summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.arclint18
-rw-r--r--Makefile13
-rw-r--r--Makefile.inc139
-rw-r--r--ObsoleteFiles.inc88
-rw-r--r--README36
-rw-r--r--UPDATING18
-rw-r--r--bin/chflags/chflags.115
-rw-r--r--bin/chflags/chflags.c51
-rw-r--r--bin/chmod/chmod.114
-rw-r--r--bin/chmod/chmod.c90
-rw-r--r--bin/csh/config.h2
-rw-r--r--bin/csh/iconv_stub.h2
-rw-r--r--bin/ed/ed.12
-rw-r--r--bin/ed/glbl.c4
-rw-r--r--bin/expr/expr.18
-rw-r--r--bin/sh/jobs.c2
-rw-r--r--bin/sh/sh.15
-rw-r--r--bin/sh/tests/builtins/Makefile2
-rw-r--r--bin/sh/tests/builtins/trap15.05
-rw-r--r--bin/sh/tests/builtins/trap16.020
-rw-r--r--bin/sh/trap.c2
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/dtrace.15
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/drti.c5
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c16
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c75
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c11
-rw-r--r--cddl/lib/libdtrace/libproc_compat.h2
-rw-r--r--cddl/lib/libdtrace/tcp.d75
-rw-r--r--cddl/usr.bin/ctfmerge/Makefile3
-rw-r--r--contrib/bmake/ChangeLog70
-rw-r--r--contrib/bmake/FILES97
-rw-r--r--contrib/bmake/Makefile10
-rw-r--r--contrib/bmake/PSD.doc/Makefile6
-rw-r--r--contrib/bmake/PSD.doc/tutorial.ms12
-rw-r--r--contrib/bmake/bmake.1210
-rw-r--r--contrib/bmake/bmake.cat1173
-rw-r--r--contrib/bmake/compat.c6
-rwxr-xr-xcontrib/bmake/configure2
-rw-r--r--contrib/bmake/configure.in4
-rw-r--r--contrib/bmake/job.c27
-rw-r--r--contrib/bmake/lst.h2
-rw-r--r--contrib/bmake/lst.lib/lstInt.h2
-rw-r--r--contrib/bmake/lst.lib/lstRemove.c6
-rw-r--r--contrib/bmake/main.c22
-rw-r--r--contrib/bmake/make.1210
-rw-r--r--contrib/bmake/make.c8
-rw-r--r--contrib/bmake/make.h3
-rw-r--r--contrib/bmake/meta.c87
-rw-r--r--contrib/bmake/mk/ChangeLog108
-rw-r--r--contrib/bmake/mk/FILES4
-rw-r--r--contrib/bmake/mk/auto.dep.mk4
-rw-r--r--contrib/bmake/mk/auto.obj.mk9
-rw-r--r--contrib/bmake/mk/autodep.mk7
-rw-r--r--contrib/bmake/mk/cython.mk96
-rw-r--r--contrib/bmake/mk/dep.mk14
-rw-r--r--contrib/bmake/mk/dirdeps.mk161
-rw-r--r--contrib/bmake/mk/gendirdeps.mk13
-rw-r--r--contrib/bmake/mk/install-mk4
-rw-r--r--contrib/bmake/mk/links.mk13
-rw-r--r--contrib/bmake/mk/manifest.mk66
-rw-r--r--contrib/bmake/mk/meta.autodep.mk5
-rw-r--r--contrib/bmake/mk/meta.stage.mk39
-rw-r--r--contrib/bmake/mk/meta.sys.mk20
-rwxr-xr-xcontrib/bmake/mk/meta2deps.py220
-rwxr-xr-xcontrib/bmake/mk/meta2deps.sh30
-rw-r--r--contrib/bmake/mk/mk-files.txt20
-rwxr-xr-xcontrib/bmake/mk/mkopt.sh94
-rw-r--r--contrib/bmake/mk/own.mk4
-rw-r--r--contrib/bmake/mk/sys.dependfile.mk8
-rw-r--r--contrib/bmake/mk/whats.mk63
-rw-r--r--contrib/bmake/nonints.h2
-rw-r--r--contrib/bmake/parse.c87
-rw-r--r--contrib/bmake/suff.c6
-rw-r--r--contrib/bmake/targ.c6
-rw-r--r--contrib/bmake/unit-tests/Makefile.in108
-rw-r--r--contrib/bmake/unit-tests/comment.exp5
-rw-r--r--contrib/bmake/unit-tests/comment.mk (renamed from contrib/bmake/unit-tests/comment)0
-rw-r--r--contrib/bmake/unit-tests/cond1.exp23
-rw-r--r--contrib/bmake/unit-tests/cond1.mk (renamed from contrib/bmake/unit-tests/cond1)2
-rw-r--r--contrib/bmake/unit-tests/doterror.exp9
-rw-r--r--contrib/bmake/unit-tests/doterror.mk (renamed from contrib/bmake/unit-tests/doterror)2
-rw-r--r--contrib/bmake/unit-tests/dotwait.exp30
-rw-r--r--contrib/bmake/unit-tests/dotwait.mk (renamed from contrib/bmake/unit-tests/dotwait)2
-rw-r--r--contrib/bmake/unit-tests/error.exp4
-rw-r--r--contrib/bmake/unit-tests/error.mk (renamed from contrib/bmake/unit-tests/error)2
-rw-r--r--contrib/bmake/unit-tests/escape.exp104
-rw-r--r--contrib/bmake/unit-tests/escape.mk246
-rw-r--r--contrib/bmake/unit-tests/export-all.exp12
-rw-r--r--contrib/bmake/unit-tests/export-all.mk (renamed from contrib/bmake/unit-tests/export-all)4
-rw-r--r--contrib/bmake/unit-tests/export-env.exp9
-rw-r--r--contrib/bmake/unit-tests/export-env.mk (renamed from contrib/bmake/unit-tests/export-env)2
-rw-r--r--contrib/bmake/unit-tests/export.exp6
-rw-r--r--contrib/bmake/unit-tests/export.mk (renamed from contrib/bmake/unit-tests/export)2
-rw-r--r--contrib/bmake/unit-tests/forloop.exp19
-rw-r--r--contrib/bmake/unit-tests/forloop.mk (renamed from contrib/bmake/unit-tests/forloop)2
-rw-r--r--contrib/bmake/unit-tests/forsubst.exp2
-rw-r--r--contrib/bmake/unit-tests/forsubst.mk (renamed from contrib/bmake/unit-tests/forsubst)2
-rw-r--r--contrib/bmake/unit-tests/hash.exp9
-rw-r--r--contrib/bmake/unit-tests/hash.mk (renamed from contrib/bmake/unit-tests/hash)0
-rw-r--r--contrib/bmake/unit-tests/impsrc.exp13
-rw-r--r--contrib/bmake/unit-tests/impsrc.mk43
-rw-r--r--contrib/bmake/unit-tests/misc.exp1
-rw-r--r--contrib/bmake/unit-tests/misc.mk (renamed from contrib/bmake/unit-tests/misc)2
-rw-r--r--contrib/bmake/unit-tests/moderrs.exp16
-rw-r--r--contrib/bmake/unit-tests/moderrs.mk (renamed from contrib/bmake/unit-tests/moderrs)2
-rw-r--r--contrib/bmake/unit-tests/modmatch.exp17
-rw-r--r--contrib/bmake/unit-tests/modmatch.mk (renamed from contrib/bmake/unit-tests/modmatch)0
-rw-r--r--contrib/bmake/unit-tests/modmisc.exp10
-rw-r--r--contrib/bmake/unit-tests/modmisc.mk (renamed from contrib/bmake/unit-tests/modmisc)2
-rw-r--r--contrib/bmake/unit-tests/modorder.exp11
-rw-r--r--contrib/bmake/unit-tests/modorder.mk (renamed from contrib/bmake/unit-tests/modorder)2
-rw-r--r--contrib/bmake/unit-tests/modts.exp33
-rw-r--r--contrib/bmake/unit-tests/modts.mk (renamed from contrib/bmake/unit-tests/modts)0
-rw-r--r--contrib/bmake/unit-tests/modword.exp122
-rw-r--r--contrib/bmake/unit-tests/modword.mk (renamed from contrib/bmake/unit-tests/modword)2
-rw-r--r--contrib/bmake/unit-tests/order.exp4
-rw-r--r--contrib/bmake/unit-tests/order.mk (renamed from contrib/bmake/unit-tests/order)2
-rw-r--r--contrib/bmake/unit-tests/phony-end.exp6
-rw-r--r--contrib/bmake/unit-tests/phony-end.mk (renamed from contrib/bmake/unit-tests/phony-end)2
-rw-r--r--contrib/bmake/unit-tests/posix.exp23
-rw-r--r--contrib/bmake/unit-tests/posix.mk (renamed from contrib/bmake/unit-tests/posix)2
-rw-r--r--contrib/bmake/unit-tests/posix1.exp185
-rw-r--r--contrib/bmake/unit-tests/posix1.mk184
-rw-r--r--contrib/bmake/unit-tests/qequals.exp2
-rw-r--r--contrib/bmake/unit-tests/qequals.mk (renamed from contrib/bmake/unit-tests/qequals)2
-rw-r--r--contrib/bmake/unit-tests/suffixes.exp35
-rw-r--r--contrib/bmake/unit-tests/suffixes.mk89
-rw-r--r--contrib/bmake/unit-tests/sunshcmd.exp4
-rw-r--r--contrib/bmake/unit-tests/sunshcmd.mk (renamed from contrib/bmake/unit-tests/sunshcmd)0
-rw-r--r--contrib/bmake/unit-tests/sysv.exp7
-rw-r--r--contrib/bmake/unit-tests/sysv.mk (renamed from contrib/bmake/unit-tests/sysv)6
-rw-r--r--contrib/bmake/unit-tests/ternary.exp10
-rw-r--r--contrib/bmake/unit-tests/ternary.mk (renamed from contrib/bmake/unit-tests/ternary)0
-rw-r--r--contrib/bmake/unit-tests/test.exp383
-rw-r--r--contrib/bmake/unit-tests/unexport-env.exp2
-rw-r--r--contrib/bmake/unit-tests/unexport-env.mk (renamed from contrib/bmake/unit-tests/unexport-env)4
-rw-r--r--contrib/bmake/unit-tests/unexport.exp4
-rw-r--r--contrib/bmake/unit-tests/unexport.mk (renamed from contrib/bmake/unit-tests/unexport)4
-rw-r--r--contrib/bmake/unit-tests/varcmd.exp9
-rw-r--r--contrib/bmake/unit-tests/varcmd.mk (renamed from contrib/bmake/unit-tests/varcmd)2
-rw-r--r--contrib/bmake/unit-tests/varmisc.exp2
-rw-r--r--contrib/bmake/unit-tests/varmisc.mk8
-rw-r--r--contrib/bmake/unit-tests/varshell.exp10
-rw-r--r--contrib/bmake/unit-tests/varshell.mk19
-rw-r--r--contrib/bmake/var.c67
-rw-r--r--contrib/compiler-rt/lib/builtins/floatditf.c52
-rw-r--r--contrib/compiler-rt/lib/builtins/floatunditf.c40
-rw-r--r--contrib/compiler-rt/lib/builtins/multc3.c73
-rw-r--r--contrib/gcclibs/libgomp/ChangeLog430
-rw-r--r--contrib/gcclibs/libgomp/ChangeLog.gcc448
-rw-r--r--contrib/gcclibs/libgomp/Makefile.am21
-rw-r--r--contrib/gcclibs/libgomp/Makefile.in237
-rw-r--r--contrib/gcclibs/libgomp/aclocal.m45
-rw-r--r--contrib/gcclibs/libgomp/config.h.in16
-rw-r--r--contrib/gcclibs/libgomp/config/bsd/proc.c117
-rw-r--r--contrib/gcclibs/libgomp/config/linux/affinity.c107
-rw-r--r--contrib/gcclibs/libgomp/config/linux/proc.c179
-rw-r--r--contrib/gcclibs/libgomp/config/mingw32/proc.c82
-rw-r--r--contrib/gcclibs/libgomp/config/posix/affinity.c41
-rwxr-xr-xcontrib/gcclibs/libgomp/configure11122
-rw-r--r--contrib/gcclibs/libgomp/configure.ac77
-rw-r--r--contrib/gcclibs/libgomp/configure.tgt20
-rw-r--r--contrib/gcclibs/libgomp/env.c97
-rw-r--r--contrib/gcclibs/libgomp/iter.c22
-rw-r--r--contrib/gcclibs/libgomp/libgomp.h12
-rw-r--r--contrib/gcclibs/libgomp/libgomp.texi27
-rw-r--r--contrib/gcclibs/libgomp/omp.h.in49
-rw-r--r--contrib/gcclibs/libgomp/omp_lib.h.in10
-rw-r--r--contrib/gcclibs/libgomp/team.c23
-rw-r--r--contrib/ipfilter/ipsend/44arp.c3
-rw-r--r--contrib/ipfilter/ipsend/ip.c3
-rw-r--r--contrib/ipfilter/ipsend/resend.c3
-rw-r--r--contrib/ipfilter/lib/kmem.c3
-rw-r--r--contrib/ipfilter/tools/ipfs.c3
-rw-r--r--contrib/ipfilter/tools/ipnat.c3
-rw-r--r--contrib/ipfilter/tools/ipnat_y.y3
-rw-r--r--contrib/ipfilter/tools/ippool.c3
-rw-r--r--contrib/ipfilter/tools/ippool_y.y3
-rw-r--r--contrib/ldns/drill/config.h4
-rw-r--r--contrib/ldns/drill/drill.111
-rwxr-xr-xcontrib/ldns/freebsd-configure.sh19
-rw-r--r--contrib/ldns/packaging/fedora/ldns.spec212
-rw-r--r--contrib/ldns/packaging/ldns-config.143
-rwxr-xr-xcontrib/ldns/packaging/ldns-config.in31
-rw-r--r--contrib/ldns/packaging/libldns.pc.in13
-rw-r--r--contrib/libxo/Makefile.am2
-rw-r--r--contrib/libxo/configure.ac13
-rw-r--r--contrib/libxo/doc/libxo.txt97
-rw-r--r--contrib/libxo/libxo/Makefile.am5
-rw-r--r--contrib/libxo/libxo/libxo.c693
-rw-r--r--contrib/libxo/libxo/xo.h115
-rw-r--r--contrib/libxo/libxo/xo_error.37
-rw-r--r--contrib/libxo/libxo/xo_format.556
-rw-r--r--contrib/libxo/libxo/xo_open_container.38
-rw-r--r--contrib/libxo/libxo/xo_open_marker.3138
-rw-r--r--contrib/libxo/libxo/xo_set_version.359
-rw-r--r--contrib/libxo/libxo/xoconfig.h12
-rw-r--r--contrib/libxo/libxo/xoconfig.h.in6
-rw-r--r--contrib/libxo/libxo/xoversion.h6
-rw-r--r--contrib/libxo/m4/libtool.m42561
-rw-r--r--contrib/libxo/m4/ltoptions.m4127
-rw-r--r--contrib/libxo/m4/ltversion.m412
-rw-r--r--contrib/libxo/tests/core/Makefile.am4
-rw-r--r--contrib/libxo/tests/core/saved/test_01.JP.out6
-rw-r--r--contrib/libxo/tests/core/saved/test_02.JP.out4
-rw-r--r--contrib/libxo/tests/core/saved/test_05.H.out2
-rw-r--r--contrib/libxo/tests/core/saved/test_05.HIPx.out59
-rw-r--r--contrib/libxo/tests/core/saved/test_05.HP.out59
-rw-r--r--contrib/libxo/tests/core/saved/test_05.J.out2
-rw-r--r--contrib/libxo/tests/core/saved/test_05.JP.out16
-rw-r--r--contrib/libxo/tests/core/saved/test_05.T.out10
-rw-r--r--contrib/libxo/tests/core/saved/test_05.X.out2
-rw-r--r--contrib/libxo/tests/core/saved/test_05.XP.out16
-rw-r--r--contrib/libxo/tests/core/saved/test_09.JP.out20
-rw-r--r--contrib/libxo/tests/core/saved/test_10.H.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.H.out1
-rw-r--r--contrib/libxo/tests/core/saved/test_10.HIPx.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.HIPx.out316
-rw-r--r--contrib/libxo/tests/core/saved/test_10.HP.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.HP.out316
-rw-r--r--contrib/libxo/tests/core/saved/test_10.J.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.J.out2
-rw-r--r--contrib/libxo/tests/core/saved/test_10.JP.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.JP.out113
-rw-r--r--contrib/libxo/tests/core/saved/test_10.T.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.T.out48
-rw-r--r--contrib/libxo/tests/core/saved/test_10.X.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.X.out1
-rw-r--r--contrib/libxo/tests/core/saved/test_10.XP.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.XP.out100
-rw-r--r--contrib/libxo/tests/core/saved/test_10.err0
-rw-r--r--contrib/libxo/tests/core/saved/test_10.out38
-rw-r--r--contrib/libxo/tests/core/test_05.c17
-rw-r--r--contrib/libxo/tests/core/test_10.c212
-rw-r--r--contrib/libxo/xo/xo.12
-rw-r--r--contrib/libxo/xohtml/Makefile.am38
-rw-r--r--contrib/libxo/xohtml/xohtml.1125
-rw-r--r--contrib/libxo/xohtml/xohtml.css24
-rw-r--r--contrib/libxo/xohtml/xohtml.sh.in20
-rw-r--r--contrib/libxo/xolint/Makefile.am3
-rw-r--r--contrib/libxo/xolint/xolint.12
-rwxr-xr-xcontrib/libxo/xolint/xolint.pl63
-rw-r--r--contrib/llvm/lib/MC/MCParser/AsmParser.cpp24
-rw-r--r--contrib/llvm/patches/patch-13-llvm-r229911-uleb128-commas.diff77
-rw-r--r--contrib/mdocml/config.h2
-rw-r--r--contrib/netbsd-tests/lib/libm/t_fmod.c6
-rw-r--r--contrib/netbsd-tests/lib/libpthread/t_swapcontext.c3
-rw-r--r--contrib/nvi/README4
-rw-r--r--contrib/nvi/catalog/dump.c19
-rw-r--r--contrib/nvi/catalog/spell.ok19
-rw-r--r--contrib/nvi/cl/cl.h12
-rw-r--r--contrib/nvi/cl/cl_funcs.c46
-rw-r--r--contrib/nvi/cl/cl_main.c37
-rw-r--r--contrib/nvi/cl/cl_read.c11
-rw-r--r--contrib/nvi/cl/cl_screen.c50
-rw-r--r--contrib/nvi/cl/cl_term.c27
-rw-r--r--contrib/nvi/cl/extern.h62
-rw-r--r--contrib/nvi/common/common.h4
-rw-r--r--contrib/nvi/common/conv.c538
-rw-r--r--contrib/nvi/common/cut.c14
-rw-r--r--contrib/nvi/common/delete.c2
-rw-r--r--contrib/nvi/common/encoding.c26
-rw-r--r--contrib/nvi/common/exf.c41
-rw-r--r--contrib/nvi/common/extern.h262
-rw-r--r--contrib/nvi/common/gs.h70
-rw-r--r--contrib/nvi/common/key.c28
-rw-r--r--contrib/nvi/common/line.c79
-rw-r--r--contrib/nvi/common/log.c30
-rw-r--r--contrib/nvi/common/main.c24
-rw-r--r--contrib/nvi/common/mark.c16
-rw-r--r--contrib/nvi/common/msg.c28
-rw-r--r--contrib/nvi/common/options.c42
-rw-r--r--contrib/nvi/common/options.h2
-rw-r--r--contrib/nvi/common/options_f.c30
-rw-r--r--contrib/nvi/common/put.c2
-rw-r--r--contrib/nvi/common/recover.c29
-rw-r--r--contrib/nvi/common/screen.c6
-rw-r--r--contrib/nvi/common/search.c21
-rw-r--r--contrib/nvi/common/seq.c30
-rw-r--r--contrib/nvi/common/util.c30
-rw-r--r--contrib/nvi/docs/TODO147
-rw-r--r--contrib/nvi/docs/USD.doc/edit/Makefile11
-rw-r--r--contrib/nvi/docs/USD.doc/edit/edit.vindex115
-rw-r--r--contrib/nvi/docs/USD.doc/exref/Makefile17
-rw-r--r--contrib/nvi/docs/USD.doc/vi.man/spell.ok179
-rw-r--r--contrib/nvi/docs/USD.doc/vi.ref/Makefile32
-rw-r--r--contrib/nvi/docs/USD.doc/vi.ref/index.so260
-rw-r--r--contrib/nvi/docs/USD.doc/vi.ref/merge.awk16
-rw-r--r--contrib/nvi/docs/USD.doc/vi.ref/spell.ok414
-rw-r--r--contrib/nvi/docs/USD.doc/vitut/Makefile22
-rw-r--r--contrib/nvi/docs/changelog1102
-rw-r--r--contrib/nvi/docs/ev55
-rw-r--r--contrib/nvi/docs/features83
-rw-r--r--contrib/nvi/docs/help229
-rw-r--r--contrib/nvi/docs/internals/autowrite88
-rw-r--r--contrib/nvi/docs/internals/context32
-rw-r--r--contrib/nvi/docs/internals/cscope.NOTES142
-rw-r--r--contrib/nvi/docs/internals/gdb.script76
-rw-r--r--contrib/nvi/docs/internals/input350
-rw-r--r--contrib/nvi/docs/internals/openmode36
-rw-r--r--contrib/nvi/docs/internals/quoting208
-rw-r--r--contrib/nvi/docs/internals/structures68
-rw-r--r--contrib/nvi/docs/interp/interp190
-rw-r--r--contrib/nvi/docs/interp/spell.ok46
-rw-r--r--contrib/nvi/docs/man/Makefile (renamed from contrib/nvi/docs/USD.doc/vi.man/Makefile)0
-rw-r--r--contrib/nvi/docs/man/vi.1 (renamed from contrib/nvi/docs/USD.doc/vi.man/vi.1)69
-rw-r--r--contrib/nvi/docs/spell.ok173
-rw-r--r--contrib/nvi/docs/tutorial/vi.advanced1458
-rw-r--r--contrib/nvi/docs/tutorial/vi.beginner741
-rwxr-xr-xcontrib/nvi/docs/tutorial/vi.tut.csh24
-rw-r--r--contrib/nvi/ex/ex.c30
-rw-r--r--contrib/nvi/ex/ex.h4
-rw-r--r--contrib/nvi/ex/ex_abbrev.c4
-rw-r--r--contrib/nvi/ex/ex_append.c8
-rw-r--r--contrib/nvi/ex/ex_args.c12
-rw-r--r--contrib/nvi/ex/ex_argv.c32
-rw-r--r--contrib/nvi/ex/ex_at.c2
-rw-r--r--contrib/nvi/ex/ex_bang.c2
-rw-r--r--contrib/nvi/ex/ex_cd.c2
-rw-r--r--contrib/nvi/ex/ex_cscope.c44
-rw-r--r--contrib/nvi/ex/ex_delete.c2
-rw-r--r--contrib/nvi/ex/ex_display.c8
-rw-r--r--contrib/nvi/ex/ex_edit.c4
-rw-r--r--contrib/nvi/ex/ex_equal.c2
-rw-r--r--contrib/nvi/ex/ex_file.c2
-rw-r--r--contrib/nvi/ex/ex_filter.c6
-rw-r--r--contrib/nvi/ex/ex_global.c8
-rw-r--r--contrib/nvi/ex/ex_init.c14
-rw-r--r--contrib/nvi/ex/ex_join.c6
-rw-r--r--contrib/nvi/ex/ex_map.c4
-rw-r--r--contrib/nvi/ex/ex_mark.c2
-rw-r--r--contrib/nvi/ex/ex_mkexrc.c2
-rw-r--r--contrib/nvi/ex/ex_move.c4
-rw-r--r--contrib/nvi/ex/ex_open.c2
-rw-r--r--contrib/nvi/ex/ex_preserve.c4
-rw-r--r--contrib/nvi/ex/ex_print.c22
-rw-r--r--contrib/nvi/ex/ex_put.c2
-rw-r--r--contrib/nvi/ex/ex_quit.c2
-rw-r--r--contrib/nvi/ex/ex_read.c4
-rw-r--r--contrib/nvi/ex/ex_screen.c8
-rw-r--r--contrib/nvi/ex/ex_script.c20
-rw-r--r--contrib/nvi/ex/ex_set.c2
-rw-r--r--contrib/nvi/ex/ex_shell.c8
-rw-r--r--contrib/nvi/ex/ex_shift.c6
-rw-r--r--contrib/nvi/ex/ex_source.c2
-rw-r--r--contrib/nvi/ex/ex_stop.c2
-rw-r--r--contrib/nvi/ex/ex_subst.c26
-rw-r--r--contrib/nvi/ex/ex_tag.c60
-rw-r--r--contrib/nvi/ex/ex_txt.c6
-rw-r--r--contrib/nvi/ex/ex_undo.c2
-rw-r--r--contrib/nvi/ex/ex_usage.c6
-rw-r--r--contrib/nvi/ex/ex_util.c12
-rw-r--r--contrib/nvi/ex/ex_version.c2
-rw-r--r--contrib/nvi/ex/ex_visual.c2
-rw-r--r--contrib/nvi/ex/ex_write.c57
-rw-r--r--contrib/nvi/ex/ex_yank.c2
-rw-r--r--contrib/nvi/ex/ex_z.c6
-rw-r--r--contrib/nvi/ex/extern.h258
-rw-r--r--contrib/nvi/ex/version.h2
-rw-r--r--contrib/nvi/regex/COPYRIGHT6
-rw-r--r--contrib/nvi/regex/cclass.h6
-rw-r--r--contrib/nvi/regex/cname.h6
-rw-r--r--contrib/nvi/regex/engine.c248
-rw-r--r--contrib/nvi/regex/re_format.76
-rw-r--r--contrib/nvi/regex/regcomp.c498
-rw-r--r--contrib/nvi/regex/regerror.c25
-rw-r--r--contrib/nvi/regex/regex.36
-rw-r--r--contrib/nvi/regex/regex.h16
-rw-r--r--contrib/nvi/regex/regex2.h6
-rw-r--r--contrib/nvi/regex/regexec.c15
-rw-r--r--contrib/nvi/regex/regfree.c9
-rw-r--r--contrib/nvi/regex/utils.h6
-rw-r--r--contrib/nvi/vi/extern.h290
-rw-r--r--contrib/nvi/vi/getc.c12
-rw-r--r--contrib/nvi/vi/v_at.c2
-rw-r--r--contrib/nvi/vi/v_ch.c16
-rw-r--r--contrib/nvi/vi/v_delete.c2
-rw-r--r--contrib/nvi/vi/v_ex.c34
-rw-r--r--contrib/nvi/vi/v_increment.c4
-rw-r--r--contrib/nvi/vi/v_init.c6
-rw-r--r--contrib/nvi/vi/v_itxt.c22
-rw-r--r--contrib/nvi/vi/v_left.c10
-rw-r--r--contrib/nvi/vi/v_mark.c25
-rw-r--r--contrib/nvi/vi/v_match.c6
-rw-r--r--contrib/nvi/vi/v_paragraph.c6
-rw-r--r--contrib/nvi/vi/v_put.c6
-rw-r--r--contrib/nvi/vi/v_redraw.c2
-rw-r--r--contrib/nvi/vi/v_replace.c2
-rw-r--r--contrib/nvi/vi/v_right.c4
-rw-r--r--contrib/nvi/vi/v_screen.c2
-rw-r--r--contrib/nvi/vi/v_scroll.c28
-rw-r--r--contrib/nvi/vi/v_search.c16
-rw-r--r--contrib/nvi/vi/v_section.c4
-rw-r--r--contrib/nvi/vi/v_sentence.c4
-rw-r--r--contrib/nvi/vi/v_status.c2
-rw-r--r--contrib/nvi/vi/v_txt.c46
-rw-r--r--contrib/nvi/vi/v_ulcase.c6
-rw-r--r--contrib/nvi/vi/v_undo.c4
-rw-r--r--contrib/nvi/vi/v_util.c14
-rw-r--r--contrib/nvi/vi/v_word.c18
-rw-r--r--contrib/nvi/vi/v_xchar.c4
-rw-r--r--contrib/nvi/vi/v_yank.c2
-rw-r--r--contrib/nvi/vi/v_z.c4
-rw-r--r--contrib/nvi/vi/v_zexit.c2
-rw-r--r--contrib/nvi/vi/vi.c21
-rw-r--r--contrib/nvi/vi/vi.h14
-rw-r--r--contrib/nvi/vi/vs_line.c4
-rw-r--r--contrib/nvi/vi/vs_msg.c22
-rw-r--r--contrib/nvi/vi/vs_refresh.c12
-rw-r--r--contrib/nvi/vi/vs_relative.c10
-rw-r--r--contrib/nvi/vi/vs_smap.c36
-rw-r--r--contrib/nvi/vi/vs_split.c26
-rw-r--r--contrib/pjdfstest/tests/open/20.t4
-rw-r--r--contrib/pjdfstest/tests/truncate/11.t4
-rw-r--r--contrib/smbfs/include/netsmb/smb_lib.h14
-rw-r--r--contrib/smbfs/lib/smb/nls.c12
-rw-r--r--contrib/smbfs/lib/smb/print.c2
-rw-r--r--contrib/smbfs/lib/smb/rq.c4
-rwxr-xr-xcontrib/sqlite3/configure20
-rw-r--r--contrib/sqlite3/configure.ac2
-rw-r--r--contrib/sqlite3/shell.c928
-rw-r--r--contrib/sqlite3/sqlite3.183
-rw-r--r--contrib/sqlite3/sqlite3.c8407
-rw-r--r--contrib/sqlite3/sqlite3.h1398
-rw-r--r--contrib/tcpdump/interface.h2
-rw-r--r--contrib/tcpdump/netdissect.h2
-rw-r--r--contrib/tcpdump/print-ip.c2
-rw-r--r--contrib/tcpdump/print-pfsync.c210
-rw-r--r--contrib/unbound/Makefile.in184
-rw-r--r--contrib/unbound/compat/getentropy_linux.c21
-rw-r--r--contrib/unbound/config.h15
-rw-r--r--contrib/unbound/config.h.in9
-rwxr-xr-xcontrib/unbound/configure122
-rw-r--r--contrib/unbound/configure.ac18
-rw-r--r--contrib/unbound/daemon/remote.c9
-rw-r--r--contrib/unbound/daemon/unbound.c33
-rw-r--r--contrib/unbound/daemon/worker.c2
-rw-r--r--contrib/unbound/doc/Changelog106
-rw-r--r--contrib/unbound/doc/README2
-rw-r--r--contrib/unbound/doc/example.conf12
-rw-r--r--contrib/unbound/doc/example.conf.in12
-rw-r--r--contrib/unbound/doc/libunbound.34
-rw-r--r--contrib/unbound/doc/libunbound.3.in4
-rw-r--r--contrib/unbound/doc/unbound-anchor.82
-rw-r--r--contrib/unbound/doc/unbound-anchor.8.in2
-rw-r--r--contrib/unbound/doc/unbound-checkconf.86
-rw-r--r--contrib/unbound/doc/unbound-checkconf.8.in6
-rw-r--r--contrib/unbound/doc/unbound-control.82
-rw-r--r--contrib/unbound/doc/unbound-control.8.in2
-rw-r--r--contrib/unbound/doc/unbound-host.12
-rw-r--r--contrib/unbound/doc/unbound-host.1.in2
-rw-r--r--contrib/unbound/doc/unbound.84
-rw-r--r--contrib/unbound/doc/unbound.8.in4
-rw-r--r--contrib/unbound/doc/unbound.conf.516
-rw-r--r--contrib/unbound/doc/unbound.conf.5.in16
-rw-r--r--contrib/unbound/iterator/iter_scrub.c4
-rw-r--r--contrib/unbound/iterator/iter_utils.c36
-rw-r--r--contrib/unbound/iterator/iter_utils.h9
-rw-r--r--contrib/unbound/iterator/iterator.c15
-rw-r--r--contrib/unbound/libunbound/libworker.c6
-rw-r--r--contrib/unbound/libunbound/python/libunbound.i8
-rw-r--r--contrib/unbound/services/listen_dnsport.c64
-rw-r--r--contrib/unbound/services/localzone.c29
-rw-r--r--contrib/unbound/services/localzone.h9
-rw-r--r--contrib/unbound/smallapp/unbound-checkconf.c20
-rwxr-xr-xcontrib/unbound/smallapp/unbound-control-setup.sh3
-rwxr-xr-xcontrib/unbound/smallapp/unbound-control-setup.sh.in3
-rw-r--r--contrib/unbound/smallapp/unbound-control.c8
-rw-r--r--contrib/unbound/util/config_file.c25
-rw-r--r--contrib/unbound/util/config_file.h11
-rw-r--r--contrib/unbound/util/configlexer.lex1
-rw-r--r--contrib/unbound/util/configparser.y18
-rw-r--r--contrib/unbound/util/iana_ports.inc7
-rw-r--r--contrib/unbound/util/net_help.c7
-rw-r--r--contrib/unbound/util/rtt.c2
-rw-r--r--contrib/unbound/util/rtt.h2
-rw-r--r--contrib/unbound/validator/val_secalgo.c3
-rw-r--r--contrib/unbound/validator/val_utils.c12
-rw-r--r--contrib/unbound/validator/val_utils.h7
-rw-r--r--contrib/unbound/validator/validator.c57
-rw-r--r--contrib/wpa/CONTRIBUTIONS143
-rw-r--r--contrib/wpa/COPYING2
-rw-r--r--contrib/wpa/README2
-rw-r--r--contrib/wpa/hostapd/ChangeLog186
-rw-r--r--contrib/wpa/hostapd/README8
-rw-r--r--contrib/wpa/hostapd/README-WPS24
-rw-r--r--contrib/wpa/hostapd/config_file.c3202
-rw-r--r--contrib/wpa/hostapd/ctrl_iface.c1518
-rw-r--r--contrib/wpa/hostapd/defconfig79
-rw-r--r--contrib/wpa/hostapd/dump_state.c180
-rw-r--r--contrib/wpa/hostapd/dump_state.h14
-rw-r--r--contrib/wpa/hostapd/eap_register.c12
-rw-r--r--contrib/wpa/hostapd/hapd_module_tests.c17
-rw-r--r--contrib/wpa/hostapd/hlr_auc_gw.c250
-rw-r--r--contrib/wpa/hostapd/hostapd.82
-rw-r--r--contrib/wpa/hostapd/hostapd.conf289
-rw-r--r--contrib/wpa/hostapd/hostapd.eap_user6
-rw-r--r--contrib/wpa/hostapd/hostapd.eap_user_sqlite9
-rw-r--r--contrib/wpa/hostapd/hostapd_cli.c332
-rw-r--r--contrib/wpa/hostapd/main.c311
-rwxr-xr-xcontrib/wpa/hostapd/wps-ap-nfc.py342
-rw-r--r--contrib/wpa/hs20/client/Android.mk81
-rw-r--r--contrib/wpa/hs20/client/Makefile94
-rw-r--r--contrib/wpa/hs20/client/devdetail.xml47
-rw-r--r--contrib/wpa/hs20/client/devinfo.xml7
-rw-r--r--contrib/wpa/hs20/client/est.c715
-rw-r--r--contrib/wpa/hs20/client/oma_dm_client.c1392
-rw-r--r--contrib/wpa/hs20/client/osu_client.c3227
-rw-r--r--contrib/wpa/hs20/client/osu_client.h118
-rw-r--r--contrib/wpa/hs20/client/spp_client.c995
-rw-r--r--contrib/wpa/patches/openssl-0.9.8-tls-extensions.patch429
-rw-r--r--contrib/wpa/patches/openssl-0.9.8d-tls-extensions.patch429
-rw-r--r--contrib/wpa/patches/openssl-0.9.8e-tls-extensions.patch353
-rw-r--r--contrib/wpa/patches/openssl-0.9.8g-tls-extensions.patch330
-rw-r--r--contrib/wpa/patches/openssl-0.9.8h-tls-extensions.patch344
-rw-r--r--contrib/wpa/patches/openssl-0.9.8i-tls-extensions.patch404
-rw-r--r--contrib/wpa/patches/openssl-0.9.8za-tls-extensions.patch (renamed from contrib/wpa/patches/openssl-0.9.8x-tls-extensions.patch)75
-rw-r--r--contrib/wpa/patches/openssl-0.9.9-session-ticket.patch374
-rw-r--r--contrib/wpa/src/ap/accounting.c68
-rw-r--r--contrib/wpa/src/ap/acs.c949
-rw-r--r--contrib/wpa/src/ap/acs.h27
-rw-r--r--contrib/wpa/src/ap/ap_config.c427
-rw-r--r--contrib/wpa/src/ap/ap_config.h164
-rw-r--r--contrib/wpa/src/ap/ap_drv_ops.c137
-rw-r--r--contrib/wpa/src/ap/ap_drv_ops.h137
-rw-r--r--contrib/wpa/src/ap/ap_list.c108
-rw-r--r--contrib/wpa/src/ap/ap_list.h22
-rw-r--r--contrib/wpa/src/ap/ap_mlme.c6
-rw-r--r--contrib/wpa/src/ap/authsrv.c17
-rw-r--r--contrib/wpa/src/ap/beacon.c487
-rw-r--r--contrib/wpa/src/ap/beacon.h19
-rw-r--r--contrib/wpa/src/ap/bss_load.c65
-rw-r--r--contrib/wpa/src/ap/bss_load.h17
-rw-r--r--contrib/wpa/src/ap/ctrl_iface_ap.c334
-rw-r--r--contrib/wpa/src/ap/ctrl_iface_ap.h7
-rw-r--r--contrib/wpa/src/ap/dfs.c1064
-rw-r--r--contrib/wpa/src/ap/dfs.h30
-rw-r--r--contrib/wpa/src/ap/dhcp_snoop.c178
-rw-r--r--contrib/wpa/src/ap/dhcp_snoop.h30
-rw-r--r--contrib/wpa/src/ap/drv_callbacks.c603
-rw-r--r--contrib/wpa/src/ap/eap_user_db.c16
-rw-r--r--contrib/wpa/src/ap/gas_serv.c494
-rw-r--r--contrib/wpa/src/ap/gas_serv.h19
-rw-r--r--contrib/wpa/src/ap/hostapd.c1804
-rw-r--r--contrib/wpa/src/ap/hostapd.h172
-rw-r--r--contrib/wpa/src/ap/hs20.c154
-rw-r--r--contrib/wpa/src/ap/hs20.h8
-rw-r--r--contrib/wpa/src/ap/hw_features.c801
-rw-r--r--contrib/wpa/src/ap/hw_features.h16
-rw-r--r--contrib/wpa/src/ap/iapp.c84
-rw-r--r--contrib/wpa/src/ap/ieee802_11.c1156
-rw-r--r--contrib/wpa/src/ap/ieee802_11.h32
-rw-r--r--contrib/wpa/src/ap/ieee802_11_auth.c38
-rw-r--r--contrib/wpa/src/ap/ieee802_11_ht.c278
-rw-r--r--contrib/wpa/src/ap/ieee802_11_shared.c136
-rw-r--r--contrib/wpa/src/ap/ieee802_11_vht.c207
-rw-r--r--contrib/wpa/src/ap/ieee802_1x.c692
-rw-r--r--contrib/wpa/src/ap/ieee802_1x.h1
-rw-r--r--contrib/wpa/src/ap/ndisc_snoop.c171
-rw-r--r--contrib/wpa/src/ap/ndisc_snoop.h36
-rw-r--r--contrib/wpa/src/ap/p2p_hostapd.c5
-rw-r--r--contrib/wpa/src/ap/peerkey_auth.c22
-rw-r--r--contrib/wpa/src/ap/pmksa_cache_auth.c180
-rw-r--r--contrib/wpa/src/ap/pmksa_cache_auth.h8
-rw-r--r--contrib/wpa/src/ap/sta_info.c329
-rw-r--r--contrib/wpa/src/ap/sta_info.h73
-rw-r--r--contrib/wpa/src/ap/tkip_countermeasures.c8
-rw-r--r--contrib/wpa/src/ap/vlan_init.c114
-rw-r--r--contrib/wpa/src/ap/vlan_init.h10
-rw-r--r--contrib/wpa/src/ap/wmm.c12
-rw-r--r--contrib/wpa/src/ap/wmm.h10
-rw-r--r--contrib/wpa/src/ap/wnm_ap.c357
-rw-r--r--contrib/wpa/src/ap/wnm_ap.h15
-rw-r--r--contrib/wpa/src/ap/wpa_auth.c590
-rw-r--r--contrib/wpa/src/ap/wpa_auth.h41
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ft.c351
-rw-r--r--contrib/wpa/src/ap/wpa_auth_glue.c88
-rw-r--r--contrib/wpa/src/ap/wpa_auth_i.h39
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ie.c161
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ie.h7
-rw-r--r--contrib/wpa/src/ap/wps_hostapd.c508
-rw-r--r--contrib/wpa/src/ap/wps_hostapd.h9
-rw-r--r--contrib/wpa/src/ap/x_snoop.c123
-rw-r--r--contrib/wpa/src/ap/x_snoop.h56
-rw-r--r--contrib/wpa/src/common/common_module_tests.c172
-rw-r--r--contrib/wpa/src/common/defs.h92
-rw-r--r--contrib/wpa/src/common/eapol_common.h13
-rw-r--r--contrib/wpa/src/common/hw_features_common.c438
-rw-r--r--contrib/wpa/src/common/hw_features_common.h40
-rw-r--r--contrib/wpa/src/common/ieee802_11_common.c469
-rw-r--r--contrib/wpa/src/common/ieee802_11_common.h33
-rw-r--r--contrib/wpa/src/common/ieee802_11_defs.h410
-rw-r--r--contrib/wpa/src/common/ieee802_1x_defs.h78
-rw-r--r--contrib/wpa/src/common/privsep_commands.h2
-rw-r--r--contrib/wpa/src/common/qca-vendor-attr.h28
-rw-r--r--contrib/wpa/src/common/qca-vendor.h246
-rw-r--r--contrib/wpa/src/common/sae.c1069
-rw-r--r--contrib/wpa/src/common/sae.h67
-rw-r--r--contrib/wpa/src/common/tnc.h121
-rw-r--r--contrib/wpa/src/common/version.h2
-rw-r--r--contrib/wpa/src/common/wpa_common.c586
-rw-r--r--contrib/wpa/src/common/wpa_common.h121
-rw-r--r--contrib/wpa/src/common/wpa_ctrl.c134
-rw-r--r--contrib/wpa/src/common/wpa_ctrl.h142
-rw-r--r--contrib/wpa/src/common/wpa_helpers.c292
-rw-r--r--contrib/wpa/src/common/wpa_helpers.h37
-rw-r--r--contrib/wpa/src/crypto/aes-ccm.c2
-rw-r--r--contrib/wpa/src/crypto/aes-eax.c2
-rw-r--r--contrib/wpa/src/crypto/aes-gcm.c2
-rw-r--r--contrib/wpa/src/crypto/aes-omac1.c64
-rw-r--r--contrib/wpa/src/crypto/aes-siv.c188
-rw-r--r--contrib/wpa/src/crypto/aes-unwrap.c19
-rw-r--r--contrib/wpa/src/crypto/aes-wrap.c20
-rw-r--r--contrib/wpa/src/crypto/aes_siv.h19
-rw-r--r--contrib/wpa/src/crypto/aes_wrap.h15
-rw-r--r--contrib/wpa/src/crypto/crypto.h323
-rw-r--r--contrib/wpa/src/crypto/crypto_internal-rsa.c9
-rw-r--r--contrib/wpa/src/crypto/crypto_module_tests.c1679
-rw-r--r--contrib/wpa/src/crypto/crypto_nss.c207
-rw-r--r--contrib/wpa/src/crypto/crypto_openssl.c635
-rw-r--r--contrib/wpa/src/crypto/dh_groups.c674
-rw-r--r--contrib/wpa/src/crypto/dh_groups.h3
-rw-r--r--contrib/wpa/src/crypto/fips_prf_cryptoapi.c19
-rw-r--r--contrib/wpa/src/crypto/fips_prf_gnutls.c20
-rw-r--r--contrib/wpa/src/crypto/fips_prf_nss.c19
-rw-r--r--contrib/wpa/src/crypto/md5.c6
-rw-r--r--contrib/wpa/src/crypto/milenage.c4
-rw-r--r--contrib/wpa/src/crypto/ms_funcs.c1
-rw-r--r--contrib/wpa/src/crypto/random.c12
-rw-r--r--contrib/wpa/src/crypto/sha1-internal.c2
-rw-r--r--contrib/wpa/src/crypto/sha1-prf.c1
-rw-r--r--contrib/wpa/src/crypto/sha1.c5
-rw-r--r--contrib/wpa/src/crypto/sha256-kdf.c76
-rw-r--r--contrib/wpa/src/crypto/sha256-prf.c40
-rw-r--r--contrib/wpa/src/crypto/sha256.h8
-rw-r--r--contrib/wpa/src/crypto/sha384.h19
-rw-r--r--contrib/wpa/src/crypto/tls.h47
-rw-r--r--contrib/wpa/src/crypto/tls_gnutls.c939
-rw-r--r--contrib/wpa/src/crypto/tls_internal.c55
-rw-r--r--contrib/wpa/src/crypto/tls_none.c6
-rw-r--r--contrib/wpa/src/crypto/tls_nss.c645
-rw-r--r--contrib/wpa/src/crypto/tls_openssl.c1053
-rw-r--r--contrib/wpa/src/crypto/tls_schannel.c31
-rw-r--r--contrib/wpa/src/drivers/driver.h1970
-rw-r--r--contrib/wpa/src/drivers/driver_bsd.c238
-rw-r--r--contrib/wpa/src/drivers/driver_common.c154
-rw-r--r--contrib/wpa/src/drivers/driver_macsec_qca.c891
-rw-r--r--contrib/wpa/src/drivers/driver_ndis.c42
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211.h274
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_android.c220
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_capa.c1532
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_event.c2029
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_monitor.c491
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_scan.c775
-rw-r--r--contrib/wpa/src/drivers/driver_openbsd.c136
-rw-r--r--contrib/wpa/src/drivers/driver_privsep.c31
-rw-r--r--contrib/wpa/src/drivers/driver_wired.c106
-rw-r--r--contrib/wpa/src/drivers/drivers.c36
-rw-r--r--contrib/wpa/src/drivers/linux_defines.h46
-rw-r--r--contrib/wpa/src/eap_common/eap_common.c85
-rw-r--r--contrib/wpa/src/eap_common/eap_common.h12
-rw-r--r--contrib/wpa/src/eap_common/eap_defs.h42
-rw-r--r--contrib/wpa/src/eap_common/eap_eke_common.c768
-rw-r--r--contrib/wpa/src/eap_common/eap_eke_common.h114
-rw-r--r--contrib/wpa/src/eap_common/eap_fast_common.c2
-rw-r--r--contrib/wpa/src/eap_common/eap_fast_common.h2
-rw-r--r--contrib/wpa/src/eap_common/eap_gpsk_common.c144
-rw-r--r--contrib/wpa/src/eap_common/eap_gpsk_common.h6
-rw-r--r--contrib/wpa/src/eap_common/eap_ikev2_common.c12
-rw-r--r--contrib/wpa/src/eap_common/eap_ikev2_common.h7
-rw-r--r--contrib/wpa/src/eap_common/eap_pax_common.c8
-rw-r--r--contrib/wpa/src/eap_common/eap_pax_common.h3
-rw-r--r--contrib/wpa/src/eap_common/eap_pwd_common.c17
-rw-r--r--contrib/wpa/src/eap_common/eap_pwd_common.h2
-rw-r--r--contrib/wpa/src/eap_common/eap_sim_common.c13
-rw-r--r--contrib/wpa/src/eap_common/eap_sim_common.h3
-rw-r--r--contrib/wpa/src/eap_common/ikev2_common.c89
-rw-r--r--contrib/wpa/src/eap_common/ikev2_common.h4
-rw-r--r--contrib/wpa/src/eap_peer/eap.c639
-rw-r--r--contrib/wpa/src/eap_peer/eap.h33
-rw-r--r--contrib/wpa/src/eap_peer/eap_aka.c170
-rw-r--r--contrib/wpa/src/eap_peer/eap_config.h113
-rw-r--r--contrib/wpa/src/eap_peer/eap_eke.c765
-rw-r--r--contrib/wpa/src/eap_peer/eap_fast.c74
-rw-r--r--contrib/wpa/src/eap_peer/eap_fast_pac.c36
-rw-r--r--contrib/wpa/src/eap_peer/eap_gpsk.c86
-rw-r--r--contrib/wpa/src/eap_peer/eap_i.h37
-rw-r--r--contrib/wpa/src/eap_peer/eap_ikev2.c72
-rw-r--r--contrib/wpa/src/eap_peer/eap_leap.c5
-rw-r--r--contrib/wpa/src/eap_peer/eap_methods.c4
-rw-r--r--contrib/wpa/src/eap_peer/eap_methods.h2
-rw-r--r--contrib/wpa/src/eap_peer/eap_mschapv2.c52
-rw-r--r--contrib/wpa/src/eap_peer/eap_pax.c32
-rw-r--r--contrib/wpa/src/eap_peer/eap_peap.c139
-rw-r--r--contrib/wpa/src/eap_peer/eap_proxy.h49
-rw-r--r--contrib/wpa/src/eap_peer/eap_proxy_dummy.c77
-rw-r--r--contrib/wpa/src/eap_peer/eap_psk.c29
-rw-r--r--contrib/wpa/src/eap_peer/eap_pwd.c128
-rw-r--r--contrib/wpa/src/eap_peer/eap_sake.c27
-rw-r--r--contrib/wpa/src/eap_peer/eap_sim.c162
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls.c111
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls_common.c78
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls_common.h4
-rw-r--r--contrib/wpa/src/eap_peer/eap_tnc.c3
-rw-r--r--contrib/wpa/src/eap_peer/eap_ttls.c93
-rw-r--r--contrib/wpa/src/eap_peer/eap_vendor_test.c21
-rw-r--r--contrib/wpa/src/eap_peer/eap_wsc.c75
-rw-r--r--contrib/wpa/src/eap_peer/ikev2.c65
-rw-r--r--contrib/wpa/src/eap_peer/mschapv2.c4
-rw-r--r--contrib/wpa/src/eap_peer/tncc.c61
-rw-r--r--contrib/wpa/src/eap_server/eap.h33
-rw-r--r--contrib/wpa/src/eap_server/eap_i.h32
-rw-r--r--contrib/wpa/src/eap_server/eap_methods.h2
-rw-r--r--contrib/wpa/src/eap_server/eap_server.c608
-rw-r--r--contrib/wpa/src/eap_server/eap_server_aka.c39
-rw-r--r--contrib/wpa/src/eap_server/eap_server_eke.c793
-rw-r--r--contrib/wpa/src/eap_server/eap_server_fast.c46
-rw-r--r--contrib/wpa/src/eap_server/eap_server_gpsk.c68
-rw-r--r--contrib/wpa/src/eap_server/eap_server_gtc.c2
-rw-r--r--contrib/wpa/src/eap_server/eap_server_identity.c7
-rw-r--r--contrib/wpa/src/eap_server/eap_server_ikev2.c55
-rw-r--r--contrib/wpa/src/eap_server/eap_server_md5.c2
-rw-r--r--contrib/wpa/src/eap_server/eap_server_methods.c4
-rw-r--r--contrib/wpa/src/eap_server/eap_server_mschapv2.c34
-rw-r--r--contrib/wpa/src/eap_server/eap_server_pax.c42
-rw-r--r--contrib/wpa/src/eap_server/eap_server_peap.c156
-rw-r--r--contrib/wpa/src/eap_server/eap_server_psk.c49
-rw-r--r--contrib/wpa/src/eap_server/eap_server_pwd.c114
-rw-r--r--contrib/wpa/src/eap_server/eap_server_sake.c66
-rw-r--r--contrib/wpa/src/eap_server/eap_server_sim.c36
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tls.c72
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tls_common.c70
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tnc.c3
-rw-r--r--contrib/wpa/src/eap_server/eap_server_ttls.c80
-rw-r--r--contrib/wpa/src/eap_server/eap_server_wsc.c2
-rw-r--r--contrib/wpa/src/eap_server/eap_sim_db.c56
-rw-r--r--contrib/wpa/src/eap_server/eap_tls_common.h4
-rw-r--r--contrib/wpa/src/eap_server/ikev2.c4
-rw-r--r--contrib/wpa/src/eap_server/tncs.c79
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_dump.c268
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm.c107
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm.h16
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h8
-rw-r--r--contrib/wpa/src/eapol_supp/eapol_supp_sm.c275
-rw-r--r--contrib/wpa/src/eapol_supp/eapol_supp_sm.h60
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet.h30
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_freebsd.c19
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_ndis.c19
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_none.c22
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_privsep.c36
-rw-r--r--contrib/wpa/src/p2p/p2p.c2296
-rw-r--r--contrib/wpa/src/p2p/p2p.h514
-rw-r--r--contrib/wpa/src/p2p/p2p_build.c348
-rw-r--r--contrib/wpa/src/p2p/p2p_dev_disc.c88
-rw-r--r--contrib/wpa/src/p2p/p2p_go_neg.c655
-rw-r--r--contrib/wpa/src/p2p/p2p_group.c214
-rw-r--r--contrib/wpa/src/p2p/p2p_i.h192
-rw-r--r--contrib/wpa/src/p2p/p2p_invitation.c382
-rw-r--r--contrib/wpa/src/p2p/p2p_parse.c186
-rw-r--r--contrib/wpa/src/p2p/p2p_pd.c858
-rw-r--r--contrib/wpa/src/p2p/p2p_sd.c328
-rw-r--r--contrib/wpa/src/p2p/p2p_utils.c422
-rw-r--r--contrib/wpa/src/pae/Makefile8
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_cp.c744
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_cp.h50
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay.c3541
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay.h194
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay_i.h419
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_key.c189
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_key.h26
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_secy_ops.c492
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_secy_ops.h62
-rw-r--r--contrib/wpa/src/radius/radius.c225
-rw-r--r--contrib/wpa/src/radius/radius.h39
-rw-r--r--contrib/wpa/src/radius/radius_client.c371
-rw-r--r--contrib/wpa/src/radius/radius_das.c60
-rw-r--r--contrib/wpa/src/radius/radius_das.h12
-rw-r--r--contrib/wpa/src/radius/radius_server.c717
-rw-r--r--contrib/wpa/src/radius/radius_server.h31
-rw-r--r--contrib/wpa/src/rsn_supp/peerkey.c189
-rw-r--r--contrib/wpa/src/rsn_supp/peerkey.h13
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.c79
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.h16
-rw-r--r--contrib/wpa/src/rsn_supp/preauth.c54
-rw-r--r--contrib/wpa/src/rsn_supp/preauth.h6
-rw-r--r--contrib/wpa/src/rsn_supp/tdls.c1155
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.c842
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.h83
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ft.c99
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_i.h84
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.c168
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.h16
-rw-r--r--contrib/wpa/src/tls/asn1.c33
-rw-r--r--contrib/wpa/src/tls/asn1.h6
-rw-r--r--contrib/wpa/src/tls/libtommath.c12
-rw-r--r--contrib/wpa/src/tls/pkcs1.c165
-rw-r--r--contrib/wpa/src/tls/pkcs1.h7
-rw-r--r--contrib/wpa/src/tls/rsa.c25
-rw-r--r--contrib/wpa/src/tls/rsa.h3
-rw-r--r--contrib/wpa/src/tls/tlsv1_client.c52
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_read.c124
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_write.c38
-rw-r--r--contrib/wpa/src/tls/tlsv1_common.c178
-rw-r--r--contrib/wpa/src/tls/tlsv1_common.h13
-rw-r--r--contrib/wpa/src/tls/tlsv1_record.c2
-rw-r--r--contrib/wpa/src/tls/tlsv1_server.c226
-rw-r--r--contrib/wpa/src/tls/tlsv1_server.h5
-rw-r--r--contrib/wpa/src/tls/tlsv1_server_i.h13
-rw-r--r--contrib/wpa/src/tls/tlsv1_server_read.c438
-rw-r--r--contrib/wpa/src/tls/tlsv1_server_write.c193
-rw-r--r--contrib/wpa/src/tls/x509v3.c26
-rw-r--r--contrib/wpa/src/utils/base64.c18
-rw-r--r--contrib/wpa/src/utils/bitfield.c89
-rw-r--r--contrib/wpa/src/utils/bitfield.h21
-rw-r--r--contrib/wpa/src/utils/browser-android.c128
-rw-r--r--contrib/wpa/src/utils/browser-system.c119
-rw-r--r--contrib/wpa/src/utils/browser-wpadebug.c136
-rw-r--r--contrib/wpa/src/utils/browser.c219
-rw-r--r--contrib/wpa/src/utils/browser.h21
-rw-r--r--contrib/wpa/src/utils/build_config.h27
-rw-r--r--contrib/wpa/src/utils/common.c496
-rw-r--r--contrib/wpa/src/utils/common.h213
-rw-r--r--contrib/wpa/src/utils/edit.c4
-rw-r--r--contrib/wpa/src/utils/edit_readline.c4
-rw-r--r--contrib/wpa/src/utils/edit_simple.c2
-rw-r--r--contrib/wpa/src/utils/eloop.c333
-rw-r--r--contrib/wpa/src/utils/eloop.h49
-rw-r--r--contrib/wpa/src/utils/eloop_none.c395
-rw-r--r--contrib/wpa/src/utils/eloop_win.c224
-rw-r--r--contrib/wpa/src/utils/ext_password_test.c2
-rw-r--r--contrib/wpa/src/utils/http-utils.h63
-rw-r--r--contrib/wpa/src/utils/http_curl.c1641
-rw-r--r--contrib/wpa/src/utils/ip_addr.c24
-rw-r--r--contrib/wpa/src/utils/ip_addr.h1
-rw-r--r--contrib/wpa/src/utils/list.h2
-rw-r--r--contrib/wpa/src/utils/os.h158
-rw-r--r--contrib/wpa/src/utils/os_internal.c89
-rw-r--r--contrib/wpa/src/utils/os_none.c17
-rw-r--r--contrib/wpa/src/utils/os_unix.c232
-rw-r--r--contrib/wpa/src/utils/os_win32.c32
-rw-r--r--contrib/wpa/src/utils/pcsc_funcs.c117
-rw-r--r--contrib/wpa/src/utils/pcsc_funcs.h11
-rw-r--r--contrib/wpa/src/utils/platform.h21
-rw-r--r--contrib/wpa/src/utils/radiotap.c379
-rw-r--r--contrib/wpa/src/utils/radiotap.h56
-rw-r--r--contrib/wpa/src/utils/radiotap_iter.h108
-rw-r--r--contrib/wpa/src/utils/trace.c62
-rw-r--r--contrib/wpa/src/utils/trace.h1
-rw-r--r--contrib/wpa/src/utils/utils_module_tests.c423
-rw-r--r--contrib/wpa/src/utils/uuid.c2
-rw-r--r--contrib/wpa/src/utils/wpa_debug.c132
-rw-r--r--contrib/wpa/src/utils/wpa_debug.h68
-rw-r--r--contrib/wpa/src/utils/wpabuf.c9
-rw-r--r--contrib/wpa/src/utils/wpabuf.h1
-rw-r--r--contrib/wpa/src/utils/xml-utils.c471
-rw-r--r--contrib/wpa/src/utils/xml-utils.h97
-rw-r--r--contrib/wpa/src/utils/xml_libxml2.c457
-rw-r--r--contrib/wpa/src/wps/http_client.c2
-rw-r--r--contrib/wpa/src/wps/http_server.c10
-rw-r--r--contrib/wpa/src/wps/httpread.c54
-rw-r--r--contrib/wpa/src/wps/ndef.c89
-rw-r--r--contrib/wpa/src/wps/wps.c78
-rw-r--r--contrib/wpa/src/wps/wps.h102
-rw-r--r--contrib/wpa/src/wps/wps_attr_build.c104
-rw-r--r--contrib/wpa/src/wps/wps_attr_parse.c43
-rw-r--r--contrib/wpa/src/wps/wps_attr_parse.h7
-rw-r--r--contrib/wpa/src/wps/wps_attr_process.c77
-rw-r--r--contrib/wpa/src/wps/wps_common.c360
-rw-r--r--contrib/wpa/src/wps/wps_defs.h69
-rw-r--r--contrib/wpa/src/wps/wps_dev_attr.c51
-rw-r--r--contrib/wpa/src/wps/wps_dev_attr.h6
-rw-r--r--contrib/wpa/src/wps/wps_enrollee.c234
-rw-r--r--contrib/wpa/src/wps/wps_er.c211
-rw-r--r--contrib/wpa/src/wps/wps_er.h1
-rw-r--r--contrib/wpa/src/wps/wps_er_ssdp.c4
-rw-r--r--contrib/wpa/src/wps/wps_i.h23
-rw-r--r--contrib/wpa/src/wps/wps_module_tests.c337
-rw-r--r--contrib/wpa/src/wps/wps_registrar.c346
-rw-r--r--contrib/wpa/src/wps/wps_upnp.c56
-rw-r--r--contrib/wpa/src/wps/wps_upnp_ap.c8
-rw-r--r--contrib/wpa/src/wps/wps_upnp_i.h3
-rw-r--r--contrib/wpa/src/wps/wps_upnp_ssdp.c32
-rw-r--r--contrib/wpa/src/wps/wps_upnp_web.c49
-rw-r--r--contrib/wpa/src/wps/wps_validate.c4
-rw-r--r--contrib/wpa/wpa_supplicant/ChangeLog372
-rw-r--r--contrib/wpa/wpa_supplicant/README132
-rw-r--r--contrib/wpa/wpa_supplicant/README-HS2095
-rw-r--r--contrib/wpa/wpa_supplicant/README-P2P308
-rw-r--r--contrib/wpa/wpa_supplicant/README-WPS80
-rw-r--r--contrib/wpa/wpa_supplicant/ap.c522
-rw-r--r--contrib/wpa/wpa_supplicant/ap.h42
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan.c6
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan.h5
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan_learn.c42
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan_simple.c12
-rw-r--r--contrib/wpa/wpa_supplicant/bss.c278
-rw-r--r--contrib/wpa/wpa_supplicant/bss.h31
-rw-r--r--contrib/wpa/wpa_supplicant/config.c1694
-rw-r--r--contrib/wpa/wpa_supplicant/config.h382
-rw-r--r--contrib/wpa/wpa_supplicant/config_file.c368
-rw-r--r--contrib/wpa/wpa_supplicant/config_none.c9
-rw-r--r--contrib/wpa/wpa_supplicant/config_ssid.h162
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface.c4708
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface.h8
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c2
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_udp.c131
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_unix.c710
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/Makefile2
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_common.c59
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c301
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h30
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new.c1087
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new.h44
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c1408
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h48
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c939
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h48
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c205
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c328
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h18
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c17
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old.c118
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old.h9
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c472
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h6
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c29
-rw-r--r--contrib/wpa/wpa_supplicant/defconfig122
-rw-r--r--contrib/wpa/wpa_supplicant/driver_i.h465
-rw-r--r--contrib/wpa/wpa_supplicant/eap_proxy_dummy.mak0
-rw-r--r--contrib/wpa/wpa_supplicant/eap_proxy_dummy.mk0
-rw-r--r--contrib/wpa/wpa_supplicant/eap_register.c12
-rw-r--r--contrib/wpa/wpa_supplicant/eapol_test.c169
-rw-r--r--contrib/wpa/wpa_supplicant/events.c1699
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/p2p-action.sh15
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/p2p-nfc.py654
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wps-ap-cli9
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wps-nfc.py485
-rw-r--r--contrib/wpa/wpa_supplicant/gas_query.c262
-rw-r--r--contrib/wpa/wpa_supplicant/gas_query.h3
-rw-r--r--contrib/wpa/wpa_supplicant/hs20_supplicant.c846
-rw-r--r--contrib/wpa/wpa_supplicant/hs20_supplicant.h27
-rw-r--r--contrib/wpa/wpa_supplicant/ibss_rsn.c318
-rw-r--r--contrib/wpa/wpa_supplicant/ibss_rsn.h20
-rw-r--r--contrib/wpa/wpa_supplicant/interworking.c1566
-rw-r--r--contrib/wpa/wpa_supplicant/interworking.h10
-rw-r--r--contrib/wpa/wpa_supplicant/main.c56
-rw-r--r--contrib/wpa/wpa_supplicant/main_none.c2
-rw-r--r--contrib/wpa/wpa_supplicant/mesh.c540
-rw-r--r--contrib/wpa/wpa_supplicant/mesh.h44
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_mpm.c1059
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_mpm.h43
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_rsn.c574
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_rsn.h36
-rw-r--r--contrib/wpa/wpa_supplicant/notify.c217
-rw-r--r--contrib/wpa/wpa_supplicant/notify.h8
-rw-r--r--contrib/wpa/wpa_supplicant/offchannel.c80
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant.c5402
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant.h273
-rw-r--r--contrib/wpa/wpa_supplicant/preauth_test.c5
-rw-r--r--contrib/wpa/wpa_supplicant/scan.c1307
-rw-r--r--contrib/wpa/wpa_supplicant/scan.h24
-rw-r--r--contrib/wpa/wpa_supplicant/sme.c629
-rw-r--r--contrib/wpa/wpa_supplicant/sme.h9
-rw-r--r--contrib/wpa/wpa_supplicant/tests/test_wpa.c8
-rw-r--r--contrib/wpa/wpa_supplicant/todo.txt13
-rw-r--r--contrib/wpa/wpa_supplicant/wifi_display.c173
-rw-r--r--contrib/wpa/wpa_supplicant/wifi_display.h4
-rw-r--r--contrib/wpa/wpa_supplicant/wmm_ac.c995
-rw-r--r--contrib/wpa/wpa_supplicant/wmm_ac.h176
-rw-r--r--contrib/wpa/wpa_supplicant/wnm_sta.c809
-rw-r--r--contrib/wpa/wpa_supplicant/wnm_sta.h62
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_cli.c944
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_priv.c37
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant.c2503
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant.conf369
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant_i.h415
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf2
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_glue.c273
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_kay.c378
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_kay.h41
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_module_tests.c108
-rw-r--r--contrib/wpa/wpa_supplicant/wps_supplicant.c1130
-rw-r--r--contrib/wpa/wpa_supplicant/wps_supplicant.h29
-rw-r--r--contrib/xz/ChangeLog230
-rw-r--r--contrib/xz/THANKS3
-rw-r--r--contrib/xz/src/common/tuklib_cpucores.c18
-rw-r--r--contrib/xz/src/common/tuklib_integer.h24
-rw-r--r--contrib/xz/src/liblzma/api/lzma/version.h2
-rw-r--r--contrib/xz/src/liblzma/common/memcmplen.h15
-rw-r--r--contrib/xz/src/liblzma/lz/lz_encoder.c6
-rw-r--r--contrib/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c2
-rw-r--r--contrib/xz/src/xz/file_io.c85
-rw-r--r--etc/Makefile51
-rw-r--r--etc/defaults/rc.conf5
-rw-r--r--etc/login.conf6
-rw-r--r--etc/mtree/BSD.include.dist4
-rw-r--r--etc/mtree/BSD.tests.dist18
-rw-r--r--etc/mtree/BSD.usr.dist8
-rw-r--r--etc/rc.d/Makefile4
-rwxr-xr-xetc/rc.d/devd2
-rwxr-xr-xetc/rc.d/hostid64
-rwxr-xr-xetc/rc.d/hostid_save15
-rwxr-xr-xetc/rc.d/mountd6
-rwxr-xr-xetc/rc.d/nfsd51
-rwxr-xr-xetc/rc.d/pflog70
-rw-r--r--etc/rc.d/tests/Makefile (renamed from etc/tests/rc.d/Makefile)0
-rwxr-xr-xetc/rc.d/tests/routing_test.sh (renamed from etc/tests/rc.d/routing_test.sh)0
-rw-r--r--etc/tests/Makefile2
-rw-r--r--gnu/lib/libgomp/Makefile2
-rw-r--r--gnu/lib/libgomp/config.h6
-rw-r--r--gnu/usr.bin/cc/Makefile5
-rw-r--r--gnu/usr.bin/groff/src/preproc/Makefile2
-rw-r--r--include/Makefile11
-rw-r--r--include/iconv.h4
-rw-r--r--include/pthread.h147
-rw-r--r--include/signal.h6
-rw-r--r--include/stdlib.h16
-rw-r--r--lib/libarchive/Makefile2
-rw-r--r--lib/libarchive/config_freebsd.h7
-rw-r--r--lib/libbluetooth/bluetooth.c2
-rw-r--r--lib/libbluetooth/dev.c1
-rw-r--r--lib/libbluetooth/hci.c1
-rw-r--r--lib/libc/Makefile9
-rw-r--r--lib/libc/Makefile.amd646
-rw-r--r--lib/libc/Makefile.i3866
-rw-r--r--lib/libc/aarch64/Makefile.inc4
-rw-r--r--lib/libc/aarch64/SYS.h63
-rw-r--r--lib/libc/aarch64/Symbol.map29
-rw-r--r--lib/libc/aarch64/_fpmath.h58
-rw-r--r--lib/libc/aarch64/arith.h19
-rw-r--r--lib/libc/aarch64/gd_qnan.h21
-rw-r--r--lib/libc/aarch64/gen/Makefile.inc9
-rw-r--r--lib/libc/aarch64/gen/_set_tp.c (renamed from lib/libc/sys/lseek.c)40
-rw-r--r--lib/libc/aarch64/gen/_setjmp.S105
-rw-r--r--lib/libc/aarch64/gen/flt_rounds.c (renamed from lib/libc/sys/pread.c)48
-rw-r--r--lib/libc/aarch64/gen/setjmp.S123
-rw-r--r--lib/libc/aarch64/gen/sigsetjmp.S53
-rw-r--r--lib/libc/aarch64/sys/Makefile.inc25
-rw-r--r--lib/libc/aarch64/sys/brk.S93
-rw-r--r--lib/libc/aarch64/sys/cerror.S41
-rw-r--r--lib/libc/aarch64/sys/pipe.S52
-rw-r--r--lib/libc/aarch64/sys/sbrk.S79
-rw-r--r--lib/libc/aarch64/sys/shmat.S35
-rw-r--r--lib/libc/aarch64/sys/sigreturn.S35
-rw-r--r--lib/libc/aarch64/sys/syscall.S35
-rw-r--r--lib/libc/aarch64/sys/vfork.S42
-rw-r--r--lib/libc/amd64/sys/Makefile.inc3
-rw-r--r--lib/libc/arm/sys/Makefile.inc3
-rw-r--r--lib/libc/gen/_once_stub.c2
-rw-r--r--lib/libc/gen/fts.c11
-rw-r--r--lib/libc/gen/getutxent.32
-rw-r--r--lib/libc/gen/nice.32
-rw-r--r--lib/libc/gen/posix_spawn.32
-rw-r--r--lib/libc/gen/posix_spawn_file_actions_addopen.32
-rw-r--r--lib/libc/gen/posix_spawn_file_actions_init.32
-rw-r--r--lib/libc/gen/posix_spawnattr_getflags.32
-rw-r--r--lib/libc/gen/posix_spawnattr_getpgroup.32
-rw-r--r--lib/libc/gen/posix_spawnattr_getschedparam.32
-rw-r--r--lib/libc/gen/posix_spawnattr_getschedpolicy.32
-rw-r--r--lib/libc/gen/posix_spawnattr_getsigdefault.32
-rw-r--r--lib/libc/gen/posix_spawnattr_getsigmask.32
-rw-r--r--lib/libc/gen/posix_spawnattr_init.32
-rw-r--r--lib/libc/gen/setproctitle.c73
-rw-r--r--lib/libc/gen/tls.c5
-rw-r--r--lib/libc/gen/waitid.c5
-rw-r--r--lib/libc/i386/sys/Makefile.inc3
-rw-r--r--lib/libc/iconv/__iconv.c2
-rw-r--r--lib/libc/iconv/bsd_iconv.c4
-rw-r--r--lib/libc/iconv/citrus_iconv.h2
-rw-r--r--lib/libc/iconv/citrus_iconv_local.h4
-rw-r--r--lib/libc/iconv/citrus_none.c4
-rw-r--r--lib/libc/iconv/citrus_prop.c4
-rw-r--r--lib/libc/iconv/citrus_stdenc.h2
-rw-r--r--lib/libc/iconv/citrus_stdenc_local.h8
-rw-r--r--lib/libc/iconv/citrus_stdenc_template.h4
-rw-r--r--lib/libc/iconv/iconv-internal.h4
-rw-r--r--lib/libc/iconv/iconv.32
-rw-r--r--lib/libc/iconv/iconv.c2
-rw-r--r--lib/libc/iconv/iconv_compat.c4
-rw-r--r--lib/libc/include/compat.h4
-rw-r--r--lib/libc/include/libc_private.h19
-rw-r--r--lib/libc/locale/cXXrtomb_iconv.h3
-rw-r--r--lib/libc/locale/duplocale.32
-rw-r--r--lib/libc/locale/freelocale.32
-rw-r--r--lib/libc/locale/mbrtocXX_iconv.h3
-rw-r--r--lib/libc/locale/newlocale.32
-rw-r--r--lib/libc/locale/none.c2
-rw-r--r--lib/libc/locale/querylocale.32
-rw-r--r--lib/libc/locale/uselocale.32
-rw-r--r--lib/libc/mips/sys/Makefile.inc6
-rw-r--r--lib/libc/net/getaddrinfo.c1
-rw-r--r--lib/libc/net/name6.c1
-rw-r--r--lib/libc/net/sctp_recvmsg.36
-rw-r--r--lib/libc/nls/catopen.32
-rw-r--r--lib/libc/powerpc/gen/_setjmp.S72
-rw-r--r--lib/libc/powerpc/gen/setjmp.S72
-rw-r--r--lib/libc/powerpc/gen/sigsetjmp.S72
-rw-r--r--lib/libc/powerpc/sys/Makefile.inc3
-rw-r--r--lib/libc/powerpc64/sys/Makefile.inc3
-rw-r--r--lib/libc/regex/re_format.76
-rw-r--r--lib/libc/regex/regcomp.c4
-rw-r--r--lib/libc/regex/regex.36
-rw-r--r--lib/libc/rpc/rpcbind.32
-rw-r--r--lib/libc/sparc64/sys/Makefile.inc3
-rw-r--r--lib/libc/stdio/flags.c4
-rw-r--r--lib/libc/stdio/open_memstream.32
-rw-r--r--lib/libc/stdio/open_memstream.c2
-rw-r--r--lib/libc/stdio/open_wmemstream.c2
-rw-r--r--lib/libc/stdlib/Makefile.inc5
-rw-r--r--lib/libc/stdlib/Symbol.map1
-rw-r--r--lib/libc/stdlib/reallocarray.3137
-rw-r--r--lib/libc/stdlib/reallocarray.c42
-rw-r--r--lib/libc/string/strlcat.c48
-rw-r--r--lib/libc/string/strlcpy.c37
-rw-r--r--lib/libc/sys/Makefile.inc14
-rw-r--r--lib/libc/sys/closefrom.22
-rw-r--r--lib/libc/sys/fcntl.c62
-rw-r--r--lib/libc/sys/fork.27
-rw-r--r--lib/libc/sys/interposing_table.c4
-rw-r--r--lib/libc/sys/mount.27
-rw-r--r--lib/libc/sys/posix_openpt.22
-rw-r--r--lib/libc/sys/ppoll.c51
-rw-r--r--lib/libc/sys/procctl.22
-rw-r--r--lib/libc/sys/pwrite.c56
-rw-r--r--lib/libc/sys/vfork.24
-rw-r--r--lib/libc/sys/wait6.c52
-rw-r--r--lib/libc/tests/db/Makefile1
-rw-r--r--lib/libc/tests/sys/Makefile2
-rw-r--r--lib/libc/xdr/xdr_float.c3
-rw-r--r--lib/libcapsicum/libcapsicum.318
-rw-r--r--lib/libcapsicum/libcapsicum.c14
-rw-r--r--lib/libcapsicum/libcapsicum.h4
-rw-r--r--lib/libcapsicum/libcapsicum_dns.c44
-rw-r--r--lib/libcapsicum/libcapsicum_grp.c35
-rw-r--r--lib/libcapsicum/libcapsicum_pwd.c22
-rw-r--r--lib/libcapsicum/libcapsicum_random.c2
-rw-r--r--lib/libcapsicum/libcapsicum_service.c2
-rw-r--r--lib/libcapsicum/libcapsicum_sysctl.c2
-rw-r--r--lib/libcasper/libcasper.c4
-rw-r--r--lib/libcompiler_rt/Makefile38
-rw-r--r--lib/libedit/el.c2
-rw-r--r--lib/libelftc/elftc_version.c2
-rw-r--r--lib/libgeom/geom_xml2tree.c1
-rw-r--r--lib/libiconv_modules/BIG5/citrus_big5.c4
-rw-r--r--lib/libiconv_modules/DECHanyu/citrus_dechanyu.c4
-rw-r--r--lib/libiconv_modules/EUC/citrus_euc.c4
-rw-r--r--lib/libiconv_modules/EUCTW/citrus_euctw.c4
-rw-r--r--lib/libiconv_modules/GBK2K/citrus_gbk2k.c4
-rw-r--r--lib/libiconv_modules/HZ/citrus_hz.c4
-rw-r--r--lib/libiconv_modules/ISO2022/citrus_iso2022.c6
-rw-r--r--lib/libiconv_modules/JOHAB/citrus_johab.c4
-rw-r--r--lib/libiconv_modules/MSKanji/citrus_mskanji.c4
-rw-r--r--lib/libiconv_modules/UES/citrus_ues.c4
-rw-r--r--lib/libiconv_modules/UTF1632/citrus_utf1632.c4
-rw-r--r--lib/libiconv_modules/UTF7/citrus_utf7.c6
-rw-r--r--lib/libiconv_modules/UTF8/citrus_utf8.c4
-rw-r--r--lib/libiconv_modules/VIQR/citrus_viqr.c4
-rw-r--r--lib/libiconv_modules/ZW/citrus_zw.c4
-rw-r--r--lib/libiconv_modules/iconv_none/citrus_iconv_none.c2
-rw-r--r--lib/libiconv_modules/iconv_std/citrus_iconv_std.c6
-rw-r--r--lib/libkiconv/xlat16_iconv.c19
-rw-r--r--lib/liblzma/Symbol.map12
-rw-r--r--lib/liblzma/config.h410
-rw-r--r--lib/libmandoc/Makefile2
-rw-r--r--lib/libmd/mdXhl.c2
-rw-r--r--lib/libmt/Makefile3
-rw-r--r--lib/libmt/mt.31
-rw-r--r--lib/libnv/Makefile175
-rw-r--r--lib/libnv/nv.361
-rw-r--r--lib/libnv/tests/dnv_tests.cc38
-rw-r--r--lib/libnv/tests/nv_tests.cc75
-rw-r--r--lib/libnv/tests/nvlist_send_recv_test.c2
-rw-r--r--lib/libpmc/libpmc.c45
-rw-r--r--lib/libpmc/pmc.haswellxeon.32
-rw-r--r--lib/librt/Makefile4
-rw-r--r--lib/librt/Makefile.amd646
-rw-r--r--lib/librt/Makefile.i3866
-rw-r--r--lib/libsdp/search.c1
-rw-r--r--lib/libsdp/service.c1
-rw-r--r--lib/libsdp/session.c5
-rw-r--r--lib/libsdp/util.c1
-rw-r--r--lib/libstand/Makefile38
-rw-r--r--lib/libthr/Makefile6
-rw-r--r--lib/libthr/Makefile.amd646
-rw-r--r--lib/libthr/Makefile.i3866
-rw-r--r--lib/libthr/tests/Makefile2
-rw-r--r--lib/libthr/thread/thr_clean.c2
-rw-r--r--lib/libthr/thread/thr_syscalls.c53
-rw-r--r--lib/libvmmapi/Makefile2
-rw-r--r--lib/libxo/Makefile2
-rw-r--r--lib/msun/Makefile4
-rw-r--r--lib/msun/Makefile.amd646
-rw-r--r--lib/msun/Makefile.i3866
-rw-r--r--lib/msun/man/j0.36
-rw-r--r--lib/msun/man/lgamma.31
-rw-r--r--lib/msun/man/nextafter.34
-rw-r--r--lib/msun/tests/Makefile9
-rw-r--r--libexec/casper/dns/dns.c27
-rw-r--r--libexec/casper/grp/grp.c9
-rw-r--r--libexec/getty/subr.c14
-rw-r--r--libexec/rtld-elf/aarch64/reloc.c4
-rw-r--r--libexec/rtld-elf/mips/reloc.c2
-rw-r--r--libexec/rtld-elf/rtld.c132
-rw-r--r--libexec/rtld-elf/rtld.h1
-rw-r--r--release/Makefile.ec216
-rw-r--r--release/arm/BEAGLEBONE.conf2
-rw-r--r--release/arm/PANDABOARD.conf2
-rw-r--r--release/arm/RPI-B.conf2
-rw-r--r--release/arm/WANDBOARD-QUAD.conf2
-rw-r--r--release/arm/ZEDBOARD.conf2
-rwxr-xr-xrelease/arm64/make-memstick.sh41
-rw-r--r--release/doc/en_US.ISO8859-1/relnotes/article.xml139
-rw-r--r--release/doc/share/xml/release.ent1
-rw-r--r--release/doc/share/xml/sponsor.ent6
-rw-r--r--release/release.conf.sample1
-rwxr-xr-xrelease/release.sh2
-rwxr-xr-xrelease/scripts/mk-vmimage.sh10
-rw-r--r--release/tools/vmimage.subr34
-rw-r--r--sbin/atm/atmconfig/atmconfig.84
-rw-r--r--sbin/camcontrol/camcontrol.87
-rw-r--r--sbin/casperd/casperd.c2
-rw-r--r--sbin/casperd/zygote.c4
-rw-r--r--sbin/dmesg/dmesg.c3
-rw-r--r--sbin/ggate/ggatel/ggatel.826
-rw-r--r--sbin/growfs/Makefile6
-rw-r--r--sbin/growfs/growfs.c4
-rw-r--r--sbin/ifconfig/af_inet.c1
-rw-r--r--sbin/ifconfig/af_inet6.c1
-rw-r--r--sbin/ifconfig/af_nd6.c1
-rw-r--r--sbin/ifconfig/carp.c1
-rw-r--r--sbin/ifconfig/ifconfig.c1
-rw-r--r--sbin/ifconfig/ifmedia.c32
-rw-r--r--sbin/ifconfig/ifvlan.c1
-rw-r--r--sbin/ifconfig/ifvxlan.c1
-rw-r--r--sbin/ipfw/ipfw2.c125
-rw-r--r--sbin/ipfw/ipfw2.h2
-rw-r--r--sbin/ipfw/nat.c5
-rw-r--r--sbin/ipfw/tables.c67
-rw-r--r--sbin/mount/mount.81
-rw-r--r--sbin/mount/mount.c2
-rw-r--r--sbin/mount_nfs/Makefile3
-rw-r--r--sbin/mount_nfs/mount_nfs.86
-rw-r--r--sbin/newfs_msdos/newfs_msdos.84
-rw-r--r--sbin/pfctl/parse.y8
-rw-r--r--sbin/pfctl/pfctl.c2
-rw-r--r--sbin/pfctl/pfctl_altq.c8
-rw-r--r--sbin/pfctl/pfctl_qstats.c8
-rw-r--r--share/doc/papers/Makefile1
-rw-r--r--share/doc/papers/bufbio/bio.ms20
-rw-r--r--share/doc/papers/hwpmc/Makefile8
-rw-r--r--share/doc/papers/hwpmc/hwpmc.ms34
-rw-r--r--share/doc/usd/06.bc/bc5
-rw-r--r--share/doc/usd/10.exref/Makefile.inc1
-rw-r--r--share/doc/usd/10.exref/exref/ex.rm (renamed from contrib/nvi/docs/USD.doc/exref/ex.rm)2
-rw-r--r--share/doc/usd/10.exref/summary/ex.summary (renamed from contrib/nvi/docs/USD.doc/exref/ex.summary)0
-rw-r--r--share/doc/usd/11.vitut/Makefile1
-rw-r--r--share/doc/usd/11.vitut/edittut.ms (renamed from contrib/nvi/docs/USD.doc/edit/edittut.ms)0
-rw-r--r--share/doc/usd/12.vi/Makefile.inc1
-rw-r--r--share/doc/usd/12.vi/summary/vi.summary (renamed from contrib/nvi/docs/USD.doc/vitut/vi.summary)0
-rw-r--r--share/doc/usd/12.vi/vi/vi.chars (renamed from contrib/nvi/docs/USD.doc/vitut/vi.chars)0
-rw-r--r--share/doc/usd/12.vi/vi/vi.in (renamed from contrib/nvi/docs/USD.doc/vitut/vi.in)0
-rw-r--r--share/doc/usd/12.vi/viapwh/vi.apwh.ms (renamed from contrib/nvi/docs/USD.doc/vitut/vi.apwh.ms)0
-rw-r--r--share/doc/usd/13.viref/Makefile1
-rw-r--r--share/doc/usd/13.viref/ex.cmd.roff (renamed from contrib/nvi/docs/USD.doc/vi.ref/ex.cmd.roff)0
-rw-r--r--share/doc/usd/13.viref/ref.so (renamed from contrib/nvi/docs/USD.doc/vi.ref/ref.so)0
-rw-r--r--share/doc/usd/13.viref/set.opt.roff (renamed from contrib/nvi/docs/USD.doc/vi.ref/set.opt.roff)0
-rw-r--r--share/doc/usd/13.viref/vi.cmd.roff (renamed from contrib/nvi/docs/USD.doc/vi.ref/vi.cmd.roff)0
-rw-r--r--share/doc/usd/13.viref/vi.ref (renamed from contrib/nvi/docs/USD.doc/vi.ref/vi.ref)0
-rw-r--r--share/doc/usd/18.msdiffs/ms.diffs1
-rw-r--r--share/doc/usd/22.trofftut/tt001
-rw-r--r--share/doc/usd/contents/contents.ms1
-rwxr-xr-xshare/dtrace/siftr68
-rw-r--r--share/man/man3/pthread_testcancel.35
-rw-r--r--share/man/man3/queue.34
-rw-r--r--share/man/man4/Makefile15
-rw-r--r--share/man/man4/ada.41
-rw-r--r--share/man/man4/amdtemp.42
-rw-r--r--share/man/man4/ata.41
-rw-r--r--share/man/man4/ctl.43
-rw-r--r--share/man/man4/dtrace-io.4123
-rw-r--r--share/man/man4/dtrace-ip.4285
-rw-r--r--share/man/man4/dtrace-proc.4264
-rw-r--r--share/man/man4/dtrace-sched.4227
-rw-r--r--share/man/man4/dtrace-tcp.4400
-rw-r--r--share/man/man4/dtrace-udp.4199
-rw-r--r--share/man/man4/inet.416
-rw-r--r--share/man/man4/run.43
-rw-r--r--share/man/man4/smb.4168
-rw-r--r--share/man/man4/tap.46
-rw-r--r--share/man/man4/urtwn.42
-rw-r--r--share/man/man4/xen.448
-rw-r--r--share/man/man5/rc.conf.58
-rw-r--r--share/man/man5/src.conf.59
-rw-r--r--share/man/man9/BUS_BIND_INTR.92
-rw-r--r--share/man/man9/BUS_CHILD_DELETED.92
-rw-r--r--share/man/man9/BUS_CHILD_DETACHED.92
-rw-r--r--share/man/man9/BUS_DESCRIBE_INTR.92
-rw-r--r--share/man/man9/BUS_NEW_PASS.92
-rw-r--r--share/man/man9/Makefile1
-rw-r--r--share/man/man9/SDT.942
-rw-r--r--share/man/man9/VOP_ADVISE.92
-rw-r--r--share/man/man9/VOP_ALLOCATE.92
-rw-r--r--share/man/man9/bus_adjust_resource.92
-rw-r--r--share/man/man9/bus_generic_new_pass.92
-rw-r--r--share/man/man9/bus_set_pass.92
-rw-r--r--share/man/man9/getenv.92
-rw-r--r--share/man/man9/panic.98
-rw-r--r--share/man/man9/printf.93
-rw-r--r--share/man/man9/refcount.92
-rw-r--r--share/man/man9/sglist.92
-rw-r--r--share/man/man9/shm_map.92
-rw-r--r--share/misc/committers-src.dot2
-rw-r--r--share/mk/bsd.dep.mk8
-rw-r--r--share/mk/src.libnames.mk15
-rw-r--r--share/mk/src.opts.mk7
-rw-r--r--share/mk/sys.mk14
-rw-r--r--sys/amd64/amd64/apic_vector.S16
-rw-r--r--sys/amd64/amd64/machdep.c378
-rw-r--r--sys/amd64/amd64/mp_machdep.c1034
-rw-r--r--sys/amd64/amd64/pmap.c2
-rw-r--r--sys/amd64/conf/GENERIC4
-rw-r--r--sys/amd64/conf/NOTES2
-rw-r--r--sys/amd64/include/md_var.h1
-rw-r--r--sys/amd64/include/metadata.h10
-rw-r--r--sys/amd64/include/smp.h39
-rw-r--r--sys/amd64/include/vm.h2
-rw-r--r--sys/amd64/include/vmm.h6
-rw-r--r--sys/amd64/include/xen/xenfunc.h9
-rw-r--r--sys/amd64/include/xen/xenpmap.h227
-rw-r--r--sys/amd64/include/xen/xenvar.h61
-rw-r--r--sys/amd64/vmm/amd/amdv.c1
-rw-r--r--sys/amd64/vmm/amd/svm.c3
-rw-r--r--sys/amd64/vmm/amd/svm_msr.c31
-rw-r--r--sys/amd64/vmm/amd/vmcb.c1
-rw-r--r--sys/amd64/vmm/intel/vmx_msr.c23
-rw-r--r--sys/amd64/vmm/io/vatpic.c1
-rw-r--r--sys/amd64/vmm/io/vatpit.c1
-rw-r--r--sys/amd64/vmm/io/vhpet.c1
-rw-r--r--sys/amd64/vmm/io/vioapic.c1
-rw-r--r--sys/amd64/vmm/io/vlapic.c20
-rw-r--r--sys/amd64/vmm/io/vpmtmr.c1
-rw-r--r--sys/amd64/vmm/io/vrtc.c118
-rw-r--r--sys/amd64/vmm/vmm.c8
-rw-r--r--sys/amd64/vmm/vmm_instruction_emul.c251
-rw-r--r--sys/amd64/vmm/vmm_ioport.c6
-rw-r--r--sys/amd64/vmm/vmm_lapic.c6
-rw-r--r--sys/amd64/vmm/vmm_stat.c1
-rw-r--r--sys/amd64/vmm/x86.c22
-rw-r--r--sys/arm/allwinner/a10_clk.c1
-rw-r--r--sys/arm/allwinner/a10_clk.h162
-rw-r--r--sys/arm/allwinner/a10_common.c1
-rw-r--r--sys/arm/allwinner/a10_gpio.c1
-rw-r--r--sys/arm/allwinner/a10_sramc.c1
-rw-r--r--sys/arm/allwinner/a10_wdog.c1
-rw-r--r--sys/arm/allwinner/a20/a20_cpu_cfg.c1
-rw-r--r--sys/arm/allwinner/a20/a20_mp.c6
-rw-r--r--sys/arm/allwinner/a20/files.a2014
-rw-r--r--sys/arm/allwinner/a20/std.a201
-rw-r--r--sys/arm/allwinner/files.a1016
-rw-r--r--sys/arm/allwinner/files.allwinner18
-rw-r--r--sys/arm/allwinner/if_emac.c168
-rw-r--r--sys/arm/allwinner/if_emacreg.h5
-rw-r--r--sys/arm/allwinner/std.a103
-rw-r--r--sys/arm/allwinner/timer.c1
-rw-r--r--sys/arm/altera/socfpga/socfpga_gpio.c1
-rw-r--r--sys/arm/altera/socfpga/socfpga_manager.c1
-rw-r--r--sys/arm/altera/socfpga/socfpga_mp.c3
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_clkmsr.c34
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_fb.c3
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_i2c.c2
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_identsoc.c19
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_machdep.c26
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_mmc.c347
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_mmc.h14
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_mp.c3
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_soc.h4
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_timer.c2
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_wdt.c2
-rw-r--r--sys/arm/amlogic/aml8726/files.aml87263
-rw-r--r--sys/arm/amlogic/aml8726/files.smp4
-rw-r--r--sys/arm/amlogic/aml8726/std.aml87269
-rw-r--r--sys/arm/amlogic/aml8726/std.odroidc117
-rw-r--r--sys/arm/amlogic/aml8726/std.vsatv102-m617
-rw-r--r--sys/arm/amlogic/aml8726/uart_dev_aml8726.c32
-rw-r--r--sys/arm/arm/busdma_machdep-v6.c4
-rw-r--r--sys/arm/arm/busdma_machdep.c4
-rw-r--r--sys/arm/arm/cpufunc.c3
-rw-r--r--sys/arm/arm/devmap.c65
-rw-r--r--sys/arm/arm/elf_machdep.c12
-rw-r--r--sys/arm/arm/generic_timer.c50
-rw-r--r--sys/arm/arm/intr.c1
-rw-r--r--sys/arm/arm/locore-v4.S74
-rw-r--r--sys/arm/arm/locore-v6.S125
-rw-r--r--sys/arm/arm/machdep.c2
-rw-r--r--sys/arm/arm/mpcore_timer.c1
-rw-r--r--sys/arm/arm/pmap-v6-new.c42
-rw-r--r--sys/arm/arm/pmap-v6.c30
-rw-r--r--sys/arm/arm/pmap.c34
-rw-r--r--sys/arm/arm/pmu.c1
-rw-r--r--sys/arm/arm/trap-v6.c5
-rw-r--r--sys/arm/arm/vm_machdep.c4
-rw-r--r--sys/arm/at91/at91_common.c7
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_common.c1
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_fb.c416
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_fbd.c264
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_mbox.c177
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h153
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_sdhci.c13
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_spi.c1
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_systimer.c1
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_wdog.c1
-rw-r--r--sys/arm/broadcom/bcm2835/std.bcm28362
-rw-r--r--sys/arm/conf/AML8726143
-rw-r--r--sys/arm/conf/CUBIEBOARD2
-rw-r--r--sys/arm/conf/CUBIEBOARD22
-rw-r--r--sys/arm/conf/EFIKA_MX2
-rw-r--r--sys/arm/conf/IMX532
-rw-r--r--sys/arm/conf/IMX62
-rw-r--r--sys/arm/conf/ODROIDC1121
-rw-r--r--sys/arm/conf/RK31884
-rw-r--r--sys/arm/conf/RPI28
-rw-r--r--sys/arm/conf/VIRT97
-rw-r--r--sys/arm/conf/VSATV102121
-rw-r--r--sys/arm/freescale/imx/files.imx5 (renamed from sys/arm/freescale/imx/files.imx53)5
-rw-r--r--sys/arm/freescale/imx/files.imx5149
-rw-r--r--sys/arm/freescale/imx/imx51_ccm.c1
-rw-r--r--sys/arm/freescale/imx/imx51_ipuv3.c3
-rw-r--r--sys/arm/freescale/imx/imx51_ipuv3_fbd.c1
-rw-r--r--sys/arm/freescale/imx/imx6_anatop.c1
-rw-r--r--sys/arm/freescale/imx/imx6_audmux.c1
-rw-r--r--sys/arm/freescale/imx/imx6_mp.c3
-rw-r--r--sys/arm/freescale/imx/imx6_sdma.c1
-rw-r--r--sys/arm/freescale/imx/imx6_ssi.c1
-rw-r--r--sys/arm/freescale/imx/imx_common.c1
-rw-r--r--sys/arm/freescale/imx/imx_gpt.c1
-rw-r--r--sys/arm/freescale/imx/imx_iomux.c1
-rw-r--r--sys/arm/freescale/imx/imx_wdog.c1
-rw-r--r--sys/arm/freescale/imx/std.imx513
-rw-r--r--sys/arm/freescale/imx/std.imx533
-rw-r--r--sys/arm/freescale/vybrid/vf_adc.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_anadig.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_ccm.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_dcu4.c3
-rw-r--r--sys/arm/freescale/vybrid/vf_dmamux.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_edma.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_gpio.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_i2c.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_iomuxc.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_mscm.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_nfc.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_port.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_sai.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_spi.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_src.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_tcon.c1
-rw-r--r--sys/arm/freescale/vybrid/vf_uart.c4
-rw-r--r--sys/arm/include/fdt.h10
-rw-r--r--sys/arm/include/metadata.h7
-rw-r--r--sys/arm/include/pmap-v6.h3
-rw-r--r--sys/arm/include/pmap.h3
-rw-r--r--sys/arm/mv/armadaxp/armadaxp_mp.c1
-rw-r--r--sys/arm/mv/gpio.c1
-rw-r--r--sys/arm/mv/mv_localbus.c1
-rw-r--r--sys/arm/mv/mv_ts.c1
-rw-r--r--sys/arm/mv/mvvar.h1
-rw-r--r--sys/arm/qemu/files.qemu16
-rw-r--r--sys/arm/qemu/std.virt15
-rw-r--r--sys/arm/qemu/virt_common.c45
-rw-r--r--sys/arm/qemu/virt_machdep.c (renamed from lib/libc/sys/mmap.c)88
-rw-r--r--sys/arm/rockchip/rk30xx_common.c1
-rw-r--r--sys/arm/rockchip/rk30xx_gpio.c1
-rw-r--r--sys/arm/rockchip/rk30xx_grf.c1
-rw-r--r--sys/arm/rockchip/rk30xx_mp.c3
-rw-r--r--sys/arm/rockchip/rk30xx_pmu.c1
-rw-r--r--sys/arm/samsung/exynos/exynos5_mp.c3
-rw-r--r--sys/arm/samsung/exynos/exynos_uart.c1
-rw-r--r--sys/arm/samsung/s3c2xx0/uart_dev_s3c2410.c1
-rw-r--r--sys/arm/ti/am335x/am335x_dmtimer.c1
-rw-r--r--sys/arm/ti/am335x/am335x_prcm.c1
-rw-r--r--sys/arm/ti/omap4/omap4_mp.c3
-rw-r--r--sys/arm/ti/ti_common.c1
-rw-r--r--sys/arm/ti/ti_mbox.c1
-rw-r--r--sys/arm/ti/ti_pruss.c1
-rw-r--r--sys/arm/ti/ti_wdt.c1
-rw-r--r--sys/arm/versatile/pl050.c1
-rw-r--r--sys/arm/versatile/sp804.c1
-rw-r--r--sys/arm/versatile/versatile_clcd.c1
-rw-r--r--sys/arm/versatile/versatile_common.c1
-rw-r--r--sys/arm/versatile/versatile_pci.c4
-rw-r--r--sys/arm/versatile/versatile_timer.c1
-rw-r--r--sys/arm/xilinx/zy7_mp.c3
-rw-r--r--sys/arm64/arm64/autoconf.c90
-rw-r--r--sys/arm64/arm64/bcopy.c139
-rw-r--r--sys/arm64/arm64/bus_machdep.c204
-rw-r--r--sys/arm64/arm64/bus_space_asm.S235
-rw-r--r--sys/arm64/arm64/busdma_machdep.c68
-rw-r--r--sys/arm64/arm64/clock.c39
-rw-r--r--sys/arm64/arm64/copyinout.S118
-rw-r--r--sys/arm64/arm64/copystr.c61
-rw-r--r--sys/arm64/arm64/cpufunc_asm.S154
-rw-r--r--sys/arm64/arm64/db_disasm.c41
-rw-r--r--sys/arm64/arm64/db_interface.c168
-rw-r--r--sys/arm64/arm64/db_trace.c152
-rw-r--r--sys/arm64/arm64/debug_monitor.c487
-rw-r--r--sys/arm64/arm64/dump_machdep.c73
-rw-r--r--sys/arm64/arm64/elf_machdep.c164
-rw-r--r--sys/arm64/arm64/exception.S198
-rw-r--r--sys/arm64/arm64/genassym.c61
-rw-r--r--sys/arm64/arm64/gic.c398
-rw-r--r--sys/arm64/arm64/identcpu.c199
-rw-r--r--sys/arm64/arm64/in_cksum.c241
-rw-r--r--sys/arm64/arm64/intr_machdep.c503
-rw-r--r--sys/arm64/arm64/locore.S544
-rw-r--r--sys/arm64/arm64/machdep.c854
-rw-r--r--sys/arm64/arm64/mem.c47
-rw-r--r--sys/arm64/arm64/minidump_machdep.c50
-rw-r--r--sys/arm64/arm64/nexus.c334
-rw-r--r--sys/arm64/arm64/pic_if.m180
-rw-r--r--sys/arm64/arm64/pmap.c3082
-rw-r--r--sys/arm64/arm64/stack_machdep.c60
-rw-r--r--sys/arm64/arm64/support.S255
-rw-r--r--sys/arm64/arm64/swtch.S255
-rw-r--r--sys/arm64/arm64/sys_machdep.c47
-rw-r--r--sys/arm64/arm64/trap.c311
-rw-r--r--sys/arm64/arm64/uio_machdep.c134
-rw-r--r--sys/arm64/arm64/vfp.c195
-rw-r--r--sys/arm64/arm64/vm_machdep.c265
-rw-r--r--sys/arm64/conf/DEFAULTS14
-rw-r--r--sys/arm64/conf/GENERIC94
-rw-r--r--sys/arm64/include/_bus.h46
-rw-r--r--sys/arm64/include/armreg.h194
-rw-r--r--sys/arm64/include/atomic.h242
-rw-r--r--sys/arm64/include/bus.h469
-rw-r--r--sys/arm64/include/bus_dma.h8
-rw-r--r--sys/arm64/include/clock.h1
-rw-r--r--sys/arm64/include/counter.h93
-rw-r--r--sys/arm64/include/cpufunc.h1
-rw-r--r--sys/arm64/include/db_machdep.h126
-rw-r--r--sys/arm64/include/debug_monitor.h63
-rw-r--r--sys/arm64/include/devmap.h93
-rw-r--r--sys/arm64/include/dump.h74
-rw-r--r--sys/arm64/include/hypervisor.h85
-rw-r--r--sys/arm64/include/in_cksum.h (renamed from lib/libc/sys/ftruncate.c)51
-rw-r--r--sys/arm64/include/intr.h56
-rw-r--r--sys/arm64/include/kdb.h53
-rw-r--r--sys/arm64/include/machdep.h44
-rw-r--r--sys/arm64/include/md_var.h (renamed from lib/libc/sys/truncate.c)47
-rw-r--r--sys/arm64/include/memdev.h40
-rw-r--r--sys/arm64/include/metadata.h41
-rw-r--r--sys/arm64/include/ofw_machdep.h44
-rw-r--r--sys/arm64/include/param.h4
-rw-r--r--sys/arm64/include/pmap.h5
-rw-r--r--sys/arm64/include/psl.h1
-rw-r--r--sys/arm64/include/resource.h46
-rw-r--r--sys/arm64/include/sf_buf.h51
-rw-r--r--sys/arm64/include/smp.h1
-rw-r--r--sys/arm64/include/stack.h35
-rw-r--r--sys/arm64/include/trap.h1
-rw-r--r--sys/arm64/include/vfp.h46
-rw-r--r--sys/boot/Makefile1
-rw-r--r--sys/boot/Makefile.arm2
-rw-r--r--sys/boot/Makefile.arm647
-rw-r--r--sys/boot/arm64/Makefile3
-rw-r--r--sys/boot/arm64/libarm64/cache.c95
-rw-r--r--sys/boot/arm64/libarm64/cache.h38
-rw-r--r--sys/boot/common/Makefile.inc12
-rw-r--r--sys/boot/common/md.c2
-rw-r--r--sys/boot/efi/Makefile12
-rw-r--r--sys/boot/efi/boot1/Makefile40
-rw-r--r--sys/boot/efi/boot1/boot1.c61
-rw-r--r--sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu (renamed from sys/boot/efi/boot1/fat.tmpl.bz2.uu)2
-rw-r--r--sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu26
-rw-r--r--sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu26
-rw-r--r--sys/boot/efi/boot1/fat-i386.tmpl.bz2.uu26
-rwxr-xr-xsys/boot/efi/boot1/generate-fat.sh15
-rw-r--r--sys/boot/efi/fdt/Makefile6
-rw-r--r--sys/boot/efi/include/arm/efibind.h165
-rw-r--r--sys/boot/efi/include/arm64/efibind.h219
-rw-r--r--sys/boot/efi/libefi/Makefile2
-rw-r--r--sys/boot/efi/loader/Makefile51
-rw-r--r--sys/boot/efi/loader/arch/amd64/Makefile.inc6
-rw-r--r--sys/boot/efi/loader/arch/arm/Makefile.inc6
-rw-r--r--sys/boot/efi/loader/arch/arm/exec.c107
-rw-r--r--sys/boot/efi/loader/arch/arm/ldscript.arm62
-rw-r--r--sys/boot/efi/loader/arch/arm/start.S189
-rw-r--r--sys/boot/efi/loader/arch/arm64/Makefile.inc9
-rw-r--r--sys/boot/efi/loader/arch/arm64/exec.c109
-rw-r--r--sys/boot/efi/loader/arch/arm64/ldscript.arm6480
-rw-r--r--sys/boot/efi/loader/arch/arm64/start.S165
-rw-r--r--sys/boot/efi/loader/arch/i386/Makefile.inc13
-rw-r--r--sys/boot/efi/loader/arch/i386/bootinfo.c2
-rw-r--r--sys/boot/efi/loader/arch/i386/elf32_freebsd.c10
-rw-r--r--sys/boot/efi/loader/arch/i386/i386_copy.c2
-rw-r--r--sys/boot/efi/loader/arch/i386/start.S2
-rw-r--r--sys/boot/efi/loader/bootinfo.c63
-rw-r--r--sys/boot/efi/loader/copy.c18
-rw-r--r--sys/boot/efi/loader/main.c34
-rw-r--r--sys/boot/efi/loader/reloc.c (renamed from sys/boot/efi/loader/arch/amd64/reloc.c)39
-rw-r--r--sys/boot/fdt/dts/arm/bcm2836.dtsi14
-rw-r--r--sys/boot/fdt/dts/arm/meson8b.dtsi79
-rw-r--r--sys/boot/fdt/dts/arm/odroidc1.dts280
-rw-r--r--sys/boot/fdt/dts/arm/rpi2.dts20
-rw-r--r--sys/boot/fdt/dts/arm/vsatv102-m6.dts256
-rw-r--r--sys/boot/ficl/aarch64/sysdep.c99
-rw-r--r--sys/boot/ficl/aarch64/sysdep.h411
-rw-r--r--sys/boot/forth/check-password.4th9
-rw-r--r--sys/boot/forth/check-password.4th.842
-rw-r--r--sys/boot/forth/loader.conf11
-rw-r--r--sys/boot/forth/menu.4th2
-rw-r--r--sys/boot/forth/menu.rc33
-rw-r--r--sys/boot/forth/version.4th6
-rw-r--r--sys/boot/i386/common/edd.h2
-rw-r--r--sys/boot/i386/libi386/libi386.h4
-rw-r--r--sys/boot/i386/libi386/smbios.c21
-rw-r--r--sys/boot/i386/libi386/smbios.h34
-rw-r--r--sys/boot/i386/loader/main.c5
-rw-r--r--sys/boot/libstand32/Makefile36
-rw-r--r--sys/boot/sparc64/loader/main.c6
-rw-r--r--sys/boot/userboot/libstand/Makefile39
-rw-r--r--sys/cam/cam_xpt.c4
-rw-r--r--sys/cam/scsi/scsi_all.c2
-rw-r--r--sys/cam/scsi/scsi_da.c2
-rw-r--r--sys/cddl/contrib/opensolaris/common/nvpair/nvpair.c1
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c50
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c6
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c13
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c32
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c3
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c5
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c5
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c2
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c24
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h5
-rw-r--r--sys/cddl/dev/dtrace/amd64/dtrace_asm.S208
-rw-r--r--sys/cddl/dev/dtrace/arm/dtrace_asm.S18
-rw-r--r--sys/cddl/dev/dtrace/dtrace_hacks.c3
-rw-r--r--sys/cddl/dev/dtrace/dtrace_ioctl.c7
-rw-r--r--sys/cddl/dev/dtrace/i386/dtrace_asm.S164
-rw-r--r--sys/cddl/dev/dtrace/mips/dtrace_asm.S44
-rw-r--r--sys/cddl/dev/dtrace/powerpc/dtrace_asm.S40
-rw-r--r--sys/cddl/dev/profile/profile.c6
-rw-r--r--sys/compat/freebsd32/freebsd32.h26
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c5
-rw-r--r--sys/compat/linprocfs/linprocfs.c37
-rw-r--r--sys/compat/linux/linux_file.c92
-rw-r--r--sys/compat/linux/linux_getcwd.c414
-rw-r--r--sys/compat/linux/linux_misc.h2
-rw-r--r--sys/compat/svr4/svr4_stream.c4
-rw-r--r--sys/conf/Makefile.arm6454
-rw-r--r--sys/conf/Makefile.pc983
-rw-r--r--sys/conf/NOTES1
-rw-r--r--sys/conf/files78
-rw-r--r--sys/conf/files.amd6411
-rw-r--r--sys/conf/files.arm2
-rw-r--r--sys/conf/files.arm6454
-rw-r--r--sys/conf/files.i38648
-rw-r--r--sys/conf/files.mips1
-rw-r--r--sys/conf/files.pc982
-rw-r--r--sys/conf/files.powerpc16
-rw-r--r--sys/conf/kern.mk2
-rw-r--r--sys/conf/kern.pre.mk11
-rw-r--r--sys/conf/kmod.mk8
-rw-r--r--sys/conf/ldscript.arm64149
-rw-r--r--sys/conf/newvers.sh8
-rw-r--r--sys/conf/options3
-rw-r--r--sys/conf/options.amd642
-rw-r--r--sys/conf/options.arm3
-rw-r--r--sys/conf/options.arm646
-rw-r--r--sys/conf/options.i3869
-rw-r--r--sys/contrib/altq/altq/altqconf.h29
-rwxr-xr-xsys/contrib/dev/acpica/acpica_prep.sh11
-rw-r--r--sys/contrib/dev/acpica/changes.txt107
-rw-r--r--sys/contrib/dev/acpica/common/adfile.c10
-rw-r--r--sys/contrib/dev/acpica/common/adisasm.c95
-rw-r--r--sys/contrib/dev/acpica/common/dmtable.c136
-rw-r--r--sys/contrib/dev/acpica/common/dmtbdump.c100
-rw-r--r--sys/contrib/dev/acpica/common/dmtbinfo.c42
-rw-r--r--sys/contrib/dev/acpica/compiler/aslcodegen.c2
-rw-r--r--sys/contrib/dev/acpica/compiler/aslcompile.c12
-rw-r--r--sys/contrib/dev/acpica/compiler/aslcompiler.h8
-rw-r--r--sys/contrib/dev/acpica/compiler/asldefine.h1
-rw-r--r--sys/contrib/dev/acpica/compiler/aslfold.c706
-rw-r--r--sys/contrib/dev/acpica/compiler/asllisting.c5
-rw-r--r--sys/contrib/dev/acpica/compiler/aslmain.c1
-rw-r--r--sys/contrib/dev/acpica/compiler/aslmap.c2
-rw-r--r--sys/contrib/dev/acpica/compiler/aslmapenter.c10
-rw-r--r--sys/contrib/dev/acpica/compiler/asloptions.c5
-rw-r--r--sys/contrib/dev/acpica/compiler/aslrules.y53
-rw-r--r--sys/contrib/dev/acpica/compiler/aslstartup.c2
-rw-r--r--sys/contrib/dev/acpica/compiler/asltree.c199
-rw-r--r--sys/contrib/dev/acpica/compiler/asltypes.y2
-rw-r--r--sys/contrib/dev/acpica/compiler/aslutils.c9
-rw-r--r--sys/contrib/dev/acpica/compiler/aslwalks.c10
-rw-r--r--sys/contrib/dev/acpica/compiler/dtcompile.c17
-rw-r--r--sys/contrib/dev/acpica/compiler/dtcompiler.h20
-rw-r--r--sys/contrib/dev/acpica/compiler/dtio.c6
-rw-r--r--sys/contrib/dev/acpica/compiler/dttable.c35
-rw-r--r--sys/contrib/dev/acpica/compiler/dttemplate.h17
-rw-r--r--sys/contrib/dev/acpica/compiler/dtutils.c3
-rw-r--r--sys/contrib/dev/acpica/components/debugger/dbmethod.c4
-rw-r--r--sys/contrib/dev/acpica/components/debugger/dbxface.c13
-rw-r--r--sys/contrib/dev/acpica/components/disassembler/dmopcode.c12
-rw-r--r--sys/contrib/dev/acpica/components/disassembler/dmwalk.c2
-rw-r--r--sys/contrib/dev/acpica/components/dispatcher/dsopcode.c6
-rw-r--r--sys/contrib/dev/acpica/components/dispatcher/dsutils.c9
-rw-r--r--sys/contrib/dev/acpica/components/events/evregion.c2
-rw-r--r--sys/contrib/dev/acpica/components/events/evxfevnt.c5
-rw-r--r--sys/contrib/dev/acpica/components/executer/exdump.c2
-rw-r--r--sys/contrib/dev/acpica/components/executer/exfldio.c4
-rw-r--r--sys/contrib/dev/acpica/components/executer/exoparg3.c13
-rw-r--r--sys/contrib/dev/acpica/components/executer/exregion.c13
-rw-r--r--sys/contrib/dev/acpica/components/hardware/hwgpe.c15
-rw-r--r--sys/contrib/dev/acpica/components/hardware/hwvalid.c12
-rw-r--r--sys/contrib/dev/acpica/components/namespace/nsdump.c6
-rw-r--r--sys/contrib/dev/acpica/components/parser/psopcode.c6
-rw-r--r--sys/contrib/dev/acpica/components/parser/psopinfo.c2
-rw-r--r--sys/contrib/dev/acpica/components/resources/rsaddr.c8
-rw-r--r--sys/contrib/dev/acpica/components/resources/rsdump.c279
-rw-r--r--sys/contrib/dev/acpica/components/resources/rsdumpinfo.c45
-rw-r--r--sys/contrib/dev/acpica/components/resources/rsxface.c10
-rw-r--r--sys/contrib/dev/acpica/components/tables/tbdata.c33
-rw-r--r--sys/contrib/dev/acpica/components/tables/tbinstal.c68
-rw-r--r--sys/contrib/dev/acpica/components/tables/tbprint.c18
-rw-r--r--sys/contrib/dev/acpica/components/tables/tbxfroot.c6
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utaddress.c22
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utbuffer.c9
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utglobal.c13
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utmisc.c2
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utosi.c1
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utprint.c13
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utstate.c38
-rw-r--r--sys/contrib/dev/acpica/components/utilities/utuuid.c2
-rw-r--r--sys/contrib/dev/acpica/include/acdebug.h2
-rw-r--r--sys/contrib/dev/acpica/include/acdisasm.h20
-rw-r--r--sys/contrib/dev/acpica/include/acglobal.h9
-rw-r--r--sys/contrib/dev/acpica/include/aclocal.h2
-rw-r--r--sys/contrib/dev/acpica/include/acmacros.h13
-rw-r--r--sys/contrib/dev/acpica/include/acopcode.h2
-rw-r--r--sys/contrib/dev/acpica/include/acpixf.h4
-rw-r--r--sys/contrib/dev/acpica/include/acresrc.h4
-rw-r--r--sys/contrib/dev/acpica/include/acrestyp.h54
-rw-r--r--sys/contrib/dev/acpica/include/acstruct.h5
-rw-r--r--sys/contrib/dev/acpica/include/actables.h13
-rw-r--r--sys/contrib/dev/acpica/include/actbl2.h83
-rw-r--r--sys/contrib/dev/acpica/include/actypes.h46
-rw-r--r--sys/contrib/dev/acpica/include/acutils.h27
-rw-r--r--sys/contrib/dev/acpica/include/amlcode.h2
-rw-r--r--sys/contrib/dev/acpica/include/platform/acenv.h1
-rw-r--r--sys/contrib/ipfilter/netinet/ip_compat.h34
-rw-r--r--sys/contrib/x86emu/x86emu.c4
-rw-r--r--sys/crypto/aesni/aesencdec.h2
-rw-r--r--sys/crypto/aesni/aesni_ghash.c1
-rw-r--r--sys/crypto/aesni/aesni_os.h33
-rw-r--r--sys/dev/acpica/acpi.c45
-rw-r--r--sys/dev/acpica/acpi_pcib_acpi.c24
-rw-r--r--sys/dev/acpica/acpi_resource.c32
-rw-r--r--sys/dev/acpica/acpivar.h7
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212.h4
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_misc.c26
-rw-r--r--sys/dev/atkbdc/atkbd.c82
-rw-r--r--sys/dev/atkbdc/psm.c320
-rw-r--r--sys/dev/bxe/bxe.h2
-rw-r--r--sys/dev/cxgbe/t4_main.c41
-rw-r--r--sys/dev/cxgbe/tom/t4_listen.c56
-rw-r--r--sys/dev/e1000/if_igb.c164
-rw-r--r--sys/dev/etherswitch/miiproxy.c122
-rw-r--r--sys/dev/fdt/fdt_arm64.c49
-rw-r--r--sys/dev/fdt/fdt_pinctrl.c6
-rw-r--r--sys/dev/hptnr/README14
-rw-r--r--sys/dev/hptnr/amd64-elf.hptnr_lib.o.uu23796
-rw-r--r--sys/dev/hptnr/him.h3
-rw-r--r--sys/dev/hptnr/hptintf.h1
-rw-r--r--sys/dev/hptnr/hptnr_config.c2
-rw-r--r--sys/dev/hptnr/hptnr_config.h2
-rw-r--r--sys/dev/hptnr/hptnr_osm_bsd.c405
-rw-r--r--sys/dev/hptnr/i386-elf.hptnr_lib.o.uu16552
-rw-r--r--sys/dev/hptnr/ldm.h1
-rw-r--r--sys/dev/hptnr/os_bsd.h2
-rw-r--r--sys/dev/hwpmc/hwpmc_core.c25
-rw-r--r--sys/dev/hwpmc/hwpmc_e500.c660
-rw-r--r--sys/dev/hwpmc/hwpmc_intel.c8
-rw-r--r--sys/dev/hwpmc/hwpmc_mips74k.c261
-rw-r--r--sys/dev/hwpmc/hwpmc_mpc7xxx.c4
-rw-r--r--sys/dev/hwpmc/hwpmc_powerpc.c5
-rw-r--r--sys/dev/hwpmc/hwpmc_powerpc.h1
-rw-r--r--sys/dev/hwpmc/hwpmc_ppc970.c4
-rw-r--r--sys/dev/hwpmc/pmc_events.h313
-rw-r--r--sys/dev/hyperv/include/hyperv.h167
-rw-r--r--sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c801
-rw-r--r--sys/dev/hyperv/storvsc/hv_vstorage.h16
-rw-r--r--sys/dev/hyperv/utilities/hv_kvp.c11
-rw-r--r--sys/dev/hyperv/utilities/hv_util.c9
-rw-r--r--sys/dev/hyperv/vmbus/hv_channel.c98
-rw-r--r--sys/dev/hyperv/vmbus/hv_channel_mgmt.c265
-rw-r--r--sys/dev/hyperv/vmbus/hv_connection.c286
-rw-r--r--sys/dev/hyperv/vmbus/hv_hv.c66
-rw-r--r--sys/dev/hyperv/vmbus/hv_ring_buffer.c76
-rw-r--r--sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c364
-rw-r--r--sys/dev/hyperv/vmbus/hv_vmbus_priv.h71
-rw-r--r--sys/dev/ichsmb/ichsmb_pci.c10
-rw-r--r--sys/dev/iicbus/iic.c437
-rw-r--r--sys/dev/iicbus/iic.h1
-rw-r--r--sys/dev/iicbus/iicbus_if.m4
-rw-r--r--sys/dev/iicbus/iiconf.c71
-rw-r--r--sys/dev/iicbus/pcf8563.c67
-rw-r--r--sys/dev/ipmi/ipmi.c23
-rw-r--r--sys/dev/ipmi/ipmi_kcs.c1
-rw-r--r--sys/dev/ipmi/ipmi_smic.c1
-rw-r--r--sys/dev/ipmi/ipmivars.h1
-rw-r--r--sys/dev/iscsi/icl_conn_if.m4
-rw-r--r--sys/dev/iscsi/icl_soft.c20
-rw-r--r--sys/dev/iscsi/icl_wrappers.h7
-rw-r--r--sys/dev/iwn/if_iwn.c2
-rw-r--r--sys/dev/ixgbe/if_ix.c1070
-rw-r--r--sys/dev/ixgbe/if_ixv.c9
-rw-r--r--sys/dev/ixgbe/ix_txrx.c57
-rw-r--r--sys/dev/ixgbe/ixgbe.h39
-rw-r--r--sys/dev/ixgbe/ixgbe_82598.c7
-rw-r--r--sys/dev/ixgbe/ixgbe_82598.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_82599.c6
-rw-r--r--sys/dev/ixgbe/ixgbe_82599.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_api.c122
-rw-r--r--sys/dev/ixgbe/ixgbe_api.h11
-rw-r--r--sys/dev/ixgbe/ixgbe_common.c6
-rw-r--r--sys/dev/ixgbe/ixgbe_common.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_dcb.c12
-rw-r--r--sys/dev/ixgbe/ixgbe_dcb.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_dcb_82598.c2
-rw-r--r--sys/dev/ixgbe/ixgbe_dcb_82598.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_dcb_82599.c2
-rw-r--r--sys/dev/ixgbe/ixgbe_dcb_82599.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_mbx.c4
-rw-r--r--sys/dev/ixgbe/ixgbe_mbx.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_osdep.h9
-rw-r--r--sys/dev/ixgbe/ixgbe_phy.c228
-rw-r--r--sys/dev/ixgbe/ixgbe_phy.h23
-rw-r--r--sys/dev/ixgbe/ixgbe_type.h265
-rw-r--r--sys/dev/ixgbe/ixgbe_vf.c3
-rw-r--r--sys/dev/ixgbe/ixgbe_vf.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_x540.c12
-rw-r--r--sys/dev/ixgbe/ixgbe_x540.h2
-rw-r--r--sys/dev/ixgbe/ixgbe_x550.c3191
-rw-r--r--sys/dev/ixgbe/ixgbe_x550.h109
-rw-r--r--sys/dev/ixl/ixl.h2
-rw-r--r--sys/dev/mii/acphy.c8
-rw-r--r--sys/dev/mii/brgphy.c51
-rw-r--r--sys/dev/mii/lxtphy.c8
-rw-r--r--sys/dev/mii/mii_physubr.c160
-rw-r--r--sys/dev/mii/miivar.h21
-rw-r--r--sys/dev/mii/mlphy.c22
-rw-r--r--sys/dev/mii/xmphy.c9
-rw-r--r--sys/dev/mxge/if_mxge.c2
-rw-r--r--sys/dev/netmap/netmap.c6
-rw-r--r--sys/dev/nvme/nvme.c47
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c181
-rw-r--r--sys/dev/nvme/nvme_ns.c46
-rw-r--r--sys/dev/nvme/nvme_private.h38
-rw-r--r--sys/dev/nvme/nvme_qpair.c56
-rw-r--r--sys/dev/pccbb/pccbb_pci.c52
-rw-r--r--sys/dev/pci/pci.c120
-rw-r--r--sys/dev/pci/pci_iov.c2
-rw-r--r--sys/dev/pci/pci_pci.c66
-rw-r--r--sys/dev/pci/pci_subr.c2
-rw-r--r--sys/dev/pci/pcib_private.h3
-rw-r--r--sys/dev/pci/pcivar.h10
-rw-r--r--sys/dev/psci/psci.c286
-rw-r--r--sys/dev/psci/psci.h102
-rw-r--r--sys/dev/psci/psci_arm.S47
-rw-r--r--sys/dev/psci/psci_arm64.S49
-rw-r--r--sys/dev/re/if_re.c14
-rw-r--r--sys/dev/smbus/smb.c148
-rw-r--r--sys/dev/smbus/smb.h37
-rw-r--r--sys/dev/smbus/smbconf.h33
-rw-r--r--sys/dev/smbus/smbus.c88
-rw-r--r--sys/dev/smbus/smbus.h4
-rw-r--r--sys/dev/smbus/smbus_if.m17
-rw-r--r--sys/dev/sound/pci/hda/hdaa_patches.c7
-rw-r--r--sys/dev/sound/pci/hda/hdac.c2
-rw-r--r--sys/dev/sound/pci/hda/hdac.h5
-rw-r--r--sys/dev/sound/pci/hda/hdacc.c2
-rw-r--r--sys/dev/sound/pcm/dsp.c12
-rw-r--r--sys/dev/streams/streams.c4
-rw-r--r--sys/dev/uart/uart_bus.h1
-rw-r--r--sys/dev/uart/uart_bus_fdt.c33
-rw-r--r--sys/dev/uart/uart_core.c6
-rw-r--r--sys/dev/uart/uart_cpu.h1
-rw-r--r--sys/dev/uart/uart_cpu_fdt.c58
-rw-r--r--sys/dev/uart/uart_cpu_fdt.h2
-rw-r--r--sys/dev/uart/uart_dev_imx.c3
-rw-r--r--sys/dev/uart/uart_dev_lpc.c3
-rw-r--r--sys/dev/uart/uart_dev_msm.c1
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c3
-rw-r--r--sys/dev/uart/uart_dev_pl011.c3
-rw-r--r--sys/dev/uart/uart_dev_quicc.c3
-rw-r--r--sys/dev/uart/uart_dev_sab82532.c3
-rw-r--r--sys/dev/uart/uart_dev_ti8250.c3
-rw-r--r--sys/dev/uart/uart_dev_z8530.c3
-rw-r--r--sys/dev/usb/controller/dwc_otg.c16
-rw-r--r--sys/dev/usb/controller/ehci_pci.c2
-rw-r--r--sys/dev/usb/controller/uhci_pci.c2
-rw-r--r--sys/dev/usb/controller/xhci_pci.c2
-rw-r--r--sys/dev/usb/net/if_axge.c1
-rw-r--r--sys/dev/usb/serial/uftdi.c4
-rw-r--r--sys/dev/usb/usbdevs5
-rw-r--r--sys/dev/usb/video/udl.c76
-rw-r--r--sys/dev/usb/video/udl.h9
-rw-r--r--sys/dev/usb/wlan/if_run.c3
-rw-r--r--sys/dev/usb/wlan/if_urtwn.c134
-rw-r--r--sys/dev/virtio/block/virtio_blk.c3
-rw-r--r--sys/dev/virtio/network/if_vtnet.c5
-rw-r--r--sys/dev/vt/hw/fb/vt_fb.c54
-rw-r--r--sys/dev/vt/hw/vga/vt_vga.c16
-rw-r--r--sys/dev/vt/vt_core.c20
-rw-r--r--sys/dev/vt/vt_font.c4
-rw-r--r--sys/dev/wpi/if_wpi.c37
-rw-r--r--sys/dev/xen/balloon/balloon.c48
-rw-r--r--sys/dev/xen/blkback/blkback.c13
-rw-r--r--sys/dev/xen/control/control.c130
-rw-r--r--sys/dev/xen/grant_table/grant_table.c70
-rw-r--r--sys/dev/xen/netback/netback.c14
-rw-r--r--sys/dev/xen/netfront/netfront.c12
-rw-r--r--sys/fs/ext2fs/ext2_dir.h15
-rw-r--r--sys/fs/ext2fs/ext2_extern.h15
-rw-r--r--sys/fs/ext2fs/ext2_hash.c316
-rw-r--r--sys/fs/ext2fs/ext2_htree.c899
-rw-r--r--sys/fs/ext2fs/ext2_lookup.c336
-rw-r--r--sys/fs/ext2fs/ext2_vfsops.c21
-rw-r--r--sys/fs/ext2fs/ext2fs.h8
-rw-r--r--sys/fs/fuse/fuse_vfsops.c1
-rw-r--r--sys/fs/msdosfs/msdosfs_fat.c6
-rw-r--r--sys/fs/msdosfs/msdosfs_vfsops.c13
-rw-r--r--sys/fs/nandfs/nandfs_vfsops.c1
-rw-r--r--sys/fs/nfs/nfs.h2
-rw-r--r--sys/fs/nfs/nfs_commonport.c18
-rw-r--r--sys/fs/nfs/nfsport.h2
-rw-r--r--sys/fs/nfs/nfsproto.h15
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c8
-rw-r--r--sys/fs/nfsclient/nfs_clvfsops.c26
-rw-r--r--sys/fs/nfsserver/nfs_nfsdkrpc.c3
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c9
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c2
-rw-r--r--sys/fs/nullfs/null_vfsops.c2
-rw-r--r--sys/fs/tmpfs/tmpfs_vnops.c8
-rw-r--r--sys/geom/geom_dev.c2
-rw-r--r--sys/geom/multipath/g_multipath.c4
-rw-r--r--sys/geom/uncompress/g_uncompress.c3
-rw-r--r--sys/geom/uzip/g_uzip.c2
-rw-r--r--sys/gnu/dts/arm/meson.dtsi23
-rw-r--r--sys/gnu/dts/arm/meson6.dtsi4
-rw-r--r--sys/gnu/dts/arm/meson8.dtsi4
-rw-r--r--sys/i386/conf/DEFAULTS1
-rw-r--r--sys/i386/conf/GENERIC4
-rw-r--r--sys/i386/conf/XEN96
-rw-r--r--sys/i386/i386/apic_vector.s39
-rw-r--r--sys/i386/i386/bios.c2
-rw-r--r--sys/i386/i386/db_trace.c3
-rw-r--r--sys/i386/i386/genassym.c5
-rw-r--r--sys/i386/i386/initcpu.c2
-rw-r--r--sys/i386/i386/locore.s10
-rw-r--r--sys/i386/i386/machdep.c752
-rw-r--r--sys/i386/i386/minidump_machdep.c30
-rw-r--r--sys/i386/i386/mp_machdep.c1009
-rw-r--r--sys/i386/i386/mpboot.s2
-rw-r--r--sys/i386/i386/pmap.c153
-rw-r--r--sys/i386/i386/support.s2
-rw-r--r--sys/i386/i386/swtch.s28
-rw-r--r--sys/i386/i386/sys_machdep.c103
-rw-r--r--sys/i386/i386/trap.c2
-rw-r--r--sys/i386/i386/vm86bios.s2
-rw-r--r--sys/i386/i386/vm_machdep.c29
-rw-r--r--sys/i386/include/asmacros.h31
-rw-r--r--sys/i386/include/cpufunc.h46
-rw-r--r--sys/i386/include/intr_machdep.h8
-rw-r--r--sys/i386/include/md_var.h1
-rw-r--r--sys/i386/include/param.h2
-rw-r--r--sys/i386/include/pcpu.h32
-rw-r--r--sys/i386/include/pmap.h111
-rw-r--r--sys/i386/include/segments.h6
-rw-r--r--sys/i386/include/smp.h48
-rw-r--r--sys/i386/include/vm.h2
-rw-r--r--sys/i386/include/vmparam.h14
-rw-r--r--sys/i386/include/xen/features.h22
-rw-r--r--sys/i386/include/xen/hypercall.h6
-rw-r--r--sys/i386/include/xen/xen-os.h99
-rw-r--r--sys/i386/include/xen/xenfunc.h1
-rw-r--r--sys/i386/include/xen/xenpmap.h237
-rw-r--r--sys/i386/include/xen/xenstored.h89
-rw-r--r--sys/i386/include/xen/xenvar.h85
-rw-r--r--sys/i386/isa/npx.c9
-rw-r--r--sys/i386/pci/pci_cfgreg.c10
-rw-r--r--sys/i386/pci/pci_pir.c9
-rw-r--r--sys/i386/xen/clock.c570
-rw-r--r--sys/i386/xen/exception.s494
-rw-r--r--sys/i386/xen/locore.s360
-rw-r--r--sys/i386/xen/mp_machdep.c1309
-rw-r--r--sys/i386/xen/mptable.c109
-rw-r--r--sys/i386/xen/pmap.c4520
-rw-r--r--sys/i386/xen/xen_machdep.c1236
-rw-r--r--sys/kern/imgact_elf.c15
-rw-r--r--sys/kern/init_main.c3
-rw-r--r--sys/kern/init_sysent.c20
-rw-r--r--sys/kern/kern_descrip.c41
-rw-r--r--sys/kern/kern_exec.c17
-rw-r--r--sys/kern/kern_exit.c8
-rw-r--r--sys/kern/kern_fork.c2
-rw-r--r--sys/kern/kern_gzio.c3
-rw-r--r--sys/kern/kern_intr.c5
-rw-r--r--sys/kern/kern_jail.c22
-rw-r--r--sys/kern/kern_physio.c154
-rw-r--r--sys/kern/kern_poll.c6
-rw-r--r--sys/kern/kern_proc.c2
-rw-r--r--sys/kern/kern_racct.c98
-rw-r--r--sys/kern/kern_rctl.c69
-rw-r--r--sys/kern/kern_resource.c7
-rw-r--r--sys/kern/kern_shutdown.c9
-rw-r--r--sys/kern/kern_synch.c20
-rw-r--r--sys/kern/kern_thr.c26
-rw-r--r--sys/kern/kern_thread.c1
-rw-r--r--sys/kern/kern_timeout.c2
-rw-r--r--sys/kern/link_elf.c2
-rw-r--r--sys/kern/link_elf_obj.c2
-rw-r--r--sys/kern/sched_4bsd.c2
-rw-r--r--sys/kern/subr_bus.c18
-rw-r--r--sys/kern/subr_dnvlist.c166
-rw-r--r--sys/kern/subr_nvlist.c910
-rw-r--r--sys/kern/subr_nvpair.c382
-rw-r--r--sys/kern/subr_param.c4
-rw-r--r--sys/kern/subr_prf.c2
-rw-r--r--sys/kern/subr_trap.c22
-rw-r--r--sys/kern/subr_vmem.c3
-rw-r--r--sys/kern/sys_generic.c4
-rw-r--r--sys/kern/sys_pipe.c4
-rw-r--r--sys/kern/syscalls.c14
-rw-r--r--sys/kern/syscalls.master12
-rw-r--r--sys/kern/systrace_args.c216
-rw-r--r--sys/kern/sysv_msg.c42
-rw-r--r--sys/kern/sysv_sem.c25
-rw-r--r--sys/kern/sysv_shm.c82
-rw-r--r--sys/kern/tty_pts.c2
-rw-r--r--sys/kern/uipc_mqueue.c2
-rw-r--r--sys/kern/uipc_sem.c6
-rw-r--r--sys/kern/uipc_shm.c17
-rw-r--r--sys/kern/uipc_syscalls.c63
-rw-r--r--sys/kern/vfs_aio.c206
-rw-r--r--sys/kern/vfs_bio.c107
-rw-r--r--sys/kern/vfs_cache.c46
-rw-r--r--sys/kern/vfs_subr.c1
-rw-r--r--sys/kern/vfs_syscalls.c31
-rw-r--r--sys/kern/vfs_vnops.c6
-rw-r--r--sys/libkern/zlib.c (renamed from sys/net/zlib.c)2
-rw-r--r--sys/mips/adm5120/uart_dev_adm5120.c3
-rw-r--r--sys/mips/atheros/uart_dev_ar933x.c3
-rw-r--r--sys/mips/cavium/uart_dev_oct16550.c3
-rw-r--r--sys/mips/conf/CARAMBOLA2.hints17
-rw-r--r--sys/mips/conf/DIR-655A1.hints38
-rw-r--r--sys/mips/conf/DIR-825C1.hints28
-rw-r--r--sys/mips/include/reg.h4
-rw-r--r--sys/mips/mips/busdma_machdep.c4
-rw-r--r--sys/mips/rt305x/uart_dev_rt305x.c3
-rw-r--r--sys/modules/dtb/allwinner/Makefile7
-rw-r--r--sys/modules/ext2fs/Makefile4
-rw-r--r--sys/modules/hwpmc/Makefile2
-rw-r--r--sys/modules/i2c/iicbb/Makefile5
-rw-r--r--sys/modules/ix/Makefile2
-rw-r--r--sys/modules/ixv/Makefile2
-rw-r--r--sys/modules/oce/Makefile2
-rw-r--r--sys/modules/usb/Makefile1
-rw-r--r--sys/modules/zlib/Makefile2
-rw-r--r--sys/net/altq/altq.h (renamed from sys/contrib/altq/altq/altq.h)10
-rw-r--r--sys/net/altq/altq_cbq.c (renamed from sys/contrib/altq/altq/altq_cbq.c)22
-rw-r--r--sys/net/altq/altq_cbq.h (renamed from sys/contrib/altq/altq/altq_cbq.h)15
-rw-r--r--sys/net/altq/altq_cdnr.c (renamed from sys/contrib/altq/altq/altq_cdnr.c)24
-rw-r--r--sys/net/altq/altq_cdnr.h (renamed from sys/contrib/altq/altq/altq_cdnr.h)9
-rw-r--r--sys/net/altq/altq_classq.h (renamed from sys/contrib/altq/altq/altq_classq.h)7
-rw-r--r--sys/net/altq/altq_hfsc.c (renamed from sys/contrib/altq/altq/altq_hfsc.c)34
-rw-r--r--sys/net/altq/altq_hfsc.h (renamed from sys/contrib/altq/altq/altq_hfsc.h)15
-rw-r--r--sys/net/altq/altq_priq.c (renamed from sys/contrib/altq/altq/altq_priq.c)29
-rw-r--r--sys/net/altq/altq_priq.h (renamed from sys/contrib/altq/altq/altq_priq.h)14
-rw-r--r--sys/net/altq/altq_red.c (renamed from sys/contrib/altq/altq/altq_red.c)26
-rw-r--r--sys/net/altq/altq_red.h (renamed from sys/contrib/altq/altq/altq_red.h)9
-rw-r--r--sys/net/altq/altq_rio.c (renamed from sys/contrib/altq/altq/altq_rio.c)28
-rw-r--r--sys/net/altq/altq_rio.h (renamed from sys/contrib/altq/altq/altq_rio.h)9
-rw-r--r--sys/net/altq/altq_rmclass.c (renamed from sys/contrib/altq/altq/altq_rmclass.c)44
-rw-r--r--sys/net/altq/altq_rmclass.h (renamed from sys/contrib/altq/altq/altq_rmclass.h)9
-rw-r--r--sys/net/altq/altq_rmclass_debug.h (renamed from sys/contrib/altq/altq/altq_rmclass_debug.h)7
-rw-r--r--sys/net/altq/altq_subr.c (renamed from sys/contrib/altq/altq/altq_subr.c)68
-rw-r--r--sys/net/altq/altq_var.h (renamed from sys/contrib/altq/altq/altq_var.h)38
-rw-r--r--sys/net/altq/if_altq.h (renamed from sys/contrib/altq/altq/if_altq.h)16
-rw-r--r--sys/net/bpf.c23
-rw-r--r--sys/net/bpf.h21
-rw-r--r--sys/net/ieee8023ad_lacp.c42
-rw-r--r--sys/net/if.c1
-rw-r--r--sys/net/if_media.c33
-rw-r--r--sys/net/if_media.h108
-rw-r--r--sys/net/if_tap.c13
-rw-r--r--sys/net/if_types.h431
-rw-r--r--sys/net/if_var.h2
-rw-r--r--sys/net/if_vlan.c21
-rw-r--r--sys/net/ifq.h2
-rw-r--r--sys/net/netisr.c15
-rw-r--r--sys/net/pfvar.h11
-rw-r--r--sys/net/route.c1
-rw-r--r--sys/net80211/ieee80211_mesh.c2
-rw-r--r--sys/netgraph/bluetooth/hci/ng_hci_cmds.c141
-rw-r--r--sys/netgraph/bluetooth/hci/ng_hci_evnt.c247
-rw-r--r--sys/netgraph/bluetooth/hci/ng_hci_main.c4
-rw-r--r--sys/netgraph/bluetooth/hci/ng_hci_misc.c9
-rw-r--r--sys/netgraph/bluetooth/hci/ng_hci_misc.h2
-rw-r--r--sys/netgraph/bluetooth/hci/ng_hci_ulpi.c220
-rw-r--r--sys/netgraph/bluetooth/hci/ng_hci_var.h1
-rw-r--r--sys/netgraph/bluetooth/include/ng_btsocket.h19
-rw-r--r--sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h4
-rw-r--r--sys/netgraph/bluetooth/include/ng_hci.h323
-rw-r--r--sys/netgraph/bluetooth/include/ng_l2cap.h44
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c23
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.h19
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_evnt.c157
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c19
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.h2
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c94
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.h10
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c147
-rw-r--r--sys/netgraph/bluetooth/l2cap/ng_l2cap_var.h7
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c3
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c171
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c12
-rw-r--r--sys/netgraph/ng_deflate.c3
-rw-r--r--sys/netinet/igmp.c7
-rw-r--r--sys/netinet/in.c24
-rw-r--r--sys/netinet/in.h1
-rw-r--r--sys/netinet/in_kdtrace.c3
-rw-r--r--sys/netinet/in_kdtrace.h3
-rw-r--r--sys/netinet/in_var.h9
-rw-r--r--sys/netinet/ip_carp.c109
-rw-r--r--sys/netinet/ip_fw.h5
-rw-r--r--sys/netinet/ip_input.c562
-rw-r--r--sys/netinet/ip_ipsec.c11
-rw-r--r--sys/netinet/ip_reass.c658
-rw-r--r--sys/netinet/libalias/libalias.38
-rw-r--r--sys/netinet/sctp_indata.c11
-rw-r--r--sys/netinet/sctp_syscalls.c10
-rw-r--r--sys/netinet/siftr.c4
-rw-r--r--sys/netinet/tcp_subr.c110
-rw-r--r--sys/netinet/tcp_timer.c168
-rw-r--r--sys/netinet/tcp_timer.h24
-rw-r--r--sys/netinet/tcp_timewait.c7
-rw-r--r--sys/netinet/tcp_var.h5
-rw-r--r--sys/netinet6/in6.c39
-rw-r--r--sys/netinet6/in6.h1
-rw-r--r--sys/netinet6/in6_ifattach.c4
-rw-r--r--sys/netinet6/in6_mcast.c14
-rw-r--r--sys/netinet6/ip6_forward.c93
-rw-r--r--sys/netinet6/ip6_ipsec.c12
-rw-r--r--sys/netinet6/ip6_mroute.c31
-rw-r--r--sys/netinet6/ip6_mroute.h14
-rw-r--r--sys/netinet6/nd6.c15
-rw-r--r--sys/netinet6/nd6_nbr.c27
-rw-r--r--sys/netinet6/nd6_rtr.c12
-rw-r--r--sys/netipsec/ipsec.c65
-rw-r--r--sys/netipsec/ipsec.h5
-rw-r--r--sys/netipsec/ipsec_input.c58
-rw-r--r--sys/netipsec/ipsec_output.c258
-rw-r--r--sys/netipsec/key.c43
-rw-r--r--sys/netipsec/xform.h6
-rw-r--r--sys/netipsec/xform_ah.c47
-rw-r--r--sys/netipsec/xform_esp.c66
-rw-r--r--sys/netipsec/xform_ipcomp.c39
-rw-r--r--sys/netipsec/xform_ipip.c307
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c6
-rw-r--r--sys/netpfil/ipfw/ip_fw_nat.c26
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h113
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c564
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c573
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.h13
-rw-r--r--sys/netpfil/pf/pf.c2
-rw-r--r--sys/netpfil/pf/pf_ioctl.c2
-rw-r--r--sys/netpfil/pf/pf_norm.c3
-rw-r--r--sys/nfsclient/nfs.h3
-rw-r--r--sys/ofed/include/linux/file.h2
-rw-r--r--sys/ofed/include/linux/linux_idr.c30
-rw-r--r--sys/opencrypto/cryptodeflate.c4
-rw-r--r--sys/opencrypto/deflate.h2
-rw-r--r--sys/opencrypto/gmac.h1
-rw-r--r--sys/pc98/pc98/genassym.c3
-rw-r--r--sys/powerpc/aim/aim_machdep.c (renamed from sys/powerpc/aim/machdep.c)370
-rw-r--r--sys/powerpc/aim/mmu_oea64.c5
-rw-r--r--sys/powerpc/booke/booke_machdep.c (renamed from sys/powerpc/booke/machdep.c)376
-rw-r--r--sys/powerpc/booke/interrupt.c25
-rw-r--r--sys/powerpc/booke/locore.S6
-rw-r--r--sys/powerpc/booke/pmap.c7
-rw-r--r--sys/powerpc/booke/trap.c519
-rw-r--r--sys/powerpc/booke/trap_subr.S13
-rw-r--r--sys/powerpc/conf/GENERIC1
-rw-r--r--sys/powerpc/include/pmc_mdep.h58
-rw-r--r--sys/powerpc/include/reg.h4
-rw-r--r--sys/powerpc/include/trap.h2
-rw-r--r--sys/powerpc/mpc85xx/mpc85xx_gpio.c307
-rw-r--r--sys/powerpc/ofw/ofw_machdep.c23
-rw-r--r--sys/powerpc/powerpc/busdma_machdep.c4
-rw-r--r--sys/powerpc/powerpc/machdep.c502
-rw-r--r--sys/powerpc/powerpc/trap.c (renamed from sys/powerpc/aim/trap.c)150
-rw-r--r--sys/powerpc/powerpc/uma_machdep.c (renamed from sys/powerpc/aim/uma_machdep.c)0
-rw-r--r--sys/rpc/svc_generic.c4
-rw-r--r--sys/rpc/svc_vc.c2
-rw-r--r--sys/sparc64/include/reg.h6
-rw-r--r--sys/sparc64/pci/apb.c10
-rw-r--r--sys/sparc64/pci/sbbc.c3
-rw-r--r--sys/sys/buf.h4
-rw-r--r--sys/sys/cdefs.h26
-rw-r--r--sys/sys/elf_common.h1
-rw-r--r--sys/sys/fcntl.h4
-rw-r--r--sys/sys/filedesc.h2
-rw-r--r--sys/sys/imgact.h1
-rw-r--r--sys/sys/kerneldump.h1
-rw-r--r--sys/sys/malloc.h10
-rw-r--r--sys/sys/mbuf.h19
-rw-r--r--sys/sys/module.h2
-rw-r--r--sys/sys/mount.h1
-rw-r--r--sys/sys/mouse.h28
-rw-r--r--sys/sys/nv.h134
-rw-r--r--sys/sys/nv_impl.h51
-rw-r--r--sys/sys/nvlist_impl.h4
-rw-r--r--sys/sys/param.h18
-rw-r--r--sys/sys/pmc.h6
-rw-r--r--sys/sys/procctl.h2
-rw-r--r--sys/sys/procfs.h27
-rw-r--r--sys/sys/racct.h4
-rw-r--r--sys/sys/seq.h8
-rw-r--r--sys/sys/socketvar.h2
-rw-r--r--sys/sys/sockio.h1
-rw-r--r--sys/sys/syscall.h2
-rw-r--r--sys/sys/syscall.mk2
-rw-r--r--sys/sys/syscallsubr.h4
-rw-r--r--sys/sys/sysproto.h92
-rw-r--r--sys/sys/systm.h1
-rw-r--r--sys/sys/vnode.h2
-rw-r--r--sys/sys/zlib.h (renamed from sys/net/zlib.h)0
-rw-r--r--sys/sys/zutil.h (renamed from sys/net/zutil.h)2
-rw-r--r--sys/ufs/ffs/ffs_alloc.c78
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c4
-rw-r--r--sys/ufs/ufs/inode.h2
-rw-r--r--sys/vm/device_pager.c2
-rw-r--r--sys/vm/sg_pager.c2
-rw-r--r--sys/vm/swap_pager.c103
-rw-r--r--sys/vm/uma_core.c14
-rw-r--r--sys/vm/vm_fault.c88
-rw-r--r--sys/vm/vm_map.c55
-rw-r--r--sys/vm/vm_mmap.c34
-rw-r--r--sys/vm/vm_page.c186
-rw-r--r--sys/vm/vm_pageout.c302
-rw-r--r--sys/vm/vm_reserv.c14
-rw-r--r--sys/vm/vm_unix.c81
-rw-r--r--sys/x86/acpica/OsdEnvironment.c2
-rw-r--r--sys/x86/acpica/acpi_wakeup.c2
-rw-r--r--sys/x86/acpica/srat.c2
-rw-r--r--sys/x86/include/apicvar.h1
-rw-r--r--sys/x86/include/mca.h2
-rw-r--r--sys/x86/include/reg.h1
-rw-r--r--sys/x86/include/segments.h8
-rw-r--r--sys/x86/iommu/busdma_dmar.c18
-rw-r--r--sys/x86/iommu/intel_dmar.h2
-rw-r--r--sys/x86/iommu/intel_gas.c33
-rw-r--r--sys/x86/pci/qpi.c2
-rw-r--r--sys/x86/x86/busdma_bounce.c9
-rw-r--r--sys/x86/x86/cpu_machdep.c486
-rw-r--r--sys/x86/x86/identcpu.c4
-rw-r--r--sys/x86/x86/intr_machdep.c7
-rw-r--r--sys/x86/x86/local_apic.c6
-rw-r--r--sys/x86/x86/mca.c27
-rw-r--r--sys/x86/x86/mp_x86.c1120
-rw-r--r--sys/x86/xen/xen_apic.c19
-rw-r--r--sys/x86/xen/xen_intr.c4
-rw-r--r--sys/x86/xen/xen_nexus.c6
-rw-r--r--tests/freebsd_test_suite/macros.h56
-rw-r--r--tests/sys/Makefile6
-rw-r--r--tests/sys/aio/Makefile16
-rw-r--r--tests/sys/aio/aio_kqueue_test.c (renamed from tools/regression/aio/kqueue/aio_kqueue.c)36
-rw-r--r--tests/sys/aio/aio_test.c (renamed from tools/regression/aio/aiotest/aiotest.c)246
-rw-r--r--tests/sys/aio/lio_kqueue_test.c (renamed from tools/regression/aio/kqueue/lio/lio_kqueue.c)22
-rw-r--r--tests/sys/fifo/Makefile13
-rw-r--r--tests/sys/fifo/fifo_create.c (renamed from tools/regression/fifo/fifo_create/fifo_create.c)17
-rw-r--r--tests/sys/fifo/fifo_io.c (renamed from tools/regression/fifo/fifo_io/fifo_io.c)48
-rw-r--r--tests/sys/fifo/fifo_misc.c (renamed from tools/regression/fifo/fifo_misc/fifo_misc.c)15
-rw-r--r--tests/sys/fifo/fifo_open.c (renamed from tools/regression/fifo/fifo_open/fifo_open.c)6
-rw-r--r--tests/sys/file/Makefile25
-rw-r--r--tests/sys/file/closefrom_test.c275
-rw-r--r--tests/sys/file/dup_test.c (renamed from tools/regression/file/dup/dup.c)0
-rw-r--r--tests/sys/file/fcntlflags_test.c (renamed from tools/regression/file/fcntlflags/fcntlflags.c)0
-rw-r--r--tests/sys/file/flock_helper.c (renamed from tools/regression/file/flock/flock.c)0
-rwxr-xr-xtests/sys/file/flock_test.sh57
-rw-r--r--tests/sys/file/ftruncate_test.c (renamed from tools/regression/file/ftruncate/ftruncate.c)24
-rw-r--r--tests/sys/file/newfileops_on_fork_test.c (renamed from tools/regression/file/newfileops_on_fork/newfileops_on_fork.c)0
-rw-r--r--tests/sys/kern/Makefile2
-rw-r--r--tests/sys/kern/execve/Makefile39
-rw-r--r--tests/sys/kern/execve/bad_interp_len (renamed from tools/regression/execve/tests/badinterplen)0
-rw-r--r--tests/sys/kern/execve/dev_null_script (renamed from tools/regression/execve/tests/devnullscript)0
-rw-r--r--tests/sys/kern/execve/execve_helper.c (renamed from tools/regression/execve/doexec.c)14
-rw-r--r--tests/sys/kern/execve/execve_test.sh115
-rw-r--r--tests/sys/kern/execve/good_aout.c (renamed from tools/regression/execve/tests/goodaout.c)4
-rw-r--r--tests/sys/kern/execve/good_script (renamed from tools/regression/execve/tests/goodscript)2
-rw-r--r--tests/sys/kern/execve/non_exist_shell (renamed from tools/regression/execve/tests/nonexistshell)0
-rw-r--r--tests/sys/kern/execve/script_arg (renamed from tools/regression/execve/tests/scriptarg)0
-rw-r--r--tests/sys/kern/execve/script_arg_nospace (renamed from tools/regression/execve/tests/scriptarg-nospace)0
-rw-r--r--tests/sys/kqueue/Makefile (renamed from tools/regression/kqueue/Makefile)13
-rw-r--r--tests/sys/kqueue/common.h (renamed from tools/regression/kqueue/common.h)0
-rw-r--r--tests/sys/kqueue/config.h (renamed from tools/regression/kqueue/config.h)0
-rwxr-xr-xtests/sys/kqueue/kqueue_test.sh17
-rw-r--r--tests/sys/kqueue/main.c (renamed from tools/regression/kqueue/main.c)0
-rw-r--r--tests/sys/kqueue/proc.c (renamed from tools/regression/kqueue/proc.c)0
-rw-r--r--tests/sys/kqueue/read.c (renamed from tools/regression/kqueue/read.c)0
-rw-r--r--tests/sys/kqueue/signal.c (renamed from tools/regression/kqueue/signal.c)0
-rw-r--r--tests/sys/kqueue/timer.c (renamed from tools/regression/kqueue/timer.c)0
-rw-r--r--tests/sys/kqueue/user.c (renamed from tools/regression/kqueue/user.c)0
-rw-r--r--tests/sys/kqueue/vnode.c (renamed from tools/regression/kqueue/vnode.c)0
-rw-r--r--tests/sys/mqueue/Makefile22
-rw-r--r--tests/sys/mqueue/mqtest1.c (renamed from tools/regression/mqueue/mqtest1/mqtest1.c)7
-rw-r--r--tests/sys/mqueue/mqtest2.c (renamed from tools/regression/mqueue/mqtest2/mqtest2.c)18
-rw-r--r--tests/sys/mqueue/mqtest3.c (renamed from tools/regression/mqueue/mqtest3/mqtest3.c)23
-rw-r--r--tests/sys/mqueue/mqtest4.c (renamed from tools/regression/mqueue/mqtest4/mqtest4.c)25
-rw-r--r--tests/sys/mqueue/mqtest5.c (renamed from tools/regression/mqueue/mqtest5/mqtest5.c)18
-rwxr-xr-x[-rw-r--r--]tests/sys/mqueue/mqueue_test.sh (renamed from tools/regression/sockets/so_setfib/so_setfib.t)78
-rw-r--r--tests/sys/vm/Makefile7
-rw-r--r--tests/sys/vm/mmap_test.c (renamed from tools/regression/mmap/mmap.c)39
-rwxr-xr-xtools/build/check-links.sh124
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc6
-rw-r--r--tools/build/options/WITHOUT_CXX2
-rw-r--r--tools/build/options/WITHOUT_SYSCALL_COMPAT2
-rw-r--r--tools/debugscripts/netstat-anr.gdb163
-rw-r--r--tools/regression/aio/aiop/Makefile2
-rw-r--r--tools/regression/aio/aiop/aiop.c112
-rw-r--r--tools/regression/aio/aiotest/Makefile11
-rw-r--r--tools/regression/aio/kqueue/Makefile10
-rw-r--r--tools/regression/aio/kqueue/lio/Makefile8
-rw-r--r--tools/regression/execve/Makefile70
-rw-r--r--tools/regression/execve/execve.t27
-rw-r--r--tools/regression/fifo/fifo_create/Makefile7
-rw-r--r--tools/regression/fifo/fifo_io/Makefile7
-rw-r--r--tools/regression/fifo/fifo_misc/Makefile7
-rw-r--r--tools/regression/fifo/fifo_open/Makefile7
-rw-r--r--tools/regression/file/closefrom/closefrom.c2
-rw-r--r--tools/regression/file/dup/Makefile7
-rw-r--r--tools/regression/file/dup/dup.t10
-rw-r--r--tools/regression/file/fcntlflags/Makefile7
-rw-r--r--tools/regression/file/fcntlflags/fcntlflags.t10
-rw-r--r--tools/regression/file/flock/Makefile9
-rw-r--r--tools/regression/file/ftruncate/Makefile7
-rw-r--r--tools/regression/file/newfileops_on_fork/Makefile8
-rw-r--r--tools/regression/gaithrstress/gaithrstress.c10
-rw-r--r--tools/regression/lib/libc/stdio/test-open_memstream.c2
-rw-r--r--tools/regression/lib/libc/stdio/test-open_wmemstream.c2
-rw-r--r--tools/regression/mmap/Makefile6
-rw-r--r--tools/regression/mqueue/Makefile5
-rw-r--r--tools/regression/mqueue/mqtest1/Makefile9
-rw-r--r--tools/regression/mqueue/mqtest2/Makefile9
-rw-r--r--tools/regression/mqueue/mqtest3/Makefile9
-rw-r--r--tools/regression/mqueue/mqtest4/Makefile9
-rw-r--r--tools/regression/mqueue/mqtest5/Makefile9
-rw-r--r--tools/regression/netinet/arphold/arphold.c2
-rw-r--r--tools/regression/p1003_1b/Makefile1
-rw-r--r--tools/regression/p1003_1b/fifo.c14
-rw-r--r--tools/regression/p1003_1b/sched.c26
-rw-r--r--tools/regression/p1003_1b/yield.c2
-rw-r--r--tools/regression/sockets/accept_fd_leak/Makefile4
-rw-r--r--tools/regression/sockets/accept_fd_leak/accept_fd_leak.c52
-rw-r--r--tools/regression/sockets/accf_data_attach/Makefile4
-rw-r--r--tools/regression/sockets/accf_data_attach/accf_data_attach.c2
-rw-r--r--tools/regression/sockets/fstat/Makefile2
-rw-r--r--tools/regression/sockets/fstat/fstat.c2
-rw-r--r--tools/regression/sockets/kqueue/Makefile1
-rw-r--r--tools/regression/sockets/kqueue/kqueue.c4
-rw-r--r--tools/regression/sockets/listen_backlog/Makefile2
-rw-r--r--tools/regression/sockets/listen_backlog/listen_backlog.c5
-rw-r--r--tools/regression/sockets/listenclose/Makefile2
-rw-r--r--tools/regression/sockets/listenclose/listenclose.c2
-rw-r--r--tools/regression/sockets/pr_atomic/Makefile2
-rw-r--r--tools/regression/sockets/pr_atomic/pr_atomic.c14
-rw-r--r--tools/regression/sockets/reconnect/Makefile2
-rw-r--r--tools/regression/sockets/reconnect/reconnect.c36
-rw-r--r--tools/regression/sockets/rtsocket/Makefile2
-rw-r--r--tools/regression/sockets/rtsocket/rtsocket.c2
-rw-r--r--tools/regression/sockets/sblock/Makefile2
-rw-r--r--tools/regression/sockets/sblock/sblock.c12
-rw-r--r--tools/regression/sockets/sendfile/sendfile.c8
-rw-r--r--tools/regression/sockets/shutdown/Makefile2
-rw-r--r--tools/regression/sockets/shutdown/shutdown.c2
-rw-r--r--tools/regression/sockets/sigpipe/Makefile2
-rw-r--r--tools/regression/sockets/sigpipe/sigpipe.c2
-rw-r--r--tools/regression/sockets/so_setfib/Makefile10
-rw-r--r--tools/regression/sockets/so_setfib/so_setfib.c11
-rw-r--r--tools/regression/sockets/socketpair/Makefile2
-rw-r--r--tools/regression/sockets/socketpair/socketpair.c2
-rw-r--r--tools/regression/sockets/unix_bindconnect/Makefile2
-rw-r--r--tools/regression/sockets/unix_bindconnect/unix_bindconnect.c10
-rw-r--r--tools/regression/sockets/unix_close_race/Makefile2
-rw-r--r--tools/regression/sockets/unix_close_race/unix_close_race.c15
-rw-r--r--tools/regression/sockets/unix_passfd/Makefile2
-rw-r--r--tools/regression/sockets/unix_passfd/unix_passfd.c8
-rw-r--r--tools/regression/sockets/unix_sendtorace/Makefile2
-rw-r--r--tools/regression/sockets/unix_sendtorace/unix_sendtorace.c23
-rw-r--r--tools/regression/sockets/unix_socket/Makefile2
-rw-r--r--tools/regression/sockets/unix_socket/unix_socket.c2
-rw-r--r--tools/regression/sockets/unix_sorflush/Makefile2
-rw-r--r--tools/regression/sockets/unix_sorflush/unix_sorflush.c2
-rw-r--r--tools/regression/sockets/zerosend/zerosend.c6
-rw-r--r--tools/tools/ath/athratestats/main.c1
-rw-r--r--tools/tools/ath/athstats/athstats.c6
-rw-r--r--tools/tools/cxgbtool/cxgbtool.c1
-rw-r--r--tools/tools/iwn/iwnstats/iwn_ioctl.c1
-rw-r--r--tools/tools/netmap/pkt-gen.c71
-rw-r--r--tools/tools/tscdrift/tscdrift.c2
-rw-r--r--usr.bin/Makefile10
-rw-r--r--usr.bin/ar/read.c10
-rw-r--r--usr.bin/bluetooth/bthost/bthost.c1
-rw-r--r--usr.bin/bluetooth/btsockstat/btsockstat.c2
-rw-r--r--usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c2
-rw-r--r--usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c1
-rw-r--r--usr.bin/bmake/Makefile10
-rw-r--r--usr.bin/bmake/unit-tests/Makefile110
-rw-r--r--usr.bin/calendar/calendars/calendar.freebsd1
-rw-r--r--usr.bin/calendar/calendars/calendar.holiday2
-rw-r--r--usr.bin/calendar/io.c3
-rw-r--r--usr.bin/col/Makefile6
-rw-r--r--usr.bin/col/col.c35
-rw-r--r--usr.bin/col/tests/Makefile11
-rwxr-xr-xusr.bin/col/tests/col.sh33
-rw-r--r--usr.bin/col/tests/rlf.in2
-rw-r--r--usr.bin/col/tests/rlf2.in2
-rw-r--r--usr.bin/cxxfilt/Makefile17
-rw-r--r--usr.bin/find/find.12
-rw-r--r--usr.bin/gcore/elf32core.c18
-rw-r--r--usr.bin/gzip/gzip.19
-rw-r--r--usr.bin/gzip/gzip.c28
-rw-r--r--usr.bin/hexdump/display.c2
-rw-r--r--usr.bin/iconv/iconv.c3
-rw-r--r--usr.bin/ipcs/Makefile2
-rw-r--r--usr.bin/ipcs/ipc.c21
-rw-r--r--usr.bin/ipcs/ipc.h5
-rw-r--r--usr.bin/ipcs/ipcs.c55
-rw-r--r--usr.bin/iscsictl/Makefile2
-rw-r--r--usr.bin/iscsictl/iscsictl.c294
-rw-r--r--usr.bin/iscsictl/parse.y59
-rw-r--r--usr.bin/iscsictl/periphs.c38
-rw-r--r--usr.bin/jot/jot.14
-rw-r--r--usr.bin/kdump/kdump.c15
-rw-r--r--usr.bin/kdump/mkioctls1
-rw-r--r--usr.bin/lam/lam.14
-rw-r--r--usr.bin/lockf/lockf.11
-rw-r--r--usr.bin/lockf/lockf.c2
-rw-r--r--usr.bin/m4/misc.c36
-rw-r--r--usr.bin/mt/Makefile3
-rw-r--r--usr.bin/mt/mt.c1
-rw-r--r--usr.bin/netstat/bpf.c1
-rw-r--r--usr.bin/netstat/if.c1
-rw-r--r--usr.bin/netstat/inet6.c1
-rw-r--r--usr.bin/netstat/mroute6.c81
-rw-r--r--usr.bin/netstat/netstat.111
-rw-r--r--usr.bin/netstat/route.c401
-rw-r--r--usr.bin/nfsstat/Makefile2
-rw-r--r--usr.bin/nfsstat/nfsstat.112
-rw-r--r--usr.bin/nfsstat/nfsstat.c555
-rw-r--r--usr.bin/patch/inp.c58
-rw-r--r--usr.bin/patch/pch.c1
-rw-r--r--usr.bin/patch/util.c6
-rw-r--r--usr.bin/perror/perror.12
-rw-r--r--usr.bin/perror/perror.c2
-rw-r--r--usr.bin/procstat/procstat_rusage.c2
-rw-r--r--usr.bin/protect/protect.12
-rw-r--r--usr.bin/protect/protect.c2
-rw-r--r--usr.bin/rctl/rctl.c47
-rw-r--r--usr.bin/rpcgen/rpc_sample.c2
-rw-r--r--usr.bin/rs/rs.14
-rw-r--r--usr.bin/smbutil/Makefile2
-rw-r--r--usr.bin/sockstat/sockstat.14
-rw-r--r--usr.bin/soelim/Makefile11
-rw-r--r--usr.bin/soelim/soelim.1 (renamed from usr.bin/soeliminate/soeliminate.1)12
-rw-r--r--usr.bin/soelim/soelim.c (renamed from usr.bin/soeliminate/soeliminate.c)38
-rw-r--r--usr.bin/soelim/tests/Makefile13
-rw-r--r--usr.bin/soelim/tests/basic1
-rw-r--r--usr.bin/soelim/tests/basic.in3
-rw-r--r--usr.bin/soelim/tests/basic.out3
-rw-r--r--usr.bin/soelim/tests/nonexisting.in3
-rwxr-xr-xusr.bin/soelim/tests/soelim.sh96
-rw-r--r--usr.bin/soeliminate/Makefile5
-rw-r--r--usr.bin/sort/bwstring.c27
-rw-r--r--usr.bin/sort/coll.c14
-rw-r--r--usr.bin/sort/file.c38
-rw-r--r--usr.bin/sort/file.h14
-rw-r--r--usr.bin/sort/mem.c1
-rw-r--r--usr.bin/sort/radixsort.c4
-rw-r--r--usr.bin/sort/sort.1.in18
-rw-r--r--usr.bin/sort/sort.c54
-rw-r--r--usr.bin/vi/Makefile2
-rw-r--r--usr.bin/w/Makefile2
-rw-r--r--usr.bin/w/w.c24
-rw-r--r--usr.bin/wc/wc.c11
-rw-r--r--usr.bin/whois/whois.c136
-rw-r--r--usr.sbin/acpi/acpiconf/acpiconf.c34
-rw-r--r--usr.sbin/acpi/acpidump/acpi.c82
-rw-r--r--usr.sbin/amd/include/config.h3
-rw-r--r--usr.sbin/ancontrol/ancontrol.c1
-rw-r--r--usr.sbin/authpf/Makefile2
-rw-r--r--usr.sbin/bhyve/Makefile2
-rw-r--r--usr.sbin/bhyve/acpi.c2
-rw-r--r--usr.sbin/bhyve/bhyverun.c11
-rw-r--r--usr.sbin/bhyve/block_if.c108
-rw-r--r--usr.sbin/bhyve/block_if.h1
-rw-r--r--usr.sbin/bhyve/ioapic.c2
-rw-r--r--usr.sbin/bhyve/ioapic.h2
-rw-r--r--usr.sbin/bhyve/pci_ahci.c249
-rw-r--r--usr.sbin/bhyve/pci_emul.c125
-rw-r--r--usr.sbin/bhyve/pci_irq.c2
-rw-r--r--usr.sbin/bhyve/pci_irq.h2
-rw-r--r--usr.sbin/bhyve/pci_virtio_block.c5
-rw-r--r--usr.sbin/bhyve/pci_virtio_net.c8
-rw-r--r--usr.sbin/bhyve/pm.c2
-rw-r--r--usr.sbin/bhyvectl/Makefile2
-rw-r--r--usr.sbin/bhyvectl/bhyvectl.c18
-rw-r--r--usr.sbin/bhyveload/Makefile2
-rw-r--r--usr.sbin/bluetooth/Makefile13
-rw-r--r--usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c1
-rw-r--r--usr.sbin/bluetooth/bthidcontrol/hid.c1
-rw-r--r--usr.sbin/bluetooth/bthidcontrol/sdp.c1
-rw-r--r--usr.sbin/bluetooth/bthidd/bthidd.c1
-rw-r--r--usr.sbin/bluetooth/bthidd/client.c5
-rw-r--r--usr.sbin/bluetooth/bthidd/hid.c21
-rw-r--r--usr.sbin/bluetooth/bthidd/kbd.c1
-rw-r--r--usr.sbin/bluetooth/bthidd/lexer.l2
-rw-r--r--usr.sbin/bluetooth/bthidd/parser.y1
-rw-r--r--usr.sbin/bluetooth/bthidd/server.c5
-rw-r--r--usr.sbin/bluetooth/bthidd/session.c1
-rw-r--r--usr.sbin/bluetooth/btpand/bnep.c1
-rw-r--r--usr.sbin/bluetooth/btpand/btpand.c1
-rw-r--r--usr.sbin/bluetooth/btpand/channel.c2
-rw-r--r--usr.sbin/bluetooth/btpand/client.c4
-rw-r--r--usr.sbin/bluetooth/btpand/event.c1
-rw-r--r--usr.sbin/bluetooth/btpand/packet.c1
-rw-r--r--usr.sbin/bluetooth/btpand/sdp.c1
-rw-r--r--usr.sbin/bluetooth/btpand/server.c4
-rw-r--r--usr.sbin/bluetooth/btpand/tap.c1
-rw-r--r--usr.sbin/bluetooth/hccontrol/Makefile2
-rw-r--r--usr.sbin/bluetooth/hccontrol/hccontrol.c8
-rw-r--r--usr.sbin/bluetooth/hccontrol/hccontrol.h1
-rw-r--r--usr.sbin/bluetooth/hccontrol/host_controller_baseband.c84
-rw-r--r--usr.sbin/bluetooth/hccontrol/info.c1
-rw-r--r--usr.sbin/bluetooth/hccontrol/le.c356
-rw-r--r--usr.sbin/bluetooth/hccontrol/link_control.c1
-rw-r--r--usr.sbin/bluetooth/hccontrol/link_policy.c1
-rw-r--r--usr.sbin/bluetooth/hccontrol/node.c1
-rw-r--r--usr.sbin/bluetooth/hccontrol/util.c15
-rw-r--r--usr.sbin/bluetooth/hcsecd/hcsecd.c1
-rw-r--r--usr.sbin/bluetooth/hcsecd/parser.y1
-rw-r--r--usr.sbin/bluetooth/l2control/l2cap.c1
-rw-r--r--usr.sbin/bluetooth/l2control/l2control.c1
-rw-r--r--usr.sbin/bluetooth/l2ping/l2ping.c1
-rw-r--r--usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c2
-rw-r--r--usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c1
-rw-r--r--usr.sbin/bluetooth/sdpcontrol/search.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/bgd.c2
-rw-r--r--usr.sbin/bluetooth/sdpd/dun.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/ftrn.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/gn.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/irmc.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/irmc_command.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/lan.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/main.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/nap.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/opush.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/panu.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/profile.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/provider.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/sar.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/scr.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/sd.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/server.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/sp.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/srr.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/ssar.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/ssr.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/sur.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/uuid.c2
-rwxr-xr-xusr.sbin/bsdinstall/scripts/zfsboot6
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/Makefile4
-rw-r--r--usr.sbin/chown/chgrp.115
-rw-r--r--usr.sbin/chown/chown.811
-rw-r--r--usr.sbin/chown/chown.c106
-rw-r--r--usr.sbin/config/main.c4
-rwxr-xr-xusr.sbin/crashinfo/crashinfo.sh6
-rw-r--r--usr.sbin/crunch/crunchide/Makefile19
-rw-r--r--usr.sbin/crunch/crunchide/crunchide.c6
-rw-r--r--usr.sbin/crunch/crunchide/exec_aout.c198
-rw-r--r--usr.sbin/crunch/crunchide/exec_elf32.c45
-rw-r--r--usr.sbin/crunch/crunchide/extern.h8
-rw-r--r--usr.sbin/ctld/ctl.conf.512
-rw-r--r--usr.sbin/ctld/ctld.c7
-rw-r--r--usr.sbin/ctld/discovery.c1
-rw-r--r--usr.sbin/ctld/isns.c6
-rw-r--r--usr.sbin/ctld/keys.c1
-rw-r--r--usr.sbin/ctld/login.c5
-rw-r--r--usr.sbin/ctld/parse.y1
-rw-r--r--usr.sbin/ctld/pdu.c2
-rw-r--r--usr.sbin/ctld/token.l1
-rw-r--r--usr.sbin/etcupdate/etcupdate.82
-rwxr-xr-xusr.sbin/etcupdate/etcupdate.sh2
-rw-r--r--usr.sbin/etcupdate/tests/always_test.sh2
-rw-r--r--usr.sbin/etcupdate/tests/conflicts_test.sh2
-rw-r--r--usr.sbin/etcupdate/tests/fbsdid_test.sh2
-rw-r--r--usr.sbin/etcupdate/tests/ignore_test.sh2
-rw-r--r--usr.sbin/etcupdate/tests/preworld_test.sh2
-rw-r--r--usr.sbin/etcupdate/tests/tests_test.sh2
-rw-r--r--usr.sbin/etcupdate/tests/tzsetup_test.sh2
-rw-r--r--usr.sbin/fifolog/fifolog_reader/Makefile2
-rw-r--r--usr.sbin/fifolog/fifolog_writer/Makefile2
-rw-r--r--usr.sbin/freebsd-update/freebsd-update.sh4
-rw-r--r--usr.sbin/ifmcstat/ifmcstat.c1
-rw-r--r--usr.sbin/inetd/inetd.c6
-rw-r--r--usr.sbin/iovctl/iovctl.c2
-rw-r--r--usr.sbin/iovctl/iovctl.conf.56
-rw-r--r--usr.sbin/ip6addrctl/ip6addrctl.c1
-rw-r--r--usr.sbin/jail/jail.81
-rw-r--r--usr.sbin/mld6query/mld6.c1
-rw-r--r--usr.sbin/mountd/mountd.88
-rw-r--r--usr.sbin/mountd/mountd.c43
-rw-r--r--usr.sbin/ndp/ndp.c1
-rw-r--r--usr.sbin/nfsd/nfsd.810
-rw-r--r--usr.sbin/nfsd/nfsd.c175
-rw-r--r--usr.sbin/ntp/config.h3
-rw-r--r--usr.sbin/ntp/doc/ntptime.84
-rw-r--r--usr.sbin/pciconf/err.c2
-rw-r--r--usr.sbin/ppp/iface.c3
-rw-r--r--usr.sbin/rip6query/rip6query.c3
-rw-r--r--usr.sbin/route6d/route6d.c1
-rw-r--r--usr.sbin/rpc.lockd/Makefile2
-rw-r--r--usr.sbin/rrenumd/lexer.l4
-rw-r--r--usr.sbin/rrenumd/parser.y3
-rw-r--r--usr.sbin/rtadvctl/rtadvctl.c1
-rw-r--r--usr.sbin/rtadvd/config.c1
-rw-r--r--usr.sbin/rtadvd/if.c1
-rw-r--r--usr.sbin/rtadvd/rrenum.c1
-rw-r--r--usr.sbin/rtadvd/rtadvd.c1
-rw-r--r--usr.sbin/rtsold/Makefile1
-rw-r--r--usr.sbin/rtsold/if.c5
-rw-r--r--usr.sbin/rtsold/probe.c1
-rw-r--r--usr.sbin/rtsold/rtsold.c1
-rw-r--r--usr.sbin/smbmsg/smbmsg.c23
-rw-r--r--usr.sbin/sysrc/sysrc2
-rw-r--r--usr.sbin/tzsetup/tzsetup.c4
-rw-r--r--usr.sbin/uhsoctl/uhsoctl.c1
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.c6
-rw-r--r--usr.sbin/wpa/Makefile.crypto5
-rw-r--r--usr.sbin/wpa/hostapd/Makefile17
-rw-r--r--usr.sbin/wpa/ndis_events/ndis_events.c1
-rw-r--r--usr.sbin/wpa/wpa_passphrase/Makefile7
-rw-r--r--usr.sbin/wpa/wpa_supplicant/Makefile11
-rw-r--r--usr.sbin/wpa/wpa_supplicant/Packet32.c1
2654 files changed, 201927 insertions, 94213 deletions
diff --git a/.arclint b/.arclint
index e153458..31bda09 100644
--- a/.arclint
+++ b/.arclint
@@ -1,9 +1,25 @@
{
+ "exclude": "(contrib|crypto)",
"linters": {
"python": {
"type": "pep8",
- "exclude": "(contrib)",
"include": "(\\.py$)"
+ },
+ "spelling": {
+ "type": "spelling"
+ },
+ "chmod": {
+ "type": "chmod"
+ },
+ "merge-conflict": {
+ "type": "merge-conflict"
+ },
+ "filename": {
+ "type": "filename"
+ },
+ "json": {
+ "type": "json",
+ "include": "(\\.arclint|\\.json$)"
}
}
}
diff --git a/Makefile b/Makefile
index d952d99..06d9f2d 100644
--- a/Makefile
+++ b/Makefile
@@ -374,8 +374,19 @@ kernel-toolchains:
# existing system is.
#
.if make(universe) || make(universe_kernels) || make(tinderbox) || make(targets)
-TARGETS?=amd64 arm i386 mips pc98 powerpc sparc64
+# XXX Add arm64 to universe only if we have an external binutils installed.
+# It does not build with the in-tree linker.
+.if exists(/usr/local/aarch64-freebsd/bin/ld)
+UNIVERSE_arm64=arm64
+.elif empty(${TARGETS})
+universe: universe_arm64_skip
+universe_epilogue: universe_arm64_skip
+universe_arm64_skip: universe_prologue
+ @echo ">> arm64 skipped - install aarch64-binutils port or package to build"
+.endif
+TARGETS?=amd64 arm ${UNIVERSE_arm64} i386 mips pc98 powerpc sparc64
TARGET_ARCHES_arm?= arm armeb armv6 armv6hf
+TARGET_ARCHES_arm64?= aarch64
TARGET_ARCHES_mips?= mipsel mips mips64el mips64 mipsn32
TARGET_ARCHES_powerpc?= powerpc powerpc64
TARGET_ARCHES_pc98?= i386
diff --git a/Makefile.inc1 b/Makefile.inc1
index 6b70564..66a6b9f 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -1387,7 +1387,8 @@ _gperf= gnu/usr.bin/gperf
.endif
.if ${MK_GROFF} != "no"
-_groff= gnu/usr.bin/groff
+_groff= gnu/usr.bin/groff \
+ usr.bin/soelim
.endif
.if ${MK_VT} != "no"
@@ -1405,10 +1406,6 @@ _m4= lib/libohash \
${_bt}-usr.bin/m4: ${_bt}-lib/libohash
.endif
-.if ${BOOTSTRAPPING} < 1000014
-_crunch= usr.sbin/crunch
-.endif
-
.if ${BOOTSTRAPPING} < 1000026
_nmtree= lib/libnetbsd \
usr.sbin/nmtree
@@ -1424,16 +1421,18 @@ _cat= bin/cat
_lex= usr.bin/lex
.endif
+.if ${BOOTSTRAPPING} < 1001507
+_crunch= usr.sbin/crunch
+.endif
+
.if ${BOOTSTRAPPING} >= 900040 && ${BOOTSTRAPPING} < 900041
_awk= usr.bin/awk
.endif
-.if ${BOOTSTRAPPING} < 1001506
_yacc= lib/liby \
usr.bin/yacc
${_bt}-usr.bin/yacc: ${_bt}-lib/liby
-.endif
.if ${MK_BSNMP} != "no"
_gensnmptree= usr.sbin/bsnmpd/gensnmptree
@@ -1483,8 +1482,7 @@ _kerberos5_bootstrap_tools= \
kerberos5/tools/slc \
usr.bin/compile_et
-${_bt}-kerberos5/tools/slc: ${_bt}-kerberos5/lib/libroken
-${_bt}-kerberos5/tools/asn1_compile: ${_bt}-kerberos5/lib/libroken
+.ORDER: ${_kerberos5_bootstrap_tools:C/^/${_bt}-/g}
.endif
bootstrap-tools: .PHONY
@@ -1590,12 +1588,9 @@ _btxld= usr.sbin/btxld
.endif
.endif
.if ${TARGET_ARCH} != ${MACHINE_ARCH}
-.if ${MK_RESCUE} != "no" || defined(RELEASEDIR)
+.if ${MK_RESCUE} != "no"
_crunchide= usr.sbin/crunch/crunchide
.endif
-.if ${TARGET_ARCH} == "i386" && defined(RELEASEDIR)
-_kgzip= usr.sbin/kgzip
-.endif
.endif
# If we're given an XAS, don't build binutils.
@@ -1641,7 +1636,6 @@ cross-tools: .MAKE
${_cc} \
${_btxld} \
${_crunchide} \
- ${_kgzip} \
sys/boot/usb/tools
${_+_}@${ECHODIR} "===> ${_tool} (obj,depend,all,install)"; \
cd ${.CURDIR}/${_tool} && \
@@ -1653,7 +1647,8 @@ cross-tools: .MAKE
NXBENV= MAKEOBJDIRPREFIX=${OBJTREE}/nxb \
INSTALL="sh ${.CURDIR}/tools/install.sh" \
- VERSION="${VERSION}"
+ VERSION="${VERSION}" \
+ PATH=${PATH}:${OBJTREE}/gperf_for_gcc/usr/bin
NXBMAKE= ${NXBENV} ${MAKE} \
TBLGEN=${OBJTREE}/nxb-bin/usr/bin/tblgen \
CLANG_TBLGEN=${OBJTREE}/nxb-bin/usr/bin/clang-tblgen \
@@ -1666,7 +1661,21 @@ NXBMAKE= ${NXBENV} ${MAKE} \
MK_CLANG_EXTRAS=no MK_CLANG_FULL=no \
MK_LLDB=no
+# native-xtools is the current target for qemu-user cross builds of ports
+# via poudriere and the imgact_binmisc kernel module.
+# For non-clang enabled targets that are still using the in tree gcc
+# we must build a gperf binary for one instance of its Makefiles. On
+# clang-enabled systems, the gperf binary is obsolete.
native-xtools: .MAKE
+.if ${MK_GCC_BOOTSTRAP} != "no"
+ mkdir -p ${OBJTREE}/gperf_for_gcc/usr/bin
+ ${_+_}@${ECHODIR} "===> ${_gperf} (obj,depend,all,install)"; \
+ cd ${.CURDIR}/${_gperf} && \
+ ${NXBMAKE} DIRPRFX=${_gperf}/ obj && \
+ ${NXBMAKE} DIRPRFX=${_gperf}/ depend && \
+ ${NXBMAKE} DIRPRFX=${_gperf}/ all && \
+ ${NXBMAKE} DIRPRFX=${_gperf}/ DESTDIR=${OBJTREE}/gperf_for_gcc install
+.endif
mkdir -p ${OBJTREE}/nxb-bin/bin
mkdir -p ${OBJTREE}/nxb-bin/sbin
mkdir -p ${OBJTREE}/nxb-bin/usr
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index 434a74a..a8a9f90 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -38,6 +38,90 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20150501
+OLD_FILES+=usr/bin/soeliminate
+OLD_FILES+=usr/share/man/man1/soeliminate.1.gz
+# 20150501: Remove the nvlist_.*[vf] functions manpages.
+OLD_FILES+=usr/share/man/man3/nvlist_addf_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addf_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addf_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addf_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addf_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addf_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addf_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addv_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addv_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addv_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addv_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addv_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addv_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_addv_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsf_type.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_existsv_type.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freef_type.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_freev_type.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getf_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getf_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getf_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getf_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getf_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getf_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getv_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getv_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getv_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getv_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getv_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_getv_string.3.gz
+# 20150429:
+OLD_FILES+=usr/share/docs/papers/hwpmc.ascii.gz
+# 20150427: test/sys/kern/mmap_test moved to test/sys/vm/mmap_test
+OLD_FILES+=usr/tests/sys/kern/mmap_test
+# 20150418
+OLD_FILES+=sbin/mount_oldnfs
+OLD_FILES+=usr/share/man/man8/mount_oldnfs.8.gz
+# 20150416: ALTQ moved to net/altq
+OLD_FILES+=usr/include/altq/altq_rmclass_debug.h
+OLD_FILES+=usr/include/altq/altq.h
+OLD_FILES+=usr/include/altq/altq_cdnr.h
+OLD_FILES+=usr/include/altq/altq_hfsc.h
+OLD_FILES+=usr/include/altq/altq_priq.h
+OLD_FILES+=usr/include/altq/altqconf.h
+OLD_FILES+=usr/include/altq/altq_classq.h
+OLD_FILES+=usr/include/altq/altq_red.h
+OLD_FILES+=usr/include/altq/if_altq.h
+OLD_FILES+=usr/include/altq/altq_var.h
+OLD_FILES+=usr/include/altq/altq_rmclass.h
+OLD_FILES+=usr/include/altq/altq_cbq.h
+OLD_FILES+=usr/include/altq/altq_rio.h
+OLD_DIRS+=usr/include/altq
# 20150329
.if ${TARGET_ARCH} == "arm"
OLD_FILES+=usr/include/bootconfig.h
@@ -323,6 +407,10 @@ OLD_FILES+=usr/lib/debug/usr/lib32/i18n
OLD_FILES+=usr/lib/debug/usr/lib32/private
# 20141015: OpenSSL 1.0.1j import
OLD_FILES+=usr/share/openssl/man/man3/CMS_sign_add1_signer.3.gz
+.if ${MK_GCC} == "no"
+# 20141009: gperf disabled by default
+OLD_FILES+=usr/bin/gperf
+.endif
# 20140922: sleepq_calc_signal_retval.9 and sleepq_catch_signals.9 removed
OLD_FILES+=usr/share/man/man9/sleepq_calc_signal_retval.9.gz
OLD_FILES+=usr/share/man/man9/sleepq_catch_signals.9.gz
diff --git a/README b/README
index 4e49142..266dfb1 100644
--- a/README
+++ b/README
@@ -8,39 +8,32 @@ sources in this tree - please see the specific source directories for
more information).
The Makefile in this directory supports a number of targets for
-building components (or all) of the FreeBSD source tree, the most
-commonly used one being ``world'', which rebuilds and installs
-everything in the FreeBSD system from the source tree except the
-kernel, the kernel-modules and the contents of /etc. The ``world''
-target should only be used in cases where the source tree has not
-changed from the currently running version. See:
-http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html
+building components (or all) of the FreeBSD source tree. See build(7)
+and http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html
for more information, including setting make(1) variables.
-The ``buildkernel'' and ``installkernel'' targets build and install
+The `buildkernel` and `installkernel` targets build and install
the kernel and the modules (see below). Please see the top of
the Makefile in this directory for more information on the
standard build targets and compile-time flags.
-Building a kernel is a somewhat more involved process, documentation
-for which can be found at:
- http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig.html
-And in the config(8) man page.
+Building a kernel is a somewhat more involved process. See build(7), config(8),
+and http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig.html
+for more information.
+
Note: If you want to build and install the kernel with the
-``buildkernel'' and ``installkernel'' targets, you might need to build
+`buildkernel` and `installkernel` targets, you might need to build
world before. More information is available in the handbook.
-The sample kernel configuration files reside in the sys/<arch>/conf
-sub-directory (assuming that you've installed the kernel sources), the
-file named GENERIC being the one used to build your initial installation
-kernel. The file NOTES contains entries and documentation for all possible
-devices, not just those commonly used. It is the successor of the ancient
-LINT file, but in contrast to LINT, it is not buildable as a kernel but a
-pure reference and documentation file.
+The kernel configuration files reside in the sys/<arch>/conf
+sub-directory. GENERIC is the default configuration used in release builds.
+NOTES contains entries and documentation for all possible
+devices, not just those commonly used.
Source Roadmap:
---------------
+
bin System/user commands.
cddl Various commands and libraries under the Common Development
@@ -77,6 +70,9 @@ share Shared resources.
sys Kernel sources.
+tests Regression tests which can be run by Kyua. See tests/README
+ for additional information.
+
tools Utilities for regression testing and miscellaneous tasks.
usr.bin User commands.
diff --git a/UPDATING b/UPDATING
index 175a916..12b554c 100644
--- a/UPDATING
+++ b/UPDATING
@@ -31,6 +31,24 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW:
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
+20150501:
+ soelim(1) from gnu/usr.bin/groff has been replaced by usr.bin/soelim.
+ If you need the GNU extension from groff soelim(1), install groff
+ from package: pkg install groff, or via ports: textproc/groff.
+
+20150423:
+ chmod, chflags, chown and chgrp now affect symlinks in -R mode as
+ defined in symlink(7); previously symlinks were silently ignored.
+
+20150415:
+ The const qualifier has been removed from iconv(3) to comply with
+ POSIX. The ports tree is aware of this from r384038 onwards.
+
+20150416:
+ Libraries specified by LIBADD in Makefiles must have a corresponding
+ DPADD_<lib> variable to ensure correct dependencies. This is now
+ enforced in src.libnames.mk.
+
20150324:
From legacy ata(4) driver was removed support for SATA controllers
supported by more functional drivers ahci(4), siis(4) and mvs(4).
diff --git a/bin/chflags/chflags.1 b/bin/chflags/chflags.1
index 47d5b18..755cbce 100644
--- a/bin/chflags/chflags.1
+++ b/bin/chflags/chflags.1
@@ -32,7 +32,7 @@
.\" @(#)chflags.1 8.4 (Berkeley) 5/2/95
.\" $FreeBSD$
.\"
-.Dd April 8, 2013
+.Dd April 20, 2015
.Dt CHFLAGS 1
.Os
.Sh NAME
@@ -66,8 +66,9 @@ nor modify the exit status to reflect such failures.
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during traversal are not followed.)
.It Fl h
If the
.Ar file
@@ -83,8 +84,12 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the file flags for the file hierarchies rooted
-in the files instead of just the files themselves.
+Change the file flags of the file hierarchies rooted in the files,
+instead of just the files themselves.
+Beware of unintentionally matching the
+.Dq Pa ".."
+hard link to the parent directory when using wildcards like
+.Dq Li ".*" .
.It Fl v
Cause
.Nm
diff --git a/bin/chflags/chflags.c b/bin/chflags/chflags.c
index e94c34d..2029ac5 100644
--- a/bin/chflags/chflags.c
+++ b/bin/chflags/chflags.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
@@ -65,7 +66,6 @@ main(int argc, char *argv[])
int Hflag, Lflag, Rflag, fflag, hflag, vflag;
int ch, fts_options, oct, rval;
char *flags, *ep;
- int (*change_flags)(const char *, unsigned long);
Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
@@ -104,20 +104,23 @@ main(int argc, char *argv[])
usage();
if (Rflag) {
- fts_options = FTS_PHYSICAL;
if (hflag)
- errx(1, "the -R and -h options "
- "may not be specified together");
- if (Hflag)
- fts_options |= FTS_COMFOLLOW;
+ errx(1, "the -R and -h options may not be "
+ "specified together.");
if (Lflag) {
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
- }
- } else
- fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+ fts_options = FTS_LOGICAL;
+ } else {
+ fts_options = FTS_PHYSICAL;
- change_flags = hflag ? lchflags : chflags;
+ if (Hflag) {
+ fts_options |= FTS_COMFOLLOW;
+ }
+ }
+ } else if (hflag) {
+ fts_options = FTS_PHYSICAL;
+ } else {
+ fts_options = FTS_LOGICAL;
+ }
flags = *argv;
if (*flags >= '0' && *flags <= '7') {
@@ -142,12 +145,21 @@ main(int argc, char *argv[])
err(1, NULL);
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ int atflag;
+
+ if ((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) &&
+ p->fts_level == FTS_ROOTLEVEL))
+ atflag = 0;
+ else
+ atflag = AT_SYMLINK_NOFOLLOW;
+
switch (p->fts_info) {
case FTS_D: /* Change it at FTS_DP if we're recursive. */
if (!Rflag)
fts_set(ftsp, p, FTS_SKIP);
continue;
- case FTS_DNR: /* Warn, chflag, continue. */
+ case FTS_DNR: /* Warn, chflags. */
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
break;
@@ -156,16 +168,6 @@ main(int argc, char *argv[])
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
continue;
- case FTS_SL: /* Ignore. */
- case FTS_SLNONE:
- /*
- * The only symlinks that end up here are ones that
- * don't point to anything and ones that we found
- * doing a physical walk.
- */
- if (!hflag)
- continue;
- /* FALLTHROUGH */
default:
break;
}
@@ -175,7 +177,8 @@ main(int argc, char *argv[])
newflags = (p->fts_statp->st_flags | set) & clear;
if (newflags == p->fts_statp->st_flags)
continue;
- if ((*change_flags)(p->fts_accpath, newflags) && !fflag) {
+ if (chflagsat(AT_FDCWD, p->fts_accpath, newflags,
+ atflag) == -1 && !fflag) {
warn("%s", p->fts_path);
rval = 1;
} else if (vflag) {
diff --git a/bin/chmod/chmod.1 b/bin/chmod/chmod.1
index 34a1ff0..7efaabc 100644
--- a/bin/chmod/chmod.1
+++ b/bin/chmod/chmod.1
@@ -32,7 +32,7 @@
.\" @(#)chmod.1 8.4 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd January 26, 2009
+.Dd April 20, 2015
.Dt CHMOD 1
.Os
.Sh NAME
@@ -63,9 +63,9 @@ nor modify the exit status to reflect such failures.
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed by
-default.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during tree traversal are not followed.)
.It Fl h
If the file is a symbolic link, change the mode of the link itself
rather than the file that the link points to.
@@ -79,8 +79,12 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the modes of the file hierarchies rooted in the files
+Change the modes of the file hierarchies rooted in the files,
instead of just the files themselves.
+Beware of unintentionally matching the
+.Dq Pa ".."
+hard link to the parent directory when using wildcards like
+.Dq Li ".*" .
.It Fl v
Cause
.Nm
diff --git a/bin/chmod/chmod.c b/bin/chmod/chmod.c
index dc51faa..9b80157 100644
--- a/bin/chmod/chmod.c
+++ b/bin/chmod/chmod.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <fts.h>
#include <limits.h>
#include <stdio.h>
@@ -62,7 +63,7 @@ main(int argc, char *argv[])
FTS *ftsp;
FTSENT *p;
mode_t *set;
- int Hflag, Lflag, Rflag, ch, error, fflag, fts_options, hflag, rval;
+ int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval;
int vflag;
char *mode;
mode_t newmode;
@@ -126,18 +127,23 @@ done: argv += optind;
usage();
if (Rflag) {
- fts_options = FTS_PHYSICAL;
if (hflag)
- errx(1,
- "the -R and -h options may not be specified together.");
- if (Hflag)
- fts_options |= FTS_COMFOLLOW;
+ errx(1, "the -R and -h options may not be "
+ "specified together.");
if (Lflag) {
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
+ fts_options = FTS_LOGICAL;
+ } else {
+ fts_options = FTS_PHYSICAL;
+
+ if (Hflag) {
+ fts_options |= FTS_COMFOLLOW;
+ }
}
- } else
- fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+ } else if (hflag) {
+ fts_options = FTS_PHYSICAL;
+ } else {
+ fts_options = FTS_LOGICAL;
+ }
mode = *argv;
if ((set = setmode(mode)) == NULL)
@@ -146,12 +152,21 @@ done: argv += optind;
if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
err(1, "fts_open");
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ int atflag;
+
+ if ((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) &&
+ p->fts_level == FTS_ROOTLEVEL))
+ atflag = 0;
+ else
+ atflag = AT_SYMLINK_NOFOLLOW;
+
switch (p->fts_info) {
case FTS_D: /* Change it at FTS_DP. */
if (!Rflag)
fts_set(ftsp, p, FTS_SKIP);
continue;
- case FTS_DNR: /* Warn, chmod, continue. */
+ case FTS_DNR: /* Warn, chmod. */
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
break;
@@ -160,16 +175,6 @@ done: argv += optind;
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
continue;
- case FTS_SL: /* Ignore. */
- case FTS_SLNONE:
- /*
- * The only symlinks that end up here are ones that
- * don't point to anything and ones that we found
- * doing a physical walk.
- */
- if (!hflag)
- continue;
- /* FALLTHROUGH */
default:
break;
}
@@ -182,32 +187,25 @@ done: argv += optind;
if (may_have_nfs4acl(p, hflag) == 0 &&
(newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
continue;
- if (hflag)
- error = lchmod(p->fts_accpath, newmode);
- else
- error = chmod(p->fts_accpath, newmode);
- if (error) {
- if (!fflag) {
- warn("%s", p->fts_path);
- rval = 1;
- }
- } else {
- if (vflag) {
- (void)printf("%s", p->fts_path);
-
- if (vflag > 1) {
- char m1[12], m2[12];
-
- strmode(p->fts_statp->st_mode, m1);
- strmode((p->fts_statp->st_mode &
- S_IFMT) | newmode, m2);
- (void)printf(": 0%o [%s] -> 0%o [%s]",
- p->fts_statp->st_mode, m1,
- (p->fts_statp->st_mode & S_IFMT) |
- newmode, m2);
- }
- (void)printf("\n");
+ if (fchmodat(AT_FDCWD, p->fts_accpath, newmode, atflag) == -1
+ && !fflag) {
+ warn("%s", p->fts_path);
+ rval = 1;
+ } else if (vflag) {
+ (void)printf("%s", p->fts_path);
+
+ if (vflag > 1) {
+ char m1[12], m2[12];
+
+ strmode(p->fts_statp->st_mode, m1);
+ strmode((p->fts_statp->st_mode &
+ S_IFMT) | newmode, m2);
+ (void)printf(": 0%o [%s] -> 0%o [%s]",
+ p->fts_statp->st_mode, m1,
+ (p->fts_statp->st_mode & S_IFMT) |
+ newmode, m2);
}
+ (void)printf("\n");
}
}
if (errno)
diff --git a/bin/csh/config.h b/bin/csh/config.h
index 99f7d0b..99aed5f 100644
--- a/bin/csh/config.h
+++ b/bin/csh/config.h
@@ -198,7 +198,7 @@
#define HAVE_WCWIDTH 1
/* Define as const if the declaration of iconv() needs const. */
-#define ICONV_CONST const
+#define ICONV_CONST
/* Support NLS. */
#define NLS 1
diff --git a/bin/csh/iconv_stub.h b/bin/csh/iconv_stub.h
index 89e9d0d..a3e069a0 100644
--- a/bin/csh/iconv_stub.h
+++ b/bin/csh/iconv_stub.h
@@ -30,7 +30,7 @@
#define _ICONV_H_
typedef void *iconv_t;
-typedef size_t dl_iconv_t(iconv_t, const char **, size_t *, char **, size_t *);
+typedef size_t dl_iconv_t(iconv_t, char **, size_t *, char **, size_t *);
typedef int dl_iconv_close_t(iconv_t);
extern iconv_t dl_iconv_open(const char *, const char *);
diff --git a/bin/ed/ed.1 b/bin/ed/ed.1
index 8342645..335dbd8 100644
--- a/bin/ed/ed.1
+++ b/bin/ed/ed.1
@@ -738,7 +738,7 @@ It is an error if no substitutions are performed on any of the addressed
lines.
The current address is set the last line affected.
.Pp
-.Ar Re
+.Ar \&Re
and
.Ar replacement
may be delimited by any character other than space and newline
diff --git a/bin/ed/glbl.c b/bin/ed/glbl.c
index 5524700..dfb44d2 100644
--- a/bin/ed/glbl.c
+++ b/bin/ed/glbl.c
@@ -60,7 +60,7 @@ build_active_list(int isgcmd)
return ERR;
if (isbinary)
NUL_TO_NEWLINE(s, lp->len);
- if (!regexec(pat, s, 0, NULL, 0) == isgcmd &&
+ if (!(regexec(pat, s, 0, NULL, 0) == isgcmd) &&
set_active_node(lp) < 0)
return ERR;
}
@@ -153,7 +153,7 @@ set_active_node(line_t *lp)
if (active_list != NULL) {
#endif
if ((ts = (line_t **) realloc(active_list,
- (ti += MINBUFSZ) * sizeof(line_t **))) == NULL) {
+ (ti += MINBUFSZ) * sizeof(line_t *))) == NULL) {
fprintf(stderr, "%s\n", strerror(errno));
errmsg = "out of memory";
SPL0();
diff --git a/bin/expr/expr.1 b/bin/expr/expr.1
index 34be0b8f..d021055 100644
--- a/bin/expr/expr.1
+++ b/bin/expr/expr.1
@@ -90,17 +90,17 @@ Return the evaluation of
.Ar expr1
if neither expression evaluates to an empty string or zero;
otherwise, returns zero.
-.It Ar expr1 Li "{=, >, >=, <, <=, !=}" Ar expr2
+.It Ar expr1 Bro =, >, >=, <, <=, != Brc Ar expr2
Return the results of integer comparison if both arguments are integers;
otherwise, returns the results of string comparison using the locale-specific
collation sequence.
The result of each comparison is 1 if the specified relation is true,
or 0 if the relation is false.
-.It Ar expr1 Li "{+, -}" Ar expr2
+.It Ar expr1 Bro +, - Brc Ar expr2
Return the results of addition or subtraction of integer-valued arguments.
-.It Ar expr1 Li "{*, /, %}" Ar expr2
+.It Ar expr1 Bro *, /, % Brc Ar expr2
Return the results of multiplication, integer division, or remainder of integer-valued arguments.
-.It Ar expr1 Li : Ar expr2
+.It Ar expr1 Li \&: Ar expr2
The
.Dq Li \&:
operator matches
diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c
index 753cf7b..b531231 100644
--- a/bin/sh/jobs.c
+++ b/bin/sh/jobs.c
@@ -1057,7 +1057,7 @@ waitforjob(struct job *jp, int *origstatus)
CLEAR_PENDING_INT;
}
#if JOBS
- else if (rootshell && iflag && propagate_int &&
+ else if (rootshell && propagate_int &&
WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
kill(getpid(), SIGINT);
#endif
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
index b22a98f..e5707c0 100644
--- a/bin/sh/sh.1
+++ b/bin/sh/sh.1
@@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
-.Dd February 22, 2015
+.Dd April 18, 2015
.Dt SH 1
.Os
.Sh NAME
@@ -2574,8 +2574,7 @@ the former causes the specified signal to be ignored
and the latter causes the default action to be taken.
Omitting the
.Ar action
-is another way to request the default action, for compatibility reasons this
-usage is not recommended though.
+and using only signal numbers is another way to request the default action.
In a subshell or utility environment,
the shell resets trapped (but not ignored) signals to the default action.
The
diff --git a/bin/sh/tests/builtins/Makefile b/bin/sh/tests/builtins/Makefile
index 5f5da4a..ad39aac 100644
--- a/bin/sh/tests/builtins/Makefile
+++ b/bin/sh/tests/builtins/Makefile
@@ -137,6 +137,8 @@ FILES+= trap11.0
FILES+= trap12.0
FILES+= trap13.0
FILES+= trap14.0
+FILES+= trap15.0
+FILES+= trap16.0
FILES+= trap2.0
FILES+= trap3.0
FILES+= trap4.0
diff --git a/bin/sh/tests/builtins/trap15.0 b/bin/sh/tests/builtins/trap15.0
new file mode 100644
index 0000000..6b9857d
--- /dev/null
+++ b/bin/sh/tests/builtins/trap15.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+(${SH} -c 'term(){ exit 5;}; trap term TERM; kill -TERM $$') &
+wait >/dev/null 2>&1 $!
+[ $? -eq 5 ]
diff --git a/bin/sh/tests/builtins/trap16.0 b/bin/sh/tests/builtins/trap16.0
new file mode 100644
index 0000000..3d70cce
--- /dev/null
+++ b/bin/sh/tests/builtins/trap16.0
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+traps=$(${SH} -c 'trap "echo bad" 0; trap - 0; trap')
+[ -z "$traps" ] || exit 1
+traps=$(${SH} -c 'trap "echo bad" 0; trap "" 0; trap')
+expected_traps=$(${SH} -c 'trap "" EXIT; trap')
+[ "$traps" = "$expected_traps" ] || exit 2
+traps=$(${SH} -c 'trap "echo bad" 0; trap 0; trap')
+[ -z "$traps" ] || exit 3
+traps=$(${SH} -c 'trap "echo bad" 0; trap -- 0; trap')
+[ -z "$traps" ] || exit 4
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap - 0 1 2; trap')
+[ -z "$traps" ] || exit 5
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap "" 0 1 2; trap')
+expected_traps=$(${SH} -c 'trap "" EXIT HUP INT; trap')
+[ "$traps" = "$expected_traps" ] || exit 6
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap 0 1 2; trap')
+[ -z "$traps" ] || exit 7
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap -- 0 1 2; trap')
+[ -z "$traps" ] || exit 8
diff --git a/bin/sh/trap.c b/bin/sh/trap.c
index 4a185b4..f562e27 100644
--- a/bin/sh/trap.c
+++ b/bin/sh/trap.c
@@ -183,7 +183,7 @@ trapcmd(int argc __unused, char **argv)
return 0;
}
action = NULL;
- if (*argv && sigstring_to_signum(*argv) == -1) {
+ if (*argv && !is_number(*argv)) {
if (strcmp(*argv, "-") == 0)
argv++;
else {
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
index 2d210a2..907baee 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
+++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
@@ -21,7 +21,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 5, 2013
+.Dd April 18, 2015
.Dt DTRACE 1
.Os
.Sh NAME
@@ -670,7 +670,8 @@ Invalid command line options or arguments were specified.
.Sh SEE ALSO
.Xr cpp 1 ,
.Xr dtruss 1 ,
-.Xr elf 5
+.Xr elf 5 ,
+.Xr SDT 9
.Rs
.%T Solaris Dynamic Tracing Guide
.Re
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
index a75dc02..5fab935 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
@@ -147,6 +147,9 @@ dtrace_dof_init(void)
dh.dofhp_dof = (uintptr_t)dof;
dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0;
+#ifdef __FreeBSD__
+ dh.dofhp_pid = getpid();
+#endif
if (lmid == 0) {
(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
@@ -184,7 +187,7 @@ dtrace_dof_init(void)
else {
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
#ifdef __FreeBSD__
- gen = dh.gen;
+ gen = dh.dofhp_gen;
#endif
}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index ae41269..eaf0961 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -1785,11 +1785,17 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
"failed to open %s: %s", file, strerror(errno)));
}
#else
- snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
- if ((fd = mkstemp(tfile)) == -1)
- return (dt_link_error(dtp, NULL, -1, NULL,
- "failed to create temporary file %s: %s",
- tfile, strerror(errno)));
+ if (dtp->dt_lazyload) {
+ if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to open %s: %s", file, strerror(errno)));
+ } else {
+ snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
+ if ((fd = mkstemp(tfile)) == -1)
+ return (dt_link_error(dtp, NULL, -1, NULL,
+ "failed to create temporary file %s: %s",
+ tfile, strerror(errno)));
+ }
#endif
/*
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
index e628e62..c61a710 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
@@ -44,10 +44,15 @@
#include <dt_program.h>
#include <dt_pid.h>
#include <dt_string.h>
+#include <dt_module.h>
+
#ifndef illumos
+#include <sys/sysctl.h>
+#include <unistd.h>
#include <libproc_compat.h>
+#include <libelf.h>
+#include <gelf.h>
#endif
-#include <dt_module.h>
typedef struct dt_pid_probe {
dtrace_hdl_t *dpp_dtp;
@@ -566,6 +571,12 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
prsyminfo_t sip;
dof_helper_t dh;
GElf_Half e_type;
+#ifdef __FreeBSD__
+ dof_hdr_t hdr;
+ size_t sz;
+ uint64_t dofmax;
+ void *dof;
+#endif
const char *mname;
const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
int i, fd = -1;
@@ -595,17 +606,61 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
continue;
}
- dh.dofhp_dof = sym.st_value;
+#ifdef __FreeBSD__
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
+ if (Pread(P, &hdr, sizeof (hdr), sym.st_value) !=
+ sizeof (hdr)) {
+ dt_dprintf("read of DOF header failed\n");
+ continue;
+ }
+
+ sz = sizeof(dofmax);
+ if (sysctlbyname("kern.dtrace.dof_maxsize", &dofmax, &sz,
+ NULL, 0) != 0) {
+ dt_dprintf("failed to read dof_maxsize: %s\n",
+ strerror(errno));
+ continue;
+ }
+ if (dofmax < hdr.dofh_loadsz) {
+ dt_dprintf("DOF load size exceeds maximum\n");
+ continue;
+ }
+
+ if ((dof = malloc(hdr.dofh_loadsz)) == NULL)
+ return (-1);
+
+ if (Pread(P, dof, hdr.dofh_loadsz, sym.st_value) !=
+ hdr.dofh_loadsz) {
+ free(dof);
+ dt_dprintf("read of DOF section failed\n");
+ continue;
+ }
+
+ dh.dofhp_dof = (uintptr_t)dof;
+ dh.dofhp_pid = proc_getpid(P);
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
-#ifdef illumos
sip.prs_lmid, mname);
+
+ if (fd == -1 &&
+ (fd = open("/dev/dtrace/helper", O_RDWR, 0)) < 0) {
+ dt_dprintf("open of helper device failed: %s\n",
+ strerror(errno));
+ free(dof);
+ return (-1); /* errno is set for us */
+ }
+
+ if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
+ dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
+
+ free(dof);
#else
- 0, mname);
-#endif
+ dh.dofhp_dof = sym.st_value;
+ dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
+
+ dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
+ sip.prs_lmid, mname);
-#ifdef illumos
if (fd == -1 &&
(fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("pr_open of helper device failed: %s\n",
@@ -618,8 +673,10 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
#endif
}
-#ifdef illumos
if (fd != -1)
+#ifdef __FreeBSD__
+ (void) close(fd);
+#else
(void) pr_close(P, fd);
#endif
@@ -634,7 +691,6 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
int ret = 0;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
-#ifdef illumos
(void) Pupdate_maps(P);
if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
ret = -1;
@@ -646,9 +702,6 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
(int)proc_getpid(P), strerror(errno));
#endif
}
-#else
- ret = 0;
-#endif
/*
* Put the module name in its canonical form.
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
index 7a265bd..7ad5141 100644
--- a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
+++ b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
@@ -793,6 +793,7 @@ dump_nvlist(nvlist_t *list, int indent)
{
nvpair_t *elem = NULL;
boolean_t bool_value;
+ boolean_t *bool_array_value;
nvlist_t *nvlist_value;
nvlist_t **nvlist_array_value;
uint_t i, count;
@@ -853,6 +854,16 @@ dump_nvlist(nvlist_t *list, int indent)
NVP(elem, string, char *, char *, "'%s'");
break;
+ case DATA_TYPE_BOOLEAN_ARRAY:
+ (void) nvpair_value_boolean_array(elem,
+ &bool_array_value, &count);
+ for (i = 0; i < count; i++) {
+ (void) printf("%*s%s[%d]: %s\n", indent, "",
+ nvpair_name(elem), i,
+ bool_array_value[i] ? "true" : "false");
+ }
+ break;
+
case DATA_TYPE_BYTE_ARRAY:
NVPA(elem, byte_array, uchar_t, int, "%u");
break;
diff --git a/cddl/lib/libdtrace/libproc_compat.h b/cddl/lib/libdtrace/libproc_compat.h
index 0d99d96..8704b82 100644
--- a/cddl/lib/libdtrace/libproc_compat.h
+++ b/cddl/lib/libdtrace/libproc_compat.h
@@ -59,6 +59,6 @@
#define Pstate proc_state
#define Psymbol_iter_by_addr proc_iter_symbyaddr
#define Punsetflags proc_clearflags
-#define Pupdate_maps(p) do { } while (0)
+#define Pupdate_maps proc_rdagent
#define Pupdate_syms proc_updatesyms
#define Pxecbkpt proc_bkptexec
diff --git a/cddl/lib/libdtrace/tcp.d b/cddl/lib/libdtrace/tcp.d
index 4b826f1..e642020 100644
--- a/cddl/lib/libdtrace/tcp.d
+++ b/cddl/lib/libdtrace/tcp.d
@@ -241,3 +241,78 @@ translator tcpinfoh_t < struct tcphdr *p > {
translator tcplsinfo_t < int s > {
tcps_state = s;
};
+
+/*
+ * Convert a SIFTR direction value to a string
+ */
+#pragma D binding "1.12.1" SIFTR_IN
+inline int SIFTR_IN = 1;
+#pragma D binding "1.12.1" SIFTR_OUT
+inline int SIFTR_OUT = 2;
+
+/* SIFTR direction strings. */
+#pragma D binding "1.12.1" siftr_dir_string
+inline string siftr_dir_string[uint8_t direction] =
+ direction == SIFTR_IN ? "in" :
+ direction == SIFTR_OUT ? "out" :
+ "unknown" ;
+
+typedef struct siftrinfo {
+ struct timeval tval;
+ uint8_t direction;
+ uint8_t ipver;
+ uint32_t hash;
+ uint16_t tcp_localport;
+ uint16_t tcp_foreignport;
+ uint64_t snd_cwnd;
+ u_long snd_wnd;
+ u_long rcv_wnd;
+ u_long snd_bwnd;
+ u_long snd_ssthresh;
+ int conn_state;
+ u_int max_seg_size;
+ int smoothed_rtt;
+ u_char sack_enabled;
+ u_char snd_scale;
+ u_char rcv_scale;
+ u_int flags;
+ int rxt_length;
+ u_int snd_buf_hiwater;
+ u_int snd_buf_cc;
+ u_int rcv_buf_hiwater;
+ u_int rcv_buf_cc;
+ u_int sent_inflight_bytes;
+ int t_segqlen;
+ u_int flowid;
+ u_int flowtype;
+} siftrinfo_t;
+
+#pragma D binding "1.12.1" translator
+translator siftrinfo_t < struct pkt_node *p > {
+ direction = p == NULL ? 0 : p->direction;
+ ipver = p == NULL ? 0 : p->ipver;
+ hash = p == NULL ? 0 : p->hash;
+ tcp_localport = p == NULL ? 0 : ntohs(p->tcp_localport);
+ tcp_foreignport = p == NULL ? 0 : ntohs(p->tcp_foreignport);
+ snd_cwnd = p == NULL ? 0 : p->snd_cwnd;
+ snd_wnd = p == NULL ? 0 : p->snd_wnd;
+ rcv_wnd = p == NULL ? 0 : p->rcv_wnd;
+ snd_bwnd = p == NULL ? 0 : p->snd_bwnd;
+ snd_ssthresh = p == NULL ? 0 : p->snd_ssthresh;
+ conn_state = p == NULL ? 0 : p->conn_state;
+ max_seg_size = p == NULL ? 0 : p->max_seg_size;
+ smoothed_rtt = p == NULL ? 0 : p->smoothed_rtt;
+ sack_enabled = p == NULL ? 0 : p->sack_enabled;
+ snd_scale = p == NULL ? 0 : p->snd_scale;
+ rcv_scale = p == NULL ? 0 : p->rcv_scale;
+ flags = p == NULL ? 0 : p->flags;
+ rxt_length = p == NULL ? 0 : p->rxt_length;
+ snd_buf_hiwater = p == NULL ? 0 : p->snd_buf_hiwater;
+ snd_buf_cc = p == NULL ? 0 : p->snd_buf_cc;
+ rcv_buf_hiwater = p == NULL ? 0 : p->rcv_buf_hiwater;
+ rcv_buf_cc = p == NULL ? 0 : p->rcv_buf_cc;
+ sent_inflight_bytes = p == NULL ? 0 : p->sent_inflight_bytes;
+ t_segqlen = p == NULL ? 0 : p->t_segqlen;
+ flowid = p == NULL ? 0 : p->flowid;
+ flowtype = p == NULL ? 0 : p->flowtype;
+};
diff --git a/cddl/usr.bin/ctfmerge/Makefile b/cddl/usr.bin/ctfmerge/Makefile
index de1e9b4..86e8a0d 100644
--- a/cddl/usr.bin/ctfmerge/Makefile
+++ b/cddl/usr.bin/ctfmerge/Makefile
@@ -33,7 +33,6 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${OPENSOLARIS_USR_DISTDIR}/tools/ctf/cvt \
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common
-DPADD= ${LIBDWARF} ${LIBELF} ${LIBZ} ${LIBPTHREAD}
-LDADD= -ldwarf -lelf -lz -lpthread
+LIBADD= elf z pthread
.include <bsd.prog.mk>
diff --git a/contrib/bmake/ChangeLog b/contrib/bmake/ChangeLog
index 1dbf0ef..2fe7369 100644
--- a/contrib/bmake/ChangeLog
+++ b/contrib/bmake/ChangeLog
@@ -1,8 +1,76 @@
+2015-04-18 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * Makefile (MAKE_VERSION): 20150418
+ Merge with NetBSD make, pick up
+ o job.c: use memmove() rather than memcpy()
+
+ * unit-tests/varshell.mk: SunOS cannot handle the TERMINATED_BY_SIGNAL
+ case, so skip it.
+
+2015-04-11 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * Makefile (MAKE_VERSION): 20150411
+ bump version - only mk/ changes.
+
+2015-04-10 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * Makefile (MAKE_VERSION): 20150410
+ Merge with NetBSD make, pick up
+ o document different handling of '-' in jobs mode vs compat
+ o fix jobs mode so that '-' only applies to whole job
+ when shell lacks hasErrCtl
+ o meta.c: use separate vars to track lcwd and latestdir (read)
+ per process
+
+2015-04-01 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * Makefile (MAKE_VERSION): 20150401
+ Merge with NetBSD make, pick up
+ o meta.c: close meta file in child
+
+ * Makefile: use BINDIR.bmake if set.
+ Same for MANDIR and SHAREDIR
+ Handy for testing release candidates
+ in various environments.
+
+2015-03-26 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * move initialization of savederr to block where it is used
+ to avoid spurious warning from gcc5
+
+2014-11-11 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * Makefile (MAKE_VERSION): 20141111
+ just a cooler number
+
+2014-11-05 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * Makefile (MAKE_VERSION): 20141105
+ Merge with NetBSD make, pick up
+ o revert major overhaul of suffix handling
+ and POSIX compliance - too much breakage
+ and impossible to make backwards compatible.
+ o we still have the new unit test structure which is ok.
+ o meta.c ensure "-- filemon" is at start of line.
+
+2014-09-17 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * configure.in: test that result of getconf PATH_MAX is numeric
+ and discard if not. Apparently needed for Hurd.
+
+2014-08-30 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * Makefile (MAKE_VERSION): 20140830
+ Merge with NetBSD make, pick up
+ o major overhaul of suffix handling
+ o improved POSIX compliance
+ o overhauled unit-tests
+
2014-06-20 Simon J. Gerraty <sjg@bad.crufty.net>
* Makefile (MAKE_VERSION): 20140620
Merge with NetBSD make, pick up
- o var.c return varNoError rather than var_Error for ::= modidiers.
+ o var.c return varNoError rather than var_Error for ::= modifiers.
2014-05-22 Simon J. Gerraty <sjg@bad.crufty.net>
diff --git a/contrib/bmake/FILES b/contrib/bmake/FILES
index d4b5dca..8189973 100644
--- a/contrib/bmake/FILES
+++ b/contrib/bmake/FILES
@@ -92,35 +92,74 @@ targ.c
trace.c
trace.h
unit-tests/Makefile.in
-unit-tests/comment
-unit-tests/cond1
-unit-tests/doterror
-unit-tests/dotwait
-unit-tests/error
-unit-tests/export
-unit-tests/export-all
-unit-tests/export-env
-unit-tests/forloop
-unit-tests/forsubst
-unit-tests/hash
-unit-tests/misc
-unit-tests/moderrs
-unit-tests/modmatch
-unit-tests/modmisc
-unit-tests/modorder
-unit-tests/modts
-unit-tests/modword
-unit-tests/order
-unit-tests/phony-end
-unit-tests/posix
-unit-tests/qequals
-unit-tests/sunshcmd
-unit-tests/sysv
-unit-tests/ternary
-unit-tests/test.exp
-unit-tests/unexport
-unit-tests/unexport-env
-unit-tests/varcmd
+unit-tests/comment.exp
+unit-tests/comment.mk
+unit-tests/cond1.exp
+unit-tests/cond1.mk
+unit-tests/doterror.exp
+unit-tests/doterror.mk
+unit-tests/dotwait.exp
+unit-tests/dotwait.mk
+unit-tests/error.exp
+unit-tests/error.mk
+unit-tests/escape.exp
+unit-tests/escape.mk
+unit-tests/export-all.exp
+unit-tests/export-all.mk
+unit-tests/export-env.exp
+unit-tests/export-env.mk
+unit-tests/export.exp
+unit-tests/export.mk
+unit-tests/forloop.exp
+unit-tests/forloop.mk
+unit-tests/forsubst.exp
+unit-tests/forsubst.mk
+unit-tests/hash.exp
+unit-tests/hash.mk
+unit-tests/impsrc.exp
+unit-tests/impsrc.mk
+unit-tests/misc.exp
+unit-tests/misc.mk
+unit-tests/moderrs.exp
+unit-tests/moderrs.mk
+unit-tests/modmatch.exp
+unit-tests/modmatch.mk
+unit-tests/modmisc.exp
+unit-tests/modmisc.mk
+unit-tests/modorder.exp
+unit-tests/modorder.mk
+unit-tests/modts.exp
+unit-tests/modts.mk
+unit-tests/modword.exp
+unit-tests/modword.mk
+unit-tests/order.exp
+unit-tests/order.mk
+unit-tests/phony-end.exp
+unit-tests/phony-end.mk
+unit-tests/posix.exp
+unit-tests/posix.mk
+unit-tests/posix1.exp
+unit-tests/posix1.mk
+unit-tests/qequals.exp
+unit-tests/qequals.mk
+unit-tests/suffixes.exp
+unit-tests/suffixes.mk
+unit-tests/sunshcmd.exp
+unit-tests/sunshcmd.mk
+unit-tests/sysv.exp
+unit-tests/sysv.mk
+unit-tests/ternary.exp
+unit-tests/ternary.mk
+unit-tests/unexport-env.exp
+unit-tests/unexport-env.mk
+unit-tests/unexport.exp
+unit-tests/unexport.mk
+unit-tests/varcmd.exp
+unit-tests/varcmd.mk
+unit-tests/varmisc.exp
+unit-tests/varmisc.mk
+unit-tests/varshell.exp
+unit-tests/varshell.mk
util.c
var.c
wait.h
diff --git a/contrib/bmake/Makefile b/contrib/bmake/Makefile
index 42258c4..9a0abc6 100644
--- a/contrib/bmake/Makefile
+++ b/contrib/bmake/Makefile
@@ -1,7 +1,7 @@
-# $Id: Makefile,v 1.27 2014/06/20 14:51:54 sjg Exp $
+# $Id: Makefile,v 1.36 2015/04/18 19:58:53 sjg Exp $
# Base version on src date
-MAKE_VERSION= 20140620
+MAKE_VERSION= 20150418
PROG= bmake
@@ -180,9 +180,9 @@ COPTS.parse.c += -Wno-format-nonliteral
COPTS.var.c += -Wno-format-nonliteral
# Force these
-SHAREDIR= ${prefix}/share
-BINDIR= ${prefix}/bin
-MANDIR= ${SHAREDIR}/man
+SHAREDIR= ${SHAREDIR.bmake:U${prefix}/share}
+BINDIR= ${BINDIR.bmake:U${prefix}/bin}
+MANDIR= ${MANDIR.bmake:U${SHAREDIR}/man}
.if !exists(.depend)
${OBJS}: config.h
diff --git a/contrib/bmake/PSD.doc/Makefile b/contrib/bmake/PSD.doc/Makefile
index 8e1f1fa..67702b8 100644
--- a/contrib/bmake/PSD.doc/Makefile
+++ b/contrib/bmake/PSD.doc/Makefile
@@ -1,8 +1,10 @@
-# $NetBSD: Makefile,v 1.2 1995/06/14 15:20:23 christos Exp $
+# $NetBSD: Makefile,v 1.4 2014/07/05 19:22:43 dholland Exp $
# @(#)Makefile 8.1 (Berkeley) 8/14/93
-DIR= psd/12.make
+SECTION=reference/ref1
+ARTICLE=make
SRCS= tutorial.ms
MACROS= -ms
+EXTRAHTMLFILES=make1.png make2.png
.include <bsd.doc.mk>
diff --git a/contrib/bmake/PSD.doc/tutorial.ms b/contrib/bmake/PSD.doc/tutorial.ms
index c1a6444..d5c8a7d 100644
--- a/contrib/bmake/PSD.doc/tutorial.ms
+++ b/contrib/bmake/PSD.doc/tutorial.ms
@@ -1,4 +1,4 @@
-.\" $NetBSD: tutorial.ms,v 1.11 2011/08/18 15:19:30 sjg Exp $
+.\" $NetBSD: tutorial.ms,v 1.12 2014/09/30 21:33:14 christos Exp $
.\" Copyright (c) 1988, 1989, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -67,6 +67,16 @@
.\"
.EH 'PSD:12-%''PMake \*- A Tutorial'
.OH 'PMake \*- A Tutorial''PSD:12-%'
+.\" Ix is an indexing macro similar to .IX but I've disabled it for now
+.\" Since that would require 2 passes and I am not in the mood for that.
+.de Ix
+..
+.\" Rd is section (region) define and Rm is region mention? Again disable for
+.\" now.
+.de Rd
+..
+.de Rm
+..
.\" xH is a macro to provide numbered headers that are automatically stuffed
.\" into a table-of-contents, properly indented, etc. If the first argument
.\" is numeric, it is taken as the depth for numbering (as for .NH), else
diff --git a/contrib/bmake/bmake.1 b/contrib/bmake/bmake.1
index 5363e88..702d392 100644
--- a/contrib/bmake/bmake.1
+++ b/contrib/bmake/bmake.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: make.1,v 1.229 2014/01/19 10:23:29 apb Exp $
+.\" $NetBSD: make.1,v 1.247 2015/04/10 08:43:32 wiz Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd February 14, 2014
+.Dd April 9, 2015
.Dt MAKE 1
.Os
.Sh NAME
@@ -209,8 +209,6 @@ Force the
option to print raw values of variables.
.It Ar v
Print debugging information about variable assignment.
-.It Ar w
-Print entering and leaving directory messages, pre and post processing.
.It Ar x
Run shell commands with
.Fl x
@@ -352,6 +350,8 @@ contains a
then the value will be expanded before printing.
.It Fl W
Treat any warnings during makefile parsing as errors.
+.It Fl w
+Print entering and leaving directory messages, pre and post processing.
.It Fl X
Don't export variables passed on the command line to the environment
individually.
@@ -441,17 +441,29 @@ The value
need not necessarily be used to describe existing files.
Expansion is in directory order, not alphabetically as done in the shell.
.Sh SHELL COMMANDS
-Each target may have associated with it a series of shell commands, normally
+Each target may have associated with it one or more lines of shell
+commands, normally
used to create the target.
-Each of the commands in this script
+Each of the lines in this script
.Em must
be preceded by a tab.
-While any target may appear on a dependency line, only one of these
-dependencies may be followed by a creation script, unless the
+(For historical reasons, spaces are not accepted.)
+While targets can appear in many dependency lines if desired, by
+default only one of these rules may be followed by a creation
+script.
+If the
.Ql Ic \&::
-operator is used.
+operator is used, however, all rules may include scripts and the
+scripts are executed in the order found.
.Pp
-If the first characters of the command line are any combination of
+Each line is treated as a separate shell command, unless the end of
+line is escaped with a backslash
+.Pq Ql \e
+in which case that line and the next are combined.
+.\" The escaped newline is retained and passed to the shell, which
+.\" normally ignores it.
+.\" However, the tab at the beginning of the following line is removed.
+If the first characters of the command are any combination of
.Ql Ic @ ,
.Ql Ic + ,
or
@@ -469,6 +481,7 @@ This is similar to the effect of the .MAKE special source,
except that the effect can be limited to a single line of a script.
A
.Ql Ic \-
+in compatibility mode
causes any non-zero exit status of the command line to be ignored.
.Pp
When
@@ -477,22 +490,21 @@ is run in jobs mode with
.Fl j Ar max_jobs ,
the entire script for the target is fed to a
single instance of the shell.
-.Pp
In compatibility (non-jobs) mode, each command is run in a separate process.
If the command contains any shell meta characters
.Pq Ql #=|^(){};&<>*?[]:$`\e\en
-it will be passed to the shell, otherwise
+it will be passed to the shell; otherwise
.Nm
will attempt direct execution.
-.Pp
-Since
-.Nm
-will
-.Xr chdir 2
-to
-.Ql Va .OBJDIR
-before executing any targets, each child process
-starts with that as its current working directory.
+If a line starts with
+.Ql Ic \-
+and the shell has ErrCtl enabled then failure of the command line
+will be ignored as in compatibility mode.
+Otherwise
+.Ql Ic \-
+affects the entire job;
+the script will stop at the first command line that fails,
+but the target will not be deemed to have failed.
.Pp
Makefiles should be written so that the mode of
.Nm
@@ -500,20 +512,32 @@ operation does not change their behavior.
For example, any command which needs to use
.Dq cd
or
-.Dq chdir ,
-without side-effect should be put in parenthesis:
+.Dq chdir
+without potentially changing the directory for subsequent commands
+should be put in parentheses so it executes in a subshell.
+To force the use of one shell, escape the line breaks so as to make
+the whole script one command.
+For example:
.Bd -literal -offset indent
-
avoid-chdir-side-effects:
@echo Building $@ in `pwd`
- @(cd ${.CURDIR} && ${.MAKE} $@)
+ @(cd ${.CURDIR} && ${MAKE} $@)
@echo Back in `pwd`
ensure-one-shell-regardless-of-mode:
- @echo Building $@ in `pwd`; \\
- (cd ${.CURDIR} && ${.MAKE} $@); \\
+ @echo Building $@ in `pwd`; \e
+ (cd ${.CURDIR} && ${MAKE} $@); \e
echo Back in `pwd`
.Ed
+.Pp
+Since
+.Nm
+will
+.Xr chdir 2
+to
+.Ql Va .OBJDIR
+before executing any targets, each child process
+starts with that as its current working directory.
.Sh VARIABLE ASSIGNMENTS
Variables in make are much like variables in the shell, and, by tradition,
consist of all upper-case letters.
@@ -624,13 +648,19 @@ Variables defined in the makefile or in included makefiles.
Variables defined as part of the command line.
.It Local variables
Variables that are defined specific to a certain target.
+.El
+.Pp
+Local variables are all built in and their values vary magically from
+target to target.
+It is not currently possible to define new local variables.
The seven local variables are as follows:
-.Bl -tag -width ".ARCHIVE"
+.Bl -tag -width ".ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
.Ql Va \&\*[Gt] .
.It Va .ARCHIVE
-The name of the archive file.
+The name of the archive file; also known as
+.Ql Va \&! .
.It Va .IMPSRC
In suffix-transformation rules, the name/path of the source from which the
target is to be transformed (the
@@ -639,7 +669,8 @@ source); also known as
.Ql Va \&\*[Lt] .
It is not defined in explicit rules.
.It Va .MEMBER
-The name of the archive member.
+The name of the archive member; also known as
+.Ql Va % .
.It Va .OODATE
The list of sources for this target that were deemed out-of-date; also
known as
@@ -648,31 +679,41 @@ known as
The file prefix of the target, containing only the file portion, no suffix
or preceding directory components; also known as
.Ql Va * .
+The suffix must be one of the known suffixes declared with
+.Ic .SUFFIXES
+or it will not be recognized.
.It Va .TARGET
The name of the target; also known as
.Ql Va @ .
.El
.Pp
The shorter forms
-.Ql Va @ ,
+.Ql ( Va \*[Gt] ,
+.Ql Va \&! ,
+.Ql Va \*[Lt] ,
+.Ql Va % ,
.Ql Va \&? ,
-.Ql Va \&\*[Lt] ,
-.Ql Va \&\*[Gt] ,
+.Ql Va * ,
and
-.Ql Va *
+.Ql Va @ )
are permitted for backward
-compatibility with historical makefiles and are not recommended.
-The six variables
-.Ql Va "@F" ,
-.Ql Va "@D" ,
-.Ql Va "\*[Lt]F" ,
-.Ql Va "\*[Lt]D" ,
-.Ql Va "*F" ,
+compatibility with historical makefiles and legacy POSIX make and are
+not recommended.
+.Pp
+Variants of these variables with the punctuation followed immediately by
+.Ql D
+or
+.Ql F ,
+e.g.
+.Ql Va $(@D) ,
+are legacy forms equivalent to using the
+.Ql :H
and
-.Ql Va "*D"
-are permitted for compatibility with
+.Ql :T
+modifiers.
+These forms are accepted for compatibility with
.At V
-makefiles and are not recommended.
+makefiles and POSIX but are not recommended.
.Pp
Four of the local variables may be used in sources on dependency lines
because they expand to the proper value for each target on the line.
@@ -682,7 +723,6 @@ These variables are
.Ql Va .ARCHIVE ,
and
.Ql Va .MEMBER .
-.El
.Ss Additional built-in variables
In addition,
.Nm
@@ -2119,19 +2159,87 @@ system makefile
system makefile directory
.El
.Sh COMPATIBILITY
-The basic make syntax is compatible between different versions of make,
+The basic make syntax is compatible between different versions of make;
however the special variables, variable modifiers and conditionals are not.
-.Pp
-The way that parallel makes are scheduled changed in
-NetBSD 4.0
-so that .ORDER and .WAIT apply recursively to the dependent nodes.
-The algorithms used may change again in the future.
+.Ss Older versions
+An incomplete list of changes in older versions of
+.Nm :
.Pp
The way that .for loop variables are substituted changed after
NetBSD 5.0
so that they still appear to be variable expansions.
In particular this stops them being treated as syntax, and removes some
obscure problems using them in .if statements.
+.Pp
+The way that parallel makes are scheduled changed in
+NetBSD 4.0
+so that .ORDER and .WAIT apply recursively to the dependent nodes.
+The algorithms used may change again in the future.
+.Ss Other make dialects
+Other make dialects (GNU make, SVR4 make, POSIX make, etc.) do not
+support most of the features of
+.Nm
+as described in this manual.
+Most notably:
+.Bl -bullet -offset indent
+.It
+The
+.Ic .WAIT
+and
+.Ic .ORDER
+declarations and most functionality pertaining to parallelization.
+(GNU make supports parallelization but lacks these features needed to
+control it effectively.)
+.It
+Directives, including for loops and conditionals and most of the
+forms of include files.
+(GNU make has its own incompatible and less powerful syntax for
+conditionals.)
+.It
+All built-in variables that begin with a dot.
+.It
+Most of the special sources and targets that begin with a dot,
+with the notable exception of
+.Ic .PHONY ,
+.Ic .PRECIOUS ,
+and
+.Ic .SUFFIXES .
+.It
+Variable modifiers, except for the
+.Dl :old=new
+string substitution, which does not portably support globbing with
+.Ql %
+and historically only works on declared suffixes.
+.It
+The
+.Ic $>
+variable even in its short form; most makes support this functionality
+but its name varies.
+.El
+.Pp
+Some features are somewhat more portable, such as assignment with
+.Ic += ,
+.Ic ?= ,
+and
+.Ic != .
+The
+.Ic .PATH
+functionality is based on an older feature
+.Ic VPATH
+found in GNU make and many versions of SVR4 make; however,
+historically its behavior is too ill-defined (and too buggy) to rely
+upon.
+.Pp
+The
+.Ic $@
+and
+.Ic $<
+variables are more or less universally portable, as is the
+.Ic $(MAKE)
+variable.
+Basic use of suffix rules (for files only in the current directory,
+not trying to chain transformations together, etc.) is also reasonably
+portable.
.Sh SEE ALSO
.Xr mkdep 1
.Sh HISTORY
diff --git a/contrib/bmake/bmake.cat1 b/contrib/bmake/bmake.cat1
index 0ce26a5..5c62c1b 100644
--- a/contrib/bmake/bmake.cat1
+++ b/contrib/bmake/bmake.cat1
@@ -122,9 +122,6 @@ DDEESSCCRRIIPPTTIIOONN
_v Print debugging information about variable assignment.
- _w Print entering and leaving directory messages, pre and
- post processing.
-
_x Run shell commands with --xx so the actual commands are
printed as they are executed.
@@ -221,6 +218,9 @@ DDEESSCCRRIIPPTTIIOONN
--WW Treat any warnings during makefile parsing as errors.
+ --ww Print entering and leaving directory messages, pre and post pro-
+ cessing.
+
--XX Don't export variables passed on the command line to the environ-
ment individually. Variables passed on the command line are
still exported via the _M_A_K_E_F_L_A_G_S environment variable. This
@@ -273,46 +273,55 @@ FFIILLEE DDEEPPEENNDDEENNCCYY SSPPEECCIIFFIICCAATTIIOO
done in the shell.
SSHHEELLLL CCOOMMMMAANNDDSS
- Each target may have associated with it a series of shell commands, nor-
- mally used to create the target. Each of the commands in this script
- _m_u_s_t be preceded by a tab. While any target may appear on a dependency
- line, only one of these dependencies may be followed by a creation
- script, unless the `::::' operator is used.
-
- If the first characters of the command line are any combination of `@@',
- `++', or `--', the command is treated specially. A `@@' causes the command
- not to be echoed before it is executed. A `++' causes the command to be
- executed even when --nn is given. This is similar to the effect of the
- .MAKE special source, except that the effect can be limited to a single
- line of a script. A `--' causes any non-zero exit status of the command
- line to be ignored.
+ Each target may have associated with it one or more lines of shell com-
+ mands, normally used to create the target. Each of the lines in this
+ script _m_u_s_t be preceded by a tab. (For historical reasons, spaces are
+ not accepted.) While targets can appear in many dependency lines if
+ desired, by default only one of these rules may be followed by a creation
+ script. If the `::::' operator is used, however, all rules may include
+ scripts and the scripts are executed in the order found.
+
+ Each line is treated as a separate shell command, unless the end of line
+ is escaped with a backslash (`\') in which case that line and the next
+ are combined. If the first characters of the command are any combination
+ of `@@', `++', or `--', the command is treated specially. A `@@' causes the
+ command not to be echoed before it is executed. A `++' causes the command
+ to be executed even when --nn is given. This is similar to the effect of
+ the .MAKE special source, except that the effect can be limited to a sin-
+ gle line of a script. A `--' in compatibility mode causes any non-zero
+ exit status of the command line to be ignored.
When bbmmaakkee is run in jobs mode with --jj _m_a_x___j_o_b_s, the entire script for
- the target is fed to a single instance of the shell.
-
- In compatibility (non-jobs) mode, each command is run in a separate
- process. If the command contains any shell meta characters
- (`#=|^(){};&<>*?[]:$`\\n') it will be passed to the shell, otherwise
- bbmmaakkee will attempt direct execution.
-
- Since bbmmaakkee will chdir(2) to `_._O_B_J_D_I_R' before executing any targets, each
- child process starts with that as its current working directory.
+ the target is fed to a single instance of the shell. In compatibility
+ (non-jobs) mode, each command is run in a separate process. If the com-
+ mand contains any shell meta characters (`#=|^(){};&<>*?[]:$`\\n') it
+ will be passed to the shell; otherwise bbmmaakkee will attempt direct execu-
+ tion. If a line starts with `--' and the shell has ErrCtl enabled then
+ failure of the command line will be ignored as in compatibility mode.
+ Otherwise `--' affects the entire job; the script will stop at the first
+ command line that fails, but the target will not be deemed to have
+ failed.
Makefiles should be written so that the mode of bbmmaakkee operation does not
change their behavior. For example, any command which needs to use
- ``cd'' or ``chdir'', without side-effect should be put in parenthesis:
-
+ ``cd'' or ``chdir'' without potentially changing the directory for subse-
+ quent commands should be put in parentheses so it executes in a subshell.
+ To force the use of one shell, escape the line breaks so as to make the
+ whole script one command. For example:
avoid-chdir-side-effects:
@echo Building $@ in `pwd`
- @(cd ${.CURDIR} && ${.MAKE} $@)
+ @(cd ${.CURDIR} && ${MAKE} $@)
@echo Back in `pwd`
ensure-one-shell-regardless-of-mode:
@echo Building $@ in `pwd`; \
- (cd ${.CURDIR} && ${.MAKE} $@); \
+ (cd ${.CURDIR} && ${MAKE} $@); \
echo Back in `pwd`
+ Since bbmmaakkee will chdir(2) to `_._O_B_J_D_I_R' before executing any targets, each
+ child process starts with that as its current working directory.
+
VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
Variables in make are much like variables in the shell, and, by tradi-
tion, consist of all upper-case letters.
@@ -402,40 +411,47 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
Variables defined as part of the command line.
Local variables
- Variables that are defined specific to a certain target. The
- seven local variables are as follows:
+ Variables that are defined specific to a certain target.
+
+ Local variables are all built in and their values vary magically from
+ target to target. It is not currently possible to define new local vari-
+ ables. The seven local variables are as follows:
- _._A_L_L_S_R_C The list of all sources for this target; also known as
- `_>'.
+ _._A_L_L_S_R_C The list of all sources for this target; also known as
+ `_>'.
- _._A_R_C_H_I_V_E The name of the archive file.
+ _._A_R_C_H_I_V_E The name of the archive file; also known as `_!'.
- _._I_M_P_S_R_C In suffix-transformation rules, the name/path of the
- source from which the target is to be transformed (the
- ``implied'' source); also known as `_<'. It is not
- defined in explicit rules.
+ _._I_M_P_S_R_C In suffix-transformation rules, the name/path of the
+ source from which the target is to be transformed (the
+ ``implied'' source); also known as `_<'. It is not
+ defined in explicit rules.
- _._M_E_M_B_E_R The name of the archive member.
+ _._M_E_M_B_E_R The name of the archive member; also known as `_%'.
- _._O_O_D_A_T_E The list of sources for this target that were deemed
- out-of-date; also known as `_?'.
+ _._O_O_D_A_T_E The list of sources for this target that were deemed out-
+ of-date; also known as `_?'.
- _._P_R_E_F_I_X The file prefix of the target, containing only the file
- portion, no suffix or preceding directory components;
- also known as `_*'.
+ _._P_R_E_F_I_X The file prefix of the target, containing only the file
+ portion, no suffix or preceding directory components;
+ also known as `_*'. The suffix must be one of the known
+ suffixes declared with ..SSUUFFFFIIXXEESS or it will not be recog-
+ nized.
- _._T_A_R_G_E_T The name of the target; also known as `_@'.
+ _._T_A_R_G_E_T The name of the target; also known as `_@'.
- The shorter forms `_@', `_?', `_<', `_>', and `_*' are permitted for
- backward compatibility with historical makefiles and are not rec-
- ommended. The six variables `_@_F', `_@_D', `_<_F', `_<_D', `_*_F', and
- `_*_D' are permitted for compatibility with AT&T System V UNIX
- makefiles and are not recommended.
+ The shorter forms (`_>', `_!', `_<', `_%', `_?', `_*', and `_@') are permitted
+ for backward compatibility with historical makefiles and legacy POSIX
+ make and are not recommended.
- Four of the local variables may be used in sources on dependency
- lines because they expand to the proper value for each target on
- the line. These variables are `_._T_A_R_G_E_T', `_._P_R_E_F_I_X', `_._A_R_C_H_I_V_E',
- and `_._M_E_M_B_E_R'.
+ Variants of these variables with the punctuation followed immediately by
+ `D' or `F', e.g. `_$_(_@_D_)', are legacy forms equivalent to using the `:H'
+ and `:T' modifiers. These forms are accepted for compatibility with AT&T
+ System V UNIX makefiles and POSIX but are not recommended.
+
+ Four of the local variables may be used in sources on dependency lines
+ because they expand to the proper value for each target on the line.
+ These variables are `_._T_A_R_G_E_T', `_._P_R_E_F_I_X', `_._A_R_C_H_I_V_E', and `_._M_E_M_B_E_R'.
AAddddiittiioonnaall bbuuiilltt--iinn vvaarriiaabblleess
In addition, bbmmaakkee sets or knows about the following variables:
@@ -1356,19 +1372,58 @@ FFIILLEESS
/usr/share/mk system makefile directory
CCOOMMPPAATTIIBBIILLIITTYY
- The basic make syntax is compatible between different versions of make,
+ The basic make syntax is compatible between different versions of make;
however the special variables, variable modifiers and conditionals are
not.
- The way that parallel makes are scheduled changed in NetBSD 4.0 so that
- .ORDER and .WAIT apply recursively to the dependent nodes. The algo-
- rithms used may change again in the future.
+ OOllddeerr vveerrssiioonnss
+ An incomplete list of changes in older versions of bbmmaakkee:
The way that .for loop variables are substituted changed after NetBSD 5.0
so that they still appear to be variable expansions. In particular this
stops them being treated as syntax, and removes some obscure problems
using them in .if statements.
+ The way that parallel makes are scheduled changed in NetBSD 4.0 so that
+ .ORDER and .WAIT apply recursively to the dependent nodes. The algo-
+ rithms used may change again in the future.
+
+ OOtthheerr mmaakkee ddiiaalleeccttss
+ Other make dialects (GNU make, SVR4 make, POSIX make, etc.) do not sup-
+ port most of the features of bbmmaakkee as described in this manual. Most
+ notably:
+
+ ++oo The ..WWAAIITT and ..OORRDDEERR declarations and most functionality per-
+ taining to parallelization. (GNU make supports parallelization
+ but lacks these features needed to control it effectively.)
+
+ ++oo Directives, including for loops and conditionals and most of
+ the forms of include files. (GNU make has its own incompatible
+ and less powerful syntax for conditionals.)
+
+ ++oo All built-in variables that begin with a dot.
+
+ ++oo Most of the special sources and targets that begin with a dot,
+ with the notable exception of ..PPHHOONNYY, ..PPRREECCIIOOUUSS, and ..SSUUFFFFIIXXEESS.
+
+ ++oo Variable modifiers, except for the
+ :old=new
+ string substitution, which does not portably support globbing
+ with `%' and historically only works on declared suffixes.
+
+ ++oo The $$>> variable even in its short form; most makes support this
+ functionality but its name varies.
+
+ Some features are somewhat more portable, such as assignment with ++==, ??==,
+ and !!==. The ..PPAATTHH functionality is based on an older feature VVPPAATTHH found
+ in GNU make and many versions of SVR4 make; however, historically its
+ behavior is too ill-defined (and too buggy) to rely upon.
+
+ The $$@@ and $$<< variables are more or less universally portable, as is the
+ $$((MMAAKKEE)) variable. Basic use of suffix rules (for files only in the cur-
+ rent directory, not trying to chain transformations together, etc.) is
+ also reasonably portable.
+
SSEEEE AALLSSOO
mkdep(1)
@@ -1394,4 +1449,4 @@ BBUUGGSS
There is no way of escaping a space character in a filename.
-NetBSD 5.1 February 14, 2014 NetBSD 5.1
+NetBSD 5.1 April 9, 2015 NetBSD 5.1
diff --git a/contrib/bmake/compat.c b/contrib/bmake/compat.c
index 97fcfe4..fd00eb7 100644
--- a/contrib/bmake/compat.c
+++ b/contrib/bmake/compat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: compat.c,v 1.94 2014/01/03 00:02:01 sjg Exp $ */
+/* $NetBSD: compat.c,v 1.96 2014/09/07 20:55:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: compat.c,v 1.94 2014/01/03 00:02:01 sjg Exp $";
+static char rcsid[] = "$NetBSD: compat.c,v 1.96 2014/09/07 20:55:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: compat.c,v 1.94 2014/01/03 00:02:01 sjg Exp $");
+__RCSID("$NetBSD: compat.c,v 1.96 2014/09/07 20:55:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
diff --git a/contrib/bmake/configure b/contrib/bmake/configure
index e3ff4de..08b21b3 100755
--- a/contrib/bmake/configure
+++ b/contrib/bmake/configure
@@ -4247,6 +4247,8 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
if test -x /usr/bin/getconf; then
bmake_path_max=`getconf PATH_MAX / 2> /dev/null`
+ # only a numeric response is useful
+ test ${bmake_path_max:-0} -gt 0 2> /dev/null || bmake_path_max=
fi
bmake_path_max=${bmake_path_max:-1024}
if test $bmake_path_max -gt 1024; then
diff --git a/contrib/bmake/configure.in b/contrib/bmake/configure.in
index ecaa53a..e2249b0 100644
--- a/contrib/bmake/configure.in
+++ b/contrib/bmake/configure.in
@@ -1,6 +1,6 @@
dnl
dnl RCSid:
-dnl $Id: configure.in,v 1.52 2014/02/15 22:27:59 sjg Exp $
+dnl $Id: configure.in,v 1.53 2014/11/06 01:49:40 sjg Exp $
dnl
dnl Process this file with autoconf to produce a configure script
dnl
@@ -82,6 +82,8 @@ dnl
dnl Hurd refuses to define PATH_MAX or MAXPATHLEN
if test -x /usr/bin/getconf; then
bmake_path_max=`getconf PATH_MAX / 2> /dev/null`
+ # only a numeric response is useful
+ test ${bmake_path_max:-0} -gt 0 2> /dev/null || bmake_path_max=
fi
bmake_path_max=${bmake_path_max:-1024}
if test $bmake_path_max -gt 1024; then
diff --git a/contrib/bmake/job.c b/contrib/bmake/job.c
index 4e22959..8a7a902 100644
--- a/contrib/bmake/job.c
+++ b/contrib/bmake/job.c
@@ -1,4 +1,4 @@
-/* $NetBSD: job.c,v 1.176 2013/08/04 16:48:15 sjg Exp $ */
+/* $NetBSD: job.c,v 1.180 2015/04/16 13:31:03 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: job.c,v 1.176 2013/08/04 16:48:15 sjg Exp $";
+static char rcsid[] = "$NetBSD: job.c,v 1.180 2015/04/16 13:31:03 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: job.c,v 1.176 2013/08/04 16:48:15 sjg Exp $");
+__RCSID("$NetBSD: job.c,v 1.180 2015/04/16 13:31:03 joerg Exp $");
#endif
#endif /* not lint */
#endif
@@ -744,7 +744,6 @@ JobPrintCommand(void *cmdp, void *jobp)
shutUp = DEBUG(LOUD) ? FALSE : TRUE;
break;
case '-':
- job->flags |= JOB_IGNERR;
errOff = TRUE;
break;
case '+':
@@ -823,6 +822,7 @@ JobPrintCommand(void *cmdp, void *jobp)
* to ignore errors. Set cmdTemplate to use the weirdness
* instead of the simple "%s\n" template.
*/
+ job->flags |= JOB_IGNERR;
if (!(job->flags & JOB_SILENT) && !shutUp) {
if (commandShell->hasEchoCtl) {
DBPRINTF("%s\n", commandShell->echoOff);
@@ -1376,7 +1376,8 @@ JobExec(Job *job, char **argv)
(void)fcntl(0, F_SETFD, 0);
(void)lseek(0, (off_t)0, SEEK_SET);
- if (Always_pass_job_queue || (job->node->type & OP_MAKE)) {
+ if (Always_pass_job_queue ||
+ (job->node->type & (OP_MAKE | OP_SUBMAKE))) {
/*
* Pass job token pipe to submakes.
*/
@@ -1910,16 +1911,16 @@ end_loop:
(void)fflush(stdout);
}
}
- if (i < max - 1) {
- /* shift the remaining characters down */
- (void)memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1));
+ /*
+ * max is the last offset still in the buffer. Move any remaining
+ * characters to the start of the buffer and update the end marker
+ * curPos.
+ */
+ if (i < max) {
+ (void)memmove(job->outBuf, &job->outBuf[i + 1], max - (i + 1));
job->curPos = max - (i + 1);
-
} else {
- /*
- * We have written everything out, so we just start over
- * from the start of the buffer. No copying. No nothing.
- */
+ assert(i == max);
job->curPos = 0;
}
}
diff --git a/contrib/bmake/lst.h b/contrib/bmake/lst.h
index e067407..e207bc8 100644
--- a/contrib/bmake/lst.h
+++ b/contrib/bmake/lst.h
@@ -1,4 +1,4 @@
-/* $NetBSD: lst.h,v 1.18 2009/01/23 21:58:27 dsl Exp $ */
+/* $NetBSD: lst.h,v 1.20 2014/09/07 20:55:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
diff --git a/contrib/bmake/lst.lib/lstInt.h b/contrib/bmake/lst.lib/lstInt.h
index 34a2fbd..ac53dcb 100644
--- a/contrib/bmake/lst.lib/lstInt.h
+++ b/contrib/bmake/lst.lib/lstInt.h
@@ -1,4 +1,4 @@
-/* $NetBSD: lstInt.h,v 1.20 2009/01/24 14:43:29 dsl Exp $ */
+/* $NetBSD: lstInt.h,v 1.22 2014/09/07 20:55:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
diff --git a/contrib/bmake/lst.lib/lstRemove.c b/contrib/bmake/lst.lib/lstRemove.c
index 54d7b33..7480d30 100644
--- a/contrib/bmake/lst.lib/lstRemove.c
+++ b/contrib/bmake/lst.lib/lstRemove.c
@@ -1,4 +1,4 @@
-/* $NetBSD: lstRemove.c,v 1.14 2008/12/13 15:19:29 dsl Exp $ */
+/* $NetBSD: lstRemove.c,v 1.16 2014/09/07 20:55:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -33,14 +33,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: lstRemove.c,v 1.14 2008/12/13 15:19:29 dsl Exp $";
+static char rcsid[] = "$NetBSD: lstRemove.c,v 1.16 2014/09/07 20:55:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lstRemove.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: lstRemove.c,v 1.14 2008/12/13 15:19:29 dsl Exp $");
+__RCSID("$NetBSD: lstRemove.c,v 1.16 2014/09/07 20:55:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
diff --git a/contrib/bmake/main.c b/contrib/bmake/main.c
index f86184c..3287115 100644
--- a/contrib/bmake/main.c
+++ b/contrib/bmake/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.226 2014/02/07 17:23:35 pooka Exp $ */
+/* $NetBSD: main.c,v 1.232 2015/03/26 22:20:42 sjg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,7 +69,7 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: main.c,v 1.226 2014/02/07 17:23:35 pooka Exp $";
+static char rcsid[] = "$NetBSD: main.c,v 1.232 2015/03/26 22:20:42 sjg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
@@ -81,7 +81,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\
#if 0
static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: main.c,v 1.226 2014/02/07 17:23:35 pooka Exp $");
+__RCSID("$NetBSD: main.c,v 1.232 2015/03/26 22:20:42 sjg Exp $");
#endif
#endif /* not lint */
#endif
@@ -99,14 +99,14 @@ __RCSID("$NetBSD: main.c,v 1.226 2014/02/07 17:23:35 pooka Exp $");
*
* Error Print a tagged error message. The global
* MAKE variable must have been defined. This
- * takes a format string and two optional
- * arguments for it.
+ * takes a format string and optional arguments
+ * for it.
*
* Fatal Print an error message and exit. Also takes
- * a format string and two arguments.
+ * a format string and arguments for it.
*
* Punt Aborts all jobs and exits with a message. Also
- * takes a format string and two arguments.
+ * takes a format string and arguments for it.
*
* Finish Finish things up by printing the number of
* errors which occurred, as passed to it, and
@@ -1522,7 +1522,8 @@ Cmd_Exec(const char *cmd, const char **errnum)
WAIT_T status; /* command exit status */
Buffer buf; /* buffer to store the result */
char *cp;
- int cc;
+ int cc; /* bytes read, or -1 */
+ int savederr; /* saved errno */
*errnum = NULL;
@@ -1579,6 +1580,7 @@ Cmd_Exec(const char *cmd, const char **errnum)
*/
(void)close(fds[1]);
+ savederr = 0;
Buf_Init(&buf, 0);
do {
@@ -1588,6 +1590,8 @@ Cmd_Exec(const char *cmd, const char **errnum)
Buf_AddBytes(&buf, cc, result);
}
while (cc > 0 || (cc == -1 && errno == EINTR));
+ if (cc == -1)
+ savederr = errno;
/*
* Close the input side of the pipe.
@@ -1604,7 +1608,7 @@ Cmd_Exec(const char *cmd, const char **errnum)
cc = Buf_Size(&buf);
res = Buf_Destroy(&buf, FALSE);
- if (cc == 0)
+ if (savederr != 0)
*errnum = "Couldn't read shell's output for \"%s\"";
if (WIFSIGNALED(status))
diff --git a/contrib/bmake/make.1 b/contrib/bmake/make.1
index 8a841db..3acc02a 100644
--- a/contrib/bmake/make.1
+++ b/contrib/bmake/make.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: make.1,v 1.230 2014/02/15 18:55:30 sjg Exp $
+.\" $NetBSD: make.1,v 1.247 2015/04/10 08:43:32 wiz Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd February 14, 2014
+.Dd April 9, 2015
.Dt MAKE 1
.Os
.Sh NAME
@@ -209,8 +209,6 @@ Force the
option to print raw values of variables.
.It Ar v
Print debugging information about variable assignment.
-.It Ar w
-Print entering and leaving directory messages, pre and post processing.
.It Ar x
Run shell commands with
.Fl x
@@ -352,6 +350,8 @@ contains a
then the value will be expanded before printing.
.It Fl W
Treat any warnings during makefile parsing as errors.
+.It Fl w
+Print entering and leaving directory messages, pre and post processing.
.It Fl X
Don't export variables passed on the command line to the environment
individually.
@@ -441,17 +441,29 @@ The value
need not necessarily be used to describe existing files.
Expansion is in directory order, not alphabetically as done in the shell.
.Sh SHELL COMMANDS
-Each target may have associated with it a series of shell commands, normally
+Each target may have associated with it one or more lines of shell
+commands, normally
used to create the target.
-Each of the commands in this script
+Each of the lines in this script
.Em must
be preceded by a tab.
-While any target may appear on a dependency line, only one of these
-dependencies may be followed by a creation script, unless the
+(For historical reasons, spaces are not accepted.)
+While targets can appear in many dependency lines if desired, by
+default only one of these rules may be followed by a creation
+script.
+If the
.Ql Ic \&::
-operator is used.
+operator is used, however, all rules may include scripts and the
+scripts are executed in the order found.
.Pp
-If the first characters of the command line are any combination of
+Each line is treated as a separate shell command, unless the end of
+line is escaped with a backslash
+.Pq Ql \e
+in which case that line and the next are combined.
+.\" The escaped newline is retained and passed to the shell, which
+.\" normally ignores it.
+.\" However, the tab at the beginning of the following line is removed.
+If the first characters of the command are any combination of
.Ql Ic @ ,
.Ql Ic + ,
or
@@ -469,6 +481,7 @@ This is similar to the effect of the .MAKE special source,
except that the effect can be limited to a single line of a script.
A
.Ql Ic \-
+in compatibility mode
causes any non-zero exit status of the command line to be ignored.
.Pp
When
@@ -477,22 +490,21 @@ is run in jobs mode with
.Fl j Ar max_jobs ,
the entire script for the target is fed to a
single instance of the shell.
-.Pp
In compatibility (non-jobs) mode, each command is run in a separate process.
If the command contains any shell meta characters
.Pq Ql #=|^(){};&<>*?[]:$`\e\en
-it will be passed to the shell, otherwise
+it will be passed to the shell; otherwise
.Nm
will attempt direct execution.
-.Pp
-Since
-.Nm
-will
-.Xr chdir 2
-to
-.Ql Va .OBJDIR
-before executing any targets, each child process
-starts with that as its current working directory.
+If a line starts with
+.Ql Ic \-
+and the shell has ErrCtl enabled then failure of the command line
+will be ignored as in compatibility mode.
+Otherwise
+.Ql Ic \-
+affects the entire job;
+the script will stop at the first command line that fails,
+but the target will not be deemed to have failed.
.Pp
Makefiles should be written so that the mode of
.Nm
@@ -500,20 +512,32 @@ operation does not change their behavior.
For example, any command which needs to use
.Dq cd
or
-.Dq chdir ,
-without side-effect should be put in parenthesis:
+.Dq chdir
+without potentially changing the directory for subsequent commands
+should be put in parentheses so it executes in a subshell.
+To force the use of one shell, escape the line breaks so as to make
+the whole script one command.
+For example:
.Bd -literal -offset indent
-
avoid-chdir-side-effects:
@echo Building $@ in `pwd`
- @(cd ${.CURDIR} && ${.MAKE} $@)
+ @(cd ${.CURDIR} && ${MAKE} $@)
@echo Back in `pwd`
ensure-one-shell-regardless-of-mode:
- @echo Building $@ in `pwd`; \\
- (cd ${.CURDIR} && ${.MAKE} $@); \\
+ @echo Building $@ in `pwd`; \e
+ (cd ${.CURDIR} && ${MAKE} $@); \e
echo Back in `pwd`
.Ed
+.Pp
+Since
+.Nm
+will
+.Xr chdir 2
+to
+.Ql Va .OBJDIR
+before executing any targets, each child process
+starts with that as its current working directory.
.Sh VARIABLE ASSIGNMENTS
Variables in make are much like variables in the shell, and, by tradition,
consist of all upper-case letters.
@@ -624,13 +648,19 @@ Variables defined in the makefile or in included makefiles.
Variables defined as part of the command line.
.It Local variables
Variables that are defined specific to a certain target.
+.El
+.Pp
+Local variables are all built in and their values vary magically from
+target to target.
+It is not currently possible to define new local variables.
The seven local variables are as follows:
-.Bl -tag -width ".ARCHIVE"
+.Bl -tag -width ".ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
.Ql Va \&\*[Gt] .
.It Va .ARCHIVE
-The name of the archive file.
+The name of the archive file; also known as
+.Ql Va \&! .
.It Va .IMPSRC
In suffix-transformation rules, the name/path of the source from which the
target is to be transformed (the
@@ -639,7 +669,8 @@ source); also known as
.Ql Va \&\*[Lt] .
It is not defined in explicit rules.
.It Va .MEMBER
-The name of the archive member.
+The name of the archive member; also known as
+.Ql Va % .
.It Va .OODATE
The list of sources for this target that were deemed out-of-date; also
known as
@@ -648,31 +679,41 @@ known as
The file prefix of the target, containing only the file portion, no suffix
or preceding directory components; also known as
.Ql Va * .
+The suffix must be one of the known suffixes declared with
+.Ic .SUFFIXES
+or it will not be recognized.
.It Va .TARGET
The name of the target; also known as
.Ql Va @ .
.El
.Pp
The shorter forms
-.Ql Va @ ,
+.Ql ( Va \*[Gt] ,
+.Ql Va \&! ,
+.Ql Va \*[Lt] ,
+.Ql Va % ,
.Ql Va \&? ,
-.Ql Va \&\*[Lt] ,
-.Ql Va \&\*[Gt] ,
+.Ql Va * ,
and
-.Ql Va *
+.Ql Va @ )
are permitted for backward
-compatibility with historical makefiles and are not recommended.
-The six variables
-.Ql Va "@F" ,
-.Ql Va "@D" ,
-.Ql Va "\*[Lt]F" ,
-.Ql Va "\*[Lt]D" ,
-.Ql Va "*F" ,
+compatibility with historical makefiles and legacy POSIX make and are
+not recommended.
+.Pp
+Variants of these variables with the punctuation followed immediately by
+.Ql D
+or
+.Ql F ,
+e.g.
+.Ql Va $(@D) ,
+are legacy forms equivalent to using the
+.Ql :H
and
-.Ql Va "*D"
-are permitted for compatibility with
+.Ql :T
+modifiers.
+These forms are accepted for compatibility with
.At V
-makefiles and are not recommended.
+makefiles and POSIX but are not recommended.
.Pp
Four of the local variables may be used in sources on dependency lines
because they expand to the proper value for each target on the line.
@@ -682,7 +723,6 @@ These variables are
.Ql Va .ARCHIVE ,
and
.Ql Va .MEMBER .
-.El
.Ss Additional built-in variables
In addition,
.Nm
@@ -2130,19 +2170,87 @@ system makefile
system makefile directory
.El
.Sh COMPATIBILITY
-The basic make syntax is compatible between different versions of make,
+The basic make syntax is compatible between different versions of make;
however the special variables, variable modifiers and conditionals are not.
-.Pp
-The way that parallel makes are scheduled changed in
-.Nx 4.0
-so that .ORDER and .WAIT apply recursively to the dependent nodes.
-The algorithms used may change again in the future.
+.Ss Older versions
+An incomplete list of changes in older versions of
+.Nm :
.Pp
The way that .for loop variables are substituted changed after
.Nx 5.0
so that they still appear to be variable expansions.
In particular this stops them being treated as syntax, and removes some
obscure problems using them in .if statements.
+.Pp
+The way that parallel makes are scheduled changed in
+.Nx 4.0
+so that .ORDER and .WAIT apply recursively to the dependent nodes.
+The algorithms used may change again in the future.
+.Ss Other make dialects
+Other make dialects (GNU make, SVR4 make, POSIX make, etc.) do not
+support most of the features of
+.Nm
+as described in this manual.
+Most notably:
+.Bl -bullet -offset indent
+.It
+The
+.Ic .WAIT
+and
+.Ic .ORDER
+declarations and most functionality pertaining to parallelization.
+(GNU make supports parallelization but lacks these features needed to
+control it effectively.)
+.It
+Directives, including for loops and conditionals and most of the
+forms of include files.
+(GNU make has its own incompatible and less powerful syntax for
+conditionals.)
+.It
+All built-in variables that begin with a dot.
+.It
+Most of the special sources and targets that begin with a dot,
+with the notable exception of
+.Ic .PHONY ,
+.Ic .PRECIOUS ,
+and
+.Ic .SUFFIXES .
+.It
+Variable modifiers, except for the
+.Dl :old=new
+string substitution, which does not portably support globbing with
+.Ql %
+and historically only works on declared suffixes.
+.It
+The
+.Ic $>
+variable even in its short form; most makes support this functionality
+but its name varies.
+.El
+.Pp
+Some features are somewhat more portable, such as assignment with
+.Ic += ,
+.Ic ?= ,
+and
+.Ic != .
+The
+.Ic .PATH
+functionality is based on an older feature
+.Ic VPATH
+found in GNU make and many versions of SVR4 make; however,
+historically its behavior is too ill-defined (and too buggy) to rely
+upon.
+.Pp
+The
+.Ic $@
+and
+.Ic $<
+variables are more or less universally portable, as is the
+.Ic $(MAKE)
+variable.
+Basic use of suffix rules (for files only in the current directory,
+not trying to chain transformations together, etc.) is also reasonably
+portable.
.Sh SEE ALSO
.Xr mkdep 1
.Sh HISTORY
diff --git a/contrib/bmake/make.c b/contrib/bmake/make.c
index 7905f8c..fde1850 100644
--- a/contrib/bmake/make.c
+++ b/contrib/bmake/make.c
@@ -1,4 +1,4 @@
-/* $NetBSD: make.c,v 1.88 2012/11/09 18:53:05 sjg Exp $ */
+/* $NetBSD: make.c,v 1.91 2014/10/18 08:33:30 snj Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: make.c,v 1.88 2012/11/09 18:53:05 sjg Exp $";
+static char rcsid[] = "$NetBSD: make.c,v 1.91 2014/10/18 08:33:30 snj Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: make.c,v 1.88 2012/11/09 18:53:05 sjg Exp $");
+__RCSID("$NetBSD: make.c,v 1.91 2014/10/18 08:33:30 snj Exp $");
#endif
#endif /* not lint */
#endif
@@ -563,7 +563,7 @@ MakeHandleUse(void *cgnp, void *pgnp)
* in the comments below.
*
* Results:
- * returns 0 if the gnode does not exist, or it's filesystem
+ * returns 0 if the gnode does not exist, or its filesystem
* time if it does.
*
* Side Effects:
diff --git a/contrib/bmake/make.h b/contrib/bmake/make.h
index 7579f62..9cf7243 100644
--- a/contrib/bmake/make.h
+++ b/contrib/bmake/make.h
@@ -1,4 +1,4 @@
-/* $NetBSD: make.h,v 1.92 2013/09/04 15:38:26 sjg Exp $ */
+/* $NetBSD: make.h,v 1.95 2014/09/07 20:55:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -289,6 +289,7 @@ typedef struct GNode {
#define OP_NOMETA 0x00080000 /* .NOMETA do not create a .meta file */
#define OP_META 0x00100000 /* .META we _do_ want a .meta file */
#define OP_NOMETA_CMP 0x00200000 /* Do not compare commands in .meta file */
+#define OP_SUBMAKE 0x00400000 /* Possibly a submake node */
/* Attributes applied by PMake */
#define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */
#define OP_MEMBER 0x40000000 /* Target is a member of an archive */
diff --git a/contrib/bmake/meta.c b/contrib/bmake/meta.c
index ddced23..5600a77 100644
--- a/contrib/bmake/meta.c
+++ b/contrib/bmake/meta.c
@@ -1,4 +1,4 @@
-/* $NetBSD: meta.c,v 1.33 2013/10/01 05:37:17 sjg Exp $ */
+/* $NetBSD: meta.c,v 1.38 2015/04/11 05:24:30 sjg Exp $ */
/*
* Implement 'meta' mode.
@@ -155,8 +155,8 @@ filemon_open(BuildMon *pbm)
static void
filemon_read(FILE *mfp, int fd)
{
- FILE *fp;
char buf[BUFSIZ];
+ int n;
/* Check if we're not writing to a meta data file.*/
if (mfp == NULL) {
@@ -166,17 +166,14 @@ filemon_read(FILE *mfp, int fd)
}
/* rewind */
(void)lseek(fd, (off_t)0, SEEK_SET);
- if ((fp = fdopen(fd, "r")) == NULL)
- err(1, "Could not read build monitor file '%d'", fd);
fprintf(mfp, "\n-- filemon acquired metadata --\n");
- while (fgets(buf, sizeof(buf), fp)) {
- fprintf(mfp, "%s", buf);
+ while ((n = read(fd, buf, sizeof(buf))) > 0) {
+ fwrite(buf, 1, n, mfp);
}
fflush(mfp);
- clearerr(fp);
- fclose(fp);
+ close(fd);
}
#endif
@@ -662,17 +659,21 @@ meta_job_child(Job *job)
{
#ifdef USE_FILEMON
BuildMon *pbm;
- pid_t pid;
if (job != NULL) {
pbm = &job->bm;
} else {
pbm = &Mybm;
}
- pid = getpid();
- if (pbm->mfp != NULL && useFilemon) {
- if (ioctl(pbm->filemon_fd, FILEMON_SET_PID, &pid) < 0) {
- err(1, "Could not set filemon pid!");
+ if (pbm->mfp != NULL) {
+ close(fileno(pbm->mfp));
+ if (useFilemon) {
+ pid_t pid;
+
+ pid = getpid();
+ if (ioctl(pbm->filemon_fd, FILEMON_SET_PID, &pid) < 0) {
+ err(1, "Could not set filemon pid!");
+ }
}
}
#endif
@@ -844,9 +845,10 @@ string_match(const void *p, const void *q)
/*
* When running with 'meta' functionality, a target can be out-of-date
- * if any of the references in it's meta data file is more recent.
+ * if any of the references in its meta data file is more recent.
* We have to track the latestdir on a per-process basis.
*/
+#define LCWD_VNAME_FMT ".meta.%d.lcwd"
#define LDIR_VNAME_FMT ".meta.%d.ldir"
/*
@@ -872,11 +874,14 @@ meta_oodate(GNode *gn, Boolean oodate)
{
static char *tmpdir = NULL;
static char cwd[MAXPATHLEN];
+ char lcwd_vname[64];
char ldir_vname[64];
+ char lcwd[MAXPATHLEN];
char latestdir[MAXPATHLEN];
char fname[MAXPATHLEN];
char fname1[MAXPATHLEN];
char fname2[MAXPATHLEN];
+ char fname3[MAXPATHLEN];
char *p;
char *cp;
char *link_src;
@@ -928,6 +933,8 @@ meta_oodate(GNode *gn, Boolean oodate)
err(1, "Could not get current working directory");
cwdlen = strlen(cwd);
}
+ strlcpy(lcwd, cwd, sizeof(lcwd));
+ strlcpy(latestdir, cwd, sizeof(latestdir));
if (!tmpdir) {
tmpdir = getTmpdir();
@@ -1011,9 +1018,11 @@ meta_oodate(GNode *gn, Boolean oodate)
char *tp;
if (lastpid > 0) {
- /* We need to remember this. */
+ /* We need to remember these. */
+ Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
Var_Set(ldir_vname, latestdir, VAR_GLOBAL, 0);
}
+ snprintf(lcwd_vname, sizeof(lcwd_vname), LCWD_VNAME_FMT, pid);
snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid);
lastpid = pid;
ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp);
@@ -1021,15 +1030,22 @@ meta_oodate(GNode *gn, Boolean oodate)
strlcpy(latestdir, ldir, sizeof(latestdir));
if (tp)
free(tp);
- } else
- strlcpy(latestdir, cwd, sizeof(latestdir));
+ }
+ ldir = Var_Value(lcwd_vname, VAR_GLOBAL, &tp);
+ if (ldir) {
+ strlcpy(lcwd, ldir, sizeof(lcwd));
+ if (tp)
+ free(tp);
+ }
}
/* Skip past the pid. */
if (strsep(&p, " ") == NULL)
continue;
#ifdef DEBUG_META_MODE
if (DEBUG(META))
- fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, latestdir);
+ fprintf(debug_file, "%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
+ fname, lineno,
+ pid, buf[0], cwd, lcwd, latestdir);
#endif
break;
}
@@ -1039,6 +1055,7 @@ meta_oodate(GNode *gn, Boolean oodate)
/* Process according to record type. */
switch (buf[0]) {
case 'X': /* eXit */
+ Var_Delete(lcwd_vname, VAR_GLOBAL);
Var_Delete(ldir_vname, VAR_GLOBAL);
lastpid = 0; /* no need to save ldir_vname */
break;
@@ -1050,15 +1067,30 @@ meta_oodate(GNode *gn, Boolean oodate)
child = atoi(p);
if (child > 0) {
+ snprintf(cldir, sizeof(cldir), LCWD_VNAME_FMT, child);
+ Var_Set(cldir, lcwd, VAR_GLOBAL, 0);
snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child);
Var_Set(cldir, latestdir, VAR_GLOBAL, 0);
+#ifdef DEBUG_META_MODE
+ if (DEBUG(META))
+ fprintf(debug_file, "%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
+ fname, lineno,
+ child, cwd, lcwd, latestdir);
+#endif
}
}
break;
case 'C': /* Chdir */
- /* Update the latest directory. */
- strlcpy(latestdir, p, sizeof(latestdir));
+ /* Update lcwd and latest directory. */
+ strlcpy(latestdir, p, sizeof(latestdir));
+ strlcpy(lcwd, p, sizeof(lcwd));
+ Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
+ Var_Set(ldir_vname, lcwd, VAR_GLOBAL, 0);
+#ifdef DEBUG_META_MODE
+ if (DEBUG(META))
+ fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, lcwd);
+#endif
break;
case 'M': /* renaMe */
@@ -1207,11 +1239,16 @@ meta_oodate(GNode *gn, Boolean oodate)
snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p);
sdirs[sdx++] = fname1;
- if (strcmp(latestdir, cwd) != 0) {
- /* Check vs cwd */
- snprintf(fname2, sizeof(fname2), "%s/%s", cwd, p);
+ if (strcmp(latestdir, lcwd) != 0) {
+ /* Check vs lcwd */
+ snprintf(fname2, sizeof(fname2), "%s/%s", lcwd, p);
sdirs[sdx++] = fname2;
}
+ if (strcmp(lcwd, cwd) != 0) {
+ /* Check vs cwd */
+ snprintf(fname3, sizeof(fname3), "%s/%s", cwd, p);
+ sdirs[sdx++] = fname3;
+ }
}
sdirs[sdx++] = NULL;
@@ -1250,6 +1287,10 @@ meta_oodate(GNode *gn, Boolean oodate)
oodate = TRUE;
}
}
+ if (buf[0] == 'E') {
+ /* previous latestdir is no longer relevant */
+ strlcpy(latestdir, lcwd, sizeof(latestdir));
+ }
break;
default:
break;
diff --git a/contrib/bmake/mk/ChangeLog b/contrib/bmake/mk/ChangeLog
index 80671ef..597d814 100644
--- a/contrib/bmake/mk/ChangeLog
+++ b/contrib/bmake/mk/ChangeLog
@@ -1,3 +1,111 @@
+2015-04-16 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20150411
+ bump version
+
+ * own.mk: put AUTO_OBJ in OPTIONS_DEFAULT_NO rather than YES.
+ it is here mainly for documentation purposes, since
+ if using auto.obj.mk it is better done via sys.mk
+
+2015-04-01 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20150401
+
+ * meta2deps.sh: support @list
+
+ * meta2deps.py: updates from Juniper
+ o add EXCLUDES
+ o skip bogus input files.
+ o treat 'M' and 'L' as both an 'R' and a 'W'
+
+2015-03-03 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20150303
+
+ * dirdeps.mk: if MK_DIRDEPS_CACHE is yes, use dirdeps-cache
+ which is built via sub-make so we have a .meta file to tell if
+ it is out-of-date.
+ The dirdeps-cache contains the same dependency rules that we
+ normaly construct on the fly.
+ This adds a few seconds overhead when the cache is out of date,
+ but for a large target, the savings can be significant (10-20min).
+
+2014-11-18 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20141118
+
+ * meta.stage.mk: add stale_staged
+
+ * dirdeps.mk (_DIRDEP_USE_LEVEL): allow this to be tweaked
+ only useful under very rare conditions such as
+ FreeBSD's make universe.
+
+ * auto.obj.mk: Allow MK_AUTO_OBJ to set MKOBJDIRS=auto
+
+2014-11-11 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20141111
+
+ * mkopt.sh: use consistent semantics for _mk_opt and _mk_opts
+
+2014-11-09 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * FILES: include mkopt.sh which allows handling options in shell
+ scripts in a manner compatible with options.mk
+
+2014-10-12 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * meta.stage.mk: ensure only _STAGED_DIRS under objroot are used
+ for GENDIRDEPS_FILTER to avoid surprises.
+
+2014-10-10 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * dirdeps.mk (NSkipHostDir): this needs SRCTOP prepended since by
+ the time it is applied to __depdirs they have.
+
+ * dirdeps.mk fix filtering of _machines since M_dep_qual_fixes
+ expects patterns like *.${MACHINE}
+
+ * cython.mk (pyprefix?): use pyprefix to find python bits
+ since prefix might be something else (where we install our
+ stuff)
+
+2014-09-11 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20140911
+
+ * dirdeps.mk: add bootstrap target to simplify adding support for
+ new MACHINE.
+
+2014-09-01 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * gendirdeps.mk: Add handling of GENDIRDEPS_FILTER_DIR_VARS and
+ GENDIRDEPS_FILTER_VARS to make it easier to produce sharable
+ Makefile.depend files.
+
+2014-08-28 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20140828
+
+ * cython.mk: capture logic for building python extension modules
+ with Cython.
+
+2014-08-08 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * meta.stage.mk (_STAGE_AS_BASENAME_USE): Add StageAs variant
+
+2014-08-02 Simon J. Gerraty <sjg@bad.crufty.net>
+
+ * install-mk (MK_VERSION): 20140801
+
+ * dep.mk: use explicit MKDEP_MK rather than overload MKDEP to
+ identify the autodep.mk variant.
+
+ * sys.dependfile.mk: delete .MAKE.DEPENDFILE if its
+ initial value does not match .MAKE.DEPENDFILE_PREFIX
+
+ * meta.autodep.mk: if _bootstrap_dirdeps add RELDIR to DIRDEPS
+
2014-05-22 Simon J. Gerraty <sjg@bad.crufty.net>
* install-mk (MK_VERSION): 20140522
diff --git a/contrib/bmake/mk/FILES b/contrib/bmake/mk/FILES
index 443aa2e..0a72c67 100644
--- a/contrib/bmake/mk/FILES
+++ b/contrib/bmake/mk/FILES
@@ -5,6 +5,7 @@ auto.obj.mk
autoconf.mk
autodep.mk
auto.dep.mk
+cython.mk
dep.mk
doc.mk
dpadd.mk
@@ -20,7 +21,9 @@ libnames.mk
libs.mk
links.mk
man.mk
+manifest.mk
mk-files.txt
+mkopt.sh
nls.mk
obj.mk
options.mk
@@ -49,6 +52,7 @@ sys/SunOS.mk
sys/UnixWare.mk
target-flags.mk
warnings.mk
+whats.mk
yacc.mk
dirdeps.mk
gendirdeps.mk
diff --git a/contrib/bmake/mk/auto.dep.mk b/contrib/bmake/mk/auto.dep.mk
index bb2d4c1..3313724 100644
--- a/contrib/bmake/mk/auto.dep.mk
+++ b/contrib/bmake/mk/auto.dep.mk
@@ -1,6 +1,6 @@
#
# RCSid:
-# $Id: auto.dep.mk,v 1.2 2010/04/19 17:37:19 sjg Exp $
+# $Id: auto.dep.mk,v 1.3 2014/08/04 05:19:10 sjg Exp $
#
# @(#) Copyright (c) 2010, Simon J. Gerraty
#
@@ -18,7 +18,7 @@
# This module provides automagic dependency generation along the
# lines suggested in the GNU make.info
-# set MKDEP=auto.dep and dep.mk will include us
+# set MKDEP_MK=auto.dep.mk and dep.mk will include us
# This version differs from autodep.mk, in that
# we use ${.TARGET:T}.d rather than ${.TARGET:T:R}.d
diff --git a/contrib/bmake/mk/auto.obj.mk b/contrib/bmake/mk/auto.obj.mk
index adccd4b..e25a721 100644
--- a/contrib/bmake/mk/auto.obj.mk
+++ b/contrib/bmake/mk/auto.obj.mk
@@ -1,4 +1,4 @@
-# $Id: auto.obj.mk,v 1.8 2011/08/08 17:35:20 sjg Exp $
+# $Id: auto.obj.mk,v 1.10 2015/04/16 16:59:00 sjg Exp $
#
# @(#) Copyright (c) 2004, Simon J. Gerraty
#
@@ -34,10 +34,14 @@ Mkdirs= Mkdirs() { \
# if MKOBJDIRS is set to auto (and NOOBJ isn't defined) do some magic...
# This will automatically create objdirs as needed.
# Skip it if we are just doing 'clean'.
+.if ${MK_AUTO_OBJ:Uno} == "yes"
+MKOBJDIRS= auto
+.endif
.if !defined(NOOBJ) && !defined(NO_OBJ) && ${MKOBJDIRS:Uno} == auto
# Use __objdir here so it is easier to tweak without impacting
# the logic.
__objdir?= ${MAKEOBJDIR}
+__objdir:= ${__objdir:tA}
.if ${.OBJDIR} != ${__objdir}
# We need to chdir, make the directory if needed
.if !exists(${__objdir}/) && \
@@ -46,11 +50,12 @@ __objdir?= ${MAKEOBJDIR}
__objdir_made != echo ${__objdir}/; umask ${OBJDIR_UMASK:U002}; \
${ECHO_TRACE} "[Creating objdir ${__objdir}...]" >&2; \
${Mkdirs}; Mkdirs ${__objdir}
+__objdir:= ${__objdir:tA}
.endif
# This causes make to use the specified directory as .OBJDIR
.OBJDIR: ${__objdir}
.if ${.OBJDIR} != ${__objdir} && ${__objdir_made:Uno:M${__objdir}/*} != ""
-.error could not use ${__objdir}
+.error could not use ${__objdir}: .OBJDIR=${.OBJDIR}
.endif
.endif
.endif
diff --git a/contrib/bmake/mk/autodep.mk b/contrib/bmake/mk/autodep.mk
index 818c474..84dea81 100644
--- a/contrib/bmake/mk/autodep.mk
+++ b/contrib/bmake/mk/autodep.mk
@@ -1,6 +1,6 @@
#
# RCSid:
-# $Id: autodep.mk,v 1.33 2014/04/05 22:56:54 sjg Exp $
+# $Id: autodep.mk,v 1.34 2014/08/04 05:12:27 sjg Exp $
#
# @(#) Copyright (c) 1999-2010, Simon J. Gerraty
#
@@ -19,14 +19,9 @@
# The depend target is mainly for backwards compatibility,
# dependencies are normally updated as part of compilation.
-# set MKDEP=autodep and dep.mk will include us
.if !target(__${.PARSEFILE}__)
__${.PARSEFILE}__:
-# different versions of bsd.dep.mk use these
-MKDEP=autodep
-MKDEPCMD=autodep
-
DEPENDFILE?= .depend
.for d in ${DEPENDFILE:N.depend}
# bmake only groks .depend
diff --git a/contrib/bmake/mk/cython.mk b/contrib/bmake/mk/cython.mk
new file mode 100644
index 0000000..7d9b8cd
--- /dev/null
+++ b/contrib/bmake/mk/cython.mk
@@ -0,0 +1,96 @@
+# RCSid:
+# $Id: cython.mk,v 1.6 2014/10/15 06:23:51 sjg Exp $
+#
+# @(#) Copyright (c) 2014, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+# this is what we build
+CYTHON_MODULE = ${CYTHON_MODULE_NAME}${CYTHON_PYVERSION}.so
+
+CYTHON_MODULE_NAME?= it
+CYTHON_SRCS?= ${CYTHON_MODULE_NAME}.pyx
+
+# this is where we save generated src
+CYTHON_SAVEGENDIR?= ${.CURDIR}/gen
+
+# pyprefix is where python bits are
+# which may not be where we want to put ours (prefix)
+.if exists(/usr/pkg/include)
+pyprefix?= /usr/pkg
+.endif
+pyprefix?= /usr/local
+
+PYTHON_VERSION?= 2.7
+PYTHON_H?= ${pyprefix}/include/python${PYTHON_VERSION}/Python.h
+PYVERSION:= ${PYTHON_VERSION:C,\..*,,}
+
+# set this empty if you don't want to handle multiple versions
+.if !defined(CYTHON_PYVERSION)
+CYTHON_PYVERSION:= ${PYVERSION}
+.endif
+
+CFLAGS+= -I${PYTHON_H:H}
+
+CYTHON_GENSRCS= ${CYTHON_SRCS:R:S,$,${CYTHON_PYVERSION}.c,}
+SRCS+= ${CYTHON_GENSRCS}
+
+.SUFFIXES: .pyx .c .So
+
+CYTHON?= ${pyprefix}/bin/cython
+
+# if we don't have cython we can use pre-generated srcs
+.if ${type ${CYTHON} 2> /dev/null || echo:L:sh:M/*} == ""
+.PATH: ${CYTHON_SAVEGENDIR}
+.else
+
+.if !empty(CYTHON_PYVERSION)
+.for c in ${CYTHON_SRCS}
+${c:R}${CYTHON_PYVERSION}.${c:E}: $c
+ ln -sf ${.ALLSRC:M*pyx} ${.TARGET}
+.endfor
+.endif
+
+.pyx.c:
+ ${CYTHON} ${CYTHON_FLAGS} -${PYVERSION} -o ${.TARGET} ${.IMPSRC}
+
+
+save-gen: ${CYTHON_GENSRCS}
+ mkdir -p ${CYTHON_SAVEGENDIR}
+ cp -p ${.ALLSRC} ${CYTHON_SAVEGENDIR}
+
+.endif
+
+COMPILE.c?= ${CC} -c ${CFLAGS}
+
+.c.So:
+ ${COMPILE.c} ${PICFLAG} ${CC_PIC} ${.IMPSRC} -o ${.TARGET}
+
+${CYTHON_MODULE}: ${SRCS:S,.c,.So,}
+ ${CC} ${CC_SHARED:U-shared} -o ${.TARGET} ${.ALLSRC:M*.So} ${LDADD}
+
+# conf.host_target() is limited to uname -m rather than uname -p
+_HOST_MACHINE!= uname -m
+.if ${HOST_TARGET:M*${_HOST_MACHINE}} == ""
+PY_HOST_TARGET:= ${HOST_TARGET:S,${_HOST_ARCH:U${uname -p:L:sh}}$,${_HOST_MACHINE},}
+.endif
+
+MODULE_BINDIR?= ${.CURDIR:H}/${PY_HOST_TARGET:U${HOST_TARGET}}
+
+build-cython-module: ${CYTHON_MODULE}
+
+install-cython-module: ${CYTHON_MODULE}
+ test -d ${DESTDIR}${MODULE_BINDIR} || \
+ ${INSTALL} -d ${DESTDIR}${MODULE_BINDIR}
+ ${INSTALL} -m 755 ${.ALLSRC} ${DESTDIR}${MODULE_BINDIR}
+
+CLEANFILES+= *.So ${CYTHON_MODULE}
diff --git a/contrib/bmake/mk/dep.mk b/contrib/bmake/mk/dep.mk
index b754500..b07191a 100644
--- a/contrib/bmake/mk/dep.mk
+++ b/contrib/bmake/mk/dep.mk
@@ -1,4 +1,4 @@
-# $Id: dep.mk,v 1.16 2012/11/11 22:37:02 sjg Exp $
+# $Id: dep.mk,v 1.17 2014/08/04 05:12:27 sjg Exp $
.if !target(__${.PARSEFILE}__)
__${.PARSEFILE}__:
@@ -34,21 +34,15 @@ MKDEP ?= ${MKDEP_CMD}
.NOPATH: .depend
-.if ${MKDEP} == "auto.dep" && make(depend)
+.if ${MKDEP_MK:Uno} == "auto.dep.mk" && make(depend)
# auto.dep.mk does not "do" depend
MK_AUTODEP= no
.endif
.if ${MK_AUTODEP} == yes
-.if ${MKDEP:T:S,auto,,} != ${MKDEP:T}
-.include <${MKDEP}.mk>
+MKDEP_MK ?= autodep.mk
+.include <${MKDEP_MK}>
.else
-.include <autodep.mk>
-.endif
-.else
-.if ${MKDEP:T:S,auto,,} != ${MKDEP:T}
-MKDEP = ${MKDEP_CMD}
-.endif
MKDEP_ENV_VARS += CC CXX
.for v in ${MKDEP_ENV_VARS:O:u}
.if !empty($v)
diff --git a/contrib/bmake/mk/dirdeps.mk b/contrib/bmake/mk/dirdeps.mk
index 8c342be..fd03c82 100644
--- a/contrib/bmake/mk/dirdeps.mk
+++ b/contrib/bmake/mk/dirdeps.mk
@@ -1,4 +1,4 @@
-# $Id: dirdeps.mk,v 1.35 2014/05/03 06:27:56 sjg Exp $
+# $Id: dirdeps.mk,v 1.49 2015/03/11 21:39:28 sjg Exp $
# Copyright (c) 2010-2013, Juniper Networks, Inc.
# All rights reserved.
@@ -111,7 +111,9 @@
# TARGET_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts,}
#
-.if ${.MAKE.LEVEL} == 0
+# touch this at your peril
+_DIRDEP_USE_LEVEL?= 0
+.if ${.MAKE.LEVEL} == ${_DIRDEP_USE_LEVEL}
# only the first instance is interested in all this
# First off, we want to know what ${MACHINE} to build for.
@@ -121,6 +123,12 @@
.if !target(_DIRDEP_USE)
# do some setup we only need once
_CURDIR ?= ${.CURDIR}
+_OBJDIR ?= ${.OBJDIR}
+
+now_utc = ${%s:L:gmtime}
+.if !defined(start_utc)
+start_utc := ${now_utc}
+.endif
# make sure these are empty to start with
_DEP_TARGET_SPEC =
@@ -201,7 +209,7 @@ _last_dependfile := ${.INCLUDEDFROMFILE:M${.MAKE.DEPENDFILE_PREFIX}*}
.else
_last_dependfile := ${.MAKE.MAKEFILES:M*/${.MAKE.DEPENDFILE_PREFIX}*:[-1]}
.endif
-.if !empty(_debug_reldir)
+.if ${_debug_reldir:U0}
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: _last_dependfile='${_last_dependfile}'
.endif
@@ -260,7 +268,7 @@ _DEP_RELDIR := ${DEP_RELDIR}
# things we skip for host tools
SKIP_HOSTDIR ?=
-NSkipHostDir = ${SKIP_HOSTDIR:N*.host:S,$,.host,:N.host:${M_ListToSkip}}
+NSkipHostDir = ${SKIP_HOSTDIR:N*.host*:S,$,.host*,:N.host*:S,^,${SRCTOP}/,:${M_ListToSkip}}
# things we always skip
# SKIP_DIRDEPS allows for adding entries on command line.
@@ -332,8 +340,78 @@ _only_machines := ${_only_machines:${NOT_MACHINE_LIST:${M_ListToSkip}}}
DIRDEPS ?= ${RELDIR}
.endif # target
-_debug_reldir := ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.${DEP_MACHINE}:L:M$x}@}
-_debug_search := ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.depend:L:M$x}@}
+# if repeatedly building the same target,
+# we can avoid the overhead of re-computing the tree dependencies.
+MK_DIRDEPS_CACHE ?= no
+BUILD_DIRDEPS_CACHE ?= no
+BUILD_DIRDEPS ?= yes
+
+.if !defined(NO_DIRDEPS)
+.if ${MK_DIRDEPS_CACHE} == "yes"
+# this is where we will cache all our work
+DIRDEPS_CACHE?= ${_OBJDIR}/dirdeps.cache${.TARGETS:Nall:O:u:ts-:S,^,.,:N.}
+
+# just ensure this exists
+build-dirdeps:
+
+M_oneperline = @x@\\${.newline} $$x@
+
+.if ${BUILD_DIRDEPS_CACHE} == "no"
+.if !target(dirdeps-cached)
+# we do this via sub-make
+BUILD_DIRDEPS = no
+
+dirdeps: dirdeps-cached
+dirdeps-cached: ${DIRDEPS_CACHE} .MAKE
+ @echo "${TRACER}Using ${DIRDEPS_CACHE}"
+ @MAKELEVEL=${.MAKE.LEVEL} ${.MAKE} -C ${_CURDIR} -f ${DIRDEPS_CACHE} \
+ dirdeps MK_DIRDEPS_CACHE=no BUILD_DIRDEPS=no
+
+# these should generally do
+BUILD_DIRDEPS_MAKEFILE ?= ${MAKEFILE}
+BUILD_DIRDEPS_TARGETS ?= ${.TARGETS}
+
+# we need the .meta file to ensure we update if
+# any of the Makefile.depend* changed.
+# We do not want to compare the command line though.
+${DIRDEPS_CACHE}: .META .NOMETA_CMP
+ +@{ echo '# Autogenerated - do NOT edit!'; echo; \
+ echo 'BUILD_DIRDEPS=no'; echo; \
+ echo '.include <dirdeps.mk>'; \
+ } > ${.TARGET}.new
+ +@MAKELEVEL=${.MAKE.LEVEL} DIRDEPS_CACHE=${DIRDEPS_CACHE} \
+ DIRDEPS="${DIRDEPS}" \
+ MAKEFLAGS= ${.MAKE} -C ${_CURDIR} -f ${BUILD_DIRDEPS_MAKEFILE} \
+ ${BUILD_DIRDEPS_TARGETS} BUILD_DIRDEPS_CACHE=yes \
+ 3>&1 1>&2 | sed 's,${SRCTOP},$${SRCTOP},g' >> ${.TARGET}.new && \
+ mv ${.TARGET}.new ${.TARGET}
+
+.endif
+.elif !target(_count_dirdeps)
+# we want to capture the dirdeps count in the cache
+.END: _count_dirdeps
+_count_dirdeps: .NOMETA
+ @echo '.info $${.newline}$${TRACER}Makefiles read: total=${.MAKE.MAKEFILES:[#]} depend=${.MAKE.MAKEFILES:M*depend*:[#]} dirdeps=${.ALLTARGETS:M${SRCTOP}*:O:u:[#]}' >&3
+
+.endif
+.endif
+.elif !target(_count_dirdeps)
+beforedirdeps: _count_dirdeps
+_count_dirdeps: .NOMETA
+ @echo "${TRACER}Makefiles read: total=${.MAKE.MAKEFILES:[#]} depend=${.MAKE.MAKEFILES:M*depend*:[#]} dirdeps=${.ALLTARGETS:M${SRCTOP}*:O:u:[#]} seconds=`expr ${now_utc} - ${start_utc}`"
+
+.endif
+.if ${BUILD_DIRDEPS} == "yes"
+.if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.${DEP_MACHINE}:L:M$x}@} != ""
+_debug_reldir = 1
+.else
+_debug_reldir = 0
+.endif
+.if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.depend:L:M$x}@} != ""
+_debug_search = 1
+.else
+_debug_search = 0
+.endif
# the rest is done repeatedly for every Makefile.depend we read.
# if we are anything but the original dir we care only about the
@@ -368,7 +446,8 @@ _machines := ${_machines:O:u}
# we need to tweak _machines
_dm := ${DEP_MACHINE}
# apply the same filtering that we do when qualifying DIRDEPS.
-_machines := ${_machines:@DEP_MACHINE@${DEP_TARGET_SPEC}@:${M_dep_qual_fixes:ts:}:O:u}
+# M_dep_qual_fixes expects .${MACHINE}* so add (and remove) '.'
+_machines := ${_machines:@DEP_MACHINE@${DEP_TARGET_SPEC}@:S,^,.,:${M_dep_qual_fixes:ts:}:O:u:S,^.,,}
DEP_MACHINE := ${_dm}
.endif
@@ -388,7 +467,7 @@ _build_dirs += ${_machines:N${DEP_TARGET_SPEC}:@m@${_CURDIR}.$m@}
.endif
.endif
-.if !empty(_debug_reldir)
+.if ${_debug_reldir}
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: DIRDEPS='${DIRDEPS}'
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: _machines='${_machines}'
.endif
@@ -419,7 +498,7 @@ __hostdpadd := ${DPADD:U.:M${HOST_OBJTOP}/*:S,${HOST_OBJTOP}/,,:H:${NSkipDir}:${
__qual_depdirs += ${__hostdpadd}
.endif
-.if !empty(_debug_reldir)
+.if ${_debug_reldir}
.info depdirs=${__depdirs}
.info qualified=${__qual_depdirs}
.info unqualified=${__unqual_depdirs}
@@ -429,7 +508,8 @@ __qual_depdirs += ${__hostdpadd}
_build_dirs += \
${__qual_depdirs:M*.host:${NSkipHostDir}:N.host} \
${__qual_depdirs:N*.host} \
- ${_machines:@m@${__unqual_depdirs:@d@$d.$m@}@}
+ ${_machines:Mhost*:@m@${__unqual_depdirs:@d@$d.$m@}@:${NSkipHostDir}:N.host} \
+ ${_machines:Nhost*:@m@${__unqual_depdirs:@d@$d.$m@}@}
# qualify everything now
_build_dirs := ${_build_dirs:${M_dep_qual_fixes:ts:}:O:u}
@@ -441,11 +521,17 @@ _build_dirs := ${_build_dirs:${M_dep_qual_fixes:ts:}:O:u}
# but if we want to count the number of Makefile.depend* read, we do.
.if ${.MAKEFLAGS:M-V${_V_READ_DIRDEPS}} == ""
.if !empty(_build_dirs)
+.if ${BUILD_DIRDEPS_CACHE} == "yes"
+x!= { echo; echo '\# ${DEP_RELDIR}.${DEP_TARGET_SPEC}'; \
+ echo 'dirdeps: ${_build_dirs:${M_oneperline}}'; echo; } >&3; echo
+x!= { ${_build_dirs:@x@${target($x):?:echo '$x: _DIRDEP_USE';}@} echo; } >&3; echo
+.else
# this makes it all happen
dirdeps: ${_build_dirs}
+.endif
${_build_dirs}: _DIRDEP_USE
-.if !empty(_debug_reldir)
+.if ${_debug_reldir}
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: needs: ${_build_dirs}
.endif
@@ -454,16 +540,24 @@ ${_build_dirs}: _DIRDEP_USE
# it would be nice to do :N${.TARGET}
.if !empty(__qual_depdirs)
.for q in ${__qual_depdirs:${M_dep_qual_fixes:ts:}:E:O:u:N$m}
-.if !empty(_debug_reldir) || ${DEBUG_DIRDEPS:@x@${${DEP_RELDIR}.$m:L:M$x}${${DEP_RELDIR}.$q:L:M$x}@} != ""
+.if ${_debug_reldir} || ${DEBUG_DIRDEPS:@x@${${DEP_RELDIR}.$m:L:M$x}${${DEP_RELDIR}.$q:L:M$x}@} != ""
.info ${DEP_RELDIR}.$m: graph: ${_build_dirs:M*.$q}
.endif
+.if ${BUILD_DIRDEPS_CACHE} == "yes"
+x!= { echo; echo '${_this_dir}.$m: ${_build_dirs:M*.$q:${M_oneperline}}'; echo; } >&3; echo
+.else
${_this_dir}.$m: ${_build_dirs:M*.$q}
+.endif
.endfor
.endif
-.if !empty(_debug_reldir)
+.if ${_debug_reldir}
.info ${DEP_RELDIR}.$m: graph: ${_build_dirs:M*.$m:N${_this_dir}.$m}
.endif
+.if ${BUILD_DIRDEPS_CACHE} == "yes"
+x!= { echo; echo '${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m:${M_oneperline}}'; echo; } >&3; echo
+.else
${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m}
+.endif
.endfor
.endif
@@ -473,7 +567,7 @@ ${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m}
.if ${_DIRDEP_CHECKED:M$d} == ""
# once only
_DIRDEP_CHECKED += $d
-.if !empty(_debug_search)
+.if ${_debug_search}
.info checking $d
.endif
# Note: _build_dirs is fully qualifed so d:R is always the directory
@@ -485,14 +579,14 @@ _m := ${.MAKE.DEPENDFILE_PREFERENCE:T:S;${TARGET_SPEC}$;${d:E};:S;${MACHINE};${d
.if !empty(_m)
# M_dep_qual_fixes isn't geared to Makefile.depend
_qm := ${_m:C;(\.depend)$;\1.${d:E};:${M_dep_qual_fixes:ts:}}
-.if !empty(_debug_search)
+.if ${_debug_search}
.info Looking for ${_qm}
.endif
# we pass _DEP_TARGET_SPEC to tell the next step what we want
_DEP_TARGET_SPEC := ${d:E}
# some makefiles may still look at this
_DEP_MACHINE := ${d:E:C/,.*//}
-.if !empty(_debug_reldir) && ${_qm} != ${_m}
+.if ${_debug_reldir} && ${_qm} != ${_m}
.info loading ${_m} for ${d:E}
.endif
.include <${_m}>
@@ -502,6 +596,7 @@ _DEP_MACHINE := ${d:E:C/,.*//}
.endfor
.endif # -V
+.endif # BUILD_DIRDEPS
.elif ${.MAKE.LEVEL} > 42
.error You should have stopped recursing by now.
@@ -511,3 +606,37 @@ _DEP_RELDIR := ${DEP_RELDIR}
.-include <.depend>
.endif
+# bootstrapping new dependencies made easy?
+.if make(bootstrap*) && !target(bootstrap)
+
+.if exists(${.CURDIR}/${.MAKE.DEPENDFILE:T})
+# stop here
+${.TARGETS:Mboot*}:
+.else
+# find a Makefile.depend to use as _src
+_src != cd ${.CURDIR} && for m in ${.MAKE.DEPENDFILE_PREFERENCE:T:S,${MACHINE},*,}; do test -s $$m || continue; echo $$m; break; done; echo
+.if empty(_src)
+.error cannot find any of ${.MAKE.DEPENDFILE_PREFERENCE:T}
+.endif
+
+_src?= ${.MAKE.DEPENDFILE:T}
+
+bootstrap-this: .NOTMAIN
+ @echo Bootstrapping ${RELDIR}/${.MAKE.DEPENDFILE:T} from ${_src:T}
+ (cd ${.CURDIR} && sed 's,${_src:E},${MACHINE},g' ${_src} > ${.MAKE.DEPENDFILE:T})
+
+bootstrap: bootstrap-recurse
+bootstrap-recurse: bootstrap-this
+
+_mf := ${.PARSEFILE}
+bootstrap-recurse: .NOTMAIN .MAKE
+ @cd ${SRCTOP} && \
+ for d in `cd ${RELDIR} && ${.MAKE} -B -f ${"${.MAKEFLAGS:M-n}":?${_src}:${.MAKE.DEPENDFILE:T}} -V DIRDEPS`; do \
+ test -d $$d || d=$${d%.*}; \
+ test -d $$d || continue; \
+ echo "Checking $$d for bootstrap ..."; \
+ (cd $$d && ${.MAKE} -f ${_mf} bootstrap-recurse); \
+ done
+
+.endif
+.endif
diff --git a/contrib/bmake/mk/gendirdeps.mk b/contrib/bmake/mk/gendirdeps.mk
index b313298..28e1f21 100644
--- a/contrib/bmake/mk/gendirdeps.mk
+++ b/contrib/bmake/mk/gendirdeps.mk
@@ -1,4 +1,4 @@
-# $Id: gendirdeps.mk,v 1.25 2014/03/14 21:28:37 sjg Exp $
+# $Id: gendirdeps.mk,v 1.26 2014/09/05 04:40:52 sjg Exp $
# Copyright (c) 2010-2013, Juniper Networks, Inc.
# All rights reserved.
@@ -93,6 +93,17 @@ _skip_gendirdeps = egrep -v '^(${SKIP_GENDIRDEPS:O:u:ts|})' |
_skip_gendirdeps =
.endif
+# Below we will turn _{VAR} into ${VAR} which keeps this simple
+# GENDIRDEPS_FILTER_DIR_VARS is a list of dirs to be substiuted for.
+# GENDIRDEPS_FILTER_VARS is more general.
+# In each case order matters.
+.if !empty(GENDIRDEPS_FILTER_DIR_VARS)
+GENDIRDEPS_FILTER += ${GENDIRDEPS_FILTER_DIR_VARS:@v@S,${$v},_{${v}},@}
+.endif
+.if !empty(GENDIRDEPS_FILTER_VARS)
+GENDIRDEPS_FILTER += ${GENDIRDEPS_FILTER_VARS:@v@S,/${$v}/,/_{${v}}/,@:NS,//,*:u}
+.endif
+
# this (*should* be set in meta.sys.mk)
# is the script that extracts what we want.
META2DEPS ?= ${.PARSEDIR}/meta2deps.sh
diff --git a/contrib/bmake/mk/install-mk b/contrib/bmake/mk/install-mk
index 7e4ee8b..047fcfd 100644
--- a/contrib/bmake/mk/install-mk
+++ b/contrib/bmake/mk/install-mk
@@ -55,7 +55,7 @@
# Simon J. Gerraty <sjg@crufty.net>
# RCSid:
-# $Id: install-mk,v 1.100 2014/05/23 01:30:36 sjg Exp $
+# $Id: install-mk,v 1.109 2015/04/16 16:59:00 sjg Exp $
#
# @(#) Copyright (c) 1994 Simon J. Gerraty
#
@@ -70,7 +70,7 @@
# sjg@crufty.net
#
-MK_VERSION=20140522
+MK_VERSION=20150411
OWNER=
GROUP=
MODE=444
diff --git a/contrib/bmake/mk/links.mk b/contrib/bmake/mk/links.mk
index 4ec8a01..aac3914 100644
--- a/contrib/bmake/mk/links.mk
+++ b/contrib/bmake/mk/links.mk
@@ -1,4 +1,4 @@
-# $Id: links.mk,v 1.5 2005/07/11 18:01:05 sjg Exp $
+# $Id: links.mk,v 1.6 2014/09/29 17:14:40 sjg Exp $
#
# @(#) Copyright (c) 2005, Simon J. Gerraty
#
@@ -22,9 +22,14 @@ SYMLINKS?=
__SYMLINK_SCRIPT= \
${ECHO} "$$t -> $$l"; \
- mkdir -p `dirname $$t`; \
- rm -f $$t; \
- ${LN} -s $$l $$t
+ case `'ls' -l $$t 2> /dev/null` in \
+ *"> $$l") ;; \
+ *) \
+ mkdir -p `dirname $$t`; \
+ rm -f $$t; \
+ ${LN} -s $$l $$t;; \
+ esac
+
__LINK_SCRIPT= \
${ECHO} "$$t -> $$l"; \
diff --git a/contrib/bmake/mk/manifest.mk b/contrib/bmake/mk/manifest.mk
new file mode 100644
index 0000000..797038d
--- /dev/null
+++ b/contrib/bmake/mk/manifest.mk
@@ -0,0 +1,66 @@
+# $Id: manifest.mk,v 1.2 2014/10/31 18:06:17 sjg Exp $
+#
+# @(#) Copyright (c) 2014, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+# generate mtree style manifest supported by makefs in FreeBSD
+
+# input looks like
+# MANIFEST= my.mtree
+# for each MANIFEST we have a list of dirs
+# ${MANIFEST}.DIRS += bin sbin usr/bin ...
+# for each dir we have a ${MANIFEST}.SRCS.$dir
+# that provides the absolute path to the contents
+# ${MANIFEST}.SRCS.bin += ${OBJTOP}/bin/sh/sh
+# ${MANIFEST}.SYMLINKS is a list of src target pairs
+# for each file/dir there are a number of attributes
+# UID GID MODE FLAGS
+# which can be set per dir, per file or we use defaults
+# eg.
+# MODE.sbin = 550
+# MODE.usr/sbin = 550
+# MODE.dirs = 555
+# means that sbin and usr/sbin get 550 all other dirs get 555
+# MODE.usr/bin/passwd = 4555
+# MODE.usr/bin.files = 555
+# MODE.usr/sbin.files = 500
+# means passwd gets 4555 other files in usr/bin get 555 and
+# files in usr/sbin get 500
+# STORE defaults to basename of src and target directory
+# but we can use
+# ${MANIFEST}.SRCS.sbin += ${OBJTOP}/bin/sh-static/sh-static
+# STORE.sbin/sh-static = sbin/sh
+#
+# the above is a little overkill but means we can easily adapt to
+# different formats
+
+UID.dirs ?= 0
+GID.dirs ?= 0
+MODE.dirs ?= 775
+FLAGS.dirs ?=
+
+UID.files ?= 0
+GID.files ?= 0
+MODE.files ?= 555
+
+# a is attribute name d is dirname
+M_DIR_ATTR = L:@a@$${$$a.$$d:U$${$$a.dirs}}@
+# as above and s is set to the name we store f as
+M_FILE_ATTR = L:@a@$${$$a.$$s:U$${$$a.$$d.files:U$${$$a.files}}}@
+
+# this produces the body of the manifest
+# there should typically be a header prefixed
+_GEN_MTREE_MANIFEST_USE: .USE
+ @(${${.TARGET}.DIRS:O:u:@d@echo '$d type=dir uid=${UID:${M_DIR_ATTR}} gid=${GID:${M_DIR_ATTR}} mode=${MODE:${M_DIR_ATTR}} ${FLAGS:${M_DIR_ATTR}}';@} \
+ ${${.TARGET}.DIRS:O:u:@d@${${.TARGET}.SRCS.$d:O:u:@f@echo '${s::=${STORE.$d/${f:T}:U$d/${f:T}}}$s contents="$f" type=file uid=${UID:${M_FILE_ATTR}} gid=${GID:${M_FILE_ATTR}} mode=${MODE:${M_FILE_ATTR}} ${FLAGS:${M_FILE_ATTR}}';@}@} \
+ set ${${.TARGET}.SYMLINKS}; while test $$# -ge 2; do echo "$$2 type=link link=$$1"; shift 2; done) > ${.TARGET}
diff --git a/contrib/bmake/mk/meta.autodep.mk b/contrib/bmake/mk/meta.autodep.mk
index a961bff..64bc30b 100644
--- a/contrib/bmake/mk/meta.autodep.mk
+++ b/contrib/bmake/mk/meta.autodep.mk
@@ -1,4 +1,4 @@
-# $Id: meta.autodep.mk,v 1.35 2014/05/09 00:05:46 sjg Exp $
+# $Id: meta.autodep.mk,v 1.36 2014/08/02 23:10:29 sjg Exp $
#
# @(#) Copyright (c) 2010, Simon J. Gerraty
@@ -254,6 +254,9 @@ ${_DEPENDFILE}: ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} $${.MAKE.MET
.endif
.if ${_bootstrap_dirdeps} == "yes"
+.if ${BUILD_AT_LEVEL0:Uno} == "no"
+DIRDEPS+= ${RELDIR}.${TARGET_SPEC:U${MACHINE}}
+.endif
# make sure this is included at least once
.include <dirdeps.mk>
.else
diff --git a/contrib/bmake/mk/meta.stage.mk b/contrib/bmake/mk/meta.stage.mk
index 2f02700..cd95113 100644
--- a/contrib/bmake/mk/meta.stage.mk
+++ b/contrib/bmake/mk/meta.stage.mk
@@ -1,4 +1,4 @@
-# $Id: meta.stage.mk,v 1.30 2013/04/19 16:32:57 sjg Exp $
+# $Id: meta.stage.mk,v 1.34 2014/11/20 22:40:08 sjg Exp $
#
# @(#) Copyright (c) 2011, Simon J. Gerraty
#
@@ -35,7 +35,13 @@ _stage_file_basename = $${f\#\#*/}
_stage_target_dirname = $${t%/*}
.endif
+_OBJROOT ?= ${OBJROOT:U${OBJTOP:H}}
+.if ${_OBJROOT:M*/} != ""
+_objroot ?= ${_OBJROOT:tA}/
+.else
_objroot ?= ${_OBJROOT:tA}
+.endif
+
# make sure this is global
_STAGED_DIRS ?=
.export _STAGED_DIRS
@@ -46,7 +52,7 @@ STAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@
# convert _STAGED_DIRS into suitable filters
GENDIRDEPS_FILTER += Nnot-empty-is-important \
${_STAGED_DIRS:O:u:M${OBJTOP}*:S,${OBJTOP}/,N,} \
- ${_STAGED_DIRS:O:u:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,}
+ ${_STAGED_DIRS:O:u:M${_objroot}*:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,}
LN_CP_SCRIPT = LnCp() { \
rm -f $$2 2> /dev/null; \
@@ -113,10 +119,14 @@ STAGE_AS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageAs() { \
_STAGE_BASENAME_USE: .USE ${.TARGET:T}
@${STAGE_FILE_SCRIPT}; StageFiles ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T}
+_STAGE_AS_BASENAME_USE: .USE ${.TARGET:T}
+ @${STAGE_AS_SCRIPT}; StageAs ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T} ${STAGE_AS_${.TARGET:T}:U${.TARGET:T}}
+
.if !empty(STAGE_INCSDIR)
STAGE_TARGETS += stage_incs
STAGE_INCS ?= ${.ALLSRC:N.dirdep}
+stage_includes: stage_incs
stage_incs: .dirdep
@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_INCSDIR:${STAGE_DIR_FILTER}} ${STAGE_INCS}
@touch $@
@@ -129,12 +139,14 @@ STAGE_LIBS ?= ${.ALLSRC:N.dirdep}
stage_libs: .dirdep
@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${STAGE_LIBS}
+.if !defined(NO_SHLIB_LINKS)
.if !empty(SHLIB_LINKS)
@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \
${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@}
.elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME)
@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK} ${SYMLINKS:T}
.endif
+.endif
@touch $@
.endif
@@ -212,7 +224,7 @@ stage_as.$s: .dirdep
.endfor
.endif
-CLEANFILES += ${STAGE_TARGETS}
+CLEANFILES += ${STAGE_TARGETS} stage_incs stage_includes
# stage_*links usually needs to follow any others.
.for t in ${STAGE_TARGETS:N*links:O:u}
@@ -240,5 +252,26 @@ INSTALL := ${STAGE_INSTALL}
beforeinstall: .dirdep
.endif
.endif
+.NOPATH: ${STAGE_FILES}
+
+.if !empty(STAGE_TARGETS)
+MK_STALE_STAGED?= no
+.if ${MK_STALE_STAGED} == "yes"
+all: stale_staged
+# get a list of paths that we have just staged
+# get a list of paths that we have previously staged to those same dirs
+# anything in the 2nd list but not the first is stale - remove it.
+stale_staged: staging .NOMETA
+ @egrep '^[WL] .*${STAGE_OBJTOP}' /dev/null ${.MAKE.META.FILES:M*stage_*} | \
+ sed "/\.dirdep/d;s,.* '*\(${STAGE_OBJTOP}/[^ '][^ ']*\).*,\1," | \
+ sort > ${.TARGET}.staged1
+ @grep -l '${_dirdep}' /dev/null ${_STAGED_DIRS:M${STAGE_OBJTOP}*:O:u:@d@$d/*.dirdep@} | \
+ sed 's,\.dirdep,,' | sort > ${.TARGET}.staged2
+ @comm -13 ${.TARGET}.staged1 ${.TARGET}.staged2 > ${.TARGET}.stale
+ @test ! -s ${.TARGET}.stale || { \
+ echo "Removing stale staged files..."; \
+ sed 's,.*,& &.dirdep,' ${.TARGET}.stale | xargs rm -f; }
.endif
+.endif
+.endif
diff --git a/contrib/bmake/mk/meta.sys.mk b/contrib/bmake/mk/meta.sys.mk
index 1707a66..bcafd55 100644
--- a/contrib/bmake/mk/meta.sys.mk
+++ b/contrib/bmake/mk/meta.sys.mk
@@ -1,4 +1,4 @@
-# $Id: meta.sys.mk,v 1.16 2012/07/03 05:26:00 sjg Exp $
+# $Id: meta.sys.mk,v 1.20 2014/08/04 05:12:27 sjg Exp $
#
# @(#) Copyright (c) 2010, Simon J. Gerraty
@@ -106,7 +106,13 @@ _metaError: .NOMETA .NOTMAIN
# Are we, after all, in meta mode?
.if ${.MAKE.MODE:Mmeta*} != ""
-MKDEP = meta.autodep
+MKDEP_MK = meta.autodep.mk
+
+# if we think we are updating dependencies,
+# then filemon had better be present
+.if ${UPDATE_DEPENDFILE:Uyes:tl} != "no" && !exists(/dev/filemon)
+.error ${.newline}ERROR: The filemon module (/dev/filemon) is not loaded.
+.endif
.if ${.MAKE.LEVEL} == 0
# make sure dirdeps target exists and do it first
@@ -121,19 +127,11 @@ dirdeps:
# tell dirdeps.mk what we want
BUILD_AT_LEVEL0 = no
.endif
-
-.if ${.MAKE.DEPENDFILE:E} == ${MACHINE}
+.if ${.TARGETS:Nall} == ""
# it works best if we do everything via sub-makes
BUILD_AT_LEVEL0 ?= no
.endif
-BUILD_AT_LEVEL0 ?= yes
-.endif
-# if we think we are updating dependencies,
-# then filemon had better be present
-.if ${UPDATE_DEPENDFILE:Uyes:tl} != "no" && !exists(/dev/filemon)
-.error ${.newline}ERROR: The filemon module (/dev/filemon) is not loaded.
.endif
-
.endif
.endif
diff --git a/contrib/bmake/mk/meta2deps.py b/contrib/bmake/mk/meta2deps.py
index 8e349e7..ed183f0 100755
--- a/contrib/bmake/mk/meta2deps.py
+++ b/contrib/bmake/mk/meta2deps.py
@@ -37,7 +37,7 @@ We only pay attention to a subset of the information in the
"""
RCSid:
- $Id: meta2deps.py,v 1.17 2014/04/05 22:56:54 sjg Exp $
+ $Id: meta2deps.py,v 1.18 2015/04/03 18:23:25 sjg Exp $
Copyright (c) 2011-2013, Juniper Networks, Inc.
All rights reserved.
@@ -112,7 +112,8 @@ def abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
rpath = resolve(path, cwd, last_dir, debug, debug_out)
if rpath:
path = rpath
- if (path.find('./') > 0 or
+ if (path.find('/') < 0 or
+ path.find('./') > 0 or
path.endswith('/..') or
os.path.islink(path)):
return os.path.realpath(path)
@@ -142,7 +143,7 @@ class MetaFile:
host_target = None
srctops = []
objroots = []
-
+ excludes = []
seen = {}
obj_deps = []
src_deps = []
@@ -179,6 +180,10 @@ class MetaFile:
This can allow 'bmake' to learn all the dirs within
the tree that depend on 'foo.h'
+ EXCLUDES
+ A list of paths to ignore.
+ ccache(1) can otherwise be trouble.
+
debug desired debug level
debug_out open file to send debug output to (sys.stderr)
@@ -236,11 +241,14 @@ class MetaFile:
# we want the longest match
self.srctops.sort(reverse=True)
self.objroots.sort(reverse=True)
-
+
+ self.excludes = getv(conf, 'EXCLUDES', [])
+
if self.debug:
print("host_target=", self.host_target, file=self.debug_out)
print("srctops=", self.srctops, file=self.debug_out)
print("objroots=", self.objroots, file=self.debug_out)
+ print("excludes=", self.excludes, file=self.debug_out)
self.dirdep_re = re.compile(r'([^/]+)/(.+)')
@@ -257,6 +265,7 @@ class MetaFile:
self.dpdeps = None # we cannot do it?
self.cwd = os.getcwd() # make sure this is initialized
+ self.last_dir = self.cwd
if name:
self.try_parse()
@@ -360,18 +369,18 @@ class MetaFile:
V 3
C "pid" "cwd"
E "pid" "path"
- F "pid" "child"
+ F "pid" "child"
R "pid" "path"
W "pid" "path"
X "pid" "status"
- D "pid" "path"
- L "pid" "src" "target"
- M "pid" "old" "new"
- S "pid" "path"
- # Bye bye
-
- We go to some effort to avoid processing a dependency more than once.
- Of the above record types only C,E,F,L,R,V and W are of interest.
+ D "pid" "path"
+ L "pid" "src" "target"
+ M "pid" "old" "new"
+ S "pid" "path"
+ # Bye bye
+
+ We go to some effort to avoid processing a dependency more than once.
+ Of the above record types only C,E,F,L,R,V and W are of interest.
"""
version = 0 # unknown
@@ -379,7 +388,7 @@ class MetaFile:
self.name = name;
if file:
f = file
- cwd = last_dir = self.cwd
+ cwd = self.last_dir = self.cwd
else:
f = open(self.name, 'r')
skip = True
@@ -412,7 +421,7 @@ class MetaFile:
interesting += 'W'
"""
elif w[0] == 'CWD':
- self.cwd = cwd = last_dir = w[1]
+ self.cwd = cwd = self.last_dir = w[1]
self.seenit(cwd) # ignore this
if self.debug:
print("%s: CWD=%s" % (self.name, cwd), file=self.debug_out)
@@ -422,9 +431,9 @@ class MetaFile:
if pid != last_pid:
if last_pid:
pid_cwd[last_pid] = cwd
- pid_last_dir[last_pid] = last_dir
+ pid_last_dir[last_pid] = self.last_dir
cwd = getv(pid_cwd, pid, self.cwd)
- last_dir = getv(pid_last_dir, pid, self.cwd)
+ self.last_dir = getv(pid_last_dir, pid, self.cwd)
last_pid = pid
# process operations
@@ -438,7 +447,7 @@ class MetaFile:
cwd = abspath(w[2], cwd, None, self.debug, self.debug_out)
if cwd.endswith('/.'):
cwd = cwd[0:-2]
- last_dir = cwd
+ self.last_dir = cwd
if self.debug > 1:
print("cwd=", cwd, file=self.debug_out)
continue
@@ -449,98 +458,114 @@ class MetaFile:
continue
# file operations
if w[0] in 'ML':
- path = w[2].strip("'")
- else:
- path = w[2]
- # we are never interested in .dirdep files as dependencies
- if path.endswith('.dirdep'):
+ # these are special, tread src as read and
+ # target as write
+ self.parse_path(w[1].strip("'"), cwd, 'R', w)
+ self.parse_path(w[2].strip("'"), cwd, 'W', w)
continue
- # we don't want to resolve the last component if it is
- # a symlink
- path = resolve(path, cwd, last_dir, self.debug, self.debug_out)
- if not path:
- continue
- dir,base = os.path.split(path)
- if dir in self.seen:
+ elif w[0] in 'ERWS':
+ path = w[2]
+ self.parse_path(path, cwd, w[0], w)
+
+ if not file:
+ f.close()
+
+ def parse_path(self, path, cwd, op=None, w=[]):
+ """look at a path for the op specified"""
+
+ if not op:
+ op = w[0]
+
+ # we are never interested in .dirdep files as dependencies
+ if path.endswith('.dirdep'):
+ return
+ for p in self.excludes:
+ if p and path.startswith(p):
if self.debug > 2:
- print("seen:", dir, file=self.debug_out)
- continue
- # we can have a path in an objdir which is a link
- # to the src dir, we may need to add dependencies for each
- rdir = dir
- dir = abspath(dir, cwd, last_dir, self.debug, self.debug_out)
- if rdir == dir or rdir.find('./') > 0:
- rdir = None
- # now put path back together
- path = '/'.join([dir,base])
- if self.debug > 1:
- print("raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path), file=self.debug_out)
- if w[0] in 'SRWL':
- if w[0] == 'W' and path.endswith('.dirdep'):
- continue
- if path in [last_dir, cwd, self.cwd, self.curdir]:
- if self.debug > 1:
- print("skipping:", path, file=self.debug_out)
- continue
- if os.path.isdir(path):
- if w[0] in 'RW':
- last_dir = path;
- if self.debug > 1:
- print("ldir=", last_dir, file=self.debug_out)
- continue
+ print >> self.debug_out, "exclude:", p, path
+ return
+ # we don't want to resolve the last component if it is
+ # a symlink
+ path = resolve(path, cwd, self.last_dir, self.debug, self.debug_out)
+ if not path:
+ return
+ dir,base = os.path.split(path)
+ if dir in self.seen:
+ if self.debug > 2:
+ print("seen:", dir, file=self.debug_out)
+ return
+ # we can have a path in an objdir which is a link
+ # to the src dir, we may need to add dependencies for each
+ rdir = dir
+ dir = abspath(dir, cwd, self.last_dir, self.debug, self.debug_out)
+ if rdir == dir or rdir.find('./') > 0:
+ rdir = None
+ # now put path back together
+ path = '/'.join([dir,base])
+ if self.debug > 1:
+ print("raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path), file=self.debug_out)
+ if op in 'RWS':
+ if path in [self.last_dir, cwd, self.cwd, self.curdir]:
+ if self.debug > 1:
+ print("skipping:", path, file=self.debug_out)
+ return
+ if os.path.isdir(path):
+ if op in 'RW':
+ self.last_dir = path;
+ if self.debug > 1:
+ print("ldir=", self.last_dir, file=self.debug_out)
+ return
+
+ if op in 'ERW':
+ # finally, we get down to it
+ if dir == self.cwd or dir == self.curdir:
+ return
+ srctop = self.find_top(path, self.srctops)
+ if srctop:
+ if self.dpdeps:
+ self.add(self.file_deps, path.replace(srctop,''), 'file')
+ self.add(self.src_deps, dir.replace(srctop,''), 'src')
+ self.seenit(w[2])
+ self.seenit(dir)
+ if rdir and not rdir.startswith(srctop):
+ dir = rdir # for below
+ rdir = None
+ else:
+ return
- if w[0] in 'REWML':
- # finally, we get down to it
- if dir == self.cwd or dir == self.curdir:
+ objroot = None
+ for dir in [dir,rdir]:
+ if not dir:
continue
- srctop = self.find_top(path, self.srctops)
- if srctop:
- if self.dpdeps:
- self.add(self.file_deps, path.replace(srctop,''), 'file')
- self.add(self.src_deps, dir.replace(srctop,''), 'src')
- self.seenit(w[2])
- self.seenit(dir)
- if rdir and not rdir.startswith(srctop):
- dir = rdir # for below
- rdir = None
- else:
- continue
-
- objroot = None
- for dir in [dir,rdir]:
- if not dir:
- continue
- objroot = self.find_top(dir, self.objroots)
- if objroot:
- break
+ objroot = self.find_top(dir, self.objroots)
if objroot:
- ddep = self.find_obj(objroot, dir, path, w[2])
- if ddep:
- self.add(self.obj_deps, ddep, 'obj')
- else:
- # don't waste time looking again
- self.seenit(w[2])
- self.seenit(dir)
- if not file:
- f.close()
+ break
+ if objroot:
+ ddep = self.find_obj(objroot, dir, path, w[2])
+ if ddep:
+ self.add(self.obj_deps, ddep, 'obj')
+ else:
+ # don't waste time looking again
+ self.seenit(w[2])
+ self.seenit(dir)
def main(argv, klass=MetaFile, xopts='', xoptf=None):
"""Simple driver for class MetaFile.
Usage:
- script [options] [key=value ...] "meta" ...
+ script [options] [key=value ...] "meta" ...
Options and key=value pairs contribute to the
dictionary passed to MetaFile.
-S "SRCTOP"
- add "SRCTOP" to the "SRCTOPS" list.
+ add "SRCTOP" to the "SRCTOPS" list.
-C "CURDIR"
-O "OBJROOT"
- add "OBJROOT" to the "OBJROOTS" list.
+ add "OBJROOT" to the "OBJROOTS" list.
-m "MACHINE"
@@ -550,7 +575,7 @@ def main(argv, klass=MetaFile, xopts='', xoptf=None):
-D "DPDEPS"
- -d bumps debug level
+ -d bumps debug level
"""
import getopt
@@ -568,6 +593,7 @@ def main(argv, klass=MetaFile, xopts='', xoptf=None):
conf = {
'SRCTOPS': [],
'OBJROOTS': [],
+ 'EXCLUDES': [],
}
try:
@@ -589,7 +615,7 @@ def main(argv, klass=MetaFile, xopts='', xoptf=None):
debug = 0
output = True
- opts, args = getopt.getopt(argv[1:], 'a:dS:C:O:R:m:D:H:qT:' + xopts)
+ opts, args = getopt.getopt(argv[1:], 'a:dS:C:O:R:m:D:H:qT:X:' + xopts)
for o, a in opts:
if o == '-a':
conf['MACHINE_ARCH'] = a
@@ -615,6 +641,9 @@ def main(argv, klass=MetaFile, xopts='', xoptf=None):
conf['MACHINE'] = a
elif o == '-T':
conf['TARGET_SPEC'] = a
+ elif o == '-X':
+ if a not in conf['EXCLUDES']:
+ conf['EXCLUDES'].append(a)
elif xoptf:
xoptf(o, a, conf)
@@ -649,16 +678,21 @@ def main(argv, klass=MetaFile, xopts='', xoptf=None):
for k,v in list(conf.items()):
print("%s=%s" % (k,v), file=debug_out)
+ m = None
for a in args:
if a.endswith('.meta'):
+ if not os.path.exists(a):
+ continue
m = klass(a, conf)
elif a.startswith('@'):
# there can actually multiple files per line
for line in open(a[1:]):
for f in line.strip().split():
+ if not os.path.exists(f):
+ continue
m = klass(f, conf)
- if output:
+ if output and m:
print(m.dirdeps())
print(m.src_dirdeps('\nsrc:'))
diff --git a/contrib/bmake/mk/meta2deps.sh b/contrib/bmake/mk/meta2deps.sh
index d96ce07..2a79be1 100755
--- a/contrib/bmake/mk/meta2deps.sh
+++ b/contrib/bmake/mk/meta2deps.sh
@@ -77,7 +77,7 @@
# RCSid:
-# $Id: meta2deps.sh,v 1.7 2014/04/05 22:56:54 sjg Exp $
+# $Id: meta2deps.sh,v 1.9 2015/04/03 18:23:25 sjg Exp $
# Copyright (c) 2010-2013, Juniper Networks, Inc.
# All rights reserved.
@@ -139,10 +139,15 @@ add_list() {
eval "$name=\"$list\""
}
+_excludes_f() {
+ egrep -v "$EXCLUDES"
+}
+
meta2deps() {
DPDEPS=
SRCTOPS=$SRCTOP
OBJROOTS=
+ EXCLUDES=
while :
do
case "$1" in
@@ -153,6 +158,7 @@ meta2deps() {
-H) HOST_TARGET=$2; shift 2;;
-S) add_list SRCTOPS $2; shift 2;;
-O) add_list OBJROOTS $2; shift 2;;
+ -X) add_list EXCLUDES '|' $2; shift 2;;
-R) RELDIR=$2; shift 2;;
-T) TARGET_SPEC=$2; shift 2;;
*) break;;
@@ -212,8 +218,26 @@ meta2deps() {
seenit=
seensrc=
lpid=
- cat /dev/null "$@" |
- sed -e 's,^CWD,C C,;/^[CREFL] /!d' -e "s,',,g" |
+ case "$EXCLUDES" in
+ "") _excludes=cat;;
+ *) _excludes=_excludes_f;;
+ esac
+ # handle @list files
+ case "$@" in
+ *@[!.]*)
+ for f in "$@"
+ do
+ case "$f" in
+ *.meta) cat $f;;
+ @*) xargs cat < ${f#@};;
+ *) cat $f;;
+ esac
+ done
+ ;;
+ *) cat /dev/null "$@";;
+ esac 2> /dev/null |
+ sed -e 's,^CWD,C C,;/^[CREFLM] /!d' -e "s,',,g" |
+ $_excludes |
while read op pid path junk
do
: op=$op pid=$pid path=$path
diff --git a/contrib/bmake/mk/mk-files.txt b/contrib/bmake/mk/mk-files.txt
index 7882641..7eebfd6 100644
--- a/contrib/bmake/mk/mk-files.txt
+++ b/contrib/bmake/mk/mk-files.txt
@@ -432,13 +432,27 @@ You should never need to edit ``warnings.mk``, it will include
``warnings-sets.mk`` if it exists and you use that to make any local
customizations.
+rst2htm.mk
+----------
+
+Logic to simplify generating HTML (and PDF) documents from ReStructuredText.
+
+cython.mk
+---------
+
+Logic to build Python C interface modules using Cython_
+
+.. _Cython: http://www.cython.org/
+
Meta mode
=========
The 20110505 and later versions of ``mk-files`` include a number of
-makefile contributed by Juniper Networks, Inc.
-These allow the latest version of bmake_ to run in `meta mode`_.
+makefiles contributed by Juniper Networks, Inc.
+These allow the latest version of bmake_ to run in `meta mode`_
+see `dirdeps.mk`_
+.. _`dirdeps.mk`: /help/sjg/dirdeps.htm
.. _`meta mode`: bmake-meta-mode.htm
Install
@@ -463,5 +477,5 @@ where you unpacked the tar file, you can::
.. _mk.tar.gz: http://www.crufty.net/ftp/pub/sjg/mk.tar.gz
:Author: sjg@crufty.net
-:Revision: $Id: mk-files.txt,v 1.15 2011/06/08 07:06:18 sjg Exp $
+:Revision: $Id: mk-files.txt,v 1.16 2014/09/05 04:41:16 sjg Exp $
:Copyright: Crufty.NET
diff --git a/contrib/bmake/mk/mkopt.sh b/contrib/bmake/mk/mkopt.sh
new file mode 100755
index 0000000..38b624e
--- /dev/null
+++ b/contrib/bmake/mk/mkopt.sh
@@ -0,0 +1,94 @@
+:
+# $Id: mkopt.sh,v 1.8 2014/11/15 07:07:18 sjg Exp $
+#
+# @(#) Copyright (c) 2014, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+# handle WITH[OUT]_* options in a manner compatible with
+# options.mk and bsd.mkopt.mk in recent FreeBSD
+
+# no need to be included more than once
+_MKOPT_SH=:
+
+#
+# _mk_opt OPT default
+#
+# Set MK_$OPT
+#
+# The semantics are simple, if MK_$OPT has no value
+# WITHOUT_$OPT results in MK_$OPT=no
+# otherwise WITH_$OPT results in MK_$OPT=yes.
+# Note WITHOUT_$OPT overrides WITH_$OPT.
+#
+# For backwards compatability reasons we treat WITH_$OPT=no
+# the same as WITHOUT_$OPT.
+#
+_mk_opt() {
+ _d=$1
+ _mo=MK_$2 _wo=WITHOUT_$2 _wi=WITH_$2
+ eval "_mov=\$$_mo _wov=\$$_wo _wiv=\$$_wi"
+
+ case "$_wiv" in
+ no) _wov=no;;
+ esac
+ _v=${_mov:-${_wov:+no}}
+ _v=${_v:-${_wiv:+yes}}
+ _v=${_v:-$_d}
+ _opt_list="$_opt_list $_mo"
+ case "$_v" in
+ yes|no) ;; # sane
+ 0|[NnFf]*) _v=no;; # they mean no
+ 1|[YyTt]*) _v=yes;; # they mean yes
+ *) _v=$_d;; # ignore bogus value
+ esac
+ eval "$_mo=$_v"
+}
+
+#
+# _mk_opts default opt ... [default [opt] ...]
+#
+# see _mk_opts_defaults for example
+#
+_mk_opts() {
+ _d=no
+ for _o in "$@"
+ do
+ case "$_o" in
+ yes|no) _d=$_o; continue;;
+ esac
+ _mk_opt $_d $_o
+ done
+}
+
+_mk_opts_defaults() {
+ _mk_opts no $__DEFAULT_NO_OPTIONS yes $__DEFAULT_YES_OPTIONS
+}
+
+case "/$0" in
+*/mkopt*)
+ _list=no
+ while :
+ do
+ case "$1" in
+ *=*) eval "$1"; shift;;
+ --no|no) _list="$_list no"; shift;;
+ --yes|yes) _list="$_list yes"; shift;;
+ -DWITH*) eval "${1#-D}=1"; shift;;
+ [A-Z]*) _list="$_list $1"; shift;;
+ *) break;;
+ esac
+ done
+ _mk_opts $_list
+ ;;
+esac
+
diff --git a/contrib/bmake/mk/own.mk b/contrib/bmake/mk/own.mk
index e29ff9e..f090bbe 100644
--- a/contrib/bmake/mk/own.mk
+++ b/contrib/bmake/mk/own.mk
@@ -1,4 +1,4 @@
-# $Id: own.mk,v 1.27 2013/07/18 05:46:24 sjg Exp $
+# $Id: own.mk,v 1.28 2015/04/16 16:59:00 sjg Exp $
.if !target(__${.PARSEFILE}__)
__${.PARSEFILE}__:
@@ -89,6 +89,7 @@ OPTIONS_DEFAULT_NO+= DPADD_MK
# process options
OPTIONS_DEFAULT_NO+= \
+ AUTO_OBJ \
INSTALL_AS_USER \
GPROF \
LIBTOOL \
@@ -98,7 +99,6 @@ OPTIONS_DEFAULT_NO+= \
OPTIONS_DEFAULT_YES+= \
ARCHIVE \
AUTODEP \
- AUTO_OBJ \
CRYPTO \
DOC \
DPADD_MK \
diff --git a/contrib/bmake/mk/sys.dependfile.mk b/contrib/bmake/mk/sys.dependfile.mk
index 42cec61..e915082 100644
--- a/contrib/bmake/mk/sys.dependfile.mk
+++ b/contrib/bmake/mk/sys.dependfile.mk
@@ -1,4 +1,4 @@
-# $Id: sys.dependfile.mk,v 1.5 2013/03/08 00:59:21 sjg Exp $
+# $Id: sys.dependfile.mk,v 1.6 2014/08/02 18:02:06 sjg Exp $
#
# @(#) Copyright (c) 2012, Simon J. Gerraty
#
@@ -25,6 +25,12 @@
# All depend file names should start with this
.MAKE.DEPENDFILE_PREFIX ?= Makefile.depend
+.if !empty(.MAKE.DEPENDFILE) && \
+ ${.MAKE.DEPENDFILE:M${.MAKE.DEPENDFILE_PREFIX}*} == ""
+# let us do our thing below...
+.undef .MAKE.DEPENDFILE
+.endif
+
# The order of preference: we will use the first one of these we find.
# It usually makes sense to order from most specific to least.
.MAKE.DEPENDFILE_PREFERENCE ?= \
diff --git a/contrib/bmake/mk/whats.mk b/contrib/bmake/mk/whats.mk
new file mode 100644
index 0000000..d17c3ef
--- /dev/null
+++ b/contrib/bmake/mk/whats.mk
@@ -0,0 +1,63 @@
+# $Id: whats.mk,v 1.1 2014/08/30 22:40:47 sjg Exp $
+#
+# @(#) Copyright (c) 2014, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+.if ${MK_WHATSTRING:Uno} != "no"
+what_build_exts?= o
+# it can be useful to embed a what(1) string in binaries
+# so that the build location can be seen from a core file.
+.if defined(PROG) && ${.MAKE.MAKEFILES:M*prog.mk} != ""
+what_thing?= ${PROGNAME:U${PROG}}
+what_build_thing?= ${PROG}
+.elif defined(LIB) && ${.MAKE.MAKEFILES:M*lib.mk} != ""
+# probably only makes sense for shared libs
+# and the plumbing needed varies depending on *lib.mk
+what_thing?= lib${LIB}
+.if !empty(SOBJS)
+_soe:= ${SOBJS:E:[1]}
+what_build_exts= ${_soe}
+SOBJS+= ${what_uuid}.${_soe}
+.endif
+.elif defined(KMOD) && ${.MAKE.MAKEFILES:M*kmod.mk} != ""
+what_thing?= ${KMOD}
+what_build_thing?= ${KMOD}.ko
+.endif
+
+.if !empty(what_thing)
+# a unique name that won't conflict with anything
+what_uuid = what_${.CURDIR:T:hash}
+
+.if !empty(what_build_thing)
+${what_build_thing}: ${what_build_exts:@e@${what_uuid}.$e@}
+.endif
+OBJS+= ${what_uuid}.o
+CLEANFILES+= ${what_uuid}.c
+
+# we do not need to capture this
+SUPPRESS_DEPEND+= *${what_uuid}.c
+
+SB?= ${SRCTOP:H}
+SB_LOCATION?= ${HOST}:${SB}
+what_location:= ${.OBJDIR:S,${SB},${SB_LOCATION},}
+
+# this works with clang and gcc
+_what_t= const char __attribute__ ((section(".data")))
+_what1:= @(\#)${what_thing:tu} built ${%Y%m%d:L:localtime} by ${USER}
+_what2:= @(\#)${what_location}
+
+${what_uuid}.c:
+ echo '${_what_t} ${what_uuid}1[] = "${_what1}";' > $@ ${.OODATE:MNO_META_CMP}
+ echo '${_what_t} ${what_uuid}2[] = "${_what2}";' >> $@
+.endif
+.endif
diff --git a/contrib/bmake/nonints.h b/contrib/bmake/nonints.h
index c19ba89..b244f0b 100644
--- a/contrib/bmake/nonints.h
+++ b/contrib/bmake/nonints.h
@@ -1,4 +1,4 @@
-/* $NetBSD: nonints.h,v 1.65 2012/08/30 21:17:05 sjg Exp $ */
+/* $NetBSD: nonints.h,v 1.67 2014/09/07 20:55:34 joerg Exp $ */
/*-
* Copyright (c) 1988, 1989, 1990, 1993
diff --git a/contrib/bmake/parse.c b/contrib/bmake/parse.c
index 0f9a8fc..a55582e 100644
--- a/contrib/bmake/parse.c
+++ b/contrib/bmake/parse.c
@@ -1,4 +1,4 @@
-/* $NetBSD: parse.c,v 1.194 2014/02/15 00:17:17 christos Exp $ */
+/* $NetBSD: parse.c,v 1.204 2014/09/18 08:06:13 dholland Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: parse.c,v 1.194 2014/02/15 00:17:17 christos Exp $";
+static char rcsid[] = "$NetBSD: parse.c,v 1.204 2014/09/18 08:06:13 dholland Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: parse.c,v 1.194 2014/02/15 00:17:17 christos Exp $");
+__RCSID("$NetBSD: parse.c,v 1.204 2014/09/18 08:06:13 dholland Exp $");
#endif
#endif /* not lint */
#endif
@@ -1203,7 +1203,17 @@ ParseDoDependency(char *line)
curTargs = Lst_Init(FALSE);
+ /*
+ * First, grind through the targets.
+ */
+
do {
+ /*
+ * Here LINE points to the beginning of the next word, and
+ * LSTART points to the actual beginning of the line.
+ */
+
+ /* Find the end of the next word. */
for (cp = line; *cp && (ParseIsEscaped(lstart, cp) ||
!(isspace((unsigned char)*cp) ||
*cp == '!' || *cp == ':' || *cp == LPAREN));
@@ -1226,6 +1236,10 @@ ParseDoDependency(char *line)
}
}
+ /*
+ * If the word is followed by a left parenthesis, it's the
+ * name of an object file inside an archive (ar file).
+ */
if (!ParseIsEscaped(lstart, cp) && *cp == LPAREN) {
/*
* Archives must be handled specially to make sure the OP_ARCHV
@@ -1242,13 +1256,16 @@ ParseDoDependency(char *line)
"Error in archive specification: \"%s\"", line);
goto out;
} else {
+ /* Done with this word; on to the next. */
continue;
}
}
- savec = *cp;
if (!*cp) {
/*
+ * We got to the end of the line while we were still
+ * looking at targets.
+ *
* Ending a dependency line without an operator is a Bozo
* no-no. As a heuristic, this is also often triggered by
* undetected conflicts from cvs/rcs merges.
@@ -1263,10 +1280,13 @@ ParseDoDependency(char *line)
: "Need an operator");
goto out;
}
+
+ /* Insert a null terminator. */
+ savec = *cp;
*cp = '\0';
/*
- * Have a word in line. See if it's a special target and set
+ * Got the word. See if it's a special target and if so set
* specType to match it.
*/
if (*line == '.' && isupper ((unsigned char)line[1])) {
@@ -1405,6 +1425,8 @@ ParseDoDependency(char *line)
(void)Lst_AtEnd(curTargs, line);
}
+ /* Apply the targets. */
+
while(!Lst_IsEmpty(curTargs)) {
char *targName = (char *)Lst_DeQueue(curTargs);
@@ -1422,7 +1444,9 @@ ParseDoDependency(char *line)
Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
}
+ /* Don't need the inserted null terminator any more. */
*cp = savec;
+
/*
* If it is a special type and not .PATH, it's the only target we
* allow on this line...
@@ -1498,12 +1522,21 @@ ParseDoDependency(char *line)
goto out;
}
- cp++; /* Advance beyond operator */
+ /* Advance beyond the operator */
+ cp++;
+ /*
+ * Apply the operator to the target. This is how we remember which
+ * operator a target was defined with. It fails if the operator
+ * used isn't consistent across all references.
+ */
Lst_ForEach(targets, ParseDoOp, &op);
/*
- * Get to the first source
+ * Onward to the sources.
+ *
+ * LINE will now point to the first source word, if any, or the
+ * end of the string if not.
*/
while (*cp && isspace ((unsigned char)*cp)) {
cp++;
@@ -1962,6 +1995,40 @@ Parse_DoVar(char *line, GNode *ctxt)
}
+/*
+ * ParseMaybeSubMake --
+ * Scan the command string to see if it a possible submake node
+ * Input:
+ * cmd the command to scan
+ * Results:
+ * TRUE if the command is possibly a submake, FALSE if not.
+ */
+static Boolean
+ParseMaybeSubMake(const char *cmd)
+{
+ size_t i;
+ static struct {
+ const char *name;
+ size_t len;
+ } vals[] = {
+#define MKV(A) { A, sizeof(A) - 1 }
+ MKV("${MAKE}"),
+ MKV("${.MAKE}"),
+ MKV("$(MAKE)"),
+ MKV("$(.MAKE)"),
+ MKV("make"),
+ };
+ for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
+ char *ptr;
+ if ((ptr = strstr(cmd, vals[i].name)) == NULL)
+ continue;
+ if ((ptr == cmd || !isalnum((unsigned char)ptr[-1]))
+ && !isalnum((unsigned char)ptr[vals[i].len]))
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*-
* ParseAddCmd --
* Lst_ForEach function to add a command line to all targets
@@ -1974,7 +2041,9 @@ Parse_DoVar(char *line, GNode *ctxt)
* Always 0
*
* Side Effects:
- * A new element is added to the commands list of the node.
+ * A new element is added to the commands list of the node,
+ * and the node can be marked as a submake node if the command is
+ * determined to be that.
*/
static int
ParseAddCmd(void *gnp, void *cmd)
@@ -1988,6 +2057,8 @@ ParseAddCmd(void *gnp, void *cmd)
/* if target already supplied, ignore commands */
if (!(gn->type & OP_HAS_COMMANDS)) {
(void)Lst_AtEnd(gn->commands, cmd);
+ if (ParseMaybeSubMake(cmd))
+ gn->type |= OP_SUBMAKE;
ParseMark(gn);
} else {
#ifdef notyet
diff --git a/contrib/bmake/suff.c b/contrib/bmake/suff.c
index d4f0eb1..c42d2ec 100644
--- a/contrib/bmake/suff.c
+++ b/contrib/bmake/suff.c
@@ -1,4 +1,4 @@
-/* $NetBSD: suff.c,v 1.70 2013/05/18 13:13:34 sjg Exp $ */
+/* $NetBSD: suff.c,v 1.73 2014/09/07 20:55:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: suff.c,v 1.70 2013/05/18 13:13:34 sjg Exp $";
+static char rcsid[] = "$NetBSD: suff.c,v 1.73 2014/09/07 20:55:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
#else
-__RCSID("$NetBSD: suff.c,v 1.70 2013/05/18 13:13:34 sjg Exp $");
+__RCSID("$NetBSD: suff.c,v 1.73 2014/09/07 20:55:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
diff --git a/contrib/bmake/targ.c b/contrib/bmake/targ.c
index d26b845..527206e 100644
--- a/contrib/bmake/targ.c
+++ b/contrib/bmake/targ.c
@@ -1,4 +1,4 @@
-/* $NetBSD: targ.c,v 1.57 2012/06/12 19:21:51 joerg Exp $ */
+/* $NetBSD: targ.c,v 1.59 2014/09/07 20:55:34 joerg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: targ.c,v 1.57 2012/06/12 19:21:51 joerg Exp $";
+static char rcsid[] = "$NetBSD: targ.c,v 1.59 2014/09/07 20:55:34 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: targ.c,v 1.57 2012/06/12 19:21:51 joerg Exp $");
+__RCSID("$NetBSD: targ.c,v 1.59 2014/09/07 20:55:34 joerg Exp $");
#endif
#endif /* not lint */
#endif
diff --git a/contrib/bmake/unit-tests/Makefile.in b/contrib/bmake/unit-tests/Makefile.in
index 3f70f8a..f5f528c 100644
--- a/contrib/bmake/unit-tests/Makefile.in
+++ b/contrib/bmake/unit-tests/Makefile.in
@@ -1,17 +1,18 @@
-# $Id: Makefile.in,v 1.44 2013/08/28 22:09:29 sjg Exp $
+# $Id: Makefile.in,v 1.46 2014/11/06 01:47:57 sjg Exp $
#
-# $NetBSD: Makefile,v 1.38 2013/08/28 21:56:50 sjg Exp $
+# $NetBSD: Makefile,v 1.51 2014/10/20 23:21:11 sjg Exp $
#
# Unit tests for make(1)
# The main targets are:
#
# all: run all the tests
-# test: run 'all', capture output and compare to expected results
+# test: run 'all', and compare to expected results
# accept: move generated output to expected results
#
# Adding a test case.
# Each feature should get its own set of tests in its own suitably
-# named makefile which should be added to SUBFILES to hook it in.
+# named makefile (*.mk), with its own set of expected results (*.exp),
+# and it should be added to the TESTNAMES list.
#
srcdir= @srcdir@
@@ -19,10 +20,11 @@ srcdir= @srcdir@
.MAIN: all
UNIT_TESTS:= ${srcdir}
+.PATH: ${UNIT_TESTS}
-# Simple sub-makefiles - we run them as a black box
-# keep the list sorted.
-SUBFILES= \
+# Each test is in a sub-makefile.
+# Keep the list sorted.
+TESTNAMES= \
comment \
cond1 \
error \
@@ -42,7 +44,6 @@ SUBFILES= \
modts \
modword \
order \
- phony-end \
posix \
qequals \
sunshcmd \
@@ -50,23 +51,36 @@ SUBFILES= \
ternary \
unexport \
unexport-env \
- varcmd
+ varcmd \
+ varmisc \
+ varshell
-all: ${SUBFILES}
+# these tests were broken by referting POSIX chanegs
+STRICT_POSIX_TESTS = \
+ escape \
+ impsrc \
+ phony-end \
+ posix1 \
+ suffixes
+# Override make flags for certain tests
flags.doterror=
flags.order=-j1
-# the tests are actually done with sub-makes.
-.PHONY: ${SUBFILES}
-.PRECIOUS: ${SUBFILES}
-${SUBFILES}:
- -@${.MAKE} ${flags.$@:U-k} -f ${UNIT_TESTS}/$@
+OUTFILES= ${TESTNAMES:S/$/.out/}
-clean:
- rm -f *.out *.fail *.core
+all: ${OUTFILES}
-.-include <obj.mk>
+CLEANFILES += *.rawout *.out *.status *.tmp *.core *.tmp
+CLEANFILES += obj*.[och] lib*.a # posix1.mk
+CLEANFILES += issue* .[ab]* # suffixes.mk
+CLEANRECURSIVE += dir dummy # posix1.mk
+
+clean:
+ rm -f ${CLEANFILES}
+.if !empty(CLEANRECURSIVE)
+ rm -rf ${CLEANRECURSIVE}
+.endif
TEST_MAKE?= ${.MAKE}
TOOL_SED?= sed
@@ -81,22 +95,56 @@ LANG= C
.export LANG LC_ALL
.endif
-# The driver.
+# some tests need extra post-processing
+SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \
+ -e '/command/s,No such.*,not found,'
+
+# the tests are actually done with sub-makes.
+.SUFFIXES: .mk .rawout .out
+.mk.rawout:
+ @echo ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC}
+ -@cd ${.OBJDIR} && \
+ { ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} \
+ 2>&1 ; echo $$? >${.TARGET:R}.status ; } > ${.TARGET}.tmp
+ @mv ${.TARGET}.tmp ${.TARGET}
+
# We always pretend .MAKE was called 'make'
# and strip ${.CURDIR}/ from the output
# and replace anything after 'stopped in' with unit-tests
# so the results can be compared.
-test:
- @echo "${TEST_MAKE} -f ${MAKEFILE} > ${.TARGET}.out 2>&1"
- @cd ${.OBJDIR} && ${TEST_MAKE} -f ${MAKEFILE} 2>&1 | \
- ${TOOL_TR} -d '\015' | \
- ${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[^:]*:,make:,' \
- -e '/stopped/s, /.*, unit-tests,' \
- -e 's,${.CURDIR:C/\./\\\./g}/,,g' \
- -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' > ${.TARGET}.out || { \
- tail ${.TARGET}.out; mv ${.TARGET}.out ${.TARGET}.fail; exit 1; }
- ${TOOL_DIFF} ${DIFF_FLAGS} ${UNIT_TESTS}/${.TARGET}.exp ${.TARGET}.out
+.rawout.out:
+ @echo postprocess ${.TARGET}
+ @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \
+ -e 's,${TEST_MAKE:C/\./\\\./g},make,' \
+ -e '/stopped/s, /.*, unit-tests,' \
+ -e 's,${.CURDIR:C/\./\\\./g}/,,g' \
+ -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \
+ < ${.IMPSRC} > ${.TARGET}.tmp
+ @echo "exit status `cat ${.TARGET:R}.status`" >> ${.TARGET}.tmp
+ @mv ${.TARGET}.tmp ${.TARGET}
+
+# Compare all output files
+test: ${OUTFILES} .PHONY
+ @failed= ; \
+ for test in ${TESTNAMES}; do \
+ ${TOOL_DIFF} -u ${UNIT_TESTS}/$${test}.exp $${test}.out \
+ || failed="$${failed}$${failed:+ }$${test}" ; \
+ done ; \
+ if [ -n "$${failed}" ]; then \
+ echo "Failed tests: $${failed}" ; false ; \
+ else \
+ echo "All tests passed" ; \
+ fi
accept:
- mv test.out ${srcdir}/test.exp
+ @for test in ${TESTNAMES}; do \
+ cmp -s ${UNIT_TESTS}/$${test}.exp $${test}.out \
+ || { echo "Replacing $${test}.exp" ; \
+ cp $${test}.out ${UNIT_TESTS}/$${test}.exp ; } \
+ done
+.if exists(${TEST_MAKE})
+${TESTNAMES:S/$/.rawout/}: ${TEST_MAKE}
+.endif
+
+.-include <obj.mk>
diff --git a/contrib/bmake/unit-tests/comment.exp b/contrib/bmake/unit-tests/comment.exp
new file mode 100644
index 0000000..9a97df0
--- /dev/null
+++ b/contrib/bmake/unit-tests/comment.exp
@@ -0,0 +1,5 @@
+comment testing start
+this is foo
+This is how a comment looks: # comment
+comment testing done
+exit status 0
diff --git a/contrib/bmake/unit-tests/comment b/contrib/bmake/unit-tests/comment.mk
index 7dd7dbb..7dd7dbb 100644
--- a/contrib/bmake/unit-tests/comment
+++ b/contrib/bmake/unit-tests/comment.mk
diff --git a/contrib/bmake/unit-tests/cond1.exp b/contrib/bmake/unit-tests/cond1.exp
new file mode 100644
index 0000000..701d504
--- /dev/null
+++ b/contrib/bmake/unit-tests/cond1.exp
@@ -0,0 +1,23 @@
+make: "cond1.mk" line 75: warning: extra else
+make: "cond1.mk" line 85: warning: extra else
+2 is prime
+A='other' B='unknown' C='clever' o='no,no'
+Passed:
+ var
+ ("var")
+ (var != var)
+ var != var
+ !((var != var) && defined(name))
+ var == quoted
+
+1 is not prime
+2 is prime
+3 is prime
+4 is not prime
+5 is prime
+
+make: warning: String comparison operator should be either == or !=
+make: Bad conditional expression `"0" > 0' in "0" > 0?OK:No
+
+OK
+exit status 0
diff --git a/contrib/bmake/unit-tests/cond1 b/contrib/bmake/unit-tests/cond1.mk
index c877c3d..2fc2c7c 100644
--- a/contrib/bmake/unit-tests/cond1
+++ b/contrib/bmake/unit-tests/cond1.mk
@@ -1,4 +1,4 @@
-# $Id: cond1,v 1.1.1.3 2011/03/06 00:04:58 sjg Exp $
+# $Id: cond1.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
# hard code these!
TEST_UNAME_S= NetBSD
diff --git a/contrib/bmake/unit-tests/doterror.exp b/contrib/bmake/unit-tests/doterror.exp
new file mode 100644
index 0000000..0447a51
--- /dev/null
+++ b/contrib/bmake/unit-tests/doterror.exp
@@ -0,0 +1,9 @@
+At first, I am
+happy
+and now: sad
+.ERROR: Looks like 'sad' is upset.
+*** Error code 1
+
+Stop.
+make: stopped in unit-tests
+exit status 1
diff --git a/contrib/bmake/unit-tests/doterror b/contrib/bmake/unit-tests/doterror.mk
index 75d8920..9030dce 100644
--- a/contrib/bmake/unit-tests/doterror
+++ b/contrib/bmake/unit-tests/doterror.mk
@@ -1,4 +1,4 @@
-# $Id: doterror,v 1.1.1.1 2010/04/08 17:43:00 sjg Exp $
+# $Id: doterror.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
.BEGIN:
diff --git a/contrib/bmake/unit-tests/dotwait.exp b/contrib/bmake/unit-tests/dotwait.exp
new file mode 100644
index 0000000..6bf96e3
--- /dev/null
+++ b/contrib/bmake/unit-tests/dotwait.exp
@@ -0,0 +1,30 @@
+simple.1
+simple.1
+simple.2
+simple.2
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.1.*
+recursive.1.99
+recursive.1.99
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.1.*
+recursive.2.99
+recursive.2.99
+shared.0
+shared.0
+shared.1.99
+shared.1.99
+shared.2.1
+shared.2.1
+shared.2.99
+shared.2.99
+make: Graph cycles through `cycle.2.99'
+make: Graph cycles through `cycle.2.98'
+make: Graph cycles through `cycle.2.97'
+cycle.1.99
+cycle.1.99
+exit status 0
diff --git a/contrib/bmake/unit-tests/dotwait b/contrib/bmake/unit-tests/dotwait.mk
index 43706af..9bdaaba 100644
--- a/contrib/bmake/unit-tests/dotwait
+++ b/contrib/bmake/unit-tests/dotwait.mk
@@ -1,4 +1,4 @@
-# $NetBSD: dotwait,v 1.1 2006/02/26 22:45:46 apb Exp $
+# $NetBSD: dotwait.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
THISMAKEFILE:= ${.PARSEDIR}/${.PARSEFILE}
diff --git a/contrib/bmake/unit-tests/error.exp b/contrib/bmake/unit-tests/error.exp
new file mode 100644
index 0000000..a2bf71b
--- /dev/null
+++ b/contrib/bmake/unit-tests/error.exp
@@ -0,0 +1,4 @@
+make: "error.mk" line 3: just FYI
+make: "error.mk" line 4: warning: this could be serious
+make: "error.mk" line 5: this is fatal
+exit status 1
diff --git a/contrib/bmake/unit-tests/error b/contrib/bmake/unit-tests/error.mk
index c0a1403..c6b553e 100644
--- a/contrib/bmake/unit-tests/error
+++ b/contrib/bmake/unit-tests/error.mk
@@ -1,4 +1,4 @@
-# $Id: error,v 1.1.1.2 2010/05/24 23:36:03 sjg Exp $
+# $Id: error.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
.info just FYI
.warning this could be serious
diff --git a/contrib/bmake/unit-tests/escape.exp b/contrib/bmake/unit-tests/escape.exp
new file mode 100644
index 0000000..6238e27
--- /dev/null
+++ b/contrib/bmake/unit-tests/escape.exp
@@ -0,0 +1,104 @@
+var-1bs
+printf "%s=:%s:\n" VAR1BS 111\\111; printf "%s=:%s:\n" VAR1BSa 111\\aaa; printf "%s=:%s:\n" VAR1BSA 111\\aaa; printf "%s=:%s:\n" VAR1BSda 111\\\$\{a\}; printf "%s=:%s:\n" VAR1BSdA 111\\\$\{A\}; printf "%s=:%s:\n" VAR1BSc 111\#\ backslash\ escapes\ comment\ char,\ so\ this\ is\ part\ of\ the\ value; printf "%s=:%s:\n" VAR1BSsc 111\\\ ;
+VAR1BS=:111\111:
+VAR1BSa=:111\aaa:
+VAR1BSA=:111\aaa:
+VAR1BSda=:111\${a}:
+VAR1BSdA=:111\${A}:
+VAR1BSc=:111# backslash escapes comment char, so this is part of the value:
+VAR1BSsc=:111\ :
+var-2bs
+printf "%s=:%s:\n" VAR2BS 222\\\\222; printf "%s=:%s:\n" VAR2BSa 222\\\\aaa; printf "%s=:%s:\n" VAR2BSA 222\\\\aaa; printf "%s=:%s:\n" VAR2BSda 222\\\\\$\{a\}; printf "%s=:%s:\n" VAR2BSdA 222\\\\\$\{A\}; printf "%s=:%s:\n" VAR2BSc 222\\\\; printf "%s=:%s:\n" VAR2BSsc 222\\\\;
+VAR2BS=:222\\222:
+VAR2BSa=:222\\aaa:
+VAR2BSA=:222\\aaa:
+VAR2BSda=:222\\${a}:
+VAR2BSdA=:222\\${A}:
+VAR2BSc=:222\\:
+VAR2BSsc=:222\\:
+var-1bsnl
+printf "%s=:%s:\n" VAR1BSNL 111\ 111; printf "%s=:%s:\n" VAR1BSNLa 111\ aaa; printf "%s=:%s:\n" VAR1BSNLA 111\ aaa; printf "%s=:%s:\n" VAR1BSNLda 111\ \$\{a\}; printf "%s=:%s:\n" VAR1BSNLdA 111\ \$\{A\}; printf "%s=:%s:\n" VAR1BSNLc 111; printf "%s=:%s:\n" VAR1BSNLsc 111;
+VAR1BSNL=:111 111:
+VAR1BSNLa=:111 aaa:
+VAR1BSNLA=:111 aaa:
+VAR1BSNLda=:111 ${a}:
+VAR1BSNLdA=:111 ${A}:
+VAR1BSNLc=:111:
+VAR1BSNLsc=:111:
+var-2bsnl
+printf "%s=:%s:\n" VAR2BSNL 222\\\\; printf "%s=:%s:\n" VAR2BSNLa 222\\\\; printf "%s=:%s:\n" VAR2BSNLA 222\\\\; printf "%s=:%s:\n" VAR2BSNLda 222\\\\; printf "%s=:%s:\n" VAR2BSNLdA 222\\\\; printf "%s=:%s:\n" VAR2BSNLc 222\\\\; printf "%s=:%s:\n" VAR2BSNLsc 222\\\\;
+VAR2BSNL=:222\\:
+VAR2BSNLa=:222\\:
+VAR2BSNLA=:222\\:
+VAR2BSNLda=:222\\:
+VAR2BSNLdA=:222\\:
+VAR2BSNLc=:222\\:
+VAR2BSNLsc=:222\\:
+var-3bsnl
+printf "%s=:%s:\n" VAR3BSNL 333\\\\\ 333=; printf "%s=:%s:\n" VAR3BSNLa 333\\\\\ aaa=; printf "%s=:%s:\n" VAR3BSNLA 333\\\\\ aaa=; printf "%s=:%s:\n" VAR3BSNLda 333\\\\\ \$\{a\}=; printf "%s=:%s:\n" VAR3BSNLdA 333\\\\\ \$\{A\}=; printf "%s=:%s:\n" VAR3BSNLc 333\\\\; printf "%s=:%s:\n" VAR3BSNLsc 333\\\\;
+VAR3BSNL=:333\\ 333=:
+VAR3BSNLa=:333\\ aaa=:
+VAR3BSNLA=:333\\ aaa=:
+VAR3BSNLda=:333\\ ${a}=:
+VAR3BSNLdA=:333\\ ${A}=:
+VAR3BSNLc=:333\\:
+VAR3BSNLsc=:333\\:
+var-1bsnl-space
+printf "%s=:%s:\n" VAR1BSNL00 first\ line; printf "%s=:%s:\n" VAR1BSNL0 first\ line\ no\ space\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLs first\ line\ one\ space\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLss first\ line\ two\ spaces\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLt first\ line\ one\ tab\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLtt first\ line\ two\ tabs\ on\ second\ line; printf "%s=:%s:\n" VAR1BSNLxx first\ line\ many\ spaces\ and\ tabs\ \[\ \ \ \ \]\ on\ second\ line;
+VAR1BSNL00=:first line:
+VAR1BSNL0=:first line no space on second line:
+VAR1BSNLs=:first line one space on second line:
+VAR1BSNLss=:first line two spaces on second line:
+VAR1BSNLt=:first line one tab on second line:
+VAR1BSNLtt=:first line two tabs on second line:
+VAR1BSNLxx=:first line many spaces and tabs [ ] on second line:
+cmd-1bsnl
+echo :'first line\
+#second line without space\
+third line':
+:first line\
+#second line without space\
+third line:
+echo :'first line\
+ second line spaces should be retained':
+:first line\
+ second line spaces should be retained:
+echo :'first line\
+second line tab should be elided':
+:first line\
+second line tab should be elided:
+echo :'first line\
+ only one tab should be elided, second tab remains'
+:first line\
+ only one tab should be elided, second tab remains
+cmd-1bsnl-eof
+echo :'command ending with backslash-newline'; \
+
+:command ending with backslash-newline
+cmd-2bsnl
+echo take one\\
+take one\
+echo take two\\
+take two\
+echo take three\\
+take three\
+cmd-3bsnl
+echo :'first line\\\
+#second line without space\\\
+third line':
+:first line\\\
+#second line without space\\\
+third line:
+echo :'first line\\\
+ second line spaces should be retained':
+:first line\\\
+ second line spaces should be retained:
+echo :'first line\\\
+second line tab should be elided':
+:first line\\\
+second line tab should be elided:
+echo :'first line\\\
+ only one tab should be elided, second tab remains'
+:first line\\\
+ only one tab should be elided, second tab remains
+exit status 0
diff --git a/contrib/bmake/unit-tests/escape.mk b/contrib/bmake/unit-tests/escape.mk
new file mode 100644
index 0000000..bb37c92
--- /dev/null
+++ b/contrib/bmake/unit-tests/escape.mk
@@ -0,0 +1,246 @@
+# $Id: escape.mk,v 1.1.1.2 2014/11/06 01:40:37 sjg Exp $
+#
+# Test backslash escaping.
+
+# Extracts from the POSIX 2008 specification
+# <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html>:
+#
+# Comments start with a <number-sign> ( '#' ) and continue until an
+# unescaped <newline> is reached.
+#
+# When an escaped <newline> (one preceded by a <backslash>) is found
+# anywhere in the makefile except in a command line, an include
+# line, or a line immediately preceding an include line, it shall
+# be replaced, along with any leading white space on the following
+# line, with a single <space>.
+#
+# When an escaped <newline> is found in a command line in a
+# makefile, the command line shall contain the <backslash>, the
+# <newline>, and the next line, except that the first character of
+# the next line shall not be included if it is a <tab>.
+#
+# When an escaped <newline> is found in an include line or in a
+# line immediately preceding an include line, the behavior is
+# unspecified.
+#
+# Notice that the behaviour of <backslash><backslash> or
+# <backslash><anything other than newline> is not mentioned. I think
+# this implies that <backslash> should be taken literally everywhere
+# except before <newline>.
+#
+# Our practice, despite what POSIX might say, is that "\#"
+# in a variable assignment stores "#" as part of the value.
+# The "\" is not taken literally, and the "#" does not begin a comment.
+#
+# Also, our practice is that an even number of backslashes before a
+# newline in a variable assignment simply stores the backslashes as part
+# of the value, and treats the newline as though it was not escaped.
+# Similarly, ann even number of backslashes before a newline in a
+# command simply uses the backslashes as part of the command test, but
+# does not escape the newline. This is compatible with GNU make.
+
+all: .PHONY
+# We will add dependencies like "all: yet-another-test" later.
+
+# Some variables to be expanded in tests
+#
+a = aaa
+A = ${a}
+
+# Backslash at end of line in a comment\
+should continue the comment. \
+# This is also tested in comment.mk.
+
+__printvars: .USE .MADE
+ @echo ${.TARGET}
+ ${.ALLSRC:@v@ printf "%s=:%s:\n" ${v:Q} ${${v}:Q}; @}
+
+# Embedded backslash in variable should be taken literally.
+#
+VAR1BS = 111\111
+VAR1BSa = 111\${a}
+VAR1BSA = 111\${A}
+VAR1BSda = 111\$${a}
+VAR1BSdA = 111\$${A}
+VAR1BSc = 111\# backslash escapes comment char, so this is part of the value
+VAR1BSsc = 111\ # This is a comment. Value ends with <backslash><space>
+
+all: var-1bs
+var-1bs: .PHONY __printvars VAR1BS VAR1BSa VAR1BSA VAR1BSda VAR1BSdA \
+ VAR1BSc VAR1BSsc
+
+# Double backslash in variable should be taken as two literal backslashes.
+#
+VAR2BS = 222\\222
+VAR2BSa = 222\\${a}
+VAR2BSA = 222\\${A}
+VAR2BSda = 222\\$${a}
+VAR2BSdA = 222\\$${A}
+VAR2BSc = 222\\# backslash does not escape comment char, so this is a comment
+VAR2BSsc = 222\\ # This is a comment. Value ends with <backslash><backslash>
+
+all: var-2bs
+var-2bs: .PHONY __printvars VAR2BS VAR2BSa VAR2BSA VAR2BSda VAR2BSdA \
+ VAR2BSc VAR2BSsc
+
+# Backslash-newline in a variable setting is replaced by a single space.
+#
+VAR1BSNL = 111\
+111
+VAR1BSNLa = 111\
+${a}
+VAR1BSNLA = 111\
+${A}
+VAR1BSNLda = 111\
+$${a}
+VAR1BSNLdA = 111\
+$${A}
+VAR1BSNLc = 111\
+# this should be processed as a comment
+VAR1BSNLsc = 111\
+ # this should be processed as a comment
+
+all: var-1bsnl
+var-1bsnl: .PHONY
+var-1bsnl: .PHONY __printvars \
+ VAR1BSNL VAR1BSNLa VAR1BSNLA VAR1BSNLda VAR1BSNLdA \
+ VAR1BSNLc VAR1BSNLsc
+
+# Double-backslash-newline in a variable setting.
+# Both backslashes should be taken literally, and the newline is NOT escaped.
+#
+# The second lines below each end with '=' so that they will not
+# generate syntax errors regardless of whether or not they are
+# treated as part of the value.
+#
+VAR2BSNL = 222\\
+222=
+VAR2BSNLa = 222\\
+${a}=
+VAR2BSNLA = 222\\
+${A}=
+VAR2BSNLda = 222\\
+$${a}=
+VAR2BSNLdA = 222\\
+$${A}=
+VAR2BSNLc = 222\\
+# this should be processed as a comment
+VAR2BSNLsc = 222\\
+ # this should be processed as a comment
+
+all: var-2bsnl
+var-2bsnl: .PHONY __printvars \
+ VAR2BSNL VAR2BSNLa VAR2BSNLA VAR2BSNLda VAR2BSNLdA \
+ VAR2BSNLc VAR2BSNLsc
+
+# Triple-backslash-newline in a variable setting.
+# First two should be taken literally, and last should escape the newline.
+#
+# The second lines below each end with '=' so that they will not
+# generate syntax errors regardless of whether or not they are
+# treated as part of the value.
+#
+VAR3BSNL = 333\\\
+333=
+VAR3BSNLa = 333\\\
+${a}=
+VAR3BSNLA = 333\\\
+${A}=
+VAR3BSNLda = 333\\\
+$${a}=
+VAR3BSNLdA = 333\\\
+$${A}=
+VAR3BSNLc = 333\\\
+# this should be processed as a comment
+VAR3BSNLsc = 333\\\
+ # this should be processed as a comment
+
+all: var-3bsnl
+var-3bsnl: .PHONY __printvars \
+ VAR3BSNL VAR3BSNLa VAR3BSNLA VAR3BSNLda VAR3BSNLdA \
+ VAR3BSNLc VAR3BSNLsc
+
+# Backslash-newline in a variable setting, plus any amount of white space
+# on the next line, is replaced by a single space.
+#
+VAR1BSNL00= first line\
+
+# above line is entirely empty, and this is a comment
+VAR1BSNL0= first line\
+no space on second line
+VAR1BSNLs= first line\
+ one space on second line
+VAR1BSNLss= first line\
+ two spaces on second line
+VAR1BSNLt= first line\
+ one tab on second line
+VAR1BSNLtt= first line\
+ two tabs on second line
+VAR1BSNLxx= first line\
+ many spaces and tabs [ ] on second line
+
+all: var-1bsnl-space
+var-1bsnl-space: .PHONY __printvars \
+ VAR1BSNL00 VAR1BSNL0 VAR1BSNLs VAR1BSNLss VAR1BSNLt VAR1BSNLtt \
+ VAR1BSNLxx
+
+# Backslash-newline in a command is retained.
+#
+# The "#" in "# second line without space" makes it a comment instead
+# of a syntax error if the preceding line is parsed incorretly.
+# The ":" in "third line':" makes it look like the start of a
+# target instead of a syntax error if the first line is parsed incorrectly.
+#
+all: cmd-1bsnl
+cmd-1bsnl: .PHONY
+ @echo ${.TARGET}
+ echo :'first line\
+#second line without space\
+third line':
+ echo :'first line\
+ second line spaces should be retained':
+ echo :'first line\
+ second line tab should be elided':
+ echo :'first line\
+ only one tab should be elided, second tab remains'
+
+# When backslash-newline appears at the end of a command script,
+# both the backslash and the newline should be passed to the shell.
+# The shell should elide the backslash-newline.
+#
+all: cmd-1bsnl-eof
+cmd-1bsnl-eof:
+ @echo ${.TARGET}
+ echo :'command ending with backslash-newline'; \
+
+# above line must be blank
+
+# Double-backslash-newline in a command.
+# Both backslashes are retained, but the newline is not escaped.
+# XXX: This may differ from POSIX, but matches gmake.
+#
+# When make passes two backslashes to the shell, the shell will pass one
+# backslash to the echo commant.
+#
+all: cmd-2bsnl
+cmd-2bsnl: .PHONY
+ @echo ${.TARGET}
+ echo take one\\
+# this should be a comment
+ echo take two\\
+ echo take three\\
+
+# Triple-backslash-newline in a command is retained.
+#
+all: cmd-3bsnl
+cmd-3bsnl: .PHONY
+ @echo ${.TARGET}
+ echo :'first line\\\
+#second line without space\\\
+third line':
+ echo :'first line\\\
+ second line spaces should be retained':
+ echo :'first line\\\
+ second line tab should be elided':
+ echo :'first line\\\
+ only one tab should be elided, second tab remains'
diff --git a/contrib/bmake/unit-tests/export-all.exp b/contrib/bmake/unit-tests/export-all.exp
new file mode 100644
index 0000000..e3aefd4
--- /dev/null
+++ b/contrib/bmake/unit-tests/export-all.exp
@@ -0,0 +1,12 @@
+UT_ALL=even this gets exported
+UT_BADDIR=unit-tests
+UT_DOLLAR=This is $UT_FU
+UT_F=fine
+UT_FOO=foobar is fubar
+UT_FU=fubar
+UT_NO=all
+UT_OK=good
+UT_OKDIR=unit-tests
+UT_TEST=export-all
+UT_ZOO=hoopie
+exit status 0
diff --git a/contrib/bmake/unit-tests/export-all b/contrib/bmake/unit-tests/export-all.mk
index a243fe3..200412f 100644
--- a/contrib/bmake/unit-tests/export-all
+++ b/contrib/bmake/unit-tests/export-all.mk
@@ -1,4 +1,4 @@
-# $Id: export-all,v 1.1.1.2 2010/04/21 04:26:14 sjg Exp $
+# $Id: export-all.mk,v 1.1.1.2 2015/04/10 20:43:38 sjg Exp $
UT_OK=good
UT_F=fine
@@ -17,7 +17,7 @@ UT_OKDIR = ${${here}/../${here:T}:L:${M_tA}:T}
.export
-.include "export"
+.include "export.mk"
UT_TEST=export-all
UT_ALL=even this gets exported
diff --git a/contrib/bmake/unit-tests/export-env.exp b/contrib/bmake/unit-tests/export-env.exp
new file mode 100644
index 0000000..6221232
--- /dev/null
+++ b/contrib/bmake/unit-tests/export-env.exp
@@ -0,0 +1,9 @@
+make:
+UT_TEST=export-env.mk
+UT_ENV=not-exported
+UT_EXP=not-exported
+env:
+UT_TEST=export-env.mk
+UT_ENV=exported
+UT_EXP=exported
+exit status 0
diff --git a/contrib/bmake/unit-tests/export-env b/contrib/bmake/unit-tests/export-env.mk
index b6ce6a2..6b7cd4c 100644
--- a/contrib/bmake/unit-tests/export-env
+++ b/contrib/bmake/unit-tests/export-env.mk
@@ -1,4 +1,4 @@
-# $Id: export-env,v 1.1.1.1 2013/03/23 02:26:59 sjg Exp $
+# $Id: export-env.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
# our normal .export, subsequent changes affect the environment
UT_TEST=this
diff --git a/contrib/bmake/unit-tests/export.exp b/contrib/bmake/unit-tests/export.exp
new file mode 100644
index 0000000..143771c
--- /dev/null
+++ b/contrib/bmake/unit-tests/export.exp
@@ -0,0 +1,6 @@
+UT_DOLLAR=This is $UT_FU
+UT_FOO=foobar is fubar
+UT_FU=fubar
+UT_TEST=export
+UT_ZOO=hoopie
+exit status 0
diff --git a/contrib/bmake/unit-tests/export b/contrib/bmake/unit-tests/export.mk
index 3e2ad95..01f69f9 100644
--- a/contrib/bmake/unit-tests/export
+++ b/contrib/bmake/unit-tests/export.mk
@@ -1,4 +1,4 @@
-# $Id: export,v 1.1.1.1 2007/10/08 20:30:12 sjg Exp $
+# $Id: export.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
UT_TEST=export
UT_FOO=foo${BAR}
diff --git a/contrib/bmake/unit-tests/forloop.exp b/contrib/bmake/unit-tests/forloop.exp
new file mode 100644
index 0000000..df14b75
--- /dev/null
+++ b/contrib/bmake/unit-tests/forloop.exp
@@ -0,0 +1,19 @@
+x=one
+x="two and three"
+x=four
+x="five"
+x=-I/this
+x=-I"This or that"
+x=-Ithat
+x="-DTHIS=\"this and that\""
+cfl=-I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
+a=one b="two and three"
+a=four b="five"
+a=ONE b="TWO AND THREE"
+a=FOUR b="FIVE"
+We expect an error next:
+make: "forloop.mk" line 38: Wrong number of words (9) in .for substitution list with 2 vars
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
+OK
+exit status 0
diff --git a/contrib/bmake/unit-tests/forloop b/contrib/bmake/unit-tests/forloop.mk
index 0b50e66..9aad7c6 100644
--- a/contrib/bmake/unit-tests/forloop
+++ b/contrib/bmake/unit-tests/forloop.mk
@@ -1,4 +1,4 @@
-# $Id: forloop,v 1.1.1.1 2012/06/19 23:30:49 sjg Exp $
+# $Id: forloop.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
all: for-loop
diff --git a/contrib/bmake/unit-tests/forsubst.exp b/contrib/bmake/unit-tests/forsubst.exp
new file mode 100644
index 0000000..0a98c00
--- /dev/null
+++ b/contrib/bmake/unit-tests/forsubst.exp
@@ -0,0 +1,2 @@
+.for with :S;... OK
+exit status 0
diff --git a/contrib/bmake/unit-tests/forsubst b/contrib/bmake/unit-tests/forsubst.mk
index d3a7de1..2923e4b 100644
--- a/contrib/bmake/unit-tests/forsubst
+++ b/contrib/bmake/unit-tests/forsubst.mk
@@ -1,4 +1,4 @@
-# $Id: forsubst,v 1.1.1.1 2009/10/07 18:53:35 sjg Exp $
+# $Id: forsubst.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
all: for-subst
diff --git a/contrib/bmake/unit-tests/hash.exp b/contrib/bmake/unit-tests/hash.exp
new file mode 100644
index 0000000..0a24234
--- /dev/null
+++ b/contrib/bmake/unit-tests/hash.exp
@@ -0,0 +1,9 @@
+b2af338b
+3360ac65
+7747f046
+9ca87054
+880fe816
+208fcbd3
+d5d376eb
+de41416c
+exit status 0
diff --git a/contrib/bmake/unit-tests/hash b/contrib/bmake/unit-tests/hash.mk
index 1ed84e7..1ed84e7 100644
--- a/contrib/bmake/unit-tests/hash
+++ b/contrib/bmake/unit-tests/hash.mk
diff --git a/contrib/bmake/unit-tests/impsrc.exp b/contrib/bmake/unit-tests/impsrc.exp
new file mode 100644
index 0000000..23e8347
--- /dev/null
+++ b/contrib/bmake/unit-tests/impsrc.exp
@@ -0,0 +1,13 @@
+expected: source4
+actual: source4
+expected: target1.x
+actual: target1.x
+expected: target1.y
+actual: target1.y
+expected: source1
+actual: source1
+expected: source2
+actual: source2
+expected: source1
+actual: source1
+exit status 0
diff --git a/contrib/bmake/unit-tests/impsrc.mk b/contrib/bmake/unit-tests/impsrc.mk
new file mode 100644
index 0000000..95ae0c3
--- /dev/null
+++ b/contrib/bmake/unit-tests/impsrc.mk
@@ -0,0 +1,43 @@
+# $NetBSD: impsrc.mk,v 1.2 2014/08/30 22:21:07 sjg Exp $
+
+# Does ${.IMPSRC} work properly?
+# It should be set, in order of precedence, to ${.TARGET} of:
+# 1) the implied source of a transformation rule,
+# 2) the first prerequisite from the dependency line of an explicit rule, or
+# 3) the first prerequisite of an explicit rule.
+#
+
+all: target1.z target2 target3 target4
+
+.SUFFIXES: .x .y .z
+
+.x.y: source1
+ @echo 'expected: target1.x'
+ @echo 'actual: $<'
+
+.y.z: source2
+ @echo 'expected: target1.y'
+ @echo 'actual: $<'
+
+target1.y: source3
+
+target1.x: source4
+ @echo 'expected: source4'
+ @echo 'actual: $<'
+
+target2: source1 source2
+ @echo 'expected: source1'
+ @echo 'actual: $<'
+
+target3: source1
+target3: source2 source3
+ @echo 'expected: source2'
+ @echo 'actual: $<'
+
+target4: source1
+target4:
+ @echo 'expected: source1'
+ @echo 'actual: $<'
+
+source1 source2 source3 source4:
+
diff --git a/contrib/bmake/unit-tests/misc.exp b/contrib/bmake/unit-tests/misc.exp
new file mode 100644
index 0000000..39a9383
--- /dev/null
+++ b/contrib/bmake/unit-tests/misc.exp
@@ -0,0 +1 @@
+exit status 0
diff --git a/contrib/bmake/unit-tests/misc b/contrib/bmake/unit-tests/misc.mk
index 4ba3655..0301150 100644
--- a/contrib/bmake/unit-tests/misc
+++ b/contrib/bmake/unit-tests/misc.mk
@@ -1,4 +1,4 @@
-# $Id: misc,v 1.1.1.1 2011/03/06 00:04:58 sjg Exp $
+# $Id: misc.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
.if !exists(${.CURDIR}/)
.warning ${.CURDIR}/ doesn't exist ?
diff --git a/contrib/bmake/unit-tests/moderrs.exp b/contrib/bmake/unit-tests/moderrs.exp
new file mode 100644
index 0000000..cb51aa0
--- /dev/null
+++ b/contrib/bmake/unit-tests/moderrs.exp
@@ -0,0 +1,16 @@
+Expect: Unknown modifier 'Z'
+make: Unknown modifier 'Z'
+VAR:Z=
+Expect: Unknown modifier 'Z'
+make: Unknown modifier 'Z'
+VAR:Z=
+Expect: Unclosed variable specification for VAR
+make: Unclosed variable specification (expecting '}') for "VAR" (value "Thevariable") modifier S
+VAR:S,V,v,=Thevariable
+Expect: Unclosed variable specification for VAR
+make: Unclosed variable specification after complex modifier (expecting '}') for VAR
+VAR:S,V,v,=Thevariable
+Expect: Unclosed substitution for VAR (, missing)
+make: Unclosed substitution for VAR (, missing)
+VAR:S,V,v=
+exit status 0
diff --git a/contrib/bmake/unit-tests/moderrs b/contrib/bmake/unit-tests/moderrs.mk
index b8f78ce..d0eb17f 100644
--- a/contrib/bmake/unit-tests/moderrs
+++ b/contrib/bmake/unit-tests/moderrs.mk
@@ -1,4 +1,4 @@
-# $Id: moderrs,v 1.2 2006/05/11 18:53:39 sjg Exp $
+# $Id: moderrs.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
#
# various modifier error tests
diff --git a/contrib/bmake/unit-tests/modmatch.exp b/contrib/bmake/unit-tests/modmatch.exp
new file mode 100644
index 0000000..fcaf6c0
--- /dev/null
+++ b/contrib/bmake/unit-tests/modmatch.exp
@@ -0,0 +1,17 @@
+LIB=a X_LIBS:M${LIB${LIB:tu}} is "/tmp/liba.a"
+LIB=a X_LIBS:M*/lib${LIB}.a is "/tmp/liba.a"
+LIB=a X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBA.A"
+LIB=b X_LIBS:M${LIB${LIB:tu}} is ""
+LIB=b X_LIBS:M*/lib${LIB}.a is ""
+LIB=b X_LIBS:M*/lib${LIB}.a:tu is ""
+LIB=c X_LIBS:M${LIB${LIB:tu}} is ""
+LIB=c X_LIBS:M*/lib${LIB}.a is ""
+LIB=c X_LIBS:M*/lib${LIB}.a:tu is ""
+LIB=d X_LIBS:M${LIB${LIB:tu}} is "/tmp/libd.a"
+LIB=d X_LIBS:M*/lib${LIB}.a is "/tmp/libd.a"
+LIB=d X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBD.A"
+LIB=e X_LIBS:M${LIB${LIB:tu}} is "/tmp/libe.a"
+LIB=e X_LIBS:M*/lib${LIB}.a is "/tmp/libe.a"
+LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
+Mscanner=OK
+exit status 0
diff --git a/contrib/bmake/unit-tests/modmatch b/contrib/bmake/unit-tests/modmatch.mk
index 48a1bef..48a1bef 100644
--- a/contrib/bmake/unit-tests/modmatch
+++ b/contrib/bmake/unit-tests/modmatch.mk
diff --git a/contrib/bmake/unit-tests/modmisc.exp b/contrib/bmake/unit-tests/modmisc.exp
new file mode 100644
index 0000000..e406647
--- /dev/null
+++ b/contrib/bmake/unit-tests/modmisc.exp
@@ -0,0 +1,10 @@
+path=':/bin:/tmp::/:.:/no/such/dir:.'
+path='/bin:/tmp:/:/no/such/dir'
+path='/bin:/tmp:/:/no/such/dir'
+path='/bin':'/tmp':'/':'/no/such/dir'
+path='/bin':'/tmp':'/':'/no/such/dir'
+path_/usr/xbin=/opt/xbin/
+paths=/bin /tmp / /no/such/dir /opt/xbin
+PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN
+The answer is 42
+exit status 0
diff --git a/contrib/bmake/unit-tests/modmisc b/contrib/bmake/unit-tests/modmisc.mk
index d562e46..043498f 100644
--- a/contrib/bmake/unit-tests/modmisc
+++ b/contrib/bmake/unit-tests/modmisc.mk
@@ -1,4 +1,4 @@
-# $Id: modmisc,v 1.1.1.5 2011/04/11 15:10:32 sjg Exp $
+# $Id: modmisc.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
#
# miscellaneous modifier tests
diff --git a/contrib/bmake/unit-tests/modorder.exp b/contrib/bmake/unit-tests/modorder.exp
new file mode 100644
index 0000000..4117427
--- /dev/null
+++ b/contrib/bmake/unit-tests/modorder.exp
@@ -0,0 +1,11 @@
+LIST = one two three four five six seven eight nine ten
+LIST:O = eight five four nine one seven six ten three two
+LIST:Ox = Ok
+LIST:O:Ox = Ok
+LISTX = Ok
+LISTSX = Ok
+make: Bad modifier `:OX' for LIST
+BADMOD 1 = }
+make: Bad modifier `:OxXX' for LIST
+BADMOD 2 = XX}
+exit status 0
diff --git a/contrib/bmake/unit-tests/modorder b/contrib/bmake/unit-tests/modorder.mk
index 68b66fb..bc24d33 100644
--- a/contrib/bmake/unit-tests/modorder
+++ b/contrib/bmake/unit-tests/modorder.mk
@@ -1,4 +1,4 @@
-# $NetBSD: modorder,v 1.2 2007/10/05 15:27:46 sjg Exp $
+# $NetBSD: modorder.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
LIST= one two three four five six seven eight nine ten
LISTX= ${LIST:Ox}
diff --git a/contrib/bmake/unit-tests/modts.exp b/contrib/bmake/unit-tests/modts.exp
new file mode 100644
index 0000000..cf3c91d
--- /dev/null
+++ b/contrib/bmake/unit-tests/modts.exp
@@ -0,0 +1,33 @@
+LIST="one two three four five six"
+LIST:ts,="one,two,three,four,five,six"
+LIST:ts/:tu="ONE/TWO/THREE/FOUR/FIVE/SIX"
+LIST:ts::tu="ONE:TWO:THREE:FOUR:FIVE:SIX"
+LIST:ts:tu="ONETWOTHREEFOURFIVESIX"
+LIST:tu:ts/="ONE/TWO/THREE/FOUR/FIVE/SIX"
+LIST:ts:="one:two:three:four:five:six"
+LIST:ts="onetwothreefourfivesix"
+LIST:ts:S/two/2/="one2threefourfivesix"
+LIST:S/two/2/:ts="one2threefourfivesix"
+LIST:ts/:S/two/2/="one/2/three/four/five/six"
+Pretend the '/' in '/n' etc. below are back-slashes.
+LIST:ts/n="one
+two
+three
+four
+five
+six"
+LIST:ts/t="one two three four five six"
+LIST:ts/012:tu="ONE
+TWO
+THREE
+FOUR
+FIVE
+SIX"
+make: Bad modifier `:tx' for LIST
+LIST:tx="}"
+make: Bad modifier `:ts\x' for LIST
+LIST:ts/x:tu="\x:tu}"
+FU_mod-ts="a/b/cool"
+FU_mod-ts:ts:T="cool" == cool?
+B.${AAA:ts}="Baaa" == Baaa?
+exit status 0
diff --git a/contrib/bmake/unit-tests/modts b/contrib/bmake/unit-tests/modts.mk
index 616bd89..616bd89 100644
--- a/contrib/bmake/unit-tests/modts
+++ b/contrib/bmake/unit-tests/modts.mk
diff --git a/contrib/bmake/unit-tests/modword.exp b/contrib/bmake/unit-tests/modword.exp
new file mode 100644
index 0000000..258d7ea
--- /dev/null
+++ b/contrib/bmake/unit-tests/modword.exp
@@ -0,0 +1,122 @@
+make: Bad modifier `:[]' for LIST
+LIST:[]="" is an error
+LIST:[0]="one two three four five six"
+LIST:[0x0]="one two three four five six"
+LIST:[000]="one two three four five six"
+LIST:[*]="one two three four five six"
+LIST:[@]="one two three four five six"
+LIST:[0]:C/ /,/="one,two three four five six"
+LIST:[0]:C/ /,/g="one,two,three,four,five,six"
+LIST:[0]:C/ /,/1g="one,two,three,four,five,six"
+LIST:[*]:C/ /,/="one,two three four five six"
+LIST:[*]:C/ /,/g="one,two,three,four,five,six"
+LIST:[*]:C/ /,/1g="one,two,three,four,five,six"
+LIST:[@]:C/ /,/="one two three four five six"
+LIST:[@]:C/ /,/g="one two three four five six"
+LIST:[@]:C/ /,/1g="one two three four five six"
+LIST:[@]:[0]:C/ /,/="one,two three four five six"
+LIST:[0]:[@]:C/ /,/="one two three four five six"
+LIST:[@]:[*]:C/ /,/="one,two three four five six"
+LIST:[*]:[@]:C/ /,/="one two three four five six"
+EMPTY=""
+EMPTY:[#]="1" == 1 ?
+ESCAPEDSPACE="\ "
+ESCAPEDSPACE:[#]="1" == 1 ?
+REALLYSPACE=" "
+REALLYSPACE:[#]="1" == 1 ?
+LIST:[#]="6"
+LIST:[0]:[#]="1" == 1 ?
+LIST:[*]:[#]="1" == 1 ?
+LIST:[@]:[#]="6"
+LIST:[1]:[#]="1"
+LIST:[1..3]:[#]="3"
+EMPTY:[1]=""
+ESCAPEDSPACE="\ "
+ESCAPEDSPACE:[1]="\ "
+REALLYSPACE=" "
+REALLYSPACE:[1]="" == "" ?
+REALLYSPACE:[*]:[1]=" " == " " ?
+LIST:[1]="one"
+make: Bad modifier `:[1.]' for LIST
+LIST:[1.]="" is an error
+make: Bad modifier `:[1].' for LIST
+LIST:[1].="}" is an error
+LIST:[2]="two"
+LIST:[6]="six"
+LIST:[7]=""
+LIST:[999]=""
+make: Bad modifier `:[-]' for LIST
+LIST:[-]="" is an error
+make: Bad modifier `:[--]' for LIST
+LIST:[--]="" is an error
+LIST:[-1]="six"
+LIST:[-2]="five"
+LIST:[-6]="one"
+LIST:[-7]=""
+LIST:[-999]=""
+LONGLIST:[17]="17"
+LONGLIST:[0x11]="17"
+LONGLIST:[021]="17"
+LIST:[0]:[1]="one two three four five six"
+LIST:[*]:[1]="one two three four five six"
+LIST:[@]:[1]="one"
+LIST:[0]:[2]=""
+LIST:[*]:[2]=""
+LIST:[@]:[2]="two"
+LIST:[*]:C/ /,/:[2]=""
+LIST:[*]:C/ /,/:[*]:[2]=""
+LIST:[*]:C/ /,/:[@]:[2]="three"
+make: Bad modifier `:[1.]' for LIST
+LIST:[1.]="" is an error
+make: Bad modifier `:[1..]' for LIST
+LIST:[1..]="" is an error
+LIST:[1..1]="one"
+make: Bad modifier `:[1..1.]' for LIST
+LIST:[1..1.]="" is an error
+LIST:[1..2]="one two"
+LIST:[2..1]="two one"
+LIST:[3..-2]="three four five"
+LIST:[-4..4]="three four"
+make: Bad modifier `:[0..1]' for LIST
+LIST:[0..1]="" is an error
+make: Bad modifier `:[-1..0]' for LIST
+LIST:[-1..0]="" is an error
+LIST:[-1..1]="six five four three two one"
+LIST:[0..0]="one two three four five six"
+LIST:[3..99]="three four five six"
+LIST:[-3..-99]="four three two one"
+LIST:[-99..-3]="one two three four"
+HASH="#" == "#" ?
+LIST:[${HASH}]="6"
+LIST:[${ZERO}]="one two three four five six"
+LIST:[${ZERO}x${ONE}]="one"
+LIST:[${ONE}]="one"
+LIST:[${MINUSONE}]="six"
+LIST:[${STAR}]="one two three four five six"
+LIST:[${AT}]="one two three four five six"
+make: Bad modifier `:[${EMPTY' for LIST
+LIST:[${EMPTY}]="" is an error
+LIST:[${LONGLIST:[21]:S/2//}]="one"
+LIST:[${LIST:[#]}]="six"
+LIST:[${LIST:[${HASH}]}]="six"
+LIST:S/ /,/="one two three four five six"
+LIST:S/ /,/W="one,two three four five six"
+LIST:S/ /,/gW="one,two,three,four,five,six"
+EMPTY:S/^/,/=","
+EMPTY:S/^/,/W=","
+LIST:C/ /,/="one two three four five six"
+LIST:C/ /,/W="one,two three four five six"
+LIST:C/ /,/gW="one,two,three,four,five,six"
+EMPTY:C/^/,/=","
+EMPTY:C/^/,/W=","
+LIST:tW="one two three four five six"
+LIST:tw="one two three four five six"
+LIST:tW:C/ /,/="one,two three four five six"
+LIST:tW:C/ /,/g="one,two,three,four,five,six"
+LIST:tW:C/ /,/1g="one,two,three,four,five,six"
+LIST:tw:C/ /,/="one two three four five six"
+LIST:tw:C/ /,/g="one two three four five six"
+LIST:tw:C/ /,/1g="one two three four five six"
+LIST:tw:tW:C/ /,/="one,two three four five six"
+LIST:tW:tw:C/ /,/="one two three four five six"
+exit status 0
diff --git a/contrib/bmake/unit-tests/modword b/contrib/bmake/unit-tests/modword.mk
index 39355d7..1327624 100644
--- a/contrib/bmake/unit-tests/modword
+++ b/contrib/bmake/unit-tests/modword.mk
@@ -1,4 +1,4 @@
-# $Id: modword,v 1.1.1.1 2003/09/28 17:01:48 sjg Exp $
+# $Id: modword.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
#
# Test behaviour of new :[] modifier
diff --git a/contrib/bmake/unit-tests/order.exp b/contrib/bmake/unit-tests/order.exp
new file mode 100644
index 0000000..d876914
--- /dev/null
+++ b/contrib/bmake/unit-tests/order.exp
@@ -0,0 +1,4 @@
+Making the.c
+Making the.h
+Making the.o from the.h the.c
+exit status 0
diff --git a/contrib/bmake/unit-tests/order b/contrib/bmake/unit-tests/order.mk
index 175da47..f90b627 100644
--- a/contrib/bmake/unit-tests/order
+++ b/contrib/bmake/unit-tests/order.mk
@@ -1,4 +1,4 @@
-# $NetBSD: order,v 1.1 2012/11/09 19:08:28 sjg Exp $
+# $NetBSD: order.mk,v 1.1 2014/08/21 13:44:51 apb Exp $
# Test that .ORDER is handled correctly.
# The explicit dependency the.o: the.h will make us examine the.h
diff --git a/contrib/bmake/unit-tests/phony-end.exp b/contrib/bmake/unit-tests/phony-end.exp
new file mode 100644
index 0000000..c3c517c
--- /dev/null
+++ b/contrib/bmake/unit-tests/phony-end.exp
@@ -0,0 +1,6 @@
+.TARGET="phony" .PREFIX="phony" .IMPSRC=""
+.TARGET="all" .PREFIX="all" .IMPSRC="phony"
+.TARGET="ok" .PREFIX="ok" .IMPSRC=""
+.TARGET="also.ok" .PREFIX="also.ok" .IMPSRC=""
+.TARGET="bug" .PREFIX="bug" .IMPSRC=""
+exit status 0
diff --git a/contrib/bmake/unit-tests/phony-end b/contrib/bmake/unit-tests/phony-end.mk
index d61884c..07f4b02 100644
--- a/contrib/bmake/unit-tests/phony-end
+++ b/contrib/bmake/unit-tests/phony-end.mk
@@ -1,4 +1,4 @@
-# $Id: phony-end,v 1.1.1.1 2011/10/01 17:19:39 sjg Exp $
+# $Id: phony-end.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
all ok also.ok bug phony:
@echo '${.TARGET .PREFIX .IMPSRC:L:@v@$v="${$v}"@}'
diff --git a/contrib/bmake/unit-tests/posix.exp b/contrib/bmake/unit-tests/posix.exp
new file mode 100644
index 0000000..7e74cab
--- /dev/null
+++ b/contrib/bmake/unit-tests/posix.exp
@@ -0,0 +1,23 @@
+Posix says we should execute the command as if run by system(3)
+Expect 'Hello,' and 'World!'
+Hello,
+World!
+a command
+a command prefixed by '+' executes even with -n
+another command
+make -n
+echo a command
+echo "a command prefixed by '+' executes even with -n"
+a command prefixed by '+' executes even with -n
+echo another command
+make -n -j1
+{ echo a command
+} || exit $?
+echo "a command prefixed by '+' executes even with -n"
+a command prefixed by '+' executes even with -n
+{ echo another command
+} || exit $?
+Now we expect an error...
+*** Error code 1 (continuing)
+`all' not remade because of errors.
+exit status 0
diff --git a/contrib/bmake/unit-tests/posix b/contrib/bmake/unit-tests/posix.mk
index 48ed7a3..608a24a 100644
--- a/contrib/bmake/unit-tests/posix
+++ b/contrib/bmake/unit-tests/posix.mk
@@ -1,4 +1,4 @@
-# $Id: posix,v 1.1.1.1 2004/05/08 16:45:39 sjg Exp $
+# $Id: posix.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
all: x plus subs err
diff --git a/contrib/bmake/unit-tests/posix1.exp b/contrib/bmake/unit-tests/posix1.exp
new file mode 100644
index 0000000..92809e6
--- /dev/null
+++ b/contrib/bmake/unit-tests/posix1.exp
@@ -0,0 +1,185 @@
+${VAR} = "foo bar baz"
+a
+b
+c
+foo baR baz, bar baz, foo bar baz, fooadd baradd bazadd
+mkdir -p 'dir'
+touch 'dir/obj_1.h'
+mkdir -p 'dir'
+printf '#include "obj_1.h"\nconst char* obj_1 = "dir/obj_1.c";\n' \
+ >'dir/obj_1.c'
+Local variables
+ ${@}="dir/obj_1.o" ${<}="dir/obj_1.c"
+ ${*}="dir/obj_1" ${?}="dir/obj_1.h dir/obj_1.c"
+ ${%}=""
+
+Directory and filename parts of local variables
+ ${@D}="dir" ${@F}="obj_1.o"
+ ${<D}="dir" ${<F}="obj_1.c"
+ ${*D}="dir" ${*F}="obj_1"
+ ${?D}="dir dir" ${?F}="obj_1.h obj_1.c"
+ ${%D}="" ${%F}=""
+
+Local variable substitutions
+ ${@:.o=}="dir/obj_1" ${<:.c=.C}="dir/obj_1.C"
+ ${*:=.h}="dir/obj_1.h" ${?:.h=.H}="dir/obj_1.H dir/obj_1.c"
+ ${%:=}=""
+
+Target with suffix transformations
+ ${@D:=append}="dirappend"
+ ${@F:.o=.O}="obj_1.O"
+
+ Implied source with suffix transformations
+ ${<D:r=rr}="dirr"
+ ${<F:.c=.C}="obj_1.C"
+
+ Suffixless target with suffix transformations
+ ${*D:.=dot}="dir"
+ ${*F:.a=}="obj_1"
+
+ Out-of-date dependencies with suffix transformations
+ ${?D:ir=}="d d"
+ ${?F:.h=.H}="obj_1.H obj_1.c"
+
+ Member with suffix transformations
+ ${%D:.=}=""
+ ${%F:${VAR2}=${VAR}}=""
+
+cc -c -o 'dir/obj_1.o' 'dir/obj_1.c'
+mkdir -p '.'
+touch 'dummy'
+Local variables
+ ${@}="lib.a" ${<}="dir/obj_1.o"
+ ${*}="obj1" ${?}="dir/obj_1.o dummy"
+ ${%}="obj1.o"
+
+Directory and filename parts of local variables
+ ${@D}="." ${@F}="lib.a"
+ ${<D}="dir" ${<F}="obj_1.o"
+ ${*D}="." ${*F}="obj1"
+ ${?D}="dir ." ${?F}="obj_1.o dummy"
+ ${%D}="." ${%F}="obj1.o"
+
+Local variable substitutions
+ ${@:.o=}="lib.a" ${<:.c=.C}="dir/obj_1.o"
+ ${*:=.h}="obj1.h" ${?:.h=.H}="dir/obj_1.o dummy"
+ ${%:=}="obj1.o"
+
+Target with suffix transformations
+ ${@D:=append}=".append"
+ ${@F:.o=.O}="lib.a"
+
+ Implied source with suffix transformations
+ ${<D:r=rr}="dirr"
+ ${<F:.c=.C}="obj_1.o"
+
+ Suffixless target with suffix transformations
+ ${*D:.=dot}="dot"
+ ${*F:.a=}="obj1"
+
+ Out-of-date dependencies with suffix transformations
+ ${?D:ir=}="d ."
+ ${?F:.h=.H}="obj_1.o dummy"
+
+ Member with suffix transformations
+ ${%D:.=}=""
+ ${%F:${VAR2}=${VAR}}="obj1foo bar baz"
+
+cp 'dir/obj_1.o' 'obj1.o'
+ar -rcv 'lib.a' 'obj1.o'
+a - obj1.o
+rm -f 'obj1.o'
+mkdir -p '.'
+printf '#include "obj_2.h"\nconst char* obj_2 = "obj_2.c";\n' \
+ >'obj_2.c'
+mkdir -p '.'
+touch 'obj_2.h'
+Local variables
+ ${@}="obj2.o" ${<}="obj_2.c"
+ ${*}="obj2" ${?}="obj_2.c obj_2.h dir/obj_1.h"
+ ${%}=""
+
+Directory and filename parts of local variables
+ ${@D}="." ${@F}="obj2.o"
+ ${<D}="." ${<F}="obj_2.c"
+ ${*D}="." ${*F}="obj2"
+ ${?D}=". . dir" ${?F}="obj_2.c obj_2.h obj_1.h"
+ ${%D}="" ${%F}=""
+
+Local variable substitutions
+ ${@:.o=}="obj2" ${<:.c=.C}="obj_2.C"
+ ${*:=.h}="obj2.h" ${?:.h=.H}="obj_2.c obj_2.H dir/obj_1.H"
+ ${%:=}=""
+
+Target with suffix transformations
+ ${@D:=append}=".append"
+ ${@F:.o=.O}="obj2.O"
+
+ Implied source with suffix transformations
+ ${<D:r=rr}="."
+ ${<F:.c=.C}="obj_2.C"
+
+ Suffixless target with suffix transformations
+ ${*D:.=dot}="dot"
+ ${*F:.a=}="obj2"
+
+ Out-of-date dependencies with suffix transformations
+ ${?D:ir=}=". . d"
+ ${?F:.h=.H}="obj_2.c obj_2.H obj_1.H"
+
+ Member with suffix transformations
+ ${%D:.=}=""
+ ${%F:${VAR2}=${VAR}}=""
+
+cc -c -o 'obj2.o' 'obj_2.c'
+ar -rcv 'lib.a' 'obj2.o'
+a - obj2.o
+mkdir -p '.'
+touch 'obj3.h'
+mkdir -p 'dir'
+touch 'dir/dummy'
+mkdir -p '.'
+printf '#include "obj3.h"\nconst char* obj3 = "obj3.c";\n' \
+ >'obj3.c'
+Local variables
+ ${@}="lib.a" ${<}="obj3.c"
+ ${*}="obj3" ${?}="obj3.h dir/dummy obj3.c"
+ ${%}="obj3.o"
+
+Directory and filename parts of local variables
+ ${@D}="." ${@F}="lib.a"
+ ${<D}="." ${<F}="obj3.c"
+ ${*D}="." ${*F}="obj3"
+ ${?D}=". dir ." ${?F}="obj3.h dummy obj3.c"
+ ${%D}="." ${%F}="obj3.o"
+
+Local variable substitutions
+ ${@:.o=}="lib.a" ${<:.c=.C}="obj3.C"
+ ${*:=.h}="obj3.h" ${?:.h=.H}="obj3.H dir/dummy obj3.c"
+ ${%:=}="obj3.o"
+
+Target with suffix transformations
+ ${@D:=append}=".append"
+ ${@F:.o=.O}="lib.a"
+
+ Implied source with suffix transformations
+ ${<D:r=rr}="."
+ ${<F:.c=.C}="obj3.C"
+
+ Suffixless target with suffix transformations
+ ${*D:.=dot}="dot"
+ ${*F:.a=}="obj3"
+
+ Out-of-date dependencies with suffix transformations
+ ${?D:ir=}=". d ."
+ ${?F:.h=.H}="obj3.H dummy obj3.c"
+
+ Member with suffix transformations
+ ${%D:.=}=""
+ ${%F:${VAR2}=${VAR}}="obj3foo bar baz"
+
+cc -c -o 'obj3.o' 'obj3.c'
+ar -rcv 'lib.a' 'obj3.o'
+a - obj3.o
+rm -f 'obj3.o'
+exit status 0
diff --git a/contrib/bmake/unit-tests/posix1.mk b/contrib/bmake/unit-tests/posix1.mk
new file mode 100644
index 0000000..50b0a63
--- /dev/null
+++ b/contrib/bmake/unit-tests/posix1.mk
@@ -0,0 +1,184 @@
+# $NetBSD: posix1.mk,v 1.3 2014/08/30 22:21:08 sjg Exp $
+
+# Keep the default suffixes from interfering, just in case.
+.SUFFIXES:
+
+all: line-continuations suffix-substitution localvars
+
+# we need to clean for repeatable results
+.BEGIN: clean
+clean:
+ @rm -f lib.a dir/* dummy obj*
+
+#
+# Line continuations
+#
+
+# Escaped newlines and leading whitespace from the next line are replaced
+# with single space, except in commands, where the escape and the newline
+# are retained, but a single leading tab (if any) from the next line is
+# removed. (PR 49085)
+# Expect:
+# ${VAR} = "foo bar baz"
+# a
+# b
+# c
+VAR = foo\
+\
+ bar\
+ baz
+
+line-continuations:
+ @echo '$${VAR} = "${VAR}"'
+ @echo 'aXbXc' | sed -e 's/X/\
+ /g'
+
+
+#
+# Suffix substitution
+#
+
+# The only variable modifier accepted by POSIX.
+# ${VAR:s1=s2}: replace s1, if found, with s2 at end of each word in
+# ${VAR}. s1 and s2 may contain macro expansions.
+# Expect: foo baR baz, bar baz, foo bar baz, fooadd baradd bazadd
+suffix-substitution:
+ @echo '${VAR:r=R}, ${VAR:foo=}, ${VAR:not_there=wrong}, ${VAR:=add}'
+
+
+#
+# Local variables: regular forms, D/F forms and suffix substitution.
+#
+
+# In the past substitutions did not work with the D/F forms and those
+# forms were not available for $?. (PR 49085)
+
+ARFLAGS = -rcv
+
+localvars: lib.a
+
+# $@ = target or archive name $< = implied source
+# $* = target without suffix $? = sources newer than target
+# $% = archive member name
+LOCALS = \
+ "Local variables\n\
+ \$${@}=\"${@}\" \$${<}=\"${<}\"\n\
+ \$${*}=\"${*}\" \$${?}=\"${?}\"\n\
+ \$${%%}=\"${%}\"\n\n"
+
+# $XD = directory part of X $XF = file part of X
+# X is one of the local variables.
+LOCAL_ALTERNATIVES = \
+ "Directory and filename parts of local variables\n\
+ \$${@D}=\"${@D}\" \$${@F}=\"${@F}\"\n\
+ \$${<D}=\"${<D}\" \$${<F}=\"${<F}\"\n\
+ \$${*D}=\"${*D}\" \$${*F}=\"${*F}\"\n\
+ \$${?D}=\"${?D}\" \$${?F}=\"${?F}\"\n\
+ \$${%%D}=\"${%D}\" \$${%%F}=\"${%F}\"\n\n"
+
+# Do all kinds of meaningless substitutions on local variables to see
+# if they work. Add, remove and replace things.
+VAR2 = .o
+VAR3 = foo
+LOCAL_SUBSTITUTIONS = \
+ "Local variable substitutions\n\
+ \$${@:.o=}=\"${@:.o=}\" \$${<:.c=.C}=\"${<:.c=.C}\"\n\
+ \$${*:=.h}=\"${*:=.h}\" \$${?:.h=.H}=\"${?:.h=.H}\"\n\
+ \$${%%:=}=\"${%:=}\"\n\n"
+
+LOCAL_ALTERNATIVE_SUBSTITUTIONS = \
+ "Target with suffix transformations\n\
+ \$${@D:=append}=\"${@D:=append}\"\n\
+ \$${@F:.o=.O}=\"${@F:.o=.O}\"\n\
+ \n\
+ Implied source with suffix transformations\n\
+ \$${<D:r=rr}=\"${<D:r=rr}\"\n\
+ \$${<F:.c=.C}=\"${<F:.c=.C}\"\n\
+ \n\
+ Suffixless target with suffix transformations\n\
+ \$${*D:.=dot}=\"${*D:.=dot}\"\n\
+ \$${*F:.a=}=\"${*F:.a=}\"\n\
+ \n\
+ Out-of-date dependencies with suffix transformations\n\
+ \$${?D:ir=}=\"${?D:ir=}\"\n\
+ \$${?F:.h=.H}=\"${?F:.h=.H}\"\n\
+ \n\
+ Member with suffix transformations\n\
+ \$${%%D:.=}=\"${%D:.=}\"\n\
+ \$${%%F:\$${VAR2}=\$${VAR}}=\"${%F:${VAR2}=${VAR}}\"\n\n"
+
+.SUFFIXES: .c .o .a
+
+# The system makefiles make the .c.a rule .PRECIOUS with a special source,
+# but such a thing is not POSIX compatible. It's also somewhat useless
+# in a test makefile.
+.c.a:
+ @printf ${LOCALS}
+ @printf ${LOCAL_ALTERNATIVES}
+ @printf ${LOCAL_SUBSTITUTIONS}
+ @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
+ cc -c -o '${%}' '${<}'
+ ar ${ARFLAGS} '${@}' '${%}'
+ rm -f '${%}'
+
+.c.o:
+ @printf ${LOCALS}
+ @printf ${LOCAL_ALTERNATIVES}
+ @printf ${LOCAL_SUBSTITUTIONS}
+ @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
+ cc -c -o '${@}' '${<}'
+
+# Some of these rules are padded with useless extra dependencies just so
+# that ${?} has more than one file.
+
+lib.a: lib.a(obj1.o) lib.a(obj2.o) lib.a(obj3.o)
+ @ar -s '${@}'
+
+# Explicit rule where the dependency is an inferred file. The dependency
+# object's name differs from the member's because there was a bug which
+# forced a dependency on member even when no such dependency was specified
+# (PR 49086).
+lib.a(obj1.o): dir/obj_1.o dummy
+ @printf ${LOCALS}
+ @printf ${LOCAL_ALTERNATIVES}
+ @printf ${LOCAL_SUBSTITUTIONS}
+ @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
+ cp 'dir/obj_1.o' '$%'
+ ar ${ARFLAGS} '${@}' '$%'
+ rm -f '$%'
+
+# Excplicit rule where the dependency also has an explicit rule.
+lib.a(obj2.o): obj2.o
+ ar ${ARFLAGS} '${@}' '${%}'
+
+# Use .c.a inference with an extra dependency.
+lib.a(obj3.o): obj3.h dir/dummy
+
+# Use .c.o inference with an extra dependency.
+dir/obj_1.o: dir/obj_1.h
+
+# According to POSIX, $* is only required for inference rules and $<'s
+# value is unspecified outside of inference rules. Strictly speaking
+# we shouldn't be expanding them here but who cares. At least we get
+# to check that the program does nothing stupid (like crash) with them.
+# The C file is named differently from the object file because there
+# was a bug which forced dependencies based on inference rules on all
+# applicable targets (PR 49086).
+obj2.o: obj_2.c obj_2.h dir/obj_1.h
+ @printf ${LOCALS}
+ @printf ${LOCAL_ALTERNATIVES}
+ @printf ${LOCAL_SUBSTITUTIONS}
+ @printf ${LOCAL_ALTERNATIVE_SUBSTITUTIONS}
+ cc -c -o '${@}' 'obj_2.c'
+
+# Hey, this is make, we can make our own test data setup! obj1.c
+# and obj2.c are not used, so they should not get created. They're here
+# as a bait for a regression into the forced dependencies discussed earlier.
+obj1.c dir/obj_1.c obj2.c obj_2.c obj3.c:
+ mkdir -p '${@D}'
+ printf '#include "${@F:.c=.h}"\nconst char* ${@F:.c=} = "${@}";\n' \
+ >'${@}'
+
+dir/obj_1.h obj_2.h obj3.h dummy dir/dummy:
+ mkdir -p '${@D}'
+ touch '${@}'
diff --git a/contrib/bmake/unit-tests/qequals.exp b/contrib/bmake/unit-tests/qequals.exp
new file mode 100644
index 0000000..6b2f4dc
--- /dev/null
+++ b/contrib/bmake/unit-tests/qequals.exp
@@ -0,0 +1,2 @@
+V.i386 ?= OK
+exit status 0
diff --git a/contrib/bmake/unit-tests/qequals b/contrib/bmake/unit-tests/qequals.mk
index e23078e..67a48ad 100644
--- a/contrib/bmake/unit-tests/qequals
+++ b/contrib/bmake/unit-tests/qequals.mk
@@ -1,4 +1,4 @@
-# $Id: qequals,v 1.1.1.1 2008/03/31 00:13:05 sjg Exp $
+# $Id: qequals.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
M= i386
V.i386= OK
diff --git a/contrib/bmake/unit-tests/suffixes.exp b/contrib/bmake/unit-tests/suffixes.exp
new file mode 100644
index 0000000..2a46e1c
--- /dev/null
+++ b/contrib/bmake/unit-tests/suffixes.exp
@@ -0,0 +1,35 @@
+make: don't know how to make issue3 (continuing)
+There should be no text after the colon:
+touch .a
+There should be no text after the colon:
+touch .a.b
+There should be no text after the colon:
+touch .b.a
+touch issue5a.c
+first set
+cp issue5a.c issue5a.d
+touch issue5b.d
+first set
+cp issue5b.d issue5b.c
+touch issue5c.d
+first set
+cp issue5c.d issue5c
+touch issue5d.d
+first set
+cp issue5d.d issue5d.e
+touch issue5e.e
+first set
+cp issue5e.e issue5e.d
+make: don't know how to make issue6.f (continuing)
+touch issue10.d
+first set
+cp issue10.d issue10.e
+touch issue11.h
+touch issue11.first
+.ALLSRC: issue11.h issue11.first
+cp issue11.h issue11.i
+touch issue11.second
+.ALLSRC: issue11.i issue11.second
+cp issue11.i issue11.j
+`all' not remade because of errors.
+exit status 0
diff --git a/contrib/bmake/unit-tests/suffixes.mk b/contrib/bmake/unit-tests/suffixes.mk
new file mode 100644
index 0000000..113484a
--- /dev/null
+++ b/contrib/bmake/unit-tests/suffixes.mk
@@ -0,0 +1,89 @@
+# $NetBSD: suffixes.mk,v 1.3 2014/08/30 22:21:08 sjg Exp $
+
+# Issues from PR 49086
+
+# Issue 3: single suffix rules remain active after .SUFFIXES is cleared
+#
+# There's a rule for issue3.a, but .a is no longer a known suffix when
+# targets are being made, so issue3 should not get made.
+all: issue3
+
+# Issue 4: suffix rules do not become regular rules when .SUFFIXES is cleared
+#
+# When the rules were encountered, .a and .b were known suffices, but later
+# on they were forgotten. These should get created as regular targets.
+all: .a .a.b .b.a
+
+# Issue 5: adding more suffixes does not make existing rules into suffix rules
+#
+# When the targets .c.d, .d.c, .d, .d.e, and .e.d were encountered, only .a,
+# .b and .c were known suffixes, so all of them were regular rules. Later
+# rest of the suffixes were made known, so they should all be suffix
+# transformation rules.
+all: issue5a.d issue5b.c issue5c issue5d.e issue5e.d
+
+# Issue 6: transformation search can end up in an infinite loop
+#
+# There is no file or target from which issue6.f could be made from so
+# this should fail. The bug was that because rules .e.f, .d.e and .e.d
+# exist, make would try to make .f from .e and then infinitely try
+# to do .e from .d and vice versa.
+all: issue6.f
+
+# Issue 10: explicit dependencies affect transformation rule selection
+#
+# If issue10.e is wanted and both issue10.d and issue10.f are available,
+# make should choose the .d.e rule, because .d is before .f in .SUFFIXES.
+# The bug was that if issue10.d had an explicit dependency on issue10.f,
+# it would choose .f.e instead.
+all: issue10.e
+
+# Issue 11: sources from transformation rules are expanded incorrectly
+#
+# issue11.j should depend on issue11.i and issue11.second and issue11.i
+# should depend on issue11.h and issue11.first. The bug was that
+# the dynamic sources were expanded before ${.PREFIX} and ${.TARGET} were
+# available, so they would have expanded to a null string.
+all: issue11.j
+
+# we need to clean for repeatable results
+.BEGIN: clean
+clean:
+ @rm -f issue* .[ab]*
+
+.SUFFIXES: .a .b .c
+
+.a .a.b .b.a:
+ @echo 'There should be no text after the colon: ${.IMPSRC}'
+ touch ${.TARGET}
+
+.c.d .d.c .d .d.e .e.d:
+ @echo 'first set'
+ cp ${.IMPSRC} ${.TARGET}
+
+.SUFFIXES:
+.SUFFIXES: .c .d .e .f .g
+
+.e .e.f .f.e:
+ @echo 'second set'
+ cp ${.IMPSRC} ${.TARGET}
+
+issue3.a:
+ @echo 'There is a bug if you see this.'
+ touch ${.TARGET}
+
+issue5a.c issue5b.d issue5c.d issue5d.d issue5e.e issue10.d issue10.f:
+ touch ${.TARGET}
+
+.SUFFIXES: .h .i .j
+
+.h.i: ${.PREFIX}.first
+ @echo '.ALLSRC: ${.ALLSRC}'
+ cp ${.IMPSRC} ${.TARGET}
+
+.i.j: ${.PREFIX}.second
+ @echo '.ALLSRC: ${.ALLSRC}'
+ cp ${.IMPSRC} ${.TARGET}
+
+issue11.h issue11.first issue11.second:
+ touch ${.TARGET}
diff --git a/contrib/bmake/unit-tests/sunshcmd.exp b/contrib/bmake/unit-tests/sunshcmd.exp
new file mode 100644
index 0000000..b14f6b6
--- /dev/null
+++ b/contrib/bmake/unit-tests/sunshcmd.exp
@@ -0,0 +1,4 @@
+TEST1=hello
+TEST2=bye
+TEST3=later
+exit status 0
diff --git a/contrib/bmake/unit-tests/sunshcmd b/contrib/bmake/unit-tests/sunshcmd.mk
index e3baf90..e3baf90 100644
--- a/contrib/bmake/unit-tests/sunshcmd
+++ b/contrib/bmake/unit-tests/sunshcmd.mk
diff --git a/contrib/bmake/unit-tests/sysv.exp b/contrib/bmake/unit-tests/sysv.exp
new file mode 100644
index 0000000..4cce2de
--- /dev/null
+++ b/contrib/bmake/unit-tests/sysv.exp
@@ -0,0 +1,7 @@
+FOOBAR =
+FOOBAR = foobar fubar
+fun
+fun
+fun
+In the Sun
+exit status 0
diff --git a/contrib/bmake/unit-tests/sysv b/contrib/bmake/unit-tests/sysv.mk
index 9eedacb..d5e99ff 100644
--- a/contrib/bmake/unit-tests/sysv
+++ b/contrib/bmake/unit-tests/sysv.mk
@@ -1,7 +1,7 @@
-# $Id: sysv,v 1.1.1.2 2011/06/05 04:23:49 sjg Exp $
+# $Id: sysv.mk,v 1.2 2014/08/30 22:25:14 sjg Exp $
FOO ?=
-FOOBAR = $(FOO:=bar)
+FOOBAR = ${FOO:=bar}
_this := ${.PARSEDIR}/${.PARSEFILE}
@@ -14,7 +14,7 @@ SUN = the Sun
all: foo fun
foo:
- @echo FOOBAR = $(FOOBAR)
+ @echo FOOBAR = ${FOOBAR}
.if empty(FOO)
@FOO="foo fu" ${.MAKE} -f ${_this} foo
.endif
diff --git a/contrib/bmake/unit-tests/ternary.exp b/contrib/bmake/unit-tests/ternary.exp
new file mode 100644
index 0000000..ed9c1bd
--- /dev/null
+++ b/contrib/bmake/unit-tests/ternary.exp
@@ -0,0 +1,10 @@
+The answer is unknown
+The answer is unknown
+The answer is empty
+The answer is known
+The answer is
+The answer is empty
+The answer is known
+The answer is 42
+The answer is 42
+exit status 0
diff --git a/contrib/bmake/unit-tests/ternary b/contrib/bmake/unit-tests/ternary.mk
index 77f8349..77f8349 100644
--- a/contrib/bmake/unit-tests/ternary
+++ b/contrib/bmake/unit-tests/ternary.mk
diff --git a/contrib/bmake/unit-tests/test.exp b/contrib/bmake/unit-tests/test.exp
deleted file mode 100644
index aaecb96..0000000
--- a/contrib/bmake/unit-tests/test.exp
+++ /dev/null
@@ -1,383 +0,0 @@
-comment testing start
-this is foo
-This is how a comment looks: # comment
-comment testing done
-make: "cond1" line 75: warning: extra else
-make: "cond1" line 85: warning: extra else
-2 is prime
-A='other' B='unknown' C='clever' o='no,no'
-Passed:
- var
- ("var")
- (var != var)
- var != var
- !((var != var) && defined(name))
- var == quoted
-
-1 is not prime
-2 is prime
-3 is prime
-4 is not prime
-5 is prime
-
-make: warning: String comparison operator should be either == or !=
-make: Bad conditional expression `"0" > 0' in "0" > 0?OK:No
-
-OK
-make: "error" line 3: just FYI
-make: "error" line 4: warning: this could be serious
-make: "error" line 5: this is fatal
-UT_DOLLAR=This is $UT_FU
-UT_FOO=foobar is fubar
-UT_FU=fubar
-UT_TEST=export
-UT_ZOO=hoopie
-UT_ALL=even this gets exported
-UT_BADDIR=unit-tests
-UT_DOLLAR=This is $UT_FU
-UT_F=fine
-UT_FOO=foobar is fubar
-UT_FU=fubar
-UT_NO=all
-UT_OK=good
-UT_OKDIR=unit-tests
-UT_TEST=export-all
-UT_ZOO=hoopie
-make:
-UT_TEST=export-env
-UT_ENV=not-exported
-UT_EXP=not-exported
-env:
-UT_TEST=export-env
-UT_ENV=exported
-UT_EXP=exported
-At first, I am
-happy
-and now: sad
-.ERROR: Looks like 'sad' is upset.
-*** Error code 1
-
-Stop.
-make: stopped in unit-tests
-simple.1
-simple.1
-simple.2
-simple.2
-recursive.1.1.*
-recursive.1.1.*
-recursive.1.1.*
-recursive.1.1.*
-recursive.1.99
-recursive.1.99
-recursive.2.1.*
-recursive.2.1.*
-recursive.2.1.*
-recursive.2.1.*
-recursive.2.99
-recursive.2.99
-shared.0
-shared.0
-shared.1.99
-shared.1.99
-shared.2.1
-shared.2.1
-shared.2.99
-shared.2.99
-make: Graph cycles through `cycle.2.99'
-make: Graph cycles through `cycle.2.98'
-make: Graph cycles through `cycle.2.97'
-cycle.1.99
-cycle.1.99
-x=one
-x="two and three"
-x=four
-x="five"
-x=-I/this
-x=-I"This or that"
-x=-Ithat
-x="-DTHIS=\"this and that\""
-cfl=-I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
-a=one b="two and three"
-a=four b="five"
-a=ONE b="TWO AND THREE"
-a=FOUR b="FIVE"
-We expect an error next:
-make: "forloop" line 38: Wrong number of words (9) in .for substitution list with 2 vars
-make: Fatal errors encountered -- cannot continue
-make: stopped in unit-tests
-OK
-.for with :S;... OK
-b2af338b
-3360ac65
-7747f046
-9ca87054
-880fe816
-208fcbd3
-d5d376eb
-de41416c
-Expect: Unknown modifier 'Z'
-make: Unknown modifier 'Z'
-VAR:Z=
-Expect: Unknown modifier 'Z'
-make: Unknown modifier 'Z'
-VAR:Z=
-Expect: Unclosed variable specification for VAR
-make: Unclosed variable specification (expecting '}') for "VAR" (value "Thevariable") modifier S
-VAR:S,V,v,=Thevariable
-Expect: Unclosed variable specification for VAR
-make: Unclosed variable specification after complex modifier (expecting '}') for VAR
-VAR:S,V,v,=Thevariable
-Expect: Unclosed substitution for VAR (, missing)
-make: Unclosed substitution for VAR (, missing)
-VAR:S,V,v=
-LIB=a X_LIBS:M${LIB${LIB:tu}} is "/tmp/liba.a"
-LIB=a X_LIBS:M*/lib${LIB}.a is "/tmp/liba.a"
-LIB=a X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBA.A"
-LIB=b X_LIBS:M${LIB${LIB:tu}} is ""
-LIB=b X_LIBS:M*/lib${LIB}.a is ""
-LIB=b X_LIBS:M*/lib${LIB}.a:tu is ""
-LIB=c X_LIBS:M${LIB${LIB:tu}} is ""
-LIB=c X_LIBS:M*/lib${LIB}.a is ""
-LIB=c X_LIBS:M*/lib${LIB}.a:tu is ""
-LIB=d X_LIBS:M${LIB${LIB:tu}} is "/tmp/libd.a"
-LIB=d X_LIBS:M*/lib${LIB}.a is "/tmp/libd.a"
-LIB=d X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBD.A"
-LIB=e X_LIBS:M${LIB${LIB:tu}} is "/tmp/libe.a"
-LIB=e X_LIBS:M*/lib${LIB}.a is "/tmp/libe.a"
-LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
-Mscanner=OK
-path=':/bin:/tmp::/:.:/no/such/dir:.'
-path='/bin:/tmp:/:/no/such/dir'
-path='/bin:/tmp:/:/no/such/dir'
-path='/bin':'/tmp':'/':'/no/such/dir'
-path='/bin':'/tmp':'/':'/no/such/dir'
-path_/usr/xbin=/opt/xbin/
-paths=/bin /tmp / /no/such/dir /opt/xbin
-PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN
-The answer is 42
-LIST = one two three four five six seven eight nine ten
-LIST:O = eight five four nine one seven six ten three two
-LIST:Ox = Ok
-LIST:O:Ox = Ok
-LISTX = Ok
-LISTSX = Ok
-make: Bad modifier `:OX' for LIST
-BADMOD 1 = }
-make: Bad modifier `:OxXX' for LIST
-BADMOD 2 = XX}
-LIST="one two three four five six"
-LIST:ts,="one,two,three,four,five,six"
-LIST:ts/:tu="ONE/TWO/THREE/FOUR/FIVE/SIX"
-LIST:ts::tu="ONE:TWO:THREE:FOUR:FIVE:SIX"
-LIST:ts:tu="ONETWOTHREEFOURFIVESIX"
-LIST:tu:ts/="ONE/TWO/THREE/FOUR/FIVE/SIX"
-LIST:ts:="one:two:three:four:five:six"
-LIST:ts="onetwothreefourfivesix"
-LIST:ts:S/two/2/="one2threefourfivesix"
-LIST:S/two/2/:ts="one2threefourfivesix"
-LIST:ts/:S/two/2/="one/2/three/four/five/six"
-Pretend the '/' in '/n' etc. below are back-slashes.
-LIST:ts/n="one
-two
-three
-four
-five
-six"
-LIST:ts/t="one two three four five six"
-LIST:ts/012:tu="ONE
-TWO
-THREE
-FOUR
-FIVE
-SIX"
-make: Bad modifier `:tx' for LIST
-LIST:tx="}"
-make: Bad modifier `:ts\x' for LIST
-LIST:ts/x:tu="\x:tu}"
-FU_mod-ts="a/b/cool"
-FU_mod-ts:ts:T="cool" == cool?
-B.${AAA:ts}="Baaa" == Baaa?
-make: Bad modifier `:[]' for LIST
-LIST:[]="" is an error
-LIST:[0]="one two three four five six"
-LIST:[0x0]="one two three four five six"
-LIST:[000]="one two three four five six"
-LIST:[*]="one two three four five six"
-LIST:[@]="one two three four five six"
-LIST:[0]:C/ /,/="one,two three four five six"
-LIST:[0]:C/ /,/g="one,two,three,four,five,six"
-LIST:[0]:C/ /,/1g="one,two,three,four,five,six"
-LIST:[*]:C/ /,/="one,two three four five six"
-LIST:[*]:C/ /,/g="one,two,three,four,five,six"
-LIST:[*]:C/ /,/1g="one,two,three,four,five,six"
-LIST:[@]:C/ /,/="one two three four five six"
-LIST:[@]:C/ /,/g="one two three four five six"
-LIST:[@]:C/ /,/1g="one two three four five six"
-LIST:[@]:[0]:C/ /,/="one,two three four five six"
-LIST:[0]:[@]:C/ /,/="one two three four five six"
-LIST:[@]:[*]:C/ /,/="one,two three four five six"
-LIST:[*]:[@]:C/ /,/="one two three four five six"
-EMPTY=""
-EMPTY:[#]="1" == 1 ?
-ESCAPEDSPACE="\ "
-ESCAPEDSPACE:[#]="1" == 1 ?
-REALLYSPACE=" "
-REALLYSPACE:[#]="1" == 1 ?
-LIST:[#]="6"
-LIST:[0]:[#]="1" == 1 ?
-LIST:[*]:[#]="1" == 1 ?
-LIST:[@]:[#]="6"
-LIST:[1]:[#]="1"
-LIST:[1..3]:[#]="3"
-EMPTY:[1]=""
-ESCAPEDSPACE="\ "
-ESCAPEDSPACE:[1]="\ "
-REALLYSPACE=" "
-REALLYSPACE:[1]="" == "" ?
-REALLYSPACE:[*]:[1]=" " == " " ?
-LIST:[1]="one"
-make: Bad modifier `:[1.]' for LIST
-LIST:[1.]="" is an error
-make: Bad modifier `:[1].' for LIST
-LIST:[1].="}" is an error
-LIST:[2]="two"
-LIST:[6]="six"
-LIST:[7]=""
-LIST:[999]=""
-make: Bad modifier `:[-]' for LIST
-LIST:[-]="" is an error
-make: Bad modifier `:[--]' for LIST
-LIST:[--]="" is an error
-LIST:[-1]="six"
-LIST:[-2]="five"
-LIST:[-6]="one"
-LIST:[-7]=""
-LIST:[-999]=""
-LONGLIST:[17]="17"
-LONGLIST:[0x11]="17"
-LONGLIST:[021]="17"
-LIST:[0]:[1]="one two three four five six"
-LIST:[*]:[1]="one two three four five six"
-LIST:[@]:[1]="one"
-LIST:[0]:[2]=""
-LIST:[*]:[2]=""
-LIST:[@]:[2]="two"
-LIST:[*]:C/ /,/:[2]=""
-LIST:[*]:C/ /,/:[*]:[2]=""
-LIST:[*]:C/ /,/:[@]:[2]="three"
-make: Bad modifier `:[1.]' for LIST
-LIST:[1.]="" is an error
-make: Bad modifier `:[1..]' for LIST
-LIST:[1..]="" is an error
-LIST:[1..1]="one"
-make: Bad modifier `:[1..1.]' for LIST
-LIST:[1..1.]="" is an error
-LIST:[1..2]="one two"
-LIST:[2..1]="two one"
-LIST:[3..-2]="three four five"
-LIST:[-4..4]="three four"
-make: Bad modifier `:[0..1]' for LIST
-LIST:[0..1]="" is an error
-make: Bad modifier `:[-1..0]' for LIST
-LIST:[-1..0]="" is an error
-LIST:[-1..1]="six five four three two one"
-LIST:[0..0]="one two three four five six"
-LIST:[3..99]="three four five six"
-LIST:[-3..-99]="four three two one"
-LIST:[-99..-3]="one two three four"
-HASH="#" == "#" ?
-LIST:[${HASH}]="6"
-LIST:[${ZERO}]="one two three four five six"
-LIST:[${ZERO}x${ONE}]="one"
-LIST:[${ONE}]="one"
-LIST:[${MINUSONE}]="six"
-LIST:[${STAR}]="one two three four five six"
-LIST:[${AT}]="one two three four five six"
-make: Bad modifier `:[${EMPTY' for LIST
-LIST:[${EMPTY}]="" is an error
-LIST:[${LONGLIST:[21]:S/2//}]="one"
-LIST:[${LIST:[#]}]="six"
-LIST:[${LIST:[${HASH}]}]="six"
-LIST:S/ /,/="one two three four five six"
-LIST:S/ /,/W="one,two three four five six"
-LIST:S/ /,/gW="one,two,three,four,five,six"
-EMPTY:S/^/,/=","
-EMPTY:S/^/,/W=","
-LIST:C/ /,/="one two three four five six"
-LIST:C/ /,/W="one,two three four five six"
-LIST:C/ /,/gW="one,two,three,four,five,six"
-EMPTY:C/^/,/=","
-EMPTY:C/^/,/W=","
-LIST:tW="one two three four five six"
-LIST:tw="one two three four five six"
-LIST:tW:C/ /,/="one,two three four five six"
-LIST:tW:C/ /,/g="one,two,three,four,five,six"
-LIST:tW:C/ /,/1g="one,two,three,four,five,six"
-LIST:tw:C/ /,/="one two three four five six"
-LIST:tw:C/ /,/g="one two three four five six"
-LIST:tw:C/ /,/1g="one two three four five six"
-LIST:tw:tW:C/ /,/="one,two three four five six"
-LIST:tW:tw:C/ /,/="one two three four five six"
-Making the.c
-Making the.h
-Making the.o from the.h the.c
-.TARGET="phony" .PREFIX="phony" .IMPSRC=""
-.TARGET="all" .PREFIX="all" .IMPSRC=""
-.TARGET="ok" .PREFIX="ok" .IMPSRC=""
-.TARGET="also.ok" .PREFIX="also.ok" .IMPSRC=""
-.TARGET="bug" .PREFIX="bug" .IMPSRC=""
-Posix says we should execute the command as if run by system(3)
-Expect 'Hello,' and 'World!'
-Hello,
-World!
-a command
-a command prefixed by '+' executes even with -n
-another command
-make -n
-echo a command
-echo "a command prefixed by '+' executes even with -n"
-a command prefixed by '+' executes even with -n
-echo another command
-make -n -j1
-{ echo a command
-} || exit $?
-echo "a command prefixed by '+' executes even with -n"
-a command prefixed by '+' executes even with -n
-{ echo another command
-} || exit $?
-Now we expect an error...
-*** Error code 1 (continuing)
-`all' not remade because of errors.
-V.i386 ?= OK
-TEST1=hello
-TEST2=bye
-TEST3=later
-FOOBAR =
-FOOBAR = foobar fubar
-fun
-fun
-fun
-In the Sun
-The answer is unknown
-The answer is unknown
-The answer is empty
-The answer is known
-The answer is
-The answer is empty
-The answer is known
-The answer is 42
-The answer is 42
-UT_DOLLAR=This is $UT_FU
-UT_FU=fubar
-UT_TEST=unexport
-UT_TEST=unexport-env
-default FU=<v>fu</v> FOO=<v>foo</v> VAR=<v></v>
-two FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
-three FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
-four FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
-five FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
-five v=is x k=is x
-six v=is y k=is y
-show-v v=override k=override
-*** Error code 1 (ignored)
-*** Error code 1 (ignored)
diff --git a/contrib/bmake/unit-tests/unexport-env.exp b/contrib/bmake/unit-tests/unexport-env.exp
new file mode 100644
index 0000000..6d43cab
--- /dev/null
+++ b/contrib/bmake/unit-tests/unexport-env.exp
@@ -0,0 +1,2 @@
+UT_TEST=unexport-env
+exit status 0
diff --git a/contrib/bmake/unit-tests/unexport-env b/contrib/bmake/unit-tests/unexport-env.mk
index f6a2ff9..aaabcd4 100644
--- a/contrib/bmake/unit-tests/unexport-env
+++ b/contrib/bmake/unit-tests/unexport-env.mk
@@ -1,7 +1,7 @@
-# $Id: unexport-env,v 1.1.1.1 2009/11/19 00:31:11 sjg Exp $
+# $Id: unexport-env.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
# pick up a bunch of exported vars
-.include "export"
+.include "export.mk"
# an example of setting up a minimal environment.
PATH = /bin:/usr/bin:/sbin:/usr/sbin
diff --git a/contrib/bmake/unit-tests/unexport.exp b/contrib/bmake/unit-tests/unexport.exp
new file mode 100644
index 0000000..7b16ea3
--- /dev/null
+++ b/contrib/bmake/unit-tests/unexport.exp
@@ -0,0 +1,4 @@
+UT_DOLLAR=This is $UT_FU
+UT_FU=fubar
+UT_TEST=unexport
+exit status 0
diff --git a/contrib/bmake/unit-tests/unexport b/contrib/bmake/unit-tests/unexport.mk
index fb40d0c..0f12452 100644
--- a/contrib/bmake/unit-tests/unexport
+++ b/contrib/bmake/unit-tests/unexport.mk
@@ -1,7 +1,7 @@
-# $Id: unexport,v 1.1.1.1 2009/11/19 00:31:11 sjg Exp $
+# $Id: unexport.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
# pick up a bunch of exported vars
-.include "export"
+.include "export.mk"
.unexport UT_ZOO UT_FOO
diff --git a/contrib/bmake/unit-tests/varcmd.exp b/contrib/bmake/unit-tests/varcmd.exp
new file mode 100644
index 0000000..34dd637
--- /dev/null
+++ b/contrib/bmake/unit-tests/varcmd.exp
@@ -0,0 +1,9 @@
+default FU=<v>fu</v> FOO=<v>foo</v> VAR=<v></v>
+two FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
+three FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
+four FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
+five FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
+five v=is x k=is x
+six v=is y k=is y
+show-v v=override k=override
+exit status 0
diff --git a/contrib/bmake/unit-tests/varcmd b/contrib/bmake/unit-tests/varcmd.mk
index a58e014..a5fd198 100644
--- a/contrib/bmake/unit-tests/varcmd
+++ b/contrib/bmake/unit-tests/varcmd.mk
@@ -1,4 +1,4 @@
-# $Id: varcmd,v 1.3 2008/05/15 04:30:47 sjg Exp $
+# $Id: varcmd.mk,v 1.1.1.1 2014/08/30 18:57:18 sjg Exp $
#
# Test behaviour of recursive make and vars set on command line.
diff --git a/contrib/bmake/unit-tests/varmisc.exp b/contrib/bmake/unit-tests/varmisc.exp
new file mode 100644
index 0000000..1636aaf
--- /dev/null
+++ b/contrib/bmake/unit-tests/varmisc.exp
@@ -0,0 +1,2 @@
+
+exit status 0
diff --git a/contrib/bmake/unit-tests/varmisc.mk b/contrib/bmake/unit-tests/varmisc.mk
new file mode 100644
index 0000000..4b4a931
--- /dev/null
+++ b/contrib/bmake/unit-tests/varmisc.mk
@@ -0,0 +1,8 @@
+# $Id: varmisc.mk,v 1.2 2014/08/30 22:25:14 sjg Exp $
+#
+# Miscellaneous variable tests.
+
+all: unmatched_var_paren
+
+unmatched_var_paren:
+ @echo ${foo::=foo-text}
diff --git a/contrib/bmake/unit-tests/varshell.exp b/contrib/bmake/unit-tests/varshell.exp
new file mode 100644
index 0000000..dae2c6b
--- /dev/null
+++ b/contrib/bmake/unit-tests/varshell.exp
@@ -0,0 +1,10 @@
+make: "varshell.mk" line 5: warning: "/bin/no/such/command 2> /dev/null" returned non-zero status
+make: "varshell.mk" line 8: warning: "false" returned non-zero status
+make: "varshell.mk" line 9: warning: "echo "output before the error"; false" returned non-zero status
+EXEC_FAILED=''
+TERMINATED_BY_SIGNAL=''
+ERROR_NO_OUTPUT=''
+ERROR_WITH_OUTPUT='output before the error'
+NO_ERROR_NO_OUTPUT=''
+NO_ERROR_WITH_OUTPUT='this is good'
+exit status 0
diff --git a/contrib/bmake/unit-tests/varshell.mk b/contrib/bmake/unit-tests/varshell.mk
new file mode 100644
index 0000000..9c8baac
--- /dev/null
+++ b/contrib/bmake/unit-tests/varshell.mk
@@ -0,0 +1,19 @@
+# $Id: varshell.mk,v 1.4 2015/04/20 03:16:39 sjg Exp $
+#
+# Test VAR != shell command
+
+EXEC_FAILED != /bin/no/such/command 2> /dev/null
+# SunOS cannot handle this one
+#TERMINATED_BY_SIGNAL != kill -14 $$$$
+ERROR_NO_OUTPUT != false
+ERROR_WITH_OUTPUT != echo "output before the error"; false
+NO_ERROR_NO_OUTPUT != true
+NO_ERROR_WITH_OUTPUT != echo "this is good"
+
+allvars= EXEC_FAILED TERMINATED_BY_SIGNAL ERROR_NO_OUTPUT ERROR_WITH_OUTPUT \
+ NO_ERROR_NO_OUTPUT NO_ERROR_WITH_OUTPUT
+
+all:
+.for v in ${allvars}
+ @echo ${v}=\'${${v}}\'
+.endfor
diff --git a/contrib/bmake/var.c b/contrib/bmake/var.c
index 0b7e88e..2a94dee 100644
--- a/contrib/bmake/var.c
+++ b/contrib/bmake/var.c
@@ -1,4 +1,4 @@
-/* $NetBSD: var.c,v 1.186 2014/06/20 06:13:45 sjg Exp $ */
+/* $NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: var.c,v 1.186 2014/06/20 06:13:45 sjg Exp $";
+static char rcsid[] = "$NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
#else
-__RCSID("$NetBSD: var.c,v 1.186 2014/06/20 06:13:45 sjg Exp $");
+__RCSID("$NetBSD: var.c,v 1.191 2014/09/14 02:32:51 dholland Exp $");
#endif
#endif /* not lint */
#endif
@@ -3600,14 +3600,13 @@ Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
* expanding it in a non-local context. This
* is done to support dynamic sources. The
* result is just the invocation, unaltered */
- Var_Parse_State parsestate; /* Flags passed to helper functions */
+ const char *extramodifiers; /* extra modifiers to apply first */
char name[2];
*freePtr = NULL;
+ extramodifiers = NULL;
dynamic = FALSE;
start = str;
- parsestate.oneBigWord = FALSE;
- parsestate.varSpace = ' '; /* word separator */
startc = str[1];
if (startc != PROPEN && startc != BROPEN) {
@@ -3735,7 +3734,7 @@ Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
*/
if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
(vlen == 2) && (str[1] == 'F' || str[1] == 'D') &&
- strchr("@%*!<>", str[0]) != NULL) {
+ strchr("@%?*!<>", str[0]) != NULL) {
/*
* Well, it's local -- go look for it.
*/
@@ -3744,29 +3743,12 @@ Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
v = VarFind(name, ctxt, 0);
if (v != NULL) {
- /*
- * No need for nested expansion or anything, as we're
- * the only one who sets these things and we sure don't
- * but nested invocations in them...
- */
- nstr = Buf_GetAll(&v->val, NULL);
-
if (str[1] == 'D') {
- nstr = VarModify(ctxt, &parsestate, nstr, VarHead,
- NULL);
- } else {
- nstr = VarModify(ctxt, &parsestate, nstr, VarTail,
- NULL);
+ extramodifiers = "H:";
+ }
+ else { /* F */
+ extramodifiers = "T:";
}
- /*
- * Resulting string is dynamically allocated, so
- * tell caller to free it.
- */
- *freePtr = nstr;
- *lengthPtr = tstr-start+1;
- Buf_Destroy(&buf, TRUE);
- VarFreeEnv(v, TRUE);
- return nstr;
}
}
@@ -3861,16 +3843,29 @@ Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
v->flags &= ~VAR_IN_USE;
- if ((nstr != NULL) && haveModifier) {
+ if ((nstr != NULL) && (haveModifier || extramodifiers != NULL)) {
+ void *extraFree;
int used;
- /*
- * Skip initial colon.
- */
- tstr++;
- nstr = ApplyModifiers(nstr, tstr, startc, endc,
- v, ctxt, errnum, &used, freePtr);
- tstr += used;
+ extraFree = NULL;
+ if (extramodifiers != NULL) {
+ nstr = ApplyModifiers(nstr, extramodifiers, '(', ')',
+ v, ctxt, errnum, &used, &extraFree);
+ }
+
+ if (haveModifier) {
+ /* Skip initial colon. */
+ tstr++;
+
+ nstr = ApplyModifiers(nstr, tstr, startc, endc,
+ v, ctxt, errnum, &used, freePtr);
+ tstr += used;
+ if (extraFree) {
+ free(extraFree);
+ }
+ } else {
+ *freePtr = extraFree;
+ }
}
if (*tstr) {
*lengthPtr = tstr - start + 1;
diff --git a/contrib/compiler-rt/lib/builtins/floatditf.c b/contrib/compiler-rt/lib/builtins/floatditf.c
new file mode 100644
index 0000000..01261c6
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/floatditf.c
@@ -0,0 +1,52 @@
+//===-- lib/floatditf.c - integer -> quad-precision conversion ----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements di_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatditf(di_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ unsigned aAbs = (unsigned)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs += 0x80000000;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit. Extra
+ // cast to unsigned int is necessary to get the correct behavior for
+ // the input INT_MIN.
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/floatunditf.c b/contrib/compiler-rt/lib/builtins/floatunditf.c
new file mode 100644
index 0000000..7533f81
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/floatunditf.c
@@ -0,0 +1,40 @@
+//===-- lib/floatunditf.c - uint -> quad-precision conversion -----*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements du_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatunditf(du_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0) return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clz(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
+}
+
+#endif
diff --git a/contrib/compiler-rt/lib/builtins/multc3.c b/contrib/compiler-rt/lib/builtins/multc3.c
new file mode 100644
index 0000000..b9953cf
--- /dev/null
+++ b/contrib/compiler-rt/lib/builtins/multc3.c
@@ -0,0 +1,73 @@
+/* ===-- multc3.c - Implement __multc3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __multc3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+#include "int_math.h"
+
+/* Returns: the product of a + ib and c + id */
+
+COMPILER_RT_ABI long double _Complex
+__multc3(long double __a, long double __b, long double __c, long double __d)
+{
+ long double __ac = __a * __c;
+ long double __bd = __b * __d;
+ long double __ad = __a * __d;
+ long double __bc = __b * __c;
+ long double _Complex z;
+ __real__ z = __ac - __bd;
+ __imag__ z = __ad + __bc;
+ if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
+ {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b))
+ {
+ __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
+ }
+ if (crt_isinf(__c) || crt_isinf(__d))
+ {
+ __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
+ crt_isinf(__ad) || crt_isinf(__bc)))
+ {
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc)
+ {
+ __real__ z = CRT_INFINITY * (__a * __c - __b * __d);
+ __imag__ z = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
+}
diff --git a/contrib/gcclibs/libgomp/ChangeLog b/contrib/gcclibs/libgomp/ChangeLog
index 56191ec..2237892 100644
--- a/contrib/gcclibs/libgomp/ChangeLog
+++ b/contrib/gcclibs/libgomp/ChangeLog
@@ -1,6 +1,223 @@
-2007-07-19 Release Manager
+2010-05-22 Release Manager
- * GCC 4.2.1 released.
+ * GCC 4.3.5 released.
+
+2010-05-06 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ PR other/43620
+ * configure.ac (AM_INIT_AUTOMAKE): Add no-dist.
+ * configure: Regenerate.
+ * aclocal.m4: Regenerate.
+ * config.h.in: Regenerate.
+ * Makefile.in: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2009-08-19 Tobias Burnus <burnus@net-b.de>
+
+ PR fortran/41102
+ omp_lib.h.in: Fix -std=f95 errors.
+
+2009-08-14 Uros Bizjak <ubizjak@gmail.com>
+
+ Backport from mainline:
+ 2008-12-26 Uros Bizjak <ubizjak@gmail.com>
+
+ * testsuite/libgomp.c/atomic-6.c: Add -mieee for alpha*-*-* targets.
+
+2009-08-04 Release Manager
+
+ * GCC 4.3.4 released.
+
+2009-01-24 Release Manager
+
+ * GCC 4.3.3 released.
+
+2008-12-05 Janis Johnson <janis187@us.ibm.com>
+
+ Backport from mainline:
+ 2008-05-15 Janis Johnson <janis187@us.ibm.com>
+
+ * testsuite/lib/libgomp.exp: Load new torture support.
+
+2008-12-02 Janis Johnson <janis187@us.ibm.com>
+
+ Backport from mainline:
+ 2008-11-26 Janis Johnson <janis187@us.ibm.com>
+
+ PR testsuite/28870
+ * testsuite/lib/libgomp.exp: Include new timeout library files.
+ (libgomp_target_compile): Set timeout value from new proc.
+
+2008-08-27 Release Manager
+
+ * GCC 4.3.2 released.
+
+2008-06-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/36506
+ * testsuite/libgomp.c/reduction-5.c: New test.
+
+2008-06-06 Release Manager
+
+ * GCC 4.3.1 released.
+
+2008-05-23 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/36308
+ * testsuite/libgomp.c++/ctor-11.C: New test.
+ * testsuite/libgomp.c++/ctor-12.C: New test.
+
+2008-05-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/36106
+ * testsuite/libgomp.c/atomic-5.c: New test.
+ * testsuite/libgomp.c/atomic-6.c: New test.
+ * testsuite/libgomp.c/autopar-1.c: New test.
+
+2008-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/35611
+ * testsuite/libgomp.c/atomic-4.c: New test.
+
+ PR libgomp/35625
+ * iter.c (gomp_iter_guided_next_locked): If q > n, set end to ws->end.
+ (gomp_iter_guided_next): Likewise.
+ * testsuite/libgomp.c/pr35625.c: New test.
+
+2008-03-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/35185
+ * testsuite/libgomp.c++/pr35185.C: New test.
+
+2008-03-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/35549
+ * testsuite/libgomp.c/pr35549.c: New test.
+
+2008-03-06 Jakub Jelinek <jakub@redhat.com>
+
+ * testsuite/libgomp.c/atomic-3.c: New test.
+
+2008-03-05 Release Manager
+
+ * GCC 4.3.0 released.
+
+2008-02-15 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/35196
+ * testsuite/libgomp.c/pr35196.c: New test.
+
+ PR middle-end/35130
+ * testsuite/libgomp.fortran/pr35130.f90: New test.
+ * testsuite/libgomp.c/pr35130.c: New test.
+
+2008-01-25 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/33880
+ * testsuite/libgomp.c/pr33880.c: New test.
+ * testsuite/libgomp.fortran/pr33880.f90: New test.
+
+2008-01-24 David Edelsohn <edelsohn@gnu.org>
+
+ * configure: Regenerate.
+
+2008-01-08 Jakub Jelinek <jakub@redhat.com>
+
+ * configure.ac: Move futex checking into ../config/futex.m4.
+ * configure: Rebuilt.
+ * aclocal.m4: Rebuilt.
+ * Makefile.in: Rebuilt.
+
+ * configure.tgt: Rename have_tls to gcc_cv_have_tls to match
+ 2007-10-15 ../config/tls.m4 change.
+
+2007-12-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/34513
+ * testsuite/libgomp.c/pr34513.c: New test.
+ * testsuite/libgomp.c++/pr34513.C: New test.
+
+2007-12-17 Jack Howarth <howarth@bromo.med.uc.edu>
+
+ PR target/32765
+ * testsuite/libgomp.fortran/crayptr2.f90: Move dg-options for darwin.
+
+2007-12-04 Jakub Jelinek <jakub@redhat.com>
+
+ * omp.h.in (__GOMP_NOTHROW): Define. Use it on omp_* prototypes.
+
+2007-12-03 Jakub Jelinek <jakub@redhat.com>
+
+ * testsuite/libgomp.c/private-1.c: New test.
+
+2007-11-29 Andris Pavenis <andris.pavenis@iki.fi>
+ Paolo Bonzini <bonzini@gnu.org>
+
+ * Makefile.am: Use space as vpath separator. Use 'vpath %'
+ instead of 'VPATH ='.
+ * Makefile.in: Regenerate.
+
+2007-11-23 Matthias Klose <doko@ubuntu.com>
+
+ * configure.ac: Adjust makeinfo version check.
+ * configure: Regenerate.
+
+2007-11-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR fortran/34020
+ * testsuite/libgomp.fortran/pr34020.f90: New test.
+
+2007-11-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/33894
+ * testsuite/libgomp.c++/atomic-1.C: New test.
+
+2007-10-25 Jakub Jelinek <jakub@redhat.com>
+
+ PR libgomp/33275
+ * testsuite/libgomp.fortran/omp_parse3.f90 (test_threadprivate):
+ Make x and y integers rather than (implicit) reals. Add private (j)
+ clause to the last omp parallel.
+
+2007-10-15 Maciej W. Rozycki <macro@linux-mips.org>
+
+ * configure: Regenerate following changes to ../config/tls.m4.
+
+2007-09-28 Jakub Jelinek <jakub@redhat.com>
+
+ * testsuite/libgomp.fortran/stack.f90: New test.
+
+2007-09-10 Danny Smith <dannysmith@users.sourceforge.net>
+
+ * config/mingw32/proc.c: New file.
+
+2007-09-05 Uros Bizjak <ubizjak@gmail.com>
+
+ * testsuite/libgomp.c/atomic-1.c: Include cpuid.h for i386 targets.
+ (main): Use __get_cpuid to get i386 target fetaures.
+ * testsuite/libgomp.c/atomic-2.c: Include cpuid.h for x86_64 targets.
+ (main): Use __get_cpuid to get x86_64 target fetaures.
+
+2007-08-15 Jack Howarth <howarth@bromo.med.uc.edu>
+
+ PR target/32765
+ * testsuite/libgomp.fortran/pr32550.f90: Use -static-libgcc on Darwin.
+ * testsuite/libgomp.fortran/crayptr2.f90: Likwise.
+
+2007-07-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR fortran/32550
+ * testsuite/libgomp.fortran/pr32550.f90: New test.
+ * testsuite/libgomp.fortran/crayptr2.f90: New test.
+
+2007-07-05 H.J. Lu <hongjiu.lu@intel.com>
+
+ * aclocal.m4: Regenerated.
+
+2007-07-05 Tobias Burnus <burnus@net-b.de>
+
+ PR fortran/32359
+ * testsuite/libgomp.fortran/pr32359.f90: New.
2007-07-02 Jakub Jelinek <jakub@redhat.com>
@@ -21,9 +238,117 @@
* testsuite/libgomp.c/pr32362-2.c: New test.
* testsuite/libgomp.c/pr32362-3.c: New test.
-2007-05-13 Release Manager
+2007-06-07 Jakub Jelinek <jakub@redhat.com>
+
+ * team.c (gomp_team_start): Fix setting up thread_attr
+ stack size.
+
+2007-06-02 Paolo Bonzini <bonzini@gnu.org>
+
+ * configure: Regenerate.
+
+2007-05-23 Steve Ellcey <sje@cup.hp.com>
+
+ * Makefile.in: Regenerate.
+ * configure: Regenerate.
+ * aclocal.m4: Regenerate.
+ * testsuite/Makefile.in: Regenerate.
+
+2007-05-04 Jakub Jelinek <jakub@redhat.com>
+
+ * config/linux/proc.c: New file.
+
+ PR libgomp/28482
+ * configure.tgt: Don't link with -Wl,-z,nodlopen even on Linux.
+
+2007-04-19 Daniel Franke <franke.daniel@gmail.com>
- * GCC 4.2.0 released.
+ * libgomp.texi (GOMP_CPU_AFFINITY): Updated.
+
+2007-04-16 Matthias Klose <doko@debian.org>
+
+ * configure.tgt (i[456]86-*-linux*): Only add ia32 specific
+ flags if not building with -m64.
+ * testsuite/lib/libgomp-dg.exp (libgomp_init): Don't add -march
+ flag for i?86-*-* targets, if current target matches -m64.
+
+2007-04-14 Steve Ellcey <sje@cup.hp.com>
+
+ * Makefile.am: Add -I .. to ACLOCAL_AMFLAGS.
+ * Makefile.in: Regenerate.
+
+2007-04-07 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
+
+ PR testsuite/31369
+ * testsuite/libgomp.c++/c++.exp: Don't use concat when setting
+ ld_library_path.
+ * testsuite/libgomp.fortran/fortran.exp: Likewise.
+
+2007-04-04 Jakub Jelinek <jakub@redhat.com>
+
+ * libgomp.h (gomp_cpu_affinity, gomp_cpu_affinity_len): New extern
+ decls.
+ (gomp_init_affinity, gomp_init_thread_affinity): New prototypes.
+ * env.c (gomp_cpu_affinity, gomp_cpu_affinity_len): New variables.
+ (parse_affinity): New function.
+ (initialize_env): Call it and gomp_init_affinity.
+ * team.c (gomp_team_start): If gomp_cpu_affinity != NULL,
+ create new pthread_attr_t and call gomp_init_thread_affinity
+ on it for each thread before passing the attribute to pthread_create.
+ * config/linux/affinity.c: New file.
+ * config/posix/affinity.c: New file.
+ * configure.ac (HAVE_PTHREAD_AFFINITY_NP): New test.
+ * configure: Rebuilt.
+ * config.h.in: Rebuilt.
+ * Makefile.am (libgomp_la_SOURCES): Add affinity.c.
+ * Makefile.in: Rebuilt.
+
+2007-03-23 Andreas Tobler <a.tobler@schweiz.org>
+
+ * testsuite/lib/libgomp.exp (libgomp_init): Add -shared-libgcc for
+ *-*-darwin*.
+ * testsuite/libgomp.c++/c++.exp: Look for shared libstdc++ library
+ and use it if found.
+
+2007-03-18 Uros Bizjak <ubizjak@gmail.com>
+
+ * testsuite/config/default.exp: New file.
+ * testsuite/lib/libgomp.exp: New file.
+ * testsuite/lib/libgomp.dg (load_gcc_lib, libgomp_init,
+ libgomp_target_compile, libgomp_option_help, libgomp_option_proc,
+ load_lib *, load_gcc_lib *): Move to libgomp.exp.
+ (libgomp_load): Remove.
+ * testsuite/lib/libgomp.exp (libgomp_init): Compute
+ always_ld_library_path, not ld_library_path. Set additional_flags
+ to -march=i486 for ilp32 x86_64-*-* and i386-*-* targets.
+ (target_compile): Do not call libgomp_init. Append lang_library_path
+ and lang_link_flags to options.
+ * testsuite/libgomp.c/c.exp: Set DEFAULT_FLAGS to -O2. Set
+ ld_library_path from always_ld_library_path. Set LD_LIBRARY_PATH
+ here.
+ * testsuite/libgomp.c++/c++.exp: Set ld_library_path from
+ always_ld_library_path. Set LD_LIBRARY_PATH here.
+ * testsuite/libgomp.fortran/fortran.exp: Ditto.
+ * testsuite/libgomp.c/atomic-1.c: Set dg-options to
+ "-O2 -march=pentium" for ilp32 x86 targets. Simplify check for
+ CX8 flag.
+ * testsuite/libgomp.c/atomic-2.c: Set dg-options to "-O2 -mcx16" for
+ lp64 x86 targets. Do not check for SSE3 bit. Do not define bit_SSE3.
+ * testsuite/libgomp.c/pr29947-1.c: Remove default dg-options.
+ * testsuite/libgomp.c/pr29947-1.c: Ditto.
+ * testsuite/libgomp.c/atomic-10.c: Ditto.
+
+2007-03-21 Jakub Jelinek <jakub@redhat.com>
+
+ * testsuite/libgomp.fortran/appendix-a/a.22.8.f90: Add
+ dg-final cleanup-modules line.
+ * testsuite/libgomp.fortran/appendix-a/a.40.1.f90: Likewise.
+ * testsuite/libgomp.fortran/appendix-a/a.31.5.f90: Likewise.
+ * testsuite/libgomp.fortran/appendix-a/a.31.4.f90: Likewise.
+ * testsuite/libgomp.fortran/threadprivate2.f90: Likewise.
+ * testsuite/libgomp.fortran/reduction5.f90: Likewise.
+ * testsuite/libgomp.fortran/threadprivate3.f90: Likewise.
+ * testsuite/libgomp.fortran/threadprivate1.f90: Likewise.
2007-03-18 Andreas Schwab <schwab@suse.de>
@@ -31,15 +356,32 @@
extraction.
* configure: Regenerate.
+2007-03-01 Brooks Moses <brooks.moses@codesourcery.com>
+
+ * Makefile.am: Add install-pdf target as copied from
+ automake v1.10 rules.
+ * Makefile.in: Regenerate
+
2007-02-07 Jakub Jelinek <jakub@redhat.com>
+ PR libgomp/28486
+ * configure: Regenerate.
+
PR c++/30703
* testsuite/libgomp.c++/pr30703.C: New test.
-2007-02-07 Daniel Franke <franke.daniel@gmail.com>
+2007-02-02 Jakub Jelinek <jakub@redhat.com>
- Backport from mainline:
- 2007-01-31 Daniel Franke <franke.daniel@gmail.com>
+ Revert:
+ 2006-07-05 Eric Christopher <echristo@apple.com>
+ * configure.ac: Depend addition of -pthread on host OS.
+ * configure: Regenerate.
+
+2007-01-31 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ * libgomp.texi: Fix spacing after abbreviations.
+
+2007-01-31 Daniel Franke <franke.daniel@gmail.com>
PR libgomp/30546
* configure.ac: Add check for makeinfo
@@ -50,74 +392,47 @@
* Makefile.in: Regenerated.
* testsuite/Makefile.in: Regenerated.
-2007-02-07 Daniel Franke <franke.daniel@gmail.com>
-
- Backport from mainline:
- 2007-01-31 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
-
- * libgomp.texi: Fix spacing after abbreviations.
-
- Backport from mainline:
- 2007-01-29 Daniel Franke <franke.daniel@gmail.com>
+2007-01-29 Daniel Franke <franke.daniel@gmail.com>
PR libgomp/30540
* libgomp.texi: More about implementation-dependent settings.
-2007-02-06 Roger Sayle <roger@eyesopen.com>
+2007-01-26 Tobias Burnus <burnus@net-b.de>
- PR libgomp/28296
- Backport from mainline.
- Revert:
- 2006-07-05 Eric Christopher <echristo@apple.com>
- * configure.ac: Depend addition of -pthread on host OS.
- * configure: Regenerate.
+ * testsuite/libgomp.fortran/fortran.exp: Support .f03 extension.
-2007-01-30 Tobias Burnus <burnus@net-b.de>
+2007-01-24 Jakub Jelinek <jakub@redhat.com>
- Backport from mainline.
- 2007-01-26 Tobias Burnus <burnus@net-b.de>
+ PR middle-end/30494
+ * testsuite/libgomp.c/pr30494.c: New test.
- * testsuite/libgomp.fortran/fortran.exp: Support .f03 extension.
+2007-01-15 Tom Tromey <tromey@redhat.com>
-2007-01-25 Daniel Franke <franke.daniel@gmail.com>
+ * configure: Rebuilt.
+ * configure.ac: Fixed comment.
- Backport from mainline:
- 2006-12-21 Daniel Franke <franke.daniel@gmail.com>
+2007-01-14 Daniel Franke <franke.daniel@gmail.com>
+
+ * libgomp.texi: Document implementation specific default values of
+ environment variables.
+
+2006-12-21 Daniel Franke <franke.daniel@gmail.com>
PR libgomp/28209
* libgomp.texi: New file.
* configure.ac: Add --enable-generated-files-in-srcdir option.
- * Makefile.am: Add info, dvi, pdf, html targets. On request,
- copy files to srcdir.
+ * Makefile.am: Add info, dvi, pdf, html targets. On request, copy
+ files to srcdir.
* Makefile.in: Regenerated.
+ * config.h.in: Regenerated.
* testsuite/Makefile.in: Regenerated.
* NOTES: Removed.
- Backport from mainline:
- 2007-01-14 Daniel Franke <franke.daniel@gmail.com>
- * libgomp.texi: Document implementation specific default values of
- environment variables.
-
-2007-01-24 Jakub Jelinek <jakub@redhat.com>
-
- PR middle-end/30494
- * testsuite/libgomp.c/pr30494.c: New test.
-
-2006-12-18 Daniel Franke <franke.daniel@gmail.com>
-
- Backport from mainline:
- 2006-12-04 Daniel Franke <franke.daniel@gmail.com>
+2006-12-04 Daniel Franke <franke.daniel@gmail.com>
PR libgomp/29949
* env.c (omp_set_num_threads): Set illegal thread count to 1.
- Backport from mainline:
- 2006-11-09 Uros Bizjak <ubizjak@gmail.com>
-
- * env.c (parse_schedule): Reject out of range values.
- (parse_unsigned_long): Reject out of range, negative
- or zero values.
-
2006-12-04 Eric Botcazou <ebotcazou@libertysurf.fr>
* configure: Regenerate.
@@ -135,6 +450,15 @@
* configure.tgt: Force initial-exec TLS model on Linux only.
+2006-11-13 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * configure: Regenerated.
+
+2006-11-09 Uros Bizjak <ubizjak@gmail.com>
+
+ * env.c (parse_schedule): Reject out of range values.
+ (parse_unsigned_long): Reject out of range, negative or zero values.
+
2006-10-29 Jakub Jelinek <jakub@redhat.com>
PR fortran/29629
diff --git a/contrib/gcclibs/libgomp/ChangeLog.gcc44 b/contrib/gcclibs/libgomp/ChangeLog.gcc44
new file mode 100644
index 0000000..234d010
--- /dev/null
+++ b/contrib/gcclibs/libgomp/ChangeLog.gcc44
@@ -0,0 +1,8 @@
+2008-09-19 Jakub Jelinek <jakub@redhat.com> (r140497)
+ Andreas Tobler <a.tobler@schweiz.org>
+
+ * config/bsd/proc.c: New file.
+ * configure.tgt (*-*-darwin*): Use config_path "darwin posix".
+ * configure.ac: Check for header <sys/sysctl.h>
+ * configure: Regenerate.
+ * config.h.in: Likewise.
diff --git a/contrib/gcclibs/libgomp/Makefile.am b/contrib/gcclibs/libgomp/Makefile.am
index c2bfbea..55e3bf3 100644
--- a/contrib/gcclibs/libgomp/Makefile.am
+++ b/contrib/gcclibs/libgomp/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-ACLOCAL_AMFLAGS = -I ../config
+ACLOCAL_AMFLAGS = -I .. -I ../config
SUBDIRS = testsuite
## May be used by toolexeclibdir.
@@ -12,9 +12,7 @@ search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) $(top_srcdir)
fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/finclude
libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
-empty =
-space = $(empty) $(empty)
-VPATH = $(subst $(space),:,$(strip $(search_path)))
+vpath % $(strip $(search_path))
AM_CPPFLAGS = $(addprefix -I, $(search_path))
AM_CFLAGS = $(XCFLAGS)
@@ -33,7 +31,7 @@ libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script)
libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
loop.c ordered.c parallel.c sections.c single.c team.c work.c \
- lock.c mutex.c proc.c sem.c bar.c time.c fortran.c
+ lock.c mutex.c proc.c sem.c bar.c time.c fortran.c affinity.c
nodist_noinst_HEADERS = libgomp_f.h
nodist_libsubinclude_HEADERS = omp.h
@@ -51,10 +49,19 @@ env.lo: libgomp_f.h
env.o: libgomp_f.h
-# No install-html target
-.PHONY: install-html
+# No install-html or install-pdf support in automake yet
+.PHONY: install-html install-pdf
install-html:
+install-pdf: $(PDFS)
+ @$(NORMAL_INSTALL)
+ test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)"
+ @list='$(PDFS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/$$f"; \
+ done
# Automake Documentation:
# If your package has Texinfo files in many directories, you can use the
diff --git a/contrib/gcclibs/libgomp/Makefile.in b/contrib/gcclibs/libgomp/Makefile.in
index 7fee1cc..57daccc 100644
--- a/contrib/gcclibs/libgomp/Makefile.in
+++ b/contrib/gcclibs/libgomp/Makefile.in
@@ -17,6 +17,7 @@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
+VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
@@ -37,24 +38,27 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
-DIST_COMMON = $(am__configure_deps) $(srcdir)/../config.guess \
- $(srcdir)/../config.sub $(srcdir)/../depcomp \
- $(srcdir)/../install-sh $(srcdir)/../ltmain.sh \
- $(srcdir)/../missing $(srcdir)/../mkinstalldirs \
- $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
- $(srcdir)/config.h.in $(srcdir)/libgomp.spec.in \
- $(srcdir)/libgomp_f.h.in $(srcdir)/omp.h.in \
- $(srcdir)/omp_lib.f90.in $(srcdir)/omp_lib.h.in \
- $(top_srcdir)/configure ChangeLog
+DIST_COMMON = $(srcdir)/../config.guess $(srcdir)/../config.sub \
+ ChangeLog $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/configure $(am__configure_deps) \
+ $(srcdir)/config.h.in $(srcdir)/../mkinstalldirs \
+ $(srcdir)/omp.h.in $(srcdir)/omp_lib.h.in \
+ $(srcdir)/omp_lib.f90.in $(srcdir)/libgomp_f.h.in \
+ $(srcdir)/libgomp.spec.in $(srcdir)/../depcomp \
+ $(srcdir)/../ltmain.sh $(srcdir)/../config.guess \
+ $(srcdir)/../config.sub
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
$(top_srcdir)/../config/depstand.m4 \
$(top_srcdir)/../config/enable.m4 \
+ $(top_srcdir)/../config/futex.m4 \
$(top_srcdir)/../config/lead-dot.m4 \
$(top_srcdir)/../config/multi.m4 \
$(top_srcdir)/../config/stdint.m4 \
- $(top_srcdir)/../config/tls.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/../config/tls.m4 $(top_srcdir)/../ltoptions.m4 \
+ $(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+ $(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -79,21 +83,20 @@ libgomp_la_LIBADD =
am_libgomp_la_OBJECTS = alloc.lo barrier.lo critical.lo env.lo \
error.lo iter.lo loop.lo ordered.lo parallel.lo sections.lo \
single.lo team.lo work.lo lock.lo mutex.lo proc.lo sem.lo \
- bar.lo time.lo fortran.lo
+ bar.lo time.lo fortran.lo affinity.lo
libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
depcomp = $(SHELL) $(top_srcdir)/../depcomp
am__depfiles_maybe = depfiles
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
-LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(libgomp_la_SOURCES)
-DIST_SOURCES = $(libgomp_la_SOURCES)
MULTISRCTOP =
MULTIBUILDTOP =
MULTIDIRS =
@@ -126,18 +129,6 @@ HEADERS = $(nodist_finclude_HEADERS) $(nodist_libsubinclude_HEADERS) \
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-distdir = $(PACKAGE)-$(VERSION)
-top_distdir = $(distdir)
-am__remove_distdir = \
- { test ! -d $(distdir) \
- || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
- && rm -fr $(distdir); }; }
-DIST_ARCHIVES = $(distdir).tar.gz
-GZIP_ENV = --best
-distuninstallcheck_listfiles = find . -type f -print
-distcleancheck_listfiles = find . -type f -print
-VPATH = $(subst $(space),:,$(strip $(search_path)))
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
@@ -157,6 +148,7 @@ CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
+DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
@@ -164,12 +156,15 @@ EGREP = @EGREP@
EXEEXT = @EXEEXT@
FC = @FC@
FCFLAGS = @FCFLAGS@
+FGREP = @FGREP@
GENINSRC_FALSE = @GENINSRC_FALSE@
GENINSRC_TRUE = @GENINSRC_TRUE@
+GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
LDFLAGS = @LDFLAGS@
LIBGOMP_BUILD_VERSIONED_SHLIB_FALSE = @LIBGOMP_BUILD_VERSIONED_SHLIB_FALSE@
LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE = @LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE@
@@ -182,6 +177,7 @@ MAINT = @MAINT@
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
+NM = @NM@
OBJEXT = @OBJEXT@
OMP_LOCK_ALIGN = @OMP_LOCK_ALIGN@
OMP_LOCK_KIND = @OMP_LOCK_KIND@
@@ -200,6 +196,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
RANLIB = @RANLIB@
SECTION_LDFLAGS = @SECTION_LDFLAGS@
+SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@@ -210,6 +207,7 @@ XCFLAGS = @XCFLAGS@
XLDFLAGS = @XLDFLAGS@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
ac_ct_FC = @ac_ct_FC@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
@@ -244,6 +242,7 @@ libexecdir = @libexecdir@
libtool_VERSION = @libtool_VERSION@
link_gomp = @link_gomp@
localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
mandir = @mandir@
mkdir_p = @mkdir_p@
multi_basedir = @multi_basedir@
@@ -260,14 +259,12 @@ target_os = @target_os@
target_vendor = @target_vendor@
toolexecdir = @toolexecdir@
toolexeclibdir = @toolexeclibdir@
-ACLOCAL_AMFLAGS = -I ../config
+ACLOCAL_AMFLAGS = -I .. -I ../config
SUBDIRS = testsuite
gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) $(top_srcdir)
fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/finclude
libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
-empty =
-space = $(empty) $(empty)
AM_CPPFLAGS = $(addprefix -I, $(search_path))
AM_CFLAGS = $(XCFLAGS)
AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS)
@@ -279,7 +276,7 @@ libgomp_version_info = -version-info $(libtool_VERSION)
libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script)
libgomp_la_SOURCES = alloc.c barrier.c critical.c env.c error.c iter.c \
loop.c ordered.c parallel.c sections.c single.c team.c work.c \
- lock.c mutex.c proc.c sem.c bar.c time.c fortran.c
+ lock.c mutex.c proc.c sem.c bar.c time.c fortran.c affinity.c
nodist_noinst_HEADERS = libgomp_f.h
nodist_libsubinclude_HEADERS = omp.h
@@ -406,6 +403,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bar.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/barrier.Plo@am__quote@
@@ -733,152 +731,6 @@ GTAGS:
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
- $(am__remove_distdir)
- mkdir $(distdir)
- $(mkdir_p) $(distdir)/. $(distdir)/.. $(distdir)/../config
- @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
- list='$(DISTFILES)'; for file in $$list; do \
- case $$file in \
- $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
- $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
- esac; \
- if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test "$$dir" != "$$file" && test "$$dir" != "."; then \
- dir="/$$dir"; \
- $(mkdir_p) "$(distdir)$$dir"; \
- else \
- dir=''; \
- fi; \
- if test -d $$d/$$file; then \
- if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
- cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
- fi; \
- cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
- else \
- test -f $(distdir)/$$file \
- || cp -p $$d/$$file $(distdir)/$$file \
- || exit 1; \
- fi; \
- done
- list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
- if test "$$subdir" = .; then :; else \
- test -d "$(distdir)/$$subdir" \
- || $(mkdir_p) "$(distdir)/$$subdir" \
- || exit 1; \
- distdir=`$(am__cd) $(distdir) && pwd`; \
- top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
- (cd $$subdir && \
- $(MAKE) $(AM_MAKEFLAGS) \
- top_distdir="$$top_distdir" \
- distdir="$$distdir/$$subdir" \
- distdir) \
- || exit 1; \
- fi; \
- done
- $(MAKE) $(AM_MAKEFLAGS) \
- top_distdir="$(top_distdir)" distdir="$(distdir)" \
- dist-info
- -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
- ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
- ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
- ! -type d ! -perm -444 -exec $(SHELL) $(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
- $(am__remove_distdir)
-
-dist-bzip2: distdir
- tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
- $(am__remove_distdir)
-
-dist-tarZ: distdir
- tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
- $(am__remove_distdir)
-
-dist-shar: distdir
- shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
- $(am__remove_distdir)
-
-dist-zip: distdir
- -rm -f $(distdir).zip
- zip -rq $(distdir).zip $(distdir)
- $(am__remove_distdir)
-
-dist dist-all: distdir
- tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
- $(am__remove_distdir)
-
-# This target untars the dist file and tries a VPATH configuration. Then
-# it guarantees that the distribution is self-contained by making another
-# tarfile.
-distcheck: dist
- case '$(DIST_ARCHIVES)' in \
- *.tar.gz*) \
- GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
- *.tar.bz2*) \
- bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
- *.tar.Z*) \
- uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
- *.shar.gz*) \
- GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
- *.zip*) \
- unzip $(distdir).zip ;;\
- esac
- chmod -R a-w $(distdir); chmod a+w $(distdir)
- mkdir $(distdir)/_build
- mkdir $(distdir)/_inst
- chmod a-w $(distdir)
- dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
- && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
- && cd $(distdir)/_build \
- && ../configure --srcdir=.. --prefix="$$dc_install_base" \
- $(DISTCHECK_CONFIGURE_FLAGS) \
- && $(MAKE) $(AM_MAKEFLAGS) \
- && $(MAKE) $(AM_MAKEFLAGS) dvi \
- && $(MAKE) $(AM_MAKEFLAGS) check \
- && $(MAKE) $(AM_MAKEFLAGS) install \
- && $(MAKE) $(AM_MAKEFLAGS) installcheck \
- && $(MAKE) $(AM_MAKEFLAGS) uninstall \
- && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
- distuninstallcheck \
- && chmod -R a-w "$$dc_install_base" \
- && ({ \
- (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
- && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
- && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
- && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
- distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
- } || { rm -rf "$$dc_destdir"; exit 1; }) \
- && rm -rf "$$dc_destdir" \
- && $(MAKE) $(AM_MAKEFLAGS) dist \
- && rm -rf $(DIST_ARCHIVES) \
- && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
- $(am__remove_distdir)
- @(echo "$(distdir) archives ready for distribution: "; \
- list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
- sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
-distuninstallcheck:
- @cd $(distuninstallcheck_dir) \
- && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
- || { echo "ERROR: files left after uninstall:" ; \
- if test -n "$(DESTDIR)"; then \
- echo " (check DESTDIR support)"; \
- fi ; \
- $(distuninstallcheck_listfiles) ; \
- exit 1; } >&2
-distcleancheck: distclean
- @if test '$(srcdir)' = . ; then \
- echo "ERROR: distcleancheck can only run from a VPATH build" ; \
- exit 1 ; \
- fi
- @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
- || { echo "ERROR: files left in build directory after distclean:" ; \
- $(distcleancheck_listfiles) ; \
- exit 1; } >&2
check-am: all-am
check: check-recursive
all-am: Makefile $(INFO_DEPS) $(LTLIBRARIES) all-multi $(HEADERS) \
@@ -1011,16 +863,13 @@ uninstall-info: uninstall-info-recursive
.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am all-local \
all-multi am--refresh check check-am clean clean-generic \
clean-libtool clean-multi clean-recursive \
- clean-toolexeclibLTLIBRARIES ctags ctags-recursive dist \
- dist-all dist-bzip2 dist-gzip dist-info dist-shar dist-tarZ \
- dist-zip distcheck distclean distclean-compile \
- distclean-generic distclean-hdr distclean-libtool \
- distclean-multi distclean-recursive distclean-tags \
- distcleancheck distdir distuninstallcheck dvi dvi-am html \
- html-am info info-am install install-am install-data \
- install-data-am install-exec install-exec-am install-info \
- install-info-am install-man install-multi \
- install-nodist_fincludeHEADERS \
+ clean-toolexeclibLTLIBRARIES ctags ctags-recursive dist-info \
+ distclean distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-multi distclean-recursive \
+ distclean-tags dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-multi install-nodist_fincludeHEADERS \
install-nodist_libsubincludeHEADERS \
install-nodist_toolexeclibHEADERS install-strip \
install-toolexeclibLTLIBRARIES installcheck installcheck-am \
@@ -1036,6 +885,8 @@ uninstall-info: uninstall-info-recursive
uninstall-toolexeclibLTLIBRARIES
+vpath % $(strip $(search_path))
+
omp_lib_kinds.mod: omp_lib.mod
:
omp_lib.mod: omp_lib.f90
@@ -1045,10 +896,20 @@ fortran.o: libgomp_f.h
env.lo: libgomp_f.h
env.o: libgomp_f.h
-# No install-html target
-.PHONY: install-html
+# No install-html or install-pdf support in automake yet
+.PHONY: install-html install-pdf
install-html:
+install-pdf: $(PDFS)
+ @$(NORMAL_INSTALL)
+ test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)"
+ @list='$(PDFS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/$$f"; \
+ done
+
all-local: $(STAMP_GENINSRC)
stamp-geninsrc: libgomp.info
diff --git a/contrib/gcclibs/libgomp/aclocal.m4 b/contrib/gcclibs/libgomp/aclocal.m4
index 31c2eec..eee6ec0 100644
--- a/contrib/gcclibs/libgomp/aclocal.m4
+++ b/contrib/gcclibs/libgomp/aclocal.m4
@@ -859,8 +859,13 @@ AC_SUBST([am__untar])
m4_include([../config/acx.m4])
m4_include([../config/depstand.m4])
m4_include([../config/enable.m4])
+m4_include([../config/futex.m4])
m4_include([../config/lead-dot.m4])
m4_include([../config/multi.m4])
m4_include([../config/stdint.m4])
m4_include([../config/tls.m4])
+m4_include([../ltoptions.m4])
+m4_include([../ltsugar.m4])
+m4_include([../ltversion.m4])
+m4_include([../lt~obsolete.m4])
m4_include([acinclude.m4])
diff --git a/contrib/gcclibs/libgomp/config.h.in b/contrib/gcclibs/libgomp/config.h.in
index 0c15993..fa4206b 100644
--- a/contrib/gcclibs/libgomp/config.h.in
+++ b/contrib/gcclibs/libgomp/config.h.in
@@ -12,9 +12,15 @@
/* Define if the POSIX Semaphores do not work on your system. */
#undef HAVE_BROKEN_POSIX_SEMAPHORES
+/* Define to 1 if the target assembler supports thread-local storage. */
+#undef HAVE_CC_TLS
+
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
/* Define to 1 if you have the `getloadavg' function. */
#undef HAVE_GETLOADAVG
@@ -24,6 +30,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
+/* Define if pthread_{,attr_}{g,s}etaffinity_np is supported. */
+#undef HAVE_PTHREAD_AFFINITY_NP
+
/* Define to 1 if you have the <semaphore.h> header file. */
#undef HAVE_SEMAPHORE_H
@@ -48,6 +57,9 @@
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#undef HAVE_SYS_SYSCTL_H
+
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
@@ -60,6 +72,10 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
/* Name of package */
#undef PACKAGE
diff --git a/contrib/gcclibs/libgomp/config/bsd/proc.c b/contrib/gcclibs/libgomp/config/bsd/proc.c
new file mode 100644
index 0000000..513d8df
--- /dev/null
+++ b/contrib/gcclibs/libgomp/config/bsd/proc.c
@@ -0,0 +1,117 @@
+/* Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc.
+ Contributed by Richard Henderson <rth@redhat.com>.
+
+ This file is part of the GNU OpenMP Library (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with libgomp; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* As a special exception, if you link this library with other files, some
+ of which are compiled with GCC, to produce an executable, this library
+ does not by itself cause the resulting executable to be covered by the
+ GNU General Public License. This exception does not however invalidate
+ any other reasons why the executable file might be covered by the GNU
+ General Public License. */
+
+/* This file contains system specific routines related to counting
+ online processors and dynamic load balancing. It is expected that
+ a system may well want to write special versions of each of these.
+
+ The following implementation uses a mix of POSIX and BSD routines. */
+
+#include "libgomp.h"
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef HAVE_GETLOADAVG
+# ifdef HAVE_SYS_LOADAVG_H
+# include <sys/loadavg.h>
+# endif
+#endif
+#ifdef HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+#endif
+
+static int
+get_num_procs (void)
+{
+#ifdef _SC_NPROCESSORS_ONLN
+ return sysconf (_SC_NPROCESSORS_ONLN);
+#elif defined HW_NCPU
+ int ncpus = 1;
+ size_t len = sizeof(ncpus);
+ sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
+ return ncpus;
+#else
+ return 0;
+#endif
+}
+
+/* At startup, determine the default number of threads. It would seem
+ this should be related to the number of cpus online. */
+
+void
+gomp_init_num_threads (void)
+{
+ int ncpus = get_num_procs ();
+
+ if (ncpus > 0)
+ gomp_global_icv.nthreads_var = ncpus;
+}
+
+/* When OMP_DYNAMIC is set, at thread launch determine the number of
+ threads we should spawn for this team. */
+/* ??? I have no idea what best practice for this is. Surely some
+ function of the number of processors that are *still* online and
+ the load average. Here I use the number of processors online
+ minus the 15 minute load average. */
+
+unsigned
+gomp_dynamic_max_threads (void)
+{
+ unsigned n_onln, loadavg;
+ unsigned nthreads_var = gomp_icv (false)->nthreads_var;
+
+ n_onln = get_num_procs ();
+ if (!n_onln || n_onln > nthreads_var)
+ n_onln = nthreads_var;
+
+ loadavg = 0;
+#ifdef HAVE_GETLOADAVG
+ {
+ double dloadavg[3];
+ if (getloadavg (dloadavg, 3) == 3)
+ {
+ /* Add 0.1 to get a kind of biased rounding. */
+ loadavg = dloadavg[2] + 0.1;
+ }
+ }
+#endif
+
+ if (loadavg >= n_onln)
+ return 1;
+ else
+ return n_onln - loadavg;
+}
+
+int
+omp_get_num_procs (void)
+{
+ int ncpus = get_num_procs ();
+ if (ncpus <= 0)
+ ncpus = gomp_icv (false)->nthreads_var;
+ return ncpus;
+}
+
+ialias (omp_get_num_procs)
diff --git a/contrib/gcclibs/libgomp/config/linux/affinity.c b/contrib/gcclibs/libgomp/config/linux/affinity.c
new file mode 100644
index 0000000..8fcce5f
--- /dev/null
+++ b/contrib/gcclibs/libgomp/config/linux/affinity.c
@@ -0,0 +1,107 @@
+/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU OpenMP Library (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with libgomp; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* As a special exception, if you link this library with other files, some
+ of which are compiled with GCC, to produce an executable, this library
+ does not by itself cause the resulting executable to be covered by the
+ GNU General Public License. This exception does not however invalidate
+ any other reasons why the executable file might be covered by the GNU
+ General Public License. */
+
+/* This is a Linux specific implementation of a CPU affinity setting. */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include "libgomp.h"
+#include <sched.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_PTHREAD_AFFINITY_NP
+
+static unsigned int affinity_counter;
+#ifndef HAVE_SYNC_BUILTINS
+static gomp_mutex_t affinity_lock;
+#endif
+
+void
+gomp_init_affinity (void)
+{
+ cpu_set_t cpuset;
+ size_t idx, widx;
+
+ if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset), &cpuset))
+ {
+ gomp_error ("could not get CPU affinity set");
+ free (gomp_cpu_affinity);
+ gomp_cpu_affinity = NULL;
+ gomp_cpu_affinity_len = 0;
+ return;
+ }
+
+ for (widx = idx = 0; idx < gomp_cpu_affinity_len; idx++)
+ if (gomp_cpu_affinity[idx] < CPU_SETSIZE
+ && CPU_ISSET (gomp_cpu_affinity[idx], &cpuset))
+ gomp_cpu_affinity[widx++] = gomp_cpu_affinity[idx];
+
+ if (widx == 0)
+ {
+ gomp_error ("no CPUs left for affinity setting");
+ free (gomp_cpu_affinity);
+ gomp_cpu_affinity = NULL;
+ gomp_cpu_affinity_len = 0;
+ return;
+ }
+
+ gomp_cpu_affinity_len = widx;
+ CPU_ZERO (&cpuset);
+ CPU_SET (gomp_cpu_affinity[0], &cpuset);
+ pthread_setaffinity_np (pthread_self (), sizeof (cpuset), &cpuset);
+ affinity_counter = 1;
+#ifndef HAVE_SYNC_BUILTINS
+ gomp_mutex_init (&affinity_lock);
+#endif
+}
+
+void
+gomp_init_thread_affinity (pthread_attr_t *attr)
+{
+ unsigned int cpu;
+ cpu_set_t cpuset;
+
+#ifdef HAVE_SYNC_BUILTINS
+ cpu = __sync_fetch_and_add (&affinity_counter, 1);
+#else
+ gomp_mutex_lock (&affinity_lock);
+ cpu = affinity_counter++;
+ gomp_mutex_unlock (&affinity_lock);
+#endif
+ cpu %= gomp_cpu_affinity_len;
+ CPU_ZERO (&cpuset);
+ CPU_SET (gomp_cpu_affinity[cpu], &cpuset);
+ pthread_attr_setaffinity_np (attr, sizeof (cpu_set_t), &cpuset);
+}
+
+#else
+
+#include "../posix/affinity.c"
+
+#endif
diff --git a/contrib/gcclibs/libgomp/config/linux/proc.c b/contrib/gcclibs/libgomp/config/linux/proc.c
new file mode 100644
index 0000000..2267cfb
--- /dev/null
+++ b/contrib/gcclibs/libgomp/config/linux/proc.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU OpenMP Library (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with libgomp; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* As a special exception, if you link this library with other files, some
+ of which are compiled with GCC, to produce an executable, this library
+ does not by itself cause the resulting executable to be covered by the
+ GNU General Public License. This exception does not however invalidate
+ any other reasons why the executable file might be covered by the GNU
+ General Public License. */
+
+/* This file contains system specific routines related to counting
+ online processors and dynamic load balancing. */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include "libgomp.h"
+#include <sched.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_GETLOADAVG
+# ifdef HAVE_SYS_LOADAVG_H
+# include <sys/loadavg.h>
+# endif
+#endif
+
+#ifdef HAVE_PTHREAD_AFFINITY_NP
+static unsigned long
+cpuset_popcount (cpu_set_t *cpusetp)
+{
+#ifdef CPU_COUNT
+ /* glibc 2.6 and above provide a macro for this. */
+ return CPU_COUNT (cpusetp);
+#else
+ size_t i;
+ unsigned long ret = 0;
+ extern int check[sizeof (cpusetp->__bits[0]) == sizeof (unsigned long int)];
+
+ (void) check;
+ for (i = 0; i < sizeof (*cpusetp) / sizeof (cpusetp->__bits[0]); i++)
+ {
+ unsigned long int mask = cpusetp->__bits[i];
+ if (mask == 0)
+ continue;
+ ret += __builtin_popcountl (mask);
+ }
+ return ret;
+#endif
+}
+#endif
+
+/* At startup, determine the default number of threads. It would seem
+ this should be related to the number of cpus online. */
+
+void
+gomp_init_num_threads (void)
+{
+#ifdef HAVE_PTHREAD_AFFINITY_NP
+ cpu_set_t cpuset;
+
+ if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset), &cpuset) == 0)
+ {
+ /* Count only the CPUs this process can use. */
+ gomp_nthreads_var = cpuset_popcount (&cpuset);
+ if (gomp_nthreads_var == 0)
+ gomp_nthreads_var = 1;
+ return;
+ }
+#endif
+#ifdef _SC_NPROCESSORS_ONLN
+ gomp_nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
+#endif
+}
+
+static int
+get_num_procs (void)
+{
+#ifdef HAVE_PTHREAD_AFFINITY_NP
+ cpu_set_t cpuset;
+
+ if (gomp_cpu_affinity == NULL)
+ {
+ /* Count only the CPUs this process can use. */
+ if (pthread_getaffinity_np (pthread_self (), sizeof (cpuset),
+ &cpuset) == 0)
+ {
+ int ret = cpuset_popcount (&cpuset);
+ return ret != 0 ? ret : 1;
+ }
+ }
+ else
+ {
+ size_t idx;
+ static int affinity_cpus;
+
+ /* We can't use pthread_getaffinity_np in this case
+ (we have changed it ourselves, it binds to just one CPU).
+ Count instead the number of different CPUs we are
+ using. */
+ CPU_ZERO (&cpuset);
+ if (affinity_cpus == 0)
+ {
+ int cpus = 0;
+ for (idx = 0; idx < gomp_cpu_affinity_len; idx++)
+ if (! CPU_ISSET (gomp_cpu_affinity[idx], &cpuset))
+ {
+ cpus++;
+ CPU_SET (gomp_cpu_affinity[idx], &cpuset);
+ }
+ affinity_cpus = cpus;
+ }
+ return affinity_cpus;
+ }
+#endif
+#ifdef _SC_NPROCESSORS_ONLN
+ return sysconf (_SC_NPROCESSORS_ONLN);
+#else
+ return gomp_nthreads_var;
+#endif
+}
+
+/* When OMP_DYNAMIC is set, at thread launch determine the number of
+ threads we should spawn for this team. */
+/* ??? I have no idea what best practice for this is. Surely some
+ function of the number of processors that are *still* online and
+ the load average. Here I use the number of processors online
+ minus the 15 minute load average. */
+
+unsigned
+gomp_dynamic_max_threads (void)
+{
+ unsigned n_onln, loadavg;
+
+ n_onln = get_num_procs ();
+ if (n_onln > gomp_nthreads_var)
+ n_onln = gomp_nthreads_var;
+
+ loadavg = 0;
+#ifdef HAVE_GETLOADAVG
+ {
+ double dloadavg[3];
+ if (getloadavg (dloadavg, 3) == 3)
+ {
+ /* Add 0.1 to get a kind of biased rounding. */
+ loadavg = dloadavg[2] + 0.1;
+ }
+ }
+#endif
+
+ if (loadavg >= n_onln)
+ return 1;
+ else
+ return n_onln - loadavg;
+}
+
+int
+omp_get_num_procs (void)
+{
+ return get_num_procs ();
+}
+
+ialias (omp_get_num_procs)
diff --git a/contrib/gcclibs/libgomp/config/mingw32/proc.c b/contrib/gcclibs/libgomp/config/mingw32/proc.c
new file mode 100644
index 0000000..def7bb5
--- /dev/null
+++ b/contrib/gcclibs/libgomp/config/mingw32/proc.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 2007 Free Software Foundation, Inc.
+ Contributed by Danny Smith <dannysmith@users.sourceforge.net>
+
+ This file is part of the GNU OpenMP Library (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with libgomp; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* As a special exception, if you link this library with other files, some
+ of which are compiled with GCC, to produce an executable, this library
+ does not by itself cause the resulting executable to be covered by the
+ GNU General Public License. This exception does not however invalidate
+ any other reasons why the executable file might be covered by the GNU
+ General Public License. */
+
+/* This file contains system specific routines related to counting
+ online processors and dynamic load balancing. It is expected that
+ a system may well want to write special versions of each of these.
+
+ The following implementation uses win32 API routines. */
+
+#include "libgomp.h"
+#include <windows.h>
+
+/* Count the CPU's currently available to this process. */
+static int
+count_avail_process_cpus ()
+{
+ DWORD_PTR process_cpus;
+ DWORD_PTR system_cpus;
+
+ if (GetProcessAffinityMask (GetCurrentProcess (),
+ &process_cpus, &system_cpus))
+ {
+ unsigned int count;
+ for (count = 0; process_cpus != 0; process_cpus >>= 1)
+ if (process_cpus & 1)
+ count++;
+ return count;
+ }
+ return 1;
+}
+
+/* At startup, determine the default number of threads. It would seem
+ this should be related to the number of cpus available to the process. */
+
+void
+gomp_init_num_threads (void)
+{
+ gomp_nthreads_var = count_avail_process_cpus ();
+}
+
+/* When OMP_DYNAMIC is set, at thread launch determine the number of
+ threads we should spawn for this team. FIXME: How do we adjust for
+ load average on MS Windows? */
+
+unsigned
+gomp_dynamic_max_threads (void)
+{
+ int n_onln = count_avail_process_cpus ();
+ return n_onln > gomp_nthreads_var ? gomp_nthreads_var : n_onln;
+}
+
+int
+omp_get_num_procs (void)
+{
+ return count_avail_process_cpus ();
+}
+
+ialias (omp_get_num_procs)
diff --git a/contrib/gcclibs/libgomp/config/posix/affinity.c b/contrib/gcclibs/libgomp/config/posix/affinity.c
new file mode 100644
index 0000000..67cb37a
--- /dev/null
+++ b/contrib/gcclibs/libgomp/config/posix/affinity.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ This file is part of the GNU OpenMP Library (libgomp).
+
+ Libgomp is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with libgomp; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* As a special exception, if you link this library with other files, some
+ of which are compiled with GCC, to produce an executable, this library
+ does not by itself cause the resulting executable to be covered by the
+ GNU General Public License. This exception does not however invalidate
+ any other reasons why the executable file might be covered by the GNU
+ General Public License. */
+
+/* This is a generic stub implementation of a CPU affinity setting. */
+
+#include "libgomp.h"
+
+void
+gomp_init_affinity (void)
+{
+}
+
+void
+gomp_init_thread_affinity (pthread_attr_t *attr)
+{
+ (void) attr;
+}
diff --git a/contrib/gcclibs/libgomp/configure b/contrib/gcclibs/libgomp/configure
index af4254c..a5cee6a 100755
--- a/contrib/gcclibs/libgomp/configure
+++ b/contrib/gcclibs/libgomp/configure
@@ -241,6 +241,155 @@ IFS=" $as_nl"
$as_unset CDPATH
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$lt_ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','`
+ ;;
+esac
+
+ECHO=${lt_ECHO-echo}
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $ECHO works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<_LT_EOF
+$*
+_LT_EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$lt_ECHO"; then
+ if test "X${echo_test_string+set}" != Xset; then
+ # find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
+ { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
+ then
+ break
+ fi
+ done
+ fi
+
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+ else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$ECHO" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ ECHO='print -r'
+ elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
+ else
+ # Try using printf.
+ ECHO='printf %s\n'
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ ECHO="$CONFIG_SHELL $0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$CONFIG_SHELL $0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+ if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "$0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ ECHO=echo
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+lt_ECHO=$ECHO
+if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+ lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
+fi
+
+
+
+
# Name of the host.
# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
# so uname gets run too.
@@ -308,7 +457,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS GENINSRC_TRUE GENINSRC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar multi_basedir toolexecdir toolexeclibdir CC ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CFLAGS AR ac_ct_AR RANLIB ac_ct_RANLIB PERL BUILD_INFO_TRUE BUILD_INFO_FALSE LN_S LIBTOOL enable_shared enable_static MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT FC FCFLAGS LDFLAGS ac_ct_FC libtool_VERSION CPP CPPFLAGS EGREP SECTION_LDFLAGS OPT_LDFLAGS LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE LIBGOMP_BUILD_VERSIONED_SHLIB_FALSE config_path XCFLAGS XLDFLAGS link_gomp USE_FORTRAN_TRUE USE_FORTRAN_FALSE OMP_LOCK_SIZE OMP_LOCK_ALIGN OMP_NEST_LOCK_SIZE OMP_NEST_LOCK_ALIGN OMP_LOCK_KIND OMP_NEST_LOCK_KIND LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS GENINSRC_TRUE GENINSRC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar multi_basedir toolexecdir toolexeclibdir CC ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CFLAGS AR ac_ct_AR RANLIB ac_ct_RANLIB PERL BUILD_INFO_TRUE BUILD_INFO_FALSE LIBTOOL SED EGREP FGREP GREP LD DUMPBIN ac_ct_DUMPBIN NM LN_S lt_ECHO CPP CPPFLAGS enable_shared enable_static MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT FC FCFLAGS LDFLAGS ac_ct_FC libtool_VERSION SECTION_LDFLAGS OPT_LDFLAGS LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE LIBGOMP_BUILD_VERSIONED_SHLIB_FALSE config_path XCFLAGS XLDFLAGS link_gomp USE_FORTRAN_TRUE USE_FORTRAN_FALSE OMP_LOCK_SIZE OMP_LOCK_ALIGN OMP_NEST_LOCK_SIZE OMP_NEST_LOCK_ALIGN OMP_LOCK_KIND OMP_NEST_LOCK_KIND LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -718,13 +867,13 @@ echo X"$0" |
/^X\(\/\).*/{ s//\1/; q; }
s/.*/./; q'`
srcdir=$ac_confdir
- if test ! -r "$srcdir/$ac_unique_file"; then
+ if test ! -r $srcdir/$ac_unique_file; then
srcdir=..
fi
else
ac_srcdir_defaulted=no
fi
-if test ! -r "$srcdir/$ac_unique_file"; then
+if test ! -r $srcdir/$ac_unique_file; then
if test "$ac_srcdir_defaulted" = yes; then
{ echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
{ (exit 1); exit 1; }; }
@@ -733,7 +882,7 @@ if test ! -r "$srcdir/$ac_unique_file"; then
{ (exit 1); exit 1; }; }
fi
fi
-(cd $srcdir && test -r "./$ac_unique_file") 2>/dev/null ||
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
{ echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
{ (exit 1); exit 1; }; }
srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
@@ -749,6 +898,14 @@ ac_env_target_alias_set=${target_alias+set}
ac_env_target_alias_value=$target_alias
ac_cv_env_target_alias_set=${target_alias+set}
ac_cv_env_target_alias_value=$target_alias
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
ac_env_FC_set=${FC+set}
ac_env_FC_value=$FC
ac_cv_env_FC_set=${FC+set}
@@ -761,14 +918,6 @@ ac_env_LDFLAGS_set=${LDFLAGS+set}
ac_env_LDFLAGS_value=$LDFLAGS
ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
ac_cv_env_LDFLAGS_value=$LDFLAGS
-ac_env_CPP_set=${CPP+set}
-ac_env_CPP_value=$CPP
-ac_cv_env_CPP_set=${CPP+set}
-ac_cv_env_CPP_value=$CPP
-ac_env_CPPFLAGS_set=${CPPFLAGS+set}
-ac_env_CPPFLAGS_value=$CPPFLAGS
-ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
-ac_cv_env_CPPFLAGS_value=$CPPFLAGS
#
# Report the --help message.
@@ -854,8 +1003,6 @@ Optional Features:
--enable-version-specific-runtime-libs
Specify that runtime libraries should be installed
in a compiler-specific directory [default=no]
- --enable-linux-futex Use the Linux futex system call
- [default=default]
--enable-generated-files-in-srcdir
put copies of generated files in source dir intended
for creating source tarballs for users without
@@ -863,12 +1010,17 @@ Optional Features:
--enable-multilib build many library versions (default)
--disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors
- --enable-shared=PKGS build shared libraries default=yes
- --enable-static=PKGS build static libraries default=yes
- --enable-fast-install=PKGS optimize for fast installation default=yes
+ --enable-shared[=PKGS]
+ build shared libraries [default=yes]
+ --enable-static[=PKGS]
+ build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
--disable-libtool-lock avoid locking (might break parallel builds)
--enable-maintainer-mode enable make rules and dependencies not useful
(and sometimes confusing) to the casual installer
+ --enable-linux-futex use the Linux futex system call
+ [default=default]
--enable-tls Use thread-local storage [default=yes]
--enable-symvers=STYLE enables symbol versioning of the shared library
[default=yes]
@@ -876,8 +1028,9 @@ Optional Features:
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --with-gnu-ld assume the C compiler uses GNU ld default=no
- --with-pic try to use only PIC/non-PIC objects default=use both
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
Some influential environment variables:
CC C compiler command
@@ -886,9 +1039,9 @@ Some influential environment variables:
nonstandard directory <lib dir>
CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
headers in a nonstandard directory <include dir>
+ CPP C preprocessor
FC Fortran compiler command
FCFLAGS Fortran compiler flags
- CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -1365,26 +1518,6 @@ fi;
echo "$as_me:$LINENO: result: $enable_version_specific_runtime_libs" >&5
echo "${ECHO_T}$enable_version_specific_runtime_libs" >&6
-echo "$as_me:$LINENO: checking for --enable-linux-futex" >&5
-echo $ECHO_N "checking for --enable-linux-futex... $ECHO_C" >&6
- # Check whether --enable-linux-futex or --disable-linux-futex was given.
-if test "${enable_linux_futex+set}" = set; then
- enableval="$enable_linux_futex"
-
- case "$enableval" in
- yes|no|default) ;;
- *) { { echo "$as_me:$LINENO: error: Unknown argument to enable/disable linux-futex" >&5
-echo "$as_me: error: Unknown argument to enable/disable linux-futex" >&2;}
- { (exit 1); exit 1; }; } ;;
- esac
-
-else
- enable_linux_futex=default
-fi;
-
-echo "$as_me:$LINENO: result: $enable_linux_futex" >&5
-echo "${ECHO_T}$enable_linux_futex" >&6
-
# We would like our source tree to be readonly. However when releases or
# pre-releases are generated, the flex/bison generated files as well as the
# various formats of manuals need to be included along with the rest of the
@@ -1556,7 +1689,7 @@ target_alias=${target_alias-$host_alias}
# we can do about that; they come from AC_INIT).
# foreign: we don't follow the normal rules for GNU packages (no COPYING
# file in the top srcdir, etc, etc), so stop complaining.
-# no-dependencies: turns off auto dependency generation (just for now)
+# no-dist: we don't want 'dist' and related rules.
# -Wall: turns on all automake warnings...
# -Wno-portability: ...except this one, since GNU make is required.
# -Wno-override: ... and this one, since we do want this in testsuite.
@@ -3526,13 +3659,10 @@ else
sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'`
case $ac_prog_version in
- '') gcc_cv_prog_makeinfo_modern=no;;
- 4.[4-9]*) gcc_cv_prog_makeinfo_modern=yes;;
- *) gcc_cv_prog_makeinfo_modern=no;;
- esac
- if test $gcc_cv_prog_makeinfo_modern = no; then
- MAKEINFO="${CONFIG_SHELL-/bin/sh} $ac_aux_dir/missing makeinfo"
- fi
+ '') gcc_cv_prog_makeinfo_modern=no;;
+ 4.[4-9]*|4.[1-9][0-9]*|[5-9]*|[1-9][0-9]*) gcc_cv_prog_makeinfo_modern=yes;;
+ *) gcc_cv_prog_makeinfo_modern=no;;
+ esac
fi
echo "$as_me:$LINENO: result: $gcc_cv_prog_makeinfo_modern" >&5
@@ -3540,6 +3670,9 @@ echo "${ECHO_T}$gcc_cv_prog_makeinfo_modern" >&6
else
gcc_cv_prog_makeinfo_modern=no
fi
+ if test $gcc_cv_prog_makeinfo_modern = no; then
+ MAKEINFO="${CONFIG_SHELL-/bin/sh} $ac_aux_dir/missing makeinfo"
+ fi
@@ -3554,73 +3687,264 @@ fi
# Configure libtool
+
+
+macro_version='2.1a'
+macro_revision='1.2435'
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Set options
+
+enable_dlopen=no
+
+
+enable_win32_dll=no
+
+
# Check whether --enable-shared or --disable-shared was given.
if test "${enable_shared+set}" = set; then
enableval="$enable_shared"
p=${PACKAGE-default}
-case $enableval in
-yes) enable_shared=yes ;;
-no) enable_shared=no ;;
-*)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
else
enable_shared=yes
fi;
+
+
+
+
+
+
+
+
# Check whether --enable-static or --disable-static was given.
if test "${enable_static+set}" = set; then
enableval="$enable_static"
p=${PACKAGE-default}
-case $enableval in
-yes) enable_static=yes ;;
-no) enable_static=no ;;
-*)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
else
enable_static=yes
fi;
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic or --without-pic was given.
+if test "${with_pic+set}" = set; then
+ withval="$with_pic"
+ pic_mode="$withval"
+else
+ pic_mode=default
+fi;
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
# Check whether --enable-fast-install or --disable-fast-install was given.
if test "${enable_fast_install+set}" = set; then
enableval="$enable_fast_install"
p=${PACKAGE-default}
-case $enableval in
-yes) enable_fast_install=yes ;;
-no) enable_fast_install=no ;;
-*)
- enable_fast_install=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
else
enable_fast_install=yes
fi;
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
+echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6
+if test "${lt_cv_path_SED+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+
+fi
+
+SED=$lt_cv_path_SED
+
+echo "$as_me:$LINENO: result: $SED" >&5
+echo "${ECHO_T}$SED" >&6
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for fgrep" >&5
+echo $ECHO_N "checking for fgrep... $ECHO_C" >&6
+if test "${ac_cv_prog_fgrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo 'ab*c' | (grep -F 'ab*c') >/dev/null 2>&1
+ then ac_cv_prog_fgrep='grep -F'
+ else ac_cv_prog_fgrep='fgrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_fgrep" >&5
+echo "${ECHO_T}$ac_cv_prog_fgrep" >&6
+ FGREP=$ac_cv_prog_fgrep
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# Check whether --with-gnu-ld or --without-gnu-ld was given.
if test "${with_gnu_ld+set}" = set; then
withval="$with_gnu_ld"
@@ -3631,8 +3955,8 @@ fi;
ac_prog=ld
if test "$GCC" = yes; then
# Check if gcc -print-prog-name=ld gives a path.
- echo "$as_me:$LINENO: checking for ld used by GCC" >&5
-echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6
+ echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
case $host in
*-*-mingw*)
# gcc leaves a trailing carriage return which upsets mingw
@@ -3642,12 +3966,12 @@ echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6
esac
case $ac_prog in
# Accept absolute paths.
- [\\/]* | [A-Za-z]:[\\/]*)
+ [\\/]* | ?:[\\/]*)
re_direlt='/[^/][^/]*/\.\./'
- # Canonicalize the path of ld
- ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
- while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
done
test -z "$LD" && LD="$ac_prog"
;;
@@ -3671,22 +3995,26 @@ if test "${lt_cv_path_LD+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test -z "$LD"; then
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
lt_cv_path_LD="$ac_dir/$ac_prog"
# Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
+ # but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
- if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
test "$with_gnu_ld" != no && break
- else
+ ;;
+ *)
test "$with_gnu_ld" != yes && break
- fi
+ ;;
+ esac
fi
done
- IFS="$ac_save_ifs"
+ IFS="$lt_save_ifs"
else
lt_cv_path_LD="$LD" # Let the user override the test with a path.
fi
@@ -3708,32 +4036,31 @@ echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
if test "${lt_cv_prog_gnu_ld+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- # I'd rather use --version here, but apparently some GNU ld's only accept -v.
-if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
lt_cv_prog_gnu_ld=yes
-else
+ ;;
+*)
lt_cv_prog_gnu_ld=no
-fi
+ ;;
+esac
fi
echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
with_gnu_ld=$lt_cv_prog_gnu_ld
-echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
-echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6
-if test "${lt_cv_ld_reload_flag+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- lt_cv_ld_reload_flag='-r'
-fi
-echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
-echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6
-reload_flag=$lt_cv_ld_reload_flag
-test -n "$reload_flag" && reload_flag=" $reload_flag"
-echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
-echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for BSD- or MS-compatible name lister (nm)" >&5
+echo $ECHO_N "checking for BSD- or MS-compatible name lister (nm)... $ECHO_C" >&6
if test "${lt_cv_path_NM+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
@@ -3741,35 +4068,173 @@ else
# Let the user override the test.
lt_cv_path_NM="$NM"
else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
- for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
- test -z "$ac_dir" && ac_dir=.
- tmp_nm=$ac_dir/${ac_tool_prefix}nm
- if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then
- lt_cv_path_NM="$tmp_nm -B"
- break
- elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- lt_cv_path_NM="$tmp_nm -p"
- break
- else
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
fi
- fi
+ done
+ IFS="$lt_save_ifs"
done
- IFS="$ac_save_ifs"
- test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+ : ${lt_cv_path_NM=no}
+fi
+fi
+echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5
+echo "${ECHO_T}$lt_cv_path_NM" >&6
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_DUMPBIN+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ echo "$as_me:$LINENO: result: $DUMPBIN" >&5
+echo "${ECHO_T}$DUMPBIN" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
fi
fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ echo "$as_me:$LINENO: result: $ac_ct_DUMPBIN" >&5
+echo "${ECHO_T}$ac_ct_DUMPBIN" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+test -n "$ac_ct_DUMPBIN" || ac_ct_DUMPBIN=":"
-NM="$lt_cv_path_NM"
-echo "$as_me:$LINENO: result: $NM" >&5
-echo "${ECHO_T}$NM" >&6
+ DUMPBIN=$ac_ct_DUMPBIN
+fi
+
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking the name lister ($NM) interface" >&5
+echo $ECHO_N "checking the name lister ($NM) interface... $ECHO_C" >&6
+if test "${lt_cv_nm_interface+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:4223: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:4226: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:4229: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+echo "$as_me:$LINENO: result: $lt_cv_nm_interface" >&5
+echo "${ECHO_T}$lt_cv_nm_interface" >&6
echo "$as_me:$LINENO: checking whether ln -s works" >&5
echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
@@ -3782,8 +4247,234 @@ else
echo "${ECHO_T}no, using $LN_S" >&6
fi
-echo "$as_me:$LINENO: checking how to recognise dependant libraries" >&5
-echo $ECHO_N "checking how to recognise dependant libraries... $ECHO_C" >&6
+# find the maximum length of command line arguments
+echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
+echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`getconf ARG_MAX 2> /dev/null`
+ if test -n $lt_cv_sys_max_cmd_len; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
+ = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
+echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6
+else
+ echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+echo "$as_me:$LINENO: checking whether the shell understands some XSI constructs" >&5
+echo $ECHO_N "checking whether the shell understands some XSI constructs... $ECHO_C" >&6
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+echo "$as_me:$LINENO: result: $xsi_shell" >&5
+echo "${ECHO_T}$xsi_shell" >&6
+
+
+echo "$as_me:$LINENO: checking whether the shell understands \"+=\"" >&5
+echo $ECHO_N "checking whether the shell understands \"+=\"... $ECHO_C" >&6
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+echo "$as_me:$LINENO: result: $lt_shell_append" >&5
+echo "${ECHO_T}$lt_shell_append" >&6
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
+echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6
+if test "${lt_cv_ld_reload_flag+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
+echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5
+echo $ECHO_N "checking how to recognize dependent libraries... $ECHO_C" >&6
if test "${lt_cv_deplibs_check_method+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
@@ -3796,13 +4487,13 @@ lt_cv_deplibs_check_method='unknown'
# `unknown' -- same as none, but documents that we really don't know.
# 'pass_all' -- all dependencies passed with no checks.
# 'test_compile' -- check by making test program.
-# 'file_magic [regex]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given egrep regex.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
# If you have `file' or equivalent on your system and you're not sure
# whether `pass_all' will *always* work, you probably want this one.
case $host_os in
-aix*)
+aix[4-9]*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -3810,39 +4501,42 @@ beos*)
lt_cv_deplibs_check_method=pass_all
;;
-bsdi4*)
+bsdi[45]*)
lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
lt_cv_file_magic_cmd='/usr/bin/file -L'
lt_cv_file_magic_test_file=/shlib/libc.so
;;
-cygwin* | mingw* |pw32*)
- lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
;;
darwin* | rhapsody*)
- # this will be overwritten by pass_all, but leave it in just in case
- lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- case "$host_os" in
- rhapsody* | darwin1.012)
- lt_cv_file_magic_test_file='/System/Library/Frameworks/System.framework/System'
- ;;
- *) # Darwin 1.3 on
- lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib'
- ;;
- esac
lt_cv_deplibs_check_method=pass_all
;;
-freebsd* | kfreebsd*-gnu)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
case $host_cpu in
i*86 )
# Not sure whether the presence of OpenBSD here was a mistake.
# Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
lt_cv_file_magic_cmd=/usr/bin/file
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
;;
@@ -3856,92 +4550,116 @@ gnu*)
lt_cv_deplibs_check_method=pass_all
;;
-hpux10.20*|hpux11*)
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
case $host_cpu in
- hppa*)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
ia64*)
lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
- lt_cv_file_magic_cmd=/usr/bin/file
lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
;;
- esac
- ;;
-
-irix5* | irix6*)
- case $host_os in
- irix5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
;;
*)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
;;
esac
- lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*`
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
lt_cv_deplibs_check_method=pass_all
;;
# This must be Linux ELF.
-linux-gnu*)
+linux* | k*bsd*-gnu)
lt_cv_deplibs_check_method=pass_all
;;
-netbsd* | knetbsd*-gnu)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
- lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$'
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
else
- lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$'
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
fi
;;
-newsos6)
+newos6*)
lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
lt_cv_file_magic_cmd=/usr/bin/file
lt_cv_file_magic_test_file=/usr/lib/libnls.so
;;
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
osf3* | osf4* | osf5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method='file_magic COFF format alpha shared library'
- lt_cv_file_magic_test_file=/shlib/libc.so
lt_cv_deplibs_check_method=pass_all
;;
-sco3.2v5*)
+rdos*)
lt_cv_deplibs_check_method=pass_all
;;
solaris*)
lt_cv_deplibs_check_method=pass_all
- lt_cv_file_magic_test_file=/lib/libc.so
;;
-sysv5uw[78]* | sysv4*uw2*)
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
lt_cv_deplibs_check_method=pass_all
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
case $host_vendor in
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
motorola)
lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
esac
;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
esac
fi
@@ -3949,223 +4667,29 @@ echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6
file_magic_cmd=$lt_cv_file_magic_cmd
deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
-# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
-
-# find the maximum length of command line arguments
-echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
-echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6
-if test "${lt_cv_sys_max_cmd_len+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- i=0
- teststring="ABCD"
-
- case $build_os in
- msdosdjgpp*)
- # On DJGPP, this test can blow up pretty badly due to problems in libc
- # (any single argument exceeding 2000 bytes causes a buffer overrun
- # during glob expansion). Even if it were fixed, the result of this
- # check would be larger than it should be.
- lt_cv_sys_max_cmd_len=12288; # 12K is about right
- ;;
-
- cygwin* | mingw*)
- # On Win9x/ME, this test blows up -- it succeeds, but takes
- # about 5 minutes as the teststring grows exponentially.
- # Worse, since 9x/ME are not pre-emptively multitasking,
- # you end up with a "frozen" computer, even though with patience
- # the test eventually succeeds (with a max line length of 256k).
- # Instead, let's just punt: use the minimum linelength reported by
- # all of the supported platforms: 8192 (on NT/2K/XP).
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- amigaos*)
- # On AmigaOS with pdksh, this test takes hours, literally.
- # So we just punt and use a minimum line length of 8192.
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
- # This has been around since 386BSD, at least. Likely further.
- if test -x /sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
- elif test -x /usr/sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
- else
- lt_cv_sys_max_cmd_len=65536 # usable default for *BSD
- fi
- # And add a safety zone
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
- ;;
- esac
-
-fi
-
-if test -n "$lt_cv_sys_max_cmd_len" ; then
- echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
-echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6
-else
- echo "$as_me:$LINENO: result: none" >&5
-echo "${ECHO_T}none" >&6
-fi
-
-
-# Only perform the check for file, if the check method requires it
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
-echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6
-if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- case $MAGIC_CMD in
- /*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
- ;;
- ?:/*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
- ;;
- *)
- ac_save_MAGIC_CMD="$MAGIC_CMD"
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="/usr/bin:$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/${ac_tool_prefix}file; then
- lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- egrep "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS="$ac_save_ifs"
- MAGIC_CMD="$ac_save_MAGIC_CMD"
- ;;
-esac
-fi
-
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
- echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
-echo "${ECHO_T}$MAGIC_CMD" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-if test -z "$lt_cv_path_MAGIC_CMD"; then
- if test -n "$ac_tool_prefix"; then
- echo "$as_me:$LINENO: checking for file" >&5
-echo $ECHO_N "checking for file... $ECHO_C" >&6
-if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- case $MAGIC_CMD in
- /*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
- ;;
- ?:/*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
- ;;
- *)
- ac_save_MAGIC_CMD="$MAGIC_CMD"
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="/usr/bin:$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/file; then
- lt_cv_path_MAGIC_CMD="$ac_dir/file"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- egrep "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<EOF 1>&2
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS="$ac_save_ifs"
- MAGIC_CMD="$ac_save_MAGIC_CMD"
- ;;
-esac
-fi
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
- echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
-echo "${ECHO_T}$MAGIC_CMD" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
- else
- MAGIC_CMD=:
- fi
-fi
- fi
- ;;
-esac
if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
echo "$as_me:$LINENO: checking for $ac_word" >&5
echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_RANLIB+set}" = set; then
+if test "${ac_cv_prog_AR+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
@@ -4174,7 +4698,7 @@ do
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
@@ -4183,27 +4707,27 @@ done
fi
fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- echo "$as_me:$LINENO: result: $RANLIB" >&5
-echo "${ECHO_T}$RANLIB" >&6
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
else
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
fi
fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
echo "$as_me:$LINENO: checking for $ac_word" >&5
echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
@@ -4212,30 +4736,43 @@ do
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_RANLIB="ranlib"
+ ac_cv_prog_ac_ct_AR="ar"
echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
- test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+ test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false"
fi
fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
-echo "${ECHO_T}$ac_ct_RANLIB" >&6
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
else
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
fi
- RANLIB=$ac_ct_RANLIB
+ AR=$ac_ct_AR
else
- RANLIB="$ac_cv_prog_RANLIB"
+ AR="$ac_cv_prog_AR"
fi
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+
+
+
+
+
+
+
+
+
+
+
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
set dummy ${ac_tool_prefix}strip; ac_word=$2
@@ -4316,96 +4853,472 @@ else
STRIP="$ac_cv_prog_STRIP"
fi
+test -z "$STRIP" && STRIP=:
-# Check for any special flags to pass to ltconfig.
-libtool_flags="--cache-file=$cache_file"
-test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
-test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
-test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install"
-test "$GCC" = yes && libtool_flags="$libtool_flags --with-gcc"
-test "$lt_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
-# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
-if test "${enable_libtool_lock+set}" = set; then
- enableval="$enable_libtool_lock"
-fi;
-test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock"
-test x"$silent" = xyes && libtool_flags="$libtool_flags --silent"
-# Check whether --with-pic or --without-pic was given.
-if test "${with_pic+set}" = set; then
- withval="$with_pic"
- pic_mode="$withval"
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- pic_mode=default
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5
+echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
+ (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -f conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ echo "$as_me:$LINENO: result: failed" >&5
+echo "${ECHO_T}failed" >&6
+else
+ echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+ enableval="$enable_libtool_lock"
+
fi;
-test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic"
-test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic"
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
# Some flags need to be propagated to the compiler or linker for good
# libtool support.
case $host in
-*-*-irix6*)
+ia64-*-hpux*)
# Find out which ABI we are using.
- echo '#line 4353 "configure"' > conftest.$ac_ext
+ echo 'int i;' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; then
- if test "$lt_cv_prog_gnu_ld" = yes; then
case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -melf32bsmip"
- ;;
- *N32*)
- LD="${LD-ld} -melf32bmipn32"
- ;;
- *64-bit*)
- LD="${LD-ld} -melf64bmip"
- ;;
- esac
- else
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
esac
- fi
fi
rm -rf conftest*
;;
-
-ia64-*-hpux*)
+*-*-irix6*)
# Find out which ABI we are using.
- echo 'int i;' > conftest.$ac_ext
+ echo '#line 5285 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; then
- case "`/usr/bin/file conftest.o`" in
- *ELF-32*)
- HPUX_IA64_MODE="32"
- ;;
- *ELF-64*)
- HPUX_IA64_MODE="64"
- ;;
- esac
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
fi
rm -rf conftest*
;;
-x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
@@ -4413,39 +5326,45 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; then
- case "`/usr/bin/file conftest.o`" in
- *32-bit*)
- case $host in
- x86_64-*linux*)
- LD="${LD-ld} -m elf_i386"
- ;;
- ppc64-*linux*|powerpc64-*linux*)
- LD="${LD-ld} -m elf32ppclinux"
- ;;
- s390x-*linux*)
- LD="${LD-ld} -m elf_s390"
- ;;
- sparc64-*linux*)
- LD="${LD-ld} -m elf32_sparc"
- ;;
- esac
- ;;
- *64-bit*)
- case $host in
- x86_64-*linux*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- ppc*-*linux*|powerpc*-*linux*)
- LD="${LD-ld} -m elf64ppc"
- ;;
- s390*-*linux*)
- LD="${LD-ld} -m elf64_s390"
- ;;
- sparc*-*linux*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- ;;
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
esac
fi
rm -rf conftest*
@@ -4460,9 +5379,7 @@ echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6
if test "${lt_cv_cc_needs_belf+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
-
-
- ac_ext=c
+ ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
@@ -4528,114 +5445,4553 @@ echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6
CFLAGS="$SAVE_CFLAGS"
fi
;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *) LD="${LD-ld} -64" ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+echo "$as_me:$LINENO: checking for objdir" >&5
+echo $ECHO_N "checking for objdir... $ECHO_C" >&6
+if test "${lt_cv_objdir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5
+echo "${ECHO_T}$lt_cv_objdir" >&6
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
+echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ echo "$as_me:$LINENO: checking for file" >&5
+echo $ECHO_N "checking for file... $ECHO_C" >&6
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+
+ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:6385: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:6389: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ if test "$host_cpu" = m68k; then
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ fi
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ lt_prog_compiler_pic='-qnocommon'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ icc* | ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Sun\ F*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic" >&6
+
+
+
+
-# Save cache, so that ltconfig can load it
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems. If it contains results you don't
-# want to keep, you may remove or edit it.
#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
+# Check to make sure the PIC flag actually works.
#
-# `ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
+if test -n "$lt_prog_compiler_pic"; then
+ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:6707: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:6711: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6
+
+if test x"$lt_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_static_works=yes
+ fi
+ else
+ lt_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works" >&6
+
+if test x"$lt_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:6812: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:6816: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:6867: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:6871: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ if test "$host_cpu" = m68k; then
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ fi
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ *)
+ tmp_sharedflag='-shared' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, don't put newlines in cache variables' values.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
+int
+main ()
{
- (set) 2>&1 |
- case `(ac_space=' '; set | grep ac_space) 2>&1` in
- *ac_space=\ *)
- # `set' does not quote correctly, so add quotes (double-quote
- # substitution turns \\\\ into \\, and sed turns \\ into \).
- sed -n \
- "s/'/'\\\\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ if test "$host_cpu" = m68k; then
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ fi
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[012])
+ allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ ;;
+ esac
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ whole_archive_flag_spec=''
+ link_all_deplibs=yes
+ if test "$GCC" = yes ; then
+ if test "${lt_cv_apple_cc_single_mod+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi-module to the
+ # link flags.
+ echo "int foo(void){return 1;}" > conftest.c
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib ${wl}-single_module conftest.c
+ if test -f libconftest.dylib; then
+ lt_cv_apple_cc_single_mod=yes
+ rm libconftest.dylib
+ fi
+ rm conftest.$ac_ext
+ fi
+fi
+
+ output_verbose_link_cmd=echo
+ if test "X$lt_cv_apple_cc_single_mod" = Xyes ; then
+ archive_cmds='$CC -dynamiclib $single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ archive_expsym_cmds='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $single_module -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ archive_expsym_cmds='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ module_expsym_cmds='sed -e "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd=echo
+ archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`$ECHO $rpath/$soname` $verstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat >conftest.$ac_ext <<_ACEOF
+int foo(void) {}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
*)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n \
- "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ld_shlibs=no
;;
- esac;
-} |
- sed '
- t clear
- : clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
- t end
- /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
- : end' >>confcache
-if diff $cache_file confcache >/dev/null 2>&1; then :; else
- if test -w $cache_file; then
- test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
- cat confcache >$cache_file
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs" >&5
+echo "${ECHO_T}$ld_shlibs" >&6
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc=no
+ else
+ archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5
+echo "${ECHO_T}$archive_cmds_need_lc" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+withGCC=$GCC
+if test "$withGCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
else
- echo "not updating unwritable cache $cache_file"
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ if test "$host_cpu" = m68k; then
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ else
+ dynamic_linker=no
+ fi
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $withGCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # Some binutils ld are patched to set DT_RUNPATH
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir"; then
+ shlibpath_overrides_runpath=yes
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_name_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi
-rm -f confcache
-# Actually configure libtool. ac_aux_dir is where install-sh is found.
-AR="$AR" LTCC="$CC" CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
-MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
-LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \
-AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \
-objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \
-deplibs_check_method="$deplibs_check_method" file_magic_cmd="$file_magic_cmd" \
-${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \
-$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \
-|| { { echo "$as_me:$LINENO: error: libtool configure failed" >&5
-echo "$as_me: error: libtool configure failed" >&2;}
- { (exit 1); exit 1; }; }
-# Reload cache, that may have been modified by ltconfig
-if test -r "$cache_file"; then
- # Some versions of bash will fail to source /dev/null (special
- # files actually), so we avoid doing that.
- if test -f "$cache_file"; then
- { echo "$as_me:$LINENO: loading cache $cache_file" >&5
-echo "$as_me: loading cache $cache_file" >&6;}
- case $cache_file in
- [\\/]* | ?:[\\/]* ) . $cache_file;;
- *) . ./$cache_file;;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action" >&5
+echo "${ECHO_T}$hardcode_action" >&6
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+char (*f) () = shl_load;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != shl_load;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+char (*f) () = dlopen;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != dlopen;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_svld_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link ();
+int
+main ()
+{
+dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_dld_link=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 9664 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ exit (status);
+}
+_LT_EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
fi
+fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- { echo "$as_me:$LINENO: creating cache $cache_file" >&5
-echo "$as_me: creating cache $cache_file" >&6;}
- >$cache_file
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 9764 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ exit (status);
+}
+_LT_EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
fi
+rm -fr conftest*
+
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ fi
+ ;;
+ *)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+ echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh $ac_aux_dir/ltcf-c.sh"
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-# Redirect the config.log output again, so that the ltconfig log is not
-# clobbered by the next message.
-exec 5>>./config.log
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
@@ -4760,7 +10116,7 @@ fi
# Provide some information about the compiler.
-echo "$as_me:4763:" \
+echo "$as_me:10119:" \
"checking for Fortran compiler version" >&5
ac_compiler=`set X $ac_compile; echo $2`
{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
@@ -4903,241 +10259,2926 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-FCFLAGS="$FCFLAGS -Wall"
-# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=1:0:0
+ac_ext=${FC_SRCEXT-f}
+ac_compile='$FC -c $FCFLAGS $FCFLAGS_SRCEXT conftest.$ac_ext >&5'
+ac_link='$FC -o conftest$ac_exeext $FCFLAGS $LDFLAGS $FCFLAGS_SRCEXT conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_fc_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in f95 fort xlf95 ifc efc pgf95 lf95 gfortran f90 xlf90 pgf90 epcf90 g77 f77 xlf frt pgf77 fort77 fl32 af77
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_FC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$FC"; then
+ ac_cv_prog_FC="$FC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_FC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+fi
+fi
+FC=$ac_cv_prog_FC
+if test -n "$FC"; then
+ echo "$as_me:$LINENO: result: $FC" >&5
+echo "${ECHO_T}$FC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
-# Check header files.
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
-echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
+ test -n "$FC" && break
+ done
fi
-if test -z "$CPP"; then
- if test "${ac_cv_prog_CPP+set}" = set; then
+if test -z "$FC"; then
+ ac_ct_FC=$FC
+ for ac_prog in f95 fort xlf95 ifc efc pgf95 lf95 gfortran f90 xlf90 pgf90 epcf90 g77 f77 xlf frt pgf77 fort77 fl32 af77
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_FC+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- # Double quotes because CPP needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
- do
- ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
+ if test -n "$ac_ct_FC"; then
+ ac_cv_prog_ac_ct_FC="$ac_ct_FC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_FC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_FC=$ac_cv_prog_ac_ct_FC
+if test -n "$ac_ct_FC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_FC" >&5
+echo "${ECHO_T}$ac_ct_FC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_FC" && break
+done
+
+ FC=$ac_ct_FC
+fi
+
+
+# Provide some information about the compiler.
+echo "$as_me:10355:" \
+ "checking for Fortran compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+rm -f a.out
+
+# If we don't use `.F' as extension, the preprocessor is not run on the
+# input file. (Note that this only needs to work for GNU compilers.)
+ac_save_ext=$ac_ext
+ac_ext=F
+echo "$as_me:$LINENO: checking whether we are using the GNU Fortran compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU Fortran compiler... $ECHO_C" >&6
+if test "${ac_cv_fc_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
+ program main
+#ifndef __GNUC__
+ choke me
#endif
- Syntax error
+
+ end
_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- :
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_fc_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
- # Broken: fails on valid input.
-continue
+ac_compiler_gnu=no
fi
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_fc_compiler_gnu=$ac_compiler_gnu
- # OK, works on sane cases. Now check whether non-existent headers
- # can be detected and how.
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
+fi
+echo "$as_me:$LINENO: result: $ac_cv_fc_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_fc_compiler_gnu" >&6
+ac_ext=$ac_save_ext
+ac_test_FFLAGS=${FCFLAGS+set}
+ac_save_FFLAGS=$FCFLAGS
+FCFLAGS=
+echo "$as_me:$LINENO: checking whether $FC accepts -g" >&5
+echo $ECHO_N "checking whether $FC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_fc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ FCFLAGS=-g
+cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_fc_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_fc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_fc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_fc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_fc_g" >&6
+if test "$ac_test_FFLAGS" = set; then
+ FCFLAGS=$ac_save_FFLAGS
+elif test $ac_cv_prog_fc_g = yes; then
+ if test "x$ac_cv_fc_compiler_gnu" = xyes; then
+ FCFLAGS="-g -O2"
else
- ac_cpp_err=
+ FCFLAGS="-g"
fi
else
- ac_cpp_err=yes
+ if test "x$ac_cv_fc_compiler_gnu" = xyes; then
+ FCFLAGS="-O2"
+ else
+ FCFLAGS=
+ fi
fi
-if test -z "$ac_cpp_err"; then
- # Broken: success on invalid input.
-continue
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- # Passes both tests.
-ac_preproc_ok=:
-break
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
fi
-rm -f conftest.err conftest.$ac_ext
+
+
+ ac_ext=${FC_SRCEXT-f}
+ac_compile='$FC -c $FCFLAGS $FCFLAGS_SRCEXT conftest.$ac_ext >&5'
+ac_link='$FC -o conftest$ac_exeext $FCFLAGS $LDFLAGS $FCFLAGS_SRCEXT conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_fc_compiler_gnu
+
+
+archive_cmds_need_lc_FC=no
+allow_undefined_flag_FC=
+always_export_symbols_FC=no
+archive_expsym_cmds_FC=
+export_dynamic_flag_spec_FC=
+hardcode_direct_FC=no
+hardcode_direct_absolute_FC=no
+hardcode_libdir_flag_spec_FC=
+hardcode_libdir_flag_spec_ld_FC=
+hardcode_libdir_separator_FC=
+hardcode_minus_L_FC=no
+hardcode_automatic_FC=no
+inherit_rpath_FC=no
+module_cmds_FC=
+module_expsym_cmds_FC=
+link_all_deplibs_FC=unknown
+old_archive_cmds_FC=$old_archive_cmds
+no_undefined_flag_FC=
+whole_archive_flag_spec_FC=
+enable_shared_with_static_runtimes_FC=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+objext_FC=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+ # save warnings/boilerplate of simple test code
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM conftest*
+
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ CC=${FC-"f95"}
+ compiler=$CC
+ compiler_FC=$CC
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
- break
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+
+ if test -n "$compiler"; then
+ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
+ echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6
+
+ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6
+
+ echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6
+
+ GCC_FC="$ac_cv_fc_compiler_gnu"
+ LD_FC="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ # Dependencies to place before and after the object being linked:
+predep_objects_FC=
+postdep_objects_FC=
+predeps_FC=
+postdeps_FC=
+compiler_lib_search_path_FC=
+
+cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ # The `*' in the case matches for architectures that use `case' in
+ # $output_verbose_cmd can trigger glob expansion during the loop
+ # eval without this substitution.
+ output_verbose_link_cmd=`$ECHO "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
+
+ for p in `eval $output_verbose_link_cmd`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$compiler_lib_search_path_FC"; then
+ compiler_lib_search_path_FC="${prev}${p}"
+ else
+ compiler_lib_search_path_FC="${compiler_lib_search_path_FC} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$postdeps_FC"; then
+ postdeps_FC="${prev}${p}"
+ else
+ postdeps_FC="${postdeps_FC} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$predep_objects_FC"; then
+ predep_objects_FC="$p"
+ else
+ predep_objects_FC="$predep_objects_FC $p"
+ fi
+ else
+ if test -z "$postdep_objects_FC"; then
+ postdep_objects_FC="$p"
+ else
+ postdep_objects_FC="$postdep_objects_FC $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling FC test program"
fi
- done
- ac_cv_prog_CPP=$CPP
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+
+
+case " $postdeps_FC " in
+*" -lc "*) archive_cmds_need_lc_FC=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lt_prog_compiler_wl_FC=
+lt_prog_compiler_pic_FC=
+lt_prog_compiler_static_FC=
+
+echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl_FC='-Wl,'
+ lt_prog_compiler_static_FC='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_FC='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ if test "$host_cpu" = m68k; then
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_FC='-m68020 -resident32 -malways-restore-a4'
+ fi
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic_FC='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_FC='-fno-common'
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_FC='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared_FC=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_FC='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_FC=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic_FC='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_FC='-Bstatic'
+ else
+ lt_prog_compiler_static_FC='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ lt_prog_compiler_pic_FC='-qnocommon'
+ lt_prog_compiler_wl_FC='-Wl,'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_FC='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_FC='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static_FC='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static_FC='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ icc* | ecc*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ lt_prog_compiler_pic_FC='-KPIC'
+ lt_prog_compiler_static_FC='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl_FC='-Wl,'
+ lt_prog_compiler_pic_FC='-fpic'
+ lt_prog_compiler_static_FC='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static_FC='-non_shared'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic_FC='-KPIC'
+ lt_prog_compiler_static_FC='-Bstatic'
+ lt_prog_compiler_wl_FC='-Wl,'
+ ;;
+ *Sun\ F*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic_FC='-KPIC'
+ lt_prog_compiler_static_FC='-Bstatic'
+ lt_prog_compiler_wl_FC=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic_FC='-KPIC'
+ lt_prog_compiler_static_FC='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_FC='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static_FC='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static_FC='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic_FC='-KPIC'
+ lt_prog_compiler_static_FC='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl_FC='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl_FC='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl_FC='-Qoption ld '
+ lt_prog_compiler_pic_FC='-PIC'
+ lt_prog_compiler_static_FC='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ lt_prog_compiler_pic_FC='-KPIC'
+ lt_prog_compiler_static_FC='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic_FC='-Kconform_pic'
+ lt_prog_compiler_static_FC='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ lt_prog_compiler_pic_FC='-KPIC'
+ lt_prog_compiler_static_FC='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl_FC='-Wl,'
+ lt_prog_compiler_can_build_shared_FC=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic_FC='-pic'
+ lt_prog_compiler_static_FC='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared_FC=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_FC=
+ ;;
+ *)
+ lt_prog_compiler_pic_FC="$lt_prog_compiler_pic_FC"
+ ;;
+esac
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_FC" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_FC" >&6
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_FC"; then
+ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_FC works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_FC works... $ECHO_C" >&6
+if test "${lt_prog_compiler_pic_works_FC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works_FC=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_FC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:11071: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:11075: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_pic_works_FC=yes
+ fi
+ fi
+ $RM conftest*
fi
- CPP=$ac_cv_prog_CPP
+echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_FC" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works_FC" >&6
+
+if test x"$lt_prog_compiler_pic_works_FC" = xyes; then
+ case $lt_prog_compiler_pic_FC in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_FC=" $lt_prog_compiler_pic_FC" ;;
+ esac
else
- ac_cv_prog_CPP=$CPP
+ lt_prog_compiler_pic_FC=
+ lt_prog_compiler_can_build_shared_FC=no
fi
-echo "$as_me:$LINENO: result: $CPP" >&5
-echo "${ECHO_T}$CPP" >&6
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
- Syntax error
+
+fi
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_FC eval lt_tmp_static_flag=\"$lt_prog_compiler_static_FC\"
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works_FC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works_FC=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_static_works_FC=yes
+ fi
+ else
+ lt_prog_compiler_static_works_FC=yes
+ fi
+ fi
+ $RM conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_FC" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works_FC" >&6
+
+if test x"$lt_prog_compiler_static_works_FC" = xyes; then
+ :
+else
+ lt_prog_compiler_static_FC=
+fi
+
+
+
+
+ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_FC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_FC=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:11170: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:11174: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_FC=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_FC" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_FC" >&6
+
+
+
+ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
+if test "${lt_cv_prog_compiler_c_o_FC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o_FC=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:11222: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:11226: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_FC=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_FC" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o_FC" >&6
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_FC" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6
+
+ runpath_var=
+ allow_undefined_flag_FC=
+ always_export_symbols_FC=no
+ archive_cmds_FC=
+ archive_expsym_cmds_FC=
+ compiler_needs_object_FC=no
+ enable_shared_with_static_runtimes_FC=no
+ export_dynamic_flag_spec_FC=
+ export_symbols_cmds_FC='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic_FC=no
+ hardcode_direct_FC=no
+ hardcode_direct_absolute_FC=no
+ hardcode_libdir_flag_spec_FC=
+ hardcode_libdir_flag_spec_ld_FC=
+ hardcode_libdir_separator_FC=
+ hardcode_minus_L_FC=no
+ hardcode_shlibpath_var_FC=unsupported
+ inherit_rpath_FC=no
+ link_all_deplibs_FC=unknown
+ module_cmds_FC=
+ module_expsym_cmds_FC=
+ old_archive_from_new_cmds_FC=
+ old_archive_from_expsyms_cmds_FC=
+ thread_safe_flag_spec_FC=
+ whole_archive_flag_spec_FC=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms_FC=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms_FC="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs_FC=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_FC='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_FC='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_FC="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_FC=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs_FC=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ if test "$host_cpu" = m68k; then
+ archive_cmds_FC='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ hardcode_minus_L_FC=yes
+ fi
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs_FC=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_FC=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_FC='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_FC=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, FC) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ allow_undefined_flag_FC=unsupported
+ always_export_symbols_FC=no
+ enable_shared_with_static_runtimes_FC=yes
+ export_symbols_cmds_FC='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_FC='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs_FC=no
+ fi
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct_FC=no
+ hardcode_shlibpath_var_FC=no
+ hardcode_libdir_flag_spec_FC='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_FC='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_FC='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_FC='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec_FC='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec_FC='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec_FC='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object_FC=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ *)
+ tmp_sharedflag='-shared' ;;
+ esac
+ archive_cmds_FC='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds_FC='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ else
+ ld_shlibs_FC=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds_FC='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs_FC=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_FC=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs_FC=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec_FC='${wl}-rpath ${wl}$libdir'
+ archive_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_FC=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds_FC='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct_FC=yes
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_FC=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs_FC" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec_FC=
+ export_dynamic_flag_spec_FC=
+ whole_archive_flag_spec_FC=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag_FC=unsupported
+ always_export_symbols_FC=yes
+ archive_expsym_cmds_FC='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L_FC=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct_FC=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds_FC='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_FC='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_FC=''
+ hardcode_direct_FC=yes
+ hardcode_direct_absolute_FC=yes
+ hardcode_libdir_separator_FC=':'
+ link_all_deplibs_FC=yes
+ file_list_spec_FC='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct_FC=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_FC=yes
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ hardcode_libdir_separator_FC=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_FC=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_FC='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_fc_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
-if test -z "$ac_cpp_err"; then
- :
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
- # Broken: fails on valid input.
-continue
fi
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
- # OK, works on sane cases. Now check whether non-existent headers
- # can be detected and how.
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
+ hardcode_libdir_flag_spec_FC='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds_FC='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_FC='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_FC="-z nodefs"
+ archive_expsym_cmds_FC="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_fc_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_FC='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_FC=' ${wl}-bernotok'
+ allow_undefined_flag_FC=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_FC='$convenience'
+ archive_cmds_need_lc_FC=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds_FC="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ if test "$host_cpu" = m68k; then
+ archive_cmds_FC='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ hardcode_minus_L_FC=yes
+ fi
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs_FC=no
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec_FC=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec_FC=' '
+ allow_undefined_flag_FC=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds_FC='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds_FC='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds_FC='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path_FC='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes_FC=yes
+ ;;
+
+ darwin* | rhapsody*)
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_FC='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[012])
+ allow_undefined_flag_FC='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_FC='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ ;;
+ esac
+ archive_cmds_need_lc_FC=no
+ hardcode_direct_FC=no
+ hardcode_automatic_FC=yes
+ hardcode_shlibpath_var_FC=unsupported
+ whole_archive_flag_spec_FC=''
+ link_all_deplibs_FC=yes
+ if test "$GCC" = yes ; then
+ if test "${lt_cv_apple_cc_single_mod+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi-module to the
+ # link flags.
+ echo "int foo(void){return 1;}" > conftest.c
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib ${wl}-single_module conftest.c
+ if test -f libconftest.dylib; then
+ lt_cv_apple_cc_single_mod=yes
+ rm libconftest.dylib
+ fi
+ rm conftest.$ac_ext
+ fi
+fi
+
+ output_verbose_link_cmd=echo
+ if test "X$lt_cv_apple_cc_single_mod" = Xyes ; then
+ archive_cmds_FC='$CC -dynamiclib $single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ archive_expsym_cmds_FC='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $single_module -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_cmds_FC='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ archive_expsym_cmds_FC='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_cmds_FC='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ module_expsym_cmds_FC='sed -e "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd=echo
+ archive_cmds_FC='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`$ECHO $rpath/$soname` $verstring'
+ module_cmds_FC='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds_FC='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_FC='sed "s,^,_," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs_FC=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds_FC='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs_FC=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds_FC='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec_FC='-R$libdir'
+ hardcode_direct_FC=yes
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds_FC='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_FC=yes
+ hardcode_minus_L_FC=yes
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds_FC='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_FC='-R$libdir'
+ hardcode_direct_FC=yes
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds_FC='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds_FC='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec_FC='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_FC=:
+ hardcode_direct_FC=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_FC=yes
+ export_dynamic_flag_spec_FC='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ archive_cmds_FC='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_FC='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec_FC='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_FC='+b $libdir'
+ hardcode_libdir_separator_FC=:
+ hardcode_direct_FC=yes
+ hardcode_direct_absolute_FC=yes
+ export_dynamic_flag_spec_FC='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_FC=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_FC='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_FC='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_FC='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_FC='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_FC='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_FC='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec_FC='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_FC=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct_FC=no
+ hardcode_shlibpath_var_FC=no
+ ;;
+ *)
+ hardcode_direct_FC=yes
+ hardcode_direct_absolute_FC=yes
+ export_dynamic_flag_spec_FC='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_FC=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat >conftest.$ac_ext <<_ACEOF
+int foo(void) {}
_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_fc_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ archive_expsym_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+ else
+ archive_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_FC='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc_FC='no'
+ hardcode_libdir_flag_spec_FC='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_FC=:
+ inherit_rpath_FC=yes
+ link_all_deplibs_FC=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds_FC='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds_FC='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec_FC='-R$libdir'
+ hardcode_direct_FC=yes
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ newsos6)
+ archive_cmds_FC='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_FC=yes
+ hardcode_libdir_flag_spec_FC='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_FC=:
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ hardcode_direct_FC=yes
+ hardcode_shlibpath_var_FC=no
+ hardcode_direct_absolute_FC=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds_FC='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_FC='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec_FC='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_FC='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds_FC='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_FC='-R$libdir'
+ ;;
+ *)
+ archive_cmds_FC='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_FC='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ hardcode_minus_L_FC=yes
+ allow_undefined_flag_FC=unsupported
+ archive_cmds_FC='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds_FC='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag_FC=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_FC='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag_FC=' -expect_unresolved \*'
+ archive_cmds_FC='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc_FC='no'
+ hardcode_libdir_flag_spec_FC='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_FC=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag_FC=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_FC='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_FC='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag_FC=' -expect_unresolved \*'
+ archive_cmds_FC='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_FC='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec_FC='-rpath $libdir'
+ fi
+ archive_cmds_need_lc_FC='no'
+ hardcode_libdir_separator_FC=:
+ ;;
+
+ solaris*)
+ no_undefined_flag_FC=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds_FC='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_FC='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds_FC='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_FC='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds_FC='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_FC='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec_FC='-R$libdir'
+ hardcode_shlibpath_var_FC=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec_FC='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec_FC='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs_FC=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds_FC='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_FC='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ hardcode_direct_FC=yes
+ hardcode_minus_L_FC=yes
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds_FC='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_FC=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds_FC='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds_FC='$CC -r -o $output$reload_objs'
+ hardcode_direct_FC=no
+ ;;
+ motorola)
+ archive_cmds_FC='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_FC=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds_FC='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_FC=no
+ export_dynamic_flag_spec_FC='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds_FC='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_FC=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs_FC=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag_FC='${wl}-z,text'
+ archive_cmds_need_lc_FC=no
+ hardcode_shlibpath_var_FC=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds_FC='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_FC='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_FC='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_FC='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag_FC='${wl}-z,text'
+ allow_undefined_flag_FC='${wl}-z,nodefs'
+ archive_cmds_need_lc_FC=no
+ hardcode_shlibpath_var_FC=no
+ hardcode_libdir_flag_spec_FC='${wl}-R,$libdir'
+ hardcode_libdir_separator_FC=':'
+ link_all_deplibs_FC=yes
+ export_dynamic_flag_spec_FC='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds_FC='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_FC='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_FC='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_FC='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds_FC='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_FC='-L$libdir'
+ hardcode_shlibpath_var_FC=no
+ ;;
+
+ *)
+ ld_shlibs_FC=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec_FC='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+echo "$as_me:$LINENO: result: $ld_shlibs_FC" >&5
+echo "${ECHO_T}$ld_shlibs_FC" >&6
+test "$ld_shlibs_FC" = no && can_build_shared=no
+
+with_gnu_ld_FC=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_FC" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_FC=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_FC in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_FC
+ pic_flag=$lt_prog_compiler_pic_FC
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_FC
+ allow_undefined_flag_FC=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds_FC 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds_FC 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc_FC=no
+ else
+ archive_cmds_need_lc_FC=yes
+ fi
+ allow_undefined_flag_FC=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ echo "$as_me:$LINENO: result: $archive_cmds_need_lc_FC" >&5
+echo "${ECHO_T}$archive_cmds_need_lc_FC" >&6
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
+withGCC=$ac_cv_fc_compiler_gnu
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
else
- ac_cpp_err=
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
fi
-else
- ac_cpp_err=yes
+ ;;
+
+amigaos*)
+ if test "$host_cpu" = m68k; then
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ else
+ dynamic_linker=no
+ fi
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $withGCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # Some binutils ld are patched to set DT_RUNPATH
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_FC\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_FC\""
+ cat >conftest.$ac_ext <<_ACEOF
+ program main
+
+ end
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_fc_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir"; then
+ shlibpath_overrides_runpath=yes
fi
-if test -z "$ac_cpp_err"; then
- # Broken: success on invalid input.
-continue
+
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
- # Passes both tests.
-ac_preproc_ok=:
-break
fi
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
- :
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_name_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
+hardcode_action_FC=
+if test -n "$hardcode_libdir_flag_spec_FC" ||
+ test -n "$runpath_var_FC" ||
+ test "X$hardcode_automatic_FC" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_FC" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, FC)" != no &&
+ test "$hardcode_minus_L_FC" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_FC=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_FC=immediate
+ fi
else
- { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details." >&5
-echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_FC=unsupported
+fi
+echo "$as_me:$LINENO: result: $hardcode_action_FC" >&5
+echo "${ECHO_T}$hardcode_action_FC" >&6
+
+if test "$hardcode_action_FC" = relink ||
+ test "$inherit_rpath_FC" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
fi
+
+
+
+
+
+
+ fi # test -n "$compiler"
+
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_FC" != yes
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -5145,21 +13186,13 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-echo "$as_me:$LINENO: checking for egrep" >&5
-echo $ECHO_N "checking for egrep... $ECHO_C" >&6
-if test "${ac_cv_prog_egrep+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if echo a | (grep -E '(a|b)') >/dev/null 2>&1
- then ac_cv_prog_egrep='grep -E'
- else ac_cv_prog_egrep='egrep'
- fi
-fi
-echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
-echo "${ECHO_T}$ac_cv_prog_egrep" >&6
- EGREP=$ac_cv_prog_egrep
+FCFLAGS="$FCFLAGS -Wall"
+
+# For libtool versioning info, format is CURRENT:REVISION:AGE
+libtool_VERSION=1:0:0
+# Check header files.
echo "$as_me:$LINENO: checking for ANSI C header files" >&5
echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
if test "${ac_cv_header_stdc+set}" = set; then
@@ -5391,83 +13424,11 @@ _ACEOF
fi
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-
-
-
-
-
-
-
-
-
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
- inttypes.h stdint.h unistd.h
-do
-as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-$ac_includes_default
-
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- eval "$as_ac_Header=yes"
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-eval "$as_ac_Header=no"
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
-if test `eval echo '${'$as_ac_Header'}'` = yes; then
- cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-for ac_header in unistd.h semaphore.h sys/loadavg.h sys/time.h
+for ac_header in unistd.h semaphore.h sys/loadavg.h sys/sysctl.h sys/time.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -8681,6 +16642,24 @@ cat >>confdefs.h <<\_ACEOF
_ACEOF
;;
+esac
+
+ # Check whether --enable-linux-futex or --disable-linux-futex was given.
+if test "${enable_linux_futex+set}" = set; then
+ enableval="$enable_linux_futex"
+
+ case "$enableval" in
+ yes|no|default) ;;
+ *) { { echo "$as_me:$LINENO: error: Unknown argument to enable/disable linux-futex" >&5
+echo "$as_me: error: Unknown argument to enable/disable linux-futex" >&2;}
+ { (exit 1); exit 1; }; } ;;
+ esac
+
+else
+ enable_linux_futex=default
+fi;
+
+case "$target" in
*-linux*)
case "$enable_linux_futex" in
default)
@@ -8729,7 +16708,9 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- cat >conftest.$ac_ext <<_ACEOF
+ save_LIBS="$LIBS"
+ LIBS="-lpthread $LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
@@ -8777,7 +16758,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
if test x$cross_compiling = xno; then
if getconf GNU_LIBPTHREAD_VERSION 2>/dev/null \
- | LC_ALL=C grep -i NPTL > /dev/null 2>/dev/null; then
+ | LC_ALL=C grep -i NPTL > /dev/null 2>/dev/null; then :; else
{ echo "$as_me:$LINENO: WARNING: The kernel might not support futex or gettid syscalls.
If so, please configure with --disable-linux-futex" >&5
echo "$as_me: WARNING: The kernel might not support futex or gettid syscalls.
@@ -8788,6 +16769,7 @@ If so, please configure with --disable-linux-futex" >&2;}
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
+ LIBS="$save_LIBS"
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
@@ -8849,7 +16831,76 @@ rm -f conftest.err conftest.$ac_objext \
;;
esac
;;
+ *)
+ enable_linux_futex=no
+ ;;
esac
+if test x$enable_linux_futex = xyes; then
+ :
+fi
+
+
+# Check for pthread_{,attr_}[sg]etaffinity_np.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#define _GNU_SOURCE
+ #include <pthread.h>
+int
+main ()
+{
+cpu_set_t cpuset;
+ pthread_attr_t attr;
+ pthread_getaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+ if (CPU_ISSET (0, &cpuset))
+ CPU_SET (1, &cpuset);
+ else
+ CPU_ZERO (&cpuset);
+ pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+ pthread_attr_init (&attr);
+ pthread_attr_getaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);
+ pthread_attr_setaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PTHREAD_AFFINITY_NP 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
# At least for glibc, clock_gettime is in librt. But don't pull that
# in if it still doesn't give us the function we want.
@@ -8948,17 +16999,17 @@ fi;
echo "$as_me:$LINENO: checking whether the target supports thread-local storage" >&5
echo $ECHO_N "checking whether the target supports thread-local storage... $ECHO_C" >&6
-if test "${have_tls+set}" = set; then
+if test "${gcc_cv_have_tls+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "$cross_compiling" = yes; then
- cat >conftest.$ac_ext <<_ACEOF
-__thread int foo;
+ cat >conftest.$ac_ext <<_ACEOF
+__thread int a; int b; int main() { return a = b; }
_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
@@ -8972,20 +17023,22 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
+ { ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- have_tls=yes
+ gcc_cv_have_tls=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-have_tls=no
+gcc_cv_have_tls=no
fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
else
cat >conftest.$ac_ext <<_ACEOF
@@ -9002,7 +17055,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- save_LDFLAGS="$LDFLAGS"
+ chktls_save_LDFLAGS="$LDFLAGS"
LDFLAGS="-static $LDFLAGS"
cat >conftest.$ac_ext <<_ACEOF
int main() { return 0; }
@@ -9050,14 +17103,14 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- have_tls=yes
+ gcc_cv_have_tls=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
-have_tls=no
+gcc_cv_have_tls=no
fi
rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
@@ -9065,25 +17118,147 @@ else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-have_tls=yes
+gcc_cv_have_tls=yes
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$chktls_save_LDFLAGS"
+ if test $gcc_cv_have_tls = yes; then
+ chktls_save_CFLAGS="$CFLAGS"
+ thread_CFLAGS=failed
+ for flag in '' '-pthread' '-lpthread'; do
+ CFLAGS="$flag $chktls_save_CFLAGS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <pthread.h>
+ void *g(void *d) { return NULL; }
+int
+main ()
+{
+pthread_t t; pthread_create(&t,NULL,g,NULL);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ thread_CFLAGS="$flag"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
- LDFLAGS="$save_LDFLAGS"
+ if test "X$thread_CFLAGS" != Xfailed; then
+ break
+ fi
+ done
+ CFLAGS="$chktls_save_CFLAGS"
+ if test "X$thread_CFLAGS" != Xfailed; then
+ CFLAGS="$thread_CFLAGS $chktls_save_CFLAGS"
+ if test "$cross_compiling" = yes; then
+ { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <pthread.h>
+ __thread int a;
+ static int *a_in_other_thread;
+ static void *
+ thread_func (void *arg)
+ {
+ a_in_other_thread = &a;
+ return (void *)0;
+ }
+int
+main ()
+{
+pthread_t thread;
+ void *thread_retval;
+ int *a_in_main_thread;
+ if (pthread_create (&thread, (pthread_attr_t *)0,
+ thread_func, (void *)0))
+ return 0;
+ a_in_main_thread = &a;
+ if (pthread_join (thread, &thread_retval))
+ return 0;
+ return (a_in_other_thread == a_in_main_thread);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ gcc_cv_have_tls=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
-have_tls=no
+gcc_cv_have_tls=no
fi
rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
+ CFLAGS="$chktls_save_CFLAGS"
+ fi
+ fi
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+gcc_cv_have_tls=no
fi
-echo "$as_me:$LINENO: result: $have_tls" >&5
-echo "${ECHO_T}$have_tls" >&6
- if test "$enable_tls $have_tls" = "yes yes"; then
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $gcc_cv_have_tls" >&5
+echo "${ECHO_T}$gcc_cv_have_tls" >&6
+ if test "$enable_tls $gcc_cv_have_tls" = "yes yes"; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_TLS 1
@@ -9288,6 +17463,118 @@ _ACEOF
fi
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval="$with_gnu_ld"
+ test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi;
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
+else
+ echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
# If we're not using GNU ld, then there's no point in even trying these
# tests. Check for that first. We should have already tested for gld
# by now (in libtool), but require it now just to be safe...
@@ -11703,6 +19990,339 @@ CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
CC="$CC"
AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`'
+enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`'
+host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`'
+host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`'
+host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`'
+build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`'
+build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`'
+build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`'
+SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`'
+Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`'
+GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`'
+EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`'
+FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`'
+LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`'
+NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`'
+LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`'
+exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`'
+AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`'
+STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`'
+compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`'
+GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`'
+objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`'
+SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`'
+ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`'
+need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`'
+libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
+need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`'
+version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`'
+striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "X$predep_objects" | $Xsed -e "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "X$postdep_objects" | $Xsed -e "$delay_single_quote_subst"`'
+predeps='`$ECHO "X$predeps" | $Xsed -e "$delay_single_quote_subst"`'
+postdeps='`$ECHO "X$postdeps" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "X$compiler_lib_search_path" | $Xsed -e "$delay_single_quote_subst"`'
+LD_FC='`$ECHO "X$LD_FC" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_cmds_FC='`$ECHO "X$old_archive_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_FC='`$ECHO "X$compiler_FC" | $Xsed -e "$delay_single_quote_subst"`'
+GCC_FC='`$ECHO "X$GCC_FC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_FC='`$ECHO "X$lt_prog_compiler_no_builtin_flag_FC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_FC='`$ECHO "X$lt_prog_compiler_wl_FC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_FC='`$ECHO "X$lt_prog_compiler_pic_FC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_static_FC='`$ECHO "X$lt_prog_compiler_static_FC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_FC='`$ECHO "X$lt_cv_prog_compiler_c_o_FC" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds_need_lc_FC='`$ECHO "X$archive_cmds_need_lc_FC" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_FC='`$ECHO "X$enable_shared_with_static_runtimes_FC" | $Xsed -e "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_FC='`$ECHO "X$export_dynamic_flag_spec_FC" | $Xsed -e "$delay_single_quote_subst"`'
+whole_archive_flag_spec_FC='`$ECHO "X$whole_archive_flag_spec_FC" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_needs_object_FC='`$ECHO "X$compiler_needs_object_FC" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_FC='`$ECHO "X$old_archive_from_new_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_FC='`$ECHO "X$old_archive_from_expsyms_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds_FC='`$ECHO "X$archive_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+archive_expsym_cmds_FC='`$ECHO "X$archive_expsym_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+module_cmds_FC='`$ECHO "X$module_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+module_expsym_cmds_FC='`$ECHO "X$module_expsym_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+with_gnu_ld_FC='`$ECHO "X$with_gnu_ld_FC" | $Xsed -e "$delay_single_quote_subst"`'
+allow_undefined_flag_FC='`$ECHO "X$allow_undefined_flag_FC" | $Xsed -e "$delay_single_quote_subst"`'
+no_undefined_flag_FC='`$ECHO "X$no_undefined_flag_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_FC='`$ECHO "X$hardcode_libdir_flag_spec_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld_FC='`$ECHO "X$hardcode_libdir_flag_spec_ld_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_separator_FC='`$ECHO "X$hardcode_libdir_separator_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct_FC='`$ECHO "X$hardcode_direct_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct_absolute_FC='`$ECHO "X$hardcode_direct_absolute_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_minus_L_FC='`$ECHO "X$hardcode_minus_L_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_FC='`$ECHO "X$hardcode_shlibpath_var_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_automatic_FC='`$ECHO "X$hardcode_automatic_FC" | $Xsed -e "$delay_single_quote_subst"`'
+inherit_rpath_FC='`$ECHO "X$inherit_rpath_FC" | $Xsed -e "$delay_single_quote_subst"`'
+link_all_deplibs_FC='`$ECHO "X$link_all_deplibs_FC" | $Xsed -e "$delay_single_quote_subst"`'
+fix_srcfile_path_FC='`$ECHO "X$fix_srcfile_path_FC" | $Xsed -e "$delay_single_quote_subst"`'
+always_export_symbols_FC='`$ECHO "X$always_export_symbols_FC" | $Xsed -e "$delay_single_quote_subst"`'
+export_symbols_cmds_FC='`$ECHO "X$export_symbols_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+exclude_expsyms_FC='`$ECHO "X$exclude_expsyms_FC" | $Xsed -e "$delay_single_quote_subst"`'
+include_expsyms_FC='`$ECHO "X$include_expsyms_FC" | $Xsed -e "$delay_single_quote_subst"`'
+prelink_cmds_FC='`$ECHO "X$prelink_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`'
+file_list_spec_FC='`$ECHO "X$file_list_spec_FC" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_action_FC='`$ECHO "X$hardcode_action_FC" | $Xsed -e "$delay_single_quote_subst"`'
+predep_objects_FC='`$ECHO "X$predep_objects_FC" | $Xsed -e "$delay_single_quote_subst"`'
+postdep_objects_FC='`$ECHO "X$postdep_objects_FC" | $Xsed -e "$delay_single_quote_subst"`'
+predeps_FC='`$ECHO "X$predeps_FC" | $Xsed -e "$delay_single_quote_subst"`'
+postdeps_FC='`$ECHO "X$postdeps_FC" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_lib_search_path_FC='`$ECHO "X$compiler_lib_search_path_FC" | $Xsed -e "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# Quote evaled strings.
+for var in SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+deplibs_check_method \
+file_magic_cmd \
+AR \
+AR_FLAGS \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+SHELL \
+ECHO \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_wl \
+lt_prog_compiler_pic \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_flag_spec_ld \
+hardcode_libdir_separator \
+fix_srcfile_path \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+finish_eval \
+old_striplib \
+striplib \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_FC \
+compiler_FC \
+lt_prog_compiler_no_builtin_flag_FC \
+lt_prog_compiler_wl_FC \
+lt_prog_compiler_pic_FC \
+lt_prog_compiler_static_FC \
+lt_cv_prog_compiler_c_o_FC \
+export_dynamic_flag_spec_FC \
+whole_archive_flag_spec_FC \
+compiler_needs_object_FC \
+with_gnu_ld_FC \
+allow_undefined_flag_FC \
+no_undefined_flag_FC \
+hardcode_libdir_flag_spec_FC \
+hardcode_libdir_flag_spec_ld_FC \
+hardcode_libdir_separator_FC \
+fix_srcfile_path_FC \
+exclude_expsyms_FC \
+include_expsyms_FC \
+file_list_spec_FC \
+predep_objects_FC \
+postdep_objects_FC \
+predeps_FC \
+postdeps_FC \
+compiler_lib_search_path_FC; do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec \
+old_archive_cmds_FC \
+old_archive_from_new_cmds_FC \
+old_archive_from_expsyms_cmds_FC \
+archive_cmds_FC \
+archive_expsym_cmds_FC \
+module_cmds_FC \
+module_expsym_cmds_FC \
+export_symbols_cmds_FC \
+prelink_cmds_FC; do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Fix-up fallback echo if it was mangled by the above quoting rules.
+case \$lt_ECHO in
+*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\`
+ ;;
+esac
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+
+
GCC="$GCC"
CC="$CC"
acx_cv_header_stdint="$acx_cv_header_stdint"
@@ -11739,6 +20359,7 @@ do
"libgomp.spec" ) CONFIG_FILES="$CONFIG_FILES libgomp.spec" ;;
"default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
"depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool" ) CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
"gstdint.h" ) CONFIG_COMMANDS="$CONFIG_COMMANDS gstdint.h" ;;
"config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
@@ -11886,8 +20507,19 @@ s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
s,@PERL@,$PERL,;t t
s,@BUILD_INFO_TRUE@,$BUILD_INFO_TRUE,;t t
s,@BUILD_INFO_FALSE@,$BUILD_INFO_FALSE,;t t
-s,@LN_S@,$LN_S,;t t
s,@LIBTOOL@,$LIBTOOL,;t t
+s,@SED@,$SED,;t t
+s,@EGREP@,$EGREP,;t t
+s,@FGREP@,$FGREP,;t t
+s,@GREP@,$GREP,;t t
+s,@LD@,$LD,;t t
+s,@DUMPBIN@,$DUMPBIN,;t t
+s,@ac_ct_DUMPBIN@,$ac_ct_DUMPBIN,;t t
+s,@NM@,$NM,;t t
+s,@LN_S@,$LN_S,;t t
+s,@lt_ECHO@,$lt_ECHO,;t t
+s,@CPP@,$CPP,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
s,@enable_shared@,$enable_shared,;t t
s,@enable_static@,$enable_static,;t t
s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t
@@ -11898,9 +20530,6 @@ s,@FCFLAGS@,$FCFLAGS,;t t
s,@LDFLAGS@,$LDFLAGS,;t t
s,@ac_ct_FC@,$ac_ct_FC,;t t
s,@libtool_VERSION@,$libtool_VERSION,;t t
-s,@CPP@,$CPP,;t t
-s,@CPPFLAGS@,$CPPFLAGS,;t t
-s,@EGREP@,$EGREP,;t t
s,@SECTION_LDFLAGS@,$SECTION_LDFLAGS,;t t
s,@OPT_LDFLAGS@,$OPT_LDFLAGS,;t t
s,@LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE@,$LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE,;t t
@@ -12609,6 +21238,716 @@ echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;}
done
done
;;
+ libtool )
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me (GNU $PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007 Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, a copy can be downloaded from
+# http://www.gnu.org/copyleft/gpl.html, or by writing to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="FC "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that does not interpret backslashes.
+ECHO=$lt_ECHO
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[^=]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+}
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1+=\$2"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1=\$$1\$2"
+}
+_LT_EOF
+ ;;
+ esac
+
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+
+ cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: FC
+
+# The linker used to build libraries.
+LD=$lt_LD_FC
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_FC
+
+# A language specific compiler.
+CC=$lt_compiler_FC
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_FC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_FC
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_FC
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_FC
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_FC
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_FC
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_FC
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_FC
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_FC
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_FC
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_FC
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_FC
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_FC
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_FC
+archive_expsym_cmds=$lt_archive_expsym_cmds_FC
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_FC
+module_expsym_cmds=$lt_module_expsym_cmds_FC
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_FC
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_FC
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_FC
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_FC
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_FC
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_FC
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_FC
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_FC
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_FC
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_FC
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_FC
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_FC
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_FC
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path_FC
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_FC
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_FC
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_FC
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_FC
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_FC
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_FC
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_FC
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_FC
+postdep_objects=$lt_postdep_objects_FC
+predeps=$lt_predeps_FC
+postdeps=$lt_postdeps_FC
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_FC
+
+# ### END LIBTOOL TAG CONFIG: FC
+_LT_EOF
+
+ ;;
gstdint.h )
if test "$GCC" = yes; then
echo "/* generated for " `$CC --version | sed 1q` "*/" > tmp-stdint.h
@@ -12650,33 +21989,51 @@ if test "$acx_cv_header_stdint" = stddef.h; then
#ifndef _UINT8_T
#define _UINT8_T
+ #ifndef __uint8_t_defined
+ #define __uint8_t_defined
typedef unsigned $acx_cv_type_int8_t uint8_t;
#endif
+ #endif
#ifndef _UINT16_T
#define _UINT16_T
+ #ifndef __uint16_t_defined
+ #define __uint16_t_defined
typedef unsigned $acx_cv_type_int16_t uint16_t;
#endif
+ #endif
#ifndef _UINT32_T
#define _UINT32_T
+ #ifndef __uint32_t_defined
+ #define __uint32_t_defined
typedef unsigned $acx_cv_type_int32_t uint32_t;
#endif
+ #endif
#ifndef _INT8_T
#define _INT8_T
+ #ifndef __int8_t_defined
+ #define __int8_t_defined
typedef $acx_cv_type_int8_t int8_t;
#endif
+ #endif
#ifndef _INT16_T
#define _INT16_T
+ #ifndef __int16_t_defined
+ #define __int16_t_defined
typedef $acx_cv_type_int16_t int16_t;
#endif
+ #endif
#ifndef _INT32_T
#define _INT32_T
+ #ifndef __int32_t_defined
+ #define __int32_t_defined
typedef $acx_cv_type_int32_t int32_t;
#endif
+ #endif
EOF
elif test "$ac_cv_type_u_int32_t" = yes; then
sed 's/^ *//' >> tmp-stdint.h <<EOF
@@ -12694,18 +22051,27 @@ elif test "$ac_cv_type_u_int32_t" = yes; then
#ifndef _UINT8_T
#define _UINT8_T
+ #ifndef __uint8_t_defined
+ #define __uint8_t_defined
typedef u_int8_t uint8_t;
#endif
+ #endif
#ifndef _UINT16_T
#define _UINT16_T
+ #ifndef __uint16_t_defined
+ #define __uint16_t_defined
typedef u_int16_t uint16_t;
#endif
+ #endif
#ifndef _UINT32_T
#define _UINT32_T
+ #ifndef __uint32_t_defined
+ #define __uint32_t_defined
typedef u_int32_t uint32_t;
#endif
+ #endif
EOF
else
sed 's/^ *//' >> tmp-stdint.h <<EOF
@@ -12753,8 +22119,11 @@ elif test "$ac_cv_type_u_int64_t" = yes; then
#endif
#ifndef _UINT64_T
#define _UINT64_T
+ #ifndef __uint64_t_defined
+ #define __uint64_t_defined
typedef u_int64_t uint64_t;
#endif
+ #endif
EOF
elif test -n "$acx_cv_type_int64_t"; then
sed 's/^ *//' >> tmp-stdint.h <<EOF
@@ -12766,8 +22135,11 @@ elif test -n "$acx_cv_type_int64_t"; then
#endif
#ifndef _UINT64_T
#define _UINT64_T
+ #ifndef __uint64_t_defined
+ #define __uint64_t_defined
typedef unsigned $acx_cv_type_int64_t uint64_t;
#endif
+ #endif
EOF
else
sed 's/^ *//' >> tmp-stdint.h <<EOF
@@ -12776,8 +22148,10 @@ else
#if defined __STDC_VERSION__ && (__STDC_VERSION__-0) >= 199901L
#ifndef _INT64_T
#define _INT64_T
+ #ifndef __int64_t_defined
typedef long long int64_t;
#endif
+ #endif
#ifndef _UINT64_T
#define _UINT64_T
typedef unsigned long long uint64_t;
@@ -12822,8 +22196,12 @@ if test "$ac_cv_type_uintptr_t" != yes; then
sed 's/^ *//' >> tmp-stdint.h <<EOF
/* Define intptr_t based on sizeof(void*) = $ac_cv_sizeof_void_p */
+ #ifndef __uintptr_t_defined
typedef u$acx_cv_type_intptr_t uintptr_t;
+ #endif
+ #ifndef __intptr_t_defined
typedef $acx_cv_type_intptr_t intptr_t;
+ #endif
EOF
fi
diff --git a/contrib/gcclibs/libgomp/configure.ac b/contrib/gcclibs/libgomp/configure.ac
index fc0f003..c43858d 100644
--- a/contrib/gcclibs/libgomp/configure.ac
+++ b/contrib/gcclibs/libgomp/configure.ac
@@ -15,12 +15,6 @@ LIBGOMP_ENABLE(version-specific-runtime-libs, no, ,
permit yes|no)
AC_MSG_RESULT($enable_version_specific_runtime_libs)
-AC_MSG_CHECKING([for --enable-linux-futex])
-LIBGOMP_ENABLE(linux-futex, default, ,
- [Use the Linux futex system call],
- permit yes|no|default)
-AC_MSG_RESULT($enable_linux_futex)
-
# We would like our source tree to be readonly. However when releases or
# pre-releases are generated, the flex/bison generated files as well as the
# various formats of manuals need to be included along with the rest of the
@@ -64,11 +58,11 @@ target_alias=${target_alias-$host_alias}
# we can do about that; they come from AC_INIT).
# foreign: we don't follow the normal rules for GNU packages (no COPYING
# file in the top srcdir, etc, etc), so stop complaining.
-# no-dependencies: turns off auto dependency generation (just for now)
+# no-dist: we don't want 'dist' and related rules.
# -Wall: turns on all automake warnings...
# -Wno-portability: ...except this one, since GNU make is required.
# -Wno-override: ... and this one, since we do want this in testsuite.
-AM_INIT_AUTOMAKE([1.9.0 foreign -Wall -Wno-portability -Wno-override])
+AM_INIT_AUTOMAKE([1.9.0 foreign no-dist -Wall -Wno-portability -Wno-override])
AM_ENABLE_MULTILIB(, ..)
# Calculate toolexeclibdir
@@ -135,7 +129,7 @@ AC_PROG_INSTALL
# that we can use it.
ACX_CHECK_PROG_VER([MAKEINFO], [makeinfo], [--version],
[GNU texinfo.* \([0-9][0-9.]*\)],
- [4.[4-9]*])
+ [4.[4-9]*|4.[1-9][0-9]*|[5-9]*|[1-9][0-9]*])
AM_CONDITIONAL(BUILD_INFO, test $gcc_cv_prog_makeinfo_modern = "yes")
@@ -160,7 +154,7 @@ AC_SUBST(libtool_VERSION)
# Check header files.
AC_STDC_HEADERS
AC_HEADER_TIME
-AC_CHECK_HEADERS(unistd.h semaphore.h sys/loadavg.h sys/time.h)
+AC_CHECK_HEADERS(unistd.h semaphore.h sys/loadavg.h sys/sysctl.h sys/time.h)
GCC_HEADER_STDINT(gstdint.h)
@@ -193,50 +187,29 @@ case "$host" in
AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1,
Define if the POSIX Semaphores do not work on your system.)
;;
- *-linux*)
- case "$enable_linux_futex" in
- default)
- # If headers don't have gettid/futex syscalls definition, then
- # default to no, otherwise there will be compile time failures.
- # Otherwise, default to yes. If we don't detect we are
- # compiled/linked against NPTL and not cross-compiling, check
- # if programs are run by default against NPTL and if not, issue
- # a warning.
- enable_linux_futex=no
- AC_LINK_IFELSE(
- [AC_LANG_PROGRAM(
- [#include <sys/syscall.h>
- int lk;],
- [syscall (SYS_gettid); syscall (SYS_futex, &lk, 0, 0, 0);])],
- [AC_LINK_IFELSE(
- [AC_LANG_PROGRAM(
- [#ifndef _GNU_SOURCE
- #define _GNU_SOURCE 1
- #endif
- #include <pthread.h>
- pthread_t th; void *status;],
- [pthread_tryjoin_np (th, &status);])],[enable_linux_futex=yes],
- [if test x$cross_compiling = xno; then
- if getconf GNU_LIBPTHREAD_VERSION 2>/dev/null \
- | LC_ALL=C grep -i NPTL > /dev/null 2>/dev/null; then
- AC_MSG_WARN([The kernel might not support futex or gettid syscalls.
-If so, please configure with --disable-linux-futex])
- fi
- fi
- enable_linux_futex=yes])])
- ;;
- yes)
- AC_LINK_IFELSE(
- [AC_LANG_PROGRAM(
- [#include <sys/syscall.h>
- int lk;],
- [syscall (SYS_gettid); syscall (SYS_futex, &lk, 0, 0, 0);])],[],
- [AC_MSG_ERROR([SYS_gettid and SYS_futex required for --enable-linux-futex])])
- ;;
- esac
- ;;
esac
+GCC_LINUX_FUTEX(:)
+
+# Check for pthread_{,attr_}[sg]etaffinity_np.
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#define _GNU_SOURCE
+ #include <pthread.h>],
+ [cpu_set_t cpuset;
+ pthread_attr_t attr;
+ pthread_getaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+ if (CPU_ISSET (0, &cpuset))
+ CPU_SET (1, &cpuset);
+ else
+ CPU_ZERO (&cpuset);
+ pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
+ pthread_attr_init (&attr);
+ pthread_attr_getaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);
+ pthread_attr_setaffinity_np (&attr, sizeof (cpu_set_t), &cpuset);])],
+ AC_DEFINE(HAVE_PTHREAD_AFFINITY_NP, 1,
+[ Define if pthread_{,attr_}{g,s}etaffinity_np is supported.]))
+
# At least for glibc, clock_gettime is in librt. But don't pull that
# in if it still doesn't give us the function we want.
if test $ac_cv_func_clock_gettime = no; then
diff --git a/contrib/gcclibs/libgomp/configure.tgt b/contrib/gcclibs/libgomp/configure.tgt
index 89bae02..a666943 100644
--- a/contrib/gcclibs/libgomp/configure.tgt
+++ b/contrib/gcclibs/libgomp/configure.tgt
@@ -11,14 +11,11 @@
# XLDFLAGS Add extra link flags to use.
# Optimize TLS usage by avoiding the overhead of dynamic allocation.
-# This does require that the library be present during process
-# startup, so mark the library as not to be dlopened.
-if test $have_tls = yes ; then
+if test $gcc_cv_have_tls = yes ; then
case "${target}" in
*-*-linux*)
XCFLAGS="${XCFLAGS} -ftls-model=initial-exec"
- XLDFLAGS="${XLDFLAGS} -Wl,-z,nodlopen"
;;
esac
fi
@@ -49,9 +46,14 @@ if test $enable_linux_futex = yes; then
# Note that bare i386 is not included here. We need cmpxchg.
i[456]86-*-linux*)
config_path="linux/x86 linux posix"
- if test -z "$with_arch"; then
- XCFLAGS="${XCFLAGS} -march=i486 -mtune=${target_cpu}"
- fi
+ case " ${CC} ${CFLAGS} " in
+ *" -m64 "*)
+ ;;
+ *)
+ if test -z "$with_arch"; then
+ XCFLAGS="${XCFLAGS} -march=i486 -mtune=${target_cpu}"
+ fi
+ esac
;;
# Similar jiggery-pokery for x86_64 multilibs, except here we
@@ -105,6 +107,10 @@ case "${target}" in
XLDFLAGS="${XLDFLAGS} -lposix4"
;;
+ *-*-darwin*)
+ config_path="bsd posix"
+ ;;
+
*)
;;
diff --git a/contrib/gcclibs/libgomp/env.c b/contrib/gcclibs/libgomp/env.c
index f07b31b..4a07bfa 100644
--- a/contrib/gcclibs/libgomp/env.c
+++ b/contrib/gcclibs/libgomp/env.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
@@ -42,6 +42,8 @@ bool gomp_dyn_var = false;
bool gomp_nest_var = false;
enum gomp_schedule_type gomp_run_sched_var = GFS_DYNAMIC;
unsigned long gomp_run_sched_chunk = 1;
+unsigned short *gomp_cpu_affinity;
+size_t gomp_cpu_affinity_len;
/* Parse the OMP_SCHEDULE environment variable. */
@@ -177,6 +179,97 @@ parse_boolean (const char *name, bool *value)
gomp_error ("Invalid value for environment variable %s", name);
}
+/* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
+ present and it was successfully parsed. */
+
+static bool
+parse_affinity (void)
+{
+ char *env, *end;
+ unsigned long cpu_beg, cpu_end, cpu_stride;
+ unsigned short *cpus = NULL;
+ size_t allocated = 0, used = 0, needed;
+
+ env = getenv ("GOMP_CPU_AFFINITY");
+ if (env == NULL)
+ return false;
+
+ do
+ {
+ while (*env == ' ' || *env == '\t')
+ env++;
+
+ cpu_beg = strtoul (env, &end, 0);
+ cpu_end = cpu_beg;
+ cpu_stride = 1;
+ if (env == end || cpu_beg >= 65536)
+ goto invalid;
+
+ env = end;
+ if (*env == '-')
+ {
+ cpu_end = strtoul (++env, &end, 0);
+ if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
+ goto invalid;
+
+ env = end;
+ if (*env == ':')
+ {
+ cpu_stride = strtoul (++env, &end, 0);
+ if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
+ goto invalid;
+
+ env = end;
+ }
+ }
+
+ needed = (cpu_end - cpu_beg) / cpu_stride + 1;
+ if (used + needed >= allocated)
+ {
+ unsigned short *new_cpus;
+
+ if (allocated < 64)
+ allocated = 64;
+ if (allocated > needed)
+ allocated <<= 1;
+ else
+ allocated += 2 * needed;
+ new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
+ if (new_cpus == NULL)
+ {
+ free (cpus);
+ gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
+ return false;
+ }
+
+ cpus = new_cpus;
+ }
+
+ while (needed--)
+ {
+ cpus[used++] = cpu_beg;
+ cpu_beg += cpu_stride;
+ }
+
+ while (*env == ' ' || *env == '\t')
+ env++;
+
+ if (*env == ',')
+ env++;
+ else if (*env == '\0')
+ break;
+ }
+ while (1);
+
+ gomp_cpu_affinity = cpus;
+ gomp_cpu_affinity_len = used;
+ return true;
+
+ invalid:
+ gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
+ return false;
+}
+
static void __attribute__((constructor))
initialize_env (void)
{
@@ -190,6 +283,8 @@ initialize_env (void)
parse_boolean ("OMP_NESTED", &gomp_nest_var);
if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_nthreads_var))
gomp_init_num_threads ();
+ if (parse_affinity ())
+ gomp_init_affinity ();
/* Not strictly environment related, but ordering constructors is tricky. */
pthread_attr_init (&gomp_thread_attr);
diff --git a/contrib/gcclibs/libgomp/iter.c b/contrib/gcclibs/libgomp/iter.c
index 1a8a2a7..2d5dd2e 100644
--- a/contrib/gcclibs/libgomp/iter.c
+++ b/contrib/gcclibs/libgomp/iter.c
@@ -242,16 +242,16 @@ gomp_iter_guided_next_locked (long *pstart, long *pend)
if (ws->next == ws->end)
return false;
- n = (ws->end - ws->next) / ws->incr;
+ start = ws->next;
+ n = (ws->end - start) / ws->incr;
q = (n + nthreads - 1) / nthreads;
if (q < ws->chunk_size)
q = ws->chunk_size;
- if (q > n)
- q = n;
-
- start = ws->next;
- end = start + q * ws->incr;
+ if (q <= n)
+ end = start + q * ws->incr;
+ else
+ end = ws->end;
ws->next = end;
*pstart = start;
@@ -286,15 +286,15 @@ gomp_iter_guided_next (long *pstart, long *pend)
if (start == end)
return false;
- n = (end - start) / ws->incr;
+ n = (end - start) / incr;
q = (n + nthreads - 1) / nthreads;
if (q < chunk_size)
q = chunk_size;
- if (q > n)
- q = n;
-
- nend = start + q * incr;
+ if (__builtin_expect (q <= n, 1))
+ nend = start + q * incr;
+ else
+ nend = end;
tmp = __sync_val_compare_and_swap (&ws->next, start, nend);
if (__builtin_expect (tmp == start, 1))
diff --git a/contrib/gcclibs/libgomp/libgomp.h b/contrib/gcclibs/libgomp/libgomp.h
index 47e68e6..7075250 100644
--- a/contrib/gcclibs/libgomp/libgomp.h
+++ b/contrib/gcclibs/libgomp/libgomp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
@@ -246,8 +246,18 @@ extern unsigned long gomp_run_sched_chunk;
/* The attributes to be used during thread creation. */
extern pthread_attr_t gomp_thread_attr;
+/* Other variables. */
+
+extern unsigned short *gomp_cpu_affinity;
+extern size_t gomp_cpu_affinity_len;
+
/* Function prototypes. */
+/* affinity.c */
+
+extern void gomp_init_affinity (void);
+extern void gomp_init_thread_affinity (pthread_attr_t *);
+
/* alloc.c */
extern void *gomp_malloc (size_t) __attribute__((malloc));
diff --git a/contrib/gcclibs/libgomp/libgomp.texi b/contrib/gcclibs/libgomp/libgomp.texi
index c48cf93..f92a5da 100644
--- a/contrib/gcclibs/libgomp/libgomp.texi
+++ b/contrib/gcclibs/libgomp/libgomp.texi
@@ -895,14 +895,25 @@ dynamic scheduling and a chunk size of 1 is used.
@cindex Environment Variable
@table @asis
@item @emph{Description}:
-A patch for this extension has been submitted, but was not yet applied at the
-time of writing.
-
-@item @emph{Reference}:
-@uref{http://gcc.gnu.org/ml/gcc-patches/2006-05/msg00982.html,
-GCC Patches Mailinglist}
-@uref{http://gcc.gnu.org/ml/gcc-patches/2006-05/msg01133.html,
-GCC Patches Mailinglist}
+Binds threads to specific CPUs. The variable should contain a space- or
+comma-separated list of CPUs. This list may contain different kind of
+entries: either single CPU numbers in any order, a range of CPUs (M-N)
+or a range with some stride (M-N:S). CPU numbers are zero based. For example,
+@code{GOMP_CPU_AFFINITY="0 3 1-2 4-15:2"} will bind the initial thread
+to CPU 0, the second to CPU 3, the third to CPU 1, the fourth to
+CPU 2, the fifth to CPU 4, the sixth through tenth to CPUs 6, 8, 10, 12,
+and 14 respectively and then start assigning back from the beginning of
+the list. @code{GOMP_CPU_AFFINITY=0} binds all threads to CPU 0.
+
+There is no GNU OpenMP library routine to determine whether a CPU affinity
+specification is in effect. As a workaround, language-specific library
+functions, e.g., @code{getenv} in C or @code{GET_ENVIRONMENT_VARIABLE} in
+Fortran, may be used to query the setting of the @code{GOMP_CPU_AFFINITY}
+environment variable. A defined CPU affinity on startup cannot be changed
+or disabled during the runtime of the application.
+
+If this environment variable is omitted, the host system will handle the
+assignment of threads to CPUs.
@end table
diff --git a/contrib/gcclibs/libgomp/omp.h.in b/contrib/gcclibs/libgomp/omp.h.in
index 44fda90..5ebcdbb 100644
--- a/contrib/gcclibs/libgomp/omp.h.in
+++ b/contrib/gcclibs/libgomp/omp.h.in
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
@@ -49,36 +49,39 @@ typedef struct
#ifdef __cplusplus
extern "C" {
+# define __GOMP_NOTHROW throw ()
+#else
+# define __GOMP_NOTHROW __attribute__((__nothrow__))
#endif
-extern void omp_set_num_threads (int);
-extern int omp_get_num_threads (void);
-extern int omp_get_max_threads (void);
-extern int omp_get_thread_num (void);
-extern int omp_get_num_procs (void);
+extern void omp_set_num_threads (int) __GOMP_NOTHROW;
+extern int omp_get_num_threads (void) __GOMP_NOTHROW;
+extern int omp_get_max_threads (void) __GOMP_NOTHROW;
+extern int omp_get_thread_num (void) __GOMP_NOTHROW;
+extern int omp_get_num_procs (void) __GOMP_NOTHROW;
-extern int omp_in_parallel (void);
+extern int omp_in_parallel (void) __GOMP_NOTHROW;
-extern void omp_set_dynamic (int);
-extern int omp_get_dynamic (void);
+extern void omp_set_dynamic (int) __GOMP_NOTHROW;
+extern int omp_get_dynamic (void) __GOMP_NOTHROW;
-extern void omp_set_nested (int);
-extern int omp_get_nested (void);
+extern void omp_set_nested (int) __GOMP_NOTHROW;
+extern int omp_get_nested (void) __GOMP_NOTHROW;
-extern void omp_init_lock (omp_lock_t *);
-extern void omp_destroy_lock (omp_lock_t *);
-extern void omp_set_lock (omp_lock_t *);
-extern void omp_unset_lock (omp_lock_t *);
-extern int omp_test_lock (omp_lock_t *);
+extern void omp_init_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern void omp_destroy_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern void omp_set_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern void omp_unset_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern int omp_test_lock (omp_lock_t *) __GOMP_NOTHROW;
-extern void omp_init_nest_lock (omp_nest_lock_t *);
-extern void omp_destroy_nest_lock (omp_nest_lock_t *);
-extern void omp_set_nest_lock (omp_nest_lock_t *);
-extern void omp_unset_nest_lock (omp_nest_lock_t *);
-extern int omp_test_nest_lock (omp_nest_lock_t *);
+extern void omp_init_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void omp_destroy_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void omp_set_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void omp_unset_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern int omp_test_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
-extern double omp_get_wtime (void);
-extern double omp_get_wtick (void);
+extern double omp_get_wtime (void) __GOMP_NOTHROW;
+extern double omp_get_wtick (void) __GOMP_NOTHROW;
#ifdef __cplusplus
}
diff --git a/contrib/gcclibs/libgomp/omp_lib.h.in b/contrib/gcclibs/libgomp/omp_lib.h.in
index 734f2f7..2376b23 100644
--- a/contrib/gcclibs/libgomp/omp_lib.h.in
+++ b/contrib/gcclibs/libgomp/omp_lib.h.in
@@ -38,16 +38,16 @@
external omp_set_num_threads
external omp_get_dynamic, omp_get_nested
- logical*4 omp_get_dynamic, omp_get_nested
+ logical(4) omp_get_dynamic, omp_get_nested
external omp_test_lock, omp_in_parallel
- logical*4 omp_test_lock, omp_in_parallel
+ logical(4) omp_test_lock, omp_in_parallel
external omp_get_max_threads, omp_get_num_procs
- integer*4 omp_get_max_threads, omp_get_num_procs
+ integer(4) omp_get_max_threads, omp_get_num_procs
external omp_get_num_threads, omp_get_thread_num
- integer*4 omp_get_num_threads, omp_get_thread_num
+ integer(4) omp_get_num_threads, omp_get_thread_num
external omp_test_nest_lock
- integer*4 omp_test_nest_lock
+ integer(4) omp_test_nest_lock
external omp_get_wtick, omp_get_wtime
double precision omp_get_wtick, omp_get_wtime
diff --git a/contrib/gcclibs/libgomp/team.c b/contrib/gcclibs/libgomp/team.c
index 060f4ea..7d50bfc 100644
--- a/contrib/gcclibs/libgomp/team.c
+++ b/contrib/gcclibs/libgomp/team.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
@@ -183,6 +183,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
struct gomp_team *team;
bool nested;
unsigned i, n, old_threads_used = 0;
+ pthread_attr_t thread_attr, *attr;
thr = gomp_thread ();
nested = thr->ts.team != NULL;
@@ -265,6 +266,17 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
}
}
+ attr = &gomp_thread_attr;
+ if (gomp_cpu_affinity != NULL)
+ {
+ size_t stacksize;
+ pthread_attr_init (&thread_attr);
+ pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
+ if (! pthread_attr_getstacksize (&gomp_thread_attr, &stacksize))
+ pthread_attr_setstacksize (&thread_attr, stacksize);
+ attr = &thread_attr;
+ }
+
start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
* (nthreads-i));
@@ -283,12 +295,17 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
start_data->fn_data = data;
start_data->nested = nested;
- err = pthread_create (&pt, &gomp_thread_attr,
- gomp_thread_start, start_data);
+ if (gomp_cpu_affinity != NULL)
+ gomp_init_thread_affinity (attr);
+
+ err = pthread_create (&pt, attr, gomp_thread_start, start_data);
if (err != 0)
gomp_fatal ("Thread creation failed: %s", strerror (err));
}
+ if (gomp_cpu_affinity != NULL)
+ pthread_attr_destroy (&thread_attr);
+
do_release:
gomp_barrier_wait (nested ? &team->barrier : &gomp_threads_dock);
diff --git a/contrib/ipfilter/ipsend/44arp.c b/contrib/ipfilter/ipsend/44arp.c
index 9033ab9..9215959 100644
--- a/contrib/ipfilter/ipsend/44arp.c
+++ b/contrib/ipfilter/ipsend/44arp.c
@@ -8,9 +8,6 @@
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
-#if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-#endif
#include <net/if_dl.h>
#include <net/if_types.h>
#ifndef __osf__
diff --git a/contrib/ipfilter/ipsend/ip.c b/contrib/ipfilter/ipsend/ip.c
index 74d164b..fc76170 100644
--- a/contrib/ipfilter/ipsend/ip.c
+++ b/contrib/ipfilter/ipsend/ip.c
@@ -21,9 +21,6 @@ static const char rcsid[] = "@(#)$Id$";
# include <net/route.h>
# include <netinet/if_ether.h>
# include <netinet/ip_var.h>
-# if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-# endif
#endif
#include <errno.h>
#include <stdio.h>
diff --git a/contrib/ipfilter/ipsend/resend.c b/contrib/ipfilter/ipsend/resend.c
index d113af3..45159bf 100644
--- a/contrib/ipfilter/ipsend/resend.c
+++ b/contrib/ipfilter/ipsend/resend.c
@@ -22,9 +22,6 @@ static const char rcsid[] = "@(#)$Id$";
#ifndef linux
# include <netinet/ip_var.h>
# include <netinet/if_ether.h>
-# if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-# endif
#endif
#include <stdio.h>
#include <netdb.h>
diff --git a/contrib/ipfilter/lib/kmem.c b/contrib/ipfilter/lib/kmem.c
index 382a51c..d895baf 100644
--- a/contrib/ipfilter/lib/kmem.c
+++ b/contrib/ipfilter/lib/kmem.c
@@ -29,9 +29,6 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <net/if.h>
-#if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-#endif
#if defined(linux) || defined(__osf__) || defined(__sgi) || defined(__hpux)
# include <stdlib.h>
#endif
diff --git a/contrib/ipfilter/tools/ipfs.c b/contrib/ipfilter/tools/ipfs.c
index b5484be..43abd74 100644
--- a/contrib/ipfilter/tools/ipfs.c
+++ b/contrib/ipfilter/tools/ipfs.c
@@ -33,9 +33,6 @@
#include <netinet/in_systm.h>
#include <sys/time.h>
#include <net/if.h>
-#if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-#endif
#include <netinet/ip.h>
#include <netdb.h>
#include <arpa/nameser.h>
diff --git a/contrib/ipfilter/tools/ipnat.c b/contrib/ipfilter/tools/ipnat.c
index 448c1c0..c3a7156 100644
--- a/contrib/ipfilter/tools/ipnat.c
+++ b/contrib/ipfilter/tools/ipnat.c
@@ -37,9 +37,6 @@
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/if.h>
-#if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-#endif
#include <netdb.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
diff --git a/contrib/ipfilter/tools/ipnat_y.y b/contrib/ipfilter/tools/ipnat_y.y
index 8c23403..39e6a92 100644
--- a/contrib/ipfilter/tools/ipnat_y.y
+++ b/contrib/ipfilter/tools/ipnat_y.y
@@ -35,9 +35,6 @@
#include <sys/time.h>
#include <syslog.h>
#include <net/if.h>
-#if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-#endif
#include <netdb.h>
#include <arpa/nameser.h>
#include <resolv.h>
diff --git a/contrib/ipfilter/tools/ippool.c b/contrib/ipfilter/tools/ippool.c
index 49cf7da..243932c 100644
--- a/contrib/ipfilter/tools/ippool.c
+++ b/contrib/ipfilter/tools/ippool.c
@@ -15,9 +15,6 @@
#include <sys/ioctl.h>
#include <net/if.h>
-#if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-#endif
#include <netinet/in.h>
#include <arpa/inet.h>
diff --git a/contrib/ipfilter/tools/ippool_y.y b/contrib/ipfilter/tools/ippool_y.y
index 3498745..93593ce 100644
--- a/contrib/ipfilter/tools/ippool_y.y
+++ b/contrib/ipfilter/tools/ippool_y.y
@@ -16,9 +16,6 @@
#include <sys/ioctl.h>
#include <net/if.h>
-#if __FreeBSD_version >= 300000
-# include <net/if_var.h>
-#endif
#include <netinet/in.h>
#include <arpa/inet.h>
diff --git a/contrib/ldns/drill/config.h b/contrib/ldns/drill/config.h
index 74b1e40..f012625 100644
--- a/contrib/ldns/drill/config.h
+++ b/contrib/ldns/drill/config.h
@@ -122,7 +122,7 @@
#define PACKAGE_NAME "ldns"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "ldns 1.6.16"
+#define PACKAGE_STRING "ldns 1.6.17"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libdns"
@@ -131,7 +131,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.6.16"
+#define PACKAGE_VERSION "1.6.17"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
diff --git a/contrib/ldns/drill/drill.1 b/contrib/ldns/drill/drill.1
index 971b73a..cfbde05 100644
--- a/contrib/ldns/drill/drill.1
+++ b/contrib/ldns/drill/drill.1
@@ -83,6 +83,11 @@ Chase the signature(s) of 'name' to a known key or as high up in
the tree as possible.
.TP
+\fB\-I \fIIPv4 or IPv6 address\fR
+Source address to query from. The source address has to be present
+on an interface of the host running drill.
+
+.TP
\fB\-V \fIlevel\fR
Be more verbose. Set level to 5 to see the actual query that is sent.
@@ -217,6 +222,12 @@ specify named base64 tsig key, and optional an algorithm (defaults to hmac-md5.s
\fB\-z \fR
don't randomize the nameserver list before sending queries.
+.SH "EXIT STATUS"
+The exit status is 0 if the looked up answer is secure and trusted,
+or insecure.
+The exit status is not 0 if the looked up answer is untrusted or bogus,
+or an error occurred while performing the lookup.
+
.SH "FILES"
.TP
/etc/unbound/root.key
diff --git a/contrib/ldns/freebsd-configure.sh b/contrib/ldns/freebsd-configure.sh
new file mode 100755
index 0000000..3ad6446
--- /dev/null
+++ b/contrib/ldns/freebsd-configure.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+set -e
+
+ldns=$(dirname $(realpath $0))
+cd $ldns
+
+libtoolize --copy
+autoheader
+autoconf
+./configure --prefix= --exec-prefix=/usr
+
+cd $ldns/drill
+autoheader
+autoconf
+./configure --prefix= --exec-prefix=/usr
diff --git a/contrib/ldns/packaging/fedora/ldns.spec b/contrib/ldns/packaging/fedora/ldns.spec
new file mode 100644
index 0000000..6658d01
--- /dev/null
+++ b/contrib/ldns/packaging/fedora/ldns.spec
@@ -0,0 +1,212 @@
+%{?!with_python: %global with_python 1}
+
+%if %{with_python}
+%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
+%{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
+%endif
+
+Summary: Lowlevel DNS(SEC) library with API
+Name: ldns
+Version: 1.6.13
+Release: 1%{?dist}
+License: BSD
+Url: http://www.nlnetlabs.nl/%{name}/
+Source: http://www.nlnetlabs.nl/downloads/%{%name}/%{name}-%{version}.tar.gz
+Group: System Environment/Libraries
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildRequires: perl, libpcap-devel, openssl-devel , gcc-c++, doxygen,
+# Only needed for builds from svn snapshot
+# BuildRequires: libtool, autoconf, automake
+
+%if %{with_python}
+BuildRequires: python-devel, swig
+%endif
+
+%description
+ldns is a library with the aim to simplify DNS programing in C. All
+lowlevel DNS/DNSSEC operations are supported. We also define a higher
+level API which allows a programmer to (for instance) create or sign
+packets.
+
+%package devel
+Summary: Development package that includes the ldns header files
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+The devel package contains the ldns library and the include files
+
+%if %{with_python}
+%package python
+Summary: Python extensions for ldns
+Group: Applications/System
+Requires: %{name} = %{version}-%{release}
+
+%description python
+Python extensions for ldns
+%endif
+
+%prep
+%setup -q
+# To built svn snapshots
+# rm config.guess config.sub ltmain.sh
+# aclocal
+# libtoolize -c
+# autoreconf
+
+%build
+%configure --disable-rpath --disable-static --with-sha2 --disable-gost \
+%if %{with_python}
+ --with-pyldns
+%endif
+
+(cd drill ; %configure --disable-rpath --disable-static --with-sha2 --disable-gost --with-ldns=%{buildroot}/lib/ )
+(cd examples ; %configure --disable-rpath --disable-static --with-sha2 --disable-gost --with-ldns=%{buildroot}/lib/ )
+
+make %{?_smp_mflags}
+( cd drill ; make %{?_smp_mflags} )
+( cd examples ; make %{?_smp_mflags} )
+make %{?_smp_mflags} doc
+
+%install
+rm -rf %{buildroot}
+
+make DESTDIR=%{buildroot} INSTALL="%{__install} -p" install
+make DESTDIR=%{buildroot} INSTALL="%{__install} -p" install-doc
+
+# don't install another set of man pages from doc/
+rm -rf doc/man/
+
+# don't package building script for install-doc in doc section
+rm doc/doxyparse.pl
+
+# remove .la files
+rm -rf %{buildroot}%{_libdir}/*.la %{buildroot}%{python_sitearch}/*.la
+(cd drill ; make DESTDIR=%{buildroot} install)
+(cd examples; make DESTDIR=%{buildroot} install)
+
+%clean
+rm -rf %{buildroot}
+
+%files
+%defattr(-,root,root)
+%{_libdir}/libldns*so.*
+%{_bindir}/drill
+%{_bindir}/ldnsd
+%{_bindir}/ldns-chaos
+%{_bindir}/ldns-compare-zones
+%{_bindir}/ldns-[d-z]*
+%doc README LICENSE
+%{_mandir}/*/*
+
+%files devel
+%defattr(-,root,root,-)
+%{_libdir}/libldns*so
+%{_bindir}/ldns-config
+%dir %{_includedir}/ldns
+%{_includedir}/ldns/*.h
+%doc doc Changelog README
+
+%if %{with_python}
+%files python
+%defattr(-,root,root)
+%{python_sitearch}/*
+%endif
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%changelog
+* Thu Sep 22 2011 Paul Wouters <paul@xelerance.com> - 1.6.11-1
+- Updated to 1.6.11
+- Cleanup spec for
+- Python goes into sitearch, not sitelib
+
+* Wed Jun 08 2011 Paul Wouters <paul@xelerance.com> - 1.6.10-1
+- Updated to 1.6.10
+- commented out build dependancies for svn snapshots
+
+* Sun Mar 27 2011 Paul Wouters <paul@xelerance.com> - 1.6.9-1
+- Updated to 1.6.9
+
+* Mon Jan 24 2011 Paul Wouters <paul@xelerance.com> - 1.6.8-1
+- Updated to 1.6.8
+
+* Thu Aug 26 2010 Paul Wouters <paul@xelerance.com> - 1.6.6-1
+- Upgraded to 1.6.6
+
+* Mon Apr 26 2010 Paul Wouters <paul@xelerance.com> - 1.6.4-4
+- Disable a debug line that was added to find the LOC issue that causes
+ unexpected output for automated tools using ldns-read-zone
+
+* Thu Feb 11 2010 Paul Wouters <paul@xelerance.com> - 1.6.4-3
+- Applied fix svn 3186 for LOC record parsing
+
+* Fri Jan 22 2010 Paul Wouters <paul@xelerance.com> - 1.6.4-2
+- libtool on EL-5 does not take --install as argument
+
+* Fri Jan 22 2010 Paul Wouters <paul@xelerance.com> - 1.6.4-1
+- Upgraded to 1.6.4
+- Added ldns-python sub package
+- Patch for installing ldns-python files
+- Patch for rpath in ldns-python
+
+* Sun Aug 16 2009 Paul Wouters <paul@xelerance.com> - 1.6.1-2
+- Bump version, sources file was not updated.
+
+* Sun Aug 16 2009 Paul Wouters <paul@xelerance.com> - 1.6.1-1
+-Updated to 1.6.1
+
+* Sat Jul 11 2009 Paul Wouters <paul@xelerance.com> - 1.6.0-1
+- Updated to 1.6.0
+
+* Thu Apr 16 2009 Paul Wouters <paul@xelerance.com> - 1.5.1-2
+- Memory management bug when generating a sha256 key, see:
+ https://bugzilla.redhat.com/show_bug.cgi?id=493953
+
+* Fri Feb 13 2009 Paul Wouters <paul@xelerance.com> - 1.5.1-1
+- Upgrade to 1.5.1 (1.5.0 was a dud release)
+
+* Sun Nov 9 2008 Paul Wouters <paul@xelerance.com> - 1.4.0-2
+- libldns.so was missing in files section.
+
+* Sun Nov 9 2008 Paul Wouters <paul@xelerance.com> - 1.4.0-1
+- Updated to 1.4.0
+- enable SHA2 functionality
+
+* Mon Jun 30 2008 Paul Wouters <paul@xelerance.com> - 1.3.0-1
+- Updated to latest release
+
+* Thu Nov 29 2007 Paul Wouters <paul@xelerance.com> - 1.2.2-1
+- Upgraded to 1.2.2.
+
+* Mon Sep 11 2006 Paul Wouters <paul@xelerance.com> 1.0.1-4
+- Commented out 1.1.0 make targets, put make 1.0.1 targets.
+
+* Mon Sep 11 2006 Paul Wouters <paul@xelerance.com> 1.0.1-3
+- Fixed changelog typo in date
+- Rebuild requested for PT_GNU_HASH support from gcc
+- Did not upgrade to 1.1.0 due to compile issues on x86_64
+
+* Fri Jan 6 2006 Paul Wouters <paul@xelerance.com> 1.0.1-1
+- Upgraded to 1.0.1. Removed temporary clean hack from spec file.
+
+* Sun Dec 18 2005 Paul Wouters <paul@xelerance.com> 1.0.0-8
+- Cannot use make clean because there are no Makefiles. Use hardcoded rm.
+
+* Sun Dec 18 2005 Paul Wouters <paul@xelerance.com> 1.0.0-7
+- Patched 'make clean' target to get rid of object files shipped with 1.0.0
+
+* Sun Dec 13 2005 Paul Wouters <paul@xelerance.com> 1.0.0-6
+- added a make clean for 2.3.3 since .o files were left behind upstream,
+ causing failure on ppc platform
+
+* Sun Dec 11 2005 Tom "spot" Callaway <tcallawa@redhat.com> 1.0.0-5
+- minor cleanups
+
+* Wed Oct 5 2005 Paul Wouters <paul@xelerance.com> 0.70_1205
+- reworked for svn version
+
+* Sun Sep 25 2005 Paul Wouters <paul@xelerance.com> - 0.70
+- Initial version
diff --git a/contrib/ldns/packaging/ldns-config.1 b/contrib/ldns/packaging/ldns-config.1
new file mode 100644
index 0000000..c5a00a1
--- /dev/null
+++ b/contrib/ldns/packaging/ldns-config.1
@@ -0,0 +1,43 @@
+.TH ldns-config 1 "22 Sep 2011"
+.SH NAME
+ldns-config \- show compiler and linker flags for ldns usage.
+.SH SYNOPSIS
+.B ldns-config
+[
+.IR OPTIONS
+]
+
+.SH DESCRIPTION
+When writing programs using ldns, you have to tell the compiler
+where to look for include files and what libraries from which location
+to link to. \fBldns-config\fR can be used to find out what flags to use
+with the C compiler and the linker.
+
+.SH OPTIONS
+.TP
+\fB--cflags\fR
+Show the C compiler flags needed to compile with ldns
+
+.TP
+\fB--libs\fR
+Show the flags to be used to link with ldns
+
+.TP
+\fB--version\fR
+Shows the version of the installed ldns library
+
+.TP
+\fB--help\fR
+Show \fBldns-config\fR usage description
+
+.SH AUTHOR
+Written by the ldns team.
+
+.SH REPORTING BUGS
+Report bugs to <ldns-team@nlnetlabs.nl>.
+
+.SH COPYRIGHT
+Copyright (C) 2011 NLnet Labs. This is free software. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.
+
diff --git a/contrib/ldns/packaging/ldns-config.in b/contrib/ldns/packaging/ldns-config.in
new file mode 100755
index 0000000..b728ba5
--- /dev/null
+++ b/contrib/ldns/packaging/ldns-config.in
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+VERSION="@PACKAGE_VERSION@"
+CFLAGS="@CFLAGS@"
+CPPFLAGS="@CPPFLAGS@ @LIBSSL_CPPFLAGS@ @PYTHON_CPPFLAGS@"
+LDFLAGS="@LDFLAGS@ @LIBSSL_LDFLAGS@ @PYTHON_LDFLAGS@"
+LIBS="@LIBS@ @LIBSSL_LIBS@"
+LIBDIR="@libdir@"
+INCLUDEDIR="@includedir@"
+
+for arg in $@
+do
+ if [ $arg = "--cflags" ]
+ then
+ echo "-I${INCLUDEDIR}"
+ fi
+ if [ $arg = "--libs" ]
+ then
+ echo "${LDFLAGS} -L${LIBDIR} ${LIBS} -lldns"
+ fi
+ if [ $arg = "-h" ] || [ $arg = "--help" ]
+ then
+ echo "Usage: $0 [--cflags] [--libs] [--version]"
+ fi
+ if [ $arg = "--version" ]
+ then
+ echo "${VERSION}"
+ fi
+done
diff --git a/contrib/ldns/packaging/libldns.pc.in b/contrib/ldns/packaging/libldns.pc.in
new file mode 100644
index 0000000..923b688
--- /dev/null
+++ b/contrib/ldns/packaging/libldns.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ldns
+Description: Library for DNS programming
+URL: http://www.nlnetlabs.nl/projects/ldns
+Version: @PACKAGE_VERSION@
+Requires:
+Libs: -L${libdir} -lldns
+Libs.private: @LDFLAGS@
+Cflags: -I${includedir}
diff --git a/contrib/libxo/Makefile.am b/contrib/libxo/Makefile.am
index 4ff2aad..1abfd5e 100644
--- a/contrib/libxo/Makefile.am
+++ b/contrib/libxo/Makefile.am
@@ -10,7 +10,7 @@
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = libxo xo xolint tests doc
+SUBDIRS = libxo xo xolint xohtml tests doc
bin_SCRIPTS=libxo-config
dist_doc_DATA = Copyright
diff --git a/contrib/libxo/configure.ac b/contrib/libxo/configure.ac
index b2553b8..5491d57 100644
--- a/contrib/libxo/configure.ac
+++ b/contrib/libxo/configure.ac
@@ -12,7 +12,7 @@
#
AC_PREREQ(2.2)
-AC_INIT([libxo], [0.2.0], [phil@juniper.net])
+AC_INIT([libxo], [0.3.2], [phil@juniper.net])
AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability])
# Support silent build rules. Requires at least automake-1.11.
@@ -133,6 +133,14 @@ AC_ARG_ENABLE([debug],
AC_MSG_RESULT([$LIBXO_DEBUG])
AM_CONDITIONAL([LIBXO_DEBUG], [test "$LIBXO_DEBUG" != "no"])
+AC_MSG_CHECKING([whether to build with text-only rendering])
+AC_ARG_ENABLE([text-only],
+ [ --enable-text-only Turn on text-only rendering],
+ [LIBXO_TEXT_ONLY=yes; AC_DEFINE([LIBXO_TEXT_ONLY], [1], [Enable text-only rendering])],
+ [LIBXO_TEXT_ONLY=no])
+AC_MSG_RESULT([$LIBXO_TEXT_ONLY])
+AM_CONDITIONAL([LIBXO_TEXT_ONLY], [test "$LIBXO_TEXT_ONLY" != "no"])
+
AC_CHECK_LIB([m], [lrint])
AM_CONDITIONAL([HAVE_LIBM], [test "$HAVE_LIBM" != "no"])
@@ -233,6 +241,7 @@ AC_CONFIG_FILES([
libxo/xoversion.h
xo/Makefile
xolint/Makefile
+ xohtml/Makefile
packaging/libxo.pc
doc/Makefile
tests/Makefile
@@ -253,6 +262,7 @@ AC_MSG_NOTICE([summary of build options:
bindir: ${XO_BINDIR}
includedir: ${XO_INCLUDEDIR}
share dir: ${XO_SHAREDIR}
+ oxtradoc dir: ${SLAX_OXTRADOCDIR}
compiler: ${CC} (${HAVE_GCC:-no})
compiler flags: ${CFLAGS}
@@ -262,4 +272,5 @@ AC_MSG_NOTICE([summary of build options:
debug: ${LIBXO_DEBUG:-no}
printf-like: ${HAVE_PRINTFLIKE:-no}
libxo-options: ${LIBXO_OPTS:-no}
+ text-only: ${LIBXO_TEXT_ONLY:-no}
])
diff --git a/contrib/libxo/doc/libxo.txt b/contrib/libxo/doc/libxo.txt
index 31aec53..81a40b6 100644
--- a/contrib/libxo/doc/libxo.txt
+++ b/contrib/libxo/doc/libxo.txt
@@ -134,7 +134,7 @@ A single libxo function call in source code is all that's required:
<host>my-box</host>
<domain>example.com</domain>
JSON:
- "host": my-box",
+ "host": "my-box",
"domain": "example.com"
For brevity, the HTML output is emitted.
@@ -228,17 +228,17 @@ data, including data type, description, and an XPath location.
<div class="line">
<div class="data" data-tag="blocks">36</div>
<div class="padding"> </div>
- <div class="data data-tag="path">./src</div>
+ <div class="data" data-tag="path">./src</div>
</div>
<div class="line">
<div class="data" data-tag="blocks">40</div>
<div class="padding"> </div>
- <div class="data data-tag="path">./bin</div>
+ <div class="data" data-tag="path">./bin</div>
</div>
<div class="line">
<div class="data" data-tag="blocks">90</div>
<div class="padding"> </div>
- <div class="data data-tag="path">./</div>
+ <div class="data" data-tag="path">./</div>
</div>
** Format Strings @format-strings@
@@ -285,6 +285,7 @@ content. The roles are listed below; only one role is permitted:
|---+--------------+-------------------------------------------------|
| M | Name | Description |
|---+--------------+-------------------------------------------------|
+| C | color/effect | Field has color and effect controls |
| D | decoration | Field is non-text (e.g., colon, comma) |
| E | error | Field is an error message |
| L | label | Field is text that prefixes a value |
@@ -298,6 +299,56 @@ content. The roles are listed below; only one role is permitted:
| ] | stop anchor | End a section of anchored variable-width text |
|---+--------------+-------------------------------------------------|
+**** The Color Role ({C:})
+
+Colors and effects control how text values are displayed; they are
+used for display styles (TEXT and HTML). The color content can be
+either static, when placed directly within the field descriptor, or a
+printf-style format descriptor can be used, if preceded by a slash ("/"):
+
+ xo_emit("{C:bold}{Lwc:Cost}{:cost/%u}{C:reset}\n", cost);
+ xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n",
+ fg_color, bg_color, cost);
+
+The content should be a comma-separated list of zero or more colors or
+display effects. Colors and effects remain in effect until
+modified by other "C" roles. If the content is empty, the "reset"
+action is performed.
+
+|---------------+-------------------------------------------------|
+| Name | Description |
+|---------------+-------------------------------------------------|
+| bg-XXXXX | Change background color |
+| bold | Start bold text effect |
+| fg-XXXXX | Change foreground color |
+| inverse | Start inverse (aka reverse) text effect |
+| no-bold | Stop bold text effect |
+| no-inverse | Stop inverse (aka reverse) text effect |
+| no-underline | Stop underline text effect |
+| normal | Reset effects (only) |
+| reset | Reset colors and effects (restore defaults) |
+| underline | Start underline text effect |
+|---------------+-------------------------------------------------|
+
+The following color names are supported:
+
+|---------------|
+| Name |
+|---------------|
+| black |
+| blue |
+| cyan |
+| default |
+| green |
+| magenta |
+| red |
+| white |
+| yellow |
+|---------------|
+
+Color names are prefixed with either "fg-" or "bg-" to change the
+foreground and background colors, respectively.
+
**** The Decoration Role ({D:})
Decorations are typically punctuation marks such as colons,
@@ -1404,9 +1455,21 @@ functions like xo_failure, xo_warn, xo_err, etc. The program name is
initialized by xo_parse_args, but subsequent calls to xo_set_program
can override this value.
+ xo_set_program(argv[0]);
+
Note that the value is not copied, so the memory passed to
xo_set_program (and xo_parse_args) must be maintained by the caller.
+*** xo_set_version
+
+The xo_set_version function records a version number to be emitted as
+part of the data for encoding styles (XML and JSON). This version
+number is suitable for tracking changes in the content, allowing a
+user of the data to discern which version of the data model is in use.
+
+ void xo_set_version (const char *version);
+ void xo_set_version_h (xo_handle_t *xop, const char *version);
+
*** Field Information (xo_info_t) @info@
HTML data can include additional information in attributes that
@@ -1705,6 +1768,32 @@ The "-V" option does not report errors, but prints a complete list of
all field names, sorted alphabetically. The output can help spot
inconsistencies and spelling errors.
+* xohtml
+
+xohtml is a tool for turning the output of libxo-enabled commands into
+html files suitable for display in modern HTML web browsers. It can
+be used to test and debug HTML output, as well as to make the user
+ache to escape the world of 70s terminal devices.
+
+xohtml is given a command, either on the command line or via the "-c"
+option. If not command is given, standard input is used. The
+command's output is wrapped in HTML tags, with references to
+supporting CSS and Javascript files, and written to standard output or
+the file given in the "-f" option. The "-b" option can be used to
+provide an alternative base path for the support files.
+
+|--------------+---------------------------------------------------|
+| Option | Meaning |
+|--------------+---------------------------------------------------|
+| -b <base> | Base path for finding css/javascript files |
+| -c <command> | Command to execute |
+| -f <file> | Output file name |
+|--------------+---------------------------------------------------|
+
+The "-c" option takes a full command with arguments, including
+any libxo options needed to generate html ("--libxo=html"). This
+value must be quoted if it consists of multiple tokens.
+
* FAQs
This section contains the set of questions that users typically ask,
diff --git a/contrib/libxo/libxo/Makefile.am b/contrib/libxo/libxo/Makefile.am
index 3303e94..0047b63 100644
--- a/contrib/libxo/libxo/Makefile.am
+++ b/contrib/libxo/libxo/Makefile.am
@@ -38,12 +38,15 @@ man_MANS = \
xo_no_setlocale.3 \
xo_open_container.3 \
xo_open_list.3 \
+ xo_open_marker.3 \
xo_parse_args.3 \
xo_set_allocator.3 \
xo_set_flags.3 \
xo_set_info.3 \
xo_set_options.3 \
xo_set_style.3 \
+ xo_set_version.3 \
xo_set_writer.3
-EXTRA_DIST =
+EXTRA_DIST = ${man_MANS}
+
diff --git a/contrib/libxo/libxo/libxo.c b/contrib/libxo/libxo/libxo.c
index e9d05ce..4fd18fd 100644
--- a/contrib/libxo/libxo/libxo.c
+++ b/contrib/libxo/libxo/libxo.c
@@ -121,6 +121,50 @@ typedef struct xo_stack_s {
char *xs_keys; /* XPath predicate for any key fields */
} xo_stack_t;
+/* "colors" refers to fancy ansi codes */
+#define XO_COL_DEFAULT 0
+#define XO_COL_BLACK 1
+#define XO_COL_RED 2
+#define XO_COL_GREEN 3
+#define XO_COL_YELLOW 4
+#define XO_COL_BLUE 5
+#define XO_COL_MAGENTA 6
+#define XO_COL_CYAN 7
+#define XO_COL_WHITE 8
+
+#define XO_NUM_COLORS 9
+
+/* "effects" refers to fancy ansi codes */
+/*
+ * Yes, there's no blink. We're civilized. We like users. Blink
+ * isn't something one does to someone you like. Friends don't let
+ * friends use blink. On friends. You know what I mean. Blink is
+ * like, well, it's like bursting into show tunes at a funeral. It's
+ * just not done. Not something anyone wants. And on those rare
+ * instances where it might actually be appropriate, it's still wrong.
+ * It's likely done my the wrong person for the wrong reason. Just
+ * like blink. And if I implemented blink, I'd be like a funeral
+ * director who adds "Would you like us to burst into show tunes?" on
+ * the list of questions asking while making funeral arrangements.
+ * It's formalizing wrongness in the wrong way. And we're just too
+ * civilized to do that. Hhhmph!
+ */
+#define XO_EFF_RESET (1<<0)
+#define XO_EFF_NORMAL (1<<1)
+#define XO_EFF_BOLD (1<<2)
+#define XO_EFF_UNDERLINE (1<<3)
+#define XO_EFF_INVERSE (1<<4)
+
+#define XO_EFF_CLEAR_BITS XO_EFF_RESET
+
+typedef uint8_t xo_effect_t;
+typedef uint8_t xo_color_t;
+typedef struct xo_colors_s {
+ xo_effect_t xoc_effects; /* Current effect set */
+ xo_color_t xoc_col_fg; /* Foreground color */
+ xo_color_t xoc_col_bg; /* Background color */
+} xo_colors_t;
+
/*
* xo_handle_t: this is the principle data structure for libxo.
* It's used as a store for state, options, and content.
@@ -136,7 +180,6 @@ struct xo_handle_s {
xo_formatter_t xo_formatter; /* Custom formating function */
xo_checkpointer_t xo_checkpointer; /* Custom formating support function */
void *xo_opaque; /* Opaque data for write function */
- FILE *xo_fp; /* XXX File pointer */
xo_buffer_t xo_data; /* Output data */
xo_buffer_t xo_fmt; /* Work area for building format strings */
xo_buffer_t xo_attrs; /* Work area for building XML attributes */
@@ -154,6 +197,11 @@ struct xo_handle_s {
int xo_anchor_min_width; /* Desired width of anchored text */
unsigned xo_units_offset; /* Start of units insertion point */
unsigned xo_columns; /* Columns emitted during this xo_emit call */
+ uint8_t xo_color_map_fg[XO_NUM_COLORS]; /* Foreground color mappings */
+ uint8_t xo_color_map_bg[XO_NUM_COLORS]; /* Background color mappings */
+ xo_colors_t xo_colors; /* Current color and effect values */
+ xo_buffer_t xo_color_buf; /* HTML: buffer of colors and effects */
+ char *xo_version; /* Version string */
};
/* Flags for formatting functions */
@@ -161,7 +209,7 @@ typedef unsigned long xo_xff_flags_t;
#define XFF_COLON (1<<0) /* Append a ":" */
#define XFF_COMMA (1<<1) /* Append a "," iff there's more output */
#define XFF_WS (1<<2) /* Append a blank */
-#define XFF_ENCODE_ONLY (1<<3) /* Only emit for encoding formats (xml and json) */
+#define XFF_ENCODE_ONLY (1<<3) /* Only emit for encoding formats (xml, json) */
#define XFF_QUOTE (1<<4) /* Force quotes */
#define XFF_NOQUOTE (1<<5) /* Force no quotes */
@@ -277,6 +325,24 @@ static void
xo_anchor_clear (xo_handle_t *xop);
/*
+ * xo_style is used to retrieve the current style. When we're built
+ * for "text only" mode, we use this function to drive the removal
+ * of most of the code in libxo. We return a constant and the compiler
+ * happily removes the non-text code that is not longer executed. This
+ * trims our code nicely without needing to trampel perfectly readable
+ * code with ifdefs.
+ */
+static inline unsigned short
+xo_style (xo_handle_t *xop UNUSED)
+{
+#ifdef LIBXO_TEXT_ONLY
+ return XO_STYLE_TEXT;
+#else /* LIBXO_TEXT_ONLY */
+ return xop->xo_style;
+#endif /* LIBXO_TEXT_ONLY */
+}
+
+/*
* Callback to write data to a FILE pointer
*/
static int
@@ -321,6 +387,24 @@ xo_buf_init (xo_buffer_t *xbp)
}
/*
+ * Reset the buffer to empty
+ */
+static void
+xo_buf_reset (xo_buffer_t *xbp)
+{
+ xbp->xb_curp = xbp->xb_bufp;
+}
+
+/*
+ * Reset the buffer to empty
+ */
+static int
+xo_buf_is_empty (xo_buffer_t *xbp)
+{
+ return (xbp->xb_curp == xbp->xb_bufp);
+}
+
+/*
* Initialize the contents of an xo_buffer_t.
*/
static void
@@ -363,8 +447,8 @@ xo_no_setlocale (void)
/*
* We need to decide if stdout is line buffered (_IOLBF). Lacking a
* standard way to decide this (e.g. getlinebuf()), we have configure
- * look to find __flbf, which glibc supported. If not, we'll rely
- * on isatty, with the assumption that terminals are the only thing
+ * look to find __flbf, which glibc supported. If not, we'll rely on
+ * isatty, with the assumption that terminals are the only thing
* that's line buffered. We _could_ test for "steam._flags & _IOLBF",
* which is all __flbf does, but that's even tackier. Like a
* bedazzled Elvis outfit on an ugly lap dog sort of tacky. Not
@@ -399,6 +483,13 @@ xo_init_handle (xo_handle_t *xop)
xop->xo_flags |= XOF_FLUSH_LINE;
/*
+ * We only want to do color output on terminals, but we only want
+ * to do this if the user has asked for color.
+ */
+ if ((xop->xo_flags & XOF_COLOR_ALLOWED) && isatty(1))
+ xop->xo_flags |= XOF_COLOR;
+
+ /*
* We need to initialize the locale, which isn't really pretty.
* Libraries should depend on their caller to set up the
* environment. But we really can't count on the caller to do
@@ -497,7 +588,7 @@ xo_default (xo_handle_t *xop)
/*
* Return the number of spaces we should be indenting. If
- * we are pretty-printing, theis is indent * indent_by.
+ * we are pretty-printing, this is indent * indent_by.
*/
static int
xo_indent (xo_handle_t *xop)
@@ -647,6 +738,21 @@ xo_buf_append (xo_buffer_t *xbp, const char *str, int len)
xbp->xb_curp += len;
}
+/*
+ * Append the given NUL-terminated string to the given buffer
+ */
+static void
+xo_buf_append_str (xo_buffer_t *xbp, const char *str)
+{
+ int len = strlen(str);
+
+ if (!xo_buf_has_room(xbp, len))
+ return;
+
+ memcpy(xbp->xb_curp, str, len);
+ xbp->xb_curp += len;
+}
+
static void
xo_buf_escape (xo_handle_t *xop, xo_buffer_t *xbp,
const char *str, int len, xo_xff_flags_t flags)
@@ -656,7 +762,7 @@ xo_buf_escape (xo_handle_t *xop, xo_buffer_t *xbp,
memcpy(xbp->xb_curp, str, len);
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
case XO_STYLE_HTML:
len = xo_escape_xml(xbp, len, (flags & XFF_ATTR));
@@ -711,7 +817,7 @@ xo_vsnprintf (xo_handle_t *xop, xo_buffer_t *xbp, const char *fmt, va_list vap)
else
rc = vsnprintf(xbp->xb_curp, left, fmt, va_local);
- if (rc > xbp->xb_size) {
+ if (rc >= left) {
if (!xo_buf_has_room(xbp, rc)) {
va_end(va_local);
return -1;
@@ -721,7 +827,7 @@ xo_vsnprintf (xo_handle_t *xop, xo_buffer_t *xbp, const char *fmt, va_list vap)
* After we call vsnprintf(), the stage of vap is not defined.
* We need to copy it before we pass. Then we have to do our
* own logic below to move it along. This is because the
- * implementation can have va_list be a point (bsd) or a
+ * implementation can have va_list be a pointer (bsd) or a
* structure (macosx) or anything in between.
*/
@@ -730,7 +836,7 @@ xo_vsnprintf (xo_handle_t *xop, xo_buffer_t *xbp, const char *fmt, va_list vap)
left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
if (xop->xo_formatter)
- xop->xo_formatter(xop, xbp->xb_curp, left, fmt, va_local);
+ rc = xop->xo_formatter(xop, xbp->xb_curp, left, fmt, va_local);
else
rc = vsnprintf(xbp->xb_curp, left, fmt, va_local);
}
@@ -1219,7 +1325,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
int need_nl = (fmt[strlen(fmt) - 1] != '\n');
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
xbp = &xop->xo_data;
if (xop->xo_flags & XOF_PRETTY)
@@ -1431,6 +1537,10 @@ xo_destroy (xo_handle_t *xop_arg)
xo_buf_cleanup(&xop->xo_fmt);
xo_buf_cleanup(&xop->xo_predicate);
xo_buf_cleanup(&xop->xo_attrs);
+ xo_buf_cleanup(&xop->xo_color_buf);
+
+ if (xop->xo_version)
+ xo_free(xop->xo_version);
if (xop_arg == NULL) {
bzero(&xo_default_handle, sizeof(xo_default_handle));
@@ -1457,7 +1567,7 @@ xo_style_t
xo_get_style (xo_handle_t *xop)
{
xop = xo_default(xop);
- return xop->xo_style;
+ return xo_style(xop);
}
static int
@@ -1492,6 +1602,8 @@ xo_name_to_flag (const char *name)
return XOF_INFO;
if (strcmp(name, "warn-xml") == 0)
return XOF_WARN_XML;
+ if (strcmp(name, "color") == 0)
+ return XOF_COLOR_ALLOWED;
if (strcmp(name, "columns") == 0)
return XOF_COLUMNS;
if (strcmp(name, "dtrt") == 0)
@@ -1547,6 +1659,11 @@ xo_set_options (xo_handle_t *xop, const char *input)
xop = xo_default(xop);
+#ifdef LIBXO_COLOR_ON_BY_DEFAULT
+ /* If the installer used --enable-color-on-by-default, then we allow it */
+ xop->xo_flags |= XOF_COLOR_ALLOWED;
+#endif /* LIBXO_COLOR_ON_BY_DEFAULT */
+
/*
* We support a simpler, old-school style of giving option
* also, using a single character for each option. It's
@@ -1557,6 +1674,10 @@ xo_set_options (xo_handle_t *xop, const char *input)
for (input++ ; *input; input++) {
switch (*input) {
+ case 'c':
+ xop->xo_flags |= XOF_COLOR_ALLOWED;
+ break;
+
case 'f':
xop->xo_flags |= XOF_FLUSH;
break;
@@ -1634,6 +1755,11 @@ xo_set_options (xo_handle_t *xop, const char *input)
if (vp)
*vp++ = '\0';
+ if (strcmp("colors", cp) == 0) {
+ /* XXX Look for colors=red-blue+green-yellow */
+ continue;
+ }
+
new_style = xo_name_to_style(cp);
if (new_style >= 0) {
if (style >= 0)
@@ -1645,7 +1771,9 @@ xo_set_options (xo_handle_t *xop, const char *input)
if (new_flag != 0)
xop->xo_flags |= new_flag;
else {
- if (strcmp(cp, "indent") == 0) {
+ if (strcmp(cp, "no-color") == 0) {
+ xop->xo_flags &= ~XOF_COLOR_ALLOWED;
+ } else if (strcmp(cp, "indent") == 0) {
xop->xo_indent_by = atoi(vp);
} else {
xo_warnx("unknown option: '%s'", cp);
@@ -1801,7 +1929,7 @@ xo_line_ensure_open (xo_handle_t *xop, xo_xff_flags_t flags UNUSED)
if (xop->xo_flags & XOF_DIV_OPEN)
return;
- if (xop->xo_style != XO_STYLE_HTML)
+ if (xo_style(xop) != XO_STYLE_HTML)
return;
xop->xo_flags |= XOF_DIV_OPEN;
@@ -1819,7 +1947,7 @@ xo_line_close (xo_handle_t *xop)
{
static char div_close[] = "</div>";
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_HTML:
if (!(xop->xo_flags & XOF_DIV_OPEN))
xo_line_ensure_open(xop, 0);
@@ -1976,7 +2104,7 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
if (width < 0)
width = iswcntrl(wc) ? 0 : 1;
- if (xop->xo_style == XO_STYLE_TEXT || xop->xo_style == XO_STYLE_HTML) {
+ if (xo_style(xop) == XO_STYLE_TEXT || xo_style(xop) == XO_STYLE_HTML) {
if (max > 0 && cols + width > max)
break;
}
@@ -1985,7 +2113,7 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
case XF_ENC_UTF8:
/* Output in UTF-8 needs to be escaped, based on the style */
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
case XO_STYLE_HTML:
if (wc == '<')
@@ -2071,7 +2199,7 @@ xo_format_string (xo_handle_t *xop, xo_buffer_t *xbp, xo_xff_flags_t flags,
wchar_t *wcp = NULL;
int len, cols = 0, rc = 0;
int off = xbp->xb_curp - xbp->xb_bufp, off2;
- int need_enc = (xop->xo_style == XO_STYLE_TEXT)
+ int need_enc = (xo_style(xop) == XO_STYLE_TEXT)
? XF_ENC_LOCALE : XF_ENC_UTF8;
if (xo_check_conversion(xop, xfp->xf_enc, need_enc))
@@ -2185,7 +2313,7 @@ static void
xo_data_append_content (xo_handle_t *xop, const char *str, int len)
{
int cols;
- int need_enc = (xop->xo_style == XO_STYLE_TEXT)
+ int need_enc = (xo_style(xop) == XO_STYLE_TEXT)
? XF_ENC_LOCALE : XF_ENC_UTF8;
cols = xo_format_string_direct(xop, &xop->xo_data, XFF_UNESCAPE,
@@ -2246,9 +2374,9 @@ xo_format_data (xo_handle_t *xop, xo_buffer_t *xbp,
xo_format_t xf;
const char *cp, *ep, *sp, *xp = NULL;
int rc, cols;
- int style = (flags & XFF_XML) ? XO_STYLE_XML : xop->xo_style;
+ int style = (flags & XFF_XML) ? XO_STYLE_XML : xo_style(xop);
unsigned make_output = !(flags & XFF_NO_OUTPUT);
- int need_enc = (xop->xo_style == XO_STYLE_TEXT)
+ int need_enc = (xo_style(xop) == XO_STYLE_TEXT)
? XF_ENC_LOCALE : XF_ENC_UTF8;
if (xbp == NULL)
@@ -2310,11 +2438,11 @@ xo_format_data (xo_handle_t *xop, xo_buffer_t *xbp,
/* Hidden fields are only visible to JSON and XML */
if (xop->xo_flags & XFF_ENCODE_ONLY) {
if (style != XO_STYLE_XML
- && xop->xo_style != XO_STYLE_JSON)
+ && xo_style(xop) != XO_STYLE_JSON)
xf.xf_skip = 1;
} else if (xop->xo_flags & XFF_DISPLAY_ONLY) {
if (style != XO_STYLE_TEXT
- && xop->xo_style != XO_STYLE_HTML)
+ && xo_style(xop) != XO_STYLE_HTML)
xf.xf_skip = 1;
}
@@ -2420,8 +2548,8 @@ xo_format_data (xo_handle_t *xop, xo_buffer_t *xbp,
rc = xo_format_string(xop, xbp, flags, &xf);
if ((flags & XFF_TRIM_WS)
- && (xop->xo_style == XO_STYLE_XML
- || xop->xo_style == XO_STYLE_JSON))
+ && (xo_style(xop) == XO_STYLE_XML
+ || xo_style(xop) == XO_STYLE_JSON))
rc = xo_trim_ws(xbp, rc);
} else {
@@ -2567,6 +2695,20 @@ xo_fix_encoding (xo_handle_t *xop UNUSED, char *encoding)
}
static void
+xo_color_append_html (xo_handle_t *xop)
+{
+ /*
+ * If the color buffer has content, we add it now. It's already
+ * prebuilt and ready, since we want to add it to every <div>.
+ */
+ if (!xo_buf_is_empty(&xop->xo_color_buf)) {
+ xo_buffer_t *xbp = &xop->xo_color_buf;
+
+ xo_data_append(xop, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp);
+ }
+}
+
+static void
xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
const char *name, int nlen,
const char *value, int vlen,
@@ -2663,6 +2805,16 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
xo_data_append(xop, div_start, sizeof(div_start) - 1);
xo_data_append(xop, class, strlen(class));
+ /*
+ * If the color buffer has content, we add it now. It's already
+ * prebuilt and ready, since we want to add it to every <div>.
+ */
+ if (!xo_buf_is_empty(&xop->xo_color_buf)) {
+ xo_buffer_t *xbp = &xop->xo_color_buf;
+
+ xo_data_append(xop, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp);
+ }
+
if (name) {
xo_data_append(xop, div_tag, sizeof(div_tag) - 1);
xo_data_escape(xop, name, nlen);
@@ -2753,7 +2905,7 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
static void
xo_format_text (xo_handle_t *xop, const char *str, int len)
{
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_TEXT:
xo_buf_append_locale(xop, &xop->xo_data, str, len);
break;
@@ -2768,7 +2920,8 @@ static void
xo_format_title (xo_handle_t *xop, const char *str, int len,
const char *fmt, int flen)
{
- static char div_open[] = "<div class=\"title\">";
+ static char div_open[] = "<div class=\"title";
+ static char div_middle[] = "\">";
static char div_close[] = "</div>";
if (flen == 0) {
@@ -2776,7 +2929,7 @@ xo_format_title (xo_handle_t *xop, const char *str, int len,
flen = 2;
}
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
case XO_STYLE_JSON:
/*
@@ -2794,12 +2947,14 @@ xo_format_title (xo_handle_t *xop, const char *str, int len,
int rc;
int need_enc = XF_ENC_LOCALE;
- if (xop->xo_style == XO_STYLE_HTML) {
+ if (xo_style(xop) == XO_STYLE_HTML) {
need_enc = XF_ENC_UTF8;
xo_line_ensure_open(xop, 0);
if (xop->xo_flags & XOF_PRETTY)
xo_buf_indent(xop, xop->xo_indent_by);
xo_buf_append(&xop->xo_data, div_open, sizeof(div_open) - 1);
+ xo_color_append_html(xop);
+ xo_buf_append(&xop->xo_data, div_middle, sizeof(div_middle) - 1);
}
start = xbp->xb_curp - xbp->xb_bufp; /* Reset start */
@@ -2862,7 +3017,7 @@ xo_format_title (xo_handle_t *xop, const char *str, int len,
}
/* If we're styling HTML, then we need to escape it */
- if (xop->xo_style == XO_STYLE_HTML) {
+ if (xo_style(xop) == XO_STYLE_HTML) {
rc = xo_escape_xml(xbp, rc, 0);
}
@@ -2870,7 +3025,7 @@ xo_format_title (xo_handle_t *xop, const char *str, int len,
xbp->xb_curp += rc;
move_along:
- if (xop->xo_style == XO_STYLE_HTML) {
+ if (xo_style(xop) == XO_STYLE_HTML) {
xo_data_append(xop, div_close, sizeof(div_close) - 1);
if (xop->xo_flags & XOF_PRETTY)
xo_data_append(xop, "\n", 1);
@@ -2978,7 +3133,7 @@ xo_format_value (xo_handle_t *xop, const char *name, int nlen,
}
}
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_TEXT:
if (flags & XFF_ENCODE_ONLY)
flags |= XFF_NO_OUTPUT;
@@ -3103,7 +3258,9 @@ xo_format_value (xo_handle_t *xop, const char *name, int nlen,
}
if (flags & XFF_LEAF_LIST) {
- if (first && pretty)
+ if (!first && pretty)
+ xo_data_append(xop, "\n", 1);
+ if (pretty)
xo_buf_indent(xop, -1);
} else {
if (pretty)
@@ -3122,10 +3279,10 @@ xo_format_value (xo_handle_t *xop, const char *name, int nlen,
xbp->xb_bufp[off] = '_';
}
xo_data_append(xop, "\":", 2);
+ if (pretty)
+ xo_data_append(xop, " ", 1);
}
- if (pretty)
- xo_data_append(xop, " ", 1);
if (quote)
xo_data_append(xop, "\"", 1);
@@ -3142,7 +3299,7 @@ xo_format_content (xo_handle_t *xop, const char *class_name,
const char *xml_tag, int display_only,
const char *str, int len, const char *fmt, int flen)
{
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_TEXT:
if (len) {
xo_data_append_content(xop, str, len);
@@ -3195,6 +3352,362 @@ xo_format_content (xo_handle_t *xop, const char *class_name,
}
}
+static const char *xo_color_names[] = {
+ "default", /* XO_COL_DEFAULT */
+ "black", /* XO_COL_BLACK */
+ "red", /* XO_CLOR_RED */
+ "green", /* XO_COL_GREEN */
+ "yellow", /* XO_COL_YELLOW */
+ "blue", /* XO_COL_BLUE */
+ "magenta", /* XO_COL_MAGENTA */
+ "cyan", /* XO_COL_CYAN */
+ "white", /* XO_COL_WHITE */
+ NULL
+};
+
+static int
+xo_color_find (const char *str)
+{
+ int i;
+
+ for (i = 0; xo_color_names[i]; i++) {
+ if (strcmp(xo_color_names[i], str) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+static const char *xo_effect_names[] = {
+ "reset", /* XO_EFF_RESET */
+ "normal", /* XO_EFF_NORMAL */
+ "bold", /* XO_EFF_BOLD */
+ "underline", /* XO_EFF_UNDERLINE */
+ "inverse", /* XO_EFF_INVERSE */
+ NULL
+};
+
+static const char *xo_effect_on_codes[] = {
+ "0", /* XO_EFF_RESET */
+ "0", /* XO_EFF_NORMAL */
+ "1", /* XO_EFF_BOLD */
+ "4", /* XO_EFF_UNDERLINE */
+ "7", /* XO_EFF_INVERSE */
+ NULL
+};
+
+#if 0
+/*
+ * See comment below re: joy of terminal standards. These can
+ * be use by just adding:
+ * if (newp->xoc_effects & bit)
+ * code = xo_effect_on_codes[i];
+ * + else
+ * + code = xo_effect_off_codes[i];
+ * in xo_color_handle_text.
+ */
+static const char *xo_effect_off_codes[] = {
+ "0", /* XO_EFF_RESET */
+ "0", /* XO_EFF_NORMAL */
+ "21", /* XO_EFF_BOLD */
+ "24", /* XO_EFF_UNDERLINE */
+ "27", /* XO_EFF_INVERSE */
+ NULL
+};
+#endif /* 0 */
+
+static int
+xo_effect_find (const char *str)
+{
+ int i;
+
+ for (i = 0; xo_effect_names[i]; i++) {
+ if (strcmp(xo_effect_names[i], str) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+static void
+xo_colors_parse (xo_handle_t *xop, xo_colors_t *xocp, char *str)
+{
+#ifdef LIBXO_TEXT_ONLY
+ return;
+#endif /* LIBXO_TEXT_ONLY */
+
+ char *cp, *ep, *np, *xp;
+ int len = strlen(str);
+ int rc;
+
+ /*
+ * Possible tokens: colors, bg-colors, effects, no-effects, "reset".
+ */
+ for (cp = str, ep = cp + len - 1; cp && cp < ep; cp = np) {
+ /* Trim leading whitespace */
+ while (isspace((int) *cp))
+ cp += 1;
+
+ np = strchr(cp, ',');
+ if (np)
+ *np++ = '\0';
+
+ /* Trim trailing whitespace */
+ xp = cp + strlen(cp) - 1;
+ while (isspace(*xp) && xp > cp)
+ *xp-- = '\0';
+
+ if (cp[0] == 'f' && cp[1] == 'g' && cp[2] == '-') {
+ rc = xo_color_find(cp + 3);
+ if (rc < 0)
+ goto unknown;
+
+ xocp->xoc_col_fg = rc;
+
+ } else if (cp[0] == 'b' && cp[1] == 'g' && cp[2] == '-') {
+ rc = xo_color_find(cp + 3);
+ if (rc < 0)
+ goto unknown;
+ xocp->xoc_col_bg = rc;
+
+ } else if (cp[0] == 'n' && cp[1] == 'o' && cp[2] == '-') {
+ rc = xo_effect_find(cp + 3);
+ if (rc < 0)
+ goto unknown;
+ xocp->xoc_effects &= ~(1 << rc);
+
+ } else {
+ rc = xo_effect_find(cp);
+ if (rc < 0)
+ goto unknown;
+ xocp->xoc_effects |= 1 << rc;
+
+ switch (1 << rc) {
+ case XO_EFF_RESET:
+ xocp->xoc_col_fg = xocp->xoc_col_bg = 0;
+ /* Note: not "|=" since we want to wipe out the old value */
+ xocp->xoc_effects = XO_EFF_RESET;
+ break;
+
+ case XO_EFF_NORMAL:
+ xocp->xoc_effects &= ~(XO_EFF_BOLD | XO_EFF_UNDERLINE
+ | XO_EFF_INVERSE | XO_EFF_NORMAL);
+ break;
+ }
+ }
+ continue;
+
+ unknown:
+ if (xop->xo_flags & XOF_WARN)
+ xo_failure(xop, "unknown color/effect string detected: '%s'", cp);
+ }
+}
+
+static inline int
+xo_colors_enabled (xo_handle_t *xop UNUSED)
+{
+#ifdef LIBXO_TEXT_ONLY
+ return 0;
+#else /* LIBXO_TEXT_ONLY */
+ return ((xop->xo_flags & XOF_COLOR) ? 1 : 0);
+#endif /* LIBXO_TEXT_ONLY */
+}
+
+static void
+xo_colors_handle_text (xo_handle_t *xop UNUSED, xo_colors_t *newp)
+{
+ char buf[BUFSIZ];
+ char *cp = buf, *ep = buf + sizeof(buf);
+ unsigned i, bit;
+ xo_colors_t *oldp = &xop->xo_colors;
+ const char *code = NULL;
+
+ /*
+ * Start the buffer with an escape. We don't want to add the '['
+ * now, since we let xo_effect_text_add unconditionally add the ';'.
+ * We'll replace the first ';' with a '[' when we're done.
+ */
+ *cp++ = 0x1b; /* Escape */
+
+ /*
+ * Terminals were designed back in the age before "certainty" was
+ * invented, when standards were more what you'd call "guidelines"
+ * than actual rules. Anyway we can't depend on them to operate
+ * correctly. So when display attributes are changed, we punt,
+ * reseting them all and turning back on the ones we want to keep.
+ * Longer, but should be completely reliable. Savvy?
+ */
+ if (oldp->xoc_effects != (newp->xoc_effects & oldp->xoc_effects)) {
+ newp->xoc_effects |= XO_EFF_RESET;
+ oldp->xoc_effects = 0;
+ }
+
+ for (i = 0, bit = 1; xo_effect_names[i]; i++, bit <<= 1) {
+ if ((newp->xoc_effects & bit) == (oldp->xoc_effects & bit))
+ continue;
+
+ if (newp->xoc_effects & bit)
+ code = xo_effect_on_codes[i];
+
+ cp += snprintf(cp, ep - cp, ";%s", code);
+ if (cp >= ep)
+ return; /* Should not occur */
+
+ if (bit == XO_EFF_RESET) {
+ /* Mark up the old value so we can detect current values as new */
+ oldp->xoc_effects = 0;
+ oldp->xoc_col_fg = oldp->xoc_col_bg = XO_COL_DEFAULT;
+ }
+ }
+
+ if (newp->xoc_col_fg != oldp->xoc_col_fg) {
+ cp += snprintf(cp, ep - cp, ";3%u",
+ (newp->xoc_col_fg != XO_COL_DEFAULT)
+ ? newp->xoc_col_fg - 1 : 9);
+ }
+
+ if (newp->xoc_col_bg != oldp->xoc_col_bg) {
+ cp += snprintf(cp, ep - cp, ";4%u",
+ (newp->xoc_col_bg != XO_COL_DEFAULT)
+ ? newp->xoc_col_bg - 1 : 9);
+ }
+
+ if (cp - buf != 1 && cp < ep - 3) {
+ buf[1] = '['; /* Overwrite leading ';' */
+ *cp++ = 'm';
+ *cp = '\0';
+ xo_buf_append(&xop->xo_data, buf, cp - buf);
+ }
+}
+
+static void
+xo_colors_handle_html (xo_handle_t *xop, xo_colors_t *newp)
+{
+ xo_colors_t *oldp = &xop->xo_colors;
+
+ /*
+ * HTML colors are mostly trivial: fill in xo_color_buf with
+ * a set of class tags representing the colors and effects.
+ */
+
+ /* If nothing changed, then do nothing */
+ if (oldp->xoc_effects == newp->xoc_effects
+ && oldp->xoc_col_fg == newp->xoc_col_fg
+ && oldp->xoc_col_bg == newp->xoc_col_bg)
+ return;
+
+ unsigned i, bit;
+ xo_buffer_t *xbp = &xop->xo_color_buf;
+
+ xo_buf_reset(xbp); /* We rebuild content after each change */
+
+ for (i = 0, bit = 1; xo_effect_names[i]; i++, bit <<= 1) {
+ if (!(newp->xoc_effects & bit))
+ continue;
+
+ xo_buf_append_str(xbp, " effect-");
+ xo_buf_append_str(xbp, xo_effect_names[i]);
+ }
+
+ const char *fg = NULL;
+ const char *bg = NULL;
+
+ if (newp->xoc_col_fg != XO_COL_DEFAULT)
+ fg = xo_color_names[newp->xoc_col_fg];
+ if (newp->xoc_col_bg != XO_COL_DEFAULT)
+ bg = xo_color_names[newp->xoc_col_bg];
+
+ if (newp->xoc_effects & XO_EFF_INVERSE) {
+ const char *tmp = fg;
+ fg = bg;
+ bg = tmp;
+ if (fg == NULL)
+ fg = "inverse";
+ if (bg == NULL)
+ bg = "inverse";
+
+ }
+
+ if (fg) {
+ xo_buf_append_str(xbp, " color-fg-");
+ xo_buf_append_str(xbp, fg);
+ }
+
+ if (bg) {
+ xo_buf_append_str(xbp, " color-bg-");
+ xo_buf_append_str(xbp, bg);
+ }
+}
+
+static void
+xo_format_colors (xo_handle_t *xop, const char *str, int len,
+ const char *fmt, int flen)
+{
+ xo_buffer_t xb;
+
+ /* If the string is static and we've in an encoding style, bail */
+ if (len != 0
+ && (xo_style(xop) == XO_STYLE_XML || xo_style(xop) == XO_STYLE_JSON))
+ return;
+
+ xo_buf_init(&xb);
+
+ if (len)
+ xo_buf_append(&xb, str, len);
+ else if (flen)
+ xo_format_data(xop, &xb, fmt, flen, 0);
+ else
+ xo_buf_append(&xb, "reset", 6); /* Default if empty */
+
+ if (xo_colors_enabled(xop)) {
+ switch (xo_style(xop)) {
+ case XO_STYLE_TEXT:
+ case XO_STYLE_HTML:
+ xo_buf_append(&xb, "", 1);
+
+ xo_colors_t xoc = xop->xo_colors;
+ xo_colors_parse(xop, &xoc, xb.xb_bufp);
+
+ if (xo_style(xop) == XO_STYLE_TEXT) {
+ /*
+ * Text mode means emitting the colors as ANSI character
+ * codes. This will allow people who like colors to have
+ * colors. The issue is, of course conflicting with the
+ * user's perfectly reasonable color scheme. Which leads
+ * to the hell of LSCOLORS, where even app need to have
+ * customization hooks for adjusting colors. Instead we
+ * provide a simpler-but-still-annoying answer where one
+ * can map colors to other colors.
+ */
+ xo_colors_handle_text(xop, &xoc);
+ xoc.xoc_effects &= ~XO_EFF_RESET; /* After handling it */
+
+ } else {
+ /*
+ * HTML output is wrapped in divs, so the color information
+ * must appear in every div until cleared. Most pathetic.
+ * Most unavoidable.
+ */
+ xoc.xoc_effects &= ~XO_EFF_RESET; /* Before handling effects */
+ xo_colors_handle_html(xop, &xoc);
+ }
+
+ xop->xo_colors = xoc;
+ break;
+
+ case XO_STYLE_XML:
+ case XO_STYLE_JSON:
+ /*
+ * Nothing to do; we did all that work just to clear the stack of
+ * formatting arguments.
+ */
+ break;
+ }
+ }
+
+ xo_buf_cleanup(&xb);
+}
+
static void
xo_format_units (xo_handle_t *xop, const char *str, int len,
const char *fmt, int flen)
@@ -3211,9 +3724,9 @@ xo_format_units (xo_handle_t *xop, const char *str, int len,
int start = xop->xo_units_offset;
int stop = xbp->xb_curp - xbp->xb_bufp;
- if (xop->xo_style == XO_STYLE_XML)
+ if (xo_style(xop) == XO_STYLE_XML)
xo_buf_append(xbp, units_start_xml, sizeof(units_start_xml) - 1);
- else if (xop->xo_style == XO_STYLE_HTML)
+ else if (xo_style(xop) == XO_STYLE_HTML)
xo_buf_append(xbp, units_start_html, sizeof(units_start_html) - 1);
else
return;
@@ -3295,7 +3808,7 @@ static void
xo_anchor_start (xo_handle_t *xop, const char *str, int len,
const char *fmt, int flen)
{
- if (xop->xo_style != XO_STYLE_TEXT && xop->xo_style != XO_STYLE_HTML)
+ if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
return;
if (xop->xo_flags & XOF_ANCHOR)
@@ -3317,7 +3830,7 @@ static void
xo_anchor_stop (xo_handle_t *xop, const char *str, int len,
const char *fmt, int flen)
{
- if (xop->xo_style != XO_STYLE_TEXT && xop->xo_style != XO_STYLE_HTML)
+ if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
return;
if (!(xop->xo_flags & XOF_ANCHOR)) {
@@ -3484,6 +3997,7 @@ xo_do_emit (xo_handle_t *xop, const char *fmt)
}
switch (*sp) {
+ case 'C':
case 'D':
case 'E':
case 'L':
@@ -3621,6 +4135,8 @@ xo_do_emit (xo_handle_t *xop, const char *fmt)
xo_anchor_start(xop, content, clen, format, flen);
else if (ftype == ']')
xo_anchor_stop(xop, content, clen, format, flen);
+ else if (ftype == 'C')
+ xo_format_colors(xop, content, clen, format, flen);
else if (clen || format) { /* Need either content or format */
if (format == NULL) {
@@ -3726,7 +4242,7 @@ xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap)
const int extra = 5; /* space, equals, quote, quote, and nul */
xop = xo_default(xop);
- if (xop->xo_style != XO_STYLE_XML)
+ if (xo_style(xop) != XO_STYLE_XML)
return 0;
int nlen = strlen(name);
@@ -3798,7 +4314,7 @@ static void
xo_depth_change (xo_handle_t *xop, const char *name,
int delta, int indent, xo_state_t state, xo_xsf_flags_t flags)
{
- if (xop->xo_style == XO_STYLE_HTML || xop->xo_style == XO_STYLE_TEXT)
+ if (xo_style(xop) == XO_STYLE_HTML || xo_style(xop) == XO_STYLE_TEXT)
indent = 0;
if (xop->xo_flags & XOF_DTRT)
@@ -3884,6 +4400,20 @@ xo_stack_flags (unsigned xflags)
return 0;
}
+static void
+xo_emit_top (xo_handle_t *xop, const char *ppn)
+{
+ xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn);
+ xop->xo_flags |= XOF_TOP_EMITTED;
+
+ if (xop->xo_version) {
+ xo_printf(xop, "%*s\"__version\": \"%s\", %s",
+ xo_indent(xop), "", xop->xo_version, ppn);
+ xo_free(xop->xo_version);
+ xop->xo_version = NULL;
+ }
+}
+
static int
xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
{
@@ -3898,7 +4428,7 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
flags |= xop->xo_flags; /* Pick up handle flags */
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name);
@@ -3915,12 +4445,9 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
case XO_STYLE_JSON:
xo_stack_set_flags(xop);
- if (!(xop->xo_flags & XOF_NO_TOP)) {
- if (!(xop->xo_flags & XOF_TOP_EMITTED)) {
- xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn);
- xop->xo_flags |= XOF_TOP_EMITTED;
- }
- }
+ if (!(xop->xo_flags & XOF_NO_TOP)
+ && !(xop->xo_flags & XOF_TOP_EMITTED))
+ xo_emit_top(xop, ppn);
if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
pre_nl = (xop->xo_flags & XOF_PRETTY) ? ",\n" : ", ";
@@ -3992,7 +4519,7 @@ xo_do_close_container (xo_handle_t *xop, const char *name)
}
}
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0);
rc = xo_printf(xop, "%*s</%s>%s", xo_indent(xop), "", name, ppn);
@@ -4048,17 +4575,14 @@ xo_do_open_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
xop = xo_default(xop);
- if (xop->xo_style == XO_STYLE_JSON) {
+ if (xo_style(xop) == XO_STYLE_JSON) {
const char *ppn = (xop->xo_flags & XOF_PRETTY) ? "\n" : "";
const char *pre_nl = "";
indent = 1;
- if (!(xop->xo_flags & XOF_NO_TOP)) {
- if (!(xop->xo_flags & XOF_TOP_EMITTED)) {
- xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn);
- xop->xo_flags |= XOF_TOP_EMITTED;
- }
- }
+ if (!(xop->xo_flags & XOF_NO_TOP)
+ && !(xop->xo_flags & XOF_TOP_EMITTED))
+ xo_emit_top(xop, ppn);
if (name == NULL) {
xo_failure(xop, "NULL passed for list name");
@@ -4133,7 +4657,7 @@ xo_do_close_list (xo_handle_t *xop, const char *name)
}
}
- if (xop->xo_style == XO_STYLE_JSON) {
+ if (xo_style(xop) == XO_STYLE_JSON) {
if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
pre_nl = (xop->xo_flags & XOF_PRETTY) ? "\n" : "";
xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
@@ -4182,7 +4706,7 @@ xo_do_open_leaf_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
xop = xo_default(xop);
- if (xop->xo_style == XO_STYLE_JSON) {
+ if (xo_style(xop) == XO_STYLE_JSON) {
const char *ppn = (xop->xo_flags & XOF_PRETTY) ? "\n" : "";
const char *pre_nl = "";
@@ -4238,7 +4762,7 @@ xo_do_close_leaf_list (xo_handle_t *xop, const char *name)
}
}
- if (xop->xo_style == XO_STYLE_JSON) {
+ if (xo_style(xop) == XO_STYLE_JSON) {
if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
pre_nl = (xop->xo_flags & XOF_PRETTY) ? "\n" : "";
xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
@@ -4271,7 +4795,7 @@ xo_do_open_instance (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
name = XO_FAILURE_NAME;
}
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name);
@@ -4357,7 +4881,7 @@ xo_do_close_instance (xo_handle_t *xop, const char *name)
}
}
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_XML:
xo_depth_change(xop, name, -1, -1, XSS_CLOSE_INSTANCE, 0);
rc = xo_printf(xop, "%*s</%s>%s", xo_indent(xop), "", name, ppn);
@@ -4639,8 +5163,8 @@ xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name,
rc = xo_do_open_instance(xop, flags, name);
break;
- case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_INSTANCE):
case XSS_TRANSITION(XSS_INIT, XSS_OPEN_INSTANCE):
+ case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_INSTANCE):
rc = xo_do_open_list(xop, flags, name);
if (rc >= 0)
goto open_instance;
@@ -4673,6 +5197,8 @@ xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name,
case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_INSTANCE):
/* This one makes no sense; ignore it */
+ xo_failure(xop, "xo_close_instance ignored when called from "
+ "initial state ('%s')", name ?: "(unknown)");
break;
case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_INSTANCE):
@@ -4715,6 +5241,8 @@ xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name,
case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_LEAF_LIST):
/* Makes no sense; ignore */
+ xo_failure(xop, "xo_close_leaf_list ignored when called from "
+ "initial state ('%s')", name ?: "(unknown)");
break;
case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_LEAF_LIST):
@@ -4836,7 +5364,7 @@ xo_flush_h (xo_handle_t *xop)
xop = xo_default(xop);
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_HTML:
if (xop->xo_flags & XOF_DIV_OPEN) {
xop->xo_flags &= ~XOF_DIV_OPEN;
@@ -4871,7 +5399,7 @@ xo_finish_h (xo_handle_t *xop)
if (!(xop->xo_flags & XOF_NO_CLOSE))
xo_do_close_all(xop, xop->xo_stack);
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_JSON:
if (!(xop->xo_flags & XOF_NO_TOP)) {
if (xop->xo_flags & XOF_TOP_EMITTED)
@@ -4913,7 +5441,7 @@ xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)
fmt = newfmt;
}
- switch (xop->xo_style) {
+ switch (xo_style(xop)) {
case XO_STYLE_TEXT:
vfprintf(stderr, fmt, vap);
break;
@@ -5052,6 +5580,41 @@ xo_set_program (const char *name)
xo_program = name;
}
+void
+xo_set_version_h (xo_handle_t *xop, const char *version UNUSED)
+{
+ xop = xo_default(xop);
+
+ if (version == NULL || strchr(version, '"') != NULL)
+ return;
+
+ switch (xo_style(xop)) {
+ case XO_STYLE_XML:
+ /* For XML, we record this as an attribute for the first tag */
+ xo_attr_h(xop, "__version", "%s", version);
+ break;
+
+ case XO_STYLE_JSON:
+ {
+ /*
+ * For XML, we record the version string in our handle, and emit
+ * it in xo_emit_top.
+ */
+ int len = strlen(version) + 1;
+ xop->xo_version = xo_realloc(NULL, len);
+ if (xop->xo_version)
+ memcpy(xop->xo_version, version, len);
+ }
+ break;
+ }
+}
+
+void
+xo_set_version (const char *version)
+{
+ xo_set_version_h(NULL, version);
+}
+
#ifdef UNIT_TEST
int
main (int argc, char **argv)
diff --git a/contrib/libxo/libxo/xo.h b/contrib/libxo/libxo/xo.h
index ea289f0..c065740 100644
--- a/contrib/libxo/libxo/xo.h
+++ b/contrib/libxo/libxo/xo.h
@@ -9,7 +9,7 @@
*/
/**
- * libxo provides a means of generating text, XML, and JSON output
+ * libxo provides a means of generating text, XML, JSON, and HTML output
* using a single set of function calls, maximizing the value of output
* while minimizing the cost/impact on the code.
*/
@@ -17,6 +17,27 @@
#ifndef INCLUDE_XO_H
#define INCLUDE_XO_H
+#include <sys/types.h>
+
+#ifdef __dead2
+#define NORETURN __dead2
+#else
+#define NORETURN
+#endif /* __dead2 */
+
+/*
+ * Normally we'd use the HAVE_PRINTFLIKE define triggered by the
+ * --enable-printflike option to configure, but we don't install
+ * our internal "xoconfig.h", and I'd rather not. Taking the
+ * coward's path, we'll turn it on inside a #if that allows
+ * others to turn it off where needed. Not ideal, but functional.
+ */
+#if !defined(NO_PRINTFLIKE) && !defined(__linux__)
+#define PRINTFLIKE(_x, _y) __printflike(_x, _y)
+#else
+#define PRINTFLIKE(_x, _y)
+#endif /* NO_PRINTFLIKE */
+
/** Formatting types */
typedef unsigned xo_style_t;
#define XO_STYLE_TEXT 0 /** Generate text output */
@@ -58,6 +79,8 @@ typedef unsigned long long xo_xof_flags_t;
#define XOF_FLUSH_LINE XOF_BIT(23) /** Flush after each newline */
#define XOF_NO_CLOSE XOF_BIT(24) /** xo_finish won't close open elements */
+#define XOF_COLOR_ALLOWED XOF_BIT(25) /** Allow color/effects to be enabled */
+#define XOF_COLOR XOF_BIT(26) /** Enable color and effects */
/*
* The xo_info_t structure provides a mapping between names and
@@ -260,64 +283,116 @@ void
xo_set_leading_xpath (xo_handle_t *xop, const char *path);
void
-xo_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...);
+xo_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
void
-xo_warn_c (int code, const char *fmt, ...);
+xo_warn_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
void
-xo_warn (const char *fmt, ...);
+xo_warn (const char *fmt, ...) PRINTFLIKE(1, 2);
void
-xo_warnx (const char *fmt, ...);
+xo_warnx (const char *fmt, ...) PRINTFLIKE(1, 2);
void
-xo_err (int eval, const char *fmt, ...) __dead2;
+xo_err (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
void
-xo_errx (int eval, const char *fmt, ...) __dead2;
+xo_errx (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
void
-xo_errc (int eval, int code, const char *fmt, ...) __dead2;
+xo_errc (int eval, int code, const char *fmt, ...) NORETURN PRINTFLIKE(3, 4);
void
xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap);
void
-xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...);
+xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
void
-xo_message_c (int code, const char *fmt, ...);
+xo_message_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
void
-xo_message (const char *fmt, ...);
+xo_message (const char *fmt, ...) PRINTFLIKE(1, 2);
void
xo_no_setlocale (void);
+/**
+ * @brief Lift libxo-specific arguments from a set of arguments
+ *
+ * libxo-enable programs typically use command line options to enable
+ * all the nifty-cool libxo features. xo_parse_args() makes this simple
+ * by pre-processing the command line arguments given to main(), handling
+ * and removing the libxo-specific ones, meaning anything starting with
+ * "--libxo". A full description of these arguments is in the base
+ * documentation.
+ * @param[in] argc Number of arguments (ala #main())
+ * @param[in] argc Array of argument strings (ala #main())
+ * @return New number of arguments, or -1 for failure.
+ */
int
xo_parse_args (int argc, char **argv);
-/*
+/**
* This is the "magic" number returned by libxo-supporting commands
* when passed the equally magic "--libxo-check" option. If you
- * return this, we can assume that since you know the magic handshake,
- * you'll happily handle future --libxo options and not do something
- * violent like reboot the box or create another hole in the ozone
- * layer.
+ * return this, we can (unsafely) assume that since you know the magic
+ * handshake, you'll happily handle future --libxo options and not do
+ * something violent like reboot the box or create another hole in the
+ * ozone layer.
*/
#define XO_HAS_LIBXO 121
-/*
- * externs for our version number strings
+/**
+ * externs for libxo's version number strings
*/
-extern const char xo_version[];
-extern const char xo_version_extra[];
+extern const char xo_version[]; /** Base version triple string */
+extern const char xo_version_extra[]; /** Extra version magic content */
+/**
+ * @brief Dump the internal stack of a libxo handle.
+ *
+ * This diagnostic function is something I will ask you to call from
+ * your program when you write to tell me libxo has gone bat-stink
+ * crazy and has discarded your list or container or content. Output
+ * content will be what we lovingly call "developer entertainment".
+ * @param[in] xop A valid libxo handle, or NULL for the default handle
+ */
void
xo_dump_stack (xo_handle_t *xop);
+/**
+ * @brief Recode the name of the program, suitable for error output.
+ *
+ * libxo will record the given name for use while generating error
+ * messages. The contents are not copied, so the value must continue
+ * to point to a valid memory location. This allows the caller to change
+ * the value, but requires the caller to manage the memory. Typically
+ * this is called with argv[0] from main().
+ * @param[in] name The name of the current application program
+ */
void
xo_set_program (const char *name);
+/**
+ * @brief Add a version string to the output, where possible.
+ *
+ * Adds a version number to the output, suitable for tracking
+ * changes in the content. This is only important for the "encoding"
+ * format styles (XML and JSON) and allows a user of the data to
+ * discern which version of the data model is in use.
+ * @param[in] version The version number, encoded as a string
+ */
+void
+xo_set_version (const char *version);
+
+/**
+ * #xo_set_version with a handle.
+ * @param[in] xop A valid libxo handle, or NULL for the default handle
+ * @param[in] version The version number, encoded as a string
+ */
+void
+xo_set_version_h (xo_handle_t *xop, const char *version);
+
#endif /* INCLUDE_XO_H */
diff --git a/contrib/libxo/libxo/xo_error.3 b/contrib/libxo/libxo/xo_error.3
index da91785..01431cb 100644
--- a/contrib/libxo/libxo/xo_error.3
+++ b/contrib/libxo/libxo/xo_error.3
@@ -28,12 +28,13 @@ The
argument is a string containing printf-style formatting
instructions that describe the remaining arguments.
.Pp
-When converting an application to libxo, one can replace
+When converting an application to
+.Nm libxo ,
+one can replace
.Em "fprintf(stderr,...)"
calls with
.Fn xo_error
calls.
-.Pp
.Sh ADDITIONAL DOCUMENTATION
Complete documentation can be found on github:
.Bd -literal -offset indent
@@ -53,7 +54,7 @@ is available at:
https://github.com/Juniper/libxo/releases
.Ed
.Sh SEE ALSO
-.Xr printf 3
+.Xr printf 3 ,
.Xr xo_emit 3
.Sh HISTORY
The
diff --git a/contrib/libxo/libxo/xo_format.5 b/contrib/libxo/libxo/xo_format.5
index b021b98..bce5dc5 100644
--- a/contrib/libxo/libxo/xo_format.5
+++ b/contrib/libxo/libxo/xo_format.5
@@ -74,7 +74,7 @@ function as an unsigned integer.
.Ed
.Pp
This single line of code can generate text ("In stock: 65\\n"), XML
-("<in-stock>65</in-stock>"), JSON ('"in-stock": 6'), or HTML (too
+("<in-stock>65</in-stock>"), JSON ('"in-stock": 65'), or HTML (too
lengthy to be listed here).
.Ss Modifier Roles
Modifiers are optional, and indicate the role and formatting of the
@@ -96,6 +96,55 @@ The roles are listed below; only one role is permitted:
.It \&] "stop anchor " "End a section of anchored variable-width text"
.El
.Pp
+.Ss The Color Role ({C:})
+Colors and effects control how text values are displayed; they are
+used for display styles (TEXT and HTML).
+The color content can be
+either static, when placed directly within the field descriptor, or a
+printf-style format descriptor can be used, if preceded by a slash ("/"):
+.Bd -literal -offset indent
+ xo_emit("{C:bold}{Lwc:Cost}{:cost/%u}{C:reset}\n", cost);
+ xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n",
+ fg_color, bg_color, cost);
+.Ed
+.Pp
+The content should be a comma-separated list of zero or more colors or
+display effects.
+.Pp
+Colors and effects remain in effect until modified by other "C" roles.
+.Pp
+If the content is empty, the "reset" action is performed.
+.Pp
+.Bl -column "no-underline"
+.It Sy "Name Description"
+.It "bg-xxxxx " "Change background color"
+.It "bold " "Start bold text effect"
+.It "fg-xxxxx " "Change foreground color"
+.It "inverse " "Start inverse (aka reverse) text effect"
+.It "no-bold " "Stop bold text effect"
+.It "no-inverse " "Stop inverse (aka reverse) text effect"
+.It "no-underline " "Stop underline text effect"
+.It "normal " "Reset effects (only)"
+.It "reset " "Reset colors and effects (restore defaults)"
+.It "underline " "Start underline text effect"
+.El
+.Pp
+The following color names are supported:
+.Bl -column "no-underline"
+.It Sy "Name"
+.It black
+.It blue
+.It cyan
+.It default
+.It green
+.It magenta
+.It red
+.It white
+.It yellow
+.El
+.Pp
+Color names are prefixed with either "fg-" or "bg-" to change the
+foreground and background colors, respectively.
.Ss The Decoration Role ({D:})
Decorations are typically punctuation marks such as colons,
semi-colons, and commas used to decorate the text and make it simpler
@@ -230,6 +279,7 @@ content emitted for some output styles:
.It d "display " "Only emit field for display styles (text/HTML)"
.It e "encoding " "Only emit for encoding styles (XML/JSON)"
.It k "key " "Field is a key, suitable for XPath predicates"
+.It l "leaf " "Field is a leaf-list, a list of leaf values"
.It n "no-quotes " "Do not quote the field when using JSON style"
.It q "quotes " "Quote the field when using JSON style"
.It w "white space " "A blank ("" "") is appended after the label"
@@ -269,8 +319,8 @@ the display output styles, TEXT and HTML.
The display modifier is the opposite of the encoding modifier, and
they are often used to give to distinct views of the underlying data.
.Ss The Encoding Modifier ({e:})
-The display modifier indicated the field should only be generated for
-the display output styles, TEXT and HTML.
+The encoding modifier indicated the field should only be generated for
+the encoding output styles, such as JSON and XML.
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{Lcw:Name}{:name} {e:id/%d}\\n", "phil", 1);
diff --git a/contrib/libxo/libxo/xo_open_container.3 b/contrib/libxo/libxo/xo_open_container.3
index 86412ca..3649556 100644
--- a/contrib/libxo/libxo/xo_open_container.3
+++ b/contrib/libxo/libxo/xo_open_container.3
@@ -11,8 +11,8 @@
.Dt LIBXO 3
.Os
.Sh NAME
-.Nm xo_emit
-.Nd emit formatted output based on format string and arguments
+.Nm xo_open_container
+.Nd open (and close) container constructs
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
@@ -48,7 +48,7 @@
.Fn xo_close_container_d "void"
.Sh DESCRIPTION
.Nm libxo
-represents to types of hierarchy:
+represents two types of hierarchy:
.Dq containers
and
.Dq lists .
@@ -72,7 +72,7 @@ or
.Fn xo_close_container_h
functions.
.Pp
-Each open call must have a matching close call.
+Each open call should have a matching close call.
If the
.Dv XOF_WARN
flag is set and the name given does not match the name of
diff --git a/contrib/libxo/libxo/xo_open_marker.3 b/contrib/libxo/libxo/xo_open_marker.3
new file mode 100644
index 0000000..d7a858c
--- /dev/null
+++ b/contrib/libxo/libxo/xo_open_marker.3
@@ -0,0 +1,138 @@
+.\" #
+.\" # Copyright (c) 2015, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, January 2015
+.\"
+.Dd January 22, 2015
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_open_marker
+.Nd prevent and allow closing of open constructs
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Sh NAME
+.Nm xo_open_marker
+.Nm xo_open_marker_h
+.Nm xo_close_marker
+.Nm xo_close_marker_h
+.Nd open and close markers
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.Ft int
+.Fn xo_open_marker "const char *name"
+.Ft int
+.Fn xo_open_marker_h "xo_handle_t *handle" "const char *name"
+.Ft int
+.Fn xo_close_marker "const char *name"
+.Ft int
+.Fn xo_close_marker_h "xo_handle_t *handle" "const char *name"
+.Sh DESCRIPTION
+.Nm libxo
+represents hierarchy using two constructs:
+.Dq containers
+and
+.Dq lists .
+A marker can be used to affect how open constructs are closed, either
+by preventing their (implicit or explicit) closure or by forcing their
+closure.
+While a marker is open, no other open constructs can be closed.
+When a marker is closed, all constructs open since the marker was opened
+will be closed.
+A marker is used to "freeze" any open constructs.
+Calls to
+.Fn xo_close_*
+functions that would normally close them will be ignored, effectively
+blocking their closure.
+However when
+.Fn xo_close_marker
+is called, any containers, lists, or leaf-lists open since the
+matching
+.Fn xo_open_marker
+call will be close and the marker discarded.
+Markers use names which are not user-visible, allowing the caller to
+choose appropriate internal names.
+The marker has no value and is not emitted in any form.
+.Pp
+To open a marker, call
+.Fn xo_open_marker
+or
+.Fn xo_open_marker_h .
+The former uses the default handle and
+the latter accepts a specific handle.
+.Pp
+To close a marker, use the
+.Fn xo_close_marker
+or
+.Fn xo_close_marker_h
+functions.
+.Pp
+Each open call must have a matching close call.
+.Pp
+In this example, the
+.Fn xo_close_container
+call on line [1] will be ignored, since the open marker "outer"
+will prevent close of any open constructs that precede it.
+The
+.Fn xo_close_marker
+call on line [2] will close the "system" container, since it was
+opened after the "outer" marker.
+.Bd -literal -offset indent -compact
+ Example:
+
+ xo_open_container("top");
+ xo_open_marker("outer");
+ xo_open_container("system");
+ xo_emit("{:host-name/%s%s%s", hostname,
+ domainname ? "." : "", domainname ?: "");
+ xo_close_container("top"); /* [1] */
+ xo_close_marker("outer"); /* [2] */
+ xo_close_container("top");
+.Ed
+.Pp
+In this example, the code whiffles through a list of fish, calling a
+function to emit details about each fish. The marker "fish-guts" is
+used to ensure that any constructs opened by the function are closed
+properly.
+.Bd -literal -offset indent
+ for (i = 0; fish[i]; i++) {
+ xo_open_instance("fish");
+ xo_open_marker("fish-guts");
+ dump_fish_details(i);
+ xo_close_marker("fish-guts");
+ }
+.Ed
+.Sh ADDITIONAL DOCUMENTATION
+Complete documentation can be found on github:
+.Bd -literal -offset indent
+http://juniper.github.io/libxo/libxo-manual.html
+.Ed
+.Pp
+.Nm libxo
+lives on github as:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo
+.Ed
+.Pp
+The latest release of
+.Nm libxo
+is available at:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo/releases
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3
+.Sh HISTORY
+The
+.Nm libxo
+library was added in
+.Fx 11.0 .
+.Sh AUTHOR
+Phil Shafer
diff --git a/contrib/libxo/libxo/xo_set_version.3 b/contrib/libxo/libxo/xo_set_version.3
new file mode 100644
index 0000000..888aef5
--- /dev/null
+++ b/contrib/libxo/libxo/xo_set_version.3
@@ -0,0 +1,59 @@
+.\" #
+.\" # Copyright (c) 2015, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_set_version
+.Nd record content version information in encoded output
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft void
+.Fn xo_set_version "const char *version"
+.Ft void
+.Fn xo_set_version_h "xo_handle_t *xop" "const char *version"
+.Sh DESCRIPTION
+The
+.Nm xo_set_version
+function records a version number to be emitted as
+part of the data for encoding styles (XML and JSON).
+This version number is suitable for tracking changes in the content,
+allowing a user of the data to discern which version of the data model
+is in use.
+.Sh ADDITIONAL DOCUMENTATION
+Complete documentation can be found on github:
+.Bd -literal -offset indent
+http://juniper.github.io/libxo/libxo-manual.html
+.Ed
+.Pp
+.Nm libxo
+lives on github as:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo
+.Ed
+.Pp
+The latest release of
+.Nm libxo
+is available at:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo/releases
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr libxo 3
+.Sh HISTORY
+The
+.Nm libxo
+library was added in
+.Fx 11.0 .
+.Sh AUTHOR
+Phil Shafer
diff --git a/contrib/libxo/libxo/xoconfig.h b/contrib/libxo/libxo/xoconfig.h
index 4c596b4..dd1823e 100644
--- a/contrib/libxo/libxo/xoconfig.h
+++ b/contrib/libxo/libxo/xoconfig.h
@@ -150,8 +150,10 @@
/* Enable debugging */
/* #undef LIBXO_DEBUG */
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
+/* Enable text-only rendering */
+/* #undef LIBXO_TEXT_ONLY */
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"
/* Name of package */
@@ -164,7 +166,7 @@
#define PACKAGE_NAME "libxo"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libxo 0.2.0"
+#define PACKAGE_STRING "libxo 0.3.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libxo"
@@ -173,7 +175,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.2.0"
+#define PACKAGE_VERSION "0.3.2"
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
@@ -187,7 +189,7 @@
#define STDC_HEADERS 1
/* Version number of package */
-#define VERSION "0.2.0"
+#define VERSION "0.3.2"
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
diff --git a/contrib/libxo/libxo/xoconfig.h.in b/contrib/libxo/libxo/xoconfig.h.in
index 467f564..ad992f3 100644
--- a/contrib/libxo/libxo/xoconfig.h.in
+++ b/contrib/libxo/libxo/xoconfig.h.in
@@ -149,8 +149,10 @@
/* Enable debugging */
#undef LIBXO_DEBUG
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
+/* Enable text-only rendering */
+#undef LIBXO_TEXT_ONLY
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
diff --git a/contrib/libxo/libxo/xoversion.h b/contrib/libxo/libxo/xoversion.h
index 4c29e82..6a60596 100644
--- a/contrib/libxo/libxo/xoversion.h
+++ b/contrib/libxo/libxo/xoversion.h
@@ -18,17 +18,17 @@
/**
* The version string
*/
-#define LIBXO_VERSION "0.2.0"
+#define LIBXO_VERSION "0.3.2"
/**
* The version number
*/
-#define LIBXO_VERSION_NUMBER 2000
+#define LIBXO_VERSION_NUMBER 3002
/**
* The version number as a string
*/
-#define LIBXO_VERSION_STRING "2000"
+#define LIBXO_VERSION_STRING "3002"
/**
* The version number extra info as a string
diff --git a/contrib/libxo/m4/libtool.m4 b/contrib/libxo/m4/libtool.m4
index 44e0ecf..a3bc337 100644
--- a/contrib/libxo/m4/libtool.m4
+++ b/contrib/libxo/m4/libtool.m4
@@ -1,8 +1,6 @@
# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
#
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-# Foundation, Inc.
+# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
# Written by Gordon Matzigkeit, 1996
#
# This file is free software; the Free Software Foundation gives
@@ -10,36 +8,30 @@
# modifications, as long as this notice is preserved.
m4_define([_LT_COPYING], [dnl
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-# Foundation, Inc.
-# Written by Gordon Matzigkeit, 1996
-#
-# This file is part of GNU Libtool.
-#
-# GNU Libtool is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
+# Copyright (C) 2014 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.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
#
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
#
-# GNU Libtool is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING. If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
-# obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
])
-# serial 57 LT_INIT
+# serial 58 LT_INIT
# LT_PREREQ(VERSION)
@@ -67,7 +59,7 @@ esac
# LT_INIT([OPTIONS])
# ------------------
AC_DEFUN([LT_INIT],
-[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
AC_BEFORE([$0], [LT_LANG])dnl
AC_BEFORE([$0], [LT_OUTPUT])dnl
@@ -91,7 +83,7 @@ dnl Parse OPTIONS
_LT_SET_OPTIONS([$0], [$1])
# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ltmain"
+LIBTOOL_DEPS=$ltmain
# Always use our own libtool.
LIBTOOL='$(SHELL) $(top_builddir)/libtool'
@@ -111,26 +103,43 @@ dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in @S|@*""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
# _LT_CC_BASENAME(CC)
# -------------------
-# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
m4_defun([_LT_CC_BASENAME],
-[for cc_temp in $1""; do
- case $cc_temp in
- compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
- distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
- \-*) ;;
- *) break;;
- esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
])
# _LT_FILEUTILS_DEFAULTS
# ----------------------
# It is okay to use these file commands and assume they have been set
-# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
m4_defun([_LT_FILEUTILS_DEFAULTS],
[: ${CP="cp -f"}
: ${MV="mv -f"}
@@ -177,15 +186,16 @@ m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
m4_require([_LT_CMD_OLD_ARCHIVE])dnl
m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
_LT_CONFIG_LIBTOOL_INIT([
-# See if we are running on zsh, and set the options which allow our
+# See if we are running on zsh, and set the options that allow our
# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}" ; then
+if test -n "\${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
])
-if test -n "${ZSH_VERSION+set}" ; then
+if test -n "${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
@@ -198,7 +208,7 @@ aix3*)
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
- if test "X${COLLECT_NAMES+set}" != Xset; then
+ if test set != "${COLLECT_NAMES+set}"; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
@@ -209,14 +219,14 @@ esac
ofile=libtool
can_build_shared=yes
-# All known linkers require a `.a' archive for static linking (except MSVC,
+# All known linkers require a '.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
-with_gnu_ld="$lt_cv_prog_gnu_ld"
+with_gnu_ld=$lt_cv_prog_gnu_ld
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
+old_CC=$CC
+old_CFLAGS=$CFLAGS
# Set sane defaults for various variables
test -z "$CC" && CC=cc
@@ -269,14 +279,14 @@ no_glob_subst='s/\*/\\\*/g'
# _LT_PROG_LTMAIN
# ---------------
-# Note that this code is called both from `configure', and `config.status'
+# Note that this code is called both from 'configure', and 'config.status'
# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
-# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
# so we pass a copy along to make sure it has a sensible value anyway.
m4_defun([_LT_PROG_LTMAIN],
[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
-ltmain="$ac_aux_dir/ltmain.sh"
+ltmain=$ac_aux_dir/ltmain.sh
])# _LT_PROG_LTMAIN
@@ -286,7 +296,7 @@ ltmain="$ac_aux_dir/ltmain.sh"
# So that we can recreate a full libtool script including additional
# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
-# in macros and then make a single call at the end using the `libtool'
+# in macros and then make a single call at the end using the 'libtool'
# label.
@@ -421,8 +431,8 @@ m4_define([_lt_decl_all_varnames],
# _LT_CONFIG_STATUS_DECLARE([VARNAME])
# ------------------------------------
-# Quote a variable value, and forward it to `config.status' so that its
-# declaration there will have the same value as in `configure'. VARNAME
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'. VARNAME
# must have a single quote delimited value for this to work.
m4_define([_LT_CONFIG_STATUS_DECLARE],
[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
@@ -446,7 +456,7 @@ m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
# Output comment and list of tags supported by the script
m4_defun([_LT_LIBTOOL_TAGS],
[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
-available_tags="_LT_TAGS"dnl
+available_tags='_LT_TAGS'dnl
])
@@ -474,7 +484,7 @@ m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
# _LT_LIBTOOL_CONFIG_VARS
# -----------------------
# Produce commented declarations of non-tagged libtool config variables
-# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
# section) are produced by _LT_LIBTOOL_TAG_VARS.
m4_defun([_LT_LIBTOOL_CONFIG_VARS],
@@ -500,8 +510,8 @@ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
# variables for single and double quote escaping we saved from calls
# to _LT_DECL, we can put quote escaped variables declarations
-# into `config.status', and then the shell code to quote escape them in
-# for loops in `config.status'. Finally, any additional code accumulated
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'. Finally, any additional code accumulated
# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
m4_defun([_LT_CONFIG_COMMANDS],
[AC_PROVIDE_IFELSE([LT_OUTPUT],
@@ -547,7 +557,7 @@ for var in lt_decl_all_varnames([[ \
]], lt_decl_quote_varnames); do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[[\\\\\\\`\\"\\\$]]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -560,7 +570,7 @@ for var in lt_decl_all_varnames([[ \
]], lt_decl_dquote_varnames); do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[[\\\\\\\`\\"\\\$]]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -576,7 +586,7 @@ _LT_OUTPUT_LIBTOOL_INIT
# Generate a child script FILE with all initialization necessary to
# reuse the environment learned by the parent script, and make the
# file executable. If COMMENT is supplied, it is inserted after the
-# `#!' sequence but before initialization text begins. After this
+# '#!' sequence but before initialization text begins. After this
# macro, additional text can be appended to FILE to form the body of
# the child script. The macro ends with non-zero status if the
# file could not be fully written (such as if the disk is full).
@@ -598,7 +608,7 @@ AS_SHELL_SANITIZE
_AS_PREPARE
exec AS_MESSAGE_FD>&1
_ASEOF
-test $lt_write_fail = 0 && chmod +x $1[]dnl
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
# LT_OUTPUT
@@ -621,7 +631,7 @@ exec AS_MESSAGE_LOG_FD>>config.log
} >&AS_MESSAGE_LOG_FD
lt_cl_help="\
-\`$as_me' creates a local libtool stub from the current configuration,
+'$as_me' creates a local libtool stub from the current configuration,
for use in further configure time tests before the real libtool is
generated.
@@ -643,7 +653,7 @@ Copyright (C) 2011 Free Software Foundation, Inc.
This config.lt script is free software; the Free Software Foundation
gives unlimited permision to copy, distribute and modify it."
-while test $[#] != 0
+while test 0 != $[#]
do
case $[1] in
--version | --v* | -V )
@@ -656,10 +666,10 @@ do
lt_cl_silent=: ;;
-*) AC_MSG_ERROR([unrecognized option: $[1]
-Try \`$[0] --help' for more information.]) ;;
+Try '$[0] --help' for more information.]) ;;
*) AC_MSG_ERROR([unrecognized argument: $[1]
-Try \`$[0] --help' for more information.]) ;;
+Try '$[0] --help' for more information.]) ;;
esac
shift
done
@@ -685,7 +695,7 @@ chmod +x "$CONFIG_LT"
# open by configure. Here we exec the FD to /dev/null, effectively closing
# config.log, so it can be properly (re)opened and appended to by config.lt.
lt_cl_success=:
-test "$silent" = yes &&
+test yes = "$silent" &&
lt_config_lt_args="$lt_config_lt_args --quiet"
exec AS_MESSAGE_LOG_FD>/dev/null
$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
@@ -705,27 +715,31 @@ m4_defun([_LT_CONFIG],
_LT_CONFIG_SAVE_COMMANDS([
m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
m4_if(_LT_TAG, [C], [
- # See if we are running on zsh, and set the options which allow our
+ # See if we are running on zsh, and set the options that allow our
# commands through without removal of \ escapes.
- if test -n "${ZSH_VERSION+set}" ; then
+ if test -n "${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
- cfgfile="${ofile}T"
+ cfgfile=${ofile}T
trap "$RM \"$cfgfile\"; exit 1" 1 2 15
$RM "$cfgfile"
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
-
-# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Generated automatically by $as_me ($PACKAGE) $VERSION
# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
_LT_COPYING
_LT_LIBTOOL_TAGS
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
# ### BEGIN LIBTOOL CONFIG
_LT_LIBTOOL_CONFIG_VARS
_LT_LIBTOOL_TAG_VARS
@@ -733,13 +747,24 @@ _LT_LIBTOOL_TAG_VARS
_LT_EOF
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
case $host_os in
aix3*)
cat <<\_LT_EOF >> "$cfgfile"
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
+if test set != "${COLLECT_NAMES+set}"; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
@@ -756,8 +781,6 @@ _LT_EOF
sed '$q' "$ltmain" >> "$cfgfile" \
|| (rm -f "$cfgfile"; exit 1)
- _LT_PROG_REPLACE_SHELLFNS
-
mv -f "$cfgfile" "$ofile" ||
(rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
chmod +x "$ofile"
@@ -775,7 +798,6 @@ _LT_EOF
[m4_if([$1], [], [
PACKAGE='$PACKAGE'
VERSION='$VERSION'
- TIMESTAMP='$TIMESTAMP'
RM='$RM'
ofile='$ofile'], [])
])dnl /_LT_CONFIG_SAVE_COMMANDS
@@ -974,7 +996,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
[lt_cv_apple_cc_single_mod=no
- if test -z "${LT_MULTI_MODULE}"; then
+ if test -z "$LT_MULTI_MODULE"; then
# By default we will add the -single_module flag. You can override
# by either setting the environment variable LT_MULTI_MODULE
# non-empty at configure time, or by adding -multi_module to the
@@ -992,7 +1014,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
cat conftest.err >&AS_MESSAGE_LOG_FD
# Otherwise, if the output was created with a 0 exit code from
# the compiler, it worked.
- elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
lt_cv_apple_cc_single_mod=yes
else
cat conftest.err >&AS_MESSAGE_LOG_FD
@@ -1010,7 +1032,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
[lt_cv_ld_exported_symbols_list=yes],
[lt_cv_ld_exported_symbols_list=no])
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
])
AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
@@ -1032,7 +1054,7 @@ _LT_EOF
_lt_result=$?
if test -s conftest.err && $GREP force_load conftest.err; then
cat conftest.err >&AS_MESSAGE_LOG_FD
- elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
lt_cv_ld_force_load=yes
else
cat conftest.err >&AS_MESSAGE_LOG_FD
@@ -1042,32 +1064,32 @@ _LT_EOF
])
case $host_os in
rhapsody* | darwin1.[[012]])
- _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
darwin*) # darwin 5.x on
# if running on 10.5 or later, the deployment target defaults
# to the OS version, if on x86, and 10.4, the deployment
# target defaults to 10.4. Don't you love it?
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
- 10.[[012]]*)
- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]][[,.]]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
10.*)
- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
esac
- if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
_lt_dar_single_mod='$single_module'
fi
- if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
- _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
else
- _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
fi
- if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
_lt_dsymutil='~$DSYMUTIL $lib || :'
else
_lt_dsymutil=
@@ -1087,29 +1109,29 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_automatic, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- if test "$lt_cv_ld_force_load" = "yes"; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ if test yes = "$lt_cv_ld_force_load"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
[FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=''
fi
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
case $cc_basename in
- ifort*) _lt_dar_can_shared=yes ;;
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
*) _lt_dar_can_shared=$GCC ;;
esac
- if test "$_lt_dar_can_shared" = "yes"; then
+ if test yes = "$_lt_dar_can_shared"; then
output_verbose_link_cmd=func_echo_all
- _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
- _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
- _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
m4_if([$1], [CXX],
-[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
- _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+[ if test yes != "$lt_cv_apple_cc_single_mod"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
fi
],[])
else
@@ -1129,7 +1151,7 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
# Allow to override them for all tags through lt_cv_aix_libpath.
m4_defun([_LT_SYS_MODULE_PATH_AIX],
[m4_require([_LT_DECL_SED])dnl
-if test "${lt_cv_aix_libpath+set}" = set; then
+if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
@@ -1147,7 +1169,7 @@ else
_LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi],[])
if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
- _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
fi
])
aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
@@ -1167,8 +1189,8 @@ m4_define([_LT_SHELL_INIT],
# -----------------------
# Find how we can fake an echo command that does not interpret backslash.
# In particular, with Autoconf 2.60 or later we add some code to the start
-# of the generated configure script which will find a shell with a builtin
-# printf (which we can use as an echo command).
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
m4_defun([_LT_PROG_ECHO_BACKSLASH],
[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
@@ -1196,10 +1218,10 @@ fi
# Invoke $ECHO with all args, space-separated.
func_echo_all ()
{
- $ECHO "$*"
+ $ECHO "$*"
}
-case "$ECHO" in
+case $ECHO in
printf*) AC_MSG_RESULT([printf]) ;;
print*) AC_MSG_RESULT([print -r]) ;;
*) AC_MSG_RESULT([cat]) ;;
@@ -1225,16 +1247,17 @@ _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
AC_DEFUN([_LT_WITH_SYSROOT],
[AC_MSG_CHECKING([for sysroot])
AC_ARG_WITH([sysroot],
-[ --with-sysroot[=DIR] Search for dependent libraries within DIR
- (or the compiler's sysroot if not specified).],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+ [Search for dependent libraries within DIR (or the compiler's sysroot
+ if not specified).])],
[], [with_sysroot=no])
dnl lt_sysroot will always be passed unquoted. We quote it here
dnl in case the user passed a directory name.
lt_sysroot=
-case ${with_sysroot} in #(
+case $with_sysroot in #(
yes)
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
lt_sysroot=`$CC --print-sysroot 2>/dev/null`
fi
;; #(
@@ -1244,14 +1267,14 @@ case ${with_sysroot} in #(
no|'')
;; #(
*)
- AC_MSG_RESULT([${with_sysroot}])
+ AC_MSG_RESULT([$with_sysroot])
AC_MSG_ERROR([The sysroot must be an absolute path.])
;;
esac
AC_MSG_RESULT([${lt_sysroot:-no}])
_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
-[dependent libraries, and in which our libraries should be installed.])])
+[dependent libraries, and where our libraries should be installed.])])
# _LT_ENABLE_LOCK
# ---------------
@@ -1259,31 +1282,33 @@ m4_defun([_LT_ENABLE_LOCK],
[AC_ARG_ENABLE([libtool-lock],
[AS_HELP_STRING([--disable-libtool-lock],
[avoid locking (might break parallel builds)])])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
# Some flags need to be propagated to the compiler or linker for good
# libtool support.
case $host in
ia64-*-hpux*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.$ac_objext` in
*ELF-32*)
- HPUX_IA64_MODE="32"
+ HPUX_IA64_MODE=32
;;
*ELF-64*)
- HPUX_IA64_MODE="64"
+ HPUX_IA64_MODE=64
;;
esac
fi
rm -rf conftest*
;;
*-*-irix6*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
- if test "$lt_cv_prog_gnu_ld" = yes; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
case `/usr/bin/file conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -melf32bsmip"
@@ -1312,9 +1337,46 @@ ia64-*-hpux*)
rm -rf conftest*
;;
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
@@ -1324,9 +1386,19 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
LD="${LD-ld} -m elf_i386_fbsd"
;;
x86_64-*linux*)
- LD="${LD-ld} -m elf_i386"
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
;;
- ppc64-*linux*|powerpc64-*linux*)
+ powerpc64le-*linux*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*linux*)
LD="${LD-ld} -m elf32ppclinux"
;;
s390x-*linux*)
@@ -1345,7 +1417,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
x86_64-*linux*)
LD="${LD-ld} -m elf_x86_64"
;;
- ppc*-*linux*|powerpc*-*linux*)
+ powerpcle-*linux*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*linux*)
LD="${LD-ld} -m elf64ppc"
;;
s390*-*linux*|s390*-*tpf*)
@@ -1363,19 +1438,20 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
*-*-sco3.2v5*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS="$CFLAGS"
+ SAVE_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -belf"
AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
[AC_LANG_PUSH(C)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
AC_LANG_POP])
- if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ if test yes != "$lt_cv_cc_needs_belf"; then
# this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS="$SAVE_CFLAGS"
+ CFLAGS=$SAVE_CFLAGS
fi
;;
*-*solaris*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
@@ -1383,7 +1459,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
case $lt_cv_prog_gnu_ld in
yes*)
case $host in
- i?86-*-solaris*)
+ i?86-*-solaris*|x86_64-*-solaris*)
LD="${LD-ld} -m elf_x86_64"
;;
sparc*-*-solaris*)
@@ -1392,7 +1468,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
esac
# GNU ld 2.21 introduced _sol2 emulations. Use them if available.
if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
- LD="${LD-ld}_sol2"
+ LD=${LD-ld}_sol2
fi
;;
*)
@@ -1408,7 +1484,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
;;
esac
-need_locks="$enable_libtool_lock"
+need_locks=$enable_libtool_lock
])# _LT_ENABLE_LOCK
@@ -1427,11 +1503,11 @@ AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
[echo conftest.$ac_objext > conftest.lst
lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
AC_TRY_EVAL([lt_ar_try])
- if test "$ac_status" -eq 0; then
+ if test 0 -eq "$ac_status"; then
# Ensure the archiver fails upon bogus file names.
rm -f conftest.$ac_objext libconftest.a
AC_TRY_EVAL([lt_ar_try])
- if test "$ac_status" -ne 0; then
+ if test 0 -ne "$ac_status"; then
lt_cv_ar_at_file=@
fi
fi
@@ -1439,7 +1515,7 @@ AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
])
])
-if test "x$lt_cv_ar_at_file" = xno; then
+if test no = "$lt_cv_ar_at_file"; then
archiver_list_spec=
else
archiver_list_spec=$lt_cv_ar_at_file
@@ -1470,7 +1546,7 @@ old_postuninstall_cmds=
if test -n "$RANLIB"; then
case $host_os in
- openbsd*)
+ bitrig* | openbsd*)
old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
;;
*)
@@ -1506,7 +1582,7 @@ AC_CACHE_CHECK([$1], [$2],
[$2=no
m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="$3"
+ lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
# Note that $ac_compile itself does not contain backslashes and begins
@@ -1533,7 +1609,7 @@ AC_CACHE_CHECK([$1], [$2],
$RM conftest*
])
-if test x"[$]$2" = xyes; then
+if test yes = "[$]$2"; then
m4_if([$5], , :, [$5])
else
m4_if([$6], , :, [$6])
@@ -1555,7 +1631,7 @@ AC_DEFUN([_LT_LINKER_OPTION],
m4_require([_LT_DECL_SED])dnl
AC_CACHE_CHECK([$1], [$2],
[$2=no
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $3"
echo "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -1574,10 +1650,10 @@ AC_CACHE_CHECK([$1], [$2],
fi
fi
$RM -r conftest*
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
])
-if test x"[$]$2" = xyes; then
+if test yes = "[$]$2"; then
m4_if([$4], , :, [$4])
else
m4_if([$5], , :, [$5])
@@ -1598,7 +1674,7 @@ AC_DEFUN([LT_CMD_MAX_LEN],
AC_MSG_CHECKING([the maximum length of command line arguments])
AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
i=0
- teststring="ABCD"
+ teststring=ABCD
case $build_os in
msdosdjgpp*)
@@ -1638,7 +1714,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
lt_cv_sys_max_cmd_len=8192;
;;
- netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
@@ -1688,22 +1764,23 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
;;
*)
lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
- if test -n "$lt_cv_sys_max_cmd_len"; then
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
else
# Make teststring a little bigger before we do anything with it.
# a 1K string should be a reasonable start.
- for i in 1 2 3 4 5 6 7 8 ; do
+ for i in 1 2 3 4 5 6 7 8; do
teststring=$teststring$teststring
done
SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
# If test is not a shell built-in, we'll probably end up computing a
# maximum length that is only half of the actual maximum length, but
# we can't tell.
- while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
= "X$teststring$teststring"; } >/dev/null 2>&1 &&
- test $i != 17 # 1/2 MB should be enough
+ test 17 != "$i" # 1/2 MB should be enough
do
i=`expr $i + 1`
teststring=$teststring$teststring
@@ -1719,7 +1796,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
;;
esac
])
-if test -n $lt_cv_sys_max_cmd_len ; then
+if test -n "$lt_cv_sys_max_cmd_len"; then
AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
else
AC_MSG_RESULT(none)
@@ -1747,7 +1824,7 @@ m4_defun([_LT_HEADER_DLFCN],
# ----------------------------------------------------------------
m4_defun([_LT_TRY_DLOPEN_SELF],
[m4_require([_LT_HEADER_DLFCN])dnl
-if test "$cross_compiling" = yes; then :
+if test yes = "$cross_compiling"; then :
[$4]
else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
@@ -1794,9 +1871,9 @@ else
# endif
#endif
-/* When -fvisbility=hidden is used, assume the code has been annotated
+/* When -fvisibility=hidden is used, assume the code has been annotated
correspondingly for the symbols needed. */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
int fnord () __attribute__((visibility("default")));
#endif
@@ -1822,7 +1899,7 @@ int main ()
return status;
}]
_LT_EOF
- if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
(./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
lt_status=$?
case x$lt_status in
@@ -1843,7 +1920,7 @@ rm -fr conftest*
# ------------------
AC_DEFUN([LT_SYS_DLOPEN_SELF],
[m4_require([_LT_HEADER_DLFCN])dnl
-if test "x$enable_dlopen" != xyes; then
+if test yes != "$enable_dlopen"; then
enable_dlopen=unknown
enable_dlopen_self=unknown
enable_dlopen_self_static=unknown
@@ -1853,44 +1930,52 @@ else
case $host_os in
beos*)
- lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen=load_add_on
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
;;
mingw* | pw32* | cegcc*)
- lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen=LoadLibrary
lt_cv_dlopen_libs=
;;
cygwin*)
- lt_cv_dlopen="dlopen"
+ lt_cv_dlopen=dlopen
lt_cv_dlopen_libs=
;;
darwin*)
- # if libdl is installed we need to link against it
+ # if libdl is installed we need to link against it
AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
- lt_cv_dlopen="dyld"
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+ lt_cv_dlopen=dyld
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
])
;;
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
*)
AC_CHECK_FUNC([shl_load],
- [lt_cv_dlopen="shl_load"],
+ [lt_cv_dlopen=shl_load],
[AC_CHECK_LIB([dld], [shl_load],
- [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
[AC_CHECK_FUNC([dlopen],
- [lt_cv_dlopen="dlopen"],
+ [lt_cv_dlopen=dlopen],
[AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
[AC_CHECK_LIB([svld], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
[AC_CHECK_LIB([dld], [dld_link],
- [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
])
])
])
@@ -1899,21 +1984,21 @@ else
;;
esac
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
+ if test no = "$lt_cv_dlopen"; then
enable_dlopen=no
+ else
+ enable_dlopen=yes
fi
case $lt_cv_dlopen in
dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
- save_LIBS="$LIBS"
+ save_LIBS=$LIBS
LIBS="$lt_cv_dlopen_libs $LIBS"
AC_CACHE_CHECK([whether a program can dlopen itself],
@@ -1923,7 +2008,7 @@ else
lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
])
- if test "x$lt_cv_dlopen_self" = xyes; then
+ if test yes = "$lt_cv_dlopen_self"; then
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
lt_cv_dlopen_self_static, [dnl
@@ -1933,9 +2018,9 @@ else
])
fi
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
;;
esac
@@ -2027,8 +2112,8 @@ m4_defun([_LT_COMPILER_FILE_LOCKS],
m4_require([_LT_FILEUTILS_DEFAULTS])dnl
_LT_COMPILER_C_O([$1])
-hard_links="nottested"
-if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
# do not overwrite the value of need_locks provided by the user
AC_MSG_CHECKING([if we can lock with hard links])
hard_links=yes
@@ -2038,8 +2123,8 @@ if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" !=
ln conftest.a conftest.b 2>&5 || hard_links=no
ln conftest.a conftest.b 2>/dev/null && hard_links=no
AC_MSG_RESULT([$hard_links])
- if test "$hard_links" = no; then
- AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ if test no = "$hard_links"; then
+ AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
need_locks=warn
fi
else
@@ -2066,8 +2151,8 @@ objdir=$lt_cv_objdir
_LT_DECL([], [objdir], [0],
[The name of the directory that contains temporary libtool files])dnl
m4_pattern_allow([LT_OBJDIR])dnl
-AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
- [Define to the sub-directory in which libtool stores uninstalled libraries.])
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+ [Define to the sub-directory where libtool stores uninstalled libraries.])
])# _LT_CHECK_OBJDIR
@@ -2079,15 +2164,15 @@ m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
_LT_TAGVAR(hardcode_action, $1)=
if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
test -n "$_LT_TAGVAR(runpath_var, $1)" ||
- test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+ test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
# We can hardcode non-existent directories.
- if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
# If the only mechanism to avoid hardcoding is shlibpath_var, we
# have to relink, otherwise we might link with an installed library
# when we should be linking with a yet-to-be-installed one
- ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
- test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+ test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
# Linking always hardcodes the temporary library directory.
_LT_TAGVAR(hardcode_action, $1)=relink
else
@@ -2101,12 +2186,12 @@ else
fi
AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
-if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
- test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+ test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
# Fast installation is not supported
enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
# Fast installation is not necessary
enable_fast_install=needless
fi
@@ -2130,7 +2215,7 @@ else
# FIXME - insert some real tests, host_os isn't really good enough
case $host_os in
darwin*)
- if test -n "$STRIP" ; then
+ if test -n "$STRIP"; then
striplib="$STRIP -x"
old_striplib="$STRIP -S"
AC_MSG_RESULT([yes])
@@ -2148,6 +2233,47 @@ _LT_DECL([], [striplib], [1])
])# _LT_CMD_STRIPLIB
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x@S|@2 in
+ x)
+ ;;
+ *:)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+ ;;
+ x:*)
+ eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+ ;;
+ *)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
# _LT_SYS_DYNAMIC_LINKER([TAG])
# -----------------------------
# PORTME Fill in your ld.so characteristics
@@ -2158,17 +2284,18 @@ m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_OBJDUMP])dnl
m4_require([_LT_DECL_SED])dnl
m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
AC_MSG_CHECKING([dynamic linker characteristics])
m4_if([$1],
[], [
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
case $host_os in
- darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
- *) lt_awk_arg="/^libraries:/" ;;
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
esac
case $host_os in
- mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
- *) lt_sed_strip_eq="s,=/,/,g" ;;
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
esac
lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
case $lt_search_path_spec in
@@ -2184,28 +2311,35 @@ if test "$GCC" = yes; then
;;
esac
# Ok, now we have the path, separated by spaces, we can step through it
- # and add multilib dir if necessary.
+ # and add multilib dir if necessary...
lt_tmp_lt_search_path_spec=
- lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
for lt_sys_path in $lt_search_path_spec; do
- if test -d "$lt_sys_path/$lt_multi_os_dir"; then
- lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
- else
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
test -d "$lt_sys_path" && \
lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
fi
done
lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS=" "; FS="/|\n";} {
- lt_foo="";
- lt_count=0;
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
for (lt_i = NF; lt_i > 0; lt_i--) {
if ($lt_i != "" && $lt_i != ".") {
if ($lt_i == "..") {
lt_count++;
} else {
if (lt_count == 0) {
- lt_foo="/" $lt_i lt_foo;
+ lt_foo = "/" $lt_i lt_foo;
} else {
lt_count--;
}
@@ -2219,7 +2353,7 @@ BEGIN {RS=" "; FS="/|\n";} {
# for these hosts.
case $host_os in
mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
- $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
esac
sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
else
@@ -2228,7 +2362,7 @@ fi])
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext_cmds=".so"
+shrext_cmds=.so
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -2245,14 +2379,17 @@ hardcode_into_libs=no
# flags to be left without arguments
need_version=unknown
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
case $host_os in
aix3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
shlibpath_var=LIBPATH
# AIX 3 has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}${shared_ext}$major'
+ soname_spec='$libname$release$shared_ext$major'
;;
aix[[4-9]]*)
@@ -2260,41 +2397,91 @@ aix[[4-9]]*)
need_lib_prefix=no
need_version=no
hardcode_into_libs=yes
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 supports IA64
- library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
else
# With GCC up to 2.95.x, collect2 would create an import file
# for dependence libraries. The import file would start with
- # the line `#! .'. This would cause the generated library to
- # depend on `.', always an invalid library. This was fixed in
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
# development snapshots of GCC prior to 3.0.
case $host_os in
aix4 | aix4.[[01]] | aix4.[[01]].*)
if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
echo ' yes '
- echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
:
else
can_build_shared=no
fi
;;
esac
- # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
# soname into executable. Probably we can add versioning support to
# collect2, so additional links can be useful in future.
- if test "$aix_use_runtimelinking" = yes; then
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
# If using run time linking (on AIX 4.2 or later) use lib<name>.so
# instead of lib<name>.a to let people know that these are not
# typical AIX shared libraries.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a[(]lib.so.V[)]'
# We preserve .a as extension for shared libraries through AIX4.2
# and later when we are not doing run time linking.
- library_names_spec='${libname}${release}.a $libname.a'
- soname_spec='${libname}${release}${shared_ext}$major'
- fi
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
shlibpath_var=LIBPATH
fi
;;
@@ -2304,18 +2491,18 @@ amigaos*)
powerpc)
# Since July 2007 AmigaOS4 officially supports .so libraries.
# When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
;;
m68k)
library_names_spec='$libname.ixlibrary $libname.a'
# Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
;;
esac
;;
beos*)
- library_names_spec='${libname}${shared_ext}'
+ library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"
shlibpath_var=LIBRARY_PATH
;;
@@ -2323,8 +2510,8 @@ beos*)
bsdi[[45]]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
@@ -2336,7 +2523,7 @@ bsdi[[45]]*)
cygwin* | mingw* | pw32* | cegcc*)
version_type=windows
- shrext_cmds=".dll"
+ shrext_cmds=.dll
need_version=no
need_lib_prefix=no
@@ -2345,8 +2532,8 @@ cygwin* | mingw* | pw32* | cegcc*)
# gcc
library_names_spec='$libname.dll.a'
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname~
@@ -2362,17 +2549,17 @@ cygwin* | mingw* | pw32* | cegcc*)
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
;;
mingw* | cegcc*)
# MinGW DLLs use traditional 'lib' prefix
- soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
;;
esac
dynamic_linker='Win32 ld.exe'
@@ -2381,8 +2568,8 @@ m4_if([$1], [],[
*,cl*)
# Native MSVC
libname_spec='$name'
- soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
- library_names_spec='${libname}.dll.lib'
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
case $build_os in
mingw*)
@@ -2409,7 +2596,7 @@ m4_if([$1], [],[
sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
;;
*)
- sys_lib_search_path_spec="$LIB"
+ sys_lib_search_path_spec=$LIB
if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
# It is most probably a Windows format PATH.
sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
@@ -2422,8 +2609,8 @@ m4_if([$1], [],[
esac
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname'
@@ -2436,7 +2623,7 @@ m4_if([$1], [],[
*)
# Assume MSVC wrapper
- library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
esac
@@ -2449,8 +2636,8 @@ darwin* | rhapsody*)
version_type=darwin
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
- soname_spec='${libname}${release}${major}$shared_ext'
+ library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
@@ -2463,8 +2650,8 @@ dgux*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -2482,12 +2669,13 @@ freebsd* | dragonfly*)
version_type=freebsd-$objformat
case $version_type in
freebsd-elf*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
need_version=no
need_lib_prefix=no
;;
freebsd-*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
need_version=yes
;;
esac
@@ -2512,26 +2700,15 @@ freebsd* | dragonfly*)
esac
;;
-gnu*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
haiku*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
dynamic_linker="$host_os runtime_loader"
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=yes
+ shlibpath_overrides_runpath=no
sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
hardcode_into_libs=yes
;;
@@ -2549,14 +2726,15 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- if test "X$HPUX_IA64_MODE" = X32; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
else
sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
fi
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
shrext_cmds='.sl'
@@ -2564,8 +2742,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
@@ -2574,8 +2752,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
;;
esac
# HP-UX runs *really* slowly unless shared libraries are mode 555, ...
@@ -2588,8 +2766,8 @@ interix[[3-9]]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -2600,7 +2778,7 @@ irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
*)
- if test "$lt_cv_prog_gnu_ld" = yes; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
version_type=linux # correct to gnu/linux during the next big refactor
else
version_type=irix
@@ -2608,8 +2786,8 @@ irix5* | irix6* | nonstopux*)
esac
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
case $host_os in
irix5* | nonstopux*)
libsuff= shlibsuff=
@@ -2628,8 +2806,8 @@ irix5* | irix6* | nonstopux*)
esac
shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
hardcode_into_libs=yes
;;
@@ -2638,13 +2816,33 @@ linux*oldld* | linux*aout* | linux*coff*)
dynamic_linker=no
;;
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ ;;
+
# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -2669,7 +2867,12 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu)
# before this can be enabled.
hardcode_into_libs=yes
- # Append ld.so.conf contents to the search path
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
@@ -2689,12 +2892,12 @@ netbsd*)
need_lib_prefix=no
need_version=no
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
dynamic_linker='NetBSD (a.out) ld.so'
else
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='NetBSD ld.elf_so'
fi
shlibpath_var=LD_LIBRARY_PATH
@@ -2704,7 +2907,7 @@ netbsd*)
newsos6)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
;;
@@ -2713,58 +2916,68 @@ newsos6)
version_type=qnx
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='ldqnx.so'
;;
-openbsd*)
+openbsd* | bitrig*)
version_type=sunos
- sys_lib_dlsearch_path_spec="/usr/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib
need_lib_prefix=no
- # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
- case $host_os in
- openbsd3.3 | openbsd3.3.*) need_version=yes ;;
- *) need_version=no ;;
- esac
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- case $host_os in
- openbsd2.[[89]] | openbsd2.[[89]].*)
- shlibpath_overrides_runpath=no
- ;;
- *)
- shlibpath_overrides_runpath=yes
- ;;
- esac
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
else
- shlibpath_overrides_runpath=yes
+ need_version=yes
fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
;;
os2*)
libname_spec='$name'
- shrext_cmds=".dll"
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
need_lib_prefix=no
- library_names_spec='$libname${shared_ext} $libname.a'
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
;;
osf3* | osf4* | osf5*)
version_type=osf
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
rdos*)
@@ -2775,8 +2988,8 @@ solaris*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
@@ -2786,11 +2999,11 @@ solaris*)
sunos4*)
version_type=sunos
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
need_lib_prefix=no
fi
need_version=yes
@@ -2798,8 +3011,8 @@ sunos4*)
sysv4 | sysv4.3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
case $host_vendor in
sni)
@@ -2820,24 +3033,24 @@ sysv4 | sysv4.3*)
;;
sysv4*MP*)
- if test -d /usr/nec ;then
+ if test -d /usr/nec; then
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
- soname_spec='$libname${shared_ext}.$major'
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
shlibpath_var=LD_LIBRARY_PATH
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- version_type=freebsd-elf
+ version_type=sco
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
else
sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
@@ -2855,7 +3068,7 @@ tpf*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
@@ -2863,8 +3076,8 @@ tpf*)
uts4*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -2873,20 +3086,30 @@ uts4*)
;;
esac
AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
+test no = "$dynamic_linker" && can_build_shared=no
variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
- sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
- sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
fi
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
_LT_DECL([], [variables_saved_for_relink], [1],
[Variables whose values should be saved in libtool wrapper scripts and
restored at link time])
@@ -2919,39 +3142,41 @@ _LT_DECL([], [hardcode_into_libs], [0],
[Whether we should hardcode library paths into libraries])
_LT_DECL([], [sys_lib_search_path_spec], [2],
[Compile-time system search path for libraries])
-_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
- [Run-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+ [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+ [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
])# _LT_SYS_DYNAMIC_LINKER
# _LT_PATH_TOOL_PREFIX(TOOL)
# --------------------------
-# find a file program which can recognize shared library
+# find a file program that can recognize shared library
AC_DEFUN([_LT_PATH_TOOL_PREFIX],
[m4_require([_LT_DECL_EGREP])dnl
AC_MSG_CHECKING([for $1])
AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
[case $MAGIC_CMD in
[[\\/*] | ?:[\\/]*])
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
;;
*)
- lt_save_MAGIC_CMD="$MAGIC_CMD"
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
dnl $ac_dummy forces splitting on constant user-supplied paths.
dnl POSIX.2 word splitting is done only on the output of word expansions,
dnl not every word. This closes a longstanding sh security hole.
ac_dummy="m4_if([$2], , $PATH, [$2])"
for ac_dir in $ac_dummy; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$1; then
- lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -f "$ac_dir/$1"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
:
@@ -2974,11 +3199,11 @@ _LT_EOF
break
fi
done
- IFS="$lt_save_ifs"
- MAGIC_CMD="$lt_save_MAGIC_CMD"
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
;;
esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if test -n "$MAGIC_CMD"; then
AC_MSG_RESULT($MAGIC_CMD)
else
@@ -2996,7 +3221,7 @@ dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
# _LT_PATH_MAGIC
# --------------
-# find a file program which can recognize a shared library
+# find a file program that can recognize a shared library
m4_defun([_LT_PATH_MAGIC],
[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
if test -z "$lt_cv_path_MAGIC_CMD"; then
@@ -3023,16 +3248,16 @@ m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
AC_ARG_WITH([gnu-ld],
[AS_HELP_STRING([--with-gnu-ld],
[assume the C compiler uses GNU ld @<:@default=no@:>@])],
- [test "$withval" = no || with_gnu_ld=yes],
+ [test no = "$withval" || with_gnu_ld=yes],
[with_gnu_ld=no])dnl
ac_prog=ld
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
# Check if gcc -print-prog-name=ld gives a path.
AC_MSG_CHECKING([for ld used by $CC])
case $host in
*-*-mingw*)
- # gcc leaves a trailing carriage return which upsets mingw
+ # gcc leaves a trailing carriage return, which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
@@ -3046,7 +3271,7 @@ if test "$GCC" = yes; then
while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
done
- test -z "$LD" && LD="$ac_prog"
+ test -z "$LD" && LD=$ac_prog
;;
"")
# If it fails, then pretend we aren't using GCC.
@@ -3057,37 +3282,37 @@ if test "$GCC" = yes; then
with_gnu_ld=unknown
;;
esac
-elif test "$with_gnu_ld" = yes; then
+elif test yes = "$with_gnu_ld"; then
AC_MSG_CHECKING([for GNU ld])
else
AC_MSG_CHECKING([for non-GNU ld])
fi
AC_CACHE_VAL(lt_cv_path_LD,
[if test -z "$LD"; then
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD="$ac_dir/$ac_prog"
+ lt_cv_path_LD=$ac_dir/$ac_prog
# Check to see if the program is GNU ld. I'd rather use --version,
# but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
- test "$with_gnu_ld" != no && break
+ test no != "$with_gnu_ld" && break
;;
*)
- test "$with_gnu_ld" != yes && break
+ test yes != "$with_gnu_ld" && break
;;
esac
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
else
- lt_cv_path_LD="$LD" # Let the user override the test with a path.
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
fi])
-LD="$lt_cv_path_LD"
+LD=$lt_cv_path_LD
if test -n "$LD"; then
AC_MSG_RESULT($LD)
else
@@ -3141,13 +3366,13 @@ esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- if test "$GCC" != yes; then
+ if test yes != "$GCC"; then
reload_cmds=false
fi
;;
darwin*)
- if test "$GCC" = yes; then
- reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
else
reload_cmds='$LD$reload_flag -o $output$reload_objs'
fi
@@ -3158,6 +3383,43 @@ _LT_TAGDECL([], [reload_cmds], [2])dnl
])# _LT_CMD_RELOAD
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+ [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
# _LT_CHECK_MAGIC_METHOD
# ----------------------
# how to check for library dependencies
@@ -3173,13 +3435,13 @@ lt_cv_deplibs_check_method='unknown'
# Need to set the preceding variable on all platforms that support
# interlibrary dependencies.
# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
+# 'unknown' -- same as none, but documents that we really don't know.
# 'pass_all' -- all dependencies passed with no checks.
# 'test_compile' -- check by making test program.
# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given extended regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
case $host_os in
aix[[4-9]]*)
@@ -3206,8 +3468,7 @@ mingw* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
# func_win32_libid shell function, so use a weaker test based on 'objdump',
# unless we find 'file', for example because we are cross-compiling.
- # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
- if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ if ( file / ) >/dev/null 2>&1; then
lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
lt_cv_file_magic_cmd='func_win32_libid'
else
@@ -3243,10 +3504,6 @@ freebsd* | dragonfly*)
fi
;;
-gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
haiku*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -3285,7 +3542,7 @@ irix5* | irix6* | nonstopux*)
;;
# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -3307,8 +3564,8 @@ newos6*)
lt_cv_deplibs_check_method=pass_all
;;
-openbsd*)
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
else
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
@@ -3361,6 +3618,9 @@ sysv4 | sysv4.3*)
tpf*)
lt_cv_deplibs_check_method=pass_all
;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
esac
])
@@ -3401,33 +3661,38 @@ AC_DEFUN([LT_PATH_NM],
AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
[if test -n "$NM"; then
# Let the user override the test.
- lt_cv_path_NM="$NM"
+ lt_cv_path_NM=$NM
else
- lt_nm_to_check="${ac_tool_prefix}nm"
+ lt_nm_to_check=${ac_tool_prefix}nm
if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
lt_nm_to_check="$lt_nm_to_check nm"
fi
for lt_tmp_nm in $lt_nm_to_check; do
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
- tmp_nm="$ac_dir/$lt_tmp_nm"
- if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
# Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
# nm: unknown option "B" ignored
# Tru64's nm complains that /dev/null is an invalid object file
- case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
- */dev/null* | *'Invalid file or object type'*)
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
lt_cv_path_NM="$tmp_nm -B"
- break
+ break 2
;;
*)
case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
*/dev/null*)
lt_cv_path_NM="$tmp_nm -p"
- break
+ break 2
;;
*)
lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
@@ -3438,21 +3703,21 @@ else
esac
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
done
: ${lt_cv_path_NM=no}
fi])
-if test "$lt_cv_path_NM" != "no"; then
- NM="$lt_cv_path_NM"
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
else
# Didn't find any BSD compatible name lister, look for dumpbin.
if test -n "$DUMPBIN"; then :
# Let the user override the test.
else
AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
- case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
*COFF*)
- DUMPBIN="$DUMPBIN -symbols"
+ DUMPBIN="$DUMPBIN -symbols -headers"
;;
*)
DUMPBIN=:
@@ -3460,8 +3725,8 @@ else
esac
fi
AC_SUBST([DUMPBIN])
- if test "$DUMPBIN" != ":"; then
- NM="$DUMPBIN"
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
fi
fi
test -z "$NM" && NM=nm
@@ -3507,8 +3772,8 @@ lt_cv_sharedlib_from_linklib_cmd,
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- # two different shell functions defined in ltmain.sh
- # decide which to use based on capabilities of $DLLTOOL
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
case `$DLLTOOL --help 2>&1` in
*--identify-strict*)
lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
@@ -3520,7 +3785,7 @@ cygwin* | mingw* | pw32* | cegcc*)
;;
*)
# fallback: assume linklib IS sharedlib
- lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
;;
esac
])
@@ -3547,13 +3812,28 @@ AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool
lt_cv_path_mainfest_tool=yes
fi
rm -f conftest*])
-if test "x$lt_cv_path_mainfest_tool" != xyes; then
+if test yes != "$lt_cv_path_mainfest_tool"; then
MANIFEST_TOOL=:
fi
_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
])# _LT_PATH_MANIFEST_TOOL
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+ test DEF = "`$SED -n dnl
+ -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace
+ -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments
+ -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl
+ -e q dnl Only consider the first "real" line
+ $1`" dnl
+])# _LT_DLL_DEF_P
+
+
# LT_LIB_M
# --------
# check for math library
@@ -3565,11 +3845,11 @@ case $host in
# These system don't have libm, or don't need it
;;
*-ncr-sysv4.3*)
- AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
;;
*)
- AC_CHECK_LIB(m, cos, LIBM="-lm")
+ AC_CHECK_LIB(m, cos, LIBM=-lm)
;;
esac
AC_SUBST([LIBM])
@@ -3588,7 +3868,7 @@ m4_defun([_LT_COMPILER_NO_RTTI],
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
case $cc_basename in
nvcc*)
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
@@ -3640,7 +3920,7 @@ cygwin* | mingw* | pw32* | cegcc*)
symcode='[[ABCDGISTW]]'
;;
hpux*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
symcode='[[ABCDEGRST]]'
fi
;;
@@ -3673,14 +3953,44 @@ case `$NM -V 2>&1` in
symcode='[[ABCDGIRSTW]]' ;;
esac
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
# Transform an extracted symbol line into a proper C declaration.
# Some systems (esp. on ia64) link data and code symbols differently,
# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
# Handle CRLF in mingw tool chain
opt_cr=
@@ -3698,21 +4008,24 @@ for ac_symprfx in "" "_"; do
# Write the raw and C identifiers.
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- # Fake it for dumpbin and say T for any non-static function
- # and D for any global variable.
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
# Also find C++ and __fastcall symbols from MSVC++,
# which start with @ or ?.
lt_cv_sys_global_symbol_pipe="$AWK ['"\
" {last_section=section; section=\$ 3};"\
" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
" \$ 0!~/External *\|/{next};"\
" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
" {if(hide[section]) next};"\
-" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
-" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
-" s[1]~/^[@?]/{print s[1], s[1]; next};"\
-" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
" ' prfx=^$ac_symprfx]"
else
lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
@@ -3752,11 +4065,11 @@ _LT_EOF
if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
cat <<_LT_EOF > conftest.$ac_ext
/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
relocations are performed -- see ld's documentation on pseudo-relocs. */
# define LT@&t@_DLSYM_CONST
-#elif defined(__osf__)
+#elif defined __osf__
/* This system does not cope well with relocations in const data. */
# define LT@&t@_DLSYM_CONST
#else
@@ -3782,7 +4095,7 @@ lt__PROGRAM__LTX_preloaded_symbols[[]] =
{
{ "@PROGRAM@", (void *) 0 },
_LT_EOF
- $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
cat <<\_LT_EOF >> conftest.$ac_ext
{0, (void *) 0}
};
@@ -3802,9 +4115,9 @@ _LT_EOF
mv conftest.$ac_objext conftstm.$ac_objext
lt_globsym_save_LIBS=$LIBS
lt_globsym_save_CFLAGS=$CFLAGS
- LIBS="conftstm.$ac_objext"
+ LIBS=conftstm.$ac_objext
CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
- if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
pipe_works=yes
fi
LIBS=$lt_globsym_save_LIBS
@@ -3825,7 +4138,7 @@ _LT_EOF
rm -rf conftest* conftst*
# Do not use the global_symbol_pipe unless it works.
- if test "$pipe_works" = yes; then
+ if test yes = "$pipe_works"; then
break
else
lt_cv_sys_global_symbol_pipe=
@@ -3852,12 +4165,16 @@ _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
[Take the output of nm and produce a listing of raw symbols and C names])
_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
[Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+ [Transform the output of nm into a list of symbols to manually relocate])
_LT_DECL([global_symbol_to_c_name_address],
[lt_cv_sys_global_symbol_to_c_name_address], [1],
[Transform the output of nm in a C name address pair])
_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
[lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
[Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+ [The name lister interface])
_LT_DECL([], [nm_file_list_spec], [1],
[Specify filename containing input files for $NM])
]) # _LT_CMD_GLOBAL_SYMBOLS
@@ -3873,17 +4190,18 @@ _LT_TAGVAR(lt_prog_compiler_static, $1)=
m4_if([$1], [CXX], [
# C++ specific cases for pic, static, wl, etc.
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
case $host_os in
aix*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
amigaos*)
@@ -3894,8 +4212,8 @@ m4_if([$1], [CXX], [
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
esac
@@ -3911,6 +4229,11 @@ m4_if([$1], [CXX], [
# (--disable-auto-import) libraries
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
;;
darwin* | rhapsody*)
# PIC is the default on this platform
@@ -3960,7 +4283,7 @@ m4_if([$1], [CXX], [
case $host_os in
aix[[4-9]]*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
else
@@ -4001,14 +4324,14 @@ m4_if([$1], [CXX], [
case $cc_basename in
CC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
- if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ if test ia64 != "$host_cpu"; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
fi
;;
aCC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
case $host_cpu in
hppa*64*|ia64*)
# +Z the default
@@ -4037,7 +4360,7 @@ m4_if([$1], [CXX], [
;;
esac
;;
- linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
case $cc_basename in
KCC*)
# KAI C++ Compiler
@@ -4045,7 +4368,7 @@ m4_if([$1], [CXX], [
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
ecpc* )
- # old Intel C++ for x86_64 which still supported -KPIC.
+ # old Intel C++ for x86_64, which still supported -KPIC.
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
@@ -4190,17 +4513,18 @@ m4_if([$1], [CXX], [
fi
],
[
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
case $host_os in
aix*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
amigaos*)
@@ -4211,8 +4535,8 @@ m4_if([$1], [CXX], [
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
esac
@@ -4229,6 +4553,11 @@ m4_if([$1], [CXX], [
# (--disable-auto-import) libraries
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
;;
darwin* | rhapsody*)
@@ -4299,7 +4628,7 @@ m4_if([$1], [CXX], [
case $host_os in
aix*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
else
@@ -4307,11 +4636,30 @@ m4_if([$1], [CXX], [
fi
;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+
mingw* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
;;
hpux9* | hpux10* | hpux11*)
@@ -4327,7 +4675,7 @@ m4_if([$1], [CXX], [
;;
esac
# Is there a better lt_prog_compiler_static that works with the bundled CC?
- _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
;;
irix5* | irix6* | nonstopux*)
@@ -4336,9 +4684,9 @@ m4_if([$1], [CXX], [
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
- linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
case $cc_basename in
- # old Intel for x86_64 which still supported -KPIC.
+ # old Intel for x86_64, which still supported -KPIC.
ecc*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
@@ -4363,6 +4711,12 @@ m4_if([$1], [CXX], [
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group compilers (*not* the Pentium gcc compiler,
# which looks to be a dead project)
@@ -4460,7 +4814,7 @@ m4_if([$1], [CXX], [
;;
sysv4*MP*)
- if test -d /usr/nec ;then
+ if test -d /usr/nec; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
@@ -4489,7 +4843,7 @@ m4_if([$1], [CXX], [
fi
])
case $host_os in
- # For platforms which do not support PIC, -DPIC is meaningless:
+ # For platforms that do not support PIC, -DPIC is meaningless:
*djgpp*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)=
;;
@@ -4555,17 +4909,21 @@ m4_if([$1], [CXX], [
case $host_os in
aix[[4-9]]*)
# If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to AIX nm, but means don't demangle with GNU nm
- # Also, AIX nm treats weak defined symbols like other global defined
- # symbols, whereas GNU nm marks them as "W".
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
;;
pw32*)
- _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
;;
cygwin* | mingw* | cegcc*)
case $cc_basename in
@@ -4611,9 +4969,9 @@ m4_if([$1], [CXX], [
# included in the symbol list
_LT_TAGVAR(include_expsyms, $1)=
# exclude_expsyms can be an extended regexp of symbols to exclude
- # it will be wrapped by ` (' and `)$', so one must not match beginning or
- # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
- # as well as any symbol that contains `d'.
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
_LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
# platforms (ab)use it in PIC code, but their linkers get confused if
@@ -4629,7 +4987,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
- if test "$GCC" != yes; then
+ if test yes != "$GCC"; then
with_gnu_ld=no
fi
;;
@@ -4637,7 +4995,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
- openbsd*)
+ openbsd* | bitrig*)
with_gnu_ld=no
;;
esac
@@ -4647,7 +5005,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
# On some targets, GNU ld is compatible enough with the native linker
# that we're better off using the native interface for both.
lt_use_gnu_ld_interface=no
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
case $host_os in
aix*)
# The AIX port of GNU ld has always aspired to compatibility
@@ -4669,24 +5027,24 @@ dnl Note also adjust exclude_expsyms for C++ above.
esac
fi
- if test "$lt_use_gnu_ld_interface" = yes; then
+ if test yes = "$lt_use_gnu_ld_interface"; then
# If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='${wl}'
+ wlarc='$wl'
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
runpath_var=LD_RUN_PATH
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
# ancient GNU ld didn't support --whole-archive et. al.
if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
supports_anon_versioning=no
- case `$LD -v 2>&1` in
+ case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
*GNU\ gold*) supports_anon_versioning=yes ;;
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
@@ -4699,7 +5057,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
case $host_os in
aix[[3-9]]*)
# On AIX/PPC, the GNU linker is very broken
- if test "$host_cpu" != ia64; then
+ if test ia64 != "$host_cpu"; then
_LT_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
@@ -4718,7 +5076,7 @@ _LT_EOF
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)=''
;;
m68k)
@@ -4734,7 +5092,7 @@ _LT_EOF
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
- _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -4744,7 +5102,7 @@ _LT_EOF
# _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
# as there is no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -4752,61 +5110,89 @@ _LT_EOF
_LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is; otherwise, prepend...
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
haiku*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
interix[[3-9]]*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
tmp_diet=no
- if test "$host_os" = linux-dietlibc; then
+ if test linux-dietlibc = "$host_os"; then
case $cc_basename in
diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
esac
fi
if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
- && test "$tmp_diet" = no
+ && test no = "$tmp_diet"
then
tmp_addflag=' $pic_flag'
tmp_sharedflag='-shared'
case $cc_basename,$host_cpu in
pgcc*) # Portland Group C compiler
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
tmp_addflag=' $pic_flag'
;;
pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group f77 and f90 compilers
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
tmp_addflag=' $pic_flag -Mnomain' ;;
ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
tmp_addflag=' -i_dynamic' ;;
@@ -4817,42 +5203,47 @@ _LT_EOF
lf95*) # Lahey Fortran 8.1
_LT_TAGVAR(whole_archive_flag_spec, $1)=
tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
tmp_sharedflag='-qmkshrobj'
tmp_addflag= ;;
nvcc*) # Cuda Compiler Driver 2.2
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
;;
esac
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*) # Sun C 5.9
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
tmp_sharedflag='-G' ;;
*Sun\ F*) # Sun Fortran 8.3
tmp_sharedflag='-G' ;;
esac
- _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
case $cc_basename in
+ tcc*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+ ;;
xlf* | bgf* | bgxlf* | mpixlf*)
# IBM XL Fortran 10.1 on PPC cannot create shared libs itself
_LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
fi
;;
esac
@@ -4866,8 +5257,8 @@ _LT_EOF
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
fi
;;
@@ -4885,8 +5276,8 @@ _LT_EOF
_LT_EOF
elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -4898,7 +5289,7 @@ _LT_EOF
_LT_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
*** reliably create shared libraries on SCO systems. Therefore, libtool
*** is disabling shared libraries support. We urge you to upgrade GNU
*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
@@ -4913,9 +5304,9 @@ _LT_EOF
# DT_RUNPATH tag from executables and libraries. But doing so
# requires that you compile everything twice, which is a pain.
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -4932,15 +5323,15 @@ _LT_EOF
*)
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
- if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
runpath_var=
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_TAGVAR(export_dynamic_flag_spec, $1)=
@@ -4956,7 +5347,7 @@ _LT_EOF
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
- if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
_LT_TAGVAR(hardcode_direct, $1)=unsupported
@@ -4964,34 +5355,57 @@ _LT_EOF
;;
aix[[4-9]]*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
- no_entry_flag=""
+ no_entry_flag=
else
# If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to AIX nm, but means don't demangle with GNU nm
- # Also, AIX nm treats weak defined symbols like other global
- # defined symbols, whereas GNU nm marks them as "W".
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
for ld_flag in $LDFLAGS; do
- if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
aix_use_runtimelinking=yes
break
fi
done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
;;
esac
@@ -5010,13 +5424,21 @@ _LT_EOF
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
- collect2name=`${CC} -print-prog-name=collect2`
+ collect2name=`$CC -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
@@ -5035,61 +5457,80 @@ _LT_EOF
;;
esac
shared_flag='-shared'
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag="$shared_flag "'${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
else
# not using gcc
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
else
- shared_flag='${wl}-bM:SRE'
+ shared_flag='$wl-bM:SRE'
fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
fi
fi
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to export.
_LT_TAGVAR(always_export_symbols, $1)=yes
- if test "$aix_use_runtimelinking" = yes; then
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
# Warning - without using the other runtime loading flags (-brtl),
# -berok will link without error, but may produce a broken library.
_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
# Determine the default libpath from the value encoded in an
# empty executable.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
else
- if test "$host_cpu" = ia64; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
_LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an
# empty executable.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
- if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
# We only use this code for GNU lds that support --whole-archive.
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
_LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- # This is similar to how AIX traditionally builds its shared libraries.
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
fi
fi
;;
@@ -5098,7 +5539,7 @@ _LT_EOF
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)=''
;;
m68k)
@@ -5128,16 +5569,17 @@ _LT_EOF
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
- else
- sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -5146,18 +5588,18 @@ _LT_EOF
# Don't use ranlib
_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile="$lt_outputfile.exe"
- lt_tool_outputfile="$lt_tool_outputfile.exe"
- ;;
- esac~
- if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
;;
*)
# Assume MSVC wrapper
@@ -5166,7 +5608,7 @@ _LT_EOF
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
@@ -5216,33 +5658,33 @@ _LT_EOF
;;
hpux9*)
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
else
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_direct, $1)=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
;;
hpux10*)
- if test "$GCC" = yes && test "$with_gnu_ld" = no; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
fi
- if test "$with_gnu_ld" = no; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
@@ -5250,25 +5692,25 @@ _LT_EOF
;;
hpux11*)
- if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ if test yes,no = "$GCC,$with_gnu_ld"; then
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
m4_if($1, [], [
@@ -5276,14 +5718,14 @@ _LT_EOF
# (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
_LT_LINKER_OPTION([if $CC understands -b],
_LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
- [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
[_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
- [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
;;
esac
fi
- if test "$with_gnu_ld" = no; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
case $host_cpu in
@@ -5294,7 +5736,7 @@ _LT_EOF
*)
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
@@ -5305,16 +5747,16 @@ _LT_EOF
;;
irix5* | irix6* | nonstopux*)
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
# Try to use the -exported_symbol ld option, if it does not
# work, assume that -exports_file does not work either and
# implicitly export all symbols.
# This should be the same for all languages, so no per-tag cache variable.
AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
[lt_cv_irix_exported_symbol],
- [save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ [save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
AC_LINK_IFELSE(
[AC_LANG_SOURCE(
[AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
@@ -5327,21 +5769,31 @@ _LT_EOF
end]])])],
[lt_cv_irix_exported_symbol=yes],
[lt_cv_irix_exported_symbol=no])
- LDFLAGS="$save_LDFLAGS"])
- if test "$lt_cv_irix_exported_symbol" = yes; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ LDFLAGS=$save_LDFLAGS])
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
fi
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(inherit_rpath, $1)=yes
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
@@ -5356,7 +5808,7 @@ _LT_EOF
newsos6)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
@@ -5364,27 +5816,19 @@ _LT_EOF
*nto* | *qnx*)
;;
- openbsd*)
+ openbsd* | bitrig*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
else
- case $host_os in
- openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- ;;
- esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
fi
else
_LT_TAGVAR(ld_shlibs, $1)=no
@@ -5395,33 +5839,53 @@ _LT_EOF
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
;;
osf3*)
- if test "$GCC" = yes; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
else
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
;;
osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test "$GCC" = yes; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
else
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
- $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
# Both c and cxx compiler support -rpath directly
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -5432,24 +5896,24 @@ _LT_EOF
solaris*)
_LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
- if test "$GCC" = yes; then
- wlarc='${wl}'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
else
case `$CC -V 2>&1` in
*"Compilers 5.0"*)
wlarc=''
- _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
;;
*)
- wlarc='${wl}'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
;;
esac
fi
@@ -5459,11 +5923,11 @@ _LT_EOF
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The compiler driver will combine and reorder linker options,
- # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
# but is careful enough not to reorder.
# Supported since Solaris 2.6 (maybe 2.5.1?)
- if test "$GCC" = yes; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
fi
@@ -5473,10 +5937,10 @@ _LT_EOF
;;
sunos4*)
- if test "x$host_vendor" = xsequent; then
+ if test sequent = "$host_vendor"; then
# Use $CC to link under sequent, because it throws in some extra .o
# files that make .init and .fini sections work.
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
fi
@@ -5525,43 +5989,43 @@ _LT_EOF
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
runpath_var='LD_RUN_PATH'
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
sysv5* | sco3.2v5* | sco5v6*)
- # Note: We can NOT use -z defs as we might desire, because we do not
+ # Note: We CANNOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
- _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
runpath_var='LD_RUN_PATH'
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
@@ -5576,17 +6040,17 @@ _LT_EOF
;;
esac
- if test x$host_vendor = xsni; then
+ if test sni = "$host_vendor"; then
case $host in
sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
;;
esac
fi
fi
])
AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
@@ -5603,7 +6067,7 @@ x|xyes)
# Assume -lc should be added
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- if test "$enable_shared" = yes && test "$GCC" = yes; then
+ if test yes,yes = "$GCC,$enable_shared"; then
case $_LT_TAGVAR(archive_cmds, $1) in
*'~'*)
# FIXME: we may have to deal with multi-command sequences.
@@ -5683,12 +6147,12 @@ _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
_LT_TAGDECL([], [hardcode_libdir_separator], [1],
[Whether we need a single "-rpath" flag with a separated argument])
_LT_TAGDECL([], [hardcode_direct], [0],
- [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
DIR into the resulting binary])
_LT_TAGDECL([], [hardcode_direct_absolute], [0],
- [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
DIR into the resulting binary and the resulting library dependency is
- "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ "absolute", i.e impossible to change by setting $shlibpath_var if the
library is relocated])
_LT_TAGDECL([], [hardcode_minus_L], [0],
[Set to "yes" if using the -LDIR flag during linking hardcodes DIR
@@ -5729,10 +6193,10 @@ dnl [Compiler flag to generate thread safe objects])
# ------------------------
# Ensure that the configuration variables for a C compiler are suitably
# defined. These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
+# the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_C_CONFIG],
[m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC="$CC"
+lt_save_CC=$CC
AC_LANG_PUSH(C)
# Source file extension for C test sources.
@@ -5772,18 +6236,18 @@ if test -n "$compiler"; then
LT_SYS_DLOPEN_SELF
_LT_CMD_STRIPLIB
- # Report which library types will actually be built
+ # Report what library types will actually be built
AC_MSG_CHECKING([if libtool supports shared libraries])
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
- test "$can_build_shared" = "no" && enable_shared=no
+ test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
- test "$enable_shared" = yes && enable_static=no
+ test yes = "$enable_shared" && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
@@ -5791,8 +6255,12 @@ if test -n "$compiler"; then
;;
aix[[4-9]]*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
fi
;;
esac
@@ -5800,13 +6268,13 @@ if test -n "$compiler"; then
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
- test "$enable_shared" = yes || enable_static=yes
+ test yes = "$enable_shared" || enable_static=yes
AC_MSG_RESULT([$enable_static])
_LT_CONFIG($1)
fi
AC_LANG_POP
-CC="$lt_save_CC"
+CC=$lt_save_CC
])# _LT_LANG_C_CONFIG
@@ -5814,14 +6282,14 @@ CC="$lt_save_CC"
# --------------------------
# Ensure that the configuration variables for a C++ compiler are suitably
# defined. These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
+# the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_CXX_CONFIG],
[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_EGREP])dnl
m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
- ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
- (test "X$CXX" != "Xg++"))) ; then
+if test -n "$CXX" && ( test no != "$CXX" &&
+ ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+ (test g++ != "$CXX"))); then
AC_PROG_CXXCPP
else
_lt_caught_CXX_error=yes
@@ -5863,7 +6331,7 @@ _LT_TAGVAR(objext, $1)=$objext
# the CXX compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_caught_CXX_error" != yes; then
+if test yes != "$_lt_caught_CXX_error"; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;"
@@ -5905,35 +6373,35 @@ if test "$_lt_caught_CXX_error" != yes; then
if test -n "$compiler"; then
# We don't want -fno-exception when compiling C++ code, so set the
# no_builtin_flag separately
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
else
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
fi
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
# Set up default GNU C++ configuration
LT_PATH_LD
# Check if GNU C++ uses GNU ld as the underlying linker, since the
# archiving commands below assume that GNU ld is being used.
- if test "$with_gnu_ld" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ if test yes = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
# If archive_cmds runs LD, not CC, wlarc should be empty
# XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
# investigate it a little bit more. (MM)
- wlarc='${wl}'
+ wlarc='$wl'
# ancient GNU ld didn't support --whole-archive et. al.
if eval "`$CC -print-prog-name=ld` --help 2>&1" |
$GREP 'no-whole-archive' > /dev/null; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
@@ -5969,18 +6437,30 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(ld_shlibs, $1)=no
;;
aix[[4-9]]*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
- no_entry_flag=""
+ no_entry_flag=
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
for ld_flag in $LDFLAGS; do
case $ld_flag in
@@ -5990,6 +6470,13 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
esac
done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
;;
esac
@@ -6008,13 +6495,21 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
- collect2name=`${CC} -print-prog-name=collect2`
+ collect2name=`$CC -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
@@ -6032,64 +6527,84 @@ if test "$_lt_caught_CXX_error" != yes; then
fi
esac
shared_flag='-shared'
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag="$shared_flag "'${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag=$shared_flag' $wl-G'
fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
else
# not using gcc
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
else
- shared_flag='${wl}-bM:SRE'
+ shared_flag='$wl-bM:SRE'
fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
fi
fi
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to
# export.
_LT_TAGVAR(always_export_symbols, $1)=yes
- if test "$aix_use_runtimelinking" = yes; then
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
# Warning - without using the other runtime loading flags (-brtl),
# -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # The "-G" linker flag allows undefined symbols.
+ _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
# Determine the default libpath from the value encoded in an empty
# executable.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
else
- if test "$host_cpu" = ia64; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
_LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an
# empty executable.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
- if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
# We only use this code for GNU lds that support --whole-archive.
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
_LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- # This is similar to how AIX traditionally builds its shared
- # libraries.
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared
+ # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
fi
fi
;;
@@ -6099,7 +6614,7 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
- _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -6127,57 +6642,58 @@ if test "$_lt_caught_CXX_error" != yes; then
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
- else
- $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
# Don't use ranlib
_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile="$lt_outputfile.exe"
- lt_tool_outputfile="$lt_tool_outputfile.exe"
- ;;
- esac~
- func_to_tool_file "$lt_outputfile"~
- if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
;;
*)
# g++
# _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
# as there is no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is; otherwise, prepend...
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -6188,6 +6704,34 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_DARWIN_LINKER_FEATURES($1)
;;
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
dgux*)
case $cc_basename in
ec++*)
@@ -6222,18 +6766,15 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(ld_shlibs, $1)=yes
;;
- gnu*)
- ;;
-
haiku*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
hpux9*)
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
# but as the default
@@ -6245,7 +6786,7 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(ld_shlibs, $1)=no
;;
aCC*)
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
@@ -6254,11 +6795,11 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
else
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
@@ -6268,15 +6809,15 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
hpux10*|hpux11*)
- if test $with_gnu_ld = no; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
case $host_cpu in
hppa*64*|ia64*)
;;
*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
;;
esac
fi
@@ -6302,13 +6843,13 @@ if test "$_lt_caught_CXX_error" != yes; then
aCC*)
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
# Commands to make compiler produce verbose output that lists
@@ -6319,20 +6860,20 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes; then
- if test $with_gnu_ld = no; then
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
fi
@@ -6347,22 +6888,22 @@ if test "$_lt_caught_CXX_error" != yes; then
interix[[3-9]]*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
irix5* | irix6*)
case $cc_basename in
CC*)
# SGI C++
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
# Archives containing C++ object files must be created using
# "CC -ar", where "CC" is the IRIX C++ compiler. This is
@@ -6371,22 +6912,22 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
;;
*)
- if test "$GXX" = yes; then
- if test "$with_gnu_ld" = no; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
fi
fi
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
esac
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(inherit_rpath, $1)=yes
;;
- linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
case $cc_basename in
KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
@@ -6394,8 +6935,8 @@ if test "$_lt_caught_CXX_error" != yes; then
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
- _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
@@ -6404,10 +6945,10 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
# Archives containing C++ object files must be created using
# "CC -Bstatic", where "CC" is the KAI C++ compiler.
@@ -6421,59 +6962,59 @@ if test "$_lt_caught_CXX_error" != yes; then
# earlier do not add the objects themselves.
case `$CC -V 2>&1` in
*"Version 7."*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
*) # Version 8.0 or newer
tmp_idyn=
case $host_cpu in
ia64*) tmp_idyn=' -i_dynamic';;
esac
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
esac
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
;;
pgCC* | pgcpp*)
# Portland Group C++ compiler
case `$CC -V` in
*pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
_LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
- compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
_LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
- $RANLIB $oldlib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
_LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
*) # Version 6 and above use weak symbols
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
esac
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
;;
cxx*)
# Compaq C++
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols'
runpath_var=LD_RUN_PATH
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -6487,18 +7028,18 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
;;
xl* | mpixl* | bgxl*)
# IBM XL 8.0 on PPC, with GNU ld
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
- _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
;;
*)
@@ -6506,10 +7047,10 @@ if test "$_lt_caught_CXX_error" != yes; then
*Sun\ C*)
# Sun C++ 5.9
_LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
# Not sure whether something based on
@@ -6567,22 +7108,17 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(ld_shlibs, $1)=yes
;;
- openbsd2*)
- # C++ shared libraries are fairly broken
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- openbsd*)
+ openbsd* | bitrig*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
- _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
fi
output_verbose_link_cmd=func_echo_all
else
@@ -6598,9 +7134,9 @@ if test "$_lt_caught_CXX_error" != yes; then
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
- _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Archives containing C++ object files must be created using
@@ -6618,17 +7154,17 @@ if test "$_lt_caught_CXX_error" != yes; then
cxx*)
case $host in
osf3*)
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
;;
*)
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
- echo "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
- $RM $lib.exp'
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+ $RM $lib.exp'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
;;
esac
@@ -6643,21 +7179,21 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes && test "$with_gnu_ld" = no; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
case $host in
osf3*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
;;
esac
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Commands to make compiler produce verbose output that lists
@@ -6703,9 +7239,9 @@ if test "$_lt_caught_CXX_error" != yes; then
# Sun C++ 4.2, 5.x and Centerline C++
_LT_TAGVAR(archive_cmds_need_lc,$1)=yes
_LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
@@ -6713,7 +7249,7 @@ if test "$_lt_caught_CXX_error" != yes; then
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The compiler driver will combine and reorder linker options,
- # but understands `-z linker_flag'.
+ # but understands '-z linker_flag'.
# Supported since Solaris 2.6 (maybe 2.5.1?)
_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
;;
@@ -6730,30 +7266,30 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
gcx*)
# Green Hills C++ Compiler
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
# The C++ compiler must be used to create the archive.
_LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
;;
*)
# GNU C++ compiler with Solaris linker
- if test "$GXX" = yes && test "$with_gnu_ld" = no; then
- _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
if $CC --version | $GREP -v '^2\.7' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
else
- # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # g++ 2.7 appears to require '-G' NOT '-shared' on this
# platform.
- _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
@@ -6761,11 +7297,11 @@ if test "$_lt_caught_CXX_error" != yes; then
output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
;;
esac
fi
@@ -6774,52 +7310,52 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
sysv5* | sco3.2v5* | sco5v6*)
- # Note: We can NOT use -z defs as we might desire, because we do not
+ # Note: We CANNOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
- _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
- '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
_LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
- '"$_LT_TAGVAR(reload_cmds, $1)"
+ '"$_LT_TAGVAR(reload_cmds, $1)"
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
@@ -6850,10 +7386,10 @@ if test "$_lt_caught_CXX_error" != yes; then
esac
AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
- test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+ test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
- _LT_TAGVAR(GCC, $1)="$GXX"
- _LT_TAGVAR(LD, $1)="$LD"
+ _LT_TAGVAR(GCC, $1)=$GXX
+ _LT_TAGVAR(LD, $1)=$LD
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
@@ -6880,7 +7416,7 @@ if test "$_lt_caught_CXX_error" != yes; then
lt_cv_path_LD=$lt_save_path_LD
lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test "$_lt_caught_CXX_error" != yes
+fi # test yes != "$_lt_caught_CXX_error"
AC_LANG_POP
])# _LT_LANG_CXX_CONFIG
@@ -6902,13 +7438,14 @@ AC_REQUIRE([_LT_DECL_SED])
AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
func_stripname_cnf ()
{
- case ${2} in
- .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
- *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ case @S|@2 in
+ .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+ *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
esac
} # func_stripname_cnf
])# _LT_FUNC_STRIPNAME_CNF
+
# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
# ---------------------------------
# Figure out "hidden" library dependencies from verbose
@@ -6992,13 +7529,13 @@ if AC_TRY_EVAL(ac_compile); then
pre_test_object_deps_done=no
for p in `eval "$output_verbose_link_cmd"`; do
- case ${prev}${p} in
+ case $prev$p in
-L* | -R* | -l*)
# Some compilers place space between "-{L,R}" and the path.
# Remove the space.
- if test $p = "-L" ||
- test $p = "-R"; then
+ if test x-L = "$p" ||
+ test x-R = "$p"; then
prev=$p
continue
fi
@@ -7014,16 +7551,16 @@ if AC_TRY_EVAL(ac_compile); then
case $p in
=*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
esac
- if test "$pre_test_object_deps_done" = no; then
- case ${prev} in
+ if test no = "$pre_test_object_deps_done"; then
+ case $prev in
-L | -R)
# Internal compiler library paths should come after those
# provided the user. The postdeps already come after the
# user supplied libs so there is no need to process them.
if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
- _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
else
- _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
fi
;;
# The "-l" case would never come before the object being
@@ -7031,9 +7568,9 @@ if AC_TRY_EVAL(ac_compile); then
esac
else
if test -z "$_LT_TAGVAR(postdeps, $1)"; then
- _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ _LT_TAGVAR(postdeps, $1)=$prev$p
else
- _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
fi
fi
prev=
@@ -7048,15 +7585,15 @@ if AC_TRY_EVAL(ac_compile); then
continue
fi
- if test "$pre_test_object_deps_done" = no; then
+ if test no = "$pre_test_object_deps_done"; then
if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
- _LT_TAGVAR(predep_objects, $1)="$p"
+ _LT_TAGVAR(predep_objects, $1)=$p
else
_LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
fi
else
if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
- _LT_TAGVAR(postdep_objects, $1)="$p"
+ _LT_TAGVAR(postdep_objects, $1)=$p
else
_LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
fi
@@ -7087,51 +7624,6 @@ interix[[3-9]]*)
_LT_TAGVAR(postdep_objects,$1)=
_LT_TAGVAR(postdeps,$1)=
;;
-
-linux*)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*)
- # Sun C++ 5.9
-
- # The more standards-conforming stlport4 library is
- # incompatible with the Cstd library. Avoid specifying
- # it if it's in CXXFLAGS. Ignore libCrun as
- # -library=stlport4 depends on it.
- case " $CXX $CXXFLAGS " in
- *" -library=stlport4 "*)
- solaris_use_stlport4=yes
- ;;
- esac
-
- if test "$solaris_use_stlport4" != yes; then
- _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
- fi
- ;;
- esac
- ;;
-
-solaris*)
- case $cc_basename in
- CC* | sunCC*)
- # The more standards-conforming stlport4 library is
- # incompatible with the Cstd library. Avoid specifying
- # it if it's in CXXFLAGS. Ignore libCrun as
- # -library=stlport4 depends on it.
- case " $CXX $CXXFLAGS " in
- *" -library=stlport4 "*)
- solaris_use_stlport4=yes
- ;;
- esac
-
- # Adding this requires a known-good setup of shared libraries for
- # Sun compiler versions before 5.6, else PIC objects from an old
- # archive will be linked into the output, leading to subtle bugs.
- if test "$solaris_use_stlport4" != yes; then
- _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
- fi
- ;;
- esac
- ;;
esac
])
@@ -7140,7 +7632,7 @@ case " $_LT_TAGVAR(postdeps, $1) " in
esac
_LT_TAGVAR(compiler_lib_search_dirs, $1)=
if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
fi
_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
[The directories searched by this compiler when creating a shared library])
@@ -7160,10 +7652,10 @@ _LT_TAGDECL([], [compiler_lib_search_path], [1],
# --------------------------
# Ensure that the configuration variables for a Fortran 77 compiler are
# suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_F77_CONFIG],
[AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test "X$F77" = "Xno"; then
+if test -z "$F77" || test no = "$F77"; then
_lt_disable_F77=yes
fi
@@ -7200,7 +7692,7 @@ _LT_TAGVAR(objext, $1)=$objext
# the F77 compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_F77" != yes; then
+if test yes != "$_lt_disable_F77"; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="\
subroutine t
@@ -7222,7 +7714,7 @@ if test "$_lt_disable_F77" != yes; then
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
- lt_save_CC="$CC"
+ lt_save_CC=$CC
lt_save_GCC=$GCC
lt_save_CFLAGS=$CFLAGS
CC=${F77-"f77"}
@@ -7236,21 +7728,25 @@ if test "$_lt_disable_F77" != yes; then
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
- test "$can_build_shared" = "no" && enable_shared=no
+ test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
- test "$enable_shared" = yes && enable_static=no
+ test yes = "$enable_shared" && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
fi
;;
aix[[4-9]]*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
fi
;;
esac
@@ -7258,11 +7754,11 @@ if test "$_lt_disable_F77" != yes; then
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
- test "$enable_shared" = yes || enable_static=yes
+ test yes = "$enable_shared" || enable_static=yes
AC_MSG_RESULT([$enable_static])
- _LT_TAGVAR(GCC, $1)="$G77"
- _LT_TAGVAR(LD, $1)="$LD"
+ _LT_TAGVAR(GCC, $1)=$G77
+ _LT_TAGVAR(LD, $1)=$LD
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
@@ -7279,9 +7775,9 @@ if test "$_lt_disable_F77" != yes; then
fi # test -n "$compiler"
GCC=$lt_save_GCC
- CC="$lt_save_CC"
- CFLAGS="$lt_save_CFLAGS"
-fi # test "$_lt_disable_F77" != yes
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
AC_LANG_POP
])# _LT_LANG_F77_CONFIG
@@ -7291,11 +7787,11 @@ AC_LANG_POP
# -------------------------
# Ensure that the configuration variables for a Fortran compiler are
# suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_FC_CONFIG],
[AC_LANG_PUSH(Fortran)
-if test -z "$FC" || test "X$FC" = "Xno"; then
+if test -z "$FC" || test no = "$FC"; then
_lt_disable_FC=yes
fi
@@ -7332,7 +7828,7 @@ _LT_TAGVAR(objext, $1)=$objext
# the FC compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_FC" != yes; then
+if test yes != "$_lt_disable_FC"; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="\
subroutine t
@@ -7354,7 +7850,7 @@ if test "$_lt_disable_FC" != yes; then
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
- lt_save_CC="$CC"
+ lt_save_CC=$CC
lt_save_GCC=$GCC
lt_save_CFLAGS=$CFLAGS
CC=${FC-"f95"}
@@ -7370,21 +7866,25 @@ if test "$_lt_disable_FC" != yes; then
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
- test "$can_build_shared" = "no" && enable_shared=no
+ test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
- test "$enable_shared" = yes && enable_static=no
+ test yes = "$enable_shared" && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
fi
;;
aix[[4-9]]*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
fi
;;
esac
@@ -7392,11 +7892,11 @@ if test "$_lt_disable_FC" != yes; then
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
- test "$enable_shared" = yes || enable_static=yes
+ test yes = "$enable_shared" || enable_static=yes
AC_MSG_RESULT([$enable_static])
- _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
- _LT_TAGVAR(LD, $1)="$LD"
+ _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+ _LT_TAGVAR(LD, $1)=$LD
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
@@ -7416,7 +7916,7 @@ if test "$_lt_disable_FC" != yes; then
GCC=$lt_save_GCC
CC=$lt_save_CC
CFLAGS=$lt_save_CFLAGS
-fi # test "$_lt_disable_FC" != yes
+fi # test yes != "$_lt_disable_FC"
AC_LANG_POP
])# _LT_LANG_FC_CONFIG
@@ -7426,7 +7926,7 @@ AC_LANG_POP
# --------------------------
# Ensure that the configuration variables for the GNU Java Compiler compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_GCJ_CONFIG],
[AC_REQUIRE([LT_PROG_GCJ])dnl
AC_LANG_SAVE
@@ -7460,7 +7960,7 @@ CC=${GCJ-"gcj"}
CFLAGS=$GCJFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
+_LT_TAGVAR(LD, $1)=$LD
_LT_CC_BASENAME([$compiler])
# GCJ did not exist at the time GCC didn't implicitly link libc in.
@@ -7497,7 +7997,7 @@ CFLAGS=$lt_save_CFLAGS
# --------------------------
# Ensure that the configuration variables for the GNU Go compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_GO_CONFIG],
[AC_REQUIRE([LT_PROG_GO])dnl
AC_LANG_SAVE
@@ -7531,7 +8031,7 @@ CC=${GOC-"gccgo"}
CFLAGS=$GOFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
+_LT_TAGVAR(LD, $1)=$LD
_LT_CC_BASENAME([$compiler])
# Go did not exist at the time GCC didn't implicitly link libc in.
@@ -7568,7 +8068,7 @@ CFLAGS=$lt_save_CFLAGS
# -------------------------
# Ensure that the configuration variables for the Windows resource compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_RC_CONFIG],
[AC_REQUIRE([LT_PROG_RC])dnl
AC_LANG_SAVE
@@ -7584,7 +8084,7 @@ _LT_TAGVAR(objext, $1)=$objext
lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
# Code to be used in simple link tests
-lt_simple_link_test_code="$lt_simple_compile_test_code"
+lt_simple_link_test_code=$lt_simple_compile_test_code
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
@@ -7594,7 +8094,7 @@ _LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
-lt_save_CC="$CC"
+lt_save_CC=$CC
lt_save_CFLAGS=$CFLAGS
lt_save_GCC=$GCC
GCC=
@@ -7623,7 +8123,7 @@ AC_DEFUN([LT_PROG_GCJ],
[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
[m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
[AC_CHECK_TOOL(GCJ, gcj,)
- test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
AC_SUBST(GCJFLAGS)])])[]dnl
])
@@ -7734,7 +8234,7 @@ lt_ac_count=0
# Add /usr/xpg4/bin/sed as it is typically found on Solaris
# along with /bin/sed that truncates output.
for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
- test ! -f $lt_ac_sed && continue
+ test ! -f "$lt_ac_sed" && continue
cat /dev/null > conftest.in
lt_ac_count=0
echo $ECHO_N "0123456789$ECHO_C" >conftest.in
@@ -7751,9 +8251,9 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
$lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
cmp -s conftest.out conftest.nl || break
# 10000 chars as input seems more than enough
- test $lt_ac_count -gt 10 && break
+ test 10 -lt "$lt_ac_count" && break
lt_ac_count=`expr $lt_ac_count + 1`
- if test $lt_ac_count -gt $lt_ac_max; then
+ if test "$lt_ac_count" -gt "$lt_ac_max"; then
lt_ac_max=$lt_ac_count
lt_cv_path_SED=$lt_ac_sed
fi
@@ -7777,27 +8277,7 @@ dnl AC_DEFUN([LT_AC_PROG_SED], [])
# Find out whether the shell is Bourne or XSI compatible,
# or has some other useful features.
m4_defun([_LT_CHECK_SHELL_FEATURES],
-[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
-# Try some XSI features
-xsi_shell=no
-( _lt_dummy="a/b/c"
- test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
- = c,a/b,b/c, \
- && eval 'test $(( 1 + 1 )) -eq 2 \
- && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
- && xsi_shell=yes
-AC_MSG_RESULT([$xsi_shell])
-_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
-
-AC_MSG_CHECKING([whether the shell understands "+="])
-lt_shell_append=no
-( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
- >/dev/null 2>&1 \
- && lt_shell_append=yes
-AC_MSG_RESULT([$lt_shell_append])
-_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
lt_unset=unset
else
lt_unset=false
@@ -7821,102 +8301,9 @@ _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
])# _LT_CHECK_SHELL_FEATURES
-# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
-# ------------------------------------------------------
-# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
-# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
-m4_defun([_LT_PROG_FUNCTION_REPLACE],
-[dnl {
-sed -e '/^$1 ()$/,/^} # $1 /c\
-$1 ()\
-{\
-m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1])
-} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-])
-
-
-# _LT_PROG_REPLACE_SHELLFNS
-# -------------------------
-# Replace existing portable implementations of several shell functions with
-# equivalent extended shell implementations where those features are available..
-m4_defun([_LT_PROG_REPLACE_SHELLFNS],
-[if test x"$xsi_shell" = xyes; then
- _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
- case ${1} in
- */*) func_dirname_result="${1%/*}${2}" ;;
- * ) func_dirname_result="${3}" ;;
- esac])
-
- _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
- func_basename_result="${1##*/}"])
-
- _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
- case ${1} in
- */*) func_dirname_result="${1%/*}${2}" ;;
- * ) func_dirname_result="${3}" ;;
- esac
- func_basename_result="${1##*/}"])
-
- _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
- # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
- # positional parameters, so assign one to ordinary parameter first.
- func_stripname_result=${3}
- func_stripname_result=${func_stripname_result#"${1}"}
- func_stripname_result=${func_stripname_result%"${2}"}])
-
- _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
- func_split_long_opt_name=${1%%=*}
- func_split_long_opt_arg=${1#*=}])
-
- _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
- func_split_short_opt_arg=${1#??}
- func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
-
- _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
- case ${1} in
- *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
- *) func_lo2o_result=${1} ;;
- esac])
-
- _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo])
-
- _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))])
-
- _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}])
-fi
-
-if test x"$lt_shell_append" = xyes; then
- _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"])
-
- _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
- func_quote_for_eval "${2}"
-dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
- eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
-
- # Save a `func_append' function call where possible by direct use of '+='
- sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
- test 0 -eq $? || _lt_function_replace_fail=:
-else
- # Save a `func_append' function call even when '+=' is not available
- sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
- test 0 -eq $? || _lt_function_replace_fail=:
-fi
-
-if test x"$_lt_function_replace_fail" = x":"; then
- AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
-fi
-])
-
# _LT_PATH_CONVERSION_FUNCTIONS
# -----------------------------
-# Determine which file name conversion functions should be used by
+# Determine what file name conversion functions should be used by
# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
# for certain cross-compile configurations and native mingw.
m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
diff --git a/contrib/libxo/m4/ltoptions.m4 b/contrib/libxo/m4/ltoptions.m4
index 5d9acd8..94b0829 100644
--- a/contrib/libxo/m4/ltoptions.m4
+++ b/contrib/libxo/m4/ltoptions.m4
@@ -1,14 +1,14 @@
# Helper functions for option handling. -*- Autoconf -*-
#
-# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
-# Inc.
+# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# 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.
-# serial 7 ltoptions.m4
+# serial 8 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
@@ -29,7 +29,7 @@ m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
- [m4_warning([Unknown $1 option `$2'])])[]dnl
+ [m4_warning([Unknown $1 option '$2'])])[]dnl
])
@@ -75,13 +75,15 @@ m4_if([$1],[LT_INIT],[
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
- dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
- [_LT_ENABLE_FAST_INSTALL])
+ [_LT_ENABLE_FAST_INSTALL])
+ _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+ [_LT_WITH_AIX_SONAME([aix])])
])
])# _LT_SET_OPTIONS
@@ -112,7 +114,7 @@ AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `dlopen' option into LT_INIT's first parameter.])
+put the 'dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
@@ -148,7 +150,7 @@ AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `win32-dll' option into LT_INIT's first parameter.])
+put the 'win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
@@ -157,9 +159,9 @@ dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
-# implement the --enable-shared flag, and supports the `shared' and
-# `disable-shared' LT_INIT options.
-# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
@@ -172,14 +174,14 @@ AC_ARG_ENABLE([shared],
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
@@ -211,9 +213,9 @@ dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
-# implement the --enable-static flag, and support the `static' and
-# `disable-static' LT_INIT options.
-# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
@@ -226,14 +228,14 @@ AC_ARG_ENABLE([static],
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
@@ -265,9 +267,9 @@ dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
-# implement the --enable-fast-install flag, and support the `fast-install'
-# and `disable-fast-install' LT_INIT options.
-# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
@@ -280,14 +282,14 @@ AC_ARG_ENABLE([fast-install],
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
@@ -304,14 +306,14 @@ AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `fast-install' option into LT_INIT's first parameter.])
+the 'fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `disable-fast-install' option into LT_INIT's first parameter.])
+the 'disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
@@ -319,11 +321,64 @@ dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+ AC_MSG_CHECKING([which variant of shared library versioning to provide])
+ AC_ARG_WITH([aix-soname],
+ [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+ [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+ [case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname],
+ [AC_CACHE_VAL([lt_cv_with_aix_soname],
+ [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+ with_aix_soname=$lt_cv_with_aix_soname])
+ AC_MSG_RESULT([$with_aix_soname])
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+ [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
# _LT_WITH_PIC([MODE])
# --------------------
-# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
# LT_INIT options.
-# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
@@ -334,19 +389,17 @@ m4_define([_LT_WITH_PIC],
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
- [pic_mode=default])
-
-test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+ [pic_mode=m4_default([$1], [default])])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
@@ -359,7 +412,7 @@ AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `pic-only' option into LT_INIT's first parameter.])
+put the 'pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
diff --git a/contrib/libxo/m4/ltversion.m4 b/contrib/libxo/m4/ltversion.m4
index 07a8602..fa04b52 100644
--- a/contrib/libxo/m4/ltversion.m4
+++ b/contrib/libxo/m4/ltversion.m4
@@ -1,6 +1,6 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
-# Copyright (C) 2004 Free Software Foundation, Inc.
+# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
@@ -9,15 +9,15 @@
# @configure_input@
-# serial 3337 ltversion.m4
+# serial 4179 ltversion.m4
# This file is part of GNU Libtool
-m4_define([LT_PACKAGE_VERSION], [2.4.2])
-m4_define([LT_PACKAGE_REVISION], [1.3337])
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.2'
-macro_revision='1.3337'
+[macro_version='2.4.6'
+macro_revision='2.4.6'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])
diff --git a/contrib/libxo/tests/core/Makefile.am b/contrib/libxo/tests/core/Makefile.am
index f145d18..92f5f36 100644
--- a/contrib/libxo/tests/core/Makefile.am
+++ b/contrib/libxo/tests/core/Makefile.am
@@ -20,7 +20,8 @@ test_05.c \
test_06.c \
test_07.c \
test_08.c \
-test_09.c
+test_09.c \
+test_10.c
test_01_test_SOURCES = test_01.c
test_02_test_SOURCES = test_02.c
@@ -31,6 +32,7 @@ test_06_test_SOURCES = test_06.c
test_07_test_SOURCES = test_07.c
test_08_test_SOURCES = test_08.c
test_09_test_SOURCES = test_09.c
+test_10_test_SOURCES = test_10.c
# TEST_CASES := $(shell cd ${srcdir} ; echo *.c )
diff --git a/contrib/libxo/tests/core/saved/test_01.JP.out b/contrib/libxo/tests/core/saved/test_01.JP.out
index e1fd231..4790065 100644
--- a/contrib/libxo/tests/core/saved/test_01.JP.out
+++ b/contrib/libxo/tests/core/saved/test_01.JP.out
@@ -91,7 +91,11 @@
},
"data": {
"item": [
- "gum", "rope", "ladder", "bolt", "water"
+ "gum",
+ "rope",
+ "ladder",
+ "bolt",
+ "water"
]
},
"cost": 425,
diff --git a/contrib/libxo/tests/core/saved/test_02.JP.out b/contrib/libxo/tests/core/saved/test_02.JP.out
index 21b168b..ade2dc2 100644
--- a/contrib/libxo/tests/core/saved/test_02.JP.out
+++ b/contrib/libxo/tests/core/saved/test_02.JP.out
@@ -26,7 +26,9 @@
"cur": 20,
"max": 125,
"flag": [
- "one", "two", "three"
+ "one",
+ "two",
+ "three"
],
"empty-tag": true,
"t1": "1000",
diff --git a/contrib/libxo/tests/core/saved/test_05.H.out b/contrib/libxo/tests/core/saved/test_05.H.out
index b75d728..136b956 100644
--- a/contrib/libxo/tests/core/saved/test_05.H.out
+++ b/contrib/libxo/tests/core/saved/test_05.H.out
@@ -1 +1 @@
-<div class="line"><div class="text">Οὐχὶ ταὐτὰ παρίσταταί μοι </div><div class="data" data-tag="v1">γιγνώσκειν</div><div class="text">, </div><div class="data" data-tag="v2">ὦ ἄνδρες ᾿Αθηναῖοι</div></div><div class="line"><div class="text">გთხოვთ </div><div class="data" data-tag="v1">ახლავე გაიაროთ რეგისტრაცია</div><div class="text"> </div><div class="data" data-tag="v2">Unicode-ის მეათე საერთაშორისო</div></div><div class="line"><div class="title">First Name </div><div class="title">Last Name </div><div class="title">Department </div><div class="title">Time (%)</div></div><div class="line"><div class="data" data-tag="first-name">Jim</div><div class="text"> (</div><div class="data" data-tag="nic-name">"რეგტ"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">გთხოვთ ახ </div><div class="data" data-tag="department"> 431</div><div class="data" data-tag="percent-time"> 90</div></div><div class="line"><div class="data" data-tag="first-name">Terry</div><div class="text"> (</div><div class="data" data-tag="nic-name">"&lt;one"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">Οὐχὶ ταὐτὰ παρ</div><div class="data" data-tag="department"> 660</div><div class="data" data-tag="percent-time"> 90</div></div><div class="line"><div class="data" data-tag="first-name">Leslie</div><div class="text"> (</div><div class="data" data-tag="nic-name">"Les"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">Patterson </div><div class="data" data-tag="department"> 341</div><div class="data" data-tag="percent-time"> 60</div></div><div class="line"><div class="data" data-tag="first-name">Ashley</div><div class="text"> (</div><div class="data" data-tag="nic-name">"Ash"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">Meter &amp; Smith </div><div class="data" data-tag="department"> 1440</div><div class="data" data-tag="percent-time"> 40</div></div><div class="line"><div class="data" data-tag="first-name">0123456789</div><div class="text"> (</div><div class="data" data-tag="nic-name">"0123456789"</div><div class="text">)</div><div class="data" data-tag="last-name">01234567890123</div><div class="data" data-tag="department"> 1440</div><div class="data" data-tag="percent-time"> 40</div></div><div class="line"><div class="data" data-tag="first-name">ახლა</div><div class="text"> (</div><div class="data" data-tag="nic-name">"გაიარო"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">საერთაშორისო </div><div class="data" data-tag="department"> 123</div><div class="data" data-tag="percent-time"> 90</div></div> \ No newline at end of file
+<div class="line"><div class="text">Οὐχὶ ταὐτὰ παρίσταταί μοι </div><div class="data" data-tag="v1">γιγνώσκειν</div><div class="text">, </div><div class="data" data-tag="v2">ὦ ἄνδρες ᾿Αθηναῖοι</div></div><div class="line"><div class="text">გთხოვთ </div><div class="data" data-tag="v1">ახლავე გაიაროთ რეგისტრაცია</div><div class="text"> </div><div class="data" data-tag="v2">Unicode-ის მეათე საერთაშორისო</div></div><div class="line"><div class="title">Width</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="width">63</div></div><div class="line"><div class="text">[</div><div class="data" data-tag="sinhala">෴ණ්ණ෴</div><div class="text">]</div></div><div class="line"><div class="title">Width</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="width">7</div></div><div class="line"><div class="text">[</div><div class="data" data-tag="sinhala">෴</div><div class="text">]</div></div><div class="line"><div class="title">Width</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="width">3</div></div><div class="line"><div class="text">[</div><div class="data" data-tag="sinhala">෴ණ්ණ</div><div class="text">]</div></div><div class="line"><div class="text">[</div><div class="data" data-tag="not-sinhala">1234</div><div class="text">]</div></div><div class="line"><div class="text">[</div><div class="data" data-tag="tag">ර්‍ඝ</div><div class="text">]</div></div><div class="line"><div class="title">Width</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="width">5</div></div><div class="line"><div class="title">First Name </div><div class="title">Last Name </div><div class="title">Department </div><div class="title">Time (%)</div></div><div class="line"><div class="data" data-tag="first-name">Jim</div><div class="text"> (</div><div class="data" data-tag="nic-name">"რეგტ"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">გთხოვთ ახ </div><div class="data" data-tag="department"> 431</div><div class="data" data-tag="percent-time"> 90</div></div><div class="line"><div class="data" data-tag="first-name">Terry</div><div class="text"> (</div><div class="data" data-tag="nic-name">"&lt;one"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">Οὐχὶ ταὐτὰ παρ</div><div class="data" data-tag="department"> 660</div><div class="data" data-tag="percent-time"> 90</div></div><div class="line"><div class="data" data-tag="first-name">Leslie</div><div class="text"> (</div><div class="data" data-tag="nic-name">"Les"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">Patterson </div><div class="data" data-tag="department"> 341</div><div class="data" data-tag="percent-time"> 60</div></div><div class="line"><div class="data" data-tag="first-name">Ashley</div><div class="text"> (</div><div class="data" data-tag="nic-name">"Ash"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">Meter &amp; Smith </div><div class="data" data-tag="department"> 1440</div><div class="data" data-tag="percent-time"> 40</div></div><div class="line"><div class="data" data-tag="first-name">0123456789</div><div class="text"> (</div><div class="data" data-tag="nic-name">"0123456789"</div><div class="text">)</div><div class="data" data-tag="last-name">01234567890123</div><div class="data" data-tag="department"> 1440</div><div class="data" data-tag="percent-time"> 40</div></div><div class="line"><div class="data" data-tag="first-name">ახლა</div><div class="text"> (</div><div class="data" data-tag="nic-name">"გაიარო"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">საერთაშორისო </div><div class="data" data-tag="department"> 123</div><div class="data" data-tag="percent-time"> 90</div></div><div class="line"><div class="data" data-tag="first-name">෴ණ්ණ෴෴ණ්ණ෴</div><div class="text"> (</div><div class="data" data-tag="nic-name">"Mick"</div><div class="text">)</div><div class="padding"> </div><div class="data" data-tag="last-name">෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ</div><div class="data" data-tag="department"> 110</div><div class="data" data-tag="percent-time"> 20</div></div> \ No newline at end of file
diff --git a/contrib/libxo/tests/core/saved/test_05.HIPx.out b/contrib/libxo/tests/core/saved/test_05.HIPx.out
index 2054de1..105f848 100644
--- a/contrib/libxo/tests/core/saved/test_05.HIPx.out
+++ b/contrib/libxo/tests/core/saved/test_05.HIPx.out
@@ -11,6 +11,55 @@
<div class="data" data-tag="v2" data-xpath="/employees/v2">Unicode-ის მეათე საერთაშორისო</div>
</div>
<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width" data-xpath="/employees/width">63</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="sinhala" data-xpath="/employees/sinhala">෴ණ්ණ෴</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width" data-xpath="/employees/width">7</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="sinhala" data-xpath="/employees/sinhala">෴</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width" data-xpath="/employees/width">3</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="sinhala" data-xpath="/employees/sinhala">෴ණ්ණ</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="not-sinhala" data-xpath="/employees/not-sinhala">1234</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="tag" data-xpath="/employees/tag">ර්‍ඝ</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width" data-xpath="/employees/width">5</div>
+</div>
+<div class="line">
<div class="title">First Name </div>
<div class="title">Last Name </div>
<div class="title">Department </div>
@@ -75,3 +124,13 @@
<div class="data" data-tag="department" data-xpath="/employees/employee/department"> 123</div>
<div class="data" data-tag="percent-time" data-xpath="/employees/employee/percent-time" data-type="number" data-help="Percentage of full &amp; part time (%)"> 90</div>
</div>
+<div class="line">
+ <div class="data" data-tag="first-name" data-xpath="/employees/employee/first-name" data-type="string" data-help="First name of employee">෴ණ්ණ෴෴ණ්ණ෴</div>
+ <div class="text"> (</div>
+ <div class="data" data-tag="nic-name" data-xpath="/employees/employee/nic-name">"Mick"</div>
+ <div class="text">)</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="last-name" data-xpath="/employees/employee/last-name" data-type="string" data-help="Last name of employee">෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ</div>
+ <div class="data" data-tag="department" data-xpath="/employees/employee/department"> 110</div>
+ <div class="data" data-tag="percent-time" data-xpath="/employees/employee/percent-time" data-type="number" data-help="Percentage of full &amp; part time (%)"> 20</div>
+</div>
diff --git a/contrib/libxo/tests/core/saved/test_05.HP.out b/contrib/libxo/tests/core/saved/test_05.HP.out
index 1c34b95..e66cf2b 100644
--- a/contrib/libxo/tests/core/saved/test_05.HP.out
+++ b/contrib/libxo/tests/core/saved/test_05.HP.out
@@ -11,6 +11,55 @@
<div class="data" data-tag="v2">Unicode-ის მეათე საერთაშორისო</div>
</div>
<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width">63</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="sinhala">෴ණ්ණ෴</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width">7</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="sinhala">෴</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width">3</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="sinhala">෴ණ්ණ</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="not-sinhala">1234</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="text">[</div>
+ <div class="data" data-tag="tag">ර්‍ඝ</div>
+ <div class="text">]</div>
+</div>
+<div class="line">
+ <div class="title">Width</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="width">5</div>
+</div>
+<div class="line">
<div class="title">First Name </div>
<div class="title">Last Name </div>
<div class="title">Department </div>
@@ -75,3 +124,13 @@
<div class="data" data-tag="department"> 123</div>
<div class="data" data-tag="percent-time"> 90</div>
</div>
+<div class="line">
+ <div class="data" data-tag="first-name">෴ණ්ණ෴෴ණ්ණ෴</div>
+ <div class="text"> (</div>
+ <div class="data" data-tag="nic-name">"Mick"</div>
+ <div class="text">)</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="last-name">෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ</div>
+ <div class="data" data-tag="department"> 110</div>
+ <div class="data" data-tag="percent-time"> 20</div>
+</div>
diff --git a/contrib/libxo/tests/core/saved/test_05.J.out b/contrib/libxo/tests/core/saved/test_05.J.out
index 5155489..25d13ea 100644
--- a/contrib/libxo/tests/core/saved/test_05.J.out
+++ b/contrib/libxo/tests/core/saved/test_05.J.out
@@ -1,2 +1,2 @@
-{"employees": {"v1":"γιγνώσκειν","v2":"ὦ ἄνδρες ᾿Αθηναῖοι","v1":"ახლავე გაიაროთ რეგისტრაცია","v2":"Unicode-ის მეათე საერთაშორისო", "employee": [{"first-name":"Jim","nic-name":"\"რეგტ\"","last-name":"გთხოვთ ახ","department":431,"percent-time":90,"benefits":"full"}, {"first-name":"Terry","nic-name":"\"<one\"","last-name":"Οὐχὶ ταὐτὰ παρίσταταί μοι Jones","department":660,"percent-time":90,"benefits":"full"}, {"first-name":"Leslie","nic-name":"\"Les\"","last-name":"Patterson","department":341,"percent-time":60,"benefits":"full"}, {"first-name":"Ashley","nic-name":"\"Ash\"","last-name":"Meter & Smith","department":1440,"percent-time":40}, {"first-name":"0123456789","nic-name":"\"0123456789\"","last-name":"012345678901234567890","department":1440,"percent-time":40}, {"first-name":"ახლა","nic-name":"\"გაიარო\"","last-name":"საერთაშორისო","department":123,"percent-time":90,"benefits":"full"}]}
+{"employees": {"v1":"γιγνώσκειν","v2":"ὦ ἄνδρες ᾿Αθηναῖοι","v1":"ახლავე გაიაროთ რეგისტრაცია","v2":"Unicode-ის მეათე საერთაშორისო","width":55,"sinhala":"෴ණ්ණ෴","width":5,"sinhala":"෴","width":1,"sinhala":"෴ණ්ණ෴෴ණ්ණ෴","not-sinhala":"123456","tag":"ර්‍ඝ","width":3, "employee": [{"first-name":"Jim","nic-name":"\"რეგტ\"","last-name":"გთხოვთ ახ","department":431,"percent-time":90,"benefits":"full"}, {"first-name":"Terry","nic-name":"\"<one\"","last-name":"Οὐχὶ ταὐτὰ παρίσταταί μοι Jones","department":660,"percent-time":90,"benefits":"full"}, {"first-name":"Leslie","nic-name":"\"Les\"","last-name":"Patterson","department":341,"percent-time":60,"benefits":"full"}, {"first-name":"Ashley","nic-name":"\"Ash\"","last-name":"Meter & Smith","department":1440,"percent-time":40}, {"first-name":"0123456789","nic-name":"\"0123456789\"","last-name":"012345678901234567890","department":1440,"percent-time":40}, {"first-name":"ახლა","nic-name":"\"გაიარო\"","last-name":"საერთაშორისო","department":123,"percent-time":90,"benefits":"full"}, {"first-name":"෴ණ්ණ෴෴ණ්ණ෴","nic-name":"\"Mick\"","last-name":"෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ෴෴෴","department":110,"percent-time":20}]}
}
diff --git a/contrib/libxo/tests/core/saved/test_05.JP.out b/contrib/libxo/tests/core/saved/test_05.JP.out
index 7d77d70..c321917 100644
--- a/contrib/libxo/tests/core/saved/test_05.JP.out
+++ b/contrib/libxo/tests/core/saved/test_05.JP.out
@@ -4,6 +4,15 @@
"v2": "ὦ ἄνδρες ᾿Αθηναῖοι",
"v1": "ახლავე გაიაროთ რეგისტრაცია",
"v2": "Unicode-ის მეათე საერთაშორისო",
+ "width": 55,
+ "sinhala": "෴ණ්ණ෴",
+ "width": 5,
+ "sinhala": "෴",
+ "width": 1,
+ "sinhala": "෴ණ්ණ෴෴ණ්ණ෴",
+ "not-sinhala": "123456",
+ "tag": "ර්‍ඝ",
+ "width": 3,
"employee": [
{
"first-name": "Jim",
@@ -50,6 +59,13 @@
"department": 123,
"percent-time": 90,
"benefits": "full"
+ },
+ {
+ "first-name": "෴ණ්ණ෴෴ණ්ණ෴",
+ "nic-name": "\"Mick\"",
+ "last-name": "෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ෴෴෴",
+ "department": 110,
+ "percent-time": 20
}
]
}
diff --git a/contrib/libxo/tests/core/saved/test_05.T.out b/contrib/libxo/tests/core/saved/test_05.T.out
index c709f6c..db713a6 100644
--- a/contrib/libxo/tests/core/saved/test_05.T.out
+++ b/contrib/libxo/tests/core/saved/test_05.T.out
@@ -1,5 +1,14 @@
Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι
გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო
+Width: 63
+[෴ණ්ණ෴]
+Width: 7
+[෴]
+Width: 3
+[෴ණ්ණ]
+[1234]
+[ර්‍ඝ]
+Width: 5
First Name Last Name Department Time (%)
Jim ("რეგტ") გთხოვთ ახ 431 90
Terry ("<one") Οὐχὶ ταὐτὰ παρ 660 90
@@ -7,3 +16,4 @@ Leslie ("Les") Patterson 341 60
Ashley ("Ash") Meter & Smith 1440 40
0123456789 ("0123456789")01234567890123 1440 40
ახლა ("გაიარო") საერთაშორისო 123 90
+෴ණ්ණ෴෴ණ්ණ෴ ("Mick") ෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ 110 20
diff --git a/contrib/libxo/tests/core/saved/test_05.X.out b/contrib/libxo/tests/core/saved/test_05.X.out
index 85ecbbc..7cd2926 100644
--- a/contrib/libxo/tests/core/saved/test_05.X.out
+++ b/contrib/libxo/tests/core/saved/test_05.X.out
@@ -1 +1 @@
-<employees><v1>γιγνώσκειν</v1><v2>ὦ ἄνδρες ᾿Αθηναῖοι</v2><v1>ახლავე გაიაროთ რეგისტრაცია</v1><v2>Unicode-ის მეათე საერთაშორისო</v2><employee><first-name>Jim</first-name><nic-name>"რეგტ"</nic-name><last-name>გთხოვთ ახ</last-name><department>431</department><percent-time>90</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee><employee><first-name>Terry</first-name><nic-name>"&lt;one"</nic-name><last-name>Οὐχὶ ταὐτὰ παρίσταταί μοι Jones</last-name><department>660</department><percent-time>90</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee><employee><first-name>Leslie</first-name><nic-name>"Les"</nic-name><last-name>Patterson</last-name><department>341</department><percent-time>60</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee><employee><first-name>Ashley</first-name><nic-name>"Ash"</nic-name><last-name>Meter &amp; Smith</last-name><department>1440</department><percent-time>40</percent-time></employee><employee><first-name>0123456789</first-name><nic-name>"0123456789"</nic-name><last-name>012345678901234567890</last-name><department>1440</department><percent-time>40</percent-time></employee><employee><first-name>ახლა</first-name><nic-name>"გაიარო"</nic-name><last-name>საერთაშორისო</last-name><department>123</department><percent-time>90</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee></employees> \ No newline at end of file
+<employees><v1>γιγνώσκειν</v1><v2>ὦ ἄνδρες ᾿Αθηναῖοι</v2><v1>ახლავე გაიაროთ რეგისტრაცია</v1><v2>Unicode-ის მეათე საერთაშორისო</v2><width>55</width><sinhala>෴ණ්ණ෴</sinhala><width>5</width><sinhala>෴</sinhala><width>1</width><sinhala>෴ණ්ණ෴෴ණ්ණ෴</sinhala><not-sinhala>123456</not-sinhala><tag>ර්‍ඝ</tag><width>3</width><employee><first-name>Jim</first-name><nic-name>"რეგტ"</nic-name><last-name>გთხოვთ ახ</last-name><department>431</department><percent-time>90</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee><employee><first-name>Terry</first-name><nic-name>"&lt;one"</nic-name><last-name>Οὐχὶ ταὐτὰ παρίσταταί μοι Jones</last-name><department>660</department><percent-time>90</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee><employee><first-name>Leslie</first-name><nic-name>"Les"</nic-name><last-name>Patterson</last-name><department>341</department><percent-time>60</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee><employee><first-name>Ashley</first-name><nic-name>"Ash"</nic-name><last-name>Meter &amp; Smith</last-name><department>1440</department><percent-time>40</percent-time></employee><employee><first-name>0123456789</first-name><nic-name>"0123456789"</nic-name><last-name>012345678901234567890</last-name><department>1440</department><percent-time>40</percent-time></employee><employee><first-name>ახლა</first-name><nic-name>"გაიარო"</nic-name><last-name>საერთაშორისო</last-name><department>123</department><percent-time>90</percent-time><benefits full-time="honest &amp; for true">full</benefits></employee><employee><first-name>෴ණ්ණ෴෴ණ්ණ෴</first-name><nic-name>"Mick"</nic-name><last-name>෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ෴෴෴</last-name><department>110</department><percent-time>20</percent-time></employee></employees> \ No newline at end of file
diff --git a/contrib/libxo/tests/core/saved/test_05.XP.out b/contrib/libxo/tests/core/saved/test_05.XP.out
index 55507eb..6ef573f 100644
--- a/contrib/libxo/tests/core/saved/test_05.XP.out
+++ b/contrib/libxo/tests/core/saved/test_05.XP.out
@@ -3,6 +3,15 @@
<v2>ὦ ἄνδρες ᾿Αθηναῖοι</v2>
<v1>ახლავე გაიაროთ რეგისტრაცია</v1>
<v2>Unicode-ის მეათე საერთაშორისო</v2>
+ <width>55</width>
+ <sinhala>෴ණ්ණ෴</sinhala>
+ <width>5</width>
+ <sinhala>෴</sinhala>
+ <width>1</width>
+ <sinhala>෴ණ්ණ෴෴ණ්ණ෴</sinhala>
+ <not-sinhala>123456</not-sinhala>
+ <tag>ර්‍ඝ</tag>
+ <width>3</width>
<employee>
<first-name>Jim</first-name>
<nic-name>"რეგტ"</nic-name>
@@ -49,4 +58,11 @@
<percent-time>90</percent-time>
<benefits full-time="honest &amp; for true">full</benefits>
</employee>
+ <employee>
+ <first-name>෴ණ්ණ෴෴ණ්ණ෴</first-name>
+ <nic-name>"Mick"</nic-name>
+ <last-name>෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ෴෴෴</last-name>
+ <department>110</department>
+ <percent-time>20</percent-time>
+ </employee>
</employees>
diff --git a/contrib/libxo/tests/core/saved/test_09.JP.out b/contrib/libxo/tests/core/saved/test_09.JP.out
index 8340b27..48e20c1 100644
--- a/contrib/libxo/tests/core/saved/test_09.JP.out
+++ b/contrib/libxo/tests/core/saved/test_09.JP.out
@@ -3,22 +3,34 @@
"data": {
"contents": {
"name": [
- "gum", "rope", "ladder", "bolt", "water"
+ "gum",
+ "rope",
+ "ladder",
+ "bolt",
+ "water"
]
},
"contents": {
"item": [
- "gum", "rope", "ladder", "bolt", "water"
+ "gum",
+ "rope",
+ "ladder",
+ "bolt",
+ "water"
]
},
"contents": {
"item": [
- "gum", "rope", "ladder", "bolt", "water"
+ "gum",
+ "rope",
+ "ladder",
+ "bolt",
+ "water"
],
"total": "six",
"one": "one",
"two": [
- "two"
+ "two"
],
"three": "three"
}
diff --git a/contrib/libxo/tests/core/saved/test_10.H.err b/contrib/libxo/tests/core/saved/test_10.H.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.H.err
diff --git a/contrib/libxo/tests/core/saved/test_10.H.out b/contrib/libxo/tests/core/saved/test_10.H.out
new file mode 100644
index 0000000..d4ec07d
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.H.out
@@ -0,0 +1 @@
+<div class="line"><div class="title color-fg-blue">blue</div><div class="title color-fg-green color-bg-blue">green</div><div class="title color-fg-red color-bg-green">red</div><div class="title color-fg-yellow color-bg-red">yellow</div><div class="title color-bg-yellow">default</div></div><div class="line"><div class="data effect-bold" data-tag="data">bold</div><div class="text effect-bold"> </div><div class="data effect-bold effect-underline" data-tag="data">bold-ul</div><div class="text effect-bold effect-underline"> </div><div class="data effect-bold effect-underline effect-inverse color-fg-inverse color-bg-inverse" data-tag="data">triple</div><div class="text effect-bold effect-underline effect-inverse color-fg-inverse color-bg-inverse"> </div><div class="data effect-underline effect-inverse color-fg-inverse color-bg-inverse" data-tag="data">inv-ul</div><div class="text effect-underline effect-inverse color-fg-inverse color-bg-inverse"> </div><div class="data effect-underline" data-tag="data">underline</div><div class="text effect-underline"> </div><div class="data" data-tag="data">plain</div></div><div class="line"><div class="title">Item </div><div class="title effect-bold effect-underline"> Total Sold</div><div class="title effect-underline"> In Stock</div><div class="title effect-underline effect-inverse color-fg-inverse color-bg-inverse"> On Order</div><div class="title"> SKU</div></div><div class="line"><div class="data" data-tag="name" data-key="key">gum </div><div class="data" data-tag="sold"> 1412</div><div class="data" data-tag="in-stock"> 54</div><div class="data color-fg-yellow" data-tag="on-order"> 10</div><div class="data" data-tag="sku" data-key="key"> GRO-000-415</div></div><div class="line"><div class="data" data-tag="name" data-key="key">rope </div><div class="data" data-tag="sold"> 85</div><div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock"> 4</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="sku" data-key="key"> HRD-000-212</div></div><div class="line"><div class="data" data-tag="name" data-key="key">ladder </div><div class="data" data-tag="sold"> 0</div><div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock"> 2</div><div class="data" data-tag="on-order"> 1</div><div class="data" data-tag="sku" data-key="key"> HRD-000-517</div></div><div class="line"><div class="data" data-tag="name" data-key="key">bolt </div><div class="data" data-tag="sold"> 4123</div><div class="data" data-tag="in-stock"> 144</div><div class="data color-fg-yellow" data-tag="on-order"> 42</div><div class="data" data-tag="sku" data-key="key"> HRD-000-632</div></div><div class="line"><div class="data" data-tag="name" data-key="key">water </div><div class="data" data-tag="sold"> 17</div><div class="data" data-tag="in-stock"> 14</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="sku" data-key="key"> GRO-000-2331</div></div><div class="line"></div><div class="line"></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">gum</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">1412.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">54</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">10</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-415</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">rope</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">85.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">4</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">2</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-212</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">ladder</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">2</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">1</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-517</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">bolt</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">4123.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">144</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">42</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-632</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">water</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">17.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">14</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">2</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-2331</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">fish</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label effect-bold color-fg-white color-bg-blue">Total sold</div><div class="text effect-bold color-fg-white color-bg-blue">: </div><div class="data effect-bold color-fg-white color-bg-blue" data-tag="sold">1321.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">45</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">1</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-533</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">gum</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">rope</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">ladder</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">bolt</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">water</div></div><div class="line"><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div></div><div class="line"><div class="text">X</div><div class="padding"> </div><div class="text">X</div><div class="label">Cost</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="cost">425</div></div><div class="line"><div class="text">X</div><div class="padding"> </div><div class="text">X</div><div class="label">Cost</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="cost">455</div></div> \ No newline at end of file
diff --git a/contrib/libxo/tests/core/saved/test_10.HIPx.err b/contrib/libxo/tests/core/saved/test_10.HIPx.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.HIPx.err
diff --git a/contrib/libxo/tests/core/saved/test_10.HIPx.out b/contrib/libxo/tests/core/saved/test_10.HIPx.out
new file mode 100644
index 0000000..ef64173
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.HIPx.out
@@ -0,0 +1,316 @@
+<div class="line">
+ <div class="title color-fg-blue">blue</div>
+ <div class="title color-fg-green color-bg-blue">green</div>
+ <div class="title color-fg-red color-bg-green">red</div>
+ <div class="title color-fg-yellow color-bg-red">yellow</div>
+ <div class="title color-bg-yellow">default</div>
+</div>
+<div class="line">
+ <div class="data effect-bold" data-tag="data" data-xpath="/top/data/data">bold</div>
+ <div class="text effect-bold"> </div>
+ <div class="data effect-bold effect-underline" data-tag="data" data-xpath="/top/data/data">bold-ul</div>
+ <div class="text effect-bold effect-underline"> </div>
+ <div class="data effect-bold effect-underline effect-inverse color-fg-inverse color-bg-inverse" data-tag="data" data-xpath="/top/data/data">triple</div>
+ <div class="text effect-bold effect-underline effect-inverse color-fg-inverse color-bg-inverse"> </div>
+ <div class="data effect-underline effect-inverse color-fg-inverse color-bg-inverse" data-tag="data" data-xpath="/top/data/data">inv-ul</div>
+ <div class="text effect-underline effect-inverse color-fg-inverse color-bg-inverse"> </div>
+ <div class="data effect-underline" data-tag="data" data-xpath="/top/data/data">underline</div>
+ <div class="text effect-underline"> </div>
+ <div class="data" data-tag="data" data-xpath="/top/data/data">plain</div>
+</div>
+<div class="line">
+ <div class="title">Item </div>
+ <div class="title effect-bold effect-underline"> Total Sold</div>
+ <div class="title effect-underline"> In Stock</div>
+ <div class="title effect-underline effect-inverse color-fg-inverse color-bg-inverse"> On Order</div>
+ <div class="title"> SKU</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">gum </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/sold" data-type="number" data-help="Number of items sold"> 1412</div>
+ <div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/in-stock" data-type="number" data-help="Number of items in stock"> 54</div>
+ <div class="data color-fg-yellow" data-tag="on-order" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/on-order" data-type="number" data-help="Number of items on order"> 10</div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> GRO-000-415</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">rope </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/sold" data-type="number" data-help="Number of items sold"> 85</div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/in-stock" data-type="number" data-help="Number of items in stock"> 4</div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/on-order" data-type="number" data-help="Number of items on order"> 2</div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> HRD-000-212</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">ladder </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/sold" data-type="number" data-help="Number of items sold"> 0</div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/in-stock" data-type="number" data-help="Number of items in stock"> 2</div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/on-order" data-type="number" data-help="Number of items on order"> 1</div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> HRD-000-517</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">bolt </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/sold" data-type="number" data-help="Number of items sold"> 4123</div>
+ <div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/in-stock" data-type="number" data-help="Number of items in stock"> 144</div>
+ <div class="data color-fg-yellow" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/on-order" data-type="number" data-help="Number of items on order"> 42</div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> HRD-000-632</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">water </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/sold" data-type="number" data-help="Number of items sold"> 17</div>
+ <div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/in-stock" data-type="number" data-help="Number of items in stock"> 14</div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/on-order" data-type="number" data-help="Number of items on order"> 2</div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> GRO-000-2331</div>
+</div>
+<div class="line">
+</div>
+<div class="line">
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">gum</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/sold" data-type="number" data-help="Number of items sold">1412.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/in-stock" data-type="number" data-help="Number of items in stock">54</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/on-order" data-type="number" data-help="Number of items on order">10</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">GRO-000-415</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">rope</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/sold" data-type="number" data-help="Number of items sold">85.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/in-stock" data-type="number" data-help="Number of items in stock">4</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/on-order" data-type="number" data-help="Number of items on order">2</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">HRD-000-212</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">ladder</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/sold" data-type="number" data-help="Number of items sold">0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/in-stock" data-type="number" data-help="Number of items in stock">2</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/on-order" data-type="number" data-help="Number of items on order">1</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">HRD-000-517</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">bolt</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/sold" data-type="number" data-help="Number of items sold">4123.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/in-stock" data-type="number" data-help="Number of items in stock">144</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/on-order" data-type="number" data-help="Number of items on order">42</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">HRD-000-632</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">water</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/sold" data-type="number" data-help="Number of items sold">17.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/in-stock" data-type="number" data-help="Number of items in stock">14</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/on-order" data-type="number" data-help="Number of items on order">2</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">GRO-000-2331</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">fish</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label effect-bold color-fg-white color-bg-blue">Total sold</div>
+ <div class="text effect-bold color-fg-white color-bg-blue">: </div>
+ <div class="data effect-bold color-fg-white color-bg-blue" data-tag="sold" data-xpath="/top/data/item[sku = 'GRO-000-533'][name = 'fish']/sold" data-type="number" data-help="Number of items sold">1321.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'GRO-000-533'][name = 'fish']/in-stock" data-type="number" data-help="Number of items in stock">45</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'GRO-000-533'][name = 'fish']/on-order" data-type="number" data-help="Number of items on order">1</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">GRO-000-533</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item" data-xpath="/top/data/item">gum</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item" data-xpath="/top/data/item">rope</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item" data-xpath="/top/data/item">ladder</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item" data-xpath="/top/data/item">bolt</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item" data-xpath="/top/data/item">water</div>
+</div>
+<div class="line">
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+</div>
+<div class="line">
+ <div class="text">X</div>
+ <div class="padding"> </div>
+ <div class="text">X</div>
+ <div class="label">Cost</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="cost" data-xpath="/top/cost">425</div>
+</div>
+<div class="line">
+ <div class="text">X</div>
+ <div class="padding"> </div>
+ <div class="text">X</div>
+ <div class="label">Cost</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="cost" data-xpath="/top/cost">455</div>
+</div>
diff --git a/contrib/libxo/tests/core/saved/test_10.HP.err b/contrib/libxo/tests/core/saved/test_10.HP.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.HP.err
diff --git a/contrib/libxo/tests/core/saved/test_10.HP.out b/contrib/libxo/tests/core/saved/test_10.HP.out
new file mode 100644
index 0000000..abb1b01
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.HP.out
@@ -0,0 +1,316 @@
+<div class="line">
+ <div class="title color-fg-blue">blue</div>
+ <div class="title color-fg-green color-bg-blue">green</div>
+ <div class="title color-fg-red color-bg-green">red</div>
+ <div class="title color-fg-yellow color-bg-red">yellow</div>
+ <div class="title color-bg-yellow">default</div>
+</div>
+<div class="line">
+ <div class="data effect-bold" data-tag="data">bold</div>
+ <div class="text effect-bold"> </div>
+ <div class="data effect-bold effect-underline" data-tag="data">bold-ul</div>
+ <div class="text effect-bold effect-underline"> </div>
+ <div class="data effect-bold effect-underline effect-inverse color-fg-inverse color-bg-inverse" data-tag="data">triple</div>
+ <div class="text effect-bold effect-underline effect-inverse color-fg-inverse color-bg-inverse"> </div>
+ <div class="data effect-underline effect-inverse color-fg-inverse color-bg-inverse" data-tag="data">inv-ul</div>
+ <div class="text effect-underline effect-inverse color-fg-inverse color-bg-inverse"> </div>
+ <div class="data effect-underline" data-tag="data">underline</div>
+ <div class="text effect-underline"> </div>
+ <div class="data" data-tag="data">plain</div>
+</div>
+<div class="line">
+ <div class="title">Item </div>
+ <div class="title effect-bold effect-underline"> Total Sold</div>
+ <div class="title effect-underline"> In Stock</div>
+ <div class="title effect-underline effect-inverse color-fg-inverse color-bg-inverse"> On Order</div>
+ <div class="title"> SKU</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-key="key">gum </div>
+ <div class="data" data-tag="sold"> 1412</div>
+ <div class="data" data-tag="in-stock"> 54</div>
+ <div class="data color-fg-yellow" data-tag="on-order"> 10</div>
+ <div class="data" data-tag="sku" data-key="key"> GRO-000-415</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-key="key">rope </div>
+ <div class="data" data-tag="sold"> 85</div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock"> 4</div>
+ <div class="data" data-tag="on-order"> 2</div>
+ <div class="data" data-tag="sku" data-key="key"> HRD-000-212</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-key="key">ladder </div>
+ <div class="data" data-tag="sold"> 0</div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock"> 2</div>
+ <div class="data" data-tag="on-order"> 1</div>
+ <div class="data" data-tag="sku" data-key="key"> HRD-000-517</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-key="key">bolt </div>
+ <div class="data" data-tag="sold"> 4123</div>
+ <div class="data" data-tag="in-stock"> 144</div>
+ <div class="data color-fg-yellow" data-tag="on-order"> 42</div>
+ <div class="data" data-tag="sku" data-key="key"> HRD-000-632</div>
+</div>
+<div class="line">
+ <div class="data" data-tag="name" data-key="key">water </div>
+ <div class="data" data-tag="sold"> 17</div>
+ <div class="data" data-tag="in-stock"> 14</div>
+ <div class="data" data-tag="on-order"> 2</div>
+ <div class="data" data-tag="sku" data-key="key"> GRO-000-2331</div>
+</div>
+<div class="line">
+</div>
+<div class="line">
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-key="key">gum</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">1412.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">54</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">10</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-key="key">GRO-000-415</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-key="key">rope</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">85.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">4</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">2</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-key="key">HRD-000-212</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-key="key">ladder</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">2</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">1</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-key="key">HRD-000-517</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-key="key">bolt</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">4123.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">144</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">42</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-key="key">HRD-000-632</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-key="key">water</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">17.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data effect-inverse color-fg-inverse color-bg-inverse" data-tag="in-stock">14</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">2</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-key="key">GRO-000-2331</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name" data-key="key">fish</div>
+ <div class="text">':</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label effect-bold color-fg-white color-bg-blue">Total sold</div>
+ <div class="text effect-bold color-fg-white color-bg-blue">: </div>
+ <div class="data effect-bold color-fg-white color-bg-blue" data-tag="sold">1321.0</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">45</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">1</div>
+</div>
+<div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku" data-key="key">GRO-000-533</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item">gum</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item">rope</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item">ladder</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item">bolt</div>
+</div>
+<div class="line">
+ <div class="label">Item</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="item">water</div>
+</div>
+<div class="line">
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+ <div class="text">X</div>
+</div>
+<div class="line">
+ <div class="text">X</div>
+ <div class="padding"> </div>
+ <div class="text">X</div>
+ <div class="label">Cost</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="cost">425</div>
+</div>
+<div class="line">
+ <div class="text">X</div>
+ <div class="padding"> </div>
+ <div class="text">X</div>
+ <div class="label">Cost</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="cost">455</div>
+</div>
diff --git a/contrib/libxo/tests/core/saved/test_10.J.err b/contrib/libxo/tests/core/saved/test_10.J.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.J.err
diff --git a/contrib/libxo/tests/core/saved/test_10.J.out b/contrib/libxo/tests/core/saved/test_10.J.out
new file mode 100644
index 0000000..5091685
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.J.out
@@ -0,0 +1,2 @@
+{"__version": "3.1.4", "top": {"data": {"item": [],"data":"bold","data":"bold-ul","data":"triple","data":"inv-ul","data":"underline","data":"plain", "item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data": {"item": ["gum","rope","ladder","bolt","water"]},"cost":425,"cost":455}
+}
diff --git a/contrib/libxo/tests/core/saved/test_10.JP.err b/contrib/libxo/tests/core/saved/test_10.JP.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.JP.err
diff --git a/contrib/libxo/tests/core/saved/test_10.JP.out b/contrib/libxo/tests/core/saved/test_10.JP.out
new file mode 100644
index 0000000..0ca3269
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.JP.out
@@ -0,0 +1,113 @@
+{
+ "__version": "3.1.4",
+ "top": {
+ "data": {
+ "item": [
+ ],
+ "data": "bold",
+ "data": "bold-ul",
+ "data": "triple",
+ "data": "inv-ul",
+ "data": "underline",
+ "data": "plain",
+ "item": [
+ {
+ "sku": "GRO-000-415",
+ "name": "gum",
+ "sold": 1412,
+ "in-stock": 54,
+ "on-order": 10
+ },
+ {
+ "sku": "HRD-000-212",
+ "name": "rope",
+ "sold": 85,
+ "in-stock": 4,
+ "on-order": 2
+ },
+ {
+ "sku": "HRD-000-517",
+ "name": "ladder",
+ "sold": 0,
+ "in-stock": 2,
+ "on-order": 1
+ },
+ {
+ "sku": "HRD-000-632",
+ "name": "bolt",
+ "sold": 4123,
+ "in-stock": 144,
+ "on-order": 42
+ },
+ {
+ "sku": "GRO-000-2331",
+ "name": "water",
+ "sold": 17,
+ "in-stock": 14,
+ "on-order": 2
+ }
+ ]
+ },
+ "data": {
+ "item": [
+ {
+ "sku": "GRO-000-415",
+ "name": "gum",
+ "sold": 1412.0,
+ "in-stock": 54,
+ "on-order": 10
+ },
+ {
+ "sku": "HRD-000-212",
+ "name": "rope",
+ "sold": 85.0,
+ "in-stock": 4,
+ "on-order": 2
+ },
+ {
+ "sku": "HRD-000-517",
+ "name": "ladder",
+ "sold": 0,
+ "in-stock": 2,
+ "on-order": 1
+ },
+ {
+ "sku": "HRD-000-632",
+ "name": "bolt",
+ "sold": 4123.0,
+ "in-stock": 144,
+ "on-order": 42
+ },
+ {
+ "sku": "GRO-000-2331",
+ "name": "water",
+ "sold": 17.0,
+ "in-stock": 14,
+ "on-order": 2
+ }
+ ]
+ },
+ "data": {
+ "item": [
+ {
+ "sku": "GRO-000-533",
+ "name": "fish",
+ "sold": 1321.0,
+ "in-stock": 45,
+ "on-order": 1
+ }
+ ]
+ },
+ "data": {
+ "item": [
+ "gum",
+ "rope",
+ "ladder",
+ "bolt",
+ "water"
+ ]
+ },
+ "cost": 425,
+ "cost": 455
+ }
+}
diff --git a/contrib/libxo/tests/core/saved/test_10.T.err b/contrib/libxo/tests/core/saved/test_10.T.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.T.err
diff --git a/contrib/libxo/tests/core/saved/test_10.T.out b/contrib/libxo/tests/core/saved/test_10.T.out
new file mode 100644
index 0000000..21fa81b
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.T.out
@@ -0,0 +1,48 @@
+bluegreenredyellowdefault
+bold bold-ul triple inv-ul underline plain
+Item  Total Sold In Stock On Order SKU
+gum 1412 54 10 GRO-000-415
+rope 85 4 2 HRD-000-212
+ladder 0 2 1 HRD-000-517
+bolt 4123 144 42 HRD-000-632
+water 17 14 2 GRO-000-2331
+
+
+Item 'gum':
+ Total sold: 1412.0
+ In stock: 54
+ On order: 10
+ SKU: GRO-000-415
+Item 'rope':
+ Total sold: 85.0
+ In stock: 4
+ On order: 2
+ SKU: HRD-000-212
+Item 'ladder':
+ Total sold: 0
+ In stock: 2
+ On order: 1
+ SKU: HRD-000-517
+Item 'bolt':
+ Total sold: 4123.0
+ In stock: 144
+ On order: 42
+ SKU: HRD-000-632
+Item 'water':
+ Total sold: 17.0
+ In stock: 14
+ On order: 2
+ SKU: GRO-000-2331
+Item 'fish':
+ Total sold: 1321.0
+ In stock: 45
+ On order: 1
+ SKU: GRO-000-533
+Item: gum
+Item: rope
+Item: ladder
+Item: bolt
+Item: water
+XXXXXXXX
+X XCost: 425
+X XCost: 455
diff --git a/contrib/libxo/tests/core/saved/test_10.X.err b/contrib/libxo/tests/core/saved/test_10.X.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.X.err
diff --git a/contrib/libxo/tests/core/saved/test_10.X.out b/contrib/libxo/tests/core/saved/test_10.X.out
new file mode 100644
index 0000000..49c6dd8
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.X.out
@@ -0,0 +1 @@
+<top __version="3.1.4"><data test="value"><data test2="value2">bold</data><data>bold-ul</data><data>triple</data><data>inv-ul</data><data>underline</data><data>plain</data><item><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><in-stock>14</in-stock><on-order>2</on-order></item></data><data><item><sku key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412.0</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku key="key">HRD-000-212</sku><name key="key">rope</name><sold>85.0</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123.0</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku key="key">GRO-000-2331</sku><name key="key">water</name><sold>17.0</sold><in-stock>14</in-stock><on-order>2</on-order></item></data><data><item><sku key="key">GRO-000-533</sku><name key="key">fish</name><sold>1321.0</sold><in-stock>45</in-stock><on-order>1</on-order></item></data><data><item test4="value4">gum</item><item test4="value4">rope</item><item test4="value4">ladder</item><item test4="value4">bolt</item><item test4="value4">water</item></data><cost>425</cost><cost>455</cost></top> \ No newline at end of file
diff --git a/contrib/libxo/tests/core/saved/test_10.XP.err b/contrib/libxo/tests/core/saved/test_10.XP.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.XP.err
diff --git a/contrib/libxo/tests/core/saved/test_10.XP.out b/contrib/libxo/tests/core/saved/test_10.XP.out
new file mode 100644
index 0000000..33c88d9
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.XP.out
@@ -0,0 +1,100 @@
+<top __version="3.1.4">
+ <data test="value">
+ <data test2="value2">bold</data>
+ <data>bold-ul</data>
+ <data>triple</data>
+ <data>inv-ul</data>
+ <data>underline</data>
+ <data>plain</data>
+ <item>
+ <sku test3="value3" key="key">GRO-000-415</sku>
+ <name key="key">gum</name>
+ <sold>1412</sold>
+ <in-stock>54</in-stock>
+ <on-order>10</on-order>
+ </item>
+ <item>
+ <sku test3="value3" key="key">HRD-000-212</sku>
+ <name key="key">rope</name>
+ <sold>85</sold>
+ <in-stock>4</in-stock>
+ <on-order>2</on-order>
+ </item>
+ <item>
+ <sku test3="value3" key="key">HRD-000-517</sku>
+ <name key="key">ladder</name>
+ <sold>0</sold>
+ <in-stock>2</in-stock>
+ <on-order>1</on-order>
+ </item>
+ <item>
+ <sku test3="value3" key="key">HRD-000-632</sku>
+ <name key="key">bolt</name>
+ <sold>4123</sold>
+ <in-stock>144</in-stock>
+ <on-order>42</on-order>
+ </item>
+ <item>
+ <sku test3="value3" key="key">GRO-000-2331</sku>
+ <name key="key">water</name>
+ <sold>17</sold>
+ <in-stock>14</in-stock>
+ <on-order>2</on-order>
+ </item>
+ </data>
+ <data>
+ <item>
+ <sku key="key">GRO-000-415</sku>
+ <name key="key">gum</name>
+ <sold>1412.0</sold>
+ <in-stock>54</in-stock>
+ <on-order>10</on-order>
+ </item>
+ <item>
+ <sku key="key">HRD-000-212</sku>
+ <name key="key">rope</name>
+ <sold>85.0</sold>
+ <in-stock>4</in-stock>
+ <on-order>2</on-order>
+ </item>
+ <item>
+ <sku key="key">HRD-000-517</sku>
+ <name key="key">ladder</name>
+ <sold>0</sold>
+ <in-stock>2</in-stock>
+ <on-order>1</on-order>
+ </item>
+ <item>
+ <sku key="key">HRD-000-632</sku>
+ <name key="key">bolt</name>
+ <sold>4123.0</sold>
+ <in-stock>144</in-stock>
+ <on-order>42</on-order>
+ </item>
+ <item>
+ <sku key="key">GRO-000-2331</sku>
+ <name key="key">water</name>
+ <sold>17.0</sold>
+ <in-stock>14</in-stock>
+ <on-order>2</on-order>
+ </item>
+ </data>
+ <data>
+ <item>
+ <sku key="key">GRO-000-533</sku>
+ <name key="key">fish</name>
+ <sold>1321.0</sold>
+ <in-stock>45</in-stock>
+ <on-order>1</on-order>
+ </item>
+ </data>
+ <data>
+ <item test4="value4">gum</item>
+ <item test4="value4">rope</item>
+ <item test4="value4">ladder</item>
+ <item test4="value4">bolt</item>
+ <item test4="value4">water</item>
+ </data>
+ <cost>425</cost>
+ <cost>455</cost>
+</top>
diff --git a/contrib/libxo/tests/core/saved/test_10.err b/contrib/libxo/tests/core/saved/test_10.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.err
diff --git a/contrib/libxo/tests/core/saved/test_10.out b/contrib/libxo/tests/core/saved/test_10.out
new file mode 100644
index 0000000..c2ad7a0
--- /dev/null
+++ b/contrib/libxo/tests/core/saved/test_10.out
@@ -0,0 +1,38 @@
+Item Total Sold In Stock On Order SKU
+gum 1412 54 10 GRO-000-415
+rope 85 4 2 HRD-000-212
+ladder 0 2 1 HRD-000-517
+bolt 4123 144 42 HRD-000-632
+water 17 14 2 GRO-000-2331
+
+
+Item 'gum':
+ Total sold: 1412.0
+ In stock: 54
+ On order: 10
+ SKU: GRO-000-415
+Item 'rope':
+ Total sold: 85.0
+ In stock: 4
+ On order: 2
+ SKU: HRD-000-212
+Item 'ladder':
+ Total sold: 0
+ In stock: 2
+ On order: 1
+ SKU: HRD-000-517
+Item 'bolt':
+ Total sold: 4123.0
+ In stock: 144
+ On order: 42
+ SKU: HRD-000-632
+Item 'water':
+ Total sold: 17.0
+ In stock: 14
+ On order: 2
+ SKU: GRO-000-2331
+Item 'fish':
+ Total sold: 1321.0
+ In stock: 45
+ On order: 1
+ SKU: GRO-000-533
diff --git a/contrib/libxo/tests/core/test_05.c b/contrib/libxo/tests/core/test_05.c
index 61241b8..a883a88 100644
--- a/contrib/libxo/tests/core/test_05.c
+++ b/contrib/libxo/tests/core/test_05.c
@@ -39,23 +39,38 @@ main (int argc, char **argv)
{ "Ashley", "Ash", "Meter & Smith", 1440, 40 },
{ "0123456789", "0123456789", "012345678901234567890", 1440, 40 },
{ "ახლა", "გაიარო", "საერთაშორისო", 123, 90 },
+ { "෴ණ්ණ෴෴ණ්ණ෴", "Mick",
+ "෴ණ්ණ෴෴ණ්ණ෴෴ණ්ණ෴෴෴", 110, 20 },
{ NULL, NULL }
}, *ep = employees;
+ int rc;
argc = xo_parse_args(argc, argv);
if (argc < 0)
return 1;
xo_set_info(NULL, info, info_count);
+ xo_set_flags(NULL, XOF_COLUMNS);
xo_open_container("employees");
xo_emit("Οὐχὶ ταὐτὰ παρίσταταί μοι {:v1/%s}, {:v2/%s}\n",
"γιγνώσκειν", "ὦ ἄνδρες ᾿Αθηναῖοι");
- xo_emit("გთხოვთ {:v1/%s} {:v2/%s}\n",
+ rc = xo_emit("გთხოვთ {:v1/%s} {:v2/%s}\n",
"ახლავე გაიაროთ რეგისტრაცია",
"Unicode-ის მეათე საერთაშორისო");
+ xo_emit("{Twc:Width}{:width/%d}\n", rc);
+
+ /* Okay, Sinhala is uber cool ... */
+ rc = xo_emit("[{:sinhala}]\n", "෴ණ්ණ෴");
+ xo_emit("{Twc:Width}{:width/%d}\n", rc);
+ rc = xo_emit("[{:sinhala}]\n", "෴");
+ xo_emit("{Twc:Width}{:width/%d}\n", rc);
+ rc = xo_emit("[{:sinhala/%-4..4s/%s}]\n", "෴ණ්ණ෴෴ණ්ණ෴");
+ xo_emit("[{:not-sinhala/%-4..4s/%s}]\n", "123456");
+ rc = xo_emit("[{:tag/%s}]\n", "ර්‍ඝ");
+ xo_emit("{Twc:Width}{:width/%d}\n", rc);
xo_open_list("employee");
diff --git a/contrib/libxo/tests/core/test_10.c b/contrib/libxo/tests/core/test_10.c
new file mode 100644
index 0000000..223ec55
--- /dev/null
+++ b/contrib/libxo/tests/core/test_10.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2014, Juniper Networks, Inc.
+ * All rights reserved.
+ * This SOFTWARE is licensed under the LICENSE provided in the
+ * ../Copyright file. By downloading, installing, copying, or otherwise
+ * using the SOFTWARE, you agree to be bound by the terms of that
+ * LICENSE.
+ * Phil Shafer, July 2014
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "xo.h"
+
+int
+main (int argc, char **argv)
+{
+ static char base_grocery[] = "GRO";
+ static char base_hardware[] = "HRD";
+ struct item {
+ const char *i_title;
+ int i_sold;
+ int i_instock;
+ int i_onorder;
+ const char *i_sku_base;
+ int i_sku_num;
+ };
+ struct item list[] = {
+ { "gum", 1412, 54, 10, base_grocery, 415 },
+ { "rope", 85, 4, 2, base_hardware, 212 },
+ { "ladder", 0, 2, 1, base_hardware, 517 },
+ { "bolt", 4123, 144, 42, base_hardware, 632 },
+ { "water", 17, 14, 2, base_grocery, 2331 },
+ { NULL, 0, 0, 0, NULL, 0 }
+ };
+ struct item list2[] = {
+ { "fish", 1321, 45, 1, base_grocery, 533 },
+ { NULL, 0, 0, 0, NULL, 0 }
+ };
+ struct item *ip;
+ xo_info_t info[] = {
+ { "in-stock", "number", "Number of items in stock" },
+ { "name", "string", "Name of the item" },
+ { "on-order", "number", "Number of items on order" },
+ { "sku", "string", "Stock Keeping Unit" },
+ { "sold", "number", "Number of items sold" },
+ { NULL, NULL, NULL },
+ };
+ int info_count = (sizeof(info) / sizeof(info[0])) - 1;
+
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ return 1;
+
+ for (argc = 1; argv[argc]; argc++) {
+ if (strcmp(argv[argc], "xml") == 0)
+ xo_set_style(NULL, XO_STYLE_XML);
+ else if (strcmp(argv[argc], "json") == 0)
+ xo_set_style(NULL, XO_STYLE_JSON);
+ else if (strcmp(argv[argc], "text") == 0)
+ xo_set_style(NULL, XO_STYLE_TEXT);
+ else if (strcmp(argv[argc], "html") == 0)
+ xo_set_style(NULL, XO_STYLE_HTML);
+ else if (strcmp(argv[argc], "pretty") == 0)
+ xo_set_flags(NULL, XOF_PRETTY);
+ else if (strcmp(argv[argc], "xpath") == 0)
+ xo_set_flags(NULL, XOF_XPATH);
+ else if (strcmp(argv[argc], "info") == 0)
+ xo_set_flags(NULL, XOF_INFO);
+ else if (strcmp(argv[argc], "error") == 0) {
+ close(-1);
+ xo_err(1, "error detected");
+ }
+ }
+
+ xo_set_info(NULL, info, info_count);
+ xo_set_flags(NULL, XOF_KEYS);
+
+ /* Normally one would use "XOF_COLOR_ALLOWED", but we want to force it */
+ xo_set_flags(NULL, XOF_COLOR);
+
+ xo_set_version("3.1.4");
+
+ xo_open_container_h(NULL, "top");
+
+ xo_attr("test", "value");
+ xo_open_container("data");
+ xo_open_list("item");
+ xo_attr("test2", "value2");
+
+ static const char *colors[] =
+ { "blue", "green", "red", "yellow", "default", NULL };
+
+ int i;
+ for (i = 0; colors[i]; i++) {
+ if (i > 0)
+ xo_emit("{C:/bg-%s}", colors[i-1]);
+ xo_emit("{C:/fg-%s}{T:/%s}", colors[i], colors[i]);
+ }
+ xo_emit("{C:reset}\n");
+
+ xo_emit("{C:bold}{:data} {C:underline}{:data} {C:inverse}{:data} "
+ "{C:no-bold}{:data} {C:no-inverse}{:data} "
+ "{C:no-underline}{:data}\n",
+ "bold", "bold-ul", "triple", "inv-ul", "underline", "plain");
+
+ xo_emit("{T:Item/%-10s}{C:bold,underline}{T:Total Sold/%12s}{C:no-bold}"
+ "{T:In Stock/%12s}{C:/%s}"
+ "{T:On Order/%12s}{C:normal}{T:SKU/%5s}\n", "inverse");
+
+#if 0
+ xo_finish();
+ return 0;
+#endif
+
+ for (ip = list; ip->i_title; ip++) {
+ xo_open_instance("item");
+ xo_attr("test3", "value3");
+
+ xo_emit("{keq:sku/%s-%u/%s-000-%u}"
+ "{k:name/%-10s/%s}{n:sold/%12u/%u}"
+ "{C:/%s}{:in-stock/%12u/%u}{C:normal}"
+ "{C:/fg-%s}{:on-order/%12u/%u}{C:/fg-default}"
+ "{qkd:sku/%5s-000-%u/%s-000-%u}\n",
+ ip->i_sku_base, ip->i_sku_num,
+ ip->i_title, ip->i_sold,
+ (ip->i_instock < 5) ? "inverse" : "normal", ip->i_instock,
+ (ip->i_onorder > 5) ? "yellow" : "default", ip->i_onorder,
+ ip->i_sku_base, ip->i_sku_num);
+
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+ xo_close_container("data");
+
+ xo_emit("\n\n");
+
+ xo_open_container("data");
+ xo_open_list("item");
+
+ for (ip = list; ip->i_title; ip++) {
+ xo_open_instance("item");
+
+ xo_emit("{keq:sku/%s-%u/%s-000-%u}", ip->i_sku_base, ip->i_sku_num);
+ xo_emit("{L:Item} '{k:name/%s}':\n", ip->i_title);
+ xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n",
+ ip->i_sold, ip->i_sold ? ".0" : "");
+ xo_emit("{P: }{Lcw:In stock}{C:inverse}{:in-stock/%u}{C:}\n",
+ ip->i_instock);
+ xo_emit("{P: }{Lcw:On order}{:on-order/%u}\n", ip->i_onorder);
+ xo_emit("{P: }{L:SKU}: {qkd:sku/%s-000-%u}\n",
+ ip->i_sku_base, ip->i_sku_num);
+
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+ xo_close_container("data");
+
+ xo_open_container("data");
+ xo_open_list("item");
+
+ for (ip = list2; ip->i_title; ip++) {
+ xo_open_instance("item");
+
+ xo_emit("{keq:sku/%s-%u/%s-000-%u}", ip->i_sku_base, ip->i_sku_num);
+ xo_emit("{L:Item} '{k:name/%s}':\n", ip->i_title);
+ xo_emit("{P: }{C:bg-blue , fg-white, bold }{L:Total sold}: "
+ "{n:sold/%u%s}{C:}\n",
+ ip->i_sold, ip->i_sold ? ".0" : "");
+ xo_emit("{P: }{Lcw:In stock}{:in-stock/%u}\n", ip->i_instock);
+ xo_emit("{P: }{Lcw:On order}{:on-order/%u}\n", ip->i_onorder);
+ xo_emit("{P: }{L:SKU}: {qkd:sku/%s-000-%u}\n",
+ ip->i_sku_base, ip->i_sku_num);
+
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+ xo_close_container("data");
+
+ xo_open_container("data");
+ xo_open_list("item");
+
+ for (ip = list; ip->i_title; ip++) {
+ xo_attr("test4", "value4");
+ xo_emit("{Lwc:Item}{l:item}\n", ip->i_title);
+ }
+
+ xo_close_list("item");
+ xo_close_container("data");
+
+ xo_emit("X{P:}X", "epic fail");
+ xo_emit("X{T:}X", "epic fail");
+ xo_emit("X{N:}X", "epic fail");
+ xo_emit("X{L:}X\n", "epic fail");
+
+ xo_emit("X{P: }X{Lwc:Cost}{:cost/%u}\n", 425);
+ xo_emit("X{P:/%30s}X{Lwc:Cost}{:cost/%u}\n", "", 455);
+
+ xo_close_container_h(NULL, "top");
+
+ xo_finish();
+
+ return 0;
+}
diff --git a/contrib/libxo/xo/xo.1 b/contrib/libxo/xo/xo.1
index 12fc959..9dcae85 100644
--- a/contrib/libxo/xo/xo.1
+++ b/contrib/libxo/xo/xo.1
@@ -74,7 +74,7 @@ utility accepts a format string suitable for
.Xr xo_emit 3
and a set of zero or more arguments used to supply data for that string.
.Bd -literal -offset indent
- xo "The {k:name} weighs {:weight/%d} pounds.\n" fish 6
+ xo "The {k:name} weighs {:weight/%d} pounds.\\n" fish 6
TEXT:
The fish weighs 6 pounds.
diff --git a/contrib/libxo/xohtml/Makefile.am b/contrib/libxo/xohtml/Makefile.am
new file mode 100644
index 0000000..49dffed
--- /dev/null
+++ b/contrib/libxo/xohtml/Makefile.am
@@ -0,0 +1,38 @@
+#
+# Copyright 2015, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+man_MANS = xohtml.1
+
+EXTERNAL_FILES = \
+ external/jquery.js \
+ external/jquery.qtip.css \
+ external/jquery.qtip.js
+
+INTERNAL_FILES = \
+ xohtml.js \
+ xohtml.css
+
+EXTRA_DIST = \
+ xohtml.1 \
+ xohtml.sh.in \
+ ${INTERNAL_FILES} \
+ ${EXTERNAL_FILES}
+
+install-exec-hook:
+ install xohtml.sh ${DESTDIR}${bindir}/xohtml
+ mkdir -p ${DESTDIR}${XO_SHAREDIR}/external
+ for file in ${INTERNAL_FILES}; do \
+ install ${srcdir}/$$file ${DESTDIR}${XO_SHAREDIR} ; done
+ for file in ${EXTERNAL_FILES}; do \
+ install ${srcdir}/$$file ${DESTDIR}${XO_SHAREDIR}/external ; done
+
+uninstall-hook:
+ for file in ${INTERNAL_FILES} ${EXTERNAL_FILES}; do \
+ rm ${DESTDIR}${XO_SHAREDIR}/$$file ; done
+ rmdir ${DESTDIR}${XO_SHAREDIR}/external
+ rm -f ${DESTDIR}${bindir}/xohtml
diff --git a/contrib/libxo/xohtml/xohtml.1 b/contrib/libxo/xohtml/xohtml.1
new file mode 100644
index 0000000..d520cb3
--- /dev/null
+++ b/contrib/libxo/xohtml/xohtml.1
@@ -0,0 +1,125 @@
+.\" #
+.\" # Copyright (c) 2015, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt XOHTML 1
+.Os
+.Sh NAME
+.Nm xohtml
+.Nd display libxo html output
+.Xr xo_emit 3
+.Sh SYNOPSIS
+.Nm xohtml
+.Op Fl c
+.Op Fl "b <base>"
+.Op Fl "c" <command>"
+.Op Fl "f" <output>
+.Op Ar command argument...
+.Sh DESCRIPTION
+.Nm
+is a tool for preparing
+.Xr libxo 3
+HTML output for display in modern HTML web browsers.
+.Nm
+can operate in two modes.
+If command is provided
+either with the
+.Fl c
+option or as argument(s) to the
+.Nm
+command, that command is executed and the resulting output is processed.
+If no command is given, the
+standard input is used.
+.Pp
+.Nm
+is typically used to wrap
+.Nm libxo
+output with sufficient HTML content to allow display in a web browser.
+This includes parent HTML tags as well as
+.Nm CSS
+stylesheets and
+.Nm Javascript
+files.
+.Pp
+If the command is given directly on the command line,
+.Nm
+will add the "--libxo=html" option needed to generate HTML output
+from
+.Nm libxo "-enabled"
+applications. See
+.Xr libxo 3
+for details.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl "b <base>"
+.It Fl "-base <base>"
+Supplies a source path for the CSS and Javascript files referenced in
+the output of
+.Nm xohtml .
+.It Fl "c <command>"
+.It Fl "-command <command>"
+Use the given command instead of one on the command line.
+This command should be quoted if it consists of multiple tokens, and
+should contain the "--libxo=html" option or equivalent, since the
+command is used directly.
+.It Fl "f <file>"
+.It Fl "-file <file>"
+Output is saved to the given file, rather than to the standard output
+descriptor.
+.El
+.Pp
+.Sh EXAMPLES
+The following command line will run "du --libxo=html ~/src" and save
+the output to /tmp/src.html:
+.Bd -literal -offset indent
+ xohtml du ~/src > /tmp/src.html
+.Ed
+.Pp
+The following command line will run "du --libxo=html,warn ~/src" and save
+the output to /tmp/src.html:
+.Bd -literal -offset indent
+ du --libxo=html,warn ~/src | xohtml -f /tmp/src.html
+.Ed
+.Pp
+The following command line will run "du --libxo=html,warn ~/src" and save
+the output to /tmp/src.html:
+.Bd -literal -offset indent
+ xohtml -c "du --libxo=html,warn ~/src" -f /tmp/src.html
+.Ed
+.Pp
+.Sh ADDITIONAL DOCUMENTATION
+Complete documentation can be found on github:
+.Bd -literal -offset indent
+http://juniper.github.io/libxo/libxo-manual.html
+.Ed
+.Pp
+.Nm libxo
+lives on github as:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo
+.Ed
+.Pp
+The latest release of
+.Nm libxo
+is available at:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo/releases
+.Ed
+.Sh SEE ALSO
+.Xr libxo 3 ,
+.Xr xo_emit 3
+.Sh HISTORY
+The
+.Nm libxo
+library was added in
+.Fx 11.0 .
+.Sh AUTHOR
+Phil Shafer
+
diff --git a/contrib/libxo/xohtml/xohtml.css b/contrib/libxo/xohtml/xohtml.css
index 655bf12..fc9ea06 100644
--- a/contrib/libxo/xohtml/xohtml.css
+++ b/contrib/libxo/xohtml/xohtml.css
@@ -1014,3 +1014,27 @@ div.xpath {
position: relative;
top: 1px;
}
+
+div.color-fg-black { color: black; }
+div.color-fg-red { color: red; }
+div.color-fg-green { color: green; }
+div.color-fg-yellow { color: yellow; }
+div.color-fg-blue { color: blue; }
+div.color-fg-magenta { color: magenta; }
+div.color-fg-cyan { color: cyan; }
+div.color-fg-white { color: white; }
+
+div.color-bg-black { background-color: black; }
+div.color-bg-red { background-color: red; }
+div.color-bg-green { background-color: green; }
+div.color-bg-yellow { background-color: yellow; }
+div.color-bg-blue { background-color: blue; }
+div.color-bg-magenta { background-color: magenta; }
+div.color-bg-cyan { background-color: cyan; }
+div.color-bg-white { background-color: white; }
+
+div.color-fg-inverse { color: white; }
+div.color-bg-inverse { background-color: black; }
+
+div.effect-bold { font-weight:bold; }
+div.effect-underline { text-decoration: underline; }
diff --git a/contrib/libxo/xohtml/xohtml.sh.in b/contrib/libxo/xohtml/xohtml.sh.in
index cbd3066..a15d82e 100644
--- a/contrib/libxo/xohtml/xohtml.sh.in
+++ b/contrib/libxo/xohtml/xohtml.sh.in
@@ -13,6 +13,16 @@ BASE=@XO_SHAREDIR@
CMD=cat
DONE=
+do_help () {
+ echo "xohtml: wrap libxo-enabled output in HTML"
+ echo "Usage: xohtml [options] [command [arguments]]"
+ echo "Valid options are:"
+ echo " -b <basepath> | --base <basepath>"
+ echo " -c <command> | --command <command>"
+ echo " -f <output-file> | --file <output-file>"
+ exit 1
+}
+
while [ -z "$DONE" -a ! -z "$1" ]; do
case "$1" in
-b|--base)
@@ -31,12 +41,22 @@ while [ -z "$DONE" -a ! -z "$1" ]; do
shift;
exec > "$FILE";
;;
+ -*)
+ do_help
+ ;;
*)
DONE=1;
+ XX=$1;
+ shift;
+ CMD="$XX --libxo=html $@"
;;
esac
done
+if [ "$CMD" = "cat" -a -t 0 ]; then
+ do_help
+fi
+
echo "<html>\n<head>\n"
echo '<meta http-equiv="content-type" content="text/html; charset=utf-8"/>'
echo '<link rel="stylesheet" href="'$BASE'/xohtml.css">'
diff --git a/contrib/libxo/xolint/Makefile.am b/contrib/libxo/xolint/Makefile.am
index a847e72..ec5c36d 100644
--- a/contrib/libxo/xolint/Makefile.am
+++ b/contrib/libxo/xolint/Makefile.am
@@ -12,3 +12,6 @@ EXTRA_DIST = xolint.1 xolint.pl
install-exec-hook:
install ${srcdir}/xolint.pl ${DESTDIR}${bindir}/xolint
+
+uninstall-hook:
+ rm -f ${DESTDIR}${bindir}/xolint
diff --git a/contrib/libxo/xolint/xolint.1 b/contrib/libxo/xolint/xolint.1
index fcf7bcd..16a59fc 100644
--- a/contrib/libxo/xolint/xolint.1
+++ b/contrib/libxo/xolint/xolint.1
@@ -99,6 +99,6 @@ https://github.com/Juniper/libxo/releases
The
.Nm libxo
library was added in
-.Fx 10.1 .
+.Fx 11.0 .
.Sh AUTHOR
Phil Shafer
diff --git a/contrib/libxo/xolint/xolint.pl b/contrib/libxo/xolint/xolint.pl
index 427edf7..515f7fa 100755
--- a/contrib/libxo/xolint/xolint.pl
+++ b/contrib/libxo/xolint/xolint.pl
@@ -347,32 +347,32 @@ sub check_field {
error("only one field role can be used (" . join(", ", @roles) . ")")
if $#roles > 0;
- # Field is a note, label, or title
- if ($field[0] =~ /[DLNT]/) {
+ # Field is a color, note, label, or title
+ if ($field[0] =~ /[CDLNT]/) {
- #@ Potential missing slash after N, L, or T with format
+ #@ Potential missing slash after C, D, N, L, or T with format
#@ xo_emit("{T:%6.6s}\n", "Max");
#@ should be:
#@ xo_emit("{T:/%6.6s}\n", "Max");
#@ The "%6.6s" will be a literal, not a field format. While
#@ it's possibly valid, it's likely a missing "/".
- info("potential missing slash after N, L, or T with format")
+ info("potential missing slash after C, D, N, L, or T with format")
if $field[1] =~ /%/;
#@ An encoding format cannot be given (roles: DNLT)
#@ xo_emit("{T:Max//%s}", "Max");
- #@ Fields with the D, N, L, and T roles are not emitted in
+ #@ Fields with the C, D, N, L, and T roles are not emitted in
#@ the 'encoding' style (JSON, XML), so an encoding format
#@ would make no sense.
error("encoding format cannot be given when content is present")
if $field[3];
}
- # Field is a decoration, label, or title
- if ($field[0] =~ /DLN/) {
- #@ Format cannot be given when content is present (roles: DLN)
+ # Field is a color, decoration, label, or title
+ if ($field[0] =~ /[CDLN]/) {
+ #@ Format cannot be given when content is present (roles: CDLN)
#@ xo_emit("{N:Max/%6.6s}", "Max");
- #@ Fields with the D, L, or N roles can't have both
+ #@ Fields with the C, D, L, or N roles can't have both
#@ static literal content ("{L:Label}") and a
#@ format ("{L:/%s}").
#@ This error will also occur when the content has a backslash
@@ -383,6 +383,49 @@ sub check_field {
if $field[1] && $field[2];
}
+ # Field is a color/effect
+ if ($field[0] =~ /C/) {
+ if ($field[1]) {
+ my $val;
+ my @sub = split(/,/, $field[1]);
+ grep { s/^\s*//; s/\s*$//; } @sub;
+
+ for $val (@sub) {
+ if ($val =~ /^(default,black,red,green,yellow,blue,magenta,cyan,white)$/) {
+
+ #@ Field has color without fg- or bg- (role: C)
+ #@ xo_emit("{C:green}{:foo}{C:}", x);
+ #@ Should be:
+ #@ xo_emit("{C:fg-green}{:foo}{C:}", x);
+ #@ Colors must be prefixed by either "fg-" or "bg-".
+ error("Field has color without fg- or bg- (role: C)");
+
+ } elsif ($val =~ /^(fg|bg)-(default|black|red|green|yellow|blue|magenta|cyan|white)$/) {
+ # color
+ } elsif ($val =~ /^(bold|underline)$/) {
+ } elsif ($val =~ /^(no-)?(bold|underline|inverse)$/) {
+ # effect
+
+ } elsif ($val =~ /^(reset|normal)$/) {
+ # effect also
+ } else {
+ #@ Field has invalid color or effect (role: C)
+ #@ xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x);
+ #@ Should be:
+ #@ xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x);
+ #@ The list of colors and effects are limited. The
+ #@ set of colors includes default, black, red, green,
+ #@ yellow, blue, magenta, cyan, and white, which must
+ #@ be prefixed by either "fg-" or "bg-". Effects are
+ #@ limited to bold, no-bold, underline, no-underline,
+ #@ inverse, no-inverse, normal, and reset. Values must
+ #@ be separated by commas.
+ error("Field has invalid color or effect (role: C) ($val)");
+ }
+ }
+ }
+ }
+
# A value field
if (length($field[0]) == 0 || $field[0] =~ /V/) {
@@ -456,7 +499,7 @@ sub check_field {
#@ Should be:
#@ xo_emit("{D:((}{:good}{D:))}", "yes");
#@ This is minor, but fields should use proper roles. Decoration
- #@ fields are meant to hold puncuation and other characters used
+ #@ fields are meant to hold punctuation and other characters used
#@ to decorate the content, typically to make it more readable
#@ to human readers.
warn("decoration field contains invalid character")
diff --git a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp
index 8eff90a..e2a4fc1 100644
--- a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -3636,21 +3636,27 @@ bool AsmParser::parseDirectiveSpace(StringRef IDVal) {
}
/// parseDirectiveLEB128
-/// ::= (.sleb128 | .uleb128) expression
+/// ::= (.sleb128 | .uleb128) [ expression (, expression)* ]
bool AsmParser::parseDirectiveLEB128(bool Signed) {
checkForValidSection();
const MCExpr *Value;
- if (parseExpression(Value))
- return true;
+ for (;;) {
+ if (parseExpression(Value))
+ return true;
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return TokError("unexpected token in directive");
+ if (Signed)
+ getStreamer().EmitSLEB128Value(Value);
+ else
+ getStreamer().EmitULEB128Value(Value);
- if (Signed)
- getStreamer().EmitSLEB128Value(Value);
- else
- getStreamer().EmitULEB128Value(Value);
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+ }
return false;
}
diff --git a/contrib/llvm/patches/patch-13-llvm-r229911-uleb128-commas.diff b/contrib/llvm/patches/patch-13-llvm-r229911-uleb128-commas.diff
new file mode 100644
index 0000000..bf13463
--- /dev/null
+++ b/contrib/llvm/patches/patch-13-llvm-r229911-uleb128-commas.diff
@@ -0,0 +1,77 @@
+Pull in r229911 from upstream llvm trunk (by Benjamin Kramer):
+
+ MC: Allow multiple comma-separated expressions on the .uleb128 directive.
+
+ For compatiblity with GNU as. Binutils documents this as
+ '.uleb128 expressions'. Subtle, isn't it?
+
+Introduced here: http://svnweb.freebsd.org/changeset/base/281775
+
+Index: lib/MC/MCParser/AsmParser.cpp
+===================================================================
+--- lib/MC/MCParser/AsmParser.cpp
++++ lib/MC/MCParser/AsmParser.cpp
+@@ -3636,22 +3636,28 @@ bool AsmParser::parseDirectiveSpace(StringRef IDVa
+ }
+
+ /// parseDirectiveLEB128
+-/// ::= (.sleb128 | .uleb128) expression
++/// ::= (.sleb128 | .uleb128) [ expression (, expression)* ]
+ bool AsmParser::parseDirectiveLEB128(bool Signed) {
+ checkForValidSection();
+ const MCExpr *Value;
+
+- if (parseExpression(Value))
+- return true;
++ for (;;) {
++ if (parseExpression(Value))
++ return true;
+
+- if (getLexer().isNot(AsmToken::EndOfStatement))
+- return TokError("unexpected token in directive");
++ if (Signed)
++ getStreamer().EmitSLEB128Value(Value);
++ else
++ getStreamer().EmitULEB128Value(Value);
+
+- if (Signed)
+- getStreamer().EmitSLEB128Value(Value);
+- else
+- getStreamer().EmitULEB128Value(Value);
++ if (getLexer().is(AsmToken::EndOfStatement))
++ break;
+
++ if (getLexer().isNot(AsmToken::Comma))
++ return TokError("unexpected token in directive");
++ Lex();
++ }
++
+ return false;
+ }
+
+Index: test/MC/ELF/uleb.s
+===================================================================
+--- test/MC/ELF/uleb.s
++++ test/MC/ELF/uleb.s
+@@ -11,16 +11,17 @@ foo:
+ .uleb128 128
+ .uleb128 16383
+ .uleb128 16384
++ .uleb128 23, 42
+
+ // ELF_32: Name: .text
+ // ELF_32: SectionData (
+-// ELF_32: 0000: 00017F80 01FF7F80 8001
++// ELF_32: 0000: 00017F80 01FF7F80 8001172A
+ // ELF_32: )
+ // ELF_64: Name: .text
+ // ELF_64: SectionData (
+-// ELF_64: 0000: 00017F80 01FF7F80 8001
++// ELF_64: 0000: 00017F80 01FF7F80 8001172A
+ // ELF_64: )
+ // MACHO_32: ('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+-// MACHO_32: ('_section_data', '00017f80 01ff7f80 8001')
++// MACHO_32: ('_section_data', '00017f80 01ff7f80 8001172a')
+ // MACHO_64: ('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+-// MACHO_64: ('_section_data', '00017f80 01ff7f80 8001')
++// MACHO_64: ('_section_data', '00017f80 01ff7f80 8001172a')
diff --git a/contrib/mdocml/config.h b/contrib/mdocml/config.h
index b952c45..e7d3c63 100644
--- a/contrib/mdocml/config.h
+++ b/contrib/mdocml/config.h
@@ -12,7 +12,7 @@
#define HAVE_FTS 1
#define HAVE_GETSUBOPT 1
#define HAVE_MMAP 1
-#define HAVE_REALLOCARRAY 0
+#define HAVE_REALLOCARRAY 1
#define HAVE_STRCASESTR 1
#define HAVE_STRLCAT 1
#define HAVE_STRLCPY 1
diff --git a/contrib/netbsd-tests/lib/libm/t_fmod.c b/contrib/netbsd-tests/lib/libm/t_fmod.c
index 7dac93d..837e9b2 100644
--- a/contrib/netbsd-tests/lib/libm/t_fmod.c
+++ b/contrib/netbsd-tests/lib/libm/t_fmod.c
@@ -43,15 +43,21 @@ ATF_TC_BODY(fmod, tc)
{
ATF_CHECK(fmodf(2.0, 1.0) == 0);
ATF_CHECK(fmod(2.0, 1.0) == 0);
+#if !defined(__FreeBSD__) || LDBL_PREC != 53
ATF_CHECK(fmodl(2.0, 1.0) == 0);
+#endif
ATF_CHECK(fmodf(2.0, 0.5) == 0);
ATF_CHECK(fmod(2.0, 0.5) == 0);
+#if !defined(__FreeBSD__) || LDBL_PREC != 53
ATF_CHECK(fmodl(2.0, 0.5) == 0);
+#endif
ATF_CHECK(fabsf(fmodf(1.0, 0.1) - 0.1f) <= 55 * FLT_EPSILON);
ATF_CHECK(fabs(fmod(1.0, 0.1) - 0.1) <= 55 * DBL_EPSILON);
+#if !defined(__FreeBSD__) || LDBL_PREC != 53
ATF_CHECK(fabsl(fmodl(1.0, 0.1L) - 0.1L) <= 55 * LDBL_EPSILON);
+#endif
}
ATF_TP_ADD_TCS(tp)
diff --git a/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c b/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c
index 8fd2314..c0c375f 100644
--- a/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c
+++ b/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c
@@ -28,6 +28,9 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD");
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
#include <pthread.h>
#include <ucontext.h>
#include <stdio.h>
diff --git a/contrib/nvi/README b/contrib/nvi/README
index c129439..26fcc16 100644
--- a/contrib/nvi/README
+++ b/contrib/nvi/README
@@ -1,6 +1,6 @@
-# $Id: README,v 9.1 2013/11/02 02:50:23 zy Exp $
+# $Id: README,v 9.2 2015/04/08 17:18:56 zy Exp $
-This is version 2.1.2 (2012-11-02) of nex/nvi, a reimplementation of the ex/vi
+This is version 2.1.3 (2015-04-08) of nex/nvi, a reimplementation of the ex/vi
text editors originally distributed as part of the Fourth Berkeley
Software Distribution (4BSD), by the University of California, Berkeley.
diff --git a/contrib/nvi/catalog/dump.c b/contrib/nvi/catalog/dump.c
index b657877..b87b29c 100644
--- a/contrib/nvi/catalog/dump.c
+++ b/contrib/nvi/catalog/dump.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -32,12 +28,6 @@
*/
#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1992, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
static char sccsid[] = "@(#)dump.c 8.1 (Berkeley) 8/31/94";
#endif /* not lint */
@@ -45,8 +35,7 @@ static char sccsid[] = "@(#)dump.c 8.1 (Berkeley) 8/31/94";
#include <stdio.h>
static void
-parse(fp)
- FILE *fp;
+parse(FILE *fp)
{
int ch, s1, s2, s3;
@@ -96,9 +85,7 @@ parse(fp)
}
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
FILE *fp;
diff --git a/contrib/nvi/catalog/spell.ok b/contrib/nvi/catalog/spell.ok
deleted file mode 100644
index 00be471..0000000
--- a/contrib/nvi/catalog/spell.ok
+++ /dev/null
@@ -1,19 +0,0 @@
-ARGMAX
-LC
-NL
-XXXX
-arg1
-arg2
-chys
-english
-english.base
-german.base
-langauge
-msg
-msg.c
-msgcat
-msgq
-nvi
-nvi's
-pathname
-sp
diff --git a/contrib/nvi/cl/cl.h b/contrib/nvi/cl/cl.h
index c84ef88..cca0acb 100644
--- a/contrib/nvi/cl/cl.h
+++ b/contrib/nvi/cl/cl.h
@@ -80,16 +80,4 @@ typedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_INTR, INP_TIMEOUT } input_t;
#define RCNO(sp, cno) (cno)
#define RLNO(sp, lno) (lno)
-/*
- * XXX
- * Some implementations of curses.h don't define these for us. Used for
- * compatibility only.
- */
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
#include "extern.h"
diff --git a/contrib/nvi/cl/cl_funcs.c b/contrib/nvi/cl/cl_funcs.c
index 8b14e8d..4c15458 100644
--- a/contrib/nvi/cl/cl_funcs.c
+++ b/contrib/nvi/cl/cl_funcs.c
@@ -33,7 +33,7 @@ static const char sccsid[] = "$Id: cl_funcs.c,v 10.74 2012/10/11 10:30:16 zy Exp
#include "../vi/vi.h"
#include "cl.h"
-static void cl_rdiv __P((SCR *));
+static void cl_rdiv(SCR *);
static int
addstr4(SCR *sp, void *str, size_t len, int wide)
@@ -76,31 +76,31 @@ addstr4(SCR *sp, void *str, size_t len, int wide)
* cl_waddstr --
* Add len bytes from the string at the cursor, advancing the cursor.
*
- * PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t));
+ * PUBLIC: int cl_waddstr(SCR *, const CHAR_T *, size_t);
*/
int
cl_waddstr(SCR *sp, const CHAR_T *str, size_t len)
{
- return addstr4(sp, (void *)str, len, 1);
+ return addstr4(sp, (void *)str, len, 1);
}
/*
* cl_addstr --
* Add len bytes from the string at the cursor, advancing the cursor.
*
- * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t));
+ * PUBLIC: int cl_addstr(SCR *, const char *, size_t);
*/
int
cl_addstr(SCR *sp, const char *str, size_t len)
{
- return addstr4(sp, (void *)str, len, 0);
+ return addstr4(sp, (void *)str, len, 0);
}
/*
* cl_attr --
* Toggle a screen attribute on/off.
*
- * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
+ * PUBLIC: int cl_attr(SCR *, scr_attr_t, int);
*/
int
cl_attr(SCR *sp, scr_attr_t attribute, int on)
@@ -187,7 +187,7 @@ cl_attr(SCR *sp, scr_attr_t attribute, int on)
* cl_baud --
* Return the baud rate.
*
- * PUBLIC: int cl_baud __P((SCR *, u_long *));
+ * PUBLIC: int cl_baud(SCR *, u_long *);
*/
int
cl_baud(SCR *sp, u_long *ratep)
@@ -228,7 +228,7 @@ cl_baud(SCR *sp, u_long *ratep)
* cl_bell --
* Ring the bell/flash the screen.
*
- * PUBLIC: int cl_bell __P((SCR *));
+ * PUBLIC: int cl_bell(SCR *);
*/
int
cl_bell(SCR *sp)
@@ -252,7 +252,7 @@ cl_bell(SCR *sp)
* cl_clrtoeol --
* Clear from the current cursor to the end of the line.
*
- * PUBLIC: int cl_clrtoeol __P((SCR *));
+ * PUBLIC: int cl_clrtoeol(SCR *);
*/
int
cl_clrtoeol(SCR *sp)
@@ -281,7 +281,7 @@ cl_clrtoeol(SCR *sp)
* cl_cursor --
* Return the current cursor position.
*
- * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *));
+ * PUBLIC: int cl_cursor(SCR *, size_t *, size_t *);
*/
int
cl_cursor(SCR *sp, size_t *yp, size_t *xp)
@@ -307,7 +307,7 @@ cl_cursor(SCR *sp, size_t *yp, size_t *xp)
* cl_deleteln --
* Delete the current line, scrolling all lines below it.
*
- * PUBLIC: int cl_deleteln __P((SCR *));
+ * PUBLIC: int cl_deleteln(SCR *);
*/
int
cl_deleteln(SCR *sp)
@@ -344,7 +344,7 @@ cl_deleteln(SCR *sp)
* cl_discard --
* Discard a screen.
*
- * PUBLIC: int cl_discard __P((SCR *, SCR **));
+ * PUBLIC: int cl_discard(SCR *, SCR **);
*/
int
cl_discard(SCR *discardp, SCR **acquirep)
@@ -385,7 +385,7 @@ cl_discard(SCR *discardp, SCR **acquirep)
* Adjust the screen for ex. This routine is purely for standalone
* ex programs. All special purpose, all special case.
*
- * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
+ * PUBLIC: int cl_ex_adjust(SCR *, exadj_t);
*/
int
cl_ex_adjust(SCR *sp, exadj_t action)
@@ -440,7 +440,7 @@ cl_ex_adjust(SCR *sp, exadj_t action)
* cl_insertln --
* Push down the current line, discarding the bottom line.
*
- * PUBLIC: int cl_insertln __P((SCR *));
+ * PUBLIC: int cl_insertln(SCR *);
*/
int
cl_insertln(SCR *sp)
@@ -458,7 +458,7 @@ cl_insertln(SCR *sp)
* cl_keyval --
* Return the value for a special key.
*
- * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
+ * PUBLIC: int cl_keyval(SCR *, scr_keyval_t, CHAR_T *, int *);
*/
int
cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
@@ -496,7 +496,7 @@ cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
* cl_move --
* Move the cursor.
*
- * PUBLIC: int cl_move __P((SCR *, size_t, size_t));
+ * PUBLIC: int cl_move(SCR *, size_t, size_t);
*/
int
cl_move(SCR *sp, size_t lno, size_t cno)
@@ -516,7 +516,7 @@ cl_move(SCR *sp, size_t lno, size_t cno)
* cl_refresh --
* Refresh the screen.
*
- * PUBLIC: int cl_refresh __P((SCR *, int));
+ * PUBLIC: int cl_refresh(SCR *, int);
*/
int
cl_refresh(SCR *sp, int repaint)
@@ -599,7 +599,7 @@ cl_rdiv(SCR *sp)
* cl_rename --
* Rename the file.
*
- * PUBLIC: int cl_rename __P((SCR *, char *, int));
+ * PUBLIC: int cl_rename(SCR *, char *, int);
*/
int
cl_rename(SCR *sp, char *name, int on)
@@ -621,7 +621,7 @@ cl_rename(SCR *sp, char *name, int on)
if (on) {
clp->focus = sp;
if (!F_ISSET(clp, CL_RENAME_OK) ||
- strncmp(OG_STR(gp, GO_TERM), "xterm", 5))
+ strncmp(OG_STR(gp, GO_TERM), "xterm", 5))
return (0);
if (clp->oname == NULL && (wid = getenv("WINDOWID"))) {
@@ -654,7 +654,7 @@ rename: cl_setname(gp, name);
* cl_setname --
* Set a X11 icon/window name.
*
- * PUBLIC: void cl_setname __P((GS *, char *));
+ * PUBLIC: void cl_setname(GS *, char *);
*/
void
cl_setname(GS *gp, char *name)
@@ -671,7 +671,7 @@ cl_setname(GS *gp, char *name)
* cl_split --
* Split a screen.
*
- * PUBLIC: int cl_split __P((SCR *, SCR *));
+ * PUBLIC: int cl_split(SCR *, SCR *);
*/
int
cl_split(SCR *origp, SCR *newp)
@@ -697,7 +697,7 @@ cl_split(SCR *origp, SCR *newp)
* cl_suspend --
* Suspend a screen.
*
- * PUBLIC: int cl_suspend __P((SCR *, int *));
+ * PUBLIC: int cl_suspend(SCR *, int *);
*/
int
cl_suspend(SCR *sp, int *allowedp)
@@ -825,7 +825,7 @@ cl_suspend(SCR *sp, int *allowedp)
* cl_usage --
* Print out the curses usage messages.
*
- * PUBLIC: void cl_usage __P((void));
+ * PUBLIC: void cl_usage(void);
*/
void
cl_usage(void)
diff --git a/contrib/nvi/cl/cl_main.c b/contrib/nvi/cl/cl_main.c
index 98f1313..42c3c82 100644
--- a/contrib/nvi/cl/cl_main.c
+++ b/contrib/nvi/cl/cl_main.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: cl_main.c,v 10.55 2011/08/15 19:52:28 zy Exp $";
+static const char sccsid[] = "$Id: cl_main.c,v 10.56 2015/04/05 06:20:53 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -36,20 +36,20 @@ static const char sccsid[] = "$Id: cl_main.c,v 10.55 2011/08/15 19:52:28 zy Exp
GS *__global_list; /* GLOBAL: List of screens. */
sigset_t __sigblockset; /* GLOBAL: Blocked signals. */
-static void cl_func_std __P((GS *));
-static CL_PRIVATE *cl_init __P((GS *));
-static GS *gs_init __P((char *));
-static void perr __P((char *, char *));
-static int setsig __P((int, struct sigaction *, void (*)(int)));
-static void sig_end __P((GS *));
-static void term_init __P((char *, char *));
+static void cl_func_std(GS *);
+static CL_PRIVATE *cl_init(GS *);
+static GS *gs_init(char *);
+static void perr(char *, char *);
+static int setsig(int, struct sigaction *, void (*)(int));
+static void sig_end(GS *);
+static void term_init(char *, char *);
/*
* main --
* This is the main loop for the standalone curses editor.
*/
int
-main(int argc, char **argv)
+main(int argc, char *argv[])
{
static int reenter;
CL_PRIVATE *clp;
@@ -92,7 +92,7 @@ main(int argc, char **argv)
* have to use termcap/terminfo to find out how big the screen is.
*/
if ((ttype = getenv("TERM")) == NULL)
- ttype = "unknown";
+ ttype = "ansi";
term_init(gp->progname, ttype);
/* Add the terminal type to the global structure. */
@@ -146,7 +146,7 @@ main(int argc, char **argv)
}
/* Free the global and CL private areas. */
-#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
+#if defined(DEBUG) || defined(PURIFY)
if (clp->oname != NULL)
free(clp->oname);
free(clp);
@@ -292,7 +292,7 @@ h_winch(int signo)
* sig_init --
* Initialize signals.
*
- * PUBLIC: int sig_init __P((GS *, SCR *));
+ * PUBLIC: int sig_init(GS *, SCR *);
*/
int
sig_init(GS *gp, SCR *sp)
@@ -337,7 +337,7 @@ sig_init(GS *gp, SCR *sp)
* Set a signal handler.
*/
static int
-setsig(int signo, struct sigaction *oactp, void (*handler) (int))
+setsig(int signo, struct sigaction *oactp, void (*handler)(int))
{
struct sigaction act;
@@ -345,21 +345,12 @@ setsig(int signo, struct sigaction *oactp, void (*handler) (int))
* Use sigaction(2), not signal(3), since we don't always want to
* restart system calls. The example is when waiting for a command
* mode keystroke and SIGWINCH arrives. Besides, you can't portably
- * restart system calls (thanks, POSIX!). On the other hand, you
- * can't portably NOT restart system calls (thanks, Sun!). SunOS
- * used SA_INTERRUPT as their extension to NOT restart read calls.
- * We sure hope nobody else used it for anything else. Mom told me
- * there'd be days like this. She just never told me that there'd
- * be so many.
+ * restart system calls (thanks, POSIX!).
*/
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
-#ifdef SA_INTERRUPT
- act.sa_flags = SA_INTERRUPT;
-#else
act.sa_flags = 0;
-#endif
return (sigaction(signo, &act, oactp));
}
diff --git a/contrib/nvi/cl/cl_read.c b/contrib/nvi/cl/cl_read.c
index 410cdd4..3d9064c 100644
--- a/contrib/nvi/cl/cl_read.c
+++ b/contrib/nvi/cl/cl_read.c
@@ -35,15 +35,15 @@ static const char sccsid[] = "$Id: cl_read.c,v 10.30 2012/07/12 18:28:58 zy Exp
#undef columns
#undef lines
-static input_t cl_read __P((SCR *,
- u_int32_t, char *, size_t, int *, struct timeval *));
-static int cl_resize __P((SCR *, size_t, size_t));
+static input_t cl_read(SCR *,
+ u_int32_t, char *, size_t, int *, struct timeval *);
+static int cl_resize(SCR *, size_t, size_t);
/*
* cl_event --
* Return a single event.
*
- * PUBLIC: int cl_event __P((SCR *, EVENT *, u_int32_t, int));
+ * PUBLIC: int cl_event(SCR *, EVENT *, u_int32_t, int);
*/
int
cl_event(SCR *sp, EVENT *evp, u_int32_t flags, int ms)
@@ -143,7 +143,8 @@ read:
* Read characters from the input.
*/
static input_t
-cl_read(SCR *sp, u_int32_t flags, char *bp, size_t blen, int *nrp, struct timeval *tp)
+cl_read(SCR *sp, u_int32_t flags, char *bp, size_t blen, int *nrp,
+ struct timeval *tp)
{
struct termios term1, term2;
CL_PRIVATE *clp;
diff --git a/contrib/nvi/cl/cl_screen.c b/contrib/nvi/cl/cl_screen.c
index 91ff278..16c8772 100644
--- a/contrib/nvi/cl/cl_screen.c
+++ b/contrib/nvi/cl/cl_screen.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: cl_screen.c,v 10.56 2002/05/03 19:59:44 skimo Exp $";
+static const char sccsid[] = "$Id: cl_screen.c,v 10.58 2015/04/08 02:12:11 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -32,18 +32,18 @@ static const char sccsid[] = "$Id: cl_screen.c,v 10.56 2002/05/03 19:59:44 skimo
#include "../common/common.h"
#include "cl.h"
-static int cl_ex_end __P((GS *));
-static int cl_ex_init __P((SCR *));
-static void cl_freecap __P((CL_PRIVATE *));
-static int cl_vi_end __P((GS *));
-static int cl_vi_init __P((SCR *));
-static int cl_putenv __P((char *, char *, u_long));
+static int cl_ex_end(GS *);
+static int cl_ex_init(SCR *);
+static void cl_freecap(CL_PRIVATE *);
+static int cl_vi_end(GS *);
+static int cl_vi_init(SCR *);
+static int cl_putenv(char *, char *, u_long);
/*
* cl_screen --
* Switch screen types.
*
- * PUBLIC: int cl_screen __P((SCR *, u_int32_t));
+ * PUBLIC: int cl_screen(SCR *, u_int32_t);
*/
int
cl_screen(SCR *sp, u_int32_t flags)
@@ -58,11 +58,9 @@ cl_screen(SCR *sp, u_int32_t flags)
/* See if the current information is incorrect. */
if (F_ISSET(gp, G_SRESTART)) {
- if (CLSP(sp)) {
- delwin(CLSP(sp));
- sp->cl_private = NULL;
- }
- if (cl_quit(gp))
+ if ((!F_ISSET(sp, SC_SCR_EX | SC_SCR_VI) ||
+ resizeterm(O_VAL(sp, O_LINES), O_VAL(sp, O_COLUMNS))) &&
+ cl_quit(gp))
return (1);
F_CLR(gp, G_SRESTART);
}
@@ -131,7 +129,7 @@ cl_screen(SCR *sp, u_int32_t flags)
* cl_quit --
* Shutdown the screens.
*
- * PUBLIC: int cl_quit __P((GS *));
+ * PUBLIC: int cl_quit(GS *);
*/
int
cl_quit(GS *gp)
@@ -234,20 +232,15 @@ cl_vi_init(SCR *sp)
cl_putenv("COLUMNS", NULL, (u_long)O_VAL(sp, O_COLUMNS));
/*
- * We don't care about the SCREEN reference returned by newterm, we
- * never have more than one SCREEN at a time.
- *
- * XXX
- * The SunOS initscr() can't be called twice. Don't even think about
- * using it. It fails in subtle ways (e.g. select(2) on fileno(stdin)
- * stops working). (The SVID notes that applications should only call
- * initscr() once.)
- *
- * XXX
- * The HP/UX newterm doesn't support the NULL first argument, so we
- * have to specify the terminal type.
+ * The terminal is aways initialized, either in `main`, or by a
+ * previous call to newterm(3X).
*/
(void)del_curterm(cur_term);
+
+ /*
+ * We never have more than one SCREEN at a time, so set_term(NULL) will
+ * give us the last SCREEN.
+ */
errno = 0;
if (newterm(ttype, stdout, stdin) == NULL) {
if (errno)
@@ -416,6 +409,9 @@ cl_vi_end(GS *gp)
/* End curses window. */
(void)endwin();
+ /* Free the SCREEN created by newterm(3X). */
+ delscreen(set_term(NULL));
+
/*
* XXX
* The screen TE sequence just got sent. See the comment in
@@ -520,7 +516,7 @@ cl_ex_end(GS *gp)
* cl_getcap --
* Retrieve termcap/terminfo strings.
*
- * PUBLIC: int cl_getcap __P((SCR *, char *, char **));
+ * PUBLIC: int cl_getcap(SCR *, char *, char **);
*/
int
cl_getcap(SCR *sp, char *name, char **elementp)
diff --git a/contrib/nvi/cl/cl_term.c b/contrib/nvi/cl/cl_term.c
index 7e8f6c7..d4b1efc 100644
--- a/contrib/nvi/cl/cl_term.c
+++ b/contrib/nvi/cl/cl_term.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: cl_term.c,v 10.34 2013/12/07 16:21:14 wjenkner Exp $";
+static const char sccsid[] = "$Id: cl_term.c,v 10.35 2015/04/08 02:12:11 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -34,7 +34,7 @@ static const char sccsid[] = "$Id: cl_term.c,v 10.34 2013/12/07 16:21:14 wjenkne
#include "../common/common.h"
#include "cl.h"
-static int cl_pfmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
+static int cl_pfmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t);
/*
* XXX
@@ -81,7 +81,7 @@ static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */
* cl_term_init --
* Initialize the special keys defined by the termcap/terminfo entry.
*
- * PUBLIC: int cl_term_init __P((SCR *));
+ * PUBLIC: int cl_term_init(SCR *);
*/
int
cl_term_init(SCR *sp)
@@ -182,7 +182,7 @@ cl_term_init(SCR *sp)
* cl_term_end --
* End the special keys defined by the termcap/terminfo entry.
*
- * PUBLIC: int cl_term_end __P((GS *));
+ * PUBLIC: int cl_term_end(GS *);
*/
int
cl_term_end(GS *gp)
@@ -206,7 +206,7 @@ cl_term_end(GS *gp)
* cl_fmap --
* Map a function key.
*
- * PUBLIC: int cl_fmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
+ * PUBLIC: int cl_fmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t);
*/
int
cl_fmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
@@ -258,7 +258,7 @@ cl_pfmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tle
* cl_optchange --
* Curses screen specific "option changed" routine.
*
- * PUBLIC: int cl_optchange __P((SCR *, int, char *, u_long *));
+ * PUBLIC: int cl_optchange(SCR *, int, char *, u_long *);
*/
int
cl_optchange(SCR *sp, int opt, char *str, u_long *valp)
@@ -268,15 +268,16 @@ cl_optchange(SCR *sp, int opt, char *str, u_long *valp)
clp = CLP(sp);
switch (opt) {
+ case O_TERM:
+ F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
+ /* FALLTHROUGH */
case O_COLUMNS:
case O_LINES:
- case O_TERM:
/*
- * Changing the columns, lines or terminal require that
- * we restart the screen.
+ * Changing the terminal type requires that we reinitialize
+ * curses, while resizing does not.
*/
F_SET(sp->gp, G_SRESTART);
- F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
break;
case O_MESG:
(void)cl_omesg(sp, clp, *valp);
@@ -305,7 +306,7 @@ cl_optchange(SCR *sp, int opt, char *str, u_long *valp)
* cl_omesg --
* Turn the tty write permission on or off.
*
- * PUBLIC: int cl_omesg __P((SCR *, CL_PRIVATE *, int));
+ * PUBLIC: int cl_omesg(SCR *, CL_PRIVATE *, int);
*/
int
cl_omesg(SCR *sp, CL_PRIVATE *clp, int on)
@@ -351,7 +352,7 @@ cl_omesg(SCR *sp, CL_PRIVATE *clp, int on)
* cl_ssize --
* Return the terminal size.
*
- * PUBLIC: int cl_ssize __P((SCR *, int, size_t *, size_t *, int *));
+ * PUBLIC: int cl_ssize(SCR *, int, size_t *, size_t *, int *);
*/
int
cl_ssize(SCR *sp, int sigwinch, size_t *rowp, size_t *colp, int *changedp)
@@ -467,7 +468,7 @@ noterm: if (row == 0)
* cl_putchar --
* Function version of putchar, for tputs.
*
- * PUBLIC: int cl_putchar __P((int));
+ * PUBLIC: int cl_putchar(int);
*/
int
cl_putchar(int ch)
diff --git a/contrib/nvi/cl/extern.h b/contrib/nvi/cl/extern.h
index 626f4fb..7b01ccd 100644
--- a/contrib/nvi/cl/extern.h
+++ b/contrib/nvi/cl/extern.h
@@ -1,31 +1,31 @@
-int cl_waddstr __P((SCR *, const CHAR_T *, size_t));
-int cl_addstr __P((SCR *, const char *, size_t));
-int cl_attr __P((SCR *, scr_attr_t, int));
-int cl_baud __P((SCR *, u_long *));
-int cl_bell __P((SCR *));
-int cl_clrtoeol __P((SCR *));
-int cl_cursor __P((SCR *, size_t *, size_t *));
-int cl_deleteln __P((SCR *));
-int cl_discard __P((SCR *, SCR **));
-int cl_ex_adjust __P((SCR *, exadj_t));
-int cl_insertln __P((SCR *));
-int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
-int cl_move __P((SCR *, size_t, size_t));
-int cl_refresh __P((SCR *, int));
-int cl_rename __P((SCR *, char *, int));
-void cl_setname __P((GS *, char *));
-int cl_split __P((SCR *, SCR *));
-int cl_suspend __P((SCR *, int *));
-void cl_usage __P((void));
-int sig_init __P((GS *, SCR *));
-int cl_event __P((SCR *, EVENT *, u_int32_t, int));
-int cl_screen __P((SCR *, u_int32_t));
-int cl_quit __P((GS *));
-int cl_getcap __P((SCR *, char *, char **));
-int cl_term_init __P((SCR *));
-int cl_term_end __P((GS *));
-int cl_fmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
-int cl_optchange __P((SCR *, int, char *, u_long *));
-int cl_omesg __P((SCR *, CL_PRIVATE *, int));
-int cl_ssize __P((SCR *, int, size_t *, size_t *, int *));
-int cl_putchar __P((int));
+int cl_waddstr(SCR *, const CHAR_T *, size_t);
+int cl_addstr(SCR *, const char *, size_t);
+int cl_attr(SCR *, scr_attr_t, int);
+int cl_baud(SCR *, u_long *);
+int cl_bell(SCR *);
+int cl_clrtoeol(SCR *);
+int cl_cursor(SCR *, size_t *, size_t *);
+int cl_deleteln(SCR *);
+int cl_discard(SCR *, SCR **);
+int cl_ex_adjust(SCR *, exadj_t);
+int cl_insertln(SCR *);
+int cl_keyval(SCR *, scr_keyval_t, CHAR_T *, int *);
+int cl_move(SCR *, size_t, size_t);
+int cl_refresh(SCR *, int);
+int cl_rename(SCR *, char *, int);
+void cl_setname(GS *, char *);
+int cl_split(SCR *, SCR *);
+int cl_suspend(SCR *, int *);
+void cl_usage(void);
+int sig_init(GS *, SCR *);
+int cl_event(SCR *, EVENT *, u_int32_t, int);
+int cl_screen(SCR *, u_int32_t);
+int cl_quit(GS *);
+int cl_getcap(SCR *, char *, char **);
+int cl_term_init(SCR *);
+int cl_term_end(GS *);
+int cl_fmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t);
+int cl_optchange(SCR *, int, char *, u_long *);
+int cl_omesg(SCR *, CL_PRIVATE *, int);
+int cl_ssize(SCR *, int, size_t *, size_t *, int *);
+int cl_putchar(int);
diff --git a/contrib/nvi/common/common.h b/contrib/nvi/common/common.h
index 71f4c7f..c64adb5 100644
--- a/contrib/nvi/common/common.h
+++ b/contrib/nvi/common/common.h
@@ -23,8 +23,8 @@
*/
typedef struct _cb CB;
typedef struct _csc CSC;
-typedef struct _conv CONV;
-typedef struct _conv_win CONVWIN;
+typedef struct _conv CONV;
+typedef struct _conv_win CONVWIN;
typedef struct _event EVENT;
typedef struct _excmd EXCMD;
typedef struct _exf EXF;
diff --git a/contrib/nvi/common/conv.c b/contrib/nvi/common/conv.c
index 7803cec..aaa7af3 100644
--- a/contrib/nvi/common/conv.c
+++ b/contrib/nvi/common/conv.c
@@ -12,7 +12,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: conv.c,v 2.39 2013/07/01 23:28:13 zy Exp $";
+static const char sccsid[] = "$Id: conv.c,v 2.40 2014/02/27 16:25:29 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -36,35 +36,37 @@ static const char sccsid[] = "$Id: conv.c,v 2.39 2013/07/01 23:28:13 zy Exp $";
* codeset --
* Get the locale encoding.
*
- * PUBLIC: char * codeset __P((void));
+ * PUBLIC: char * codeset(void);
*/
char *
-codeset(void) {
- static char *cs;
+codeset(void)
+{
+ static char *cs;
+
+ if (cs == NULL)
+ cs = nl_langinfo(CODESET);
- if (cs == NULL)
- cs = nl_langinfo(CODESET);
- return cs;
+ return cs;
}
#ifdef USE_WIDECHAR
static int
-raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, CHAR_T **dst)
+raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
+ CHAR_T **dst)
{
- int i;
- CHAR_T **tostr = &cw->bp1.wc;
- size_t *blen = &cw->blen1;
+ int i;
+ CHAR_T **tostr = &cw->bp1.wc;
+ size_t *blen = &cw->blen1;
- BINC_RETW(NULL, *tostr, *blen, len);
+ BINC_RETW(NULL, *tostr, *blen, len);
- *tolen = len;
- for (i = 0; i < len; ++i)
- (*tostr)[i] = (u_char) str[i];
+ *tolen = len;
+ for (i = 0; i < len; ++i)
+ (*tostr)[i] = (u_char) str[i];
- *dst = cw->bp1.wc;
+ *dst = cw->bp1.wc;
- return 0;
+ return 0;
}
#define CONV_BUFFER_SIZE 512
@@ -73,27 +75,27 @@ raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
* len contains the number of bytes put in the buffer
*/
#ifdef USE_ICONV
-#define CONVERT(str, left, src, len) \
- do { \
- size_t outleft; \
- char *bp = buffer; \
- outleft = CONV_BUFFER_SIZE; \
- errno = 0; \
- if (iconv(id, (iconv_src_t)&str, &left, &bp, &outleft) == -1 && \
- errno != E2BIG) \
- goto err; \
- if ((len = CONV_BUFFER_SIZE - outleft) == 0) { \
- error = -left; \
- goto err; \
- } \
- src = buffer; \
- } while (0)
+#define CONVERT(str, left, src, len) \
+ do { \
+ size_t outleft; \
+ char *bp = buffer; \
+ outleft = CONV_BUFFER_SIZE; \
+ errno = 0; \
+ if (iconv(id, (iconv_src_t)&str, &left, &bp, &outleft) \
+ == -1 && errno != E2BIG) \
+ goto err; \
+ if ((len = CONV_BUFFER_SIZE - outleft) == 0) { \
+ error = -left; \
+ goto err; \
+ } \
+ src = buffer; \
+ } while (0)
#define IC_RESET() \
- do { \
- if (id != (iconv_t)-1) \
- iconv(id, NULL, NULL, NULL, NULL); \
- } while(0)
+ do { \
+ if (id != (iconv_t)-1) \
+ iconv(id, NULL, NULL, NULL, NULL); \
+ } while(0)
#else
#define CONVERT(str, left, src, len)
#define IC_RESET()
@@ -101,114 +103,116 @@ raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
static int
default_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, CHAR_T **dst, iconv_t id)
+ size_t *tolen, CHAR_T **dst, iconv_t id)
{
- size_t i = 0, j;
- CHAR_T **tostr = &cw->bp1.wc;
- size_t *blen = &cw->blen1;
- mbstate_t mbs;
- size_t n;
- ssize_t nlen = len;
- char *src = (char *)str;
+ size_t i = 0, j;
+ CHAR_T **tostr = &cw->bp1.wc;
+ size_t *blen = &cw->blen1;
+ mbstate_t mbs;
+ size_t n;
+ ssize_t nlen = len;
+ char *src = (char *)str;
#ifdef USE_ICONV
- char buffer[CONV_BUFFER_SIZE];
+ char buffer[CONV_BUFFER_SIZE];
#endif
- size_t left = len;
- int error = 1;
+ size_t left = len;
+ int error = 1;
- BZERO(&mbs, 1);
- BINC_RETW(NULL, *tostr, *blen, nlen);
+ BZERO(&mbs, 1);
+ BINC_RETW(NULL, *tostr, *blen, nlen);
#ifdef USE_ICONV
- if (id != (iconv_t)-1)
- CONVERT(str, left, src, len);
+ if (id != (iconv_t)-1)
+ CONVERT(str, left, src, len);
#endif
- for (i = 0, j = 0; j < len; ) {
- n = mbrtowc((*tostr)+i, src+j, len-j, &mbs);
- /* NULL character converted */
- if (n == -2) error = -(len-j);
- if (n == -1 || n == -2) goto err;
- if (n == 0) n = 1;
- j += n;
- if (++i >= *blen) {
- nlen += 256;
- BINC_RETW(NULL, *tostr, *blen, nlen);
- }
- if (id != (iconv_t)-1 && j == len && left) {
- CONVERT(str, left, src, len);
- j = 0;
+ for (i = 0, j = 0; j < len; ) {
+ n = mbrtowc((*tostr)+i, src+j, len-j, &mbs);
+ /* NULL character converted */
+ if (n == -2)
+ error = -(len-j);
+ if (n == -1 || n == -2)
+ goto err;
+ if (n == 0)
+ n = 1;
+ j += n;
+ if (++i >= *blen) {
+ nlen += 256;
+ BINC_RETW(NULL, *tostr, *blen, nlen);
+ }
+ if (id != (iconv_t)-1 && j == len && left) {
+ CONVERT(str, left, src, len);
+ j = 0;
+ }
}
- }
- error = 0;
+ error = 0;
err:
- *tolen = i;
- *dst = cw->bp1.wc;
- IC_RESET();
+ *tolen = i;
+ *dst = cw->bp1.wc;
+ IC_RESET();
- return error;
+ return error;
}
static int
-fe_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, CHAR_T **dst)
+fe_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
+ CHAR_T **dst)
{
- return default_char2int(sp, str, len, cw, tolen, dst,
- sp->conv.id[IC_FE_CHAR2INT]);
+ return default_char2int(sp, str, len, cw, tolen, dst,
+ sp->conv.id[IC_FE_CHAR2INT]);
}
static int
-ie_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, CHAR_T **dst)
+ie_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
+ CHAR_T **dst)
{
- return default_char2int(sp, str, len, cw, tolen, dst,
- sp->conv.id[IC_IE_CHAR2INT]);
+ return default_char2int(sp, str, len, cw, tolen, dst,
+ sp->conv.id[IC_IE_CHAR2INT]);
}
static int
-cs_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, CHAR_T **dst)
+cs_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
+ CHAR_T **dst)
{
- return default_char2int(sp, str, len, cw, tolen, dst,
- (iconv_t)-1);
+ return default_char2int(sp, str, len, cw, tolen, dst, (iconv_t)-1);
}
static int
-int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, char **dst)
+int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, size_t *tolen,
+ char **dst)
{
- int i;
- char **tostr = &cw->bp1.c;
- size_t *blen = &cw->blen1;
+ int i;
+ char **tostr = &cw->bp1.c;
+ size_t *blen = &cw->blen1;
- BINC_RETC(NULL, *tostr, *blen, len);
+ BINC_RETC(NULL, *tostr, *blen, len);
- *tolen = len;
- for (i = 0; i < len; ++i)
- (*tostr)[i] = str[i];
+ *tolen = len;
+ for (i = 0; i < len; ++i)
+ (*tostr)[i] = str[i];
- *dst = cw->bp1.c;
+ *dst = cw->bp1.c;
- return 0;
+ return 0;
}
static int
default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, char **pdst, iconv_t id)
+ size_t *tolen, char **pdst, iconv_t id)
{
- size_t i, j, offset = 0;
- char **tostr = &cw->bp1.c;
- size_t *blen = &cw->blen1;
- mbstate_t mbs;
- size_t n;
- ssize_t nlen = len + MB_CUR_MAX;
- char *dst;
- size_t buflen;
+ size_t i, j, offset = 0;
+ char **tostr = &cw->bp1.c;
+ size_t *blen = &cw->blen1;
+ mbstate_t mbs;
+ size_t n;
+ ssize_t nlen = len + MB_CUR_MAX;
+ char *dst;
+ size_t buflen;
#ifdef USE_ICONV
- char buffer[CONV_BUFFER_SIZE];
+ char buffer[CONV_BUFFER_SIZE];
#endif
- int error = 1;
+ int error = 1;
/* convert first len bytes of buffer and append it to cw->bp
* len is adjusted => 0
@@ -217,87 +221,90 @@ default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
*/
#ifdef USE_ICONV
#define CONVERT2(_buffer, lenp, cw, offset) \
- do { \
- char *bp = _buffer; \
- int ret; \
do { \
- size_t outleft = cw->blen1 - offset; \
- char *obp = cw->bp1.c + offset; \
- if (cw->blen1 < offset + MB_CUR_MAX) { \
- nlen += 256; \
- BINC_RETC(NULL, cw->bp1.c, cw->blen1, nlen); \
- } \
- errno = 0; \
- ret = iconv(id, (iconv_src_t)&bp, lenp, &obp, &outleft); \
- if (ret == -1 && errno != E2BIG) \
- goto err; \
- offset = cw->blen1 - outleft; \
- } while (ret != 0); \
- } while (0)
+ char *bp = _buffer; \
+ int ret; \
+ do { \
+ size_t outleft = cw->blen1 - offset; \
+ char *obp = cw->bp1.c + offset; \
+ if (cw->blen1 < offset + MB_CUR_MAX) { \
+ nlen += 256; \
+ BINC_RETC(NULL, cw->bp1.c, cw->blen1, \
+ nlen); \
+ } \
+ errno = 0; \
+ ret = iconv(id, (iconv_src_t)&bp, lenp, &obp, \
+ &outleft); \
+ if (ret == -1 && errno != E2BIG) \
+ goto err; \
+ offset = cw->blen1 - outleft; \
+ } while (ret != 0); \
+ } while (0)
#else
#define CONVERT2(_buffer, lenp, cw, offset)
#endif
- BZERO(&mbs, 1);
- BINC_RETC(NULL, *tostr, *blen, nlen);
- dst = *tostr; buflen = *blen;
+ BZERO(&mbs, 1);
+ BINC_RETC(NULL, *tostr, *blen, nlen);
+ dst = *tostr; buflen = *blen;
#ifdef USE_ICONV
- if (id != (iconv_t)-1) {
- dst = buffer; buflen = CONV_BUFFER_SIZE;
- }
+ if (id != (iconv_t)-1) {
+ dst = buffer; buflen = CONV_BUFFER_SIZE;
+ }
#endif
- for (i = 0, j = 0; i < len; ++i) {
- n = wcrtomb(dst+j, str[i], &mbs);
- if (n == -1) goto err;
- j += n;
- if (buflen < j + MB_CUR_MAX) {
- if (id != (iconv_t)-1) {
- CONVERT2(buffer, &j, cw, offset);
- } else {
- nlen += 256;
- BINC_RETC(NULL, *tostr, *blen, nlen);
- dst = *tostr; buflen = *blen;
- }
+ for (i = 0, j = 0; i < len; ++i) {
+ n = wcrtomb(dst+j, str[i], &mbs);
+ if (n == -1)
+ goto err;
+ j += n;
+ if (buflen < j + MB_CUR_MAX) {
+ if (id != (iconv_t)-1) {
+ CONVERT2(buffer, &j, cw, offset);
+ } else {
+ nlen += 256;
+ BINC_RETC(NULL, *tostr, *blen, nlen);
+ dst = *tostr; buflen = *blen;
+ }
+ }
}
- }
- n = wcrtomb(dst+j, L'\0', &mbs);
- j += n - 1; /* don't count NUL at the end */
- *tolen = j;
+ n = wcrtomb(dst+j, L'\0', &mbs);
+ j += n - 1; /* don't count NUL at the end */
+ *tolen = j;
- if (id != (iconv_t)-1) {
- CONVERT2(buffer, &j, cw, offset);
- CONVERT2(NULL, NULL, cw, offset); /* back to the initial state */
- *tolen = offset;
- }
+ if (id != (iconv_t)-1) {
+ CONVERT2(buffer, &j, cw, offset);
+ /* back to the initial state */
+ CONVERT2(NULL, NULL, cw, offset);
+ *tolen = offset;
+ }
- error = 0;
+ error = 0;
err:
- if (error)
- *tolen = j;
- *pdst = cw->bp1.c;
- IC_RESET();
+ if (error)
+ *tolen = j;
+ *pdst = cw->bp1.c;
+ IC_RESET();
- return error;
+ return error;
}
static int
fe_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, char **dst)
+ size_t *tolen, char **dst)
{
- return default_int2char(sp, str, len, cw, tolen, dst,
- sp->conv.id[IC_FE_INT2CHAR]);
+ return default_int2char(sp, str, len, cw, tolen, dst,
+ sp->conv.id[IC_FE_INT2CHAR]);
}
static int
cs_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
- size_t *tolen, char **dst)
+ size_t *tolen, char **dst)
{
- return default_int2char(sp, str, len, cw, tolen, dst,
- (iconv_t)-1);
+ return default_int2char(sp, str, len, cw, tolen, dst, (iconv_t)-1);
}
#endif
@@ -306,58 +313,58 @@ cs_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
* conv_init --
* Initialize the iconv environment.
*
- * PUBLIC: void conv_init __P((SCR *, SCR *));
+ * PUBLIC: void conv_init(SCR *, SCR *);
*/
void
conv_init(SCR *orig, SCR *sp)
{
- int i;
+ int i;
- if (orig == NULL)
- setlocale(LC_ALL, "");
- if (orig != NULL)
- BCOPY(&orig->conv, &sp->conv, 1);
+ if (orig == NULL)
+ setlocale(LC_ALL, "");
+ if (orig != NULL)
+ BCOPY(&orig->conv, &sp->conv, 1);
#ifdef USE_WIDECHAR
- else {
- char *ctype = setlocale(LC_CTYPE, NULL);
-
- /*
- * XXX
- * This hack fixes the libncursesw issue on FreeBSD.
- */
- if (!strcmp(ctype, "ko_KR.CP949"))
- setlocale(LC_CTYPE, "ko_KR.eucKR");
- else if (!strcmp(ctype, "zh_CN.GB2312"))
- setlocale(LC_CTYPE, "zh_CN.eucCN");
- else if (!strcmp(ctype, "zh_CN.GBK"))
- setlocale(LC_CTYPE, "zh_CN.GB18030");
-
- /*
- * Switch to 8bit mode if locale is C;
- * LC_CTYPE should be reseted to C if unmatched.
- */
- if (!strcmp(ctype, "C") || !strcmp(ctype, "POSIX")) {
- sp->conv.sys2int = sp->conv.file2int = raw2int;
- sp->conv.int2sys = sp->conv.int2file = int2raw;
- sp->conv.input2int = raw2int;
- } else {
- sp->conv.sys2int = cs_char2int;
- sp->conv.int2sys = cs_int2char;
- sp->conv.file2int = fe_char2int;
- sp->conv.int2file = fe_int2char;
- sp->conv.input2int = ie_char2int;
- }
+ else {
+ char *ctype = setlocale(LC_CTYPE, NULL);
+
+ /*
+ * XXX
+ * This hack fixes the libncursesw issue on FreeBSD.
+ */
+ if (!strcmp(ctype, "ko_KR.CP949"))
+ setlocale(LC_CTYPE, "ko_KR.eucKR");
+ else if (!strcmp(ctype, "zh_CN.GB2312"))
+ setlocale(LC_CTYPE, "zh_CN.eucCN");
+ else if (!strcmp(ctype, "zh_CN.GBK"))
+ setlocale(LC_CTYPE, "zh_CN.GB18030");
+
+ /*
+ * Switch to 8bit mode if locale is C;
+ * LC_CTYPE should be reseted to C if unmatched.
+ */
+ if (!strcmp(ctype, "C") || !strcmp(ctype, "POSIX")) {
+ sp->conv.sys2int = sp->conv.file2int = raw2int;
+ sp->conv.int2sys = sp->conv.int2file = int2raw;
+ sp->conv.input2int = raw2int;
+ } else {
+ sp->conv.sys2int = cs_char2int;
+ sp->conv.int2sys = cs_int2char;
+ sp->conv.file2int = fe_char2int;
+ sp->conv.int2file = fe_int2char;
+ sp->conv.input2int = ie_char2int;
+ }
#ifdef USE_ICONV
- o_set(sp, O_INPUTENCODING, OS_STRDUP, codeset(), 0);
+ o_set(sp, O_INPUTENCODING, OS_STRDUP, codeset(), 0);
#endif
- }
+ }
#endif
- /* iconv descriptors must be distinct to screens. */
- for (i = 0; i <= IC_IE_TO_UTF16; ++i)
- sp->conv.id[i] = (iconv_t)-1;
+ /* iconv descriptors must be distinct to screens. */
+ for (i = 0; i <= IC_IE_TO_UTF16; ++i)
+ sp->conv.id[i] = (iconv_t)-1;
#ifdef USE_ICONV
- conv_enc(sp, O_INPUTENCODING, 0);
+ conv_enc(sp, O_INPUTENCODING, 0);
#endif
}
@@ -365,82 +372,99 @@ conv_init(SCR *orig, SCR *sp)
* conv_enc --
* Convert file/input encoding.
*
- * PUBLIC: int conv_enc __P((SCR *, int, char *));
+ * PUBLIC: int conv_enc(SCR *, int, char *);
*/
int
conv_enc(SCR *sp, int option, char *enc)
{
#if defined(USE_WIDECHAR) && defined(USE_ICONV)
- iconv_t *c2w, *w2c;
+ iconv_t *c2w, *w2c;
+ iconv_t id_c2w, id_w2c;
+
+ switch (option) {
+ case O_FILEENCODING:
+ c2w = sp->conv.id + IC_FE_CHAR2INT;
+ w2c = sp->conv.id + IC_FE_INT2CHAR;
+ if (!enc)
+ enc = O_STR(sp, O_FILEENCODING);
+
+ if (strcasecmp(codeset(), enc)) {
+ if ((id_c2w = iconv_open(codeset(), enc)) ==
+ (iconv_t)-1)
+ goto err;
+ if ((id_w2c = iconv_open(enc, codeset())) ==
+ (iconv_t)-1)
+ goto err;
+ } else {
+ id_c2w = (iconv_t)-1;
+ id_w2c = (iconv_t)-1;
+ }
+
+ break;
+
+ case O_INPUTENCODING:
+ c2w = sp->conv.id + IC_IE_CHAR2INT;
+ w2c = sp->conv.id + IC_IE_TO_UTF16;
+ if (!enc)
+ enc = O_STR(sp, O_INPUTENCODING);
+
+ if (strcasecmp(codeset(), enc)) {
+ if ((id_c2w = iconv_open(codeset(), enc)) ==
+ (iconv_t)-1)
+ goto err;
+ } else
+ id_c2w = (iconv_t)-1;
+
+ /* UTF-16 can not be locale and can not be inputed. */
+ if ((id_w2c = iconv_open("utf-16be", enc)) == (iconv_t)-1)
+ goto err;
+
+ break;
+
+ default:
+ abort();
+ }
- switch (option) {
- case O_FILEENCODING:
- c2w = sp->conv.id + IC_FE_CHAR2INT;
- w2c = sp->conv.id + IC_FE_INT2CHAR;
- if (!enc) enc = O_STR(sp, O_FILEENCODING);
- if (*c2w != (iconv_t)-1)
- iconv_close(*c2w);
- if (*w2c != (iconv_t)-1)
- iconv_close(*w2c);
- if (strcasecmp(codeset(), enc)) {
- if ((*c2w = iconv_open(codeset(), enc)) == (iconv_t)-1)
- goto err;
- if ((*w2c = iconv_open(enc, codeset())) == (iconv_t)-1)
- goto err;
- } else *c2w = *w2c = (iconv_t)-1;
- break;
- case O_INPUTENCODING:
- c2w = sp->conv.id + IC_IE_CHAR2INT;
- w2c = sp->conv.id + IC_IE_TO_UTF16;
- if (!enc) enc = O_STR(sp, O_INPUTENCODING);
if (*c2w != (iconv_t)-1)
- iconv_close(*c2w);
+ iconv_close(*c2w);
if (*w2c != (iconv_t)-1)
- iconv_close(*w2c);
- if (strcasecmp(codeset(), enc)) {
- if ((*c2w = iconv_open(codeset(), enc)) == (iconv_t)-1)
- goto err;
- } else *c2w = (iconv_t)-1;
- /* UTF-16 can not be locale and can not be inputed. */
- if ((*w2c = iconv_open("utf-16be", enc)) == (iconv_t)-1)
- goto err;
- break;
- }
-
- F_CLR(sp, SC_CONV_ERROR);
- F_SET(sp, SC_SCR_REFORMAT);
-
- return 0;
+ iconv_close(*w2c);
+
+ *c2w = id_c2w;
+ *w2c = id_w2c;
+
+ F_CLR(sp, SC_CONV_ERROR);
+ F_SET(sp, SC_SCR_REFORMAT);
+
+ return 0;
err:
#endif
- switch (option) {
- case O_FILEENCODING:
- msgq(sp, M_ERR,
- "321|File encoding conversion not supported");
- break;
- case O_INPUTENCODING:
- msgq(sp, M_ERR,
- "322|Input encoding conversion not supported");
- break;
- }
- return 1;
+ switch (option) {
+ case O_FILEENCODING:
+ msgq(sp, M_ERR, "321|File encoding conversion not supported");
+ break;
+ case O_INPUTENCODING:
+ msgq(sp, M_ERR, "322|Input encoding conversion not supported");
+ break;
+ }
+ return 1;
}
/*
* conv_end --
* Close the iconv descriptors, release the buffer.
*
- * PUBLIC: void conv_end __P((SCR *));
+ * PUBLIC: void conv_end(SCR *);
*/
void
conv_end(SCR *sp)
{
#if defined(USE_WIDECHAR) && defined(USE_ICONV)
- int i;
- for (i = 0; i <= IC_IE_TO_UTF16; ++i)
- if (sp->conv.id[i] != (iconv_t)-1)
- iconv_close(sp->conv.id[i]);
+ int i;
+ for (i = 0; i <= IC_IE_TO_UTF16; ++i)
+ if (sp->conv.id[i] != (iconv_t)-1)
+ iconv_close(sp->conv.id[i]);
if (sp->cw.bp1.c != NULL)
- free(sp->cw.bp1.c);
+ free(sp->cw.bp1.c);
#endif
}
diff --git a/contrib/nvi/common/cut.c b/contrib/nvi/common/cut.c
index 11db42f..810aef6 100644
--- a/contrib/nvi/common/cut.c
+++ b/contrib/nvi/common/cut.c
@@ -27,7 +27,7 @@ static const char sccsid[] = "$Id: cut.c,v 10.12 2012/02/11 15:52:33 zy Exp $";
#include "common.h"
-static void cb_rotate __P((SCR *));
+static void cb_rotate(SCR *);
/*
* cut --
@@ -61,7 +61,7 @@ static void cb_rotate __P((SCR *));
* replacing the contents. Hopefully it's not worth getting right, and here
* we just treat the numeric buffers like any other named buffer.
*
- * PUBLIC: int cut __P((SCR *, CHAR_T *, MARK *, MARK *, int));
+ * PUBLIC: int cut(SCR *, CHAR_T *, MARK *, MARK *, int);
*/
int
cut(
@@ -222,7 +222,7 @@ cb_rotate(SCR *sp)
* cut_line --
* Cut a portion of a single line.
*
- * PUBLIC: int cut_line __P((SCR *, recno_t, size_t, size_t, CB *));
+ * PUBLIC: int cut_line(SCR *, recno_t, size_t, size_t, CB *);
*/
int
cut_line(
@@ -266,7 +266,7 @@ cut_line(
* cut_close --
* Discard all cut buffers.
*
- * PUBLIC: void cut_close __P((GS *));
+ * PUBLIC: void cut_close(GS *);
*/
void
cut_close(GS *gp)
@@ -291,7 +291,7 @@ cut_close(GS *gp)
* text_init --
* Allocate a new TEXT structure.
*
- * PUBLIC: TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t));
+ * PUBLIC: TEXT *text_init(SCR *, const CHAR_T *, size_t, size_t);
*/
TEXT *
text_init(
@@ -323,7 +323,7 @@ text_init(
* text_lfree --
* Free a chain of text structures.
*
- * PUBLIC: void text_lfree __P((TEXTH *));
+ * PUBLIC: void text_lfree(TEXTH *);
*/
void
text_lfree(TEXTH *headp)
@@ -340,7 +340,7 @@ text_lfree(TEXTH *headp)
* text_free --
* Free a text structure.
*
- * PUBLIC: void text_free __P((TEXT *));
+ * PUBLIC: void text_free(TEXT *);
*/
void
text_free(TEXT *tp)
diff --git a/contrib/nvi/common/delete.c b/contrib/nvi/common/delete.c
index bb476c0..b9bd038 100644
--- a/contrib/nvi/common/delete.c
+++ b/contrib/nvi/common/delete.c
@@ -30,7 +30,7 @@ static const char sccsid[] = "$Id: delete.c,v 10.18 2012/02/11 15:52:33 zy Exp $
* del --
* Delete a range of text.
*
- * PUBLIC: int del __P((SCR *, MARK *, MARK *, int));
+ * PUBLIC: int del(SCR *, MARK *, MARK *, int);
*/
int
del(
diff --git a/contrib/nvi/common/encoding.c b/contrib/nvi/common/encoding.c
index 6de509e..7bdcf70 100644
--- a/contrib/nvi/common/encoding.c
+++ b/contrib/nvi/common/encoding.c
@@ -11,10 +11,10 @@ static const char sccsid[] = "$Id: encoding.c,v 1.4 2011/12/13 19:40:52 zy Exp $
#include <sys/types.h>
-int looks_utf8 __P((const char *, size_t));
-int looks_utf16 __P((const char *, size_t));
-int decode_utf8 __P((const char *));
-int decode_utf16 __P((const char *, int));
+int looks_utf8(const char *, size_t);
+int looks_utf16(const char *, size_t);
+int decode_utf8(const char *);
+int decode_utf16(const char *, int);
#define F 0 /* character never appears in text */
#define T 1 /* character appears in plain ASCII text */
@@ -54,7 +54,7 @@ static char text_chars[256] = {
*
* Based on RFC 3629. UTF-8 with BOM is not accepted.
*
- * PUBLIC: int looks_utf8 __P((const char *, size_t));
+ * PUBLIC: int looks_utf8(const char *, size_t);
*/
int
looks_utf8(const char *ibuf, size_t nbytes)
@@ -115,7 +115,7 @@ done:
* 1: Little-endian UTF-16
* 2: Big-endian UTF-16
*
- * PUBLIC: int looks_utf16 __P((const char *, size_t));
+ * PUBLIC: int looks_utf16(const char *, size_t);
*/
int
looks_utf16(const char *ibuf, size_t nbytes)
@@ -175,9 +175,11 @@ looks_utf16(const char *ibuf, size_t nbytes)
*
* Based on RFC 3629, but without error detection.
*
- * PUBLIC: int decode_utf8 __P((const char *));
+ * PUBLIC: int decode_utf8(const char *);
*/
-int decode_utf8(const char *ibuf) {
+int
+decode_utf8(const char *ibuf)
+{
const u_char *buf = (u_char *)ibuf;
int u = -1;
@@ -194,6 +196,7 @@ int decode_utf8(const char *ibuf) {
u = (buf[0] ^ 0xF0) << 18 ^ (buf[1] ^ 0x80) << 12
^ (buf[2] ^ 0x80) << 6 ^ (buf[3] ^ 0x80);
}
+
return u;
}
@@ -204,9 +207,11 @@ int decode_utf8(const char *ibuf) {
*
* No error detection on supplementary bytes.
*
- * PUBLIC: int decode_utf16 __P((const char *, int));
+ * PUBLIC: int decode_utf16(const char *, int);
*/
-int decode_utf16(const char* ibuf, int bigend) {
+int
+decode_utf16(const char* ibuf, int bigend)
+{
const u_char *buf = (u_char *)ibuf;
int u = -1;
unsigned int w1, w2;
@@ -226,5 +231,6 @@ int decode_utf16(const char* ibuf, int bigend) {
w2 = buf[2] ^ buf[3] << 8;
u = ((w1 ^ 0xD800) << 10 ^ (w2 ^ 0xDC00)) + 0x10000;
}
+
return u;
}
diff --git a/contrib/nvi/common/exf.c b/contrib/nvi/common/exf.c
index 6579ab2..1fcf7f6 100644
--- a/contrib/nvi/common/exf.c
+++ b/contrib/nvi/common/exf.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: exf.c,v 10.62 2013/07/01 23:28:13 zy Exp $";
+static const char sccsid[] = "$Id: exf.c,v 10.64 2015/04/05 15:21:55 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -37,11 +37,11 @@ static const char sccsid[] = "$Id: exf.c,v 10.62 2013/07/01 23:28:13 zy Exp $";
#include "common.h"
-static int file_backup __P((SCR *, char *, char *));
-static void file_cinit __P((SCR *));
-static void file_encinit __P((SCR *));
-static void file_comment __P((SCR *));
-static int file_spath __P((SCR *, FREF *, struct stat *, int *));
+static int file_backup(SCR *, char *, char *);
+static void file_cinit(SCR *);
+static void file_encinit(SCR *);
+static void file_comment(SCR *);
+static int file_spath(SCR *, FREF *, struct stat *, int *);
/*
* file_add --
@@ -56,7 +56,7 @@ static int file_spath __P((SCR *, FREF *, struct stat *, int *));
* vi now remembers the last location in any file that it has ever edited,
* not just the previously edited file.
*
- * PUBLIC: FREF *file_add __P((SCR *, char *));
+ * PUBLIC: FREF *file_add(SCR *, char *);
*/
FREF *
file_add(
@@ -118,7 +118,7 @@ file_add(
* let go of any previous file. Don't release the previous file until
* absolutely sure we have the new one.
*
- * PUBLIC: int file_init __P((SCR *, FREF *, char *, int));
+ * PUBLIC: int file_init(SCR *, FREF *, char *, int);
*/
int
file_init(
@@ -259,6 +259,8 @@ file_init(
DB_RECNO, &oinfo)) == NULL) {
msgq_str(sp,
M_SYSERR, rcv_name == NULL ? oname : rcv_name, "%s");
+ if (F_ISSET(frp, FR_NEWFILE))
+ goto err;
/*
* !!!
* Historically, vi permitted users to edit files that couldn't
@@ -340,6 +342,8 @@ file_init(
break;
case LOCK_UNAVAIL:
readonly = 1;
+ if (F_ISSET(sp, SC_READONLY))
+ break;
msgq_str(sp, M_INFO, oname,
"239|%s already locked, session is read-only");
break;
@@ -625,7 +629,7 @@ file_cinit(SCR *sp)
* file_end --
* Stop editing a file.
*
- * PUBLIC: int file_end __P((SCR *, EXF *, int));
+ * PUBLIC: int file_end(SCR *, EXF *, int);
*/
int
file_end(
@@ -737,7 +741,7 @@ file_end(
* semantics for whether or not writes would happen. That's
* why all the flags.
*
- * PUBLIC: int file_write __P((SCR *, MARK *, MARK *, char *, int));
+ * PUBLIC: int file_write(SCR *, MARK *, MARK *, char *, int);
*/
int
file_write(
@@ -841,7 +845,6 @@ file_write(
return (1);
/* Open the file. */
- SIGBLOCK;
if ((fd = open(name, oflags,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0) {
if (errno == EACCES && LF_ISSET(FS_FORCE)) {
@@ -873,11 +876,9 @@ file_write(
errno = EACCES;
}
msgq_str(sp, M_SYSERR, name, "%s");
- SIGUNBLOCK;
return (1);
}
success_open:
- SIGUNBLOCK;
/* Try and get a lock. */
if (!noname && file_lock(sp, NULL, fd, 0) == LOCK_UNAVAIL)
@@ -1246,7 +1247,7 @@ file_encinit(SCR *sp)
if (looks_utf8(buf, blen) > 1)
o_set(sp, O_FILEENCODING, OS_STRDUP, "utf-8", 0);
else if (!O_ISSET(sp, O_FILEENCODING) ||
- !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-8", 5))
+ !strcasecmp(O_STR(sp, O_FILEENCODING), "utf-8"))
o_set(sp, O_FILEENCODING, OS_STRDUP, codeset(), 0);
conv_enc(sp, O_FILEENCODING, 0);
@@ -1302,7 +1303,7 @@ file_comment(SCR *sp)
* First modification check routine. The :next, :prev, :rewind, :tag,
* :tagpush, :tagpop, ^^ modifications check.
*
- * PUBLIC: int file_m1 __P((SCR *, int, int));
+ * PUBLIC: int file_m1(SCR *, int, int);
*/
int
file_m1(
@@ -1343,7 +1344,7 @@ file_m1(
* Second modification check routine. The :edit, :quit, :recover
* modifications check.
*
- * PUBLIC: int file_m2 __P((SCR *, int));
+ * PUBLIC: int file_m2(SCR *, int);
*/
int
file_m2(
@@ -1375,7 +1376,7 @@ file_m2(
* file_m3 --
* Third modification check routine.
*
- * PUBLIC: int file_m3 __P((SCR *, int));
+ * PUBLIC: int file_m3(SCR *, int);
*/
int
file_m3(
@@ -1411,7 +1412,7 @@ file_m3(
* is not set, write the file. A routine so there's a place to put the
* comment.
*
- * PUBLIC: int file_aw __P((SCR *, int));
+ * PUBLIC: int file_aw(SCR *, int);
*/
int
file_aw(
@@ -1472,7 +1473,7 @@ file_aw(
* If the user edits a temporary file, there may be times when there is no
* alternative file name. A name argument of NULL turns it off.
*
- * PUBLIC: void set_alt_name __P((SCR *, char *));
+ * PUBLIC: void set_alt_name(SCR *, char *);
*/
void
set_alt_name(
@@ -1491,7 +1492,7 @@ set_alt_name(
* file_lock --
* Get an exclusive lock on a file.
*
- * PUBLIC: lockr_t file_lock __P((SCR *, char *, int, int));
+ * PUBLIC: lockr_t file_lock(SCR *, char *, int, int);
*/
lockr_t
file_lock(
diff --git a/contrib/nvi/common/extern.h b/contrib/nvi/common/extern.h
index 20672e3..f8acf8e 100644
--- a/contrib/nvi/common/extern.h
+++ b/contrib/nvi/common/extern.h
@@ -1,132 +1,132 @@
-char * codeset __P((void));
-void conv_init __P((SCR *, SCR *));
-int conv_enc __P((SCR *, int, char *));
-void conv_end __P((SCR *));
-int cut __P((SCR *, CHAR_T *, MARK *, MARK *, int));
-int cut_line __P((SCR *, recno_t, size_t, size_t, CB *));
-void cut_close __P((GS *));
-TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t));
-void text_lfree __P((TEXTH *));
-void text_free __P((TEXT *));
-int del __P((SCR *, MARK *, MARK *, int));
-int looks_utf8 __P((const char *, size_t));
-int looks_utf16 __P((const char *, size_t));
-int decode_utf8 __P((const char *));
-int decode_utf16 __P((const char *, int));
-FREF *file_add __P((SCR *, char *));
-int file_init __P((SCR *, FREF *, char *, int));
-int file_end __P((SCR *, EXF *, int));
-int file_write __P((SCR *, MARK *, MARK *, char *, int));
-int file_m1 __P((SCR *, int, int));
-int file_m2 __P((SCR *, int));
-int file_m3 __P((SCR *, int));
-int file_aw __P((SCR *, int));
-void set_alt_name __P((SCR *, char *));
-lockr_t file_lock __P((SCR *, char *, int, int));
-int v_key_init __P((SCR *));
-void v_key_ilookup __P((SCR *));
-size_t v_key_len __P((SCR *, ARG_CHAR_T));
-char *v_key_name __P((SCR *, ARG_CHAR_T));
-e_key_t v_key_val __P((SCR *, ARG_CHAR_T));
-int v_event_push __P((SCR *, EVENT *, CHAR_T *, size_t, u_int));
-int v_event_get __P((SCR *, EVENT *, int, u_int32_t));
-void v_event_err __P((SCR *, EVENT *));
-int v_event_flush __P((SCR *, u_int));
-int db_eget __P((SCR *, recno_t, CHAR_T **, size_t *, int *));
-int db_get __P((SCR *, recno_t, u_int32_t, CHAR_T **, size_t *));
-int db_delete __P((SCR *, recno_t));
-int db_append __P((SCR *, int, recno_t, CHAR_T *, size_t));
-int db_insert __P((SCR *, recno_t, CHAR_T *, size_t));
-int db_set __P((SCR *, recno_t, CHAR_T *, size_t));
-int db_exist __P((SCR *, recno_t));
-int db_last __P((SCR *, recno_t *));
-int db_rget __P((SCR *, recno_t, char **, size_t *));
-int db_rset __P((SCR *, recno_t, char *, size_t));
-void db_err __P((SCR *, recno_t));
-int log_init __P((SCR *, EXF *));
-int log_end __P((SCR *, EXF *));
-int log_cursor __P((SCR *));
-int log_line __P((SCR *, recno_t, u_int));
-int log_mark __P((SCR *, LMARK *));
-int log_backward __P((SCR *, MARK *));
-int log_setline __P((SCR *));
-int log_forward __P((SCR *, MARK *));
-int editor __P((GS *, int, char *[]));
-void v_end __P((GS *));
-int mark_init __P((SCR *, EXF *));
-int mark_end __P((SCR *, EXF *));
-int mark_get __P((SCR *, ARG_CHAR_T, MARK *, mtype_t));
-int mark_set __P((SCR *, ARG_CHAR_T, MARK *, int));
-int mark_insdel __P((SCR *, lnop_t, recno_t));
-void msgq __P((SCR *, mtype_t, const char *, ...));
-void msgq_wstr __P((SCR *, mtype_t, const CHAR_T *, const char *));
-void msgq_str __P((SCR *, mtype_t, const char *, const char *));
-void mod_rpt __P((SCR *));
-void msgq_status __P((SCR *, recno_t, u_int));
-int msg_open __P((SCR *, char *));
-void msg_close __P((GS *));
-const char *msg_cmsg __P((SCR *, cmsg_t, size_t *));
-const char *msg_cat __P((SCR *, const char *, size_t *));
-char *msg_print __P((SCR *, const char *, int *));
-int opts_init __P((SCR *, int *));
-int opts_set __P((SCR *, ARGS *[], char *));
-int o_set __P((SCR *, int, u_int, char *, u_long));
-int opts_empty __P((SCR *, int, int));
-void opts_dump __P((SCR *, enum optdisp));
-int opts_save __P((SCR *, FILE *));
-OPTLIST const *opts_search __P((CHAR_T *));
-void opts_nomatch __P((SCR *, CHAR_T *));
-int opts_copy __P((SCR *, SCR *));
-void opts_free __P((SCR *));
-int f_altwerase __P((SCR *, OPTION *, char *, u_long *));
-int f_columns __P((SCR *, OPTION *, char *, u_long *));
-int f_lines __P((SCR *, OPTION *, char *, u_long *));
-int f_lisp __P((SCR *, OPTION *, char *, u_long *));
-int f_msgcat __P((SCR *, OPTION *, char *, u_long *));
-int f_print __P((SCR *, OPTION *, char *, u_long *));
-int f_readonly __P((SCR *, OPTION *, char *, u_long *));
-int f_recompile __P((SCR *, OPTION *, char *, u_long *));
-int f_reformat __P((SCR *, OPTION *, char *, u_long *));
-int f_ttywerase __P((SCR *, OPTION *, char *, u_long *));
-int f_w300 __P((SCR *, OPTION *, char *, u_long *));
-int f_w1200 __P((SCR *, OPTION *, char *, u_long *));
-int f_w9600 __P((SCR *, OPTION *, char *, u_long *));
-int f_window __P((SCR *, OPTION *, char *, u_long *));
-int f_encoding __P((SCR *, OPTION *, char *, u_long *));
-int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int));
-int rcv_tmp __P((SCR *, EXF *, char *));
-int rcv_init __P((SCR *));
-int rcv_sync __P((SCR *, u_int));
-int rcv_list __P((SCR *));
-int rcv_read __P((SCR *, FREF *));
-int screen_init __P((GS *, SCR *, SCR **));
-int screen_end __P((SCR *));
-SCR *screen_next __P((SCR *));
-int f_search __P((SCR *,
- MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
-int b_search __P((SCR *,
- MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
-void search_busy __P((SCR *, busy_t));
-int seq_set __P((SCR *, CHAR_T *,
- size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
-int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
-int seq_free __P((SEQ *));
+char * codeset(void);
+void conv_init(SCR *, SCR *);
+int conv_enc(SCR *, int, char *);
+void conv_end(SCR *);
+int cut(SCR *, CHAR_T *, MARK *, MARK *, int);
+int cut_line(SCR *, recno_t, size_t, size_t, CB *);
+void cut_close(GS *);
+TEXT *text_init(SCR *, const CHAR_T *, size_t, size_t);
+void text_lfree(TEXTH *);
+void text_free(TEXT *);
+int del(SCR *, MARK *, MARK *, int);
+int looks_utf8(const char *, size_t);
+int looks_utf16(const char *, size_t);
+int decode_utf8(const char *);
+int decode_utf16(const char *, int);
+FREF *file_add(SCR *, char *);
+int file_init(SCR *, FREF *, char *, int);
+int file_end(SCR *, EXF *, int);
+int file_write(SCR *, MARK *, MARK *, char *, int);
+int file_m1(SCR *, int, int);
+int file_m2(SCR *, int);
+int file_m3(SCR *, int);
+int file_aw(SCR *, int);
+void set_alt_name(SCR *, char *);
+lockr_t file_lock(SCR *, char *, int, int);
+int v_key_init(SCR *);
+void v_key_ilookup(SCR *);
+size_t v_key_len(SCR *, ARG_CHAR_T);
+char *v_key_name(SCR *, ARG_CHAR_T);
+e_key_t v_key_val(SCR *, ARG_CHAR_T);
+int v_event_push(SCR *, EVENT *, CHAR_T *, size_t, u_int);
+int v_event_get(SCR *, EVENT *, int, u_int32_t);
+void v_event_err(SCR *, EVENT *);
+int v_event_flush(SCR *, u_int);
+int db_eget(SCR *, recno_t, CHAR_T **, size_t *, int *);
+int db_get(SCR *, recno_t, u_int32_t, CHAR_T **, size_t *);
+int db_delete(SCR *, recno_t);
+int db_append(SCR *, int, recno_t, CHAR_T *, size_t);
+int db_insert(SCR *, recno_t, CHAR_T *, size_t);
+int db_set(SCR *, recno_t, CHAR_T *, size_t);
+int db_exist(SCR *, recno_t);
+int db_last(SCR *, recno_t *);
+int db_rget(SCR *, recno_t, char **, size_t *);
+int db_rset(SCR *, recno_t, char *, size_t);
+void db_err(SCR *, recno_t);
+int log_init(SCR *, EXF *);
+int log_end(SCR *, EXF *);
+int log_cursor(SCR *);
+int log_line(SCR *, recno_t, u_int);
+int log_mark(SCR *, LMARK *);
+int log_backward(SCR *, MARK *);
+int log_setline(SCR *);
+int log_forward(SCR *, MARK *);
+int editor(GS *, int, char *[]);
+void v_end(GS *);
+int mark_init(SCR *, EXF *);
+int mark_end(SCR *, EXF *);
+int mark_get(SCR *, ARG_CHAR_T, MARK *, mtype_t);
+int mark_set(SCR *, ARG_CHAR_T, MARK *, int);
+int mark_insdel(SCR *, lnop_t, recno_t);
+void msgq(SCR *, mtype_t, const char *, ...);
+void msgq_wstr(SCR *, mtype_t, const CHAR_T *, const char *);
+void msgq_str(SCR *, mtype_t, const char *, const char *);
+void mod_rpt(SCR *);
+void msgq_status(SCR *, recno_t, u_int);
+int msg_open(SCR *, char *);
+void msg_close(GS *);
+const char *msg_cmsg(SCR *, cmsg_t, size_t *);
+const char *msg_cat(SCR *, const char *, size_t *);
+char *msg_print(SCR *, const char *, int *);
+int opts_init(SCR *, int *);
+int opts_set(SCR *, ARGS *[], char *);
+int o_set(SCR *, int, u_int, char *, u_long);
+int opts_empty(SCR *, int, int);
+void opts_dump(SCR *, enum optdisp);
+int opts_save(SCR *, FILE *);
+OPTLIST const *opts_search(CHAR_T *);
+void opts_nomatch(SCR *, CHAR_T *);
+int opts_copy(SCR *, SCR *);
+void opts_free(SCR *);
+int f_altwerase(SCR *, OPTION *, char *, u_long *);
+int f_columns(SCR *, OPTION *, char *, u_long *);
+int f_lines(SCR *, OPTION *, char *, u_long *);
+int f_lisp(SCR *, OPTION *, char *, u_long *);
+int f_msgcat(SCR *, OPTION *, char *, u_long *);
+int f_print(SCR *, OPTION *, char *, u_long *);
+int f_readonly(SCR *, OPTION *, char *, u_long *);
+int f_recompile(SCR *, OPTION *, char *, u_long *);
+int f_reformat(SCR *, OPTION *, char *, u_long *);
+int f_ttywerase(SCR *, OPTION *, char *, u_long *);
+int f_w300(SCR *, OPTION *, char *, u_long *);
+int f_w1200(SCR *, OPTION *, char *, u_long *);
+int f_w9600(SCR *, OPTION *, char *, u_long *);
+int f_window(SCR *, OPTION *, char *, u_long *);
+int f_encoding(SCR *, OPTION *, char *, u_long *);
+int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int);
+int rcv_tmp(SCR *, EXF *, char *);
+int rcv_init(SCR *);
+int rcv_sync(SCR *, u_int);
+int rcv_list(SCR *);
+int rcv_read(SCR *, FREF *);
+int screen_init(GS *, SCR *, SCR **);
+int screen_end(SCR *);
+SCR *screen_next(SCR *);
+int f_search(SCR *,
+ MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int);
+int b_search(SCR *,
+ MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int);
+void search_busy(SCR *, busy_t);
+int seq_set(SCR *, CHAR_T *,
+ size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int);
+int seq_delete(SCR *, CHAR_T *, size_t, seq_t);
+int seq_free(SEQ *);
SEQ *seq_find
- __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
-void seq_close __P((GS *));
-int seq_dump __P((SCR *, seq_t, int));
-int seq_save __P((SCR *, FILE *, char *, seq_t));
-int e_memcmp __P((CHAR_T *, EVENT *, size_t));
-void *binc __P((SCR *, void *, size_t *, size_t));
-int nonblank __P((SCR *, recno_t, size_t *));
-char *tail __P((char *));
-char *join __P((char *, char *));
-char *expanduser __P((char *));
-char *quote __P((char *));
-char *v_strdup __P((SCR *, const char *, size_t));
-CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t));
-enum nresult nget_uslong __P((u_long *, const CHAR_T *, CHAR_T **, int));
-enum nresult nget_slong __P((long *, const CHAR_T *, CHAR_T **, int));
-void timepoint_steady __P((struct timespec *));
-void timepoint_system __P((struct timespec *));
-void TRACE __P((SCR *, const char *, ...));
+ (SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *);
+void seq_close(GS *);
+int seq_dump(SCR *, seq_t, int);
+int seq_save(SCR *, FILE *, char *, seq_t);
+int e_memcmp(CHAR_T *, EVENT *, size_t);
+void *binc(SCR *, void *, size_t *, size_t);
+int nonblank(SCR *, recno_t, size_t *);
+char *tail(char *);
+char *join(char *, char *);
+char *expanduser(char *);
+char *quote(char *);
+char *v_strdup(SCR *, const char *, size_t);
+CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t);
+enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int);
+enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int);
+void timepoint_steady(struct timespec *);
+void timepoint_system(struct timespec *);
+void TRACE(SCR *, const char *, ...);
diff --git a/contrib/nvi/common/gs.h b/contrib/nvi/common/gs.h
index 33a0245..4d0dc6f 100644
--- a/contrib/nvi/common/gs.h
+++ b/contrib/nvi/common/gs.h
@@ -144,73 +144,55 @@ struct _gs {
/* Screen interface functions. */
/* Add a string to the screen. */
- int (*scr_addstr) __P((SCR *, const char *, size_t));
+ int (*scr_addstr)(SCR *, const char *, size_t);
/* Add a string to the screen. */
- int (*scr_waddstr) __P((SCR *, const CHAR_T *, size_t));
+ int (*scr_waddstr)(SCR *, const CHAR_T *, size_t);
/* Toggle a screen attribute. */
- int (*scr_attr) __P((SCR *, scr_attr_t, int));
+ int (*scr_attr)(SCR *, scr_attr_t, int);
/* Terminal baud rate. */
- int (*scr_baud) __P((SCR *, u_long *));
+ int (*scr_baud)(SCR *, u_long *);
/* Beep/bell/flash the terminal. */
- int (*scr_bell) __P((SCR *));
+ int (*scr_bell)(SCR *);
/* Display a busy message. */
- void (*scr_busy) __P((SCR *, const char *, busy_t));
+ void (*scr_busy)(SCR *, const char *, busy_t);
/* Prepare child. */
- int (*scr_child) __P((SCR *));
+ int (*scr_child)(SCR *);
/* Clear to the end of the line. */
- int (*scr_clrtoeol) __P((SCR *));
+ int (*scr_clrtoeol)(SCR *);
/* Return the cursor location. */
- int (*scr_cursor) __P((SCR *, size_t *, size_t *));
+ int (*scr_cursor)(SCR *, size_t *, size_t *);
/* Delete a line. */
- int (*scr_deleteln) __P((SCR *));
+ int (*scr_deleteln)(SCR *);
/* Discard a screen. */
- int (*scr_discard) __P((SCR *, SCR **));
+ int (*scr_discard)(SCR *, SCR **);
/* Get a keyboard event. */
- int (*scr_event) __P((SCR *, EVENT *, u_int32_t, int));
+ int (*scr_event)(SCR *, EVENT *, u_int32_t, int);
/* Ex: screen adjustment routine. */
- int (*scr_ex_adjust) __P((SCR *, exadj_t));
+ int (*scr_ex_adjust)(SCR *, exadj_t);
int (*scr_fmap) /* Set a function key. */
- __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
+ (SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t);
/* Get terminal key value. */
- int (*scr_keyval) __P((SCR *, scr_keyval_t, CHAR_T *, int *));
+ int (*scr_keyval)(SCR *, scr_keyval_t, CHAR_T *, int *);
/* Insert a line. */
- int (*scr_insertln) __P((SCR *));
+ int (*scr_insertln)(SCR *);
/* Handle an option change. */
- int (*scr_optchange) __P((SCR *, int, char *, u_long *));
+ int (*scr_optchange)(SCR *, int, char *, u_long *);
/* Move the cursor. */
- int (*scr_move) __P((SCR *, size_t, size_t));
+ int (*scr_move)(SCR *, size_t, size_t);
/* Message or ex output. */
- void (*scr_msg) __P((SCR *, mtype_t, char *, size_t));
+ void (*scr_msg)(SCR *, mtype_t, char *, size_t);
/* Refresh the screen. */
- int (*scr_refresh) __P((SCR *, int));
+ int (*scr_refresh)(SCR *, int);
/* Rename the file. */
- int (*scr_rename) __P((SCR *, char *, int));
+ int (*scr_rename)(SCR *, char *, int);
/* Reply to an event. */
- int (*scr_reply) __P((SCR *, int, char *));
+ int (*scr_reply)(SCR *, int, char *);
/* Set the screen type. */
- int (*scr_screen) __P((SCR *, u_int32_t));
+ int (*scr_screen)(SCR *, u_int32_t);
/* Split the screen. */
- int (*scr_split) __P((SCR *, SCR *));
+ int (*scr_split)(SCR *, SCR *);
/* Suspend the editor. */
- int (*scr_suspend) __P((SCR *, int *));
+ int (*scr_suspend)(SCR *, int *);
/* Print usage message. */
- void (*scr_usage) __P((void));
+ void (*scr_usage)(void);
};
-
-/*
- * XXX
- * Block signals if there are asynchronous events. Used to keep DB system calls
- * from being interrupted and not restarted, as that will result in consistency
- * problems. This should be handled by DB.
- */
-#ifdef BLOCK_SIGNALS
-#include <signal.h>
-extern sigset_t __sigblockset;
-#define SIGBLOCK \
- (void)sigprocmask(SIG_BLOCK, &__sigblockset, NULL)
-#define SIGUNBLOCK \
- (void)sigprocmask(SIG_UNBLOCK, &__sigblockset, NULL);
-#else
-#define SIGBLOCK
-#define SIGUNBLOCK
-#endif
diff --git a/contrib/nvi/common/key.c b/contrib/nvi/common/key.c
index 9fc20b7..790c371 100644
--- a/contrib/nvi/common/key.c
+++ b/contrib/nvi/common/key.c
@@ -30,11 +30,11 @@ static const char sccsid[] = "$Id: key.c,v 10.54 2013/11/13 12:15:27 zy Exp $";
#include "common.h"
#include "../vi/vi.h"
-static int v_event_append __P((SCR *, EVENT *));
-static int v_event_grow __P((SCR *, int));
-static int v_key_cmp __P((const void *, const void *));
-static void v_keyval __P((SCR *, int, scr_keyval_t));
-static void v_sync __P((SCR *, int));
+static int v_event_append(SCR *, EVENT *);
+static int v_event_grow(SCR *, int);
+static int v_key_cmp(const void *, const void *);
+static void v_keyval(SCR *, int, scr_keyval_t);
+static void v_sync(SCR *, int);
/*
* !!!
@@ -97,7 +97,7 @@ static int nkeylist =
* v_key_init --
* Initialize the special key lookup table.
*
- * PUBLIC: int v_key_init __P((SCR *));
+ * PUBLIC: int v_key_init(SCR *);
*/
int
v_key_init(SCR *sp)
@@ -179,7 +179,7 @@ v_keyval(
* v_key_ilookup --
* Build the fast-lookup key display array.
*
- * PUBLIC: void v_key_ilookup __P((SCR *));
+ * PUBLIC: void v_key_ilookup(SCR *);
*/
void
v_key_ilookup(SCR *sp)
@@ -203,7 +203,7 @@ v_key_ilookup(SCR *sp)
* Return the length of the string that will display the key.
* This routine is the backup for the KEY_LEN() macro.
*
- * PUBLIC: size_t v_key_len __P((SCR *, ARG_CHAR_T));
+ * PUBLIC: size_t v_key_len(SCR *, ARG_CHAR_T);
*/
size_t
v_key_len(
@@ -219,7 +219,7 @@ v_key_len(
* Return the string that will display the key. This routine
* is the backup for the KEY_NAME() macro.
*
- * PUBLIC: char *v_key_name __P((SCR *, ARG_CHAR_T));
+ * PUBLIC: char *v_key_name(SCR *, ARG_CHAR_T);
*/
char *
v_key_name(
@@ -327,7 +327,7 @@ done: sp->cname[sp->clen = len] = '\0';
* Fill in the value for a key. This routine is the backup
* for the KEY_VAL() macro.
*
- * PUBLIC: e_key_t v_key_val __P((SCR *, ARG_CHAR_T));
+ * PUBLIC: e_key_t v_key_val(SCR *, ARG_CHAR_T);
*/
e_key_t
v_key_val(
@@ -351,7 +351,7 @@ v_key_val(
* an associated flag value, which indicates if it has already been quoted,
* and if it is the result of a mapping or an abbreviation.
*
- * PUBLIC: int v_event_push __P((SCR *, EVENT *, CHAR_T *, size_t, u_int));
+ * PUBLIC: int v_event_push(SCR *, EVENT *, CHAR_T *, size_t, u_int);
*/
int
v_event_push(
@@ -532,7 +532,7 @@ v_event_append(
* point. Given that this might make the log grow unacceptably (consider that
* cursor keys are done with maps), for now we leave any changes made in place.
*
- * PUBLIC: int v_event_get __P((SCR *, EVENT *, int, u_int32_t));
+ * PUBLIC: int v_event_get(SCR *, EVENT *, int, u_int32_t);
*/
int
v_event_get(
@@ -771,7 +771,7 @@ v_sync(
* v_event_err --
* Unexpected event.
*
- * PUBLIC: void v_event_err __P((SCR *, EVENT *));
+ * PUBLIC: void v_event_err(SCR *, EVENT *);
*/
void
v_event_err(
@@ -821,7 +821,7 @@ v_event_err(
* v_event_flush --
* Flush any flagged keys, returning if any keys were flushed.
*
- * PUBLIC: int v_event_flush __P((SCR *, u_int));
+ * PUBLIC: int v_event_flush(SCR *, u_int);
*/
int
v_event_flush(
diff --git a/contrib/nvi/common/line.c b/contrib/nvi/common/line.c
index 0bceccf..5549ad9 100644
--- a/contrib/nvi/common/line.c
+++ b/contrib/nvi/common/line.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: line.c,v 10.26 2011/08/12 12:36:41 zy Exp $";
+static const char sccsid[] = "$Id: line.c,v 10.27 2015/04/03 14:17:21 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -26,13 +26,13 @@ static const char sccsid[] = "$Id: line.c,v 10.26 2011/08/12 12:36:41 zy Exp $";
#include "common.h"
#include "../vi/vi.h"
-static int scr_update __P((SCR *, recno_t, lnop_t, int));
+static int scr_update(SCR *, recno_t, lnop_t, int);
/*
* db_eget --
* Front-end to db_get, special case handling for empty files.
*
- * PUBLIC: int db_eget __P((SCR *, recno_t, CHAR_T **, size_t *, int *));
+ * PUBLIC: int db_eget(SCR *, recno_t, CHAR_T **, size_t *, int *);
*/
int
db_eget(
@@ -76,7 +76,7 @@ db_eget(
* Look in the text buffers for a line, followed by the cache, followed
* by the database.
*
- * PUBLIC: int db_get __P((SCR *, recno_t, u_int32_t, CHAR_T **, size_t *));
+ * PUBLIC: int db_get(SCR *, recno_t, u_int32_t, CHAR_T **, size_t *);
*/
int
db_get(
@@ -92,7 +92,6 @@ db_get(
recno_t l1, l2;
CHAR_T *wp;
size_t wlen;
- size_t nlen;
/*
* The underlying recno stuff handles zero by returning NULL, but
@@ -152,8 +151,6 @@ db_get(
ep->c_lno = OOBLNO;
nocache:
- nlen = 1024;
-retry:
/* Get the line from the underlying database. */
key.data = &lno;
key.size = sizeof(lno);
@@ -169,11 +166,6 @@ err3: if (lenp != NULL)
if (pp != NULL)
*pp = NULL;
return (1);
- case 0:
- if (data.size > nlen) {
- nlen = data.size;
- goto retry;
- }
}
if (FILE2INT(sp, data.data, data.size, wp, wlen)) {
@@ -207,7 +199,7 @@ err3: if (lenp != NULL)
* db_delete --
* Delete a line from the file.
*
- * PUBLIC: int db_delete __P((SCR *, recno_t));
+ * PUBLIC: int db_delete(SCR *, recno_t);
*/
int
db_delete(
@@ -238,13 +230,11 @@ db_delete(
/* Update file. */
key.data = &lno;
key.size = sizeof(lno);
- SIGBLOCK;
if (ep->db->del(ep->db, &key, 0) == 1) {
msgq(sp, M_SYSERR,
"003|unable to delete line %lu", (u_long)lno);
return (1);
}
- SIGUNBLOCK;
/* Flush the cache, update line count, before screen update. */
if (lno <= ep->c_lno)
@@ -265,7 +255,7 @@ db_delete(
* db_append --
* Append a line into the file.
*
- * PUBLIC: int db_append __P((SCR *, int, recno_t, CHAR_T *, size_t));
+ * PUBLIC: int db_append(SCR *, int, recno_t, CHAR_T *, size_t);
*/
int
db_append(
@@ -297,13 +287,11 @@ db_append(
key.size = sizeof(lno);
data.data = fp;
data.size = flen;
- SIGBLOCK;
if (ep->db->put(ep->db, &key, &data, R_IAFTER) == -1) {
msgq(sp, M_SYSERR,
"004|unable to append to line %lu", (u_long)lno);
return (1);
}
- SIGUNBLOCK;
/* Flush the cache, update line count, before screen update. */
if (lno < ep->c_lno)
@@ -343,7 +331,7 @@ db_append(
* db_insert --
* Insert a line into the file.
*
- * PUBLIC: int db_insert __P((SCR *, recno_t, CHAR_T *, size_t));
+ * PUBLIC: int db_insert(SCR *, recno_t, CHAR_T *, size_t);
*/
int
db_insert(
@@ -375,13 +363,11 @@ db_insert(
key.size = sizeof(lno);
data.data = fp;
data.size = flen;
- SIGBLOCK;
if (ep->db->put(ep->db, &key, &data, R_IBEFORE) == -1) {
msgq(sp, M_SYSERR,
"005|unable to insert at line %lu", (u_long)lno);
return (1);
}
- SIGUNBLOCK;
/* Flush the cache, update line count, before screen update. */
if (lno >= ep->c_lno)
@@ -412,7 +398,7 @@ db_insert(
* db_set --
* Store a line in the file.
*
- * PUBLIC: int db_set __P((SCR *, recno_t, CHAR_T *, size_t));
+ * PUBLIC: int db_set(SCR *, recno_t, CHAR_T *, size_t);
*/
int
db_set(
@@ -446,13 +432,11 @@ db_set(
key.size = sizeof(lno);
data.data = fp;
data.size = flen;
- SIGBLOCK;
if (ep->db->put(ep->db, &key, &data, 0) == -1) {
msgq(sp, M_SYSERR,
"006|unable to store line %lu", (u_long)lno);
return (1);
}
- SIGUNBLOCK;
/* Flush the cache, before logging or screen update. */
if (lno == ep->c_lno)
@@ -474,7 +458,7 @@ db_set(
* db_exist --
* Return if a line exists.
*
- * PUBLIC: int db_exist __P((SCR *, recno_t));
+ * PUBLIC: int db_exist(SCR *, recno_t);
*/
int
db_exist(
@@ -509,7 +493,7 @@ db_exist(
* db_last --
* Return the number of lines in the file.
*
- * PUBLIC: int db_last __P((SCR *, recno_t *));
+ * PUBLIC: int db_last(SCR *, recno_t *);
*/
int
db_last(
@@ -552,8 +536,6 @@ alloc_err:
case 1:
*lnop = 0;
return (0);
- case 0:
- ;
}
memcpy(&lno, key.data, sizeof(lno));
@@ -581,9 +563,9 @@ alloc_err:
/*
* db_rget --
- * Retrieve a raw line from database. No cache, no conversion.
+ * Retrieve a raw line from the database.
*
- * PUBLIC: int db_rget __P((SCR *, recno_t, char **, size_t *));
+ * PUBLIC: int db_rget(SCR *, recno_t, char **, size_t *);
*/
int
db_rget(
@@ -593,31 +575,26 @@ db_rget(
size_t *lenp) /* Length store. */
{
DBT data, key;
- EXF *ep;
-
- /* Check for no underlying file. */
- if ((ep = sp->ep) == NULL)
- return (1);
+ EXF *ep = sp->ep;
+ int rval;
/* Get the line from the underlying database. */
key.data = &lno;
key.size = sizeof(lno);
- if (ep->db->get(ep->db, &key, &data, 0))
- /* We do not report error, and do not ensure the size! */
- return (1);
-
- if (lenp != NULL)
+ if ((rval = ep->db->get(ep->db, &key, &data, 0)) == 0)
+ {
*lenp = data.size;
- if (pp != NULL)
*pp = data.data;
- return (0);
+ }
+
+ return (rval);
}
/*
* db_rset --
- * Store a line in the file. No log, no conversion.
+ * Store a raw line into the database.
*
- * PUBLIC: int db_rset __P((SCR *, recno_t, char *, size_t));
+ * PUBLIC: int db_rset(SCR *, recno_t, char *, size_t);
*/
int
db_rset(
@@ -627,29 +604,21 @@ db_rset(
size_t len)
{
DBT data, key;
- EXF *ep;
+ EXF *ep = sp->ep;
- /* Check for no underlying file. */
- if ((ep = sp->ep) == NULL)
- return (1);
-
/* Update file. */
key.data = &lno;
key.size = sizeof(lno);
data.data = p;
data.size = len;
- if (ep->db->put(ep->db, &key, &data, 0) == -1)
- /* We do not report error, and do not ensure the size! */
- return (1);
-
- return (0);
+ return ep->db->put(ep->db, &key, &data, 0);
}
/*
* db_err --
* Report a line error.
*
- * PUBLIC: void db_err __P((SCR *, recno_t));
+ * PUBLIC: void db_err(SCR *, recno_t);
*/
void
db_err(
diff --git a/contrib/nvi/common/log.c b/contrib/nvi/common/log.c
index eb8d85b..5adfeaf 100644
--- a/contrib/nvi/common/log.c
+++ b/contrib/nvi/common/log.c
@@ -63,13 +63,13 @@ static const char sccsid[] = "$Id: log.c,v 10.27 2011/07/13 06:25:50 zy Exp $";
* behaved that way.
*/
-static int log_cursor1 __P((SCR *, int));
-static void log_err __P((SCR *, char *, int));
+static int log_cursor1(SCR *, int);
+static void log_err(SCR *, char *, int);
#if defined(DEBUG) && 0
-static void log_trace __P((SCR *, char *, recno_t, u_char *));
+static void log_trace(SCR *, char *, recno_t, u_char *);
#endif
-static int apply_with __P((int (*)(SCR *, recno_t, CHAR_T *, size_t),
- SCR *, recno_t, u_char *, size_t));
+static int apply_with(int (*)(SCR *, recno_t, CHAR_T *, size_t),
+ SCR *, recno_t, u_char *, size_t);
/* Try and restart the log on failure, i.e. if we run out of memory. */
#define LOG_ERR { \
@@ -81,8 +81,8 @@ static int apply_with __P((int (*)(SCR *, recno_t, CHAR_T *, size_t),
* because it is passed to db_set as a string
*/
typedef struct {
- char data[sizeof(u_char) /* type */ + sizeof(recno_t)];
- CHAR_T str[1];
+ char data[sizeof(u_char) /* type */ + sizeof(recno_t)];
+ CHAR_T str[1];
} log_t;
#define CHAR_T_OFFSET ((char *)(((log_t*)0)->str) - (char *)0)
@@ -90,7 +90,7 @@ typedef struct {
* log_init --
* Initialize the logging subsystem.
*
- * PUBLIC: int log_init __P((SCR *, EXF *));
+ * PUBLIC: int log_init(SCR *, EXF *);
*/
int
log_init(
@@ -126,7 +126,7 @@ log_init(
* log_end --
* Close the logging subsystem.
*
- * PUBLIC: int log_end __P((SCR *, EXF *));
+ * PUBLIC: int log_end(SCR *, EXF *);
*/
int
log_end(
@@ -156,7 +156,7 @@ log_end(
* log_cursor --
* Log the current cursor position, starting an event.
*
- * PUBLIC: int log_cursor __P((SCR *));
+ * PUBLIC: int log_cursor(SCR *);
*/
int
log_cursor(SCR *sp)
@@ -221,7 +221,7 @@ log_cursor1(
* log_line --
* Log a line change.
*
- * PUBLIC: int log_line __P((SCR *, recno_t, u_int));
+ * PUBLIC: int log_line(SCR *, recno_t, u_int);
*/
int
log_line(
@@ -324,7 +324,7 @@ log_line(
* would mean that undo operations would only reset marks, and not
* cause any other change.
*
- * PUBLIC: int log_mark __P((SCR *, LMARK *));
+ * PUBLIC: int log_mark(SCR *, LMARK *);
*/
int
log_mark(
@@ -370,7 +370,7 @@ log_mark(
* Log_backward --
* Roll the log backward one operation.
*
- * PUBLIC: int log_backward __P((SCR *, MARK *));
+ * PUBLIC: int log_backward(SCR *, MARK *);
*/
int
log_backward(
@@ -474,7 +474,7 @@ err: F_CLR(ep, F_NOLOG);
* then move back on and do a 'U', the line will be restored to the way
* it was before the original change.
*
- * PUBLIC: int log_setline __P((SCR *));
+ * PUBLIC: int log_setline(SCR *);
*/
int
log_setline(SCR *sp)
@@ -558,7 +558,7 @@ err: F_CLR(ep, F_NOLOG);
* Log_forward --
* Roll the log forward one operation.
*
- * PUBLIC: int log_forward __P((SCR *, MARK *));
+ * PUBLIC: int log_forward(SCR *, MARK *);
*/
int
log_forward(
diff --git a/contrib/nvi/common/main.c b/contrib/nvi/common/main.c
index 6ff4181..d9ae96f 100644
--- a/contrib/nvi/common/main.c
+++ b/contrib/nvi/common/main.c
@@ -10,14 +10,6 @@
#include "config.h"
#ifndef lint
-static const char copyright[] =
-"@(#) Copyright (c) 1992, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n\
-@(#) Copyright (c) 1992, 1993, 1994, 1995, 1996\n\
- Keith Bostic. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
static const char sccsid[] = "$Id: main.c,v 11.0 2012/10/17 06:34:37 zy Exp $";
#endif /* not lint */
@@ -38,15 +30,15 @@ static const char sccsid[] = "$Id: main.c,v 11.0 2012/10/17 06:34:37 zy Exp $";
#include "../vi/vi.h"
#include "pathnames.h"
-static void attach __P((GS *));
-static void v_estr __P((char *, int, char *));
-static int v_obsolete __P((char *, char *[]));
+static void attach(GS *);
+static void v_estr(char *, int, char *);
+static int v_obsolete(char *, char *[]);
/*
* editor --
* Main editor routine.
*
- * PUBLIC: int editor __P((GS *, int, char *[]));
+ * PUBLIC: int editor(GS *, int, char *[]);
*/
int
editor(
@@ -436,7 +428,7 @@ err: rval = 1;
* v_end --
* End the program, discarding screens and most of the global area.
*
- * PUBLIC: void v_end __P((GS *));
+ * PUBLIC: void v_end(GS *);
*/
void
v_end(gp)
@@ -455,7 +447,7 @@ v_end(gp)
while ((sp = TAILQ_FIRST(gp->hq)) != NULL)
(void)screen_end(sp);
-#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
+#if defined(DEBUG) || defined(PURIFY)
{ FREF *frp;
/* Free FREF's. */
while ((frp = TAILQ_FIRST(gp->frefq)) != NULL) {
@@ -499,13 +491,13 @@ v_end(gp)
(void)fprintf(stderr, "%s%.*s",
mp->mtype == M_ERR ? "ex/vi: " : "", (int)mp->len, mp->buf);
SLIST_REMOVE_HEAD(gp->msgq, q);
-#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
+#if defined(DEBUG) || defined(PURIFY)
free(mp->buf);
free(mp);
#endif
}
-#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
+#if defined(DEBUG) || defined(PURIFY)
/* Free any temporary space. */
if (gp->tmp_bp != NULL)
free(gp->tmp_bp);
diff --git a/contrib/nvi/common/mark.c b/contrib/nvi/common/mark.c
index 7a95439..a3158e4 100644
--- a/contrib/nvi/common/mark.c
+++ b/contrib/nvi/common/mark.c
@@ -26,7 +26,7 @@ static const char sccsid[] = "$Id: mark.c,v 10.14 2011/07/04 14:42:58 zy Exp $";
#include "common.h"
-static LMARK *mark_find __P((SCR *, ARG_CHAR_T));
+static LMARK *mark_find(SCR *, ARG_CHAR_T);
/*
* Marks are maintained in a key sorted singly linked list. We can't
@@ -63,7 +63,7 @@ static LMARK *mark_find __P((SCR *, ARG_CHAR_T));
* mark_init --
* Set up the marks.
*
- * PUBLIC: int mark_init __P((SCR *, EXF *));
+ * PUBLIC: int mark_init(SCR *, EXF *);
*/
int
mark_init(
@@ -84,7 +84,7 @@ mark_init(
* mark_end --
* Free up the marks.
*
- * PUBLIC: int mark_end __P((SCR *, EXF *));
+ * PUBLIC: int mark_end(SCR *, EXF *);
*/
int
mark_end(
@@ -108,7 +108,7 @@ mark_end(
* mark_get --
* Get the location referenced by a mark.
*
- * PUBLIC: int mark_get __P((SCR *, ARG_CHAR_T, MARK *, mtype_t));
+ * PUBLIC: int mark_get(SCR *, ARG_CHAR_T, MARK *, mtype_t);
*/
int
mark_get(
@@ -125,12 +125,12 @@ mark_get(
lmp = mark_find(sp, key);
if (lmp == NULL || lmp->name != key) {
msgq(sp, mtype, "017|Mark %s: not set", KEY_NAME(sp, key));
- return (1);
+ return (1);
}
if (F_ISSET(lmp, MARK_DELETED)) {
msgq(sp, mtype,
"018|Mark %s: the line was deleted", KEY_NAME(sp, key));
- return (1);
+ return (1);
}
/*
@@ -153,7 +153,7 @@ mark_get(
* mark_set --
* Set the location referenced by a mark.
*
- * PUBLIC: int mark_set __P((SCR *, ARG_CHAR_T, MARK *, int));
+ * PUBLIC: int mark_set(SCR *, ARG_CHAR_T, MARK *, int);
*/
int
mark_set(
@@ -220,7 +220,7 @@ mark_find(
* mark_insdel --
* Update the marks based on an insertion or deletion.
*
- * PUBLIC: int mark_insdel __P((SCR *, lnop_t, recno_t));
+ * PUBLIC: int mark_insdel(SCR *, lnop_t, recno_t);
*/
int
mark_insdel(
diff --git a/contrib/nvi/common/msg.c b/contrib/nvi/common/msg.c
index c0930b8..3099b1e 100644
--- a/contrib/nvi/common/msg.c
+++ b/contrib/nvi/common/msg.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: msg.c,v 11.0 2012/10/17 06:34:37 zy Exp $";
+static const char sccsid[] = "$Id: msg.c,v 11.1 2015/02/09 11:12:44 marc Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -36,7 +36,7 @@ static const char sccsid[] = "$Id: msg.c,v 11.0 2012/10/17 06:34:37 zy Exp $";
* msgq --
* Display a message.
*
- * PUBLIC: void msgq __P((SCR *, mtype_t, const char *, ...));
+ * PUBLIC: void msgq(SCR *, mtype_t, const char *, ...);
*/
void
msgq(
@@ -60,7 +60,7 @@ msgq(
size_t blen, len, mlen, nlen;
const char *p;
char *bp, *mp;
- va_list ap;
+ va_list ap;
#ifndef NL_ARGMAX
int ch;
char *rbp, *s_rbp;
@@ -274,7 +274,7 @@ retry: FREE_SPACE(sp, bp, blen);
#ifndef NL_ARGMAX
format: /* Format the arguments into the string. */
#endif
- va_start(ap, fmt);
+ va_start(ap, fmt);
len = vsnprintf(mp, REM, fmt, ap);
va_end(ap);
if (len >= nlen)
@@ -356,7 +356,7 @@ alloc_err:
* msgq_wstr --
* Display a message with an embedded string.
*
- * PUBLIC: void msgq_wstr __P((SCR *, mtype_t, const CHAR_T *, const char *));
+ * PUBLIC: void msgq_wstr(SCR *, mtype_t, const CHAR_T *, const char *);
*/
void
msgq_wstr(
@@ -380,7 +380,7 @@ msgq_wstr(
* msgq_str --
* Display a message with an embedded string.
*
- * PUBLIC: void msgq_str __P((SCR *, mtype_t, const char *, const char *));
+ * PUBLIC: void msgq_str(SCR *, mtype_t, const char *, const char *);
*/
void
msgq_str(
@@ -423,7 +423,7 @@ msgq_str(
* the command 2d}, from the 'b' would report that two lines were deleted,
* not one.
*
- * PUBLIC: void mod_rpt __P((SCR *));
+ * PUBLIC: void mod_rpt(SCR *);
*/
void
mod_rpt(SCR *sp)
@@ -533,7 +533,7 @@ alloc_err:
* msgq_status --
* Report on the file's status.
*
- * PUBLIC: void msgq_status __P((SCR *, recno_t, u_int));
+ * PUBLIC: void msgq_status(SCR *, recno_t, u_int);
*/
void
msgq_status(
@@ -647,7 +647,7 @@ msgq_status(
p += len;
} else {
t = msg_cat(sp, "027|line %lu of %lu [%ld%%]", &len);
- (void)snprintf(p, ep - p, t, lno, last,
+ (void)snprintf(p, ep - p, t, (u_long)lno, (u_long)last,
((u_long)lno * 100) / last);
p += strlen(p);
}
@@ -705,7 +705,7 @@ alloc_err:
* msg_open --
* Open the message catalogs.
*
- * PUBLIC: int msg_open __P((SCR *, char *));
+ * PUBLIC: int msg_open(SCR *, char *);
*/
int
msg_open(
@@ -772,7 +772,7 @@ ret: free(p);
* msg_close --
* Close the message catalogs.
*
- * PUBLIC: void msg_close __P((GS *));
+ * PUBLIC: void msg_close(GS *);
*/
void
msg_close(GS *gp)
@@ -785,7 +785,7 @@ msg_close(GS *gp)
* msg_cont --
* Return common continuation messages.
*
- * PUBLIC: const char *msg_cmsg __P((SCR *, cmsg_t, size_t *));
+ * PUBLIC: const char *msg_cmsg(SCR *, cmsg_t, size_t *);
*/
const char *
msg_cmsg(
@@ -823,7 +823,7 @@ msg_cmsg(
* Only a single catalog message can be accessed at a time, if multiple
* ones are needed, they must be copied into local memory.
*
- * PUBLIC: const char *msg_cat __P((SCR *, const char *, size_t *));
+ * PUBLIC: const char *msg_cat(SCR *, const char *, size_t *);
*/
const char *
msg_cat(
@@ -861,7 +861,7 @@ msg_cat(
* msg_print --
* Return a printable version of a string, in allocated memory.
*
- * PUBLIC: char *msg_print __P((SCR *, const char *, int *));
+ * PUBLIC: char *msg_print(SCR *, const char *, int *);
*/
char *
msg_print(
diff --git a/contrib/nvi/common/options.c b/contrib/nvi/common/options.c
index 71a5e43..e619d8f 100644
--- a/contrib/nvi/common/options.c
+++ b/contrib/nvi/common/options.c
@@ -30,9 +30,9 @@ static const char sccsid[] = "$Id: options.c,v 10.73 2012/10/09 06:14:07 zy Exp
#include "../vi/vi.h"
#include "pathnames.h"
-static int opts_abbcmp __P((const void *, const void *));
-static int opts_cmp __P((const void *, const void *));
-static int opts_print __P((SCR *, OPTLIST const *));
+static int opts_abbcmp(const void *, const void *);
+static int opts_cmp(const void *, const void *);
+static int opts_print(SCR *, OPTLIST const *);
#ifdef USE_WIDECHAR
#define OPT_WC 0
@@ -243,8 +243,8 @@ OPTLIST const optlist[] = {
};
typedef struct abbrev {
- CHAR_T *name;
- int offset;
+ CHAR_T *name;
+ int offset;
} OABBREV;
static OABBREV const abbrev[] = {
@@ -294,7 +294,7 @@ static OABBREV const abbrev[] = {
* opts_init --
* Initialize some of the options.
*
- * PUBLIC: int opts_init __P((SCR *, int *));
+ * PUBLIC: int opts_init(SCR *, int *);
*/
int
opts_init(
@@ -460,7 +460,7 @@ err: msgq_wstr(sp, M_ERR, optlist[optindx].name,
* opts_set --
* Change the values of one or more options.
*
- * PUBLIC: int opts_set __P((SCR *, ARGS *[], char *));
+ * PUBLIC: int opts_set(SCR *, ARGS *[], char *);
*/
int
opts_set(
@@ -754,7 +754,7 @@ badnum: INT2CHAR(sp, name, STRLEN(name) + 1,
* o_set --
* Set an option's value.
*
- * PUBLIC: int o_set __P((SCR *, int, u_int, char *, u_long));
+ * PUBLIC: int o_set(SCR *, int, u_int, char *, u_long);
*/
int
o_set(
@@ -798,7 +798,7 @@ o_set(
* opts_empty --
* Return 1 if the string option is invalid, 0 if it's OK.
*
- * PUBLIC: int opts_empty __P((SCR *, int, int));
+ * PUBLIC: int opts_empty(SCR *, int, int);
*/
int
opts_empty(
@@ -821,7 +821,7 @@ opts_empty(
* opts_dump --
* List the current values of selected options.
*
- * PUBLIC: void opts_dump __P((SCR *, enum optdisp));
+ * PUBLIC: void opts_dump(SCR *, enum optdisp);
*/
void
opts_dump(
@@ -987,7 +987,7 @@ opts_print(
* opts_save --
* Write the current configuration to a file.
*
- * PUBLIC: int opts_save __P((SCR *, FILE *));
+ * PUBLIC: int opts_save(SCR *, FILE *);
*/
int
opts_save(
@@ -1045,7 +1045,7 @@ opts_save(
* opts_search --
* Search for an option.
*
- * PUBLIC: OPTLIST const *opts_search __P((CHAR_T *));
+ * PUBLIC: OPTLIST const *opts_search(CHAR_T *);
*/
OPTLIST const *
opts_search(CHAR_T *name)
@@ -1090,7 +1090,7 @@ opts_search(CHAR_T *name)
* opts_nomatch --
* Standard nomatch error message for options.
*
- * PUBLIC: void opts_nomatch __P((SCR *, CHAR_T *));
+ * PUBLIC: void opts_nomatch(SCR *, CHAR_T *);
*/
void
opts_nomatch(
@@ -1103,25 +1103,25 @@ opts_nomatch(
static int
opts_abbcmp(
- const void *a,
- const void *b)
+ const void *a,
+ const void *b)
{
- return(STRCMP(((OABBREV *)a)->name, ((OABBREV *)b)->name));
+ return(STRCMP(((OABBREV *)a)->name, ((OABBREV *)b)->name));
}
static int
opts_cmp(
- const void *a,
- const void *b)
+ const void *a,
+ const void *b)
{
- return(STRCMP(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
+ return(STRCMP(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
}
/*
* opts_copy --
* Copy a screen's OPTION array.
*
- * PUBLIC: int opts_copy __P((SCR *, SCR *));
+ * PUBLIC: int opts_copy(SCR *, SCR *);
*/
int
opts_copy(
@@ -1169,7 +1169,7 @@ nomem: msgq(orig, M_SYSERR, NULL);
* opts_free --
* Free all option strings
*
- * PUBLIC: void opts_free __P((SCR *));
+ * PUBLIC: void opts_free(SCR *);
*/
void
opts_free(SCR *sp)
diff --git a/contrib/nvi/common/options.h b/contrib/nvi/common/options.h
index fe1f80f..aaeece1 100644
--- a/contrib/nvi/common/options.h
+++ b/contrib/nvi/common/options.h
@@ -78,7 +78,7 @@ struct _option {
struct _optlist {
CHAR_T *name; /* Name. */
/* Change function. */
- int (*func) __P((SCR *, OPTION *, char *, u_long *));
+ int (*func)(SCR *, OPTION *, char *, u_long *);
/* Type of object. */
enum { OPT_0BOOL, OPT_1BOOL, OPT_NUM, OPT_STR } type;
diff --git a/contrib/nvi/common/options_f.c b/contrib/nvi/common/options_f.c
index 482a37e..850bfc2 100644
--- a/contrib/nvi/common/options_f.c
+++ b/contrib/nvi/common/options_f.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: options_f.c,v 10.34 04/07/11 16:06:29 zy Exp
#include "common.h"
/*
- * PUBLIC: int f_altwerase __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_altwerase(SCR *, OPTION *, char *, u_long *);
*/
int
f_altwerase(
@@ -44,7 +44,7 @@ f_altwerase(
}
/*
- * PUBLIC: int f_columns __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_columns(SCR *, OPTION *, char *, u_long *);
*/
int
f_columns(
@@ -78,7 +78,7 @@ f_columns(
}
/*
- * PUBLIC: int f_lines __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_lines(SCR *, OPTION *, char *, u_long *);
*/
int
f_lines(
@@ -135,7 +135,7 @@ f_lines(
}
/*
- * PUBLIC: int f_lisp __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_lisp(SCR *, OPTION *, char *, u_long *);
*/
int
f_lisp(
@@ -149,7 +149,7 @@ f_lisp(
}
/*
- * PUBLIC: int f_msgcat __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_msgcat(SCR *, OPTION *, char *, u_long *);
*/
int
f_msgcat(
@@ -163,7 +163,7 @@ f_msgcat(
}
/*
- * PUBLIC: int f_print __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_print(SCR *, OPTION *, char *, u_long *);
*/
int
f_print(
@@ -192,7 +192,7 @@ f_print(
}
/*
- * PUBLIC: int f_readonly __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_readonly(SCR *, OPTION *, char *, u_long *);
*/
int
f_readonly(
@@ -213,7 +213,7 @@ f_readonly(
}
/*
- * PUBLIC: int f_recompile __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_recompile(SCR *, OPTION *, char *, u_long *);
*/
int
f_recompile(
@@ -234,7 +234,7 @@ f_recompile(
}
/*
- * PUBLIC: int f_reformat __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_reformat(SCR *, OPTION *, char *, u_long *);
*/
int
f_reformat(
@@ -248,7 +248,7 @@ f_reformat(
}
/*
- * PUBLIC: int f_ttywerase __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_ttywerase(SCR *, OPTION *, char *, u_long *);
*/
int
f_ttywerase(
@@ -263,7 +263,7 @@ f_ttywerase(
}
/*
- * PUBLIC: int f_w300 __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_w300(SCR *, OPTION *, char *, u_long *);
*/
int
f_w300(
@@ -284,7 +284,7 @@ f_w300(
}
/*
- * PUBLIC: int f_w1200 __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_w1200(SCR *, OPTION *, char *, u_long *);
*/
int
f_w1200(
@@ -305,7 +305,7 @@ f_w1200(
}
/*
- * PUBLIC: int f_w9600 __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_w9600(SCR *, OPTION *, char *, u_long *);
*/
int
f_w9600(
@@ -326,7 +326,7 @@ f_w9600(
}
/*
- * PUBLIC: int f_window __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_window(SCR *, OPTION *, char *, u_long *);
*/
int
f_window(
@@ -342,7 +342,7 @@ f_window(
}
/*
- * PUBLIC: int f_encoding __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_encoding(SCR *, OPTION *, char *, u_long *);
*/
int
f_encoding(
diff --git a/contrib/nvi/common/put.c b/contrib/nvi/common/put.c
index 6e9dc09..d3adf5c 100644
--- a/contrib/nvi/common/put.c
+++ b/contrib/nvi/common/put.c
@@ -30,7 +30,7 @@ static const char sccsid[] = "$Id: put.c,v 10.19 04/07/11 17:00:24 zy Exp $";
* put --
* Put text buffer contents into the file.
*
- * PUBLIC: int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int));
+ * PUBLIC: int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int);
*/
int
put(
diff --git a/contrib/nvi/common/recover.c b/contrib/nvi/common/recover.c
index b20471f..d0a927b 100644
--- a/contrib/nvi/common/recover.c
+++ b/contrib/nvi/common/recover.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: recover.c,v 11.2 2012/10/09 08:06:58 zy Exp $";
+static const char sccsid[] = "$Id: recover.c,v 11.3 2015/04/04 03:50:42 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -102,18 +102,18 @@ static const char sccsid[] = "$Id: recover.c,v 11.2 2012/10/09 08:06:58 zy Exp $
#define VI_DHEADER "X-vi-data:"
-static int rcv_copy __P((SCR *, int, char *));
-static void rcv_email __P((SCR *, char *));
-static int rcv_mailfile __P((SCR *, int, char *));
-static int rcv_mktemp __P((SCR *, char *, char *));
-static int rcv_dlnwrite __P((SCR *, const char *, const char *, FILE *));
-static int rcv_dlnread __P((SCR *, char **, char **, FILE *));
+static int rcv_copy(SCR *, int, char *);
+static void rcv_email(SCR *, char *);
+static int rcv_mailfile(SCR *, int, char *);
+static int rcv_mktemp(SCR *, char *, char *);
+static int rcv_dlnwrite(SCR *, const char *, const char *, FILE *);
+static int rcv_dlnread(SCR *, char **, char **, FILE *);
/*
* rcv_tmp --
* Build a file name that will be used as the recovery file.
*
- * PUBLIC: int rcv_tmp __P((SCR *, EXF *, char *));
+ * PUBLIC: int rcv_tmp(SCR *, EXF *, char *);
*/
int
rcv_tmp(
@@ -172,7 +172,7 @@ err: msgq(sp, M_ERR,
* rcv_init --
* Force the file to be snapshotted for recovery.
*
- * PUBLIC: int rcv_init __P((SCR *));
+ * PUBLIC: int rcv_init(SCR *);
*/
int
rcv_init(SCR *sp)
@@ -234,7 +234,7 @@ err: msgq(sp, M_ERR,
* sending email to the user if the file was modified
* ending the file session
*
- * PUBLIC: int rcv_sync __P((SCR *, u_int));
+ * PUBLIC: int rcv_sync(SCR *, u_int);
*/
int
rcv_sync(
@@ -252,15 +252,12 @@ rcv_sync(
/* Sync the file if it's been modified. */
if (F_ISSET(ep, F_MODIFIED)) {
- SIGBLOCK;
if (ep->db->sync(ep->db, R_RECNOSYNC)) {
F_CLR(ep, F_RCV_ON | F_RCV_NORM);
msgq_str(sp, M_SYSERR,
ep->rcv_path, "060|File backup failed: %s");
- SIGUNBLOCK;
return (1);
}
- SIGUNBLOCK;
/* REQUEST: don't remove backing file on exit. */
if (LF_ISSET(RCV_PRESERVE))
@@ -505,7 +502,7 @@ err: if (!issync)
* rcv_list --
* List the files that can be recovered by this user.
*
- * PUBLIC: int rcv_list __P((SCR *));
+ * PUBLIC: int rcv_list(SCR *);
*/
int
rcv_list(SCR *sp)
@@ -612,7 +609,7 @@ next: (void)fclose(fp);
* rcv_read --
* Start a recovered file as the file to edit.
*
- * PUBLIC: int rcv_read __P((SCR *, FREF *));
+ * PUBLIC: int rcv_read(SCR *, FREF *);
*/
int
rcv_read(
@@ -635,7 +632,7 @@ rcv_read(
return (1);
rp = O_STR(sp, O_RECDIR);
if ((dirp = opendir(rp)) == NULL) {
- msgq_str(sp, M_ERR, rp, "%s");
+ msgq_str(sp, M_SYSERR, rp, "%s");
return (1);
}
diff --git a/contrib/nvi/common/screen.c b/contrib/nvi/common/screen.c
index 9ff6845..ae6fb20 100644
--- a/contrib/nvi/common/screen.c
+++ b/contrib/nvi/common/screen.c
@@ -32,7 +32,7 @@ static const char sccsid[] = "$Id: screen.c,v 10.25 2011/12/04 04:06:45 zy Exp $
* screen_init --
* Do the default initialization of an SCR structure.
*
- * PUBLIC: int screen_init __P((GS *, SCR *, SCR **));
+ * PUBLIC: int screen_init(GS *, SCR *, SCR **);
*/
int
screen_init(
@@ -129,7 +129,7 @@ err: screen_end(sp);
* Release a screen, no matter what had (and had not) been
* initialized.
*
- * PUBLIC: int screen_end __P((SCR *));
+ * PUBLIC: int screen_end(SCR *);
*/
int
screen_end(SCR *sp)
@@ -205,7 +205,7 @@ screen_end(SCR *sp)
* screen_next --
* Return the next screen in the queue.
*
- * PUBLIC: SCR *screen_next __P((SCR *));
+ * PUBLIC: SCR *screen_next(SCR *);
*/
SCR *
screen_next(SCR *sp)
diff --git a/contrib/nvi/common/search.c b/contrib/nvi/common/search.c
index 22f0203..4831a08 100644
--- a/contrib/nvi/common/search.c
+++ b/contrib/nvi/common/search.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: search.c,v 10.26 2011/07/04 20:16:26 zy Exp $";
+static const char sccsid[] = "$Id: search.c,v 10.27 2015/03/13 18:41:35 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -30,8 +30,8 @@ static const char sccsid[] = "$Id: search.c,v 10.26 2011/07/04 20:16:26 zy Exp $
typedef enum { S_EMPTY, S_EOF, S_NOPREV, S_NOTFOUND, S_SOF, S_WRAP } smsg_t;
-static void search_msg __P((SCR *, smsg_t));
-static int search_init __P((SCR *, dir_t, CHAR_T *, size_t, CHAR_T **, u_int));
+static void search_msg(SCR *, smsg_t);
+static int search_init(SCR *, dir_t, CHAR_T *, size_t, CHAR_T **, u_int);
/*
* search_init --
@@ -142,8 +142,8 @@ prev: if (sp->re == NULL) {
* f_search --
* Do a forward search.
*
- * PUBLIC: int f_search __P((SCR *,
- * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
+ * PUBLIC: int f_search(SCR *,
+ * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int);
*/
int
f_search(
@@ -159,7 +159,7 @@ f_search(
recno_t lno;
regmatch_t match[1];
size_t coff, len;
- int cnt, eval, rval, wrapped;
+ int cnt, eval, rval, wrapped = 0;
CHAR_T *l;
if (search_init(sp, FORWARD, ptrn, plen, eptrn, flags))
@@ -198,13 +198,14 @@ f_search(
return (1);
}
lno = 1;
+ wrapped = 1;
}
} else
coff = fm->cno + 1;
}
btype = BUSY_ON;
- for (cnt = INTERRUPT_CHECK, rval = 1, wrapped = 0;; ++lno, coff = 0) {
+ for (cnt = INTERRUPT_CHECK, rval = 1;; ++lno, coff = 0) {
if (cnt-- == 0) {
if (INTERRUPTED(sp))
break;
@@ -288,8 +289,8 @@ f_search(
* b_search --
* Do a backward search.
*
- * PUBLIC: int b_search __P((SCR *,
- * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
+ * PUBLIC: int b_search(SCR *,
+ * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int);
*/
int
b_search(
@@ -487,7 +488,7 @@ search_msg(
* search_busy --
* Put up the busy searching message.
*
- * PUBLIC: void search_busy __P((SCR *, busy_t));
+ * PUBLIC: void search_busy(SCR *, busy_t);
*/
void
search_busy(
diff --git a/contrib/nvi/common/seq.c b/contrib/nvi/common/seq.c
index 45c6c11..61c7fcd 100644
--- a/contrib/nvi/common/seq.c
+++ b/contrib/nvi/common/seq.c
@@ -31,8 +31,8 @@ static const char sccsid[] = "$Id: seq.c,v 10.18 2011/12/11 23:13:00 zy Exp $";
* seq_set --
* Internal version to enter a sequence.
*
- * PUBLIC: int seq_set __P((SCR *, CHAR_T *,
- * PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
+ * PUBLIC: int seq_set(SCR *, CHAR_T *,
+ * PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int);
*/
int
seq_set(
@@ -136,7 +136,7 @@ mem1: errno = sv_errno;
* seq_delete --
* Delete a sequence.
*
- * PUBLIC: int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
+ * PUBLIC: int seq_delete(SCR *, CHAR_T *, size_t, seq_t);
*/
int
seq_delete(
@@ -172,7 +172,7 @@ seq_delete(
* seq_free --
* Free a map entry.
*
- * PUBLIC: int seq_free __P((SEQ *));
+ * PUBLIC: int seq_free(SEQ *);
*/
int
seq_free(SEQ *qp)
@@ -193,7 +193,7 @@ seq_free(SEQ *qp)
* isn't NULL, partial matches count.
*
* PUBLIC: SEQ *seq_find
- * PUBLIC: __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
+ * PUBLIC: (SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *);
*/
SEQ *
seq_find(
@@ -278,7 +278,7 @@ seq_find(
* seq_close --
* Discard all sequences.
*
- * PUBLIC: void seq_close __P((GS *));
+ * PUBLIC: void seq_close(GS *);
*/
void
seq_close(GS *gp)
@@ -295,7 +295,7 @@ seq_close(GS *gp)
* seq_dump --
* Display the sequence entries of a specified type.
*
- * PUBLIC: int seq_dump __P((SCR *, seq_t, int));
+ * PUBLIC: int seq_dump(SCR *, seq_t, int);
*/
int
seq_dump(
@@ -343,7 +343,7 @@ seq_dump(
* seq_save --
* Save the sequence entries to a file.
*
- * PUBLIC: int seq_save __P((SCR *, FILE *, char *, seq_t));
+ * PUBLIC: int seq_save(SCR *, FILE *, char *, seq_t);
*/
int
seq_save(
@@ -389,7 +389,7 @@ seq_save(
* e_memcmp --
* Compare a string of EVENT's to a string of CHAR_T's.
*
- * PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t));
+ * PUBLIC: int e_memcmp(CHAR_T *, EVENT *, size_t);
*/
int
e_memcmp(
@@ -398,11 +398,11 @@ e_memcmp(
size_t n)
{
if (n != 0) {
- do {
- if (*p1++ != ep->e_c)
- return (*--p1 - ep->e_c);
+ do {
+ if (*p1++ != ep->e_c)
+ return (*--p1 - ep->e_c);
++ep;
- } while (--n != 0);
- }
- return (0);
+ } while (--n != 0);
+ }
+ return (0);
}
diff --git a/contrib/nvi/common/util.c b/contrib/nvi/common/util.c
index 43fa9d1..44c8e29 100644
--- a/contrib/nvi/common/util.c
+++ b/contrib/nvi/common/util.c
@@ -39,7 +39,7 @@ static const char sccsid[] = "$Id: util.c,v 10.30 2013/03/19 10:00:27 yamt Exp $
* binc --
* Increase the size of a buffer.
*
- * PUBLIC: void *binc __P((SCR *, void *, size_t *, size_t));
+ * PUBLIC: void *binc(SCR *, void *, size_t *, size_t);
*/
void *
binc(
@@ -76,7 +76,7 @@ binc(
* including or after the starting column. On error, set
* the column to 0, it's safest.
*
- * PUBLIC: int nonblank __P((SCR *, recno_t, size_t *));
+ * PUBLIC: int nonblank(SCR *, recno_t, size_t *);
*/
int
nonblank(
@@ -112,7 +112,7 @@ nonblank(
* tail --
* Return tail of a path.
*
- * PUBLIC: char *tail __P((char *));
+ * PUBLIC: char *tail(char *);
*/
char *
tail(char *path)
@@ -128,12 +128,12 @@ tail(char *path)
* join --
* Join two paths; need free.
*
- * PUBLIC: char *join __P((char *, char *));
+ * PUBLIC: char *join(char *, char *);
*/
char *
join(
- char *path1,
- char *path2)
+ char *path1,
+ char *path2)
{
char *p;
@@ -148,7 +148,7 @@ join(
* expanduser --
* Return a "~" or "~user" expanded path; need free.
*
- * PUBLIC: char *expanduser __P((char *));
+ * PUBLIC: char *expanduser(char *);
*/
char *
expanduser(char *str)
@@ -198,7 +198,7 @@ expanduser(char *str)
* quote --
* Return a escaped string for /bin/sh; need free.
*
- * PUBLIC: char *quote __P((char *));
+ * PUBLIC: char *quote(char *);
*/
char *
quote(char *str)
@@ -245,7 +245,7 @@ quote(char *str)
* v_strdup --
* Strdup for 8-bit character strings with an associated length.
*
- * PUBLIC: char *v_strdup __P((SCR *, const char *, size_t));
+ * PUBLIC: char *v_strdup(SCR *, const char *, size_t);
*/
char *
v_strdup(
@@ -267,7 +267,7 @@ v_strdup(
* v_wstrdup --
* Strdup for wide character strings with an associated length.
*
- * PUBLIC: CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t));
+ * PUBLIC: CHAR_T *v_wstrdup(SCR *, const CHAR_T *, size_t);
*/
CHAR_T *
v_wstrdup(SCR *sp,
@@ -288,7 +288,7 @@ v_wstrdup(SCR *sp,
* nget_uslong --
* Get an unsigned long, checking for overflow.
*
- * PUBLIC: enum nresult nget_uslong __P((u_long *, const CHAR_T *, CHAR_T **, int));
+ * PUBLIC: enum nresult nget_uslong(u_long *, const CHAR_T *, CHAR_T **, int);
*/
enum nresult
nget_uslong(
@@ -310,7 +310,7 @@ nget_uslong(
* nget_slong --
* Convert a signed long, checking for overflow and underflow.
*
- * PUBLIC: enum nresult nget_slong __P((long *, const CHAR_T *, CHAR_T **, int));
+ * PUBLIC: enum nresult nget_slong(long *, const CHAR_T *, CHAR_T **, int);
*/
enum nresult
nget_slong(
@@ -336,7 +336,7 @@ nget_slong(
* timepoint_steady --
* Get a timestamp from a monotonic clock.
*
- * PUBLIC: void timepoint_steady __P((struct timespec *));
+ * PUBLIC: void timepoint_steady(struct timespec *);
*/
void
timepoint_steady(
@@ -367,7 +367,7 @@ timepoint_steady(
* timepoint_system --
* Get the current calendar time.
*
- * PUBLIC: void timepoint_system __P((struct timespec *));
+ * PUBLIC: void timepoint_system(struct timespec *);
*/
void
timepoint_system(
@@ -401,7 +401,7 @@ timepoint_system(
* TRACE --
* debugging trace routine.
*
- * PUBLIC: void TRACE __P((SCR *, const char *, ...));
+ * PUBLIC: void TRACE(SCR *, const char *, ...);
*/
void
TRACE(
diff --git a/contrib/nvi/docs/TODO b/contrib/nvi/docs/TODO
deleted file mode 100644
index 6fe8829..0000000
--- a/contrib/nvi/docs/TODO
+++ /dev/null
@@ -1,147 +0,0 @@
-CL: In single-line screens, have to press 'q' twice when quitting out
- of a ":set all" display.
-
-COMMON: There's a serious problem with error returns -- we need to separate
- command failure from fatal error, consistently, over the entire source
- tree.
-
- We need to rework all of vi to have three return values:
-
- 0: success
- 1: vi error, continue
- 2: fatal error, die
-
- Right now we don't recognize fatal errors for what they are.
-
-VI: Change the screen scrolling to not eat user characters... i.e.
- g/pattern/foo should not eat already entered chars.
-
-COMMON: It's known that it's possible to sync the backing files in the
- wrong manner, leaving backup files that aren't recoverable. This
- is going to be left alone until we have a logging version of DB,
- which will hopefully fix this (or at least make it possible to
- easily do so).
-
-COMMON: The complete list of POSIX.1 calls that can return EINTR are:
-
- wait, waitpid, sleep, dup2, close, read, write,
- fcntl(SETLCKW) tcsetattr, tcdrain
-
- The problem is that technically, any system/library call can
- return EINTR, so, while nvi blocks (most of?) the obvious ones,
- someone may have to do a complete pass and block signals
- everywhere.
-
-COMMON: The vi main command loop should use the general-purpose overflow
- and underflow routines. In addition, the vi command loop uses
- unsigned longs -- should probably be fixed as a 32-bit unsigned
- type, and then check to make sure it's never used as as variable
- type again.
-
-DB: When nvi edits files that don't have trailing newlines, it appends
- one, regardless. This is required, by default, from POSIX.2.
-
-COMMON: Open mode is not yet implemented.
-
-COMMON: ^C isn't passed to the shell in the script windows as an interrupt
- character.
-
-COMMON: The options:
-
- hardtabs, lisp, optimize, redraw, slowopen
-
- are recognized, but not implemented. These options are unlikely
- to be implemented, so if you want them you might want to say
- something! I will implement lisp if anyone ever documents how it
- worked.
-
-COMMON: If you run out of space in the recovery directory, the recovery
- file is left in place.
-
-COMMON: Should "view" set a lock on the file?
-
-COMMON: Field editing shouldn't be hard to add to nvi:
-
- Field editing file template:
-
- version #
- field # row/column start row/column stop
- label field # Label string
- re field # Matching re string.
- field # row/column start row/column stop
- label field # Label string
- re field # Matching re string.
-
- <tab> moves to the next field
- <bs> in column 0 moves to the previous field
-
-COMMON: Let's rethink using an IPC mechanism:
-
- Two way channel, with events passing in both directions.
-
- Load into the same address space (else, how do file permissions) forks
- in v_init -- screens get events from vi, vi gets events queued up from
- screens.
-
- Vi:
- E_CHARACTER, /* Input character: e_c set. */
- E_EOF, /* End of input (NOT ^D). */
- E_ERR, /* Input error. */
- E_INTERRUPT, /* Interrupt. */
- E_REPAINT, /* Repaint: e_flno, e_tlno set. */
- E_RESIZE, /* SIGWINCH: e_lno, e_cno set. */
- E_SIGCONT, /* SIGCONT arrived. */
- E_SIGFATAL, /* fatal signal arrived.
- E_START, /* Start ex/vi. */
- E_STOP, /* Stop ex/vi. */
- E_STRING, /* Input string: e_csp, e_len set. */
-
- Screen:
- E_ADDSTR /* Add a string to the screen. */
- E_ATTRIBUTE /* Screen attribute. */
- E_BELL /* Beep/bell/flash the terminal. */
- E_BUSY /* Display a busy message. */
- E_CANONICAL /* Enter tty canonical mode. */
- E_CLRTOEOL /* Clear to the end of the line. */
- E_CURSOR /* Return the cursor location. */
- E_DELETELN /* Delete a line. */
- E_DISCARD /* Discard a screen. */
- E_EXADJUST /* Ex: screen adjustment routine. */
- E_FMAP /* Set a function key. */
- E_GETKEY /* Get a key event. */
- E_INSERTLN /* Insert a line. */
- E_MOVE /* Move the cursor. */
- E_MESSAGE /* Message or ex output. */
- E_REFRESH /* Refresh the screen. */
- E_RESIZE /* Resize two screens. */
- E_SPLIT /* Split the screen. */
- E_SUSPEND /* Suspend the editor. */
-
-EX: It would be nice to inverse video the replaced text during
- interactive substitute.
-
-EX: The :args command should put the current file name out in reverse
- video. This isn't going to be easy, currently only full lines can
- be in reverse video, not just parts.
-
-TK: We currently permit the user to change the lines, columns and term
- edit options. Shouldn't that be illegal in tknvi?
-
-VI: The strings found by searches should be highlighted until the next
- character is entered.
-
-VI: Display a split vi screen for the :help command.
-
-VI: When getting a key for a continue screen, we should always read from
- the terminal, not from a mapped key.
-
-VI: The sentence, paragraph and section movement commands don't match
- historic practice in some boundary cases. This should be left
- alone until POSIX 1003.2 makes up its mind.
-
-VI: The vs_sm_fill routine should scroll if possible, not always redraw.
-
-VI: Think about setting a dirty/inuse bits on the lines of the SMAP
- structure. That way the message routines could steal lines and
- refresh would continue to work, because it would know not to touch
- the lines that were in use.
diff --git a/contrib/nvi/docs/USD.doc/edit/Makefile b/contrib/nvi/docs/USD.doc/edit/Makefile
deleted file mode 100644
index 0c59f6d..0000000
--- a/contrib/nvi/docs/USD.doc/edit/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# @(#)Makefile 8.4 (Berkeley) 8/18/96
-
-ROFF= groff
-TBL= tbl
-
-edittut.ps: edittut.ms
- ${TBL} edittut.ms | ${ROFF} -ms > $@
- chmod 444 $@
-
-clean:
- rm -f edittut.ps
diff --git a/contrib/nvi/docs/USD.doc/edit/edit.vindex b/contrib/nvi/docs/USD.doc/edit/edit.vindex
deleted file mode 100644
index 2098f14..0000000
--- a/contrib/nvi/docs/USD.doc/edit/edit.vindex
+++ /dev/null
@@ -1,115 +0,0 @@
-.\" Copyright (c) 1980, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" @(#)edit.vindex 8.1 (Berkeley) 6/8/93
-.\"
-.bd I
-.ND
-.TL
-Index
-.sp 3
-.2C
-.nf
-addressing, \fIsee\fR line numbers
-append mode, 4
-backslash (\\), 18
-buffer, 2
-command mode, 4
-context search, 8, 10, 13, 18
-control characters (``^'' notation), 8
-control-d, 6
-current filename, 19, 20
-current line (.), 9, 15
-diagnostic messages, 4
-disk, 2
-documentation, 21
-edit (to begin editing session), 3, 7
-editing commands:
-.in +2
-append (a), 4, 7
-change (c), 16
-copy (co), 13
-delete (d), 13-14
-edit (e), 12
-file (f), 19
-global (g), 18-19
-move (m), 12-13
-number (nu), 9
-preserve (pre), 20-21
-print (p), 8
-quit (q), 5, 11
-quit! (q!), 11
-read (r), 20
-recover (rec), 20
-substitute (s), 9-10, 17, 18
-undo (u), 14, 17
-write (w), 5-6, 11, 19-20
-z, 11
-.sp 10i
-! (shell escape), 19
-$= , 15
-+, 15
-\-, 15
-//, 8, 18
-??, 18
-\&\fB.\fR, 9, 15
-\&\fB.\fR=, 9, 15
-.in -2
-erasing
-.ti +2
-characters (#), 8
-.ti +2
-lines (@), 8
-ex (text editor), 21
-\fIEx Reference Manual\fR, 21
-file, 1
-file recovery, 20
-filename, 2
-Interrupt (message), 7
-line numbers, \fIsee also\fR current line
-.ti +2
-dollar sign ($), 8, 12-13, 15
-.ti +2
-dot (.), 9, 15
-.ti +2
-relative (+ and \-), 15, 16
-logging out, 6
-login procedure, 2
-``magic'' characters, 21
-non-printing characters, 8
-``not found'' (message), 3
-program, 1
-recovery \fIsee\fR file recovery
-shell, 18
-shell escape (!), 19
-special characters (^, $, \e), 18
-text input mode, 4
-UNIX, 1
diff --git a/contrib/nvi/docs/USD.doc/exref/Makefile b/contrib/nvi/docs/USD.doc/exref/Makefile
deleted file mode 100644
index 11b5423..0000000
--- a/contrib/nvi/docs/USD.doc/exref/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# @(#)Makefile 8.8 (Berkeley) 10/10/96
-
-ROFF= groff
-TBL= tbl
-
-all: exref.ps summary.ps
-
-exref.ps: ex.rm
- ${TBL} ex.rm | ${ROFF} -ms > $@
- chmod 444 $@
-
-summary.ps: ex.summary
- ${TBL} ex.summary | ${ROFF} -ms > $@
- chmod 444 $@
-
-clean:
- rm -f exref.ps summary.ps
diff --git a/contrib/nvi/docs/USD.doc/vi.man/spell.ok b/contrib/nvi/docs/USD.doc/vi.man/spell.ok
deleted file mode 100644
index 80ebcab..0000000
--- a/contrib/nvi/docs/USD.doc/vi.man/spell.ok
+++ /dev/null
@@ -1,179 +0,0 @@
-Ar
-Bostic
-CDPATH
-COLUMNSXX
-Cscope
-Ds
-EXINIT
-Ee
-Ev
-Fa
-Ff
-Fl
-HUnhsh
-IPLPPPQPP
-LIpplpipbp
-Li
-Lite
-NEXINIT
-NHSHH
-Nex
-Nn
-POSIX
-Pp
-QQ
-SIGWINCHXX
-Std
-Sy
-TMPDIR
-Tt
-USD
-Unmap
-VI
-Vi
-XXXX
-ZZ
-ags
-ai
-altwerase
-ap
-autoindent
-autoprint
-autowrite
-aw
-bf
-bigwords
-cd
-cdpath
-cedit
-cmd
-co
-creens
-cs
-ctags
-db
-dbopen
-dd
-di
-dir
-dit
-doc
-docs
-eFRrsv
-eFRrv
-eFlRrv
-ead
-eb
-edcompatible
-egrep
-elete
-errorbells
-esc
-exrc
-exu
-fg
-filec
-hange
-hardtabs
-ht
-ic
-iclower
-ignorecase
-ile
-ind
-ious
-ist
-ize
-keytime
-leftright
-lhs
-li
-libc
-lobal
-lp
-matchtime
-mber
-mesg
-mk
-modeful
-modeline
-modelines
-nex
-nexrc
-nk
-nonblank
-nooption
-noprint
-nsert
-nul
-nvi
-oin
-onnections
-ove
-ppend
-prev
-pu
-readonly
-rec
-recdir
-redist
-rhs
-rint
-rk
-ro
-rsion
-sccs
-scr
-se
-searchincr
-sh
-shareware
-shellmeta
-shiftwidth
-showmatch
-showmode
-sidescroll
-slowopen
-sm
-smd
-sourceany
-su
-sual
-sw
-ta
-tabstop
-taglength
-tagn
-tagp
-tagstring
-th's
-tildeop
-tl
-tmp
-tr
-ts
-ttytype
-ttywerase
-ubstitute
-uffers
-uit
-unm
-urce
-var
-ve
-vi
-viu
-wa
-wi
-windowname
-wl
-wm
-wn
-wq
-wraplen
-wrapmargin
-wrapscan
-writeany
-ws
-ya
-yy
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/Makefile b/contrib/nvi/docs/USD.doc/vi.ref/Makefile
deleted file mode 100644
index 0e1b634..0000000
--- a/contrib/nvi/docs/USD.doc/vi.ref/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-# @(#)Makefile 8.20 (Berkeley) 8/18/96
-
-MACROS= -me
-ROFF= groff
-TBL= tbl
-
-all: vi.ref.txt vi.ref.ps
-
-vi.ref.txt: vi.ref index.so
- soelim vi.ref | ${TBL} | groff ${MACROS} -Tascii > $@
- rm -f index
- chmod 444 $@
-
-vi.ref.ps: vi.ref index.so
- soelim vi.ref | ${TBL} | ${ROFF} ${MACROS} > $@
- rm -f index
- chmod 444 $@
-
-index.so: vi.ref
- # Build index.so, side-effect of building the paper.
- soelim vi.ref | ${TBL} | ${ROFF} ${MACROS} > /dev/null
- sed -e 's/MINUSSIGN/\\-/' \
- -e 's/DOUBLEQUOTE/""/' \
- -e "s/SQUOTE/'/" \
- -e 's/ /__SPACE/g' < index | \
- sort -u '-t ' +0 -1 +1n | awk -f merge.awk | \
- sed -e 's/__SPACE/ /g' > $@
- rm -f index
- chmod 444 $@
-
-clean:
- rm -f vi.ref.ps vi.ref.txt index index.so
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/index.so b/contrib/nvi/docs/USD.doc/vi.ref/index.so
deleted file mode 100644
index 4c3acb6..0000000
--- a/contrib/nvi/docs/USD.doc/vi.ref/index.so
+++ /dev/null
@@ -1,260 +0,0 @@
-! 21, 42
-"" 42
-# 22, 43
-$ 22
-% 22
-& 23, 51
-'<character> 23
-( 23
-) 24
-* 43
-+ 19
-, 24
-. 24
-/RE/ 25
-0 25
-0<control-D> 38
-: 26
-; 26
-< 26, 43
-<carriage-return> 14
-<control-A> 17
-<control-B> 17
-<control-D> 17, 38, 42
-<control-E> 18
-<control-F> 18
-<control-G> 18
-<control-H> 18, 39
-<control-J> 19
-<control-L> 19
-<control-M> 19
-<control-N> 19
-<control-P> 19
-<control-R> 19
-<control-T> 19, 38
-<control-U> 20
-<control-W> 20, 39
-<control-X> 39
-<control-Y> 20
-<control-Z> 20, 52
-<control-]> 20
-<control-^> 21
-<end-of-file> 40, 42
-<erase> 39
-<escape> 20, 39
-<interrupt> 12, 37, 39
-<line erase> 39
-<literal-next> 12, 39
-<newline> 14
-<nul> 38
-<space> 21
-<word erase> 39
-= 43
-> 26, 43
-?RE? 25
-@ 26, 43
-A 27
-B 27
-C 27
-D 27
-E 28
-F 28
-G 28
-H 28
-I 28
-J 29
-L 29
-M 29
-N 25
-O 29
-P 29
-Q 30
-R 30
-S 30
-T 30
-U 30
-W 31
-X 31
-Y 31
-ZZ 31
-[[ 31
-\- 24
-]] 32
-^ 32
-^<control-D> 38
-_ 32
-`<character> 23
-a 32
-abbrev 43
-alternate pathname 13
-altwerase 56
-append 44
-args 44
-autoindent 56
-autoprint 56
-autowrite 57
-b 32
-backup 57
-beautify 57
-bg 44
-bigword 16
-buffer 13
-c 33
-cd 45
-cdpath 57
-cedit 57
-change 45
-chdir 45
-columns 58
-comment 58
-copy 45
-count 16, 41
-cscope 45
-current pathname 12
-d 33
-delete 45
-directory 58
-display 45
-e 33
-edcompatible 58
-edit 46
-errorbells 58
-escapetime 58
-exrc 58
-extended 58
-exusage 46
-f 33
-fg 46
-file 41, 46
-filec 58
-flags 41
-flash 59
-global 47
-hardtabs 59
-help 47
-i 33
-iclower 59
-ignorecase 59
-insert 47
-j 19
-join 47
-k 19, 48
-keytime 59
-l 21
-leftright 59
-line 41
-lines 59
-lisp 59
-list 48, 59
-lock 59
-m 34
-magic 60
-map 48
-mark 48
-matchtime 60
-mesg 60
-mkexrc 49
-modelines 60
-motion 15
-move 48
-msgcat 60
-n 25
-next 49
-noprint 60
-number 43, 61
-o 34
-octal 61
-open 49, 61
-optimize 61
-p 34
-paragraph 16
-paragraphs 61
-path 61
-preserve 49
-previous 49
-previous context 15
-print 50, 61
-prompt 61
-put 50
-quit 50
-r 34
-range 41
-read 50
-readonly 61
-recdir 62
-recover 50
-redraw 62
-remap 62
-report 62
-resize 50
-rewind 51
-ruler 62
-s 34
-scroll 62
-searchincr 62
-section 17
-sections 63
-secure 63
-sentence 17
-set 51
-shell 51, 63
-shellmeta 63
-shiftwidth 63
-showmatch 63
-showmode 63
-sidescroll 63
-slowopen 63
-source 51
-sourceany 64
-stop 52
-substitute 51
-suspend 52
-t 35, 45
-tabstop 64
-tag 52
-taglength 64
-tagnext 52
-tagpop 53
-tagprev 53
-tags 64
-tagtop 53
-term 64
-terse 64
-tildeop 64
-timeout 64
-ttywerase 64
-u 35
-unabbrev 53
-undo 53
-unmap 54
-unnamed buffer 14
-v 47
-verbose 64
-version 54
-visual 54
-viusage 54
-w 35
-w1200 64
-w300 64
-w9600 64
-warn 65
-whitespace 14
-window 65
-windowname 65
-wn 54
-word 16
-wq 54
-wraplen 65
-wrapmargin 65
-wrapscan 65
-write 54
-writeany 66
-x 35
-xit 55
-y 35
-yank 55
-z 36, 55
-{ 36
-| 36
-} 37
-~ 37, 51
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/merge.awk b/contrib/nvi/docs/USD.doc/vi.ref/merge.awk
deleted file mode 100644
index c65207c..0000000
--- a/contrib/nvi/docs/USD.doc/vi.ref/merge.awk
+++ /dev/null
@@ -1,16 +0,0 @@
-# @(#)merge.awk 8.3 (Berkeley) 5/25/94
-#
-# merge index entries into one line per label
-$1 == prev {
- printf ", %s", $2;
- next;
-}
-{
- if (NR != 1)
- printf "\n";
- printf "%s \t%s", $1, $2;
- prev = $1;
-}
-END {
- printf "\n"
-}
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/spell.ok b/contrib/nvi/docs/USD.doc/vi.ref/spell.ok
deleted file mode 100644
index a7d95e3..0000000
--- a/contrib/nvi/docs/USD.doc/vi.ref/spell.ok
+++ /dev/null
@@ -1,414 +0,0 @@
-ABC
-Amir
-Autoindent
-Autoprint
-BRE's
-Bostic
-Bourne
-CDPATH
-CSCOPE
-Cscope
-DIRS
-DOUBLEQUOTE
-Dq
-Ds
-ERE's
-EXINIT
-Englar
-Ev
-FF
-Fa
-Fg
-FindScreen
-Fl
-Foregrounding
-HUnhsh
-IPLPPPQPP
-Kirkendall
-Korn
-LC
-LIpplpipbp
-LaA
-Li
-Lowercase
-MINUSSIGN
-Makefiles
-Mayoff
-NEX
-NEXINIT
-NHSHH
-NVI
-Neville
-Nex
-Nvi
-OS
-POSIX
-Perl
-PostScript
-QQ
-RE's
-README
-RECDIR
-Reference''USD:13
-SENDMAIL
-SIGHUP
-SIGWINCH
-SQUOTE
-Se
-Std
-Std1003.2
-Sven
-Sy
-TANDARDS
-TIOCGWINSZ
-TMPDIR
-TOC
-Tagnext
-Tagprev
-Tcl
-Tk
-Todo
-USD
-USD.doc
-USD:13
-UUNET
-Unmap
-VI
-Verdoolaege
-Vi
-Vx
-Whitespace
-XOFF
-XON
-XOptions
-XXCOLUMNS
-XXXX
-XXXXXX
-XXb
-ZZ
-ab
-abbrev
-abc
-ags
-ai
-al
-altwerase
-ap
-api
-ar
-arg
-args
-att
-autoindent
-autoprint
-autowrite
-aw
-backgrounded
-backgrounding
-bbrev
-berkeley
-bf
-bg
-bigword
-bigwords
-bostic
-bp
-brev
-bsd
-bugs.current
-c2w
-carat
-cd
-cdpath
-cdy
-cedit
-changelog
-chd
-chdir
-cmd
-co
-count1
-count2
-creens
-cs
-cs.berkeley.edu
-cscope
-ctags
-cw
-db
-dbopen
-dd
-def
-di
-dir
-dit
-docs
-eE
-eFlRsv
-eFlRv
-eL
-eU
-ead
-eb
-edcompatible
-edu
-ee
-egrep
-elete
-elp
-elvis
-email
-enum
-eof
-errorbells
-esc
-escapetime
-eset
-eu
-ex.cmd.roff
-exrc
-ext
-exu
-exusage
-fcntl
-fg
-fi
-filec
-filesystem
-filesystems
-foo
-foregrounded
-foregrounding
-ftp.cs.berkeley.edu
-ftp.uu.net
-gdb
-gdb.script
-getpwent
-gs
-gzip'd
-halfbyte
-hange
-hangup
-hardtabs
-ht
-html
-http
-ic
-iclower
-ifdef
-ignorecase
-ile
-ind
-initially
-ious
-ir
-iscntrl
-isprint
-ist
-ize
-keystroke
-keystrokes
-keytime
-leftright
-lhs
-li
-lib
-libc
-libc.tags
-lineNum
-lineNumber
-lobal
-lowercase
-lp
-luR
-matchtime
-mber
-mesg
-meta
-mk
-mkexrc
-modeful
-modeline
-modelines
-ms
-msgcat
-ndo
-nex
-nexrc
-nk
-nomagic
-nonblank
-nonoverlapping
-nooption
-noprint
-nsert
-nul
-nvi
-nvi.tar.Z
-nvi.tar.z
-nz
-oin
-onnections
-op
-ove
-para
-pathname
-pathnames
-pe
-perl
-perld
-ppend
-prev
-pu
-py
-rc
-rc.local
-readonly
-rec
-recdir
-recfile
-recover.XXXX
-recover.XXXXXX
-recover.c
-recover.script
-redist
-redistributable
-reimplementations
-remapmax
-remapped
-repl
-res
-rew
-rhs
-rint
-ript
-rk
-rl
-ro
-roff
-rsion
-sc
-sccs
-scr
-screeen
-screenId
-se
-searchincr
-sendmail
-set.opt.roff
-settable
-setuid
-sh
-shareware
-shellmeta
-shiftwidth
-showmatch
-showmode
-sidescroll
-slowopen
-sm
-smd
-sourceany
-sp
-spell.ok
-ssg
-st
-su
-sual
-svi
-sw
-ta
-tabstop
-taglength
-tagn
-tagnext
-tagp
-tagpop
-tagprev
-tagstring
-tagt
-tagtop
-tc
-tcl
-tclproc
-terminfo
-th
-th's
-tildeop
-tl
-tmp
-toolchest
-tpath
-tr
-ts
-ttytype
-ttywerase
-uR
-ubstitute
-ucb
-uffers
-uit
-una
-unabbrev
-unescaped
-unm
-unmap
-unsets
-uppercase
-urce
-usr
-uunet
-v
-var
-ve
-vi
-vi.0.ps
-vi.0.txt
-vi.1
-vi.XXXX
-vi.XXXXXX
-vi.cmd.roff
-vi.exrc
-vi.recover
-viAppendLine
-viDelLine
-viEndScreen
-viFindScreen
-viGetCursor
-viGetLine
-viGetMark
-viGetOpt
-viInsertLine
-viLastLine
-viMapKey
-viMsg
-viNewScreen
-viSetCursor
-viSetLine
-viSetMark
-viSetOpt
-viSwitchScreen
-viUnmMapKey
-vibackup
-virecovery
-viu
-viusage
-wa
-whitespace
-wi
-windowname
-wl
-wm
-wn
-wq
-wraplen
-wrapmargin
-wrapscan
-writeany
-ws
-www
-xaw
-xit
-xterm
-ya
-yy
diff --git a/contrib/nvi/docs/USD.doc/vitut/Makefile b/contrib/nvi/docs/USD.doc/vitut/Makefile
deleted file mode 100644
index 3d4aca0..0000000
--- a/contrib/nvi/docs/USD.doc/vitut/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# @(#)Makefile 8.7 (Berkeley) 8/18/96
-
-MACROS= -ms
-ROFF= groff
-TBL= tbl
-
-all: vitut.ps summary.ps viapwh.ps
-
-vitut.ps: vi.in vi.chars
- ${TBL} vi.in vi.chars | ${ROFF} ${MACROS} > $@
- chmod 444 $@
-
-summary.ps: vi.summary
- ${TBL} vi.summary | ${ROFF} ${MACROS} > $@
- chmod 444 $@
-
-viapwh.ps: vi.apwh.ms
- ${TBL} vi.apwh.ms | ${ROFF} ${MACROS} > $@
- chmod 444 $@
-
-clean:
- rm -f vitut.ps summary.ps viapwh.ps
diff --git a/contrib/nvi/docs/changelog b/contrib/nvi/docs/changelog
deleted file mode 100644
index 1f2a8c6..0000000
--- a/contrib/nvi/docs/changelog
+++ /dev/null
@@ -1,1102 +0,0 @@
-1.78 -> 1.79 (10/23/96)
- + Rename delete() to del(), for C++.
- + Add Spanish to the list of translations.
- + Update to Perl 5.003_06, and other Perl interpreter updates.
- + Update the set-edit-option interface for the scripting languages.
- + Rework ex command parsing to match historic practice for backslash
- escaped <newline> characters inside of global commands.
- + Enhance the comment edit option to skip C++ comments.
- + Change installation to configure the recovery shell script to match
- the system pathnames and to install it into the vi data directory.
- Move the recover script into the build directory, and delete the
- recover directory.
- + Enhance LynxOS support.
-1.76 -> 1.78 (10/01/96)
- + Fix bugs when both the leftright scrolling and number edit options
- were on.
- + Fix bug where splitting in the middle of the screen could repaint
- incorrectly.
- + Fix first-nul in input bug, where random garbage was inserted.
- + Correct search and mark-as-motion-command bug, it's a line mode
- action if the search starts at or before the first non<blank>.
- + Fix bug autoindent bug, where ^D could shift too far in the line.
- + Fix core dump where ! command called from the .exrc file.
- + Add the -S command-line option, which initializes vi to have the
- secure edit option preset.
-1.75 -> 1.76 (09/15/96)
- + Fix bug where ^V didn't keep input mapping from happening.
- + Fix a core dump bug in the R command.
- + Give up on licensing: no more shareware, adware, whatever.
- + Fix cursor positioning bug for C, S and c$ in an empty file.
-1.74 -> 1.75 (08/22/96)
- + Add French to the error message translations.
- + Move the UNLICENSED message to the end of the message line.
- + Fix bug where wide characters in a file name weren't calculated
- correctly in the status message.
- + Fix bug where cl_rename was called directly, by the ex shell code.
- + Fix bug where splitting a screen resulting in a new screen at the
- top of the display resulted in badly displayed status messages.
-1.73 -> 1.74 (08/18/96)
- + Fix bug where the status line wasn't redisplayed if the user ran
- an ex command that trashed the screen.
- + Fix bug where the long version of the status line wasn't displayed
- when switching screens.
- + Rework fast-path filename completion code to sort the entries, and
- strip out . and .. by default.
- + Fix bug where ex went to the first line instead of the last one when
- reading in a file.
-1.72 -> 1.73 (08/12/96)
- + Do filename completion and some file expansion internally for speed.
- + Fix CSCOPE_DIRS environmental variable support.
- + Ex parser fix for global commands in script files.
- + Add the O_PATH option, so you can specify a directory search path
- for files.
- + Make it possible to specify the database file to cscope, allowing
- multiple databases in a single directory.
- + Fix incremental search to overwrite erased characters so the user
- can tell where they are on the colon-command line.
- + Fix incremental search to restart the search if the user enters an
- unescaped shell meta character.
-1.71 -> 1.72 (07/12/96)
- + Cscope fix: test for files newer than the database was reversed.
- + Display "files to edit" message for rewind, next and initial screen.
- + Fix a bug in the R command where it could fail if the user extended
- the file.
- + Fix a bug where text abbreviations could corrupt the line.
- + Fix a bug where the windowname edit option couldn't be set before a
- file was loaded into the edit buffer.
- + Fix a bug where the system .exrc values weren't being overridden by
- the user's $HOME .exrc values.
- + Fix a bug in the filename completion code, where garbage characters
- could be added to the colon command line.
- + Fix bug where multiple edit sessions on a non-existent file could
- all write the file without warning.
- + Fix bug where screen update was incorrect if a character triggered
- both a wrapmargin and showmatch condition.
- + Fix bug in leftright scrolling where <CR> during text input didn't
- return the cursor to the left margin.
- + Rev the Perl interpreter code, new version from Sven Verdoolaege,
- based on Perl 5.003.01.
- + Fix bug in tags file pattern search introduced in 1.71.
-1.70 -> 1.71 (07/01/96)
- + Don't include <term.h> -- neither HPUX or Solaris can cope with it.
- + Fix bug where ^M's in the original pattern were converted into new
- lines in the file during substitution commands.
- + Make window resize events separate from interrupts -- too many users
- complained.
- + Fix bug in first-character-is-null text input semantic.
- + Rework search routines to take a length instead of a nul-terminated
- string for a pattern. This fixes a couple of bugs in searching, but
- probably introduces new ones.
- + Fix prompting the user after a write filter command, the way I did
- it in 1.70 broke the display.
- + Don't switch to the alternate xterm screen when entering the ex
- text input commands from vi mode.
- + Implement the Fg command, so can foreground a background screen into
- a split screen.
- + Change the fg command to match screen names using the last component
- of the filename the full filename fails.
-1.69 -> 1.70 (06/28/96)
- + Change the ex read command to support named pipes.
- + Copy the EXINIT/NEXINIT strings before executing their commands so
- we don't step on the process environment.
- + Don't do "line modification" reports for intermediate commands
- executed from the vi colon command line, it screws up filter
- reads, causing nvi to prompt for the user to continue.
- + Add "smd" as an abbreviation for showmode: HP, ICL and SCO have it.
- + Change nvi to always prompt the user after a write filter command.
- This matches historic practice.
- + Fix recovery information mailed to the user to reflect the program's
- installed name.
- + Change configuration script to not cache option information, e.g.,
- --disable-curses.
- + Fix a bug where the second character of the vi [[, ]] and ZZ
- commands could start a command mapped sequence.
- + Fix 3 write bugs: partial writes (3,$write), were clearing the
- modified flag, full writes using line numbers (1,$write) were
- not, and append historically never cleared the modified flag, and
- we didn't get that right.
- + Shorten the "more files to edit" message so it can gang on a single
- line, lots of people have complained. Add the number of files that
- are left to edit, it's historic practice.
- + Fix core dump where message catalogs collided with truncating the
- write path. Add a new write message so the string "appended" is
- taken from a message catalog.
- + Fix bug where an undo followed by '.' to repeat it wouldn't work
- if no other repeatable commands had been entered.
- + Fix core dump when resolution of input lines' autoindent characters
- invalidated cached display information.
- + Set the name of the X11 xterm icon/window to "xterm" when exiting,
- if modified based on the windowname option.
- + Include <term.h> if it exists, fixes portability problems on IRIX
- systems.
-1.68 -> 1.69 (06/17/96)
- + Add the windowname edit option and code to change the icon/window
- name for xterm's.
- + Enhance the comment edit option to skip shell comments.
- + Add conditional prototypes to replacement C library functions.
- + Minor enhancements/reworking to Makefile.in, other build files.
- + Fix bug in vi text input ^D processing, could result in cursor
- warp to the beginning of the line.
- + Fix leftright screen bug where the screen wasn't repainted when
- being repainted from scratch.
- + Update the Swedish and Dutch catalogs.
- + Truncate paths in write commands if they don't fit on one line.
- + Fix alternate screen bug where the screen flashed and output lost
- when switching to/from the X11 xterm alternate screen. Fix bug
- where nvi switched into the alternate screen during filter-read
- commands, which doesn't match historic practice.
- + Minor relative cursor positioning change, make cursor position
- changes from ex real and permanent.
-1.67 -> 1.68 (06/09/96)
- + Fix core dump when tagging out of a modified file.
-1.66 -> 1.67 (06/09/96)
- + Convert the license to adware.
- + Leftright scrolling tweak, don't repaint the screen as often.
- + Change so that search warning/error messages don't appear during an
- incremental search.
- + Cscope fix: test for files newer than the database was reversed.
- + Don't display ex `welcome message' if in ex batch mode.
- + Test for vsnprintf and snprintf separately, HP 10.10 has snprintf
- but not vsnprintf.
- + Reverse lookup order between LC_MESSAGES and LANG.
- + Fix Tcl/Perl core dumps in common API code to get/set options.
- + Fix R command -- it used a DB pinned page after discarding it.
- + Minor fixes in multiple edit buffer message handling code.
- + Fix yk command moving to shorter line core dump.
- + Rework message handling to try and gang more messages onto a single
- line.
-1.65 -> 1.66 (05/18/96)
- + Convert vi man page to historic -man macro package, and install it.
- + Fix bug were !! on an empty line with a nonexistent command left the
- cursor on the second character, not the first.
- + Fix bug where line redisplay was wrong when a <tab> replaced a
- previous <tab> in the line.
- + Fix bug where D (d$) didn't reset the relative cursor position.
- + Fix bug where yG incorrectly reset the relative cursor position.
- + Fix bug where the window size couldn't be grown once it was shrunk.
- + Fix bug where the extended edit option caused tag searches to fail.
- + If multiple lines in the tags file with the same leading tag, build
- a tags stack like the Cscope stack. This is the obvious extension,
- and the way that Larry McVoy's ctags program works.
- + Send the appropriate TI/TE sequence in the curses screen whenever
- entering ex/vi mode. This means that :shell now shows the correct
- screen when using xterm alternate screens.
- + Rework the options display code to get five columns in an 80 column
- screen.
- + Interactive Unix V3.0 port -- mostly file name shortening, other
- minor changes. Only preliminary, more work will be necessary.
- + Add debugging option to not read EXINIT/.exrc information.
- + Fix bug where re_compile printed an error message to the screen
- when the user entered [ to an incremental search.
- + Turn off screen beeps when incremental search is failing.
- + Fix bug where the iclower option didn't trigger an RE recompilation.
- + Fix bug where -t into an already locked file forced the user to wait
- as if a startup command had failed.
- + LynxOS port -- mostly adding <sys/types.h> even though <sys/param.h>
- was already included.
- + Fix ex output bug, where it appeared as if an ex command was skipped
- due to flags not being cleared in the vs_msg() routine.
- + Fix core dump when global command tried to switch screens.
-1.64 -> 1.65 (05/13/96)
- + Fix cscope <blank>-matching pattern to use extended RE's, and bug
- that kept cscope from finding patterns containing <blank>s.
- + Fix core dumps in both leftright and folded screens when tabstops
- edit option value was large, and tab characters occurred as the last
- character in the logical screen.
- + Fix core dump where the second screen of a folded line wasn't
- displayed correctly.
- + Fix incremental search to match the current location for strings
- starting with \< patterns.
- + Fix bug where margins were ignored during replay of text input.
- + Fix bug where motion components to shorter lines could lose because
- the relative motion flags weren't ever set. This has been broken
- forever, but the change almost certainly breaks something else -- I
- have no idea what.
- + Tags display: don't print the current entry separately, display
- them all and add a trailing asterisk for the current one.
- + Change the cscope add command to put the directory name through
- standard file name expansion.
- + Fix cscope use of buffers -- search commands weren't nul-terminated.
-1.63 -> 1.64 (05/08/96)
- + Add installation target to the Makefile.
- + Add documentation on the new tags commands to the Vi Reference
- Manual.
- + Make the sidescroll edit option work again.
- + Fix bug where messages output during startup by ex could be lost.
- + Change ex/vi commands errors into beeps, unless the verbose edit
- option is set -- there are too many macros that are expected to
- eventually fail. This matches historic practice.
- + Truncate paths in initial vi screen if they won't fit on one line.
- + Make cursor position after filter write match historic practice.
- + Force the user to wait if there is output and the user is leaving
- the screen for any reason -- don't permit further ex commands.
- + Don't use a <newline> character to scroll the screen when exiting,
- scroll in the vi screen before endwin() is called.
- + Fix bug where the column number could be incorrect because the old
- screen wasn't updated after a screen split.
- + Fix ex print routine to correctly specify print flags.
- + Make -g/-O a separate make/configuration option.
- + Fix bug where ex/vi messages weren't being joined.
- + Fix bug where termcap strings were free'd twice.
- + Fix bug where TI/TE still weren't working -- I didn't put in the
- translation strings for BSD style curses.
- + Fix bug where I misspelled the iclower edit option as icloser.
-1.62 -> 1.63 (04/29/96)
- + Robustness and type/lint fixes for the Tcl interface code.
- + Fix core dump if TERM wasn't set or terminal type was unknown.
- + Fix bug where combining ex commands that did/did not require an
- ex screen would overwrite the command with the want-to-continue
- messsage.
- + Fix bug where the screen was never resolved if the user continued
- entering ex commands using the : character, but then backspaced
- over the prompt to quit or tried to edit their colon command-line
- history.
- + Fix bug where cursor wasn't placed over the ^ placeholder character
- when quoting using the literal-next character.
- + Fix bug where nvi under BSD style curses wasn't sending TI/TE termcap
- strings when suspending the process.
- + Rename mic again, to iclower.
- + Fix bug where 'z' commands trailing / or ? commands weren't being
- executed.
- + Change incremental search to leave the cursor at its last position
- when searching for something that was never found.
- + Fix bug where search-with-confirmation from vi mode didn't position
- the cursor correctly after displaying the confirm message.
- + Fix bug where the "search wrapped" message was dependent on the
- verbose edit option, which doesn't match historic practice. Change
- search messages to be in inverse video.
- + Fix bug where matched showmatch character wasn't being displayed
- before the matching character was displayed.
- + Another cursor update bug required a change to vs_paint().
- + Fix bug were initial line offset was wrong for the first split screen
- (symptom is very strange column numbers and blank first line).
- + Create filename "argument" lists when creating new screens.
- + Fix bug where globals with associated commands that included both
- buffer execution and other commands could fail to execute the latter.
-1.61 -> 1.62 (04/22/96)
- + Rename the "searchci" edit option to be "mic".
- + Fix memory corruption in global commands ending in searches.
- + Fix text resolution bug, corrected the cursor based on the
- first line input, not the last.
- + Rework the readonly edit option to match historic practice.
- + Fix several minor incremental search bugs; make incremental
- searches work in maps.
- + Fix long-line core dump, where an incorrect screen map could be
- used.
-1.60 -> 1.61 (04/12/96)
- + The cursor now ends up on the FIRST character of the put text for
- all versions of the vi put commands, regardless of the source
- of the text. This matches System III/V behavior and POSIX 1003.2.
- + Fixed bug where showmatch messages were getting discarded.
- + Minor Perl integration fixes.
- + Integrate Cscope into the tags stack code -- major change.
- + Fixed bug where ^T would drop core if returning to a temporary file.
- + Changed vs_ routine to display ex output to replace tab characters
- with spaces.
- + Fix autoindent code to not back up past beginning of line when ^T
- inserted into the middle of a line, i.e. offset != 0.
- + Fix "notimeout" option, was being ignored, by a coding error.
- + Fix showmatch code to never flash on a match if keys are waiting.
- + Change the vi 'D' command to ignore any supplied count, matching
- historic practice.
- + Fix viusage for D, S, C and Y (the aliased vi commands).
- + Fix the Perl5 configuration bug in the configuration script.
- + Make file completion commands in empty lines work.
- + Fix where the change to let vi use the default ex command structure
- broke the ex specification of the script or source file name.
- + Fix to free saved RE structures when screens exit. This is a major
- RE change, which fixed several bugs in the handling of saved/subst
- RE's. It's likely to have added new bugs, however.
- + Add case-independent searching (the searchci edit option).
- + Add incremental search (the searchincr edit option).
- + Home the cursor when executing ex commands from vi.
-1.59 -> 1.60 (03/29/96)
- + Fix ":w >>" core dump, make that command match historic practice.
- + Fix autoindent bug where the length of the line was incorrectly
- calculated.
- + Fix cursor bug where cursor could end up at the wrong place if the
- movement keys were entered quickly enough.
- + Change the read/write whirling indicator to appear only every 1/4
- second, clean up the appearance.
- + Don't change the options real values until underlying functions
- have returned OK -- fix "set tabstop=0" core dump.
- + Fix resizing on Sun's: use SA_INTERRUPT to interrupt read calls.
- + Fix two forward mark command bugs: one where it wasn't setting the
- "favorite cursor" position because of the refresh optimization,
- and one where it didn't have VM_RCM_SET set in the command flags
- for some reason.
- + Fix a bug were the 's' command on top of a <tab> didn't correctly
- copy the buffer.
- + Make :exusage command work for commands having optional leading
- capital letters, e.g. Next.
- + Previous changes broke the inital-matching-prefix code in the key
- mapping part of v_event_get -- fix it, and fix the infinite macro
- interrupt code at the same time.
- + Add "cedit" edit option, so colon command-line editing is optional.
- Change filec/cedit so that you can set them to the same character,
- and they do cedit if in column 1, and filec otherwise.
- + Fix "source of non-existent file" core dump.
- + Fix bug where functions keys specified in startup information were
- never resolved/activated.
- + Fix v_txt bug where could infinitely loop if <escape> triggered an
- abbreviation expansion.
- + Move version string into VERSION file, out of ex_version.c
-1.58 -> 1.59
- + Configuration changes, several minor bug fixes, including a few
- core dumps. No functional changes.
-1.57 -> 1.58
- + Fix the problem where colon command-line temporary files were
- getting left in /tmp.
- + Fix the configuration scripts to quit immediately if the Perl
- or Tk/Tcl libraries are specified but not found.
- + Several screen fixes -- the changes in 1.57 weren't as safe as
- I thought. More specifically, the refresh-only-if-waiting change
- caused a lot of problems. In general, fixing them should provide
- even more speedup, but I'm nervous.
- + Lots of changes in the configuration scripts, hopefully this is
- just a first-round ordeal.
- + Several other minor bug fixes.
-1.56 -> 1.57
- + Add <esc> hook to colon commands, so you can edit colon commands.
- + Add Perl5 interpreter.
- + Change shell expansion code to fail if it doesn't read at least
- one non-blank character from the shell. If the shell expansion
- process fails, or if not at least one non-blank character, it
- now displays an error message to the user.
- + Rework the screen display so that it matches the historic vi screen
- refreshes.
- + Rework options processing: print/noprint are no longer cumulative,
- provide more information to underlying edit options modules, move
- O_MESG information into the screen specific code.
- + Make file completion character settable.
- + Rework terminal restart -- you can now use ":set term" to switch
- terminal types. This cleaned up screen resizing considerably.
- + Character display fix, display \177 as ^?, not in hex/octal.
- + Tag search bug fix, don't repeat search if successful.
- + Replace sys_siglist[] use with private sigmsg() routine.
- + Fix core dump if illegal screenId specified to Tcl routine.
- + Add get/set mark interface to Tcl Interpreter interface.
- + Fix core dump if file expansion code stressed (re: filec edit option)
- + Fix bug where filter commands in empty files couldn't find line 0.
- + Switch to GNU autoconf 2.7 for configuration, delete nvi/PORT.
- Many random portability fixes.
-1.55 -> 1.56 (11/26/95)
- + Bug fix release -- generally available beta release.
-1.54 -> 1.55 (11/18/95)
- + Bug fix release.
- + Integrate Tcl interpreter.
-1.53 -> 1.54 (11/11/95)
- + Bug fix release. A major change in reworking the ex commands, when
- called from the colon command line, to match historic practice, and
- permit them to be entered repeatedly after ex has trashed the screen.
- + Use restartable endwin() from System V curses to implement screen
- + suspend.
-1.52 -> 1.53 (10/29/95)
- + Switch to using vendor's curses library for all ports.
- + Back out the event driven version, leaving screen separation.
- + User configuration of <escape> timeout (the escapetime edit option).
- + Add Tcl/Tk screen support.
- + Add file name completion (the filec edit option).
- + Disallow access to outside applications (the secure edit option).
-1.51 -> 1.52 (7/26/95)
- + Minor cleanups, snapshotted for SMI.
-1.50 -> 1.51 (7/05/95)
- + Lots and lots of changes for event driven model, largely in moving
- the boundary between the screen code and the editor up and down.
- Private release for Rob Zimmermann @ Tartan and Bill Shannon @ SMI.
-1.49 -> 1.50 Fri Jun 9 13:56:17 1995
- + Minor bug fixes for stability.
- + Convert to an event driven model, with the usual Nachos Supreme
- layering that results. This is a completely new version, nothing
- done previously matters any more.
-1.48 -> 1.49 Wed Mar 8 10:42:17 1995
- + Changes in 1.46 broke ^A processing.
- + Add :previous to split screen commands.
- + Lots o' random bug fixes -- passes purify testing again.
-1.47 -> 1.48 Thu Feb 9 18:13:29 1995
- + Random bug fixes for 1.47.
- + Move the FREF (file structure) list out of the screen and into
- the global area.
- + Change semantics to :E to more closely match :e -- ":E" joins
- the current file, so ":E /tmp" is now the command to match the
- historic ":split".
-1.46 -> 1.47 Wed Feb 8 19:43:41 1995
- + All ex commands (including visual and excluding global and v)
- are now supported inside ex global commands.
- + Rework the append/change/insert commands to match historic
- practice for text appended to the ex command line, and inside
- of ex global commands.
- + Restructure to make single-line screens work.
- + Restructure to create curses independent screen routines.
- + Restructure to permit Edit, Next, and Tag routines to create new
- screens on the fly.
- + Change hexadecimal output to be \x## instead of 0x##.
- + Change ex commands run from vi to stay in vi mode for as long as
- possible, i.e. until ex modifies the screen outside of the editor.
-1.45 -> 1.46 Tue Jan 24 10:22:27 1995
- + Restructure to build as a library.
-1.44 -> 1.45 Thu Jan 12 21:33:06 1995
- + Fix relative cursor motion to handle folded lines.
- + Recompile the search pattern if applicable edit options change.
- + Change +/-c command ordering to match historic practice.
- + Rework autoindent code to always resolve preceeding <blank>
- characters when a ^T or ^D are entered.
- + Add the print/noprint edit options, so can now specify if
- a character is printable.
- + Change ex to run in canonical mode.
- + Fix ex text input to support the number edit option.
- + Vi text input fix for the R command to correctly restore
- characters entered and then backspaced over.
- + Several vi increment command fixes.
-1.43 -> 1.44
- + Bug fix, vi was printing the last line number on the status line
- at startup. Change to execute commands at first line set, i.e.
- "vi -t tag -c cmd" executes cmd at the tag line, not EOF.
-1.42 -> 1.43 Sat Dec 3 13:11:32 1994
- + Marks, SunOS signed comparison fix for 1.42.
-1.41 -> 1.42 Fri Dec 2 20:08:16 1994
- + Make autowrite require the file not be read-only.
- + Make the ex insert command work in empty files.
- + Tab expansion is no longer limited to values < 20 (which matches
- historical practice).
- + Simplify (and fix limit detection for) the # command. It's no
- longer possible to use the # command itself to repeat or modify
- a previous # command, '.' is the only possibility.
- + Lots more reworking of the ex addresses, putting ? and / into
- the ex addressing code broke the world.
- + Make the Put, Preserve and Print commands work (don't ask).
- + Split stdout/stderr from shell expansions; stdout is expansion
- text, stderr is entered on the message queue.
-1.40 -> 1.41 Fri Nov 18 16:13:52 1994
- + Addition of a port for AUX 3.1
- + Addition of a message catalog for Russian.
- + Make vi ? and / commands be true ex addresses (historic practice).
- + Display the date first in vi -r recovery list.
-1.39 -> 1.40 Mon Nov 14 10:46:56 1994
- + Two bug fixes for 1.39; -r option and v_change core dump.
-1.38 -> 1.39 Sun Nov 13 18:04:08 1994
- + Ex substitution with confirmation now matches historic practice
- (except that it still runs in raw mode, not cooked).
- + Nvi now clears the screen before painting, if repainting the
- entire screen.
- + Fix final cursor position for put command entering text in a
- single line.
- + Change to break error message lines on the last <blank> in the
- line.
- + Always center the current line when returning to a previously
- edited file or moving to a tag line that's not visible on the
- screen.
- + Change write of the current file using an explicit name or % to
- match the semantics of :w<CR>, not :w file<CR>.
- + Add command aliases to vi, and remap 6 historic commands to their
- historic counterparts: D->d$, Y->y_, S->c_, C->c$, A->$a, I->^i.
- + Match option display to historic practice; if boolean or numeric
- options changed to default values, not displayed by default.
- Nvi treats string options the same way, vi always displayed any
- string option that was changed.
- + Added lock edit option, if not set, no file locking is done.
- + Rework ex to permit any ex command in the EXINIT variable or
- exrc startup files. This fixes the bug were `vi +100 file'
- painted the screen and then moved to line 100 and repainted.
- (Yanked to SCCS ID 9.1.)
- + Bug fix: could report file modified more recently than it was
- written, incorrectly.
- + Search fix: historically, motions with deltas were not corrected
- to the previous/next line based on the starting/stopping column.
- + Addressing fixes: make trailing non-existent addresses work, change
- % to be text substitution, not a unique address (to follow future
- POSIX).
-1.37 -> 1.38 Mon Oct 24 12:51:58 1994
- + Scrolling fix; ^B can move to nonexistent lines.
- + Fix to vi mapped commands; <escape> characters while already in
- command mode did not historically cause the mapped characters to
- be flushed.
- + Add the backup edit option, automatically version edit files.
- + Make it possible to edit files that db can't read, i.e. edit a
- temporary file, with the correct file name.
- + Only anchor the last line of the file to the bottom line of the
- screen if there's half or less of a screen between the target
- line and the end of the file.
- + Fix wrapmargin text allocation bug.
- + Fix ex put command to work in any empty file.
- + Fix global command to handle move's to line 0 correctly.
- + Regularize the yank cursor motions, several bug fixes for historic
- practice.
- + Fix N and n, when used as a motion command for the ! command,
- repeat the last bang command instead of prompting for a new
- one.
- + Timeout maps beginning with <escape> quickly, instead of based
- on the keytime option.
- + Bug fix for wraplen option, wasn't triggered for input commands.
-1.36 -> 1.37 Sun Oct 9 19:02:53 1994
- + Change PORT directories to install patches before distribution.
- + Fix ^A to set search direction and pattern for consistency.
- + Fold the showdirty option into the showmode option.
- + Ex addressing fix: change search offset and line arguments (e.g.
- the copy command) to be ex addressing offsets, matching historic
- practice.
- + Ex addressing fix: support ^ as an offset/flag equivalent to -.
- + Ex addressing fix: historically, any missing address defaulted to
- dot, e.g. "4,,," was the same as ".,.".
- + Ex addressing fix: historically, <blank> separated numbers were
- additive, e.g. "3 5p" displayed line 8.
- + Ex addressing fix: make ';' as a range delimiter match historic
- practice.
- + Change nvi to exit immediately if stdout isn't a terminal.
- + Change alternate file name behavior to match historic practice,
- make the :write command set the current file name.
- + Text input fix; input keys from a map, with an associated count,
- weren't historically affected by the wrapmargin value.
- + Add wraplen option, same as wrapmargin, but from the left-hand
- column, not the right.
- + Make ex address .<number> be equivalent to .+<number>, i.e. the
- '+' is understood; matches historic practice, and it's widely
- documented for ed(1).
- + Input mode ^V^J historically mapped into a single ^J.
- + Minor catalog changes, fixes; don't use 's' to pluralize words.
-1.35 -> 1.36 Thu Sep 8 08:40:25 1994
- + Don't overwrite user's maps with standard (termcap) mappings.
- + Make \ escape kill and erase characters in vi text input mode.
- + Fix ^D autoindent bug by resolving leading <blank>s at ^D.
- + Rework abbreviation tests (again!) to match historic practice.
- + Change ^D/^U default scrolling value to be based on window option
- value, not screen lines, correct scrolling option value, both to
- match historic practice. NOTE: System V does this differently!
-1.34 -> 1.35 Wed Aug 31 19:20:15 1994
- + Add the historic -l option.
- + Message catalogs.
- + Display global messages at each flush, just in case some are there.
- + Fix global substitute code, `\\' wasn't handled correctly.
- + Fix abbreviation code to use <blank>s as the preceding character.
- + Fix ruler to display logical column, not physical column.
- + Block signals when user issues :preserve command, so no race caused
- by SIGHUP/SIGTERM.
-1.33 -> 1.34 Wed Aug 17 14:37:32 1994 (PUBLICLY AVAILABLE VERSION)
- + Back out sccsid string fix, it won't work on SunOS 4.1.
-1.32 -> 1.33 Wed Aug 17 09:31:41 1994 (PUBLICLY AVAILABLE VERSION)
- + Get back 5K of data space for the sccsid strings.
- + Fix bug where cG fix in version 1.31 broke cw cursor positioning
- when the change command extended the line.
- + Fix core dump in map/seq code if character larger than 7 bits.
- + Block signals when manipulating the SCR chains.
- + Fix memory allocation for machines with multiple pointer sizes.
-1.31 -> 1.32 Mon Aug 15 14:27:49 1994
- + Turn off recno mmap call for Solaris 2.4/SunOS 5.4.
-1.30 -> 1.31 Sun Aug 14 13:13:35 1994
- + Fix bug were cG on the last line of a file wasn't done in line mode,
- and where the cursor wasn't positioned correctly after exiting text
- insert mode.
- + Add termcap workaround to make function keys greater than 9 work
- correctly (or fail if old-style termcap support).
- + Change ex/vi to not flush mapped keys on error -- this is historic
- practice, and people depended on it.
- + Rework vi parser so that no command including a mapped key ever
- becomes the '.' command, matching historic practice.
- + Make <escape> cancellation in the vi parser match POSIX 1003.2.
- + Fix curses bug where standout string was written for each standout
- character, and where standout mode was never exited explicitly.
- Fix bugs in curses SF/sf and SR/sr scrolling, as seen on Sun and
- x86 consoles.
- + The v/global commands execute the print command by default.
- + The number option historically applies to ex as well as vi.
-1.29 -> 1.30 Mon Aug 8 10:30:42 1994
- + Make first read into a temporary set the file's name.
- + Permit any key to continue scrolling or ex commands -- this
- allows stacked colon commands, and matches historic practice.
- + Don't output normal ! command commentary in ex silent mode.
- + Allow +/- flags after substitute commands, make line (flag)
- offsets from vi mode match historic practice.
- + Return <eof> to ex immediately, even if preceded by spaces. Rework
- ex parser to do erase the prompt instead of depending on the print
- routines to do it. Minor fixes to the ex parser for display of
- default and scrolling commands. MORE EX PARSER CHANGES.
-1.28 -> 1.29 Fri Aug 5 10:18:07 1994
- + Make the abbreviated ex delete command work (:dele---###lll for
- example, is historically legal.
- + When autoprint fires, multiple flags may be set, use ex_print
- directly instead of the stub routines.
- + Change v/global commands to turn off autoprint while running.
- + Minor changes to make the ! command display match historic output.
- + Rework the ex parser to permit multiple command separators without
- commands -- MAJOR CHANGE, likely to introduce all sorts of new bugs.
- + Fix cd command to expand argument in the context of each element
- of the cdpath option, make relative paths always relative to the
- current directory.
- + Rework write/quit cases for temporary files, so that user's don't
- discard them accidentally.
- + Check for window size changes when continuing after a suspend.
- + Fix memory problem in svi_screen, used free'd memory.
- + Change the ex change, insert, append commands to match historic
- cursor positions if no data entered by the user.
- + Change ex format flags (#, l, p) to affect future commands, not
- just the current one, to match historic practice.
- + Make the user's EOF character an additional scroll character in ex.
- + Fix ex ^D scrolling to be the value of the scroll option, not half
- the screen.
- + Fix buffer execution to match historic practice -- bugs where the
- '*' command didn't work, and @<carriage-return> didn't work.
- + Fix doubled reporting of deleted lines in filters.
- + Rework the % ` / ? ( ) N n { and ^A commands to always cut into
- numeric buffers regardless of the location or length of the cut.
- This matches historic practice.
- + Fix the { command to check the current line if the cursor doesn't
- start on the first character of the line.
- + Do '!' expansion in the ex read command arguments, it's historic
- practice. In addition, it sets the last '!' command.
-1.27 -> 1.28 Wed Jul 27 21:29:18 1994
- + Add support for scrolling using the CS and SF/sf/SR/sr termcap
- strings to the 4BSD curses.
- + Rework of getkey() introduced a bug where command interrupt put
- nvi into an infinite loop.
- + Piping through a filter historically cut the replaced lines into
- the default buffer, although not the numeric ones.
- + Read of a filter and !! historically moved to the first nonblank
- of the resulting cursor line (most of the time).
- + Rework cursor motion flags, to support '!' as a motion command.
-1.26 -> 1.27 Tue Jul 26 10:27:58 1994
- + Add the meta option, to specify characters the shell will expand.
- + Fix the read command to match historic practice, the white space
- and bang characters weren't getting parsed correctly.
- + Change SIGALRM handler to save and restore errno.
- + Change SunOS include/compat.h to include <vfork.h> so that the
- ex/filter.c code works again.
- + Don't put lines deleted by the ex delete command into the numeric
- buffers, matching historic practice.
- + Fix; if appending to a buffer, default buffer historically only
- references the appended text, not the resulting text.
- + Support multiple, semi-colon separated search strings, and 'z'
- commands after search strings.
- + Make previous context mark setting match historic practice (see
- docs/internals/context).
- + Fix the set command to permit whitespace between the option and
- the question mark, fix question marks in general.
- + Fix bug where ex error messages could be accidentally preceded
- by a single space.
- + Fix bug where curses reorganization could lose screen specific
- mappings as soon as any screen exited.
- + Fix bug in paragraph code where invalid macros could be matched.
- Make paragraph motions stop at formfeed (^L) characters.
- + Change 'c' to match historic practice, it cut text into numeric
- buffers.
-1.25 -> 1.26 Tue Jul 19 17:46:24 1994
- + Ignore SIGWINCH if the screen size is unchanged; SunOS systems
- deliver one when a screen is uncovered.
- + Fix: don't permit a command with a motion component to wrap due
- to wrapscan and return to the original cursor position.
- + Fix: ^E wasn't beeping when reaching the bottom of the file.
- + Fix bg/fg bug where tmp file exiting caused a NULL dereference.
- + Rework file locking code to use fcntl(2) explicitly.
- + Fix bug in section code where invalid macros could be matched.
- + Fix bug where line number reset by vi's Q command.
- + Add explicit character mode designation to character mode buffers.
- + Add <sys/ioctl.h> include to sex/sex_window.c, needed by NET/2
- vintage systems.
- + Change to always flush a character during suspend, 4BSD curses
- has the optimization where it doesn't flush after a standend().
- + Fix bug on OSF1 where <curses.h> changes the values of VERASE,
- VKILL and VWERASE to incorrect ones.
- + Fix bug where optarg used incorrectly in main.c.
- + Block all signals when acting on a signal delivery.
- + Fix recovery bug where RCV_EMAIL could fire even if there wasn't
- a backing file; format recovery message.
-1.24 -> 1.25 Sun Jul 17 14:33:38 1994
- + Stop allowing keyboard suspends (^Z) in insert mode, it's hard
- to get autowrite correct, and it's not historic practice.
- + Fix z^, z+ to match historic practice.
- + Bug in message handling, "vi +35 non-existent_file" lost the
- status message because the "+35" pushed onto the stack erased
- it. For now, change so that messages aren't displayed if there
- are keys waiting -- may need to add a "don't-erase" bit to the
- character in the stack instead.
- + Bug in svi_msgflush(), where error messages could come out in
- normal video.
-1.23 -> 1.24 Sat Jul 16 18:30:18 1994
- + Fix core dump in exf.c, where editing a non-existent file and
- exiting could cause already free'd memory to be free'd.
- + Clean up numerous memory errors, courtesy of Purify.
- + Change process wait code to fail if wait fails, and not attempt
- to interpret the wait return information.
- + Open recovery and DB files for writing as well as reading, System
- V (fcntl) won't let you acquire LOCK_EX locks otherwise.
- + Fix substitute bug where could malloc 0 bytes (AIX breaks).
- + Permit the mapping of <carriage-return>, it's historic practice.
- + Historic vi didn't eat <blank> characters before the force
- flag, match historic practice.
- + Bug in ex argument parsing, corrected for literal characters
- twice.
- + Delete screen specific maps when the screen closes.
- + Move to the first non-<blank> in the line on startup; historic
- practice.
- + Change the ex visual command to move directly to a line if no
- trailing 'z' command.
- + Fix "[[" and "]]" to match historic practice (yet again...).
- + Fix "yb" and "y{" commands to update the cursor correctly.
- + Change "~<motion>" to match the yank cursor movement semantics
- exactly.
- + Move all of the curses related code into sex/svi -- major rework,
- but should help in future ports.
- + Fix bug in split code caused by new file naming code, where would
- drop core when a split screen exited.
- + Change svi_ex_write to do character display translation, so that
- messages with file names in them are displayed correctly.
- + Display the file name on split screens instead of a divider line.
- + Fix move bug, wasn't copying lines before putting them.
- + Fix bug were :n dropped core if no arguments supplied.
- + Don't quote characters in executed buffer: "ifoo<esc>" should leave
- insert mode after the buffer is executed.
- + Tagpop and tagpush should set the absolute mark in case only moving
- within a file.
- + Skip leading whitespace characters before tags and cursor word
- searches.
- + Fix bug in ex_global where re_conv() was allocating the temporary
- buffer and not freeing it.
-1.22 -> 1.23: Wed Jun 29 19:22:33 1994
- + New <sys/cdefs.h> required "inline" to change to "__inline"
- + Fix System V curses code for new ^Z support.
- + Fix off-by-one in the move code, avoid ":1,$mo$" with only one
- line in the buffer.
- + Line orientation of motion commands was remembered too long,
- i.e. '.' command could be incorrectly marked as line oriented.
- + Move file modification time into EXF, so it's shared across
- split screens.
- + Put the prev[ious] command back in, people complained.
- + Random fixes to next/prev semantics changed in 1.22.
- + Historically vi doesn't only move to the last address if there's
- ANYTHING after the addresses, e.g. ":3" moves to line 3, ":3|"
- prints line 3.
-1.21 -> 1.22: Mon Jun 27 11:01:41 1994
- + Make the line between split screens inverse video again.
- + Delete the prev[ious] command, it's not useful enough to keep.
- + Rework :args/file name handling from scratch -- MAJOR CHANGE,
- likely to introduce all sorts of new bugs.
- + Fix RE bug where no subexpressions in the pattern but there were
- subexpressions referenced in the replacement, e.g. "s/XXX/\1/g".
- + Change recovery to not leave unmodified files around after a
- crash, by using the owner 'x' bit on unmodified backup files.
- MAJOR CHANGE, the system recovery script has to change!
- + Change -r option to delete recovery.* files that reference non-
- existent vi.* files.
- + Rework recovery locking so that fcntl(2) locking will work.
- + Fix append (upper-case) buffers, broken by cut fixes.
- + Fix | to not set the absolute motion mark.
- + Read $HOME/.exrc file on startup if the effective user ID is
- root. This makes running vi while su(1)'d work correctly.
- + Use the full pathname of the file as the recovery name, not
- just the last component. Matches historic practice.
- + Keep marks in empty files from being destroyed.
- + Block all caught signals before calling the DB routines.
- + Make the line change report match historic practice (yanked
- lines were different than everything else).
- + Add section on multiple screens to the reference manual.
- + Display all messages at once, combine onto a single line if
- possible. Delete the trailing period from all messages.
-1.20 -> 1.21: Thu May 19 12:21:58 1994
- + Delete the -l flag from the recover mail.
- + Send the user email if ex command :preserve executed, this matches
- historic practice. Lots of changes to the preserve and recovery
- code, change preserve to snapshot files (again, historic practice).
- + Make buffers match historic practice: "add logically stores text
- into buffer a, buffer 1, and the unnamed buffer.
- + Print <tab> characters as ^I on the colon command line if the
- list option set.
- + Adjust ^F and ^B scroll values in the presence of split screens
- and small windows.
- + Break msg* routines out from util.c into msg.c, start thinking
- about message catalogs.
- + Add tildeop set option, based on stevie's option of the same name.
- Changes the ~ command into "[count] ~ motion", i.e. ~ takes a
- trailing motion.
- + Chose NOT to match historic practice on cursor positioning after
- consecutive undo commands on a single line; see vi/v_undo.c for
- the comment.
- + Add a one line cache so that multiple changes to the same line
- are only counted once (e.g. "dl35p" changes one line, not 35).
- + Rework signals some more. Block file sync signals in vi routines
- that interface to DB, so can sync the files at interrupt time.
- Write up all of the signal handling arguments, see signal.c.
-1.19 -> 1.20: Thu May 5 19:24:57 1994
- + Return ^Z to synchronous handling. See the dicussion in signal.c
- and svi_screen.c:svi_curses_init().
- + Fix bug where line change report was wrong in util.c:msg_rpt().
-1.18 -> 1.19: Thu May 5 12:59:51 1994
- + Block DSUSP so that ^Y isn't delivered at SIGTSTP.
- + Fix bug -- put into an empty file leaves the cursor at 1,0,
- not the first nonblank.
- + Fix bug were number of lines reported for the 'P' command was
- off-by-one.
- + Fix bug were 0^D wasn't being handled correctly.
- + Delete remnants of ^Z as a raw character.
- + Fix bug where if a map was an entire colon command, it may never
- have been displayed.
- + Final cursor position fixes for the vi T and t commands.
- + The ex :next command took an optional ex command as it's first
- argument similar to the :edit commands. Match historic practice.
-1.17 -> 1.18: Wed May 4 13:57:10 1994
- + Rework curses information in the PORT/Makefile's.
- + Minor fixes to ^Z asynchronous code.
-1.16 -> 1.17: Wed May 4 11:15:56 1994
- + Make ex comment handling match historic practice.
- + Make ^Z work asynchronously, we can no longer use the SIGTSTP
- handler in the curses library.
-1.15 -> 1.16: Mon May 2 19:42:07 1994
- + Make the 'p' and 'P' commands support counts, i.e. "Y10p" works.
- + Make characters that map to themselves as the first part of the
- mapping work, it's historic practice.
- + Fix bug where "s/./\& /" discarded the space in the replacement
- string.
- + Add support for up/down cursor arrows in text input mode, rework
- left/right support to match industry practice.
- + Fix bug were enough character remapping could corrupt memory.
- + Delete O_REMAPMAX in favor of setting interrupts after N mapped
- characters without a read, delete the map counter per character.
- MAJOR CHANGE. All of the interrupt signal handling has been
- reworked so that interrupts are always turned on instead of
- being turned on periodically, when an interruptible operation is
- pending.
- + Fix bug where vi wait() was interrupted by the recovery alarm.
- + Make +cmd's and initial commands execute with the current line
- set to the last line of the file. This is historic practice.
- + Change "lock failed" error message to a file status message.
- It always fails over NFS, and making all NFS files readonly
- isn't going to fly.
- + Use the historic line number format, but check for overflow.
- + Fix bug where vi command parser ignored buffers specified as
- part of the motion command.
- + Make [@*]buffer commands on character mode buffers match historic
- practice.
- + Fix bug where the cmap/chf entries of the tty structure weren't
- being cleared when new characters were read.
- + Fix bug where the default command motion flags were being set
- when the command was a motion component.
- + Fix wrapmargin bug; if appending characters, and wrapmargin breaks
- the line, an additional space is eaten.
-1.14 -> 1.15: Fri Apr 29 07:44:57 1994
- + Make the ex delete command work in any empty file.
- + Fix bug where 't' command placed the cursor on the character
- instead of to its left.
- + ^D and ^U didn't set the scroll option value historically.
- Note, this change means that any user set value (e.g. 15^D)
- will be lost when splitting the screen, since the split code
- now resets the scroll value regardless.
- + Fix the ( command to set the absolute movement mark.
- + Only use TIOCGWINSZ for window information if SIGWINCH signal
- caught.
- + Delete the -l flag, and make -r work for multiple arguments.
- Add the ex "recover[!] file" command.
- + Switch into ex terminal mode and use the sex routines when
- append/change/insert called from vi mode.
- + Make ^F and ^B match historic practice. This required a fairly
- extensive rework of the svi scrolling code.
- + Cursor positioning in H, M, L, G (first non-blank for 1G) wasn't
- being done correctly. Delete the SETLFNB flag. H, M, and L stay
- logical movements (SETNNB) and G always moves to the first nonblank.
- + System V uses "lines" and "cols", not "li" and "co", change as
- necessary. Check termcap function returns for errors.
- + Fix `<character> command to do start/end of line correction,
- and to set line mode if starting and stopping at column 0.
- + Fix bug in delete code where dropped core if deleted in character
- mode to an empty line. (Rework the delete code for efficiency.)
- + Give up on SunOS 4.1.X, and use "cc" instead of /usr/5bin/cc.
- + Protect ex_getline routine from interrupted system calls (if
- possible, set SA_RESTART on SIGALRM, too).
- + Fix leftright scrolling bug, when moving to a shorter line.
- + Do validity checking on the copy, move, t command target line
- numbers.
- + Change for System V % pattern broke trailing flags for empty
- replacement strings.
- + Fix bug when RCM flags retained in the saved dot structure.
- + Make the ex '=' command work for empty files.
- + Fix bug where special_key array was being free'd (it's no longer
- allocated).
- + Matches cut in line mode only if the starting cursor is at or
- before the first nonblank in its line, and the ending cursor is
- at or after the last nonblank in its line.
- + Add the :wn command, so you can write a file and switch to a new
- file in one command.
- + Allow only a single key as an argument to :viusage.
- + New movement code broke filter/paragraph operations in empty
- files ("!}date" in an empty file was dropping core).
-1.12 -> 1.14: Mon Apr 18 11:05:10 1994 (PUBLICLY AVAILABLE VERSION, 4.4BSD)
- + Fix FILE structure leakage in the ex filter code.
- + Rework suspend code for System V curses. Nvi has to do the
- the work, there's no way to get curses to do it right.
- + Revert SunOS 4.1.X ports to the distributed curses. There's
- a bug in Sun's implementation that we can't live with.
- + Quit immediately if row/column values are unreasonable.
- + Fix the function keys to match vi historic behavior.
- + Replace the echo/awk magic in the Makefile's with awk scripts.
-1.11 -> 1.12: Thu Apr 14 11:10:19 1994
- + Fix bug where only the first vi key was checked for validity.
- + Make 'R' continue to overwrite after a <carriage-return>.
- + Only display the "no recovery" message once.
- + Rework line backup code to restore the line to its previous
- condition.
- + Don't permit :q in a .exrc file or EXINIT variable.
- + Fix wrapscan option bug where forward searches become backward
- searches and do cursor correction accordingly.
- + Change "dd" to move the cursor to the first non-blank on the line.
- + Delete cursor attraction to the first non-blank, change non-blank
- motions to set the most attractive cursor position instead.
- + Fix 'r' substitute option to set the RE to the last RE, not the
- last substitute RE.
- + Fix 'c' and 'g' substitute options to always toggle, and fix
- edcompatible option to not reset them.
- + Display ex error messages in inverse video.
- + Fix errorbells option to match historic practice.
- + Delete fixed character display table in favor of table built based
- on the current locale.
- + Add ":set octal" option, that displays unknown characters as octal
- values instead of the default hexadecimal.
- + Make all command and text input modes interruptible.
- + Fix ex input mode to display error messages immediately, instead
- of waiting for the lines to be resolved.
- + Fix bug where vi calling append could overwrite the command.
- + Fix off-by-one in the ex print routine tab code.
- + Fix incorrect ^D test in vi text input routines.
- + Add autoindent support for ex text insert routines.
- + Add System V substitute command replacement pattern semantics,
- where '%' means the last replacement pattern.
- + Fix bug that \ didn't escape newlines in ex commands.
- + Regularize the names of special characters to CH_*.
- + Change hex insert character from ^Vx<hex_char> to ^X<hex_char>
- + Integrate System V style curses, so SunOS and Solaris ports can
- use the native curses implementation.
-1.10 -> 1.11: Thu Mar 24 16:07:45 EST 1994 (PUBLICLY AVAILABLE VERSION)
- + Change H, M, and L to set the absolute mark, historical practice.
- + Fix bug in stepping through multiple tags files.
- + Add "remapmax" option that turns off map counts so you can remap
- infinitely. If it's off, term_key() can be interrupted from the
- keyboard, which will cause the buffers to flush. I also dropped
- the default max number of remaps to 50. (Only Dave Hitz's TM
- macros and maze appear to go over that limit.)
- + Change :mkexrc to not dump w{300,1200,9600}, lisp options.
- + Fix backward search within a line bug.
- + Change all the includes of "pathnames.h" to use <>'s so that the
- PORT versions can use -I. to replace it with their own versions.
- + Make reads and writes interruptible. Rework code that enters and
- leaves ex for '!' and filter commands, rework all interrupt and
- timer code.
- + Fix core dump when user displayed option in .exrc file.
- + Fix bug where writing empty files didn't update the saved
- modification time.
- + Fix bug where /pattern/ addressing was always a backward search.
- + Fix bug triggered by autoindent of more than 32 characters, where
- nvi wasn't checking the right TEXT length.
- + Fix bug where joining only empty lines caused a core dump.
-1.09 -> 1.10: Sat Mar 19 15:40:29 EST 1994
- + Fix "set all" core dump.
-1.08 -> 1.09: Sat Mar 19 10:11:14 EST 1994
- + If the tag's file path is relative, and it doesn't exist, check
- relative to the tag file location.
- + Fix ~ command to free temporary buffer on error return.
- + Create vi.ref, a first cut at a reference document for vi.
- The manual page and the reference document only document the
- set options, so far.
- + Fix 1G bug not always going to the first non-blank.
- + Upgrade PORT/regex to release alpha3.4, from Henry Spencer.
- + Add MKS vi's "cdpath" option, supporting a cd search path.
- + Handle if search as a motion was discarded, i.e. "d/<erase>".
- + Change nvi to not create multiple recovery files if modifying
- a recovered file.
- + Decide to ignore that the cursor is before the '$' when inserting
- in list mode. It's too hard to fix.
-1.07 -> 1.08: Wed Mar 16 07:37:36 EST 1994
- + Leftright and big line scrolling fixes. This meant more changes
- to the screen display code, so there may be new problems.
- + Don't permit search-style addresses until a file has been read.
- + "c[Ww]" command incorrectly handled the "in whitespace" case.
- + Fix key space allocation bug triggered by cut/paste under SunOS.
- + Ex move command got the final cursor position wrong.
- + Delete "optimize option not implemented" message.
- + Make the literal-next character turn off mapping for the next
- character in text input mode.
-1.06 -> 1.07: Mon Mar 14 11:10:33 EST 1994
- + The "wire down" change in 1.05 broke ex command parsing, there
- wasn't a corresponding change to handle multiple K_VLNEXT chars.
- + Fix final position for vi's 't' command.
-1.05 -> 1.06: Sun Mar 13 16:12:52 EST 1994
- + Wire down ^D, ^H, ^W, and ^V, regardless of the user's termios
- values.
- + Add ^D as the ex scroll command.
- + Support ^Q as a literal-next character.
- + Rework abbreviations to be delimited by any !inword() character.
- + Add options description to the manual page.
- + Minor screen cache fix for svi_get.c.
- + Rework beautify option support to match historical practice.
- + Exit immediately if not reading from a tty and a command fails.
- + Default the SunOS 4.* ports to the distributed curses, not SMI's.
-1.04 -> 1.05: Thu Mar 24 16:07:45 EST 1994
- + Make cursor keys work in input mode.
- + Rework screen column code in vi curses screen. MAJOR CHANGE --
- after this, we'll be debugging curses screen presentation from
- scratch.
- + Explode include files in vi.h into the source files.
-1.03 -> 1.04: Sun Mar 6 14:14:16 EST 1994
- + Make the ex move command keep the marks on the moved lines.
- + Change resize semantics so you can set the screen size to a
- specific value. A couple of screen fixes for the resize code.
- + Fixes for foreground/background due to SIGWINCH.
- + Complete rework of all of vi's cursor movements. The underlying
- assumption in the old code was that the starting cursor position
- was part of the range of lines cut or deleted. The command
- "d[[" is an example where this isn't true. Change it so that all
- motion component commands set the final cursor position separately
- from the range, as it can't be done correctly later. This is a
- MAJOR CHANGE -- after this change, we'll be debugging the cursor
- positioning from scratch.
- + Rewrite the B, b, E, e commands to use vi's getc() interface
- instead of rolling their own.
- + Add a second MARK structure, LMARK, which is the larger mark
- needed by the logging and mark queue code. Everything else uses
- the reworked MARK structure, which is simply a line/column pair.
- + Rework cut/delete to not expect 1-past-the-end in the range, but
- to act on text to the end of the range, inclusive.
- + Sync on write's, to force NFS to flush.
-1.01 -> 1.03: Sun Jan 23 17:50:35 EST 1994 (PUBLICLY AVAILABLE VERSION)
- + Tag stack fixes, was returning to the tag, not the position from
- which the user tagged.
- + Only use from the cursor to the end of the word in cursor word
- searches and tags. (Matches historical vi behavior.)
- + Fix delete-last-line bug when line number option set.
- + Fix usage line for :split command.
- + If O_NUMBER set, long input lines would eventually fail, the column
- count for the second screen of long lines wasn't set correctly.
- + Fix for [[ reaching SOF with a column longer than the first line.
- + Fix for multiple error messages if no screen displayed.
- + Fix :read to set alternate file name as in historical practice.
- + Fix cut to rotate the numeric buffers if line mode flag set.
-1.00 -> 1.01: Wed Jan 12 13:37:18 EST 1994
- + Don't put cut items into numeric buffers if cutting less than
- parts of two lines.
-0.94 -> 1.00: Mon Jan 10 02:27:27 EST 1994
- + Read-ahead not there; BSD tty driver problem, SunOS curses
- problem.
- + Global command could error if it deleted the last line of
- the file.
- + Change '.' to only apply to the 'u' if entered immediately
- after the 'u' command. "1pu.u.u. is still broken, but I
- expect that it's going to be sacrificed for multiple undo.
- + If backward motion on a command, now move to the point; get
- yank cursor positioning correct.
- + Rework cut buffers to match historic practice -- yank/delete
- numeric buffers redone sensibly, ignoring historic practice.
-0.92 -> 0.93: Mon Dec 20 19:52:14 EST 1993
- + Christos Zoulas reimplemented the script windows using pty's,
- which means that they now work reasonably. The down side of
- this is that almost all ports other than 4.4BSD need to include
- two new files, login_tty.c and pty.c from the PORT/clib directory.
- I've added them to the Makefiles.
- + All calloc/malloc/realloc functions now cast their pointers, for
- SunOS -- there should be far fewer warning messages, during the
- build. The remaining messages are where CHAR_T's meet char *'s,
- i.e. where 8-bit clean meets strcmp.
- + The user's argument list handling has been reworked so that there
- is always a single consistent position for use by :next, :prev and
- :rewind.
- + All of the historical options are now at least accepted, although
- not all of them are implemented. (Edcompatible, hardtabs, lisp,
- optimize, redraw, and slowopen aren't implemented.)
- + The RE's have been reworked so that matches of length 0 are handled
- in the same way as vi used to handle them.
- + Several more mapping fixes and ex parser addressing fixes.
diff --git a/contrib/nvi/docs/ev b/contrib/nvi/docs/ev
deleted file mode 100644
index 144295a..0000000
--- a/contrib/nvi/docs/ev
+++ /dev/null
@@ -1,55 +0,0 @@
-# @(#)ev 8.4 (Berkeley) 4/29/94
-
-Ev: Vi: Result:
-<CK> <CK> (Cursor keys). Move around the file.
-
-Meta key commands:
-^A<#> <#>G Goto line #.
-^A$ G Goto the end of the file.
-^A/ / Prompt and execute a forward search.
-^A: : Prompt and execute an ex command.
-^A? ? Prompt and execute a backward search.
-^Ac y'<c> Copy to mark in line mode (or copy the current line).
-^AC y`<c> Copy to mark in character mode.
-^Ad d'<c> Delete to mark in line mode (or delete the current line).
-^AD d`<c> Delete to mark in character mode.
-^Aj J Join lines.
-^Am m<c> Mark the current cursor position.
-^AN N Repeat search in the reverse direction.
-^An ^A Search for the word under the cursor.
-^Ar u Redo a command.
-^Au u Undo a command.
-
-Single key commands:
-^B ^B Page up a screen.
-^C ^C Interrupt long-running commands.
-^D ^D Page down a half-screen.
-^E $ End of line.
-^F ^F Page down a screen.
-^G ^G File status/information.
-^H X Delete the character to the left of the cursor.
-^I (TAB)
-^J j Cursor down one line.
-^K k Cursor up one line.
-^L ^L Redraw the screen.
-^M (CR) ^M In insert mode, split the line at the current cursor,
- creating a new line.
- In overwrite mode, cursor down one line.
-^N n Repeat previous search, in previous direction.
-^O (UNUSED)
-^P p Paste the cut text at the cursor position.
-^Q (XON/XOFF)
-^R (UNUSED)
-^S (XON/XOFF)
-^T D Truncate the line at the cursor position.
-^U ^U Page up a half-screen.
-^V<c> ^V<c> Insert/overwrite with a literal next character.
-^W w Move forward one whitespace separated word.
-^X x Delete the current character.
-^Y (UNUSED)
-^Z ^Z Suspend.
-
-New ex mode commands:
-
-^A:set ov[erwrite] Toggle "insert" mode, so that input keys overwrite
- the existing characters.
diff --git a/contrib/nvi/docs/features b/contrib/nvi/docs/features
deleted file mode 100644
index 51650f9..0000000
--- a/contrib/nvi/docs/features
+++ /dev/null
@@ -1,83 +0,0 @@
-List of things that should be added:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
-+ X11 (Tk, Motif, Xaw) interface.
-+ Interpreted language (Perl, Scheme, Tcl/Rush, Python)
-+ Additional ports: Windows, Windows NT, MSDOS
-+ Forms editing package; use RE's to verify field contents.
-+ Internationalization, including wide character and multibyte support.
-+ Support for single line window editing, including full editing
- capability on the vi colon command line.
-+ Rob Pike's sam style RE's.
-+ Right-to-left and bottom to top text support.
-+ Quitall command, to leave all windows. A ! will force the quit.
-
-List of suggested features:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-+ It would be nice to have the completion mechanism found in tcsh versions
- >= 6.03. For instance, the completion for the `:cd' command will be
- directories only. The completion for the `:set' command will be all
- options not set at that moment, and for `:set un' will be all options
- that are set at that moment. The completion for `:< count' will be the
- flags.
-
-+ Add an command-line option to initially split the screen based on the
- number of file arguments, e.g., "nvi -a file1 file2" would initialize
- a two edit-buffer display.
-
-+ Add a "push" command that would push a file on the tags stack.
- (Essentially make tags a special case of the stack, and make
- the stack more general purpose.)
-
-+ Make :script just run a command and edit the output, and :interactive,
- which allows interactive shell session, instead of just the current
- :script.
-
-+ Add tagging information to the man page so that users can display
- the part of the man page that discusses the command in which they're
- interested.
-
-+ Add a zone option so that you can declare that top/bottom few lines
- of the screen aren't filled except by accident, so that the text
- you ask for is always concentrated in the center of the screen.
-
-+ Change
- :di[splay] tags -> :tags
- :di[splay] screens -> :screens
- :di[splay] buffers -> :buffers
-
-+ A macro record function. Add the ability to record a sequence
- of keystrokes into a named buffer for later use. Handy when
- you're trying to build a semi-complex macro.
-
-+ The semantics of :split, :bg, and :fg aren't right. Someone needs to
- rethink how they should interact. The main problem arises when users
- want to get a window into a new file. Currently, the necessary sequence
- is ":split newfile|^W|:bg". It would be nice if you could simply
- background the current screen and edit a new one.
-
-+ An option to turn on a ``quarter plane'' model so that you can
- go as far to the right or down as you wish. The File or the
- current line is only extended if you actually put down a char at
- the new location. Very handy for ascii graphics and tables.
-
-+ Some way of replacing the command bindings. For this to work
- cleanly the notion of a command must be separate from that of a
- key. (Simulate the Rand editor?)
-
-+ Vertical splitting, so you can see files side by side.
-
-+ Tracking. Two or more files are associated so that when one file
- is scrolled up/down/left/right other files track by the same amount.
- Tracking may be constrained such that two files only track vertically
- or horizontally. This is relatively easy to implement.
-
-+ A status file so that the next time invocation of the editor returns
- to the same place, with the same number of windows etc. In case of
- change of the screen size, reasonable defaults are used. For each
- window size and location of the window, name of the file and position
- in it, any tab settings, any other settings for the window (such as
- insert/overwrite mode, auto indent etc). Last search RE and maybe
- direction. If a file does not exist the next time you invoke the
- editor, its window is left in the same place but with some default
- message.
diff --git a/contrib/nvi/docs/help b/contrib/nvi/docs/help
deleted file mode 100644
index a7b5d74..0000000
--- a/contrib/nvi/docs/help
+++ /dev/null
@@ -1,229 +0,0 @@
-MOVING THE CURSOR:
- k - cursor up ^F - page forward /<pattern><CR> - search forward
- j - cursor down ^B - page backward ?<pattern><CR> - search backward
- h - cursor left w - move forward a "word" n - repeat the last search
- l - cursor right b - move backward a "word"
-
-ENTERING TEXT:
-a - append after the cursor. Use the <escape> key to return to
-i - insert before the cursor. command mode.
-o - open a new line below the cursor.
-O - open new line above the cursor.
-
-WRITING AND EXITING:
-:w<Enter> - write the file
-:q<Enter> - exit the file
-:q!<Enter> - exit without writing the file
-:#<Enter> - move to a line (e.g., :35<Enter> moves to line 35)
-
-MISCELLANEOUS:
-^G - display the file name
- J - join two lines (use i<Enter><escape> to split a line)
- u - undo the last change (enter . after a 'u' to undo more than one change)
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-VI COMMANDS:
- ^A search forward for cursor word
- ^B scroll up by screens
- ^C interrupt an operation (e.g. read, write, search)
- ^D scroll down by half screens (setting count)
- ^E scroll down by lines
- ^F scroll down by screens
- ^G file status
- ^H move left by characters
- ^J move down by lines
- ^L redraw screen
- ^M move down by lines (to first non-blank)
- ^N move down by lines
- ^P move up by lines
- ^R redraw screen
- ^T tag pop
- ^U half page up (set count)
- ^V input a literal character
- ^W move to next screen
- ^Y page up by lines
- ^Z suspend editor
- ^[ <escape> exit input mode, cancel partial commands
- ^\ switch to ex mode
- ^] tag push cursor word
- ^^ switch to previous file
- <space> move right by columns
- ! filter through command(s) to motion
- # number increment/decrement
- $ move to last column
- % move to match
- & repeat substitution
- ' move to mark (to first non-blank)
- ( move back sentence
- ) move forward sentence
- + move down by lines (to first non-blank)
- , reverse last F, f, T or t search
- - move up by lines (to first non-blank)
- . repeat the last command
- / search forward
- 0 move to first character
- : ex command
- ; repeat last F, f, T or t search
- < shift lines left to motion
- > shift lines right to motion
- ? search backward
- @ execute buffer
- A append to the line
- B move back bigword
- C change to end-of-line
- D delete to end-of-line
- E move to end of bigword
- F character in line backward search
- G move to line
- H move to count lines from screen top
- I insert before first nonblank
- J join lines
- L move to screen bottom
- M move to screen middle
- N reverse last search
- O insert above line
- P insert before cursor from buffer
- Q switch to ex mode
- R replace characters
- S substitute for the line(s)
- T before character in line backward search
- U Restore the current line
- W move to next bigword
- X delete character before cursor
- Y copy line
- ZZ save file and exit
- [[ move back section
- ]] move forward section
- ^ move to first non-blank
- _ move to first non-blank
- ` move to mark
- a append after cursor
- b move back word
- c change to motion
- d delete to motion
- e move to end of word
- f character in line forward search
- h move left by columns
- i insert before cursor
- j move down by lines
- k move up by lines
- l move right by columns
- m set mark
- n repeat last search
- o append after line
- p insert after cursor from buffer
- r replace character
- s substitute character
- t before character in line forward search
- u undo last change
- w move to next word
- x delete character
- y copy text to motion into a cut buffer
- z reposition the screen
- { move back paragraph
- | move to column
- } move forward paragraph
- ~ reverse case
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-EX COMMANDS:
- ^D: scroll lines
- !: filter lines through commands or run commands
- #: display numbered lines
- &: repeat the last substitution
- *: execute a buffer
- <: shift lines left
- =: display line number
- >: shift lines right
- @: execute a buffer
- append: append input to a line
- abbreviate: specify an input abbreviation
- args: display file argument list
- bg: background the current screen
- change: change lines to input
- cd: change the current directory
- chdir: change the current directory
- copy: copy lines elsewhere in the file
- cscope: create a set of tags using a cscope command
- delete: delete lines from the file
- display: display buffers, screens or tags
- [Ee]dit: begin editing another file
- [Ee]x: begin editing another file
- exusage: display ex command usage statement
- file: display (and optionally set) file name
- fg: switch the current screen and a backgrounded screen
- global: execute a global command on lines matching an RE
- help: display help statement
- insert: insert input before a line
- join: join lines into a single line
- k: mark a line position
- list: display lines in an unambiguous form
- move: move lines elsewhere in the file
- mark: mark a line position
- map: map input or commands to one or more keys
- mkexrc: write a .exrc file
- [Nn]ext: edit (and optionally specify) the next file
- number: change display to number lines
- open: enter "open" mode (not implemented)
- print: display lines
- perl: run the perl interpreter with the command
- perldo: run the perl interpreter with the command, on each line
- preserve: preserve an edit session for recovery
- [Pp]revious: edit the previous file in the file argument list
- put: append a cut buffer to the line
- quit: exit ex/vi
- read: append input from a command or file to the line
- recover: recover a saved file
- resize: grow or shrink the current screen
- rewind: re-edit all the files in the file argument list
- s: substitute on lines matching an RE
- script: run a shell in a screen
- set: set options (use ":set all" to see all options)
- shell: suspend editing and run a shell
- source: read a file of ex commands
- stop: suspend the edit session
- suspend: suspend the edit session
- t: copy lines elsewhere in the file
- [Tt]ag: edit the file containing the tag
- tagnext: move to the next tag
- tagpop: return to the previous group of tags
- tagprev: move to the previous tag
- tagtop: discard all tags
- tcl: run the tcl interpreter with the command
- undo: undo the most recent change
-unabbreviate: delete an abbreviation
- unmap: delete an input or command map
- v: execute a global command on lines NOT matching an RE
- version: display the program version information
- visual: enter visual (vi) mode from ex mode
- [Vv]isual: edit another file (from vi mode only)
- viusage: display vi key usage statement
- write: write the file
- wn: write the file and switch to the next file
- wq: write the file and exit
- xit: exit
- yank: copy lines to a cut buffer
- z: display different screens of the file
- ~: replace previous RE with previous replacement string,
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-Edit options:
-noaltwerase filec="" nomodeline scroll=17 notildeop
-autoindent flash msgcat="./" nosearchincr timeout
-autoprint hardtabs=0 noprint="" nosecure nottywerase
-noautowrite noiclower nonumber shiftwidth=8 noverbose
-backup="" noignorecase nooctal noshowmatch warn
-nobeautify keytime=6 open noshowmode window=35
-cedit="" noleftright optimize sidescroll=16 nowindowname
-columns=80 lines=36 print="" noslowopen wraplen=0
-comment nolisp prompt nosourceany wrapmargin=0
-noedcompatible nolist readonly tabstop=8 wrapscan
-escapetime=1 lock noredraw taglength=0 nowriteany
-noerrorbells magic remap tags="tags"
-exrc matchtime=7 report=5 term="xterm"
-noextended mesg ruler noterse
-cdpath="/usr/src/local/nvi:/tmp"
-directory="/tmp"
-paragraphs="IPLPPPQPP LIpplpipbp"
-recdir="/var/tmp/vi.recover"
-sections="NHSHH HUnhsh"
-shell="/bin/csh"
-shellmeta="~{[*?$`'"\"
diff --git a/contrib/nvi/docs/internals/autowrite b/contrib/nvi/docs/internals/autowrite
deleted file mode 100644
index dbad6c8..0000000
--- a/contrib/nvi/docs/internals/autowrite
+++ /dev/null
@@ -1,88 +0,0 @@
-# @(#)autowrite 8.3 (Berkeley) 2/17/95
-
-Vi autowrite behavior, the fields with *'s are "don't cares".
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-Commands that are affected only by autowrite:
-
-Command File Autowrite? Action:
- modified?
------------------------------------------------
-^Z Y Y Write file and suspend.
-^Z Y N Suspend.
-^Z N * Suspend.
-
-# This behavior is NOT identical to :edit.
-^^ Y Y Write file and jump.
-^^ Y N Error.
-^^ N * Jump.
-
-# The new nvi command ^T (:tagpop) behaves identically to ^].
-# This behavior is identical to :tag, :tagpop, and :tagpush with
-# force always set to N.
-^] Y Y Write file and jump.
-^] Y N Error.
-^] N * Jump.
-
-# There's no way to specify a force flag to the '!' command.
-:! Y Y Write file and execute.
-:! Y N Warn (if warn option) and execute.
-:! N * Execute.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-Commands that are affected by both autowrite and force:
-
-NOTE: the "force" flag is never passed on, i.e. the write
-to the file caused by the autowrite flag is never forced.
-
-Command File Autowrite? Force? Action:
- modified? (!)
--------------------------------------------------------
-# The first rule (YYY) is historic practice, but seems wrong.
-# In nvi, :next and :prev commands behave identically to :rewind.
-:next Y Y Y Write changes and jump.
-:next Y Y N Write changes and jump.
-:next Y N Y Abandon changes and jump.
-:next Y N N Error.
-:next N * * Jump.
-
-:rewind Y Y Y Abandon changes and jump.
-:rewind Y Y N Write changes and jump.
-:rewind Y N Y Abandon changes and jump.
-:rewind Y N N Error.
-:rewind N * * Jump.
-
-# The new nvi commands, :tagpop and :tagtop, behave identically to :tag.
-# Note, this behavior is the same as :rewind and friends, as well.
-:tag Y Y Y Abandon changes and jump.
-:tag Y Y N Write changes and jump.
-:tag Y N Y Abandon changes and jump.
-:tag Y N N Error.
-:tag N * * Jump.
-
-# The command :suspend behaves identically to :stop.
-:stop Y Y Y Suspend.
-:stop Y Y N Write changes and suspend.
-:stop Y N Y Suspend.
-:stop Y N N Suspend.
-:stop N * * Suspend.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-Commands that might be affected by autowrite, but aren't:
-
-Command File Autowrite? Force? Action:
- modified? (!)
--------------------------------------------------------
-#:ex, and :vi (executed while in vi mode) behave identically to :edit.
-:edit Y * Y Abandon changes and jump.
-:edit Y * N Error.
-:edit N * * Jump.
-
-:quit Y * Y Quit.
-:quit Y * N Error.
-:quit N * * Quit.
-
-:shell * * * Execute shell.
-
-:xit Y * * Write changes and exit.
-:xit N * * Exit.
diff --git a/contrib/nvi/docs/internals/context b/contrib/nvi/docs/internals/context
deleted file mode 100644
index 8b1db32..0000000
--- a/contrib/nvi/docs/internals/context
+++ /dev/null
@@ -1,32 +0,0 @@
-# @(#)context 8.6 (Berkeley) 10/14/94
-
-In historic vi, the previous context mark was always set:
-
-ex address:
- any number, <question-mark>, <slash>, <dollar-sign>,
- <single-quote>, <backslash>
-
-ex commands: undo, "z.", global, v
-
-vi commands: (, ), {, }, %, [[, ]], ^]
-
-nvi adds the vi command ^T to this list.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-In historic vi, the previous context mark was set if the
-line changed:
-
-vi commands: '<mark>, G, H, L, M, z
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-In historic vi, the previous context mark was set if the
-line or column changed:
-
-vi commands: `<mark>, /, ?, N, n
-
-nvi adds the vi command ^A to this list.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-In historic vi, the previous context mark was set in non-visual
-mode for ^R and ^L if the line changed, but I have yet to figure
-out how the line could change.
diff --git a/contrib/nvi/docs/internals/cscope.NOTES b/contrib/nvi/docs/internals/cscope.NOTES
deleted file mode 100644
index e0e3483..0000000
--- a/contrib/nvi/docs/internals/cscope.NOTES
+++ /dev/null
@@ -1,142 +0,0 @@
-Cscope Notes:
-
-The nvi tags structure has been reworked to handle the notion of multiple
-locations per tag. This supports cscope, which returns multiple locations
-per query. It will hopefully support ctags programs that create databases
-with multiple locations per tag as well.
-
-There is now a list of "tag queues" chained from each screen. Each tag
-queue has one or more "tag locations".
-
- +----+ +----+ +----+ +----+
- | EP | -> | Q1 | <-- | T1 | <-- | T2 |
- +----+ +----+ --> +----+ --> +----+
- |
- +----+ +----+
- | Q2 | <-- | T1 |
- +----+ --> +----+
- |
- +----+ +----+
- | Q3 | <-- | T1 |
- +----+ --> +----+
-
-In the above diagram, each "Q" is a "tag queue", and each "T" is a
-tag location. Generally, the commands:
-
- :tag create a new Q
- ^[ create a new Q
- :cscope find create a new Q
- :tagnext move to the next T
- :tagprev move to the previous T
- :tagpop discard one or more Q's
- ^T discard the most recent Q
- :tagtop discard all Q's
-
-More specifically:
-
-:cs[cope] a[dd] cscope-dir
-
- Attach to the cscope database in cscope-dir.
-
-:cs[cope] f[ind] c|d|e|f|g|i|s|t buffer|pattern
-
- Query all attached cscopes for the pattern. The pattern is a
- regular expression. If the pattern is a double-quote character
- followed by a valid buffer name (e.g., "t), then the contents
- of the named buffer are used as the pattern.
-
- c: find callers of name
- d: find all function calls made from name
- e: find pattern
- f: find files with name as substring
- g: find definition of name
- i: find files #including name
- s: find all uses of name
- t: find assignments to name
-
- The find command pushes the current location onto the tags stack,
- and switches to the first location resulting from the query, if
- the query returned at least one result.
-
-:cs[cope] h[elp] [command]
-
- List the cscope commands, or usage help on one command.
-
-:display c[onnections]
-
- Display the list of cscope connections
-
-:display t[ags]
-
- The tags display has been enhanced to display multiple tag
- locations per tag query.
-
-:cs[cope] k[ill] #
-
- Kill cscope connection number #.
-
-:cs[cope] r[eset]
- Kill all attached cscopes. Useful if one got hung but you don't
- know which one.
-
-:tagn[ext][!]
-
- Move to the next tag resulting from a query.
-
-:tagpr[ev][!]
-
- Return to the previous tag resulting from a query.
-
-:tagp[op], ^T
-
- Return to the previous tag group (no change).
-
-:tagt[op]
-
- Discard all tag groups (no change).
-
-Suggested maps:
-
- " ^N: move to the next tag
- map ^N :tagnext^M
- " ^P: move to the previous tag
- map ^P :tagprev^M
-
- " Tab+letter performs a C-Scope query on the current word.
- " C-Scope 12.9 has a text-string query (type t).
- " C-Scope 13.3 replaces it with an assignment query; hence a==t.
- map <tab>a "tye:csc find t"t
- map <tab>c "tye:csc find c"t
- map <tab>d "tye:csc find d"t
- map <tab>e "tye:csc find e"t
- map <tab>f "tye:csc find f"t
- map <tab>g "tye:csc find g"t
- map <tab>i "tye:csc find i"t
- map <tab>s "tye:csc find s"t
- map <tab>t "tye:csc find t"t
-
-To start nvi with an initial set of cscope directories, use the environment
-variable CSCOPE_DIRS. This variable should contain a <blank>-separated
-list of directories containing cscope databases. (This MAY be changed to
-be an edit option, I haven't really decided, yet.)
-
-Each cscope directory must contain a file named "cscope.out" which is the
-main cscope database, or nvi will not attempt to connect to a cscope to
-handle requests for that database.
-
-The file "cscope.tpath" may contain a colon-separated directory search
-path which will be used to find the files reported by cscope. If this
-cscope.tpath does not exist, then the paths are assumed to be relative to
-the cscope directory itself. This is an extension to the standard cscope,
-but seems important enough to keep.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-Cscope Availability:
-
-UNIXWare System V Release 4.0 variants such as Sun Solaris 2.x
-(/opt/SUNWspro/bin) have version 11.5, and UNIXWare System V
-Release 4.1 has version 12.10 with an option for much faster
-searching.
-
-You can buy version 13.3 source with an unrestricted license
-for $400 from AT&T Software Solutions by calling +1-800-462-8146.
diff --git a/contrib/nvi/docs/internals/gdb.script b/contrib/nvi/docs/internals/gdb.script
deleted file mode 100644
index a112234..0000000
--- a/contrib/nvi/docs/internals/gdb.script
+++ /dev/null
@@ -1,76 +0,0 @@
-# @(#)gdb.script 8.5 (Berkeley) 5/4/96
-
-# display the VI screen map
-# usage dmap(sp)
-define dmap
- set $h = ((VI_PRIVATE *)$arg0->vi_private)->h_smap
- set $t = ((VI_PRIVATE *)$arg0->vi_private)->t_smap
- while ($h <= $t)
- printf "lno: %2d; soff %d coff %d ", \
- (int)$h->lno, (int)$h->soff, (int)$h->coff
- if ($h->c_ecsize == 0)
- printf "flushed\n"
- else
- printf "\n\tsboff %d; scoff %d\n", \
- (int)$h->c_sboff, (int)$h->c_scoff
- printf "\teboff %d; eclen %d; ecsize %d\n", \
- (int)$h->c_eboff, (int)$h->c_eclen, \
- (int)$h->c_ecsize
- end
- set $h = $h + 1
- end
-end
-
-# display the tail of the VI screen map
-define tmap
- set $h = ((VI_PRIVATE *)$arg0->vi_private)->h_smap
- set $t = ((VI_PRIVATE *)$arg0->vi_private)->t_smap
- while ($t >= $h)
- printf "lno: %2d; soff %d coff %d ", \
- (int)$t->lno, (int)$t->soff, (int)$t->coff
- if ($t->c_ecsize == 0)
- printf "flushed\n"
- else
- printf "\n\tsboff %d; scoff %d\n", \
- (int)$t->c_sboff, (int)$t->c_scoff
- printf "\teboff %d; eclen %d; ecsize %d\n", \
- (int)$t->c_eboff, (int)$t->c_eclen, \
- (int)$t->c_ecsize
- end
- set $t = $t - 1
- end
-end
-
-# display the private structures
-define clp
- print *((CL_PRIVATE *)sp->gp->cl_private)
-end
-define vip
- print *((VI_PRIVATE *)sp->vi_private)
-end
-define exp
- print *((EX_PRIVATE *)sp->ex_private)
-end
-
-# display the marks
-define markp
- set $h = sp->ep->marks.next
- set $t = &sp->ep->marks
- while ($h != 0 && $h != $t)
- printf "key %c lno: %d cno: %d flags: %x\n", \
- ((MARK *)$h)->name, ((MARK *)$h)->lno, \
- ((MARK *)$h)->cno, ((MARK *)$h)->flags
- set $h = ((MARK *)$h)->next
- end
-end
-
-# display the tags
-define tagp
- set $h = sp->taghdr.next
- set $t = &sp->taghdr
- while ($h != 0 && $h != $t)
- printf "tag: %s lno %d cno %d\n", ((TAG *)$h)->frp->fname, \
- ((TAG *)$h)->lno, ((TAG *)$h)->cno
- set $h= ((TAG *)$h)->next
- end
-end
diff --git a/contrib/nvi/docs/internals/input b/contrib/nvi/docs/internals/input
deleted file mode 100644
index 9a7506e..0000000
--- a/contrib/nvi/docs/internals/input
+++ /dev/null
@@ -1,350 +0,0 @@
-# @(#)input 5.5 (Berkeley) 7/2/94
-
-MAPS, EXECUTABLE BUFFERS AND INPUT IN EX/VI:
-
-The basic rule is that input in ex/vi is a stack. Every time a key which
-gets expanded is encountered, it is expanded and the expansion is treated
-as if it were input from the user. So, maps and executable buffers are
-simply pushed onto the stack from which keys are returned. The exception
-is that if the "remap" option is turned off, only a single map expansion
-is done. I intend to be fully backward compatible with this.
-
-Historically, if the mode of the editor changed (ex to vi or vice versa),
-any queued input was silently discarded. I don't see any reason to either
-support or not support this semantic. I intend to retain the queued input,
-mostly because it's simpler than throwing it away.
-
-Historically, neither the initial command on the command line (the + flag)
-or the +cmd associated with the ex and edit commands was subject to mapping.
-Also, while the +cmd appears to be subject to "@buffer" expansion, once
-expanded it doesn't appear to work correctly. I don't see any reason to
-either support or not support these semantics, so, for consistency, I intend
-to pass both the initial command and the command associated with ex and edit
-commands through the standard mapping and @ buffer expansion.
-
-One other difference between the historic ex/vi and nex/nvi is that nex
-displays the executed buffers as it executes them. This means that if
-the file is:
-
- set term=xterm
- set term=yterm
- set term=yterm
-
-the user will see the following during a typical edit session:
-
- nex testfile
- testfile: unmodified: line 3
- :1,$yank a
- :@a
- :set term=zterm
- :set term=yterm
- :set term=xterm
- :q!
-
-This seems like a feature and unlikely to break anything, so I don't
-intend to match historic practice in this area.
-
-The rest of this document is a set of conclusions as to how I believe
-the historic maps and @ buffers work. The summary is as follows:
-
-1: For buffers that are cut in "line mode", or buffers that are not cut
- in line mode but which contain portions of more than a single line, a
- trailing <newline> character appears in the input for each line in the
- buffer when it is executed. For buffers not cut in line mode and which
- contain portions of only a single line, no additional characters
- appear in the input.
-2: Executable buffers that execute other buffers don't load their
- contents until they execute them.
-3: Maps and executable buffers are copied when they are executed --
- they can be modified by the command but that does not change their
- actions.
-4: Historically, executable buffers are discarded if the editor
- switches between ex and vi modes.
-5: Executable buffers inside of map commands are expanded normally.
- Maps inside of executable buffers are expanded normally.
-6: If an error is encountered while executing a mapped command or buffer,
- the rest of the mapped command/buffer is discarded. No user input
- characters are discarded.
-7: Characters in executable buffers are remapped.
-8: Characters in executable buffers are not quoted.
-
-Individual test cases follow. Note, in the test cases, control characters
-are not literal and will have to be replaced to make the test cases work.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-1: For buffers that are cut in "line mode", or buffers that are not cut
- in line mode but which contain portions of more than a single line, a
- trailing <newline> character appears in the input for each line in the
- buffer when it is executed. For buffers not cut in line mode and which
- contain portions of only a single line, no additional characters
- appear in the input.
-
-=== test file ===
-3Gw
-w
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-=== end test file ===
-
- If the first line is loaded into 'a' and executed:
-
-1G"ayy@a
-
- The cursor ends up on the '2', a result of pushing "3Gw^J" onto
- the stack.
-
- If the first two lines are loaded into 'a' and executed:
-
-1G2"ayy@a
-
- The cursor ends up on the 'f' in "foo" in the fifth line of the
- file, a result of pushing "3Gw^Jw^J" onto the stack.
-
- If the first line is loaded into 'a', but not using line mode,
- and executed:
-
-1G"ay$@a
-
- The cursor ends up on the '1', a result of pushing "3Gw" onto
- the stack
-
- If the first two lines are loaded into 'a', but not using line mode,
- and executed:
-
-1G2"ay$@a
-
- The cursor ends up on the 'f' in "foo" in the fifth line of the
- file, a result of pushing "3Gw^Jw^J" onto the stack.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-2: Executable buffers that execute other buffers don't load their
- contents until they execute them.
-
-=== test file ===
-cwLOAD B^[
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-@a@b
-"byy
-=== end test file ===
-
- The command is loaded into 'e', and then executed. 'e' executes
- 'a', which loads 'b', then 'e' executes 'b'.
-
-5G"eyy6G"ayy1G@e
-
- The output should be:
-
-=== output file ===
-cwLOAD B^[
-LOAD B 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-@a@b
-"byy
-=== end output file ===
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-3: Maps and executable buffers are copied when they are executed --
- they can be modified by the command but that does not change their
- actions.
-
- Executable buffers:
-
-=== test file ===
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-@a@b
-"eyy
-cwEXECUTE B^[
-=== end test file ===
-
-4G"eyy5G"ayy6G"byy1G@eG"ep
-
- The command is loaded into 'e', and then executed. 'e' executes
- 'a', which loads 'e', then 'e' executes 'b' anyway.
-
- The output should be:
-
-=== output file ===
-line 1 foo bar baz
-EXECUTE B 2 foo bar baz
-line 3 foo bar baz
-@a@b
-"eyy
-cwEXECUTE B^[
-line 1 foo bar baz
-=== end output file ===
-
- Maps:
-
-=== test file ===
-Cine 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-=== end test file ===
-
- Entering the command ':map = :map = rB^V^MrA^M1G==' shows that
- the first time the '=' is entered the '=' map is set and the
- character is changed to 'A', the second time the character is
- changed to 'B'.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-4: Historically, executable buffers are discarded if the editor
- switches between ex and vi modes.
-
-=== test file ===
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-cwCHANGE^[Q:set
-set|visual|1Gwww
-=== end test file ===
-
-vi testfile
-4G"ayy@a
-
-ex testfile
-$p
-yank a
-@a
-
- In vi, the command is loaded into 'a' and then executed. The command
- subsequent to the 'Q' is (historically, silently) discarded.
-
- In ex, the command is loaded into 'a' and then executed. The command
- subsequent to the 'visual' is (historically, silently) discarded. The
- first set command is output by ex, although refreshing the screen usually
- causes it not to be seen.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-5: Executable buffers inside of map commands are expanded normally.
- Maps inside of executable buffers are expanded normally.
-
- Buffers inside of map commands:
-
-=== test file ===
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-cwREPLACE BY A^[
-=== end test file ===
-
-4G"ay$:map x @a
-1Gx
-
- The output should be:
-
-=== output file ===
-REPLACE BY A 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-cwREPLACE BY A^[
-=== end output file ===
-
- Maps commands inside of executable buffers:
-
-=== test file ===
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-X
-=== end test file ===
-
-:map X cwREPLACE BY XMAP^[
-4G"ay$1G@a
-
- The output should be:
-
-=== output file ===
-REPLACE BY XMAP 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-X
-=== end output file ===
-
- Here's a test that does both, repeatedly.
-
-=== test file ===
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-X
-Y
-cwREPLACED BY C^[
-blank line
-=== end test file ===
-
-:map x @a
-4G"ay$
-:map X @b
-5G"by$
-:map Y @c
-6G"cy$
-1Gx
-
- The output should be:
-
-=== output file ===
-REPLACED BY C 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-X
-Y
-cwREPLACED BY C^[
-blank line
-=== end output file ===
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-6: If an error is encountered while executing a mapped command or
- a buffer, the rest of the mapped command/buffer is discarded. No
- user input characters are discarded.
-
-=== test file ===
-line 1 foo bar baz
-line 2 foo bar baz
-line 3 foo bar baz
-:map = 10GcwREPLACMENT^V^[^[
-=== end test file ===
-
- The above mapping fails, however, if the 10G is changed to 1, 2,
- or 3G, it will succeed.
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-7: Characters in executable buffers are remapped.
-
-=== test file ===
-abcdefghijklmnnop
-ggg
-=== end test file ===
-
-:map g x
-2G"ay$1G@a
-
- The output should be:
-
-=== output file ===
-defghijklmnnop
-ggg
-=== end output file ===
-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-8: Characters in executable buffers are not quoted.
-
-=== test file ===
-iFOO^[
-
-=== end test file ===
-
-1G"ay$2G@a
-
- The output should be:
-
-=== output file ===
-iFOO^[
-FOO
-=== end output file ===
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
diff --git a/contrib/nvi/docs/internals/openmode b/contrib/nvi/docs/internals/openmode
deleted file mode 100644
index c64b767..0000000
--- a/contrib/nvi/docs/internals/openmode
+++ /dev/null
@@ -1,36 +0,0 @@
- @(#)openmode 8.1 (Berkeley) 10/29/94
-
-Open mode has the following special behaviors:
-
-z, ^F, ^B:
- If count is not specified, it shall default to the window
- edit option - 2.
-
- Write lines from the edit buffer starting at:
-
- (the current line) - ((count - 2) / 2)
-
- until:
-
- (((count + 1) / 2) * 2) - 1
-
- lines, or the last line in the edit buffer has been written. A
- line consisting of the smaller of the number of columns in the
- display divided by two or 40 ``-'' characters shall be written
- immediately before and after the specified is written. These two
- lines shall count against the total number of lines to be written.
- A blank line shall be written after the last line is written.
-
- z, ^F and ^B all behave identically.
-
-^D: Display the next scroll value lines, change the current line.
-
-^U: Change the current line, do nothing else.
-
-^E, ^Y: Do nothing.
-
-^L: Clear the screen and redisplay the current line.
-
-H, L, M:
- Move to the first nonblank of the current line and do nothing
- else.
diff --git a/contrib/nvi/docs/internals/quoting b/contrib/nvi/docs/internals/quoting
deleted file mode 100644
index a5fb892..0000000
--- a/contrib/nvi/docs/internals/quoting
+++ /dev/null
@@ -1,208 +0,0 @@
-# @(#)quoting 5.5 (Berkeley) 11/12/94
-
-QUOTING IN EX/VI:
-
-There are four escape characters in historic ex/vi:
-
- \ (backslashes)
- ^V
- ^Q (assuming it wasn't used for IXON/IXOFF)
- The terminal literal next character.
-
-Vi did not use the lnext character, it always used ^V (or ^Q).
-^V and ^Q were equivalent in all cases for vi.
-
-There are four different areas in ex/vi where escaping characters
-is interesting:
-
- 1: In vi text input mode.
- 2: In vi command mode.
- 3: In ex command and text input modes.
- 4: In the ex commands themselves.
-
-1: Vi text input mode (a, i, o, :colon commands, etc.):
-
- The set of characters that users might want to escape are as follows.
- As ^L and ^Z were not special in input mode, they are not listed.
-
- carriage return (^M)
- escape (^[)
- autoindents (^D, 0, ^, ^T)
- erase (^H)
- word erase (^W)
- line erase (^U)
- newline (^J) (not historic practice)
-
- Historic practice was that ^V was the only way to escape any
- of these characters, and that whatever character followed
- the ^V was taken literally, e.g. ^V^V is a single ^V. I
- don't see any strong reason to make it possible to escape
- ^J, so I'm going to leave that alone.
-
- One comment regarding the autoindent characters. In historic
- vi, if you entered "^V0^D" autoindent erasure was still
- triggered, although it wasn't if you entered "0^V^D". In
- nvi, if you escape either character, autoindent erasure is
- not triggered.
-
- Abbreviations were not performed if the non-word character
- that triggered the abbreviation was escaped by a ^V. Input
- maps were not triggered if any part of the map was escaped
- by a ^V.
-
- The historic vi implementation for the 'r' command requires
- two leading ^V's to replace a character with a literal
- character. This is obviously a bug, and should be fixed.
-
-2: Vi command mode
-
- Command maps were not triggered if the second or later
- character of a map was escaped by a ^V.
-
- The obvious extension is that ^V should keep the next command
- character from being mapped, so you can do ":map x xxx" and
- then enter ^Vx to delete a single character.
-
-3: Ex command and text input modes.
-
- As ex ran in canonical mode, there was little work that it
- needed to do for quoting. The notable differences between
- ex and vi are that it was possible to escape a <newline> in
- the ex command and text input modes, and ex used the "literal
- next" character, not control-V/control-Q.
-
-4: The ex commands:
-
- Ex commands are delimited by '|' or newline characters.
- Within the commands, whitespace characters delimit the
- arguments. Backslash will generally escape any following
- character. In the abbreviate, unabbreviate, map and unmap
- commands, control-V escapes the next character, instead.
-
- This is historic behavior in vi, although there are special
- cases where it's impossible to escape a character, generally
- a whitespace character.
-
- Escaping characters in file names in ex commands:
-
- :cd [directory] (directory)
- :chdir [directory] (directory)
- :edit [+cmd] [file] (file)
- :ex [+cmd] [file] (file)
- :file [file] (file)
- :next [file ...] (file ...)
- :read [!cmd | file] (file)
- :source [file] (file)
- :write [!cmd | file] (file)
- :wq [file] (file)
- :xit [file] (file)
-
- Since file names are also subject to word expansion, the
- underlying shell had better be doing the correct backslash
- escaping. This is NOT historic behavior in vi, making it
- impossible to insert a whitespace, newline or carriage return
- character into a file name.
-
-4: Escaping characters in non-file arguments in ex commands:
-
- :abbreviate word string (word, string)
-* :edit [+cmd] [file] (+cmd)
-* :ex [+cmd] [file] (+cmd)
- :map word string (word, string)
-* :set [option ...] (option)
-* :tag string (string)
- :unabbreviate word (word)
- :unmap word (word)
-
- These commands use whitespace to delimit their arguments, and use
- ^V to escape those characters. The exceptions are starred in the
- above list, and are discussed below.
-
- In general, I intend to treat a ^V in any argument, followed by
- any character, as that literal character. This will permit
- editing of files name "foo|", for example, by using the string
- "foo\^V|", where the literal next character protects the pipe
- from the ex command parser and the backslash protects it from the
- shell expansion.
-
- This is backward compatible with historical vi, although there
- were a number of special cases where vi wasn't consistent.
-
-4.1: The edit/ex commands:
-
- The edit/ex commands are a special case because | symbols may
- occur in the "+cmd" field, for example:
-
- :edit +10|s/abc/ABC/ file.c
-
- In addition, the edit and ex commands have historically
- ignored literal next characters in the +cmd string, so that
- the following command won't work.
-
- :edit +10|s/X/^V / file.c
-
- I intend to handle the literal next character in edit/ex consistently
- with how it is handled in other commands.
-
- More fun facts to know and tell:
- The acid test for the ex/edit commands:
-
- date > file1; date > file2
- vi
- :edit +1|s/./XXX/|w file1| e file2|1 | s/./XXX/|wq
-
- No version of vi, of which I'm aware, handles it.
-
-4.2: The set command:
-
- The set command treats ^V's as literal characters, so the
- following command won't work. Backslashes do work in this
- case, though, so the second version of the command does work.
-
- set tags=tags_file1^V tags_file2
- set tags=tags_file1\ tags_file2
-
- I intend to continue permitting backslashes in set commands,
- but to also permit literal next characters to work as well.
- This is backward compatible, but will also make set
- consistent with the other commands. I think it's unlikely
- to break any historic .exrc's, given that there are probably
- very few files with ^V's in their name.
-
-4.3: The tag command:
-
- The tag command ignores ^V's and backslashes; there's no way to
- get a space into a tag name.
-
- I think this is a don't care, and I don't intend to fix it.
-
-5: Regular expressions:
-
- :global /pattern/ command
- :substitute /pattern/replace/
- :vglobal /pattern/ command
-
- I intend to treat a backslash in the pattern, followed by the
- delimiter character or a backslash, as that literal character.
-
- This is historic behavior in vi. It would get rid of a fairly
- hard-to-explain special case if we could just use the character
- immediately following the backslash in all cases, or, if we
- changed nvi to permit using the literal next character as a
- pattern escape character, but that would probably break historic
- scripts.
-
- There is an additional escaping issue for regular expressions.
- Within the pattern and replacement, the '|' character did not
- delimit ex commands. For example, the following is legal.
-
- :substitute /|/PIPE/|s/P/XXX/
-
- This is a special case that I will support.
-
-6: Ending anything with an escape character:
-
- In all of the above rules, an escape character (either ^V or a
- backslash) at the end of an argument or file name is not handled
- specially, but used as a literal character.
-
diff --git a/contrib/nvi/docs/internals/structures b/contrib/nvi/docs/internals/structures
deleted file mode 100644
index a25c780..0000000
--- a/contrib/nvi/docs/internals/structures
+++ /dev/null
@@ -1,68 +0,0 @@
-# @(#)structures 5.4 (Berkeley) 10/4/95
-
-There are three major data structures in this package, plus a single data
-structure per screen type. The first is a single global structure (GS)
-which contains information common to all files and screens. It hold
-global things like the input key queues, and functions as a single place
-to hang things. For example, interrupt routines have to be able to find
-screen structures, and they can only do this if they have a starting
-point. The number of globals in nvi is dependent on the screen type, but
-every screen type will have at least one global, __global_list, which
-references the GS structure.
-
-The GS structure contains linked lists of screen (SCR) structures.
-Each SCR structure normally references a file (EXF) structure.
-
-The GS structure has a set of functions which update the screen and/or
-return information about the screen from the underlying screen package.
-The GS structure never goes away. The SCR structure persists over
-instances of screens, and the EXF structure persists over references to
-files.
-
-File names have different properties than files themselves, so the name
-information for a file is held in an FREF structure which is chained from
-the SCR structure.
-
-In general, functions are always passed an SCR structure, which usually
-references an underlying EXF structure. The SCR structure is necessary
-for any routine that wishes to talk to the screen, the EXF structure is
-necessary for any routine that wants to modify the file. The relationship
-between an SCR structure and its underlying EXF structure is not fixed,
-and various ex commands will substitute a new EXF in place of the current
-one, and there's no way to detect this.
-
-The naming of the structures is consistent across the program. (Macros
-even depend on it, so don't try and change it!) The global structure is
-"gp", the screen structure is "sp", and the file structure is "ep".
-
-A few other data structures:
-
-TEXT In nvi/cut.h. This structure describes a portion of a line,
- and is used by the input routines and as the "line" part of a
- cut buffer.
-
-CB In nvi/cut.h. A cut buffer. A cut buffer is a place to
- hang a list of TEXT structures.
-
-CL The curses screen private data structure. Everything to
- do standalone curses screens.
-
-MARK In nvi/mark.h. A cursor position, consisting of a line number
- and a column number.
-
-MSG In nvi/msg.h. A chain of messages for the user.
-
-SEQ In nvi/seq.h. An abbreviation or a map entry.
-
-TK The Tcl/Tk screen private data structure. Everything to
- do standalone Tcl/Tk screens.
-
-EXCMD In nvi/ex/ex.h. The structure that gets passed around to the
- functions that implement the ex commands. (The main ex command
- loop (see nvi/ex/ex.c) builds this up and then passes it to the
- ex functions.)
-
-VICMD In nvi/vi/vi.h. The structure that gets passed around to the
- functions that implement the vi commands. (The main vi command
- loop (see nvi/vi/vi.c) builds this up and then passes it to the
- vi functions.)
diff --git a/contrib/nvi/docs/interp/interp b/contrib/nvi/docs/interp/interp
deleted file mode 100644
index 3da5a8f..0000000
--- a/contrib/nvi/docs/interp/interp
+++ /dev/null
@@ -1,190 +0,0 @@
-# @(#)interp 8.5 (Berkeley) 10/19/96
- Nvi Interpreter API
-
-Introduction:
- The intention is to provide a way to graft a fairly generic extension
- language into nvi. I think that the obvious candidates are Tcl/Rush,
- Scheme, Python and Perl. Since the interpretation language chosen
- is often a religious issue, the method should be as flexible as
- possible. I don't expect to rewrite the editor in the interpreted
- language, so that isn't a consideration.
-
- Q: Is there any reason for nvi to support multiple interpreters in
- a single executable?
-
-Interpreter functions in nvi:
-
- 1: Function to get the current screen pointer.
-
- SCR *inter_screen();
-
- Return a pointer to the current screen.
-
- 2: Functions to execute both ex and vi commands. The return value of the
- function will be success/failure. The editor itself will continue to
- handle the display of all messages and text for the foreseeable future.
-
- int inter_vicmd(SCR *, char *cmds, size_t len);
- int inter_excmd(SCR *, char *cmds, size_t len);
-
- The byte string cmds, of length len, is entered into the standard
- vi or ex parser, as if typed by the user. The characters are not
- mapped in any way, i.e. the user's vi mappings don't apply. If
- any error occurs, an error value is returned, and the rest of the
- characters are discarded.
-
- 3: Functions to handle lines of text in the file.
-
- int inter_gline(SCR *, recno_t lno, char **lp, size_t *lenp);
-
- Return a pointer to the text of the line lno, into the location
- referenced by lp, and its length into the location referenced by
- lenp.
-
- int inter_dline(SCR *, recno_t lno);
-
- Delete the line lno from the file.
-
- int inter_aline(SCR *, recno_t lno, char *lp, size_t len);
-
- Append a line consisting of the len bytes of text referenced by
- lp to the line lno.
-
- int inter_iline(SCR *, recno_t lno, char *lp, size_t len);
-
- Insert a line consisting of the len bytes of text referenced by
- lp before the line lno.
-
- int inter_sline(SCR *, recno_t lno, char *lp, size_t len);
-
- Replace line lno with the len bytes of text referenced by lp.
-
- int inter_lline(SCR *, recno_t *lnop);
-
- Return the number of the last line in the file in the location
- referenced by lnop.
-
- 4: Function to post an error message to the user.
-
- int inter_msgq(SCR *, enum msgtype, char *fmt, ...);
-
- Display the message for the user. Valid message types are:
-
- M_BERR Error: M_ERR if verbose, else bell.
- M_ERR Error: Display in inverse video.
- M_INFO Info: Display in normal video.
- M_SYSERR Error: M_ERR, using strerror(3) message.
- M_VINFO Info: M_INFO if verbose, else ignore.
-
- 5: Function to manipulate cut buffers.
-
- int inter_setbuf(SCR *, CHAR_T buffer);
-
- Create the specified buffer if it does not exist (the
- buffer will have no contents).
-
- int inter_getbuf(SCR *, CHAR_T buffer, TEXT **textp);
-
- Return a pointer to the specified buffer in the location
- referenced by textp. (Since a pointer to the real item
- is being returned, it can be manipulated in any way the
- interpreter chooses.)
-
- 6: Functions to manipulate marks.
-
- int inter_setmark(SCR *, CHAR_T name);
-
- Create the specified mark if it does not exist (the
- mark will have no contents).
-
- int inter_getmark(SCR *, CHAR_T name, MARK **markp);
-
- Return a pointer to the specified mark in the location
- referenced by markp. (Since a pointer to the real item
- is being returned, it can be manipulated in any way the
- interpreter chooses.)
-
- 7: Function to manipulate screens.
-
- SCR *inter_iscreen();
-
- Create a new screen, and return a pointer to it.
-
- int inter_escreen(SCR *);
-
- End a screen.
-
- 8: Functions to get input from the user.
-
- int inter_getchar(CHAR_T *chp,
- enum maptype {NONE, INPUT, COMMAND} mapt);
-
- Return a character from the keyboard into the location referenced
- by chp. Mapt can be set to INPUT, COMMAND or NONE, depending on
- what vi mappings should be applied to the character.
-
- int inter_getline(SCR *, char *prompt, CHAR_T **linep,
- size_t *lenp, enum maptype {NONE, INPUT, COMMAND} mapt);
-
- Return a pointer to a line entered by the user, and its length,
- into the locations linep and lenp. A prompt may be specified
- by prompt, and mappings by mapt.
-
- int inter_freeline(CHAR_T *linep);
-
- Free the memory that was allocated by inter_getline();
-
- 9: Function to retrieve and set the cursor.
-
- int inter_getcursor(SCR *, MARK *mark);
-
- Store the current cursor position in mark.
-
- int inter_setcursor(SCR *, MARK *mark);
-
- Set the current cursor position to mark.
-
-10: Function to return a motion command from the user.
-
- int inter_getmotion(SCR *,
- MARK *start, MARK *end, enum movetype {LINE, CHAR} *mt);
-
- Nvi gets a motion command from the user and returns the starting
- and stopping points of the movement, reordered from the beginning
- to the end of the file. The standard rules for line/character
- motions are applied, and returned to the interpreter through the
- mt argument.
-
-11: Functions to return pathnames.
-
-12: Functions to return edit options.
-
-13: Nvi commands which will send text to the interpreter.
-
- Nvi will have a new ex command "inter", which will pipe the rest of
- the line up to the first unescaped <newline> to the interpreter, of
- the following form:
-
- :[address[,address]] inter [count] command
-
- The interface from the ex command to the interpreter is a function:
-
- int inter_ex(
- SCR *, /* Current screen. */
- char *cmd; /* The command. */
- size_t len; /* The command length. */
- MARK *start, /* Starting address for INTER_EX */
- MARK *end, /* Ending address for INTER_EX */
- int count); /* Count. */
-
- Nvi will have a new vi command "*<buffer>" which will pipe the contents
- of the named buffer to the interpreter, of the following form:
-
- [count]*<buffer>
-
- The interface from the vi command to the interpreter is a function:
-
- int inter_vi(
- SCR *, /* Current screen. */
- CHAR_T buffer, /* Buffer. */
- int count); /* Count. */
diff --git a/contrib/nvi/docs/interp/spell.ok b/contrib/nvi/docs/interp/spell.ok
deleted file mode 100644
index 4ca990c..0000000
--- a/contrib/nvi/docs/interp/spell.ok
+++ /dev/null
@@ -1,46 +0,0 @@
-API
-BERR
-Mapt
-Nvi
-Perl
-SCR
-SYSERR
-Tcl
-VINFO
-aline
-callback
-chp
-cmd
-cmds
-dline
-enum
-escreen
-excmd
-freeline
-getbuf
-getcursor
-getline
-getmotion
-gline
-iline
-int
-interp
-iscreen
-lenp
-linep
-lline
-lno
-lnop
-lp
-mapt
-maptype
-movetype
-msgq
-msgtype
-nvi
-recno
-setcursor
-sline
-strerror
-textp
-vicmd
diff --git a/contrib/nvi/docs/USD.doc/vi.man/Makefile b/contrib/nvi/docs/man/Makefile
index 5433864..5433864 100644
--- a/contrib/nvi/docs/USD.doc/vi.man/Makefile
+++ b/contrib/nvi/docs/man/Makefile
diff --git a/contrib/nvi/docs/USD.doc/vi.man/vi.1 b/contrib/nvi/docs/man/vi.1
index 44da037..73ebdbd 100644
--- a/contrib/nvi/docs/USD.doc/vi.man/vi.1
+++ b/contrib/nvi/docs/man/vi.1
@@ -13,7 +13,6 @@
.\" redistribute it, contributions to the authors would be appreciated.
.\"
.\" $Id: vi.1,v 9.0 2013/11/02 12:11:56 zy Exp $
-.\" $FreeBSD$
.\"
.Dd November 2, 2013
.Dt VI 1
@@ -198,7 +197,8 @@ and that is the
.Aq escape
key.
.Pp
-Key names are written using less-than and greater-than signs, e.g.,
+In this manual,
+key names are denoted with \(la and \(ra, e.g.,
.Aq escape
means the
.Dq escape
@@ -239,9 +239,9 @@ Move the cursor up one line.
Move the cursor right one character.
.It Aq Cm cursor-arrows
The cursor arrow keys should work, too.
-.It Cm / Ns text
+.It Cm / Ns Ar text
Search for the string
-.Dq text
+.Dq Ar text
in the file,
and move the cursor to its first character.
.El
@@ -347,10 +347,10 @@ version of regular expressions:
.It
An empty regular expression is equivalent to the last regular expression used.
.It
-.Sq \e\(la
+.Sq \e<
matches the beginning of the word.
.It
-.Sq \e\(ra
+.Sq \e>
matches the end of the word.
.It
.Sq \(a~
@@ -364,7 +364,7 @@ for later use.
.Nm vi
buffers are named with a single character preceded by a double quote,
for example
-.Pf \&" Ns Aq c ;
+.Cm \&" Ns Aq Ar c ;
.Nm ex
buffers are the same,
but without the double quote.
@@ -414,7 +414,7 @@ make the destination buffer character-oriented.
.Cm j ,
.Aq Cm control-M ,
.Cm k ,
-.Cm ' ,
+.Cm \(aq ,
.Cm - ,
.Cm G ,
.Cm H ,
@@ -427,7 +427,7 @@ make the destination buffer line-oriented.
.It
.Cm $ ,
.Cm % ,
-.Cm ` ,
+.Cm \` ,
.Cm (\& ,
.Cm )\& ,
.Cm / ,
@@ -477,7 +477,7 @@ It is specified using a line-oriented motion.
.It
It is specified using one of the following motion commands:
.Aq Cm control-A ,
-.Cm ` Ns Aq Cm character ,
+.Cm \` Ns Aq Ar character ,
.Cm n ,
.Cm N ,
.Cm % ,
@@ -804,7 +804,7 @@ If
.Ar count
is specified, additionally move the cursor down
.Ar count
-\- 1 lines.
+\(mi 1 lines.
.Pp
.It Cm %
Move to the
@@ -816,26 +816,26 @@ the one found at the cursor position or the closest to the right of it.
Repeat the previous substitution command on the current line.
.Pp
.It Xo
-.Cm ' Ns Aq Ar character
+.Cm \(aq Ns Aq Ar character
.Xc
.It Xo
-.Cm ` Ns Aq Ar character
+.Cm \` Ns Aq Ar character
.Xc
Return to the cursor position marked by the character
.Ar character ,
or, if
.Ar character
is
-.Sq '
+.Sq \(aq
or
-.Sq ` ,
+.Sq \` ,
to the position of the cursor before the last of the following commands:
.Aq Cm control-A ,
.Aq Cm control-T ,
.Aq Cm control-] ,
.Cm % ,
-.Cm ' ,
-.Cm ` ,
+.Cm \(aq ,
+.Cm \` ,
.Cm (\& ,
.Cm )\& ,
.Cm / ,
@@ -1028,7 +1028,7 @@ If a
.Ar count
argument is given, the characters input are repeated
.Ar count
-\- 1 times after input mode is exited.
+\(mi 1 times after input mode is exited.
.Pp
.It Xo
.Op Ar count
@@ -1095,7 +1095,7 @@ is not specified.
.Xc
Move to the screen line
.Ar count
-\- 1 lines below the top of the screen.
+\(mi 1 lines below the top of the screen.
.Pp
.It Xo
.Op Ar count
@@ -1107,7 +1107,7 @@ If a
argument is given,
the characters input are repeated
.Ar count
-\- 1 more times.
+\(mi 1 more times.
.Pp
.It Xo
.Op Ar count
@@ -1126,7 +1126,7 @@ It is set to one whitespace character otherwise.
.Xc
Move to the screen line
.Ar count
-\- 1 lines above the bottom of the screen.
+\(mi 1 lines above the bottom of the screen.
.Pp
.It Cm M
Move to the screen line in the middle of the screen.
@@ -1141,7 +1141,7 @@ If a
argument is given,
the characters input are repeated
.Ar count
-\- 1 more times.
+\(mi 1 more times.
.Pp
.It Xo
.Op Ar buffer
@@ -1171,7 +1171,7 @@ If a
argument is given,
the characters input are repeated
.Ar count
-\- 1 more times upon exit from insert mode.
+\(mi 1 more times upon exit from insert mode.
.Pp
.It Xo
.Op Ar buffer
@@ -1268,7 +1268,7 @@ Move to the first non-blank character on the current line.
.Xc
Move down
.Ar count
-\- 1 lines, to the first non-blank character.
+\(mi 1 lines, to the first non-blank character.
.Pp
.It Xo
.Op Ar count
@@ -1372,7 +1372,7 @@ If a
argument is given,
the characters input are repeated
.Ar count
-\- 1 more times.
+\(mi 1 more times.
.Pp
.It Xo
.Op Ar buffer
@@ -2051,10 +2051,11 @@ If this is the entire
pattern, the replacement part of the previous
.Cm substitute
command.
-.It Sq \e\(sh
+.It Sq \e Ns Ar \(sh
Where
-.Sq \(sh
-is an integer from 1 to 9, the text matched by the #'th subexpression in
+.Sq Ar \(sh
+is an integer from 1 to 9, the text matched by the
+.Ar # Ns 'th subexpression in
.Ar pattern .
.It Sq \eL
Causes the characters up to the end of the line of the next occurrence of
@@ -2265,7 +2266,7 @@ session.
Back up files before they are overwritten.
.It Cm beautify , bf Bq off
Discard control characters.
-.It Cm cdpath Bq "environment variable CDPATH, or current directory"
+.It Cm cdpath Bo environment variable Ev CDPATH , or current directory Bc
The directory paths used as path prefixes for the
.Cm cd
command.
@@ -2277,7 +2278,7 @@ Set the number of columns in the screen.
.Nm vi
only.
Skip leading comments in shell, C and C++ language files.
-.It Cm directory , dir Bq "environment variable TMPDIR, or /tmp"
+.It Cm directory , dir Bo environment variable Ev TMPDIR , or Pa /tmp Bc
The directory where temporary files are created.
.It Cm edcompatible , ed Bq off
Remember the values of the
@@ -2446,9 +2447,9 @@ and
commands.
.It Cm secure Bq off
Turns off all access to external programs.
-.It Cm shell , sh Bq "environment variable SHELL, or /bin/sh"
+.It Cm shell , sh Bo environment variable Ev SHELL , or Pa /bin/sh Bc
Select the shell used by the editor.
-.It Cm shellmeta Bq ~{[*?$`'\&"\e
+.It Cm shellmeta Bq ~{[*?$\`\(aq\&"\e
Set the meta characters checked to determine if file name expansion
is necessary.
.It Cm shiftwidth , sw Bq 8
@@ -2481,7 +2482,7 @@ Set the number of significant characters in tag names.
Set the list of tags files.
.It Xo
.Cm term , ttytype , tty
-.Bq "environment variable TERM"
+.Bq environment variable Ev TERM
.Xc
Set the terminal type.
.It Cm terse Bq off
@@ -2522,7 +2523,7 @@ if the file has been modified since it was last written, before a
command.
.It Xo
.Cm window , w , wi
-.Bq "environment variable LINES \- 1"
+.Bq environment variable Ev LINES No \(mi 1
.Xc
Set the window size for the screen.
.It Cm windowname Bq off
diff --git a/contrib/nvi/docs/spell.ok b/contrib/nvi/docs/spell.ok
deleted file mode 100644
index ec854ff..0000000
--- a/contrib/nvi/docs/spell.ok
+++ /dev/null
@@ -1,173 +0,0 @@
-API's
-Amiga
-Amir
-Bostic
-CFLAGS
-CR
-CTYPE
-Cscope
-Ctags
-DB
-DPURIFY
-Darren
-Ds
-Dw
-EXINIT
-Englar
-FreeBSD
-GDB
-Hiebert
-Kirkendall
-LC
-LN
-Linux
-Lite
-MSDOS
-Makefile
-Mayoff
-NEXINIT
-NVI
-NetBSD
-Neville
-Nvi
-Nvi's
-OS
-POSIX
-POSIX.2
-Perl
-PostScript
-README
-Roff
-Solaris
-SunOS
-Sven
-Tcl
-Tk
-Todo
-USD
-USD.doc
-USD:14
-USD:15
-USD:16
-UUNET
-UX
-Verdoolaege
-Vi
-Vi's
-WindowsNT
-ags
-al
-american
-api
-autowrite
-berkeley
-bitstring
-bitstring.h
-bostic
-bsd
-bugs.current
-ccil
-changelog
-cl
-clib
-cont
-cs
-cs.berkeley.edu
-cscope
-csh
-cshrc
-ctags
-darren
-db
-dbopen
-devel
-doc
-docs
-edu
-elvis
-email
-enum
-escapetime
-esr
-execl
-exrc
-exref
-fcntl
-filesystem
-free's
-ftp.cs.berkeley.edu
-gdb
-gdb.script
-gvr
-gz
-gzip'd
-hardtabs
-hiwaay
-html
-http
-ic
-iclower
-ignorecase
-il
-init
-init.tcl
-iso
-isprint
-kB
-keystrokes
-ksh
-lang
-ld
-lt
-lu
-mmap
-ncurses
-nex
-nexrc
-nul's
-nvi
-nvi's
-nvi.ALPHA.tar.gz
-nvi.tar.Z
-nvi.tar.gz
-openmode
-org
-perl
-preformatted
-ps
-queue.h
-readonly
-recover.script
-redistributable
-regex
-remapped
-setenv
-settable
-shiftwidth
-sirsi
-slowopen
-sourced
-struct
-sunsite
-svi
-tcl
-tclapi
-terminfo
-tk
-tknvi
-txt
-ucb
-unc
-uunet
-version's
-vi
-vi's
-vi.man
-vi.ref
-vi.ref.ps
-vi.ref.txt
-vitut
-writeable
-www
-xaw
-ynq
diff --git a/contrib/nvi/docs/tutorial/vi.advanced b/contrib/nvi/docs/tutorial/vi.advanced
deleted file mode 100644
index f757ad1..0000000
--- a/contrib/nvi/docs/tutorial/vi.advanced
+++ /dev/null
@@ -1,1458 +0,0 @@
-Section 26: Index to the rest of the tutorial
-
-The remainder of the tutorial can be perused at your leisure. Simply find the
-topic of interest in the following list, and {/Section xx:/^M} to get to the
-appropriate section. (Remember that ^M means the return key)
-
-The material in the following sections is not necessarily in a bottom up
-order. It should be fairly obvious that if a section mentions something with
-which you are not familiar, say, buffers, you might {/buffer/^M} followed by
-several {n} to do a keyword search of the file for more details on that item.
-Another point to remember is that commands are surrounded by curly-braces and
-can therefore be found rather easily. To see where, say, the X command is
-used try {/{X}/^M}. Subsequent {n} will show you other places the command was
-used. We have tried to maintain the convention of placing the command letter
-surrounded by curly-braces on the section line where that command is
-mentioned.
-
-Finally, you should have enough 'savvy' at this point to be able to do your
-own experimentation with commands without too much hand-holding on the part of
-the tutorial. Experimentation is the best way to learn the effects of the
-commands.
-
- Section Topic - description
- ------- -------------------
-(Sections 1 through 25 are located in the file vi.beginner.)
- 1 introduction: {^F} {ZZ}
- 2 introduction (con't) and positioning: {^F} {^B}
- 3 introduction (con't) and positioning: {^F} {^B}
- 4 positioning: {^F} {^B} ^M (return key)
- 5 quitting: {:q!} ^M key
- 6 marking, cursor and screen positioning: {m} {G} {'} {z}
- 7 marking, cursor and screen positioning: {m} {G} {'} {z}
- 8 marking, cursor and screen positioning: {z} {m} {'}
- 9 marking and positioning: {m} {''}
- 10 line positioning: {^M} {-}
- 11 scrolling with {^M}
- 12 scrolling with {-} and screen adjustment {z}
- 13 notes on use of tutorial
- 14 other scrolling and postioning commands: {^E} {^Y} {^D} {^U}
- 15 searching: {/ .. /^M}
- 16 searching: {? .. ?^M} {n} (in search strings ^ $)
- 17 searching: \ and magic-characters in search strings
- 18 colon commands, exiting: {:} {ZZ}
- 19 screen positioning: {H} {M} {L}
- 20 character positioning: {w} {b} {0} {W} {B} {e} {E} {'} {`}
- 21 cursor positioning: {l} {k} {j} {h}
- 22 adding text: {i} {a} {I} {A} {o} {O} ^[ (escape key)
- 23 character manipulation: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J}
- 24 undo: {u} {U}
- 25 review
-(The following sections are in this file.)
- 26 Index to the rest of the tutorial ******** YOU ARE HERE *******
- 27 discussion of repeat counts and the repeat command: {.}
- 28 more on low-level character motions: {t} {T} {|}
- 29 advanced correction operators: {d} {c}
- 30 updating the screen: {^R}
- 31 text buffers: {"}
- 32 rearranging and duplicating text: {p} {P} {y} {Y}
- 33 recovering lost lines
- 34 advanced file manipulation with vi
- 34.1 more than one file at a time: {:n}
- 34.2 reading files and command output: {:r}
- 34.3 invoking vi from within vi: {:e} {:vi}
- 34.4 escaping to a shell: {:sh} {:!}
- 34.5 writing parts of a file: {:w}
- 34.6 filtering portions of text: {!}
- 35 advanced searching: magic patterns
- 36 advanced substitution: {:s}
- 37 advanced line addressing: {:p} {:g} {:v}
- 38 higher level text objects and nroff: ( ) { } [[ ]]
- 39 more about inserting text
- 40 more on operators: {d} {c} {<} {>} {!} {=} {y}
- 41 abbreviations: {:ab}
- 42 vi's relationship with the ex editor: {:}
- 43 vi on hardcopy terminals and dumb terminals: open mode
- 44 options: {:set} {setenv EXINIT}
- 44.1 autoindent
- 44.2 autoprint
- 44.3 autowrite
- 44.4 beautify
- 44.5 directory
- 44.6 edcompatible
- 44.7 errorbells
- 44.8 hardtabs
- 44.9 ignorecase
- 44.10 lisp
- 44.11 list
- 44.12 magic
- 44.13 mesg
- 44.14 number
- 44.15 open
- 44.16 optimize
- 44.17 paragraphs
- 44.18 prompt
- 44.19 readonly
- 44.20 redraw
- 44.21 remap
- 44.22 report
- 44.23 scroll
- 44.24 sections
- 44.25 shell
- 44.26 shiftwidth
- 44.27 showmatch
- 44.28 slowopen
- 44.29 tabstop
- 44.30 tags
- 44.31 taglength
- 44.32 term
- 44.33 terse
- 44.34 timeout
- 44.35 ttytype
- 44.36 warn
- 44.37 window
- 44.38 wrapscan
- 44.39 wrapmargin
- 44.40 writeany
- 44.41 w300, w1200, w9600
-
-Section 27: repetition counts and the repeat command {.}
-
-Most vi commands will use a preceding count to affect their behavior in some
-way. We have already seen how {3x} deletes three characters, and {22G} moves
-us to line 22 of the file. For almost all of the commands, one can survive by
-thinking of these leading numbers as a 'repeat count' specifying that the
-command is to be repeated so many number of times.
-
-Other commands use the repeat count slightly differently, like the {G} command
-which use it as a line number.
-
-For example:
-
-{3^D} means scroll down in the file three lines. Subsequent {^D} OR {^U} will
-scroll only three lines in their respective directions!
-
-{3z^M} says put line three of the file at the top of the screen, while {3z.}
-says put line three as close to the middle of the screen as possible.
-
-{50|} moves the cursor to column fifty in the current line.
-
-{3^F} says move forward 3 screenfulls. This is a repetition count. The
-documents advertise that {3^B} should move BACK three screenfulls, but I
-can't get it to work.
-
-Position the cursor on some text and try {3r.}. This replaces three characters
-with '...'. However, {3s.....^[} is the same as {3xi.....^[}.
-
-Try {10a+----^[}.
-
-A very useful instance of a repetition count is one given to the '.' command,
-which repeats the last 'change' command. If you {dw} and then {3.}, you will
-delete first one and then three words. You can then delete two more words with
-{2.}. If you {3dw}, you will delete three words. A subsequent {.} will delete
-three more words. But a subsequent {2.} will delete only two words, not three
-times two words.
-
-Caveat: The author has noticed that any repetition count with {^B} will NOT
-work: indeed, if you are at the end of your file and try {3^B} sufficiently
-often, the editor will hang you in an infinite loop. Please don't try it:
-take my word for it.
-
-Section 28: {t} {T} {|}
-
-Position the cursor on line 13 below:
-
-Line 13: Four score and seven years ago, our forefathers brought ...
-
-Note that {fv} moves the cursor on/over the 'v' in 'seven'. Do a {0} to return
-to the beginning of the line and try a {tv}. The cursor is now on/over the
-first 'e' in 'seven'. The {f} command finds the next occurrence of the
-specified letter and moves the cursor to it. The {t} command finds the
-specified letter and moves the cursor to the character immediately preceding
-it. {T} searches backwards, as does {F}.
-
-Now try {60|}: the cursor is now on the 'o' in 'brought', which is the
-sixtieth character on the line.
-
-Section 29: {d} {c}
-
-Due to their complexity we have delayed discussion of two of the most powerful
-operators in vi until now. Effective use of these operators requires more
-explanation than was deemed appropriate for the first half of the tutorial.
-
-{d} and {c} are called operators instead of commands because they consist of
-three parts: a count specification or a buffer specification (see section
-#BUFFERS), the {d} or {c}, and the object or range description. We will not
-discuss buffers at this stage, but will limit ourselves to count
-specifications. Examples speak louder than words: position the cursor at the
-beginning of line 14:
-
-Line 14: Euclid alone has looked on beauty bear.
-
-Obviously, there is something wrong with this quotation. Type {2fb} to
-position the cursor on the 'b' of 'bear'. Now, type {cwbare^[}
-and observe the results. The {cw} specifies that the change command {c} is to
-operate on a word object. More accurately, it specifies that the range of the
-change command includes the next word.
-
-Position the cursor on the period in Line 14. (one way is to use {f.})
-Now, type {cbbeast^[}. This specifies the range of the change command to be the
-previous word (the 'b' reminiscent of the {b} command). If we had wished to
-delete the word rather than change it, we would have used the {d} operator,
-rather than the {c} operator.
-
-Position the cursor at the beginning of the line with {0}. Type
-{d/look/^M}. The search string specified the range of the delete.
-Everything UP TO the word 'looking' was deleted from the line.
-
-In general, almost any command that would move the cursor will specify a range
-for these commands. The most confusing exception to this rule is when {dd} or
-{cc} is entered: they refer to the whole line. Following is a summary of the
-suffixes (suffices? suffici?) and the ranges they specify:
-
- suffix will delete{d}/change{c}
- ------ ------------------------
- ^[ cancels the command
- w the word to the right of the cursor
- W ditto, but ignoring punctuation
- b the word to the left of the cursor
- B ditto, but ignoring punctuation
- e see below.
- E ditto
- (space) a character
- $ to the end of the line
- ^ to the beginning of the line
- / .. / up to, but not including, the string
- ? .. ? back to and including the string
- fc up to and including the occurrence of c
- Fc back to and including the occurrence of c
- tc up to but not including the occurrence of c
- Tc back to but not including the occurrence of c
- ^M TWO lines (that's right: two)
- (number)^M that many lines plus one
- (number)G up to and including line (number)
- ( the previous sentence if you are at the beginning of
- the current sentence, or the current sentence up to where
- you are if you are not at the beginning of the current
- sentence. Here, 'sentence' refers to the intuitive
- notion of an English sentence, ending with '!', '?',
- or '.' and followed by an end of line or two spaces.
- ) the rest of the current sentence
- { analogous to '(', but in reference to paragraphs:
- sections of text surrounded by blank lines
- } analogous to ')', but in reference to paragraphs
- [[ analogous to '(', but in reference to sections
- ]] analogous to ')', but in reference to sections
- H the first line on the screen
- M the middle line on the screen
- L the last line on the screen
- 3L through the third line from the bottom of the screen
- ^F forward a screenful
- ^B backward a screenful
- :
- : etc. etc. etc.
-
-This list is not exhaustive, but it should be sufficient to get the idea
-across: after the {c} or {d} operator, you can specify a range with another
-move-the-cursor command, and that is the region of text over which the command
-will be effective.
-
-Section 30: updating the screen {^R}
-
-Vi tries to be very intelligent about the type of terminal you are working on
-and tries to use the in-terminal computing power (if any) of your terminal.
-Also if the terminal is running at a low baud rate (say 1200 or below), vi sets
-various parameters to make things easier for you. For example, if you were
-running on a 300 baud terminal (that's 30 characters per second transmission
-rate) not all 24 lines of the screen would be used by vi. In addition, there
-is a large portion of the editor keeping track of what your screen currently
-looks like, and what it would look like after a command has been executed. Vi
-then compares the two, and updates only those portions of the screen that have
-changed.
-
-Furthermore, some of you may have noticed (it depends on your terminal) that
-deleting lines or changing large portions of text may leave some lines on the
-screen looking like:
-@
-meaning that this line of the screen does not correspond to any line in your
-file. It would cost more to update the line than to leave it blank for the
-moment. If you would like to see your screen fully up-to-date with the
-contents of your file, type {^R}.
-
-To see it in action, delete several lines with {5dd}, type {^R}, and then type
-{u} to get the lines back.
-
-Here is as good a place as any to mention that if the editor is displaying the
-end of your file, there may be lines on the screen that look like:
-~
-indicating that that screen line would not be affected by {^R}. These lines
-simply indicate the end of the file.
-
-Section 31: text buffers {"}
-
-Vi gives you the ability to store text away in "buffers". This feature is very
-convenient for moving text around in your file. There are a total of thirty-
-five buffers available in vi. There is the "unnamed" buffer that is used by all
-commands that delete text, including the change operator {c}, the substitute
-and replace commands {s} and {r}, as well as the delete operator {d} and delete
-commands {x} and {X}. This buffer is filled each time any of these commands
-are used. However, the undo command {u} has no effect on the unnamed buffer.
-
-There are twenty-six buffers named 'a' through 'z' which are available for the
-user. If the name of the buffer is capitalized, then the buffer is not
-overwritten but appended to. For example, the command {"qdd} will delete one
-line and store that line in the 'q' buffer, destroying the previous contents of
-the buffer. However, {"Qdd} will delete one line of text and append that line
-to the current contents of the 'q' buffer.
-
-Finally, there are nine buffers named '1' through '9' in which the last nine
-deletes are stored. Buffer 1 is the default buffer for the modify commands and
-is sometimes called the unnamed buffer.
-
-To reference a specific buffer, use the double-quote command {"} followed by
-the name of the buffer. The next two sections show how buffers can be used to
-advantage.
-
-Section 32: rearranging and duplicating text: {y} {Y} {p} {P}
-
-Position yourself on line 15 below and {z^M}:
-
-Line 15: A tree as lovely as a poem ...
-Line 16: I think that I shall never see
-
-Type {dd}. Line 15 has disappeared and been replaced with the empty line (one
-with the single character @ on it) or (again depending on your terminal) Line
-16 has moved up and taken its place. We could recover Line 15 with an undo
-{u} but that would simply return it to its original location. Obviously, the
-two lines are reversed, so we want to put line 15 AFTER line 16. This is
-simply done with the put command {p}, which you should type now. What has
-happened is that {dd} put Line 15 into the unnamed buffer, and the {p} command
-retrieved the line from the unnamed buffer.
-
-Now type {u} and observe that Line 15 disappears again (the put was undone
-without affecting the unnamed buffer). Type {P} and see that the capital {P}
-puts the line BEFORE the cursor.
-
-To get Line 15 where it belongs again type {dd}{p}.
-
-Also in Line 15 note that the words 'tree' and 'poem' are reversed. Using the
-unnamed buffer again: {ft}{dw}{ma}{fp}{P}{w}{dw}{`aP} will set things aright
-(note the use of the reverse quote).
-
-The put commands {p} and {P} do not affect the contents of the buffer.
-Therefore, multiple {p} or {P} will put multiple copies of the unnamed buffer
-into your file.
-
-Experiment with {d} and {p} on words, paragraphs, etc. Whatever {d}
-deletes, {p} can put.
-
-Position the cursor on Line 17 and {z^M}:
-
-Line 17: interest apple cat elephant boy dog girl hay farmer
-
-Our task is to alphabetize the words on line 17. With the named buffers (and a
-contrived example) it is quite easy:
-
-{"idw}{"adw}{"cdw}{"edw}{"bdw}{"ddw}{"gdw}{"hdw}{"fdw}
-
-stores each of the words in the named buffer corresponding to the first letter
-of each of the words ('interest' goes in buffer "i, 'apple' goes in buffer "a,
-etc.). Now to put the words in order type:
-
-{"ap$}{"bp$}{"cp$}{"dp$}{"ep$}{"fp$}{"gp$}{"hp$}{"ip$}
-
-Notice that, because 'farmer' was at the end of the line, {dw} did not include
-a space after it, and that, therefore, there is no space between 'farmer' and
-'girl'. This is corrected with {Fg}{i ^[}.
-
-This example could have been done just as easily with lines as with
-words.
-
-You do not have to delete the text in order to put it into a buffer. If all
-you wish to do is to copy the text somewhere else, don't use {d}, rather use
-the yank commands {y} or {Y}. {y} is like {d} and {c} - an operator rather
-than a command. It, too, takes a buffer specification and a range
-specification. Therefore, instead of {dw}{P} to load the unnamed buffer with a
-word without deleting the word, use {yw} (yank a word).
-
-{Y} is designed yank lines, and not arbitrary ranges. That is, {Y} is
-equivalent to {yy} (remember that operators doubled means the current line),
-and {3Y} is equivalent to {3yy}.
-
-If the text you yank or modify forms a part of a line, or is an object such as
-a sentence which partially spans more than one line, then when you put the text
-back, it will be placed after the cursor (or before if you use {P}). If the
-yanked text forms whole lines, they will be put back as whole lines, without
-changing the current line. In this case, the put acts much like the {o} or {O}
-command.
-
-The named buffers "a through "z are not affected by changing edit files.
-However, the unnamed buffer is lost when you change files, so to move text from
-one file to another you should use a named buffer.
-
-Section 33: recovering lost lines
-
-Vi also keeps track of the last nine deletes, whether you ask for it or not.
-This is very convenient if you would like to recover some text that was
-accidentally deleted or modified. Position the cursor on line 18 following,
-and {z^M}.
-
-
-Line 18: line 1
-Line 19: line 2
-Line 20: line 3
-Line 21: line 4
-Line 22: line 5
-Line 23: line 6
-Line 24: line 7
-Line 25: line 8
-Line 26: line 9
-Type {dd} nine times: now don't cheat with {9dd}! That is totally different.
-
-The command {"1p} will retrieve the last delete. Furthermore, when the
-numbered buffers are used, the repeat-command command {.} will increment the
-buffer numbers before executing, so that subsequent {.} will recover all nine
-of the deleted lines, albeit in reverse order. If you would like to review the
-last nine deletes without affecting the buffers or your file, do an undo {u}
-after each put {p} and {.}:
-
-{"1p}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}{u}{.}
-
-will show you all the buffers and leave them and your file intact.
-
-If you had cheated above and deleted the nine lines with {9dd}, all nine lines
-would have been stored in both the unnamed buffer and in buffer number 1.
-(Obviously, buffer number 1 IS the unnamed buffer and is just the default
-buffer for the modify commands.)
-
-Section 34: advanced file manipulation: {:r} {:e} {:n} {:w} {!} {:!}
-
-We've already looked at writing out the file you are editing with the
-{:w} command. Now let's look at some other vi commands to make editing
-more efficient.
-
-Section 34.1: more than one file at a time {:n} {:args}
-
-Many times you will want to edit more than one file in an editing session.
-Instead of entering vi and editing the first file, exiting, entering vi and
-editing the second, etc., vi will allow you to specify ALL files that you wish
-to edit on the invocation line. Therefore, if you wanted to edit file1 and
-file2:
-
-% vi file1 file2
-
-will set up file1 for editing. When you are done editing file one, write it
-out {:w^M} and then type {:n^M} to get the next file on the list. On large
-programming projects with many source files, it is often convenient just to
-specify all source files with, say:
-
-% vi *.c
-
-If {:n^M} brings in a file that does not need any editing, another {:n^M}
-will bring in the next file.
-
-If you have made changes to the first file, but decide to discard these changes
-and proceed to the next file, {:n!^M} forces the editor to discard the current
-contents of the editor.
-
-You can specify a new list of files after {:n}; e.g., {:n f1 f2 f3^M}. This
-will replace the current list of files (if any).
-
-You can see the current list of files being edited with {:args^M}.
-
-Section 34.2: reading files and command output: {:r}
-
-Typing {:r fname^M} will read the contents of file fname into the editor and
-put the contents AFTER the cursor line.
-
-Typing {:r !cmd^M} will read the output of the command cmd and place that
-output after the cursor line.
-
-Section 34.3: invoking vi from within vi: {:e} {:vi}
-
-To edit another file not mentioned on the invocation line, type {:e filename^M}
-or {:vi filename^M}. If you wish to discard the changes to the current file,
-use the exclamation point after the command, e.g. {:e! filename^M}.
-
-Section 34.4: escaping to a shell: {:sh} {:!} {^Z}
-
-Occasionally, it is useful to interrupt the current editing session to perform
-a UNIX task. However, there is no need to write the current file out, exit
-the editor, perform the task, and then reinvoke the editor on the same file.
-One thing to do is to spin off another process. If there are several UNIX
-commands you will need to execute, simply create another shell with {:sh^M}.
-At this point, the editor is put to sleep and will be reawakened when you log
-out of the shell.
-
-If it is a single command that you want to execute, type {:!cmd^M}, where cmd
-is the command that you wish to run. The output of the command will come to
-the terminal as normal, and will not be made part of your file. The message
-"[Hit return to continue]" will be displayed by vi after the command is
-finished. Hitting return will then repaint the screen. Typing another
-{:!cmd^M} at this point is also acceptable.
-
-However, there is a quicker, easier way: type {^Z}. Now this is a little
-tricky, but hang in there. When you logged into UNIX, the first program you
-began communicating with was a program that is called a "shell" (i.e. it 'lays
-over' the operating system protecting you from it, sort of like a considerate
-porcupine). When you got your first prompt on the terminal (probably a '%'
-character) this was the shell telling you to type your first command. When
-you typed {vi filename} for some file, the shell did not go away, it just went
-to sleep. The shell is now the parent of vi. When you type {^Z} the editor
-goes to sleep, the shell wakes up and says "you rang?" in the form of another
-prompt (probably '%'). At this point you are talking to the shell again and
-you can do anything that you could before including edit another file! (The
-only thing you can't do is log out: you will get the message "There are
-stopped jobs.")
-
-When your business with the shell is done, type {fg} for 'foreground' and the
-last process which you ^Z'd out of will be reawakened and the shell will go
-back to sleep. I will refer you to the documentation for the Berkeley shell
-'csh' for more information on this useful capability.
-
-Section 34.5: writing parts of a file: {:w}
-
-The {:w} command will accept a range specifier that will then write only a
-selected range of lines to a file. To write this section to a file, position
-the cursor on the section line (e.g. {/^Section 34.5:/^M}) and {z^M}. Now type
-{^G} to find out the line number (it will be something like "line 513"). Now
-{/^Section 34.6:/-1^M} to find the last line of this section, and {^G} to find
-its line number (it will be something like 542). To write out this section of
-text by itself to a separate file which we will call "sepfile", type
-{:510,542w sepfile^M}. If sepfile already exists, you will have to use the
-exclamation point: {:1147,1168w! sepfile^M} or write to a different, non-
-existent file.
-
-{:!cat sepfile^M} will display the file just written, and it should be the
-contents of this section.
-
-There is an alternate method of determining the line numbers for the write.
-{:set number^M} will repaint the screen with each line numbered. When the file
-is written and the numbers no longer needed, {:set nonumber^M} will remove the
-numbers, and {^R} will adjust the screen.
-
-Or, if you remember your earlier lessons about marking lines of text,
-mark the beginning and ending lines. Suppose we had used {ma} to mark the
-first line of the section and {mb} to mark the last. Then the command
-{:'a,'bw sepfile^M} will write the section into "sepfile". In general,
-you can replace a line number with the 'name' of a marked line (a single-quote
-followed by the letter used to mark the line)
-
-
-Section 34.6: filtering portions of text: {!}
-
-{!} is an operator like {c} and {d}. That is, it consists of a repetition
-count, {!}, and a range specifier. Once the {!} operator is entered in its
-entirety, a prompt will be given at the bottom of the screen for a UNIX
-command. The text specified by the {!} operator is then deleted and
-passed/filtered/piped to the UNIX command you type. The output of the UNIX
-command is then placed in your file. For example, place the cursor at the
-beginning of the following line and {z^M}:
-
-ls -l vi.tutorial
-********* marks the bottom of the output from the ls command **********
-
-Now type {!!csh^M}. The line will be replaced with the output from the ls
-command. The {u} command works on {!}, also.
-
-Here is an extended exercise to display some of these capabilities. When this
-tutorial was prepared, certain auxiliary programs were created to aid in its
-development. Of major concern was the formatting of sections of the tutorial
-to fit on a single screen, particularly the first few sections. What was
-needed was a vi command that would 'format' a paragraph; that is, fill out
-lines with as many words as would fit in eighty columns. There is no such vi
-command. Therefore, another method had to be found.
-
-Of course, nroff was designed to do text formatting. However, it produces a
-'page'; meaning that there may be many blank lines at the end of a formatted
-paragraph from nroff. The awk program was used to strip these blank lines from
-the output from nroff. Below are the two files used for this purpose: I refer
-you to documentation on nroff and awk for a full explanation of their function.
-Position the cursor on the next line and {z^M}.
-
-******** contents of file f **********
-#
-nroff -i form.mac | awk "length != 0 { print }"
-***** contents of file form.mac ******
-.na
-.nh
-.ll 79
-.ec 
-.c2 
-.cc 
-**************************************
-
-Determine the line numbers of the two lines of file f. They should be
-something like 574 and 575, although you better double check: this file is
-under constant revision and the line numbers may change inadvertently. Then
-{:574,575w f^M}. Do the same for the lines of file form.mac. They will be
-approximately 577 and 582. Then {:577,582w form.mac^M}. File f must have
-execute privileges as a shell file: {:!chmod 744 f^M}.
-
-Observe that this paragraph is
-rather ratty in appearance. With our newly created files we can
-clean it up dramatically. Position the cursor at the beginning
-of this paragraph and type the following sequence of
-characters
-(note that we must abandon temporarily our convention
-of curly braces since the command itself contains a curly brace - we
-will use square brackets for the nonce): [!}f^M].
-
-Here is a brief explanation of what has happened. By typing [!}f^M] we
-specified that the paragraph (all text between the cursor and the first blank
-line) will be removed from the edit file and piped to a UNIX program called
-"f". This is a shell command file that we have created. This shell file runs
-nroff, pipes its output to awk to remove blank lines, and the output from awk
-is then read back into our file in the place of the old, ratty paragraph. The
-file form.mac is a list of commands to nroff to get it to produce paragraphs
-to our taste (the right margin is not justified, the line is 79 characters
-long, words are not hyphenated, and three nroff characters are renamed to
-avoid conflict: note that in this file, the {^G} you see there is vi's display
-of the control-G character, and not the two separate characters ^ up-arrow and
-G upper-case g).
-
-This example was created before the existence of the fmt program. I now type
-[!}fmt^M] to get the same effect much faster. Actually, I don't type those
-six keys each time: I have an abbreviation (which see).
-
-Section 35: searching with magic patterns
-
-The documentation available for "magic patterns" (i.e. regular expressions) is
-very scanty. The following should explain this possibly very confusing feature
-of the editor. This section assumes that the magic option is on. To make
-sure, you might want to type {:set magic^M}.
-
-By "magic pattern" we mean a general description of a piece of text that the
-editor attempts to find during a search. Most search patterns consist of
-strings of characters that must be matched exactly, e.g. {/card/^M} searches
-for a specific string of four characters. Let us suppose that you have
-discovered that you consistently have mistyped this simple word as either ccrd
-or czrd (this is not so far-fetched for touch typists). You could {/ccrd/^M}
-and {n} until there are no more of this spelling, followed by {/czrd/^M} and
-{n} until there are no more of these. Or you could {/c.rd/^M} and catch all of
-them on the first pass. Try typing {/c.rd/^M} followed by several {n} and
-observe the effect.
-
-Line 27: card cord curd ceard
-
-When '.' is used in a search string, it has the effect of matching any single
-character.
-
-The character '^' (up-arrow) used at the beginning of a search string means
-the beginning of the line. {/^Line 27/^M} will find the example line above,
-while {/Line 27/^M} will find an occurrence of this string anywhere in the
-line.
-
-Similarly, {/ the$/^M} will find all occurrences of the word 'the' occurring
-at the end of a line. There are several of them in this file.
-
-Note that {:set nomagic^M} will turn off the special meaning of these magic
-characters EXCEPT for '^' and '$' which retain their special meanings at the
-beginning and end of a search string. Within the search string they hold no
-special meaning. Try {/\/ the$\//^M} and note that the dollar-sign is not the
-last character in the search string. Let the dollar-sign be the last
-character in the search string, as in {/\/ the$/^M} and observe the result.
-
-Observe the result of {/back.*file/^M}. This command, followed by sufficient
-{n}, will show you all lines in the file that contain both the words 'back'
-and 'file' on the same line. The '*' magic character specifies that the
-previous regular expression (the '.' in our example) is to be repeatedly
-matched zero or more times. In our example we specified that the words 'back'
-and 'file' must appear on the same line (they may be parts of words such as
-'backwards' or 'workfile') separated by any number (including zero) of
-characters.
-
-We could have specified that 'back' and 'file' are to be words by themselves by
-using the magic sequences '\<' or '\>'. E.g. {/\<back\>.*\<file\>/^M}. The
-sequence '\<' specifies that this point of the search string must match the
-beginning of a word, while '\>' specifies a match at the end of a word. By
-surrounding a string with these characters we have specified that they must be
-words.
-
-To find all words that begin with an 'l' or a 'w', followed by an 'a' or an
-'e', and ending in 'ing', try {/\<[lw][ea][a-z]*ing\>/^M}. This will match
-words like 'learning', 'warning', and 'leading'. The '[..]' notation matches
-exactly ONE character. The character matched will be one of the characters
-enclosed in the square brackets. The characters may be specified individually
-as in [abcd] or a '-' may be used to specify a range of characters as in [a-d].
-That is, [az] will match the letter 'a' OR the letter 'z', while [a-z] will
-match any of the lower case letters from 'a' through 'z'. If you would like to
-match either an 'a', a '-', or a 'z', then the '-' must be escaped: [a\-z] will
-match ONE of the three characters 'a', '-', or 'z'.
-
-If you wish to find all Capitalized words, try {/\<[A-Z][a-z]*\>/^M}. The
-following will find all character sequences that do NOT begin with an
-uncapitalized letter by applying a special meaning to the '^' character in
-square brackets: {/\<[^a-z][a-z]*\>/^M}. When '^' is the first character of a
-square-bracket expression, it specifies "all but these characters". (No
-one claimed vi was consistent.)
-
-To find all variable names (the first character is alphabetic, the remaining
-characters are alphanumeric): try {/\<[A-Za-z][A-Za-z0-9]*\>/^M}.
-
-In summary, here are the primitives for building regular expressions:
-
- ^ at beginning of pattern, matches beginning of line
- $ at end of pattern, matches end of line
- . matches any single character
- \< matches the beginning of a word
- \> matches the end of a word
- [str] matches any single character in str
- [^str] matches any single character NOT in str
- [x-y] matches any character in the ASCII range between x and y
- * matches any number (including zero) of the preceding pattern
-
-Section 36: advanced substitution: {:s}
-
-The straightforward colon-substitute command looks like the substitute
-command of most line-oriented editors. Indeed, vi is nothing more than a
-superstructure on the line-oriented editor ex and the colon commands are
-simply a way of accessing commands within ex (see section #EX). This gives us
-a lot of global file processing not usually found in visual oriented editors.
-
-The colon-substitute command looks like: {:s/ .. / .. /^M} and will find the
-pattern specified after the first slash (this is called the search pattern),
-and replace it with the pattern specified after the second slash (called,
-obviously enough, the replacement pattern). E.g. position the cursor on line
-28 below and {:s/esample/example/^M}:
-
-Line 28: This is an esample.
-
-The {u} and {U} commands work for {:s}. The first pattern (the search pattern)
-may be a regular expression just as for the search command (after all, it IS a
-search, albeit limited to the current line). Do an {u} on the above line, and
-try the following substitute, which will do almost the same thing:
-{:s/s[^ ]/x/^M}.
-Better undo it with {u}. The first pattern {s[^ ]} matches an 's'
-NOT followed by a blank: the search therefore ignores the 's'es in 'This' and
-'is'. However, the character matched by {[^ ]} must appear in the replacement
-pattern. But, in general, we do not know what that character is! (In this
-particular example we obviously do, but more complicated examples will follow.)
-Therefore, vi (really ex) has a duplication mechanism to copy patterns matched
-in the search string into the replacement string. Line 29 below is a copy of
-line 28 above so you can adjust your screen.
-
-Line 29: This is an esample.
-
-In general, you can nest parts of the search pattern in \( .. \) and refer to
-it in the replacement pattern as \n, where n is a digit. The problem outlined
-in the previous paragraph is solved with {:s/s\([^ ]\)/x\1/^M}: try it. Here
-\1 refers to the first pattern grouping \( .. \) in the search string.
-
-Obviously, for a single line, this is rather tedious. Where it becomes
-powerful, if not necessary, is in colon-substitutes that cover a range of
-lines. (See the next section for a particularly comprehensive example.)
-
-If the entire character sequence matched by the search pattern is needed in
-the replacement pattern, then the unescaped character '&' can be used. On
-Line 29 above, try {:s/an e.ample/not &/^M}. If another line is to have the
-word 'not' prepended to a pattern, then '~' can save you from re-typing the
-replacement pattern. E.g. {:s/some pattern/~/^M} after the previous example
-would be equivalent to {:s/some pattern/not &/^M}.
-
-One other useful replacement pattern allows you to change the case of
-individual letters. The sequences {\u} and {\l} cause the immediately
-following character in the replacement to be converted to upper- or lower-case,
-respectively, if this character is a letter. The sequences {\U} and {\L} turn
-such conversion on, either until {\E} or {\e} is encountered, or until the end
-of the replacement pattern.
-
-For example, position the cursor on a line: pick a line, any line. Type
-{:s/.*/\U&/^M} and observe the result. You can undo it with {u}.
-
-The search pattern may actually match more than once on a single line.
-However, only the first pattern is substituted. If you would like ALL
-patterns matched on the line to be substituted, append a 'g' after the
-replacement pattern: {:s/123/456/g^M} will substitute EVERY occurrence
-on the line of 123 with 456.
-
-Section 37: advanced line addressing: {:p} {:g} {:v}
-
-Ex (available through the colon command in vi) offers several methods for
-specifying the lines on which a set of commands will act. For example, if you
-would like to see lines 50 through 100 of your file: {:50,100p^M} will display
-them, wait for you to [Hit return to continue], and leave you on line 100.
-Obviously, it would be easier just to do {100G} from within vi. But
-what if you would like to make changes to just those lines? Then the
-addressing is important and powerful.
-
-Line 30: This is a text.
-Line 31: Here is another text.
-Line 32: One more text line.
-
-The lines above contain a typing error that the author of this tutorial tends
-to make every time he attempts to type the word 'test'. To change all of these
-'text's into 'test's, try the following:
-{:/^Line 30/,/^Line 32/s/text/test/^M}. This finds the beginning and end of
-the portion of text to be changed, and limits the substitution to each of the
-lines in that range. The {u} command applies to ALL of the substitutions as
-a group.
-
-This provides a mechanism for powerful text manipulations.
-And very complicated examples.
-
-Line 33: This test is a.
-Line 34: Here test is another.
-Line 35: One line more test.
-
-The above three lines have the second word out of order. The following command
-string will put things right. Be very careful when typing this: it is very
-long, full of special characters, and easy to mess up. You may want to
-consider reading the following section to understand it before trying the
-experiment. Don't worry about messing up the rest of the file, though: the
-address range is specified.
-
-{:/^Line 33/,/^Line 35/s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/^M}
-
-There are several things to note about this command string. First of all, the
-range of the substitute was limited by the address specification {/^Line
-33/,/^Line 35/^M}. It might have been simpler to do {:set number^M} to see the
-line numbers directly, and then, in place of the two searches, typed
-the line numbers, e.g. {1396,1398}. Or to mark the lines with {ma} and {mb}
-and use {'a,'b}.
-
-Then follows the substitute pattern itself. To make it easier to understand
-what the substitute is doing, the command is duplicated below with the various
-patterns named for easier reference:
-
- s/\([^:]*\): \([^ ]*\) \([^ ]*\) \([^.]*\)/\1: \2 \4 \3/
- |--\1---| |--\2---| |--\3---| |--\4---|
- |--------search pattern------------------|-replacement|
- |--pattern---|
-
-In overview, the substitute looks for a particular pattern made up of
-sub-patterns, which are named \1, \2, \3, and \4. These patterns are specified
-by stating what they are NOT. Pattern \1 is the sequence of characters that
-are NOT colons: in the search string, {[^:]} will match exactly one character
-that is not a colon, while appending the asterisk {[^:]*} specifies that the
-'not a colon' pattern is to be repeated until no longer satisfied, and
-{\([^:]*\)} then gives the pattern its name, in this case \1. Outside of the
-specification of \1 comes {: }, specifying that the next two characters must be
-a colon followed by a blank.
-
-Patterns \2 and \3 are similar, specifying character sequences that are
-not blanks. Pattern \4 matches up to the period at the end of the line.
-
-The replacement pattern then consists of specifying the new order of the
-patterns.
-
-This is a particularly complicated example, perhaps the most complicated
-in this tutorial/reference. For our small examples, it is obviously
-tedious and error prone. For large files, however, it may be the most
-efficient way to make the desired modifications.
-
-(The reader is advised to look at the documentation for awk. This tool is very
-powerful and slightly simpler to use than vi for this kind of file
-manipulation. But, it is another command language to learn.)
-
-Many times, you will not want to operate on every line in a certain
-range. Rather you will want to make changes on lines that satisfy
-certain patterns; e.g. for every line that has the string 'NPS' on it,
-change 'NPS' to 'Naval Postgraduate School'. The {:g} addressing
-command was designed for this purpose. The example of this paragraph
-could be typed as {:g/NPS/s//Naval Postgraduate School/^M}.
-
-The general format of the command is {:g/(pattern)/cmds^M} and it
-works in the following way: all lines that match the pattern
-following the {:g} are 'tagged' in a special way. Then each of these
-lines have the commands following the pattern executed over them.
-
-Line 36: ABC rhino george farmer Dick jester lest
-Line 37: george farmer rhino lest jester ABC
-Line 38: rhino lest george Dick farmer ABC jester
-
-Type:
-
-{:g/^Line.*ABC/s/Dick/Harry Binswanger/|s/george farmer/gentleman george/p^M}
-
-There are several things of note here. First, lines 36, 37, and 38 above are
-tagged by the {:g}. Type {:g/^Line.*ABC/p^M} to verify this. Second, there
-are two substitutes on the same line separated by '|'. In general, any colon
-commands can be strung together with '|'. Third, both substitutes operate on
-all three lines, even though the first stubstitute works on only two of the
-lines (36 and 38). Fourth, the second substitute works on only two lines (36
-and 37) and those are the two lines printed by the trailing 'p'.
-
-The {:v} command works similarly to the {:g} command, except that the sense of
-the test for 'tagging' the lines is reversed: all lines NOT matching the search
-pattern are tagged and operated on by the commands.
-
-Using {^V} to quote carriage return (see section 39) can be used in global
-substitutions to split two lines. For example, the command
-{:g/\. /s//.^V^M/g^M} will change your file so that each sentence is on a
-separate line. (Note that we have to 'escape' the '.', because '.' by itself
-matches any character. Our command says to find any line which contains a
-period followed by 2 spaces, and inserts a carriage return after the period.)
-
-Caveat: In some of the documentation for ex and vi you may find the
-comment to the effect that {\^M} can be used between commands following
-{:g}. The author of this tutorial has never gotten this to work and has
-crashed the editor trying.
-
-Section 38: higher level text objects and nroff: {(} {)} [{] [}] {[[} {]]}
-
-(Note: this section may be a little confusing because of our command
-notation. Using curly braces to surround command strings works fine as
-long as the command string does not contain any curly braces itself.
-However, the curly braces are legitimate commands in vi. Therefore, for
-any command sequence that contains curly braces, we will surround that
-sequence with SQUARE braces, as on the previous Section line.)
-
-In working with a document, particularly if using the text formatting
-programs nroff or troff, it is often advantageous to work in terms of
-sentences, paragraphs, and sections. The operations {(} and {)} move to
-the beginning of the previous and next sentences, respectively. Thus
-the command {d)} will delete the rest of the current sentence; likewise
-{d(} will delete the previous sentence if you are at the beginning of
-the current sentence, or, if you are not at the beginning of a sentence,
-it will delete the current sentence from the beginning
-up to where you are.
-
-A sentence is defined to end at a '.', '!', or '?' which is followed
-by either the end of a line, or by two spaces. Any number of closing
-')', ']', '"', and ''' characters may appear after the '.', '!', or '?'
-before the spaces or end of line. Therefore, the {(} and {)} commands
-would recognize only one sentence in the following line, but two
-sentences on the second following line.
-
-Line 39: This is one sentence. Even though it looks like two.
-Line 40: This is two sentences. Because it has two spaces after the '.'.
-
-The operations [{] and [}] move over paragraphs and the operations {[[}
-and {]]} move over sections.
-
-A paragraph begins after each empty line, and also at each of a set of nroff
-paragraph macros. A section begins after each line with a form-feed ^L in the
-first column, and at each of a set of nroff section macros. When preparing a
-text file as input to nroff, you will probably be using a set of nroff macros
-to make the formatting specifications easier, or more to your taste. These
-macros are invoked by beginning a line with a period followed by the one or two
-letter macro name. Vi has been programmed to recognize these nroff macros, and
-if it doesn't recognize your particular macro you can use the {:set paragraphs}
-or {:set sections} commands so that it will.
-
-Section 39: more about inserting text
-
-There are a number of characters which you can use to make correnctions
-during input mode. These are summarized in the following table.
-
- ^H deletes the last input character
- ^W deletes the last input word
- (erase) same as ^H; each terminal can define its own erase character;
- for some it is ^H, for others it is the DELETE key, and for
- others it is '@'.
- (kill) deletes the input on this line; each terminal can define its
- own line-kill character; for some it is ^U, for others it is
- '@'; you will need to experiment on your terminal to find
- out what your line-kill and erase characters are.
- \ escapes a following ^H, (kill), and (erase) characters: i.e.
- this is how to put these characters in your file.
- ^[ escape key; ends insertion mode
- ^? the delete key; interrupts an insertion, terminating it
- abnormally.
- ^M the return key; starts a new line.
- ^D backtabs over the indentation set by the autoindent option
- 0^D backtabs over all indentation back to the beginning of the line
- ^^D (up-arrow followed by control-d)same as 0^D, except the indentation
- will be restored at the beginning of the next line.
- ^V quotes the next non-printing character into the file
-
-If you wish to type in your erase or kill character (say # or @ or ^U) then you
-must precede it with a \, just as you would do at the normal system command
-level. A more general way of typing non-printing characters into the file is
-to precede them with a ^V. The ^V echoes as a ^ character on which the cursor
-rests. This indicates that the editor expects you to type a control character
-and it will be inserted into the file at that point. There are a few
-exceptions to note. The implementation of the editor does not allow the null
-character ^@ to appear in files. Also the linefeed character ^J is used by the
-editor to separate lines in the file, so it cannot appear in the middle of a
-line. (Trying to insert a ^M into a file, or putting it in the replacement
-part of a substitution string will result in the matched line being split in
-two. This, in effect, is how to split lines by using a substitution.) You can
-insert any other character, however, if you wait for the editor to echo the ^
-before you type the character. In fact, the editor will treat a following
-letter as a request for the corresponding control character. This is the only
-way to type ^S or ^Q, since the system normally uses them to suspend and resume
-output and never gives them to the editor to process.
-
-If you are using the autoindent option you can backtab over the indent which it
-supplies by typing a ^D. This backs up to the boundary specified by the
-shiftwidth option. This only works immediately after the supplied autoindent.
-
-When you are using the autoindent option you may wish to place a label at the
-left margin of a line. The way to do this easily is to type ^ (up-arrow) and
-then ^D. The editor will move the cursor to the left margin for one line, and
-restore the previous indent on the next. You can also type a 0 followed
-immediately by a ^D if you wish to kill all indentation and not have it resume
-on the next line.
-
-Section 40: more on operators: {d} {c} {<} {>} {!} {=} {y}
-
-Below is a non-exhaustive list of commands that can follow the operators
-to affect the range over which the operators will work. However, note
-that the operators {<}, {>}, {!}, and {=} do not operate on any object
-less than a line. Try {!w} and you will get a beep. To get the
-operator to work on just the current line, double it. E.g. {<<}.
-
- suffix will operate on
- ------ ------------------------
- ^[ cancels the command
- w the word to the right of the cursor
- W ditto, but ignoring punctuation
- b the word to the left of the cursor
- B ditto, but ignoring punctuation
- e see below.
- E ditto
- (space) a character
- $ to the end of the line
- ^ to the beginning of the line
- / .. / up to, but not including, the string
- ? .. ? back to and including the string
- fc up to and including the occurrence of c
- Fc back to and including the occurrence of c
- tc up to but not including the occurrence of c
- Tc back to but not including the occurrence of c
- ^M TWO lines (that's right: two)
- (number)^M that many lines plus one
- (number)G up to and including line (number)
- ( the previous sentence if you are at the beginning of
- the current sentence, or the current sentence up to where
- you are if you are not at the beginning of the current
- sentence. Here, 'sentence' refers to the intuitive
- notion of an English sentence, ending with '!', '?',
- or '.' and followed by an end of line or two spaces.
- ) the rest of the current sentence
- { analogous to '(', but in reference to paragraphs:
- sections of text surrounded by blank lines
- } analogous to ')', but in reference to paragraphs
- [[ analogous to '(', but in reference to sections
- ]] analogous to ')', but in reference to sections
- H the first line on the screen
- M the middle line on the screen
- L the last line on the screen
- 3L through the third line from the bottom of the screen
- ^F forward a screenful
- ^B backward a screenful
- :
- : etc. etc. etc.
-
-This list is not exhaustive, but it should be sufficient to get the idea
-across: after the operator, you can specify a range with a move-the-cursor
-command, and that is the region of text over which the operator will be
-effective.
-
-Section 41: abbreviations: {:ab}
-
-When typing large documents you may find yourself typing a large phrase
-over and over. Vi gives you the ability to specify an abbreviation for
-a long string such that typing the abbreviation will automatically
-expand into the longer phrase.
-
-Type {:ab nps Naval Postgraduate School^M}. Now type:
-
-{iThis is to show off the nps's UNIX editor.^M^[}
-
-Section 42: vi's relationship with the ex editor: {:}
-
-Vi is actually one mode of editing within the editor ex. When you are
-running vi you can escape to the line oriented editor of ex by giving
-the command {Q}. All of the colon-commands which were introduced above
-are available in ex. Likewise, most ex commands can be invoked from vi
-using {:}.
-
-In rare instances, an internal error may occur in vi. In this case you
-will get a diagnostic and will be left in the command mode of ex. You can
-then save your work and quit if you wish by giving the command {x} after
-the colon prompt of ex. Or you can reenter vi (if you are brave) by
-giving ex the command {vi}.
-
-Section 43: vi on hardcopy terminals and dumb terminals: open mode
-
-(The author has not checked the following documentation for accuracy. It is
-abstracted from the Introduction to Vi Editing document.)
-
-If you are on a hardcopy terminal or a terminal which does not have a cursor
-which can move off the bottom line, you can still use the command set of vi,
-but in a different mode. When you give the vi command to UNIX, the editor will
-tell you that it is using open mode. This name comes from the open command in
-ex, which is used to get into the same mode.
-
-The only difference between visual mode (normal vi) and open mode is the way in
-which the text is displayed.
-
-In open mode the editor uses a single line window into the file, and moving
-backward and forward in the file causes new lines to be displayed, always below
-the current line. Two commands of vi work differently in open: {z} and {^R}.
-The {z} command does not take parameters, but rather draws a window of context
-around the current line and then returns you to the current line.
-
-If you are on a hardcopy terminal, the {^R} command will retype the current
-line. On such terminals, the editor normally uses two lines to represent the
-current line. The first line is a copy of the line as you started to edit it,
-and you work on the line below this line. When you delete characters, the
-editor types a number of \'s to show you the characters which are deleted. The
-editor also reprints the current line soon after such changes so that you can
-see what the line looks like again.
-
-It is sometimes useful to use this mode on very slow terminals which can
-support vi in the full screen mode. You can do this by entering ex and using
-an {open} command.
-
-*********************************************************************
-Section 44: options: {:set} {setenv EXINIT}
-
-You will discover options as you need them. Do not worry about them very much
-on the first pass through this document. My advice is to glance through them,
-noting the ones that look interesting, ignoring the ones you don't understand,
-and try re-scanning them in a couple of weeks.
-
-If you decide that you have a favorite set of options and would like to change
-the default values for the editor, place a {setenv EXINIT} command in your
-.login file. When you are given an account under UNIX your directory has
-placed in it a file that is executed each time you log in. If one of the
-commands in this file sets the environment variable EXINIT to a string of vi
-commands, you can have many things done for you each time you invoke vi. For
-example, if you decide that you don't like tabstops placed every eight columns
-but prefer every four columns, and that you wish the editor to insert linefeeds
-for you when your typing gets you close to column 72, and you want
-autoindentation, then include the following line in your .login file:
-
-setenv EXINIT='set tabstop=4 wrapmargin=8 autoindent'
-
-or equivalently
-
-setenv EXINIT='se ts=4 wm=8 ai'
-
-Each time you bring up vi, this command will be executed and the options set.
-
-There are forty options in the vi/ex editor that the user can set for his/her
-own convenience. They are described in more detail in individual sections
-below. The section line will show the full spelling of the option name, the
-abbreviation, and the default value of the option. The text itself
-comes from the ex reference manual and is not the epitome of clarity.
-
-Section 44.1: {autoindent}, {ai} default: noai
-
-Can be used to ease the preparation of structured program text. At the
-beginning of each append, change or insert command or when a new line is opened
-or created by an append, change, insert, or substitute operation within open or
-visual mode, ex looks at the line being appended after, the first line changed
-or the line inserted before and calculates the amount of white space at the
-start of the line. It then aligns the cursor at the level of indentation so
-determined.
-
-If the user then types lines of text in, they will continue to be justified at
-the displayed indenting level. If more white space is typed at the beginning
-of a line, the following line will start aligned with the first non-white
-character of the previous line. To back the cursor up to the preceding tab
-stop one can hit {^D}. The tab stops going backwards are defined at multiples
-of the shiftwidth option. You cannot backspace over the indent, except by
-sending an end-of-file with a {^D}. A line with no characters added to it
-turns into a completely blank line (the white space provided for the autoindent
-is discarded). Also specially processed in this mode are lines beginning with
-an up-arrow `^' and immediately followed by a {^D}. This causes the input to
-be repositioned at the beginning of the line, but retaining the previous indent
-for the next line. Similarly, a `0' followed by a {^D} repositions at the
-beginning but without retaining the previous indent. Autoindent doesn't happen
-in global commands or when the input is not a terminal.
-
-Section 44.2: {autoprint}, {ap} default: ap
-
-Causes the current line to be printed after each delete, copy, join, move,
-substitute, t, undo or shift command. This has the same effect as supplying a
-trailing `p' to each such command. Autoprint is suppressed in globals, and
-only applies to the last of many commands on a line.
-
-Section 44.3: {autowrite}, {aw} default: noaw
-
-Causes the contents of the buffer to be written to the current file if you have
-modified it and give a next, rewind, stop, tag, or {!} command, or a control-
-up-arrow {^^} (switch files) or {^]} (tag goto) command in visual. Note, that
-the edit and ex commands do not autowrite. In each case, there is an
-equivalent way of switching when autowrite is set to avoid the autowrite
-({edit} for next, rewind! for rewind, stop! for stop, tag! for tag, shell
-for {!}, and {:e #} and a {:ta!} command from within visual).
-
-Section 44.4: {beautify}, {bf} default: nobeautify
-
-Causes all control characters except tab ^I, newline ^M and form-feed ^L to be
-discarded from the input. A complaint is registered the first time a backspace
-character is discarded. Beautify does not apply to command input.
-
-Section 44.5: {directory}, {dir} default: dir=/tmp
-
-Specifies the directory in which ex places its buffer file. If this directory
-in not writable, then the editor will exit abruptly when it fails to be able to
-create its buffer there.
-
-Section 44.6: {edcompatible} default: noedcompatible
-
-Causes the presence or absence of g and c suffixes on substitute commands to be
-remembered, and to be toggled by repeating the suffices. The suffix r makes
-the substitution be as in the {~} command, instead of like {&}.
-
-[Author's note: this should not concern users of vi.]
-
-Section 44.7: {errorbells}, {eb} default: noeb
-
-Error messages are preceded by a bell. However, bell ringing in open and
-visual modes on errors is not suppressed by setting noeb. If possible the
-editor always places the error message in a standout mode of the terminal (such
-as inverse video) instead of ringing the bell.
-
-Section 44.8: {hardtabs}, {ht} default: ht=8
-
-Gives the boundaries on which terminal hardware tabs are set (or on which the
-system expands tabs).
-
-Section 44.9: {ignorecase}, {ic} default: noic
-
-All upper case characters in the text are mapped to lower case in regular
-expression matching. In addition, all upper case characters in regular
-expressions are mapped to lower case except in character class specifications
-(that is, character in square brackets).
-
-Section 44.10: {lisp} default: nolisp
-
-Autoindent indents appropriately for lisp code, and the {(}, {)}, [{], [}],
-{[[}, and {]]} commands in open and visual modes are modified in a
-striaghtforward, intuitive fashion to have meaning for lisp.
-
-[Author's note: but don't ask me to define them precisely.]
-
-Section 44.11: {list} default: nolist
-
-All printed lines will be displayed (more) unambiguously, showing tabs as ^I
-and end-of-lines with `$'. This is the same as in the ex command {list}.
-
-Section 44.12: {magic} default: magic for {ex} and {vi}, nomagic for edit.
-
-If nomagic is set, the number of regular expression metacharacters is greatly
-reduced, with only up-arrow `^' and `$' having special effects. In addition
-the metacharacters `~' and `&' of the replacement pattern are treated as normal
-characters. All the normal metacharacters may be made magic when nomagic is
-set by preceding them with a `\'.
-
-[Author's note: In other words, if magic is set a back-slant turns the magic
-off for the following character, and if nomagic is set a back-slant turns the
-magic ON for the following character. And, no, we are not playing Dungeons and
-Dragons, although I think the writers of these option notes must have played it
-all the time.]
-
-Section 44.13: {mesg} default: mesg
-
-Causes write permission to be turned off to the terminal while you are in
-visual mode, if nomesg is set.
-
-[Author's note: I don't know if anyone could have made any one sentence
-paragraph more confusing than this one. What it says is: mesg allows people to
-write to you even if you are in visual or open mode; nomesg locks your terminal
-so they can't write to you and mess up your screen.]
-
-Section 44.14: {number, nu} default: nonumber
-
-Causes all output lines to be printed with their line numbers. In addition
-each input line will be prompted with its line number.
-
-Section 44.15: {open} default: open
-
-If {noopen}, the commands open and visual are not permitted. This is set for
-edit to prevent confusion resulting from accidental entry to open or visual
-mode.
-
-[Author's note: As you may have guessed by now, there are actually three
-editors available under Berkeley UNIX that are in reality the same
-program, ex, with different options set: ex itself, vi, and edit.]
-
-Section 44.16: {optimize, opt} default: optimize
-
-Throughput of text is expedited by setting the terminal to not do automatic
-carriage returns when printing more than one (logical) line of output, greatly
-speeding output on terminals without addressable cursors when text with leading
-white space is printed.
-
-[Author's note: I still don't know what this option does.]
-
-Section 44.17: {paragraphs, para} default: para=IPLPPPQPP LIbp
-
-Specifies the paragraphs for the [{] and [}] operations in open and visual.
-The pairs of characters in the option's value are the names of the nroff macros
-which start paragraphs.
-
-Section 44.18: {prompt} default: prompt
-
-Command mode input is prompted for with a `:'.
-
-[Author's note: Doesn't seem to have any effect on vi.]
-
-Section 44.19: {readonly}, {ro} default: noro, unless invoked with -R
- or insufficient privileges on file
-
-This option allows you to guarantee that you won't clobber your file by
-accident. You can set the option and writes will fail unless you use an `!'
-after the write. Commands such as {x}, {ZZ}, the autowrite option, and in
-general anything that writes is affected. This option is turned on if you
-invoke the editor with the -R flag.
-
-Section 44.20: {redraw} default: noredraw
-
-The editor simulates (using great amounts of output), an intelligent terminal
-on a dumb terminal (e.g. during insertions in visual the characters to the
-right of the cursor position are refreshed as each input character is typed).
-Useful only at very high baud rates, and should be used only if the system is
-not heavily loaded: you will notice the performance degradation yourself.
-
-Section 44.21: {remap} default: remap
-
-If on, macros are repeatedly tried until they are unchanged. For example, if o
-is mapped to O, and O is mapped to I, then if remap is set, o will map to I,
-but if noremap is set, it will map to O .
-
-Section 44.22: {report} default: report=5 for ex and vi, 2 for edit
-
-Specifies a threshold for feedback from commands. Any command which modifies
-more than the specified number of lines will provide feedback as to the scope
-of its changes. For commands such as global, open, undo, and visual which have
-potentially more far reaching scope, the net change in the number of lines in
-the buffer is presented at the end of the command, subject to this same
-threshold. Thus notification is suppressed during a global command on the
-individual commands performed.
-
-Section 44.23: {scroll} default: scroll=1/2 window
-
-Determines the number of logical lines scrolled when a {^D} is received from a
-terminal in command mode, and determines the number of lines printed by a
-command mode z command (double the value of scroll).
-
-[Author's note: Doesn't seem to affect {^D} and {z} in visual (vi) mode.]
-
-Section 44.24: sections {sections} default: sections=SHNHH HU
-
-Specifies the section macros from nroff for the {[[} and {]]} operations in
-open and visual. The pairs of characters in the options's value are the names
-of the macros which start paragraphs.
-
-Section 44.25: {shell}, {sh} default: sh=/bin/sh
-
-Gives the path name of the shell forked for the shell escape command `!', and
-by the shell command. The default is taken from SHELL in the environment, if
-present.
-
-[Editor's note: I would suggest that you place the following line in
-your .login file:
-setenv SHELL '/bin/csh'
-]
-
-Section 44.26: {shiftwidth}, {sw} default: sw=8
-
-Used in reverse tabbing with {^D} when using autoindent to append text, and
-used by the shift commands. Should probably be the same value as the tabstop
-option.
-
-Section 44.27: {showmatch}, {sm} default: nosm
-
-In open and visual mode, when a `)' or `}' is typed, if the matching `(' or `{'
-is on the screen, move the cursor to it for one second. Extremely useful with
-complicated nested expressions, or with lisp.
-
-Section 44.28: {slowopen}, {slow} default: terminal dependent
-
-Affects the display algorithm used in visual mode, holding off display updating
-during input of new text to improve throughput when the terminal in use is both
-slow and unintelligent. See "An Introduction to Display Editing with Vi" for
-more details.
-
-Section 44.29: {tabstop}, {ts} default: ts=8
-
-The editor expands tabs ^I to tabstop boundaries in the display.
-
-Section 44.30: {taglength}, {tl} default: tl=0
-
-Tags are not significant beyond this many characters.
-A value of zero (the default) means that all characters are significant.
-
-Section 44.31: {tags} default: tags=tags /usr/lib/tags
-
-A path of files to be used as tag files for the tag command. A requested tag
-is searched for in the specified files, sequentially. By default files called
-tags are searched for in the current directory and in /usr/lib (a master file
-for the entire system).
-
-[Author's note: The author of this tutorial has never used this option, nor
-seen it used. I'm not even sure I know what they are talking about.]
-
-Section 44.32: {term} default: from environment variable TERM
-
-The terminal type of the output device.
-
-Section 44.33: {terse} default: noterse
-
-Shorter error diagnostics are produced for the experienced user.
-
-Section 44.34: {timeout} default: timeout
-
-Causes macros to time out after one second. Turn it off and they will
-wait forever. This is useful if you want multi-character macros, but if
-your terminal sends escape sequences for arrow keys, it will be
-necessary to hit escape twice to get a beep.
-
-[Editor's note: Another paragraph which requires a cryptographer.]
-
-Section 44.35: ttytype
-
-[Editor's note: I have found no documentation for this option at all.]
-
-Section 44.36: {warn} default: warn
-
-Warn if there has been `[No write since last change]' before a `!' command
-escape.
-
-Section 44.37: {window} default: window=speed dependent
-
-The number of lines in a text window in the visual command. The default is 8
-at slow speeds (600 baud or less), 16 at medium speed (1200 baud), and the full
-screen (minus one line) at higher speeds.
-
-Section 44.38: {wrapscan}, {ws} default: ws
-
-Searches using the regular expressions in addressing will wrap around past the
-end of the file.
-
-Section 44.39: {wrapmargin}, {wm} default: wm=0
-
-Defines a margin for automatic wrapover of text during input in open and visual
-modes. The numeric value is the number of columns from the right edge of the
-screen around which vi looks for a convenient place to insert a new-line
-character (wm=0 is OFF). This is very convenient for touch typists.
-Wrapmargin behaves much like fill/nojustify mode does in nroff.
-
-Section 44.40: {writeany}, {wa} default: nowa
-
-Inhibit the checks normally made before write commands, allowing a write to any
-file which the system protection mechanism will allow.
-
-Section 44.41: {w300}, {w1200}, {w9600} defaults: w300=8
- w1200=16
- w9600=full screen minus one
-
-These are not true options but set the default size of the window for when the
-speed is slow (300), medium (1200), or high (9600), respectively. They are
-suitable for an EXINIT and make it easy to change the 8/16/full screen rule.
-
-Section 45: Limitations
-
-Here are some editor limits that the user is likely to encounter:
- 1024 characters per line
- 256 characters per global command list
- 128 characters per file name
- 128 characters in the previous inserted and deleted text in open or
- visual
- 100 characters in a shell escape command
- 63 characters in a string valued option
- 30 characters in a tag name
- 250000 lines in the file (this is silently enforced).
-
-The visual implementation limits the number of macros defined with map to 32,
-and the total number of characters in macros to be less than 512.
-
-[Editor's note: these limits may not apply to versions after 4.1BSD.]
diff --git a/contrib/nvi/docs/tutorial/vi.beginner b/contrib/nvi/docs/tutorial/vi.beginner
deleted file mode 100644
index 3bf35ac..0000000
--- a/contrib/nvi/docs/tutorial/vi.beginner
+++ /dev/null
@@ -1,741 +0,0 @@
-Section 1: {^F} {ZZ}
-
-To get out of this tutorial, type: ZZ (two capital Z's).
-
-Learning a new computer system implies learning a new text editor. These
-tutorial lessons were created by Dain Samples to help you come to grips with
-UC Berkeley's screen oriented editor called vi (for VIsual). This tutorial
-uses the vi editor itself as the means of presentation.
-
-For best use of this tutorial, read all of a screen before performing any of
-the indicated actions. This tutorial (or, at least, the first half of it) has
-been designed to systematically present the vi commands IF THE INSTRUCTIONS
-ARE FOLLOWED! If you are too adventuresome, you may find yourself lost. If
-you ever find yourself stuck, remember the first line of this section.
-
-OK, now find the control key on your keyboard; it usually has CTL or CTRL
-written on its upper surface. Your first assignment is to hold the control
-key down while you press the 'F' key on your keyboard. Please do so now.
-
-
-
-Section 2: {^F} {^B}
-Many of vi's commands use the control key and some other key in combination,
-as with the control and the 'F' key above. This is abbreviated CTL-F, or ^F.
-
-As you have probably guessed by now, ^F (CTL-F) moves you forward a fixed
-number of lines in the file. Throughout the remainder of the tutorial when
-you are ready to advance to the next section of text, hit ^F.
-
-The opposite command is ^B. Just for fun, you might want to try a ^B to see
-the previous section again. Be sure to do a ^F to return you here.
-
-Determine what the cursor looks like on your screen. Whatever it is (a box,
-an underscore, blinking, flashing, inverse, etc.) it should now be positioned
-in the upper left-hand corner of your screen under or on the S of Section.
-Become familiar with your cursor: to use vi correctly it is important to
-always know where the cursor is.
-
-Did you notice that when you do a ^F the cursor is left at the top of the
-screen, and a ^B leaves the cursor near the bottom of the screen? Try the two
-commands ^B^F again. And now do another ^F to see the next section.
-
-Section 3: {^F} {^B}
-You now have two basic commands for examining a file, both forwards (^F) and
-backwards (^B).
-
-Note that these are vi text editing commands: they are not commands for the
-tutorial. Indeed, this tutorial is nothing but a text file which you are now
-editing. Everything you do and learn in this tutorial will be applicable to
-editing text files.
-
-Therefore, when you are editing a file and are ready to see more of the text,
-entering ^F will get you to the next section of the file. Entering ^B will
-show you the previous section.
-
-Time for you to do another ^F.
-
-
-
-
-
-
-
-Section 4: {^F} {^B} {^M} (return key)
-We will adopt the notation of putting commands in curly braces so we can write
-them unambiguously. For example, if you are to type the command sequence
-"control B control F" (as we asked you to do above) it would appear as {^B^F}.
-This allows clear delineation of the command strings from the text. Remember
-that the curly braces are NOT part of the command string you are to type. Do
-NOT type the curly braces.
-
-Sometimes, the command string in the curly braces will be rather long, and may
-be such that the first couple of characters of the command will erase from
-the screen the string you are trying to read and type. It is suggested that
-you write down the longer commands BEFORE you type them so you won't forget
-them once they disappear.
-
-Now locate the return key on your keyboard: it is usually marked 'RETURN',
-indicate hitting the return key. In fact, the control-M key sequence is
-exactly the same as if you hit the return key, and vice versa.
-
-Now type {^F}.
-
-
-Section 5: {:q!} {ZZ} {^M} (return key)
-Recognize that this tutorial is nothing more than a text file that you
-are editing. This means that if you do something wrong, it is possible
-for you to destroy the information in this file. Don't worry. If this
-happens, type {ZZ} (two capital Z's) or {:q!^M} to leave the tutorial.
-Restart the tutorial. Once in the tutorial, you can then page forward
-with {^F} until you are back to where you want to be. (There are
-easier ways to do this, some of which will be discussed later, but this
-is the most straightforward.)
-
-You may want to write these commands down in a convenient place for quick
-reference: {:q!^M} and {ZZ}
-
-We will assume that you now know to do a {^F} to advance the file
-
-
-
-
-
-
-
-Section 6: {m} {G} {'} {z}
-Now that you know how to get around in the file via ^F and ^B let's look at
-other ways of examining a text file. Sometimes it is necessary, in the midst
-of editing a file, to examine another part of the file. You are then faced
-with the problem of remembering your place in the file, looking at the other
-text, and then getting back to your original location. Vi has a 'mark'
-command, m. Type {mp}. You have just 'marked' your current location in the
-file and given it the name 'p'. The command string below will do three
-things: position you at the beginning of the file (line 1), then return you to
-the location 'p' that you just marked with the 'm' command, and, since the
-screen will not look exactly the same as it does right now, the 'z' command
-will reposition the screen. (You may want to write the string down before
-typing it: once you type {1G} it will no longer be on the screen.)
-
-So now type {1G'pz^M} - a one followed by a capital G, followed by the quote
-mark, followed by a lower case 'p', then a lower case 'z', then a return
-(which is the same as a ^M). The {1G} moves you to line 1, i.e. the beginning
-of the file. The {'p} moves you to the location you marked with {mp}. The
-{z^M} command will repaint the screen putting the cursor at the top of the
-screen. (Now {^F}.)
-
-Section 7: {m} {G} {'} {z}
-Let's look at some variations on those commands. If you wanted to look at
-line 22 in the file and return to this location you could type {mp22G'p}. Do
-so now, observing that {22G} puts your cursor at the beginning of section 2 in
-the middle of the screen.
-
-Also note that, without the {z^M} command, the line with 'Section 7' on it is
-now in the MIDDLE of the screen, and not at the top. Our cursor is on the
-correct line (where we did the {mp} command) but the line is not where we
-might like it to be on the screen. That is the function of the {z^M} command.
-(Remember, ^M is the same as the 'return' key on your keyboard.) Type {z^M}
-now and observe the effect.
-
-As you can see, the 'Section 7' line is now at the top of the screen with the
-cursor happily under the capital S. If you would like the cursor line (i.e.
-the line which the cursor is on) in the middle of the screen again, you would
-type {z.}. If you wanted the cursor line to be at the BOTTOM of the screen,
-type {z-}. Try typing {z-z.z^M} and watch what happens.
-
-{^F}
-
-Section 8: {z} {m} {'}
-
-Note that the z command does not change the position of our cursor in the file
-itself, it simply moves the cursor around on the screen by moving the contents
-of the file around on the screen. The cursor stays on the same line of the
-file when using the z command.
-
-This brings up an important point. There are two questions that the users of
-vi continually need to know the answer to: "Where am I in the file?" and
-"Where am I on the screen?" The cursor on your terminal shows the answer to
-both questions. Some commands will move you around in the file, usually
-changing the location of the cursor on the screen as well. Other commands
-move the cursor around on the screen without changing your location in the
-file.
-
-Now type {ma}. Your location in the file has been given the name 'a'. If you
-type {'p'a} you will see the previous location we marked in section 7, and
-then will be returned to the current location. (You will want to do a {z^M}
-to repaint the screen afterwards.) Try it.
-{^F}
-
-Section 9: {m} {''}
-Now we can move about in our file pretty freely. By using the {m} command we
-can give the current cursor position a lower-case-character name, like 'p',
-'a', 'e', 'm', or 'b'. Using the {G} command preceded by a line number we can
-look at any line in the file we like. Using the single quote command {'}
-followed by a character used in an {m} command, we can return to any location
-in the file we have marked.
-
-However, try {m3}, or {mM}. You should hear a beep, or bell. Only lower-case
-letters are acceptable to the {m} and {'} commands: numbers, upper-case
-letters, and special characters are not acceptable.
-
-If you type the {'} command with a character that is lower-case alphabetic but
-that has not been used in an {m} command, or for which the 'marked' text has
-been deleted, you will also get a beep. Try {'i}. You should get a beep
-because the command {mi} has never been issued. (Unless you've been
-experimenting.)
-
-The command {''} attempts to return you to the location at which you last
-modified some part of your file. However, my experience has been that it is
-difficult to predict exactly where you will end up.
-Section 10: {^M} {-}
-Now do {ma}, marking your position at the top of the screen. Now hit {^M} (or
-return) until the cursor is right ...
-* <- here, over/under the asterisk. Now
-type {mb'a'b} and watch the cursor move from the asterisk to the top of the
-screen and back again.
-
-The {^M} command moves the cursor to the beginning of the next line. Now type
-{^M} until the cursor is right ...
-* <- here. The command to move the cursor to the beginning of the
-previous line is {-}. Practice moving the cursor around on the screen by using
-{^M} and {-}. BE CAREFUL to not move the cursor OFF the screen just yet. If
-you do, type {'az^M}.
-
-Now we can move to any line within the screen. Practice moving around in the
-file using the {^F}, {^B}, {-}, {^M}, {z}, and {'} commands. When you are
-fairly confident that you can get to where you need to be in the file, and
-position the cursor on the screen where you want it type {'az^M^F} (which, of
-course, moves you back to the beginning of this section, repositions the
-cursor at the top of the screen, and advances you to the next section).
-
-Section 11: scrolling: {^M}
-The cursor should now be on the S of 'Section 11', and this should be on the
-first line of the screen. If it is not, do {^M} or {-} as appropriate to put
-the cursor on the section line, and type {z^M}.
-
-Type {mc} to mark your place.
-
-Now type {^M} until the cursor is on the last line of this screen. Now do one
-more {^M} and observe the result. This is called scrolling. When you
-attempted to move to a line not displayed on the screen, the line at the top of
-the screen was 'scrolled off', and a line at the bottom of the screen was
-'scrolled on'. The top line with 'Section 11' should no longer be visible.
-
-Now type {'cz^M} to reset the screen and type {^F} for the next section.
-
-
-
-
-
-
-
-Section 12: {-} {z}
-
-The {-} command moves the cursor to the previous line in the file. Now type
-{-}, which attempts to move the cursor to the previous line in this file.
-However, that line is not on the screen. The resulting action will depend on
-your terminal. (Do a {^Mz^M} to reposition the file). On intelligent
-terminals (e.g. VT100s, Z19s, Concept 100s), a top line is 'scrolled on' and
-the bottom line is 'scrolled off'. Other terminals, however, may not have
-this 'reverse scrolling' feature. They will simply repaint the screen with
-the cursor line in the middle of the screen. On such terminals it is
-necessary to type {z^M} to get the cursor line back to the top of the screen.
-
-
-
-
-
-
-
-
-
-
-Section 13:
-Up until this point, the tutorial has always tried to make sure that the first
-line of each screen has on it the section number and a list of the commands
-covered in that section. This will no longer be strictly maintained. If you
-want the section line at the top of the screen, you now know enough commands to
-do it easily: do {^M} or {-} until the cursor is on the section line and
-then {z^M}. Also, from this point on, it may not be the case that a {^F} will
-put you at the beginning of the next section. Therefore, be aware of where you
-are in the file as we look at other commands. You may have to find your way
-back to a particular section without any help from the tutorial. If you do not
-feel comfortable with this, then it is suggested that you practice moving from
-section 1 to section 13, back and forth, using {^M}, {-}, {^F}, and {^B}
-commands for a while.
-
-Also make liberal use of the mark command {m}: if, for example, you make a
-habit of using {mz} to mark your current location in the file, then you will
-always be able to return to that location with {'z} if the editor does
-something strange and you have no idea where you are or what happened.
-
-And finally, the proscription against experimentation is hereby lifted: play
-with the editor. Feel free to try out variations on the commands and move
-around in the file. By this time you should be able to recover from any gross
-errors.
-
-Section 14: {^E} {^Y} {^D} {^U}
-Let us now look at a few other commands for moving around in the file, and
-moving the file around on the screen. Note that the commands we have already
-looked at are sufficient: you really don't need any more commands for looking
-in a file. The following commands are not absolutely necessary. However,
-they can make editing more convenient, and you should take note of their
-existence. But it would be perfectly valid to decide to ignore them on this
-first pass: you can learn them later when you see a need for them, if you ever
-do.
-
-First, let's clear up some potentially confusing language. In at least one
-place in the official document ('An Introduction to Display Editing with Vi'
-by William Joy, and Mark Horton, September 1980), the expression "to scroll
-down text" means that the cursor is moved down in your file. However, note
-that this may result in the text on the screen moving UP. This use of the
-word 'scroll' refers to the action of the cursor within the file. However,
-another legitimate use of the word refers to the action of the text on the
-screen. That is, if the lines on your screen move up toward the top of the
-screen, this would be 'scrolling the screen up'. If the lines move down
-toward the bottom of the screen, this would be refered to as scrolling down.
-
-I have tried to maintain the following jargon: 'scrolling' refers to what the
-text does on the screen, not to what the cursor does within the file. For the
-latter I will refer to the cursor 'moving', or to 'moving the cursor'. I
-realize that this is not necessarily consistent with Joy and Horton, but they
-were wrong.
-
-{^E} scrolls the whole screen up one line, keeping the cursor on the same line,
-if possible. However, if the cursor line is the first line on the screen, then
-the cursor is moved to the next line in the file. Try typing {^E}.
-
-{^Y} scrolls the screen down one line, keeping the cursor on the same line, if
-possible. However, if the cursor line is the last line on the screen, then the
-cursor is moved to the previous line in the file. Try it.
-
-{^D} moves the cursor down into the file, scrolling the screen up.
-
-{^U} moves the cursor up into the file, also scrolling the screen if the
-terminal you are on has the reverse scroll capability. Otherwise the
-screen is repainted.
-
-Note that {^E} and {^Y} move the cursor on the screen while trying to keep the
-cursor at the same place in the file (if possible: however, the cursor can
-never move off screen), while {^D} and {^U} keep the cursor at the same place
-on the screen while moving the cursor within the file.
-
-Section 15: {/ .. /^M}
-
-Another way to position yourself in the file is by giving the editor a string
-to search for. Type the following: {/Here 1/^M} and the cursor should end up
-right ...........................here ^. Now type {/Section 15:/^M} and the
-cursor will end up over/on .....................here ^. Now type {//^M} and
-observe that the cursor is now over the capital S five lines above this line.
-Typing {//^M} several more times will bounce the cursor back and forth between
-the two occurrences of the string. In other words, when you type a string
-between the two slashes, it is searched for. Typing the slashes with nothing
-between them acts as if you had typed the previous string again.
-
-Observe that the string you type between the two slashes is entered on the
-bottom line of the screen. Now type {/Search for x /^M} except replace the 'x'
-in the string with some other character, say 'b'. The message "Pattern not
-found" should appear on the bottom of the screen. If you hadn't replaced the
-'x', then you would have found the string. Try it.
-
-Section 16: {? .. ?^M} {n} (search strings: ^ $)
-
-When you surround the sought-for string with slashes as in {/Search/}, the
-file is searched beginning from your current position in the file. If the
-string is not found by the end of the file, searching is restarted at the
-beginning of the file. However, if you do want the search to find the
-PREVIOUS rather than the NEXT occurrence of the string, surround the string
-with question marks instead of slash marks.
-
-Below are several occurrences of the same string.
-Here 2 Here 2 Here 2
- Here 2 Here 2.
-Observe the effect of the following search commands (try them in the
-sequence shown):
-{/Here 2/^M} {//^M} {??^M}
-{/^Here 2/^M} {//^M} {??^M}
-{/Here 2$/^M} {//^M} {??^M}
-
-The first command looks for the next occurrence of the string 'Here 2'.
-However the second line of commands looks for an occurrence of 'Here 2' that
-is at the beginning of the line. When the up-arrow is the first character of
-a search string it stands for the beginning of the line. When the dollar-sign
-is the last character of the search string it stands for the end of the line.
-Therefore, the third line of commands searches for the string only when it is
-at the end of the line. Since there is only one place the string begins a
-line, and only one place the string ends the line, subsequent {//^M} and
-{??^M} will find those same strings over and over.
-
-The {n} command will find the next occurrence of the / or ? search
-string. Try {/Here 2/^M} followed by several {n} and observe the
-effect. Then try {??^M} followed by several {n}. The {n} command
-remembers the direction of the last search. It is just a way to save a
-few keystrokes.
-
-Section 17: \ and magic-characters in search strings
-
-Now type {/Here 3$/^M}. You might expect the cursor to end up
-right......^ here. However, you will get "Pattern not found" at the bottom of
-the screen. Remember that the dollar-sign stands for the end of the line.
-Somehow, you must tell vi that you do not want the end of the line, but a
-dollar-sign. In other words, you must take away the special meaning that the
-dollar-sign has for the search mechanism. You do this (for any special
-character, including the up-arrow ^) by putting a back-slash ('\', not '/') in
-front of the character.
-
-Now try {/Here 3\$/^M} and you should end up nine lines above this one. Try
-{//^M} and note that it returns you to the same place, and not to the first
-line of this paragraph: the back-slash character is not part of the search
-string and will not be found. To find the string in the first line of this
-paragraph, type {/Here 3\\\$/^M}. There are three back-slashes: the first takes
-away the special meaning from the second, and the third takes away the special
-meaning from the dollar-sign.
-
-Following is a list of the characters that have special meanings in search
-strings. If you wish to find a string containing one of these characters, you
-will have to be precede the character with a backslash. These characters are
-called magic characters because of the fun and games you can have with them
-and they can have with you, if you aren't aware of what they do.
-
- ^ - (up-arrow) beginning of a line
- $ - (dollar-sign) end of a line
- . - (period) matches any character
- \ - (backslant) the escape character itself
- [ - (square bracket) for finding patterns (see section #SEARCH)
- ] - (square bracket) ditto
- * - (asterisk) ditto
-
-Without trying to explain it here, note that {:set nomagic^M} turns off the
-special meanings of all but the ^ up-arrow, $ dollar-sign, and backslash
-characters.
-
-Section 18: {: (colon commands)} {ZZ}
-
-In this section we will discuss getting into and out of the editor in more
-detail. If you are editing a file and wish to save the results the command
-sequence {:w^M} writes the current contents of the file out to disk, using the
-file name you used when you invoked the editor. That is, if you are at the
-command level in Unix, and you invoke vi with {vi foo} where foo is the name
-of the file you wish to edit, then foo is the name of the file used by the
-{:w^M} command.
-
-If you are done, the write and quit commands can be combined into a single
-command {:wq^M}. An even simpler way is the command {ZZ} (two capital Z's).
-
-If, for some reason, you wish to exit without saving any changes you have made,
-{:q!^M} does the trick. If you have not made any changes, the exclamation
-point is not necessary: {:q^M}. Vi is pretty good about not letting you
-get out without warning you that you haven't saved your file.
-
-We have mentioned before that you are currently in the vi editor, editing a
-file. If you wish to start the tutorial over from the very beginning, you
-could {ZZ}, and then type {vi.tut beginner} in response to the Unix prompt.
-This will create a fresh copy of this file for you, which might be necessary
-if you accidentally destroyed the copy you were working with. Just do a
-search for the last section you were in: e.g. {/Section 18:/^Mz^M}.
-
-Section 19: {H} {M} {L}
-
-Here are a few more commands that will move you around on the screen. Again,
-they are not absolutely necessary, but they can make screen positioning easier:
-
-{H} - puts the cursor at the top of the screen (the 'home' position)
-
-{M} - puts the cursor in the middle of the screen
-
-{L} - puts the cursor at the bottom of the screen.
-
-Try typing {HML} and watch the cursor.
-
-Try typing {5HM5L} and note that 5H puts you five lines from the top of the
-screen, and 5L puts you five lines from the bottom of the screen.
-
-Section 20: {w} {b} {0} {W} {B} {e} {E} {'} {`}
-
-Up to this point we have concentrated on positioning in the file, and
-positioning on the screen. Now let's look at positioning in a line. Put the
-cursor at the beginning of the following line and type {z^M}:
-
-This is a test line: your cursor should initially be at its beginning.
-
-The test line should now be at the top of your screen. Type {w} several times.
-Note that it moves you forward to the beginning of the next word. Now type
-{b} (back to the beginning of the word) several times till you are at the
-beginning of the line. (If you accidentally type too many {b}, type {w} until
-you are on the beginning of the line again.) Type {wwwww} (five w's) and note
-that the cursor is now on the colon in the sentence. The lower-case w command
-moves you forward one word, paying attention to certain characters such as
-colon and period as delimiters and counting them as words themselves. Now
-type {0} (zero, not o 'oh'): this moves you to the beginning of the current
-line. Now type {5w} and notice that this has the effect of repeating {w} five
-times and that you are now back on the colon. Type {0} (zero) again. To
-ignore the delimiters and to move to the beginning of the next word using only
-blanks, tabs and carriage-returns (these are called white-space characters) to
-delimit the words, use the {W} command: upper-case W. {B} takes you back a
-word using white-space characters as word delimiters.
-
-Note that the commands {wbWB} do not stop at the beginning or end of a line:
-they will continue to the next word on the next line in the direction specified
-(a blank line counts as a word).
-
-If you are interested in the END of the word, and not the BEGINNING, then use
-the {e} and {E} commands. These commands only move forward and there are no
-corresponding 'reverse search' commands for the end of a word.
-
-Also, we have been using the {'} command to move the cursor to a position that
-we have previously marked with the {m} command. However, position the cursor
-in the middle of a line (any line, just pick one) and type {mk}, marking that
-position with the letter k. Now type a few returns {^M} and type {'k}.
-Observe that the cursor is now at the beginning of the line that you marked.
-Now try {`k}: note that this is the reverse apostrophe, or back-quote, or grave
-accent, or whatever you want to call it. Also note that it moves you to the
-character that was marked, not just to the line that was marked.
-
-In addition, the {``} command works just like the {''} command except that you
-are taken to the exact character, not just to the line. (I'm still not
-sure which exact character, just as I'm still not sure which line.)
-
-Section 21: {l} {k} {j} {h}
-
-There are several commands to move around on the screen on a character by
-character basis:
-
-l - moves the cursor one character to the RIGHT
-k - moves the cursor UP one line
-j - moves the cursor DOWN one line
-h - moves the cursor one character to the LEFT
-
-Section 22: {i} {a} {I} {A} {o} {O} ^[ (escape key)
-
-For this and following sections you will need to use the ESCAPE key on your
-terminal. It is usually marked ESC. Since the escape key is the same as
-typing {^[} we will use ^[ for the escape key.
-
-Probably the most often used command in an editor is the insert command. Below
-are two lines of text, the first correct, the second incorrect. Position your
-cursor at the beginning of Line 1 and type {z^M}.
-
-Line 1: This is an example of the insert command.
-Line 2: This is an of the insert command.
-
-To make line 2 look like line 1, we are going to insert the characters
-'example ' before the word 'of'. So, now move the cursor so that it is
-positioned on the 'o' of 'of'. (You can do this by typing {^M} to move
-to the beginning of line 2, followed by {6w} or {wwwwww} to position the cursor
-on the word 'of'.)
-
-Now carefully type the following string and observe the effects:
- {iexample ^[} (remember: ^[ is the escape key)}
-The {i} begins the insert mode, and 'example ' is inserted into the line:
-be sure to notice the blank in 'example '. The ^[ ends insertion mode,
-and the line is updated to include the new string. Line 1 should look exactly
-like Line 2.
-
-Move the cursor to the beginning of Line 3 below and type {z^M}:
-
-Line 3: These lines are examples for the 'a' command.
-Line 4: These line are examples for the '
-
-We will change line four to look like line three by using the append command.
-We need to append an 's' to the word 'line'. Position the cursor on the 'e'
-of 'line'. You can do this in several ways, one way is the following:
-First, type {/line /^M}. This puts us on the word 'line' in Line 4
-(the blank in the search string is important!). Next, type {e}. The 'e' puts
-us at the end of the word. Now, type {as^[ (^[ is the escape character)}.
-The 'a' puts us in insert mode, AFTER the current character. We appended the
-'s', and the escape ^[ ended the insert mode.
-
-The difference between {i} (insert) and {a} (append) is that {i} begins
-inserting text BEFORE the cursor, and {a} begins inserting AFTER the cursor.
-
-Now type {Aa' command.^[}. The cursor is moved to the end of the line and the
-string following {A} is inserted into the text. Line 4 should now look like
-line 3.
-
-Just as {A} moves you to the end of the line to begin inserting, {I} would
-begin inserting at the FRONT of the line.
-
-To begin the insertion of a line after the cursor line, type {o}. To insert a
-line before the cursor line, type {O}. In other words {o123^[} is equivalent
-to {A^M123^[}, and {O123^[} is equivalent to {I123^M^[}. The text after the
-{o} or {O} is ended with an escape ^[.
-
-This paragraph contains information that is terminal dependent: you will just
-have to experiment to discover what your terminal does. Once in the insert
-mode, if you make a mistake in the typing, ^H will delete the previous
-character up to the beginning of the current insertion. ^W will delete the
-previous word, and one of ^U, @, or ^X will delete the current line (up to the
-beginning of the current insertion). You will need to experiment with ^U, @,
-and ^X to determine which works for your terminal.
-
-Section 23: {f} {x} {X} {w} {l} {r} {R} {s} {S} {J}
-
-Position the cursor at the beginning of line 5 and {z^M}:
-
-Line 5: The line as it should be.
-Line 6: The line as it shouldn't be.
-
-To make Line 6 like Line 5, we have to delete the 'n', the apostrophe, and the
-'t'. There are several ways to position ourselves at the 'n'. Choose
-whichever one suits your fancy:
-
-{/n't/^M}
-{^M7w6l} or {^M7w6 } (note the space)
-{^M3fn} (finds the 3rd 'n' on the line)
-
-Now {xxx} will delete the three characters, as will {3x}.
-
-Note that {X} deletes the character just BEFORE the cursor, as opposed
-to the character AT the cursor.
-
-Position the cursor at line 7 and {z^M}:
-
-Line 7: The line as it would be.
-Line 8: The line as it could be.
-
-To change line 8 into line 7 we need to change the 'c' in 'could' into a 'w'.
-The 'r' (replace) command was designed for this. Typing {rc} is the same as
-typing {xic^[} (i.e. delete the 'bad' character and insert the correct
-new character). Therefore, assuming that you have positioned the cursor on the
-'c' of 'could', the easiest way to change 'could' into 'would' is {rw}.
-
-If you would like to now change the 'would' into 'should', use the substitute
-command, 's': {ssh^[}. The difference between 'r' and 's' is that 'r'
-(replace) replaces the current character with another character, while 's'
-(substitute) substitutes the current character with a string, ended with an
-escape.
-
-The capital letter version of replace {R} replaces each character by a
-character one at a time until you type an escape, ^[. The 'S' command
-substitutes the whole line.
-
-Position your cursor at the beginning of line 9 and {z^M}.
-
-Line 9: Love is a many splendored thing.
-Line 10: Love is a most splendored thing.
-
-To change line 10 into line 9, position the cursor at the beginning of 'most',
-and type {Rmany^[}.
-
-You may have noticed that, when inserting text, a new line is formed by typing
-{^M}. When changing, replacing, or substituting text you can make a new line
-by typing {^M}. However, neither {x} nor {X} will remove ^M to make two lines
-into one line. To do this, position the cursor on the first of the two lines
-you wish to make into a single line and type {J} (uppercase J for 'Join').
-
-Section 24: {u} {U}
-
-Finally, before we review, let's look at the undo command. Position
-your cursor on line 11 below and {z^M}.
-
-Line 11: The quick brown fox jumped over the lazy hound dog.
-Line 12: the qwick black dog dumped over the laxy poune fox.
-
-Type the following set of commands, and observe carefully the effect of each
-of the commands:
-
-{/^Line 12:/^M} {ft} {rT} {fw} {ru} {w} {Rbrown fox^[} {w} {rj}
-{fx} {rz} {w} {Rhound dog^[}
-
-Line 12 now matches line 11. Now type {U} - capital 'U'. And line 12 now
-looks like it did before you typed in the command strings. Now type:
-
-{ft} {rT} {fw} {ru} {^M} {^M}
-
-and then type {u}: the cursor jumps back to the line containing the second
-change you made and 'undoes' it. That is, {U} 'undoes' all the changes on the
-line, and {u} 'undoes' only the last change. Type {u} several times and
-observe what happens: {u} can undo a previous {u}!
-
-Caveat: {U} only works as long as the cursor is still on the line. Move the
-cursor off the line and {U} will have no effect, except to possibly beep at
-you. However, {u} will undo the last change, no matter where it occurred.
-
-Section 25: review
-
-At this point, you have all the commands you need in order to make use of vi.
-The remainder of this tutorial will discuss variations on these commands as
-well as introduce new commands that make the job of editing more efficient.
-Here is a brief review of the basic commands we have covered. They are listed
-in the order of increasing complexity and/or decreasing necessity (to say that
-a command is less necessary is not to say that it is less useful!). These
-commands allow you to comfortably edit any text file. There are other
-commands that will make life easier but will require extra time to learn,
-obviously. You may want to consider setting this tutorial aside for several
-weeks and returning to it later after gaining experience with vi and getting
-comfortable with it. The convenience of some of the more exotic commands may
-then be apparent and worth the extra investment of time and effort
-required to master them.
-
-to get into the editor from Unix: {vi filename}
-to exit the editor
- saving all changes {ZZ} or {:wq^M}
- throwing away all changes {:q!^M}
- when no changes have been made {:q^M}
-save a file without exiting the editor {:w^M}
-write the file into another file {:w filename^M}
-insert text
- before the cursor {i ...text... ^[}
- at the beginning of the line {I ...text... ^[}
- after the cursor (append) {a ...text... ^[}
- at the end of the line {A ...text... ^[}
- after the current line {o ...text... ^[}
- before the current line {O ...text... ^[}
-delete the character ...
- under the cursor {x}
- to the left of the cursor {X}
-delete n characters {nx} or {nX} (for n a number)
-make two lines into one line (Join) {J}
-find a string in the file ...
- searching forward {/ ...string... /^M}
- searching backwards {? ...string... ?^M}
-repeat the last search command {n}
-repeat the last search command in the
- opposite direction {N}
-find the character c on this line ...
- searching forward {fc}
- searching backward {Fc}
-repeat the last 'find character' command {;}
-replace a character with character x {rx}
-substitute a single character with text {s ...text... ^[}
-substitute n characters with text {ns ...text... ^[}
-replace characters one-by-one with text {R ...text... ^[}
-undo all changes to the current line {U}
-undo the last single change {u}
-move forward in the file a "screenful" {^F}
-move back in the file a "screenful" {^B}
-move forward in the file one line {^M} or {+}
-move backward in the file one line {-}
-move to the beginning of the line {0}
-move to the end of the line {$}
-move forward one word {w}
-move forward one word, ignoring punctuation {W}
-move forward to the end of the next word {e}
-to the end of the word, ignoring punctuation{E}
-move backward one word {b}
-move back one word, ignoring punctuation {B}
-return to the last line modified {''}
-scroll a line onto the top of the screen {^Y}
-scroll a line onto the bottom of the screen {^E}
-move "up" in the file a half-screen {^U}
-move "down" in the file a half-screen {^D}
-move the cursor to the top screen line {H}
-move the cursor to the bottom screen line {L}
-move the cursor to the middle line {M}
-move LEFT one character position {h} or {^H}
-move RIGHT one character position {l} or { }
-move UP in the same column {k} or {^P}
-move DOWN in the same column {j} or {^N}
-mark the current position, name it x {mx}
-move to the line marked/named x {'x}
-move to the character position named x {`x}
-move to the beginning of the file {1G}
-move to the end of the file {G}
-move to line 23 in the file {23G}
-repaint the screen with the cursor line
- at the top of the screen {z^M}
- in the middle of the screen {z.}
- at the bottom of the screen {z-}
-
-More information on vi can be found in the file vi.advanced, which you can
-peruse at your leisure. From UNIX, type {vi.tut advanced^M}.
diff --git a/contrib/nvi/docs/tutorial/vi.tut.csh b/contrib/nvi/docs/tutorial/vi.tut.csh
deleted file mode 100755
index 01554bc..0000000
--- a/contrib/nvi/docs/tutorial/vi.tut.csh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/csh -f
-#
-# This makes the user's EXINIT variable set to the 'correct' things.
-# I don't know what will happen if they also have a .exrc file!
-#
-# XXX
-# Make sure that user is using a 24 line window!!!
-#
-if ($1 != "beginner" && $1 != "advanced") then
- echo Usage: $0 beginner or $0 advanced
- exit
-endif
-
-if ($?EXINIT) then
- set oexinit="$EXINIT"
- setenv EXINIT 'se ts=4 wm=8 sw=4'
-endif
-
-vi vi.{$1}
-
-onintr:
- if ($?oexinit) then
- setenv EXINIT "$oexinit"
-endif
diff --git a/contrib/nvi/ex/ex.c b/contrib/nvi/ex/ex.c
index 609f961..00df2cc 100644
--- a/contrib/nvi/ex/ex.c
+++ b/contrib/nvi/ex/ex.c
@@ -31,20 +31,20 @@ static const char sccsid[] = "$Id: ex.c,v 10.80 2012/10/03 16:24:40 zy Exp $";
#include "../vi/vi.h"
#if defined(DEBUG) && defined(COMLOG)
-static void ex_comlog __P((SCR *, EXCMD *));
+static void ex_comlog(SCR *, EXCMD *);
#endif
static EXCMDLIST const *
- ex_comm_search __P((CHAR_T *, size_t));
-static int ex_discard __P((SCR *));
-static int ex_line __P((SCR *, EXCMD *, MARK *, int *, int *));
-static int ex_load __P((SCR *));
-static void ex_unknown __P((SCR *, CHAR_T *, size_t));
+ ex_comm_search(CHAR_T *, size_t);
+static int ex_discard(SCR *);
+static int ex_line(SCR *, EXCMD *, MARK *, int *, int *);
+static int ex_load(SCR *);
+static void ex_unknown(SCR *, CHAR_T *, size_t);
/*
* ex --
* Main ex loop.
*
- * PUBLIC: int ex __P((SCR **));
+ * PUBLIC: int ex(SCR **);
*/
int
ex(SCR **spp)
@@ -187,7 +187,7 @@ ex(SCR **spp)
*
* For extra credit, try them in a startup .exrc file.
*
- * PUBLIC: int ex_cmd __P((SCR *));
+ * PUBLIC: int ex_cmd(SCR *);
*/
int
ex_cmd(SCR *sp)
@@ -1616,7 +1616,7 @@ rsuccess: tmp = 0;
* ex_range --
* Get a line range for ex commands, or perform a vi ex address search.
*
- * PUBLIC: int ex_range __P((SCR *, EXCMD *, int *));
+ * PUBLIC: int ex_range(SCR *, EXCMD *, int *);
*/
int
ex_range(SCR *sp, EXCMD *ecp, int *errp)
@@ -1689,12 +1689,12 @@ ex_range(SCR *sp, EXCMD *ecp, int *errp)
++ecp->cp;
--ecp->clen;
break;
- case ',': /* Comma delimiter. */
+ case ',': /* Comma delimiter. */
/* Vi ex address searches didn't permit commas. */
if (F_ISSET(ecp, E_VISEARCH))
goto ret;
/* FALLTHROUGH */
- case ';': /* Semi-colon delimiter. */
+ case ';': /* Semi-colon delimiter. */
if (sp->ep == NULL) {
ex_badaddr(sp, NULL, A_EMPTY, NUM_OK);
*errp = 1;
@@ -1825,7 +1825,7 @@ ex_line(SCR *sp, EXCMD *ecp, MARK *mp, int *isaddrp, int *errp)
GS *gp;
long total, val;
int isneg;
- int (*sf) __P((SCR *, MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
+ int (*sf)(SCR *, MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int);
CHAR_T *endp;
gp = sp->gp;
@@ -2219,7 +2219,7 @@ alloc_err:
* [un]abbreviate command, so it can turn off abbreviations. See
* the usual ranting in the vi/v_txt_ev.c:txt_abbrev() routine.
*
- * PUBLIC: int ex_is_abbrev __P((CHAR_T *, size_t));
+ * PUBLIC: int ex_is_abbrev(CHAR_T *, size_t);
*/
int
ex_is_abbrev(CHAR_T *name, size_t len)
@@ -2236,7 +2236,7 @@ ex_is_abbrev(CHAR_T *name, size_t len)
* unmap command, so it can turn off input mapping. See the usual
* ranting in the vi/v_txt_ev.c:txt_unmap() routine.
*
- * PUBLIC: int ex_is_unmap __P((CHAR_T *, size_t));
+ * PUBLIC: int ex_is_unmap(CHAR_T *, size_t);
*/
int
ex_is_unmap(CHAR_T *name, size_t len)
@@ -2279,7 +2279,7 @@ ex_comm_search(CHAR_T *name, size_t len)
* Display a bad address message.
*
* PUBLIC: void ex_badaddr
- * PUBLIC: __P((SCR *, EXCMDLIST const *, enum badaddr, enum nresult));
+ * PUBLIC: (SCR *, EXCMDLIST const *, enum badaddr, enum nresult);
*/
void
ex_badaddr(SCR *sp, const EXCMDLIST *cp, enum badaddr ba, enum nresult nret)
diff --git a/contrib/nvi/ex/ex.h b/contrib/nvi/ex/ex.h
index f5ba4c2..4cb52cc 100644
--- a/contrib/nvi/ex/ex.h
+++ b/contrib/nvi/ex/ex.h
@@ -13,7 +13,7 @@
typedef struct _excmdlist { /* Ex command table structure. */
CHAR_T *name; /* Command name, underlying function. */
- int (*fn) __P((SCR *, EXCMD *));
+ int (*fn)(SCR *, EXCMD *);
#define E_ADDR1 0x00000001 /* One address. */
#define E_ADDR2 0x00000002 /* Two addresses. */
@@ -222,7 +222,7 @@ typedef enum {
/* Ex address error types. */
enum badaddr { A_COMBO, A_EMPTY, A_EOF, A_NOTSET, A_ZERO };
-/* Ex common tag error messages. */
+/* Ex common tag error messages. */
typedef enum {
TAG_BADLNO, /* Tag line doesn't exist. */
TAG_EMPTY, /* Tags stack is empty. */
diff --git a/contrib/nvi/ex/ex_abbrev.c b/contrib/nvi/ex/ex_abbrev.c
index 6624889..5fd5735 100644
--- a/contrib/nvi/ex/ex_abbrev.c
+++ b/contrib/nvi/ex/ex_abbrev.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: ex_abbrev.c,v 10.10 2001/12/16 18:18:54 skimo
* ex_abbr -- :abbreviate [key replacement]
* Create an abbreviation or display abbreviations.
*
- * PUBLIC: int ex_abbr __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_abbr(SCR *, EXCMD *);
*/
int
ex_abbr(SCR *sp, EXCMD *cmdp)
@@ -95,7 +95,7 @@ ex_abbr(SCR *sp, EXCMD *cmdp)
* ex_unabbr -- :unabbreviate key
* Delete an abbreviation.
*
- * PUBLIC: int ex_unabbr __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_unabbr(SCR *, EXCMD *);
*/
int
ex_unabbr(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_append.c b/contrib/nvi/ex/ex_append.c
index de224f8..d2d44e2 100644
--- a/contrib/nvi/ex/ex_append.c
+++ b/contrib/nvi/ex/ex_append.c
@@ -27,14 +27,14 @@ static const char sccsid[] = "$Id: ex_append.c,v 10.34 2001/06/25 15:19:14 skimo
enum which {APPEND, CHANGE, INSERT};
-static int ex_aci __P((SCR *, EXCMD *, enum which));
+static int ex_aci(SCR *, EXCMD *, enum which);
/*
* ex_append -- :[line] a[ppend][!]
* Append one or more lines of new text after the specified line,
* or the current line if no address is specified.
*
- * PUBLIC: int ex_append __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_append(SCR *, EXCMD *);
*/
int
ex_append(SCR *sp, EXCMD *cmdp)
@@ -46,7 +46,7 @@ ex_append(SCR *sp, EXCMD *cmdp)
* ex_change -- :[line[,line]] c[hange][!] [count]
* Change one or more lines to the input text.
*
- * PUBLIC: int ex_change __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_change(SCR *, EXCMD *);
*/
int
ex_change(SCR *sp, EXCMD *cmdp)
@@ -59,7 +59,7 @@ ex_change(SCR *sp, EXCMD *cmdp)
* Insert one or more lines of new text before the specified line,
* or the current line if no address is specified.
*
- * PUBLIC: int ex_insert __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_insert(SCR *, EXCMD *);
*/
int
ex_insert(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_args.c b/contrib/nvi/ex/ex_args.c
index 2105d2d..37dfa88 100644
--- a/contrib/nvi/ex/ex_args.c
+++ b/contrib/nvi/ex/ex_args.c
@@ -27,7 +27,7 @@ static const char sccsid[] = "$Id: ex_args.c,v 10.19 2011/12/16 16:18:10 zy Exp
#include "../common/common.h"
#include "../vi/vi.h"
-static int ex_N_next __P((SCR *, EXCMD *));
+static int ex_N_next(SCR *, EXCMD *);
/*
* ex_next -- :next [+cmd] [files]
@@ -39,7 +39,7 @@ static int ex_N_next __P((SCR *, EXCMD *));
* idea was that it ignored the force flag if the autowrite flag was
* set. This implementation handles them all identically.
*
- * PUBLIC: int ex_next __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_next(SCR *, EXCMD *);
*/
int
ex_next(SCR *sp, EXCMD *cmdp)
@@ -171,7 +171,7 @@ ex_N_next(SCR *sp, EXCMD *cmdp)
* ex_prev -- :prev
* Edit the previous file.
*
- * PUBLIC: int ex_prev __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_prev(SCR *, EXCMD *);
*/
int
ex_prev(SCR *sp, EXCMD *cmdp)
@@ -220,7 +220,7 @@ ex_prev(SCR *sp, EXCMD *cmdp)
* anyone noticing, but if they do, we'll have to put information into the SCR
* structure so we can keep track of it.
*
- * PUBLIC: int ex_rew __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_rew(SCR *, EXCMD *);
*/
int
ex_rew(SCR *sp, EXCMD *cmdp)
@@ -258,7 +258,7 @@ ex_rew(SCR *sp, EXCMD *cmdp)
* ex_args -- :args
* Display the list of files.
*
- * PUBLIC: int ex_args __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_args(SCR *, EXCMD *);
*/
int
ex_args(SCR *sp, EXCMD *cmdp)
@@ -299,7 +299,7 @@ ex_args(SCR *sp, EXCMD *cmdp)
* ex_buildargv --
* Build a new file argument list.
*
- * PUBLIC: char **ex_buildargv __P((SCR *, EXCMD *, char *));
+ * PUBLIC: char **ex_buildargv(SCR *, EXCMD *, char *);
*/
char **
ex_buildargv(SCR *sp, EXCMD *cmdp, char *name)
diff --git a/contrib/nvi/ex/ex_argv.c b/contrib/nvi/ex/ex_argv.c
index b3e3edf..2d121cb 100644
--- a/contrib/nvi/ex/ex_argv.c
+++ b/contrib/nvi/ex/ex_argv.c
@@ -30,18 +30,18 @@ static const char sccsid[] = "$Id: ex_argv.c,v 11.2 2012/10/09 23:00:29 zy Exp $
#include "../common/common.h"
-static int argv_alloc __P((SCR *, size_t));
-static int argv_comp __P((const void *, const void *));
-static int argv_fexp __P((SCR *, EXCMD *,
- CHAR_T *, size_t, CHAR_T *, size_t *, CHAR_T **, size_t *, int));
-static int argv_sexp __P((SCR *, CHAR_T **, size_t *, size_t *));
-static int argv_flt_user __P((SCR *, EXCMD *, CHAR_T *, size_t));
+static int argv_alloc(SCR *, size_t);
+static int argv_comp(const void *, const void *);
+static int argv_fexp(SCR *, EXCMD *,
+ CHAR_T *, size_t, CHAR_T *, size_t *, CHAR_T **, size_t *, int);
+static int argv_sexp(SCR *, CHAR_T **, size_t *, size_t *);
+static int argv_flt_user(SCR *, EXCMD *, CHAR_T *, size_t);
/*
* argv_init --
* Build a prototype arguments list.
*
- * PUBLIC: int argv_init __P((SCR *, EXCMD *));
+ * PUBLIC: int argv_init(SCR *, EXCMD *);
*/
int
argv_init(SCR *sp, EXCMD *excp)
@@ -61,7 +61,7 @@ argv_init(SCR *sp, EXCMD *excp)
* argv_exp0 --
* Append a string to the argument list.
*
- * PUBLIC: int argv_exp0 __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ * PUBLIC: int argv_exp0(SCR *, EXCMD *, CHAR_T *, size_t);
*/
int
argv_exp0(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
@@ -84,7 +84,7 @@ argv_exp0(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
* Do file name expansion on a string, and append it to the
* argument list.
*
- * PUBLIC: int argv_exp1 __P((SCR *, EXCMD *, CHAR_T *, size_t, int));
+ * PUBLIC: int argv_exp1(SCR *, EXCMD *, CHAR_T *, size_t, int);
*/
int
argv_exp1(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen, int is_bang)
@@ -123,7 +123,7 @@ ret: FREE_SPACEW(sp, bp, blen);
* Do file name and shell expansion on a string, and append it to
* the argument list.
*
- * PUBLIC: int argv_exp2 __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ * PUBLIC: int argv_exp2(SCR *, EXCMD *, CHAR_T *, size_t);
*/
int
argv_exp2(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
@@ -209,7 +209,7 @@ err: FREE_SPACEW(sp, bp, blen);
* Take a string and break it up into an argv, which is appended
* to the argument list.
*
- * PUBLIC: int argv_exp3 __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ * PUBLIC: int argv_exp3(SCR *, EXCMD *, CHAR_T *, size_t);
*/
int
argv_exp3(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
@@ -277,7 +277,7 @@ argv_exp3(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
* Filter the ex commands with a prefix, and append the results to
* the argument list.
*
- * PUBLIC: int argv_flt_ex __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ * PUBLIC: int argv_flt_ex(SCR *, EXCMD *, CHAR_T *, size_t);
*/
int
argv_flt_ex(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
@@ -520,7 +520,7 @@ mem: msgq(sp, M_SYSERR, NULL);
* argv_free --
* Free up argument structures.
*
- * PUBLIC: int argv_free __P((SCR *));
+ * PUBLIC: int argv_free(SCR *);
*/
int
argv_free(SCR *sp)
@@ -550,7 +550,7 @@ argv_free(SCR *sp)
* Find all file names matching the prefix and append them to the
* argument list.
*
- * PUBLIC: int argv_flt_path __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ * PUBLIC: int argv_flt_path(SCR *, EXCMD *, CHAR_T *, size_t);
*/
int
argv_flt_path(SCR *sp, EXCMD *excp, CHAR_T *path, size_t plen)
@@ -812,7 +812,7 @@ alloc_err: rval = SEXP_ERR;
* argv_esc --
* Escape a string into an ex and shell argument.
*
- * PUBLIC: CHAR_T *argv_esc __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ * PUBLIC: CHAR_T *argv_esc(SCR *, EXCMD *, CHAR_T *, size_t);
*/
CHAR_T *
argv_esc(SCR *sp, EXCMD *excp, CHAR_T *str, size_t len)
@@ -875,7 +875,7 @@ alloc_err:
* argv_uesc --
* Unescape an escaped ex and shell argument.
*
- * PUBLIC: CHAR_T *argv_uesc __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ * PUBLIC: CHAR_T *argv_uesc(SCR *, EXCMD *, CHAR_T *, size_t);
*/
CHAR_T *
argv_uesc(SCR *sp, EXCMD *excp, CHAR_T *str, size_t len)
diff --git a/contrib/nvi/ex/ex_at.c b/contrib/nvi/ex/ex_at.c
index 0c12e6c..875423f 100644
--- a/contrib/nvi/ex/ex_at.c
+++ b/contrib/nvi/ex/ex_at.c
@@ -32,7 +32,7 @@ static const char sccsid[] = "$Id: ex_at.c,v 10.16 2001/06/25 15:19:14 skimo Exp
*
* Execute the contents of the buffer.
*
- * PUBLIC: int ex_at __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_at(SCR *, EXCMD *);
*/
int
ex_at(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_bang.c b/contrib/nvi/ex/ex_bang.c
index 4b6f75e..9b7c376 100644
--- a/contrib/nvi/ex/ex_bang.c
+++ b/contrib/nvi/ex/ex_bang.c
@@ -44,7 +44,7 @@ static const char sccsid[] = "$Id: ex_bang.c,v 10.36 2001/06/25 15:19:14 skimo E
* ways of getting here display the right things. It took a long time to
* get it right (wrong?), so be careful.
*
- * PUBLIC: int ex_bang __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_bang(SCR *, EXCMD *);
*/
int
ex_bang(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_cd.c b/contrib/nvi/ex/ex_cd.c
index 30a596f..4b32166 100644
--- a/contrib/nvi/ex/ex_cd.c
+++ b/contrib/nvi/ex/ex_cd.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: ex_cd.c,v 10.13 2012/04/12 06:28:27 zy Exp $"
* ex_cd -- :cd[!] [directory]
* Change directories.
*
- * PUBLIC: int ex_cd __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_cd(SCR *, EXCMD *);
*/
int
ex_cd(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_cscope.c b/contrib/nvi/ex/ex_cscope.c
index afc7fa9..0503fb3 100644
--- a/contrib/nvi/ex/ex_cscope.c
+++ b/contrib/nvi/ex/ex_cscope.c
@@ -61,15 +61,15 @@ find c|d|e|f|g|i|s|t buffer|pattern\n\
s: find all uses of name\n\
t: find assignments to name"
-static int cscope_add __P((SCR *, EXCMD *, CHAR_T *));
-static int cscope_find __P((SCR *, EXCMD*, CHAR_T *));
-static int cscope_help __P((SCR *, EXCMD *, CHAR_T *));
-static int cscope_kill __P((SCR *, EXCMD *, CHAR_T *));
-static int cscope_reset __P((SCR *, EXCMD *, CHAR_T *));
+static int cscope_add(SCR *, EXCMD *, CHAR_T *);
+static int cscope_find(SCR *, EXCMD*, CHAR_T *);
+static int cscope_help(SCR *, EXCMD *, CHAR_T *);
+static int cscope_kill(SCR *, EXCMD *, CHAR_T *);
+static int cscope_reset(SCR *, EXCMD *, CHAR_T *);
typedef struct _cc {
char *name;
- int (*function) __P((SCR *, EXCMD *, CHAR_T *));
+ int (*function)(SCR *, EXCMD *, CHAR_T *);
char *help_msg;
char *usage_msg;
} CC;
@@ -88,23 +88,23 @@ static CC const cscope_cmds[] = {
{ NULL }
};
-static TAGQ *create_cs_cmd __P((SCR *, char *, size_t *));
-static int csc_help __P((SCR *, char *));
-static void csc_file __P((SCR *,
- CSC *, char *, char **, size_t *, int *));
-static int get_paths __P((SCR *, CSC *));
-static CC const *lookup_ccmd __P((char *));
-static int parse __P((SCR *, CSC *, TAGQ *, int *));
-static int read_prompt __P((SCR *, CSC *));
-static int run_cscope __P((SCR *, CSC *, char *));
-static int start_cscopes __P((SCR *, EXCMD *));
-static int terminate __P((SCR *, CSC *, int));
+static TAGQ *create_cs_cmd(SCR *, char *, size_t *);
+static int csc_help(SCR *, char *);
+static void csc_file(SCR *,
+ CSC *, char *, char **, size_t *, int *);
+static int get_paths(SCR *, CSC *);
+static CC const *lookup_ccmd(char *);
+static int parse(SCR *, CSC *, TAGQ *, int *);
+static int read_prompt(SCR *, CSC *);
+static int run_cscope(SCR *, CSC *, char *);
+static int start_cscopes(SCR *, EXCMD *);
+static int terminate(SCR *, CSC *, int);
/*
* ex_cscope --
* Perform an ex cscope.
*
- * PUBLIC: int ex_cscope __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_cscope(SCR *, EXCMD *);
*/
int
ex_cscope(SCR *sp, EXCMD *cmdp)
@@ -861,7 +861,7 @@ csc_help(SCR *sp, char *cmd)
return (1);
} else {
ex_printf(sp,
- "Command: %s (%s)\n", ccp->name, ccp->help_msg);
+ "Command: %s (%s)\n", ccp->name, ccp->help_msg);
ex_printf(sp, " Usage: %s\n", ccp->usage_msg);
return (0);
}
@@ -965,7 +965,7 @@ cscope_reset(SCR *sp, EXCMD *cmdp, CHAR_T *notusedp)
* cscope_end --
* End all cscope connections.
*
- * PUBLIC: int cscope_end __P((SCR *));
+ * PUBLIC: int cscope_end(SCR *);
*/
int
cscope_end(SCR *sp)
@@ -982,7 +982,7 @@ cscope_end(SCR *sp)
* cscope_display --
* Display current connections.
*
- * PUBLIC: int cscope_display __P((SCR *));
+ * PUBLIC: int cscope_display(SCR *);
*/
int
cscope_display(SCR *sp)
@@ -1006,7 +1006,7 @@ cscope_display(SCR *sp)
* cscope_search --
* Search a file for a cscope entry.
*
- * PUBLIC: int cscope_search __P((SCR *, TAGQ *, TAG *));
+ * PUBLIC: int cscope_search(SCR *, TAGQ *, TAG *);
*/
int
cscope_search(SCR *sp, TAGQ *tqp, TAG *tp)
diff --git a/contrib/nvi/ex/ex_delete.c b/contrib/nvi/ex/ex_delete.c
index 34bbee4..e599489 100644
--- a/contrib/nvi/ex/ex_delete.c
+++ b/contrib/nvi/ex/ex_delete.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: ex_delete.c,v 10.11 2001/06/25 15:19:15 skimo
*
* Delete lines from the file.
*
- * PUBLIC: int ex_delete __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_delete(SCR *, EXCMD *);
*/
int
ex_delete(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_display.c b/contrib/nvi/ex/ex_display.c
index 6142a44..0ace60b 100644
--- a/contrib/nvi/ex/ex_display.c
+++ b/contrib/nvi/ex/ex_display.c
@@ -26,16 +26,16 @@ static const char sccsid[] = "$Id: ex_display.c,v 10.15 2001/06/25 15:19:15 skim
#include "../common/common.h"
#include "tag.h"
-static int is_prefix __P((ARGS *, CHAR_T *));
-static int bdisplay __P((SCR *));
-static void db __P((SCR *, CB *, const char *));
+static int is_prefix(ARGS *, CHAR_T *);
+static int bdisplay(SCR *);
+static void db(SCR *, CB *, const char *);
/*
* ex_display -- :display b[uffers] | c[onnections] | s[creens] | t[ags]
*
* Display cscope connections, buffers, tags or screens.
*
- * PUBLIC: int ex_display __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_display(SCR *, EXCMD *);
*/
int
ex_display(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_edit.c b/contrib/nvi/ex/ex_edit.c
index ce0f9a4..f9f77e8 100644
--- a/contrib/nvi/ex/ex_edit.c
+++ b/contrib/nvi/ex/ex_edit.c
@@ -27,7 +27,7 @@ static const char sccsid[] = "$Id: ex_edit.c,v 10.15 2011/12/22 23:26:50 zy Exp
#include "../common/common.h"
#include "../vi/vi.h"
-static int ex_N_edit __P((SCR *, EXCMD *, FREF *, int));
+static int ex_N_edit(SCR *, EXCMD *, FREF *, int);
/*
* ex_edit -- :e[dit][!] [+cmd] [file]
@@ -43,7 +43,7 @@ static int ex_N_edit __P((SCR *, EXCMD *, FREF *, int));
* a file name as well. This seems unreasonable, so we support it
* regardless.
*
- * PUBLIC: int ex_edit __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_edit(SCR *, EXCMD *);
*/
int
ex_edit(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_equal.c b/contrib/nvi/ex/ex_equal.c
index 7da5a20..a6745ce 100644
--- a/contrib/nvi/ex/ex_equal.c
+++ b/contrib/nvi/ex/ex_equal.c
@@ -26,7 +26,7 @@ static const char sccsid[] = "$Id: ex_equal.c,v 10.12 2001/06/25 15:19:15 skimo
/*
* ex_equal -- :address =
*
- * PUBLIC: int ex_equal __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_equal(SCR *, EXCMD *);
*/
int
ex_equal(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_file.c b/contrib/nvi/ex/ex_file.c
index 12714a3..fdef211 100644
--- a/contrib/nvi/ex/ex_file.c
+++ b/contrib/nvi/ex/ex_file.c
@@ -30,7 +30,7 @@ static const char sccsid[] = "$Id: ex_file.c,v 10.14 2001/06/25 15:19:16 skimo E
* ex_file -- :f[ile] [name]
* Change the file's name and display the status line.
*
- * PUBLIC: int ex_file __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_file(SCR *, EXCMD *);
*/
int
ex_file(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_filter.c b/contrib/nvi/ex/ex_filter.c
index 9af9a7c..cff55bf 100644
--- a/contrib/nvi/ex/ex_filter.c
+++ b/contrib/nvi/ex/ex_filter.c
@@ -27,7 +27,7 @@ static const char sccsid[] = "$Id: ex_filter.c,v 10.44 2003/11/05 17:11:54 skimo
#include "../common/common.h"
-static int filter_ldisplay __P((SCR *, FILE *));
+static int filter_ldisplay(SCR *, FILE *);
/*
* ex_filter --
@@ -35,8 +35,8 @@ static int filter_ldisplay __P((SCR *, FILE *));
* replace the original text with the stdout/stderr output of
* the utility.
*
- * PUBLIC: int ex_filter __P((SCR *,
- * PUBLIC: EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype));
+ * PUBLIC: int ex_filter(SCR *,
+ * PUBLIC: EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype);
*/
int
ex_filter(SCR *sp, EXCMD *cmdp, MARK *fm, MARK *tm, MARK *rp, CHAR_T *cmd, enum filtertype ftype)
diff --git a/contrib/nvi/ex/ex_global.c b/contrib/nvi/ex/ex_global.c
index 5dbbb07..4482ccd 100644
--- a/contrib/nvi/ex/ex_global.c
+++ b/contrib/nvi/ex/ex_global.c
@@ -30,13 +30,13 @@ static const char sccsid[] = "$Id: ex_global.c,v 10.32 2011/12/26 23:37:01 zy Ex
enum which {GLOBAL, V};
-static int ex_g_setup __P((SCR *, EXCMD *, enum which));
+static int ex_g_setup(SCR *, EXCMD *, enum which);
/*
* ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands]
* Exec on lines matching a pattern.
*
- * PUBLIC: int ex_global __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_global(SCR *, EXCMD *);
*/
int
ex_global(SCR *sp, EXCMD *cmdp)
@@ -49,7 +49,7 @@ ex_global(SCR *sp, EXCMD *cmdp)
* ex_v -- [line [,line]] v /pattern/ [commands]
* Exec on lines not matching a pattern.
*
- * PUBLIC: int ex_v __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_v(SCR *, EXCMD *);
*/
int
ex_v(SCR *sp, EXCMD *cmdp)
@@ -248,7 +248,7 @@ usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
* ex_g_insdel --
* Update the ranges based on an insertion or deletion.
*
- * PUBLIC: int ex_g_insdel __P((SCR *, lnop_t, recno_t));
+ * PUBLIC: int ex_g_insdel(SCR *, lnop_t, recno_t);
*/
int
ex_g_insdel(SCR *sp, lnop_t op, recno_t lno)
diff --git a/contrib/nvi/ex/ex_init.c b/contrib/nvi/ex/ex_init.c
index 5b93e5b..ad54591 100644
--- a/contrib/nvi/ex/ex_init.c
+++ b/contrib/nvi/ex/ex_init.c
@@ -30,15 +30,15 @@ static const char sccsid[] = "$Id: ex_init.c,v 10.33 2012/04/11 19:12:34 zy Exp
#include "pathnames.h"
enum rc { NOEXIST, NOPERM, RCOK };
-static enum rc exrc_isok __P((SCR *, struct stat *, char *, int, int));
+static enum rc exrc_isok(SCR *, struct stat *, char *, int, int);
-static int ex_run_file __P((SCR *, char *));
+static int ex_run_file(SCR *, char *);
/*
* ex_screen_copy --
* Copy ex screen.
*
- * PUBLIC: int ex_screen_copy __P((SCR *, SCR *));
+ * PUBLIC: int ex_screen_copy(SCR *, SCR *);
*/
int
ex_screen_copy(SCR *orig, SCR *sp)
@@ -74,7 +74,7 @@ ex_screen_copy(SCR *orig, SCR *sp)
* ex_screen_end --
* End a vi screen.
*
- * PUBLIC: int ex_screen_end __P((SCR *));
+ * PUBLIC: int ex_screen_end(SCR *);
*/
int
ex_screen_end(SCR *sp)
@@ -120,7 +120,7 @@ ex_screen_end(SCR *sp)
* ex_optchange --
* Handle change of options for ex.
*
- * PUBLIC: int ex_optchange __P((SCR *, int, char *, u_long *));
+ * PUBLIC: int ex_optchange(SCR *, int, char *, u_long *);
*/
int
ex_optchange(SCR *sp, int offset, char *str, u_long *valp)
@@ -137,7 +137,7 @@ ex_optchange(SCR *sp, int offset, char *str, u_long *valp)
* Read the EXINIT environment variable and the startup exrc files,
* and execute their commands.
*
- * PUBLIC: int ex_exrc __P((SCR *));
+ * PUBLIC: int ex_exrc(SCR *);
*/
int
ex_exrc(SCR *sp)
@@ -281,7 +281,7 @@ ex_run_file(SCR *sp, char *name)
* ex_run_str --
* Set up a string of ex commands to run.
*
- * PUBLIC: int ex_run_str __P((SCR *, char *, CHAR_T *, size_t, int, int));
+ * PUBLIC: int ex_run_str(SCR *, char *, CHAR_T *, size_t, int, int);
*/
int
ex_run_str(SCR *sp, char *name, CHAR_T *str, size_t len, int ex_flags, int nocopy)
diff --git a/contrib/nvi/ex/ex_join.c b/contrib/nvi/ex/ex_join.c
index 822ed79..2917b2e 100644
--- a/contrib/nvi/ex/ex_join.c
+++ b/contrib/nvi/ex/ex_join.c
@@ -30,7 +30,7 @@ static const char sccsid[] = "$Id: ex_join.c,v 10.17 2004/03/16 14:14:04 skimo E
* ex_join -- :[line [,line]] j[oin][!] [count] [flags]
* Join lines.
*
- * PUBLIC: int ex_join __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_join(SCR *, EXCMD *);
*/
int
ex_join(SCR *sp, EXCMD *cmdp)
@@ -62,7 +62,7 @@ ex_join(SCR *sp, EXCMD *cmdp)
++cmdp->addr2.lno;
clen = tlen = 0;
- for (first = 1,
+ for (first = 1,
from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
/*
* Get next line. Historic versions of vi allowed "10J" while
@@ -154,7 +154,7 @@ ex_join(SCR *sp, EXCMD *cmdp)
sp->lno = cmdp->addr1.lno;
/* Delete the joined lines. */
- for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to)
+ for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to)
if (db_delete(sp, to))
goto err;
diff --git a/contrib/nvi/ex/ex_map.c b/contrib/nvi/ex/ex_map.c
index 60dbfe0..932d633 100644
--- a/contrib/nvi/ex/ex_map.c
+++ b/contrib/nvi/ex/ex_map.c
@@ -40,7 +40,7 @@ static const char sccsid[] = "$Id: ex_map.c,v 10.11 2001/06/25 15:19:17 skimo Ex
* put the map in a .exrc file, things would often work much better.
* No clue why.
*
- * PUBLIC: int ex_map __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_map(SCR *, EXCMD *);
*/
int
ex_map(SCR *sp, EXCMD *cmdp)
@@ -103,7 +103,7 @@ nofunc: if (stype == SEQ_COMMAND && input[1] == '\0')
* ex_unmap -- (:unmap[!] key)
* Unmap a key.
*
- * PUBLIC: int ex_unmap __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_unmap(SCR *, EXCMD *);
*/
int
ex_unmap(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_mark.c b/contrib/nvi/ex/ex_mark.c
index 8c8ec34..e259837 100644
--- a/contrib/nvi/ex/ex_mark.c
+++ b/contrib/nvi/ex/ex_mark.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: ex_mark.c,v 10.9 2001/06/25 15:19:17 skimo Ex
* Mark lines.
*
*
- * PUBLIC: int ex_mark __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_mark(SCR *, EXCMD *);
*/
int
ex_mark(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_mkexrc.c b/contrib/nvi/ex/ex_mkexrc.c
index 8753014..82678b1 100644
--- a/contrib/nvi/ex/ex_mkexrc.c
+++ b/contrib/nvi/ex/ex_mkexrc.c
@@ -34,7 +34,7 @@ static const char sccsid[] = "$Id: ex_mkexrc.c,v 10.13 2001/06/25 15:19:17 skimo
*
* Create (or overwrite) a .exrc file with the current info.
*
- * PUBLIC: int ex_mkexrc __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_mkexrc(SCR *, EXCMD *);
*/
int
ex_mkexrc(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_move.c b/contrib/nvi/ex/ex_move.c
index c2499fd..a7f6b5f 100644
--- a/contrib/nvi/ex/ex_move.c
+++ b/contrib/nvi/ex/ex_move.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: ex_move.c,v 10.16 2012/02/11 15:52:33 zy Exp
* ex_copy -- :[line [,line]] co[py] line [flags]
* Copy selected lines.
*
- * PUBLIC: int ex_copy __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_copy(SCR *, EXCMD *);
*/
int
ex_copy(SCR *sp, EXCMD *cmdp)
@@ -81,7 +81,7 @@ err: text_lfree(cb.textq);
* ex_move -- :[line [,line]] mo[ve] line
* Move selected lines.
*
- * PUBLIC: int ex_move __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_move(SCR *, EXCMD *);
*/
int
ex_move(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_open.c b/contrib/nvi/ex/ex_open.c
index 97414b9..ca54eca 100644
--- a/contrib/nvi/ex/ex_open.c
+++ b/contrib/nvi/ex/ex_open.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: ex_open.c,v 10.8 2001/06/25 15:19:17 skimo Ex
*
* Switch to single line "open" mode.
*
- * PUBLIC: int ex_open __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_open(SCR *, EXCMD *);
*/
int
ex_open(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_preserve.c b/contrib/nvi/ex/ex_preserve.c
index bda4bb4..e0dc286 100644
--- a/contrib/nvi/ex/ex_preserve.c
+++ b/contrib/nvi/ex/ex_preserve.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: ex_preserve.c,v 10.15 2001/06/25 15:19:18 ski
* ex_preserve -- :pre[serve]
* Push the file to recovery.
*
- * PUBLIC: int ex_preserve __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_preserve(SCR *, EXCMD *);
*/
int
ex_preserve(SCR *sp, EXCMD *cmdp)
@@ -63,7 +63,7 @@ ex_preserve(SCR *sp, EXCMD *cmdp)
* ex_recover -- :rec[over][!] file
* Recover the file.
*
- * PUBLIC: int ex_recover __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_recover(SCR *, EXCMD *);
*/
int
ex_recover(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_print.c b/contrib/nvi/ex/ex_print.c
index 5903e97..7cdde7a 100644
--- a/contrib/nvi/ex/ex_print.c
+++ b/contrib/nvi/ex/ex_print.c
@@ -26,15 +26,15 @@ static const char sccsid[] = "$Id: ex_print.c,v 10.26 2013/11/02 02:11:07 zy Exp
#include "../common/common.h"
-static int ex_prchars __P((SCR *, const CHAR_T *, size_t *, size_t,
- u_int, int));
+static int ex_prchars(SCR *,
+ const CHAR_T *, size_t *, size_t, u_int, int);
/*
* ex_list -- :[line [,line]] l[ist] [count] [flags]
*
* Display the addressed lines such that the output is unambiguous.
*
- * PUBLIC: int ex_list __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_list(SCR *, EXCMD *);
*/
int
ex_list(SCR *sp, EXCMD *cmdp)
@@ -52,7 +52,7 @@ ex_list(SCR *sp, EXCMD *cmdp)
*
* Display the addressed lines with a leading line number.
*
- * PUBLIC: int ex_number __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_number(SCR *, EXCMD *);
*/
int
ex_number(SCR *sp, EXCMD *cmdp)
@@ -70,7 +70,7 @@ ex_number(SCR *sp, EXCMD *cmdp)
*
* Display the addressed lines.
*
- * PUBLIC: int ex_pr __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_pr(SCR *, EXCMD *);
*/
int
ex_pr(SCR *sp, EXCMD *cmdp)
@@ -86,7 +86,7 @@ ex_pr(SCR *sp, EXCMD *cmdp)
* ex_print --
* Print the selected lines.
*
- * PUBLIC: int ex_print __P((SCR *, EXCMD *, MARK *, MARK *, u_int32_t));
+ * PUBLIC: int ex_print(SCR *, EXCMD *, MARK *, MARK *, u_int32_t);
*/
int
ex_print(SCR *sp, EXCMD *cmdp, MARK *fp, MARK *tp, u_int32_t flags)
@@ -141,7 +141,7 @@ ex_print(SCR *sp, EXCMD *cmdp, MARK *fp, MARK *tp, u_int32_t flags)
* ex_ldisplay --
* Display a line without any preceding number.
*
- * PUBLIC: int ex_ldisplay __P((SCR *, const CHAR_T *, size_t, size_t, u_int));
+ * PUBLIC: int ex_ldisplay(SCR *, const CHAR_T *, size_t, size_t, u_int);
*/
int
ex_ldisplay(SCR *sp, const CHAR_T *p, size_t len, size_t col, u_int flags)
@@ -162,7 +162,7 @@ ex_ldisplay(SCR *sp, const CHAR_T *p, size_t len, size_t col, u_int flags)
* ex_scprint --
* Display a line for the substitute with confirmation routine.
*
- * PUBLIC: int ex_scprint __P((SCR *, MARK *, MARK *));
+ * PUBLIC: int ex_scprint(SCR *, MARK *, MARK *);
*/
int
ex_scprint(SCR *sp, MARK *fp, MARK *tp)
@@ -258,7 +258,7 @@ intr: *colp = col;
* ex_printf --
* Ex's version of printf.
*
- * PUBLIC: int ex_printf __P((SCR *, const char *, ...));
+ * PUBLIC: int ex_printf(SCR *, const char *, ...);
*/
int
ex_printf(
@@ -288,7 +288,7 @@ ex_printf(
* ex_puts --
* Ex's version of puts.
*
- * PUBLIC: int ex_puts __P((SCR *, const char *));
+ * PUBLIC: int ex_puts(SCR *, const char *);
*/
int
ex_puts(SCR *sp, const char *str)
@@ -314,7 +314,7 @@ ex_puts(SCR *sp, const char *str)
* ex_fflush --
* Ex's version of fflush.
*
- * PUBLIC: int ex_fflush __P((SCR *sp));
+ * PUBLIC: int ex_fflush(SCR *sp);
*/
int
ex_fflush(SCR *sp)
diff --git a/contrib/nvi/ex/ex_put.c b/contrib/nvi/ex/ex_put.c
index 7a3996b..384b500 100644
--- a/contrib/nvi/ex/ex_put.c
+++ b/contrib/nvi/ex/ex_put.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: ex_put.c,v 10.8 2001/06/25 15:19:18 skimo Exp
* ex_put -- [line] pu[t] [buffer]
* Append a cut buffer into the file.
*
- * PUBLIC: int ex_put __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_put(SCR *, EXCMD *);
*/
int
ex_put(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_quit.c b/contrib/nvi/ex/ex_quit.c
index 2cfaeb1..faf31d7 100644
--- a/contrib/nvi/ex/ex_quit.c
+++ b/contrib/nvi/ex/ex_quit.c
@@ -27,7 +27,7 @@ static const char sccsid[] = "$Id: ex_quit.c,v 10.8 2001/06/25 15:19:18 skimo Ex
* ex_quit -- :quit[!]
* Quit.
*
- * PUBLIC: int ex_quit __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_quit(SCR *, EXCMD *);
*/
int
ex_quit(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_read.c b/contrib/nvi/ex/ex_read.c
index 187f090..00276a2 100644
--- a/contrib/nvi/ex/ex_read.c
+++ b/contrib/nvi/ex/ex_read.c
@@ -36,7 +36,7 @@ static const char sccsid[] = "$Id: ex_read.c,v 10.44 2001/06/25 15:19:19 skimo E
* !!!
* Historical vi wouldn't undo a filter read, for no apparent reason.
*
- * PUBLIC: int ex_read __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_read(SCR *, EXCMD *);
*/
int
ex_read(SCR *sp, EXCMD *cmdp)
@@ -291,7 +291,7 @@ ex_read(SCR *sp, EXCMD *cmdp)
* ex_readfp --
* Read lines into the file.
*
- * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
+ * PUBLIC: int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int);
*/
int
ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp, int silent)
diff --git a/contrib/nvi/ex/ex_screen.c b/contrib/nvi/ex/ex_screen.c
index 9cb108f9..7bec2bc 100644
--- a/contrib/nvi/ex/ex_screen.c
+++ b/contrib/nvi/ex/ex_screen.c
@@ -30,7 +30,7 @@ static const char sccsid[] = "$Id: ex_screen.c,v 10.12 2001/06/25 15:19:19 skimo
* ex_bg -- :bg
* Hide the screen.
*
- * PUBLIC: int ex_bg __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_bg(SCR *, EXCMD *);
*/
int
ex_bg(SCR *sp, EXCMD *cmdp)
@@ -42,7 +42,7 @@ ex_bg(SCR *sp, EXCMD *cmdp)
* ex_fg -- :fg [file]
* Show the screen.
*
- * PUBLIC: int ex_fg __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_fg(SCR *, EXCMD *);
*/
int
ex_fg(SCR *sp, EXCMD *cmdp)
@@ -66,7 +66,7 @@ ex_fg(SCR *sp, EXCMD *cmdp)
* ex_resize -- :resize [+-]rows
* Change the screen size.
*
- * PUBLIC: int ex_resize __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_resize(SCR *, EXCMD *);
*/
int
ex_resize(SCR *sp, EXCMD *cmdp)
@@ -95,7 +95,7 @@ ex_resize(SCR *sp, EXCMD *cmdp)
* ex_sdisplay --
* Display the list of screens.
*
- * PUBLIC: int ex_sdisplay __P((SCR *));
+ * PUBLIC: int ex_sdisplay(SCR *);
*/
int
ex_sdisplay(SCR *sp)
diff --git a/contrib/nvi/ex/ex_script.c b/contrib/nvi/ex/ex_script.c
index 5ba0acf..2dc4465 100644
--- a/contrib/nvi/ex/ex_script.c
+++ b/contrib/nvi/ex/ex_script.c
@@ -45,18 +45,18 @@ static const char sccsid[] = "$Id: ex_script.c,v 10.44 2012/10/05 10:17:47 zy Ex
#include "script.h"
#include "pathnames.h"
-static void sscr_check __P((SCR *));
-static int sscr_getprompt __P((SCR *));
-static int sscr_init __P((SCR *));
-static int sscr_insert __P((SCR *));
-static int sscr_matchprompt __P((SCR *, char *, size_t, size_t *));
-static int sscr_setprompt __P((SCR *, char *, size_t));
+static void sscr_check(SCR *);
+static int sscr_getprompt(SCR *);
+static int sscr_init(SCR *);
+static int sscr_insert(SCR *);
+static int sscr_matchprompt(SCR *, char *, size_t, size_t *);
+static int sscr_setprompt(SCR *, char *, size_t);
/*
* ex_script -- : sc[ript][!] [file]
* Switch to script mode.
*
- * PUBLIC: int ex_script __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_script(SCR *, EXCMD *);
*/
int
ex_script(SCR *sp, EXCMD *cmdp)
@@ -292,7 +292,7 @@ prompterr: sscr_end(sp);
* sscr_exec --
* Take a line and hand it off to the shell.
*
- * PUBLIC: int sscr_exec __P((SCR *, recno_t));
+ * PUBLIC: int sscr_exec(SCR *, recno_t);
*/
int
sscr_exec(SCR *sp, recno_t lno)
@@ -368,7 +368,7 @@ err1: rval = 1;
* sscr_input --
* Read any waiting shell input.
*
- * PUBLIC: int sscr_input __P((SCR *));
+ * PUBLIC: int sscr_input(SCR *);
*/
int
sscr_input(SCR *sp)
@@ -577,7 +577,7 @@ sscr_matchprompt(SCR *sp, char *lp, size_t line_len, size_t *lenp)
* sscr_end --
* End the pipe to a shell.
*
- * PUBLIC: int sscr_end __P((SCR *));
+ * PUBLIC: int sscr_end(SCR *);
*/
int
sscr_end(SCR *sp)
diff --git a/contrib/nvi/ex/ex_set.c b/contrib/nvi/ex/ex_set.c
index 5134bab..2acc3a8 100644
--- a/contrib/nvi/ex/ex_set.c
+++ b/contrib/nvi/ex/ex_set.c
@@ -27,7 +27,7 @@ static const char sccsid[] = "$Id: ex_set.c,v 10.8 2001/06/25 15:19:19 skimo Exp
* ex_set -- :set
* Ex set option.
*
- * PUBLIC: int ex_set __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_set(SCR *, EXCMD *);
*/
int
ex_set(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_shell.c b/contrib/nvi/ex/ex_shell.c
index d127305..43be5cb 100644
--- a/contrib/nvi/ex/ex_shell.c
+++ b/contrib/nvi/ex/ex_shell.c
@@ -29,14 +29,14 @@ static const char sccsid[] = "$Id: ex_shell.c,v 10.44 2012/07/06 06:51:26 zy Exp
#include "../common/common.h"
-static const char *sigmsg __P((int));
+static const char *sigmsg(int);
/*
* ex_shell -- :sh[ell]
* Invoke the program named in the SHELL environment variable
* with the argument -i.
*
- * PUBLIC: int ex_shell __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_shell(SCR *, EXCMD *);
*/
int
ex_shell(SCR *sp, EXCMD *cmdp)
@@ -82,7 +82,7 @@ ex_shell(SCR *sp, EXCMD *cmdp)
* ex_exec_proc --
* Run a separate process.
*
- * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
+ * PUBLIC: int ex_exec_proc(SCR *, EXCMD *, char *, const char *, int);
*/
int
ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, int need_newline)
@@ -147,7 +147,7 @@ ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, int need_newline)
* rules get you. I'm using a long based on the belief that nobody is
* going to make it unsigned and it's unlikely to be a quad.
*
- * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int));
+ * PUBLIC: int proc_wait(SCR *, long, const char *, int, int);
*/
int
proc_wait(SCR *sp, long int pid, const char *cmd, int silent, int okpipe)
diff --git a/contrib/nvi/ex/ex_shift.c b/contrib/nvi/ex/ex_shift.c
index cc6e1aa..fec800c 100644
--- a/contrib/nvi/ex/ex_shift.c
+++ b/contrib/nvi/ex/ex_shift.c
@@ -26,13 +26,13 @@ static const char sccsid[] = "$Id: ex_shift.c,v 10.17 2001/06/25 15:19:20 skimo
#include "../common/common.h"
enum which {LEFT, RIGHT};
-static int shift __P((SCR *, EXCMD *, enum which));
+static int shift(SCR *, EXCMD *, enum which);
/*
* ex_shiftl -- :<[<...]
*
*
- * PUBLIC: int ex_shiftl __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_shiftl(SCR *, EXCMD *);
*/
int
ex_shiftl(SCR *sp, EXCMD *cmdp)
@@ -43,7 +43,7 @@ ex_shiftl(SCR *sp, EXCMD *cmdp)
/*
* ex_shiftr -- :>[>...]
*
- * PUBLIC: int ex_shiftr __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_shiftr(SCR *, EXCMD *);
*/
int
ex_shiftr(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_source.c b/contrib/nvi/ex/ex_source.c
index 63375d2..6ac698d 100644
--- a/contrib/nvi/ex/ex_source.c
+++ b/contrib/nvi/ex/ex_source.c
@@ -32,7 +32,7 @@ static const char sccsid[] = "$Id: ex_source.c,v 10.17 2011/12/19 16:17:06 zy Ex
* ex_source -- :source file
* Execute ex commands from a file.
*
- * PUBLIC: int ex_source __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_source(SCR *, EXCMD *);
*/
int
ex_source(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_stop.c b/contrib/nvi/ex/ex_stop.c
index 7916789..4bc1bb2 100644
--- a/contrib/nvi/ex/ex_stop.c
+++ b/contrib/nvi/ex/ex_stop.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: ex_stop.c,v 10.11 2001/06/25 15:19:20 skimo E
* :suspend[!]
* Suspend execution.
*
- * PUBLIC: int ex_stop __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_stop(SCR *, EXCMD *);
*/
int
ex_stop(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_subst.c b/contrib/nvi/ex/ex_subst.c
index 9339843..db79376 100644
--- a/contrib/nvi/ex/ex_subst.c
+++ b/contrib/nvi/ex/ex_subst.c
@@ -32,12 +32,12 @@ static const char sccsid[] = "$Id: ex_subst.c,v 10.53 2011/12/21 20:40:35 zy Exp
#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */
#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */
-static int re_conv __P((SCR *, CHAR_T **, size_t *, int *));
-static int re_cscope_conv __P((SCR *, CHAR_T **, size_t *, int *));
-static int re_sub __P((SCR *,
- CHAR_T *, CHAR_T **, size_t *, size_t *, regmatch_t [10]));
-static int re_tag_conv __P((SCR *, CHAR_T **, size_t *, int *));
-static int s __P((SCR *, EXCMD *, CHAR_T *, regex_t *, u_int));
+static int re_conv(SCR *, CHAR_T **, size_t *, int *);
+static int re_cscope_conv(SCR *, CHAR_T **, size_t *, int *);
+static int re_sub(SCR *,
+ CHAR_T *, CHAR_T **, size_t *, size_t *, regmatch_t [10]);
+static int re_tag_conv(SCR *, CHAR_T **, size_t *, int *);
+static int s(SCR *, EXCMD *, CHAR_T *, regex_t *, u_int);
/*
* ex_s --
@@ -45,7 +45,7 @@ static int s __P((SCR *, EXCMD *, CHAR_T *, regex_t *, u_int));
*
* Substitute on lines matching a pattern.
*
- * PUBLIC: int ex_s __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_s(SCR *, EXCMD *);
*/
int
ex_s(SCR *sp, EXCMD *cmdp)
@@ -250,7 +250,7 @@ tilde: ++p;
*
* Substitute using the last substitute RE and replacement pattern.
*
- * PUBLIC: int ex_subagain __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_subagain(SCR *, EXCMD *);
*/
int
ex_subagain(SCR *sp, EXCMD *cmdp)
@@ -273,7 +273,7 @@ ex_subagain(SCR *sp, EXCMD *cmdp)
*
* Substitute using the last RE and last substitute replacement pattern.
*
- * PUBLIC: int ex_subtilde __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_subtilde(SCR *, EXCMD *);
*/
int
ex_subtilde(SCR *sp, EXCMD *cmdp)
@@ -879,8 +879,8 @@ err: rval = 1;
* re_compile --
* Compile the RE.
*
- * PUBLIC: int re_compile __P((SCR *,
- * PUBLIC: CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int));
+ * PUBLIC: int re_compile(SCR *,
+ * PUBLIC: CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int);
*/
int
re_compile(SCR *sp, CHAR_T *ptrn, size_t plen, CHAR_T **ptrnp, size_t *lenp, regex_t *rep, u_int flags)
@@ -1280,7 +1280,7 @@ re_cscope_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
* re_error --
* Report a regular expression error.
*
- * PUBLIC: void re_error __P((SCR *, int, regex_t *));
+ * PUBLIC: void re_error(SCR *, int, regex_t *);
*/
void
re_error(SCR *sp, int errcode, regex_t *preg)
@@ -1396,7 +1396,7 @@ re_sub(
case '5': case '6': case '7': case '8': case '9':
no = *rp++ - '0';
subzero: if (match[no].rm_so == -1 ||
- match[no].rm_eo == -1)
+ match[no].rm_eo == -1)
break;
mlen = match[no].rm_eo - match[no].rm_so;
for (t = ip + match[no].rm_so; mlen--; ++t)
diff --git a/contrib/nvi/ex/ex_tag.c b/contrib/nvi/ex/ex_tag.c
index 4ef03fb..172e5e2 100644
--- a/contrib/nvi/ex/ex_tag.c
+++ b/contrib/nvi/ex/ex_tag.c
@@ -36,24 +36,24 @@ static const char sccsid[] = "$Id: ex_tag.c,v 10.54 2012/04/12 07:17:30 zy Exp $
#include "../vi/vi.h"
#include "tag.h"
-static char *binary_search __P((char *, char *, char *));
-static int compare __P((char *, char *, char *));
-static void ctag_file __P((SCR *, TAGF *, char *, char **, size_t *));
-static int ctag_search __P((SCR *, CHAR_T *, size_t, char *));
-static int ctag_sfile __P((SCR *, TAGF *, TAGQ *, char *));
-static TAGQ *ctag_slist __P((SCR *, CHAR_T *));
-static char *linear_search __P((char *, char *, char *, long));
-static int tag_copy __P((SCR *, TAG *, TAG **));
-static int tag_pop __P((SCR *, TAGQ *, int));
-static int tagf_copy __P((SCR *, TAGF *, TAGF **));
-static int tagf_free __P((SCR *, TAGF *));
-static int tagq_copy __P((SCR *, TAGQ *, TAGQ **));
+static char *binary_search(char *, char *, char *);
+static int compare(char *, char *, char *);
+static void ctag_file(SCR *, TAGF *, char *, char **, size_t *);
+static int ctag_search(SCR *, CHAR_T *, size_t, char *);
+static int ctag_sfile(SCR *, TAGF *, TAGQ *, char *);
+static TAGQ *ctag_slist(SCR *, CHAR_T *);
+static char *linear_search(char *, char *, char *, long);
+static int tag_copy(SCR *, TAG *, TAG **);
+static int tag_pop(SCR *, TAGQ *, int);
+static int tagf_copy(SCR *, TAGF *, TAGF **);
+static int tagf_free(SCR *, TAGF *);
+static int tagq_copy(SCR *, TAGQ *, TAGQ **);
/*
* ex_tag_first --
* The tag code can be entered from main, e.g., "vi -t tag".
*
- * PUBLIC: int ex_tag_first __P((SCR *, CHAR_T *));
+ * PUBLIC: int ex_tag_first(SCR *, CHAR_T *);
*/
int
ex_tag_first(SCR *sp, CHAR_T *tagarg)
@@ -86,7 +86,7 @@ ex_tag_first(SCR *sp, CHAR_T *tagarg)
*
* Enter a new TAGQ context based on a ctag string.
*
- * PUBLIC: int ex_tag_push __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_tag_push(SCR *, EXCMD *);
*/
int
ex_tag_push(SCR *sp, EXCMD *cmdp)
@@ -137,7 +137,7 @@ ex_tag_push(SCR *sp, EXCMD *cmdp)
* ex_tag_next --
* Switch context to the next TAG.
*
- * PUBLIC: int ex_tag_next __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_tag_next(SCR *, EXCMD *);
*/
int
ex_tag_next(SCR *sp, EXCMD *cmdp)
@@ -177,7 +177,7 @@ ex_tag_next(SCR *sp, EXCMD *cmdp)
* ex_tag_prev --
* Switch context to the next TAG.
*
- * PUBLIC: int ex_tag_prev __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_tag_prev(SCR *, EXCMD *);
*/
int
ex_tag_prev(SCR *sp, EXCMD *cmdp)
@@ -217,7 +217,7 @@ ex_tag_prev(SCR *sp, EXCMD *cmdp)
* ex_tag_nswitch --
* Switch context to the specified TAG.
*
- * PUBLIC: int ex_tag_nswitch __P((SCR *, TAG *, int));
+ * PUBLIC: int ex_tag_nswitch(SCR *, TAG *, int);
*/
int
ex_tag_nswitch(SCR *sp, TAG *tp, int force)
@@ -251,7 +251,7 @@ ex_tag_nswitch(SCR *sp, TAG *tp, int force)
* ex_tag_Nswitch --
* Switch context to the specified TAG in a new screen.
*
- * PUBLIC: int ex_tag_Nswitch __P((SCR *, TAG *, int));
+ * PUBLIC: int ex_tag_Nswitch(SCR *, TAG *, int);
*/
int
ex_tag_Nswitch(SCR *sp, TAG *tp, int force)
@@ -305,7 +305,7 @@ ex_tag_Nswitch(SCR *sp, TAG *tp, int force)
*
* Pop to a previous TAGQ context.
*
- * PUBLIC: int ex_tag_pop __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_tag_pop(SCR *, EXCMD *);
*/
int
ex_tag_pop(SCR *sp, EXCMD *cmdp)
@@ -384,7 +384,7 @@ filearg: arglen = strlen(arg);
* ex_tag_top -- :tagt[op][!]
* Clear the tag stack.
*
- * PUBLIC: int ex_tag_top __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_tag_top(SCR *, EXCMD *);
*/
int
ex_tag_top(SCR *sp, EXCMD *cmdp)
@@ -459,7 +459,7 @@ tag_pop(SCR *sp, TAGQ *dtqp, int force)
* ex_tag_display --
* Display the list of tags.
*
- * PUBLIC: int ex_tag_display __P((SCR *));
+ * PUBLIC: int ex_tag_display(SCR *);
*/
int
ex_tag_display(SCR *sp)
@@ -536,7 +536,7 @@ ex_tag_display(SCR *sp)
* ex_tag_copy --
* Copy a screen's tag structures.
*
- * PUBLIC: int ex_tag_copy __P((SCR *, SCR *));
+ * PUBLIC: int ex_tag_copy(SCR *, SCR *);
*/
int
ex_tag_copy(SCR *orig, SCR *sp)
@@ -677,7 +677,7 @@ tagf_free(SCR *sp, TAGF *tfp)
* tagq_free --
* Free a TAGQ structure (and associated TAG structures).
*
- * PUBLIC: int tagq_free __P((SCR *, TAGQ *));
+ * PUBLIC: int tagq_free(SCR *, TAGQ *);
*/
int
tagq_free(SCR *sp, TAGQ *tqp)
@@ -702,7 +702,7 @@ tagq_free(SCR *sp, TAGQ *tqp)
}
/*
- * PUBLIC: int tagq_push __P((SCR*, TAGQ*, int, int ));
+ * PUBLIC: int tagq_push(SCR*, TAGQ*, int, int );
*/
int
tagq_push(SCR *sp, TAGQ *tqp, int new_screen, int force)
@@ -814,7 +814,7 @@ alloc_err:
* tag_msg
* A few common messages.
*
- * PUBLIC: void tag_msg __P((SCR *, tagmsg_t, char *));
+ * PUBLIC: void tag_msg(SCR *, tagmsg_t, char *);
*/
void
tag_msg(SCR *sp, tagmsg_t msg, char *tag)
@@ -839,7 +839,7 @@ tag_msg(SCR *sp, tagmsg_t msg, char *tag)
* ex_tagf_alloc --
* Create a new list of ctag files.
*
- * PUBLIC: int ex_tagf_alloc __P((SCR *, char *));
+ * PUBLIC: int ex_tagf_alloc(SCR *, char *);
*/
int
ex_tagf_alloc(SCR *sp, char *str)
@@ -881,7 +881,7 @@ ex_tagf_alloc(SCR *sp, char *str)
* ex_tag_free --
* Free the ex tag information.
*
- * PUBLIC: int ex_tag_free __P((SCR *));
+ * PUBLIC: int ex_tag_free(SCR *);
*/
int
ex_tag_free(SCR *sp)
@@ -1241,9 +1241,9 @@ ctag_file(SCR *sp, TAGF *tfp, char *name, char **dirp, size_t *dlenp)
while (p < back && *p++ != '\n') continue;
static char *
-binary_search(register char *string, register char *front, register char *back)
+binary_search(char *string, char *front, char *back)
{
- register char *p;
+ char *p;
p = front + (back - front) / 2;
SKIP_PAST_NEWLINE(p, back);
@@ -1304,7 +1304,7 @@ linear_search(char *string, char *front, char *back, long tl)
* However, historic programs did use spaces, and, I got complaints.
*/
static int
-compare(register char *s1, register char *s2, register char *back)
+compare(char *s1, char *s2, char *back)
{
for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2)
if (*s1 != *s2)
diff --git a/contrib/nvi/ex/ex_txt.c b/contrib/nvi/ex/ex_txt.c
index 21d9f44..4e62a7e 100644
--- a/contrib/nvi/ex/ex_txt.c
+++ b/contrib/nvi/ex/ex_txt.c
@@ -44,14 +44,14 @@ static const char sccsid[] = "$Id: ex_txt.c,v 10.23 2001/06/25 15:19:21 skimo Ex
* characters remaining when failure occurred.
*/
-static int txt_dent __P((SCR *, TEXT *));
-static void txt_prompt __P((SCR *, TEXT *, ARG_CHAR_T, u_int32_t));
+static int txt_dent(SCR *, TEXT *);
+static void txt_prompt(SCR *, TEXT *, ARG_CHAR_T, u_int32_t);
/*
* ex_txt --
* Get lines from the terminal for ex.
*
- * PUBLIC: int ex_txt __P((SCR *, TEXTH *, ARG_CHAR_T, u_int32_t));
+ * PUBLIC: int ex_txt(SCR *, TEXTH *, ARG_CHAR_T, u_int32_t);
*/
int
ex_txt(SCR *sp, TEXTH *tiqh, ARG_CHAR_T prompt, u_int32_t flags)
diff --git a/contrib/nvi/ex/ex_undo.c b/contrib/nvi/ex/ex_undo.c
index 9e4cd79..32f35fd 100644
--- a/contrib/nvi/ex/ex_undo.c
+++ b/contrib/nvi/ex/ex_undo.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: ex_undo.c,v 10.7 2001/06/25 15:19:21 skimo Ex
* ex_undo -- u
* Undo the last change.
*
- * PUBLIC: int ex_undo __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_undo(SCR *, EXCMD *);
*/
int
ex_undo(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_usage.c b/contrib/nvi/ex/ex_usage.c
index 9a20ce1..b28d8a5 100644
--- a/contrib/nvi/ex/ex_usage.c
+++ b/contrib/nvi/ex/ex_usage.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: ex_usage.c,v 10.16 2011/12/21 19:26:48 zy Exp
* ex_help -- :help
* Display help message.
*
- * PUBLIC: int ex_help __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_help(SCR *, EXCMD *);
*/
int
ex_help(SCR *sp, EXCMD *cmdp)
@@ -52,7 +52,7 @@ ex_help(SCR *sp, EXCMD *cmdp)
* ex_usage -- :exusage [cmd]
* Display ex usage strings.
*
- * PUBLIC: int ex_usage __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_usage(SCR *, EXCMD *);
*/
int
ex_usage(SCR *sp, EXCMD *cmdp)
@@ -133,7 +133,7 @@ ex_usage(SCR *sp, EXCMD *cmdp)
* ex_viusage -- :viusage [key]
* Display vi usage strings.
*
- * PUBLIC: int ex_viusage __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_viusage(SCR *, EXCMD *);
*/
int
ex_viusage(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_util.c b/contrib/nvi/ex/ex_util.c
index 2e56a06..6071fe2 100644
--- a/contrib/nvi/ex/ex_util.c
+++ b/contrib/nvi/ex/ex_util.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: ex_util.c,v 10.32 2001/06/25 15:19:21 skimo E
* ex_cinit --
* Create an EX command structure.
*
- * PUBLIC: void ex_cinit __P((SCR *, EXCMD *, int, int, recno_t, recno_t, int));
+ * PUBLIC: void ex_cinit(SCR *, EXCMD *, int, int, recno_t, recno_t, int);
*/
void
ex_cinit(SCR *sp, EXCMD *cmdp, int cmd_id, int naddr, recno_t lno1, recno_t lno2, int force)
@@ -51,7 +51,7 @@ ex_cinit(SCR *sp, EXCMD *cmdp, int cmd_id, int naddr, recno_t lno1, recno_t lno2
* ex_getline --
* Return a line from the file.
*
- * PUBLIC: int ex_getline __P((SCR *, FILE *, size_t *));
+ * PUBLIC: int ex_getline(SCR *, FILE *, size_t *);
*/
int
ex_getline(SCR *sp, FILE *fp, size_t *lenp)
@@ -91,7 +91,7 @@ ex_getline(SCR *sp, FILE *fp, size_t *lenp)
* ex_ncheck --
* Check for more files to edit.
*
- * PUBLIC: int ex_ncheck __P((SCR *, int));
+ * PUBLIC: int ex_ncheck(SCR *, int);
*/
int
ex_ncheck(SCR *sp, int force)
@@ -120,7 +120,7 @@ ex_ncheck(SCR *sp, int force)
* ex_init --
* Init the screen for ex.
*
- * PUBLIC: int ex_init __P((SCR *));
+ * PUBLIC: int ex_init(SCR *);
*/
int
ex_init(SCR *sp)
@@ -145,7 +145,7 @@ ex_init(SCR *sp)
* ex_emsg --
* Display a few common ex and vi error messages.
*
- * PUBLIC: void ex_wemsg __P((SCR *, CHAR_T *, exm_t));
+ * PUBLIC: void ex_wemsg(SCR *, CHAR_T *, exm_t);
*/
void
ex_wemsg(SCR* sp, CHAR_T *p, exm_t which)
@@ -162,7 +162,7 @@ ex_wemsg(SCR* sp, CHAR_T *p, exm_t which)
* ex_emsg --
* Display a few common ex and vi error messages.
*
- * PUBLIC: void ex_emsg __P((SCR *, char *, exm_t));
+ * PUBLIC: void ex_emsg(SCR *, char *, exm_t);
*/
void
ex_emsg(SCR *sp, char *p, exm_t which)
diff --git a/contrib/nvi/ex/ex_version.c b/contrib/nvi/ex/ex_version.c
index 4f0a17d..dc18aa1 100644
--- a/contrib/nvi/ex/ex_version.c
+++ b/contrib/nvi/ex/ex_version.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: ex_version.c,v 10.32 2001/06/25 15:19:22 skim
* ex_version -- :version
* Display the program version.
*
- * PUBLIC: int ex_version __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_version(SCR *, EXCMD *);
*/
int
ex_version(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_visual.c b/contrib/nvi/ex/ex_visual.c
index f913c71..bfad97c 100644
--- a/contrib/nvi/ex/ex_visual.c
+++ b/contrib/nvi/ex/ex_visual.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: ex_visual.c,v 10.16 2001/08/29 11:04:13 skimo
* ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags]
* Switch to visual mode.
*
- * PUBLIC: int ex_visual __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_visual(SCR *, EXCMD *);
*/
int
ex_visual(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_write.c b/contrib/nvi/ex/ex_write.c
index 1f94a63..18a578c 100644
--- a/contrib/nvi/ex/ex_write.c
+++ b/contrib/nvi/ex/ex_write.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: ex_write.c,v 10.41 2011/12/02 01:07:06 zy Exp $";
+static const char sccsid[] = "$Id: ex_write.c,v 10.43 2015/04/03 15:18:45 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -25,19 +25,18 @@ static const char sccsid[] = "$Id: ex_write.c,v 10.41 2011/12/02 01:07:06 zy Exp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <strings.h>
#include <unistd.h>
#include "../common/common.h"
enum which {WN, WQ, WRITE, XIT};
-static int exwr __P((SCR *, EXCMD *, enum which));
+static int exwr(SCR *, EXCMD *, enum which);
/*
* ex_wn -- :wn[!] [>>] [file]
* Write to a file and switch to the next one.
*
- * PUBLIC: int ex_wn __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_wn(SCR *, EXCMD *);
*/
int
ex_wn(SCR *sp, EXCMD *cmdp)
@@ -57,7 +56,7 @@ ex_wn(SCR *sp, EXCMD *cmdp)
* ex_wq -- :wq[!] [>>] [file]
* Write to a file and quit.
*
- * PUBLIC: int ex_wq __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_wq(SCR *, EXCMD *);
*/
int
ex_wq(SCR *sp, EXCMD *cmdp)
@@ -83,7 +82,7 @@ ex_wq(SCR *sp, EXCMD *cmdp)
* :write [!] [cmd]
* Write to a file.
*
- * PUBLIC: int ex_write __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_write(SCR *, EXCMD *);
*/
int
ex_write(SCR *sp, EXCMD *cmdp)
@@ -96,7 +95,7 @@ ex_write(SCR *sp, EXCMD *cmdp)
* ex_xit -- :x[it]! [file]
* Write out any modifications and quit.
*
- * PUBLIC: int ex_xit __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_xit(SCR *, EXCMD *);
*/
int
ex_xit(SCR *sp, EXCMD *cmdp)
@@ -279,8 +278,8 @@ exwr(SCR *sp, EXCMD *cmdp, enum which cmd)
* ex_writefp --
* Write a range of lines to a FILE *.
*
- * PUBLIC: int ex_writefp __P((SCR *,
- * PUBLIC: char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
+ * PUBLIC: int ex_writefp(SCR *,
+ * PUBLIC: char *, FILE *, MARK *, MARK *, u_long *, u_long *, int);
*/
int
ex_writefp(SCR *sp, char *name, FILE *fp, MARK *fm, MARK *tm, u_long *nlno, u_long *nch, int silent)
@@ -291,11 +290,7 @@ ex_writefp(SCR *sp, char *name, FILE *fp, MARK *fm, MARK *tm, u_long *nlno, u_lo
recno_t fline, tline, lcnt;
size_t len;
int rval;
- char *msg;
- CHAR_T *p;
- char *f;
- size_t flen;
- int isutf16;
+ char *msg, *p;
gp = sp->gp;
fline = fm->lno;
@@ -324,17 +319,7 @@ ex_writefp(SCR *sp, char *name, FILE *fp, MARK *fm, MARK *tm, u_long *nlno, u_lo
ccnt = 0;
lcnt = 0;
msg = "253|Writing...";
-
- if (O_ISSET(sp, O_FILEENCODING)) {
- isutf16 = !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-16", 6);
- isutf16 += !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-16le", 8);
- } else isutf16 = 0;
-
- if (tline != 0) {
- if (isutf16 == 1 && fwrite("\xfe\xff", 1, 2, fp) != 2)
- goto err;
- if (isutf16 == 2 && fwrite("\xff\xfe", 1, 2, fp) != 2)
- goto err;
+ if (tline != 0)
for (; fline <= tline; ++fline, ++lcnt) {
/* Caller has to provide any interrupt message. */
if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
@@ -346,31 +331,17 @@ ex_writefp(SCR *sp, char *name, FILE *fp, MARK *fm, MARK *tm, u_long *nlno, u_lo
msg = NULL;
}
}
- if (db_get(sp, fline, DBG_FATAL, &p, &len))
+ if (db_rget(sp, fline, &p, &len))
goto err;
- INT2FILE(sp, p, len, f, flen);
- if (fwrite(f, 1, flen, fp) != flen)
+ if (fwrite(p, 1, len, fp) != len)
goto err;
ccnt += len;
- /* UTF-16 w/o BOM is big-endian */
- switch (isutf16) {
- case 1: /* UTF-16BE */
- if (fwrite("\0\x0a", 1, 2, fp) != 2)
- goto done;
- break;
- case 2: /* UTF-16LE */
- if (fwrite("\x0a\0", 1, 2, fp) != 2)
- goto done;
+ if (putc('\n', fp) != '\n')
break;
- default:
- if (putc('\n', fp) != '\n')
- goto done;
- }
++ccnt;
}
- }
-done: if (fflush(fp))
+ if (fflush(fp))
goto err;
/*
* XXX
diff --git a/contrib/nvi/ex/ex_yank.c b/contrib/nvi/ex/ex_yank.c
index 262c78f..5d1be5a 100644
--- a/contrib/nvi/ex/ex_yank.c
+++ b/contrib/nvi/ex/ex_yank.c
@@ -27,7 +27,7 @@ static const char sccsid[] = "$Id: ex_yank.c,v 10.8 2001/06/25 15:19:22 skimo Ex
* ex_yank -- :[line [,line]] ya[nk] [buffer] [count]
* Yank the lines into a buffer.
*
- * PUBLIC: int ex_yank __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_yank(SCR *, EXCMD *);
*/
int
ex_yank(SCR *sp, EXCMD *cmdp)
diff --git a/contrib/nvi/ex/ex_z.c b/contrib/nvi/ex/ex_z.c
index 18a7859..fff80d8 100644
--- a/contrib/nvi/ex/ex_z.c
+++ b/contrib/nvi/ex/ex_z.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: ex_z.c,v 10.12 2001/06/25 15:19:22 skimo Exp
* ex_z -- :[line] z [^-.+=] [count] [flags]
* Adjust window.
*
- * PUBLIC: int ex_z __P((SCR *, EXCMD *));
+ * PUBLIC: int ex_z(SCR *, EXCMD *);
*/
int
ex_z(SCR *sp, EXCMD *cmdp)
@@ -54,11 +54,7 @@ ex_z(SCR *sp, EXCMD *cmdp)
if (FL_ISSET(cmdp->iflags, E_C_COUNT))
cnt = cmdp->count;
else
-#ifdef HISTORICAL_PRACTICE
- cnt = O_VAL(sp, O_SCROLL) * 2;
-#else
cnt = O_VAL(sp, O_WINDOW) - 1;
-#endif
equals = 0;
eofcheck = 0;
diff --git a/contrib/nvi/ex/extern.h b/contrib/nvi/ex/extern.h
index f54548b..ed1e1b7 100644
--- a/contrib/nvi/ex/extern.h
+++ b/contrib/nvi/ex/extern.h
@@ -1,130 +1,130 @@
-int ex __P((SCR **));
-int ex_cmd __P((SCR *));
-int ex_range __P((SCR *, EXCMD *, int *));
-int ex_is_abbrev __P((CHAR_T *, size_t));
-int ex_is_unmap __P((CHAR_T *, size_t));
+int ex(SCR **);
+int ex_cmd(SCR *);
+int ex_range(SCR *, EXCMD *, int *);
+int ex_is_abbrev(CHAR_T *, size_t);
+int ex_is_unmap(CHAR_T *, size_t);
void ex_badaddr
- __P((SCR *, EXCMDLIST const *, enum badaddr, enum nresult));
-int ex_abbr __P((SCR *, EXCMD *));
-int ex_unabbr __P((SCR *, EXCMD *));
-int ex_append __P((SCR *, EXCMD *));
-int ex_change __P((SCR *, EXCMD *));
-int ex_insert __P((SCR *, EXCMD *));
-int ex_next __P((SCR *, EXCMD *));
-int ex_prev __P((SCR *, EXCMD *));
-int ex_rew __P((SCR *, EXCMD *));
-int ex_args __P((SCR *, EXCMD *));
-char **ex_buildargv __P((SCR *, EXCMD *, char *));
-int argv_init __P((SCR *, EXCMD *));
-int argv_exp0 __P((SCR *, EXCMD *, CHAR_T *, size_t));
-int argv_exp1 __P((SCR *, EXCMD *, CHAR_T *, size_t, int));
-int argv_exp2 __P((SCR *, EXCMD *, CHAR_T *, size_t));
-int argv_exp3 __P((SCR *, EXCMD *, CHAR_T *, size_t));
-int argv_flt_ex __P((SCR *, EXCMD *, CHAR_T *, size_t));
-int argv_free __P((SCR *));
-int argv_flt_path __P((SCR *, EXCMD *, CHAR_T *, size_t));
-CHAR_T *argv_esc __P((SCR *, EXCMD *, CHAR_T *, size_t));
-CHAR_T *argv_uesc __P((SCR *, EXCMD *, CHAR_T *, size_t));
-int ex_at __P((SCR *, EXCMD *));
-int ex_bang __P((SCR *, EXCMD *));
-int ex_cd __P((SCR *, EXCMD *));
-int ex_cscope __P((SCR *, EXCMD *));
-int cscope_end __P((SCR *));
-int cscope_display __P((SCR *));
-int cscope_search __P((SCR *, TAGQ *, TAG *));
-int ex_delete __P((SCR *, EXCMD *));
-int ex_display __P((SCR *, EXCMD *));
-int ex_edit __P((SCR *, EXCMD *));
-int ex_equal __P((SCR *, EXCMD *));
-int ex_file __P((SCR *, EXCMD *));
-int ex_filter __P((SCR *,
- EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype));
-int ex_global __P((SCR *, EXCMD *));
-int ex_v __P((SCR *, EXCMD *));
-int ex_g_insdel __P((SCR *, lnop_t, recno_t));
-int ex_screen_copy __P((SCR *, SCR *));
-int ex_screen_end __P((SCR *));
-int ex_optchange __P((SCR *, int, char *, u_long *));
-int ex_exrc __P((SCR *));
-int ex_run_str __P((SCR *, char *, CHAR_T *, size_t, int, int));
-int ex_join __P((SCR *, EXCMD *));
-int ex_map __P((SCR *, EXCMD *));
-int ex_unmap __P((SCR *, EXCMD *));
-int ex_mark __P((SCR *, EXCMD *));
-int ex_mkexrc __P((SCR *, EXCMD *));
-int ex_copy __P((SCR *, EXCMD *));
-int ex_move __P((SCR *, EXCMD *));
-int ex_open __P((SCR *, EXCMD *));
-int ex_preserve __P((SCR *, EXCMD *));
-int ex_recover __P((SCR *, EXCMD *));
-int ex_list __P((SCR *, EXCMD *));
-int ex_number __P((SCR *, EXCMD *));
-int ex_pr __P((SCR *, EXCMD *));
-int ex_print __P((SCR *, EXCMD *, MARK *, MARK *, u_int32_t));
-int ex_ldisplay __P((SCR *, const CHAR_T *, size_t, size_t, u_int));
-int ex_scprint __P((SCR *, MARK *, MARK *));
-int ex_printf __P((SCR *, const char *, ...));
-int ex_puts __P((SCR *, const char *));
-int ex_fflush __P((SCR *sp));
-int ex_put __P((SCR *, EXCMD *));
-int ex_quit __P((SCR *, EXCMD *));
-int ex_read __P((SCR *, EXCMD *));
-int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
-int ex_bg __P((SCR *, EXCMD *));
-int ex_fg __P((SCR *, EXCMD *));
-int ex_resize __P((SCR *, EXCMD *));
-int ex_sdisplay __P((SCR *));
-int ex_script __P((SCR *, EXCMD *));
-int sscr_exec __P((SCR *, recno_t));
-int sscr_input __P((SCR *));
-int sscr_end __P((SCR *));
-int ex_set __P((SCR *, EXCMD *));
-int ex_shell __P((SCR *, EXCMD *));
-int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
-int proc_wait __P((SCR *, long, const char *, int, int));
-int ex_shiftl __P((SCR *, EXCMD *));
-int ex_shiftr __P((SCR *, EXCMD *));
-int ex_source __P((SCR *, EXCMD *));
-int ex_stop __P((SCR *, EXCMD *));
-int ex_s __P((SCR *, EXCMD *));
-int ex_subagain __P((SCR *, EXCMD *));
-int ex_subtilde __P((SCR *, EXCMD *));
-int re_compile __P((SCR *,
- CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int));
-void re_error __P((SCR *, int, regex_t *));
-int ex_tag_first __P((SCR *, CHAR_T *));
-int ex_tag_push __P((SCR *, EXCMD *));
-int ex_tag_next __P((SCR *, EXCMD *));
-int ex_tag_prev __P((SCR *, EXCMD *));
-int ex_tag_nswitch __P((SCR *, TAG *, int));
-int ex_tag_Nswitch __P((SCR *, TAG *, int));
-int ex_tag_pop __P((SCR *, EXCMD *));
-int ex_tag_top __P((SCR *, EXCMD *));
-int ex_tag_display __P((SCR *));
-int ex_tag_copy __P((SCR *, SCR *));
-int tagq_free __P((SCR *, TAGQ *));
-int tagq_push __P((SCR*, TAGQ*, int, int ));
-void tag_msg __P((SCR *, tagmsg_t, char *));
-int ex_tagf_alloc __P((SCR *, char *));
-int ex_tag_free __P((SCR *));
-int ex_txt __P((SCR *, TEXTH *, ARG_CHAR_T, u_int32_t));
-int ex_undo __P((SCR *, EXCMD *));
-int ex_help __P((SCR *, EXCMD *));
-int ex_usage __P((SCR *, EXCMD *));
-int ex_viusage __P((SCR *, EXCMD *));
-void ex_cinit __P((SCR *, EXCMD *, int, int, recno_t, recno_t, int));
-int ex_getline __P((SCR *, FILE *, size_t *));
-int ex_ncheck __P((SCR *, int));
-int ex_init __P((SCR *));
-void ex_wemsg __P((SCR *, CHAR_T *, exm_t));
-void ex_emsg __P((SCR *, char *, exm_t));
-int ex_version __P((SCR *, EXCMD *));
-int ex_visual __P((SCR *, EXCMD *));
-int ex_wn __P((SCR *, EXCMD *));
-int ex_wq __P((SCR *, EXCMD *));
-int ex_write __P((SCR *, EXCMD *));
-int ex_xit __P((SCR *, EXCMD *));
-int ex_writefp __P((SCR *,
- char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
-int ex_yank __P((SCR *, EXCMD *));
-int ex_z __P((SCR *, EXCMD *));
+ (SCR *, EXCMDLIST const *, enum badaddr, enum nresult);
+int ex_abbr(SCR *, EXCMD *);
+int ex_unabbr(SCR *, EXCMD *);
+int ex_append(SCR *, EXCMD *);
+int ex_change(SCR *, EXCMD *);
+int ex_insert(SCR *, EXCMD *);
+int ex_next(SCR *, EXCMD *);
+int ex_prev(SCR *, EXCMD *);
+int ex_rew(SCR *, EXCMD *);
+int ex_args(SCR *, EXCMD *);
+char **ex_buildargv(SCR *, EXCMD *, char *);
+int argv_init(SCR *, EXCMD *);
+int argv_exp0(SCR *, EXCMD *, CHAR_T *, size_t);
+int argv_exp1(SCR *, EXCMD *, CHAR_T *, size_t, int);
+int argv_exp2(SCR *, EXCMD *, CHAR_T *, size_t);
+int argv_exp3(SCR *, EXCMD *, CHAR_T *, size_t);
+int argv_flt_ex(SCR *, EXCMD *, CHAR_T *, size_t);
+int argv_free(SCR *);
+int argv_flt_path(SCR *, EXCMD *, CHAR_T *, size_t);
+CHAR_T *argv_esc(SCR *, EXCMD *, CHAR_T *, size_t);
+CHAR_T *argv_uesc(SCR *, EXCMD *, CHAR_T *, size_t);
+int ex_at(SCR *, EXCMD *);
+int ex_bang(SCR *, EXCMD *);
+int ex_cd(SCR *, EXCMD *);
+int ex_cscope(SCR *, EXCMD *);
+int cscope_end(SCR *);
+int cscope_display(SCR *);
+int cscope_search(SCR *, TAGQ *, TAG *);
+int ex_delete(SCR *, EXCMD *);
+int ex_display(SCR *, EXCMD *);
+int ex_edit(SCR *, EXCMD *);
+int ex_equal(SCR *, EXCMD *);
+int ex_file(SCR *, EXCMD *);
+int ex_filter(SCR *,
+ EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype);
+int ex_global(SCR *, EXCMD *);
+int ex_v(SCR *, EXCMD *);
+int ex_g_insdel(SCR *, lnop_t, recno_t);
+int ex_screen_copy(SCR *, SCR *);
+int ex_screen_end(SCR *);
+int ex_optchange(SCR *, int, char *, u_long *);
+int ex_exrc(SCR *);
+int ex_run_str(SCR *, char *, CHAR_T *, size_t, int, int);
+int ex_join(SCR *, EXCMD *);
+int ex_map(SCR *, EXCMD *);
+int ex_unmap(SCR *, EXCMD *);
+int ex_mark(SCR *, EXCMD *);
+int ex_mkexrc(SCR *, EXCMD *);
+int ex_copy(SCR *, EXCMD *);
+int ex_move(SCR *, EXCMD *);
+int ex_open(SCR *, EXCMD *);
+int ex_preserve(SCR *, EXCMD *);
+int ex_recover(SCR *, EXCMD *);
+int ex_list(SCR *, EXCMD *);
+int ex_number(SCR *, EXCMD *);
+int ex_pr(SCR *, EXCMD *);
+int ex_print(SCR *, EXCMD *, MARK *, MARK *, u_int32_t);
+int ex_ldisplay(SCR *, const CHAR_T *, size_t, size_t, u_int);
+int ex_scprint(SCR *, MARK *, MARK *);
+int ex_printf(SCR *, const char *, ...);
+int ex_puts(SCR *, const char *);
+int ex_fflush(SCR *sp);
+int ex_put(SCR *, EXCMD *);
+int ex_quit(SCR *, EXCMD *);
+int ex_read(SCR *, EXCMD *);
+int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int);
+int ex_bg(SCR *, EXCMD *);
+int ex_fg(SCR *, EXCMD *);
+int ex_resize(SCR *, EXCMD *);
+int ex_sdisplay(SCR *);
+int ex_script(SCR *, EXCMD *);
+int sscr_exec(SCR *, recno_t);
+int sscr_input(SCR *);
+int sscr_end(SCR *);
+int ex_set(SCR *, EXCMD *);
+int ex_shell(SCR *, EXCMD *);
+int ex_exec_proc(SCR *, EXCMD *, char *, const char *, int);
+int proc_wait(SCR *, long, const char *, int, int);
+int ex_shiftl(SCR *, EXCMD *);
+int ex_shiftr(SCR *, EXCMD *);
+int ex_source(SCR *, EXCMD *);
+int ex_stop(SCR *, EXCMD *);
+int ex_s(SCR *, EXCMD *);
+int ex_subagain(SCR *, EXCMD *);
+int ex_subtilde(SCR *, EXCMD *);
+int re_compile(SCR *,
+ CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int);
+void re_error(SCR *, int, regex_t *);
+int ex_tag_first(SCR *, CHAR_T *);
+int ex_tag_push(SCR *, EXCMD *);
+int ex_tag_next(SCR *, EXCMD *);
+int ex_tag_prev(SCR *, EXCMD *);
+int ex_tag_nswitch(SCR *, TAG *, int);
+int ex_tag_Nswitch(SCR *, TAG *, int);
+int ex_tag_pop(SCR *, EXCMD *);
+int ex_tag_top(SCR *, EXCMD *);
+int ex_tag_display(SCR *);
+int ex_tag_copy(SCR *, SCR *);
+int tagq_free(SCR *, TAGQ *);
+int tagq_push(SCR*, TAGQ*, int, int );
+void tag_msg(SCR *, tagmsg_t, char *);
+int ex_tagf_alloc(SCR *, char *);
+int ex_tag_free(SCR *);
+int ex_txt(SCR *, TEXTH *, ARG_CHAR_T, u_int32_t);
+int ex_undo(SCR *, EXCMD *);
+int ex_help(SCR *, EXCMD *);
+int ex_usage(SCR *, EXCMD *);
+int ex_viusage(SCR *, EXCMD *);
+void ex_cinit(SCR *, EXCMD *, int, int, recno_t, recno_t, int);
+int ex_getline(SCR *, FILE *, size_t *);
+int ex_ncheck(SCR *, int);
+int ex_init(SCR *);
+void ex_wemsg(SCR *, CHAR_T *, exm_t);
+void ex_emsg(SCR *, char *, exm_t);
+int ex_version(SCR *, EXCMD *);
+int ex_visual(SCR *, EXCMD *);
+int ex_wn(SCR *, EXCMD *);
+int ex_wq(SCR *, EXCMD *);
+int ex_write(SCR *, EXCMD *);
+int ex_xit(SCR *, EXCMD *);
+int ex_writefp(SCR *,
+ char *, FILE *, MARK *, MARK *, u_long *, u_long *, int);
+int ex_yank(SCR *, EXCMD *);
+int ex_z(SCR *, EXCMD *);
diff --git a/contrib/nvi/ex/version.h b/contrib/nvi/ex/version.h
index ef0af0f..e079bc6 100644
--- a/contrib/nvi/ex/version.h
+++ b/contrib/nvi/ex/version.h
@@ -1 +1 @@
-#define VI_VERSION "2.1.2 (2012-11-02)"
+#define VI_VERSION "2.1.3 (2015-04-08)"
diff --git a/contrib/nvi/regex/COPYRIGHT b/contrib/nvi/regex/COPYRIGHT
index 574f6bc..a0f83a4 100644
--- a/contrib/nvi/regex/COPYRIGHT
+++ b/contrib/nvi/regex/COPYRIGHT
@@ -32,11 +32,7 @@ to the following restrictions:
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/contrib/nvi/regex/cclass.h b/contrib/nvi/regex/cclass.h
index f28bccd..e635dcd 100644
--- a/contrib/nvi/regex/cclass.h
+++ b/contrib/nvi/regex/cclass.h
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/contrib/nvi/regex/cname.h b/contrib/nvi/regex/cname.h
index da69843..60656d2 100644
--- a/contrib/nvi/regex/cname.h
+++ b/contrib/nvi/regex/cname.h
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/contrib/nvi/regex/engine.c b/contrib/nvi/regex/engine.c
index ad1c501..069a473 100644
--- a/contrib/nvi/regex/engine.c
+++ b/contrib/nvi/regex/engine.c
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -92,12 +88,12 @@ extern "C" {
#endif
/* === engine.c === */
-static int matcher __P((struct re_guts *g, const RCHAR_T *string, size_t nmatch, regmatch_t pmatch[], int eflags));
-static const RCHAR_T *dissect __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
-static const RCHAR_T *backref __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev));
-static const RCHAR_T *fast __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
-static const RCHAR_T *slow __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
-static states step __P((struct re_guts *g, sopno start, sopno stop, states bef, int flag, RCHAR_T ch, states aft));
+static int matcher(struct re_guts *g, const RCHAR_T *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+static const RCHAR_T *dissect(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst);
+static const RCHAR_T *backref(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev);
+static const RCHAR_T *fast(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst);
+static const RCHAR_T *slow(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst);
+static states step(struct re_guts *g, sopno start, sopno stop, states bef, int flag, RCHAR_T ch, states aft);
#define BOL (1)
#define EOL (BOL+1)
#define BOLEOL (BOL+2)
@@ -105,13 +101,13 @@ static states step __P((struct re_guts *g, sopno start, sopno stop, states bef,
#define BOW (BOL+4)
#define EOW (BOL+5)
#ifdef REDEBUG
-static void print __P((struct match *m, char *caption, states st, int ch, FILE *d));
+static void print(struct match *m, char *caption, states st, int ch, FILE *d);
#endif
#ifdef REDEBUG
-static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst));
+static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst);
#endif
#ifdef REDEBUG
-static char *pchar __P((int ch));
+static char *pchar(int ch);
#endif
#ifdef __cplusplus
@@ -131,24 +127,18 @@ static char *pchar __P((int ch));
/*
- matcher - the actual matching engine
- == static int matcher(register struct re_guts *g, const RCHAR_T *string, \
- == size_t nmatch, regmatch_t pmatch[], int eflags);
*/
static int /* 0 success, REG_NOMATCH failure */
-matcher(g, string, nmatch, pmatch, eflags)
-register struct re_guts *g;
-const RCHAR_T *string;
-size_t nmatch;
-regmatch_t pmatch[];
-int eflags;
+matcher(struct re_guts *g, const RCHAR_T *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
{
- register const RCHAR_T *endp;
- register size_t i;
+ const RCHAR_T *endp;
+ size_t i;
struct match mv;
- register struct match *m = &mv;
- register const RCHAR_T *dp;
- register const sopno gf = g->firststate+1; /* +1 for OEND */
- register const sopno gl = g->laststate;
+ struct match *m = &mv;
+ const RCHAR_T *dp;
+ const sopno gf = g->firststate+1; /* +1 for OEND */
+ const sopno gl = g->laststate;
const RCHAR_T *start;
const RCHAR_T *stop;
@@ -297,30 +287,24 @@ int eflags;
/*
- dissect - figure out what matched what, no back references
- == static const RCHAR_T *dissect(register struct match *m, const RCHAR_T *start, \
- == const RCHAR_T *stop, sopno startst, sopno stopst);
*/
static const RCHAR_T * /* == stop (success) always */
-dissect(m, start, stop, startst, stopst)
-register struct match *m;
-const RCHAR_T *start;
-const RCHAR_T *stop;
-sopno startst;
-sopno stopst;
+dissect(struct match *m, const RCHAR_T *start, const RCHAR_T *stop,
+ sopno startst, sopno stopst)
{
- register int i;
- register sopno ss; /* start sop of current subRE */
- register sopno es; /* end sop of current subRE */
- register const RCHAR_T *sp; /* start of string matched by it */
- register const RCHAR_T *stp; /* string matched by it cannot pass here */
- register const RCHAR_T *rest; /* start of rest of string */
- register const RCHAR_T *tail; /* string unmatched by rest of RE */
- register sopno ssub; /* start sop of subsubRE */
- register sopno esub; /* end sop of subsubRE */
- register const RCHAR_T *ssp; /* start of string matched by subsubRE */
- register const RCHAR_T *sep; /* end of string matched by subsubRE */
- register const RCHAR_T *oldssp; /* previous ssp */
- register const RCHAR_T *dp;
+ int i;
+ sopno ss; /* start sop of current subRE */
+ sopno es; /* end sop of current subRE */
+ const RCHAR_T *sp; /* start of string matched by it */
+ const RCHAR_T *stp; /* string matched by it cannot pass here */
+ const RCHAR_T *rest; /* start of rest of string */
+ const RCHAR_T *tail; /* string unmatched by rest of RE */
+ sopno ssub; /* start sop of subsubRE */
+ sopno esub; /* end sop of subsubRE */
+ const RCHAR_T *ssp; /* start of string matched by subsubRE */
+ const RCHAR_T *sep; /* end of string matched by subsubRE */
+ const RCHAR_T *oldssp; /* previous ssp */
+ const RCHAR_T *dp;
AT("diss", start, stop, startst, stopst);
sp = start;
@@ -485,31 +469,24 @@ sopno stopst;
/*
- backref - figure out what matched what, figuring in back references
- == static const RCHAR_T *backref(register struct match *m, const RCHAR_T *start, \
- == const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev);
*/
static const RCHAR_T * /* == stop (success) or NULL (failure) */
-backref(m, start, stop, startst, stopst, lev)
-register struct match *m;
-const RCHAR_T *start;
-const RCHAR_T *stop;
-sopno startst;
-sopno stopst;
-sopno lev; /* PLUS nesting level */
+backref(struct match *m, const RCHAR_T *start, const RCHAR_T *stop,
+ sopno startst, sopno stopst, sopno lev) /* PLUS nesting level */
{
- register int i;
- register sopno ss; /* start sop of current subRE */
- register const RCHAR_T *sp; /* start of string matched by it */
- register sopno ssub; /* start sop of subsubRE */
- register sopno esub; /* end sop of subsubRE */
- register const RCHAR_T *ssp; /* start of string matched by subsubRE */
- register const RCHAR_T *dp;
- register size_t len;
- register int hard;
- register sop s;
- register RCHAR_T d;
- register regoff_t offsave;
- register cset *cs;
+ int i;
+ sopno ss; /* start sop of current subRE */
+ const RCHAR_T *sp; /* start of string matched by it */
+ sopno ssub; /* start sop of subsubRE */
+ sopno esub; /* end sop of subsubRE */
+ const RCHAR_T *ssp; /* start of string matched by subsubRE */
+ const RCHAR_T *dp;
+ size_t len;
+ int hard;
+ sop s;
+ RCHAR_T d;
+ regoff_t offsave;
+ cset *cs;
AT("back", start, stop, startst, stopst);
sp = start;
@@ -698,26 +675,20 @@ sopno lev; /* PLUS nesting level */
/*
- fast - step through the string at top speed
- == static const RCHAR_T *fast(register struct match *m, const RCHAR_T *start, \
- == const RCHAR_T *stop, sopno startst, sopno stopst);
*/
static const RCHAR_T * /* where tentative match ended, or NULL */
-fast(m, start, stop, startst, stopst)
-register struct match *m;
-const RCHAR_T *start;
-const RCHAR_T *stop;
-sopno startst;
-sopno stopst;
+fast(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst,
+ sopno stopst)
{
- register states st = m->st;
- register states fresh = m->fresh;
- register states tmp = m->tmp;
- register const RCHAR_T *p = start;
- register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
- register RCHAR_T lastc; /* previous c */
- register int flag;
- register int i;
- register const RCHAR_T *coldp; /* last p after which no match was underway */
+ states st = m->st;
+ states fresh = m->fresh;
+ states tmp = m->tmp;
+ const RCHAR_T *p = start;
+ RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
+ RCHAR_T lastc; /* previous c */
+ int flag;
+ int i;
+ const RCHAR_T *coldp; /* last p after which no match was underway */
CLEAR(st);
SET1(st, startst);
@@ -789,26 +760,20 @@ sopno stopst;
/*
- slow - step through the string more deliberately
- == static const RCHAR_T *slow(register struct match *m, const RCHAR_T *start, \
- == const RCHAR_T *stop, sopno startst, sopno stopst);
*/
static const RCHAR_T * /* where it ended */
-slow(m, start, stop, startst, stopst)
-register struct match *m;
-const RCHAR_T *start;
-const RCHAR_T *stop;
-sopno startst;
-sopno stopst;
+slow(struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst,
+ sopno stopst)
{
- register states st = m->st;
- register states empty = m->empty;
- register states tmp = m->tmp;
- register const RCHAR_T *p = start;
- register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
- register RCHAR_T lastc; /* previous c */
- register int flag;
- register int i;
- register const RCHAR_T *matchp; /* last p at which a match ended */
+ states st = m->st;
+ states empty = m->empty;
+ states tmp = m->tmp;
+ const RCHAR_T *p = start;
+ RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
+ RCHAR_T lastc; /* previous c */
+ int flag;
+ int i;
+ const RCHAR_T *matchp; /* last p at which a match ended */
AT("slow", start, stop, startst, stopst);
CLEAR(st);
@@ -876,32 +841,23 @@ sopno stopst;
/*
- step - map set of states reachable before char to set reachable after
- == static states step(register struct re_guts *g, sopno start, sopno stop, \
- == register states bef, int flag, RCHAR_T ch, register states aft);
- == #define BOL (1)
- == #define EOL (BOL+1)
- == #define BOLEOL (BOL+2)
- == #define NOTHING (BOL+3)
- == #define BOW (BOL+4)
- == #define EOW (BOL+5)
*/
static states
-step(g, start, stop, bef, flag, ch, aft)
-register struct re_guts *g;
-sopno start; /* start state within strip */
-sopno stop; /* state after stop state within strip */
-register states bef; /* states reachable before */
-int flag; /* NONCHAR flag */
-RCHAR_T ch; /* character code */
-register states aft; /* states already known reachable after */
+step(struct re_guts *g,
+ sopno start, /* start state within strip */
+ sopno stop, /* state after stop state within strip */
+ states bef, /* states reachable before */
+ int flag, /* NONCHAR flag */
+ RCHAR_T ch, /* character code */
+ states aft) /* states already known reachable after */
{
- register cset *cs;
- register sop s;
- register RCHAR_T d;
- register sopno pc;
- register onestate here; /* note, macros know this name */
- register sopno look;
- register int i;
+ cset *cs;
+ sop s;
+ RCHAR_T d;
+ sopno pc;
+ onestate here; /* note, macros know this name */
+ sopno look;
+ int i;
for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
s = g->strip[pc];
@@ -1008,22 +964,13 @@ register states aft; /* states already known reachable after */
#ifdef REDEBUG
/*
- print - print a set of states
- == #ifdef REDEBUG
- == static void print(struct match *m, char *caption, states st, \
- == int ch, FILE *d);
- == #endif
*/
static void
-print(m, caption, st, ch, d)
-struct match *m;
-char *caption;
-states st;
-int ch;
-FILE *d;
+print(struct match *m, char *caption, states st, int ch, FILE *d)
{
- register struct re_guts *g = m->g;
- register int i;
- register int first = 1;
+ struct re_guts *g = m->g;
+ int i;
+ int first = 1;
if (!(m->eflags&REG_TRACE))
return;
@@ -1041,19 +988,10 @@ FILE *d;
/*
- at - print current situation
- == #ifdef REDEBUG
- == static void at(struct match *m, char *title, char *start, char *stop, \
- == sopno startst, sopno stopst);
- == #endif
*/
static void
-at(m, title, start, stop, startst, stopst)
-struct match *m;
-char *title;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
+at(struct match *m, char *title, char *start, char *stop, sopno startst,
+ sopno stopst)
{
if (!(m->eflags&REG_TRACE))
return;
@@ -1067,9 +1005,6 @@ sopno stopst;
#define PCHARDONE /* never again */
/*
- pchar - make a character printable
- == #ifdef REDEBUG
- == static char *pchar(int ch);
- == #endif
*
* Is this identical to regchar() over in debug.c? Well, yes. But a
* duplicate here avoids having a debugging-capable regexec.o tied to
@@ -1077,8 +1012,7 @@ sopno stopst;
* the non-debug compilation anyway, so it doesn't matter much.
*/
static char * /* -> representation */
-pchar(ch)
-int ch;
+pchar(int ch)
{
static char pbuf[10];
diff --git a/contrib/nvi/regex/re_format.7 b/contrib/nvi/regex/re_format.7
index 61d1aea..ca6f71d 100644
--- a/contrib/nvi/regex/re_format.7
+++ b/contrib/nvi/regex/re_format.7
@@ -15,11 +15,7 @@
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
diff --git a/contrib/nvi/regex/regcomp.c b/contrib/nvi/regex/regcomp.c
index 8f7438f..cec7ba0 100644
--- a/contrib/nvi/regex/regcomp.c
+++ b/contrib/nvi/regex/regcomp.c
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -82,50 +78,50 @@ extern "C" {
#endif
/* === regcomp.c === */
-static void p_ere __P((struct parse *p, int stop, size_t reclimit));
-static void p_ere_exp __P((struct parse *p, size_t reclimit));
-static void p_str __P((struct parse *p));
-static void p_bre __P((struct parse *p, int end1, int end2, size_t reclimit));
-static int p_simp_re __P((struct parse *p, int starordinary, size_t reclimit));
-static int p_count __P((struct parse *p));
-static void p_bracket __P((struct parse *p));
-static void p_b_term __P((struct parse *p, cset *cs));
-static void p_b_cclass __P((struct parse *p, cset *cs));
-static void p_b_eclass __P((struct parse *p, cset *cs));
-static char p_b_symbol __P((struct parse *p));
-static char p_b_coll_elem __P((struct parse *p, int endc));
-static char othercase __P((int ch));
-static void bothcases __P((struct parse *p, int ch));
-static void ordinary __P((struct parse *p, int ch));
-static void nonnewline __P((struct parse *p));
-static void repeat __P((struct parse *p, sopno start, int from, int to, size_t reclimit));
-static int seterr __P((struct parse *p, int e));
-static cset *allocset __P((struct parse *p));
-static void freeset __P((struct parse *p, cset *cs));
-static int freezeset __P((struct parse *p, cset *cs));
-static int firstch __P((struct parse *p, cset *cs));
-static int nch __P((struct parse *p, cset *cs));
-static void mcadd __P((struct parse *p, cset *cs, const char *cp));
+static void p_ere(struct parse *p, int stop, size_t reclimit);
+static void p_ere_exp(struct parse *p, size_t reclimit);
+static void p_str(struct parse *p);
+static void p_bre(struct parse *p, int end1, int end2, size_t reclimit);
+static int p_simp_re(struct parse *p, int starordinary, size_t reclimit);
+static int p_count(struct parse *p);
+static void p_bracket(struct parse *p);
+static void p_b_term(struct parse *p, cset *cs);
+static void p_b_cclass(struct parse *p, cset *cs);
+static void p_b_eclass(struct parse *p, cset *cs);
+static char p_b_symbol(struct parse *p);
+static char p_b_coll_elem(struct parse *p, int endc);
+static char othercase(int ch);
+static void bothcases(struct parse *p, int ch);
+static void ordinary(struct parse *p, int ch);
+static void nonnewline(struct parse *p);
+static void repeat(struct parse *p, sopno start, int from, int to, size_t reclimit);
+static int seterr(struct parse *p, int e);
+static cset *allocset(struct parse *p);
+static void freeset(struct parse *p, cset *cs);
+static int freezeset(struct parse *p, cset *cs);
+static int firstch(struct parse *p, cset *cs);
+static int nch(struct parse *p, cset *cs);
+static void mcadd(struct parse *p, cset *cs, const char *cp);
#ifdef notdef
-static void mcsub __P((cset *cs, char *cp));
-static int mcin __P((cset *cs, char *cp));
-static char *mcfind __P((cset *cs, char *cp));
+static void mcsub(cset *cs, char *cp);
+static int mcin(cset *cs, char *cp);
+static char *mcfind(cset *cs, char *cp);
#endif
-static void mcinvert __P((struct parse *p, cset *cs));
-static void mccase __P((struct parse *p, cset *cs));
+static void mcinvert(struct parse *p, cset *cs);
+static void mccase(struct parse *p, cset *cs);
#ifdef notdef
-static int isinsets __P((struct re_guts *g, int c));
-static int samesets __P((struct re_guts *g, int c1, int c2));
+static int isinsets(struct re_guts *g, int c);
+static int samesets(struct re_guts *g, int c1, int c2);
#endif
-static void categorize __P((struct parse *p, struct re_guts *g));
-static sopno dupl __P((struct parse *p, sopno start, sopno finish));
-static void doemit __P((struct parse *p, sop op, size_t opnd));
-static void doinsert __P((struct parse *p, sop op, size_t opnd, sopno pos));
-static void dofwd __P((struct parse *p, sopno pos, sop value));
-static int enlarge __P((struct parse *p, sopno size));
-static void stripsnug __P((struct parse *p, struct re_guts *g));
-static void findmust __P((struct parse *p, struct re_guts *g));
-static sopno pluscount __P((struct parse *p, struct re_guts *g));
+static void categorize(struct parse *p, struct re_guts *g);
+static sopno dupl(struct parse *p, sopno start, sopno finish);
+static void doemit(struct parse *p, sop op, size_t opnd);
+static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos);
+static void dofwd(struct parse *p, sopno pos, sop value);
+static int enlarge(struct parse *p, sopno size);
+static void stripsnug(struct parse *p, struct re_guts *g);
+static void findmust(struct parse *p, struct re_guts *g);
+static sopno pluscount(struct parse *p, struct re_guts *g);
#ifdef __cplusplus
}
@@ -179,24 +175,15 @@ static int never = 0; /* for use in asserts; shuts lint up */
/*
- regcomp - interface for parser and compilation
- = extern int regcomp(regex_t *, const RCHAR_T *, int);
- = #define REG_BASIC 0000
- = #define REG_EXTENDED 0001
- = #define REG_ICASE 0002
- = #define REG_NOSUB 0004
- = #define REG_NEWLINE 0010
- = #define REG_NOSPEC 0020
- = #define REG_PEND 0040
- = #define REG_DUMP 0200
*/
int /* 0 success, otherwise REG_something */
regcomp(regex_t *preg, const RCHAR_T *pattern, int cflags)
{
struct parse pa;
- register struct re_guts *g;
- register struct parse *p = &pa;
- register int i;
- register size_t len;
+ struct re_guts *g;
+ struct parse *p = &pa;
+ int i;
+ size_t len;
#ifdef REDEBUG
# define GOODFLAGS(f) (f)
#else
@@ -257,7 +244,7 @@ regcomp(regex_t *preg, const RCHAR_T *pattern, int cflags)
#if 0
g->ncategories = 1; /* category 0 is "everything else" */
g->categories = &g->catspace[-(CHAR_MIN)];
- (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+ memset((char *)g->catspace, 0, NC*sizeof(cat_t));
#endif
g->backrefs = 0;
@@ -296,18 +283,16 @@ regcomp(regex_t *preg, const RCHAR_T *pattern, int cflags)
/*
- p_ere - ERE parser top level, concatenation and alternation
- == static void p_ere(register struct parse *p, int stop, size_t reclimit);
*/
static void
-p_ere(register struct parse *p, int stop, size_t reclimit)
-
+p_ere(struct parse *p, int stop, size_t reclimit)
/* character this ERE should end at */
{
- register char c;
- register sopno prevback = 0;
- register sopno prevfwd = 0;
- register sopno conc;
- register int first = 1; /* is this the first alternative? */
+ char c;
+ sopno prevback = 0;
+ sopno prevfwd = 0;
+ sopno conc;
+ int first = 1; /* is this the first alternative? */
if (reclimit++ > RECLIMIT || p->error == REG_ESPACE) {
p->error = REG_ESPACE;
@@ -347,16 +332,15 @@ p_ere(register struct parse *p, int stop, size_t reclimit)
/*
- p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
- == static void p_ere_exp(register struct parse *p);
*/
static void
-p_ere_exp(register struct parse *p, size_t reclimit)
+p_ere_exp(struct parse *p, size_t reclimit)
{
- register char c;
- register sopno pos;
- register int count;
- register int count2;
- register sopno subno;
+ char c;
+ sopno pos;
+ int count;
+ int count2;
+ sopno subno;
int wascaret = 0;
assert(MORE()); /* caller should have ensured this */
@@ -495,10 +479,9 @@ p_ere_exp(register struct parse *p, size_t reclimit)
/*
- p_str - string (no metacharacters) "parser"
- == static void p_str(register struct parse *p);
*/
static void
-p_str(register struct parse *p)
+p_str(struct parse *p)
{
(void)REQUIRE(MORE(), REG_EMPTY);
while (MORE())
@@ -507,8 +490,6 @@ p_str(register struct parse *p)
/*
- p_bre - BRE parser top level, anchoring and concatenation
- == static void p_bre(register struct parse *p, register int end1, \
- == register int end2, size_t reclimit);
* Giving end1 as OUT essentially eliminates the end1/end2 check.
*
* This implementation is a bit of a kludge, in that a trailing $ is first
@@ -518,14 +499,14 @@ p_str(register struct parse *p)
* The amount of lookahead needed to avoid this kludge is excessive.
*/
static void
-p_bre(register struct parse *p, register int end1, register int end2, size_t reclimit)
-
- /* first terminating character */
- /* second terminating character */
+p_bre(struct parse *p,
+ int end1, /* first terminating character */
+ int end2, /* second terminating character */
+ size_t reclimit)
{
- register sopno start;
- register int first = 1; /* first subexpression? */
- register int wasdollar = 0;
+ sopno start;
+ int first = 1; /* first subexpression? */
+ int wasdollar = 0;
if (reclimit++ > RECLIMIT || p->error == REG_ESPACE) {
p->error = REG_ESPACE;
@@ -555,19 +536,18 @@ p_bre(register struct parse *p, register int end1, register int end2, size_t rec
/*
- p_simp_re - parse a simple RE, an atom possibly followed by a repetition
- == static int p_simp_re(register struct parse *p, int starordinary, size_t reclimit);
*/
static int /* was the simple RE an unbackslashed $? */
-p_simp_re(register struct parse *p, int starordinary, size_t reclimit)
-
- /* is a leading * an ordinary character? */
+p_simp_re(struct parse *p,
+ int starordinary, /* is a leading * an ordinary character? */
+ size_t reclimit)
{
- register int c;
- register int count;
- register int count2;
- register sopno pos;
- register int i;
- register sopno subno;
+ int c;
+ int count;
+ int count2;
+ sopno pos;
+ int i;
+ sopno subno;
int backsl;
pos = HERE(); /* repetion op, if any, covers from here */
@@ -680,13 +660,12 @@ p_simp_re(register struct parse *p, int starordinary, size_t reclimit)
/*
- p_count - parse a repetition count
- == static int p_count(register struct parse *p);
*/
static int /* the value */
-p_count(register struct parse *p)
+p_count(struct parse *p)
{
- register int count = 0;
- register int ndigits = 0;
+ int count = 0;
+ int ndigits = 0;
while (MORE() && ISDIGIT((UCHAR_T)PEEK()) && count <= DUPMAX) {
count = count*10 + (GETNEXT() - '0');
@@ -699,16 +678,15 @@ p_count(register struct parse *p)
/*
- p_bracket - parse a bracketed character list
- == static void p_bracket(register struct parse *p);
*
* Note a significant property of this code: if the allocset() did SETERROR,
* no set operations are done.
*/
static void
-p_bracket(register struct parse *p)
+p_bracket(struct parse *p)
{
- register cset *cs;
- register int invert = 0;
+ cset *cs;
+ int invert = 0;
static RCHAR_T bow[] = { '[', ':', '<', ':', ']', ']' };
static RCHAR_T eow[] = { '[', ':', '>', ':', ']', ']' };
@@ -744,8 +722,8 @@ p_bracket(register struct parse *p)
return;
if (p->g->cflags&REG_ICASE) {
- register int i;
- register int ci;
+ int i;
+ int ci;
for (i = p->g->csetsize - 1; i >= 0; i--)
if (CHIN(cs, i) && isalpha(i)) {
@@ -757,7 +735,7 @@ p_bracket(register struct parse *p)
mccase(p, cs);
}
if (invert) {
- register int i;
+ int i;
for (i = p->g->csetsize - 1; i >= 0; i--)
if (CHIN(cs, i))
@@ -781,14 +759,13 @@ p_bracket(register struct parse *p)
/*
- p_b_term - parse one term of a bracketed character list
- == static void p_b_term(register struct parse *p, register cset *cs);
*/
static void
-p_b_term(register struct parse *p, register cset *cs)
+p_b_term(struct parse *p, cset *cs)
{
- register char c;
- register char start, finish;
- register int i;
+ char c;
+ char start, finish;
+ int i;
/* classify what we've got */
switch ((MORE()) ? PEEK() : '\0') {
@@ -845,16 +822,15 @@ p_b_term(register struct parse *p, register cset *cs)
/*
- p_b_cclass - parse a character-class name and deal with it
- == static void p_b_cclass(register struct parse *p, register cset *cs);
*/
static void
-p_b_cclass(register struct parse *p, register cset *cs)
+p_b_cclass(struct parse *p, cset *cs)
{
- register RCHAR_T *sp = p->next;
- register struct cclass *cp;
- register size_t len;
- register const char *u;
- register char c;
+ RCHAR_T *sp = p->next;
+ struct cclass *cp;
+ size_t len;
+ const char *u;
+ char c;
while (MORE() && isalpha(PEEK()))
NEXT();
@@ -877,14 +853,13 @@ p_b_cclass(register struct parse *p, register cset *cs)
/*
- p_b_eclass - parse an equivalence-class name and deal with it
- == static void p_b_eclass(register struct parse *p, register cset *cs);
*
* This implementation is incomplete. xxx
*/
static void
-p_b_eclass(register struct parse *p, register cset *cs)
+p_b_eclass(struct parse *p, cset *cs)
{
- register char c;
+ char c;
c = p_b_coll_elem(p, '=');
CHadd(cs, c);
@@ -892,12 +867,11 @@ p_b_eclass(register struct parse *p, register cset *cs)
/*
- p_b_symbol - parse a character or [..]ed multicharacter collating symbol
- == static char p_b_symbol(register struct parse *p);
*/
static char /* value of symbol */
-p_b_symbol(register struct parse *p)
+p_b_symbol(struct parse *p)
{
- register char value;
+ char value;
(void)REQUIRE(MORE(), REG_EBRACK);
if (!EATTWO('[', '.'))
@@ -911,16 +885,15 @@ p_b_symbol(register struct parse *p)
/*
- p_b_coll_elem - parse a collating-element name and look it up
- == static char p_b_coll_elem(register struct parse *p, int endc);
*/
static char /* value of collating element */
-p_b_coll_elem(register struct parse *p, int endc)
+p_b_coll_elem(struct parse *p, int endc)
/* name ended by endc,']' */
{
- register RCHAR_T *sp = p->next;
- register struct cname *cp;
- register size_t len;
+ RCHAR_T *sp = p->next;
+ struct cname *cp;
+ size_t len;
while (MORE() && !SEETWO(endc, ']'))
NEXT();
@@ -940,7 +913,6 @@ p_b_coll_elem(register struct parse *p, int endc)
/*
- othercase - return the case counterpart of an alphabetic
- == static char othercase(int ch);
*/
static char /* if no counterpart, return ch */
othercase(int ch)
@@ -956,15 +928,14 @@ othercase(int ch)
/*
- bothcases - emit a dualcase version of a two-case character
- == static void bothcases(register struct parse *p, int ch);
*
* Boy, is this implementation ever a kludge...
*/
static void
-bothcases(register struct parse *p, int ch)
+bothcases(struct parse *p, int ch)
{
- register RCHAR_T *oldnext = p->next;
- register RCHAR_T *oldend = p->end;
+ RCHAR_T *oldnext = p->next;
+ RCHAR_T *oldend = p->end;
RCHAR_T bracket[3];
assert(othercase(ch) != ch); /* p_bracket() would recurse */
@@ -981,13 +952,12 @@ bothcases(register struct parse *p, int ch)
/*
- ordinary - emit an ordinary character
- == static void ordinary(register struct parse *p, register int ch);
*/
static void
-ordinary(register struct parse *p, register int ch)
+ordinary(struct parse *p, int ch)
{
/*
- register cat_t *cap = p->g->categories;
+ cat_t *cap = p->g->categories;
*/
if ((p->g->cflags&REG_ICASE) && isalpha(ch) && othercase(ch) != ch)
@@ -1003,15 +973,14 @@ ordinary(register struct parse *p, register int ch)
/*
- nonnewline - emit REG_NEWLINE version of OANY
- == static void nonnewline(register struct parse *p);
*
* Boy, is this implementation ever a kludge...
*/
static void
-nonnewline(register struct parse *p)
+nonnewline(struct parse *p)
{
- register RCHAR_T *oldnext = p->next;
- register RCHAR_T *oldend = p->end;
+ RCHAR_T *oldnext = p->next;
+ RCHAR_T *oldend = p->end;
RCHAR_T bracket[4];
p->next = bracket;
@@ -1028,21 +997,20 @@ nonnewline(register struct parse *p)
/*
- repeat - generate code for a bounded repetition, recursively if needed
- == static void repeat(register struct parse *p, sopno start, int from, int to, size_t reclimit);
*/
static void
-repeat(register struct parse *p, sopno start, int from, int to, size_t reclimit)
-
- /* operand from here to end of strip */
- /* repeated from this number */
- /* to this number of times (maybe INFINITY) */
+repeat(struct parse *p,
+ sopno start, /* operand from here to end of strip */
+ int from, /* repeated from this number */
+ int to, /* to this number of times (maybe INFINITY) */
+ size_t reclimit)
{
- register sopno finish;
+ sopno finish;
# define N 2
# define INF 3
# define REP(f, t) ((f)*8 + (t))
# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
- register sopno copy;
+ sopno copy;
if (reclimit++ > RECLIMIT)
p->error = REG_ESPACE;
@@ -1104,10 +1072,9 @@ repeat(register struct parse *p, sopno start, int from, int to, size_t reclimit)
/*
- seterr - set an error condition
- == static int seterr(register struct parse *p, int e);
*/
static int /* useless but makes type checking happy */
-seterr(register struct parse *p, int e)
+seterr(struct parse *p, int e)
{
if (p->error == 0) /* keep earliest error condition */
p->error = e;
@@ -1118,17 +1085,16 @@ seterr(register struct parse *p, int e)
/*
- allocset - allocate a set of characters for []
- == static cset *allocset(register struct parse *p);
*/
static cset *
-allocset(register struct parse *p)
+allocset(struct parse *p)
{
- register int no = p->g->ncsets++;
- register size_t nc;
- register size_t nbytes;
- register cset *cs;
- register size_t css = (size_t)p->g->csetsize;
- register int i;
+ int no = p->g->ncsets++;
+ size_t nc;
+ size_t nbytes;
+ cset *cs;
+ size_t css = (size_t)p->g->csetsize;
+ int i;
if (no >= p->ncsalloc) { /* need another column of space */
p->ncsalloc += CHAR_BIT;
@@ -1152,7 +1118,7 @@ allocset(register struct parse *p)
p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
}
if (p->g->sets != NULL && p->g->setbits != NULL)
- (void) memset((char *)p->g->setbits + (nbytes - css),
+ memset((char *)p->g->setbits + (nbytes - css),
0, css);
else {
oomem:
@@ -1175,14 +1141,13 @@ oomem:
/*
- freeset - free a now-unused set
- == static void freeset(register struct parse *p, register cset *cs);
*/
static void
-freeset(register struct parse *p, register cset *cs)
+freeset(struct parse *p, cset *cs)
{
- register size_t i;
- register cset *top = &p->g->sets[p->g->ncsets];
- register size_t css = (size_t)p->g->csetsize;
+ size_t i;
+ cset *top = &p->g->sets[p->g->ncsets];
+ size_t css = (size_t)p->g->csetsize;
for (i = 0; i < css; i++)
CHsub(cs, i);
@@ -1192,7 +1157,6 @@ freeset(register struct parse *p, register cset *cs)
/*
- freezeset - final processing on a set of characters
- == static int freezeset(register struct parse *p, register cset *cs);
*
* The main task here is merging identical sets. This is usually a waste
* of time (although the hash code minimizes the overhead), but can win
@@ -1201,13 +1165,13 @@ freeset(register struct parse *p, register cset *cs)
* the same value!
*/
static int /* set number */
-freezeset(register struct parse *p, register cset *cs)
+freezeset(struct parse *p, cset *cs)
{
- register uch h = cs->hash;
- register size_t i;
- register cset *top = &p->g->sets[p->g->ncsets];
- register cset *cs2;
- register size_t css = (size_t)p->g->csetsize;
+ uch h = cs->hash;
+ size_t i;
+ cset *top = &p->g->sets[p->g->ncsets];
+ cset *cs2;
+ size_t css = (size_t)p->g->csetsize;
/* look for an earlier one which is the same */
for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
@@ -1230,13 +1194,12 @@ freezeset(register struct parse *p, register cset *cs)
/*
- firstch - return first character in a set (which must have at least one)
- == static int firstch(register struct parse *p, register cset *cs);
*/
static int /* character; there is no "none" value */
-firstch(register struct parse *p, register cset *cs)
+firstch(struct parse *p, cset *cs)
{
- register size_t i;
- register size_t css = (size_t)p->g->csetsize;
+ size_t i;
+ size_t css = (size_t)p->g->csetsize;
for (i = 0; i < css; i++)
if (CHIN(cs, i))
@@ -1247,14 +1210,13 @@ firstch(register struct parse *p, register cset *cs)
/*
- nch - number of characters in a set
- == static int nch(register struct parse *p, register cset *cs);
*/
static int
-nch(register struct parse *p, register cset *cs)
+nch(struct parse *p, cset *cs)
{
- register size_t i;
- register size_t css = (size_t)p->g->csetsize;
- register int n = 0;
+ size_t i;
+ size_t css = (size_t)p->g->csetsize;
+ int n = 0;
for (i = 0; i < css; i++)
if (CHIN(cs, i))
@@ -1264,13 +1226,11 @@ nch(register struct parse *p, register cset *cs)
/*
- mcadd - add a collating element to a cset
- == static void mcadd(register struct parse *p, register cset *cs, \
- == register char *cp);
*/
static void
-mcadd(register struct parse *p, register cset *cs, register const char *cp)
+mcadd(struct parse *p, cset *cs, const char *cp)
{
- register size_t oldend = cs->smultis;
+ size_t oldend = cs->smultis;
void *np;
cs->smultis += strlen(cp) + 1;
@@ -1284,85 +1244,29 @@ mcadd(register struct parse *p, register cset *cs, register const char *cp)
}
cs->multis = np;
- (void) strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1);
+ strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1);
}
-#ifdef notdef
-/*
- - mcsub - subtract a collating element from a cset
- == static void mcsub(register cset *cs, register char *cp);
- */
-static void
-mcsub(register cset *cs, register char *cp)
-{
- register char *fp = mcfind(cs, cp);
- register size_t len = strlen(fp);
-
- assert(fp != NULL);
- (void) memmove(fp, fp + len + 1,
- cs->smultis - (fp + len + 1 - cs->multis));
- cs->smultis -= len;
-
- if (cs->smultis == 0) {
- free(cs->multis);
- cs->multis = NULL;
- return;
- }
-
- cs->multis = realloc(cs->multis, cs->smultis);
- assert(cs->multis != NULL);
-}
-
-/*
- - mcin - is a collating element in a cset?
- == static int mcin(register cset *cs, register char *cp);
- */
-static int
-mcin(register cset *cs, register char *cp)
-{
- return(mcfind(cs, cp) != NULL);
-}
-
-/*
- - mcfind - find a collating element in a cset
- == static char *mcfind(register cset *cs, register char *cp);
- */
-static char *
-mcfind(register cset *cs, register char *cp)
-{
- register char *p;
-
- if (cs->multis == NULL)
- return(NULL);
- for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
- if (strcmp(cp, p) == 0)
- return(p);
- return(NULL);
-}
-#endif
-
/*
- mcinvert - invert the list of collating elements in a cset
- == static void mcinvert(register struct parse *p, register cset *cs);
*
* This would have to know the set of possibilities. Implementation
* is deferred.
*/
static void
-mcinvert(register struct parse *p, register cset *cs)
+mcinvert(struct parse *p, cset *cs)
{
assert(cs->multis == NULL); /* xxx */
}
/*
- mccase - add case counterparts of the list of collating elements in a cset
- == static void mccase(register struct parse *p, register cset *cs);
*
* This would have to know the set of possibilities. Implementation
* is deferred.
*/
static void
-mccase(register struct parse *p, register cset *cs)
+mccase(struct parse *p, cset *cs)
{
assert(cs->multis == NULL); /* xxx */
}
@@ -1370,15 +1274,14 @@ mccase(register struct parse *p, register cset *cs)
#ifdef notdef
/*
- isinsets - is this character in any sets?
- == static int isinsets(register struct re_guts *g, int c);
*/
static int /* predicate */
-isinsets(register struct re_guts *g, int c)
+isinsets(struct re_guts *g, int c)
{
- register uch *col;
- register int i;
- register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
- register unsigned uc = (unsigned char)c;
+ uch *col;
+ int i;
+ int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ unsigned uc = (unsigned char)c;
for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
if (col[uc] != 0)
@@ -1388,16 +1291,15 @@ isinsets(register struct re_guts *g, int c)
/*
- samesets - are these two characters in exactly the same sets?
- == static int samesets(register struct re_guts *g, int c1, int c2);
*/
static int /* predicate */
-samesets(register struct re_guts *g, int c1, int c2)
+samesets(struct re_guts *g, int c1, int c2)
{
- register uch *col;
- register int i;
- register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
- register unsigned uc1 = (unsigned char)c1;
- register unsigned uc2 = (unsigned char)c2;
+ uch *col;
+ int i;
+ int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ unsigned uc1 = (unsigned char)c1;
+ unsigned uc2 = (unsigned char)c2;
for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
if (col[uc1] != col[uc2])
@@ -1408,16 +1310,15 @@ samesets(register struct re_guts *g, int c1, int c2)
/*
- categorize - sort out character categories
- == static void categorize(struct parse *p, register struct re_guts *g);
*/
static void
-categorize(struct parse *p, register struct re_guts *g)
+categorize(struct parse *p, struct re_guts *g)
{
#ifdef notdef
- register cat_t *cats = g->categories;
- register int c;
- register int c2;
- register cat_t cat;
+ cat_t *cats = g->categories;
+ int c;
+ int c2;
+ cat_t cat;
/* avoid making error situations worse */
if (p->error != 0)
@@ -1436,16 +1337,14 @@ categorize(struct parse *p, register struct re_guts *g)
/*
- dupl - emit a duplicate of a bunch of sops
- == static sopno dupl(register struct parse *p, sopno start, sopno finish);
*/
static sopno /* start of duplicate */
-dupl(register struct parse *p, sopno start, sopno finish)
-
- /* from here */
- /* to this less one */
+dupl(struct parse *p,
+ sopno start, /* from here */
+ sopno finish) /* to this less one */
{
- register sopno ret = HERE();
- register sopno len = finish - start;
+ sopno ret = HERE();
+ sopno len = finish - start;
assert(finish >= start);
if (len == 0)
@@ -1463,14 +1362,13 @@ dupl(register struct parse *p, sopno start, sopno finish)
/*
- doemit - emit a strip operator
- == static void doemit(register struct parse *p, sop op, size_t opnd);
*
* It might seem better to implement this as a macro with a function as
* hard-case backup, but it's just too big and messy unless there are
* some changes to the data structures. Maybe later.
*/
static void
-doemit(register struct parse *p, sop op, size_t opnd)
+doemit(struct parse *p, sop op, size_t opnd)
{
/* avoid making error situations worse */
if (p->error != 0)
@@ -1492,15 +1390,14 @@ doemit(register struct parse *p, sop op, size_t opnd)
/*
- doinsert - insert a sop into the strip
- == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
*/
static void
-doinsert(register struct parse *p, sop op, size_t opnd, sopno pos)
+doinsert(struct parse *p, sop op, size_t opnd, sopno pos)
{
- register sopno sn;
- register sop s;
- register RCHAR_T d;
- register int i;
+ sopno sn;
+ sop s;
+ RCHAR_T d;
+ int i;
/* avoid making error situations worse */
if (p->error != 0)
@@ -1533,10 +1430,9 @@ doinsert(register struct parse *p, sop op, size_t opnd, sopno pos)
/*
- dofwd - complete a forward reference
- == static void dofwd(register struct parse *p, sopno pos, sop value);
*/
static void
-dofwd(register struct parse *p, register sopno pos, sop value)
+dofwd(struct parse *p, sopno pos, sop value)
{
/* avoid making error situations worse */
if (p->error != 0)
@@ -1548,13 +1444,12 @@ dofwd(register struct parse *p, register sopno pos, sop value)
/*
- enlarge - enlarge the strip
- == static int enlarge(register struct parse *p, sopno size);
*/
static int
-enlarge(register struct parse *p, register sopno size)
+enlarge(struct parse *p, sopno size)
{
- register sop *sp;
- register RCHAR_T *dp;
+ sop *sp;
+ RCHAR_T *dp;
sopno osize;
if (p->ssize >= size)
@@ -1581,10 +1476,9 @@ oomem:
/*
- stripsnug - compact the strip
- == static void stripsnug(register struct parse *p, register struct re_guts *g);
*/
static void
-stripsnug(register struct parse *p, register struct re_guts *g)
+stripsnug(struct parse *p, struct re_guts *g)
{
g->nstates = p->slen;
g->strip = (sop *)realloc((char *)p->strip,
@@ -1603,7 +1497,6 @@ stripsnug(register struct parse *p, register struct re_guts *g)
/*
- findmust - fill in must and mlen with longest mandatory literal string
- == static void findmust(register struct parse *p, register struct re_guts *g);
*
* This algorithm could do fancy things like analyzing the operands of |
* for common subsequences. Someday. This code is simple and finds most
@@ -1612,19 +1505,19 @@ stripsnug(register struct parse *p, register struct re_guts *g)
* Note that must and mlen got initialized during setup.
*/
static void
-findmust(struct parse *p, register struct re_guts *g)
+findmust(struct parse *p, struct re_guts *g)
{
- register sop *scans;
- register RCHAR_T *scand;
+ sop *scans;
+ RCHAR_T *scand;
sop *starts = 0;
RCHAR_T *startd = NULL;
- register sop *newstarts = 0;
- register RCHAR_T *newstartd = NULL;
- register sopno newlen;
- register sop s;
- register RCHAR_T d;
- register RCHAR_T *cp;
- register sopno i;
+ sop *newstarts = 0;
+ RCHAR_T *newstartd = NULL;
+ sopno newlen;
+ sop s;
+ RCHAR_T d;
+ RCHAR_T *cp;
+ sopno i;
/* avoid making error situations worse */
if (p->error != 0)
@@ -1704,15 +1597,14 @@ findmust(struct parse *p, register struct re_guts *g)
/*
- pluscount - count + nesting
- == static sopno pluscount(register struct parse *p, register struct re_guts *g);
*/
static sopno /* nesting depth */
-pluscount(struct parse *p, register struct re_guts *g)
+pluscount(struct parse *p, struct re_guts *g)
{
- register sop *scan;
- register sop s;
- register sopno plusnest = 0;
- register sopno maxnest = 0;
+ sop *scan;
+ sop s;
+ sopno plusnest = 0;
+ sopno maxnest = 0;
if (p->error != 0)
return(0); /* there may not be an OEND */
diff --git a/contrib/nvi/regex/regerror.c b/contrib/nvi/regex/regerror.c
index 5ff1f6b..ad86119 100644
--- a/contrib/nvi/regex/regerror.c
+++ b/contrib/nvi/regex/regerror.c
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -59,7 +55,7 @@ extern "C" {
#endif
/* === regerror.c === */
-static char *regatoi __P((const regex_t *preg, char *localbuf));
+static char *regatoi(const regex_t *preg, char *localbuf);
#ifdef __cplusplus
}
@@ -117,10 +113,10 @@ static struct rerr {
size_t
regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
{
- register struct rerr *r;
- register size_t len;
- register int target = errcode &~ REG_ITOA;
- register const char *s;
+ struct rerr *r;
+ size_t len;
+ int target = errcode &~ REG_ITOA;
+ const char *s;
char convbuf[50];
if (errcode == REG_ATOI)
@@ -144,7 +140,7 @@ regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
len = strlen(s) + 1;
if (errbuf_size > 0) {
- (void) strlcpy(errbuf, s, errbuf_size);
+ strlcpy(errbuf, s, errbuf_size);
}
return(len);
@@ -152,15 +148,14 @@ regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
/*
- regatoi - internal routine to implement REG_ATOI
- == static char *regatoi(const regex_t *preg, char *localbuf);
*/
static char *
regatoi(const regex_t *preg, char *localbuf)
{
#if 0 /* we don't seem to use this and it gives a warning. */
- register struct rerr *r;
- register size_t siz;
- register char *p;
+ struct rerr *r;
+ size_t siz;
+ char *p;
for (r = rerrs; r->code != 0; r++)
if (strcmp(r->name, preg->re_endp) == 0)
diff --git a/contrib/nvi/regex/regex.3 b/contrib/nvi/regex/regex.3
index 2c17254..8646fd3 100644
--- a/contrib/nvi/regex/regex.3
+++ b/contrib/nvi/regex/regex.3
@@ -15,11 +15,7 @@
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
diff --git a/contrib/nvi/regex/regex.h b/contrib/nvi/regex/regex.h
index cabd66b..20ea786 100644
--- a/contrib/nvi/regex/regex.h
+++ b/contrib/nvi/regex/regex.h
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -100,10 +96,10 @@ typedef struct {
#define REG_LARGE 01000 /* force large representation */
#define REG_BACKR 02000 /* force use of backref code */
-int regcomp __P((regex_t *, const RCHAR_T *, int));
-size_t regerror __P((int, const regex_t *, char *, size_t));
-int regexec __P((const regex_t *,
- const RCHAR_T *, size_t, regmatch_t [], int));
-void regfree __P((regex_t *));
+int regcomp(regex_t *, const RCHAR_T *, int);
+size_t regerror(int, const regex_t *, char *, size_t);
+int regexec(const regex_t *,
+ const RCHAR_T *, size_t, regmatch_t [], int);
+void regfree(regex_t *);
#endif /* !_REGEX_H_ */
diff --git a/contrib/nvi/regex/regex2.h b/contrib/nvi/regex/regex2.h
index 7c93528..c353063 100644
--- a/contrib/nvi/regex/regex2.h
+++ b/contrib/nvi/regex/regex2.h
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/contrib/nvi/regex/regexec.c b/contrib/nvi/regex/regexec.c
index 89ab2ca..67abd01 100644
--- a/contrib/nvi/regex/regexec.c
+++ b/contrib/nvi/regex/regexec.c
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -61,10 +57,6 @@ static char sccsid[] = "@(#)regexec.c 8.2 (Berkeley) 3/16/94";
#include "utils.h"
#include "regex2.h"
-#ifdef notdef
-static int nope = 0; /* for use in asserts; shuts lint up */
-#endif
-
/* macros for manipulating states, small version */
#define states int
#define states1 int /* for later use in regexec() decision */
@@ -157,9 +149,10 @@ static int nope = 0; /* for use in asserts; shuts lint up */
* have been prototyped.
*/
int /* 0 success, REG_NOMATCH failure */
-regexec(const regex_t *preg, const RCHAR_T *string, size_t nmatch, regmatch_t *pmatch, int eflags)
+regexec(const regex_t *preg, const RCHAR_T *string, size_t nmatch,
+ regmatch_t *pmatch, int eflags)
{
- register struct re_guts *g = preg->re_g;
+ struct re_guts *g = preg->re_g;
#ifdef REDEBUG
# define GOODFLAGS(f) (f)
#else
diff --git a/contrib/nvi/regex/regfree.c b/contrib/nvi/regex/regfree.c
index 61df17c..3329768 100644
--- a/contrib/nvi/regex/regfree.c
+++ b/contrib/nvi/regex/regfree.c
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -53,12 +49,11 @@ static char sccsid[] = "@(#)regfree.c 8.2 (Berkeley) 3/16/94";
/*
- regfree - free everything
- = extern void regfree(regex_t *);
*/
void
regfree(regex_t *preg)
{
- register struct re_guts *g;
+ struct re_guts *g;
if (preg->re_magic != MAGIC1) /* oops */
return; /* nice to complain, but hard */
diff --git a/contrib/nvi/regex/utils.h b/contrib/nvi/regex/utils.h
index 4a6f57a..75f061e 100644
--- a/contrib/nvi/regex/utils.h
+++ b/contrib/nvi/regex/utils.h
@@ -16,11 +16,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/contrib/nvi/vi/extern.h b/contrib/nvi/vi/extern.h
index 600caa6..8e145c6 100644
--- a/contrib/nvi/vi/extern.h
+++ b/contrib/nvi/vi/extern.h
@@ -1,145 +1,145 @@
-int cs_init __P((SCR *, VCS *));
-int cs_next __P((SCR *, VCS *));
-int cs_fspace __P((SCR *, VCS *));
-int cs_fblank __P((SCR *, VCS *));
-int cs_prev __P((SCR *, VCS *));
-int cs_bblank __P((SCR *, VCS *));
-int v_at __P((SCR *, VICMD *));
-int v_chrepeat __P((SCR *, VICMD *));
-int v_chrrepeat __P((SCR *, VICMD *));
-int v_cht __P((SCR *, VICMD *));
-int v_chf __P((SCR *, VICMD *));
-int v_chT __P((SCR *, VICMD *));
-int v_chF __P((SCR *, VICMD *));
-int v_delete __P((SCR *, VICMD *));
-int v_again __P((SCR *, VICMD *));
-int v_exmode __P((SCR *, VICMD *));
-int v_join __P((SCR *, VICMD *));
-int v_shiftl __P((SCR *, VICMD *));
-int v_shiftr __P((SCR *, VICMD *));
-int v_suspend __P((SCR *, VICMD *));
-int v_switch __P((SCR *, VICMD *));
-int v_tagpush __P((SCR *, VICMD *));
-int v_tagpop __P((SCR *, VICMD *));
-int v_filter __P((SCR *, VICMD *));
-int v_ex __P((SCR *, VICMD *));
-int v_ecl_exec __P((SCR *));
-int v_increment __P((SCR *, VICMD *));
-int v_screen_copy __P((SCR *, SCR *));
-int v_screen_end __P((SCR *));
-int v_optchange __P((SCR *, int, char *, u_long *));
-int v_iA __P((SCR *, VICMD *));
-int v_ia __P((SCR *, VICMD *));
-int v_iI __P((SCR *, VICMD *));
-int v_ii __P((SCR *, VICMD *));
-int v_iO __P((SCR *, VICMD *));
-int v_io __P((SCR *, VICMD *));
-int v_change __P((SCR *, VICMD *));
-int v_Replace __P((SCR *, VICMD *));
-int v_subst __P((SCR *, VICMD *));
-int v_left __P((SCR *, VICMD *));
-int v_cfirst __P((SCR *, VICMD *));
-int v_first __P((SCR *, VICMD *));
-int v_ncol __P((SCR *, VICMD *));
-int v_zero __P((SCR *, VICMD *));
-int v_mark __P((SCR *, VICMD *));
-int v_bmark __P((SCR *, VICMD *));
-int v_fmark __P((SCR *, VICMD *));
-int v_emark __P((SCR *, VICMD *));
-int v_match __P((SCR *, VICMD *));
-int v_buildmcs __P((SCR *, char *));
-int v_paragraphf __P((SCR *, VICMD *));
-int v_paragraphb __P((SCR *, VICMD *));
-int v_buildps __P((SCR *, char *, char *));
-int v_Put __P((SCR *, VICMD *));
-int v_put __P((SCR *, VICMD *));
-int v_redraw __P((SCR *, VICMD *));
-int v_replace __P((SCR *, VICMD *));
-int v_right __P((SCR *, VICMD *));
-int v_dollar __P((SCR *, VICMD *));
-int v_screen __P((SCR *, VICMD *));
-int v_lgoto __P((SCR *, VICMD *));
-int v_home __P((SCR *, VICMD *));
-int v_middle __P((SCR *, VICMD *));
-int v_bottom __P((SCR *, VICMD *));
-int v_up __P((SCR *, VICMD *));
-int v_cr __P((SCR *, VICMD *));
-int v_down __P((SCR *, VICMD *));
-int v_hpageup __P((SCR *, VICMD *));
-int v_hpagedown __P((SCR *, VICMD *));
-int v_pagedown __P((SCR *, VICMD *));
-int v_pageup __P((SCR *, VICMD *));
-int v_lineup __P((SCR *, VICMD *));
-int v_linedown __P((SCR *, VICMD *));
-int v_searchb __P((SCR *, VICMD *));
-int v_searchf __P((SCR *, VICMD *));
-int v_searchN __P((SCR *, VICMD *));
-int v_searchn __P((SCR *, VICMD *));
-int v_searchw __P((SCR *, VICMD *));
-int v_correct __P((SCR *, VICMD *, int));
-int v_sectionf __P((SCR *, VICMD *));
-int v_sectionb __P((SCR *, VICMD *));
-int v_sentencef __P((SCR *, VICMD *));
-int v_sentenceb __P((SCR *, VICMD *));
-int v_status __P((SCR *, VICMD *));
-int v_tcmd __P((SCR *, VICMD *, ARG_CHAR_T, u_int));
-int v_txt __P((SCR *, VICMD *, MARK *,
- const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t));
-int v_txt_auto __P((SCR *, recno_t, TEXT *, size_t, TEXT *));
-int v_ulcase __P((SCR *, VICMD *));
-int v_mulcase __P((SCR *, VICMD *));
-int v_Undo __P((SCR *, VICMD *));
-int v_undo __P((SCR *, VICMD *));
-void v_eof __P((SCR *, MARK *));
-void v_eol __P((SCR *, MARK *));
-void v_nomove __P((SCR *));
-void v_sof __P((SCR *, MARK *));
-void v_sol __P((SCR *));
-int v_isempty __P((CHAR_T *, size_t));
-void v_emsg __P((SCR *, char *, vim_t));
-int v_wordW __P((SCR *, VICMD *));
-int v_wordw __P((SCR *, VICMD *));
-int v_wordE __P((SCR *, VICMD *));
-int v_worde __P((SCR *, VICMD *));
-int v_wordB __P((SCR *, VICMD *));
-int v_wordb __P((SCR *, VICMD *));
-int v_xchar __P((SCR *, VICMD *));
-int v_Xchar __P((SCR *, VICMD *));
-int v_yank __P((SCR *, VICMD *));
-int v_z __P((SCR *, VICMD *));
-int vs_crel __P((SCR *, long));
-int v_zexit __P((SCR *, VICMD *));
-int vi __P((SCR **));
-int v_curword __P((SCR *));
-int vs_line __P((SCR *, SMAP *, size_t *, size_t *));
-int vs_number __P((SCR *));
-void vs_busy __P((SCR *, const char *, busy_t));
-void vs_home __P((SCR *));
-void vs_update __P((SCR *, const char *, const CHAR_T *));
-void vs_msg __P((SCR *, mtype_t, char *, size_t));
-int vs_ex_resolve __P((SCR *, int *));
-int vs_resolve __P((SCR *, SCR *, int));
-int vs_repaint __P((SCR *, EVENT *));
-int vs_refresh __P((SCR *, int));
-int vs_column __P((SCR *, size_t *));
-size_t vs_screens __P((SCR *, recno_t, size_t *));
-size_t vs_columns __P((SCR *, CHAR_T *, recno_t, size_t *, size_t *));
-size_t vs_rcm __P((SCR *, recno_t, int));
-size_t vs_colpos __P((SCR *, recno_t, size_t));
-int vs_change __P((SCR *, recno_t, lnop_t));
-int vs_sm_fill __P((SCR *, recno_t, pos_t));
-int vs_sm_scroll __P((SCR *, MARK *, recno_t, scroll_t));
-int vs_sm_1up __P((SCR *));
-int vs_sm_1down __P((SCR *));
-int vs_sm_next __P((SCR *, SMAP *, SMAP *));
-int vs_sm_prev __P((SCR *, SMAP *, SMAP *));
-int vs_sm_cursor __P((SCR *, SMAP **));
-int vs_sm_position __P((SCR *, MARK *, u_long, pos_t));
-recno_t vs_sm_nlines __P((SCR *, SMAP *, recno_t, size_t));
-int vs_split __P((SCR *, SCR *, int));
-int vs_vsplit __P((SCR *, SCR *));
-int vs_discard __P((SCR *, SCR **));
-int vs_fg __P((SCR *, SCR **, CHAR_T *, int));
-int vs_bg __P((SCR *));
-int vs_swap __P((SCR *, SCR **, char *));
-int vs_resize __P((SCR *, long, adj_t));
+int cs_init(SCR *, VCS *);
+int cs_next(SCR *, VCS *);
+int cs_fspace(SCR *, VCS *);
+int cs_fblank(SCR *, VCS *);
+int cs_prev(SCR *, VCS *);
+int cs_bblank(SCR *, VCS *);
+int v_at(SCR *, VICMD *);
+int v_chrepeat(SCR *, VICMD *);
+int v_chrrepeat(SCR *, VICMD *);
+int v_cht(SCR *, VICMD *);
+int v_chf(SCR *, VICMD *);
+int v_chT(SCR *, VICMD *);
+int v_chF(SCR *, VICMD *);
+int v_delete(SCR *, VICMD *);
+int v_again(SCR *, VICMD *);
+int v_exmode(SCR *, VICMD *);
+int v_join(SCR *, VICMD *);
+int v_shiftl(SCR *, VICMD *);
+int v_shiftr(SCR *, VICMD *);
+int v_suspend(SCR *, VICMD *);
+int v_switch(SCR *, VICMD *);
+int v_tagpush(SCR *, VICMD *);
+int v_tagpop(SCR *, VICMD *);
+int v_filter(SCR *, VICMD *);
+int v_ex(SCR *, VICMD *);
+int v_ecl_exec(SCR *);
+int v_increment(SCR *, VICMD *);
+int v_screen_copy(SCR *, SCR *);
+int v_screen_end(SCR *);
+int v_optchange(SCR *, int, char *, u_long *);
+int v_iA(SCR *, VICMD *);
+int v_ia(SCR *, VICMD *);
+int v_iI(SCR *, VICMD *);
+int v_ii(SCR *, VICMD *);
+int v_iO(SCR *, VICMD *);
+int v_io(SCR *, VICMD *);
+int v_change(SCR *, VICMD *);
+int v_Replace(SCR *, VICMD *);
+int v_subst(SCR *, VICMD *);
+int v_left(SCR *, VICMD *);
+int v_cfirst(SCR *, VICMD *);
+int v_first(SCR *, VICMD *);
+int v_ncol(SCR *, VICMD *);
+int v_zero(SCR *, VICMD *);
+int v_mark(SCR *, VICMD *);
+int v_bmark(SCR *, VICMD *);
+int v_fmark(SCR *, VICMD *);
+int v_emark(SCR *, VICMD *);
+int v_match(SCR *, VICMD *);
+int v_buildmcs(SCR *, char *);
+int v_paragraphf(SCR *, VICMD *);
+int v_paragraphb(SCR *, VICMD *);
+int v_buildps(SCR *, char *, char *);
+int v_Put(SCR *, VICMD *);
+int v_put(SCR *, VICMD *);
+int v_redraw(SCR *, VICMD *);
+int v_replace(SCR *, VICMD *);
+int v_right(SCR *, VICMD *);
+int v_dollar(SCR *, VICMD *);
+int v_screen(SCR *, VICMD *);
+int v_lgoto(SCR *, VICMD *);
+int v_home(SCR *, VICMD *);
+int v_middle(SCR *, VICMD *);
+int v_bottom(SCR *, VICMD *);
+int v_up(SCR *, VICMD *);
+int v_cr(SCR *, VICMD *);
+int v_down(SCR *, VICMD *);
+int v_hpageup(SCR *, VICMD *);
+int v_hpagedown(SCR *, VICMD *);
+int v_pagedown(SCR *, VICMD *);
+int v_pageup(SCR *, VICMD *);
+int v_lineup(SCR *, VICMD *);
+int v_linedown(SCR *, VICMD *);
+int v_searchb(SCR *, VICMD *);
+int v_searchf(SCR *, VICMD *);
+int v_searchN(SCR *, VICMD *);
+int v_searchn(SCR *, VICMD *);
+int v_searchw(SCR *, VICMD *);
+int v_correct(SCR *, VICMD *, int);
+int v_sectionf(SCR *, VICMD *);
+int v_sectionb(SCR *, VICMD *);
+int v_sentencef(SCR *, VICMD *);
+int v_sentenceb(SCR *, VICMD *);
+int v_status(SCR *, VICMD *);
+int v_tcmd(SCR *, VICMD *, ARG_CHAR_T, u_int);
+int v_txt(SCR *, VICMD *, MARK *,
+ const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t);
+int v_txt_auto(SCR *, recno_t, TEXT *, size_t, TEXT *);
+int v_ulcase(SCR *, VICMD *);
+int v_mulcase(SCR *, VICMD *);
+int v_Undo(SCR *, VICMD *);
+int v_undo(SCR *, VICMD *);
+void v_eof(SCR *, MARK *);
+void v_eol(SCR *, MARK *);
+void v_nomove(SCR *);
+void v_sof(SCR *, MARK *);
+void v_sol(SCR *);
+int v_isempty(CHAR_T *, size_t);
+void v_emsg(SCR *, char *, vim_t);
+int v_wordW(SCR *, VICMD *);
+int v_wordw(SCR *, VICMD *);
+int v_wordE(SCR *, VICMD *);
+int v_worde(SCR *, VICMD *);
+int v_wordB(SCR *, VICMD *);
+int v_wordb(SCR *, VICMD *);
+int v_xchar(SCR *, VICMD *);
+int v_Xchar(SCR *, VICMD *);
+int v_yank(SCR *, VICMD *);
+int v_z(SCR *, VICMD *);
+int vs_crel(SCR *, long);
+int v_zexit(SCR *, VICMD *);
+int vi(SCR **);
+int v_curword(SCR *);
+int vs_line(SCR *, SMAP *, size_t *, size_t *);
+int vs_number(SCR *);
+void vs_busy(SCR *, const char *, busy_t);
+void vs_home(SCR *);
+void vs_update(SCR *, const char *, const CHAR_T *);
+void vs_msg(SCR *, mtype_t, char *, size_t);
+int vs_ex_resolve(SCR *, int *);
+int vs_resolve(SCR *, SCR *, int);
+int vs_repaint(SCR *, EVENT *);
+int vs_refresh(SCR *, int);
+int vs_column(SCR *, size_t *);
+size_t vs_screens(SCR *, recno_t, size_t *);
+size_t vs_columns(SCR *, CHAR_T *, recno_t, size_t *, size_t *);
+size_t vs_rcm(SCR *, recno_t, int);
+size_t vs_colpos(SCR *, recno_t, size_t);
+int vs_change(SCR *, recno_t, lnop_t);
+int vs_sm_fill(SCR *, recno_t, pos_t);
+int vs_sm_scroll(SCR *, MARK *, recno_t, scroll_t);
+int vs_sm_1up(SCR *);
+int vs_sm_1down(SCR *);
+int vs_sm_next(SCR *, SMAP *, SMAP *);
+int vs_sm_prev(SCR *, SMAP *, SMAP *);
+int vs_sm_cursor(SCR *, SMAP **);
+int vs_sm_position(SCR *, MARK *, u_long, pos_t);
+recno_t vs_sm_nlines(SCR *, SMAP *, recno_t, size_t);
+int vs_split(SCR *, SCR *, int);
+int vs_vsplit(SCR *, SCR *);
+int vs_discard(SCR *, SCR **);
+int vs_fg(SCR *, SCR **, CHAR_T *, int);
+int vs_bg(SCR *);
+int vs_swap(SCR *, SCR **, char *);
+int vs_resize(SCR *, long, adj_t);
diff --git a/contrib/nvi/vi/getc.c b/contrib/nvi/vi/getc.c
index deb3554..1d2dc2b 100644
--- a/contrib/nvi/vi/getc.c
+++ b/contrib/nvi/vi/getc.c
@@ -40,7 +40,7 @@ static const char sccsid[] = "$Id: getc.c,v 10.13 2011/12/27 00:49:31 zy Exp $";
* cs_init --
* Initialize character stream routines.
*
- * PUBLIC: int cs_init __P((SCR *, VCS *));
+ * PUBLIC: int cs_init(SCR *, VCS *);
*/
int
cs_init(SCR *sp, VCS *csp)
@@ -66,7 +66,7 @@ cs_init(SCR *sp, VCS *csp)
* cs_next --
* Retrieve the next character.
*
- * PUBLIC: int cs_next __P((SCR *, VCS *));
+ * PUBLIC: int cs_next(SCR *, VCS *);
*/
int
cs_next(SCR *sp, VCS *csp)
@@ -116,7 +116,7 @@ cs_next(SCR *sp, VCS *csp)
* function -- once the other word routines are converted, they may have
* to change.
*
- * PUBLIC: int cs_fspace __P((SCR *, VCS *));
+ * PUBLIC: int cs_fspace(SCR *, VCS *);
*/
int
cs_fspace(SCR *sp, VCS *csp)
@@ -136,7 +136,7 @@ cs_fspace(SCR *sp, VCS *csp)
* cs_fblank --
* Eat forward to the next non-whitespace character.
*
- * PUBLIC: int cs_fblank __P((SCR *, VCS *));
+ * PUBLIC: int cs_fblank(SCR *, VCS *);
*/
int
cs_fblank(SCR *sp, VCS *csp)
@@ -156,7 +156,7 @@ cs_fblank(SCR *sp, VCS *csp)
* cs_prev --
* Retrieve the previous character.
*
- * PUBLIC: int cs_prev __P((SCR *, VCS *));
+ * PUBLIC: int cs_prev(SCR *, VCS *);
*/
int
cs_prev(SCR *sp, VCS *csp)
@@ -205,7 +205,7 @@ cs_prev(SCR *sp, VCS *csp)
* cs_bblank --
* Eat backward to the next non-whitespace character.
*
- * PUBLIC: int cs_bblank __P((SCR *, VCS *));
+ * PUBLIC: int cs_bblank(SCR *, VCS *);
*/
int
cs_bblank(SCR *sp, VCS *csp)
diff --git a/contrib/nvi/vi/v_at.c b/contrib/nvi/vi/v_at.c
index 45757d4..96e1616 100644
--- a/contrib/nvi/vi/v_at.c
+++ b/contrib/nvi/vi/v_at.c
@@ -30,7 +30,7 @@ static const char sccsid[] = "$Id: v_at.c,v 10.11 2001/06/25 15:19:30 skimo Exp
* v_at -- @
* Execute a buffer.
*
- * PUBLIC: int v_at __P((SCR *, VICMD *));
+ * PUBLIC: int v_at(SCR *, VICMD *);
*/
int
v_at(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_ch.c b/contrib/nvi/vi/v_ch.c
index 04fb6af..86bd532 100644
--- a/contrib/nvi/vi/v_ch.c
+++ b/contrib/nvi/vi/v_ch.c
@@ -25,14 +25,14 @@ static const char sccsid[] = "$Id: v_ch.c,v 10.11 2011/12/02 19:49:50 zy Exp $";
#include "../common/common.h"
#include "vi.h"
-static void notfound __P((SCR *, ARG_CHAR_T));
-static void noprev __P((SCR *));
+static void notfound(SCR *, ARG_CHAR_T);
+static void noprev(SCR *);
/*
* v_chrepeat -- [count];
* Repeat the last F, f, T or t search.
*
- * PUBLIC: int v_chrepeat __P((SCR *, VICMD *));
+ * PUBLIC: int v_chrepeat(SCR *, VICMD *);
*/
int
v_chrepeat(SCR *sp, VICMD *vp)
@@ -61,7 +61,7 @@ v_chrepeat(SCR *sp, VICMD *vp)
* v_chrrepeat -- [count],
* Repeat the last F, f, T or t search in the reverse direction.
*
- * PUBLIC: int v_chrrepeat __P((SCR *, VICMD *));
+ * PUBLIC: int v_chrrepeat(SCR *, VICMD *);
*/
int
v_chrrepeat(SCR *sp, VICMD *vp)
@@ -100,7 +100,7 @@ v_chrrepeat(SCR *sp, VICMD *vp)
* Search forward in the line for the character before the next
* occurrence of the specified character.
*
- * PUBLIC: int v_cht __P((SCR *, VICMD *));
+ * PUBLIC: int v_cht(SCR *, VICMD *);
*/
int
v_cht(SCR *sp, VICMD *vp)
@@ -131,7 +131,7 @@ v_cht(SCR *sp, VICMD *vp)
* Search forward in the line for the next occurrence of the
* specified character.
*
- * PUBLIC: int v_chf __P((SCR *, VICMD *));
+ * PUBLIC: int v_chf(SCR *, VICMD *);
*/
int
v_chf(SCR *sp, VICMD *vp)
@@ -188,7 +188,7 @@ empty: notfound(sp, key);
* Search backward in the line for the character after the next
* occurrence of the specified character.
*
- * PUBLIC: int v_chT __P((SCR *, VICMD *));
+ * PUBLIC: int v_chT(SCR *, VICMD *);
*/
int
v_chT(SCR *sp, VICMD *vp)
@@ -213,7 +213,7 @@ v_chT(SCR *sp, VICMD *vp)
* Search backward in the line for the next occurrence of the
* specified character.
*
- * PUBLIC: int v_chF __P((SCR *, VICMD *));
+ * PUBLIC: int v_chF(SCR *, VICMD *);
*/
int
v_chF(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_delete.c b/contrib/nvi/vi/v_delete.c
index b3b879e..b36808e 100644
--- a/contrib/nvi/vi/v_delete.c
+++ b/contrib/nvi/vi/v_delete.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: v_delete.c,v 10.11 2001/06/25 15:19:31 skimo
* [buffer][count]D
* Delete a range of text.
*
- * PUBLIC: int v_delete __P((SCR *, VICMD *));
+ * PUBLIC: int v_delete(SCR *, VICMD *);
*/
int
v_delete(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_ex.c b/contrib/nvi/vi/v_ex.c
index e5ac573..c6c1133 100644
--- a/contrib/nvi/vi/v_ex.c
+++ b/contrib/nvi/vi/v_ex.c
@@ -27,17 +27,17 @@ static const char sccsid[] = "$Id: v_ex.c,v 10.61 2011/12/22 18:41:53 zy Exp $";
#include "../common/common.h"
#include "vi.h"
-static int v_ecl __P((SCR *));
-static int v_ecl_init __P((SCR *));
-static int v_ecl_log __P((SCR *, TEXT *));
-static int v_ex_done __P((SCR *, VICMD *));
-static int v_exec_ex __P((SCR *, VICMD *, EXCMD *));
+static int v_ecl(SCR *);
+static int v_ecl_init(SCR *);
+static int v_ecl_log(SCR *, TEXT *);
+static int v_ex_done(SCR *, VICMD *);
+static int v_exec_ex(SCR *, VICMD *, EXCMD *);
/*
* v_again -- &
* Repeat the previous substitution.
*
- * PUBLIC: int v_again __P((SCR *, VICMD *));
+ * PUBLIC: int v_again(SCR *, VICMD *);
*/
int
v_again(SCR *sp, VICMD *vp)
@@ -53,7 +53,7 @@ v_again(SCR *sp, VICMD *vp)
* v_exmode -- Q
* Switch the editor into EX mode.
*
- * PUBLIC: int v_exmode __P((SCR *, VICMD *));
+ * PUBLIC: int v_exmode(SCR *, VICMD *);
*/
int
v_exmode(SCR *sp, VICMD *vp)
@@ -89,7 +89,7 @@ v_exmode(SCR *sp, VICMD *vp)
* v_join -- [count]J
* Join lines together.
*
- * PUBLIC: int v_join __P((SCR *, VICMD *));
+ * PUBLIC: int v_join(SCR *, VICMD *);
*/
int
v_join(SCR *sp, VICMD *vp)
@@ -118,7 +118,7 @@ v_join(SCR *sp, VICMD *vp)
* v_shiftl -- [count]<motion
* Shift lines left.
*
- * PUBLIC: int v_shiftl __P((SCR *, VICMD *));
+ * PUBLIC: int v_shiftl(SCR *, VICMD *);
*/
int
v_shiftl(SCR *sp, VICMD *vp)
@@ -134,7 +134,7 @@ v_shiftl(SCR *sp, VICMD *vp)
* v_shiftr -- [count]>motion
* Shift lines right.
*
- * PUBLIC: int v_shiftr __P((SCR *, VICMD *));
+ * PUBLIC: int v_shiftr(SCR *, VICMD *);
*/
int
v_shiftr(SCR *sp, VICMD *vp)
@@ -150,7 +150,7 @@ v_shiftr(SCR *sp, VICMD *vp)
* v_suspend -- ^Z
* Suspend vi.
*
- * PUBLIC: int v_suspend __P((SCR *, VICMD *));
+ * PUBLIC: int v_suspend(SCR *, VICMD *);
*/
int
v_suspend(SCR *sp, VICMD *vp)
@@ -166,7 +166,7 @@ v_suspend(SCR *sp, VICMD *vp)
* v_switch -- ^^
* Switch to the previous file.
*
- * PUBLIC: int v_switch __P((SCR *, VICMD *));
+ * PUBLIC: int v_switch(SCR *, VICMD *);
*/
int
v_switch(SCR *sp, VICMD *vp)
@@ -199,7 +199,7 @@ v_switch(SCR *sp, VICMD *vp)
* v_tagpush -- ^[
* Do a tag search on the cursor keyword.
*
- * PUBLIC: int v_tagpush __P((SCR *, VICMD *));
+ * PUBLIC: int v_tagpush(SCR *, VICMD *);
*/
int
v_tagpush(SCR *sp, VICMD *vp)
@@ -215,7 +215,7 @@ v_tagpush(SCR *sp, VICMD *vp)
* v_tagpop -- ^T
* Pop the tags stack.
*
- * PUBLIC: int v_tagpop __P((SCR *, VICMD *));
+ * PUBLIC: int v_tagpop(SCR *, VICMD *);
*/
int
v_tagpop(SCR *sp, VICMD *vp)
@@ -230,7 +230,7 @@ v_tagpop(SCR *sp, VICMD *vp)
* v_filter -- [count]!motion command(s)
* Run range through shell commands, replacing text.
*
- * PUBLIC: int v_filter __P((SCR *, VICMD *));
+ * PUBLIC: int v_filter(SCR *, VICMD *);
*/
int
v_filter(SCR *sp, VICMD *vp)
@@ -319,7 +319,7 @@ v_exec_ex(SCR *sp, VICMD *vp, EXCMD *exp)
* v_ex -- :
* Execute a colon command line.
*
- * PUBLIC: int v_ex __P((SCR *, VICMD *));
+ * PUBLIC: int v_ex(SCR *, VICMD *);
*/
int
v_ex(SCR *sp, VICMD *vp)
@@ -543,7 +543,7 @@ v_ecl(SCR *sp)
* v_ecl_exec --
* Execute a command from a colon command-line window.
*
- * PUBLIC: int v_ecl_exec __P((SCR *));
+ * PUBLIC: int v_ecl_exec(SCR *);
*/
int
v_ecl_exec(SCR *sp)
diff --git a/contrib/nvi/vi/v_increment.c b/contrib/nvi/vi/v_increment.c
index 0a121a9..0293425 100644
--- a/contrib/nvi/vi/v_increment.c
+++ b/contrib/nvi/vi/v_increment.c
@@ -41,13 +41,13 @@ static CHAR_T * const fmt[] = {
L("%#0*lo"),
};
-static void inc_err __P((SCR *, enum nresult));
+static void inc_err(SCR *, enum nresult);
/*
* v_increment -- [count]#[#+-]
* Increment/decrement a keyword number.
*
- * PUBLIC: int v_increment __P((SCR *, VICMD *));
+ * PUBLIC: int v_increment(SCR *, VICMD *);
*/
int
v_increment(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_init.c b/contrib/nvi/vi/v_init.c
index e47a821..a996632 100644
--- a/contrib/nvi/vi/v_init.c
+++ b/contrib/nvi/vi/v_init.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: v_init.c,v 10.10 2012/02/11 00:33:46 zy Exp $
* v_screen_copy --
* Copy vi screen.
*
- * PUBLIC: int v_screen_copy __P((SCR *, SCR *));
+ * PUBLIC: int v_screen_copy(SCR *, SCR *);
*/
int
v_screen_copy(SCR *orig, SCR *sp)
@@ -79,7 +79,7 @@ v_screen_copy(SCR *orig, SCR *sp)
* v_screen_end --
* End a vi screen.
*
- * PUBLIC: int v_screen_end __P((SCR *));
+ * PUBLIC: int v_screen_end(SCR *);
*/
int
v_screen_end(SCR *sp)
@@ -110,7 +110,7 @@ v_screen_end(SCR *sp)
* v_optchange --
* Handle change of options for vi.
*
- * PUBLIC: int v_optchange __P((SCR *, int, char *, u_long *));
+ * PUBLIC: int v_optchange(SCR *, int, char *, u_long *);
*/
int
v_optchange(SCR *sp, int offset, char *str, u_long *valp)
diff --git a/contrib/nvi/vi/v_itxt.c b/contrib/nvi/vi/v_itxt.c
index 8b26329..6446092 100644
--- a/contrib/nvi/vi/v_itxt.c
+++ b/contrib/nvi/vi/v_itxt.c
@@ -57,13 +57,13 @@ static const char sccsid[] = "$Id: v_itxt.c,v 10.21 2001/06/25 15:19:32 skimo Ex
(void)log_cursor(sp); \
}
-static u_int32_t set_txt_std __P((SCR *, VICMD *, u_int32_t));
+static u_int32_t set_txt_std(SCR *, VICMD *, u_int32_t);
/*
* v_iA -- [count]A
* Append text to the end of the line.
*
- * PUBLIC: int v_iA __P((SCR *, VICMD *));
+ * PUBLIC: int v_iA(SCR *, VICMD *);
*/
int
v_iA(SCR *sp, VICMD *vp)
@@ -83,7 +83,7 @@ v_iA(SCR *sp, VICMD *vp)
* [count]A
* Append text to the cursor position.
*
- * PUBLIC: int v_ia __P((SCR *, VICMD *));
+ * PUBLIC: int v_ia(SCR *, VICMD *);
*/
int
v_ia(SCR *sp, VICMD *vp)
@@ -120,7 +120,7 @@ v_ia(SCR *sp, VICMD *vp)
* v_iI -- [count]I
* Insert text at the first nonblank.
*
- * PUBLIC: int v_iI __P((SCR *, VICMD *));
+ * PUBLIC: int v_iI(SCR *, VICMD *);
*/
int
v_iI(SCR *sp, VICMD *vp)
@@ -139,7 +139,7 @@ v_iI(SCR *sp, VICMD *vp)
* [count]I
* Insert text at the cursor position.
*
- * PUBLIC: int v_ii __P((SCR *, VICMD *));
+ * PUBLIC: int v_ii(SCR *, VICMD *);
*/
int
v_ii(SCR *sp, VICMD *vp)
@@ -166,13 +166,13 @@ v_ii(SCR *sp, VICMD *vp)
}
enum which { o_cmd, O_cmd };
-static int io __P((SCR *, VICMD *, enum which));
+static int io(SCR *, VICMD *, enum which);
/*
* v_iO -- [count]O
* Insert text above this line.
*
- * PUBLIC: int v_iO __P((SCR *, VICMD *));
+ * PUBLIC: int v_iO(SCR *, VICMD *);
*/
int
v_iO(SCR *sp, VICMD *vp)
@@ -184,7 +184,7 @@ v_iO(SCR *sp, VICMD *vp)
* v_io -- [count]o
* Insert text after this line.
*
- * PUBLIC: int v_io __P((SCR *, VICMD *));
+ * PUBLIC: int v_io(SCR *, VICMD *);
*/
int
v_io(SCR *sp, VICMD *vp)
@@ -240,7 +240,7 @@ insert: p = L("");
* [buffer][count]S
* Change command.
*
- * PUBLIC: int v_change __P((SCR *, VICMD *));
+ * PUBLIC: int v_change(SCR *, VICMD *);
*/
int
v_change(SCR *sp, VICMD *vp)
@@ -380,7 +380,7 @@ v_change(SCR *sp, VICMD *vp)
* v_Replace -- [count]R
* Overwrite multiple characters.
*
- * PUBLIC: int v_Replace __P((SCR *, VICMD *));
+ * PUBLIC: int v_Replace(SCR *, VICMD *);
*/
int
v_Replace(SCR *sp, VICMD *vp)
@@ -414,7 +414,7 @@ v_Replace(SCR *sp, VICMD *vp)
* v_subst -- [buffer][count]s
* Substitute characters.
*
- * PUBLIC: int v_subst __P((SCR *, VICMD *));
+ * PUBLIC: int v_subst(SCR *, VICMD *);
*/
int
v_subst(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_left.c b/contrib/nvi/vi/v_left.c
index 2a8f6e6..dd7ccb8 100644
--- a/contrib/nvi/vi/v_left.c
+++ b/contrib/nvi/vi/v_left.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_left.c,v 10.9 2001/06/25 15:19:32 skimo Exp
* v_left -- [count]^H, [count]h
* Move left by columns.
*
- * PUBLIC: int v_left __P((SCR *, VICMD *));
+ * PUBLIC: int v_left(SCR *, VICMD *);
*/
int
v_left(SCR *sp, VICMD *vp)
@@ -66,7 +66,7 @@ v_left(SCR *sp, VICMD *vp)
* v_cfirst -- [count]_
* Move to the first non-blank character in a line.
*
- * PUBLIC: int v_cfirst __P((SCR *, VICMD *));
+ * PUBLIC: int v_cfirst(SCR *, VICMD *);
*/
int
v_cfirst(SCR *sp, VICMD *vp)
@@ -133,7 +133,7 @@ v_cfirst(SCR *sp, VICMD *vp)
* v_first -- ^
* Move to the first non-blank character in this line.
*
- * PUBLIC: int v_first __P((SCR *, VICMD *));
+ * PUBLIC: int v_first(SCR *, VICMD *);
*/
int
v_first(SCR *sp, VICMD *vp)
@@ -195,7 +195,7 @@ v_first(SCR *sp, VICMD *vp)
* requested column is past EOL, move to EOL. The nasty part is
* that we have to know character column widths to make this work.
*
- * PUBLIC: int v_ncol __P((SCR *, VICMD *));
+ * PUBLIC: int v_ncol(SCR *, VICMD *);
*/
int
v_ncol(SCR *sp, VICMD *vp)
@@ -255,7 +255,7 @@ v_ncol(SCR *sp, VICMD *vp)
* v_zero -- 0
* Move to the first column on this line.
*
- * PUBLIC: int v_zero __P((SCR *, VICMD *));
+ * PUBLIC: int v_zero(SCR *, VICMD *);
*/
int
v_zero(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_mark.c b/contrib/nvi/vi/v_mark.c
index 39ed0aa..2254fd3 100644
--- a/contrib/nvi/vi/v_mark.c
+++ b/contrib/nvi/vi/v_mark.c
@@ -26,13 +26,13 @@ static const char sccsid[] = "$Id: v_mark.c,v 10.12 2001/06/25 15:19:32 skimo Ex
#include "vi.h"
enum which {BQMARK, FQMARK};
-static int mark __P((SCR *, VICMD *, int, enum which));
+static int mark(SCR *, VICMD *, int, enum which);
/*
* v_mark -- m[a-z]
* Set a mark.
*
- * PUBLIC: int v_mark __P((SCR *, VICMD *));
+ * PUBLIC: int v_mark(SCR *, VICMD *);
*/
int
v_mark(SCR *sp, VICMD *vp)
@@ -53,7 +53,7 @@ v_mark(SCR *sp, VICMD *vp)
* people don't know it and will be delighted that you are able to tell
* them.
*
- * PUBLIC: int v_bmark __P((SCR *, VICMD *));
+ * PUBLIC: int v_bmark(SCR *, VICMD *);
*/
int
v_bmark(SCR *sp, VICMD *vp)
@@ -67,7 +67,7 @@ v_bmark(SCR *sp, VICMD *vp)
*
* Move to the first nonblank character of the line containing the mark.
*
- * PUBLIC: int v_fmark __P((SCR *, VICMD *));
+ * PUBLIC: int v_fmark(SCR *, VICMD *);
*/
int
v_fmark(SCR *sp, VICMD *vp)
@@ -79,7 +79,7 @@ v_fmark(SCR *sp, VICMD *vp)
* v_emark -- <mouse click>
* Mouse mark.
*
- * PUBLIC: int v_emark __P((SCR *, VICMD *));
+ * PUBLIC: int v_emark(SCR *, VICMD *);
*/
int
v_emark(SCR *sp, VICMD *vp)
@@ -196,22 +196,7 @@ mark(SCR *sp, VICMD *vp, int getmark, enum which cmd)
* Delete cursor motion was always to the start of the text region,
* regardless. Ignore other motion commands.
*/
-#ifdef HISTORICAL_PRACTICE
- if (ISCMD(vp->rkp, 'y')) {
- if ((cmd == BQMARK ||
- (cmd == FQMARK && vp->m_start.lno != vp->m_stop.lno)) &&
- (vp->m_start.lno > vp->m_stop.lno ||
- (vp->m_start.lno == vp->m_stop.lno &&
- vp->m_start.cno > vp->m_stop.cno)))
- vp->m_final = vp->m_stop;
- } else if (ISCMD(vp->rkp, 'd'))
- if (vp->m_start.lno > vp->m_stop.lno ||
- (vp->m_start.lno == vp->m_stop.lno &&
- vp->m_start.cno > vp->m_stop.cno))
- vp->m_final = vp->m_stop;
-#else
vp->m_final = vp->m_start;
-#endif
/*
* Forward marks are always line oriented, and it's set in the
diff --git a/contrib/nvi/vi/v_match.c b/contrib/nvi/vi/v_match.c
index 2fae58e..503c65c 100644
--- a/contrib/nvi/vi/v_match.c
+++ b/contrib/nvi/vi/v_match.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: v_match.c,v 10.11 2012/02/11 00:33:46 zy Exp
* v_match -- %
* Search to matching character.
*
- * PUBLIC: int v_match __P((SCR *, VICMD *));
+ * PUBLIC: int v_match(SCR *, VICMD *);
*/
int
v_match(SCR *sp, VICMD *vp)
@@ -39,7 +39,7 @@ v_match(SCR *sp, VICMD *vp)
VCS cs;
MARK *mp;
size_t cno, len, off;
- int cnt, isempty, matchc, startc, (*gc)__P((SCR *, VCS *));
+ int cnt, isempty, matchc, startc, (*gc)(SCR *, VCS *);
CHAR_T *p;
CHAR_T *cp;
const CHAR_T *match_chars;
@@ -154,7 +154,7 @@ nomatch: msgq(sp, M_BERR, "184|No match character on this line");
* v_buildmcs --
* Build the match character list.
*
- * PUBLIC: int v_buildmcs __P((SCR *, char *));
+ * PUBLIC: int v_buildmcs(SCR *, char *);
*/
int
v_buildmcs(SCR *sp, char *str)
diff --git a/contrib/nvi/vi/v_paragraph.c b/contrib/nvi/vi/v_paragraph.c
index 4ff4b15..2cc40b1 100644
--- a/contrib/nvi/vi/v_paragraph.c
+++ b/contrib/nvi/vi/v_paragraph.c
@@ -61,7 +61,7 @@ static const char sccsid[] = "$Id: v_paragraph.c,v 10.10 2001/06/25 15:19:32 ski
* Paragraphs are empty lines after text, formfeed characters, or values
* from the paragraph or section options.
*
- * PUBLIC: int v_paragraphf __P((SCR *, VICMD *));
+ * PUBLIC: int v_paragraphf(SCR *, VICMD *);
*/
int
v_paragraphf(SCR *sp, VICMD *vp)
@@ -199,7 +199,7 @@ eof: if (vp->m_start.lno == lno || vp->m_start.lno == lno - 1) {
* v_paragraphb -- [count]{
* Move backward count paragraphs.
*
- * PUBLIC: int v_paragraphb __P((SCR *, VICMD *));
+ * PUBLIC: int v_paragraphb(SCR *, VICMD *);
*/
int
v_paragraphb(SCR *sp, VICMD *vp)
@@ -306,7 +306,7 @@ found: vp->m_stop.lno = lno;
* v_buildps --
* Build the paragraph command search pattern.
*
- * PUBLIC: int v_buildps __P((SCR *, char *, char *));
+ * PUBLIC: int v_buildps(SCR *, char *, char *);
*/
int
v_buildps(SCR *sp, char *p_p, char *s_p)
diff --git a/contrib/nvi/vi/v_put.c b/contrib/nvi/vi/v_put.c
index a739bd1..8843c69 100644
--- a/contrib/nvi/vi/v_put.c
+++ b/contrib/nvi/vi/v_put.c
@@ -24,13 +24,13 @@ static const char sccsid[] = "$Id: v_put.c,v 10.6 2001/06/25 15:19:34 skimo Exp
#include "../common/common.h"
#include "vi.h"
-static void inc_buf __P((SCR *, VICMD *));
+static void inc_buf(SCR *, VICMD *);
/*
* v_Put -- [buffer]P
* Insert the contents of the buffer before the cursor.
*
- * PUBLIC: int v_Put __P((SCR *, VICMD *));
+ * PUBLIC: int v_Put(SCR *, VICMD *);
*/
int
v_Put(SCR *sp, VICMD *vp)
@@ -61,7 +61,7 @@ v_Put(SCR *sp, VICMD *vp)
* v_put -- [buffer]p
* Insert the contents of the buffer after the cursor.
*
- * PUBLIC: int v_put __P((SCR *, VICMD *));
+ * PUBLIC: int v_put(SCR *, VICMD *);
*/
int
v_put(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_redraw.c b/contrib/nvi/vi/v_redraw.c
index 979f37c..5549546 100644
--- a/contrib/nvi/vi/v_redraw.c
+++ b/contrib/nvi/vi/v_redraw.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_redraw.c,v 10.7 2001/06/25 15:19:34 skimo E
* v_redraw -- ^L, ^R
* Redraw the screen.
*
- * PUBLIC: int v_redraw __P((SCR *, VICMD *));
+ * PUBLIC: int v_redraw(SCR *, VICMD *);
*/
int
v_redraw(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_replace.c b/contrib/nvi/vi/v_replace.c
index 2a7ea97..e471df5 100644
--- a/contrib/nvi/vi/v_replace.c
+++ b/contrib/nvi/vi/v_replace.c
@@ -40,7 +40,7 @@ static const char sccsid[] = "$Id: v_replace.c,v 10.24 2001/06/25 15:19:34 skimo
* <literal> character, it required three <literal> characters after the
* command. This may not be right, but at least it's not insane.
*
- * PUBLIC: int v_replace __P((SCR *, VICMD *));
+ * PUBLIC: int v_replace(SCR *, VICMD *);
*/
int
v_replace(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_right.c b/contrib/nvi/vi/v_right.c
index 566f952..bfcf8dd 100644
--- a/contrib/nvi/vi/v_right.c
+++ b/contrib/nvi/vi/v_right.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_right.c,v 10.8 2001/06/25 15:19:34 skimo Ex
* v_right -- [count]' ', [count]l
* Move right by columns.
*
- * PUBLIC: int v_right __P((SCR *, VICMD *));
+ * PUBLIC: int v_right(SCR *, VICMD *);
*/
int
v_right(SCR *sp, VICMD *vp)
@@ -78,7 +78,7 @@ eol: v_eol(sp, NULL);
* v_dollar -- [count]$
* Move to the last column.
*
- * PUBLIC: int v_dollar __P((SCR *, VICMD *));
+ * PUBLIC: int v_dollar(SCR *, VICMD *);
*/
int
v_dollar(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_screen.c b/contrib/nvi/vi/v_screen.c
index d7932a4..97c60e4 100644
--- a/contrib/nvi/vi/v_screen.c
+++ b/contrib/nvi/vi/v_screen.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_screen.c,v 10.12 2001/06/25 15:19:34 skimo
* v_screen -- ^W
* Switch screens.
*
- * PUBLIC: int v_screen __P((SCR *, VICMD *));
+ * PUBLIC: int v_screen(SCR *, VICMD *);
*/
int
v_screen(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_scroll.c b/contrib/nvi/vi/v_scroll.c
index 71528a0..35c01a0 100644
--- a/contrib/nvi/vi/v_scroll.c
+++ b/contrib/nvi/vi/v_scroll.c
@@ -25,7 +25,7 @@ static const char sccsid[] = "$Id: v_scroll.c,v 10.12 2001/06/25 15:19:34 skimo
#include "../common/common.h"
#include "vi.h"
-static void goto_adjust __P((VICMD *));
+static void goto_adjust(VICMD *);
/*
* The historic vi had a problem in that all movements were by physical
@@ -64,7 +64,7 @@ static void goto_adjust __P((VICMD *));
* Go to first non-blank character of the line count, the last line
* of the file by default.
*
- * PUBLIC: int v_lgoto __P((SCR *, VICMD *));
+ * PUBLIC: int v_lgoto(SCR *, VICMD *);
*/
int
v_lgoto(SCR *sp, VICMD *vp)
@@ -101,7 +101,7 @@ v_lgoto(SCR *sp, VICMD *vp)
* Move to the first non-blank character of the logical line
* count - 1 from the top of the screen, 0 by default.
*
- * PUBLIC: int v_home __P((SCR *, VICMD *));
+ * PUBLIC: int v_home(SCR *, VICMD *);
*/
int
v_home(SCR *sp, VICMD *vp)
@@ -118,7 +118,7 @@ v_home(SCR *sp, VICMD *vp)
* Move to the first non-blank character of the logical line
* in the middle of the screen.
*
- * PUBLIC: int v_middle __P((SCR *, VICMD *));
+ * PUBLIC: int v_middle(SCR *, VICMD *);
*/
int
v_middle(SCR *sp, VICMD *vp)
@@ -139,7 +139,7 @@ v_middle(SCR *sp, VICMD *vp)
* Move to the first non-blank character of the logical line
* count - 1 from the bottom of the screen, 0 by default.
*
- * PUBLIC: int v_bottom __P((SCR *, VICMD *));
+ * PUBLIC: int v_bottom(SCR *, VICMD *);
*/
int
v_bottom(SCR *sp, VICMD *vp)
@@ -202,7 +202,7 @@ goto_adjust(VICMD *vp)
* v_up -- [count]^P, [count]k, [count]-
* Move up by lines.
*
- * PUBLIC: int v_up __P((SCR *, VICMD *));
+ * PUBLIC: int v_up(SCR *, VICMD *);
*/
int
v_up(SCR *sp, VICMD *vp)
@@ -224,7 +224,7 @@ v_up(SCR *sp, VICMD *vp)
* In a script window, send the line to the shell.
* In a regular window, move down by lines.
*
- * PUBLIC: int v_cr __P((SCR *, VICMD *));
+ * PUBLIC: int v_cr(SCR *, VICMD *);
*/
int
v_cr(SCR *sp, VICMD *vp)
@@ -245,7 +245,7 @@ v_cr(SCR *sp, VICMD *vp)
* v_down -- [count]^J, [count]^N, [count]j, [count]^M, [count]+
* Move down by lines.
*
- * PUBLIC: int v_down __P((SCR *, VICMD *));
+ * PUBLIC: int v_down(SCR *, VICMD *);
*/
int
v_down(SCR *sp, VICMD *vp)
@@ -266,7 +266,7 @@ v_down(SCR *sp, VICMD *vp)
* v_hpageup -- [count]^U
* Page up half screens.
*
- * PUBLIC: int v_hpageup __P((SCR *, VICMD *));
+ * PUBLIC: int v_hpageup(SCR *, VICMD *);
*/
int
v_hpageup(SCR *sp, VICMD *vp)
@@ -290,7 +290,7 @@ v_hpageup(SCR *sp, VICMD *vp)
* v_hpagedown -- [count]^D
* Page down half screens.
*
- * PUBLIC: int v_hpagedown __P((SCR *, VICMD *));
+ * PUBLIC: int v_hpagedown(SCR *, VICMD *);
*/
int
v_hpagedown(SCR *sp, VICMD *vp)
@@ -318,7 +318,7 @@ v_hpagedown(SCR *sp, VICMD *vp)
* if EOF was already displayed on the screen. This implementation does
* move to EOF in that case, making ^F more like the the historic ^D.
*
- * PUBLIC: int v_pagedown __P((SCR *, VICMD *));
+ * PUBLIC: int v_pagedown(SCR *, VICMD *);
*/
int
v_pagedown(SCR *sp, VICMD *vp)
@@ -364,7 +364,7 @@ v_pagedown(SCR *sp, VICMD *vp)
* if SOF was already displayed on the screen. This implementation does
* move to SOF in that case, making ^B more like the the historic ^U.
*
- * PUBLIC: int v_pageup __P((SCR *, VICMD *));
+ * PUBLIC: int v_pageup(SCR *, VICMD *);
*/
int
v_pageup(SCR *sp, VICMD *vp)
@@ -410,7 +410,7 @@ v_pageup(SCR *sp, VICMD *vp)
* v_lineup -- [count]^Y
* Page up by lines.
*
- * PUBLIC: int v_lineup __P((SCR *, VICMD *));
+ * PUBLIC: int v_lineup(SCR *, VICMD *);
*/
int
v_lineup(SCR *sp, VICMD *vp)
@@ -430,7 +430,7 @@ v_lineup(SCR *sp, VICMD *vp)
* v_linedown -- [count]^E
* Page down by lines.
*
- * PUBLIC: int v_linedown __P((SCR *, VICMD *));
+ * PUBLIC: int v_linedown(SCR *, VICMD *);
*/
int
v_linedown(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_search.c b/contrib/nvi/vi/v_search.c
index 1d6b260..5952583 100644
--- a/contrib/nvi/vi/v_search.c
+++ b/contrib/nvi/vi/v_search.c
@@ -28,14 +28,14 @@ static const char sccsid[] = "$Id: v_search.c,v 10.31 2012/02/08 07:26:59 zy Exp
#include "../common/common.h"
#include "vi.h"
-static int v_exaddr __P((SCR *, VICMD *, dir_t));
-static int v_search __P((SCR *, VICMD *, CHAR_T *, size_t, u_int, dir_t));
+static int v_exaddr(SCR *, VICMD *, dir_t);
+static int v_search(SCR *, VICMD *, CHAR_T *, size_t, u_int, dir_t);
/*
* v_srch -- [count]?RE[? offset]
* Ex address search backward.
*
- * PUBLIC: int v_searchb __P((SCR *, VICMD *));
+ * PUBLIC: int v_searchb(SCR *, VICMD *);
*/
int
v_searchb(SCR *sp, VICMD *vp)
@@ -47,7 +47,7 @@ v_searchb(SCR *sp, VICMD *vp)
* v_searchf -- [count]/RE[/ offset]
* Ex address search forward.
*
- * PUBLIC: int v_searchf __P((SCR *, VICMD *));
+ * PUBLIC: int v_searchf(SCR *, VICMD *);
*/
int
v_searchf(SCR *sp, VICMD *vp)
@@ -278,7 +278,7 @@ err2: vp->m_final.lno = s_lno;
* v_searchN -- N
* Reverse last search.
*
- * PUBLIC: int v_searchN __P((SCR *, VICMD *));
+ * PUBLIC: int v_searchN(SCR *, VICMD *);
*/
int
v_searchN(SCR *sp, VICMD *vp)
@@ -303,7 +303,7 @@ v_searchN(SCR *sp, VICMD *vp)
* v_searchn -- n
* Repeat last search.
*
- * PUBLIC: int v_searchn __P((SCR *, VICMD *));
+ * PUBLIC: int v_searchn(SCR *, VICMD *);
*/
int
v_searchn(SCR *sp, VICMD *vp)
@@ -338,7 +338,7 @@ is_special(CHAR_T c)
* v_searchw -- [count]^A
* Search for the word under the cursor.
*
- * PUBLIC: int v_searchw __P((SCR *, VICMD *));
+ * PUBLIC: int v_searchw(SCR *, VICMD *);
*/
int
v_searchw(SCR *sp, VICMD *vp)
@@ -450,7 +450,7 @@ v_search(SCR *sp, VICMD *vp, CHAR_T *ptrn, size_t plen, u_int flags, dir_t dir)
* 'k' and put would no longer work correctly. In any case, we try to do
* the right thing, but it's not going to exactly match historic practice.
*
- * PUBLIC: int v_correct __P((SCR *, VICMD *, int));
+ * PUBLIC: int v_correct(SCR *, VICMD *, int);
*/
int
v_correct(SCR *sp, VICMD *vp, int isdelta)
diff --git a/contrib/nvi/vi/v_section.c b/contrib/nvi/vi/v_section.c
index e769cda..3613afe 100644
--- a/contrib/nvi/vi/v_section.c
+++ b/contrib/nvi/vi/v_section.c
@@ -59,7 +59,7 @@ static const char sccsid[] = "$Id: v_section.c,v 10.10 2001/06/25 15:19:35 skimo
* a section, it did NOT include the matched line. If it matched a }, it
* did include the line. No clue why.
*
- * PUBLIC: int v_sectionf __P((SCR *, VICMD *));
+ * PUBLIC: int v_sectionf(SCR *, VICMD *);
*/
int
v_sectionf(SCR *sp, VICMD *vp)
@@ -166,7 +166,7 @@ ret2: if (ISMOTION(vp)) {
* v_sectionb -- [count][[
* Move backward count sections/functions.
*
- * PUBLIC: int v_sectionb __P((SCR *, VICMD *));
+ * PUBLIC: int v_sectionb(SCR *, VICMD *);
*/
int
v_sectionb(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_sentence.c b/contrib/nvi/vi/v_sentence.c
index ddbc6c7..df10839 100644
--- a/contrib/nvi/vi/v_sentence.c
+++ b/contrib/nvi/vi/v_sentence.c
@@ -49,7 +49,7 @@ static const char sccsid[] = "$Id: v_sentence.c,v 10.9 2001/06/25 15:19:35 skimo
* v_sentencef -- [count])
* Move forward count sentences.
*
- * PUBLIC: int v_sentencef __P((SCR *, VICMD *));
+ * PUBLIC: int v_sentencef(SCR *, VICMD *);
*/
int
v_sentencef(SCR *sp, VICMD *vp)
@@ -188,7 +188,7 @@ okret: vp->m_stop.lno = cs.cs_lno;
* v_sentenceb -- [count](
* Move backward count sentences.
*
- * PUBLIC: int v_sentenceb __P((SCR *, VICMD *));
+ * PUBLIC: int v_sentenceb(SCR *, VICMD *);
*/
int
v_sentenceb(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_status.c b/contrib/nvi/vi/v_status.c
index 82fe74b..0d9afd0 100644
--- a/contrib/nvi/vi/v_status.c
+++ b/contrib/nvi/vi/v_status.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_status.c,v 10.10 2001/06/25 15:19:35 skimo
* v_status -- ^G
* Show the file status.
*
- * PUBLIC: int v_status __P((SCR *, VICMD *));
+ * PUBLIC: int v_status(SCR *, VICMD *);
*/
int
v_status(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_txt.c b/contrib/nvi/vi/v_txt.c
index 1348b27..be4309a 100644
--- a/contrib/nvi/vi/v_txt.c
+++ b/contrib/nvi/vi/v_txt.c
@@ -29,25 +29,25 @@ static const char sccsid[] = "$Id: v_txt.c,v 11.5 2013/05/19 20:37:45 bentley Ex
#include "../common/common.h"
#include "vi.h"
-static int txt_abbrev __P((SCR *, TEXT *, CHAR_T *, int, int *, int *));
-static void txt_ai_resolve __P((SCR *, TEXT *, int *));
-static TEXT *txt_backup __P((SCR *, TEXTH *, TEXT *, u_int32_t *));
-static int txt_dent __P((SCR *, TEXT *, int));
-static int txt_emark __P((SCR *, TEXT *, size_t));
-static void txt_err __P((SCR *, TEXTH *));
-static int txt_fc __P((SCR *, TEXT *, int *));
-static int txt_fc_col __P((SCR *, int, ARGS **));
-static int txt_hex __P((SCR *, TEXT *));
-static int txt_insch __P((SCR *, TEXT *, CHAR_T *, u_int));
-static int txt_isrch __P((SCR *, VICMD *, TEXT *, u_int8_t *));
-static int txt_map_end __P((SCR *));
-static int txt_map_init __P((SCR *));
-static int txt_margin __P((SCR *, TEXT *, TEXT *, int *, u_int32_t));
-static void txt_nomorech __P((SCR *));
-static void txt_Rresolve __P((SCR *, TEXTH *, TEXT *, const size_t));
-static int txt_resolve __P((SCR *, TEXTH *, u_int32_t));
-static int txt_showmatch __P((SCR *, TEXT *));
-static void txt_unmap __P((SCR *, TEXT *, u_int32_t *));
+static int txt_abbrev(SCR *, TEXT *, CHAR_T *, int, int *, int *);
+static void txt_ai_resolve(SCR *, TEXT *, int *);
+static TEXT *txt_backup(SCR *, TEXTH *, TEXT *, u_int32_t *);
+static int txt_dent(SCR *, TEXT *, int);
+static int txt_emark(SCR *, TEXT *, size_t);
+static void txt_err(SCR *, TEXTH *);
+static int txt_fc(SCR *, TEXT *, int *);
+static int txt_fc_col(SCR *, int, ARGS **);
+static int txt_hex(SCR *, TEXT *);
+static int txt_insch(SCR *, TEXT *, CHAR_T *, u_int);
+static int txt_isrch(SCR *, VICMD *, TEXT *, u_int8_t *);
+static int txt_map_end(SCR *);
+static int txt_map_init(SCR *);
+static int txt_margin(SCR *, TEXT *, TEXT *, int *, u_int32_t);
+static void txt_nomorech(SCR *);
+static void txt_Rresolve(SCR *, TEXTH *, TEXT *, const size_t);
+static int txt_resolve(SCR *, TEXTH *, u_int32_t);
+static int txt_showmatch(SCR *, TEXT *);
+static void txt_unmap(SCR *, TEXT *, u_int32_t *);
/* Cursor character (space is hard to track on the screen). */
#if defined(DEBUG) && 0
@@ -59,7 +59,7 @@ static void txt_unmap __P((SCR *, TEXT *, u_int32_t *));
* v_tcmd --
* Fill a buffer from the terminal for vi.
*
- * PUBLIC: int v_tcmd __P((SCR *, VICMD *, ARG_CHAR_T, u_int));
+ * PUBLIC: int v_tcmd(SCR *, VICMD *, ARG_CHAR_T, u_int);
*/
int
v_tcmd(SCR *sp, VICMD *vp, ARG_CHAR_T prompt, u_int flags)
@@ -234,8 +234,8 @@ txt_map_end(SCR *sp)
* v_txt --
* Vi text input.
*
- * PUBLIC: int v_txt __P((SCR *, VICMD *, MARK *,
- * PUBLIC: const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t));
+ * PUBLIC: int v_txt(SCR *, VICMD *, MARK *,
+ * PUBLIC: const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t);
*/
int
v_txt(
@@ -1760,7 +1760,7 @@ txt_ai_resolve(SCR *sp, TEXT *tp, int *changedp)
* Handle autoindent. If aitp isn't NULL, use it, otherwise,
* retrieve the line.
*
- * PUBLIC: int v_txt_auto __P((SCR *, recno_t, TEXT *, size_t, TEXT *));
+ * PUBLIC: int v_txt_auto(SCR *, recno_t, TEXT *, size_t, TEXT *);
*/
int
v_txt_auto(SCR *sp, recno_t lno, TEXT *aitp, size_t len, TEXT *tp)
diff --git a/contrib/nvi/vi/v_ulcase.c b/contrib/nvi/vi/v_ulcase.c
index 10d3d35..9e306ca 100644
--- a/contrib/nvi/vi/v_ulcase.c
+++ b/contrib/nvi/vi/v_ulcase.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_ulcase.c,v 10.12 2011/12/02 19:58:32 zy Exp
#include "../common/common.h"
#include "vi.h"
-static int ulcase __P((SCR *, recno_t, CHAR_T *, size_t, size_t, size_t));
+static int ulcase(SCR *, recno_t, CHAR_T *, size_t, size_t, size_t);
/*
* v_ulcase -- [count]~
@@ -44,7 +44,7 @@ static int ulcase __P((SCR *, recno_t, CHAR_T *, size_t, size_t, size_t));
* if there had been an associated motion, but it's too late to make
* that the default now.
*
- * PUBLIC: int v_ulcase __P((SCR *, VICMD *));
+ * PUBLIC: int v_ulcase(SCR *, VICMD *);
*/
int
v_ulcase(SCR *sp, VICMD *vp)
@@ -102,7 +102,7 @@ v_ulcase(SCR *sp, VICMD *vp)
* v_mulcase -- [count]~[count]motion
* Toggle upper & lower case letters over a range.
*
- * PUBLIC: int v_mulcase __P((SCR *, VICMD *));
+ * PUBLIC: int v_mulcase(SCR *, VICMD *);
*/
int
v_mulcase(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_undo.c b/contrib/nvi/vi/v_undo.c
index 2bbd920..6cac736 100644
--- a/contrib/nvi/vi/v_undo.c
+++ b/contrib/nvi/vi/v_undo.c
@@ -31,7 +31,7 @@ static const char sccsid[] = "$Id: v_undo.c,v 10.6 2001/06/25 15:19:36 skimo Exp
* v_Undo -- U
* Undo changes to this line.
*
- * PUBLIC: int v_Undo __P((SCR *, VICMD *));
+ * PUBLIC: int v_Undo(SCR *, VICMD *);
*/
int
v_Undo(SCR *sp, VICMD *vp)
@@ -65,7 +65,7 @@ v_Undo(SCR *sp, VICMD *vp)
* v_undo -- u
* Undo the last change.
*
- * PUBLIC: int v_undo __P((SCR *, VICMD *));
+ * PUBLIC: int v_undo(SCR *, VICMD *);
*/
int
v_undo(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_util.c b/contrib/nvi/vi/v_util.c
index 6348ca7..f8f3792 100644
--- a/contrib/nvi/vi/v_util.c
+++ b/contrib/nvi/vi/v_util.c
@@ -32,7 +32,7 @@ static const char sccsid[] = "$Id: v_util.c,v 10.14 2001/06/25 15:19:36 skimo Ex
* v_eof --
* Vi end-of-file error.
*
- * PUBLIC: void v_eof __P((SCR *, MARK *));
+ * PUBLIC: void v_eof(SCR *, MARK *);
*/
void
v_eof(SCR *sp, MARK *mp)
@@ -55,7 +55,7 @@ v_eof(SCR *sp, MARK *mp)
* v_eol --
* Vi end-of-line error.
*
- * PUBLIC: void v_eol __P((SCR *, MARK *));
+ * PUBLIC: void v_eol(SCR *, MARK *);
*/
void
v_eol(SCR *sp, MARK *mp)
@@ -78,7 +78,7 @@ v_eol(SCR *sp, MARK *mp)
* v_nomove --
* Vi no cursor movement error.
*
- * PUBLIC: void v_nomove __P((SCR *));
+ * PUBLIC: void v_nomove(SCR *);
*/
void
v_nomove(SCR *sp)
@@ -90,7 +90,7 @@ v_nomove(SCR *sp)
* v_sof --
* Vi start-of-file error.
*
- * PUBLIC: void v_sof __P((SCR *, MARK *));
+ * PUBLIC: void v_sof(SCR *, MARK *);
*/
void
v_sof(SCR *sp, MARK *mp)
@@ -105,7 +105,7 @@ v_sof(SCR *sp, MARK *mp)
* v_sol --
* Vi start-of-line error.
*
- * PUBLIC: void v_sol __P((SCR *));
+ * PUBLIC: void v_sol(SCR *);
*/
void
v_sol(SCR *sp)
@@ -117,7 +117,7 @@ v_sol(SCR *sp)
* v_isempty --
* Return if the line contains nothing but white-space characters.
*
- * PUBLIC: int v_isempty __P((CHAR_T *, size_t));
+ * PUBLIC: int v_isempty(CHAR_T *, size_t);
*/
int
v_isempty(CHAR_T *p, size_t len)
@@ -132,7 +132,7 @@ v_isempty(CHAR_T *p, size_t len)
* v_emsg --
* Display a few common vi messages.
*
- * PUBLIC: void v_emsg __P((SCR *, char *, vim_t));
+ * PUBLIC: void v_emsg(SCR *, char *, vim_t);
*/
void
v_emsg(SCR *sp, char *p, vim_t which)
diff --git a/contrib/nvi/vi/v_word.c b/contrib/nvi/vi/v_word.c
index 6336e2d..f07dbb6 100644
--- a/contrib/nvi/vi/v_word.c
+++ b/contrib/nvi/vi/v_word.c
@@ -66,15 +66,15 @@ static const char sccsid[] = "$Id: v_word.c,v 10.7 2011/12/27 00:49:31 zy Exp $"
enum which {BIGWORD, LITTLEWORD};
-static int bword __P((SCR *, VICMD *, enum which));
-static int eword __P((SCR *, VICMD *, enum which));
-static int fword __P((SCR *, VICMD *, enum which));
+static int bword(SCR *, VICMD *, enum which);
+static int eword(SCR *, VICMD *, enum which);
+static int fword(SCR *, VICMD *, enum which);
/*
* v_wordW -- [count]W
* Move forward a bigword at a time.
*
- * PUBLIC: int v_wordW __P((SCR *, VICMD *));
+ * PUBLIC: int v_wordW(SCR *, VICMD *);
*/
int
v_wordW(SCR *sp, VICMD *vp)
@@ -86,7 +86,7 @@ v_wordW(SCR *sp, VICMD *vp)
* v_wordw -- [count]w
* Move forward a word at a time.
*
- * PUBLIC: int v_wordw __P((SCR *, VICMD *));
+ * PUBLIC: int v_wordw(SCR *, VICMD *);
*/
int
v_wordw(SCR *sp, VICMD *vp)
@@ -234,7 +234,7 @@ ret: if (!ISMOTION(vp) &&
* v_wordE -- [count]E
* Move forward to the end of the bigword.
*
- * PUBLIC: int v_wordE __P((SCR *, VICMD *));
+ * PUBLIC: int v_wordE(SCR *, VICMD *);
*/
int
v_wordE(SCR *sp, VICMD *vp)
@@ -246,7 +246,7 @@ v_wordE(SCR *sp, VICMD *vp)
* v_worde -- [count]e
* Move forward to the end of the word.
*
- * PUBLIC: int v_worde __P((SCR *, VICMD *));
+ * PUBLIC: int v_worde(SCR *, VICMD *);
*/
int
v_worde(SCR *sp, VICMD *vp)
@@ -380,7 +380,7 @@ ret: if (!ISMOTION(vp) &&
* v_WordB -- [count]B
* Move backward a bigword at a time.
*
- * PUBLIC: int v_wordB __P((SCR *, VICMD *));
+ * PUBLIC: int v_wordB(SCR *, VICMD *);
*/
int
v_wordB(SCR *sp, VICMD *vp)
@@ -392,7 +392,7 @@ v_wordB(SCR *sp, VICMD *vp)
* v_wordb -- [count]b
* Move backward a word at a time.
*
- * PUBLIC: int v_wordb __P((SCR *, VICMD *));
+ * PUBLIC: int v_wordb(SCR *, VICMD *);
*/
int
v_wordb(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_xchar.c b/contrib/nvi/vi/v_xchar.c
index a0c1a69..52fa03a 100644
--- a/contrib/nvi/vi/v_xchar.c
+++ b/contrib/nvi/vi/v_xchar.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_xchar.c,v 10.10 2001/06/25 15:19:36 skimo E
* v_xchar -- [buffer] [count]x
* Deletes the character(s) on which the cursor sits.
*
- * PUBLIC: int v_xchar __P((SCR *, VICMD *));
+ * PUBLIC: int v_xchar(SCR *, VICMD *);
*/
int
v_xchar(SCR *sp, VICMD *vp)
@@ -75,7 +75,7 @@ nodel: msgq(sp, M_BERR, "206|No characters to delete");
* Deletes the character(s) immediately before the current cursor
* position.
*
- * PUBLIC: int v_Xchar __P((SCR *, VICMD *));
+ * PUBLIC: int v_Xchar(SCR *, VICMD *);
*/
int
v_Xchar(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_yank.c b/contrib/nvi/vi/v_yank.c
index 7b02cce..7322f73 100644
--- a/contrib/nvi/vi/v_yank.c
+++ b/contrib/nvi/vi/v_yank.c
@@ -39,7 +39,7 @@ static const char sccsid[] = "$Id: v_yank.c,v 10.10 2001/06/25 15:19:36 skimo Ex
* to the line and column marked by a. Hopefully, the motion component code
* got it right... Unlike delete, we make no adjustments here.
*
- * PUBLIC: int v_yank __P((SCR *, VICMD *));
+ * PUBLIC: int v_yank(SCR *, VICMD *);
*/
int
v_yank(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/v_z.c b/contrib/nvi/vi/v_z.c
index 9d4ef64..c95c82d 100644
--- a/contrib/nvi/vi/v_z.c
+++ b/contrib/nvi/vi/v_z.c
@@ -28,7 +28,7 @@ static const char sccsid[] = "$Id: v_z.c,v 10.13 2011/12/02 17:26:59 zy Exp $";
* v_z -- [count]z[count][-.+^<CR>]
* Move the screen.
*
- * PUBLIC: int v_z __P((SCR *, VICMD *));
+ * PUBLIC: int v_z(SCR *, VICMD *);
*/
int
v_z(SCR *sp, VICMD *vp)
@@ -131,7 +131,7 @@ v_z(SCR *sp, VICMD *vp)
* vs_crel --
* Change the relative size of the current screen.
*
- * PUBLIC: int vs_crel __P((SCR *, long));
+ * PUBLIC: int vs_crel(SCR *, long);
*/
int
vs_crel(SCR *sp, long int count)
diff --git a/contrib/nvi/vi/v_zexit.c b/contrib/nvi/vi/v_zexit.c
index a2decd6..b9805b3 100644
--- a/contrib/nvi/vi/v_zexit.c
+++ b/contrib/nvi/vi/v_zexit.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: v_zexit.c,v 10.7 2001/06/25 15:19:37 skimo Ex
* v_zexit -- ZZ
* Save the file and exit.
*
- * PUBLIC: int v_zexit __P((SCR *, VICMD *));
+ * PUBLIC: int v_zexit(SCR *, VICMD *);
*/
int
v_zexit(SCR *sp, VICMD *vp)
diff --git a/contrib/nvi/vi/vi.c b/contrib/nvi/vi/vi.c
index aafdbd1..144d903 100644
--- a/contrib/nvi/vi/vi.c
+++ b/contrib/nvi/vi/vi.c
@@ -34,16 +34,16 @@ typedef enum {
} gcret_t;
static VIKEYS const
- *v_alias __P((SCR *, VICMD *, VIKEYS const *));
-static gcret_t v_cmd __P((SCR *, VICMD *, VICMD *, VICMD *, int *, int *));
-static int v_count __P((SCR *, ARG_CHAR_T, u_long *));
-static void v_dtoh __P((SCR *));
-static int v_init __P((SCR *));
-static gcret_t v_key __P((SCR *, int, EVENT *, u_int32_t));
-static int v_motion __P((SCR *, VICMD *, VICMD *, int *));
+ *v_alias(SCR *, VICMD *, VIKEYS const *);
+static gcret_t v_cmd(SCR *, VICMD *, VICMD *, VICMD *, int *, int *);
+static int v_count(SCR *, ARG_CHAR_T, u_long *);
+static void v_dtoh(SCR *);
+static int v_init(SCR *);
+static gcret_t v_key(SCR *, int, EVENT *, u_int32_t);
+static int v_motion(SCR *, VICMD *, VICMD *, int *);
#if defined(DEBUG) && defined(COMLOG)
-static void v_comlog __P((SCR *, VICMD *));
+static void v_comlog(SCR *, VICMD *);
#endif
/*
@@ -58,7 +58,7 @@ static void v_comlog __P((SCR *, VICMD *));
* vi --
* Main vi command loop.
*
- * PUBLIC: int vi __P((SCR **));
+ * PUBLIC: int vi(SCR **);
*/
int
vi(SCR **spp)
@@ -1031,7 +1031,7 @@ v_dtoh(SCR *sp)
* v_curword --
* Get the word (tagstring, actually) the cursor is on.
*
- * PUBLIC: int v_curword __P((SCR *));
+ * PUBLIC: int v_curword(SCR *);
*/
int
v_curword(SCR *sp)
@@ -1216,7 +1216,6 @@ v_key(
break;
case E_WRESIZE:
return (GC_ERR);
- /* FALLTHROUGH */
default:
v_event_err(sp, evp);
return (GC_ERR);
diff --git a/contrib/nvi/vi/vi.h b/contrib/nvi/vi/vi.h
index 2cfbb99..eeb6b9f 100644
--- a/contrib/nvi/vi/vi.h
+++ b/contrib/nvi/vi/vi.h
@@ -126,7 +126,7 @@ typedef struct _vicmd {
/* Vi command table structure. */
struct _vikeys { /* Underlying function. */
- int (*func) __P((SCR *, VICMD *));
+ int (*func)(SCR *, VICMD *);
#define V_ABS 0x00004000 /* Absolute movement, set '' mark. */
#define V_ABS_C 0x00008000 /* V_ABS: if the line/column changed. */
#define V_ABS_L 0x00010000 /* V_ABS: if the line changed. */
@@ -161,12 +161,12 @@ typedef struct _vcs {
int cs_flags; /* Return flags. */
} VCS;
-int cs_bblank __P((SCR *, VCS *));
-int cs_fblank __P((SCR *, VCS *));
-int cs_fspace __P((SCR *, VCS *));
-int cs_init __P((SCR *, VCS *));
-int cs_next __P((SCR *, VCS *));
-int cs_prev __P((SCR *, VCS *));
+int cs_bblank(SCR *, VCS *);
+int cs_fblank(SCR *, VCS *);
+int cs_fspace(SCR *, VCS *);
+int cs_init(SCR *, VCS *);
+int cs_next(SCR *, VCS *);
+int cs_prev(SCR *, VCS *);
/*
* We use a single "window" for each set of vi screens. The model would be
diff --git a/contrib/nvi/vi/vs_line.c b/contrib/nvi/vi/vs_line.c
index dc12a3a..e523076 100644
--- a/contrib/nvi/vi/vs_line.c
+++ b/contrib/nvi/vi/vs_line.c
@@ -35,7 +35,7 @@ static const char sccsid[] = "$Id: vs_line.c,v 10.40 2012/02/13 19:22:25 zy Exp
* vs_line --
* Update one line on the screen.
*
- * PUBLIC: int vs_line __P((SCR *, SMAP *, size_t *, size_t *));
+ * PUBLIC: int vs_line(SCR *, SMAP *, size_t *, size_t *);
*/
int
vs_line(SCR *sp, SMAP *smp, size_t *yp, size_t *xp)
@@ -482,7 +482,7 @@ ret1: (void)gp->scr_move(sp, oldy, oldx);
* vs_number --
* Repaint the numbers on all the lines.
*
- * PUBLIC: int vs_number __P((SCR *));
+ * PUBLIC: int vs_number(SCR *);
*/
int
vs_number(SCR *sp)
diff --git a/contrib/nvi/vi/vs_msg.c b/contrib/nvi/vi/vs_msg.c
index 32b2755..2eb88e4 100644
--- a/contrib/nvi/vi/vs_msg.c
+++ b/contrib/nvi/vi/vs_msg.c
@@ -37,11 +37,11 @@ typedef enum {
*/
} sw_t;
-static void vs_divider __P((SCR *));
-static void vs_msgsave __P((SCR *, mtype_t, char *, size_t));
-static void vs_output __P((SCR *, mtype_t, const char *, int));
-static void vs_scroll __P((SCR *, int *, sw_t));
-static void vs_wait __P((SCR *, int *, sw_t));
+static void vs_divider(SCR *);
+static void vs_msgsave(SCR *, mtype_t, char *, size_t);
+static void vs_output(SCR *, mtype_t, const char *, int);
+static void vs_scroll(SCR *, int *, sw_t);
+static void vs_wait(SCR *, int *, sw_t);
/*
* vs_busy --
@@ -53,7 +53,7 @@ static void vs_wait __P((SCR *, int *, sw_t));
* messages, e.g. X11 clock icons, should set their scr_busy function to the
* correct function before calling the main editor routine.
*
- * PUBLIC: void vs_busy __P((SCR *, const char *, busy_t));
+ * PUBLIC: void vs_busy(SCR *, const char *, busy_t);
*/
void
vs_busy(SCR *sp, const char *msg, busy_t btype)
@@ -142,7 +142,7 @@ vs_busy(SCR *sp, const char *msg, busy_t btype)
* vs_home --
* Home the cursor to the bottom row, left-most column.
*
- * PUBLIC: void vs_home __P((SCR *));
+ * PUBLIC: void vs_home(SCR *);
*/
void
vs_home(SCR *sp)
@@ -155,7 +155,7 @@ vs_home(SCR *sp)
* vs_update --
* Update a command.
*
- * PUBLIC: void vs_update __P((SCR *, const char *, const CHAR_T *));
+ * PUBLIC: void vs_update(SCR *, const char *, const CHAR_T *);
*/
void
vs_update(SCR *sp, const char *m1, const CHAR_T *m2)
@@ -225,7 +225,7 @@ vs_update(SCR *sp, const char *m1, const CHAR_T *m2)
* alternate method of displaying messages, e.g. dialog boxes, should set their
* scr_msg function to the correct function before calling the editor.
*
- * PUBLIC: void vs_msg __P((SCR *, mtype_t, char *, size_t));
+ * PUBLIC: void vs_msg(SCR *, mtype_t, char *, size_t);
*/
void
vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len)
@@ -506,7 +506,7 @@ vs_output(SCR *sp, mtype_t mtype, const char *line, int llen)
* This routine is called when exiting a colon command to resolve any ex
* output that may have occurred.
*
- * PUBLIC: int vs_ex_resolve __P((SCR *, int *));
+ * PUBLIC: int vs_ex_resolve(SCR *, int *);
*/
int
vs_ex_resolve(SCR *sp, int *continuep)
@@ -630,7 +630,7 @@ vs_ex_resolve(SCR *sp, int *continuep)
* vs_resolve --
* Deal with message output.
*
- * PUBLIC: int vs_resolve __P((SCR *, SCR *, int));
+ * PUBLIC: int vs_resolve(SCR *, SCR *, int);
*/
int
vs_resolve(SCR *sp, SCR *csp, int forcewait)
diff --git a/contrib/nvi/vi/vs_refresh.c b/contrib/nvi/vi/vs_refresh.c
index 8343b80..68b51a1 100644
--- a/contrib/nvi/vi/vs_refresh.c
+++ b/contrib/nvi/vi/vs_refresh.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: vs_refresh.c,v 10.53 2013/11/01 11:57:36 zy Exp $";
+static const char sccsid[] = "$Id: vs_refresh.c,v 10.54 2015/04/08 16:32:49 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -30,14 +30,14 @@ static const char sccsid[] = "$Id: vs_refresh.c,v 10.53 2013/11/01 11:57:36 zy E
#define UPDATE_CURSOR 0x01 /* Update the cursor. */
#define UPDATE_SCREEN 0x02 /* Flush to screen. */
-static void vs_modeline __P((SCR *));
-static int vs_paint __P((SCR *, u_int));
+static void vs_modeline(SCR *);
+static int vs_paint(SCR *, u_int);
/*
* v_repaint --
* Repaint selected lines from the screen.
*
- * PUBLIC: int vs_repaint __P((SCR *, EVENT *));
+ * PUBLIC: int vs_repaint(SCR *, EVENT *);
*/
int
vs_repaint(
@@ -59,7 +59,7 @@ vs_repaint(
* vs_refresh --
* Refresh all screens.
*
- * PUBLIC: int vs_refresh __P((SCR *, int));
+ * PUBLIC: int vs_refresh(SCR *, int);
*/
int
vs_refresh(
@@ -593,7 +593,7 @@ slow: for (smp = HMAP; smp->lno != LNO; ++smp);
* for the number option offset.
*/
cnt = vs_columns(sp, NULL, LNO, &CNO, NULL);
- if (O_ISSET(sp, O_NUMBER) && cnt >= O_NUMBER_LENGTH)
+ if (O_ISSET(sp, O_NUMBER))
cnt -= O_NUMBER_LENGTH;
/* Adjust the window towards the beginning of the line. */
diff --git a/contrib/nvi/vi/vs_relative.c b/contrib/nvi/vi/vs_relative.c
index 5f25b51..abeb70e 100644
--- a/contrib/nvi/vi/vs_relative.c
+++ b/contrib/nvi/vi/vs_relative.c
@@ -29,7 +29,7 @@ static const char sccsid[] = "$Id: vs_relative.c,v 10.19 2011/12/01 15:22:59 zy
* vs_column --
* Return the logical column of the cursor in the line.
*
- * PUBLIC: int vs_column __P((SCR *, size_t *));
+ * PUBLIC: int vs_column(SCR *, size_t *);
*/
int
vs_column(SCR *sp, size_t *colp)
@@ -50,7 +50,7 @@ vs_column(SCR *sp, size_t *colp)
* the physical character column within the line, including space
* required for the O_NUMBER and O_LIST options.
*
- * PUBLIC: size_t vs_screens __P((SCR *, recno_t, size_t *));
+ * PUBLIC: size_t vs_screens(SCR *, recno_t, size_t *);
*/
size_t
vs_screens(SCR *sp, recno_t lno, size_t *cnop)
@@ -93,7 +93,7 @@ vs_screens(SCR *sp, recno_t lno, size_t *cnop)
* Return the screen columns necessary to display the line, or,
* if specified, the physical character column within the line.
*
- * PUBLIC: size_t vs_columns __P((SCR *, CHAR_T *, recno_t, size_t *, size_t *));
+ * PUBLIC: size_t vs_columns(SCR *, CHAR_T *, recno_t, size_t *, size_t *);
*/
size_t
vs_columns(SCR *sp, CHAR_T *lp, recno_t lno, size_t *cnop, size_t *diffp)
@@ -192,7 +192,7 @@ done: if (diffp != NULL) /* XXX */
* character closest to the currently most attractive character
* position (which is stored as a screen column).
*
- * PUBLIC: size_t vs_rcm __P((SCR *, recno_t, int));
+ * PUBLIC: size_t vs_rcm(SCR *, recno_t, int);
*/
size_t
vs_rcm(SCR *sp, recno_t lno, int islast)
@@ -218,7 +218,7 @@ vs_rcm(SCR *sp, recno_t lno, int islast)
* Return the physical column from the line that will display a
* character closest to the specified screen column.
*
- * PUBLIC: size_t vs_colpos __P((SCR *, recno_t, size_t));
+ * PUBLIC: size_t vs_colpos(SCR *, recno_t, size_t);
*/
size_t
vs_colpos(SCR *sp, recno_t lno, size_t cno)
diff --git a/contrib/nvi/vi/vs_smap.c b/contrib/nvi/vi/vs_smap.c
index 0ab2df9..9dcb8d4 100644
--- a/contrib/nvi/vi/vs_smap.c
+++ b/contrib/nvi/vi/vs_smap.c
@@ -26,20 +26,20 @@ static const char sccsid[] = "$Id: vs_smap.c,v 10.31 2011/02/26 13:56:21 skimo E
#include "../common/common.h"
#include "vi.h"
-static int vs_deleteln __P((SCR *, int));
-static int vs_insertln __P((SCR *, int));
-static int vs_sm_delete __P((SCR *, recno_t));
-static int vs_sm_down __P((SCR *, MARK *, recno_t, scroll_t, SMAP *));
-static int vs_sm_erase __P((SCR *));
-static int vs_sm_insert __P((SCR *, recno_t));
-static int vs_sm_reset __P((SCR *, recno_t));
-static int vs_sm_up __P((SCR *, MARK *, recno_t, scroll_t, SMAP *));
+static int vs_deleteln(SCR *, int);
+static int vs_insertln(SCR *, int);
+static int vs_sm_delete(SCR *, recno_t);
+static int vs_sm_down(SCR *, MARK *, recno_t, scroll_t, SMAP *);
+static int vs_sm_erase(SCR *);
+static int vs_sm_insert(SCR *, recno_t);
+static int vs_sm_reset(SCR *, recno_t);
+static int vs_sm_up(SCR *, MARK *, recno_t, scroll_t, SMAP *);
/*
* vs_change --
* Make a change to the screen.
*
- * PUBLIC: int vs_change __P((SCR *, recno_t, lnop_t));
+ * PUBLIC: int vs_change(SCR *, recno_t, lnop_t);
*/
int
vs_change(SCR *sp, recno_t lno, lnop_t op)
@@ -171,7 +171,7 @@ vs_change(SCR *sp, recno_t lno, lnop_t op)
* slot is already filled in, P_BOTTOM means that the TMAP slot is
* already filled in, and we just finish up the job.
*
- * PUBLIC: int vs_sm_fill __P((SCR *, recno_t, pos_t));
+ * PUBLIC: int vs_sm_fill(SCR *, recno_t, pos_t);
*/
int
vs_sm_fill(SCR *sp, recno_t lno, pos_t pos)
@@ -512,7 +512,7 @@ vs_sm_reset(SCR *sp, recno_t lno)
* Scroll the SMAP up/down count logical lines. Different
* semantics based on the vi command, *sigh*.
*
- * PUBLIC: int vs_sm_scroll __P((SCR *, MARK *, recno_t, scroll_t));
+ * PUBLIC: int vs_sm_scroll(SCR *, MARK *, recno_t, scroll_t);
*/
int
vs_sm_scroll(SCR *sp, MARK *rp, recno_t count, scroll_t scmd)
@@ -745,7 +745,7 @@ vs_sm_up(SCR *sp, MARK *rp, recno_t count, scroll_t scmd, SMAP *smp)
* vs_sm_1up --
* Scroll the SMAP up one.
*
- * PUBLIC: int vs_sm_1up __P((SCR *));
+ * PUBLIC: int vs_sm_1up(SCR *);
*/
int
vs_sm_1up(SCR *sp)
@@ -978,7 +978,7 @@ vs_sm_erase(SCR *sp)
* vs_sm_1down --
* Scroll the SMAP down one.
*
- * PUBLIC: int vs_sm_1down __P((SCR *));
+ * PUBLIC: int vs_sm_1down(SCR *);
*/
int
vs_sm_1down(SCR *sp)
@@ -1042,7 +1042,7 @@ vs_insertln(SCR *sp, int cnt)
* vs_sm_next --
* Fill in the next entry in the SMAP.
*
- * PUBLIC: int vs_sm_next __P((SCR *, SMAP *, SMAP *));
+ * PUBLIC: int vs_sm_next(SCR *, SMAP *, SMAP *);
*/
int
vs_sm_next(SCR *sp, SMAP *p, SMAP *t)
@@ -1070,7 +1070,7 @@ vs_sm_next(SCR *sp, SMAP *p, SMAP *t)
* vs_sm_prev --
* Fill in the previous entry in the SMAP.
*
- * PUBLIC: int vs_sm_prev __P((SCR *, SMAP *, SMAP *));
+ * PUBLIC: int vs_sm_prev(SCR *, SMAP *, SMAP *);
*/
int
vs_sm_prev(SCR *sp, SMAP *p, SMAP *t)
@@ -1095,7 +1095,7 @@ vs_sm_prev(SCR *sp, SMAP *p, SMAP *t)
* vs_sm_cursor --
* Return the SMAP entry referenced by the cursor.
*
- * PUBLIC: int vs_sm_cursor __P((SCR *, SMAP **));
+ * PUBLIC: int vs_sm_cursor(SCR *, SMAP **);
*/
int
vs_sm_cursor(SCR *sp, SMAP **smpp)
@@ -1134,7 +1134,7 @@ vs_sm_cursor(SCR *sp, SMAP **smpp)
* (The vi H, M and L commands.) Here because only the screen routines
* know what's really out there.
*
- * PUBLIC: int vs_sm_position __P((SCR *, MARK *, u_long, pos_t));
+ * PUBLIC: int vs_sm_position(SCR *, MARK *, u_long, pos_t);
*/
int
vs_sm_position(SCR *sp, MARK *rp, u_long cnt, pos_t pos)
@@ -1214,7 +1214,7 @@ eof: msgq(sp, M_BERR,
* Return the number of screen lines from an SMAP entry to the
* start of some file line, less than a maximum value.
*
- * PUBLIC: recno_t vs_sm_nlines __P((SCR *, SMAP *, recno_t, size_t));
+ * PUBLIC: recno_t vs_sm_nlines(SCR *, SMAP *, recno_t, size_t);
*/
recno_t
vs_sm_nlines(SCR *sp, SMAP *from_sp, recno_t to_lno, size_t max)
diff --git a/contrib/nvi/vi/vs_split.c b/contrib/nvi/vi/vs_split.c
index 07bc8e5..d70b4a1 100644
--- a/contrib/nvi/vi/vs_split.c
+++ b/contrib/nvi/vi/vs_split.c
@@ -10,7 +10,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "$Id: vs_split.c,v 10.42 2001/06/25 15:19:38 skimo Exp $";
+static const char sccsid[] = "$Id: vs_split.c,v 10.43 2015/04/05 15:21:55 zy Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -29,15 +29,15 @@ static const char sccsid[] = "$Id: vs_split.c,v 10.42 2001/06/25 15:19:38 skimo
typedef enum { HORIZ_FOLLOW, HORIZ_PRECEDE, VERT_FOLLOW, VERT_PRECEDE } jdir_t;
-static SCR *vs_getbg __P((SCR *, char *));
-static void vs_insert __P((SCR *sp, GS *gp));
-static int vs_join __P((SCR *, SCR **, jdir_t *));
+static SCR *vs_getbg(SCR *, char *);
+static void vs_insert(SCR *sp, GS *gp);
+static int vs_join(SCR *, SCR **, jdir_t *);
/*
* vs_split --
* Create a new screen, horizontally.
*
- * PUBLIC: int vs_split __P((SCR *, SCR *, int));
+ * PUBLIC: int vs_split(SCR *, SCR *, int);
*/
int
vs_split(
@@ -194,7 +194,7 @@ vs_split(
*/
F_SET(new,
SC_SCR_REFORMAT | SC_STATUS |
- F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX));
+ F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX | SC_READONLY));
return (0);
}
@@ -202,7 +202,7 @@ vs_split(
* vs_vsplit --
* Create a new screen, vertically.
*
- * PUBLIC: int vs_vsplit __P((SCR *, SCR *));
+ * PUBLIC: int vs_vsplit(SCR *, SCR *);
*/
int
vs_vsplit(SCR *sp, SCR *new)
@@ -285,7 +285,7 @@ vs_vsplit(SCR *sp, SCR *new)
*/
F_SET(new,
SC_SCR_REFORMAT | SC_STATUS |
- F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX));
+ F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX | SC_READONLY));
return (0);
}
@@ -331,7 +331,7 @@ vs_insert(SCR *sp, GS *gp)
* Discard the screen, folding the real-estate into a related screen,
* if one exists, and return that screen.
*
- * PUBLIC: int vs_discard __P((SCR *, SCR **));
+ * PUBLIC: int vs_discard(SCR *, SCR **);
*/
int
vs_discard(SCR *sp, SCR **spp)
@@ -608,7 +608,7 @@ vs_join(SCR *sp, SCR **listp, jdir_t *jdirp)
* vs_fg --
* Background the current screen, and foreground a new one.
*
- * PUBLIC: int vs_fg __P((SCR *, SCR **, CHAR_T *, int));
+ * PUBLIC: int vs_fg(SCR *, SCR **, CHAR_T *, int);
*/
int
vs_fg(SCR *sp, SCR **nspp, CHAR_T *name, int newscreen)
@@ -661,7 +661,7 @@ vs_fg(SCR *sp, SCR **nspp, CHAR_T *name, int newscreen)
* vs_bg --
* Background the screen, and switch to the next one.
*
- * PUBLIC: int vs_bg __P((SCR *));
+ * PUBLIC: int vs_bg(SCR *);
*/
int
vs_bg(SCR *sp)
@@ -699,7 +699,7 @@ vs_bg(SCR *sp)
* vs_swap --
* Swap the current screen with a backgrounded one.
*
- * PUBLIC: int vs_swap __P((SCR *, SCR **, char *));
+ * PUBLIC: int vs_swap(SCR *, SCR **, char *);
*/
int
vs_swap(SCR *sp, SCR **nspp, char *name)
@@ -794,7 +794,7 @@ vs_swap(SCR *sp, SCR **nspp, char *name)
* vs_resize --
* Change the absolute size of the current screen.
*
- * PUBLIC: int vs_resize __P((SCR *, long, adj_t));
+ * PUBLIC: int vs_resize(SCR *, long, adj_t);
*/
int
vs_resize(SCR *sp, long int count, adj_t adj)
diff --git a/contrib/pjdfstest/tests/open/20.t b/contrib/pjdfstest/tests/open/20.t
index de80b61..7b94b03 100644
--- a/contrib/pjdfstest/tests/open/20.t
+++ b/contrib/pjdfstest/tests/open/20.t
@@ -14,7 +14,11 @@ n0=`namegen`
cp -pf `which sleep` ${n0}
./${n0} 3 &
+while ! pkill -0 -f ./${n0}; do
+ sleep 0.1
+done
expect ETXTBSY open ${n0} O_WRONLY
expect ETXTBSY open ${n0} O_RDWR
expect ETXTBSY open ${n0} O_RDONLY,O_TRUNC
+pkill -9 -f ./${n0}
expect 0 unlink ${n0}
diff --git a/contrib/pjdfstest/tests/truncate/11.t b/contrib/pjdfstest/tests/truncate/11.t
index b00d7b8..f4ecb42 100644
--- a/contrib/pjdfstest/tests/truncate/11.t
+++ b/contrib/pjdfstest/tests/truncate/11.t
@@ -14,5 +14,9 @@ n0=`namegen`
cp -pf `which sleep` ${n0}
./${n0} 3 &
+while ! pkill -0 -f ./${n0}; do
+ sleep 0.1
+done
expect ETXTBSY truncate ${n0} 123
+pkill -9 -f ./${n0}
expect 0 unlink ${n0}
diff --git a/contrib/smbfs/include/netsmb/smb_lib.h b/contrib/smbfs/include/netsmb/smb_lib.h
index 04e8279..12c7086 100644
--- a/contrib/smbfs/include/netsmb/smb_lib.h
+++ b/contrib/smbfs/include/netsmb/smb_lib.h
@@ -191,7 +191,7 @@ int smb_ctx_readrc(struct smb_ctx *);
int smb_ctx_resolve(struct smb_ctx *);
int smb_ctx_setflags(struct smb_ctx *, int, int, int);
-int smb_smb_open_print_file(struct smb_ctx *, int, int, const char *, smbfh*);
+int smb_smb_open_print_file(struct smb_ctx *, int, int, char *, smbfh*);
int smb_smb_close_print_file(struct smb_ctx *, smbfh);
int smb_read(struct smb_ctx *, smbfh, off_t, size_t, char *);
@@ -204,8 +204,8 @@ int smb_rq_init(struct smb_ctx *, u_char, size_t, struct smb_rq **);
void smb_rq_done(struct smb_rq *);
void smb_rq_wend(struct smb_rq *);
int smb_rq_simple(struct smb_rq *);
-int smb_rq_dmem(struct mbdata *, const char *, size_t);
-int smb_rq_dstring(struct mbdata *, const char *);
+int smb_rq_dmem(struct mbdata *, char *, size_t);
+int smb_rq_dstring(struct mbdata *, char *);
int smb_t2_request(struct smb_ctx *, int, int, const char *,
int, void *, int, void *, int *, void *, int *, void *);
@@ -246,10 +246,10 @@ extern u_char nls_lower[256], nls_upper[256];
int nls_setrecode(const char *, const char *);
int nls_setlocale(const char *);
-char* nls_str_toext(char *, const char *);
-char* nls_str_toloc(char *, const char *);
-void* nls_mem_toext(void *, const void *, int);
-void* nls_mem_toloc(void *, const void *, int);
+char* nls_str_toext(char *, char *);
+char* nls_str_toloc(char *, char *);
+void* nls_mem_toext(void *, void *, int);
+void* nls_mem_toloc(void *, void *, int);
char* nls_str_upper(char *, const char *);
char* nls_str_lower(char *, const char *);
diff --git a/contrib/smbfs/lib/smb/nls.c b/contrib/smbfs/lib/smb/nls.c
index 5c2dbd9..b79d49c 100644
--- a/contrib/smbfs/lib/smb/nls.c
+++ b/contrib/smbfs/lib/smb/nls.c
@@ -102,7 +102,7 @@ nls_setrecode(const char *local, const char *external)
}
char *
-nls_str_toloc(char *dst, const char *src)
+nls_str_toloc(char *dst, char *src)
{
#ifdef HAVE_ICONV
char *p = dst;
@@ -125,7 +125,7 @@ nls_str_toloc(char *dst, const char *src)
}
char *
-nls_str_toext(char *dst, const char *src)
+nls_str_toext(char *dst, char *src)
{
#ifdef HAVE_ICONV
char *p = dst;
@@ -148,11 +148,11 @@ nls_str_toext(char *dst, const char *src)
}
void *
-nls_mem_toloc(void *dst, const void *src, int size)
+nls_mem_toloc(void *dst, void *src, int size)
{
#ifdef HAVE_ICONV
char *p = dst;
- const char *s = src;
+ char *s = src;
size_t inlen, outlen;
if (size == 0)
@@ -174,11 +174,11 @@ nls_mem_toloc(void *dst, const void *src, int size)
}
void *
-nls_mem_toext(void *dst, const void *src, int size)
+nls_mem_toext(void *dst, void *src, int size)
{
#ifdef HAVE_ICONV
char *p = dst;
- const char *s = src;
+ char *s = src;
size_t inlen, outlen;
if (size == 0)
diff --git a/contrib/smbfs/lib/smb/print.c b/contrib/smbfs/lib/smb/print.c
index 243ad5b..b4c07c6 100644
--- a/contrib/smbfs/lib/smb/print.c
+++ b/contrib/smbfs/lib/smb/print.c
@@ -54,7 +54,7 @@
int
smb_smb_open_print_file(struct smb_ctx *ctx, int setuplen, int mode,
- const char *ident, smbfh *fhp)
+ char *ident, smbfh *fhp)
{
struct smb_rq *rqp;
struct mbdata *mbp;
diff --git a/contrib/smbfs/lib/smb/rq.c b/contrib/smbfs/lib/smb/rq.c
index 7ecbb36..7dda4792 100644
--- a/contrib/smbfs/lib/smb/rq.c
+++ b/contrib/smbfs/lib/smb/rq.c
@@ -86,7 +86,7 @@ smb_rq_wend(struct smb_rq *rqp)
}
int
-smb_rq_dmem(struct mbdata *mbp, const char *src, size_t size)
+smb_rq_dmem(struct mbdata *mbp, char *src, size_t size)
{
struct mbuf *m;
char * dst;
@@ -118,7 +118,7 @@ smb_rq_dmem(struct mbdata *mbp, const char *src, size_t size)
}
int
-smb_rq_dstring(struct mbdata *mbp, const char *s)
+smb_rq_dstring(struct mbdata *mbp, char *s)
{
return smb_rq_dmem(mbp, s, strlen(s) + 1);
}
diff --git a/contrib/sqlite3/configure b/contrib/sqlite3/configure
index d2db900..91f22b2 100755
--- a/contrib/sqlite3/configure
+++ b/contrib/sqlite3/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sqlite 3.8.7.2.
+# Generated by GNU Autoconf 2.69 for sqlite 3.8.9.
#
# Report bugs to <http://www.sqlite.org>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.8.7.2'
-PACKAGE_STRING='sqlite 3.8.7.2'
+PACKAGE_VERSION='3.8.9'
+PACKAGE_STRING='sqlite 3.8.9'
PACKAGE_BUGREPORT='http://www.sqlite.org'
PACKAGE_URL=''
@@ -1313,7 +1313,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 sqlite 3.8.7.2 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.8.9 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1383,7 +1383,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.8.7.2:";;
+ short | recursive ) echo "Configuration of sqlite 3.8.9:";;
esac
cat <<\_ACEOF
@@ -1489,7 +1489,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.8.7.2
+sqlite configure 3.8.9
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1813,7 +1813,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 sqlite $as_me 3.8.7.2, which was
+It was created by sqlite $as_me 3.8.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2631,7 +2631,7 @@ fi
# Define the identity of the package.
PACKAGE='sqlite'
- VERSION='3.8.7.2'
+ VERSION='3.8.9'
cat >>confdefs.h <<_ACEOF
@@ -13196,7 +13196,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 sqlite $as_me 3.8.7.2, which was
+This file was extended by sqlite $as_me 3.8.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -13253,7 +13253,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="\\
-sqlite config.status 3.8.7.2
+sqlite config.status 3.8.9
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/contrib/sqlite3/configure.ac b/contrib/sqlite3/configure.ac
index c21506a..a78a3cb 100644
--- a/contrib/sqlite3/configure.ac
+++ b/contrib/sqlite3/configure.ac
@@ -8,7 +8,7 @@
#
AC_PREREQ(2.61)
-AC_INIT(sqlite, 3.8.7.2, http://www.sqlite.org)
+AC_INIT(sqlite, 3.8.9, http://www.sqlite.org)
AC_CONFIG_SRCDIR([sqlite3.c])
# Use automake.
diff --git a/contrib/sqlite3/shell.c b/contrib/sqlite3/shell.c
index 3ca4b09..7ff3eb6 100644
--- a/contrib/sqlite3/shell.c
+++ b/contrib/sqlite3/shell.c
@@ -18,6 +18,20 @@
#endif
/*
+** If requested, include the SQLite compiler options file for MSVC.
+*/
+#if defined(INCLUDE_MSVC_H)
+#include "msvc.h"
+#endif
+
+/*
+** No support for loadable extensions in VxWorks.
+*/
+#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION 1
+#endif
+
+/*
** Enable large-file support for fopen() and friends on unix.
*/
#ifndef SQLITE_DISABLE_LFS
@@ -48,23 +62,42 @@
# include <sys/types.h>
#endif
-#if defined(HAVE_READLINE) && HAVE_READLINE!=0
+#if HAVE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
-#else
-# undef HAVE_READLINE
#endif
-#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
-# define HAVE_READLINE 1
+
+#if HAVE_EDITLINE
# include <editline/readline.h>
#endif
-#if !defined(HAVE_READLINE)
-# define add_history(X)
-# define read_history(X)
-# define write_history(X)
-# define stifle_history(X)
+
+#if HAVE_EDITLINE || HAVE_READLINE
+
+# define shell_add_history(X) add_history(X)
+# define shell_read_history(X) read_history(X)
+# define shell_write_history(X) write_history(X)
+# define shell_stifle_history(X) stifle_history(X)
+# define shell_readline(X) readline(X)
+
+#elif HAVE_LINENOISE
+
+# include "linenoise.h"
+# define shell_add_history(X) linenoiseHistoryAdd(X)
+# define shell_read_history(X) linenoiseHistoryLoad(X)
+# define shell_write_history(X) linenoiseHistorySave(X)
+# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
+# define shell_readline(X) linenoise(X)
+
+#else
+
+# define shell_read_history(X)
+# define shell_write_history(X)
+# define shell_stifle_history(X)
+
+# define SHELL_USE_LOCAL_GETLINE 1
#endif
+
#if defined(_WIN32) || defined(WIN32)
# include <io.h>
# include <fcntl.h>
@@ -81,10 +114,15 @@
*/
extern int isatty(int);
-/* popen and pclose are not C89 functions and so are sometimes omitted from
-** the <stdio.h> header */
-extern FILE *popen(const char*,const char*);
-extern int pclose(FILE*);
+#if !defined(__RTP__) && !defined(_WRS_KERNEL)
+ /* popen and pclose are not C89 functions and so are sometimes omitted from
+ ** the <stdio.h> header */
+ extern FILE *popen(const char*,const char*);
+ extern int pclose(FILE*);
+#else
+# define SQLITE_OMIT_POPEN 1
+#endif
+
#endif
#if defined(_WIN32_WCE)
@@ -100,6 +138,26 @@ extern int pclose(FILE*);
#define IsDigit(X) isdigit((unsigned char)X)
#define ToLower(X) (char)tolower((unsigned char)X)
+/* On Windows, we normally run with output mode of TEXT so that \n characters
+** are automatically translated into \r\n. However, this behavior needs
+** to be disabled in some cases (ex: when generating CSV output and when
+** rendering quoted strings that contain \n characters). The following
+** routines take care of that.
+*/
+#if defined(_WIN32) || defined(WIN32)
+static void setBinaryMode(FILE *out){
+ fflush(out);
+ _setmode(_fileno(out), _O_BINARY);
+}
+static void setTextMode(FILE *out){
+ fflush(out);
+ _setmode(_fileno(out), _O_TEXT);
+}
+#else
+# define setBinaryMode(X)
+# define setTextMode(X)
+#endif
+
/* True if the timer is enabled */
static int enableTimer = 0;
@@ -119,11 +177,19 @@ static sqlite3_int64 timeOfDay(void){
return t;
}
-#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
- && !defined(__minux)
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
#include <sys/time.h>
#include <sys/resource.h>
+/* VxWorks does not support getrusage() as far as we can determine */
+#if defined(_WRS_KERNEL) || defined(__RTP__)
+struct rusage {
+ struct timeval ru_utime; /* user CPU time used */
+ struct timeval ru_stime; /* system CPU time used */
+};
+#define getrusage(A,B) memset(B,0,sizeof(*B))
+#endif
+
/* Saved resource information for the beginning of an operation */
static struct rusage sBegin; /* CPU time at start */
static sqlite3_int64 iBegin; /* Wall-clock time at start */
@@ -149,8 +215,8 @@ static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
*/
static void endTimer(void){
if( enableTimer ){
- struct rusage sEnd;
sqlite3_int64 iEnd = timeOfDay();
+ struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(iEnd - iBegin)*0.001,
@@ -172,7 +238,8 @@ static HANDLE hProcess;
static FILETIME ftKernelBegin;
static FILETIME ftUserBegin;
static sqlite3_int64 ftWallBegin;
-typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
+typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
+ LPFILETIME, LPFILETIME);
static GETPROCTIMES getProcessTimesAddr = NULL;
/*
@@ -183,15 +250,16 @@ static int hasTimer(void){
if( getProcessTimesAddr ){
return 1;
} else {
- /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.
- ** See if the version we are running on has it, and if it does, save off
- ** a pointer to it and the current process handle.
+ /* GetProcessTimes() isn't supported in WIN95 and some other Windows
+ ** versions. See if the version we are running on has it, and if it
+ ** does, save off a pointer to it and the current process handle.
*/
hProcess = GetCurrentProcess();
if( hProcess ){
HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
if( NULL != hinstLib ){
- getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
+ getProcessTimesAddr =
+ (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
if( NULL != getProcessTimesAddr ){
return 1;
}
@@ -208,7 +276,8 @@ static int hasTimer(void){
static void beginTimer(void){
if( enableTimer && getProcessTimesAddr ){
FILETIME ftCreation, ftExit;
- getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
+ getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
+ &ftKernelBegin,&ftUserBegin);
ftWallBegin = timeOfDay();
}
}
@@ -227,7 +296,7 @@ static void endTimer(void){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
- getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
+ getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.001,
timeDiff(&ftUserBegin, &ftUserEnd),
@@ -301,7 +370,7 @@ static FILE *iotrace = 0;
** is written to iotrace.
*/
#ifdef SQLITE_ENABLE_IOTRACE
-static void iotracePrintf(const char *zFormat, ...){
+static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
va_list ap;
char *z;
if( iotrace==0 ) return;
@@ -422,14 +491,14 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
zResult = local_getline(zPrior, in);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
-#if defined(HAVE_READLINE)
- free(zPrior);
- zResult = readline(zPrompt);
- if( zResult && *zResult ) add_history(zResult);
-#else
+#if SHELL_USE_LOCAL_GETLINE
printf("%s", zPrompt);
fflush(stdout);
zResult = local_getline(zPrior, stdin);
+#else
+ free(zPrior);
+ zResult = shell_readline(zPrompt);
+ if( zResult && *zResult ) shell_add_history(zResult);
#endif
}
return zResult;
@@ -457,6 +526,7 @@ struct ShellState {
int echoOn; /* True to echo input commands */
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
int statsOn; /* True to display memory stats before each finalize */
+ int scanstatsOn; /* True to display scan stats before each finalize */
int outCount; /* Revert to stdout when reaching zero */
int cnt; /* Number of records displayed so far */
FILE *out; /* Write results here */
@@ -467,11 +537,11 @@ struct ShellState {
int showHeader; /* True to show column names in List or Column mode */
unsigned shellFlgs; /* Various flags */
char *zDestTable; /* Name of destination table when MODE_Insert */
- char separator[20]; /* Separator character for MODE_List */
- char newline[20]; /* Record separator in MODE_Csv */
+ char colSeparator[20]; /* Column separator character for several modes */
+ char rowSeparator[20]; /* Row separator character for MODE_Ascii */
int colWidth[100]; /* Requested width of each column when in column mode*/
int actualWidth[100]; /* Actual width of each column */
- char nullvalue[20]; /* The text to print when a NULL comes back from
+ char nullValue[20]; /* The text to print when a NULL comes back from
** the database */
SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */
@@ -504,6 +574,7 @@ struct ShellState {
#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
#define MODE_Csv 7 /* Quote strings, numbers are plain */
#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
+#define MODE_Ascii 9 /* Use ASCII unit and record separators (0x1F/0x1E) */
static const char *modeDescr[] = {
"line",
@@ -515,9 +586,23 @@ static const char *modeDescr[] = {
"tcl",
"csv",
"explain",
+ "ascii",
};
/*
+** These are the column/row/line separators used by the various
+** import/export modes.
+*/
+#define SEP_Column "|"
+#define SEP_Row "\n"
+#define SEP_Tab "\t"
+#define SEP_Space " "
+#define SEP_Comma ","
+#define SEP_CrLf "\r\n"
+#define SEP_Unit "\x1F"
+#define SEP_Record "\x1E"
+
+/*
** Number of elements in an array
*/
#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
@@ -559,6 +644,7 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
static void output_quoted_string(FILE *out, const char *z){
int i;
int nSingle = 0;
+ setBinaryMode(out);
for(i=0; z[i]; i++){
if( z[i]=='\'' ) nSingle++;
}
@@ -581,6 +667,7 @@ static void output_quoted_string(FILE *out, const char *z){
}
fprintf(out,"'");
}
+ setTextMode(out);
}
/*
@@ -673,22 +760,22 @@ static const char needCsvQuote[] = {
};
/*
-** Output a single term of CSV. Actually, p->separator is used for
-** the separator, which may or may not be a comma. p->nullvalue is
+** Output a single term of CSV. Actually, p->colSeparator is used for
+** the separator, which may or may not be a comma. p->nullValue is
** the null value. Strings are quoted if necessary. The separator
** is only issued if bSep is true.
*/
static void output_csv(ShellState *p, const char *z, int bSep){
FILE *out = p->out;
if( z==0 ){
- fprintf(out,"%s",p->nullvalue);
+ fprintf(out,"%s",p->nullValue);
}else{
int i;
- int nSep = strlen30(p->separator);
+ int nSep = strlen30(p->colSeparator);
for(i=0; z[i]; i++){
if( needCsvQuote[((unsigned char*)z)[i]]
- || (z[i]==p->separator[0] &&
- (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
+ || (z[i]==p->colSeparator[0] &&
+ (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
i = 0;
break;
}
@@ -705,7 +792,7 @@ static void output_csv(ShellState *p, const char *z, int bSep){
}
}
if( bSep ){
- fprintf(p->out, "%s", p->separator);
+ fprintf(p->out, "%s", p->colSeparator);
}
}
@@ -725,7 +812,13 @@ static void interrupt_handler(int NotUsed){
** This is the callback routine that the shell
** invokes for each row of a query result.
*/
-static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){
+static int shell_callback(
+ void *pArg,
+ int nArg, /* Number of result columns */
+ char **azArg, /* Text of each result column */
+ char **azCol, /* Column names */
+ int *aiType /* Column types */
+){
int i;
ShellState *p = (ShellState*)pArg;
@@ -737,10 +830,10 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
int len = strlen30(azCol[i] ? azCol[i] : "");
if( len>w ) w = len;
}
- if( p->cnt++>0 ) fprintf(p->out,"\n");
+ if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator);
for(i=0; i<nArg; i++){
- fprintf(p->out,"%*s = %s\n", w, azCol[i],
- azArg[i] ? azArg[i] : p->nullvalue);
+ fprintf(p->out,"%*s = %s%s", w, azCol[i],
+ azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
}
break;
}
@@ -757,7 +850,7 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
if( w==0 ){
w = strlen30(azCol[i] ? azCol[i] : "");
if( w<10 ) w = 10;
- n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
+ n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
if( w<n ) w = n;
}
if( i<ArraySize(p->actualWidth) ){
@@ -765,9 +858,11 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
}
if( p->showHeader ){
if( w<0 ){
- fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": " ");
+ fprintf(p->out,"%*.*s%s",-w,-w,azCol[i],
+ i==nArg-1 ? p->rowSeparator : " ");
}else{
- fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
+ fprintf(p->out,"%-*.*s%s",w,w,azCol[i],
+ i==nArg-1 ? p->rowSeparator : " ");
}
}
}
@@ -782,7 +877,7 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
}
fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
"----------------------------------------------------------",
- i==nArg-1 ? "\n": " ");
+ i==nArg-1 ? p->rowSeparator : " ");
}
}
}
@@ -805,10 +900,12 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
}
if( w<0 ){
fprintf(p->out,"%*.*s%s",-w,-w,
- azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
+ azArg[i] ? azArg[i] : p->nullValue,
+ i==nArg-1 ? p->rowSeparator : " ");
}else{
fprintf(p->out,"%-*.*s%s",w,w,
- azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
+ azArg[i] ? azArg[i] : p->nullValue,
+ i==nArg-1 ? p->rowSeparator : " ");
}
}
break;
@@ -817,20 +914,21 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
case MODE_List: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
+ fprintf(p->out,"%s%s",azCol[i],
+ i==nArg-1 ? p->rowSeparator : p->colSeparator);
}
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
char *z = azArg[i];
- if( z==0 ) z = p->nullvalue;
+ if( z==0 ) z = p->nullValue;
fprintf(p->out, "%s", z);
if( i<nArg-1 ){
- fprintf(p->out, "%s", p->separator);
+ fprintf(p->out, "%s", p->colSeparator);
}else if( p->mode==MODE_Semi ){
- fprintf(p->out, ";\n");
+ fprintf(p->out, ";%s", p->rowSeparator);
}else{
- fprintf(p->out, "\n");
+ fprintf(p->out, "%s", p->rowSeparator);
}
}
break;
@@ -849,7 +947,7 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
fprintf(p->out,"<TR>");
for(i=0; i<nArg; i++){
fprintf(p->out,"<TD>");
- output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
+ output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
fprintf(p->out,"</TD>\n");
}
fprintf(p->out,"</TR>\n");
@@ -859,39 +957,33 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
output_c_string(p->out,azCol[i] ? azCol[i] : "");
- if(i<nArg-1) fprintf(p->out, "%s", p->separator);
+ if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
}
- fprintf(p->out,"\n");
+ fprintf(p->out, "%s", p->rowSeparator);
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
- if(i<nArg-1) fprintf(p->out, "%s", p->separator);
+ output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
+ if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
}
- fprintf(p->out,"\n");
+ fprintf(p->out, "%s", p->rowSeparator);
break;
}
case MODE_Csv: {
-#if defined(WIN32) || defined(_WIN32)
- fflush(p->out);
- _setmode(_fileno(p->out), _O_BINARY);
-#endif
+ setBinaryMode(p->out);
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
}
- fprintf(p->out,"%s",p->newline);
+ fprintf(p->out, "%s", p->rowSeparator);
}
- if( azArg>0 ){
+ if( nArg>0 ){
for(i=0; i<nArg; i++){
output_csv(p, azArg[i], i<nArg-1);
}
- fprintf(p->out,"%s",p->newline);
+ fprintf(p->out, "%s", p->rowSeparator);
}
-#if defined(WIN32) || defined(_WIN32)
- fflush(p->out);
- _setmode(_fileno(p->out), _O_TEXT);
-#endif
+ setTextMode(p->out);
break;
}
case MODE_Insert: {
@@ -923,6 +1015,22 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
fprintf(p->out,");\n");
break;
}
+ case MODE_Ascii: {
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
+ fprintf(p->out,"%s",azCol[i] ? azCol[i] : "");
+ }
+ fprintf(p->out, "%s", p->rowSeparator);
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
+ fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
+ }
+ fprintf(p->out, "%s", p->rowSeparator);
+ break;
+ }
}
return 0;
}
@@ -1104,57 +1212,77 @@ static int display_stats(
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr);
+ fprintf(pArg->out,
+ "Memory Used: %d (max %d) bytes\n",
+ iCur, iHiwtr);
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr);
+ fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n",
+ iCur, iHiwtr);
if( pArg->shellFlgs & SHFLG_Pagecache ){
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr);
+ fprintf(pArg->out,
+ "Number of Pcache Pages Used: %d (max %d) pages\n",
+ iCur, iHiwtr);
}
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
+ fprintf(pArg->out,
+ "Number of Pcache Overflow Bytes: %d (max %d) bytes\n",
+ iCur, iHiwtr);
if( pArg->shellFlgs & SHFLG_Scratch ){
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr);
+ fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n",
+ iCur, iHiwtr);
}
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
+ fprintf(pArg->out,
+ "Number of Scratch Overflow Bytes: %d (max %d) bytes\n",
+ iCur, iHiwtr);
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr);
+ fprintf(pArg->out, "Largest Allocation: %d bytes\n",
+ iHiwtr);
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr);
+ fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n",
+ iHiwtr);
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr);
+ fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n",
+ iHiwtr);
#ifdef YYTRACKMAXSTACKDEPTH
iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr);
+ fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n",
+ iCur, iHiwtr);
#endif
}
if( pArg && pArg->out && db ){
if( pArg->shellFlgs & SHFLG_Lookaside ){
iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset);
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
+ &iCur, &iHiwtr, bReset);
+ fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n",
+ iCur, iHiwtr);
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
+ &iCur, &iHiwtr, bReset);
fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr);
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset);
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
+ &iCur, &iHiwtr, bReset);
fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr);
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset);
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
+ &iCur, &iHiwtr, bReset);
fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr);
}
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1;
+ fprintf(pArg->out, "Pager Heap Usage: %d bytes\n",iCur);
+ iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
fprintf(pArg->out, "Page cache hits: %d\n", iCur);
iHiwtr = iCur = -1;
@@ -1165,18 +1293,19 @@ static int display_stats(
fprintf(pArg->out, "Page cache writes: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur);
+ fprintf(pArg->out, "Schema Heap Usage: %d bytes\n",iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
- fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
+ fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",iCur);
}
if( pArg && pArg->out && db && pArg->pStmt ){
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
+ bReset);
fprintf(pArg->out, "Fullscan Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
fprintf(pArg->out, "Sort Operations: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
@@ -1186,6 +1315,51 @@ static int display_stats(
}
/*
+** Display scan stats.
+*/
+static void display_scanstats(
+ sqlite3 *db, /* Database to query */
+ ShellState *pArg /* Pointer to ShellState */
+){
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int i, k, n, mx;
+ fprintf(pArg->out, "-------- scanstats --------\n");
+ mx = 0;
+ for(k=0; k<=mx; k++){
+ double rEstLoop = 1.0;
+ for(i=n=0; 1; i++){
+ sqlite3_stmt *p = pArg->pStmt;
+ sqlite3_int64 nLoop, nVisit;
+ double rEst;
+ int iSid;
+ const char *zExplain;
+ if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
+ break;
+ }
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
+ if( iSid>mx ) mx = iSid;
+ if( iSid!=k ) continue;
+ if( n==0 ){
+ rEstLoop = (double)nLoop;
+ if( k>0 ) fprintf(pArg->out, "-------- subquery %d -------\n", k);
+ }
+ n++;
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
+ fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain);
+ rEstLoop *= rEst;
+ fprintf(pArg->out,
+ " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
+ nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
+ );
+ }
+ }
+ fprintf(pArg->out, "---------------------------\n");
+#endif
+}
+
+/*
** Parameter azArray points to a zero-terminated array of strings. zStr
** points to a single nul-terminated string. Return non-zero if zStr
** is equal, according to strcmp(), to any of the strings in the array.
@@ -1226,7 +1400,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
"NextIfOpen", "PrevIfOpen", 0 };
- const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 };
+ const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
+ "Rewind", 0 };
const char *azGoto[] = { "Goto", 0 };
/* Try to figure out if this is really an EXPLAIN statement. If this
@@ -1339,7 +1514,8 @@ static int shell_exec(
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
if( pArg && pArg->autoEQP ){
sqlite3_stmt *pExplain;
- char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt));
+ char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s",
+ sqlite3_sql(pStmt));
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc==SQLITE_OK ){
while( sqlite3_step(pExplain)==SQLITE_ROW ){
@@ -1423,6 +1599,11 @@ static int shell_exec(
display_stats(db, pArg, 0);
}
+ /* print loop-counters if required */
+ if( pArg && pArg->scanstatsOn ){
+ display_scanstats(db, pArg);
+ }
+
/* Finalize the statement just executed. If this fails, save a
** copy of the error message. Otherwise, set zSql to point to the
** next statement to execute. */
@@ -1592,6 +1773,7 @@ static char zHelp[] =
".bail on|off Stop after hitting an error. Default OFF\n"
".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n"
+ ".dbinfo ?DB? Show status information about the database\n"
".dump ?TABLE? ... Dump the database in an SQL text format\n"
" If TABLE specified, only dump tables matching\n"
" LIKE pattern TABLE.\n"
@@ -1604,8 +1786,8 @@ static char zHelp[] =
".headers on|off Turn display of headers on or off\n"
".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n"
- ".indices ?TABLE? Show names of all indices\n"
- " If TABLE specified, only show indices for tables\n"
+ ".indexes ?TABLE? Show names of all indexes\n"
+ " If TABLE specified, only show indexes for tables\n"
" matching LIKE pattern TABLE.\n"
#ifdef SQLITE_ENABLE_IOTRACE
".iotrace FILE Enable I/O diagnostic logging to FILE\n"
@@ -1615,12 +1797,13 @@ static char zHelp[] =
#endif
".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
+ " ascii Columns/rows delimited by 0x1F and 0x1E\n"
" csv Comma-separated values\n"
" column Left-aligned columns. (See .width)\n"
" html HTML <table> code\n"
" insert SQL insert statements for TABLE\n"
" line One value per line\n"
- " list Values delimited by .separator string\n"
+ " list Values delimited by .separator strings\n"
" tabs Tab-separated values\n"
" tcl TCL list elements\n"
".nullvalue STRING Use STRING in place of NULL values\n"
@@ -1633,11 +1816,12 @@ static char zHelp[] =
".read FILENAME Execute SQL in FILENAME\n"
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
".save FILE Write in-memory database into FILE\n"
+ ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
".schema ?TABLE? Show the CREATE statements\n"
" If TABLE specified, only show tables matching\n"
" LIKE pattern TABLE.\n"
- ".separator STRING ?NL? Change separator used by output mode and .import\n"
- " NL is the end-of-line mark for CSV\n"
+ ".separator COL ?ROW? Change the column separator and optionally the row\n"
+ " separator for both the output mode and .import\n"
".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
".show Show the current values for various settings\n"
".stats on|off Turn stats on or off\n"
@@ -1918,10 +2102,10 @@ static void test_breakpoint(void){
}
/*
-** An object used to read a CSV file
+** An object used to read a CSV and other files for import.
*/
-typedef struct CSVReader CSVReader;
-struct CSVReader {
+typedef struct ImportCtx ImportCtx;
+struct ImportCtx {
const char *zFile; /* Name of the input file */
FILE *in; /* Read the CSV text from this input stream */
char *z; /* Accumulated text for a field */
@@ -1929,11 +2113,12 @@ struct CSVReader {
int nAlloc; /* Space allocated for z[] */
int nLine; /* Current line number */
int cTerm; /* Character that terminated the most recent field */
- int cSeparator; /* The separator character. (Usually ",") */
+ int cColSep; /* The column separator character. (Usually ",") */
+ int cRowSep; /* The row separator character. (Usually "\n") */
};
/* Append a single byte to z[] */
-static void csv_append_char(CSVReader *p, int c){
+static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
p->nAlloc += p->nAlloc + 100;
p->z = sqlite3_realloc(p->z, p->nAlloc);
@@ -1951,15 +2136,17 @@ static void csv_append_char(CSVReader *p, int c){
** + Input comes from p->in.
** + Store results in p->z of length p->n. Space to hold p->z comes
** from sqlite3_malloc().
-** + Use p->cSep as the separator. The default is ",".
+** + Use p->cSep as the column separator. The default is ",".
+** + Use p->rSep as the row separator. The default is "\n".
** + Keep track of the line number in p->nLine.
** + Store the character that terminates the field in p->cTerm. Store
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
-static char *csv_read_one_field(CSVReader *p){
- int c, pc, ppc;
- int cSep = p->cSeparator;
+static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
+ int c;
+ int cSep = p->cColSep;
+ int rSep = p->cRowSep;
p->n = 0;
c = fgetc(p->in);
if( c==EOF || seenInterrupt ){
@@ -1967,12 +2154,13 @@ static char *csv_read_one_field(CSVReader *p){
return 0;
}
if( c=='"' ){
+ int pc, ppc;
int startLine = p->nLine;
int cQuote = c;
pc = ppc = 0;
while( 1 ){
c = fgetc(p->in);
- if( c=='\n' ) p->nLine++;
+ if( c==rSep ) p->nLine++;
if( c==cQuote ){
if( pc==cQuote ){
pc = 0;
@@ -1980,8 +2168,8 @@ static char *csv_read_one_field(CSVReader *p){
}
}
if( (c==cSep && pc==cQuote)
- || (c=='\n' && pc==cQuote)
- || (c=='\n' && pc=='\r' && ppc==cQuote)
+ || (c==rSep && pc==cQuote)
+ || (c==rSep && pc=='\r' && ppc==cQuote)
|| (c==EOF && pc==cQuote)
){
do{ p->n--; }while( p->z[p->n]!=cQuote );
@@ -1995,19 +2183,19 @@ static char *csv_read_one_field(CSVReader *p){
if( c==EOF ){
fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
p->zFile, startLine, cQuote);
- p->cTerm = EOF;
+ p->cTerm = c;
break;
}
- csv_append_char(p, c);
+ import_append_char(p, c);
ppc = pc;
pc = c;
}
}else{
- while( c!=EOF && c!=cSep && c!='\n' ){
- csv_append_char(p, c);
+ while( c!=EOF && c!=cSep && c!=rSep ){
+ import_append_char(p, c);
c = fgetc(p->in);
}
- if( c=='\n' ){
+ if( c==rSep ){
p->nLine++;
if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
}
@@ -2017,6 +2205,40 @@ static char *csv_read_one_field(CSVReader *p){
return p->z;
}
+/* Read a single field of ASCII delimited text.
+**
+** + Input comes from p->in.
+** + Store results in p->z of length p->n. Space to hold p->z comes
+** from sqlite3_malloc().
+** + Use p->cSep as the column separator. The default is "\x1F".
+** + Use p->rSep as the row separator. The default is "\x1E".
+** + Keep track of the row number in p->nLine.
+** + Store the character that terminates the field in p->cTerm. Store
+** EOF on end-of-file.
+** + Report syntax errors on stderr
+*/
+static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
+ int c;
+ int cSep = p->cColSep;
+ int rSep = p->cRowSep;
+ p->n = 0;
+ c = fgetc(p->in);
+ if( c==EOF || seenInterrupt ){
+ p->cTerm = EOF;
+ return 0;
+ }
+ while( c!=EOF && c!=cSep && c!=rSep ){
+ import_append_char(p, c);
+ c = fgetc(p->in);
+ }
+ if( c==rSep ){
+ p->nLine++;
+ }
+ p->cTerm = c;
+ if( p->z ) p->z[p->n] = 0;
+ return p->z;
+}
+
/*
** Try to transfer data for table zTable. If an error is seen while
** moving forward, try to go backwards. The backwards movement won't
@@ -2237,7 +2459,9 @@ static void tryToClone(ShellState *p, const char *zNewDb){
*/
static void output_reset(ShellState *p){
if( p->outfile[0]=='|' ){
+#ifndef SQLITE_OMIT_POPEN
pclose(p->out);
+#endif
}else{
output_file_close(p->out);
}
@@ -2246,6 +2470,115 @@ static void output_reset(ShellState *p){
}
/*
+** Run an SQL command and return the single integer result.
+*/
+static int db_int(ShellState *p, const char *zSql){
+ sqlite3_stmt *pStmt;
+ int res = 0;
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
+ res = sqlite3_column_int(pStmt,0);
+ }
+ sqlite3_finalize(pStmt);
+ return res;
+}
+
+/*
+** Convert a 2-byte or 4-byte big-endian integer into a native integer
+*/
+unsigned int get2byteInt(unsigned char *a){
+ return (a[0]<<8) + a[1];
+}
+unsigned int get4byteInt(unsigned char *a){
+ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
+}
+
+/*
+** Implementation of the ".info" command.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
+ static const struct { const char *zName; int ofst; } aField[] = {
+ { "file change counter:", 24 },
+ { "database page count:", 28 },
+ { "freelist page count:", 36 },
+ { "schema cookie:", 40 },
+ { "schema format:", 44 },
+ { "default cache size:", 48 },
+ { "autovacuum top root:", 52 },
+ { "incremental vacuum:", 64 },
+ { "text encoding:", 56 },
+ { "user version:", 60 },
+ { "application id:", 68 },
+ { "software version:", 96 },
+ };
+ static const struct { const char *zName; const char *zSql; } aQuery[] = {
+ { "number of tables:",
+ "SELECT count(*) FROM %s WHERE type='table'" },
+ { "number of indexes:",
+ "SELECT count(*) FROM %s WHERE type='index'" },
+ { "number of triggers:",
+ "SELECT count(*) FROM %s WHERE type='trigger'" },
+ { "number of views:",
+ "SELECT count(*) FROM %s WHERE type='view'" },
+ { "schema size:",
+ "SELECT total(length(sql)) FROM %s" },
+ };
+ sqlite3_file *pFile;
+ int i;
+ char *zSchemaTab;
+ char *zDb = nArg>=2 ? azArg[1] : "main";
+ unsigned char aHdr[100];
+ open_db(p, 0);
+ if( p->db==0 ) return 1;
+ sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
+ if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
+ return 1;
+ }
+ i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
+ if( i!=SQLITE_OK ){
+ fprintf(stderr, "unable to read database header\n");
+ return 1;
+ }
+ i = get2byteInt(aHdr+16);
+ if( i==1 ) i = 65536;
+ fprintf(p->out, "%-20s %d\n", "database page size:", i);
+ fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
+ fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
+ fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
+ for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
+ int ofst = aField[i].ofst;
+ unsigned int val = get4byteInt(aHdr + ofst);
+ fprintf(p->out, "%-20s %u", aField[i].zName, val);
+ switch( ofst ){
+ case 56: {
+ if( val==1 ) fprintf(p->out, " (utf8)");
+ if( val==2 ) fprintf(p->out, " (utf16le)");
+ if( val==3 ) fprintf(p->out, " (utf16be)");
+ }
+ }
+ fprintf(p->out, "\n");
+ }
+ if( zDb==0 ){
+ zSchemaTab = sqlite3_mprintf("main.sqlite_master");
+ }else if( strcmp(zDb,"temp")==0 ){
+ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
+ }else{
+ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
+ }
+ for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
+ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
+ int val = db_int(p, zSql);
+ sqlite3_free(zSql);
+ fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
+ }
+ sqlite3_free(zSchemaTab);
+ return 0;
+}
+
+
+/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
@@ -2387,6 +2720,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
+ rc = shell_dbinfo_command(p, nArg, azArg);
+ }else
+
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
open_db(p, 0);
/* When playing back a "dump", the content might appear in an order
@@ -2571,10 +2908,11 @@ static int do_meta_command(char *zLine, ShellState *p){
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
int needCommit; /* True to COMMIT or ROLLBACK at end */
- int nSep; /* Number of bytes in p->separator[] */
+ int nSep; /* Number of bytes in p->colSeparator[] */
char *zSql; /* An SQL statement */
- CSVReader sCsv; /* Reader context */
- int (*xCloser)(FILE*); /* Procedure to close th3 connection */
+ ImportCtx sCtx; /* Reader context */
+ char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
+ int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
if( nArg!=3 ){
fprintf(stderr, "Usage: .import FILE TABLE\n");
@@ -2583,55 +2921,84 @@ static int do_meta_command(char *zLine, ShellState *p){
zFile = azArg[1];
zTable = azArg[2];
seenInterrupt = 0;
- memset(&sCsv, 0, sizeof(sCsv));
+ memset(&sCtx, 0, sizeof(sCtx));
open_db(p, 0);
- nSep = strlen30(p->separator);
+ nSep = strlen30(p->colSeparator);
if( nSep==0 ){
- fprintf(stderr, "Error: non-null separator required for import\n");
+ fprintf(stderr, "Error: non-null column separator required for import\n");
return 1;
}
if( nSep>1 ){
- fprintf(stderr, "Error: multi-character separators not allowed"
+ fprintf(stderr, "Error: multi-character column separators not allowed"
" for import\n");
return 1;
}
- sCsv.zFile = zFile;
- sCsv.nLine = 1;
- if( sCsv.zFile[0]=='|' ){
- sCsv.in = popen(sCsv.zFile+1, "r");
- sCsv.zFile = "<pipe>";
+ nSep = strlen30(p->rowSeparator);
+ if( nSep==0 ){
+ fprintf(stderr, "Error: non-null row separator required for import\n");
+ return 1;
+ }
+ if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
+ /* When importing CSV (only), if the row separator is set to the
+ ** default output row separator, change it to the default input
+ ** row separator. This avoids having to maintain different input
+ ** and output row separators. */
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ nSep = strlen30(p->rowSeparator);
+ }
+ if( nSep>1 ){
+ fprintf(stderr, "Error: multi-character row separators not allowed"
+ " for import\n");
+ return 1;
+ }
+ sCtx.zFile = zFile;
+ sCtx.nLine = 1;
+ if( sCtx.zFile[0]=='|' ){
+#ifdef SQLITE_OMIT_POPEN
+ fprintf(stderr, "Error: pipes are not supported in this OS\n");
+ return 1;
+#else
+ sCtx.in = popen(sCtx.zFile+1, "r");
+ sCtx.zFile = "<pipe>";
xCloser = pclose;
+#endif
}else{
- sCsv.in = fopen(sCsv.zFile, "rb");
+ sCtx.in = fopen(sCtx.zFile, "rb");
xCloser = fclose;
}
- if( sCsv.in==0 ){
+ if( p->mode==MODE_Ascii ){
+ xRead = ascii_read_one_field;
+ }else{
+ xRead = csv_read_one_field;
+ }
+ if( sCtx.in==0 ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
return 1;
}
- sCsv.cSeparator = p->separator[0];
+ sCtx.cColSep = p->colSeparator[0];
+ sCtx.cRowSep = p->rowSeparator[0];
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
- xCloser(sCsv.in);
+ xCloser(sCtx.in);
return 1;
}
nByte = strlen30(zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- csv_append_char(&sCsv, 0); /* To ensure sCsv.z is allocated */
+ import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
char cSep = '(';
- while( csv_read_one_field(&sCsv) ){
- zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z);
+ while( xRead(&sCtx) ){
+ zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCtx.z);
cSep = ',';
- if( sCsv.cTerm!=sCsv.cSeparator ) break;
+ if( sCtx.cTerm!=sCtx.cColSep ) break;
}
if( cSep=='(' ){
sqlite3_free(zCreate);
- sqlite3_free(sCsv.z);
- xCloser(sCsv.in);
- fprintf(stderr,"%s: empty file\n", sCsv.zFile);
+ sqlite3_free(sCtx.z);
+ xCloser(sCtx.in);
+ fprintf(stderr,"%s: empty file\n", sCtx.zFile);
return 1;
}
zCreate = sqlite3_mprintf("%z\n)", zCreate);
@@ -2640,8 +3007,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
sqlite3_errmsg(db));
- sqlite3_free(sCsv.z);
- xCloser(sCsv.in);
+ sqlite3_free(sCtx.z);
+ xCloser(sCtx.in);
return 1;
}
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
@@ -2650,7 +3017,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
- xCloser(sCsv.in);
+ xCloser(sCtx.in);
return 1;
}
nCol = sqlite3_column_count(pStmt);
@@ -2660,7 +3027,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
- xCloser(sCsv.in);
+ xCloser(sCtx.in);
return 1;
}
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
@@ -2676,51 +3043,62 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
if (pStmt) sqlite3_finalize(pStmt);
- xCloser(sCsv.in);
+ xCloser(sCtx.in);
return 1;
}
needCommit = sqlite3_get_autocommit(db);
if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
do{
- int startLine = sCsv.nLine;
+ int startLine = sCtx.nLine;
for(i=0; i<nCol; i++){
- char *z = csv_read_one_field(&sCsv);
+ char *z = xRead(&sCtx);
+ /*
+ ** Did we reach end-of-file before finding any columns?
+ ** If so, stop instead of NULL filling the remaining columns.
+ */
if( z==0 && i==0 ) break;
+ /*
+ ** Did we reach end-of-file OR end-of-line before finding any
+ ** columns in ASCII mode? If so, stop instead of NULL filling
+ ** the remaining columns.
+ */
+ if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
- if( i<nCol-1 && sCsv.cTerm!=sCsv.cSeparator ){
+ if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
"filling the rest with NULL\n",
- sCsv.zFile, startLine, nCol, i+1);
- i++;
+ sCtx.zFile, startLine, nCol, i+1);
+ i += 2;
while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
}
}
- if( sCsv.cTerm==sCsv.cSeparator ){
+ if( sCtx.cTerm==sCtx.cColSep ){
do{
- csv_read_one_field(&sCsv);
+ xRead(&sCtx);
i++;
- }while( sCsv.cTerm==sCsv.cSeparator );
+ }while( sCtx.cTerm==sCtx.cColSep );
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
"extras ignored\n",
- sCsv.zFile, startLine, nCol, i);
+ sCtx.zFile, startLine, nCol, i);
}
if( i>=nCol ){
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
if( rc!=SQLITE_OK ){
- fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine,
+ fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
sqlite3_errmsg(db));
}
}
- }while( sCsv.cTerm!=EOF );
+ }while( sCtx.cTerm!=EOF );
- xCloser(sCsv.in);
- sqlite3_free(sCsv.z);
+ xCloser(sCtx.in);
+ sqlite3_free(sCtx.z);
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
}else
- if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
+ if( c=='i' && (strncmp(azArg[0], "indices", n)==0
+ || strncmp(azArg[0], "indexes", n)==0) ){
ShellState data;
char *zErrMsg = 0;
open_db(p, 0);
@@ -2750,7 +3128,7 @@ static int do_meta_command(char *zLine, ShellState *p){
);
zShellStatic = 0;
}else{
- fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
+ fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
}
@@ -2766,7 +3144,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_ENABLE_IOTRACE
if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
- extern void (*sqlite3IoTrace)(const char*, ...);
+ SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
if( iotrace && iotrace!=stdout ) fclose(iotrace);
iotrace = 0;
if( nArg<2 ){
@@ -2833,28 +3211,32 @@ static int do_meta_command(char *zLine, ShellState *p){
p->mode = MODE_Html;
}else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
p->mode = MODE_Tcl;
- sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
p->mode = MODE_Csv;
- sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
- sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n");
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
}else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
p->mode = MODE_List;
- sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
}else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, nArg>=3 ? azArg[2] : "table");
+ }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
+ p->mode = MODE_Ascii;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
}else {
fprintf(stderr,"Error: mode should be one of: "
- "column csv html insert line list tabs tcl\n");
+ "ascii column csv html insert line list tabs tcl\n");
rc = 1;
}
}else
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
if( nArg==2 ){
- sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
- "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
+ sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
+ "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
}else{
fprintf(stderr, "Usage: .nullvalue STRING\n");
rc = 1;
@@ -2902,6 +3284,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}
output_reset(p);
if( zFile[0]=='|' ){
+#ifdef SQLITE_OMIT_POPEN
+ fprintf(stderr,"Error: pipes are not supported in this OS\n");
+ rc = 1;
+ p->out = stdout;
+#else
p->out = popen(zFile + 1, "w");
if( p->out==0 ){
fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
@@ -2910,6 +3297,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
+#endif
}else{
p->out = output_file_open(zFile);
if( p->out==0 ){
@@ -3014,6 +3402,19 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_close(pSrc);
}else
+
+ if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
+ if( nArg==2 ){
+ p->scanstatsOn = booleanValue(azArg[1]);
+#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
+ fprintf(stderr, "Warning: .scanstats not available in this build.\n");
+#endif
+ }else{
+ fprintf(stderr, "Usage: .scanstats on|off\n");
+ rc = 1;
+ }
+ }else
+
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
ShellState data;
char *zErrMsg = 0;
@@ -3096,7 +3497,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
extern int sqlite3SelectTrace;
- sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
+ sqlite3SelectTrace = integerValue(azArg[1]);
}else
#endif
@@ -3126,14 +3527,16 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
if( nArg<2 || nArg>3 ){
- fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
+ fprintf(stderr, "Usage: .separator COL ?ROW?\n");
rc = 1;
}
if( nArg>=2 ){
- sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]);
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
+ "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
}
if( nArg>=3 ){
- sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
+ "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
}
}else
@@ -3164,23 +3567,24 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}
- fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
- fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
+ fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
+ fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
- fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
- fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
- fprintf(p->out,"%9.9s: ", "nullvalue");
- output_c_string(p->out, p->nullvalue);
+ fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
+ fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
+ fprintf(p->out,"%12.12s: ", "nullvalue");
+ output_c_string(p->out, p->nullValue);
fprintf(p->out, "\n");
- fprintf(p->out,"%9.9s: %s\n","output",
+ fprintf(p->out,"%12.12s: %s\n","output",
strlen30(p->outfile) ? p->outfile : "stdout");
- fprintf(p->out,"%9.9s: ", "separator");
- output_c_string(p->out, p->separator);
- fprintf(p->out," ");
- output_c_string(p->out, p->newline);
+ fprintf(p->out,"%12.12s: ", "colseparator");
+ output_c_string(p->out, p->colSeparator);
+ fprintf(p->out, "\n");
+ fprintf(p->out,"%12.12s: ", "rowseparator");
+ output_c_string(p->out, p->rowSeparator);
fprintf(p->out, "\n");
- fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
- fprintf(p->out,"%9.9s: ","width");
+ fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
+ fprintf(p->out,"%12.12s: ","width");
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
fprintf(p->out,"%d ",p->colWidth[i]);
}
@@ -3271,7 +3675,7 @@ static int do_meta_command(char *zLine, ShellState *p){
for(i=0; i<nPrintRow; i++){
for(j=i; j<nRow; j+=nPrintRow){
char *zSp = j<nPrintRow ? "" : " ";
- fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
+ fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
}
fprintf(p->out, "\n");
}
@@ -3299,6 +3703,8 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
+ { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
+ { "imposter", SQLITE_TESTCTRL_IMPOSTER },
};
int testctrl = -1;
int rc = 0;
@@ -3365,7 +3771,8 @@ static int do_meta_command(char *zLine, ShellState *p){
/* sqlite3_test_control(int, int) */
case SQLITE_TESTCTRL_ASSERT:
- case SQLITE_TESTCTRL_ALWAYS:
+ case SQLITE_TESTCTRL_ALWAYS:
+ case SQLITE_TESTCTRL_NEVER_CORRUPT:
if( nArg==3 ){
int opt = booleanValue(azArg[2]);
rc = sqlite3_test_control(testctrl, opt);
@@ -3390,6 +3797,18 @@ static int do_meta_command(char *zLine, ShellState *p){
break;
#endif
+ case SQLITE_TESTCTRL_IMPOSTER:
+ if( nArg==5 ){
+ rc = sqlite3_test_control(testctrl, p->db,
+ azArg[2],
+ integerValue(azArg[3]),
+ integerValue(azArg[4]));
+ fprintf(p->out, "%d (0x%08x)\n", rc, rc);
+ }else{
+ fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
+ }
+ break;
+
case SQLITE_TESTCTRL_BITVEC_TEST:
case SQLITE_TESTCTRL_FAULT_INSTALL:
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
@@ -3422,12 +3841,12 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
open_db(p, 0);
- output_file_close(p->traceOut);
if( nArg!=2 ){
fprintf(stderr, "Usage: .trace FILE|off\n");
rc = 1;
goto meta_command_exit;
}
+ output_file_close(p->traceOut);
p->traceOut = output_file_open(azArg[1]);
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
if( p->traceOut==0 ){
@@ -3741,7 +4160,8 @@ static char *find_home_dir(void){
static char *home_dir = NULL;
if( home_dir ) return home_dir;
-#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
+#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
+ && !defined(__RTP__) && !defined(_WRS_KERNEL)
{
struct passwd *pwent;
uid_t uid = getuid();
@@ -3802,7 +4222,7 @@ static char *find_home_dir(void){
**
** Returns the number of errors.
*/
-static int process_sqliterc(
+static void process_sqliterc(
ShellState *p, /* Configuration data */
const char *sqliterc_override /* Name of config file. NULL to use default */
){
@@ -3810,15 +4230,13 @@ static int process_sqliterc(
const char *sqliterc = sqliterc_override;
char *zBuf = 0;
FILE *in = NULL;
- int rc = 0;
if (sqliterc == NULL) {
home_dir = find_home_dir();
if( home_dir==0 ){
-#if !defined(__RTP__) && !defined(_WRS_KERNEL)
- fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0);
-#endif
- return 1;
+ fprintf(stderr, "-- warning: cannot find home directory;"
+ " cannot read ~/.sqliterc\n");
+ return;
}
sqlite3_initialize();
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
@@ -3829,17 +4247,17 @@ static int process_sqliterc(
if( stdin_is_interactive ){
fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
}
- rc = process_input(p,in);
+ process_input(p,in);
fclose(in);
}
sqlite3_free(zBuf);
- return rc;
}
/*
** Show available command line options
*/
static const char zOptions[] =
+ " -ascii set output mode to 'ascii'\n"
" -bail stop after hitting an error\n"
" -batch force batch I/O\n"
" -column set output mode to 'column'\n"
@@ -3861,11 +4279,11 @@ static const char zOptions[] =
#ifdef SQLITE_ENABLE_MULTIPLEX
" -multiplex enable the multiplexor VFS\n"
#endif
- " -newline SEP set newline character(s) for CSV\n"
+ " -newline SEP set output row separator. Default: '\\n'\n"
" -nullvalue TEXT set text string for NULL values. Default ''\n"
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
" -scratch SIZE N use N slots of SZ bytes each for scratch memory\n"
- " -separator SEP set output field separator. Default: '|'\n"
+ " -separator SEP set output column separator. Default: '|'\n"
" -stats print memory stats before each finalize\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
@@ -3892,8 +4310,8 @@ static void usage(int showDetail){
static void main_init(ShellState *data) {
memset(data, 0, sizeof(*data));
data->mode = MODE_List;
- memcpy(data->separator,"|", 2);
- memcpy(data->newline,"\r\n", 3);
+ memcpy(data->colSeparator,SEP_Column, 2);
+ memcpy(data->rowSeparator,SEP_Row, 2);
data->showHeader = 0;
data->shellFlgs = SHFLG_Lookaside;
sqlite3_config(SQLITE_CONFIG_URI, 1);
@@ -3936,14 +4354,16 @@ static char *cmdline_option_value(int argc, char **argv, int i){
return argv[i];
}
-int main(int argc, char **argv){
+int SQLITE_CDECL main(int argc, char **argv){
char *zErrMsg = 0;
ShellState data;
const char *zInitFile = 0;
- char *zFirstCmd = 0;
int i;
int rc = 0;
int warnInmemoryDb = 0;
+ int readStdin = 1;
+ int nCmd = 0;
+ char **azCmd = 0;
#if USE_SYSTEM_SQLITE+0!=1
if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
@@ -3952,6 +4372,8 @@ int main(int argc, char **argv){
exit(1);
}
#endif
+ setBinaryMode(stdin);
+ setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
Argv0 = argv[0];
main_init(&data);
stdin_is_interactive = isatty(0);
@@ -3963,6 +4385,18 @@ int main(int argc, char **argv){
signal(SIGINT, interrupt_handler);
#endif
+#ifdef SQLITE_SHELL_DBNAME_PROC
+ {
+ /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
+ ** of a C-function that will provide the name of the database file. Use
+ ** this compile-time option to embed this shell program in larger
+ ** applications. */
+ extern void SQLITE_SHELL_DBNAME_PROC(const char**);
+ SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
+ warnInmemoryDb = 0;
+ }
+#endif
+
/* Do an initial pass through the command-line argument to locate
** the name of the database file, the name of the initialization file,
** the size of the alternative malloc heap,
@@ -3974,15 +4408,18 @@ int main(int argc, char **argv){
if( z[0]!='-' ){
if( data.zDbFilename==0 ){
data.zDbFilename = z;
- continue;
- }
- if( zFirstCmd==0 ){
- zFirstCmd = z;
- continue;
+ }else{
+ /* Excesss arguments are interpreted as SQL (or dot-commands) and
+ ** mean that nothing is read from stdin */
+ readStdin = 0;
+ nCmd++;
+ azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
+ if( azCmd==0 ){
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ azCmd[nCmd-1] = z;
}
- fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
- fprintf(stderr,"Use -help for a list of options.\n");
- return 1;
}
if( z[1]=='-' ) z++;
if( strcmp(z,"-separator")==0
@@ -4073,11 +4510,6 @@ int main(int argc, char **argv){
fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
return 1;
#endif
-#ifdef SQLITE_SHELL_DBNAME_PROC
- { extern void SQLITE_SHELL_DBNAME_PROC(const char**);
- SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
- warnInmemoryDb = 0; }
-#endif
}
data.out = stdout;
@@ -4094,10 +4526,7 @@ int main(int argc, char **argv){
** is given on the command line, look for a file named ~/.sqliterc and
** try to process it.
*/
- rc = process_sqliterc(&data,zInitFile);
- if( rc>0 ){
- return rc;
- }
+ process_sqliterc(&data,zInitFile);
/* Make a second pass through the command-line argument and set
** options. This second pass is delayed until after the initialization
@@ -4120,15 +4549,21 @@ int main(int argc, char **argv){
data.mode = MODE_Column;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
- memcpy(data.separator,",",2);
+ memcpy(data.colSeparator,",",2);
+ }else if( strcmp(z,"-ascii")==0 ){
+ data.mode = MODE_Ascii;
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
+ SEP_Unit);
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
+ SEP_Record);
}else if( strcmp(z,"-separator")==0 ){
- sqlite3_snprintf(sizeof(data.separator), data.separator,
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-newline")==0 ){
- sqlite3_snprintf(sizeof(data.newline), data.newline,
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-nullvalue")==0 ){
- sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
+ sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-header")==0 ){
data.showHeader = 1;
@@ -4140,6 +4575,8 @@ int main(int argc, char **argv){
data.autoEQP = 1;
}else if( strcmp(z,"-stats")==0 ){
data.statsOn = 1;
+ }else if( strcmp(z,"-scanstats")==0 ){
+ data.scanstatsOn = 1;
}else if( strcmp(z,"-bail")==0 ){
bail_on_error = 1;
}else if( strcmp(z,"-version")==0 ){
@@ -4172,6 +4609,10 @@ int main(int argc, char **argv){
}else if( strcmp(z,"-help")==0 ){
usage(1);
}else if( strcmp(z,"-cmd")==0 ){
+ /* Run commands that follow -cmd first and separately from commands
+ ** that simply appear on the command-line. This seems goofy. It would
+ ** be better if all commands ran in the order that they appear. But
+ ** we retain the goofy behavior for historical compatibility. */
if( i==argc-1 ) break;
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
@@ -4195,23 +4636,28 @@ int main(int argc, char **argv){
}
}
- if( zFirstCmd ){
- /* Run just the command that follows the database name
+ if( !readStdin ){
+ /* Run all arguments that do not begin with '-' as if they were separate
+ ** command-line inputs, except for the argToSkip argument which contains
+ ** the database filename.
*/
- if( zFirstCmd[0]=='.' ){
- rc = do_meta_command(zFirstCmd, &data);
- if( rc==2 ) rc = 0;
- }else{
- open_db(&data, 0);
- rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
- if( zErrMsg!=0 ){
- fprintf(stderr,"Error: %s\n", zErrMsg);
- return rc!=0 ? rc : 1;
- }else if( rc!=0 ){
- fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
- return rc;
+ for(i=0; i<nCmd; i++){
+ if( azCmd[i][0]=='.' ){
+ rc = do_meta_command(azCmd[i], &data);
+ if( rc ) return rc==2 ? 0 : rc;
+ }else{
+ open_db(&data, 0);
+ rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
+ if( zErrMsg!=0 ){
+ fprintf(stderr,"Error: %s\n", zErrMsg);
+ return rc!=0 ? rc : 1;
+ }else if( rc!=0 ){
+ fprintf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
+ return rc;
+ }
}
}
+ free(azCmd);
}else{
/* Run commands received from standard input
*/
@@ -4237,13 +4683,11 @@ int main(int argc, char **argv){
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
}
}
-#if defined(HAVE_READLINE)
- if( zHistory ) read_history(zHistory);
-#endif
+ if( zHistory ) shell_read_history(zHistory);
rc = process_input(&data, 0);
if( zHistory ){
- stifle_history(100);
- write_history(zHistory);
+ shell_stifle_history(100);
+ shell_write_history(zHistory);
free(zHistory);
}
}else{
diff --git a/contrib/sqlite3/sqlite3.1 b/contrib/sqlite3/sqlite3.1
index 02df7f4..80353b0 100644
--- a/contrib/sqlite3/sqlite3.1
+++ b/contrib/sqlite3/sqlite3.1
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
-.TH SQLITE3 1 "Mon Jan 31 11:14:00 2014"
+.TH SQLITE3 1 "Fri Oct 31 10:41:31 EDT 2014"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -49,7 +49,7 @@ a table named "memos" and insert a couple of records into that table:
$
.B sqlite3 mydata.db
.br
-SQLite version 3.8.3
+SQLite version 3.8.8
.br
Enter ".help" for instructions
.br
@@ -107,26 +107,29 @@ the '.help' command. For example:
sqlite>
.B .help
.nf
-.cc |
-.backup ?DB? FILE Backup DB (default "main") to FILE
-.bail ON|OFF Stop after hitting an error. Default OFF
-.databases List names and files of attached databases
-.dump ?TABLE? ... Dump the database in an SQL text format
+.tr %.
+%backup ?DB? FILE Backup DB (default "main") to FILE
+%bail on|off Stop after hitting an error. Default OFF
+%clone NEWDB Clone data into NEWDB from the existing database
+%databases List names and files of attached databases
+%dump ?TABLE? ... Dump the database in an SQL text format
If TABLE specified, only dump tables matching
LIKE pattern TABLE.
-.echo ON|OFF Turn command echo on or off
-.exit Exit this program
-.explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.
+%echo on|off Turn command echo on or off
+%eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN
+%exit Exit this program
+%explain ?on|off? Turn output mode suitable for EXPLAIN on or off.
With no args, it turns EXPLAIN on.
-.header(s) ON|OFF Turn display of headers on or off
-.help Show this message
-.import FILE TABLE Import data from FILE into TABLE
-.indices ?TABLE? Show names of all indices
+%fullschema Show schema and the content of sqlite_stat tables
+%headers on|off Turn display of headers on or off
+%help Show this message
+%import FILE TABLE Import data from FILE into TABLE
+%indices ?TABLE? Show names of all indices
If TABLE specified, only show indices for tables
matching LIKE pattern TABLE.
-.load FILE ?ENTRY? Load an extension library
-.log FILE|off Turn logging on or off. FILE can be stderr/stdout
-.mode MODE ?TABLE? Set output mode where MODE is one of:
+%load FILE ?ENTRY? Load an extension library
+%log FILE|off Turn logging on or off. FILE can be stderr/stdout
+%mode MODE ?TABLE? Set output mode where MODE is one of:
csv Comma-separated values
column Left-aligned columns. (See .width)
html HTML <table> code
@@ -135,31 +138,35 @@ sqlite>
list Values delimited by .separator string
tabs Tab-separated values
tcl TCL list elements
-.nullvalue STRING Use STRING in place of NULL values
-.open ?FILENAME? Close existing database and reopen FILENAME
-.output FILENAME Send output to FILENAME
-.output stdout Send output to the screen
-.print STRING... Print literal STRING
-.prompt MAIN CONTINUE Replace the standard prompts
-.quit Exit this program
-.read FILENAME Execute SQL in FILENAME
-.restore ?DB? FILE Restore content of DB (default "main") from FILE
-.schema ?TABLE? Show the CREATE statements
+%nullvalue STRING Use STRING in place of NULL values
+%once FILENAME Output for the next SQL command only to FILENAME
+%open ?FILENAME? Close existing database and reopen FILENAME
+%output ?FILENAME? Send output to FILENAME or stdout
+%print STRING... Print literal STRING
+%prompt MAIN CONTINUE Replace the standard prompts
+%quit Exit this program
+%read FILENAME Execute SQL in FILENAME
+%restore ?DB? FILE Restore content of DB (default "main") from FILE
+%save FILE Write in-memory database into FILE
+%schema ?TABLE? Show the CREATE statements
If TABLE specified, only show tables matching
LIKE pattern TABLE.
-.separator STRING Change separator used by output mode and .import
-.show Show the current values for various settings
-.stats ON|OFF Turn stats on or off
-.tables ?TABLE? List names of tables
+%separator STRING ?NL? Change separator used by output mode and .import
+ NL is the end-of-line mark for CSV
+%shell CMD ARGS... Run CMD ARGS... in a system shell
+%show Show the current values for various settings
+%stats on|off Turn stats on or off
+%system CMD ARGS... Run CMD ARGS... in a system shell
+%tables ?TABLE? List names of tables
If TABLE specified, only list tables matching
LIKE pattern TABLE.
-.timeout MS Try opening locked tables for MS milliseconds
-.trace FILE|off Output each SQL statement as it is run
-.vfsname ?AUX? Print the name of the VFS stack
-.width NUM1 NUM2 ... Set column widths for "column" mode
-.timer ON|OFF Turn the CPU timer measurement on or off
+%timeout MS Try opening locked tables for MS milliseconds
+%timer on|off Turn SQL timer on or off
+%trace FILE|off Output each SQL statement as it is run
+%vfsname ?AUX? Print the name of the VFS stack
+%width NUM1 NUM2 ... Set column widths for "column" mode
+ Negative values right-justify
sqlite>
-|cc .
.sp
.fi
.SH OPTIONS
@@ -269,7 +276,7 @@ o If the -init option is present, the specified file is processed.
o All other command line options are processed.
.SH SEE ALSO
-http://www.sqlite.org/
+http://www.sqlite.org/cli.html
.br
The sqlite3-doc package.
.SH AUTHOR
diff --git a/contrib/sqlite3/sqlite3.c b/contrib/sqlite3/sqlite3.c
index 9a8a0ea..a8922e4 100644
--- a/contrib/sqlite3/sqlite3.c
+++ b/contrib/sqlite3/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.8.7.2. By combining all the individual C code files into this
+** version 3.8.9. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -22,9 +22,6 @@
#ifndef SQLITE_PRIVATE
# define SQLITE_PRIVATE static
#endif
-#ifndef SQLITE_API
-# define SQLITE_API
-#endif
/************** Begin file sqliteInt.h ***************************************/
/*
** 2001 September 15
@@ -44,6 +41,91 @@
#define _SQLITEINT_H_
/*
+** Include the header file used to customize the compiler options for MSVC.
+** This should be done first so that it can successfully prevent spurious
+** compiler warnings due to subsequent content in this file and other files
+** that are included by this file.
+*/
+/************** Include msvc.h in the middle of sqliteInt.h ******************/
+/************** Begin file msvc.h ********************************************/
+/*
+** 2015 January 12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code that is specific to MSVC.
+*/
+#ifndef _MSVC_H_
+#define _MSVC_H_
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4054)
+#pragma warning(disable : 4055)
+#pragma warning(disable : 4100)
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4152)
+#pragma warning(disable : 4189)
+#pragma warning(disable : 4206)
+#pragma warning(disable : 4210)
+#pragma warning(disable : 4232)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4306)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 4706)
+#endif /* defined(_MSC_VER) */
+
+#endif /* _MSVC_H_ */
+
+/************** End of msvc.h ************************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
+
+/*
+** Special setup for VxWorks
+*/
+/************** Include vxworks.h in the middle of sqliteInt.h ***************/
+/************** Begin file vxworks.h *****************************************/
+/*
+** 2015-03-02
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code that is specific to Wind River's VxWorks
+*/
+#if defined(__RTP__) || defined(_WRS_KERNEL)
+/* This is VxWorks. Set up things specially for that OS
+*/
+#include <vxWorks.h>
+#include <pthread.h> /* amalgamator: dontcache */
+#define OS_VXWORKS 1
+#define SQLITE_OS_OTHER 0
+#define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1
+#define SQLITE_OMIT_LOAD_EXTENSION 1
+#define SQLITE_ENABLE_LOCKING_STYLE 0
+#define HAVE_UTIME 1
+#else
+/* This is not VxWorks. */
+#define OS_VXWORKS 0
+#endif /* defined(_WRS_KERNEL) */
+
+/************** End of vxworks.h *********************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
+
+/*
** These #defines should enable >2GB file support on POSIX if the
** underlying operating system supports it. If the OS lacks
** large file support, or if the OS is windows, these should be no-ops.
@@ -167,21 +249,25 @@ extern "C" {
/*
-** Add the ability to override 'extern'
+** Provide the ability to override linkage features of the interface.
*/
#ifndef SQLITE_EXTERN
# define SQLITE_EXTERN extern
#endif
-
#ifndef SQLITE_API
# define SQLITE_API
#endif
-
+#ifndef SQLITE_CDECL
+# define SQLITE_CDECL
+#endif
+#ifndef SQLITE_STDCALL
+# define SQLITE_STDCALL
+#endif
/*
** These no-op macros are used in front of interfaces to mark those
** interfaces as either deprecated or experimental. New applications
-** should not use deprecated interfaces - they are support for backwards
+** should not use deprecated interfaces - they are supported for backwards
** compatibility only. Application writers should be aware that
** experimental interfaces are subject to change in point releases.
**
@@ -231,9 +317,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.8.7.2"
-#define SQLITE_VERSION_NUMBER 3008007
-#define SQLITE_SOURCE_ID "2014-11-18 20:57:56 2ab564bf9655b7c7b97ab85cafc8a48329b27f93"
+#define SQLITE_VERSION "3.8.9"
+#define SQLITE_VERSION_NUMBER 3008009
+#define SQLITE_SOURCE_ID "2015-04-08 12:16:33 8a8ffc862e96f57aa698f93de10dee28e69f6e09"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -266,9 +352,9 @@ extern "C" {
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
-SQLITE_API const char *sqlite3_libversion(void);
-SQLITE_API const char *sqlite3_sourceid(void);
-SQLITE_API int sqlite3_libversion_number(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
@@ -293,8 +379,8 @@ SQLITE_API int sqlite3_libversion_number(void);
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
-SQLITE_API const char *sqlite3_compileoption_get(int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
#endif
/*
@@ -325,7 +411,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
** can be fully or partially disabled using a call to [sqlite3_config()]
** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
-** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
+** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
** sqlite3_threadsafe() function shows only the compile-time setting of
** thread safety, not any run-time changes to that setting made by
** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
@@ -333,7 +419,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
**
** See the [threading mode] documentation for additional information.
*/
-SQLITE_API int sqlite3_threadsafe(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
/*
** CAPI3REF: Database Connection Handle
@@ -429,8 +515,8 @@ typedef sqlite_uint64 sqlite3_uint64;
** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
** argument is a harmless no-op.
*/
-SQLITE_API int sqlite3_close(sqlite3*);
-SQLITE_API int sqlite3_close_v2(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
/*
** The type for a callback function.
@@ -500,7 +586,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** </ul>
*/
-SQLITE_API int sqlite3_exec(
+SQLITE_API int SQLITE_STDCALL sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
@@ -880,14 +966,16 @@ struct sqlite3_io_methods {
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
+** <ul>
+** <li>[[SQLITE_FCNTL_LOCKSTATE]]
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-** <ul>
+** is used during testing and is only available when the SQLITE_TEST
+** compile-time option is used.
+**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
@@ -1012,7 +1100,9 @@ struct sqlite3_io_methods {
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
** file control returns [SQLITE_OK], then the parser assumes that the
** VFS has handled the PRAGMA itself and the parser generates a no-op
-** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns
+** prepared statement if result string is NULL, or that returns a copy
+** of the result string if the string is non-NULL.
+** ^If the [SQLITE_FCNTL_PRAGMA] file control returns
** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means
** that the VFS encountered an error while handling the [PRAGMA] and the
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
@@ -1070,12 +1160,19 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
+** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
+** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
+** be advantageous to block on the next WAL lock if the lock is not immediately
+** available. The WAL subsystem issues this signal during rare
+** circumstances in order to fix a problem with priority inversion.
+** Applications should <em>not</em> use this file-control.
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
+#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3
+#define SQLITE_FCNTL_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7
@@ -1094,6 +1191,13 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_SYNC 21
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
+#define SQLITE_FCNTL_WAL_BLOCK 24
+
+/* deprecated names */
+#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
+#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
+#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
+
/*
** CAPI3REF: Mutex Handle
@@ -1345,7 +1449,7 @@ struct sqlite3_vfs {
** </ul>
**
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
-** was given no the corresponding lock.
+** was given on the corresponding lock.
**
** The xShmLock method can transition between unlocked and SHARED or
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
@@ -1442,10 +1546,10 @@ struct sqlite3_vfs {
** must return [SQLITE_OK] on success and some other [error code] upon
** failure.
*/
-SQLITE_API int sqlite3_initialize(void);
-SQLITE_API int sqlite3_shutdown(void);
-SQLITE_API int sqlite3_os_init(void);
-SQLITE_API int sqlite3_os_end(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
/*
** CAPI3REF: Configuring The SQLite Library
@@ -1476,7 +1580,7 @@ SQLITE_API int sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API int sqlite3_config(int, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
@@ -1494,7 +1598,7 @@ SQLITE_API int sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
@@ -1628,31 +1732,33 @@ struct sqlite3_mem_methods {
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
**
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The argument specifies
+** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
+** a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The argument specifies
** alternative low-level memory allocation routines to be used in place of
** the memory allocation routines built into SQLite.)^ ^SQLite makes
** its own private copy of the content of the [sqlite3_mem_methods] structure
** before the [sqlite3_config()] call returns.</dd>
**
** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
+** <dd> ^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The [sqlite3_mem_methods]
** structure is filled with the currently defined memory allocation routines.)^
** This option can be used to overload the default memory allocation
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
-** <dd> ^This option takes single argument of type int, interpreted as a
-** boolean, which enables or disables the collection of memory allocation
-** statistics. ^(When memory allocation statistics are disabled, the
-** following SQLite interfaces become non-operational:
+** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
+** interpreted as a boolean, which enables or disables the collection of
+** memory allocation statistics. ^(When memory allocation statistics are
+** disabled, the following SQLite interfaces become non-operational:
** <ul>
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
-** <li> [sqlite3_status()]
+** <li> [sqlite3_status64()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
@@ -1660,53 +1766,67 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** scratch memory. There are three arguments: A pointer an 8-byte
+** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
+** that SQLite can use for scratch memory. ^(There are three arguments
+** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
** aligned memory buffer from which the scratch allocations will be
** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N). The sz
-** argument must be a multiple of 16.
+** and the maximum number of scratch allocations (N).)^
** The first argument must be a pointer to an 8-byte aligned buffer
** of at least sz*N bytes of memory.
-** ^SQLite will use no more than two scratch buffers per thread. So
-** N should be set to twice the expected maximum number of threads.
-** ^SQLite will never require a scratch buffer that is more than 6
-** times the database page size. ^If SQLite needs needs additional
+** ^SQLite will not use more than one scratch buffers per thread.
+** ^SQLite will never request a scratch buffer that is more than 6
+** times the database page size.
+** ^If SQLite needs needs additional
** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
+** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
+** ^When the application provides any amount of scratch memory using
+** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
+** [sqlite3_malloc|heap allocations].
+** This can help [Robson proof|prevent memory allocation failures] due to heap
+** fragmentation in low-memory embedded systems.
+** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implementation.
+** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
+** that SQLite can use for the database page cache with the default page
+** cache implementation.
** This configuration should not be used if an application-define page
-** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option.
-** There are three arguments to this option: A pointer to 8-byte aligned
+** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
+** configuration option.
+** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
+** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
-** (a power of two between 512 and 32768) plus a little extra for each
-** page header. ^The page header size is 20 to 40 bytes depending on
-** the host architecture. ^It is harmless, apart from the wasted memory,
-** to make sz a little too large. The first
-** argument should point to an allocation of at least sz*N bytes of memory.
+** (a power of two between 512 and 65536) plus some extra bytes for each
+** page header. ^The number of extra bytes needed by the page header
+** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
+** to [sqlite3_config()].
+** ^It is harmless, apart from the wasted memory,
+** for the sz parameter to be larger than necessary. The first
+** argument should pointer to an 8-byte aligned block of memory that
+** is at least sz*N bytes of memory, otherwise subsequent behavior is
+** undefined.
** ^SQLite will use the memory provided by the first argument to satisfy its
** memory needs for the first N pages that it adds to cache. ^If additional
** page cache memory is needed beyond what is provided by this option, then
-** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** The pointer in the first argument must
-** be aligned to an 8-byte boundary or subsequent behavior of SQLite
-** will be undefined.</dd>
+** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite will use
-** for all of its dynamic memory allocation needs beyond those provided
-** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
-** There are three arguments: An 8-byte aligned pointer to the memory,
+** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
+** that SQLite will use for all of its dynamic memory allocation needs
+** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
+** [SQLITE_CONFIG_PAGECACHE].
+** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
+** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
+** [SQLITE_ERROR] if invoked otherwise.
+** ^There are three arguments to SQLITE_CONFIG_HEAP:
+** An 8-byte aligned pointer to the memory,
** the number of bytes in the memory buffer, and the minimum allocation size.
** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts
** to using its default memory allocator (the system malloc() implementation),
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
-** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
-** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
+** memory pointer is not NULL then the alternative memory
** allocator is engaged to handle all of SQLites memory allocation needs.
** The first pointer (the memory pointer) must be aligned to an 8-byte
** boundary or subsequent behavior of SQLite will be undefined.
@@ -1714,11 +1834,11 @@ struct sqlite3_mem_methods {
** for the minimum allocation size are 2**5 through 2**8.</dd>
**
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The argument specifies
-** alternative low-level mutex routines to be used in place
-** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the
-** content of the [sqlite3_mutex_methods] structure before the call to
+** <dd> ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a
+** pointer to an instance of the [sqlite3_mutex_methods] structure.
+** The argument specifies alternative low-level mutex routines to be used
+** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of
+** the content of the [sqlite3_mutex_methods] structure before the call to
** [sqlite3_config()] returns. ^If SQLite is compiled with
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
** the entire mutexing subsystem is omitted from the build and hence calls to
@@ -1726,8 +1846,8 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The
+** <dd> ^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The
** [sqlite3_mutex_methods]
** structure is filled with the currently defined mutex routines.)^
** This option can be used to overload the default mutex allocation
@@ -1739,25 +1859,25 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
-** <dd> ^(This option takes two arguments that determine the default
-** memory allocation for the lookaside memory allocator on each
-** [database connection]. The first argument is the
+** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
+** the default size of lookaside memory on each [database connection].
+** The first argument is the
** size of each lookaside buffer slot and the second is the number of
-** slots allocated to each database connection.)^ ^(This option sets the
-** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
-** verb to [sqlite3_db_config()] can be used to change the lookaside
+** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
+** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
+** option to [sqlite3_db_config()] can be used to change the lookaside
** configuration on individual connections.)^ </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to
-** an [sqlite3_pcache_methods2] object. This object specifies the interface
-** to a custom page cache implementation.)^ ^SQLite makes a copy of the
-** object and uses it for page cache memory allocations.</dd>
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
+** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
+** the interface to a custom page cache implementation.)^
+** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
**
** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** [sqlite3_pcache_methods2] object. SQLite copies of the current
-** page cache implementation into that object.)^ </dd>
+** <dd> ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which
+** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of
+** the current page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
@@ -1780,10 +1900,11 @@ struct sqlite3_mem_methods {
** function must be threadsafe. </dd>
**
** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
-** <dd>^(This option takes a single argument of type int. If non-zero, then
-** URI handling is globally enabled. If the parameter is zero, then URI handling
-** is globally disabled.)^ ^If URI handling is globally enabled, all filenames
-** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
+** <dd>^(The SQLITE_CONFIG_URI option takes a single argument of type int.
+** If non-zero, then URI handling is globally enabled. If the parameter is zero,
+** then URI handling is globally disabled.)^ ^If URI handling is globally
+** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()],
+** [sqlite3_open16()] or
** specified as part of [ATTACH] commands are interpreted as URIs, regardless
** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
** connection is opened. ^If it is globally disabled, filenames are
@@ -1793,9 +1914,10 @@ struct sqlite3_mem_methods {
** [SQLITE_USE_URI] symbol defined.)^
**
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
-** <dd>^This option takes a single integer argument which is interpreted as
-** a boolean in order to enable or disable the use of covering indices for
-** full table scans in the query optimizer. ^The default setting is determined
+** <dd>^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer
+** argument which is interpreted as a boolean in order to enable or disable
+** the use of covering indices for full table scans in the query optimizer.
+** ^The default setting is determined
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"
** if that compile-time option is omitted.
** The ability to disable the use of covering indices for full table scans
@@ -1835,18 +1957,37 @@ struct sqlite3_mem_methods {
** ^The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_size] command, or by using the
** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size
-** cannot be changed at run-time. Nor may the maximum allowed mmap size
-** exceed the compile-time maximum mmap size set by the
+** will be silently truncated if necessary so that it does not exceed the
+** compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
**
** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
-** <dd>^This option is only available if SQLite is compiled for Windows
-** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
-** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
+** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is
+** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro
+** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
** that specifies the maximum size of the created heap.
+**
+** [[SQLITE_CONFIG_PCACHE_HDRSZ]]
+** <dt>SQLITE_CONFIG_PCACHE_HDRSZ
+** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
+** is a pointer to an integer and writes into that integer the number of extra
+** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
+** The amount of extra space required can change depending on the compiler,
+** target platform, and SQLite version.
+**
+** [[SQLITE_CONFIG_PMASZ]]
+** <dt>SQLITE_CONFIG_PMASZ
+** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
+** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
+** sorter to that integer. The default minimum PMA Size is set by the
+** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
+** to help with sort operations when multithreaded sorting
+** is enabled (using the [PRAGMA threads] command) and the amount of content
+** to be sorted exceeds the page size times the minimum of the
+** [PRAGMA cache_size] setting and this value.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1872,6 +2013,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
+#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
+#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1943,7 +2086,7 @@ struct sqlite3_mem_methods {
** [extended result codes] feature of SQLite. ^The extended result
** codes are disabled by default for historical compatibility.
*/
-SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
/*
** CAPI3REF: Last Insert Rowid
@@ -1994,52 +2137,50 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
** unpredictable and might not equal either the old or the new
** last insert [rowid].
*/
-SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
/*
** CAPI3REF: Count The Number Of Rows Modified
**
-** ^This function returns the number of database rows that were changed
-** or inserted or deleted by the most recently completed SQL statement
-** on the [database connection] specified by the first parameter.
-** ^(Only changes that are directly specified by the [INSERT], [UPDATE],
-** or [DELETE] statement are counted. Auxiliary changes caused by
-** triggers or [foreign key actions] are not counted.)^ Use the
-** [sqlite3_total_changes()] function to find the total number of changes
-** including changes caused by triggers and foreign key actions.
-**
-** ^Changes to a view that are simulated by an [INSTEAD OF trigger]
-** are not counted. Only real table changes are counted.
-**
-** ^(A "row change" is a change to a single row of a single table
-** caused by an INSERT, DELETE, or UPDATE statement. Rows that
-** are changed as side effects of [REPLACE] constraint resolution,
-** rollback, ABORT processing, [DROP TABLE], or by any other
-** mechanisms do not count as direct row changes.)^
-**
-** A "trigger context" is a scope of execution that begins and
-** ends with the script of a [CREATE TRIGGER | trigger].
-** Most SQL statements are
-** evaluated outside of any trigger. This is the "top level"
-** trigger context. If a trigger fires from the top level, a
-** new trigger context is entered for the duration of that one
-** trigger. Subtriggers create subcontexts for their duration.
-**
-** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
-** not create a new trigger context.
-**
-** ^This function returns the number of direct row changes in the
-** most recent INSERT, UPDATE, or DELETE statement within the same
-** trigger context.
-**
-** ^Thus, when called from the top level, this function returns the
-** number of changes in the most recent INSERT, UPDATE, or DELETE
-** that also occurred at the top level. ^(Within the body of a trigger,
-** the sqlite3_changes() interface can be called to find the number of
-** changes in the most recently completed INSERT, UPDATE, or DELETE
-** statement within the body of the same trigger.
-** However, the number returned does not include changes
-** caused by subtriggers since those have their own context.)^
+** ^This function returns the number of rows modified, inserted or
+** deleted by the most recently completed INSERT, UPDATE or DELETE
+** statement on the database connection specified by the only parameter.
+** ^Executing any other type of SQL statement does not modify the value
+** returned by this function.
+**
+** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
+** [foreign key actions] or [REPLACE] constraint resolution are not counted.
+**
+** Changes to a view that are intercepted by
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
+** DELETE statement run on a view is always zero. Only changes made to real
+** tables are counted.
+**
+** Things are more complicated if the sqlite3_changes() function is
+** executed while a trigger program is running. This may happen if the
+** program uses the [changes() SQL function], or if some other callback
+** function invokes sqlite3_changes() directly. Essentially:
+**
+** <ul>
+** <li> ^(Before entering a trigger program the value returned by
+** sqlite3_changes() function is saved. After the trigger program
+** has finished, the original value is restored.)^
+**
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
+** statement sets the value returned by sqlite3_changes()
+** upon completion as normal. Of course, this value will not include
+** any changes performed by sub-triggers, as the sqlite3_changes()
+** value will be saved and restored after each sub-trigger has run.)^
+** </ul>
+**
+** ^This means that if the changes() SQL function (or similar) is used
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
+** returns the value as set when the calling statement began executing.
+** ^If it is used by the second or subsequent such statement within a trigger
+** program, the value returned reflects the number of rows modified by the
+** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
** See also the [sqlite3_total_changes()] interface, the
** [count_changes pragma], and the [changes() SQL function].
@@ -2048,25 +2189,22 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
/*
** CAPI3REF: Total Number Of Rows Modified
**
-** ^This function returns the number of row changes caused by [INSERT],
-** [UPDATE] or [DELETE] statements since the [database connection] was opened.
-** ^(The count returned by sqlite3_total_changes() includes all changes
-** from all [CREATE TRIGGER | trigger] contexts and changes made by
-** [foreign key actions]. However,
-** the count does not include changes used to implement [REPLACE] constraints,
-** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
-** count does not include rows of views that fire an [INSTEAD OF trigger],
-** though if the INSTEAD OF trigger makes changes of its own, those changes
-** are counted.)^
-** ^The sqlite3_total_changes() function counts the changes as soon as
-** the statement that makes them is completed (when the statement handle
-** is passed to [sqlite3_reset()] or [sqlite3_finalize()]).
-**
+** ^This function returns the total number of rows inserted, modified or
+** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
+** since the database connection was opened, including those executed as
+** part of trigger programs. ^Executing any other type of SQL statement
+** does not affect the value returned by sqlite3_total_changes().
+**
+** ^Changes made as part of [foreign key actions] are included in the
+** count, but those made as part of REPLACE constraint resolution are
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
+** are not counted.
+**
** See also the [sqlite3_changes()] interface, the
** [count_changes pragma], and the [total_changes() SQL function].
**
@@ -2074,7 +2212,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_total_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
/*
** CAPI3REF: Interrupt A Long-Running Query
@@ -2113,7 +2251,7 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
** If the database connection closes while [sqlite3_interrupt()]
** is running then bad things will likely happen.
*/
-SQLITE_API void sqlite3_interrupt(sqlite3*);
+SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2148,11 +2286,12 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
-SQLITE_API int sqlite3_complete(const char *sql);
-SQLITE_API int sqlite3_complete16(const void *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
+** KEYWORDS: {busy-handler callback} {busy handler}
**
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
** that might be invoked with argument P whenever
@@ -2169,7 +2308,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** ^The first argument to the busy handler is a copy of the void* pointer which
** is the third argument to sqlite3_busy_handler(). ^The second argument to
** the busy handler callback is the number of times that the busy handler has
-** been invoked for the same locking event. ^If the
+** been invoked previously for the same locking event. ^If the
** busy callback returns 0, then no additional attempts are made to
** access the database and [SQLITE_BUSY] is returned
** to the application.
@@ -2208,7 +2347,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
-SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
/*
** CAPI3REF: Set A Busy Timeout
@@ -2230,7 +2369,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
**
** See also: [PRAGMA busy_timeout]
*/
-SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
@@ -2304,7 +2443,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** reflected in subsequent calls to [sqlite3_errcode()] or
** [sqlite3_errmsg()].
*/
-SQLITE_API int sqlite3_get_table(
+SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
@@ -2312,13 +2451,17 @@ SQLITE_API int sqlite3_get_table(
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
-SQLITE_API void sqlite3_free_table(char **result);
+SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
/*
** CAPI3REF: Formatted String Printing Functions
**
** These routines are work-alikes of the "printf()" family of functions
** from the standard C library.
+** These routines understand most of the common K&R formatting options,
+** plus some additional non-standard formats, detailed below.
+** Note that some of the more obscure formatting options from recent
+** C-library standards are omitted from this implementation.
**
** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
** results into memory obtained from [sqlite3_malloc()].
@@ -2351,7 +2494,7 @@ SQLITE_API void sqlite3_free_table(char **result);
** These routines all implement some additional formatting
** options that are useful for constructing SQL statements.
** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", and "%z" options.
+** is are "%q", "%Q", "%w" and "%z" options.
**
** ^(The %q option works like %s in that it substitutes a nul-terminated
** string from the argument list. But %q also doubles every '\'' character.
@@ -2404,14 +2547,20 @@ SQLITE_API void sqlite3_free_table(char **result);
** The code above will render a correct SQL statement in the zSQL
** variable even if the zText variable is a NULL pointer.
**
+** ^(The "%w" formatting option is like "%q" except that it expects to
+** be contained within double-quotes instead of single quotes, and it
+** escapes the double-quote character instead of the single-quote
+** character.)^ The "%w" formatting option is intended for safely inserting
+** table and column names into a constructed SQL statement.
+**
** ^(The "%z" formatting option works like "%s" but with the
** addition that after the string has been read and copied into
** the result, [sqlite3_free()] is called on the input string.)^
*/
-SQLITE_API char *sqlite3_mprintf(const char*,...);
-SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
-SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
-SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
/*
** CAPI3REF: Memory Allocation Subsystem
@@ -2501,12 +2650,12 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** a block of memory after it has been released using
** [sqlite3_free()] or [sqlite3_realloc()].
*/
-SQLITE_API void *sqlite3_malloc(int);
-SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
-SQLITE_API void *sqlite3_realloc(void*, int);
-SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
-SQLITE_API void sqlite3_free(void*);
-SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
+SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
+SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
/*
** CAPI3REF: Memory Allocator Statistics
@@ -2531,8 +2680,8 @@ SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
** by [sqlite3_memory_highwater(1)] is the high-water mark
** prior to the reset.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
/*
** CAPI3REF: Pseudo-Random Number Generator
@@ -2544,17 +2693,18 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
-** ^If N is less than one, then P can be a NULL pointer.
+** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
-** call had N less than one, then the PRNG is seeded using randomness
-** obtained from the xRandomness method of the default [sqlite3_vfs] object.
-** ^If the previous call to this routine had an N of 1 or more then
-** the pseudo-randomness is generated
+** call had N less than one or a NULL pointer for P, then the PRNG is
+** seeded using randomness obtained from the xRandomness method of
+** the default [sqlite3_vfs] object.
+** ^If the previous call to this routine had an N of 1 or more and a
+** non-NULL P then the pseudo-randomness is generated
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/
-SQLITE_API void sqlite3_randomness(int N, void *P);
+SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
@@ -2636,7 +2786,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** as stated in the previous paragraph, sqlite3_step() invokes
** sqlite3_prepare_v2() to reprepare a statement after a schema change.
*/
-SQLITE_API int sqlite3_set_authorizer(
+SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
sqlite3*,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pUserData
@@ -2740,8 +2890,8 @@ SQLITE_API int sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
-SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
+SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
@@ -2775,7 +2925,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
** database connections for the meaning of "modify" in this paragraph.
**
*/
-SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
+SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
** CAPI3REF: Opening A New Database Connection
@@ -3003,15 +3153,15 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** See also: [sqlite3_temp_directory]
*/
-SQLITE_API int sqlite3_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open16(
+SQLITE_API int SQLITE_STDCALL sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -3057,19 +3207,21 @@ SQLITE_API int sqlite3_open_v2(
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
** CAPI3REF: Error Codes And Messages
**
-** ^The sqlite3_errcode() interface returns the numeric [result code] or
-** [extended result code] for the most recent failed sqlite3_* API call
-** associated with a [database connection]. If a prior API call failed
-** but the most recent API call succeeded, the return value from
-** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
+** ^If the most recent sqlite3_* API call associated with
+** [database connection] D failed, then the sqlite3_errcode(D) interface
+** returns the numeric [result code] or [extended result code] for that
+** API call.
+** If the most recent API call was successful,
+** then the return value from sqlite3_errcode() is undefined.
+** ^The sqlite3_extended_errcode()
** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
@@ -3100,11 +3252,11 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
** was invoked incorrectly by the application. In that case, the
** error code and message may or may not be set.
*/
-SQLITE_API int sqlite3_errcode(sqlite3 *db);
-SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
-SQLITE_API const char *sqlite3_errmsg(sqlite3*);
-SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
-SQLITE_API const char *sqlite3_errstr(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
/*
** CAPI3REF: SQL Statement Object
@@ -3171,7 +3323,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
**
** New run-time limit categories may be added in future releases.
*/
-SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
+SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
/*
** CAPI3REF: Run-Time Limit Categories
@@ -3258,16 +3410,14 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
** use UTF-16.
**
-** ^If the nByte argument is less than zero, then zSql is read up to the
-** first zero terminator. ^If nByte is non-negative, then it is the maximum
-** number of bytes read from zSql. ^When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or
-** the nByte-th byte, whichever comes first. If the caller knows
-** that the supplied string is nul-terminated, then there is a small
-** performance advantage to be gained by passing an nByte parameter that
-** is equal to the number of bytes in the input string <i>including</i>
-** the nul-terminator bytes as this saves SQLite from having to
-** make a copy of the input string.
+** ^If the nByte argument is negative, then zSql is read up to the
+** first zero terminator. ^If nByte is positive, then it is the
+** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** statement is generated.
+** If the caller knows that the supplied string is nul-terminated, then
+** there is a small performance advantage to passing an nByte parameter that
+** is the number of bytes in the input string <i>including</i>
+** the nul-terminator.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -3323,28 +3473,28 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
** </ol>
*/
-SQLITE_API int sqlite3_prepare(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
@@ -3359,7 +3509,7 @@ SQLITE_API int sqlite3_prepare16_v2(
** SQL text used to create a [prepared statement] if that statement was
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
*/
-SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
@@ -3390,7 +3540,7 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
*/
-SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
@@ -3409,7 +3559,7 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
-SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
/*
** CAPI3REF: Dynamically Typed Value Object
@@ -3570,19 +3720,19 @@ typedef struct sqlite3_context sqlite3_context;
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
void(*)(void*));
-SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
-SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
-SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
-SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
-SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
/*
** CAPI3REF: Number Of SQL Parameters
@@ -3602,7 +3752,7 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
** [sqlite3_bind_parameter_name()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
** CAPI3REF: Name Of A Host Parameter
@@ -3629,7 +3779,7 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
/*
** CAPI3REF: Index Of A Parameter With A Given Name
@@ -3645,7 +3795,7 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
** CAPI3REF: Reset All Bindings On A Prepared Statement
@@ -3654,7 +3804,7 @@ SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
** ^Use this routine to reset all host parameters to NULL.
*/
-SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
/*
** CAPI3REF: Number Of Columns In A Result Set
@@ -3665,7 +3815,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
**
** See also: [sqlite3_data_count()]
*/
-SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Column Names In A Result Set
@@ -3693,8 +3843,8 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
** then the name of the column is unspecified and may change from
** one release of SQLite to the next.
*/
-SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
-SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
/*
** CAPI3REF: Source Of Data In A Query Result
@@ -3741,12 +3891,12 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
-SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
/*
** CAPI3REF: Declared Datatype Of A Query Result
@@ -3777,8 +3927,8 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
** is associated with individual values, not with the containers
** used to hold those values.
*/
-SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
/*
** CAPI3REF: Evaluate An SQL Statement
@@ -3857,7 +4007,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** then the more specific [error codes] are returned directly
** by sqlite3_step(). The use of the "v2" interface is recommended.
*/
-SQLITE_API int sqlite3_step(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
/*
** CAPI3REF: Number of columns in a result set
@@ -3877,7 +4027,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
**
** See also: [sqlite3_column_count()]
*/
-SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Fundamental Datatypes
@@ -4073,16 +4223,16 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** pointer. Subsequent calls to [sqlite3_errcode()] will return
** [SQLITE_NOMEM].)^
*/
-SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
@@ -4109,7 +4259,7 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
*/
-SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Reset A Prepared Statement Object
@@ -4135,7 +4285,7 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
-SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
@@ -4234,7 +4384,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** close the database connection nor finalize or reset the prepared
** statement in which the function is running.
*/
-SQLITE_API int sqlite3_create_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4244,7 +4394,7 @@ SQLITE_API int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -4254,7 +4404,7 @@ SQLITE_API int sqlite3_create_function16(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4272,9 +4422,9 @@ SQLITE_API int sqlite3_create_function_v2(
** These constant define integer codes that represent the various
** text encodings supported by SQLite.
*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
+#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */
+#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */
+#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */
#define SQLITE_UTF16 4 /* Use native byte order */
#define SQLITE_ANY 5 /* Deprecated */
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
@@ -4296,16 +4446,16 @@ SQLITE_API int sqlite3_create_function_v2(
** These functions are [deprecated]. In order to maintain
** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
-** the use of these functions. To help encourage people to avoid
-** using these functions, we are not going to tell you what they do.
+** the use of these functions. To encourage programmers to avoid
+** these functions, we will not explain what they do.
*/
#ifndef SQLITE_OMIT_DEPRECATED
-SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
-SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
#endif
@@ -4354,18 +4504,18 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
*/
-SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
-SQLITE_API double sqlite3_value_double(sqlite3_value*);
-SQLITE_API int sqlite3_value_int(sqlite3_value*);
-SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
-SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int sqlite3_value_type(sqlite3_value*);
-SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
@@ -4409,7 +4559,7 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** This routine must be called from the same thread in which
** the aggregate SQL function is running.
*/
-SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
+SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
** CAPI3REF: User Data For Functions
@@ -4423,7 +4573,7 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
** This routine must be called from the same thread in which
** the application-defined function is running.
*/
-SQLITE_API void *sqlite3_user_data(sqlite3_context*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
/*
** CAPI3REF: Database Connection For Functions
@@ -4434,7 +4584,7 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context*);
** and [sqlite3_create_function16()] routines that originally
** registered the application defined function.
*/
-SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
/*
** CAPI3REF: Function Auxiliary Data
@@ -4486,8 +4636,8 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** These routines must be called from the same thread in which
** the SQL function is running.
*/
-SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
-SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
+SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
@@ -4622,25 +4772,26 @@ typedef void (*sqlite3_destructor_type)(void*);
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*));
-SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
-SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
-SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
-SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-SQLITE_API void sqlite3_result_null(sqlite3_context*);
-SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
+ sqlite3_uint64,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
/*
** CAPI3REF: Define New Collating Sequences
@@ -4721,14 +4872,14 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
-SQLITE_API int sqlite3_create_collation(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
-SQLITE_API int sqlite3_create_collation_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
int eTextRep,
@@ -4736,7 +4887,7 @@ SQLITE_API int sqlite3_create_collation_v2(
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
-SQLITE_API int sqlite3_create_collation16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
@@ -4770,12 +4921,12 @@ SQLITE_API int sqlite3_create_collation16(
** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
** [sqlite3_create_collation_v2()].
*/
-SQLITE_API int sqlite3_collation_needed(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
-SQLITE_API int sqlite3_collation_needed16(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
@@ -4789,11 +4940,11 @@ SQLITE_API int sqlite3_collation_needed16(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_key(
+SQLITE_API int SQLITE_STDCALL sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
-SQLITE_API int sqlite3_key_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
@@ -4807,11 +4958,11 @@ SQLITE_API int sqlite3_key_v2(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_rekey(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
-SQLITE_API int sqlite3_rekey_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
@@ -4821,7 +4972,7 @@ SQLITE_API int sqlite3_rekey_v2(
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
-SQLITE_API void sqlite3_activate_see(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4831,7 +4982,7 @@ SQLITE_API void sqlite3_activate_see(
** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
-SQLITE_API void sqlite3_activate_cerod(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4853,7 +5004,7 @@ SQLITE_API void sqlite3_activate_cerod(
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
*/
-SQLITE_API int sqlite3_sleep(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
/*
** CAPI3REF: Name Of The Folder Holding Temporary Files
@@ -4971,7 +5122,7 @@ SQLITE_API char *sqlite3_data_directory;
** connection while this routine is running, then the return value
** is undefined.
*/
-SQLITE_API int sqlite3_get_autocommit(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
/*
** CAPI3REF: Find The Database Handle Of A Prepared Statement
@@ -4983,7 +5134,7 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
-SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Filename For A Database Connection
@@ -4999,7 +5150,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -5008,7 +5159,7 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
** the name of a database on connection D.
*/
-SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Find the next prepared statement
@@ -5023,7 +5174,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
** [sqlite3_next_stmt(D,S)] must refer to an open database
** connection and in particular must not be a NULL pointer.
*/
-SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
+SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
/*
** CAPI3REF: Commit And Rollback Notification Callbacks
@@ -5071,8 +5222,8 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
**
** See also the [sqlite3_update_hook()] interface.
*/
-SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
/*
** CAPI3REF: Data Change Notification Callbacks
@@ -5122,7 +5273,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
** interfaces.
*/
-SQLITE_API void *sqlite3_update_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
@@ -5152,12 +5303,17 @@ SQLITE_API void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
+** and will always return SQLITE_MISUSE. On those systems,
+** shared cache mode should be enabled per-database connection via
+** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
+**
** This interface is threadsafe on processors where writing a
** 32-bit integer is atomic.
**
** See Also: [SQLite Shared-Cache Mode]
*/
-SQLITE_API int sqlite3_enable_shared_cache(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
/*
** CAPI3REF: Attempt To Free Heap Memory
@@ -5173,7 +5329,7 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
**
** See also: [sqlite3_db_release_memory()]
*/
-SQLITE_API int sqlite3_release_memory(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
/*
** CAPI3REF: Free Memory Used By A Database Connection
@@ -5186,7 +5342,7 @@ SQLITE_API int sqlite3_release_memory(int);
**
** See also: [sqlite3_release_memory()]
*/
-SQLITE_API int sqlite3_db_release_memory(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
@@ -5238,7 +5394,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** The circumstances under which SQLite will enforce the soft heap limit may
** changes in future releases of SQLite.
*/
-SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5249,26 +5405,33 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
** only. All new applications should use the
** [sqlite3_soft_heap_limit64()] interface rather than this one.
*/
-SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
**
-** ^This routine returns metadata about a specific column of a specific
-** database table accessible using the [database connection] handle
-** passed as the first function argument.
+** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
+** information about column C of table T in database D
+** on [database connection] X.)^ ^The sqlite3_table_column_metadata()
+** interface returns SQLITE_OK and fills in the non-NULL pointers in
+** the final five arguments with appropriate values if the specified
+** column exists. ^The sqlite3_table_column_metadata() interface returns
+** SQLITE_ERROR and if the specified column does not exist.
+** ^If the column-name parameter to sqlite3_table_column_metadata() is a
+** NULL pointer, then this routine simply checks for the existance of the
+** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
+** does not.
**
** ^The column is identified by the second, third and fourth parameters to
-** this function. ^The second parameter is either the name of the database
+** this function. ^(The second parameter is either the name of the database
** (i.e. "main", "temp", or an attached database) containing the specified
-** table or NULL. ^If it is NULL, then all attached databases are searched
+** table or NULL.)^ ^If it is NULL, then all attached databases are searched
** for the table using the same algorithm used by the database engine to
** resolve unqualified table references.
**
** ^The third and fourth parameters to this function are the table and column
-** name of the desired column, respectively. Neither of these parameters
-** may be NULL.
+** name of the desired column, respectively.
**
** ^Metadata is returned by writing to the memory locations passed as the 5th
** and subsequent parameters to this function. ^Any of these arguments may be
@@ -5287,16 +5450,17 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** </blockquote>)^
**
** ^The memory pointed to by the character pointers returned for the
-** declaration type and collation sequence is valid only until the next
+** declaration type and collation sequence is valid until the next
** call to any SQLite API function.
**
** ^If the specified table is actually a view, an [error code] is returned.
**
-** ^If the specified column is "rowid", "oid" or "_rowid_" and an
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
+** is not a [WITHOUT ROWID] table and an
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
** parameters are set for the explicitly declared column. ^(If there is no
-** explicitly declared [INTEGER PRIMARY KEY] column, then the output
-** parameters are set as follows:
+** [INTEGER PRIMARY KEY] column, then the outputs
+** for the [rowid] are set as follows:
**
** <pre>
** data type: "INTEGER"
@@ -5306,15 +5470,11 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** auto increment: 0
** </pre>)^
**
-** ^(This function may load one or more schemas from database files. If an
-** error occurs during this process, or if the requested table or column
-** cannot be found, an [error code] is returned and an error message left
-** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^
-**
-** ^This API is only available if the library was compiled with the
-** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined.
+** ^This function causes all database schemas to be read from disk and
+** parsed, if that has not already been done, and returns an error if
+** any errors are encountered while loading the schema.
*/
-SQLITE_API int sqlite3_table_column_metadata(
+SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -5360,7 +5520,7 @@ SQLITE_API int sqlite3_table_column_metadata(
**
** See also the [load_extension() SQL function].
*/
-SQLITE_API int sqlite3_load_extension(
+SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Derived from zFile if 0 */
@@ -5380,7 +5540,7 @@ SQLITE_API int sqlite3_load_extension(
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
*/
-SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
** CAPI3REF: Automatically Load Statically Linked Extensions
@@ -5418,7 +5578,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** See also: [sqlite3_reset_auto_extension()]
** and [sqlite3_cancel_auto_extension()]
*/
-SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Cancel Automatic Extension Loading
@@ -5430,7 +5590,7 @@ SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
-SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
@@ -5438,7 +5598,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
** ^This interface disables all automatic extensions previously
** registered using [sqlite3_auto_extension()].
*/
-SQLITE_API void sqlite3_reset_auto_extension(void);
+SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
/*
** The interface to the virtual-table mechanism is currently considered
@@ -5641,13 +5801,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API int sqlite3_create_module(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API int sqlite3_create_module_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -5675,7 +5835,7 @@ SQLITE_API int sqlite3_create_module_v2(
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* NO LONGER USED */
+ int nRef; /* Number of open cursors */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -5710,7 +5870,7 @@ struct sqlite3_vtab_cursor {
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
@@ -5728,7 +5888,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -5765,26 +5925,42 @@ typedef struct sqlite3_blob sqlite3_blob;
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre>)^
**
+** ^(Parameter zDb is not the filename that contains the database, but
+** rather the symbolic name of the database. For attached databases, this is
+** the name that appears after the AS keyword in the [ATTACH] statement.
+** For the main database file, the database name is "main". For TEMP
+** tables, the database name is "temp".)^
+**
** ^If the flags parameter is non-zero, then the BLOB is opened for read
-** and write access. ^If it is zero, the BLOB is opened for read access.
-** ^It is not possible to open a column that is part of an index or primary
-** key for writing. ^If [foreign key constraints] are enabled, it is
-** not possible to open a column that is part of a [child key] for writing.
-**
-** ^Note that the database name is not the filename that contains
-** the database but rather the symbolic name of the database that
-** appears after the AS keyword when the database is connected using [ATTACH].
-** ^For the main database file, the database name is "main".
-** ^For TEMP tables, the database name is "temp".
-**
-** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
-** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
-** to be a null pointer.)^
-** ^This function sets the [database connection] error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
-** functions. ^Note that the *ppBlob variable is always initialized in a
-** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
-** regardless of the success or failure of this routine.
+** and write access. ^If the flags parameter is zero, the BLOB is opened for
+** read-only access.
+**
+** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
+** in *ppBlob. Otherwise an [error code] is returned and, unless the error
+** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
+** on *ppBlob after this function it returns.
+**
+** This function fails with SQLITE_ERROR if any of the following are true:
+** <ul>
+** <li> ^(Database zDb does not exist)^,
+** <li> ^(Table zTable does not exist within database zDb)^,
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
+** <li> ^(Column zColumn does not exist)^,
+** <li> ^(Row iRow is not present in the table)^,
+** <li> ^(The specified column of row iRow contains a value that is not
+** a TEXT or BLOB value)^,
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
+** constraint and the blob is being opened for read/write access)^,
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
+** column zColumn is part of a [child key] definition and the blob is
+** being opened for read/write access)^.
+** </ul>
+**
+** ^Unless it returns SQLITE_MISUSE, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+**
**
** ^(If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
@@ -5802,18 +5978,14 @@ typedef struct sqlite3_blob sqlite3_blob;
** interface. Use the [UPDATE] SQL command to change the size of a
** blob.
**
-** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID]
-** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables.
-**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
-** and the built-in [zeroblob] SQL function can be used, if desired,
-** to create an empty, zero-filled blob in which to read or write using
-** this interface.
+** and the built-in [zeroblob] SQL function may be used to create a
+** zero-filled blob to read or write using the incremental-blob interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
*/
-SQLITE_API int sqlite3_blob_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3*,
const char *zDb,
const char *zTable,
@@ -5845,31 +6017,29 @@ SQLITE_API int sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
**
-** ^Closes an open [BLOB handle].
-**
-** ^Closing a BLOB shall cause the current transaction to commit
-** if there are no other BLOBs, no pending prepared statements, and the
-** database connection is in [autocommit mode].
-** ^If any writes were made to the BLOB, they might be held in cache
-** until the close operation if they will fit.
-**
-** ^(Closing the BLOB often forces the changes
-** out to disk and so if any I/O errors occur, they will likely occur
-** at the time when the BLOB is closed. Any errors that occur during
-** closing are reported as a non-zero return value.)^
+** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
+** unconditionally. Even if this routine returns an error code, the
+** handle is still closed.)^
**
-** ^(The BLOB is closed unconditionally. Even if this routine returns
-** an error code, the BLOB is still closed.)^
+** ^If the blob handle being closed was opened for read-write access, and if
+** the database is in auto-commit mode and there are no other open read-write
+** blob handles or active write statements, the current transaction is
+** committed. ^If an error occurs while committing the transaction, an error
+** code is returned and the transaction rolled back.
**
-** ^Calling this routine with a null pointer (such as would be returned
-** by a failed call to [sqlite3_blob_open()]) is a harmless no-op.
+** Calling this function with an argument that is not a NULL pointer or an
+** open blob handle results in undefined behaviour. ^Calling this routine
+** with a null pointer (such as would be returned by a failed call to
+** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
+** is passed a valid open blob handle, the values returned by the
+** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
-SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB
@@ -5884,7 +6054,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
*/
-SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
/*
** CAPI3REF: Read Data From A BLOB Incrementally
@@ -5912,26 +6082,32 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
**
** See also: [sqlite3_blob_write()].
*/
-SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
/*
** CAPI3REF: Write Data Into A BLOB Incrementally
**
-** ^This function is used to write data into an open [BLOB handle] from a
-** caller-supplied buffer. ^N bytes of data are copied from the buffer Z
-** into the open BLOB, starting at offset iOffset.
+** ^(This function is used to write data into an open [BLOB handle] from a
+** caller-supplied buffer. N bytes of data are copied from the buffer Z
+** into the open BLOB, starting at offset iOffset.)^
+**
+** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
+** Otherwise, an [error code] or an [extended error code] is returned.)^
+** ^Unless SQLITE_MISUSE is returned, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
** ^If the [BLOB handle] passed as the first argument was not opened for
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
** this function returns [SQLITE_READONLY].
**
-** ^This function may only modify the contents of the BLOB; it is
+** This function may only modify the contents of the BLOB; it is
** not possible to increase the size of a BLOB using this API.
** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is written. ^If N is
-** less than zero [SQLITE_ERROR] is returned and no data is written.
-** The size of the BLOB (and hence the maximum value of N+iOffset)
-** can be determined using the [sqlite3_blob_bytes()] interface.
+** [SQLITE_ERROR] is returned and no data is written. The size of the
+** BLOB (and hence the maximum value of N+iOffset) can be determined
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
+** than zero [SQLITE_ERROR] is returned and no data is written.
**
** ^An attempt to write to an expired [BLOB handle] fails with an
** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
@@ -5940,9 +6116,6 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** have been overwritten by the statement that expired the BLOB handle
** or by other independent statements.
**
-** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
-** Otherwise, an [error code] or an [extended error code] is returned.)^
-**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
@@ -5950,7 +6123,7 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
**
** See also: [sqlite3_blob_read()].
*/
-SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
/*
** CAPI3REF: Virtual File System Objects
@@ -5981,9 +6154,9 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOff
** ^(If the default VFS is unregistered, another VFS is chosen as
** the default. The choice for the new VFS is arbitrary.)^
*/
-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
-SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
+SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
/*
** CAPI3REF: Mutexes
@@ -5995,34 +6168,34 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** The SQLite source code contains multiple implementations
** of these mutex routines. An appropriate implementation
-** is selected automatically at compile-time. ^(The following
+** is selected automatically at compile-time. The following
** implementations are available in the SQLite core:
**
** <ul>
** <li> SQLITE_MUTEX_PTHREADS
** <li> SQLITE_MUTEX_W32
** <li> SQLITE_MUTEX_NOOP
-** </ul>)^
+** </ul>
**
-** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
+** The SQLITE_MUTEX_NOOP implementation is a set of routines
** that does no real locking and is appropriate for use in
-** a single-threaded application. ^The SQLITE_MUTEX_PTHREADS and
+** a single-threaded application. The SQLITE_MUTEX_PTHREADS and
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
** and Windows.
**
-** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
+** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
** implementation is included with the library. In this case the
** application must supply a custom mutex implementation using the
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
** before calling sqlite3_initialize() or any other public sqlite3_
-** function that calls sqlite3_initialize().)^
+** function that calls sqlite3_initialize().
**
** ^The sqlite3_mutex_alloc() routine allocates a new
-** mutex and returns a pointer to it. ^If it returns NULL
-** that means that a mutex could not be allocated. ^SQLite
-** will unwind its stack and return an error. ^(The argument
-** to sqlite3_mutex_alloc() is one of these integer constants:
+** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
+** routine returns NULL if it is unable to allocate the requested
+** mutex. The argument to sqlite3_mutex_alloc() must one of these
+** integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST
@@ -6035,7 +6208,8 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
-** </ul>)^
+** <li> SQLITE_MUTEX_STATIC_APP3
+** </ul>
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
** cause sqlite3_mutex_alloc() to create
@@ -6043,14 +6217,14 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
-** not want to. ^SQLite will only request a recursive mutex in
-** cases where it really needs one. ^If a faster non-recursive mutex
+** not want to. SQLite will only request a recursive mutex in
+** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other
** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
-** a pointer to a static preexisting mutex. ^Six static mutexes are
+** a pointer to a static preexisting mutex. ^Nine static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
@@ -6059,16 +6233,13 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. ^But for the static
+** returns a different mutex on every call. ^For the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
**
** ^The sqlite3_mutex_free() routine deallocates a previously
-** allocated dynamic mutex. ^SQLite is careful to deallocate every
-** dynamic mutex that it allocates. The dynamic mutexes must not be in
-** use when they are deallocated. Attempting to deallocate a static
-** mutex results in undefined behavior. ^SQLite never deallocates
-** a static mutex.
+** allocated dynamic mutex. Attempting to deallocate a static
+** mutex results in undefined behavior.
**
** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. ^If another thread is already within the mutex,
@@ -6076,23 +6247,21 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK]
** upon successful entry. ^(Mutexes created using
** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
-** In such cases the,
+** In such cases, the
** mutex must be exited an equal number of times before another thread
-** can enter.)^ ^(If the same thread tries to enter any other
-** kind of mutex more than once, the behavior is undefined.
-** SQLite will never exhibit
-** such behavior in its own use of mutexes.)^
+** can enter.)^ If the same thread tries to enter any mutex other
+** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined.
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^
+** will always return SQLITE_BUSY. The SQLite core only ever uses
+** sqlite3_mutex_try() as an optimization so this is acceptable
+** behavior.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
-** previously entered by the same thread. ^(The behavior
+** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
-** calling thread or is not currently allocated. SQLite will
-** never do either.)^
+** calling thread or is not currently allocated.
**
** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
** sqlite3_mutex_leave() is a NULL pointer, then all three routines
@@ -6100,11 +6269,11 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
@@ -6113,9 +6282,9 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** used to allocate and use mutexes.
**
** Usually, the default mutex implementations provided by SQLite are
-** sufficient, however the user has the option of substituting a custom
+** sufficient, however the application has the option of substituting a custom
** implementation for specialized deployments or systems for which SQLite
-** does not provide a suitable implementation. In this case, the user
+** does not provide a suitable implementation. In this case, the application
** creates and populates an instance of this structure to pass
** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option.
** Additionally, an instance of this structure can be used as an
@@ -6156,13 +6325,13 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
-** The xMutexInit() method must be threadsafe. ^It must be harmless to
+** The xMutexInit() method must be threadsafe. It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd(). Second and subsequent calls to
** xMutexInit() must be no-ops.
**
-** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
-** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory
+** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
+** and its associates). Similarly, xMutexAlloc() must not use SQLite memory
** allocation for a static mutex. ^However xMutexAlloc() may use SQLite
** memory allocation for a fast or recursive mutex.
**
@@ -6188,34 +6357,34 @@ struct sqlite3_mutex_methods {
** CAPI3REF: Mutex Verification Routines
**
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
-** are intended for use inside assert() statements. ^The SQLite core
+** are intended for use inside assert() statements. The SQLite core
** never uses these routines except inside an assert() and applications
-** are advised to follow the lead of the core. ^The SQLite core only
+** are advised to follow the lead of the core. The SQLite core only
** provides implementations for these routines when it is compiled
-** with the SQLITE_DEBUG flag. ^External mutex implementations
+** with the SQLITE_DEBUG flag. External mutex implementations
** are only required to provide these routines if SQLITE_DEBUG is
** defined and if NDEBUG is not defined.
**
-** ^These routines should return true if the mutex in their argument
+** These routines should return true if the mutex in their argument
** is held or not held, respectively, by the calling thread.
**
-** ^The implementation is not required to provide versions of these
+** The implementation is not required to provide versions of these
** routines that actually work. If the implementation does not provide working
** versions of these routines, it should at least provide stubs that always
** return true so that one does not get spurious assertion failures.
**
-** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
+** If the argument to sqlite3_mutex_held() is a NULL pointer then
** the routine should return 1. This seems counter-intuitive since
** clearly the mutex cannot be held if it does not exist. But
** the reason the mutex does not exist is because the build is not
** using mutexes. And we do not want the assert() containing the
** call to sqlite3_mutex_held() to fail, so a non-zero return is
-** the appropriate thing to do. ^The sqlite3_mutex_notheld()
+** the appropriate thing to do. The sqlite3_mutex_notheld()
** interface should also return 1 when given a NULL pointer.
*/
#ifndef NDEBUG
-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#endif
/*
@@ -6251,7 +6420,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
** ^If the [threading mode] is Single-thread or Multi-thread then this
** routine returns a NULL pointer.
*/
-SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
@@ -6285,7 +6454,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
**
** See also: [SQLITE_FCNTL_LOCKSTATE]
*/
-SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
/*
** CAPI3REF: Testing Interface
@@ -6304,7 +6473,7 @@ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*
** Unlike most of the SQLite API, this function is not guaranteed to
** operate consistently from one release to the next.
*/
-SQLITE_API int sqlite3_test_control(int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
/*
** CAPI3REF: Testing Interface Operation Codes
@@ -6338,12 +6507,13 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24
-#define SQLITE_TESTCTRL_LAST 24
+#define SQLITE_TESTCTRL_IMPOSTER 25
+#define SQLITE_TESTCTRL_LAST 25
/*
** CAPI3REF: SQLite Runtime Status
**
-** ^This interface is used to retrieve runtime status information
+** ^These interfaces are used to retrieve runtime status information
** about the performance of SQLite, and optionally to reset various
** highwater marks. ^The first argument is an integer code for
** the specific parameter to measure. ^(Recognized integer codes
@@ -6357,19 +6527,22 @@ SQLITE_API int sqlite3_test_control(int op, ...);
** ^(Other parameters record only the highwater mark and not the current
** value. For these latter parameters nothing is written into *pCurrent.)^
**
-** ^The sqlite3_status() routine returns SQLITE_OK on success and a
-** non-zero [error code] on failure.
+** ^The sqlite3_status() and sqlite3_status64() routines return
+** SQLITE_OK on success and a non-zero [error code] on failure.
**
-** This routine is threadsafe but is not atomic. This routine can be
-** called while other threads are running the same or different SQLite
-** interfaces. However the values returned in *pCurrent and
-** *pHighwater reflect the status of SQLite at different points in time
-** and it is possible that another thread might change the parameter
-** in between the times when *pCurrent and *pHighwater are written.
+** If either the current value or the highwater mark is too large to
+** be represented by a 32-bit integer, then the values returned by
+** sqlite3_status() are undefined.
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+);
/*
@@ -6487,7 +6660,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
@@ -6616,7 +6789,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
@@ -6943,6 +7116,10 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
+** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
+** there is already a read or read-write transaction open on the
+** destination database.
+**
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
** returned and an error code and error message are stored in the
** destination [database connection] D.
@@ -7035,20 +7212,20 @@ typedef struct sqlite3_backup sqlite3_backup;
** is not a permanent error and does not affect the return value of
** sqlite3_backup_finish().
**
-** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]]
** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
**
-** ^Each call to sqlite3_backup_step() sets two values inside
-** the [sqlite3_backup] object: the number of pages still to be backed
-** up and the total number of pages in the source database file.
-** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
-** retrieve these two values, respectively.
-**
-** ^The values returned by these functions are only updated by
-** sqlite3_backup_step(). ^If the source database is modified during a backup
-** operation, then the values are not updated to account for any extra
-** pages that need to be updated or the size of the source database file
-** changing.
+** ^The sqlite3_backup_remaining() routine returns the number of pages still
+** to be backed up at the conclusion of the most recent sqlite3_backup_step().
+** ^The sqlite3_backup_pagecount() routine returns the total number of pages
+** in the source database at the conclusion of the most recent
+** sqlite3_backup_step().
+** ^(The values returned by these functions are only updated by
+** sqlite3_backup_step(). If the source database is modified in a way that
+** changes the size of the source database or the number of pages remaining,
+** those changes are not reflected in the output of sqlite3_backup_pagecount()
+** and sqlite3_backup_remaining() until after the next
+** sqlite3_backup_step().)^
**
** <b>Concurrent Usage of Database Handles</b>
**
@@ -7081,16 +7258,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
*/
-SQLITE_API sqlite3_backup *sqlite3_backup_init(
+SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
const char *zDestName, /* Destination database name */
sqlite3 *pSource, /* Source database handle */
const char *zSourceName /* Source database name */
);
-SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
-SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
@@ -7206,7 +7383,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
-SQLITE_API int sqlite3_unlock_notify(
+SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
sqlite3 *pBlocked, /* Waiting connection */
void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
void *pNotifyArg /* Argument to pass to xNotify */
@@ -7221,8 +7398,8 @@ SQLITE_API int sqlite3_unlock_notify(
** strings in a case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int sqlite3_stricmp(const char *, const char *);
-SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
+SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
@@ -7237,7 +7414,7 @@ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
*/
-SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
+SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: Error Logging Interface
@@ -7260,18 +7437,16 @@ SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
** a few hundred characters, it will be truncated to the length of the
** buffer.
*/
-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
+SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
**
** ^The [sqlite3_wal_hook()] function is used to register a callback that
-** will be invoked each time a database connection commits data to a
-** [write-ahead log] (i.e. whenever a transaction is committed in
-** [journal_mode | journal_mode=WAL mode]).
+** is invoked each time data is committed to a database in wal mode.
**
-** ^The callback is invoked by SQLite after the commit has taken place and
-** the associated write-lock on the database released, so the implementation
+** ^(The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released)^, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
@@ -7297,7 +7472,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
-SQLITE_API void *sqlite3_wal_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
@@ -7331,104 +7506,121 @@ SQLITE_API void *sqlite3_wal_hook(
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
-SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
**
-** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
-** on [database connection] D to be [checkpointed]. ^If X is NULL or an
-** empty string, then a checkpoint is run on all databases of
-** connection D. ^If the database connection D is not in
-** [WAL | write-ahead log mode] then this interface is a harmless no-op.
-** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
-** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
-** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
-** or RESET checkpoint.
+** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
+** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
**
-** ^The [wal_checkpoint pragma] can be used to invoke this interface
-** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
-** [wal_autocheckpoint pragma] can be used to cause this interface to be
-** run whenever the WAL reaches a certain size threshold.
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
+** [write-ahead log] for database X on [database connection] D to be
+** transferred into the database file and for the write-ahead log to
+** be reset. See the [checkpointing] documentation for addition
+** information.
**
-** See also: [sqlite3_wal_checkpoint_v2()]
+** This interface used to be the only way to cause a checkpoint to
+** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()]
+** interface was added. This interface is retained for backwards
+** compatibility and as a convenience for applications that need to manually
+** start a callback but which do not need the full power (and corresponding
+** complication) of [sqlite3_wal_checkpoint_v2()].
*/
-SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** CAPI3REF: Checkpoint a database
**
-** Run a checkpoint operation on WAL database zDb attached to database
-** handle db. The specific operation is determined by the value of the
-** eMode parameter:
+** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint
+** operation on database X of [database connection] D in mode M. Status
+** information is written back into integers pointed to by L and C.)^
+** ^(The M parameter must be a valid [checkpoint mode]:)^
**
** <dl>
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
-** Checkpoint as many frames as possible without waiting for any database
-** readers or writers to finish. Sync the db file if all frames in the log
-** are checkpointed. This mode is the same as calling
-** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
-** is never invoked.
+** ^Checkpoint as many frames as possible without waiting for any database
+** readers or writers to finish, then sync the database file if all frames
+** in the log were checkpointed. ^The [busy-handler callback]
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
+** ^On the other hand, passive mode might leave the checkpoint unfinished
+** if there are concurrent readers or writers.
**
** <dt>SQLITE_CHECKPOINT_FULL<dd>
-** This mode blocks (it invokes the
+** ^This mode blocks (it invokes the
** [sqlite3_busy_handler|busy-handler callback]) until there is no
** database writer and all readers are reading from the most recent database
-** snapshot. It then checkpoints all frames in the log file and syncs the
-** database file. This call blocks database writers while it is running,
-** but not database readers.
+** snapshot. ^It then checkpoints all frames in the log file and syncs the
+** database file. ^This mode blocks new database writers while it is pending,
+** but new database readers are allowed to continue unimpeded.
**
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
-** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
-** checkpointing the log file it blocks (calls the
-** [sqlite3_busy_handler|busy-handler callback])
-** until all readers are reading from the database file only. This ensures
-** that the next client to write to the database file restarts the log file
-** from the beginning. This call blocks database writers while it is running,
-** but not database readers.
+** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
+** that after checkpointing the log file it blocks (calls the
+** [busy-handler callback])
+** until all readers are reading from the database file only. ^This ensures
+** that the next writer will restart the log file from the beginning.
+** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
+** database writer attempts while it is pending, but does not impede readers.
+**
+** <dt>SQLITE_CHECKPOINT_TRUNCATE<dd>
+** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the
+** addition that it also truncates the log file to zero bytes just prior
+** to a successful return.
** </dl>
**
-** If pnLog is not NULL, then *pnLog is set to the total number of frames in
-** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to
-** the total number of checkpointed frames (including any that were already
-** checkpointed when this function is called). *pnLog and *pnCkpt may be
-** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK.
-** If no values are available because of an error, they are both set to -1
-** before returning to communicate this to the caller.
-**
-** All calls obtain an exclusive "checkpoint" lock on the database file. If
+** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in
+** the log file or to -1 if the checkpoint could not run because
+** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not
+** NULL,then *pnCkpt is set to the total number of checkpointed frames in the
+** log file (including any that were already checkpointed before the function
+** was called) or to -1 if the checkpoint could not run due to an error or
+** because the database is not in WAL mode. ^Note that upon successful
+** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been
+** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
+**
+** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
** any other process is running a checkpoint operation at the same time, the
-** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
** busy-handler configured, it will not be invoked in this case.
**
-** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive
-** "writer" lock on the database file. If the writer lock cannot be obtained
-** immediately, and a busy-handler is configured, it is invoked and the writer
-** lock retried until either the busy-handler returns 0 or the lock is
-** successfully obtained. The busy-handler is also invoked while waiting for
-** database readers as described above. If the busy-handler returns 0 before
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
+** exclusive "writer" lock on the database file. ^If the writer lock cannot be
+** obtained immediately, and a busy-handler is configured, it is invoked and
+** the writer lock retried until either the busy-handler returns 0 or the lock
+** is successfully obtained. ^The busy-handler is also invoked while waiting for
+** database readers as described above. ^If the busy-handler returns 0 before
** the writer lock is obtained or while waiting for database readers, the
** checkpoint operation proceeds from that point in the same way as
** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
-** without blocking any further. SQLITE_BUSY is returned in this case.
+** without blocking any further. ^SQLITE_BUSY is returned in this case.
**
-** If parameter zDb is NULL or points to a zero length string, then the
-** specified operation is attempted on all WAL databases. In this case the
-** values written to output parameters *pnLog and *pnCkpt are undefined. If
+** ^If parameter zDb is NULL or points to a zero length string, then the
+** specified operation is attempted on all WAL databases [attached] to
+** [database connection] db. In this case the
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
** an SQLITE_BUSY error is encountered when processing one or more of the
** attached WAL databases, the operation is still attempted on any remaining
-** attached databases and SQLITE_BUSY is returned to the caller. If any other
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
** error occurs while processing an attached database, processing is abandoned
-** and the error code returned to the caller immediately. If no error
+** and the error code is returned to the caller immediately. ^If no error
** (SQLITE_BUSY or otherwise) is encountered while processing the attached
** databases, SQLITE_OK is returned.
**
-** If database zDb is the name of an attached database that is not in WAL
-** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If
+** ^If database zDb is the name of an attached database that is not in WAL
+** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If
** zDb is not NULL (or a zero length string) and is not the name of any
** attached database, SQLITE_ERROR is returned to the caller.
+**
+** ^Unless it returns SQLITE_MISUSE,
+** the sqlite3_wal_checkpoint_v2() interface
+** sets the error information that is queried by
+** [sqlite3_errcode()] and [sqlite3_errmsg()].
+**
+** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
+** from SQL.
*/
-SQLITE_API int sqlite3_wal_checkpoint_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -7437,16 +7629,18 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
);
/*
-** CAPI3REF: Checkpoint operation parameters
+** CAPI3REF: Checkpoint Mode Values
+** KEYWORDS: {checkpoint mode}
**
-** These constants can be used as the 3rd parameter to
-** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()]
-** documentation for additional information about the meaning and use of
-** each of these values.
+** These constants define all valid values for the "checkpoint mode" passed
+** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface.
+** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the
+** meaning of each of these checkpoint modes.
*/
-#define SQLITE_CHECKPOINT_PASSIVE 0
-#define SQLITE_CHECKPOINT_FULL 1
-#define SQLITE_CHECKPOINT_RESTART 2
+#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
+#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
** CAPI3REF: Virtual Table Interface Configuration
@@ -7462,7 +7656,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
** may be added in the future.
*/
-SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
@@ -7515,7 +7709,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
-SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
+SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
@@ -7535,6 +7729,106 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/* #define SQLITE_ABORT 4 // Also an error code */
#define SQLITE_REPLACE 5
+/*
+** CAPI3REF: Prepared Statement Scan Status Opcodes
+** KEYWORDS: {scanstatus options}
+**
+** The following constants can be used for the T parameter to the
+** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
+** different metric for sqlite3_stmt_scanstatus() to return.
+**
+** When the value returned to V is a string, space to hold that string is
+** managed by the prepared statement S and will be automatically freed when
+** S is finalized.
+**
+** <dl>
+** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
+** set to the total number of times that the X-th loop has run.</dd>
+**
+** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
+** to the total number of rows examined by all iterations of the X-th loop.</dd>
+**
+** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
+** <dd>^The "double" variable pointed to by the T parameter will be set to the
+** query planner's estimate for the average number of rows output from each
+** iteration of the X-th loop. If the query planner's estimates was accurate,
+** then this value will approximate the quotient NVISIT/NLOOP and the
+** product of this value for all prior loops with the same SELECTID will
+** be the NLOOP value for the current loop.
+**
+** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the name of the index or table
+** used for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
+** description for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** <dd>^The "int" variable pointed to by the T parameter will be set to the
+** "select-id" for the X-th loop. The select-id identifies which query or
+** subquery the loop is part of. The main query has a select-id of zero.
+** The select-id is the same value as is output in the first column
+** of an [EXPLAIN QUERY PLAN] query.
+** </dl>
+*/
+#define SQLITE_SCANSTAT_NLOOP 0
+#define SQLITE_SCANSTAT_NVISIT 1
+#define SQLITE_SCANSTAT_EST 2
+#define SQLITE_SCANSTAT_NAME 3
+#define SQLITE_SCANSTAT_EXPLAIN 4
+#define SQLITE_SCANSTAT_SELECTID 5
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+**
+** This interface returns information about the predicted and measured
+** performance for pStmt. Advanced applications can use this
+** interface to compare the predicted and the measured performance and
+** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
+**
+** Since this interface is expected to be rarely used, it is only
+** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
+** compile-time option.
+**
+** The "iScanStatusOp" parameter determines which status information to return.
+** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
+** of this interface is undefined.
+** ^The requested measurement is written into a variable pointed to by
+** the "pOut" parameter.
+** Parameter "idx" identifies the specific loop to retrieve statistics for.
+** Loops are numbered starting from zero. ^If idx is out of range - less than
+** zero or greater than or equal to the total number of loops used to implement
+** the statement - a non-zero value is returned and the variable that pOut
+** points to is unchanged.
+**
+** ^Statistics might not be available for all loops in all statements. ^In cases
+** where there exist loops with no available statistics, this function behaves
+** as if the loop did not exist - it returns non-zero and leave the variable
+** that pOut points to unchanged.
+**
+** See also: [sqlite3_stmt_scanstatus_reset()]
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Zero Scan-Status Counters
+**
+** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
+**
+** This API is only available if the library is built with pre-processor
+** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
@@ -7589,7 +7883,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
*/
-SQLITE_API int sqlite3_rtree_geometry_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
@@ -7615,7 +7909,7 @@ struct sqlite3_rtree_geometry {
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
-SQLITE_API int sqlite3_rtree_query_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
@@ -7779,15 +8073,17 @@ struct sqlite3_rtree_query_info {
#endif
/*
-** The maximum number of in-memory pages to use for the main database
-** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
+** The suggested maximum number of in-memory pages to use for
+** the main database table and for temporary tables.
+**
+** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
+** is 2000 pages.
+** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
+** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
*/
#ifndef SQLITE_DEFAULT_CACHE_SIZE
# define SQLITE_DEFAULT_CACHE_SIZE 2000
#endif
-#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
-# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
-#endif
/*
** The default number of frames to accumulate in the log file before
@@ -7980,10 +8276,9 @@ struct sqlite3_rtree_query_info {
#endif
/*
-** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
-** It determines whether or not the features related to
-** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
-** be overridden at runtime using the sqlite3_config() API.
+** EVIDENCE-OF: R-25715-37072 Memory allocation statistics are enabled by
+** default unless SQLite is compiled with SQLITE_DEFAULT_MEMSTATUS=0 in
+** which case memory allocation statistics are disabled by default.
*/
#if !defined(SQLITE_DEFAULT_MEMSTATUS)
# define SQLITE_DEFAULT_MEMSTATUS 1
@@ -8613,7 +8908,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
** gives a possible range of values of approximately 1.0e986 to 1e-986.
** But the allowed values are "grainy". Not every value is representable.
** For example, quantities 16 and 17 are both represented by a LogEst
-** of 40. However, since LogEst quantaties are suppose to be estimates,
+** of 40. However, since LogEst quantities are suppose to be estimates,
** not exact values, this imprecision is not a problem.
**
** "LogEst" is short for "Logarithmic Estimate".
@@ -8633,6 +8928,20 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
typedef INT16_TYPE LogEst;
/*
+** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer
+*/
+#ifndef SQLITE_PTRSIZE
+# if defined(__SIZEOF_POINTER__)
+# define SQLITE_PTRSIZE __SIZEOF_POINTER__
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(_M_ARM) || defined(__arm__) || defined(__x86)
+# define SQLITE_PTRSIZE 4
+# else
+# define SQLITE_PTRSIZE 8
+# endif
+#endif
+
+/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
**
@@ -8844,8 +9153,8 @@ struct BusyHandler {
#define SQLITE_WSD const
#define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v)))
#define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config)
-SQLITE_API int sqlite3_wsd_init(int N, int J);
-SQLITE_API void *sqlite3_wsd_find(void *K, int L);
+SQLITE_API int SQLITE_STDCALL sqlite3_wsd_init(int N, int J);
+SQLITE_API void *SQLITE_STDCALL sqlite3_wsd_find(void *K, int L);
#else
#define SQLITE_WSD
#define GLOBAL(t,v) v
@@ -8949,7 +9258,7 @@ typedef struct With With;
/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/
-#define SQLITE_N_BTREE_META 10
+#define SQLITE_N_BTREE_META 16
/*
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
@@ -9003,10 +9312,8 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*);
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
-#endif
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int);
@@ -9064,6 +9371,11 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
** For example, the free-page-count field is located at byte offset 36 of
** the database file header. The incr-vacuum-flag field is located at
** byte offset 64 (== 36+4*7).
+**
+** The BTREE_DATA_VERSION value is not really a value stored in the header.
+** It is a read-only number computed by the pager. But we merge it with
+** the header value access routines since its access pattern is the same.
+** Call it a "virtual meta value".
*/
#define BTREE_FREE_PAGE_COUNT 0
#define BTREE_SCHEMA_VERSION 1
@@ -9074,12 +9386,23 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
#define BTREE_USER_VERSION 6
#define BTREE_INCR_VACUUM 7
#define BTREE_APPLICATION_ID 8
+#define BTREE_DATA_VERSION 15 /* A virtual meta-value */
/*
** Values that may be OR'd together to form the second argument of an
** sqlite3BtreeCursorHints() call.
+**
+** The BTREE_BULKLOAD flag is set on index cursors when the index is going
+** to be filled with content that is already in sorted order.
+**
+** The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or
+** OP_SeekLE opcodes for a range search, but where the range of entries
+** selected will all have the same key. In other words, the cursor will
+** be used only for equality key searches.
+**
*/
-#define BTREE_BULKLOAD 0x00000001
+#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */
+#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */
SQLITE_PRIVATE int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
@@ -9125,7 +9448,11 @@ SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
+#endif
SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt);
+SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
@@ -9490,23 +9817,25 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_MemMax 136 /* synopsis: r[P1]=max(r[P1],r[P2]) */
#define OP_IfPos 137 /* synopsis: if r[P1]>0 goto P2 */
#define OP_IfNeg 138 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */
-#define OP_IfZero 139 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */
-#define OP_AggFinal 140 /* synopsis: accum=r[P1] N=P2 */
-#define OP_IncrVacuum 141
-#define OP_Expire 142
-#define OP_TableLock 143 /* synopsis: iDb=P1 root=P2 write=P3 */
-#define OP_VBegin 144
-#define OP_VCreate 145
-#define OP_VDestroy 146
-#define OP_VOpen 147
-#define OP_VColumn 148 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VNext 149
-#define OP_VRename 150
-#define OP_Pagecount 151
-#define OP_MaxPgcnt 152
-#define OP_Init 153 /* synopsis: Start at P2 */
-#define OP_Noop 154
-#define OP_Explain 155
+#define OP_IfNotZero 139 /* synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 */
+#define OP_DecrJumpZero 140 /* synopsis: if (--r[P1])==0 goto P2 */
+#define OP_JumpZeroIncr 141 /* synopsis: if (r[P1]++)==0 ) goto P2 */
+#define OP_AggFinal 142 /* synopsis: accum=r[P1] N=P2 */
+#define OP_IncrVacuum 143
+#define OP_Expire 144
+#define OP_TableLock 145 /* synopsis: iDb=P1 root=P2 write=P3 */
+#define OP_VBegin 146
+#define OP_VCreate 147
+#define OP_VDestroy 148
+#define OP_VOpen 149
+#define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VNext 151
+#define OP_VRename 152
+#define OP_Pagecount 153
+#define OP_MaxPgcnt 154
+#define OP_Init 155 /* synopsis: Start at P2 */
+#define OP_Noop 156
+#define OP_Explain 157
/* Properties such as "out2" or "jump" that are specified in
@@ -9538,9 +9867,9 @@ typedef struct VdbeOpList VdbeOpList;
/* 112 */ 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,\
/* 120 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 128 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x02, 0x00, 0x01,\
-/* 136 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00,\
-/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,\
-/* 152 */ 0x02, 0x01, 0x00, 0x00,}
+/* 136 */ 0x08, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x01,\
+/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\
+/* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,}
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
@@ -9668,6 +9997,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int);
# define VDBE_OFFSET_LINENO(x) 0
#endif
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
+#else
+# define sqlite3VdbeScanStatus(a,b,c,d,e)
+#endif
+
#endif
/************** End of vdbe.h ************************************************/
@@ -9848,6 +10183,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
@@ -9864,6 +10200,8 @@ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
+SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
+
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
#endif
@@ -10051,6 +10389,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats(int*,int*,int*,int*);
SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
+/* Return the header size */
+SQLITE_PRIVATE int sqlite3HeaderSizePcache(void);
+SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
+
#endif /* _PCACHE_H_ */
/************** End of pcache.h **********************************************/
@@ -10583,6 +10925,7 @@ struct sqlite3 {
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
u16 dbOptFlags; /* Flags to enable/disable optimizations */
+ u8 enc; /* Text encoding */
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
u8 mallocFailed; /* True if we have seen a malloc failure */
@@ -10602,11 +10945,13 @@ struct sqlite3 {
u8 iDb; /* Which db file is being initialized */
u8 busy; /* TRUE if currently initializing */
u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
+ u8 imposterTable; /* Building an imposter table */
} init;
int nVdbeActive; /* Number of VDBEs currently running */
int nVdbeRead; /* Number of active VDBEs that read or write */
int nVdbeWrite; /* Number of active VDBEs that read and write */
int nVdbeExec; /* Number of nested calls to VdbeExec() */
+ int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
void (*xTrace)(void*,const char*); /* Trace function */
@@ -10684,7 +11029,8 @@ struct sqlite3 {
/*
** A macro to discover the encoding of a database.
*/
-#define ENC(db) ((db)->aDb[0].pSchema->enc)
+#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
+#define ENC(db) ((db)->enc)
/*
** Possible values for the sqlite3.flags.
@@ -10737,7 +11083,7 @@ struct sqlite3 {
#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
-#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */
+#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@@ -11308,7 +11654,6 @@ struct Index {
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
- KeyInfo *pKeyInfo; /* A KeyInfo object suitable for this index */
int tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nKeyCol; /* Number of columns forming the key */
@@ -11319,12 +11664,14 @@ struct Index {
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
unsigned isResized:1; /* True if resizeIndexObject() has been called */
unsigned isCovering:1; /* True if this is a covering index */
+ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
- tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this table */
+ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
+ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
};
@@ -11522,7 +11869,7 @@ struct Expr {
int iTable; /* TK_COLUMN: cursor number of table holding column
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
- ** EP_Unlikely: 1000 times likelihood */
+ ** EP_Unlikely: 134217728 times likelihood */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
** TK_VARIABLE: variable number (always >= 1). */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
@@ -11537,7 +11884,7 @@ struct Expr {
/*
** The following are the meanings of bits in the Expr.flags field.
*/
-#define EP_FromJoin 0x000001 /* Originated in ON or USING clause of a join */
+#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x000008 /* Expression contains one or more errors */
@@ -11556,7 +11903,14 @@ struct Expr {
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
-#define EP_Constant 0x080000 /* Node is a constant */
+#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */
+#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
+#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
+
+/*
+** Combinations of two or more EP_* flags
+*/
+#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
/*
** These macros can be used to test, set, or clear bits in the
@@ -11755,7 +12109,7 @@ struct SrcList {
#define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */
#define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */
#define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */
- /* 0x0080 // not currently used */
+#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */
#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */
#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
@@ -11869,11 +12223,12 @@ struct Select {
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
#define SF_Compound 0x0040 /* Part of a compound query */
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
- /* 0x0100 NOT USED */
+#define SF_AllValues 0x0100 /* All terms of compound are VALUES */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
+#define SF_Converted 0x2000 /* By convertCompoundSelectToSubquery() */
/*
@@ -12192,7 +12547,8 @@ struct AuthContext {
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
-#define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */
+#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
+#define OPFLAG_P2ISREG 0x04 /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
/*
@@ -12359,6 +12715,7 @@ struct Sqlite3Config {
int nPage; /* Number of pages in pPage[] */
int mxParserStack; /* maximum depth of the parser stack */
int sharedCacheEnabled; /* true if shared-cache mode enabled */
+ u32 szPma; /* Maximum Sorter PMA size */
/* The above might be initialized to non-zero. The following need to always
** initially be zero, however. */
int isInit; /* True after initialization has finished */
@@ -12414,9 +12771,11 @@ struct Walker {
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
Parse *pParse; /* Parser context. */
int walkerDepth; /* Number of subqueries */
+ u8 eCode; /* A small processing code */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
- int i; /* Integer value */
+ int n; /* A counter */
+ int iCur; /* A cursor number */
SrcList *pSrcList; /* FROM clause */
struct SrcCount *pSrcCount; /* Counting column references */
} u;
@@ -12494,7 +12853,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3.
*/
#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
-# define SQLITE_ENABLE_FTS3
+# define SQLITE_ENABLE_FTS3 1
#endif
/*
@@ -12593,10 +12952,15 @@ SQLITE_PRIVATE int sqlite3MutexInit(void);
SQLITE_PRIVATE int sqlite3MutexEnd(void);
#endif
-SQLITE_PRIVATE int sqlite3StatusValue(int);
-SQLITE_PRIVATE void sqlite3StatusAdd(int, int);
+SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
+SQLITE_PRIVATE void sqlite3StatusUp(int, int);
+SQLITE_PRIVATE void sqlite3StatusDown(int, int);
SQLITE_PRIVATE void sqlite3StatusSet(int, int);
+/* Access to mutexes used by sqlite3_status() */
+SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void);
+SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void);
+
#ifndef SQLITE_OMIT_FLOATING_POINT
SQLITE_PRIVATE int sqlite3IsNaN(double);
#else
@@ -12661,6 +13025,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
+SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
@@ -12817,6 +13182,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
+SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
@@ -12974,7 +13340,7 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
-SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
@@ -13243,12 +13609,11 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
SQLITE_PRIVATE int sqlite3MemJournalSize(void);
SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *);
+SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
#if SQLITE_MAX_EXPR_DEPTH>0
-SQLITE_PRIVATE void sqlite3ExprSetHeight(Parse *pParse, Expr *p);
SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *);
SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int);
#else
- #define sqlite3ExprSetHeight(x,y)
#define sqlite3SelectExprHeight(x) 0
#define sqlite3ExprCheckHeight(x,y)
#endif
@@ -13278,7 +13643,7 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *);
#ifdef SQLITE_ENABLE_IOTRACE
# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*);
-SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*,...);
+SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
#else
# define IOTRACE(A)
# define sqlite3VdbeIOTraceSql(X)
@@ -13385,16 +13750,16 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
- 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
- 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
+ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */
160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
- 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
- 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
+ 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */
#endif
};
@@ -13474,15 +13839,30 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
**
** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled
** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
+**
+** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
+** disabled. The default value may be changed by compiling with the
+** SQLITE_USE_URI symbol defined.
*/
#ifndef SQLITE_USE_URI
# define SQLITE_USE_URI 0
#endif
+/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
+** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
+** that compile-time option is omitted.
+*/
#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
#endif
+/* The minimum PMA size is set to this value multiplied by the database
+** page size in bytes.
+*/
+#ifndef SQLITE_SORTER_PMASZ
+# define SQLITE_SORTER_PMASZ 250
+#endif
+
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -13513,6 +13893,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* nPage */
0, /* mxParserStack */
0, /* sharedCacheEnabled */
+ SQLITE_SORTER_PMASZ, /* szPma */
/* All the rest should always be initialized to zero */
0, /* isInit */
0, /* inProgress */
@@ -13568,8 +13949,8 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
**
** IMPORTANT: Changing the pending byte to any value other than
** 0x40000000 results in an incompatible database file format!
-** Changing the pending byte during operating results in undefined
-** and dileterious behavior.
+** Changing the pending byte during operation will result in undefined
+** and incorrect behavior.
*/
#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
@@ -13619,88 +14000,91 @@ static const char * const azCompileOpt[] = {
#define CTIMEOPT_VAL_(opt) #opt
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
-#ifdef SQLITE_32BIT_ROWID
+#if SQLITE_32BIT_ROWID
"32BIT_ROWID",
#endif
-#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+#if SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC",
#endif
-#ifdef SQLITE_CASE_SENSITIVE_LIKE
+#if SQLITE_CASE_SENSITIVE_LIKE
"CASE_SENSITIVE_LIKE",
#endif
-#ifdef SQLITE_CHECK_PAGES
+#if SQLITE_CHECK_PAGES
"CHECK_PAGES",
#endif
-#ifdef SQLITE_COVERAGE_TEST
+#if SQLITE_COVERAGE_TEST
"COVERAGE_TEST",
#endif
-#ifdef SQLITE_DEBUG
+#if SQLITE_DEBUG
"DEBUG",
#endif
-#ifdef SQLITE_DEFAULT_LOCKING_MODE
+#if SQLITE_DEFAULT_LOCKING_MODE
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
#endif
-#ifdef SQLITE_DISABLE_DIRSYNC
+#if SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC",
#endif
-#ifdef SQLITE_DISABLE_LFS
+#if SQLITE_DISABLE_LFS
"DISABLE_LFS",
#endif
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if SQLITE_ENABLE_API_ARMOR
+ "ENABLE_API_ARMOR",
+#endif
+#if SQLITE_ENABLE_ATOMIC_WRITE
"ENABLE_ATOMIC_WRITE",
#endif
-#ifdef SQLITE_ENABLE_CEROD
+#if SQLITE_ENABLE_CEROD
"ENABLE_CEROD",
#endif
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
+#if SQLITE_ENABLE_COLUMN_METADATA
"ENABLE_COLUMN_METADATA",
#endif
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+#if SQLITE_ENABLE_EXPENSIVE_ASSERT
"ENABLE_EXPENSIVE_ASSERT",
#endif
-#ifdef SQLITE_ENABLE_FTS1
+#if SQLITE_ENABLE_FTS1
"ENABLE_FTS1",
#endif
-#ifdef SQLITE_ENABLE_FTS2
+#if SQLITE_ENABLE_FTS2
"ENABLE_FTS2",
#endif
-#ifdef SQLITE_ENABLE_FTS3
+#if SQLITE_ENABLE_FTS3
"ENABLE_FTS3",
#endif
-#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
+#if SQLITE_ENABLE_FTS3_PARENTHESIS
"ENABLE_FTS3_PARENTHESIS",
#endif
-#ifdef SQLITE_ENABLE_FTS4
+#if SQLITE_ENABLE_FTS4
"ENABLE_FTS4",
#endif
-#ifdef SQLITE_ENABLE_ICU
+#if SQLITE_ENABLE_ICU
"ENABLE_ICU",
#endif
-#ifdef SQLITE_ENABLE_IOTRACE
+#if SQLITE_ENABLE_IOTRACE
"ENABLE_IOTRACE",
#endif
-#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+#if SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION",
#endif
-#ifdef SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
#endif
-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+#if SQLITE_ENABLE_MEMORY_MANAGEMENT
"ENABLE_MEMORY_MANAGEMENT",
#endif
-#ifdef SQLITE_ENABLE_MEMSYS3
+#if SQLITE_ENABLE_MEMSYS3
"ENABLE_MEMSYS3",
#endif
-#ifdef SQLITE_ENABLE_MEMSYS5
+#if SQLITE_ENABLE_MEMSYS5
"ENABLE_MEMSYS5",
#endif
-#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
"ENABLE_OVERSIZE_CELL_CHECK",
#endif
-#ifdef SQLITE_ENABLE_RTREE
+#if SQLITE_ENABLE_RTREE
"ENABLE_RTREE",
#endif
#if defined(SQLITE_ENABLE_STAT4)
@@ -13708,31 +14092,31 @@ static const char * const azCompileOpt[] = {
#elif defined(SQLITE_ENABLE_STAT3)
"ENABLE_STAT3",
#endif
-#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+#if SQLITE_ENABLE_UNLOCK_NOTIFY
"ENABLE_UNLOCK_NOTIFY",
#endif
-#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
"ENABLE_UPDATE_DELETE_LIMIT",
#endif
-#ifdef SQLITE_HAS_CODEC
+#if SQLITE_HAS_CODEC
"HAS_CODEC",
#endif
-#ifdef SQLITE_HAVE_ISNAN
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
"HAVE_ISNAN",
#endif
-#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
"HOMEGROWN_RECURSIVE_MUTEX",
#endif
-#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
+#if SQLITE_IGNORE_AFP_LOCK_ERRORS
"IGNORE_AFP_LOCK_ERRORS",
#endif
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
"IGNORE_FLOCK_LOCK_ERRORS",
#endif
#ifdef SQLITE_INT64_TYPE
"INT64_TYPE",
#endif
-#ifdef SQLITE_LOCK_TRACE
+#if SQLITE_LOCK_TRACE
"LOCK_TRACE",
#endif
#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
@@ -13741,226 +14125,226 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_MAX_SCHEMA_RETRY
"MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
#endif
-#ifdef SQLITE_MEMDEBUG
+#if SQLITE_MEMDEBUG
"MEMDEBUG",
#endif
-#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
"MIXED_ENDIAN_64BIT_FLOAT",
#endif
-#ifdef SQLITE_NO_SYNC
+#if SQLITE_NO_SYNC
"NO_SYNC",
#endif
-#ifdef SQLITE_OMIT_ALTERTABLE
+#if SQLITE_OMIT_ALTERTABLE
"OMIT_ALTERTABLE",
#endif
-#ifdef SQLITE_OMIT_ANALYZE
+#if SQLITE_OMIT_ANALYZE
"OMIT_ANALYZE",
#endif
-#ifdef SQLITE_OMIT_ATTACH
+#if SQLITE_OMIT_ATTACH
"OMIT_ATTACH",
#endif
-#ifdef SQLITE_OMIT_AUTHORIZATION
+#if SQLITE_OMIT_AUTHORIZATION
"OMIT_AUTHORIZATION",
#endif
-#ifdef SQLITE_OMIT_AUTOINCREMENT
+#if SQLITE_OMIT_AUTOINCREMENT
"OMIT_AUTOINCREMENT",
#endif
-#ifdef SQLITE_OMIT_AUTOINIT
+#if SQLITE_OMIT_AUTOINIT
"OMIT_AUTOINIT",
#endif
-#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
+#if SQLITE_OMIT_AUTOMATIC_INDEX
"OMIT_AUTOMATIC_INDEX",
#endif
-#ifdef SQLITE_OMIT_AUTORESET
+#if SQLITE_OMIT_AUTORESET
"OMIT_AUTORESET",
#endif
-#ifdef SQLITE_OMIT_AUTOVACUUM
+#if SQLITE_OMIT_AUTOVACUUM
"OMIT_AUTOVACUUM",
#endif
-#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
+#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
"OMIT_BETWEEN_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_BLOB_LITERAL
+#if SQLITE_OMIT_BLOB_LITERAL
"OMIT_BLOB_LITERAL",
#endif
-#ifdef SQLITE_OMIT_BTREECOUNT
+#if SQLITE_OMIT_BTREECOUNT
"OMIT_BTREECOUNT",
#endif
-#ifdef SQLITE_OMIT_BUILTIN_TEST
+#if SQLITE_OMIT_BUILTIN_TEST
"OMIT_BUILTIN_TEST",
#endif
-#ifdef SQLITE_OMIT_CAST
+#if SQLITE_OMIT_CAST
"OMIT_CAST",
#endif
-#ifdef SQLITE_OMIT_CHECK
+#if SQLITE_OMIT_CHECK
"OMIT_CHECK",
#endif
-#ifdef SQLITE_OMIT_COMPLETE
+#if SQLITE_OMIT_COMPLETE
"OMIT_COMPLETE",
#endif
-#ifdef SQLITE_OMIT_COMPOUND_SELECT
+#if SQLITE_OMIT_COMPOUND_SELECT
"OMIT_COMPOUND_SELECT",
#endif
-#ifdef SQLITE_OMIT_CTE
+#if SQLITE_OMIT_CTE
"OMIT_CTE",
#endif
-#ifdef SQLITE_OMIT_DATETIME_FUNCS
+#if SQLITE_OMIT_DATETIME_FUNCS
"OMIT_DATETIME_FUNCS",
#endif
-#ifdef SQLITE_OMIT_DECLTYPE
+#if SQLITE_OMIT_DECLTYPE
"OMIT_DECLTYPE",
#endif
-#ifdef SQLITE_OMIT_DEPRECATED
+#if SQLITE_OMIT_DEPRECATED
"OMIT_DEPRECATED",
#endif
-#ifdef SQLITE_OMIT_DISKIO
+#if SQLITE_OMIT_DISKIO
"OMIT_DISKIO",
#endif
-#ifdef SQLITE_OMIT_EXPLAIN
+#if SQLITE_OMIT_EXPLAIN
"OMIT_EXPLAIN",
#endif
-#ifdef SQLITE_OMIT_FLAG_PRAGMAS
+#if SQLITE_OMIT_FLAG_PRAGMAS
"OMIT_FLAG_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_FLOATING_POINT
+#if SQLITE_OMIT_FLOATING_POINT
"OMIT_FLOATING_POINT",
#endif
-#ifdef SQLITE_OMIT_FOREIGN_KEY
+#if SQLITE_OMIT_FOREIGN_KEY
"OMIT_FOREIGN_KEY",
#endif
-#ifdef SQLITE_OMIT_GET_TABLE
+#if SQLITE_OMIT_GET_TABLE
"OMIT_GET_TABLE",
#endif
-#ifdef SQLITE_OMIT_INCRBLOB
+#if SQLITE_OMIT_INCRBLOB
"OMIT_INCRBLOB",
#endif
-#ifdef SQLITE_OMIT_INTEGRITY_CHECK
+#if SQLITE_OMIT_INTEGRITY_CHECK
"OMIT_INTEGRITY_CHECK",
#endif
-#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
+#if SQLITE_OMIT_LIKE_OPTIMIZATION
"OMIT_LIKE_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_LOAD_EXTENSION
+#if SQLITE_OMIT_LOAD_EXTENSION
"OMIT_LOAD_EXTENSION",
#endif
-#ifdef SQLITE_OMIT_LOCALTIME
+#if SQLITE_OMIT_LOCALTIME
"OMIT_LOCALTIME",
#endif
-#ifdef SQLITE_OMIT_LOOKASIDE
+#if SQLITE_OMIT_LOOKASIDE
"OMIT_LOOKASIDE",
#endif
-#ifdef SQLITE_OMIT_MEMORYDB
+#if SQLITE_OMIT_MEMORYDB
"OMIT_MEMORYDB",
#endif
-#ifdef SQLITE_OMIT_OR_OPTIMIZATION
+#if SQLITE_OMIT_OR_OPTIMIZATION
"OMIT_OR_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_PAGER_PRAGMAS
+#if SQLITE_OMIT_PAGER_PRAGMAS
"OMIT_PAGER_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_PRAGMA
+#if SQLITE_OMIT_PRAGMA
"OMIT_PRAGMA",
#endif
-#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
+#if SQLITE_OMIT_PROGRESS_CALLBACK
"OMIT_PROGRESS_CALLBACK",
#endif
-#ifdef SQLITE_OMIT_QUICKBALANCE
+#if SQLITE_OMIT_QUICKBALANCE
"OMIT_QUICKBALANCE",
#endif
-#ifdef SQLITE_OMIT_REINDEX
+#if SQLITE_OMIT_REINDEX
"OMIT_REINDEX",
#endif
-#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
+#if SQLITE_OMIT_SCHEMA_PRAGMAS
"OMIT_SCHEMA_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
"OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
-#ifdef SQLITE_OMIT_SHARED_CACHE
+#if SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE",
#endif
-#ifdef SQLITE_OMIT_SUBQUERY
+#if SQLITE_OMIT_SUBQUERY
"OMIT_SUBQUERY",
#endif
-#ifdef SQLITE_OMIT_TCL_VARIABLE
+#if SQLITE_OMIT_TCL_VARIABLE
"OMIT_TCL_VARIABLE",
#endif
-#ifdef SQLITE_OMIT_TEMPDB
+#if SQLITE_OMIT_TEMPDB
"OMIT_TEMPDB",
#endif
-#ifdef SQLITE_OMIT_TRACE
+#if SQLITE_OMIT_TRACE
"OMIT_TRACE",
#endif
-#ifdef SQLITE_OMIT_TRIGGER
+#if SQLITE_OMIT_TRIGGER
"OMIT_TRIGGER",
#endif
-#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
"OMIT_TRUNCATE_OPTIMIZATION",
#endif
-#ifdef SQLITE_OMIT_UTF16
+#if SQLITE_OMIT_UTF16
"OMIT_UTF16",
#endif
-#ifdef SQLITE_OMIT_VACUUM
+#if SQLITE_OMIT_VACUUM
"OMIT_VACUUM",
#endif
-#ifdef SQLITE_OMIT_VIEW
+#if SQLITE_OMIT_VIEW
"OMIT_VIEW",
#endif
-#ifdef SQLITE_OMIT_VIRTUALTABLE
+#if SQLITE_OMIT_VIRTUALTABLE
"OMIT_VIRTUALTABLE",
#endif
-#ifdef SQLITE_OMIT_WAL
+#if SQLITE_OMIT_WAL
"OMIT_WAL",
#endif
-#ifdef SQLITE_OMIT_WSD
+#if SQLITE_OMIT_WSD
"OMIT_WSD",
#endif
-#ifdef SQLITE_OMIT_XFER_OPT
+#if SQLITE_OMIT_XFER_OPT
"OMIT_XFER_OPT",
#endif
-#ifdef SQLITE_PERFORMANCE_TRACE
+#if SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE",
#endif
-#ifdef SQLITE_PROXY_DEBUG
+#if SQLITE_PROXY_DEBUG
"PROXY_DEBUG",
#endif
-#ifdef SQLITE_RTREE_INT_ONLY
+#if SQLITE_RTREE_INT_ONLY
"RTREE_INT_ONLY",
#endif
-#ifdef SQLITE_SECURE_DELETE
+#if SQLITE_SECURE_DELETE
"SECURE_DELETE",
#endif
-#ifdef SQLITE_SMALL_STACK
+#if SQLITE_SMALL_STACK
"SMALL_STACK",
#endif
-#ifdef SQLITE_SOUNDEX
+#if SQLITE_SOUNDEX
"SOUNDEX",
#endif
-#ifdef SQLITE_SYSTEM_MALLOC
+#if SQLITE_SYSTEM_MALLOC
"SYSTEM_MALLOC",
#endif
-#ifdef SQLITE_TCL
+#if SQLITE_TCL
"TCL",
#endif
#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
#endif
-#ifdef SQLITE_TEST
+#if SQLITE_TEST
"TEST",
#endif
#if defined(SQLITE_THREADSAFE)
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
#endif
-#ifdef SQLITE_USE_ALLOCA
+#if SQLITE_USE_ALLOCA
"USE_ALLOCA",
#endif
-#ifdef SQLITE_USER_AUTHENTICATION
+#if SQLITE_USER_AUTHENTICATION
"USER_AUTHENTICATION",
#endif
-#ifdef SQLITE_WIN32_MALLOC
+#if SQLITE_WIN32_MALLOC
"WIN32_MALLOC",
#endif
-#ifdef SQLITE_ZERO_MALLOC
+#if SQLITE_ZERO_MALLOC
"ZERO_MALLOC"
#endif
};
@@ -13972,8 +14356,15 @@ static const char * const azCompileOpt[] = {
** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
** is not required for a match.
*/
-SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
+SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
int i, n;
+
+#if SQLITE_ENABLE_API_ARMOR
+ if( zOptName==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
n = sqlite3Strlen30(zOptName);
@@ -13993,7 +14384,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
** Return the N-th compile-time option string. If N is out of range,
** return a NULL pointer.
*/
-SQLITE_API const char *sqlite3_compileoption_get(int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
if( N>=0 && N<ArraySize(azCompileOpt) ){
return azCompileOpt[N];
}
@@ -14155,6 +14546,7 @@ struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
+ i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
@@ -14167,7 +14559,8 @@ struct VdbeFrame {
int nOnceFlag; /* Number of entries in aOnceFlag */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
- int nChange; /* Statement changes (Vdbe.nChanges) */
+ int nChange; /* Statement changes (Vdbe.nChange) */
+ int nDbChange; /* Value of db->nChange */
};
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
@@ -14318,20 +14711,22 @@ struct Explain {
*/
typedef unsigned bft; /* Bit Field Type */
+typedef struct ScanStatus ScanStatus;
+struct ScanStatus {
+ int addrExplain; /* OP_Explain for loop */
+ int addrLoop; /* Address of "loops" counter */
+ int addrVisit; /* Address of "rows visited" counter */
+ int iSelectID; /* The "Select-ID" for this loop */
+ LogEst nEst; /* Estimated output rows per loop */
+ char *zName; /* Name of table or index */
+};
+
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
** is really a pointer to an instance of this structure.
-**
-** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
-** any virtual table method invocations made by the vdbe program. It is
-** set to 2 for xDestroy method calls and 1 for all other methods. This
-** variable is used for two purposes: to allow xDestroy methods to execute
-** "DROP TABLE" statements and to prevent some nasty side effects of
-** malloc failure when SQLite is invoked recursively by a virtual table
-** method function.
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
@@ -14355,11 +14750,13 @@ struct Vdbe {
u32 cacheCtr; /* VdbeCursor row cache generation counter */
int pc; /* The program counter */
int rc; /* Value to return */
+#ifdef SQLITE_DEBUG
+ int rcApp; /* errcode set by sqlite3_result_error_code() */
+#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
bft explain:2; /* True if EXPLAIN present on SQL command */
- bft inVtabMethod:2; /* See comments above */
bft changeCntOn:1; /* True to update the change-counter */
bft expired:1; /* True if the VM needs to be recompiled */
bft runOnlyOnce:1; /* Automatically expire on reset */
@@ -14390,6 +14787,11 @@ struct Vdbe {
int nOnceFlag; /* Size of array aOnceFlag[] */
u8 *aOnceFlag; /* Flags for OP_Once */
AuxData *pAuxData; /* Linked list of auxdata allocations */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ i64 *anExec; /* Number of times each op has been executed */
+ int nScan; /* Entries in aScan[] */
+ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */
+#endif
};
/*
@@ -14514,10 +14916,32 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
*/
typedef struct sqlite3StatType sqlite3StatType;
static SQLITE_WSD struct sqlite3StatType {
- int nowValue[10]; /* Current value */
- int mxValue[10]; /* Maximum value */
+#if SQLITE_PTRSIZE>4
+ sqlite3_int64 nowValue[10]; /* Current value */
+ sqlite3_int64 mxValue[10]; /* Maximum value */
+#else
+ u32 nowValue[10]; /* Current value */
+ u32 mxValue[10]; /* Maximum value */
+#endif
} sqlite3Stat = { {0,}, {0,} };
+/*
+** Elements of sqlite3Stat[] are protected by either the memory allocator
+** mutex, or by the pcache1 mutex. The following array determines which.
+*/
+static const char statMutex[] = {
+ 0, /* SQLITE_STATUS_MEMORY_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */
+ 0, /* SQLITE_STATUS_SCRATCH_USED */
+ 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */
+ 0, /* SQLITE_STATUS_MALLOC_SIZE */
+ 0, /* SQLITE_STATUS_PARSER_STACK */
+ 1, /* SQLITE_STATUS_PAGECACHE_SIZE */
+ 0, /* SQLITE_STATUS_SCRATCH_SIZE */
+ 0, /* SQLITE_STATUS_MALLOC_COUNT */
+};
+
/* The "wsdStat" macro will resolve to the status information
** state vector. If writable static data is unsupported on the target,
@@ -14534,33 +14958,60 @@ static SQLITE_WSD struct sqlite3StatType {
#endif
/*
-** Return the current value of a status parameter.
+** Return the current value of a status parameter. The caller must
+** be holding the appropriate mutex.
*/
-SQLITE_PRIVATE int sqlite3StatusValue(int op){
+SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
return wsdStat.nowValue[op];
}
/*
-** Add N to the value of a status record. It is assumed that the
-** caller holds appropriate locks.
+** Add N to the value of a status record. The caller must hold the
+** appropriate mutex. (Locking is checked by assert()).
+**
+** The StatusUp() routine can accept positive or negative values for N.
+** The value of N is added to the current status value and the high-water
+** mark is adjusted if necessary.
+**
+** The StatusDown() routine lowers the current value by N. The highwater
+** mark is unchanged. N must be non-negative for StatusDown().
*/
-SQLITE_PRIVATE void sqlite3StatusAdd(int op, int N){
+SQLITE_PRIVATE void sqlite3StatusUp(int op, int N){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] += N;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
+SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
+ wsdStatInit;
+ assert( N>=0 );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
+ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ wsdStat.nowValue[op] -= N;
+}
/*
-** Set the value of a status to X.
+** Set the value of a status to X. The highwater mark is adjusted if
+** necessary. The caller must hold the appropriate mutex.
*/
SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] = X;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
@@ -14569,28 +15020,50 @@ SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
/*
** Query status information.
-**
-** This implementation assumes that reading or writing an aligned
-** 32-bit integer is an atomic operation. If that assumption is not true,
-** then this routine is not threadsafe.
*/
-SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+){
+ sqlite3_mutex *pMutex;
wsdStatInit;
if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
return SQLITE_MISUSE_BKPT;
}
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex();
+ sqlite3_mutex_enter(pMutex);
*pCurrent = wsdStat.nowValue[op];
*pHighwater = wsdStat.mxValue[op];
if( resetFlag ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
+ sqlite3_mutex_leave(pMutex);
+ (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */
return SQLITE_OK;
}
+SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+ sqlite3_int64 iCur, iHwtr;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
+ if( rc==0 ){
+ *pCurrent = (int)iCur;
+ *pHighwater = (int)iHwtr;
+ }
+ return rc;
+}
/*
** Query status information for a single database connection
*/
-SQLITE_API int sqlite3_db_status(
+SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
sqlite3 *db, /* The database connection whose status is desired */
int op, /* Status verb */
int *pCurrent, /* Write current value here */
@@ -14598,6 +15071,11 @@ SQLITE_API int sqlite3_db_status(
int resetFlag /* Reset high-water mark if true */
){
int rc = SQLITE_OK; /* Return code */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
@@ -14776,7 +15254,7 @@ SQLITE_API int sqlite3_db_status(
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** SQLite processes all times and dates as Julian Day numbers. The
+** SQLite processes all times and dates as julian day numbers. The
** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
** calendar system.
@@ -14791,7 +15269,7 @@ SQLITE_API int sqlite3_db_status(
**
** The Gregorian calendar system is used for all dates and times,
** even those that predate the Gregorian calendar. Historians usually
-** use the Julian calendar for dates prior to 1582-10-15 and for some
+** use the julian calendar for dates prior to 1582-10-15 and for some
** dates afterwards, depending on locale. Beware of this difference.
**
** The conversion algorithms are implemented based on descriptions
@@ -15063,7 +15541,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
}
/*
-** Attempt to parse the given string into a Julian Day Number. Return
+** Attempt to parse the given string into a julian day number. Return
** the number of errors.
**
** The following are acceptable forms for the input string:
@@ -15171,8 +15649,9 @@ static void clearYMD_HMS_TZ(DateTime *p){
** already, check for an MSVC build environment that provides
** localtime_s().
*/
-#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
- defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
+ && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
+#undef HAVE_LOCALTIME_S
#define HAVE_LOCALTIME_S 1
#endif
@@ -15192,8 +15671,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
*/
static int osLocaltime(time_t *t, struct tm *pTm){
int rc;
-#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
- && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
struct tm *pX;
#if SQLITE_THREADSAFE>0
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
@@ -15210,7 +15688,7 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#ifndef SQLITE_OMIT_BUILTIN_TEST
if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
#endif
-#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R
+#if HAVE_LOCALTIME_R
rc = localtime_r(t, pTm)==0;
#else
rc = localtime_s(pTm, t);
@@ -15634,7 +16112,7 @@ static void dateFunc(
** %f ** fractional seconds SS.SSS
** %H hour 00-24
** %j day of year 000-366
-** %J ** Julian day number
+** %J ** julian day number
** %m month 01-12
** %M minute 00-59
** %s seconds since 1970-01-01
@@ -15654,8 +16132,10 @@ static void strftimeFunc(
size_t i,j;
char *z;
sqlite3 *db;
- const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
+ const char *zFmt;
char zBuf[100];
+ if( argc==0 ) return;
+ zFmt = (const char*)sqlite3_value_text(argv[0]);
if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
db = sqlite3_context_db_handle(context);
for(i=0, n=1; zFmt[i]; i++, n++){
@@ -15849,7 +16329,7 @@ static void currentTimeFunc(
iT = sqlite3StmtCurrentTime(context);
if( iT<=0 ) return;
t = iT/1000 - 10000*(sqlite3_int64)21086676;
-#ifdef HAVE_GMTIME_R
+#if HAVE_GMTIME_R
pTm = gmtime_r(&t, &sNow);
#else
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
@@ -16207,7 +16687,7 @@ static sqlite3_vfs * SQLITE_WSD vfsList = 0;
** Locate a VFS by name. If no name is given, simply return the
** first VFS on the list.
*/
-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
+SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfs){
sqlite3_vfs *pVfs = 0;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex;
@@ -16253,12 +16733,16 @@ static void vfsUnlink(sqlite3_vfs *pVfs){
** VFS multiple times. The new VFS becomes the default if makeDflt is
** true.
*/
-SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
MUTEX_LOGIC(sqlite3_mutex *mutex;)
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+
MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
@@ -16277,7 +16761,7 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
/*
** Unregister a VFS so that it is no longer accessible.
*/
-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -16519,9 +17003,9 @@ static malloc_zone_t* _sqliteZone_;
** The malloc.h header file is needed for malloc_usable_size() function
** on some systems (e.g. Linux).
*/
-#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE)
-# define SQLITE_USE_MALLOC_H
-# define SQLITE_USE_MALLOC_USABLE_SIZE
+#if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE
+# define SQLITE_USE_MALLOC_H 1
+# define SQLITE_USE_MALLOC_USABLE_SIZE 1
/*
** The MSVCRT has malloc_usable_size(), but it is called _msize(). The
** use of _msize() is automatic, but can be disabled by compiling with
@@ -18613,9 +19097,10 @@ SQLITE_PRIVATE int sqlite3MutexEnd(void){
/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
+ if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
#endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
@@ -18631,7 +19116,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
/*
** Free a dynamic mutex.
*/
-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexFree(p);
}
@@ -18641,7 +19126,7 @@ SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
** Obtain the mutex p. If some other thread already has the mutex, block
** until it can be obtained.
*/
-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexEnter(p);
}
@@ -18651,7 +19136,7 @@ SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
*/
-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
int rc = SQLITE_OK;
if( p ){
return sqlite3GlobalConfig.mutex.xMutexTry(p);
@@ -18665,7 +19150,7 @@ SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
** is not currently entered. If a NULL pointer is passed as an argument
** this function is a no-op.
*/
-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexLeave(p);
}
@@ -18676,10 +19161,10 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
#endif
@@ -18809,8 +19294,12 @@ static sqlite3_mutex *debugMutexAlloc(int id){
break;
}
default: {
- assert( id-2 >= 0 );
- assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( id-2<0 || id-2>=ArraySize(aStatic) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
pNew = &aStatic[id-2];
pNew->id = id;
break;
@@ -18825,8 +19314,13 @@ static sqlite3_mutex *debugMutexAlloc(int id){
static void debugMutexFree(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->cnt==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
- sqlite3_free(p);
+ if( p->id==SQLITE_MUTEX_RECURSIVE || p->id==SQLITE_MUTEX_FAST ){
+ sqlite3_free(p);
+ }else{
+#ifdef SQLITE_ENABLE_API_ARMOR
+ (void)SQLITE_MISUSE_BKPT;
+#endif
+ }
}
/*
@@ -18937,8 +19431,10 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
*/
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
-#if SQLITE_MUTEX_NREF
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
int id; /* Mutex type */
+#endif
+#if SQLITE_MUTEX_NREF
volatile int nRef; /* Number of entrances */
volatile pthread_t owner; /* Thread that is within this mutex */
int trace; /* True to trace changes */
@@ -19055,32 +19551,30 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
-#if SQLITE_MUTEX_NREF
- p->id = iType;
-#endif
}
break;
}
case SQLITE_MUTEX_FAST: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
-#if SQLITE_MUTEX_NREF
- p->id = iType;
-#endif
pthread_mutex_init(&p->mutex, 0);
}
break;
}
default: {
- assert( iType-2 >= 0 );
- assert( iType-2 < ArraySize(staticMutexes) );
- p = &staticMutexes[iType-2];
-#if SQLITE_MUTEX_NREF
- p->id = iType;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
#endif
+ p = &staticMutexes[iType-2];
break;
}
}
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
+ if( p ) p->id = iType;
+#endif
return p;
}
@@ -19092,9 +19586,18 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
*/
static void pthreadMutexFree(sqlite3_mutex *p){
assert( p->nRef==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
- pthread_mutex_destroy(&p->mutex);
- sqlite3_free(p);
+#if SQLITE_ENABLE_API_ARMOR
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
+#endif
+ {
+ pthread_mutex_destroy(&p->mutex);
+ sqlite3_free(p);
+ }
+#ifdef SQLITE_ENABLE_API_ARMOR
+ else{
+ (void)SQLITE_MISUSE_BKPT;
+ }
+#endif
}
/*
@@ -19564,6 +20067,17 @@ SQLITE_API int sqlite3_open_file_count = 0;
# define SQLITE_WIN32_VOLATILE volatile
#endif
+/*
+** For some Windows sub-platforms, the _beginthreadex() / _endthreadex()
+** functions are not available (e.g. those not using MSVC, Cygwin, etc).
+*/
+#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
+ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__)
+# define SQLITE_OS_WIN_THREADS 1
+#else
+# define SQLITE_OS_WIN_THREADS 0
+#endif
+
#endif /* _OS_WIN_H_ */
/************** End of os_win.h **********************************************/
@@ -19646,8 +20160,8 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */
*/
static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;
-SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */
-SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void); /* os_win.c */
+SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
static int winMutexInit(void){
/* The first to increment to 1 does actual initialization */
@@ -19739,8 +20253,8 @@ static sqlite3_mutex *winMutexAlloc(int iType){
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
-#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC
p->trace = 1;
#endif
@@ -19754,12 +20268,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){
break;
}
default: {
- assert( iType-2 >= 0 );
- assert( iType-2 < ArraySize(winMutex_staticMutexes) );
- assert( winMutex_isInit==1 );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
p = &winMutex_staticMutexes[iType-2];
-#ifdef SQLITE_DEBUG
p->id = iType;
+#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
p->trace = 1;
#endif
@@ -19778,13 +20295,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){
*/
static void winMutexFree(sqlite3_mutex *p){
assert( p );
-#ifdef SQLITE_DEBUG
assert( p->nRef==0 && p->owner==0 );
- assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){
+ DeleteCriticalSection(&p->mutex);
+ sqlite3_free(p);
+ }else{
+#ifdef SQLITE_ENABLE_API_ARMOR
+ (void)SQLITE_MISUSE_BKPT;
#endif
- assert( winMutex_isInit==1 );
- DeleteCriticalSection(&p->mutex);
- sqlite3_free(p);
+ }
}
/*
@@ -19938,7 +20457,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
** held by SQLite. An example of non-essential memory is memory used to
** cache database pages that are not currently in use.
*/
-SQLITE_API int sqlite3_release_memory(int n){
+SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
return sqlite3PcacheReleaseMemory(n);
#else
@@ -19994,6 +20513,13 @@ static SQLITE_WSD struct Mem0Global {
#define mem0 GLOBAL(struct Mem0Global, mem0)
/*
+** Return the memory allocator mutex. sqlite3_status() needs it.
+*/
+SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){
+ return mem0.mutex;
+}
+
+/*
** This routine runs when the memory allocator sees that the
** total memory allocation is about to exceed the soft heap
** limit.
@@ -20015,7 +20541,7 @@ static int sqlite3MemoryAlarm(
void *pArg,
sqlite3_int64 iThreshold
){
- int nUsed;
+ sqlite3_int64 nUsed;
sqlite3_mutex_enter(mem0.mutex);
mem0.alarmCallback = xCallback;
mem0.alarmArg = pArg;
@@ -20031,7 +20557,7 @@ static int sqlite3MemoryAlarm(
** Deprecated external interface. Internal/core SQLite code
** should call sqlite3MemoryAlarm.
*/
-SQLITE_API int sqlite3_memory_alarm(
+SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
void *pArg,
sqlite3_int64 iThreshold
@@ -20044,7 +20570,7 @@ SQLITE_API int sqlite3_memory_alarm(
** Set the soft heap-size limit for the library. Passing a zero or
** negative value indicates no limit.
*/
-SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
sqlite3_int64 excess;
#ifndef SQLITE_OMIT_AUTOINIT
@@ -20064,7 +20590,7 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
return priorLimit;
}
-SQLITE_API void sqlite3_soft_heap_limit(int n){
+SQLITE_API void SQLITE_STDCALL sqlite3_soft_heap_limit(int n){
if( n<0 ) n = 0;
sqlite3_soft_heap_limit64(n);
}
@@ -20073,6 +20599,7 @@ SQLITE_API void sqlite3_soft_heap_limit(int n){
** Initialize the memory allocation subsystem.
*/
SQLITE_PRIVATE int sqlite3MallocInit(void){
+ int rc;
if( sqlite3GlobalConfig.m.xMalloc==0 ){
sqlite3MemSetDefault();
}
@@ -20108,7 +20635,9 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
sqlite3GlobalConfig.szPage = 0;
sqlite3GlobalConfig.nPage = 0;
}
- return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
+ if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
+ return rc;
}
/*
@@ -20133,7 +20662,7 @@ SQLITE_PRIVATE void sqlite3MallocEnd(void){
/*
** Return the amount of memory currently checked out.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
int n, mx;
sqlite3_int64 res;
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, 0);
@@ -20146,7 +20675,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
** checked out since either the beginning of this process
** or since the most recent reset.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){
int n, mx;
sqlite3_int64 res;
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, resetFlag);
@@ -20184,7 +20713,7 @@ static int mallocWithAlarm(int n, void **pp){
nFull = sqlite3GlobalConfig.m.xRoundup(n);
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmCallback!=0 ){
- int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
@@ -20201,8 +20730,8 @@ static int mallocWithAlarm(int n, void **pp){
#endif
if( p ){
nFull = sqlite3MallocSize(p);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull);
+ sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
}
*pp = p;
return nFull;
@@ -20237,13 +20766,13 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
** First make sure the memory subsystem is initialized, then do the
** allocation.
*/
-SQLITE_API void *sqlite3_malloc(int n){
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
return n<=0 ? 0 : sqlite3Malloc(n);
}
-SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -20279,14 +20808,14 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
p = mem0.pScratchFree;
mem0.pScratchFree = mem0.pScratchFree->pNext;
mem0.nScratchFree--;
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3_mutex_leave(mem0.mutex);
p = sqlite3Malloc(n);
if( sqlite3GlobalConfig.bMemstat && p ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
sqlite3_mutex_leave(mem0.mutex);
}
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
@@ -20295,11 +20824,12 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than two scratch allocations per thread
- ** are outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut<=1 );
+ /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
+ ** buffers per thread.
+ **
+ ** This can only be checked in single-threaded mode.
+ */
+ assert( scratchAllocOut==0 );
if( p ) scratchAllocOut++;
#endif
@@ -20326,19 +20856,19 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
mem0.pScratchFree = pSlot;
mem0.nScratchFree++;
assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
/* Release memory back to the heap */
assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_SCRATCH) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
@@ -20369,7 +20899,7 @@ SQLITE_PRIVATE int sqlite3MallocSize(void *p){
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
if( db==0 ){
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3MallocSize(p);
}else{
@@ -20378,13 +20908,13 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
return db->lookaside.sz;
}else{
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
return sqlite3GlobalConfig.m.xSize(p);
}
}
}
-SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
+SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
}
@@ -20392,14 +20922,14 @@ SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
/*
** Free memory previously obtained from sqlite3Malloc().
*/
-SQLITE_API void sqlite3_free(void *p){
+SQLITE_API void SQLITE_STDCALL sqlite3_free(void *p){
if( p==0 ) return; /* IMP: R-49053-54554 */
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p));
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
@@ -20440,7 +20970,7 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
}
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
@@ -20453,7 +20983,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
int nOld, nNew, nDiff;
void *pNew;
assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
- assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) );
if( pOld==0 ){
return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */
}
@@ -20487,7 +21017,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
}
if( pNew ){
nNew = sqlite3MallocSize(pNew);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
}
sqlite3_mutex_leave(mem0.mutex);
}else{
@@ -20501,14 +21031,14 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
** The public interface to sqlite3Realloc. Make sure that the memory
** subsystem is initialized prior to invoking sqliteRealloc.
*/
-SQLITE_API void *sqlite3_realloc(void *pOld, int n){
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void *pOld, int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
if( n<0 ) n = 0; /* IMP: R-26507-47431 */
return sqlite3Realloc(pOld, n);
}
-SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -20620,7 +21150,7 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
}
}else{
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc64(p, n);
if( !pNew ){
@@ -20750,17 +21280,6 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
*/
/*
-** If the strchrnul() library function is available, then set
-** HAVE_STRCHRNUL. If that routine is not available, this module
-** will supply its own. The built-in version is slower than
-** the glibc version so the glibc version is definitely preferred.
-*/
-#if !defined(HAVE_STRCHRNUL)
-# define HAVE_STRCHRNUL 0
-#endif
-
-
-/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
@@ -21007,15 +21526,19 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}
if( width<0 ){
flag_leftjustify = 1;
- width = -width;
+ width = width >= -2147483647 ? -width : 0;
}
c = *++fmt;
}else{
+ unsigned wx = 0;
while( c>='0' && c<='9' ){
- width = width*10 + c - '0';
+ wx = wx*10 + c - '0';
c = *++fmt;
}
+ testcase( wx>0x7fffffff );
+ width = wx & 0x7fffffff;
}
+
/* Get the precision */
if( c=='.' ){
precision = 0;
@@ -21026,13 +21549,18 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
precision = va_arg(ap,int);
}
- if( precision<0 ) precision = -precision;
c = *++fmt;
+ if( precision<0 ){
+ precision = precision >= -2147483647 ? -precision : -1;
+ }
}else{
+ unsigned px = 0;
while( c>='0' && c<='9' ){
- precision = precision*10 + c - '0';
+ px = px*10 + c - '0';
c = *++fmt;
}
+ testcase( px>0x7fffffff );
+ precision = px & 0x7fffffff;
}
}else{
precision = -1;
@@ -21196,7 +21724,8 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
else prefix = 0;
}
if( xtype==etGENERIC && precision>0 ) precision--;
- for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
+ testcase( precision>0xfff );
+ for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){}
if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
@@ -21251,8 +21780,9 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
e2 = exp;
}
- if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){
- bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 );
+ if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){
+ bufpt = zExtra
+ = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 );
if( bufpt==0 ){
setStrAccumError(pAccum, STRACCUM_NOMEM);
return;
@@ -21484,7 +22014,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
*/
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
- assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
+ assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
@@ -21498,6 +22028,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
szNew += N + 1;
+ if( szNew+p->nChar<=p->mxAlloc ){
+ /* Force exponential buffer size growth as long as it does not overflow,
+ ** to avoid having to call this routine too often */
+ szNew += p->nChar;
+ }
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_TOOBIG);
@@ -21514,6 +22049,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
assert( p->zText!=0 || p->nChar==0 );
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
+ p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
@@ -21527,7 +22063,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
** Append N copies of character c to the given string buffer.
*/
SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){
- if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
+ testcase( p->nChar + (i64)N > 0x7fffffff );
+ if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
+ return;
+ }
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
@@ -21679,10 +22218,17 @@ SQLITE_PRIVATE char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zForma
** Print into memory obtained from sqlite3_malloc(). Omit the internal
** %-conversion extensions.
*/
-SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
+SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap){
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zFormat==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -21697,7 +22243,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
** Print into memory obtained from sqlite3_malloc()(). Omit the internal
** %-conversion extensions.
*/
-SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
+SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
#ifndef SQLITE_OMIT_AUTOINIT
@@ -21722,15 +22268,22 @@ SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
**
** sqlite3_vsnprintf() is the varargs version.
*/
-SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
+SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
StrAccum acc;
if( n<=0 ) return zBuf;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zBuf==0 || zFormat==0 ) {
+ (void)SQLITE_MISUSE_BKPT;
+ if( zBuf ) zBuf[0] = 0;
+ return zBuf;
+ }
+#endif
sqlite3StrAccumInit(&acc, zBuf, n, 0);
acc.useMalloc = 0;
sqlite3VXPrintf(&acc, 0, zFormat, ap);
return sqlite3StrAccumFinish(&acc);
}
-SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
+SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
va_start(ap,zFormat);
@@ -21762,7 +22315,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
/*
** Format and write a message to the log if logging is enabled.
*/
-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
+SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...){
va_list ap; /* Vararg list */
if( sqlite3GlobalConfig.xLog ){
va_start(ap, zFormat);
@@ -21898,7 +22451,7 @@ static SQLITE_WSD struct sqlite3PrngType {
/*
** Return N random bytes.
*/
-SQLITE_API void sqlite3_randomness(int N, void *pBuf){
+SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
unsigned char t;
unsigned char *zBuf = pBuf;
@@ -21916,11 +22469,19 @@ SQLITE_API void sqlite3_randomness(int N, void *pBuf){
#endif
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
- sqlite3_mutex_enter(mutex);
+ sqlite3_mutex *mutex;
+#endif
+
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return;
+#endif
+
+#if SQLITE_THREADSAFE
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
#endif
- if( N<=0 ){
+ sqlite3_mutex_enter(mutex);
+ if( N<=0 || pBuf==0 ){
wsdPrng.isInit = 0;
sqlite3_mutex_leave(mutex);
return;
@@ -22022,6 +22583,8 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
** of multiple cores can do so, while also allowing applications to stay
** single-threaded if desired.
*/
+#if SQLITE_OS_WIN
+#endif
#if SQLITE_MAX_WORKER_THREADS>0
@@ -22094,7 +22657,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
/********************************* Win32 Threads ****************************/
-#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
+#if SQLITE_OS_WIN_THREADS
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <process.h>
@@ -22187,7 +22750,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
}
-#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */
+#endif /* SQLITE_OS_WIN_THREADS */
/******************************** End Win32 Threads *************************/
@@ -22808,7 +23371,7 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
**
*/
/* #include <stdarg.h> */
-#ifdef SQLITE_HAVE_ISNAN
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
# include <math.h>
#endif
@@ -22849,7 +23412,7 @@ SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
*/
SQLITE_PRIVATE int sqlite3IsNaN(double x){
int rc; /* The value return */
-#if !defined(SQLITE_HAVE_ISNAN)
+#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN
/*
** Systems that support the isnan() library function should probably
** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
@@ -22879,9 +23442,9 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x){
volatile double y = x;
volatile double z = y;
rc = (y!=z);
-#else /* if defined(SQLITE_HAVE_ISNAN) */
+#else /* if HAVE_ISNAN */
rc = isnan(x);
-#endif /* SQLITE_HAVE_ISNAN */
+#endif /* HAVE_ISNAN */
testcase( rc );
return rc;
}
@@ -23040,15 +23603,25 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
** case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
+SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *zLeft, const char *zRight){
register unsigned char *a, *b;
+ if( zLeft==0 ){
+ return zRight ? -1 : 0;
+ }else if( zRight==0 ){
+ return 1;
+ }
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
return UpperToLower[*a] - UpperToLower[*b];
}
-SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
+SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
register unsigned char *a, *b;
+ if( zLeft==0 ){
+ return zRight ? -1 : 0;
+ }else if( zRight==0 ){
+ return 1;
+ }
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
@@ -24573,23 +25146,25 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 136 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
/* 137 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
/* 138 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"),
- /* 139 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
- /* 140 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 141 */ "IncrVacuum" OpHelp(""),
- /* 142 */ "Expire" OpHelp(""),
- /* 143 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
- /* 144 */ "VBegin" OpHelp(""),
- /* 145 */ "VCreate" OpHelp(""),
- /* 146 */ "VDestroy" OpHelp(""),
- /* 147 */ "VOpen" OpHelp(""),
- /* 148 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 149 */ "VNext" OpHelp(""),
- /* 150 */ "VRename" OpHelp(""),
- /* 151 */ "Pagecount" OpHelp(""),
- /* 152 */ "MaxPgcnt" OpHelp(""),
- /* 153 */ "Init" OpHelp("Start at P2"),
- /* 154 */ "Noop" OpHelp(""),
- /* 155 */ "Explain" OpHelp(""),
+ /* 139 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]+=P3, goto P2"),
+ /* 140 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 141 */ "JumpZeroIncr" OpHelp("if (r[P1]++)==0 ) goto P2"),
+ /* 142 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 143 */ "IncrVacuum" OpHelp(""),
+ /* 144 */ "Expire" OpHelp(""),
+ /* 145 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
+ /* 146 */ "VBegin" OpHelp(""),
+ /* 147 */ "VCreate" OpHelp(""),
+ /* 148 */ "VDestroy" OpHelp(""),
+ /* 149 */ "VOpen" OpHelp(""),
+ /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 151 */ "VNext" OpHelp(""),
+ /* 152 */ "VRename" OpHelp(""),
+ /* 153 */ "Pagecount" OpHelp(""),
+ /* 154 */ "MaxPgcnt" OpHelp(""),
+ /* 155 */ "Init" OpHelp("Start at P2"),
+ /* 156 */ "Noop" OpHelp(""),
+ /* 157 */ "Explain" OpHelp(""),
};
return azName[i];
}
@@ -24670,18 +25245,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#endif
/*
-** Define the OS_VXWORKS pre-processor macro to 1 if building on
-** vxworks, or 0 otherwise.
-*/
-#ifndef OS_VXWORKS
-# if defined(__RTP__) || defined(_WRS_KERNEL)
-# define OS_VXWORKS 1
-# else
-# define OS_VXWORKS 0
-# endif
-#endif
-
-/*
** standard include files.
*/
#include <sys/types.h>
@@ -24695,18 +25258,19 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
# include <sys/mman.h>
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS
+#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
-# if OS_VXWORKS
-# include <semaphore.h>
-# include <limits.h>
-# else
-# include <sys/file.h>
-# include <sys/param.h>
-# endif
+# include <sys/file.h>
+# include <sys/param.h>
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+#if OS_VXWORKS
+/* # include <sys/ioctl.h> */
+# include <semaphore.h>
+# include <limits.h>
+#endif /* OS_VXWORKS */
+
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
# include <sys/mount.h>
#endif
@@ -24747,6 +25311,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
*/
#define MAX_PATHNAME 512
+/* Always cast the getpid() return type for compatibility with
+** kernel modules in VxWorks. */
+#define osGetpid(X) (pid_t)getpid()
+
/*
** Only set the lastErrno if the error code is a real error and not
** a normal expected return code of SQLITE_BUSY or SQLITE_OK
@@ -24835,7 +25403,7 @@ struct unixFile {
** method was called. If xOpen() is called from a different process id,
** indicating that a fork() has occurred, the PRNG will be reset.
*/
-static int randomnessPid = 0;
+static pid_t randomnessPid = 0;
/*
** Allowed values for the unixFile.ctrlFlags bitmask:
@@ -24852,7 +25420,8 @@ static int randomnessPid = 0;
#define UNIXFILE_DELETE 0x20 /* Delete on close */
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
-#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */
+#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings issued */
+#define UNIXFILE_BLOCK 0x0200 /* Next SHM lock might block */
/*
** Include code that is common to all os_*.c files
@@ -25191,7 +25760,7 @@ static struct unix_syscall {
{ "read", (sqlite3_syscall_ptr)read, 0 },
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
-#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
{ "pread", (sqlite3_syscall_ptr)pread, 0 },
#else
{ "pread", (sqlite3_syscall_ptr)0, 0 },
@@ -25208,7 +25777,7 @@ static struct unix_syscall {
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
-#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
{ "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
#else
{ "pwrite", (sqlite3_syscall_ptr)0, 0 },
@@ -25523,9 +26092,9 @@ static int lockTrace(int fd, int op, struct flock *p){
/*
** Retry ftruncate() calls that fail due to EINTR
**
-** All calls to ftruncate() within this file should be made through this wrapper.
-** On the Android platform, bypassing the logic below could lead to a corrupt
-** database.
+** All calls to ftruncate() within this file should be made through
+** this wrapper. On the Android platform, bypassing the logic below
+** could lead to a corrupt database.
*/
static int robust_ftruncate(int h, sqlite3_int64 sz){
int rc;
@@ -25985,6 +26554,14 @@ static void robust_close(unixFile *pFile, int h, int lineno){
}
/*
+** Set the pFile->lastErrno. Do this in a subroutine as that provides
+** a convenient place to set a breakpoint.
+*/
+static void storeLastErrno(unixFile *pFile, int error){
+ pFile->lastErrno = error;
+}
+
+/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
*/
static void closePendingFds(unixFile *pFile){
@@ -26057,7 +26634,7 @@ static int findInodeInfo(
fd = pFile->h;
rc = osFstat(fd, &statbuf);
if( rc!=0 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
#ifdef EOVERFLOW
if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
#endif
@@ -26078,12 +26655,12 @@ static int findInodeInfo(
if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR );
if( rc!=1 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR;
}
rc = osFstat(fd, &statbuf);
if( rc!=0 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR;
}
}
@@ -26206,7 +26783,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
lock.l_type = F_WRLCK;
if( osFcntl(pFile->h, F_GETLK, &lock) ){
rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
} else if( lock.l_type!=F_UNLCK ){
reserved = 1;
}
@@ -26339,7 +26916,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){
assert( pFile );
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
azFileLock(eFileLock), azFileLock(pFile->eFileLock),
- azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid()));
+ azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared,
+ osGetpid(0)));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the end_lock: exit path, as
@@ -26406,7 +26984,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( rc!=SQLITE_BUSY ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_lock;
}
@@ -26441,7 +27019,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
if( rc ){
if( rc!=SQLITE_BUSY ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_lock;
}else{
@@ -26474,7 +27052,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( rc!=SQLITE_BUSY ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
}
}
@@ -26547,7 +27125,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock,
pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
- getpid()));
+ osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
if( pFile->eFileLock<=eFileLock ){
@@ -26581,7 +27159,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
** 4: [RRRR.]
*/
if( eFileLock==SHARED_LOCK ){
-
#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
(void)handleNFSUnlock;
assert( handleNFSUnlock==0 );
@@ -26599,7 +27176,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
tErrno = errno;
rc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_unlock;
}
@@ -26611,7 +27188,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_unlock;
}
@@ -26623,7 +27200,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
tErrno = errno;
rc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
goto end_unlock;
}
@@ -26642,7 +27219,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
** SQLITE_BUSY would confuse the upper layer (in practice it causes
** an assert to fail). */
rc = SQLITE_IOERR_RDLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
goto end_unlock;
}
}
@@ -26655,7 +27232,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
pInode->eFileLock = SHARED_LOCK;
}else{
rc = SQLITE_IOERR_UNLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
goto end_unlock;
}
}
@@ -26673,7 +27250,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
pInode->eFileLock = NO_LOCK;
}else{
rc = SQLITE_IOERR_UNLOCK;
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
pInode->eFileLock = NO_LOCK;
pFile->eFileLock = NO_LOCK;
}
@@ -26948,7 +27525,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
} else {
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
}
return rc;
@@ -26975,7 +27552,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
- pFile->eFileLock, getpid()));
+ pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
@@ -27002,7 +27579,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
rc = SQLITE_IOERR_UNLOCK;
}
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
return rc;
}
@@ -27038,10 +27615,9 @@ static int dotlockClose(sqlite3_file *id) {
** still works when you do this, but concurrency is reduced since
** only a single process can be reading the database at a time.
**
-** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if
-** compiling for VXWORKS.
+** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off
*/
-#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+#if SQLITE_ENABLE_LOCKING_STYLE
/*
** Retry flock() calls that fail with EINTR
@@ -27089,7 +27665,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
/* unlock failed with an error */
lrc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(lrc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
rc = lrc;
}
}
@@ -27099,7 +27675,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
/* someone else might have it reserved */
lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(lrc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
rc = lrc;
}
}
@@ -27165,7 +27741,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
/* didn't get, must be busy */
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
} else {
/* got it, set the type and return ok */
@@ -27194,7 +27770,7 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
- pFile->eFileLock, getpid()));
+ pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
@@ -27255,7 +27831,7 @@ static int flockClose(sqlite3_file *id) {
** to a non-zero value otherwise *pResOut is set to zero. The return value
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
*/
-static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
+static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) {
int rc = SQLITE_OK;
int reserved = 0;
unixFile *pFile = (unixFile*)id;
@@ -27277,7 +27853,7 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
int tErrno = errno;
if( EAGAIN != tErrno ){
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
} else {
/* someone else has the lock when we are in NO_LOCK */
reserved = (pFile->eFileLock < SHARED_LOCK);
@@ -27322,7 +27898,7 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int semLock(sqlite3_file *id, int eFileLock) {
+static int semXLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
@@ -27355,14 +27931,14 @@ static int semLock(sqlite3_file *id, int eFileLock) {
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int semUnlock(sqlite3_file *id, int eFileLock) {
+static int semXUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
sem_t *pSem = pFile->pInode->pSem;
assert( pFile );
assert( pSem );
OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
- pFile->eFileLock, getpid()));
+ pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
@@ -27381,7 +27957,7 @@ static int semUnlock(sqlite3_file *id, int eFileLock) {
int rc, tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
return rc;
}
@@ -27392,10 +27968,10 @@ static int semUnlock(sqlite3_file *id, int eFileLock) {
/*
** Close a file.
*/
-static int semClose(sqlite3_file *id) {
+static int semXClose(sqlite3_file *id) {
if( id ){
unixFile *pFile = (unixFile*)id;
- semUnlock(id, NO_LOCK);
+ semXUnlock(id, NO_LOCK);
assert( pFile );
unixEnterMutex();
releaseInodeInfo(pFile);
@@ -27483,7 +28059,7 @@ static int afpSetLock(
setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK);
#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ storeLastErrno(pFile, tErrno);
}
return rc;
} else {
@@ -27576,7 +28152,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
assert( pFile );
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h,
azFileLock(eFileLock), azFileLock(pFile->eFileLock),
- azFileLock(pInode->eFileLock), pInode->nShared , getpid()));
+ azFileLock(pInode->eFileLock), pInode->nShared , osGetpid(0)));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the afp_end_lock: exit path, as
@@ -27666,7 +28242,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
if( IS_LOCK_ERROR(lrc1) ) {
- pFile->lastErrno = lrc1Errno;
+ storeLastErrno(pFile, lrc1Errno);
rc = lrc1;
goto afp_end_lock;
} else if( IS_LOCK_ERROR(lrc2) ){
@@ -27762,7 +28338,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
- getpid()));
+ osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
if( pFile->eFileLock<=eFileLock ){
@@ -27953,9 +28529,9 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
SimulateIOError( newOffset-- );
if( newOffset!=offset ){
if( newOffset == -1 ){
- ((unixFile*)id)->lastErrno = errno;
+ storeLastErrno((unixFile*)id, errno);
}else{
- ((unixFile*)id)->lastErrno = 0;
+ storeLastErrno((unixFile*)id, 0);
}
return -1;
}
@@ -27965,7 +28541,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
if( got<0 ){
if( errno==EINTR ){ got = 1; continue; }
prior = 0;
- ((unixFile*)id)->lastErrno = errno;
+ storeLastErrno((unixFile*)id, errno);
break;
}else if( got>0 ){
cnt -= got;
@@ -28030,7 +28606,7 @@ static int unixRead(
/* lastErrno set by seekAndRead */
return SQLITE_IOERR_READ;
}else{
- pFile->lastErrno = 0; /* not a system error */
+ storeLastErrno(pFile, 0); /* not a system error */
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[got], 0, amt-got);
return SQLITE_IOERR_SHORT_READ;
@@ -28059,9 +28635,9 @@ static int seekAndWriteFd(
TIMER_START;
#if defined(USE_PREAD)
- do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
+ do{ rc = (int)osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
#elif defined(USE_PREAD64)
- do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
+ do{ rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
#else
do{
i64 iSeek = lseek(fd, iOff, SEEK_SET);
@@ -28171,7 +28747,7 @@ static int unixWrite(
/* lastErrno set by seekAndWrite */
return SQLITE_IOERR_WRITE;
}else{
- pFile->lastErrno = 0; /* not a system error */
+ storeLastErrno(pFile, 0); /* not a system error */
return SQLITE_FULL;
}
}
@@ -28192,9 +28768,9 @@ SQLITE_API int sqlite3_fullsync_count = 0;
** We do not trust systems to provide a working fdatasync(). Some do.
** Others do no. To be safe, we will stick with the (slightly slower)
** fsync(). If you know that your system does support fdatasync() correctly,
-** then simply compile with -Dfdatasync=fdatasync
+** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
*/
-#if !defined(fdatasync)
+#if !defined(fdatasync) && !HAVE_FDATASYNC
# define fdatasync fsync
#endif
@@ -28380,7 +28956,7 @@ static int unixSync(sqlite3_file *id, int flags){
rc = full_fsync(pFile->h, isFullsync, isDataOnly);
SimulateIOError( rc=1 );
if( rc ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
}
@@ -28424,7 +29000,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
rc = robust_ftruncate(pFile->h, nByte);
if( rc ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}else{
#ifdef SQLITE_DEBUG
@@ -28464,7 +29040,7 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
rc = osFstat(((unixFile*)id)->h, &buf);
SimulateIOError( rc=1 );
if( rc!=0 ){
- ((unixFile*)id)->lastErrno = errno;
+ storeLastErrno((unixFile*)id, errno);
return SQLITE_IOERR_FSTAT;
}
*pSize = buf.st_size;
@@ -28500,7 +29076,9 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
- if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
+ if( osFstat(pFile->h, &buf) ){
+ return SQLITE_IOERR_FSTAT;
+ }
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
if( nSize>(i64)buf.st_size ){
@@ -28515,24 +29093,28 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}while( err==EINTR );
if( err ) return SQLITE_IOERR_WRITE;
#else
- /* If the OS does not have posix_fallocate(), fake it. First use
- ** ftruncate() to set the file size, then write a single byte to
- ** the last byte in each block within the extended region. This
- ** is the same technique used by glibc to implement posix_fallocate()
- ** on systems that do not have a real fallocate() system call.
+ /* If the OS does not have posix_fallocate(), fake it. Write a
+ ** single byte to the last byte in each block that falls entirely
+ ** within the extended region. Then, if required, a single byte
+ ** at offset (nSize-1), to set the size of the file correctly.
+ ** This is a similar technique to that used by glibc on systems
+ ** that do not have a real fallocate() call.
*/
int nBlk = buf.st_blksize; /* File-system block size */
+ int nWrite = 0; /* Number of bytes written by seekAndWrite */
i64 iWrite; /* Next offset to write to */
- if( robust_ftruncate(pFile->h, nSize) ){
- pFile->lastErrno = errno;
- return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
- }
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
- while( iWrite<nSize ){
- int nWrite = seekAndWrite(pFile, iWrite, "", 1);
+ assert( iWrite>=buf.st_size );
+ assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
+ assert( ((iWrite+1)%nBlk)==0 );
+ for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
+ nWrite = seekAndWrite(pFile, iWrite, "", 1);
+ if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
+ }
+ if( nWrite==0 || (nSize%nBlk) ){
+ nWrite = seekAndWrite(pFile, nSize-1, "", 1);
if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
- iWrite += nBlk;
}
#endif
}
@@ -28543,7 +29125,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
int rc;
if( pFile->szChunk<=0 ){
if( robust_ftruncate(pFile->h, nByte) ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}
}
@@ -28581,11 +29163,15 @@ static int unixGetTempname(int nBuf, char *zBuf);
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
unixFile *pFile = (unixFile*)id;
switch( op ){
+ case SQLITE_FCNTL_WAL_BLOCK: {
+ /* pFile->ctrlFlags |= UNIXFILE_BLOCK; // Deferred feature */
+ return SQLITE_OK;
+ }
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
}
- case SQLITE_LAST_ERRNO: {
+ case SQLITE_FCNTL_LAST_ERRNO: {
*(int*)pArg = pFile->lastErrno;
return SQLITE_OK;
}
@@ -28654,8 +29240,8 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- case SQLITE_SET_LOCKPROXYFILE:
- case SQLITE_GET_LOCKPROXYFILE: {
+ case SQLITE_FCNTL_SET_LOCKPROXYFILE:
+ case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
return proxyFileControl(id,op,pArg);
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
@@ -28795,7 +29381,9 @@ static int unixDeviceCharacteristics(sqlite3_file *id){
** Instead, it should be called via macro osGetpagesize().
*/
static int unixGetpagesize(void){
-#if defined(_BSD_SOURCE)
+#if OS_VXWORKS
+ return 1024;
+#elif defined(_BSD_SOURCE)
return getpagesize();
#else
return (int)sysconf(_SC_PAGESIZE);
@@ -28888,15 +29476,17 @@ struct unixShm {
** otherwise.
*/
static int unixShmSystemLock(
- unixShmNode *pShmNode, /* Apply locks to this open shared-memory segment */
+ unixFile *pFile, /* Open connection to the WAL file */
int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
int ofst, /* First byte of the locking range */
int n /* Number of bytes to lock */
){
- struct flock f; /* The posix advisory locking structure */
- int rc = SQLITE_OK; /* Result code form fcntl() */
+ unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */
+ struct flock f; /* The posix advisory locking structure */
+ int rc = SQLITE_OK; /* Result code form fcntl() */
/* Access to the unixShmNode object is serialized by the caller */
+ pShmNode = pFile->pInode->pShmNode;
assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
/* Shared locks never span more than one byte */
@@ -28906,6 +29496,7 @@ static int unixShmSystemLock(
assert( n>=1 && n<SQLITE_SHM_NLOCK );
if( pShmNode->h>=0 ){
+ int lkType;
/* Initialize the locking parameters */
memset(&f, 0, sizeof(f));
f.l_type = lockType;
@@ -28913,8 +29504,10 @@ static int unixShmSystemLock(
f.l_start = ofst;
f.l_len = n;
- rc = osFcntl(pShmNode->h, F_SETLK, &f);
+ lkType = (pFile->ctrlFlags & UNIXFILE_BLOCK)!=0 ? F_SETLKW : F_SETLK;
+ rc = osFcntl(pShmNode->h, lkType, &f);
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+ pFile->ctrlFlags &= ~UNIXFILE_BLOCK;
}
/* Update the global lock state and do debug tracing */
@@ -29060,6 +29653,9 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
pShmNode = pInode->pShmNode;
if( pShmNode==0 ){
struct stat sStat; /* fstat() info for database file */
+#ifndef SQLITE_SHM_DIRECTORY
+ const char *zBasePath = pDbFd->zPath;
+#endif
/* Call fstat() to figure out the permissions on the database file. If
** a new *-shm file is created, an attempt will be made to create it
@@ -29073,7 +29669,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
#ifdef SQLITE_SHM_DIRECTORY
nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31;
#else
- nShmFilename = 6 + (int)strlen(pDbFd->zPath);
+ nShmFilename = 6 + (int)strlen(zBasePath);
#endif
pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
if( pShmNode==0 ){
@@ -29087,7 +29683,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
(u32)sStat.st_ino, (u32)sStat.st_dev);
#else
- sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
+ sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath);
sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
#endif
pShmNode->h = -1;
@@ -29121,13 +29717,13 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
** If not, truncate the file to zero length.
*/
rc = SQLITE_OK;
- if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
+ if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
if( robust_ftruncate(pShmNode->h, 0) ){
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
}
}
if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
}
@@ -29359,7 +29955,7 @@ static int unixShmLock(
/* Unlock the system-level locks */
if( (mask & allMask)==0 ){
- rc = unixShmSystemLock(pShmNode, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
@@ -29387,7 +29983,7 @@ static int unixShmLock(
/* Get shared locks at the system level, if necessary */
if( rc==SQLITE_OK ){
if( (allShared & mask)==0 ){
- rc = unixShmSystemLock(pShmNode, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
@@ -29412,7 +30008,7 @@ static int unixShmLock(
** also mark the local connection as being locked.
*/
if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
@@ -29421,7 +30017,7 @@ static int unixShmLock(
}
sqlite3_mutex_leave(pShmNode->mutex);
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
- p->id, getpid(), p->sharedMask, p->exclMask));
+ p->id, osGetpid(0), p->sharedMask, p->exclMask));
return rc;
}
@@ -29480,7 +30076,9 @@ static int unixShmUnmap(
assert( pShmNode->nRef>0 );
pShmNode->nRef--;
if( pShmNode->nRef==0 ){
- if( deleteFlag && pShmNode->h>=0 ) osUnlink(pShmNode->zFilename);
+ if( deleteFlag && pShmNode->h>=0 ){
+ osUnlink(pShmNode->zFilename);
+ }
unixShmPurge(pDbFd);
}
unixLeaveMutex();
@@ -29757,7 +30355,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
** * An I/O method finder function called FINDER that returns a pointer
** to the METHOD object in the previous bullet.
*/
-#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK, SHMMAP) \
+#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \
static const sqlite3_io_methods METHOD = { \
VERSION, /* iVersion */ \
CLOSE, /* xClose */ \
@@ -29822,7 +30420,7 @@ IOMETHODS(
0 /* xShmMap method */
)
-#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+#if SQLITE_ENABLE_LOCKING_STYLE
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
@@ -29840,10 +30438,10 @@ IOMETHODS(
semIoFinder, /* Finder function name */
semIoMethods, /* sqlite3_io_methods object name */
1, /* shared memory is disabled */
- semClose, /* xClose method */
- semLock, /* xLock method */
- semUnlock, /* xUnlock method */
- semCheckReservedLock, /* xCheckReservedLock method */
+ semXClose, /* xClose method */
+ semXLock, /* xLock method */
+ semXUnlock, /* xUnlock method */
+ semXCheckReservedLock, /* xCheckReservedLock method */
0 /* xShmMap method */
)
#endif
@@ -29967,15 +30565,13 @@ static const sqlite3_io_methods
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
-#if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE
-/*
-** This "finder" function attempts to determine the best locking strategy
-** for the database file "filePath". It then returns the sqlite3_io_methods
-** object that implements that strategy.
-**
-** This is for VXWorks only.
+#if OS_VXWORKS
+/*
+** This "finder" function for VxWorks checks to see if posix advisory
+** locking works. If it does, then that is what is used. If it does not
+** work, then fallback to named semaphore locking.
*/
-static const sqlite3_io_methods *autolockIoFinderImpl(
+static const sqlite3_io_methods *vxworksIoFinderImpl(
const char *filePath, /* name of the database file */
unixFile *pNew /* the open file object */
){
@@ -30001,9 +30597,9 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
}
}
static const sqlite3_io_methods
- *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
+ *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl;
-#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
+#endif /* OS_VXWORKS */
/*
** An abstract type for a pointer to an IO method finder function:
@@ -30185,7 +30781,7 @@ static int fillInUnixFile(
}
#endif
- pNew->lastErrno = 0;
+ storeLastErrno(pNew, 0);
#if OS_VXWORKS
if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__);
@@ -30516,8 +31112,8 @@ static int unixOpen(
** the same instant might all reset the PRNG. But multiple resets
** are harmless.
*/
- if( randomnessPid!=getpid() ){
- randomnessPid = getpid();
+ if( randomnessPid!=osGetpid(0) ){
+ randomnessPid = osGetpid(0);
sqlite3_randomness(0,0);
}
@@ -30633,13 +31229,16 @@ static int unixOpen(
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
if( fstatfs(fd, &fsInfo) == -1 ){
- ((unixFile*)pFile)->lastErrno = errno;
+ storeLastErrno(p, errno);
robust_close(p, fd, __LINE__);
return SQLITE_IOERR_ACCESS;
}
if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
}
+ if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
+ ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
+ }
#endif
/* Set up appropriate ctrlFlags */
@@ -30662,19 +31261,6 @@ static int unixOpen(
if( envforce!=NULL ){
useProxy = atoi(envforce)>0;
}else{
- if( statfs(zPath, &fsInfo) == -1 ){
- /* In theory, the close(fd) call is sub-optimal. If the file opened
- ** with fd is a database file, and there are other connections open
- ** on that file that are currently holding advisory locks on it,
- ** then the call to close() will cancel those locks. In practice,
- ** we're assuming that statfs() doesn't fail very often. At least
- ** not while other file descriptors opened by the same process on
- ** the same file are working. */
- p->lastErrno = errno;
- robust_close(p, fd, __LINE__);
- rc = SQLITE_IOERR_ACCESS;
- goto open_finished;
- }
useProxy = !(fsInfo.f_flags&MNT_LOCAL);
}
if( useProxy ){
@@ -30918,7 +31504,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** tests repeatable.
*/
memset(zBuf, 0, nBuf);
- randomnessPid = getpid();
+ randomnessPid = osGetpid(0);
#if !defined(SQLITE_TEST)
{
int fd, got;
@@ -31100,9 +31686,10 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
**
** C APIs
**
-** sqlite3_file_control(db, dbname, SQLITE_SET_LOCKPROXYFILE,
+** sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE,
** <proxy_path> | ":auto:");
-** sqlite3_file_control(db, dbname, SQLITE_GET_LOCKPROXYFILE, &<proxy_path>);
+** sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE,
+** &<proxy_path>);
**
**
** SQL pragmas
@@ -31195,7 +31782,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
** force proxy locking to be used for every database file opened, and 0
** will force automatic proxy locking to be disabled for all database
-** files (explicitly calling the SQLITE_SET_LOCKPROXYFILE pragma or
+** files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or
** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
*/
@@ -31216,6 +31803,7 @@ struct proxyLockingContext {
char *lockProxyPath; /* Name of the proxy lock file */
char *dbPath; /* Name of the open file */
int conchHeld; /* 1 if the conch is held, -1 if lockless */
+ int nFails; /* Number of conch taking failures */
void *oldLockingContext; /* Original lockingcontext to restore on close */
sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
};
@@ -31237,7 +31825,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
{
if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){
OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n",
- lPath, errno, getpid()));
+ lPath, errno, osGetpid(0)));
return SQLITE_IOERR_LOCK;
}
len = strlcat(lPath, "sqliteplocks", maxLen);
@@ -31259,7 +31847,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
}
lPath[i+len]='\0';
strlcat(lPath, ":auto:", maxLen);
- OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid()));
+ OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, osGetpid(0)));
return SQLITE_OK;
}
@@ -31286,7 +31874,7 @@ static int proxyCreateLockPath(const char *lockPath){
if( err!=EEXIST ) {
OSTRACE(("CREATELOCKPATH FAILED creating %s, "
"'%s' proxy lock path=%s pid=%d\n",
- buf, strerror(err), lockPath, getpid()));
+ buf, strerror(err), lockPath, osGetpid(0)));
return err;
}
}
@@ -31295,7 +31883,7 @@ static int proxyCreateLockPath(const char *lockPath){
}
buf[i] = lockPath[i];
}
- OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid()));
+ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, osGetpid(0)));
return 0;
}
@@ -31404,10 +31992,10 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
static int proxyGetHostID(unsigned char *pHostID, int *pError){
assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
memset(pHostID, 0, PROXY_HOSTIDLEN);
-#if defined(__MAX_OS_X_VERSION_MIN_REQUIRED)\
- && __MAC_OS_X_VERSION_MIN_REQUIRED<1050
+# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
+ (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
{
- static const struct timespec timeout = {1, 0}; /* 1 sec timeout */
+ struct timespec timeout = {1, 0}; /* 1 sec timeout */
if( gethostuuid(pHostID, &timeout) ){
int err = errno;
if( pError ){
@@ -31522,7 +32110,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
*/
struct stat buf;
if( osFstat(conchFile->h, &buf) ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR_LOCK;
}
@@ -31542,7 +32130,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
char tBuf[PROXY_MAXCONCHLEN];
int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
if( len<0 ){
- pFile->lastErrno = errno;
+ storeLastErrno(pFile, errno);
return SQLITE_IOERR_LOCK;
}
if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
@@ -31562,7 +32150,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
if( 0==proxyBreakConchLock(pFile, myHostID) ){
rc = SQLITE_OK;
if( lockType==EXCLUSIVE_LOCK ){
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
}
if( !rc ){
rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
@@ -31600,11 +32188,12 @@ static int proxyTakeConch(unixFile *pFile){
int forceNewLockPath = 0;
OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
+ osGetpid(0)));
rc = proxyGetHostID(myHostID, &pError);
if( (rc&0xff)==SQLITE_IOERR ){
- pFile->lastErrno = pError;
+ storeLastErrno(pFile, pError);
goto end_takeconch;
}
rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
@@ -31615,7 +32204,7 @@ static int proxyTakeConch(unixFile *pFile){
readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
if( readLen<0 ){
/* I/O error: lastErrno set by seekAndRead */
- pFile->lastErrno = conchFile->lastErrno;
+ storeLastErrno(pFile, conchFile->lastErrno);
rc = SQLITE_IOERR_READ;
goto end_takeconch;
}else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
@@ -31688,7 +32277,7 @@ static int proxyTakeConch(unixFile *pFile){
rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
}
}else{
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
+ rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
}
if( rc==SQLITE_OK ){
char writeBuffer[PROXY_MAXCONCHLEN];
@@ -31697,7 +32286,8 @@ static int proxyTakeConch(unixFile *pFile){
writeBuffer[0] = (char)PROXY_CONCHVERSION;
memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
if( pCtx->lockProxyPath!=NULL ){
- strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN);
+ strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath,
+ MAXPATHLEN);
}else{
strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
}
@@ -31809,7 +32399,7 @@ static int proxyReleaseConch(unixFile *pFile){
conchFile = pCtx->conchFile;
OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
(pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
- getpid()));
+ osGetpid(0)));
if( pCtx->conchHeld>0 ){
rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
}
@@ -31909,7 +32499,8 @@ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
/* afp style keeps a reference to the db path in the filePath field
** of the struct */
assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
- strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, MAXPATHLEN);
+ strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath,
+ MAXPATHLEN);
} else
#endif
if( pFile->pMethod == &dotlockIoMethods ){
@@ -31950,7 +32541,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
}
OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
- (lockPath ? lockPath : ":auto:"), getpid()));
+ (lockPath ? lockPath : ":auto:"), osGetpid(0)));
pCtx = sqlite3_malloc( sizeof(*pCtx) );
if( pCtx==0 ){
@@ -32022,7 +32613,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
*/
static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
switch( op ){
- case SQLITE_GET_LOCKPROXYFILE: {
+ case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
unixFile *pFile = (unixFile*)id;
if( pFile->pMethod == &proxyIoMethods ){
proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
@@ -32037,13 +32628,16 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
- case SQLITE_SET_LOCKPROXYFILE: {
+ case SQLITE_FCNTL_SET_LOCKPROXYFILE: {
unixFile *pFile = (unixFile*)id;
int rc = SQLITE_OK;
int isProxyStyle = (pFile->pMethod == &proxyIoMethods);
if( pArg==NULL || (const char *)pArg==0 ){
if( isProxyStyle ){
- /* turn off proxy locking - not supported */
+ /* turn off proxy locking - not supported. If support is added for
+ ** switching proxy locking mode off then it will need to fail if
+ ** the journal mode is WAL mode.
+ */
rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;
}else{
/* turn off proxy locking - already off - NOOP */
@@ -32234,7 +32828,7 @@ static int proxyClose(sqlite3_file *id) {
** necessarily been initialized when this routine is called, and so they
** should not be used.
*/
-SQLITE_API int sqlite3_os_init(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
/*
** The following macro defines an initializer for an sqlite3_vfs object.
** The name of the VFS is NAME. The pAppData is a pointer to a pointer
@@ -32288,8 +32882,10 @@ SQLITE_API int sqlite3_os_init(void){
** array cannot be const.
*/
static sqlite3_vfs aVfs[] = {
-#if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__))
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix", autolockIoFinder ),
+#elif OS_VXWORKS
+ UNIXVFS("unix", vxworksIoFinder ),
#else
UNIXVFS("unix", posixIoFinder ),
#endif
@@ -32299,11 +32895,11 @@ SQLITE_API int sqlite3_os_init(void){
#if OS_VXWORKS
UNIXVFS("unix-namedsem", semIoFinder ),
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS
UNIXVFS("unix-posix", posixIoFinder ),
-#if !OS_VXWORKS
- UNIXVFS("unix-flock", flockIoFinder ),
#endif
+#if SQLITE_ENABLE_LOCKING_STYLE
+ UNIXVFS("unix-flock", flockIoFinder ),
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix-afp", afpIoFinder ),
@@ -32331,7 +32927,7 @@ SQLITE_API int sqlite3_os_init(void){
** to release dynamically allocated objects. But not on unix.
** This routine is a no-op for unix.
*/
-SQLITE_API int sqlite3_os_end(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
return SQLITE_OK;
}
@@ -32581,6 +33177,11 @@ SQLITE_API int sqlite3_open_file_count = 0;
with SQLITE_OMIT_WAL."
#endif
+#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0
+# error "Memory mapped files require support from the Windows NT kernel,\
+ compile with SQLITE_MAX_MMAP_SIZE=0."
+#endif
+
/*
** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
** based on the sub-platform)?
@@ -32710,10 +33311,11 @@ SQLITE_API int sqlite3_open_file_count = 0;
/*
** Do we need to manually define the Win32 file mapping APIs for use with WAL
-** mode (e.g. these APIs are available in the Windows CE SDK; however, they
-** are not present in the header file)?
+** mode or memory mapped files (e.g. these APIs are available in the Windows
+** CE SDK; however, they are not present in the header file)?
*/
-#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
+#if SQLITE_WIN32_FILEMAPPING_API && \
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
/*
** Two of the file mapping APIs are different under WinRT. Figure out which
** set we need.
@@ -32738,10 +33340,12 @@ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
#endif /* SQLITE_OS_WINRT */
/*
-** This file mapping API is common to both Win32 and WinRT.
+** These file mapping APIs are common to both Win32 and WinRT.
*/
+
+WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T);
WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
-#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
+#endif /* SQLITE_WIN32_FILEMAPPING_API */
/*
** Some Microsoft compilers lack this definition.
@@ -33034,7 +33638,7 @@ static struct win_syscall {
LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
- !defined(SQLITE_OMIT_WAL))
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
{ "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
#else
{ "CreateFileMappingA", (SYSCALL)0, 0 },
@@ -33044,7 +33648,7 @@ static struct win_syscall {
DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
- !defined(SQLITE_OMIT_WAL))
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
{ "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
#else
{ "CreateFileMappingW", (SYSCALL)0, 0 },
@@ -33384,7 +33988,8 @@ static struct win_syscall {
LPOVERLAPPED))aSyscall[48].pCurrent)
#endif
-#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL))
+#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
{ "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
#else
{ "MapViewOfFile", (SYSCALL)0, 0 },
@@ -33454,7 +34059,7 @@ static struct win_syscall {
#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
LPOVERLAPPED))aSyscall[58].pCurrent)
-#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL)
+#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
{ "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
#else
{ "UnmapViewOfFile", (SYSCALL)0, 0 },
@@ -33517,7 +34122,7 @@ static struct win_syscall {
#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent)
-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
{ "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
#else
{ "MapViewOfFileFromApp", (SYSCALL)0, 0 },
@@ -33581,7 +34186,7 @@ static struct win_syscall {
#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent)
-#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
{ "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
#else
{ "CreateFileMappingFromApp", (SYSCALL)0, 0 },
@@ -33606,6 +34211,32 @@ static struct win_syscall {
SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
#endif /* defined(InterlockedCompareExchange) */
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ { "UuidCreate", (SYSCALL)UuidCreate, 0 },
+#else
+ { "UuidCreate", (SYSCALL)0, 0 },
+#endif
+
+#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent)
+
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 },
+#else
+ { "UuidCreateSequential", (SYSCALL)0, 0 },
+#endif
+
+#define osUuidCreateSequential \
+ ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent)
+
+#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0
+ { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 },
+#else
+ { "FlushViewOfFile", (SYSCALL)0, 0 },
+#endif
+
+#define osFlushViewOfFile \
+ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
+
}; /* End of the overrideable system calls */
/*
@@ -33699,7 +34330,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
** "pnLargest" argument, if non-zero, will be used to return the size of the
** largest committed free block in the heap, in bytes.
*/
-SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
int rc = SQLITE_OK;
UINT nLargest = 0;
HANDLE hHeap;
@@ -33739,12 +34370,12 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
** be returned and no changes will be made to the Win32 native heap.
*/
-SQLITE_API int sqlite3_win32_reset_heap(){
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
int rc;
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
+ MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
sqlite3_mutex_enter(pMaster);
sqlite3_mutex_enter(pMem);
winMemAssertMagic();
@@ -33784,7 +34415,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){
** (if available).
*/
-SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
+SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){
char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
@@ -33824,7 +34455,7 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
static HANDLE sleepObj = NULL;
#endif
-SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
+SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){
#if SQLITE_OS_WINRT
if ( sleepObj==NULL ){
sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
@@ -33873,7 +34504,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
** This function determines if the machine is running a version of Windows
** based on the NT kernel.
*/
-SQLITE_API int sqlite3_win32_is_nt(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
#if SQLITE_OS_WINRT
/*
** NOTE: The WinRT sub-platform is always assumed to be based on the NT
@@ -34227,7 +34858,7 @@ static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
** Convert multibyte character string to UTF-8. Space to hold the
** returned string is obtained from sqlite3_malloc().
*/
-SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
+SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
char *zFilenameUtf8;
LPWSTR zTmpWide;
@@ -34244,7 +34875,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
** Convert UTF-8 to multibyte character string. Space to hold the
** returned string is obtained from sqlite3_malloc().
*/
-SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
+SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
char *zFilenameMbcs;
LPWSTR zTmpWide;
@@ -34264,7 +34895,7 @@ SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
** argument is the name of the directory to use. The return value will be
** SQLITE_OK if successful.
*/
-SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
char **ppDirectory = 0;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
@@ -34489,11 +35120,11 @@ static int winRetryIoerr(int *pnRetry, DWORD *pError){
/*
** Log a I/O error retry episode.
*/
-static void winLogIoerr(int nRetry){
+static void winLogIoerr(int nRetry, int lineno){
if( nRetry ){
- sqlite3_log(SQLITE_IOERR,
- "delayed %dms for lock/sharing conflict",
- winIoerrRetryDelay*nRetry*(nRetry+1)/2
+ sqlite3_log(SQLITE_NOTICE,
+ "delayed %dms for lock/sharing conflict at line %d",
+ winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno
);
}
}
@@ -34973,7 +35604,8 @@ static int winClose(sqlite3_file *id){
assert( pFile->pShm==0 );
#endif
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
- OSTRACE(("CLOSE file=%p\n", pFile->h));
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
#if SQLITE_MAX_MMAP_SIZE>0
winUnmapfile(pFile);
@@ -35002,7 +35634,8 @@ static int winClose(sqlite3_file *id){
pFile->h = NULL;
}
OpenCounter(-1);
- OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed"));
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed"));
return rc ? SQLITE_OK
: winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
"winClose", pFile->zPath);
@@ -35019,7 +35652,7 @@ static int winRead(
int amt, /* Number of bytes to read */
sqlite3_int64 offset /* Begin reading at this offset */
){
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
OVERLAPPED overlapped; /* The offset for ReadFile. */
#endif
winFile *pFile = (winFile*)id; /* file handle */
@@ -35030,7 +35663,8 @@ static int winRead(
assert( amt>0 );
assert( offset>=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
@@ -35039,7 +35673,8 @@ static int winRead(
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
- OSTRACE(("READ-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
@@ -35051,9 +35686,10 @@ static int winRead(
}
#endif
-#if SQLITE_OS_WINCE
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( winSeekFile(pFile, offset) ){
- OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_FULL;
}
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
@@ -35067,19 +35703,22 @@ static int winRead(
DWORD lastErrno;
if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
pFile->lastErrno = lastErrno;
- OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winRead", pFile->zPath);
}
- winLogIoerr(nRetry);
+ winLogIoerr(nRetry, __LINE__);
if( nRead<(DWORD)amt ){
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[nRead], 0, amt-nRead);
- OSTRACE(("READ file=%p, rc=SQLITE_IOERR_SHORT_READ\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_IOERR_SHORT_READ;
}
- OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
@@ -35102,7 +35741,8 @@ static int winWrite(
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
@@ -35111,7 +35751,8 @@ static int winWrite(
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
- OSTRACE(("WRITE-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
@@ -35123,13 +35764,13 @@ static int winWrite(
}
#endif
-#if SQLITE_OS_WINCE
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
rc = winSeekFile(pFile, offset);
if( rc==0 ){
#else
{
#endif
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
OVERLAPPED overlapped; /* The offset for WriteFile. */
#endif
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
@@ -35137,14 +35778,14 @@ static int winWrite(
DWORD nWrite; /* Bytes written by each WriteFile() call */
DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
#endif
while( nRem>0 ){
-#if SQLITE_OS_WINCE
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
#else
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
@@ -35157,7 +35798,7 @@ static int winWrite(
lastErrno = osGetLastError();
break;
}
-#if !SQLITE_OS_WINCE
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
offset += nWrite;
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
@@ -35174,17 +35815,20 @@ static int winWrite(
if( rc ){
if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
|| ( pFile->lastErrno==ERROR_DISK_FULL )){
- OSTRACE(("WRITE file=%p, rc=SQLITE_FULL\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_FULL, pFile->lastErrno,
"winWrite1", pFile->zPath);
}
- OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
"winWrite2", pFile->zPath);
}else{
- winLogIoerr(nRetry);
+ winLogIoerr(nRetry, __LINE__);
}
- OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
@@ -35198,8 +35842,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
assert( pFile );
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n",
- pFile->h, nByte, pFile->locktype));
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n",
+ osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype));
/* If the user has configured a chunk-size for this file, truncate the
** file so that it consists of an integer number of chunks (i.e. the
@@ -35231,7 +35875,8 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
}
#endif
- OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n",
+ osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc)));
return rc;
}
@@ -35276,8 +35921,9 @@ static int winSync(sqlite3_file *id, int flags){
*/
SimulateDiskfullError( return SQLITE_FULL );
- OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n",
- pFile->h, flags, pFile->locktype));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n",
+ osGetCurrentProcessId(), pFile, pFile->h, flags,
+ pFile->locktype));
#ifndef SQLITE_TEST
UNUSED_PARAMETER(flags);
@@ -35292,19 +35938,38 @@ static int winSync(sqlite3_file *id, int flags){
** no-op
*/
#ifdef SQLITE_NO_SYNC
- OSTRACE(("SYNC-NOP file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
#else
+#if SQLITE_MAX_MMAP_SIZE>0
+ if( pFile->pMapRegion ){
+ if( osFlushViewOfFile(pFile->pMapRegion, 0) ){
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ "rc=SQLITE_OK\n", osGetCurrentProcessId(),
+ pFile, pFile->pMapRegion));
+ }else{
+ pFile->lastErrno = osGetLastError();
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
+ "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(),
+ pFile, pFile->pMapRegion));
+ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+ "winSync1", pFile->zPath);
+ }
+ }
+#endif
rc = osFlushFileBuffers(pFile->h);
SimulateIOError( rc=FALSE );
if( rc ){
- OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}else{
pFile->lastErrno = osGetLastError();
- OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h));
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
+ osGetCurrentProcessId(), pFile, pFile->h));
return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
- "winSync", pFile->zPath);
+ "winSync2", pFile->zPath);
}
#endif
}
@@ -36354,16 +37019,16 @@ static int winShmMap(
void volatile **pp /* OUT: Mapped memory */
){
winFile *pDbFd = (winFile*)fd;
- winShm *p = pDbFd->pShm;
+ winShm *pShm = pDbFd->pShm;
winShmNode *pShmNode;
int rc = SQLITE_OK;
- if( !p ){
+ if( !pShm ){
rc = winOpenSharedMemory(pDbFd);
if( rc!=SQLITE_OK ) return rc;
- p = pDbFd->pShm;
+ pShm = pDbFd->pShm;
}
- pShmNode = p->pShmNode;
+ pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
@@ -37275,7 +37940,7 @@ static int winOpen(
}
}
#endif
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name,
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
@@ -37459,7 +38124,7 @@ static int winDelete(
if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename);
}else{
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
}
sqlite3_free(zConverted);
OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
@@ -37509,7 +38174,7 @@ static int winAccess(
attr = sAttrData.dwFileAttributes;
}
}else{
- winLogIoerr(cnt);
+ winLogIoerr(cnt, __LINE__);
if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
sqlite3_free(zConverted);
return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess",
@@ -37885,6 +38550,22 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
n += sizeof(i);
}
#endif
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
+ if( sizeof(UUID)<=nBuf-n ){
+ UUID id;
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreate(&id);
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
+ }
+ if( sizeof(UUID)<=nBuf-n ){
+ UUID id;
+ memset(&id, 0, sizeof(UUID));
+ osUuidCreateSequential(&id);
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
+ }
+#endif
return n;
}
@@ -38008,7 +38689,7 @@ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
/*
** Initialize and deinitialize the operating system interface.
*/
-SQLITE_API int sqlite3_os_init(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
static sqlite3_vfs winVfs = {
3, /* iVersion */
sizeof(winFile), /* szOsFile */
@@ -38062,7 +38743,7 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==77 );
+ assert( ArraySize(aSyscall)==80 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
@@ -38083,7 +38764,7 @@ SQLITE_API int sqlite3_os_init(void){
return SQLITE_OK;
}
-SQLITE_API int sqlite3_os_end(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
#if SQLITE_OS_WINRT
if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
@@ -38538,18 +39219,6 @@ struct PCache {
PgHdr *pPage1; /* Reference to page 1 */
};
-/*
-** Some of the assert() macros in this code are too expensive to run
-** even during normal debugging. Use them only rarely on long-running
-** tests. Enable the expensive asserts using the
-** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
-*/
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-# define expensive_assert(X) assert(X)
-#else
-# define expensive_assert(X)
-#endif
-
/********************************** Linked List Management ********************/
/* Allowed values for second argument to pcacheManageDirtyList() */
@@ -38633,12 +39302,20 @@ static void pcacheUnpin(PgHdr *p){
}
/*
-** Compute the number of pages of cache requested.
+** Compute the number of pages of cache requested. p->szCache is the
+** cache size requested by the "PRAGMA cache_size" statement.
+**
+**
*/
static int numberOfCachePages(PCache *p){
if( p->szCache>=0 ){
+ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
+ ** suggested cache size is set to N. */
return p->szCache;
}else{
+ /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then
+ ** the number of cache pages is adjusted to use approximately abs(N*1024)
+ ** bytes of memory. */
return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
}
}
@@ -38703,7 +39380,8 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
if( pCache->szPage ){
sqlite3_pcache *pNew;
pNew = sqlite3GlobalConfig.pcache2.xCreate(
- szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
+ szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
+ pCache->bPurgeable
);
if( pNew==0 ) return SQLITE_NOMEM;
sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
@@ -39158,6 +39836,13 @@ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
}
+/*
+** Return the size of the header added by this middleware layer
+** in the page-cache hierarchy.
+*/
+SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
+
+
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
** For all dirty pages currently in the cache, invoke the specified
@@ -39370,7 +40055,6 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
static void *pcache1Alloc(int nByte){
void *p = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
- sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
if( nByte<=pcache1.szSlot ){
sqlite3_mutex_enter(pcache1.mutex);
p = (PgHdr1 *)pcache1.pFree;
@@ -39379,7 +40063,8 @@ static void *pcache1Alloc(int nByte){
pcache1.nFreeSlot--;
pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
assert( pcache1.nFreeSlot>=0 );
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
}
sqlite3_mutex_leave(pcache1.mutex);
}
@@ -39392,7 +40077,8 @@ static void *pcache1Alloc(int nByte){
if( p ){
int sz = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
sqlite3_mutex_leave(pcache1.mutex);
}
#endif
@@ -39410,7 +40096,7 @@ static int pcache1Free(void *p){
if( p>=pcache1.pStart && p<pcache1.pEnd ){
PgFreeslot *pSlot;
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
@@ -39424,7 +40110,7 @@ static int pcache1Free(void *p){
nFreed = sqlite3MallocSize(p);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
sqlite3_mutex_leave(pcache1.mutex);
#endif
sqlite3_free(p);
@@ -39471,7 +40157,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
pPg = 0;
}
#else
- pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra);
+ pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
pcache1EnterMutex(pCache->pGroup);
@@ -40156,6 +40842,19 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
}
+/*
+** Return the size of the header on each page of this PCACHE implementation.
+*/
+SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
+
+/*
+** Return the global mutex used by this PCACHE implementation. The
+** sqlite3_status() routine needs access to this mutex.
+*/
+SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){
+ return pcache1.mutex;
+}
+
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
@@ -41512,6 +42211,8 @@ struct Pager {
u8 setMaster; /* True if a m-j name has been written to jrnl */
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 subjInMemory; /* True to use in-memory sub-journals */
+ u8 bUseFetch; /* True to use xFetch() */
+ u8 hasBeenUsed; /* True if any content previously read from this pager*/
Pgno dbSize; /* Number of pages in the database */
Pgno dbOrigSize; /* dbSize before the current transaction */
Pgno dbFileSize; /* Number of pages in the database file */
@@ -41529,9 +42230,9 @@ struct Pager {
sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
PagerSavepoint *aSavepoint; /* Array of active savepoints */
int nSavepoint; /* Number of elements in aSavepoint[] */
+ u32 iDataVersion; /* Changes whenever database content changes */
char dbFileVers[16]; /* Changes whenever database file changes */
- u8 bUseFetch; /* True to use xFetch() */
int nMmapOut; /* Number of mmap pages currently outstanding */
sqlite3_int64 szMmap; /* Desired maximum mmap size */
PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
@@ -42547,11 +43248,20 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
** Discard the entire contents of the in-memory page-cache.
*/
static void pager_reset(Pager *pPager){
+ pPager->iDataVersion++;
sqlite3BackupRestart(pPager->pBackup);
sqlite3PcacheClear(pPager->pPCache);
}
/*
+** Return the pPager->iDataVersion value
+*/
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
+ assert( pPager->eState>PAGER_OPEN );
+ return pPager->iDataVersion;
+}
+
+/*
** Free all structures in the Pager.aSavepoint[] array and set both
** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
** if it is open and the pager is not in exclusive mode.
@@ -43765,7 +44475,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
**
** For an encrypted database, the situation is more complex: bytes
** 24..39 of the database are white noise. But the probability of
- ** white noising equaling 16 bytes of 0xff is vanishingly small so
+ ** white noise equaling 16 bytes of 0xff is vanishingly small so
** we should still be ok.
*/
memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
@@ -44753,7 +45463,7 @@ static int pagerAcquireMapPage(
PgHdr **ppPage /* OUT: Acquired page object */
){
PgHdr *p; /* Memory mapped page to return */
-
+
if( pPager->pMmapFreelist ){
*ppPage = p = pPager->pMmapFreelist;
pPager->pMmapFreelist = p->pDirty;
@@ -45984,16 +46694,12 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
);
}
- if( !pPager->tempFile && (
- pPager->pBackup
- || sqlite3PcachePagecount(pPager->pPCache)>0
- || USEFETCH(pPager)
- )){
- /* The shared-lock has just been acquired on the database file
- ** and there are already pages in the cache (from a previous
- ** read or write transaction). Check to see if the database
- ** has been modified. If the database has changed, flush the
- ** cache.
+ if( !pPager->tempFile && pPager->hasBeenUsed ){
+ /* The shared-lock has just been acquired then check to
+ ** see if the database has been modified. If the database has changed,
+ ** flush the cache. The pPager->hasBeenUsed flag prevents this from
+ ** occurring on the very first access to a file, in order to save a
+ ** single unnecessary sqlite3OsRead() call at the start-up.
**
** Database changes is detected by looking at 15 bytes beginning
** at offset 24 into the file. The first 4 of these 16 bytes are
@@ -46158,6 +46864,7 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
if( pgno==0 ){
return SQLITE_CORRUPT_BKPT;
}
+ pPager->hasBeenUsed = 1;
/* If the pager is in the error state, return an error immediately.
** Otherwise, request the page from the PCache layer. */
@@ -46307,6 +47014,7 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
assert( pgno!=0 );
assert( pPager->pPCache!=0 );
pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
+ assert( pPage==0 || pPager->hasBeenUsed );
return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
}
@@ -47173,6 +47881,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
+ pPager->iDataVersion++;
rc = pager_end_transaction(pPager, pPager->setMaster, 1);
return pager_error(pPager, rc);
}
@@ -47714,6 +48423,18 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
#endif
/*
+** The page handle passed as the first argument refers to a dirty page
+** with a page number other than iNew. This function changes the page's
+** page number to iNew and sets the value of the PgHdr.flags field to
+** the value passed as the third parameter.
+*/
+SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){
+ assert( pPg->pgno!=iNew );
+ pPg->flags = flags;
+ sqlite3PcacheMove(pPg, iNew);
+}
+
+/*
** Return a pointer to the data for the specified page.
*/
SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
@@ -47929,7 +48650,8 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog,
int rc = SQLITE_OK;
if( pPager->pWal ){
rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
- pPager->xBusyHandler, pPager->pBusyHandlerArg,
+ (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
+ pPager->pBusyHandlerArg,
pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
);
@@ -48111,6 +48833,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
@@ -48904,9 +49627,10 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
}
-static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
int rc;
if( pWal->exclusiveMode ) return SQLITE_OK;
+ if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
@@ -49192,7 +49916,7 @@ static int walIndexRecover(Wal *pWal){
assert( pWal->writeLock );
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
nLock = SQLITE_SHM_NLOCK - iLock;
- rc = walLockExclusive(pWal, iLock, nLock);
+ rc = walLockExclusive(pWal, iLock, nLock, 0);
if( rc ){
return rc;
}
@@ -49620,7 +50344,7 @@ static void walMergesort(
** Free an iterator allocated by walIteratorInit().
*/
static void walIteratorFree(WalIterator *p){
- sqlite3ScratchFree(p);
+ sqlite3_free(p);
}
/*
@@ -49655,7 +50379,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
- p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+ p = (WalIterator *)sqlite3_malloc(nByte);
if( !p ){
return SQLITE_NOMEM;
}
@@ -49665,7 +50389,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
/* Allocate temporary space used by the merge-sort routine. This block
** of memory will be freed before this function returns.
*/
- aTmp = (ht_slot *)sqlite3ScratchMalloc(
+ aTmp = (ht_slot *)sqlite3_malloc(
sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
);
if( !aTmp ){
@@ -49702,7 +50426,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
p->aSegment[i].aPgno = (u32 *)aPgno;
}
}
- sqlite3ScratchFree(aTmp);
+ sqlite3_free(aTmp);
if( rc!=SQLITE_OK ){
walIteratorFree(p);
@@ -49726,7 +50450,7 @@ static int walBusyLock(
){
int rc;
do {
- rc = walLockExclusive(pWal, lockIdx, n);
+ rc = walLockExclusive(pWal, lockIdx, n, 0);
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
return rc;
}
@@ -49740,6 +50464,38 @@ static int walPagesize(Wal *pWal){
}
/*
+** The following is guaranteed when this function is called:
+**
+** a) the WRITER lock is held,
+** b) the entire log file has been checkpointed, and
+** c) any existing readers are reading exclusively from the database
+** file - there are no readers that may attempt to read a frame from
+** the log file.
+**
+** This function updates the shared-memory structures so that the next
+** client to write to the database (which may be this one) does so by
+** writing frames into the start of the log file.
+**
+** The value of parameter salt1 is used as the aSalt[1] value in the
+** new wal-index header. It should be passed a pseudo-random value (i.e.
+** one obtained from sqlite3_randomness()).
+*/
+static void walRestartHdr(Wal *pWal, u32 salt1){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ int i; /* Loop counter */
+ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
+ pWal->nCkpt++;
+ pWal->hdr.mxFrame = 0;
+ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+ memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
+ walIndexWriteHdr(pWal);
+ pInfo->nBackfill = 0;
+ pInfo->aReadMark[1] = 0;
+ for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+ assert( pInfo->aReadMark[0]==0 );
+}
+
+/*
** Copy as much content as we can from the WAL back into the database file
** in response to an sqlite3_wal_checkpoint() request or the equivalent.
**
@@ -49773,12 +50529,12 @@ static int walPagesize(Wal *pWal){
static int walCheckpoint(
Wal *pWal, /* Wal connection */
int eMode, /* One of PASSIVE, FULL or RESTART */
- int (*xBusyCall)(void*), /* Function to call when busy */
+ int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags for OsSync() (or 0) */
u8 *zBuf /* Temporary buffer to use */
){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int szPage; /* Database page-size */
WalIterator *pIter = 0; /* Wal iterator context */
u32 iDbpage = 0; /* Next database page to write */
@@ -49787,123 +50543,146 @@ static int walCheckpoint(
u32 mxPage; /* Max database page to write */
int i; /* Loop counter */
volatile WalCkptInfo *pInfo; /* The checkpoint status information */
- int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
szPage = walPagesize(pWal);
testcase( szPage<=32768 );
testcase( szPage>=65536 );
pInfo = walCkptInfo(pWal);
- if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
+ if( pInfo->nBackfill<pWal->hdr.mxFrame ){
- /* Allocate the iterator */
- rc = walIteratorInit(pWal, &pIter);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert( pIter );
+ /* Allocate the iterator */
+ rc = walIteratorInit(pWal, &pIter);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ assert( pIter );
- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
+ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+ ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
- /* Compute in mxSafeFrame the index of the last frame of the WAL that is
- ** safe to write into the database. Frames beyond mxSafeFrame might
- ** overwrite database pages that are in use by active readers and thus
- ** cannot be backfilled from the WAL.
- */
- mxSafeFrame = pWal->hdr.mxFrame;
- mxPage = pWal->hdr.nPage;
- for(i=1; i<WAL_NREADER; i++){
- u32 y = pInfo->aReadMark[i];
- if( mxSafeFrame>y ){
- assert( y<=pWal->hdr.mxFrame );
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
- if( rc==SQLITE_OK ){
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
- }else if( rc==SQLITE_BUSY ){
- mxSafeFrame = y;
- xBusy = 0;
- }else{
- goto walcheckpoint_out;
+ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+ ** safe to write into the database. Frames beyond mxSafeFrame might
+ ** overwrite database pages that are in use by active readers and thus
+ ** cannot be backfilled from the WAL.
+ */
+ mxSafeFrame = pWal->hdr.mxFrame;
+ mxPage = pWal->hdr.nPage;
+ for(i=1; i<WAL_NREADER; i++){
+ u32 y = pInfo->aReadMark[i];
+ if( mxSafeFrame>y ){
+ assert( y<=pWal->hdr.mxFrame );
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc==SQLITE_BUSY ){
+ mxSafeFrame = y;
+ xBusy = 0;
+ }else{
+ goto walcheckpoint_out;
+ }
}
}
- }
-
- if( pInfo->nBackfill<mxSafeFrame
- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
- ){
- i64 nSize; /* Current size of database file */
- u32 nBackfill = pInfo->nBackfill;
- /* Sync the WAL to disk */
- if( sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
- }
+ if( pInfo->nBackfill<mxSafeFrame
+ && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+ ){
+ i64 nSize; /* Current size of database file */
+ u32 nBackfill = pInfo->nBackfill;
- /* If the database may grow as a result of this checkpoint, hint
- ** about the eventual size of the db file to the VFS layer.
- */
- if( rc==SQLITE_OK ){
- i64 nReq = ((i64)mxPage * szPage);
- rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
- if( rc==SQLITE_OK && nSize<nReq ){
- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ /* Sync the WAL to disk */
+ if( sync_flags ){
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
}
- }
+ /* If the database may grow as a result of this checkpoint, hint
+ ** about the eventual size of the db file to the VFS layer.
+ */
+ if( rc==SQLITE_OK ){
+ i64 nReq = ((i64)mxPage * szPage);
+ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+ if( rc==SQLITE_OK && nSize<nReq ){
+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ }
+ }
- /* Iterate through the contents of the WAL, copying data to the db file. */
- while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
- i64 iOffset;
- assert( walFramePgno(pWal, iFrame)==iDbpage );
- if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
- iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
- /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
- rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
- if( rc!=SQLITE_OK ) break;
- iOffset = (iDbpage-1)*(i64)szPage;
- testcase( IS_BIG_INT(iOffset) );
- rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
- if( rc!=SQLITE_OK ) break;
- }
- /* If work was actually accomplished... */
- if( rc==SQLITE_OK ){
- if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
- i64 szDb = pWal->hdr.nPage*(i64)szPage;
- testcase( IS_BIG_INT(szDb) );
- rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
- if( rc==SQLITE_OK && sync_flags ){
- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ /* Iterate through the contents of the WAL, copying data to the db file */
+ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+ i64 iOffset;
+ assert( walFramePgno(pWal, iFrame)==iDbpage );
+ if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
+ continue;
}
+ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ iOffset = (iDbpage-1)*(i64)szPage;
+ testcase( IS_BIG_INT(iOffset) );
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
}
+
+ /* If work was actually accomplished... */
if( rc==SQLITE_OK ){
- pInfo->nBackfill = mxSafeFrame;
+ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+ i64 szDb = pWal->hdr.nPage*(i64)szPage;
+ testcase( IS_BIG_INT(szDb) );
+ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+ if( rc==SQLITE_OK && sync_flags ){
+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pInfo->nBackfill = mxSafeFrame;
+ }
}
- }
- /* Release the reader lock held while backfilling */
- walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
- }
+ /* Release the reader lock held while backfilling */
+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+ }
- if( rc==SQLITE_BUSY ){
- /* Reset the return code so as not to report a checkpoint failure
- ** just because there are active readers. */
- rc = SQLITE_OK;
+ if( rc==SQLITE_BUSY ){
+ /* Reset the return code so as not to report a checkpoint failure
+ ** just because there are active readers. */
+ rc = SQLITE_OK;
+ }
}
- /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
- ** file has been copied into the database file, then block until all
- ** readers have finished using the wal file. This ensures that the next
- ** process to write to the database restarts the wal file.
+ /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
+ ** entire wal file has been copied into the database file, then block
+ ** until all readers have finished using the wal file. This ensures that
+ ** the next process to write to the database restarts the wal file.
*/
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
assert( pWal->writeLock );
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
rc = SQLITE_BUSY;
- }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
- assert( mxSafeFrame==pWal->hdr.mxFrame );
+ }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
+ u32 salt1;
+ sqlite3_randomness(4, &salt1);
+ assert( pInfo->nBackfill==pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
if( rc==SQLITE_OK ){
+ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
+ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
+ ** SQLITE_CHECKPOINT_RESTART with the addition that it also
+ ** truncates the log file to zero bytes just prior to a
+ ** successful return.
+ **
+ ** In theory, it might be safe to do this without updating the
+ ** wal-index header in shared memory, as all subsequent reader or
+ ** writer clients should see that the entire log file has been
+ ** checkpointed and behave accordingly. This seems unsafe though,
+ ** as it would leave the system in a state where the contents of
+ ** the wal-index header do not match the contents of the
+ ** file-system. To avoid this, update the wal-index header to
+ ** indicate that the log file contains zero valid frames. */
+ walRestartHdr(pWal, salt1);
+ rc = sqlite3OsTruncate(pWal->pWalFd, 0);
+ }
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
}
}
@@ -50104,7 +50883,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
walUnlockShared(pWal, WAL_WRITE_LOCK);
rc = SQLITE_READONLY_RECOVERY;
}
- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
@@ -50310,7 +51089,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
&& (mxReadMark<pWal->hdr.mxFrame || mxI==0)
){
for(i=1; i<WAL_NREADER; i++){
- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
if( rc==SQLITE_OK ){
mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
mxI = i;
@@ -50476,7 +51255,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
u32 iFrame = aHash[iKey] + iZero;
if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
- /* assert( iFrame>iRead ); -- not true if there is corruption */
+ assert( iFrame>iRead || CORRUPT_DB );
iRead = iFrame;
}
if( (nCollide--)==0 ){
@@ -50566,7 +51345,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
/* Only one writer allowed at a time. Get the write lock. Return
** SQLITE_BUSY if unable.
*/
- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
if( rc ){
return rc;
}
@@ -50689,7 +51468,6 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
return rc;
}
-
/*
** This function is called just before writing a set of frames to the log
** file (see sqlite3WalFrames()). It checks to see if, instead of appending
@@ -50712,7 +51490,7 @@ static int walRestartLog(Wal *pWal){
if( pInfo->nBackfill>0 ){
u32 salt1;
sqlite3_randomness(4, &salt1);
- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
if( rc==SQLITE_OK ){
/* If all readers are using WAL_READ_LOCK(0) (in other words if no
** readers are currently using the WAL), then the transactions
@@ -50722,20 +51500,8 @@ static int walRestartLog(Wal *pWal){
** In theory it would be Ok to update the cache of the header only
** at this point. But updating the actual wal-index header is also
** safe and means there is no special case for sqlite3WalUndo()
- ** to handle if this transaction is rolled back.
- */
- int i; /* Loop counter */
- u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
-
- pWal->nCkpt++;
- pWal->hdr.mxFrame = 0;
- sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
- aSalt[1] = salt1;
- walIndexWriteHdr(pWal);
- pInfo->nBackfill = 0;
- pInfo->aReadMark[1] = 0;
- for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
- assert( pInfo->aReadMark[0]==0 );
+ ** to handle if this transaction is rolled back. */
+ walRestartHdr(pWal, salt1);
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
}else if( rc!=SQLITE_BUSY ){
return rc;
@@ -51023,7 +51789,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
*/
SQLITE_PRIVATE int sqlite3WalCheckpoint(
Wal *pWal, /* Wal connection */
- int eMode, /* PASSIVE, FULL or RESTART */
+ int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags to sync db file with (or 0) */
@@ -51035,29 +51801,42 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
int rc; /* Return code */
int isChanged = 0; /* True if a new wal-index header is loaded */
int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
+ int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */
assert( pWal->ckptLock==0 );
assert( pWal->writeLock==0 );
+ /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+ ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
+
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+
+ /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
+ ** "checkpoint" lock on the database file. */
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
if( rc ){
- /* Usually this is SQLITE_BUSY meaning that another thread or process
- ** is already running a checkpoint, or maybe a recovery. But it might
- ** also be SQLITE_IOERR. */
+ /* EVIDENCE-OF: R-10421-19736 If any other process is running a
+ ** checkpoint operation at the same time, the lock cannot be obtained and
+ ** SQLITE_BUSY is returned.
+ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
+ ** it will not be invoked in this case.
+ */
+ testcase( rc==SQLITE_BUSY );
+ testcase( xBusy!=0 );
return rc;
}
pWal->ckptLock = 1;
- /* If this is a blocking-checkpoint, then obtain the write-lock as well
- ** to prevent any writers from running while the checkpoint is underway.
- ** This has to be done before the call to walIndexReadHdr() below.
+ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
+ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
+ ** file.
**
- ** If the writer lock cannot be obtained, then a passive checkpoint is
- ** run instead. Since the checkpointer is not holding the writer lock,
- ** there is no point in blocking waiting for any readers. Assuming no
- ** other error occurs, this function will return SQLITE_BUSY to the caller.
+ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
+ ** immediately, and a busy-handler is configured, it is invoked and the
+ ** writer lock retried until either the busy-handler returns 0 or the
+ ** lock is successfully obtained.
*/
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
@@ -51065,6 +51844,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
pWal->writeLock = 1;
}else if( rc==SQLITE_BUSY ){
eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+ xBusy2 = 0;
rc = SQLITE_OK;
}
}
@@ -51082,7 +51862,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
rc = SQLITE_CORRUPT_BKPT;
}else{
- rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
+ rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
}
/* If no error occurred, set the output variables. */
@@ -51510,6 +52290,7 @@ struct MemPage {
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u8 max1bytePayload; /* min(maxLocal,127) */
+ u8 bBusy; /* Prevent endless loops on corrupt database files */
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
@@ -51581,6 +52362,7 @@ struct Btree {
u8 locked; /* True if db currently has pBt locked */
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
int nBackup; /* Number of backup operations reading this btree */
+ u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
Btree *pNext; /* List of other sharable Btrees from the same db */
Btree *pPrev; /* Back pointer of the same list */
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -51647,6 +52429,9 @@ struct BtShared {
#endif
u8 inTransaction; /* Transaction state */
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
+#ifdef SQLITE_HAS_CODEC
+ u8 optimalReserve; /* Desired amount of reserved space per page */
+#endif
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
@@ -52033,6 +52818,7 @@ static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){
** Exit the recursive mutex on a Btree.
*/
SQLITE_PRIVATE void sqlite3BtreeLeave(Btree *p){
+ assert( sqlite3_mutex_held(p->db->mutex) );
if( p->sharable ){
assert( p->wantToLock>0 );
p->wantToLock--;
@@ -52280,7 +53066,7 @@ static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
** The shared cache setting effects only future calls to
** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
-SQLITE_API int sqlite3_enable_shared_cache(int enable){
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){
sqlite3GlobalConfig.sharedCacheEnabled = enable;
return SQLITE_OK;
}
@@ -52369,6 +53155,12 @@ static int hasSharedCacheTableLock(
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
Index *pIdx = (Index *)sqliteHashData(p);
if( pIdx->tnum==(int)iRoot ){
+ if( iTab ){
+ /* Two or more indexes share the same root page. There must
+ ** be imposter tables. So just return true. The assert is not
+ ** useful in that case. */
+ return 1;
+ }
iTab = pIdx->pTable->tnum;
}
}
@@ -52788,10 +53580,15 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
static int saveCursorPosition(BtCursor *pCur){
int rc;
- assert( CURSOR_VALID==pCur->eState );
+ assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
+ if( pCur->eState==CURSOR_SKIPNEXT ){
+ pCur->eState = CURSOR_VALID;
+ }else{
+ pCur->skipNext = 0;
+ }
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
@@ -52862,7 +53659,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
){
do{
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
- if( p->eState==CURSOR_VALID ){
+ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
@@ -52934,17 +53731,19 @@ static int btreeMoveto(
*/
static int btreeRestoreCursorPosition(BtCursor *pCur){
int rc;
+ int skipNext;
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skipNext;
}
pCur->eState = CURSOR_INVALID;
- rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skipNext);
+ rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
+ pCur->skipNext |= skipNext;
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
pCur->eState = CURSOR_SKIPNEXT;
}
@@ -52996,9 +53795,10 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
*pDifferentRow = 1;
return rc;
}
- if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
+ if( pCur->eState!=CURSOR_VALID ){
*pDifferentRow = 1;
}else{
+ assert( pCur->skipNext==0 );
*pDifferentRow = 0;
}
return SQLITE_OK;
@@ -53333,6 +54133,11 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
** end of the page and all free space is collected into one
** big FreeBlk that occurs in between the header and cell
** pointer array and the cell content area.
+**
+** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a
+** b-tree page so that there are no freeblocks or fragment bytes, all
+** unused bytes are contained in the unallocated space region, and all
+** cells are packed tightly at the end of the page.
*/
static int defragmentPage(MemPage *pPage){
int i; /* Loop counter */
@@ -53345,6 +54150,7 @@ static int defragmentPage(MemPage *pPage){
int nCell; /* Number of cells on the page */
unsigned char *data; /* The page data */
unsigned char *temp; /* Temp area for cell content */
+ unsigned char *src; /* Source of content */
int iCellFirst; /* First allowable cell index */
int iCellLast; /* Last possible cell index */
@@ -53354,15 +54160,13 @@ static int defragmentPage(MemPage *pPage){
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
- data = pPage->aData;
+ temp = 0;
+ src = data = pPage->aData;
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
nCell = pPage->nCell;
assert( nCell==get2byte(&data[hdr+3]) );
usableSize = pPage->pBt->usableSize;
- cbrk = get2byte(&data[hdr+5]);
- memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk);
cbrk = usableSize;
iCellFirst = cellOffset + 2*nCell;
iCellLast = usableSize - 4;
@@ -53381,7 +54185,7 @@ static int defragmentPage(MemPage *pPage){
}
#endif
assert( pc>=iCellFirst && pc<=iCellLast );
- size = cellSizePtr(pPage, &temp[pc]);
+ size = cellSizePtr(pPage, &src[pc]);
cbrk -= size;
#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
if( cbrk<iCellFirst ){
@@ -53395,8 +54199,16 @@ static int defragmentPage(MemPage *pPage){
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
testcase( cbrk+size==usableSize );
testcase( pc+size==usableSize );
- memcpy(&data[cbrk], &temp[pc], size);
put2byte(pAddr, cbrk);
+ if( temp==0 ){
+ int x;
+ if( cbrk==pc ) continue;
+ temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
+ x = get2byte(&data[hdr+5]);
+ memcpy(&temp[x], &data[x], (cbrk+size) - x);
+ src = temp;
+ }
+ memcpy(&data[cbrk], &src[pc], size);
}
assert( cbrk>=iCellFirst );
put2byte(&data[hdr+5], cbrk);
@@ -53412,6 +54224,69 @@ static int defragmentPage(MemPage *pPage){
}
/*
+** Search the free-list on page pPg for space to store a cell nByte bytes in
+** size. If one can be found, return a pointer to the space and remove it
+** from the free-list.
+**
+** If no suitable space can be found on the free-list, return NULL.
+**
+** This function may detect corruption within pPg. If corruption is
+** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned.
+**
+** If a slot of at least nByte bytes is found but cannot be used because
+** there are already at least 60 fragmented bytes on the page, return NULL.
+** In this case, if pbDefrag parameter is not NULL, set *pbDefrag to true.
+*/
+static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){
+ const int hdr = pPg->hdrOffset;
+ u8 * const aData = pPg->aData;
+ int iAddr;
+ int pc;
+ int usableSize = pPg->pBt->usableSize;
+
+ for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
+ int size; /* Size of the free slot */
+ /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
+ ** increasing offset. */
+ if( pc>usableSize-4 || pc<iAddr+4 ){
+ *pRc = SQLITE_CORRUPT_BKPT;
+ return 0;
+ }
+ /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
+ ** freeblock form a big-endian integer which is the size of the freeblock
+ ** in bytes, including the 4-byte header. */
+ size = get2byte(&aData[pc+2]);
+ if( size>=nByte ){
+ int x = size - nByte;
+ testcase( x==4 );
+ testcase( x==3 );
+ if( x<4 ){
+ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
+ ** number of bytes in fragments may not exceed 60. */
+ if( aData[hdr+7]>=60 ){
+ if( pbDefrag ) *pbDefrag = 1;
+ return 0;
+ }
+ /* Remove the slot from the free-list. Update the number of
+ ** fragmented bytes within the page. */
+ memcpy(&aData[iAddr], &aData[pc], 2);
+ aData[hdr+7] += (u8)x;
+ }else if( size+pc > usableSize ){
+ *pRc = SQLITE_CORRUPT_BKPT;
+ return 0;
+ }else{
+ /* The slot remains on the free-list. Reduce its size to account
+ ** for the portion used by the new allocation. */
+ put2byte(&aData[pc+2], x);
+ }
+ return &aData[pc + x];
+ }
+ }
+
+ return 0;
+}
+
+/*
** Allocate nByte bytes of space from within the B-Tree page passed
** as the first argument. Write into *pIdx the index into pPage->aData[]
** of the first byte of allocated space. Return either SQLITE_OK or
@@ -53428,9 +54303,8 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
int top; /* First byte of cell content area */
+ int rc = SQLITE_OK; /* Integer return code */
int gap; /* First byte of gap between cell pointers and cell content */
- int rc; /* Integer return code */
- int usableSize; /* Usable size of the page */
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt );
@@ -53438,20 +54312,18 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
assert( nByte>=0 ); /* Minimum cell size is 4 */
assert( pPage->nFree>=nByte );
assert( pPage->nOverflow==0 );
- usableSize = pPage->pBt->usableSize;
- assert( nByte < usableSize-8 );
+ assert( nByte < (int)(pPage->pBt->usableSize-8) );
assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf );
gap = pPage->cellOffset + 2*pPage->nCell;
assert( gap<=65536 );
- top = get2byte(&data[hdr+5]);
- if( gap>top ){
- if( top==0 ){
- top = 65536;
- }else{
- return SQLITE_CORRUPT_BKPT;
- }
- }
+ /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size
+ ** and the reserved space is zero (the usual value for reserved space)
+ ** then the cell content offset of an empty page wants to be 65536.
+ ** However, that integer is too large to be stored in a 2-byte unsigned
+ ** integer, so a value of 0 is used in its place. */
+ top = get2byteNotZero(&data[hdr+5]);
+ if( gap>top ) return SQLITE_CORRUPT_BKPT;
/* If there is enough space between gap and top for one more cell pointer
** array entry offset, and if the freelist is not empty, then search the
@@ -53461,33 +54333,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
testcase( gap+1==top );
testcase( gap==top );
if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){
- int pc, addr;
- for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){
- int size; /* Size of the free slot */
- if( pc>usableSize-4 || pc<addr+4 ){
- return SQLITE_CORRUPT_BKPT;
- }
- size = get2byte(&data[pc+2]);
- if( size>=nByte ){
- int x = size - nByte;
- testcase( x==4 );
- testcase( x==3 );
- if( x<4 ){
- if( data[hdr+7]>=60 ) goto defragment_page;
- /* Remove the slot from the free-list. Update the number of
- ** fragmented bytes within the page. */
- memcpy(&data[addr], &data[pc], 2);
- data[hdr+7] += (u8)x;
- }else if( size+pc > usableSize ){
- return SQLITE_CORRUPT_BKPT;
- }else{
- /* The slot remains on the free-list. Reduce its size to account
- ** for the portion used by the new allocation. */
- put2byte(&data[pc+2], x);
- }
- *pIdx = pc + x;
- return SQLITE_OK;
- }
+ int bDefrag = 0;
+ u8 *pSpace = pageFindSlot(pPage, nByte, &rc, &bDefrag);
+ if( rc ) return rc;
+ if( bDefrag ) goto defragment_page;
+ if( pSpace ){
+ assert( pSpace>=data && (pSpace - data)<65536 );
+ *pIdx = (int)(pSpace - data);
+ return SQLITE_OK;
}
}
@@ -53496,8 +54349,8 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
*/
testcase( gap+2+nByte==top );
if( gap+2+nByte>top ){
-defragment_page:
- testcase( pPage->nCell==0 );
+ defragment_page:
+ assert( pPage->nCell>0 || CORRUPT_DB );
rc = defragmentPage(pPage);
if( rc ) return rc;
top = get2byteNotZero(&data[hdr+5]);
@@ -53544,7 +54397,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( pPage->pBt!=0 );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( iStart>=pPage->hdrOffset+6+pPage->childPtrSize );
- assert( iEnd <= pPage->pBt->usableSize );
+ assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
assert( iStart<=iLast );
@@ -53639,18 +54492,32 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->childPtrSize = 4-4*pPage->leaf;
pBt = pPage->pBt;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
+ /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
+ ** table b-tree page. */
+ assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
+ /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
+ ** table b-tree page. */
+ assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1;
pPage->intKeyLeaf = pPage->leaf;
pPage->noPayload = !pPage->leaf;
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else if( flagByte==PTF_ZERODATA ){
+ /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
+ ** index b-tree page. */
+ assert( (PTF_ZERODATA)==2 );
+ /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
+ ** index b-tree page. */
+ assert( (PTF_ZERODATA|PTF_LEAF)==10 );
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
pPage->noPayload = 0;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
+ /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
+ ** an error. */
return SQLITE_CORRUPT_BKPT;
}
pPage->max1bytePayload = pBt->max1bytePayload;
@@ -53690,21 +54557,33 @@ static int btreeInitPage(MemPage *pPage){
hdr = pPage->hdrOffset;
data = pPage->aData;
+ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
+ ** the b-tree page type. */
if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nOverflow = 0;
usableSize = pBt->usableSize;
- pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
+ pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
pPage->aDataEnd = &data[usableSize];
pPage->aCellIdx = &data[cellOffset];
+ /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
+ ** the start of the cell content area. A zero value for this integer is
+ ** interpreted as 65536. */
top = get2byteNotZero(&data[hdr+5]);
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
pPage->nCell = get2byte(&data[hdr+3]);
if( pPage->nCell>MX_CELL(pBt) ){
/* To many cells for a single page. The page must be corrupt */
return SQLITE_CORRUPT_BKPT;
}
testcase( pPage->nCell==MX_CELL(pBt) );
+ /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
+ ** possible for a root page of a table that contains no rows) then the
+ ** offset to the cell content area will equal the page size minus the
+ ** bytes of reserved space. */
+ assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
/* A malformed database page might cause us to read past the end
** of page when parsing a cell.
@@ -53738,13 +54617,20 @@ static int btreeInitPage(MemPage *pPage){
}
#endif
- /* Compute the total free space on the page */
+ /* Compute the total free space on the page
+ ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
+ ** start of the first freeblock on the page, or is zero if there are no
+ ** freeblocks. */
pc = get2byte(&data[hdr+1]);
- nFree = data[hdr+7] + top;
+ nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
while( pc>0 ){
u16 next, size;
if( pc<iCellFirst || pc>iCellLast ){
- /* Start of free block is off the page */
+ /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
+ ** always be at least one cell before the first freeblock.
+ **
+ ** Or, the freeblock is off the end of the page
+ */
return SQLITE_CORRUPT_BKPT;
}
next = get2byte(&data[pc]);
@@ -54053,16 +54939,18 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
*/
if( isTempDb==0 && (isMemdb==0 || (vfsFlags&SQLITE_OPEN_URI)!=0) ){
if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){
+ int nFilename = sqlite3Strlen30(zFilename)+1;
int nFullPathname = pVfs->mxPathname+1;
- char *zFullPathname = sqlite3Malloc(nFullPathname);
+ char *zFullPathname = sqlite3Malloc(MAX(nFullPathname,nFilename));
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
+
p->sharable = 1;
if( !zFullPathname ){
sqlite3_free(p);
return SQLITE_NOMEM;
}
if( isMemdb ){
- memcpy(zFullPathname, zFilename, sqlite3Strlen30(zFilename)+1);
+ memcpy(zFullPathname, zFilename, nFilename);
}else{
rc = sqlite3OsFullPathname(pVfs, zFilename,
nFullPathname, zFullPathname);
@@ -54119,8 +55007,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
** the right size. This is to guard against size changes that result
** when compiling on a different architecture.
*/
- assert( sizeof(i64)==8 || sizeof(i64)==4 );
- assert( sizeof(u64)==8 || sizeof(u64)==4 );
+ assert( sizeof(i64)==8 );
+ assert( sizeof(u64)==8 );
assert( sizeof(u32)==4 );
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
@@ -54150,6 +55038,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
#ifdef SQLITE_SECURE_DELETE
pBt->btsFlags |= BTS_SECURE_DELETE;
#endif
+ /* EVIDENCE-OF: R-51873-39618 The page size for a database file is
+ ** determined by the 2-byte integer located at an offset of 16 bytes from
+ ** the beginning of the database file. */
pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
@@ -54168,6 +55059,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
#endif
nReserve = 0;
}else{
+ /* EVIDENCE-OF: R-37497-42412 The size of the reserved region is
+ ** determined by the one-byte unsigned integer found at an offset of 20
+ ** into the database file header. */
nReserve = zDbHeader[20];
pBt->btsFlags |= BTS_PAGESIZE_FIXED;
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -54501,6 +55395,9 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve,
BtShared *pBt = p->pBt;
assert( nReserve>=-1 && nReserve<=255 );
sqlite3BtreeEnter(p);
+#if SQLITE_HAS_CODEC
+ if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
+#endif
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p);
return SQLITE_READONLY;
@@ -54530,7 +55427,6 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){
return p->pBt->pageSize;
}
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
/*
** This function is similar to sqlite3BtreeGetReserve(), except that it
** may only be called if it is guaranteed that the b-tree mutex is already
@@ -54543,25 +55439,33 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){
** database handle that owns *p, causing undefined behavior.
*/
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){
+ int n;
assert( sqlite3_mutex_held(p->pBt->mutex) );
- return p->pBt->pageSize - p->pBt->usableSize;
+ n = p->pBt->pageSize - p->pBt->usableSize;
+ return n;
}
-#endif /* SQLITE_HAS_CODEC || SQLITE_DEBUG */
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
/*
** Return the number of bytes of space at the end of every page that
** are intentually left unused. This is the "reserved" space that is
** sometimes used by extensions.
+**
+** If SQLITE_HAS_MUTEX is defined then the number returned is the
+** greater of the current reserved space and the maximum requested
+** reserve space.
*/
-SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree *p){
+SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){
int n;
sqlite3BtreeEnter(p);
- n = p->pBt->pageSize - p->pBt->usableSize;
+ n = sqlite3BtreeGetReserveNoMutex(p);
+#ifdef SQLITE_HAS_CODEC
+ if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
+#endif
sqlite3BtreeLeave(p);
return n;
}
+
/*
** Set the maximum page count for a database if mxPage is positive.
** No changes are made if mxPage is 0 or negative.
@@ -54592,7 +55496,6 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
sqlite3BtreeLeave(p);
return b;
}
-#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
/*
** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
@@ -54677,6 +55580,9 @@ static int lockBtree(BtShared *pBt){
u32 usableSize;
u8 *page1 = pPage1->aData;
rc = SQLITE_NOTADB;
+ /* EVIDENCE-OF: R-43737-39999 Every valid SQLite database file begins
+ ** with the following 16 bytes (in hex): 53 51 4c 69 74 65 20 66 6f 72 6d
+ ** 61 74 20 33 00. */
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
}
@@ -54717,15 +55623,21 @@ static int lockBtree(BtShared *pBt){
}
#endif
- /* The maximum embedded fraction must be exactly 25%. And the minimum
- ** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
+ /* EVIDENCE-OF: R-15465-20813 The maximum and minimum embedded payload
+ ** fractions and the leaf payload fraction values must be 64, 32, and 32.
+ **
** The original design allowed these amounts to vary, but as of
** version 3.6.0, we require them to be fixed.
*/
if( memcmp(&page1[21], "\100\040\040",3)!=0 ){
goto page1_init_failed;
}
+ /* EVIDENCE-OF: R-51873-39618 The page size for a database file is
+ ** determined by the 2-byte integer located at an offset of 16 bytes from
+ ** the beginning of the database file. */
pageSize = (page1[16]<<8) | (page1[17]<<16);
+ /* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two
+ ** between 512 and 65536 inclusive. */
if( ((pageSize-1)&pageSize)!=0
|| pageSize>SQLITE_MAX_PAGE_SIZE
|| pageSize<=256
@@ -54733,6 +55645,13 @@ static int lockBtree(BtShared *pBt){
goto page1_init_failed;
}
assert( (pageSize & 7)==0 );
+ /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
+ ** integer at offset 20 is the number of bytes of space at the end of
+ ** each page to reserve for extensions.
+ **
+ ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is
+ ** determined by the one-byte unsigned integer found at an offset of 20
+ ** into the database file header. */
usableSize = pageSize - page1[20];
if( (u32)pageSize!=pBt->pageSize ){
/* After reading the first page of the database assuming a page size
@@ -54753,6 +55672,9 @@ static int lockBtree(BtShared *pBt){
rc = SQLITE_CORRUPT_BKPT;
goto page1_init_failed;
}
+ /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to
+ ** be less than 480. In other words, if the page size is 512, then the
+ ** reserved space size cannot exceed 32. */
if( usableSize<480 ){
goto page1_init_failed;
}
@@ -55633,6 +56555,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
sqlite3BtreeLeave(p);
return rc;
}
+ p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */
pBt->inTransaction = TRANS_READ;
btreeClearHasContent(pBt);
}
@@ -55692,7 +56615,7 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
- if( p->eState==CURSOR_VALID ){
+ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
rc = saveCursorPosition(p);
if( rc!=SQLITE_OK ){
(void)sqlite3BtreeTripAllCursors(pBtree, rc, 0);
@@ -55996,7 +56919,7 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
releasePage(pCur->apPage[i]);
}
unlockBtreeIfUnused(pBt);
- sqlite3DbFree(pBtree->db, pCur->aOverflow);
+ sqlite3_free(pCur->aOverflow);
/* sqlite3_free(pCur); */
sqlite3BtreeLeave(pBtree);
}
@@ -56098,6 +57021,8 @@ SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->iPage>=0 );
+ assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
getCellInfo(pCur);
*pSize = pCur->info.nPayload;
@@ -56291,6 +57216,7 @@ static int accessPayload(
offset -= pCur->info.nLocal;
}
+
if( rc==SQLITE_OK && amt>0 ){
const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
Pgno nextPage;
@@ -56308,8 +57234,8 @@ static int accessPayload(
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
if( nOvfl>pCur->nOvflAlloc ){
- Pgno *aNew = (Pgno*)sqlite3DbRealloc(
- pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
+ Pgno *aNew = (Pgno*)sqlite3Realloc(
+ pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
rc = SQLITE_NOMEM;
@@ -56356,6 +57282,7 @@ static int accessPayload(
*/
assert( eOp!=2 );
assert( pCur->curFlags & BTCF_ValidOvfl );
+ assert( pCur->pBtree->db==pBt->db );
if( pCur->aOverflow[iIdx+1] ){
nextPage = pCur->aOverflow[iIdx+1];
}else{
@@ -56574,7 +57501,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
return SQLITE_OK;
}
-#if 0
+#if SQLITE_DEBUG
/*
** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
@@ -56583,6 +57510,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
** the page.
*/
static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
+ if( CORRUPT_DB ) return; /* The conditions tested below might not be true
+ ** in a corrupt database */
assert( iIdx<=pParent->nCell );
if( iIdx==pParent->nCell ){
assert( get4byte(&pParent->aData[pParent->hdrOffset+8])==iChild );
@@ -56607,19 +57536,11 @@ static void moveToParent(BtCursor *pCur){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
-
- /* UPDATE: It is actually possible for the condition tested by the assert
- ** below to be untrue if the database file is corrupt. This can occur if
- ** one cursor has modified page pParent while a reference to it is held
- ** by a second cursor. Which can only happen if a single page is linked
- ** into more than one b-tree structure in a corrupt database. */
-#if 0
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
);
-#endif
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
releasePage(pCur->apPage[pCur->iPage]);
@@ -57330,6 +58251,8 @@ static int allocateBtreePage(
assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
pPage1 = pBt->pPage1;
mxPage = btreePagecount(pBt);
+ /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
+ ** stores stores the total number of pages on the freelist. */
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -57376,8 +58299,14 @@ static int allocateBtreePage(
do {
pPrevTrunk = pTrunk;
if( pPrevTrunk ){
+ /* EVIDENCE-OF: R-01506-11053 The first integer on a freelist trunk page
+ ** is the page number of the next freelist trunk page in the list or
+ ** zero if this is the last freelist trunk page. */
iTrunk = get4byte(&pPrevTrunk->aData[0]);
}else{
+ /* EVIDENCE-OF: R-59841-13798 The 4-byte big-endian integer at offset 32
+ ** stores the page number of the first page of the freelist, or zero if
+ ** the freelist is empty. */
iTrunk = get4byte(&pPage1->aData[32]);
}
testcase( iTrunk==mxPage );
@@ -57392,8 +58321,9 @@ static int allocateBtreePage(
}
assert( pTrunk!=0 );
assert( pTrunk->aData!=0 );
-
- k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */
+ /* EVIDENCE-OF: R-13523-04394 The second integer on a freelist trunk page
+ ** is the number of leaf page pointers to follow. */
+ k = get4byte(&pTrunk->aData[4]);
if( k==0 && !searchList ){
/* The trunk has no leaves and the list is not being searched.
** So extract the trunk page itself and use it as the newly
@@ -57711,6 +58641,11 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
** for now. At some point in the future (once everyone has upgraded
** to 3.6.0 or later) we should consider fixing the conditional above
** to read "usableSize/4-2" instead of "usableSize/4-8".
+ **
+ ** EVIDENCE-OF: R-19920-11576 However, newer versions of SQLite still
+ ** avoid using the last six entries in the freelist trunk page array in
+ ** order that database files created by newer versions of SQLite can be
+ ** read by older versions of SQLite.
*/
rc = sqlite3PagerWrite(pTrunk->pDbPage);
if( rc==SQLITE_OK ){
@@ -58062,9 +58997,17 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
return;
}
pPage->nCell--;
- memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
- put2byte(&data[hdr+3], pPage->nCell);
- pPage->nFree += 2;
+ if( pPage->nCell==0 ){
+ memset(&data[hdr+1], 0, 4);
+ data[hdr+7] = 0;
+ put2byte(&data[hdr+5], pPage->pBt->usableSize);
+ pPage->nFree = pPage->pBt->usableSize - pPage->hdrOffset
+ - pPage->childPtrSize - 8;
+ }else{
+ memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
+ put2byte(&data[hdr+3], pPage->nCell);
+ pPage->nFree += 2;
+ }
}
/*
@@ -58159,45 +59102,271 @@ static void insertCell(
}
/*
-** Add a list of cells to a page. The page should be initially empty.
-** The cells are guaranteed to fit on the page.
+** Array apCell[] contains pointers to nCell b-tree page cells. The
+** szCell[] array contains the size in bytes of each cell. This function
+** replaces the current contents of page pPg with the contents of the cell
+** array.
+**
+** Some of the cells in apCell[] may currently be stored in pPg. This
+** function works around problems caused by this by making a copy of any
+** such cells before overwriting the page data.
+**
+** The MemPage.nFree field is invalidated by this function. It is the
+** responsibility of the caller to set it correctly.
*/
-static void assemblePage(
- MemPage *pPage, /* The page to be assembled */
- int nCell, /* The number of cells to add to this page */
- u8 **apCell, /* Pointers to cell bodies */
- u16 *aSize /* Sizes of the cells */
+static void rebuildPage(
+ MemPage *pPg, /* Edit this page */
+ int nCell, /* Final number of cells on page */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
){
- int i; /* Loop counter */
- u8 *pCellptr; /* Address of next cell pointer */
- int cellbody; /* Address of next cell body */
- u8 * const data = pPage->aData; /* Pointer to data for pPage */
- const int hdr = pPage->hdrOffset; /* Offset of header on pPage */
- const int nUsable = pPage->pBt->usableSize; /* Usable size of page */
+ const int hdr = pPg->hdrOffset; /* Offset of header on pPg */
+ u8 * const aData = pPg->aData; /* Pointer to data for pPg */
+ const int usableSize = pPg->pBt->usableSize;
+ u8 * const pEnd = &aData[usableSize];
+ int i;
+ u8 *pCellptr = pPg->aCellIdx;
+ u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
+ u8 *pData;
- assert( pPage->nOverflow==0 );
- assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- assert( nCell>=0 && nCell<=(int)MX_CELL(pPage->pBt)
- && (int)MX_CELL(pPage->pBt)<=10921);
- assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+ i = get2byte(&aData[hdr+5]);
+ memcpy(&pTmp[i], &aData[i], usableSize - i);
+
+ pData = pEnd;
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
+ if( pCell>aData && pCell<pEnd ){
+ pCell = &pTmp[pCell - aData];
+ }
+ pData -= szCell[i];
+ memcpy(pData, pCell, szCell[i]);
+ put2byte(pCellptr, (pData - aData));
+ pCellptr += 2;
+ assert( szCell[i]==cellSizePtr(pPg, pCell) );
+ }
- /* Check that the page has just been zeroed by zeroPage() */
- assert( pPage->nCell==0 );
- assert( get2byteNotZero(&data[hdr+5])==nUsable );
+ /* The pPg->nFree field is now set incorrectly. The caller will fix it. */
+ pPg->nCell = nCell;
+ pPg->nOverflow = 0;
- pCellptr = &pPage->aCellIdx[nCell*2];
- cellbody = nUsable;
- for(i=nCell-1; i>=0; i--){
- u16 sz = aSize[i];
- pCellptr -= 2;
- cellbody -= sz;
- put2byte(pCellptr, cellbody);
- memcpy(&data[cellbody], apCell[i], sz);
+ put2byte(&aData[hdr+1], 0);
+ put2byte(&aData[hdr+3], pPg->nCell);
+ put2byte(&aData[hdr+5], pData - aData);
+ aData[hdr+7] = 0x00;
+}
+
+/*
+** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
+** contains the size in bytes of each such cell. This function attempts to
+** add the cells stored in the array to page pPg. If it cannot (because
+** the page needs to be defragmented before the cells will fit), non-zero
+** is returned. Otherwise, if the cells are added successfully, zero is
+** returned.
+**
+** Argument pCellptr points to the first entry in the cell-pointer array
+** (part of page pPg) to populate. After cell apCell[0] is written to the
+** page body, a 16-bit offset is written to pCellptr. And so on, for each
+** cell in the array. It is the responsibility of the caller to ensure
+** that it is safe to overwrite this part of the cell-pointer array.
+**
+** When this function is called, *ppData points to the start of the
+** content area on page pPg. If the size of the content area is extended,
+** *ppData is updated to point to the new start of the content area
+** before returning.
+**
+** Finally, argument pBegin points to the byte immediately following the
+** end of the space required by this page for the cell-pointer area (for
+** all cells - not just those inserted by the current call). If the content
+** area must be extended to before this point in order to accomodate all
+** cells in apCell[], then the cells do not fit and non-zero is returned.
+*/
+static int pageInsertArray(
+ MemPage *pPg, /* Page to add cells to */
+ u8 *pBegin, /* End of cell-pointer array */
+ u8 **ppData, /* IN/OUT: Page content -area pointer */
+ u8 *pCellptr, /* Pointer to cell-pointer area */
+ int nCell, /* Number of cells to add to pPg */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
+){
+ int i;
+ u8 *aData = pPg->aData;
+ u8 *pData = *ppData;
+ const int bFreelist = aData[1] || aData[2];
+ assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
+ for(i=0; i<nCell; i++){
+ int sz = szCell[i];
+ int rc;
+ u8 *pSlot;
+ if( bFreelist==0 || (pSlot = pageFindSlot(pPg, sz, &rc, 0))==0 ){
+ pData -= sz;
+ if( pData<pBegin ) return 1;
+ pSlot = pData;
+ }
+ memcpy(pSlot, apCell[i], sz);
+ put2byte(pCellptr, (pSlot - aData));
+ pCellptr += 2;
}
- put2byte(&data[hdr+3], nCell);
- put2byte(&data[hdr+5], cellbody);
- pPage->nFree -= (nCell*2 + nUsable - cellbody);
- pPage->nCell = (u16)nCell;
+ *ppData = pData;
+ return 0;
+}
+
+/*
+** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
+** contains the size in bytes of each such cell. This function adds the
+** space associated with each cell in the array that is currently stored
+** within the body of pPg to the pPg free-list. The cell-pointers and other
+** fields of the page are not updated.
+**
+** This function returns the total number of cells added to the free-list.
+*/
+static int pageFreeArray(
+ MemPage *pPg, /* Page to edit */
+ int nCell, /* Cells to delete */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
+){
+ u8 * const aData = pPg->aData;
+ u8 * const pEnd = &aData[pPg->pBt->usableSize];
+ u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
+ int nRet = 0;
+ int i;
+ u8 *pFree = 0;
+ int szFree = 0;
+
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
+ if( pCell>=pStart && pCell<pEnd ){
+ int sz = szCell[i];
+ if( pFree!=(pCell + sz) ){
+ if( pFree ){
+ assert( pFree>aData && (pFree - aData)<65536 );
+ freeSpace(pPg, (u16)(pFree - aData), szFree);
+ }
+ pFree = pCell;
+ szFree = sz;
+ if( pFree+sz>pEnd ) return 0;
+ }else{
+ pFree = pCell;
+ szFree += sz;
+ }
+ nRet++;
+ }
+ }
+ if( pFree ){
+ assert( pFree>aData && (pFree - aData)<65536 );
+ freeSpace(pPg, (u16)(pFree - aData), szFree);
+ }
+ return nRet;
+}
+
+/*
+** apCell[] and szCell[] contains pointers to and sizes of all cells in the
+** pages being balanced. The current page, pPg, has pPg->nCell cells starting
+** with apCell[iOld]. After balancing, this page should hold nNew cells
+** starting at apCell[iNew].
+**
+** This routine makes the necessary adjustments to pPg so that it contains
+** the correct cells after being balanced.
+**
+** The pPg->nFree field is invalid when this function returns. It is the
+** responsibility of the caller to set it correctly.
+*/
+static void editPage(
+ MemPage *pPg, /* Edit this page */
+ int iOld, /* Index of first cell currently on page */
+ int iNew, /* Index of new first cell on page */
+ int nNew, /* Final number of cells on page */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
+){
+ u8 * const aData = pPg->aData;
+ const int hdr = pPg->hdrOffset;
+ u8 *pBegin = &pPg->aCellIdx[nNew * 2];
+ int nCell = pPg->nCell; /* Cells stored on pPg */
+ u8 *pData;
+ u8 *pCellptr;
+ int i;
+ int iOldEnd = iOld + pPg->nCell + pPg->nOverflow;
+ int iNewEnd = iNew + nNew;
+
+#ifdef SQLITE_DEBUG
+ u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
+ memcpy(pTmp, aData, pPg->pBt->usableSize);
+#endif
+
+ /* Remove cells from the start and end of the page */
+ if( iOld<iNew ){
+ int nShift = pageFreeArray(
+ pPg, iNew-iOld, &apCell[iOld], &szCell[iOld]
+ );
+ memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
+ nCell -= nShift;
+ }
+ if( iNewEnd < iOldEnd ){
+ nCell -= pageFreeArray(
+ pPg, iOldEnd-iNewEnd, &apCell[iNewEnd], &szCell[iNewEnd]
+ );
+ }
+
+ pData = &aData[get2byteNotZero(&aData[hdr+5])];
+ if( pData<pBegin ) goto editpage_fail;
+
+ /* Add cells to the start of the page */
+ if( iNew<iOld ){
+ int nAdd = MIN(nNew,iOld-iNew);
+ assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB );
+ pCellptr = pPg->aCellIdx;
+ memmove(&pCellptr[nAdd*2], pCellptr, nCell*2);
+ if( pageInsertArray(
+ pPg, pBegin, &pData, pCellptr,
+ nAdd, &apCell[iNew], &szCell[iNew]
+ ) ) goto editpage_fail;
+ nCell += nAdd;
+ }
+
+ /* Add any overflow cells */
+ for(i=0; i<pPg->nOverflow; i++){
+ int iCell = (iOld + pPg->aiOvfl[i]) - iNew;
+ if( iCell>=0 && iCell<nNew ){
+ pCellptr = &pPg->aCellIdx[iCell * 2];
+ memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
+ nCell++;
+ if( pageInsertArray(
+ pPg, pBegin, &pData, pCellptr,
+ 1, &apCell[iCell + iNew], &szCell[iCell + iNew]
+ ) ) goto editpage_fail;
+ }
+ }
+
+ /* Append cells to the end of the page */
+ pCellptr = &pPg->aCellIdx[nCell*2];
+ if( pageInsertArray(
+ pPg, pBegin, &pData, pCellptr,
+ nNew-nCell, &apCell[iNew+nCell], &szCell[iNew+nCell]
+ ) ) goto editpage_fail;
+
+ pPg->nCell = nNew;
+ pPg->nOverflow = 0;
+
+ put2byte(&aData[hdr+3], pPg->nCell);
+ put2byte(&aData[hdr+5], pData - aData);
+
+#ifdef SQLITE_DEBUG
+ for(i=0; i<nNew && !CORRUPT_DB; i++){
+ u8 *pCell = apCell[i+iNew];
+ int iOff = get2byte(&pPg->aCellIdx[i*2]);
+ if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
+ pCell = &pTmp[pCell - aData];
+ }
+ assert( 0==memcmp(pCell, &aData[iOff], szCell[i+iNew]) );
+ }
+#endif
+
+ return;
+ editpage_fail:
+ /* Unable to edit this page. Rebuild it from scratch instead. */
+ rebuildPage(pPg, nNew, &apCell[iNew], &szCell[iNew]);
}
/*
@@ -58251,7 +59420,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( pPage->nOverflow==1 );
/* This error condition is now caught prior to reaching this function */
- if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT;
+ if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT;
/* Allocate a new page. This page will become the right-sibling of
** pPage. Make the parent page writable, so that the new divider cell
@@ -58269,7 +59438,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
- assemblePage(pNew, 1, &pCell, &szCell);
+ rebuildPage(pNew, 1, &pCell, &szCell);
+ pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
/* If this is an auto-vacuum database, update the pointer map
** with entries for the new page, and any pointer from the
@@ -58488,17 +59658,22 @@ static int balance_nonroot(
int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */
int szScratch; /* Size of scratch memory requested */
MemPage *apOld[NB]; /* pPage and up to two siblings */
- MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */
u8 *pRight; /* Location in parent of right-sibling pointer */
u8 *apDiv[NB-1]; /* Divider cells in pParent */
int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */
- int szNew[NB+2]; /* Combined size of cells place on i-th page */
+ int cntOld[NB+2]; /* Old index in aCell[] after i-th page */
+ int szNew[NB+2]; /* Combined size of cells placed on i-th page */
u8 **apCell = 0; /* All cells begin balanced */
u16 *szCell; /* Local size of all cells in apCell[] */
u8 *aSpace1; /* Space for copies of dividers cells */
Pgno pgno; /* Temp var to store a page number in */
+ u8 abDone[NB+2]; /* True after i'th new page is populated */
+ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
+ Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
+ u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
+ memset(abDone, 0, sizeof(abDone));
pBt = pParent->pBt;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
@@ -58607,12 +59782,14 @@ static int balance_nonroot(
/*
** Allocate space for memory structures
*/
- k = pBt->pageSize + ROUND8(sizeof(MemPage));
szScratch =
nMaxCells*sizeof(u8*) /* apCell */
+ nMaxCells*sizeof(u16) /* szCell */
- + pBt->pageSize /* aSpace1 */
- + k*nOld; /* Page copies (apCopy) */
+ + pBt->pageSize; /* aSpace1 */
+
+ /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
+ ** that is more than 6 times the database page size. */
+ assert( szScratch<=6*(int)pBt->pageSize );
apCell = sqlite3ScratchMalloc( szScratch );
if( apCell==0 ){
rc = SQLITE_NOMEM;
@@ -58625,8 +59802,8 @@ static int balance_nonroot(
/*
** Load pointers to all cells on sibling pages and the divider cells
** into the local apCell[] array. Make copies of the divider cells
- ** into space obtained from aSpace1[] and remove the divider cells
- ** from pParent.
+ ** into space obtained from aSpace1[]. The divider cells have already
+ ** been removed from pParent.
**
** If the siblings are on leaf pages, then the child pointers of the
** divider cells are stripped from the cells before they are copied
@@ -58642,15 +59819,7 @@ static int balance_nonroot(
leafData = apOld[0]->intKeyLeaf;
for(i=0; i<nOld; i++){
int limit;
-
- /* Before doing anything else, take a copy of the i'th original sibling
- ** The rest of this function will use data from the copies rather
- ** that the original pages since the original pages will be in the
- ** process of being overwritten. */
- MemPage *pOld = apCopy[i] = (MemPage*)&aSpace1[pBt->pageSize + k*i];
- memcpy(pOld, apOld[i], sizeof(MemPage));
- pOld->aData = (void*)&pOld[1];
- memcpy(pOld->aData, apOld[i]->aData, pBt->pageSize);
+ MemPage *pOld = apOld[i];
limit = pOld->nCell+pOld->nOverflow;
if( pOld->nOverflow>0 ){
@@ -58671,6 +59840,7 @@ static int balance_nonroot(
nCell++;
}
}
+ cntOld[i] = nCell;
if( i<nOld-1 && !leafData){
u16 sz = (u16)szNew[i];
u8 *pTemp;
@@ -58693,7 +59863,11 @@ static int balance_nonroot(
}else{
assert( leafCorrection==4 );
if( szCell[nCell]<4 ){
- /* Do not allow any cells smaller than 4 bytes. */
+ /* Do not allow any cells smaller than 4 bytes. If a smaller cell
+ ** does exist, pad it with 0x00 bytes. */
+ assert( szCell[nCell]==3 );
+ assert( apCell[nCell]==&aSpace1[iSpace1-3] );
+ aSpace1[iSpace1++] = 0x00;
szCell[nCell] = 4;
}
}
@@ -58722,7 +59896,7 @@ static int balance_nonroot(
assert( i<nMaxCells );
subtotal += szCell[i] + 2;
if( subtotal > usableSpace ){
- szNew[k] = subtotal - szCell[i];
+ szNew[k] = subtotal - szCell[i] - 2;
cntNew[k] = i;
if( leafData ){ i--; }
subtotal = 0;
@@ -58736,9 +59910,10 @@ static int balance_nonroot(
/*
** The packing computed by the previous block is biased toward the siblings
- ** on the left side. The left siblings are always nearly full, while the
- ** right-most sibling might be nearly empty. This block of code attempts
- ** to adjust the packing of siblings to get a better balance.
+ ** on the left side (siblings with smaller keys). The left siblings are
+ ** always nearly full, while the right-most sibling might be nearly empty.
+ ** The next block of code attempts to adjust the packing of siblings to
+ ** get a better balance.
**
** This adjustment is more than an optimization. The packing above might
** be so out of balance as to be illegal. For example, the right-most
@@ -58767,22 +59942,18 @@ static int balance_nonroot(
szNew[i-1] = szLeft;
}
- /* Either we found one or more cells (cntnew[0])>0) or pPage is
- ** a virtual root page. A virtual root page is when the real root
- ** page is page 1 and we are the only child of that page.
- **
- ** UPDATE: The assert() below is not necessarily true if the database
- ** file is corrupt. The corruption will be detected and reported later
- ** in this procedure so there is no need to act upon it now.
+ /* Sanity check: For a non-corrupt database file one of the follwing
+ ** must be true:
+ ** (1) We found one or more cells (cntNew[0])>0), or
+ ** (2) pPage is a virtual root page. A virtual root page is when
+ ** the real root page is page 1 and we are the only child of
+ ** that page.
*/
-#if 0
- assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) );
-#endif
-
- TRACE(("BALANCE: old: %d %d %d ",
- apOld[0]->pgno,
- nOld>=2 ? apOld[1]->pgno : 0,
- nOld>=3 ? apOld[2]->pgno : 0
+ assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
+ TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
+ apOld[0]->pgno, apOld[0]->nCell,
+ nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
+ nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
));
/*
@@ -58805,8 +59976,10 @@ static int balance_nonroot(
assert( i>0 );
rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0);
if( rc ) goto balance_cleanup;
+ zeroPage(pNew, pageFlags);
apNew[i] = pNew;
nNew++;
+ cntOld[i] = nCell;
/* Set the pointer-map entry for the new sibling page. */
if( ISAUTOVACUUM ){
@@ -58818,135 +59991,247 @@ static int balance_nonroot(
}
}
- /* Free any old pages that were not reused as new pages.
- */
- while( i<nOld ){
- freePage(apOld[i], &rc);
- if( rc ) goto balance_cleanup;
- releasePage(apOld[i]);
- apOld[i] = 0;
- i++;
- }
-
/*
- ** Put the new pages in ascending order. This helps to
- ** keep entries in the disk file in order so that a scan
- ** of the table is a linear scan through the file. That
- ** in turn helps the operating system to deliver pages
- ** from the disk more rapidly.
+ ** Reassign page numbers so that the new pages are in ascending order.
+ ** This helps to keep entries in the disk file in order so that a scan
+ ** of the table is closer to a linear scan through the file. That in turn
+ ** helps the operating system to deliver pages from the disk more rapidly.
**
- ** An O(n^2) insertion sort algorithm is used, but since
- ** n is never more than NB (a small constant), that should
- ** not be a problem.
+ ** An O(n^2) insertion sort algorithm is used, but since n is never more
+ ** than (NB+2) (a small constant), that should not be a problem.
**
- ** When NB==3, this one optimization makes the database
- ** about 25% faster for large insertions and deletions.
+ ** When NB==3, this one optimization makes the database about 25% faster
+ ** for large insertions and deletions.
*/
- for(i=0; i<k-1; i++){
- int minV = apNew[i]->pgno;
- int minI = i;
- for(j=i+1; j<k; j++){
- if( apNew[j]->pgno<(unsigned)minV ){
- minI = j;
- minV = apNew[j]->pgno;
+ for(i=0; i<nNew; i++){
+ aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
+ aPgFlags[i] = apNew[i]->pDbPage->flags;
+ for(j=0; j<i; j++){
+ if( aPgno[j]==aPgno[i] ){
+ /* This branch is taken if the set of sibling pages somehow contains
+ ** duplicate entries. This can happen if the database is corrupt.
+ ** It would be simpler to detect this as part of the loop below, but
+ ** we do the detection here in order to avoid populating the pager
+ ** cache with two separate objects associated with the same
+ ** page number. */
+ assert( CORRUPT_DB );
+ rc = SQLITE_CORRUPT_BKPT;
+ goto balance_cleanup;
}
}
- if( minI>i ){
- MemPage *pT;
- pT = apNew[i];
- apNew[i] = apNew[minI];
- apNew[minI] = pT;
+ }
+ for(i=0; i<nNew; i++){
+ int iBest = 0; /* aPgno[] index of page number to use */
+ for(j=1; j<nNew; j++){
+ if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j;
+ }
+ pgno = aPgOrder[iBest];
+ aPgOrder[iBest] = 0xffffffff;
+ if( iBest!=i ){
+ if( iBest>i ){
+ sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0);
+ }
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]);
+ apNew[i]->pgno = pgno;
}
}
- TRACE(("new: %d(%d) %d(%d) %d(%d) %d(%d) %d(%d)\n",
- apNew[0]->pgno, szNew[0],
+
+ TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
+ "%d(%d nc=%d) %d(%d nc=%d)\n",
+ apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
+ nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
nNew>=3 ? apNew[2]->pgno : 0, nNew>=3 ? szNew[2] : 0,
+ nNew>=3 ? cntNew[2] - cntNew[1] - !leafData : 0,
nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0,
- nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0));
+ nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0,
+ nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0,
+ nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0
+ ));
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
put4byte(pRight, apNew[nNew-1]->pgno);
- /*
- ** Evenly distribute the data in apCell[] across the new pages.
- ** Insert divider cells into pParent as necessary.
+ /* If the sibling pages are not leaves, ensure that the right-child pointer
+ ** of the right-most new sibling page is set to the value that was
+ ** originally in the same field of the right-most old sibling page. */
+ if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){
+ MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1];
+ memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4);
+ }
+
+ /* Make any required updates to pointer map entries associated with
+ ** cells stored on sibling pages following the balance operation. Pointer
+ ** map entries associated with divider cells are set by the insertCell()
+ ** routine. The associated pointer map entries are:
+ **
+ ** a) if the cell contains a reference to an overflow chain, the
+ ** entry associated with the first page in the overflow chain, and
+ **
+ ** b) if the sibling pages are not leaves, the child page associated
+ ** with the cell.
+ **
+ ** If the sibling pages are not leaves, then the pointer map entry
+ ** associated with the right-child of each sibling may also need to be
+ ** updated. This happens below, after the sibling pages have been
+ ** populated, not here.
*/
- j = 0;
- for(i=0; i<nNew; i++){
- /* Assemble the new sibling page. */
+ if( ISAUTOVACUUM ){
+ MemPage *pNew = apNew[0];
+ u8 *aOld = pNew->aData;
+ int cntOldNext = pNew->nCell + pNew->nOverflow;
+ int usableSize = pBt->usableSize;
+ int iNew = 0;
+ int iOld = 0;
+
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
+ if( i==cntOldNext ){
+ MemPage *pOld = (++iOld)<nNew ? apNew[iOld] : apOld[iOld];
+ cntOldNext += pOld->nCell + pOld->nOverflow + !leafData;
+ aOld = pOld->aData;
+ }
+ if( i==cntNew[iNew] ){
+ pNew = apNew[++iNew];
+ if( !leafData ) continue;
+ }
+
+ /* Cell pCell is destined for new sibling page pNew. Originally, it
+ ** was either part of sibling page iOld (possibly an overflow cell),
+ ** or else the divider cell to the left of sibling page iOld. So,
+ ** if sibling page iOld had the same page number as pNew, and if
+ ** pCell really was a part of sibling page iOld (not a divider or
+ ** overflow cell), we can skip updating the pointer map entries. */
+ if( iOld>=nNew
+ || pNew->pgno!=aPgno[iOld]
+ || pCell<aOld
+ || pCell>=&aOld[usableSize]
+ ){
+ if( !leafCorrection ){
+ ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc);
+ }
+ if( szCell[i]>pNew->minLocal ){
+ ptrmapPutOvflPtr(pNew, pCell, &rc);
+ }
+ }
+ }
+ }
+
+ /* Insert new divider cells into pParent. */
+ for(i=0; i<nNew-1; i++){
+ u8 *pCell;
+ u8 *pTemp;
+ int sz;
MemPage *pNew = apNew[i];
+ j = cntNew[i];
+
assert( j<nMaxCells );
- zeroPage(pNew, pageFlags);
- assemblePage(pNew, cntNew[i]-j, &apCell[j], &szCell[j]);
- assert( pNew->nCell>0 || (nNew==1 && cntNew[0]==0) );
- assert( pNew->nOverflow==0 );
+ pCell = apCell[j];
+ sz = szCell[j] + leafCorrection;
+ pTemp = &aOvflSpace[iOvflSpace];
+ if( !pNew->leaf ){
+ memcpy(&pNew->aData[8], pCell, 4);
+ }else if( leafData ){
+ /* If the tree is a leaf-data tree, and the siblings are leaves,
+ ** then there is no divider cell in apCell[]. Instead, the divider
+ ** cell consists of the integer key for the right-most cell of
+ ** the sibling-page assembled above only.
+ */
+ CellInfo info;
+ j--;
+ btreeParseCellPtr(pNew, apCell[j], &info);
+ pCell = pTemp;
+ sz = 4 + putVarint(&pCell[4], info.nKey);
+ pTemp = 0;
+ }else{
+ pCell -= 4;
+ /* Obscure case for non-leaf-data trees: If the cell at pCell was
+ ** previously stored on a leaf node, and its reported size was 4
+ ** bytes, then it may actually be smaller than this
+ ** (see btreeParseCellPtr(), 4 bytes is the minimum size of
+ ** any cell). But it is important to pass the correct size to
+ ** insertCell(), so reparse the cell now.
+ **
+ ** Note that this can never happen in an SQLite data file, as all
+ ** cells are at least 4 bytes. It only happens in b-trees used
+ ** to evaluate "IN (SELECT ...)" and similar clauses.
+ */
+ if( szCell[j]==4 ){
+ assert(leafCorrection==4);
+ sz = cellSizePtr(pParent, pCell);
+ }
+ }
+ iOvflSpace += sz;
+ assert( sz<=pBt->maxLocal+23 );
+ assert( iOvflSpace <= (int)pBt->pageSize );
+ insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc);
+ if( rc!=SQLITE_OK ) goto balance_cleanup;
+ assert( sqlite3PagerIswriteable(pParent->pDbPage) );
+ }
- j = cntNew[i];
+ /* Now update the actual sibling pages. The order in which they are updated
+ ** is important, as this code needs to avoid disrupting any page from which
+ ** cells may still to be read. In practice, this means:
+ **
+ ** (1) If cells are moving left (from apNew[iPg] to apNew[iPg-1])
+ ** then it is not safe to update page apNew[iPg] until after
+ ** the left-hand sibling apNew[iPg-1] has been updated.
+ **
+ ** (2) If cells are moving right (from apNew[iPg] to apNew[iPg+1])
+ ** then it is not safe to update page apNew[iPg] until after
+ ** the right-hand sibling apNew[iPg+1] has been updated.
+ **
+ ** If neither of the above apply, the page is safe to update.
+ **
+ ** The iPg value in the following loop starts at nNew-1 goes down
+ ** to 0, then back up to nNew-1 again, thus making two passes over
+ ** the pages. On the initial downward pass, only condition (1) above
+ ** needs to be tested because (2) will always be true from the previous
+ ** step. On the upward pass, both conditions are always true, so the
+ ** upwards pass simply processes pages that were missed on the downward
+ ** pass.
+ */
+ for(i=1-nNew; i<nNew; i++){
+ int iPg = i<0 ? -i : i;
+ assert( iPg>=0 && iPg<nNew );
+ if( abDone[iPg] ) continue; /* Skip pages already processed */
+ if( i>=0 /* On the upwards pass, or... */
+ || cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */
+ ){
+ int iNew;
+ int iOld;
+ int nNewCell;
- /* If the sibling page assembled above was not the right-most sibling,
- ** insert a divider cell into the parent page.
- */
- assert( i<nNew-1 || j==nCell );
- if( j<nCell ){
- u8 *pCell;
- u8 *pTemp;
- int sz;
+ /* Verify condition (1): If cells are moving left, update iPg
+ ** only after iPg-1 has already been updated. */
+ assert( iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1] );
- assert( j<nMaxCells );
- pCell = apCell[j];
- sz = szCell[j] + leafCorrection;
- pTemp = &aOvflSpace[iOvflSpace];
- if( !pNew->leaf ){
- memcpy(&pNew->aData[8], pCell, 4);
- }else if( leafData ){
- /* If the tree is a leaf-data tree, and the siblings are leaves,
- ** then there is no divider cell in apCell[]. Instead, the divider
- ** cell consists of the integer key for the right-most cell of
- ** the sibling-page assembled above only.
- */
- CellInfo info;
- j--;
- btreeParseCellPtr(pNew, apCell[j], &info);
- pCell = pTemp;
- sz = 4 + putVarint(&pCell[4], info.nKey);
- pTemp = 0;
+ /* Verify condition (2): If cells are moving right, update iPg
+ ** only after iPg+1 has already been updated. */
+ assert( cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1] );
+
+ if( iPg==0 ){
+ iNew = iOld = 0;
+ nNewCell = cntNew[0];
}else{
- pCell -= 4;
- /* Obscure case for non-leaf-data trees: If the cell at pCell was
- ** previously stored on a leaf node, and its reported size was 4
- ** bytes, then it may actually be smaller than this
- ** (see btreeParseCellPtr(), 4 bytes is the minimum size of
- ** any cell). But it is important to pass the correct size to
- ** insertCell(), so reparse the cell now.
- **
- ** Note that this can never happen in an SQLite data file, as all
- ** cells are at least 4 bytes. It only happens in b-trees used
- ** to evaluate "IN (SELECT ...)" and similar clauses.
- */
- if( szCell[j]==4 ){
- assert(leafCorrection==4);
- sz = cellSizePtr(pParent, pCell);
- }
+ iOld = iPg<nOld ? (cntOld[iPg-1] + !leafData) : nCell;
+ iNew = cntNew[iPg-1] + !leafData;
+ nNewCell = cntNew[iPg] - iNew;
}
- iOvflSpace += sz;
- assert( sz<=pBt->maxLocal+23 );
- assert( iOvflSpace <= (int)pBt->pageSize );
- insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc);
- if( rc!=SQLITE_OK ) goto balance_cleanup;
- assert( sqlite3PagerIswriteable(pParent->pDbPage) );
- j++;
- nxDiv++;
+ editPage(apNew[iPg], iOld, iNew, nNewCell, apCell, szCell);
+ abDone[iPg]++;
+ apNew[iPg]->nFree = usableSpace-szNew[iPg];
+ assert( apNew[iPg]->nOverflow==0 );
+ assert( apNew[iPg]->nCell==nNewCell );
}
}
- assert( j==nCell );
+
+ /* All pages have been processed exactly once */
+ assert( memcmp(abDone, "\01\01\01\01\01", nNew)==0 );
+
assert( nOld>0 );
assert( nNew>0 );
- if( (pageFlags & PTF_LEAF)==0 ){
- u8 *zChild = &apCopy[nOld-1]->aData[8];
- memcpy(&apNew[nNew-1]->aData[8], zChild, 4);
- }
if( isRoot && pParent->nCell==0 && pParent->hdrOffset<=apNew[0]->nFree ){
/* The root page of the b-tree now contains no cells. The only sibling
@@ -58959,126 +60244,50 @@ static int balance_nonroot(
** sets all pointer-map entries corresponding to database image pages
** for which the pointer is stored within the content being copied.
**
- ** The second assert below verifies that the child page is defragmented
- ** (it must be, as it was just reconstructed using assemblePage()). This
- ** is important if the parent page happens to be page 1 of the database
- ** image. */
+ ** It is critical that the child page be defragmented before being
+ ** copied into the parent, because if the parent is page 1 then it will
+ ** by smaller than the child due to the database header, and so all the
+ ** free space needs to be up front.
+ */
assert( nNew==1 );
+ rc = defragmentPage(apNew[0]);
+ testcase( rc!=SQLITE_OK );
assert( apNew[0]->nFree ==
- (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
+ (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
+ || rc!=SQLITE_OK
);
copyNodeContent(apNew[0], pParent, &rc);
freePage(apNew[0], &rc);
- }else if( ISAUTOVACUUM ){
- /* Fix the pointer-map entries for all the cells that were shifted around.
- ** There are several different types of pointer-map entries that need to
- ** be dealt with by this routine. Some of these have been set already, but
- ** many have not. The following is a summary:
- **
- ** 1) The entries associated with new sibling pages that were not
- ** siblings when this function was called. These have already
- ** been set. We don't need to worry about old siblings that were
- ** moved to the free-list - the freePage() code has taken care
- ** of those.
- **
- ** 2) The pointer-map entries associated with the first overflow
- ** page in any overflow chains used by new divider cells. These
- ** have also already been taken care of by the insertCell() code.
- **
- ** 3) If the sibling pages are not leaves, then the child pages of
- ** cells stored on the sibling pages may need to be updated.
- **
- ** 4) If the sibling pages are not internal intkey nodes, then any
- ** overflow pages used by these cells may need to be updated
- ** (internal intkey nodes never contain pointers to overflow pages).
- **
- ** 5) If the sibling pages are not leaves, then the pointer-map
- ** entries for the right-child pages of each sibling may need
- ** to be updated.
- **
- ** Cases 1 and 2 are dealt with above by other code. The next
- ** block deals with cases 3 and 4 and the one after that, case 5. Since
- ** setting a pointer map entry is a relatively expensive operation, this
- ** code only sets pointer map entries for child or overflow pages that have
- ** actually moved between pages. */
- MemPage *pNew = apNew[0];
- MemPage *pOld = apCopy[0];
- int nOverflow = pOld->nOverflow;
- int iNextOld = pOld->nCell + nOverflow;
- int iOverflow = (nOverflow ? pOld->aiOvfl[0] : -1);
- j = 0; /* Current 'old' sibling page */
- k = 0; /* Current 'new' sibling page */
- for(i=0; i<nCell; i++){
- int isDivider = 0;
- while( i==iNextOld ){
- /* Cell i is the cell immediately following the last cell on old
- ** sibling page j. If the siblings are not leaf pages of an
- ** intkey b-tree, then cell i was a divider cell. */
- assert( j+1 < ArraySize(apCopy) );
- assert( j+1 < nOld );
- pOld = apCopy[++j];
- iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow;
- if( pOld->nOverflow ){
- nOverflow = pOld->nOverflow;
- iOverflow = i + !leafData + pOld->aiOvfl[0];
- }
- isDivider = !leafData;
- }
-
- assert(nOverflow>0 || iOverflow<i );
- assert(nOverflow<2 || pOld->aiOvfl[0]==pOld->aiOvfl[1]-1);
- assert(nOverflow<3 || pOld->aiOvfl[1]==pOld->aiOvfl[2]-1);
- if( i==iOverflow ){
- isDivider = 1;
- if( (--nOverflow)>0 ){
- iOverflow++;
- }
- }
-
- if( i==cntNew[k] ){
- /* Cell i is the cell immediately following the last cell on new
- ** sibling page k. If the siblings are not leaf pages of an
- ** intkey b-tree, then cell i is a divider cell. */
- pNew = apNew[++k];
- if( !leafData ) continue;
- }
- assert( j<nOld );
- assert( k<nNew );
-
- /* If the cell was originally divider cell (and is not now) or
- ** an overflow cell, or if the cell was located on a different sibling
- ** page before the balancing, then the pointer map entries associated
- ** with any child or overflow pages need to be updated. */
- if( isDivider || pOld->pgno!=pNew->pgno ){
- if( !leafCorrection ){
- ptrmapPut(pBt, get4byte(apCell[i]), PTRMAP_BTREE, pNew->pgno, &rc);
- }
- if( szCell[i]>pNew->minLocal ){
- ptrmapPutOvflPtr(pNew, apCell[i], &rc);
- }
- }
+ }else if( ISAUTOVACUUM && !leafCorrection ){
+ /* Fix the pointer map entries associated with the right-child of each
+ ** sibling page. All other pointer map entries have already been taken
+ ** care of. */
+ for(i=0; i<nNew; i++){
+ u32 key = get4byte(&apNew[i]->aData[8]);
+ ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc);
}
+ }
- if( !leafCorrection ){
- for(i=0; i<nNew; i++){
- u32 key = get4byte(&apNew[i]->aData[8]);
- ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc);
- }
- }
+ assert( pParent->isInit );
+ TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
+ nOld, nNew, nCell));
+
+ /* Free any old pages that were not reused as new pages.
+ */
+ for(i=nNew; i<nOld; i++){
+ freePage(apOld[i], &rc);
+ }
#if 0
+ if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
/* The ptrmapCheckPages() contains assert() statements that verify that
** all pointer map pages are set correctly. This is helpful while
** debugging. This is usually disabled because a corrupt database may
** cause an assert() statement to fail. */
ptrmapCheckPages(apNew, nNew);
ptrmapCheckPages(&pParent, 1);
-#endif
}
-
- assert( pParent->isInit );
- TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
- nOld, nNew, nCell));
+#endif
/*
** Cleanup before returning.
@@ -59257,7 +60466,8 @@ static int balance(BtCursor *pCur){
** pSpace buffer passed to the latter call to balance_nonroot().
*/
u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize);
- rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, pCur->hints);
+ rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1,
+ pCur->hints&BTREE_BULKLOAD);
if( pFree ){
/* If pFree is not NULL, it points to the pSpace buffer used
** by a previous call to balance_nonroot(). Its contents are
@@ -59278,6 +60488,7 @@ static int balance(BtCursor *pCur){
/* The next iteration of the do-loop balances the parent page. */
releasePage(pPage);
pCur->iPage--;
+ assert( pCur->iPage>=0 );
}
}while( rc==SQLITE_OK );
@@ -59754,9 +60965,13 @@ static int clearDatabasePage(
if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
-
rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
+ if( pPage->bBusy ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto cleardatabasepage_out;
+ }
+ pPage->bBusy = 1;
hdr = pPage->hdrOffset;
for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i);
@@ -59781,6 +60996,7 @@ static int clearDatabasePage(
}
cleardatabasepage_out:
+ pPage->bBusy = 0;
releasePage(pPage);
return rc;
}
@@ -59970,6 +61186,13 @@ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
** The schema layer numbers meta values differently. At the schema
** layer (and the SetCookie and ReadCookie opcodes) the number of
** free pages is not visible. So Cookie[0] is the same as Meta[1].
+**
+** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead
+** of reading the value out of the header, it instead loads the "DataVersion"
+** from the pager. The BTREE_DATA_VERSION value is not actually stored in the
+** database file. It is a number computed by the pager. But its access
+** pattern is the same as header meta values, and so it is convenient to
+** read it from this routine.
*/
SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
BtShared *pBt = p->pBt;
@@ -59980,7 +61203,11 @@ SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
assert( pBt->pPage1 );
assert( idx>=0 && idx<=15 );
- *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
+ if( idx==BTREE_DATA_VERSION ){
+ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion;
+ }else{
+ *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
+ }
/* If auto-vacuum is disabled in this build and this is an auto-vacuum
** database, mark the database as read-only. */
@@ -60071,7 +61298,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
if( pCur->iPage==0 ){
/* All pages of the b-tree have been visited. Return successfully. */
*pnEntry = nEntry;
- return SQLITE_OK;
+ return moveToRoot(pCur);
}
moveToParent(pCur);
}while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
@@ -60463,8 +61690,14 @@ static int checkTreePage(
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
memset(hit+contentOffset, 0, usableSize-contentOffset);
memset(hit, 1, contentOffset);
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
nCell = get2byte(&data[hdr+3]);
+ /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
+ ** immediately follows the b-tree page header. */
cellStart = hdr + 12 - 4*pPage->leaf;
+ /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
+ ** integer offsets to the cell contents. */
for(i=0; i<nCell; i++){
int pc = get2byte(&data[cellStart+i*2]);
u32 size = 65536;
@@ -60480,6 +61713,9 @@ static int checkTreePage(
for(j=pc+size-1; j>=pc; j--) hit[j]++;
}
}
+ /* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
+ ** is the offset of the first freeblock, or zero if there are no
+ ** freeblocks on the page. */
i = get2byte(&data[hdr+1]);
while( i>0 ){
int size, j;
@@ -60487,7 +61723,13 @@ static int checkTreePage(
size = get2byte(&data[i+2]);
assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */
for(j=i+size-1; j>=i; j--) hit[j]++;
+ /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
+ ** big-endian integer which is the offset in the b-tree page of the next
+ ** freeblock in the chain, or zero if the freeblock is the last on the
+ ** chain. */
j = get2byte(&data[i]);
+ /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
+ ** increasing offset. */
assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */
assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */
i = j;
@@ -60501,6 +61743,11 @@ static int checkTreePage(
break;
}
}
+ /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments
+ ** is stored in the fifth field of the b-tree page header.
+ ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
+ ** number of fragmented free bytes within the cell content area.
+ */
if( cnt!=data[hdr+7] ){
checkAppendMsg(pCheck,
"Fragmentation of %d bytes reported as %d on page %d",
@@ -60889,14 +62136,23 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
}
/*
-** set the mask of hint flags for cursor pCsr. Currently the only valid
-** values are 0 and BTREE_BULKLOAD.
+** set the mask of hint flags for cursor pCsr.
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
- assert( mask==BTREE_BULKLOAD || mask==0 );
+ assert( mask==BTREE_BULKLOAD || mask==BTREE_SEEK_EQ || mask==0 );
pCsr->hints = mask;
}
+#ifdef SQLITE_DEBUG
+/*
+** Return true if the cursor has a hint specified. This routine is
+** only used from within assert() statements
+*/
+SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){
+ return (pCsr->hints & mask)!=0;
+}
+#endif
+
/*
** Return true if the given Btree is read-only.
*/
@@ -60904,6 +62160,11 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
return (p->pBt->btsFlags & BTS_READ_ONLY)!=0;
}
+/*
+** Return the size of the header added to each page by this module.
+*/
+SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
+
/************** End of btree.c ***********************************************/
/************** Begin file backup.c ******************************************/
/*
@@ -61029,6 +62290,20 @@ static int setDestPgsz(sqlite3_backup *p){
}
/*
+** Check that there is no open read-transaction on the b-tree passed as the
+** second argument. If there is not, return SQLITE_OK. Otherwise, if there
+** is an open read-transaction, return SQLITE_ERROR and leave an error
+** message in database handle db.
+*/
+static int checkReadTransaction(sqlite3 *db, Btree *p){
+ if( sqlite3BtreeIsInReadTrans(p) ){
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use");
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+/*
** Create an sqlite3_backup process to copy the contents of zSrcDb from
** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
** a pointer to the new sqlite3_backup object.
@@ -61036,7 +62311,7 @@ static int setDestPgsz(sqlite3_backup *p){
** If an error occurs, NULL is returned and an error code and error message
** stored in database handle pDestDb.
*/
-SQLITE_API sqlite3_backup *sqlite3_backup_init(
+SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
sqlite3* pDestDb, /* Database to write to */
const char *zDestDb, /* Name of database within pDestDb */
sqlite3* pSrcDb, /* Database connection to read from */
@@ -61044,6 +62319,13 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
){
sqlite3_backup *p; /* Value to return */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(pSrcDb)||!sqlite3SafetyCheckOk(pDestDb) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+
/* Lock the source database handle. The destination database
** handle is not locked in this routine, but it is locked in
** sqlite3_backup_step(). The user is required to ensure that no
@@ -61080,12 +62362,15 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
p->iNext = 1;
p->isAttached = 0;
- if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){
+ if( 0==p->pSrc || 0==p->pDest
+ || setDestPgsz(p)==SQLITE_NOMEM
+ || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
+ ){
/* One (or both) of the named databases did not exist or an OOM
- ** error was hit. The error has already been written into the
- ** pDestDb handle. All that is left to do here is free the
- ** sqlite3_backup structure.
- */
+ ** error was hit. Or there is a transaction open on the destination
+ ** database. The error has already been written into the pDestDb
+ ** handle. All that is left to do here is free the sqlite3_backup
+ ** structure. */
sqlite3_free(p);
p = 0;
}
@@ -61129,7 +62414,7 @@ static int backupOnePage(
** guaranteed that the shared-mutex is held by this thread, handle
** p->pSrc may not actually be the owner. */
int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
- int nDestReserve = sqlite3BtreeGetReserve(p->pDest);
+ int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
#endif
int rc = SQLITE_OK;
i64 iOff;
@@ -61234,12 +62519,15 @@ static void attachBackupObject(sqlite3_backup *p){
/*
** Copy nPage pages from the source b-tree to the destination.
*/
-SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
int destMode; /* Destination journal mode */
int pgszSrc = 0; /* Source page size */
int pgszDest = 0; /* Destination page size */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
if( p->pDestDb ){
@@ -61476,7 +62764,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/*
** Release all resources associated with an sqlite3_backup* handle.
*/
-SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
sqlite3_backup **pp; /* Ptr to head of pagers backup list */
sqlite3 *pSrcDb; /* Source database connection */
int rc; /* Value to return */
@@ -61528,7 +62816,13 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
** Return the number of pages still to be backed up as of the most recent
** call to sqlite3_backup_step().
*/
-SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return p->nRemaining;
}
@@ -61536,7 +62830,13 @@ SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
** Return the total number of pages in the source database as of the most
** recent call to sqlite3_backup_step().
*/
-SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return p->nPagecount;
}
@@ -62745,7 +64045,7 @@ struct ValueNewStat4Ctx {
** Otherwise, if the second argument is non-zero, then this function is
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
** already been allocated, allocate the UnpackedRecord structure that
-** that function will return to its caller here. Then return a pointer
+** that function will return to its caller here. Then return a pointer to
** an sqlite3_value within the UnpackedRecord.a[] array.
*/
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
@@ -62790,6 +64090,113 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
}
/*
+** The expression object indicated by the second argument is guaranteed
+** to be a scalar SQL function. If
+**
+** * all function arguments are SQL literals,
+** * the SQLITE_FUNC_CONSTANT function flag is set, and
+** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
+**
+** then this routine attempts to invoke the SQL function. Assuming no
+** error occurs, output parameter (*ppVal) is set to point to a value
+** object containing the result before returning SQLITE_OK.
+**
+** Affinity aff is applied to the result of the function before returning.
+** If the result is a text value, the sqlite3_value object uses encoding
+** enc.
+**
+** If the conditions above are not met, this function returns SQLITE_OK
+** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
+** NULL and an SQLite error code returned.
+*/
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+static int valueFromFunction(
+ sqlite3 *db, /* The database connection */
+ Expr *p, /* The expression to evaluate */
+ u8 enc, /* Encoding to use */
+ u8 aff, /* Affinity to use */
+ sqlite3_value **ppVal, /* Write the new value here */
+ struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */
+){
+ sqlite3_context ctx; /* Context object for function invocation */
+ sqlite3_value **apVal = 0; /* Function arguments */
+ int nVal = 0; /* Size of apVal[] array */
+ FuncDef *pFunc = 0; /* Function definition */
+ sqlite3_value *pVal = 0; /* New value */
+ int rc = SQLITE_OK; /* Return code */
+ int nName; /* Size of function name in bytes */
+ ExprList *pList = 0; /* Function arguments */
+ int i; /* Iterator variable */
+
+ assert( pCtx!=0 );
+ assert( (p->flags & EP_TokenOnly)==0 );
+ pList = p->x.pList;
+ if( pList ) nVal = pList->nExpr;
+ nName = sqlite3Strlen30(p->u.zToken);
+ pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
+ assert( pFunc );
+ if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0
+ || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ ){
+ return SQLITE_OK;
+ }
+
+ if( pList ){
+ apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
+ if( apVal==0 ){
+ rc = SQLITE_NOMEM;
+ goto value_from_function_out;
+ }
+ for(i=0; i<nVal; i++){
+ rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
+ if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
+ }
+ }
+
+ pVal = valueNew(db, pCtx);
+ if( pVal==0 ){
+ rc = SQLITE_NOMEM;
+ goto value_from_function_out;
+ }
+
+ assert( pCtx->pParse->rc==SQLITE_OK );
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.pOut = pVal;
+ ctx.pFunc = pFunc;
+ pFunc->xFunc(&ctx, nVal, apVal);
+ if( ctx.isError ){
+ rc = ctx.isError;
+ sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
+ }else{
+ sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
+ assert( rc==SQLITE_OK );
+ rc = sqlite3VdbeChangeEncoding(pVal, enc);
+ if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
+ rc = SQLITE_TOOBIG;
+ pCtx->pParse->nErr++;
+ }
+ }
+ pCtx->pParse->rc = rc;
+
+ value_from_function_out:
+ if( rc!=SQLITE_OK ){
+ pVal = 0;
+ }
+ if( apVal ){
+ for(i=0; i<nVal; i++){
+ sqlite3ValueFree(apVal[i]);
+ }
+ sqlite3DbFree(db, apVal);
+ }
+
+ *ppVal = pVal;
+ return rc;
+}
+#else
+# define valueFromFunction(a,b,c,d,e,f) SQLITE_OK
+#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
+
+/*
** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
** using valueNew().
@@ -62821,6 +64228,12 @@ static int valueFromExpr(
while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
+ /* Compressed expressions only appear when parsing the DEFAULT clause
+ ** on a table column definition, and hence only when pCtx==0. This
+ ** check ensures that an EP_TokenOnly expression is never passed down
+ ** into valueFromFunction(). */
+ assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 );
+
if( op==TK_CAST ){
u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
@@ -62897,6 +64310,12 @@ static int valueFromExpr(
}
#endif
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ else if( op==TK_FUNCTION && pCtx!=0 ){
+ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
+ }
+#endif
+
*ppVal = pVal;
return rc;
@@ -63286,7 +64705,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepa
/*
** Return the SQL associated with a prepared statement
*/
-SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe *)pStmt;
return (p && p->isPrepareV2) ? p->zSql : 0;
}
@@ -63627,6 +65046,7 @@ static Op *opIterNext(VdbeOpIter *p){
*/
SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int hasAbort = 0;
+ int hasFkCounter = 0;
Op *pOp;
VdbeOpIter sIter;
memset(&sIter, 0, sizeof(sIter));
@@ -63635,15 +65055,17 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
while( (pOp = opIterNext(&sIter))!=0 ){
int opcode = pOp->opcode;
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
-#ifndef SQLITE_OMIT_FOREIGN_KEY
- || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
-#endif
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
){
hasAbort = 1;
break;
}
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+ if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
+ hasFkCounter = 1;
+ }
+#endif
}
sqlite3DbFree(v->db, sIter.apSub);
@@ -63652,7 +65074,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
** through all opcodes and hasAbort may be set incorrectly. Return
** true for this case to prevent the assert() in the callers frame
** from failing. */
- return ( v->db->mallocFailed || hasAbort==mayAbort );
+ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter );
}
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
@@ -63828,6 +65250,34 @@ SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp,
return addr;
}
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+/*
+** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
+*/
+SQLITE_PRIVATE void sqlite3VdbeScanStatus(
+ Vdbe *p, /* VM to add scanstatus() to */
+ int addrExplain, /* Address of OP_Explain (or 0) */
+ int addrLoop, /* Address of loop counter */
+ int addrVisit, /* Address of rows visited counter */
+ LogEst nEst, /* Estimated number of output rows */
+ const char *zName /* Name of table or index being scanned */
+){
+ int nByte = (p->nScan+1) * sizeof(ScanStatus);
+ ScanStatus *aNew;
+ aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
+ if( aNew ){
+ ScanStatus *pNew = &aNew[p->nScan++];
+ pNew->addrExplain = addrExplain;
+ pNew->addrLoop = addrLoop;
+ pNew->addrVisit = addrVisit;
+ pNew->nEst = nEst;
+ pNew->zName = sqlite3DbStrDup(p->db, zName);
+ p->aScan = aNew;
+ }
+}
+#endif
+
+
/*
** Change the value of the P1 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -64318,7 +65768,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P4_VTAB: {
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
- sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
+ sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab);
break;
}
#endif
@@ -64926,6 +66376,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
&zCsr, zEnd, &nByte);
p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte);
+#endif
if( nByte ){
p->pFree = sqlite3DbMallocZero(db, nByte);
}
@@ -64942,7 +66395,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->aVar[n].db = db;
}
}
- if( p->azVar ){
+ if( p->azVar && pParse->nzVar>0 ){
p->nzVar = pParse->nzVar;
memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
@@ -64979,9 +66432,9 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
else if( pCx->pVtabCursor ){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
- p->inVtabMethod = 1;
+ assert( pVtabCursor->pVtab->nRef>0 );
+ pVtabCursor->pVtab->nRef--;
pModule->xClose(pVtabCursor);
- p->inVtabMethod = 0;
}
#endif
}
@@ -64993,6 +66446,9 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
*/
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
Vdbe *v = pFrame->v;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ v->anExec = pFrame->anExec;
+#endif
v->aOnceFlag = pFrame->aOnceFlag;
v->nOnceFlag = pFrame->nOnceFlag;
v->aOp = pFrame->aOp;
@@ -65003,6 +66459,7 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
v->nCursor = pFrame->nCursor;
v->db->lastRowid = pFrame->lastRowid;
v->nChange = pFrame->nChange;
+ v->db->nChange = pFrame->nDbChange;
return pFrame->pc;
}
@@ -65336,7 +66793,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
+ rc = sqlite3OsDelete(pVfs, zMaster, needSync);
sqlite3DbFree(db, zMaster);
zMaster = 0;
if( rc ){
@@ -65570,6 +67027,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
+ p->nChange = 0;
}
}
}
@@ -65610,6 +67068,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}else if( rc!=SQLITE_OK ){
p->rc = rc;
sqlite3RollbackAll(db, SQLITE_OK);
+ p->nChange = 0;
}else{
db->nDeferredCons = 0;
db->nDeferredImmCons = 0;
@@ -65618,6 +67077,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
}else{
sqlite3RollbackAll(db, SQLITE_OK);
+ p->nChange = 0;
}
db->nStatement = 0;
}else if( eStatementOp==0 ){
@@ -65629,6 +67089,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
+ p->nChange = 0;
}
}
@@ -65649,6 +67110,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
+ p->nChange = 0;
}
}
@@ -65910,6 +67372,12 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
sqlite3DbFree(db, p->pFree);
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ for(i=0; i<p->nScan; i++){
+ sqlite3DbFree(db, p->aScan[i].zName);
+ }
+ sqlite3DbFree(db, p->aScan);
+#endif
}
/*
@@ -66068,9 +67536,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
i64 i = pMem->u.i;
u64 u;
if( i<0 ){
- if( i<(-MAX_6BYTE) ) return 6;
- /* Previous test prevents: u = -(-9223372036854775808) */
- u = -i;
+ u = ~i;
}else{
u = i;
}
@@ -66236,10 +67702,14 @@ static u32 SQLITE_NOINLINE serialGet(
u32 y = FOUR_BYTE_UINT(buf+4);
x = (x<<32) + y;
if( serial_type==6 ){
+ /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit
+ ** twos-complement integer. */
pMem->u.i = *(i64*)&x;
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
}else{
+ /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit
+ ** floating point number. */
#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
/* Verify that integers and floating point values use the same
** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
@@ -66267,35 +67737,46 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
switch( serial_type ){
case 10: /* Reserved for future use */
case 11: /* Reserved for future use */
- case 0: { /* NULL */
+ case 0: { /* Null */
+ /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
pMem->flags = MEM_Null;
break;
}
- case 1: { /* 1-byte signed integer */
+ case 1: {
+ /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement
+ ** integer. */
pMem->u.i = ONE_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 1;
}
case 2: { /* 2-byte signed integer */
+ /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit
+ ** twos-complement integer. */
pMem->u.i = TWO_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 2;
}
case 3: { /* 3-byte signed integer */
+ /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit
+ ** twos-complement integer. */
pMem->u.i = THREE_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 3;
}
case 4: { /* 4-byte signed integer */
+ /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
+ ** twos-complement integer. */
pMem->u.i = FOUR_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 4;
}
case 5: { /* 6-byte signed integer */
+ /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit
+ ** twos-complement integer. */
pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
@@ -66309,11 +67790,17 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
}
case 8: /* Integer 0 */
case 9: { /* Integer 1 */
+ /* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */
+ /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */
pMem->u.i = serial_type-8;
pMem->flags = MEM_Int;
return 0;
}
default: {
+ /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in
+ ** length.
+ ** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and
+ ** (N-13)/2 bytes in length. */
static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
pMem->z = (char *)buf;
pMem->n = (serial_type-12)/2;
@@ -66512,6 +67999,42 @@ debugCompareEnd:
}
#endif
+#if SQLITE_DEBUG
+/*
+** Count the number of fields (a.k.a. columns) in the record given by
+** pKey,nKey. The verify that this count is less than or equal to the
+** limit given by pKeyInfo->nField + pKeyInfo->nXField.
+**
+** If this constraint is not satisfied, it means that the high-speed
+** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
+** not work correctly. If this assert() ever fires, it probably means
+** that the KeyInfo.nField or KeyInfo.nXField values were computed
+** incorrectly.
+*/
+static void vdbeAssertFieldCountWithinLimits(
+ int nKey, const void *pKey, /* The record to verify */
+ const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
+){
+ int nField = 0;
+ u32 szHdr;
+ u32 idx;
+ u32 notUsed;
+ const unsigned char *aKey = (const unsigned char*)pKey;
+
+ if( CORRUPT_DB ) return;
+ idx = getVarint32(aKey, szHdr);
+ assert( nKey>=0 );
+ assert( szHdr<=(u32)nKey );
+ while( idx<szHdr ){
+ idx += getVarint32(aKey+idx, notUsed);
+ nField++;
+ }
+ assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
+}
+#else
+# define vdbeAssertFieldCountWithinLimits(A,B,C)
+#endif
+
/*
** Both *pMem1 and *pMem2 contain string values. Compare the two values
** using the collation sequence pColl. As usual, return a negative , zero
@@ -66923,6 +68446,7 @@ static int vdbeRecordCompareInt(
i64 v = pPKey2->aMem[0].u.i;
i64 lhs;
+ vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
switch( serial_type ){
case 1: { /* 1-byte signed integer */
@@ -67010,6 +68534,7 @@ static int vdbeRecordCompareString(
int serial_type;
int res;
+ vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
getVarint32(&aKey1[1], serial_type);
if( serial_type<12 ){
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
@@ -67336,7 +68861,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
** collating sequences are registered or if an authorizer function is
** added or changed.
*/
-SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p==0 || p->expired;
}
@@ -67373,7 +68898,7 @@ static int vdbeSafetyNotNull(Vdbe *p){
** This routine sets the error code and string returned by
** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
*/
-SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
/* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
@@ -67399,7 +68924,7 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
** This routine sets the error code and string returned by
** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
*/
-SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
rc = SQLITE_OK;
@@ -67418,7 +68943,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
/*
** Set all the parameters in the compiled SQL statement to NULL.
*/
-SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int i;
int rc = SQLITE_OK;
Vdbe *p = (Vdbe*)pStmt;
@@ -67442,7 +68967,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
** The following routines extract information from a Mem or sqlite3_value
** structure.
*/
-SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
Mem *p = (Mem*)pVal;
if( p->flags & (MEM_Blob|MEM_Str) ){
sqlite3VdbeMemExpandBlob(p);
@@ -67452,36 +68977,40 @@ SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
return sqlite3_value_text(pVal);
}
}
-SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF8);
}
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
}
-SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){
+SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value *pVal){
return sqlite3VdbeRealValue((Mem*)pVal);
}
-SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){
return (int)sqlite3VdbeIntValue((Mem*)pVal);
}
-SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
+SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
return sqlite3VdbeIntValue((Mem*)pVal);
}
-SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value* pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
}
-SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16BE);
}
-SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
+/* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five
+** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
+** point number string BLOB NULL
+*/
+SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
static const u8 aType[] = {
SQLITE_BLOB, /* 0x00 */
SQLITE_NULL, /* 0x01 */
@@ -67557,7 +69086,7 @@ static int invokeValueDestructor(
if( pCtx ) sqlite3_result_error_toobig(pCtx);
return SQLITE_TOOBIG;
}
-SQLITE_API void sqlite3_result_blob(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -67567,7 +69096,7 @@ SQLITE_API void sqlite3_result_blob(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, 0, xDel);
}
-SQLITE_API void sqlite3_result_blob64(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
sqlite3_context *pCtx,
const void *z,
sqlite3_uint64 n,
@@ -67581,37 +69110,37 @@ SQLITE_API void sqlite3_result_blob64(
setResultStrOrError(pCtx, z, (int)n, 0, xDel);
}
}
-SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context *pCtx, double rVal){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
-SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
-SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context *pCtx, int iVal){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
-SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
}
-SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
-SQLITE_API void sqlite3_result_text(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
sqlite3_context *pCtx,
const char *z,
int n,
@@ -67620,7 +69149,7 @@ SQLITE_API void sqlite3_result_text(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
-SQLITE_API void sqlite3_result_text64(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
sqlite3_context *pCtx,
const char *z,
sqlite3_uint64 n,
@@ -67637,7 +69166,7 @@ SQLITE_API void sqlite3_result_text64(
}
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API void sqlite3_result_text16(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -67646,7 +69175,7 @@ SQLITE_API void sqlite3_result_text16(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
}
-SQLITE_API void sqlite3_result_text16be(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -67655,7 +69184,7 @@ SQLITE_API void sqlite3_result_text16be(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
}
-SQLITE_API void sqlite3_result_text16le(
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -67665,17 +69194,20 @@ SQLITE_API void sqlite3_result_text16le(
setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemCopy(pCtx->pOut, pValue);
}
-SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
}
-SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
pCtx->fErrorOrAux = 1;
+#ifdef SQLITE_DEBUG
+ if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
+#endif
if( pCtx->pOut->flags & MEM_Null ){
sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
SQLITE_UTF8, SQLITE_STATIC);
@@ -67683,7 +69215,7 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
}
/* Force an SQLITE_TOOBIG error. */
-SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
pCtx->fErrorOrAux = 1;
@@ -67692,7 +69224,7 @@ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
}
/* An SQLITE_NOMEM error. */
-SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM;
@@ -67711,7 +69243,10 @@ static int doWalCallbacks(sqlite3 *db){
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ int nEntry;
+ sqlite3BtreeEnter(pBt);
+ nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ sqlite3BtreeLeave(pBt);
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
}
@@ -67753,7 +69288,7 @@ static int sqlite3Step(Vdbe *p){
** or SQLITE_BUSY error.
*/
#ifdef SQLITE_OMIT_AUTORESET
- if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){
+ if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
sqlite3_reset((sqlite3_stmt*)p);
}else{
return SQLITE_MISUSE_BKPT;
@@ -67799,6 +69334,9 @@ static int sqlite3Step(Vdbe *p){
if( p->bIsReader ) db->nVdbeRead++;
p->pc = 0;
}
+#ifdef SQLITE_DEBUG
+ p->rcApp = SQLITE_OK;
+#endif
#ifndef SQLITE_OMIT_EXPLAIN
if( p->explain ){
rc = sqlite3VdbeList(p);
@@ -67843,7 +69381,7 @@ end_of_step:
assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| rc==SQLITE_BUSY || rc==SQLITE_MISUSE
);
- assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE );
+ assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
/* If this statement was prepared using sqlite3_prepare_v2(), and an
** error has occurred, then return the error code in p->rc to the
@@ -67859,7 +69397,7 @@ end_of_step:
** sqlite3Step() to do most of the work. If a schema error occurs,
** call sqlite3Reprepare() and try again.
*/
-SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_OK; /* Result from sqlite3Step() */
int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
@@ -67891,7 +69429,6 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
** sqlite3_errmsg() and sqlite3_errcode().
*/
const char *zErr = (const char *)sqlite3_value_text(db->pErr);
- assert( zErr!=0 || db->mallocFailed );
sqlite3DbFree(db, v->zErrMsg);
if( !db->mallocFailed ){
v->zErrMsg = sqlite3DbStrDup(db, zErr);
@@ -67911,7 +69448,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
** Extract the user data from a sqlite3_context structure and return a
** pointer to it.
*/
-SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
+SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
@@ -67926,22 +69463,32 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
** sqlite3_create_function16() routines that originally registered the
** application defined function.
*/
-SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){
assert( p && p->pFunc );
return p->pOut->db;
}
/*
-** Return the current time for a statement
+** Return the current time for a statement. If the current time
+** is requested more than once within the same run of a single prepared
+** statement, the exact same time is returned for each invocation regardless
+** of the amount of time that elapses between invocations. In other words,
+** the time returned is always the time of the first call.
*/
SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
- Vdbe *v = p->pVdbe;
int rc;
- if( v->iCurrentTime==0 ){
- rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime);
- if( rc ) v->iCurrentTime = 0;
+#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
+ sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime;
+ assert( p->pVdbe!=0 );
+#else
+ sqlite3_int64 iTime = 0;
+ sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime;
+#endif
+ if( *piTime==0 ){
+ rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime);
+ if( rc ) *piTime = 0;
}
- return v->iCurrentTime;
+ return *piTime;
}
/*
@@ -67992,7 +69539,7 @@ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
*/
-SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
+SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
assert( sqlite3_mutex_held(p->pOut->db->mutex) );
testcase( nByte<0 );
@@ -68007,10 +69554,15 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
*/
-SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
+SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+#if SQLITE_ENABLE_STAT3_OR_STAT4
+ if( pCtx->pVdbe==0 ) return 0;
+#else
+ assert( pCtx->pVdbe!=0 );
+#endif
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
}
@@ -68023,7 +69575,7 @@ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
** argument to the user-function defined by pCtx. Any previous value is
** deleted by calling the delete function specified when it was set.
*/
-SQLITE_API void sqlite3_set_auxdata(
+SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(
sqlite3_context *pCtx,
int iArg,
void *pAux,
@@ -68034,6 +69586,11 @@ SQLITE_API void sqlite3_set_auxdata(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( iArg<0 ) goto failed;
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ if( pVdbe==0 ) goto failed;
+#else
+ assert( pVdbe!=0 );
+#endif
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
@@ -68073,7 +69630,7 @@ failed:
** implementations should keep their own counts within their aggregate
** context.
*/
-SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
+SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
return p->pMem->n;
}
@@ -68082,7 +69639,7 @@ SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
/*
** Return the number of columns in the result set for the statement pStmt.
*/
-SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
return pVm ? pVm->nResColumn : 0;
}
@@ -68091,7 +69648,7 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
** Return the number of values available from the current row of the
** currently executing statement pStmt.
*/
-SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
if( pVm==0 || pVm->pResultSet==0 ) return 0;
return pVm->nResColumn;
@@ -68193,7 +69750,7 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
** The following routines are used to access elements of the current row
** in the result set.
*/
-SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
val = sqlite3_value_blob( columnMem(pStmt,i) );
/* Even though there is no encoding conversion, value_blob() might
@@ -68203,37 +69760,37 @@ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_bytes( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
+SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt *pStmt, int i){
double val = sqlite3_value_double( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_int( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
+SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt *pStmt, int i){
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
+SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStmt, int i){
Mem *pOut = columnMem(pStmt, i);
if( pOut->flags&MEM_Static ){
pOut->flags &= ~MEM_Static;
@@ -68243,13 +69800,13 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
return (sqlite3_value *)pOut;
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt *pStmt, int i){
int iType = sqlite3_value_type( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return iType;
@@ -68277,11 +69834,19 @@ static const void *columnName(
const void *(*xFunc)(Mem*),
int useType
){
- const void *ret = 0;
- Vdbe *p = (Vdbe *)pStmt;
+ const void *ret;
+ Vdbe *p;
int n;
- sqlite3 *db = p->db;
-
+ sqlite3 *db;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ ret = 0;
+ p = (Vdbe *)pStmt;
+ db = p->db;
assert( db!=0 );
n = sqlite3_column_count(pStmt);
if( N<n && N>=0 ){
@@ -68305,12 +69870,12 @@ static const void *columnName(
** Return the name of the Nth column of the result set returned by SQL
** statement pStmt.
*/
-SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
}
@@ -68330,12 +69895,12 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
** Return the column declaration type (if applicable) of the 'i'th column
** of the result set of SQL statement pStmt.
*/
-SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
}
@@ -68348,12 +69913,12 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
** NULL is returned if the result column is an expression or constant or
** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
}
@@ -68364,12 +69929,12 @@ SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N
** NULL is returned if the result column is an expression or constant or
** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
}
@@ -68380,12 +69945,12 @@ SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
** NULL is returned if the result column is an expression or constant or
** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
}
@@ -68486,7 +70051,7 @@ static int bindText(
/*
** Bind a blob value to an SQL statement variable.
*/
-SQLITE_API int sqlite3_bind_blob(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(
sqlite3_stmt *pStmt,
int i,
const void *zData,
@@ -68495,7 +70060,7 @@ SQLITE_API int sqlite3_bind_blob(
){
return bindText(pStmt, i, zData, nData, xDel, 0);
}
-SQLITE_API int sqlite3_bind_blob64(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
sqlite3_stmt *pStmt,
int i,
const void *zData,
@@ -68509,7 +70074,7 @@ SQLITE_API int sqlite3_bind_blob64(
return bindText(pStmt, i, zData, (int)nData, xDel, 0);
}
}
-SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -68519,10 +70084,10 @@ SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
}
return rc;
}
-SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
return sqlite3_bind_int64(p, i, (i64)iValue);
}
-SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -68532,7 +70097,7 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu
}
return rc;
}
-SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
int rc;
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, i);
@@ -68541,7 +70106,7 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
}
return rc;
}
-SQLITE_API int sqlite3_bind_text(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(
sqlite3_stmt *pStmt,
int i,
const char *zData,
@@ -68550,7 +70115,7 @@ SQLITE_API int sqlite3_bind_text(
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
-SQLITE_API int sqlite3_bind_text64(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(
sqlite3_stmt *pStmt,
int i,
const char *zData,
@@ -68567,7 +70132,7 @@ SQLITE_API int sqlite3_bind_text64(
}
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API int sqlite3_bind_text16(
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
sqlite3_stmt *pStmt,
int i,
const void *zData,
@@ -68577,7 +70142,7 @@ SQLITE_API int sqlite3_bind_text16(
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
int rc;
switch( sqlite3_value_type((sqlite3_value*)pValue) ){
case SQLITE_INTEGER: {
@@ -68608,7 +70173,7 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu
}
return rc;
}
-SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -68623,7 +70188,7 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
** Return the number of wildcards that can be potentially bound to.
** This routine is added to support DBD::SQLite.
*/
-SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p ? p->nVar : 0;
}
@@ -68634,7 +70199,7 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
**
** The result is always UTF-8.
*/
-SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt;
if( p==0 || i<1 || i>p->nzVar ){
return 0;
@@ -68662,7 +70227,7 @@ SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nNa
}
return 0;
}
-SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
}
@@ -68696,7 +70261,7 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt
** an SQLITE_ERROR is returned. Nothing else can go wrong, so otherwise
** SQLITE_OK is returned.
*/
-SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
Vdbe *pFrom = (Vdbe*)pFromStmt;
Vdbe *pTo = (Vdbe*)pToStmt;
if( pFrom->nVar!=pTo->nVar ){
@@ -68718,7 +70283,7 @@ SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *
** the first argument to the sqlite3_prepare() that was used to create
** the statement in the first place.
*/
-SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->db : 0;
}
@@ -68726,14 +70291,14 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
** Return true if the prepared statement is guaranteed to not modify the
** database.
*/
-SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
}
/*
** Return true if the prepared statement is in need of being reset.
*/
-SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN;
}
@@ -68744,8 +70309,14 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
** prepared statement for the database connection. Return NULL if there
** are no more.
*/
-SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
+SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
sqlite3_stmt *pNext;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(pDb) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(pDb->mutex);
if( pStmt==0 ){
pNext = (sqlite3_stmt*)pDb->pVdbe;
@@ -68759,13 +70330,89 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
/*
** Return the value of a status counter for a prepared statement
*/
-SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
- u32 v = pVdbe->aCounter[op];
+ u32 v;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !pStmt ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ v = pVdbe->aCounter[op];
if( resetFlag ) pVdbe->aCounter[op] = 0;
return (int)v;
}
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+/*
+** Return status data for a single loop within query pStmt.
+*/
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+ sqlite3_stmt *pStmt, /* Prepared statement being queried */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Which metric to return */
+ void *pOut /* OUT: Write the answer here */
+){
+ Vdbe *p = (Vdbe*)pStmt;
+ ScanStatus *pScan;
+ if( idx<0 || idx>=p->nScan ) return 1;
+ pScan = &p->aScan[idx];
+ switch( iScanStatusOp ){
+ case SQLITE_SCANSTAT_NLOOP: {
+ *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop];
+ break;
+ }
+ case SQLITE_SCANSTAT_NVISIT: {
+ *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit];
+ break;
+ }
+ case SQLITE_SCANSTAT_EST: {
+ double r = 1.0;
+ LogEst x = pScan->nEst;
+ while( x<100 ){
+ x += 10;
+ r *= 0.5;
+ }
+ *(double*)pOut = r*sqlite3LogEstToInt(x);
+ break;
+ }
+ case SQLITE_SCANSTAT_NAME: {
+ *(const char**)pOut = pScan->zName;
+ break;
+ }
+ case SQLITE_SCANSTAT_EXPLAIN: {
+ if( pScan->addrExplain ){
+ *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+ }else{
+ *(const char**)pOut = 0;
+ }
+ break;
+ }
+ case SQLITE_SCANSTAT_SELECTID: {
+ if( pScan->addrExplain ){
+ *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+ }else{
+ *(int*)pOut = -1;
+ }
+ break;
+ }
+ default: {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
+*/
+SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
+ Vdbe *p = (Vdbe*)pStmt;
+ memset(p->anExec, 0, p->nOp * sizeof(i64));
+}
+#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
+
/************** End of vdbeapi.c *********************************************/
/************** Begin file vdbetrace.c ***************************************/
/*
@@ -69259,7 +70906,7 @@ static void applyAffinity(
** is appropriate. But only do the conversion if it is possible without
** loss of information and return the revised type of the argument.
*/
-SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
+SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value *pVal){
int eType = sqlite3_value_type(pVal);
if( eType==SQLITE_TEXT ){
Mem *pMem = (Mem*)pVal;
@@ -69651,6 +71298,9 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
#endif
nVmStep++;
pOp = &aOp[pc];
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ if( p->anExec ) p->anExec[pc]++;
+#endif
/* Only allow tracing if SQLITE_DEBUG is defined.
*/
@@ -70055,7 +71705,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
** Synopsis: r[P2]='P4'
**
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
-** into a String before it is executed for the first time. During
+** into a String opcode before it is executed for the first time. During
** this transformation, the length of string P4 is computed and stored
** as the P1 parameter.
*/
@@ -70087,10 +71737,15 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
/* Fall through to the next case, OP_String */
}
-/* Opcode: String P1 P2 * P4 *
+/* Opcode: String P1 P2 P3 P4 P5
** Synopsis: r[P2]='P4' (len=P1)
**
** The string value P4 of length P1 (bytes) is stored in register P2.
+**
+** If P5!=0 and the content of register P3 is greater than zero, then
+** the datatype of the register P2 is converted to BLOB. The content is
+** the same sequence of bytes, it is merely interpreted as a BLOB instead
+** of a string, as if it had been CAST.
*/
case OP_String: { /* out2-prerelease */
assert( pOp->p4.z!=0 );
@@ -70099,6 +71754,13 @@ case OP_String: { /* out2-prerelease */
pOut->n = pOp->p1;
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
+ if( pOp->p5 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=(p->nMem-p->nCursor) );
+ pIn3 = &aMem[pOp->p3];
+ assert( pIn3->flags & MEM_Int );
+ if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
+ }
break;
}
@@ -70545,7 +72207,7 @@ arithmetic_result_is_null:
**
** The interface used by the implementation of the aforementioned functions
** to retrieve the collation sequence set by this opcode is not available
-** publicly, only to user functions defined in func.c.
+** publicly. Only built-in functions have access to this feature.
*/
case OP_CollSeq: {
assert( pOp->p4type==P4_COLLSEQ );
@@ -70948,11 +72610,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
sqlite3VdbeMemStringify(pIn1, encoding, 1);
+ testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
+ flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
}
if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
sqlite3VdbeMemStringify(pIn3, encoding, 1);
+ testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );
+ flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
}
}
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
@@ -70989,7 +72655,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}
}
/* Undo any changes made by applyAffinity() to the input registers. */
+ assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
pIn1->flags = flags1;
+ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
pIn3->flags = flags3;
break;
}
@@ -71676,7 +73344,10 @@ case OP_MakeRecord: {
nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
}while( (--pRec)>=pData0 );
- /* Add the initial header varint and total the size */
+ /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
+ ** which determines the total number of bytes in the header. The varint
+ ** value is the size of the header in bytes including the size varint
+ ** itself. */
testcase( nHdr==126 );
testcase( nHdr==127 );
if( nHdr<=126 ){
@@ -71710,7 +73381,11 @@ case OP_MakeRecord: {
pRec = pData0;
do{
serial_type = pRec->uTemp;
+ /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more
+ ** additional varints, one per column. */
i += putVarint32(&zNewRecord[i], serial_type); /* serial type */
+ /* EVIDENCE-OF: R-64536-51728 The values for each column in the record
+ ** immediately follow the header. */
j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
}while( (++pRec)<=pLast );
assert( i==nHdr );
@@ -72083,7 +73758,12 @@ case OP_Transaction: {
p->nStmtDefImmCons = db->nDeferredImmCons;
}
- /* Gather the schema version number for checking */
+ /* Gather the schema version number for checking:
+ ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite
+ ** each time a query is executed to ensure that the internal cache of the
+ ** schema used when compiling the SQL query matches the schema of the
+ ** database against which the compiled query is actually executed.
+ */
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
}else{
@@ -72251,31 +73931,29 @@ case OP_SetCookie: { /* in3 */
** See also OpenRead.
*/
case OP_ReopenIdx: {
+ int nField;
+ KeyInfo *pKeyInfo;
+ int p2;
+ int iDb;
+ int wrFlag;
+ Btree *pX;
VdbeCursor *pCur;
+ Db *pDb;
- assert( pOp->p5==0 );
+ assert( pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
assert( pOp->p4type==P4_KEYINFO );
pCur = p->apCsr[pOp->p1];
if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){
assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */
- break;
+ goto open_cursor_set_hints;
}
/* If the cursor is not currently open or is open on a different
** index, then fall through into OP_OpenRead to force a reopen */
-}
case OP_OpenRead:
-case OP_OpenWrite: {
- int nField;
- KeyInfo *pKeyInfo;
- int p2;
- int iDb;
- int wrFlag;
- Btree *pX;
- VdbeCursor *pCur;
- Db *pDb;
+case OP_OpenWrite:
- assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
- assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
+ assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 );
+ assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
assert( p->bIsReader );
assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
|| p->readOnly==0 );
@@ -72338,14 +74016,17 @@ case OP_OpenWrite: {
pCur->pgnoRoot = p2;
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
pCur->pKeyInfo = pKeyInfo;
- assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
- sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR));
-
/* Set the VdbeCursor.isTable variable. Previous versions of
** SQLite used to check if the root-page flags were sane at this point
** and report database corruption if they were not, but this check has
** since moved into the btree layer. */
pCur->isTable = pOp->p4type!=P4_KEYINFO;
+
+open_cursor_set_hints:
+ assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
+ assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
+ sqlite3BtreeCursorHints(pCur->pCursor,
+ (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
break;
}
@@ -72606,6 +74287,22 @@ case OP_SeekGT: { /* jump, in3 */
#ifdef SQLITE_DEBUG
pC->seekOp = pOp->opcode;
#endif
+
+ /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
+ ** OP_SeekLE opcodes are allowed, and these must be immediately followed
+ ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
+ */
+#ifdef SQLITE_DEBUG
+ if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
+ assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
+ assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
+ assert( pOp[1].p1==pOp[0].p1 );
+ assert( pOp[1].p2==pOp[0].p2 );
+ assert( pOp[1].p3==pOp[0].p3 );
+ assert( pOp[1].p4.i==pOp[0].p4.i );
+ }
+#endif
+
if( pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
@@ -72845,10 +74542,10 @@ case OP_Found: { /* jump, in3 */
}else{
pIdxKey = sqlite3VdbeAllocUnpackedRecord(
pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
- );
+ );
if( pIdxKey==0 ) goto no_mem;
assert( pIn3->flags & MEM_Blob );
- assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
+ ExpandBlob(pIn3);
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
}
pIdxKey->default_rc = 0;
@@ -72856,8 +74553,8 @@ case OP_Found: { /* jump, in3 */
/* For the OP_NoConflict opcode, take the jump if any of the
** input fields are NULL, since any key with a NULL will not
** conflict */
- for(ii=0; ii<r.nField; ii++){
- if( r.aMem[ii].flags & MEM_Null ){
+ for(ii=0; ii<pIdxKey->nField; ii++){
+ if( pIdxKey->aMem[ii].flags & MEM_Null ){
pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
break;
}
@@ -73542,9 +75239,9 @@ case OP_Sort: { /* jump */
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
-** If the table or index is empty and P2>0, then jump immediately to P2.
-** If P2 is 0 or if the table or index is not empty, fall through
-** to the following instruction.
+** If the table or index is empty, jump immediately to P2.
+** If the table or index is not empty, fall through to the following
+** instruction.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
@@ -73945,30 +75642,15 @@ case OP_IdxGE: { /* jump */
*/
case OP_Destroy: { /* out2-prerelease */
int iMoved;
- int iCnt;
- Vdbe *pVdbe;
int iDb;
assert( p->readOnly==0 );
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- iCnt = 0;
- for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){
- if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->bIsReader
- && pVdbe->inVtabMethod<2 && pVdbe->pc>=0
- ){
- iCnt++;
- }
- }
-#else
- iCnt = db->nVdbeRead;
-#endif
pOut->flags = MEM_Null;
- if( iCnt>1 ){
+ if( db->nVdbeRead > db->nVDestroy+1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
iDb = pOp->p3;
- assert( iCnt==1 );
assert( DbMaskTest(p->btreeMask, iDb) );
iMoved = 0; /* Not needed. Only to silence a warning. */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
@@ -74460,6 +76142,9 @@ case OP_Program: { /* jump */
pFrame->token = pProgram->token;
pFrame->aOnceFlag = p->aOnceFlag;
pFrame->nOnceFlag = p->nOnceFlag;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pFrame->anExec = p->anExec;
+#endif
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
@@ -74477,6 +76162,7 @@ case OP_Program: { /* jump */
pFrame->pParent = p->pFrame;
pFrame->lastRowid = lastRowid;
pFrame->nChange = p->nChange;
+ pFrame->nDbChange = p->db->nChange;
p->nChange = 0;
p->pFrame = pFrame;
p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
@@ -74487,6 +76173,9 @@ case OP_Program: { /* jump */
p->nOp = pProgram->nOp;
p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
p->nOnceFlag = pProgram->nOnce;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ p->anExec = 0;
+#endif
pc = -1;
memset(p->aOnceFlag, 0, p->nOnceFlag);
@@ -74594,10 +76283,12 @@ case OP_MemMax: { /* in2 */
/* Opcode: IfPos P1 P2 * * *
** Synopsis: if r[P1]>0 goto P2
**
-** If the value of register P1 is 1 or greater, jump to P2.
+** Register P1 must contain an integer.
+** If the value of register P1 is 1 or greater, jump to P2 and
+** add the literal value P3 to register P1.
**
-** It is illegal to use this instruction on a register that does
-** not contain an integer. An assertion fault will result if you try.
+** If the initial value of register P1 is less than 1, then the
+** value is unchanged and control passes through to the next instruction.
*/
case OP_IfPos: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
@@ -74626,16 +76317,34 @@ case OP_IfNeg: { /* jump, in1 */
break;
}
-/* Opcode: IfZero P1 P2 P3 * *
-** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2
+/* Opcode: IfNotZero P1 P2 P3 * *
+** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2
**
-** The register P1 must contain an integer. Add literal P3 to the
-** value in register P1. If the result is exactly 0, jump to P2.
+** Register P1 must contain an integer. If the content of register P1 is
+** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is
+** initially zero, leave it unchanged and fall through.
*/
-case OP_IfZero: { /* jump, in1 */
+case OP_IfNotZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
- pIn1->u.i += pOp->p3;
+ VdbeBranchTaken(pIn1->u.i<0, 2);
+ if( pIn1->u.i ){
+ pIn1->u.i += pOp->p3;
+ pc = pOp->p2 - 1;
+ }
+ break;
+}
+
+/* Opcode: DecrJumpZero P1 P2 * * *
+** Synopsis: if (--r[P1])==0 goto P2
+**
+** Register P1 must hold an integer. Decrement the value in register P1
+** then jump to P2 if the new value is exactly zero.
+*/
+case OP_DecrJumpZero: { /* jump, in1 */
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags&MEM_Int );
+ pIn1->u.i--;
VdbeBranchTaken(pIn1->u.i==0, 2);
if( pIn1->u.i==0 ){
pc = pOp->p2 - 1;
@@ -74643,6 +76352,24 @@ case OP_IfZero: { /* jump, in1 */
break;
}
+
+/* Opcode: JumpZeroIncr P1 P2 * * *
+** Synopsis: if (r[P1]++)==0 ) goto P2
+**
+** The register P1 must contain an integer. If register P1 is initially
+** zero, then jump to P2. Increment register P1 regardless of whether or
+** not the jump is taken.
+*/
+case OP_JumpZeroIncr: { /* jump, in1 */
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags&MEM_Int );
+ VdbeBranchTaken(pIn1->u.i==0, 2);
+ if( (pIn1->u.i++)==0 ){
+ pc = pOp->p2 - 1;
+ }
+ break;
+}
+
/* Opcode: AggStep * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
@@ -74731,8 +76458,8 @@ case OP_AggFinal: {
/* Opcode: Checkpoint P1 P2 P3 * *
**
** Checkpoint database P1. This is a no-op if P1 is not currently in
-** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL
-** or RESTART. Write 1 or 0 into mem[P3] if the checkpoint returns
+** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL,
+** RESTART, or TRUNCATE. Write 1 or 0 into mem[P3] if the checkpoint returns
** SQLITE_BUSY or not, respectively. Write the number of pages in the
** WAL after the checkpoint into mem[P3+1] and the number of pages
** in the WAL that have been checkpointed after the checkpoint
@@ -74750,6 +76477,7 @@ case OP_Checkpoint: {
assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
|| pOp->p2==SQLITE_CHECKPOINT_FULL
|| pOp->p2==SQLITE_CHECKPOINT_RESTART
+ || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE
);
rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
if( rc==SQLITE_BUSY ){
@@ -74979,13 +76707,29 @@ case OP_VBegin: {
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VCreate P1 * * P4 *
+/* Opcode: VCreate P1 P2 * * *
**
-** P4 is the name of a virtual table in database P1. Call the xCreate method
-** for that table.
+** P2 is a register that holds the name of a virtual table in database
+** P1. Call the xCreate method for that table.
*/
case OP_VCreate: {
- rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p4.z, &p->zErrMsg);
+ Mem sMem; /* For storing the record being decoded */
+ const char *zTab; /* Name of the virtual table */
+
+ memset(&sMem, 0, sizeof(sMem));
+ sMem.db = db;
+ /* Because P2 is always a static string, it is impossible for the
+ ** sqlite3VdbeMemCopy() to fail */
+ assert( (aMem[pOp->p2].flags & MEM_Str)!=0 );
+ assert( (aMem[pOp->p2].flags & MEM_Static)!=0 );
+ rc = sqlite3VdbeMemCopy(&sMem, &aMem[pOp->p2]);
+ assert( rc==SQLITE_OK );
+ zTab = (const char*)sqlite3_value_text(&sMem);
+ assert( zTab || db->mallocFailed );
+ if( zTab ){
+ rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg);
+ }
+ sqlite3VdbeMemRelease(&sMem);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -74997,9 +76741,9 @@ case OP_VCreate: {
** of that table.
*/
case OP_VDestroy: {
- p->inVtabMethod = 2;
+ db->nVDestroy++;
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
- p->inVtabMethod = 0;
+ db->nVDestroy--;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -75015,14 +76759,17 @@ case OP_VOpen: {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
- sqlite3_module *pModule;
+ const sqlite3_module *pModule;
assert( p->bIsReader );
pCur = 0;
pVtabCursor = 0;
pVtab = pOp->p4.pVtab->pVtab;
- pModule = (sqlite3_module *)pVtab->pModule;
- assert(pVtab && pModule);
+ if( pVtab==0 || NEVER(pVtab->pModule==0) ){
+ rc = SQLITE_LOCKED;
+ break;
+ }
+ pModule = pVtab->pModule;
rc = pModule->xOpen(pVtab, &pVtabCursor);
sqlite3VtabImportErrmsg(p, pVtab);
if( SQLITE_OK==rc ){
@@ -75033,6 +76780,7 @@ case OP_VOpen: {
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
+ pVtab->nRef++;
}else{
db->mallocFailed = 1;
pModule->xClose(pVtabCursor);
@@ -75098,9 +76846,7 @@ case OP_VFilter: { /* jump */
apArg[i] = &pArgc[i+1];
}
- p->inVtabMethod = 1;
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
- p->inVtabMethod = 0;
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pVtabCursor);
@@ -75190,9 +76936,7 @@ case OP_VNext: { /* jump */
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
- p->inVtabMethod = 1;
rc = pModule->xNext(pCur->pVtabCursor);
- p->inVtabMethod = 0;
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
@@ -75267,7 +77011,7 @@ case OP_VRename: {
*/
case OP_VUpdate: {
sqlite3_vtab *pVtab;
- sqlite3_module *pModule;
+ const sqlite3_module *pModule;
int nArg;
int i;
sqlite_int64 rowid;
@@ -75279,7 +77023,11 @@ case OP_VUpdate: {
);
assert( p->readOnly==0 );
pVtab = pOp->p4.pVtab->pVtab;
- pModule = (sqlite3_module *)pVtab->pModule;
+ if( pVtab==0 || NEVER(pVtab->pModule==0) ){
+ rc = SQLITE_LOCKED;
+ break;
+ }
+ pModule = pVtab->pModule;
nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
if( ALWAYS(pModule->xUpdate) ){
@@ -75626,7 +77374,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
/*
** Open a blob handle.
*/
-SQLITE_API int sqlite3_blob_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3* db, /* The database connection */
const char *zDb, /* The attached database containing the blob */
const char *zTable, /* The table containing the blob */
@@ -75675,8 +77423,18 @@ SQLITE_API int sqlite3_blob_open(
Parse *pParse = 0;
Incrblob *pBlob = 0;
- flags = !!flags; /* flags = (flags ? 1 : 0); */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppBlob==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
*ppBlob = 0;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ flags = !!flags; /* flags = (flags ? 1 : 0); */
sqlite3_mutex_enter(db->mutex);
@@ -75853,7 +77611,7 @@ blob_open_out:
** Close a blob handle that was previously created using
** sqlite3_blob_open().
*/
-SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
int rc;
sqlite3 *db;
@@ -75890,10 +77648,9 @@ static int blobReadWrite(
sqlite3_mutex_enter(db->mutex);
v = (Vdbe*)p->pStmt;
- if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
+ if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){
/* Request is out of range. Return a transient error. */
rc = SQLITE_ERROR;
- sqlite3Error(db, SQLITE_ERROR);
}else if( v==0 ){
/* If there is no statement handle, then the blob-handle has
** already been invalidated. Return SQLITE_ABORT in this case.
@@ -75911,10 +77668,10 @@ static int blobReadWrite(
sqlite3VdbeFinalize(v);
p->pStmt = 0;
}else{
- db->errCode = rc;
v->rc = rc;
}
}
+ sqlite3Error(db, rc);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -75923,14 +77680,14 @@ static int blobReadWrite(
/*
** Read data from a blob handle.
*/
-SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
}
/*
** Write data to a blob handle.
*/
-SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
}
@@ -75940,7 +77697,7 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
*/
-SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
return (p && p->pStmt) ? p->nByte : 0;
}
@@ -75955,7 +77712,7 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
** immediately return SQLITE_ABORT.
*/
-SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
int rc;
Incrblob *p = (Incrblob *)pBlob;
sqlite3 *db;
@@ -76091,7 +77848,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
** The sorter is running in multi-threaded mode if (a) the library was built
** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater
** than zero, and (b) worker threads have been enabled at runtime by calling
-** sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, ...).
+** "PRAGMA threads=N" with some value of N greater than 0.
**
** When Rewind() is called, any data remaining in memory is flushed to a
** final PMA. So at this point the data is stored in some number of sorted
@@ -76137,6 +77894,13 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
#endif
/*
+** Hard-coded maximum amount of data to accumulate in memory before flushing
+** to a level 0 PMA. The purpose of this limit is to prevent various integer
+** overflows. 512MiB.
+*/
+#define SQLITE_MAX_PMASZ (1<<29)
+
+/*
** Private objects used by the sorter
*/
typedef struct MergeEngine MergeEngine; /* Merge PMAs together */
@@ -76430,9 +78194,6 @@ struct SorterRecord {
*/
#define SRVAL(p) ((void*)((SorterRecord*)(p) + 1))
-/* The minimum PMA size is set to this value multiplied by the database
-** page size in bytes. */
-#define SORTER_MIN_WORKING 10
/* Maximum number of PMAs that a single MergeEngine can merge */
#define SORTER_MAX_MERGE_COUNT 16
@@ -76831,16 +78592,15 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
if( !sqlite3TempInMemory(db) ){
- pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz;
+ u32 szPma = sqlite3GlobalConfig.szPma;
+ pSorter->mnPmaSize = szPma * pgsz;
mxCache = db->aDb[0].pSchema->cache_size;
- if( mxCache<SORTER_MIN_WORKING ) mxCache = SORTER_MIN_WORKING;
- pSorter->mxPmaSize = mxCache * pgsz;
-
- /* If the application has not configure scratch memory using
- ** SQLITE_CONFIG_SCRATCH then we assume it is OK to do large memory
- ** allocations. If scratch memory has been configured, then assume
- ** large memory allocations should be avoided to prevent heap
- ** fragmentation.
+ if( mxCache<(int)szPma ) mxCache = (int)szPma;
+ pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
+
+ /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
+ ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
+ ** large heap allocations.
*/
if( sqlite3GlobalConfig.pScratch==0 ){
assert( pSorter->iMemory==0 );
@@ -77114,12 +78874,12 @@ SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
*/
static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){
- int rc = sqlite3OsTruncate(pFd, nByte);
- if( rc==SQLITE_OK ){
- void *p = 0;
- sqlite3OsFetch(pFd, 0, (int)nByte, &p);
- sqlite3OsUnfetch(pFd, 0, p);
- }
+ void *p = 0;
+ int chunksize = 4*1024;
+ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
+ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
+ sqlite3OsFetch(pFd, 0, (int)nByte, &p);
+ sqlite3OsUnfetch(pFd, 0, p);
}
}
#else
@@ -77137,6 +78897,7 @@ static int vdbeSorterOpenTempFile(
sqlite3_file **ppFd
){
int rc;
+ if( sqlite3FaultSim(202) ) return SQLITE_IOERR_ACCESS;
rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd,
SQLITE_OPEN_TEMP_JOURNAL |
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
@@ -78400,6 +80161,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in
}else
#endif
/*if( !pSorter->bUseThreads )*/ {
+ assert( pSorter->pMerger!=0 );
assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
}
@@ -79212,7 +80974,7 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
** is a helper function - a callback for the tree walker.
*/
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
- if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.i;
+ if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
return WRC_Continue;
}
static void incrAggFunctionDepth(Expr *pExpr, int N){
@@ -79220,7 +80982,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
Walker w;
memset(&w, 0, sizeof(w));
w.xExprCallback = incrAggDepth;
- w.u.i = N;
+ w.u.n = N;
sqlite3WalkExpr(&w, pExpr);
}
}
@@ -79431,9 +81193,10 @@ static int lookupName(
testcase( pNC->ncFlags & NC_PartIdx );
testcase( pNC->ncFlags & NC_IsCheck );
if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){
- /* Silently ignore database qualifiers inside CHECK constraints and partial
- ** indices. Do not raise errors because that might break legacy and
- ** because it does not hurt anything to just ignore the database name. */
+ /* Silently ignore database qualifiers inside CHECK constraints and
+ ** partial indices. Do not raise errors because that might break
+ ** legacy and because it does not hurt anything to just ignore the
+ ** database name. */
zDb = 0;
}else{
for(i=0; i<db->nDb; i++){
@@ -79504,6 +81267,11 @@ static int lookupName(
if( pMatch ){
pExpr->iTable = pMatch->iCursor;
pExpr->pTab = pMatch->pTab;
+ /* RIGHT JOIN not (yet) supported */
+ assert( (pMatch->jointype & JT_RIGHT)==0 );
+ if( (pMatch->jointype & JT_LEFT)!=0 ){
+ ExprSetProperty(pExpr, EP_CanBeNull);
+ }
pSchema = pExpr->pTab->pSchema;
}
} /* if( pSrcList ) */
@@ -79768,7 +81536,7 @@ static int exprProbability(Expr *p){
sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8);
assert( r>=0.0 );
if( r>1.0 ) return -1;
- return (int)(r*1000.0);
+ return (int)(r*134217728.0);
}
/*
@@ -79821,7 +81589,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->affinity = SQLITE_AFF_INTEGER;
break;
}
-#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */
+#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
+ && !defined(SQLITE_OMIT_SUBQUERY) */
/* A lone identifier is the name of a column.
*/
@@ -79886,21 +81655,22 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( n==2 ){
pExpr->iTable = exprProbability(pList->a[1].pExpr);
if( pExpr->iTable<0 ){
- sqlite3ErrorMsg(pParse, "second argument to likelihood() must be a "
- "constant between 0.0 and 1.0");
+ sqlite3ErrorMsg(pParse,
+ "second argument to likelihood() must be a "
+ "constant between 0.0 and 1.0");
pNC->nErr++;
}
}else{
- /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to
- ** likelihood(X, 0.0625).
- ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for
- ** likelihood(X,0.0625).
- ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for
- ** likelihood(X,0.9375).
- ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to
- ** likelihood(X,0.9375). */
+ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is
+ ** equivalent to likelihood(X, 0.0625).
+ ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is
+ ** short-hand for likelihood(X,0.0625).
+ ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand
+ ** for likelihood(X,0.9375).
+ ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent
+ ** to likelihood(X,0.9375). */
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
- pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
+ pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120;
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -79915,7 +81685,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
return WRC_Prune;
}
#endif
- if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
+ if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){
+ ExprSetProperty(pExpr,EP_ConstFunc);
+ }
}
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
@@ -80226,7 +81998,8 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
return 1;
}
- resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, zType,0);
+ resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,
+ zType,0);
}
}
return 0;
@@ -80359,6 +82132,20 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
sqlite3ResolveExprNames(&sNC, p->pOffset) ){
return WRC_Abort;
}
+
+ /* If the SF_Converted flags is set, then this Select object was
+ ** was created by the convertCompoundSelectToSubquery() function.
+ ** In this case the ORDER BY clause (p->pOrderBy) should be resolved
+ ** as if it were part of the sub-query, not the parent. This block
+ ** moves the pOrderBy down to the sub-query. It will be moved back
+ ** after the names have been resolved. */
+ if( p->selFlags & SF_Converted ){
+ Select *pSub = p->pSrc->a[0].pSelect;
+ assert( p->pSrc->nSrc==1 && isCompound==0 && p->pOrderBy );
+ assert( pSub->pPrior && pSub->pOrderBy==0 );
+ pSub->pOrderBy = p->pOrderBy;
+ p->pOrderBy = 0;
+ }
/* Recursively resolve names in all subqueries
*/
@@ -80441,6 +82228,17 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
sNC.pNext = 0;
sNC.ncFlags |= NC_AllowAgg;
+ /* If this is a converted compound query, move the ORDER BY clause from
+ ** the sub-query back to the parent query. At this point each term
+ ** within the ORDER BY clause has been transformed to an integer value.
+ ** These integers will be replaced by copies of the corresponding result
+ ** set expressions by the call to resolveOrderGroupBy() below. */
+ if( p->selFlags & SF_Converted ){
+ Select *pSub = p->pSrc->a[0].pSelect;
+ p->pOrderBy = pSub->pOrderBy;
+ pSub->pOrderBy = 0;
+ }
+
/* Process the ORDER BY clause for singleton SELECT statements.
** The ORDER BY clause for compounds SELECT statements is handled
** below, after all of the result-sets for all of the elements of
@@ -80716,10 +82514,11 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
- const Token *pCollName /* Name of collating sequence */
+ const Token *pCollName, /* Name of collating sequence */
+ int dequote /* True to dequote pCollName */
){
if( pCollName->n>0 ){
- Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
+ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote);
if( pNew ){
pNew->pLeft = pExpr;
pNew->flags |= EP_Collate|EP_Skip;
@@ -80733,7 +82532,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con
assert( zC!=0 );
s.z = zC;
s.n = sqlite3Strlen30(s.z);
- return sqlite3ExprAddCollateToken(pParse, pExpr, &s);
+ return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
}
/*
@@ -80779,9 +82578,9 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
}
- if( p->pTab!=0
- && (op==TK_AGG_COLUMN || op==TK_COLUMN
+ if( (op==TK_AGG_COLUMN || op==TK_COLUMN
|| op==TK_REGISTER || op==TK_TRIGGER)
+ && p->pTab!=0
){
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
** a TK_COLUMN but was previously evaluated and cached in a register */
@@ -80793,10 +82592,25 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
break;
}
if( p->flags & EP_Collate ){
- if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){
+ if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){
p = p->pLeft;
}else{
- p = p->pRight;
+ Expr *pNext = p->pRight;
+ /* The Expr.x union is never used at the same time as Expr.pRight */
+ assert( p->x.pList==0 || p->pRight==0 );
+ /* p->flags holds EP_Collate and p->pLeft->flags does not. And
+ ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at
+ ** least one EP_Collate. Thus the following two ALWAYS. */
+ if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){
+ int i;
+ for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
+ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
+ pNext = p->x.pList->a[i].pExpr;
+ break;
+ }
+ }
+ }
+ p = pNext;
}
}else{
break;
@@ -81002,6 +82816,9 @@ static void heightOfSelect(Select *p, int *pnHeight){
** Expr.pSelect member has a height of 1. Any other expression
** has a height equal to the maximum height of any other
** referenced Expr plus one.
+**
+** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
+** if appropriate.
*/
static void exprSetHeight(Expr *p){
int nHeight = 0;
@@ -81009,8 +82826,9 @@ static void exprSetHeight(Expr *p){
heightOfExpr(p->pRight, &nHeight);
if( ExprHasProperty(p, EP_xIsSelect) ){
heightOfSelect(p->x.pSelect, &nHeight);
- }else{
+ }else if( p->x.pList ){
heightOfExprList(p->x.pList, &nHeight);
+ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
}
p->nHeight = nHeight + 1;
}
@@ -81019,8 +82837,12 @@ static void exprSetHeight(Expr *p){
** Set the Expr.nHeight variable using the exprSetHeight() function. If
** the height is greater than the maximum allowed expression depth,
** leave an error in pParse.
+**
+** Also propagate all EP_Propagate flags from the Expr.x.pList into
+** Expr.flags.
*/
-SQLITE_PRIVATE void sqlite3ExprSetHeight(Parse *pParse, Expr *p){
+SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
+ if( pParse->nErr ) return;
exprSetHeight(p);
sqlite3ExprCheckHeight(pParse, p->nHeight);
}
@@ -81034,8 +82856,17 @@ SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){
heightOfSelect(p, &nHeight);
return nHeight;
}
-#else
- #define exprSetHeight(y)
+#else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */
+/*
+** Propagate all EP_Propagate flags from the Expr.x.pList into
+** Expr.flags.
+*/
+SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
+ if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){
+ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
+ }
+}
+#define exprSetHeight(y)
#endif /* SQLITE_MAX_EXPR_DEPTH>0 */
/*
@@ -81137,11 +82968,11 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(
}else{
if( pRight ){
pRoot->pRight = pRight;
- pRoot->flags |= EP_Collate & pRight->flags;
+ pRoot->flags |= EP_Propagate & pRight->flags;
}
if( pLeft ){
pRoot->pLeft = pLeft;
- pRoot->flags |= EP_Collate & pLeft->flags;
+ pRoot->flags |= EP_Propagate & pLeft->flags;
}
exprSetHeight(pRoot);
}
@@ -81162,7 +82993,7 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
const Token *pToken /* Argument token */
){
Expr *p;
- if( op==TK_AND && pLeft && pRight ){
+ if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){
/* Take advantage of short-circuit false optimization for AND */
p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
}else{
@@ -81241,7 +83072,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
}
pNew->x.pList = pList;
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
- sqlite3ExprSetHeight(pParse, pNew);
+ sqlite3ExprSetHeightAndFlags(pParse, pNew);
return pNew;
}
@@ -81857,20 +83688,39 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
}
/*
-** These routines are Walker callbacks. Walker.u.pi is a pointer
-** to an integer. These routines are checking an expression to see
-** if it is a constant. Set *Walker.u.i to 0 if the expression is
-** not constant.
+** Return the bitwise-OR of all Expr.flags fields in the given
+** ExprList.
+*/
+SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
+ int i;
+ u32 m = 0;
+ if( pList ){
+ for(i=0; i<pList->nExpr; i++){
+ m |= pList->a[i].pExpr->flags;
+ }
+ }
+ return m;
+}
+
+/*
+** These routines are Walker callbacks used to check expressions to
+** see if they are "constant" for some definition of constant. The
+** Walker.eCode value determines the type of "constant" we are looking
+** for.
**
** These callback routines are used to implement the following:
**
-** sqlite3ExprIsConstant() pWalker->u.i==1
-** sqlite3ExprIsConstantNotJoin() pWalker->u.i==2
-** sqlite3ExprIsConstantOrFunction() pWalker->u.i==3 or 4
+** sqlite3ExprIsConstant() pWalker->eCode==1
+** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2
+** sqlite3ExprRefOneTableOnly() pWalker->eCode==3
+** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5
+**
+** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
+** is found to not be a constant.
**
** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions
-** in a CREATE TABLE statement. The Walker.u.i value is 4 when parsing
-** an existing schema and 3 when processing a new statement. A bound
+** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing
+** an existing schema and 4 when processing a new statement. A bound
** parameter raises an error for new statements, but is silently converted
** to NULL for existing schemas. This allows sqlite_master tables that
** contain a bound parameter because they were generated by older versions
@@ -81879,23 +83729,25 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
*/
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
- /* If pWalker->u.i is 2 then any term of the expression that comes from
- ** the ON or USING clauses of a join disqualifies the expression
+ /* If pWalker->eCode is 2 then any term of the expression that comes from
+ ** the ON or USING clauses of a left join disqualifies the expression
** from being considered constant. */
- if( pWalker->u.i==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
- pWalker->u.i = 0;
+ if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
+ pWalker->eCode = 0;
return WRC_Abort;
}
switch( pExpr->op ){
/* Consider functions to be constant if all their arguments are constant
- ** and either pWalker->u.i==3 or 4 or the function as the SQLITE_FUNC_CONST
- ** flag. */
+ ** and either pWalker->eCode==4 or 5 or the function has the
+ ** SQLITE_FUNC_CONST flag. */
case TK_FUNCTION:
- if( pWalker->u.i>=3 || ExprHasProperty(pExpr,EP_Constant) ){
+ if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){
return WRC_Continue;
+ }else{
+ pWalker->eCode = 0;
+ return WRC_Abort;
}
- /* Fall through */
case TK_ID:
case TK_COLUMN:
case TK_AGG_FUNCTION:
@@ -81904,18 +83756,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
testcase( pExpr->op==TK_AGG_COLUMN );
- pWalker->u.i = 0;
- return WRC_Abort;
+ if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
+ return WRC_Continue;
+ }else{
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
case TK_VARIABLE:
- if( pWalker->u.i==4 ){
+ if( pWalker->eCode==5 ){
/* Silently convert bound parameters that appear inside of CREATE
** statements into a NULL when parsing the CREATE statement text out
** of the sqlite_master table */
pExpr->op = TK_NULL;
- }else if( pWalker->u.i==3 ){
+ }else if( pWalker->eCode==4 ){
/* A bound parameter in a CREATE statement that originates from
** sqlite3_prepare() causes an error */
- pWalker->u.i = 0;
+ pWalker->eCode = 0;
return WRC_Abort;
}
/* Fall through */
@@ -81927,21 +83783,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
}
static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
UNUSED_PARAMETER(NotUsed);
- pWalker->u.i = 0;
+ pWalker->eCode = 0;
return WRC_Abort;
}
-static int exprIsConst(Expr *p, int initFlag){
+static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
memset(&w, 0, sizeof(w));
- w.u.i = initFlag;
+ w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = selectNodeIsConstant;
+ w.u.iCur = iCur;
sqlite3WalkExpr(&w, p);
- return w.u.i;
+ return w.eCode;
}
/*
-** Walk an expression tree. Return 1 if the expression is constant
+** Walk an expression tree. Return non-zero if the expression is constant
** and 0 if it involves variables or function calls.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
@@ -81949,21 +83806,31 @@ static int exprIsConst(Expr *p, int initFlag){
** a constant.
*/
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){
- return exprIsConst(p, 1);
+ return exprIsConst(p, 1, 0);
}
/*
-** Walk an expression tree. Return 1 if the expression is constant
+** Walk an expression tree. Return non-zero if the expression is constant
** that does no originate from the ON or USING clauses of a join.
** Return 0 if it involves variables or function calls or terms from
** an ON or USING clause.
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
- return exprIsConst(p, 2);
+ return exprIsConst(p, 2, 0);
+}
+
+/*
+** Walk an expression tree. Return non-zero if the expression constant
+** for any single row of the table with cursor iCur. In other words, the
+** expression must not refer to any non-deterministic function nor any
+** table other than iCur.
+*/
+SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
+ return exprIsConst(p, 3, iCur);
}
/*
-** Walk an expression tree. Return 1 if the expression is constant
+** Walk an expression tree. Return non-zero if the expression is constant
** or a function call with constant arguments. Return and 0 if there
** are any variables.
**
@@ -81973,7 +83840,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
assert( isInit==0 || isInit==1 );
- return exprIsConst(p, 3+isInit);
+ return exprIsConst(p, 4+isInit, 0);
}
/*
@@ -82040,7 +83907,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
return 0;
case TK_COLUMN:
assert( p->pTab!=0 );
- return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
+ return ExprHasProperty(p, EP_CanBeNull) ||
+ (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
}
@@ -82881,7 +84749,8 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
int idxLru;
struct yColCache *p;
- assert( iReg>0 ); /* Register numbers are always positive */
+ /* Unless an error has occurred, register numbers are always positive. */
+ assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed );
assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */
/* The SQLITE_ColumnCache flag disables the column cache. This is used
@@ -83629,7 +85498,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
#ifndef SQLITE_OMIT_FLOATING_POINT
/* If the column has REAL affinity, it may currently be stored as an
- ** integer. Use OP_RealAffinity to make sure it is really real. */
+ ** integer. Use OP_RealAffinity to make sure it is really real.
+ **
+ ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to
+ ** floating point when extracting it from the record. */
if( pExpr->iColumn>=0
&& pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
){
@@ -84691,10 +86563,11 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
int i;
struct SrcCount *p = pWalker->u.pSrcCount;
SrcList *pSrc = p->pSrc;
- for(i=0; i<pSrc->nSrc; i++){
+ int nSrc = pSrc ? pSrc->nSrc : 0;
+ for(i=0; i<nSrc; i++){
if( pExpr->iTable==pSrc->a[i].iCursor ) break;
}
- if( i<pSrc->nSrc ){
+ if( i<nSrc ){
p->nThis++;
}else{
p->nOther++;
@@ -85684,7 +87557,10 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
*/
if( pDflt ){
sqlite3_value *pVal = 0;
- if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
+ int rc;
+ rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ if( rc!=SQLITE_OK ){
db->mallocFailed = 1;
return;
}
@@ -86272,7 +88148,7 @@ static void statInit(
p->mxSample = mxSample;
p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
p->current.anLt = &p->current.anEq[nColUp];
- p->iPrn = nCol*0x689e962d ^ sqlite3_value_int(argv[2])*0xd0944565;
+ p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
/* Set up the Stat4Accum.a[] and aBest[] arrays */
p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
@@ -87281,23 +89157,28 @@ static void decodeIntArray(
if( *z==' ' ) z++;
}
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
- assert( pIndex!=0 );
+ assert( pIndex!=0 ); {
#else
- if( pIndex )
+ if( pIndex ){
#endif
- while( z[0] ){
- if( sqlite3_strglob("unordered*", z)==0 ){
- pIndex->bUnordered = 1;
- }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
- }
+ pIndex->bUnordered = 0;
+ pIndex->noSkipScan = 0;
+ while( z[0] ){
+ if( sqlite3_strglob("unordered*", z)==0 ){
+ pIndex->bUnordered = 1;
+ }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
+ pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
+ }else if( sqlite3_strglob("noskipscan*", z)==0 ){
+ pIndex->noSkipScan = 1;
+ }
#ifdef SQLITE_ENABLE_COSTMULT
- else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
- pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
- }
+ else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
+ pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
+ }
#endif
- while( z[0]!=0 && z[0]!=' ' ) z++;
- while( z[0]==' ' ) z++;
+ while( z[0]!=0 && z[0]!=' ' ) z++;
+ while( z[0]==' ' ) z++;
+ }
}
}
@@ -87415,7 +89296,7 @@ static void initAvgEq(Index *pIdx){
i64 nSum100 = 0; /* Number of terms contributing to sumEq */
i64 nDist100; /* Number of distinct values in index */
- if( pIdx->aiRowEst==0 || pIdx->aiRowEst[iCol+1]==0 ){
+ if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){
nRow = pFinal->anLt[iCol];
nDist100 = (i64)100 * pFinal->anDLt[iCol];
nSample--;
@@ -87423,6 +89304,7 @@ static void initAvgEq(Index *pIdx){
nRow = pIdx->aiRowEst[0];
nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1];
}
+ pIdx->nRowEst0 = nRow;
/* Set nSum to the number of distinct (iCol+1) field prefixes that
** occur in the stat4 table for this index. Set sumEq to the sum of
@@ -87684,7 +89566,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
int lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = loadStat4(db, sInfo.zDatabase);
@@ -87859,6 +89741,7 @@ static void attachFunc(
"attached databases must use the same text encoding as main database");
rc = SQLITE_ERROR;
}
+ sqlite3BtreeEnter(aNew->pBt);
pPager = sqlite3BtreePager(aNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
sqlite3BtreeSecureDelete(aNew->pBt,
@@ -87866,6 +89749,7 @@ static void attachFunc(
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
#endif
+ sqlite3BtreeLeave(aNew->pBt);
}
aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
@@ -87898,7 +89782,7 @@ static void attachFunc(
case SQLITE_NULL:
/* No key specified. Use the key from the main database */
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){
+ if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
}
break;
@@ -88361,11 +90245,14 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
** Setting the auth function to NULL disables this hook. The default
** setting of the auth function is NULL.
*/
-SQLITE_API int sqlite3_set_authorizer(
+SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
sqlite3 *db,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pArg
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->xAuth = (sqlite3_xauth)xAuth;
db->pAuthArg = pArg;
@@ -88860,7 +90747,7 @@ SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){
SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
Table *p = 0;
int i;
- assert( zName!=0 );
+
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
#if SQLITE_USER_AUTHENTICATION
@@ -88984,7 +90871,6 @@ static void freeIndex(sqlite3 *db, Index *p){
#ifndef SQLITE_OMIT_ANALYZE
sqlite3DeleteIndexSamples(db, p);
#endif
- if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo);
sqlite3ExprDelete(db, p->pPartIdxWhere);
sqlite3DbFree(db, p->zColAff);
if( p->isResized ) sqlite3DbFree(db, p->azColl);
@@ -90263,16 +92149,32 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
pTab->iPKey = -1;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
+ /*
+ ** Remove all redundant columns from the PRIMARY KEY. For example, change
+ ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
+ ** code assumes the PRIMARY KEY contains no repeated columns.
+ */
+ for(i=j=1; i<pPk->nKeyCol; i++){
+ if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){
+ pPk->nColumn--;
+ }else{
+ pPk->aiColumn[j++] = pPk->aiColumn[i];
+ }
+ }
+ pPk->nKeyCol = j;
}
pPk->isCovering = 1;
assert( pPk!=0 );
nPk = pPk->nKeyCol;
- /* Make sure every column of the PRIMARY KEY is NOT NULL */
- for(i=0; i<nPk; i++){
- pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+ /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except,
+ ** do not enforce this for imposter tables.) */
+ if( !db->init.imposterTable ){
+ for(i=0; i<nPk; i++){
+ pTab->aCol[pPk->aiColumn[i]].notNull = 1;
+ }
+ pPk->uniqNotNull = 1;
}
- pPk->uniqNotNull = 1;
/* The root page of the PRIMARY KEY is the table root page */
pPk->tnum = pTab->tnum;
@@ -91721,6 +93623,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
pIdx->onError = pIndex->onError;
}
}
+ pRet = pIdx;
goto exit_create_index;
}
}
@@ -92739,40 +94642,31 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
** when it has finished using it.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
+ int i;
+ int nCol = pIdx->nColumn;
+ int nKey = pIdx->nKeyCol;
+ KeyInfo *pKey;
if( pParse->nErr ) return 0;
-#ifndef SQLITE_OMIT_SHARED_CACHE
- if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){
- sqlite3KeyInfoUnref(pIdx->pKeyInfo);
- pIdx->pKeyInfo = 0;
+ if( pIdx->uniqNotNull ){
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
+ }else{
+ pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
}
-#endif
- if( pIdx->pKeyInfo==0 ){
- int i;
- int nCol = pIdx->nColumn;
- int nKey = pIdx->nKeyCol;
- KeyInfo *pKey;
- if( pIdx->uniqNotNull ){
- pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey);
- }else{
- pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0);
+ if( pKey ){
+ assert( sqlite3KeyInfoIsWriteable(pKey) );
+ for(i=0; i<nCol; i++){
+ char *zColl = pIdx->azColl[i];
+ assert( zColl!=0 );
+ pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
+ sqlite3LocateCollSeq(pParse, zColl);
+ pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
- if( pKey ){
- assert( sqlite3KeyInfoIsWriteable(pKey) );
- for(i=0; i<nCol; i++){
- char *zColl = pIdx->azColl[i];
- assert( zColl!=0 );
- pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
- sqlite3LocateCollSeq(pParse, zColl);
- pKey->aSortOrder[i] = pIdx->aSortOrder[i];
- }
- if( pParse->nErr ){
- sqlite3KeyInfoUnref(pKey);
- }else{
- pIdx->pKeyInfo = pKey;
- }
+ if( pParse->nErr ){
+ sqlite3KeyInfoUnref(pKey);
+ pKey = 0;
}
}
- return sqlite3KeyInfoRef(pIdx->pKeyInfo);
+ return pKey;
}
#ifndef SQLITE_OMIT_CTE
@@ -93516,7 +95410,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
pInClause->x.pSelect = pSelect;
pInClause->flags |= EP_xIsSelect;
- sqlite3ExprSetHeight(pParse, pInClause);
+ sqlite3ExprSetHeightAndFlags(pParse, pInClause);
return pInClause;
/* something went wrong. clean up anything allocated. */
@@ -93553,8 +95447,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
int iTabCur; /* Cursor number for the table */
- int iDataCur; /* VDBE cursor for the canonical data source */
- int iIdxCur; /* Cursor number of the first index */
+ int iDataCur = 0; /* VDBE cursor for the canonical data source */
+ int iIdxCur = 0; /* Cursor number of the first index */
int nIdx; /* Number of indices */
sqlite3 *db; /* Main database structure */
AuthContext sContext; /* Authorization context */
@@ -94189,7 +96083,9 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
- VdbeOp *pOp = &context->pVdbe->aOp[context->iOp-1];
+ VdbeOp *pOp;
+ assert( context->pVdbe!=0 );
+ pOp = &context->pVdbe->aOp[context->iOp-1];
assert( pOp->opcode==OP_CollSeq );
assert( pOp->p4type==P4_COLLSEQ );
return pOp->p4.pColl;
@@ -94324,8 +96220,8 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
default: {
/* Because sqlite3_value_double() returns 0.0 if the argument is not
** something that can be converted into a number, we have:
- ** IMP: R-57326-31541 Abs(X) return 0.0 if X is a string or blob that
- ** cannot be converted to a numeric value.
+ ** IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob
+ ** that cannot be converted to a numeric value.
*/
double rVal = sqlite3_value_double(argv[0]);
if( rVal<0 ) rVal = -rVal;
@@ -94458,6 +96354,14 @@ static void substrFunc(
}
}
}
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
+ /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
+ ** as substr(X,1,N) - it returns the first N characters of X. This
+ ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
+ ** from 2009-02-02 for compatibility of applications that exploited the
+ ** old buggy behavior. */
+ if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
+#endif
if( argc==3 ){
p2 = sqlite3_value_int(argv[2]);
if( p2<0 ){
@@ -94919,7 +96823,7 @@ static int patternCompare(
/*
** The sqlite3_strglob() interface.
*/
-SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
+SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
}
@@ -95809,6 +97713,11 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
** then set aWc[0] through aWc[2] to the wildcard characters and
** return TRUE. If the function is not a LIKE-style function then
** return FALSE.
+**
+** *pIsNocase is set to true if uppercase and lowercase are equivalent for
+** the function (default for LIKE). If the function makes the distinction
+** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to
+** false.
*/
SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
@@ -96393,7 +98302,7 @@ static void fkLookupParent(
OE_Abort, 0, P4_STATIC, P5_ConstraintFK);
}else{
if( nIncr>0 && pFKey->isDeferred==0 ){
- sqlite3ParseToplevel(pParse)->mayAbort = 1;
+ sqlite3MayAbort(pParse);
}
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
}
@@ -96465,6 +98374,10 @@ static Expr *exprTableColumn(
** code for an SQL UPDATE operation, this function may be called twice -
** once to "delete" the old row and once to "insert" the new row.
**
+** Parameter nIncr is passed -1 when inserting a row (as this may decrease
+** the number of FK violations in the db) or +1 when deleting one (as this
+** may increase the number of FK constraint problems).
+**
** The code generated by this function scans through the rows in the child
** table that correspond to the parent table row being deleted or inserted.
** For each child row found, one of the following actions is taken:
@@ -96581,13 +98494,9 @@ static void fkScanChildren(
sqlite3ResolveExprNames(&sNameContext, pWhere);
/* Create VDBE to loop through the entries in pSrc that match the WHERE
- ** clause. If the constraint is not deferred, throw an exception for
- ** each row found. Otherwise, for deferred constraints, increment the
- ** deferred constraint counter by nIncr for each row selected. */
+ ** clause. For each row found, increment either the deferred or immediate
+ ** foreign key constraint counter. */
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
- if( nIncr>0 && pFKey->isDeferred==0 ){
- sqlite3ParseToplevel(pParse)->mayAbort = 1;
- }
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
if( pWInfo ){
sqlite3WhereEnd(pWInfo);
@@ -96767,6 +98676,24 @@ static int fkParentIsModified(
}
/*
+** Return true if the parser passed as the first argument is being
+** used to code a trigger that is really a "SET NULL" action belonging
+** to trigger pFKey.
+*/
+static int isSetNullAction(Parse *pParse, FKey *pFKey){
+ Parse *pTop = sqlite3ParseToplevel(pParse);
+ if( pTop->pTriggerPrg ){
+ Trigger *p = pTop->pTriggerPrg->pTrigger;
+ if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
+ || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
** This function is called when inserting, deleting or updating a row of
** table pTab to generate VDBE code to perform foreign key constraint
** processing for the operation.
@@ -96818,7 +98745,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
int *aiCol;
int iCol;
int i;
- int isIgnore = 0;
+ int bIgnore = 0;
if( aChange
&& sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
@@ -96877,7 +98804,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
int rcauth;
char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName;
rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
- isIgnore = (rcauth==SQLITE_IGNORE);
+ bIgnore = (rcauth==SQLITE_IGNORE);
}
#endif
}
@@ -96892,12 +98819,18 @@ SQLITE_PRIVATE void sqlite3FkCheck(
/* A row is being removed from the child table. Search for the parent.
** If the parent does not exist, removing the child row resolves an
** outstanding foreign key constraint violation. */
- fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1,isIgnore);
+ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore);
}
- if( regNew!=0 ){
+ if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){
/* A row is being added to the child table. If a parent row cannot
- ** be found, adding the child row has violated the FK constraint. */
- fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1,isIgnore);
+ ** be found, adding the child row has violated the FK constraint.
+ **
+ ** If this operation is being performed as part of a trigger program
+ ** that is actually a "SET NULL" action belonging to this very
+ ** foreign key, then omit this scan altogether. As all child key
+ ** values are guaranteed to be NULL, it is not possible for adding
+ ** this row to cause an FK violation. */
+ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore);
}
sqlite3DbFree(db, aiFree);
@@ -96918,8 +98851,8 @@ SQLITE_PRIVATE void sqlite3FkCheck(
&& !pParse->pToplevel && !pParse->isMultiWrite
){
assert( regOld==0 && regNew!=0 );
- /* Inserting a single row into a parent table cannot cause an immediate
- ** foreign key violation. So do nothing in this case. */
+ /* Inserting a single row into a parent table cannot cause (or fix)
+ ** an immediate foreign key violation. So do nothing in this case. */
continue;
}
@@ -96943,13 +98876,28 @@ SQLITE_PRIVATE void sqlite3FkCheck(
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
}
if( regOld!=0 ){
- /* If there is a RESTRICT action configured for the current operation
- ** on the parent table of this FK, then throw an exception
- ** immediately if the FK constraint is violated, even if this is a
- ** deferred trigger. That's what RESTRICT means. To defer checking
- ** the constraint, the FK should specify NO ACTION (represented
- ** using OE_None). NO ACTION is the default. */
+ int eAction = pFKey->aAction[aChange!=0];
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
+ /* If this is a deferred FK constraint, or a CASCADE or SET NULL
+ ** action applies, then any foreign key violations caused by
+ ** removing the parent key will be rectified by the action trigger.
+ ** So do not set the "may-abort" flag in this case.
+ **
+ ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the
+ ** may-abort flag will eventually be set on this statement anyway
+ ** (when this function is called as part of processing the UPDATE
+ ** within the action trigger).
+ **
+ ** Note 2: At first glance it may seem like SQLite could simply omit
+ ** all OP_FkCounter related scans when either CASCADE or SET NULL
+ ** applies. The trouble starts if the CASCADE or SET NULL action
+ ** trigger causes other triggers or action rules attached to the
+ ** child table to fire. In these cases the fk constraint counters
+ ** might be set incorrectly if any OP_FkCounter related scans are
+ ** omitted. */
+ if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){
+ sqlite3MayAbort(pParse);
+ }
}
pItem->zName = 0;
sqlite3SrcListDelete(db, pSrc);
@@ -99370,7 +101318,7 @@ static int xferOptimization(
** argument to xCallback(). If xCallback=NULL then no callback
** is invoked, even for queries.
*/
-SQLITE_API int sqlite3_exec(
+SQLITE_API int SQLITE_STDCALL sqlite3_exec(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
sqlite3_callback xCallback, /* Invoke this callback routine */
@@ -100043,7 +101991,6 @@ struct sqlite3_api_routines {
# define sqlite3_column_table_name16 0
# define sqlite3_column_origin_name 0
# define sqlite3_column_origin_name16 0
-# define sqlite3_table_column_metadata 0
#endif
#ifdef SQLITE_OMIT_AUTHORIZATION
@@ -100566,7 +102513,7 @@ static int sqlite3LoadExtension(
db->aExtension[db->nExtension++] = handle;
return SQLITE_OK;
}
-SQLITE_API int sqlite3_load_extension(
+SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
@@ -100597,7 +102544,7 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
** Enable or disable extension loading. Extension loading is disabled by
** default so as not to open security holes in older applications.
*/
-SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){
sqlite3_mutex_enter(db->mutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension;
@@ -100654,7 +102601,7 @@ static SQLITE_WSD struct sqlite3AutoExtList {
** Register a statically linked extension that is automatically
** loaded by every new database connection.
*/
-SQLITE_API int sqlite3_auto_extension(void (*xInit)(void)){
+SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@@ -100699,7 +102646,7 @@ SQLITE_API int sqlite3_auto_extension(void (*xInit)(void)){
** Return 1 if xInit was found on the list and removed. Return 0 if xInit
** was not on the list.
*/
-SQLITE_API int sqlite3_cancel_auto_extension(void (*xInit)(void)){
+SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -100722,7 +102669,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(void (*xInit)(void)){
/*
** Reset the automatic extension loading mechanism.
*/
-SQLITE_API void sqlite3_reset_auto_extension(void){
+SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize()==SQLITE_OK )
#endif
@@ -100804,11 +102751,18 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
#endif
/***************************************************************************
-** The next block of code, including the PragTyp_XXXX macro definitions and
-** the aPragmaName[] object is composed of generated code. DO NOT EDIT.
-**
-** To add new pragmas, edit the code in ../tool/mkpragmatab.tcl and rerun
-** that script. Then copy/paste the output in place of the following:
+** The "pragma.h" include file is an automatically generated file that
+** that includes the PragType_XXXX macro definitions and the aPragmaName[]
+** object. This ensures that the aPragmaName[] table is arranged in
+** lexicographical order to facility a binary search of the pragma name.
+** Do not edit pragma.h directly. Edit and rerun the script in at
+** ../tool/mkpragmatab.tcl. */
+/************** Include pragma.h in the middle of pragma.c *******************/
+/************** Begin file pragma.h ******************************************/
+/* DO NOT EDIT!
+** This file is automatically generated by the script at
+** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
+** that script and rerun it.
*/
#define PragTyp_HEADER_VALUE 0
#define PragTyp_AUTO_VACUUM 1
@@ -100853,6 +102807,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
#define PragTyp_LOCK_STATUS 40
#define PragTyp_PARSER_TRACE 41
#define PragFlag_NeedSchema 0x01
+#define PragFlag_ReadOnly 0x02
static const struct sPragmaNames {
const char *const zName; /* Name of pragma */
u8 ePragTyp; /* PragTyp_XXX value */
@@ -100869,7 +102824,7 @@ static const struct sPragmaNames {
{ /* zName: */ "application_id",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* iArg: */ BTREE_APPLICATION_ID },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
{ /* zName: */ "auto_vacuum",
@@ -100935,6 +102890,12 @@ static const struct sPragmaNames {
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
+ { /* zName: */ "data_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlag: */ PragFlag_ReadOnly,
+ /* iArg: */ BTREE_DATA_VERSION },
+#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{ /* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
@@ -100990,8 +102951,8 @@ static const struct sPragmaNames {
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
{ /* zName: */ "freelist_count",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* ePragFlag: */ PragFlag_ReadOnly,
+ /* iArg: */ BTREE_FREE_PAGE_COUNT },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{ /* zName: */ "full_column_names",
@@ -101036,6 +102997,10 @@ static const struct sPragmaNames {
/* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlag: */ PragFlag_NeedSchema,
/* iArg: */ 0 },
+ { /* zName: */ "index_xinfo",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlag: */ PragFlag_NeedSchema,
+ /* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{ /* zName: */ "integrity_check",
@@ -101143,7 +103108,7 @@ static const struct sPragmaNames {
{ /* zName: */ "schema_version",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* iArg: */ BTREE_SCHEMA_VERSION },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{ /* zName: */ "secure_delete",
@@ -101209,7 +103174,7 @@ static const struct sPragmaNames {
{ /* zName: */ "user_version",
/* ePragTyp: */ PragTyp_HEADER_VALUE,
/* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* iArg: */ BTREE_USER_VERSION },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if defined(SQLITE_DEBUG)
@@ -101252,9 +103217,10 @@ static const struct sPragmaNames {
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif
};
-/* Number of pragmas: 57 on by default, 70 total. */
-/* End of the automatically generated pragma table.
-***************************************************************************/
+/* Number of pragmas: 59 on by default, 72 total. */
+
+/************** End of pragma.h **********************************************/
+/************** Continuing where we left off in pragma.c *********************/
/*
** Interpret the given string as a safety level. Return 0 for OFF,
@@ -101502,11 +103468,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
Token *pId; /* Pointer to <id> token */
char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
int iDb; /* Database index for <database> */
- int lwr, upr, mid; /* Binary search bounds */
+ int lwr, upr, mid = 0; /* Binary search bounds */
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
+ const struct sPragmaNames *pPragma;
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
@@ -101542,6 +103509,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS
** connection. If it returns SQLITE_OK, then assume that the VFS
** handled the pragma and generate a no-op prepared statement.
+ **
+ ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed,
+ ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file
+ ** object corresponding to the database file to which the pragma
+ ** statement refers.
+ **
+ ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA
+ ** file control is an array of pointers to strings (char**) in which the
+ ** second element of the array is the name of the pragma and the third
+ ** element is the argument to the pragma or NULL if the pragma has no
+ ** argument.
*/
aFcntl[0] = 0;
aFcntl[1] = zLeft;
@@ -101584,14 +103562,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}
if( lwr>upr ) goto pragma_out;
+ pPragma = &aPragmaNames[mid];
/* Make sure the database schema is loaded if the pragma requires that */
- if( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){
+ if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
}
/* Jump to the appropriate pragma handler */
- switch( aPragmaNames[mid].ePragTyp ){
+ switch( pPragma->ePragTyp ){
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
@@ -102170,10 +104149,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
case PragTyp_FLAG: {
if( zRight==0 ){
- returnSingleInt(pParse, aPragmaNames[mid].zName,
- (db->flags & aPragmaNames[mid].iArg)!=0 );
+ returnSingleInt(pParse, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
}else{
- int mask = aPragmaNames[mid].iArg; /* Mask of bits to set or clear. */
+ int mask = pPragma->iArg; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
/* Foreign key support may not be enabled or disabled while not
** in auto-commit mode. */
@@ -102302,20 +104280,42 @@ SQLITE_PRIVATE void sqlite3Pragma(
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
int i;
+ int mx;
+ if( pPragma->iArg ){
+ /* PRAGMA index_xinfo (newer version with more rows and columns) */
+ mx = pIdx->nColumn;
+ pParse->nMem = 6;
+ }else{
+ /* PRAGMA index_info (legacy version) */
+ mx = pIdx->nKeyCol;
+ pParse->nMem = 3;
+ }
pTab = pIdx->pTable;
- sqlite3VdbeSetNumCols(v, 3);
- pParse->nMem = 3;
+ sqlite3VdbeSetNumCols(v, pParse->nMem);
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
- for(i=0; i<pIdx->nKeyCol; i++){
+ if( pPragma->iArg ){
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC);
+ }
+ for(i=0; i<mx; i++){
i16 cnum = pIdx->aiColumn[i];
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
- assert( pTab->nCol>cnum );
- sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
+ if( cnum<0 ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 3);
+ }else{
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
+ }
+ if( pPragma->iArg ){
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6);
+ }
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem);
}
}
}
@@ -102328,17 +104328,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
- sqlite3VdbeSetNumCols(v, 3);
- pParse->nMem = 3;
+ sqlite3VdbeSetNumCols(v, 5);
+ pParse->nMem = 5;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "origin", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "partial", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
+ const char *azOrigin[] = { "c", "u", "pk" };
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, azOrigin[pIdx->idxType], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->pPartIdxWhere!=0, 5);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
}
}
@@ -102862,7 +104867,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
){
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
- ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
+ SCHEMA_ENC(db) = ENC(db) =
+ pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
break;
}
}
@@ -102907,24 +104913,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
** applications for any purpose.
*/
case PragTyp_HEADER_VALUE: {
- int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
+ int iCookie = pPragma->iArg; /* Which cookie to read or write */
sqlite3VdbeUsesBtree(v, iDb);
- switch( zLeft[0] ){
- case 'a': case 'A':
- iCookie = BTREE_APPLICATION_ID;
- break;
- case 'f': case 'F':
- iCookie = BTREE_FREE_PAGE_COUNT;
- break;
- case 's': case 'S':
- iCookie = BTREE_SCHEMA_VERSION;
- break;
- default:
- iCookie = BTREE_USER_VERSION;
- break;
- }
-
- if( zRight && iCookie!=BTREE_FREE_PAGE_COUNT ){
+ if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
@@ -102977,7 +104968,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_WAL
/*
- ** PRAGMA [database.]wal_checkpoint = passive|full|restart
+ ** PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate
**
** Checkpoint the database.
*/
@@ -102989,6 +104980,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
eMode = SQLITE_CHECKPOINT_FULL;
}else if( sqlite3StrICmp(zRight, "restart")==0 ){
eMode = SQLITE_CHECKPOINT_RESTART;
+ }else if( sqlite3StrICmp(zRight, "truncate")==0 ){
+ eMode = SQLITE_CHECKPOINT_TRUNCATE;
}
}
sqlite3VdbeSetNumCols(v, 3);
@@ -103024,8 +105017,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
/*
** PRAGMA shrink_memory
**
- ** This pragma attempts to free as much memory as possible from the
- ** current database connection.
+ ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database
+ ** connection on which it is invoked to free up as much memory as it
+ ** can, by calling sqlite3_db_release_memory().
*/
case PragTyp_SHRINK_MEMORY: {
sqlite3_db_release_memory(db);
@@ -103042,7 +105036,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** disables the timeout.
*/
/*case PragTyp_BUSY_TIMEOUT*/ default: {
- assert( aPragmaNames[mid].ePragTyp==PragTyp_BUSY_TIMEOUT );
+ assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT );
if( zRight ){
sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
}
@@ -103054,8 +105048,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
** PRAGMA soft_heap_limit
** PRAGMA soft_heap_limit = N
**
- ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted,
- ** use -1.
+ ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the
+ ** sqlite3_soft_heap_limit64() interface with the argument N, if N is
+ ** specified and is a non-negative integer.
+ ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always
+ ** returns the same integer that would be returned by the
+ ** sqlite3_soft_heap_limit64(-1) C-language function.
*/
case PragTyp_SOFT_HEAP_LIMIT: {
sqlite3_int64 N;
@@ -103568,9 +105566,11 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int commit_internal = !(db->flags&SQLITE_InternChanges);
assert( sqlite3_mutex_held(db->mutex) );
+ assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
assert( db->init.busy==0 );
rc = SQLITE_OK;
db->init.busy = 1;
+ ENC(db) = SCHEMA_ENC(db);
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
rc = sqlite3InitOne(db, i, pzErrMsg);
@@ -103883,9 +105883,12 @@ static int sqlite3LockAndPrepare(
const char **pzTail /* OUT: End of parsed string */
){
int rc;
- assert( ppStmt!=0 );
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppStmt = 0;
- if( !sqlite3SafetyCheckOk(db) ){
+ if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
@@ -103946,7 +105949,7 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
** and the statement is automatically recompiled if an schema change
** occurs.
*/
-SQLITE_API int sqlite3_prepare(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -103958,7 +105961,7 @@ SQLITE_API int sqlite3_prepare(
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
-SQLITE_API int sqlite3_prepare_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -103992,9 +105995,11 @@ static int sqlite3Prepare16(
const char *zTail8 = 0;
int rc = SQLITE_OK;
- assert( ppStmt );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppStmt = 0;
- if( !sqlite3SafetyCheckOk(db) ){
+ if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
if( nBytes>=0 ){
@@ -104032,7 +106037,7 @@ static int sqlite3Prepare16(
** and the statement is automatically recompiled if an schema change
** occurs.
*/
-SQLITE_API int sqlite3_prepare16(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -104044,7 +106049,7 @@ SQLITE_API int sqlite3_prepare16(
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
-SQLITE_API int sqlite3_prepare16_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -104120,20 +106125,25 @@ struct SortCtx {
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
/*
-** Delete all the content of a Select structure but do not deallocate
-** the select structure itself.
+** Delete all the content of a Select structure. Deallocate the structure
+** itself only if bFree is true.
*/
-static void clearSelect(sqlite3 *db, Select *p){
- sqlite3ExprListDelete(db, p->pEList);
- sqlite3SrcListDelete(db, p->pSrc);
- sqlite3ExprDelete(db, p->pWhere);
- sqlite3ExprListDelete(db, p->pGroupBy);
- sqlite3ExprDelete(db, p->pHaving);
- sqlite3ExprListDelete(db, p->pOrderBy);
- sqlite3SelectDelete(db, p->pPrior);
- sqlite3ExprDelete(db, p->pLimit);
- sqlite3ExprDelete(db, p->pOffset);
- sqlite3WithDelete(db, p->pWith);
+static void clearSelect(sqlite3 *db, Select *p, int bFree){
+ while( p ){
+ Select *pPrior = p->pPrior;
+ sqlite3ExprListDelete(db, p->pEList);
+ sqlite3SrcListDelete(db, p->pSrc);
+ sqlite3ExprDelete(db, p->pWhere);
+ sqlite3ExprListDelete(db, p->pGroupBy);
+ sqlite3ExprDelete(db, p->pHaving);
+ sqlite3ExprListDelete(db, p->pOrderBy);
+ sqlite3ExprDelete(db, p->pLimit);
+ sqlite3ExprDelete(db, p->pOffset);
+ sqlite3WithDelete(db, p->pWith);
+ if( bFree ) sqlite3DbFree(db, p);
+ p = pPrior;
+ bFree = 1;
+ }
}
/*
@@ -104192,8 +106202,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
if( db->mallocFailed ) {
- clearSelect(db, pNew);
- if( pNew!=&standin ) sqlite3DbFree(db, pNew);
+ clearSelect(db, pNew, pNew!=&standin);
pNew = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
@@ -104218,10 +106227,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
- if( p ){
- clearSelect(db, p);
- sqlite3DbFree(db, p);
- }
+ clearSelect(db, p, 1);
}
/*
@@ -104604,7 +106610,9 @@ static void pushOntoSorter(
pKI = pOp->p4.pKeyInfo;
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
- pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
+ testcase( pKI->nXField>2 );
+ pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
+ pKI->nXField-1);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
@@ -104622,20 +106630,17 @@ static void pushOntoSorter(
}
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( pSelect->iLimit ){
- int addr1, addr2;
+ int addr;
int iLimit;
if( pSelect->iOffset ){
iLimit = pSelect->iOffset+1;
}else{
iLimit = pSelect->iLimit;
}
- addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
- addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
- sqlite3VdbeJumpHere(v, addr1);
+ addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
- sqlite3VdbeJumpHere(v, addr2);
+ sqlite3VdbeJumpHere(v, addr);
}
}
@@ -105032,7 +107037,7 @@ static void selectInnerLoop(
** the output for us.
*/
if( pSort==0 && p->iLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
}
@@ -105115,7 +107120,7 @@ static KeyInfo *keyInfoFromExprList(
int i;
nExpr = pList->nExpr;
- pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
+ pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1);
if( pInfo ){
assert( sqlite3KeyInfoIsWriteable(pInfo) );
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
@@ -105885,7 +107890,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
sqlite3ExprCode(pParse, p->pLimit, iLimit);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
VdbeComment((v, "LIMIT counter"));
- sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
}
if( p->pOffset ){
p->iOffset = iOffset = ++pParse->nMem;
@@ -106104,7 +108109,7 @@ static void generateWithRecursiveQuery(
selectInnerLoop(pParse, p, p->pEList, iCurrent,
0, 0, pDest, addrCont, addrBreak);
if( regLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
VdbeCoverage(v);
}
sqlite3VdbeResolveLabel(v, addrCont);
@@ -106137,6 +108142,66 @@ static int multiSelectOrderBy(
SelectDest *pDest /* What to do with query results */
);
+/*
+** Error message for when two or more terms of a compound select have different
+** size result sets.
+*/
+static void selectWrongNumTermsError(Parse *pParse, Select *p){
+ if( p->selFlags & SF_Values ){
+ sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
+ }else{
+ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
+ " do not have the same number of result columns", selectOpName(p->op));
+ }
+}
+
+/*
+** Handle the special case of a compound-select that originates from a
+** VALUES clause. By handling this as a special case, we avoid deep
+** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
+** on a VALUES clause.
+**
+** Because the Select object originates from a VALUES clause:
+** (1) It has no LIMIT or OFFSET
+** (2) All terms are UNION ALL
+** (3) There is no ORDER BY clause
+*/
+static int multiSelectValues(
+ Parse *pParse, /* Parsing context */
+ Select *p, /* The right-most of SELECTs to be coded */
+ SelectDest *pDest /* What to do with query results */
+){
+ Select *pPrior;
+ int nExpr = p->pEList->nExpr;
+ int nRow = 1;
+ int rc = 0;
+ assert( p->pNext==0 );
+ assert( p->selFlags & SF_AllValues );
+ do{
+ assert( p->selFlags & SF_Values );
+ assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
+ assert( p->pLimit==0 );
+ assert( p->pOffset==0 );
+ if( p->pEList->nExpr!=nExpr ){
+ selectWrongNumTermsError(pParse, p);
+ return 1;
+ }
+ if( p->pPrior==0 ) break;
+ assert( p->pPrior->pNext==p );
+ p = p->pPrior;
+ nRow++;
+ }while(1);
+ while( p ){
+ pPrior = p->pPrior;
+ p->pPrior = 0;
+ rc = sqlite3Select(pParse, p, pDest);
+ p->pPrior = pPrior;
+ if( rc ) break;
+ p->nSelectRow = nRow;
+ p = p->pNext;
+ }
+ return rc;
+}
/*
** This routine is called to process a compound query form from
@@ -106218,17 +108283,19 @@ static int multiSelect(
dest.eDest = SRT_Table;
}
+ /* Special handling for a compound-select that originates as a VALUES clause.
+ */
+ if( p->selFlags & SF_AllValues ){
+ rc = multiSelectValues(pParse, p, &dest);
+ goto multi_select_end;
+ }
+
/* Make sure all SELECTs in the statement have the same number of elements
** in their result sets.
*/
assert( p->pEList && pPrior->pEList );
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
- if( p->selFlags & SF_Values ){
- sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
- }else{
- sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
- " do not have the same number of result columns", selectOpName(p->op));
- }
+ selectWrongNumTermsError(pParse, p);
rc = 1;
goto multi_select_end;
}
@@ -106267,7 +108334,7 @@ static int multiSelect(
p->iLimit = pPrior->iLimit;
p->iOffset = pPrior->iOffset;
if( p->iLimit ){
- addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v);
+ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
VdbeComment((v, "Jump ahead if LIMIT reached"));
}
explainSetInteger(iSub2, pParse->iNextSelectId);
@@ -106668,7 +108735,7 @@ static int generateOutputSubroutine(
/* Jump to the end of the loop if the LIMIT is reached.
*/
if( p->iLimit ){
- sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
/* Generate the subroutine return
@@ -107191,7 +109258,10 @@ static void substSelect(
**
** (1) The subquery and the outer query do not both use aggregates.
**
-** (2) The subquery is not an aggregate or the outer query is not a join.
+** (2) The subquery is not an aggregate or (2a) the outer query is not a join
+** and (2b) the outer query does not use subqueries other than the one
+** FROM-clause subquery that is a candidate for flattening. (2b is
+** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
**
** (3) The subquery is not the right operand of a left outer join
** (Originally ticket #306. Strengthened by ticket #3300)
@@ -107328,8 +109398,17 @@ static int flattenSubquery(
iParent = pSubitem->iCursor;
pSub = pSubitem->pSelect;
assert( pSub!=0 );
- if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */
- if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */
+ if( subqueryIsAgg ){
+ if( isAgg ) return 0; /* Restriction (1) */
+ if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
+ if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
+ || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
+ || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
+ ){
+ return 0; /* Restriction (2b) */
+ }
+ }
+
pSubSrc = pSub->pSrc;
assert( pSubSrc );
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
@@ -107872,6 +109951,8 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
p->pPrior = 0;
p->pNext = 0;
p->selFlags &= ~SF_Compound;
+ assert( (p->selFlags & SF_Converted)==0 );
+ p->selFlags |= SF_Converted;
assert( pNew->pPrior!=0 );
pNew->pPrior->pNext = pNew;
pNew->pLimit = 0;
@@ -108023,7 +110104,7 @@ static int withExpand(
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
pEList = pLeft->pEList;
if( pCte->pCols ){
- if( pEList->nExpr!=pCte->pCols->nExpr ){
+ if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){
sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
pCte->zName, pEList->nExpr, pCte->pCols->nExpr
);
@@ -108114,7 +110195,9 @@ static int selectExpander(Walker *pWalker, Select *p){
}
pTabList = p->pSrc;
pEList = p->pEList;
- sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
+ if( pWalker->xSelectCallback2==selectPopWith ){
+ sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
+ }
/* Make sure cursor numbers have been assigned to all entries in
** the FROM clause of the SELECT statement.
@@ -108148,7 +110231,7 @@ static int selectExpander(Walker *pWalker, Select *p){
/* A sub-query in the FROM clause of a SELECT */
assert( pSel!=0 );
assert( pFrom->pTab==0 );
- sqlite3WalkSelect(pWalker, pSel);
+ if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->nRef = 1;
@@ -108405,7 +110488,9 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
sqlite3WalkSelect(&w, pSelect);
}
w.xSelectCallback = selectExpander;
- w.xSelectCallback2 = selectPopWith;
+ if( (pSelect->selFlags & SF_AllValues)==0 ){
+ w.xSelectCallback2 = selectPopWith;
+ }
sqlite3WalkSelect(&w, pSelect);
}
@@ -108745,6 +110830,13 @@ SQLITE_PRIVATE int sqlite3Select(
}
isAgg = (p->selFlags & SF_Aggregate)!=0;
assert( pEList!=0 );
+#if SELECTTRACE_ENABLED
+ if( sqlite3SelectTrace & 0x100 ){
+ SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+
/* Begin generating code.
*/
@@ -108891,7 +110983,7 @@ SQLITE_PRIVATE int sqlite3Select(
**
** is transformed to:
**
- ** SELECT xyz FROM ... GROUP BY xyz
+ ** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz
**
** The second form is preferred as a single index (or temp-table) may be
** used for both the ORDER BY and DISTINCT processing. As originally
@@ -108904,7 +110996,6 @@ SQLITE_PRIVATE int sqlite3Select(
p->selFlags &= ~SF_Distinct;
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
- sSort.pOrderBy = 0;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
@@ -108920,7 +111011,7 @@ SQLITE_PRIVATE int sqlite3Select(
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
- pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
+ pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
sSort.iECursor = pParse->nTab++;
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
@@ -109094,7 +111185,7 @@ SQLITE_PRIVATE int sqlite3Select(
** will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
- pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
+ pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);
@@ -109491,9 +111582,9 @@ select_end:
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
int n = 0;
pView = sqlite3TreeViewPush(pView, moreToFollow);
- sqlite3TreeViewLine(pView, "SELECT%s%s",
+ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p)",
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
- ((p->selFlags & SF_Aggregate) ? " agg_flag" : "")
+ ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p
);
if( p->pSrc && p->pSrc->nSrc ) n++;
if( p->pWhere ) n++;
@@ -109696,7 +111787,7 @@ malloc_failed:
** Instead, the entire table should be passed to sqlite3_free_table() when
** the calling procedure is finished using it.
*/
-SQLITE_API int sqlite3_get_table(
+SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
char ***pazResult, /* Write the result table here */
@@ -109707,6 +111798,9 @@ SQLITE_API int sqlite3_get_table(
int rc;
TabResult res;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*pazResult = 0;
if( pnColumn ) *pnColumn = 0;
if( pnRow ) *pnRow = 0;
@@ -109762,7 +111856,7 @@ SQLITE_API int sqlite3_get_table(
/*
** This routine frees the space the sqlite3_get_table() malloced.
*/
-SQLITE_API void sqlite3_free_table(
+SQLITE_API void SQLITE_STDCALL sqlite3_free_table(
char **azResult /* Result returned from sqlite3_get_table() */
){
if( azResult ){
@@ -111770,7 +113864,7 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
** overwriting the database with the vacuumed content.
**
** Only 1x temporary space and only 1x writes would be required if
-** the copy of step (3) were replace by deleting the original database
+** the copy of step (3) were replaced by deleting the original database
** and renaming the transient database as the original. But that will
** not work if other processes are attached to the original database.
** And a power loss in between deleting the original and renaming the
@@ -111860,7 +113954,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** cause problems for the call to BtreeSetPageSize() below. */
sqlite3BtreeCommit(pTemp);
- nRes = sqlite3BtreeGetReserve(pMain);
+ nRes = sqlite3BtreeGetOptimalReserve(pMain);
/* A VACUUM cannot change the pagesize of an encrypted database. */
#ifdef SQLITE_HAS_CODEC
@@ -112122,25 +114216,31 @@ static int createModule(
/*
** External API function used to create a new virtual-table module.
*/
-SQLITE_API int sqlite3_create_module(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
const sqlite3_module *pModule, /* The definition of the module */
void *pAux /* Context pointer for xCreate/xConnect */
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
return createModule(db, zName, pModule, pAux, 0);
}
/*
** External API function used to create a new virtual-table module.
*/
-SQLITE_API int sqlite3_create_module_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
const sqlite3_module *pModule, /* The definition of the module */
void *pAux, /* Context pointer for xCreate/xConnect */
void (*xDestroy)(void *) /* Module destructor function */
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
return createModule(db, zName, pModule, pAux, xDestroy);
}
@@ -112373,7 +114473,12 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
addModuleArgument(db, pTable, 0);
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
- pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
+ assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0)
+ || (pParse->sNameToken.z==pName1->z && pName2->z==0)
+ );
+ pParse->sNameToken.n = (int)(
+ &pModuleName->z[pModuleName->n] - pParse->sNameToken.z
+ );
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Creating a virtual table invokes the authorization callback twice.
@@ -112425,6 +114530,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
char *zStmt;
char *zWhere;
int iDb;
+ int iReg;
Vdbe *v;
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
@@ -112459,8 +114565,10 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
- sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
- pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
+
+ iReg = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, iReg, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
/* If we are rereading the sqlite_master table create the in-memory
@@ -112738,13 +114846,18 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
** valid to call this function from within the xCreate() or xConnect() of a
** virtual table module.
*/
-SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
+SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
Parse *pParse;
int rc = SQLITE_OK;
Table *pTab;
char *zErr = 0;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
sqlite3Error(db, SQLITE_MISUSE);
@@ -112808,11 +114921,15 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
- VTable *p = vtabDisconnectAll(db, pTab);
-
- assert( rc==SQLITE_OK );
+ VTable *p;
+ for(p=pTab->pVTable; p; p=p->pNext){
+ assert( p->pVtab );
+ if( p->pVtab->nRef>0 ){
+ return SQLITE_LOCKED;
+ }
+ }
+ p = vtabDisconnectAll(db, pTab);
rc = p->pMod->pModule->xDestroy(p->pVtab);
-
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
if( rc==SQLITE_OK ){
assert( pTab->pVTable==p && p->pNext==0 );
@@ -113097,10 +115214,13 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
** The results of this routine are undefined unless it is called from
** within an xUpdate method.
*/
-SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
static const unsigned char aMap[] = {
SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
};
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
assert( OE_Ignore==4 && OE_Replace==5 );
assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 );
@@ -113112,12 +115232,14 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
** the SQLite core with additional information about the behavior
** of the virtual table being implemented.
*/
-SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
va_list ap;
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
-
va_start(ap, op);
switch( op ){
case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
@@ -113236,6 +115358,8 @@ struct WhereLevel {
int addrCont; /* Jump here to continue with the next loop cycle */
int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */
+ int iLikeRepCntr; /* LIKE range processing counter register */
+ int addrLikeRep; /* LIKE range processing address */
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to ends the loop */
@@ -113252,6 +115376,9 @@ struct WhereLevel {
} u;
struct WhereLoop *pWLoop; /* The selected WhereLoop object */
Bitmask notReady; /* FROM entries not usable at this level */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrVisit; /* Address at which row is visited */
+#endif
};
/*
@@ -113282,7 +115409,6 @@ struct WhereLoop {
union {
struct { /* Information for internal btree tables */
u16 nEq; /* Number of equality constraints */
- u16 nSkip; /* Number of initial index columns to skip */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
@@ -113295,12 +115421,13 @@ struct WhereLoop {
} u;
u32 wsFlags; /* WHERE_* flags describing the plan */
u16 nLTerm; /* Number of entries in aLTerm[] */
+ u16 nSkip; /* Number of NULL aLTerm[] entries */
/**** whereLoopXfer() copies fields above ***********************/
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
WhereTerm **aLTerm; /* WhereTerms used */
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
- WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
+ WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */
};
/* This object holds the prerequisites and the cost of running a
@@ -113417,7 +115544,7 @@ struct WhereTerm {
} u;
LogEst truthProb; /* Probability of truth for this expression */
u16 eOperator; /* A WO_xx value describing <op> */
- u8 wtFlags; /* TERM_xxx bit flags. See below */
+ u16 wtFlags; /* TERM_xxx bit flags. See below */
u8 nChild; /* Number of children that must disable us */
WhereClause *pWC; /* The clause this term is part of */
Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
@@ -113439,6 +115566,9 @@ struct WhereTerm {
#else
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
#endif
+#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */
+#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */
+#define TERM_LIKE 0x400 /* The original LIKE operator */
/*
** An instance of the WhereScan object is used as an iterator for locating
@@ -113626,6 +115756,7 @@ struct WhereInfo {
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
+#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
/************** End of whereInt.h ********************************************/
/************** Continuing where we left off in where.c **********************/
@@ -113813,7 +115944,7 @@ static void whereClauseClear(WhereClause *pWC){
** calling this routine. Such pointers may be reinitialized by referencing
** the pWC->a[] array.
*/
-static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
+static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
WhereTerm *pTerm;
int idx;
testcase( wtFlags & TERM_VIRTUAL );
@@ -113833,10 +115964,11 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
sqlite3DbFree(db, pOld);
}
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
+ memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm));
}
pTerm = &pWC->a[idx = pWC->nTerm++];
if( p && ExprHasProperty(p, EP_Unlikely) ){
- pTerm->truthProb = sqlite3LogEst(p->iTable) - 99;
+ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270;
}else{
pTerm->truthProb = 1;
}
@@ -114237,7 +116369,11 @@ static void exprAnalyzeAll(
** so and false if not.
**
** In order for the operator to be optimizible, the RHS must be a string
-** literal that does not begin with a wildcard.
+** literal that does not begin with a wildcard. The LHS must be a column
+** that may only be NULL, a string, or a BLOB, never a number. (This means
+** that virtual tables cannot participate in the LIKE optimization.) If the
+** collating sequence for the column on the LHS must be appropriate for
+** the operator.
*/
static int isLikeOrGlob(
Parse *pParse, /* Parsing and code generating context */
@@ -114266,7 +116402,7 @@ static int isLikeOrGlob(
pLeft = pList->a[1].pExpr;
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
- || IsVirtual(pLeft->pTab)
+ || IsVirtual(pLeft->pTab) /* Value might be numeric */
){
/* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
** be the name of an indexed column with TEXT affinity. */
@@ -114367,6 +116503,88 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
}
}
+/*
+** Mark term iChild as being a child of term iParent
+*/
+static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){
+ pWC->a[iChild].iParent = iParent;
+ pWC->a[iChild].truthProb = pWC->a[iParent].truthProb;
+ pWC->a[iParent].nChild++;
+}
+
+/*
+** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not
+** a conjunction, then return just pTerm when N==0. If N is exceeds
+** the number of available subterms, return NULL.
+*/
+static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){
+ if( pTerm->eOperator!=WO_AND ){
+ return N==0 ? pTerm : 0;
+ }
+ if( N<pTerm->u.pAndInfo->wc.nTerm ){
+ return &pTerm->u.pAndInfo->wc.a[N];
+ }
+ return 0;
+}
+
+/*
+** Subterms pOne and pTwo are contained within WHERE clause pWC. The
+** two subterms are in disjunction - they are OR-ed together.
+**
+** If these two terms are both of the form: "A op B" with the same
+** A and B values but different operators and if the operators are
+** compatible (if one is = and the other is <, for example) then
+** add a new virtual AND term to pWC that is the combination of the
+** two.
+**
+** Some examples:
+**
+** x<y OR x=y --> x<=y
+** x=y OR x=y --> x=y
+** x<=y OR x<y --> x<=y
+**
+** The following is NOT generated:
+**
+** x<y OR x>y --> x!=y
+*/
+static void whereCombineDisjuncts(
+ SrcList *pSrc, /* the FROM clause */
+ WhereClause *pWC, /* The complete WHERE clause */
+ WhereTerm *pOne, /* First disjunct */
+ WhereTerm *pTwo /* Second disjunct */
+){
+ u16 eOp = pOne->eOperator | pTwo->eOperator;
+ sqlite3 *db; /* Database connection (for malloc) */
+ Expr *pNew; /* New virtual expression */
+ int op; /* Operator for the combined expression */
+ int idxNew; /* Index in pWC of the next virtual term */
+
+ if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
+ if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
+ if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp
+ && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return;
+ assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 );
+ assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 );
+ if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
+ if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return;
+ /* If we reach this point, it means the two subterms can be combined */
+ if( (eOp & (eOp-1))!=0 ){
+ if( eOp & (WO_LT|WO_LE) ){
+ eOp = WO_LE;
+ }else{
+ assert( eOp & (WO_GT|WO_GE) );
+ eOp = WO_GE;
+ }
+ }
+ db = pWC->pWInfo->pParse->db;
+ pNew = sqlite3ExprDup(db, pOne->pExpr, 0);
+ if( pNew==0 ) return;
+ for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( op<TK_GE ); }
+ pNew->op = op;
+ idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
+ exprAnalyze(pSrc, pWC, idxNew);
+}
+
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
/*
** Analyze a term that consists of two or more OR-connected
@@ -114391,6 +116609,7 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15)
** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*')
** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6)
+** (F) x>A OR (x=A AND y>=B)
**
** CASE 1:
**
@@ -114407,6 +116626,16 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
**
** CASE 2:
**
+** If there are exactly two disjuncts one side has x>A and the other side
+** has x=A (for the same x and A) then add a new virtual conjunct term to the
+** WHERE clause of the form "x>=A". Example:
+**
+** x>A OR (x=A AND y>B) adds: x>=A
+**
+** The added conjunct can sometimes be helpful in query planning.
+**
+** CASE 3:
+**
** If all subterms are indexable by a single table T, then set
**
** WhereTerm.eOperator = WO_OR
@@ -114533,12 +116762,26 @@ static void exprAnalyzeOrTerm(
}
/*
- ** Record the set of tables that satisfy case 2. The set might be
+ ** Record the set of tables that satisfy case 3. The set might be
** empty.
*/
pOrInfo->indexable = indexable;
pTerm->eOperator = indexable==0 ? 0 : WO_OR;
+ /* For a two-way OR, attempt to implementation case 2.
+ */
+ if( indexable && pOrWc->nTerm==2 ){
+ int iOne = 0;
+ WhereTerm *pOne;
+ while( (pOne = whereNthSubterm(&pOrWc->a[0],iOne++))!=0 ){
+ int iTwo = 0;
+ WhereTerm *pTwo;
+ while( (pTwo = whereNthSubterm(&pOrWc->a[1],iTwo++))!=0 ){
+ whereCombineDisjuncts(pSrc, pWC, pOne, pTwo);
+ }
+ }
+ }
+
/*
** chngToIN holds a set of tables that *might* satisfy case 1. But
** we have to do some additional checking to see if case 1 really
@@ -114664,12 +116907,11 @@ static void exprAnalyzeOrTerm(
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
- pWC->a[idxNew].iParent = idxTerm;
- pTerm->nChild = 1;
+ markTermAsChild(pWC, idxNew, idxTerm);
}else{
sqlite3ExprListDelete(db, pList);
}
- pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
+ pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */
}
}
}
@@ -114707,7 +116949,7 @@ static void exprAnalyze(
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
- int noCase = 0; /* LIKE/GLOB distinguishes case */
+ int noCase = 0; /* uppercase equivalent to lowercase */
int op; /* Top-level operator. pExpr->op */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection */
@@ -114767,9 +117009,8 @@ static void exprAnalyze(
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
if( idxNew==0 ) return;
pNew = &pWC->a[idxNew];
- pNew->iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
- pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
if( pExpr->op==TK_EQ
&& !ExprHasProperty(pExpr, EP_FromJoin)
@@ -114826,9 +117067,8 @@ static void exprAnalyze(
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
- pWC->a[idxNew].iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
}
- pTerm->nChild = 2;
}
#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */
@@ -114847,12 +117087,15 @@ static void exprAnalyze(
/* Add constraints to reduce the search space on a LIKE or GLOB
** operator.
**
- ** A like pattern of the form "x LIKE 'abc%'" is changed into constraints
+ ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints
**
- ** x>='abc' AND x<'abd' AND x LIKE 'abc%'
+ ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%'
**
** The last character of the prefix "abc" is incremented to form the
- ** termination condition "abd".
+ ** termination condition "abd". If case is not significant (the default
+ ** for LIKE) then the lower-bound is made all uppercase and the upper-
+ ** bound is made all lowercase so that the bounds also work when comparing
+ ** BLOBs.
*/
if( pWC->op==TK_AND
&& isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
@@ -114863,10 +117106,26 @@ static void exprAnalyze(
Expr *pNewExpr2;
int idxNew1;
int idxNew2;
- Token sCollSeqName; /* Name of collating sequence */
+ const char *zCollSeqName; /* Name of collating sequence */
+ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC;
pLeft = pExpr->x.pList->a[1].pExpr;
pStr2 = sqlite3ExprDup(db, pStr1, 0);
+
+ /* Convert the lower bound to upper-case and the upper bound to
+ ** lower-case (upper-case is less than lower-case in ASCII) so that
+ ** the range constraints also work for BLOBs
+ */
+ if( noCase && !pParse->db->mallocFailed ){
+ int i;
+ char c;
+ pTerm->wtFlags |= TERM_LIKE;
+ for(i=0; (c = pStr1->u.zToken[i])!=0; i++){
+ pStr1->u.zToken[i] = sqlite3Toupper(c);
+ pStr2->u.zToken[i] = sqlite3Tolower(c);
+ }
+ }
+
if( !db->mallocFailed ){
u8 c, *pC; /* Last character before the first wildcard */
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
@@ -114883,29 +117142,27 @@ static void exprAnalyze(
}
*pC = c + 1;
}
- sCollSeqName.z = noCase ? "NOCASE" : "BINARY";
- sCollSeqName.n = 6;
+ zCollSeqName = noCase ? "NOCASE" : "BINARY";
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
- pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
- sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
+ pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
+ sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
pStr1, 0);
transferJoinMarkings(pNewExpr1, pExpr);
- idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
+ idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
- sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
+ sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
pStr2, 0);
transferJoinMarkings(pNewExpr2, pExpr);
- idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
+ idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
- pWC->a[idxNew1].iParent = idxTerm;
- pWC->a[idxNew2].iParent = idxTerm;
- pTerm->nChild = 2;
+ markTermAsChild(pWC, idxNew1, idxTerm);
+ markTermAsChild(pWC, idxNew2, idxTerm);
}
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
@@ -114938,9 +117195,8 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_MATCH;
- pNewTerm->iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
- pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
@@ -114961,7 +117217,7 @@ static void exprAnalyze(
if( pExpr->op==TK_NOTNULL
&& pExpr->pLeft->op==TK_COLUMN
&& pExpr->pLeft->iColumn>=0
- && OptimizationEnabled(db, SQLITE_Stat3)
+ && OptimizationEnabled(db, SQLITE_Stat34)
){
Expr *pNewExpr;
Expr *pLeft = pExpr->pLeft;
@@ -114980,9 +117236,8 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_GT;
- pNewTerm->iParent = idxTerm;
+ markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
- pTerm->nChild = 1;
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
@@ -115202,6 +117457,8 @@ static void constructAutomaticIndex(
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
u8 sentWarning = 0; /* True if a warnning has been issued */
+ Expr *pPartial = 0; /* Partial Index Expression */
+ int iContinue = 0; /* Jump here to skip excluded rows */
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
@@ -115217,6 +117474,17 @@ static void constructAutomaticIndex(
pLoop = pLevel->pWLoop;
idxCols = 0;
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ Expr *pExpr = pTerm->pExpr;
+ assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */
+ || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */
+ || pLoop->prereq!=0 ); /* table of a LEFT JOIN */
+ if( pLoop->prereq==0
+ && (pTerm->wtFlags & TERM_VIRTUAL)==0
+ && !ExprHasProperty(pExpr, EP_FromJoin)
+ && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){
+ pPartial = sqlite3ExprAnd(pParse->db, pPartial,
+ sqlite3ExprDup(pParse->db, pExpr, 0));
+ }
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
int iCol = pTerm->u.leftColumn;
Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
@@ -115229,7 +117497,9 @@ static void constructAutomaticIndex(
sentWarning = 1;
}
if( (idxCols & cMask)==0 ){
- if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ) return;
+ if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){
+ goto end_auto_index_create;
+ }
pLoop->aLTerm[nKeyCol++] = pTerm;
idxCols |= cMask;
}
@@ -115249,7 +117519,7 @@ static void constructAutomaticIndex(
** if they go out of sync.
*/
extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
- mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
+ mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
for(i=0; i<mxBitCol; i++){
@@ -115258,11 +117528,10 @@ static void constructAutomaticIndex(
if( pSrc->colUsed & MASKBIT(BMS-1) ){
nKeyCol += pTable->nCol - BMS + 1;
}
- pLoop->wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY;
/* Construct the Index object to describe this index */
pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed);
- if( pIdx==0 ) return;
+ if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
pIdx->zName = "auto-index";
pIdx->pTable = pTable;
@@ -115314,18 +117583,29 @@ static void constructAutomaticIndex(
VdbeComment((v, "for %s", pTable->zName));
/* Fill the automatic index with content */
+ sqlite3ExprCachePush(pParse);
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
+ if( pPartial ){
+ iContinue = sqlite3VdbeMakeLabel(v);
+ sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL);
+ pLoop->wsFlags |= WHERE_PARTIALIDX;
+ }
regRecord = sqlite3GetTempReg(pParse);
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
+ if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRecord);
+ sqlite3ExprCachePop(pParse);
/* Jump here when skipping the initialization */
sqlite3VdbeJumpHere(v, addrInit);
+
+end_auto_index_create:
+ sqlite3ExprDelete(pParse->db, pPartial);
}
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
@@ -115485,18 +117765,21 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
}
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
-
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** Estimate the location of a particular key among all keys in an
** index. Store the results in aStat as follows:
**
-** aStat[0] Est. number of rows less than pVal
-** aStat[1] Est. number of rows equal to pVal
+** aStat[0] Est. number of rows less than pRec
+** aStat[1] Est. number of rows equal to pRec
**
-** Return SQLITE_OK on success.
+** Return the index of the sample that is the smallest sample that
+** is greater than or equal to pRec. Note that this index is not an index
+** into the aSample[] array - it is an index into a virtual set of samples
+** based on the contents of aSample[] and the number of fields in record
+** pRec.
*/
-static void whereKeyStats(
+static int whereKeyStats(
Parse *pParse, /* Database connection */
Index *pIdx, /* Index to consider domain of */
UnpackedRecord *pRec, /* Vector of values to consider */
@@ -115505,67 +117788,158 @@ static void whereKeyStats(
){
IndexSample *aSample = pIdx->aSample;
int iCol; /* Index of required stats in anEq[] etc. */
+ int i; /* Index of first sample >= pRec */
+ int iSample; /* Smallest sample larger than or equal to pRec */
int iMin = 0; /* Smallest sample not yet tested */
- int i = pIdx->nSample; /* Smallest sample larger than or equal to pRec */
int iTest; /* Next sample to test */
int res; /* Result of comparison operation */
+ int nField; /* Number of fields in pRec */
+ tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */
#ifndef SQLITE_DEBUG
UNUSED_PARAMETER( pParse );
#endif
assert( pRec!=0 );
- iCol = pRec->nField - 1;
assert( pIdx->nSample>0 );
- assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
+ assert( pRec->nField>0 && pRec->nField<=pIdx->nSampleCol );
+
+ /* Do a binary search to find the first sample greater than or equal
+ ** to pRec. If pRec contains a single field, the set of samples to search
+ ** is simply the aSample[] array. If the samples in aSample[] contain more
+ ** than one fields, all fields following the first are ignored.
+ **
+ ** If pRec contains N fields, where N is more than one, then as well as the
+ ** samples in aSample[] (truncated to N fields), the search also has to
+ ** consider prefixes of those samples. For example, if the set of samples
+ ** in aSample is:
+ **
+ ** aSample[0] = (a, 5)
+ ** aSample[1] = (a, 10)
+ ** aSample[2] = (b, 5)
+ ** aSample[3] = (c, 100)
+ ** aSample[4] = (c, 105)
+ **
+ ** Then the search space should ideally be the samples above and the
+ ** unique prefixes [a], [b] and [c]. But since that is hard to organize,
+ ** the code actually searches this set:
+ **
+ ** 0: (a)
+ ** 1: (a, 5)
+ ** 2: (a, 10)
+ ** 3: (a, 10)
+ ** 4: (b)
+ ** 5: (b, 5)
+ ** 6: (c)
+ ** 7: (c, 100)
+ ** 8: (c, 105)
+ ** 9: (c, 105)
+ **
+ ** For each sample in the aSample[] array, N samples are present in the
+ ** effective sample array. In the above, samples 0 and 1 are based on
+ ** sample aSample[0]. Samples 2 and 3 on aSample[1] etc.
+ **
+ ** Often, sample i of each block of N effective samples has (i+1) fields.
+ ** Except, each sample may be extended to ensure that it is greater than or
+ ** equal to the previous sample in the array. For example, in the above,
+ ** sample 2 is the first sample of a block of N samples, so at first it
+ ** appears that it should be 1 field in size. However, that would make it
+ ** smaller than sample 1, so the binary search would not work. As a result,
+ ** it is extended to two fields. The duplicates that this creates do not
+ ** cause any problems.
+ */
+ nField = pRec->nField;
+ iCol = 0;
+ iSample = pIdx->nSample * nField;
do{
- iTest = (iMin+i)/2;
- res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec);
+ int iSamp; /* Index in aSample[] of test sample */
+ int n; /* Number of fields in test sample */
+
+ iTest = (iMin+iSample)/2;
+ iSamp = iTest / nField;
+ if( iSamp>0 ){
+ /* The proposed effective sample is a prefix of sample aSample[iSamp].
+ ** Specifically, the shortest prefix of at least (1 + iTest%nField)
+ ** fields that is greater than the previous effective sample. */
+ for(n=(iTest % nField) + 1; n<nField; n++){
+ if( aSample[iSamp-1].anLt[n-1]!=aSample[iSamp].anLt[n-1] ) break;
+ }
+ }else{
+ n = iTest + 1;
+ }
+
+ pRec->nField = n;
+ res = sqlite3VdbeRecordCompare(aSample[iSamp].n, aSample[iSamp].p, pRec);
if( res<0 ){
+ iLower = aSample[iSamp].anLt[n-1] + aSample[iSamp].anEq[n-1];
+ iMin = iTest+1;
+ }else if( res==0 && n<nField ){
+ iLower = aSample[iSamp].anLt[n-1];
iMin = iTest+1;
+ res = -1;
}else{
- i = iTest;
+ iSample = iTest;
+ iCol = n-1;
}
- }while( res && iMin<i );
+ }while( res && iMin<iSample );
+ i = iSample / nField;
#ifdef SQLITE_DEBUG
/* The following assert statements check that the binary search code
** above found the right answer. This block serves no purpose other
** than to invoke the asserts. */
- if( res==0 ){
- /* If (res==0) is true, then sample $i must be equal to pRec */
- assert( i<pIdx->nSample );
- assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
- || pParse->db->mallocFailed );
- }else{
- /* Otherwise, pRec must be smaller than sample $i and larger than
- ** sample ($i-1). */
- assert( i==pIdx->nSample
- || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
- || pParse->db->mallocFailed );
- assert( i==0
- || sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
- || pParse->db->mallocFailed );
+ if( pParse->db->mallocFailed==0 ){
+ if( res==0 ){
+ /* If (res==0) is true, then pRec must be equal to sample i. */
+ assert( i<pIdx->nSample );
+ assert( iCol==nField-1 );
+ pRec->nField = nField;
+ assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
+ || pParse->db->mallocFailed
+ );
+ }else{
+ /* Unless i==pIdx->nSample, indicating that pRec is larger than
+ ** all samples in the aSample[] array, pRec must be smaller than the
+ ** (iCol+1) field prefix of sample i. */
+ assert( i<=pIdx->nSample && i>=0 );
+ pRec->nField = iCol+1;
+ assert( i==pIdx->nSample
+ || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
+ || pParse->db->mallocFailed );
+
+ /* if i==0 and iCol==0, then record pRec is smaller than all samples
+ ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must
+ ** be greater than or equal to the (iCol) field prefix of sample i.
+ ** If (i>0), then pRec must also be greater than sample (i-1). */
+ if( iCol>0 ){
+ pRec->nField = iCol;
+ assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0
+ || pParse->db->mallocFailed );
+ }
+ if( i>0 ){
+ pRec->nField = nField;
+ assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
+ || pParse->db->mallocFailed );
+ }
+ }
}
#endif /* ifdef SQLITE_DEBUG */
- /* At this point, aSample[i] is the first sample that is greater than
- ** or equal to pVal. Or if i==pIdx->nSample, then all samples are less
- ** than pVal. If aSample[i]==pVal, then res==0.
- */
if( res==0 ){
+ /* Record pRec is equal to sample i */
+ assert( iCol==nField-1 );
aStat[0] = aSample[i].anLt[iCol];
aStat[1] = aSample[i].anEq[iCol];
}else{
- tRowcnt iLower, iUpper, iGap;
- if( i==0 ){
- iLower = 0;
- iUpper = aSample[0].anLt[iCol];
+ /* At this point, the (iCol+1) field prefix of aSample[i] is the first
+ ** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec
+ ** is larger than all samples in the array. */
+ tRowcnt iUpper, iGap;
+ if( i>=pIdx->nSample ){
+ iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
}else{
- i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
- iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol];
- iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
+ iUpper = aSample[i].anLt[iCol];
}
- aStat[1] = pIdx->aAvgEq[iCol];
+
if( iLower>=iUpper ){
iGap = 0;
}else{
@@ -115577,7 +117951,12 @@ static void whereKeyStats(
iGap = iGap/3;
}
aStat[0] = iLower + iGap;
+ aStat[1] = pIdx->aAvgEq[iCol];
}
+
+ /* Restore the pRec->nField value before returning. */
+ pRec->nField = nField;
+ return i;
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
@@ -115728,7 +118107,7 @@ static int whereRangeSkipScanEst(
** If either of the upper or lower bound is not present, then NULL is passed in
** place of the corresponding WhereTerm.
**
-** The value in (pBuilder->pNew->u.btree.nEq) is the index of the index
+** The value in (pBuilder->pNew->u.btree.nEq) is the number of the index
** column subject to the range constraint. Or, equivalently, the number of
** equality constraints optimized by the proposed index scan. For example,
** assuming index p is on t1(a, b), and the SQL query is:
@@ -115744,7 +118123,7 @@ static int whereRangeSkipScanEst(
**
** When this function is called, *pnOut is set to the sqlite3LogEst() of the
** number of rows that the index scan is expected to visit without
-** considering the range constraints. If nEq is 0, this is the number of
+** considering the range constraints. If nEq is 0, then *pnOut is the number of
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
** to account for the range constraints pLower and pUpper.
**
@@ -115768,10 +118147,7 @@ static int whereRangeScanEst(
Index *p = pLoop->u.btree.pIndex;
int nEq = pLoop->u.btree.nEq;
- if( p->nSample>0
- && nEq<p->nSampleCol
- && OptimizationEnabled(pParse->db, SQLITE_Stat3)
- ){
+ if( p->nSample>0 && nEq<p->nSampleCol ){
if( nEq==pBuilder->nRecValid ){
UnpackedRecord *pRec = pBuilder->pRec;
tRowcnt a[2];
@@ -115787,15 +118163,19 @@ static int whereRangeScanEst(
** is not a simple variable or literal value), the lower bound of the
** range is $P. Due to a quirk in the way whereKeyStats() works, even
** if $L is available, whereKeyStats() is called for both ($P) and
- ** ($P:$L) and the larger of the two returned values used.
+ ** ($P:$L) and the larger of the two returned values is used.
**
** Similarly, iUpper is to be set to the estimate of the number of rows
** less than the upper bound of the range query. Where the upper bound
** is either ($P) or ($P:$U). Again, even if $U is available, both values
** of iUpper are requested of whereKeyStats() and the smaller used.
+ **
+ ** The number of rows between the two bounds is then just iUpper-iLower.
*/
- tRowcnt iLower;
- tRowcnt iUpper;
+ tRowcnt iLower; /* Rows less than the lower bound */
+ tRowcnt iUpper; /* Rows less than the upper bound */
+ int iLwrIdx = -2; /* aSample[] for the lower bound */
+ int iUprIdx = -1; /* aSample[] for the upper bound */
if( pRec ){
testcase( pRec->nField!=pBuilder->nRecValid );
@@ -115809,7 +118189,7 @@ static int whereRangeScanEst(
/* Determine iLower and iUpper using ($P) only. */
if( nEq==0 ){
iLower = 0;
- iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]);
+ iUpper = p->nRowEst0;
}else{
/* Note: this call could be optimized away - since the same values must
** have been requested when testing key $P in whereEqualScanEst(). */
@@ -115833,7 +118213,7 @@ static int whereRangeScanEst(
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
if( rc==SQLITE_OK && bOk ){
tRowcnt iNew;
- whereKeyStats(pParse, p, pRec, 0, a);
+ iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a);
iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
if( iNew>iLower ) iLower = iNew;
nOut--;
@@ -115848,7 +118228,7 @@ static int whereRangeScanEst(
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
if( rc==SQLITE_OK && bOk ){
tRowcnt iNew;
- whereKeyStats(pParse, p, pRec, 1, a);
+ iUprIdx = whereKeyStats(pParse, p, pRec, 1, a);
iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
if( iNew<iUpper ) iUpper = iNew;
nOut--;
@@ -115860,6 +118240,11 @@ static int whereRangeScanEst(
if( rc==SQLITE_OK ){
if( iUpper>iLower ){
nNew = sqlite3LogEst(iUpper - iLower);
+ /* TUNING: If both iUpper and iLower are derived from the same
+ ** sample, then assume they are 4x more selective. This brings
+ ** the estimated selectivity more in line with what it would be
+ ** if estimated without the use of STAT3/4 tables. */
+ if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) );
}else{
nNew = 10; assert( 10==sqlite3LogEst(2) );
}
@@ -115884,12 +118269,15 @@ static int whereRangeScanEst(
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
- /* TUNING: If there is both an upper and lower limit, assume the range is
+ /* TUNING: If there is both an upper and lower limit and neither limit
+ ** has an application-defined likelihood(), assume the range is
** reduced by an additional 75%. This means that, by default, an open-ended
** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the
** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to
** match 1/64 of the index. */
- if( pLower && pUpper ) nNew -= 20;
+ if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){
+ nNew -= 20;
+ }
nOut -= (pLower!=0) + (pUpper!=0);
if( nNew<10 ) nNew = 10;
@@ -116041,20 +118429,43 @@ static int whereInScanEst(
** but joins might run a little slower. The trick is to disable as much
** as we can without disabling too much. If we disabled in (1), we'd get
** the wrong answer. See ticket #813.
+**
+** If all the children of a term are disabled, then that term is also
+** automatically disabled. In this way, terms get disabled if derived
+** virtual terms are tested first. For example:
+**
+** x GLOB 'abc*' AND x>='abc' AND x<'acd'
+** \___________/ \______/ \_____/
+** parent child1 child2
+**
+** Only the parent term was in the original WHERE clause. The child1
+** and child2 terms were added by the LIKE optimization. If both of
+** the virtual child terms are valid, then testing of the parent can be
+** skipped.
+**
+** Usually the parent term is marked as TERM_CODED. But if the parent
+** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead.
+** The TERM_LIKECOND marking indicates that the term should be coded inside
+** a conditional such that is only evaluated on the second pass of a
+** LIKE-optimization loop, when scanning BLOBs instead of strings.
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
- if( pTerm
+ int nLoop = 0;
+ while( pTerm
&& (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0
){
- pTerm->wtFlags |= TERM_CODED;
- if( pTerm->iParent>=0 ){
- WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent];
- if( (--pOther->nChild)==0 ){
- disableTerm(pLevel, pOther);
- }
+ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
+ pTerm->wtFlags |= TERM_LIKECOND;
+ }else{
+ pTerm->wtFlags |= TERM_CODED;
}
+ if( pTerm->iParent<0 ) break;
+ pTerm = &pTerm->pWC->a[pTerm->iParent];
+ pTerm->nChild--;
+ if( pTerm->nChild!=0 ) break;
+ nLoop++;
}
}
@@ -116249,7 +118660,7 @@ static int codeAllEqualityTerms(
pLoop = pLevel->pWLoop;
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
nEq = pLoop->u.btree.nEq;
- nSkip = pLoop->u.btree.nSkip;
+ nSkip = pLoop->nSkip;
pIdx = pLoop->u.btree.pIndex;
assert( pIdx!=0 );
@@ -116363,7 +118774,7 @@ static void explainAppendTerm(
static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
Index *pIndex = pLoop->u.btree.pIndex;
u16 nEq = pLoop->u.btree.nEq;
- u16 nSkip = pLoop->u.btree.nSkip;
+ u16 nSkip = pLoop->nSkip;
int i, j;
Column *aCol = pTab->aCol;
i16 *aiColumn = pIndex->aiColumn;
@@ -116394,11 +118805,14 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single
-** record is added to the output to describe the table scan strategy in
-** pLevel.
+** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
+** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
+** is added to the output to describe the table scan strategy in pLevel.
+**
+** If an OP_Explain opcode is added to the VM, its address is returned.
+** Otherwise, if no OP_Explain is coded, zero is returned.
*/
-static void explainOneScan(
+static int explainOneScan(
Parse *pParse, /* Parse context */
SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
@@ -116406,7 +118820,8 @@ static void explainOneScan(
int iFrom, /* Value for "from" column of output */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){
-#ifndef SQLITE_DEBUG
+ int ret = 0;
+#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
if( pParse->explain==2 )
#endif
{
@@ -116423,7 +118838,7 @@ static void explainOneScan(
pLoop = pLevel->pWLoop;
flags = pLoop->wsFlags;
- if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;
+ if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
@@ -116452,6 +118867,8 @@ static void explainOneScan(
if( isSearch ){
zFmt = "PRIMARY KEY";
}
+ }else if( flags & WHERE_PARTIALIDX ){
+ zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
}else if( flags & WHERE_AUTO_INDEX ){
zFmt = "AUTOMATIC COVERING INDEX";
}else if( flags & WHERE_IDX_ONLY ){
@@ -116493,13 +118910,73 @@ static void explainOneScan(
}
#endif
zMsg = sqlite3StrAccumFinish(&str);
- sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
+ ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC);
}
+ return ret;
}
#else
-# define explainOneScan(u,v,w,x,y,z)
+# define explainOneScan(u,v,w,x,y,z) 0
#endif /* SQLITE_OMIT_EXPLAIN */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+/*
+** Configure the VM passed as the first argument with an
+** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
+** implement level pLvl. Argument pSrclist is a pointer to the FROM
+** clause that the scan reads data from.
+**
+** If argument addrExplain is not 0, it must be the address of an
+** OP_Explain instruction that describes the same loop.
+*/
+static void addScanStatus(
+ Vdbe *v, /* Vdbe to add scanstatus entry to */
+ SrcList *pSrclist, /* FROM clause pLvl reads data from */
+ WhereLevel *pLvl, /* Level to add scanstatus() entry for */
+ int addrExplain /* Address of OP_Explain (or 0) */
+){
+ const char *zObj = 0;
+ WhereLoop *pLoop = pLvl->pWLoop;
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ zObj = pLoop->u.btree.pIndex->zName;
+ }else{
+ zObj = pSrclist->a[pLvl->iFrom].zName;
+ }
+ sqlite3VdbeScanStatus(
+ v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
+ );
+}
+#else
+# define addScanStatus(a, b, c, d) ((void)d)
+#endif
+
+/*
+** If the most recently coded instruction is a constant range contraint
+** that originated from the LIKE optimization, then change the P3 to be
+** pLoop->iLikeRepCntr and set P5.
+**
+** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
+** expression: "x>='ABC' AND x<'abd'". But this requires that the range
+** scan loop run twice, once for strings and a second time for BLOBs.
+** The OP_String opcodes on the second pass convert the upper and lower
+** bound string contants to blobs. This routine makes the necessary changes
+** to the OP_String opcodes for that to happen.
+*/
+static void whereLikeOptimizationStringFixup(
+ Vdbe *v, /* prepared statement under construction */
+ WhereLevel *pLevel, /* The loop that contains the LIKE operator */
+ WhereTerm *pTerm /* The upper or lower bound just coded */
+){
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ VdbeOp *pOp;
+ assert( pLevel->iLikeRepCntr>0 );
+ pOp = sqlite3VdbeGetOp(v, -1);
+ assert( pOp!=0 );
+ assert( pOp->opcode==OP_String8
+ || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
+ pOp->p3 = pLevel->iLikeRepCntr;
+ pOp->p5 = 1;
+ }
+}
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
@@ -116800,7 +119277,7 @@ static Bitmask codeOneLoopStart(
pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur;
- assert( nEq>=pLoop->u.btree.nSkip );
+ assert( nEq>=pLoop->nSkip );
/* If this loop satisfies a sort order (pOrderBy) request that
** was passed to this function to implement a "SELECT min(x) ..."
@@ -116817,7 +119294,7 @@ static Bitmask codeOneLoopStart(
&& pWInfo->nOBSat>0
&& (pIdx->nKeyCol>nEq)
){
- assert( pLoop->u.btree.nSkip==0 );
+ assert( pLoop->nSkip==0 );
bSeekPastNull = 1;
nExtraReg = 1;
}
@@ -116829,10 +119306,25 @@ static Bitmask codeOneLoopStart(
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
pRangeStart = pLoop->aLTerm[j++];
nExtraReg = 1;
+ /* Like optimization range constraints always occur in pairs */
+ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
+ (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
}
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
pRangeEnd = pLoop->aLTerm[j++];
nExtraReg = 1;
+ if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
+ assert( pRangeStart!=0 ); /* LIKE opt constraints */
+ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */
+ pLevel->iLikeRepCntr = ++pParse->nMem;
+ testcase( bRev );
+ testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC),
+ pLevel->iLikeRepCntr);
+ VdbeComment((v, "LIKE loop counter"));
+ pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
+ }
if( pRangeStart==0
&& (j = pIdx->aiColumn[nEq])>=0
&& pIdx->pTable->aCol[j].notNull==0
@@ -116875,6 +119367,7 @@ static Bitmask codeOneLoopStart(
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
if( (pRangeStart->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
@@ -116920,6 +119413,7 @@ static Bitmask codeOneLoopStart(
Expr *pRight = pRangeEnd->pExpr->pRight;
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
){
@@ -117130,10 +119624,9 @@ static Bitmask codeOneLoopStart(
Expr *pExpr = pWC->a[iTerm].pExpr;
if( &pWC->a[iTerm] == pTerm ) continue;
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
- testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
- testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
- if( pWC->a[iTerm].wtFlags & (TERM_ORINFO|TERM_VIRTUAL) ) continue;
+ if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue;
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
+ testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
pExpr = sqlite3ExprDup(db, pExpr, 0);
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
}
@@ -117148,7 +119641,8 @@ static Bitmask codeOneLoopStart(
*/
wctrlFlags = WHERE_OMIT_OPEN_CLOSE
| WHERE_FORCE_TABLE
- | WHERE_ONETABLE_ONLY;
+ | WHERE_ONETABLE_ONLY
+ | WHERE_NO_AUTOINDEX;
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
@@ -117166,9 +119660,11 @@ static Bitmask codeOneLoopStart(
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
if( pSubWInfo ){
WhereLoop *pSubLoop;
- explainOneScan(
+ int addrExplain = explainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
);
+ addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
+
/* This is the sub-WHERE clause body. First skip over
** duplicate rows from prior sub-WHERE clauses, and record the
** rowid (or PRIMARY KEY) for the current row so that the same
@@ -117299,11 +119795,16 @@ static Bitmask codeOneLoopStart(
}
}
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pLevel->addrVisit = sqlite3VdbeCurrentAddr(v);
+#endif
+
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
*/
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
Expr *pE;
+ int skipLikeAddr = 0;
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
@@ -117318,7 +119819,13 @@ static Bitmask codeOneLoopStart(
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
continue;
}
+ if( pTerm->wtFlags & TERM_LIKECOND ){
+ assert( pLevel->iLikeRepCntr>0 );
+ skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
+ VdbeCoverage(v);
+ }
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
+ if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
pTerm->wtFlags |= TERM_CODED;
}
@@ -117438,7 +119945,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
sqlite3_free(z);
}
if( p->wsFlags & WHERE_SKIPSCAN ){
- sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->u.btree.nSkip);
+ sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
}else{
sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
}
@@ -117474,7 +119981,6 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
p->u.vtab.idxStr = 0;
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
- sqlite3KeyInfoUnref(p->u.btree.pIndex->pKeyInfo);
sqlite3DbFree(db, p->u.btree.pIndex);
p->u.btree.pIndex = 0;
}
@@ -117549,10 +120055,11 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
}
/*
-** Return TRUE if both of the following are true:
+** Return TRUE if all of the following are true:
**
** (1) X has the same or lower cost that Y
** (2) X is a proper subset of Y
+** (3) X skips at least as many columns as Y
**
** By "proper subset" we mean that X uses fewer WHERE clause terms
** than Y and that every WHERE clause term used by X is also used
@@ -117560,19 +120067,25 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
**
** If X is a proper subset of Y then Y is a better choice and ought
** to have a lower cost. This routine returns TRUE when that cost
-** relationship is inverted and needs to be adjusted.
+** relationship is inverted and needs to be adjusted. The third rule
+** was added because if X uses skip-scan less than Y it still might
+** deserve a lower cost even if it is a proper subset of Y.
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
const WhereLoop *pY /* Compare against this WhereLoop */
){
int i, j;
- if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */
+ if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
+ return 0; /* X is not a subset of Y */
+ }
+ if( pY->nSkip > pX->nSkip ) return 0;
if( pX->rRun >= pY->rRun ){
if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
}
for(i=pX->nLTerm-1; i>=0; i--){
+ if( pX->aLTerm[i]==0 ) continue;
for(j=pY->nLTerm-1; j>=0; j--){
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
}
@@ -117594,33 +120107,24 @@ static int whereLoopCheaperProperSubset(
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
-**
-** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the
-** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE
-** clause terms covered, since some of the first nLTerm entries in aLTerm[]
-** will be NULL (because they are skipped). That makes it more difficult
-** to compare the loops. We could add extra code to do the comparison, and
-** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this
-** adjustment is sufficient minor, that it is very difficult to construct
-** a test case where the extra code would improve the query plan. Better
-** to avoid the added complexity and just omit cost adjustments to SKIPSCAN
-** loops.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
- if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return;
for(; p; p=p->pNextLoop){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
- if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue;
if( whereLoopCheaperProperSubset(p, pTemplate) ){
/* Adjust pTemplate cost downward so that it is cheaper than its
- ** subset p */
+ ** subset p. */
+ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
+ pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1));
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut - 1;
}else if( whereLoopCheaperProperSubset(pTemplate, p) ){
/* Adjust pTemplate cost upward so that it is costlier than p since
** pTemplate is a proper subset of p */
+ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
+ pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1));
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut + 1;
}
@@ -117665,8 +120169,9 @@ static WhereLoop **whereLoopFindLesser(
/* Any loop using an appliation-defined index (or PRIMARY KEY or
** UNIQUE constraint) with one or more == constraints is better
- ** than an automatic index. */
+ ** than an automatic index. Unless it is a skip-scan. */
if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
+ && (pTemplate->nSkip)==0
&& (pTemplate->wsFlags & WHERE_INDEXED)!=0
&& (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0
&& (p->prereq & pTemplate->prereq)==pTemplate->prereq
@@ -117825,10 +120330,30 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
** Adjust the WhereLoop.nOut value downward to account for terms of the
** WHERE clause that reference the loop but which are not used by an
** index.
-**
-** In the current implementation, the first extra WHERE clause term reduces
-** the number of output rows by a factor of 10 and each additional term
-** reduces the number of output rows by sqrt(2).
+*
+** For every WHERE clause term that is not used by the index
+** and which has a truth probability assigned by one of the likelihood(),
+** likely(), or unlikely() SQL functions, reduce the estimated number
+** of output rows by the probability specified.
+**
+** TUNING: For every WHERE clause term that is not used by the index
+** and which does not have an assigned truth probability, heuristics
+** described below are used to try to estimate the truth probability.
+** TODO --> Perhaps this is something that could be improved by better
+** table statistics.
+**
+** Heuristic 1: Estimate the truth probability as 93.75%. The 93.75%
+** value corresponds to -1 in LogEst notation, so this means decrement
+** the WhereLoop.nOut field for every such WHERE clause term.
+**
+** Heuristic 2: If there exists one or more WHERE clause terms of the
+** form "x==EXPR" and EXPR is not a constant 0 or 1, then make sure the
+** final output row estimate is no greater than 1/4 of the total number
+** of rows in the table. In other words, assume that x==EXPR will filter
+** out at least 3 out of 4 rows. If EXPR is -1 or 0 or 1, then maybe the
+** "x" column is boolean or else -1 or 0 or 1 is a common default value
+** on the "x" column and so in that case only cap the output row estimate
+** at 1/2 instead of 1/4.
*/
static void whereLoopOutputAdjust(
WhereClause *pWC, /* The WHERE clause */
@@ -117837,9 +120362,10 @@ static void whereLoopOutputAdjust(
){
WhereTerm *pTerm, *pX;
Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf);
- int i, j;
- int nEq = 0; /* Number of = constraints not within likely()/unlikely() */
+ int i, j, k;
+ LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
+ assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
@@ -117852,20 +120378,26 @@ static void whereLoopOutputAdjust(
}
if( j<0 ){
if( pTerm->truthProb<=0 ){
+ /* If a truth probability is specified using the likelihood() hints,
+ ** then use the probability provided by the application. */
pLoop->nOut += pTerm->truthProb;
}else{
+ /* In the absence of explicit truth probabilities, use heuristics to
+ ** guess a reasonable truth probability. */
pLoop->nOut--;
- if( pTerm->eOperator&WO_EQ ) nEq++;
+ if( pTerm->eOperator&WO_EQ ){
+ Expr *pRight = pTerm->pExpr->pRight;
+ if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
+ k = 10;
+ }else{
+ k = 20;
+ }
+ if( iReduce<k ) iReduce = k;
+ }
}
}
}
- /* TUNING: If there is at least one equality constraint in the WHERE
- ** clause that does not have a likelihood() explicitly assigned to it
- ** then do not let the estimated number of output rows exceed half
- ** the number of rows in the table. */
- if( nEq && pLoop->nOut>nRow-10 ){
- pLoop->nOut = nRow - 10;
- }
+ if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce;
}
/*
@@ -117906,7 +120438,7 @@ static int whereLoopAddBtreeIndex(
Bitmask saved_prereq; /* Original value of pNew->prereq */
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
u16 saved_nEq; /* Original value of pNew->u.btree.nEq */
- u16 saved_nSkip; /* Original value of pNew->u.btree.nSkip */
+ u16 saved_nSkip; /* Original value of pNew->nSkip */
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
LogEst saved_nOut; /* Original value of pNew->nOut */
int iCol; /* Index of the column in the table */
@@ -117935,7 +120467,7 @@ static int whereLoopAddBtreeIndex(
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
opMask, pProbe);
saved_nEq = pNew->u.btree.nEq;
- saved_nSkip = pNew->u.btree.nSkip;
+ saved_nSkip = pNew->nSkip;
saved_nLTerm = pNew->nLTerm;
saved_wsFlags = pNew->wsFlags;
saved_prereq = pNew->prereq;
@@ -117943,44 +120475,6 @@ static int whereLoopAddBtreeIndex(
pNew->rSetup = 0;
rSize = pProbe->aiRowLogEst[0];
rLogSize = estLog(rSize);
-
- /* Consider using a skip-scan if there are no WHERE clause constraints
- ** available for the left-most terms of the index, and if the average
- ** number of repeats in the left-most terms is at least 18.
- **
- ** The magic number 18 is selected on the basis that scanning 17 rows
- ** is almost always quicker than an index seek (even though if the index
- ** contains fewer than 2^17 rows we assume otherwise in other parts of
- ** the code). And, even if it is not, it should not be too much slower.
- ** On the other hand, the extra seeks could end up being significantly
- ** more expensive. */
- assert( 42==sqlite3LogEst(18) );
- if( saved_nEq==saved_nSkip
- && saved_nEq+1<pProbe->nKeyCol
- && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
- && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
- ){
- LogEst nIter;
- pNew->u.btree.nEq++;
- pNew->u.btree.nSkip++;
- pNew->aLTerm[pNew->nLTerm++] = 0;
- pNew->wsFlags |= WHERE_SKIPSCAN;
- nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
- if( pTerm ){
- /* TUNING: When estimating skip-scan for a term that is also indexable,
- ** multiply the cost of the skip-scan by 2.0, to make it a little less
- ** desirable than the regular index lookup. */
- nIter += 10; assert( 10==sqlite3LogEst(2) );
- }
- pNew->nOut -= nIter;
- /* TUNING: Because uncertainties in the estimates for skip-scan queries,
- ** add a 1.375 fudge factor to make skip-scan slightly less likely. */
- nIter += 5;
- whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
- pNew->nOut = saved_nOut;
- pNew->u.btree.nEq = saved_nEq;
- pNew->u.btree.nSkip = saved_nSkip;
- }
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */
LogEst rCostIdx;
@@ -117996,6 +120490,10 @@ static int whereLoopAddBtreeIndex(
}
if( pTerm->prereqRight & pNew->maskSelf ) continue;
+ /* Do not allow the upper bound of a LIKE optimization range constraint
+ ** to mix with a lower range bound from some other source */
+ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
+
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->nLTerm = saved_nLTerm;
@@ -118039,6 +120537,17 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
pBtm = pTerm;
pTop = 0;
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ /* Range contraints that come from the LIKE optimization are
+ ** always used in pairs. */
+ pTop = &pTerm[1];
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
+ assert( pTop->wtFlags & TERM_LIKEOPT );
+ assert( pTop->eOperator==WO_LT );
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
+ }
}else{
assert( eOp & (WO_LT|WO_LE) );
testcase( eOp & WO_LT );
@@ -118075,7 +120584,6 @@ static int whereLoopAddBtreeIndex(
if( nInMul==0
&& pProbe->nSample
&& pNew->u.btree.nEq<=pProbe->nSampleCol
- && OptimizationEnabled(db, SQLITE_Stat3)
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
){
Expr *pExpr = pTerm->pExpr;
@@ -118143,10 +120651,45 @@ static int whereLoopAddBtreeIndex(
}
pNew->prereq = saved_prereq;
pNew->u.btree.nEq = saved_nEq;
- pNew->u.btree.nSkip = saved_nSkip;
+ pNew->nSkip = saved_nSkip;
pNew->wsFlags = saved_wsFlags;
pNew->nOut = saved_nOut;
pNew->nLTerm = saved_nLTerm;
+
+ /* Consider using a skip-scan if there are no WHERE clause constraints
+ ** available for the left-most terms of the index, and if the average
+ ** number of repeats in the left-most terms is at least 18.
+ **
+ ** The magic number 18 is selected on the basis that scanning 17 rows
+ ** is almost always quicker than an index seek (even though if the index
+ ** contains fewer than 2^17 rows we assume otherwise in other parts of
+ ** the code). And, even if it is not, it should not be too much slower.
+ ** On the other hand, the extra seeks could end up being significantly
+ ** more expensive. */
+ assert( 42==sqlite3LogEst(18) );
+ if( saved_nEq==saved_nSkip
+ && saved_nEq+1<pProbe->nKeyCol
+ && pProbe->noSkipScan==0
+ && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
+ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
+ ){
+ LogEst nIter;
+ pNew->u.btree.nEq++;
+ pNew->nSkip++;
+ pNew->aLTerm[pNew->nLTerm++] = 0;
+ pNew->wsFlags |= WHERE_SKIPSCAN;
+ nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
+ pNew->nOut -= nIter;
+ /* TUNING: Because uncertainties in the estimates for skip-scan queries,
+ ** add a 1.375 fudge factor to make skip-scan slightly less likely. */
+ nIter += 5;
+ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
+ pNew->nOut = saved_nOut;
+ pNew->u.btree.nEq = saved_nEq;
+ pNew->nSkip = saved_nSkip;
+ pNew->wsFlags = saved_wsFlags;
+ }
+
return rc;
}
@@ -118206,7 +120749,12 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
int i;
WhereTerm *pTerm;
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab) ) return 1;
+ Expr *pExpr = pTerm->pExpr;
+ if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab)
+ && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
+ ){
+ return 1;
+ }
}
return 0;
}
@@ -118310,6 +120858,7 @@ static int whereLoopAddBtree(
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/* Automatic indexes */
if( !pBuilder->pOrSet
+ && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
&& pSrc->pIndex==0
&& !pSrc->viaCoroutine
@@ -118325,7 +120874,7 @@ static int whereLoopAddBtree(
if( pTerm->prereqRight & pNew->maskSelf ) continue;
if( termCanDriveIndex(pTerm, pSrc, 0) ){
pNew->u.btree.nEq = 1;
- pNew->u.btree.nSkip = 0;
+ pNew->nSkip = 0;
pNew->u.btree.pIndex = 0;
pNew->nLTerm = 1;
pNew->aLTerm[0] = pTerm;
@@ -118366,7 +120915,7 @@ static int whereLoopAddBtree(
}
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
- pNew->u.btree.nSkip = 0;
+ pNew->nSkip = 0;
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
pNew->rSetup = 0;
@@ -118916,7 +121465,7 @@ static i8 wherePathSatisfiesOrderBy(
/* Skip over == and IS NULL terms */
if( j<pLoop->u.btree.nEq
- && pLoop->u.btree.nSkip==0
+ && pLoop->nSkip==0
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
){
if( i & WO_ISNULL ){
@@ -119193,10 +121742,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Seed the search with a single WherePath containing zero WhereLoops.
**
- ** TUNING: Do not let the number of iterations go above 25. If the cost
- ** of computing an automatic index is not paid back within the first 25
+ ** TUNING: Do not let the number of iterations go above 28. If the cost
+ ** of computing an automatic index is not paid back within the first 28
** rows, then do not use the automatic index. */
- aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
+ aFrom[0].nRow = MIN(pParse->nQueryLoop, 48); assert( 48==sqlite3LogEst(28) );
nFrom = 1;
assert( aFrom[0].isOrdered==0 );
if( nOrderBy ){
@@ -119370,7 +121919,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
#ifdef WHERETRACE_ENABLED /* >=2 */
- if( sqlite3WhereTrace>=2 ){
+ if( sqlite3WhereTrace & 0x02 ){
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
@@ -119489,7 +122038,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pWC = &pWInfo->sWC;
pLoop = pBuilder->pNew;
pLoop->wsFlags = 0;
- pLoop->u.btree.nSkip = 0;
+ pLoop->nSkip = 0;
pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0);
if( pTerm ){
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
@@ -119501,7 +122050,6 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm );
- assert( ArraySize(pLoop->aLTermSpace)==4 );
if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
@@ -119995,6 +122543,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( op ){
sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
+ if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
+ && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
+ && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
+ ){
+ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
+ }
VdbeComment((v, "%s", pIx->zName));
}
}
@@ -120010,7 +122564,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
*/
notReady = ~(Bitmask)0;
for(ii=0; ii<nTabList; ii++){
+ int addrExplain;
+ int wsFlags;
pLevel = &pWInfo->a[ii];
+ wsFlags = pLevel->pWLoop->wsFlags;
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
constructAutomaticIndex(pParse, &pWInfo->sWC,
@@ -120018,10 +122575,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( db->mallocFailed ) goto whereBeginError;
}
#endif
- explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags);
+ addrExplain = explainOneScan(
+ pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags
+ );
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
notReady = codeOneLoopStart(pWInfo, ii, notReady);
pWInfo->iContinue = pLevel->addrCont;
+ if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){
+ addScanStatus(v, pTabList, pLevel, addrExplain);
+ }
}
/* Done. */
@@ -120088,6 +122650,16 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeJumpHere(v, pLevel->addrSkip);
sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
}
+ if( pLevel->addrLikeRep ){
+ int op;
+ if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){
+ op = OP_DecrJumpZero;
+ }else{
+ op = OP_JumpZeroIncr;
+ }
+ sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
+ VdbeCoverage(v);
+ }
if( pLevel->iLeftJoin ){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
@@ -122602,13 +125174,19 @@ static void yy_reduce(
int cnt = 0, mxSelect;
p->pWith = yymsp[-1].minor.yy59;
if( p->pPrior ){
+ u16 allValues = SF_Values;
pNext = 0;
for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
pLoop->pNext = pNext;
pLoop->selFlags |= SF_Compound;
+ allValues &= pLoop->selFlags;
}
- mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
- if( mxSelect && cnt>mxSelect ){
+ if( allValues ){
+ p->selFlags |= SF_AllValues;
+ }else if(
+ (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
+ && cnt>mxSelect
+ ){
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
}
}
@@ -122972,7 +125550,7 @@ static void yy_reduce(
break;
case 193: /* expr ::= expr COLLATE ID|STRING */
{
- yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr, &yymsp[0].minor.yy0);
+ yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr, &yymsp[0].minor.yy0, 1);
yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
@@ -123135,7 +125713,7 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
}
@@ -123150,8 +125728,8 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
- ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
}
@@ -123164,8 +125742,8 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
- ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
}
@@ -123180,8 +125758,8 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
- ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
}
@@ -123195,8 +125773,8 @@ static void yy_reduce(
Expr *p = yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->x.pSelect = yymsp[-1].minor.yy3;
- ExprSetProperty(p, EP_xIsSelect);
- sqlite3ExprSetHeight(pParse, p);
+ ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, p);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
}
@@ -123209,7 +125787,7 @@ static void yy_reduce(
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy132, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy132 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy132) : yymsp[-2].minor.yy14;
- sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy132);
@@ -123252,7 +125830,7 @@ static void yy_reduce(
break;
case 244: /* idxlist ::= idxlist COMMA nm collate sortorder */
{
- Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0);
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, p);
sqlite3ExprListSetName(pParse,yygotominor.yy14,&yymsp[-2].minor.yy0,1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
@@ -123261,7 +125839,7 @@ static void yy_reduce(
break;
case 245: /* idxlist ::= nm collate sortorder */
{
- Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0);
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, p);
sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
@@ -124451,7 +127029,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
-
+ assert( zSql!=0 );
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->nVdbeActive==0 ){
db->u1.isInterrupted = 0;
@@ -124520,9 +127098,11 @@ abort_parse:
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
#ifdef YYTRACKMAXSTACKDEPTH
+ sqlite3_mutex_enter(sqlite3MallocMutex());
sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
+ sqlite3_mutex_leave(sqlite3MallocMutex());
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
db->lookaside.bEnabled = enableLookaside;
@@ -124686,7 +127266,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
** to recognize the end of a trigger can be omitted. All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
-SQLITE_API int sqlite3_complete(const char *zSql){
+SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
@@ -124719,6 +127299,13 @@ SQLITE_API int sqlite3_complete(const char *zSql){
};
#endif /* SQLITE_OMIT_TRIGGER */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zSql==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+
while( *zSql ){
switch( *zSql ){
case ';': { /* A semicolon */
@@ -124844,7 +127431,7 @@ SQLITE_API int sqlite3_complete(const char *zSql){
** above, except that the parameter is required to be UTF-16 encoded, not
** UTF-8.
*/
-SQLITE_API int sqlite3_complete16(const void *zSql){
+SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
sqlite3_value *pVal;
char const *zSql8;
int rc = SQLITE_NOMEM;
@@ -124994,24 +127581,24 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
** a pointer to the to the sqlite3_version[] string constant.
*/
-SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
+SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void){ return sqlite3_version; }
/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
** pointer to a string constant whose value is the same as the
** SQLITE_SOURCE_ID C preprocessor macro.
*/
-SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
** returns an integer equal to SQLITE_VERSION_NUMBER.
*/
-SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
/* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns
** zero if and only if SQLite was compiled with mutexing code omitted due to
** the SQLITE_THREADSAFE compile-time option being set to 0.
*/
-SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
+SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
/*
@@ -125020,7 +127607,7 @@ SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
** I/O active are written using this function. These messages
** are intended for debugging activity only.
*/
-SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*, ...) = 0;
+SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0;
#endif
/*
@@ -125072,7 +127659,7 @@ SQLITE_API char *sqlite3_data_directory = 0;
** * Recursive calls to this routine from thread X return immediately
** without blocking.
*/
-SQLITE_API int sqlite3_initialize(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
int rc; /* Result code */
#ifdef SQLITE_EXTRA_INIT
@@ -125086,6 +127673,11 @@ SQLITE_API int sqlite3_initialize(void){
}
#endif
+ /* If the following assert() fails on some obscure processor/compiler
+ ** combination, the work-around is to set the correct pointer
+ ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */
+ assert( SQLITE_PTRSIZE==sizeof(char*) );
+
/* If SQLite is already completely initialized, then this call
** to sqlite3_initialize() should be a no-op. But the initialization
** must be complete. So isInit must not be set until the very end
@@ -125228,7 +127820,14 @@ SQLITE_API int sqlite3_initialize(void){
** on when SQLite is already shut down. If SQLite is already shut down
** when this routine is invoked, then this routine is a harmless no-op.
*/
-SQLITE_API int sqlite3_shutdown(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
+#ifdef SQLITE_OMIT_WSD
+ int rc = sqlite3_wsd_init(4096, 24);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+#endif
+
if( sqlite3GlobalConfig.isInit ){
#ifdef SQLITE_EXTRA_SHUTDOWN
void SQLITE_EXTRA_SHUTDOWN(void);
@@ -125275,7 +127874,7 @@ SQLITE_API int sqlite3_shutdown(void){
** threadsafe. Failure to heed these warnings can lead to unpredictable
** behavior.
*/
-SQLITE_API int sqlite3_config(int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
va_list ap;
int rc = SQLITE_OK;
@@ -125287,33 +127886,43 @@ SQLITE_API int sqlite3_config(int op, ...){
switch( op ){
/* Mutex configuration options are only available in a threadsafe
- ** compile.
+ ** compile.
*/
-#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */
case SQLITE_CONFIG_SINGLETHREAD: {
- /* Disable all mutexing */
- sqlite3GlobalConfig.bCoreMutex = 0;
- sqlite3GlobalConfig.bFullMutex = 0;
+ /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to
+ ** Single-thread. */
+ sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */
case SQLITE_CONFIG_MULTITHREAD: {
- /* Disable mutexing of database connections */
- /* Enable mutexing of core data structures */
- sqlite3GlobalConfig.bCoreMutex = 1;
- sqlite3GlobalConfig.bFullMutex = 0;
+ /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to
+ ** Multi-thread. */
+ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */
case SQLITE_CONFIG_SERIALIZED: {
- /* Enable all mutexing */
- sqlite3GlobalConfig.bCoreMutex = 1;
- sqlite3GlobalConfig.bFullMutex = 1;
+ /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to
+ ** Serialized. */
+ sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */
+ sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */
case SQLITE_CONFIG_MUTEX: {
/* Specify an alternative mutex implementation */
sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*);
break;
}
+#endif
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */
case SQLITE_CONFIG_GETMUTEX: {
/* Retrieve the current mutex implementation */
*va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex;
@@ -125321,37 +127930,61 @@ SQLITE_API int sqlite3_config(int op, ...){
}
#endif
-
case SQLITE_CONFIG_MALLOC: {
- /* Specify an alternative malloc implementation */
+ /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a
+ ** single argument which is a pointer to an instance of the
+ ** sqlite3_mem_methods structure. The argument specifies alternative
+ ** low-level memory allocation routines to be used in place of the memory
+ ** allocation routines built into SQLite. */
sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*);
break;
}
case SQLITE_CONFIG_GETMALLOC: {
- /* Retrieve the current malloc() implementation */
+ /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a
+ ** single argument which is a pointer to an instance of the
+ ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is
+ ** filled with the currently defined memory allocation routines. */
if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault();
*va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m;
break;
}
case SQLITE_CONFIG_MEMSTATUS: {
- /* Enable or disable the malloc status collection */
+ /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes
+ ** single argument of type int, interpreted as a boolean, which enables
+ ** or disables the collection of memory allocation statistics. */
sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_SCRATCH: {
- /* Designate a buffer for scratch memory space */
+ /* EVIDENCE-OF: R-08404-60887 There are three arguments to
+ ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
+ ** which the scratch allocations will be drawn, the size of each scratch
+ ** allocation (sz), and the maximum number of scratch allocations (N). */
sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
sqlite3GlobalConfig.szScratch = va_arg(ap, int);
sqlite3GlobalConfig.nScratch = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_PAGECACHE: {
- /* Designate a buffer for page cache memory space */
+ /* EVIDENCE-OF: R-31408-40510 There are three arguments to
+ ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size
+ ** of each page buffer (sz), and the number of pages (N). */
sqlite3GlobalConfig.pPage = va_arg(ap, void*);
sqlite3GlobalConfig.szPage = va_arg(ap, int);
sqlite3GlobalConfig.nPage = va_arg(ap, int);
break;
}
+ case SQLITE_CONFIG_PCACHE_HDRSZ: {
+ /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes
+ ** a single parameter which is a pointer to an integer and writes into
+ ** that integer the number of extra bytes per page required for each page
+ ** in SQLITE_CONFIG_PAGECACHE. */
+ *va_arg(ap, int*) =
+ sqlite3HeaderSizeBtree() +
+ sqlite3HeaderSizePcache() +
+ sqlite3HeaderSizePcache1();
+ break;
+ }
case SQLITE_CONFIG_PCACHE: {
/* no-op */
@@ -125364,11 +127997,18 @@ SQLITE_API int sqlite3_config(int op, ...){
}
case SQLITE_CONFIG_PCACHE2: {
- /* Specify an alternative page cache implementation */
+ /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a
+ ** single argument which is a pointer to an sqlite3_pcache_methods2
+ ** object. This object specifies the interface to a custom page cache
+ ** implementation. */
sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*);
break;
}
case SQLITE_CONFIG_GETPCACHE2: {
+ /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a
+ ** single argument which is a pointer to an sqlite3_pcache_methods2
+ ** object. SQLite copies of the current page cache implementation into
+ ** that object. */
if( sqlite3GlobalConfig.pcache2.xInit==0 ){
sqlite3PCacheSetDefault();
}
@@ -125376,9 +128016,15 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
+/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only
+** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or
+** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
case SQLITE_CONFIG_HEAP: {
- /* Designate a buffer for heap memory space */
+ /* EVIDENCE-OF: R-19854-42126 There are three arguments to
+ ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the
+ ** number of bytes in the memory buffer, and the minimum allocation size.
+ */
sqlite3GlobalConfig.pHeap = va_arg(ap, void*);
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
sqlite3GlobalConfig.mnReq = va_arg(ap, int);
@@ -125391,17 +128037,19 @@ SQLITE_API int sqlite3_config(int op, ...){
}
if( sqlite3GlobalConfig.pHeap==0 ){
- /* If the heap pointer is NULL, then restore the malloc implementation
- ** back to NULL pointers too. This will cause the malloc to go
- ** back to its default implementation when sqlite3_initialize() is
- ** run.
+ /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer)
+ ** is NULL, then SQLite reverts to using its default memory allocator
+ ** (the system malloc() implementation), undoing any prior invocation of
+ ** SQLITE_CONFIG_MALLOC.
+ **
+ ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to
+ ** revert to its default implementation when sqlite3_initialize() is run
*/
memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m));
}else{
- /* The heap pointer is not NULL, then install one of the
- ** mem5.c/mem3.c methods. The enclosing #if guarantees at
- ** least one of these methods is currently enabled.
- */
+ /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the
+ ** alternative memory allocator is engaged to handle all of SQLites
+ ** memory allocation needs. */
#ifdef SQLITE_ENABLE_MEMSYS3
sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
#endif
@@ -125440,11 +128088,19 @@ SQLITE_API int sqlite3_config(int op, ...){
** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls.
*/
case SQLITE_CONFIG_URI: {
+ /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single
+ ** argument of type int. If non-zero, then URI handling is globally
+ ** enabled. If the parameter is zero, then URI handling is globally
+ ** disabled. */
sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_COVERING_INDEX_SCAN: {
+ /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN
+ ** option takes a single integer argument which is interpreted as a
+ ** boolean in order to enable or disable the use of covering indices for
+ ** full table scans in the query optimizer. */
sqlite3GlobalConfig.bUseCis = va_arg(ap, int);
break;
}
@@ -125459,25 +128115,45 @@ SQLITE_API int sqlite3_config(int op, ...){
#endif
case SQLITE_CONFIG_MMAP_SIZE: {
+ /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit
+ ** integer (sqlite3_int64) values that are the default mmap size limit
+ ** (the default setting for PRAGMA mmap_size) and the maximum allowed
+ ** mmap size limit. */
sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64);
sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64);
+ /* EVIDENCE-OF: R-53367-43190 If either argument to this option is
+ ** negative, then that argument is changed to its compile-time default.
+ **
+ ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be
+ ** silently truncated if necessary so that it does not exceed the
+ ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE
+ ** compile-time option.
+ */
if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){
mxMmap = SQLITE_MAX_MMAP_SIZE;
}
- sqlite3GlobalConfig.mxMmap = mxMmap;
if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE;
if( szMmap>mxMmap) szMmap = mxMmap;
+ sqlite3GlobalConfig.mxMmap = mxMmap;
sqlite3GlobalConfig.szMmap = szMmap;
break;
}
-#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC)
+#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */
case SQLITE_CONFIG_WIN32_HEAPSIZE: {
+ /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit
+ ** unsigned integer value that specifies the maximum size of the created
+ ** heap. */
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
break;
}
#endif
+ case SQLITE_CONFIG_PMASZ: {
+ sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int);
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
@@ -125555,7 +128231,13 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
/*
** Return the mutex associated with a database connection.
*/
-SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->mutex;
}
@@ -125563,8 +128245,12 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
** Free up as much memory as we can from the given database
** connection.
*/
-SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
int i;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
for(i=0; i<db->nDb; i++){
@@ -125582,7 +128268,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
/*
** Configuration settings for an individual database connection
*/
-SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
va_start(ap, op);
@@ -125654,13 +128340,20 @@ static int binCollFunc(
){
int rc, n;
n = nKey1<nKey2 ? nKey1 : nKey2;
+ /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares
+ ** strings byte by byte using the memcmp() function from the standard C
+ ** library. */
rc = memcmp(pKey1, pKey2, n);
if( rc==0 ){
if( padFlag
&& allSpaces(((char*)pKey1)+n, nKey1-n)
&& allSpaces(((char*)pKey2)+n, nKey2-n)
){
- /* Leave rc unchanged at 0 */
+ /* EVIDENCE-OF: R-31624-24737 RTRIM is like BINARY except that extra
+ ** spaces at the end of either string do not change the result. In other
+ ** words, strings will compare equal to one another as long as they
+ ** differ only in the number of spaces at the end.
+ */
}else{
rc = nKey1 - nKey2;
}
@@ -125694,21 +128387,39 @@ static int nocaseCollatingFunc(
/*
** Return the ROWID of the most recent insert
*/
-SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
+SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->lastRowid;
}
/*
** Return the number of changes in the most recent call to sqlite3_exec().
*/
-SQLITE_API int sqlite3_changes(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->nChange;
}
/*
** Return the number of changes since the database handle was opened.
*/
-SQLITE_API int sqlite3_total_changes(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->nTotalChange;
}
@@ -125844,8 +128555,8 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
** unclosed resources, and arranges for deallocation when the last
** prepare statement or sqlite3_backup closes.
*/
-SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
-SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
+SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
+SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
/*
@@ -126194,7 +128905,7 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
+#if SQLITE_OS_WIN || HAVE_USLEEP
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -126252,11 +128963,14 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
** This routine sets the busy callback for an Sqlite database to the
** given callback function with the given argument.
*/
-SQLITE_API int sqlite3_busy_handler(
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
sqlite3 *db,
int (*xBusy)(void*,int),
void *pArg
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
@@ -126272,12 +128986,18 @@ SQLITE_API int sqlite3_busy_handler(
** given callback function with the given argument. The progress callback will
** be invoked every nOps opcodes.
*/
-SQLITE_API void sqlite3_progress_handler(
+SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
sqlite3 *db,
int nOps,
int (*xProgress)(void*),
void *pArg
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
if( nOps>0 ){
db->xProgress = xProgress;
@@ -126297,7 +129017,10 @@ SQLITE_API void sqlite3_progress_handler(
** This routine installs a default busy handler that waits for the
** specified number of milliseconds before returning 0.
*/
-SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
if( ms>0 ){
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
db->busyTimeout = ms;
@@ -126310,7 +129033,13 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
/*
** Cause any pending operation to stop at its earliest opportunity.
*/
-SQLITE_API void sqlite3_interrupt(sqlite3 *db){
+SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return;
+ }
+#endif
db->u1.isInterrupted = 1;
}
@@ -126421,7 +129150,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
/*
** Create new user functions.
*/
-SQLITE_API int sqlite3_create_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
sqlite3 *db,
const char *zFunc,
int nArg,
@@ -126435,7 +129164,7 @@ SQLITE_API int sqlite3_create_function(
xFinal, 0);
}
-SQLITE_API int sqlite3_create_function_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunc,
int nArg,
@@ -126448,6 +129177,12 @@ SQLITE_API int sqlite3_create_function_v2(
){
int rc = SQLITE_ERROR;
FuncDestructor *pArg = 0;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
if( xDestroy ){
pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
@@ -126472,7 +129207,7 @@ SQLITE_API int sqlite3_create_function_v2(
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API int sqlite3_create_function16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -126484,6 +129219,10 @@ SQLITE_API int sqlite3_create_function16(
){
int rc;
char *zFunc8;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
@@ -126508,13 +129247,19 @@ SQLITE_API int sqlite3_create_function16(
** A global function must exist in order for name resolution to work
** properly.
*/
-SQLITE_API int sqlite3_overload_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
sqlite3 *db,
const char *zName,
int nArg
){
int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
@@ -126534,8 +129279,15 @@ SQLITE_API int sqlite3_overload_function(
** trace is a pointer to a function that is invoked at the start of each
** SQL statement.
*/
-SQLITE_API void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
+SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
void *pOld;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->xTrace = xTrace;
@@ -126551,12 +129303,19 @@ SQLITE_API void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), v
** profile is a pointer to a function that is invoked at the conclusion of
** each SQL statement that is run.
*/
-SQLITE_API void *sqlite3_profile(
+SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
sqlite3 *db,
void (*xProfile)(void*,const char*,sqlite_uint64),
void *pArg
){
void *pOld;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pProfileArg;
db->xProfile = xProfile;
@@ -126571,12 +129330,19 @@ SQLITE_API void *sqlite3_profile(
** If the invoked function returns non-zero, then the commit becomes a
** rollback.
*/
-SQLITE_API void *sqlite3_commit_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
sqlite3 *db, /* Attach the hook to this database */
int (*xCallback)(void*), /* Function to invoke on each commit */
void *pArg /* Argument to the function */
){
void *pOld;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pCommitArg;
db->xCommitCallback = xCallback;
@@ -126589,12 +129355,19 @@ SQLITE_API void *sqlite3_commit_hook(
** Register a callback to be invoked each time a row is updated,
** inserted or deleted using this database connection.
*/
-SQLITE_API void *sqlite3_update_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3 *db, /* Attach the hook to this database */
void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
void *pArg /* Argument to the function */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pUpdateArg;
db->xUpdateCallback = xCallback;
@@ -126607,12 +129380,19 @@ SQLITE_API void *sqlite3_update_hook(
** Register a callback to be invoked each time a transaction is rolled
** back by this database connection.
*/
-SQLITE_API void *sqlite3_rollback_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
sqlite3 *db, /* Attach the hook to this database */
void (*xCallback)(void*), /* Callback function */
void *pArg /* Argument to the function */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pRollbackArg;
db->xRollbackCallback = xCallback;
@@ -126654,11 +129434,14 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook(
** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
** configured by this function.
*/
-SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
#ifdef SQLITE_OMIT_WAL
UNUSED_PARAMETER(db);
UNUSED_PARAMETER(nFrame);
#else
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
if( nFrame>0 ){
sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
}else{
@@ -126672,13 +129455,19 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
** Register a callback to be invoked each time a transaction is written
** into the write-ahead-log by this database connection.
*/
-SQLITE_API void *sqlite3_wal_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3 *db, /* Attach the hook to this db handle */
int(*xCallback)(void *, sqlite3*, const char*, int),
void *pArg /* First argument passed to xCallback() */
){
#ifndef SQLITE_OMIT_WAL
void *pRet;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pWalArg;
db->xWalCallback = xCallback;
@@ -126693,7 +129482,7 @@ SQLITE_API void *sqlite3_wal_hook(
/*
** Checkpoint database zDb.
*/
-SQLITE_API int sqlite3_wal_checkpoint_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -126706,14 +129495,21 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
int rc; /* Return code */
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
+
/* Initialize the output variables to -1 in case an error occurs. */
if( pnLog ) *pnLog = -1;
if( pnCkpt ) *pnCkpt = -1;
- assert( SQLITE_CHECKPOINT_FULL>SQLITE_CHECKPOINT_PASSIVE );
- assert( SQLITE_CHECKPOINT_FULL<SQLITE_CHECKPOINT_RESTART );
- assert( SQLITE_CHECKPOINT_PASSIVE+2==SQLITE_CHECKPOINT_RESTART );
- if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_RESTART ){
+ assert( SQLITE_CHECKPOINT_PASSIVE==0 );
+ assert( SQLITE_CHECKPOINT_FULL==1 );
+ assert( SQLITE_CHECKPOINT_RESTART==2 );
+ assert( SQLITE_CHECKPOINT_TRUNCATE==3 );
+ if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
+ /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
+ ** mode: */
return SQLITE_MISUSE;
}
@@ -126725,6 +129521,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
rc = SQLITE_ERROR;
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
}else{
+ db->busyHandler.nBusy = 0;
rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
sqlite3Error(db, rc);
}
@@ -126740,8 +129537,10 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** to contains a zero-length string, all attached databases are
** checkpointed.
*/
-SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
- return sqlite3_wal_checkpoint_v2(db, zDb, SQLITE_CHECKPOINT_PASSIVE, 0, 0);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
+ /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to
+ ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */
+ return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0);
}
#ifndef SQLITE_OMIT_WAL
@@ -126827,7 +129626,7 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
** Return UTF-8 encoded English language explanation of the most recent
** error.
*/
-SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
const char *z;
if( !db ){
return sqlite3ErrStr(SQLITE_NOMEM);
@@ -126855,7 +129654,7 @@ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
** Return UTF-16 encoded English language explanation of the most recent
** error.
*/
-SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
+SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
static const u16 outOfMem[] = {
'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
};
@@ -126900,7 +129699,7 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
** Return the most recent error code generated by an SQLite routine. If NULL is
** passed to this function, we assume a malloc() failed during sqlite3_open().
*/
-SQLITE_API int sqlite3_errcode(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db){
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
@@ -126909,7 +129708,7 @@ SQLITE_API int sqlite3_errcode(sqlite3 *db){
}
return db->errCode & db->errMask;
}
-SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db){
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
@@ -126924,37 +129723,11 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
** argument. For now, this simply calls the internal sqlite3ErrStr()
** function.
*/
-SQLITE_API const char *sqlite3_errstr(int rc){
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int rc){
return sqlite3ErrStr(rc);
}
/*
-** Invalidate all cached KeyInfo objects for database connection "db"
-*/
-static void invalidateCachedKeyInfo(sqlite3 *db){
- Db *pDb; /* A single database */
- int iDb; /* The database index number */
- HashElem *k; /* For looping over tables in pDb */
- Table *pTab; /* A table in the database */
- Index *pIdx; /* Each index */
-
- for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
- if( pDb->pBt==0 ) continue;
- sqlite3BtreeEnter(pDb->pBt);
- for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
- pTab = (Table*)sqliteHashData(k);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->pKeyInfo && pIdx->pKeyInfo->db==db ){
- sqlite3KeyInfoUnref(pIdx->pKeyInfo);
- pIdx->pKeyInfo = 0;
- }
- }
- }
- sqlite3BtreeLeave(pDb->pBt);
- }
-}
-
-/*
** Create a new collating function for database "db". The name is zName
** and the encoding is enc.
*/
@@ -126997,7 +129770,6 @@ static int createCollation(
return SQLITE_BUSY;
}
sqlite3ExpirePreparedStatements(db);
- invalidateCachedKeyInfo(db);
/* If collation sequence pColl was created directly by a call to
** sqlite3_create_collation, and not generated by synthCollSeq(),
@@ -127099,9 +129871,15 @@ static const int aHardLimit[] = {
** It merely prevents new constructs that exceed the limit
** from forming.
*/
-SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
+SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
int oldLimit;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return -1;
+ }
+#endif
/* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME
** there is a hard upper bound set at compile-time by a C preprocessor
@@ -127178,7 +129956,8 @@ SQLITE_PRIVATE int sqlite3ParseUri(
assert( *pzErrMsg==0 );
- if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri)
+ if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
+ || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
&& nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
){
char *zOpt;
@@ -127196,7 +129975,19 @@ SQLITE_PRIVATE int sqlite3ParseUri(
if( !zFile ) return SQLITE_NOMEM;
iIn = 5;
-#ifndef SQLITE_ALLOW_URI_AUTHORITY
+#ifdef SQLITE_ALLOW_URI_AUTHORITY
+ if( strncmp(zUri+5, "///", 3)==0 ){
+ iIn = 7;
+ /* The following condition causes URIs with five leading / characters
+ ** like file://///host/path to be converted into UNCs like //host/path.
+ ** The correct URI for that UNC has only two or four leading / characters
+ ** file://host/path or file:////host/path. But 5 leading slashes is a
+ ** common error, we are told, so we handle it as a special case. */
+ if( strncmp(zUri+7, "///", 3)==0 ){ iIn++; }
+ }else if( strncmp(zUri+5, "//localhost/", 12)==0 ){
+ iIn = 16;
+ }
+#else
/* Discard the scheme and authority segments of the URI. */
if( zUri[5]=='/' && zUri[6]=='/' ){
iIn = 7;
@@ -127387,6 +130178,9 @@ static int openDatabase(
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@@ -127480,6 +130274,9 @@ static int openDatabase(
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
| SQLITE_AutoIndex
#endif
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+ | SQLITE_CkptFullFSync
+#endif
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
@@ -127492,6 +130289,9 @@ static int openDatabase(
#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS
| SQLITE_ForeignKeys
#endif
+#if defined(SQLITE_REVERSE_UNORDERED_SELECTS)
+ | SQLITE_ReverseOrder
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -127501,20 +130301,24 @@ static int openDatabase(
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
+ **
+ ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating
+ ** functions:
*/
createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0);
createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0);
createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0);
+ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
if( db->mallocFailed ){
goto opendb_out;
}
+ /* EVIDENCE-OF: R-08308-17224 The default collating function for all
+ ** strings is BINARY.
+ */
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
assert( db->pDfltColl!=0 );
- /* Also add a UTF-8 case-insensitive collation sequence. */
- createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
-
/* Parse the filename/URI argument. */
db->openFlags = flags;
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
@@ -127535,7 +130339,10 @@ static int openDatabase(
sqlite3Error(db, rc);
goto opendb_out;
}
+ sqlite3BtreeEnter(db->aDb[0].pBt);
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
+ if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
+ sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
/* The default safety_level for the main database is 'full'; for the temp
@@ -127623,7 +130430,8 @@ static int openDatabase(
opendb_out:
sqlite3_free(zOpen);
if( db ){
- assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
+ assert( db->mutex!=0 || isThreadsafe==0
+ || sqlite3GlobalConfig.bFullMutex==0 );
sqlite3_mutex_leave(db->mutex);
}
rc = sqlite3_errcode(db);
@@ -127648,14 +130456,14 @@ opendb_out:
/*
** Open a new database handle.
*/
-SQLITE_API int sqlite3_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_open(
const char *zFilename,
sqlite3 **ppDb
){
return openDatabase(zFilename, ppDb,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
}
-SQLITE_API int sqlite3_open_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -127668,7 +130476,7 @@ SQLITE_API int sqlite3_open_v2(
/*
** Open a new database handle.
*/
-SQLITE_API int sqlite3_open16(
+SQLITE_API int SQLITE_STDCALL sqlite3_open16(
const void *zFilename,
sqlite3 **ppDb
){
@@ -127676,13 +130484,15 @@ SQLITE_API int sqlite3_open16(
sqlite3_value *pVal;
int rc;
- assert( zFilename );
- assert( ppDb );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
+#endif
*ppDb = 0;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ) return rc;
#endif
+ if( zFilename==0 ) zFilename = "\000\000";
pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
@@ -127691,7 +130501,7 @@ SQLITE_API int sqlite3_open16(
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
assert( *ppDb || rc==SQLITE_NOMEM );
if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
- ENC(*ppDb) = SQLITE_UTF16NATIVE;
+ SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
}
}else{
rc = SQLITE_NOMEM;
@@ -127705,26 +130515,20 @@ SQLITE_API int sqlite3_open16(
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int sqlite3_create_collation(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
sqlite3* db,
const char *zName,
int enc,
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
- int rc;
- sqlite3_mutex_enter(db->mutex);
- assert( !db->mallocFailed );
- rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, 0);
- rc = sqlite3ApiExit(db, rc);
- sqlite3_mutex_leave(db->mutex);
- return rc;
+ return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0);
}
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int sqlite3_create_collation_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
sqlite3* db,
const char *zName,
int enc,
@@ -127733,6 +130537,10 @@ SQLITE_API int sqlite3_create_collation_v2(
void(*xDel)(void*)
){
int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel);
@@ -127745,7 +130553,7 @@ SQLITE_API int sqlite3_create_collation_v2(
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int sqlite3_create_collation16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
sqlite3* db,
const void *zName,
int enc,
@@ -127754,6 +130562,10 @@ SQLITE_API int sqlite3_create_collation16(
){
int rc = SQLITE_OK;
char *zName8;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
@@ -127771,11 +130583,14 @@ SQLITE_API int sqlite3_create_collation16(
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
-SQLITE_API int sqlite3_collation_needed(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
sqlite3 *db,
void *pCollNeededArg,
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = xCollNeeded;
db->xCollNeeded16 = 0;
@@ -127789,11 +130604,14 @@ SQLITE_API int sqlite3_collation_needed(
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
-SQLITE_API int sqlite3_collation_needed16(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
sqlite3 *db,
void *pCollNeededArg,
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = 0;
db->xCollNeeded16 = xCollNeeded16;
@@ -127808,7 +130626,7 @@ SQLITE_API int sqlite3_collation_needed16(
** This function is now an anachronism. It used to be used to recover from a
** malloc() failure, but SQLite now does this automatically.
*/
-SQLITE_API int sqlite3_global_recover(void){
+SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
return SQLITE_OK;
}
#endif
@@ -127819,7 +130637,13 @@ SQLITE_API int sqlite3_global_recover(void){
** by default. Autocommit is disabled by a BEGIN statement and reenabled
** by the next COMMIT or ROLLBACK.
*/
-SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
return db->autoCommit;
}
@@ -127865,7 +130689,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
** SQLite no longer uses thread-specific data so this routine is now a
** no-op. It is retained for historical compatibility.
*/
-SQLITE_API void sqlite3_thread_cleanup(void){
+SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
}
#endif
@@ -127873,8 +130697,7 @@ SQLITE_API void sqlite3_thread_cleanup(void){
** Return meta information about a specific column of a database table.
** See comment in sqlite3.h (sqlite.h.in) for details.
*/
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
-SQLITE_API int sqlite3_table_column_metadata(
+SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -127889,14 +130712,20 @@ SQLITE_API int sqlite3_table_column_metadata(
char *zErrMsg = 0;
Table *pTab = 0;
Column *pCol = 0;
- int iCol;
-
+ int iCol = 0;
char const *zDataType = 0;
char const *zCollSeq = 0;
int notnull = 0;
int primarykey = 0;
int autoinc = 0;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+
/* Ensure the database schema has been loaded */
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
@@ -127913,11 +130742,8 @@ SQLITE_API int sqlite3_table_column_metadata(
}
/* Find the column for which info is requested */
- if( sqlite3IsRowid(zColumnName) ){
- iCol = pTab->iPKey;
- if( iCol>=0 ){
- pCol = &pTab->aCol[iCol];
- }
+ if( zColumnName==0 ){
+ /* Query for existance of table only */
}else{
for(iCol=0; iCol<pTab->nCol; iCol++){
pCol = &pTab->aCol[iCol];
@@ -127926,8 +130752,13 @@ SQLITE_API int sqlite3_table_column_metadata(
}
}
if( iCol==pTab->nCol ){
- pTab = 0;
- goto error_out;
+ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){
+ iCol = pTab->iPKey;
+ pCol = iCol>=0 ? &pTab->aCol[iCol] : 0;
+ }else{
+ pTab = 0;
+ goto error_out;
+ }
}
}
@@ -127980,12 +130811,11 @@ error_out:
sqlite3_mutex_leave(db->mutex);
return rc;
}
-#endif
/*
** Sleep for a little while. Return the amount of time slept.
*/
-SQLITE_API int sqlite3_sleep(int ms){
+SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
sqlite3_vfs *pVfs;
int rc;
pVfs = sqlite3_vfs_find(0);
@@ -128001,7 +130831,10 @@ SQLITE_API int sqlite3_sleep(int ms){
/*
** Enable or disable the extended result codes.
*/
-SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
db->errMask = onoff ? 0xffffffff : 0xff;
sqlite3_mutex_leave(db->mutex);
@@ -128011,10 +130844,13 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
/*
** Invoke the xFileControl method on a particular database.
*/
-SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
+SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
int rc = SQLITE_ERROR;
Btree *pBtree;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
pBtree = sqlite3DbNameToBtree(db, zDbName);
if( pBtree ){
@@ -128036,13 +130872,13 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
sqlite3BtreeLeave(pBtree);
}
sqlite3_mutex_leave(db->mutex);
- return rc;
+ return rc;
}
/*
** Interface to the testing logic.
*/
-SQLITE_API int sqlite3_test_control(int op, ...){
+SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
int rc = 0;
#ifndef SQLITE_OMIT_BUILTIN_TEST
va_list ap;
@@ -128339,6 +131175,35 @@ SQLITE_API int sqlite3_test_control(int op, ...){
if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR;
break;
}
+
+ /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum);
+ **
+ ** This test control is used to create imposter tables. "db" is a pointer
+ ** to the database connection. dbName is the database name (ex: "main" or
+ ** "temp") which will receive the imposter. "onOff" turns imposter mode on
+ ** or off. "tnum" is the root page of the b-tree to which the imposter
+ ** table should connect.
+ **
+ ** Enable imposter mode only when the schema has already been parsed. Then
+ ** run a single CREATE TABLE statement to construct the imposter table in
+ ** the parsed schema. Then turn imposter mode back off again.
+ **
+ ** If onOff==0 and tnum>0 then reset the schema for all databases, causing
+ ** the schema to be reparsed the next time it is needed. This has the
+ ** effect of erasing all imposter tables.
+ */
+ case SQLITE_TESTCTRL_IMPOSTER: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ sqlite3_mutex_enter(db->mutex);
+ db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
+ db->init.busy = db->init.imposterTable = va_arg(ap,int);
+ db->init.newTnum = va_arg(ap,int);
+ if( db->init.busy==0 && db->init.newTnum>0 ){
+ sqlite3ResetAllSchemasOfConnection(db);
+ }
+ sqlite3_mutex_leave(db->mutex);
+ break;
+ }
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
@@ -128356,8 +131221,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** parameter if it exists. If the parameter does not exist, this routine
** returns a NULL pointer.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
- if( zFilename==0 ) return 0;
+SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam){
+ if( zFilename==0 || zParam==0 ) return 0;
zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){
int x = strcmp(zFilename, zParam);
@@ -128371,7 +131236,7 @@ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *
/*
** Return a boolean value for a query parameter.
*/
-SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
+SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
bDflt = bDflt!=0;
return z ? sqlite3GetBoolean(z, bDflt) : bDflt;
@@ -128380,7 +131245,7 @@ SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, in
/*
** Return a 64-bit integer value for a query parameter.
*/
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
const char *zFilename, /* Filename as passed to xOpen */
const char *zParam, /* URI parameter sought */
sqlite3_int64 bDflt /* return if parameter is missing */
@@ -128412,8 +131277,15 @@ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
** Return the filename of the database associated with a database
** connection.
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
- Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName){
+ Btree *pBt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
}
@@ -128421,8 +131293,15 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
** Return 1 if database is read-only or 0 if read/write. Return -1 if
** no such database exists.
*/
-SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
- Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
+ Btree *pBt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return -1;
+ }
+#endif
+ pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
}
@@ -128573,7 +131452,7 @@ static void leaveMutex(void){
** on the same "db". If xNotify==0 then any prior callbacks are immediately
** cancelled.
*/
-SQLITE_API int sqlite3_unlock_notify(
+SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
sqlite3 *db,
void (*xNotify)(void **, int),
void *pArg
@@ -129708,6 +132587,11 @@ struct Fts3Phrase {
int bIncr; /* True if doclist is loaded incrementally */
int iDoclistToken;
+ /* Used by sqlite3Fts3EvalPhrasePoslist() if this is a descendent of an
+ ** OR condition. */
+ char *pOrPoslist;
+ i64 iOrDocid;
+
/* Variables below this point are populated by fts3_expr.c when parsing
** a MATCH expression. Everything above is part of the evaluation phase.
*/
@@ -130548,11 +133432,16 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
** This function is used when parsing the "prefix=" FTS4 parameter.
*/
static int fts3GobbleInt(const char **pp, int *pnOut){
+ const int MAX_NPREFIX = 10000000;
const char *p; /* Iterator pointer */
int nInt = 0; /* Output value */
for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
nInt = nInt * 10 + (p[0] - '0');
+ if( nInt>MAX_NPREFIX ){
+ nInt = 0;
+ break;
+ }
}
if( p==*pp ) return SQLITE_ERROR;
*pnOut = nInt;
@@ -130595,7 +133484,6 @@ static int fts3PrefixParameter(
aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
*apIndex = aIndex;
- *pnIndex = nIndex;
if( !aIndex ){
return SQLITE_NOMEM;
}
@@ -130605,13 +133493,20 @@ static int fts3PrefixParameter(
const char *p = zParam;
int i;
for(i=1; i<nIndex; i++){
- int nPrefix;
+ int nPrefix = 0;
if( fts3GobbleInt(&p, &nPrefix) ) return SQLITE_ERROR;
- aIndex[i].nPrefix = nPrefix;
+ assert( nPrefix>=0 );
+ if( nPrefix==0 ){
+ nIndex--;
+ i--;
+ }else{
+ aIndex[i].nPrefix = nPrefix;
+ }
p++;
}
}
+ *pnIndex = nIndex;
return SQLITE_OK;
}
@@ -130735,7 +133630,7 @@ static int fts3InitVtab(
const char **aCol; /* Array of column names */
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
- int nIndex; /* Size of aIndex[] array */
+ int nIndex = 0; /* Size of aIndex[] array */
struct Fts3Index *aIndex = 0; /* Array of indexes for this table */
/* The results of parsing supported FTS4 key=value options: */
@@ -131491,7 +134386,7 @@ static int fts3SelectLeaf(
sqlite3_int64 *piLeaf, /* Selected leaf node */
sqlite3_int64 *piLeaf2 /* Selected leaf node */
){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int iHeight; /* Height of this node in tree */
assert( piLeaf || piLeaf2 );
@@ -131502,7 +134397,7 @@ static int fts3SelectLeaf(
if( rc==SQLITE_OK && iHeight>1 ){
char *zBlob = 0; /* Blob read from %_segments table */
- int nBlob; /* Size of zBlob in bytes */
+ int nBlob = 0; /* Size of zBlob in bytes */
if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);
@@ -132129,26 +135024,33 @@ static int fts3DoclistOrMerge(
**
** The right-hand input doclist is overwritten by this function.
*/
-static void fts3DoclistPhraseMerge(
+static int fts3DoclistPhraseMerge(
int bDescDoclist, /* True if arguments are desc */
int nDist, /* Distance from left to right (1=adjacent) */
char *aLeft, int nLeft, /* Left doclist */
- char *aRight, int *pnRight /* IN/OUT: Right/output doclist */
+ char **paRight, int *pnRight /* IN/OUT: Right/output doclist */
){
sqlite3_int64 i1 = 0;
sqlite3_int64 i2 = 0;
sqlite3_int64 iPrev = 0;
+ char *aRight = *paRight;
char *pEnd1 = &aLeft[nLeft];
char *pEnd2 = &aRight[*pnRight];
char *p1 = aLeft;
char *p2 = aRight;
char *p;
int bFirstOut = 0;
- char *aOut = aRight;
+ char *aOut;
assert( nDist>0 );
-
+ if( bDescDoclist ){
+ aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX);
+ if( aOut==0 ) return SQLITE_NOMEM;
+ }else{
+ aOut = aRight;
+ }
p = aOut;
+
fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1);
fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2);
@@ -132177,6 +135079,12 @@ static void fts3DoclistPhraseMerge(
}
*pnRight = (int)(p - aOut);
+ if( bDescDoclist ){
+ sqlite3_free(aRight);
+ *paRight = aOut;
+ }
+
+ return SQLITE_OK;
}
/*
@@ -132301,8 +135209,22 @@ static int fts3TermSelectMerge(
){
if( pTS->aaOutput[0]==0 ){
/* If this is the first term selected, copy the doclist to the output
- ** buffer using memcpy(). */
- pTS->aaOutput[0] = sqlite3_malloc(nDoclist);
+ ** buffer using memcpy().
+ **
+ ** Add FTS3_VARINT_MAX bytes of unused space to the end of the
+ ** allocation. This is so as to ensure that the buffer is big enough
+ ** to hold the current doclist AND'd with any other doclist. If the
+ ** doclists are stored in order=ASC order, this padding would not be
+ ** required (since the size of [doclistA AND doclistB] is always less
+ ** than or equal to the size of [doclistA] in that case). But this is
+ ** not true for order=DESC. For example, a doclist containing (1, -1)
+ ** may be smaller than (-1), as in the first example the -1 may be stored
+ ** as a single-byte delta, whereas in the second it must be stored as a
+ ** FTS3_VARINT_MAX byte varint.
+ **
+ ** Similar padding is added in the fts3DoclistOrMerge() function.
+ */
+ pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
@@ -132724,7 +135646,7 @@ static int fts3FilterMethod(
int nVal, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
- int rc;
+ int rc = SQLITE_OK;
char *zSql; /* SQL statement used to access %_content */
int eSearch;
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
@@ -132802,10 +135724,17 @@ static int fts3FilterMethod(
** row by docid.
*/
if( eSearch==FTS3_FULLSCAN_SEARCH ){
- zSql = sqlite3_mprintf(
- "SELECT %s ORDER BY rowid %s",
- p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
- );
+ if( pDocidGe || pDocidLe ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s",
+ p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid,
+ (pCsr->bDesc ? "DESC" : "ASC")
+ );
+ }else{
+ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
+ p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
+ );
+ }
if( zSql ){
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
sqlite3_free(zSql);
@@ -133551,14 +136480,17 @@ static void fts3EvalAllocateReaders(
** This function assumes that pList points to a buffer allocated using
** sqlite3_malloc(). This function takes responsibility for eventually
** freeing the buffer.
+**
+** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs.
*/
-static void fts3EvalPhraseMergeToken(
+static int fts3EvalPhraseMergeToken(
Fts3Table *pTab, /* FTS Table pointer */
Fts3Phrase *p, /* Phrase to merge pList/nList into */
int iToken, /* Token pList/nList corresponds to */
char *pList, /* Pointer to doclist */
int nList /* Number of bytes in pList */
){
+ int rc = SQLITE_OK;
assert( iToken!=p->iDoclistToken );
if( pList==0 ){
@@ -133597,13 +136529,16 @@ static void fts3EvalPhraseMergeToken(
nDiff = p->iDoclistToken - iToken;
}
- fts3DoclistPhraseMerge(pTab->bDescIdx, nDiff, pLeft, nLeft, pRight,&nRight);
+ rc = fts3DoclistPhraseMerge(
+ pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight
+ );
sqlite3_free(pLeft);
p->doclist.aAll = pRight;
p->doclist.nAll = nRight;
}
if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken;
+ return rc;
}
/*
@@ -133629,7 +136564,7 @@ static int fts3EvalPhraseLoad(
char *pThis = 0;
rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis);
if( rc==SQLITE_OK ){
- fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis);
+ rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis);
}
}
assert( pToken->pSegcsr==0 );
@@ -134432,8 +137367,12 @@ static int fts3EvalSelectDeferred(
rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList);
assert( rc==SQLITE_OK || pList==0 );
if( rc==SQLITE_OK ){
+ rc = fts3EvalPhraseMergeToken(
+ pTab, pTC->pPhrase, pTC->iToken,pList,nList
+ );
+ }
+ if( rc==SQLITE_OK ){
int nCount;
- fts3EvalPhraseMergeToken(pTab, pTC->pPhrase, pTC->iToken,pList,nList);
nCount = fts3DoclistCountDocids(
pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll
);
@@ -134658,6 +137597,22 @@ static void fts3EvalNextRow(
}
pExpr->iDocid = pLeft->iDocid;
pExpr->bEof = (pLeft->bEof || pRight->bEof);
+ if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
+ if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
+ Fts3Doclist *pDl = &pRight->pPhrase->doclist;
+ while( *pRc==SQLITE_OK && pRight->bEof==0 ){
+ memset(pDl->pList, 0, pDl->nList);
+ fts3EvalNextRow(pCsr, pRight, pRc);
+ }
+ }
+ if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){
+ Fts3Doclist *pDl = &pLeft->pPhrase->doclist;
+ while( *pRc==SQLITE_OK && pLeft->bEof==0 ){
+ memset(pDl->pList, 0, pDl->nList);
+ fts3EvalNextRow(pCsr, pLeft, pRc);
+ }
+ }
+ }
}
break;
}
@@ -135030,6 +137985,7 @@ static void fts3EvalRestart(
}
pPhrase->doclist.pNextDocid = 0;
pPhrase->doclist.iDocid = 0;
+ pPhrase->pOrPoslist = 0;
}
pExpr->iDocid = 0;
@@ -135275,8 +138231,8 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
iDocid = pExpr->iDocid;
pIter = pPhrase->doclist.pList;
if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
+ int rc = SQLITE_OK;
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
- int iMul; /* +1 if csr dir matches index dir, else -1 */
int bOr = 0;
u8 bEof = 0;
u8 bTreeEof = 0;
@@ -135300,72 +138256,43 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
** an incremental phrase. Load the entire doclist for the phrase
** into memory in this case. */
if( pPhrase->bIncr ){
- int rc = SQLITE_OK;
- int bEofSave = pExpr->bEof;
- fts3EvalRestart(pCsr, pExpr, &rc);
- while( rc==SQLITE_OK && !pExpr->bEof ){
- fts3EvalNextRow(pCsr, pExpr, &rc);
- if( bEofSave==0 && pExpr->iDocid==iDocid ) break;
+ int bEofSave = pNear->bEof;
+ fts3EvalRestart(pCsr, pNear, &rc);
+ while( rc==SQLITE_OK && !pNear->bEof ){
+ fts3EvalNextRow(pCsr, pNear, &rc);
+ if( bEofSave==0 && pNear->iDocid==iDocid ) break;
}
- pIter = pPhrase->doclist.pList;
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
- if( rc!=SQLITE_OK ) return rc;
}
-
- iMul = ((pCsr->bDesc==bDescDoclist) ? 1 : -1);
- while( bTreeEof==1
- && pNear->bEof==0
- && (DOCID_CMP(pNear->iDocid, pCsr->iPrevId) * iMul)<0
- ){
- int rc = SQLITE_OK;
- fts3EvalNextRow(pCsr, pExpr, &rc);
- if( rc!=SQLITE_OK ) return rc;
- iDocid = pExpr->iDocid;
- pIter = pPhrase->doclist.pList;
+ if( bTreeEof ){
+ while( rc==SQLITE_OK && !pNear->bEof ){
+ fts3EvalNextRow(pCsr, pNear, &rc);
+ }
}
+ if( rc!=SQLITE_OK ) return rc;
- bEof = (pPhrase->doclist.nAll==0);
- assert( bDescDoclist==0 || bDescDoclist==1 );
- assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
-
- if( bEof==0 ){
- if( pCsr->bDesc==bDescDoclist ){
+ pIter = pPhrase->pOrPoslist;
+ iDocid = pPhrase->iOrDocid;
+ if( pCsr->bDesc==bDescDoclist ){
+ bEof = (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll));
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
+ sqlite3Fts3DoclistNext(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &bEof
+ );
+ }
+ }else{
+ bEof = !pPhrase->doclist.nAll || (pIter && pIter<=pPhrase->doclist.aAll);
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
int dummy;
- if( pNear->bEof ){
- /* This expression is already at EOF. So position it to point to the
- ** last entry in the doclist at pPhrase->doclist.aAll[]. Variable
- ** iDocid is already set for this entry, so all that is required is
- ** to set pIter to point to the first byte of the last position-list
- ** in the doclist.
- **
- ** It would also be correct to set pIter and iDocid to zero. In
- ** this case, the first call to sqltie3Fts4DoclistPrev() below
- ** would also move the iterator to point to the last entry in the
- ** doclist. However, this is expensive, as to do so it has to
- ** iterate through the entire doclist from start to finish (since
- ** it does not know the docid for the last entry). */
- pIter = &pPhrase->doclist.aAll[pPhrase->doclist.nAll-1];
- fts3ReversePoslist(pPhrase->doclist.aAll, &pIter);
- }
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
- sqlite3Fts3DoclistPrev(
- bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
- &pIter, &iDocid, &dummy, &bEof
- );
- }
- }else{
- if( pNear->bEof ){
- pIter = 0;
- iDocid = 0;
- }
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
- sqlite3Fts3DoclistNext(
- bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
- &pIter, &iDocid, &bEof
- );
- }
+ sqlite3Fts3DoclistPrev(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &dummy, &bEof
+ );
}
}
+ pPhrase->pOrPoslist = pIter;
+ pPhrase->iOrDocid = iDocid;
if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
}
@@ -135379,10 +138306,13 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
}
while( iThis<iCol ){
fts3ColumnlistCopy(0, &pIter);
- if( *pIter==0x00 ) return 0;
+ if( *pIter==0x00 ) return SQLITE_OK;
pIter++;
pIter += fts3GetVarint32(pIter, &iThis);
}
+ if( *pIter==0x00 ){
+ pIter = 0;
+ }
*ppOut = ((iCol==iThis)?pIter:0);
return SQLITE_OK;
@@ -135425,7 +138355,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int sqlite3_fts3_init(
+SQLITE_API int SQLITE_STDCALL sqlite3_fts3_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -137843,7 +140773,7 @@ static int isVowel(const char *z){
** by a consonant.
**
** In this routine z[] is in reverse order. So we are really looking
-** for an instance of of a consonant followed by a vowel.
+** for an instance of a consonant followed by a vowel.
*/
static int m_gt_0(const char *z){
while( isVowel(z) ){ z++; }
@@ -138393,7 +141323,7 @@ static void scalarFunc(
if( argc==2 ){
void *pOld;
int n = sqlite3_value_bytes(argv[1]);
- if( n!=sizeof(pPtr) ){
+ if( zName==0 || n!=sizeof(pPtr) ){
sqlite3_result_error(context, "argument type mismatch", -1);
return;
}
@@ -138404,7 +141334,9 @@ static void scalarFunc(
return;
}
}else{
- pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
+ if( zName ){
+ pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
+ }
if( !pPtr ){
char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
sqlite3_result_error(context, zErr, -1);
@@ -138485,6 +141417,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
zEnd = &zCopy[strlen(zCopy)];
z = (char *)sqlite3Fts3NextToken(zCopy, &n);
+ if( z==0 ){
+ assert( n==0 );
+ z = zCopy;
+ }
z[n] = '\0';
sqlite3Fts3Dequote(z);
@@ -139212,7 +142148,7 @@ static int fts3tokConnectMethod(
sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
char **pzErr /* OUT: sqlite3_malloc'd error message */
){
- Fts3tokTable *pTab;
+ Fts3tokTable *pTab = 0;
const sqlite3_tokenizer_module *pMod = 0;
sqlite3_tokenizer *pTok = 0;
int rc;
@@ -141130,7 +144066,10 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
** an array of pending terms by term. This occurs as part of flushing
** the contents of the pending-terms hash table to the database.
*/
-static int fts3CompareElemByTerm(const void *lhs, const void *rhs){
+static int SQLITE_CDECL fts3CompareElemByTerm(
+ const void *lhs,
+ const void *rhs
+){
char *z1 = fts3HashKey(*(Fts3HashElem **)lhs);
char *z2 = fts3HashKey(*(Fts3HashElem **)rhs);
int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs);
@@ -142587,8 +145526,8 @@ static int fts3PromoteSegments(
if( bOk ){
int iIdx = 0;
- sqlite3_stmt *pUpdate1;
- sqlite3_stmt *pUpdate2;
+ sqlite3_stmt *pUpdate1 = 0;
+ sqlite3_stmt *pUpdate2 = 0;
if( rc==SQLITE_OK ){
rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0);
@@ -145609,37 +148548,39 @@ static int fts3BestSnippet(
sIter.nSnippet = nSnippet;
sIter.nPhrase = nList;
sIter.iCurrent = -1;
- (void)fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
+ rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
+ if( rc==SQLITE_OK ){
- /* Set the *pmSeen output variable. */
- for(i=0; i<nList; i++){
- if( sIter.aPhrase[i].pHead ){
- *pmSeen |= (u64)1 << i;
+ /* Set the *pmSeen output variable. */
+ for(i=0; i<nList; i++){
+ if( sIter.aPhrase[i].pHead ){
+ *pmSeen |= (u64)1 << i;
+ }
}
- }
- /* Loop through all candidate snippets. Store the best snippet in
- ** *pFragment. Store its associated 'score' in iBestScore.
- */
- pFragment->iCol = iCol;
- while( !fts3SnippetNextCandidate(&sIter) ){
- int iPos;
- int iScore;
- u64 mCover;
- u64 mHighlight;
- fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover, &mHighlight);
- assert( iScore>=0 );
- if( iScore>iBestScore ){
- pFragment->iPos = iPos;
- pFragment->hlmask = mHighlight;
- pFragment->covered = mCover;
- iBestScore = iScore;
+ /* Loop through all candidate snippets. Store the best snippet in
+ ** *pFragment. Store its associated 'score' in iBestScore.
+ */
+ pFragment->iCol = iCol;
+ while( !fts3SnippetNextCandidate(&sIter) ){
+ int iPos;
+ int iScore;
+ u64 mCover;
+ u64 mHighlite;
+ fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite);
+ assert( iScore>=0 );
+ if( iScore>iBestScore ){
+ pFragment->iPos = iPos;
+ pFragment->hlmask = mHighlite;
+ pFragment->covered = mCover;
+ iBestScore = iScore;
+ }
}
- }
+ *piScore = iBestScore;
+ }
sqlite3_free(sIter.aPhrase);
- *piScore = iBestScore;
- return SQLITE_OK;
+ return rc;
}
@@ -145847,8 +148788,12 @@ static int fts3SnippetText(
** required. They are required if (a) this is not the first fragment,
** or (b) this fragment does not begin at position 0 of its column.
*/
- if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){
- rc = fts3StringAppend(pOut, zEllipsis, -1);
+ if( rc==SQLITE_OK ){
+ if( iPos>0 || iFragment>0 ){
+ rc = fts3StringAppend(pOut, zEllipsis, -1);
+ }else if( iBegin ){
+ rc = fts3StringAppend(pOut, zDoc, iBegin);
+ }
}
if( rc!=SQLITE_OK || iCurrent<iPos ) continue;
}
@@ -146414,7 +149359,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
*/
for(iRead=0; iRead<pTab->nColumn; iRead++){
SnippetFragment sF = {0, 0, 0, 0};
- int iS;
+ int iS = 0;
if( iCol>=0 && iRead!=iCol ) continue;
/* Find the best snippet of nFToken tokens in column iRead. */
@@ -147820,13 +150765,12 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
- u32 i = (
+ pCoord->u = (
(((u32)p[0]) << 24) +
(((u32)p[1]) << 16) +
(((u32)p[2]) << 8) +
(((u32)p[3]) << 0)
);
- *(u32 *)pCoord = i;
}
static i64 readInt64(u8 *p){
return (
@@ -147855,7 +150799,7 @@ static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
- i = *(u32 *)pCoord;
+ i = pCoord->u;
p[0] = (i>>24)&0xFF;
p[1] = (i>>16)&0xFF;
p[2] = (i>> 8)&0xFF;
@@ -148186,14 +151130,13 @@ static void nodeGetCell(
RtreeCell *pCell /* OUT: Write the cell contents here */
){
u8 *pData;
- u8 *pEnd;
RtreeCoord *pCoord;
+ int ii;
pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
- pEnd = pData + pRtree->nDim*8;
pCoord = pCell->aCoord;
- for(; pData<pEnd; pData+=4, pCoord++){
- readCoord(pData, pCoord);
+ for(ii=0; ii<pRtree->nDim*2; ii++){
+ readCoord(&pData[ii*4], &pCoord[ii]);
}
}
@@ -148633,7 +151576,7 @@ static RtreeSearchPoint *rtreeEnqueue(
pNew = pCur->aPoint + i;
pNew->rScore = rScore;
pNew->iLevel = iLevel;
- assert( iLevel>=0 && iLevel<=RTREE_MAX_DEPTH );
+ assert( iLevel<=RTREE_MAX_DEPTH );
while( i>0 ){
RtreeSearchPoint *pParent;
j = (i-1)/2;
@@ -150257,6 +153200,8 @@ static int rtreeUpdate(
rtreeReference(pRtree);
assert(nData>=1);
+ cell.iRowid = 0; /* Used only to suppress a compiler warning */
+
/* Constraint handling. A write operation on an r-tree table may return
** SQLITE_CONSTRAINT for two reasons:
**
@@ -150857,7 +153802,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
/*
** Register a new geometry function for use with the r-tree MATCH operator.
*/
-SQLITE_API int sqlite3_rtree_geometry_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
sqlite3 *db, /* Register SQL function on this connection */
const char *zGeom, /* Name of the new SQL function */
int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */
@@ -150881,7 +153826,7 @@ SQLITE_API int sqlite3_rtree_geometry_callback(
** Register a new 2nd-generation geometry function for use with the
** r-tree MATCH operator.
*/
-SQLITE_API int sqlite3_rtree_query_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
sqlite3 *db, /* Register SQL function on this connection */
const char *zQueryFunc, /* Name of new SQL function */
int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */
@@ -150906,7 +153851,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int sqlite3_rtree_init(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -151411,7 +154356,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int sqlite3_icu_init(
+SQLITE_API int SQLITE_STDCALL sqlite3_icu_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
diff --git a/contrib/sqlite3/sqlite3.h b/contrib/sqlite3/sqlite3.h
index 023dad1..2c244ab 100644
--- a/contrib/sqlite3/sqlite3.h
+++ b/contrib/sqlite3/sqlite3.h
@@ -43,21 +43,25 @@ extern "C" {
/*
-** Add the ability to override 'extern'
+** Provide the ability to override linkage features of the interface.
*/
#ifndef SQLITE_EXTERN
# define SQLITE_EXTERN extern
#endif
-
#ifndef SQLITE_API
# define SQLITE_API
#endif
-
+#ifndef SQLITE_CDECL
+# define SQLITE_CDECL
+#endif
+#ifndef SQLITE_STDCALL
+# define SQLITE_STDCALL
+#endif
/*
** These no-op macros are used in front of interfaces to mark those
** interfaces as either deprecated or experimental. New applications
-** should not use deprecated interfaces - they are support for backwards
+** should not use deprecated interfaces - they are supported for backwards
** compatibility only. Application writers should be aware that
** experimental interfaces are subject to change in point releases.
**
@@ -107,9 +111,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.8.7.2"
-#define SQLITE_VERSION_NUMBER 3008007
-#define SQLITE_SOURCE_ID "2014-11-18 20:57:56 2ab564bf9655b7c7b97ab85cafc8a48329b27f93"
+#define SQLITE_VERSION "3.8.9"
+#define SQLITE_VERSION_NUMBER 3008009
+#define SQLITE_SOURCE_ID "2015-04-08 12:16:33 8a8ffc862e96f57aa698f93de10dee28e69f6e09"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -142,9 +146,9 @@ extern "C" {
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
SQLITE_API SQLITE_EXTERN const char sqlite3_version[];
-SQLITE_API const char *sqlite3_libversion(void);
-SQLITE_API const char *sqlite3_sourceid(void);
-SQLITE_API int sqlite3_libversion_number(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
@@ -169,8 +173,8 @@ SQLITE_API int sqlite3_libversion_number(void);
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
-SQLITE_API const char *sqlite3_compileoption_get(int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
#endif
/*
@@ -201,7 +205,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
** can be fully or partially disabled using a call to [sqlite3_config()]
** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
-** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
+** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the
** sqlite3_threadsafe() function shows only the compile-time setting of
** thread safety, not any run-time changes to that setting made by
** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
@@ -209,7 +213,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
**
** See the [threading mode] documentation for additional information.
*/
-SQLITE_API int sqlite3_threadsafe(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
/*
** CAPI3REF: Database Connection Handle
@@ -305,8 +309,8 @@ typedef sqlite_uint64 sqlite3_uint64;
** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
** argument is a harmless no-op.
*/
-SQLITE_API int sqlite3_close(sqlite3*);
-SQLITE_API int sqlite3_close_v2(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
/*
** The type for a callback function.
@@ -376,7 +380,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** </ul>
*/
-SQLITE_API int sqlite3_exec(
+SQLITE_API int SQLITE_STDCALL sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
@@ -756,14 +760,16 @@ struct sqlite3_io_methods {
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
+** <ul>
+** <li>[[SQLITE_FCNTL_LOCKSTATE]]
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-** <ul>
+** is used during testing and is only available when the SQLITE_TEST
+** compile-time option is used.
+**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
@@ -888,7 +894,9 @@ struct sqlite3_io_methods {
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
** file control returns [SQLITE_OK], then the parser assumes that the
** VFS has handled the PRAGMA itself and the parser generates a no-op
-** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns
+** prepared statement if result string is NULL, or that returns a copy
+** of the result string if the string is non-NULL.
+** ^If the [SQLITE_FCNTL_PRAGMA] file control returns
** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means
** that the VFS encountered an error while handling the [PRAGMA] and the
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
@@ -946,12 +954,19 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
+** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
+** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
+** be advantageous to block on the next WAL lock if the lock is not immediately
+** available. The WAL subsystem issues this signal during rare
+** circumstances in order to fix a problem with priority inversion.
+** Applications should <em>not</em> use this file-control.
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
+#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3
+#define SQLITE_FCNTL_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7
@@ -970,6 +985,13 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_SYNC 21
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
+#define SQLITE_FCNTL_WAL_BLOCK 24
+
+/* deprecated names */
+#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
+#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
+#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
+
/*
** CAPI3REF: Mutex Handle
@@ -1221,7 +1243,7 @@ struct sqlite3_vfs {
** </ul>
**
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
-** was given no the corresponding lock.
+** was given on the corresponding lock.
**
** The xShmLock method can transition between unlocked and SHARED or
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
@@ -1318,10 +1340,10 @@ struct sqlite3_vfs {
** must return [SQLITE_OK] on success and some other [error code] upon
** failure.
*/
-SQLITE_API int sqlite3_initialize(void);
-SQLITE_API int sqlite3_shutdown(void);
-SQLITE_API int sqlite3_os_init(void);
-SQLITE_API int sqlite3_os_end(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
+SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
/*
** CAPI3REF: Configuring The SQLite Library
@@ -1352,7 +1374,7 @@ SQLITE_API int sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API int sqlite3_config(int, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
@@ -1370,7 +1392,7 @@ SQLITE_API int sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
@@ -1504,31 +1526,33 @@ struct sqlite3_mem_methods {
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
**
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The argument specifies
+** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
+** a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The argument specifies
** alternative low-level memory allocation routines to be used in place of
** the memory allocation routines built into SQLite.)^ ^SQLite makes
** its own private copy of the content of the [sqlite3_mem_methods] structure
** before the [sqlite3_config()] call returns.</dd>
**
** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
+** <dd> ^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mem_methods] structure.
+** The [sqlite3_mem_methods]
** structure is filled with the currently defined memory allocation routines.)^
** This option can be used to overload the default memory allocation
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
-** <dd> ^This option takes single argument of type int, interpreted as a
-** boolean, which enables or disables the collection of memory allocation
-** statistics. ^(When memory allocation statistics are disabled, the
-** following SQLite interfaces become non-operational:
+** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
+** interpreted as a boolean, which enables or disables the collection of
+** memory allocation statistics. ^(When memory allocation statistics are
+** disabled, the following SQLite interfaces become non-operational:
** <ul>
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
-** <li> [sqlite3_status()]
+** <li> [sqlite3_status64()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
@@ -1536,53 +1560,67 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** scratch memory. There are three arguments: A pointer an 8-byte
+** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
+** that SQLite can use for scratch memory. ^(There are three arguments
+** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
** aligned memory buffer from which the scratch allocations will be
** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N). The sz
-** argument must be a multiple of 16.
+** and the maximum number of scratch allocations (N).)^
** The first argument must be a pointer to an 8-byte aligned buffer
** of at least sz*N bytes of memory.
-** ^SQLite will use no more than two scratch buffers per thread. So
-** N should be set to twice the expected maximum number of threads.
-** ^SQLite will never require a scratch buffer that is more than 6
-** times the database page size. ^If SQLite needs needs additional
+** ^SQLite will not use more than one scratch buffers per thread.
+** ^SQLite will never request a scratch buffer that is more than 6
+** times the database page size.
+** ^If SQLite needs needs additional
** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
+** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
+** ^When the application provides any amount of scratch memory using
+** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
+** [sqlite3_malloc|heap allocations].
+** This can help [Robson proof|prevent memory allocation failures] due to heap
+** fragmentation in low-memory embedded systems.
+** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implementation.
+** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
+** that SQLite can use for the database page cache with the default page
+** cache implementation.
** This configuration should not be used if an application-define page
-** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option.
-** There are three arguments to this option: A pointer to 8-byte aligned
+** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
+** configuration option.
+** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
+** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
-** (a power of two between 512 and 32768) plus a little extra for each
-** page header. ^The page header size is 20 to 40 bytes depending on
-** the host architecture. ^It is harmless, apart from the wasted memory,
-** to make sz a little too large. The first
-** argument should point to an allocation of at least sz*N bytes of memory.
+** (a power of two between 512 and 65536) plus some extra bytes for each
+** page header. ^The number of extra bytes needed by the page header
+** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
+** to [sqlite3_config()].
+** ^It is harmless, apart from the wasted memory,
+** for the sz parameter to be larger than necessary. The first
+** argument should pointer to an 8-byte aligned block of memory that
+** is at least sz*N bytes of memory, otherwise subsequent behavior is
+** undefined.
** ^SQLite will use the memory provided by the first argument to satisfy its
** memory needs for the first N pages that it adds to cache. ^If additional
** page cache memory is needed beyond what is provided by this option, then
-** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** The pointer in the first argument must
-** be aligned to an 8-byte boundary or subsequent behavior of SQLite
-** will be undefined.</dd>
+** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite will use
-** for all of its dynamic memory allocation needs beyond those provided
-** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
-** There are three arguments: An 8-byte aligned pointer to the memory,
+** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
+** that SQLite will use for all of its dynamic memory allocation needs
+** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
+** [SQLITE_CONFIG_PAGECACHE].
+** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
+** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
+** [SQLITE_ERROR] if invoked otherwise.
+** ^There are three arguments to SQLITE_CONFIG_HEAP:
+** An 8-byte aligned pointer to the memory,
** the number of bytes in the memory buffer, and the minimum allocation size.
** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts
** to using its default memory allocator (the system malloc() implementation),
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
-** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
-** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
+** memory pointer is not NULL then the alternative memory
** allocator is engaged to handle all of SQLites memory allocation needs.
** The first pointer (the memory pointer) must be aligned to an 8-byte
** boundary or subsequent behavior of SQLite will be undefined.
@@ -1590,11 +1628,11 @@ struct sqlite3_mem_methods {
** for the minimum allocation size are 2**5 through 2**8.</dd>
**
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The argument specifies
-** alternative low-level mutex routines to be used in place
-** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the
-** content of the [sqlite3_mutex_methods] structure before the call to
+** <dd> ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a
+** pointer to an instance of the [sqlite3_mutex_methods] structure.
+** The argument specifies alternative low-level mutex routines to be used
+** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of
+** the content of the [sqlite3_mutex_methods] structure before the call to
** [sqlite3_config()] returns. ^If SQLite is compiled with
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
** the entire mutexing subsystem is omitted from the build and hence calls to
@@ -1602,8 +1640,8 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The
+** <dd> ^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which
+** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The
** [sqlite3_mutex_methods]
** structure is filled with the currently defined mutex routines.)^
** This option can be used to overload the default mutex allocation
@@ -1615,25 +1653,25 @@ struct sqlite3_mem_methods {
** return [SQLITE_ERROR].</dd>
**
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
-** <dd> ^(This option takes two arguments that determine the default
-** memory allocation for the lookaside memory allocator on each
-** [database connection]. The first argument is the
+** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
+** the default size of lookaside memory on each [database connection].
+** The first argument is the
** size of each lookaside buffer slot and the second is the number of
-** slots allocated to each database connection.)^ ^(This option sets the
-** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
-** verb to [sqlite3_db_config()] can be used to change the lookaside
+** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
+** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
+** option to [sqlite3_db_config()] can be used to change the lookaside
** configuration on individual connections.)^ </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to
-** an [sqlite3_pcache_methods2] object. This object specifies the interface
-** to a custom page cache implementation.)^ ^SQLite makes a copy of the
-** object and uses it for page cache memory allocations.</dd>
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
+** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
+** the interface to a custom page cache implementation.)^
+** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
**
** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** [sqlite3_pcache_methods2] object. SQLite copies of the current
-** page cache implementation into that object.)^ </dd>
+** <dd> ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which
+** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of
+** the current page cache implementation into that object.)^ </dd>
**
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
@@ -1656,10 +1694,11 @@ struct sqlite3_mem_methods {
** function must be threadsafe. </dd>
**
** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
-** <dd>^(This option takes a single argument of type int. If non-zero, then
-** URI handling is globally enabled. If the parameter is zero, then URI handling
-** is globally disabled.)^ ^If URI handling is globally enabled, all filenames
-** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
+** <dd>^(The SQLITE_CONFIG_URI option takes a single argument of type int.
+** If non-zero, then URI handling is globally enabled. If the parameter is zero,
+** then URI handling is globally disabled.)^ ^If URI handling is globally
+** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()],
+** [sqlite3_open16()] or
** specified as part of [ATTACH] commands are interpreted as URIs, regardless
** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
** connection is opened. ^If it is globally disabled, filenames are
@@ -1669,9 +1708,10 @@ struct sqlite3_mem_methods {
** [SQLITE_USE_URI] symbol defined.)^
**
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
-** <dd>^This option takes a single integer argument which is interpreted as
-** a boolean in order to enable or disable the use of covering indices for
-** full table scans in the query optimizer. ^The default setting is determined
+** <dd>^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer
+** argument which is interpreted as a boolean in order to enable or disable
+** the use of covering indices for full table scans in the query optimizer.
+** ^The default setting is determined
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"
** if that compile-time option is omitted.
** The ability to disable the use of covering indices for full table scans
@@ -1711,18 +1751,37 @@ struct sqlite3_mem_methods {
** ^The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_size] command, or by using the
** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size
-** cannot be changed at run-time. Nor may the maximum allowed mmap size
-** exceed the compile-time maximum mmap size set by the
+** will be silently truncated if necessary so that it does not exceed the
+** compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
**
** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
-** <dd>^This option is only available if SQLite is compiled for Windows
-** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
-** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
+** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is
+** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro
+** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
** that specifies the maximum size of the created heap.
+**
+** [[SQLITE_CONFIG_PCACHE_HDRSZ]]
+** <dt>SQLITE_CONFIG_PCACHE_HDRSZ
+** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
+** is a pointer to an integer and writes into that integer the number of extra
+** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
+** The amount of extra space required can change depending on the compiler,
+** target platform, and SQLite version.
+**
+** [[SQLITE_CONFIG_PMASZ]]
+** <dt>SQLITE_CONFIG_PMASZ
+** <dd>^The SQLITE_CONFIG_PMASZ option takes a single parameter which
+** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded
+** sorter to that integer. The default minimum PMA Size is set by the
+** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched
+** to help with sort operations when multithreaded sorting
+** is enabled (using the [PRAGMA threads] command) and the amount of content
+** to be sorted exceeds the page size times the minimum of the
+** [PRAGMA cache_size] setting and this value.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1748,6 +1807,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
+#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
+#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1819,7 +1880,7 @@ struct sqlite3_mem_methods {
** [extended result codes] feature of SQLite. ^The extended result
** codes are disabled by default for historical compatibility.
*/
-SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
/*
** CAPI3REF: Last Insert Rowid
@@ -1870,52 +1931,50 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
** unpredictable and might not equal either the old or the new
** last insert [rowid].
*/
-SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
/*
** CAPI3REF: Count The Number Of Rows Modified
**
-** ^This function returns the number of database rows that were changed
-** or inserted or deleted by the most recently completed SQL statement
-** on the [database connection] specified by the first parameter.
-** ^(Only changes that are directly specified by the [INSERT], [UPDATE],
-** or [DELETE] statement are counted. Auxiliary changes caused by
-** triggers or [foreign key actions] are not counted.)^ Use the
-** [sqlite3_total_changes()] function to find the total number of changes
-** including changes caused by triggers and foreign key actions.
-**
-** ^Changes to a view that are simulated by an [INSTEAD OF trigger]
-** are not counted. Only real table changes are counted.
-**
-** ^(A "row change" is a change to a single row of a single table
-** caused by an INSERT, DELETE, or UPDATE statement. Rows that
-** are changed as side effects of [REPLACE] constraint resolution,
-** rollback, ABORT processing, [DROP TABLE], or by any other
-** mechanisms do not count as direct row changes.)^
-**
-** A "trigger context" is a scope of execution that begins and
-** ends with the script of a [CREATE TRIGGER | trigger].
-** Most SQL statements are
-** evaluated outside of any trigger. This is the "top level"
-** trigger context. If a trigger fires from the top level, a
-** new trigger context is entered for the duration of that one
-** trigger. Subtriggers create subcontexts for their duration.
-**
-** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
-** not create a new trigger context.
-**
-** ^This function returns the number of direct row changes in the
-** most recent INSERT, UPDATE, or DELETE statement within the same
-** trigger context.
-**
-** ^Thus, when called from the top level, this function returns the
-** number of changes in the most recent INSERT, UPDATE, or DELETE
-** that also occurred at the top level. ^(Within the body of a trigger,
-** the sqlite3_changes() interface can be called to find the number of
-** changes in the most recently completed INSERT, UPDATE, or DELETE
-** statement within the body of the same trigger.
-** However, the number returned does not include changes
-** caused by subtriggers since those have their own context.)^
+** ^This function returns the number of rows modified, inserted or
+** deleted by the most recently completed INSERT, UPDATE or DELETE
+** statement on the database connection specified by the only parameter.
+** ^Executing any other type of SQL statement does not modify the value
+** returned by this function.
+**
+** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
+** [foreign key actions] or [REPLACE] constraint resolution are not counted.
+**
+** Changes to a view that are intercepted by
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
+** DELETE statement run on a view is always zero. Only changes made to real
+** tables are counted.
+**
+** Things are more complicated if the sqlite3_changes() function is
+** executed while a trigger program is running. This may happen if the
+** program uses the [changes() SQL function], or if some other callback
+** function invokes sqlite3_changes() directly. Essentially:
+**
+** <ul>
+** <li> ^(Before entering a trigger program the value returned by
+** sqlite3_changes() function is saved. After the trigger program
+** has finished, the original value is restored.)^
+**
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
+** statement sets the value returned by sqlite3_changes()
+** upon completion as normal. Of course, this value will not include
+** any changes performed by sub-triggers, as the sqlite3_changes()
+** value will be saved and restored after each sub-trigger has run.)^
+** </ul>
+**
+** ^This means that if the changes() SQL function (or similar) is used
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
+** returns the value as set when the calling statement began executing.
+** ^If it is used by the second or subsequent such statement within a trigger
+** program, the value returned reflects the number of rows modified by the
+** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
** See also the [sqlite3_total_changes()] interface, the
** [count_changes pragma], and the [changes() SQL function].
@@ -1924,25 +1983,22 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
/*
** CAPI3REF: Total Number Of Rows Modified
**
-** ^This function returns the number of row changes caused by [INSERT],
-** [UPDATE] or [DELETE] statements since the [database connection] was opened.
-** ^(The count returned by sqlite3_total_changes() includes all changes
-** from all [CREATE TRIGGER | trigger] contexts and changes made by
-** [foreign key actions]. However,
-** the count does not include changes used to implement [REPLACE] constraints,
-** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
-** count does not include rows of views that fire an [INSTEAD OF trigger],
-** though if the INSTEAD OF trigger makes changes of its own, those changes
-** are counted.)^
-** ^The sqlite3_total_changes() function counts the changes as soon as
-** the statement that makes them is completed (when the statement handle
-** is passed to [sqlite3_reset()] or [sqlite3_finalize()]).
-**
+** ^This function returns the total number of rows inserted, modified or
+** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
+** since the database connection was opened, including those executed as
+** part of trigger programs. ^Executing any other type of SQL statement
+** does not affect the value returned by sqlite3_total_changes().
+**
+** ^Changes made as part of [foreign key actions] are included in the
+** count, but those made as part of REPLACE constraint resolution are
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
+** are not counted.
+**
** See also the [sqlite3_changes()] interface, the
** [count_changes pragma], and the [total_changes() SQL function].
**
@@ -1950,7 +2006,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
*/
-SQLITE_API int sqlite3_total_changes(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
/*
** CAPI3REF: Interrupt A Long-Running Query
@@ -1989,7 +2045,7 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
** If the database connection closes while [sqlite3_interrupt()]
** is running then bad things will likely happen.
*/
-SQLITE_API void sqlite3_interrupt(sqlite3*);
+SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2024,11 +2080,12 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
-SQLITE_API int sqlite3_complete(const char *sql);
-SQLITE_API int sqlite3_complete16(const void *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
+SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
+** KEYWORDS: {busy-handler callback} {busy handler}
**
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
** that might be invoked with argument P whenever
@@ -2045,7 +2102,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** ^The first argument to the busy handler is a copy of the void* pointer which
** is the third argument to sqlite3_busy_handler(). ^The second argument to
** the busy handler callback is the number of times that the busy handler has
-** been invoked for the same locking event. ^If the
+** been invoked previously for the same locking event. ^If the
** busy callback returns 0, then no additional attempts are made to
** access the database and [SQLITE_BUSY] is returned
** to the application.
@@ -2084,7 +2141,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
-SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
/*
** CAPI3REF: Set A Busy Timeout
@@ -2106,7 +2163,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
**
** See also: [PRAGMA busy_timeout]
*/
-SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
+SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
@@ -2180,7 +2237,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** reflected in subsequent calls to [sqlite3_errcode()] or
** [sqlite3_errmsg()].
*/
-SQLITE_API int sqlite3_get_table(
+SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
@@ -2188,13 +2245,17 @@ SQLITE_API int sqlite3_get_table(
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
-SQLITE_API void sqlite3_free_table(char **result);
+SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
/*
** CAPI3REF: Formatted String Printing Functions
**
** These routines are work-alikes of the "printf()" family of functions
** from the standard C library.
+** These routines understand most of the common K&R formatting options,
+** plus some additional non-standard formats, detailed below.
+** Note that some of the more obscure formatting options from recent
+** C-library standards are omitted from this implementation.
**
** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
** results into memory obtained from [sqlite3_malloc()].
@@ -2227,7 +2288,7 @@ SQLITE_API void sqlite3_free_table(char **result);
** These routines all implement some additional formatting
** options that are useful for constructing SQL statements.
** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", and "%z" options.
+** is are "%q", "%Q", "%w" and "%z" options.
**
** ^(The %q option works like %s in that it substitutes a nul-terminated
** string from the argument list. But %q also doubles every '\'' character.
@@ -2280,14 +2341,20 @@ SQLITE_API void sqlite3_free_table(char **result);
** The code above will render a correct SQL statement in the zSQL
** variable even if the zText variable is a NULL pointer.
**
+** ^(The "%w" formatting option is like "%q" except that it expects to
+** be contained within double-quotes instead of single quotes, and it
+** escapes the double-quote character instead of the single-quote
+** character.)^ The "%w" formatting option is intended for safely inserting
+** table and column names into a constructed SQL statement.
+**
** ^(The "%z" formatting option works like "%s" but with the
** addition that after the string has been read and copied into
** the result, [sqlite3_free()] is called on the input string.)^
*/
-SQLITE_API char *sqlite3_mprintf(const char*,...);
-SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
-SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
-SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
+SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
/*
** CAPI3REF: Memory Allocation Subsystem
@@ -2377,12 +2444,12 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** a block of memory after it has been released using
** [sqlite3_free()] or [sqlite3_realloc()].
*/
-SQLITE_API void *sqlite3_malloc(int);
-SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
-SQLITE_API void *sqlite3_realloc(void*, int);
-SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
-SQLITE_API void sqlite3_free(void*);
-SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
+SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
+SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
+SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
/*
** CAPI3REF: Memory Allocator Statistics
@@ -2407,8 +2474,8 @@ SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
** by [sqlite3_memory_highwater(1)] is the high-water mark
** prior to the reset.
*/
-SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
/*
** CAPI3REF: Pseudo-Random Number Generator
@@ -2420,17 +2487,18 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
-** ^If N is less than one, then P can be a NULL pointer.
+** ^The P parameter can be a NULL pointer.
**
** ^If this routine has not been previously called or if the previous
-** call had N less than one, then the PRNG is seeded using randomness
-** obtained from the xRandomness method of the default [sqlite3_vfs] object.
-** ^If the previous call to this routine had an N of 1 or more then
-** the pseudo-randomness is generated
+** call had N less than one or a NULL pointer for P, then the PRNG is
+** seeded using randomness obtained from the xRandomness method of
+** the default [sqlite3_vfs] object.
+** ^If the previous call to this routine had an N of 1 or more and a
+** non-NULL P then the pseudo-randomness is generated
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/
-SQLITE_API void sqlite3_randomness(int N, void *P);
+SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
@@ -2512,7 +2580,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** as stated in the previous paragraph, sqlite3_step() invokes
** sqlite3_prepare_v2() to reprepare a statement after a schema change.
*/
-SQLITE_API int sqlite3_set_authorizer(
+SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
sqlite3*,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pUserData
@@ -2616,8 +2684,8 @@ SQLITE_API int sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
-SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
+SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
@@ -2651,7 +2719,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
** database connections for the meaning of "modify" in this paragraph.
**
*/
-SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
+SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
** CAPI3REF: Opening A New Database Connection
@@ -2879,15 +2947,15 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** See also: [sqlite3_temp_directory]
*/
-SQLITE_API int sqlite3_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open16(
+SQLITE_API int SQLITE_STDCALL sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int sqlite3_open_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -2933,19 +3001,21 @@ SQLITE_API int sqlite3_open_v2(
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
** CAPI3REF: Error Codes And Messages
**
-** ^The sqlite3_errcode() interface returns the numeric [result code] or
-** [extended result code] for the most recent failed sqlite3_* API call
-** associated with a [database connection]. If a prior API call failed
-** but the most recent API call succeeded, the return value from
-** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
+** ^If the most recent sqlite3_* API call associated with
+** [database connection] D failed, then the sqlite3_errcode(D) interface
+** returns the numeric [result code] or [extended result code] for that
+** API call.
+** If the most recent API call was successful,
+** then the return value from sqlite3_errcode() is undefined.
+** ^The sqlite3_extended_errcode()
** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
@@ -2976,11 +3046,11 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
** was invoked incorrectly by the application. In that case, the
** error code and message may or may not be set.
*/
-SQLITE_API int sqlite3_errcode(sqlite3 *db);
-SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
-SQLITE_API const char *sqlite3_errmsg(sqlite3*);
-SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
-SQLITE_API const char *sqlite3_errstr(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
+SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
/*
** CAPI3REF: SQL Statement Object
@@ -3047,7 +3117,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
**
** New run-time limit categories may be added in future releases.
*/
-SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
+SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
/*
** CAPI3REF: Run-Time Limit Categories
@@ -3134,16 +3204,14 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
** use UTF-16.
**
-** ^If the nByte argument is less than zero, then zSql is read up to the
-** first zero terminator. ^If nByte is non-negative, then it is the maximum
-** number of bytes read from zSql. ^When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or
-** the nByte-th byte, whichever comes first. If the caller knows
-** that the supplied string is nul-terminated, then there is a small
-** performance advantage to be gained by passing an nByte parameter that
-** is equal to the number of bytes in the input string <i>including</i>
-** the nul-terminator bytes as this saves SQLite from having to
-** make a copy of the input string.
+** ^If the nByte argument is negative, then zSql is read up to the
+** first zero terminator. ^If nByte is positive, then it is the
+** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** statement is generated.
+** If the caller knows that the supplied string is nul-terminated, then
+** there is a small performance advantage to passing an nByte parameter that
+** is the number of bytes in the input string <i>including</i>
+** the nul-terminator.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -3199,28 +3267,28 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
** </ol>
*/
-SQLITE_API int sqlite3_prepare(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int sqlite3_prepare16_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
@@ -3235,7 +3303,7 @@ SQLITE_API int sqlite3_prepare16_v2(
** SQL text used to create a [prepared statement] if that statement was
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
*/
-SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
@@ -3266,7 +3334,7 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
*/
-SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
@@ -3285,7 +3353,7 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
-SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
/*
** CAPI3REF: Dynamically Typed Value Object
@@ -3446,19 +3514,19 @@ typedef struct sqlite3_context sqlite3_context;
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
void(*)(void*));
-SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
-SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
-SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
-SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
-SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
/*
** CAPI3REF: Number Of SQL Parameters
@@ -3478,7 +3546,7 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
** [sqlite3_bind_parameter_name()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
** CAPI3REF: Name Of A Host Parameter
@@ -3505,7 +3573,7 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
/*
** CAPI3REF: Index Of A Parameter With A Given Name
@@ -3521,7 +3589,7 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
+SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
** CAPI3REF: Reset All Bindings On A Prepared Statement
@@ -3530,7 +3598,7 @@ SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
** ^Use this routine to reset all host parameters to NULL.
*/
-SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
/*
** CAPI3REF: Number Of Columns In A Result Set
@@ -3541,7 +3609,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
**
** See also: [sqlite3_data_count()]
*/
-SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Column Names In A Result Set
@@ -3569,8 +3637,8 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
** then the name of the column is unspecified and may change from
** one release of SQLite to the next.
*/
-SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
-SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
/*
** CAPI3REF: Source Of Data In A Query Result
@@ -3617,12 +3685,12 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
-SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
/*
** CAPI3REF: Declared Datatype Of A Query Result
@@ -3653,8 +3721,8 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
** is associated with individual values, not with the containers
** used to hold those values.
*/
-SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
/*
** CAPI3REF: Evaluate An SQL Statement
@@ -3733,7 +3801,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** then the more specific [error codes] are returned directly
** by sqlite3_step(). The use of the "v2" interface is recommended.
*/
-SQLITE_API int sqlite3_step(sqlite3_stmt*);
+SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
/*
** CAPI3REF: Number of columns in a result set
@@ -3753,7 +3821,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
**
** See also: [sqlite3_column_count()]
*/
-SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Fundamental Datatypes
@@ -3949,16 +4017,16 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** pointer. Subsequent calls to [sqlite3_errcode()] will return
** [SQLITE_NOMEM].)^
*/
-SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
+SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
@@ -3985,7 +4053,7 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
*/
-SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Reset A Prepared Statement Object
@@ -4011,7 +4079,7 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
-SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
+SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
@@ -4110,7 +4178,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** close the database connection nor finalize or reset the prepared
** statement in which the function is running.
*/
-SQLITE_API int sqlite3_create_function(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4120,7 +4188,7 @@ SQLITE_API int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -4130,7 +4198,7 @@ SQLITE_API int sqlite3_create_function16(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int sqlite3_create_function_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4148,9 +4216,9 @@ SQLITE_API int sqlite3_create_function_v2(
** These constant define integer codes that represent the various
** text encodings supported by SQLite.
*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
+#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */
+#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */
+#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */
#define SQLITE_UTF16 4 /* Use native byte order */
#define SQLITE_ANY 5 /* Deprecated */
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
@@ -4172,16 +4240,16 @@ SQLITE_API int sqlite3_create_function_v2(
** These functions are [deprecated]. In order to maintain
** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
-** the use of these functions. To help encourage people to avoid
-** using these functions, we are not going to tell you what they do.
+** the use of these functions. To encourage programmers to avoid
+** these functions, we will not explain what they do.
*/
#ifndef SQLITE_OMIT_DEPRECATED
-SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
-SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
+SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
#endif
@@ -4230,18 +4298,18 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
*/
-SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
-SQLITE_API double sqlite3_value_double(sqlite3_value*);
-SQLITE_API int sqlite3_value_int(sqlite3_value*);
-SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
-SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int sqlite3_value_type(sqlite3_value*);
-SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
+SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
+SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
+SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
@@ -4285,7 +4353,7 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** This routine must be called from the same thread in which
** the aggregate SQL function is running.
*/
-SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
+SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
** CAPI3REF: User Data For Functions
@@ -4299,7 +4367,7 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
** This routine must be called from the same thread in which
** the application-defined function is running.
*/
-SQLITE_API void *sqlite3_user_data(sqlite3_context*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
/*
** CAPI3REF: Database Connection For Functions
@@ -4310,7 +4378,7 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context*);
** and [sqlite3_create_function16()] routines that originally
** registered the application defined function.
*/
-SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
/*
** CAPI3REF: Function Auxiliary Data
@@ -4362,8 +4430,8 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** These routines must be called from the same thread in which
** the SQL function is running.
*/
-SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
-SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
+SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
@@ -4498,25 +4566,26 @@ typedef void (*sqlite3_destructor_type)(void*);
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*));
-SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
-SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
-SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
-SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-SQLITE_API void sqlite3_result_null(sqlite3_context*);
-SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
+ sqlite3_uint64,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
/*
** CAPI3REF: Define New Collating Sequences
@@ -4597,14 +4666,14 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
-SQLITE_API int sqlite3_create_collation(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
-SQLITE_API int sqlite3_create_collation_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
int eTextRep,
@@ -4612,7 +4681,7 @@ SQLITE_API int sqlite3_create_collation_v2(
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
-SQLITE_API int sqlite3_create_collation16(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
@@ -4646,12 +4715,12 @@ SQLITE_API int sqlite3_create_collation16(
** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
** [sqlite3_create_collation_v2()].
*/
-SQLITE_API int sqlite3_collation_needed(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
-SQLITE_API int sqlite3_collation_needed16(
+SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
@@ -4665,11 +4734,11 @@ SQLITE_API int sqlite3_collation_needed16(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_key(
+SQLITE_API int SQLITE_STDCALL sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
-SQLITE_API int sqlite3_key_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
@@ -4683,11 +4752,11 @@ SQLITE_API int sqlite3_key_v2(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int sqlite3_rekey(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
-SQLITE_API int sqlite3_rekey_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
@@ -4697,7 +4766,7 @@ SQLITE_API int sqlite3_rekey_v2(
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
-SQLITE_API void sqlite3_activate_see(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4707,7 +4776,7 @@ SQLITE_API void sqlite3_activate_see(
** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
-SQLITE_API void sqlite3_activate_cerod(
+SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4729,7 +4798,7 @@ SQLITE_API void sqlite3_activate_cerod(
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
*/
-SQLITE_API int sqlite3_sleep(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
/*
** CAPI3REF: Name Of The Folder Holding Temporary Files
@@ -4847,7 +4916,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
** connection while this routine is running, then the return value
** is undefined.
*/
-SQLITE_API int sqlite3_get_autocommit(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
/*
** CAPI3REF: Find The Database Handle Of A Prepared Statement
@@ -4859,7 +4928,7 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
-SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Filename For A Database Connection
@@ -4875,7 +4944,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -4884,7 +4953,7 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
** the name of a database on connection D.
*/
-SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Find the next prepared statement
@@ -4899,7 +4968,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
** [sqlite3_next_stmt(D,S)] must refer to an open database
** connection and in particular must not be a NULL pointer.
*/
-SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
+SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
/*
** CAPI3REF: Commit And Rollback Notification Callbacks
@@ -4947,8 +5016,8 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
**
** See also the [sqlite3_update_hook()] interface.
*/
-SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
/*
** CAPI3REF: Data Change Notification Callbacks
@@ -4998,7 +5067,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
** interfaces.
*/
-SQLITE_API void *sqlite3_update_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
@@ -5028,12 +5097,17 @@ SQLITE_API void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
+** and will always return SQLITE_MISUSE. On those systems,
+** shared cache mode should be enabled per-database connection via
+** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
+**
** This interface is threadsafe on processors where writing a
** 32-bit integer is atomic.
**
** See Also: [SQLite Shared-Cache Mode]
*/
-SQLITE_API int sqlite3_enable_shared_cache(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
/*
** CAPI3REF: Attempt To Free Heap Memory
@@ -5049,7 +5123,7 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
**
** See also: [sqlite3_db_release_memory()]
*/
-SQLITE_API int sqlite3_release_memory(int);
+SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
/*
** CAPI3REF: Free Memory Used By A Database Connection
@@ -5062,7 +5136,7 @@ SQLITE_API int sqlite3_release_memory(int);
**
** See also: [sqlite3_release_memory()]
*/
-SQLITE_API int sqlite3_db_release_memory(sqlite3*);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
@@ -5114,7 +5188,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** The circumstances under which SQLite will enforce the soft heap limit may
** changes in future releases of SQLite.
*/
-SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5125,26 +5199,33 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
** only. All new applications should use the
** [sqlite3_soft_heap_limit64()] interface rather than this one.
*/
-SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
**
-** ^This routine returns metadata about a specific column of a specific
-** database table accessible using the [database connection] handle
-** passed as the first function argument.
+** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
+** information about column C of table T in database D
+** on [database connection] X.)^ ^The sqlite3_table_column_metadata()
+** interface returns SQLITE_OK and fills in the non-NULL pointers in
+** the final five arguments with appropriate values if the specified
+** column exists. ^The sqlite3_table_column_metadata() interface returns
+** SQLITE_ERROR and if the specified column does not exist.
+** ^If the column-name parameter to sqlite3_table_column_metadata() is a
+** NULL pointer, then this routine simply checks for the existance of the
+** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
+** does not.
**
** ^The column is identified by the second, third and fourth parameters to
-** this function. ^The second parameter is either the name of the database
+** this function. ^(The second parameter is either the name of the database
** (i.e. "main", "temp", or an attached database) containing the specified
-** table or NULL. ^If it is NULL, then all attached databases are searched
+** table or NULL.)^ ^If it is NULL, then all attached databases are searched
** for the table using the same algorithm used by the database engine to
** resolve unqualified table references.
**
** ^The third and fourth parameters to this function are the table and column
-** name of the desired column, respectively. Neither of these parameters
-** may be NULL.
+** name of the desired column, respectively.
**
** ^Metadata is returned by writing to the memory locations passed as the 5th
** and subsequent parameters to this function. ^Any of these arguments may be
@@ -5163,16 +5244,17 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** </blockquote>)^
**
** ^The memory pointed to by the character pointers returned for the
-** declaration type and collation sequence is valid only until the next
+** declaration type and collation sequence is valid until the next
** call to any SQLite API function.
**
** ^If the specified table is actually a view, an [error code] is returned.
**
-** ^If the specified column is "rowid", "oid" or "_rowid_" and an
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
+** is not a [WITHOUT ROWID] table and an
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
** parameters are set for the explicitly declared column. ^(If there is no
-** explicitly declared [INTEGER PRIMARY KEY] column, then the output
-** parameters are set as follows:
+** [INTEGER PRIMARY KEY] column, then the outputs
+** for the [rowid] are set as follows:
**
** <pre>
** data type: "INTEGER"
@@ -5182,15 +5264,11 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** auto increment: 0
** </pre>)^
**
-** ^(This function may load one or more schemas from database files. If an
-** error occurs during this process, or if the requested table or column
-** cannot be found, an [error code] is returned and an error message left
-** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^
-**
-** ^This API is only available if the library was compiled with the
-** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined.
+** ^This function causes all database schemas to be read from disk and
+** parsed, if that has not already been done, and returns an error if
+** any errors are encountered while loading the schema.
*/
-SQLITE_API int sqlite3_table_column_metadata(
+SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -5236,7 +5314,7 @@ SQLITE_API int sqlite3_table_column_metadata(
**
** See also the [load_extension() SQL function].
*/
-SQLITE_API int sqlite3_load_extension(
+SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Derived from zFile if 0 */
@@ -5256,7 +5334,7 @@ SQLITE_API int sqlite3_load_extension(
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
*/
-SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
+SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
** CAPI3REF: Automatically Load Statically Linked Extensions
@@ -5294,7 +5372,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** See also: [sqlite3_reset_auto_extension()]
** and [sqlite3_cancel_auto_extension()]
*/
-SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Cancel Automatic Extension Loading
@@ -5306,7 +5384,7 @@ SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
-SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
@@ -5314,7 +5392,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
** ^This interface disables all automatic extensions previously
** registered using [sqlite3_auto_extension()].
*/
-SQLITE_API void sqlite3_reset_auto_extension(void);
+SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
/*
** The interface to the virtual-table mechanism is currently considered
@@ -5517,13 +5595,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API int sqlite3_create_module(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API int sqlite3_create_module_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -5551,7 +5629,7 @@ SQLITE_API int sqlite3_create_module_v2(
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* NO LONGER USED */
+ int nRef; /* Number of open cursors */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -5586,7 +5664,7 @@ struct sqlite3_vtab_cursor {
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
@@ -5604,7 +5682,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -5641,26 +5719,42 @@ typedef struct sqlite3_blob sqlite3_blob;
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre>)^
**
+** ^(Parameter zDb is not the filename that contains the database, but
+** rather the symbolic name of the database. For attached databases, this is
+** the name that appears after the AS keyword in the [ATTACH] statement.
+** For the main database file, the database name is "main". For TEMP
+** tables, the database name is "temp".)^
+**
** ^If the flags parameter is non-zero, then the BLOB is opened for read
-** and write access. ^If it is zero, the BLOB is opened for read access.
-** ^It is not possible to open a column that is part of an index or primary
-** key for writing. ^If [foreign key constraints] are enabled, it is
-** not possible to open a column that is part of a [child key] for writing.
-**
-** ^Note that the database name is not the filename that contains
-** the database but rather the symbolic name of the database that
-** appears after the AS keyword when the database is connected using [ATTACH].
-** ^For the main database file, the database name is "main".
-** ^For TEMP tables, the database name is "temp".
-**
-** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
-** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
-** to be a null pointer.)^
-** ^This function sets the [database connection] error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
-** functions. ^Note that the *ppBlob variable is always initialized in a
-** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
-** regardless of the success or failure of this routine.
+** and write access. ^If the flags parameter is zero, the BLOB is opened for
+** read-only access.
+**
+** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
+** in *ppBlob. Otherwise an [error code] is returned and, unless the error
+** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
+** on *ppBlob after this function it returns.
+**
+** This function fails with SQLITE_ERROR if any of the following are true:
+** <ul>
+** <li> ^(Database zDb does not exist)^,
+** <li> ^(Table zTable does not exist within database zDb)^,
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
+** <li> ^(Column zColumn does not exist)^,
+** <li> ^(Row iRow is not present in the table)^,
+** <li> ^(The specified column of row iRow contains a value that is not
+** a TEXT or BLOB value)^,
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
+** constraint and the blob is being opened for read/write access)^,
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
+** column zColumn is part of a [child key] definition and the blob is
+** being opened for read/write access)^.
+** </ul>
+**
+** ^Unless it returns SQLITE_MISUSE, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+**
**
** ^(If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
@@ -5678,18 +5772,14 @@ typedef struct sqlite3_blob sqlite3_blob;
** interface. Use the [UPDATE] SQL command to change the size of a
** blob.
**
-** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID]
-** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables.
-**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
-** and the built-in [zeroblob] SQL function can be used, if desired,
-** to create an empty, zero-filled blob in which to read or write using
-** this interface.
+** and the built-in [zeroblob] SQL function may be used to create a
+** zero-filled blob to read or write using the incremental-blob interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
*/
-SQLITE_API int sqlite3_blob_open(
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3*,
const char *zDb,
const char *zTable,
@@ -5721,31 +5811,29 @@ SQLITE_API int sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
**
-** ^Closes an open [BLOB handle].
+** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
+** unconditionally. Even if this routine returns an error code, the
+** handle is still closed.)^
**
-** ^Closing a BLOB shall cause the current transaction to commit
-** if there are no other BLOBs, no pending prepared statements, and the
-** database connection is in [autocommit mode].
-** ^If any writes were made to the BLOB, they might be held in cache
-** until the close operation if they will fit.
+** ^If the blob handle being closed was opened for read-write access, and if
+** the database is in auto-commit mode and there are no other open read-write
+** blob handles or active write statements, the current transaction is
+** committed. ^If an error occurs while committing the transaction, an error
+** code is returned and the transaction rolled back.
**
-** ^(Closing the BLOB often forces the changes
-** out to disk and so if any I/O errors occur, they will likely occur
-** at the time when the BLOB is closed. Any errors that occur during
-** closing are reported as a non-zero return value.)^
-**
-** ^(The BLOB is closed unconditionally. Even if this routine returns
-** an error code, the BLOB is still closed.)^
-**
-** ^Calling this routine with a null pointer (such as would be returned
-** by a failed call to [sqlite3_blob_open()]) is a harmless no-op.
+** Calling this function with an argument that is not a NULL pointer or an
+** open blob handle results in undefined behaviour. ^Calling this routine
+** with a null pointer (such as would be returned by a failed call to
+** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
+** is passed a valid open blob handle, the values returned by the
+** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
-SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB
@@ -5760,7 +5848,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
*/
-SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
/*
** CAPI3REF: Read Data From A BLOB Incrementally
@@ -5788,26 +5876,32 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
**
** See also: [sqlite3_blob_write()].
*/
-SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
/*
** CAPI3REF: Write Data Into A BLOB Incrementally
**
-** ^This function is used to write data into an open [BLOB handle] from a
-** caller-supplied buffer. ^N bytes of data are copied from the buffer Z
-** into the open BLOB, starting at offset iOffset.
+** ^(This function is used to write data into an open [BLOB handle] from a
+** caller-supplied buffer. N bytes of data are copied from the buffer Z
+** into the open BLOB, starting at offset iOffset.)^
+**
+** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
+** Otherwise, an [error code] or an [extended error code] is returned.)^
+** ^Unless SQLITE_MISUSE is returned, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
** ^If the [BLOB handle] passed as the first argument was not opened for
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
** this function returns [SQLITE_READONLY].
**
-** ^This function may only modify the contents of the BLOB; it is
+** This function may only modify the contents of the BLOB; it is
** not possible to increase the size of a BLOB using this API.
** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is written. ^If N is
-** less than zero [SQLITE_ERROR] is returned and no data is written.
-** The size of the BLOB (and hence the maximum value of N+iOffset)
-** can be determined using the [sqlite3_blob_bytes()] interface.
+** [SQLITE_ERROR] is returned and no data is written. The size of the
+** BLOB (and hence the maximum value of N+iOffset) can be determined
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
+** than zero [SQLITE_ERROR] is returned and no data is written.
**
** ^An attempt to write to an expired [BLOB handle] fails with an
** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
@@ -5816,9 +5910,6 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** have been overwritten by the statement that expired the BLOB handle
** or by other independent statements.
**
-** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
-** Otherwise, an [error code] or an [extended error code] is returned.)^
-**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
@@ -5826,7 +5917,7 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
**
** See also: [sqlite3_blob_read()].
*/
-SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
+SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
/*
** CAPI3REF: Virtual File System Objects
@@ -5857,9 +5948,9 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOff
** ^(If the default VFS is unregistered, another VFS is chosen as
** the default. The choice for the new VFS is arbitrary.)^
*/
-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
-SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
+SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
+SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
/*
** CAPI3REF: Mutexes
@@ -5871,34 +5962,34 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** The SQLite source code contains multiple implementations
** of these mutex routines. An appropriate implementation
-** is selected automatically at compile-time. ^(The following
+** is selected automatically at compile-time. The following
** implementations are available in the SQLite core:
**
** <ul>
** <li> SQLITE_MUTEX_PTHREADS
** <li> SQLITE_MUTEX_W32
** <li> SQLITE_MUTEX_NOOP
-** </ul>)^
+** </ul>
**
-** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
+** The SQLITE_MUTEX_NOOP implementation is a set of routines
** that does no real locking and is appropriate for use in
-** a single-threaded application. ^The SQLITE_MUTEX_PTHREADS and
+** a single-threaded application. The SQLITE_MUTEX_PTHREADS and
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
** and Windows.
**
-** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
+** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
** implementation is included with the library. In this case the
** application must supply a custom mutex implementation using the
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
** before calling sqlite3_initialize() or any other public sqlite3_
-** function that calls sqlite3_initialize().)^
+** function that calls sqlite3_initialize().
**
** ^The sqlite3_mutex_alloc() routine allocates a new
-** mutex and returns a pointer to it. ^If it returns NULL
-** that means that a mutex could not be allocated. ^SQLite
-** will unwind its stack and return an error. ^(The argument
-** to sqlite3_mutex_alloc() is one of these integer constants:
+** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
+** routine returns NULL if it is unable to allocate the requested
+** mutex. The argument to sqlite3_mutex_alloc() must one of these
+** integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST
@@ -5911,7 +6002,8 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
-** </ul>)^
+** <li> SQLITE_MUTEX_STATIC_APP3
+** </ul>
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
** cause sqlite3_mutex_alloc() to create
@@ -5919,14 +6011,14 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
-** not want to. ^SQLite will only request a recursive mutex in
-** cases where it really needs one. ^If a faster non-recursive mutex
+** not want to. SQLite will only request a recursive mutex in
+** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other
** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
-** a pointer to a static preexisting mutex. ^Six static mutexes are
+** a pointer to a static preexisting mutex. ^Nine static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
@@ -5935,16 +6027,13 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. ^But for the static
+** returns a different mutex on every call. ^For the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
**
** ^The sqlite3_mutex_free() routine deallocates a previously
-** allocated dynamic mutex. ^SQLite is careful to deallocate every
-** dynamic mutex that it allocates. The dynamic mutexes must not be in
-** use when they are deallocated. Attempting to deallocate a static
-** mutex results in undefined behavior. ^SQLite never deallocates
-** a static mutex.
+** allocated dynamic mutex. Attempting to deallocate a static
+** mutex results in undefined behavior.
**
** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. ^If another thread is already within the mutex,
@@ -5952,23 +6041,21 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK]
** upon successful entry. ^(Mutexes created using
** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
-** In such cases the,
+** In such cases, the
** mutex must be exited an equal number of times before another thread
-** can enter.)^ ^(If the same thread tries to enter any other
-** kind of mutex more than once, the behavior is undefined.
-** SQLite will never exhibit
-** such behavior in its own use of mutexes.)^
+** can enter.)^ If the same thread tries to enter any mutex other
+** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined.
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^
+** will always return SQLITE_BUSY. The SQLite core only ever uses
+** sqlite3_mutex_try() as an optimization so this is acceptable
+** behavior.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
-** previously entered by the same thread. ^(The behavior
+** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
-** calling thread or is not currently allocated. SQLite will
-** never do either.)^
+** calling thread or is not currently allocated.
**
** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
** sqlite3_mutex_leave() is a NULL pointer, then all three routines
@@ -5976,11 +6063,11 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
+SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
@@ -5989,9 +6076,9 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** used to allocate and use mutexes.
**
** Usually, the default mutex implementations provided by SQLite are
-** sufficient, however the user has the option of substituting a custom
+** sufficient, however the application has the option of substituting a custom
** implementation for specialized deployments or systems for which SQLite
-** does not provide a suitable implementation. In this case, the user
+** does not provide a suitable implementation. In this case, the application
** creates and populates an instance of this structure to pass
** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option.
** Additionally, an instance of this structure can be used as an
@@ -6032,13 +6119,13 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
**
-** The xMutexInit() method must be threadsafe. ^It must be harmless to
+** The xMutexInit() method must be threadsafe. It must be harmless to
** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd(). Second and subsequent calls to
** xMutexInit() must be no-ops.
**
-** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
-** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory
+** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
+** and its associates). Similarly, xMutexAlloc() must not use SQLite memory
** allocation for a static mutex. ^However xMutexAlloc() may use SQLite
** memory allocation for a fast or recursive mutex.
**
@@ -6064,34 +6151,34 @@ struct sqlite3_mutex_methods {
** CAPI3REF: Mutex Verification Routines
**
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
-** are intended for use inside assert() statements. ^The SQLite core
+** are intended for use inside assert() statements. The SQLite core
** never uses these routines except inside an assert() and applications
-** are advised to follow the lead of the core. ^The SQLite core only
+** are advised to follow the lead of the core. The SQLite core only
** provides implementations for these routines when it is compiled
-** with the SQLITE_DEBUG flag. ^External mutex implementations
+** with the SQLITE_DEBUG flag. External mutex implementations
** are only required to provide these routines if SQLITE_DEBUG is
** defined and if NDEBUG is not defined.
**
-** ^These routines should return true if the mutex in their argument
+** These routines should return true if the mutex in their argument
** is held or not held, respectively, by the calling thread.
**
-** ^The implementation is not required to provide versions of these
+** The implementation is not required to provide versions of these
** routines that actually work. If the implementation does not provide working
** versions of these routines, it should at least provide stubs that always
** return true so that one does not get spurious assertion failures.
**
-** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
+** If the argument to sqlite3_mutex_held() is a NULL pointer then
** the routine should return 1. This seems counter-intuitive since
** clearly the mutex cannot be held if it does not exist. But
** the reason the mutex does not exist is because the build is not
** using mutexes. And we do not want the assert() containing the
** call to sqlite3_mutex_held() to fail, so a non-zero return is
-** the appropriate thing to do. ^The sqlite3_mutex_notheld()
+** the appropriate thing to do. The sqlite3_mutex_notheld()
** interface should also return 1 when given a NULL pointer.
*/
#ifndef NDEBUG
-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
+SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#endif
/*
@@ -6127,7 +6214,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
** ^If the [threading mode] is Single-thread or Multi-thread then this
** routine returns a NULL pointer.
*/
-SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
+SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
@@ -6161,7 +6248,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
**
** See also: [SQLITE_FCNTL_LOCKSTATE]
*/
-SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
+SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
/*
** CAPI3REF: Testing Interface
@@ -6180,7 +6267,7 @@ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*
** Unlike most of the SQLite API, this function is not guaranteed to
** operate consistently from one release to the next.
*/
-SQLITE_API int sqlite3_test_control(int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
/*
** CAPI3REF: Testing Interface Operation Codes
@@ -6214,12 +6301,13 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24
-#define SQLITE_TESTCTRL_LAST 24
+#define SQLITE_TESTCTRL_IMPOSTER 25
+#define SQLITE_TESTCTRL_LAST 25
/*
** CAPI3REF: SQLite Runtime Status
**
-** ^This interface is used to retrieve runtime status information
+** ^These interfaces are used to retrieve runtime status information
** about the performance of SQLite, and optionally to reset various
** highwater marks. ^The first argument is an integer code for
** the specific parameter to measure. ^(Recognized integer codes
@@ -6233,19 +6321,22 @@ SQLITE_API int sqlite3_test_control(int op, ...);
** ^(Other parameters record only the highwater mark and not the current
** value. For these latter parameters nothing is written into *pCurrent.)^
**
-** ^The sqlite3_status() routine returns SQLITE_OK on success and a
-** non-zero [error code] on failure.
+** ^The sqlite3_status() and sqlite3_status64() routines return
+** SQLITE_OK on success and a non-zero [error code] on failure.
**
-** This routine is threadsafe but is not atomic. This routine can be
-** called while other threads are running the same or different SQLite
-** interfaces. However the values returned in *pCurrent and
-** *pHighwater reflect the status of SQLite at different points in time
-** and it is possible that another thread might change the parameter
-** in between the times when *pCurrent and *pHighwater are written.
+** If either the current value or the highwater mark is too large to
+** be represented by a 32-bit integer, then the values returned by
+** sqlite3_status() are undefined.
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+);
/*
@@ -6363,7 +6454,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
@@ -6492,7 +6583,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
@@ -6819,6 +6910,10 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
+** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
+** there is already a read or read-write transaction open on the
+** destination database.
+**
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
** returned and an error code and error message are stored in the
** destination [database connection] D.
@@ -6911,20 +7006,20 @@ typedef struct sqlite3_backup sqlite3_backup;
** is not a permanent error and does not affect the return value of
** sqlite3_backup_finish().
**
-** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]]
** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
**
-** ^Each call to sqlite3_backup_step() sets two values inside
-** the [sqlite3_backup] object: the number of pages still to be backed
-** up and the total number of pages in the source database file.
-** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
-** retrieve these two values, respectively.
-**
-** ^The values returned by these functions are only updated by
-** sqlite3_backup_step(). ^If the source database is modified during a backup
-** operation, then the values are not updated to account for any extra
-** pages that need to be updated or the size of the source database file
-** changing.
+** ^The sqlite3_backup_remaining() routine returns the number of pages still
+** to be backed up at the conclusion of the most recent sqlite3_backup_step().
+** ^The sqlite3_backup_pagecount() routine returns the total number of pages
+** in the source database at the conclusion of the most recent
+** sqlite3_backup_step().
+** ^(The values returned by these functions are only updated by
+** sqlite3_backup_step(). If the source database is modified in a way that
+** changes the size of the source database or the number of pages remaining,
+** those changes are not reflected in the output of sqlite3_backup_pagecount()
+** and sqlite3_backup_remaining() until after the next
+** sqlite3_backup_step().)^
**
** <b>Concurrent Usage of Database Handles</b>
**
@@ -6957,16 +7052,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
*/
-SQLITE_API sqlite3_backup *sqlite3_backup_init(
+SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
const char *zDestName, /* Destination database name */
sqlite3 *pSource, /* Source database handle */
const char *zSourceName /* Source database name */
);
-SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
-SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
+SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
@@ -7082,7 +7177,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
-SQLITE_API int sqlite3_unlock_notify(
+SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
sqlite3 *pBlocked, /* Waiting connection */
void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
void *pNotifyArg /* Argument to pass to xNotify */
@@ -7097,8 +7192,8 @@ SQLITE_API int sqlite3_unlock_notify(
** strings in a case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int sqlite3_stricmp(const char *, const char *);
-SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
+SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
+SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
@@ -7113,7 +7208,7 @@ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
*/
-SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
+SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: Error Logging Interface
@@ -7136,18 +7231,16 @@ SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
** a few hundred characters, it will be truncated to the length of the
** buffer.
*/
-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
+SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
**
** ^The [sqlite3_wal_hook()] function is used to register a callback that
-** will be invoked each time a database connection commits data to a
-** [write-ahead log] (i.e. whenever a transaction is committed in
-** [journal_mode | journal_mode=WAL mode]).
+** is invoked each time data is committed to a database in wal mode.
**
-** ^The callback is invoked by SQLite after the commit has taken place and
-** the associated write-lock on the database released, so the implementation
+** ^(The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released)^, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
@@ -7173,7 +7266,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
-SQLITE_API void *sqlite3_wal_hook(
+SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
@@ -7207,104 +7300,121 @@ SQLITE_API void *sqlite3_wal_hook(
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
-SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
**
-** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
-** on [database connection] D to be [checkpointed]. ^If X is NULL or an
-** empty string, then a checkpoint is run on all databases of
-** connection D. ^If the database connection D is not in
-** [WAL | write-ahead log mode] then this interface is a harmless no-op.
-** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
-** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
-** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
-** or RESET checkpoint.
+** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
+** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
**
-** ^The [wal_checkpoint pragma] can be used to invoke this interface
-** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
-** [wal_autocheckpoint pragma] can be used to cause this interface to be
-** run whenever the WAL reaches a certain size threshold.
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
+** [write-ahead log] for database X on [database connection] D to be
+** transferred into the database file and for the write-ahead log to
+** be reset. See the [checkpointing] documentation for addition
+** information.
**
-** See also: [sqlite3_wal_checkpoint_v2()]
+** This interface used to be the only way to cause a checkpoint to
+** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()]
+** interface was added. This interface is retained for backwards
+** compatibility and as a convenience for applications that need to manually
+** start a callback but which do not need the full power (and corresponding
+** complication) of [sqlite3_wal_checkpoint_v2()].
*/
-SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** CAPI3REF: Checkpoint a database
**
-** Run a checkpoint operation on WAL database zDb attached to database
-** handle db. The specific operation is determined by the value of the
-** eMode parameter:
+** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint
+** operation on database X of [database connection] D in mode M. Status
+** information is written back into integers pointed to by L and C.)^
+** ^(The M parameter must be a valid [checkpoint mode]:)^
**
** <dl>
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
-** Checkpoint as many frames as possible without waiting for any database
-** readers or writers to finish. Sync the db file if all frames in the log
-** are checkpointed. This mode is the same as calling
-** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
-** is never invoked.
+** ^Checkpoint as many frames as possible without waiting for any database
+** readers or writers to finish, then sync the database file if all frames
+** in the log were checkpointed. ^The [busy-handler callback]
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
+** ^On the other hand, passive mode might leave the checkpoint unfinished
+** if there are concurrent readers or writers.
**
** <dt>SQLITE_CHECKPOINT_FULL<dd>
-** This mode blocks (it invokes the
+** ^This mode blocks (it invokes the
** [sqlite3_busy_handler|busy-handler callback]) until there is no
** database writer and all readers are reading from the most recent database
-** snapshot. It then checkpoints all frames in the log file and syncs the
-** database file. This call blocks database writers while it is running,
-** but not database readers.
+** snapshot. ^It then checkpoints all frames in the log file and syncs the
+** database file. ^This mode blocks new database writers while it is pending,
+** but new database readers are allowed to continue unimpeded.
**
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
-** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
-** checkpointing the log file it blocks (calls the
-** [sqlite3_busy_handler|busy-handler callback])
-** until all readers are reading from the database file only. This ensures
-** that the next client to write to the database file restarts the log file
-** from the beginning. This call blocks database writers while it is running,
-** but not database readers.
+** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
+** that after checkpointing the log file it blocks (calls the
+** [busy-handler callback])
+** until all readers are reading from the database file only. ^This ensures
+** that the next writer will restart the log file from the beginning.
+** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
+** database writer attempts while it is pending, but does not impede readers.
+**
+** <dt>SQLITE_CHECKPOINT_TRUNCATE<dd>
+** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the
+** addition that it also truncates the log file to zero bytes just prior
+** to a successful return.
** </dl>
**
-** If pnLog is not NULL, then *pnLog is set to the total number of frames in
-** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to
-** the total number of checkpointed frames (including any that were already
-** checkpointed when this function is called). *pnLog and *pnCkpt may be
-** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK.
-** If no values are available because of an error, they are both set to -1
-** before returning to communicate this to the caller.
-**
-** All calls obtain an exclusive "checkpoint" lock on the database file. If
+** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in
+** the log file or to -1 if the checkpoint could not run because
+** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not
+** NULL,then *pnCkpt is set to the total number of checkpointed frames in the
+** log file (including any that were already checkpointed before the function
+** was called) or to -1 if the checkpoint could not run due to an error or
+** because the database is not in WAL mode. ^Note that upon successful
+** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been
+** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
+**
+** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
** any other process is running a checkpoint operation at the same time, the
-** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
** busy-handler configured, it will not be invoked in this case.
**
-** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive
-** "writer" lock on the database file. If the writer lock cannot be obtained
-** immediately, and a busy-handler is configured, it is invoked and the writer
-** lock retried until either the busy-handler returns 0 or the lock is
-** successfully obtained. The busy-handler is also invoked while waiting for
-** database readers as described above. If the busy-handler returns 0 before
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
+** exclusive "writer" lock on the database file. ^If the writer lock cannot be
+** obtained immediately, and a busy-handler is configured, it is invoked and
+** the writer lock retried until either the busy-handler returns 0 or the lock
+** is successfully obtained. ^The busy-handler is also invoked while waiting for
+** database readers as described above. ^If the busy-handler returns 0 before
** the writer lock is obtained or while waiting for database readers, the
** checkpoint operation proceeds from that point in the same way as
** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
-** without blocking any further. SQLITE_BUSY is returned in this case.
+** without blocking any further. ^SQLITE_BUSY is returned in this case.
**
-** If parameter zDb is NULL or points to a zero length string, then the
-** specified operation is attempted on all WAL databases. In this case the
-** values written to output parameters *pnLog and *pnCkpt are undefined. If
+** ^If parameter zDb is NULL or points to a zero length string, then the
+** specified operation is attempted on all WAL databases [attached] to
+** [database connection] db. In this case the
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
** an SQLITE_BUSY error is encountered when processing one or more of the
** attached WAL databases, the operation is still attempted on any remaining
-** attached databases and SQLITE_BUSY is returned to the caller. If any other
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
** error occurs while processing an attached database, processing is abandoned
-** and the error code returned to the caller immediately. If no error
+** and the error code is returned to the caller immediately. ^If no error
** (SQLITE_BUSY or otherwise) is encountered while processing the attached
** databases, SQLITE_OK is returned.
**
-** If database zDb is the name of an attached database that is not in WAL
-** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If
+** ^If database zDb is the name of an attached database that is not in WAL
+** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If
** zDb is not NULL (or a zero length string) and is not the name of any
** attached database, SQLITE_ERROR is returned to the caller.
+**
+** ^Unless it returns SQLITE_MISUSE,
+** the sqlite3_wal_checkpoint_v2() interface
+** sets the error information that is queried by
+** [sqlite3_errcode()] and [sqlite3_errmsg()].
+**
+** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
+** from SQL.
*/
-SQLITE_API int sqlite3_wal_checkpoint_v2(
+SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -7313,16 +7423,18 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
);
/*
-** CAPI3REF: Checkpoint operation parameters
+** CAPI3REF: Checkpoint Mode Values
+** KEYWORDS: {checkpoint mode}
**
-** These constants can be used as the 3rd parameter to
-** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()]
-** documentation for additional information about the meaning and use of
-** each of these values.
+** These constants define all valid values for the "checkpoint mode" passed
+** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface.
+** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the
+** meaning of each of these checkpoint modes.
*/
-#define SQLITE_CHECKPOINT_PASSIVE 0
-#define SQLITE_CHECKPOINT_FULL 1
-#define SQLITE_CHECKPOINT_RESTART 2
+#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
+#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
** CAPI3REF: Virtual Table Interface Configuration
@@ -7338,7 +7450,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
** may be added in the future.
*/
-SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
+SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
@@ -7391,7 +7503,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
-SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
+SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
@@ -7411,6 +7523,106 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/* #define SQLITE_ABORT 4 // Also an error code */
#define SQLITE_REPLACE 5
+/*
+** CAPI3REF: Prepared Statement Scan Status Opcodes
+** KEYWORDS: {scanstatus options}
+**
+** The following constants can be used for the T parameter to the
+** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a
+** different metric for sqlite3_stmt_scanstatus() to return.
+**
+** When the value returned to V is a string, space to hold that string is
+** managed by the prepared statement S and will be automatically freed when
+** S is finalized.
+**
+** <dl>
+** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
+** set to the total number of times that the X-th loop has run.</dd>
+**
+** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
+** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
+** to the total number of rows examined by all iterations of the X-th loop.</dd>
+**
+** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
+** <dd>^The "double" variable pointed to by the T parameter will be set to the
+** query planner's estimate for the average number of rows output from each
+** iteration of the X-th loop. If the query planner's estimates was accurate,
+** then this value will approximate the quotient NVISIT/NLOOP and the
+** product of this value for all prior loops with the same SELECTID will
+** be the NLOOP value for the current loop.
+**
+** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the name of the index or table
+** used for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
+** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
+** description for the X-th loop.
+**
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** <dd>^The "int" variable pointed to by the T parameter will be set to the
+** "select-id" for the X-th loop. The select-id identifies which query or
+** subquery the loop is part of. The main query has a select-id of zero.
+** The select-id is the same value as is output in the first column
+** of an [EXPLAIN QUERY PLAN] query.
+** </dl>
+*/
+#define SQLITE_SCANSTAT_NLOOP 0
+#define SQLITE_SCANSTAT_NVISIT 1
+#define SQLITE_SCANSTAT_EST 2
+#define SQLITE_SCANSTAT_NAME 3
+#define SQLITE_SCANSTAT_EXPLAIN 4
+#define SQLITE_SCANSTAT_SELECTID 5
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+**
+** This interface returns information about the predicted and measured
+** performance for pStmt. Advanced applications can use this
+** interface to compare the predicted and the measured performance and
+** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
+**
+** Since this interface is expected to be rarely used, it is only
+** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS]
+** compile-time option.
+**
+** The "iScanStatusOp" parameter determines which status information to return.
+** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
+** of this interface is undefined.
+** ^The requested measurement is written into a variable pointed to by
+** the "pOut" parameter.
+** Parameter "idx" identifies the specific loop to retrieve statistics for.
+** Loops are numbered starting from zero. ^If idx is out of range - less than
+** zero or greater than or equal to the total number of loops used to implement
+** the statement - a non-zero value is returned and the variable that pOut
+** points to is unchanged.
+**
+** ^Statistics might not be available for all loops in all statements. ^In cases
+** where there exist loops with no available statistics, this function behaves
+** as if the loop did not exist - it returns non-zero and leave the variable
+** that pOut points to unchanged.
+**
+** See also: [sqlite3_stmt_scanstatus_reset()]
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Zero Scan-Status Counters
+**
+** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
+**
+** This API is only available if the library is built with pre-processor
+** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
@@ -7465,7 +7677,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
*/
-SQLITE_API int sqlite3_rtree_geometry_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
@@ -7491,7 +7703,7 @@ struct sqlite3_rtree_geometry {
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
-SQLITE_API int sqlite3_rtree_query_callback(
+SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
diff --git a/contrib/tcpdump/interface.h b/contrib/tcpdump/interface.h
index 5efecb8..299d010 100644
--- a/contrib/tcpdump/interface.h
+++ b/contrib/tcpdump/interface.h
@@ -148,8 +148,6 @@ extern uint16_t create_osi_cksum(const uint8_t *, int, int);
#include <pcap.h>
-extern void pfsync_ip_print(const u_char *, u_int);
-
extern char *q922_string(const u_char *);
extern char *smb_errstr(int, int);
extern const char *nt_errstr(uint32_t);
diff --git a/contrib/tcpdump/netdissect.h b/contrib/tcpdump/netdissect.h
index 55d45b2..a40869c 100644
--- a/contrib/tcpdump/netdissect.h
+++ b/contrib/tcpdump/netdissect.h
@@ -540,6 +540,8 @@ extern void timed_print(netdissect_options *, const u_char *);
extern void m3ua_print(netdissect_options *, const u_char *, const u_int);
extern void aoe_print(netdissect_options *, const u_char *, const u_int);
+extern void pfsync_ip_print(netdissect_options *, const u_char *, u_int);
+
/* stuff that has not yet been rototiled */
#if 0
diff --git a/contrib/tcpdump/print-ip.c b/contrib/tcpdump/print-ip.c
index 1add0c7..0e3ae96 100644
--- a/contrib/tcpdump/print-ip.c
+++ b/contrib/tcpdump/print-ip.c
@@ -487,7 +487,7 @@ again:
#if defined(HAVE_NET_PFVAR_H)
case IPPROTO_PFSYNC:
- pfsync_ip_print(ipds->cp, ipds->len);
+ pfsync_ip_print(ndo, ipds->cp, ipds->len);
break;
#endif
diff --git a/contrib/tcpdump/print-pfsync.c b/contrib/tcpdump/print-pfsync.c
index ed7f8dd..eb9aed8 100644
--- a/contrib/tcpdump/print-pfsync.c
+++ b/contrib/tcpdump/print-pfsync.c
@@ -47,10 +47,12 @@
#include "interface.h"
#include "addrtoname.h"
-static void pfsync_print(struct pfsync_header *, const u_char *, u_int);
-static void print_src_dst(const struct pfsync_state_peer *,
+static void pfsync_print(netdissect_options *, struct pfsync_header *,
+ const u_char *, u_int);
+static void print_src_dst(netdissect_options *,
+ const struct pfsync_state_peer *,
const struct pfsync_state_peer *, uint8_t);
-static void print_state(struct pfsync_state *);
+static void print_state(netdissect_options *, struct pfsync_state *);
#ifdef notyet
void
@@ -62,7 +64,7 @@ pfsync_if_print(u_char *user, const struct pcap_pkthdr *h,
ts_print(&h->ts);
if (caplen < PFSYNC_HDRLEN) {
- printf("[|pfsync]");
+ ND_PRINT((ndo, "[|pfsync]"));
goto out;
}
@@ -73,36 +75,36 @@ out:
if (xflag) {
default_print((const u_char *)p, caplen);
}
- putchar('\n');
+ safeputchar(ndo, '\n');
}
#endif /* notyet */
void
-pfsync_ip_print(const u_char *bp, u_int len)
+pfsync_ip_print(netdissect_options *ndo , const u_char *bp, u_int len)
{
struct pfsync_header *hdr = (struct pfsync_header *)bp;
if (len < PFSYNC_HDRLEN)
- printf("[|pfsync]");
+ ND_PRINT((ndo, "[|pfsync]"));
else
- pfsync_print(hdr, bp + sizeof(struct pfsync_header),
+ pfsync_print(ndo, hdr, bp + sizeof(struct pfsync_header),
len - sizeof(struct pfsync_header));
}
struct pfsync_actions {
const char *name;
size_t len;
- void (*print)(const void *);
+ void (*print)(netdissect_options *, const void *);
};
-static void pfsync_print_clr(const void *);
-static void pfsync_print_state(const void *);
-static void pfsync_print_ins_ack(const void *);
-static void pfsync_print_upd_c(const void *);
-static void pfsync_print_upd_req(const void *);
-static void pfsync_print_del_c(const void *);
-static void pfsync_print_bus(const void *);
-static void pfsync_print_tdb(const void *);
+static void pfsync_print_clr(netdissect_options *, const void *);
+static void pfsync_print_state(netdissect_options *, const void *);
+static void pfsync_print_ins_ack(netdissect_options *, const void *);
+static void pfsync_print_upd_c(netdissect_options *, const void *);
+static void pfsync_print_upd_req(netdissect_options *, const void *);
+static void pfsync_print_del_c(netdissect_options *, const void *);
+static void pfsync_print_bus(netdissect_options *, const void *);
+static void pfsync_print_tdb(netdissect_options *, const void *);
struct pfsync_actions actions[] = {
{ "clear all", sizeof(struct pfsync_clr), pfsync_print_clr },
@@ -125,7 +127,8 @@ struct pfsync_actions actions[] = {
};
static void
-pfsync_print(struct pfsync_header *hdr, const u_char *bp, u_int len)
+pfsync_print(netdissect_options *ndo, struct pfsync_header *hdr,
+ const u_char *bp, u_int len)
{
struct pfsync_subheader *subh;
int count, plen, i;
@@ -133,7 +136,7 @@ pfsync_print(struct pfsync_header *hdr, const u_char *bp, u_int len)
plen = ntohs(hdr->len);
- printf("PFSYNCv%d len %d", hdr->version, plen);
+ ND_PRINT((ndo, "PFSYNCv%d len %d", hdr->version, plen));
if (hdr->version != PFSYNC_VERSION)
return;
@@ -150,19 +153,22 @@ pfsync_print(struct pfsync_header *hdr, const u_char *bp, u_int len)
plen -= sizeof(*subh);
if (subh->action >= PFSYNC_ACT_MAX) {
- printf("\n act UNKNOWN id %d", subh->action);
+ ND_PRINT((ndo, "\n act UNKNOWN id %d",
+ subh->action));
return;
}
count = ntohs(subh->count);
- printf("\n %s count %d", actions[subh->action].name, count);
+ ND_PRINT((ndo, "\n %s count %d", actions[subh->action].name,
+ count));
alen = actions[subh->action].len;
if (subh->action == PFSYNC_ACT_EOF)
return;
if (actions[subh->action].print == NULL) {
- printf("\n unimplemented action %hhu", subh->action);
+ ND_PRINT((ndo, "\n unimplemented action %hhu",
+ subh->action));
return;
}
@@ -173,7 +179,7 @@ pfsync_print(struct pfsync_header *hdr, const u_char *bp, u_int len)
}
if (vflag)
- actions[subh->action].print(bp);
+ actions[subh->action].print(ndo, bp);
bp += alen;
len -= alen;
@@ -182,78 +188,78 @@ pfsync_print(struct pfsync_header *hdr, const u_char *bp, u_int len)
}
if (plen > 0) {
- printf("\n ...");
+ ND_PRINT((ndo, "\n ..."));
return;
}
if (plen < 0) {
- printf("\n invalid header length");
+ ND_PRINT((ndo, "\n invalid header length"));
return;
}
if (len > 0)
- printf("\n invalid packet length");
+ ND_PRINT((ndo, "\n invalid packet length"));
}
static void
-pfsync_print_clr(const void *bp)
+pfsync_print_clr(netdissect_options *ndo, const void *bp)
{
const struct pfsync_clr *clr = bp;
- printf("\n\tcreatorid: %08x", htonl(clr->creatorid));
+ ND_PRINT((ndo, "\n\tcreatorid: %08x", htonl(clr->creatorid)));
if (clr->ifname[0] != '\0')
- printf(" interface: %s", clr->ifname);
+ ND_PRINT((ndo, " interface: %s", clr->ifname));
}
static void
-pfsync_print_state(const void *bp)
+pfsync_print_state(netdissect_options *ndo, const void *bp)
{
struct pfsync_state *st = (struct pfsync_state *)bp;
- putchar('\n');
- print_state(st);
+ safeputchar(ndo, '\n');
+ print_state(ndo, st);
}
static void
-pfsync_print_ins_ack(const void *bp)
+pfsync_print_ins_ack(netdissect_options *ndo, const void *bp)
{
const struct pfsync_ins_ack *iack = bp;
- printf("\n\tid: %016jx creatorid: %08x", (uintmax_t )be64toh(iack->id),
- ntohl(iack->creatorid));
+ ND_PRINT((ndo, "\n\tid: %016jx creatorid: %08x",
+ (uintmax_t)be64toh(iack->id), ntohl(iack->creatorid)));
}
static void
-pfsync_print_upd_c(const void *bp)
+pfsync_print_upd_c(netdissect_options *ndo, const void *bp)
{
const struct pfsync_upd_c *u = bp;
- printf("\n\tid: %016jx creatorid: %08x", (uintmax_t )be64toh(u->id),
- ntohl(u->creatorid));
+ ND_PRINT((ndo, "\n\tid: %016jx creatorid: %08x",
+ (uintmax_t)be64toh(u->id), ntohl(u->creatorid)));
if (vflag > 2) {
- printf("\n\tTCP? :");
- print_src_dst(&u->src, &u->dst, IPPROTO_TCP);
+ ND_PRINT((ndo, "\n\tTCP? :"));
+ print_src_dst(ndo, &u->src, &u->dst, IPPROTO_TCP);
}
}
static void
-pfsync_print_upd_req(const void *bp)
+pfsync_print_upd_req(netdissect_options *ndo, const void *bp)
{
const struct pfsync_upd_req *ur = bp;
- printf("\n\tid: %016jx creatorid: %08x", (uintmax_t )be64toh(ur->id),
- ntohl(ur->creatorid));
+ ND_PRINT((ndo, "\n\tid: %016jx creatorid: %08x",
+ (uintmax_t)be64toh(ur->id), ntohl(ur->creatorid)));
}
static void
-pfsync_print_del_c(const void *bp)
+pfsync_print_del_c(netdissect_options *ndo, const void *bp)
{
const struct pfsync_del_c *d = bp;
- printf("\n\tid: %016jx creatorid: %08x", (uintmax_t )be64toh(d->id),
- ntohl(d->creatorid));
+ ND_PRINT((ndo, "\n\tid: %016jx creatorid: %08x",
+ (uintmax_t)be64toh(d->id), ntohl(d->creatorid)));
}
static void
-pfsync_print_bus(const void *bp)
+pfsync_print_bus(netdissect_options *ndo, const void *bp)
{
const struct pfsync_bus *b = bp;
uint32_t endtime;
@@ -278,95 +284,95 @@ pfsync_print_bus(const void *bp)
break;
}
- printf("\n\tcreatorid: %08x age: %.2u:%.2u:%.2u status: %s",
- htonl(b->creatorid), endtime, min, sec, status);
+ ND_PRINT((ndo, "\n\tcreatorid: %08x age: %.2u:%.2u:%.2u status: %s",
+ htonl(b->creatorid), endtime, min, sec, status));
}
static void
-pfsync_print_tdb(const void *bp)
+pfsync_print_tdb(netdissect_options *ndo, const void *bp)
{
const struct pfsync_tdb *t = bp;
- printf("\n\tspi: 0x%08x rpl: %ju cur_bytes: %ju",
+ ND_PRINT((ndo, "\n\tspi: 0x%08x rpl: %ju cur_bytes: %ju",
ntohl(t->spi), (uintmax_t )be64toh(t->rpl),
- (uintmax_t )be64toh(t->cur_bytes));
+ (uintmax_t )be64toh(t->cur_bytes)));
}
static void
-print_host(struct pf_addr *addr, uint16_t port, sa_family_t af,
- const char *proto)
+print_host(netdissect_options *ndo, struct pf_addr *addr, uint16_t port,
+ sa_family_t af, const char *proto)
{
char buf[48];
if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL)
- printf("?");
+ ND_PRINT((ndo, "?"));
else
- printf("%s", buf);
+ ND_PRINT((ndo, "%s", buf));
if (port)
- printf(".%hu", ntohs(port));
+ ND_PRINT((ndo, ".%hu", ntohs(port)));
}
static void
-print_seq(const struct pfsync_state_peer *p)
+print_seq(netdissect_options *ndo, const struct pfsync_state_peer *p)
{
if (p->seqdiff)
- printf("[%u + %u](+%u)", ntohl(p->seqlo),
- ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff));
+ ND_PRINT((ndo, "[%u + %u](+%u)", ntohl(p->seqlo),
+ ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)));
else
- printf("[%u + %u]", ntohl(p->seqlo),
- ntohl(p->seqhi) - ntohl(p->seqlo));
+ ND_PRINT((ndo, "[%u + %u]", ntohl(p->seqlo),
+ ntohl(p->seqhi) - ntohl(p->seqlo)));
}
static void
-print_src_dst(const struct pfsync_state_peer *src,
+print_src_dst(netdissect_options *ndo, const struct pfsync_state_peer *src,
const struct pfsync_state_peer *dst, uint8_t proto)
{
if (proto == IPPROTO_TCP) {
if (src->state <= TCPS_TIME_WAIT &&
dst->state <= TCPS_TIME_WAIT)
- printf(" %s:%s", tcpstates[src->state],
- tcpstates[dst->state]);
+ ND_PRINT((ndo, " %s:%s", tcpstates[src->state],
+ tcpstates[dst->state]));
else if (src->state == PF_TCPS_PROXY_SRC ||
dst->state == PF_TCPS_PROXY_SRC)
- printf(" PROXY:SRC");
+ ND_PRINT((ndo, " PROXY:SRC"));
else if (src->state == PF_TCPS_PROXY_DST ||
dst->state == PF_TCPS_PROXY_DST)
- printf(" PROXY:DST");
+ ND_PRINT((ndo, " PROXY:DST"));
else
- printf(" <BAD STATE LEVELS %u:%u>",
- src->state, dst->state);
+ ND_PRINT((ndo, " <BAD STATE LEVELS %u:%u>",
+ src->state, dst->state));
if (vflag > 1) {
- printf("\n\t");
- print_seq(src);
+ ND_PRINT((ndo, "\n\t"));
+ print_seq(ndo, src);
if (src->wscale && dst->wscale)
- printf(" wscale %u",
- src->wscale & PF_WSCALE_MASK);
- printf(" ");
- print_seq(dst);
+ ND_PRINT((ndo, " wscale %u",
+ src->wscale & PF_WSCALE_MASK));
+ ND_PRINT((ndo, " "));
+ print_seq(ndo, dst);
if (src->wscale && dst->wscale)
- printf(" wscale %u",
- dst->wscale & PF_WSCALE_MASK);
+ ND_PRINT((ndo, " wscale %u",
+ dst->wscale & PF_WSCALE_MASK));
}
} else if (proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES &&
dst->state < PFUDPS_NSTATES) {
const char *states[] = PFUDPS_NAMES;
- printf(" %s:%s", states[src->state], states[dst->state]);
+ ND_PRINT((ndo, " %s:%s", states[src->state], states[dst->state]));
} else if (proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
dst->state < PFOTHERS_NSTATES) {
/* XXX ICMP doesn't really have state levels */
const char *states[] = PFOTHERS_NAMES;
- printf(" %s:%s", states[src->state], states[dst->state]);
+ ND_PRINT((ndo, " %s:%s", states[src->state], states[dst->state]));
} else {
- printf(" %u:%u", src->state, dst->state);
+ ND_PRINT((ndo, " %u:%u", src->state, dst->state));
}
}
static void
-print_state(struct pfsync_state *s)
+print_state(netdissect_options *ndo, struct pfsync_state *s)
{
struct pfsync_state_peer *src, *dst;
struct pfsync_state_key *sk, *nk;
@@ -387,29 +393,29 @@ print_state(struct pfsync_state *s)
if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
sk->port[1] = nk->port[1];
}
- printf("\t%s ", s->ifname);
- printf("proto %u ", s->proto);
+ ND_PRINT((ndo, "\t%s ", s->ifname));
+ ND_PRINT((ndo, "proto %u ", s->proto));
- print_host(&nk->addr[1], nk->port[1], s->af, NULL);
+ print_host(ndo, &nk->addr[1], nk->port[1], s->af, NULL);
if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) ||
nk->port[1] != sk->port[1]) {
- printf(" (");
- print_host(&sk->addr[1], sk->port[1], s->af, NULL);
- printf(")");
+ ND_PRINT((ndo, " ("));
+ print_host(ndo, &sk->addr[1], sk->port[1], s->af, NULL);
+ ND_PRINT((ndo, ")"));
}
if (s->direction == PF_OUT)
- printf(" -> ");
+ ND_PRINT((ndo, " -> "));
else
- printf(" <- ");
- print_host(&nk->addr[0], nk->port[0], s->af, NULL);
+ ND_PRINT((ndo, " <- "));
+ print_host(ndo, &nk->addr[0], nk->port[0], s->af, NULL);
if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) ||
nk->port[0] != sk->port[0]) {
- printf(" (");
- print_host(&sk->addr[0], sk->port[0], s->af, NULL);
- printf(")");
+ ND_PRINT((ndo, " ("));
+ print_host(ndo, &sk->addr[0], sk->port[0], s->af, NULL);
+ ND_PRINT((ndo, ")"));
}
- print_src_dst(src, dst, s->proto);
+ print_src_dst(ndo, src, dst, s->proto);
if (vflag > 1) {
uint64_t packets[2];
@@ -421,30 +427,30 @@ print_state(struct pfsync_state *s)
creation /= 60;
min = creation % 60;
creation /= 60;
- printf("\n\tage %.2u:%.2u:%.2u", creation, min, sec);
+ ND_PRINT((ndo, "\n\tage %.2u:%.2u:%.2u", creation, min, sec));
sec = expire % 60;
expire /= 60;
min = expire % 60;
expire /= 60;
- printf(", expires in %.2u:%.2u:%.2u", expire, min, sec);
+ ND_PRINT((ndo, ", expires in %.2u:%.2u:%.2u", expire, min, sec));
bcopy(s->packets[0], &packets[0], sizeof(uint64_t));
bcopy(s->packets[1], &packets[1], sizeof(uint64_t));
bcopy(s->bytes[0], &bytes[0], sizeof(uint64_t));
bcopy(s->bytes[1], &bytes[1], sizeof(uint64_t));
- printf(", %ju:%ju pkts, %ju:%ju bytes",
+ ND_PRINT((ndo, ", %ju:%ju pkts, %ju:%ju bytes",
be64toh(packets[0]), be64toh(packets[1]),
- be64toh(bytes[0]), be64toh(bytes[1]));
+ be64toh(bytes[0]), be64toh(bytes[1])));
if (s->anchor != ntohl(-1))
- printf(", anchor %u", ntohl(s->anchor));
+ ND_PRINT((ndo, ", anchor %u", ntohl(s->anchor)));
if (s->rule != ntohl(-1))
- printf(", rule %u", ntohl(s->rule));
+ ND_PRINT((ndo, ", rule %u", ntohl(s->rule)));
}
if (vflag > 1) {
uint64_t id;
bcopy(&s->id, &id, sizeof(uint64_t));
- printf("\n\tid: %016jx creatorid: %08x",
- (uintmax_t )be64toh(id), ntohl(s->creatorid));
+ ND_PRINT((ndo, "\n\tid: %016jx creatorid: %08x",
+ (uintmax_t )be64toh(id), ntohl(s->creatorid)));
}
}
diff --git a/contrib/unbound/Makefile.in b/contrib/unbound/Makefile.in
index 02532a9..0c7e0c6 100644
--- a/contrib/unbound/Makefile.in
+++ b/contrib/unbound/Makefile.in
@@ -459,8 +459,8 @@ strip:
$(STRIP) unbound$(EXEEXT)
$(STRIP) unbound-checkconf$(EXEEXT)
$(STRIP) unbound-control$(EXEEXT)
- $(STRIP) unbound-host$(EXEEXT)
- $(STRIP) unbound-anchor$(EXEEXT)
+ $(STRIP) unbound-host$(EXEEXT) || $(STRIP) .libs/unbound-host$(EXEEXT)
+ $(STRIP) unbound-anchor$(EXEEXT) || $(STRIP) .libs/unbound-anchor$(EXEEXT)
pythonmod-install:
$(INSTALL) -m 755 -d $(DESTDIR)$(PYTHON_SITE_PKG)
@@ -576,6 +576,7 @@ depend:
-e 's?$$(srcdir)/util/configlexer.c?util/configlexer.c?g' \
-e 's?$$(srcdir)/util/configparser.c?util/configparser.c?g' \
-e 's?$$(srcdir)/util/configparser.h?util/configparser.h?g' \
+ -e 's?$$(srcdir)/dnstap/dnstap_config.h??g' \
-e 's?$$(srcdir)/pythonmod/pythonmod.h?$$(PYTHONMOD_HEADER)?g' \
-e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' \
> $(DEPEND_TMP)
@@ -689,13 +690,14 @@ iter_utils.lo iter_utils.o: $(srcdir)/iterator/iter_utils.c config.h $(srcdir)/i
$(srcdir)/validator/val_utils.h $(srcdir)/validator/val_sigcrypt.h $(srcdir)/ldns/sbuffer.h
listen_dnsport.lo listen_dnsport.o: $(srcdir)/services/listen_dnsport.c config.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/util/netevent.h $(srcdir)/services/outside_network.h \
- $(srcdir)/util/rbtree.h $(srcdir)/util/log.h $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h \
- $(srcdir)/ldns/sbuffer.h
+ $(srcdir)/util/rbtree.h $(srcdir)/util/log.h $(srcdir)/util/config_file.h \
+ $(srcdir)/util/net_help.h $(srcdir)/ldns/sbuffer.h
localzone.lo localzone.o: $(srcdir)/services/localzone.c config.h $(srcdir)/services/localzone.h \
$(srcdir)/util/rbtree.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/ldns/str2wire.h $(srcdir)/ldns/rrdef.h \
$(srcdir)/ldns/sbuffer.h $(srcdir)/util/regional.h $(srcdir)/util/config_file.h $(srcdir)/util/data/dname.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgencode.h \
- $(srcdir)/util/net_help.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h
+ $(srcdir)/util/net_help.h $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h \
+ $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h
mesh.lo mesh.o: $(srcdir)/services/mesh.c config.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/netevent.h $(srcdir)/util/data/msgparse.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
$(srcdir)/util/log.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
@@ -711,15 +713,16 @@ modstack.lo modstack.o: $(srcdir)/services/modstack.c config.h $(srcdir)/service
$(srcdir)/services/outbound_list.h $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h
outbound_list.lo outbound_list.o: $(srcdir)/services/outbound_list.c config.h \
$(srcdir)/services/outbound_list.h $(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h \
- $(srcdir)/util/netevent.h
+ $(srcdir)/util/netevent.h
outside_network.lo outside_network.o: $(srcdir)/services/outside_network.c config.h \
$(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h $(srcdir)/util/netevent.h \
- $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/lruhash.h \
- $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/rtt.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h \
- $(srcdir)/ldns/rrdef.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
- $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h $(srcdir)/util/net_help.h $(srcdir)/util/random.h \
- $(srcdir)/util/fptr_wlist.h $(srcdir)/util/module.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h \
- $(srcdir)/services/modstack.h $(srcdir)/ldns/sbuffer.h \
+ $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/infra.h \
+ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/rtt.h \
+ $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/data/msgreply.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h \
+ $(srcdir)/util/net_help.h $(srcdir)/util/random.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/module.h \
+ $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h $(srcdir)/ldns/sbuffer.h \
+ $(srcdir)/dnstap/dnstap.h \
alloc.lo alloc.o: $(srcdir)/util/alloc.c config.h $(srcdir)/util/alloc.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/util/regional.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
@@ -732,8 +735,8 @@ config_file.lo config_file.o: $(srcdir)/util/config_file.c config.h $(srcdir)/ut
$(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/regional.h $(srcdir)/util/fptr_wlist.h \
$(srcdir)/util/netevent.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \
- $(srcdir)/services/modstack.h $(srcdir)/util/data/dname.h $(srcdir)/ldns/wire2str.h $(srcdir)/ldns/parseutil.h \
- $(srcdir)/util/iana_ports.inc
+ $(srcdir)/services/modstack.h $(srcdir)/util/data/dname.h $(srcdir)/util/rtt.h $(srcdir)/ldns/wire2str.h \
+ $(srcdir)/ldns/parseutil.h $(srcdir)/util/iana_ports.inc
configlexer.lo configlexer.o: util/configlexer.c config.h $(srcdir)/util/configyyrename.h \
$(srcdir)/util/config_file.h util/configparser.h
configparser.lo configparser.o: util/configparser.c config.h $(srcdir)/util/configyyrename.h \
@@ -743,15 +746,16 @@ fptr_wlist.lo fptr_wlist.o: $(srcdir)/util/fptr_wlist.c config.h $(srcdir)/util/
$(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
$(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/tube.h \
$(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h $(srcdir)/util/mini_event.h \
- $(srcdir)/util/rbtree.h $(srcdir)/services/outside_network.h $(srcdir)/services/localzone.h \
- $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/cache/rrset.h \
- $(srcdir)/util/storage/slabhash.h $(srcdir)/dns64/dns64.h $(srcdir)/iterator/iterator.h \
- $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/validator/validator.h \
- $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_anchor.h $(srcdir)/validator/val_nsec3.h \
- $(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_kentry.h $(srcdir)/validator/val_neg.h \
- $(srcdir)/validator/autotrust.h $(srcdir)/util/storage/dnstree.h $(srcdir)/libunbound/libworker.h \
- $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/libunbound/unbound.h \
- $(srcdir)/libunbound/worker.h $(srcdir)/ldns/sbuffer.h $(srcdir)/util/config_file.h
+ $(srcdir)/util/rbtree.h $(srcdir)/services/outside_network.h \
+ $(srcdir)/services/localzone.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/dns64/dns64.h \
+ $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_fwd.h \
+ $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_anchor.h \
+ $(srcdir)/validator/val_nsec3.h $(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_kentry.h \
+ $(srcdir)/validator/val_neg.h $(srcdir)/validator/autotrust.h $(srcdir)/util/storage/dnstree.h \
+ $(srcdir)/libunbound/libworker.h $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h \
+ $(srcdir)/libunbound/unbound.h $(srcdir)/libunbound/worker.h $(srcdir)/ldns/sbuffer.h \
+ $(srcdir)/util/config_file.h
locks.lo locks.o: $(srcdir)/util/locks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h
log.lo log.o: $(srcdir)/util/log.c config.h $(srcdir)/util/log.h $(srcdir)/util/locks.h $(srcdir)/ldns/sbuffer.h
mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \
@@ -767,6 +771,7 @@ netevent.lo netevent.o: $(srcdir)/util/netevent.c config.h $(srcdir)/util/neteve
$(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
$(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/tube.h \
$(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h $(srcdir)/ldns/sbuffer.h \
+ $(srcdir)/dnstap/dnstap.h \
$(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h
net_help.lo net_help.o: $(srcdir)/util/net_help.c config.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h \
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/module.h \
@@ -854,8 +859,8 @@ val_nsec.lo val_nsec.o: $(srcdir)/validator/val_nsec.c config.h $(srcdir)/valida
$(srcdir)/validator/val_utils.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/dname.h \
$(srcdir)/util/net_help.h $(srcdir)/util/module.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h \
$(srcdir)/ldns/rrdef.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h
-val_secalgo.lo val_secalgo.o: $(srcdir)/validator/val_secalgo.c config.h $(srcdir)/validator/val_secalgo.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
+val_secalgo.lo val_secalgo.o: $(srcdir)/validator/val_secalgo.c config.h $(srcdir)/util/data/packed_rrset.h \
+ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/validator/val_secalgo.h \
$(srcdir)/ldns/rrdef.h $(srcdir)/ldns/keyraw.h \
$(srcdir)/ldns/sbuffer.h \
@@ -884,6 +889,11 @@ dns64.lo dns64.o: $(srcdir)/dns64/dns64.c config.h $(srcdir)/dns64/dns64.h $(src
$(srcdir)/util/regional.h
checklocks.lo checklocks.o: $(srcdir)/testcode/checklocks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/testcode/checklocks.h
+dnstap.lo dnstap.o: $(srcdir)/dnstap/dnstap.c config.h $(srcdir)/ldns/sbuffer.h \
+ $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h \
+ $(srcdir)/dnstap/dnstap.h \
+ $(srcdir)/dnstap/dnstap.pb-c.h
+dnstap.pb-c.lo dnstap.pb-c.o: $(srcdir)/dnstap/dnstap.pb-c.c $(srcdir)/dnstap/dnstap.pb-c.h
unitanchor.lo unitanchor.o: $(srcdir)/testcode/unitanchor.c config.h $(srcdir)/util/log.h $(srcdir)/util/data/dname.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/testcode/unitmain.h \
$(srcdir)/validator/val_anchor.h $(srcdir)/util/rbtree.h $(srcdir)/ldns/sbuffer.h $(srcdir)/ldns/rrdef.h
@@ -894,7 +904,8 @@ unitlruhash.lo unitlruhash.o: $(srcdir)/testcode/unitlruhash.c config.h $(srcdir
$(srcdir)/util/log.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/storage/slabhash.h
unitmain.lo unitmain.o: $(srcdir)/testcode/unitmain.c config.h \
$(srcdir)/ldns/rrdef.h $(srcdir)/ldns/keyraw.h \
- $(srcdir)/util/log.h $(srcdir)/testcode/unitmain.h $(srcdir)/util/alloc.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h \
+ $(srcdir)/util/log.h \
+ $(srcdir)/testcode/unitmain.h $(srcdir)/util/alloc.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h \
$(srcdir)/util/config_file.h $(srcdir)/util/rtt.h $(srcdir)/services/cache/infra.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/random.h
unitmsgparse.lo unitmsgparse.o: $(srcdir)/testcode/unitmsgparse.c config.h $(srcdir)/util/log.h \
@@ -935,19 +946,21 @@ cachedump.lo cachedump.o: $(srcdir)/daemon/cachedump.c config.h \
$(srcdir)/ldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
$(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h $(srcdir)/util/alloc.h \
$(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h \
- $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/services/cache/rrset.h \
- $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/dns.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h \
- $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_delegpt.h \
- $(srcdir)/iterator/iter_utils.h $(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_fwd.h \
- $(srcdir)/util/rbtree.h $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h \
- $(srcdir)/ldns/wire2str.h $(srcdir)/ldns/str2wire.h
+ $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \
+ $(srcdir)/services/cache/dns.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/util/regional.h \
+ $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h $(srcdir)/iterator/iterator.h \
+ $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/iterator/iter_utils.h \
+ $(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/util/rbtree.h \
+ $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h $(srcdir)/ldns/wire2str.h \
+ $(srcdir)/ldns/str2wire.h
daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h \
$(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
- $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/ldns/sbuffer.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/netevent.h \
- $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h \
- $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/daemon/remote.h \
+ $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h \
+ $(srcdir)/ldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
+ $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h \
+ $(srcdir)/ldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
+ $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/remote.h \
$(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/storage/slabhash.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
@@ -959,11 +972,12 @@ remote.lo remote.o: $(srcdir)/daemon/remote.c config.h \
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
$(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
- $(srcdir)/daemon/daemon.h $(srcdir)/services/modstack.h $(srcdir)/daemon/cachedump.h \
- $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/services/listen_dnsport.h \
- $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/localzone.h \
- $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/data/dname.h $(srcdir)/validator/validator.h \
+ $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/daemon.h \
+ $(srcdir)/services/modstack.h $(srcdir)/daemon/cachedump.h $(srcdir)/util/config_file.h \
+ $(srcdir)/util/net_help.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
+ $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/localzone.h $(srcdir)/util/fptr_wlist.h \
+ $(srcdir)/util/tube.h $(srcdir)/util/data/dname.h $(srcdir)/validator/validator.h \
$(srcdir)/validator/val_utils.h $(srcdir)/validator/val_kcache.h $(srcdir)/validator/val_kentry.h \
$(srcdir)/validator/val_anchor.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h \
@@ -973,14 +987,15 @@ stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(s
$(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/ldns/sbuffer.h \
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
- $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/daemon/daemon.h \
- $(srcdir)/services/modstack.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \
- $(srcdir)/services/outside_network.h $(srcdir)/util/config_file.h $(srcdir)/util/tube.h \
- $(srcdir)/util/net_help.h $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h \
- $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/validator/val_kcache.h
+ $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h \
+ $(srcdir)/daemon/daemon.h $(srcdir)/services/modstack.h \
+ $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/outside_network.h \
+ $(srcdir)/util/config_file.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/validator/validator.h \
+ $(srcdir)/validator/val_utils.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \
+ $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/validator/val_kcache.h
unbound.lo unbound.o: $(srcdir)/daemon/unbound.c config.h $(srcdir)/util/log.h $(srcdir)/daemon/daemon.h \
- $(srcdir)/util/locks.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h \
+ $(srcdir)/util/locks.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
+ $(srcdir)/daemon/remote.h \
$(srcdir)/util/config_file.h $(srcdir)/util/storage/slabhash.h $(srcdir)/util/storage/lruhash.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/util/netevent.h $(srcdir)/services/cache/rrset.h \
$(srcdir)/util/data/packed_rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
@@ -993,7 +1008,8 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
$(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
$(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
- $(srcdir)/daemon/daemon.h $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h \
+ $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/daemon.h \
+ $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h \
$(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/config_file.h $(srcdir)/util/regional.h $(srcdir)/util/storage/slabhash.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/services/outside_network.h \
@@ -1008,9 +1024,10 @@ testbound.lo testbound.o: $(srcdir)/testcode/testbound.c config.h $(srcdir)/test
$(srcdir)/daemon/remote.h \
$(srcdir)/util/config_file.h $(srcdir)/ldns/keyraw.h $(srcdir)/daemon/unbound.c $(srcdir)/util/log.h \
$(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
- $(srcdir)/util/storage/slabhash.h $(srcdir)/util/storage/lruhash.h $(srcdir)/services/listen_dnsport.h \
- $(srcdir)/services/cache/rrset.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/util/storage/lruhash.h \
+ $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
+ $(srcdir)/util/fptr_wlist.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
$(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/tube.h \
$(srcdir)/services/mesh.h $(srcdir)/util/net_help.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h
testpkts.lo testpkts.o: $(srcdir)/testcode/testpkts.c config.h $(srcdir)/testcode/testpkts.h \
@@ -1021,7 +1038,8 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
$(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
$(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
- $(srcdir)/daemon/daemon.h $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h \
+ $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/daemon.h \
+ $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h \
$(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/config_file.h $(srcdir)/util/regional.h $(srcdir)/util/storage/slabhash.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/services/outside_network.h \
@@ -1036,10 +1054,11 @@ acl_list.lo acl_list.o: $(srcdir)/daemon/acl_list.c config.h $(srcdir)/daemon/ac
$(srcdir)/util/config_file.h $(srcdir)/util/net_help.h
daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h \
$(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
- $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/ldns/sbuffer.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/netevent.h \
- $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h \
- $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/daemon/remote.h \
+ $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h \
+ $(srcdir)/ldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
+ $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h \
+ $(srcdir)/ldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
+ $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/remote.h \
$(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/storage/slabhash.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
@@ -1049,12 +1068,12 @@ stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(s
$(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/ldns/sbuffer.h \
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
- $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/daemon/daemon.h \
- $(srcdir)/services/modstack.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \
- $(srcdir)/services/outside_network.h $(srcdir)/util/config_file.h $(srcdir)/util/tube.h \
- $(srcdir)/util/net_help.h $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h \
- $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/validator/val_kcache.h
+ $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h \
+ $(srcdir)/daemon/daemon.h $(srcdir)/services/modstack.h \
+ $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/outside_network.h \
+ $(srcdir)/util/config_file.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/validator/validator.h \
+ $(srcdir)/validator/val_utils.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \
+ $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/validator/val_kcache.h
replay.lo replay.o: $(srcdir)/testcode/replay.c config.h $(srcdir)/util/log.h $(srcdir)/util/net_help.h \
$(srcdir)/util/config_file.h $(srcdir)/testcode/replay.h $(srcdir)/util/netevent.h $(srcdir)/testcode/testpkts.h \
$(srcdir)/util/rbtree.h $(srcdir)/testcode/fake_event.h $(srcdir)/ldns/str2wire.h $(srcdir)/ldns/rrdef.h
@@ -1063,10 +1082,10 @@ fake_event.lo fake_event.o: $(srcdir)/testcode/fake_event.c config.h $(srcdir)/t
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h \
$(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgencode.h \
$(srcdir)/util/data/dname.h $(srcdir)/util/config_file.h $(srcdir)/services/listen_dnsport.h \
- $(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/testcode/replay.h $(srcdir)/testcode/testpkts.h $(srcdir)/util/fptr_wlist.h \
- $(srcdir)/util/module.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h \
- $(srcdir)/ldns/sbuffer.h $(srcdir)/ldns/wire2str.h $(srcdir)/ldns/str2wire.h
+ $(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h \
+ $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/testcode/replay.h $(srcdir)/testcode/testpkts.h \
+ $(srcdir)/util/fptr_wlist.h $(srcdir)/util/module.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h \
+ $(srcdir)/services/modstack.h $(srcdir)/ldns/sbuffer.h $(srcdir)/ldns/wire2str.h $(srcdir)/ldns/str2wire.h
lock_verify.lo lock_verify.o: $(srcdir)/testcode/lock_verify.c config.h $(srcdir)/util/log.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/locks.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h $(srcdir)/util/storage/lruhash.h \
$(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
@@ -1118,13 +1137,14 @@ libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h \
$(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h \
$(srcdir)/services/modstack.h $(srcdir)/libunbound/unbound.h $(srcdir)/libunbound/worker.h \
$(srcdir)/ldns/sbuffer.h $(srcdir)/libunbound/unbound-event.h $(srcdir)/services/outside_network.h \
- $(srcdir)/util/netevent.h $(srcdir)/services/mesh.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h \
- $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/services/localzone.h \
- $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/outbound_list.h \
- $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/regional.h $(srcdir)/util/random.h \
- $(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h \
- $(srcdir)/util/data/dname.h $(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h \
- $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h $(srcdir)/ldns/str2wire.h
+ $(srcdir)/util/netevent.h $(srcdir)/services/mesh.h \
+ $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h $(srcdir)/util/module.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/services/localzone.h $(srcdir)/services/cache/rrset.h \
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/services/outbound_list.h $(srcdir)/util/fptr_wlist.h \
+ $(srcdir)/util/tube.h $(srcdir)/util/regional.h $(srcdir)/util/random.h $(srcdir)/util/config_file.h \
+ $(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h \
+ $(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \
+ $(srcdir)/util/storage/dnstree.h $(srcdir)/ldns/str2wire.h
unbound-host.lo unbound-host.o: $(srcdir)/smallapp/unbound-host.c config.h $(srcdir)/libunbound/unbound.h \
$(srcdir)/ldns/rrdef.h $(srcdir)/ldns/wire2str.h
asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libunbound/unbound.h \
@@ -1144,7 +1164,8 @@ perf.lo perf.o: $(srcdir)/testcode/perf.c config.h $(srcdir)/util/log.h $(srcdir
delayer.lo delayer.o: $(srcdir)/testcode/delayer.c config.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h \
$(srcdir)/util/config_file.h $(srcdir)/ldns/sbuffer.h
unbound-control.lo unbound-control.o: $(srcdir)/smallapp/unbound-control.c config.h \
- $(srcdir)/util/log.h $(srcdir)/util/config_file.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h
+ $(srcdir)/util/log.h \
+ $(srcdir)/util/config_file.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h
unbound-anchor.lo unbound-anchor.o: $(srcdir)/smallapp/unbound-anchor.c config.h $(srcdir)/libunbound/unbound.h \
$(srcdir)/ldns/rrdef.h \
@@ -1155,13 +1176,14 @@ pythonmod_utils.lo pythonmod_utils.o: $(srcdir)/pythonmod/pythonmod_utils.c conf
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h \
$(srcdir)/util/netevent.h $(srcdir)/util/net_help.h $(srcdir)/services/cache/dns.h \
$(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/util/regional.h \
- $(srcdir)/ldns/sbuffer.h
+ $(srcdir)/iterator/iter_delegpt.h $(srcdir)/ldns/sbuffer.h
win_svc.lo win_svc.o: $(srcdir)/winrc/win_svc.c config.h $(srcdir)/winrc/win_svc.h $(srcdir)/winrc/w_inst.h \
$(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
- $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/ldns/sbuffer.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/netevent.h \
- $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h $(srcdir)/ldns/rrdef.h \
- $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/daemon/remote.h \
+ $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h \
+ $(srcdir)/ldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
+ $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/ldns/pkthdr.h \
+ $(srcdir)/ldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
+ $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/remote.h \
$(srcdir)/util/config_file.h $(srcdir)/util/winsock_event.h
w_inst.lo w_inst.o: $(srcdir)/winrc/w_inst.c config.h $(srcdir)/winrc/w_inst.h $(srcdir)/winrc/win_svc.h
unbound-service-install.lo unbound-service-install.o: $(srcdir)/winrc/unbound-service-install.c config.h \
diff --git a/contrib/unbound/compat/getentropy_linux.c b/contrib/unbound/compat/getentropy_linux.c
index 32d58a7..d4adab2 100644
--- a/contrib/unbound/compat/getentropy_linux.c
+++ b/contrib/unbound/compat/getentropy_linux.c
@@ -93,6 +93,13 @@ getentropy(void *buf, size_t len)
return -1;
}
+#ifdef SYS_getrandom
+ /* try to use getrandom syscall introduced with kernel 3.17 */
+ ret = syscall(SYS_getrandom, buf, len, 0);
+ if (ret != -1)
+ return (ret);
+#endif /* SYS_getrandom */
+
/*
* Try to get entropy with /dev/urandom
*
@@ -474,22 +481,24 @@ getentropy_fallback(void *buf, size_t len)
HD(cnt);
}
-#ifdef AT_RANDOM
+#ifdef HAVE_GETAUXVAL
+# ifdef AT_RANDOM
/* Not as random as you think but we take what we are given */
p = (char *) getauxval(AT_RANDOM);
if (p)
HR(p, 16);
-#endif
-#ifdef AT_SYSINFO_EHDR
+# endif
+# ifdef AT_SYSINFO_EHDR
p = (char *) getauxval(AT_SYSINFO_EHDR);
if (p)
HR(p, pgs);
-#endif
-#ifdef AT_BASE
+# endif
+# ifdef AT_BASE
p = (char *) getauxval(AT_BASE);
if (p)
HD(p);
-#endif
+# endif
+#endif /* HAVE_GETAUXVAL */
SHA512_Final(results, &ctx);
memcpy((char*)buf + i, results, min(sizeof(results), len - i));
diff --git a/contrib/unbound/config.h b/contrib/unbound/config.h
index 8c93eb4..641ddd3 100644
--- a/contrib/unbound/config.h
+++ b/contrib/unbound/config.h
@@ -43,7 +43,7 @@
/* Whether the C compiler accepts the "unused" attribute */
#define HAVE_ATTR_UNUSED 1
-/* Define to 1 if your system has a working `chown' function. */
+/* Define to 1 if you have the `chown' function. */
#define HAVE_CHOWN 1
/* Define to 1 if you have the `chroot' function. */
@@ -147,6 +147,9 @@
/* Whether getaddrinfo is available */
#define HAVE_GETADDRINFO 1
+/* Define to 1 if you have the `getauxval' function. */
+/* #undef HAVE_GETAUXVAL */
+
/* Define to 1 if you have the `getentropy' function. */
/* #undef HAVE_GETENTROPY */
@@ -483,7 +486,7 @@
#define PACKAGE_NAME "unbound"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "unbound 1.5.1"
+#define PACKAGE_STRING "unbound 1.5.3"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "unbound"
@@ -492,7 +495,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.5.1"
+#define PACKAGE_VERSION "1.5.3"
/* default pidfile location */
#define PIDFILE "/var/unbound/unbound.pid"
@@ -511,7 +514,7 @@
#define ROOT_CERT_FILE "/var/unbound/icannbundle.pem"
/* version number for resource files */
-#define RSRC_PACKAGE_VERSION 1,5,1,0
+#define RSRC_PACKAGE_VERSION 1,5,3,0
/* Directory to chdir to */
#define RUN_DIR "/var/unbound"
@@ -800,6 +803,10 @@
#define ARG_LL "%I64"
#endif
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
#ifdef HAVE_ATTR_FORMAT
diff --git a/contrib/unbound/config.h.in b/contrib/unbound/config.h.in
index a8fd05c..c36d4b9 100644
--- a/contrib/unbound/config.h.in
+++ b/contrib/unbound/config.h.in
@@ -42,7 +42,7 @@
/* Whether the C compiler accepts the "unused" attribute */
#undef HAVE_ATTR_UNUSED
-/* Define to 1 if your system has a working `chown' function. */
+/* Define to 1 if you have the `chown' function. */
#undef HAVE_CHOWN
/* Define to 1 if you have the `chroot' function. */
@@ -146,6 +146,9 @@
/* Whether getaddrinfo is available */
#undef HAVE_GETADDRINFO
+/* Define to 1 if you have the `getauxval' function. */
+#undef HAVE_GETAUXVAL
+
/* Define to 1 if you have the `getentropy' function. */
#undef HAVE_GETENTROPY
@@ -799,6 +802,10 @@
#define ARG_LL "%I64"
#endif
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
#ifdef HAVE_ATTR_FORMAT
diff --git a/contrib/unbound/configure b/contrib/unbound/configure
index 8c6c078..20ff33d 100755
--- a/contrib/unbound/configure
+++ b/contrib/unbound/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for unbound 1.5.1.
+# Generated by GNU Autoconf 2.69 for unbound 1.5.3.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
-PACKAGE_VERSION='1.5.1'
-PACKAGE_STRING='unbound 1.5.1'
+PACKAGE_VERSION='1.5.3'
+PACKAGE_STRING='unbound 1.5.3'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl'
PACKAGE_URL=''
@@ -733,6 +733,7 @@ UNBOUND_PIDFILE
UNBOUND_SHARE_DIR
UNBOUND_CHROOT_DIR
UNBOUND_RUN_DIR
+ub_conf_dir
ub_conf_file
EGREP
GREP
@@ -1387,7 +1388,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 unbound 1.5.1 to adapt to many kinds of systems.
+\`configure' configures unbound 1.5.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1452,7 +1453,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of unbound 1.5.1:";;
+ short | recursive ) echo "Configuration of unbound 1.5.3:";;
esac
cat <<\_ACEOF
@@ -1627,7 +1628,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-unbound configure 1.5.1
+unbound configure 1.5.3
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2336,7 +2337,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 unbound $as_me 1.5.1, which was
+It was created by unbound $as_me 1.5.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2688,11 +2689,11 @@ UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=5
-UNBOUND_VERSION_MICRO=1
+UNBOUND_VERSION_MICRO=3
LIBUNBOUND_CURRENT=5
-LIBUNBOUND_REVISION=3
+LIBUNBOUND_REVISION=6
LIBUNBOUND_AGE=3
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -2732,7 +2733,9 @@ LIBUNBOUND_AGE=3
# 1.4.21 had 4:1:2
# 1.4.22 had 4:1:2
# 1.5.0 had 5:3:3 # adds ub_ctx_add_ta_autr
-# 1.5.1 had 5:4:3
+# 1.5.1 had 5:3:3
+# 1.5.2 had 5:5:3
+# 1.5.3 had 5:6:3
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -4047,6 +4050,30 @@ cat >>confdefs.h <<_ACEOF
#define CONFIGFILE "$hdr_config"
_ACEOF
+ub_conf_dir=`$as_dirname -- "$ub_conf_file" ||
+$as_expr X"$ub_conf_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ub_conf_file" : 'X\(//\)[^/]' \| \
+ X"$ub_conf_file" : 'X\(//\)$' \| \
+ X"$ub_conf_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ub_conf_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
# Determine run, chroot directory and pidfile locations
@@ -17932,7 +17959,7 @@ if test "$ac_res" != no; then :
fi
-for ac_func in tzset sigprocmask fcntl getpwnam getrlimit setrlimit setsid sbrk chroot kill sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent
+for ac_func in tzset sigprocmask fcntl getpwnam getrlimit setrlimit setsid sbrk chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -18227,6 +18254,62 @@ done
# this lib needed for sha2 on solaris
LIBS="$LIBS -lmd"
fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+$as_echo_n "checking for library containing clock_gettime... " >&6; }
+if ${ac_cv_search_clock_gettime+:} 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 clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' rt; 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_clock_gettime=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_clock_gettime+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_clock_gettime+:} false; then :
+
+else
+ ac_cv_search_clock_gettime=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+$as_echo "$ac_cv_search_clock_gettime" >&6; }
+ac_res=$ac_cv_search_clock_gettime
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
;;
Linux|*)
case " $LIBOBJS " in
@@ -18271,6 +18354,17 @@ fi
done
+ for ac_func in getauxval
+do :
+ ac_fn_c_check_func "$LINENO" "getauxval" "ac_cv_func_getauxval"
+if test "x$ac_cv_func_getauxval" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETAUXVAL 1
+_ACEOF
+
+fi
+done
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
$as_echo_n "checking for library containing clock_gettime... " >&6; }
if ${ac_cv_search_clock_gettime+:} false; then :
@@ -18768,7 +18862,7 @@ _ACEOF
-version=1.5.1
+version=1.5.3
date=`date +'%b %e, %Y'`
@@ -19283,7 +19377,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 unbound $as_me 1.5.1, which was
+This file was extended by unbound $as_me 1.5.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -19349,7 +19443,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="\\
-unbound config.status 1.5.1
+unbound config.status 1.5.3
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/contrib/unbound/configure.ac b/contrib/unbound/configure.ac
index e06c1d6..ae0525b 100644
--- a/contrib/unbound/configure.ac
+++ b/contrib/unbound/configure.ac
@@ -10,14 +10,14 @@ sinclude(dnstap/dnstap.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
m4_define([VERSION_MINOR],[5])
-m4_define([VERSION_MICRO],[1])
+m4_define([VERSION_MICRO],[3])
AC_INIT(unbound, m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]), unbound-bugs@nlnetlabs.nl, unbound)
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=5
-LIBUNBOUND_REVISION=3
+LIBUNBOUND_REVISION=6
LIBUNBOUND_AGE=3
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -57,7 +57,9 @@ LIBUNBOUND_AGE=3
# 1.4.21 had 4:1:2
# 1.4.22 had 4:1:2
# 1.5.0 had 5:3:3 # adds ub_ctx_add_ta_autr
-# 1.5.1 had 5:4:3
+# 1.5.1 had 5:3:3
+# 1.5.2 had 5:5:3
+# 1.5.3 had 5:6:3
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -118,6 +120,8 @@ AC_ARG_WITH([conf_file],
AC_SUBST(ub_conf_file)
ACX_ESCAPE_BACKSLASH($ub_conf_file, hdr_config)
AC_DEFINE_UNQUOTED(CONFIGFILE, ["$hdr_config"], [Pathname to the Unbound configuration file])
+ub_conf_dir=`AS_DIRNAME(["$ub_conf_file"])`
+AC_SUBST(ub_conf_dir)
# Determine run, chroot directory and pidfile locations
AC_ARG_WITH(run-dir,
@@ -975,7 +979,7 @@ AC_INCLUDES_DEFAULT
#endif
])
AC_SEARCH_LIBS([setusercontext], [util])
-AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam getrlimit setrlimit setsid sbrk chroot kill sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent])
+AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam getrlimit setrlimit setsid sbrk chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent])
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])
@@ -1018,6 +1022,7 @@ if test "$USE_NSS" = "no"; then
# this lib needed for sha2 on solaris
LIBS="$LIBS -lmd"
fi
+ AC_SEARCH_LIBS([clock_gettime], [rt])
;;
Linux|*)
AC_LIBOBJ(getentropy_linux)
@@ -1026,6 +1031,7 @@ if test "$USE_NSS" = "no"; then
AC_LIBOBJ(sha512)
])
AC_CHECK_HEADERS([sys/sysctl.h],,, [AC_INCLUDES_DEFAULT])
+ AC_CHECK_FUNCS([getauxval])
AC_SEARCH_LIBS([clock_gettime], [rt])
;;
esac
@@ -1211,6 +1217,10 @@ dnl includes
#else
#define ARG_LL "%I64"
#endif
+
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
]
AHX_CONFIG_FORMAT_ATTRIBUTE
diff --git a/contrib/unbound/daemon/remote.c b/contrib/unbound/daemon/remote.c
index a5be6d6..3ce55ee 100644
--- a/contrib/unbound/daemon/remote.c
+++ b/contrib/unbound/daemon/remote.c
@@ -327,9 +327,14 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
* group as the user we run as.
*/
if(fd != -1) {
- if (cfg->username && cfg->username[0])
- chown(ip, cfg->uid, cfg->gid);
+#ifdef HAVE_CHOWN
+ if (cfg->username && cfg->username[0] &&
+ cfg_uid != (uid_t)-1)
+ chown(ip, cfg_uid, cfg_gid);
chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
+#else
+ (void)cfg;
+#endif
}
} else {
hints.ai_socktype = SOCK_STREAM;
diff --git a/contrib/unbound/daemon/unbound.c b/contrib/unbound/daemon/unbound.c
index a31b039..8e07c38 100644
--- a/contrib/unbound/daemon/unbound.c
+++ b/contrib/unbound/daemon/unbound.c
@@ -503,26 +503,28 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
#ifdef HAVE_KILL
if(cfg->pidfile && cfg->pidfile[0]) {
writepid(daemon->pidfile, getpid());
- if(cfg->username && cfg->username[0]) {
- if(chown(daemon->pidfile, cfg->uid, cfg->gid) == -1) {
+ if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
+# ifdef HAVE_CHOWN
+ if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) {
log_err("cannot chown %u.%u %s: %s",
- (unsigned)cfg->uid, (unsigned)cfg->gid,
+ (unsigned)cfg_uid, (unsigned)cfg_gid,
daemon->pidfile, strerror(errno));
}
+# endif /* HAVE_CHOWN */
}
}
#else
(void)daemon;
-#endif
+#endif /* HAVE_KILL */
/* Set user context */
#ifdef HAVE_GETPWNAM
- if(cfg->username && cfg->username[0]) {
+ if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
#ifdef HAVE_SETUSERCONTEXT
/* setusercontext does initgroups, setuid, setgid, and
* also resource limits from login config, but we
* still call setresuid, setresgid to be sure to set all uid*/
- if(setusercontext(NULL, pwd, cfg->uid, (unsigned)
+ if(setusercontext(NULL, pwd, cfg_uid, (unsigned)
LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0)
log_warn("unable to setusercontext %s: %s",
cfg->username, strerror(errno));
@@ -584,29 +586,29 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
/* drop permissions after chroot, getpwnam, pidfile, syslog done*/
#ifdef HAVE_GETPWNAM
- if(cfg->username && cfg->username[0]) {
+ if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
# ifdef HAVE_INITGROUPS
- if(initgroups(cfg->username, cfg->gid) != 0)
+ if(initgroups(cfg->username, cfg_gid) != 0)
log_warn("unable to initgroups %s: %s",
cfg->username, strerror(errno));
# endif /* HAVE_INITGROUPS */
endpwent();
#ifdef HAVE_SETRESGID
- if(setresgid(cfg->gid,cfg->gid,cfg->gid) != 0)
+ if(setresgid(cfg_gid,cfg_gid,cfg_gid) != 0)
#elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID)
- if(setregid(cfg->gid,cfg->gid) != 0)
+ if(setregid(cfg_gid,cfg_gid) != 0)
#else /* use setgid */
- if(setgid(cfg->gid) != 0)
+ if(setgid(cfg_gid) != 0)
#endif /* HAVE_SETRESGID */
fatal_exit("unable to set group id of %s: %s",
cfg->username, strerror(errno));
#ifdef HAVE_SETRESUID
- if(setresuid(cfg->uid,cfg->uid,cfg->uid) != 0)
+ if(setresuid(cfg_uid,cfg_uid,cfg_uid) != 0)
#elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID)
- if(setreuid(cfg->uid,cfg->uid) != 0)
+ if(setreuid(cfg_uid,cfg_uid) != 0)
#else /* use setuid */
- if(setuid(cfg->uid) != 0)
+ if(setuid(cfg_uid) != 0)
#endif /* HAVE_SETRESUID */
fatal_exit("unable to set user id of %s: %s",
cfg->username, strerror(errno));
@@ -651,7 +653,8 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode)
log_warn("Continuing with default config settings");
}
apply_settings(daemon, cfg, cmdline_verbose, debug_mode);
- config_lookup_uid(cfg);
+ if(!done_setup)
+ config_lookup_uid(cfg);
/* prepare */
if(!daemon_open_shared_ports(daemon))
diff --git a/contrib/unbound/daemon/worker.c b/contrib/unbound/daemon/worker.c
index 59ae9df..5edc21d 100644
--- a/contrib/unbound/daemon/worker.c
+++ b/contrib/unbound/daemon/worker.c
@@ -900,7 +900,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
goto send_reply;
}
if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
- c->buffer, worker->scratchpad)) {
+ c->buffer, worker->scratchpad, repinfo)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
diff --git a/contrib/unbound/doc/Changelog b/contrib/unbound/doc/Changelog
index 1bd19f1..a1c2f76 100644
--- a/contrib/unbound/doc/Changelog
+++ b/contrib/unbound/doc/Changelog
@@ -1,12 +1,112 @@
-8 December 2014: Wouter
- - Fix CVE-2014-8602: denial of service by making resolver chase
- endless series of delegations.
+23 March 2015: Wouter
+ - Fix segfault on user not found at startup (from Maciej Soltysiak).
+
+2 March 2015: Wouter
+ - iana portlist update.
+
+20 February 2015: Wouter
+ - Use the getrandom syscall introduced in Linux 3.17 (from Heiner
+ Kallweit).
+ - Fix #645 Portability to Solaris 10, use AF_LOCAL.
+ - Fix #646 Portability to Solaris, -lrt for getentropy_solaris.
+ - Fix #647 crash in 1.5.2 because pwd.db no longer accessible after
+ reload.
+
+19 February 2015: Wouter
+ - 1.5.2 release tag.
+ - svn trunk contains 1.5.3 under development.
+
+13 February 2015: Wouter
+ - Fix #643: doc/example.conf.in: unnecessary whitespace.
+
+12 February 2015: Wouter
+ - tag 1.5.2rc1
+
+11 February 2015: Wouter
+ - iana portlist update.
+
+10 February 2015: Wouter
+ - Fix scrubber with harden-glue turned off to reject NS (and other
+ not-address) records.
+
+9 February 2015: Wouter
+ - Fix validation failure in case upstream forwarder (ISC BIND) does
+ not have the same trust anchors and decides to insert unsigned NS
+ record in authority section.
+
+2 February 2015: Wouter
+ - infra-cache-min-rtt patch from Florian Riehm, for expected long
+ uplink roundtrip times.
+
+30 January 2015: Wouter
+ - Fix 0x20 capsforid fallback to omit gratuitous NS and additional
+ section changes.
+ - Portability fix for Solaris ('sun' is not usable for a variable).
+
+29 January 2015: Wouter
+ - Fix pyunbound byte string representation for python3.
+
+26 January 2015: Wouter
+ - Fix unintended use of gcc extension for incomplete enum types,
+ compile with pedantic c99 compliance (from Daniel Dickman).
+
+23 January 2015: Wouter
+ - windows port fixes, no AF_LOCAL, no chown, no chmod(grp).
+
+16 January 2015: Wouter
+ - unit test for local unix connection. Documentation and log_addr
+ does not inspect port for AF_LOCAL.
+ - unbound-checkconf -f prints chroot with pidfile path.
+
+13 January 2015: Wouter
+ - iana portlist update.
+
+12 January 2015: Wouter
+ - Cast sun_len sizeof to socklen_t.
+ - Fix pyunbound ord call, portable for python 2 and 3.
+
+7 January 2015: Wouter
+ - Fix warnings in pythonmod changes.
+
+6 January 2015: Wouter
+ - iana portlist update.
- patch for remote control over local sockets, from Dag-Erling
Smorgrav, Ilya Bakulin. Use control-interface: /path/sock and
control-use-cert: no.
- Fixup that patch and uid lookup (only for daemon).
- coded the default of control-use-cert, to yes.
+5 January 2015: Wouter
+ - getauxval test for ppc64 linux compatibility.
+ - make strip works for unbound-host and unbound-anchor.
+ - patch from Stephane Lapie that adds to the python API, that
+ exposes struct delegpt, and adds the find_delegation function.
+ - print query name when max target count is exceeded.
+ - patch from Stuart Henderson that fixes DESTDIR in
+ unbound-control-setup for installs where config is not in
+ the prefix location.
+ - Fix #634: fix fail to start on Linux LTS 3.14.X, ignores missing
+ IP_MTU_DISCOVER OMIT option (fix from Remi Gacogne).
+ - Updated contrib warmup.cmd/sh to support two modes - load
+ from pre-defined list of domains or (with filename as argument)
+ load from user-specified list of domains, and updated contrib
+ unbound_cache.sh/cmd to support loading/save/reload cache to/from
+ default path or (with secondary argument) arbitrary path/filename,
+ from Yuri Voinov.
+ - Patch from Philip Paeps to contrib/unbound_munin_ that uses
+ type ABSOLUTE. Allows munin.conf: [idleserver.example.net]
+ unbound_munin_hits.graph_period minute
+
+9 December 2014: Wouter
+ - svn trunk has 1.5.2 in development.
+ - config.guess and config.sub update from libtoolize.
+ - local-zone: example.com inform makes unbound log a message with
+ client IP for queries in that zone. Eg. for finding infected hosts.
+
+8 December 2014: Wouter
+ - Fix CVE-2014-8602: denial of service by making resolver chase
+ endless series of delegations.
+
1 December 2014: Wouter
- Fix bug#632: unbound fails to build on AArch64, protects
getentropy compat code from calling sysctl if it is has been removed.
diff --git a/contrib/unbound/doc/README b/contrib/unbound/doc/README
index df92fcc..f3530d6 100644
--- a/contrib/unbound/doc/README
+++ b/contrib/unbound/doc/README
@@ -1,4 +1,4 @@
-README for Unbound 1.5.1
+README for Unbound 1.5.3
Copyright 2007 NLnet Labs
http://unbound.net
diff --git a/contrib/unbound/doc/example.conf b/contrib/unbound/doc/example.conf
index 945e9e3..acb553b 100644
--- a/contrib/unbound/doc/example.conf
+++ b/contrib/unbound/doc/example.conf
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
-# See unbound.conf(5) man page, version 1.5.1.
+# See unbound.conf(5) man page, version 1.5.3.
#
# this is a comment.
@@ -138,6 +138,9 @@ server:
# the time to live (TTL) value for cached roundtrip times, lameness and
# EDNS version information for hosts. In seconds.
# infra-host-ttl: 900
+
+ # minimum wait time for responses, increase if uplink is long. In msec.
+ # infra-cache-min-rtt: 50
# the number of slabs to use for the Infrastructure cache.
# the number of slabs must be a power of 2.
@@ -437,7 +440,7 @@ server:
# the amount of memory to use for the negative cache (used for DLV).
# plain value in bytes or you can append k, m or G. default is "1Mb".
# neg-cache-size: 1m
-
+
# By default, for a number of zones a small default 'nothing here'
# reply is built-in. Query traffic is thus blocked. If you
# wish to serve such zone you can unblock them by uncommenting one
@@ -497,6 +500,7 @@ server:
# o redirect serves the zone data for any subdomain in the zone.
# o nodefault can be used to normally resolve AS112 zones.
# o typetransparent resolves normally for other types and other names
+ # o inform resolves normally, but logs client IP address
#
# defaults are localhost address, reverse for 127.0.0.1 and ::1
# and nxdomain for AS112 zones. If you configure one of these zones
@@ -552,6 +556,10 @@ remote-control:
# set up the keys and certificates with unbound-control-setup.
# control-enable: no
+ # Set to no and use an absolute path as control-interface to use
+ # a unix local named pipe for unbound-control.
+ # control-use-cert: yes
+
# what interfaces are listened to for remote control.
# give 0.0.0.0 and ::0 to listen to all interfaces.
# control-interface: 127.0.0.1
diff --git a/contrib/unbound/doc/example.conf.in b/contrib/unbound/doc/example.conf.in
index b95b3a6..60ed5c8 100644
--- a/contrib/unbound/doc/example.conf.in
+++ b/contrib/unbound/doc/example.conf.in
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
-# See unbound.conf(5) man page, version 1.5.1.
+# See unbound.conf(5) man page, version 1.5.3.
#
# this is a comment.
@@ -138,6 +138,9 @@ server:
# the time to live (TTL) value for cached roundtrip times, lameness and
# EDNS version information for hosts. In seconds.
# infra-host-ttl: 900
+
+ # minimum wait time for responses, increase if uplink is long. In msec.
+ # infra-cache-min-rtt: 50
# the number of slabs to use for the Infrastructure cache.
# the number of slabs must be a power of 2.
@@ -437,7 +440,7 @@ server:
# the amount of memory to use for the negative cache (used for DLV).
# plain value in bytes or you can append k, m or G. default is "1Mb".
# neg-cache-size: 1m
-
+
# By default, for a number of zones a small default 'nothing here'
# reply is built-in. Query traffic is thus blocked. If you
# wish to serve such zone you can unblock them by uncommenting one
@@ -497,6 +500,7 @@ server:
# o redirect serves the zone data for any subdomain in the zone.
# o nodefault can be used to normally resolve AS112 zones.
# o typetransparent resolves normally for other types and other names
+ # o inform resolves normally, but logs client IP address
#
# defaults are localhost address, reverse for 127.0.0.1 and ::1
# and nxdomain for AS112 zones. If you configure one of these zones
@@ -552,6 +556,10 @@ remote-control:
# set up the keys and certificates with unbound-control-setup.
# control-enable: no
+ # Set to no and use an absolute path as control-interface to use
+ # a unix local named pipe for unbound-control.
+ # control-use-cert: yes
+
# what interfaces are listened to for remote control.
# give 0.0.0.0 and ::0 to listen to all interfaces.
# control-interface: 127.0.0.1
diff --git a/contrib/unbound/doc/libunbound.3 b/contrib/unbound/doc/libunbound.3
index 55a9cb2..a4c7945 100644
--- a/contrib/unbound/doc/libunbound.3
+++ b/contrib/unbound/doc/libunbound.3
@@ -1,4 +1,4 @@
-.TH "libunbound" "3" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "libunbound" "3" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" libunbound.3 -- unbound library functions manual
.\"
@@ -42,7 +42,7 @@
.B ub_ctx_zone_remove,
.B ub_ctx_data_add,
.B ub_ctx_data_remove
-\- Unbound DNS validating resolver 1.5.1 functions.
+\- Unbound DNS validating resolver 1.5.3 functions.
.SH "SYNOPSIS"
.B #include <unbound.h>
.LP
diff --git a/contrib/unbound/doc/libunbound.3.in b/contrib/unbound/doc/libunbound.3.in
index 55a9cb2..a4c7945 100644
--- a/contrib/unbound/doc/libunbound.3.in
+++ b/contrib/unbound/doc/libunbound.3.in
@@ -1,4 +1,4 @@
-.TH "libunbound" "3" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "libunbound" "3" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" libunbound.3 -- unbound library functions manual
.\"
@@ -42,7 +42,7 @@
.B ub_ctx_zone_remove,
.B ub_ctx_data_add,
.B ub_ctx_data_remove
-\- Unbound DNS validating resolver 1.5.1 functions.
+\- Unbound DNS validating resolver 1.5.3 functions.
.SH "SYNOPSIS"
.B #include <unbound.h>
.LP
diff --git a/contrib/unbound/doc/unbound-anchor.8 b/contrib/unbound/doc/unbound-anchor.8
index a001620..3682d8f 100644
--- a/contrib/unbound/doc/unbound-anchor.8
+++ b/contrib/unbound/doc/unbound-anchor.8
@@ -1,4 +1,4 @@
-.TH "unbound-anchor" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound-anchor" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\"
diff --git a/contrib/unbound/doc/unbound-anchor.8.in b/contrib/unbound/doc/unbound-anchor.8.in
index 80a3438d..fb2136f 100644
--- a/contrib/unbound/doc/unbound-anchor.8.in
+++ b/contrib/unbound/doc/unbound-anchor.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-anchor" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound-anchor" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\"
diff --git a/contrib/unbound/doc/unbound-checkconf.8 b/contrib/unbound/doc/unbound-checkconf.8
index 3da7ec0..d2b659e 100644
--- a/contrib/unbound/doc/unbound-checkconf.8
+++ b/contrib/unbound/doc/unbound-checkconf.8
@@ -1,4 +1,4 @@
-.TH "unbound-checkconf" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound-checkconf" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-checkconf.8 -- unbound configuration checker manual
.\"
@@ -13,6 +13,7 @@ unbound\-checkconf
.SH "SYNOPSIS"
.B unbound\-checkconf
.RB [ \-h ]
+.RB [ \-f ]
.RB [ \-o
.IR option ]
.RI [ cfgfile ]
@@ -29,6 +30,9 @@ The available options are:
.B \-h
Show the version and commandline option help.
.TP
+.B \-f
+Print full pathname, with chroot applied to it. Use with the -o option.
+.TP
.B \-o\fI option
If given, after checking the config file the value of this option is
printed to stdout. For "" (disabled) options an empty line is printed.
diff --git a/contrib/unbound/doc/unbound-checkconf.8.in b/contrib/unbound/doc/unbound-checkconf.8.in
index 5ab5348..e7db810 100644
--- a/contrib/unbound/doc/unbound-checkconf.8.in
+++ b/contrib/unbound/doc/unbound-checkconf.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-checkconf" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound-checkconf" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-checkconf.8 -- unbound configuration checker manual
.\"
@@ -13,6 +13,7 @@ unbound\-checkconf
.SH "SYNOPSIS"
.B unbound\-checkconf
.RB [ \-h ]
+.RB [ \-f ]
.RB [ \-o
.IR option ]
.RI [ cfgfile ]
@@ -29,6 +30,9 @@ The available options are:
.B \-h
Show the version and commandline option help.
.TP
+.B \-f
+Print full pathname, with chroot applied to it. Use with the -o option.
+.TP
.B \-o\fI option
If given, after checking the config file the value of this option is
printed to stdout. For "" (disabled) options an empty line is printed.
diff --git a/contrib/unbound/doc/unbound-control.8 b/contrib/unbound/doc/unbound-control.8
index e768fa9..e6228b7 100644
--- a/contrib/unbound/doc/unbound-control.8
+++ b/contrib/unbound/doc/unbound-control.8
@@ -1,4 +1,4 @@
-.TH "unbound-control" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound-control" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-control.8 -- unbound remote control manual
.\"
diff --git a/contrib/unbound/doc/unbound-control.8.in b/contrib/unbound/doc/unbound-control.8.in
index 92d2d1a..f6eae24 100644
--- a/contrib/unbound/doc/unbound-control.8.in
+++ b/contrib/unbound/doc/unbound-control.8.in
@@ -1,4 +1,4 @@
-.TH "unbound-control" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound-control" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-control.8 -- unbound remote control manual
.\"
diff --git a/contrib/unbound/doc/unbound-host.1 b/contrib/unbound/doc/unbound-host.1
index 0bd194e..bda99ce 100644
--- a/contrib/unbound/doc/unbound-host.1
+++ b/contrib/unbound/doc/unbound-host.1
@@ -1,4 +1,4 @@
-.TH "unbound\-host" "1" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound\-host" "1" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-host.1 -- unbound DNS lookup utility
.\"
diff --git a/contrib/unbound/doc/unbound-host.1.in b/contrib/unbound/doc/unbound-host.1.in
index d9e92bb..9129bea 100644
--- a/contrib/unbound/doc/unbound-host.1.in
+++ b/contrib/unbound/doc/unbound-host.1.in
@@ -1,4 +1,4 @@
-.TH "unbound\-host" "1" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound\-host" "1" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound-host.1 -- unbound DNS lookup utility
.\"
diff --git a/contrib/unbound/doc/unbound.8 b/contrib/unbound/doc/unbound.8
index f9c5b6a..8609a0a 100644
--- a/contrib/unbound/doc/unbound.8
+++ b/contrib/unbound/doc/unbound.8
@@ -1,4 +1,4 @@
-.TH "unbound" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound.8 -- unbound manual
.\"
@@ -9,7 +9,7 @@
.\"
.SH "NAME"
.B unbound
-\- Unbound DNS validating resolver 1.5.1.
+\- Unbound DNS validating resolver 1.5.3.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]
diff --git a/contrib/unbound/doc/unbound.8.in b/contrib/unbound/doc/unbound.8.in
index 3b74a32..7242469 100644
--- a/contrib/unbound/doc/unbound.8.in
+++ b/contrib/unbound/doc/unbound.8.in
@@ -1,4 +1,4 @@
-.TH "unbound" "8" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound" "8" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound.8 -- unbound manual
.\"
@@ -9,7 +9,7 @@
.\"
.SH "NAME"
.B unbound
-\- Unbound DNS validating resolver 1.5.1.
+\- Unbound DNS validating resolver 1.5.3.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]
diff --git a/contrib/unbound/doc/unbound.conf.5 b/contrib/unbound/doc/unbound.conf.5
index f5a4471..c2637aa 100644
--- a/contrib/unbound/doc/unbound.conf.5
+++ b/contrib/unbound/doc/unbound.conf.5
@@ -1,4 +1,4 @@
-.TH "unbound.conf" "5" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound.conf" "5" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound.conf.5 -- unbound.conf manual
.\"
@@ -301,6 +301,11 @@ by threads. Must be set to a power of 2.
.B infra\-cache\-numhosts: \fI<number>
Number of hosts for which information is cached. Default is 10000.
.TP
+.B infra\-cache\-min\-rtt: \fI<msec>
+Lower limit for dynamic retransmit timeout calculation in infrastructure
+cache. Default is 50 milliseconds. Increase this value if using forwarders
+needing more time to do recursive name resolution.
+.TP
.B do\-ip4: \fI<yes or no>
Enable or disable whether ip4 queries are answered or issued. Default is yes.
.TP
@@ -791,7 +796,7 @@ data leakage about the local network to the upstream DNS servers.
.B local\-zone: \fI<zone> <type>
Configure a local zone. The type determines the answer to give if
there is no match from local\-data. The types are deny, refuse, static,
-transparent, redirect, nodefault, typetransparent, and are explained
+transparent, redirect, nodefault, typetransparent, inform, and are explained
below. After that the default settings are listed. Use local\-data: to
enter data into the local zone. Answers for local zones are authoritative
DNS answers. By default the zones are class IN.
@@ -841,6 +846,13 @@ local\-data: "example.com. A 127.0.0.1"
queries for www.example.com and www.foo.example.com are redirected, so
that users with web browsers cannot access sites with suffix example.com.
.TP 10
+\h'5'\fIinform\fR
+The query is answered normally. The client IP address (@portnumber)
+is printed to the logfile. The log message is: timestamp, unbound-pid,
+info: zonename inform IP@port queryname type class. This option can be
+used for normal resolution, but machines looking up infected names are
+logged, eg. to run antivirus on them.
+.TP 10
\h'5'\fInodefault\fR
Used to turn off default contents for AS112 zones. The other types
also turn off default contents for the zone. The 'nodefault' option
diff --git a/contrib/unbound/doc/unbound.conf.5.in b/contrib/unbound/doc/unbound.conf.5.in
index d4420e2..9b088f3 100644
--- a/contrib/unbound/doc/unbound.conf.5.in
+++ b/contrib/unbound/doc/unbound.conf.5.in
@@ -1,4 +1,4 @@
-.TH "unbound.conf" "5" "Dec 8, 2014" "NLnet Labs" "unbound 1.5.1"
+.TH "unbound.conf" "5" "Mar 10, 2015" "NLnet Labs" "unbound 1.5.3"
.\"
.\" unbound.conf.5 -- unbound.conf manual
.\"
@@ -301,6 +301,11 @@ by threads. Must be set to a power of 2.
.B infra\-cache\-numhosts: \fI<number>
Number of hosts for which information is cached. Default is 10000.
.TP
+.B infra\-cache\-min\-rtt: \fI<msec>
+Lower limit for dynamic retransmit timeout calculation in infrastructure
+cache. Default is 50 milliseconds. Increase this value if using forwarders
+needing more time to do recursive name resolution.
+.TP
.B do\-ip4: \fI<yes or no>
Enable or disable whether ip4 queries are answered or issued. Default is yes.
.TP
@@ -791,7 +796,7 @@ data leakage about the local network to the upstream DNS servers.
.B local\-zone: \fI<zone> <type>
Configure a local zone. The type determines the answer to give if
there is no match from local\-data. The types are deny, refuse, static,
-transparent, redirect, nodefault, typetransparent, and are explained
+transparent, redirect, nodefault, typetransparent, inform, and are explained
below. After that the default settings are listed. Use local\-data: to
enter data into the local zone. Answers for local zones are authoritative
DNS answers. By default the zones are class IN.
@@ -841,6 +846,13 @@ local\-data: "example.com. A 127.0.0.1"
queries for www.example.com and www.foo.example.com are redirected, so
that users with web browsers cannot access sites with suffix example.com.
.TP 10
+\h'5'\fIinform\fR
+The query is answered normally. The client IP address (@portnumber)
+is printed to the logfile. The log message is: timestamp, unbound-pid,
+info: zonename inform IP@port queryname type class. This option can be
+used for normal resolution, but machines looking up infected names are
+logged, eg. to run antivirus on them.
+.TP 10
\h'5'\fInodefault\fR
Used to turn off default contents for AS112 zones. The other types
also turn off default contents for the zone. The 'nodefault' option
diff --git a/contrib/unbound/iterator/iter_scrub.c b/contrib/unbound/iterator/iter_scrub.c
index b2248bc..1c81975 100644
--- a/contrib/unbound/iterator/iter_scrub.c
+++ b/contrib/unbound/iterator/iter_scrub.c
@@ -680,7 +680,9 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
* (we dont want its glue that was approved
* during the normalize action) */
del_addi = 1;
- } else if(!env->cfg->harden_glue) {
+ } else if(!env->cfg->harden_glue && (
+ rrset->type == LDNS_RR_TYPE_A ||
+ rrset->type == LDNS_RR_TYPE_AAAA)) {
/* store in cache! Since it is relevant
* (from normalize) it will be picked up
* from the cache to be used later */
diff --git a/contrib/unbound/iterator/iter_utils.c b/contrib/unbound/iterator/iter_utils.c
index 9d0aa69..10ae12f 100644
--- a/contrib/unbound/iterator/iter_utils.c
+++ b/contrib/unbound/iterator/iter_utils.c
@@ -715,6 +715,42 @@ reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
}
void
+caps_strip_reply(struct reply_info* rep)
+{
+ size_t i;
+ if(!rep) return;
+ /* see if message is a referral, in which case the additional and
+ * NS record cannot be removed */
+ /* referrals have the AA flag unset (strict check, not elsewhere in
+ * unbound, but for 0x20 this is very convenient). */
+ if(!(rep->flags&BIT_AA))
+ return;
+ /* remove the additional section from the reply */
+ if(rep->ar_numrrsets != 0) {
+ verbose(VERB_ALGO, "caps fallback: removing additional section");
+ rep->rrset_count -= rep->ar_numrrsets;
+ rep->ar_numrrsets = 0;
+ }
+ /* is there an NS set in the authority section to remove? */
+ /* the failure case (Cisco firewalls) only has one rrset in authsec */
+ for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
+ struct ub_packed_rrset_key* s = rep->rrsets[i];
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS) {
+ /* remove NS rrset and break from loop (loop limits
+ * have changed) */
+ /* move last rrset into this position (there is no
+ * additional section any more) */
+ verbose(VERB_ALGO, "caps fallback: removing NS rrset");
+ if(i < rep->rrset_count-1)
+ rep->rrsets[i]=rep->rrsets[rep->rrset_count-1];
+ rep->rrset_count --;
+ rep->ns_numrrsets --;
+ break;
+ }
+ }
+}
+
+void
iter_store_parentside_rrset(struct module_env* env,
struct ub_packed_rrset_key* rrset)
{
diff --git a/contrib/unbound/iterator/iter_utils.h b/contrib/unbound/iterator/iter_utils.h
index d7c2b68..9373487 100644
--- a/contrib/unbound/iterator/iter_utils.h
+++ b/contrib/unbound/iterator/iter_utils.h
@@ -223,6 +223,15 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
int reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region);
/**
+ * Remove unused bits from the reply if possible.
+ * So that caps-for-id (0x20) fallback is more likely to be successful.
+ * This removes like, the additional section, and NS record in the authority
+ * section if those records are gratuitous (not for a referral).
+ * @param rep: the reply to strip stuff out of.
+ */
+void caps_strip_reply(struct reply_info* rep);
+
+/**
* Store parent-side rrset in seperate rrset cache entries for later
* last-resort * lookups in case the child-side versions of this information
* fails.
diff --git a/contrib/unbound/iterator/iterator.c b/contrib/unbound/iterator/iterator.c
index 6e05c99..2037cc8 100644
--- a/contrib/unbound/iterator/iterator.c
+++ b/contrib/unbound/iterator/iterator.c
@@ -1383,8 +1383,10 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
return 0;
if(iq->depth > 0 && iq->target_count &&
iq->target_count[1] > MAX_TARGET_COUNT) {
- verbose(VERB_QUERY, "request has exceeded the maximum "
- "number of glue fetches %d", iq->target_count[1]);
+ char s[LDNS_MAX_DOMAINLEN+1];
+ dname_str(qstate->qinfo.qname, s);
+ verbose(VERB_QUERY, "request %s has exceeded the maximum "
+ "number of glue fetches %d", s, iq->target_count[1]);
return 0;
}
@@ -1581,8 +1583,10 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
}
if(iq->depth > 0 && iq->target_count &&
iq->target_count[1] > MAX_TARGET_COUNT) {
- verbose(VERB_QUERY, "request has exceeded the maximum "
- "number of glue fetches %d", iq->target_count[1]);
+ char s[LDNS_MAX_DOMAINLEN+1];
+ dname_str(qstate->qinfo.qname, s);
+ verbose(VERB_QUERY, "request %s has exceeded the maximum "
+ "number of glue fetches %d", s, iq->target_count[1]);
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
/* mark cycle targets for parent-side lookups */
@@ -2878,6 +2882,9 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
iq->response->rep);
if(event == module_event_capsfail || iq->caps_fallback) {
+ /* for fallback we care about main answer, not additionals */
+ /* removing that makes comparison more likely to succeed */
+ caps_strip_reply(iq->response->rep);
if(!iq->caps_fallback) {
/* start fallback */
iq->caps_fallback = 1;
diff --git a/contrib/unbound/libunbound/libworker.c b/contrib/unbound/libunbound/libworker.c
index e388e79..c72b586 100644
--- a/contrib/unbound/libunbound/libworker.c
+++ b/contrib/unbound/libunbound/libworker.c
@@ -606,7 +606,7 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
- w->back->udp_buff, w->env->scratch)) {
+ w->back->udp_buff, w->env->scratch, NULL)) {
regional_free_all(w->env->scratch);
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
w->back->udp_buff, sec_status_insecure, NULL);
@@ -676,7 +676,7 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
- w->back->udp_buff, w->env->scratch)) {
+ w->back->udp_buff, w->env->scratch, NULL)) {
regional_free_all(w->env->scratch);
free(qinfo.qname);
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
@@ -796,7 +796,7 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns,
- w->back->udp_buff, w->env->scratch)) {
+ w->back->udp_buff, w->env->scratch, NULL)) {
regional_free_all(w->env->scratch);
q->msg_security = sec_status_insecure;
add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
diff --git a/contrib/unbound/libunbound/python/libunbound.i b/contrib/unbound/libunbound/python/libunbound.i
index 313c748..1bef79f 100644
--- a/contrib/unbound/libunbound/python/libunbound.i
+++ b/contrib/unbound/libunbound/python/libunbound.i
@@ -44,6 +44,10 @@
%pythoncode %{
import encodings.idna
+ try:
+ import builtins
+ except ImportError:
+ import __builtin__ as builtins
# Ensure compatibility with older python versions
if 'bytes' not in vars():
@@ -52,7 +56,7 @@
def ord(s):
if isinstance(s, int):
return s
- return __builtins__.ord(s)
+ return builtins.ord(s)
%}
//%include "doc.i"
@@ -699,7 +703,7 @@ Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
while (idx < slen):
complen = ord(s[idx])
# In python 3.x `str()` converts the string to unicode which is the expected text string type
- res.append(str(s[idx+1:idx+1+complen]))
+ res.append(str(s[idx+1:idx+1+complen].decode()))
idx += complen + 1
return res
diff --git a/contrib/unbound/services/listen_dnsport.c b/contrib/unbound/services/listen_dnsport.c
index 0ce0a6b..3e5bf40 100644
--- a/contrib/unbound/services/listen_dnsport.c
+++ b/contrib/unbound/services/listen_dnsport.c
@@ -372,29 +372,47 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
* (and also uses the interface mtu to determine the size of the packets).
* So there won't be any EMSGSIZE error. Against DNS fragmentation attacks.
* FreeBSD already has same semantics without setting the option. */
-# if defined(IP_PMTUDISC_OMIT)
- int action = IP_PMTUDISC_OMIT;
-# else
- int action = IP_PMTUDISC_DONT;
-# endif
+ int omit_set = 0;
+ int action;
+# if defined(IP_PMTUDISC_OMIT)
+ action = IP_PMTUDISC_OMIT;
if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
&action, (socklen_t)sizeof(action)) < 0) {
- log_err("setsockopt(..., IP_MTU_DISCOVER, "
-# if defined(IP_PMTUDISC_OMIT)
- "IP_PMTUDISC_OMIT"
+
+ if (errno != EINVAL) {
+ log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_OMIT...) failed: %s",
+ strerror(errno));
+
+# ifndef USE_WINSOCK
+ close(s);
# else
- "IP_PMTUDISC_DONT"
+ closesocket(s);
# endif
- "...) failed: %s",
- strerror(errno));
+ *noproto = 0;
+ *inuse = 0;
+ return -1;
+ }
+ }
+ else
+ {
+ omit_set = 1;
+ }
+# endif
+ if (omit_set == 0) {
+ action = IP_PMTUDISC_DONT;
+ if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
+ &action, (socklen_t)sizeof(action)) < 0) {
+ log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_DONT...) failed: %s",
+ strerror(errno));
# ifndef USE_WINSOCK
- close(s);
+ close(s);
# else
- closesocket(s);
+ closesocket(s);
# endif
- *noproto = 0;
- *inuse = 0;
- return -1;
+ *noproto = 0;
+ *inuse = 0;
+ return -1;
+ }
}
# elif defined(IP_DONTFRAG)
int off = 0;
@@ -580,17 +598,18 @@ create_local_accept_sock(const char *path, int* noproto)
{
#ifdef HAVE_SYS_UN_H
int s;
- struct sockaddr_un sun;
+ struct sockaddr_un usock;
+ verbose(VERB_ALGO, "creating unix socket %s", path);
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
/* this member exists on BSDs, not Linux */
- sun.sun_len = (sa_family_t)sizeof(sun);
+ usock.sun_len = (socklen_t)sizeof(usock);
#endif
- sun.sun_family = AF_LOCAL;
+ usock.sun_family = AF_LOCAL;
/* length is 92-108, 104 on FreeBSD */
- (void)strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+ (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path));
- if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
+ if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
log_err("Cannot create local socket %s (%s)",
path, strerror(errno));
return -1;
@@ -603,7 +622,7 @@ create_local_accept_sock(const char *path, int* noproto)
return -1;
}
- if (bind(s, (struct sockaddr *)&sun,
+ if (bind(s, (struct sockaddr *)&usock,
(socklen_t)sizeof(struct sockaddr_un)) == -1) {
log_err("Cannot bind local socket %s (%s)",
path, strerror(errno));
@@ -623,6 +642,7 @@ create_local_accept_sock(const char *path, int* noproto)
(void)noproto; /*unused*/
return s;
#else
+ (void)path;
log_err("Local sockets are not supported");
*noproto = 1;
return -1;
diff --git a/contrib/unbound/services/localzone.c b/contrib/unbound/services/localzone.c
index d285a12..57510bd 100644
--- a/contrib/unbound/services/localzone.c
+++ b/contrib/unbound/services/localzone.c
@@ -48,6 +48,7 @@
#include "util/data/packed_rrset.h"
#include "util/data/msgencode.h"
#include "util/net_help.h"
+#include "util/netevent.h"
#include "util/data/msgreply.h"
#include "util/data/msgparse.h"
@@ -1022,6 +1023,10 @@ void local_zones_print(struct local_zones* zones)
log_nametypeclass(0, "static zone",
z->name, 0, z->dclass);
break;
+ case local_zone_inform:
+ log_nametypeclass(0, "inform zone",
+ z->name, 0, z->dclass);
+ break;
default:
log_nametypeclass(0, "badtyped zone",
z->name, 0, z->dclass);
@@ -1169,9 +1174,25 @@ lz_zone_answer(struct local_zone* z, struct query_info* qinfo,
return 0;
}
+/** print log information for an inform zone query */
+static void
+lz_inform_print(struct local_zone* z, struct query_info* qinfo,
+ struct comm_reply* repinfo)
+{
+ char ip[128], txt[512];
+ char zname[LDNS_MAX_DOMAINLEN+1];
+ uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
+ dname_str(z->name, zname);
+ addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
+ snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip,
+ (unsigned)port);
+ log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
+}
+
int
local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp)
+ struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
+ struct comm_reply* repinfo)
{
/* see if query is covered by a zone,
* if so: - try to match (exact) local data
@@ -1190,6 +1211,9 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
lock_rw_rdlock(&z->lock);
lock_rw_unlock(&zones->lock);
+ if(z->type == local_zone_inform && repinfo)
+ lz_inform_print(z, qinfo, repinfo);
+
if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) {
lock_rw_unlock(&z->lock);
return 1;
@@ -1209,6 +1233,7 @@ const char* local_zone_type2str(enum localzone_type t)
case local_zone_typetransparent: return "typetransparent";
case local_zone_static: return "static";
case local_zone_nodefault: return "nodefault";
+ case local_zone_inform: return "inform";
}
return "badtyped";
}
@@ -1227,6 +1252,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
*t = local_zone_typetransparent;
else if(strcmp(type, "redirect") == 0)
*t = local_zone_redirect;
+ else if(strcmp(type, "inform") == 0)
+ *t = local_zone_inform;
else return 0;
return 1;
}
diff --git a/contrib/unbound/services/localzone.h b/contrib/unbound/services/localzone.h
index 788fbfb..29ba866 100644
--- a/contrib/unbound/services/localzone.h
+++ b/contrib/unbound/services/localzone.h
@@ -49,6 +49,7 @@ struct config_file;
struct edns_data;
struct query_info;
struct sldns_buffer;
+struct comm_reply;
/**
* Local zone type
@@ -70,7 +71,9 @@ enum localzone_type {
local_zone_redirect,
/** remove default AS112 blocking contents for zone
* nodefault is used in config not during service. */
- local_zone_nodefault
+ local_zone_nodefault,
+ /** log client address, but no block (transparent) */
+ local_zone_inform
};
/**
@@ -220,12 +223,14 @@ void local_zones_print(struct local_zones* zones);
* @param edns: edns info (parsed).
* @param buf: buffer with query ID and flags, also for reply.
* @param temp: temporary storage region.
+ * @param repinfo: source address for checks. may be NULL.
* @return true if answer is in buffer. false if query is not answered
* by authority data. If the reply should be dropped altogether, the return
* value is true, but the buffer is cleared (empty).
*/
int local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
- struct edns_data* edns, struct sldns_buffer* buf, struct regional* temp);
+ struct edns_data* edns, struct sldns_buffer* buf, struct regional* temp,
+ struct comm_reply* repinfo);
/**
* Parse the string into localzone type.
diff --git a/contrib/unbound/smallapp/unbound-checkconf.c b/contrib/unbound/smallapp/unbound-checkconf.c
index 7723c33..b5d7b9f 100644
--- a/contrib/unbound/smallapp/unbound-checkconf.c
+++ b/contrib/unbound/smallapp/unbound-checkconf.c
@@ -78,6 +78,7 @@ usage()
printf(" Checks unbound configuration file for errors.\n");
printf("file if omitted %s is used.\n", CONFIGFILE);
printf("-o option print value of option to stdout.\n");
+ printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n");
printf("-h show this usage help.\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n");
@@ -90,10 +91,15 @@ usage()
* @param cfg: config
* @param opt: option name without trailing :.
* This is different from config_set_option.
+ * @param final: if final pathname with chroot applied has to be printed.
*/
static void
-print_option(struct config_file* cfg, const char* opt)
+print_option(struct config_file* cfg, const char* opt, int final)
{
+ if(strcmp(opt, "pidfile") == 0 && final) {
+ printf("%s\n", fname_after_chroot(cfg->pidfile, cfg, 1));
+ return;
+ }
if(!config_get_option(cfg, opt, config_print_func, stdout))
fatal_exit("cannot print option '%s'", opt);
}
@@ -456,7 +462,7 @@ check_hints(struct config_file* cfg)
/** check config file */
static void
-checkconf(const char* cfgfile, const char* opt)
+checkconf(const char* cfgfile, const char* opt, int final)
{
struct config_file* cfg = config_create();
if(!cfg)
@@ -467,7 +473,7 @@ checkconf(const char* cfgfile, const char* opt)
exit(1);
}
if(opt) {
- print_option(cfg, opt);
+ print_option(cfg, opt, final);
config_delete(cfg);
return;
}
@@ -493,6 +499,7 @@ extern char* optarg;
int main(int argc, char* argv[])
{
int c;
+ int final = 0;
const char* f;
const char* opt = NULL;
const char* cfgfile = CONFIGFILE;
@@ -505,8 +512,11 @@ int main(int argc, char* argv[])
cfgfile = CONFIGFILE;
#endif /* USE_WINSOCK */
/* parse the options */
- while( (c=getopt(argc, argv, "ho:")) != -1) {
+ while( (c=getopt(argc, argv, "fho:")) != -1) {
switch(c) {
+ case 'f':
+ final = 1;
+ break;
case 'o':
opt = optarg;
break;
@@ -523,7 +533,7 @@ int main(int argc, char* argv[])
if(argc == 1)
f = argv[0];
else f = cfgfile;
- checkconf(f, opt);
+ checkconf(f, opt, final);
checklock_stop();
return 0;
}
diff --git a/contrib/unbound/smallapp/unbound-control-setup.sh b/contrib/unbound/smallapp/unbound-control-setup.sh
index f22f4b8..010bfd4 100755
--- a/contrib/unbound/smallapp/unbound-control-setup.sh
+++ b/contrib/unbound/smallapp/unbound-control-setup.sh
@@ -36,8 +36,7 @@
# settings:
# directory for files
-prefix=
-DESTDIR=${prefix}/etc/unbound
+DESTDIR=/var/unbound
# issuer and subject name for certificates
SERVERNAME=unbound
diff --git a/contrib/unbound/smallapp/unbound-control-setup.sh.in b/contrib/unbound/smallapp/unbound-control-setup.sh.in
index 79605dc..75e76e2 100755
--- a/contrib/unbound/smallapp/unbound-control-setup.sh.in
+++ b/contrib/unbound/smallapp/unbound-control-setup.sh.in
@@ -36,8 +36,7 @@
# settings:
# directory for files
-prefix=@prefix@
-DESTDIR=@sysconfdir@/unbound
+DESTDIR=@ub_conf_dir@
# issuer and subject name for certificates
SERVERNAME=unbound
diff --git a/contrib/unbound/smallapp/unbound-control.c b/contrib/unbound/smallapp/unbound-control.c
index ac8d968..3b47d3b 100644
--- a/contrib/unbound/smallapp/unbound-control.c
+++ b/contrib/unbound/smallapp/unbound-control.c
@@ -204,12 +204,12 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
fatal_exit("could not parse IP@port: %s", svr);
#ifdef HAVE_SYS_UN_H
} else if(svr[0] == '/') {
- struct sockaddr_un* sun = (struct sockaddr_un *) &addr;
- sun->sun_family = AF_LOCAL;
+ struct sockaddr_un* usock = (struct sockaddr_un *) &addr;
+ usock->sun_family = AF_LOCAL;
#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
- sun->sun_len = (sa_family_t)sizeof(sun);
+ usock->sun_len = (socklen_t)sizeof(usock);
#endif
- (void)strlcpy(sun->sun_path, svr, sizeof(sun->sun_path));
+ (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path));
addrlen = (socklen_t)sizeof(struct sockaddr_un);
addrfamily = AF_LOCAL;
#endif
diff --git a/contrib/unbound/util/config_file.c b/contrib/unbound/util/config_file.c
index a2352d5..cdb2b33 100644
--- a/contrib/unbound/util/config_file.c
+++ b/contrib/unbound/util/config_file.c
@@ -55,6 +55,7 @@
#include "util/regional.h"
#include "util/fptr_wlist.h"
#include "util/data/dname.h"
+#include "util/rtt.h"
#include "ldns/wire2str.h"
#include "ldns/parseutil.h"
#ifdef HAVE_GLOB_H
@@ -64,6 +65,11 @@
#include <pwd.h>
#endif
+/** from cfg username, after daemonise setup performed */
+uid_t cfg_uid = (uid_t)-1;
+/** from cfg username, after daemonise setup performed */
+gid_t cfg_gid = (gid_t)-1;
+
/** global config during parsing */
struct config_parser_state* cfg_parser = 0;
@@ -129,13 +135,12 @@ config_create(void)
cfg->prefetch_key = 0;
cfg->infra_cache_slabs = 4;
cfg->infra_cache_numhosts = 10000;
+ cfg->infra_cache_min_rtt = 50;
cfg->delay_close = 0;
if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int))))
goto error_exit;
init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
- cfg->uid = (uid_t)-1;
- cfg->gid = (gid_t)-1;
#ifdef HAVE_CHROOT
if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
#endif
@@ -375,6 +380,10 @@ int config_set_option(struct config_file* cfg, const char* opt,
{ IS_NUMBER_OR_ZERO; cfg->max_ttl = atoi(val); MAX_TTL=(time_t)cfg->max_ttl;}
else if(strcmp(opt, "cache-min-ttl:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->min_ttl = atoi(val); MIN_TTL=(time_t)cfg->min_ttl;}
+ else if(strcmp(opt, "infra-cache-min-rtt:") == 0) {
+ IS_NUMBER_OR_ZERO; cfg->infra_cache_min_rtt = atoi(val);
+ RTT_MIN_TIMEOUT=cfg->infra_cache_min_rtt;
+ }
else S_NUMBER_OR_ZERO("infra-host-ttl:", host_ttl)
else S_POW2("infra-cache-slabs:", infra_cache_slabs)
else S_SIZET_NONZERO("infra-cache-numhosts:", infra_cache_numhosts)
@@ -623,6 +632,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "cache-min-ttl", min_ttl)
else O_DEC(opt, "infra-host-ttl", host_ttl)
else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
+ else O_DEC(opt, "infra-cache-min-rtt", infra_cache_min_rtt)
else O_MEM(opt, "infra-cache-numhosts", infra_cache_numhosts)
else O_UNS(opt, "delay-close", delay_close)
else O_YNO(opt, "do-ip4", do_ip4)
@@ -1188,6 +1198,7 @@ config_apply(struct config_file* config)
{
MAX_TTL = (time_t)config->max_ttl;
MIN_TTL = (time_t)config->min_ttl;
+ RTT_MIN_TIMEOUT = config->infra_cache_min_rtt;
EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
MINIMAL_RESPONSES = config->minimal_responses;
RRSET_ROUNDROBIN = config->rrset_roundrobin;
@@ -1200,11 +1211,13 @@ void config_lookup_uid(struct config_file* cfg)
/* translate username into uid and gid */
if(cfg->username && cfg->username[0]) {
struct passwd *pwd;
- if((pwd = getpwnam(cfg->username)) == NULL)
- log_err("user '%s' does not exist.", cfg->username);
- cfg->uid = pwd->pw_uid;
- cfg->gid = pwd->pw_gid;
+ if((pwd = getpwnam(cfg->username)) != NULL) {
+ cfg_uid = pwd->pw_uid;
+ cfg_gid = pwd->pw_gid;
+ }
}
+#else
+ (void)cfg;
#endif
}
diff --git a/contrib/unbound/util/config_file.h b/contrib/unbound/util/config_file.h
index 327eadc..ca512d7 100644
--- a/contrib/unbound/util/config_file.h
+++ b/contrib/unbound/util/config_file.h
@@ -119,6 +119,8 @@ struct config_file {
size_t infra_cache_slabs;
/** max number of hosts in the infra cache */
size_t infra_cache_numhosts;
+ /** min value for infra cache rtt */
+ int infra_cache_min_rtt;
/** delay close of udp-timeouted ports, if 0 no delayclose. in msec */
int delay_close;
@@ -192,8 +194,6 @@ struct config_file {
char* chrootdir;
/** username to change to, if not "". */
char* username;
- uid_t uid;
- gid_t gid;
/** working directory */
char* directory;
/** filename to log to. */
@@ -343,6 +343,11 @@ struct config_file {
int dnstap_log_forwarder_response_messages;
};
+/** from cfg username, after daemonise setup performed */
+extern uid_t cfg_uid;
+/** from cfg username, after daemonise setup performed */
+extern gid_t cfg_gid;
+
/**
* Stub config options
*/
@@ -427,7 +432,7 @@ void config_delete(struct config_file* config);
void config_apply(struct config_file* config);
/**
- * Find username, sets uid and gid.
+ * Find username, sets cfg_uid and cfg_gid.
* @param config: the config structure.
*/
void config_lookup_uid(struct config_file* config);
diff --git a/contrib/unbound/util/configlexer.lex b/contrib/unbound/util/configlexer.lex
index e13bad0..0e22946 100644
--- a/contrib/unbound/util/configlexer.lex
+++ b/contrib/unbound/util/configlexer.lex
@@ -247,6 +247,7 @@ infra-lame-ttl{COLON} { YDVAR(1, VAR_INFRA_LAME_TTL) }
infra-cache-slabs{COLON} { YDVAR(1, VAR_INFRA_CACHE_SLABS) }
infra-cache-numhosts{COLON} { YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) }
infra-cache-lame-size{COLON} { YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) }
+infra-cache-min-rtt{COLON} { YDVAR(1, VAR_INFRA_CACHE_MIN_RTT) }
num-queries-per-thread{COLON} { YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) }
jostle-timeout{COLON} { YDVAR(1, VAR_JOSTLE_TIMEOUT) }
delay-close{COLON} { YDVAR(1, VAR_DELAY_CLOSE) }
diff --git a/contrib/unbound/util/configparser.y b/contrib/unbound/util/configparser.y
index cbb5e16..396ea3c 100644
--- a/contrib/unbound/util/configparser.y
+++ b/contrib/unbound/util/configparser.y
@@ -107,6 +107,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
%token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN
%token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE VAR_UNBLOCK_LAN_ZONES
+%token VAR_INFRA_CACHE_MIN_RTT
%token VAR_DNS64_PREFIX VAR_DNS64_SYNTHALL
%token VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH
%token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION
@@ -175,7 +176,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_ssl_service_key | server_ssl_service_pem | server_ssl_port |
server_minimal_responses | server_rrset_roundrobin | server_max_udp_size |
server_so_reuseport | server_delay_close | server_unblock_lan_zones |
- server_dns64_prefix | server_dns64_synthall
+ server_dns64_prefix | server_dns64_synthall |
+ server_infra_cache_min_rtt
;
stubstart: VAR_STUB_ZONE
{
@@ -768,6 +770,15 @@ server_infra_cache_slabs: VAR_INFRA_CACHE_SLABS STRING_ARG
free($2);
}
;
+server_infra_cache_min_rtt: VAR_INFRA_CACHE_MIN_RTT STRING_ARG
+ {
+ OUTYY(("P(server_infra_cache_min_rtt:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->infra_cache_min_rtt = atoi($2);
+ free($2);
+ }
+ ;
server_target_fetch_policy: VAR_TARGET_FETCH_POLICY STRING_ARG
{
OUTYY(("P(server_target_fetch_policy:%s)\n", $2));
@@ -1105,10 +1116,11 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
if(strcmp($3, "static")!=0 && strcmp($3, "deny")!=0 &&
strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 &&
strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0
- && strcmp($3, "typetransparent")!=0)
+ && strcmp($3, "typetransparent")!=0 &&
+ strcmp($3, "inform")!=0)
yyerror("local-zone type: expected static, deny, "
"refuse, redirect, transparent, "
- "typetransparent or nodefault");
+ "typetransparent, inform or nodefault");
else if(strcmp($3, "nodefault")==0) {
if(!cfg_strlist_insert(&cfg_parser->cfg->
local_zones_nodefault, $2))
diff --git a/contrib/unbound/util/iana_ports.inc b/contrib/unbound/util/iana_ports.inc
index d318477..ce939d5 100644
--- a/contrib/unbound/util/iana_ports.inc
+++ b/contrib/unbound/util/iana_ports.inc
@@ -3819,6 +3819,7 @@
4359,
4361,
4362,
+4366,
4368,
4369,
4370,
@@ -4399,6 +4400,7 @@
6163,
6200,
6201,
+6209,
6222,
6241,
6242,
@@ -4488,6 +4490,8 @@
6628,
6633,
6634,
+6635,
+6636,
6653,
6657,
6670,
@@ -4671,6 +4675,7 @@
7778,
7779,
7781,
+7784,
7786,
7787,
7789,
@@ -4839,6 +4844,8 @@
8912,
8913,
8954,
+8980,
+8981,
8989,
8990,
8991,
diff --git a/contrib/unbound/util/net_help.c b/contrib/unbound/util/net_help.c
index 335ee74..e2b7c38 100644
--- a/contrib/unbound/util/net_help.c
+++ b/contrib/unbound/util/net_help.c
@@ -156,7 +156,12 @@ log_addr(enum verbosity_value v, const char* str,
case AF_INET6: family="ip6";
sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
break;
- case AF_LOCAL: family="local"; break;
+ case AF_LOCAL:
+ dest[0]=0;
+ (void)inet_ntop(af, sinaddr, dest,
+ (socklen_t)sizeof(dest));
+ verbose(v, "%s local %s", str, dest);
+ return; /* do not continue and try to get port */
default: break;
}
if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
diff --git a/contrib/unbound/util/rtt.c b/contrib/unbound/util/rtt.c
index 4b44fca..5d86f13 100644
--- a/contrib/unbound/util/rtt.c
+++ b/contrib/unbound/util/rtt.c
@@ -42,6 +42,8 @@
#include "config.h"
#include "util/rtt.h"
+/* overwritten by config: infra_cache_min_rtt: */
+int RTT_MIN_TIMEOUT = 50;
/** calculate RTO from rtt information */
static int
calc_rto(const struct rtt_info* rtt)
diff --git a/contrib/unbound/util/rtt.h b/contrib/unbound/util/rtt.h
index 57e904d..d6da986 100644
--- a/contrib/unbound/util/rtt.h
+++ b/contrib/unbound/util/rtt.h
@@ -56,7 +56,7 @@ struct rtt_info {
};
/** min retransmit timeout value, in milliseconds */
-#define RTT_MIN_TIMEOUT 50
+extern int RTT_MIN_TIMEOUT;
/** max retransmit timeout value, in milliseconds */
#define RTT_MAX_TIMEOUT 120000
diff --git a/contrib/unbound/validator/val_secalgo.c b/contrib/unbound/validator/val_secalgo.c
index d89675f..3437c8d 100644
--- a/contrib/unbound/validator/val_secalgo.c
+++ b/contrib/unbound/validator/val_secalgo.c
@@ -41,8 +41,9 @@
* and do the library calls (for the crypto library in use).
*/
#include "config.h"
-#include "validator/val_secalgo.h"
+/* packed_rrset on top to define enum types (forced by c99 standard) */
#include "util/data/packed_rrset.h"
+#include "validator/val_secalgo.h"
#include "util/log.h"
#include "ldns/rrdef.h"
#include "ldns/keyraw.h"
diff --git a/contrib/unbound/validator/val_utils.c b/contrib/unbound/validator/val_utils.c
index ecf2dfa..475b0c9 100644
--- a/contrib/unbound/validator/val_utils.c
+++ b/contrib/unbound/validator/val_utils.c
@@ -846,6 +846,18 @@ val_fill_reply(struct reply_info* chase, struct reply_info* orig,
chase->ar_numrrsets;
}
+void val_reply_remove_auth(struct reply_info* rep, size_t index)
+{
+ log_assert(index < rep->rrset_count);
+ log_assert(index >= rep->an_numrrsets);
+ log_assert(index < rep->an_numrrsets+rep->ns_numrrsets);
+ memmove(rep->rrsets+index, rep->rrsets+index+1,
+ sizeof(struct ub_packed_rrset_key*)*
+ (rep->rrset_count - index - 1));
+ rep->ns_numrrsets--;
+ rep->rrset_count--;
+}
+
void
val_check_nonsecure(struct val_env* ve, struct reply_info* rep)
{
diff --git a/contrib/unbound/validator/val_utils.h b/contrib/unbound/validator/val_utils.h
index b0344ef..cdb8769 100644
--- a/contrib/unbound/validator/val_utils.h
+++ b/contrib/unbound/validator/val_utils.h
@@ -295,6 +295,13 @@ void val_fill_reply(struct reply_info* chase, struct reply_info* orig,
size_t cname_skip, uint8_t* name, size_t len, uint8_t* signer);
/**
+ * Remove rrset with index from reply, from the authority section.
+ * @param rep: reply to remove it from.
+ * @param index: rrset to remove, must be in the authority section.
+ */
+void val_reply_remove_auth(struct reply_info* rep, size_t index);
+
+/**
* Remove all unsigned or non-secure status rrsets from NS and AR sections.
* So that unsigned data does not get let through to clients, when we have
* found the data to be secure.
diff --git a/contrib/unbound/validator/validator.c b/contrib/unbound/validator/validator.c
index 9d5d5c3..cc07cc2 100644
--- a/contrib/unbound/validator/validator.c
+++ b/contrib/unbound/validator/validator.c
@@ -574,6 +574,61 @@ detect_wrongly_truncated(struct reply_info* rep)
return 1;
}
+/**
+ * For messages that are not referrals, if the chase reply contains an
+ * unsigned NS record in the authority section it could have been
+ * inserted by a (BIND) forwarder that thinks the zone is insecure, and
+ * that has an NS record without signatures in cache. Remove the NS
+ * record since the reply does not hinge on that record (in the authority
+ * section), but do not remove it if it removes the last record from the
+ * answer+authority sections.
+ * @param chase_reply: the chased reply, we have a key for this contents,
+ * so we should have signatures for these rrsets and not having
+ * signatures means it will be bogus.
+ * @param orig_reply: original reply, remove NS from there as well because
+ * we cannot mark the NS record as DNSSEC valid because it is not
+ * validated by signatures.
+ */
+static void
+remove_spurious_authority(struct reply_info* chase_reply,
+ struct reply_info* orig_reply)
+{
+ size_t i, found = 0;
+ int remove = 0;
+ /* if no answer and only 1 auth RRset, do not remove that one */
+ if(chase_reply->an_numrrsets == 0 && chase_reply->ns_numrrsets == 1)
+ return;
+ /* search authority section for unsigned NS records */
+ for(i = chase_reply->an_numrrsets;
+ i < chase_reply->an_numrrsets+chase_reply->ns_numrrsets; i++) {
+ struct packed_rrset_data* d = (struct packed_rrset_data*)
+ chase_reply->rrsets[i]->entry.data;
+ if(ntohs(chase_reply->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS
+ && d->rrsig_count == 0) {
+ found = i;
+ remove = 1;
+ break;
+ }
+ }
+ /* see if we found the entry */
+ if(!remove) return;
+ log_rrset_key(VERB_ALGO, "Removing spurious unsigned NS record "
+ "(likely inserted by forwarder)", chase_reply->rrsets[found]);
+
+ /* find rrset in orig_reply */
+ for(i = orig_reply->an_numrrsets;
+ i < orig_reply->an_numrrsets+orig_reply->ns_numrrsets; i++) {
+ if(ntohs(orig_reply->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS
+ && query_dname_compare(orig_reply->rrsets[i]->rk.dname,
+ chase_reply->rrsets[found]->rk.dname) == 0) {
+ /* remove from orig_msg */
+ val_reply_remove_auth(orig_reply, i);
+ break;
+ }
+ }
+ /* remove rrset from chase_reply */
+ val_reply_remove_auth(chase_reply, found);
+}
/**
* Given a "positive" response -- a response that contains an answer to the
@@ -1642,6 +1697,8 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
}
subtype = val_classify_response(qstate->query_flags, &qstate->qinfo,
&vq->qchase, vq->orig_msg->rep, vq->rrset_skip);
+ if(subtype != VAL_CLASS_REFERRAL)
+ remove_spurious_authority(vq->chase_reply, vq->orig_msg->rep);
/* check signatures in the message;
* answer and authority must be valid, additional is only checked. */
diff --git a/contrib/wpa/CONTRIBUTIONS b/contrib/wpa/CONTRIBUTIONS
new file mode 100644
index 0000000..ca09bae
--- /dev/null
+++ b/contrib/wpa/CONTRIBUTIONS
@@ -0,0 +1,143 @@
+Contributions to hostap.git
+---------------------------
+
+This software is distributed under a permissive open source license to
+allow it to be used in any projects, whether open source or proprietary.
+Contributions to the project are welcome and it is important to maintain
+clear record of contributions and terms under which they are licensed.
+To help with this, following procedure is used to allow acceptance and
+recording of the terms.
+
+All contributions are expected to be licensed under the modified BSD
+license (see below). Acknowledgment of the terms is tracked through
+inclusion of Signed-off-by tag in the contributions at the end of the
+commit log message. This tag indicates that the contributor agrees with
+the Developer Certificate of Origin (DCO) version 1.1 terms (see below;
+also available from http://developercertificate.org/).
+
+
+The current requirements for contributions to hostap.git
+--------------------------------------------------------
+
+To indicate your acceptance of Developer's Certificate of Origin 1.1
+terms, please add the following line to the end of the commit message
+for each contribution you make to the project:
+
+Signed-off-by: Your Name <your@email.example.org>
+
+using your real name. Pseudonyms or anonymous contributions cannot
+unfortunately be accepted.
+
+
+History of license and contributions terms
+------------------------------------------
+
+Until February 11, 2012, in case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed both under GPL v2 and modified BSD license (see below) and
+the choice between these licenses is given to anyone who redistributes
+or uses the software. As such, the contribution has to be licensed under
+both options to allow this choice.
+
+As of February 11, 2012, the project has chosen to use only the BSD
+license option for future distribution. As such, the GPL v2 license
+option is no longer used and the contributions are not required to be
+licensed until GPL v2. In case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed under the modified BSD license (see below).
+
+Until February 13, 2014, the project used an extended version of the DCO
+that included the identical items (a) through (d) from DCO 1.1 and an
+additional item (e):
+
+(e) The contribution can be licensed under the modified BSD license
+ as shown below even in case of files that are currently licensed
+ under other terms.
+
+This was used during the period when some of the files included the old
+license terms. Acceptance of this extended DCO version was indicated
+with a Signed-hostap tag in the commit message. This additional item (e)
+was used to collect explicit approval to license the contribution with
+only the modified BSD license (see below), i.e., without the GPL v2
+option. This was done to allow simpler licensing terms to be used in the
+future. It should be noted that the modified BSD license is compatible
+with GNU GPL and as such, this possible move to simpler licensing option
+does not prevent use of this software in GPL projects.
+
+
+===[ start quote from http://developercertificate.org/ ]=======================
+
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+===[ end quote from http://developercertificate.org/ ]=========================
+
+
+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
+All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/contrib/wpa/COPYING b/contrib/wpa/COPYING
index 8a98582..5962e2f 100644
--- a/contrib/wpa/COPYING
+++ b/contrib/wpa/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/contrib/wpa/README b/contrib/wpa/README
index 1721a3b..07d1d25 100644
--- a/contrib/wpa/README
+++ b/contrib/wpa/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, 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 6824e5a..e6f8c6a 100644
--- a/contrib/wpa/hostapd/ChangeLog
+++ b/contrib/wpa/hostapd/ChangeLog
@@ -1,5 +1,191 @@
ChangeLog for hostapd
+2015-03-15 - v2.4
+ * allow OpenSSL cipher configuration to be set for internal EAP server
+ (openssl_ciphers parameter)
+ * fixed number of small issues based on hwsim test case failures and
+ static analyzer reports
+ * fixed Accounting-Request to not include duplicated Acct-Session-Id
+ * add support for Acct-Multi-Session-Id in RADIUS Accounting messages
+ * add support for PMKSA caching with SAE
+ * add support for generating BSS Load element (bss_load_update_period)
+ * fixed channel switch from VHT to HT
+ * add INTERFACE-ENABLED and INTERFACE-DISABLED ctrl_iface events
+ * add support for learning STA IPv4/IPv6 addresses and configuring
+ ProxyARP support
+ * dropped support for the madwifi driver interface
+ * add support for Suite B (128-bit and 192-bit level) key management and
+ cipher suites
+ * fixed a regression with driver=wired
+ * extend EAPOL-Key msg 1/4 retry workaround for changing SNonce
+ * add BSS_TM_REQ ctrl_iface command to send BSS Transition Management
+ Request frames and BSS-TM-RESP event to indicate response to such
+ frame
+ * add support for EAP Re-Authentication Protocol (ERP)
+ * fixed AP IE in EAPOL-Key 3/4 when both WPA and FT was enabled
+ * fixed a regression in HT 20/40 coex Action frame parsing
+ * set stdout to be line-buffered
+ * add support for vendor specific VHT extension to enable 256 QAM rates
+ (VHT-MCS 8 and 9) on 2.4 GHz band
+ * RADIUS DAS:
+ - extend Disconnect-Request processing to allow matching of multiple
+ sessions
+ - support Acct-Multi-Session-Id as an identifier
+ - allow PMKSA cache entry to be removed without association
+ * expire hostapd STA entry if kernel does not have a matching entry
+ * allow chanlist to be used to specify a subset of channels for ACS
+ * improve ACS behavior on 2.4 GHz band and allow channel bias to be
+ configured with acs_chan_bias parameter
+ * do not reply to a Probe Request frame that includes DSS Parameter Set
+ element in which the channel does not match the current operating
+ channel
+ * add UPDATE_BEACON ctrl_iface command; this can be used to force Beacon
+ frame contents to be updated and to start beaconing on an interface
+ that used start_disabled=1
+ * fixed some RADIUS server failover cases
+
+2014-10-09 - v2.3
+ * fixed number of minor issues identified in static analyzer warnings
+ * fixed DFS and channel switch operation for multi-BSS cases
+ * started to use constant time comparison for various password and hash
+ values to reduce possibility of any externally measurable timing
+ differences
+ * extended explicit clearing of freed memory and expired keys to avoid
+ keeping private data in memory longer than necessary
+ * added support for number of new RADIUS attributes from RFC 7268
+ (Mobility-Domain-Id, WLAN-HESSID, WLAN-Pairwise-Cipher,
+ WLAN-Group-Cipher, WLAN-AKM-Suite, WLAN-Group-Mgmt-Pairwise-Cipher)
+ * fixed GET_CONFIG wpa_pairwise_cipher value
+ * added code to clear bridge FDB entry on station disconnection
+ * fixed PMKSA cache timeout from Session-Timeout for WPA/WPA2 cases
+ * fixed OKC PMKSA cache entry fetch to avoid a possible infinite loop
+ in case the first entry does not match
+ * fixed hostapd_cli action script execution to use more robust mechanism
+ (CVE-2014-3686)
+
+2014-06-04 - v2.2
+ * fixed SAE confirm-before-commit validation to avoid a potential
+ segmentation fault in an unexpected message sequence that could be
+ triggered remotely
+ * extended VHT support
+ - Operating Mode Notification
+ - Power Constraint element (local_pwr_constraint)
+ - Spectrum management capability (spectrum_mgmt_required=1)
+ - fix VHT80 segment picking in ACS
+ - fix vht_capab 'Maximum A-MPDU Length Exponent' handling
+ - fix VHT20
+ * fixed HT40 co-ex scan for some pri/sec channel switches
+ * extended HT40 co-ex support to allow dynamic channel width changes
+ during the lifetime of the BSS
+ * fixed HT40 co-ex support to check for overlapping 20 MHz BSS
+ * fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding;
+ this fixes password with include UTF-8 characters that use
+ three-byte encoding EAP methods that use NtPasswordHash
+ * reverted TLS certificate validation step change in v2.1 that rejected
+ any AAA server certificate with id-kp-clientAuth even if
+ id-kp-serverAuth EKU was included
+ * fixed STA validation step for WPS ER commands to prevent a potential
+ crash if an ER sends an unexpected PutWLANResponse to a station that
+ is disassociated, but not fully removed
+ * enforce full EAP authentication after RADIUS Disconnect-Request by
+ removing the PMKSA cache entry
+ * added support for NAS-IP-Address, NAS-identifier, and NAS-IPv6-Address
+ in RADIUS Disconnect-Request
+ * added mechanism for removing addresses for MAC ACLs by prefixing an
+ entry with "-"
+ * Interworking/Hotspot 2.0 enhancements
+ - support Hotspot 2.0 Release 2
+ * OSEN network for online signup connection
+ * subscription remediation (based on RADIUS server request or
+ control interface HS20_WNM_NOTIF for testing purposes)
+ * Hotspot 2.0 release number indication in WFA RADIUS VSA
+ * deauthentication request (based on RADIUS server request or
+ control interface WNM_DEAUTH_REQ for testing purposes)
+ * Session Info URL RADIUS AVP to trigger ESS Disassociation Imminent
+ * hs20_icon config parameter to configure icon files for OSU
+ * osu_* config parameters for OSU Providers list
+ - do not use Interworking filtering rules on Probe Request if
+ Interworking is disabled to avoid interop issues
+ * added/fixed nl80211 functionality
+ - AP interface teardown optimization
+ - support vendor specific driver command
+ (VENDOR <vendor id> <sub command id> [<hex formatted data>])
+ * fixed PMF protection of Deauthentication frame when this is triggered
+ by session timeout
+ * internal TLS implementation enhancements/fixes
+ - add SHA256-based cipher suites
+ - add DHE-RSA cipher suites
+ - fix X.509 validation of PKCS#1 signature to check for extra data
+ * RADIUS server functionality
+ - add minimal RADIUS accounting server support (hostapd-as-server);
+ this is mainly to enable testing coverage with hwsim scripts
+ - allow authentication log to be written into SQLite databse
+ - added option for TLS protocol testing of an EAP peer by simulating
+ various misbehaviors/known attacks
+ - MAC ACL support for testing purposes
+ * fixed PTK derivation for CCMP-256 and GCMP-256
+ * extended WPS per-station PSK to support ER case
+ * added option to configure the management group cipher
+ (group_mgmt_cipher=AES-128-CMAC (default), BIP-GMAC-128, BIP-GMAC-256,
+ BIP-CMAC-256)
+ * fixed AP mode default TXOP Limit values for AC_VI and AC_VO (these
+ were rounded incorrectly)
+ * added support for postponing FT response in case PMK-R1 needs to be
+ pulled from R0KH
+ * added option to advertise 40 MHz intolerant HT capability with
+ ht_capab=[40-INTOLERANT]
+ * remove WPS 1.0 only support, i.e., WSC 2.0 support is now enabled
+ whenever CONFIG_WPS=y is set
+ * EAP-pwd fixes
+ - fix possible segmentation fault on EAP method deinit if an invalid
+ group is negotiated
+ * fixed RADIUS client retransmit/failover behavior
+ - there was a potential ctash due to freed memory being accessed
+ - failover to a backup server mechanism did not work properly
+ * fixed a possible crash on double DISABLE command when multiple BSSes
+ are enabled
+ * fixed a memory leak in SAE random number generation
+ * fixed GTK rekeying when the station uses FT protocol
+ * fixed off-by-one bounds checking in printf_encode()
+ - this could result in deinial of service in some EAP server cases
+ * various bug fixes
+
+2014-02-04 - v2.1
+ * added support for simultaneous authentication of equals (SAE) for
+ stronger password-based authentication with WPA2-Personal
+ * added nl80211 functionality
+ - VHT configuration for nl80211
+ - support split wiphy dump
+ - driver-based MAC ACL
+ - QoS Mapping configuration
+ * added fully automated regression testing with mac80211_hwsim
+ * allow ctrl_iface group to be specified on command line (-G<group>)
+ * allow single hostapd process to control independent WPS interfaces
+ (wps_independent=1) instead of synchronized operations through all
+ configured interfaces within a process
+ * avoid processing received management frames multiple times when using
+ nl80211 with multiple BSSes
+ * added support for DFS (processing radar detection events, CAC, channel
+ re-selection)
+ * added EAP-EKE server
+ * added automatic channel selection (ACS)
+ * added option for using per-BSS (vif) configuration files with
+ -b<phyname>:<config file name>
+ * extended global control interface ADD/REMOVE commands to allow BSSes
+ of a radio to be removed individually without having to add/remove all
+ other BSSes of the radio at the same time
+ * added support for sending debug info to Linux tracing (-T on command
+ line)
+ * replace dump_file functionality with same information being available
+ through the hostapd control interface
+ * added support for using Protected Dual of Public Action frames for
+ GAS/ANQP exchanges when PMF is enabled
+ * added support for WPS+NFC updates
+ - improved protocol
+ - option to fetch and report alternative carrier records for external
+ NFC operations
+ * various bug fixes
+
2013-01-12 - v2.0
* added AP-STA-DISCONNECTED ctrl_iface event
* improved debug logging (human readable event names, interface name
diff --git a/contrib/wpa/hostapd/README b/contrib/wpa/hostapd/README
index 34dad30..366b199 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-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
@@ -74,12 +74,6 @@ Current hardware/software requirements:
Please note that station firmware version needs to be 1.7.0 or newer
to work in WPA mode.
- madwifi driver for cards based on Atheros chip set (ar521x)
- (http://sourceforge.net/projects/madwifi/)
- Please note that you will need to add the correct path for
- madwifi driver root directory in .config (see defconfig file for
- an example: CFLAGS += -I<path>)
-
mac80211-based drivers that support AP mode (with driver=nl80211).
This includes drivers for Atheros (ath9k) and Broadcom (b43)
chipsets.
diff --git a/contrib/wpa/hostapd/README-WPS b/contrib/wpa/hostapd/README-WPS
index 87a6f91..d5f713a 100644
--- a/contrib/wpa/hostapd/README-WPS
+++ b/contrib/wpa/hostapd/README-WPS
@@ -58,12 +58,10 @@ hostapd configuration
WPS is an optional component that needs to be enabled in hostapd build
configuration (.config). Here is an example configuration that
-includes WPS support and uses madwifi driver interface:
+includes WPS support and uses nl80211 driver interface:
-CONFIG_DRIVER_MADWIFI=y
-CFLAGS += -I/usr/src/madwifi-0.9.3
+CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
-CONFIG_WPS2=y
CONFIG_WPS_UPNP=y
Following parameter can be used to enable support for NFC config method:
@@ -75,8 +73,8 @@ Following section shows an example runtime configuration
(hostapd.conf) that enables WPS:
# Configure the driver and network interface
-driver=madwifi
-interface=ath0
+driver=nl80211
+interface=wlan0
# WPA2-Personal configuration for the AP
ssid=wps-test
@@ -338,3 +336,17 @@ If the NFC tag contains a password token, the token is added to the
internal Registrar. This allows station Enrollee from which the password
token was received to run through WPS protocol to provision the
credential.
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" is used to report completed NFC
+connection handover. The first parameter indicates whether the local
+device initiated or responded to the connection handover and the carrier
+records are the selected carrier from the handover request and select
+messages as a hexdump.
diff --git a/contrib/wpa/hostapd/config_file.c b/contrib/wpa/hostapd/config_file.c
index 2ba7cc1..53143f7 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,7 +22,12 @@
#include "config_file.h"
-extern struct wpa_driver_ops *wpa_drivers[];
+#ifndef CONFIG_NO_RADIUS
+#ifdef EAP_SERVER
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value);
+#endif /* EAP_SERVER */
+#endif /* CONFIG_NO_RADIUS */
#ifndef CONFIG_NO_VLAN
@@ -83,7 +88,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
return -1;
}
- vlan = os_malloc(sizeof(*vlan));
+ vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while reading "
"VLAN interfaces from '%s'", fname);
@@ -91,14 +96,10 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
return -1;
}
- os_memset(vlan, 0, sizeof(*vlan));
vlan->vlan_id = vlan_id;
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
- if (bss->vlan_tail)
- bss->vlan_tail->next = vlan;
- else
- bss->vlan = vlan;
- bss->vlan_tail = vlan;
+ vlan->next = bss->vlan;
+ bss->vlan = vlan;
}
fclose(f);
@@ -136,6 +137,8 @@ static int hostapd_config_read_maclist(const char *fname,
}
while (fgets(buf, sizeof(buf), f)) {
+ int i, rem = 0;
+
line++;
if (buf[0] == '#')
@@ -150,14 +153,32 @@ static int hostapd_config_read_maclist(const char *fname,
}
if (buf[0] == '\0')
continue;
+ pos = buf;
+ if (buf[0] == '-') {
+ rem = 1;
+ pos++;
+ }
- if (hwaddr_aton(buf, addr)) {
+ if (hwaddr_aton(pos, addr)) {
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
- "line %d in '%s'", buf, line, fname);
+ "line %d in '%s'", pos, line, fname);
fclose(f);
return -1;
}
+ 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++;
+ }
+ continue;
+ }
vlan_id = 0;
pos = buf;
while (*pos != '\0' && *pos != ' ' && *pos != '\t')
@@ -195,7 +216,7 @@ static int hostapd_config_read_eap_user(const char *fname,
FILE *f;
char buf[512], *pos, *start, *pos2;
int line = 0, ret = 0, num_methods;
- struct hostapd_eap_user *user, *tail = NULL;
+ struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
if (!fname)
return 0;
@@ -229,6 +250,28 @@ static int hostapd_config_read_eap_user(const char *fname,
if (buf[0] == '\0')
continue;
+#ifndef CONFIG_NO_RADIUS
+ if (user && os_strncmp(buf, "radius_accept_attr=", 19) == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(buf + 19);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
+ buf + 19);
+ user = NULL; /* already in the BSS list */
+ goto failed;
+ }
+ if (user->accept_attr == NULL) {
+ user->accept_attr = attr;
+ } else {
+ a = user->accept_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ continue;
+ }
+#endif /* CONFIG_NO_RADIUS */
+
user = NULL;
if (buf[0] != '"' && buf[0] != '*') {
@@ -323,6 +366,10 @@ static int hostapd_config_read_eap_user(const char *fname,
EAP_TTLS_AUTH_MSCHAPV2;
goto skip_eap;
}
+ if (os_strcmp(start, "MACACL") == 0) {
+ user->macacl = 1;
+ goto skip_eap;
+ }
wpa_printf(MSG_ERROR, "Unsupported EAP type "
"'%s' on line %d in '%s'",
start, line, fname);
@@ -337,7 +384,7 @@ static int hostapd_config_read_eap_user(const char *fname,
break;
start = pos3;
}
- if (num_methods == 0 && user->ttls_auth == 0) {
+ if (num_methods == 0 && user->ttls_auth == 0 && !user->macacl) {
wpa_printf(MSG_ERROR, "No EAP types configured on "
"line %d in '%s'", line, fname);
goto failed;
@@ -447,7 +494,7 @@ static int hostapd_config_read_eap_user(const char *fname,
done:
if (tail == NULL) {
- tail = conf->eap_user = user;
+ tail = new_user = user;
} else {
tail->next = user;
tail = user;
@@ -455,17 +502,26 @@ static int hostapd_config_read_eap_user(const char *fname,
continue;
failed:
- if (user) {
- os_free(user->password);
- os_free(user->identity);
- os_free(user);
- }
+ if (user)
+ hostapd_config_free_eap_user(user);
ret = -1;
break;
}
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);
+ }
+ conf->eap_user = new_user;
+ }
+
return ret;
}
#endif /* EAP_SERVER */
@@ -636,6 +692,14 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (os_strcmp(start, "FT-SAE") == 0)
val |= WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SUITEB
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -661,49 +725,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
static int hostapd_config_parse_cipher(int line, const char *value)
{
- int val = 0, last;
- char *start, *end, *buf;
-
- buf = os_strdup(value);
- if (buf == NULL)
+ int val = wpa_parse_cipher(value);
+ if (val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, value);
return -1;
- start = buf;
-
- while (*start != '\0') {
- while (*start == ' ' || *start == '\t')
- start++;
- if (*start == '\0')
- break;
- end = start;
- while (*end != ' ' && *end != '\t' && *end != '\0')
- end++;
- last = *end == '\0';
- *end = '\0';
- if (os_strcmp(start, "CCMP") == 0)
- val |= WPA_CIPHER_CCMP;
- else if (os_strcmp(start, "GCMP") == 0)
- val |= WPA_CIPHER_GCMP;
- else if (os_strcmp(start, "TKIP") == 0)
- val |= WPA_CIPHER_TKIP;
- else if (os_strcmp(start, "WEP104") == 0)
- val |= WPA_CIPHER_WEP104;
- else if (os_strcmp(start, "WEP40") == 0)
- val |= WPA_CIPHER_WEP40;
- else if (os_strcmp(start, "NONE") == 0)
- val |= WPA_CIPHER_NONE;
- else {
- wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
- line, start);
- os_free(buf);
- return -1;
- }
-
- if (last)
- break;
- start = end + 1;
}
- os_free(buf);
-
if (val == 0) {
wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
line);
@@ -748,14 +775,14 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
}
-static int hostapd_parse_rates(int **rate_list, char *val)
+static int hostapd_parse_intlist(int **int_list, char *val)
{
int *list;
int count;
char *pos, *end;
- os_free(*rate_list);
- *rate_list = NULL;
+ os_free(*int_list);
+ *int_list = NULL;
pos = val;
count = 0;
@@ -782,37 +809,39 @@ static int hostapd_parse_rates(int **rate_list, char *val)
}
list[count] = -1;
- *rate_list = list;
+ *int_list = list;
return 0;
}
static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
{
- struct hostapd_bss_config *bss;
+ struct hostapd_bss_config **all, *bss;
if (*ifname == '\0')
return -1;
- bss = os_realloc_array(conf->bss, conf->num_bss + 1,
- sizeof(struct hostapd_bss_config));
- if (bss == NULL) {
+ all = os_realloc_array(conf->bss, conf->num_bss + 1,
+ sizeof(struct hostapd_bss_config *));
+ if (all == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"multi-BSS entry");
return -1;
}
- conf->bss = bss;
+ conf->bss = all;
- bss = &(conf->bss[conf->num_bss]);
- os_memset(bss, 0, sizeof(*bss));
+ bss = os_zalloc(sizeof(*bss));
+ if (bss == NULL)
+ return -1;
bss->radius = os_zalloc(sizeof(*bss->radius));
if (bss->radius == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"multi-BSS RADIUS data");
+ os_free(bss);
return -1;
}
- conf->num_bss++;
+ conf->bss[conf->num_bss++] = bss;
conf->last_bss = bss;
hostapd_config_defaults_bss(bss);
@@ -1060,8 +1089,8 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
if (os_strstr(capab, "[DSSS_CCK-40]"))
conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
- if (os_strstr(capab, "[PSMP]"))
- conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
+ if (os_strstr(capab, "[40-INTOLERANT]"))
+ conf->ht_capab |= HT_CAP_INFO_40MHZ_INTOLERANT;
if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
@@ -1082,8 +1111,6 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
if (os_strstr(capab, "[VHT160-80PLUS80]"))
conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
- if (os_strstr(capab, "[VHT160-80PLUS80]"))
- conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
if (os_strstr(capab, "[RXLDPC]"))
conf->vht_capab |= VHT_CAP_RXLDPC;
if (os_strstr(capab, "[SHORT-GI-80]"))
@@ -1101,15 +1128,15 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
if (os_strstr(capab, "[RX-STBC-1234]"))
conf->vht_capab |= VHT_CAP_RXSTBC_4;
if (os_strstr(capab, "[SU-BEAMFORMER]"))
- conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+ conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE;
if (os_strstr(capab, "[SU-BEAMFORMEE]"))
- conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+ conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE;
if (os_strstr(capab, "[BF-ANTENNA-2]") &&
- (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
- conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
- (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
- conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+ conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
if (os_strstr(capab, "[MU-BEAMFORMER]"))
conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
if (os_strstr(capab, "[MU-BEAMFORMEE]"))
@@ -1118,8 +1145,20 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
if (os_strstr(capab, "[HTC-VHT]"))
conf->vht_capab |= VHT_CAP_HTC_VHT;
- if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
- conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+ if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP7]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
+ else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP6]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6;
+ else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP5]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_5;
+ else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP4]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_4;
+ else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP3]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_3;
+ else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP2]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_2;
+ else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP1]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_1;
if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
(conf->vht_capab & VHT_CAP_HTC_VHT))
conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
@@ -1135,141 +1174,6 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
#endif /* CONFIG_IEEE80211AC */
-static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
- struct hostapd_config *conf)
-{
- if (bss->ieee802_1x && !bss->eap_server &&
- !bss->radius->auth_servers) {
- wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
- "EAP authenticator configured).");
- return -1;
- }
-
- if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
- bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
- wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
- "RADIUS checking (macaddr_acl=2) enabled.");
- return -1;
- }
-
- if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
- bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
- bss->ssid.wpa_psk_file == NULL &&
- (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
- bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
- wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
- "is not configured.");
- return -1;
- }
-
- if (hostapd_mac_comp_empty(bss->bssid) != 0) {
- size_t i;
-
- for (i = 0; i < conf->num_bss; i++) {
- if ((&conf->bss[i] != bss) &&
- (hostapd_mac_comp(conf->bss[i].bssid,
- bss->bssid) == 0)) {
- wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
- " on interface '%s' and '%s'.",
- MAC2STR(bss->bssid),
- conf->bss[i].iface, bss->iface);
- return -1;
- }
- }
- }
-
-#ifdef CONFIG_IEEE80211R
- if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
- (bss->nas_identifier == NULL ||
- os_strlen(bss->nas_identifier) < 1 ||
- os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
- wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
- "nas_identifier to be configured as a 1..48 octet "
- "string");
- return -1;
- }
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211N
- if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
- bss->disable_11n = 1;
- wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
- "allowed, disabling HT capabilites");
- }
-
- if (conf->ieee80211n &&
- bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11n = 1;
- wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
- "allowed, disabling HT capabilities");
- }
-
- if (conf->ieee80211n && bss->wpa &&
- !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
- !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
- bss->disable_11n = 1;
- wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
- "requires CCMP/GCMP to be enabled, disabling HT "
- "capabilities");
- }
-#endif /* CONFIG_IEEE80211N */
-
-#ifdef CONFIG_WPS2
- if (bss->wps_state && bss->ignore_broadcast_ssid) {
- wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
- "configuration forced WPS to be disabled");
- bss->wps_state = 0;
- }
-
- if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
- wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
- "disabled");
- bss->wps_state = 0;
- }
-
- if (bss->wps_state && bss->wpa &&
- (!(bss->wpa & 2) ||
- !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
- wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
- "WPA2/CCMP forced WPS to be disabled");
- bss->wps_state = 0;
- }
-#endif /* CONFIG_WPS2 */
-
-#ifdef CONFIG_HS20
- if (bss->hs20 &&
- (!(bss->wpa & 2) ||
- !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
- wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
- "configuration is required for Hotspot 2.0 "
- "functionality");
- return -1;
- }
-#endif /* CONFIG_HS20 */
-
- return 0;
-}
-
-
-static int hostapd_config_check(struct hostapd_config *conf)
-{
- size_t i;
-
- if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
- wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
- "setting the country_code");
- return -1;
- }
-
- for (i = 0; i < conf->num_bss; i++) {
- if (hostapd_config_check_bss(&conf->bss[i], conf))
- return -1;
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_INTERWORKING
static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
int line)
@@ -1306,26 +1210,34 @@ static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
static int parse_lang_string(struct hostapd_lang_string **array,
unsigned int *count, char *pos)
{
- char *sep;
- size_t clen, nlen;
+ char *sep, *str = NULL;
+ size_t clen, nlen, slen;
struct hostapd_lang_string *ls;
+ int ret = -1;
+
+ if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) {
+ str = wpa_config_parse_string(pos, &slen);
+ if (!str)
+ return -1;
+ pos = str;
+ }
sep = os_strchr(pos, ':');
if (sep == NULL)
- return -1;
+ goto fail;
*sep++ = '\0';
clen = os_strlen(pos);
- if (clen < 2)
- return -1;
+ if (clen < 2 || clen > sizeof(ls->lang))
+ goto fail;
nlen = os_strlen(sep);
if (nlen > 252)
- return -1;
+ goto fail;
ls = os_realloc_array(*array, *count + 1,
sizeof(struct hostapd_lang_string));
if (ls == NULL)
- return -1;
+ goto fail;
*array = ls;
ls = &(*array)[*count];
@@ -1336,7 +1248,10 @@ static int parse_lang_string(struct hostapd_lang_string **array,
ls->name_len = nlen;
os_memcpy(ls->name, sep, nlen);
- return 0;
+ ret = 0;
+fail:
+ os_free(str);
+ return ret;
}
@@ -1363,7 +1278,7 @@ static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
count = 1;
for (pos = buf; *pos; pos++) {
- if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
+ if ((*pos < '0' || *pos > '9') && *pos != ';' && *pos != ',')
goto fail;
if (*pos == ';')
count++;
@@ -1567,6 +1482,47 @@ fail:
return -1;
}
+
+static int parse_qos_map_set(struct hostapd_bss_config *bss,
+ char *buf, int line)
+{
+ u8 qos_map_set[16 + 2 * 21], count = 0;
+ char *pos = buf;
+ int val;
+
+ for (;;) {
+ if (count == sizeof(qos_map_set)) {
+ wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set "
+ "parameters '%s'", line, buf);
+ return -1;
+ }
+
+ val = atoi(pos);
+ if (val > 255 || val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set "
+ "'%s'", line, buf);
+ return -1;
+ }
+
+ qos_map_set[count++] = val;
+ pos = os_strchr(pos, ',');
+ if (!pos)
+ break;
+ pos++;
+ }
+
+ if (count < 16 || count & 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'",
+ line, buf);
+ return -1;
+ }
+
+ os_memcpy(bss->qos_map_set, qos_map_set, count);
+ bss->qos_map_set_len = count;
+
+ return 0;
+}
+
#endif /* CONFIG_INTERWORKING */
@@ -1664,7 +1620,7 @@ static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
fail:
wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
- line, pos);
+ line, buf);
os_free(wan_metrics);
return -1;
}
@@ -1681,6 +1637,197 @@ static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
}
return 0;
}
+
+
+static int hs20_parse_icon(struct hostapd_bss_config *bss, char *pos)
+{
+ struct hs20_icon *icon;
+ char *end;
+
+ icon = os_realloc_array(bss->hs20_icons, bss->hs20_icons_count + 1,
+ sizeof(struct hs20_icon));
+ if (icon == NULL)
+ return -1;
+ bss->hs20_icons = icon;
+ icon = &bss->hs20_icons[bss->hs20_icons_count];
+ os_memset(icon, 0, sizeof(*icon));
+
+ icon->width = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ pos++;
+
+ icon->height = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ pos++;
+
+ end = os_strchr(pos, ':');
+ if (end == NULL || end - pos > 3)
+ return -1;
+ os_memcpy(icon->language, pos, end - pos);
+ pos = end + 1;
+
+ end = os_strchr(pos, ':');
+ if (end == NULL || end - pos > 255)
+ return -1;
+ os_memcpy(icon->type, pos, end - pos);
+ pos = end + 1;
+
+ end = os_strchr(pos, ':');
+ if (end == NULL || end - pos > 255)
+ return -1;
+ os_memcpy(icon->name, pos, end - pos);
+ pos = end + 1;
+
+ if (os_strlen(pos) > 255)
+ return -1;
+ os_memcpy(icon->file, pos, os_strlen(pos));
+
+ bss->hs20_icons_count++;
+
+ return 0;
+}
+
+
+static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
+ char *pos, int line)
+{
+ size_t slen;
+ char *str;
+
+ str = wpa_config_parse_string(pos, &slen);
+ if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
+ os_free(str);
+ return -1;
+ }
+
+ os_memcpy(bss->osu_ssid, str, slen);
+ bss->osu_ssid_len = slen;
+ os_free(str);
+
+ return 0;
+}
+
+
+static int hs20_parse_osu_server_uri(struct hostapd_bss_config *bss,
+ char *pos, int line)
+{
+ struct hs20_osu_provider *p;
+
+ p = os_realloc_array(bss->hs20_osu_providers,
+ bss->hs20_osu_providers_count + 1, sizeof(*p));
+ if (p == NULL)
+ return -1;
+
+ bss->hs20_osu_providers = p;
+ bss->last_osu = &bss->hs20_osu_providers[bss->hs20_osu_providers_count];
+ bss->hs20_osu_providers_count++;
+ os_memset(bss->last_osu, 0, sizeof(*p));
+ bss->last_osu->server_uri = os_strdup(pos);
+
+ return 0;
+}
+
+
+static int hs20_parse_osu_friendly_name(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;
+ }
+
+ if (parse_lang_string(&bss->last_osu->friendly_name,
+ &bss->last_osu->friendly_name_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid osu_friendly_name '%s'",
+ line, pos);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hs20_parse_osu_nai(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_nai);
+ bss->last_osu->osu_nai = os_strdup(pos);
+ if (bss->last_osu->osu_nai == NULL)
+ return -1;
+
+ return 0;
+}
+
+
+static int hs20_parse_osu_method_list(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;
+ }
+
+ if (hostapd_parse_intlist(&bss->last_osu->method_list, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid osu_method_list", line);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hs20_parse_osu_icon(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ char **n;
+ struct hs20_osu_provider *p = bss->last_osu;
+
+ if (p == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
+ return -1;
+ }
+
+ n = os_realloc_array(p->icons, p->icons_count + 1, sizeof(char *));
+ if (n == NULL)
+ return -1;
+ p->icons = n;
+ p->icons[p->icons_count] = os_strdup(pos);
+ if (p->icons[p->icons_count] == NULL)
+ return -1;
+ p->icons_count++;
+
+ return 0;
+}
+
+
+static int hs20_parse_osu_service_desc(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;
+ }
+
+ if (parse_lang_string(&bss->last_osu->service_desc,
+ &bss->last_osu->service_desc_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid osu_service_desc '%s'",
+ line, pos);
+ return -1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_HS20 */
@@ -1709,1302 +1856,1434 @@ static struct wpabuf * hostapd_parse_bin(const char *buf)
#endif /* CONFIG_WPS_NFC */
+#ifdef CONFIG_ACS
+static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
+ char *pos)
+{
+ struct acs_bias *bias = NULL, *tmp;
+ unsigned int num = 0;
+ char *end;
+
+ while (*pos) {
+ tmp = os_realloc_array(bias, num + 1, sizeof(*bias));
+ if (!tmp)
+ goto fail;
+ bias = tmp;
+
+ bias[num].channel = atoi(pos);
+ if (bias[num].channel <= 0)
+ goto fail;
+ pos = os_strchr(pos, ':');
+ if (!pos)
+ goto fail;
+ pos++;
+ bias[num].bias = strtod(pos, &end);
+ if (end == pos || bias[num].bias < 0.0)
+ goto fail;
+ pos = end;
+ if (*pos != ' ' && *pos != '\0')
+ goto fail;
+ num++;
+ }
+
+ os_free(conf->acs_chan_bias);
+ conf->acs_chan_bias = bias;
+ conf->num_acs_chan_bias = num;
+
+ return 0;
+fail:
+ os_free(bias);
+ return -1;
+}
+#endif /* CONFIG_ACS */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
char *buf, char *pos, int line)
{
- int errors = 0;
-
- {
- if (os_strcmp(buf, "interface") == 0) {
- os_strlcpy(conf->bss[0].iface, pos,
- sizeof(conf->bss[0].iface));
- } else if (os_strcmp(buf, "bridge") == 0) {
- os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
- } else if (os_strcmp(buf, "wds_bridge") == 0) {
- os_strlcpy(bss->wds_bridge, pos,
- sizeof(bss->wds_bridge));
- } else if (os_strcmp(buf, "driver") == 0) {
- int j;
- /* clear to get error below if setting is invalid */
- conf->driver = NULL;
- for (j = 0; wpa_drivers[j]; j++) {
- if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
- {
- conf->driver = wpa_drivers[j];
- break;
- }
- }
- if (conf->driver == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: invalid/"
- "unknown driver '%s'", line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "debug") == 0) {
- wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
- "configuration variable is not used "
- "anymore", line);
- } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
- bss->logger_syslog_level = atoi(pos);
- } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
- bss->logger_stdout_level = atoi(pos);
- } else if (os_strcmp(buf, "logger_syslog") == 0) {
- bss->logger_syslog = atoi(pos);
- } else if (os_strcmp(buf, "logger_stdout") == 0) {
- bss->logger_stdout = atoi(pos);
- } else if (os_strcmp(buf, "dump_file") == 0) {
- bss->dump_log_name = os_strdup(pos);
- } else if (os_strcmp(buf, "ssid") == 0) {
- bss->ssid.ssid_len = os_strlen(pos);
- if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
- bss->ssid.ssid_len < 1) {
- wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
- "'%s'", line, pos);
- errors++;
- } else {
- os_memcpy(bss->ssid.ssid, pos,
- bss->ssid.ssid_len);
- bss->ssid.ssid_set = 1;
- }
- } else if (os_strcmp(buf, "ssid2") == 0) {
- size_t slen;
- char *str = wpa_config_parse_string(pos, &slen);
- if (str == NULL || slen < 1 ||
- slen > HOSTAPD_MAX_SSID_LEN) {
- wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
- "'%s'", line, pos);
- errors++;
- } else {
- os_memcpy(bss->ssid.ssid, str, slen);
- bss->ssid.ssid_len = slen;
- bss->ssid.ssid_set = 1;
+ if (os_strcmp(buf, "interface") == 0) {
+ os_strlcpy(conf->bss[0]->iface, pos,
+ sizeof(conf->bss[0]->iface));
+ } else if (os_strcmp(buf, "bridge") == 0) {
+ os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+ } else if (os_strcmp(buf, "vlan_bridge") == 0) {
+ os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
+ } else if (os_strcmp(buf, "wds_bridge") == 0) {
+ os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
+ } else if (os_strcmp(buf, "driver") == 0) {
+ int j;
+ /* clear to get error below if setting is invalid */
+ conf->driver = NULL;
+ for (j = 0; wpa_drivers[j]; j++) {
+ if (os_strcmp(pos, wpa_drivers[j]->name) == 0) {
+ conf->driver = wpa_drivers[j];
+ break;
}
+ }
+ if (conf->driver == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid/unknown driver '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "driver_params") == 0) {
+ os_free(conf->driver_params);
+ conf->driver_params = os_strdup(pos);
+ } else if (os_strcmp(buf, "debug") == 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' configuration variable is not used anymore",
+ line);
+ } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
+ bss->logger_syslog_level = atoi(pos);
+ } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
+ bss->logger_stdout_level = atoi(pos);
+ } else if (os_strcmp(buf, "logger_syslog") == 0) {
+ bss->logger_syslog = atoi(pos);
+ } else if (os_strcmp(buf, "logger_stdout") == 0) {
+ bss->logger_stdout = atoi(pos);
+ } else if (os_strcmp(buf, "dump_file") == 0) {
+ wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore",
+ line);
+ } else if (os_strcmp(buf, "ssid") == 0) {
+ bss->ssid.ssid_len = os_strlen(pos);
+ if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+ bss->ssid.ssid_len < 1) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
+ line, pos);
+ return 1;
+ }
+ os_memcpy(bss->ssid.ssid, pos, bss->ssid.ssid_len);
+ bss->ssid.ssid_set = 1;
+ } else if (os_strcmp(buf, "ssid2") == 0) {
+ size_t slen;
+ char *str = wpa_config_parse_string(pos, &slen);
+ if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
+ line, pos);
os_free(str);
- } else if (os_strcmp(buf, "utf8_ssid") == 0) {
- bss->ssid.utf8_ssid = atoi(pos) > 0;
- } else if (os_strcmp(buf, "macaddr_acl") == 0) {
- bss->macaddr_acl = atoi(pos);
- if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
- bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
- bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
- wpa_printf(MSG_ERROR, "Line %d: unknown "
- "macaddr_acl %d",
- line, bss->macaddr_acl);
- }
- } else if (os_strcmp(buf, "accept_mac_file") == 0) {
- if (hostapd_config_read_maclist(pos, &bss->accept_mac,
- &bss->num_accept_mac))
- {
- wpa_printf(MSG_ERROR, "Line %d: Failed to "
- "read accept_mac_file '%s'",
- line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "deny_mac_file") == 0) {
- if (hostapd_config_read_maclist(pos, &bss->deny_mac,
- &bss->num_deny_mac)) {
- wpa_printf(MSG_ERROR, "Line %d: Failed to "
- "read deny_mac_file '%s'",
- line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "wds_sta") == 0) {
- bss->wds_sta = atoi(pos);
- } else if (os_strcmp(buf, "ap_isolate") == 0) {
- bss->isolate = atoi(pos);
- } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
- bss->ap_max_inactivity = atoi(pos);
- } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
- bss->skip_inactivity_poll = atoi(pos);
- } else if (os_strcmp(buf, "country_code") == 0) {
- os_memcpy(conf->country, pos, 2);
- /* FIX: make this configurable */
- conf->country[2] = ' ';
- } else if (os_strcmp(buf, "ieee80211d") == 0) {
- conf->ieee80211d = atoi(pos);
- } else if (os_strcmp(buf, "ieee8021x") == 0) {
- bss->ieee802_1x = atoi(pos);
- } else if (os_strcmp(buf, "eapol_version") == 0) {
- bss->eapol_version = atoi(pos);
- if (bss->eapol_version < 1 ||
- bss->eapol_version > 2) {
- wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
- "version (%d): '%s'.",
- line, bss->eapol_version, pos);
- errors++;
- } else
- wpa_printf(MSG_DEBUG, "eapol_version=%d",
- bss->eapol_version);
+ return 1;
+ }
+ os_memcpy(bss->ssid.ssid, str, slen);
+ bss->ssid.ssid_len = slen;
+ bss->ssid.ssid_set = 1;
+ os_free(str);
+ } else if (os_strcmp(buf, "utf8_ssid") == 0) {
+ bss->ssid.utf8_ssid = atoi(pos) > 0;
+ } else if (os_strcmp(buf, "macaddr_acl") == 0) {
+ bss->macaddr_acl = atoi(pos);
+ if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+ bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown macaddr_acl %d",
+ line, bss->macaddr_acl);
+ }
+ } else if (os_strcmp(buf, "accept_mac_file") == 0) {
+ if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+ &bss->num_accept_mac)) {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to read accept_mac_file '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "deny_mac_file") == 0) {
+ if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+ &bss->num_deny_mac)) {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to read deny_mac_file '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wds_sta") == 0) {
+ bss->wds_sta = atoi(pos);
+ } else if (os_strcmp(buf, "start_disabled") == 0) {
+ bss->start_disabled = atoi(pos);
+ } else if (os_strcmp(buf, "ap_isolate") == 0) {
+ bss->isolate = atoi(pos);
+ } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
+ bss->ap_max_inactivity = atoi(pos);
+ } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
+ bss->skip_inactivity_poll = atoi(pos);
+ } else if (os_strcmp(buf, "country_code") == 0) {
+ os_memcpy(conf->country, pos, 2);
+ /* FIX: make this configurable */
+ conf->country[2] = ' ';
+ } else if (os_strcmp(buf, "ieee80211d") == 0) {
+ conf->ieee80211d = atoi(pos);
+ } else if (os_strcmp(buf, "ieee80211h") == 0) {
+ conf->ieee80211h = atoi(pos);
+ } else if (os_strcmp(buf, "ieee8021x") == 0) {
+ bss->ieee802_1x = atoi(pos);
+ } else if (os_strcmp(buf, "eapol_version") == 0) {
+ bss->eapol_version = atoi(pos);
+ if (bss->eapol_version < 1 || bss->eapol_version > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid EAPOL version (%d): '%s'.",
+ line, bss->eapol_version, pos);
+ return 1;
+ }
+ wpa_printf(MSG_DEBUG, "eapol_version=%d", bss->eapol_version);
#ifdef EAP_SERVER
- } else if (os_strcmp(buf, "eap_authenticator") == 0) {
- bss->eap_server = atoi(pos);
- wpa_printf(MSG_ERROR, "Line %d: obsolete "
- "eap_authenticator used; this has been "
- "renamed to eap_server", line);
- } else if (os_strcmp(buf, "eap_server") == 0) {
- bss->eap_server = atoi(pos);
- } else if (os_strcmp(buf, "eap_user_file") == 0) {
- if (hostapd_config_read_eap_user(pos, bss))
- errors++;
- } else if (os_strcmp(buf, "ca_cert") == 0) {
- os_free(bss->ca_cert);
- bss->ca_cert = os_strdup(pos);
- } else if (os_strcmp(buf, "server_cert") == 0) {
- os_free(bss->server_cert);
- bss->server_cert = os_strdup(pos);
- } else if (os_strcmp(buf, "private_key") == 0) {
- os_free(bss->private_key);
- bss->private_key = os_strdup(pos);
- } else if (os_strcmp(buf, "private_key_passwd") == 0) {
- os_free(bss->private_key_passwd);
- bss->private_key_passwd = os_strdup(pos);
- } else if (os_strcmp(buf, "check_crl") == 0) {
- bss->check_crl = atoi(pos);
- } else if (os_strcmp(buf, "dh_file") == 0) {
- os_free(bss->dh_file);
- bss->dh_file = os_strdup(pos);
- } else if (os_strcmp(buf, "fragment_size") == 0) {
- bss->fragment_size = atoi(pos);
+ } else if (os_strcmp(buf, "eap_authenticator") == 0) {
+ bss->eap_server = atoi(pos);
+ wpa_printf(MSG_ERROR, "Line %d: obsolete eap_authenticator used; this has been renamed to eap_server", line);
+ } else if (os_strcmp(buf, "eap_server") == 0) {
+ bss->eap_server = atoi(pos);
+ } else if (os_strcmp(buf, "eap_user_file") == 0) {
+ if (hostapd_config_read_eap_user(pos, bss))
+ return 1;
+ } else if (os_strcmp(buf, "ca_cert") == 0) {
+ os_free(bss->ca_cert);
+ bss->ca_cert = os_strdup(pos);
+ } else if (os_strcmp(buf, "server_cert") == 0) {
+ os_free(bss->server_cert);
+ bss->server_cert = os_strdup(pos);
+ } else if (os_strcmp(buf, "private_key") == 0) {
+ os_free(bss->private_key);
+ bss->private_key = os_strdup(pos);
+ } else if (os_strcmp(buf, "private_key_passwd") == 0) {
+ os_free(bss->private_key_passwd);
+ bss->private_key_passwd = os_strdup(pos);
+ } else if (os_strcmp(buf, "check_crl") == 0) {
+ bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
+ os_free(bss->ocsp_stapling_response);
+ bss->ocsp_stapling_response = os_strdup(pos);
+ } else if (os_strcmp(buf, "dh_file") == 0) {
+ os_free(bss->dh_file);
+ bss->dh_file = os_strdup(pos);
+ } else if (os_strcmp(buf, "openssl_ciphers") == 0) {
+ os_free(bss->openssl_ciphers);
+ bss->openssl_ciphers = os_strdup(pos);
+ } else if (os_strcmp(buf, "fragment_size") == 0) {
+ bss->fragment_size = atoi(pos);
#ifdef EAP_SERVER_FAST
- } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
- os_free(bss->pac_opaque_encr_key);
- bss->pac_opaque_encr_key = os_malloc(16);
- if (bss->pac_opaque_encr_key == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: No memory for "
- "pac_opaque_encr_key", line);
- errors++;
- } else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
- 16)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "pac_opaque_encr_key", line);
- errors++;
- }
- } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
- size_t idlen = os_strlen(pos);
- if (idlen & 1) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "eap_fast_a_id", line);
- errors++;
- } else {
- os_free(bss->eap_fast_a_id);
- bss->eap_fast_a_id = os_malloc(idlen / 2);
- if (bss->eap_fast_a_id == NULL ||
- hexstr2bin(pos, bss->eap_fast_a_id,
- idlen / 2)) {
- wpa_printf(MSG_ERROR, "Line %d: "
- "Failed to parse "
- "eap_fast_a_id", line);
- errors++;
- } else
- bss->eap_fast_a_id_len = idlen / 2;
- }
- } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
- os_free(bss->eap_fast_a_id_info);
- bss->eap_fast_a_id_info = os_strdup(pos);
- } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
- bss->eap_fast_prov = atoi(pos);
- } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
- bss->pac_key_lifetime = atoi(pos);
- } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
- bss->pac_key_refresh_time = atoi(pos);
+ } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
+ os_free(bss->pac_opaque_encr_key);
+ bss->pac_opaque_encr_key = os_malloc(16);
+ if (bss->pac_opaque_encr_key == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: No memory for pac_opaque_encr_key",
+ line);
+ return 1;
+ } else if (hexstr2bin(pos, bss->pac_opaque_encr_key, 16)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid pac_opaque_encr_key",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
+ size_t idlen = os_strlen(pos);
+ if (idlen & 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid eap_fast_a_id",
+ line);
+ return 1;
+ }
+ os_free(bss->eap_fast_a_id);
+ bss->eap_fast_a_id = os_malloc(idlen / 2);
+ if (bss->eap_fast_a_id == NULL ||
+ hexstr2bin(pos, bss->eap_fast_a_id, idlen / 2)) {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to parse eap_fast_a_id",
+ line);
+ os_free(bss->eap_fast_a_id);
+ bss->eap_fast_a_id = NULL;
+ return 1;
+ } else {
+ bss->eap_fast_a_id_len = idlen / 2;
+ }
+ } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
+ os_free(bss->eap_fast_a_id_info);
+ bss->eap_fast_a_id_info = os_strdup(pos);
+ } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
+ bss->eap_fast_prov = atoi(pos);
+ } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
+ bss->pac_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
+ bss->pac_key_refresh_time = atoi(pos);
#endif /* EAP_SERVER_FAST */
#ifdef EAP_SERVER_SIM
- } else if (os_strcmp(buf, "eap_sim_db") == 0) {
- os_free(bss->eap_sim_db);
- bss->eap_sim_db = os_strdup(pos);
- } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
- bss->eap_sim_aka_result_ind = atoi(pos);
+ } else if (os_strcmp(buf, "eap_sim_db") == 0) {
+ os_free(bss->eap_sim_db);
+ bss->eap_sim_db = os_strdup(pos);
+ } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
+ bss->eap_sim_aka_result_ind = atoi(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
- } else if (os_strcmp(buf, "tnc") == 0) {
- bss->tnc = atoi(pos);
+ } else if (os_strcmp(buf, "tnc") == 0) {
+ bss->tnc = atoi(pos);
#endif /* EAP_SERVER_TNC */
#ifdef EAP_SERVER_PWD
- } else if (os_strcmp(buf, "pwd_group") == 0) {
- bss->pwd_group = atoi(pos);
+ } else if (os_strcmp(buf, "pwd_group") == 0) {
+ bss->pwd_group = atoi(pos);
#endif /* EAP_SERVER_PWD */
+ } else if (os_strcmp(buf, "eap_server_erp") == 0) {
+ bss->eap_server_erp = atoi(pos);
#endif /* EAP_SERVER */
- } else if (os_strcmp(buf, "eap_message") == 0) {
- char *term;
- bss->eap_req_id_text = os_strdup(pos);
- if (bss->eap_req_id_text == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Failed to "
- "allocate memory for "
- "eap_req_id_text", line);
- errors++;
- return errors;
- }
- bss->eap_req_id_text_len =
- os_strlen(bss->eap_req_id_text);
- term = os_strstr(bss->eap_req_id_text, "\\0");
- if (term) {
- *term++ = '\0';
- os_memmove(term, term + 1,
- bss->eap_req_id_text_len -
- (term - bss->eap_req_id_text) - 1);
- bss->eap_req_id_text_len--;
- }
- } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
- bss->default_wep_key_len = atoi(pos);
- if (bss->default_wep_key_len > 13) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
- "key len %lu (= %lu bits)", line,
- (unsigned long)
- bss->default_wep_key_len,
- (unsigned long)
- bss->default_wep_key_len * 8);
- errors++;
- }
- } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
- bss->individual_wep_key_len = atoi(pos);
- if (bss->individual_wep_key_len < 0 ||
- bss->individual_wep_key_len > 13) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
- "key len %d (= %d bits)", line,
- bss->individual_wep_key_len,
- bss->individual_wep_key_len * 8);
- errors++;
- }
- } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
- bss->wep_rekeying_period = atoi(pos);
- if (bss->wep_rekeying_period < 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "period %d",
- line, bss->wep_rekeying_period);
- errors++;
- }
- } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
- bss->eap_reauth_period = atoi(pos);
- if (bss->eap_reauth_period < 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "period %d",
- line, bss->eap_reauth_period);
- errors++;
- }
- } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
- bss->eapol_key_index_workaround = atoi(pos);
+ } else if (os_strcmp(buf, "eap_message") == 0) {
+ char *term;
+ os_free(bss->eap_req_id_text);
+ bss->eap_req_id_text = os_strdup(pos);
+ if (bss->eap_req_id_text == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to allocate memory for eap_req_id_text",
+ line);
+ return 1;
+ }
+ bss->eap_req_id_text_len = os_strlen(bss->eap_req_id_text);
+ term = os_strstr(bss->eap_req_id_text, "\\0");
+ if (term) {
+ *term++ = '\0';
+ os_memmove(term, term + 1,
+ bss->eap_req_id_text_len -
+ (term - bss->eap_req_id_text) - 1);
+ bss->eap_req_id_text_len--;
+ }
+ } else if (os_strcmp(buf, "erp_send_reauth_start") == 0) {
+ bss->erp_send_reauth_start = atoi(pos);
+ } else if (os_strcmp(buf, "erp_domain") == 0) {
+ 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);
+ return 1;
+ }
+ } 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);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
+ bss->wep_rekeying_period = atoi(pos);
+ if (bss->wep_rekeying_period < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid period %d",
+ line, bss->wep_rekeying_period);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
+ bss->eap_reauth_period = atoi(pos);
+ if (bss->eap_reauth_period < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid period %d",
+ line, bss->eap_reauth_period);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
+ bss->eapol_key_index_workaround = atoi(pos);
#ifdef CONFIG_IAPP
- } else if (os_strcmp(buf, "iapp_interface") == 0) {
- bss->ieee802_11f = 1;
- os_strlcpy(bss->iapp_iface, pos,
- sizeof(bss->iapp_iface));
+ } else if (os_strcmp(buf, "iapp_interface") == 0) {
+ bss->ieee802_11f = 1;
+ os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface));
#endif /* CONFIG_IAPP */
- } else if (os_strcmp(buf, "own_ip_addr") == 0) {
- if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid IP "
- "address '%s'", line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "nas_identifier") == 0) {
- bss->nas_identifier = os_strdup(pos);
+ } else if (os_strcmp(buf, "own_ip_addr") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "nas_identifier") == 0) {
+ os_free(bss->nas_identifier);
+ bss->nas_identifier = os_strdup(pos);
#ifndef CONFIG_NO_RADIUS
- } else if (os_strcmp(buf, "auth_server_addr") == 0) {
- if (hostapd_config_read_radius_addr(
- &bss->radius->auth_servers,
- &bss->radius->num_auth_servers, pos, 1812,
- &bss->radius->auth_server)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid IP "
- "address '%s'", line, pos);
- errors++;
- }
- } else if (bss->radius->auth_server &&
- os_strcmp(buf, "auth_server_port") == 0) {
- bss->radius->auth_server->port = atoi(pos);
- } else if (bss->radius->auth_server &&
- os_strcmp(buf, "auth_server_shared_secret") == 0) {
- int len = os_strlen(pos);
- if (len == 0) {
- /* RFC 2865, Ch. 3 */
- wpa_printf(MSG_ERROR, "Line %d: empty shared "
- "secret is not allowed.", line);
- errors++;
- }
- bss->radius->auth_server->shared_secret =
- (u8 *) os_strdup(pos);
- bss->radius->auth_server->shared_secret_len = len;
- } else if (os_strcmp(buf, "acct_server_addr") == 0) {
- if (hostapd_config_read_radius_addr(
- &bss->radius->acct_servers,
- &bss->radius->num_acct_servers, pos, 1813,
- &bss->radius->acct_server)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid IP "
- "address '%s'", line, pos);
- errors++;
- }
- } else if (bss->radius->acct_server &&
- os_strcmp(buf, "acct_server_port") == 0) {
- bss->radius->acct_server->port = atoi(pos);
- } else if (bss->radius->acct_server &&
- os_strcmp(buf, "acct_server_shared_secret") == 0) {
- int len = os_strlen(pos);
- if (len == 0) {
- /* RFC 2865, Ch. 3 */
- wpa_printf(MSG_ERROR, "Line %d: empty shared "
- "secret is not allowed.", line);
- errors++;
- }
- bss->radius->acct_server->shared_secret =
- (u8 *) os_strdup(pos);
- bss->radius->acct_server->shared_secret_len = len;
- } else if (os_strcmp(buf, "radius_retry_primary_interval") ==
- 0) {
- bss->radius->retry_primary_interval = atoi(pos);
- } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
- {
- bss->acct_interim_interval = atoi(pos);
- } else if (os_strcmp(buf, "radius_request_cui") == 0) {
- bss->radius_request_cui = atoi(pos);
- } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
- struct hostapd_radius_attr *attr, *a;
- attr = hostapd_parse_radius_attr(pos);
- if (attr == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "radius_auth_req_attr", line);
- errors++;
- } else if (bss->radius_auth_req_attr == NULL) {
- bss->radius_auth_req_attr = attr;
- } else {
- a = bss->radius_auth_req_attr;
- while (a->next)
- a = a->next;
- a->next = attr;
- }
- } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
- struct hostapd_radius_attr *attr, *a;
- attr = hostapd_parse_radius_attr(pos);
- if (attr == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "radius_acct_req_attr", line);
- errors++;
- } else if (bss->radius_acct_req_attr == NULL) {
- bss->radius_acct_req_attr = attr;
- } else {
- a = bss->radius_acct_req_attr;
- while (a->next)
- a = a->next;
- a->next = attr;
- }
- } else if (os_strcmp(buf, "radius_das_port") == 0) {
- bss->radius_das_port = atoi(pos);
- } else if (os_strcmp(buf, "radius_das_client") == 0) {
- if (hostapd_parse_das_client(bss, pos) < 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "DAS client", line);
- errors++;
- }
- } else if (os_strcmp(buf, "radius_das_time_window") == 0) {
- bss->radius_das_time_window = atoi(pos);
- } else if (os_strcmp(buf, "radius_das_require_event_timestamp")
- == 0) {
- bss->radius_das_require_event_timestamp = atoi(pos);
+ } else if (os_strcmp(buf, "radius_client_addr") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->radius->client_addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ bss->radius->force_client_addr = 1;
+ } else if (os_strcmp(buf, "auth_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &bss->radius->auth_servers,
+ &bss->radius->num_auth_servers, pos, 1812,
+ &bss->radius->auth_server)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_addr_replace") == 0) {
+ if (hostapd_parse_ip_addr(pos,
+ &bss->radius->auth_server->addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_port") == 0) {
+ bss->radius->auth_server->port = atoi(pos);
+ } else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_shared_secret") == 0) {
+ int len = os_strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ wpa_printf(MSG_ERROR, "Line %d: empty shared secret is not allowed",
+ line);
+ return 1;
+ }
+ os_free(bss->radius->auth_server->shared_secret);
+ bss->radius->auth_server->shared_secret = (u8 *) os_strdup(pos);
+ bss->radius->auth_server->shared_secret_len = len;
+ } else if (os_strcmp(buf, "acct_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &bss->radius->acct_servers,
+ &bss->radius->num_acct_servers, pos, 1813,
+ &bss->radius->acct_server)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_addr_replace") == 0) {
+ if (hostapd_parse_ip_addr(pos,
+ &bss->radius->acct_server->addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_port") == 0) {
+ bss->radius->acct_server->port = atoi(pos);
+ } else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_shared_secret") == 0) {
+ int len = os_strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ wpa_printf(MSG_ERROR, "Line %d: empty shared secret is not allowed",
+ line);
+ return 1;
+ }
+ os_free(bss->radius->acct_server->shared_secret);
+ bss->radius->acct_server->shared_secret = (u8 *) os_strdup(pos);
+ bss->radius->acct_server->shared_secret_len = len;
+ } else if (os_strcmp(buf, "radius_retry_primary_interval") == 0) {
+ bss->radius->retry_primary_interval = atoi(pos);
+ } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) {
+ bss->acct_interim_interval = atoi(pos);
+ } else if (os_strcmp(buf, "radius_request_cui") == 0) {
+ bss->radius_request_cui = atoi(pos);
+ } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(pos);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid radius_auth_req_attr",
+ line);
+ return 1;
+ } else if (bss->radius_auth_req_attr == NULL) {
+ bss->radius_auth_req_attr = attr;
+ } else {
+ a = bss->radius_auth_req_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(pos);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid radius_acct_req_attr",
+ line);
+ return 1;
+ } else if (bss->radius_acct_req_attr == NULL) {
+ bss->radius_acct_req_attr = attr;
+ } else {
+ a = bss->radius_acct_req_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ } else if (os_strcmp(buf, "radius_das_port") == 0) {
+ bss->radius_das_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_client") == 0) {
+ if (hostapd_parse_das_client(bss, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid DAS client",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "radius_das_time_window") == 0) {
+ bss->radius_das_time_window = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
+ bss->radius_das_require_event_timestamp = atoi(pos);
#endif /* CONFIG_NO_RADIUS */
- } else if (os_strcmp(buf, "auth_algs") == 0) {
- bss->auth_algs = atoi(pos);
- if (bss->auth_algs == 0) {
- wpa_printf(MSG_ERROR, "Line %d: no "
- "authentication algorithms allowed",
- line);
- errors++;
- }
- } else if (os_strcmp(buf, "max_num_sta") == 0) {
- bss->max_num_sta = atoi(pos);
- if (bss->max_num_sta < 0 ||
- bss->max_num_sta > MAX_STA_COUNT) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "max_num_sta=%d; allowed range "
- "0..%d", line, bss->max_num_sta,
- MAX_STA_COUNT);
- errors++;
- }
- } else if (os_strcmp(buf, "wpa") == 0) {
- bss->wpa = atoi(pos);
- } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
- bss->wpa_group_rekey = atoi(pos);
- } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
- bss->wpa_strict_rekey = atoi(pos);
- } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
- bss->wpa_gmk_rekey = atoi(pos);
- } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
- bss->wpa_ptk_rekey = atoi(pos);
- } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
- int len = os_strlen(pos);
- if (len < 8 || len > 63) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
- "passphrase length %d (expected "
- "8..63)", line, len);
- errors++;
- } else {
- os_free(bss->ssid.wpa_passphrase);
- bss->ssid.wpa_passphrase = os_strdup(pos);
- os_free(bss->ssid.wpa_psk);
- bss->ssid.wpa_psk = NULL;
- }
- } else if (os_strcmp(buf, "wpa_psk") == 0) {
- os_free(bss->ssid.wpa_psk);
- bss->ssid.wpa_psk =
- os_zalloc(sizeof(struct hostapd_wpa_psk));
- if (bss->ssid.wpa_psk == NULL)
- errors++;
- else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
- PMK_LEN) ||
- pos[PMK_LEN * 2] != '\0') {
- wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
- "'%s'.", line, pos);
- errors++;
- } else {
- bss->ssid.wpa_psk->group = 1;
- os_free(bss->ssid.wpa_passphrase);
- bss->ssid.wpa_passphrase = NULL;
- }
- } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
- os_free(bss->ssid.wpa_psk_file);
- bss->ssid.wpa_psk_file = os_strdup(pos);
- if (!bss->ssid.wpa_psk_file) {
- wpa_printf(MSG_ERROR, "Line %d: allocation "
- "failed", line);
- errors++;
- }
- } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
- bss->wpa_key_mgmt =
- hostapd_config_parse_key_mgmt(line, pos);
- if (bss->wpa_key_mgmt == -1)
- errors++;
- } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
- bss->wpa_psk_radius = atoi(pos);
- if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
- bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
- bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
- wpa_printf(MSG_ERROR, "Line %d: unknown "
- "wpa_psk_radius %d",
- line, bss->wpa_psk_radius);
- errors++;
- }
- } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
- bss->wpa_pairwise =
- hostapd_config_parse_cipher(line, pos);
- if (bss->wpa_pairwise == -1 ||
- bss->wpa_pairwise == 0)
- errors++;
- else if (bss->wpa_pairwise &
- (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
- WPA_CIPHER_WEP104)) {
- wpa_printf(MSG_ERROR, "Line %d: unsupported "
- "pairwise cipher suite '%s'",
- bss->wpa_pairwise, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
- bss->rsn_pairwise =
- hostapd_config_parse_cipher(line, pos);
- if (bss->rsn_pairwise == -1 ||
- bss->rsn_pairwise == 0)
- errors++;
- else if (bss->rsn_pairwise &
- (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
- WPA_CIPHER_WEP104)) {
- wpa_printf(MSG_ERROR, "Line %d: unsupported "
- "pairwise cipher suite '%s'",
- bss->rsn_pairwise, pos);
- errors++;
- }
+ } else if (os_strcmp(buf, "auth_algs") == 0) {
+ bss->auth_algs = atoi(pos);
+ if (bss->auth_algs == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no authentication algorithms allowed",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "max_num_sta") == 0) {
+ bss->max_num_sta = atoi(pos);
+ if (bss->max_num_sta < 0 ||
+ bss->max_num_sta > MAX_STA_COUNT) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid max_num_sta=%d; allowed range 0..%d",
+ line, bss->max_num_sta, MAX_STA_COUNT);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wpa") == 0) {
+ bss->wpa = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
+ bss->wpa_group_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
+ bss->wpa_strict_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
+ bss->wpa_gmk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
+ bss->wpa_ptk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
+ int len = os_strlen(pos);
+ if (len < 8 || len > 63) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WPA passphrase length %d (expected 8..63)",
+ line, len);
+ return 1;
+ }
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = os_strdup(pos);
+ if (bss->ssid.wpa_passphrase) {
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
+ bss->ssid.wpa_passphrase_set = 1;
+ }
+ } else if (os_strcmp(buf, "wpa_psk") == 0) {
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (bss->ssid.wpa_psk == NULL)
+ return 1;
+ if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, PMK_LEN) ||
+ pos[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
+ line, pos);
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
+ return 1;
+ }
+ bss->ssid.wpa_psk->group = 1;
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = NULL;
+ bss->ssid.wpa_psk_set = 1;
+ } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
+ os_free(bss->ssid.wpa_psk_file);
+ bss->ssid.wpa_psk_file = os_strdup(pos);
+ if (!bss->ssid.wpa_psk_file) {
+ wpa_printf(MSG_ERROR, "Line %d: allocation failed",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
+ bss->wpa_key_mgmt = hostapd_config_parse_key_mgmt(line, pos);
+ if (bss->wpa_key_mgmt == -1)
+ return 1;
+ } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
+ bss->wpa_psk_radius = atoi(pos);
+ if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+ bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
+ bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unknown wpa_psk_radius %d",
+ line, bss->wpa_psk_radius);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
+ bss->wpa_pairwise = hostapd_config_parse_cipher(line, pos);
+ if (bss->wpa_pairwise == -1 || bss->wpa_pairwise == 0)
+ return 1;
+ 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);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
+ bss->rsn_pairwise = hostapd_config_parse_cipher(line, pos);
+ if (bss->rsn_pairwise == -1 || bss->rsn_pairwise == 0)
+ return 1;
+ 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);
+ return 1;
+ }
#ifdef CONFIG_RSN_PREAUTH
- } else if (os_strcmp(buf, "rsn_preauth") == 0) {
- bss->rsn_preauth = atoi(pos);
- } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
- bss->rsn_preauth_interfaces = os_strdup(pos);
+ } else if (os_strcmp(buf, "rsn_preauth") == 0) {
+ bss->rsn_preauth = atoi(pos);
+ } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
+ 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);
+ } else if (os_strcmp(buf, "peerkey") == 0) {
+ bss->peerkey = atoi(pos);
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
- } else if (os_strcmp(buf, "mobility_domain") == 0) {
- if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
- hexstr2bin(pos, bss->mobility_domain,
- MOBILITY_DOMAIN_ID_LEN) != 0) {
- wpa_printf(MSG_DEBUG, "Line %d: Invalid "
- "mobility_domain '%s'", line, pos);
- errors++;
- return errors;
- }
- } else if (os_strcmp(buf, "r1_key_holder") == 0) {
- if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
- hexstr2bin(pos, bss->r1_key_holder,
- FT_R1KH_ID_LEN) != 0) {
- wpa_printf(MSG_DEBUG, "Line %d: Invalid "
- "r1_key_holder '%s'", line, pos);
- errors++;
- return errors;
- }
- } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
- bss->r0_key_lifetime = atoi(pos);
- } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
- bss->reassociation_deadline = atoi(pos);
- } else if (os_strcmp(buf, "r0kh") == 0) {
- if (add_r0kh(bss, pos) < 0) {
- wpa_printf(MSG_DEBUG, "Line %d: Invalid "
- "r0kh '%s'", line, pos);
- errors++;
- return errors;
- }
- } else if (os_strcmp(buf, "r1kh") == 0) {
- if (add_r1kh(bss, pos) < 0) {
- wpa_printf(MSG_DEBUG, "Line %d: Invalid "
- "r1kh '%s'", line, pos);
- errors++;
- return errors;
- }
- } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
- bss->pmk_r1_push = atoi(pos);
- } else if (os_strcmp(buf, "ft_over_ds") == 0) {
- bss->ft_over_ds = atoi(pos);
+ } else if (os_strcmp(buf, "mobility_domain") == 0) {
+ if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
+ hexstr2bin(pos, bss->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid mobility_domain '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "r1_key_holder") == 0) {
+ if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
+ hexstr2bin(pos, bss->r1_key_holder, FT_R1KH_ID_LEN) != 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid r1_key_holder '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+ bss->r0_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
+ bss->reassociation_deadline = atoi(pos);
+ } else if (os_strcmp(buf, "r0kh") == 0) {
+ if (add_r0kh(bss, pos) < 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid r0kh '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "r1kh") == 0) {
+ if (add_r1kh(bss, pos) < 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid r1kh '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
+ bss->pmk_r1_push = atoi(pos);
+ } else if (os_strcmp(buf, "ft_over_ds") == 0) {
+ bss->ft_over_ds = atoi(pos);
#endif /* CONFIG_IEEE80211R */
#ifndef CONFIG_NO_CTRL_IFACE
- } else if (os_strcmp(buf, "ctrl_interface") == 0) {
- os_free(bss->ctrl_interface);
- bss->ctrl_interface = os_strdup(pos);
- } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
+ } else if (os_strcmp(buf, "ctrl_interface") == 0) {
+ os_free(bss->ctrl_interface);
+ bss->ctrl_interface = os_strdup(pos);
+ } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
#ifndef CONFIG_NATIVE_WINDOWS
- struct group *grp;
- char *endp;
- const char *group = pos;
-
- grp = getgrnam(group);
- if (grp) {
- bss->ctrl_interface_gid = grp->gr_gid;
- bss->ctrl_interface_gid_set = 1;
- wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
- " (from group name '%s')",
- bss->ctrl_interface_gid, group);
- return errors;
- }
+ struct group *grp;
+ char *endp;
+ const char *group = pos;
- /* Group name not found - try to parse this as gid */
- bss->ctrl_interface_gid = strtol(group, &endp, 10);
- if (*group == '\0' || *endp != '\0') {
- wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
- "'%s'", line, group);
- errors++;
- return errors;
- }
+ grp = getgrnam(group);
+ if (grp) {
+ bss->ctrl_interface_gid = grp->gr_gid;
bss->ctrl_interface_gid_set = 1;
- wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
- bss->ctrl_interface_gid);
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d (from group name '%s')",
+ bss->ctrl_interface_gid, group);
+ return 0;
+ }
+
+ /* Group name not found - try to parse this as gid */
+ bss->ctrl_interface_gid = strtol(group, &endp, 10);
+ if (*group == '\0' || *endp != '\0') {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid group '%s'",
+ line, group);
+ return 1;
+ }
+ bss->ctrl_interface_gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ bss->ctrl_interface_gid);
#endif /* CONFIG_NATIVE_WINDOWS */
#endif /* CONFIG_NO_CTRL_IFACE */
#ifdef RADIUS_SERVER
- } else if (os_strcmp(buf, "radius_server_clients") == 0) {
- os_free(bss->radius_server_clients);
- bss->radius_server_clients = os_strdup(pos);
- } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
- bss->radius_server_auth_port = atoi(pos);
- } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
- bss->radius_server_ipv6 = atoi(pos);
+ } else if (os_strcmp(buf, "radius_server_clients") == 0) {
+ os_free(bss->radius_server_clients);
+ bss->radius_server_clients = os_strdup(pos);
+ } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
+ bss->radius_server_auth_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_server_acct_port") == 0) {
+ bss->radius_server_acct_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
+ bss->radius_server_ipv6 = atoi(pos);
#endif /* RADIUS_SERVER */
- } else if (os_strcmp(buf, "test_socket") == 0) {
- os_free(bss->test_socket);
- bss->test_socket = os_strdup(pos);
- } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
- bss->use_pae_group_addr = atoi(pos);
- } else if (os_strcmp(buf, "hw_mode") == 0) {
- if (os_strcmp(pos, "a") == 0)
- conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
- else if (os_strcmp(pos, "b") == 0)
- conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
- else if (os_strcmp(pos, "g") == 0)
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- else if (os_strcmp(pos, "ad") == 0)
- conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
- else {
- wpa_printf(MSG_ERROR, "Line %d: unknown "
- "hw_mode '%s'", line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
- if (os_strcmp(pos, "a") == 0)
- bss->wps_rf_bands = WPS_RF_50GHZ;
- else if (os_strcmp(pos, "g") == 0 ||
- os_strcmp(pos, "b") == 0)
- bss->wps_rf_bands = WPS_RF_24GHZ;
- else if (os_strcmp(pos, "ag") == 0 ||
- os_strcmp(pos, "ga") == 0)
- bss->wps_rf_bands =
- WPS_RF_24GHZ | WPS_RF_50GHZ;
- else {
- wpa_printf(MSG_ERROR, "Line %d: unknown "
- "wps_rf_band '%s'", line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "channel") == 0) {
+ } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
+ bss->use_pae_group_addr = atoi(pos);
+ } else if (os_strcmp(buf, "hw_mode") == 0) {
+ if (os_strcmp(pos, "a") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+ else if (os_strcmp(pos, "b") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ else if (os_strcmp(pos, "g") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ else if (os_strcmp(pos, "ad") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
+ if (os_strcmp(pos, "a") == 0)
+ bss->wps_rf_bands = WPS_RF_50GHZ;
+ else if (os_strcmp(pos, "g") == 0 ||
+ os_strcmp(pos, "b") == 0)
+ bss->wps_rf_bands = WPS_RF_24GHZ;
+ else if (os_strcmp(pos, "ag") == 0 ||
+ os_strcmp(pos, "ga") == 0)
+ bss->wps_rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
+ else {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unknown wps_rf_band '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "channel") == 0) {
+ if (os_strcmp(pos, "acs_survey") == 0) {
+#ifndef CONFIG_ACS
+ wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled",
+ line);
+ return 1;
+#else /* CONFIG_ACS */
+ conf->channel = 0;
+#endif /* CONFIG_ACS */
+ } else
conf->channel = atoi(pos);
- } else if (os_strcmp(buf, "beacon_int") == 0) {
- int val = atoi(pos);
- /* MIB defines range as 1..65535, but very small values
- * cause problems with the current implementation.
- * Since it is unlikely that this small numbers are
- * useful in real life scenarios, do not allow beacon
- * period to be set below 15 TU. */
- if (val < 15 || val > 65535) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "beacon_int %d (expected "
- "15..65535)", line, val);
- errors++;
- } else
- conf->beacon_int = val;
- } else if (os_strcmp(buf, "dtim_period") == 0) {
- bss->dtim_period = atoi(pos);
- if (bss->dtim_period < 1 || bss->dtim_period > 255) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "dtim_period %d",
- line, bss->dtim_period);
- errors++;
- }
- } else if (os_strcmp(buf, "rts_threshold") == 0) {
- conf->rts_threshold = atoi(pos);
- if (conf->rts_threshold < 0 ||
- conf->rts_threshold > 2347) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "rts_threshold %d",
- line, conf->rts_threshold);
- errors++;
- }
- } else if (os_strcmp(buf, "fragm_threshold") == 0) {
- conf->fragm_threshold = atoi(pos);
- if (conf->fragm_threshold < 256 ||
- conf->fragm_threshold > 2346) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "fragm_threshold %d",
- line, conf->fragm_threshold);
- errors++;
- }
- } else if (os_strcmp(buf, "send_probe_response") == 0) {
- int val = atoi(pos);
- if (val != 0 && val != 1) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "send_probe_response %d (expected "
- "0 or 1)", line, val);
- } else
- conf->send_probe_response = val;
- } else if (os_strcmp(buf, "supported_rates") == 0) {
- if (hostapd_parse_rates(&conf->supported_rates, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid rate "
- "list", line);
- errors++;
- }
- } else if (os_strcmp(buf, "basic_rates") == 0) {
- if (hostapd_parse_rates(&conf->basic_rates, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid rate "
- "list", line);
- errors++;
- }
- } else if (os_strcmp(buf, "preamble") == 0) {
- if (atoi(pos))
- conf->preamble = SHORT_PREAMBLE;
- else
- conf->preamble = LONG_PREAMBLE;
- } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
- bss->ignore_broadcast_ssid = atoi(pos);
- } else if (os_strcmp(buf, "wep_default_key") == 0) {
- bss->ssid.wep.idx = atoi(pos);
- if (bss->ssid.wep.idx > 3) {
- wpa_printf(MSG_ERROR, "Invalid "
- "wep_default_key index %d",
- bss->ssid.wep.idx);
- errors++;
- }
- } else if (os_strcmp(buf, "wep_key0") == 0 ||
- os_strcmp(buf, "wep_key1") == 0 ||
- os_strcmp(buf, "wep_key2") == 0 ||
- os_strcmp(buf, "wep_key3") == 0) {
- if (hostapd_config_read_wep(&bss->ssid.wep,
- buf[7] - '0', pos)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
- "key '%s'", line, buf);
- errors++;
- }
+ } else if (os_strcmp(buf, "chanlist") == 0) {
+ if (hostapd_parse_intlist(&conf->chanlist, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "beacon_int") == 0) {
+ int val = atoi(pos);
+ /* MIB defines range as 1..65535, but very small values
+ * cause problems with the current implementation.
+ * Since it is unlikely that this small numbers are
+ * useful in real life scenarios, do not allow beacon
+ * period to be set below 15 TU. */
+ if (val < 15 || val > 65535) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid beacon_int %d (expected 15..65535)",
+ line, val);
+ return 1;
+ }
+ conf->beacon_int = val;
+#ifdef CONFIG_ACS
+ } else if (os_strcmp(buf, "acs_num_scans") == 0) {
+ int val = atoi(pos);
+ if (val <= 0 || val > 100) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid acs_num_scans %d (expected 1..100)",
+ line, val);
+ return 1;
+ }
+ conf->acs_num_scans = val;
+ } else if (os_strcmp(buf, "acs_chan_bias") == 0) {
+ if (hostapd_config_parse_acs_chan_bias(conf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias",
+ line);
+ return -1;
+ }
+#endif /* CONFIG_ACS */
+ } else if (os_strcmp(buf, "dtim_period") == 0) {
+ bss->dtim_period = atoi(pos);
+ if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid dtim_period %d",
+ line, bss->dtim_period);
+ return 1;
+ }
+ } 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) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid bss_load_update_period %d",
+ line, bss->bss_load_update_period);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "rts_threshold") == 0) {
+ conf->rts_threshold = atoi(pos);
+ if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid rts_threshold %d",
+ line, conf->rts_threshold);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "fragm_threshold") == 0) {
+ conf->fragm_threshold = atoi(pos);
+ if (conf->fragm_threshold < 256 ||
+ conf->fragm_threshold > 2346) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid fragm_threshold %d",
+ line, conf->fragm_threshold);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "send_probe_response") == 0) {
+ int val = atoi(pos);
+ if (val != 0 && val != 1) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid send_probe_response %d (expected 0 or 1)",
+ line, val);
+ return 1;
+ }
+ conf->send_probe_response = val;
+ } else if (os_strcmp(buf, "supported_rates") == 0) {
+ if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "basic_rates") == 0) {
+ if (hostapd_parse_intlist(&conf->basic_rates, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "preamble") == 0) {
+ if (atoi(pos))
+ conf->preamble = SHORT_PREAMBLE;
+ else
+ conf->preamble = LONG_PREAMBLE;
+ } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
+ bss->ignore_broadcast_ssid = atoi(pos);
+ } else if (os_strcmp(buf, "wep_default_key") == 0) {
+ bss->ssid.wep.idx = atoi(pos);
+ if (bss->ssid.wep.idx > 3) {
+ wpa_printf(MSG_ERROR,
+ "Invalid wep_default_key index %d",
+ bss->ssid.wep.idx);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wep_key0") == 0 ||
+ os_strcmp(buf, "wep_key1") == 0 ||
+ os_strcmp(buf, "wep_key2") == 0 ||
+ os_strcmp(buf, "wep_key3") == 0) {
+ if (hostapd_config_read_wep(&bss->ssid.wep,
+ buf[7] - '0', pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WEP key '%s'",
+ line, buf);
+ return 1;
+ }
#ifndef CONFIG_NO_VLAN
- } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
- bss->ssid.dynamic_vlan = atoi(pos);
- } else if (os_strcmp(buf, "vlan_file") == 0) {
- if (hostapd_config_read_vlan_file(bss, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: failed to "
- "read VLAN file '%s'", line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "vlan_naming") == 0) {
- bss->ssid.vlan_naming = atoi(pos);
- if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
- bss->ssid.vlan_naming < 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "naming scheme %d", line,
- bss->ssid.vlan_naming);
- errors++;
- }
+ } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
+ bss->ssid.dynamic_vlan = atoi(pos);
+ } else if (os_strcmp(buf, "vlan_file") == 0) {
+ if (hostapd_config_read_vlan_file(bss, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "vlan_naming") == 0) {
+ bss->ssid.vlan_naming = atoi(pos);
+ if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
+ bss->ssid.vlan_naming < 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid naming scheme %d",
+ line, bss->ssid.vlan_naming);
+ return 1;
+ }
#ifdef CONFIG_FULL_DYNAMIC_VLAN
- } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
- bss->ssid.vlan_tagged_interface = os_strdup(pos);
+ } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
+ os_free(bss->ssid.vlan_tagged_interface);
+ bss->ssid.vlan_tagged_interface = os_strdup(pos);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
#endif /* CONFIG_NO_VLAN */
- } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
- conf->ap_table_max_size = atoi(pos);
- } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
- conf->ap_table_expiration_time = atoi(pos);
- } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
- if (hostapd_config_tx_queue(conf, buf, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid TX "
- "queue item", line);
- errors++;
- }
- } else if (os_strcmp(buf, "wme_enabled") == 0 ||
- os_strcmp(buf, "wmm_enabled") == 0) {
- bss->wmm_enabled = atoi(pos);
- } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
- bss->wmm_uapsd = atoi(pos);
- } else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
- os_strncmp(buf, "wmm_ac_", 7) == 0) {
- if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
- pos)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
- "ac item", line);
- errors++;
- }
- } else if (os_strcmp(buf, "bss") == 0) {
- if (hostapd_config_bss(conf, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid bss "
- "item", line);
- errors++;
- }
- } else if (os_strcmp(buf, "bssid") == 0) {
- if (hwaddr_aton(pos, bss->bssid)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
- "item", line);
- errors++;
- }
+ } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
+ conf->ap_table_max_size = atoi(pos);
+ } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
+ conf->ap_table_expiration_time = atoi(pos);
+ } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
+ if (hostapd_config_tx_queue(conf, buf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wme_enabled") == 0 ||
+ os_strcmp(buf, "wmm_enabled") == 0) {
+ bss->wmm_enabled = atoi(pos);
+ } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
+ bss->wmm_uapsd = atoi(pos);
+ } else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
+ os_strncmp(buf, "wmm_ac_", 7) == 0) {
+ if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WMM ac item",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "bss") == 0) {
+ if (hostapd_config_bss(conf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid bss item",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "bssid") == 0) {
+ if (hwaddr_aton(pos, bss->bssid)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid bssid item",
+ line);
+ return 1;
+ }
#ifdef CONFIG_IEEE80211W
- } else if (os_strcmp(buf, "ieee80211w") == 0) {
- bss->ieee80211w = atoi(pos);
- } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
- bss->assoc_sa_query_max_timeout = atoi(pos);
- if (bss->assoc_sa_query_max_timeout == 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "assoc_sa_query_max_timeout", line);
- errors++;
- }
- } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
- {
- bss->assoc_sa_query_retry_timeout = atoi(pos);
- if (bss->assoc_sa_query_retry_timeout == 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "assoc_sa_query_retry_timeout",
- line);
- errors++;
- }
+ } else if (os_strcmp(buf, "ieee80211w") == 0) {
+ bss->ieee80211w = atoi(pos);
+ } else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
+ if (os_strcmp(pos, "AES-128-CMAC") == 0) {
+ bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
+ } else if (os_strcmp(pos, "BIP-GMAC-128") == 0) {
+ bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_128;
+ } else if (os_strcmp(pos, "BIP-GMAC-256") == 0) {
+ bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_256;
+ } else if (os_strcmp(pos, "BIP-CMAC-256") == 0) {
+ bss->group_mgmt_cipher = WPA_CIPHER_BIP_CMAC_256;
+ } else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid group_mgmt_cipher: %s",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
+ bss->assoc_sa_query_max_timeout = atoi(pos);
+ if (bss->assoc_sa_query_max_timeout == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid assoc_sa_query_max_timeout",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) {
+ bss->assoc_sa_query_retry_timeout = atoi(pos);
+ if (bss->assoc_sa_query_retry_timeout == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid assoc_sa_query_retry_timeout",
+ line);
+ return 1;
+ }
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211N
- } else if (os_strcmp(buf, "ieee80211n") == 0) {
- conf->ieee80211n = atoi(pos);
- } else if (os_strcmp(buf, "ht_capab") == 0) {
- if (hostapd_config_ht_capab(conf, pos) < 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "ht_capab", line);
- errors++;
- }
- } else if (os_strcmp(buf, "require_ht") == 0) {
- conf->require_ht = atoi(pos);
+ } else if (os_strcmp(buf, "ieee80211n") == 0) {
+ conf->ieee80211n = atoi(pos);
+ } else if (os_strcmp(buf, "ht_capab") == 0) {
+ if (hostapd_config_ht_capab(conf, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid ht_capab",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "require_ht") == 0) {
+ conf->require_ht = atoi(pos);
+ } else if (os_strcmp(buf, "obss_interval") == 0) {
+ conf->obss_interval = atoi(pos);
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- } else if (os_strcmp(buf, "ieee80211ac") == 0) {
- conf->ieee80211ac = atoi(pos);
- } else if (os_strcmp(buf, "vht_capab") == 0) {
- if (hostapd_config_vht_capab(conf, pos) < 0) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "vht_capab", line);
- errors++;
- }
- } else if (os_strcmp(buf, "require_vht") == 0) {
- conf->require_vht = atoi(pos);
- } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
- conf->vht_oper_chwidth = atoi(pos);
- } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
- {
- conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
- } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
- {
- conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+ } else if (os_strcmp(buf, "ieee80211ac") == 0) {
+ conf->ieee80211ac = atoi(pos);
+ } else if (os_strcmp(buf, "vht_capab") == 0) {
+ if (hostapd_config_vht_capab(conf, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid vht_capab",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "require_vht") == 0) {
+ conf->require_vht = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
+ conf->vht_oper_chwidth = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0) {
+ conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) {
+ conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+ } else if (os_strcmp(buf, "vendor_vht") == 0) {
+ bss->vendor_vht = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
- } else if (os_strcmp(buf, "max_listen_interval") == 0) {
- bss->max_listen_interval = atoi(pos);
- } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
- bss->disable_pmksa_caching = atoi(pos);
- } else if (os_strcmp(buf, "okc") == 0) {
- bss->okc = atoi(pos);
+ } else if (os_strcmp(buf, "max_listen_interval") == 0) {
+ bss->max_listen_interval = atoi(pos);
+ } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
+ bss->disable_pmksa_caching = atoi(pos);
+ } else if (os_strcmp(buf, "okc") == 0) {
+ bss->okc = atoi(pos);
#ifdef CONFIG_WPS
- } else if (os_strcmp(buf, "wps_state") == 0) {
- bss->wps_state = atoi(pos);
- if (bss->wps_state < 0 || bss->wps_state > 2) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "wps_state", line);
- errors++;
- }
- } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
- bss->ap_setup_locked = atoi(pos);
- } else if (os_strcmp(buf, "uuid") == 0) {
- if (uuid_str2bin(pos, bss->uuid)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
- line);
- errors++;
- }
- } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
- os_free(bss->wps_pin_requests);
- bss->wps_pin_requests = os_strdup(pos);
- } else if (os_strcmp(buf, "device_name") == 0) {
- if (os_strlen(pos) > 32) {
- wpa_printf(MSG_ERROR, "Line %d: Too long "
- "device_name", line);
- errors++;
- }
- os_free(bss->device_name);
- bss->device_name = os_strdup(pos);
- } else if (os_strcmp(buf, "manufacturer") == 0) {
- if (os_strlen(pos) > 64) {
- wpa_printf(MSG_ERROR, "Line %d: Too long "
- "manufacturer", line);
- errors++;
- }
- os_free(bss->manufacturer);
- bss->manufacturer = os_strdup(pos);
- } else if (os_strcmp(buf, "model_name") == 0) {
- if (os_strlen(pos) > 32) {
- wpa_printf(MSG_ERROR, "Line %d: Too long "
- "model_name", line);
- errors++;
- }
- os_free(bss->model_name);
- bss->model_name = os_strdup(pos);
- } else if (os_strcmp(buf, "model_number") == 0) {
- if (os_strlen(pos) > 32) {
- wpa_printf(MSG_ERROR, "Line %d: Too long "
- "model_number", line);
- errors++;
- }
- os_free(bss->model_number);
- bss->model_number = os_strdup(pos);
- } else if (os_strcmp(buf, "serial_number") == 0) {
- if (os_strlen(pos) > 32) {
- wpa_printf(MSG_ERROR, "Line %d: Too long "
- "serial_number", line);
- errors++;
- }
- os_free(bss->serial_number);
- bss->serial_number = os_strdup(pos);
- } else if (os_strcmp(buf, "device_type") == 0) {
- if (wps_dev_type_str2bin(pos, bss->device_type))
- errors++;
- } else if (os_strcmp(buf, "config_methods") == 0) {
- os_free(bss->config_methods);
- bss->config_methods = os_strdup(pos);
- } else if (os_strcmp(buf, "os_version") == 0) {
- if (hexstr2bin(pos, bss->os_version, 4)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "os_version", line);
- errors++;
- }
- } else if (os_strcmp(buf, "ap_pin") == 0) {
- os_free(bss->ap_pin);
- bss->ap_pin = os_strdup(pos);
- } else if (os_strcmp(buf, "skip_cred_build") == 0) {
- bss->skip_cred_build = atoi(pos);
- } else if (os_strcmp(buf, "extra_cred") == 0) {
- os_free(bss->extra_cred);
- bss->extra_cred =
- (u8 *) os_readfile(pos, &bss->extra_cred_len);
- if (bss->extra_cred == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: could not "
- "read Credentials from '%s'",
- line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "wps_cred_processing") == 0) {
- bss->wps_cred_processing = atoi(pos);
- } else if (os_strcmp(buf, "ap_settings") == 0) {
- os_free(bss->ap_settings);
- bss->ap_settings =
- (u8 *) os_readfile(pos, &bss->ap_settings_len);
- if (bss->ap_settings == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: could not "
- "read AP Settings from '%s'",
- line, pos);
- errors++;
- }
- } else if (os_strcmp(buf, "upnp_iface") == 0) {
- bss->upnp_iface = os_strdup(pos);
- } else if (os_strcmp(buf, "friendly_name") == 0) {
- os_free(bss->friendly_name);
- bss->friendly_name = os_strdup(pos);
- } else if (os_strcmp(buf, "manufacturer_url") == 0) {
- os_free(bss->manufacturer_url);
- bss->manufacturer_url = os_strdup(pos);
- } else if (os_strcmp(buf, "model_description") == 0) {
- os_free(bss->model_description);
- bss->model_description = os_strdup(pos);
- } else if (os_strcmp(buf, "model_url") == 0) {
- os_free(bss->model_url);
- bss->model_url = os_strdup(pos);
- } else if (os_strcmp(buf, "upc") == 0) {
- os_free(bss->upc);
- bss->upc = os_strdup(pos);
- } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
- bss->pbc_in_m1 = atoi(pos);
+ } else if (os_strcmp(buf, "wps_state") == 0) {
+ bss->wps_state = atoi(pos);
+ if (bss->wps_state < 0 || bss->wps_state > 2) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid wps_state",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wps_independent") == 0) {
+ bss->wps_independent = atoi(pos);
+ } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
+ bss->ap_setup_locked = atoi(pos);
+ } else if (os_strcmp(buf, "uuid") == 0) {
+ if (uuid_str2bin(pos, bss->uuid)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
+ os_free(bss->wps_pin_requests);
+ bss->wps_pin_requests = os_strdup(pos);
+ } else if (os_strcmp(buf, "device_name") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long "
+ "device_name", line);
+ return 1;
+ }
+ os_free(bss->device_name);
+ bss->device_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "manufacturer") == 0) {
+ if (os_strlen(pos) > 64) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long manufacturer",
+ line);
+ return 1;
+ }
+ os_free(bss->manufacturer);
+ bss->manufacturer = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_name") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long model_name",
+ line);
+ return 1;
+ }
+ os_free(bss->model_name);
+ bss->model_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_number") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long model_number",
+ line);
+ return 1;
+ }
+ os_free(bss->model_number);
+ bss->model_number = os_strdup(pos);
+ } else if (os_strcmp(buf, "serial_number") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long serial_number",
+ line);
+ return 1;
+ }
+ os_free(bss->serial_number);
+ bss->serial_number = os_strdup(pos);
+ } else if (os_strcmp(buf, "device_type") == 0) {
+ if (wps_dev_type_str2bin(pos, bss->device_type))
+ return 1;
+ } else if (os_strcmp(buf, "config_methods") == 0) {
+ os_free(bss->config_methods);
+ bss->config_methods = os_strdup(pos);
+ } else if (os_strcmp(buf, "os_version") == 0) {
+ if (hexstr2bin(pos, bss->os_version, 4)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid os_version",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "ap_pin") == 0) {
+ os_free(bss->ap_pin);
+ bss->ap_pin = os_strdup(pos);
+ } else if (os_strcmp(buf, "skip_cred_build") == 0) {
+ bss->skip_cred_build = atoi(pos);
+ } else if (os_strcmp(buf, "extra_cred") == 0) {
+ os_free(bss->extra_cred);
+ bss->extra_cred = (u8 *) os_readfile(pos, &bss->extra_cred_len);
+ if (bss->extra_cred == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: could not read Credentials from '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "wps_cred_processing") == 0) {
+ bss->wps_cred_processing = atoi(pos);
+ } else if (os_strcmp(buf, "ap_settings") == 0) {
+ os_free(bss->ap_settings);
+ bss->ap_settings =
+ (u8 *) os_readfile(pos, &bss->ap_settings_len);
+ if (bss->ap_settings == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: could not read AP Settings from '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "upnp_iface") == 0) {
+ os_free(bss->upnp_iface);
+ bss->upnp_iface = os_strdup(pos);
+ } else if (os_strcmp(buf, "friendly_name") == 0) {
+ os_free(bss->friendly_name);
+ bss->friendly_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "manufacturer_url") == 0) {
+ os_free(bss->manufacturer_url);
+ bss->manufacturer_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_description") == 0) {
+ os_free(bss->model_description);
+ bss->model_description = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_url") == 0) {
+ os_free(bss->model_url);
+ bss->model_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "upc") == 0) {
+ os_free(bss->upc);
+ bss->upc = os_strdup(pos);
+ } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
+ bss->pbc_in_m1 = atoi(pos);
+ } else if (os_strcmp(buf, "server_id") == 0) {
+ os_free(bss->server_id);
+ bss->server_id = os_strdup(pos);
#ifdef CONFIG_WPS_NFC
- } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
- bss->wps_nfc_dev_pw_id = atoi(pos);
- if (bss->wps_nfc_dev_pw_id < 0x10 ||
- bss->wps_nfc_dev_pw_id > 0xffff) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "wps_nfc_dev_pw_id value", line);
- errors++;
- }
- } 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);
- } 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);
- } 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);
+ } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
+ bss->wps_nfc_dev_pw_id = atoi(pos);
+ if (bss->wps_nfc_dev_pw_id < 0x10 ||
+ bss->wps_nfc_dev_pw_id > 0xffff) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid wps_nfc_dev_pw_id value",
+ line);
+ return 1;
+ }
+ bss->wps_nfc_pw_from_config = 1;
+ } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
+ wpabuf_free(bss->wps_nfc_dh_pubkey);
+ bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
+ } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
+ wpabuf_free(bss->wps_nfc_dh_privkey);
+ bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
+ } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
+ wpabuf_free(bss->wps_nfc_dev_pw);
+ bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P_MANAGER
- } else if (os_strcmp(buf, "manage_p2p") == 0) {
- int manage = atoi(pos);
- if (manage)
- bss->p2p |= P2P_MANAGE;
- else
- bss->p2p &= ~P2P_MANAGE;
- } else if (os_strcmp(buf, "allow_cross_connection") == 0) {
- if (atoi(pos))
- bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
- else
- bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
+ } else if (os_strcmp(buf, "manage_p2p") == 0) {
+ if (atoi(pos))
+ bss->p2p |= P2P_MANAGE;
+ else
+ bss->p2p &= ~P2P_MANAGE;
+ } else if (os_strcmp(buf, "allow_cross_connection") == 0) {
+ if (atoi(pos))
+ bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
+ else
+ bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
#endif /* CONFIG_P2P_MANAGER */
- } else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
- bss->disassoc_low_ack = atoi(pos);
- } else if (os_strcmp(buf, "tdls_prohibit") == 0) {
- int val = atoi(pos);
- if (val)
- bss->tdls |= TDLS_PROHIBIT;
- else
- bss->tdls &= ~TDLS_PROHIBIT;
- } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
- int val = atoi(pos);
- if (val)
- bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
- else
- bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
+ } else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
+ bss->disassoc_low_ack = atoi(pos);
+ } else if (os_strcmp(buf, "tdls_prohibit") == 0) {
+ if (atoi(pos))
+ bss->tdls |= TDLS_PROHIBIT;
+ else
+ bss->tdls &= ~TDLS_PROHIBIT;
+ } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
+ if (atoi(pos))
+ bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
+ else
+ bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
#ifdef CONFIG_RSN_TESTING
- } else if (os_strcmp(buf, "rsn_testing") == 0) {
- extern int rsn_testing;
- rsn_testing = atoi(pos);
+ } else if (os_strcmp(buf, "rsn_testing") == 0) {
+ extern int rsn_testing;
+ rsn_testing = atoi(pos);
#endif /* CONFIG_RSN_TESTING */
- } else if (os_strcmp(buf, "time_advertisement") == 0) {
- bss->time_advertisement = atoi(pos);
- } else if (os_strcmp(buf, "time_zone") == 0) {
- size_t tz_len = os_strlen(pos);
- if (tz_len < 4 || tz_len > 255) {
- wpa_printf(MSG_DEBUG, "Line %d: invalid "
- "time_zone", line);
- errors++;
- return errors;
- }
- os_free(bss->time_zone);
- bss->time_zone = os_strdup(pos);
- if (bss->time_zone == NULL)
- errors++;
+ } else if (os_strcmp(buf, "time_advertisement") == 0) {
+ bss->time_advertisement = atoi(pos);
+ } else if (os_strcmp(buf, "time_zone") == 0) {
+ size_t tz_len = os_strlen(pos);
+ if (tz_len < 4 || tz_len > 255) {
+ wpa_printf(MSG_DEBUG, "Line %d: invalid time_zone",
+ line);
+ return 1;
+ }
+ os_free(bss->time_zone);
+ bss->time_zone = os_strdup(pos);
+ if (bss->time_zone == NULL)
+ return 1;
#ifdef CONFIG_WNM
- } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
- bss->wnm_sleep_mode = atoi(pos);
- } else if (os_strcmp(buf, "bss_transition") == 0) {
- bss->bss_transition = atoi(pos);
+ } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
+ bss->wnm_sleep_mode = atoi(pos);
+ } else if (os_strcmp(buf, "bss_transition") == 0) {
+ bss->bss_transition = atoi(pos);
#endif /* CONFIG_WNM */
#ifdef CONFIG_INTERWORKING
- } else if (os_strcmp(buf, "interworking") == 0) {
- bss->interworking = atoi(pos);
- } else if (os_strcmp(buf, "access_network_type") == 0) {
- bss->access_network_type = atoi(pos);
- if (bss->access_network_type < 0 ||
- bss->access_network_type > 15) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "access_network_type", line);
- errors++;
- }
- } else if (os_strcmp(buf, "internet") == 0) {
- bss->internet = atoi(pos);
- } else if (os_strcmp(buf, "asra") == 0) {
- bss->asra = atoi(pos);
- } else if (os_strcmp(buf, "esr") == 0) {
- bss->esr = atoi(pos);
- } else if (os_strcmp(buf, "uesa") == 0) {
- bss->uesa = atoi(pos);
- } else if (os_strcmp(buf, "venue_group") == 0) {
- bss->venue_group = atoi(pos);
- bss->venue_info_set = 1;
- } else if (os_strcmp(buf, "venue_type") == 0) {
- bss->venue_type = atoi(pos);
- bss->venue_info_set = 1;
- } else if (os_strcmp(buf, "hessid") == 0) {
- if (hwaddr_aton(pos, bss->hessid)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "hessid", line);
- errors++;
- }
- } else if (os_strcmp(buf, "roaming_consortium") == 0) {
- if (parse_roaming_consortium(bss, pos, line) < 0)
- errors++;
- } else if (os_strcmp(buf, "venue_name") == 0) {
- if (parse_venue_name(bss, pos, line) < 0)
- errors++;
- } else if (os_strcmp(buf, "network_auth_type") == 0) {
- u8 auth_type;
- u16 redirect_url_len;
- if (hexstr2bin(pos, &auth_type, 1)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "network_auth_type '%s'",
- line, pos);
- errors++;
- return errors;
- }
- if (auth_type == 0 || auth_type == 2)
- redirect_url_len = os_strlen(pos + 2);
- else
- redirect_url_len = 0;
- os_free(bss->network_auth_type);
- bss->network_auth_type =
- os_malloc(redirect_url_len + 3 + 1);
- if (bss->network_auth_type == NULL) {
- errors++;
- return errors;
- }
- *bss->network_auth_type = auth_type;
- WPA_PUT_LE16(bss->network_auth_type + 1,
- redirect_url_len);
- if (redirect_url_len)
- os_memcpy(bss->network_auth_type + 3,
- pos + 2, redirect_url_len);
- bss->network_auth_type_len = 3 + redirect_url_len;
- } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
- if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
- {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "ipaddr_type_availability '%s'",
- line, pos);
- bss->ipaddr_type_configured = 0;
- errors++;
- return errors;
- }
- bss->ipaddr_type_configured = 1;
- } else if (os_strcmp(buf, "domain_name") == 0) {
- int j, num_domains, domain_len, domain_list_len = 0;
- char *tok_start, *tok_prev;
- u8 *domain_list, *domain_ptr;
-
- domain_list_len = os_strlen(pos) + 1;
- domain_list = os_malloc(domain_list_len);
- if (domain_list == NULL) {
- errors++;
- return errors;
- }
-
- domain_ptr = domain_list;
- tok_prev = pos;
- num_domains = 1;
- while ((tok_prev = os_strchr(tok_prev, ','))) {
- num_domains++;
- tok_prev++;
- }
- tok_prev = pos;
- for (j = 0; j < num_domains; j++) {
- tok_start = os_strchr(tok_prev, ',');
- if (tok_start) {
- domain_len = tok_start - tok_prev;
- *domain_ptr = domain_len;
- os_memcpy(domain_ptr + 1, tok_prev,
- domain_len);
- domain_ptr += domain_len + 1;
- tok_prev = ++tok_start;
- } else {
- domain_len = os_strlen(tok_prev);
- *domain_ptr = domain_len;
- os_memcpy(domain_ptr + 1, tok_prev,
- domain_len);
- domain_ptr += domain_len + 1;
- }
+ } else if (os_strcmp(buf, "interworking") == 0) {
+ bss->interworking = atoi(pos);
+ } else if (os_strcmp(buf, "access_network_type") == 0) {
+ bss->access_network_type = atoi(pos);
+ if (bss->access_network_type < 0 ||
+ bss->access_network_type > 15) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid access_network_type",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "internet") == 0) {
+ bss->internet = atoi(pos);
+ } else if (os_strcmp(buf, "asra") == 0) {
+ bss->asra = atoi(pos);
+ } else if (os_strcmp(buf, "esr") == 0) {
+ bss->esr = atoi(pos);
+ } else if (os_strcmp(buf, "uesa") == 0) {
+ bss->uesa = atoi(pos);
+ } else if (os_strcmp(buf, "venue_group") == 0) {
+ bss->venue_group = atoi(pos);
+ bss->venue_info_set = 1;
+ } else if (os_strcmp(buf, "venue_type") == 0) {
+ bss->venue_type = atoi(pos);
+ bss->venue_info_set = 1;
+ } else if (os_strcmp(buf, "hessid") == 0) {
+ if (hwaddr_aton(pos, bss->hessid)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid hessid", line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "roaming_consortium") == 0) {
+ if (parse_roaming_consortium(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "venue_name") == 0) {
+ if (parse_venue_name(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "network_auth_type") == 0) {
+ u8 auth_type;
+ u16 redirect_url_len;
+ if (hexstr2bin(pos, &auth_type, 1)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid network_auth_type '%s'",
+ line, pos);
+ return 1;
+ }
+ if (auth_type == 0 || auth_type == 2)
+ redirect_url_len = os_strlen(pos + 2);
+ else
+ redirect_url_len = 0;
+ os_free(bss->network_auth_type);
+ bss->network_auth_type = os_malloc(redirect_url_len + 3 + 1);
+ if (bss->network_auth_type == NULL)
+ return 1;
+ *bss->network_auth_type = auth_type;
+ WPA_PUT_LE16(bss->network_auth_type + 1, redirect_url_len);
+ if (redirect_url_len)
+ os_memcpy(bss->network_auth_type + 3, pos + 2,
+ redirect_url_len);
+ bss->network_auth_type_len = 3 + redirect_url_len;
+ } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
+ if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid ipaddr_type_availability '%s'",
+ line, pos);
+ bss->ipaddr_type_configured = 0;
+ return 1;
+ }
+ bss->ipaddr_type_configured = 1;
+ } else if (os_strcmp(buf, "domain_name") == 0) {
+ int j, num_domains, domain_len, domain_list_len = 0;
+ char *tok_start, *tok_prev;
+ u8 *domain_list, *domain_ptr;
+
+ domain_list_len = os_strlen(pos) + 1;
+ domain_list = os_malloc(domain_list_len);
+ if (domain_list == NULL)
+ return 1;
+
+ domain_ptr = domain_list;
+ tok_prev = pos;
+ num_domains = 1;
+ while ((tok_prev = os_strchr(tok_prev, ','))) {
+ num_domains++;
+ tok_prev++;
+ }
+ tok_prev = pos;
+ for (j = 0; j < num_domains; j++) {
+ tok_start = os_strchr(tok_prev, ',');
+ if (tok_start) {
+ domain_len = tok_start - tok_prev;
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev, domain_len);
+ domain_ptr += domain_len + 1;
+ tok_prev = ++tok_start;
+ } else {
+ domain_len = os_strlen(tok_prev);
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev, domain_len);
+ domain_ptr += domain_len + 1;
}
+ }
- os_free(bss->domain_name);
- bss->domain_name = domain_list;
- bss->domain_name_len = domain_list_len;
- } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
- if (parse_3gpp_cell_net(bss, pos, line) < 0)
- errors++;
- } else if (os_strcmp(buf, "nai_realm") == 0) {
- if (parse_nai_realm(bss, pos, line) < 0)
- errors++;
- } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
- bss->gas_frag_limit = atoi(pos);
- } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
- bss->gas_comeback_delay = atoi(pos);
+ os_free(bss->domain_name);
+ bss->domain_name = domain_list;
+ bss->domain_name_len = domain_list_len;
+ } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
+ if (parse_3gpp_cell_net(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "nai_realm") == 0) {
+ if (parse_nai_realm(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
+ bss->gas_frag_limit = atoi(pos);
+ } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
+ bss->gas_comeback_delay = atoi(pos);
+ } else if (os_strcmp(buf, "qos_map_set") == 0) {
+ if (parse_qos_map_set(bss, pos, line) < 0)
+ return 1;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_RADIUS_TEST
- } else if (os_strcmp(buf, "dump_msk_file") == 0) {
- os_free(bss->dump_msk_file);
- bss->dump_msk_file = os_strdup(pos);
+ } else if (os_strcmp(buf, "dump_msk_file") == 0) {
+ os_free(bss->dump_msk_file);
+ bss->dump_msk_file = os_strdup(pos);
#endif /* CONFIG_RADIUS_TEST */
#ifdef CONFIG_HS20
- } else if (os_strcmp(buf, "hs20") == 0) {
- bss->hs20 = atoi(pos);
- } else if (os_strcmp(buf, "disable_dgaf") == 0) {
- bss->disable_dgaf = atoi(pos);
- } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
- if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
- errors++;
- } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
- if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
- errors++;
- return errors;
- }
- } else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
- if (hs20_parse_conn_capab(bss, pos, line) < 0) {
- errors++;
- return errors;
- }
- } else if (os_strcmp(buf, "hs20_operating_class") == 0) {
- u8 *oper_class;
- size_t oper_class_len;
- oper_class_len = os_strlen(pos);
- if (oper_class_len < 2 || (oper_class_len & 0x01)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "hs20_operating_class '%s'",
- line, pos);
- errors++;
- return errors;
- }
- oper_class_len /= 2;
- oper_class = os_malloc(oper_class_len);
- if (oper_class == NULL) {
- errors++;
- return errors;
- }
- if (hexstr2bin(pos, oper_class, oper_class_len)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "hs20_operating_class '%s'",
- line, pos);
- os_free(oper_class);
- errors++;
- return errors;
- }
- os_free(bss->hs20_operating_class);
- bss->hs20_operating_class = oper_class;
- bss->hs20_operating_class_len = oper_class_len;
+ } else if (os_strcmp(buf, "hs20") == 0) {
+ bss->hs20 = atoi(pos);
+ } else if (os_strcmp(buf, "disable_dgaf") == 0) {
+ bss->disable_dgaf = atoi(pos);
+ } else if (os_strcmp(buf, "proxy_arp") == 0) {
+ bss->proxy_arp = atoi(pos);
+ } else if (os_strcmp(buf, "osen") == 0) {
+ bss->osen = atoi(pos);
+ } else if (os_strcmp(buf, "anqp_domain_id") == 0) {
+ bss->anqp_domain_id = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_deauth_req_timeout") == 0) {
+ bss->hs20_deauth_req_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
+ if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
+ if (hs20_parse_wan_metrics(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
+ if (hs20_parse_conn_capab(bss, pos, line) < 0) {
+ return 1;
+ }
+ } else if (os_strcmp(buf, "hs20_operating_class") == 0) {
+ u8 *oper_class;
+ size_t oper_class_len;
+ oper_class_len = os_strlen(pos);
+ if (oper_class_len < 2 || (oper_class_len & 0x01)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid hs20_operating_class '%s'",
+ line, pos);
+ return 1;
+ }
+ oper_class_len /= 2;
+ oper_class = os_malloc(oper_class_len);
+ if (oper_class == NULL)
+ return 1;
+ if (hexstr2bin(pos, oper_class, oper_class_len)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid hs20_operating_class '%s'",
+ line, pos);
+ os_free(oper_class);
+ return 1;
+ }
+ os_free(bss->hs20_operating_class);
+ bss->hs20_operating_class = oper_class;
+ bss->hs20_operating_class_len = oper_class_len;
+ } else if (os_strcmp(buf, "hs20_icon") == 0) {
+ if (hs20_parse_icon(bss, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_icon '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "osu_ssid") == 0) {
+ if (hs20_parse_osu_ssid(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "osu_server_uri") == 0) {
+ if (hs20_parse_osu_server_uri(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "osu_friendly_name") == 0) {
+ if (hs20_parse_osu_friendly_name(bss, pos, line) < 0)
+ return 1;
+ } 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_method_list") == 0) {
+ if (hs20_parse_osu_method_list(bss, pos, line) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "osu_icon") == 0) {
+ if (hs20_parse_osu_icon(bss, pos, line) < 0)
+ return 1;
+ } 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, "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);
#endif /* CONFIG_HS20 */
- } else if (os_strcmp(buf, "vendor_elements") == 0) {
- struct wpabuf *elems;
- size_t len = os_strlen(pos);
- if (len & 0x01) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "vendor_elements '%s'", line, pos);
- return 1;
- }
- len /= 2;
- if (len == 0) {
- wpabuf_free(bss->vendor_elements);
- bss->vendor_elements = NULL;
- return 0;
- }
-
- elems = wpabuf_alloc(len);
- if (elems == NULL)
- return 1;
-
- if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
- wpabuf_free(elems);
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "vendor_elements '%s'", line, pos);
- return 1;
- }
-
+#ifdef CONFIG_TESTING_OPTIONS
+#define PARSE_TEST_PROBABILITY(_val) \
+ } else if (os_strcmp(buf, #_val) == 0) { \
+ char *end; \
+ \
+ conf->_val = strtod(pos, &end); \
+ if (*end || conf->_val < 0.0 || \
+ conf->_val > 1.0) { \
+ wpa_printf(MSG_ERROR, \
+ "Line %d: Invalid value '%s'", \
+ line, pos); \
+ return 1; \
+ }
+ PARSE_TEST_PROBABILITY(ignore_probe_probability)
+ PARSE_TEST_PROBABILITY(ignore_auth_probability)
+ PARSE_TEST_PROBABILITY(ignore_assoc_probability)
+ PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
+ PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+ } else if (os_strcmp(buf, "bss_load_test") == 0) {
+ WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid bss_load_test",
+ line);
+ return 1;
+ }
+ pos++;
+ bss->bss_load_test[2] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid bss_load_test",
+ line);
+ return 1;
+ }
+ pos++;
+ WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
+ bss->bss_load_test_set = 1;
+ } else if (os_strcmp(buf, "radio_measurements") == 0) {
+ bss->radio_measurements = atoi(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);
+ return 1;
+ }
+ len /= 2;
+ if (len == 0) {
wpabuf_free(bss->vendor_elements);
- bss->vendor_elements = elems;
- } else {
- wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
- "item '%s'", line, buf);
- errors++;
+ bss->vendor_elements = NULL;
+ return 0;
}
- }
- return errors;
-}
+ elems = wpabuf_alloc(len);
+ if (elems == NULL)
+ return 1;
+ if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+ wpabuf_free(elems);
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid vendor_elements '%s'",
+ line, pos);
+ return 1;
+ }
-static void hostapd_set_security_params(struct hostapd_bss_config *bss)
-{
- int pairwise;
-
- if (bss->individual_wep_key_len == 0) {
- /* individual keys are not use; can use key idx0 for
- * broadcast keys */
- bss->broadcast_key_idx_min = 0;
- }
-
- /* Select group cipher based on the enabled pairwise cipher
- * suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
- }
- if (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
- WPA_CIPHER_GCMP)
- bss->wpa_group = WPA_CIPHER_GCMP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
-
- bss->radius->auth_server = bss->radius->auth_servers;
- bss->radius->acct_server = bss->radius->acct_servers;
-
- if (bss->wpa && bss->ieee802_1x) {
- bss->ssid.security_policy = SECURITY_WPA;
- } else if (bss->wpa) {
- bss->ssid.security_policy = SECURITY_WPA_PSK;
- } else if (bss->ieee802_1x) {
- int cipher = WPA_CIPHER_NONE;
- bss->ssid.security_policy = SECURITY_IEEE_802_1X;
- bss->ssid.wep.default_len = bss->default_wep_key_len;
- if (bss->default_wep_key_len)
- cipher = bss->default_wep_key_len >= 13 ?
- WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
- bss->wpa_group = cipher;
- bss->wpa_pairwise = cipher;
- bss->rsn_pairwise = cipher;
- } else if (bss->ssid.wep.keys_set) {
- int cipher = WPA_CIPHER_WEP40;
- if (bss->ssid.wep.len[0] >= 13)
- cipher = WPA_CIPHER_WEP104;
- bss->ssid.security_policy = SECURITY_STATIC_WEP;
- bss->wpa_group = cipher;
- bss->wpa_pairwise = cipher;
- bss->rsn_pairwise = cipher;
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = elems;
+ } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
+ bss->sae_anti_clogging_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "sae_groups") == 0) {
+ if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid sae_groups value '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
+ int val = atoi(pos);
+ if (val < 0 || val > 255) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid local_pwr_constraint %d (expected 0..255)",
+ line, val);
+ return 1;
+ }
+ conf->local_pwr_constraint = val;
+ } else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) {
+ conf->spectrum_mgmt_required = atoi(pos);
+ } else if (os_strcmp(buf, "wowlan_triggers") == 0) {
+ os_free(bss->wowlan_triggers);
+ bss->wowlan_triggers = os_strdup(pos);
} else {
- bss->ssid.security_policy = SECURITY_PLAINTEXT;
- bss->wpa_group = WPA_CIPHER_NONE;
- bss->wpa_pairwise = WPA_CIPHER_NONE;
- bss->rsn_pairwise = WPA_CIPHER_NONE;
+ wpa_printf(MSG_ERROR,
+ "Line %d: unknown configuration item '%s'",
+ line, buf);
+ return 1;
}
+
+ return 0;
}
@@ -3016,7 +3295,6 @@ static void hostapd_set_security_params(struct hostapd_bss_config *bss)
struct hostapd_config * hostapd_config_read(const char *fname)
{
struct hostapd_config *conf;
- struct hostapd_bss_config *bss;
FILE *f;
char buf[512], *pos;
int line = 0;
@@ -3045,9 +3323,11 @@ struct hostapd_config * hostapd_config_read(const char *fname)
return NULL;
}
- bss = conf->last_bss = conf->bss;
+ conf->last_bss = conf->bss[0];
while (fgets(buf, sizeof(buf), f)) {
+ struct hostapd_bss_config *bss;
+
bss = conf->last_bss;
line++;
@@ -3079,9 +3359,9 @@ struct hostapd_config * hostapd_config_read(const char *fname)
fclose(f);
for (i = 0; i < conf->num_bss; i++)
- hostapd_set_security_params(&conf->bss[i]);
+ hostapd_set_security_params(conf->bss[i], 1);
- if (hostapd_config_check(conf))
+ if (hostapd_config_check(conf, 1))
errors++;
#ifndef WPA_IGNORE_CONFIG_ERRORS
@@ -3111,9 +3391,9 @@ int hostapd_set_iface(struct hostapd_config *conf,
}
for (i = 0; i < conf->num_bss; i++)
- hostapd_set_security_params(&conf->bss[i]);
+ hostapd_set_security_params(conf->bss[i], 0);
- if (hostapd_config_check(conf)) {
+ if (hostapd_config_check(conf, 0)) {
wpa_printf(MSG_ERROR, "Configuration check failed");
return -1;
}
diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c
index 3c9071c..86f1aa6 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-2012, 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.
@@ -10,6 +10,11 @@
#ifndef CONFIG_NATIVE_WINDOWS
+#ifdef CONFIG_TESTING_OPTIONS
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#endif /* CONFIG_TESTING_OPTIONS */
+
#include <sys/un.h>
#include <sys/stat.h>
#include <stddef.h>
@@ -18,8 +23,11 @@
#include "utils/eloop.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "crypto/tls.h"
#include "drivers/driver.h"
#include "radius/radius_client.h"
+#include "radius/radius_server.h"
+#include "l2_packet/l2_packet.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ieee802_1x.h"
@@ -29,6 +37,10 @@
#include "ap/wps_hostapd.h"
#include "ap/ctrl_iface_ap.h"
#include "ap/ap_drv_ops.h"
+#include "ap/hs20.h"
+#include "ap/wnm_ap.h"
+#include "ap/wpa_auth.h"
+#include "ap/beacon.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "config_file.h"
@@ -81,15 +93,15 @@ static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
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);
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
- (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
return 0;
}
prev = dst;
@@ -236,14 +248,14 @@ static int hostapd_ctrl_iface_wps_check_pin(
if (!wps_pin_valid(pin_val)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
}
ret = os_snprintf(buf, buflen, "%s", pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
@@ -352,6 +364,116 @@ static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
return -1;
}
+
+
+static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+ char *pos;
+ int ndef;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ if (os_strcmp(pos, "WPS-CR") == 0)
+ buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
+ else
+ buf = NULL;
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *req, *sel;
+ int ret;
+ char *pos, *role, *type, *pos2;
+
+ role = cmd;
+ pos = os_strchr(role, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ type = pos;
+ pos = os_strchr(type, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL)
+ return -1;
+ *pos2++ = '\0';
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ req = wpabuf_alloc(len);
+ if (req == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+ wpabuf_free(req);
+ return -1;
+ }
+
+ len = os_strlen(pos2);
+ if (len & 0x01) {
+ wpabuf_free(req);
+ return -1;
+ }
+ len /= 2;
+
+ sel = wpabuf_alloc(len);
+ if (sel == NULL) {
+ wpabuf_free(req);
+ return -1;
+ }
+ if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+ wpabuf_free(req);
+ wpabuf_free(sel);
+ return -1;
+ }
+
+ if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
+ ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
+ } else {
+ wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+ "reported: role=%s type=%s", role, type);
+ ret = -1;
+ }
+ wpabuf_free(req);
+ wpabuf_free(sel);
+
+ return ret;
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -433,8 +555,253 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
}
+
+
+static const char * pbc_status_str(enum pbc_status status)
+{
+ switch (status) {
+ case WPS_PBC_STATUS_DISABLE:
+ return "Disabled";
+ case WPS_PBC_STATUS_ACTIVE:
+ return "Active";
+ case WPS_PBC_STATUS_TIMEOUT:
+ return "Timed-out";
+ case WPS_PBC_STATUS_OVERLAP:
+ return "Overlap";
+ default:
+ return "Unknown";
+ }
+}
+
+
+static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
+ pbc_status_str(hapd->wps_stats.pbc_status));
+
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
+ (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
+ "Success":
+ (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
+ "Failed" : "None")));
+
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ /* If status == Failure - Add possible Reasons */
+ if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
+ hapd->wps_stats.failure_reason > 0) {
+ ret = os_snprintf(pos, end - pos,
+ "Failure Reason: %s\n",
+ wps_ei_str(hapd->wps_stats.failure_reason));
+
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->wps_stats.status) {
+ ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
+ MAC2STR(hapd->wps_stats.peer_addr));
+
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
#endif /* CONFIG_WPS */
+#ifdef CONFIG_HS20
+
+static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *url;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+ url = cmd + 17;
+ if (*url == '\0') {
+ url = NULL;
+ } else {
+ if (*url != ' ')
+ return -1;
+ url++;
+ if (*url == '\0')
+ url = NULL;
+ }
+
+ return hs20_send_wnm_notification(hapd, addr, 1, url);
+}
+
+
+static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int code, reauth_delay, ret;
+ const char *pos;
+ size_t url_len;
+ struct wpabuf *req;
+
+ /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ code = atoi(pos);
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ reauth_delay = atoi(pos);
+
+ url_len = 0;
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ pos++;
+ url_len = os_strlen(pos);
+ }
+
+ req = wpabuf_alloc(4 + url_len);
+ if (req == NULL)
+ return -1;
+ wpabuf_put_u8(req, code);
+ wpabuf_put_le16(req, reauth_delay);
+ wpabuf_put_u8(req, url_len);
+ if (pos)
+ wpabuf_put_data(req, pos, url_len);
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
+ " to indicate imminent deauthentication (code=%d "
+ "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
+ ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
+ wpabuf_free(req);
+ return ret;
+}
+
+#endif /* CONFIG_HS20 */
+
+
+#ifdef CONFIG_INTERWORKING
+
+static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 qos_map_set[16 + 2 * 21], count = 0;
+ const char *pos = cmd;
+ int val, ret;
+
+ for (;;) {
+ if (count == sizeof(qos_map_set)) {
+ wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
+ return -1;
+ }
+
+ val = atoi(pos);
+ if (val < 0 || val > 255) {
+ wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+ return -1;
+ }
+
+ qos_map_set[count++] = val;
+ pos = os_strchr(pos, ',');
+ if (!pos)
+ break;
+ pos++;
+ }
+
+ if (count < 16 || count & 1) {
+ wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+ return -1;
+ }
+
+ ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
+ if (ret) {
+ wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
+ return -1;
+ }
+
+ os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
+ hapd->conf->qos_map_set_len = count;
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ struct wpabuf *buf;
+ u8 *qos_map_set = hapd->conf->qos_map_set;
+ u8 qos_map_set_len = hapd->conf->qos_map_set_len;
+ int ret;
+
+ if (!qos_map_set_len) {
+ wpa_printf(MSG_INFO, "QoS Map Set is not set");
+ return -1;
+ }
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
+ "for QoS Map Configuration message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ if (!sta->qos_map_enabled) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
+ "support for QoS Map", MAC2STR(addr));
+ return -1;
+ }
+
+ buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
+ if (buf == NULL)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_QOS);
+ wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
+
+ /* QoS Map Set Element */
+ wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
+ wpabuf_put_u8(buf, qos_map_set_len);
+ wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_INTERWORKING */
+
#ifdef CONFIG_WNM
@@ -442,9 +809,8 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
const char *cmd)
{
u8 addr[ETH_ALEN];
- u8 buf[1000], *pos;
- struct ieee80211_mgmt *mgmt;
int disassoc_timer;
+ struct sta_info *sta;
if (hwaddr_aton(cmd, addr))
return -1;
@@ -452,31 +818,15 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
return -1;
disassoc_timer = atoi(cmd + 17);
- 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, addr, ETH_ALEN);
- os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
- mgmt->u.action.category = WLAN_ACTION_WNM;
- mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
- mgmt->u.action.u.bss_tm_req.dialog_token = 1;
- mgmt->u.action.u.bss_tm_req.req_mode =
- WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
- mgmt->u.action.u.bss_tm_req.disassoc_timer =
- host_to_le16(disassoc_timer);
- mgmt->u.action.u.bss_tm_req.validity_interval = 0;
-
- pos = mgmt->u.action.u.bss_tm_req.variable;
-
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
- "Management Request frame");
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for disassociation imminent message",
+ MAC2STR(addr));
return -1;
}
- return 0;
+ return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
}
@@ -484,50 +834,222 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
const char *cmd)
{
u8 addr[ETH_ALEN];
- const char *url;
- u8 buf[1000], *pos;
- struct ieee80211_mgmt *mgmt;
- size_t url_len;
+ const char *url, *timerstr;
+ int disassoc_timer;
+ struct sta_info *sta;
if (hwaddr_aton(cmd, addr))
return -1;
- url = cmd + 17;
- if (*url != ' ')
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for ESS disassociation imminent message",
+ MAC2STR(addr));
return -1;
- url++;
- url_len = os_strlen(url);
- if (url_len > 255)
+ }
+
+ timerstr = cmd + 17;
+ if (*timerstr != ' ')
+ return -1;
+ timerstr++;
+ disassoc_timer = atoi(timerstr);
+ if (disassoc_timer < 0 || disassoc_timer > 65535)
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, addr, ETH_ALEN);
- os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
- mgmt->u.action.category = WLAN_ACTION_WNM;
- mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
- mgmt->u.action.u.bss_tm_req.dialog_token = 1;
- mgmt->u.action.u.bss_tm_req.req_mode =
- WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
- mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
- mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+ url = os_strchr(timerstr, ' ');
+ if (url == NULL)
+ return -1;
+ url++;
- pos = mgmt->u.action.u.bss_tm_req.variable;
+ return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
+}
- /* Session Information URL */
- *pos++ = url_len;
- os_memcpy(pos, url, url_len);
- pos += url_len;
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
- "Management Request frame");
+static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *pos, *end;
+ int disassoc_timer = 0;
+ struct sta_info *sta;
+ u8 req_mode = 0, valid_int = 0x01;
+ u8 bss_term_dur[12];
+ char *url = NULL;
+ int ret;
+ u8 nei_rep[1000];
+ u8 *nei_pos = nei_rep;
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
return -1;
}
- return 0;
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for BSS TM Request message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " disassoc_timer=");
+ if (pos) {
+ pos += 16;
+ disassoc_timer = atoi(pos);
+ if (disassoc_timer < 0 || disassoc_timer > 65535) {
+ wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
+ return -1;
+ }
+ }
+
+ pos = os_strstr(cmd, " valid_int=");
+ if (pos) {
+ pos += 11;
+ valid_int = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " bss_term=");
+ if (pos) {
+ pos += 10;
+ req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
+ /* TODO: TSF configurable/learnable */
+ bss_term_dur[0] = 4; /* Subelement ID */
+ bss_term_dur[1] = 10; /* Length */
+ os_memset(bss_term_dur, 2, 8);
+ end = os_strchr(pos, ',');
+ if (end == NULL) {
+ wpa_printf(MSG_DEBUG, "Invalid bss_term data");
+ return -1;
+ }
+ end++;
+ 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;
+ }
+
+ pos = os_strstr(cmd, " url=");
+ if (pos) {
+ size_t len;
+ pos += 5;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ url = os_malloc(len + 1);
+ if (url == NULL)
+ return -1;
+ os_memcpy(url, pos, len);
+ url[len] = '\0';
+ req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+ }
+
+ if (os_strstr(cmd, " pref=1"))
+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+ if (os_strstr(cmd, " abridged=1"))
+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+ if (os_strstr(cmd, " disassoc_imminent=1"))
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+ 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);
+ os_free(url);
+ return ret;
}
#endif /* CONFIG_WNM */
@@ -547,7 +1069,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
MAC2STR(hapd->own_addr),
wpa_ssid_txt(hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -556,7 +1078,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
hapd->conf->wps_state == 0 ? "disabled" :
(hapd->conf->wps_state == 1 ? "not configured" :
"configured"));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -564,7 +1086,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
hapd->conf->ssid.wpa_passphrase) {
ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
hapd->conf->ssid.wpa_passphrase);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -576,7 +1098,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
wpa_snprintf_hex(hex, sizeof(hex),
hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -584,134 +1106,127 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
ret = os_snprintf(pos, end - pos, "key_mgmt=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
ret = os_snprintf(pos, end - pos, "WPA-PSK ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "WPA-EAP ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#ifdef CONFIG_IEEE80211R
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "FT-PSK ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "FT-EAP ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_SAE
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, "FT-SAE ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ if (hapd->conf->wpa_key_mgmt & WPA_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 */
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt &
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos,
+ "WPA-EAP-SUITE-B-192 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
- if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- } else if (hapd->conf->wpa &&
- hapd->conf->wpa_group == WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- } else if (hapd->conf->wpa &&
- hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
- if (ret < 0 || ret >= end - pos)
+ if (hapd->conf->wpa) {
+ ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
+ wpa_cipher_txt(hapd->conf->wpa_group));
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "CCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "GCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "TKIP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
+ ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+ " ");
+ if (ret < 0)
+ return pos - buf;
+ pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "CCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "GCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "TKIP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
+ ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
+ " ");
+ if (ret < 0)
+ return pos - buf;
+ pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -752,6 +1267,10 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
wps_testing_dummy_cred = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
wps_testing_dummy_cred);
+ } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+ wps_corrupt_pkhash = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+ wps_corrupt_pkhash);
#endif /* CONFIG_WPS_TESTING */
#ifdef CONFIG_INTERWORKING
} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
@@ -761,8 +1280,44 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
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);
+#endif /* CONFIG_TESTING_OPTIONS */
} else {
+ struct sta_info *sta;
+ int vlan_id;
+
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);
+ }
+ }
}
return ret;
@@ -778,7 +1333,12 @@ static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
if (os_strcmp(cmd, "version") == 0) {
res = os_snprintf(buf, buflen, "%s", VERSION_STR);
- if (res < 0 || (unsigned int) res >= buflen)
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ } else if (os_strcmp(cmd, "tls_library") == 0) {
+ res = tls_get_library_version(buf, buflen);
+ if (os_snprintf_error(buflen, res))
return -1;
return res;
}
@@ -817,11 +1377,481 @@ static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
}
+#ifdef CONFIG_TESTING_OPTIONS
+
+static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
+{
+ union wpa_event_data data;
+ char *pos, *param;
+ enum wpa_event_type event;
+
+ wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
+
+ os_memset(&data, 0, sizeof(data));
+
+ param = os_strchr(cmd, ' ');
+ if (param == NULL)
+ return -1;
+ *param++ = '\0';
+
+ if (os_strcmp(cmd, "DETECTED") == 0)
+ event = EVENT_DFS_RADAR_DETECTED;
+ else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
+ event = EVENT_DFS_CAC_FINISHED;
+ else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
+ event = EVENT_DFS_CAC_ABORTED;
+ else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
+ event = EVENT_DFS_NOP_FINISHED;
+ else {
+ wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
+ cmd);
+ return -1;
+ }
+
+ pos = os_strstr(param, "freq=");
+ if (pos)
+ data.dfs_event.freq = atoi(pos + 5);
+
+ pos = os_strstr(param, "ht_enabled=1");
+ if (pos)
+ data.dfs_event.ht_enabled = 1;
+
+ pos = os_strstr(param, "chan_offset=");
+ if (pos)
+ data.dfs_event.chan_offset = atoi(pos + 12);
+
+ pos = os_strstr(param, "chan_width=");
+ if (pos)
+ data.dfs_event.chan_width = atoi(pos + 11);
+
+ pos = os_strstr(param, "cf1=");
+ if (pos)
+ data.dfs_event.cf1 = atoi(pos + 4);
+
+ pos = os_strstr(param, "cf2=");
+ if (pos)
+ data.dfs_event.cf2 = atoi(pos + 4);
+
+ wpa_supplicant_event(hapd, event, &data);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
+{
+ size_t len;
+ u8 *buf;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
+
+ len = os_strlen(cmd);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(cmd, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ res = hostapd_drv_send_mlme(hapd, buf, len, 0);
+ os_free(buf);
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
+{
+ char *pos;
+ u8 src[ETH_ALEN], *buf;
+ int used;
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ ieee802_1x_receive(hapd, src, buf, len);
+ os_free(buf);
+
+ return 0;
+}
+
+
+static u16 ipv4_hdr_checksum(const void *buf, size_t len)
+{
+ size_t i;
+ u32 sum = 0;
+ const u16 *pos = buf;
+
+ for (i = 0; i < len / 2; i++)
+ sum += *pos++;
+
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return sum ^ 0xffff;
+}
+
+
+#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)
+{
+ struct hostapd_data *hapd = ctx;
+ const struct ether_header *eth;
+ const struct iphdr *ip;
+ const u8 *pos;
+ unsigned int i;
+
+ if (len != HWSIM_PACKETLEN)
+ return;
+
+ eth = (const struct ether_header *) buf;
+ ip = (const struct iphdr *) (eth + 1);
+ pos = (const u8 *) (ip + 1);
+
+ if (ip->ihl != 5 || ip->version != 4 ||
+ ntohs(ip->tot_len) != HWSIM_IP_LEN)
+ return;
+
+ for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+ if (*pos != (u8) i)
+ return;
+ pos++;
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+}
+
+
+static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
+ char *cmd)
+{
+ int enabled = atoi(cmd);
+ char *pos;
+ const char *ifname;
+
+ if (!enabled) {
+ if (hapd->l2_test) {
+ l2_packet_deinit(hapd->l2_test);
+ hapd->l2_test = NULL;
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "test data: Disabled");
+ }
+ return 0;
+ }
+
+ if (hapd->l2_test)
+ return 0;
+
+ pos = os_strstr(cmd, " ifname=");
+ if (pos)
+ ifname = pos + 8;
+ else
+ ifname = hapd->conf->iface;
+
+ hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
+ ETHERTYPE_IP, hostapd_data_test_rx,
+ hapd, 1);
+ if (hapd->l2_test == NULL)
+ return -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
+{
+ u8 dst[ETH_ALEN], src[ETH_ALEN];
+ char *pos;
+ int used;
+ long int val;
+ u8 tos;
+ u8 buf[HWSIM_PACKETLEN];
+ struct ether_header *eth;
+ struct iphdr *ip;
+ u8 *dpos;
+ unsigned int i;
+
+ if (hapd->l2_test == NULL)
+ return -1;
+
+ /* format: <dst> <src> <tos> */
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, dst);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+
+ val = strtol(pos, NULL, 0);
+ if (val < 0 || val > 0xff)
+ return -1;
+ tos = val;
+
+ eth = (struct ether_header *) buf;
+ os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
+ os_memcpy(eth->ether_shost, src, ETH_ALEN);
+ eth->ether_type = htons(ETHERTYPE_IP);
+ ip = (struct iphdr *) (eth + 1);
+ os_memset(ip, 0, sizeof(*ip));
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->ttl = 64;
+ ip->tos = tos;
+ ip->tot_len = htons(HWSIM_IP_LEN);
+ ip->protocol = 1;
+ ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->daddr = htonl(192 << 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++)
+ *dpos++ = i;
+
+ if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, buf,
+ HWSIM_PACKETLEN) < 0)
+ return -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
+ " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
+ char *cmd)
+{
+ u8 *buf;
+ struct ether_header *eth;
+ struct l2_packet_data *l2 = NULL;
+ size_t len;
+ u16 ethertype;
+ int res = -1;
+ const char *ifname = hapd->conf->iface;
+
+ if (os_strncmp(cmd, "ifname=", 7) == 0) {
+ cmd += 7;
+ ifname = cmd;
+ cmd = os_strchr(cmd, ' ');
+ if (cmd == NULL)
+ return -1;
+ *cmd++ = '\0';
+ }
+
+ len = os_strlen(cmd);
+ if (len & 1 || len < ETH_HLEN * 2)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(cmd, buf, len) < 0)
+ goto done;
+
+ eth = (struct ether_header *) buf;
+ ethertype = ntohs(eth->ether_type);
+
+ l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
+ hostapd_data_test_rx, hapd, 1);
+ if (l2 == NULL)
+ goto done;
+
+ res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
+done:
+ if (l2)
+ l2_packet_deinit(l2);
+ os_free(buf);
+
+ return res < 0 ? -1 : 0;
+}
+
+
+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);
+ pos = os_strchr(cmd, ':');
+ if (pos) {
+ pos++;
+ os_strlcpy(wpa_trace_fail_func, pos,
+ sizeof(wpa_trace_fail_func));
+ } else {
+ wpa_trace_fail_after = 0;
+ }
+
+ return 0;
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+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 */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
+ char *pos)
+{
+#ifdef NEED_AP_MLME
+ struct csa_settings settings;
+ int ret;
+ unsigned int i;
+
+ ret = hostapd_parse_csa_settings(pos, &settings);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ ret = hostapd_switch_channel(iface->bss[i], &settings);
+ if (ret) {
+ /* FIX: What do we do if CSA fails in the middle of
+ * submitting multi-BSS CSA requests? */
+ return ret;
+ }
+ }
+
+ return 0;
+#else /* NEED_AP_MLME */
+ return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
+static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
+ int reply_size, const char *param)
+{
+#ifdef RADIUS_SERVER
+ if (os_strcmp(param, "radius_server") == 0) {
+ return radius_server_get_mib(hapd->radius_srv, reply,
+ reply_size);
+ }
+#endif /* RADIUS_SERVER */
+ return -1;
+}
+
+
+static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos;
+ u8 *data = NULL;
+ unsigned int vendor_id, subcmd;
+ struct wpabuf *reply;
+ size_t data_len = 0;
+
+ /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+ vendor_id = strtoul(cmd, &pos, 16);
+ if (!isblank(*pos))
+ return -EINVAL;
+
+ subcmd = strtoul(pos, &pos, 10);
+
+ if (*pos != '\0') {
+ if (!isblank(*pos++))
+ return -EINVAL;
+ data_len = os_strlen(pos);
+ }
+
+ if (data_len) {
+ data_len /= 2;
+ data = os_malloc(data_len);
+ if (!data)
+ return -ENOBUFS;
+
+ if (hexstr2bin(pos, data, data_len)) {
+ wpa_printf(MSG_DEBUG,
+ "Vendor command: wrong parameter format");
+ os_free(data);
+ return -EINVAL;
+ }
+ }
+
+ reply = wpabuf_alloc((buflen - 1) / 2);
+ if (!reply) {
+ os_free(data);
+ return -ENOBUFS;
+ }
+
+ ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
+ reply);
+
+ if (ret == 0)
+ ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
+ wpabuf_len(reply));
+
+ wpabuf_free(reply);
+ os_free(data);
+
+ return ret;
+}
+
+
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
- char buf[256];
+ char buf[4096];
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
@@ -833,7 +1863,8 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
@@ -843,8 +1874,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
reply = os_malloc(reply_size);
if (reply == NULL) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
+ if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
return;
}
@@ -857,6 +1891,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
if (wpa_debug_reopen_file() < 0)
reply_len = -1;
+ } else if (os_strcmp(buf, "STATUS") == 0) {
+ reply_len = hostapd_ctrl_iface_status(hapd, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
+ reply_len = hostapd_drv_status(hapd, reply, reply_size);
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
if (reply_len >= 0) {
@@ -886,6 +1925,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len += res;
}
#endif /* CONFIG_NO_RADIUS */
+ } else if (os_strncmp(buf, "MIB ", 4) == 0) {
+ reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
+ buf + 4);
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
reply_size);
@@ -914,6 +1956,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
reply_len = -1;
+ } else if (os_strcmp(buf, "STOP_AP") == 0) {
+ if (hostapd_ctrl_iface_stop_ap(hapd))
+ reply_len = -1;
#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
@@ -940,6 +1985,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
+ reply_size);
#ifdef CONFIG_WPS_NFC
} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
@@ -950,8 +1998,30 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
reply_len = hostapd_ctrl_iface_wps_nfc_token(
hapd, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
+ hapd, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
+ reply_len = -1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
+#ifdef CONFIG_INTERWORKING
+ } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
+ if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
+ if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
+ reply_len = -1;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
+ if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
+ if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
+ reply_len = -1;
+#endif /* CONFIG_HS20 */
#ifdef CONFIG_WNM
} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
@@ -959,6 +2029,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
reply_len = -1;
+ } 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_strcmp(buf, "GET_CONFIG") == 0) {
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
@@ -978,6 +2051,46 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
if (hostapd_ctrl_iface_disable(hapd->iface))
reply_len = -1;
+ } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
+ if (ieee802_11_set_beacon(hapd))
+ reply_len = -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
+ if (hostapd_ctrl_iface_radar(hapd, buf + 6))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
+ if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
+ if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
+ if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
+ if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
+ if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+ if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+ reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
+ reply_size);
+#endif /* CONFIG_TESTING_OPTIONS */
+ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+ if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
+ reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
+ ieee802_1x_erp_flush(hapd);
+#ifdef RADIUS_SERVER
+ radius_server_erp_flush(hapd->radius_srv);
+#endif /* RADIUS_SERVER */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -987,7 +2100,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
os_free(reply);
}
@@ -1013,7 +2130,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
}
-static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct hostapd_data *hapd = ctx;
@@ -1042,7 +2159,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
- perror("mkdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
+ strerror(errno));
goto fail;
}
}
@@ -1050,7 +2168,17 @@ 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) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[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",
+ strerror(errno));
return -1;
}
@@ -1075,7 +2203,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -1096,15 +2224,16 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
goto fail;
}
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("hostapd-ctrl-iface: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "hostapd-ctrl-iface: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1122,19 +2251,32 @@ 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) {
- perror("chown[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chown[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",
+ strerror(errno));
goto fail;
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
+ strerror(errno));
goto fail;
}
os_free(fname);
hapd->ctrl_sock = s;
- eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
- NULL);
+ if (eloop_register_read_sock(s, 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);
@@ -1172,17 +2314,26 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ hapd->conf->ctrl_interface,
+ strerror(errno));
}
}
}
dst = hapd->ctrl_dst;
+ hapd->ctrl_dst = NULL;
while (dst) {
prev = dst;
dst = dst->next;
os_free(prev);
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+ l2_packet_deinit(hapd->l2_test);
+ hapd->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1208,6 +2359,16 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
}
+static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
+{
+#ifdef CONFIG_WPS_TESTING
+ wps_version_number = 0x20;
+ wps_testing_dummy_cred = 0;
+ wps_corrupt_pkhash = 0;
+#endif /* CONFIG_WPS_TESTING */
+}
+
+
static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -1222,10 +2383,12 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
+ wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
@@ -1233,12 +2396,23 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
+ } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+ if (wpa_debug_reopen_file() < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FLUSH") == 0) {
+ hostapd_ctrl_iface_flush(interfaces);
} else if (os_strncmp(buf, "ADD ", 4) == 0) {
if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
reply_len = -1;
+#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 */
} else {
wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
"ignored");
@@ -1250,7 +2424,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = 5;
}
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
}
@@ -1291,9 +2469,16 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
- perror("mkdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
+ strerror(errno));
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",
+ strerror(errno));
+ goto fail;
}
if (os_strlen(interface->global_iface_path) + 1 +
@@ -1302,7 +2487,7 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -1323,15 +2508,15 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
goto fail;
}
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1347,8 +2532,16 @@ 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",
+ strerror(errno));
+ goto fail;
+ }
+
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
+ strerror(errno));
goto fail;
}
os_free(fname);
@@ -1391,7 +2584,10 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ interfaces->global_iface_path,
+ strerror(errno));
}
}
os_free(interfaces->global_iface_path);
diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig
index b5ddca3..4cde2b5 100644
--- a/contrib/wpa/hostapd/defconfig
+++ b/contrib/wpa/hostapd/defconfig
@@ -15,13 +15,22 @@ CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
-# Driver interface for madwifi driver
-#CONFIG_DRIVER_MADWIFI=y
-#CFLAGS += -I../../madwifi # change to the madwifi source directory
-
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -42,14 +51,14 @@ CONFIG_RSN_PREAUTH=y
CONFIG_PEERKEY=y
# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
-# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
# Integrated EAP server
CONFIG_EAP=y
+# EAP Re-authentication Protocol (ERP) in integrated EAP server
+CONFIG_ERP=y
+
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
@@ -96,16 +105,13 @@ CONFIG_EAP_TTLS=y
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
-# to add the needed functions.
+# 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
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
-# Enable WSC 2.0 support
-#CONFIG_WPS2=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
# Enable WPS support with NFC config method
@@ -117,6 +123,9 @@ CONFIG_EAP_TTLS=y
# Trusted Network Connect (EAP-TNC)
#CONFIG_EAP_TNC=y
+# EAP-EKE for the integrated EAP server
+#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
@@ -132,7 +141,7 @@ CONFIG_IPV6=y
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
-# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
@@ -154,6 +163,12 @@ CONFIG_IPV6=y
# Disabled by default.
#CONFIG_DEBUG_FILE=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
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
# Remove support for RADIUS accounting
#CONFIG_NO_ACCOUNTING=y
@@ -171,7 +186,7 @@ CONFIG_IPV6=y
# Note: This requires libnl 3.1 or newer.
#CONFIG_VLAN_NETLINK=y
-# Remove support for dumping state into a file on SIGUSR1 signal
+# Remove support for dumping internal state through control interface commands
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
#CONFIG_NO_DUMP_STATE=y
@@ -267,3 +282,35 @@ CONFIG_IPV6=y
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
+
+# Testing options
+# This can be used to enable some testing options (see also the example
+# configuration file) that are really useful only for testing clients that
+# connect to this hostapd. These options allow, for example, to drop a
+# certain percentage of probe requests or auth/(re)assoc frames.
+#
+#CONFIG_TESTING_OPTIONS=y
+
+# Automatic Channel Selection
+# This will allow hostapd to pick the channel automatically when channel is set
+# to "acs_survey" or "0". Eventually, other ACS algorithms can be added 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.
+#
+# You can customize the ACS survey algorithm with the hostapd.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
diff --git a/contrib/wpa/hostapd/dump_state.c b/contrib/wpa/hostapd/dump_state.c
deleted file mode 100644
index d33e05f..0000000
--- a/contrib/wpa/hostapd/dump_state.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-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 <time.h>
-
-#include "utils/common.h"
-#include "radius/radius_client.h"
-#include "radius/radius_server.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "eap_server/eap.h"
-#include "ap/hostapd.h"
-#include "ap/ap_config.h"
-#include "ap/sta_info.h"
-#include "dump_state.h"
-
-
-static void fprint_char(FILE *f, char c)
-{
- if (c >= 32 && c < 127)
- fprintf(f, "%c", c);
- else
- fprintf(f, "<%02x>", c);
-}
-
-
-static void ieee802_1x_dump_state(FILE *f, const char *prefix,
- struct sta_info *sta)
-{
- struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
- return;
-
- fprintf(f, "%sIEEE 802.1X:\n", prefix);
-
- if (sm->identity) {
- size_t i;
- fprintf(f, "%sidentity=", prefix);
- for (i = 0; i < sm->identity_len; i++)
- fprint_char(f, sm->identity[i]);
- fprintf(f, "\n");
- }
-
- fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
- "Supplicant: %d (%s)\n", prefix,
- sm->eap_type_authsrv,
- eap_server_get_name(0, sm->eap_type_authsrv),
- sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
-
- fprintf(f, "%scached_packets=%s\n", prefix,
- sm->last_recv_radius ? "[RX RADIUS]" : "");
-
- eapol_auth_dump_state(f, prefix, sm);
-}
-
-
-/**
- * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
- */
-static void hostapd_dump_state(struct hostapd_data *hapd)
-{
- FILE *f;
- time_t now;
- struct sta_info *sta;
- int i;
-#ifndef CONFIG_NO_RADIUS
- char *buf;
-#endif /* CONFIG_NO_RADIUS */
-
- if (!hapd->conf->dump_log_name) {
- wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
- "request");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
- hapd->conf->dump_log_name);
- f = fopen(hapd->conf->dump_log_name, "w");
- if (f == NULL) {
- wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
- "writing.", hapd->conf->dump_log_name);
- return;
- }
-
- time(&now);
- fprintf(f, "hostapd state dump - %s", ctime(&now));
- fprintf(f, "num_sta=%d num_sta_non_erp=%d "
- "num_sta_no_short_slot_time=%d\n"
- "num_sta_no_short_preamble=%d\n",
- hapd->num_sta, hapd->iface->num_sta_non_erp,
- hapd->iface->num_sta_no_short_slot_time,
- hapd->iface->num_sta_no_short_preamble);
-
- for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
- fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
-
- fprintf(f,
- " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
- "\n"
- " capability=0x%x listen_interval=%d\n",
- sta->aid,
- sta->flags,
- (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
- (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
- (sta->flags & WLAN_STA_PS ? "[PS]" : ""),
- (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
- (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
- (ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
- (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
- ""),
- (sta->flags & WLAN_STA_SHORT_PREAMBLE ?
- "[SHORT_PREAMBLE]" : ""),
- (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
- (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
- (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
- (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
- (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
- (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
- (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
- (sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
- sta->capability,
- sta->listen_interval);
-
- fprintf(f, " supported_rates=");
- for (i = 0; i < sta->supported_rates_len; i++)
- fprintf(f, "%02x ", sta->supported_rates[i]);
- fprintf(f, "\n");
-
- fprintf(f,
- " timeout_next=%s\n",
- (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
- (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
- "DEAUTH")));
-
- ieee802_1x_dump_state(f, " ", sta);
- }
-
-#ifndef CONFIG_NO_RADIUS
- buf = os_malloc(4096);
- if (buf) {
- int count = radius_client_get_mib(hapd->radius, buf, 4096);
- if (count < 0)
- count = 0;
- else if (count > 4095)
- count = 4095;
- buf[count] = '\0';
- fprintf(f, "%s", buf);
-
-#ifdef RADIUS_SERVER
- count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
- if (count < 0)
- count = 0;
- else if (count > 4095)
- count = 4095;
- buf[count] = '\0';
- fprintf(f, "%s", buf);
-#endif /* RADIUS_SERVER */
-
- os_free(buf);
- }
-#endif /* CONFIG_NO_RADIUS */
- fclose(f);
-}
-
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
-{
- size_t i;
-
- for (i = 0; i < iface->num_bss; i++)
- hostapd_dump_state(iface->bss[i]);
-
- return 0;
-}
diff --git a/contrib/wpa/hostapd/dump_state.h b/contrib/wpa/hostapd/dump_state.h
deleted file mode 100644
index a209d65..0000000
--- a/contrib/wpa/hostapd/dump_state.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef DUMP_STATE_H
-#define DUMP_STATE_H
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
-
-#endif /* DUMP_STATE_H */
diff --git a/contrib/wpa/hostapd/eap_register.c b/contrib/wpa/hostapd/eap_register.c
index 0a7ff91..8477c21 100644
--- a/contrib/wpa/hostapd/eap_register.c
+++ b/contrib/wpa/hostapd/eap_register.c
@@ -44,6 +44,13 @@ int eap_server_register_methods(void)
ret = eap_server_unauth_tls_register();
#endif /* EAP_SERVER_TLS */
+#ifdef EAP_SERVER_TLS
+#ifdef CONFIG_HS20
+ if (ret == 0)
+ ret = eap_server_wfa_unauth_tls_register();
+#endif /* CONFIG_HS20 */
+#endif /* EAP_SERVER_TLS */
+
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
@@ -134,5 +141,10 @@ int eap_server_register_methods(void)
ret = eap_server_pwd_register();
#endif /* EAP_SERVER_PWD */
+#ifdef EAP_SERVER_EKE
+ if (ret == 0)
+ ret = eap_server_eke_register();
+#endif /* EAP_SERVER_EKE */
+
return ret;
}
diff --git a/contrib/wpa/hostapd/hapd_module_tests.c b/contrib/wpa/hostapd/hapd_module_tests.c
new file mode 100644
index 0000000..f7887eb
--- /dev/null
+++ b/contrib/wpa/hostapd/hapd_module_tests.c
@@ -0,0 +1,17 @@
+/*
+ * hostapd module tests
+ * Copyright (c) 2014, 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"
+
+int hapd_module_tests(void)
+{
+ wpa_printf(MSG_INFO, "hostapd module tests");
+ return 0;
+}
diff --git a/contrib/wpa/hostapd/hlr_auc_gw.c b/contrib/wpa/hostapd/hlr_auc_gw.c
index e04e2e9..42d59db 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, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,6 +18,9 @@
* SIM-REQ-AUTH <IMSI> <max_chal>
* SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
* SIM-RESP-AUTH <IMSI> FAILURE
+ * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3]
+ * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3]
+ * GSM-AUTH-RESP <IMSI> FAILURE
*
* EAP-AKA / UMTS query/response:
* AKA-REQ-AUTH <IMSI>
@@ -30,12 +33,16 @@
* IMSI and max_chal are sent as an ASCII string,
* Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
*
- * The example implementation here reads GSM authentication triplets from a
+ * An example implementation here reads GSM authentication triplets from a
* text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
* strings. This is used to simulate an HLR/AuC. As such, it is not very useful
* for real life authentication, but it is useful both as an example
* implementation and for EAP-SIM/AKA/AKA' testing.
*
+ * For a stronger example design, Milenage and GSM-Milenage algorithms can be
+ * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and
+ * EAP-SIM, respectively, if Ki is known.
+ *
* SQN generation follows the not time-based Profile 2 described in
* 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
* can be changed with a command line options if needed.
@@ -58,6 +65,7 @@ static char *milenage_file = NULL;
static int update_milenage = 0;
static int sqn_changes = 0;
static int ind_len = 5;
+static int stdout_debug = 1;
/* GSM triplets */
struct gsm_triplet {
@@ -214,6 +222,9 @@ static int db_update_milenage_sqn(struct milenage_parameters *m)
{
char cmd[128], val[13], *pos;
+ if (sqlite_db == NULL)
+ return 0;
+
pos = val;
pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
*pos = '\0';
@@ -611,31 +622,30 @@ static struct milenage_parameters * get_milenage(const char *imsi)
}
-static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
- char *imsi)
+static int sim_req_auth(char *imsi, char *resp, size_t resp_len)
{
int count, max_chal, ret;
char *pos;
- char reply[1000], *rpos, *rend;
+ char *rpos, *rend;
struct milenage_parameters *m;
struct gsm_triplet *g;
- reply[0] = '\0';
+ resp[0] = '\0';
pos = strchr(imsi, ' ');
if (pos) {
*pos++ = '\0';
max_chal = atoi(pos);
- if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+ if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL)
max_chal = EAP_SIM_MAX_CHAL;
} else
max_chal = EAP_SIM_MAX_CHAL;
- rend = &reply[sizeof(reply)];
- rpos = reply;
+ rend = resp + resp_len;
+ rpos = resp;
ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
if (ret < 0 || ret >= rend - rpos)
- return;
+ return -1;
rpos += ret;
m = get_milenage(imsi);
@@ -643,7 +653,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
u8 _rand[16], sres[4], kc[8];
for (count = 0; count < max_chal; count++) {
if (random_get_bytes(_rand, 16) < 0)
- return;
+ return -1;
gsm_milenage(m->opc, m->ki, _rand, sres, kc);
*rpos++ = ' ';
rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
@@ -653,7 +663,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
}
*rpos = '\0';
- goto send;
+ return 0;
}
count = 0;
@@ -677,15 +687,61 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
printf("No GSM triplets found for %s\n", imsi);
ret = snprintf(rpos, rend - rpos, " FAILURE");
if (ret < 0 || ret >= rend - rpos)
- return;
+ return -1;
rpos += ret;
}
-send:
- printf("Send: %s\n", reply);
- if (sendto(s, reply, rpos - reply, 0,
- (struct sockaddr *) from, fromlen) < 0)
- perror("send");
+ return 0;
+}
+
+
+static int gsm_auth_req(char *imsi, char *resp, size_t resp_len)
+{
+ int count, ret;
+ char *pos, *rpos, *rend;
+ struct milenage_parameters *m;
+
+ resp[0] = '\0';
+
+ pos = os_strchr(imsi, ' ');
+ if (!pos)
+ return -1;
+ *pos++ = '\0';
+
+ rend = resp + resp_len;
+ rpos = resp;
+ ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
+ if (os_snprintf_error(rend - rpos, ret))
+ return -1;
+ rpos += ret;
+
+ m = get_milenage(imsi);
+ if (m) {
+ u8 _rand[16], sres[4], kc[8];
+ for (count = 0; count < EAP_SIM_MAX_CHAL; count++) {
+ if (hexstr2bin(pos, _rand, 16) != 0)
+ return -1;
+ gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+ *rpos++ = count == 0 ? ' ' : ':';
+ rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+ *rpos++ = ':';
+ rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+ pos += 16 * 2;
+ if (*pos != ':')
+ break;
+ pos++;
+ }
+ *rpos = '\0';
+ return 0;
+ }
+
+ printf("No GSM triplets found for %s\n", imsi);
+ ret = os_snprintf(rpos, rend - rpos, " FAILURE");
+ if (os_snprintf_error(rend - rpos, ret))
+ return -1;
+ rpos += ret;
+
+ return 0;
}
@@ -711,11 +767,10 @@ static void inc_sqn(u8 *sqn)
}
-static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
- char *imsi)
+static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
{
/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
- char reply[1000], *pos, *end;
+ char *pos, *end;
u8 _rand[EAP_AKA_RAND_LEN];
u8 autn[EAP_AKA_AUTN_LEN];
u8 ik[EAP_AKA_IK_LEN];
@@ -729,16 +784,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
m = get_milenage(imsi);
if (m) {
if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
- return;
+ return -1;
res_len = EAP_AKA_RES_MAX_LEN;
inc_sqn(m->sqn);
#ifdef CONFIG_SQLITE
db_update_milenage_sqn(m);
#endif /* CONFIG_SQLITE */
sqn_changes = 1;
- printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
- m->sqn[0], m->sqn[1], m->sqn[2],
- m->sqn[3], m->sqn[4], m->sqn[5]);
+ if (stdout_debug) {
+ printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+ m->sqn[0], m->sqn[1], m->sqn[2],
+ m->sqn[3], m->sqn[4], m->sqn[5]);
+ }
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
autn, ik, ck, res, &res_len);
} else {
@@ -756,18 +813,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
#endif /* AKA_USE_FIXED_TEST_VALUES */
}
- pos = reply;
- end = &reply[sizeof(reply)];
+ pos = resp;
+ end = resp + resp_len;
ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
if (ret < 0 || ret >= end - pos)
- return;
+ return -1;
pos += ret;
if (failed) {
ret = snprintf(pos, end - pos, "FAILURE");
if (ret < 0 || ret >= end - pos)
- return;
+ return -1;
pos += ret;
- goto done;
+ return 0;
}
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
*pos++ = ' ';
@@ -779,65 +836,87 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
-done:
- printf("Send: %s\n", reply);
-
- if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
- fromlen) < 0)
- perror("send");
+ return 0;
}
-static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
- char *imsi)
+static int aka_auts(char *imsi, char *resp, size_t resp_len)
{
char *auts, *__rand;
u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
struct milenage_parameters *m;
+ resp[0] = '\0';
+
/* AKA-AUTS <IMSI> <AUTS> <RAND> */
auts = strchr(imsi, ' ');
if (auts == NULL)
- return;
+ return -1;
*auts++ = '\0';
__rand = strchr(auts, ' ');
if (__rand == NULL)
- return;
+ return -1;
*__rand++ = '\0';
- printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
+ if (stdout_debug) {
+ printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
+ imsi, auts, __rand);
+ }
if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
printf("Could not parse AUTS/RAND\n");
- return;
+ return -1;
}
m = get_milenage(imsi);
if (m == NULL) {
printf("Unknown IMSI: %s\n", imsi);
- return;
+ return -1;
}
if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
printf("AKA-AUTS: Incorrect MAC-S\n");
} else {
memcpy(m->sqn, sqn, 6);
- printf("AKA-AUTS: Re-synchronized: "
- "SQN=%02x%02x%02x%02x%02x%02x\n",
- sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+ if (stdout_debug) {
+ printf("AKA-AUTS: Re-synchronized: "
+ "SQN=%02x%02x%02x%02x%02x%02x\n",
+ sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+ }
#ifdef CONFIG_SQLITE
db_update_milenage_sqn(m);
#endif /* CONFIG_SQLITE */
sqn_changes = 1;
}
+
+ return 0;
+}
+
+
+static int process_cmd(char *cmd, char *resp, size_t resp_len)
+{
+ if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
+ return sim_req_auth(cmd + 13, resp, resp_len);
+
+ if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0)
+ return gsm_auth_req(cmd + 13, resp, resp_len);
+
+ if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
+ return aka_req_auth(cmd + 13, resp, resp_len);
+
+ if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
+ return aka_auts(cmd + 9, resp, resp_len);
+
+ printf("Unknown request: %s\n", cmd);
+ return -1;
}
static int process(int s)
{
- char buf[1000];
+ char buf[1000], resp[1000];
struct sockaddr_un from;
socklen_t fromlen;
ssize_t res;
@@ -859,14 +938,21 @@ static int process(int s)
printf("Received: %s\n", buf);
- if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
- sim_req_auth(s, &from, fromlen, buf + 13);
- else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
- aka_req_auth(s, &from, fromlen, buf + 13);
- else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
- aka_auts(s, &from, fromlen, buf + 9);
- else
- printf("Unknown request: %s\n", buf);
+ if (process_cmd(buf, resp, sizeof(resp)) < 0) {
+ printf("Failed to process request\n");
+ return -1;
+ }
+
+ if (resp[0] == '\0') {
+ printf("No response\n");
+ return 0;
+ }
+
+ printf("Send: %s\n", resp);
+
+ if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
+ fromlen) < 0)
+ perror("send");
return 0;
}
@@ -894,8 +980,10 @@ static void cleanup(void)
os_free(prev);
}
- close(serv_sock);
- unlink(socket_path);
+ if (serv_sock >= 0)
+ close(serv_sock);
+ if (socket_path)
+ unlink(socket_path);
#ifdef CONFIG_SQLITE
if (sqlite_db) {
@@ -917,12 +1005,12 @@ static void usage(void)
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
- "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
+ "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
"[-m<milenage file>] \\\n"
- " [-D<DB file>] [-i<IND len in bits>]\n"
+ " [-D<DB file>] [-i<IND len in bits>] [command]\n"
"\n"
"options:\n"
" -h = show this usage help\n"
@@ -932,7 +1020,15 @@ static void usage(void)
" -g<triplet file> = path for GSM authentication triplets\n"
" -m<milenage file> = path for Milenage keys\n"
" -D<DB file> = path to SQLite database\n"
- " -i<IND len in bits> = IND length for SQN (default: 5)\n",
+ " -i<IND len in bits> = IND length for SQN (default: 5)\n"
+ "\n"
+ "If the optional command argument, like "
+ "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
+ "command is processed with response sent to stdout. Otherwise, "
+ "hlr_auc_gw opens\n"
+ "a control interface and processes commands sent through it "
+ "(e.g., by EAP server\n"
+ "in hostapd).\n",
default_socket_path);
}
@@ -942,6 +1038,7 @@ int main(int argc, char *argv[])
int c;
char *gsm_triplet_file = NULL;
char *sqlite_db_file = NULL;
+ int ret = 0;
if (os_program_init())
return -1;
@@ -1005,18 +1102,31 @@ int main(int argc, char *argv[])
if (milenage_file && read_milenage(milenage_file) < 0)
return -1;
- serv_sock = open_socket(socket_path);
- if (serv_sock < 0)
- return -1;
+ if (optind == argc) {
+ serv_sock = open_socket(socket_path);
+ if (serv_sock < 0)
+ return -1;
- printf("Listening for requests on %s\n", socket_path);
+ printf("Listening for requests on %s\n", socket_path);
- atexit(cleanup);
- signal(SIGTERM, handle_term);
- signal(SIGINT, handle_term);
+ atexit(cleanup);
+ signal(SIGTERM, handle_term);
+ signal(SIGINT, handle_term);
- for (;;)
- process(serv_sock);
+ for (;;)
+ process(serv_sock);
+ } else {
+ char buf[1000];
+ socket_path = NULL;
+ stdout_debug = 0;
+ if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
+ printf("FAIL\n");
+ ret = -1;
+ } else {
+ printf("%s\n", buf);
+ }
+ cleanup();
+ }
#ifdef CONFIG_SQLITE
if (sqlite_db) {
@@ -1027,5 +1137,5 @@ int main(int argc, char *argv[])
os_program_deinit();
- return 0;
+ return ret;
}
diff --git a/contrib/wpa/hostapd/hostapd.8 b/contrib/wpa/hostapd/hostapd.8
index b4456bb..d19d862 100644
--- a/contrib/wpa/hostapd/hostapd.8
+++ b/contrib/wpa/hostapd/hostapd.8
@@ -12,7 +12,7 @@ daemon.
.B hostapd
is a user space daemon for access point and authentication servers.
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
-The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211).
+The current version supports Linux (Host AP, mac80211-based drivers) and FreeBSD (net80211).
.B hostapd
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf
index 75b1941..9e81e9e 100644
--- a/contrib/wpa/hostapd/hostapd.conf
+++ b/contrib/wpa/hostapd/hostapd.conf
@@ -2,10 +2,10 @@
# Empty lines and lines starting with # are ignored
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
-# management frames); ath0 for madwifi
+# management frames with the Host AP driver); wlan0 with many nl80211 drivers
interface=wlan0
-# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
+# In case of atheros and nl80211 driver interfaces, an additional
# configuration parameter, bridge, may be used to notify hostapd if the
# interface is included in a bridge. This parameter is not used with Host AP
# driver. If the bridge parameter is not set, the drivers will automatically
@@ -18,12 +18,15 @@ interface=wlan0
# interface is also created.
#bridge=br0
-# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
+# Driver interface type (hostap/wired/none/nl80211/bsd);
# default: hostap). nl80211 is used with all Linux mac80211 drivers.
# Use driver=none if building hostapd as a standalone RADIUS server that does
# not control any wireless/wired driver.
# driver=hostap
+# Driver interface parameters (mainly for development testing use)
+# driver_params=<params>
+
# hostapd event logger configuration
#
# Two output method: syslog and stdout (only usable if not forking to
@@ -51,9 +54,6 @@ logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
-# Dump file for state information (on SIGUSR1)
-dump_file=/tmp/hostapd.dump
-
# Interface for separate control program. If this is specified, hostapd
# will create this directory and a UNIX domain socket for listening to requests
# from external programs (CLI/GUI, etc.) for status information and
@@ -105,6 +105,26 @@ ssid=test
# (default: 0 = disabled)
#ieee80211d=1
+# Enable IEEE 802.11h. This enables radar detection and DFS support if
+# available. DFS support is required on outdoor 5 GHz channels in most countries
+# of the world. This can be used only with ieee80211d=1.
+# (default: 0 = disabled)
+#ieee80211h=1
+
+# Add Power Constraint element to Beacon and Probe Response frames
+# This config option adds Power Constraint element when applicable and Country
+# element is added. Power Constraint element is required by Transmit Power
+# Control. This can be used only with ieee80211d=1.
+# Valid values are 0..255.
+#local_pwr_constraint=3
+
+# Set Spectrum Management subfield in the Capability Information field.
+# This config option forces the Spectrum Management bit to be set. When this
+# option is not set, the value of the Spectrum Management bit depends on whether
+# DFS or TPC is required by regulatory authorities. This can be used only with
+# 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)
@@ -115,8 +135,44 @@ hw_mode=g
# (default: 0, i.e., not set)
# Please note that some drivers do not use this value from hostapd and the
# channel will need to be configured separately with iwconfig.
+#
+# If CONFIG_ACS build option is enabled, the channel can be selected
+# automatically at run time by setting channel=acs_survey or channel=0, both of
+# which will enable the ACS survey based algorithm.
channel=1
+# ACS tuning - Automatic Channel Selection
+# See: http://wireless.kernel.org/en/users/Documentation/acs
+#
+# You can customize the ACS survey algorithm with following variables:
+#
+# acs_num_scans requirement is 1..100 - number of scans to be performed that
+# are used to trigger survey data gathering of an underlying device driver.
+# Scans are passive and typically take a little over 100ms (depending on the
+# driver) on each available channel for given hw_mode. Increasing this value
+# means sacrificing startup time and gathering more data wrt channel
+# interference that may help choosing a better channel. This can also help fine
+# tune the ACS scan time in case a driver has different scan dwell times.
+#
+# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be
+# used to increase (or decrease) the likelihood of a specific channel to be
+# selected by the ACS algorithm. The total interference factor for each channel
+# gets multiplied by the specified bias value before finding the channel with
+# the lowest value. In other words, values between 0.0 and 1.0 can be used to
+# make a channel more likely to be picked while values larger than 1.0 make the
+# specified channel less likely to be picked. This can be used, e.g., to prefer
+# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default
+# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified).
+#
+# Defaults:
+#acs_num_scans=5
+#acs_chan_bias=1:0.8 6:0.8 11:0.8
+
+# Channel list restriction. This option allows hostapd to select one of the
+# provided channels when a channel should be automatically selected.
+# Default: not set (allow any enabled channel to be selected)
+#chanlist=100 104 108 112 116
+
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@@ -176,7 +232,7 @@ fragm_threshold=2346
# Station MAC address -based authentication
# Please note that this kind of access control requires a driver that uses
# hostapd to take care of management frame processing and as such, this can be
-# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
+# used with driver=hostap or driver=nl80211, but not with driver=atheros.
# 0 = accept unless in deny list
# 1 = deny unless in accept list
# 2 = use external RADIUS server (accept/deny lists are searched first)
@@ -383,10 +439,24 @@ wmm_ac_vo_acm=0
# use a separate bridge.
#wds_bridge=wds-br0
+# Start the AP with beaconing disabled by default.
+#start_disabled=0
+
# 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=1
+# BSS Load update period (in BUs)
+# This field is used to enable and configure adding a BSS Load element into
+# Beacon and Probe Response frames.
+#bss_load_update_period=50
+
+# 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
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -399,7 +469,7 @@ wmm_ac_vo_acm=0
# LDPC coding capability: [LDPC] = supported
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
-# with secondary channel below the primary channel
+# with secondary channel above the primary channel
# (20 MHz only if neither is set)
# Note: There are limits on which channels can be used with HT40- and
# HT40+. Following table shows the channels that may be available for
@@ -426,13 +496,20 @@ wmm_ac_vo_acm=0
# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
# set)
# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
-# PSMP support: [PSMP] (disabled if not set)
+# 40 MHz intolerant [40-INTOLERANT] (not advertised if not set)
# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
# Require stations to support HT PHY (reject association if they do not)
#require_ht=1
+# If set non-zero, require stations to perform scans of overlapping
+# channels to test for stations which would be affected by 40 MHz traffic.
+# This parameter sets the interval in seconds between these scans. Setting this
+# to non-zero allows 2.4 GHz band AP to move dynamically to a 40 MHz channel if
+# no co-existence issues with neighboring devices are found.
+#obss_interval=0
+
##### IEEE 802.11ac related configuration #####################################
# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
@@ -627,6 +704,17 @@ eapol_key_index_workaround=0
# is only used by one station.
#use_pae_group_addr=1
+# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696)
+#
+# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before
+# EAP-Identity/Request
+#erp_send_reauth_start=1
+#
+# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not
+# set (no local ER server). This is also used by the integrated EAP server if
+# ERP is enabled (eap_server_erp=1).
+#erp_domain=example.com
+
##### Integrated EAP server ###################################################
# Optionally, hostapd can be configured to use an integrated EAP server
@@ -660,6 +748,11 @@ eap_server=0
# Passphrase for private key
#private_key_passwd=secret passphrase
+# Server identity
+# EAP methods that provide mechanism for authenticated server identity delivery
+# use this value. If not set, "hostapd" is used as a default.
+#server_id=server.example.com
+
# Enable CRL verification.
# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
# valid CRL signed by the CA is required to be included in the ca_cert file.
@@ -671,6 +764,20 @@ eap_server=0
# 2 = check all CRLs in the certificate path
#check_crl=1
+# 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.
+# This cache file can be updated, e.g., by running following command
+# periodically to get an update from the OCSP responder:
+# openssl ocsp \
+# -no_nonce \
+# -CAfile /etc/hostapd.ca.pem \
+# -issuer /etc/hostapd.ca.pem \
+# -cert /etc/hostapd.server.pem \
+# -url http://ocsp.example.com:8888/ \
+# -respout /tmp/ocsp-cache.der
+#ocsp_stapling_response=/tmp/ocsp-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
@@ -683,6 +790,15 @@ eap_server=0
# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
#dh_file=/etc/hostapd.dh.pem
+# 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.
+# 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
+
# Fragment size for EAP methods
#fragment_size=1400
@@ -744,6 +860,10 @@ eap_server=0
# EAP method is enabled, the peer will be allowed to connect without TNC.
#tnc=1
+# EAP Re-authentication Protocol (ERP) - RFC 6696
+#
+# Whether to enable ERP on the EAP server.
+#eap_server_erp=1
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
@@ -765,6 +885,12 @@ own_ip_addr=127.0.0.1
# 48 octets long.
#nas_identifier=ap.example.com
+# RADIUS client forced local IP address for the access point
+# Normally the local IP address is determined automatically based on configured
+# IP addresses, but this field can be used to force a specific address to be
+# used, e.g., when the device has multiple IP addresses.
+#radius_client_addr=127.0.0.1
+
# RADIUS authentication server
#auth_server_addr=127.0.0.1
#auth_server_port=1812
@@ -814,9 +940,8 @@ own_ip_addr=127.0.0.1
# is used for the stations. This information is parsed from following RADIUS
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
-# VLANID as a string). vlan_file option below must be configured if dynamic
-# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
-# used to set static client MAC address to VLAN ID mapping.
+# 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
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
@@ -828,6 +953,8 @@ own_ip_addr=127.0.0.1
# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
# interface and the line must include VLAN ID and interface name separated by
# white space (space or tab).
+# If no entries are provided by this file, the station is statically mapped
+# to <bss-iface>.<vlan-id> interfaces.
#vlan_file=/etc/hostapd.vlan
# Interface where 802.1q tagged packets should appear when a RADIUS server is
@@ -837,6 +964,12 @@ own_ip_addr=127.0.0.1
# to the bridge.
#vlan_tagged_interface=eth0
+# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
+# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
+# and br%s.%d if a tagged interface is given, provided %s = tagged interface
+# and %d = VLAN ID.
+#vlan_bridge=brvlan
+
# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
# to know how to name it.
# 0 = vlan<XXX>, e.g., vlan1
@@ -906,6 +1039,11 @@ own_ip_addr=127.0.0.1
# The UDP port number for the RADIUS authentication server
#radius_server_auth_port=1812
+# The UDP port number for the RADIUS accounting server
+# Commenting this out or setting this to 0 can be used to disable RADIUS
+# accounting while still enabling RADIUS authentication.
+#radius_server_acct_port=1813
+
# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
#radius_server_ipv6=1
@@ -1012,6 +1150,17 @@ own_ip_addr=127.0.0.1
# 2 = required
#ieee80211w=0
+# Group management cipher suite
+# Default: AES-128-CMAC (BIP)
+# Other options (depending on driver support):
+# BIP-GMAC-128
+# BIP-GMAC-256
+# BIP-CMAC-256
+# Note: All the stations connecting to the BSS will also need to support the
+# selected cipher. The default AES-128-CMAC is the only option that is commonly
+# available in deployed devices.
+#group_mgmt_cipher=AES-128-CMAC
+
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@@ -1037,6 +1186,19 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#okc=1
+# 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
+
+# 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
+# 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
##### IEEE 802.11r configuration ##############################################
@@ -1111,6 +1273,14 @@ own_ip_addr=127.0.0.1
# 2 = WPS enabled, configured
#wps_state=2
+# Whether to manage this interface independently from other WPS interfaces
+# By default, a single hostapd process applies WPS operations to all configured
+# interfaces. This parameter can be used to disable that behavior for a subset
+# of interfaces. If this is set to non-zero for an interface, WPS commands
+# issued on that interface do not apply to other interfaces and WPS operations
+# performed on other interfaces do not affect this interface.
+#wps_independent=0
+
# AP can be configured into a locked state where new WPS Registrar are not
# accepted, but previously authorized Registrars (including the internal one)
# can continue to add new Enrollees.
@@ -1315,6 +1485,11 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#bss_transition=1
+# Proxy ARP
+# 0 = disabled (default)
+# 1 = enabled
+#proxy_arp=1
+
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
@@ -1381,6 +1556,9 @@ own_ip_addr=127.0.0.1
# information to be complete.
#venue_name=eng:Example venue
#venue_name=fin:Esimerkkipaikka
+# Alternative format for language:value strings:
+# (double quoted string, printf-escaped string)
+#venue_name=P"eng:Example\nvenue"
# Network Authentication Type
# This parameter indicates what type of network authentication is used in the
@@ -1432,6 +1610,8 @@ own_ip_addr=127.0.0.1
# accordance with IETF RFC 4282
# NAI Realm(s): Semi-colon delimited NAI Realm(s)
# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# EAP Method types, see:
+# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4
# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
# ID 2 = Non-EAP Inner Authentication Type
# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
@@ -1445,6 +1625,23 @@ own_ip_addr=127.0.0.1
# username/password
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+# QoS Map Set configuration
+#
+# Comma delimited QoS Map Set in decimal values
+# (see IEEE Std 802.11-2012, 8.4.2.97)
+#
+# format:
+# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
+#
+# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
+# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
+# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
+# each UP starting from 0. If both low and high value are set to 255, the
+# corresponding UP is not used.
+#
+# default: not set
+#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
+
##### Hotspot 2.0 #############################################################
# Enable Hotspot 2.0 support
@@ -1457,6 +1654,21 @@ own_ip_addr=127.0.0.1
# forging such frames to other stations in the BSS.
#disable_dgaf=1
+# OSU Server-Only Authenticated L2 Encryption Network
+#osen=1
+
+# ANQP Domain ID (0..65535)
+# An identifier for a set of APs in an ESS that share the same common ANQP
+# information. 0 = Some of the ANQP information is unique to this AP (default).
+#anqp_domain_id=1234
+
+# Deauthentication request timeout
+# If the RADIUS server indicates that the station is not allowed to connect to
+# the BSS/ESS, the AP can allow the station some time to download a
+# notification page (URL included in the message). This parameter sets that
+# timeout in seconds.
+#hs20_deauth_req_timeout=60
+
# Operator Friendly Name
# This parameter can be used to configure one or more Operator Friendly Name
# Duples. Each entry has a two or three character language code (ISO-639)
@@ -1500,6 +1712,54 @@ own_ip_addr=127.0.0.1
# channels 36-48):
#hs20_operating_class=5173
+# OSU 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
+
+# OSU SSID (see ssid2 for format description)
+# This is the SSID used for all OSU connections to all the listed OSU Providers.
+#osu_ssid="example"
+
+# 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.
+#
+#osu_server_uri=https://example.com/osu/
+#osu_friendly_name=eng:Example operator
+#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
+#osu_nai=anonymous@example.com
+#osu_method_list=1 0
+#osu_icon=icon32
+#osu_icon=icon64
+#osu_service_desc=eng:Example services
+#osu_service_desc=fin:Esimerkkipalveluja
+#
+#osu_server_uri=...
+
+##### TESTING OPTIONS #########################################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow
+# testing some scenarios that are otherwise difficult to reproduce.
+#
+# Ignore probe requests sent to hostapd with the given probability, must be a
+# floating point number in the range [0, 1).
+#ignore_probe_probability=0.0
+#
+# Ignore authentication frames with the given probability
+#ignore_auth_probability=0.0
+#
+# Ignore association requests with the given probability
+#ignore_assoc_probability=0.0
+#
+# Ignore reassociation requests with the given probability
+#ignore_reassoc_probability=0.0
+#
+# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
+#corrupt_gtk_rekey_mic_probability=0.0
+
##### Multiple BSSID support ##################################################
#
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
@@ -1521,6 +1781,11 @@ 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
#
+# 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"
+# (search for "valid interface combinations").
+#
# Please note that hostapd uses some of the values configured for the first BSS
# as the defaults for the following BSSes. However, it is recommended that all
# BSSes include explicit configuration of all relevant configuration items.
diff --git a/contrib/wpa/hostapd/hostapd.eap_user b/contrib/wpa/hostapd/hostapd.eap_user
index 12a2c61..00edc95 100644
--- a/contrib/wpa/hostapd/hostapd.eap_user
+++ b/contrib/wpa/hostapd/hostapd.eap_user
@@ -48,6 +48,12 @@
# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
# hash.
+#
+# Arbitrary RADIUS attributes can be added into Access-Accept packets similarly
+# to the way radius_auth_req_attr is used for Access-Request packet in
+# hostapd.conf. For EAP server, this is configured separately for each user
+# entry with radius_accept_attr=<value> line(s) following the main user entry
+# line.
# Phase 1 users
"user" MD5 "password"
diff --git a/contrib/wpa/hostapd/hostapd.eap_user_sqlite b/contrib/wpa/hostapd/hostapd.eap_user_sqlite
index f688327..826db34 100644
--- a/contrib/wpa/hostapd/hostapd.eap_user_sqlite
+++ b/contrib/wpa/hostapd/hostapd.eap_user_sqlite
@@ -2,6 +2,7 @@ CREATE TABLE users(
identity TEXT PRIMARY KEY,
methods TEXT,
password TEXT,
+ remediation TEXT,
phase2 INTEGER
);
@@ -15,3 +16,11 @@ INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 use
INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
+
+CREATE TABLE authlog(
+ timestamp TEXT,
+ session TEXT,
+ nas_ip TEXT,
+ username TEXT,
+ note TEXT
+);
diff --git a/contrib/wpa/hostapd/hostapd_cli.c b/contrib/wpa/hostapd/hostapd_cli.c
index e8e1bb2..3f00cbb 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-2012, 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.
@@ -18,7 +18,7 @@
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
@@ -79,6 +79,7 @@ static const char *commands_help =
#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"
@@ -90,7 +91,12 @@ static const char *commands_help =
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
static int hostapd_cli_attached = 0;
-static const char *ctrl_iface_dir = "/var/run/hostapd";
+
+#ifndef CONFIG_CTRL_IFACE_DIR
+#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
+#endif /* CONFIG_CTRL_IFACE_DIR */
+static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
+
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
@@ -210,8 +216,21 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
+ return wpa_ctrl_command(ctrl, "STATUS");
+}
+
+
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
+ if (argc > 0) {
+ char buf[100];
+ os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+ }
return wpa_ctrl_command(ctrl, "MIB");
}
@@ -219,28 +238,19 @@ static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int hostapd_cli_exec(const char *program, const char *arg1,
const char *arg2)
{
- char *cmd;
+ char *arg;
size_t len;
int res;
- int ret = 0;
- len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
- cmd = os_malloc(len);
- if (cmd == NULL)
- return -1;
- res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
- if (res < 0 || (size_t) res >= len) {
- os_free(cmd);
+ len = os_strlen(arg1) + os_strlen(arg2) + 2;
+ arg = os_malloc(len);
+ if (arg == NULL)
return -1;
- }
- cmd[len - 1] = '\0';
-#ifndef _WIN32_WCE
- if (system(cmd) < 0)
- ret = -1;
-#endif /* _WIN32_WCE */
- os_free(cmd);
+ os_snprintf(arg, len, "%s %s", arg1, arg2);
+ res = os_exec(program, arg, 1);
+ os_free(arg);
- return ret;
+ return res;
}
@@ -264,12 +274,15 @@ static void hostapd_cli_action_process(char *msg, size_t len)
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char buf[64];
- if (argc != 1) {
- printf("Invalid 'sta' command - exactly one argument, STA "
+ if (argc < 1) {
+ printf("Invalid 'sta' command - at least one argument, STA "
"address, is required.\n");
return -1;
}
- snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+ if (argc > 1)
+ snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
+ else
+ snprintf(buf, sizeof(buf), "STA %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
@@ -380,7 +393,7 @@ static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
else
res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_CHECK_PIN command.\n");
return -1;
}
@@ -443,7 +456,7 @@ static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
return -1;
}
@@ -464,12 +477,35 @@ static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
}
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_NFC_TOKEN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
+
+
+static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid 'nfc_get_handover_sel' command - two arguments "
+ "are required.\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long NFC_GET_HANDOVER_SEL command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -494,6 +530,13 @@ static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
+}
+
+
static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -553,7 +596,7 @@ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
argv[0], argv[1]);
- if (res < 0 || res >= (int) sizeof(buf))
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
@@ -565,16 +608,43 @@ static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
char buf[300];
int res;
- if (argc < 2) {
- printf("Invalid 'ess_disassoc' command - two arguments (STA "
- "addr and URL) are needed\n");
+ if (argc < 3) {
+ printf("Invalid 'ess_disassoc' command - three arguments (STA "
+ "addr, disassoc timer, and URL) are needed\n");
return -1;
}
- res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
- argv[0], argv[1]);
- if (res < 0 || res >= (int) sizeof(buf))
+ res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
+ argv[0], argv[1], argv[2]);
+ if (os_snprintf_error(sizeof(buf), res))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[2000], *tmp;
+ int res, i, total;
+
+ if (argc < 1) {
+ printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
+
+ total = res;
+ for (i = 1; i < argc; i++) {
+ tmp = &buf[total];
+ res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
+ if (os_snprintf_error(sizeof(buf) - total, res))
+ return -1;
+ total += res;
+ }
return wpa_ctrl_command(ctrl, buf);
}
@@ -652,6 +722,90 @@ static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char buf[200];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'set_qos_map_set' command - "
+ "one argument (comma delimited QoS map set) "
+ "is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
+ if (os_snprintf_error(sizeof(buf), res))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char buf[50];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'send_qos_map_conf' command - "
+ "one argument (STA addr) is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
+ if (os_snprintf_error(sizeof(buf), res))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[300];
+ int res;
+
+ if (argc < 2) {
+ printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
+ "addr and URL) are needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(sizeof(buf), res))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[300];
+ int res;
+
+ if (argc < 3) {
+ printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
+ return -1;
+ }
+
+ if (argc > 3)
+ res = os_snprintf(buf, sizeof(buf),
+ "HS20_DEAUTH_REQ %s %s %s %s",
+ argv[0], argv[1], argv[2], argv[3]);
+ else
+ res = os_snprintf(buf, sizeof(buf),
+ "HS20_DEAUTH_REQ %s %s %s",
+ argv[0], argv[1], argv[2]);
+ if (os_snprintf_error(sizeof(buf), res))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
hostapd_cli_quit = 1;
@@ -706,8 +860,10 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
}
hostapd_cli_close_connection();
- free(ctrl_ifname);
- ctrl_ifname = strdup(argv[0]);
+ 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);
@@ -737,7 +893,7 @@ static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long SET command.\n");
return -1;
}
@@ -757,7 +913,7 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long GET command.\n");
return -1;
}
@@ -765,6 +921,94 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+ int i;
+ char *tmp;
+ int total;
+
+ if (argc < 2) {
+ printf("Invalid chan_switch command: needs at least two "
+ "arguments (count and freq)\n"
+ "usage: <cs_count> <freq> [sec_channel_offset=] "
+ "[center_freq1=] [center_freq2=] [bandwidth=] "
+ "[blocktx] [ht|vht]\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long CHAN_SWITCH command.\n");
+ return -1;
+ }
+
+ total = res;
+ for (i = 2; i < argc; i++) {
+ tmp = cmd + total;
+ res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
+ if (os_snprintf_error(sizeof(cmd) - total, res)) {
+ printf("Too long CHAN_SWITCH command.\n");
+ return -1;
+ }
+ total += res;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ENABLE");
+}
+
+
+static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "RELOAD");
+}
+
+
+static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DISABLE");
+}
+
+
+static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc < 2 || argc > 3) {
+ printf("Invalid vendor command\n"
+ "usage: <vendor id> <command id> [<hex formatted command argument>]\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
+ argc == 3 ? argv[2] : "");
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long VENDOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -774,6 +1018,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "ping", hostapd_cli_cmd_ping },
{ "mib", hostapd_cli_cmd_mib },
{ "relog", hostapd_cli_cmd_relog },
+ { "status", hostapd_cli_cmd_status },
{ "sta", hostapd_cli_cmd_sta },
{ "all_sta", hostapd_cli_cmd_all_sta },
{ "new_sta", hostapd_cli_cmd_new_sta },
@@ -791,12 +1036,15 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
+ { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
+ { "wps_get_status", hostapd_cli_cmd_wps_get_status },
#endif /* CONFIG_WPS */
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
+ { "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 },
@@ -805,6 +1053,16 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "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 },
{ NULL, NULL }
};
diff --git a/contrib/wpa/hostapd/main.c b/contrib/wpa/hostapd/main.c
index 56f0002..dd389a8 100644
--- a/contrib/wpa/hostapd/main.c
+++ b/contrib/wpa/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, 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,12 @@
#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <syslog.h>
+#include <grp.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/uuid.h"
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
@@ -24,17 +26,9 @@
#include "ap/ap_drv_ops.h"
#include "config_file.h"
#include "eap_register.h"
-#include "dump_state.h"
#include "ctrl_iface.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-extern struct wpa_driver_ops *wpa_drivers[];
-
-
struct hapd_global {
void **drv_priv;
size_t drv_count;
@@ -98,22 +92,24 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
if (hapd && hapd->conf && addr)
os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
hapd->conf->iface, MAC2STR(addr),
- module_str ? " " : "", module_str, txt);
+ module_str ? " " : "", module_str ? module_str : "",
+ txt);
else if (hapd && hapd->conf)
os_snprintf(format, maxlen, "%s:%s%s %s",
hapd->conf->iface, module_str ? " " : "",
- module_str, txt);
+ module_str ? module_str : "", txt);
else if (addr)
os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
MAC2STR(addr), module_str ? " " : "",
- module_str, txt);
+ module_str ? module_str : "", txt);
else
os_snprintf(format, maxlen, "%s%s%s",
- module_str, module_str ? ": " : "", txt);
+ module_str ? module_str : "",
+ module_str ? ": " : "", txt);
if ((conf_stdout & module) && level >= conf_stdout_level) {
wpa_debug_print_timestamp();
- printf("%s\n", format);
+ wpa_printf(MSG_INFO, "%s", format);
}
#ifndef CONFIG_NATIVE_WINDOWS
@@ -147,63 +143,8 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
/**
- * hostapd_init - Allocate and initialize per-interface data
- * @config_file: Path to the configuration file
- * Returns: Pointer to the allocated interface data or %NULL on failure
- *
- * This function is used to allocate main data structures for per-interface
- * data. The allocated data buffer will be freed by calling
- * hostapd_cleanup_iface().
+ * hostapd_driver_init - Preparate driver interface
*/
-static struct hostapd_iface * hostapd_init(const char *config_file)
-{
- struct hostapd_iface *hapd_iface = NULL;
- struct hostapd_config *conf = NULL;
- struct hostapd_data *hapd;
- size_t i;
-
- hapd_iface = os_zalloc(sizeof(*hapd_iface));
- if (hapd_iface == NULL)
- goto fail;
-
- hapd_iface->config_fname = os_strdup(config_file);
- if (hapd_iface->config_fname == NULL)
- goto fail;
-
- conf = hostapd_config_read(hapd_iface->config_fname);
- if (conf == NULL)
- goto fail;
- hapd_iface->conf = conf;
-
- hapd_iface->num_bss = conf->num_bss;
- hapd_iface->bss = os_calloc(conf->num_bss,
- sizeof(struct hostapd_data *));
- if (hapd_iface->bss == NULL)
- goto fail;
-
- for (i = 0; i < conf->num_bss; i++) {
- hapd = hapd_iface->bss[i] =
- hostapd_alloc_bss_data(hapd_iface, conf,
- &conf->bss[i]);
- if (hapd == NULL)
- goto fail;
- hapd->msg_ctx = hapd;
- }
-
- return hapd_iface;
-
-fail:
- if (conf)
- hostapd_config_free(conf);
- if (hapd_iface) {
- os_free(hapd_iface->config_fname);
- os_free(hapd_iface->bss);
- os_free(hapd_iface);
- }
- return NULL;
-}
-
-
static int hostapd_driver_init(struct hostapd_iface *iface)
{
struct wpa_init_params params;
@@ -243,9 +184,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
}
params.bssid = b;
params.ifname = hapd->conf->iface;
- params.ssid = hapd->conf->ssid.ssid;
- params.ssid_len = hapd->conf->ssid.ssid_len;
- params.test_socket = hapd->conf->test_socket;
+ params.driver_params = hapd->iconf->driver_params;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
@@ -271,14 +210,35 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
if (hapd->driver->get_capa &&
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
+ struct wowlan_triggers *triggs;
+
iface->drv_flags = capa.flags;
+ iface->smps_modes = capa.smps_modes;
iface->probe_resp_offloads = capa.probe_resp_offloads;
+ iface->extended_capa = capa.extended_capa;
+ iface->extended_capa_mask = capa.extended_capa_mask;
+ iface->extended_capa_len = capa.extended_capa_len;
+ iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
+
+ triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
+ if (triggs && hapd->driver->set_wowlan) {
+ if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
+ wpa_printf(MSG_ERROR, "set_wowlan failed");
+ }
+ os_free(triggs);
}
return 0;
}
+/**
+ * hostapd_interface_init - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a full interface (one
+ * or more BSSes sharing the same radio) and allocate memory for the BSS
+ * interfaces. No actiual driver operations are started.
+ */
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces,
const char *config_fname, int debug)
@@ -287,7 +247,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
int k;
wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
- iface = hostapd_init(config_fname);
+ iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
iface->interfaces = interfaces;
@@ -297,13 +257,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
iface->bss[0]->conf->logger_stdout_level--;
}
- if (iface->conf->bss[0].iface[0] != 0 ||
- hostapd_drv_none(iface->bss[0])) {
- if (hostapd_driver_init(iface) ||
- hostapd_setup_interface(iface)) {
- hostapd_interface_deinit_free(iface);
- return NULL;
- }
+ if (iface->conf->bss[0]->iface[0] == '\0' &&
+ !hostapd_drv_none(iface->bss[0])) {
+ wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ config_fname);
+ hostapd_interface_deinit_free(iface);
+ return NULL;
}
return iface;
@@ -346,10 +305,7 @@ static void handle_reload(int sig, void *signal_ctx)
static void handle_dump_state(int sig, void *signal_ctx)
{
-#ifdef HOSTAPD_DUMP_STATE
- struct hapd_interfaces *interfaces = signal_ctx;
- hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
-#endif /* HOSTAPD_DUMP_STATE */
+ /* Not used anymore - ignore signal */
}
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -452,7 +408,7 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
#endif /* EAP_SERVER_TNC */
if (daemonize && os_daemonize(pid_file)) {
- perror("daemon");
+ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
return -1;
}
@@ -468,7 +424,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-2012, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -480,7 +436,8 @@ static void usage(void)
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
- " [-g <global ctrl_iface>] <configuration file(s)>\n"
+ " [-g <global ctrl_iface>] [-G <group>] \\\n"
+ " <configuration file(s)>\n"
"\n"
"options:\n"
" -h show this usage\n"
@@ -488,11 +445,16 @@ static void usage(void)
" -B run daemon in the background\n"
" -e entropy file\n"
" -g global control interface path\n"
+ " -G group for control interfaces\n"
" -P PID file\n"
" -K include key data in debug messages\n"
#ifdef CONFIG_DEBUG_FILE
" -f log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ " -T = record to Linux tracing in addition to logging\n"
+ " (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
" -t include timestamps in some debug messages\n"
" -v show hostapd version\n");
@@ -503,8 +465,9 @@ 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)
- return hapd->iconf->bss->iface;
+ if (hapd && hapd->iconf && hapd->iconf->bss &&
+ hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
+ return hapd->iconf->bss[0]->iface;
return NULL;
}
@@ -519,6 +482,8 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
return -1;
pos = os_strrchr(interfaces->global_iface_path, '/');
if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "No '/' in the global control interface "
+ "file");
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = NULL;
return -1;
@@ -531,15 +496,57 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
}
+static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
+ const char *group)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+ struct group *grp;
+ grp = getgrnam(group);
+ if (grp == NULL) {
+ wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
+ return -1;
+ }
+ interfaces->ctrl_iface_group = grp->gr_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+ return 0;
+}
+
+
+#ifdef CONFIG_WPS
+static int gen_uuid(const char *txt_addr)
+{
+ u8 addr[ETH_ALEN];
+ u8 uuid[UUID_LEN];
+ char buf[100];
+
+ if (hwaddr_aton(txt_addr, addr) < 0)
+ return -1;
+
+ uuid_gen_mac_addr(addr, uuid);
+ if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0)
+ return -1;
+
+ printf("%s\n", buf);
+
+ return 0;
+}
+#endif /* CONFIG_WPS */
+
+
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
int ret = 1;
- size_t i;
+ size_t i, j;
int c, debug = 0, daemonize = 0;
char *pid_file = NULL;
const char *log_file = NULL;
const char *entropy_file = NULL;
+ char **bss_config = NULL, **tmp_bss;
+ size_t num_bss_configs = 0;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ int enable_trace_dbg = 0;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
if (os_program_init())
return -1;
@@ -556,7 +563,7 @@ int main(int argc, char *argv[])
interfaces.global_ctrl_sock = -1;
for (;;) {
- c = getopt(argc, argv, "Bde:f:hKP:tvg:");
+ c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
if (c < 0)
break;
switch (c) {
@@ -587,31 +594,65 @@ int main(int argc, char *argv[])
case 't':
wpa_debug_timestamp++;
break;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ case 'T':
+ enable_trace_dbg = 1;
+ break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 'v':
show_version();
exit(1);
break;
case 'g':
- hostapd_get_global_ctrl_iface(&interfaces, optarg);
+ if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
+ return -1;
break;
-
+ case 'G':
+ if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
+ return -1;
+ break;
+ case 'b':
+ tmp_bss = os_realloc_array(bss_config,
+ num_bss_configs + 1,
+ sizeof(char *));
+ if (tmp_bss == NULL)
+ goto out;
+ bss_config = tmp_bss;
+ bss_config[num_bss_configs++] = optarg;
+ break;
+#ifdef CONFIG_WPS
+ case 'u':
+ return gen_uuid(optarg);
+#endif /* CONFIG_WPS */
default:
usage();
break;
}
}
- if (optind == argc && interfaces.global_iface_path == NULL)
+ if (optind == argc && interfaces.global_iface_path == NULL &&
+ num_bss_configs == 0)
usage();
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
if (log_file)
wpa_debug_open_file(log_file);
+ else
+ wpa_debug_setup_stdout();
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ if (enable_trace_dbg) {
+ int tret = wpa_debug_open_linux_tracing();
+ if (tret) {
+ wpa_printf(MSG_ERROR, "Failed to enable trace logging");
+ return -1;
+ }
+ }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
interfaces.count = argc - optind;
- if (interfaces.count) {
- interfaces.iface = os_calloc(interfaces.count,
+ if (interfaces.count || num_bss_configs) {
+ interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
sizeof(struct hostapd_iface *));
if (interfaces.iface == NULL) {
wpa_printf(MSG_ERROR, "malloc failed");
@@ -619,30 +660,93 @@ int main(int argc, char *argv[])
}
}
- if (hostapd_global_init(&interfaces, entropy_file))
+ if (hostapd_global_init(&interfaces, entropy_file)) {
+ wpa_printf(MSG_ERROR, "Failed to initilize global context");
return -1;
+ }
- /* Initialize interfaces */
+ /* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
interfaces.iface[i] = hostapd_interface_init(&interfaces,
argv[optind + i],
debug);
- if (!interfaces.iface[i])
+ if (!interfaces.iface[i]) {
+ wpa_printf(MSG_ERROR, "Failed to initialize interface");
+ goto out;
+ }
+ }
+
+ /* Allocate and parse configuration for per-BSS files */
+ for (i = 0; i < num_bss_configs; i++) {
+ struct hostapd_iface *iface;
+ char *fname;
+
+ wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
+ fname = os_strchr(bss_config[i], ':');
+ if (fname == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Invalid BSS config identifier '%s'",
+ bss_config[i]);
+ goto out;
+ }
+ *fname++ = '\0';
+ iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
+ fname, debug);
+ if (iface == NULL)
+ goto out;
+ for (j = 0; j < interfaces.count; j++) {
+ if (interfaces.iface[j] == iface)
+ break;
+ }
+ if (j == interfaces.count) {
+ struct hostapd_iface **tmp;
+ tmp = os_realloc_array(interfaces.iface,
+ interfaces.count + 1,
+ sizeof(struct hostapd_iface *));
+ if (tmp == NULL) {
+ hostapd_interface_deinit_free(iface);
+ goto out;
+ }
+ interfaces.iface = tmp;
+ interfaces.iface[interfaces.count++] = iface;
+ }
+ }
+
+ /*
+ * Enable configured interfaces. Depending on channel configuration,
+ * this may complete full initialization before returning or use a
+ * callback mechanism to complete setup in case of operations like HT
+ * co-ex scans, ACS, or DFS are needed to determine channel parameters.
+ * In such case, the interface will be enabled from eloop context within
+ * hostapd_global_run().
+ */
+ interfaces.terminate_on_error = interfaces.count;
+ for (i = 0; i < interfaces.count; i++) {
+ if (hostapd_driver_init(interfaces.iface[i]) ||
+ hostapd_setup_interface(interfaces.iface[i]))
goto out;
}
hostapd_global_ctrl_iface_init(&interfaces);
- if (hostapd_global_run(&interfaces, daemonize, pid_file))
+ if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+ wpa_printf(MSG_ERROR, "Failed to start eloop");
goto out;
+ }
ret = 0;
out:
hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
- for (i = 0; i < interfaces.count; i++)
+ for (i = 0; i < interfaces.count; i++) {
+ if (!interfaces.iface[i])
+ continue;
+ interfaces.iface[i]->driver_ap_teardown =
+ !!(interfaces.iface[i]->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
hostapd_interface_deinit_free(interfaces.iface[i]);
+ }
os_free(interfaces.iface);
hostapd_global_deinit(pid_file);
@@ -650,6 +754,9 @@ int main(int argc, char *argv[])
if (log_file)
wpa_debug_close_file();
+ wpa_debug_close_linux_tracing();
+
+ os_free(bss_config);
os_program_deinit();
diff --git a/contrib/wpa/hostapd/wps-ap-nfc.py b/contrib/wpa/hostapd/wps-ap-nfc.py
new file mode 100755
index 0000000..2fc3012
--- /dev/null
+++ b/contrib/wpa/hostapd/wps-ap-nfc.py
@@ -0,0 +1,342 @@
+#!/usr/bin/python
+#
+# Example nfcpy to hostapd wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import argparse
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+
+import wpaspy
+
+wpas_ctrl = '/var/run/hostapd'
+continue_loop = True
+summary_file = None
+success_file = None
+
+def summary(txt):
+ print txt
+ if summary_file:
+ with open(summary_file, 'a') as f:
+ f.write(txt + "\n")
+
+def success_report(txt):
+ summary(txt)
+ if success_file:
+ with open(success_file, 'a') as f:
+ f.write(txt + "\n")
+
+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, error:
+ print "Could not find hostapd: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No hostapd control interface found"
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception, e:
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return False
+ if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
+ return False
+ return True
+
+
+def wpas_get_config_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ ret = wpas.request("WPS_NFC_TOKEN NDEF")
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
+
+
+def wpas_get_handover_sel():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ ret = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR")
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.ho_server_processing = False
+ self.success = False
+
+ # override to avoid parser error in request/response.pretty() in nfcpy
+ # due to new WSC handover format
+ def _process_request(self, request):
+ summary("received handover request {}".format(request.type))
+ response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
+ if not request.type == 'urn:nfc:wkt:Hr':
+ summary("not a handover request")
+ else:
+ try:
+ request = nfc.ndef.HandoverRequestMessage(request)
+ except nfc.ndef.DecodeError as e:
+ summary("error decoding 'Hr' message: {}".format(e))
+ else:
+ response = self.process_request(request)
+ summary("send handover response {}".format(response.type))
+ return response
+
+ 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")
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ for carrier in request.carriers:
+ 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")
+ if "OK" in wpas_report_handover(carrier.record, data):
+ success_report("Handover reported successfully")
+ else:
+ summary("Handover report rejected")
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+
+ print "Handover select:"
+ try:
+ print sel.pretty()
+ except Exception, e:
+ print e
+ print str(sel).encode("hex")
+
+ summary("Sending handover select")
+ self.success = True
+ return sel
+
+
+def wps_tag_read(tag):
+ success = False
+ if len(tag.ndef.message):
+ for record in tag.ndef.message:
+ 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)
+ break
+ else:
+ summary("Empty tag")
+
+ if success:
+ success_report("Tag read succeeded")
+
+ return success
+
+
+def rdwr_connected_write(tag):
+ summary("Tag found - writing - " + str(tag))
+ global write_data
+ tag.ndef.message = str(write_data)
+ success_report("Tag write succeeded")
+ print "Done - remove tag"
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global write_wait_remove
+ while write_wait_remove and tag.is_present:
+ time.sleep(0.1)
+
+def wps_write_config_tag(clf, wait_remove=True):
+ summary("Write WPS config token")
+ global write_data, write_wait_remove
+ write_wait_remove = wait_remove
+ write_data = wpas_get_config_token()
+ if write_data == None:
+ summary("Could not get WPS config token from hostapd")
+ return
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def wps_write_password_tag(clf, wait_remove=True):
+ summary("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:
+ summary("Could not get WPS password token from hostapd")
+ return
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ summary("Tag connected: " + str(tag))
+
+ if tag.ndef:
+ print "NDEF tag: " + tag.type
+ try:
+ print tag.ndef.message.pretty()
+ except Exception, e:
+ print e
+ success = wps_tag_read(tag)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ summary("Not an NDEF tag - remove tag")
+ return True
+
+ return not no_wait
+
+
+def llcp_startup(clf, llc):
+ print "Start LLCP server"
+ global srv
+ srv = HandoverServer(llc)
+ return llc
+
+def llcp_connected(llc):
+ print "P2P LLCP connected"
+ global wait_connection
+ wait_connection = False
+ global srv
+ srv.start()
+ return True
+
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--summary',
+ help='summary file for writing status updates')
+ parser.add_argument('--success',
+ help='success file for writing success update')
+ parser.add_argument('command', choices=['write-config',
+ 'write-password'],
+ nargs='?')
+ args = parser.parse_args()
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ if args.summary:
+ global summary_file
+ summary_file = args.summary
+
+ if args.success:
+ global success_file
+ success_file = args.success
+
+ logging.basicConfig(level=args.loglevel)
+
+ try:
+ if not clf.open("usb"):
+ print "Could not open connection with an NFC device"
+ raise SystemExit
+
+ if args.command == "write-config":
+ wps_write_config_tag(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ if args.command == "write-password":
+ wps_write_password_tag(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ 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"
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/wpa/hs20/client/Android.mk b/contrib/wpa/hs20/client/Android.mk
new file mode 100644
index 0000000..b23ac17
--- /dev/null
+++ b/contrib/wpa/hs20/client/Android.mk
@@ -0,0 +1,81 @@
+LOCAL_PATH := $(call my-dir)
+
+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
+
+# We try to keep this compiling against older platform versions.
+# The new icu location (external/icu) exports its own headers, but
+# the older versions in external/icu4c don't, and we need to add those
+# headers to the include path by hand.
+ifeq ($(wildcard external/icu),)
+INCLUDES += external/icu4c/common
+else
+# The LOCAL_EXPORT_C_INCLUDE_DIRS from ICU did not seem to fully resolve the
+# build (e.g., "mm -B" failed to build, but following that with "mm" allowed
+# the build to complete). For now, add the include directory manually here for
+# Android 5.0.
+ver = $(filter 5.0%,$(PLATFORM_VERSION))
+ifneq (,$(strip $(ver)))
+INCLUDES += external/icu/icu4c/source/common
+endif
+endif
+
+
+L_CFLAGS += -DCONFIG_CTRL_IFACE
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
+
+OBJS = spp_client.c
+OBJS += oma_dm_client.c
+OBJS += osu_client.c
+OBJS += est.c
+OBJS += ../../src/common/wpa_ctrl.c
+OBJS += ../../src/common/wpa_helpers.c
+OBJS += ../../src/utils/xml-utils.c
+#OBJS += ../../src/utils/browser-android.c
+OBJS += ../../src/utils/browser-wpadebug.c
+OBJS += ../../src/utils/wpabuf.c
+OBJS += ../../src/utils/eloop.c
+OBJS += ../../src/wps/httpread.c
+OBJS += ../../src/wps/http_server.c
+OBJS += ../../src/utils/xml_libxml2.c
+OBJS += ../../src/utils/http_curl.c
+OBJS += ../../src/utils/base64.c
+OBJS += ../../src/utils/os_unix.c
+L_CFLAGS += -DCONFIG_DEBUG_FILE
+OBJS += ../../src/utils/wpa_debug.c
+OBJS += ../../src/utils/common.c
+OBJS += ../../src/crypto/crypto_internal.c
+OBJS += ../../src/crypto/md5-internal.c
+OBJS += ../../src/crypto/sha1-internal.c
+OBJS += ../../src/crypto/sha256-internal.c
+
+L_CFLAGS += -DEAP_TLS_OPENSSL
+
+L_CFLAGS += -Wno-unused-parameter
+
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := hs20-osu-client
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES += libcrypto libssl
+#LOCAL_SHARED_LIBRARIES += libxml2
+LOCAL_STATIC_LIBRARIES += libxml2
+LOCAL_SHARED_LIBRARIES += libicuuc
+LOCAL_SHARED_LIBRARIES += libcurl
+
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
diff --git a/contrib/wpa/hs20/client/Makefile b/contrib/wpa/hs20/client/Makefile
new file mode 100644
index 0000000..ca67b54
--- /dev/null
+++ b/contrib/wpa/hs20/client/Makefile
@@ -0,0 +1,94 @@
+all: hs20-osu-client
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CFLAGS += -I../../src/utils
+CFLAGS += -I../../src/common
+CFLAGS += -I../../src
+
+ifndef CONFIG_NO_BROWSER
+ifndef CONFIG_BROWSER_SYSTEM
+GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
+GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
+CFLAGS += $(GTKCFLAGS)
+LIBS += $(GTKLIBS)
+endif
+endif
+
+OBJS=spp_client.o
+OBJS += oma_dm_client.o
+OBJS += osu_client.o
+OBJS += est.o
+OBJS += ../../src/utils/xml-utils.o
+CFLAGS += -DCONFIG_CTRL_IFACE
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+OBJS += ../../src/common/wpa_ctrl.o ../../src/common/wpa_helpers.o
+ifdef CONFIG_NO_BROWSER
+CFLAGS += -DCONFIG_NO_BROWSER
+else
+ifdef CONFIG_BROWSER_SYSTEM
+OBJS += ../../src/utils/eloop.o
+OBJS += ../../src/utils/wpabuf.o
+OBJS += ../../src/wps/httpread.o
+OBJS += ../../src/wps/http_server.o
+OBJS += ../../src/utils/browser-system.o
+else
+OBJS += ../../src/utils/browser.o
+endif
+endif
+OBJS += ../../src/utils/xml_libxml2.o
+OBJS += ../../src/utils/http_curl.o
+OBJS += ../../src/utils/base64.o
+OBJS += ../../src/utils/os_unix.o
+CFLAGS += -DCONFIG_DEBUG_FILE
+OBJS += ../../src/utils/wpa_debug.o
+OBJS += ../../src/utils/common.o
+OBJS += ../../src/crypto/crypto_internal.o
+OBJS += ../../src/crypto/md5-internal.o
+OBJS += ../../src/crypto/sha1-internal.o
+OBJS += ../../src/crypto/sha256-internal.o
+
+CFLAGS += $(shell xml2-config --cflags)
+LIBS += $(shell xml2-config --libs)
+LIBS += -lcurl
+
+CFLAGS += -DEAP_TLS_OPENSSL
+LIBS += -lssl -lcrypto
+
+hs20-osu-client: $(OBJS)
+ $(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
+ @$(E) " LD " $@
+
+%.o: %.c
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+
+clean:
+ rm -f core *~ *.o *.d hs20-osu-client
+ rm -f ../../src/utils/*.o
+ rm -f ../../src/utils/*.d
+ rm -f ../../src/common/*.o
+ rm -f ../../src/common/*.d
+ rm -f ../../src/crypto/*.o
+ rm -f ../../src/crypto/*.d
+ rm -f ../../src/wps/*.o
+ rm -f ../../src/wps/*.d
+
+-include $(OBJS:%.o=%.d)
diff --git a/contrib/wpa/hs20/client/devdetail.xml b/contrib/wpa/hs20/client/devdetail.xml
new file mode 100644
index 0000000..6d0389e
--- /dev/null
+++ b/contrib/wpa/hs20/client/devdetail.xml
@@ -0,0 +1,47 @@
+<DevDetail xmlns="urn:oma:mo:oma-dm-devdetail:1.0">
+ <Ext>
+ <org.wi-fi>
+ <Wi-Fi>
+ <EAPMethodList>
+ <EAPMethod1>
+ <EAPType>13</EAPType>
+ </EAPMethod1>
+ <EAPMethod2>
+ <EAPType>21</EAPType>
+ <InnerMethod>MS-CHAP-V2</InnerMethod>
+ </EAPMethod2>
+ <EAPMethod3>
+ <EAPType>18</EAPType>
+ </EAPMethod3>
+ <EAPMethod4>
+ <EAPType>23</EAPType>
+ </EAPMethod4>
+ <EAPMethod5>
+ <EAPType>50</EAPType>
+ </EAPMethod5>
+ </EAPMethodList>
+ <ManufacturingCertificate>false</ManufacturingCertificate>
+ <Wi-FiMACAddress>020102030405</Wi-FiMACAddress>
+ <IMSI>310026000000000</IMSI>
+ <IMEI_MEID>imei:490123456789012</IMEI_MEID>
+ <ClientTriggerRedirectURI>http://localhost:12345/</ClientTriggerRedirectURI>
+ <Ops>
+ <launchBrowserToURI></launchBrowserToURI>
+ <negotiateClientCertTLS></negotiateClientCertTLS>
+ <getCertificate></getCertificate>
+ </Ops>
+ </Wi-Fi>
+ </org.wi-fi>
+ </Ext>
+ <URI>
+ <MaxDepth>0</MaxDepth>
+ <MaxTotLen>0</MaxTotLen>
+ <MaxSegLen>0</MaxSegLen>
+ </URI>
+ <DevType>MobilePhone</DevType>
+ <OEM>Manufacturer</OEM>
+ <FwV>1.0</FwV>
+ <SwV>1.0</SwV>
+ <HwV>1.0</HwV>
+ <LrgObj>false</LrgObj>
+</DevDetail>
diff --git a/contrib/wpa/hs20/client/devinfo.xml b/contrib/wpa/hs20/client/devinfo.xml
new file mode 100644
index 0000000..d48a520
--- /dev/null
+++ b/contrib/wpa/hs20/client/devinfo.xml
@@ -0,0 +1,7 @@
+<DevInfo xmlns="urn:oma:mo:oma-dm-devinfo:1.0">
+ <DevId>urn:Example:HS20-station:123456</DevId>
+ <Man>Manufacturer</Man>
+ <Mod>HS20-station</Mod>
+ <DmV>1.2</DmV>
+ <Lang>en</Lang>
+</DevInfo>
diff --git a/contrib/wpa/hs20/client/est.c b/contrib/wpa/hs20/client/est.c
new file mode 100644
index 0000000..ec05bc4
--- /dev/null
+++ b/contrib/wpa/hs20/client/est.c
@@ -0,0 +1,715 @@
+/*
+ * Hotspot 2.0 OSU client - EST client
+ * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs7.h>
+#include <openssl/rsa.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "common.h"
+#include "utils/base64.h"
+#include "utils/xml-utils.h"
+#include "utils/http-utils.h"
+#include "osu_client.h"
+
+
+static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
+ size_t len, char *pem_file, char *der_file)
+{
+ PKCS7 *p7 = NULL;
+ const unsigned char *p = pkcs7;
+ STACK_OF(X509) *certs;
+ int i, num, ret = -1;
+ BIO *out = NULL;
+
+ p7 = d2i_PKCS7(NULL, &p, len);
+ if (p7 == NULL) {
+ 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;
+ }
+
+ switch (OBJ_obj2nid(p7->type)) {
+ case NID_pkcs7_signed:
+ certs = p7->d.sign->cert;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ certs = p7->d.signed_and_enveloped->cert;
+ break;
+ default:
+ certs = NULL;
+ break;
+ }
+
+ if (!certs || ((num = sk_X509_num(certs)) == 0)) {
+ wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
+ write_result(ctx, "No certificates found in PKCS#7 object");
+ goto fail;
+ }
+
+ if (der_file) {
+ FILE *f = fopen(der_file, "wb");
+ if (f == NULL)
+ goto fail;
+ i2d_X509_fp(f, sk_X509_value(certs, 0));
+ fclose(f);
+ }
+
+ if (pem_file) {
+ out = BIO_new(BIO_s_file());
+ if (out == NULL ||
+ BIO_write_filename(out, pem_file) <= 0)
+ goto fail;
+
+ for (i = 0; i < num; i++) {
+ X509 *cert = sk_X509_value(certs, i);
+ X509_print(out, cert);
+ PEM_write_bio_X509(out, cert);
+ BIO_puts(out, "\n");
+ }
+ }
+
+ ret = 0;
+
+fail:
+ PKCS7_free(p7);
+ if (out)
+ BIO_free_all(out);
+
+ return ret;
+}
+
+
+int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
+{
+ char *buf, *resp;
+ size_t buflen;
+ unsigned char *pkcs7;
+ size_t pkcs7_len, resp_len;
+ int res;
+
+ buflen = os_strlen(url) + 100;
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+
+ os_snprintf(buf, buflen, "%s/cacerts", url);
+ wpa_printf(MSG_INFO, "Download EST cacerts from %s", buf);
+ write_summary(ctx, "Download EST cacerts from %s", buf);
+ ctx->no_osu_cert_validation = 1;
+ http_ocsp_set(ctx->http, 1);
+ res = http_download_file(ctx->http, buf, "Cert/est-cacerts.txt",
+ ctx->ca_fname);
+ http_ocsp_set(ctx->http,
+ (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
+ ctx->no_osu_cert_validation = 0;
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "Failed to download EST cacerts from %s",
+ buf);
+ write_result(ctx, "Failed to download EST cacerts from %s",
+ buf);
+ os_free(buf);
+ return -1;
+ }
+ os_free(buf);
+
+ resp = os_readfile("Cert/est-cacerts.txt", &resp_len);
+ if (resp == NULL) {
+ wpa_printf(MSG_INFO, "Could not read Cert/est-cacerts.txt");
+ write_result(ctx, "Could not read EST cacerts");
+ return -1;
+ }
+
+ pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
+ if (pkcs7 && pkcs7_len < resp_len / 2) {
+ wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
+ (unsigned int) pkcs7_len, (unsigned int) resp_len);
+ os_free(pkcs7);
+ pkcs7 = NULL;
+ }
+ if (pkcs7 == NULL) {
+ wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
+ pkcs7 = os_malloc(resp_len);
+ if (pkcs7) {
+ os_memcpy(pkcs7, resp, resp_len);
+ pkcs7_len = resp_len;
+ }
+ }
+ os_free(resp);
+
+ if (pkcs7 == NULL) {
+ wpa_printf(MSG_INFO, "Could not fetch PKCS7 cacerts");
+ write_result(ctx, "Could not fetch EST PKCS#7 cacerts");
+ return -1;
+ }
+
+ res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est-cacerts.pem",
+ NULL);
+ os_free(pkcs7);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "Could not parse CA certs from PKCS#7 cacerts response");
+ write_result(ctx, "Could not parse CA certs from EST PKCS#7 cacerts response");
+ return -1;
+ }
+ unlink("Cert/est-cacerts.txt");
+
+ return 0;
+}
+
+
+/*
+ * CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID
+ *
+ * AttrOrOID ::= CHOICE {
+ * oid OBJECT IDENTIFIER,
+ * attribute Attribute }
+ *
+ * Attribute ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * values SET SIZE(1..MAX) OF OBJECT IDENTIFIER }
+ */
+
+typedef struct {
+ ASN1_OBJECT *type;
+ STACK_OF(ASN1_OBJECT) *values;
+} Attribute;
+
+typedef struct {
+ int type;
+ union {
+ ASN1_OBJECT *oid;
+ Attribute *attribute;
+ } d;
+} AttrOrOID;
+
+typedef struct {
+ int type;
+ STACK_OF(AttrOrOID) *attrs;
+} CsrAttrs;
+
+ASN1_SEQUENCE(Attribute) = {
+ ASN1_SIMPLE(Attribute, type, ASN1_OBJECT),
+ ASN1_SET_OF(Attribute, values, ASN1_OBJECT)
+} ASN1_SEQUENCE_END(Attribute);
+
+ASN1_CHOICE(AttrOrOID) = {
+ ASN1_SIMPLE(AttrOrOID, d.oid, ASN1_OBJECT),
+ ASN1_SIMPLE(AttrOrOID, d.attribute, Attribute)
+} ASN1_CHOICE_END(AttrOrOID);
+
+ASN1_CHOICE(CsrAttrs) = {
+ ASN1_SEQUENCE_OF(CsrAttrs, attrs, AttrOrOID)
+} ASN1_CHOICE_END(CsrAttrs);
+
+IMPLEMENT_ASN1_FUNCTIONS(CsrAttrs);
+
+
+static void add_csrattrs_oid(struct hs20_osu_client *ctx, ASN1_OBJECT *oid,
+ STACK_OF(X509_EXTENSION) *exts)
+{
+ char txt[100];
+ int res;
+
+ if (!oid)
+ return;
+
+ res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
+ if (res < 0 || res >= (int) sizeof(txt))
+ return;
+
+ if (os_strcmp(txt, "1.2.840.113549.1.9.7") == 0) {
+ wpa_printf(MSG_INFO, "TODO: csrattr challengePassword");
+ } else if (os_strcmp(txt, "1.2.840.113549.1.1.11") == 0) {
+ wpa_printf(MSG_INFO, "csrattr sha256WithRSAEncryption");
+ } else {
+ wpa_printf(MSG_INFO, "Ignore unsupported csrattr oid %s", txt);
+ }
+}
+
+
+static void add_csrattrs_ext_req(struct hs20_osu_client *ctx,
+ STACK_OF(ASN1_OBJECT) *values,
+ STACK_OF(X509_EXTENSION) *exts)
+{
+ char txt[100];
+ int i, num, res;
+
+ num = sk_ASN1_OBJECT_num(values);
+ for (i = 0; i < num; i++) {
+ ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(values, i);
+
+ res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
+ if (res < 0 || res >= (int) sizeof(txt))
+ continue;
+
+ if (os_strcmp(txt, "1.3.6.1.1.1.1.22") == 0) {
+ wpa_printf(MSG_INFO, "TODO: extReq macAddress");
+ } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.3") == 0) {
+ wpa_printf(MSG_INFO, "TODO: extReq imei");
+ } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.4") == 0) {
+ wpa_printf(MSG_INFO, "TODO: extReq meid");
+ } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.5") == 0) {
+ wpa_printf(MSG_INFO, "TODO: extReq DevId");
+ } else {
+ wpa_printf(MSG_INFO, "Ignore unsupported cstattr extensionsRequest %s",
+ txt);
+ }
+ }
+}
+
+
+static void add_csrattrs_attr(struct hs20_osu_client *ctx, Attribute *attr,
+ STACK_OF(X509_EXTENSION) *exts)
+{
+ char txt[100], txt2[100];
+ int i, num, res;
+
+ if (!attr || !attr->type || !attr->values)
+ return;
+
+ res = OBJ_obj2txt(txt, sizeof(txt), attr->type, 1);
+ if (res < 0 || res >= (int) sizeof(txt))
+ return;
+
+ if (os_strcmp(txt, "1.2.840.113549.1.9.14") == 0) {
+ add_csrattrs_ext_req(ctx, attr->values, exts);
+ return;
+ }
+
+ num = sk_ASN1_OBJECT_num(attr->values);
+ for (i = 0; i < num; i++) {
+ ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(attr->values, i);
+
+ res = OBJ_obj2txt(txt2, sizeof(txt2), oid, 1);
+ if (res < 0 || res >= (int) sizeof(txt2))
+ continue;
+
+ wpa_printf(MSG_INFO, "Ignore unsupported cstattr::attr %s oid %s",
+ txt, txt2);
+ }
+}
+
+
+static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
+ STACK_OF(X509_EXTENSION) *exts)
+{
+ int i, num;
+
+ if (!csrattrs || ! csrattrs->attrs)
+ return;
+
+ num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
+ for (i = 0; i < num; i++) {
+ AttrOrOID *ao = SKM_sk_value(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;
+ }
+ }
+}
+
+
+static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
+ char *csr_pem, char *est_req, char *old_cert,
+ CsrAttrs *csrattrs)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_PKEY *pkey = NULL;
+ RSA *rsa;
+ X509_REQ *req = NULL;
+ int ret = -1;
+ unsigned int val;
+ X509_NAME *subj = NULL;
+ char name[100];
+ STACK_OF(X509_EXTENSION) *exts = NULL;
+ X509_EXTENSION *ex;
+ BIO *out;
+
+ wpa_printf(MSG_INFO, "Generate RSA private key");
+ write_summary(ctx, "Generate RSA private key");
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+ if (!pctx)
+ return -1;
+
+ if (EVP_PKEY_keygen_init(pctx) <= 0)
+ goto fail;
+
+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0)
+ goto fail;
+
+ if (EVP_PKEY_keygen(pctx, &pkey) <= 0)
+ goto fail;
+ EVP_PKEY_CTX_free(pctx);
+ pctx = NULL;
+
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ if (rsa == NULL)
+ goto fail;
+
+ if (key_pem) {
+ FILE *f = fopen(key_pem, "wb");
+ if (f == NULL)
+ goto fail;
+ if (!PEM_write_RSAPrivateKey(f, rsa, NULL, NULL, 0, NULL,
+ NULL)) {
+ wpa_printf(MSG_INFO, "Could not write private key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ fclose(f);
+ goto fail;
+ }
+ fclose(f);
+ }
+
+ wpa_printf(MSG_INFO, "Generate CSR");
+ write_summary(ctx, "Generate CSR");
+ req = X509_REQ_new();
+ if (req == NULL)
+ goto fail;
+
+ if (old_cert) {
+ FILE *f;
+ X509 *cert;
+ int res;
+
+ f = fopen(old_cert, "r");
+ if (f == NULL)
+ goto fail;
+ cert = PEM_read_X509(f, NULL, NULL, NULL);
+ fclose(f);
+
+ if (cert == NULL)
+ goto fail;
+ res = X509_REQ_set_subject_name(req,
+ X509_get_subject_name(cert));
+ X509_free(cert);
+ if (!res)
+ goto fail;
+ } else {
+ os_get_random((u8 *) &val, sizeof(val));
+ os_snprintf(name, sizeof(name), "cert-user-%u", val);
+ subj = X509_NAME_new();
+ if (subj == NULL ||
+ !X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC,
+ (unsigned char *) name,
+ -1, -1, 0) ||
+ !X509_REQ_set_subject_name(req, subj))
+ goto fail;
+ X509_NAME_free(subj);
+ subj = NULL;
+ }
+
+ if (!X509_REQ_set_pubkey(req, pkey))
+ goto fail;
+
+ exts = sk_X509_EXTENSION_new_null();
+ if (!exts)
+ goto fail;
+
+ ex = X509V3_EXT_conf_nid(NULL, 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");
+ 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");
+ if (ex == NULL ||
+ !sk_X509_EXTENSION_push(exts, ex))
+ goto fail;
+
+ add_csrattrs(ctx, csrattrs, exts);
+
+ if (!X509_REQ_add_extensions(req, exts))
+ goto fail;
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ exts = NULL;
+
+ if (!X509_REQ_sign(req, pkey, EVP_sha256()))
+ goto fail;
+
+ out = BIO_new(BIO_s_mem());
+ if (out) {
+ char *txt;
+ size_t rlen;
+
+ X509_REQ_print(out, req);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ int res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_MSGDUMP, "OpenSSL: Certificate request:\n%s",
+ txt);
+ }
+ os_free(txt);
+ }
+ BIO_free(out);
+ }
+
+ if (csr_pem) {
+ FILE *f = fopen(csr_pem, "w");
+ if (f == NULL)
+ goto fail;
+ X509_REQ_print_fp(f, req);
+ if (!PEM_write_X509_REQ(f, req)) {
+ fclose(f);
+ goto fail;
+ }
+ fclose(f);
+ }
+
+ if (est_req) {
+ BIO *mem = BIO_new(BIO_s_mem());
+ BUF_MEM *ptr;
+ char *pos, *end, *buf_end;
+ FILE *f;
+
+ if (mem == NULL)
+ goto fail;
+ if (!PEM_write_bio_X509_REQ(mem, req)) {
+ BIO_free(mem);
+ goto fail;
+ }
+
+ BIO_get_mem_ptr(mem, &ptr);
+ pos = ptr->data;
+ buf_end = pos + ptr->length;
+
+ /* Remove START/END lines */
+ while (pos < buf_end && *pos != '\n')
+ pos++;
+ if (pos == buf_end) {
+ BIO_free(mem);
+ goto fail;
+ }
+ pos++;
+
+ end = pos;
+ while (end < buf_end && *end != '-')
+ end++;
+
+ f = fopen(est_req, "w");
+ if (f == NULL) {
+ BIO_free(mem);
+ goto fail;
+ }
+ fwrite(pos, end - pos, 1, f);
+ fclose(f);
+
+ BIO_free(mem);
+ }
+
+ ret = 0;
+fail:
+ if (exts)
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ if (subj)
+ X509_NAME_free(subj);
+ if (req)
+ X509_REQ_free(req);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (pctx)
+ EVP_PKEY_CTX_free(pctx);
+ return ret;
+}
+
+
+int est_build_csr(struct hs20_osu_client *ctx, const char *url)
+{
+ char *buf;
+ size_t buflen;
+ int res;
+ char old_cert_buf[200];
+ char *old_cert = NULL;
+ CsrAttrs *csrattrs = NULL;
+
+ buflen = os_strlen(url) + 100;
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+
+ os_snprintf(buf, buflen, "%s/csrattrs", url);
+ wpa_printf(MSG_INFO, "Download csrattrs from %s", buf);
+ write_summary(ctx, "Download EST csrattrs from %s", buf);
+ ctx->no_osu_cert_validation = 1;
+ http_ocsp_set(ctx->http, 1);
+ res = http_download_file(ctx->http, buf, "Cert/est-csrattrs.txt",
+ ctx->ca_fname);
+ http_ocsp_set(ctx->http,
+ (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
+ ctx->no_osu_cert_validation = 0;
+ os_free(buf);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "Failed to download EST csrattrs - assume no extra attributes are needed");
+ } else {
+ size_t resp_len;
+ char *resp;
+ unsigned char *attrs;
+ const unsigned char *pos;
+ size_t attrs_len;
+
+ resp = os_readfile("Cert/est-csrattrs.txt", &resp_len);
+ if (resp == NULL) {
+ wpa_printf(MSG_INFO, "Could not read csrattrs");
+ return -1;
+ }
+
+ attrs = base64_decode((unsigned char *) resp, resp_len,
+ &attrs_len);
+ os_free(resp);
+
+ if (attrs == NULL) {
+ wpa_printf(MSG_INFO, "Could not base64 decode csrattrs");
+ return -1;
+ }
+ unlink("Cert/est-csrattrs.txt");
+
+ pos = attrs;
+ csrattrs = d2i_CsrAttrs(NULL, &pos, attrs_len);
+ os_free(attrs);
+ if (csrattrs == NULL) {
+ wpa_printf(MSG_INFO, "Failed to parse csrattrs ASN.1");
+ /* Continue assuming no additional requirements */
+ }
+ }
+
+ if (ctx->client_cert_present) {
+ os_snprintf(old_cert_buf, sizeof(old_cert_buf),
+ "SP/%s/client-cert.pem", ctx->fqdn);
+ old_cert = old_cert_buf;
+ }
+
+ res = generate_csr(ctx, "Cert/privkey-plain.pem", "Cert/est-req.pem",
+ "Cert/est-req.b64", old_cert, csrattrs);
+ if (csrattrs)
+ CsrAttrs_free(csrattrs);
+
+ return res;
+}
+
+
+int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
+ const char *user, const char *pw)
+{
+ 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;
+ int res;
+
+ req = os_readfile("Cert/est-req.b64", &len);
+ if (req == NULL) {
+ wpa_printf(MSG_INFO, "Could not read Cert/req.b64");
+ return -1;
+ }
+ req2 = os_realloc(req, len + 1);
+ if (req2 == NULL) {
+ os_free(req);
+ return -1;
+ }
+ req2[len] = '\0';
+ req = req2;
+ wpa_printf(MSG_DEBUG, "EST simpleenroll request: %s", req);
+
+ buflen = os_strlen(url) + 100;
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ os_free(req);
+ return -1;
+ }
+
+ if (ctx->client_cert_present) {
+ os_snprintf(buf, buflen, "%s/simplereenroll", url);
+ os_snprintf(client_cert_buf, sizeof(client_cert_buf),
+ "SP/%s/client-cert.pem", ctx->fqdn);
+ client_cert = client_cert_buf;
+ os_snprintf(client_key_buf, sizeof(client_key_buf),
+ "SP/%s/client-key.pem", ctx->fqdn);
+ client_key = client_key_buf;
+ } else
+ os_snprintf(buf, buflen, "%s/simpleenroll", url);
+ wpa_printf(MSG_INFO, "EST simpleenroll URL: %s", buf);
+ write_summary(ctx, "EST simpleenroll URL: %s", buf);
+ ctx->no_osu_cert_validation = 1;
+ http_ocsp_set(ctx->http, 1);
+ resp = http_post(ctx->http, buf, req, "application/pkcs10",
+ "Content-Transfer-Encoding: base64",
+ ctx->ca_fname, user, pw, client_cert, client_key,
+ &resp_len);
+ http_ocsp_set(ctx->http,
+ (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
+ ctx->no_osu_cert_validation = 0;
+ os_free(buf);
+ if (resp == NULL) {
+ wpa_printf(MSG_INFO, "EST certificate enrollment failed");
+ write_result(ctx, "EST certificate enrollment failed");
+ 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) {
+ wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
+ pkcs7 = os_malloc(resp_len);
+ if (pkcs7) {
+ os_memcpy(pkcs7, resp, resp_len);
+ pkcs7_len = resp_len;
+ }
+ }
+ os_free(resp);
+
+ if (pkcs7 == NULL) {
+ wpa_printf(MSG_INFO, "Failed to parse simpleenroll base64 response");
+ write_result(ctx, "Failed to parse EST simpleenroll base64 response");
+ return -1;
+ }
+
+ res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est_cert.pem",
+ "Cert/est_cert.der");
+ os_free(pkcs7);
+
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "EST: Failed to extract certificate from PKCS7 file");
+ write_result(ctx, "EST: Failed to extract certificate from EST PKCS7 file");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "EST simple%senroll completed successfully",
+ ctx->client_cert_present ? "re" : "");
+ write_summary(ctx, "EST simple%senroll completed successfully",
+ ctx->client_cert_present ? "re" : "");
+
+ return 0;
+}
diff --git a/contrib/wpa/hs20/client/oma_dm_client.c b/contrib/wpa/hs20/client/oma_dm_client.c
new file mode 100644
index 0000000..5854b72
--- /dev/null
+++ b/contrib/wpa/hs20/client/oma_dm_client.c
@@ -0,0 +1,1392 @@
+/*
+ * Hotspot 2.0 - OMA DM client
+ * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_helpers.h"
+#include "xml-utils.h"
+#include "http-utils.h"
+#include "utils/browser.h"
+#include "osu_client.h"
+
+
+#define DM_SERVER_INITIATED_MGMT 1200
+#define DM_CLIENT_INITIATED_MGMT 1201
+#define DM_GENERIC_ALERT 1226
+
+/* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */
+#define DM_RESP_OK 200
+#define DM_RESP_AUTH_ACCEPTED 212
+#define DM_RESP_CHUNKED_ITEM_ACCEPTED 213
+#define DM_RESP_NOT_EXECUTED 215
+#define DM_RESP_ATOMIC_ROLL_BACK_OK 216
+#define DM_RESP_NOT_MODIFIED 304
+#define DM_RESP_BAD_REQUEST 400
+#define DM_RESP_UNAUTHORIZED 401
+#define DM_RESP_FORBIDDEN 403
+#define DM_RESP_NOT_FOUND 404
+#define DM_RESP_COMMAND_NOT_ALLOWED 405
+#define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406
+#define DM_RESP_MISSING_CREDENTIALS 407
+#define DM_RESP_CONFLICT 409
+#define DM_RESP_GONE 410
+#define DM_RESP_INCOMPLETE_COMMAND 412
+#define DM_RESP_REQ_ENTITY_TOO_LARGE 413
+#define DM_RESP_URI_TOO_LONG 414
+#define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415
+#define DM_RESP_REQ_TOO_BIG 416
+#define DM_RESP_ALREADY_EXISTS 418
+#define DM_RESP_DEVICE_FULL 420
+#define DM_RESP_SIZE_MISMATCH 424
+#define DM_RESP_PERMISSION_DENIED 425
+#define DM_RESP_COMMAND_FAILED 500
+#define DM_RESP_COMMAND_NOT_IMPLEMENTED 501
+#define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516
+
+#define DM_HS20_SUBSCRIPTION_CREATION \
+ "org.wi-fi.hotspot2dot0.SubscriptionCreation"
+#define DM_HS20_SUBSCRIPTION_PROVISIONING \
+ "org.wi-fi.hotspot2dot0.SubscriptionProvisioning"
+#define DM_HS20_SUBSCRIPTION_REMEDIATION \
+ "org.wi-fi.hotspot2dot0.SubscriptionRemediation"
+#define DM_HS20_POLICY_UPDATE \
+ "org.wi-fi.hotspot2dot0.PolicyUpdate"
+
+#define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription"
+#define DM_URI_LAUNCH_BROWSER \
+ "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI"
+
+
+static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
+ const char *locuri, const char *data);
+
+
+static const char * int2str(int val)
+{
+ static char buf[20];
+ snprintf(buf, sizeof(buf), "%d", val);
+ return buf;
+}
+
+
+static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx,
+ xml_node_t *node)
+{
+ xml_node_t *locuri;
+ char *uri, *ret = NULL;
+
+ locuri = get_node(ctx->xml, node, "Item/Target/LocURI");
+ if (locuri == NULL)
+ return NULL;
+
+ uri = xml_node_get_text(ctx->xml, locuri);
+ if (uri)
+ ret = os_strdup(uri);
+ xml_node_get_text_free(ctx->xml, uri);
+ return ret;
+}
+
+
+static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent,
+ const char *element, const char *uri)
+{
+ xml_node_t *node;
+
+ node = xml_node_create(ctx->xml, parent, NULL, element);
+ if (node == NULL)
+ return;
+ xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri);
+}
+
+
+static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
+ const char *url, int msgid)
+{
+ xml_node_t *syncml, *synchdr;
+ xml_namespace_t *ns;
+
+ syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
+ "SyncML");
+
+ synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr");
+ xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2");
+ xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2");
+ xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1");
+ xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid));
+
+ oma_dm_add_locuri(ctx, synchdr, "Target", url);
+ oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid);
+
+ return syncml;
+}
+
+
+static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent,
+ int cmdid)
+{
+ xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid));
+}
+
+
+static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent,
+ int cmdid, int data)
+{
+ xml_node_t *node;
+
+ node = xml_node_create(ctx->xml, parent, NULL, "Alert");
+ if (node == NULL)
+ return NULL;
+ oma_dm_add_cmdid(ctx, node, cmdid);
+ xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
+
+ return node;
+}
+
+
+static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent,
+ int msgref, int cmdref, int cmdid,
+ const char *cmd, int data, const char *targetref)
+{
+ xml_node_t *node;
+
+ node = xml_node_create(ctx->xml, parent, NULL, "Status");
+ if (node == NULL)
+ return NULL;
+ oma_dm_add_cmdid(ctx, node, cmdid);
+ xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
+ if (cmdref)
+ xml_node_create_text(ctx->xml, node, NULL, "CmdRef",
+ int2str(cmdref));
+ xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd);
+ xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
+ if (targetref) {
+ xml_node_create_text(ctx->xml, node, NULL, "TargetRef",
+ targetref);
+ }
+
+ return node;
+}
+
+
+static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent,
+ int msgref, int cmdref, int cmdid,
+ const char *locuri, const char *data)
+{
+ xml_node_t *node;
+
+ node = xml_node_create(ctx->xml, parent, NULL, "Results");
+ if (node == NULL)
+ return NULL;
+
+ oma_dm_add_cmdid(ctx, node, cmdid);
+ xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
+ xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref));
+ add_item(ctx, node, locuri, data);
+
+ return node;
+}
+
+
+static char * mo_str(struct hs20_osu_client *ctx, const char *urn,
+ const char *fname)
+{
+ xml_node_t *fnode, *tnds;
+ char *str;
+
+ fnode = node_from_file(ctx->xml, fname);
+ if (!fnode)
+ return NULL;
+ tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2");
+ xml_node_free(ctx->xml, fnode);
+ if (!tnds)
+ return NULL;
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (str == NULL)
+ return NULL;
+ wpa_printf(MSG_INFO, "MgmtTree: %s", str);
+
+ return str;
+}
+
+
+static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
+ const char *locuri, const char *data)
+{
+ xml_node_t *item, *node;
+
+ item = xml_node_create(ctx->xml, parent, NULL, "Item");
+ oma_dm_add_locuri(ctx, item, "Source", locuri);
+ node = xml_node_create(ctx->xml, item, NULL, "Meta");
+ xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
+ "Chr");
+ xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type",
+ "text/plain");
+ xml_node_create_text(ctx->xml, item, NULL, "Data", data);
+}
+
+
+static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent,
+ int cmdid)
+{
+ xml_node_t *info, *child, *replace;
+ const char *name;
+ char locuri[200], *txt;
+
+ info = node_from_file(ctx->xml, "devinfo.xml");
+ if (info == NULL) {
+ wpa_printf(MSG_INFO, "Could not read devinfo.xml");
+ return;
+ }
+
+ replace = xml_node_create(ctx->xml, parent, NULL, "Replace");
+ if (replace == NULL) {
+ xml_node_free(ctx->xml, info);
+ return;
+ }
+ oma_dm_add_cmdid(ctx, replace, cmdid);
+
+ xml_node_for_each_child(ctx->xml, child, info) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name);
+ txt = xml_node_get_text(ctx->xml, child);
+ if (txt) {
+ add_item(ctx, replace, locuri, txt);
+ xml_node_get_text_free(ctx->xml, txt);
+ }
+ }
+
+ xml_node_free(ctx->xml, info);
+}
+
+
+static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx,
+ xml_node_t *syncbody,
+ int cmdid, const char *oper,
+ const char *data)
+{
+ xml_node_t *node, *item;
+ char buf[200];
+
+ node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT);
+
+ item = xml_node_create(ctx->xml, node, NULL, "Item");
+ oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS);
+ node = xml_node_create(ctx->xml, item, NULL, "Meta");
+ snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper);
+ xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf);
+ xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
+ "xml");
+ xml_node_create_text(ctx->xml, item, NULL, "Data", data);
+}
+
+
+static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx,
+ const char *url, int msgid, const char *oper)
+{
+ xml_node_t *syncml, *syncbody;
+ char *str;
+ int cmdid = 0;
+
+ syncml = oma_dm_build_hdr(ctx, url, msgid);
+ if (syncml == NULL)
+ return NULL;
+
+ syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
+ if (syncbody == NULL) {
+ xml_node_free(ctx->xml, syncml);
+ return NULL;
+ }
+
+ cmdid++;
+ add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT);
+
+ str = mo_str(ctx, NULL, "devdetail.xml");
+ if (str == NULL) {
+ xml_node_free(ctx->xml, syncml);
+ return NULL;
+ }
+ cmdid++;
+ oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str);
+ os_free(str);
+
+ cmdid++;
+ add_replace_devinfo(ctx, syncbody, cmdid);
+
+ xml_node_create(ctx->xml, syncbody, NULL, "Final");
+
+ return syncml;
+}
+
+
+static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx,
+ const char *url, int msgid)
+{
+ xml_node_t *syncml;
+
+ syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION);
+ if (syncml)
+ debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml);
+
+ return syncml;
+}
+
+
+static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx,
+ const char *url, int msgid)
+{
+ xml_node_t *syncml;
+
+ syncml = build_oma_dm_1(ctx, url, msgid,
+ DM_HS20_SUBSCRIPTION_PROVISIONING);
+ if (syncml)
+ debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml);
+
+ return syncml;
+}
+
+
+static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx,
+ const char *url, int msgid)
+{
+ xml_node_t *syncml;
+
+ syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE);
+ if (syncml)
+ debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml);
+
+ return syncml;
+}
+
+
+static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx,
+ const char *url, int msgid)
+{
+ xml_node_t *syncml;
+
+ syncml = build_oma_dm_1(ctx, url, msgid,
+ DM_HS20_SUBSCRIPTION_REMEDIATION);
+ if (syncml)
+ debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml);
+
+ return syncml;
+}
+
+
+static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
+{
+ xml_node_t *node;
+ char *data;
+ int res;
+
+ node = get_node(ctx->xml, exec, "Item/Data");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No Data node found");
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ data = xml_node_get_text(ctx->xml, node);
+ if (data == NULL) {
+ wpa_printf(MSG_INFO, "Invalid data");
+ return DM_RESP_BAD_REQUEST;
+ }
+ wpa_printf(MSG_INFO, "Data: %s", data);
+ wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
+ write_summary(ctx, "Launch browser to URI '%s'", data);
+ res = hs20_web_browser(data);
+ xml_node_get_text_free(ctx->xml, data);
+ if (res > 0) {
+ wpa_printf(MSG_INFO, "User response in browser completed successfully");
+ write_summary(ctx, "User response in browser completed successfully");
+ return DM_RESP_OK;
+ } else {
+ wpa_printf(MSG_INFO, "Failed to receive user response");
+ write_summary(ctx, "Failed to receive user response");
+ return DM_RESP_COMMAND_FAILED;
+ }
+}
+
+
+static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec)
+{
+ xml_node_t *node, *getcert;
+ char *data;
+ const char *name;
+ int res;
+
+ wpa_printf(MSG_INFO, "Client certificate enrollment");
+ write_summary(ctx, "Client certificate enrollment");
+
+ node = get_node(ctx->xml, exec, "Item/Data");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No Data node found");
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ data = xml_node_get_text(ctx->xml, node);
+ if (data == NULL) {
+ wpa_printf(MSG_INFO, "Invalid data");
+ return DM_RESP_BAD_REQUEST;
+ }
+ wpa_printf(MSG_INFO, "Data: %s", data);
+ getcert = xml_node_from_buf(ctx->xml, data);
+ xml_node_get_text_free(ctx->xml, data);
+
+ if (getcert == NULL) {
+ wpa_printf(MSG_INFO, "Could not parse Item/Data node contents");
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ debug_dump_node(ctx, "OMA-DM getCertificate", getcert);
+
+ name = xml_node_get_localname(ctx->xml, getcert);
+ if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) {
+ wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'",
+ name);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ res = osu_get_certificate(ctx, getcert);
+
+ xml_node_free(ctx->xml, getcert);
+
+ return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED;
+}
+
+
+static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec)
+{
+ char *locuri;
+ int ret;
+
+ locuri = oma_dm_get_target_locuri(ctx, exec);
+ if (locuri == NULL) {
+ wpa_printf(MSG_INFO, "No Target LocURI node found");
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
+
+ if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
+ "launchBrowserToURI") == 0) {
+ ret = oma_dm_exec_browser(ctx, exec);
+ } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
+ "getCertificate") == 0) {
+ ret = oma_dm_exec_get_cert(ctx, exec);
+ } else {
+ wpa_printf(MSG_INFO, "Unsupported exec Target LocURI");
+ ret = DM_RESP_NOT_FOUND;
+ }
+ os_free(locuri);
+
+ return ret;
+}
+
+
+static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri,
+ xml_node_t *add, xml_node_t *pps,
+ const char *pps_fname)
+{
+ const char *pos;
+ size_t fqdn_len;
+ xml_node_t *node, *tnds, *unode, *pps_node;
+ char *data, *uri, *upos, *end;
+ int use_tnds = 0;
+ size_t uri_len;
+
+ wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri);
+
+ if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
+ wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi");
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos = locuri + 8;
+
+ if (ctx->fqdn == NULL)
+ return DM_RESP_COMMAND_FAILED;
+ fqdn_len = os_strlen(ctx->fqdn);
+ if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
+ pos[fqdn_len] != '/') {
+ wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s",
+ ctx->fqdn);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos += fqdn_len + 1;
+
+ if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
+ wpa_printf(MSG_INFO,
+ "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription",
+ ctx->fqdn);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos += 24;
+
+ wpa_printf(MSG_INFO, "Add command for PPS node %s", pos);
+
+ pps_node = get_node(ctx->xml, pps, pos);
+ if (pps_node) {
+ wpa_printf(MSG_INFO, "Specified PPS node exists already");
+ return DM_RESP_ALREADY_EXISTS;
+ }
+
+ uri = os_strdup(pos);
+ if (uri == NULL)
+ return DM_RESP_COMMAND_FAILED;
+ while (!pps_node) {
+ upos = os_strrchr(uri, '/');
+ if (!upos)
+ break;
+ upos[0] = '\0';
+ pps_node = get_node(ctx->xml, pps, uri);
+ wpa_printf(MSG_INFO, "Node %s %s", uri,
+ pps_node ? "exists" : "does not exist");
+ }
+
+ wpa_printf(MSG_INFO, "Parent URI: %s", uri);
+
+ if (!pps_node) {
+ /* Add at root of PPS MO */
+ pps_node = pps;
+ }
+
+ uri_len = os_strlen(uri);
+ os_strlcpy(uri, pos + uri_len, os_strlen(pos));
+ upos = uri;
+ while (*upos == '/')
+ upos++;
+ wpa_printf(MSG_INFO, "Nodes to add: %s", upos);
+
+ for (;;) {
+ end = os_strchr(upos, '/');
+ if (!end)
+ break;
+ *end = '\0';
+ wpa_printf(MSG_INFO, "Adding interim node %s", upos);
+ pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos);
+ if (pps_node == NULL) {
+ os_free(uri);
+ return DM_RESP_COMMAND_FAILED;
+ }
+ upos = end + 1;
+ }
+
+ wpa_printf(MSG_INFO, "Adding node %s", upos);
+
+ node = get_node(ctx->xml, add, "Item/Meta/Type");
+ if (node) {
+ char *type;
+ type = xml_node_get_text(ctx->xml, node);
+ if (type == NULL) {
+ wpa_printf(MSG_ERROR, "Could not find type text");
+ os_free(uri);
+ return DM_RESP_BAD_REQUEST;
+ }
+ use_tnds = node &&
+ os_strstr(type, "application/vnd.syncml.dmtnds+xml");
+ }
+
+ node = get_node(ctx->xml, add, "Item/Data");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No Add/Item/Data found");
+ os_free(uri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ data = xml_node_get_text(ctx->xml, node);
+ if (data == NULL) {
+ wpa_printf(MSG_INFO, "Could not get Add/Item/Data text");
+ os_free(uri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data);
+
+ if (use_tnds) {
+ tnds = xml_node_from_buf(ctx->xml, data);
+ xml_node_get_text_free(ctx->xml, data);
+ if (tnds == NULL) {
+ wpa_printf(MSG_INFO,
+ "Could not parse Add/Item/Data text");
+ os_free(uri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ unode = tnds_to_mo(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (unode == NULL) {
+ wpa_printf(MSG_INFO, "Could not parse TNDS text");
+ os_free(uri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ debug_dump_node(ctx, "Parsed TNDS", unode);
+
+ xml_node_add_child(ctx->xml, pps_node, unode);
+ } else {
+ /* TODO: What to do here? */
+ os_free(uri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ os_free(uri);
+
+ if (update_pps_file(ctx, pps_fname, pps) < 0)
+ return DM_RESP_COMMAND_FAILED;
+
+ ctx->pps_updated = 1;
+
+ return DM_RESP_OK;
+}
+
+
+static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add,
+ xml_node_t *pps, const char *pps_fname)
+{
+ xml_node_t *node;
+ char *locuri;
+ char fname[300];
+ int ret;
+
+ node = get_node(ctx->xml, add, "Item/Target/LocURI");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No Target LocURI node found");
+ return DM_RESP_BAD_REQUEST;
+ }
+ locuri = xml_node_get_text(ctx->xml, node);
+ if (locuri == NULL) {
+ wpa_printf(MSG_ERROR, "No LocURI node text found");
+ return DM_RESP_BAD_REQUEST;
+ }
+ wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
+ if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
+ wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
+ xml_node_get_text_free(ctx->xml, locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+
+ node = get_node(ctx->xml, add, "Item/Data");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No Data node found");
+ xml_node_get_text_free(ctx->xml, locuri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ if (pps_fname && os_file_exists(pps_fname)) {
+ ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname);
+ if (ret != DM_RESP_OK) {
+ xml_node_get_text_free(ctx->xml, locuri);
+ return ret;
+ }
+ ret = 0;
+ os_strlcpy(fname, pps_fname, sizeof(fname));
+ } else
+ ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname));
+ xml_node_get_text_free(ctx->xml, locuri);
+ if (ret < 0)
+ return ret == -2 ? DM_RESP_ALREADY_EXISTS :
+ DM_RESP_COMMAND_FAILED;
+
+ if (ctx->no_reconnect == 2) {
+ os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s",
+ fname);
+ ctx->pps_cred_set = 1;
+ return DM_RESP_OK;
+ }
+
+ wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
+ cmd_set_pps(ctx, fname);
+
+ if (ctx->no_reconnect)
+ return DM_RESP_OK;
+
+ wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
+ if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
+ wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
+
+ return DM_RESP_OK;
+}
+
+
+static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace,
+ xml_node_t *pps, const char *pps_fname)
+{
+ char *locuri, *pos;
+ size_t fqdn_len;
+ xml_node_t *node, *tnds, *unode, *pps_node, *parent;
+ char *data;
+ int use_tnds = 0;
+
+ locuri = oma_dm_get_target_locuri(ctx, replace);
+ if (locuri == NULL)
+ return DM_RESP_BAD_REQUEST;
+
+ wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri);
+ if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
+ wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi");
+ os_free(locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos = locuri + 8;
+
+ if (ctx->fqdn == NULL) {
+ os_free(locuri);
+ return DM_RESP_COMMAND_FAILED;
+ }
+ fqdn_len = os_strlen(ctx->fqdn);
+ if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
+ pos[fqdn_len] != '/') {
+ wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s",
+ ctx->fqdn);
+ os_free(locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos += fqdn_len + 1;
+
+ if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
+ wpa_printf(MSG_INFO,
+ "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription",
+ ctx->fqdn);
+ os_free(locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos += 24;
+
+ wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos);
+
+ pps_node = get_node(ctx->xml, pps, pos);
+ if (pps_node == NULL) {
+ wpa_printf(MSG_INFO, "Specified PPS node not found");
+ os_free(locuri);
+ return DM_RESP_NOT_FOUND;
+ }
+
+ node = get_node(ctx->xml, replace, "Item/Meta/Type");
+ if (node) {
+ char *type;
+ type = xml_node_get_text(ctx->xml, node);
+ if (type == NULL) {
+ wpa_printf(MSG_INFO, "Could not find type text");
+ os_free(locuri);
+ return DM_RESP_BAD_REQUEST;
+ }
+ use_tnds = node &&
+ os_strstr(type, "application/vnd.syncml.dmtnds+xml");
+ }
+
+ node = get_node(ctx->xml, replace, "Item/Data");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No Replace/Item/Data found");
+ os_free(locuri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ data = xml_node_get_text(ctx->xml, node);
+ if (data == NULL) {
+ wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text");
+ os_free(locuri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data);
+
+ if (use_tnds) {
+ tnds = xml_node_from_buf(ctx->xml, data);
+ xml_node_get_text_free(ctx->xml, data);
+ if (tnds == NULL) {
+ wpa_printf(MSG_INFO,
+ "Could not parse Replace/Item/Data text");
+ os_free(locuri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ unode = tnds_to_mo(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (unode == NULL) {
+ wpa_printf(MSG_INFO, "Could not parse TNDS text");
+ os_free(locuri);
+ return DM_RESP_BAD_REQUEST;
+ }
+
+ debug_dump_node(ctx, "Parsed TNDS", unode);
+
+ parent = xml_node_get_parent(ctx->xml, pps_node);
+ xml_node_detach(ctx->xml, pps_node);
+ xml_node_add_child(ctx->xml, parent, unode);
+ } else {
+ xml_node_set_text(ctx->xml, pps_node, data);
+ xml_node_get_text_free(ctx->xml, data);
+ }
+
+ os_free(locuri);
+
+ if (update_pps_file(ctx, pps_fname, pps) < 0)
+ return DM_RESP_COMMAND_FAILED;
+
+ ctx->pps_updated = 1;
+
+ return DM_RESP_OK;
+}
+
+
+static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get,
+ xml_node_t *pps, const char *pps_fname, char **value)
+{
+ char *locuri, *pos;
+ size_t fqdn_len;
+ xml_node_t *pps_node;
+ const char *name;
+
+ *value = NULL;
+
+ locuri = oma_dm_get_target_locuri(ctx, get);
+ if (locuri == NULL)
+ return DM_RESP_BAD_REQUEST;
+
+ wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri);
+ if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
+ wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi");
+ os_free(locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos = locuri + 8;
+
+ if (ctx->fqdn == NULL)
+ return DM_RESP_COMMAND_FAILED;
+ fqdn_len = os_strlen(ctx->fqdn);
+ if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
+ pos[fqdn_len] != '/') {
+ wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s",
+ ctx->fqdn);
+ os_free(locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos += fqdn_len + 1;
+
+ if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
+ wpa_printf(MSG_INFO,
+ "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription",
+ ctx->fqdn);
+ os_free(locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+ pos += 24;
+
+ wpa_printf(MSG_INFO, "Get command for PPS node %s", pos);
+
+ pps_node = get_node(ctx->xml, pps, pos);
+ if (pps_node == NULL) {
+ wpa_printf(MSG_INFO, "Specified PPS node not found");
+ os_free(locuri);
+ return DM_RESP_NOT_FOUND;
+ }
+
+ name = xml_node_get_localname(ctx->xml, pps_node);
+ wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name);
+ if (os_strcasecmp(name, "Password") == 0) {
+ wpa_printf(MSG_INFO, "Do not allow Get for Password node");
+ os_free(locuri);
+ return DM_RESP_PERMISSION_DENIED;
+ }
+
+ /*
+ * TODO: No support for DMTNDS, so if interior node, reply with a
+ * list of children node names in Results element. The child list type is
+ * defined in [DMTND].
+ */
+
+ *value = xml_node_get_text(ctx->xml, pps_node);
+ if (*value == NULL)
+ return DM_RESP_COMMAND_FAILED;
+
+ return DM_RESP_OK;
+}
+
+
+static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node)
+{
+ xml_node_t *cnode;
+ char *str;
+ int ret;
+
+ cnode = get_node(ctx->xml, node, "CmdID");
+ if (cnode == NULL)
+ return 0;
+
+ str = xml_node_get_text(ctx->xml, cnode);
+ if (str == NULL)
+ return 0;
+ ret = atoi(str);
+ xml_node_get_text_free(ctx->xml, str);
+ return ret;
+}
+
+
+static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
+ const char *url, xml_node_t *syncml,
+ const char *ext_hdr,
+ const char *username, const char *password,
+ const char *client_cert,
+ const char *client_key)
+{
+ xml_node_t *resp;
+ char *str, *res;
+ char *resp_uri = NULL;
+
+ str = xml_node_to_str(ctx->xml, syncml);
+ xml_node_free(ctx->xml, syncml);
+ if (str == NULL)
+ return NULL;
+
+ wpa_printf(MSG_INFO, "Send OMA DM Package");
+ write_summary(ctx, "Send OMA DM Package");
+ os_free(ctx->server_url);
+ ctx->server_url = os_strdup(url);
+ res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
+ ext_hdr, ctx->ca_fname, username, password,
+ client_cert, client_key, NULL);
+ os_free(str);
+ os_free(resp_uri);
+ resp_uri = NULL;
+
+ if (res == NULL) {
+ const char *err = http_get_err(ctx->http);
+ if (err) {
+ wpa_printf(MSG_INFO, "HTTP error: %s", err);
+ write_result(ctx, "HTTP error: %s", err);
+ } else {
+ write_summary(ctx, "Failed to send OMA DM Package");
+ }
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "Server response: %s", res);
+
+ wpa_printf(MSG_INFO, "Process OMA DM Package");
+ write_summary(ctx, "Process received OMA DM Package");
+ resp = xml_node_from_buf(ctx->xml, res);
+ os_free(res);
+ if (resp == NULL) {
+ wpa_printf(MSG_INFO, "Failed to parse OMA DM response");
+ return NULL;
+ }
+
+ debug_dump_node(ctx, "OMA DM Package", resp);
+
+ return resp;
+}
+
+
+static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url,
+ xml_node_t *resp, int msgid,
+ char **ret_resp_uri,
+ xml_node_t *pps, const char *pps_fname)
+{
+ xml_node_t *syncml, *syncbody, *hdr, *body, *child;
+ const char *name;
+ char *resp_uri = NULL;
+ int server_msgid = 0;
+ int cmdid = 0;
+ int server_cmdid;
+ int resp_needed = 0;
+ char *tmp;
+ int final = 0;
+ char *locuri;
+
+ *ret_resp_uri = NULL;
+
+ name = xml_node_get_localname(ctx->xml, resp);
+ if (name == NULL || os_strcasecmp(name, "SyncML") != 0) {
+ wpa_printf(MSG_INFO, "SyncML node not found");
+ return NULL;
+ }
+
+ hdr = get_node(ctx->xml, resp, "SyncHdr");
+ body = get_node(ctx->xml, resp, "SyncBody");
+ if (hdr == NULL || body == NULL) {
+ wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody");
+ return NULL;
+ }
+
+ xml_node_for_each_child(ctx->xml, child, hdr) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ wpa_printf(MSG_INFO, "SyncHdr %s", name);
+ if (os_strcasecmp(name, "RespURI") == 0) {
+ tmp = xml_node_get_text(ctx->xml, child);
+ if (tmp)
+ resp_uri = os_strdup(tmp);
+ xml_node_get_text_free(ctx->xml, tmp);
+ } else if (os_strcasecmp(name, "MsgID") == 0) {
+ tmp = xml_node_get_text(ctx->xml, child);
+ if (tmp)
+ server_msgid = atoi(tmp);
+ xml_node_get_text_free(ctx->xml, tmp);
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid);
+ if (resp_uri)
+ wpa_printf(MSG_INFO, "RespURI: %s", resp_uri);
+
+ syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid);
+ if (syncml == NULL) {
+ os_free(resp_uri);
+ return NULL;
+ }
+
+ syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
+ cmdid++;
+ add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr",
+ DM_RESP_AUTH_ACCEPTED, NULL);
+
+ xml_node_for_each_child(ctx->xml, child, body) {
+ xml_node_for_each_check(ctx->xml, child);
+ server_cmdid = oma_dm_get_cmdid(ctx, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s",
+ server_cmdid, name);
+ if (os_strcasecmp(name, "Exec") == 0) {
+ int res = oma_dm_exec(ctx, child);
+ cmdid++;
+ locuri = oma_dm_get_target_locuri(ctx, child);
+ if (locuri == NULL)
+ res = DM_RESP_BAD_REQUEST;
+ add_status(ctx, syncbody, server_msgid, server_cmdid,
+ cmdid, name, res, locuri);
+ os_free(locuri);
+ resp_needed = 1;
+ } else if (os_strcasecmp(name, "Add") == 0) {
+ int res = oma_dm_add(ctx, child, pps, pps_fname);
+ cmdid++;
+ locuri = oma_dm_get_target_locuri(ctx, child);
+ if (locuri == NULL)
+ res = DM_RESP_BAD_REQUEST;
+ add_status(ctx, syncbody, server_msgid, server_cmdid,
+ cmdid, name, res, locuri);
+ os_free(locuri);
+ resp_needed = 1;
+ } else if (os_strcasecmp(name, "Replace") == 0) {
+ int res;
+ res = oma_dm_replace(ctx, child, pps, pps_fname);
+ cmdid++;
+ locuri = oma_dm_get_target_locuri(ctx, child);
+ if (locuri == NULL)
+ res = DM_RESP_BAD_REQUEST;
+ add_status(ctx, syncbody, server_msgid, server_cmdid,
+ cmdid, name, res, locuri);
+ os_free(locuri);
+ resp_needed = 1;
+ } else if (os_strcasecmp(name, "Status") == 0) {
+ /* TODO: Verify success */
+ } else if (os_strcasecmp(name, "Get") == 0) {
+ int res;
+ char *value;
+ res = oma_dm_get(ctx, child, pps, pps_fname, &value);
+ cmdid++;
+ locuri = oma_dm_get_target_locuri(ctx, child);
+ if (locuri == NULL)
+ res = DM_RESP_BAD_REQUEST;
+ add_status(ctx, syncbody, server_msgid, server_cmdid,
+ cmdid, name, res, locuri);
+ if (res == DM_RESP_OK && value) {
+ cmdid++;
+ add_results(ctx, syncbody, server_msgid,
+ server_cmdid, cmdid, locuri, value);
+ }
+ os_free(locuri);
+ xml_node_get_text_free(ctx->xml, value);
+ resp_needed = 1;
+#if 0 /* TODO: MUST support */
+ } else if (os_strcasecmp(name, "Delete") == 0) {
+#endif
+#if 0 /* TODO: MUST support */
+ } else if (os_strcasecmp(name, "Sequence") == 0) {
+#endif
+ } else if (os_strcasecmp(name, "Final") == 0) {
+ final = 1;
+ break;
+ } else {
+ locuri = oma_dm_get_target_locuri(ctx, child);
+ add_status(ctx, syncbody, server_msgid, server_cmdid,
+ cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED,
+ locuri);
+ os_free(locuri);
+ resp_needed = 1;
+ }
+ }
+
+ if (!final) {
+ wpa_printf(MSG_INFO, "Final node not found");
+ xml_node_free(ctx->xml, syncml);
+ os_free(resp_uri);
+ return NULL;
+ }
+
+ if (!resp_needed) {
+ wpa_printf(MSG_INFO, "Exchange completed - no response needed");
+ xml_node_free(ctx->xml, syncml);
+ os_free(resp_uri);
+ return NULL;
+ }
+
+ xml_node_create(ctx->xml, syncbody, NULL, "Final");
+
+ debug_dump_node(ctx, "OMA-DM Package 3", syncml);
+
+ *ret_resp_uri = resp_uri;
+ return syncml;
+}
+
+
+int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url)
+{
+ xml_node_t *syncml, *resp;
+ char *resp_uri = NULL;
+ int msgid = 0;
+
+ if (url == NULL) {
+ wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested");
+ write_summary(ctx, "OMA-DM credential provisioning");
+
+ msgid++;
+ syncml = build_oma_dm_1_sub_reg(ctx, url, msgid);
+ if (syncml == NULL)
+ return -1;
+
+ while (syncml) {
+ resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
+ syncml, NULL, NULL, NULL, NULL, NULL);
+ if (resp == NULL)
+ return -1;
+
+ msgid++;
+ syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
+ NULL, NULL);
+ xml_node_free(ctx->xml, resp);
+ }
+
+ os_free(resp_uri);
+
+ return ctx->pps_cred_set ? 0 : -1;
+}
+
+
+int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
+{
+ xml_node_t *syncml, *resp;
+ char *resp_uri = NULL;
+ int msgid = 0;
+
+ if (url == NULL) {
+ wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested");
+ ctx->no_reconnect = 2;
+
+ wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
+ write_summary(ctx, "Wait for IP address before starting SIM provisioning");
+
+ if (wait_ip_addr(ctx->ifname, 15) < 0) {
+ wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
+ }
+ write_summary(ctx, "OMA-DM SIM provisioning");
+
+ msgid++;
+ syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
+ if (syncml == NULL)
+ return -1;
+
+ while (syncml) {
+ resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
+ syncml, NULL, NULL, NULL, NULL, NULL);
+ if (resp == NULL)
+ return -1;
+
+ msgid++;
+ syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
+ NULL, NULL);
+ xml_node_free(ctx->xml, resp);
+ }
+
+ os_free(resp_uri);
+
+ if (ctx->pps_cred_set) {
+ wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
+ cmd_set_pps(ctx, ctx->pps_fname);
+
+ wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
+ write_summary(ctx, "Requesting reconnection with updated configuration");
+ if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
+ wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
+ write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
+ return -1;
+ }
+ }
+
+ return ctx->pps_cred_set ? 0 : -1;
+}
+
+
+void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps)
+{
+ xml_node_t *syncml, *resp;
+ char *resp_uri = NULL;
+ int msgid = 0;
+
+ wpa_printf(MSG_INFO, "OMA-DM policy update");
+ write_summary(ctx, "OMA-DM policy update");
+
+ msgid++;
+ syncml = build_oma_dm_1_pol_upd(ctx, address, msgid);
+ if (syncml == NULL)
+ return;
+
+ while (syncml) {
+ resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
+ syncml, NULL, cred_username,
+ cred_password, client_cert, client_key);
+ if (resp == NULL)
+ return;
+
+ msgid++;
+ syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
+ pps, pps_fname);
+ xml_node_free(ctx->xml, resp);
+ }
+
+ os_free(resp_uri);
+
+ if (ctx->pps_updated) {
+ wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO");
+ write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection");
+ cmd_set_pps(ctx, pps_fname);
+ if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to request wpa_supplicant to reconnect");
+ write_summary(ctx,
+ "Failed to request wpa_supplicant to reconnect");
+ }
+ }
+}
+
+
+void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps)
+{
+ xml_node_t *syncml, *resp;
+ char *resp_uri = NULL;
+ int msgid = 0;
+
+ wpa_printf(MSG_INFO, "OMA-DM subscription remediation");
+ write_summary(ctx, "OMA-DM subscription remediation");
+
+ msgid++;
+ syncml = build_oma_dm_1_sub_rem(ctx, address, msgid);
+ if (syncml == NULL)
+ return;
+
+ while (syncml) {
+ resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
+ syncml, NULL, cred_username,
+ cred_password, client_cert, client_key);
+ if (resp == NULL)
+ return;
+
+ msgid++;
+ syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
+ pps, pps_fname);
+ xml_node_free(ctx->xml, resp);
+ }
+
+ os_free(resp_uri);
+
+ wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
+ write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
+ cmd_set_pps(ctx, pps_fname);
+ if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
+ wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
+ write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
+ }
+}
+
+
+void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
+ const char *add_fname)
+{
+ xml_node_t *pps, *add;
+ int res;
+
+ ctx->fqdn = os_strdup("wi-fi.org");
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
+ pps_fname);
+ return;
+ }
+
+ add = node_from_file(ctx->xml, add_fname);
+ if (add == NULL) {
+ wpa_printf(MSG_INFO, "Add file %s could not be parsed",
+ add_fname);
+ xml_node_free(ctx->xml, pps);
+ return;
+ }
+
+ res = oma_dm_add(ctx, add, pps, pps_fname);
+ wpa_printf(MSG_INFO, "oma_dm_add --> %d", res);
+
+ xml_node_free(ctx->xml, pps);
+ xml_node_free(ctx->xml, add);
+}
+
+
+void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
+ const char *replace_fname)
+{
+ xml_node_t *pps, *replace;
+ int res;
+
+ ctx->fqdn = os_strdup("wi-fi.org");
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
+ pps_fname);
+ return;
+ }
+
+ replace = node_from_file(ctx->xml, replace_fname);
+ if (replace == NULL) {
+ wpa_printf(MSG_INFO, "Replace file %s could not be parsed",
+ replace_fname);
+ xml_node_free(ctx->xml, pps);
+ return;
+ }
+
+ res = oma_dm_replace(ctx, replace, pps, pps_fname);
+ wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res);
+
+ xml_node_free(ctx->xml, pps);
+ xml_node_free(ctx->xml, replace);
+}
diff --git a/contrib/wpa/hs20/client/osu_client.c b/contrib/wpa/hs20/client/osu_client.c
new file mode 100644
index 0000000..de7f351
--- /dev/null
+++ b/contrib/wpa/hs20/client/osu_client.c
@@ -0,0 +1,3227 @@
+/*
+ * Hotspot 2.0 OSU client
+ * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <time.h>
+#include <sys/stat.h>
+#ifdef ANDROID
+#include "private/android_filesystem_config.h"
+#endif /* ANDROID */
+
+#include "common.h"
+#include "utils/browser.h"
+#include "utils/base64.h"
+#include "utils/xml-utils.h"
+#include "utils/http-utils.h"
+#include "common/wpa_ctrl.h"
+#include "common/wpa_helpers.h"
+#include "eap_common/eap_defs.h"
+#include "crypto/crypto.h"
+#include "crypto/sha256.h"
+#include "osu_client.h"
+
+
+void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ FILE *f;
+ char buf[500];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ write_summary(ctx, "%s", buf);
+
+ if (!ctx->result_file)
+ return;
+
+ f = fopen(ctx->result_file, "w");
+ if (f == NULL)
+ return;
+
+ va_start(ap, fmt);
+ vfprintf(f, fmt, ap);
+ va_end(ap);
+ fprintf(f, "\n");
+ fclose(f);
+}
+
+
+void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ FILE *f;
+
+ if (!ctx->summary_file)
+ return;
+
+ f = fopen(ctx->summary_file, "a");
+ if (f == NULL)
+ return;
+
+ va_start(ap, fmt);
+ vfprintf(f, fmt, ap);
+ va_end(ap);
+ fprintf(f, "\n");
+ fclose(f);
+}
+
+
+void debug_dump_node(struct hs20_osu_client *ctx, const char *title,
+ xml_node_t *node)
+{
+ char *str = xml_node_to_str(ctx->xml, node);
+ wpa_printf(MSG_DEBUG, "[hs20] %s: '%s'", title, str);
+ free(str);
+}
+
+
+static int valid_fqdn(const char *fqdn)
+{
+ const char *pos;
+
+ /* TODO: could make this more complete.. */
+ if (strchr(fqdn, '.') == 0 || strlen(fqdn) > 255)
+ return 0;
+ for (pos = fqdn; *pos; pos++) {
+ if (*pos >= 'a' && *pos <= 'z')
+ continue;
+ if (*pos >= 'A' && *pos <= 'Z')
+ continue;
+ if (*pos >= '0' && *pos <= '9')
+ continue;
+ if (*pos == '-' || *pos == '.' || *pos == '_')
+ continue;
+ return 0;
+ }
+ return 1;
+}
+
+
+int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
+{
+ xml_node_t *node;
+ char *url, *user = NULL, *pw = NULL;
+ char *proto;
+ int ret = -1;
+
+ proto = xml_node_get_attr_value(ctx->xml, getcert,
+ "enrollmentProtocol");
+ if (!proto)
+ return -1;
+ wpa_printf(MSG_INFO, "getCertificate - enrollmentProtocol=%s", proto);
+ write_summary(ctx, "getCertificate - enrollmentProtocol=%s", proto);
+ if (os_strcasecmp(proto, "EST") != 0) {
+ wpa_printf(MSG_INFO, "Unsupported enrollmentProtocol");
+ xml_node_get_attr_value_free(ctx->xml, proto);
+ return -1;
+ }
+ xml_node_get_attr_value_free(ctx->xml, proto);
+
+ node = get_node(ctx->xml, getcert, "enrollmentServerURI");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "Could not find enrollmentServerURI node");
+ xml_node_get_attr_value_free(ctx->xml, proto);
+ return -1;
+ }
+ url = xml_node_get_text(ctx->xml, node);
+ if (url == NULL) {
+ wpa_printf(MSG_INFO, "Could not get URL text");
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "enrollmentServerURI: %s", url);
+ write_summary(ctx, "enrollmentServerURI: %s", url);
+
+ node = get_node(ctx->xml, getcert, "estUserID");
+ if (node == NULL && !ctx->client_cert_present) {
+ wpa_printf(MSG_INFO, "Could not find estUserID node");
+ goto fail;
+ }
+ if (node) {
+ user = xml_node_get_text(ctx->xml, node);
+ if (user == NULL) {
+ wpa_printf(MSG_INFO, "Could not get estUserID text");
+ goto fail;
+ }
+ wpa_printf(MSG_INFO, "estUserID: %s", user);
+ write_summary(ctx, "estUserID: %s", user);
+ }
+
+ node = get_node(ctx->xml, getcert, "estPassword");
+ if (node == NULL && !ctx->client_cert_present) {
+ wpa_printf(MSG_INFO, "Could not find estPassword node");
+ goto fail;
+ }
+ if (node) {
+ pw = xml_node_get_base64_text(ctx->xml, node, NULL);
+ if (pw == NULL) {
+ wpa_printf(MSG_INFO, "Could not get estPassword text");
+ goto fail;
+ }
+ wpa_printf(MSG_INFO, "estPassword: %s", pw);
+ }
+
+ mkdir("Cert", S_IRWXU);
+ if (est_load_cacerts(ctx, url) < 0 ||
+ est_build_csr(ctx, url) < 0 ||
+ est_simple_enroll(ctx, url, user, pw) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ xml_node_get_text_free(ctx->xml, url);
+ xml_node_get_text_free(ctx->xml, user);
+ xml_node_get_text_free(ctx->xml, pw);
+
+ return ret;
+}
+
+
+static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert,
+ const char *fqdn)
+{
+ u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN];
+ char *der, *pem;
+ size_t der_len, pem_len;
+ char *fingerprint;
+ char buf[200];
+
+ wpa_printf(MSG_INFO, "PPS for certificate credential - fqdn=%s", fqdn);
+
+ fingerprint = xml_node_get_text(ctx->xml, cert);
+ if (fingerprint == NULL)
+ return -1;
+ if (hexstr2bin(fingerprint, digest1, SHA256_MAC_LEN) < 0) {
+ wpa_printf(MSG_INFO, "Invalid SHA256 hash value");
+ write_result(ctx, "Invalid client certificate SHA256 hash value in PPS");
+ xml_node_get_text_free(ctx->xml, fingerprint);
+ return -1;
+ }
+ xml_node_get_text_free(ctx->xml, fingerprint);
+
+ der = os_readfile("Cert/est_cert.der", &der_len);
+ if (der == NULL) {
+ wpa_printf(MSG_INFO, "Could not find client certificate from EST");
+ write_result(ctx, "Could not find client certificate from EST");
+ return -1;
+ }
+
+ if (sha256_vector(1, (const u8 **) &der, &der_len, digest2) < 0) {
+ os_free(der);
+ return -1;
+ }
+ os_free(der);
+
+ if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) {
+ wpa_printf(MSG_INFO, "Client certificate from EST does not match fingerprint from PPS MO");
+ write_result(ctx, "Client certificate from EST does not match fingerprint from PPS MO");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "Client certificate from EST matches PPS MO");
+ unlink("Cert/est_cert.der");
+
+ os_snprintf(buf, sizeof(buf), "SP/%s/client-ca.pem", fqdn);
+ if (rename("Cert/est-cacerts.pem", buf) < 0) {
+ wpa_printf(MSG_INFO, "Could not move est-cacerts.pem to client-ca.pem: %s",
+ strerror(errno));
+ return -1;
+ }
+ pem = os_readfile(buf, &pem_len);
+
+ os_snprintf(buf, sizeof(buf), "SP/%s/client-cert.pem", fqdn);
+ if (rename("Cert/est_cert.pem", buf) < 0) {
+ wpa_printf(MSG_INFO, "Could not move est_cert.pem to client-cert.pem: %s",
+ strerror(errno));
+ os_free(pem);
+ return -1;
+ }
+
+ if (pem) {
+ FILE *f = fopen(buf, "a");
+ if (f) {
+ fwrite(pem, pem_len, 1, f);
+ fclose(f);
+ }
+ os_free(pem);
+ }
+
+ os_snprintf(buf, sizeof(buf), "SP/%s/client-key.pem", fqdn);
+ if (rename("Cert/privkey-plain.pem", buf) < 0) {
+ wpa_printf(MSG_INFO, "Could not move privkey-plain.pem to client-key.pem: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ unlink("Cert/est-req.b64");
+ unlink("Cert/est-req.pem");
+ unlink("Cert/est-resp.raw");
+ rmdir("Cert");
+
+ return 0;
+}
+
+
+#define TMP_CERT_DL_FILE "tmp-cert-download"
+
+static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
+ const char *fname)
+{
+ xml_node_t *url_node, *hash_node;
+ char *url, *hash;
+ char *cert;
+ size_t len;
+ u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN];
+ int res;
+ unsigned char *b64;
+ FILE *f;
+
+ url_node = get_node(ctx->xml, params, "CertURL");
+ hash_node = get_node(ctx->xml, params, "CertSHA256Fingerprint");
+ if (url_node == NULL || hash_node == NULL)
+ return -1;
+ url = xml_node_get_text(ctx->xml, url_node);
+ hash = xml_node_get_text(ctx->xml, hash_node);
+ if (url == NULL || hash == NULL) {
+ xml_node_get_text_free(ctx->xml, url);
+ xml_node_get_text_free(ctx->xml, hash);
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "CertURL: %s", url);
+ wpa_printf(MSG_INFO, "SHA256 hash: %s", hash);
+
+ if (hexstr2bin(hash, digest1, SHA256_MAC_LEN) < 0) {
+ wpa_printf(MSG_INFO, "Invalid SHA256 hash value");
+ write_result(ctx, "Invalid SHA256 hash value for downloaded certificate");
+ xml_node_get_text_free(ctx->xml, hash);
+ return -1;
+ }
+ xml_node_get_text_free(ctx->xml, hash);
+
+ write_summary(ctx, "Download certificate from %s", url);
+ ctx->no_osu_cert_validation = 1;
+ http_ocsp_set(ctx->http, 1);
+ res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL);
+ http_ocsp_set(ctx->http,
+ (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
+ ctx->no_osu_cert_validation = 0;
+ xml_node_get_text_free(ctx->xml, url);
+ if (res < 0)
+ return -1;
+
+ cert = os_readfile(TMP_CERT_DL_FILE, &len);
+ remove(TMP_CERT_DL_FILE);
+ if (cert == NULL)
+ return -1;
+
+ if (sha256_vector(1, (const u8 **) &cert, &len, digest2) < 0) {
+ os_free(cert);
+ return -1;
+ }
+
+ if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) {
+ wpa_printf(MSG_INFO, "Downloaded certificate fingerprint did not match");
+ write_result(ctx, "Downloaded certificate fingerprint did not match");
+ os_free(cert);
+ return -1;
+ }
+
+ b64 = base64_encode((unsigned char *) cert, len, NULL);
+ os_free(cert);
+ if (b64 == NULL)
+ return -1;
+
+ f = fopen(fname, "wb");
+ if (f == NULL) {
+ os_free(b64);
+ return -1;
+ }
+
+ fprintf(f, "-----BEGIN CERTIFICATE-----\n"
+ "%s"
+ "-----END CERTIFICATE-----\n",
+ b64);
+
+ os_free(b64);
+ fclose(f);
+
+ wpa_printf(MSG_INFO, "Downloaded certificate into %s and validated fingerprint",
+ fname);
+ write_summary(ctx, "Downloaded certificate into %s and validated fingerprint",
+ fname);
+
+ return 0;
+}
+
+
+static int cmd_dl_osu_ca(struct hs20_osu_client *ctx, const char *pps_fname,
+ const char *ca_fname)
+{
+ xml_node_t *pps, *node;
+ int ret;
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
+ return -1;
+ }
+
+ node = get_child_node(ctx->xml, pps,
+ "SubscriptionUpdate/TrustRoot");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No SubscriptionUpdate/TrustRoot/CertURL found from PPS");
+ xml_node_free(ctx->xml, pps);
+ return -1;
+ }
+
+ ret = download_cert(ctx, node, ca_fname);
+ xml_node_free(ctx->xml, pps);
+
+ return ret;
+}
+
+
+static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
+ const char *ca_fname)
+{
+ xml_node_t *pps, *node;
+ int ret;
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
+ return -1;
+ }
+
+ node = get_child_node(ctx->xml, pps,
+ "Policy/PolicyUpdate/TrustRoot");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
+ xml_node_free(ctx->xml, pps);
+ return -1;
+ }
+
+ ret = download_cert(ctx, node, ca_fname);
+ xml_node_free(ctx->xml, pps);
+
+ return ret;
+}
+
+
+static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname,
+ const char *ca_fname)
+{
+ xml_node_t *pps, *node, *aaa;
+ int ret;
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
+ return -1;
+ }
+
+ node = get_child_node(ctx->xml, pps,
+ "AAAServerTrustRoot");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS");
+ xml_node_free(ctx->xml, pps);
+ return -1;
+ }
+
+ aaa = xml_node_first_child(ctx->xml, node);
+ if (aaa == NULL) {
+ wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS");
+ xml_node_free(ctx->xml, pps);
+ return -1;
+ }
+
+ ret = download_cert(ctx, aaa, ca_fname);
+ xml_node_free(ctx->xml, pps);
+
+ return ret;
+}
+
+
+static int download_trust_roots(struct hs20_osu_client *ctx,
+ const char *pps_fname)
+{
+ char *dir, *pos;
+ char fname[300];
+ int ret;
+
+ dir = os_strdup(pps_fname);
+ if (dir == NULL)
+ return -1;
+ pos = os_strrchr(dir, '/');
+ if (pos == NULL) {
+ os_free(dir);
+ return -1;
+ }
+ *pos = '\0';
+
+ 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);
+ snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
+ cmd_dl_aaa_ca(ctx, pps_fname, fname);
+
+ os_free(dir);
+
+ return ret;
+}
+
+
+static int server_dnsname_suffix_match(struct hs20_osu_client *ctx,
+ const char *fqdn)
+{
+ size_t match_len, len, i;
+ const char *val;
+
+ match_len = os_strlen(fqdn);
+
+ for (i = 0; i < ctx->server_dnsname_count; i++) {
+ wpa_printf(MSG_INFO,
+ "Checking suffix match against server dNSName %s",
+ ctx->server_dnsname[i]);
+ val = ctx->server_dnsname[i];
+ len = os_strlen(val);
+
+ if (match_len > len)
+ continue;
+
+ if (os_strncasecmp(val + len - match_len, fqdn, match_len) != 0)
+ continue; /* no match */
+
+ if (match_len == len)
+ return 1; /* exact match */
+
+ if (val[len - match_len - 1] == '.')
+ return 1; /* full label match completes suffix match */
+
+ /* Reject due to incomplete label match */
+ }
+
+ /* None of the dNSName(s) matched */
+ return 0;
+}
+
+
+int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
+ xml_node_t *add_mo, char *fname, size_t fname_len)
+{
+ char *str;
+ char *fqdn, *pos;
+ xml_node_t *tnds, *mo, *cert;
+ const char *name;
+ int ret;
+
+ if (strncmp(uri, "./Wi-Fi/", 8) != 0) {
+ wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO: '%s'",
+ uri);
+ write_result(ctx, "Unsupported location for addMO to add PPS MO: '%s'",
+ uri);
+ return -1;
+ }
+
+ fqdn = strdup(uri + 8);
+ if (fqdn == NULL)
+ return -1;
+ pos = strchr(fqdn, '/');
+ if (pos) {
+ if (os_strcasecmp(pos, "/PerProviderSubscription") != 0) {
+ wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO (extra directory): '%s'",
+ uri);
+ write_result(ctx, "Unsupported location for addMO to "
+ "add PPS MO (extra directory): '%s'", uri);
+ return -1;
+ }
+ *pos = '\0'; /* remove trailing slash and PPS node name */
+ }
+ wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn);
+
+ if (!server_dnsname_suffix_match(ctx, fqdn)) {
+ wpa_printf(MSG_INFO, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
+ fqdn);
+ write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
+ fqdn);
+ free(fqdn);
+ return -1;
+ }
+
+ if (!valid_fqdn(fqdn)) {
+ wpa_printf(MSG_INFO, "Invalid FQDN '%s'", fqdn);
+ write_result(ctx, "Invalid FQDN '%s'", fqdn);
+ free(fqdn);
+ return -1;
+ }
+
+ mkdir("SP", S_IRWXU);
+ snprintf(fname, fname_len, "SP/%s", fqdn);
+ if (mkdir(fname, S_IRWXU) < 0) {
+ if (errno != EEXIST) {
+ int err = errno;
+ wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
+ fname, strerror(err));
+ free(fqdn);
+ return -1;
+ }
+ }
+
+#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 */
+
+ snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
+
+ if (os_file_exists(fname)) {
+ wpa_printf(MSG_INFO, "PPS file '%s' exists - reject addMO",
+ fname);
+ write_result(ctx, "PPS file '%s' exists - reject addMO",
+ fname);
+ free(fqdn);
+ return -2;
+ }
+ wpa_printf(MSG_INFO, "Using PPS file: %s", fname);
+
+ str = xml_node_get_text(ctx->xml, add_mo);
+ if (str == NULL) {
+ wpa_printf(MSG_INFO, "Could not extract MO text");
+ free(fqdn);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "[hs20] addMO text: '%s'", str);
+
+ tnds = xml_node_from_buf(ctx->xml, str);
+ xml_node_get_text_free(ctx->xml, str);
+ if (tnds == NULL) {
+ wpa_printf(MSG_INFO, "[hs20] Could not parse addMO text");
+ free(fqdn);
+ return -1;
+ }
+
+ mo = tnds_to_mo(ctx->xml, tnds);
+ if (mo == NULL) {
+ wpa_printf(MSG_INFO, "[hs20] Could not parse addMO TNDS text");
+ free(fqdn);
+ return -1;
+ }
+
+ debug_dump_node(ctx, "Parsed TNDS", mo);
+
+ name = xml_node_get_localname(ctx->xml, mo);
+ if (os_strcasecmp(name, "PerProviderSubscription") != 0) {
+ wpa_printf(MSG_INFO, "[hs20] Unexpected PPS MO root node name '%s'",
+ name);
+ free(fqdn);
+ return -1;
+ }
+
+ cert = get_child_node(ctx->xml, mo,
+ "Credential/DigitalCertificate/"
+ "CertSHA256Fingerprint");
+ if (cert && process_est_cert(ctx, cert, fqdn) < 0) {
+ xml_node_free(ctx->xml, mo);
+ free(fqdn);
+ return -1;
+ }
+ free(fqdn);
+
+ if (node_to_file(ctx->xml, fname, mo) < 0) {
+ wpa_printf(MSG_INFO, "Could not write MO to file");
+ xml_node_free(ctx->xml, mo);
+ return -1;
+ }
+ xml_node_free(ctx->xml, mo);
+
+ wpa_printf(MSG_INFO, "A new PPS MO added as '%s'", fname);
+ write_summary(ctx, "A new PPS MO added as '%s'", fname);
+
+ ret = download_trust_roots(ctx, fname);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO, "Remove invalid PPS MO file");
+ write_summary(ctx, "Remove invalid PPS MO file");
+ unlink(fname);
+ }
+
+ return ret;
+}
+
+
+int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
+ xml_node_t *pps)
+{
+ char *str;
+ FILE *f;
+ char backup[300];
+
+ if (ctx->client_cert_present) {
+ xml_node_t *cert;
+ cert = get_child_node(ctx->xml, pps,
+ "Credential/DigitalCertificate/"
+ "CertSHA256Fingerprint");
+ if (cert && os_file_exists("Cert/est_cert.der") &&
+ process_est_cert(ctx, cert, ctx->fqdn) < 0) {
+ wpa_printf(MSG_INFO, "EST certificate update processing failed on PPS MO update");
+ return -1;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname);
+
+ str = xml_node_to_str(ctx->xml, pps);
+ if (str == NULL) {
+ wpa_printf(MSG_ERROR, "No node found");
+ return -1;
+ }
+ wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str);
+
+ snprintf(backup, sizeof(backup), "%s.bak", pps_fname);
+ rename(pps_fname, backup);
+ f = fopen(pps_fname, "w");
+ if (f == NULL) {
+ wpa_printf(MSG_INFO, "Could not write PPS");
+ rename(backup, pps_fname);
+ free(str);
+ return -1;
+ }
+ fprintf(f, "%s\n", str);
+ fclose(f);
+
+ free(str);
+
+ return 0;
+}
+
+
+void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps,
+ const char *alt_loc, char **user, char **pw)
+{
+ xml_node_t *node;
+
+ node = get_child_node(ctx->xml, pps,
+ "Credential/UsernamePassword/Username");
+ if (node)
+ *user = xml_node_get_text(ctx->xml, node);
+
+ node = get_child_node(ctx->xml, pps,
+ "Credential/UsernamePassword/Password");
+ if (node)
+ *pw = xml_node_get_base64_text(ctx->xml, node, NULL);
+
+ node = get_child_node(ctx->xml, pps, alt_loc);
+ if (node) {
+ xml_node_t *a;
+ a = get_node(ctx->xml, node, "Username");
+ if (a) {
+ xml_node_get_text_free(ctx->xml, *user);
+ *user = xml_node_get_text(ctx->xml, a);
+ wpa_printf(MSG_INFO, "Use OSU username '%s'", *user);
+ }
+
+ a = get_node(ctx->xml, node, "Password");
+ if (a) {
+ free(*pw);
+ *pw = xml_node_get_base64_text(ctx->xml, a, NULL);
+ wpa_printf(MSG_INFO, "Use OSU password");
+ }
+ }
+}
+
+
+/* Remove old credentials based on HomeSP/FQDN */
+static void remove_sp_creds(struct hs20_osu_client *ctx, const char *fqdn)
+{
+ char cmd[300];
+ os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED provisioning_sp=%s", fqdn);
+ if (wpa_command(ctx->ifname, cmd) < 0)
+ wpa_printf(MSG_INFO, "Failed to remove old credential(s)");
+}
+
+
+static void set_pps_cred_policy_spe(struct hs20_osu_client *ctx, int id,
+ xml_node_t *spe)
+{
+ xml_node_t *ssid;
+ char *txt;
+
+ ssid = get_node(ctx->xml, spe, "SSID");
+ if (ssid == NULL)
+ return;
+ txt = xml_node_get_text(ctx->xml, ssid);
+ if (txt == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "- Policy/SPExclusionList/<X+>/SSID = %s", txt);
+ if (set_cred_quoted(ctx->ifname, id, "excluded_ssid", txt) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred excluded_ssid");
+ xml_node_get_text_free(ctx->xml, txt);
+}
+
+
+static void set_pps_cred_policy_spel(struct hs20_osu_client *ctx, int id,
+ xml_node_t *spel)
+{
+ xml_node_t *child;
+
+ xml_node_for_each_child(ctx->xml, child, spel) {
+ xml_node_for_each_check(ctx->xml, child);
+ set_pps_cred_policy_spe(ctx, id, child);
+ }
+}
+
+
+static void set_pps_cred_policy_prp(struct hs20_osu_client *ctx, int id,
+ xml_node_t *prp)
+{
+ xml_node_t *node;
+ char *txt = NULL, *pos;
+ char *prio, *country_buf = NULL;
+ const char *country;
+ char val[200];
+ int priority;
+
+ node = get_node(ctx->xml, prp, "Priority");
+ if (node == NULL)
+ return;
+ prio = xml_node_get_text(ctx->xml, node);
+ if (prio == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Priority = %s",
+ prio);
+ priority = atoi(prio);
+ xml_node_get_text_free(ctx->xml, prio);
+
+ node = get_node(ctx->xml, prp, "Country");
+ if (node) {
+ country_buf = xml_node_get_text(ctx->xml, node);
+ if (country_buf == NULL)
+ return;
+ country = country_buf;
+ wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Country = %s",
+ country);
+ } else {
+ country = "*";
+ }
+
+ node = get_node(ctx->xml, prp, "FQDN_Match");
+ if (node == NULL)
+ goto out;
+ txt = xml_node_get_text(ctx->xml, node);
+ if (txt == NULL)
+ goto out;
+ wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/FQDN_Match = %s",
+ txt);
+ pos = strrchr(txt, ',');
+ if (pos == NULL)
+ goto out;
+ *pos++ = '\0';
+
+ snprintf(val, sizeof(val), "%s,%d,%d,%s", txt,
+ strcmp(pos, "includeSubdomains") != 0, priority, country);
+ if (set_cred_quoted(ctx->ifname, id, "roaming_partner", val) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred roaming_partner");
+out:
+ xml_node_get_text_free(ctx->xml, country_buf);
+ xml_node_get_text_free(ctx->xml, txt);
+}
+
+
+static void set_pps_cred_policy_prpl(struct hs20_osu_client *ctx, int id,
+ xml_node_t *prpl)
+{
+ xml_node_t *child;
+
+ xml_node_for_each_child(ctx->xml, child, prpl) {
+ xml_node_for_each_check(ctx->xml, child);
+ set_pps_cred_policy_prp(ctx, id, child);
+ }
+}
+
+
+static void set_pps_cred_policy_min_backhaul(struct hs20_osu_client *ctx, int id,
+ xml_node_t *min_backhaul)
+{
+ xml_node_t *node;
+ char *type, *dl = NULL, *ul = NULL;
+ int home;
+
+ node = get_node(ctx->xml, min_backhaul, "NetworkType");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without mandatory NetworkType node");
+ return;
+ }
+
+ type = xml_node_get_text(ctx->xml, node);
+ if (type == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/NetworkType = %s",
+ type);
+ if (os_strcasecmp(type, "home") == 0)
+ home = 1;
+ else if (os_strcasecmp(type, "roaming") == 0)
+ home = 0;
+ else {
+ wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold with invalid NetworkType");
+ xml_node_get_text_free(ctx->xml, type);
+ return;
+ }
+ xml_node_get_text_free(ctx->xml, type);
+
+ node = get_node(ctx->xml, min_backhaul, "DLBandwidth");
+ if (node)
+ dl = xml_node_get_text(ctx->xml, node);
+
+ node = get_node(ctx->xml, min_backhaul, "ULBandwidth");
+ if (node)
+ ul = xml_node_get_text(ctx->xml, node);
+
+ if (dl == NULL && ul == NULL) {
+ wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without either DLBandwidth or ULBandwidth nodes");
+ return;
+ }
+
+ if (dl)
+ wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/DLBandwidth = %s",
+ dl);
+ if (ul)
+ wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/ULBandwidth = %s",
+ ul);
+
+ if (home) {
+ if (dl &&
+ set_cred(ctx->ifname, id, "min_dl_bandwidth_home", dl) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit");
+ if (ul &&
+ set_cred(ctx->ifname, id, "min_ul_bandwidth_home", ul) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit");
+ } else {
+ if (dl &&
+ set_cred(ctx->ifname, id, "min_dl_bandwidth_roaming", dl) <
+ 0)
+ wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit");
+ if (ul &&
+ set_cred(ctx->ifname, id, "min_ul_bandwidth_roaming", ul) <
+ 0)
+ wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit");
+ }
+
+ xml_node_get_text_free(ctx->xml, dl);
+ xml_node_get_text_free(ctx->xml, ul);
+}
+
+
+static void set_pps_cred_policy_min_backhaul_list(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ xml_node_t *child;
+
+ wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold");
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ set_pps_cred_policy_min_backhaul(ctx, id, child);
+ }
+}
+
+
+static void set_pps_cred_policy_update(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ wpa_printf(MSG_INFO, "- Policy/PolicyUpdate");
+ /* Not used in wpa_supplicant */
+}
+
+
+static void set_pps_cred_policy_required_proto_port(struct hs20_osu_client *ctx,
+ int id, xml_node_t *tuple)
+{
+ xml_node_t *node;
+ char *proto, *port;
+ char *buf;
+ size_t buflen;
+
+ node = get_node(ctx->xml, tuple, "IPProtocol");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "Ignore RequiredProtoPortTuple without mandatory IPProtocol node");
+ return;
+ }
+
+ proto = xml_node_get_text(ctx->xml, node);
+ if (proto == NULL)
+ return;
+
+ wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/IPProtocol = %s",
+ proto);
+
+ node = get_node(ctx->xml, tuple, "PortNumber");
+ port = node ? xml_node_get_text(ctx->xml, node) : NULL;
+ if (port) {
+ wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/PortNumber = %s",
+ port);
+ buflen = os_strlen(proto) + os_strlen(port) + 10;
+ buf = os_malloc(buflen);
+ if (buf)
+ os_snprintf(buf, buflen, "%s:%s", proto, port);
+ xml_node_get_text_free(ctx->xml, port);
+ } else {
+ buflen = os_strlen(proto) + 10;
+ buf = os_malloc(buflen);
+ if (buf)
+ os_snprintf(buf, buflen, "%s", proto);
+ }
+
+ xml_node_get_text_free(ctx->xml, proto);
+
+ if (buf == NULL)
+ return;
+
+ if (set_cred(ctx->ifname, id, "req_conn_capab", buf) < 0)
+ wpa_printf(MSG_INFO, "Could not set req_conn_capab");
+
+ os_free(buf);
+}
+
+
+static void set_pps_cred_policy_required_proto_ports(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ xml_node_t *child;
+
+ wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple");
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ set_pps_cred_policy_required_proto_port(ctx, id, child);
+ }
+}
+
+
+static void set_pps_cred_policy_max_bss_load(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Policy/MaximumBSSLoadValue - %s", str);
+ if (set_cred(ctx->ifname, id, "max_bss_load", str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred max_bss_load limit");
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_policy(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ xml_node_t *child;
+ const char *name;
+
+ wpa_printf(MSG_INFO, "- Policy");
+
+ 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, "PreferredRoamingPartnerList") == 0)
+ set_pps_cred_policy_prpl(ctx, id, child);
+ else if (os_strcasecmp(name, "MinBackhaulThreshold") == 0)
+ set_pps_cred_policy_min_backhaul_list(ctx, id, child);
+ else if (os_strcasecmp(name, "PolicyUpdate") == 0)
+ set_pps_cred_policy_update(ctx, id, child);
+ else if (os_strcasecmp(name, "SPExclusionList") == 0)
+ set_pps_cred_policy_spel(ctx, id, child);
+ else if (os_strcasecmp(name, "RequiredProtoPortTuple") == 0)
+ set_pps_cred_policy_required_proto_ports(ctx, id, child);
+ else if (os_strcasecmp(name, "MaximumBSSLoadValue") == 0)
+ set_pps_cred_policy_max_bss_load(ctx, id, child);
+ else
+ wpa_printf(MSG_INFO, "Unknown Policy node '%s'", name);
+ }
+}
+
+
+static void set_pps_cred_priority(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- CredentialPriority = %s", str);
+ if (set_cred(ctx->ifname, id, "sp_priority", str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred sp_priority");
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_aaa_server_trust_root(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ wpa_printf(MSG_INFO, "- AAAServerTrustRoot - TODO");
+}
+
+
+static void set_pps_cred_sub_update(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ wpa_printf(MSG_INFO, "- SubscriptionUpdate");
+ /* not used within wpa_supplicant */
+}
+
+
+static void set_pps_cred_home_sp_network_id(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ xml_node_t *ssid_node, *hessid_node;
+ char *ssid, *hessid;
+
+ ssid_node = get_node(ctx->xml, node, "SSID");
+ if (ssid_node == NULL) {
+ wpa_printf(MSG_INFO, "Ignore HomeSP/NetworkID without mandatory SSID node");
+ return;
+ }
+
+ hessid_node = get_node(ctx->xml, node, "HESSID");
+
+ ssid = xml_node_get_text(ctx->xml, ssid_node);
+ if (ssid == NULL)
+ return;
+ hessid = hessid_node ? xml_node_get_text(ctx->xml, hessid_node) : NULL;
+
+ wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/SSID = %s", ssid);
+ if (hessid)
+ wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/HESSID = %s",
+ hessid);
+
+ /* TODO: Configure to wpa_supplicant */
+
+ xml_node_get_text_free(ctx->xml, ssid);
+ xml_node_get_text_free(ctx->xml, hessid);
+}
+
+
+static void set_pps_cred_home_sp_network_ids(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ xml_node_t *child;
+
+ wpa_printf(MSG_INFO, "- HomeSP/NetworkID");
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ set_pps_cred_home_sp_network_id(ctx, id, child);
+ }
+}
+
+
+static void set_pps_cred_home_sp_friendly_name(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- HomeSP/FriendlyName = %s", str);
+ /* not used within wpa_supplicant(?) */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_home_sp_icon_url(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- HomeSP/IconURL = %s", str);
+ /* not used within wpa_supplicant */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_home_sp_fqdn(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- HomeSP/FQDN = %s", str);
+ if (set_cred_quoted(ctx->ifname, id, "domain", str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred domain");
+ if (set_cred_quoted(ctx->ifname, id, "domain_suffix_match", str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred domain_suffix_match");
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ xml_node_t *child;
+ const char *name;
+ char *homeoi = NULL;
+ int required = 0;
+ char *str;
+
+ 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 (strcasecmp(name, "HomeOI") == 0 && !homeoi) {
+ homeoi = xml_node_get_text(ctx->xml, child);
+ wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOI = %s",
+ homeoi);
+ } else if (strcasecmp(name, "HomeOIRequired") == 0) {
+ str = xml_node_get_text(ctx->xml, child);
+ wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOIRequired = '%s'",
+ str);
+ if (str == NULL)
+ continue;
+ required = strcasecmp(str, "true") == 0;
+ xml_node_get_text_free(ctx->xml, str);
+ } else
+ wpa_printf(MSG_INFO, "Unknown HomeOIList node '%s'",
+ name);
+ }
+
+ if (homeoi == NULL) {
+ wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> without HomeOI ignored");
+ return;
+ }
+
+ wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> '%s' required=%d",
+ homeoi, required);
+
+ if (required) {
+ if (set_cred(ctx->ifname, id, "required_roaming_consortium",
+ 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)
+ wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
+ }
+
+ xml_node_get_text_free(ctx->xml, homeoi);
+}
+
+
+static void set_pps_cred_home_sp_oi_list(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ xml_node_t *child;
+
+ wpa_printf(MSG_INFO, "- HomeSP/HomeOIList");
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ set_pps_cred_home_sp_oi(ctx, id, child);
+ }
+}
+
+
+static void set_pps_cred_home_sp_other_partner(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ xml_node_t *child;
+ const char *name;
+ char *fqdn = NULL;
+
+ 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, "FQDN") == 0 && !fqdn) {
+ fqdn = xml_node_get_text(ctx->xml, child);
+ wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+>/FQDN = %s",
+ fqdn);
+ } else
+ wpa_printf(MSG_INFO, "Unknown OtherHomePartners node '%s'",
+ name);
+ }
+
+ if (fqdn == NULL) {
+ wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+> without FQDN ignored");
+ return;
+ }
+
+ if (set_cred_quoted(ctx->ifname, id, "domain", fqdn) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred domain for OtherHomePartners node");
+
+ xml_node_get_text_free(ctx->xml, fqdn);
+}
+
+
+static void set_pps_cred_home_sp_other_partners(struct hs20_osu_client *ctx,
+ int id,
+ xml_node_t *node)
+{
+ xml_node_t *child;
+
+ wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners");
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ set_pps_cred_home_sp_other_partner(ctx, id, child);
+ }
+}
+
+
+static void set_pps_cred_home_sp_roaming_consortium_oi(
+ struct hs20_osu_client *ctx, int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str);
+ /* TODO: Set to wpa_supplicant */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_home_sp(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ xml_node_t *child;
+ const char *name;
+
+ wpa_printf(MSG_INFO, "- HomeSP");
+
+ 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, "NetworkID") == 0)
+ set_pps_cred_home_sp_network_ids(ctx, id, child);
+ else if (os_strcasecmp(name, "FriendlyName") == 0)
+ set_pps_cred_home_sp_friendly_name(ctx, id, child);
+ else if (os_strcasecmp(name, "IconURL") == 0)
+ set_pps_cred_home_sp_icon_url(ctx, id, child);
+ else if (os_strcasecmp(name, "FQDN") == 0)
+ set_pps_cred_home_sp_fqdn(ctx, id, child);
+ else if (os_strcasecmp(name, "HomeOIList") == 0)
+ set_pps_cred_home_sp_oi_list(ctx, id, child);
+ else if (os_strcasecmp(name, "OtherHomePartners") == 0)
+ set_pps_cred_home_sp_other_partners(ctx, id, child);
+ else if (os_strcasecmp(name, "RoamingConsortiumOI") == 0)
+ set_pps_cred_home_sp_roaming_consortium_oi(ctx, id,
+ child);
+ else
+ wpa_printf(MSG_INFO, "Unknown HomeSP node '%s'", name);
+ }
+}
+
+
+static void set_pps_cred_sub_params(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ wpa_printf(MSG_INFO, "- SubscriptionParameters");
+ /* not used within wpa_supplicant */
+}
+
+
+static void set_pps_cred_creation_date(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Credential/CreationDate = %s", str);
+ /* not used within wpa_supplicant */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_expiration_date(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Credential/ExpirationDate = %s", str);
+ /* not used within wpa_supplicant */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_username(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Username = %s",
+ str);
+ if (set_cred_quoted(ctx->ifname, id, "username", str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred username");
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_password(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ int len, i;
+ char *pw, *hex, *pos, *end;
+
+ pw = xml_node_get_base64_text(ctx->xml, node, &len);
+ if (pw == NULL)
+ return;
+
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Password = %s", pw);
+
+ hex = malloc(len * 2 + 1);
+ if (hex == NULL) {
+ free(pw);
+ return;
+ }
+ end = hex + len * 2 + 1;
+ pos = hex;
+ for (i = 0; i < len; i++) {
+ snprintf(pos, end - pos, "%02x", pw[i]);
+ pos += 2;
+ }
+ free(pw);
+
+ if (set_cred(ctx->ifname, id, "password", hex) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred password");
+ free(hex);
+}
+
+
+static void set_pps_cred_machine_managed(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword/MachineManaged = %s",
+ str);
+ /* not used within wpa_supplicant */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_soft_token_app(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword/SoftTokenApp = %s",
+ str);
+ /* not used within wpa_supplicant */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_able_to_share(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ if (str == NULL)
+ return;
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword/AbleToShare = %s",
+ str);
+ /* not used within wpa_supplicant */
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+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");
+}
+
+
+static void set_pps_cred_username_password(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node)
+{
+ xml_node_t *child;
+ const char *name;
+
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword");
+
+ 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, "Username") == 0)
+ set_pps_cred_username(ctx, id, child);
+ else if (os_strcasecmp(name, "Password") == 0)
+ set_pps_cred_password(ctx, id, child);
+ else if (os_strcasecmp(name, "MachineManaged") == 0)
+ set_pps_cred_machine_managed(ctx, id, child);
+ else if (os_strcasecmp(name, "SoftTokenApp") == 0)
+ set_pps_cred_soft_token_app(ctx, id, child);
+ else if (os_strcasecmp(name, "AbleToShare") == 0)
+ set_pps_cred_able_to_share(ctx, id, child);
+ else if (os_strcasecmp(name, "EAPMethod") == 0)
+ set_pps_cred_eap_method(ctx, id, child);
+ else
+ wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword node '%s'",
+ name);
+ }
+}
+
+
+static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node, const char *fqdn)
+{
+ char buf[200], dir[200];
+
+ wpa_printf(MSG_INFO, "- Credential/DigitalCertificate");
+
+ if (getcwd(dir, sizeof(dir)) == NULL)
+ return;
+
+ /* TODO: could build username from Subject of Subject AltName */
+ if (set_cred_quoted(ctx->ifname, id, "username", "cert") < 0) {
+ wpa_printf(MSG_INFO, "Failed to set username");
+ }
+
+ snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, fqdn);
+ if (os_file_exists(buf)) {
+ if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) {
+ wpa_printf(MSG_INFO, "Failed to set client_cert");
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, fqdn);
+ if (os_file_exists(buf)) {
+ if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) {
+ wpa_printf(MSG_INFO, "Failed to set private_key");
+ }
+ }
+}
+
+
+static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node, const char *fqdn, int sim)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ char buf[200], dir[200];
+
+ if (str == NULL)
+ return;
+
+ wpa_printf(MSG_INFO, "- Credential/Realm = %s", str);
+ if (set_cred_quoted(ctx->ifname, id, "realm", str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred realm");
+ xml_node_get_text_free(ctx->xml, str);
+
+ if (sim)
+ return;
+
+ if (getcwd(dir, sizeof(dir)) == NULL)
+ return;
+ snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn);
+ if (os_file_exists(buf)) {
+ if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) {
+ wpa_printf(MSG_INFO, "Failed to set CA cert");
+ }
+ }
+}
+
+
+static void set_pps_cred_check_aaa_cert_status(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+
+ if (str == NULL)
+ return;
+
+ wpa_printf(MSG_INFO, "- Credential/CheckAAAServerCertStatus = %s", str);
+ if (os_strcasecmp(str, "true") == 0 &&
+ set_cred(ctx->ifname, id, "ocsp", "2") < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred ocsp");
+ xml_node_get_text_free(ctx->xml, str);
+}
+
+
+static void set_pps_cred_sim(struct hs20_osu_client *ctx, int id,
+ xml_node_t *sim, xml_node_t *realm)
+{
+ xml_node_t *node;
+ char *imsi, *eaptype, *str, buf[20];
+ int type;
+ int mnc_len = 3;
+ size_t imsi_len;
+
+ node = get_node(ctx->xml, sim, "EAPType");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No SIM/EAPType node in credential");
+ return;
+ }
+ eaptype = xml_node_get_text(ctx->xml, node);
+ if (eaptype == NULL) {
+ wpa_printf(MSG_INFO, "Could not extract SIM/EAPType");
+ return;
+ }
+ wpa_printf(MSG_INFO, " - Credential/SIM/EAPType = %s", eaptype);
+ type = atoi(eaptype);
+ xml_node_get_text_free(ctx->xml, eaptype);
+
+ switch (type) {
+ case EAP_TYPE_SIM:
+ if (set_cred(ctx->ifname, id, "eap", "SIM") < 0)
+ wpa_printf(MSG_INFO, "Could not set eap=SIM");
+ break;
+ case EAP_TYPE_AKA:
+ if (set_cred(ctx->ifname, id, "eap", "AKA") < 0)
+ wpa_printf(MSG_INFO, "Could not set eap=SIM");
+ break;
+ case EAP_TYPE_AKA_PRIME:
+ if (set_cred(ctx->ifname, id, "eap", "AKA'") < 0)
+ wpa_printf(MSG_INFO, "Could not set eap=SIM");
+ break;
+ default:
+ wpa_printf(MSG_INFO, "Unsupported SIM/EAPType %d", type);
+ return;
+ }
+
+ node = get_node(ctx->xml, sim, "IMSI");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No SIM/IMSI node in credential");
+ return;
+ }
+ imsi = xml_node_get_text(ctx->xml, node);
+ if (imsi == NULL) {
+ wpa_printf(MSG_INFO, "Could not extract SIM/IMSI");
+ return;
+ }
+ wpa_printf(MSG_INFO, " - Credential/SIM/IMSI = %s", imsi);
+ imsi_len = os_strlen(imsi);
+ if (imsi_len < 7 || imsi_len + 2 > sizeof(buf)) {
+ wpa_printf(MSG_INFO, "Invalid IMSI length");
+ xml_node_get_text_free(ctx->xml, imsi);
+ return;
+ }
+
+ str = xml_node_get_text(ctx->xml, node);
+ if (str) {
+ char *pos;
+ pos = os_strstr(str, "mnc");
+ if (pos && os_strlen(pos) >= 6) {
+ if (os_strncmp(imsi + 3, pos + 3, 3) == 0)
+ mnc_len = 3;
+ else if (os_strncmp(imsi + 3, pos + 4, 2) == 0)
+ mnc_len = 2;
+ }
+ xml_node_get_text_free(ctx->xml, str);
+ }
+
+ os_memcpy(buf, imsi, 3 + mnc_len);
+ buf[3 + mnc_len] = '-';
+ os_strlcpy(buf + 3 + mnc_len + 1, imsi + 3 + mnc_len,
+ sizeof(buf) - 3 - mnc_len - 1);
+
+ xml_node_get_text_free(ctx->xml, imsi);
+
+ if (set_cred_quoted(ctx->ifname, id, "imsi", buf) < 0)
+ wpa_printf(MSG_INFO, "Could not set IMSI");
+
+ if (set_cred_quoted(ctx->ifname, id, "milenage",
+ "90dca4eda45b53cf0f12d7c9c3bc6a89:"
+ "cb9cccc4b9258e6dca4760379fb82581:000000000123") <
+ 0)
+ wpa_printf(MSG_INFO, "Could not set Milenage parameters");
+}
+
+
+static void set_pps_cred_credential(struct hs20_osu_client *ctx, int id,
+ xml_node_t *node, const char *fqdn)
+{
+ xml_node_t *child, *sim, *realm;
+ const char *name;
+
+ wpa_printf(MSG_INFO, "- Credential");
+
+ sim = get_node(ctx->xml, node, "SIM");
+ realm = get_node(ctx->xml, node, "Realm");
+
+ 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, "CreationDate") == 0)
+ set_pps_cred_creation_date(ctx, id, child);
+ else if (os_strcasecmp(name, "ExpirationDate") == 0)
+ set_pps_cred_expiration_date(ctx, id, child);
+ else if (os_strcasecmp(name, "UsernamePassword") == 0)
+ set_pps_cred_username_password(ctx, id, child);
+ else if (os_strcasecmp(name, "DigitalCertificate") == 0)
+ set_pps_cred_digital_cert(ctx, id, child, fqdn);
+ else if (os_strcasecmp(name, "Realm") == 0)
+ set_pps_cred_realm(ctx, id, child, fqdn, sim != NULL);
+ else if (os_strcasecmp(name, "CheckAAAServerCertStatus") == 0)
+ set_pps_cred_check_aaa_cert_status(ctx, id, child);
+ else if (os_strcasecmp(name, "SIM") == 0)
+ set_pps_cred_sim(ctx, id, child, realm);
+ else
+ wpa_printf(MSG_INFO, "Unknown Credential node '%s'",
+ name);
+ }
+}
+
+
+static void set_pps_credential(struct hs20_osu_client *ctx, int id,
+ xml_node_t *cred, const char *fqdn)
+{
+ xml_node_t *child;
+ const char *name;
+
+ xml_node_for_each_child(ctx->xml, child, cred) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ if (os_strcasecmp(name, "Policy") == 0)
+ set_pps_cred_policy(ctx, id, child);
+ else if (os_strcasecmp(name, "CredentialPriority") == 0)
+ set_pps_cred_priority(ctx, id, child);
+ else if (os_strcasecmp(name, "AAAServerTrustRoot") == 0)
+ set_pps_cred_aaa_server_trust_root(ctx, id, child);
+ else if (os_strcasecmp(name, "SubscriptionUpdate") == 0)
+ set_pps_cred_sub_update(ctx, id, child);
+ else if (os_strcasecmp(name, "HomeSP") == 0)
+ set_pps_cred_home_sp(ctx, id, child);
+ else if (os_strcasecmp(name, "SubscriptionParameters") == 0)
+ set_pps_cred_sub_params(ctx, id, child);
+ else if (os_strcasecmp(name, "Credential") == 0)
+ set_pps_cred_credential(ctx, id, child, fqdn);
+ else
+ wpa_printf(MSG_INFO, "Unknown credential node '%s'",
+ name);
+ }
+}
+
+
+static void set_pps(struct hs20_osu_client *ctx, xml_node_t *pps,
+ const char *fqdn)
+{
+ xml_node_t *child;
+ const char *name;
+ int id;
+ char *update_identifier = NULL;
+
+ /*
+ * TODO: Could consider more complex mechanism that would remove
+ * credentials only if there are changes in the information sent to
+ * wpa_supplicant.
+ */
+ remove_sp_creds(ctx, fqdn);
+
+ xml_node_for_each_child(ctx->xml, child, pps) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ if (os_strcasecmp(name, "UpdateIdentifier") == 0) {
+ update_identifier = xml_node_get_text(ctx->xml, child);
+ if (update_identifier) {
+ wpa_printf(MSG_INFO, "- UpdateIdentifier = %s",
+ update_identifier);
+ break;
+ }
+ }
+ }
+
+ xml_node_for_each_child(ctx->xml, child, pps) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ if (os_strcasecmp(name, "UpdateIdentifier") == 0)
+ continue;
+ id = add_cred(ctx->ifname);
+ if (id < 0) {
+ wpa_printf(MSG_INFO, "Failed to add credential to wpa_supplicant");
+ write_summary(ctx, "Failed to add credential to wpa_supplicant");
+ break;
+ }
+ write_summary(ctx, "Add a credential to wpa_supplicant");
+ if (update_identifier &&
+ set_cred(ctx->ifname, id, "update_identifier",
+ update_identifier) < 0)
+ wpa_printf(MSG_INFO, "Failed to set update_identifier");
+ if (set_cred_quoted(ctx->ifname, id, "provisioning_sp", fqdn) <
+ 0)
+ wpa_printf(MSG_INFO, "Failed to set provisioning_sp");
+ wpa_printf(MSG_INFO, "credential localname: '%s'", name);
+ set_pps_credential(ctx, id, child, fqdn);
+ ctx->pps_cred_set = 1;
+ }
+
+ xml_node_get_text_free(ctx->xml, update_identifier);
+}
+
+
+void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname)
+{
+ xml_node_t *pps;
+ const char *fqdn;
+ char *fqdn_buf = NULL, *pos;
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
+ return;
+ }
+
+ fqdn = os_strstr(pps_fname, "SP/");
+ if (fqdn) {
+ fqdn_buf = os_strdup(fqdn + 3);
+ if (fqdn_buf == NULL)
+ return;
+ pos = os_strchr(fqdn_buf, '/');
+ if (pos)
+ *pos = '\0';
+ fqdn = fqdn_buf;
+ } else
+ fqdn = "wi-fi.org";
+
+ wpa_printf(MSG_INFO, "Set PPS MO info to wpa_supplicant - SP FQDN %s",
+ fqdn);
+ set_pps(ctx, pps, fqdn);
+
+ os_free(fqdn_buf);
+ xml_node_free(ctx->xml, pps);
+}
+
+
+static int cmd_get_fqdn(struct hs20_osu_client *ctx, const char *pps_fname)
+{
+ xml_node_t *pps, *node;
+ char *fqdn = NULL;
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
+ return -1;
+ }
+
+ node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
+ if (node)
+ fqdn = xml_node_get_text(ctx->xml, node);
+
+ xml_node_free(ctx->xml, pps);
+
+ if (fqdn) {
+ FILE *f = fopen("pps-fqdn", "w");
+ if (f) {
+ fprintf(f, "%s", fqdn);
+ fclose(f);
+ }
+ xml_node_get_text_free(ctx->xml, fqdn);
+ return 0;
+ }
+
+ xml_node_get_text_free(ctx->xml, fqdn);
+ return -1;
+}
+
+
+static void cmd_to_tnds(struct hs20_osu_client *ctx, const char *in_fname,
+ const char *out_fname, const char *urn, int use_path)
+{
+ xml_node_t *mo, *node;
+
+ mo = node_from_file(ctx->xml, in_fname);
+ if (mo == NULL) {
+ wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname);
+ return;
+ }
+
+ node = mo_to_tnds(ctx->xml, mo, use_path, urn, NULL);
+ if (node) {
+ node_to_file(ctx->xml, out_fname, node);
+ xml_node_free(ctx->xml, node);
+ }
+
+ xml_node_free(ctx->xml, mo);
+}
+
+
+static void cmd_from_tnds(struct hs20_osu_client *ctx, const char *in_fname,
+ const char *out_fname)
+{
+ xml_node_t *tnds, *mo;
+
+ tnds = node_from_file(ctx->xml, in_fname);
+ if (tnds == NULL) {
+ wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname);
+ return;
+ }
+
+ mo = tnds_to_mo(ctx->xml, tnds);
+ if (mo) {
+ node_to_file(ctx->xml, out_fname, mo);
+ xml_node_free(ctx->xml, mo);
+ }
+
+ xml_node_free(ctx->xml, tnds);
+}
+
+
+struct osu_icon {
+ int id;
+ char lang[4];
+ char mime_type[256];
+ char filename[256];
+};
+
+struct osu_data {
+ char bssid[20];
+ char url[256];
+ unsigned int methods;
+ char osu_ssid[33];
+ char osu_nai[256];
+ struct osu_lang_text friendly_name[MAX_OSU_VALS];
+ size_t friendly_name_count;
+ struct osu_lang_text serv_desc[MAX_OSU_VALS];
+ size_t serv_desc_count;
+ struct osu_icon icon[MAX_OSU_VALS];
+ size_t icon_count;
+};
+
+
+static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
+{
+ FILE *f;
+ char buf[1000];
+ struct osu_data *osu = NULL, *last = NULL;
+ size_t osu_count = 0;
+ char *pos, *end;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Could not open %s", fname);
+ return NULL;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ pos = strchr(buf, '\n');
+ if (pos)
+ *pos = '\0';
+
+ if (strncmp(buf, "OSU-PROVIDER ", 13) == 0) {
+ last = realloc(osu, (osu_count + 1) * sizeof(*osu));
+ if (last == NULL)
+ break;
+ osu = last;
+ last = &osu[osu_count++];
+ memset(last, 0, sizeof(*last));
+ snprintf(last->bssid, sizeof(last->bssid), "%s",
+ buf + 13);
+ continue;
+ }
+ if (!last)
+ continue;
+
+ if (strncmp(buf, "uri=", 4) == 0) {
+ snprintf(last->url, sizeof(last->url), "%s", buf + 4);
+ continue;
+ }
+
+ if (strncmp(buf, "methods=", 8) == 0) {
+ last->methods = strtol(buf + 8, NULL, 16);
+ continue;
+ }
+
+ if (strncmp(buf, "osu_ssid=", 9) == 0) {
+ snprintf(last->osu_ssid, sizeof(last->osu_ssid),
+ "%s", buf + 9);
+ continue;
+ }
+
+ if (os_strncmp(buf, "osu_nai=", 8) == 0) {
+ os_snprintf(last->osu_nai, sizeof(last->osu_nai),
+ "%s", buf + 8);
+ continue;
+ }
+
+ if (strncmp(buf, "friendly_name=", 14) == 0) {
+ struct osu_lang_text *txt;
+ if (last->friendly_name_count == MAX_OSU_VALS)
+ continue;
+ pos = strchr(buf + 14, ':');
+ if (pos == NULL)
+ continue;
+ *pos++ = '\0';
+ txt = &last->friendly_name[last->friendly_name_count++];
+ snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14);
+ snprintf(txt->text, sizeof(txt->text), "%s", pos);
+ }
+
+ if (strncmp(buf, "desc=", 5) == 0) {
+ struct osu_lang_text *txt;
+ if (last->serv_desc_count == MAX_OSU_VALS)
+ continue;
+ pos = strchr(buf + 5, ':');
+ if (pos == NULL)
+ continue;
+ *pos++ = '\0';
+ txt = &last->serv_desc[last->serv_desc_count++];
+ snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5);
+ snprintf(txt->text, sizeof(txt->text), "%s", pos);
+ }
+
+ if (strncmp(buf, "icon=", 5) == 0) {
+ struct osu_icon *icon;
+ if (last->icon_count == MAX_OSU_VALS)
+ continue;
+ icon = &last->icon[last->icon_count++];
+ icon->id = atoi(buf + 5);
+ pos = strchr(buf, ':');
+ if (pos == NULL)
+ continue;
+ pos = strchr(pos + 1, ':');
+ if (pos == NULL)
+ continue;
+ pos = strchr(pos + 1, ':');
+ if (pos == NULL)
+ continue;
+ pos++;
+ end = strchr(pos, ':');
+ if (!end)
+ continue;
+ *end = '\0';
+ snprintf(icon->lang, sizeof(icon->lang), "%s", pos);
+ pos = end + 1;
+
+ end = strchr(pos, ':');
+ if (end)
+ *end = '\0';
+ snprintf(icon->mime_type, sizeof(icon->mime_type),
+ "%s", pos);
+ if (!pos)
+ continue;
+ pos = end + 1;
+
+ end = strchr(pos, ':');
+ if (end)
+ *end = '\0';
+ snprintf(icon->filename, sizeof(icon->filename),
+ "%s", pos);
+ continue;
+ }
+ }
+
+ fclose(f);
+
+ *count = osu_count;
+ return osu;
+}
+
+
+static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
+ const char *ssid, const char *url,
+ unsigned int methods, int no_prod_assoc,
+ const char *osu_nai)
+{
+ int id;
+ const char *ifname = ctx->ifname;
+ char buf[200];
+ struct wpa_ctrl *mon;
+ int res;
+
+ id = add_network(ifname);
+ if (id < 0)
+ return -1;
+ if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
+ return -1;
+ 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 (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, "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 (set_network(ifname, id, "key_mgmt", "NONE") < 0)
+ return -1;
+ }
+
+ mon = open_wpa_mon(ifname);
+ if (mon == NULL)
+ return -1;
+
+ wpa_printf(MSG_INFO, "Associate with OSU SSID");
+ write_summary(ctx, "Associate with OSU SSID");
+ snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", id);
+ if (wpa_command(ifname, buf) < 0)
+ return -1;
+
+ res = get_wpa_cli_event(mon, "CTRL-EVENT-CONNECTED",
+ buf, sizeof(buf));
+
+ wpa_ctrl_detach(mon);
+ wpa_ctrl_close(mon);
+
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "Could not connect");
+ write_summary(ctx, "Could not connect to OSU network");
+ wpa_printf(MSG_INFO, "Remove OSU network connection");
+ snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
+ wpa_command(ifname, buf);
+ return -1;
+ }
+
+ write_summary(ctx, "Waiting for IP address for subscription registration");
+ if (wait_ip_addr(ifname, 15) < 0) {
+ wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
+ }
+
+ if (no_prod_assoc) {
+ if (res < 0)
+ return -1;
+ wpa_printf(MSG_INFO, "No production connection used for testing purposes");
+ write_summary(ctx, "No production connection used for testing purposes");
+ return 0;
+ }
+
+ ctx->no_reconnect = 1;
+ if (methods & 0x02)
+ res = cmd_prov(ctx, url);
+ else if (methods & 0x01)
+ res = cmd_oma_dm_prov(ctx, url);
+
+ wpa_printf(MSG_INFO, "Remove OSU network connection");
+ write_summary(ctx, "Remove OSU network connection");
+ snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
+ wpa_command(ifname, buf);
+
+ if (res < 0)
+ return -1;
+
+ wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
+ write_summary(ctx, "Requesting reconnection with updated configuration");
+ if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
+ wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
+ write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
+ int connect, int no_prod_assoc,
+ const char *friendly_name)
+{
+ char fname[255];
+ FILE *f;
+ struct osu_data *osu = NULL, *last = NULL;
+ size_t osu_count, i, j;
+ int ret;
+
+ write_summary(ctx, "OSU provider selection");
+
+ if (dir == NULL) {
+ wpa_printf(MSG_INFO, "Missing dir parameter to osu_select");
+ return -1;
+ }
+
+ snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir);
+ osu = parse_osu_providers(fname, &osu_count);
+ if (osu == NULL) {
+ wpa_printf(MSG_INFO, "Could not any OSU providers from %s",
+ fname);
+ write_result(ctx, "No OSU providers available");
+ return -1;
+ }
+
+ if (friendly_name) {
+ for (i = 0; i < osu_count; i++) {
+ last = &osu[i];
+ for (j = 0; j < last->friendly_name_count; j++) {
+ if (os_strcmp(last->friendly_name[j].text,
+ friendly_name) == 0)
+ break;
+ }
+ if (j < last->friendly_name_count)
+ break;
+ }
+ if (i == osu_count) {
+ wpa_printf(MSG_INFO, "Requested operator friendly name '%s' not found in the list of available providers",
+ friendly_name);
+ write_summary(ctx, "Requested operator friendly name '%s' not found in the list of available providers",
+ friendly_name);
+ free(osu);
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "OSU Provider selected based on requested operator friendly name '%s'",
+ friendly_name);
+ write_summary(ctx, "OSU Provider selected based on requested operator friendly name '%s'",
+ friendly_name);
+ ret = i + 1;
+ goto selected;
+ }
+
+ snprintf(fname, sizeof(fname), "%s/osu-providers.html", dir);
+ f = fopen(fname, "w");
+ if (f == NULL) {
+ wpa_printf(MSG_INFO, "Could not open %s", fname);
+ free(osu);
+ return -1;
+ }
+
+ fprintf(f, "<html><head>"
+ "<meta http-equiv=\"Content-type\" content=\"text/html; "
+ "charset=utf-8\"<title>Select service operator</title>"
+ "</head><body><h1>Select service operator</h1>\n");
+
+ if (osu_count == 0)
+ fprintf(f, "No online signup available\n");
+
+ for (i = 0; i < osu_count; i++) {
+ last = &osu[i];
+#ifdef ANDROID
+ fprintf(f, "<p>\n"
+ "<a href=\"http://localhost:12345/osu/%d\">"
+ "<table><tr><td>", (int) i + 1);
+#else /* ANDROID */
+ fprintf(f, "<p>\n"
+ "<a href=\"osu://%d\">"
+ "<table><tr><td>", (int) i + 1);
+#endif /* ANDROID */
+ for (j = 0; j < last->icon_count; j++) {
+ fprintf(f, "<img src=\"osu-icon-%d.%s\">\n",
+ last->icon[j].id,
+ strcasecmp(last->icon[j].mime_type,
+ "image/png") == 0 ? "png" : "icon");
+ }
+ fprintf(f, "<td>");
+ for (j = 0; j < last->friendly_name_count; j++) {
+ fprintf(f, "<small>[%s]</small> %s<br>\n",
+ last->friendly_name[j].lang,
+ last->friendly_name[j].text);
+ }
+ fprintf(f, "<tr><td colspan=2>");
+ for (j = 0; j < last->serv_desc_count; j++) {
+ fprintf(f, "<small>[%s]</small> %s<br>\n",
+ last->serv_desc[j].lang,
+ last->serv_desc[j].text);
+ }
+ fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
+ "SSID: %s<br>\n",
+ last->bssid, last->osu_ssid);
+ if (last->osu_nai)
+ fprintf(f, "NAI: %s<br>\n", last->osu_nai);
+ fprintf(f, "URL: %s<br>\n"
+ "methods:%s%s<br>\n"
+ "</small></p>\n",
+ last->url,
+ last->methods & 0x01 ? " OMA-DM" : "",
+ last->methods & 0x02 ? " SOAP-XML-SPP" : "");
+ }
+
+ fprintf(f, "</body></html>\n");
+
+ fclose(f);
+
+ snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
+ write_summary(ctx, "Start web browser with OSU provider selection page");
+ ret = hs20_web_browser(fname);
+
+selected:
+ if (ret > 0 && (size_t) ret <= osu_count) {
+ char *data;
+ size_t data_len;
+
+ wpa_printf(MSG_INFO, "Selected OSU id=%d", ret);
+ last = &osu[ret - 1];
+ ret = 0;
+ wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
+ wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
+ 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);
+
+ ctx->friendly_name_count = last->friendly_name_count;
+ for (j = 0; j < last->friendly_name_count; j++) {
+ wpa_printf(MSG_INFO, "FRIENDLY_NAME: [%s]%s",
+ last->friendly_name[j].lang,
+ last->friendly_name[j].text);
+ os_strlcpy(ctx->friendly_name[j].lang,
+ last->friendly_name[j].lang,
+ sizeof(ctx->friendly_name[j].lang));
+ os_strlcpy(ctx->friendly_name[j].text,
+ last->friendly_name[j].text,
+ sizeof(ctx->friendly_name[j].text));
+ }
+
+ ctx->icon_count = last->icon_count;
+ for (j = 0; j < last->icon_count; j++) {
+ char fname[256];
+
+ os_snprintf(fname, sizeof(fname), "%s/osu-icon-%d.%s",
+ dir, last->icon[j].id,
+ strcasecmp(last->icon[j].mime_type,
+ "image/png") == 0 ?
+ "png" : "icon");
+ wpa_printf(MSG_INFO, "ICON: %s (%s)",
+ fname, last->icon[j].filename);
+ os_strlcpy(ctx->icon_filename[j],
+ last->icon[j].filename,
+ sizeof(ctx->icon_filename[j]));
+
+ data = os_readfile(fname, &data_len);
+ if (data) {
+ sha256_vector(1, (const u8 **) &data, &data_len,
+ ctx->icon_hash[j]);
+ os_free(data);
+ }
+ }
+
+ if (connect == 2) {
+ if (last->methods & 0x02)
+ ret = cmd_prov(ctx, last->url);
+ else if (last->methods & 0x01)
+ ret = cmd_oma_dm_prov(ctx, last->url);
+ else
+ ret = -1;
+ } else if (connect)
+ ret = osu_connect(ctx, last->bssid, last->osu_ssid,
+ last->url, last->methods,
+ no_prod_assoc, last->osu_nai);
+ } else
+ ret = -1;
+
+ free(osu);
+
+ return ret;
+}
+
+
+static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
+ const char *friendly_name)
+{
+ char dir[255];
+ char fname[300], buf[400];
+ struct wpa_ctrl *mon;
+ const char *ifname;
+ int res;
+
+ ifname = ctx->ifname;
+
+ if (getcwd(dir, sizeof(dir)) == NULL)
+ return -1;
+
+ snprintf(fname, sizeof(fname), "%s/osu-info", dir);
+ if (mkdir(fname, S_IRWXU | S_IRWXG) < 0 && errno != EEXIST) {
+ wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
+ fname, strerror(errno));
+ return -1;
+ }
+
+ 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");
+ return -1;
+ }
+
+ mon = open_wpa_mon(ifname);
+ if (mon == NULL)
+ return -1;
+
+ wpa_printf(MSG_INFO, "Starting OSU fetch");
+ write_summary(ctx, "Starting OSU provider information fetch");
+ if (wpa_command(ifname, "FETCH_OSU") < 0) {
+ wpa_printf(MSG_INFO, "Could not start OSU fetch");
+ wpa_ctrl_detach(mon);
+ wpa_ctrl_close(mon);
+ return -1;
+ }
+ res = get_wpa_cli_event(mon, "OSU provider fetch completed",
+ buf, sizeof(buf));
+
+ wpa_ctrl_detach(mon);
+ wpa_ctrl_close(mon);
+
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "OSU fetch did not complete");
+ write_summary(ctx, "OSU fetch did not complete");
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "OSU provider fetch completed");
+
+ return cmd_osu_select(ctx, fname, 1, no_prod_assoc, friendly_name);
+}
+
+
+static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname, const char *ca_fname)
+{
+ xml_node_t *pps, *node;
+ char pps_fname_buf[300];
+ char ca_fname_buf[200];
+ char *cred_username = NULL;
+ char *cred_password = NULL;
+ char *sub_rem_uri = NULL;
+ char client_cert_buf[200];
+ char *client_cert = NULL;
+ char client_key_buf[200];
+ char *client_key = NULL;
+ int spp;
+
+ wpa_printf(MSG_INFO, "Subscription remediation requested with Server URL: %s",
+ 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) {
+ wpa_printf(MSG_INFO, "Use requested FQDN from command line");
+ os_snprintf(buf, sizeof(buf), "%s", address + 5);
+ address = NULL;
+ } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
+ sizeof(buf)) < 0) {
+ wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
+ return -1;
+ }
+ os_free(ctx->fqdn);
+ ctx->fqdn = os_strdup(buf);
+ if (ctx->fqdn == NULL)
+ return -1;
+ wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
+ buf);
+ os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
+ "SP/%s/pps.xml", ctx->fqdn);
+ pps_fname = pps_fname_buf;
+
+ os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem",
+ ctx->fqdn);
+ ca_fname = ca_fname_buf;
+ }
+
+ if (!os_file_exists(pps_fname)) {
+ wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
+ pps_fname);
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
+
+ if (ca_fname && !os_file_exists(ca_fname)) {
+ wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
+ ca_fname);
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
+ ctx->ca_fname = ca_fname;
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "Could not read PPS MO");
+ return -1;
+ }
+
+ if (!ctx->fqdn) {
+ char *tmp;
+ node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
+ return -1;
+ }
+ tmp = xml_node_get_text(ctx->xml, node);
+ if (tmp == NULL) {
+ wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
+ return -1;
+ }
+ ctx->fqdn = os_strdup(tmp);
+ xml_node_get_text_free(ctx->xml, tmp);
+ if (!ctx->fqdn) {
+ wpa_printf(MSG_INFO, "No FQDN known");
+ return -1;
+ }
+ }
+
+ node = get_child_node(ctx->xml, pps,
+ "SubscriptionUpdate/UpdateMethod");
+ if (node) {
+ char *tmp;
+ tmp = xml_node_get_text(ctx->xml, node);
+ if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0)
+ spp = 0;
+ else
+ spp = 1;
+ } else {
+ wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP");
+ spp = 1;
+ }
+
+ get_user_pw(ctx, pps, "SubscriptionUpdate/UsernamePassword",
+ &cred_username, &cred_password);
+ if (cred_username)
+ wpa_printf(MSG_INFO, "Using username: %s", cred_username);
+ if (cred_password)
+ wpa_printf(MSG_DEBUG, "Using password: %s", cred_password);
+
+ if (cred_username == NULL && cred_password == NULL &&
+ get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) {
+ wpa_printf(MSG_INFO, "Using client certificate");
+ os_snprintf(client_cert_buf, sizeof(client_cert_buf),
+ "SP/%s/client-cert.pem", ctx->fqdn);
+ client_cert = client_cert_buf;
+ os_snprintf(client_key_buf, sizeof(client_key_buf),
+ "SP/%s/client-key.pem", ctx->fqdn);
+ client_key = client_key_buf;
+ ctx->client_cert_present = 1;
+ }
+
+ node = get_child_node(ctx->xml, pps, "SubscriptionUpdate/URI");
+ if (node) {
+ sub_rem_uri = xml_node_get_text(ctx->xml, node);
+ if (sub_rem_uri &&
+ (!address || os_strcmp(address, sub_rem_uri) != 0)) {
+ wpa_printf(MSG_INFO, "Override sub rem URI based on PPS: %s",
+ sub_rem_uri);
+ address = sub_rem_uri;
+ }
+ }
+ if (!address) {
+ wpa_printf(MSG_INFO, "Server URL not known");
+ return -1;
+ }
+
+ write_summary(ctx, "Wait for IP address for subscriptiom remediation");
+ wpa_printf(MSG_INFO, "Wait for IP address before starting subscription remediation");
+
+ if (wait_ip_addr(ctx->ifname, 15) < 0) {
+ wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
+ }
+
+ if (spp)
+ spp_sub_rem(ctx, address, pps_fname,
+ client_cert, client_key,
+ cred_username, cred_password, pps);
+ else
+ oma_dm_sub_rem(ctx, address, pps_fname,
+ client_cert, client_key,
+ cred_username, cred_password, pps);
+
+ xml_node_get_text_free(ctx->xml, sub_rem_uri);
+ xml_node_get_text_free(ctx->xml, cred_username);
+ str_clear_free(cred_password);
+ xml_node_free(ctx->xml, pps);
+ return 0;
+}
+
+
+static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname, const char *ca_fname)
+{
+ xml_node_t *pps;
+ xml_node_t *node;
+ char pps_fname_buf[300];
+ char ca_fname_buf[200];
+ char *uri = NULL;
+ char *cred_username = NULL;
+ char *cred_password = NULL;
+ char client_cert_buf[200];
+ char *client_cert = NULL;
+ char client_key_buf[200];
+ char *client_key = NULL;
+ int spp;
+
+ wpa_printf(MSG_INFO, "Policy update requested");
+
+ 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) {
+ wpa_printf(MSG_INFO, "Use requested FQDN from command line");
+ os_snprintf(buf, sizeof(buf), "%s", address + 5);
+ address = NULL;
+ } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
+ sizeof(buf)) < 0) {
+ wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
+ return -1;
+ }
+ os_free(ctx->fqdn);
+ ctx->fqdn = os_strdup(buf);
+ if (ctx->fqdn == NULL)
+ return -1;
+ wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
+ buf);
+ os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
+ "SP/%s/pps.xml", ctx->fqdn);
+ pps_fname = pps_fname_buf;
+
+ os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem",
+ buf);
+ ca_fname = ca_fname_buf;
+ }
+
+ if (!os_file_exists(pps_fname)) {
+ wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
+ pps_fname);
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
+
+ if (ca_fname && !os_file_exists(ca_fname)) {
+ wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
+ ca_fname);
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
+ ctx->ca_fname = ca_fname;
+
+ pps = node_from_file(ctx->xml, pps_fname);
+ if (pps == NULL) {
+ wpa_printf(MSG_INFO, "Could not read PPS MO");
+ return -1;
+ }
+
+ if (!ctx->fqdn) {
+ char *tmp;
+ node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
+ if (node == NULL) {
+ wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
+ return -1;
+ }
+ tmp = xml_node_get_text(ctx->xml, node);
+ if (tmp == NULL) {
+ wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
+ return -1;
+ }
+ ctx->fqdn = os_strdup(tmp);
+ xml_node_get_text_free(ctx->xml, tmp);
+ if (!ctx->fqdn) {
+ wpa_printf(MSG_INFO, "No FQDN known");
+ return -1;
+ }
+ }
+
+ node = get_child_node(ctx->xml, pps,
+ "Policy/PolicyUpdate/UpdateMethod");
+ if (node) {
+ char *tmp;
+ tmp = xml_node_get_text(ctx->xml, node);
+ if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0)
+ spp = 0;
+ else
+ spp = 1;
+ } else {
+ wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP");
+ spp = 1;
+ }
+
+ get_user_pw(ctx, pps, "Policy/PolicyUpdate/UsernamePassword",
+ &cred_username, &cred_password);
+ if (cred_username)
+ wpa_printf(MSG_INFO, "Using username: %s", cred_username);
+ if (cred_password)
+ wpa_printf(MSG_DEBUG, "Using password: %s", cred_password);
+
+ if (cred_username == NULL && cred_password == NULL &&
+ get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) {
+ wpa_printf(MSG_INFO, "Using client certificate");
+ os_snprintf(client_cert_buf, sizeof(client_cert_buf),
+ "SP/%s/client-cert.pem", ctx->fqdn);
+ client_cert = client_cert_buf;
+ os_snprintf(client_key_buf, sizeof(client_key_buf),
+ "SP/%s/client-key.pem", ctx->fqdn);
+ client_key = client_key_buf;
+ }
+
+ if (!address) {
+ node = get_child_node(ctx->xml, pps, "Policy/PolicyUpdate/URI");
+ if (node) {
+ uri = xml_node_get_text(ctx->xml, node);
+ wpa_printf(MSG_INFO, "URI based on PPS: %s", uri);
+ address = uri;
+ }
+ }
+ if (!address) {
+ wpa_printf(MSG_INFO, "Server URL not known");
+ return -1;
+ }
+
+ if (spp)
+ spp_pol_upd(ctx, address, pps_fname,
+ client_cert, client_key,
+ cred_username, cred_password, pps);
+ else
+ oma_dm_pol_upd(ctx, address, pps_fname,
+ client_cert, client_key,
+ cred_username, cred_password, pps);
+
+ xml_node_get_text_free(ctx->xml, uri);
+ xml_node_get_text_free(ctx->xml, cred_username);
+ str_clear_free(cred_password);
+ xml_node_free(ctx->xml, pps);
+
+ return 0;
+}
+
+
+static char * get_hostname(const char *url)
+{
+ const char *pos, *end, *end2;
+ char *ret;
+
+ if (url == NULL)
+ return NULL;
+
+ pos = os_strchr(url, '/');
+ if (pos == NULL)
+ return NULL;
+ pos++;
+ if (*pos != '/')
+ return NULL;
+ pos++;
+
+ end = os_strchr(pos, '/');
+ end2 = os_strchr(pos, ':');
+ if (end && end2 && end2 < end)
+ end = end2;
+ if (end)
+ end--;
+ else {
+ end = pos;
+ while (*end)
+ end++;
+ if (end > pos)
+ end--;
+ }
+
+ ret = os_malloc(end - pos + 2);
+ if (ret == NULL)
+ return NULL;
+
+ os_memcpy(ret, pos, end - pos + 1);
+ ret[end - pos + 1] = '\0';
+
+ return ret;
+}
+
+
+static int osu_cert_cb(void *_ctx, struct http_cert *cert)
+{
+ struct hs20_osu_client *ctx = _ctx;
+ unsigned int i, j;
+ int found;
+ char *host = NULL;
+
+ wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d)",
+ !ctx->no_osu_cert_validation);
+
+ host = get_hostname(ctx->server_url);
+
+ for (i = 0; i < ctx->server_dnsname_count; i++)
+ os_free(ctx->server_dnsname[i]);
+ os_free(ctx->server_dnsname);
+ ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *));
+ ctx->server_dnsname_count = 0;
+
+ found = 0;
+ for (i = 0; i < cert->num_dnsname; i++) {
+ if (ctx->server_dnsname) {
+ ctx->server_dnsname[ctx->server_dnsname_count] =
+ os_strdup(cert->dnsname[i]);
+ if (ctx->server_dnsname[ctx->server_dnsname_count])
+ ctx->server_dnsname_count++;
+ }
+ if (host && os_strcasecmp(host, cert->dnsname[i]) == 0)
+ found = 1;
+ wpa_printf(MSG_INFO, "dNSName '%s'", cert->dnsname[i]);
+ }
+
+ if (host && !found) {
+ wpa_printf(MSG_INFO, "Server name from URL (%s) did not match any dNSName - abort connection",
+ host);
+ write_result(ctx, "Server name from URL (%s) did not match any dNSName - abort connection",
+ host);
+ os_free(host);
+ return -1;
+ }
+
+ os_free(host);
+
+ for (i = 0; i < cert->num_othername; i++) {
+ if (os_strcmp(cert->othername[i].oid,
+ "1.3.6.1.4.1.40808.1.1.1") == 0) {
+ wpa_hexdump_ascii(MSG_INFO,
+ "id-wfa-hotspot-friendlyName",
+ cert->othername[i].data,
+ cert->othername[i].len);
+ }
+ }
+
+ for (j = 0; !ctx->no_osu_cert_validation &&
+ j < ctx->friendly_name_count; j++) {
+ int found = 0;
+ for (i = 0; i < cert->num_othername; i++) {
+ if (os_strcmp(cert->othername[i].oid,
+ "1.3.6.1.4.1.40808.1.1.1") != 0)
+ continue;
+ if (cert->othername[i].len < 3)
+ continue;
+ if (os_strncasecmp((char *) cert->othername[i].data,
+ ctx->friendly_name[j].lang, 3) != 0)
+ continue;
+ if (os_strncmp((char *) cert->othername[i].data + 3,
+ ctx->friendly_name[j].text,
+ cert->othername[i].len - 3) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ wpa_printf(MSG_INFO, "No friendly name match found for '[%s]%s'",
+ ctx->friendly_name[j].lang,
+ ctx->friendly_name[j].text);
+ write_result(ctx, "No friendly name match found for '[%s]%s'",
+ ctx->friendly_name[j].lang,
+ ctx->friendly_name[j].text);
+ return -1;
+ }
+ }
+
+ for (i = 0; i < cert->num_logo; i++) {
+ struct http_logo *logo = &cert->logo[i];
+
+ wpa_printf(MSG_INFO, "logo hash alg %s uri '%s'",
+ logo->alg_oid, logo->uri);
+ wpa_hexdump_ascii(MSG_INFO, "hashValue",
+ logo->hash, logo->hash_len);
+ }
+
+ for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
+ int found = 0;
+ char *name = ctx->icon_filename[j];
+ size_t name_len = os_strlen(name);
+
+ wpa_printf(MSG_INFO, "Looking for icon file name '%s' match",
+ name);
+ for (i = 0; i < cert->num_logo; i++) {
+ struct http_logo *logo = &cert->logo[i];
+ size_t uri_len = os_strlen(logo->uri);
+ char *pos;
+
+ wpa_printf(MSG_INFO, "Comparing to '%s' uri_len=%d name_len=%d",
+ logo->uri, (int) uri_len, (int) name_len);
+ if (uri_len < 1 + name_len)
+ continue;
+ pos = &logo->uri[uri_len - name_len - 1];
+ if (*pos != '/')
+ continue;
+ pos++;
+ if (os_strcmp(pos, name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ wpa_printf(MSG_INFO, "No icon filename match found for '%s'",
+ name);
+ write_result(ctx,
+ "No icon filename match found for '%s'",
+ name);
+ return -1;
+ }
+ }
+
+ for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
+ int found = 0;
+
+ for (i = 0; i < cert->num_logo; i++) {
+ struct http_logo *logo = &cert->logo[i];
+
+ if (logo->hash_len != 32)
+ continue;
+ if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ wpa_printf(MSG_INFO, "No icon hash match found");
+ write_result(ctx, "No icon hash match found");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int init_ctx(struct hs20_osu_client *ctx)
+{
+ xml_node_t *devinfo, *devid;
+
+ os_memset(ctx, 0, sizeof(*ctx));
+ ctx->ifname = "wlan0";
+ ctx->xml = xml_node_init_ctx(ctx, NULL);
+ if (ctx->xml == NULL)
+ 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);
+ }
+ }
+ xml_node_free(ctx->xml, devinfo);
+
+ if (ctx->devid == NULL) {
+ wpa_printf(MSG_ERROR, "Could not fetch DevId from devinfo.xml");
+ return -1;
+ }
+
+ ctx->http = http_init_ctx(ctx, ctx->xml);
+ if (ctx->http == NULL) {
+ xml_node_deinit_ctx(ctx->xml);
+ return -1;
+ }
+ http_ocsp_set(ctx->http, 2);
+ http_set_cert_cb(ctx->http, osu_cert_cb, ctx);
+
+ return 0;
+}
+
+
+static void deinit_ctx(struct hs20_osu_client *ctx)
+{
+ size_t i;
+
+ http_deinit_ctx(ctx->http);
+ xml_node_deinit_ctx(ctx->xml);
+ os_free(ctx->fqdn);
+ os_free(ctx->server_url);
+ os_free(ctx->devid);
+
+ for (i = 0; i < ctx->server_dnsname_count; i++)
+ os_free(ctx->server_dnsname[i]);
+ os_free(ctx->server_dnsname);
+}
+
+
+static void check_workarounds(struct hs20_osu_client *ctx)
+{
+ FILE *f;
+ char buf[100];
+ unsigned long int val = 0;
+
+ f = fopen("hs20-osu-client.workarounds", "r");
+ if (f == NULL)
+ return;
+
+ if (fgets(buf, sizeof(buf), f))
+ val = strtoul(buf, NULL, 16);
+
+ fclose(f);
+
+ if (val) {
+ wpa_printf(MSG_INFO, "Workarounds enabled: 0x%lx", val);
+ ctx->workarounds = val;
+ if (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL)
+ http_ocsp_set(ctx->http, 1);
+ }
+}
+
+
+static void usage(void)
+{
+ printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
+ " [-w<wpa_supplicant ctrl_iface dir>] "
+ "[-r<result file>] [-f<debug file>] \\\n"
+ " [-s<summary file>] \\\n"
+ " <command> [arguments..]\n"
+ "commands:\n"
+ "- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n"
+ "- to_tnds2 <XML MO> <XML MO in TNDS format (Path) "
+ "[URN]>\n"
+ "- from_tnds <XML MO in TNDS format> <XML MO>\n"
+ "- set_pps <PerProviderSubscription XML file name>\n"
+ "- get_fqdn <PerProviderSubscription XML file name>\n"
+ "- pol_upd [Server URL] [PPS] [CA cert]\n"
+ "- sub_rem <Server URL> [PPS] [CA cert]\n"
+ "- prov <Server URL> [CA cert]\n"
+ "- oma_dm_prov <Server URL> [CA cert]\n"
+ "- sim_prov <Server URL> [CA cert]\n"
+ "- oma_dm_sim_prov <Server URL> [CA cert]\n"
+ "- signup [CA cert]\n"
+ "- dl_osu_ca <PPS> <CA file>\n"
+ "- dl_polupd_ca <PPS> <CA file>\n"
+ "- dl_aaa_ca <PPS> <CA file>\n"
+ "- browser <URL>\n"
+ "- parse_cert <X.509 certificate (DER)>\n"
+ "- osu_select <OSU info directory> [CA cert]\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct hs20_osu_client ctx;
+ int c;
+ int ret = 0;
+ int no_prod_assoc = 0;
+ const char *friendly_name = NULL;
+ const char *wpa_debug_file_path = NULL;
+ extern char *wpas_ctrl_path;
+ extern int wpa_debug_level;
+ extern int wpa_debug_show_keys;
+ extern int wpa_debug_timestamp;
+
+ if (init_ctx(&ctx) < 0)
+ return -1;
+
+ for (;;) {
+ c = getopt(argc, argv, "df:hi:KNO:qr:s:S:tw:");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'd':
+ if (wpa_debug_level > 0)
+ wpa_debug_level--;
+ break;
+ case 'f':
+ wpa_debug_file_path = optarg;
+ break;
+ case 'K':
+ wpa_debug_show_keys++;
+ break;
+ case 'N':
+ no_prod_assoc = 1;
+ break;
+ case 'O':
+ friendly_name = optarg;
+ break;
+ case 'q':
+ wpa_debug_level++;
+ break;
+ case 'r':
+ ctx.result_file = optarg;
+ break;
+ case 's':
+ ctx.summary_file = optarg;
+ break;
+ case 'S':
+ ctx.ifname = optarg;
+ break;
+ case 't':
+ wpa_debug_timestamp++;
+ break;
+ case 'w':
+ wpas_ctrl_path = optarg;
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ break;
+ }
+ }
+
+ if (argc - optind < 1) {
+ usage();
+ exit(0);
+ }
+
+ wpa_debug_open_file(wpa_debug_file_path);
+
+#ifdef __linux__
+ setlinebuf(stdout);
+#endif /* __linux__ */
+
+ if (ctx.result_file)
+ unlink(ctx.result_file);
+ wpa_printf(MSG_DEBUG, "===[hs20-osu-client START - command: %s ]======"
+ "================", argv[optind]);
+ check_workarounds(&ctx);
+
+ if (strcmp(argv[optind], "to_tnds") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2],
+ argc > optind + 3 ? argv[optind + 3] : NULL,
+ 0);
+ } else if (strcmp(argv[optind], "to_tnds2") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2],
+ argc > optind + 3 ? argv[optind + 3] : NULL,
+ 1);
+ } else if (strcmp(argv[optind], "from_tnds") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_from_tnds(&ctx, argv[optind + 1], argv[optind + 2]);
+ } else if (strcmp(argv[optind], "sub_rem") == 0) {
+ if (argc - optind < 2) {
+ 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);
+ } 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,
+ argc > optind + 2 ? argv[optind + 2] : NULL,
+ argc > optind + 3 ? argv[optind + 3] : NULL);
+ } else if (strcmp(argv[optind], "prov") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ ctx.ca_fname = argv[optind + 2];
+ cmd_prov(&ctx, argv[optind + 1]);
+ } else if (strcmp(argv[optind], "sim_prov") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ ctx.ca_fname = argv[optind + 2];
+ cmd_sim_prov(&ctx, argv[optind + 1]);
+ } else if (strcmp(argv[optind], "dl_osu_ca") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_dl_osu_ca(&ctx, argv[optind + 1], argv[optind + 2]);
+ } else if (strcmp(argv[optind], "dl_polupd_ca") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_dl_polupd_ca(&ctx, argv[optind + 1], argv[optind + 2]);
+ } else if (strcmp(argv[optind], "dl_aaa_ca") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_dl_aaa_ca(&ctx, argv[optind + 1], argv[optind + 2]);
+ } else if (strcmp(argv[optind], "osu_select") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ ctx.ca_fname = argc > optind + 2 ? argv[optind + 2] : NULL;
+ cmd_osu_select(&ctx, argv[optind + 1], 2, 1, NULL);
+ } else if (strcmp(argv[optind], "signup") == 0) {
+ ctx.ca_fname = argc > optind + 1 ? argv[optind + 1] : NULL;
+ ret = cmd_signup(&ctx, no_prod_assoc, friendly_name);
+ } else if (strcmp(argv[optind], "set_pps") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_set_pps(&ctx, argv[optind + 1]);
+ } else if (strcmp(argv[optind], "get_fqdn") == 0) {
+ if (argc - optind < 1) {
+ usage();
+ exit(0);
+ }
+ ret = cmd_get_fqdn(&ctx, argv[optind + 1]);
+ } else if (strcmp(argv[optind], "oma_dm_prov") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ ctx.ca_fname = argv[optind + 2];
+ cmd_oma_dm_prov(&ctx, argv[optind + 1]);
+ } else if (strcmp(argv[optind], "oma_dm_sim_prov") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ ctx.ca_fname = argv[optind + 2];
+ if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1]) < 0) {
+ write_summary(&ctx, "Failed to complete OMA DM SIM provisioning");
+ return -1;
+ }
+ } else if (strcmp(argv[optind], "oma_dm_add") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_oma_dm_add(&ctx, argv[optind + 1], argv[optind + 2]);
+ } else if (strcmp(argv[optind], "oma_dm_replace") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ cmd_oma_dm_replace(&ctx, argv[optind + 1], argv[optind + 2]);
+ } else if (strcmp(argv[optind], "est_csr") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+ mkdir("Cert", S_IRWXU);
+ est_build_csr(&ctx, argv[optind + 1]);
+ } else if (strcmp(argv[optind], "browser") == 0) {
+ int ret;
+
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+
+ wpa_printf(MSG_INFO, "Launch web browser to URL %s",
+ argv[optind + 1]);
+ ret = hs20_web_browser(argv[optind + 1]);
+ wpa_printf(MSG_INFO, "Web browser result: %d", ret);
+ } else if (strcmp(argv[optind], "parse_cert") == 0) {
+ if (argc - optind < 2) {
+ usage();
+ exit(0);
+ }
+
+ wpa_debug_level = MSG_MSGDUMP;
+ http_parse_x509_certificate(ctx.http, argv[optind + 1]);
+ wpa_debug_level = MSG_INFO;
+ } else {
+ wpa_printf(MSG_INFO, "Unknown command '%s'", argv[optind]);
+ }
+
+ deinit_ctx(&ctx);
+ wpa_printf(MSG_DEBUG,
+ "===[hs20-osu-client END ]======================");
+
+ wpa_debug_close_file();
+
+ return ret;
+}
diff --git a/contrib/wpa/hs20/client/osu_client.h b/contrib/wpa/hs20/client/osu_client.h
new file mode 100644
index 0000000..9a7059e
--- /dev/null
+++ b/contrib/wpa/hs20/client/osu_client.h
@@ -0,0 +1,118 @@
+/*
+ * Hotspot 2.0 - OSU client
+ * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OSU_CLIENT_H
+#define OSU_CLIENT_H
+
+#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
+
+#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
+#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
+#define URN_HS20_DEVDETAIL_EXT "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0"
+#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
+
+
+#define MAX_OSU_VALS 10
+
+struct osu_lang_text {
+ char lang[4];
+ char text[253];
+};
+
+struct hs20_osu_client {
+ struct xml_node_ctx *xml;
+ struct http_ctx *http;
+ int no_reconnect;
+ char pps_fname[300];
+ char *devid;
+ const char *result_file;
+ const char *summary_file;
+ const char *ifname;
+ const char *ca_fname;
+ int no_osu_cert_validation; /* for EST operations */
+ char *fqdn;
+ char *server_url;
+ struct osu_lang_text friendly_name[MAX_OSU_VALS];
+ size_t friendly_name_count;
+ size_t icon_count;
+ char icon_filename[MAX_OSU_VALS][256];
+ u8 icon_hash[MAX_OSU_VALS][32];
+ int pps_cred_set;
+ int pps_updated;
+ int client_cert_present;
+ char **server_dnsname;
+ size_t server_dnsname_count;
+#define WORKAROUND_OCSP_OPTIONAL 0x00000001
+ unsigned long int workarounds;
+};
+
+
+/* osu_client.c */
+
+void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+void debug_dump_node(struct hs20_osu_client *ctx, const char *title,
+ xml_node_t *node);
+int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert);
+int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
+ xml_node_t *add_mo, char *fname, size_t fname_len);
+void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps,
+ const char *alt_loc, char **user, char **pw);
+int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
+ xml_node_t *pps);
+void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname);
+
+
+/* spp_client.c */
+
+void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps);
+void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps);
+int cmd_prov(struct hs20_osu_client *ctx, const char *url);
+int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url);
+
+
+/* oma_dm_client.c */
+
+int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url);
+int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url);
+void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps);
+void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps);
+void cmd_oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname);
+void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
+ const char *add_fname);
+void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
+ const char *replace_fname);
+
+/* est.c */
+
+int est_load_cacerts(struct hs20_osu_client *ctx, const char *url);
+int est_build_csr(struct hs20_osu_client *ctx, const char *url);
+int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
+ const char *user, const char *pw);
+
+#endif /* OSU_CLIENT_H */
diff --git a/contrib/wpa/hs20/client/spp_client.c b/contrib/wpa/hs20/client/spp_client.c
new file mode 100644
index 0000000..302a050
--- /dev/null
+++ b/contrib/wpa/hs20/client/spp_client.c
@@ -0,0 +1,995 @@
+/*
+ * Hotspot 2.0 SPP client
+ * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/stat.h>
+
+#include "common.h"
+#include "browser.h"
+#include "wpa_ctrl.h"
+#include "wpa_helpers.h"
+#include "xml-utils.h"
+#include "http-utils.h"
+#include "utils/base64.h"
+#include "crypto/crypto.h"
+#include "crypto/sha256.h"
+#include "osu_client.h"
+
+
+static int hs20_spp_update_response(struct hs20_osu_client *ctx,
+ const char *session_id,
+ const char *spp_status,
+ const char *error_code);
+static void hs20_policy_update_complete(
+ struct hs20_osu_client *ctx, const char *pps_fname);
+
+
+static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
+ char *attr_name)
+{
+ return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
+}
+
+
+static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
+ const char *expected_name)
+{
+ struct xml_node_ctx *xctx = ctx->xml;
+ const char *name;
+ char *err;
+ int ret;
+
+ if (!xml_node_is_element(xctx, node))
+ return -1;
+
+ name = xml_node_get_localname(xctx, node);
+ if (name == NULL)
+ return -1;
+
+ if (strcmp(expected_name, name) != 0) {
+ wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
+ name, expected_name);
+ write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
+ name, expected_name);
+ return -1;
+ }
+
+ ret = xml_validate(xctx, node, "spp.xsd", &err);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
+ write_summary(ctx, "SPP XML schema validation failed");
+ os_free(err);
+ }
+ return ret;
+}
+
+
+static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
+ xml_node_t *parent, const char *urn,
+ const char *fname)
+{
+ xml_node_t *node;
+ xml_node_t *fnode, *tnds;
+ char *str;
+
+ fnode = node_from_file(ctx, fname);
+ if (!fnode)
+ return;
+ tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
+ xml_node_free(ctx, fnode);
+ if (!tnds)
+ return;
+
+ str = xml_node_to_str(ctx, tnds);
+ xml_node_free(ctx, tnds);
+ if (str == NULL)
+ return;
+
+ node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
+ if (node)
+ xml_node_add_attr(ctx, node, ns, "moURN", urn);
+ os_free(str);
+}
+
+
+static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
+ xml_namespace_t **ret_ns,
+ const char *session_id,
+ const char *reason)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node;
+
+ write_summary(ctx, "Building sppPostDevData requestReason='%s'",
+ reason);
+ spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
+ "sppPostDevData");
+ if (spp_node == NULL)
+ return NULL;
+ if (ret_ns)
+ *ret_ns = ns;
+
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
+ xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
+ if (session_id)
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
+ session_id);
+ xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
+ "http://localhost:12345/");
+
+ xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
+ "1.0");
+ xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
+ URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
+ URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
+
+ add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
+ "devinfo.xml");
+ add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
+ "devdetail.xml");
+
+ return spp_node;
+}
+
+
+static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
+ xml_node_t *update)
+{
+ xml_node_t *node, *parent, *tnds, *unode;
+ char *str;
+ const char *name;
+ char *uri, *pos;
+ char *cdata, *cdata_end;
+ size_t fqdn_len;
+
+ wpa_printf(MSG_INFO, "Processing updateNode");
+ debug_dump_node(ctx, "updateNode", update);
+
+ uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
+ if (uri == NULL) {
+ wpa_printf(MSG_INFO, "No managementTreeURI present");
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
+
+ name = os_strrchr(uri, '/');
+ if (name == NULL) {
+ wpa_printf(MSG_INFO, "Unexpected URI");
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+ name++;
+ wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
+
+ str = xml_node_get_text(ctx->xml, update);
+ if (str == NULL) {
+ wpa_printf(MSG_INFO, "Could not extract MO text");
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
+ cdata = strstr(str, "<![CDATA[");
+ cdata_end = strstr(str, "]]>");
+ if (cdata && cdata_end && cdata_end > cdata &&
+ cdata < strstr(str, "MgmtTree") &&
+ cdata_end > strstr(str, "/MgmtTree")) {
+ char *tmp;
+ wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
+ tmp = strdup(cdata + 9);
+ if (tmp) {
+ cdata_end = strstr(tmp, "]]>");
+ if (cdata_end)
+ *cdata_end = '\0';
+ wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
+ tmp);
+ tnds = xml_node_from_buf(ctx->xml, tmp);
+ free(tmp);
+ } else
+ tnds = NULL;
+ } else
+ tnds = xml_node_from_buf(ctx->xml, str);
+ xml_node_get_text_free(ctx->xml, str);
+ if (tnds == NULL) {
+ wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+
+ unode = tnds_to_mo(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (unode == NULL) {
+ wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+
+ debug_dump_node(ctx, "Parsed TNDS", unode);
+
+ if (get_node_uri(ctx->xml, unode, name) == NULL) {
+ wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
+ xml_node_free(ctx->xml, unode);
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+
+ if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
+ wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
+ xml_node_free(ctx->xml, unode);
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+ pos = uri + 8;
+
+ if (ctx->fqdn == NULL) {
+ wpa_printf(MSG_INFO, "FQDN not known");
+ xml_node_free(ctx->xml, unode);
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+ fqdn_len = os_strlen(ctx->fqdn);
+ if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
+ pos[fqdn_len] != '/') {
+ wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
+ ctx->fqdn);
+ xml_node_free(ctx->xml, unode);
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+ pos += fqdn_len + 1;
+
+ if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
+ wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
+ ctx->fqdn);
+ xml_node_free(ctx->xml, unode);
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+ pos += 24;
+
+ wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
+
+ node = get_node(ctx->xml, pps, pos);
+ if (node) {
+ parent = xml_node_get_parent(ctx->xml, node);
+ xml_node_detach(ctx->xml, node);
+ wpa_printf(MSG_INFO, "Replace '%s' node", name);
+ } else {
+ char *pos2;
+ pos2 = os_strrchr(pos, '/');
+ if (pos2 == NULL) {
+ parent = pps;
+ } else {
+ *pos2 = '\0';
+ parent = get_node(ctx->xml, pps, pos);
+ }
+ if (parent == NULL) {
+ wpa_printf(MSG_INFO, "Could not find parent %s", pos);
+ xml_node_free(ctx->xml, unode);
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "Add '%s' node", name);
+ }
+ xml_node_add_child(ctx->xml, parent, unode);
+
+ xml_node_get_attr_value_free(ctx->xml, uri);
+
+ return 0;
+}
+
+
+static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
+ const char *pps_fname, xml_node_t *pps)
+{
+ wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
+ xml_node_for_each_sibling(ctx->xml, update) {
+ xml_node_for_each_check(ctx->xml, update);
+ if (process_update_node(ctx, pps, update) < 0)
+ return -1;
+ }
+
+ return update_pps_file(ctx, pps_fname, pps);
+}
+
+
+static void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
+ const char *pps_fname)
+{
+ /*
+ * Update wpa_supplicant credentials and reconnect using updated
+ * information.
+ */
+ wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
+ cmd_set_pps(ctx, pps_fname);
+
+ if (ctx->no_reconnect)
+ return;
+
+ wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
+ if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
+ wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
+}
+
+
+static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
+ xml_node_t *cmd,
+ const char *session_id,
+ const char *pps_fname)
+{
+ xml_namespace_t *ns;
+ xml_node_t *node, *ret_node;
+ char *urn;
+
+ urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
+ if (!urn) {
+ wpa_printf(MSG_INFO, "No URN included");
+ return NULL;
+ }
+ wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
+ if (strcasecmp(urn, URN_HS20_PPS) != 0) {
+ wpa_printf(MSG_INFO, "Unsupported moURN");
+ xml_node_get_attr_value_free(ctx->xml, urn);
+ return NULL;
+ }
+ xml_node_get_attr_value_free(ctx->xml, urn);
+
+ if (!pps_fname) {
+ wpa_printf(MSG_INFO, "PPS file name no known");
+ return NULL;
+ }
+
+ node = build_spp_post_dev_data(ctx, &ns, session_id,
+ "MO upload");
+ if (node == NULL)
+ return NULL;
+ add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
+
+ ret_node = soap_send_receive(ctx->http, node);
+ if (ret_node == NULL)
+ return NULL;
+
+ debug_dump_node(ctx, "Received response to MO upload", ret_node);
+
+ if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
+ wpa_printf(MSG_INFO, "SPP validation failed");
+ xml_node_free(ctx->xml, ret_node);
+ return NULL;
+ }
+
+ return ret_node;
+}
+
+
+static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
+ char *fname, size_t fname_len)
+{
+ char *uri, *urn;
+ int ret;
+
+ debug_dump_node(ctx, "Received addMO", add_mo);
+
+ urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
+ if (urn == NULL) {
+ wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
+ if (strcasecmp(urn, URN_HS20_PPS) != 0) {
+ wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
+ xml_node_get_attr_value_free(ctx->xml, urn);
+ return -1;
+ }
+ xml_node_get_attr_value_free(ctx->xml, urn);
+
+ uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
+ if (uri == NULL) {
+ wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
+
+ ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
+ xml_node_get_attr_value_free(ctx->xml, uri);
+ return ret;
+}
+
+
+static int process_spp_user_input_response(struct hs20_osu_client *ctx,
+ const char *session_id,
+ xml_node_t *add_mo)
+{
+ int ret;
+ char fname[300];
+
+ debug_dump_node(ctx, "addMO", add_mo);
+
+ wpa_printf(MSG_INFO, "Subscription registration completed");
+
+ if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
+ wpa_printf(MSG_INFO, "Could not add MO");
+ ret = hs20_spp_update_response(
+ ctx, session_id,
+ "Error occurred",
+ "MO addition or update failed");
+ return 0;
+ }
+
+ ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
+ if (ret == 0)
+ hs20_sub_rem_complete(ctx, fname);
+
+ return 0;
+}
+
+
+static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
+ const char *session_id)
+{
+ xml_node_t *node, *ret_node;
+
+ node = build_spp_post_dev_data(ctx, NULL, session_id,
+ "User input completed");
+ if (node == NULL)
+ return NULL;
+
+ ret_node = soap_send_receive(ctx->http, node);
+ if (!ret_node) {
+ if (soap_reinit_client(ctx->http) < 0)
+ return NULL;
+ wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
+ node = build_spp_post_dev_data(ctx, NULL, session_id,
+ "User input completed");
+ if (node == NULL)
+ return NULL;
+ ret_node = soap_send_receive(ctx->http, node);
+ if (ret_node == NULL)
+ return NULL;
+ wpa_printf(MSG_INFO, "Continue with new connection");
+ }
+
+ if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
+ wpa_printf(MSG_INFO, "SPP validation failed");
+ xml_node_free(ctx->xml, ret_node);
+ return NULL;
+ }
+
+ return ret_node;
+}
+
+
+static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
+ xml_node_t *cmd,
+ const char *session_id,
+ const char *pps_fname)
+{
+ xml_namespace_t *ns;
+ xml_node_t *node, *ret_node;
+ int res;
+
+ wpa_printf(MSG_INFO, "Client certificate enrollment");
+
+ res = osu_get_certificate(ctx, cmd);
+ if (res < 0)
+ wpa_printf(MSG_INFO, "EST simpleEnroll failed");
+
+ node = build_spp_post_dev_data(ctx, &ns, session_id,
+ res == 0 ?
+ "Certificate enrollment completed" :
+ "Certificate enrollment failed");
+ if (node == NULL)
+ return NULL;
+
+ ret_node = soap_send_receive(ctx->http, node);
+ if (ret_node == NULL)
+ return NULL;
+
+ debug_dump_node(ctx, "Received response to certificate enrollment "
+ "completed", ret_node);
+
+ if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
+ wpa_printf(MSG_INFO, "SPP validation failed");
+ xml_node_free(ctx->xml, ret_node);
+ return NULL;
+ }
+
+ return ret_node;
+}
+
+
+static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
+ const char *session_id, const char *pps_fname,
+ xml_node_t *pps, xml_node_t **ret_node)
+{
+ xml_node_t *cmd;
+ const char *name;
+ char *uri;
+ char *id = strdup(session_id);
+
+ if (id == NULL)
+ return -1;
+
+ *ret_node = NULL;
+
+ debug_dump_node(ctx, "exec", exec);
+
+ xml_node_for_each_child(ctx->xml, cmd, exec) {
+ xml_node_for_each_check(ctx->xml, cmd);
+ break;
+ }
+ if (!cmd) {
+ wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
+ cmd);
+ free(id);
+ return -1;
+ }
+
+ name = xml_node_get_localname(ctx->xml, cmd);
+
+ if (strcasecmp(name, "launchBrowserToURI") == 0) {
+ int res;
+ uri = xml_node_get_text(ctx->xml, cmd);
+ if (!uri) {
+ wpa_printf(MSG_INFO, "No URI found");
+ free(id);
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
+ write_summary(ctx, "Launch browser to URI '%s'", uri);
+ res = hs20_web_browser(uri);
+ xml_node_get_text_free(ctx->xml, uri);
+ if (res > 0) {
+ wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
+ id);
+ write_summary(ctx, "User response in browser completed successfully");
+ *ret_node = hs20_spp_user_input_completed(ctx, id);
+ free(id);
+ return *ret_node ? 0 : -1;
+ } else {
+ wpa_printf(MSG_INFO, "Failed to receive user response");
+ write_summary(ctx, "Failed to receive user response");
+ hs20_spp_update_response(
+ ctx, id, "Error occurred", "Other");
+ free(id);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (strcasecmp(name, "uploadMO") == 0) {
+ if (pps_fname == NULL)
+ return -1;
+ *ret_node = hs20_spp_upload_mo(ctx, cmd, id,
+ pps_fname);
+ free(id);
+ return *ret_node ? 0 : -1;
+ }
+
+ if (strcasecmp(name, "getCertificate") == 0) {
+ *ret_node = hs20_spp_get_certificate(ctx, cmd, id,
+ pps_fname);
+ free(id);
+ return *ret_node ? 0 : -1;
+ }
+
+ wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
+ free(id);
+ return -1;
+}
+
+
+enum spp_post_dev_data_use {
+ SPP_SUBSCRIPTION_REMEDIATION,
+ SPP_POLICY_UPDATE,
+ SPP_SUBSCRIPTION_REGISTRATION,
+};
+
+static void process_spp_post_dev_data_response(
+ struct hs20_osu_client *ctx,
+ enum spp_post_dev_data_use use, xml_node_t *node,
+ const char *pps_fname, xml_node_t *pps)
+{
+ xml_node_t *child;
+ char *status = NULL;
+ xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
+ char *session_id = NULL;
+
+ debug_dump_node(ctx, "sppPostDevDataResponse node", node);
+
+ status = get_spp_attr_value(ctx->xml, node, "sppStatus");
+ if (status == NULL) {
+ wpa_printf(MSG_INFO, "No sppStatus attribute");
+ goto out;
+ }
+ write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
+ status);
+
+ session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
+ if (session_id == NULL) {
+ wpa_printf(MSG_INFO, "No sessionID attribute");
+ goto out;
+ }
+
+ wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s' sessionID: '%s'",
+ status, session_id);
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ const char *name;
+ xml_node_for_each_check(ctx->xml, child);
+ debug_dump_node(ctx, "child", child);
+ name = xml_node_get_localname(ctx->xml, child);
+ wpa_printf(MSG_INFO, "localname: '%s'", name);
+ if (!update && strcasecmp(name, "updateNode") == 0)
+ update = child;
+ if (!exec && strcasecmp(name, "exec") == 0)
+ exec = child;
+ if (!add_mo && strcasecmp(name, "addMO") == 0)
+ add_mo = child;
+ if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
+ no_mo = child;
+ }
+
+ if (use == SPP_SUBSCRIPTION_REMEDIATION &&
+ strcasecmp(status,
+ "Remediation complete, request sppUpdateResponse") == 0)
+ {
+ int res, ret;
+ if (!update && !no_mo) {
+ wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
+ goto out;
+ }
+ wpa_printf(MSG_INFO, "Subscription remediation completed");
+ res = update_pps(ctx, update, pps_fname, pps);
+ if (res < 0)
+ wpa_printf(MSG_INFO, "Failed to update PPS MO");
+ ret = hs20_spp_update_response(
+ ctx, session_id,
+ res < 0 ? "Error occurred" : "OK",
+ res < 0 ? "MO addition or update failed" : NULL);
+ if (res == 0 && ret == 0)
+ hs20_sub_rem_complete(ctx, pps_fname);
+ goto out;
+ }
+
+ if (use == SPP_SUBSCRIPTION_REMEDIATION &&
+ strcasecmp(status, "Exchange complete, release TLS connection") ==
+ 0) {
+ if (!no_mo) {
+ wpa_printf(MSG_INFO, "No noMOUpdate element");
+ goto out;
+ }
+ wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
+ goto out;
+ }
+
+ if (use == SPP_POLICY_UPDATE &&
+ strcasecmp(status, "Update complete, request sppUpdateResponse") ==
+ 0) {
+ int res, ret;
+ wpa_printf(MSG_INFO, "Policy update received - update PPS");
+ res = update_pps(ctx, update, pps_fname, pps);
+ ret = hs20_spp_update_response(
+ ctx, session_id,
+ res < 0 ? "Error occurred" : "OK",
+ res < 0 ? "MO addition or update failed" : NULL);
+ if (res == 0 && ret == 0)
+ hs20_policy_update_complete(ctx, pps_fname);
+ goto out;
+ }
+
+ if (use == SPP_SUBSCRIPTION_REGISTRATION &&
+ strcasecmp(status, "Provisioning complete, request "
+ "sppUpdateResponse") == 0) {
+ if (!add_mo) {
+ wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
+ goto out;
+ }
+ process_spp_user_input_response(ctx, session_id, add_mo);
+ node = NULL;
+ goto out;
+ }
+
+ if (strcasecmp(status, "No update available at this time") == 0) {
+ wpa_printf(MSG_INFO, "No update available at this time");
+ goto out;
+ }
+
+ if (strcasecmp(status, "OK") == 0) {
+ int res;
+ xml_node_t *ret;
+
+ if (!exec) {
+ wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
+ goto out;
+ }
+ res = hs20_spp_exec(ctx, exec, session_id,
+ pps_fname, pps, &ret);
+ /* xml_node_free(ctx->xml, node); */
+ node = NULL;
+ if (res == 0 && ret)
+ process_spp_post_dev_data_response(ctx, use,
+ ret, pps_fname, pps);
+ goto out;
+ }
+
+ if (strcasecmp(status, "Error occurred") == 0) {
+ xml_node_t *err;
+ char *code = NULL;
+ err = get_node(ctx->xml, node, "sppError");
+ if (err)
+ code = xml_node_get_attr_value(ctx->xml, err,
+ "errorCode");
+ wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
+ code ? code : "N/A");
+ xml_node_get_attr_value_free(ctx->xml, code);
+ goto out;
+ }
+
+ wpa_printf(MSG_INFO,
+ "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
+ status);
+out:
+ xml_node_get_attr_value_free(ctx->xml, status);
+ xml_node_get_attr_value_free(ctx->xml, session_id);
+ xml_node_free(ctx->xml, node);
+}
+
+
+static int spp_post_dev_data(struct hs20_osu_client *ctx,
+ enum spp_post_dev_data_use use,
+ const char *reason,
+ const char *pps_fname, xml_node_t *pps)
+{
+ xml_node_t *payload;
+ xml_node_t *ret_node;
+
+ payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
+ if (payload == NULL)
+ return -1;
+
+ ret_node = soap_send_receive(ctx->http, payload);
+ if (!ret_node) {
+ const char *err = http_get_err(ctx->http);
+ if (err) {
+ wpa_printf(MSG_INFO, "HTTP error: %s", err);
+ write_result(ctx, "HTTP error: %s", err);
+ } else {
+ write_summary(ctx, "Failed to send SOAP message");
+ }
+ return -1;
+ }
+
+ if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
+ wpa_printf(MSG_INFO, "SPP validation failed");
+ xml_node_free(ctx->xml, ret_node);
+ return -1;
+ }
+
+ process_spp_post_dev_data_response(ctx, use, ret_node,
+ pps_fname, pps);
+ return 0;
+}
+
+
+void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps)
+{
+ wpa_printf(MSG_INFO, "SPP subscription remediation");
+ write_summary(ctx, "SPP subscription remediation");
+
+ os_free(ctx->server_url);
+ ctx->server_url = os_strdup(address);
+
+ if (soap_init_client(ctx->http, address, ctx->ca_fname,
+ cred_username, cred_password, client_cert,
+ client_key) == 0) {
+ spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
+ "Subscription remediation", pps_fname, pps);
+ }
+}
+
+
+static void hs20_policy_update_complete(struct hs20_osu_client *ctx,
+ const char *pps_fname)
+{
+ wpa_printf(MSG_INFO, "Policy update completed");
+
+ /*
+ * Update wpa_supplicant credentials and reconnect using updated
+ * information.
+ */
+ wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
+ cmd_set_pps(ctx, pps_fname);
+
+ wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
+ if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
+ wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
+}
+
+
+static int process_spp_exchange_complete(struct hs20_osu_client *ctx,
+ xml_node_t *node)
+{
+ char *status, *session_id;
+
+ debug_dump_node(ctx, "sppExchangeComplete", node);
+
+ status = get_spp_attr_value(ctx->xml, node, "sppStatus");
+ if (status == NULL) {
+ wpa_printf(MSG_INFO, "No sppStatus attribute");
+ return -1;
+ }
+ write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
+ status);
+
+ session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
+ if (session_id == NULL) {
+ wpa_printf(MSG_INFO, "No sessionID attribute");
+ xml_node_get_attr_value_free(ctx->xml, status);
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s' sessionID: '%s'",
+ status, session_id);
+ xml_node_get_attr_value_free(ctx->xml, session_id);
+
+ if (strcasecmp(status, "Exchange complete, release TLS connection") ==
+ 0) {
+ xml_node_get_attr_value_free(ctx->xml, status);
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
+ write_summary(ctx, "Unexpected sppStatus '%s'", status);
+ xml_node_get_attr_value_free(ctx->xml, status);
+ return -1;
+}
+
+
+static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
+ const char *session_id,
+ const char *spp_status,
+ const char *error_code)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node;
+
+ spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
+ "sppUpdateResponse");
+ if (spp_node == NULL)
+ return NULL;
+
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
+ xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
+
+ if (error_code) {
+ node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
+ if (node)
+ xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
+ error_code);
+ }
+
+ return spp_node;
+}
+
+
+static int hs20_spp_update_response(struct hs20_osu_client *ctx,
+ const char *session_id,
+ const char *spp_status,
+ const char *error_code)
+{
+ xml_node_t *node, *ret_node;
+ int ret;
+
+ write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
+ spp_status, error_code);
+ node = build_spp_update_response(ctx, session_id, spp_status,
+ error_code);
+ if (node == NULL)
+ return -1;
+ ret_node = soap_send_receive(ctx->http, node);
+ if (!ret_node) {
+ if (soap_reinit_client(ctx->http) < 0)
+ return -1;
+ wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
+ node = build_spp_update_response(ctx, session_id, spp_status,
+ error_code);
+ if (node == NULL)
+ return -1;
+ ret_node = soap_send_receive(ctx->http, node);
+ if (ret_node == NULL)
+ return -1;
+ wpa_printf(MSG_INFO, "Continue with new connection");
+ }
+
+ if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
+ wpa_printf(MSG_INFO, "SPP validation failed");
+ xml_node_free(ctx->xml, ret_node);
+ return -1;
+ }
+
+ ret = process_spp_exchange_complete(ctx, ret_node);
+ xml_node_free(ctx->xml, ret_node);
+ return ret;
+}
+
+
+void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname,
+ const char *client_cert, const char *client_key,
+ const char *cred_username, const char *cred_password,
+ xml_node_t *pps)
+{
+ wpa_printf(MSG_INFO, "SPP policy update");
+ write_summary(ctx, "SPP policy update");
+
+ os_free(ctx->server_url);
+ ctx->server_url = os_strdup(address);
+
+ if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
+ cred_password, client_cert, client_key) == 0) {
+ spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
+ pps_fname, pps);
+ }
+}
+
+
+int cmd_prov(struct hs20_osu_client *ctx, const char *url)
+{
+ unlink("Cert/est_cert.der");
+ unlink("Cert/est_cert.pem");
+
+ if (url == NULL) {
+ wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "Credential provisioning requested");
+
+ os_free(ctx->server_url);
+ ctx->server_url = os_strdup(url);
+
+ if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
+ NULL) < 0)
+ return -1;
+ spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
+ "Subscription registration", NULL, NULL);
+
+ return ctx->pps_cred_set ? 0 : -1;
+}
+
+
+int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
+{
+ if (url == NULL) {
+ wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "SIM provisioning requested");
+
+ os_free(ctx->server_url);
+ ctx->server_url = os_strdup(url);
+
+ wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
+
+ if (wait_ip_addr(ctx->ifname, 15) < 0) {
+ wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
+ }
+
+ if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
+ NULL) < 0)
+ return -1;
+ spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
+ "Subscription provisioning", NULL, NULL);
+
+ return ctx->pps_cred_set ? 0 : -1;
+}
diff --git a/contrib/wpa/patches/openssl-0.9.8-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8-tls-extensions.patch
deleted file mode 100644
index 44490cc..0000000
--- a/contrib/wpa/patches/openssl-0.9.8-tls-extensions.patch
+++ /dev/null
@@ -1,429 +0,0 @@
-This patch is adding support for TLS hello extensions and externally
-generated pre-shared key material to OpenSSL 0.9.8. This is
-based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-
-
-diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h
---- openssl-0.9.8.orig/include/openssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
-+++ openssl-0.9.8/include/openssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
-@@ -340,6 +340,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_extension_st TLS_EXTENSION;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
- typedef struct ssl_st SSL;
- typedef struct ssl_ctx_st SSL_CTX;
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -968,6 +971,15 @@ struct ssl_st
- int first_packet;
- int client_version; /* what was passed, used for
- * SSLv3/TLS rollback check */
-+
-+ /* TLS externsions */
-+ TLS_EXTENSION *tls_extension;
-+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
-+ void *tls_extension_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
- };
-
- #ifdef __cplusplus
-@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h
---- openssl-0.9.8.orig/include/openssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
-+++ openssl-0.9.8/include/openssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
-@@ -282,6 +282,14 @@ extern "C" {
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_extension_st
-+{
-+ unsigned short type;
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile
---- openssl-0.9.8.orig/ssl/Makefile 2005-05-30 16:20:30.000000000 -0700
-+++ openssl-0.9.8/ssl/Makefile 2005-07-19 20:02:15.000000000 -0700
-@@ -24,7 +24,7 @@ LIBSRC= \
- s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
- s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
- s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
-- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
-+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
- d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
- d1_both.c d1_enc.c \
- ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
-@@ -35,7 +35,7 @@ LIBOBJ= \
- s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
- s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
- s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
-- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
-+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
- d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
- d1_both.o d1_enc.o \
- ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
-@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
- t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
- t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
- t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
-+t1_ext.o: t1_ext.c ssl_locl.h
-diff -uprN openssl-0.9.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c
---- openssl-0.9.8.orig/ssl/s3_clnt.c 2005-05-16 03:11:03.000000000 -0700
-+++ openssl-0.9.8/ssl/s3_clnt.c 2005-07-19 20:02:15.000000000 -0700
-@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s)
- }
- *(p++)=0; /* Add the NULL method */
-
-+ /* send client hello extensions if any */
-+ if (s->version >= TLS1_VERSION && s->tls_extension)
-+ {
-+ // set the total extensions length
-+ s2n(s->tls_extension->length + 4, p);
-+
-+ // put the extensions with type and length
-+ s2n(s->tls_extension->type, p);
-+ s2n(s->tls_extension->length, p);
-+
-+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
-+ p+=s->tls_extension->length;
-+ }
-+
- l=(p-d);
- d=buf;
- *(d++)=SSL3_MT_CLIENT_HELLO;
-@@ -628,7 +642,7 @@ int ssl3_get_server_hello(SSL *s)
- STACK_OF(SSL_CIPHER) *sk;
- SSL_CIPHER *c;
- unsigned char *p,*d;
-- int i,al,ok;
-+ int i,al,ok,pre_shared;
- unsigned int j;
- long n;
- SSL_COMP *comp;
-@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-- if (j != 0 && j == s->session->session_id_length
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ pre_shared = 0;
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+ s->session->session_id_length = j;
-+ memcpy(s->session->session_id, p, j);
-+ pre_shared = 1;
-+ }
-+ }
-+
-+ if ((pre_shared || j != 0) && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
- if(s->sid_ctx_length != s->session->sid_ctx_length
-diff -uprN openssl-0.9.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c
---- openssl-0.9.8.orig/ssl/s3_srvr.c 2005-05-22 17:32:55.000000000 -0700
-+++ openssl-0.9.8/ssl/s3_srvr.c 2005-07-19 20:02:15.000000000 -0700
-@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s)
- }
- #endif
-
-+ /* Check for TLS client hello extension here */
-+ if (p < (d+n) && s->version >= TLS1_VERSION)
-+ {
-+ if (s->tls_extension_cb)
-+ {
-+ TLS_EXTENSION tls_ext;
-+ unsigned short ext_total_len;
-+
-+ n2s(p, ext_total_len);
-+ n2s(p, tls_ext.type);
-+ n2s(p, tls_ext.length);
-+
-+ // sanity check in TLS extension len
-+ if (tls_ext.length > (d+n) - p)
-+ {
-+ // just cut the lenth to packet border
-+ tls_ext.length = (d+n) - p;
-+ }
-+
-+ tls_ext.data = p;
-+
-+ // returns an alert code or 0
-+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
-+ if (al != 0)
-+ {
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
-+ goto f_err;
-+ }
-+ }
-+ }
-+
-+ /* Check if we want to use external pre-shared secret for this handshake */
-+ /* for not reused session only */
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
-+
- /* Given s->session->ciphers and SSL_get_ciphers, we must
- * pick a cipher */
-
-diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c
---- openssl-0.9.8.orig/ssl/ssl_err.c 2005-06-10 12:51:16.000000000 -0700
-+++ openssl-0.9.8/ssl/ssl_err.c 2005-07-19 20:02:15.000000000 -0700
-@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
- {0,NULL}
- };
-
-diff -uprN openssl-0.9.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h
---- openssl-0.9.8.orig/ssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
-+++ openssl-0.9.8/ssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
-@@ -340,6 +340,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_extension_st TLS_EXTENSION;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
- typedef struct ssl_st SSL;
- typedef struct ssl_ctx_st SSL_CTX;
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -968,6 +971,15 @@ struct ssl_st
- int first_packet;
- int client_version; /* what was passed, used for
- * SSLv3/TLS rollback check */
-+
-+ /* TLS externsions */
-+ TLS_EXTENSION *tls_extension;
-+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
-+ void *tls_extension_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
- };
-
- #ifdef __cplusplus
-@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -uprN openssl-0.9.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c
---- openssl-0.9.8.orig/ssl/ssl_sess.c 2005-04-29 13:10:06.000000000 -0700
-+++ openssl-0.9.8/ssl/ssl_sess.c 2005-07-19 20:02:15.000000000 -0700
-@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return(s->session_timeout);
- }
-
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+{
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+}
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-diff -uprN openssl-0.9.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c
---- openssl-0.9.8.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
-+++ openssl-0.9.8/ssl/t1_ext.c 2005-07-19 20:03:29.000000000 -0700
-@@ -0,0 +1,48 @@
-+
-+#include <stdio.h>
-+#include "ssl_locl.h"
-+
-+
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ s->tls_extension = NULL;
-+ }
-+
-+ if(ext_data)
-+ {
-+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
-+ if(!s->tls_extension)
-+ {
-+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ s->tls_extension->type = ext_type;
-+ s->tls_extension->length = ext_len;
-+ s->tls_extension->data = s->tls_extension + 1;
-+ memcpy(s->tls_extension->data, ext_data, ext_len);
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ s->tls_extension_cb = cb;
-+ s->tls_extension_cb_arg = arg;
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-diff -uprN openssl-0.9.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c
---- openssl-0.9.8.orig/ssl/t1_lib.c 2005-04-26 09:02:40.000000000 -0700
-+++ openssl-0.9.8/ssl/t1_lib.c 2005-07-19 20:02:15.000000000 -0700
-@@ -131,6 +131,10 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ }
- ssl3_free(s);
- }
-
-diff -uprN openssl-0.9.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h
---- openssl-0.9.8.orig/ssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
-+++ openssl-0.9.8/ssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
-@@ -282,6 +282,14 @@ extern "C" {
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_extension_st
-+{
-+ unsigned short type;
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -uprN openssl-0.9.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num
---- openssl-0.9.8.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
-+++ openssl-0.9.8/util/ssleay.num 2005-07-19 20:02:15.000000000 -0700
-@@ -226,3 +226,6 @@ DTLSv1_server_method
- SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
- SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
- SSL_SESSION_get_id 277 EXIST::FUNCTION:
-+SSL_set_hello_extension 278 EXIST::FUNCTION:
-+SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
-+SSL_set_session_secret_cb 280 EXIST::FUNCTION:
diff --git a/contrib/wpa/patches/openssl-0.9.8d-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8d-tls-extensions.patch
deleted file mode 100644
index eec6db8..0000000
--- a/contrib/wpa/patches/openssl-0.9.8d-tls-extensions.patch
+++ /dev/null
@@ -1,429 +0,0 @@
-This patch is adding support for TLS hello extensions and externally
-generated pre-shared key material to OpenSSL 0.9.8d. This is
-based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-
-
-diff -uprN openssl-0.9.8d.orig/include/openssl/ssl.h openssl-0.9.8d/include/openssl/ssl.h
---- openssl-0.9.8d.orig/include/openssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
-+++ openssl-0.9.8d/include/openssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
-@@ -345,6 +345,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_extension_st TLS_EXTENSION;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
- typedef struct ssl_st SSL;
- typedef struct ssl_ctx_st SSL_CTX;
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -973,6 +976,15 @@ struct ssl_st
- int first_packet;
- int client_version; /* what was passed, used for
- * SSLv3/TLS rollback check */
-+
-+ /* TLS externsions */
-+ TLS_EXTENSION *tls_extension;
-+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
-+ void *tls_extension_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
- };
-
- #ifdef __cplusplus
-@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -uprN openssl-0.9.8d.orig/include/openssl/tls1.h openssl-0.9.8d/include/openssl/tls1.h
---- openssl-0.9.8d.orig/include/openssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
-+++ openssl-0.9.8d/include/openssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
-@@ -296,6 +296,14 @@ extern "C" {
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_extension_st
-+{
-+ unsigned short type;
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -uprN openssl-0.9.8d.orig/ssl/Makefile openssl-0.9.8d/ssl/Makefile
---- openssl-0.9.8d.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800
-+++ openssl-0.9.8d/ssl/Makefile 2006-12-10 08:20:02.000000000 -0800
-@@ -24,7 +24,7 @@ LIBSRC= \
- s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
- s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
- s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
-- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
-+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
- d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
- d1_both.c d1_enc.c \
- ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
-@@ -35,7 +35,7 @@ LIBOBJ= \
- s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
- s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
- s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
-- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
-+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
- d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
- d1_both.o d1_enc.o \
- ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
-@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
- t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
- t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
- t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
-+t1_ext.o: t1_ext.c ssl_locl.h
-diff -uprN openssl-0.9.8d.orig/ssl/s3_clnt.c openssl-0.9.8d/ssl/s3_clnt.c
---- openssl-0.9.8d.orig/ssl/s3_clnt.c 2005-12-12 23:41:46.000000000 -0800
-+++ openssl-0.9.8d/ssl/s3_clnt.c 2006-12-10 08:20:02.000000000 -0800
-@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
- #endif
- *(p++)=0; /* Add the NULL method */
-
-+ /* send client hello extensions if any */
-+ if (s->version >= TLS1_VERSION && s->tls_extension)
-+ {
-+ // set the total extensions length
-+ s2n(s->tls_extension->length + 4, p);
-+
-+ // put the extensions with type and length
-+ s2n(s->tls_extension->type, p);
-+ s2n(s->tls_extension->length, p);
-+
-+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
-+ p+=s->tls_extension->length;
-+ }
-+
- l=(p-d);
- d=buf;
- *(d++)=SSL3_MT_CLIENT_HELLO;
-@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
- STACK_OF(SSL_CIPHER) *sk;
- SSL_CIPHER *c;
- unsigned char *p,*d;
-- int i,al,ok;
-+ int i,al,ok,pre_shared;
- unsigned int j;
- long n;
- #ifndef OPENSSL_NO_COMP
-@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-- if (j != 0 && j == s->session->session_id_length
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ pre_shared = 0;
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+ s->session->session_id_length = j;
-+ memcpy(s->session->session_id, p, j);
-+ pre_shared = 1;
-+ }
-+ }
-+
-+ if ((pre_shared || j != 0) && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
- if(s->sid_ctx_length != s->session->sid_ctx_length
-diff -uprN openssl-0.9.8d.orig/ssl/s3_srvr.c openssl-0.9.8d/ssl/s3_srvr.c
---- openssl-0.9.8d.orig/ssl/s3_srvr.c 2006-09-28 04:29:03.000000000 -0700
-+++ openssl-0.9.8d/ssl/s3_srvr.c 2006-12-10 08:20:02.000000000 -0800
-@@ -943,6 +943,75 @@ int ssl3_get_client_hello(SSL *s)
- }
- #endif
-
-+ /* Check for TLS client hello extension here */
-+ if (p < (d+n) && s->version >= TLS1_VERSION)
-+ {
-+ if (s->tls_extension_cb)
-+ {
-+ TLS_EXTENSION tls_ext;
-+ unsigned short ext_total_len;
-+
-+ n2s(p, ext_total_len);
-+ n2s(p, tls_ext.type);
-+ n2s(p, tls_ext.length);
-+
-+ // sanity check in TLS extension len
-+ if (tls_ext.length > (d+n) - p)
-+ {
-+ // just cut the lenth to packet border
-+ tls_ext.length = (d+n) - p;
-+ }
-+
-+ tls_ext.data = p;
-+
-+ // returns an alert code or 0
-+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
-+ if (al != 0)
-+ {
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
-+ goto f_err;
-+ }
-+ }
-+ }
-+
-+ /* Check if we want to use external pre-shared secret for this handshake */
-+ /* for not reused session only */
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
-+
- /* Given s->session->ciphers and SSL_get_ciphers, we must
- * pick a cipher */
-
-diff -uprN openssl-0.9.8d.orig/ssl/ssl.h openssl-0.9.8d/ssl/ssl.h
---- openssl-0.9.8d.orig/ssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
-+++ openssl-0.9.8d/ssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
-@@ -345,6 +345,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_extension_st TLS_EXTENSION;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
- typedef struct ssl_st SSL;
- typedef struct ssl_ctx_st SSL_CTX;
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -973,6 +976,15 @@ struct ssl_st
- int first_packet;
- int client_version; /* what was passed, used for
- * SSLv3/TLS rollback check */
-+
-+ /* TLS externsions */
-+ TLS_EXTENSION *tls_extension;
-+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
-+ void *tls_extension_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
- };
-
- #ifdef __cplusplus
-@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -uprN openssl-0.9.8d.orig/ssl/ssl_err.c openssl-0.9.8d/ssl/ssl_err.c
---- openssl-0.9.8d.orig/ssl/ssl_err.c 2006-01-08 13:52:46.000000000 -0800
-+++ openssl-0.9.8d/ssl/ssl_err.c 2006-12-10 08:20:02.000000000 -0800
-@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
- {0,NULL}
- };
-
-diff -uprN openssl-0.9.8d.orig/ssl/ssl_sess.c openssl-0.9.8d/ssl/ssl_sess.c
---- openssl-0.9.8d.orig/ssl/ssl_sess.c 2005-12-30 15:51:57.000000000 -0800
-+++ openssl-0.9.8d/ssl/ssl_sess.c 2006-12-10 08:20:02.000000000 -0800
-@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return(s->session_timeout);
- }
-
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+{
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+}
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-diff -uprN openssl-0.9.8d.orig/ssl/t1_ext.c openssl-0.9.8d/ssl/t1_ext.c
---- openssl-0.9.8d.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
-+++ openssl-0.9.8d/ssl/t1_ext.c 2006-12-10 08:20:02.000000000 -0800
-@@ -0,0 +1,48 @@
-+
-+#include <stdio.h>
-+#include "ssl_locl.h"
-+
-+
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ s->tls_extension = NULL;
-+ }
-+
-+ if(ext_data)
-+ {
-+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
-+ if(!s->tls_extension)
-+ {
-+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ s->tls_extension->type = ext_type;
-+ s->tls_extension->length = ext_len;
-+ s->tls_extension->data = s->tls_extension + 1;
-+ memcpy(s->tls_extension->data, ext_data, ext_len);
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ s->tls_extension_cb = cb;
-+ s->tls_extension_cb_arg = arg;
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-diff -uprN openssl-0.9.8d.orig/ssl/t1_lib.c openssl-0.9.8d/ssl/t1_lib.c
---- openssl-0.9.8d.orig/ssl/t1_lib.c 2005-08-05 16:52:07.000000000 -0700
-+++ openssl-0.9.8d/ssl/t1_lib.c 2006-12-10 08:20:02.000000000 -0800
-@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ }
- ssl3_free(s);
- }
-
-diff -uprN openssl-0.9.8d.orig/ssl/tls1.h openssl-0.9.8d/ssl/tls1.h
---- openssl-0.9.8d.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
-+++ openssl-0.9.8d/ssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
-@@ -296,6 +296,14 @@ extern "C" {
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_extension_st
-+{
-+ unsigned short type;
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -uprN openssl-0.9.8d.orig/util/ssleay.num openssl-0.9.8d/util/ssleay.num
---- openssl-0.9.8d.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
-+++ openssl-0.9.8d/util/ssleay.num 2006-12-10 08:20:02.000000000 -0800
-@@ -226,3 +226,6 @@ DTLSv1_server_method
- SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
- SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
- SSL_SESSION_get_id 277 EXIST::FUNCTION:
-+SSL_set_hello_extension 278 EXIST::FUNCTION:
-+SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
-+SSL_set_session_secret_cb 280 EXIST::FUNCTION:
diff --git a/contrib/wpa/patches/openssl-0.9.8e-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8e-tls-extensions.patch
deleted file mode 100644
index ede053f..0000000
--- a/contrib/wpa/patches/openssl-0.9.8e-tls-extensions.patch
+++ /dev/null
@@ -1,353 +0,0 @@
-This patch is adding support for TLS hello extensions and externally
-generated pre-shared key material to OpenSSL 0.9.8e. This is
-based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-
-
-diff -uprN openssl-0.9.8e.orig/ssl/Makefile openssl-0.9.8e/ssl/Makefile
---- openssl-0.9.8e.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800
-+++ openssl-0.9.8e/ssl/Makefile 2007-03-22 20:23:19.000000000 -0700
-@@ -24,7 +24,7 @@ LIBSRC= \
- s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
- s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
- s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
-- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
-+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
- d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
- d1_both.c d1_enc.c \
- ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
-@@ -35,7 +35,7 @@ LIBOBJ= \
- s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
- s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
- s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
-- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
-+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
- d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
- d1_both.o d1_enc.o \
- ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
-@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
- t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
- t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
- t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
-+t1_ext.o: t1_ext.c ssl_locl.h
-diff -uprN openssl-0.9.8e.orig/ssl/s3_clnt.c openssl-0.9.8e/ssl/s3_clnt.c
---- openssl-0.9.8e.orig/ssl/s3_clnt.c 2006-09-28 05:23:15.000000000 -0700
-+++ openssl-0.9.8e/ssl/s3_clnt.c 2007-03-22 20:23:19.000000000 -0700
-@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
- #endif
- *(p++)=0; /* Add the NULL method */
-
-+ /* send client hello extensions if any */
-+ if (s->version >= TLS1_VERSION && s->tls_extension)
-+ {
-+ // set the total extensions length
-+ s2n(s->tls_extension->length + 4, p);
-+
-+ // put the extensions with type and length
-+ s2n(s->tls_extension->type, p);
-+ s2n(s->tls_extension->length, p);
-+
-+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
-+ p+=s->tls_extension->length;
-+ }
-+
- l=(p-d);
- d=buf;
- *(d++)=SSL3_MT_CLIENT_HELLO;
-@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
- STACK_OF(SSL_CIPHER) *sk;
- SSL_CIPHER *c;
- unsigned char *p,*d;
-- int i,al,ok;
-+ int i,al,ok,pre_shared;
- unsigned int j;
- long n;
- #ifndef OPENSSL_NO_COMP
-@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-- if (j != 0 && j == s->session->session_id_length
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ pre_shared = 0;
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+ s->session->session_id_length = j;
-+ memcpy(s->session->session_id, p, j);
-+ pre_shared = 1;
-+ }
-+ }
-+
-+ if ((pre_shared || j != 0) && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
- if(s->sid_ctx_length != s->session->sid_ctx_length
-diff -uprN openssl-0.9.8e.orig/ssl/s3_srvr.c openssl-0.9.8e/ssl/s3_srvr.c
---- openssl-0.9.8e.orig/ssl/s3_srvr.c 2007-02-07 12:36:40.000000000 -0800
-+++ openssl-0.9.8e/ssl/s3_srvr.c 2007-03-22 20:23:19.000000000 -0700
-@@ -945,6 +945,75 @@ int ssl3_get_client_hello(SSL *s)
- }
- #endif
-
-+ /* Check for TLS client hello extension here */
-+ if (p < (d+n) && s->version >= TLS1_VERSION)
-+ {
-+ if (s->tls_extension_cb)
-+ {
-+ TLS_EXTENSION tls_ext;
-+ unsigned short ext_total_len;
-+
-+ n2s(p, ext_total_len);
-+ n2s(p, tls_ext.type);
-+ n2s(p, tls_ext.length);
-+
-+ // sanity check in TLS extension len
-+ if (tls_ext.length > (d+n) - p)
-+ {
-+ // just cut the lenth to packet border
-+ tls_ext.length = (d+n) - p;
-+ }
-+
-+ tls_ext.data = p;
-+
-+ // returns an alert code or 0
-+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
-+ if (al != 0)
-+ {
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
-+ goto f_err;
-+ }
-+ }
-+ }
-+
-+ /* Check if we want to use external pre-shared secret for this handshake */
-+ /* for not reused session only */
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
-+
- /* Given s->session->ciphers and SSL_get_ciphers, we must
- * pick a cipher */
-
-diff -uprN openssl-0.9.8e.orig/ssl/ssl.h openssl-0.9.8e/ssl/ssl.h
---- openssl-0.9.8e.orig/ssl/ssl.h 2007-02-19 09:55:07.000000000 -0800
-+++ openssl-0.9.8e/ssl/ssl.h 2007-03-22 20:23:19.000000000 -0700
-@@ -345,6 +345,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_extension_st TLS_EXTENSION;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
- typedef struct ssl_st SSL;
- typedef struct ssl_ctx_st SSL_CTX;
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -973,6 +976,15 @@ struct ssl_st
- int first_packet;
- int client_version; /* what was passed, used for
- * SSLv3/TLS rollback check */
-+
-+ /* TLS externsions */
-+ TLS_EXTENSION *tls_extension;
-+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
-+ void *tls_extension_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
- };
-
- #ifdef __cplusplus
-@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -uprN openssl-0.9.8e.orig/ssl/ssl_err.c openssl-0.9.8e/ssl/ssl_err.c
---- openssl-0.9.8e.orig/ssl/ssl_err.c 2006-11-21 12:14:46.000000000 -0800
-+++ openssl-0.9.8e/ssl/ssl_err.c 2007-03-22 20:23:19.000000000 -0700
-@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
- {0,NULL}
- };
-
-diff -uprN openssl-0.9.8e.orig/ssl/ssl_sess.c openssl-0.9.8e/ssl/ssl_sess.c
---- openssl-0.9.8e.orig/ssl/ssl_sess.c 2007-02-10 02:40:24.000000000 -0800
-+++ openssl-0.9.8e/ssl/ssl_sess.c 2007-03-22 20:23:19.000000000 -0700
-@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return(s->session_timeout);
- }
-
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+{
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+}
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-diff -uprN openssl-0.9.8e.orig/ssl/t1_ext.c openssl-0.9.8e/ssl/t1_ext.c
---- openssl-0.9.8e.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
-+++ openssl-0.9.8e/ssl/t1_ext.c 2007-03-22 20:23:19.000000000 -0700
-@@ -0,0 +1,48 @@
-+
-+#include <stdio.h>
-+#include "ssl_locl.h"
-+
-+
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ s->tls_extension = NULL;
-+ }
-+
-+ if(ext_data)
-+ {
-+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
-+ if(!s->tls_extension)
-+ {
-+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ s->tls_extension->type = ext_type;
-+ s->tls_extension->length = ext_len;
-+ s->tls_extension->data = s->tls_extension + 1;
-+ memcpy(s->tls_extension->data, ext_data, ext_len);
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ s->tls_extension_cb = cb;
-+ s->tls_extension_cb_arg = arg;
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-diff -uprN openssl-0.9.8e.orig/ssl/t1_lib.c openssl-0.9.8e/ssl/t1_lib.c
---- openssl-0.9.8e.orig/ssl/t1_lib.c 2007-01-21 08:07:25.000000000 -0800
-+++ openssl-0.9.8e/ssl/t1_lib.c 2007-03-22 20:23:19.000000000 -0700
-@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ }
- ssl3_free(s);
- }
-
-diff -uprN openssl-0.9.8e.orig/ssl/tls1.h openssl-0.9.8e/ssl/tls1.h
---- openssl-0.9.8e.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
-+++ openssl-0.9.8e/ssl/tls1.h 2007-03-22 20:23:19.000000000 -0700
-@@ -296,6 +296,14 @@ extern "C" {
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_extension_st
-+{
-+ unsigned short type;
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -uprN openssl-0.9.8e.orig/util/ssleay.num openssl-0.9.8e/util/ssleay.num
---- openssl-0.9.8e.orig/util/ssleay.num 2006-11-30 05:04:43.000000000 -0800
-+++ openssl-0.9.8e/util/ssleay.num 2007-03-22 20:24:07.000000000 -0700
-@@ -238,3 +238,6 @@ SSL_CTX_set_info_callback
- SSL_CTX_sess_get_new_cb 287 EXIST::FUNCTION:
- SSL_CTX_get_client_cert_cb 288 EXIST::FUNCTION:
- SSL_CTX_sess_get_remove_cb 289 EXIST::FUNCTION:
-+SSL_set_hello_extension 290 EXIST::FUNCTION:
-+SSL_set_hello_extension_cb 291 EXIST::FUNCTION:
-+SSL_set_session_secret_cb 292 EXIST::FUNCTION:
diff --git a/contrib/wpa/patches/openssl-0.9.8g-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8g-tls-extensions.patch
deleted file mode 100644
index 8ccbfaa..0000000
--- a/contrib/wpa/patches/openssl-0.9.8g-tls-extensions.patch
+++ /dev/null
@@ -1,330 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8g does not enable TLS extension support by default, so it
-will need to be enabled by adding enable-tlsext to config script
-command line.
-
-
-diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c
---- openssl-0.9.8g.orig/ssl/s3_clnt.c 2007-08-31 03:28:51.000000000 +0300
-+++ openssl-0.9.8g/ssl/s3_clnt.c 2008-04-15 17:11:46.000000000 +0300
-@@ -727,6 +727,20 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
-diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c
---- openssl-0.9.8g.orig/ssl/s3_srvr.c 2007-09-30 21:55:59.000000000 +0300
-+++ openssl-0.9.8g/ssl/s3_srvr.c 2008-04-15 17:10:37.000000000 +0300
-@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s)
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-+
-+ /* Check if we want to use external pre-shared secret for this
-+ * handshake for not reused session only. We need to generate
-+ * server_random before calling tls_session_secret_cb in order to allow
-+ * SessionTicket processing to use it in key derivation. */
-+ {
-+ unsigned long Time;
-+ unsigned char *pos;
-+ Time=(unsigned long)time(NULL); /* Time */
-+ pos=s->s3->server_random;
-+ l2n(Time,pos);
-+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
-+ {
-+ al=SSL_AD_INTERNAL_ERROR;
-+ goto f_err;
-+ }
-+ }
-+
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
- #endif
- /* Worst case, we will use the NULL compression, but if we have other
- * options, we will now look for them. We have i-1 compression
-@@ -1066,16 +1119,22 @@ int ssl3_send_server_hello(SSL *s)
- unsigned char *buf;
- unsigned char *p,*d;
- int i,sl;
-- unsigned long l,Time;
-+ unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+ unsigned long Time;
-+#endif
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- buf=(unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
- p=s->s3->server_random;
-+ /* Generate server_random if it was not needed previously */
- Time=(unsigned long)time(NULL); /* Time */
- l2n(Time,p);
- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
- return -1;
-+#endif
- /* Do the message type and length last */
- d=p= &(buf[4]);
-
-diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h
---- openssl-0.9.8g.orig/ssl/ssl.h 2007-10-19 10:42:38.000000000 +0300
-+++ openssl-0.9.8g/ssl/ssl.h 2008-04-15 17:10:37.000000000 +0300
-@@ -342,6 +342,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_extension_st TLS_EXTENSION;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -363,6 +364,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
- typedef struct ssl_st SSL;
- typedef struct ssl_ctx_st SSL_CTX;
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -1004,6 +1007,14 @@ struct ssl_st
- */
- /* RFC4507 session ticket expected to be received or sent */
- int tlsext_ticket_expected;
-+
-+ /* TLS extensions */
-+ TLS_EXTENSION *tls_extension;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
-+
- SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
- #define session_ctx initial_ctx
- #else
-@@ -1589,6 +1600,12 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1778,6 +1795,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c
---- openssl-0.9.8g.orig/ssl/ssl_err.c 2007-10-11 17:36:59.000000000 +0300
-+++ openssl-0.9.8g/ssl/ssl_err.c 2008-04-15 17:10:37.000000000 +0300
-@@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
- {0,NULL}
- };
-
-diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c
---- openssl-0.9.8g.orig/ssl/ssl_sess.c 2007-10-19 10:36:34.000000000 +0300
-+++ openssl-0.9.8g/ssl/ssl_sess.c 2008-04-15 17:10:37.000000000 +0300
-@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return(s->session_timeout);
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+{
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+}
-+
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ s->tls_extension = NULL;
-+ }
-+
-+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
-+ if(!s->tls_extension)
-+ {
-+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ s->tls_extension->type = ext_type;
-+
-+ if(ext_data)
-+ {
-+ s->tls_extension->length = ext_len;
-+ s->tls_extension->data = s->tls_extension + 1;
-+ memcpy(s->tls_extension->data, ext_data, ext_len);
-+ } else {
-+ s->tls_extension->length = 0;
-+ s->tls_extension->data = NULL;
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c
---- openssl-0.9.8g.orig/ssl/t1_lib.c 2007-10-19 10:44:10.000000000 +0300
-+++ openssl-0.9.8g/ssl/t1_lib.c 2008-04-15 17:10:37.000000000 +0300
-@@ -105,6 +105,12 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+#ifndef OPENSSL_NO_TLSEXT
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ }
-+#endif
- ssl3_free(s);
- }
-
-@@ -174,8 +180,24 @@ unsigned char *ssl_add_clienthello_tlsex
- int ticklen;
- if (s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
-+ else if (s->session && s->tls_extension &&
-+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
-+ s->tls_extension->data)
-+ {
-+ ticklen = s->tls_extension->length;
-+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+ if (!s->session->tlsext_tick)
-+ return NULL;
-+ memcpy(s->session->tlsext_tick, s->tls_extension->data,
-+ ticklen);
-+ s->session->tlsext_ticklen = ticklen;
-+ }
- else
- ticklen = 0;
-+ if (ticklen == 0 && s->tls_extension &&
-+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
-+ s->tls_extension->data == NULL)
-+ goto skip_ext;
- /* Check for enough room 2 for extension type, 2 for len
- * rest for ticket
- */
-@@ -189,6 +211,7 @@ unsigned char *ssl_add_clienthello_tlsex
- ret += ticklen;
- }
- }
-+ skip_ext:
-
- if ((extdatalen = ret-p-2)== 0)
- return p;
-@@ -543,6 +566,8 @@ int tls1_process_ticket(SSL *s, unsigned
- s->tlsext_ticket_expected = 1;
- return 0; /* Cache miss */
- }
-+ if (s->tls_session_secret_cb)
-+ return 0;
- return tls_decrypt_ticket(s, p, size, session_id, len,
- ret);
- }
-diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h
---- openssl-0.9.8g.orig/ssl/tls1.h 2007-08-28 04:12:44.000000000 +0300
-+++ openssl-0.9.8g/ssl/tls1.h 2008-04-15 17:10:37.000000000 +0300
-@@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_extension_st
-+{
-+ unsigned short type;
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num
---- openssl-0.9.8g.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300
-+++ openssl-0.9.8g/util/ssleay.num 2008-04-15 17:10:37.000000000 +0300
-@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb
- SSL_set_SSL_CTX 290 EXIST::FUNCTION:
- SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
- SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
-+SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT
diff --git a/contrib/wpa/patches/openssl-0.9.8h-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8h-tls-extensions.patch
deleted file mode 100644
index c68f227..0000000
--- a/contrib/wpa/patches/openssl-0.9.8h-tls-extensions.patch
+++ /dev/null
@@ -1,344 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8h does not enable TLS extension support by default, so it
-will need to be enabled by adding enable-tlsext to config script
-command line.
-
-
-diff -upr openssl-0.9.8h.orig/ssl/s3_clnt.c openssl-0.9.8h/ssl/s3_clnt.c
---- openssl-0.9.8h.orig/ssl/s3_clnt.c 2008-05-28 10:29:27.000000000 +0300
-+++ openssl-0.9.8h/ssl/s3_clnt.c 2008-05-29 10:44:25.000000000 +0300
-@@ -752,6 +752,20 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
-@@ -2693,11 +2707,8 @@ static int ssl3_check_finished(SSL *s)
- {
- int ok;
- long n;
-- /* If we have no ticket or session ID is non-zero length (a match of
-- * a non-zero session length would never reach here) it cannot be a
-- * resumed session.
-- */
-- if (!s->session->tlsext_tick || s->session->session_id_length)
-+ /* If we have no ticket it cannot be a resumed session. */
-+ if (!s->session->tlsext_tick)
- return 1;
- /* this function is called when we really expect a Certificate
- * message, so permit appropriate message length */
-diff -upr openssl-0.9.8h.orig/ssl/s3_srvr.c openssl-0.9.8h/ssl/s3_srvr.c
---- openssl-0.9.8h.orig/ssl/s3_srvr.c 2008-04-30 19:11:32.000000000 +0300
-+++ openssl-0.9.8h/ssl/s3_srvr.c 2008-05-28 18:49:34.000000000 +0300
-@@ -959,6 +959,59 @@ int ssl3_get_client_hello(SSL *s)
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-+
-+ /* Check if we want to use external pre-shared secret for this
-+ * handshake for not reused session only. We need to generate
-+ * server_random before calling tls_session_secret_cb in order to allow
-+ * SessionTicket processing to use it in key derivation. */
-+ {
-+ unsigned long Time;
-+ unsigned char *pos;
-+ Time=(unsigned long)time(NULL); /* Time */
-+ pos=s->s3->server_random;
-+ l2n(Time,pos);
-+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
-+ {
-+ al=SSL_AD_INTERNAL_ERROR;
-+ goto f_err;
-+ }
-+ }
-+
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
- #endif
- /* Worst case, we will use the NULL compression, but if we have other
- * options, we will now look for them. We have i-1 compression
-@@ -1097,16 +1150,22 @@ int ssl3_send_server_hello(SSL *s)
- unsigned char *buf;
- unsigned char *p,*d;
- int i,sl;
-- unsigned long l,Time;
-+ unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+ unsigned long Time;
-+#endif
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- buf=(unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
- p=s->s3->server_random;
-+ /* Generate server_random if it was not needed previously */
- Time=(unsigned long)time(NULL); /* Time */
- l2n(Time,p);
- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
- return -1;
-+#endif
- /* Do the message type and length last */
- d=p= &(buf[4]);
-
-diff -upr openssl-0.9.8h.orig/ssl/ssl.h openssl-0.9.8h/ssl/ssl.h
---- openssl-0.9.8h.orig/ssl/ssl.h 2008-04-30 19:11:32.000000000 +0300
-+++ openssl-0.9.8h/ssl/ssl.h 2008-05-28 18:49:34.000000000 +0300
-@@ -343,6 +343,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_extension_st TLS_EXTENSION;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -364,6 +365,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
- typedef struct ssl_st SSL;
- typedef struct ssl_ctx_st SSL_CTX;
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -1027,6 +1030,14 @@ struct ssl_st
-
- /* RFC4507 session ticket expected to be received or sent */
- int tlsext_ticket_expected;
-+
-+ /* TLS extensions */
-+ TLS_EXTENSION *tls_extension;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
-+
- SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
- #define session_ctx initial_ctx
- #else
-@@ -1625,6 +1636,12 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1815,6 +1832,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -upr openssl-0.9.8h.orig/ssl/ssl_err.c openssl-0.9.8h/ssl/ssl_err.c
---- openssl-0.9.8h.orig/ssl/ssl_err.c 2007-10-12 03:00:30.000000000 +0300
-+++ openssl-0.9.8h/ssl/ssl_err.c 2008-05-28 18:49:34.000000000 +0300
-@@ -251,6 +251,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
- {0,NULL}
- };
-
-diff -upr openssl-0.9.8h.orig/ssl/ssl_sess.c openssl-0.9.8h/ssl/ssl_sess.c
---- openssl-0.9.8h.orig/ssl/ssl_sess.c 2007-10-17 20:30:15.000000000 +0300
-+++ openssl-0.9.8h/ssl/ssl_sess.c 2008-05-28 18:49:34.000000000 +0300
-@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return(s->session_timeout);
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+{
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+}
-+
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
-+{
-+ if(s->version >= TLS1_VERSION)
-+ {
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ s->tls_extension = NULL;
-+ }
-+
-+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
-+ if(!s->tls_extension)
-+ {
-+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ s->tls_extension->type = ext_type;
-+
-+ if(ext_data)
-+ {
-+ s->tls_extension->length = ext_len;
-+ s->tls_extension->data = s->tls_extension + 1;
-+ memcpy(s->tls_extension->data, ext_data, ext_len);
-+ } else {
-+ s->tls_extension->length = 0;
-+ s->tls_extension->data = NULL;
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-diff -upr openssl-0.9.8h.orig/ssl/t1_lib.c openssl-0.9.8h/ssl/t1_lib.c
---- openssl-0.9.8h.orig/ssl/t1_lib.c 2008-05-28 10:26:33.000000000 +0300
-+++ openssl-0.9.8h/ssl/t1_lib.c 2008-05-28 18:49:34.000000000 +0300
-@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+#ifndef OPENSSL_NO_TLSEXT
-+ if(s->tls_extension)
-+ {
-+ OPENSSL_free(s->tls_extension);
-+ }
-+#endif
- ssl3_free(s);
- }
-
-@@ -175,8 +181,24 @@ unsigned char *ssl_add_clienthello_tlsex
- int ticklen;
- if (s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
-+ else if (s->session && s->tls_extension &&
-+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
-+ s->tls_extension->data)
-+ {
-+ ticklen = s->tls_extension->length;
-+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+ if (!s->session->tlsext_tick)
-+ return NULL;
-+ memcpy(s->session->tlsext_tick, s->tls_extension->data,
-+ ticklen);
-+ s->session->tlsext_ticklen = ticklen;
-+ }
- else
- ticklen = 0;
-+ if (ticklen == 0 && s->tls_extension &&
-+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
-+ s->tls_extension->data == NULL)
-+ goto skip_ext;
- /* Check for enough room 2 for extension type, 2 for len
- * rest for ticket
- */
-@@ -190,6 +212,7 @@ unsigned char *ssl_add_clienthello_tlsex
- ret += ticklen;
- }
- }
-+ skip_ext:
-
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
- {
-@@ -774,6 +797,8 @@ int tls1_process_ticket(SSL *s, unsigned
- s->tlsext_ticket_expected = 1;
- return 0; /* Cache miss */
- }
-+ if (s->tls_session_secret_cb)
-+ return 0;
- return tls_decrypt_ticket(s, p, size, session_id, len,
- ret);
- }
-diff -upr openssl-0.9.8h.orig/ssl/tls1.h openssl-0.9.8h/ssl/tls1.h
---- openssl-0.9.8h.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300
-+++ openssl-0.9.8h/ssl/tls1.h 2008-05-28 18:49:34.000000000 +0300
-@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_extension_st
-+{
-+ unsigned short type;
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -upr openssl-0.9.8h.orig/util/ssleay.num openssl-0.9.8h/util/ssleay.num
---- openssl-0.9.8h.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300
-+++ openssl-0.9.8h/util/ssleay.num 2008-05-28 18:49:34.000000000 +0300
-@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb
- SSL_set_SSL_CTX 290 EXIST::FUNCTION:
- SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
- SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
-+SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT
diff --git a/contrib/wpa/patches/openssl-0.9.8i-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8i-tls-extensions.patch
deleted file mode 100644
index 90bff54..0000000
--- a/contrib/wpa/patches/openssl-0.9.8i-tls-extensions.patch
+++ /dev/null
@@ -1,404 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8i does not enable TLS extension support by default, so it
-will need to be enabled by adding enable-tlsext to config script
-command line.
-
-
-Index: openssl-0.9.8i/ssl/s3_clnt.c
-===================================================================
---- openssl-0.9.8i.orig/ssl/s3_clnt.c 2008-06-16 19:56:41.000000000 +0300
-+++ openssl-0.9.8i/ssl/s3_clnt.c 2008-11-23 20:39:40.000000000 +0200
-@@ -759,6 +759,21 @@
- goto f_err;
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->session->cipher=pref_cipher ?
-+ pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
-@@ -2701,11 +2716,8 @@
- {
- int ok;
- long n;
-- /* If we have no ticket or session ID is non-zero length (a match of
-- * a non-zero session length would never reach here) it cannot be a
-- * resumed session.
-- */
-- if (!s->session->tlsext_tick || s->session->session_id_length)
-+ /* If we have no ticket it cannot be a resumed session. */
-+ if (!s->session->tlsext_tick)
- return 1;
- /* this function is called when we really expect a Certificate
- * message, so permit appropriate message length */
-Index: openssl-0.9.8i/ssl/s3_srvr.c
-===================================================================
---- openssl-0.9.8i.orig/ssl/s3_srvr.c 2008-09-14 21:16:09.000000000 +0300
-+++ openssl-0.9.8i/ssl/s3_srvr.c 2008-11-23 20:37:40.000000000 +0200
-@@ -959,6 +959,59 @@
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-+
-+ /* Check if we want to use external pre-shared secret for this
-+ * handshake for not reused session only. We need to generate
-+ * server_random before calling tls_session_secret_cb in order to allow
-+ * SessionTicket processing to use it in key derivation. */
-+ {
-+ unsigned long Time;
-+ unsigned char *pos;
-+ Time=(unsigned long)time(NULL); /* Time */
-+ pos=s->s3->server_random;
-+ l2n(Time,pos);
-+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
-+ {
-+ al=SSL_AD_INTERNAL_ERROR;
-+ goto f_err;
-+ }
-+ }
-+
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
- #endif
- /* Worst case, we will use the NULL compression, but if we have other
- * options, we will now look for them. We have i-1 compression
-@@ -1097,16 +1150,22 @@
- unsigned char *buf;
- unsigned char *p,*d;
- int i,sl;
-- unsigned long l,Time;
-+ unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+ unsigned long Time;
-+#endif
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- buf=(unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
- p=s->s3->server_random;
-+ /* Generate server_random if it was not needed previously */
- Time=(unsigned long)time(NULL); /* Time */
- l2n(Time,p);
- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
- return -1;
-+#endif
- /* Do the message type and length last */
- d=p= &(buf[4]);
-
-Index: openssl-0.9.8i/ssl/ssl_err.c
-===================================================================
---- openssl-0.9.8i.orig/ssl/ssl_err.c 2008-08-13 22:44:44.000000000 +0300
-+++ openssl-0.9.8i/ssl/ssl_err.c 2008-11-23 20:33:43.000000000 +0200
-@@ -253,6 +253,7 @@
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
- {0,NULL}
- };
-
-Index: openssl-0.9.8i/ssl/ssl.h
-===================================================================
---- openssl-0.9.8i.orig/ssl/ssl.h 2008-08-13 22:44:44.000000000 +0300
-+++ openssl-0.9.8i/ssl/ssl.h 2008-11-23 20:35:41.000000000 +0200
-@@ -344,6 +344,7 @@
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -362,6 +363,9 @@
-
- DECLARE_STACK_OF(SSL_CIPHER)
-
-+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -1034,6 +1038,18 @@
-
- /* RFC4507 session ticket expected to be received or sent */
- int tlsext_ticket_expected;
-+
-+ /* TLS Session Ticket extension override */
-+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-+
-+ /* TLS Session Ticket extension callback */
-+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
-+ void *tls_session_ticket_ext_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
-+
- SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
- #define session_ctx initial_ctx
- #else
-@@ -1632,6 +1648,15 @@
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+ void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1824,6 +1849,7 @@
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-Index: openssl-0.9.8i/ssl/ssl_sess.c
-===================================================================
---- openssl-0.9.8i.orig/ssl/ssl_sess.c 2008-06-04 21:35:27.000000000 +0300
-+++ openssl-0.9.8i/ssl/ssl_sess.c 2008-11-23 20:32:24.000000000 +0200
-@@ -707,6 +707,61 @@
- return(s->session_timeout);
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+ {
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+ }
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+ void *arg)
-+ {
-+ if (s == NULL) return(0);
-+ s->tls_session_ticket_ext_cb = cb;
-+ s->tls_session_ticket_ext_cb_arg = arg;
-+ return(1);
-+ }
-+
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
-+ {
-+ if (s->version >= TLS1_VERSION)
-+ {
-+ if (s->tlsext_session_ticket)
-+ {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ s->tlsext_session_ticket = NULL;
-+ }
-+
-+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
-+ if (!s->tlsext_session_ticket)
-+ {
-+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ if (ext_data)
-+ {
-+ s->tlsext_session_ticket->length = ext_len;
-+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
-+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
-+ }
-+ else
-+ {
-+ s->tlsext_session_ticket->length = 0;
-+ s->tlsext_session_ticket->data = NULL;
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-Index: openssl-0.9.8i/ssl/t1_lib.c
-===================================================================
---- openssl-0.9.8i.orig/ssl/t1_lib.c 2008-09-04 01:13:04.000000000 +0300
-+++ openssl-0.9.8i/ssl/t1_lib.c 2008-11-23 20:31:20.000000000 +0200
-@@ -106,6 +106,12 @@
-
- void tls1_free(SSL *s)
- {
-+#ifndef OPENSSL_NO_TLSEXT
-+ if (s->tlsext_session_ticket)
-+ {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ }
-+#endif
- ssl3_free(s);
- }
-
-@@ -175,8 +181,23 @@
- int ticklen;
- if (s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
-+ else if (s->session && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data)
-+ {
-+ ticklen = s->tlsext_session_ticket->length;
-+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+ if (!s->session->tlsext_tick)
-+ return NULL;
-+ memcpy(s->session->tlsext_tick,
-+ s->tlsext_session_ticket->data,
-+ ticklen);
-+ s->session->tlsext_ticklen = ticklen;
-+ }
- else
- ticklen = 0;
-+ if (ticklen == 0 && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data == NULL)
-+ goto skip_ext;
- /* Check for enough room 2 for extension type, 2 for len
- * rest for ticket
- */
-@@ -190,6 +211,7 @@
- ret += ticklen;
- }
- }
-+ skip_ext:
-
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
- {
-@@ -407,6 +429,15 @@
- }
-
- }
-+ else if (type == TLSEXT_TYPE_session_ticket)
-+ {
-+ if (s->tls_session_ticket_ext_cb &&
-+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
-+ {
-+ *al = TLS1_AD_INTERNAL_ERROR;
-+ return 0;
-+ }
-+ }
- else if (type == TLSEXT_TYPE_status_request
- && s->ctx->tlsext_status_cb)
- {
-@@ -553,6 +584,12 @@
- }
- else if (type == TLSEXT_TYPE_session_ticket)
- {
-+ if (s->tls_session_ticket_ext_cb &&
-+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
-+ {
-+ *al = TLS1_AD_INTERNAL_ERROR;
-+ return 0;
-+ }
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
- || (size > 0))
- {
-@@ -776,6 +813,15 @@
- s->tlsext_ticket_expected = 1;
- return 0; /* Cache miss */
- }
-+ if (s->tls_session_secret_cb)
-+ {
-+ /* Indicate cache miss here and instead of
-+ * generating the session from ticket now,
-+ * trigger abbreviated handshake based on
-+ * external mechanism to calculate the master
-+ * secret later. */
-+ return 0;
-+ }
- return tls_decrypt_ticket(s, p, size, session_id, len,
- ret);
- }
-Index: openssl-0.9.8i/ssl/tls1.h
-===================================================================
---- openssl-0.9.8i.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300
-+++ openssl-0.9.8i/ssl/tls1.h 2008-11-23 20:22:38.000000000 +0200
-@@ -398,6 +398,13 @@
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_session_ticket_ext_st
-+ {
-+ unsigned short length;
-+ void *data;
-+ };
-+
- #ifdef __cplusplus
- }
- #endif
-Index: openssl-0.9.8i/util/ssleay.num
-===================================================================
---- openssl-0.9.8i.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300
-+++ openssl-0.9.8i/util/ssleay.num 2008-11-23 20:22:05.000000000 +0200
-@@ -242,3 +242,5 @@
- SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
- SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
- SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
-+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
diff --git a/contrib/wpa/patches/openssl-0.9.8x-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8za-tls-extensions.patch
index d1c0dbe..82bfe23 100644
--- a/contrib/wpa/patches/openssl-0.9.8x-tls-extensions.patch
+++ b/contrib/wpa/patches/openssl-0.9.8za-tls-extensions.patch
@@ -4,15 +4,15 @@ 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.8x does not enable TLS extension support by default, so it
+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.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
---- openssl-0.9.8x.orig/ssl/s3_clnt.c 2011-12-26 21:38:28.000000000 +0200
-+++ openssl-0.9.8x/ssl/s3_clnt.c 2012-07-07 10:46:31.501140621 +0300
-@@ -757,6 +757,21 @@ int ssl3_get_server_hello(SSL *s)
+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;
}
@@ -27,6 +27,7 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
+ {
+ 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 */
@@ -34,7 +35,7 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
-@@ -2725,11 +2740,8 @@ int ssl3_check_finished(SSL *s)
+@@ -2745,11 +2760,8 @@ int ssl3_check_finished(SSL *s)
{
int ok;
long n;
@@ -48,10 +49,10 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
return 1;
/* this function is called when we really expect a Certificate
* message, so permit appropriate message length */
-diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
---- openssl-0.9.8x.orig/ssl/s3_srvr.c 2012-02-16 17:21:17.000000000 +0200
-+++ openssl-0.9.8x/ssl/s3_srvr.c 2012-07-07 10:46:31.501140621 +0300
-@@ -1009,6 +1009,59 @@ int ssl3_get_client_hello(SSL *s)
+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;
}
@@ -111,7 +112,7 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
#endif
/* Worst case, we will use the NULL compression, but if we have other
* options, we will now look for them. We have i-1 compression
-@@ -1147,16 +1200,22 @@ int ssl3_send_server_hello(SSL *s)
+@@ -1161,16 +1214,22 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
@@ -135,10 +136,10 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
/* Do the message type and length last */
d=p= &(buf[4]);
-diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c
---- openssl-0.9.8x.orig/ssl/ssl_err.c 2012-03-12 16:50:55.000000000 +0200
-+++ openssl-0.9.8x/ssl/ssl_err.c 2012-07-07 10:46:31.501140621 +0300
-@@ -264,6 +264,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+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"},
@@ -146,9 +147,9 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c
{0,NULL}
};
-diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
---- openssl-0.9.8x.orig/ssl/ssl.h 2012-03-12 16:50:55.000000000 +0200
-+++ openssl-0.9.8x/ssl/ssl.h 2012-07-07 10:46:31.501140621 +0300
+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. */
@@ -167,7 +168,7 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
-@@ -1050,6 +1054,18 @@ struct ssl_st
+@@ -1053,6 +1057,18 @@ struct ssl_st
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
@@ -186,7 +187,7 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
-@@ -1663,6 +1679,15 @@ void *SSL_COMP_get_compression_methods(v
+@@ -1668,6 +1684,15 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
@@ -202,7 +203,7 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
-@@ -1866,6 +1891,7 @@ void ERR_load_SSL_strings(void);
+@@ -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
@@ -210,9 +211,9 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c
---- openssl-0.9.8x.orig/ssl/ssl_sess.c 2010-02-01 18:48:40.000000000 +0200
-+++ openssl-0.9.8x/ssl/ssl_sess.c 2012-07-07 10:46:31.501140621 +0300
+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);
}
@@ -275,9 +276,9 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c
typedef struct timeout_param_st
{
SSL_CTX *ctx;
-diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
---- openssl-0.9.8x.orig/ssl/t1_lib.c 2012-01-04 16:25:10.000000000 +0200
-+++ openssl-0.9.8x/ssl/t1_lib.c 2012-07-07 10:47:31.153140501 +0300
+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)
@@ -323,7 +324,7 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
s->version != DTLS1_VERSION)
-@@ -486,6 +508,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
+@@ -574,6 +596,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
return 0;
renegotiate_seen = 1;
}
@@ -339,7 +340,7 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
else if (type == TLSEXT_TYPE_status_request &&
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
{
-@@ -663,6 +694,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
+@@ -751,6 +782,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
}
else if (type == TLSEXT_TYPE_session_ticket)
{
@@ -352,7 +353,7 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|| (size > 0))
{
-@@ -920,6 +957,15 @@ int tls1_process_ticket(SSL *s, unsigned
+@@ -1043,6 +1080,15 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
@@ -368,10 +369,10 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
-diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h
---- openssl-0.9.8x.orig/ssl/tls1.h 2009-11-08 16:51:54.000000000 +0200
-+++ openssl-0.9.8x/ssl/tls1.h 2012-07-07 10:46:31.501140621 +0300
-@@ -401,6 +401,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+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
@@ -385,9 +386,9 @@ diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h
#ifdef __cplusplus
}
#endif
-diff -upr openssl-0.9.8x.orig/util/ssleay.num openssl-0.9.8x/util/ssleay.num
---- openssl-0.9.8x.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300
-+++ openssl-0.9.8x/util/ssleay.num 2012-07-07 10:46:31.505140623 +0300
+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
diff --git a/contrib/wpa/patches/openssl-0.9.9-session-ticket.patch b/contrib/wpa/patches/openssl-0.9.9-session-ticket.patch
deleted file mode 100644
index 3afa639..0000000
--- a/contrib/wpa/patches/openssl-0.9.9-session-ticket.patch
+++ /dev/null
@@ -1,374 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-NOTE: This patch (without SSL_set_hello_extension() wrapper) was
-merged into the upstream OpenSSL 0.9.9 tree and as such, an external
-patch for EAP-FAST support is not needed anymore.
-
-
-
-Index: openssl-SNAP-20081111/ssl/s3_clnt.c
-===================================================================
---- openssl-SNAP-20081111.orig/ssl/s3_clnt.c
-+++ openssl-SNAP-20081111/ssl/s3_clnt.c
-@@ -788,6 +788,23 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key,
-+ &s->session->master_key_length,
-+ NULL, &pref_cipher,
-+ s->tls_session_secret_cb_arg))
-+ {
-+ s->session->cipher = pref_cipher ?
-+ pref_cipher : ssl_get_cipher_by_char(s, p+j);
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
-@@ -2927,11 +2944,8 @@ static int ssl3_check_finished(SSL *s)
- {
- int ok;
- long n;
-- /* If we have no ticket or session ID is non-zero length (a match of
-- * a non-zero session length would never reach here) it cannot be a
-- * resumed session.
-- */
-- if (!s->session->tlsext_tick || s->session->session_id_length)
-+ /* If we have no ticket it cannot be a resumed session. */
-+ if (!s->session->tlsext_tick)
- return 1;
- /* this function is called when we really expect a Certificate
- * message, so permit appropriate message length */
-Index: openssl-SNAP-20081111/ssl/s3_srvr.c
-===================================================================
---- openssl-SNAP-20081111.orig/ssl/s3_srvr.c
-+++ openssl-SNAP-20081111/ssl/s3_srvr.c
-@@ -1010,6 +1010,59 @@ int ssl3_get_client_hello(SSL *s)
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-+
-+ /* Check if we want to use external pre-shared secret for this
-+ * handshake for not reused session only. We need to generate
-+ * server_random before calling tls_session_secret_cb in order to allow
-+ * SessionTicket processing to use it in key derivation. */
-+ {
-+ unsigned long Time;
-+ unsigned char *pos;
-+ Time=(unsigned long)time(NULL); /* Time */
-+ pos=s->s3->server_random;
-+ l2n(Time,pos);
-+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
-+ {
-+ al=SSL_AD_INTERNAL_ERROR;
-+ goto f_err;
-+ }
-+ }
-+
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
- #endif
-
- /* Worst case, we will use the NULL compression, but if we have other
-@@ -1134,16 +1187,22 @@ int ssl3_send_server_hello(SSL *s)
- unsigned char *buf;
- unsigned char *p,*d;
- int i,sl;
-- unsigned long l,Time;
-+ unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+ unsigned long Time;
-+#endif
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- buf=(unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
- p=s->s3->server_random;
-+ /* Generate server_random if it was not needed previously */
- Time=(unsigned long)time(NULL); /* Time */
- l2n(Time,p);
- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
- return -1;
-+#endif
- /* Do the message type and length last */
- d=p= &(buf[4]);
-
-Index: openssl-SNAP-20081111/ssl/ssl_err.c
-===================================================================
---- openssl-SNAP-20081111.orig/ssl/ssl_err.c
-+++ openssl-SNAP-20081111/ssl/ssl_err.c
-@@ -263,6 +263,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
- {0,NULL}
- };
-
-Index: openssl-SNAP-20081111/ssl/ssl.h
-===================================================================
---- openssl-SNAP-20081111.orig/ssl/ssl.h
-+++ openssl-SNAP-20081111/ssl/ssl.h
-@@ -355,6 +355,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -378,6 +379,8 @@ typedef struct ssl_cipher_st
-
- DECLARE_STACK_OF(SSL_CIPHER)
-
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -1145,6 +1148,13 @@ struct ssl_st
- void *tlsext_opaque_prf_input;
- size_t tlsext_opaque_prf_input_len;
-
-+ /* TLS Session Ticket extension override */
-+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
-+
- SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
- #define session_ctx initial_ctx
- #else
-@@ -1746,6 +1756,16 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* NOTE: This function will be removed; it is only here for backwards
-+ * compatibility for the API during testing. */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
-+
-+/* TLS extensions functions */
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1948,6 +1968,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_PRF 284
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-Index: openssl-SNAP-20081111/ssl/ssl_sess.c
-===================================================================
---- openssl-SNAP-20081111.orig/ssl/ssl_sess.c
-+++ openssl-SNAP-20081111/ssl/ssl_sess.c
-@@ -834,6 +834,62 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return(s->session_timeout);
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+ {
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+ }
-+
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
-+ {
-+ if (s->version >= TLS1_VERSION)
-+ {
-+ if (s->tlsext_session_ticket)
-+ {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ s->tlsext_session_ticket = NULL;
-+ }
-+
-+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
-+ if (!s->tlsext_session_ticket)
-+ {
-+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ if (ext_data)
-+ {
-+ s->tlsext_session_ticket->length = ext_len;
-+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
-+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
-+ }
-+ else
-+ {
-+ s->tlsext_session_ticket->length = 0;
-+ s->tlsext_session_ticket->data = NULL;
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+ }
-+
-+/* NOTE: This function will be removed; it is only here for backwards
-+ * compatibility for the API during testing. */
-+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
-+ {
-+ if (ext_type != TLSEXT_TYPE_session_ticket)
-+ return 0;
-+
-+ return SSL_set_session_ticket_ext(s, ext_data, ext_len);
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-Index: openssl-SNAP-20081111/ssl/t1_lib.c
-===================================================================
---- openssl-SNAP-20081111.orig/ssl/t1_lib.c
-+++ openssl-SNAP-20081111/ssl/t1_lib.c
-@@ -154,6 +154,12 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+#ifndef OPENSSL_NO_TLSEXT
-+ if (s->tlsext_session_ticket)
-+ {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
- ssl3_free(s);
- }
-
-@@ -357,8 +363,23 @@ unsigned char *ssl_add_clienthello_tlsex
- int ticklen;
- if (s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
-+ else if (s->session && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data)
-+ {
-+ ticklen = s->tlsext_session_ticket->length;
-+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+ if (!s->session->tlsext_tick)
-+ return NULL;
-+ memcpy(s->session->tlsext_tick,
-+ s->tlsext_session_ticket->data,
-+ ticklen);
-+ s->session->tlsext_ticklen = ticklen;
-+ }
- else
- ticklen = 0;
-+ if (ticklen == 0 && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data == NULL)
-+ goto skip_ext;
- /* Check for enough room 2 for extension type, 2 for len
- * rest for ticket
- */
-@@ -371,6 +392,7 @@ unsigned char *ssl_add_clienthello_tlsex
- ret += ticklen;
- }
- }
-+ skip_ext:
-
- #ifdef TLSEXT_TYPE_opaque_prf_input
- if (s->s3->client_opaque_prf_input != NULL)
-@@ -1435,6 +1457,15 @@ int tls1_process_ticket(SSL *s, unsigned
- s->tlsext_ticket_expected = 1;
- return 0; /* Cache miss */
- }
-+ if (s->tls_session_secret_cb)
-+ {
-+ /* Indicate cache miss here and instead of
-+ * generating the session from ticket now,
-+ * trigger abbreviated handshake based on
-+ * external mechanism to calculate the master
-+ * secret later. */
-+ return 0;
-+ }
- return tls_decrypt_ticket(s, p, size, session_id, len,
- ret);
- }
-Index: openssl-SNAP-20081111/ssl/tls1.h
-===================================================================
---- openssl-SNAP-20081111.orig/ssl/tls1.h
-+++ openssl-SNAP-20081111/ssl/tls1.h
-@@ -512,6 +512,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS Session Ticket extension struct */
-+struct tls_session_ticket_ext_st
-+ {
-+ unsigned short length;
-+ void *data;
-+ };
-+
- #ifdef __cplusplus
- }
- #endif
-Index: openssl-SNAP-20081111/util/ssleay.num
-===================================================================
---- openssl-SNAP-20081111.orig/util/ssleay.num
-+++ openssl-SNAP-20081111/util/ssleay.num
-@@ -254,3 +254,5 @@ PEM_read_bio_SSL_SESSION
- SSL_CTX_set_psk_server_callback 303 EXIST::FUNCTION:PSK
- SSL_get_psk_identity 304 EXIST::FUNCTION:PSK
- PEM_write_SSL_SESSION 305 EXIST:!WIN16:FUNCTION:
-+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
diff --git a/contrib/wpa/src/ap/accounting.c b/contrib/wpa/src/ap/accounting.c
index 9540531..7c55146 100644
--- a/contrib/wpa/src/ap/accounting.c
+++ b/contrib/wpa/src/ap/accounting.c
@@ -10,7 +10,8 @@
#include "utils/common.h"
#include "utils/eloop.h"
-#include "drivers/driver.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
@@ -44,19 +45,26 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
if (msg == NULL) {
- printf("Could not create net RADIUS packet\n");
+ wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return NULL;
}
if (sta) {
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
- os_snprintf(buf, sizeof(buf), "%08X-%08X",
- sta->acct_session_id_hi, sta->acct_session_id_lo);
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Acct-Session-Id\n");
- goto fail;
+ 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));
@@ -64,7 +72,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
status_type)) {
- printf("Could not add Acct-Status-Type\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
goto fail;
}
@@ -74,7 +82,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
- printf("Could not add Acct-Authentic\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
goto fail;
}
@@ -99,7 +107,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
len)) {
- printf("Could not add User-Name\n");
+ wpa_printf(MSG_INFO, "Could not add User-Name");
goto fail;
}
}
@@ -117,7 +125,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
val, len)) {
- printf("Could not add Class\n");
+ wpa_printf(MSG_INFO, "Could not add Class");
goto fail;
}
}
@@ -202,7 +210,6 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
{
struct radius_msg *msg;
- struct os_time t;
int interval;
if (sta->acct_session_started)
@@ -213,8 +220,7 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
"starting accounting session %08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
- os_get_time(&t);
- sta->acct_session_start = t.sec;
+ os_get_reltime(&sta->acct_session_start);
sta->last_rx_bytes = sta->last_tx_bytes = 0;
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
hostapd_drv_sta_clear_stats(hapd, sta->addr);
@@ -244,6 +250,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
struct radius_msg *msg;
int cause = sta->acct_terminate_cause;
struct hostap_sta_driver_data data;
+ struct os_reltime now_r, diff;
struct os_time now;
u32 gigawords;
@@ -254,14 +261,16 @@ static void accounting_sta_report(struct hostapd_data *hapd,
stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
if (!msg) {
- printf("Could not create RADIUS Accounting message\n");
+ wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
return;
}
+ os_get_reltime(&now_r);
os_get_time(&now);
+ os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
- now.sec - sta->acct_session_start)) {
- printf("Could not add Acct-Session-Time\n");
+ diff.sec)) {
+ wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
goto fail;
}
@@ -269,19 +278,19 @@ static void accounting_sta_report(struct hostapd_data *hapd,
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_PACKETS,
data.rx_packets)) {
- printf("Could not add Acct-Input-Packets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
data.tx_packets)) {
- printf("Could not add Acct-Output-Packets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_OCTETS,
data.rx_bytes)) {
- printf("Could not add Acct-Input-Octets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
goto fail;
}
gigawords = sta->acct_input_gigawords;
@@ -292,13 +301,13 @@ static void accounting_sta_report(struct hostapd_data *hapd,
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
gigawords)) {
- printf("Could not add Acct-Input-Gigawords\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
data.tx_bytes)) {
- printf("Could not add Acct-Output-Octets\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
goto fail;
}
gigawords = sta->acct_output_gigawords;
@@ -309,14 +318,14 @@ static void accounting_sta_report(struct hostapd_data *hapd,
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
gigawords)) {
- printf("Could not add Acct-Output-Gigawords\n");
+ 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)) {
- printf("Could not add Event-Timestamp\n");
+ wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
goto fail;
}
@@ -326,7 +335,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
if (stop && cause &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
cause)) {
- printf("Could not add Acct-Terminate-Cause\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
goto fail;
}
@@ -400,13 +409,12 @@ accounting_receive(struct radius_msg *msg, struct radius_msg *req,
void *data)
{
if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
- printf("Unknown RADIUS message code\n");
+ wpa_printf(MSG_INFO, "Unknown RADIUS message code");
return RADIUS_RX_UNKNOWN;
}
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
- printf("Incoming RADIUS packet did not have correct "
- "Authenticator - dropped\n");
+ wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
@@ -432,7 +440,7 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
{
- printf("Could not add Acct-Terminate-Cause\n");
+ wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
radius_msg_free(msg);
return;
}
diff --git a/contrib/wpa/src/ap/acs.c b/contrib/wpa/src/ap/acs.c
new file mode 100644
index 0000000..ae7f6c3
--- /dev/null
+++ b/contrib/wpa/src/ap/acs.c
@@ -0,0 +1,949 @@
+/*
+ * ACS - Automatic Channel Selection module
+ * Copyright (c) 2011, Atheros Communications
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <math.h>
+
+#include "utils/common.h"
+#include "utils/list.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "ap_config.h"
+#include "hw_features.h"
+#include "acs.h"
+
+/*
+ * Automatic Channel Selection
+ * ===========================
+ *
+ * More info at
+ * ------------
+ * http://wireless.kernel.org/en/users/Documentation/acs
+ *
+ * How to use
+ * ----------
+ * - make sure you have CONFIG_ACS=y in hostapd's .config
+ * - use channel=0 or channel=acs to enable ACS
+ *
+ * How does it work
+ * ----------------
+ * 1. passive scans are used to collect survey data
+ * (it is assumed that scan trigger collection of survey data in driver)
+ * 2. interference factor is calculated for each channel
+ * 3. ideal channel is picked depending on channel width by using adjacent
+ * channel interference factors
+ *
+ * Known limitations
+ * -----------------
+ * - Current implementation depends heavily on the amount of time willing to
+ * spend gathering survey data during hostapd startup. Short traffic bursts
+ * may be missed and a suboptimal channel may be picked.
+ * - Ideal channel may end up overlapping a channel with 40 MHz intolerant BSS
+ *
+ * Todo / Ideas
+ * ------------
+ * - implement other interference computation methods
+ * - BSS/RSSI based
+ * - spectral scan based
+ * (should be possibly to hook this up with current ACS scans)
+ * - add wpa_supplicant support (for P2P)
+ * - collect a histogram of interference over time allowing more educated
+ * guess about an ideal channel (perhaps CSA could be used to migrate AP to a
+ * new "better" channel while running)
+ * - include neighboring BSS scan to avoid conflicts with 40 MHz intolerant BSSs
+ * when choosing the ideal channel
+ *
+ * Survey interference factor implementation details
+ * -------------------------------------------------
+ * Generic interference_factor in struct hostapd_channel_data is used.
+ *
+ * The survey interference factor is defined as the ratio of the
+ * observed busy time over the time we spent on the channel,
+ * this value is then amplified by the observed noise floor on
+ * the channel in comparison to the lowest noise floor observed
+ * on the entire band.
+ *
+ * This corresponds to:
+ * ---
+ * (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf)
+ * ---
+ *
+ * The coefficient of 2 reflects the way power in "far-field"
+ * radiation decreases as the square of distance from the antenna [1].
+ * What this does is it decreases the observed busy time ratio if the
+ * noise observed was low but increases it if the noise was high,
+ * proportionally to the way "far field" radiation changes over
+ * distance.
+ *
+ * If channel busy time is not available the fallback is to use channel RX time.
+ *
+ * Since noise floor is in dBm it is necessary to convert it into Watts so that
+ * combined channel interference (e.g., HT40, which uses two channels) can be
+ * calculated easily.
+ * ---
+ * (busy time - tx time) / (active time - tx time) *
+ * 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
+ * ---
+ *
+ * However to account for cases where busy/rx time is 0 (channel load is then
+ * 0%) channel noise floor signal power is combined into the equation so a
+ * channel with lower noise floor is preferred. The equation becomes:
+ * ---
+ * 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) *
+ * 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
+ * ---
+ *
+ * All this "interference factor" is purely subjective and only time
+ * will tell how usable this is. By using the minimum noise floor we
+ * remove any possible issues due to card calibration. The computation
+ * of the interference factor then is dependent on what the card itself
+ * picks up as the minimum noise, not an actual real possible card
+ * noise value.
+ *
+ * Total interference computation details
+ * --------------------------------------
+ * The above channel interference factor is calculated with no respect to
+ * target operational bandwidth.
+ *
+ * To find an ideal channel the above data is combined by taking into account
+ * the target operational bandwidth and selected band. E.g., on 2.4 GHz channels
+ * overlap with 20 MHz bandwidth, but there is no overlap for 20 MHz bandwidth
+ * on 5 GHz.
+ *
+ * Each valid and possible channel spec (i.e., channel + width) is taken and its
+ * interference factor is computed by summing up interferences of each channel
+ * it overlaps. The one with least total interference is picked up.
+ *
+ * Note: This implies base channel interference factor must be non-negative
+ * allowing easy summing up.
+ *
+ * Example ACS analysis printout
+ * -----------------------------
+ *
+ * ACS: Trying survey-based ACS
+ * ACS: Survey analysis for channel 1 (2412 MHz)
+ * ACS: 1: min_nf=-113 interference_factor=0.0802469 nf=-113 time=162 busy=0 rx=13
+ * ACS: 2: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12
+ * ACS: 3: min_nf=-113 interference_factor=0.0679012 nf=-113 time=162 busy=0 rx=11
+ * ACS: 4: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5
+ * ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4
+ * ACS: * interference factor average: 0.0557166
+ * ACS: Survey analysis for channel 2 (2417 MHz)
+ * ACS: 1: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3
+ * ACS: 2: min_nf=-113 interference_factor=0.0246914 nf=-113 time=162 busy=0 rx=4
+ * ACS: 3: min_nf=-113 interference_factor=0.037037 nf=-113 time=162 busy=0 rx=6
+ * ACS: 4: min_nf=-113 interference_factor=0.149068 nf=-113 time=161 busy=0 rx=24
+ * ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4
+ * ACS: * interference factor average: 0.050832
+ * ACS: Survey analysis for channel 3 (2422 MHz)
+ * ACS: 1: min_nf=-113 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
+ * ACS: 2: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3
+ * ACS: 3: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
+ * ACS: 4: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
+ * ACS: 5: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
+ * ACS: * interference factor average: 0.0148838
+ * ACS: Survey analysis for channel 4 (2427 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
+ * ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9
+ * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
+ * ACS: 4: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3
+ * ACS: 5: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
+ * ACS: * interference factor average: 0.0160801
+ * ACS: Survey analysis for channel 5 (2432 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=0.409938 nf=-113 time=161 busy=0 rx=66
+ * ACS: 2: min_nf=-114 interference_factor=0.0432099 nf=-113 time=162 busy=0 rx=7
+ * ACS: 3: min_nf=-114 interference_factor=0.0124224 nf=-113 time=161 busy=0 rx=2
+ * ACS: 4: min_nf=-114 interference_factor=0.677019 nf=-113 time=161 busy=0 rx=109
+ * ACS: 5: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3
+ * ACS: * interference factor average: 0.232244
+ * ACS: Survey analysis for channel 6 (2437 MHz)
+ * ACS: 1: min_nf=-113 interference_factor=0.552795 nf=-113 time=161 busy=0 rx=89
+ * ACS: 2: min_nf=-113 interference_factor=0.0807453 nf=-112 time=161 busy=0 rx=13
+ * ACS: 3: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5
+ * ACS: 4: min_nf=-113 interference_factor=0.434783 nf=-112 time=161 busy=0 rx=70
+ * ACS: 5: min_nf=-113 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10
+ * ACS: * interference factor average: 0.232298
+ * ACS: Survey analysis for channel 7 (2442 MHz)
+ * ACS: 1: min_nf=-113 interference_factor=0.440994 nf=-112 time=161 busy=0 rx=71
+ * ACS: 2: min_nf=-113 interference_factor=0.385093 nf=-113 time=161 busy=0 rx=62
+ * ACS: 3: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
+ * ACS: 4: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
+ * ACS: 5: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12
+ * ACS: * interference factor average: 0.195031
+ * ACS: Survey analysis for channel 8 (2447 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=0.0496894 nf=-112 time=161 busy=0 rx=8
+ * ACS: 2: min_nf=-114 interference_factor=0.0496894 nf=-114 time=161 busy=0 rx=8
+ * ACS: 3: min_nf=-114 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
+ * ACS: 4: min_nf=-114 interference_factor=0.12963 nf=-113 time=162 busy=0 rx=21
+ * ACS: 5: min_nf=-114 interference_factor=0.166667 nf=-114 time=162 busy=0 rx=27
+ * ACS: * interference factor average: 0.0865885
+ * ACS: Survey analysis for channel 9 (2452 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=0.0124224 nf=-114 time=161 busy=0 rx=2
+ * ACS: 2: min_nf=-114 interference_factor=0.0310559 nf=-114 time=161 busy=0 rx=5
+ * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
+ * ACS: 4: min_nf=-114 interference_factor=0.00617284 nf=-114 time=162 busy=0 rx=1
+ * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
+ * ACS: * interference factor average: 0.00993022
+ * ACS: Survey analysis for channel 10 (2457 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
+ * ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
+ * ACS: 3: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
+ * ACS: 4: min_nf=-114 interference_factor=0.0493827 nf=-114 time=162 busy=0 rx=8
+ * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
+ * ACS: * interference factor average: 0.0136033
+ * ACS: Survey analysis for channel 11 (2462 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
+ * ACS: 2: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0
+ * ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0
+ * ACS: 4: min_nf=-114 interference_factor=0.0432099 nf=-114 time=162 busy=0 rx=7
+ * ACS: 5: min_nf=-114 interference_factor=0.0925926 nf=-114 time=162 busy=0 rx=15
+ * ACS: * interference factor average: 0.0271605
+ * ACS: Survey analysis for channel 12 (2467 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10
+ * ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
+ * ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
+ * ACS: 4: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
+ * ACS: 5: min_nf=-114 interference_factor=0.00617284 nf=-113 time=162 busy=0 rx=1
+ * ACS: * interference factor average: 0.0148992
+ * ACS: Survey analysis for channel 13 (2472 MHz)
+ * ACS: 1: min_nf=-114 interference_factor=0.0745342 nf=-114 time=161 busy=0 rx=12
+ * ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9
+ * ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
+ * ACS: 4: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
+ * ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
+ * ACS: * interference factor average: 0.0260179
+ * ACS: Survey analysis for selected bandwidth 20MHz
+ * ACS: * channel 1: total interference = 0.121432
+ * ACS: * channel 2: total interference = 0.137512
+ * ACS: * channel 3: total interference = 0.369757
+ * ACS: * channel 4: total interference = 0.546338
+ * ACS: * channel 5: total interference = 0.690538
+ * ACS: * channel 6: total interference = 0.762242
+ * ACS: * channel 7: total interference = 0.756092
+ * ACS: * channel 8: total interference = 0.537451
+ * ACS: * channel 9: total interference = 0.332313
+ * ACS: * channel 10: total interference = 0.152182
+ * ACS: * channel 11: total interference = 0.0916111
+ * ACS: * channel 12: total interference = 0.0816809
+ * ACS: * channel 13: total interference = 0.0680776
+ * ACS: Ideal channel is 13 (2472 MHz) with total interference factor of 0.0680776
+ *
+ * [1] http://en.wikipedia.org/wiki/Near_and_far_field
+ */
+
+
+static int acs_request_scan(struct hostapd_iface *iface);
+static int acs_survey_is_sufficient(struct freq_survey *survey);
+
+
+static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
+{
+ struct freq_survey *survey, *tmp;
+
+ if (dl_list_empty(&chan->survey_list))
+ return;
+
+ dl_list_for_each_safe(survey, tmp, &chan->survey_list,
+ struct freq_survey, list) {
+ dl_list_del(&survey->list);
+ os_free(survey);
+ }
+}
+
+
+static void acs_cleanup(struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+
+ if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
+ acs_clean_chan_surveys(chan);
+
+ dl_list_init(&chan->survey_list);
+ chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
+ chan->min_nf = 0;
+ }
+
+ iface->chans_surveyed = 0;
+ iface->acs_num_completed_scans = 0;
+}
+
+
+static void acs_fail(struct hostapd_iface *iface)
+{
+ wpa_printf(MSG_ERROR, "ACS: Failed to start");
+ acs_cleanup(iface);
+ hostapd_disable_iface(iface);
+}
+
+
+static long double
+acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
+{
+ long double factor, busy, total;
+
+ if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY)
+ busy = survey->channel_time_busy;
+ else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX)
+ busy = survey->channel_time_rx;
+ else {
+ /* This shouldn't really happen as survey data is checked in
+ * acs_sanity_check() */
+ wpa_printf(MSG_ERROR, "ACS: Survey data missing");
+ return 0;
+ }
+
+ total = survey->channel_time;
+
+ if (survey->filled & SURVEY_HAS_CHAN_TIME_TX) {
+ busy -= survey->channel_time_tx;
+ total -= survey->channel_time_tx;
+ }
+
+ /* TODO: figure out the best multiplier for noise floor base */
+ factor = pow(10, survey->nf / 5.0L) +
+ (busy / total) *
+ pow(2, pow(10, (long double) survey->nf / 10.0L) -
+ pow(10, (long double) min_nf / 10.0L));
+
+ return factor;
+}
+
+
+static void
+acs_survey_chan_interference_factor(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ struct freq_survey *survey;
+ unsigned int i = 0;
+ long double int_factor = 0;
+ unsigned count = 0;
+
+ if (dl_list_empty(&chan->survey_list))
+ return;
+
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ return;
+
+ chan->interference_factor = 0;
+
+ dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
+ {
+ i++;
+
+ if (!acs_survey_is_sufficient(survey)) {
+ wpa_printf(MSG_DEBUG, "ACS: %d: insufficient data", i);
+ continue;
+ }
+
+ count++;
+ int_factor = acs_survey_interference_factor(survey,
+ iface->lowest_nf);
+ chan->interference_factor += int_factor;
+ wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu",
+ i, chan->min_nf, int_factor,
+ survey->nf, (unsigned long) survey->channel_time,
+ (unsigned long) survey->channel_time_busy,
+ (unsigned long) survey->channel_time_rx);
+ }
+
+ if (!count)
+ return;
+ chan->interference_factor /= count;
+}
+
+
+static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
+{
+ const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
+ 157, 184, 192 };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(allowed); i++)
+ if (chan->chan == allowed[i])
+ return 1;
+
+ return 0;
+}
+
+
+static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
+{
+ const int allowed[] = { 36, 52, 100, 116, 132, 149 };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(allowed); i++)
+ if (chan->chan == allowed[i])
+ return 1;
+
+ return 0;
+}
+
+
+static int acs_survey_is_sufficient(struct freq_survey *survey)
+{
+ if (!(survey->filled & SURVEY_HAS_NF)) {
+ wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
+ return 0;
+ }
+
+ if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
+ wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
+ return 0;
+ }
+
+ if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
+ !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
+ wpa_printf(MSG_INFO,
+ "ACS: Survey is missing RX and busy time (at least one is required)");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
+{
+ struct freq_survey *survey;
+ int ret = -1;
+
+ dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
+ {
+ if (acs_survey_is_sufficient(survey)) {
+ ret = 1;
+ break;
+ }
+ ret = 0;
+ }
+
+ if (ret == -1)
+ ret = 1; /* no survey list entries */
+
+ if (!ret) {
+ wpa_printf(MSG_INFO,
+ "ACS: Channel %d has insufficient survey data",
+ chan->chan);
+ }
+
+ return ret;
+}
+
+
+static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+ int valid = 0;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ if (!acs_survey_list_is_sufficient(chan))
+ continue;
+
+ valid++;
+ }
+
+ /* We need at least survey data for one channel */
+ return !!valid;
+}
+
+
+static int acs_usable_chan(struct hostapd_channel_data *chan)
+{
+ if (dl_list_empty(&chan->survey_list))
+ return 0;
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ return 0;
+ if (!acs_survey_list_is_sufficient(chan))
+ return 0;
+ return 1;
+}
+
+
+static int is_in_chanlist(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ int *entry;
+
+ if (!iface->conf->chanlist)
+ return 1;
+
+ for (entry = iface->conf->chanlist; *entry != -1; entry++) {
+ if (*entry == chan->chan)
+ return 1;
+ }
+ return 0;
+}
+
+
+static void acs_survey_all_chans_intereference_factor(
+ struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+
+ if (!acs_usable_chan(chan))
+ continue;
+
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
+ wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
+ chan->chan, chan->freq);
+
+ acs_survey_chan_interference_factor(iface, chan);
+
+ wpa_printf(MSG_DEBUG, "ACS: * interference factor average: %Lg",
+ chan->interference_factor);
+ }
+}
+
+
+static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
+ int freq)
+{
+ struct hostapd_channel_data *chan;
+ int i;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ if (chan->freq == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+
+
+static int is_24ghz_mode(enum hostapd_hw_mode mode)
+{
+ return mode == HOSTAPD_MODE_IEEE80211B ||
+ mode == HOSTAPD_MODE_IEEE80211G;
+}
+
+
+static int is_common_24ghz_chan(int chan)
+{
+ return chan == 1 || chan == 6 || chan == 11;
+}
+
+
+#ifndef ACS_ADJ_WEIGHT
+#define ACS_ADJ_WEIGHT 0.85
+#endif /* ACS_ADJ_WEIGHT */
+
+#ifndef ACS_NEXT_ADJ_WEIGHT
+#define ACS_NEXT_ADJ_WEIGHT 0.55
+#endif /* ACS_NEXT_ADJ_WEIGHT */
+
+#ifndef ACS_24GHZ_PREFER_1_6_11
+/*
+ * Select commonly used channels 1, 6, 11 by default even if a neighboring
+ * channel has a smaller interference factor as long as it is not better by more
+ * than this multiplier.
+ */
+#define ACS_24GHZ_PREFER_1_6_11 0.8
+#endif /* ACS_24GHZ_PREFER_1_6_11 */
+
+/*
+ * At this point it's assumed chan->interface_factor has been computed.
+ * This function should be reusable regardless of interference computation
+ * option (survey, BSS, spectral, ...). chan->interference factor must be
+ * summable (i.e., must be always greater than zero).
+ */
+static struct hostapd_channel_data *
+acs_find_ideal_chan(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
+ *rand_chan = NULL;
+ long double factor, ideal_factor = 0;
+ int i, j;
+ int n_chans = 1;
+ unsigned int k;
+
+ /* TODO: HT40- support */
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel == -1) {
+ wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
+ return NULL;
+ }
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel)
+ n_chans = 2;
+
+ if (iface->conf->ieee80211ac &&
+ iface->conf->vht_oper_chwidth == 1)
+ n_chans = 4;
+
+ /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */
+
+ wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
+ n_chans == 1 ? 20 :
+ n_chans == 2 ? 40 :
+ n_chans == 4 ? 80 :
+ -1);
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ double total_weight;
+ struct acs_bias *bias, tmp_bias;
+
+ chan = &iface->current_mode->channels[i];
+
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
+ /* HT40 on 5 GHz has a limited set of primary channels as per
+ * 11n Annex J */
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ iface->conf->ieee80211n &&
+ iface->conf->secondary_channel &&
+ !acs_usable_ht40_chan(chan)) {
+ wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40",
+ chan->chan);
+ continue;
+ }
+
+ 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;
+ }
+
+ factor = 0;
+ if (acs_usable_chan(chan))
+ factor = chan->interference_factor;
+ total_weight = 1;
+
+ for (j = 1; j < n_chans; j++) {
+ adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
+ if (!adj_chan)
+ break;
+
+ if (acs_usable_chan(adj_chan)) {
+ factor += adj_chan->interference_factor;
+ total_weight += 1;
+ }
+ }
+
+ if (j != n_chans) {
+ wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth",
+ chan->chan);
+ continue;
+ }
+
+ /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
+ * channel interference factor. */
+ if (is_24ghz_mode(iface->current_mode->mode)) {
+ for (j = 0; j < n_chans; j++) {
+ adj_chan = acs_find_chan(iface, chan->freq +
+ (j * 20) - 5);
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_ADJ_WEIGHT;
+ }
+
+ adj_chan = acs_find_chan(iface, chan->freq +
+ (j * 20) - 10);
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_NEXT_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_NEXT_ADJ_WEIGHT;
+ }
+
+ adj_chan = acs_find_chan(iface, chan->freq +
+ (j * 20) + 5);
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_ADJ_WEIGHT;
+ }
+
+ adj_chan = acs_find_chan(iface, chan->freq +
+ (j * 20) + 10);
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_NEXT_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_NEXT_ADJ_WEIGHT;
+ }
+ }
+ }
+
+ factor /= total_weight;
+
+ bias = NULL;
+ if (iface->conf->acs_chan_bias) {
+ for (k = 0; k < iface->conf->num_acs_chan_bias; k++) {
+ bias = &iface->conf->acs_chan_bias[k];
+ if (bias->channel == chan->chan)
+ break;
+ bias = NULL;
+ }
+ } else if (is_24ghz_mode(iface->current_mode->mode) &&
+ is_common_24ghz_chan(chan->chan)) {
+ tmp_bias.channel = chan->chan;
+ tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
+ bias = &tmp_bias;
+ }
+
+ if (bias) {
+ factor *= bias->bias;
+ wpa_printf(MSG_DEBUG,
+ "ACS: * channel %d: total interference = %Lg (%f bias)",
+ chan->chan, factor, bias->bias);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "ACS: * channel %d: total interference = %Lg",
+ chan->chan, factor);
+ }
+
+ if (acs_usable_chan(chan) &&
+ (!ideal_chan || factor < ideal_factor)) {
+ ideal_factor = factor;
+ ideal_chan = chan;
+ }
+
+ /* This channel would at least be usable */
+ if (!rand_chan)
+ rand_chan = chan;
+ }
+
+ if (ideal_chan) {
+ wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
+ ideal_chan->chan, ideal_chan->freq, ideal_factor);
+ return ideal_chan;
+ }
+
+ return rand_chan;
+}
+
+
+static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
+{
+ int offset;
+
+ wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
+
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ offset = 2 * iface->conf->secondary_channel;
+ break;
+ case VHT_CHANWIDTH_80MHZ:
+ offset = 6;
+ break;
+ default:
+ /* TODO: How can this be calculated? Adjust
+ * acs_find_ideal_chan() */
+ wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now");
+ return;
+ }
+
+ iface->conf->vht_oper_centr_freq_seg0_idx =
+ iface->conf->channel + offset;
+}
+
+
+static int acs_study_survey_based(struct hostapd_iface *iface)
+{
+ wpa_printf(MSG_DEBUG, "ACS: Trying survey-based ACS");
+
+ if (!iface->chans_surveyed) {
+ wpa_printf(MSG_ERROR, "ACS: Unable to collect survey data");
+ return -1;
+ }
+
+ if (!acs_surveys_are_sufficient(iface)) {
+ wpa_printf(MSG_ERROR, "ACS: Surveys have insufficient data");
+ return -1;
+ }
+
+ acs_survey_all_chans_intereference_factor(iface);
+ return 0;
+}
+
+
+static int acs_study_options(struct hostapd_iface *iface)
+{
+ int err;
+
+ err = acs_study_survey_based(iface);
+ if (err == 0)
+ return 0;
+
+ /* TODO: If no surveys are available/sufficient this is a good
+ * place to fallback to BSS-based ACS */
+
+ return -1;
+}
+
+
+static void acs_study(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *ideal_chan;
+ int err;
+
+ err = acs_study_options(iface);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "ACS: All study options have failed");
+ goto fail;
+ }
+
+ ideal_chan = acs_find_ideal_chan(iface);
+ if (!ideal_chan) {
+ wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel");
+ err = -1;
+ goto fail;
+ }
+
+ iface->conf->channel = ideal_chan->chan;
+
+ if (iface->conf->ieee80211ac)
+ acs_adjust_vht_center_freq(iface);
+
+ err = 0;
+fail:
+ /*
+ * hostapd_setup_interface_complete() will return -1 on failure,
+ * 0 on success and 0 is HOSTAPD_CHAN_VALID :)
+ */
+ if (hostapd_acs_completed(iface, err) == HOSTAPD_CHAN_VALID) {
+ acs_cleanup(iface);
+ return;
+ }
+
+ /* This can possibly happen if channel parameters (secondary
+ * channel, center frequencies) are misconfigured */
+ wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
+ acs_fail(iface);
+}
+
+
+static void acs_scan_complete(struct hostapd_iface *iface)
+{
+ int err;
+
+ iface->scan_cb = NULL;
+
+ wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)",
+ iface->conf->acs_num_scans);
+
+ err = hostapd_drv_get_survey(iface->bss[0], 0);
+ if (err) {
+ wpa_printf(MSG_ERROR, "ACS: Failed to get survey data");
+ goto fail;
+ }
+
+ if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) {
+ err = acs_request_scan(iface);
+ if (err) {
+ wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
+ goto fail;
+ }
+
+ return;
+ }
+
+ acs_study(iface);
+ return;
+fail:
+ hostapd_acs_completed(iface, 1);
+ acs_fail(iface);
+}
+
+
+static int acs_request_scan(struct hostapd_iface *iface)
+{
+ struct wpa_driver_scan_params params;
+ struct hostapd_channel_data *chan;
+ int i, *freq;
+
+ os_memset(&params, 0, sizeof(params));
+ params.freqs = os_calloc(iface->current_mode->num_channels + 1,
+ sizeof(params.freqs[0]));
+ if (params.freqs == NULL)
+ return -1;
+
+ freq = params.freqs;
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ *freq++ = chan->freq;
+ }
+ *freq = 0;
+
+ iface->scan_cb = acs_scan_complete;
+
+ wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
+ iface->acs_num_completed_scans + 1,
+ iface->conf->acs_num_scans);
+
+ if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
+ wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
+ acs_cleanup(iface);
+ os_free(params.freqs);
+ return -1;
+ }
+
+ os_free(params.freqs);
+ return 0;
+}
+
+
+enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
+{
+ int err;
+
+ wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
+
+ 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)
+ return HOSTAPD_CHAN_INVALID;
+ return HOSTAPD_CHAN_ACS;
+ }
+
+ acs_cleanup(iface);
+
+ err = acs_request_scan(iface);
+ if (err < 0)
+ return HOSTAPD_CHAN_INVALID;
+
+ hostapd_set_state(iface, HAPD_IFACE_ACS);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
+
+ return HOSTAPD_CHAN_ACS;
+}
diff --git a/contrib/wpa/src/ap/acs.h b/contrib/wpa/src/ap/acs.h
new file mode 100644
index 0000000..fc85259
--- /dev/null
+++ b/contrib/wpa/src/ap/acs.h
@@ -0,0 +1,27 @@
+/*
+ * ACS - Automatic Channel Selection module
+ * Copyright (c) 2011, Atheros Communications
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef ACS_H
+#define ACS_H
+
+#ifdef CONFIG_ACS
+
+enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
+
+#else /* CONFIG_ACS */
+
+static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
+{
+ wpa_printf(MSG_ERROR, "ACS was disabled on your build, rebuild hostapd with CONFIG_ACS=y or set channel");
+ return HOSTAPD_CHAN_INVALID;
+}
+
+#endif /* CONFIG_ACS */
+
+#endif /* ACS_H */
diff --git a/contrib/wpa/src/ap/ap_config.c b/contrib/wpa/src/ap/ap_config.c
index 25d26e5..76011dc 100644
--- a/contrib/wpa/src/ap/ap_config.c
+++ b/contrib/wpa/src/ap/ap_config.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration helper functions
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -73,6 +73,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
+ bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
@@ -89,6 +90,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#endif /* CONFIG_IEEE80211R */
bss->radius_das_time_window = 300;
+
+ bss->sae_anti_clogging_threshold = 5;
}
@@ -104,9 +107,9 @@ struct hostapd_config * hostapd_config_defaults(void)
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
- { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ { aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
- { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+ { aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 };
const struct hostapd_tx_queue_params txq_bk =
{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
const struct hostapd_tx_queue_params txq_be =
@@ -128,9 +131,17 @@ struct hostapd_config * hostapd_config_defaults(void)
os_free(bss);
return NULL;
}
+ conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *));
+ if (conf->bss == NULL) {
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+ conf->bss[0] = bss;
bss->radius = os_zalloc(sizeof(*bss->radius));
if (bss->radius == NULL) {
+ os_free(conf->bss);
os_free(conf);
os_free(bss);
return NULL;
@@ -139,12 +150,13 @@ struct hostapd_config * hostapd_config_defaults(void)
hostapd_config_defaults_bss(bss);
conf->num_bss = 1;
- conf->bss = bss;
conf->beacon_int = 100;
conf->rts_threshold = -1; /* use driver default: 2347 */
conf->fragm_threshold = -1; /* user driver default: 2346 */
conf->send_probe_response = 1;
+ /* Set to invalid value means do not add Power Constraint IE */
+ conf->local_pwr_constraint = -1;
conf->wmm_ac_params[0] = ac_be;
conf->wmm_ac_params[1] = ac_bk;
@@ -161,6 +173,18 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ap_table_max_size = 255;
conf->ap_table_expiration_time = 60;
+#ifdef CONFIG_TESTING_OPTIONS
+ conf->ignore_probe_probability = 0.0;
+ conf->ignore_auth_probability = 0.0;
+ conf->ignore_assoc_probability = 0.0;
+ conf->ignore_reassoc_probability = 0.0;
+ conf->corrupt_gtk_rekey_mic_probability = 0.0;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_ACS
+ conf->acs_num_scans = 5;
+#endif /* CONFIG_ACS */
+
return conf;
}
@@ -315,20 +339,6 @@ int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
}
-int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
-{
- int i;
-
- if (a->idx != b->idx || a->default_len != b->default_len)
- return 1;
- for (i = 0; i < NUM_WEP_KEYS; i++)
- if (a->len[i] != b->len[i] ||
- os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
- return 1;
- return 0;
-}
-
-
static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
int num_servers)
{
@@ -365,10 +375,11 @@ static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
}
-static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
+void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
+ hostapd_config_free_radius_attr(user->accept_attr);
os_free(user->identity);
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
os_free(user);
}
@@ -377,28 +388,35 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
- os_free(keys->key[i]);
+ bin_clear_free(keys->key[i], keys->len[i]);
keys->key[i] = NULL;
}
}
-static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
+{
+ struct hostapd_wpa_psk *psk, *tmp;
+
+ for (psk = *l; psk;) {
+ tmp = psk;
+ psk = psk->next;
+ bin_clear_free(tmp, sizeof(*tmp));
+ }
+ *l = NULL;
+}
+
+
+void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
- struct hostapd_wpa_psk *psk, *prev;
struct hostapd_eap_user *user, *prev_user;
if (conf == NULL)
return;
- psk = conf->ssid.wpa_psk;
- while (psk) {
- prev = psk;
- psk = psk->next;
- os_free(prev);
- }
+ hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
- os_free(conf->ssid.wpa_passphrase);
+ str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
hostapd_config_free_wep(&conf->ssid.wep);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -413,15 +431,17 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
os_free(conf->eap_user_sqlite);
- os_free(conf->dump_log_name);
os_free(conf->eap_req_id_text);
+ os_free(conf->erp_domain);
os_free(conf->accept_mac);
os_free(conf->deny_mac);
os_free(conf->nas_identifier);
- hostapd_config_free_radius(conf->radius->auth_servers,
- conf->radius->num_auth_servers);
- hostapd_config_free_radius(conf->radius->acct_servers,
- conf->radius->num_acct_servers);
+ if (conf->radius) {
+ hostapd_config_free_radius(conf->radius->auth_servers,
+ conf->radius->num_auth_servers);
+ hostapd_config_free_radius(conf->radius->acct_servers,
+ conf->radius->num_acct_servers);
+ }
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
os_free(conf->rsn_preauth_interfaces);
@@ -430,29 +450,17 @@ static 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->ocsp_stapling_response);
os_free(conf->dh_file);
+ os_free(conf->openssl_ciphers);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
os_free(conf->radius_server_clients);
- os_free(conf->test_socket);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
hostapd_config_free_vlan(conf);
- if (conf->ssid.dyn_vlan_keys) {
- struct hostapd_ssid *ssid = &conf->ssid;
- size_t i;
- for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
- if (ssid->dyn_vlan_keys[i] == NULL)
- continue;
- hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
- os_free(ssid->dyn_vlan_keys[i]);
- }
- os_free(ssid->dyn_vlan_keys);
- ssid->dyn_vlan_keys = NULL;
- }
-
os_free(conf->time_zone);
#ifdef CONFIG_IEEE80211R
@@ -495,6 +503,12 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
+ {
+ unsigned int i;
+
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(conf->wps_vendor_ext[i]);
+ }
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -516,9 +530,36 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->hs20_wan_metrics);
os_free(conf->hs20_connection_capability);
os_free(conf->hs20_operating_class);
+ os_free(conf->hs20_icons);
+ if (conf->hs20_osu_providers) {
+ size_t i;
+ for (i = 0; i < conf->hs20_osu_providers_count; i++) {
+ struct hs20_osu_provider *p;
+ size_t j;
+ p = &conf->hs20_osu_providers[i];
+ os_free(p->friendly_name);
+ os_free(p->server_uri);
+ os_free(p->method_list);
+ for (j = 0; j < p->icons_count; j++)
+ os_free(p->icons[j]);
+ os_free(p->icons);
+ os_free(p->osu_nai);
+ os_free(p->service_desc);
+ }
+ os_free(conf->hs20_osu_providers);
+ }
+ os_free(conf->subscr_remediation_url);
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+
+ os_free(conf->sae_groups);
+
+ os_free(conf->wowlan_triggers);
+
+ os_free(conf->server_id);
+
+ os_free(conf);
}
@@ -534,10 +575,15 @@ void hostapd_config_free(struct hostapd_config *conf)
return;
for (i = 0; i < conf->num_bss; i++)
- hostapd_config_free_bss(&conf->bss[i]);
+ hostapd_config_free_bss(conf->bss[i]);
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
+ os_free(conf->chanlist);
+ os_free(conf->driver_params);
+#ifdef CONFIG_ACS
+ os_free(conf->acs_chan_bias);
+#endif /* CONFIG_ACS */
os_free(conf);
}
@@ -594,11 +640,23 @@ int hostapd_rate_found(int *list, int rate)
}
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
{
struct hostapd_vlan *v = vlan;
while (v) {
if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+ return 1;
+ v = v->next;
+ }
+ return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+ struct hostapd_vlan *v = vlan;
+ while (v) {
+ if (v->vlan_id == vlan_id)
return v->ifname;
v = v->next;
}
@@ -607,14 +665,30 @@ 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 *prev_psk)
+ const u8 *addr, const u8 *p2p_dev_addr,
+ const u8 *prev_psk)
{
struct hostapd_wpa_psk *psk;
int next_ok = prev_psk == NULL;
+ if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
+ wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
+ " p2p_dev_addr=" MACSTR " prev_psk=%p",
+ MAC2STR(addr), MAC2STR(p2p_dev_addr), prev_psk);
+ addr = NULL; /* Use P2P Device Address for matching */
+ } else {
+ wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
+ " prev_psk=%p",
+ MAC2STR(addr), prev_psk);
+ }
+
for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
if (next_ok &&
- (psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
+ (psk->group ||
+ (addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
+ (!addr && p2p_dev_addr &&
+ os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
+ 0)))
return psk->psk;
if (psk->psk == prev_psk)
@@ -623,3 +697,250 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
return NULL;
}
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+ struct hostapd_config *conf,
+ int full_config)
+{
+ if (full_config && bss->ieee802_1x && !bss->eap_server &&
+ !bss->radius->auth_servers) {
+ wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+ "EAP authenticator configured).");
+ return -1;
+ }
+
+ if (bss->wpa) {
+ int wep, i;
+
+ wep = bss->default_wep_key_len > 0 ||
+ bss->individual_wep_key_len > 0;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (bss->ssid.wep.keys_set) {
+ wep = 1;
+ break;
+ }
+ }
+
+ if (wep) {
+ wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
+ return -1;
+ }
+ }
+
+ if (full_config && bss->wpa &&
+ bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+ "RADIUS checking (macaddr_acl=2) enabled.");
+ return -1;
+ }
+
+ if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+ bss->ssid.wpa_psk_file == NULL &&
+ (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+ wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+ "is not configured.");
+ return -1;
+ }
+
+ if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (conf->bss[i] != bss &&
+ (hostapd_mac_comp(conf->bss[i]->bssid,
+ bss->bssid) == 0)) {
+ wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+ " on interface '%s' and '%s'.",
+ MAC2STR(bss->bssid),
+ conf->bss[i]->iface, bss->iface);
+ return -1;
+ }
+ }
+ }
+
+#ifdef CONFIG_IEEE80211R
+ if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+ (bss->nas_identifier == NULL ||
+ os_strlen(bss->nas_identifier) < 1 ||
+ os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+ wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+ "nas_identifier to be configured as a 1..48 octet "
+ "string");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+ if (full_config && conf->ieee80211n &&
+ conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+ bss->disable_11n = 1;
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+ "allowed, disabling HT capabilities");
+ }
+
+ if (full_config && conf->ieee80211n &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11n = 1;
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+ "allowed, disabling HT capabilities");
+ }
+
+ if (full_config && conf->ieee80211n && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+ {
+ bss->disable_11n = 1;
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+ "requires CCMP/GCMP to be enabled, disabling HT "
+ "capabilities");
+ }
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS
+ if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
+ wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+ "configuration forced WPS to be disabled");
+ bss->wps_state = 0;
+ }
+
+ if (full_config && bss->wps_state &&
+ bss->ssid.wep.keys_set && bss->wpa == 0) {
+ wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+ "disabled");
+ bss->wps_state = 0;
+ }
+
+ if (full_config && bss->wps_state && bss->wpa &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+ wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+ "WPA2/CCMP forced WPS to be disabled");
+ bss->wps_state = 0;
+ }
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_HS20
+ if (full_config && bss->hs20 &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP_256)))) {
+ wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+ "configuration is required for Hotspot 2.0 "
+ "functionality");
+ return -1;
+ }
+#endif /* CONFIG_HS20 */
+
+ return 0;
+}
+
+
+int hostapd_config_check(struct hostapd_config *conf, int full_config)
+{
+ size_t i;
+
+ if (full_config && conf->ieee80211d &&
+ (!conf->country[0] || !conf->country[1])) {
+ wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+ "setting the country_code");
+ return -1;
+ }
+
+ if (full_config && conf->ieee80211h && !conf->ieee80211d) {
+ wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
+ "IEEE 802.11d enabled");
+ return -1;
+ }
+
+ if (full_config && conf->local_pwr_constraint != -1 &&
+ !conf->ieee80211d) {
+ wpa_printf(MSG_ERROR, "Cannot add Power Constraint element without Country element");
+ return -1;
+ }
+
+ if (full_config && conf->spectrum_mgmt_required &&
+ conf->local_pwr_constraint == -1) {
+ wpa_printf(MSG_ERROR, "Cannot set Spectrum Management bit without Country and Power Constraint elements");
+ return -1;
+ }
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hostapd_set_security_params(struct hostapd_bss_config *bss,
+ int full_config)
+{
+ if (bss->individual_wep_key_len == 0) {
+ /* individual keys are not use; can use key idx0 for
+ * broadcast keys */
+ bss->broadcast_key_idx_min = 0;
+ }
+
+ if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+ bss->rsn_pairwise);
+
+ if (full_config) {
+ bss->radius->auth_server = bss->radius->auth_servers;
+ bss->radius->acct_server = bss->radius->acct_servers;
+ }
+
+ if (bss->wpa && bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_WPA;
+ } else if (bss->wpa) {
+ bss->ssid.security_policy = SECURITY_WPA_PSK;
+ } else if (bss->ieee802_1x) {
+ int cipher = WPA_CIPHER_NONE;
+ bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+ bss->ssid.wep.default_len = bss->default_wep_key_len;
+ if (full_config && bss->default_wep_key_len) {
+ cipher = bss->default_wep_key_len >= 13 ?
+ WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+ } else if (full_config && bss->ssid.wep.keys_set) {
+ if (bss->ssid.wep.len[0] >= 13)
+ cipher = WPA_CIPHER_WEP104;
+ else
+ cipher = WPA_CIPHER_WEP40;
+ }
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ if (full_config)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+ } else if (bss->ssid.wep.keys_set) {
+ int cipher = WPA_CIPHER_WEP40;
+ if (bss->ssid.wep.len[0] >= 13)
+ cipher = WPA_CIPHER_WEP104;
+ bss->ssid.security_policy = SECURITY_STATIC_WEP;
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ if (full_config)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+ } else if (bss->osen) {
+ bss->ssid.security_policy = SECURITY_OSEN;
+ bss->wpa_group = WPA_CIPHER_CCMP;
+ bss->wpa_pairwise = 0;
+ bss->rsn_pairwise = WPA_CIPHER_CCMP;
+ } else {
+ bss->ssid.security_policy = SECURITY_PLAINTEXT;
+ bss->wpa_group = WPA_CIPHER_NONE;
+ bss->wpa_pairwise = WPA_CIPHER_NONE;
+ bss->rsn_pairwise = WPA_CIPHER_NONE;
+ if (full_config)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+ }
+}
diff --git a/contrib/wpa/src/ap/ap_config.h b/contrib/wpa/src/ap/ap_config.h
index a1d2b04..961d2dd 100644
--- a/contrib/wpa/src/ap/ap_config.h
+++ b/contrib/wpa/src/ap/ap_config.h
@@ -15,6 +15,34 @@
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
+/**
+ * mesh_conf - local MBSS state and settings
+ */
+struct mesh_conf {
+ u8 meshid[32];
+ u8 meshid_len;
+ /* Active Path Selection Protocol Identifier */
+ u8 mesh_pp_id;
+ /* Active Path Selection Metric Identifier */
+ u8 mesh_pm_id;
+ /* Congestion Control Mode Identifier */
+ u8 mesh_cc_id;
+ /* Synchronization Protocol Identifier */
+ u8 mesh_sp_id;
+ /* Authentication Protocol Identifier */
+ u8 mesh_auth_id;
+ u8 *ies;
+ int ie_len;
+#define MESH_CONF_SEC_NONE BIT(0)
+#define MESH_CONF_SEC_AUTH BIT(1)
+#define MESH_CONF_SEC_AMPE BIT(2)
+ unsigned int security;
+ int dot11MeshMaxRetries;
+ int dot11MeshRetryTimeout; /* msec */
+ int dot11MeshConfirmTimeout; /* msec */
+ int dot11MeshHoldingTimeout; /* msec */
+};
+
#define MAX_STA_COUNT 2007
#define MAX_VLAN_ID 4094
@@ -45,7 +73,8 @@ typedef enum hostap_security_policy {
SECURITY_STATIC_WEP = 1,
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
- SECURITY_WPA = 4
+ SECURITY_WPA = 4,
+ SECURITY_OSEN = 5
} secpolicy;
struct hostapd_ssid {
@@ -53,6 +82,8 @@ struct hostapd_ssid {
size_t ssid_len;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
+ unsigned int wpa_passphrase_set:1;
+ unsigned int wpa_psk_set:1;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
@@ -74,8 +105,6 @@ struct hostapd_ssid {
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
- struct hostapd_wep_keys **dyn_vlan_keys;
- size_t max_dyn_vlan_keys;
};
@@ -107,6 +136,7 @@ struct hostapd_wpa_psk {
int group;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
+ u8 p2p_dev_addr[ETH_ALEN];
};
struct hostapd_eap_user {
@@ -124,7 +154,10 @@ struct hostapd_eap_user {
unsigned int wildcard_prefix:1;
unsigned int password_hash:1; /* whether password is hashed with
* nt_password_hash() */
+ unsigned int remediation:1;
+ unsigned int macacl:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
+ struct hostapd_radius_attr *accept_attr;
};
struct hostapd_radius_attr {
@@ -180,6 +213,7 @@ struct hostapd_nai_realm_data {
struct hostapd_bss_config {
char iface[IFNAMSIZ + 1];
char bridge[IFNAMSIZ + 1];
+ char vlan_bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@@ -187,11 +221,10 @@ struct hostapd_bss_config {
unsigned int logger_syslog; /* module bitfield */
unsigned int logger_stdout; /* module bitfield */
- char *dump_log_name; /* file name for state dump (SIGUSR1) */
-
int max_num_sta; /* maximum number of STAs in station table */
int dtim_period;
+ int bss_load_update_period;
int ieee802_1x; /* use IEEE 802.1X */
int eapol_version;
@@ -200,6 +233,7 @@ struct hostapd_bss_config {
struct hostapd_eap_user *eap_user;
char *eap_user_sqlite;
char *eap_sim_db;
+ int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
@@ -226,6 +260,8 @@ struct hostapd_bss_config {
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
int eap_reauth_period;
+ int erp_send_reauth_start;
+ char *erp_domain;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
@@ -242,6 +278,7 @@ struct hostapd_bss_config {
int num_deny_mac;
int wds_sta;
int isolate;
+ int start_disabled;
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
@@ -250,6 +287,7 @@ struct hostapd_bss_config {
int wpa_key_mgmt;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
+ int group_mgmt_cipher;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
@@ -294,7 +332,9 @@ struct hostapd_bss_config {
char *private_key;
char *private_key_passwd;
int check_crl;
+ char *ocsp_stapling_response;
char *dh_file;
+ char *openssl_ciphers;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@@ -309,10 +349,9 @@ struct hostapd_bss_config {
char *radius_server_clients;
int radius_server_auth_port;
+ int radius_server_acct_port;
int radius_server_ipv6;
- char *test_socket; /* UNIX domain socket path for driver_test */
-
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
* address instead of individual address
* (for driver_wired.c).
@@ -324,7 +363,7 @@ struct hostapd_bss_config {
int wmm_enabled;
int wmm_uapsd;
- struct hostapd_vlan *vlan, *vlan_tail;
+ struct hostapd_vlan *vlan;
macaddr bssid;
@@ -340,6 +379,7 @@ struct hostapd_bss_config {
int wps_state;
#ifdef CONFIG_WPS
+ int wps_independent;
int ap_setup_locked;
u8 uuid[16];
char *wps_pin_requests;
@@ -356,6 +396,7 @@ struct hostapd_bss_config {
u8 *extra_cred;
size_t extra_cred_len;
int wps_cred_processing;
+ int force_per_enrollee_psk;
u8 *ap_settings;
size_t ap_settings_len;
char *upnp_iface;
@@ -365,12 +406,14 @@ struct hostapd_bss_config {
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
struct wpabuf *wps_nfc_dh_privkey;
struct wpabuf *wps_nfc_dev_pw;
#endif /* CONFIG_WPS */
int pbc_in_m1;
+ char *server_id;
#define P2P_ENABLED BIT(0)
#define P2P_GROUP_OWNER BIT(1)
@@ -378,6 +421,12 @@ struct hostapd_bss_config {
#define P2P_MANAGE BIT(3)
#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
int p2p;
+#ifdef CONFIG_P2P
+ u8 ip_addr_go[4];
+ u8 ip_addr_mask[4];
+ u8 ip_addr_start[4];
+ u8 ip_addr_end[4];
+#endif /* CONFIG_P2P */
int disassoc_low_ack;
int skip_inactivity_poll;
@@ -436,9 +485,15 @@ struct hostapd_bss_config {
u16 gas_comeback_delay;
int gas_frag_limit;
+ u8 qos_map_set[16 + 2 * 21];
+ unsigned int qos_map_set_len;
+
+ int osen;
+ int proxy_arp;
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
+ u16 anqp_domain_id;
unsigned int hs20_oper_friendly_name_count;
struct hostapd_lang_string *hs20_oper_friendly_name;
u8 *hs20_wan_metrics;
@@ -446,6 +501,32 @@ struct hostapd_bss_config {
size_t hs20_connection_capability_len;
u8 *hs20_operating_class;
u8 hs20_operating_class_len;
+ struct hs20_icon {
+ u16 width;
+ u16 height;
+ char language[3];
+ char type[256];
+ char name[256];
+ char file[256];
+ } *hs20_icons;
+ size_t hs20_icons_count;
+ u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
+ size_t osu_ssid_len;
+ struct hs20_osu_provider {
+ unsigned int friendly_name_count;
+ struct hostapd_lang_string *friendly_name;
+ char *server_uri;
+ int *method_list;
+ char **icons;
+ size_t icons_count;
+ char *osu_nai;
+ unsigned int service_desc_count;
+ struct hostapd_lang_string *service_desc;
+ } *hs20_osu_providers, *last_osu;
+ size_t hs20_osu_providers_count;
+ unsigned int hs20_deauth_req_timeout;
+ char *subscr_remediation_url;
+ u8 subscr_remediation_method;
#endif /* CONFIG_HS20 */
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
@@ -455,6 +536,23 @@ struct hostapd_bss_config {
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
+
+ unsigned int sae_anti_clogging_threshold;
+ int *sae_groups;
+
+ char *wowlan_triggers; /* Wake-on-WLAN triggers */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 bss_load_test[5];
+ u8 bss_load_test_set;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#define MESH_ENABLED BIT(0)
+ int mesh;
+
+ int radio_measurements;
+
+ int vendor_vht;
};
@@ -462,7 +560,7 @@ struct hostapd_bss_config {
* struct hostapd_config - Per-radio interface configuration
*/
struct hostapd_config {
- struct hostapd_bss_config *bss, *last_bss;
+ struct hostapd_bss_config **bss, *last_bss;
size_t num_bss;
u16 beacon_int;
@@ -470,6 +568,7 @@ struct hostapd_config {
int fragm_threshold;
u8 send_probe_response;
u8 channel;
+ int *chanlist;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
@@ -480,6 +579,7 @@ struct hostapd_config {
int *basic_rates;
const struct wpa_driver_ops *driver;
+ char *driver_params;
int ap_table_max_size;
int ap_table_expiration_time;
@@ -493,6 +593,18 @@ struct hostapd_config {
int ieee80211d;
+ int ieee80211h; /* DFS */
+
+ /*
+ * Local power constraint is an octet encoded as an unsigned integer in
+ * units of decibels. Invalid value -1 indicates that Power Constraint
+ * element will not be added.
+ */
+ int local_pwr_constraint;
+
+ /* Control Spectrum Management bit */
+ int spectrum_mgmt_required;
+
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
/*
@@ -509,12 +621,34 @@ struct hostapd_config {
int ieee80211n;
int secondary_channel;
int require_ht;
+ int obss_interval;
u32 vht_capab;
int ieee80211ac;
int require_vht;
u8 vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
+
+#ifdef CONFIG_P2P
+ u8 p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ double ignore_probe_probability;
+ double ignore_auth_probability;
+ double ignore_assoc_probability;
+ double ignore_reassoc_probability;
+ double corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_ACS
+ unsigned int acs_num_scans;
+ struct acs_bias {
+ int channel;
+ double bias;
+ } *acs_chan_bias;
+ unsigned int num_acs_chan_bias;
+#endif /* CONFIG_ACS */
};
@@ -522,18 +656,24 @@ 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_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);
int hostapd_rate_found(int *list, int rate);
-int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
- struct hostapd_wep_keys *b);
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
- const u8 *addr, const u8 *prev_psk);
+ const u8 *addr, const u8 *p2p_dev_addr,
+ const u8 *prev_psk);
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+int hostapd_config_check(struct hostapd_config *conf, int full_config);
+void hostapd_set_security_params(struct hostapd_bss_config *bss,
+ int full_config);
#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 02da25b..e16306c 100644
--- a/contrib/wpa/src/ap/ap_drv_ops.c
+++ b/contrib/wpa/src/ap/ap_drv_ops.c
@@ -9,8 +9,8 @@
#include "utils/includes.h"
#include "utils/common.h"
-#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@@ -129,14 +129,14 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
-#ifdef CONFIG_WPS2
+#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);
wpabuf_free(a);
}
-#endif /* CONFIG_WPS2 */
+#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
@@ -171,8 +171,27 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
goto fail;
wpabuf_put_data(proberesp, buf, pos - buf);
}
+
+ 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 (wpabuf_resize(&proberesp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(proberesp, buf, pos - buf);
+ }
#endif /* CONFIG_HS20 */
+ if (hapd->conf->vendor_elements) {
+ size_t add = wpabuf_len(hapd->conf->vendor_elements);
+ if (wpabuf_resize(&beacon, add) == 0)
+ wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
+ if (wpabuf_resize(&proberesp, add) == 0)
+ wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
+ }
+
*beacon_ret = beacon;
*proberesp_ret = proberesp;
*assocresp_ret = assocresp;
@@ -262,7 +281,8 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
params.wpa = hapd->conf->wpa;
params.ieee802_1x = hapd->conf->ieee802_1x;
params.wpa_group = hapd->conf->wpa_group;
- params.wpa_pairwise = hapd->conf->wpa_pairwise;
+ params.wpa_pairwise = hapd->conf->wpa_pairwise |
+ hapd->conf->rsn_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
#ifdef CONFIG_IEEE80211W
@@ -278,7 +298,7 @@ int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
- NULL, NULL, force_ifname, if_addr, NULL);
+ NULL, NULL, force_ifname, if_addr, NULL, 0);
}
@@ -288,19 +308,19 @@ int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
}
-int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
- int val)
+int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
+ const u8 *addr, int aid, int val)
{
const char *bridge = NULL;
if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
- return 0;
+ return -1;
if (hapd->conf->wds_bridge[0])
bridge = hapd->conf->wds_bridge;
else if (hapd->conf->bridge[0])
bridge = hapd->conf->bridge;
return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
- bridge);
+ bridge, ifname_wds);
}
@@ -338,7 +358,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
- u32 flags, u8 qosinfo)
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u32 flags, u8 qosinfo, u8 vht_opmode)
{
struct hostapd_sta_add_params params;
@@ -355,6 +376,9 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.supp_rates_len = supp_rates_len;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
+ params.vht_capabilities = vht_capab;
+ params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
+ params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, &params);
@@ -407,20 +431,21 @@ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
- const char *bridge)
+ const char *bridge, int use_existing)
{
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
return -1;
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
bss_ctx, drv_priv, force_ifname, if_addr,
- bridge);
+ bridge, use_existing);
}
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname)
{
- if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->if_remove == NULL)
return -1;
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
}
@@ -453,20 +478,25 @@ int hostapd_flush(struct hostapd_data *hapd)
}
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int sec_channel_offset)
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled, int vht_enabled,
+ int sec_channel_offset, int vht_oper_chwidth,
+ int center_segment0, int center_segment1)
{
struct hostapd_freq_params data;
+
+ if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ vht_enabled, sec_channel_offset,
+ vht_oper_chwidth,
+ center_segment0, center_segment1,
+ hapd->iface->current_mode ?
+ hapd->iface->current_mode->vht_capab : 0))
+ return -1;
+
if (hapd->driver == NULL)
return 0;
if (hapd->driver->set_freq == NULL)
return 0;
- os_memset(&data, 0, sizeof(data));
- data.mode = mode;
- data.freq = freq;
- data.channel = channel;
- data.ht_enabled = ht_enabled;
- data.sec_channel_offset = sec_channel_offset;
return hapd->driver->set_freq(hapd->drv_priv, &data);
}
@@ -616,7 +646,7 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
const u8 *peer, u8 *buf, u16 *buf_len)
{
if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
- return 0;
+ return -1;
return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
buf_len);
}
@@ -632,3 +662,66 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
hapd->own_addr, hapd->own_addr, data,
len, 0);
}
+
+
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ enum hostapd_hw_mode mode, int freq,
+ int channel, int ht_enabled, int vht_enabled,
+ int sec_channel_offset, int vht_oper_chwidth,
+ int center_segment0, int center_segment1)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct hostapd_freq_params data;
+ int res;
+
+ if (!hapd->driver || !hapd->driver->start_dfs_cac)
+ return 0;
+
+ if (!iface->conf->ieee80211h) {
+ wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
+ "is not enabled");
+ return -1;
+ }
+
+ if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ vht_enabled, sec_channel_offset,
+ vht_oper_chwidth, center_segment0,
+ center_segment1,
+ iface->current_mode->vht_capab)) {
+ wpa_printf(MSG_ERROR, "Can't set freq params");
+ return -1;
+ }
+
+ res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+ if (!res) {
+ iface->cac_started = 1;
+ os_get_reltime(&iface->dfs_cac_start);
+ }
+
+ return res;
+}
+
+
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
+ const u8 *qos_map_set, u8 qos_map_set_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+ return 0;
+ return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
+ qos_map_set_len);
+}
+
+
+int hostapd_drv_do_acs(struct hostapd_data *hapd)
+{
+ struct drv_acs_params params;
+
+ if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
+ return 0;
+ os_memset(&params, 0, sizeof(params));
+ params.hw_mode = hapd->iface->conf->hw_mode;
+ params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
+ params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
+ return hapd->driver->do_acs(hapd->drv_priv, &params);
+}
diff --git a/contrib/wpa/src/ap/ap_drv_ops.h b/contrib/wpa/src/ap/ap_drv_ops.h
index 9c53b99..5d07e71 100644
--- a/contrib/wpa/src/ap/ap_drv_ops.h
+++ b/contrib/wpa/src/ap/ap_drv_ops.h
@@ -1,6 +1,6 @@
/*
* hostapd - Driver operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2014, 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,8 @@ enum wpa_driver_if_type;
struct wpa_bss_params;
struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
+struct ieee80211_vht_capabilities;
+struct hostapd_freq_params;
u32 hostapd_sta_flags_to_drv(u32 flags);
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@@ -30,14 +32,15 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
int enabled);
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
-int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
- int val);
+int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
+ const u8 *addr, int aid, int val);
int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
- u32 flags, u8 qosinfo);
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u32 flags, u8 qosinfo, u8 vht_opmode);
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);
@@ -46,7 +49,7 @@ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
- const char *bridge);
+ const char *bridge, int use_existing);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@@ -54,8 +57,10 @@ int hostapd_set_ieee8021x(struct hostapd_data *hapd,
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int sec_channel_offset);
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled, int vht_enabled,
+ int sec_channel_offset, int vht_oper_chwidth,
+ int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
@@ -97,6 +102,12 @@ int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
int reassoc, u16 status, const u8 *ie, size_t len);
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
u8 *tspec_ie, size_t tspec_ielen);
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ enum hostapd_hw_mode mode, int freq,
+ int channel, int ht_enabled, int vht_enabled,
+ int sec_channel_offset, int vht_oper_chwidth,
+ int center_segment0, int center_segment1);
+int hostapd_drv_do_acs(struct hostapd_data *hapd);
#include "drivers/driver.h"
@@ -105,6 +116,9 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
enum wnm_oper oper, const u8 *peer,
u8 *buf, u16 *buf_len);
+int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
+ u8 qos_map_set_len);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
@@ -169,6 +183,14 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
}
+static inline int hostapd_drv_set_acl(struct hostapd_data *hapd,
+ struct hostapd_acl_params *params)
+{
+ if (hapd->driver == NULL || hapd->driver->set_acl == NULL)
+ return 0;
+ return hapd->driver->set_acl(hapd->drv_priv, params);
+}
+
static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@@ -213,4 +235,105 @@ static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
}
+static inline int hostapd_drv_get_survey(struct hostapd_data *hapd,
+ unsigned int freq)
+{
+ if (hapd->driver == NULL)
+ return -1;
+ if (!hapd->driver->get_survey)
+ return -1;
+ return hapd->driver->get_survey(hapd->drv_priv, freq);
+}
+
+static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2)
+{
+ if (hapd->driver == NULL || hapd->driver->get_country == NULL)
+ return -1;
+ return hapd->driver->get_country(hapd->drv_priv, alpha2);
+}
+
+static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->get_radio_name == NULL)
+ return NULL;
+ return hapd->driver->get_radio_name(hapd->drv_priv);
+}
+
+static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
+ struct csa_settings *settings)
+{
+ if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
+ return -ENOTSUP;
+
+ return hapd->driver->switch_channel(hapd->drv_priv, settings);
+}
+
+static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
+ size_t buflen)
+{
+ if (hapd->driver == NULL || hapd->driver->status == NULL)
+ return -1;
+ return hapd->driver->status(hapd->drv_priv, buf, buflen);
+}
+
+static inline int hostapd_drv_br_add_ip_neigh(struct hostapd_data *hapd,
+ int version, const u8 *ipaddr,
+ int prefixlen, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_add_ip_neigh == NULL)
+ return -1;
+ return hapd->driver->br_add_ip_neigh(hapd->drv_priv, version, ipaddr,
+ prefixlen, addr);
+}
+
+static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd,
+ u8 version, const u8 *ipaddr)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_delete_ip_neigh == NULL)
+ return -1;
+ return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, version,
+ ipaddr);
+}
+
+static inline int hostapd_drv_br_port_set_attr(struct hostapd_data *hapd,
+ enum drv_br_port_attr attr,
+ unsigned int val)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_port_set_attr == NULL)
+ return -1;
+ return hapd->driver->br_port_set_attr(hapd->drv_priv, attr, val);
+}
+
+static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
+ enum drv_br_net_param param,
+ unsigned int val)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_set_net_param == NULL)
+ return -1;
+ return hapd->driver->br_set_net_param(hapd->drv_priv, param, val);
+}
+
+static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
+ int vendor_id, int subcmd,
+ const u8 *data, size_t data_len,
+ struct wpabuf *buf)
+{
+ if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
+ return -1;
+ return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
+ data_len, buf);
+}
+
+static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+ return 0;
+ return hapd->driver->stop_ap(hapd->drv_priv);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/contrib/wpa/src/ap/ap_list.c b/contrib/wpa/src/ap/ap_list.c
index 18090ca..04a56a9 100644
--- a/contrib/wpa/src/ap/ap_list.c
+++ b/contrib/wpa/src/ap/ap_list.c
@@ -14,7 +14,6 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ieee802_11.h"
@@ -33,7 +32,8 @@ static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
{
int i;
- if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
+ if (iface->current_mode == NULL ||
+ iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
iface->conf->channel != ap->channel)
return 0;
@@ -50,7 +50,7 @@ static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
}
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
+static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
{
struct ap_info *s;
@@ -87,34 +87,6 @@ static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
}
-static void ap_ap_iter_list_add(struct hostapd_iface *iface,
- struct ap_info *ap)
-{
- if (iface->ap_iter_list) {
- ap->iter_prev = iface->ap_iter_list->iter_prev;
- iface->ap_iter_list->iter_prev = ap;
- } else
- ap->iter_prev = ap;
- ap->iter_next = iface->ap_iter_list;
- iface->ap_iter_list = ap;
-}
-
-
-static void ap_ap_iter_list_del(struct hostapd_iface *iface,
- struct ap_info *ap)
-{
- if (iface->ap_iter_list == ap)
- iface->ap_iter_list = ap->iter_next;
- else
- ap->iter_prev->iter_next = ap->iter_next;
-
- if (ap->iter_next)
- ap->iter_next->iter_prev = ap->iter_prev;
- else if (iface->ap_iter_list)
- iface->ap_iter_list->iter_prev = ap->iter_prev;
-}
-
-
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
{
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
@@ -139,8 +111,8 @@ static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
- printf("AP: could not remove AP " MACSTR " from hash table\n",
- MAC2STR(ap->addr));
+ wpa_printf(MSG_INFO, "AP: could not remove AP " MACSTR
+ " from hash table", MAC2STR(ap->addr));
}
@@ -148,7 +120,6 @@ static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
{
ap_ap_hash_del(iface, ap);
ap_ap_list_del(iface, ap);
- ap_ap_iter_list_del(iface, ap);
iface->num_ap--;
os_free(ap);
@@ -171,25 +142,6 @@ static void hostapd_free_aps(struct hostapd_iface *iface)
}
-int ap_ap_for_each(struct hostapd_iface *iface,
- int (*func)(struct ap_info *s, void *data), void *data)
-{
- struct ap_info *s;
- int ret = 0;
-
- s = iface->ap_list;
-
- while (s) {
- ret = func(s, data);
- if (ret)
- break;
- s = s->next;
- }
-
- return ret;
-}
-
-
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
{
struct ap_info *ap;
@@ -203,7 +155,6 @@ static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
ap_ap_list_add(iface, ap);
iface->num_ap++;
ap_ap_hash_add(iface, ap);
- ap_ap_iter_list_add(iface, ap);
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
@@ -221,9 +172,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
struct hostapd_frame_info *fi)
{
struct ap_info *ap;
- struct os_time now;
int new_ap = 0;
- size_t len;
int set_beacon = 0;
if (iface->conf->ap_table_max_size < 1)
@@ -233,30 +182,17 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
if (!ap) {
ap = ap_ap_add(iface, mgmt->bssid);
if (!ap) {
- printf("Failed to allocate AP information entry\n");
+ wpa_printf(MSG_INFO,
+ "Failed to allocate AP information entry");
return;
}
new_ap = 1;
}
- ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
- ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
- if (elems->ssid) {
- len = elems->ssid_len;
- if (len >= sizeof(ap->ssid))
- len = sizeof(ap->ssid) - 1;
- os_memcpy(ap->ssid, elems->ssid, len);
- ap->ssid[len] = '\0';
- ap->ssid_len = len;
- }
-
merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
- ap->wpa = elems->wpa_ie != NULL;
-
if (elems->erp_info && elems->erp_info_len == 1)
ap->erp = elems->erp_info[0];
else
@@ -264,6 +200,8 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
if (elems->ds_params && elems->ds_params_len == 1)
ap->channel = elems->ds_params[0];
+ else if (elems->ht_operation && elems->ht_operation_len >= 1)
+ ap->channel = elems->ht_operation[0];
else if (fi)
ap->channel = fi->channel;
@@ -272,11 +210,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
else
ap->ht_support = 0;
- ap->num_beacons++;
- os_get_time(&now);
- ap->last_beacon = now.sec;
- if (fi)
- ap->datarate = fi->datarate;
+ os_get_reltime(&ap->last_beacon);
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@@ -288,17 +222,23 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
if (!iface->olbc &&
ap_list_beacon_olbc(iface, ap)) {
iface->olbc = 1;
- wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
- "protection", MAC2STR(ap->addr));
+ wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
+ " (channel %d) - enable protection",
+ MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
- if (!iface->olbc_ht && !ap->ht_support) {
+ if (!iface->olbc_ht && !ap->ht_support &&
+ (ap->channel == 0 ||
+ ap->channel == iface->conf->channel ||
+ ap->channel == iface->conf->channel +
+ iface->conf->secondary_channel * 4)) {
iface->olbc_ht = 1;
hostapd_ht_operation_update(iface);
wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
- " - enable protection", MAC2STR(ap->addr));
+ " (channel %d) - enable protection",
+ MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
@@ -311,7 +251,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_iface *iface = eloop_ctx;
- struct os_time now;
+ struct os_reltime now;
struct ap_info *ap;
int set_beacon = 0;
@@ -320,12 +260,12 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
if (!iface->ap_list)
return;
- os_get_time(&now);
+ os_get_reltime(&now);
while (iface->ap_list) {
ap = iface->ap_list->prev;
- if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
- now.sec)
+ if (!os_reltime_expired(&now, &ap->last_beacon,
+ iface->conf->ap_table_expiration_time))
break;
ap_free_ap(iface, ap);
diff --git a/contrib/wpa/src/ap/ap_list.h b/contrib/wpa/src/ap/ap_list.h
index f0b4125..93dc0ed 100644
--- a/contrib/wpa/src/ap/ap_list.h
+++ b/contrib/wpa/src/ap/ap_list.h
@@ -14,42 +14,24 @@
struct ap_info {
/* Note: next/prev pointers are updated whenever a new beacon is
* received because these are used to find the least recently used
- * entries. iter_next/iter_prev are updated only when adding new BSSes
- * and when removing old ones. These should be used when iterating
- * through the table in a manner that allows beacons to be received
- * during the iteration. */
+ * entries. */
struct ap_info *next; /* next entry in AP list */
struct ap_info *prev; /* previous entry in AP list */
struct ap_info *hnext; /* next entry in hash table list */
- struct ap_info *iter_next; /* next entry in AP iteration list */
- struct ap_info *iter_prev; /* previous entry in AP iteration list */
u8 addr[6];
- u16 beacon_int;
- u16 capability;
u8 supported_rates[WLAN_SUPP_RATES_MAX];
- u8 ssid[33];
- size_t ssid_len;
- int wpa;
int erp; /* ERP Info or -1 if ERP info element not present */
int channel;
- int datarate; /* in 100 kbps */
int ht_support;
- unsigned int num_beacons; /* number of beacon frames received */
- os_time_t last_beacon;
-
- int already_seen; /* whether API call AP-NEW has already fetched
- * information about this AP */
+ struct os_reltime last_beacon;
};
struct ieee802_11_elems;
struct hostapd_frame_info;
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
-int ap_ap_for_each(struct hostapd_iface *iface,
- int (*func)(struct ap_info *s, void *data), void *data);
void ap_list_process_beacon(struct hostapd_iface *iface,
const struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
diff --git a/contrib/wpa/src/ap/ap_mlme.c b/contrib/wpa/src/ap/ap_mlme.c
index a959694..13604ed 100644
--- a/contrib/wpa/src/ap/ap_mlme.c
+++ b/contrib/wpa/src/ap/ap_mlme.c
@@ -16,6 +16,7 @@
#include "wpa_auth.h"
#include "sta_info.h"
#include "ap_mlme.h"
+#include "hostapd.h"
#ifndef CONFIG_NO_HOSTAPD_LOGGER
@@ -80,7 +81,8 @@ void mlme_deauthenticate_indication(struct hostapd_data *hapd,
HOSTAPD_LEVEL_DEBUG,
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
MAC2STR(sta->addr), reason_code);
- mlme_deletekeys_request(hapd, sta);
+ if (!hapd->iface->driver_ap_teardown)
+ mlme_deletekeys_request(hapd, sta);
}
@@ -118,8 +120,6 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
* reassociation procedure that was initiated by that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
- *
- * sta->previous_ap contains the "Current AP" information from ReassocReq.
*/
void mlme_reassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta)
diff --git a/contrib/wpa/src/ap/authsrv.c b/contrib/wpa/src/ap/authsrv.c
index d66d97e..bd1778e 100644
--- a/contrib/wpa/src/ap/authsrv.c
+++ b/contrib/wpa/src/ap/authsrv.c
@@ -79,7 +79,10 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
user->password_hash = eap_user->password_hash;
}
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;
return 0;
}
@@ -92,6 +95,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
+ srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
@@ -111,9 +115,17 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
srv.pwd_group = conf->pwd_group;
+ srv.server_id = conf->server_id ? conf->server_id : "hostapd";
+ srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_HS20
+ srv.subscr_remediation_url = conf->subscr_remediation_url;
+ srv.subscr_remediation_method = conf->subscr_remediation_method;
+#endif /* CONFIG_HS20 */
+ srv.erp = conf->eap_server_erp;
+ srv.erp_domain = conf->erp_domain;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -132,7 +144,7 @@ int authsrv_init(struct hostapd_data *hapd)
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
- hapd->conf->dh_file)) {
+ hapd->conf->private_key || hapd->conf->dh_file)) {
struct tls_connection_params params;
hapd->ssl_ctx = tls_init(NULL);
@@ -148,6 +160,9 @@ int authsrv_init(struct hostapd_data *hapd)
params.private_key = hapd->conf->private_key;
params.private_key_passwd = hapd->conf->private_key_passwd;
params.dh_file = hapd->conf->dh_file;
+ params.openssl_ciphers = hapd->conf->openssl_ciphers;
+ params.ocsp_stapling_response =
+ hapd->conf->ocsp_stapling_response;
if (tls_global_set_params(hapd->ssl_ctx, &params)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
diff --git a/contrib/wpa/src/ap/beacon.c b/contrib/wpa/src/ap/beacon.c
index 4c47c75..e575b65 100644
--- a/contrib/wpa/src/ap/beacon.c
+++ b/contrib/wpa/src/ap/beacon.c
@@ -4,14 +4,8 @@
* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -21,7 +15,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
+#include "common/hw_features_common.h"
#include "wps/wps_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@@ -34,10 +28,56 @@
#include "ap_drv_ops.h"
#include "beacon.h"
#include "hs20.h"
+#include "dfs.h"
#ifdef NEED_AP_MLME
+static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ if (!hapd->conf->radio_measurements || len < 2 + 4)
+ 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;
+}
+
+
+static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ if (len < 2 + 5)
+ return eid;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->bss_load_test_set) {
+ *eid++ = WLAN_EID_BSS_LOAD;
+ *eid++ = 5;
+ os_memcpy(eid, hapd->conf->bss_load_test, 5);
+ eid += 5;
+ return eid;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (hapd->conf->bss_load_update_period) {
+ *eid++ = WLAN_EID_BSS_LOAD;
+ *eid++ = 5;
+ WPA_PUT_LE16(eid, hapd->num_sta);
+ eid += 2;
+ *eid++ = hapd->iface->channel_utilization;
+ WPA_PUT_LE16(eid, 0); /* no available admission capabity */
+ eid += 2;
+ }
+ return eid;
+}
+
+
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
{
u8 erp = 0;
@@ -93,6 +133,74 @@ static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
}
+static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ u8 local_pwr_constraint = 0;
+ int dfs;
+
+ if (hapd->iface->current_mode == NULL ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ /* Let host drivers add this IE if DFS support is offloaded */
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return eid;
+
+ /*
+ * There is no DFS support and power constraint was not directly
+ * requested by config option.
+ */
+ if (!hapd->iconf->ieee80211h &&
+ hapd->iconf->local_pwr_constraint == -1)
+ return eid;
+
+ /* Check if DFS is required by regulatory. */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0) {
+ wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
+ dfs);
+ dfs = 0;
+ }
+
+ if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1)
+ return eid;
+
+ /*
+ * ieee80211h (DFS) is enabled so Power Constraint element shall
+ * be added when running on DFS channel whenever local_pwr_constraint
+ * is configured or not. 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 = 3;
+
+ /*
+ * 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.
+ */
+
+ /* Element ID */
+ *pos++ = WLAN_EID_PWR_CONSTRAINT;
+ /* Length */
+ *pos++ = 1;
+ /* Local Power Constraint */
+ if (local_pwr_constraint)
+ *pos++ = local_pwr_constraint;
+ else
+ *pos++ = hapd->iconf->local_pwr_constraint;
+
+ return pos;
+}
+
+
static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
struct hostapd_channel_data *start,
struct hostapd_channel_data *prev)
@@ -146,7 +254,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
continue; /* can use same entry */
}
- if (start) {
+ if (start && prev) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
start = NULL;
@@ -187,6 +295,70 @@ 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)
+ return eid;
+
+ if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
+ NUM_HOSTAPD_MODES)
+ return eid;
+
+ *eid++ = WLAN_EID_CHANNEL_SWITCH;
+ *eid++ = 3;
+ *eid++ = hapd->cs_block_tx;
+ *eid++ = chan;
+ *eid++ = hapd->cs_count;
+
+ return eid;
+}
+
+
+static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 sec_ch;
+
+ if (!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;
+}
+
+
+static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
+ u8 *start, unsigned int *csa_counter_off)
+{
+ u8 *old_pos = pos;
+
+ if (!csa_counter_off)
+ return pos;
+
+ *csa_counter_off = 0;
+ pos = hostapd_eid_csa(hapd, pos);
+
+ if (pos != old_pos) {
+ /* save an offset to the counter - should be last byte */
+ *csa_counter_off = pos - start - 1;
+ pos = hostapd_eid_secondary_channel(hapd, pos);
+ }
+
+ return pos;
+}
+
+
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
struct sta_info *sta,
const struct ieee80211_mgmt *req,
@@ -208,6 +380,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
+ if (hapd->conf->vendor_vht) {
+ buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -242,6 +418,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_country(hapd, pos, epos - pos);
+ /* Power Constraint element */
+ pos = hostapd_eid_pwr_constraint(hapd, pos);
+
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
@@ -251,6 +430,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* RSN, MDIE, 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);
+
#ifdef CONFIG_IEEE80211N
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
@@ -265,9 +448,15 @@ 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_IEEE80211AC
- pos = hostapd_eid_vht_capabilities(hapd, pos);
- pos = hostapd_eid_vht_operation(hapd, pos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+ }
+ if (hapd->conf->vendor_vht)
+ pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
@@ -297,6 +486,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
+ pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
@@ -390,6 +580,27 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
+ /*
+ * No need to reply if the Probe Request frame was sent on an adjacent
+ * channel. IEEE Std 802.11-2012 describes this as a requirement for an
+ * AP with dot11RadioMeasurementActivated set to true, but strictly
+ * speaking does not allow such ignoring of Probe Request frames if
+ * dot11RadioMeasurementActivated is false. Anyway, this can help reduce
+ * number of unnecessary Probe Response frames for cases where the STA
+ * is less likely to see them (Probe Request frame sent on a
+ * neighboring, but partially overlapping, channel).
+ */
+ if (elems.ds_params && elems.ds_params_len == 1 &&
+ hapd->iface->current_mode &&
+ (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
+ hapd->iconf->channel != elems.ds_params[0]) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u",
+ hapd->iconf->channel, elems.ds_params[0]);
+ return;
+ }
+
#ifdef CONFIG_P2P
if (hapd->p2p && elems.wps_ie) {
struct wpabuf *wps;
@@ -443,12 +654,10 @@ void handle_probe_req(struct hostapd_data *hapd,
sta->ssid_probe = &hapd->conf->ssid;
} else {
if (!(mgmt->da[0] & 0x01)) {
- char ssid_txt[33];
- ieee802_11_print_ssid(ssid_txt, elems.ssid,
- elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")%s",
- MAC2STR(mgmt->sa), ssid_txt,
+ MAC2STR(mgmt->sa),
+ wpa_ssid_txt(elems.ssid, elems.ssid_len),
MAC2STR(mgmt->da),
elems.ssid_list ? " (SSID list)" : "");
}
@@ -456,7 +665,8 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#ifdef CONFIG_INTERWORKING
- if (elems.interworking && elems.interworking_len >= 1) {
+ if (hapd->conf->interworking &&
+ elems.interworking && elems.interworking_len >= 1) {
u8 ant = elems.interworking[0] & 0x0f;
if (ant != INTERWORKING_ANT_WILDCARD &&
ant != hapd->conf->access_network_type) {
@@ -467,7 +677,7 @@ void handle_probe_req(struct hostapd_data *hapd,
}
}
- if (elems.interworking &&
+ if (hapd->conf->interworking && elems.interworking &&
(elems.interworking_len == 7 || elems.interworking_len == 9)) {
const u8 *hessid;
if (elems.interworking_len == 7)
@@ -485,9 +695,30 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_P2P
+ if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+ supp_rates_11b_only(&elems)) {
+ /* Indicates support for 11b rates only */
+ wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
+ MACSTR " with only 802.11b rates",
+ MAC2STR(mgmt->sa));
+ return;
+ }
+#endif /* CONFIG_P2P */
+
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->iconf->ignore_probe_probability > 0.0 &&
+ drand48() < hapd->iconf->ignore_probe_probability) {
+ wpa_printf(MSG_INFO,
+ "TESTING: ignoring probe request from " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
&resp_len);
if (resp == NULL)
@@ -501,7 +732,7 @@ void handle_probe_req(struct hostapd_data *hapd,
is_broadcast_ether_addr(mgmt->da));
if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
- perror("handle_probe_req: send");
+ wpa_printf(MSG_INFO, "handle_probe_req: send failed");
os_free(resp);
@@ -549,23 +780,17 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
{
struct ieee80211_mgmt *head = NULL;
u8 *tail = NULL;
size_t head_len = 0, tail_len = 0;
u8 *resp = NULL;
size_t resp_len = 0;
- struct wpa_driver_ap_params params;
- struct wpabuf *beacon, *proberesp, *assocresp;
#ifdef NEED_AP_MLME
u16 capab_info;
u8 *pos, *tailpos;
-#endif /* NEED_AP_MLME */
-
- hapd->beacon_set_done = 1;
-
-#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -581,12 +806,20 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
+
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht) {
+ tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
+#endif /* CONFIG_IEEE80211AC */
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
os_free(head);
os_free(tail);
- return;
+ return -1;
}
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -631,6 +864,9 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_country(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ /* Power Constraint element */
+ tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
+
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
@@ -641,6 +877,13 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
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 -
+ tailpos);
+
+ tailpos = hostapd_eid_bss_load(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
#ifdef CONFIG_IEEE80211N
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
@@ -657,10 +900,15 @@ void ieee802_11_set_beacon(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_IEEE80211AC
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
- tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ }
+ if (hapd->conf->vendor_vht)
+ tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
@@ -689,6 +937,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
+ tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
@@ -702,94 +951,168 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
resp = hostapd_probe_resp_offloads(hapd, &resp_len);
#endif /* NEED_AP_MLME */
- os_memset(&params, 0, sizeof(params));
- params.head = (u8 *) head;
- params.head_len = head_len;
- params.tail = tail;
- params.tail_len = tail_len;
- params.proberesp = resp;
- params.proberesp_len = resp_len;
- params.dtim_period = hapd->conf->dtim_period;
- params.beacon_int = hapd->iconf->beacon_int;
- params.basic_rates = hapd->iface->basic_rates;
- params.ssid = hapd->conf->ssid.ssid;
- params.ssid_len = hapd->conf->ssid.ssid_len;
- params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
- hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
- params.group_cipher = hapd->conf->wpa_group;
- params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
- params.auth_algs = hapd->conf->auth_algs;
- params.wpa_version = hapd->conf->wpa;
- params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+ os_memset(params, 0, sizeof(*params));
+ params->head = (u8 *) head;
+ params->head_len = head_len;
+ params->tail = tail;
+ params->tail_len = tail_len;
+ params->proberesp = resp;
+ params->proberesp_len = resp_len;
+ params->dtim_period = hapd->conf->dtim_period;
+ params->beacon_int = hapd->iconf->beacon_int;
+ params->basic_rates = hapd->iface->basic_rates;
+ params->ssid = hapd->conf->ssid.ssid;
+ params->ssid_len = hapd->conf->ssid.ssid_len;
+ params->pairwise_ciphers = hapd->conf->wpa_pairwise |
+ hapd->conf->rsn_pairwise;
+ params->group_cipher = hapd->conf->wpa_group;
+ params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+ params->auth_algs = hapd->conf->auth_algs;
+ params->wpa_version = hapd->conf->wpa;
+ params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
(hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len));
switch (hapd->conf->ignore_broadcast_ssid) {
case 0:
- params.hide_ssid = NO_SSID_HIDING;
+ params->hide_ssid = NO_SSID_HIDING;
break;
case 1:
- params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+ params->hide_ssid = HIDDEN_SSID_ZERO_LEN;
break;
case 2:
- params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+ params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
break;
}
- hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
- params.beacon_ies = beacon;
- params.proberesp_ies = proberesp;
- params.assocresp_ies = assocresp;
- params.isolate = hapd->conf->isolate;
+ params->isolate = hapd->conf->isolate;
+ params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
- params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+ params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
- params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+ params->preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
hapd->iconf->preamble == SHORT_PREAMBLE;
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
- params.short_slot_time =
+ params->short_slot_time =
hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
else
- params.short_slot_time = -1;
+ params->short_slot_time = -1;
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
- params.ht_opmode = -1;
+ params->ht_opmode = -1;
else
- params.ht_opmode = hapd->iface->ht_op_mode;
+ params->ht_opmode = hapd->iface->ht_op_mode;
#endif /* NEED_AP_MLME */
- params.interworking = hapd->conf->interworking;
+ params->interworking = hapd->conf->interworking;
if (hapd->conf->interworking &&
!is_zero_ether_addr(hapd->conf->hessid))
- params.hessid = hapd->conf->hessid;
- params.access_network_type = hapd->conf->access_network_type;
- params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+ params->hessid = hapd->conf->hessid;
+ params->access_network_type = hapd->conf->access_network_type;
+ params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
+#ifdef CONFIG_P2P
+ params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
- params.disable_dgaf = hapd->conf->disable_dgaf;
+ params->disable_dgaf = hapd->conf->disable_dgaf;
+ if (hapd->conf->osen) {
+ params->privacy = 1;
+ params->osen = 1;
+ }
#endif /* CONFIG_HS20 */
- if (hostapd_drv_set_ap(hapd, &params))
- wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
- hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+ return 0;
+}
- os_free(tail);
- os_free(head);
- os_free(resp);
+
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
+{
+ os_free(params->tail);
+ params->tail = NULL;
+ os_free(params->head);
+ params->head = NULL;
+ os_free(params->proberesp);
+ params->proberesp = NULL;
}
-void ieee802_11_set_beacons(struct hostapd_iface *iface)
+int ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+ struct wpa_driver_ap_params params;
+ struct hostapd_freq_params freq;
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
+ struct wpabuf *beacon, *proberesp, *assocresp;
+ int res, ret = -1;
+
+ if (hapd->csa_in_progress) {
+ wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
+ return -1;
+ }
+
+ hapd->beacon_set_done = 1;
+
+ if (ieee802_11_build_ap_params(hapd, &params) < 0)
+ return -1;
+
+ if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+ 0)
+ goto fail;
+
+ params.beacon_ies = beacon;
+ params.proberesp_ies = proberesp;
+ params.assocresp_ies = assocresp;
+ params.reenable = hapd->reenable_beacon;
+ hapd->reenable_beacon = 0;
+
+ if (iface->current_mode &&
+ hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+ iconf->channel, iconf->ieee80211n,
+ iconf->ieee80211ac,
+ iconf->secondary_channel,
+ iconf->vht_oper_chwidth,
+ iconf->vht_oper_centr_freq_seg0_idx,
+ iconf->vht_oper_centr_freq_seg1_idx,
+ iface->current_mode->vht_capab) == 0)
+ params.freq = &freq;
+
+ res = hostapd_drv_set_ap(hapd, &params);
+ hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+ if (res)
+ wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+ else
+ ret = 0;
+fail:
+ ieee802_11_free_ap_params(&params);
+ return ret;
+}
+
+
+int ieee802_11_set_beacons(struct hostapd_iface *iface)
{
size_t i;
- for (i = 0; i < iface->num_bss; i++)
- ieee802_11_set_beacon(iface->bss[i]);
+ int ret = 0;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ if (iface->bss[i]->started &&
+ ieee802_11_set_beacon(iface->bss[i]) < 0)
+ ret = -1;
+ }
+
+ return ret;
}
/* only update beacons if started */
-void ieee802_11_update_beacons(struct hostapd_iface *iface)
+int ieee802_11_update_beacons(struct hostapd_iface *iface)
{
size_t i;
- for (i = 0; i < iface->num_bss; i++)
- if (iface->bss[i]->beacon_set_done)
- ieee802_11_set_beacon(iface->bss[i]);
+ int ret = 0;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ if (iface->bss[i]->beacon_set_done && iface->bss[i]->started &&
+ ieee802_11_set_beacon(iface->bss[i]) < 0)
+ ret = -1;
+ }
+
+ return ret;
}
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/wpa/src/ap/beacon.h b/contrib/wpa/src/ap/beacon.h
index 37f10d2..722159a 100644
--- a/contrib/wpa/src/ap/beacon.h
+++ b/contrib/wpa/src/ap/beacon.h
@@ -3,14 +3,8 @@
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef BEACON_H
@@ -21,8 +15,11 @@ struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal);
-void ieee802_11_set_beacon(struct hostapd_data *hapd);
-void ieee802_11_set_beacons(struct hostapd_iface *iface);
-void ieee802_11_update_beacons(struct hostapd_iface *iface);
+int ieee802_11_set_beacon(struct hostapd_data *hapd);
+int ieee802_11_set_beacons(struct hostapd_iface *iface);
+int ieee802_11_update_beacons(struct hostapd_iface *iface);
+int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params);
+void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
#endif /* BEACON_H */
diff --git a/contrib/wpa/src/ap/bss_load.c b/contrib/wpa/src/ap/bss_load.c
new file mode 100644
index 0000000..fb63942
--- /dev/null
+++ b/contrib/wpa/src/ap/bss_load.c
@@ -0,0 +1,65 @@
+/*
+ * BSS Load Element / Channel Utilization
+ * Copyright (c) 2014, 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 "hostapd.h"
+#include "bss_load.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+
+
+static void update_channel_utilization(void *eloop_data, void *user_data)
+{
+ struct hostapd_data *hapd = eloop_data;
+ unsigned int sec, usec;
+ int err;
+
+ if (!(hapd->beacon_set_done && hapd->started))
+ return;
+
+ err = hostapd_drv_get_survey(hapd, hapd->iface->freq);
+ if (err) {
+ wpa_printf(MSG_ERROR, "BSS Load: Failed to get survey data");
+ return;
+ }
+
+ ieee802_11_set_beacon(hapd);
+
+ 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);
+}
+
+
+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)
+ 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;
+}
+
+
+void bss_load_update_deinit(struct hostapd_data *hapd)
+{
+ eloop_cancel_timeout(update_channel_utilization, hapd, NULL);
+}
diff --git a/contrib/wpa/src/ap/bss_load.h b/contrib/wpa/src/ap/bss_load.h
new file mode 100644
index 0000000..ac3c793
--- /dev/null
+++ b/contrib/wpa/src/ap/bss_load.h
@@ -0,0 +1,17 @@
+/*
+ * BSS load update
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSS_LOAD_UPDATE_H
+#define BSS_LOAD_UPDATE_H
+
+
+int bss_load_update_init(struct hostapd_data *hapd);
+void bss_load_update_deinit(struct hostapd_data *hapd);
+
+
+#endif /* BSS_LOAD_UPDATE_H */
diff --git a/contrib/wpa/src/ap/ctrl_iface_ap.c b/contrib/wpa/src/ap/ctrl_iface_ap.c
index c55d3fe..41ab988 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-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,8 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
+#include "eapol_auth/eapol_auth_sm.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
@@ -21,25 +23,61 @@
#include "ap_drv_ops.h"
+static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ char *buf, size_t buflen)
+{
+ struct hostap_sta_driver_data data;
+ int ret;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return 0;
+
+ ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
+ "rx_bytes=%lu\ntx_bytes=%lu\n",
+ data.rx_packets, data.tx_packets,
+ data.rx_bytes, data.tx_bytes);
+ if (os_snprintf_error(buflen, ret))
+ return 0;
+ return ret;
+}
+
+
static int hostapd_get_sta_conn_time(struct sta_info *sta,
char *buf, size_t buflen)
{
- struct os_time now, age;
- int len = 0, ret;
+ struct os_reltime age;
+ int ret;
if (!sta->connected_time.sec)
return 0;
- os_get_time(&now);
- os_time_sub(&now, &sta->connected_time, &age);
+ os_reltime_age(&sta->connected_time, &age);
- ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
+ ret = os_snprintf(buf, buflen, "connected_time=%u\n",
(unsigned int) age.sec);
- if (ret < 0 || (size_t) ret >= buflen - len)
- return len;
- len += ret;
+ if (os_snprintf_error(buflen, ret))
+ return 0;
+ return ret;
+}
- return len;
+
+static const char * timeout_next_str(int val)
+{
+ switch (val) {
+ case STA_NULLFUNC:
+ return "NULLFUNC POLL";
+ case STA_DISASSOC:
+ return "DISASSOC";
+ case STA_DEAUTH:
+ return "DEAUTH";
+ case STA_REMOVE:
+ return "REMOVE";
+ case STA_DISASSOC_FROM_CLI:
+ return "DISASSOC_FROM_CLI";
+ }
+
+ return "?";
}
@@ -47,19 +85,42 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
- int len, res, ret;
+ int len, res, ret, i;
- if (sta == NULL) {
- ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
- return 0;
- return ret;
- }
+ if (!sta)
+ return 0;
len = 0;
- ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
+ ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
MAC2STR(sta->addr));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
+ if (ret < 0)
+ return len;
+ len += ret;
+
+ ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
+ "listen_interval=%d\nsupported_rates=",
+ sta->aid, sta->capability, sta->listen_interval);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ for (i = 0; i < sta->supported_rates_len; i++) {
+ ret = os_snprintf(buf + len, buflen - len, "%02x%s",
+ sta->supported_rates[i],
+ i + 1 < sta->supported_rates_len ? " " : "");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
+ timeout_next_str(sta->timeout_next));
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -80,9 +141,17 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (res >= 0)
len += res;
- res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
- if (res >= 0)
- len += res;
+ len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
+ len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+
+#ifdef CONFIG_SAE
+ if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
+ res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
+ sta->sae->group);
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_SAE */
return len;
}
@@ -100,15 +169,37 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
{
u8 addr[ETH_ALEN];
int ret;
+ const char *pos;
+ struct sta_info *sta;
if (hwaddr_aton(txtaddr, addr)) {
ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
- return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
- buf, buflen);
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL)
+ return -1;
+
+ pos = os_strchr(txtaddr, ' ');
+ if (pos) {
+ pos++;
+
+#ifdef HOSTAPD_DUMP_STATE
+ if (os_strcmp(pos, "eapol") == 0) {
+ if (sta->eapol_sm == NULL)
+ return -1;
+ return eapol_auth_dump_state(sta->eapol_sm, buf,
+ buflen);
+ }
+#endif /* HOSTAPD_DUMP_STATE */
+
+ return -1;
+ }
+
+ return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
}
@@ -122,10 +213,14 @@ int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
if (hwaddr_aton(txtaddr, addr) ||
(sta = ap_get_sta(hapd, addr)) == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
return ret;
- }
+ }
+
+ if (!sta->next)
+ return 0;
+
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
@@ -145,11 +240,12 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
if (mgmt == NULL)
return -1;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
- " with minor reason code %u (stype=%u)",
- MAC2STR(addr), minor_reason_code, stype);
+ " with minor reason code %u (stype=%u (%s))",
+ MAC2STR(addr), minor_reason_code, stype,
+ fc2str(mgmt->frame_control));
- mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
@@ -165,9 +261,8 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 4 + 3 + 1;
- WPA_PUT_BE24(pos, OUI_WFA);
- pos += 3;
- *pos++ = P2P_OUI_TYPE;
+ WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
+ pos += 4;
*pos++ = P2P_ATTR_MINOR_REASON_CODE;
WPA_PUT_LE16(pos, 1);
@@ -189,6 +284,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
txtaddr);
@@ -196,6 +292,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (hwaddr_aton(txtaddr, addr))
return -1;
+ pos = os_strstr(txtaddr, " reason=");
+ if (pos)
+ reason = atoi(pos + 8);
+
pos = os_strstr(txtaddr, " test=");
if (pos) {
struct ieee80211_mgmt mgmt;
@@ -210,8 +310,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
os_memcpy(mgmt.da, addr, ETH_ALEN);
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.deauth.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ mgmt.u.deauth.reason_code = host_to_le16(reason);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
@@ -228,11 +327,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
- ap_sta_deauthenticate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_deauthenticate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
@@ -246,6 +344,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
txtaddr);
@@ -253,6 +352,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (hwaddr_aton(txtaddr, addr))
return -1;
+ pos = os_strstr(txtaddr, " reason=");
+ if (pos)
+ reason = atoi(pos + 8);
+
pos = os_strstr(txtaddr, " test=");
if (pos) {
struct ieee80211_mgmt mgmt;
@@ -267,8 +370,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
os_memcpy(mgmt.da, addr, ETH_ALEN);
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.disassoc.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ mgmt.u.disassoc.reason_code = host_to_le16(reason);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
@@ -285,13 +387,159 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
- ap_sta_disassociate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_disassociate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
return 0;
}
+
+
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+ size_t buflen)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ int len = 0, ret;
+ size_t i;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "state=%s\n"
+ "phy=%s\n"
+ "freq=%d\n"
+ "num_sta_non_erp=%d\n"
+ "num_sta_no_short_slot_time=%d\n"
+ "num_sta_no_short_preamble=%d\n"
+ "olbc=%d\n"
+ "num_sta_ht_no_gf=%d\n"
+ "num_sta_no_ht=%d\n"
+ "num_sta_ht_20_mhz=%d\n"
+ "num_sta_ht40_intolerant=%d\n"
+ "olbc_ht=%d\n"
+ "ht_op_mode=0x%x\n",
+ hostapd_state_text(iface->state),
+ iface->phy,
+ iface->freq,
+ iface->num_sta_non_erp,
+ iface->num_sta_no_short_slot_time,
+ iface->num_sta_no_short_preamble,
+ iface->olbc,
+ iface->num_sta_ht_no_gf,
+ iface->num_sta_no_ht,
+ iface->num_sta_ht_20mhz,
+ iface->num_sta_ht40_intolerant,
+ iface->olbc_ht,
+ iface->ht_op_mode);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ if (!iface->cac_started || !iface->dfs_cac_ms) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "cac_time_seconds=%d\n"
+ "cac_time_left_seconds=N/A\n",
+ iface->dfs_cac_ms / 1000);
+ } else {
+ /* CAC started and CAC time set - calculate remaining time */
+ struct os_reltime now;
+ unsigned int left_time;
+
+ os_reltime_age(&iface->dfs_cac_start, &now);
+ left_time = iface->dfs_cac_ms / 1000 - now.sec;
+ ret = os_snprintf(buf + len, buflen - len,
+ "cac_time_seconds=%u\n"
+ "cac_time_left_seconds=%u\n",
+ iface->dfs_cac_ms / 1000,
+ left_time);
+ }
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "channel=%u\n"
+ "secondary_channel=%d\n"
+ "ieee80211n=%d\n"
+ "ieee80211ac=%d\n"
+ "vht_oper_chwidth=%d\n"
+ "vht_oper_centr_freq_seg0_idx=%d\n"
+ "vht_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->channel,
+ iface->conf->secondary_channel,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *bss = iface->bss[i];
+ ret = os_snprintf(buf + len, buflen - len,
+ "bss[%d]=%s\n"
+ "bssid[%d]=" MACSTR "\n"
+ "ssid[%d]=%s\n"
+ "num_sta[%d]=%d\n",
+ (int) i, bss->conf->iface,
+ (int) i, MAC2STR(bss->own_addr),
+ (int) i,
+ wpa_ssid_txt(bss->conf->ssid.ssid,
+ bss->conf->ssid.ssid_len),
+ (int) i, bss->num_sta);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ return len;
+}
+
+
+int hostapd_parse_csa_settings(const char *pos,
+ struct csa_settings *settings)
+{
+ char *end;
+
+ os_memset(settings, 0, sizeof(*settings));
+ settings->cs_count = strtol(pos, &end, 10);
+ if (pos == end) {
+ wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
+ return -1;
+ }
+
+ settings->freq_params.freq = atoi(end);
+ if (settings->freq_params.freq == 0) {
+ wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
+ return -1;
+ }
+
+#define SET_CSA_SETTING(str) \
+ do { \
+ const char *pos2 = os_strstr(pos, " " #str "="); \
+ if (pos2) { \
+ pos2 += sizeof(" " #str "=") - 1; \
+ settings->freq_params.str = atoi(pos2); \
+ } \
+ } while (0)
+
+ SET_CSA_SETTING(center_freq1);
+ SET_CSA_SETTING(center_freq2);
+ SET_CSA_SETTING(bandwidth);
+ SET_CSA_SETTING(sec_channel_offset);
+ settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
+ settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+ settings->block_tx = !!os_strstr(pos, " blocktx");
+#undef SET_CSA_SETTING
+
+ return 0;
+}
+
+
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
+{
+ return hostapd_drv_stop_ap(hapd);
+}
diff --git a/contrib/wpa/src/ap/ctrl_iface_ap.h b/contrib/wpa/src/ap/ctrl_iface_ap.h
index e83f894..e5297d0 100644
--- a/contrib/wpa/src/ap/ctrl_iface_ap.h
+++ b/contrib/wpa/src/ap/ctrl_iface_ap.h
@@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,5 +19,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
const char *txtaddr);
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
const char *txtaddr);
+int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
+ size_t buflen);
+int hostapd_parse_csa_settings(const char *pos,
+ struct csa_settings *settings);
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_AP_H */
diff --git a/contrib/wpa/src/ap/dfs.c b/contrib/wpa/src/ap/dfs.c
new file mode 100644
index 0000000..da6fd46
--- /dev/null
+++ b/contrib/wpa/src/ap/dfs.c
@@ -0,0 +1,1064 @@
+/*
+ * DFS - Dynamic Frequency Selection
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2013-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 "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "drivers/driver.h"
+#include "dfs.h"
+
+
+static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
+{
+ int n_chans = 1;
+
+ *seg1 = 0;
+
+ if (iface->conf->ieee80211n && iface->conf->secondary_channel)
+ n_chans = 2;
+
+ if (iface->conf->ieee80211ac) {
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ break;
+ case VHT_CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ n_chans = 4;
+ *seg1 = 4;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return n_chans;
+}
+
+
+static int dfs_channel_available(struct hostapd_channel_data *chan,
+ int skip_radar)
+{
+ /*
+ * When radar detection happens, CSA is performed. However, there's no
+ * time for CAC, so radar channels must be skipped when finding a new
+ * channel for CSA, unless they are available for immediate use.
+ */
+ if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
+ ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
+ HOSTAPD_CHAN_DFS_AVAILABLE))
+ return 0;
+
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ return 0;
+ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+ HOSTAPD_CHAN_DFS_UNAVAILABLE))
+ return 0;
+ return 1;
+}
+
+
+static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
+{
+ /*
+ * The tables contain first valid channel number based on channel width.
+ * We will also choose this first channel as the control one.
+ */
+ int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+ 184, 192 };
+ /*
+ * VHT80, valid channels based on center frequency:
+ * 42, 58, 106, 122, 138, 155
+ */
+ int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+ /*
+ * VHT160 valid channels based on center frequency:
+ * 50, 114
+ */
+ int allowed_160[] = { 36, 100 };
+ int *allowed = allowed_40;
+ unsigned int i, allowed_no = 0;
+
+ switch (n_chans) {
+ case 2:
+ allowed = allowed_40;
+ allowed_no = ARRAY_SIZE(allowed_40);
+ break;
+ case 4:
+ allowed = allowed_80;
+ allowed_no = ARRAY_SIZE(allowed_80);
+ break;
+ case 8:
+ allowed = allowed_160;
+ allowed_no = ARRAY_SIZE(allowed_160);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
+ break;
+ }
+
+ for (i = 0; i < allowed_no; i++) {
+ if (chan->chan == allowed[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
+ int first_chan_idx, int num_chans,
+ int skip_radar)
+{
+ struct hostapd_channel_data *first_chan, *chan;
+ int i;
+
+ if (first_chan_idx + num_chans >= mode->num_channels)
+ return 0;
+
+ first_chan = &mode->channels[first_chan_idx];
+
+ for (i = 0; i < num_chans; i++) {
+ chan = &mode->channels[first_chan_idx + i];
+
+ if (first_chan->freq + i * 20 != chan->freq)
+ return 0;
+
+ if (!dfs_channel_available(chan, skip_radar))
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int is_in_chanlist(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ int *entry;
+
+ if (!iface->conf->chanlist)
+ return 1;
+
+ for (entry = iface->conf->chanlist; *entry != -1; entry++) {
+ if (*entry == chan->chan)
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * The function assumes HT40+ operation.
+ * Make sure to adjust the following variables after calling this:
+ * - hapd->secondary_channel
+ * - hapd->vht_oper_centr_freq_seg0_idx
+ * - hapd->vht_oper_centr_freq_seg1_idx
+ */
+static int dfs_find_channel(struct hostapd_iface *iface,
+ struct hostapd_channel_data **ret_chan,
+ int idx, int skip_radar)
+{
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+ int i, channel_idx = 0, n_chans, n_chans1;
+
+ mode = iface->current_mode;
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
+
+ wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ /* Skip HT40/VHT incompatible channels */
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel &&
+ !dfs_is_chan_allowed(chan, n_chans))
+ continue;
+
+ /* Skip incompatible chandefs */
+ if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
+ continue;
+
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
+ if (ret_chan && idx == channel_idx) {
+ wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+ *ret_chan = chan;
+ return idx;
+ }
+ wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+ channel_idx++;
+ }
+ return channel_idx;
+}
+
+
+static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ int secondary_channel,
+ u8 *vht_oper_centr_freq_seg0_idx,
+ u8 *vht_oper_centr_freq_seg1_idx)
+{
+ if (!iface->conf->ieee80211ac)
+ return;
+
+ if (!chan)
+ return;
+
+ *vht_oper_centr_freq_seg1_idx = 0;
+
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ if (secondary_channel == 1)
+ *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+ else if (secondary_channel == -1)
+ *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
+ else
+ *vht_oper_centr_freq_seg0_idx = chan->chan;
+ break;
+ case VHT_CHANWIDTH_80MHZ:
+ *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
+ break;
+ default:
+ wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
+ *vht_oper_centr_freq_seg0_idx = 0;
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
+ *vht_oper_centr_freq_seg0_idx,
+ *vht_oper_centr_freq_seg1_idx);
+}
+
+
+/* Return start channel idx we will use for mode->channels[idx] */
+static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
+{
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+ int channel_no = iface->conf->channel;
+ int res = -1, i;
+ int chan_seg1 = -1;
+
+ *seg1_start = -1;
+
+ /* HT40- */
+ if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
+ channel_no -= 4;
+
+ /* VHT */
+ if (iface->conf->ieee80211ac) {
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ break;
+ case VHT_CHANWIDTH_80MHZ:
+ channel_no =
+ iface->conf->vht_oper_centr_freq_seg0_idx - 6;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ channel_no =
+ iface->conf->vht_oper_centr_freq_seg0_idx - 14;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ channel_no =
+ iface->conf->vht_oper_centr_freq_seg0_idx - 6;
+ chan_seg1 =
+ iface->conf->vht_oper_centr_freq_seg1_idx - 6;
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "DFS only VHT20/40/80/160/80+80 is supported now");
+ channel_no = -1;
+ break;
+ }
+ }
+
+ /* Get idx */
+ mode = iface->current_mode;
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if (chan->chan == channel_no) {
+ res = i;
+ break;
+ }
+ }
+
+ if (res != -1 && chan_seg1 > -1) {
+ int found = 0;
+
+ /* Get idx for seg1 */
+ mode = iface->current_mode;
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if (chan->chan == chan_seg1) {
+ *seg1_start = i;
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ res = -1;
+ }
+
+ if (res == -1) {
+ wpa_printf(MSG_DEBUG,
+ "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
+ mode->num_channels, channel_no, iface->conf->channel,
+ iface->conf->ieee80211n,
+ iface->conf->secondary_channel,
+ iface->conf->vht_oper_chwidth);
+
+ for (i = 0; i < mode->num_channels; i++) {
+ wpa_printf(MSG_DEBUG, "Available channel: %d",
+ mode->channels[i].chan);
+ }
+ }
+
+ return res;
+}
+
+
+/* At least one channel have radar flag */
+static int dfs_check_chans_radar(struct hostapd_iface *iface,
+ int start_chan_idx, int n_chans)
+{
+ struct hostapd_channel_data *channel;
+ struct hostapd_hw_modes *mode;
+ int i, res = 0;
+
+ mode = iface->current_mode;
+
+ for (i = 0; i < n_chans; i++) {
+ channel = &mode->channels[start_chan_idx + i];
+ if (channel->flag & HOSTAPD_CHAN_RADAR)
+ res++;
+ }
+
+ return res;
+}
+
+
+/* All channels available */
+static int dfs_check_chans_available(struct hostapd_iface *iface,
+ int start_chan_idx, int n_chans)
+{
+ struct hostapd_channel_data *channel;
+ struct hostapd_hw_modes *mode;
+ int i;
+
+ mode = iface->current_mode;
+
+ for (i = 0; i < n_chans; i++) {
+ channel = &mode->channels[start_chan_idx + i];
+
+ if (channel->flag & HOSTAPD_CHAN_DISABLED)
+ break;
+
+ if (!(channel->flag & HOSTAPD_CHAN_RADAR))
+ continue;
+
+ if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
+ HOSTAPD_CHAN_DFS_AVAILABLE)
+ break;
+ }
+
+ return i == n_chans;
+}
+
+
+/* At least one channel unavailable */
+static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
+ int start_chan_idx,
+ int n_chans)
+{
+ struct hostapd_channel_data *channel;
+ struct hostapd_hw_modes *mode;
+ int i, res = 0;
+
+ mode = iface->current_mode;
+
+ for (i = 0; i < n_chans; i++) {
+ channel = &mode->channels[start_chan_idx + i];
+ if (channel->flag & HOSTAPD_CHAN_DISABLED)
+ res++;
+ if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
+ HOSTAPD_CHAN_DFS_UNAVAILABLE)
+ res++;
+ }
+
+ return res;
+}
+
+
+static struct hostapd_channel_data *
+dfs_get_valid_channel(struct hostapd_iface *iface,
+ int *secondary_channel,
+ u8 *vht_oper_centr_freq_seg0_idx,
+ u8 *vht_oper_centr_freq_seg1_idx,
+ int skip_radar)
+{
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan = NULL;
+ int num_available_chandefs;
+ int chan_idx;
+ u32 _rand;
+
+ wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
+ *secondary_channel = 0;
+ *vht_oper_centr_freq_seg0_idx = 0;
+ *vht_oper_centr_freq_seg1_idx = 0;
+
+ if (iface->current_mode == NULL)
+ return NULL;
+
+ mode = iface->current_mode;
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return NULL;
+
+ /* Get the count first */
+ num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+ if (num_available_chandefs == 0)
+ return NULL;
+
+ if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+ _rand = os_random();
+ chan_idx = _rand % num_available_chandefs;
+ dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+
+ /* dfs_find_channel() calculations assume HT40+ */
+ if (iface->conf->secondary_channel)
+ *secondary_channel = 1;
+ else
+ *secondary_channel = 0;
+
+ dfs_adjust_vht_center_freq(iface, chan,
+ *secondary_channel,
+ vht_oper_centr_freq_seg0_idx,
+ vht_oper_centr_freq_seg1_idx);
+
+ return chan;
+}
+
+
+static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
+{
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan = NULL;
+ int i;
+
+ mode = iface->current_mode;
+ if (mode == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+ if (chan->freq == freq) {
+ if (chan->flag & HOSTAPD_CHAN_RADAR) {
+ chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
+ chan->flag |= state;
+ return 1; /* Channel found */
+ }
+ }
+ }
+ wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
+ return 0;
+}
+
+
+static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
+ int chan_offset, int chan_width, int cf1,
+ int cf2, u32 state)
+{
+ int n_chans = 1, i;
+ struct hostapd_hw_modes *mode;
+ int frequency = freq;
+ int ret = 0;
+
+ mode = iface->current_mode;
+ if (mode == NULL)
+ return 0;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
+ wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
+ return 0;
+ }
+
+ /* Seems cf1 and chan_width is enough here */
+ switch (chan_width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ n_chans = 1;
+ if (frequency == 0)
+ frequency = cf1;
+ break;
+ case CHAN_WIDTH_40:
+ n_chans = 2;
+ frequency = cf1 - 10;
+ break;
+ case CHAN_WIDTH_80:
+ n_chans = 4;
+ frequency = cf1 - 30;
+ break;
+ case CHAN_WIDTH_160:
+ n_chans = 8;
+ frequency = cf1 - 70;
+ break;
+ default:
+ wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
+ chan_width);
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
+ n_chans);
+ for (i = 0; i < n_chans; i++) {
+ ret += set_dfs_state_freq(iface, frequency, state);
+ frequency = frequency + 20;
+ }
+
+ return ret;
+}
+
+
+static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
+ int chan_width, int cf1, int cf2)
+{
+ int start_chan_idx, start_chan_idx1;
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+ int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
+ u8 radar_chan;
+ int res = 0;
+
+ /* Our configuration */
+ mode = iface->current_mode;
+ start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
+
+ /* Check we are on DFS channel(s) */
+ if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
+ return 0;
+
+ /* Reported via radar event */
+ switch (chan_width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ radar_n_chans = 1;
+ if (frequency == 0)
+ frequency = cf1;
+ break;
+ case CHAN_WIDTH_40:
+ radar_n_chans = 2;
+ frequency = cf1 - 10;
+ break;
+ case CHAN_WIDTH_80:
+ radar_n_chans = 4;
+ frequency = cf1 - 30;
+ break;
+ case CHAN_WIDTH_160:
+ radar_n_chans = 8;
+ frequency = cf1 - 70;
+ break;
+ default:
+ wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
+ chan_width);
+ break;
+ }
+
+ ieee80211_freq_to_chan(frequency, &radar_chan);
+
+ for (i = 0; i < n_chans; i++) {
+ chan = &mode->channels[start_chan_idx + i];
+ if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+ continue;
+ for (j = 0; j < radar_n_chans; j++) {
+ wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
+ chan->chan, radar_chan + j * 4);
+ if (chan->chan == radar_chan + j * 4)
+ res++;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "overlapped: %d", res);
+
+ return res;
+}
+
+
+static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
+ int start_chan_idx, int n_chans)
+{
+ struct hostapd_channel_data *channel;
+ struct hostapd_hw_modes *mode;
+ int i;
+ unsigned int cac_time_ms = 0;
+
+ mode = iface->current_mode;
+
+ for (i = 0; i < n_chans; i++) {
+ channel = &mode->channels[start_chan_idx + i];
+ if (!(channel->flag & HOSTAPD_CHAN_RADAR))
+ continue;
+ if (channel->dfs_cac_ms > cac_time_ms)
+ cac_time_ms = channel->dfs_cac_ms;
+ }
+
+ return cac_time_ms;
+}
+
+
+/*
+ * Main DFS handler
+ * 1 - continue channel/ap setup
+ * 0 - channel/ap setup will be continued after CAC
+ * -1 - hit critical error
+ */
+int hostapd_handle_dfs(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *channel;
+ int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
+ int skip_radar = 0;
+
+ if (!iface->current_mode) {
+ /*
+ * This can happen with drivers that do not provide mode
+ * information and as such, cannot really use hostapd for DFS.
+ */
+ wpa_printf(MSG_DEBUG,
+ "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
+ return 1;
+ }
+
+ iface->cac_started = 0;
+
+ do {
+ /* Get start (first) channel for current configuration */
+ start_chan_idx = dfs_get_start_chan_idx(iface,
+ &start_chan_idx1);
+ if (start_chan_idx == -1)
+ return -1;
+
+ /* Get number of used channels, depend on width */
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
+
+ /* Setup CAC time */
+ iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
+ n_chans);
+
+ /* Check if any of configured channels require DFS */
+ res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
+ wpa_printf(MSG_DEBUG,
+ "DFS %d channels required radar detection",
+ res);
+ if (!res)
+ return 1;
+
+ /* Check if all channels are DFS available */
+ res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
+ wpa_printf(MSG_DEBUG,
+ "DFS all channels available, (SKIP CAC): %s",
+ res ? "yes" : "no");
+ if (res)
+ return 1;
+
+ /* Check if any of configured channels is unavailable */
+ res = dfs_check_chans_unavailable(iface, start_chan_idx,
+ n_chans);
+ wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
+ res, res ? "yes": "no");
+ if (res) {
+ int sec = 0;
+ u8 cf1 = 0, cf2 = 0;
+
+ channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
+ skip_radar);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "could not get valid channel");
+ return -1;
+ }
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = sec;
+ iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
+ iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
+ }
+ } while (res);
+
+ /* Finally start CAC */
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+ "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
+ iface->freq,
+ iface->conf->channel, iface->conf->secondary_channel,
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx,
+ iface->dfs_cac_ms / 1000);
+
+ res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ iface->freq,
+ iface->conf->channel,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->secondary_channel,
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx);
+
+ if (res) {
+ wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2)
+{
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
+ "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+ success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+ if (success) {
+ /* Complete iface/ap configuration */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+ /* Complete AP configuration for the first bring up. */
+ if (iface->state != HAPD_IFACE_ENABLED)
+ hostapd_setup_interface_complete(iface, 0);
+ else
+ iface->cac_started = 0;
+ } else {
+ set_dfs_state(iface, freq, ht_enabled, chan_offset,
+ chan_width, cf1, cf2,
+ HOSTAPD_CHAN_DFS_AVAILABLE);
+ iface->cac_started = 0;
+ hostapd_setup_interface_complete(iface, 0);
+ }
+ }
+
+ return 0;
+}
+
+
+static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *channel;
+ int secondary_channel;
+ u8 vht_oper_centr_freq_seg0_idx = 0;
+ u8 vht_oper_centr_freq_seg1_idx = 0;
+ int skip_radar = 0;
+ int err = 1;
+
+ /* Radar detected during active CAC */
+ iface->cac_started = 0;
+ channel = dfs_get_valid_channel(iface, &secondary_channel,
+ &vht_oper_centr_freq_seg0_idx,
+ &vht_oper_centr_freq_seg1_idx,
+ skip_radar);
+
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "No valid channel available");
+ hostapd_setup_interface_complete(iface, err);
+ return err;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+ channel->chan);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+ "freq=%d chan=%d sec_chan=%d", channel->freq,
+ channel->chan, secondary_channel);
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ iface->conf->vht_oper_centr_freq_seg0_idx =
+ vht_oper_centr_freq_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx =
+ vht_oper_centr_freq_seg1_idx;
+ err = 0;
+
+ hostapd_setup_interface_complete(iface, err);
+ return err;
+}
+
+
+static int hostapd_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;
+ int secondary_channel;
+ u8 vht_oper_centr_freq_seg0_idx;
+ u8 vht_oper_centr_freq_seg1_idx;
+ int skip_radar = 1;
+ struct csa_settings csa_settings;
+ unsigned int i;
+ int err = 1;
+
+ wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
+ __func__, iface->cac_started ? "yes" : "no",
+ hostapd_csa_in_progress(iface) ? "yes" : "no");
+
+ /* Check if CSA in progress */
+ if (hostapd_csa_in_progress(iface))
+ return 0;
+
+ /* Check if active CAC */
+ if (iface->cac_started)
+ return hostapd_dfs_start_channel_switch_cac(iface);
+
+ /* Perform channel switch/CSA */
+ channel = dfs_get_valid_channel(iface, &secondary_channel,
+ &vht_oper_centr_freq_seg0_idx,
+ &vht_oper_centr_freq_seg1_idx,
+ skip_radar);
+
+ if (!channel) {
+ /*
+ * If there is no channel to switch immediately to, check if
+ * there is another channel where we can switch even if it
+ * requires to perform a CAC first.
+ */
+ skip_radar = 0;
+ channel = dfs_get_valid_channel(iface, &secondary_channel,
+ &vht_oper_centr_freq_seg0_idx,
+ &vht_oper_centr_freq_seg1_idx,
+ skip_radar);
+ if (!channel) {
+ /* FIXME: Wait for channel(s) to become available */
+ hostapd_disable_iface(iface);
+ return err;
+ }
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ iface->conf->vht_oper_centr_freq_seg0_idx =
+ vht_oper_centr_freq_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx =
+ vht_oper_centr_freq_seg1_idx;
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+ channel->chan);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+ "freq=%d chan=%d sec_chan=%d", channel->freq,
+ channel->chan, secondary_channel);
+
+ /* Setup CSA request */
+ os_memset(&csa_settings, 0, sizeof(csa_settings));
+ csa_settings.cs_count = 5;
+ csa_settings.block_tx = 1;
+ err = hostapd_set_freq_params(&csa_settings.freq_params,
+ iface->conf->hw_mode,
+ channel->freq,
+ channel->chan,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ secondary_channel,
+ iface->conf->vht_oper_chwidth,
+ vht_oper_centr_freq_seg0_idx,
+ vht_oper_centr_freq_seg1_idx,
+ iface->current_mode->vht_capab);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
+ hostapd_disable_iface(iface);
+ return err;
+ }
+
+ for (i = 0; i < iface->num_bss; i++) {
+ err = hostapd_switch_channel(iface->bss[i], &csa_settings);
+ if (err)
+ break;
+ }
+
+ if (err) {
+ wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
+ err);
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ iface->conf->vht_oper_centr_freq_seg0_idx =
+ vht_oper_centr_freq_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx =
+ vht_oper_centr_freq_seg1_idx;
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
+ }
+
+ /* Channel configuration will be updated once CSA completes and
+ * ch_switch_notify event is received */
+
+ wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
+ return 0;
+}
+
+
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2)
+{
+ int res;
+
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
+ "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+ freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+ /* Proceed only if DFS is not offloaded to the driver */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return 0;
+
+ if (!iface->conf->ieee80211h)
+ return 0;
+
+ /* mark radar frequency as invalid */
+ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+
+ /* Skip if reported radar event not overlapped our channels */
+ res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
+ if (!res)
+ return 0;
+
+ /* radar detected while operating, switch the channel. */
+ res = hostapd_dfs_start_channel_switch(iface);
+
+ return res;
+}
+
+
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2)
+{
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
+ "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+ freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+ /* Proceed only if DFS is not offloaded to the driver */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return 0;
+
+ /* TODO add correct implementation here */
+ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+ return 0;
+}
+
+
+int hostapd_is_dfs_required(struct hostapd_iface *iface)
+{
+ int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
+
+ if (!iface->conf->ieee80211h || !iface->current_mode ||
+ iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ /* Get start (first) channel for current configuration */
+ start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
+ if (start_chan_idx == -1)
+ return -1;
+
+ /* Get number of used channels, depend on width */
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
+
+ /* Check if any of configured channels require DFS */
+ res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
+ if (res)
+ return res;
+ if (start_chan_idx1 >= 0 && n_chans1 > 0)
+ res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
+ return res;
+}
+
+
+int hostapd_dfs_start_cac(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_CAC_START
+ "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
+ "seg1=%d cac_time=%ds",
+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+ iface->cac_started = 1;
+ return 0;
+}
+
+
+/*
+ * Main DFS handler for offloaded case.
+ * 2 - continue channel/AP setup for non-DFS channel
+ * 1 - continue channel/AP setup for DFS channel
+ * 0 - channel/AP setup will be continued after CAC
+ * -1 - hit critical error
+ */
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
+{
+ wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+ __func__, iface->cac_started);
+
+ /*
+ * If DFS has already been started, then we are being called from a
+ * callback to continue AP/channel setup. Reset the CAC start flag and
+ * return.
+ */
+ if (iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+ __func__, iface->cac_started);
+ iface->cac_started = 0;
+ return 1;
+ }
+
+ if (ieee80211_is_dfs(iface->freq)) {
+ wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
+ __func__, iface->freq);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
+ __func__, iface->freq);
+ return 2;
+}
diff --git a/contrib/wpa/src/ap/dfs.h b/contrib/wpa/src/ap/dfs.h
new file mode 100644
index 0000000..be8c0e6
--- /dev/null
+++ b/contrib/wpa/src/ap/dfs.h
@@ -0,0 +1,30 @@
+/*
+ * DFS - Dynamic Frequency Selection
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef DFS_H
+#define DFS_H
+
+int hostapd_handle_dfs(struct hostapd_iface *iface);
+
+int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2);
+int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
+ int ht_enabled,
+ int chan_offset, int chan_width,
+ int cf1, int cf2);
+int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
+ int ht_enabled,
+ int chan_offset, int chan_width, int cf1, int cf2);
+int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2);
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
+
+#endif /* DFS_H */
diff --git a/contrib/wpa/src/ap/dhcp_snoop.c b/contrib/wpa/src/ap/dhcp_snoop.c
new file mode 100644
index 0000000..3a77225
--- /dev/null
+++ b/contrib/wpa/src/ap/dhcp_snoop.c
@@ -0,0 +1,178 @@
+/*
+ * DHCP snooping for Proxy ARP
+ * Copyright (c) 2014, 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 <netinet/ip.h>
+#include <netinet/udp.h>
+
+#include "utils/common.h"
+#include "l2_packet/l2_packet.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#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)
+{
+ static char buf[17];
+
+ os_snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
+ (addr >> 24) & 0xff, (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff, addr & 0xff);
+ return buf;
+}
+
+
+static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ const struct bootp_pkt *b;
+ struct sta_info *sta;
+ int exten_len;
+ const u8 *end, *pos;
+ int res, msgtype = 0, prefixlen = 32;
+ u32 subnet_mask = 0;
+ u16 tot_len;
+
+ exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
+ if (exten_len < 4)
+ return;
+
+ b = (const struct bootp_pkt *) &buf[ETH_HLEN];
+ tot_len = ntohs(b->iph.tot_len);
+ if (tot_len > (unsigned int) (len - ETH_HLEN))
+ return;
+
+ if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
+ return;
+
+ /* Parse DHCP options */
+ end = (const u8 *) b + tot_len;
+ pos = &b->exten[4];
+ while (pos < end && *pos != 0xff) {
+ const u8 *opt = pos++;
+
+ if (*opt == 0) /* padding */
+ continue;
+
+ pos += *pos + 1;
+ if (pos >= end)
+ break;
+
+ switch (*opt) {
+ case 1: /* subnet mask */
+ if (opt[1] == 4)
+ subnet_mask = WPA_GET_BE32(&opt[2]);
+ if (subnet_mask == 0)
+ return;
+ while (!(subnet_mask & 0x1)) {
+ subnet_mask >>= 1;
+ prefixlen--;
+ }
+ break;
+ case 53: /* message type */
+ if (opt[1])
+ msgtype = opt[2];
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (msgtype == DHCPACK) {
+ if (b->your_ip == 0)
+ return;
+
+ /* DHCPACK for DHCPREQUEST */
+ sta = ap_get_sta(hapd, b->hw_addr);
+ if (!sta)
+ return;
+
+ wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
+ " @ IPv4 address %s/%d",
+ MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
+ prefixlen);
+
+ if (sta->ipaddr == b->your_ip)
+ return;
+
+ if (sta->ipaddr != 0) {
+ wpa_printf(MSG_DEBUG,
+ "dhcp_snoop: Removing IPv4 address %s from the ip neigh table",
+ ipaddr_str(be_to_host32(sta->ipaddr)));
+ hostapd_drv_br_delete_ip_neigh(hapd, 4,
+ (u8 *) &sta->ipaddr);
+ }
+
+ res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip,
+ prefixlen, sta->addr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "dhcp_snoop: Adding ip neigh table failed: %d",
+ res);
+ return;
+ }
+ 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);
+ }
+ }
+}
+
+
+int dhcp_snoop_init(struct hostapd_data *hapd)
+{
+ hapd->sock_dhcp = x_snoop_get_l2_packet(hapd, handle_dhcp,
+ L2_PACKET_FILTER_DHCP);
+ if (hapd->sock_dhcp == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "dhcp_snoop: Failed to initialize L2 packet processing for DHCP packet: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void dhcp_snoop_deinit(struct hostapd_data *hapd)
+{
+ l2_packet_deinit(hapd->sock_dhcp);
+}
diff --git a/contrib/wpa/src/ap/dhcp_snoop.h b/contrib/wpa/src/ap/dhcp_snoop.h
new file mode 100644
index 0000000..93d0050
--- /dev/null
+++ b/contrib/wpa/src/ap/dhcp_snoop.h
@@ -0,0 +1,30 @@
+/*
+ * DHCP snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DHCP_SNOOP_H
+#define DHCP_SNOOP_H
+
+#ifdef CONFIG_PROXYARP
+
+int dhcp_snoop_init(struct hostapd_data *hapd);
+void dhcp_snoop_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_PROXYARP */
+
+static inline int dhcp_snoop_init(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+static inline void dhcp_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_PROXYARP */
+
+#endif /* DHCP_SNOOP_H */
diff --git a/contrib/wpa/src/ap/drv_callbacks.c b/contrib/wpa/src/ap/drv_callbacks.c
index 8980bec..a0adc67 100644
--- a/contrib/wpa/src/ap/drv_callbacks.c
+++ b/contrib/wpa/src/ap/drv_callbacks.c
@@ -1,6 +1,6 @@
/*
* hostapd / Callback functions for driver wrappers
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, 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,12 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "radius/radius.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -28,6 +30,8 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "hw_features.h"
+#include "dfs.h"
+#include "beacon.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -44,6 +48,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#endif /* CONFIG_IEEE80211R */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
+ const u8 *p2p_dev_addr = NULL;
if (addr == NULL) {
/*
@@ -75,6 +80,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
ie = elems.wpa_ie - 2;
ielen = elems.wpa_ie_len + 2;
wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
+#ifdef CONFIG_HS20
+ } else if (elems.osen) {
+ ie = elems.osen - 2;
+ ielen = elems.osen_len + 2;
+ wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
+#endif /* CONFIG_HS20 */
} else {
ie = NULL;
ielen = 0;
@@ -84,6 +95,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta = ap_get_sta(hapd, addr);
if (sta) {
+ ap_sta_no_session_timeout(hapd, sta);
accounting_sta_stop(hapd, sta);
/*
@@ -106,9 +118,36 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
wpabuf_free(sta->p2p_ie);
sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
P2P_IE_VENDOR_TYPE);
+ if (sta->p2p_ie)
+ p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capabilities) &&
+ (hapd->iface->conf->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT)
+ ht40_intolerant_add(hapd->iface, sta);
+ }
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_INTERWORKING
+ if (elems.ext_capab && elems.ext_capab_len > 4) {
+ if (elems.ext_capab[4] & 0x01)
+ sta->qos_map_enabled = 1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
if (elems.hs20 && elems.hs20_len > 4) {
@@ -154,7 +193,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
- sta->addr);
+ sta->addr,
+ p2p_dev_addr);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
"machine");
@@ -267,6 +307,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags |= WLAN_STA_MAYBE_WPS;
wpabuf_free(wps);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_HS20
+ } else if (hapd->conf->osen) {
+ if (elems.osen == NULL) {
+ hostapd_logger(
+ hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "No HS 2.0 OSEN element in association request");
+ return WLAN_STATUS_INVALID_IE;
+ }
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to initialize WPA "
+ "state machine");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
+ elems.osen - 2, elems.osen_len + 2) < 0)
+ return WLAN_STATUS_INVALID_IE;
+#endif /* CONFIG_HS20 */
}
#ifdef CONFIG_WPS
skip_wpa_check:
@@ -277,6 +340,9 @@ skip_wpa_check:
sta->auth_alg, req_ies, req_ies_len);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+
+ if (sta->auth_alg == WLAN_AUTH_FT)
+ ap_sta_set_authorized(hapd, sta, 1);
#else /* CONFIG_IEEE80211R */
/* Keep compiler silent about unused variables */
if (status) {
@@ -285,6 +351,9 @@ skip_wpa_check:
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);
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
@@ -367,14 +436,16 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset)
+ int offset, int width, int cf1, int cf2)
{
#ifdef NEED_AP_MLME
- int channel;
+ int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "driver had channel switch: "
- "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+ 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);
hapd->iface->freq = freq;
@@ -386,13 +457,124 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
return;
}
+ switch (width) {
+ case CHAN_WIDTH_80:
+ chwidth = VHT_CHANWIDTH_80MHZ;
+ break;
+ case CHAN_WIDTH_80P80:
+ chwidth = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ case CHAN_WIDTH_160:
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ case CHAN_WIDTH_40:
+ default:
+ chwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ switch (hapd->iface->current_mode->mode) {
+ case HOSTAPD_MODE_IEEE80211A:
+ if (cf1 > 5000)
+ seg0_idx = (cf1 - 5000) / 5;
+ if (cf2 > 5000)
+ seg1_idx = (cf2 - 5000) / 5;
+ break;
+ default:
+ seg0_idx = hostapd_hw_get_channel(hapd, cf1);
+ seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+ break;
+ }
+
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
+ if (!ht)
+ hapd->iconf->ieee80211ac = 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);
+
+ if (hapd->csa_in_progress &&
+ freq == hapd->cs_freq_params.freq) {
+ hostapd_cleanup_cs_params(hapd);
+ ieee802_11_set_beacon(hapd);
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+ "freq=%d dfs=%d", freq, is_dfs);
+ } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+ "freq=%d dfs=%d", freq, is_dfs);
+ }
#endif /* NEED_AP_MLME */
}
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+ const u8 *addr, int reason_code)
+{
+ switch (reason_code) {
+ case MAX_CLIENT_REACHED:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
+ MAC2STR(addr));
+ break;
+ case BLOCKED_CLIENT:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
+ MAC2STR(addr));
+ break;
+ }
+}
+
+
+#ifdef CONFIG_ACS
+static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ u8 pri_channel, u8 sec_channel)
+{
+ int channel;
+ int ret;
+
+ if (hapd->iconf->channel) {
+ wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
+ hapd->iconf->channel);
+ return;
+ }
+
+ hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
+
+ channel = pri_channel;
+ if (!channel) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "driver switched to bad channel");
+ return;
+ }
+
+ hapd->iconf->channel = channel;
+
+ if (sec_channel == 0)
+ hapd->iconf->secondary_channel = 0;
+ else if (sec_channel < pri_channel)
+ hapd->iconf->secondary_channel = -1;
+ else if (sec_channel > pri_channel)
+ hapd->iconf->secondary_channel = 1;
+ else {
+ wpa_printf(MSG_ERROR, "Invalid secondary channel!");
+ return;
+ }
+
+ ret = hostapd_acs_completed(hapd->iface, 0);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Possibly channel configuration is invalid");
+ }
+}
+#endif /* CONFIG_ACS */
+
+
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal)
@@ -452,7 +634,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
if (!sta) {
sta = ap_sta_add(hapd, rx_auth->peer);
if (sta == NULL) {
- status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
}
@@ -463,7 +645,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_FT;
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
- sta->addr);
+ sta->addr, NULL);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
"state machine");
@@ -484,39 +666,48 @@ fail:
static void hostapd_action_rx(struct hostapd_data *hapd,
- struct rx_action *action)
+ struct rx_mgmt *drv_mgmt)
{
+ struct ieee80211_mgmt *mgmt;
struct sta_info *sta;
+ size_t plen __maybe_unused;
+ u16 fc;
+
+ if (drv_mgmt->frame_len < 24 + 1)
+ return;
+
+ plen = drv_mgmt->frame_len - 24 - 1;
+
+ mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
+ return; /* handled by the driver */
wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
- action->category, (int) action->len);
+ mgmt->u.action.category, (int) plen);
- sta = ap_get_sta(hapd, action->sa);
+ sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
return;
}
#ifdef CONFIG_IEEE80211R
- if (action->category == WLAN_ACTION_FT) {
- wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
- __func__, (int) action->len);
- wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
+ if (mgmt->u.action.category == WLAN_ACTION_FT) {
+ const u8 *payload = drv_mgmt->frame + 24 + 1;
+ wpa_ft_action_rx(sta->wpa_sm, payload, plen);
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
- if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
- wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
- __func__, (int) action->len);
- ieee802_11_sa_query_action(hapd, action->sa,
- *(action->data + 1),
- action->data + 2);
+ if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
+ ieee802_11_sa_query_action(
+ hapd, mgmt->sa,
+ mgmt->u.action.u.sa_query_resp.action,
+ mgmt->u.action.u.sa_query_resp.trans_id);
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
- if (action->category == WLAN_ACTION_WNM) {
- wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
- __func__, (int) action->len);
- ieee802_11_rx_wnm_action_ap(hapd, action);
+ if (mgmt->u.action.category == WLAN_ACTION_WNM) {
+ ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
}
#endif /* CONFIG_WNM */
}
@@ -558,17 +749,32 @@ static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
}
-static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
+static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
{
struct hostapd_iface *iface = hapd->iface;
const struct ieee80211_hdr *hdr;
const u8 *bssid;
struct hostapd_frame_info fi;
+ int ret;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_mgmt_frame_handling) {
+ size_t hex_len = 2 * rx_mgmt->frame_len + 1;
+ char *hex = os_malloc(hex_len);
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
+ rx_mgmt->frame_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
+ os_free(hex);
+ }
+ return 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
if (bssid == NULL)
- return;
+ return 0;
hapd = get_hapd_bssid(iface, bssid);
if (hapd == NULL) {
@@ -583,7 +789,7 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
hapd = iface->bss[0];
else
- return;
+ return 0;
}
os_memset(&fi, 0, sizeof(fi));
@@ -592,53 +798,25 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
if (hapd == HAPD_BROADCAST) {
size_t i;
- for (i = 0; i < iface->num_bss; i++)
- ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
- rx_mgmt->frame_len, &fi);
+ ret = 0;
+ for (i = 0; i < iface->num_bss; i++) {
+ /* if bss is set, driver will call this function for
+ * each bss individually. */
+ if (rx_mgmt->drv_priv &&
+ (iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
+ continue;
+
+ if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
+ rx_mgmt->frame_len, &fi) > 0)
+ ret = 1;
+ }
} else
- ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
+ ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
+ &fi);
random_add_randomness(&fi, sizeof(fi));
-}
-
-static void hostapd_rx_action(struct hostapd_data *hapd,
- struct rx_action *rx_action)
-{
- struct rx_mgmt rx_mgmt;
- u8 *buf;
- struct ieee80211_hdr *hdr;
-
- wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
- " BSSID=" MACSTR " category=%u",
- MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
- MAC2STR(rx_action->bssid), rx_action->category);
- wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
- rx_action->data, rx_action->len);
-
- buf = os_zalloc(24 + 1 + rx_action->len);
- if (buf == NULL)
- return;
- hdr = (struct ieee80211_hdr *) buf;
- hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- if (rx_action->category == WLAN_ACTION_SA_QUERY) {
- /*
- * Assume frame was protected; it would have been dropped if
- * not.
- */
- hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
- }
- os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
- os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
- os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
- buf[24] = rx_action->category;
- os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
- os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
- rx_mgmt.frame = buf;
- rx_mgmt.frame_len = 24 + 1 + rx_action->len;
- hostapd_mgmt_rx(hapd, &rx_mgmt);
- os_free(buf);
+ return ret;
}
@@ -697,6 +875,181 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
}
+static struct hostapd_channel_data * hostapd_get_mode_channel(
+ struct hostapd_iface *iface, unsigned int freq)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+ if (!chan)
+ return NULL;
+ if ((unsigned int) chan->freq == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+
+
+static void hostapd_update_nf(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ struct freq_survey *survey)
+{
+ if (!iface->chans_surveyed) {
+ chan->min_nf = survey->nf;
+ iface->lowest_nf = survey->nf;
+ } else {
+ if (dl_list_empty(&chan->survey_list))
+ chan->min_nf = survey->nf;
+ else if (survey->nf < chan->min_nf)
+ chan->min_nf = survey->nf;
+ if (survey->nf < iface->lowest_nf)
+ iface->lowest_nf = survey->nf;
+ }
+}
+
+
+static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_res)
+{
+ struct hostapd_channel_data *chan;
+ struct freq_survey *survey;
+ u64 divisor, dividend;
+
+ survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
+ list);
+ if (!survey || !survey->freq)
+ return;
+
+ chan = hostapd_get_mode_channel(iface, survey->freq);
+ if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
+ survey->freq,
+ (unsigned long int) survey->channel_time,
+ (unsigned long int) survey->channel_time_busy);
+
+ if (survey->channel_time > iface->last_channel_time &&
+ survey->channel_time > survey->channel_time_busy) {
+ dividend = survey->channel_time_busy -
+ iface->last_channel_time_busy;
+ divisor = survey->channel_time - iface->last_channel_time;
+
+ iface->channel_utilization = dividend * 255 / divisor;
+ wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
+ iface->channel_utilization);
+ }
+ iface->last_channel_time = survey->channel_time;
+ iface->last_channel_time_busy = survey->channel_time_busy;
+}
+
+
+static void hostapd_event_get_survey(struct hostapd_data *hapd,
+ struct survey_results *survey_results)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct freq_survey *survey, *tmp;
+ struct hostapd_channel_data *chan;
+
+ if (dl_list_empty(&survey_results->survey_list)) {
+ wpa_printf(MSG_DEBUG, "No survey data received");
+ return;
+ }
+
+ if (survey_results->freq_filter) {
+ hostapd_single_channel_get_survey(iface, survey_results);
+ return;
+ }
+
+ dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
+ struct freq_survey, list) {
+ chan = hostapd_get_mode_channel(iface, survey->freq);
+ if (!chan)
+ continue;
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ dl_list_del(&survey->list);
+ dl_list_add_tail(&chan->survey_list, &survey->list);
+
+ hostapd_update_nf(iface, chan, survey);
+
+ iface->chans_surveyed++;
+ }
+}
+
+
+#ifdef NEED_AP_MLME
+
+static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
+{
+ wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
+ hapd->conf->iface);
+
+ if (hapd->csa_in_progress) {
+ wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
+ hapd->conf->iface);
+ hostapd_switch_channel_fallback(hapd->iface,
+ &hapd->cs_freq_params);
+ }
+}
+
+
+static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
+ hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
+ hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
+ hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
+ hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
+
+static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
+ hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
+#endif /* NEED_AP_MLME */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -713,6 +1066,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
level = MSG_EXCESSIVE;
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
+ level = MSG_EXCESSIVE;
}
wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
@@ -727,12 +1083,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (hapd->iface->scan_cb)
hapd->iface->scan_cb(hapd->iface);
break;
-#ifdef CONFIG_IEEE80211R
- case EVENT_FT_RRB_RX:
- wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
- data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
- break;
-#endif /* CONFIG_IEEE80211R */
case EVENT_WPS_BUTTON_PUSHED:
hostapd_wps_button_pushed(hapd, NULL);
break;
@@ -767,10 +1117,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_from_unknown.addr,
data->rx_from_unknown.wds);
break;
+#endif /* NEED_AP_MLME */
case EVENT_RX_MGMT:
- hostapd_mgmt_rx(hapd, &data->rx_mgmt);
- break;
+ 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_action_rx(hapd, &data->rx_mgmt);
+ break;
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
data->rx_probe_req.ie == NULL)
@@ -791,6 +1147,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->eapol_rx.data_len);
break;
case EVENT_ASSOC:
+ if (!data)
+ return;
hostapd_notif_assoc(hapd, data->assoc_info.addr,
data->assoc_info.req_ies,
data->assoc_info.req_ies_len,
@@ -809,15 +1167,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
- case EVENT_RX_ACTION:
- if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
- data->rx_action.bssid == NULL)
- break;
-#ifdef NEED_AP_MLME
- hostapd_rx_action(hapd, &data->rx_action);
-#endif /* NEED_AP_MLME */
- hostapd_action_rx(hapd, &data->rx_action);
- break;
case EVENT_AUTH:
hostapd_notif_auth(hapd, &data->auth);
break;
@@ -826,8 +1175,84 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_ch_switch(hapd, data->ch_switch.freq,
data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset);
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
+ break;
+ case EVENT_CONNECT_FAILED_REASON:
+ if (!data)
+ break;
+ hostapd_event_connect_failed_reason(
+ hapd, data->connect_failed_reason.addr,
+ data->connect_failed_reason.code);
+ break;
+ case EVENT_SURVEY:
+ hostapd_event_get_survey(hapd, &data->survey_results);
+ break;
+#ifdef NEED_AP_MLME
+ case EVENT_INTERFACE_UNAVAILABLE:
+ hostapd_event_iface_unavailable(hapd);
+ break;
+ case EVENT_DFS_RADAR_DETECTED:
+ if (!data)
+ break;
+ hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
+ break;
+ case EVENT_DFS_CAC_FINISHED:
+ if (!data)
+ break;
+ hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
+ break;
+ case EVENT_DFS_CAC_ABORTED:
+ if (!data)
+ break;
+ hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
+ break;
+ case EVENT_DFS_NOP_FINISHED:
+ if (!data)
+ break;
+ hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
+ break;
+ case EVENT_CHANNEL_LIST_CHANGED:
+ /* channel list changed (regulatory?), update channel list */
+ /* TODO: check this. hostapd_get_hw_features() initializes
+ * too much stuff. */
+ /* hostapd_get_hw_features(hapd->iface); */
+ hostapd_channel_list_updated(
+ hapd->iface, data->channel_list_changed.initiator);
+ break;
+ case EVENT_DFS_CAC_STARTED:
+ if (!data)
+ break;
+ hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
+ break;
+#endif /* NEED_AP_MLME */
+ case EVENT_INTERFACE_ENABLED:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
+ if (hapd->disabled && hapd->started) {
+ hapd->disabled = 0;
+ /*
+ * Try to re-enable interface if the driver stopped it
+ * when the interface got disabled.
+ */
+ wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+ hapd->reenable_beacon = 1;
+ ieee802_11_set_beacon(hapd);
+ }
+ break;
+ case EVENT_INTERFACE_DISABLED:
+ hostapd_free_stas(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
+ hapd->disabled = 1;
+ break;
+#ifdef CONFIG_ACS
+ case EVENT_ACS_CHANNEL_SELECTED:
+ hostapd_acs_channel_selected(
+ hapd, data->acs_selected_channels.pri_channel,
+ data->acs_selected_channels.sec_channel);
break;
+#endif /* CONFIG_ACS */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/contrib/wpa/src/ap/eap_user_db.c b/contrib/wpa/src/ap/eap_user_db.c
index 79d50e5..559d77f 100644
--- a/contrib/wpa/src/ap/eap_user_db.c
+++ b/contrib/wpa/src/ap/eap_user_db.c
@@ -83,12 +83,14 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
for (i = 0; i < argc; i++) {
if (os_strcmp(col[i], "password") == 0 && argv[i]) {
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
user->password_len = os_strlen(argv[i]);
user->password = (u8 *) os_strdup(argv[i]);
user->next = (void *) 1;
} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
set_user_methods(user, argv[i]);
+ } else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
+ user->remediation = strlen(argv[i]) > 0;
}
}
@@ -116,7 +118,7 @@ static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
if (len <= user->identity_len &&
os_memcmp(argv[id], user->identity, len) == 0 &&
(user->password == NULL || len > user->password_len)) {
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
user->password_len = os_strlen(argv[id]);
user->password = (u8 *) os_strdup(argv[id]);
user->next = (void *) 1;
@@ -156,8 +158,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
return NULL;
}
- os_free(hapd->tmp_eap_user.identity);
- os_free(hapd->tmp_eap_user.password);
+ bin_clear_free(hapd->tmp_eap_user.identity,
+ hapd->tmp_eap_user.identity_len);
+ bin_clear_free(hapd->tmp_eap_user.password,
+ hapd->tmp_eap_user.password_len);
os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
hapd->tmp_eap_user.phase2 = phase2;
hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
@@ -173,8 +177,8 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
}
os_snprintf(cmd, sizeof(cmd),
- "SELECT password,methods FROM users WHERE "
- "identity='%s' AND phase2=%d;", id_str, phase2);
+ "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
+ id_str, phase2);
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
diff --git a/contrib/wpa/src/ap/gas_serv.c b/contrib/wpa/src/ap/gas_serv.c
index 851c183..9d19f98 100644
--- a/contrib/wpa/src/ap/gas_serv.c
+++ b/contrib/wpa/src/ap/gas_serv.c
@@ -1,6 +1,6 @@
/*
* Generic advertisement service (GAS) server
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,13 @@
#include "gas_serv.h"
+static void convert_to_protected_dual(struct wpabuf *msg)
+{
+ u8 *categ = wpabuf_mhead_u8(msg);
+ *categ = WLAN_ACTION_PROTECTED_DUAL;
+}
+
+
static struct gas_dialog_info *
gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
{
@@ -46,10 +53,12 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
* it to be that long.
*/
ap_sta_session_timeout(hapd, sta, 5);
+ } else {
+ ap_sta_replenish_timeout(hapd, sta, 5);
}
if (sta->gas_dialog == NULL) {
- sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+ sta->gas_dialog = os_calloc(GAS_DIALOG_MAX,
sizeof(struct gas_dialog_info));
if (sta->gas_dialog == NULL)
return NULL;
@@ -62,7 +71,6 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
continue;
dia = &sta->gas_dialog[i];
dia->valid = 1;
- dia->index = i;
dia->dialog_token = dialog_token;
sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
return dia;
@@ -150,6 +158,10 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
if (hapd->conf->hs20_operating_class)
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_icons_count)
+ wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
gas_anqp_set_element_len(buf, len);
}
#endif /* CONFIG_HS20 */
@@ -402,7 +414,7 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
gas_anqp_set_element_len(buf, realm_data_len);
}
gas_anqp_set_element_len(buf, len);
- } else if (nai_home_realm && hapd->conf->nai_realm_data) {
+ } else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
home_realm_len);
}
@@ -505,18 +517,188 @@ static void anqp_add_operating_class(struct hostapd_data *hapd,
}
}
+
+static void anqp_add_osu_provider(struct wpabuf *buf,
+ struct hostapd_bss_config *bss,
+ struct hs20_osu_provider *p)
+{
+ u8 *len, *len2, *count;
+ unsigned int i;
+
+ len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
+
+ /* OSU Friendly Name Duples */
+ len2 = wpabuf_put(buf, 2);
+ for (i = 0; i < p->friendly_name_count; i++) {
+ struct hostapd_lang_string *s = &p->friendly_name[i];
+ wpabuf_put_u8(buf, 3 + s->name_len);
+ wpabuf_put_data(buf, s->lang, 3);
+ wpabuf_put_data(buf, s->name, s->name_len);
+ }
+ WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
+
+ /* OSU Server URI */
+ if (p->server_uri) {
+ wpabuf_put_u8(buf, os_strlen(p->server_uri));
+ wpabuf_put_str(buf, p->server_uri);
+ } else
+ wpabuf_put_u8(buf, 0);
+
+ /* OSU Method List */
+ count = wpabuf_put(buf, 1);
+ for (i = 0; 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);
+ }
+ WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
+
+ /* OSU_NAI */
+ if (p->osu_nai) {
+ wpabuf_put_u8(buf, os_strlen(p->osu_nai));
+ wpabuf_put_str(buf, p->osu_nai);
+ } else
+ wpabuf_put_u8(buf, 0);
+
+ /* OSU Service Description Duples */
+ len2 = wpabuf_put(buf, 2);
+ for (i = 0; i < p->service_desc_count; i++) {
+ struct hostapd_lang_string *s = &p->service_desc[i];
+ wpabuf_put_u8(buf, 3 + s->name_len);
+ wpabuf_put_data(buf, s->lang, 3);
+ wpabuf_put_data(buf, s->name, s->name_len);
+ }
+ WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
+
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_osu_providers_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_LIST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+
+ /* OSU SSID */
+ wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
+ wpabuf_put_data(buf, hapd->conf->osu_ssid,
+ hapd->conf->osu_ssid_len);
+
+ /* Number of OSU Providers */
+ wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
+
+ for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
+ anqp_add_osu_provider(
+ buf, hapd->conf,
+ &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)
+{
+ struct hs20_icon *icon;
+ size_t i;
+ u8 *len;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename",
+ name, name_len);
+ for (i = 0; i < hapd->conf->hs20_icons_count; i++) {
+ icon = &hapd->conf->hs20_icons[i];
+ if (name_len == os_strlen(icon->name) &&
+ os_memcmp(name, icon->name, name_len) == 0)
+ break;
+ }
+
+ if (i < hapd->conf->hs20_icons_count)
+ icon = &hapd->conf->hs20_icons[i];
+ else
+ icon = NULL;
+
+ 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_ICON_BINARY_FILE);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+
+ if (icon) {
+ char *data;
+ size_t data_len;
+
+ data = os_readfile(icon->file, &data_len);
+ if (data == NULL || data_len > 65535) {
+ wpabuf_put_u8(buf, 2); /* Download Status:
+ * Unspecified file error */
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 0);
+ } else {
+ wpabuf_put_u8(buf, 0); /* Download Status: Success */
+ wpabuf_put_u8(buf, os_strlen(icon->type));
+ wpabuf_put_str(buf, icon->type);
+ wpabuf_put_le16(buf, data_len);
+ wpabuf_put_data(buf, data, data_len);
+ }
+ os_free(data);
+ } else {
+ wpabuf_put_u8(buf, 1); /* Download Status: File not found */
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 0);
+ }
+
+ gas_anqp_set_element_len(buf, len);
+}
+
#endif /* CONFIG_HS20 */
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
- struct gas_dialog_info *di,
- const u8 *home_realm, size_t home_realm_len)
+ const u8 *home_realm, size_t home_realm_len,
+ const u8 *icon_name, size_t icon_name_len)
{
struct wpabuf *buf;
+ size_t len;
+
+ len = 1400;
+ if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
+ len += 1000;
+ if (request & ANQP_REQ_ICON_REQUEST)
+ len += 65536;
- buf = wpabuf_alloc(1400);
+ buf = wpabuf_alloc(len);
if (buf == NULL)
return NULL;
@@ -550,44 +732,32 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
anqp_add_connection_capability(hapd, buf);
if (request & ANQP_REQ_OPERATING_CLASS)
anqp_add_operating_class(hapd, buf);
+ if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
+ 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);
#endif /* CONFIG_HS20 */
return buf;
}
-static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
-{
- struct gas_dialog_info *dia = eloop_data;
-
- wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
- "dialog token %d", dia->dialog_token);
-
- gas_serv_dialog_clear(dia);
-}
-
-
struct anqp_query_info {
unsigned int request;
- unsigned int remote_request;
const u8 *home_realm_query;
size_t home_realm_query_len;
- u16 remote_delay;
+ const u8 *icon_name;
+ size_t icon_name_len;
+ int p2p_sd;
};
static void set_anqp_req(unsigned int bit, const char *name, int local,
- unsigned int remote, u16 remote_delay,
struct anqp_query_info *qi)
{
qi->request |= bit;
if (local) {
wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
- } else if (bit & remote) {
- wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
- qi->remote_request |= bit;
- if (remote_delay > qi->remote_delay)
- qi->remote_delay = remote_delay;
} else {
wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
}
@@ -599,43 +769,38 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
{
switch (info_id) {
case ANQP_CAPABILITY_LIST:
- set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
- 0, qi);
+ set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1,
+ qi);
break;
case ANQP_VENUE_NAME:
set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
- hapd->conf->venue_name != NULL, 0, 0, qi);
+ hapd->conf->venue_name != 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,
- 0, 0, qi);
+ hapd->conf->network_auth_type != NULL, qi);
break;
case ANQP_ROAMING_CONSORTIUM:
set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
- hapd->conf->roaming_consortium != NULL, 0, 0, qi);
+ hapd->conf->roaming_consortium != NULL, qi);
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
"IP Addr Type Availability",
- hapd->conf->ipaddr_type_configured,
- 0, 0, qi);
+ hapd->conf->ipaddr_type_configured, qi);
break;
case ANQP_NAI_REALM:
set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
- hapd->conf->nai_realm_data != NULL,
- 0, 0, qi);
+ hapd->conf->nai_realm_data != NULL, qi);
break;
case ANQP_3GPP_CELLULAR_NETWORK:
set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
"3GPP Cellular Network",
- hapd->conf->anqp_3gpp_cell_net != NULL,
- 0, 0, qi);
+ hapd->conf->anqp_3gpp_cell_net != NULL, qi);
break;
case ANQP_DOMAIN_NAME:
set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
- hapd->conf->domain_name != NULL,
- 0, 0, qi);
+ hapd->conf->domain_name != NULL, qi);
break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
@@ -667,29 +832,30 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
switch (subtype) {
case HS20_STYPE_CAPABILITY_LIST:
set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
- 1, 0, 0, qi);
+ 1, qi);
break;
case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
"Operator Friendly Name",
- hapd->conf->hs20_oper_friendly_name != NULL,
- 0, 0, qi);
+ hapd->conf->hs20_oper_friendly_name != NULL, qi);
break;
case HS20_STYPE_WAN_METRICS:
set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
- hapd->conf->hs20_wan_metrics != NULL,
- 0, 0, qi);
+ hapd->conf->hs20_wan_metrics != NULL, qi);
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
"Connection Capability",
hapd->conf->hs20_connection_capability != NULL,
- 0, 0, qi);
+ qi);
break;
case HS20_STYPE_OPERATING_CLASS:
set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
- hapd->conf->hs20_operating_class != NULL,
- 0, 0, qi);
+ hapd->conf->hs20_operating_class != NULL, qi);
+ break;
+ case HS20_STYPE_OSU_PROVIDERS_LIST:
+ set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
+ hapd->conf->hs20_osu_providers_count, qi);
break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
@@ -716,6 +882,23 @@ static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
}
+static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ qi->request |= ANQP_REQ_ICON_REQUEST;
+ qi->icon_name = pos;
+ qi->icon_name_len = end - pos;
+ if (hapd->conf->hs20_icons_count) {
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query "
+ "(local)");
+ } else {
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not "
+ "available");
+ }
+}
+
+
static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
const u8 *pos, const u8 *end,
struct anqp_query_info *qi)
@@ -737,6 +920,21 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
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);
@@ -760,6 +958,9 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
case HS20_STYPE_NAI_HOME_REALM_QUERY:
rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
break;
+ case HS20_STYPE_ICON_REQUEST:
+ rx_anqp_hs_icon_request(hapd, pos, end, qi);
+ break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
"%u", subtype);
@@ -772,17 +973,26 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
- struct anqp_query_info *qi)
+ struct anqp_query_info *qi, int prot)
{
struct wpabuf *buf, *tx_buf;
- buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
+ buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
qi->home_realm_query,
- qi->home_realm_query_len);
+ qi->home_realm_query_len,
+ qi->icon_name, qi->icon_name_len);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf);
if (!buf)
return;
+#ifdef CONFIG_P2P
+ if (wpabuf_len(buf) == 0 && qi->p2p_sd) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Do not send response to P2P SD from generic GAS service (P2P SD implementation will process this)");
+ wpabuf_free(buf);
+ return;
+ }
+#endif /* CONFIG_P2P */
if (wpabuf_len(buf) > hapd->gas_frag_limit ||
hapd->conf->gas_comeback_delay) {
@@ -802,13 +1012,17 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
"for " MACSTR " (dialog token %u)",
MAC2STR(sa), dialog_token);
wpabuf_free(buf);
- return;
+ tx_buf = gas_anqp_build_initial_resp_buf(
+ dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
+ 0, NULL);
+ } else {
+ di->prot = prot;
+ di->sd_resp = buf;
+ di->sd_resp_pos = 0;
+ tx_buf = gas_anqp_build_initial_resp_buf(
+ dialog_token, WLAN_STATUS_SUCCESS,
+ comeback_delay, NULL);
}
- di->sd_resp = buf;
- di->sd_resp_pos = 0;
- tx_buf = gas_anqp_build_initial_resp_buf(
- dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
- NULL);
} else {
wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
tx_buf = gas_anqp_build_initial_resp_buf(
@@ -817,7 +1031,8 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
}
if (!tx_buf)
return;
-
+ if (prot)
+ convert_to_protected_dual(tx_buf);
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
wpabuf_head(tx_buf), wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
@@ -826,7 +1041,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len)
+ const u8 *data, size_t len, int prot)
{
const u8 *pos = data;
const u8 *end = data + len;
@@ -876,6 +1091,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
return;
wpabuf_put_data(buf, adv_proto, 2 + slen);
wpabuf_put_le16(buf, 0); /* Query Response Length */
+ if (prot)
+ convert_to_protected_dual(buf);
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
@@ -927,100 +1144,13 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
pos += elen;
}
- gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
-}
-
-
-void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
- struct gas_dialog_info *dialog)
-{
- struct wpabuf *buf, *tx_buf;
- u8 dialog_token = dialog->dialog_token;
- size_t frag_len;
-
- if (dialog->sd_resp == NULL) {
- buf = gas_serv_build_gas_resp_payload(hapd,
- dialog->all_requested,
- dialog, NULL, 0);
- wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
- buf);
- if (!buf)
- goto tx_gas_response_done;
- dialog->sd_resp = buf;
- dialog->sd_resp_pos = 0;
- }
- frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
- if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
- hapd->conf->gas_comeback_delay) {
- u16 comeback_delay_tus = dialog->comeback_delay +
- GAS_SERV_COMEBACK_DELAY_FUDGE;
- u32 comeback_delay_secs, comeback_delay_usecs;
-
- if (hapd->conf->gas_comeback_delay) {
- /* Testing - allow overriding of the delay value */
- comeback_delay_tus = hapd->conf->gas_comeback_delay;
- }
-
- wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
- "%u) and comeback delay %u, "
- "requesting comebacks", (unsigned int) frag_len,
- (unsigned int) hapd->gas_frag_limit,
- dialog->comeback_delay);
- tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
- WLAN_STATUS_SUCCESS,
- comeback_delay_tus,
- NULL);
- if (tx_buf) {
- wpa_msg(hapd->msg_ctx, MSG_DEBUG,
- "GAS: Tx GAS Initial Resp (comeback = 10TU)");
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
- dst,
- wpabuf_head(tx_buf),
- wpabuf_len(tx_buf));
- }
- wpabuf_free(tx_buf);
-
- /* start a timer of 1.5 * comeback-delay */
- comeback_delay_tus = comeback_delay_tus +
- (comeback_delay_tus / 2);
- comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
- comeback_delay_usecs = (comeback_delay_tus * 1024) -
- (comeback_delay_secs * 1000000);
- eloop_register_timeout(comeback_delay_secs,
- comeback_delay_usecs,
- gas_serv_clear_cached_ies, dialog,
- NULL);
- goto tx_gas_response_done;
- }
-
- buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
- dialog->sd_resp_pos, frag_len);
- if (buf == NULL) {
- wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
- "failed");
- goto tx_gas_response_done;
- }
- tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
- WLAN_STATUS_SUCCESS, 0, buf);
- wpabuf_free(buf);
- if (tx_buf == NULL)
- goto tx_gas_response_done;
- wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
- "Response (frag_id %d frag_len %d)",
- dialog->sd_frag_id, (int) frag_len);
- dialog->sd_frag_id++;
-
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
- wpabuf_head(tx_buf), wpabuf_len(tx_buf));
- wpabuf_free(tx_buf);
-tx_gas_response_done:
- gas_serv_clear_cached_ies(dialog, NULL);
+ gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
}
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len)
+ const u8 *data, size_t len, int prot)
{
struct gas_dialog_info *dialog;
struct wpabuf *buf, *tx_buf;
@@ -1051,33 +1181,6 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
goto send_resp;
}
- if (dialog->sd_resp == NULL) {
- wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
- dialog->requested, dialog->received);
- if ((dialog->requested & dialog->received) !=
- dialog->requested) {
- wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
- "from remote processing");
- gas_serv_dialog_clear(dialog);
- tx_buf = gas_anqp_build_comeback_resp_buf(
- dialog_token,
- WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
- NULL);
- if (tx_buf == NULL)
- return;
- goto send_resp;
- }
-
- buf = gas_serv_build_gas_resp_payload(hapd,
- dialog->all_requested,
- dialog, NULL, 0);
- wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
- buf);
- if (!buf)
- goto rx_gas_comeback_req_done;
- dialog->sd_resp = buf;
- dialog->sd_resp_pos = 0;
- }
frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
if (frag_len > hapd->gas_frag_limit) {
frag_len = hapd->gas_frag_limit;
@@ -1090,15 +1193,18 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
if (buf == NULL) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
"buffer");
- goto rx_gas_comeback_req_done;
+ gas_serv_dialog_clear(dialog);
+ return;
}
tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
WLAN_STATUS_SUCCESS,
dialog->sd_frag_id,
more, 0, buf);
wpabuf_free(buf);
- if (tx_buf == NULL)
- goto rx_gas_comeback_req_done;
+ if (tx_buf == NULL) {
+ gas_serv_dialog_clear(dialog);
+ return;
+ }
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
"(frag_id %d more=%d frag_len=%d)",
dialog->sd_frag_id, more, (int) frag_len);
@@ -1118,13 +1224,11 @@ 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));
wpabuf_free(tx_buf);
- return;
-
-rx_gas_comeback_req_done:
- gas_serv_clear_cached_ies(dialog, NULL);
}
@@ -1133,24 +1237,30 @@ 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;
- size_t hdr_len;
const u8 *sa, *data;
+ int prot;
mgmt = (const struct ieee80211_mgmt *) buf;
- hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
- if (hdr_len > len)
+ if (len < IEEE80211_HDRLEN + 2)
return;
- if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+ if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
+ mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
return;
+ /*
+ * Note: Public Action and Protected Dual of Public Action frames share
+ * the same payload structure, so it is fine to use definitions of
+ * Public Action frames to process both.
+ */
+ prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
sa = mgmt->sa;
- len -= hdr_len;
- data = &mgmt->u.action.u.public_action.action;
+ 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);
+ gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
break;
case WLAN_PA_GAS_COMEBACK_REQ:
- gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+ gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
break;
}
}
@@ -1158,8 +1268,8 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
int gas_serv_init(struct hostapd_data *hapd)
{
- hapd->public_action_cb = gas_serv_rx_public_action;
- hapd->public_action_cb_ctx = 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;
diff --git a/contrib/wpa/src/ap/gas_serv.h b/contrib/wpa/src/ap/gas_serv.h
index 4213cf6..4ec3201 100644
--- a/contrib/wpa/src/ap/gas_serv.h
+++ b/contrib/wpa/src/ap/gas_serv.h
@@ -1,6 +1,6 @@
/*
* Generic advertisement service (GAS) server
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -37,29 +37,22 @@
(0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
#define ANQP_REQ_OPERATING_CLASS \
(0x10000 << HS20_STYPE_OPERATING_CLASS)
-
-/* To account for latencies between hostapd and external ANQP processor */
-#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
-#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
+#define ANQP_REQ_OSU_PROVIDERS_LIST \
+ (0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
+#define ANQP_REQ_ICON_REQUEST \
+ (0x10000 << HS20_STYPE_ICON_REQUEST)
struct gas_dialog_info {
u8 valid;
- u8 index;
struct wpabuf *sd_resp; /* Fragmented response */
u8 dialog_token;
size_t sd_resp_pos; /* Offset in sd_resp */
u8 sd_frag_id;
- u16 comeback_delay;
-
- unsigned int requested;
- unsigned int received;
- unsigned int all_requested;
+ int prot; /* whether Protected Dual of Public Action frame is used */
};
struct hostapd_data;
-void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
- struct gas_dialog_info *dialog);
struct gas_dialog_info *
gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
u8 dialog_token);
diff --git a/contrib/wpa/src/ap/hostapd.c b/contrib/wpa/src/ap/hostapd.c
index cef9daf..3e4e16b 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,9 +11,12 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "radius/radius_client.h"
#include "radius/radius_das.h"
-#include "drivers/driver.h"
+#include "eap_server/tncs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
#include "hostapd.h"
#include "authsrv.h"
#include "sta_info.h"
@@ -32,14 +35,19 @@
#include "ap_config.h"
#include "p2p_hostapd.h"
#include "gas_serv.h"
+#include "dfs.h"
+#include "ieee802_11.h"
+#include "bss_load.h"
+#include "x_snoop.h"
+#include "dhcp_snoop.h"
+#include "ndisc_snoop.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
-
-extern int wpa_debug_level;
-extern struct wpa_driver_ops *wpa_drivers[];
+static int setup_interface2(struct hostapd_iface *iface);
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -61,10 +69,21 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
+ struct hostapd_ssid *ssid;
+
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
#endif /* CONFIG_NO_RADIUS */
+ ssid = &hapd->conf->ssid;
+ if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
+ ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
+ /*
+ * Force PSK to be derived again since SSID or passphrase may
+ * have changed.
+ */
+ hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk);
+ }
if (hostapd_setup_wpa_psk(hapd->conf)) {
wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
"after reloading configuration");
@@ -75,7 +94,7 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
else
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
- if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
+ if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) {
hostapd_setup_wpa(hapd);
if (hapd->wpa_auth)
wpa_init_keys(hapd->wpa_auth);
@@ -108,19 +127,10 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
}
-int hostapd_reload_config(struct hostapd_iface *iface)
+static void hostapd_clear_old(struct hostapd_iface *iface)
{
- struct hostapd_data *hapd = iface->bss[0];
- struct hostapd_config *newconf, *oldconf;
size_t j;
- if (iface->interfaces == NULL ||
- iface->interfaces->config_read_cb == NULL)
- return -1;
- newconf = iface->interfaces->config_read_cb(iface->config_fname);
- if (newconf == NULL)
- return -1;
-
/*
* Deauthenticate all stations since the new configuration may not
* allow them to use the BSS anymore.
@@ -136,6 +146,31 @@ int hostapd_reload_config(struct hostapd_iface *iface)
radius_client_flush(iface->bss[j]->radius, 0);
#endif /* CONFIG_NO_RADIUS */
}
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct hostapd_config *newconf, *oldconf;
+ size_t j;
+
+ if (iface->config_fname == NULL) {
+ /* Only in-memory config in use - assume it has been updated */
+ hostapd_clear_old(iface);
+ for (j = 0; j < iface->num_bss; j++)
+ hostapd_reload_bss(iface->bss[j]);
+ return 0;
+ }
+
+ if (iface->interfaces == NULL ||
+ iface->interfaces->config_read_cb == NULL)
+ return -1;
+ newconf = iface->interfaces->config_read_cb(iface->config_fname);
+ if (newconf == NULL)
+ return -1;
+
+ hostapd_clear_old(iface);
oldconf = hapd->iconf;
iface->conf = newconf;
@@ -143,7 +178,18 @@ int hostapd_reload_config(struct hostapd_iface *iface)
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
hapd->iconf = newconf;
- hapd->conf = &newconf->bss[j];
+ hapd->iconf->channel = oldconf->channel;
+ hapd->iconf->secondary_channel = oldconf->secondary_channel;
+ hapd->iconf->ieee80211n = oldconf->ieee80211n;
+ hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
+ hapd->iconf->ht_capab = oldconf->ht_capab;
+ hapd->iconf->vht_capab = oldconf->vht_capab;
+ hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth;
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ oldconf->vht_oper_centr_freq_seg0_idx;
+ hapd->iconf->vht_oper_centr_freq_seg1_idx =
+ oldconf->vht_oper_centr_freq_seg1_idx;
+ hapd->conf = newconf->bss[j];
hostapd_reload_bss(hapd);
}
@@ -205,36 +251,30 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
errors++;
}
- if (ssid->dyn_vlan_keys) {
- size_t i;
- for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
- const char *ifname;
- struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
- if (key == NULL)
- continue;
- ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
- i);
- if (ifname == NULL)
- continue;
-
- idx = key->idx;
- if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
- broadcast_ether_addr, idx, 1,
- NULL, 0, key->key[idx],
- key->len[idx])) {
- wpa_printf(MSG_WARNING, "Could not set "
- "dynamic VLAN WEP encryption.");
- errors++;
- }
- }
- }
-
return errors;
}
static void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
+ os_free(hapd->probereq_cb);
+ hapd->probereq_cb = NULL;
+
+#ifdef CONFIG_P2P
+ wpabuf_free(hapd->p2p_beacon_ie);
+ hapd->p2p_beacon_ie = NULL;
+ wpabuf_free(hapd->p2p_probe_resp_ie);
+ hapd->p2p_probe_resp_ie = NULL;
+#endif /* CONFIG_P2P */
+
+ if (!hapd->started) {
+ wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
+ __func__, hapd->conf->iface);
+ return;
+ }
+ hapd->started = 0;
+
+ wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
iapp_deinit(hapd->iapp);
hapd->iapp = NULL;
accounting_deinit(hapd);
@@ -252,32 +292,45 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
authsrv_deinit(hapd);
- if (hapd->interface_added &&
- hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
- wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
- hapd->conf->iface);
+ if (hapd->interface_added) {
+ hapd->interface_added = 0;
+ if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
+ wpa_printf(MSG_WARNING,
+ "Failed to remove BSS interface %s",
+ hapd->conf->iface);
+ hapd->interface_added = 1;
+ } else {
+ /*
+ * Since this was a dynamically added interface, the
+ * driver wrapper may have removed its internal instance
+ * and hapd->drv_priv is not valid anymore.
+ */
+ hapd->drv_priv = NULL;
+ }
}
- os_free(hapd->probereq_cb);
- hapd->probereq_cb = NULL;
-
-#ifdef CONFIG_P2P
- wpabuf_free(hapd->p2p_beacon_ie);
- hapd->p2p_beacon_ie = NULL;
- wpabuf_free(hapd->p2p_probe_resp_ie);
- hapd->p2p_probe_resp_ie = NULL;
-#endif /* CONFIG_P2P */
-
wpabuf_free(hapd->time_adv);
#ifdef CONFIG_INTERWORKING
gas_serv_deinit(hapd);
#endif /* CONFIG_INTERWORKING */
+ bss_load_update_deinit(hapd);
+ ndisc_snoop_deinit(hapd);
+ dhcp_snoop_deinit(hapd);
+ x_snoop_deinit(hapd);
+
#ifdef CONFIG_SQLITE
- os_free(hapd->tmp_eap_user.identity);
- os_free(hapd->tmp_eap_user.password);
+ bin_clear_free(hapd->tmp_eap_user.identity,
+ hapd->tmp_eap_user.identity_len);
+ bin_clear_free(hapd->tmp_eap_user.password,
+ hapd->tmp_eap_user.password_len);
#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_MESH
+ wpabuf_free(hapd->mesh_pending_auth);
+ hapd->mesh_pending_auth = NULL;
+#endif /* CONFIG_MESH */
}
@@ -286,13 +339,13 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
* @hapd: Pointer to BSS data
*
* This function is used to free all per-BSS data structures and resources.
- * This gets called in a loop for each BSS between calls to
- * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
- * is deinitialized. Most of the modules that are initialized in
- * hostapd_setup_bss() are deinitialized here.
+ * Most of the modules that are initialized in hostapd_setup_bss() are
+ * deinitialized here.
*/
static void hostapd_cleanup(struct hostapd_data *hapd)
{
+ wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
+ hapd->conf->iface);
if (hapd->iface->interfaces &&
hapd->iface->interfaces->ctrl_iface_deinit)
hapd->iface->interfaces->ctrl_iface_deinit(hapd);
@@ -300,20 +353,14 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
}
-/**
- * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
- * @iface: Pointer to interface data
- *
- * This function is called before per-BSS data structures are deinitialized
- * with hostapd_cleanup().
- */
-static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
-{
-}
-
-
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ hostapd_stop_setup_timers(iface);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = NULL;
os_free(iface->current_rates);
@@ -333,19 +380,23 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
*/
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+
hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
os_free(iface->config_fname);
os_free(iface->bss);
+ wpa_printf(MSG_DEBUG, "%s: free iface=%p", __func__, iface);
os_free(iface);
}
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
- if (hapd->drv_priv) {
+ if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
}
@@ -396,11 +447,15 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
return 0;
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
- if (hostapd_flush(hapd)) {
- wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
- "kernel driver");
- ret = -1;
+ if (!hapd->iface->driver_ap_teardown) {
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "Flushing old station entries");
+
+ if (hostapd_flush(hapd)) {
+ wpa_msg(hapd->msg_ctx, MSG_WARNING,
+ "Could not connect to kernel driver");
+ ret = -1;
+ }
}
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
os_memset(addr, 0xff, ETH_ALEN);
@@ -411,6 +466,14 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
}
+static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
+{
+ hostapd_free_stas(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+ hostapd_clear_wep(hapd);
+}
+
+
/**
* hostapd_validate_bssid_configuration - Validate BSSID configuration
* @iface: Pointer to interface data
@@ -437,7 +500,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 (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
if (j)
auto_addr++;
continue;
@@ -445,7 +508,7 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
for (i = 0; i < ETH_ALEN; i++) {
mask[i] |=
- iface->conf->bss[j].bssid[i] ^
+ iface->conf->bss[j]->bssid[i] ^
hapd->own_addr[i];
}
}
@@ -510,7 +573,7 @@ static int mac_in_conf(struct hostapd_config *conf, const void *a)
size_t i;
for (i = 0; i < conf->num_bss; i++) {
- if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+ if (hostapd_mac_comp(conf->bss[i]->bssid, a) == 0) {
return 1;
}
}
@@ -524,57 +587,223 @@ static int mac_in_conf(struct hostapd_config *conf, const void *a)
static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
struct radius_das_attrs *attr)
{
- /* TODO */
+ if (attr->nas_identifier &&
+ (!hapd->conf->nas_identifier ||
+ os_strlen(hapd->conf->nas_identifier) !=
+ attr->nas_identifier_len ||
+ os_memcmp(hapd->conf->nas_identifier, attr->nas_identifier,
+ attr->nas_identifier_len) != 0)) {
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-Identifier mismatch");
+ return 1;
+ }
+
+ if (attr->nas_ip_addr &&
+ (hapd->conf->own_ip_addr.af != AF_INET ||
+ os_memcmp(&hapd->conf->own_ip_addr.u.v4, attr->nas_ip_addr, 4) !=
+ 0)) {
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IP-Address mismatch");
+ return 1;
+ }
+
+#ifdef CONFIG_IPV6
+ if (attr->nas_ipv6_addr &&
+ (hapd->conf->own_ip_addr.af != AF_INET6 ||
+ os_memcmp(&hapd->conf->own_ip_addr.u.v6, attr->nas_ipv6_addr, 16)
+ != 0)) {
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: NAS-IPv6-Address mismatch");
+ return 1;
+ }
+#endif /* CONFIG_IPV6 */
+
return 0;
}
static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
- struct radius_das_attrs *attr)
+ struct radius_das_attrs *attr,
+ int *multi)
{
- struct sta_info *sta = NULL;
+ struct sta_info *selected, *sta;
char buf[128];
+ int num_attr = 0;
+ int count;
- if (attr->sta_addr)
+ *multi = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next)
+ sta->radius_das_match = 1;
+
+ if (attr->sta_addr) {
+ num_attr++;
sta = ap_get_sta(hapd, attr->sta_addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No Calling-Station-Id match");
+ return NULL;
+ }
- if (sta == NULL && attr->acct_session_id &&
- attr->acct_session_id_len == 17) {
+ selected = sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta != selected)
+ sta->radius_das_match = 0;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
+ }
+
+ if (attr->acct_session_id) {
+ num_attr++;
+ if (attr->acct_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
+
+ 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)
- break;
+ if (os_memcmp(attr->acct_session_id, buf, 17) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Session-Id check");
+ return NULL;
}
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
}
- if (sta == NULL && attr->cui) {
+ if (attr->acct_multi_session_id) {
+ num_attr++;
+ if (attr->acct_multi_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->radius_das_match)
+ continue;
+ if (!sta->eapol_sm ||
+ !sta->eapol_sm->acct_multi_session_id_hi) {
+ 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) !=
+ 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id match");
+ }
+
+ if (attr->cui) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
struct wpabuf *cui;
+
+ if (!sta->radius_das_match)
+ continue;
cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
- if (cui && wpabuf_len(cui) == attr->cui_len &&
+ if (!cui || wpabuf_len(cui) != attr->cui_len ||
os_memcmp(wpabuf_head(cui), attr->cui,
- attr->cui_len) == 0)
- break;
+ attr->cui_len) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
+ return NULL;
}
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Chargeable-User-Identity match");
}
- if (sta == NULL && attr->user_name) {
+ if (attr->user_name) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
u8 *identity;
size_t identity_len;
+
+ if (!sta->radius_das_match)
+ continue;
identity = ieee802_1x_get_identity(sta->eapol_sm,
&identity_len);
- if (identity &&
- identity_len == attr->user_name_len &&
+ if (!identity ||
+ identity_len != attr->user_name_len ||
os_memcmp(identity, attr->user_name, identity_len)
- == 0)
- break;
+ != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after User-Name check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: User-Name match");
+ }
+
+ if (num_attr == 0) {
+ /*
+ * In theory, we could match all current associations, but it
+ * seems safer to just reject requests that do not include any
+ * session identification attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No session identification attributes included");
+ return NULL;
+ }
+
+ selected = NULL;
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->radius_das_match) {
+ if (selected) {
+ *multi = 1;
+ return NULL;
+ }
+ selected = sta;
}
}
- return sta;
+ return selected;
+}
+
+
+static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ if (!hapd->wpa_auth)
+ return -1;
+ return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
}
@@ -583,13 +812,30 @@ hostapd_das_disconnect(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);
- if (sta == NULL)
+ sta = hostapd_das_find_sta(hapd, attr, &multi);
+ if (sta == NULL) {
+ if (multi) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Multiple sessions match - not supported");
+ return RADIUS_DAS_MULTI_SESSION_MATCH;
+ }
+ if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: PMKSA cache entry matched");
+ return RADIUS_DAS_SUCCESS;
+ }
+ 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
+ " - disconnecting", MAC2STR(sta->addr));
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
hostapd_drv_sta_deauth(hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -604,7 +850,8 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
/**
* hostapd_setup_bss - Per-BSS setup (initialization)
* @hapd: Pointer to BSS data
- * @first: Whether this BSS is the first BSS of an interface
+ * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
+ * but interface may exist
*
* This function is used to initialize all per-BSS data structures and
* resources. This gets called in a loop for each BSS when an interface is
@@ -618,35 +865,54 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
int ssid_len, set_ssid;
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
+ int flush_old_stations = 1;
- if (!first) {
- if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
+ wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
+ __func__, hapd, conf->iface, first);
+
+#ifdef EAP_SERVER_TNC
+ if (conf->tnc && tncs_global_init() < 0) {
+ wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
+ return -1;
+ }
+#endif /* EAP_SERVER_TNC */
+
+ if (hapd->started) {
+ wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
+ __func__, conf->iface);
+ return -1;
+ }
+ 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 {
/* Allocate the configured BSSID. */
- os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
+ os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
if (hostapd_mac_comp(hapd->own_addr,
hapd->iface->bss[0]->own_addr) ==
0) {
wpa_printf(MSG_ERROR, "BSS '%s' may not have "
"BSSID set to the MAC address of "
- "the radio", hapd->conf->iface);
+ "the radio", conf->iface);
return -1;
}
}
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
- hapd->conf->iface, hapd->own_addr, hapd,
+ conf->iface, hapd->own_addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
- hapd->conf->bridge[0] ? hapd->conf->bridge :
- NULL)) {
+ conf->bridge[0] ? conf->bridge : NULL,
+ first == -1)) {
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
MACSTR ")", MAC2STR(hapd->own_addr));
+ hapd->interface_added = 0;
return -1;
}
}
@@ -654,11 +920,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
- hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_MESH
+ if (hapd->iface->mconf == NULL)
+ flush_old_stations = 0;
+#endif /* CONFIG_MESH */
+
+ if (flush_old_stations)
+ hostapd_flush_old_stations(hapd,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
- if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+ if (hostapd_setup_encryption(conf->iface, hapd))
return -1;
/*
@@ -692,9 +965,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
- hapd->conf->iface, MAC2STR(hapd->own_addr),
- wpa_ssid_txt(hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len));
+ conf->iface, MAC2STR(hapd->own_addr),
+ wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
}
if (hostapd_setup_wpa_psk(conf)) {
@@ -710,7 +982,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (wpa_debug_level == MSG_MSGDUMP)
+ if (wpa_debug_level <= MSG_MSGDUMP)
conf->radius->msg_dumps = 1;
#ifndef CONFIG_NO_RADIUS
hapd->radius = radius_client_init(hapd, conf->radius);
@@ -719,17 +991,17 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (hapd->conf->radius_das_port) {
+ if (conf->radius_das_port) {
struct radius_das_conf das_conf;
os_memset(&das_conf, 0, sizeof(das_conf));
- das_conf.port = hapd->conf->radius_das_port;
- das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+ das_conf.port = conf->radius_das_port;
+ das_conf.shared_secret = conf->radius_das_shared_secret;
das_conf.shared_secret_len =
- hapd->conf->radius_das_shared_secret_len;
- das_conf.client_addr = &hapd->conf->radius_das_client_addr;
- das_conf.time_window = hapd->conf->radius_das_time_window;
+ conf->radius_das_shared_secret_len;
+ das_conf.client_addr = &conf->radius_das_client_addr;
+ das_conf.time_window = conf->radius_das_time_window;
das_conf.require_event_timestamp =
- hapd->conf->radius_das_require_event_timestamp;
+ conf->radius_das_require_event_timestamp;
das_conf.ctx = hapd;
das_conf.disconnect = hostapd_das_disconnect;
hapd->radius_das = radius_das_init(&das_conf);
@@ -756,7 +1028,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
+ if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd))
return -1;
if (accounting_init(hapd)) {
@@ -764,8 +1036,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (hapd->conf->ieee802_11f &&
- (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
+ if (conf->ieee802_11f &&
+ (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
"failed.");
return -1;
@@ -776,21 +1048,47 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1;
}
+
+ if (conf->qos_map_set_len &&
+ hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
+ conf->qos_map_set_len)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
+ return -1;
+ }
#endif /* CONFIG_INTERWORKING */
- if (hapd->iface->interfaces &&
- hapd->iface->interfaces->ctrl_iface_init &&
- hapd->iface->interfaces->ctrl_iface_init(hapd)) {
- wpa_printf(MSG_ERROR, "Failed to setup control interface");
+ if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
+ wpa_printf(MSG_ERROR, "BSS Load initialization failed");
return -1;
}
+ if (conf->proxy_arp) {
+ if (x_snoop_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Generic snooping infrastructure initialization failed");
+ return -1;
+ }
+
+ if (dhcp_snoop_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "DHCP snooping initialization failed");
+ return -1;
+ }
+
+ if (ndisc_snoop_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Neighbor Discovery snooping initialization failed");
+ return -1;
+ }
+ }
+
if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
wpa_printf(MSG_ERROR, "VLAN initialization failed.");
return -1;
}
- ieee802_11_set_beacon(hapd);
+ if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
+ return -1;
if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
return -1;
@@ -808,6 +1106,11 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
int i;
struct hostapd_tx_queue_params *p;
+#ifdef CONFIG_MESH
+ if (iface->mconf == NULL)
+ return;
+#endif /* CONFIG_MESH */
+
for (i = 0; i < NUM_TX_QUEUES; i++) {
p = &iface->conf->tx_queue[i];
@@ -821,11 +1124,152 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
}
+static int hostapd_set_acl_list(struct hostapd_data *hapd,
+ struct mac_acl_entry *mac_acl,
+ int n_entries, u8 accept_acl)
+{
+ struct hostapd_acl_params *acl_params;
+ int i, err;
+
+ acl_params = os_zalloc(sizeof(*acl_params) +
+ (n_entries * sizeof(acl_params->mac_acl[0])));
+ if (!acl_params)
+ return -ENOMEM;
+
+ for (i = 0; i < n_entries; i++)
+ os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr,
+ ETH_ALEN);
+
+ acl_params->acl_policy = accept_acl;
+ acl_params->num_mac_acl = n_entries;
+
+ err = hostapd_drv_set_acl(hapd, acl_params);
+
+ os_free(acl_params);
+
+ return err;
+}
+
+
+static void hostapd_set_acl(struct hostapd_data *hapd)
+{
+ struct hostapd_config *conf = hapd->iconf;
+ int err;
+ u8 accept_acl;
+
+ if (hapd->iface->drv_max_acl_mac_addrs == 0)
+ return;
+
+ if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+ accept_acl = 1;
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac,
+ conf->bss[0]->num_accept_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set accept acl");
+ return;
+ }
+ } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+ accept_acl = 0;
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
+ conf->bss[0]->num_deny_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set deny acl");
+ return;
+ }
+ }
+}
+
+
+static int start_ctrl_iface_bss(struct hostapd_data *hapd)
+{
+ if (!hapd->iface->interfaces ||
+ !hapd->iface->interfaces->ctrl_iface_init)
+ return 0;
+
+ if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to setup control interface for %s",
+ hapd->conf->iface);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int start_ctrl_iface(struct hostapd_iface *iface)
+{
+ size_t i;
+
+ if (!iface->interfaces || !iface->interfaces->ctrl_iface_init)
+ return 0;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+ if (iface->interfaces->ctrl_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to setup control interface for %s",
+ hapd->conf->iface);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+
+ if (!iface->wait_channel_update) {
+ wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
+ return;
+ }
+
+ /*
+ * It is possible that the existing channel list is acceptable, so try
+ * to proceed.
+ */
+ wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
+ setup_interface2(iface);
+}
+
+
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator)
+{
+ if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ setup_interface2(iface);
+}
+
+
static int setup_interface(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
size_t i;
- char country[4];
+
+ /*
+ * It is possible that setup_interface() is called after the interface
+ * was disabled etc., in which case driver_ap_teardown is possibly set
+ * to 1. Clear it here so any other key/station deletion, which is not
+ * part of a teardown flow, would also call the relevant driver
+ * callbacks.
+ */
+ iface->driver_ap_teardown = 0;
+
+ if (!iface->phy[0]) {
+ const char *phy = hostapd_drv_get_radio_name(hapd);
+ if (phy) {
+ wpa_printf(MSG_DEBUG, "phy: %s", phy);
+ os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+ }
+ }
/*
* Make sure that all BSSes get configured with a pointer to the same
@@ -839,15 +1283,49 @@ static int setup_interface(struct hostapd_iface *iface)
if (hostapd_validate_bssid_configuration(iface))
return -1;
+ /*
+ * Initialize control interfaces early to allow external monitoring of
+ * channel setup operations that may take considerable amount of time
+ * especially for DFS cases.
+ */
+ if (start_ctrl_iface(iface))
+ return -1;
+
if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+ char country[4], previous_country[4];
+
+ hostapd_set_state(iface, HAPD_IFACE_COUNTRY_UPDATE);
+ if (hostapd_get_country(hapd, previous_country) < 0)
+ previous_country[0] = '\0';
+
os_memcpy(country, hapd->iconf->country, 3);
country[3] = '\0';
if (hostapd_set_country(hapd, country) < 0) {
wpa_printf(MSG_ERROR, "Failed to set country code");
return -1;
}
+
+ wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
+ previous_country, country);
+
+ if (os_strncmp(previous_country, country, 2) != 0) {
+ wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
+ iface->wait_channel_update = 1;
+ eloop_register_timeout(5, 0,
+ channel_list_update_timeout,
+ iface, NULL);
+ return 0;
+ }
}
+ return setup_interface2(iface);
+}
+
+
+static int setup_interface2(struct hostapd_iface *iface)
+{
+ iface->wait_channel_update = 0;
+
if (hostapd_get_hw_features(iface)) {
/* Not all drivers support this yet, so continue without hw
* feature data. */
@@ -856,48 +1334,117 @@ static int setup_interface(struct hostapd_iface *iface)
if (ret < 0) {
wpa_printf(MSG_ERROR, "Could not select hw_mode and "
"channel. (%d)", ret);
- return -1;
+ goto fail;
+ }
+ if (ret == 1) {
+ wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
+ return 0;
}
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
- return -1;
+ goto fail;
if (ret == 1) {
wpa_printf(MSG_DEBUG, "Interface initialization will "
"be completed in a callback");
return 0;
}
+
+ if (iface->conf->ieee80211h)
+ wpa_printf(MSG_DEBUG, "DFS support is enabled");
}
return hostapd_setup_interface_complete(iface, 0);
+
+fail:
+ hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+ if (iface->interfaces && iface->interfaces->terminate_on_error)
+ eloop_terminate();
+ 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 hostapd_data *hapd = iface->bss[0];
size_t j;
u8 *prev_addr;
+ int delay_apply_cfg = 0;
+ int res_dfs_offload = 0;
- if (err) {
- wpa_printf(MSG_ERROR, "Interface initialization failed");
- eloop_terminate();
- return -1;
- }
+ if (err)
+ goto fail;
wpa_printf(MSG_DEBUG, "Completing interface initialization");
- if (hapd->iconf->channel) {
- iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+ if (iface->conf->channel) {
+#ifdef NEED_AP_MLME
+ int res;
+#endif /* NEED_AP_MLME */
+
+ iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
- hostapd_hw_mode_txt(hapd->iconf->hw_mode),
- hapd->iconf->channel, iface->freq);
+ hostapd_hw_mode_txt(iface->conf->hw_mode),
+ iface->conf->channel, iface->freq);
+
+#ifdef NEED_AP_MLME
+ /* Handle DFS only if it is not offloaded to the driver */
+ if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
+ /* Check DFS */
+ res = hostapd_handle_dfs(iface);
+ if (res <= 0) {
+ if (res < 0)
+ goto fail;
+ return res;
+ }
+ } else {
+ /* If DFS is offloaded to the driver */
+ res_dfs_offload = hostapd_handle_dfs_offload(iface);
+ if (res_dfs_offload <= 0) {
+ if (res_dfs_offload < 0)
+ goto fail;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Proceed with AP/channel setup");
+ /*
+ * If this is a DFS channel, move to completing
+ * AP setup.
+ */
+ if (res_dfs_offload == 1)
+ goto dfs_offload;
+ /* Otherwise fall through. */
+ }
+ }
+#endif /* NEED_AP_MLME */
+
+#ifdef CONFIG_MESH
+ if (iface->mconf != NULL) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Mesh configuration will be applied while joining the mesh network",
+ iface->bss[0]->conf->iface);
+ delay_apply_cfg = 1;
+ }
+#endif /* CONFIG_MESH */
- if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+ if (!delay_apply_cfg &&
+ hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
- hapd->iconf->secondary_channel)) {
+ hapd->iconf->ieee80211ac,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ hapd->iconf->vht_oper_centr_freq_seg0_idx,
+ hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
wpa_printf(MSG_ERROR, "Could not set channel for "
"kernel driver");
- return -1;
+ goto fail;
}
}
@@ -908,7 +1455,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Failed to prepare rates table.");
- return -1;
+ goto fail;
}
}
@@ -916,14 +1463,14 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
"kernel driver");
- return -1;
+ goto fail;
}
if (hapd->iconf->fragm_threshold > -1 &&
hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
"for kernel driver");
- return -1;
+ goto fail;
}
prev_addr = hapd->own_addr;
@@ -932,20 +1479,29 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hapd = iface->bss[j];
if (j)
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
- if (hostapd_setup_bss(hapd, j == 0))
- return -1;
+ if (hostapd_setup_bss(hapd, j == 0)) {
+ do {
+ hapd = iface->bss[j];
+ hostapd_bss_deinit_no_free(hapd);
+ hostapd_free_hapd_data(hapd);
+ } while (j-- > 0);
+ goto fail;
+ }
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
prev_addr = hapd->own_addr;
}
+ hapd = iface->bss[0];
hostapd_tx_queue_params(iface);
ap_list_init(iface);
+ hostapd_set_acl(hapd);
+
if (hostapd_driver_commit(hapd) < 0) {
wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
"configuration", __func__);
- return -1;
+ goto fail;
}
/*
@@ -956,16 +1512,41 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
*/
for (j = 0; j < iface->num_bss; j++) {
if (hostapd_init_wps_complete(iface->bss[j]))
- return -1;
+ goto fail;
+ }
+
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ !res_dfs_offload) {
+ /*
+ * If freq is DFS, and DFS is offloaded to the driver, then wait
+ * for CAC to complete.
+ */
+ wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
+ return res_dfs_offload;
}
+#ifdef NEED_AP_MLME
+dfs_offload:
+#endif /* NEED_AP_MLME */
+ hostapd_set_state(iface, HAPD_IFACE_ENABLED);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
+ if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
+ iface->interfaces->terminate_on_error--;
return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Interface initialization failed");
+ hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+ if (iface->interfaces && iface->interfaces->terminate_on_error)
+ eloop_terminate();
+ return -1;
}
@@ -978,6 +1559,12 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
* and sets driver parameters based on the configuration.
* Flushes old stations, sets the channel, encryption,
* beacons, and WDS links based on the configuration.
+ *
+ * If interface setup requires more time, e.g., to perform HT co-ex scans, ACS,
+ * or DFS operations, this function returns 0 before such operations have been
+ * completed. The pending operations are registered into eloop and will be
+ * completed from eloop callbacks. Those callbacks end up calling
+ * hostapd_setup_interface_complete() once setup has been completed.
*/
int hostapd_setup_interface(struct hostapd_iface *iface)
{
@@ -1027,68 +1614,327 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
}
+static void hostapd_bss_deinit(struct hostapd_data *hapd)
+{
+ wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
+ hapd->conf->iface);
+ hostapd_bss_deinit_no_free(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+ hostapd_cleanup(hapd);
+}
+
+
void hostapd_interface_deinit(struct hostapd_iface *iface)
{
- size_t j;
+ int j;
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
if (iface == NULL)
return;
- hostapd_cleanup_iface_pre(iface);
- for (j = 0; j < iface->num_bss; j++) {
- struct hostapd_data *hapd = iface->bss[j];
- hostapd_free_stas(hapd);
- hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
- hostapd_clear_wep(hapd);
- hostapd_cleanup(hapd);
- }
+ 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;
+
+ for (j = iface->num_bss - 1; j >= 0; j--)
+ hostapd_bss_deinit(iface->bss[j]);
}
void hostapd_interface_free(struct hostapd_iface *iface)
{
size_t j;
- for (j = 0; j < iface->num_bss; j++)
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+ for (j = 0; j < iface->num_bss; j++) {
+ wpa_printf(MSG_DEBUG, "%s: free hapd %p",
+ __func__, iface->bss[j]);
os_free(iface->bss[j]);
+ }
hostapd_cleanup_iface(iface);
}
-#ifdef HOSTAPD
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+ const char *config_file)
+{
+ struct hostapd_iface *hapd_iface = NULL;
+ struct hostapd_config *conf = NULL;
+ struct hostapd_data *hapd;
+ size_t i;
+
+ hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ if (hapd_iface == NULL)
+ goto fail;
+
+ hapd_iface->config_fname = os_strdup(config_file);
+ if (hapd_iface->config_fname == NULL)
+ goto fail;
+
+ conf = interfaces->config_read_cb(hapd_iface->config_fname);
+ if (conf == NULL)
+ goto fail;
+ hapd_iface->conf = conf;
+
+ hapd_iface->num_bss = conf->num_bss;
+ hapd_iface->bss = os_calloc(conf->num_bss,
+ sizeof(struct hostapd_data *));
+ if (hapd_iface->bss == NULL)
+ goto fail;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ hapd = hapd_iface->bss[i] =
+ hostapd_alloc_bss_data(hapd_iface, conf,
+ conf->bss[i]);
+ if (hapd == NULL)
+ goto fail;
+ hapd->msg_ctx = hapd;
+ }
+
+ return hapd_iface;
+
+fail:
+ wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
+ config_file);
+ if (conf)
+ hostapd_config_free(conf);
+ if (hapd_iface) {
+ os_free(hapd_iface->config_fname);
+ os_free(hapd_iface->bss);
+ wpa_printf(MSG_DEBUG, "%s: free iface %p",
+ __func__, hapd_iface);
+ os_free(hapd_iface);
+ }
+ return NULL;
+}
+
+
+static int ifname_in_use(struct hapd_interfaces *interfaces, const char *ifname)
+{
+ size_t i, j;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_data *hapd = iface->bss[j];
+ if (os_strcmp(ifname, hapd->conf->iface) == 0)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * hostapd_interface_init_bss - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a BSS. This BSS is
+ * added to an existing interface sharing the same radio (if any) or a new
+ * interface is created if this is the first interface on a radio. This
+ * allocate memory for the BSS. No actual driver operations are started.
+ *
+ * This is similar to hostapd_interface_init(), but for a case where the
+ * configuration is used to add a single BSS instead of all BSSes for a radio.
+ */
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug)
+{
+ struct hostapd_iface *new_iface = NULL, *iface = NULL;
+ struct hostapd_data *hapd;
+ int k;
+ size_t i, bss_idx;
+
+ if (!phy || !*phy)
+ return NULL;
+
+ for (i = 0; i < interfaces->count; i++) {
+ if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
+ iface = interfaces->iface[i];
+ break;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
+ config_fname, phy, iface ? "" : " --> new PHY");
+ if (iface) {
+ struct hostapd_config *conf;
+ struct hostapd_bss_config **tmp_conf;
+ struct hostapd_data **tmp_bss;
+ struct hostapd_bss_config *bss;
+ const char *ifname;
+
+ /* Add new BSS to existing iface */
+ conf = interfaces->config_read_cb(config_fname);
+ if (conf == NULL)
+ return NULL;
+ if (conf->num_bss > 1) {
+ wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ ifname = conf->bss[0]->iface;
+ if (ifname[0] != '\0' && ifname_in_use(interfaces, ifname)) {
+ wpa_printf(MSG_ERROR,
+ "Interface name %s already in use", ifname);
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ tmp_conf = os_realloc_array(
+ iface->conf->bss, iface->conf->num_bss + 1,
+ sizeof(struct hostapd_bss_config *));
+ tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+ sizeof(struct hostapd_data *));
+ if (tmp_bss)
+ iface->bss = tmp_bss;
+ if (tmp_conf) {
+ iface->conf->bss = tmp_conf;
+ iface->conf->last_bss = tmp_conf[0];
+ }
+ if (tmp_bss == NULL || tmp_conf == NULL) {
+ hostapd_config_free(conf);
+ return NULL;
+ }
+ bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
+ iface->conf->num_bss++;
+
+ hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+ if (hapd == NULL) {
+ iface->conf->num_bss--;
+ hostapd_config_free(conf);
+ return NULL;
+ }
+ iface->conf->last_bss = bss;
+ iface->bss[iface->num_bss] = hapd;
+ hapd->msg_ctx = hapd;
+
+ bss_idx = iface->num_bss++;
+ conf->num_bss--;
+ conf->bss[0] = NULL;
+ hostapd_config_free(conf);
+ } else {
+ /* Add a new iface with the first BSS */
+ new_iface = iface = hostapd_init(interfaces, config_fname);
+ if (!iface)
+ return NULL;
+ os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+ iface->interfaces = interfaces;
+ bss_idx = 0;
+ }
+
+ for (k = 0; k < debug; k++) {
+ if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
+ iface->bss[bss_idx]->conf->logger_stdout_level--;
+ }
+
+ if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
+ !hostapd_drv_none(iface->bss[bss_idx])) {
+ wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ config_fname);
+ if (new_iface)
+ hostapd_interface_deinit_free(new_iface);
+ return NULL;
+ }
+
+ return iface;
+}
+
void hostapd_interface_deinit_free(struct hostapd_iface *iface)
{
const struct wpa_driver_ops *driver;
void *drv_priv;
+
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
if (iface == NULL)
return;
+ wpa_printf(MSG_DEBUG, "%s: num_bss=%u conf->num_bss=%u",
+ __func__, (unsigned int) iface->num_bss,
+ (unsigned int) iface->conf->num_bss);
driver = iface->bss[0]->driver;
drv_priv = iface->bss[0]->drv_priv;
hostapd_interface_deinit(iface);
- if (driver && driver->hapd_deinit && drv_priv)
+ wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+ __func__, driver, drv_priv);
+ if (driver && driver->hapd_deinit && drv_priv) {
driver->hapd_deinit(drv_priv);
+ iface->bss[0]->drv_priv = NULL;
+ }
hostapd_interface_free(iface);
}
+static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
+ void *drv_priv,
+ struct hostapd_iface *hapd_iface)
+{
+ size_t j;
+
+ wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+ __func__, driver, drv_priv);
+ if (driver && driver->hapd_deinit && drv_priv) {
+ driver->hapd_deinit(drv_priv);
+ for (j = 0; j < hapd_iface->num_bss; j++) {
+ wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
+ __func__, (int) j,
+ hapd_iface->bss[j]->drv_priv);
+ if (hapd_iface->bss[j]->drv_priv == drv_priv)
+ hapd_iface->bss[j]->drv_priv = NULL;
+ }
+ }
+}
+
+
int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
{
+ size_t j;
+
if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled",
- hapd_iface->conf->bss[0].iface);
+ hapd_iface->conf->bss[0]->iface);
return -1;
}
wpa_printf(MSG_DEBUG, "Enable interface %s",
- hapd_iface->conf->bss[0].iface);
+ hapd_iface->conf->bss[0]->iface);
+
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
+ if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
+ wpa_printf(MSG_INFO, "Invalid configuration - cannot enable");
+ return -1;
+ }
if (hapd_iface->interfaces == NULL ||
hapd_iface->interfaces->driver_init == NULL ||
- hapd_iface->interfaces->driver_init(hapd_iface) ||
- hostapd_setup_interface(hapd_iface)) {
- hostapd_interface_deinit_free(hapd_iface);
+ hapd_iface->interfaces->driver_init(hapd_iface))
+ return -1;
+
+ if (hostapd_setup_interface(hapd_iface)) {
+ hostapd_deinit_driver(hapd_iface->bss[0]->driver,
+ hapd_iface->bss[0]->drv_priv,
+ hapd_iface);
return -1;
}
+
return 0;
}
@@ -1098,19 +1944,17 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
size_t j;
wpa_printf(MSG_DEBUG, "Reload interface %s",
- hapd_iface->conf->bss[0].iface);
- for (j = 0; j < hapd_iface->num_bss; j++) {
- hostapd_flush_old_stations(hapd_iface->bss[j],
- WLAN_REASON_PREV_AUTH_NOT_VALID);
-
-#ifndef CONFIG_NO_RADIUS
- /* TODO: update dynamic data based on changed configuration
- * items (e.g., open/close sockets, etc.) */
- radius_client_flush(hapd_iface->bss[j]->radius, 0);
-#endif /* CONFIG_NO_RADIUS */
-
- hostapd_reload_bss(hapd_iface->bss[j]);
+ hapd_iface->conf->bss[0]->iface);
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_set_security_params(hapd_iface->conf->bss[j], 1);
+ if (hostapd_config_check(hapd_iface->conf, 1) < 0) {
+ wpa_printf(MSG_ERROR, "Updated configuration is invalid");
+ return -1;
}
+ hostapd_clear_old(hapd_iface);
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_reload_bss(hapd_iface->bss[j]);
+
return 0;
}
@@ -1118,39 +1962,43 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
- struct hostapd_bss_config *bss;
const struct wpa_driver_ops *driver;
void *drv_priv;
if (hapd_iface == NULL)
return -1;
- bss = hapd_iface->bss[0]->conf;
+
+ if (hapd_iface->bss[0]->drv_priv == NULL) {
+ wpa_printf(MSG_INFO, "Interface %s already disabled",
+ hapd_iface->conf->bss[0]->iface);
+ return -1;
+ }
+
+ wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
driver = hapd_iface->bss[0]->driver;
drv_priv = hapd_iface->bss[0]->drv_priv;
- /* whatever hostapd_interface_deinit does */
+ hapd_iface->driver_ap_teardown =
+ !!(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
+ /* 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];
- hostapd_free_stas(hapd);
- hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
- hostapd_clear_wep(hapd);
+ hostapd_bss_deinit_no_free(hapd);
hostapd_free_hapd_data(hapd);
}
- if (driver && driver->hapd_deinit && drv_priv) {
- driver->hapd_deinit(drv_priv);
- hapd_iface->bss[0]->drv_priv = NULL;
- }
+ hostapd_deinit_driver(driver, drv_priv, hapd_iface);
/* From hostapd_cleanup_iface: These were initialized in
* hostapd_setup_interface and hostapd_setup_interface_complete
*/
hostapd_cleanup_iface_partial(hapd_iface);
- bss->wpa = 0;
- bss->wpa_key_mgmt = -1;
- bss->wpa_pairwise = -1;
- wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->iface);
+ wpa_printf(MSG_DEBUG, "Interface %s disabled",
+ hapd_iface->bss[0]->conf->iface);
+ hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
return 0;
}
@@ -1201,7 +2049,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
return NULL;
}
- bss = conf->last_bss = conf->bss;
+ bss = conf->last_bss = conf->bss[0];
os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
bss->ctrl_interface = os_strdup(ctrl_iface);
@@ -1218,51 +2066,129 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
}
-static struct hostapd_iface * hostapd_data_alloc(
- struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
+ struct hostapd_config *conf)
{
size_t i;
- struct hostapd_iface *hapd_iface =
- interfaces->iface[interfaces->count - 1];
struct hostapd_data *hapd;
- hapd_iface->conf = conf;
- hapd_iface->num_bss = conf->num_bss;
-
- hapd_iface->bss = os_zalloc(conf->num_bss *
+ hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL)
- return NULL;
+ return -1;
for (i = 0; i < conf->num_bss; i++) {
hapd = hapd_iface->bss[i] =
- hostapd_alloc_bss_data(hapd_iface, conf,
- &conf->bss[i]);
- if (hapd == NULL)
- return NULL;
+ hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
+ if (hapd == NULL) {
+ while (i > 0) {
+ i--;
+ os_free(hapd_iface->bss[i]);
+ hapd_iface->bss[i] = NULL;
+ }
+ os_free(hapd_iface->bss);
+ hapd_iface->bss = NULL;
+ return -1;
+ }
hapd->msg_ctx = hapd;
}
- hapd_iface->interfaces = interfaces;
+ hapd_iface->conf = conf;
+ hapd_iface->num_bss = conf->num_bss;
- return hapd_iface;
+ return 0;
}
int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
{
struct hostapd_config *conf = NULL;
- struct hostapd_iface *hapd_iface = NULL;
+ struct hostapd_iface *hapd_iface = NULL, *new_iface = NULL;
+ struct hostapd_data *hapd;
char *ptr;
- size_t i;
+ size_t i, j;
+ const char *conf_file = NULL, *phy_name = NULL;
+
+ if (os_strncmp(buf, "bss_config=", 11) == 0) {
+ char *pos;
+ phy_name = buf + 11;
+ pos = os_strchr(phy_name, ':');
+ if (!pos)
+ return -1;
+ *pos++ = '\0';
+ conf_file = pos;
+ if (!os_strlen(conf_file))
+ return -1;
+
+ hapd_iface = hostapd_interface_init_bss(interfaces, phy_name,
+ conf_file, 0);
+ if (!hapd_iface)
+ return -1;
+ for (j = 0; j < interfaces->count; j++) {
+ if (interfaces->iface[j] == hapd_iface)
+ break;
+ }
+ if (j == interfaces->count) {
+ struct hostapd_iface **tmp;
+ tmp = os_realloc_array(interfaces->iface,
+ interfaces->count + 1,
+ sizeof(struct hostapd_iface *));
+ if (!tmp) {
+ hostapd_interface_deinit_free(hapd_iface);
+ return -1;
+ }
+ interfaces->iface = tmp;
+ interfaces->iface[interfaces->count++] = hapd_iface;
+ new_iface = hapd_iface;
+ }
+
+ if (new_iface) {
+ if (interfaces->driver_init(hapd_iface))
+ goto fail;
+
+ if (hostapd_setup_interface(hapd_iface)) {
+ hostapd_deinit_driver(
+ hapd_iface->bss[0]->driver,
+ hapd_iface->bss[0]->drv_priv,
+ hapd_iface);
+ goto fail;
+ }
+ } else {
+ /* Assign new BSS with bss[0]'s driver info */
+ hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
+ hapd->driver = hapd_iface->bss[0]->driver;
+ hapd->drv_priv = hapd_iface->bss[0]->drv_priv;
+ os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
+ ETH_ALEN);
+
+ if (start_ctrl_iface_bss(hapd) < 0 ||
+ (hapd_iface->state == HAPD_IFACE_ENABLED &&
+ hostapd_setup_bss(hapd, -1))) {
+ hostapd_cleanup(hapd);
+ hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
+ hapd_iface->conf->num_bss--;
+ hapd_iface->num_bss--;
+ wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
+ __func__, hapd, hapd->conf->iface);
+ hostapd_config_free_bss(hapd->conf);
+ hapd->conf = NULL;
+ os_free(hapd);
+ return -1;
+ }
+ }
+ return 0;
+ }
ptr = os_strchr(buf, ' ');
if (ptr == NULL)
return -1;
*ptr++ = '\0';
+ if (os_strncmp(ptr, "config=", 7) == 0)
+ conf_file = ptr + 7;
+
for (i = 0; i < interfaces->count; i++) {
- if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+ if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
buf)) {
wpa_printf(MSG_INFO, "Cannot add interface - it "
"already exists");
@@ -1276,29 +2202,33 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
"for interface", __func__);
goto fail;
}
+ new_iface = hapd_iface;
- conf = hostapd_config_alloc(interfaces, buf, ptr);
- if (conf == NULL) {
+ if (conf_file && interfaces->config_read_cb) {
+ conf = interfaces->config_read_cb(conf_file);
+ if (conf && conf->bss)
+ os_strlcpy(conf->bss[0]->iface, buf,
+ sizeof(conf->bss[0]->iface));
+ } else
+ conf = hostapd_config_alloc(interfaces, buf, ptr);
+ if (conf == NULL || conf->bss == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
"for configuration", __func__);
goto fail;
}
- hapd_iface = hostapd_data_alloc(interfaces, conf);
- if (hapd_iface == NULL) {
+ if (hostapd_data_alloc(hapd_iface, conf) < 0) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
"for hostapd", __func__);
goto fail;
}
+ conf = NULL;
- if (hapd_iface->interfaces &&
- hapd_iface->interfaces->ctrl_iface_init &&
- hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
- wpa_printf(MSG_ERROR, "%s: Failed to setup control "
- "interface", __func__);
+ if (start_ctrl_iface(hapd_iface) < 0)
goto fail;
- }
- wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+ wpa_printf(MSG_INFO, "Add interface '%s'",
+ hapd_iface->conf->bss[0]->iface);
return 0;
@@ -1306,24 +2236,84 @@ fail:
if (conf)
hostapd_config_free(conf);
if (hapd_iface) {
- os_free(hapd_iface->bss[interfaces->count]);
- os_free(hapd_iface);
+ if (hapd_iface->bss) {
+ for (i = 0; i < hapd_iface->num_bss; i++) {
+ hapd = hapd_iface->bss[i];
+ if (!hapd)
+ continue;
+ if (hapd_iface->interfaces &&
+ hapd_iface->interfaces->ctrl_iface_deinit)
+ hapd_iface->interfaces->
+ ctrl_iface_deinit(hapd);
+ wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
+ __func__, hapd_iface->bss[i],
+ hapd->conf->iface);
+ hostapd_cleanup(hapd);
+ os_free(hapd);
+ hapd_iface->bss[i] = NULL;
+ }
+ os_free(hapd_iface->bss);
+ hapd_iface->bss = NULL;
+ }
+ if (new_iface) {
+ interfaces->count--;
+ interfaces->iface[interfaces->count] = NULL;
+ }
+ hostapd_cleanup_iface(hapd_iface);
}
return -1;
}
+static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
+{
+ size_t i;
+
+ wpa_printf(MSG_INFO, "Remove BSS '%s'", iface->conf->bss[idx]->iface);
+
+ /* Remove hostapd_data only if it has already been initialized */
+ if (idx < iface->num_bss) {
+ struct hostapd_data *hapd = iface->bss[idx];
+
+ hostapd_bss_deinit(hapd);
+ wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
+ __func__, hapd, hapd->conf->iface);
+ hostapd_config_free_bss(hapd->conf);
+ hapd->conf = NULL;
+ os_free(hapd);
+
+ iface->num_bss--;
+
+ for (i = idx; i < iface->num_bss; i++)
+ iface->bss[i] = iface->bss[i + 1];
+ } else {
+ hostapd_config_free_bss(iface->conf->bss[idx]);
+ iface->conf->bss[idx] = NULL;
+ }
+
+ iface->conf->num_bss--;
+ for (i = idx; i < iface->conf->num_bss; i++)
+ iface->conf->bss[i] = iface->conf->bss[i + 1];
+
+ return 0;
+}
+
+
int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
{
struct hostapd_iface *hapd_iface;
- size_t i, k = 0;
+ size_t i, j, k = 0;
for (i = 0; i < interfaces->count; i++) {
hapd_iface = interfaces->iface[i];
if (hapd_iface == NULL)
return -1;
- if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+ if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+ hapd_iface->driver_ap_teardown =
+ !!(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
hostapd_interface_deinit_free(hapd_iface);
k = i;
while (k < (interfaces->count - 1)) {
@@ -1334,12 +2324,19 @@ int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
interfaces->count--;
return 0;
}
+
+ for (j = 0; j < hapd_iface->conf->num_bss; j++) {
+ if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
+ hapd_iface->driver_ap_teardown =
+ !(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+ return hostapd_remove_bss(hapd_iface, j);
+ }
+ }
}
return -1;
}
-#endif /* HOSTAPD */
-
/**
* hostapd_new_assoc_sta - Notify that a new station associated with the AP
@@ -1379,8 +2376,9 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
/* Start accounting here, if IEEE 802.1X and WPA are not used.
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
- if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
- os_get_time(&sta->connected_time);
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) {
+ ap_sta_set_authorized(hapd, sta, 1);
+ os_get_reltime(&sta->connected_time);
accounting_sta_start(hapd, sta);
}
@@ -1393,11 +2391,335 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
- wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
- "for " MACSTR " (%d seconds - ap_max_inactivity)",
- __func__, MAC2STR(sta->addr),
- hapd->conf->ap_max_inactivity);
- eloop_cancel_timeout(ap_handle_timer, hapd, sta);
- eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
- ap_handle_timer, hapd, sta);
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - ap_max_inactivity)",
+ __func__, MAC2STR(sta->addr),
+ hapd->conf->ap_max_inactivity);
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+ ap_handle_timer, hapd, sta);
+ }
+}
+
+
+const char * hostapd_state_text(enum hostapd_iface_state s)
+{
+ switch (s) {
+ case HAPD_IFACE_UNINITIALIZED:
+ return "UNINITIALIZED";
+ case HAPD_IFACE_DISABLED:
+ return "DISABLED";
+ case HAPD_IFACE_COUNTRY_UPDATE:
+ return "COUNTRY_UPDATE";
+ case HAPD_IFACE_ACS:
+ return "ACS";
+ case HAPD_IFACE_HT_SCAN:
+ return "HT_SCAN";
+ case HAPD_IFACE_DFS:
+ return "DFS";
+ case HAPD_IFACE_ENABLED:
+ return "ENABLED";
+ }
+
+ return "UNKNOWN";
+}
+
+
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
+{
+ wpa_printf(MSG_INFO, "%s: interface state %s->%s",
+ iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
+ hostapd_state_text(s));
+ iface->state = s;
+}
+
+
+#ifdef NEED_AP_MLME
+
+static void free_beacon_data(struct beacon_data *beacon)
+{
+ os_free(beacon->head);
+ beacon->head = NULL;
+ os_free(beacon->tail);
+ beacon->tail = NULL;
+ os_free(beacon->probe_resp);
+ beacon->probe_resp = NULL;
+ os_free(beacon->beacon_ies);
+ beacon->beacon_ies = NULL;
+ os_free(beacon->proberesp_ies);
+ beacon->proberesp_ies = NULL;
+ os_free(beacon->assocresp_ies);
+ beacon->assocresp_ies = NULL;
}
+
+
+static int hostapd_build_beacon_data(struct hostapd_data *hapd,
+ struct beacon_data *beacon)
+{
+ struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
+ struct wpa_driver_ap_params params;
+ int ret;
+
+ os_memset(beacon, 0, sizeof(*beacon));
+ ret = ieee802_11_build_ap_params(hapd, &params);
+ if (ret < 0)
+ return ret;
+
+ ret = hostapd_build_ap_extra_ies(hapd, &beacon_extra,
+ &proberesp_extra,
+ &assocresp_extra);
+ if (ret)
+ goto free_ap_params;
+
+ ret = -1;
+ beacon->head = os_malloc(params.head_len);
+ if (!beacon->head)
+ goto free_ap_extra_ies;
+
+ os_memcpy(beacon->head, params.head, params.head_len);
+ beacon->head_len = params.head_len;
+
+ beacon->tail = os_malloc(params.tail_len);
+ if (!beacon->tail)
+ goto free_beacon;
+
+ os_memcpy(beacon->tail, params.tail, params.tail_len);
+ beacon->tail_len = params.tail_len;
+
+ if (params.proberesp != NULL) {
+ beacon->probe_resp = os_malloc(params.proberesp_len);
+ if (!beacon->probe_resp)
+ goto free_beacon;
+
+ os_memcpy(beacon->probe_resp, params.proberesp,
+ params.proberesp_len);
+ beacon->probe_resp_len = params.proberesp_len;
+ }
+
+ /* copy the extra ies */
+ if (beacon_extra) {
+ beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra));
+ if (!beacon->beacon_ies)
+ goto free_beacon;
+
+ os_memcpy(beacon->beacon_ies,
+ beacon_extra->buf, wpabuf_len(beacon_extra));
+ beacon->beacon_ies_len = wpabuf_len(beacon_extra);
+ }
+
+ if (proberesp_extra) {
+ beacon->proberesp_ies =
+ os_malloc(wpabuf_len(proberesp_extra));
+ if (!beacon->proberesp_ies)
+ goto free_beacon;
+
+ os_memcpy(beacon->proberesp_ies, proberesp_extra->buf,
+ wpabuf_len(proberesp_extra));
+ beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
+ }
+
+ if (assocresp_extra) {
+ beacon->assocresp_ies =
+ os_malloc(wpabuf_len(assocresp_extra));
+ if (!beacon->assocresp_ies)
+ goto free_beacon;
+
+ os_memcpy(beacon->assocresp_ies, assocresp_extra->buf,
+ wpabuf_len(assocresp_extra));
+ beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
+ }
+
+ ret = 0;
+free_beacon:
+ /* if the function fails, the caller should not free beacon data */
+ if (ret)
+ free_beacon_data(beacon);
+
+free_ap_extra_ies:
+ hostapd_free_ap_extra_ies(hapd, beacon_extra, proberesp_extra,
+ assocresp_extra);
+free_ap_params:
+ ieee802_11_free_ap_params(&params);
+ return ret;
+}
+
+
+/*
+ * TODO: This flow currently supports only changing frequency within the
+ * same hw_mode. Any other changes to MAC parameters or provided settings (even
+ * width) are not supported.
+ */
+static int hostapd_change_config_freq(struct hostapd_data *hapd,
+ struct hostapd_config *conf,
+ struct hostapd_freq_params *params,
+ struct hostapd_freq_params *old_params)
+{
+ int channel;
+
+ if (!params->channel) {
+ /* check if the new channel is supported by hw */
+ params->channel = hostapd_hw_get_channel(hapd, params->freq);
+ }
+
+ channel = params->channel;
+ if (!channel)
+ 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;
+ }
+
+ conf->channel = channel;
+ conf->ieee80211n = params->ht_enabled;
+ conf->secondary_channel = params->sec_channel_offset;
+
+ /* TODO: maybe call here hostapd_config_check here? */
+
+ return 0;
+}
+
+
+static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
+ struct csa_settings *settings)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_freq_params old_freq;
+ int ret;
+
+ os_memset(&old_freq, 0, sizeof(old_freq));
+ if (!iface || !iface->freq || hapd->csa_in_progress)
+ return -1;
+
+ ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
+ &settings->freq_params,
+ &old_freq);
+ if (ret)
+ return ret;
+
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
+
+ /* change back the configuration */
+ hostapd_change_config_freq(iface->bss[0], iface->conf,
+ &old_freq, NULL);
+
+ if (ret)
+ return ret;
+
+ /* set channel switch parameters for csa ie */
+ hapd->cs_freq_params = settings->freq_params;
+ hapd->cs_count = settings->cs_count;
+ hapd->cs_block_tx = settings->block_tx;
+
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa);
+ if (ret) {
+ free_beacon_data(&settings->beacon_after);
+ return ret;
+ }
+
+ settings->counter_offset_beacon = hapd->cs_c_off_beacon;
+ settings->counter_offset_presp = hapd->cs_c_off_proberesp;
+
+ return 0;
+}
+
+
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
+{
+ os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params));
+ hapd->cs_count = 0;
+ hapd->cs_block_tx = 0;
+ hapd->cs_c_off_beacon = 0;
+ hapd->cs_c_off_proberesp = 0;
+ hapd->csa_in_progress = 0;
+}
+
+
+int hostapd_switch_channel(struct hostapd_data *hapd,
+ struct csa_settings *settings)
+{
+ int ret;
+
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
+ wpa_printf(MSG_INFO, "CSA is not supported");
+ return -1;
+ }
+
+ ret = hostapd_fill_csa_settings(hapd, settings);
+ if (ret)
+ return ret;
+
+ ret = hostapd_drv_switch_channel(hapd, settings);
+ free_beacon_data(&settings->beacon_csa);
+ free_beacon_data(&settings->beacon_after);
+
+ if (ret) {
+ /* if we failed, clean cs parameters */
+ hostapd_cleanup_cs_params(hapd);
+ return ret;
+ }
+
+ hapd->csa_in_progress = 1;
+ return 0;
+}
+
+
+void
+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");
+
+ if (freq_params->center_freq1)
+ vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
+ if (freq_params->center_freq2)
+ vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
+
+ switch (freq_params->bandwidth) {
+ case 0:
+ case 20:
+ case 40:
+ vht_bw = VHT_CHANWIDTH_USE_HT;
+ break;
+ case 80:
+ if (freq_params->center_freq2)
+ vht_bw = VHT_CHANWIDTH_80P80MHZ;
+ else
+ vht_bw = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 160:
+ vht_bw = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
+ freq_params->bandwidth);
+ break;
+ }
+
+ iface->freq = freq_params->freq;
+ iface->conf->channel = freq_params->channel;
+ iface->conf->secondary_channel = freq_params->sec_channel_offset;
+ iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
+ iface->conf->vht_oper_chwidth = vht_bw;
+ iface->conf->ieee80211n = freq_params->ht_enabled;
+ iface->conf->ieee80211ac = freq_params->vht_enabled;
+
+ /*
+ * cs_params must not be cleared earlier because the freq_params
+ * argument may actually point to one of these.
+ */
+ 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 */
diff --git a/contrib/wpa/src/ap/hostapd.h b/contrib/wpa/src/ap/hostapd.h
index f1e7d9f..75cc24e 100644
--- a/contrib/wpa/src/ap/hostapd.h
+++ b/contrib/wpa/src/ap/hostapd.h
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,19 +10,22 @@
#define HOSTAPD_H
#include "common/defs.h"
+#include "utils/list.h"
#include "ap_config.h"
+#include "drivers/driver.h"
-struct wpa_driver_ops;
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
struct hostapd_data;
struct sta_info;
-struct hostap_sta_driver_data;
struct ieee80211_ht_capabilities;
struct full_dynamic_vlan;
enum wps_event;
union wps_event_data;
+#ifdef CONFIG_MESH
+struct mesh_conf;
+#endif /* CONFIG_MESH */
struct hostapd_iface;
@@ -40,9 +43,19 @@ struct hapd_interfaces {
int global_ctrl_sock;
char *global_iface_path;
char *global_iface_name;
+#ifndef CONFIG_NATIVE_WINDOWS
+ gid_t ctrl_iface_group;
+#endif /* CONFIG_NATIVE_WINDOWS */
struct hostapd_iface **iface;
+
+ size_t terminate_on_error;
};
+enum hostapd_chan_status {
+ HOSTAPD_CHAN_VALID = 0, /* channel is ready */
+ HOSTAPD_CHAN_INVALID = 1, /* no usable channel found */
+ HOSTAPD_CHAN_ACS = 2, /* ACS work being performed */
+};
struct hostapd_probereq_cb {
int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
@@ -63,6 +76,25 @@ struct hostapd_frame_info {
int ssi_signal; /* dBm */
};
+enum wps_status {
+ WPS_STATUS_SUCCESS = 1,
+ WPS_STATUS_FAILURE
+};
+
+enum pbc_status {
+ WPS_PBC_STATUS_DISABLE,
+ WPS_PBC_STATUS_ACTIVE,
+ WPS_PBC_STATUS_TIMEOUT,
+ WPS_PBC_STATUS_OVERLAP
+};
+
+struct wps_stat {
+ enum wps_status status;
+ enum wps_error_indication failure_reason;
+ enum pbc_status pbc_status;
+ u8 peer_addr[ETH_ALEN];
+};
+
/**
* struct hostapd_data - hostapd per-BSS data structure
@@ -72,6 +104,9 @@ struct hostapd_data {
struct hostapd_config *iconf;
struct hostapd_bss_config *conf;
int interface_added; /* virtual interface added for this BSS */
+ unsigned int started:1;
+ unsigned int disabled:1;
+ unsigned int reenable_beacon:1;
u8 own_addr[ETH_ALEN];
@@ -111,7 +146,7 @@ struct hostapd_data {
struct eapol_authenticator *eapol_auth;
struct rsn_preauth_interface *preauth_iface;
- time_t michael_mic_failure;
+ struct os_reltime michael_mic_failure;
int michael_mic_failures;
int tkip_countermeasures;
@@ -121,6 +156,7 @@ struct hostapd_data {
void *ssl_ctx;
void *eap_sim_db_priv;
struct radius_server_data *radius_srv;
+ struct dl_list erp_keys; /* struct eap_server_erp_key */
int parameter_set_count;
@@ -143,6 +179,8 @@ struct hostapd_data {
unsigned int ap_pin_failures_consecutive;
struct upnp_wps_device_sm *wps_upnp;
unsigned int ap_pin_lockout_time;
+
+ struct wps_stat wps_stats;
#endif /* CONFIG_WPS */
struct hostapd_probereq_cb *probereq_cb;
@@ -151,6 +189,9 @@ struct hostapd_data {
void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
void *public_action_cb_ctx;
+ void (*public_action_cb2)(void *ctx, const u8 *buf, size_t len,
+ int freq);
+ void *public_action_cb2_ctx;
int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
@@ -171,6 +212,22 @@ struct hostapd_data {
void (*setup_complete_cb)(void *ctx);
void *setup_complete_cb_ctx;
+ void (*new_psk_cb)(void *ctx, const u8 *mac_addr,
+ const u8 *p2p_dev_addr, const u8 *psk,
+ size_t psk_len);
+ void *new_psk_cb_ctx;
+
+ /* channel switch parameters */
+ struct hostapd_freq_params cs_freq_params;
+ u8 cs_count;
+ int cs_block_tx;
+ unsigned int cs_c_off_beacon;
+ unsigned int cs_c_off_proberesp;
+ int csa_in_progress;
+
+ /* BSS Load */
+ unsigned int bss_load_update_timeout;
+
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -188,10 +245,34 @@ struct hostapd_data {
#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;
+#endif /* CONFIG_PROXYARP */
+#ifdef CONFIG_MESH
+ int num_plinks;
+ int max_plinks;
+ void (*mesh_sta_free_cb)(struct sta_info *sta);
+ struct wpabuf *mesh_pending_auth;
+ struct os_reltime mesh_pending_auth_time;
+#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
struct hostapd_eap_user tmp_eap_user;
#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_SAE
+ /** Key used for generating SAE anti-clogging tokens */
+ u8 sae_token_key[8];
+ struct os_reltime last_sae_token_key_update;
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ unsigned int ext_mgmt_frame_handling:1;
+ unsigned int ext_eapol_frame_io:1;
+
+ struct l2_packet_data *l2_test;
+#endif /* CONFIG_TESTING_OPTIONS */
};
@@ -203,16 +284,42 @@ struct hostapd_iface {
void *owner;
char *config_fname;
struct hostapd_config *conf;
+ char phy[16]; /* Name of the PHY (radio) */
+
+ enum hostapd_iface_state {
+ HAPD_IFACE_UNINITIALIZED,
+ HAPD_IFACE_DISABLED,
+ HAPD_IFACE_COUNTRY_UPDATE,
+ HAPD_IFACE_ACS,
+ HAPD_IFACE_HT_SCAN,
+ HAPD_IFACE_DFS,
+ HAPD_IFACE_ENABLED
+ } state;
+
+#ifdef CONFIG_MESH
+ struct mesh_conf *mconf;
+#endif /* CONFIG_MESH */
size_t num_bss;
struct hostapd_data **bss;
+ unsigned int wait_channel_update:1;
+ unsigned int cac_started:1;
+
+ /*
+ * When set, indicates that the driver will handle the AP
+ * teardown: delete global keys, station keys, and stations.
+ */
+ unsigned int driver_ap_teardown: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];
- struct ap_info *ap_iter_list;
- unsigned int drv_flags;
+ u64 drv_flags;
+
+ /* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
+ unsigned int smps_modes;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -220,6 +327,12 @@ struct hostapd_iface {
*/
unsigned int probe_resp_offloads;
+ /* extended capabilities supported by the driver */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
+ unsigned int drv_max_acl_mac_addrs;
+
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
@@ -253,11 +366,40 @@ struct hostapd_iface {
/* Number of HT associated stations 20 MHz */
int num_sta_ht_20mhz;
+ /* Number of HT40 intolerant stations */
+ int num_sta_ht40_intolerant;
+
/* Overlapping BSS information */
int olbc_ht;
u16 ht_op_mode;
+
+ /* surveying helpers */
+
+ /* number of channels surveyed */
+ unsigned int chans_surveyed;
+
+ /* lowest observed noise floor in dBm */
+ s8 lowest_nf;
+
+ /* channel utilization calculation */
+ u64 last_channel_time;
+ u64 last_channel_time_busy;
+ u8 channel_utilization;
+
+ unsigned int dfs_cac_ms;
+ struct os_reltime dfs_cac_start;
+
+ /* Latched with the actual secondary channel information and will be
+ * used while juggling between HT20 and HT40 modes. */
+ int secondary_ch;
+
+#ifdef CONFIG_ACS
+ unsigned int acs_num_completed_scans;
+#endif /* CONFIG_ACS */
+
void (*scan_cb)(struct hostapd_iface *iface);
+ int num_ht40_scan_tries;
};
/* hostapd.c */
@@ -273,6 +415,11 @@ int hostapd_setup_interface(struct hostapd_iface *iface);
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
+ const char *config_file);
+struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
@@ -281,6 +428,15 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
+void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
+const char * hostapd_state_text(enum hostapd_iface_state s);
+int hostapd_switch_channel(struct hostapd_data *hapd,
+ struct csa_settings *settings);
+void
+hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ const struct hostapd_freq_params *freq_params);
+void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
@@ -296,11 +452,13 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+ const u8 *addr, int reason_code);
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset);
+ int offset, int width, int cf1, int cf2);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/contrib/wpa/src/ap/hs20.c b/contrib/wpa/src/ap/hs20.c
index 45d518b..d7909fa 100644
--- a/contrib/wpa/src/ap/hs20.c
+++ b/contrib/wpa/src/ap/hs20.c
@@ -1,7 +1,7 @@
/*
* Hotspot 2.0 AP ANQP processing
* Copyright (c) 2009, Atheros Communications, Inc.
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,19 +13,165 @@
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ap_config.h"
+#include "ap_drv_ops.h"
#include "hs20.h"
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
{
+ u8 conf;
if (!hapd->conf->hs20)
return eid;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
- *eid++ = 5;
+ *eid++ = 7;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_INDICATION_OUI_TYPE;
- /* Hotspot Configuration: DGAF Enabled */
- *eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00;
+ conf = HS20_VERSION; /* Release Number */
+ 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;
+
return eid;
}
+
+
+u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *len;
+ u16 capab;
+
+ if (!hapd->conf->osen)
+ return eid;
+
+ *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+ len = eid++; /* to be filled */
+ WPA_PUT_BE24(eid, OUI_WFA);
+ eid += 3;
+ *eid++ = HS20_OSEN_OUI_TYPE;
+
+ /* Group Data Cipher Suite */
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ eid += RSN_SELECTOR_LEN;
+
+ /* Pairwise Cipher Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
+ eid += RSN_SELECTOR_LEN;
+
+ /* AKM Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
+ eid += RSN_SELECTOR_LEN;
+
+ /* RSN Capabilities */
+ capab = 0;
+ if (hapd->conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+#ifdef CONFIG_IEEE80211W
+ if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#endif /* CONFIG_IEEE80211W */
+ WPA_PUT_LE16(eid, capab);
+ eid += 2;
+
+ *len = eid - len - 1;
+
+ return eid;
+}
+
+
+int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
+ u8 osu_method, const char *url)
+{
+ struct wpabuf *buf;
+ size_t len = 0;
+ int ret;
+
+ /* TODO: should refuse to send notification if the STA is not associated
+ * or if the STA did not indicate support for WNM-Notification */
+
+ if (url) {
+ len = 1 + os_strlen(url);
+ if (5 + len > 255) {
+ wpa_printf(MSG_INFO, "HS 2.0: Too long URL for "
+ "WNM-Notification: '%s'", url);
+ return -1;
+ }
+ }
+
+ buf = wpabuf_alloc(4 + 7 + len);
+ if (buf == NULL)
+ 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 */
+
+ /* Subscription Remediation subelement */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 5 + len);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_WNM_SUB_REM_NEEDED);
+ if (url) {
+ wpabuf_put_u8(buf, len - 1);
+ wpabuf_put_data(buf, url, len - 1);
+ wpabuf_put_u8(buf, osu_method);
+ } else {
+ /* Server URL and Server Method fields not included */
+ wpabuf_put_u8(buf, 0);
+ }
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
+ const u8 *addr,
+ const struct wpabuf *payload)
+{
+ struct wpabuf *buf;
+ int ret;
+
+ /* TODO: should refuse to send notification if the STA is not associated
+ * or if the STA did not indicate support for WNM-Notification */
+
+ buf = wpabuf_alloc(4 + 6 + wpabuf_len(payload));
+ if (buf == NULL)
+ 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 */
+
+ /* Deauthentication Imminent Notice subelement */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + wpabuf_len(payload));
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_WNM_DEAUTH_IMMINENT_NOTICE);
+ wpabuf_put_buf(buf, payload);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+
+ return ret;
+}
diff --git a/contrib/wpa/src/ap/hs20.h b/contrib/wpa/src/ap/hs20.h
index 98698ce..152439f 100644
--- a/contrib/wpa/src/ap/hs20.h
+++ b/contrib/wpa/src/ap/hs20.h
@@ -1,6 +1,6 @@
/*
* Hotspot 2.0 AP ANQP processing
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,5 +12,11 @@
struct hostapd_data;
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid);
+int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
+ u8 osu_method, const char *url);
+int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
+ const u8 *addr,
+ const struct wpabuf *payload);
#endif /* HS20_H */
diff --git a/contrib/wpa/src/ap/hw_features.c b/contrib/wpa/src/ap/hw_features.c
index 923b698..05431d3 100644
--- a/contrib/wpa/src/ap/hw_features.c
+++ b/contrib/wpa/src/ap/hw_features.c
@@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -20,10 +14,14 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
+#include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "acs.h"
+#include "ieee802_11.h"
+#include "beacon.h"
#include "hw_features.h"
@@ -44,10 +42,40 @@ void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
}
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static char * dfs_info(struct hostapd_channel_data *chan)
+{
+ static char info[256];
+ char *state;
+
+ switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
+ case HOSTAPD_CHAN_DFS_UNKNOWN:
+ state = "unknown";
+ break;
+ case HOSTAPD_CHAN_DFS_USABLE:
+ state = "usable";
+ break;
+ case HOSTAPD_CHAN_DFS_UNAVAILABLE:
+ state = "unavailable";
+ break;
+ case HOSTAPD_CHAN_DFS_AVAILABLE:
+ state = "available";
+ break;
+ default:
+ return "";
+ }
+ os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
+ info[sizeof(info) - 1] = '\0';
+
+ return info;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
int hostapd_get_hw_features(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
- int ret = 0, i, j;
+ int i, j;
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
@@ -70,34 +98,47 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
for (i = 0; i < num_modes; i++) {
struct hostapd_hw_modes *feature = &modes[i];
+ int dfs_enabled = hapd->iconf->ieee80211h &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
+
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
+ int dfs = 0;
+
/*
* Disable all channels that are marked not to allow
- * IBSS operation or active scanning. In addition,
- * disable all channels that require radar detection,
- * since that (in addition to full DFS) is not yet
- * supported.
+ * to initiate radiation (a.k.a. passive scan and no
+ * IBSS).
+ * Use radar channels only if the driver supports DFS.
*/
- if (feature->channels[j].flag &
- (HOSTAPD_CHAN_NO_IBSS |
- HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_RADAR))
+ if ((feature->channels[j].flag &
+ HOSTAPD_CHAN_RADAR) && dfs_enabled) {
+ dfs = 1;
+ } else if (((feature->channels[j].flag &
+ HOSTAPD_CHAN_RADAR) &&
+ !(iface->drv_flags &
+ WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
+ (feature->channels[j].flag &
+ HOSTAPD_CHAN_NO_IR)) {
feature->channels[j].flag |=
HOSTAPD_CHAN_DISABLED;
+ }
+
if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
+
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
- "chan=%d freq=%d MHz max_tx_power=%d dBm",
+ "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
feature->mode,
feature->channels[j].chan,
feature->channels[j].freq,
- feature->channels[j].max_tx_power);
+ feature->channels[j].max_tx_power,
+ dfs ? dfs_info(&feature->channels[j]) : "");
}
}
- return ret;
+ return 0;
}
@@ -183,66 +224,16 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
- int sec_chan, ok, j, first;
- int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
- size_t k;
+ int pri_chan, sec_chan;
if (!iface->conf->secondary_channel)
return 1; /* HT40 not used */
- sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
- wpa_printf(MSG_DEBUG, "HT40: control channel: %d "
- "secondary channel: %d",
- iface->conf->channel, sec_chan);
-
- /* Verify that HT40 secondary channel is an allowed 20 MHz
- * channel */
- ok = 0;
- for (j = 0; j < iface->current_mode->num_channels; j++) {
- struct hostapd_channel_data *chan =
- &iface->current_mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- chan->chan == sec_chan) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
- wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
- sec_chan);
- return 0;
- }
-
- /*
- * Verify that HT40 primary,secondary channel pair is allowed per
- * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
- * 2.4 GHz rules allow all cases where the secondary channel fits into
- * the list of allowed channels (already checked above).
- */
- if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
- return 1;
-
- if (iface->conf->secondary_channel > 0)
- first = iface->conf->channel;
- else
- first = sec_chan;
-
- ok = 0;
- for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
- if (first == allowed[k]) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
- wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
- iface->conf->channel,
- iface->conf->secondary_channel);
- return 0;
- }
+ pri_chan = iface->conf->channel;
+ sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- return 1;
+ return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
+ sec_chan);
}
@@ -258,158 +249,34 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
}
-static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
- int *pri_chan, int *sec_chan)
-{
- struct ieee80211_ht_operation *oper;
- struct ieee802_11_elems elems;
-
- *pri_chan = *sec_chan = 0;
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
- if (elems.ht_operation &&
- elems.ht_operation_len >= sizeof(*oper)) {
- oper = (struct ieee80211_ht_operation *) elems.ht_operation;
- *pri_chan = oper->control_chan;
- if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
- int sec = oper->ht_param &
- HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
- if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
- *sec_chan = *pri_chan + 4;
- else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
- *sec_chan = *pri_chan - 4;
- }
- }
-}
-
-
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
- int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
- int bss_pri_chan, bss_sec_chan;
- size_t i;
- int match;
+ int pri_chan, sec_chan;
+ int res;
pri_chan = iface->conf->channel;
- sec_chan = iface->conf->secondary_channel * 4;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
- if (iface->conf->secondary_channel > 0)
- sec_freq = pri_freq + 20;
- else
- sec_freq = pri_freq - 20;
+ sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- /*
- * Switch PRI/SEC channels if Beacons were detected on selected SEC
- * channel, but not on selected PRI channel.
- */
- pri_bss = sec_bss = 0;
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- if (bss->freq == pri_freq)
- pri_bss++;
- else if (bss->freq == sec_freq)
- sec_bss++;
- }
- if (sec_bss && !pri_bss) {
- wpa_printf(MSG_INFO, "Switch own primary and secondary "
- "channel to get secondary channel with no Beacons "
- "from other BSSes");
- ieee80211n_switch_pri_sec(iface);
- }
+ res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
- /*
- * Match PRI/SEC channel with any existing HT40 BSS on the same
- * channels that we are about to use (if already mixed order in
- * existing BSSes, use own preference).
- */
- match = 0;
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
- if (pri_chan == bss_pri_chan &&
- sec_chan == bss_sec_chan) {
- match = 1;
- break;
- }
- }
- if (!match) {
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
- &bss_sec_chan);
- if (pri_chan == bss_sec_chan &&
- sec_chan == bss_pri_chan) {
- wpa_printf(MSG_INFO, "Switch own primary and "
- "secondary channel due to BSS "
- "overlap with " MACSTR,
- MAC2STR(bss->bssid));
- ieee80211n_switch_pri_sec(iface);
- break;
- }
- }
- }
+ if (res == 2)
+ ieee80211n_switch_pri_sec(iface);
- return 1;
+ return !!res;
}
static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
- int pri_freq, sec_freq;
- int affected_start, affected_end;
- size_t i;
+ int pri_chan, sec_chan;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
- if (iface->conf->secondary_channel > 0)
- sec_freq = pri_freq + 20;
- else
- sec_freq = pri_freq - 20;
- affected_start = (pri_freq + sec_freq) / 2 - 25;
- affected_end = (pri_freq + sec_freq) / 2 + 25;
- wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
- affected_start, affected_end);
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- int pri = bss->freq;
- int sec = pri;
- int sec_chan, pri_chan;
-
- ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
-
- if (sec_chan) {
- if (sec_chan < pri_chan)
- sec = pri - 20;
- else
- sec = pri + 20;
- }
-
- if ((pri < affected_start || pri > affected_end) &&
- (sec < affected_start || sec > affected_end))
- continue; /* not within affected channel range */
-
- wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
- " freq=%d pri=%d sec=%d",
- MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
-
- if (sec_chan) {
- if (pri_freq != pri || sec_freq != sec) {
- wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
- "mismatch with BSS " MACSTR
- " <%d,%d> (chan=%d%c) vs. <%d,%d>",
- MAC2STR(bss->bssid),
- pri, sec, pri_chan,
- sec > pri ? '+' : '-',
- pri_freq, sec_freq);
- return 0;
- }
- }
-
- /* TODO: 40 MHz intolerant */
- }
+ pri_chan = iface->conf->channel;
+ sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- return 1;
+ return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan,
+ sec_chan);
}
@@ -436,6 +303,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
wpa_scan_results_free(scan_res);
+ iface->secondary_ch = iface->conf->secondary_channel;
if (!oper40) {
wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
"channel pri=%d sec=%d based on overlapping BSSes",
@@ -443,10 +311,21 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
iface->conf->channel +
iface->conf->secondary_channel * 4);
iface->conf->secondary_channel = 0;
- iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) {
+ /*
+ * TODO: Could consider scheduling another scan to check
+ * if channel width can be changed if no coex reports
+ * are received from associating stations.
+ */
+ }
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
+ if (!res) {
+ iface->conf->secondary_channel = 0;
+ wpa_printf(MSG_INFO, "Fallback to 20 MHz");
+ }
+
hostapd_setup_interface_complete(iface, !res);
}
@@ -491,25 +370,128 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
}
+static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
+ struct wpa_driver_scan_params *params)
+{
+ /* Scan only the affected frequency range */
+ int pri_freq;
+ int affected_start, affected_end;
+ int i, pos;
+ struct hostapd_hw_modes *mode;
+
+ if (iface->current_mode == NULL)
+ return;
+
+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ if (iface->conf->secondary_channel > 0) {
+ affected_start = pri_freq - 10;
+ affected_end = pri_freq + 30;
+ } else {
+ affected_start = pri_freq - 30;
+ affected_end = pri_freq + 10;
+ }
+ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+
+ mode = iface->current_mode;
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ pos = 0;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ if (chan->freq < affected_start ||
+ chan->freq > affected_end)
+ continue;
+ params->freqs[pos++] = chan->freq;
+ }
+}
+
+
+static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
+{
+#define HT2040_COEX_SCAN_RETRY 15
+ struct hostapd_iface *iface = eloop_data;
+ struct wpa_driver_scan_params params;
+ int ret;
+
+ os_memset(&params, 0, sizeof(params));
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ ieee80211n_scan_channels_2g4(iface, &params);
+ else
+ ieee80211n_scan_channels_5g(iface, &params);
+
+ ret = hostapd_driver_scan(iface->bss[0], &params);
+ iface->num_ht40_scan_tries++;
+ os_free(params.freqs);
+
+ if (ret == -EBUSY &&
+ iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
+ ret, strerror(-ret), iface->num_ht40_scan_tries);
+ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+ return;
+ }
+
+ if (ret == 0) {
+ iface->scan_cb = ieee80211n_check_scan;
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "Failed to request a scan in device, bringing up in HT20 mode");
+ iface->conf->secondary_channel = 0;
+ iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ hostapd_setup_interface_complete(iface, 0);
+}
+
+
+void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+}
+
+
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 */
+ hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
"40 MHz channel");
os_memset(&params, 0, sizeof(params));
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
ieee80211n_scan_channels_2g4(iface, &params);
- if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
- wpa_printf(MSG_ERROR, "Failed to request a scan of "
- "neighboring BSSes");
- os_free(params.freqs);
+ else
+ ieee80211n_scan_channels_5g(iface, &params);
+
+ ret = hostapd_driver_scan(iface->bss[0], &params);
+ os_free(params.freqs);
+
+ if (ret == -EBUSY) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
+ ret, strerror(-ret));
+ iface->num_ht40_scan_tries = 1;
+ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+ return 1;
+ }
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s)",
+ ret, strerror(-ret));
return -1;
}
- os_free(params.freqs);
iface->scan_cb = ieee80211n_check_scan;
return 1;
@@ -535,11 +517,24 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
- if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
- (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
- wpa_printf(MSG_ERROR, "Driver does not support configured "
- "HT capability [SMPS-*]");
- return 0;
+ switch (conf & HT_CAP_INFO_SMPS_MASK) {
+ case HT_CAP_INFO_SMPS_STATIC:
+ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
+ wpa_printf(MSG_ERROR,
+ "Driver does not support configured HT capability [SMPS-STATIC]");
+ return 0;
+ }
+ break;
+ case HT_CAP_INFO_SMPS_DYNAMIC:
+ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
+ wpa_printf(MSG_ERROR,
+ "Driver does not support configured HT capability [SMPS-DYNAMIC]");
+ return 0;
+ }
+ break;
+ case HT_CAP_INFO_SMPS_DISABLED:
+ default:
+ break;
}
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
@@ -597,12 +592,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
- if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
- wpa_printf(MSG_ERROR, "Driver does not support configured "
- "HT capability [PSMP]");
- return 0;
- }
-
if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
!(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@@ -613,6 +602,112 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 1;
}
+
+#ifdef CONFIG_IEEE80211AC
+
+static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
+{
+ u32 req_cap = conf & cap;
+
+ /*
+ * Make sure we support all requested capabilities.
+ * NOTE: We assume that 'cap' represents a capability mask,
+ * not a discrete value.
+ */
+ if ((hw & req_cap) != req_cap) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
+ name);
+ return 0;
+ }
+ return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 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;
+ u32 hw = mode->vht_capab;
+ u32 conf = iface->conf->vht_capab;
+
+ wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
+ hw, conf);
+
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ iface->conf->bss[0]->vendor_vht &&
+ mode->vht_capab == 0 && iface->hw_features) {
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &iface->hw_features[i];
+ hw = mode->vht_capab;
+ wpa_printf(MSG_DEBUG,
+ "update hw vht capab based on 5 GHz band: 0x%x",
+ hw);
+ break;
+ }
+ }
+ }
+
+#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;
+}
+#endif /* CONFIG_IEEE80211AC */
+
#endif /* CONFIG_IEEE80211N */
@@ -624,6 +719,10 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
if (!ieee80211n_supported_ht_capab(iface))
return -1;
+#ifdef CONFIG_IEEE80211AC
+ if (!ieee80211ac_supported_vht_capab(iface))
+ return -1;
+#endif /* CONFIG_IEEE80211AC */
ret = ieee80211n_check_40mhz(iface);
if (ret)
return ret;
@@ -635,6 +734,129 @@ 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;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+ if (chan->chan != channel)
+ continue;
+
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
+ return 1;
+
+ wpa_printf(MSG_DEBUG,
+ "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
+ primary ? "" : "Configured HT40 secondary ",
+ i, chan->chan, 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)
+{
+ if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
+ return 0;
+
+ if (!iface->conf->secondary_channel)
+ return 1;
+
+ return hostapd_is_usable_chan(iface, iface->conf->channel +
+ iface->conf->secondary_channel * 4, 0);
+}
+
+
+static enum hostapd_chan_status
+hostapd_check_chans(struct hostapd_iface *iface)
+{
+ if (iface->conf->channel) {
+ if (hostapd_is_usable_chans(iface))
+ return HOSTAPD_CHAN_VALID;
+ else
+ return HOSTAPD_CHAN_INVALID;
+ }
+
+ /*
+ * The user set channel=0 or channel=acs_survey
+ * which is used to trigger ACS.
+ */
+
+ switch (acs_init(iface)) {
+ case HOSTAPD_CHAN_ACS:
+ return HOSTAPD_CHAN_ACS;
+ case HOSTAPD_CHAN_VALID:
+ case HOSTAPD_CHAN_INVALID:
+ default:
+ return HOSTAPD_CHAN_INVALID;
+ }
+}
+
+
+static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
+{
+ hostapd_logger(iface->bss[0], NULL,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Configured channel (%d) not found from the "
+ "channel list of current mode (%d) %s",
+ iface->conf->channel,
+ iface->current_mode->mode,
+ hostapd_hw_mode_txt(iface->current_mode->mode));
+ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Hardware does not support configured channel");
+}
+
+
+int hostapd_acs_completed(struct hostapd_iface *iface, int err)
+{
+ int ret = -1;
+
+ if (err)
+ goto out;
+
+ switch (hostapd_check_chans(iface)) {
+ case HOSTAPD_CHAN_VALID:
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
+ ACS_EVENT_COMPLETED "freq=%d channel=%d",
+ hostapd_hw_get_freq(iface->bss[0],
+ iface->conf->channel),
+ iface->conf->channel);
+ break;
+ case HOSTAPD_CHAN_ACS:
+ wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
+ hostapd_notify_bad_chans(iface);
+ goto out;
+ case HOSTAPD_CHAN_INVALID:
+ default:
+ wpa_printf(MSG_ERROR, "ACS picked unusable channels");
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
+ hostapd_notify_bad_chans(iface);
+ goto out;
+ }
+
+ ret = hostapd_check_ht_capab(iface);
+ if (ret < 0)
+ goto out;
+ if (ret == 1) {
+ wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
+ return 0;
+ }
+
+ ret = 0;
+out:
+ return hostapd_setup_interface_complete(iface, ret);
+}
+
+
/**
* hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data.
@@ -645,11 +867,20 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
*/
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
- int i, j, ok;
+ int i;
if (iface->num_hw_features < 1)
return -1;
+ if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
+ iface->conf->channel == 14) {
+ wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
+ iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ iface->conf->ieee80211n = 0;
+ iface->conf->ieee80211ac = 0;
+ }
+
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
@@ -670,82 +901,16 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
return -2;
}
- ok = 0;
- for (j = 0; j < iface->current_mode->num_channels; j++) {
- struct hostapd_channel_data *chan =
- &iface->current_mode->channels[j];
- if (chan->chan == iface->conf->channel) {
- if (chan->flag & HOSTAPD_CHAN_DISABLED) {
- wpa_printf(MSG_ERROR,
- "channel [%i] (%i) is disabled for "
- "use in AP mode, flags: 0x%x%s%s%s",
- j, chan->chan, chan->flag,
- chan->flag & HOSTAPD_CHAN_NO_IBSS ?
- " NO-IBSS" : "",
- chan->flag &
- HOSTAPD_CHAN_PASSIVE_SCAN ?
- " PASSIVE-SCAN" : "",
- chan->flag & HOSTAPD_CHAN_RADAR ?
- " RADAR" : "");
- } else {
- ok = 1;
- break;
- }
- }
- }
- if (ok && iface->conf->secondary_channel) {
- int sec_ok = 0;
- int sec_chan = iface->conf->channel +
- iface->conf->secondary_channel * 4;
- for (j = 0; j < iface->current_mode->num_channels; j++) {
- struct hostapd_channel_data *chan =
- &iface->current_mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- (chan->chan == sec_chan)) {
- sec_ok = 1;
- break;
- }
- }
- if (!sec_ok) {
- hostapd_logger(iface->bss[0], NULL,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING,
- "Configured HT40 secondary channel "
- "(%d) not found from the channel list "
- "of current mode (%d) %s",
- sec_chan, iface->current_mode->mode,
- hostapd_hw_mode_txt(
- iface->current_mode->mode));
- ok = 0;
- }
- }
- if (iface->conf->channel == 0) {
- /* TODO: could request a scan of neighboring BSSes and select
- * the channel automatically */
- wpa_printf(MSG_ERROR, "Channel not configured "
- "(hw_mode/channel in hostapd.conf)");
+ switch (hostapd_check_chans(iface)) {
+ case HOSTAPD_CHAN_VALID:
+ return 0;
+ case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
+ return 1;
+ case HOSTAPD_CHAN_INVALID:
+ default:
+ hostapd_notify_bad_chans(iface);
return -3;
}
- if (ok == 0 && iface->conf->channel != 0) {
- hostapd_logger(iface->bss[0], NULL,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING,
- "Configured channel (%d) not found from the "
- "channel list of current mode (%d) %s",
- iface->conf->channel,
- iface->current_mode->mode,
- hostapd_hw_mode_txt(iface->current_mode->mode));
- iface->current_mode = NULL;
- }
-
- if (iface->current_mode == NULL) {
- hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING,
- "Hardware does not support configured channel");
- return -4;
- }
-
- return 0;
}
@@ -768,35 +933,11 @@ const char * hostapd_hw_mode_txt(int mode)
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
{
- int i;
-
- if (!hapd->iface->current_mode)
- return 0;
-
- for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
- struct hostapd_channel_data *ch =
- &hapd->iface->current_mode->channels[i];
- if (ch->chan == chan)
- return ch->freq;
- }
-
- return 0;
+ return hw_get_freq(hapd->iface->current_mode, chan);
}
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
{
- int i;
-
- if (!hapd->iface->current_mode)
- return 0;
-
- for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
- struct hostapd_channel_data *ch =
- &hapd->iface->current_mode->channels[i];
- if (ch->freq == freq)
- return ch->chan;
- }
-
- return 0;
+ return hw_get_chan(hapd->iface->current_mode, freq);
}
diff --git a/contrib/wpa/src/ap/hw_features.h b/contrib/wpa/src/ap/hw_features.h
index abadcd1..0f67ab8 100644
--- a/contrib/wpa/src/ap/hw_features.h
+++ b/contrib/wpa/src/ap/hw_features.h
@@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef HW_FEATURES_H
@@ -21,6 +15,7 @@
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features);
int hostapd_get_hw_features(struct hostapd_iface *iface);
+int hostapd_acs_completed(struct hostapd_iface *iface, int err);
int hostapd_select_hw_mode(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
@@ -28,6 +23,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
+void hostapd_stop_setup_timers(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -66,6 +62,10 @@ static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
return 0;
}
+static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/contrib/wpa/src/ap/iapp.c b/contrib/wpa/src/ap/iapp.c
index be55c69..99aa04d 100644
--- a/contrib/wpa/src/ap/iapp.c
+++ b/contrib/wpa/src/ap/iapp.c
@@ -204,7 +204,7 @@ static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
addr.sin_port = htons(IAPP_UDP_PORT);
if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
(struct sockaddr *) &addr, sizeof(addr)) < 0)
- perror("sendto[IAPP-ADD]");
+ wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
}
@@ -231,7 +231,7 @@ static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
* FIX: what is correct RW with 802.11? */
if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
- perror("send[L2 Update]");
+ wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
}
@@ -242,29 +242,22 @@ static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
*/
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
{
- struct ieee80211_mgmt *assoc;
- u16 seq;
+ u16 seq = 0; /* TODO */
if (iapp == NULL)
return;
- assoc = sta->last_assoc_req;
- seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
-
/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
iapp_send_layer2_update(iapp, sta->addr);
iapp_send_add(iapp, sta->addr, seq);
- if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
- WLAN_FC_STYPE_REASSOC_REQ) {
- /* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
- * Context Block, Timeout)
- */
- /* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
- * IP address */
- }
+ /* TODO: If this was reassociation:
+ * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
+ * Context Block, Timeout)
+ * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
+ * IP address */
}
@@ -276,8 +269,8 @@ static void iapp_process_add_notify(struct iapp_data *iapp,
struct sta_info *sta;
if (len != sizeof(*add)) {
- printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
- len, (unsigned long) sizeof(*add));
+ wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
+ len, (unsigned long) sizeof(*add));
return;
}
@@ -326,7 +319,8 @@ static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
(struct sockaddr *) &from, &fromlen);
if (len < 0) {
- perror("recvfrom");
+ wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
+ strerror(errno));
return;
}
@@ -350,23 +344,24 @@ static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
hdr->version, hdr->command,
be_to_host16(hdr->identifier), hlen);
if (hdr->version != IAPP_VERSION) {
- printf("Dropping IAPP frame with unknown version %d\n",
- hdr->version);
+ wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
+ hdr->version);
return;
}
if (hlen > len) {
- printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+ wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
+ hlen, len);
return;
}
if (hlen < len) {
- printf("Ignoring %d extra bytes from IAPP frame\n",
- len - hlen);
+ wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
+ len - hlen);
len = hlen;
}
switch (hdr->command) {
case IAPP_CMD_ADD_notify:
- iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
+ iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
break;
case IAPP_CMD_MOVE_notify:
/* TODO: MOVE is using TCP; so move this to TCP handler once it
@@ -376,7 +371,7 @@ static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
/* TODO: process */
break;
default:
- printf("Unknown IAPP command %d\n", hdr->command);
+ wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
break;
}
}
@@ -403,7 +398,8 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (iapp->udp_sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@@ -411,35 +407,38 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
- perror("ioctl(SIOCGIFINDEX)");
+ wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
ifindex = ifr.ifr_ifindex;
if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
- perror("ioctl(SIOCGIFADDR)");
+ wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
- printf("Invalid address family %i (SIOCGIFADDR)\n",
- paddr->sin_family);
+ wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
+ paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
iapp->own.s_addr = paddr->sin_addr.s_addr;
if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
- perror("ioctl(SIOCGIFBRDADDR)");
+ wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
- printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
- paddr->sin_family);
+ wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
+ paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
@@ -450,7 +449,8 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
uaddr.sin_port = htons(IAPP_UDP_PORT);
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
- perror("bind[UDP]");
+ wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@@ -461,14 +461,16 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0) {
- perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+ wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (iapp->packet_sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@@ -478,19 +480,20 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
addr.sll_ifindex = ifindex;
if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind[PACKET]");
+ wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
+ strerror(errno));
iapp_deinit(iapp);
return NULL;
}
if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
iapp, NULL)) {
- printf("Could not register read socket for IAPP.\n");
+ wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
iapp_deinit(iapp);
return NULL;
}
- printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+ wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
* RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
@@ -515,7 +518,8 @@ void iapp_deinit(struct iapp_data *iapp)
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
- perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+ wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
+ strerror(errno));
}
eloop_unregister_read_sock(iapp->udp_sock);
diff --git a/contrib/wpa/src/ap/ieee802_11.c b/contrib/wpa/src/ap/ieee802_11.c
index 51c8d28..89911b1 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, 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 "utils/common.h"
#include "utils/eloop.h"
#include "crypto/crypto.h"
-#include "drivers/driver.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -27,6 +29,7 @@
#include "sta_info.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
+#include "pmksa_cache_auth.h"
#include "wmm.h"
#include "ap_list.h"
#include "accounting.h"
@@ -36,6 +39,7 @@
#include "ap_drv_ops.h"
#include "wnm_ap.h"
#include "ieee802_11.h"
+#include "dfs.h"
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -59,7 +63,6 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
}
*pos++ = num;
- count = 0;
for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
i++) {
count++;
@@ -102,7 +105,6 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = num;
- count = 0;
for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
i++) {
count++;
@@ -135,6 +137,15 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
{
int capab = WLAN_CAPABILITY_ESS;
int privacy;
+ int dfs;
+
+ /* Check if any of configured channels require DFS */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0) {
+ wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
+ dfs);
+ dfs = 0;
+ }
if (hapd->iface->num_sta_no_short_preamble == 0 &&
hapd->iconf->preamble == SHORT_PREAMBLE)
@@ -150,6 +161,11 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->wpa)
privacy = 1;
+#ifdef CONFIG_HS20
+ if (hapd->conf->osen)
+ privacy = 1;
+#endif /* CONFIG_HS20 */
+
if (sta) {
int policy, def_klen;
if (probe && sta->ssid_probe) {
@@ -172,22 +188,21 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
hapd->iface->num_sta_no_short_slot_time == 0)
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
- return capab;
-}
+ /*
+ * Currently, Spectrum Management capability bit is set when directly
+ * requested in configuration by spectrum_mgmt_required or when AP is
+ * running on DFS channel.
+ * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit
+ */
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ (hapd->iconf->spectrum_mgmt_required || dfs))
+ capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+ if (hapd->conf->radio_measurements)
+ capab |= IEEE80211_CAP_RRM;
-void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
-{
- int i;
- if (len > HOSTAPD_MAX_SSID_LEN)
- len = HOSTAPD_MAX_SSID_LEN;
- for (i = 0; i < len; i++) {
- if (ssid[i] >= 32 && ssid[i] < 127)
- buf[i] = ssid[i];
- else
- buf[i] = '.';
- }
- buf[len] = '\0';
+ return capab;
}
@@ -225,7 +240,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
/* Transaction 3 */
if (!iswep || !sta->challenge || !challenge ||
- os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) {
+ os_memcmp_const(sta->challenge, challenge,
+ WLAN_AUTH_CHALLENGE_LEN)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"shared key authentication - invalid "
@@ -236,13 +252,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"authentication OK (shared key)");
-#ifdef IEEE80211_REQUIRE_AUTH_ACK
- /* Station will be marked authenticated if it ACKs the
- * authentication reply. */
-#else
sta->flags |= WLAN_STA_AUTH;
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
-#endif
os_free(sta->challenge);
sta->challenge = NULL;
@@ -283,7 +294,7 @@ static void send_auth_reply(struct hostapd_data *hapd,
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len);
if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
- perror("send_auth_reply: send");
+ wpa_printf(MSG_INFO, "send_auth_reply: send");
os_free(buf);
}
@@ -317,19 +328,34 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
#ifdef CONFIG_SAE
+#define dot11RSNASAERetransPeriod 40 /* msec */
+#define dot11RSNASAESync 5 /* attempts */
+
+
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta)
+ struct sta_info *sta, int update)
{
struct wpabuf *buf;
- buf = wpabuf_alloc(2);
- if (buf == NULL)
+ if (hapd->conf->ssid.wpa_passphrase == NULL) {
+ 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),
+ sta->sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+ return NULL;
+ }
- wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
- /* TODO: Anti-Clogging Token (if requested) */
- /* TODO: Scalar */
- /* TODO: Element */
+ buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
+ if (buf == NULL)
+ return NULL;
+ sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+ sta->sae->tmp->anti_clogging_token : NULL);
return buf;
}
@@ -340,114 +366,517 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
{
struct wpabuf *buf;
- buf = wpabuf_alloc(2);
+ buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
if (buf == NULL)
return NULL;
- wpabuf_put_le16(buf, sta->sae_send_confirm);
- sta->sae_send_confirm++;
- /* TODO: Confirm */
+ sae_write_confirm(sta->sae, buf);
return buf;
}
-static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *data, size_t len)
+static int auth_sae_send_commit(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *bssid, int update)
{
- wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len);
+ struct wpabuf *data;
- /* Check Finite Cyclic Group */
- if (len < 2)
+ data = auth_build_sae_commit(hapd, sta, update);
+ if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (WPA_GET_LE16(data) != 19) {
- wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
- WPA_GET_LE16(data));
- return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
- }
+
+ send_auth_reply(hapd, sta->addr, bssid,
+ WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS,
+ wpabuf_head(data), wpabuf_len(data));
+
+ wpabuf_free(data);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static int auth_sae_send_confirm(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *bssid)
+{
+ struct wpabuf *data;
+
+ 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));
+
+ wpabuf_free(data);
return WLAN_STATUS_SUCCESS;
}
-static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *data, size_t len)
+static int use_sae_anti_clogging(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ unsigned int open = 0;
+
+ if (hapd->conf->sae_anti_clogging_threshold == 0)
+ return 1;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->sae)
+ continue;
+ if (sta->sae->state != SAE_COMMITTED &&
+ sta->sae->state != SAE_CONFIRMED)
+ continue;
+ open++;
+ if (open >= hapd->conf->sae_anti_clogging_threshold)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *token, size_t token_len)
+{
+ u8 mac[SHA256_MAC_LEN];
+
+ if (token_len != SHA256_MAC_LEN)
+ return -1;
+ if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, mac) < 0 ||
+ os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
+ int group, const u8 *addr)
+{
+ struct wpabuf *buf;
+ u8 *token;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
+ os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
+ if (random_get_bytes(hapd->sae_token_key,
+ sizeof(hapd->sae_token_key)) < 0)
+ return NULL;
+ wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
+ hapd->sae_token_key, sizeof(hapd->sae_token_key));
+ hapd->last_sae_token_key_update = now;
+ }
+
+ buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+
+ token = wpabuf_put(buf, SHA256_MAC_LEN);
+ hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, token);
+
+ return buf;
+}
+
+
+static int sae_check_big_sync(struct sta_info *sta)
+{
+ if (sta->sae->sync > dot11RSNASAESync) {
+ sta->sae->state = SAE_NOTHING;
+ sta->sae->sync = 0;
+ return -1;
+ }
+ return 0;
+}
+
+
+static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = eloop_data;
+ int ret;
+
+ if (sae_check_big_sync(sta))
+ return;
+ sta->sae->sync++;
+
+ switch (sta->sae->state) {
+ case SAE_COMMITTED:
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+ break;
+ case SAE_CONFIRMED:
+ ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ if (ret != WLAN_STATUS_SUCCESS)
+ wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
+}
+
+
+void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+}
+
+
+static void sae_set_retransmit_timer(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
- u16 rc;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ return;
+
+ eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+}
- wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len);
- if (len < 2)
+static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *bssid, u8 auth_transaction)
+{
+ int ret;
+
+ if (auth_transaction != 1 && auth_transaction != 2)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- rc = WPA_GET_LE16(data);
- wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+ switch (sta->sae->state) {
+ case SAE_NOTHING:
+ if (auth_transaction == 1) {
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+ sta->sae->state = SAE_COMMITTED;
+
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ /*
+ * In mesh case, both Commit and Confirm can be sent
+ * immediately. In infrastructure BSS, only a single
+ * Authentication frame (Commit) is expected from the AP
+ * here and the second one (Confirm) will be sent once
+ * the STA has sent its second Authentication frame
+ * (Confirm).
+ */
+ if (hapd->conf->mesh & MESH_ENABLED) {
+ /*
+ * Send both Commit and Confirm immediately
+ * based on SAE finite state machine
+ * Nothing -> Confirm transition.
+ */
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+ sta->sae->state = SAE_CONFIRMED;
+ } 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
+ * when receiving Confirm from STA.
+ */
+ }
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "SAE confirm before commit");
+ }
+ break;
+ case SAE_COMMITTED:
+ sae_clear_retransmit_timer(hapd, sta);
+ if (auth_transaction == 1) {
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+ sta->sae->state = SAE_CONFIRMED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+ } else if (hapd->conf->mesh & MESH_ENABLED) {
+ /*
+ * In mesh case, follow SAE finite state machine and
+ * send Commit now, if sync count allows.
+ */
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+
+ sae_set_retransmit_timer(hapd, sta);
+ } else {
+ /*
+ * For instructure BSS, send the postponed Confirm from
+ * Nothing -> Confirmed transition that was reduced to
+ * Nothing -> Committed above.
+ */
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+
+ sta->sae->state = SAE_CONFIRMED;
+
+ /*
+ * 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);
+ }
+ break;
+ case SAE_CONFIRMED:
+ sae_clear_retransmit_timer(hapd, sta);
+ if (auth_transaction == 1) {
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+
+ 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);
+ }
+ break;
+ case SAE_ACCEPTED:
+ if (auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
+ ") doing reauthentication",
+ MAC2STR(sta->addr));
+ ap_free_sta(hapd, sta);
+ } else {
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ sae_clear_temp_data(sta->sae);
+ if (ret)
+ return ret;
+ }
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "SAE: invalid state %d",
+ sta->sae->state);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
return WLAN_STATUS_SUCCESS;
}
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
- u8 auth_transaction)
+ u16 auth_transaction, u16 status_code)
{
u16 resp = WLAN_STATUS_SUCCESS;
- struct wpabuf *data;
+ struct wpabuf *data = NULL;
+
+ if (!sta->sae) {
+ if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
+ return;
+ sta->sae = os_zalloc(sizeof(*sta->sae));
+ if (sta->sae == NULL)
+ return;
+ sta->sae->state = SAE_NOTHING;
+ sta->sae->sync = 0;
+ }
if (auth_transaction == 1) {
+ const u8 *token = NULL, *pos, *end;
+ size_t token_len = 0;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "start SAE authentication (RX commit)");
- resp = handle_sae_commit(hapd, sta, mgmt->u.auth.variable,
- ((u8 *) mgmt) + len -
- mgmt->u.auth.variable);
- if (resp == WLAN_STATUS_SUCCESS)
- sta->sae_state = SAE_COMMIT;
- } else if (auth_transaction == 2) {
- if (sta->sae_state != SAE_COMMIT) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "SAE confirm before commit");
- resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+ "start SAE authentication (RX commit, status=%u)",
+ status_code);
+
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
+ sta->sae->tmp) {
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+ if (pos + sizeof(le16) > end) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Too short anti-clogging token request");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
+ resp = sae_group_allowed(sta->sae,
+ hapd->conf->sae_groups,
+ WPA_GET_LE16(pos));
+ if (resp != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Invalid group in anti-clogging token request");
+ goto reply;
+ }
+ pos += sizeof(le16);
+
+ wpabuf_free(sta->sae->tmp->anti_clogging_token);
+ sta->sae->tmp->anti_clogging_token =
+ wpabuf_alloc_copy(pos, end - pos);
+ if (sta->sae->tmp->anti_clogging_token == NULL) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Failed to alloc for anti-clogging token");
+ return;
+ }
+
+ /*
+ * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
+ * is 76, a new Commit Message shall be constructed
+ * with the Anti-Clogging Token from the received
+ * Authentication frame, and the commit-scalar and
+ * COMMIT-ELEMENT previously sent.
+ */
+ if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Failed to send commit message");
+ return;
+ }
+ sta->sae->state = SAE_COMMITTED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+ return;
}
+
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return;
+
+ resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
+ ((const u8 *) mgmt) + len -
+ mgmt->u.auth.variable, &token,
+ &token_len, hapd->conf->sae_groups);
+ if (token && check_sae_token(hapd, sta->addr, token, token_len)
+ < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
+ "incorrect token from " MACSTR,
+ MAC2STR(sta->addr));
+ return;
+ }
+
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto reply;
+
+ if (!token && use_sae_anti_clogging(hapd)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Request anti-clogging token from "
+ MACSTR, MAC2STR(sta->addr));
+ data = auth_build_token_req(hapd, sta->sae->group,
+ sta->addr);
+ resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
+ if (hapd->conf->mesh & MESH_ENABLED)
+ sta->sae->state = SAE_NOTHING;
+ goto reply;
+ }
+
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+ } else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "SAE authentication (RX confirm)");
- resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable,
- ((u8 *) mgmt) + len -
- mgmt->u.auth.variable);
- if (resp == WLAN_STATUS_SUCCESS) {
- sta->flags |= WLAN_STA_AUTH;
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->auth_alg = WLAN_AUTH_SAE;
- mlme_authenticate_indication(hapd, sta);
+ "SAE authentication (RX confirm, status=%u)",
+ status_code);
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return;
+ 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) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
}
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "unexpected SAE authentication transaction %u",
- auth_transaction);
+ "unexpected SAE authentication transaction %u (status=%u)",
+ auth_transaction, status_code);
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return;
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
}
- sta->auth_alg = WLAN_AUTH_SAE;
+reply:
+ if (resp != WLAN_STATUS_SUCCESS) {
+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ auth_transaction, resp,
+ data ? wpabuf_head(data) : (u8 *) "",
+ data ? wpabuf_len(data) : 0);
+ }
+ wpabuf_free(data);
+}
- if (resp == WLAN_STATUS_SUCCESS) {
- if (auth_transaction == 1)
- data = auth_build_sae_commit(hapd, sta);
- else
- data = auth_build_sae_confirm(hapd, sta);
- if (data == NULL)
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- } else
- data = NULL;
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
- auth_transaction, resp,
- data ? wpabuf_head(data) : (u8 *) "",
- data ? wpabuf_len(data) : 0);
- wpabuf_free(data);
+/**
+ * auth_sae_init_committed - Send COMMIT and start SAE in committed state
+ * @hapd: BSS data for the device initiating the authentication
+ * @sta: the peer to which commit authentication frame is sent
+ *
+ * This function implements Init event handling (IEEE Std 802.11-2012,
+ * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
+ * sta->sae structure should be initialized appropriately via a call to
+ * sae_prepare_commit().
+ */
+int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ int ret;
+
+ if (!sta->sae || !sta->sae->tmp)
+ return -1;
+
+ if (sta->sae->state != SAE_NOTHING)
+ return -1;
+
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ if (ret)
+ return -1;
+
+ sta->sae->state = SAE_COMMITTED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+
+ return 0;
}
+
#endif /* CONFIG_SAE */
@@ -467,17 +896,29 @@ static void handle_auth(struct hostapd_data *hapd,
size_t resp_ies_len = 0;
char *identity = NULL;
char *radius_cui = NULL;
+ u16 seq_ctrl;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- printf("handle_auth - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->iconf->ignore_auth_probability > 0.0 &&
+ drand48() < hapd->iconf->ignore_auth_probability) {
+ wpa_printf(MSG_INFO,
+ "TESTING: ignoring auth frame from " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
status_code = le_to_host16(mgmt->u.auth.status_code);
fc = le_to_host16(mgmt->frame_control);
+ seq_ctrl = le_to_host16(mgmt->seq_ctrl);
if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2 + WLAN_AUTH_CHALLENGE_LEN &&
@@ -486,10 +927,12 @@ static void handle_auth(struct hostapd_data *hapd,
challenge = &mgmt->u.auth.variable[2];
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
- "auth_transaction=%d status_code=%d wep=%d%s",
+ "auth_transaction=%d status_code=%d wep=%d%s "
+ "seq_ctrl=0x%x%s",
MAC2STR(mgmt->sa), auth_alg, auth_transaction,
status_code, !!(fc & WLAN_FC_ISWEP),
- challenge ? " challenge" : "");
+ challenge ? " challenge" : "",
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
@@ -508,23 +951,23 @@ static void handle_auth(struct hostapd_data *hapd,
#endif /* CONFIG_SAE */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
- printf("Unsupported authentication algorithm (%d)\n",
- auth_alg);
+ wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
+ auth_alg);
resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
goto fail;
}
if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
- printf("Unknown authentication transaction number (%d)\n",
- auth_transaction);
+ wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
+ auth_transaction);
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
goto fail;
}
if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
- printf("Station " MACSTR " not allowed to authenticate.\n",
- MAC2STR(mgmt->sa));
+ wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+ MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -535,8 +978,8 @@ static void handle_auth(struct hostapd_data *hapd,
&psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
- printf("Station " MACSTR " not allowed to authenticate.\n",
- MAC2STR(mgmt->sa));
+ wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
+ MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -550,15 +993,49 @@ static void handle_auth(struct hostapd_data *hapd,
return;
}
- sta = ap_sta_add(hapd, mgmt->sa);
- if (!sta) {
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (sta) {
+ if ((fc & WLAN_FC_RETRY) &&
+ sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+ sta->last_seq_ctrl == seq_ctrl &&
+ sta->last_subtype == WLAN_FC_STYPE_AUTH) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Drop repeated authentication frame seq_ctrl=0x%x",
+ seq_ctrl);
+ return;
+ }
+ } 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",
+ MAC2STR(mgmt->sa));
+ /*
+ * Save a copy of the frame so that it can be processed
+ * if a new peer entry is added shortly after this.
+ */
+ wpabuf_free(hapd->mesh_pending_auth);
+ hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
+ os_get_reltime(&hapd->mesh_pending_auth_time);
+ return;
+ }
+#endif /* CONFIG_MESH */
+
+ sta = ap_sta_add(hapd, mgmt->sa);
+ if (!sta) {
+ 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_get_vlan_id_ifname(hapd->conf->vlan,
- vlan_id) == NULL) {
+ 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",
@@ -599,15 +1076,10 @@ static void handle_auth(struct hostapd_data *hapd,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"authentication OK (open system)");
-#ifdef IEEE80211_REQUIRE_AUTH_ACK
- /* Station will be marked authenticated if it ACKs the
- * authentication reply. */
-#else
sta->flags |= WLAN_STA_AUTH;
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta);
-#endif
break;
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@@ -627,7 +1099,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_FT;
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
- sta->addr);
+ sta->addr, NULL);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
"state machine");
@@ -644,7 +1116,23 @@ static void handle_auth(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
case WLAN_AUTH_SAE:
- handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+#ifdef CONFIG_MESH
+ if (status_code == WLAN_STATUS_SUCCESS &&
+ hapd->conf->mesh & MESH_ENABLED) {
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm =
+ wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Failed to initialize WPA state machine");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+#endif /* CONFIG_MESH */
+ handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
+ status_code);
return;
#endif /* CONFIG_SAE */
}
@@ -700,12 +1188,10 @@ static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
- char ssid_txt[33];
- ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"Station tried to associate with unknown SSID "
- "'%s'", ssid_txt);
+ "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len));
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
@@ -767,6 +1253,21 @@ static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
}
+static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ext_capab_ie, size_t ext_capab_ie_len)
+{
+#ifdef CONFIG_INTERWORKING
+ /* check for QoS Map support */
+ if (ext_capab_ie_len >= 5) {
+ if (ext_capab_ie[4] & 0x01)
+ sta->qos_map_enabled = 1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
{
@@ -774,6 +1275,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
u16 resp;
const u8 *wpa_ie;
size_t wpa_ie_len;
+ const u8 *p2p_dev_addr = NULL;
if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -788,6 +1290,9 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+ resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
resp = copy_supp_rates(hapd, sta, &elems);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -810,15 +1315,40 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
elems.vht_capabilities_len);
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;
+
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
!(sta->flags & WLAN_STA_VHT)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "Station does not support "
"mandatory VHT PHY - reject association");
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
+ }
+
+ if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
+ resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
+ elems.vendor_vht_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_P2P
+ if (elems.p2p) {
+ wpabuf_free(sta->p2p_ie);
+ sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+ P2P_IE_VENDOR_TYPE);
+ if (sta->p2p_ie)
+ p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
+ } else {
+ wpabuf_free(sta->p2p_ie);
+ sta->p2p_ie = NULL;
+ }
+#endif /* CONFIG_P2P */
+
if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
wpa_ie = elems.rsn_ie;
wpa_ie_len = elems.rsn_ie_len;
@@ -870,7 +1400,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
wpa_ie_len += 2;
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
- sta->addr);
+ sta->addr,
+ p2p_dev_addr);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_WARNING, "Failed to initialize WPA "
"state machine");
@@ -943,7 +1474,21 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
#ifdef CONFIG_SAE
if (wpa_auth_uses_sae(sta->wpa_sm) &&
- sta->auth_alg != WLAN_AUTH_SAE) {
+ sta->auth_alg == WLAN_AUTH_OPEN) {
+ struct rsn_pmksa_cache_entry *sa;
+ sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+ if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No PMKSA cache entry found for "
+ MACSTR, MAC2STR(sta->addr));
+ return WLAN_STATUS_INVALID_PMKID;
+ }
+ wpa_printf(MSG_DEBUG, "SAE: " MACSTR
+ " using PMKSA caching", MAC2STR(sta->addr));
+ } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
+ sta->auth_alg != WLAN_AUTH_SAE &&
+ !(sta->auth_alg == WLAN_AUTH_FT &&
+ wpa_auth_uses_ft_sae(sta->wpa_sm))) {
wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
"SAE AKM after non-SAE auth_alg %u",
MAC2STR(sta->addr), sta->auth_alg);
@@ -962,20 +1507,33 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_HS20
+ } else if (hapd->conf->osen) {
+ if (elems.osen == NULL) {
+ hostapd_logger(
+ hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "No HS 2.0 OSEN element in association request");
+ return WLAN_STATUS_INVALID_IE;
+ }
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to initialize WPA "
+ "state machine");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
+ elems.osen - 2, elems.osen_len + 2) < 0)
+ return WLAN_STATUS_INVALID_IE;
+#endif /* CONFIG_HS20 */
} else
wpa_auth_sta_no_wpa(sta->wpa_sm);
#ifdef CONFIG_P2P
- if (elems.p2p) {
- wpabuf_free(sta->p2p_ie);
- sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
- P2P_IE_VENDOR_TYPE);
-
- } else {
- wpabuf_free(sta->p2p_ie);
- sta->p2p_ie = NULL;
- }
-
p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
#endif /* CONFIG_P2P */
@@ -1038,8 +1596,7 @@ 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, sta, 0));
reply->u.assoc_resp.status_code = host_to_le16(status_code);
- reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
- | BIT(14) | BIT(15));
+ reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
/* Supported rates */
p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
/* Extended supported rates */
@@ -1066,12 +1623,21 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- p = hostapd_eid_vht_capabilities(hapd, p);
- p = hostapd_eid_vht_operation(hapd, p);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ p = hostapd_eid_vht_capabilities(hapd, p);
+ p = hostapd_eid_vht_operation(hapd, p);
+ }
#endif /* CONFIG_IEEE80211AC */
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
+ if (sta->qos_map_enabled)
+ p = hostapd_eid_qos_map_set(hapd, p);
+
+#ifdef CONFIG_IEEE80211AC
+ if (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)
p = hostapd_eid_wmm(hapd, p);
@@ -1130,7 +1696,7 @@ static void handle_assoc(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int reassoc)
{
- u16 capab_info, listen_interval;
+ u16 capab_info, listen_interval, seq_ctrl, fc;
u16 resp = WLAN_STATUS_SUCCESS;
const u8 *pos;
int left, i;
@@ -1138,20 +1704,44 @@ static void handle_assoc(struct hostapd_data *hapd,
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
- printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
- "\n", reassoc, (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)",
+ reassoc, (unsigned long) len);
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (reassoc) {
+ if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
+ drand48() < hapd->iconf->ignore_reassoc_probability) {
+ wpa_printf(MSG_INFO,
+ "TESTING: ignoring reassoc request from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+ } else {
+ if (hapd->iconf->ignore_assoc_probability > 0.0 &&
+ drand48() < hapd->iconf->ignore_assoc_probability) {
+ wpa_printf(MSG_INFO,
+ "TESTING: ignoring assoc request from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ fc = le_to_host16(mgmt->frame_control);
+ seq_ctrl = le_to_host16(mgmt->seq_ctrl);
+
if (reassoc) {
capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
listen_interval = le_to_host16(
mgmt->u.reassoc_req.listen_interval);
wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
" capab_info=0x%02x listen_interval=%d current_ap="
- MACSTR,
+ MACSTR " seq_ctrl=0x%x%s",
MAC2STR(mgmt->sa), capab_info, listen_interval,
- MAC2STR(mgmt->u.reassoc_req.current_ap));
+ MAC2STR(mgmt->u.reassoc_req.current_ap),
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
pos = mgmt->u.reassoc_req.variable;
} else {
@@ -1159,8 +1749,10 @@ static void handle_assoc(struct hostapd_data *hapd,
listen_interval = le_to_host16(
mgmt->u.assoc_req.listen_interval);
wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
- " capab_info=0x%02x listen_interval=%d",
- MAC2STR(mgmt->sa), capab_info, listen_interval);
+ " capab_info=0x%02x listen_interval=%d "
+ "seq_ctrl=0x%x%s",
+ MAC2STR(mgmt->sa), capab_info, listen_interval,
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
pos = mgmt->u.assoc_req.variable;
}
@@ -1186,6 +1778,21 @@ static void handle_assoc(struct hostapd_data *hapd,
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) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Drop repeated association frame seq_ctrl=0x%x",
+ seq_ctrl);
+ return;
+ }
+ sta->last_seq_ctrl = seq_ctrl;
+ sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
+ WLAN_FC_STYPE_ASSOC_REQ;
+
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
goto fail;
@@ -1279,17 +1886,6 @@ static void handle_assoc(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211W */
- if (reassoc) {
- os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
- ETH_ALEN);
- }
-
- if (sta->last_assoc_req)
- os_free(sta->last_assoc_req);
- sta->last_assoc_req = os_malloc(len);
- if (sta->last_assoc_req)
- os_memcpy(sta->last_assoc_req, mgmt, len);
-
/* Make sure that the previously registered inactivity timer will not
* remove the STA immediately. */
sta->timeout_next = STA_NULLFUNC;
@@ -1305,8 +1901,8 @@ static void handle_disassoc(struct hostapd_data *hapd,
struct sta_info *sta;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
- printf("handle_disassoc - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
@@ -1316,12 +1912,13 @@ static void handle_disassoc(struct hostapd_data *hapd,
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
- printf("Station " MACSTR " trying to disassociate, but it "
- "is not associated.\n", MAC2STR(mgmt->sa));
+ wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated",
+ MAC2STR(mgmt->sa));
return;
}
ap_sta_set_authorized(hapd, sta, 0);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1332,6 +1929,9 @@ static void handle_disassoc(struct hostapd_data *hapd,
* authenticated. */
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(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);
if (sta->timeout_next == STA_NULLFUNC ||
@@ -1371,6 +1971,7 @@ static void handle_deauth(struct hostapd_data *hapd,
}
ap_sta_set_authorized(hapd, sta, 0);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
@@ -1391,8 +1992,8 @@ static void handle_beacon(struct hostapd_data *hapd,
struct ieee802_11_elems elems;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
- printf("handle_beacon - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
@@ -1407,9 +2008,9 @@ static void handle_beacon(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211W
-static void hostapd_sa_query_action(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt,
- size_t len)
+static int hostapd_sa_query_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
{
const u8 *end;
@@ -1418,12 +2019,13 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd,
if (((u8 *) mgmt) + len < end) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
"frame (len=%lu)", (unsigned long) len);
- return;
+ 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;
}
@@ -1435,29 +2037,8 @@ static int robust_action_frame(u8 category)
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WNM
-static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta,
- const struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- struct rx_action action;
- if (len < IEEE80211_HDRLEN + 2)
- return;
- os_memset(&action, 0, sizeof(action));
- action.da = mgmt->da;
- action.sa = mgmt->sa;
- action.bssid = mgmt->bssid;
- action.category = mgmt->u.action.category;
- action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action;
- action.len = len - IEEE80211_HDRLEN - 1;
- action.freq = hapd->iface->freq;
- ieee802_11_rx_wnm_action_ap(hapd, &action);
-}
-#endif /* CONFIG_WNM */
-
-
-static void handle_action(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+static int handle_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len)
{
struct sta_info *sta;
sta = ap_get_sta(hapd, mgmt->sa);
@@ -1467,7 +2048,7 @@ static void handle_action(struct hostapd_data *hapd,
HOSTAPD_LEVEL_DEBUG,
"handle_action - too short payload (len=%lu)",
(unsigned long) len);
- return;
+ return 0;
}
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
@@ -1475,56 +2056,92 @@ static void handle_action(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
"frame (category=%u) from unassociated STA " MACSTR,
MAC2STR(mgmt->sa), mgmt->u.action.category);
- return;
+ return 0;
}
#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
- !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
- robust_action_frame(mgmt->u.action.category))) {
+ !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
+ robust_action_frame(mgmt->u.action.category)) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Dropped unprotected Robust Action frame from "
"an MFP STA");
- return;
+ return 0;
}
#endif /* CONFIG_IEEE80211W */
+ if (sta) {
+ u16 fc = le_to_host16(mgmt->frame_control);
+ u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
+
+ if ((fc & WLAN_FC_RETRY) &&
+ sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+ sta->last_seq_ctrl == seq_ctrl &&
+ sta->last_subtype == WLAN_FC_STYPE_ACTION) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Drop repeated action frame seq_ctrl=0x%x",
+ seq_ctrl);
+ return 1;
+ }
+
+ sta->last_seq_ctrl = seq_ctrl;
+ sta->last_subtype = WLAN_FC_STYPE_ACTION;
+ }
+
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
- if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
+ if (!sta ||
+ wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
len - IEEE80211_HDRLEN))
break;
- return;
+ return 1;
#endif /* CONFIG_IEEE80211R */
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
- return;
+ return 1;
#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
- hostapd_sa_query_action(hapd, mgmt, len);
- return;
+ return hostapd_sa_query_action(hapd, mgmt, len);
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
case WLAN_ACTION_WNM:
- hostapd_wnm_action(hapd, sta, mgmt, len);
- return;
+ ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
+ return 1;
#endif /* CONFIG_WNM */
case WLAN_ACTION_PUBLIC:
+ case WLAN_ACTION_PROTECTED_DUAL:
+#ifdef CONFIG_IEEE80211N
+ if (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);
+ }
+#endif /* CONFIG_IEEE80211N */
if (hapd->public_action_cb) {
hapd->public_action_cb(hapd->public_action_cb_ctx,
(u8 *) mgmt, len,
hapd->iface->freq);
- return;
}
+ if (hapd->public_action_cb2) {
+ hapd->public_action_cb2(hapd->public_action_cb2_ctx,
+ (u8 *) mgmt, len,
+ hapd->iface->freq);
+ }
+ if (hapd->public_action_cb || hapd->public_action_cb2)
+ return 1;
break;
case WLAN_ACTION_VENDOR_SPECIFIC:
if (hapd->vendor_action_cb) {
if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
(u8 *) mgmt, len,
hapd->iface->freq) == 0)
- return;
+ return 1;
}
break;
}
@@ -1547,7 +2164,7 @@ static void handle_action(struct hostapd_data *hapd,
"frame back to sender");
resp = os_malloc(len);
if (resp == NULL)
- return;
+ return 0;
os_memcpy(resp, mgmt, len);
os_memcpy(resp->da, resp->sa, ETH_ALEN);
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
@@ -1560,6 +2177,8 @@ static void handle_action(struct hostapd_data *hapd,
}
os_free(resp);
}
+
+ return 1;
}
@@ -1576,15 +2195,16 @@ static void handle_action(struct hostapd_data *hapd,
* addition, it can be called to re-inserted pending frames (e.g., when using
* external RADIUS server as an MAC ACL).
*/
-void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
- struct hostapd_frame_info *fi)
+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;
if (len < 24)
- return;
+ return 0;
mgmt = (struct ieee80211_mgmt *) buf;
fc = le_to_host16(mgmt->frame_control);
@@ -1592,7 +2212,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
if (stype == WLAN_FC_STYPE_BEACON) {
handle_beacon(hapd, mgmt, len, fi);
- return;
+ return 1;
}
broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
@@ -1605,16 +2225,19 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
!((hapd->conf->p2p & P2P_GROUP_OWNER) &&
stype == WLAN_FC_STYPE_ACTION) &&
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MESH
+ !(hapd->conf->mesh & MESH_ENABLED) &&
+#endif /* CONFIG_MESH */
os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
- printf("MGMT: BSSID=" MACSTR " not our address\n",
- MAC2STR(mgmt->bssid));
- return;
+ wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
+ MAC2STR(mgmt->bssid));
+ return 0;
}
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
- return;
+ return 1;
}
if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
@@ -1622,33 +2245,38 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
HOSTAPD_LEVEL_DEBUG,
"MGMT: DA=" MACSTR " not our address",
MAC2STR(mgmt->da));
- return;
+ return 0;
}
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
handle_auth(hapd, mgmt, len);
+ ret = 1;
break;
case WLAN_FC_STYPE_ASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
handle_assoc(hapd, mgmt, len, 0);
+ ret = 1;
break;
case WLAN_FC_STYPE_REASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
handle_assoc(hapd, mgmt, len, 1);
+ ret = 1;
break;
case WLAN_FC_STYPE_DISASSOC:
wpa_printf(MSG_DEBUG, "mgmt::disassoc");
handle_disassoc(hapd, mgmt, len);
+ ret = 1;
break;
case WLAN_FC_STYPE_DEAUTH:
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
handle_deauth(hapd, mgmt, len);
+ ret = 1;
break;
case WLAN_FC_STYPE_ACTION:
wpa_printf(MSG_DEBUG, "mgmt::action");
- handle_action(hapd, mgmt, len);
+ ret = handle_action(hapd, mgmt, len);
break;
default:
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1656,6 +2284,8 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
"unknown mgmt frame subtype %d", stype);
break;
}
+
+ return ret;
}
@@ -1674,8 +2304,8 @@ static void handle_auth_cb(struct hostapd_data *hapd,
}
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- printf("handle_auth_cb - too short payload (len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+ (unsigned long) len);
return;
}
@@ -1685,8 +2315,8 @@ static void handle_auth_cb(struct hostapd_data *hapd,
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
- printf("handle_auth_cb: STA " MACSTR " not found\n",
- MAC2STR(mgmt->da));
+ wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+ MAC2STR(mgmt->da));
return;
}
@@ -1700,6 +2330,30 @@ static void handle_auth_cb(struct hostapd_data *hapd,
}
+static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ char *ifname_wds)
+{
+ int i;
+ struct hostapd_ssid *ssid = sta->ssid;
+
+ if (hapd->conf->ieee802_1x || hapd->conf->wpa)
+ return;
+
+ for (i = 0; i < 4; i++) {
+ if (ssid->wep.key[i] &&
+ hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
+ i == ssid->wep.idx, NULL, 0,
+ ssid->wep.key[i], ssid->wep.len[i])) {
+ wpa_printf(MSG_WARNING,
+ "Could not set WEP keys for WDS interface; %s",
+ ifname_wds);
+ break;
+ }
+ }
+}
+
+
static void handle_assoc_cb(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
size_t len, int reassoc, int ok)
@@ -1708,18 +2362,19 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
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))) {
- printf("handle_assoc_cb(reassoc=%d) - too short payload "
- "(len=%lu)\n", reassoc, (unsigned long) len);
+ 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) {
- printf("handle_assoc_cb: STA " MACSTR " not found\n",
- MAC2STR(mgmt->da));
+ wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
+ MAC2STR(mgmt->da));
return;
}
@@ -1737,7 +2392,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
status = le_to_host16(mgmt->u.assoc_resp.status_code);
if (status != WLAN_STATUS_SUCCESS)
- goto fail;
+ return;
/* Stop previous accounting session, if one is started, and allocate
* new session id for the new session. */
@@ -1751,7 +2406,8 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
if (sta->flags & WLAN_STA_ASSOC)
new_assoc = 0;
sta->flags |= WLAN_STA_ASSOC;
- if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+ sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
+ if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) ||
sta->auth_alg == WLAN_AUTH_FT) {
/*
* Open, static WEP, or FT protocol; no separate authorization
@@ -1780,12 +2436,17 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
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, sta->qosinfo)) {
+ 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");
@@ -1793,11 +2454,18 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_DISASSOC_AP_BUSY);
- goto fail;
+ return;
}
- if (sta->flags & WLAN_STA_WDS)
- hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+ 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) {
/*
@@ -1806,11 +2474,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
* interface selection is not going to change anymore.
*/
if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
- goto fail;
+ return;
} else if (sta->vlan_id) {
/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
- goto fail;
+ return;
}
hostapd_set_sta_flags(hapd, sta);
@@ -1822,13 +2490,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
-
- fail:
- /* Copy of the association request is not needed anymore */
- if (sta->last_assoc_req) {
- os_free(sta->last_assoc_req);
- sta->last_assoc_req = NULL;
- }
}
@@ -1895,6 +2556,14 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
const struct ieee80211_mgmt *mgmt;
mgmt = (const struct ieee80211_mgmt *) buf;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_mgmt_frame_handling) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d",
+ stype, ok);
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth cb");
@@ -1923,7 +2592,7 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
wpa_printf(MSG_DEBUG, "mgmt::action cb");
break;
default:
- printf("unknown mgmt cb frame subtype %d\n", stype);
+ wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
break;
}
}
@@ -2038,11 +2707,18 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
return;
if (wds && !(sta->flags & WLAN_STA_WDS)) {
+ int ret;
+ char ifname_wds[IFNAMSIZ + 1];
+
wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
"STA " MACSTR " (aid %u)",
MAC2STR(sta->addr), sta->aid);
sta->flags |= WLAN_STA_WDS;
- hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+ ret = hostapd_set_wds_sta(hapd, ifname_wds,
+ sta->addr, sta->aid, 1);
+ if (!ret)
+ hostapd_set_wds_encryption(hapd, sta,
+ ifname_wds);
}
return;
}
diff --git a/contrib/wpa/src/ap/ieee802_11.h b/contrib/wpa/src/ap/ieee802_11.h
index 1e5800d..41c27d9 100644
--- a/contrib/wpa/src/ap/ieee802_11.h
+++ b/contrib/wpa/src/ap/ieee802_11.h
@@ -14,12 +14,14 @@ struct hostapd_data;
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
+struct ieee80211_mgmt;
-void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
- struct hostapd_frame_info *fi);
+int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+ struct hostapd_frame_info *fi);
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
u16 stype, int ok);
-void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len);
#ifdef NEED_AP_MLME
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
@@ -40,24 +42,37 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
+void ap_ht2040_timeout(void *eloop_data, void *user_data);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id);
void hostapd_get_ht_capab(struct hostapd_data *hapd,
struct ieee80211_ht_capabilities *ht_cap,
struct ieee80211_ht_capabilities *neg_ht_cap);
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+ struct ieee80211_vht_capabilities *vht_cap,
+ struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len);
+
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+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, size_t vht_capab_len);
+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,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -78,4 +93,15 @@ int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+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);
+#else /* CONFIG_SAE */
+static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+}
+#endif /* CONFIG_SAE */
+
#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 c311e55..56c3ce0 100644
--- a/contrib/wpa/src/ap/ieee802_11_auth.c
+++ b/contrib/wpa/src/ap/ieee802_11_auth.c
@@ -29,7 +29,7 @@
struct hostapd_cached_radius_acl {
- os_time_t timestamp;
+ struct os_reltime timestamp;
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
@@ -43,7 +43,7 @@ struct hostapd_cached_radius_acl {
struct hostapd_acl_query_data {
- os_time_t timestamp;
+ struct os_reltime timestamp;
u8 radius_id;
macaddr addr;
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
@@ -104,15 +104,16 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
char **identity, char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
for (entry = hapd->acl_cache; entry; entry = entry->next) {
if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
continue;
- if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+ if (os_reltime_expired(&now, &entry->timestamp,
+ RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
if (session_timeout)
@@ -265,7 +266,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
return HOSTAPD_ACL_REJECT;
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
- struct os_time t;
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
@@ -305,8 +305,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
- os_get_time(&t);
- query->timestamp = t.sec;
+ os_get_reltime(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -338,7 +337,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
#ifndef CONFIG_NO_RADIUS
-static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd,
+ struct os_reltime *now)
{
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
@@ -346,7 +346,8 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
entry = hapd->acl_cache;
while (entry) {
- if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+ if (os_reltime_expired(now, &entry->timestamp,
+ RADIUS_ACL_TIMEOUT)) {
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
@@ -367,7 +368,7 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
- os_time_t now)
+ struct os_reltime *now)
{
struct hostapd_acl_query_data *prev, *entry, *tmp;
@@ -375,7 +376,8 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
entry = hapd->acl_queries;
while (entry) {
- if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+ if (os_reltime_expired(now, &entry->timestamp,
+ RADIUS_ACL_TIMEOUT)) {
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
@@ -403,11 +405,11 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
- hostapd_acl_expire_cache(hapd, now.sec);
- hostapd_acl_expire_queries(hapd, now.sec);
+ os_get_reltime(&now);
+ hostapd_acl_expire_cache(hapd, &now);
+ hostapd_acl_expire_queries(hapd, &now);
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
@@ -480,7 +482,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
- struct os_time t;
query = hapd->acl_queries;
prev = NULL;
@@ -515,8 +516,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
- os_get_time(&t);
- cache->timestamp = t.sec;
+ os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
diff --git a/contrib/wpa/src/ap/ieee802_11_ht.c b/contrib/wpa/src/ap/ieee802_11_ht.c
index 6c3696f..4b0653d 100644
--- a/contrib/wpa/src/ap/ieee802_11_ht.c
+++ b/contrib/wpa/src/ap/ieee802_11_ht.c
@@ -3,26 +3,22 @@
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008, Intel Corporation
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
+#include "hw_features.h"
+#include "ap_drv_ops.h"
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
@@ -50,6 +46,35 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
pos += sizeof(*cap);
+ if (hapd->iconf->obss_interval) {
+ struct ieee80211_obss_scan_parameters *scan_params;
+
+ *pos++ = WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS;
+ *pos++ = sizeof(*scan_params);
+
+ scan_params = (struct ieee80211_obss_scan_parameters *) pos;
+ os_memset(scan_params, 0, sizeof(*scan_params));
+ scan_params->width_trigger_scan_interval =
+ host_to_le16(hapd->iconf->obss_interval);
+
+ /* Fill in default values for remaining parameters
+ * (IEEE Std 802.11-2012, 8.4.2.61 and MIB defval) */
+ scan_params->scan_passive_dwell =
+ host_to_le16(20);
+ scan_params->scan_active_dwell =
+ host_to_le16(10);
+ scan_params->scan_passive_total_per_channel =
+ host_to_le16(200);
+ scan_params->scan_active_total_per_channel =
+ host_to_le16(20);
+ scan_params->channel_transition_delay_factor =
+ host_to_le16(5);
+ scan_params->scan_activity_threshold =
+ host_to_le16(25);
+
+ pos += sizeof(*scan_params);
+ }
+
return pos;
}
@@ -68,14 +93,14 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
oper = (struct ieee80211_ht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
- oper->control_chan = hapd->iconf->channel;
+ oper->primary_chan = hapd->iconf->channel;
oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
if (hapd->iconf->secondary_channel == 1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
- HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+ HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
if (hapd->iconf->secondary_channel == -1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
- HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+ HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
pos += sizeof(*oper);
@@ -105,45 +130,40 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
__func__, iface->ht_op_mode);
- if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+ if (!(iface->ht_op_mode & HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT)
&& iface->num_sta_ht_no_gf) {
- iface->ht_op_mode |=
- HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ iface->ht_op_mode |= HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT;
op_mode_changes++;
} else if ((iface->ht_op_mode &
- HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+ HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT) &&
iface->num_sta_ht_no_gf == 0) {
- iface->ht_op_mode &=
- ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ iface->ht_op_mode &= ~HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT;
op_mode_changes++;
}
- if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ if (!(iface->ht_op_mode & HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT) &&
(iface->num_sta_no_ht || iface->olbc_ht)) {
- iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ iface->ht_op_mode |= HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT;
op_mode_changes++;
} else if ((iface->ht_op_mode &
- HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT) &&
(iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
- iface->ht_op_mode &=
- ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ iface->ht_op_mode &= ~HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT;
op_mode_changes++;
}
- new_op_mode = 0;
if (iface->num_sta_no_ht)
- new_op_mode = OP_MODE_MIXED;
- else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
- && iface->num_sta_ht_20mhz)
- new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+ new_op_mode = HT_PROT_NON_HT_MIXED;
+ else if (iface->conf->secondary_channel && iface->num_sta_ht_20mhz)
+ new_op_mode = HT_PROT_20MHZ_PROTECTION;
else if (iface->olbc_ht)
- new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+ new_op_mode = HT_PROT_NONMEMBER_PROTECTION;
else
- new_op_mode = OP_MODE_PURE;
+ new_op_mode = HT_PROT_NO_PROTECTION;
- cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ cur_op_mode = iface->ht_op_mode & HT_OPER_OP_MODE_HT_PROT_MASK;
if (cur_op_mode != new_op_mode) {
- iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ iface->ht_op_mode &= ~HT_OPER_OP_MODE_HT_PROT_MASK;
iface->ht_op_mode |= new_op_mode;
op_mode_changes++;
}
@@ -155,6 +175,140 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
}
+static int is_40_allowed(struct hostapd_iface *iface, int channel)
+{
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ int pri = 2407 + 5 * channel;
+
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return 1;
+
+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+
+ if (iface->conf->secondary_channel > 0)
+ sec_freq = pri_freq + 20;
+ else
+ sec_freq = pri_freq - 20;
+
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+ if ((pri < affected_start || pri > affected_end))
+ return 1; /* not within affected channel range */
+
+ wpa_printf(MSG_ERROR, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+ wpa_printf(MSG_ERROR, "Neighboring BSS: freq=%d", pri);
+ return 0;
+}
+
+
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct ieee80211_2040_bss_coex_ie *bc_ie;
+ struct ieee80211_2040_intol_chan_report *ic_report;
+ int is_ht_allowed = 1;
+ int i;
+ const u8 *start = (const u8 *) mgmt;
+ const u8 *data = start + IEEE80211_HDRLEN + 2;
+
+ 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))
+ return;
+
+ if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
+ return;
+
+ bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
+ if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
+ bc_ie->length < 1) {
+ wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report",
+ bc_ie->element_id, bc_ie->length);
+ return;
+ }
+ if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
+ return;
+ data += 2 + bc_ie->length;
+
+ wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
+ bc_ie->coex_param);
+ if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "20 MHz BSS width request bit is set in BSS coexistence information field");
+ is_ht_allowed = 0;
+ }
+
+ if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "40 MHz intolerant bit is set in BSS coexistence information field");
+ is_ht_allowed = 0;
+ }
+
+ if (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)
+ return;
+ ic_report = (struct ieee80211_2040_intol_chan_report *) data;
+ wpa_printf(MSG_DEBUG,
+ "20/40 BSS Intolerant Channel Report: Operating Class %u",
+ ic_report->op_class);
+
+ /* Go through the channel report to find any BSS there in the
+ * affected channel range */
+ for (i = 0; i < ielen - 1; i++) {
+ u8 chan = ic_report->variable[i];
+
+ if (is_40_allowed(iface, chan))
+ continue;
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "20_40_INTOLERANT channel %d reported",
+ chan);
+ is_ht_allowed = 0;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
+ is_ht_allowed, iface->num_sta_ht40_intolerant);
+
+ if (!is_ht_allowed &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ if (iface->conf->secondary_channel) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Switching to 20 MHz operation");
+ iface->conf->secondary_channel = 0;
+ ieee802_11_set_beacons(iface);
+ }
+ if (!iface->num_sta_ht40_intolerant &&
+ iface->conf->obss_interval) {
+ unsigned int delay_time;
+ delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+ iface->conf->obss_interval;
+ eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
+ NULL);
+ eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+ hapd->iface, NULL);
+ wpa_printf(MSG_DEBUG,
+ "Reschedule HT 20/40 timeout to occur in %u seconds",
+ delay_time);
+ }
+ }
+}
+
+
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len)
{
@@ -183,6 +337,52 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
}
+void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta)
+{
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return;
+
+ wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR
+ " in Association Request", MAC2STR(sta->addr));
+
+ if (sta->ht40_intolerant_set)
+ return;
+
+ sta->ht40_intolerant_set = 1;
+ iface->num_sta_ht40_intolerant++;
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+
+ if (iface->conf->secondary_channel &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ iface->conf->secondary_channel = 0;
+ ieee802_11_set_beacons(iface);
+ }
+}
+
+
+void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta)
+{
+ if (!sta->ht40_intolerant_set)
+ return;
+
+ sta->ht40_intolerant_set = 0;
+ iface->num_sta_ht40_intolerant--;
+
+ if (iface->num_sta_ht40_intolerant == 0 &&
+ (iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ unsigned int delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+ iface->conf->obss_interval;
+ wpa_printf(MSG_DEBUG,
+ "HT: Start 20->40 MHz transition timer (%d seconds)",
+ delay_time);
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+ eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+ iface, NULL);
+ }
+}
+
+
static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
{
u16 ht_capab;
@@ -210,6 +410,9 @@ static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_20mhz);
}
+
+ if (ht_capab & HT_CAP_INFO_40MHZ_INTOLERANT)
+ ht40_intolerant_add(hapd->iface, sta);
}
@@ -271,3 +474,14 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
}
+
+
+void ap_ht2040_timeout(void *eloop_data, void *user_data)
+{
+ struct hostapd_iface *iface = eloop_data;
+
+ wpa_printf(MSG_INFO, "Switching to 40 MHz operation");
+
+ iface->conf->secondary_channel = iface->secondary_ch;
+ ieee802_11_set_beacons(iface);
+}
diff --git a/contrib/wpa/src/ap/ieee802_11_shared.c b/contrib/wpa/src/ap/ieee802_11_shared.c
index 76f78a7..d462ac8 100644
--- a/contrib/wpa/src/ap/ieee802_11_shared.c
+++ b/contrib/wpa/src/ap/ieee802_11_shared.c
@@ -24,13 +24,13 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
{
u8 *pos = eid;
u32 timeout, tu;
- struct os_time now, passed;
+ struct os_reltime now, passed;
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
- os_get_time(&now);
- os_time_sub(&now, &sta->sa_query_start, &passed);
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout > tu)
timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
@@ -69,7 +69,7 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
WLAN_SA_QUERY_TR_ID_LEN);
end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
- perror("ieee802_11_send_sa_query_req: send");
+ wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
}
@@ -107,7 +107,7 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
WLAN_SA_QUERY_TR_ID_LEN);
end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
- perror("ieee80211_mgmt_sa_query_request: send");
+ wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
}
@@ -164,10 +164,62 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
#endif /* CONFIG_IEEE80211W */
+static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+{
+ *pos = 0x00;
+
+ switch (idx) {
+ case 0: /* Bits 0-7 */
+ if (hapd->iconf->obss_interval)
+ *pos |= 0x01; /* Bit 0 - Coexistence management */
+ break;
+ case 1: /* Bits 8-15 */
+ if (hapd->conf->proxy_arp)
+ *pos |= 0x10; /* Bit 12 - Proxy ARP */
+ break;
+ case 2: /* Bits 16-23 */
+ if (hapd->conf->wnm_sleep_mode)
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ if (hapd->conf->bss_transition)
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+ if (hapd->conf->time_advertisement == 2)
+ *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+ if (hapd->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+ break;
+ case 4: /* Bits 32-39 */
+ if (hapd->conf->qos_map_set_len)
+ *pos |= 0x01; /* Bit 32 - QoS Map */
+ if (hapd->conf->tdls & TDLS_PROHIBIT)
+ *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+ if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
+ /* Bit 39 - TDLS Channel Switching Prohibited */
+ *pos |= 0x80;
+ }
+ break;
+ case 5: /* Bits 40-47 */
+#ifdef CONFIG_HS20
+ if (hapd->conf->hs20)
+ *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_HS20 */
+ break;
+ case 6: /* Bits 48-55 */
+ if (hapd->conf->ssid.utf8_ssid)
+ *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+ break;
+ }
+}
+
+
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- u8 len = 0;
+ u8 len = 0, i;
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
len = 5;
@@ -175,59 +227,57 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
len = 4;
if (len < 3 && hapd->conf->wnm_sleep_mode)
len = 3;
+ if (len < 1 && hapd->iconf->obss_interval)
+ len = 1;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
#ifdef CONFIG_WNM
if (len < 4)
len = 4;
#endif /* CONFIG_WNM */
+#ifdef CONFIG_HS20
+ if (hapd->conf->hs20 && len < 6)
+ len = 6;
+#endif /* CONFIG_HS20 */
+ if (len < hapd->iface->extended_capa_len)
+ len = hapd->iface->extended_capa_len;
if (len == 0)
return eid;
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
- *pos++ = 0x00;
- *pos++ = 0x00;
+ for (i = 0; i < len; i++, pos++) {
+ hostapd_ext_capab_byte(hapd, pos, i);
- *pos = 0x00;
- if (hapd->conf->wnm_sleep_mode)
- *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
- if (hapd->conf->bss_transition)
- *pos |= 0x08; /* Bit 19 - BSS Transition */
- pos++;
+ if (i < hapd->iface->extended_capa_len) {
+ *pos &= ~hapd->iface->extended_capa_mask[i];
+ *pos |= hapd->iface->extended_capa[i];
+ }
+ }
- if (len < 4)
- return pos;
- *pos = 0x00;
-#ifdef CONFIG_WNM
- *pos |= 0x02; /* Bit 25 - SSID List */
-#endif /* CONFIG_WNM */
- if (hapd->conf->time_advertisement == 2)
- *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
- if (hapd->conf->interworking)
- *pos |= 0x80; /* Bit 31 - Interworking */
- pos++;
+ while (len > 0 && eid[1 + len] == 0) {
+ len--;
+ eid[1] = len;
+ }
+ if (len == 0)
+ return eid;
- if (len < 5)
- return pos;
- *pos = 0x00;
- if (hapd->conf->tdls & TDLS_PROHIBIT)
- *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
- if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
- *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
- pos++;
+ return eid + 2 + len;
+}
- if (len < 6)
- return pos;
- *pos = 0x00;
- pos++;
- if (len < 7)
- return pos;
- *pos = 0x00;
- if (hapd->conf->ssid.utf8_ssid)
- *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
- pos++;
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ u8 len = hapd->conf->qos_map_set_len;
+
+ if (!len)
+ return eid;
+
+ *pos++ = WLAN_EID_QOS_MAP_SET;
+ *pos++ = len;
+ os_memcpy(pos, hapd->conf->qos_map_set, len);
+ pos += len;
return pos;
}
diff --git a/contrib/wpa/src/ap/ieee802_11_vht.c b/contrib/wpa/src/ap/ieee802_11_vht.c
index b21c2b7..171538a 100644
--- a/contrib/wpa/src/ap/ieee802_11_vht.c
+++ b/contrib/wpa/src/ap/ieee802_11_vht.c
@@ -12,7 +12,6 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
@@ -23,23 +22,35 @@
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_capabilities *cap;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
- hapd->conf->disable_11ac)
+ if (!mode)
return eid;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
+ mode->vht_capab == 0 && hapd->iface->hw_features) {
+ int i;
+
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ if (hapd->iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &hapd->iface->hw_features[i];
+ break;
+ }
+ }
+ }
+
*pos++ = WLAN_EID_VHT_CAP;
*pos++ = sizeof(*cap);
cap = (struct ieee80211_vht_capabilities *) pos;
os_memset(cap, 0, sizeof(*cap));
cap->vht_capabilities_info = host_to_le32(
- hapd->iface->current_mode->vht_capab);
+ hapd->iface->conf->vht_capab);
/* Supported MCS set comes from hw */
- os_memcpy(cap->vht_supported_mcs_set,
- hapd->iface->current_mode->vht_mcs_set, 8);
+ os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
pos += sizeof(*cap);
@@ -52,9 +63,6 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
- return eid;
-
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
@@ -82,13 +90,55 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
}
+static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
+ const u8 *sta_vht_capab)
+{
+ const struct ieee80211_vht_capabilities *vht_cap;
+ struct ieee80211_vht_capabilities ap_vht_cap;
+ u16 sta_rx_mcs_set, ap_tx_mcs_set;
+ int i;
+
+ if (!mode)
+ return 1;
+
+ /*
+ * Disable VHT caps for STAs for which there is not even a single
+ * allowed MCS in any supported number of streams, i.e., STA is
+ * advertising 3 (not supported) as VHT MCS rates for all supported
+ * stream cases.
+ */
+ os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set,
+ sizeof(ap_vht_cap.vht_supported_mcs_set));
+ vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab;
+
+ /* AP Tx MCS map vs. STA Rx MCS map */
+ sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map);
+ ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map);
+
+ for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) {
+ if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3)
+ continue;
+
+ if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3)
+ continue;
+
+ return 1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "No matching VHT MCS found between AP TX and STA RX");
+ return 0;
+}
+
+
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
- hapd->conf->disable_11ac) {
+ hapd->conf->disable_11ac ||
+ !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
os_free(sta->vht_capabilities);
sta->vht_capabilities = NULL;
@@ -108,3 +158,140 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
+
+
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len)
+{
+ const u8 *vht_capab;
+ unsigned int vht_capab_len;
+
+ if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
+ hapd->conf->disable_11ac)
+ goto no_capab;
+
+ /* The VHT Capabilities element embedded in vendor VHT */
+ vht_capab = ie + 5;
+ if (vht_capab[0] != WLAN_EID_VHT_CAP)
+ goto no_capab;
+ vht_capab_len = vht_capab[1];
+ if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+ (int) vht_capab_len > ie + len - vht_capab - 2)
+ goto no_capab;
+ vht_capab += 2;
+
+ if (sta->vht_capabilities == NULL) {
+ sta->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (sta->vht_capabilities == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
+ os_memcpy(sta->vht_capabilities, vht_capab,
+ sizeof(struct ieee80211_vht_capabilities));
+ return WLAN_STATUS_SUCCESS;
+
+no_capab:
+ sta->flags &= ~WLAN_STA_VENDOR_VHT;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = (5 + /* The Vendor OUI, type and subtype */
+ 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation));
+
+ 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_operation(hapd, pos);
+
+ return pos;
+}
+
+
+u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper_notif)
+{
+ if (!vht_oper_notif) {
+ sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
+ sta->vht_opmode = *vht_oper_notif;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+ struct ieee80211_vht_capabilities *vht_cap,
+ struct ieee80211_vht_capabilities *neg_vht_cap)
+{
+ u32 cap, own_cap, sym_caps;
+
+ if (vht_cap == NULL)
+ return;
+ os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
+
+ cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
+ own_cap = hapd->iconf->vht_capab;
+
+ /* mask out symmetric VHT capabilities we don't support */
+ sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
+ cap &= ~sym_caps | (own_cap & sym_caps);
+
+ /* mask out beamformer/beamformee caps if not supported */
+ if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+ cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ VHT_CAP_BEAMFORMEE_STS_MAX);
+
+ if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ VHT_CAP_SOUNDING_DIMENSION_MAX);
+
+ if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+ cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+ if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
+ cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+ /* mask channel widths we don't support */
+ switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+ case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+ break;
+ case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+ if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
+ cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ }
+ break;
+ default:
+ cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+ break;
+ }
+
+ if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
+ cap &= ~VHT_CAP_SHORT_GI_160;
+
+ /*
+ * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
+ * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
+ */
+ if (!(own_cap & VHT_CAP_RXSTBC_MASK))
+ cap &= ~VHT_CAP_TXSTBC;
+ if (!(own_cap & VHT_CAP_TXSTBC))
+ cap &= ~VHT_CAP_RXSTBC_MASK;
+
+ neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
+}
diff --git a/contrib/wpa/src/ap/ieee802_1x.c b/contrib/wpa/src/ap/ieee802_1x.c
index d9c21a8..79dc0f9 100644
--- a/contrib/wpa/src/ap/ieee802_1x.c
+++ b/contrib/wpa/src/ap/ieee802_1x.c
@@ -29,11 +29,14 @@
#include "pmksa_cache_auth.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "wps_hostapd.h"
+#include "hs20.h"
#include "ieee802_1x.h"
static void ieee802_1x_finished(struct hostapd_data *hapd,
- struct sta_info *sta, int success);
+ struct sta_info *sta, int success,
+ int remediation);
static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
@@ -63,6 +66,20 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
if (wpa_auth_pairwise_set(sta->wpa_sm))
encrypt = 1;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_eapol_frame_io) {
+ 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,
+ "EAPOL-TX " MACSTR " %s",
+ MAC2STR(sta->addr), hex);
+ os_free(hex);
+ }
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
if (sta->flags & WLAN_STA_PREAUTH) {
rsn_preauth_send(hapd, sta, buf, len);
} else {
@@ -96,12 +113,13 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
if (res && errno != ENOENT) {
- printf("Could not set station " MACSTR " flags for kernel "
- "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
+ wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
+ " flags for kernel driver (errno=%d).",
+ MAC2STR(sta->addr), errno);
}
if (authorized) {
- os_get_time(&sta->connected_time);
+ os_get_reltime(&sta->connected_time);
accounting_sta_start(hapd, sta);
}
}
@@ -186,114 +204,10 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
}
-#ifndef CONFIG_NO_VLAN
-static struct hostapd_wep_keys *
-ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
-{
- struct hostapd_wep_keys *key;
-
- key = os_zalloc(sizeof(*key));
- if (key == NULL)
- return NULL;
-
- key->default_len = hapd->conf->default_wep_key_len;
-
- if (key->idx >= hapd->conf->broadcast_key_idx_max ||
- key->idx < hapd->conf->broadcast_key_idx_min)
- key->idx = hapd->conf->broadcast_key_idx_min;
- else
- key->idx++;
-
- if (!key->key[key->idx])
- key->key[key->idx] = os_malloc(key->default_len);
- if (key->key[key->idx] == NULL ||
- random_get_bytes(key->key[key->idx], key->default_len)) {
- printf("Could not generate random WEP key (dynamic VLAN).\n");
- os_free(key->key[key->idx]);
- key->key[key->idx] = NULL;
- os_free(key);
- return NULL;
- }
- key->len[key->idx] = key->default_len;
-
- wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n",
- ifname, key->idx);
- wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
- key->key[key->idx], key->len[key->idx]);
-
- if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
- broadcast_ether_addr, key->idx, 1,
- NULL, 0, key->key[key->idx],
- key->len[key->idx]))
- printf("Could not set dynamic VLAN WEP encryption key.\n");
-
- hostapd_set_drv_ieee8021x(hapd, ifname, 1);
-
- return key;
-}
-
-
-static struct hostapd_wep_keys *
-ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,
- size_t vlan_id)
-{
- const char *ifname;
-
- if (vlan_id == 0)
- return &ssid->wep;
-
- if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&
- ssid->dyn_vlan_keys[vlan_id])
- return ssid->dyn_vlan_keys[vlan_id];
-
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group "
- "state machine for VLAN ID %lu",
- (unsigned long) vlan_id);
-
- ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
- if (ifname == NULL) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - "
- "cannot create group key state machine",
- (unsigned long) vlan_id);
- return NULL;
- }
-
- if (ssid->dyn_vlan_keys == NULL) {
- int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
- ssid->dyn_vlan_keys = os_zalloc(size);
- if (ssid->dyn_vlan_keys == NULL)
- return NULL;
- ssid->max_dyn_vlan_keys = vlan_id;
- }
-
- if (ssid->max_dyn_vlan_keys < vlan_id) {
- struct hostapd_wep_keys **na;
- int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
- na = os_realloc(ssid->dyn_vlan_keys, size);
- if (na == NULL)
- return NULL;
- ssid->dyn_vlan_keys = na;
- os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,
- (vlan_id - ssid->max_dyn_vlan_keys) *
- sizeof(ssid->dyn_vlan_keys[0]));
- ssid->max_dyn_vlan_keys = vlan_id;
- }
-
- ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);
-
- return ssid->dyn_vlan_keys[vlan_id];
-}
-#endif /* CONFIG_NO_VLAN */
-
-
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_authenticator *eapol = hapd->eapol_auth;
struct eapol_state_machine *sm = sta->eapol_sm;
-#ifndef CONFIG_NO_VLAN
- struct hostapd_wep_keys *key = NULL;
- int vlan_id;
-#endif /* CONFIG_NO_VLAN */
if (sm == NULL || !sm->eap_if->eapKeyData)
return;
@@ -302,18 +216,12 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
MAC2STR(sta->addr));
#ifndef CONFIG_NO_VLAN
- vlan_id = sta->vlan_id;
- if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
- vlan_id = 0;
-
- if (vlan_id) {
- key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);
- if (key && key->key[key->idx])
- ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
- key->key[key->idx],
- key->len[key->idx]);
- } else
+ if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
+ wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
+ return;
+ }
#endif /* CONFIG_NO_VLAN */
+
if (eapol->default_wep_key) {
ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
eapol->default_wep_key,
@@ -388,9 +296,15 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
{
const u8 *identity;
size_t identity_len;
+ const struct eap_hdr *hdr = (const struct eap_hdr *) eap;
if (len <= sizeof(struct eap_hdr) ||
- eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
+ (hdr->code == EAP_CODE_RESPONSE &&
+ eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) ||
+ (hdr->code == EAP_CODE_INITIATE &&
+ eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) ||
+ (hdr->code != EAP_CODE_RESPONSE &&
+ hdr->code != EAP_CODE_INITIATE))
return;
identity = eap_get_identity(sm->eap, &identity_len);
@@ -399,21 +313,80 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
/* Save station identity for future RADIUS packets */
os_free(sm->identity);
- sm->identity = os_malloc(identity_len + 1);
+ sm->identity = (u8 *) dup_binstr(identity, identity_len);
if (sm->identity == NULL) {
sm->identity_len = 0;
return;
}
- os_memcpy(sm->identity, identity, identity_len);
sm->identity_len = identity_len;
- sm->identity[identity_len] = '\0';
hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
sm->dot1xAuthEapolRespIdFramesRx++;
}
+static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ u32 suite;
+ int ver, val;
+
+ ver = wpa_auth_sta_wpa_version(sta->wpa_sm);
+ val = wpa_auth_get_pairwise(sta->wpa_sm);
+ suite = wpa_cipher_to_suite(ver, val);
+ if (val != -1 &&
+ !hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER,
+ suite)) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher");
+ return -1;
+ }
+
+ suite = wpa_cipher_to_suite((hapd->conf->wpa & 0x2) ?
+ WPA_PROTO_RSN : WPA_PROTO_WPA,
+ hapd->conf->wpa_group);
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_GROUP_CIPHER) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER,
+ suite)) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher");
+ return -1;
+ }
+
+ val = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+ suite = wpa_akm_to_suite(val);
+ if (val != -1 &&
+ !hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_AKM_SUITE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
+ suite)) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite");
+ return -1;
+ }
+
+#ifdef CONFIG_IEEE80211W
+ if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
+ hapd->conf->group_mgmt_cipher);
+ if (!hostapd_config_get_radius_attr(
+ req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) &&
+ !radius_msg_add_attr_int32(
+ msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) {
+ wpa_printf(MSG_ERROR,
+ "Could not add WLAN-Group-Mgmt-Cipher");
+ return -1;
+ }
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ return 0;
+}
+
+
static int add_common_radius_sta_attr(struct hostapd_data *hapd,
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
@@ -465,6 +438,25 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
}
}
+#ifdef CONFIG_IEEE80211R
+ 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)) ||
+ sta->auth_alg == WLAN_AUTH_FT) &&
+ !hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_MOBILITY_DOMAIN_ID) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID,
+ WPA_GET_BE16(
+ hapd->conf->mobility_domain))) {
+ wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ if (hapd->conf->wpa && sta->wpa_sm &&
+ add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
+ return -1;
+
return 0;
}
@@ -528,6 +520,22 @@ int add_common_radius_attr(struct hostapd_data *hapd,
return -1;
}
+#ifdef CONFIG_INTERWORKING
+ if (hapd->conf->interworking &&
+ !is_zero_ether_addr(hapd->conf->hessid)) {
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(hapd->conf->hessid));
+ buf[sizeof(buf) - 1] = '\0';
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_HESSID) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID");
+ return -1;
+ }
+ }
+#endif /* CONFIG_INTERWORKING */
+
if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
return -1;
@@ -564,7 +572,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
sm->radius_identifier);
if (msg == NULL) {
- printf("Could not create net RADIUS packet\n");
+ wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return;
}
@@ -573,7 +581,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
if (sm->identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
sm->identity, sm->identity_len)) {
- printf("Could not add User-Name\n");
+ wpa_printf(MSG_INFO, "Could not add User-Name");
goto fail;
}
@@ -587,12 +595,12 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
RADIUS_ATTR_FRAMED_MTU) &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
- printf("Could not add Framed-MTU\n");
+ wpa_printf(MSG_INFO, "Could not add Framed-MTU");
goto fail;
}
if (eap && !radius_msg_add_eap(msg, eap, len)) {
- printf("Could not add EAP-Message\n");
+ wpa_printf(MSG_INFO, "Could not add EAP-Message");
goto fail;
}
@@ -604,8 +612,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
- printf("Could not copy State attribute from previous "
- "Access-Challenge\n");
+ wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
goto fail;
}
if (res > 0) {
@@ -632,6 +639,41 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
}
}
+#ifdef CONFIG_HS20
+ if (hapd->conf->hs20) {
+ u8 ver = 1; /* Release 2 */
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
+ &ver, 1)) {
+ wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP "
+ "version");
+ goto fail;
+ }
+
+ if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) {
+ const u8 *pos;
+ u8 buf[3];
+ u16 id;
+ pos = wpabuf_head_u8(sta->hs20_ie);
+ buf[0] = (*pos) >> 4;
+ if (((*pos) & HS20_PPS_MO_ID_PRESENT) &&
+ wpabuf_len(sta->hs20_ie) >= 3)
+ id = WPA_GET_LE16(pos + 1);
+ else
+ id = 0;
+ WPA_PUT_BE16(buf + 1, id);
+ if (!radius_msg_add_wfa(
+ msg,
+ RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION,
+ buf, sizeof(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add HS 2.0 "
+ "STA version");
+ goto fail;
+ }
+ }
+ }
+#endif /* CONFIG_HS20 */
+
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
goto fail;
@@ -655,7 +697,7 @@ static void handle_eap_response(struct hostapd_data *hapd,
data = (u8 *) (eap + 1);
if (len < sizeof(*eap) + 1) {
- printf("handle_eap_response: too short response data\n");
+ wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
return;
}
@@ -675,6 +717,39 @@ static void handle_eap_response(struct hostapd_data *hapd,
}
+static void handle_eap_initiate(struct hostapd_data *hapd,
+ struct sta_info *sta, struct eap_hdr *eap,
+ size_t len)
+{
+#ifdef CONFIG_ERP
+ u8 type, *data;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return;
+
+ if (len < sizeof(*eap) + 1) {
+ wpa_printf(MSG_INFO,
+ "handle_eap_initiate: too short response data");
+ return;
+ }
+
+ data = (u8 *) (eap + 1);
+ type = data[0];
+
+ hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
+ "id=%d len=%d) from STA: EAP Initiate type %u",
+ eap->code, eap->identifier, be_to_host16(eap->length),
+ type);
+
+ wpabuf_free(sm->eap_if->eapRespData);
+ sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
+ sm->eapolEap = TRUE;
+#endif /* CONFIG_ERP */
+}
+
+
/* Process incoming EAP packet from Supplicant */
static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
@@ -683,7 +758,7 @@ static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
u16 eap_len;
if (len < sizeof(*eap)) {
- printf(" too short EAP packet\n");
+ wpa_printf(MSG_INFO, " too short EAP packet");
return;
}
@@ -718,6 +793,13 @@ static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
case EAP_CODE_FAILURE:
wpa_printf(MSG_DEBUG, " (failure)");
return;
+ case EAP_CODE_INITIATE:
+ wpa_printf(MSG_DEBUG, " (initiate)");
+ handle_eap_initiate(hapd, sta, eap, eap_len);
+ break;
+ case EAP_CODE_FINISH:
+ wpa_printf(MSG_DEBUG, " (finish)");
+ break;
default:
wpa_printf(MSG_DEBUG, " (unknown code)");
return;
@@ -761,7 +843,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
struct rsn_pmksa_cache_entry *pmksa;
int key_mgmt;
- if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen &&
!hapd->conf->wps_state)
return;
@@ -776,7 +858,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
}
if (len < sizeof(*hdr)) {
- printf(" too short IEEE 802.1X packet\n");
+ wpa_printf(MSG_INFO, " too short IEEE 802.1X packet");
return;
}
@@ -786,7 +868,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
hdr->version, hdr->type, datalen);
if (len - sizeof(*hdr) < datalen) {
- printf(" frame too short for this IEEE 802.1X packet\n");
+ wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet");
if (sta->eapol_sm)
sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
return;
@@ -812,7 +894,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
}
- if (!hapd->conf->ieee802_1x &&
+ if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
"802.1X not enabled and WPS not used");
@@ -832,7 +914,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
#ifdef CONFIG_WPS
- if (!hapd->conf->ieee802_1x) {
+ if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) {
u32 wflags = sta->flags & (WLAN_STA_WPS |
WLAN_STA_WPS2 |
WLAN_STA_MAYBE_WPS);
@@ -939,8 +1021,9 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
int key_mgmt;
#ifdef CONFIG_WPS
- if (hapd->conf->wps_state && hapd->conf->wpa &&
- (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+ if (hapd->conf->wps_state &&
+ ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) ||
+ (sta->flags & WLAN_STA_WPS))) {
/*
* Need to enable IEEE 802.1X/EAPOL state machines for possible
* WPS handshake even if IEEE 802.1X/EAPOL is not used for
@@ -950,7 +1033,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
}
#endif /* CONFIG_WPS */
- if (!force_1x && !hapd->conf->ieee802_1x) {
+ if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
"802.1X not enabled or forced for WPS");
/*
@@ -988,7 +1071,8 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_WPS
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
- if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
+ if (!hapd->conf->ieee802_1x && hapd->conf->wps_state &&
+ !(sta->flags & WLAN_STA_WPS2)) {
/*
* Delay EAPOL frame transmission until a possible WPS STA
* initiates the handshake with EAPOL-Start. Only allow the
@@ -1127,15 +1211,11 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
if (eap_type >= 0)
sm->eap_type_authsrv = eap_type;
os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
- eap_type >= 0 ? eap_server_get_name(0, eap_type) :
- "??",
- eap_type);
+ eap_server_get_name(0, eap_type), eap_type);
break;
case EAP_CODE_RESPONSE:
os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
- eap_type >= 0 ? eap_server_get_name(0, eap_type) :
- "??",
- eap_type);
+ eap_server_get_name(0, eap_type), eap_type);
break;
case EAP_CODE_SUCCESS:
os_strlcpy(buf, "EAP Success", sizeof(buf));
@@ -1191,6 +1271,11 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
sm->eap_if->aaaEapKeyDataLen = len;
sm->eap_if->aaaEapKeyAvailable = TRUE;
}
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p",
+ keys, keys ? keys->send : NULL,
+ keys ? keys->recv : NULL);
}
if (keys) {
@@ -1272,13 +1357,10 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
NULL) < 0)
return;
- identity = os_malloc(len + 1);
+ identity = (u8 *) dup_binstr(buf, len);
if (identity == NULL)
return;
- os_memcpy(identity, buf, len);
- identity[len] = '\0';
-
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
"User-Name from Access-Accept '%s'",
@@ -1317,6 +1399,147 @@ static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
}
+#ifdef CONFIG_HS20
+
+static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
+{
+ sta->remediation = 1;
+ os_free(sta->remediation_url);
+ if (len > 2) {
+ sta->remediation_url = os_malloc(len);
+ if (!sta->remediation_url)
+ return;
+ sta->remediation_method = pos[0];
+ os_memcpy(sta->remediation_url, pos + 1, len - 1);
+ sta->remediation_url[len - 1] = '\0';
+ wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
+ "for " MACSTR " - server method %u URL %s",
+ MAC2STR(sta->addr), sta->remediation_method,
+ sta->remediation_url);
+ } else {
+ sta->remediation_url = NULL;
+ wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
+ "for " MACSTR, MAC2STR(sta->addr));
+ }
+ /* TODO: assign the STA into remediation VLAN or add filtering */
+}
+
+
+static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *pos,
+ size_t len)
+{
+ if (len < 3)
+ return; /* Malformed information */
+ sta->hs20_deauth_requested = 1;
+ wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u "
+ "Re-auth Delay %u",
+ *pos, WPA_GET_LE16(pos + 1));
+ wpabuf_free(sta->hs20_deauth_req);
+ sta->hs20_deauth_req = wpabuf_alloc(len + 1);
+ if (sta->hs20_deauth_req) {
+ wpabuf_put_data(sta->hs20_deauth_req, pos, 3);
+ wpabuf_put_u8(sta->hs20_deauth_req, len - 3);
+ wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3);
+ }
+ ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout);
+}
+
+
+static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *pos,
+ size_t len, int session_timeout)
+{
+ unsigned int swt;
+ int warning_time, beacon_int;
+
+ if (len < 1)
+ return; /* Malformed information */
+ os_free(sta->hs20_session_info_url);
+ sta->hs20_session_info_url = os_malloc(len);
+ if (sta->hs20_session_info_url == NULL)
+ return;
+ swt = pos[0];
+ os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
+ sta->hs20_session_info_url[len - 1] = '\0';
+ wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u "
+ "(session_timeout=%d)",
+ sta->hs20_session_info_url, swt, session_timeout);
+ if (session_timeout < 0) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL");
+ return;
+ }
+ if (swt == 255)
+ swt = 1; /* Use one minute as the AP selected value */
+
+ if ((unsigned int) session_timeout < swt * 60)
+ warning_time = 0;
+ else
+ warning_time = session_timeout - swt * 60;
+
+ beacon_int = hapd->iconf->beacon_int;
+ if (beacon_int < 1)
+ beacon_int = 100; /* best guess */
+ sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128;
+ if (sta->hs20_disassoc_timer > 65535)
+ sta->hs20_disassoc_timer = 65535;
+
+ ap_sta_session_warning_timeout(hapd, sta, warning_time);
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg,
+ int session_timeout)
+{
+#ifdef CONFIG_HS20
+ u8 *buf, *pos, *end, type, sublen;
+ size_t len;
+
+ buf = NULL;
+ sta->remediation = 0;
+ sta->hs20_deauth_requested = 0;
+
+ 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 */
+
+ switch (type) {
+ case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION:
+ ieee802_1x_hs20_sub_rem(sta, pos, sublen);
+ break;
+ case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ:
+ ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen);
+ break;
+ case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL:
+ ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
+ session_timeout);
+ break;
+ }
+ }
+#endif /* CONFIG_HS20 */
+}
+
+
struct sta_id_search {
u8 identifier;
struct eapol_state_machine *sm;
@@ -1391,15 +1614,14 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
"EAP-Message");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req, 1)) {
- printf("Incoming RADIUS packet did not have correct "
- "Message-Authenticator - dropped\n");
+ wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
hdr->code != RADIUS_CODE_ACCESS_REJECT &&
hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
- printf("Unknown RADIUS message code\n");
+ wpa_printf(MSG_INFO, "Unknown RADIUS message code");
return RADIUS_RX_UNKNOWN;
}
@@ -1443,8 +1665,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
sta->vlan_id = radius_msg_get_vlanid(msg);
}
if (sta->vlan_id > 0 &&
- hostapd_get_vlan_id_ifname(hapd->conf->vlan,
- sta->vlan_id)) {
+ hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -1463,6 +1684,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
break;
+ sta->session_timeout_set = !!session_timeout_set;
+ sta->session_timeout = session_timeout;
+
/* RFC 3580, Ch. 3.17 */
if (session_timeout_set && termination_action ==
RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
@@ -1477,7 +1701,11 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
ieee802_1x_store_radius_class(hapd, sta, msg);
ieee802_1x_update_sta_identity(hapd, sta, msg);
ieee802_1x_update_sta_cui(hapd, sta, msg);
- if (sm->eap_if->eapKeyAvailable &&
+ 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) {
@@ -1564,7 +1792,7 @@ static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
if (eapol->default_wep_key == NULL ||
random_get_bytes(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
- printf("Could not generate random WEP key.\n");
+ wpa_printf(MSG_INFO, "Could not generate random WEP key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return -1;
@@ -1680,14 +1908,14 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
- int preauth)
+ int preauth, int remediation)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
if (preauth)
rsn_preauth_finished(hapd, sta, success);
else
- ieee802_1x_finished(hapd, sta, success);
+ ieee802_1x_finished(hapd, sta, success, remediation);
}
@@ -1720,7 +1948,9 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
user->password_hash = eap_user->password_hash;
}
user->force_version = eap_user->force_version;
+ user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
+ user->remediation = eap_user->remediation;
return 0;
}
@@ -1804,12 +2034,43 @@ static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
}
+#ifdef CONFIG_ERP
+
+static struct eap_server_erp_key *
+ieee802_1x_erp_get_key(void *ctx, const char *keyname)
+{
+ struct hostapd_data *hapd = ctx;
+ struct eap_server_erp_key *erp;
+
+ dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key,
+ list) {
+ if (os_strcmp(erp->keyname_nai, keyname) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+
+
+static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+ struct hostapd_data *hapd = ctx;
+
+ dl_list_add(&hapd->erp_keys, &erp->list);
+ return 0;
+}
+
+#endif /* CONFIG_ERP */
+
+
int ieee802_1x_init(struct hostapd_data *hapd)
{
int i;
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
+ dl_list_init(&hapd->erp_keys);
+
os_memset(&conf, 0, sizeof(conf));
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
@@ -1821,6 +2082,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
+ conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
+ conf.erp_domain = hapd->conf->erp_domain;
+ conf.erp = hapd->conf->eap_server_erp;
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;
@@ -1834,6 +2098,13 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.fragment_size = hapd->conf->fragment_size;
conf.pwd_group = hapd->conf->pwd_group;
conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
+ if (hapd->conf->server_id) {
+ conf.server_id = (const u8 *) hapd->conf->server_id;
+ conf.server_id_len = os_strlen(hapd->conf->server_id);
+ } else {
+ conf.server_id = (const u8 *) "hostapd";
+ conf.server_id_len = 7;
+ }
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
@@ -1846,6 +2117,10 @@ int ieee802_1x_init(struct hostapd_data *hapd)
cb.abort_auth = _ieee802_1x_abort_auth;
cb.tx_key = _ieee802_1x_tx_key;
cb.eapol_event = ieee802_1x_eapol_event;
+#ifdef CONFIG_ERP
+ cb.erp_get_key = ieee802_1x_erp_get_key;
+ cb.erp_add_key = ieee802_1x_erp_add_key;
+#endif /* CONFIG_ERP */
hapd->eapol_auth = eapol_auth_init(&conf, &cb);
if (hapd->eapol_auth == NULL)
@@ -1877,6 +2152,18 @@ int ieee802_1x_init(struct hostapd_data *hapd)
}
+void ieee802_1x_erp_flush(struct hostapd_data *hapd)
+{
+ struct eap_server_erp_key *erp;
+
+ while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key,
+ list)) != NULL) {
+ dl_list_del(&erp->list);
+ bin_clear_free(erp, sizeof(*erp));
+ }
+}
+
+
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
@@ -1887,6 +2174,8 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
eapol_auth_deinit(hapd->eapol_auth);
hapd->eapol_auth = NULL;
+
+ ieee802_1x_erp_flush(hapd);
}
@@ -2061,7 +2350,9 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
{
int len = 0, ret;
struct eapol_state_machine *sm = sta->eapol_sm;
- struct os_time t;
+ struct os_reltime diff;
+ const char *name1;
+ const char *name2;
if (sm == NULL)
return 0;
@@ -2075,7 +2366,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
sta->aid,
EAPOL_VERSION,
sm->initialize);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2103,7 +2394,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
sm->reAuthPeriod,
bool_txt(sm->reAuthEnabled),
bool_txt(sm->keyTxEnabled));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2133,7 +2424,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
sm->dot1xAuthEapLengthErrorFramesRx,
sm->dot1xAuthLastEapolFrameVersion,
MAC2STR(sm->addr));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2171,12 +2462,12 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
sm->backendOtherRequestsToSupplicant,
sm->backendAuthSuccesses,
sm->backendAuthFails);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
/* dot1xAuthSessionStatsTable */
- os_get_time(&t);
+ os_reltime_age(&sta->acct_session_start, &diff);
ret = os_snprintf(buf + len, buflen - len,
/* TODO: dot1xAuthSessionOctetsRx */
/* TODO: dot1xAuthSessionOctetsTx */
@@ -2191,9 +2482,30 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
(wpa_key_mgmt_wpa_ieee8021x(
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
1 : 2,
- (unsigned int) (t.sec - sta->acct_session_start),
+ (unsigned int) diff.sec,
sm->identity);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ if (sm->acct_multi_session_id_hi) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "authMultiSessionId=%08X+%08X\n",
+ sm->acct_multi_session_id_hi,
+ sm->acct_multi_session_id_lo);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ name1 = eap_server_get_name(0, sm->eap_type_authsrv);
+ name2 = eap_server_get_name(0, sm->eap_type_supp);
+ ret = os_snprintf(buf + len, buflen - len,
+ "last_eap_type_as=%d (%s)\n"
+ "last_eap_type_sta=%d (%s)\n",
+ sm->eap_type_authsrv, name1,
+ sm->eap_type_supp, name2);
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2202,16 +2514,55 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
static void ieee802_1x_finished(struct hostapd_data *hapd,
- struct sta_info *sta, int success)
+ struct sta_info *sta, int success,
+ int remediation)
{
const u8 *key;
size_t len;
/* TODO: get PMKLifetime from WPA parameters */
static const int dot11RSNAConfigPMKLifetime = 43200;
+ unsigned int session_timeout;
+
+#ifdef CONFIG_HS20
+ if (remediation && !sta->remediation) {
+ sta->remediation = 1;
+ os_free(sta->remediation_url);
+ sta->remediation_url =
+ os_strdup(hapd->conf->subscr_remediation_url);
+ 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);
+ }
+ }
+#endif /* CONFIG_HS20 */
key = ieee802_1x_get_key(sta->eapol_sm, &len);
- if (success && key && len >= PMK_LEN &&
- wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
+ if (sta->session_timeout_set)
+ session_timeout = sta->session_timeout;
+ 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,
sta->eapol_sm) == 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
@@ -2238,5 +2589,6 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
os_sleep(0, 10000);
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+ hostapd_wps_eap_completed(hapd);
}
}
diff --git a/contrib/wpa/src/ap/ieee802_1x.h b/contrib/wpa/src/ap/ieee802_1x.h
index e1df940..de6e0e7 100644
--- a/contrib/wpa/src/ap/ieee802_1x.h
+++ b/contrib/wpa/src/ap/ieee802_1x.h
@@ -29,6 +29,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
int ieee802_1x_init(struct hostapd_data *hapd);
+void ieee802_1x_erp_flush(struct hostapd_data *hapd);
void ieee802_1x_deinit(struct hostapd_data *hapd);
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack);
diff --git a/contrib/wpa/src/ap/ndisc_snoop.c b/contrib/wpa/src/ap/ndisc_snoop.c
new file mode 100644
index 0000000..b0d42dc
--- /dev/null
+++ b/contrib/wpa/src/ap/ndisc_snoop.c
@@ -0,0 +1,171 @@
+/*
+ * Neighbor Discovery snooping for Proxy ARP
+ * Copyright (c) 2014, 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 <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include "utils/common.h"
+#include "l2_packet/l2_packet.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "list.h"
+#include "x_snoop.h"
+
+struct ip6addr {
+ struct in6_addr addr;
+ struct dl_list list;
+};
+
+struct icmpv6_ndmsg {
+ struct ip6_hdr ipv6h;
+ struct icmp6_hdr icmp6h;
+ struct in6_addr target_addr;
+ u8 opt_type;
+ u8 len;
+ u8 opt_lladdr[0];
+} STRUCT_PACKED;
+
+#define ROUTER_ADVERTISEMENT 134
+#define NEIGHBOR_SOLICITATION 135
+#define NEIGHBOR_ADVERTISEMENT 136
+#define SOURCE_LL_ADDR 1
+
+static int sta_ip6addr_add(struct sta_info *sta, struct in6_addr *addr)
+{
+ struct ip6addr *ip6addr;
+
+ ip6addr = os_zalloc(sizeof(*ip6addr));
+ if (!ip6addr)
+ return -1;
+
+ os_memcpy(&ip6addr->addr, addr, sizeof(*addr));
+
+ dl_list_add_tail(&sta->ip6addr, &ip6addr->list);
+
+ return 0;
+}
+
+
+void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct ip6addr *ip6addr, *prev;
+
+ dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
+ list) {
+ hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
+ os_free(ip6addr);
+ }
+}
+
+
+static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
+{
+ struct ip6addr *ip6addr;
+
+ dl_list_for_each(ip6addr, &sta->ip6addr, struct ip6addr, list) {
+ if (ip6addr->addr.s6_addr32[0] == addr->s6_addr32[0] &&
+ ip6addr->addr.s6_addr32[1] == addr->s6_addr32[1] &&
+ ip6addr->addr.s6_addr32[2] == addr->s6_addr32[2] &&
+ ip6addr->addr.s6_addr32[3] == addr->s6_addr32[3])
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct icmpv6_ndmsg *msg;
+ struct in6_addr *saddr;
+ struct sta_info *sta;
+ int res;
+ char addrtxt[INET6_ADDRSTRLEN + 1];
+
+ if (len < ETH_HLEN + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
+ return;
+ msg = (struct icmpv6_ndmsg *) &buf[ETH_HLEN];
+ switch (msg->icmp6h.icmp6_type) {
+ case NEIGHBOR_SOLICITATION:
+ if (len < ETH_HLEN + sizeof(*msg))
+ return;
+ if (msg->opt_type != SOURCE_LL_ADDR)
+ return;
+
+ saddr = &msg->ipv6h.ip6_src;
+ if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
+ saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
+ if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
+ return;
+ sta = ap_get_sta(hapd, msg->opt_lladdr);
+ if (!sta)
+ return;
+
+ if (sta_has_ip6addr(sta, saddr))
+ return;
+
+ if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
+ == NULL)
+ addrtxt[0] = '\0';
+ wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for "
+ MACSTR, addrtxt, MAC2STR(sta->addr));
+ hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
+ res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
+ 128, sta->addr);
+ if (res) {
+ wpa_printf(MSG_ERROR,
+ "ndisc_snoop: Adding ip neigh failed: %d",
+ res);
+ return;
+ }
+
+ if (sta_ip6addr_add(sta, saddr))
+ return;
+ }
+ break;
+ case ROUTER_ADVERTISEMENT:
+ if (!hapd->conf->disable_dgaf)
+ return;
+ /* fall through */
+ case NEIGHBOR_ADVERTISEMENT:
+ 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);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+int ndisc_snoop_init(struct hostapd_data *hapd)
+{
+ hapd->sock_ndisc = x_snoop_get_l2_packet(hapd, handle_ndisc,
+ L2_PACKET_FILTER_NDISC);
+ if (hapd->sock_ndisc == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "ndisc_snoop: Failed to initialize L2 packet processing for NDISC packets: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void ndisc_snoop_deinit(struct hostapd_data *hapd)
+{
+ l2_packet_deinit(hapd->sock_ndisc);
+}
diff --git a/contrib/wpa/src/ap/ndisc_snoop.h b/contrib/wpa/src/ap/ndisc_snoop.h
new file mode 100644
index 0000000..3cc9a55
--- /dev/null
+++ b/contrib/wpa/src/ap/ndisc_snoop.h
@@ -0,0 +1,36 @@
+/*
+ * Neighbor Discovery snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NDISC_SNOOP_H
+#define NDISC_SNOOP_H
+
+#if defined(CONFIG_PROXYARP) && defined(CONFIG_IPV6)
+
+int ndisc_snoop_init(struct hostapd_data *hapd);
+void ndisc_snoop_deinit(struct hostapd_data *hapd);
+void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
+
+#else /* CONFIG_PROXYARP && CONFIG_IPV6 */
+
+static inline int ndisc_snoop_init(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+static inline void ndisc_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline void sta_ip6addr_del(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_PROXYARP && CONFIG_IPV6 */
+
+#endif /* NDISC_SNOOP_H */
diff --git a/contrib/wpa/src/ap/p2p_hostapd.c b/contrib/wpa/src/ap/p2p_hostapd.c
index 795d313..9be640c 100644
--- a/contrib/wpa/src/ap/p2p_hostapd.c
+++ b/contrib/wpa/src/ap/p2p_hostapd.c
@@ -96,9 +96,8 @@ u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
u8 bitmap;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
*eid++ = 4 + 3 + 1;
- WPA_PUT_BE24(eid, OUI_WFA);
- eid += 3;
- *eid++ = P2P_OUI_TYPE;
+ WPA_PUT_BE32(eid, P2P_IE_VENDOR_TYPE);
+ eid += 4;
*eid++ = P2P_ATTR_MANAGEABILITY;
WPA_PUT_LE16(eid, 1);
diff --git a/contrib/wpa/src/ap/peerkey_auth.c b/contrib/wpa/src/ap/peerkey_auth.c
index ba5c606..efc1d7e 100644
--- a/contrib/wpa/src/ap/peerkey_auth.c
+++ b/contrib/wpa/src/ap/peerkey_auth.c
@@ -79,15 +79,15 @@ static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+ 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((const u8 *) (key + 1),
- WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+ 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;
}
@@ -221,8 +221,8 @@ static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
return;
/* Peer RSN IE */
- os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
- pos = buf + kde->rsn_ie_len;
+ 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);
@@ -253,14 +253,14 @@ static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+ 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((const u8 *) (key + 1),
- WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+ 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;
}
@@ -324,15 +324,15 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+ 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((const u8 *) (key + 1),
- WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+ 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;
}
diff --git a/contrib/wpa/src/ap/pmksa_cache_auth.c b/contrib/wpa/src/ap/pmksa_cache_auth.c
index d27fd30..877affe 100644
--- a/contrib/wpa/src/ap/pmksa_cache_auth.c
+++ b/contrib/wpa/src/ap/pmksa_cache_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * 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.
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
+#include "radius/radius_das.h"
#include "sta_info.h"
#include "ap_config.h"
#include "pmksa_cache_auth.h"
@@ -37,53 +38,55 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
- if (entry == NULL)
- return;
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
- os_free(entry);
+ bin_clear_free(entry, sizeof(*entry));
}
-static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
- struct rsn_pmksa_cache_entry *entry)
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
+ unsigned int hash;
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx);
- pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+
+ /* unlink from hash list */
+ hash = PMKID_HASH(entry->pmkid);
+ pos = pmksa->pmkid[hash];
prev = NULL;
while (pos) {
if (pos == entry) {
- if (prev != NULL) {
- prev->hnext = pos->hnext;
- } else {
- pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
- pos->hnext;
- }
+ if (prev != NULL)
+ prev->hnext = entry->hnext;
+ else
+ pmksa->pmkid[hash] = entry->hnext;
break;
}
prev = pos;
pos = pos->hnext;
}
+ /* unlink from entry list */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL)
- prev->next = pos->next;
+ prev->next = entry->next;
else
- pmksa->pmksa = pos->next;
+ pmksa->pmksa = entry->next;
break;
}
prev = pos;
pos = pos->next;
}
+
_pmksa_cache_free_entry(entry);
}
@@ -91,9 +94,9 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(pmksa->pmksa->spa));
@@ -107,12 +110,12 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
{
int sec;
- struct os_time now;
+ struct os_reltime now;
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
if (pmksa->pmksa == NULL)
return;
- os_get_time(&now);
+ os_get_reltime(&now);
sec = pmksa->pmksa->expiration - now.sec;
if (sec < 0)
sec = 0;
@@ -144,6 +147,9 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
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;
}
@@ -181,6 +187,9 @@ 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;
+
+ eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
+ eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
}
@@ -188,6 +197,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
+ int hash;
/* Add the new entry; order by expiration time */
pos = pmksa->pmksa;
@@ -205,8 +215,10 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
entry->next = prev->next;
prev->next = entry;
}
- entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
- pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
+
+ hash = PMKID_HASH(entry->pmkid);
+ entry->hnext = pmksa->pmkid[hash];
+ pmksa->pmkid[hash] = entry;
pmksa->pmksa_count++;
if (prev == NULL)
@@ -222,6 +234,8 @@ 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)
+ * @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
@@ -237,23 +251,32 @@ 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 *aa, const u8 *spa, int session_timeout,
- struct eapol_state_machine *eapol, int akmp)
+ 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 os_time now;
+ struct os_reltime now;
if (pmk_len > PMK_LEN)
return NULL;
+ if (wpa_key_mgmt_suite_b(akmp) && !kck)
+ return NULL;
+
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
- os_get_time(&now);
+ 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));
+ os_get_reltime(&now);
entry->expiration = now.sec;
if (session_timeout > 0)
entry->expiration += session_timeout;
@@ -342,6 +365,8 @@ void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
_pmksa_cache_free_entry(prev);
}
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+ pmksa->pmksa_count = 0;
+ pmksa->pmksa = NULL;
for (i = 0; i < PMKID_HASH_SIZE; i++)
pmksa->pmkid[i] = NULL;
os_free(pmksa);
@@ -361,18 +386,22 @@ pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
{
struct rsn_pmksa_cache_entry *entry;
- if (pmkid)
- entry = pmksa->pmkid[PMKID_HASH(pmkid)];
- else
- entry = pmksa->pmksa;
- while (entry) {
- if ((spa == NULL ||
- os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
- (pmkid == NULL ||
- os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
- return entry;
- entry = pmkid ? entry->hnext : entry->next;
+ if (pmkid) {
+ for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
+ entry = entry->hnext) {
+ if ((spa == NULL ||
+ os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
+ os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
+ return entry;
+ }
+ } else {
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ if (spa == NULL ||
+ os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
+ return entry;
+ }
}
+
return NULL;
}
@@ -394,15 +423,13 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache_entry *entry;
u8 new_pmkid[PMKID_LEN];
- entry = pmksa->pmksa;
- while (entry) {
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
wpa_key_mgmt_sha256(entry->akmp));
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
- entry = entry->next;
}
return NULL;
}
@@ -428,3 +455,74 @@ pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
return pmksa;
}
+
+
+static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
+ struct radius_das_attrs *attr)
+{
+ int match = 0;
+
+ if (attr->sta_addr) {
+ if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->acct_multi_session_id) {
+ char buf[20];
+
+ if (attr->acct_multi_session_id_len != 17)
+ 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)
+ return 0;
+ match++;
+ }
+
+ if (attr->cui) {
+ if (!entry->cui ||
+ attr->cui_len != wpabuf_len(entry->cui) ||
+ os_memcmp(attr->cui, wpabuf_head(entry->cui),
+ attr->cui_len) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->user_name) {
+ if (!entry->identity ||
+ attr->user_name_len != entry->identity_len ||
+ os_memcmp(attr->user_name, entry->identity,
+ attr->user_name_len) != 0)
+ return 0;
+ match++;
+ }
+
+ return match;
+}
+
+
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+ struct radius_das_attrs *attr)
+{
+ int found = 0;
+ struct rsn_pmksa_cache_entry *entry, *prev;
+
+ if (attr->acct_session_id)
+ return -1;
+
+ entry = pmksa->pmksa;
+ while (entry) {
+ if (das_attr_match(entry, attr)) {
+ found++;
+ prev = entry;
+ entry = entry->next;
+ pmksa_cache_free_entry(pmksa, prev);
+ continue;
+ }
+ entry = entry->next;
+ }
+
+ return found ? 0 : -1;
+}
diff --git a/contrib/wpa/src/ap/pmksa_cache_auth.h b/contrib/wpa/src/ap/pmksa_cache_auth.h
index d473f3f..8b7be12 100644
--- a/contrib/wpa/src/ap/pmksa_cache_auth.h
+++ b/contrib/wpa/src/ap/pmksa_cache_auth.h
@@ -30,6 +30,9 @@ struct rsn_pmksa_cache_entry {
u8 eap_type_authsrv;
int vlan_id;
int opportunistic;
+
+ u32 acct_multi_session_id_hi;
+ u32 acct_multi_session_id_lo;
};
struct rsn_pmksa_cache;
@@ -47,6 +50,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_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, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *
@@ -55,5 +59,9 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid);
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol);
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry);
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+ struct radius_das_attrs *attr);
#endif /* PMKSA_CACHE_H */
diff --git a/contrib/wpa/src/ap/sta_info.c b/contrib/wpa/src/ap/sta_info.c
index 97cd013..7e75e1a 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-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,9 +12,9 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
-#include "drivers/driver.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "accounting.h"
@@ -30,11 +30,14 @@
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "gas_serv.h"
+#include "wnm_ap.h"
+#include "ndisc_snoop.h"
#include "sta_info.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
@@ -69,6 +72,30 @@ struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
}
+#ifdef CONFIG_P2P
+struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct sta_info *sta;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ const u8 *p2p_dev_addr;
+
+ if (sta->p2p_ie == NULL)
+ continue;
+
+ p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
+ if (p2p_dev_addr == NULL)
+ continue;
+
+ if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
+ return sta;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_P2P */
+
+
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sta_info *tmp;
@@ -118,6 +145,12 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
}
+void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ sta_ip6addr_del(hapd, sta);
+}
+
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -128,9 +161,14 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
ap_sta_set_authorized(hapd, sta, 0);
if (sta->flags & WLAN_STA_WDS)
- hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
+ hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
+
+ if (sta->ipaddr)
+ hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
+ ap_sta_ip6addr_del(hapd, sta);
- if (!(sta->flags & WLAN_STA_PREAUTH))
+ if (!hapd->iface->driver_ap_teardown &&
+ !(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
ap_sta_hash_del(hapd, sta);
@@ -179,6 +217,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
hapd->iface->num_sta_ht_20mhz--;
}
+#ifdef CONFIG_IEEE80211N
+ ht40_intolerant_remove(hapd->iface, sta);
+#endif /* CONFIG_IEEE80211N */
+
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
sta->no_p2p_set = 0;
@@ -193,6 +235,11 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
set_beacon++;
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+#ifdef CONFIG_MESH
+ if (hapd->mesh_sta_free_cb)
+ hapd->mesh_sta_free_cb(sta);
+#endif /* CONFIG_MESH */
+
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
@@ -200,17 +247,19 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
__func__, MAC2STR(sta->addr));
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+ eloop_cancel_timeout(ap_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);
+ sae_clear_retransmit_timer(hapd, sta);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
rsn_preauth_free_station(hapd, sta);
#ifndef CONFIG_NO_RADIUS
- radius_client_flush_auth(hapd->radius, sta->addr);
+ if (hapd->radius)
+ radius_client_flush_auth(hapd->radius, sta->addr);
#endif /* CONFIG_NO_RADIUS */
- os_free(sta->last_assoc_req);
os_free(sta->challenge);
#ifdef CONFIG_IEEE80211W
@@ -236,9 +285,18 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->hs20_ie);
os_free(sta->ht_capabilities);
+ os_free(sta->vht_capabilities);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
+ os_free(sta->remediation_url);
+ wpabuf_free(sta->hs20_deauth_req);
+ os_free(sta->hs20_session_info_url);
+
+#ifdef CONFIG_SAE
+ sae_clear_data(sta->sae);
+ os_free(sta->sae);
+#endif /* CONFIG_SAE */
os_free(sta);
}
@@ -277,6 +335,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
+ int reason;
wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
__func__, MAC2STR(sta->addr), sta->flags,
@@ -311,8 +370,15 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
* but do not disconnect the station now.
*/
next_time = hapd->conf->ap_max_inactivity + fuzz;
- } else if (inactive_sec < hapd->conf->ap_max_inactivity &&
- sta->flags & WLAN_STA_ASSOC) {
+ } else if (inactive_sec == -ENOENT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Station " MACSTR " has lost its driver entry",
+ MAC2STR(sta->addr));
+
+ /* Avoid sending client probe on removed client */
+ sta->timeout_next = STA_DISASSOC;
+ goto skip_poll;
+ } else if (inactive_sec < hapd->conf->ap_max_inactivity) {
/* station activity detected; reset timeout state */
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been active %is ago",
@@ -344,6 +410,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
next_time = hapd->conf->ap_max_inactivity;
}
+skip_poll:
if (next_time) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%lu seconds)",
@@ -372,9 +439,11 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
} else {
- hostapd_drv_sta_disassoc(
- hapd, sta->addr,
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+ reason = (sta->timeout_next == STA_DISASSOC) ?
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
+ WLAN_REASON_PREV_AUTH_NOT_VALID;
+
+ hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
}
}
@@ -388,6 +457,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hapd, sta);
break;
case STA_DISASSOC:
+ case STA_DISASSOC_FROM_CLI:
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -399,14 +469,16 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
+ reason = (sta->timeout_next == STA_DISASSOC) ?
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
+ WLAN_REASON_PREV_AUTH_NOT_VALID;
sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
__func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
hapd, sta);
- mlme_disassociate_indication(
- hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+ mlme_disassociate_indication(hapd, sta, reason);
break;
case STA_DEAUTH:
case STA_REMOVE:
@@ -429,7 +501,6 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
- u8 addr[ETH_ALEN];
if (!(sta->flags & WLAN_STA_AUTH)) {
if (sta->flags & WLAN_STA_GAS) {
@@ -440,6 +511,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
return;
}
+ hostapd_drv_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -447,9 +520,19 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
"session timeout");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
- os_memcpy(addr, sta->addr, ETH_ALEN);
ap_free_sta(hapd, sta);
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
+void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+ u32 session_timeout)
+{
+ if (eloop_replenish_timeout(session_timeout, 0,
+ ap_handle_session_timer, hapd, sta) == 1) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "setting session timeout "
+ "to %d seconds", session_timeout);
+ }
}
@@ -471,6 +554,32 @@ 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
+ 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));
+ 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 */
+}
+
+
+void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
+ struct sta_info *sta, int warning_time)
+{
+ eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
+ eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer,
+ hapd, sta);
+}
+
+
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
@@ -495,13 +604,16 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
accounting_sta_get_id(hapd, sta);
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - ap_max_inactivity)",
+ __func__, MAC2STR(addr),
+ hapd->conf->ap_max_inactivity);
+ eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+ ap_handle_timer, hapd, sta);
+ }
+
/* initialize STA info data */
- wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
- "for " MACSTR " (%d seconds - ap_max_inactivity)",
- __func__, MAC2STR(addr),
- hapd->conf->ap_max_inactivity);
- eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
- ap_handle_timer, hapd, sta);
os_memcpy(sta->addr, addr, ETH_ALEN);
sta->next = hapd->sta_list;
hapd->sta_list = sta;
@@ -509,6 +621,8 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
ap_sta_hash_add(hapd, sta);
sta->ssid = &hapd->conf->ssid;
ap_sta_remove_in_other_bss(hapd, sta);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+ dl_list_init(&sta->ip6addr);
return sta;
}
@@ -518,6 +632,10 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
{
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ if (sta->ipaddr)
+ 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));
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
@@ -570,7 +688,8 @@ 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->flags &= ~WLAN_STA_ASSOC;
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
@@ -608,7 +727,8 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
{
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
@@ -663,13 +783,6 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->vlan_id == old_vlanid)
return 0;
- /*
- * During 1x reauth, if the vlan id changes, then remove the old id and
- * proceed furthur to add the new one.
- */
- if (old_vlanid > 0)
- vlan_remove_dynamic(hapd, old_vlanid);
-
iface = hapd->conf->iface;
if (sta->ssid->vlan[0])
iface = sta->ssid->vlan;
@@ -677,15 +790,19 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
else if (sta->vlan_id > 0) {
+ struct hostapd_vlan *wildcard_vlan = NULL;
vlan = hapd->conf->vlan;
while (vlan) {
- if (vlan->vlan_id == sta->vlan_id ||
- vlan->vlan_id == VLAN_ID_WILDCARD) {
- iface = vlan->ifname;
+ if (vlan->vlan_id == sta->vlan_id)
break;
- }
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ wildcard_vlan = vlan;
vlan = vlan->next;
}
+ if (!vlan)
+ vlan = wildcard_vlan;
+ if (vlan)
+ iface = vlan->ifname;
}
if (sta->vlan_id > 0 && vlan == NULL) {
@@ -693,7 +810,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
sta->vlan_id);
- return -1;
+ 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) {
@@ -702,7 +820,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_DEBUG, "could not add "
"dynamic VLAN interface for vlan_id=%d",
sta->vlan_id);
- return -1;
+ ret = -1;
+ goto done;
}
iface = vlan->ifname;
@@ -756,6 +875,12 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
"entry to vlan_id=%d", sta->vlan_id);
}
+
+done:
+ /* During 1x reauth, if the vlan id changes, then remove the old id. */
+ if (old_vlanid > 0)
+ vlan_remove_dynamic(hapd, old_vlanid);
+
return ret;
#else /* CONFIG_NO_VLAN */
return 0;
@@ -768,9 +893,9 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
- struct os_time now, passed;
- os_get_time(&now);
- os_time_sub(&now, &sta->sa_query_start, &passed);
+ struct os_reltime now, passed;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout < tu) {
hostapd_logger(hapd, sta->addr,
@@ -807,13 +932,21 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
return;
if (sta->sa_query_count == 0) {
/* Starting a new SA Query procedure */
- os_get_time(&sta->sa_query_start);
+ os_get_reltime(&sta->sa_query_start);
}
trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
sta->sa_query_trans_id = nbuf;
sta->sa_query_count++;
- os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+ if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
+ /*
+ * We don't really care which ID is used here, so simply
+ * hardcode this if the mostly theoretical os_get_random()
+ * failure happens.
+ */
+ trans_id[0] = 0x12;
+ trans_id[1] = 0x34;
+ }
timeout = hapd->conf->assoc_sa_query_retry_timeout;
sec = ((timeout / 1000) * 1024) / 1000;
@@ -849,13 +982,20 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
const u8 *dev_addr = NULL;
+ char buf[100];
#ifdef CONFIG_P2P
u8 addr[ETH_ALEN];
+ u8 ip_addr_buf[4];
#endif /* CONFIG_P2P */
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
+ if (authorized)
+ sta->flags |= WLAN_STA_AUTHORIZED;
+ else
+ sta->flags &= ~WLAN_STA_AUTHORIZED;
+
#ifdef CONFIG_P2P
if (hapd->p2p_group == NULL) {
if (sta->p2p_ie != NULL &&
@@ -863,52 +1003,46 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
dev_addr = addr;
} else
dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+
+ if (dev_addr)
+ os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
+ MAC2STR(sta->addr), MAC2STR(dev_addr));
+ else
#endif /* CONFIG_P2P */
+ os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
+
+ if (hapd->sta_authorized_cb)
+ hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
+ sta->addr, authorized, dev_addr);
if (authorized) {
- if (dev_addr)
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
- MACSTR " p2p_dev_addr=" MACSTR,
- MAC2STR(sta->addr), MAC2STR(dev_addr));
- else
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
- MACSTR, MAC2STR(sta->addr));
- if (hapd->msg_ctx_parent &&
- hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED MACSTR " p2p_dev_addr="
- MACSTR,
- MAC2STR(sta->addr), MAC2STR(dev_addr));
- else if (hapd->msg_ctx_parent &&
- hapd->msg_ctx_parent != hapd->msg_ctx)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+ char ip_addr[100];
+ ip_addr[0] = '\0';
+#ifdef CONFIG_P2P
+ if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
+ os_snprintf(ip_addr, sizeof(ip_addr),
+ " ip_addr=%u.%u.%u.%u",
+ ip_addr_buf[0], ip_addr_buf[1],
+ ip_addr_buf[2], ip_addr_buf[3]);
+ }
+#endif /* CONFIG_P2P */
- sta->flags |= WLAN_STA_AUTHORIZED;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
+ buf, ip_addr);
+
+ if (hapd->msg_ctx_parent &&
+ hapd->msg_ctx_parent != hapd->msg_ctx)
+ wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
+ AP_STA_CONNECTED "%s%s",
+ buf, ip_addr);
} else {
- if (dev_addr)
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
- MACSTR " p2p_dev_addr=" MACSTR,
- MAC2STR(sta->addr), MAC2STR(dev_addr));
- else
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
- MACSTR, MAC2STR(sta->addr));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
+
if (hapd->msg_ctx_parent &&
- hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
- MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
- else if (hapd->msg_ctx_parent &&
- hapd->msg_ctx_parent != hapd->msg_ctx)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
- sta->flags &= ~WLAN_STA_AUTHORIZED;
+ hapd->msg_ctx_parent != hapd->msg_ctx)
+ wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
+ AP_STA_DISCONNECTED "%s", buf);
}
-
- if (hapd->sta_authorized_cb)
- hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
- sta->addr, authorized, dev_addr);
}
@@ -969,3 +1103,36 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
ap_sta_disassoc_cb_timeout(hapd, sta);
}
+
+
+int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
+{
+ int res;
+
+ buf[0] = '\0';
+ res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
+ (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
+ (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
+ (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
+ ""),
+ (flags & WLAN_STA_SHORT_PREAMBLE ?
+ "[SHORT_PREAMBLE]" : ""),
+ (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
+ (flags & WLAN_STA_WMM ? "[WMM]" : ""),
+ (flags & WLAN_STA_MFP ? "[MFP]" : ""),
+ (flags & WLAN_STA_WPS ? "[WPS]" : ""),
+ (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
+ (flags & WLAN_STA_WDS ? "[WDS]" : ""),
+ (flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
+ (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
+ (flags & WLAN_STA_GAS ? "[GAS]" : ""),
+ (flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
+ (flags & WLAN_STA_WNM_SLEEP_MODE ?
+ "[WNM_SLEEP_MODE]" : ""));
+ if (os_snprintf_error(buflen, res))
+ res = -1;
+
+ return res;
+}
diff --git a/contrib/wpa/src/ap/sta_info.h b/contrib/wpa/src/ap/sta_info.h
index d5e92fa..57551ab 100644
--- a/contrib/wpa/src/ap/sta_info.h
+++ b/contrib/wpa/src/ap/sta_info.h
@@ -9,12 +9,16 @@
#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"
+
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3)
-#define WLAN_STA_PERM BIT(4)
#define WLAN_STA_AUTHORIZED BIT(5)
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_STA_SHORT_PREAMBLE BIT(7)
@@ -29,6 +33,9 @@
#define WLAN_STA_WPS2 BIT(16)
#define WLAN_STA_GAS BIT(17)
#define WLAN_STA_VHT BIT(18)
+#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
+#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
+#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -42,6 +49,8 @@ struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
u8 addr[6];
+ 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 */
u32 flags; /* Bitfield of WLAN_STA_* */
u16 capability;
@@ -50,19 +59,39 @@ struct sta_info {
int supported_rates_len;
u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
+#ifdef CONFIG_MESH
+ enum mesh_plink_state plink_state;
+ u16 peer_lid;
+ u16 my_lid;
+ u16 mpm_close_reason;
+ int mpm_retries;
+ u8 my_nonce[32];
+ u8 peer_nonce[32];
+ u8 aek[32]; /* SHA256 digest length */
+ u8 mtk[16];
+ u8 mgtk[16];
+ u8 sae_auth_retry;
+#endif /* CONFIG_MESH */
+
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
unsigned int no_short_preamble_set:1;
unsigned int no_ht_gf_set:1;
unsigned int no_ht_set:1;
+ unsigned int ht40_intolerant_set:1;
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
+ unsigned int qos_map_enabled:1;
+ unsigned int remediation:1;
+ unsigned int hs20_deauth_requested:1;
+ unsigned int session_timeout_set:1;
+ unsigned int radius_das_match:1;
u16 auth_alg;
- u8 previous_ap[6];
enum {
- STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
+ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE,
+ STA_DISASSOC_FROM_CLI
} timeout_next;
u16 deauth_reason;
@@ -71,12 +100,9 @@ struct sta_info {
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
- /* IEEE 802.11f (IAPP) related data */
- struct ieee80211_mgmt *last_assoc_req;
-
u32 acct_session_id_hi;
u32 acct_session_id_lo;
- time_t acct_session_start;
+ struct os_reltime acct_session_start;
int acct_session_started;
int acct_terminate_cause; /* Acct-Terminate-Cause */
int acct_interim_interval; /* Acct-Interim-Interval */
@@ -103,6 +129,7 @@ struct sta_info {
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
+ u8 vht_opmode;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
@@ -111,7 +138,7 @@ struct sta_info {
u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
* sa_query_count octets of pending SA Query
* transaction identifiers */
- struct os_time sa_query_start;
+ struct os_reltime sa_query_start;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_INTERWORKING
@@ -123,13 +150,25 @@ struct sta_info {
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 */
+ u8 remediation_method;
+ char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
+ struct wpabuf *hs20_deauth_req;
+ char *hs20_session_info_url;
+ int hs20_disassoc_timer;
- struct os_time connected_time;
+ struct os_reltime connected_time;
#ifdef CONFIG_SAE
- enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
- u16 sae_send_confirm;
+ struct sae_data *sae;
#endif /* CONFIG_SAE */
+
+ u32 session_timeout; /* valid only if session_timeout_set == 1 */
+
+ /* Last Authentication/(Re)Association Request/Action frame sequence
+ * control */
+ u16 last_seq_ctrl;
+ /* Last Authentication/(Re)Association Request/Action frame subtype */
+ u8 last_subtype;
};
@@ -156,14 +195,20 @@ int ap_for_each_sta(struct hostapd_data *hapd,
void *ctx),
void *ctx);
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
+struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr);
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_free_stas(struct hostapd_data *hapd);
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
+void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+ u32 session_timeout);
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
u32 session_timeout);
void ap_sta_no_session_timeout(struct hostapd_data *hapd,
struct sta_info *sta);
+void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
+ struct sta_info *sta, int warning_time);
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
@@ -191,4 +236,6 @@ 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);
+int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
+
#endif /* STA_INFO_H */
diff --git a/contrib/wpa/src/ap/tkip_countermeasures.c b/contrib/wpa/src/ap/tkip_countermeasures.c
index 4a2ea06..4725e2b 100644
--- a/contrib/wpa/src/ap/tkip_countermeasures.c
+++ b/contrib/wpa/src/ap/tkip_countermeasures.c
@@ -68,7 +68,7 @@ void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
{
- struct os_time now;
+ struct os_reltime now;
int ret = 0;
if (addr && local) {
@@ -89,8 +89,8 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
}
}
- os_get_time(&now);
- if (now.sec > hapd->michael_mic_failure + 60) {
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &hapd->michael_mic_failure, 60)) {
hapd->michael_mic_failures = 1;
} else {
hapd->michael_mic_failures++;
@@ -99,7 +99,7 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
ret = 1;
}
}
- hapd->michael_mic_failure = now.sec;
+ hapd->michael_mic_failure = now;
return ret;
}
diff --git a/contrib/wpa/src/ap/vlan_init.c b/contrib/wpa/src/ap/vlan_init.c
index 7b1a9e6..dc65019 100644
--- a/contrib/wpa/src/ap/vlan_init.c
+++ b/contrib/wpa/src/ap/vlan_init.c
@@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -493,8 +487,18 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
- os_snprintf(br_name, sizeof(br_name), "brvlan%d",
- vlan->vlan_id);
+ 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 (!br_addbr(br_name))
vlan->clean |= DVLAN_CLEAN_BR;
@@ -550,8 +554,18 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
- os_snprintf(br_name, sizeof(br_name), "brvlan%d",
- vlan->vlan_id);
+ 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);
@@ -603,6 +617,7 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
struct ifinfomsg *ifi;
int attrlen, nlmsg_len, rta_len;
struct rtattr *attr;
+ char ifname[IFNAMSIZ + 1];
if (len < sizeof(*ifi))
return;
@@ -617,29 +632,39 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
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)) {
- char ifname[IFNAMSIZ + 1];
-
if (attr->rta_type == IFLA_IFNAME) {
int n = attr->rta_len - rta_len;
if (n < 0)
break;
- os_memset(ifname, 0, sizeof(ifname));
-
- if ((size_t) n > sizeof(ifname))
- n = sizeof(ifname);
+ if ((size_t) n >= sizeof(ifname))
+ n = sizeof(ifname) - 1;
os_memcpy(ifname, ((char *) attr) + rta_len, n);
- if (del)
- vlan_dellink(ifname, hapd);
- else
- vlan_newlink(ifname, hapd);
}
attr = RTA_NEXT(attr, attrlen);
}
+
+ if (!ifname[0])
+ 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);
}
@@ -663,7 +688,7 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
}
h = (struct nlmsghdr *) buf;
- while (left >= (int) sizeof(*h)) {
+ while (NLMSG_OK(h, left)) {
int len, plen;
len = h->nlmsg_len;
@@ -684,9 +709,7 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
break;
}
- len = NLMSG_ALIGN(len);
- left -= len;
- h = (struct nlmsghdr *) ((char *) h + len);
+ h = NLMSG_NEXT(h, left);
}
if (left > 0) {
@@ -837,6 +860,24 @@ 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 &&
+ !hapd->conf->vlan) {
+ /* dynamic vlans enabled but no (or empty) vlan_file given */
+ struct hostapd_vlan *vlan;
+ vlan = os_zalloc(sizeof(*vlan));
+ if (vlan == NULL) {
+ wpa_printf(MSG_ERROR, "Out of memory while assigning "
+ "VLAN interfaces");
+ return -1;
+ }
+
+ vlan->vlan_id = VLAN_ID_WILDCARD;
+ os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
+ hapd->conf->iface);
+ vlan->next = hapd->conf->vlan;
+ hapd->conf->vlan = vlan;
+ }
+
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
return -1;
@@ -850,6 +891,7 @@ void vlan_deinit(struct hostapd_data *hapd)
#ifdef CONFIG_FULL_DYNAMIC_VLAN
full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
+ hapd->full_dynamic_vlan = NULL;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
}
@@ -858,7 +900,7 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
int vlan_id)
{
- struct hostapd_vlan *n;
+ struct hostapd_vlan *n = NULL;
char *ifname, *pos;
if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
@@ -871,28 +913,24 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
if (ifname == NULL)
return NULL;
pos = os_strchr(ifname, '#');
- if (pos == NULL) {
- os_free(ifname);
- return NULL;
- }
+ if (pos == NULL)
+ goto free_ifname;
*pos++ = '\0';
n = os_zalloc(sizeof(*n));
- if (n == NULL) {
- os_free(ifname);
- return NULL;
- }
+ if (n == NULL)
+ goto free_ifname;
n->vlan_id = vlan_id;
n->dynamic_vlan = 1;
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
pos);
- os_free(ifname);
if (hostapd_vlan_if_add(hapd, n->ifname)) {
os_free(n);
- return NULL;
+ n = NULL;
+ goto free_ifname;
}
n->next = hapd->conf->vlan;
@@ -902,6 +940,8 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
ifconfig_up(n->ifname);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+free_ifname:
+ os_free(ifname);
return n;
}
diff --git a/contrib/wpa/src/ap/vlan_init.h b/contrib/wpa/src/ap/vlan_init.h
index 382d5de..781eaac 100644
--- a/contrib/wpa/src/ap/vlan_init.h
+++ b/contrib/wpa/src/ap/vlan_init.h
@@ -3,14 +3,8 @@
* Copyright 2003, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef VLAN_INIT_H
diff --git a/contrib/wpa/src/ap/wmm.c b/contrib/wpa/src/ap/wmm.c
index d21c82f..6d4177c 100644
--- a/contrib/wpa/src/ap/wmm.c
+++ b/contrib/wpa/src/ap/wmm.c
@@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -157,7 +151,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
len = ((u8 *) (t + 1)) - buf;
if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
- perror("wmm_send_action: send");
+ wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}
diff --git a/contrib/wpa/src/ap/wmm.h b/contrib/wpa/src/ap/wmm.h
index 96b04e8..b70b863 100644
--- a/contrib/wpa/src/ap/wmm.h
+++ b/contrib/wpa/src/ap/wmm.h
@@ -3,14 +3,8 @@
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef WME_H
diff --git a/contrib/wpa/src/ap/wnm_ap.c b/contrib/wpa/src/ap/wnm_ap.c
index 54a6b85..4c8bc10 100644
--- a/contrib/wpa/src/ap/wnm_ap.c
+++ b/contrib/wpa/src/ap/wnm_ap.c
@@ -1,6 +1,6 @@
/*
* hostapd - WNM
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +9,9 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ap_config.h"
@@ -72,7 +74,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
wnmsleep_ie.len = wnmsleep_ie_len - 2;
wnmsleep_ie.action_type = action_type;
wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
- wnmsleep_ie.intval = intval;
+ wnmsleep_ie.intval = host_to_le16(intval);
/* TFS IE(s) */
wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
@@ -154,6 +156,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
+ sta->flags |= WLAN_STA_WNM_SLEEP_MODE;
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
addr, NULL, NULL);
wpa_set_wnmsleep(sta->wpa_sm, 1);
@@ -167,6 +170,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
wnmsleep_ie.status ==
WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
+ sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
wpa_set_wnmsleep(sta->wpa_sm, 0);
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
addr, NULL, NULL);
@@ -233,7 +237,7 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
wnmsleep_ie->action_type,
- wnmsleep_ie->intval);
+ le_to_host16(wnmsleep_ie->intval));
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
/* clear the tfs after sending the resp frame */
@@ -243,29 +247,350 @@ 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)
+{
+ struct ieee80211_mgmt *mgmt;
+ size_t url_len, len;
+ u8 *pos;
+ int res;
+
+ if (url)
+ url_len = os_strlen(url);
+ else
+ url_len = 0;
+
+ mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0));
+ if (mgmt == NULL)
+ return -1;
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+ mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
+ mgmt->u.action.u.bss_tm_req.req_mode = 0;
+ mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+ mgmt->u.action.u.bss_tm_req.validity_interval = 1;
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+ if (url) {
+ *pos++ += url_len;
+ os_memcpy(pos, url, url_len);
+ pos += url_len;
+ }
+
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
+ MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
+ "validity_interval=%u",
+ MAC2STR(addr), dialog_token,
+ mgmt->u.action.u.bss_tm_req.req_mode,
+ le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer),
+ mgmt->u.action.u.bss_tm_req.validity_interval);
+
+ len = pos - &mgmt->u.action.category;
+ res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+ mgmt->da, &mgmt->u.action.category, len);
+ os_free(mgmt);
+ return res;
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *frm,
+ size_t len)
+{
+ u8 dialog_token, reason;
+ const u8 *pos, *end;
+
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+
+ pos = frm;
+ end = pos + len;
+ dialog_token = *pos++;
+ reason = *pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from "
+ MACSTR " dialog_token=%u reason=%u",
+ MAC2STR(addr), dialog_token, reason);
+
+ wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
+ pos, end - pos);
+
+ ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL);
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *frm,
+ size_t len)
+{
+ u8 dialog_token, status_code, bss_termination_delay;
+ const u8 *pos, *end;
+
+ if (len < 3) {
+ wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+
+ pos = frm;
+ end = pos + len;
+ dialog_token = *pos++;
+ status_code = *pos++;
+ bss_termination_delay = *pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from "
+ MACSTR " dialog_token=%u status_code=%u "
+ "bss_termination_delay=%u", MAC2STR(addr), dialog_token,
+ status_code, bss_termination_delay);
+
+ if (status_code == WNM_BSS_TM_ACCEPT) {
+ if (end - pos < ETH_ALEN) {
+ wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
+ MAC2STR(pos));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
+ " status_code=%u bss_termination_delay=%u target_bssid="
+ MACSTR,
+ MAC2STR(addr), status_code, bss_termination_delay,
+ MAC2STR(pos));
+ pos += ETH_ALEN;
+ } else {
+ 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);
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
+ pos, end - pos);
+}
+
+
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
- struct rx_action *action)
+ const struct ieee80211_mgmt *mgmt, size_t len)
{
- if (action->len < 1 || action->data == NULL)
+ u8 action;
+ const u8 *payload;
+ size_t plen;
+
+ if (len < IEEE80211_HDRLEN + 2)
return -1;
- switch (action->data[0]) {
+ payload = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
+ action = *payload++;
+ plen = len - IEEE80211_HDRLEN - 2;
+
+ switch (action) {
case WNM_BSS_TRANS_MGMT_QUERY:
- wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
- /* TODO */
- return -1;
+ ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
case WNM_BSS_TRANS_MGMT_RESP:
- wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
- "Response");
- /* TODO */
- return -1;
+ ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
case WNM_SLEEP_MODE_REQ:
- ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
- action->len - 1);
+ ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen);
return 0;
}
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
- action->data[0], MAC2STR(action->sa));
+ action, MAC2STR(mgmt->sa));
return -1;
}
+
+
+int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
+ struct sta_info *sta, int disassoc_timer)
+{
+ u8 buf[1000], *pos;
+ struct ieee80211_mgmt *mgmt;
+
+ os_memset(buf, 0, sizeof(buf));
+ mgmt = (struct ieee80211_mgmt *) buf;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+ mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+ mgmt->u.action.u.bss_tm_req.req_mode =
+ WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+ mgmt->u.action.u.bss_tm_req.disassoc_timer =
+ host_to_le16(disassoc_timer);
+ mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
+ MACSTR, disassoc_timer, MAC2STR(sta->addr));
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+ "Management Request frame");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+ int disassoc_timer)
+{
+ int timeout, beacon_int;
+
+ /*
+ * Prevent STA from reconnecting using cached PMKSA to force
+ * full authentication with the authentication server (which may
+ * decide to reject the connection),
+ */
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+
+ beacon_int = hapd->iconf->beacon_int;
+ if (beacon_int < 1)
+ beacon_int = 100; /* best guess */
+ /* Calculate timeout in ms based on beacon_int in TU */
+ timeout = disassoc_timer * beacon_int * 128 / 125;
+ wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
+ " set to %d ms", MAC2STR(sta->addr), timeout);
+
+ sta->timeout_next = STA_DISASSOC_FROM_CLI;
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(timeout / 1000,
+ timeout % 1000 * 1000,
+ ap_handle_timer, hapd, sta);
+}
+
+
+int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
+ struct sta_info *sta, const char *url,
+ int disassoc_timer)
+{
+ u8 buf[1000], *pos;
+ struct ieee80211_mgmt *mgmt;
+ size_t url_len;
+
+ os_memset(buf, 0, sizeof(buf));
+ mgmt = (struct ieee80211_mgmt *) buf;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+ mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+ mgmt->u.action.u.bss_tm_req.req_mode =
+ WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
+ WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+ mgmt->u.action.u.bss_tm_req.disassoc_timer =
+ host_to_le16(disassoc_timer);
+ mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
+
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+
+ /* Session Information URL */
+ url_len = os_strlen(url);
+ if (url_len > 255)
+ return -1;
+ *pos++ = url_len;
+ os_memcpy(pos, url, url_len);
+ pos += url_len;
+
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+ "Management Request frame");
+ return -1;
+ }
+
+ if (disassoc_timer) {
+ /* send disassociation frame after time-out */
+ set_disassoc_timer(hapd, sta, disassoc_timer);
+ }
+
+ return 0;
+}
+
+
+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)
+{
+ u8 *buf, *pos;
+ struct ieee80211_mgmt *mgmt;
+ size_t url_len;
+
+ 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);
+ if (buf == NULL)
+ return -1;
+ mgmt = (struct ieee80211_mgmt *) buf;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+ mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+ mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
+ mgmt->u.action.u.bss_tm_req.disassoc_timer =
+ host_to_le16(disassoc_timer);
+ mgmt->u.action.u.bss_tm_req.validity_interval = valid_int;
+
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+
+ if ((req_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) &&
+ bss_term_dur) {
+ os_memcpy(pos, bss_term_dur, 12);
+ pos += 12;
+ }
+
+ if (url) {
+ /* Session Information URL */
+ url_len = os_strlen(url);
+ if (url_len > 255) {
+ os_free(buf);
+ return -1;
+ }
+
+ *pos++ = url_len;
+ os_memcpy(pos, url, url_len);
+ pos += url_len;
+ }
+
+ if (nei_rep) {
+ os_memcpy(pos, nei_rep, nei_rep_len);
+ pos += nei_rep_len;
+ }
+
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to send BSS Transition Management Request frame");
+ os_free(buf);
+ return -1;
+ }
+ os_free(buf);
+
+ if (disassoc_timer) {
+ /* send disassociation frame after time-out */
+ set_disassoc_timer(hapd, sta, disassoc_timer);
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/ap/wnm_ap.h b/contrib/wpa/src/ap/wnm_ap.h
index f05726e..7789307 100644
--- a/contrib/wpa/src/ap/wnm_ap.h
+++ b/contrib/wpa/src/ap/wnm_ap.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11v WNM related functions and structures
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,9 +9,18 @@
#ifndef WNM_AP_H
#define WNM_AP_H
-struct rx_action;
+struct sta_info;
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
- struct rx_action *action);
+ const struct ieee80211_mgmt *mgmt, size_t len);
+int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
+ struct sta_info *sta, int disassoc_timer);
+int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
+ struct sta_info *sta, const char *url,
+ int disassoc_timer);
+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);
#endif /* WNM_AP_H */
diff --git a/contrib/wpa/src/ap/wpa_auth.c b/contrib/wpa/src/ap/wpa_auth.c
index 2c70149..9c5f609 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-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.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/state_machine.h"
+#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
@@ -32,7 +33,8 @@
static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
static int wpa_sm_step(struct wpa_state_machine *sm);
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+ size_t data_len);
static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
@@ -41,6 +43,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
+ const u8 *pmk, struct wpa_ptk *ptk);
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -82,11 +86,14 @@ static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
- const u8 *addr, const u8 *prev_psk)
+ 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, prev_psk);
+ return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, p2p_dev_addr,
+ prev_psk);
}
@@ -131,6 +138,17 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
}
+#ifdef CONFIG_MESH
+static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
+ const u8 *addr)
+{
+ if (wpa_auth->cb.start_ampe == NULL)
+ return -1;
+ return wpa_auth->cb.start_ampe(wpa_auth->cb.ctx, addr);
+}
+#endif /* CONFIG_MESH */
+
+
int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
@@ -207,6 +225,8 @@ static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
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;
}
@@ -282,8 +302,9 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- u8 buf[ETH_ALEN + 8 + sizeof(group)];
+ u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
u8 rkey[32];
+ unsigned long ptr;
if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
return -1;
@@ -295,7 +316,8 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
*/
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
wpa_get_ntp_timestamp(buf + ETH_ALEN);
- os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+ ptr = (unsigned long) group;
+ os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
@@ -393,6 +415,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
wpa_auth);
if (wpa_auth->pmksa == NULL) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+ os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
return NULL;
@@ -402,6 +425,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
if (wpa_auth->ft_pmk_cache == NULL) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
+ os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
pmksa_cache_auth_deinit(wpa_auth->pmksa);
os_free(wpa_auth);
@@ -419,6 +443,17 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
wpa_rekey_gtk, wpa_auth, NULL);
}
+#ifdef CONFIG_P2P
+ if (WPA_GET_BE32(conf->ip_addr_start)) {
+ int count = WPA_GET_BE32(conf->ip_addr_end) -
+ WPA_GET_BE32(conf->ip_addr_start) + 1;
+ if (count > 1000)
+ count = 1000;
+ if (count > 0)
+ wpa_auth->ip_pool = bitfield_alloc(count);
+ }
+#endif /* CONFIG_P2P */
+
return wpa_auth;
}
@@ -432,6 +467,8 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth)
wpa_group_sm_step(wpa_auth, group);
group->GInit = FALSE;
wpa_group_sm_step(wpa_auth, group);
+ if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+ return -1;
return 0;
}
@@ -459,6 +496,11 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
wpa_auth->ft_pmk_cache = NULL;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+ bitfield_free(wpa_auth->ip_pool);
+#endif /* CONFIG_P2P */
+
+
os_free(wpa_auth->wpa_ie);
group = wpa_auth->group;
@@ -506,14 +548,20 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *
-wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ const u8 *p2p_dev_addr)
{
struct wpa_state_machine *sm;
+ if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+ return NULL;
+
sm = os_zalloc(sizeof(struct wpa_state_machine));
if (sm == NULL)
return NULL;
os_memcpy(sm->addr, addr, ETH_ALEN);
+ if (p2p_dev_addr)
+ os_memcpy(sm->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
sm->wpa_auth = wpa_auth;
sm->group = wpa_auth->group;
@@ -533,6 +581,8 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
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;
return 0;
}
#endif /* CONFIG_IEEE80211R */
@@ -570,12 +620,26 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
static void wpa_free_sta_sm(struct wpa_state_machine *sm)
{
+#ifdef CONFIG_P2P
+ if (WPA_GET_BE32(sm->ip_addr)) {
+ u32 start;
+ wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
+ "address %u.%u.%u.%u from " MACSTR,
+ sm->ip_addr[0], sm->ip_addr[1],
+ sm->ip_addr[2], sm->ip_addr[3],
+ MAC2STR(sm->addr));
+ start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start);
+ bitfield_clear(sm->wpa_auth->ip_pool,
+ WPA_GET_BE32(sm->ip_addr) - start);
+ }
+#endif /* CONFIG_P2P */
if (sm->GUpdateStationKeys) {
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
}
#ifdef CONFIG_IEEE80211R
os_free(sm->assoc_resp_ftie);
+ wpabuf_free(sm->ft_pending_req_ies);
#endif /* CONFIG_IEEE80211R */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
@@ -734,40 +798,96 @@ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
}
+static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
+ size_t data_len)
+{
+ struct wpa_ptk PTK;
+ int ok = 0;
+ const u8 *pmk = NULL;
+
+ for (;;) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
+ sm->p2p_dev_addr, pmk);
+ if (pmk == NULL)
+ break;
+ } else
+ pmk = sm->PMK;
+
+ wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
+
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
+ == 0) {
+ ok = 1;
+ break;
+ }
+
+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+ break;
+ }
+
+ if (!ok) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: Earlier SNonce did not result in matching MIC");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WPA: Earlier SNonce resulted in matching MIC");
+ sm->alt_snonce_valid = 0;
+ os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
+ os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+ sm->PTK_valid = TRUE;
+
+ return 0;
+}
+
+
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len)
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ 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;
char *msgtxt;
struct wpa_eapol_ie_parse kde;
int ft;
- const u8 *eapol_key_ie;
- size_t eapol_key_ie_len;
+ const u8 *eapol_key_ie, *key_data;
+ size_t eapol_key_ie_len, keyhdrlen, mic_len;
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return;
- if (data_len < sizeof(*hdr) + sizeof(*key))
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (data_len < sizeof(*hdr) + keyhdrlen)
return;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
key_info = WPA_GET_BE16(key->key_info);
- key_data_length = WPA_GET_BE16(key->key_data_length);
+ 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);
+ }
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
" key_info=0x%x type=%u key_data_length=%u",
MAC2STR(sm->addr), key_info, key->type, key_data_length);
- if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+ if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
"key_data overflow (%d > %lu)",
key_data_length,
(unsigned long) (data_len - sizeof(*hdr) -
- sizeof(*key)));
+ keyhdrlen));
return;
}
@@ -835,6 +955,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
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) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -853,6 +975,13 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
return;
}
}
+
+ if (wpa_key_mgmt_suite_b(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");
+ return;
+ }
}
if (key_info & WPA_KEY_INFO_REQUEST) {
@@ -888,8 +1017,25 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
"based on retransmitted EAPOL-Key "
"1/4");
sm->update_snonce = 1;
- wpa_replay_counter_mark_invalid(sm->prev_key_replay,
- key->replay_counter);
+ os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
+ sm->alt_snonce_valid = TRUE;
+ os_memcpy(sm->alt_replay_counter,
+ sm->key_replay[0].counter,
+ WPA_REPLAY_COUNTER_LEN);
+ goto continue_processing;
+ }
+
+ if (msg == PAIRWISE_4 && sm->alt_snonce_valid &&
+ sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
+ os_memcmp(key->replay_counter, sm->alt_replay_counter,
+ WPA_REPLAY_COUNTER_LEN) == 0) {
+ /*
+ * Supplicant may still be using the old SNonce since
+ * there was two EAPOL-Key 2/4 messages and they had
+ * different SNonce values.
+ */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
goto continue_processing;
}
@@ -948,8 +1094,7 @@ continue_processing:
wpa_sta_disconnect(wpa_auth, sm->addr);
return;
}
- if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
- &kde) < 0) {
+ 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");
@@ -958,6 +1103,9 @@ continue_processing:
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;
@@ -987,6 +1135,26 @@ continue_processing:
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 ||
@@ -1051,7 +1219,10 @@ continue_processing:
sm->MICVerified = FALSE;
if (sm->PTK_valid && !sm->update_snonce) {
- if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &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");
return;
@@ -1080,7 +1251,7 @@ continue_processing:
*/
if (msg == SMK_ERROR) {
#ifdef CONFIG_PEERKEY
- wpa_smk_error(wpa_auth, sm, key);
+ wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1095,11 +1266,12 @@ continue_processing:
wpa_request_new_ptk(sm);
#ifdef CONFIG_PEERKEY
} else if (msg == SMK_M1) {
- wpa_smk_m1(wpa_auth, sm, key);
+ 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((const u8 *) (key + 1),
- key_data_length, &kde) == 0 &&
+ wpa_parse_kde_ies(key_data, key_data_length,
+ &kde) == 0 &&
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -1137,7 +1309,7 @@ continue_processing:
#ifdef CONFIG_PEERKEY
if (msg == SMK_M3) {
- wpa_smk_m3(wpa_auth, sm, key);
+ wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
return;
}
#endif /* CONFIG_PEERKEY */
@@ -1212,17 +1384,25 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- size_t len;
+ 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;
+
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
- len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+ 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))
+ version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise != WPA_CIPHER_TKIP)
@@ -1230,7 +1410,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
else
version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
- pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+ pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
"ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
@@ -1245,6 +1425,8 @@ 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) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
pad_len = key_data_len % 8;
if (pad_len)
@@ -1261,6 +1443,8 @@ 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_data = ((u8 *) (hdr + 1)) + keyhdrlen;
key->type = sm->wpa == WPA_VERSION_WPA2 ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
@@ -1286,6 +1470,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
os_memcpy(key->replay_counter, sm->key_replay[0].counter,
WPA_REPLAY_COUNTER_LEN);
+ wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
+ key->replay_counter, WPA_REPLAY_COUNTER_LEN);
sm->key_replay[0].valid = TRUE;
if (nonce)
@@ -1295,8 +1481,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
if (kde && !encr) {
- os_memcpy(key + 1, kde, kde_len);
- WPA_PUT_BE16(key->key_data_length, kde_len);
+ 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);
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
if (buf == NULL) {
@@ -1313,29 +1502,47 @@ 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) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
- if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
- (u8 *) (key + 1))) {
+ 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;
}
- WPA_PUT_BE16(key->key_data_length, key_data_len);
- } else {
+ 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);
+ } else if (sm->PTK.kek_len == 16) {
u8 ek[32];
os_memcpy(key->key_iv,
sm->group->Counter + WPA_NONCE_LEN - 16, 16);
inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->PTK.kek, 16);
- os_memcpy(key + 1, buf, key_data_len);
- rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
- WPA_PUT_BE16(key->key_data_length, key_data_len);
+ os_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);
+ } else {
+ os_free(hdr);
+ os_free(buf);
+ return;
}
os_free(buf);
}
if (key_info & WPA_KEY_INFO_MIC) {
+ u8 *key_mic;
+
if (!sm->PTK_valid) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PTK not valid when sending EAPOL-Key "
@@ -1343,8 +1550,21 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
os_free(hdr);
return;
}
- wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
- key->key_mic);
+
+ 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);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!pairwise &&
+ wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
+ drand48() <
+ wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Corrupting group EAPOL-Key Key MIC");
+ key_mic[0]++;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
}
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
@@ -1386,27 +1606,32 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
}
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+static int wpa_verify_key_mic(int akmp, 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[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = wpa_mic_len(akmp);
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);
key_info = WPA_GET_BE16(key->key_info);
- os_memcpy(mic, key->key_mic, 16);
- os_memset(key->key_mic, 0, 16);
- if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
- data, data_len, key->key_mic) ||
- os_memcmp(mic, key->key_mic, 16) != 0)
+ os_memcpy(mic, key192->key_mic, mic_len);
+ os_memset(key192->key_mic, 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)
ret = -1;
- os_memcpy(key->key_mic, mic, 16);
+ os_memcpy(key192->key_mic, mic, mic_len);
return ret;
}
@@ -1433,6 +1658,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
switch (event) {
case WPA_AUTH:
+#ifdef CONFIG_MESH
+ /* PTKs are derived through AMPE */
+ if (wpa_auth_start_ampe(sm->wpa_auth, sm->addr)) {
+ /* not mesh */
+ break;
+ }
+ return 0;
+#endif /* CONFIG_MESH */
case WPA_ASSOC:
break;
case WPA_DEAUTH:
@@ -1596,6 +1829,7 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
wpa_group_ensure_init(sm->wpa_auth, sm->group);
+ sm->ReAuthenticationRequest = FALSE;
/*
* Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
@@ -1609,12 +1843,11 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
"ANonce.");
- wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ sm->Disconnect = TRUE;
return;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
WPA_NONCE_LEN);
- sm->ReAuthenticationRequest = FALSE;
/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
* logical place than INITIALIZE since AUTHENTICATION2 can be
* re-entered on ReAuthenticationRequest without going through
@@ -1646,8 +1879,12 @@ SM_STATE(WPA_PTK, INITPMK)
}
#endif /* CONFIG_IEEE80211R */
} else {
- wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+ wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
+ sm->wpa_auth->cb.get_msk);
+ sm->Disconnect = TRUE;
+ return;
}
+ os_memset(msk, 0, sizeof(msk));
sm->req_replay_counter_used = 0;
/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
@@ -1666,7 +1903,7 @@ SM_STATE(WPA_PTK, INITPSK)
{
const u8 *psk;
SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
- psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
+ psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
if (psk) {
os_memcpy(sm->PMK, psk, PMK_LEN);
#ifdef CONFIG_IEEE80211R
@@ -1686,6 +1923,7 @@ SM_STATE(WPA_PTK, PTKSTART)
SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
sm->PTKRequest = FALSE;
sm->TimeoutEvt = FALSE;
+ sm->alt_snonce_valid = FALSE;
sm->TimeoutCtr++;
if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
@@ -1701,16 +1939,20 @@ SM_STATE(WPA_PTK, PTKSTART)
* one possible PSK for this STA.
*/
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_OSEN) {
pmkid = buf;
pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
- if (sm->pmksa)
+ if (sm->pmksa) {
os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
sm->pmksa->pmkid, PMKID_LEN);
- else {
+ } else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
+ /* No KCK available to derive PMKID */
+ pmkid = NULL;
+ } else {
/*
* Calculate PMKID since no PMKSA cache entry was
* available with pre-calculated PMKID.
@@ -1726,21 +1968,17 @@ SM_STATE(WPA_PTK, PTKSTART)
}
-static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk)
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
+ const u8 *pmk, struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+ return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
- sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-
- return 0;
+ 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);
}
@@ -1759,15 +1997,17 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
* the packet */
for (;;) {
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
- pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
+ pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
+ sm->p2p_dev_addr, pmk);
if (pmk == NULL)
break;
} else
pmk = sm->PMK;
- wpa_derive_ptk(sm, pmk, &PTK);
+ wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
- if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
+ sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
ok = 1;
break;
@@ -1789,8 +2029,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
* Verify that PMKR1Name from EAPOL-Key message 2/4 matches
* with the value we derived.
*/
- if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name,
- WPA_PMK_NAME_LEN) != 0) {
+ if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKR1Name mismatch in FT 4-way "
"handshake");
@@ -1833,7 +2073,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
if (sm->mgmt_frame_prot) {
- return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
+ size_t len;
+ len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
}
return 0;
@@ -1844,6 +2086,8 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
struct wpa_group *gsm = sm->group;
+ u8 rsc[WPA_KEY_RSC_LEN];
+ size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
if (!sm->mgmt_frame_prot)
return pos;
@@ -1851,19 +2095,22 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
igtk.keyid[0] = gsm->GN_igtk;
igtk.keyid[1] = 0;
if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
- wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
os_memset(igtk.pn, 0, sizeof(igtk.pn));
- os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ 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) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
*/
- if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+ if (random_get_bytes(igtk.igtk, len) < 0)
return pos;
}
pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
- (const u8 *) &igtk, sizeof(igtk), NULL, 0);
+ (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
+ NULL, 0);
return pos;
}
@@ -1913,8 +2160,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
if (sm->wpa == WPA_VERSION_WPA &&
(sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
- /* WPA-only STA, remove RSN IE */
+ /* WPA-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,
@@ -1968,6 +2217,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
kde_len += 300; /* FTIE + 2 * TIE */
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+ if (WPA_GET_BE32(sm->ip_addr) > 0)
+ kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
+#endif /* CONFIG_P2P */
kde = os_malloc(kde_len);
if (kde == NULL)
return;
@@ -2029,6 +2282,16 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
pos += 4;
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+ if (WPA_GET_BE32(sm->ip_addr) > 0) {
+ u8 addr[3 * 4];
+ os_memcpy(addr, sm->ip_addr, 4);
+ os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
+ os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+ pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
+ addr, sizeof(addr), NULL, 0);
+ }
+#endif /* CONFIG_P2P */
wpa_send_eapol(sm->wpa_auth, sm,
(secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
@@ -2047,7 +2310,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
int klen = wpa_cipher_key_len(sm->pairwise);
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk1, klen)) {
+ sm->PTK.tk, klen)) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
return;
}
@@ -2146,7 +2409,8 @@ SM_STEP(WPA_PTK)
}
break;
case WPA_PTK_INITPSK:
- if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
+ if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
+ NULL))
SM_ENTER(WPA_PTK, PTKSTART);
else {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
@@ -2220,7 +2484,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN];
struct wpa_group *gsm = sm->group;
- u8 *kde, *pos, hdr[2];
+ const u8 *kde;
+ u8 *kde_buf = NULL, *pos, hdr[2];
size_t kde_len;
u8 *gtk, dummy_gtk[32];
@@ -2256,28 +2521,29 @@ 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);
- kde = os_malloc(kde_len);
- if (kde == NULL)
+ kde_buf = os_malloc(kde_len);
+ if (kde_buf == NULL)
return;
- pos = kde;
+ 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);
pos = ieee80211w_kde_add(sm, pos);
+ kde_len = pos - kde;
} else {
kde = gtk;
- pos = kde + gsm->GTK_len;
+ kde_len = gsm->GTK_len;
}
wpa_send_eapol(sm->wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_ACK |
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
- rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
- if (sm->wpa == WPA_VERSION_WPA2)
- os_free(kde);
+ rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+
+ os_free(kde_buf);
}
@@ -2354,15 +2620,16 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ size_t len;
+ len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
wpa_auth->addr, group->GNonce,
- group->IGTK[group->GN_igtk - 4],
- WPA_IGTK_LEN) < 0)
+ group->IGTK[group->GN_igtk - 4], len) < 0)
ret = -1;
wpa_hexdump_key(MSG_DEBUG, "IGTK",
- group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
+ group->IGTK[group->GN_igtk - 4], len);
}
#endif /* CONFIG_IEEE80211W */
@@ -2429,7 +2696,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
- if (sm->is_wnmsleep)
+ if (sm == NULL || sm->is_wnmsleep)
return;
wpa_group_update_sta(sm, NULL);
@@ -2438,7 +2705,8 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
{
- sm->is_wnmsleep = !!flag;
+ if (sm)
+ sm->is_wnmsleep = !!flag;
}
@@ -2478,26 +2746,27 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_group *gsm = sm->group;
u8 *start = pos;
+ size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
/*
* IGTK subelement:
* Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
*/
*pos++ = WNM_SLEEP_SUBELEM_IGTK;
- *pos++ = 2 + 6 + WPA_IGTK_LEN;
+ *pos++ = 2 + 6 + len;
WPA_PUT_LE16(pos, gsm->GN_igtk);
pos += 2;
if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
return 0;
pos += 6;
- os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
- pos += WPA_IGTK_LEN;
+ os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
+ pos += len;
wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
gsm->GN_igtk);
wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
- gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ gsm->IGTK[gsm->GN_igtk - 4], len);
return pos - start;
}
@@ -2552,18 +2821,48 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
ret = -1;
#ifdef CONFIG_IEEE80211W
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
- wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
- broadcast_ether_addr, group->GN_igtk,
- group->IGTK[group->GN_igtk - 4],
- WPA_IGTK_LEN) < 0)
- ret = -1;
+ if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ enum wpa_alg alg;
+ size_t len;
+
+ alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
+ len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+
+ if (ret == 0 &&
+ wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+ broadcast_ether_addr, group->GN_igtk,
+ group->IGTK[group->GN_igtk - 4], len) < 0)
+ ret = -1;
+ }
#endif /* CONFIG_IEEE80211W */
return ret;
}
+static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
+{
+ if (sm->group == ctx) {
+ wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
+ " for discconnection due to fatal failure",
+ MAC2STR(sm->addr));
+ sm->Disconnect = TRUE;
+ }
+
+ return 0;
+}
+
+
+static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
+ group->changed = TRUE;
+ group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
+ wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
+}
+
+
static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
@@ -2572,8 +2871,10 @@ static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
group->changed = TRUE;
group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
- if (wpa_group_config_group_keys(wpa_auth, group) < 0)
+ if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
+ wpa_group_fatal_failure(wpa_auth, group);
return -1;
+ }
return 0;
}
@@ -2584,6 +2885,8 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
{
if (group->GInit) {
wpa_group_gtk_init(wpa_auth, group);
+ } else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) {
+ /* Do not allow group operations */
} else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
group->GTKAuthenticator) {
wpa_group_setkeysdone(wpa_auth, group);
@@ -2711,7 +3014,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
wpa_bool_txt(preauth),
wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
wpa_bool_txt(wpa_auth->conf.rsn_preauth));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2761,7 +3064,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
wpa_auth->dot11RSNA4WayHandshakeFailures);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2771,7 +3074,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
/* Private MIB */
ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
wpa_auth->group->wpa_group_state);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2813,7 +3116,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
RSN_SUITE_ARG(pairwise),
sm->dot11RSNAStatsTKIPLocalMICFailures,
sm->dot11RSNAStatsTKIPRemoteMICFailures);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2823,7 +3126,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
"hostapdWPAPTKGroupState=%d\n",
sm->wpa_ptk_state,
sm->wpa_ptk_group_state);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2907,6 +3210,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
return -1;
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+ sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
eapol, sm->wpa_key_mgmt))
return 0;
@@ -2923,7 +3227,9 @@ 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, wpa_auth->addr,
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
+ NULL, 0,
+ wpa_auth->addr,
sta_addr, session_timeout, eapol,
WPA_KEY_MGMT_IEEE8021X))
return 0;
@@ -2932,6 +3238,38 @@ 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)
+{
+ if (wpa_auth->conf.disable_pmksa_caching)
+ return -1;
+
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
+ NULL, 0,
+ wpa_auth->addr, addr, 0, NULL,
+ WPA_KEY_MGMT_SAE))
+ return 0;
+
+ return -1;
+}
+
+
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+ return;
+ pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+ if (pmksa) {
+ wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
+ MACSTR " based on request", MAC2STR(sta_addr));
+ pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
+ }
+}
+
+
static struct wpa_group *
wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
@@ -2976,6 +3314,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
if (sm->group == group)
return 0;
+ if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+ return -1;
+
wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
"machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
@@ -3020,3 +3361,40 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm)
return 0;
return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
}
+
+
+int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
+}
+
+
+#ifdef CONFIG_P2P
+int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
+{
+ if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+ return -1;
+ os_memcpy(addr, sm->ip_addr, 4);
+ return 0;
+}
+#endif /* CONFIG_P2P */
+
+
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+ struct radius_das_attrs *attr)
+{
+ return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
+}
+
+
+void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group;
+
+ if (!wpa_auth)
+ return;
+ for (group = wpa_auth->group; group; group = group->next)
+ wpa_group_config_group_keys(wpa_auth, group);
+}
diff --git a/contrib/wpa/src/ap/wpa_auth.h b/contrib/wpa/src/ap/wpa_auth.h
index 465eec6..2788e65 100644
--- a/contrib/wpa/src/ap/wpa_auth.h
+++ b/contrib/wpa/src/ap/wpa_auth.h
@@ -42,6 +42,7 @@ struct ft_rrb_frame {
#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
struct ft_r0kh_r1kh_pull_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
@@ -49,7 +50,7 @@ struct ft_r0kh_r1kh_pull_frame {
le16 data_length; /* little endian length of data (44) */
u8 ap_address[ETH_ALEN];
- u8 nonce[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];
@@ -63,7 +64,7 @@ struct ft_r0kh_r1kh_resp_frame {
le16 data_length; /* little endian length of data (76) */
u8 ap_address[ETH_ALEN];
- u8 nonce[16]; /* copied from pull */
+ 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];
@@ -142,6 +143,7 @@ struct wpa_auth_config {
int tx_status;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
+ int group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
#define SSID_LEN 32
@@ -160,6 +162,15 @@ struct wpa_auth_config {
#endif /* CONFIG_IEEE80211R */
int disable_gtk;
int ap_mlme;
+#ifdef CONFIG_TESTING_OPTIONS
+ double corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_P2P
+ u8 ip_addr_go[4];
+ u8 ip_addr_mask[4];
+ u8 ip_addr_start[4];
+ u8 ip_addr_end[4];
+#endif /* CONFIG_P2P */
};
typedef enum {
@@ -181,7 +192,8 @@ struct wpa_auth_callbacks {
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
- const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
+ const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
+ const u8 *prev_psk);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key, size_t key_len);
@@ -199,8 +211,11 @@ struct wpa_auth_callbacks {
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);
+ size_t tspec_ielen);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_MESH
+ int (*start_ampe)(void *ctx, const u8 *sta_addr);
+#endif /* CONFIG_MESH */
};
struct wpa_authenticator * wpa_init(const u8 *addr,
@@ -222,9 +237,13 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len);
+int wpa_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);
struct wpa_state_machine *
-wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ const u8 *p2p_dev_addr);
int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm);
void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
@@ -260,6 +279,10 @@ 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);
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
@@ -288,5 +311,13 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
+int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
+
+int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
+
+struct radius_das_attrs;
+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);
#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 48bf79b..ef3249a 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-2009, 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.
@@ -9,6 +9,8 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/aes_wrap.h"
@@ -22,6 +24,12 @@
#ifdef CONFIG_IEEE80211R
+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 int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
const u8 *data, size_t data_len)
{
@@ -57,7 +65,7 @@ static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
u8 *tspec_ie, size_t tspec_ielen)
{
if (wpa_auth->cb.add_tspec == NULL) {
- wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
+ 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,
@@ -228,8 +236,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
r0 = cache->pmk_r0;
while (r0) {
if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
- os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
- == 0) {
+ os_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;
@@ -278,8 +286,8 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
r1 = cache->pmk_r1;
while (r1) {
if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
- os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
- == 0) {
+ os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
+ WPA_PMK_NAME_LEN) == 0) {
os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
if (pairwise)
*pairwise = r1->pairwise;
@@ -293,22 +301,26 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
}
-static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
- const u8 *s1kh_id, const u8 *r0kh_id,
- size_t r0kh_id_len, const u8 *pmk_r0_name)
+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;
struct ft_r0kh_r1kh_pull_frame frame, f;
- r0kh = wpa_auth->conf.r0kh_list;
+ r0kh = sm->wpa_auth->conf.r0kh_list;
while (r0kh) {
- if (r0kh->id_len == r0kh_id_len &&
- os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0)
+ if (r0kh->id_len == sm->r0kh_id_len &&
+ os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) ==
+ 0)
break;
r0kh = r0kh->next;
}
- if (r0kh == NULL)
+ if (r0kh == NULL) {
+ wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
+ sm->r0kh_id, sm->r0kh_id_len);
return -1;
+ }
wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
"address " MACSTR, MAC2STR(r0kh->addr));
@@ -317,31 +329,40 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
- os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
+ os_memcpy(frame.ap_address, sm->wpa_auth->addr, ETH_ALEN);
/* aes_wrap() does not support inplace encryption, so use a temporary
* buffer for the data. */
- if (random_get_bytes(f.nonce, sizeof(f.nonce))) {
+ if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) {
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, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
- os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+ 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, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+ if (aes_wrap(r0kh->key, sizeof(r0kh->key),
+ (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
f.nonce, frame.nonce) < 0)
return -1;
- wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
+ 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)
+ return -1;
+
+ wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
return 0;
}
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk, size_t ptk_len)
+ struct wpa_ptk *ptk)
{
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
@@ -353,7 +374,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
-
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
"derivation");
@@ -375,13 +395,9 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
sm->pairwise);
- wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, sm->pmk_r1_name,
- (u8 *) ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
- return 0;
+ return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, sm->pmk_r1_name,
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
}
@@ -416,7 +432,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
pad_len = 8 - pad_len;
if (key_len + pad_len < 16)
pad_len += 8;
- if (pad_len) {
+ if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
@@ -440,7 +456,8 @@ 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, key_len / 8, key, subelem + 13)) {
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
+ subelem + 13)) {
os_free(subelem);
return NULL;
}
@@ -472,7 +489,7 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = WPA_IGTK_LEN;
- if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
os_free(subelem);
return NULL;
@@ -569,8 +586,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
else {
/* TSPEC accepted; include updated TSPEC in
* response */
- rdie->descr_count = 1;
- pos += sizeof(*tspec);
+ rdie->descr_count = 1;
+ pos += sizeof(*tspec);
}
return pos;
}
@@ -632,8 +649,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
conf = &sm->wpa_auth->conf;
- if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
- sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
+ if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return pos;
end = pos + max_len;
@@ -725,7 +741,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
ric_start = NULL;
if (auth_alg == WLAN_AUTH_FT &&
- wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+ wpa_ft_mic(sm->PTK.kck, sm->PTK.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,
@@ -769,7 +786,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
* optimized by adding the STA entry earlier.
*/
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk1, klen))
+ sm->PTK.tk, klen))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -777,7 +794,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
}
-static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
+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)
{
@@ -787,7 +804,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
- size_t buflen, ptk_len;
+ size_t buflen;
int ret;
u8 *pos, *end;
int pairwise;
@@ -848,19 +865,13 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
&pairwise) < 0) {
- if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id,
- sm->r0kh_id_len, parse.rsn_pmkid) < 0) {
+ 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");
return WLAN_STATUS_INVALID_PMKID;
}
- /*
- * TODO: Should return "status pending" (and the caller should
- * not send out response now). The real response will be sent
- * once the response from R0KH is received.
- */
- return WLAN_STATUS_INVALID_PMKID;
+ return -1; /* Status pending */
}
wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
@@ -878,15 +889,14 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
- ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
- wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, pmk_r1_name,
- (u8 *) &sm->PTK, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->PTK, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+ if (wpa_pmk_r1_to_ptk(pmk_r1, 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;
sm->pairwise = pairwise;
+ sm->PTK_valid = TRUE;
wpa_ft_install_ptk(sm);
buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
@@ -940,6 +950,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 status;
u8 *resp_ies;
size_t resp_ies_len;
+ int res;
if (sm == NULL) {
wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
@@ -950,8 +961,16 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
" BSSID=" MACSTR " transaction=%d",
MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
- status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
- &resp_ies_len);
+ sm->ft_pending_cb = cb;
+ sm->ft_pending_cb_ctx = ctx;
+ sm->ft_pending_auth_transaction = auth_transaction;
+ res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
+ &resp_ies_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Callback postponed until response is available");
+ return;
+ }
+ status = res;
wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
" auth_transaction=%d status=%d",
@@ -969,7 +988,8 @@ 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[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = 16;
unsigned int count;
if (sm == NULL)
@@ -992,8 +1012,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_PMKID;
}
- if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
- {
+ if (os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)
+ != 0) {
wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
"with the PMKR1Name derived from auth request");
return WLAN_STATUS_INVALID_PMKID;
@@ -1039,7 +1059,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -1054,8 +1075,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
- FT_R1KH_ID_LEN) != 0) {
+ if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+ FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
@@ -1066,7 +1087,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
return -1;
@@ -1082,7 +1104,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return -1;
}
- if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+ if (wpa_ft_mic(sm->PTK.kck, sm->PTK.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,
@@ -1092,12 +1115,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->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, 16);
- wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
+ ftie->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);
wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
@@ -1166,6 +1190,8 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
/* RRB - Forward action frame to the target AP */
frame = os_malloc(sizeof(*frame) + len);
+ if (frame == NULL)
+ return -1;
frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
frame->packet_type = FT_PACKET_REQUEST;
frame->action_length = host_to_le16(len);
@@ -1180,15 +1206,27 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
}
+static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid,
+ u16 auth_transaction, u16 resp,
+ const u8 *ies, size_t ies_len)
+{
+ struct wpa_state_machine *sm = ctx;
+ wpa_printf(MSG_DEBUG, "FT: Over-the-DS RX request cb for " MACSTR,
+ MAC2STR(sm->addr));
+ wpa_ft_send_rrb_auth_resp(sm, sm->ft_pending_current_ap, sm->addr,
+ WLAN_STATUS_SUCCESS, ies, ies_len);
+}
+
+
static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
const u8 *current_ap, const u8 *sta_addr,
const u8 *body, size_t len)
{
struct wpa_state_machine *sm;
u16 status;
- u8 *resp_ies, *pos;
- size_t resp_ies_len, rlen;
- struct ft_rrb_frame *frame;
+ u8 *resp_ies;
+ size_t resp_ies_len;
+ int res;
sm = wpa_ft_add_sta(wpa_auth, sta_addr);
if (sm == NULL) {
@@ -1199,8 +1237,33 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
- status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
- &resp_ies_len);
+ 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);
+ res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
+ &resp_ies_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "FT: No immediate response available - wait for pull response");
+ return 0;
+ }
+ status = res;
+
+ res = wpa_ft_send_rrb_auth_resp(sm, current_ap, sta_addr, status,
+ resp_ies, resp_ies_len);
+ os_free(resp_ies);
+ return res;
+}
+
+
+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)
+{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ size_t rlen;
+ struct ft_rrb_frame *frame;
+ u8 *pos;
wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
" CurrentAP=" MACSTR " status=%d",
@@ -1216,6 +1279,8 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
frame = os_malloc(sizeof(*frame) + rlen);
+ if (frame == NULL)
+ return -1;
frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
frame->packet_type = FT_PACKET_RESPONSE;
frame->action_length = host_to_le16(rlen);
@@ -1229,10 +1294,8 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
pos += ETH_ALEN;
WPA_PUT_LE16(pos, status);
pos += 2;
- if (resp_ies) {
+ if (resp_ies)
os_memcpy(pos, resp_ies, resp_ies_len);
- os_free(resp_ies);
- }
wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
sizeof(*frame) + rlen);
@@ -1246,7 +1309,9 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
const u8 *data, size_t data_len)
{
- struct ft_r0kh_r1kh_pull_frame *frame, f;
+ struct ft_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];
@@ -1254,7 +1319,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
- if (data_len < sizeof(*frame))
+ if (data_len < sizeof(f))
return -1;
r1kh = wpa_auth->conf.r1kh_list;
@@ -1270,11 +1335,14 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
return -1;
}
- frame = (struct ft_r0kh_r1kh_pull_frame *) data;
+ 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, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
- frame->nonce, f.nonce) < 0) {
+ 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;
@@ -1284,7 +1352,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
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="
+ 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));
@@ -1311,8 +1379,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
WPA_PMK_NAME_LEN);
r.pairwise = host_to_le16(pairwise);
+ os_memset(r.pad, 0, sizeof(r.pad));
- if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+ 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;
@@ -1326,17 +1396,64 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
}
+static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_state_machine *sm = eloop_ctx;
+ int res;
+ u8 *resp_ies;
+ size_t resp_ies_len;
+ u16 status;
+
+ 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);
+ 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);
+
+ sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr,
+ sm->ft_pending_auth_transaction + 1, status,
+ resp_ies, resp_ies_len);
+ os_free(resp_ies);
+}
+
+
+static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
+{
+ struct ft_r0kh_r1kh_resp_frame *frame = 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)
+ 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);
+ 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)
{
- struct ft_r0kh_r1kh_resp_frame *frame, f;
+ struct ft_r0kh_r1kh_resp_frame f;
+ const u8 *crypt;
+ u8 *plain;
struct ft_remote_r0kh *r0kh;
- int pairwise;
+ int pairwise, res;
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
- if (data_len < sizeof(*frame))
+ if (data_len < sizeof(f))
return -1;
r0kh = wpa_auth->conf.r0kh_list;
@@ -1352,31 +1469,30 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
return -1;
}
- frame = (struct ft_r0kh_r1kh_resp_frame *) data;
+ 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, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
- frame->nonce, f.nonce) < 0) {
+ 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;
}
- if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
- != 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");
return -1;
}
- /* TODO: verify that <nonce,s1kh_id> matches with a pending request
- * and call this requests callback function to finish request
- * processing */
-
pairwise = le_to_host16(f.pairwise);
wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
f.nonce, sizeof(f.nonce));
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
+ 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",
@@ -1384,11 +1500,13 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
f.pmk_r1_name, WPA_PMK_NAME_LEN);
- wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
- pairwise);
+ 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);
- return 0;
+ return res ? 0 : -1;
}
@@ -1396,7 +1514,9 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
const u8 *data, size_t data_len)
{
- struct ft_r0kh_r1kh_push_frame *frame, f;
+ struct ft_r0kh_r1kh_push_frame f;
+ const u8 *crypt;
+ u8 *plain;
struct ft_remote_r0kh *r0kh;
struct os_time now;
os_time_t tsend;
@@ -1404,7 +1524,7 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
- if (data_len < sizeof(*frame))
+ if (data_len < sizeof(f))
return -1;
r0kh = wpa_auth->conf.r0kh_list;
@@ -1420,11 +1540,15 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
return -1;
}
- frame = (struct ft_r0kh_r1kh_push_frame *) data;
+ 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, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- frame->timestamp, f.timestamp) < 0) {
+ 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;
@@ -1440,8 +1564,8 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
return -1;
}
- if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
- != 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 push did not use a matching "
"R1KH-ID (received " MACSTR " own " MACSTR ")",
MAC2STR(f.r1kh_id),
@@ -1582,6 +1706,11 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
+ if (end > pos) {
+ wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
+ pos, end - pos);
+ }
+
return 0;
}
@@ -1593,6 +1722,8 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
{
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;
@@ -1614,8 +1745,14 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
os_get_time(&now);
WPA_PUT_LE32(f.timestamp, now.sec);
f.pairwise = host_to_le16(pairwise);
- if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- f.timestamp, frame.timestamp) < 0)
+ 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)
return;
wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
diff --git a/contrib/wpa/src/ap/wpa_auth_glue.c b/contrib/wpa/src/ap/wpa_auth_glue.c
index 76c61ea..7f83207 100644
--- a/contrib/wpa/src/ap/wpa_auth_glue.c
+++ b/contrib/wpa/src/ap/wpa_auth_glue.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,11 +10,11 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
#include "l2_packet/l2_packet.h"
-#include "drivers/driver.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "preauth_auth.h"
@@ -27,6 +27,7 @@
static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+ struct hostapd_config *iconf,
struct wpa_auth_config *wconf)
{
os_memset(wconf, 0, sizeof(*wconf));
@@ -48,6 +49,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
+ wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
wconf->ssid_len = conf->ssid.ssid_len;
@@ -72,7 +74,30 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_HS20
wconf->disable_gtk = conf->disable_dgaf;
+ if (conf->osen) {
+ wconf->disable_gtk = 1;
+ wconf->wpa = WPA_PROTO_OSEN;
+ wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+ wconf->wpa_pairwise = 0;
+ wconf->wpa_group = WPA_CIPHER_CCMP;
+ wconf->rsn_pairwise = WPA_CIPHER_CCMP;
+ wconf->rsn_preauth = 0;
+ wconf->disable_pmksa_caching = 1;
+#ifdef CONFIG_IEEE80211W
+ wconf->ieee80211w = 1;
+#endif /* CONFIG_IEEE80211W */
+ }
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_TESTING_OPTIONS
+ wconf->corrupt_gtk_rekey_mic_probability =
+ iconf->corrupt_gtk_rekey_mic_probability;
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_P2P
+ os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
+ os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4);
+ os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4);
+ os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4);
+#endif /* CONFIG_P2P */
}
@@ -180,11 +205,22 @@ 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)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
- const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
+ const u8 *psk;
+
+#ifdef CONFIG_SAE
+ if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+ if (!sta->sae || prev_psk)
+ return NULL;
+ return sta->sae->pmk;
+ }
+#endif /* CONFIG_SAE */
+
+ psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
@@ -213,12 +249,17 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
- if (sta == NULL)
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA");
return -1;
+ }
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
- if (key == NULL)
+ if (key == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p",
+ sta->eapol_sm);
return -1;
+ }
if (keylen > *len)
keylen = *len;
@@ -263,6 +304,21 @@ static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
struct sta_info *sta;
u32 flags = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_eapol_frame_io) {
+ size_t hex_len = 2 * data_len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex == NULL)
+ return -1;
+ wpa_snprintf_hex(hex, hex_len, data, data_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+ MAC2STR(addr), hex);
+ os_free(hex);
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
sta = ap_get_sta(hapd, addr);
if (sta)
flags = hostapd_sta_flags_to_drv(sta->flags);
@@ -368,6 +424,21 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
struct l2_ethhdr *buf;
int ret;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
+ size_t hex_len = 2 * data_len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex == NULL)
+ return -1;
+ wpa_snprintf_hex(hex, hex_len, data, data_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+ MAC2STR(dst), hex);
+ os_free(hex);
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_IEEE80211R
if (proto == ETH_P_RRB && hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
@@ -455,7 +526,7 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
return sta->wpa_sm;
}
- sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL);
if (sta->wpa_sm == NULL) {
ap_free_sta(hapd, sta);
return NULL;
@@ -498,7 +569,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
const u8 *wpa_ie;
size_t wpa_ie_len;
- hostapd_wpa_auth_conf(hapd->conf, &_conf);
+ hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
@@ -572,7 +643,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
void hostapd_reconfig_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config wpa_auth_conf;
- hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
+ hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf);
wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
}
@@ -601,5 +672,6 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R
l2_packet_deinit(hapd->l2);
+ hapd->l2 = NULL;
#endif /* CONFIG_IEEE80211R */
}
diff --git a/contrib/wpa/src/ap/wpa_auth_i.h b/contrib/wpa/src/ap/wpa_auth_i.h
index 97489d3..7b2cd3e 100644
--- a/contrib/wpa/src/ap/wpa_auth_i.h
+++ b/contrib/wpa/src/ap/wpa_auth_i.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
- * Copyright (c) 2004-2007, 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.
@@ -26,6 +26,7 @@ struct wpa_state_machine {
struct wpa_group *group;
u8 addr[ETH_ALEN];
+ u8 p2p_dev_addr[ETH_ALEN];
enum {
WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
@@ -57,6 +58,8 @@ struct wpa_state_machine {
Boolean GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
+ u8 alt_SNonce[WPA_NONCE_LEN];
+ u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
u8 PMK[PMK_LEN];
struct wpa_ptk PTK;
Boolean PTK_valid;
@@ -83,6 +86,7 @@ struct wpa_state_machine {
unsigned int mgmt_frame_prot:1;
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
+ unsigned int alt_snonce_valid:1;
#ifdef CONFIG_IEEE80211R
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
@@ -117,9 +121,22 @@ struct wpa_state_machine {
u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
* message 2/4 */
u8 *assoc_resp_ftie;
+
+ void (*ft_pending_cb)(void *ctx, const u8 *dst, const u8 *bssid,
+ u16 auth_transaction, u16 status,
+ 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_auth_transaction;
+ u8 ft_pending_current_ap[ETH_ALEN];
#endif /* CONFIG_IEEE80211R */
int pending_1_of_4_timeout;
+
+#ifdef CONFIG_P2P
+ u8 ip_addr[4];
+#endif /* CONFIG_P2P */
};
@@ -138,7 +155,8 @@ struct wpa_group {
enum {
WPA_GROUP_GTK_INIT = 0,
- WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
+ WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE,
+ WPA_GROUP_FATAL_FAILURE
} wpa_group_state;
u8 GMK[WPA_GMK_LEN];
@@ -148,7 +166,7 @@ struct wpa_group {
Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy;
#ifdef CONFIG_IEEE80211W
- u8 IGTK[2][WPA_IGTK_LEN];
+ u8 IGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
#endif /* CONFIG_IEEE80211W */
};
@@ -183,6 +201,10 @@ struct wpa_authenticator {
struct rsn_pmksa_cache *pmksa;
struct wpa_ft_pmk_cache *ft_pmk_cache;
+
+#ifdef CONFIG_P2P
+ struct bitfield *ip_pool;
+#endif /* CONFIG_P2P */
};
@@ -208,11 +230,14 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
struct wpa_stsl_negotiation *neg);
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+ 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);
+ 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);
+ 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
@@ -223,7 +248,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk, size_t ptk_len);
+ struct wpa_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);
diff --git a/contrib/wpa/src/ap/wpa_auth_ie.c b/contrib/wpa/src/ap/wpa_auth_ie.c
index 4fd0135..f287297 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-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.
@@ -200,6 +200,16 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_SAE */
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -261,7 +271,25 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
/* Management Group Cipher Suite */
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+ switch (conf->group_mgmt_cipher) {
+ case WPA_CIPHER_AES_128_CMAC:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+ break;
+ case WPA_CIPHER_BIP_GMAC_128:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
+ break;
+ case WPA_CIPHER_BIP_GMAC_256:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
+ break;
+ case WPA_CIPHER_BIP_CMAC_256:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Invalid group management cipher (0x%x)",
+ conf->group_mgmt_cipher);
+ return -1;
+ }
pos += RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
@@ -295,6 +323,55 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
+static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
+{
+ u8 *len;
+ u16 capab;
+
+ *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+ len = eid++; /* to be filled */
+ WPA_PUT_BE24(eid, OUI_WFA);
+ eid += 3;
+ *eid++ = HS20_OSEN_OUI_TYPE;
+
+ /* Group Data Cipher Suite */
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ eid += RSN_SELECTOR_LEN;
+
+ /* Pairwise Cipher Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
+ eid += RSN_SELECTOR_LEN;
+
+ /* AKM Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
+ eid += RSN_SELECTOR_LEN;
+
+ /* RSN Capabilities */
+ capab = 0;
+ if (conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+#ifdef CONFIG_IEEE80211W
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#endif /* CONFIG_IEEE80211W */
+ WPA_PUT_LE16(eid, capab);
+ eid += 2;
+
+ *len = eid - len - 1;
+
+ return eid;
+}
+
+
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
u8 *pos, buf[128];
@@ -302,6 +379,9 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
pos = buf;
+ if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
+ pos = wpa_write_osen(&wpa_auth->conf, pos);
+ }
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
res = wpa_write_rsn_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos, NULL);
@@ -407,6 +487,10 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ 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
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
@@ -485,6 +569,10 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
if (0) {
}
+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ 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
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -534,7 +622,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
- if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+ if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
+ {
wpa_printf(MSG_DEBUG, "Unsupported management group "
"cipher %d", data.mgmt_group_cipher);
return WPA_INVALID_MGMT_GROUP_CIPHER;
@@ -564,12 +653,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_IEEE80211R */
- if (ciphers & WPA_CIPHER_CCMP)
- sm->pairwise = WPA_CIPHER_CCMP;
- else if (ciphers & WPA_CIPHER_GCMP)
- sm->pairwise = WPA_CIPHER_GCMP;
- else
- sm->pairwise = WPA_CIPHER_TKIP;
+ sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
+ if (sm->pairwise < 0)
+ return WPA_INVALID_PAIRWISE;
/* TODO: clear WPA/WPA2 state if STA changes from one to another */
if (wpa_ie[0] == WLAN_EID_RSN)
@@ -607,7 +693,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
break;
}
}
- if (sm->pmksa) {
+ if (sm->pmksa && pmkid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKID found from PMKSA cache "
"eap_type=%d vlan_id=%d",
@@ -629,6 +715,36 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
+#ifdef CONFIG_HS20
+int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ const u8 *osen_ie, size_t osen_ie_len)
+{
+ if (wpa_auth == NULL || sm == NULL)
+ return -1;
+
+ /* TODO: parse OSEN element */
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+ sm->mgmt_frame_prot = 1;
+ sm->pairwise = WPA_CIPHER_CCMP;
+ sm->wpa = WPA_VERSION_WPA2;
+
+ if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) {
+ os_free(sm->wpa_ie);
+ sm->wpa_ie = os_malloc(osen_ie_len);
+ if (sm->wpa_ie == NULL)
+ return -1;
+ }
+
+ os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len);
+ sm->wpa_ie_len = osen_ie_len;
+
+ return 0;
+}
+
+#endif /* CONFIG_HS20 */
+
+
/**
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
* @pos: Pointer to the IE header
@@ -651,6 +767,12 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
+ if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ ie->osen = pos;
+ ie->osen_len = pos[1] + 2;
+ return 0;
+ }
+
if (pos + 1 + RSN_SELECTOR_LEN < end &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
@@ -711,6 +833,25 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_P2P
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+ ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: IP Address Allocation in EAPOL-Key",
+ ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+#endif /* CONFIG_P2P */
+
return 0;
}
diff --git a/contrib/wpa/src/ap/wpa_auth_ie.h b/contrib/wpa/src/ap/wpa_auth_ie.h
index 4999139..d2067ba 100644
--- a/contrib/wpa/src/ap/wpa_auth_ie.h
+++ b/contrib/wpa/src/ap/wpa_auth_ie.h
@@ -39,6 +39,13 @@ struct wpa_eapol_ie_parse {
const u8 *ftie;
size_t ftie_len;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+ const u8 *ip_addr_req;
+ const u8 *ip_addr_alloc;
+#endif /* CONFIG_P2P */
+
+ const u8 *osen;
+ size_t osen_len;
};
int wpa_parse_kde_ies(const u8 *buf, size_t len,
diff --git a/contrib/wpa/src/ap/wps_hostapd.c b/contrib/wpa/src/ap/wps_hostapd.c
index 5ce4f1b..b0e8b0b 100644
--- a/contrib/wpa/src/ap/wps_hostapd.c
+++ b/contrib/wpa/src/ap/wps_hostapd.c
@@ -40,11 +40,13 @@ static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
const u8 *ie, size_t ie_len,
int ssi_signal);
static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+static void hostapd_wps_nfc_clear(struct wps_context *wps);
struct wps_for_each_data {
int (*func)(struct hostapd_data *h, void *ctx);
void *ctx;
+ struct hostapd_data *calling_hapd;
};
@@ -57,7 +59,14 @@ static int wps_for_each(struct hostapd_iface *iface, void *ctx)
return 0;
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
- int ret = data->func(hapd, data->ctx);
+ int ret;
+
+ if (hapd != data->calling_hapd &&
+ (hapd->conf->wps_independent ||
+ data->calling_hapd->conf->wps_independent))
+ continue;
+
+ ret = data->func(hapd, data->ctx);
if (ret)
return ret;
}
@@ -74,6 +83,7 @@ static int hostapd_wps_for_each(struct hostapd_data *hapd,
struct wps_for_each_data data;
data.func = func;
data.ctx = ctx;
+ data.calling_hapd = hapd;
if (iface->interfaces == NULL ||
iface->interfaces->for_each_interface == NULL)
return wps_for_each(iface, &data);
@@ -82,15 +92,24 @@ static int hostapd_wps_for_each(struct hostapd_data *hapd,
}
-static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
+ const u8 *p2p_dev_addr, const u8 *psk,
size_t psk_len)
{
struct hostapd_data *hapd = ctx;
struct hostapd_wpa_psk *p;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
- wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA "
- MACSTR, MAC2STR(mac_addr));
+ if (is_zero_ether_addr(p2p_dev_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
+ MAC2STR(mac_addr));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
+ " P2P Device Addr " MACSTR,
+ MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
+ }
wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
if (psk_len != PMK_LEN) {
@@ -104,8 +123,14 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
if (p == NULL)
return -1;
os_memcpy(p->addr, mac_addr, ETH_ALEN);
+ os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN);
+ if (hapd->new_psk_cb) {
+ hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
+ psk, psk_len);
+ }
+
p->next = ssid->wpa_psk;
ssid->wpa_psk = p;
@@ -160,7 +185,7 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
dev->model_number, dev->serial_number,
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
sizeof(devtype)));
- if (len > 0 && len < (int) sizeof(txt))
+ if (!os_snprintf_error(sizeof(txt), len))
wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
if (hapd->conf->wps_pin_requests) {
@@ -263,6 +288,20 @@ static void wps_reload_config(void *eloop_data, void *user_ctx)
}
+void hostapd_wps_eap_completed(struct hostapd_data *hapd)
+{
+ /*
+ * Reduce race condition of the station trying to reconnect immediately
+ * after AP reconfiguration through WPS by rescheduling the reload
+ * timeout to happen after EAP completion rather than the originally
+ * scheduled 100 ms after new configuration became known.
+ */
+ if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL) ==
+ 1)
+ wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload");
+}
+
+
static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
size_t attr_len)
{
@@ -277,6 +316,84 @@ static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
}
+static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
+ const struct wps_credential *cred)
+{
+ struct hostapd_bss_config *bss = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
+
+ bss->wps_state = 2;
+ if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+ os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
+ bss->ssid.ssid_len = cred->ssid_len;
+ bss->ssid.ssid_set = 1;
+ }
+
+ if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+ (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+ bss->wpa = 3;
+ else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+ bss->wpa = 2;
+ else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ bss->wpa = 1;
+ else
+ bss->wpa = 0;
+
+ if (bss->wpa) {
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+ if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+ bss->wpa_pairwise = 0;
+ if (cred->encr_type & WPS_ENCR_AES)
+ bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+ if (cred->encr_type & WPS_ENCR_TKIP)
+ bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+ bss->wpa_pairwise,
+ bss->rsn_pairwise);
+
+ if (cred->key_len >= 8 && cred->key_len < 64) {
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
+ if (bss->ssid.wpa_passphrase)
+ os_memcpy(bss->ssid.wpa_passphrase, cred->key,
+ cred->key_len);
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
+ } else if (cred->key_len == 64) {
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk =
+ os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (bss->ssid.wpa_psk &&
+ hexstr2bin((const char *) cred->key,
+ bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
+ bss->ssid.wpa_psk->group = 1;
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = NULL;
+ }
+ }
+ bss->auth_algs = 1;
+ } else {
+ /*
+ * WPS 2.0 does not allow WEP to be configured, so no need to
+ * process that option here either.
+ */
+ bss->auth_algs = 1;
+ }
+
+ /* Schedule configuration reload after short period of time to allow
+ * EAP-WSC to be finished.
+ */
+ eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+ NULL);
+
+ return 0;
+}
+
+
static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
{
const struct wps_credential *cred = ctx;
@@ -325,6 +442,8 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
hapd->wps->ssid_len = cred->ssid_len;
hapd->wps->encr_types = 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;
if (cred->key_len == 0) {
os_free(hapd->wps->network_key);
hapd->wps->network_key = NULL;
@@ -344,7 +463,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
hapd->wps->wps_state = WPS_STATE_CONFIGURED;
if (hapd->iface->config_fname == NULL)
- return 0;
+ return hapd_wps_reconfig_in_memory(hapd, cred);
len = os_strlen(hapd->iface->config_fname) + 5;
tmp_fname = os_malloc(len);
if (tmp_fname == NULL)
@@ -437,31 +556,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "auth_algs=1\n");
} else {
- if ((cred->auth_type & WPS_AUTH_OPEN) &&
- (cred->auth_type & WPS_AUTH_SHARED))
- fprintf(nconf, "auth_algs=3\n");
- else if (cred->auth_type & WPS_AUTH_SHARED)
- fprintf(nconf, "auth_algs=2\n");
- else
- fprintf(nconf, "auth_algs=1\n");
-
- if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
- int key_idx = cred->key_idx;
- if (key_idx)
- key_idx--;
- fprintf(nconf, "wep_default_key=%d\n", key_idx);
- fprintf(nconf, "wep_key%d=", key_idx);
- if (cred->key_len == 10 || cred->key_len == 26) {
- /* WEP key as a hex string */
- for (i = 0; i < cred->key_len; i++)
- fputc(cred->key[i], nconf);
- } else {
- /* Raw WEP key; convert to hex */
- for (i = 0; i < cred->key_len; i++)
- fprintf(nconf, "%02x", cred->key[i]);
- }
- fprintf(nconf, "\n");
- }
+ /*
+ * WPS 2.0 does not allow WEP to be configured, so no need to
+ * process that option here either.
+ */
+ fprintf(nconf, "auth_algs=1\n");
}
fprintf(nconf, "# WPS configuration - END\n");
@@ -590,6 +689,12 @@ static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
struct wps_event_pwd_auth_fail *data)
{
+ /* Update WPS Status - Authentication Failure */
+ wpa_printf(MSG_DEBUG, "WPS: Authentication failure update");
+ hapd->wps_stats.status = WPS_STATUS_FAILURE;
+ hapd->wps_stats.failure_reason = WPS_EI_AUTH_FAILURE;
+ os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN);
+
hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
}
@@ -617,21 +722,59 @@ static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd)
}
-static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
- "No Error", /* WPS_EI_NO_ERROR */
- "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
- "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
-};
+static void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd)
+{
+ /* Update WPS Status - PBC Overlap */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP;
+}
+
+
+static void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd)
+{
+ /* Update WPS PBC Status:PBC Timeout */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT;
+}
+
+
+static void hostapd_wps_event_pbc_active(struct hostapd_data *hapd)
+{
+ /* Update WPS PBC status - Active */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE;
+}
+
+
+static void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd)
+{
+ /* Update WPS PBC status - Active */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
+}
+
+
+static void hostapd_wps_event_success(struct hostapd_data *hapd,
+ struct wps_event_success *success)
+{
+ /* Update WPS status - Success */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
+ hapd->wps_stats.status = WPS_STATUS_SUCCESS;
+ os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN);
+}
+
static void hostapd_wps_event_fail(struct hostapd_data *hapd,
struct wps_event_fail *fail)
{
+ /* Update WPS status - Failure */
+ hapd->wps_stats.status = WPS_STATUS_FAILURE;
+ os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN);
+
+ hapd->wps_stats.failure_reason = fail->error_indication;
+
if (fail->error_indication > 0 &&
fail->error_indication < NUM_WPS_EI_VALUES) {
wpa_msg(hapd->msg_ctx, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
- wps_event_fail_reason[fail->error_indication]);
+ wps_ei_str(fail->error_indication));
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
@@ -653,17 +796,28 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
hostapd_wps_event_fail(hapd, &data->fail);
break;
case WPS_EV_SUCCESS:
+ hostapd_wps_event_success(hapd, &data->success);
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
break;
case WPS_EV_PWD_AUTH_FAIL:
hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
break;
case WPS_EV_PBC_OVERLAP:
+ hostapd_wps_event_pbc_overlap(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
break;
case WPS_EV_PBC_TIMEOUT:
+ hostapd_wps_event_pbc_timeout(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
break;
+ case WPS_EV_PBC_ACTIVE:
+ hostapd_wps_event_pbc_active(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE);
+ break;
+ case WPS_EV_PBC_DISABLE:
+ hostapd_wps_event_pbc_disable(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE);
+ break;
case WPS_EV_ER_AP_ADD:
break;
case WPS_EV_ER_AP_REMOVE:
@@ -685,7 +839,16 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
}
-static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
+static int hostapd_wps_rf_band_cb(void *ctx)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+ WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+}
+
+
+static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
{
wpabuf_free(hapd->wps_beacon_ie);
hapd->wps_beacon_ie = NULL;
@@ -693,6 +856,9 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
wpabuf_free(hapd->wps_probe_resp_ie);
hapd->wps_probe_resp_ie = NULL;
+ if (deinit_only)
+ return;
+
hostapd_set_ap_wps_ie(hapd);
}
@@ -706,7 +872,8 @@ static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
return 0;
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
- if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+ if (hapd->wps && !hapd->conf->wps_independent &&
+ !is_nil_uuid(hapd->wps->uuid)) {
*uuid = hapd->wps->uuid;
return 1;
}
@@ -774,6 +941,21 @@ static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
}
+static void hostapd_free_wps(struct wps_context *wps)
+{
+ int i;
+
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(wps->dev.vendor_ext[i]);
+ wps_device_data_free(&wps->dev);
+ os_free(wps->network_key);
+ hostapd_wps_nfc_clear(wps);
+ wpabuf_free(wps->dh_pubkey);
+ wpabuf_free(wps->dh_privkey);
+ os_free(wps);
+}
+
+
int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf)
{
@@ -781,7 +963,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
struct wps_registrar_config cfg;
if (conf->wps_state == 0) {
- hostapd_wps_clear_ies(hapd);
+ hostapd_wps_clear_ies(hapd, 0);
return 0;
}
@@ -791,6 +973,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->cred_cb = hostapd_wps_cred_cb;
wps->event_cb = hostapd_wps_event_cb;
+ wps->rf_band_cb = hostapd_wps_rf_band_cb;
wps->cb_ctx = hapd;
os_memset(&cfg, 0, sizeof(cfg));
@@ -799,7 +982,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
if (is_nil_uuid(hapd->conf->uuid)) {
const u8 *uuid;
uuid = get_own_uuid(hapd->iface);
- if (uuid) {
+ if (uuid && !conf->wps_independent) {
os_memcpy(wps->uuid, uuid, UUID_LEN);
wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
"interface", wps->uuid, UUID_LEN);
@@ -829,7 +1012,6 @@ int hostapd_init_wps(struct hostapd_data *hapd,
os_strdup(hapd->conf->serial_number) : NULL;
wps->config_methods =
wps_config_methods_str2bin(hapd->conf->config_methods);
-#ifdef CONFIG_WPS2
if ((wps->config_methods &
(WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
@@ -844,14 +1026,11 @@ int hostapd_init_wps(struct hostapd_data *hapd,
"virtual_push_button for WPS 2.0 compliance");
wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
}
-#endif /* CONFIG_WPS2 */
os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
WPS_DEV_TYPE_LEN);
- if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) {
- os_free(wps);
- return -1;
- }
+ if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
+ goto fail;
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
@@ -869,7 +1048,7 @@ 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)
+ if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))
wps->encr_types |= WPS_ENCR_AES;
if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
wps->encr_types |= WPS_ENCR_TKIP;
@@ -890,18 +1069,6 @@ int hostapd_init_wps(struct hostapd_data *hapd,
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
wps->encr_types |= WPS_ENCR_NONE;
wps->auth_types |= WPS_AUTH_OPEN;
- } else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
- wps->encr_types |= WPS_ENCR_WEP;
- if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
- wps->auth_types |= WPS_AUTH_OPEN;
- if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
- wps->auth_types |= WPS_AUTH_SHARED;
- } else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
- wps->auth_types |= WPS_AUTH_OPEN;
- if (conf->default_wep_key_len)
- wps->encr_types |= WPS_ENCR_WEP;
- else
- wps->encr_types |= WPS_ENCR_NONE;
}
if (conf->ssid.wpa_psk_file) {
@@ -911,19 +1078,15 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
} else if (conf->ssid.wpa_psk) {
wps->network_key = os_malloc(2 * PMK_LEN + 1);
- if (wps->network_key == NULL) {
- os_free(wps);
- return -1;
- }
+ if (wps->network_key == NULL)
+ goto fail;
wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
conf->ssid.wpa_psk->psk, PMK_LEN);
wps->network_key_len = 2 * PMK_LEN;
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
wps->network_key = os_malloc(conf->ssid.wep.len[0]);
- if (wps->network_key == NULL) {
- os_free(wps);
- return -1;
- }
+ if (wps->network_key == NULL)
+ goto fail;
os_memcpy(wps->network_key, conf->ssid.wep.key[0],
conf->ssid.wep.len[0]);
wps->network_key_len = conf->ssid.wep.len[0];
@@ -934,6 +1097,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->psk_set = 1;
}
+ wps->ap_auth_type = wps->auth_types;
+ wps->ap_encr_type = wps->encr_types;
if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
/* Override parameters to enable security by default */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
@@ -962,13 +1127,12 @@ int hostapd_init_wps(struct hostapd_data *hapd,
cfg.dualband = 1;
if (cfg.dualband)
wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
+ cfg.force_per_enrollee_psk = conf->force_per_enrollee_psk;
wps->registrar = wps_registrar_init(wps, &cfg);
if (wps->registrar == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar");
- os_free(wps->network_key);
- os_free(wps);
- return -1;
+ goto fail;
}
#ifdef CONFIG_WPS_UPNP
@@ -984,6 +1148,10 @@ int hostapd_init_wps(struct hostapd_data *hapd,
hapd->wps = wps;
return 0;
+
+fail:
+ hostapd_free_wps(wps);
+ return -1;
}
@@ -998,8 +1166,7 @@ int hostapd_init_wps_complete(struct hostapd_data *hapd)
if (hostapd_wps_upnp_init(hapd, wps) < 0) {
wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
wps_registrar_deinit(wps->registrar);
- os_free(wps->network_key);
- os_free(wps);
+ hostapd_free_wps(wps);
hapd->wps = NULL;
return -1;
}
@@ -1012,6 +1179,7 @@ int hostapd_init_wps_complete(struct hostapd_data *hapd)
static void hostapd_wps_nfc_clear(struct wps_context *wps)
{
#ifdef CONFIG_WPS_NFC
+ wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps);
wps->ap_nfc_dev_pw_id = 0;
wpabuf_free(wps->ap_nfc_dh_pubkey);
wps->ap_nfc_dh_pubkey = NULL;
@@ -1027,21 +1195,19 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
{
eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
- if (hapd->wps == NULL)
+ eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL);
+ if (hapd->wps == NULL) {
+ hostapd_wps_clear_ies(hapd, 1);
return;
+ }
#ifdef CONFIG_WPS_UPNP
hostapd_wps_upnp_deinit(hapd);
#endif /* CONFIG_WPS_UPNP */
wps_registrar_deinit(hapd->wps->registrar);
- os_free(hapd->wps->network_key);
- wps_device_data_free(&hapd->wps->dev);
- wpabuf_free(hapd->wps->dh_pubkey);
- wpabuf_free(hapd->wps->dh_privkey);
wps_free_pending_msgs(hapd->wps->upnp_msgs);
- hostapd_wps_nfc_clear(hapd->wps);
- os_free(hapd->wps);
+ hostapd_free_wps(hapd->wps);
hapd->wps = NULL;
- hostapd_wps_clear_ies(hapd);
+ hostapd_wps_clear_ies(hapd, 1);
}
@@ -1123,7 +1289,7 @@ static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
{
const u8 *p2p_dev_addr = ctx;
if (hapd->wps == NULL)
- return 0;
+ return -1;
return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
}
@@ -1139,7 +1305,7 @@ int hostapd_wps_button_pushed(struct hostapd_data *hapd,
static int wps_cancel(struct hostapd_data *hapd, void *ctx)
{
if (hapd->wps == NULL)
- return 0;
+ return -1;
wps_registrar_wps_cancel(hapd->wps->registrar);
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
@@ -1260,6 +1426,16 @@ static int hostapd_rx_req_put_wlan_response(
return 0;
}
+ if (!sta->eapol_sm) {
+ /*
+ * This can happen, e.g., if an ER sends an extra message after
+ * the station has disassociated (but not fully
+ * deauthenticated).
+ */
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Matching STA did not have EAPOL state machine initialized");
+ return 0;
+ }
+
p = os_zalloc(sizeof(*p));
if (p == NULL)
return -1;
@@ -1406,7 +1582,7 @@ int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
int ret;
ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
- if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
+ if (os_snprintf_error(sizeof(data.pin_txt), ret))
return -1;
data.timeout = timeout;
return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
@@ -1453,8 +1629,6 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
if (encr) {
if (os_strncmp(encr, "NONE", 4) == 0)
cred.encr_type = WPS_ENCR_NONE;
- else if (os_strncmp(encr, "WEP", 3) == 0)
- cred.encr_type = WPS_ENCR_WEP;
else if (os_strncmp(encr, "TKIP", 4) == 0)
cred.encr_type = WPS_ENCR_TKIP;
else if (os_strncmp(encr, "CCMP", 4) == 0)
@@ -1569,7 +1743,8 @@ struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
if (hapd->wps == NULL)
return NULL;
- ret = wps_get_oob_cred(hapd->wps);
+ ret = wps_get_oob_cred(hapd->wps, hostapd_wps_rf_band_cb(hapd),
+ hapd->iconf->channel);
if (ndef && ret) {
struct wpabuf *tmp;
tmp = ndef_build_wifi(ret);
@@ -1583,8 +1758,150 @@ struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
}
+struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
+{
+ struct wpabuf *ret;
+
+ if (hapd->wps == NULL)
+ return NULL;
+
+ if (hapd->conf->wps_nfc_dh_pubkey == NULL) {
+ struct wps_context *wps = hapd->wps;
+ if (wps_nfc_gen_dh(&hapd->conf->wps_nfc_dh_pubkey,
+ &hapd->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+ hostapd_wps_nfc_clear(wps);
+ wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ wps->ap_nfc_dh_pubkey =
+ wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+ wps->ap_nfc_dh_privkey =
+ wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+ if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
+ hostapd_wps_nfc_clear(wps);
+ return NULL;
+ }
+ }
+
+ ret = wps_build_nfc_handover_sel(hapd->wps,
+ hapd->conf->wps_nfc_dh_pubkey,
+ hapd->own_addr, hapd->iface->freq);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ struct wpabuf *wps;
+ int ret = -1;
+ u16 wsc_len;
+ const u8 *pos;
+ struct wpabuf msg;
+ struct wps_parse_attr attr;
+ u16 dev_pw_id;
+
+ /*
+ * Enrollee/station is always initiator of the NFC connection handover,
+ * so use the request message here to find Enrollee public key hash.
+ */
+ wps = ndef_parse_wifi(req);
+ if (wps == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+ "payload from NFC connection handover");
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+ if (wpabuf_len(wps) < 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+ "Message");
+ goto out;
+ }
+ pos = wpabuf_head(wps);
+ wsc_len = WPA_GET_BE16(pos);
+ if (wsc_len > wpabuf_len(wps) - 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+ "in rt Wi-Fi Handover Request Message", wsc_len);
+ goto out;
+ }
+ pos += 2;
+
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: WSC attributes in Wi-Fi Handover Request Message",
+ pos, wsc_len);
+ if (wsc_len < wpabuf_len(wps) - 2) {
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: Ignore extra data after WSC attributes",
+ pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+ }
+
+ wpabuf_set(&msg, pos, wsc_len);
+ ret = wps_parse_msg(&msg, &attr);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+ "Wi-Fi Handover Request Message");
+ goto out;
+ }
+
+ if (attr.oob_dev_password == NULL ||
+ attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+ "included in Wi-Fi Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ if (attr.uuid_e == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+ "Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+ attr.oob_dev_password, attr.oob_dev_password_len);
+ dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+ WPS_OOB_PUBKEY_HASH_LEN);
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+ "%u in Wi-Fi Handover Request Message", dev_pw_id);
+ ret = -1;
+ goto out;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+ attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+ ret = wps_registrar_add_nfc_pw_token(hapd->wps->registrar,
+ attr.oob_dev_password,
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ NULL, 0, 1);
+
+out:
+ wpabuf_free(wps);
+ return ret;
+}
+
+
struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
{
+ if (hapd->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ hapd->conf->wps_nfc_dev_pw_id,
+ hapd->conf->wps_nfc_dh_pubkey,
+ hapd->conf->wps_nfc_dev_pw);
+ }
+
return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
&hapd->conf->wps_nfc_dh_pubkey,
&hapd->conf->wps_nfc_dh_privkey,
@@ -1595,6 +1912,7 @@ struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
{
struct wps_context *wps = hapd->wps;
+ struct wpabuf *pw;
if (wps == NULL)
return -1;
@@ -1606,10 +1924,22 @@ int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
return -1;
hostapd_wps_nfc_clear(wps);
+ wpa_printf(MSG_DEBUG,
+ "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)",
+ hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps);
wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
- wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+ pw = hapd->conf->wps_nfc_dev_pw;
+ wps->ap_nfc_dev_pw = wpabuf_alloc(
+ wpabuf_len(pw) * 2 + 1);
+ if (wps->ap_nfc_dev_pw) {
+ wpa_snprintf_hex_uppercase(
+ (char *) wpabuf_put(wps->ap_nfc_dev_pw,
+ wpabuf_len(pw) * 2),
+ wpabuf_len(pw) * 2 + 1,
+ wpabuf_head(pw), wpabuf_len(pw));
+ }
if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
!wps->ap_nfc_dev_pw) {
@@ -1623,6 +1953,8 @@ int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
{
+ wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s",
+ hapd->conf->iface);
hostapd_wps_nfc_clear(hapd->wps);
}
diff --git a/contrib/wpa/src/ap/wps_hostapd.h b/contrib/wpa/src/ap/wps_hostapd.h
index 4e5026b..204bd82 100644
--- a/contrib/wpa/src/ap/wps_hostapd.h
+++ b/contrib/wpa/src/ap/wps_hostapd.h
@@ -16,6 +16,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
int hostapd_init_wps_complete(struct hostapd_data *hapd);
void hostapd_deinit_wps(struct hostapd_data *hapd);
void hostapd_update_wps(struct hostapd_data *hapd);
+void hostapd_wps_eap_completed(struct hostapd_data *hapd);
int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
const char *uuid, const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
@@ -35,6 +36,10 @@ int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
const struct wpabuf *data);
struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
int ndef);
+struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
@@ -60,6 +65,10 @@ static inline void hostapd_update_wps(struct hostapd_data *hapd)
{
}
+static inline void hostapd_wps_eap_completed(struct hostapd_data *hapd)
+{
+}
+
static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
const u8 *addr,
char *buf, size_t buflen)
diff --git a/contrib/wpa/src/ap/x_snoop.c b/contrib/wpa/src/ap/x_snoop.c
new file mode 100644
index 0000000..8f77015
--- /dev/null
+++ b/contrib/wpa/src/ap/x_snoop.c
@@ -0,0 +1,123 @@
+/*
+ * Generic Snooping for Proxy ARP
+ * Copyright (c) 2014, 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 "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "x_snoop.h"
+
+
+int x_snoop_init(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ if (!conf->isolate) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: ap_isolate must be enabled for x_snoop");
+ return -1;
+ }
+
+ if (conf->bridge[0] == '\0') {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Bridge must be configured for x_snoop");
+ return -1;
+ }
+
+ if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+ 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable hairpin_mode on the bridge port");
+ return -1;
+ }
+
+ if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable proxyarp on the bridge port");
+ return -1;
+ }
+
+ if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
+ 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+ void (*handler)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ enum l2_packet_filter_type type)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct l2_packet_data *l2;
+
+ l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
+ if (l2 == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to initialize L2 packet processing %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ if (l2_packet_set_packet_filter(l2, type)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to set L2 packet filter for type: %d",
+ type);
+ l2_packet_deinit(l2);
+ return NULL;
+ }
+
+ return l2;
+}
+
+
+void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *buf,
+ size_t len)
+{
+ int res;
+ u8 addr[ETH_ALEN];
+ u8 *dst_addr = buf;
+
+ if (!(dst_addr[0] & 0x01))
+ return;
+
+ wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion "
+ MACSTR " -> " MACSTR " (len %u)",
+ MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len);
+
+ /* save the multicast destination address for restoring it later */
+ os_memcpy(addr, buf, ETH_ALEN);
+
+ os_memcpy(buf, sta->addr, ETH_ALEN);
+ res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to send mcast to ucast converted packet to "
+ MACSTR, MAC2STR(sta->addr));
+ }
+
+ /* restore the multicast destination address */
+ os_memcpy(buf, addr, ETH_ALEN);
+}
+
+
+void x_snoop_deinit(struct hostapd_data *hapd)
+{
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
+ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
+ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
+}
diff --git a/contrib/wpa/src/ap/x_snoop.h b/contrib/wpa/src/ap/x_snoop.h
new file mode 100644
index 0000000..e43a78d
--- /dev/null
+++ b/contrib/wpa/src/ap/x_snoop.h
@@ -0,0 +1,56 @@
+/*
+ * Generic Snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef X_SNOOP_H
+#define X_SNOOP_H
+
+#include "l2_packet/l2_packet.h"
+
+#ifdef CONFIG_PROXYARP
+
+int x_snoop_init(struct hostapd_data *hapd);
+struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+ void (*handler)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ enum l2_packet_filter_type type);
+void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *buf,
+ size_t len);
+void x_snoop_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_PROXYARP */
+
+static inline int x_snoop_init(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+static inline struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+ void (*handler)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ enum l2_packet_filter_type type)
+{
+ return NULL;
+}
+
+static inline void
+x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+ struct sta_info *sta, void *buf,
+ size_t len)
+{
+}
+
+static inline void x_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_PROXYARP */
+
+#endif /* X_SNOOP_H */
diff --git a/contrib/wpa/src/common/common_module_tests.c b/contrib/wpa/src/common/common_module_tests.c
new file mode 100644
index 0000000..56b1122
--- /dev/null
+++ b/contrib/wpa/src/common/common_module_tests.c
@@ -0,0 +1,172 @@
+/*
+ * common module tests
+ * Copyright (c) 2014, 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 "ieee802_11_common.h"
+#include "wpa_common.h"
+
+
+struct ieee802_11_parse_test_data {
+ u8 *data;
+ size_t len;
+ ParseRes result;
+ int count;
+};
+
+static const struct ieee802_11_parse_test_data parse_tests[] = {
+ { (u8 *) "", 0, ParseOK, 0 },
+ { (u8 *) " ", 1, ParseFailed, 0 },
+ { (u8 *) "\xff\x00", 2, ParseUnknown, 1 },
+ { (u8 *) "\xff\x01", 2, ParseFailed, 0 },
+ { (u8 *) "\xdd\x03\x01\x02\x03", 5, ParseUnknown, 1 },
+ { (u8 *) "\xdd\x04\x01\x02\x03\x04", 6, ParseUnknown, 1 },
+ { (u8 *) "\xdd\x04\x00\x50\xf2\x02", 6, ParseUnknown, 1 },
+ { (u8 *) "\xdd\x05\x00\x50\xf2\x02\x02", 7, ParseOK, 1 },
+ { (u8 *) "\xdd\x05\x00\x50\xf2\x02\xff", 7, ParseUnknown, 1 },
+ { (u8 *) "\xdd\x04\x00\x50\xf2\xff", 6, ParseUnknown, 1 },
+ { (u8 *) "\xdd\x04\x50\x6f\x9a\xff", 6, ParseUnknown, 1 },
+ { (u8 *) "\xdd\x04\x00\x90\x4c\x33", 6, ParseOK, 1 },
+ { (u8 *) "\xdd\x04\x00\x90\x4c\xff\xdd\x04\x00\x90\x4c\x33", 12,
+ ParseUnknown, 2 },
+ { (u8 *) "\x10\x01\x00\x21\x00", 5, ParseOK, 2 },
+ { (u8 *) "\x24\x00", 2, ParseOK, 1 },
+ { (u8 *) "\x38\x00", 2, ParseOK, 1 },
+ { (u8 *) "\x54\x00", 2, ParseOK, 1 },
+ { (u8 *) "\x5a\x00", 2, ParseOK, 1 },
+ { (u8 *) "\x65\x00", 2, ParseOK, 1 },
+ { (u8 *) "\x65\x12\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11",
+ 20, ParseOK, 1 },
+ { (u8 *) "\x6e\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xc7\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xc7\x01\x00", 3, ParseOK, 1 },
+ { NULL, 0, ParseOK, 0 }
+};
+
+static int ieee802_11_parse_tests(void)
+{
+ int i, ret = 0;
+
+ wpa_printf(MSG_INFO, "ieee802_11_parse tests");
+
+ for (i = 0; parse_tests[i].data; i++) {
+ const struct ieee802_11_parse_test_data *test;
+ struct ieee802_11_elems elems;
+ ParseRes res;
+
+ test = &parse_tests[i];
+ res = ieee802_11_parse_elems(test->data, test->len, &elems, 1);
+ if (res != test->result ||
+ ieee802_11_ie_count(test->data, test->len) != test->count) {
+ wpa_printf(MSG_ERROR, "ieee802_11_parse test %d failed",
+ i);
+ ret = -1;
+ }
+ }
+
+ if (ieee802_11_vendor_ie_concat((const u8 *) "\x00\x01", 2, 0) != NULL)
+ {
+ wpa_printf(MSG_ERROR,
+ "ieee802_11_vendor_ie_concat test failed");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+struct rsn_ie_parse_test_data {
+ u8 *data;
+ size_t len;
+ int result;
+};
+
+static const struct rsn_ie_parse_test_data rsn_parse_tests[] = {
+ { (u8 *) "", 0, -1 },
+ { (u8 *) "\x30\x00", 2, -1 },
+ { (u8 *) "\x30\x02\x01\x00", 4, 0 },
+ { (u8 *) "\x30\x02\x00\x00", 4, -2 },
+ { (u8 *) "\x30\x02\x02\x00", 4, -2 },
+ { (u8 *) "\x30\x02\x00\x01", 4, -2 },
+ { (u8 *) "\x30\x02\x00\x00\x00", 5, -2 },
+ { (u8 *) "\x30\x03\x01\x00\x00", 5, -3 },
+ { (u8 *) "\x30\x06\x01\x00\x00\x00\x00\x00", 8, -1 },
+ { (u8 *) "\x30\x06\x01\x00\x00\x0f\xac\x04", 8, 0 },
+ { (u8 *) "\x30\x07\x01\x00\x00\x0f\xac\x04\x00", 9, -5 },
+ { (u8 *) "\x30\x08\x01\x00\x00\x0f\xac\x04\x00\x00", 10, -4 },
+ { (u8 *) "\x30\x08\x01\x00\x00\x0f\xac\x04\x00\x01", 10, -4 },
+ { (u8 *) "\x30\x0c\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04",
+ 14, 0 },
+ { (u8 *) "\x30\x0c\x01\x00\x00\x0f\xac\x04\x00\x01\x00\x0f\xac\x04",
+ 14, -4 },
+ { (u8 *) "\x30\x0c\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x06",
+ 14, -1 },
+ { (u8 *) "\x30\x10\x01\x00\x00\x0f\xac\x04\x02\x00\x00\x0f\xac\x04\x00\x0f\xac\x08",
+ 18, 0 },
+ { (u8 *) "\x30\x0d\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x00",
+ 15, -7 },
+ { (u8 *) "\x30\x0e\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x00\x00",
+ 16, -6 },
+ { (u8 *) "\x30\x0e\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x00\x01",
+ 16, -6 },
+ { (u8 *) "\x30\x12\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01",
+ 20, 0 },
+ { (u8 *) "\x30\x16\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x02\x00\x00\x0f\xac\x01\x00\x0f\xac\x02",
+ 24, 0 },
+ { (u8 *) "\x30\x13\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00",
+ 21, 0 },
+ { (u8 *) "\x30\x14\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00",
+ 22, 0 },
+ { (u8 *) "\x30\x16\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00",
+ 24, 0 },
+ { (u8 *) "\x30\x16\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x01",
+ 24, -9 },
+ { (u8 *) "\x30\x1a\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00\x00\x00\x00\x00",
+ 28, -10 },
+ { (u8 *) "\x30\x1a\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00\x00\x0f\xac\x06",
+ 28, 0 },
+ { (u8 *) "\x30\x1c\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x00\x00\x00\x00\x00\x0f\xac\x06\x01\x02",
+ 30, 0 },
+ { NULL, 0, 0 }
+};
+
+static int rsn_ie_parse_tests(void)
+{
+ int i, ret = 0;
+
+ wpa_printf(MSG_INFO, "rsn_ie_parse tests");
+
+ for (i = 0; rsn_parse_tests[i].data; i++) {
+ const struct rsn_ie_parse_test_data *test;
+ struct wpa_ie_data data;
+
+ test = &rsn_parse_tests[i];
+ if (wpa_parse_wpa_ie_rsn(test->data, test->len, &data) !=
+ test->result) {
+ wpa_printf(MSG_ERROR, "rsn_ie_parse test %d failed", i);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+int common_module_tests(void)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "common module tests");
+
+ if (ieee802_11_parse_tests() < 0 ||
+ rsn_ie_parse_tests() < 0)
+ ret = -1;
+
+ return ret;
+}
diff --git a/contrib/wpa/src/common/defs.h b/contrib/wpa/src/common/defs.h
index 281dd8a..b5f4f80 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-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.
@@ -23,11 +23,15 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_CIPHER_WEP104 BIT(2)
#define WPA_CIPHER_TKIP BIT(3)
#define WPA_CIPHER_CCMP BIT(4)
-#ifdef CONFIG_IEEE80211W
#define WPA_CIPHER_AES_128_CMAC BIT(5)
-#endif /* CONFIG_IEEE80211W */
#define WPA_CIPHER_GCMP BIT(6)
#define WPA_CIPHER_SMS4 BIT(7)
+#define WPA_CIPHER_GCMP_256 BIT(8)
+#define WPA_CIPHER_CCMP_256 BIT(9)
+#define WPA_CIPHER_BIP_GMAC_128 BIT(11)
+#define WPA_CIPHER_BIP_GMAC_256 BIT(12)
+#define WPA_CIPHER_BIP_CMAC_256 BIT(13)
+#define WPA_CIPHER_GTK_NOT_USED BIT(14)
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
@@ -44,13 +48,19 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
#define WPA_KEY_MGMT_CCKM BIT(14)
+#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)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_CCKM |
- WPA_KEY_MGMT_IEEE8021X_SHA256));
+ WPA_KEY_MGMT_OSEN |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -58,7 +68,8 @@ static inline int wpa_key_mgmt_wpa_psk(int akm)
return !!(akm & (WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_PSK_SHA256 |
- WPA_KEY_MGMT_SAE));
+ WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_ft(int akm)
@@ -77,13 +88,27 @@ static inline int wpa_key_mgmt_sae(int akm)
static inline int wpa_key_mgmt_sha256(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SHA256));
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_OSEN |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+}
+
+static inline int wpa_key_mgmt_sha384(int akm)
+{
+ return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+}
+
+static inline int wpa_key_mgmt_suite_b(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
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_wpa_psk(akm) ||
+ wpa_key_mgmt_sae(akm);
}
static inline int wpa_key_mgmt_wpa_any(int akm)
@@ -100,6 +125,7 @@ static inline int wpa_key_mgmt_cckm(int akm)
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
#define WPA_PROTO_WAPI BIT(2)
+#define WPA_PROTO_OSEN BIT(3)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
@@ -117,41 +143,12 @@ enum wpa_alg {
WPA_ALG_PMK,
WPA_ALG_GCMP,
WPA_ALG_SMS4,
- WPA_ALG_KRK
-};
-
-/**
- * enum wpa_cipher - Cipher suites
- */
-enum wpa_cipher {
- CIPHER_NONE,
- CIPHER_WEP40,
- CIPHER_TKIP,
- CIPHER_CCMP,
- CIPHER_WEP104,
- CIPHER_GCMP,
- CIPHER_SMS4
-};
-
-/**
- * enum wpa_key_mgmt - Key management suites
- */
-enum wpa_key_mgmt {
- KEY_MGMT_802_1X,
- KEY_MGMT_PSK,
- KEY_MGMT_NONE,
- KEY_MGMT_802_1X_NO_WPA,
- KEY_MGMT_WPA_NONE,
- KEY_MGMT_FT_802_1X,
- KEY_MGMT_FT_PSK,
- KEY_MGMT_802_1X_SHA256,
- KEY_MGMT_PSK_SHA256,
- KEY_MGMT_WPS,
- KEY_MGMT_SAE,
- KEY_MGMT_FT_SAE,
- KEY_MGMT_WAPI_PSK,
- KEY_MGMT_WAPI_CERT,
- KEY_MGMT_CCKM
+ WPA_ALG_KRK,
+ WPA_ALG_GCMP_256,
+ WPA_ALG_CCMP_256,
+ WPA_ALG_BIP_GMAC_128,
+ WPA_ALG_BIP_GMAC_256,
+ WPA_ALG_BIP_CMAC_256
};
/**
@@ -312,10 +309,21 @@ enum wpa_ctrl_req_type {
WPA_CTRL_REQ_EAP_PIN,
WPA_CTRL_REQ_EAP_OTP,
WPA_CTRL_REQ_EAP_PASSPHRASE,
+ WPA_CTRL_REQ_SIM,
NUM_WPA_CTRL_REQS
};
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8
+enum mesh_plink_state {
+ PLINK_LISTEN = 1,
+ PLINK_OPEN_SENT,
+ PLINK_OPEN_RCVD,
+ PLINK_CNF_RCVD,
+ PLINK_ESTAB,
+ PLINK_HOLDING,
+ PLINK_BLOCKED,
+};
+
#endif /* DEFS_H */
diff --git a/contrib/wpa/src/common/eapol_common.h b/contrib/wpa/src/common/eapol_common.h
index 4811f38..6958661 100644
--- a/contrib/wpa/src/common/eapol_common.h
+++ b/contrib/wpa/src/common/eapol_common.h
@@ -22,17 +22,28 @@ struct ieee802_1x_hdr {
/* followed by length octets of data */
} STRUCT_PACKED;
+struct ieee8023_hdr {
+ u8 dest[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u16 ethertype;
+} STRUCT_PACKED;
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
+#ifdef CONFIG_MACSEC
+#define EAPOL_VERSION 3
+#else /* CONFIG_MACSEC */
#define EAPOL_VERSION 2
+#endif /* CONFIG_MACSEC */
enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
IEEE802_1X_TYPE_EAPOL_START = 1,
IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
IEEE802_1X_TYPE_EAPOL_KEY = 3,
- IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
+ IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4,
+ IEEE802_1X_TYPE_EAPOL_MKA = 5,
};
enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
diff --git a/contrib/wpa/src/common/hw_features_common.c b/contrib/wpa/src/common/hw_features_common.c
new file mode 100644
index 0000000..e8babb5
--- /dev/null
+++ b/contrib/wpa/src/common/hw_features_common.c
@@ -0,0 +1,438 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * 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 "includes.h"
+
+#include "common.h"
+#include "defs.h"
+#include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+#include "hw_features_common.h"
+
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+ int chan, int *freq)
+{
+ int i;
+
+ if (freq)
+ *freq = 0;
+
+ if (!mode)
+ return NULL;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+ if (ch->chan == chan) {
+ if (freq)
+ *freq = ch->freq;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+ int freq, int *chan)
+{
+ int i;
+
+ if (chan)
+ *chan = 0;
+
+ if (!mode)
+ return NULL;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+ if (ch->freq == freq) {
+ if (chan)
+ *chan = ch->chan;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
+{
+ int freq;
+
+ hw_get_channel_chan(mode, chan, &freq);
+
+ return freq;
+}
+
+
+int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
+{
+ int chan;
+
+ hw_get_channel_freq(mode, freq, &chan);
+
+ return chan;
+}
+
+
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
+ int sec_chan)
+{
+ int ok, j, first;
+ int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+ 184, 192 };
+ size_t k;
+
+ if (pri_chan == sec_chan || !sec_chan)
+ return 1; /* HT40 not used */
+
+ wpa_printf(MSG_DEBUG,
+ "HT40: control channel: %d secondary channel: %d",
+ pri_chan, sec_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) {
+ wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
+ sec_chan);
+ return 0;
+ }
+
+ /*
+ * Verify that HT40 primary,secondary channel pair is allowed per
+ * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
+ * 2.4 GHz rules allow all cases where the secondary channel fits into
+ * the list of allowed channels (already checked above).
+ */
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 1;
+
+ first = pri_chan < sec_chan ? pri_chan : sec_chan;
+
+ ok = 0;
+ for (k = 0; k < ARRAY_SIZE(allowed); k++) {
+ if (first == allowed[k]) {
+ ok = 1;
+ break;
+ }
+ }
+ if (!ok) {
+ wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
+ pri_chan, sec_chan);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
+{
+ struct ieee80211_ht_operation *oper;
+ struct ieee802_11_elems elems;
+
+ *pri_chan = *sec_chan = 0;
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+ if (elems.ht_operation &&
+ elems.ht_operation_len >= sizeof(*oper)) {
+ oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+ *pri_chan = oper->primary_chan;
+ if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
+ int sec = oper->ht_param &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ *sec_chan = *pri_chan + 4;
+ else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ *sec_chan = *pri_chan - 4;
+ }
+ }
+}
+
+
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan)
+{
+ int pri_freq, sec_freq, pri_bss, sec_bss;
+ int bss_pri_chan, bss_sec_chan;
+ size_t i;
+ int match;
+
+ if (!mode || !scan_res || !pri_chan || !sec_chan)
+ return 0;
+
+ if (pri_chan == sec_chan)
+ return 0;
+
+ pri_freq = hw_get_freq(mode, pri_chan);
+ sec_freq = hw_get_freq(mode, sec_chan);
+
+ /*
+ * Switch PRI/SEC channels if Beacons were detected on selected SEC
+ * channel, but not on selected PRI channel.
+ */
+ pri_bss = sec_bss = 0;
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ if (bss->freq == pri_freq)
+ pri_bss++;
+ else if (bss->freq == sec_freq)
+ sec_bss++;
+ }
+ if (sec_bss && !pri_bss) {
+ wpa_printf(MSG_INFO,
+ "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes");
+ return 2;
+ }
+
+ /*
+ * Match PRI/SEC channel with any existing HT40 BSS on the same
+ * channels that we are about to use (if already mixed order in
+ * existing BSSes, use own preference).
+ */
+ match = 0;
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+ if (pri_chan == bss_pri_chan &&
+ sec_chan == bss_sec_chan) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) {
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+ if (pri_chan == bss_sec_chan &&
+ sec_chan == bss_pri_chan) {
+ wpa_printf(MSG_INFO, "Switch own primary and "
+ "secondary channel due to BSS "
+ "overlap with " MACSTR,
+ MAC2STR(bss->bssid));
+ return 2;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
+{
+ struct ieee802_11_elems elems;
+ struct ieee80211_ht_operation *oper;
+
+ if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
+ return 0;
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+ if (!elems.ht_capabilities) {
+ wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
+ MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+ return 1;
+ }
+
+ if (elems.ht_operation &&
+ elems.ht_operation_len >= sizeof(*oper)) {
+ oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+ if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
+ MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+ return 1;
+ }
+ return 0;
+}
+
+
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan)
+{
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ size_t i;
+
+ if (!mode || !scan_res || !pri_chan || !sec_chan)
+ return 0;
+
+ if (pri_chan == sec_chan)
+ return 0;
+
+ pri_freq = hw_get_freq(mode, pri_chan);
+ sec_freq = hw_get_freq(mode, sec_chan);
+
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ int pri = bss->freq;
+ int sec = pri;
+ struct ieee802_11_elems elems;
+
+ /* Check for overlapping 20 MHz BSS */
+ if (check_20mhz_bss(bss, pri_freq, affected_start,
+ affected_end)) {
+ wpa_printf(MSG_DEBUG,
+ "Overlapping 20 MHz BSS is found");
+ return 0;
+ }
+
+ get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+ if (sec_chan) {
+ if (sec_chan < pri_chan)
+ sec = pri - 20;
+ else
+ sec = pri + 20;
+ }
+
+ if ((pri < affected_start || pri > affected_end) &&
+ (sec < affected_start || sec > affected_end))
+ continue; /* not within affected channel range */
+
+ wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+ " freq=%d pri=%d sec=%d",
+ MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+ if (sec_chan) {
+ if (pri_freq != pri || sec_freq != sec) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz pri/sec mismatch with BSS "
+ MACSTR
+ " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+ MAC2STR(bss->bssid),
+ pri, sec, pri_chan,
+ sec > pri ? '+' : '-',
+ pri_freq, sec_freq);
+ return 0;
+ }
+ }
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+ 0);
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capabilities)) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz Intolerant is set on channel %d in BSS "
+ MACSTR, pri, MAC2STR(bss->bssid));
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+ enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled,
+ int vht_enabled, int sec_channel_offset,
+ int vht_oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps)
+{
+ int tmp;
+
+ os_memset(data, 0, sizeof(*data));
+ data->mode = mode;
+ data->freq = freq;
+ data->channel = channel;
+ data->ht_enabled = ht_enabled;
+ data->vht_enabled = vht_enabled;
+ data->sec_channel_offset = sec_channel_offset;
+ data->center_freq1 = freq + sec_channel_offset * 10;
+ data->center_freq2 = 0;
+ data->bandwidth = sec_channel_offset ? 40 : 20;
+
+ if (data->vht_enabled) switch (vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ if (center_segment1)
+ return -1;
+ if (center_segment0 != 0 &&
+ 5000 + center_segment0 * 5 != data->center_freq1 &&
+ 2407 + center_segment0 * 5 != data->center_freq1)
+ return -1;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
+ wpa_printf(MSG_ERROR,
+ "80+80 channel width is not supported!");
+ return -1;
+ }
+ if (center_segment1 == center_segment0 + 4 ||
+ center_segment1 == center_segment0 - 4)
+ return -1;
+ data->center_freq2 = 5000 + center_segment1 * 5;
+ /* fall through */
+ case VHT_CHANWIDTH_80MHZ:
+ data->bandwidth = 80;
+ if (vht_oper_chwidth == 1 && center_segment1)
+ return -1;
+ if (vht_oper_chwidth == 3 && !center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ /* primary 40 part must match the HT configuration */
+ tmp = (30 + freq - 5000 - center_segment0 * 5) / 20;
+ tmp /= 2;
+ if (data->center_freq1 != 5000 +
+ center_segment0 * 5 - 20 + 40 * tmp)
+ return -1;
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ data->bandwidth = 160;
+ if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ wpa_printf(MSG_ERROR,
+ "160MHZ channel width is not supported!");
+ return -1;
+ }
+ if (center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ /* primary 40 part must match the HT configuration */
+ tmp = (70 + freq - 5000 - center_segment0 * 5) / 20;
+ tmp /= 2;
+ if (data->center_freq1 != 5000 +
+ center_segment0 * 5 - 60 + 40 * tmp)
+ return -1;
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ break;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/common/hw_features_common.h b/contrib/wpa/src/common/hw_features_common.h
new file mode 100644
index 0000000..7f43d00
--- /dev/null
+++ b/contrib/wpa/src/common/hw_features_common.h
@@ -0,0 +1,40 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * 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 HW_FEATURES_COMMON_H
+#define HW_FEATURES_COMMON_H
+
+#include "drivers/driver.h"
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+ int chan, int *freq);
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+ int freq, int *chan);
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
+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);
+void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan);
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end);
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan);
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+ enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled,
+ int vht_enabled, int sec_channel_offset,
+ int vht_oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps);
+
+#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 98fadda..aca0b73 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, 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 "defs.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
@@ -107,10 +108,15 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->hs20 = pos;
elems->hs20_len = elen;
break;
+ case HS20_OSEN_OUI_TYPE:
+ /* Hotspot 2.0 OSEN */
+ elems->osen = pos;
+ elems->osen_len = elen;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
- "(type=%d len=%lu)\n",
+ "(type=%d len=%lu)",
pos[3], (unsigned long) elen);
return -1;
}
@@ -122,6 +128,15 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->vendor_ht_cap = pos;
elems->vendor_ht_cap_len = elen;
break;
+ case VENDOR_VHT_TYPE:
+ if (elen > 4 &&
+ (pos[4] == VENDOR_VHT_SUBTYPE ||
+ pos[4] == VENDOR_VHT_SUBTYPE2)) {
+ elems->vendor_vht = pos;
+ elems->vendor_vht_len = elen;
+ } else
+ return -1;
+ break;
default:
wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
"information element ignored "
@@ -188,25 +203,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->supp_rates = pos;
elems->supp_rates_len = elen;
break;
- case WLAN_EID_FH_PARAMS:
- elems->fh_params = pos;
- elems->fh_params_len = elen;
- break;
case WLAN_EID_DS_PARAMS:
elems->ds_params = pos;
elems->ds_params_len = elen;
break;
case WLAN_EID_CF_PARAMS:
- elems->cf_params = pos;
- elems->cf_params_len = elen;
- break;
case WLAN_EID_TIM:
- elems->tim = pos;
- elems->tim_len = elen;
- break;
- case WLAN_EID_IBSS_PARAMS:
- elems->ibss_params = pos;
- elems->ibss_params_len = elen;
break;
case WLAN_EID_CHALLENGE:
elems->challenge = pos;
@@ -231,8 +233,6 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->rsn_ie_len = elen;
break;
case WLAN_EID_PWR_CAPABILITY:
- elems->power_cap = pos;
- elems->power_cap_len = elen;
break;
case WLAN_EID_SUPPORTED_CHANNELS:
elems->supp_channels = pos;
@@ -258,6 +258,18 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
+ case WLAN_EID_MESH_CONFIG:
+ elems->mesh_config = pos;
+ elems->mesh_config_len = elen;
+ break;
+ case WLAN_EID_MESH_ID:
+ elems->mesh_id = pos;
+ elems->mesh_id_len = elen;
+ break;
+ case WLAN_EID_PEER_MGMT:
+ elems->peer_mgmt = pos;
+ elems->peer_mgmt_len = elen;
+ break;
case WLAN_EID_VHT_CAP:
elems->vht_capabilities = pos;
elems->vht_capabilities_len = elen;
@@ -266,6 +278,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->vht_operation = pos;
elems->vht_operation_len = elen;
break;
+ case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
+ if (elen != 1)
+ break;
+ elems->vht_opmode_notif = pos;
+ break;
case WLAN_EID_LINK_ID:
if (elen < 18)
break;
@@ -275,6 +292,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->interworking = pos;
elems->interworking_len = elen;
break;
+ case WLAN_EID_QOS_MAP_SET:
+ if (elen < 16)
+ break;
+ elems->qos_map_set = pos;
+ elems->qos_map_set_len = elen;
+ break;
case WLAN_EID_EXT_CAPAB:
elems->ext_capab = pos;
elems->ext_capab_len = elen;
@@ -288,6 +311,16 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->ssid_list = pos;
elems->ssid_list_len = elen;
break;
+ case WLAN_EID_AMPE:
+ elems->ampe = pos;
+ elems->ampe_len = elen;
+ break;
+ case WLAN_EID_MIC:
+ elems->mic = pos;
+ elems->mic_len = elen;
+ /* after mic everything is encrypted, so stop. */
+ left = elen;
+ break;
default:
unknown++;
if (!show_errors)
@@ -486,3 +519,405 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
return 0;
}
+
+
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
+{
+ enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
+
+ if (freq >= 2412 && freq <= 2472) {
+ mode = HOSTAPD_MODE_IEEE80211G;
+ *channel = (freq - 2407) / 5;
+ } else if (freq == 2484) {
+ mode = HOSTAPD_MODE_IEEE80211B;
+ *channel = 14;
+ } else if (freq >= 4900 && freq < 5000) {
+ mode = HOSTAPD_MODE_IEEE80211A;
+ *channel = (freq - 4000) / 5;
+ } else if (freq >= 5000 && freq < 5900) {
+ mode = HOSTAPD_MODE_IEEE80211A;
+ *channel = (freq - 5000) / 5;
+ } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+ mode = HOSTAPD_MODE_IEEE80211AD;
+ *channel = (freq - 56160) / 2160;
+ }
+
+ return mode;
+}
+
+
+static const char *us_op_class_cc[] = {
+ "US", "CA", NULL
+};
+
+static const char *eu_op_class_cc[] = {
+ "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
+ "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
+ "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
+ "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
+};
+
+static const char *jp_op_class_cc[] = {
+ "JP", NULL
+};
+
+static const char *cn_op_class_cc[] = {
+ "CN", "CA", NULL
+};
+
+
+static int country_match(const char *cc[], const char *country)
+{
+ int i;
+
+ if (country == NULL)
+ return 0;
+ for (i = 0; cc[i]; i++) {
+ if (cc[i][0] == country[0] && cc[i][1] == country[1])
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 12: /* channels 1..11 */
+ case 32: /* channels 1..7; 40 MHz */
+ case 33: /* channels 5..11; 40 MHz */
+ if (chan < 1 || chan > 11)
+ return -1;
+ return 2407 + 5 * chan;
+ case 1: /* channels 36,40,44,48 */
+ case 2: /* channels 52,56,60,64; dfs */
+ case 22: /* channels 36,44; 40 MHz */
+ case 23: /* channels 52,60; 40 MHz */
+ case 27: /* channels 40,48; 40 MHz */
+ case 28: /* channels 56,64; 40 MHz */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 4: /* channels 100-144 */
+ case 24: /* channels 100-140; 40 MHz */
+ if (chan < 100 || chan > 144)
+ return -1;
+ return 5000 + 5 * chan;
+ case 3: /* channels 149,153,157,161 */
+ case 25: /* channels 149,157; 40 MHz */
+ case 26: /* channels 149,157; 40 MHz */
+ case 30: /* channels 153,161; 40 MHz */
+ case 31: /* channels 153,161; 40 MHz */
+ if (chan < 149 || chan > 161)
+ return -1;
+ return 5000 + 5 * chan;
+ case 34: /* 60 GHz band, channels 1..3 */
+ if (chan < 1 || chan > 3)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 4: /* channels 1..13 */
+ case 11: /* channels 1..9; 40 MHz */
+ case 12: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 1: /* channels 36,40,44,48 */
+ case 2: /* channels 52,56,60,64; dfs */
+ case 5: /* channels 36,44; 40 MHz */
+ case 6: /* channels 52,60; 40 MHz */
+ case 8: /* channels 40,48; 40 MHz */
+ case 9: /* channels 56,64; 40 MHz */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 3: /* channels 100-140 */
+ case 7: /* channels 100-132; 40 MHz */
+ case 10: /* channels 104-136; 40 MHz */
+ case 16: /* channels 100-140 */
+ if (chan < 100 || chan > 140)
+ return -1;
+ return 5000 + 5 * chan;
+ case 17: /* channels 149,153,157,161,165,169 */
+ if (chan < 149 || chan > 169)
+ return -1;
+ return 5000 + 5 * chan;
+ case 18: /* 60 GHz band, channels 1..4 */
+ if (chan < 1 || chan > 4)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 30: /* channels 1..13 */
+ case 56: /* channels 1..9; 40 MHz */
+ case 57: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 31: /* channel 14 */
+ if (chan != 14)
+ return -1;
+ return 2414 + 5 * chan;
+ case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
+ case 32: /* channels 52,56,60,64 */
+ case 33: /* channels 52,56,60,64 */
+ case 36: /* channels 36,44; 40 MHz */
+ case 37: /* channels 52,60; 40 MHz */
+ case 38: /* channels 52,60; 40 MHz */
+ case 41: /* channels 40,48; 40 MHz */
+ case 42: /* channels 56,64; 40 MHz */
+ case 43: /* channels 56,64; 40 MHz */
+ if (chan < 34 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 34: /* channels 100-140 */
+ case 35: /* channels 100-140 */
+ case 39: /* channels 100-132; 40 MHz */
+ case 40: /* channels 100-132; 40 MHz */
+ case 44: /* channels 104-136; 40 MHz */
+ case 45: /* channels 104-136; 40 MHz */
+ case 58: /* channels 100-140 */
+ if (chan < 100 || chan > 140)
+ return -1;
+ return 5000 + 5 * chan;
+ case 59: /* 60 GHz band, channels 1..4 */
+ if (chan < 1 || chan > 3)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 7: /* channels 1..13 */
+ case 8: /* channels 1..9; 40 MHz */
+ case 9: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 1: /* channels 36,40,44,48 */
+ case 2: /* channels 52,56,60,64; dfs */
+ case 4: /* channels 36,44; 40 MHz */
+ case 5: /* channels 52,60; 40 MHz */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 3: /* channels 149,153,157,161,165 */
+ case 6: /* channels 149,157; 40 MHz */
+ if (chan < 149 || chan > 165)
+ return -1;
+ return 5000 + 5 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
+{
+ /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+ switch (op_class) {
+ case 81:
+ /* channels 1..13 */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 82:
+ /* channel 14 */
+ if (chan != 14)
+ return -1;
+ return 2414 + 5 * chan;
+ case 83: /* channels 1..9; 40 MHz */
+ case 84: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 115: /* channels 36,40,44,48; indoor only */
+ case 116: /* channels 36,44; 40 MHz; indoor only */
+ case 117: /* channels 40,48; 40 MHz; indoor only */
+ case 118: /* channels 52,56,60,64; dfs */
+ case 119: /* channels 52,60; 40 MHz; dfs */
+ case 120: /* channels 56,64; 40 MHz; dfs */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 121: /* channels 100-140 */
+ case 122: /* channels 100-142; 40 MHz */
+ case 123: /* channels 104-136; 40 MHz */
+ if (chan < 100 || chan > 140)
+ return -1;
+ return 5000 + 5 * chan;
+ case 124: /* channels 149,153,157,161 */
+ case 125: /* channels 149,153,157,161,165,169 */
+ case 126: /* channels 149,157; 40 MHz */
+ case 127: /* channels 153,161; 40 MHz */
+ if (chan < 149 || chan > 161)
+ return -1;
+ return 5000 + 5 * chan;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ if (chan < 36 || chan > 161)
+ return -1;
+ return 5000 + 5 * chan;
+ case 129: /* center freqs 50, 114; 160 MHz */
+ if (chan < 50 || chan > 114)
+ return -1;
+ return 5000 + 5 * chan;
+ case 180: /* 60 GHz band, channels 1..4 */
+ if (chan < 1 || chan > 4)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+/**
+ * ieee80211_chan_to_freq - Convert channel info to frequency
+ * @country: Country code, if known; otherwise, global operating class is used
+ * @op_class: Operating class
+ * @chan: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
+{
+ int freq;
+
+ if (country_match(us_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_us(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ if (country_match(eu_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_eu(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ if (country_match(jp_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_jp(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ if (country_match(cn_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_cn(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ return ieee80211_chan_to_freq_global(op_class, chan);
+}
+
+
+int ieee80211_is_dfs(int freq)
+{
+ /* TODO: this could be more accurate to better cover all domains */
+ return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
+}
+
+
+static int is_11b(u8 rate)
+{
+ return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+int supp_rates_11b_only(struct ieee802_11_elems *elems)
+{
+ int num_11b = 0, num_others = 0;
+ int i;
+
+ if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
+ return 0;
+
+ for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
+ if (is_11b(elems->supp_rates[i]))
+ num_11b++;
+ else
+ num_others++;
+ }
+
+ for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
+ i++) {
+ if (is_11b(elems->ext_supp_rates[i]))
+ num_11b++;
+ else
+ num_others++;
+ }
+
+ return num_11b > 0 && num_others == 0;
+}
+
+
+const char * fc2str(u16 fc)
+{
+ u16 stype = WLAN_FC_GET_STYPE(fc);
+#define C2S(x) case x: return #x;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case WLAN_FC_TYPE_MGMT:
+ switch (stype) {
+ C2S(WLAN_FC_STYPE_ASSOC_REQ)
+ C2S(WLAN_FC_STYPE_ASSOC_RESP)
+ C2S(WLAN_FC_STYPE_REASSOC_REQ)
+ C2S(WLAN_FC_STYPE_REASSOC_RESP)
+ C2S(WLAN_FC_STYPE_PROBE_REQ)
+ C2S(WLAN_FC_STYPE_PROBE_RESP)
+ C2S(WLAN_FC_STYPE_BEACON)
+ C2S(WLAN_FC_STYPE_ATIM)
+ C2S(WLAN_FC_STYPE_DISASSOC)
+ C2S(WLAN_FC_STYPE_AUTH)
+ C2S(WLAN_FC_STYPE_DEAUTH)
+ C2S(WLAN_FC_STYPE_ACTION)
+ }
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ switch (stype) {
+ C2S(WLAN_FC_STYPE_PSPOLL)
+ C2S(WLAN_FC_STYPE_RTS)
+ C2S(WLAN_FC_STYPE_CTS)
+ C2S(WLAN_FC_STYPE_ACK)
+ C2S(WLAN_FC_STYPE_CFEND)
+ C2S(WLAN_FC_STYPE_CFENDACK)
+ }
+ break;
+ case WLAN_FC_TYPE_DATA:
+ switch (stype) {
+ C2S(WLAN_FC_STYPE_DATA)
+ C2S(WLAN_FC_STYPE_DATA_CFACK)
+ C2S(WLAN_FC_STYPE_DATA_CFPOLL)
+ C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
+ C2S(WLAN_FC_STYPE_NULLFUNC)
+ C2S(WLAN_FC_STYPE_CFACK)
+ C2S(WLAN_FC_STYPE_CFPOLL)
+ C2S(WLAN_FC_STYPE_CFACKPOLL)
+ C2S(WLAN_FC_STYPE_QOS_DATA)
+ C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
+ C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
+ C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
+ C2S(WLAN_FC_STYPE_QOS_NULL)
+ C2S(WLAN_FC_STYPE_QOS_CFPOLL)
+ C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
+ }
+ break;
+ }
+ return "WLAN_FC_TYPE_UNKNOWN";
+#undef C2S
+}
diff --git a/contrib/wpa/src/common/ieee802_11_common.h b/contrib/wpa/src/common/ieee802_11_common.h
index 55fa49d..7f0b296 100644
--- a/contrib/wpa/src/common/ieee802_11_common.h
+++ b/contrib/wpa/src/common/ieee802_11_common.h
@@ -13,11 +13,7 @@
struct ieee802_11_elems {
const u8 *ssid;
const u8 *supp_rates;
- const u8 *fh_params;
const u8 *ds_params;
- const u8 *cf_params;
- const u8 *tim;
- const u8 *ibss_params;
const u8 *challenge;
const u8 *erp_info;
const u8 *ext_supp_rates;
@@ -26,32 +22,36 @@ struct ieee802_11_elems {
const u8 *wmm; /* WMM Information or Parameter Element */
const u8 *wmm_tspec;
const u8 *wps_ie;
- const u8 *power_cap;
const u8 *supp_channels;
const u8 *mdie;
const u8 *ftie;
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
+ const u8 *mesh_config;
+ const u8 *mesh_id;
+ const u8 *peer_mgmt;
const u8 *vht_capabilities;
const u8 *vht_operation;
+ const u8 *vht_opmode_notif;
const u8 *vendor_ht_cap;
+ const u8 *vendor_vht;
const u8 *p2p;
const u8 *wfd;
const u8 *link_id;
const u8 *interworking;
+ const u8 *qos_map_set;
const u8 *hs20;
const u8 *ext_capab;
const u8 *bss_max_idle_period;
const u8 *ssid_list;
+ const u8 *osen;
+ const u8 *ampe;
+ const u8 *mic;
u8 ssid_len;
u8 supp_rates_len;
- u8 fh_params_len;
u8 ds_params_len;
- u8 cf_params_len;
- u8 tim_len;
- u8 ibss_params_len;
u8 challenge_len;
u8 erp_info_len;
u8 ext_supp_rates_len;
@@ -60,22 +60,29 @@ struct ieee802_11_elems {
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
u8 wmm_tspec_len;
u8 wps_ie_len;
- u8 power_cap_len;
u8 supp_channels_len;
u8 mdie_len;
u8 ftie_len;
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
+ u8 mesh_config_len;
+ u8 mesh_id_len;
+ u8 peer_mgmt_len;
u8 vht_capabilities_len;
u8 vht_operation_len;
u8 vendor_ht_cap_len;
+ u8 vendor_vht_len;
u8 p2p_len;
u8 wfd_len;
u8 interworking_len;
+ u8 qos_map_set_len;
u8 hs20_len;
u8 ext_capab_len;
u8 ssid_list_len;
+ u8 osen_len;
+ u8 ampe_len;
+ u8 mic_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -99,5 +106,11 @@ struct hostapd_wmm_ac_params {
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
+enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
+int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
+int ieee80211_is_dfs(int freq);
+int supp_rates_11b_only(struct ieee802_11_elems *elems);
+
+const char * fc2str(u16 fc);
#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 e873545..2e51935 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-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This software may be distributed under the terms of the BSD license.
@@ -25,6 +25,8 @@
#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
+#define WLAN_INVALID_MGMT_SEQ 0xFFFF
+
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
#define WLAN_GET_SEQ_SEQ(seq) \
(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
@@ -161,6 +163,8 @@
#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
#define WLAN_STATUS_TRANSMISSION_FAILURE 79
+#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
+#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -192,6 +196,16 @@
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
/* IEEE 802.11e */
#define WLAN_REASON_DISASSOC_LOW_ACK 34
+/* IEEE 802.11s */
+#define WLAN_REASON_MESH_PEERING_CANCELLED 52
+#define WLAN_REASON_MESH_MAX_PEERS 53
+#define WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION 54
+#define WLAN_REASON_MESH_CLOSE_RCVD 55
+#define WLAN_REASON_MESH_MAX_RETRIES 56
+#define WLAN_REASON_MESH_CONFIRM_TIMEOUT 57
+#define WLAN_REASON_MESH_INVALID_GTK 58
+#define WLAN_REASON_MESH_INCONSISTENT_PARAMS 59
+#define WLAN_REASON_MESH_INVALID_SECURITY_CAP 60
/* Information Element IDs */
@@ -203,6 +217,7 @@
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_BSS_LOAD 11
#define WLAN_EID_CHALLENGE 16
/* EIDs defined by IEEE 802.11h - START */
#define WLAN_EID_PWR_CONSTRAINT 32
@@ -218,16 +233,20 @@
/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_QOS 46
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_NEIGHBOR_REPORT 52
#define WLAN_EID_MOBILITY_DOMAIN 54
#define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_WAPI 68
#define WLAN_EID_TIME_ADVERTISEMENT 69
+#define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
@@ -241,8 +260,14 @@
#define WLAN_EID_LINK_ID 101
#define WLAN_EID_INTERWORKING 107
#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_QOS_MAP_SET 110
#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_MESH_CONFIG 113
+#define WLAN_EID_MESH_ID 114
+#define WLAN_EID_PEER_MGMT 117
#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_AMPE 139
+#define WLAN_EID_MIC 140
#define WLAN_EID_CCKM 156
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
@@ -266,9 +291,11 @@
#define WLAN_ACTION_FT 6
#define WLAN_ACTION_HT 7
#define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_PROTECTED_DUAL 9
#define WLAN_ACTION_WNM 10
#define WLAN_ACTION_UNPROTECTED_WNM 11
#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_SELF_PROTECTED 15
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_VENDOR_SPECIFIC 127
@@ -281,6 +308,19 @@
#define WLAN_PA_GAS_COMEBACK_RESP 13
#define WLAN_TDLS_DISCOVERY_RESPONSE 14
+/* Protected Dual of Public Action frames */
+#define WLAN_PROT_DSE_ENABLEMENT 1
+#define WLAN_PROT_DSE_DEENABLEMENT 2
+#define WLAN_PROT_EXT_CSA 4
+#define WLAN_PROT_MEASUREMENT_REQ 5
+#define WLAN_PROT_MEASUREMENT_REPORT 6
+#define WLAN_PROT_DSE_POWER_CONSTRAINT 8
+#define WLAN_PROT_VENDOR_SPECIFIC 9
+#define WLAN_PROT_GAS_INITIAL_REQ 10
+#define WLAN_PROT_GAS_INITIAL_RESP 11
+#define WLAN_PROT_GAS_COMEBACK_REQ 12
+#define WLAN_PROT_GAS_COMEBACK_RESP 13
+
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
#define WLAN_SA_QUERY_REQUEST 0
#define WLAN_SA_QUERY_RESPONSE 1
@@ -300,6 +340,19 @@
#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
#define WLAN_TDLS_DISCOVERY_REQUEST 10
+/* Radio Measurement Action codes */
+#define WLAN_RRM_RADIO_MEASUREMENT_REQUEST 0
+#define WLAN_RRM_RADIO_MEASUREMENT_REPORT 1
+#define WLAN_RRM_LINK_MEASUREMENT_REQUEST 2
+#define WLAN_RRM_LINK_MEASUREMENT_REPORT 3
+#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
+#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
+
+/* Radio Measurement capabilities (from RRM Capabilities IE) */
+/* byte 1 (out of 5) */
+#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
+#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
#define WLAN_TIMEOUT_KEY_LIFETIME 2
@@ -548,6 +601,18 @@ struct ieee80211_mgmt {
* Entries (optional) */
u8 variable[0];
} STRUCT_PACKED bss_tm_resp;
+ struct {
+ u8 action; /* 6 */
+ u8 dialog_token;
+ u8 query_reason;
+ /* BSS Transition Candidate List
+ * Entries (optional) */
+ u8 variable[0];
+ } STRUCT_PACKED bss_tm_query;
+ struct {
+ u8 action; /* 15 */
+ u8 variable[0];
+ } STRUCT_PACKED slf_prot_action;
} u;
} STRUCT_PACKED action;
} u;
@@ -557,9 +622,12 @@ struct ieee80211_mgmt {
/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
#define IEEE80211_HT_MCS_MASK_LEN 10
+/* HT Capabilities element */
struct ieee80211_ht_capabilities {
le16 ht_capabilities_info;
- u8 a_mpdu_params;
+ u8 a_mpdu_params; /* Maximum A-MPDU Length Exponent B0..B1
+ * Minimum MPDU Start Spacing B2..B4
+ * Reserved B5..B7 */
u8 supported_mcs_set[16];
le16 ht_extended_capabilities;
le32 tx_bf_capability_info;
@@ -567,18 +635,36 @@ struct ieee80211_ht_capabilities {
} STRUCT_PACKED;
+/* HT Operation element */
struct ieee80211_ht_operation {
- u8 control_chan;
- u8 ht_param;
- le16 operation_mode;
- le16 stbc_param;
- u8 basic_set[16];
+ u8 primary_chan;
+ /* Five octets of HT Operation Information */
+ u8 ht_param; /* B0..B7 */
+ le16 operation_mode; /* B8..B23 */
+ le16 param; /* B24..B39 */
+ u8 basic_mcs_set[16];
+} STRUCT_PACKED;
+
+
+struct ieee80211_obss_scan_parameters {
+ le16 scan_passive_dwell;
+ le16 scan_active_dwell;
+ le16 width_trigger_scan_interval;
+ le16 scan_passive_total_per_channel;
+ le16 scan_active_total_per_channel;
+ le16 channel_transition_delay_factor;
+ le16 scan_activity_threshold;
} STRUCT_PACKED;
struct ieee80211_vht_capabilities {
le32 vht_capabilities_info;
- u8 vht_supported_mcs_set[8];
+ struct {
+ le16 rx_map;
+ le16 rx_highest;
+ le16 tx_map;
+ le16 tx_highest;
+ } vht_supported_mcs_set;
} STRUCT_PACKED;
struct ieee80211_vht_operation {
@@ -588,6 +674,15 @@ struct ieee80211_vht_operation {
le16 vht_basic_mcs_set;
} STRUCT_PACKED;
+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];
+} STRUCT_PACKED;
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@@ -596,7 +691,9 @@ struct ieee80211_vht_operation {
#define ERP_INFO_USE_PROTECTION BIT(1)
#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+#define OVERLAPPING_BSS_TRANS_DELAY_FACTOR 5
+/* HT Capabilities Info field within HT Capabilities element */
#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0))
#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1))
#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3)))
@@ -614,73 +711,86 @@ struct ieee80211_vht_operation {
#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10))
#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11))
#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12))
-#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13))
+/* B13 - Reserved (was PSMP support during P802.11n development) */
#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14))
#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15))
-
+/* HT Extended Capabilities field within HT Capabilities element */
#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0))
+#define EXT_HT_CAP_INFO_PCO_TRANS_TIME_MASK ((u16) (BIT(1) | BIT(2)))
#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1
+/* B3..B7 - Reserved */
+#define EXT_HT_CAP_INFO_MCS_FEEDBACK_MASK ((u16) (BIT(8) | BIT(9)))
#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8
-#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10))
+#define EXT_HT_CAP_INFO_HTC_SUPPORT ((u16) BIT(10))
#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11))
-
-
-#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
-#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
-#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
-#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
-#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
-#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
-#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
-#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
-#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
-#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
-#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
-#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
-#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
-#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
-#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
-#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
-#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
-#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
-
-
-#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
-#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
-#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
-#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
-#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
-#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
-#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
-
+/* B12..B15 - Reserved */
+
+/* Transmit Beanforming Capabilities within HT Capabilities element */
+#define TX_BF_CAP_IMPLICIT_TXBF_RX_CAP ((u32) BIT(0))
+#define TX_BF_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
+#define TX_BF_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
+#define TX_BF_CAP_RX_NDP_CAP ((u32) BIT(3))
+#define TX_BF_CAP_TX_NDP_CAP ((u32) BIT(4))
+#define TX_BF_CAP_IMPLICIT_TX_BF_CAP ((u32) BIT(5))
+#define TX_BF_CAP_CALIBRATION_MASK ((u32) (BIT(6) | BIT(7))
+#define TX_BF_CAP_CALIB_OFFSET 6
+#define TX_BF_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
+#define TX_BF_CAP_EXPLICIT_NONCOMPR_STEERING_CAP ((u32) BIT(9))
+#define TX_BF_CAP_EXPLICIT_COMPR_STEERING_CAP ((u32) BIT(10))
+#define TX_BF_CAP_EXPLICIT_TX_BF_CSI_FEEDBACK_MASK ((u32) (BIT(10) | BIT(11)))
+#define TX_BF_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
+#define TX_BF_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
+#define TX_BF_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
+#define TX_BF_CAP_MINIMAL_GROUPING_OFFSET 17
+#define TX_BF_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
+#define TX_BF_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
+#define TX_BF_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
+#define TX_BF_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
+#define TX_BF_CAP_CHANNEL_ESTIMATION_CAP_MASK ((u32) (BIT(27) | BIT(28)))
+#define TX_BF_CAP_CHANNEL_ESTIMATION_CAP_OFFSET 27
+/* B29..B31 - Reserved */
+
+/* ASEL Capability field within HT Capabilities element */
+#define ASEL_CAP_ASEL_CAPABLE ((u8) BIT(0))
+#define ASEL_CAP_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
+#define ASEL_CAP_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
+#define ASEL_CAP_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
+#define ASEL_CAP_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
+#define ASEL_CAP_RX_AS_CAP ((u8) BIT(5))
+#define ASEL_CAP_TX_SOUNDING_PPDUS_CAP ((u8) BIT(6))
+/* B7 - Reserved */
+
+/* First octet of HT Operation Information within HT Operation element */
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1))
-#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2))
+#define HT_INFO_HT_PARAM_STA_CHNL_WIDTH ((u8) BIT(2))
#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3))
-#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4))
-#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5))
-
-
-#define OP_MODE_PURE 0
-#define OP_MODE_MAY_BE_LEGACY_STAS 1
-#define OP_MODE_20MHZ_HT_STA_ASSOCED 2
-#define OP_MODE_MIXED 3
-
-#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
- (0x0001 | 0x0002)
-#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
-#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
-#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
-#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4))
-
-#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6))
-#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7))
-#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8))
-#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9))
-#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
-#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
+/* B4..B7 - Reserved */
+
+/* HT Protection (B8..B9 of HT Operation Information) */
+#define HT_PROT_NO_PROTECTION 0
+#define HT_PROT_NONMEMBER_PROTECTION 1
+#define HT_PROT_20MHZ_PROTECTION 2
+#define HT_PROT_NON_HT_MIXED 3
+/* Bits within ieee80211_ht_operation::operation_mode (BIT(0) maps to B8 in
+ * HT Operation Information) */
+#define HT_OPER_OP_MODE_HT_PROT_MASK ((u16) (BIT(0) | BIT(1))) /* B8..B9 */
+#define HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT ((u16) BIT(2)) /* B10 */
+/* BIT(3), i.e., B11 in HT Operation Information field - Reserved */
+#define HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT ((u16) BIT(4)) /* B12 */
+/* BIT(5)..BIT(15), i.e., B13..B23 - Reserved */
+
+/* Last two octets of HT Operation Information (BIT(0) = B24) */
+/* B24..B29 - Reserved */
+#define HT_OPER_PARAM_DUAL_BEACON ((u16) BIT(6))
+#define HT_OPER_PARAM_DUAL_CTS_PROTECTION ((u16) BIT(7))
+#define HT_OPER_PARAM_STBC_BEACON ((u16) BIT(8))
+#define HT_OPER_PARAM_LSIG_TXOP_PROT_FULL_SUPP ((u16) BIT(9))
+#define HT_OPER_PARAM_PCO_ACTIVE ((u16) BIT(10))
+#define HT_OPER_PARAM_PCO_PHASE ((u16) BIT(11))
+/* B36..B39 - Reserved */
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
@@ -688,8 +798,11 @@ struct ieee80211_vht_operation {
/* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
#define VHT_CAP_MAX_MPDU_LENGTH_11454 ((u32) BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK ((u32) BIT(0) | BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK_SHIFT 0
#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ((u32) BIT(2))
#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3))
+#define VHT_CAP_SUPP_CHAN_WIDTH_MASK ((u32) BIT(2) | BIT(3))
#define VHT_CAP_RXLDPC ((u32) BIT(4))
#define VHT_CAP_SHORT_GI_80 ((u32) BIT(5))
#define VHT_CAP_SHORT_GI_160 ((u32) BIT(6))
@@ -698,29 +811,62 @@ struct ieee80211_vht_operation {
#define VHT_CAP_RXSTBC_2 ((u32) BIT(9))
#define VHT_CAP_RXSTBC_3 ((u32) BIT(8) | BIT(9))
#define VHT_CAP_RXSTBC_4 ((u32) BIT(10))
+#define VHT_CAP_RXSTBC_MASK ((u32) BIT(8) | BIT(9) | \
+ BIT(10))
+#define VHT_CAP_RXSTBC_MASK_SHIFT 8
#define VHT_CAP_SU_BEAMFORMER_CAPABLE ((u32) BIT(11))
#define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12))
-#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX ((u32) BIT(13) | BIT(14))
-#define VHT_CAP_SOUNDING_DIMENTION_MAX ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_BEAMFORMEE_STS_MAX ((u32) BIT(13) | \
+ BIT(14) | BIT(15))
+#define VHT_CAP_BEAMFORMEE_STS_MAX_SHIFT 13
+#define VHT_CAP_BEAMFORMEE_STS_OFFSET 13
+#define VHT_CAP_SOUNDING_DIMENSION_MAX ((u32) BIT(16) | \
+ BIT(17) | BIT(18))
+#define VHT_CAP_SOUNDING_DIMENSION_MAX_SHIFT 16
+#define VHT_CAP_SOUNDING_DIMENSION_OFFSET 16
#define VHT_CAP_MU_BEAMFORMER_CAPABLE ((u32) BIT(19))
#define VHT_CAP_MU_BEAMFORMEE_CAPABLE ((u32) BIT(20))
#define VHT_CAP_VHT_TXOP_PS ((u32) BIT(21))
#define VHT_CAP_HTC_VHT ((u32) BIT(22))
-#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT ((u32) BIT(23))
+
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_1 ((u32) BIT(23))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_2 ((u32) BIT(24))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_3 ((u32) BIT(23) | BIT(24))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_4 ((u32) BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_5 ((u32) BIT(23) | BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6 ((u32) BIT(24) | BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX ((u32) BIT(23) | \
+ BIT(24) | BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT 23
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB ((u32) BIT(27))
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27))
#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
#define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29))
+#define VHT_OPMODE_CHANNEL_WIDTH_MASK ((u8) BIT(0) | BIT(1))
+#define VHT_OPMODE_CHANNEL_RxNSS_MASK ((u8) BIT(4) | BIT(5) | \
+ BIT(6))
+#define VHT_OPMODE_NOTIF_RX_NSS_SHIFT 4
+
+#define VHT_RX_NSS_MAX_STREAMS 8
+
+/* VHT channel widths */
+#define VHT_CHANWIDTH_USE_HT 0
+#define VHT_CHANWIDTH_80MHZ 1
+#define VHT_CHANWIDTH_160MHZ 2
+#define VHT_CHANWIDTH_80P80MHZ 3
+
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
#define WPA_IE_VENDOR_TYPE 0x0050f201
+#define WMM_IE_VENDOR_TYPE 0x0050f202
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
#define WFD_IE_VENDOR_TYPE 0x506f9a0a
#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
+#define OSEN_IE_VENDOR_TYPE 0x506f9a12
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -759,6 +905,8 @@ struct wmm_information_element {
} STRUCT_PACKED;
+#define WMM_QOSINFO_AP_UAPSD 0x80
+
#define WMM_QOSINFO_STA_AC_MASK 0x0f
#define WMM_QOSINFO_STA_SP_MASK 0x03
#define WMM_QOSINFO_STA_SP_SHIFT 5
@@ -826,16 +974,18 @@ struct wmm_tspec_element {
/* Access Categories / ACI to AC coding */
-enum {
+enum wmm_ac {
WMM_AC_BE = 0 /* Best Effort */,
WMM_AC_BK = 1 /* Background */,
WMM_AC_VI = 2 /* Video */,
- WMM_AC_VO = 3 /* Voice */
+ WMM_AC_VO = 3 /* Voice */,
+ WMM_AC_NUM = 4
};
#define HS20_INDICATION_OUI_TYPE 16
#define HS20_ANQP_OUI_TYPE 17
+#define HS20_OSEN_OUI_TYPE 18
#define HS20_STYPE_QUERY_LIST 1
#define HS20_STYPE_CAPABILITY_LIST 2
#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
@@ -843,6 +993,21 @@ enum {
#define HS20_STYPE_CONNECTION_CAPABILITY 5
#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
#define HS20_STYPE_OPERATING_CLASS 7
+#define HS20_STYPE_OSU_PROVIDERS_LIST 8
+#define HS20_STYPE_ICON_REQUEST 10
+#define HS20_STYPE_ICON_BINARY_FILE 11
+
+#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 */
+
+/* WNM-Notification WFA vendors specific subtypes */
+#define HS20_WNM_SUB_REM_NEEDED 0
+#define HS20_WNM_DEAUTH_IMMINENT_NOTICE 1
+
+#define HS20_DEAUTH_REASON_CODE_BSS 0
+#define HS20_DEAUTH_REASON_CODE_ESS 1
/* Wi-Fi Direct (P2P) */
@@ -868,6 +1033,15 @@ enum p2p_attr_id {
P2P_ATTR_INTERFACE = 16,
P2P_ATTR_OPERATING_CHANNEL = 17,
P2P_ATTR_INVITATION_FLAGS = 18,
+ P2P_ATTR_OOB_GO_NEG_CHANNEL = 19,
+ P2P_ATTR_SERVICE_HASH = 21,
+ P2P_ATTR_SESSION_INFORMATION_DATA = 22,
+ P2P_ATTR_CONNECTION_CAPABILITY = 23,
+ P2P_ATTR_ADVERTISEMENT_ID = 24,
+ P2P_ATTR_ADVERTISED_SERVICE = 25,
+ P2P_ATTR_SESSION_ID = 26,
+ P2P_ATTR_FEATURE_CAPABILITY = 27,
+ P2P_ATTR_PERSISTENT_GROUP = 28,
P2P_ATTR_VENDOR_SPECIFIC = 221
};
@@ -889,6 +1063,7 @@ enum p2p_attr_id {
#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
+#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7)
/* Invitation Flags */
#define P2P_INVITATION_FLAGS_TYPE BIT(0)
@@ -911,6 +1086,13 @@ enum p2p_status_code {
P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
P2P_SC_FAIL_REJECTED_BY_USER = 11,
+ P2P_SC_SUCCESS_DEFERRED = 12,
+};
+
+enum p2p_role_indication {
+ P2P_DEVICE_NOT_IN_GROUP = 0x00,
+ P2P_CLIENT_IN_A_GROUP = 0x01,
+ P2P_GO_IN_A_GROUP = 0x02,
};
#define P2P_WILDCARD_SSID "DIRECT-"
@@ -943,6 +1125,7 @@ enum p2p_service_protocol_type {
P2P_SERV_UPNP = 2,
P2P_SERV_WS_DISCOVERY = 3,
P2P_SERV_WIFI_DISPLAY = 4,
+ P2P_SERV_P2PS = 11,
P2P_SERV_VENDOR_SPECIFIC = 255
};
@@ -967,8 +1150,24 @@ enum wifi_display_subelem {
WFD_SUBELEM_SESSION_INFO = 9
};
+/* 802.11s */
+#define MESH_SYNC_METHOD_NEIGHBOR_OFFSET 1
+#define MESH_SYNC_METHOD_VENDOR 255
+#define MESH_PATH_PROTOCOL_HWMP 1
+#define MESH_PATH_PROTOCOL_VENDOR 255
+#define MESH_PATH_METRIC_AIRTIME 1
+#define MESH_PATH_METRIC_VENDOR 255
+
+enum plink_action_field {
+ PLINK_OPEN = 1,
+ PLINK_CONFIRM,
+ PLINK_CLOSE
+};
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+#define VENDOR_VHT_TYPE 0x04
+#define VENDOR_VHT_SUBTYPE 0x08
+#define VENDOR_VHT_SUBTYPE2 0x00
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
@@ -982,6 +1181,11 @@ enum wifi_display_subelem {
#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
@@ -993,7 +1197,14 @@ enum wifi_display_subelem {
/* 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 */
@@ -1035,6 +1246,37 @@ enum wnm_action {
#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+/* IEEE Std 802.11-2012 - Table 8-253 */
+enum bss_trans_mgmt_status_code {
+ WNM_BSS_TM_ACCEPT = 0,
+ WNM_BSS_TM_REJECT_UNSPECIFIED = 1,
+ WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2,
+ WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3,
+ WNM_BSS_TM_REJECT_UNDESIRED = 4,
+ WNM_BSS_TM_REJECT_DELAY_REQUEST = 5,
+ WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+ WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7,
+ WNM_BSS_TM_REJECT_LEAVING_ESS = 8
+};
+
+#define WNM_NEIGHBOR_TSF 1
+#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2
+#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3
+#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4
+#define WNM_NEIGHBOR_BEARING 5
+#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66
+#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70
+#define WNM_NEIGHBOR_MULTIPLE_BSSID 71
+
+/* QoS action */
+enum qos_action {
+ QOS_ADDTS_REQ = 0,
+ QOS_ADDTS_RESP = 1,
+ QOS_DELTS = 2,
+ QOS_SCHEDULE = 3,
+ QOS_QOS_MAP_CONFIG = 4,
+};
+
/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
#define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0)
#define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1)
@@ -1082,4 +1324,34 @@ enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_IGTK = 1
};
+/* Channel Switch modes (802.11h) */
+#define CHAN_SWITCH_MODE_ALLOW_TX 0
+#define CHAN_SWITCH_MODE_BLOCK_TX 1
+
+struct tpc_report {
+ u8 eid;
+ u8 len;
+ u8 tx_power;
+ u8 link_margin;
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
+struct rrm_link_measurement_request {
+ u8 dialog_token;
+ s8 tx_power;
+ s8 max_tp;
+ u8 variable[0];
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.5 - Link Measurement Report frame format */
+struct rrm_link_measurement_report {
+ u8 dialog_token;
+ struct tpc_report tpc;
+ u8 rx_ant_id;
+ u8 tx_ant_id;
+ u8 rcpi;
+ u8 rsni;
+ u8 variable[0];
+} STRUCT_PACKED;
+
#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
new file mode 100644
index 0000000..cc88caa
--- /dev/null
+++ b/contrib/wpa/src/common/ieee802_1x_defs.h
@@ -0,0 +1,78 @@
+/*
+ * IEEE Std 802.1X-2010 definitions
+ * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_1X_DEFS_H
+#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_NAME_GCM_AES_128 "GCM-AES-128"
+
+enum macsec_policy {
+ /**
+ * Should secure sessions.
+ * This accepts key server's advice to determine whether to secure the
+ * session or not.
+ */
+ SHOULD_SECURE,
+
+ /**
+ * Disabled MACsec - do not secure sessions.
+ */
+ DO_NOT_SECURE,
+};
+
+
+/* IEEE Std 802.1X-2010 - Table 11-6 - MACsec Capability */
+enum macsec_cap {
+ /**
+ * MACsec is not implemented
+ */
+ MACSEC_CAP_NOT_IMPLEMENTED,
+
+ /**
+ * 'Integrity without confidentiality'
+ */
+ MACSEC_CAP_INTEGRITY,
+
+ /**
+ * 'Integrity without confidentiality' and
+ * 'Integrity and confidentiality' with a confidentiality offset of 0
+ */
+ MACSEC_CAP_INTEG_AND_CONF,
+
+ /**
+ * 'Integrity without confidentiality' and
+ * 'Integrity and confidentiality' with a confidentiality offset of 0,
+ * 30, 50
+ */
+ MACSEC_CAP_INTEG_AND_CONF_0_30_50,
+};
+
+enum validate_frames {
+ Disabled,
+ Checked,
+ Strict,
+};
+
+/* IEEE Std 802.1X-2010 - Table 11-6 - Confidentiality Offset */
+enum confidentiality_offset {
+ CONFIDENTIALITY_NONE = 0,
+ CONFIDENTIALITY_OFFSET_0 = 1,
+ CONFIDENTIALITY_OFFSET_30 = 2,
+ CONFIDENTIALITY_OFFSET_50 = 3,
+};
+
+/* IEEE Std 802.1X-2010 - Table 9-2 */
+#define DEFAULT_PRIO_INFRA_PORT 0x10
+#define DEFAULT_PRIO_PRIMRAY_AP 0x30
+#define DEFAULT_PRIO_SECONDARY_AP 0x50
+#define DEFAULT_PRIO_GROUP_CA_MEMBER 0x70
+#define DEFAULT_PRIO_NOT_KEY_SERVER 0xFF
+
+#endif /* IEEE802_1X_DEFS_H */
diff --git a/contrib/wpa/src/common/privsep_commands.h b/contrib/wpa/src/common/privsep_commands.h
index 858b51d..4dc34c4 100644
--- a/contrib/wpa/src/common/privsep_commands.h
+++ b/contrib/wpa/src/common/privsep_commands.h
@@ -31,7 +31,9 @@ struct privsep_cmd_associate
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
+ int hwmode;
int freq;
+ int channel;
int pairwise_suite;
int group_suite;
int key_mgmt_suite;
diff --git a/contrib/wpa/src/common/qca-vendor-attr.h b/contrib/wpa/src/common/qca-vendor-attr.h
new file mode 100644
index 0000000..6f51803
--- /dev/null
+++ b/contrib/wpa/src/common/qca-vendor-attr.h
@@ -0,0 +1,28 @@
+/*
+ * Qualcomm Atheros vendor specific attribute definitions
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef QCA_VENDOR_ATTR_H
+#define QCA_VENDOR_ATTR_H
+
+/*
+ * This file defines some of the attributes used with Qualcomm Atheros OUI
+ * 00:13:74 in a way that is not suitable for qca-vendor.h, e.g., due to
+ * compiler dependencies.
+ */
+
+struct qca_avoid_freq_range {
+ u32 start_freq;
+ u32 end_freq;
+} __attribute__ ((packed));
+
+struct qca_avoid_freq_list {
+ u32 count;
+ struct qca_avoid_freq_range range[0];
+} __attribute__ ((packed));
+
+#endif /* QCA_VENDOR_ATTR_H */
diff --git a/contrib/wpa/src/common/qca-vendor.h b/contrib/wpa/src/common/qca-vendor.h
new file mode 100644
index 0000000..2117ee7
--- /dev/null
+++ b/contrib/wpa/src/common/qca-vendor.h
@@ -0,0 +1,246 @@
+/*
+ * Qualcomm Atheros OUI and vendor specific assignments
+ * Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef QCA_VENDOR_H
+#define QCA_VENDOR_H
+
+/*
+ * This file is a registry of identifier assignments from the Qualcomm Atheros
+ * OUI 00:13:74 for purposes other than MAC address assignment. New identifiers
+ * can be assigned through normal review process for changes to the upstream
+ * hostap.git repository.
+ */
+
+#define OUI_QCA 0x001374
+
+/**
+ * enum qca_radiotap_vendor_ids - QCA radiotap vendor namespace IDs
+ */
+enum qca_radiotap_vendor_ids {
+ QCA_RADIOTAP_VID_WLANTEST = 0,
+};
+
+/**
+ * enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ROAMING: Set roaming policy for drivers that use
+ * internal BSS-selection. This command uses
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY to specify the new roaming policy
+ * for the current connection (i.e., changes policy set by the nl80211
+ * Connect command). @QCA_WLAN_VENDOR_ATTR_MAC_ADDR may optionally be
+ * included to indicate which BSS to use in case roaming is disabled.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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
+ * be used to request offloading of key management operations. Only used
+ * if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: An extended version of
+ * NL80211_CMD_ROAM event with optional attributes including information
+ * from offloaded key management operation. Uses
+ * enum qca_wlan_vendor_attr_roam_auth attributes. Only used
+ * if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
+ * invoke the ACS function in device and pass selected channels to
+ * hostapd.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
+ * supported by the driver. enum qca_wlan_vendor_features defines
+ * the possible features.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Event used by driver,
+ * which supports DFS offloading, to indicate a channel availability check
+ * start.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: Event used by driver,
+ * which supports DFS offloading, to indicate a channel availability check
+ * completion.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: Event used by driver,
+ * which supports DFS offloading, to indicate that the channel availability
+ * check aborted, no change to the channel status.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: Event used by
+ * driver, which supports DFS offloading, to indicate that the
+ * Non-Occupancy Period for this channel is over, channel becomes usable.
+ *
+ * @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.
+ */
+enum qca_nl80211_vendor_subcmds {
+ QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
+ QCA_NL80211_VENDOR_SUBCMD_TEST = 1,
+ /* subcmds 2..8 not yet allocated */
+ QCA_NL80211_VENDOR_SUBCMD_ROAMING = 9,
+ 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_LL_STATS_SET = 14,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET = 15,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR = 16,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS = 17,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS = 18,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS = 19,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_START = 20,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_STOP = 21,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS = 22,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES = 23,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS = 24,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE = 25,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT = 26,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT = 27,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND = 28,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST = 29,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_BSSID_HOTLIST = 30,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE = 31,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE = 32,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SIGNIFICANT_CHANGE = 33,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE = 34,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE = 35,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS = 36,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE = 37,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES = 38,
+ QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI = 39,
+ QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG = 40,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST = 41,
+ QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42,
+ /* 43..49 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50,
+ QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51,
+ QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
+ /* 53 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED = 57,
+ 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_DATA_OFFLOAD = 91,
+};
+
+
+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 */
+ 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. */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
+ QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
+ QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
+ QCA_WLAN_VENDOR_ATTR_TEST = 8,
+ /* 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_wlan_vendor_attr_roam_auth {
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
+ 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,
+ /* 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_acs_offload {
+ QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ACS_MAX =
+ QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
+};
+
+enum qca_wlan_vendor_acs_hw_mode {
+ QCA_ACS_MODE_IEEE80211B,
+ QCA_ACS_MODE_IEEE80211G,
+ QCA_ACS_MODE_IEEE80211A,
+ QCA_ACS_MODE_IEEE80211AD,
+};
+
+/**
+ * enum qca_wlan_vendor_features - Vendor device/driver feature flags
+ *
+ * @QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD: Device supports key
+ * management offload, a mechanism where the station's firmware
+ * does the exchange with the AP to establish the temporal keys
+ * after roaming, rather than having the user space wpa_supplicant do it.
+ * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
+ */
+enum qca_wlan_vendor_features {
+ QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
+ NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
+};
+
+/**
+ * enum qca_wlan_vendor_attr_data_offload_ind - Vendor Data Offload Indication
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_SESSION: Session corresponding to
+ * the offloaded data.
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_PROTOCOL: Protocol of the offloaded
+ * data.
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_EVENT: Event type for the data offload
+ * indication.
+ */
+enum qca_wlan_vendor_attr_data_offload_ind {
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_SESSION,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_PROTOCOL,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_EVENT,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_MAX =
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST - 1
+};
+#endif /* QCA_VENDOR_H */
diff --git a/contrib/wpa/src/common/sae.c b/contrib/wpa/src/common/sae.c
new file mode 100644
index 0000000..5888958
--- /dev/null
+++ b/contrib/wpa/src/common/sae.c
@@ -0,0 +1,1069 @@
+/*
+ * Simultaneous authentication of equals
+ * Copyright (c) 2012-2013, 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/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "crypto/dh_groups.h"
+#include "ieee802_11_defs.h"
+#include "sae.h"
+
+
+int sae_set_group(struct sae_data *sae, int group)
+{
+ struct sae_temporary_data *tmp;
+
+ sae_clear_data(sae);
+ tmp = sae->tmp = os_zalloc(sizeof(*tmp));
+ if (tmp == NULL)
+ return -1;
+
+ /* First, check if this is an ECC group */
+ tmp->ec = crypto_ec_init(group);
+ if (tmp->ec) {
+ sae->group = group;
+ tmp->prime_len = crypto_ec_prime_len(tmp->ec);
+ tmp->prime = crypto_ec_get_prime(tmp->ec);
+ tmp->order = crypto_ec_get_order(tmp->ec);
+ return 0;
+ }
+
+ /* Not an ECC group, check FFC */
+ tmp->dh = dh_groups_get(group);
+ if (tmp->dh) {
+ sae->group = group;
+ tmp->prime_len = tmp->dh->prime_len;
+ if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
+ sae_clear_data(sae);
+ return -1;
+ }
+
+ tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
+ tmp->prime_len);
+ if (tmp->prime_buf == NULL) {
+ sae_clear_data(sae);
+ return -1;
+ }
+ tmp->prime = tmp->prime_buf;
+
+ tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
+ tmp->dh->order_len);
+ if (tmp->order_buf == NULL) {
+ sae_clear_data(sae);
+ return -1;
+ }
+ tmp->order = tmp->order_buf;
+
+ return 0;
+ }
+
+ /* Unsupported group */
+ return -1;
+}
+
+
+void sae_clear_temp_data(struct sae_data *sae)
+{
+ struct sae_temporary_data *tmp;
+ if (sae == NULL || sae->tmp == NULL)
+ return;
+ tmp = sae->tmp;
+ crypto_ec_deinit(tmp->ec);
+ crypto_bignum_deinit(tmp->prime_buf, 0);
+ crypto_bignum_deinit(tmp->order_buf, 0);
+ crypto_bignum_deinit(tmp->sae_rand, 1);
+ crypto_bignum_deinit(tmp->pwe_ffc, 1);
+ crypto_bignum_deinit(tmp->own_commit_scalar, 0);
+ crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
+ crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
+ crypto_ec_point_deinit(tmp->pwe_ecc, 1);
+ crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
+ crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
+ wpabuf_free(tmp->anti_clogging_token);
+ bin_clear_free(tmp, sizeof(*tmp));
+ sae->tmp = NULL;
+}
+
+
+void sae_clear_data(struct sae_data *sae)
+{
+ if (sae == NULL)
+ return;
+ sae_clear_temp_data(sae);
+ crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+ os_memset(sae, 0, sizeof(*sae));
+}
+
+
+static void buf_shift_right(u8 *buf, size_t len, size_t bits)
+{
+ size_t i;
+ for (i = len - 1; i > 0; i--)
+ buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
+ buf[0] >>= bits;
+}
+
+
+static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
+{
+ u8 val[SAE_MAX_PRIME_LEN];
+ int iter = 0;
+ struct crypto_bignum *bn = NULL;
+ int order_len_bits = crypto_bignum_bits(sae->tmp->order);
+ size_t order_len = (order_len_bits + 7) / 8;
+
+ if (order_len > sizeof(val))
+ return NULL;
+
+ for (;;) {
+ if (iter++ > 100)
+ return NULL;
+ if (random_get_bytes(val, order_len) < 0)
+ return NULL;
+ if (order_len_bits % 8)
+ buf_shift_right(val, order_len, 8 - order_len_bits % 8);
+ bn = crypto_bignum_init_set(val, order_len);
+ if (bn == NULL)
+ return NULL;
+ if (crypto_bignum_is_zero(bn) ||
+ crypto_bignum_is_one(bn) ||
+ crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
+ crypto_bignum_deinit(bn, 0);
+ continue;
+ }
+ break;
+ }
+
+ os_memset(val, 0, order_len);
+ return bn;
+}
+
+
+static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
+{
+ crypto_bignum_deinit(sae->tmp->sae_rand, 1);
+ sae->tmp->sae_rand = sae_get_rand(sae);
+ if (sae->tmp->sae_rand == NULL)
+ return NULL;
+ return sae_get_rand(sae);
+}
+
+
+static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
+{
+ wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
+ " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
+ if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+ os_memcpy(key, addr1, ETH_ALEN);
+ os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
+ } else {
+ os_memcpy(key, addr2, ETH_ALEN);
+ os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
+ }
+}
+
+
+static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ struct crypto_ec_point *pwe)
+{
+ u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *x;
+ int y_bit;
+ size_t bits;
+
+ if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+ sae->tmp->prime_len) < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+ /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
+ bits = crypto_ec_prime_len_bits(sae->tmp->ec);
+ sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ prime, sae->tmp->prime_len, pwd_value, bits);
+ if (bits % 8)
+ buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, sae->tmp->prime_len);
+
+ if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
+ return 0;
+
+ y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
+
+ x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+ if (x == NULL)
+ return -1;
+ if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) {
+ crypto_bignum_deinit(x, 0);
+ wpa_printf(MSG_DEBUG, "SAE: No solution found");
+ return 0;
+ }
+ crypto_bignum_deinit(x, 0);
+
+ wpa_printf(MSG_DEBUG, "SAE: PWE found");
+
+ return 1;
+}
+
+
+static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
+ struct crypto_bignum *pwe)
+{
+ u8 pwd_value[SAE_MAX_PRIME_LEN];
+ size_t bits = sae->tmp->prime_len * 8;
+ u8 exp[1];
+ struct crypto_bignum *a, *b;
+ int res;
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+ /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
+ sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
+ bits);
+ if (bits % 8)
+ buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
+ sae->tmp->prime_len);
+
+ if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
+ {
+ wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
+ return 0;
+ }
+
+ /* PWE = pwd-value^((p-1)/r) modulo p */
+
+ a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+
+ if (sae->tmp->dh->safe_prime) {
+ /*
+ * r = (p-1)/2 for the group used here, so this becomes:
+ * PWE = pwd-value^2 modulo p
+ */
+ exp[0] = 2;
+ b = crypto_bignum_init_set(exp, sizeof(exp));
+ } else {
+ /* Calculate exponent: (p-1)/r */
+ exp[0] = 1;
+ b = crypto_bignum_init_set(exp, sizeof(exp));
+ if (b == NULL ||
+ crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
+ crypto_bignum_div(b, sae->tmp->order, b) < 0) {
+ crypto_bignum_deinit(b, 0);
+ b = NULL;
+ }
+ }
+
+ if (a == NULL || b == NULL)
+ res = -1;
+ else
+ res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
+
+ crypto_bignum_deinit(a, 0);
+ crypto_bignum_deinit(b, 0);
+
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
+ return -1;
+ }
+
+ /* if (PWE > 1) --> found */
+ if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
+ wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: PWE found");
+ return 1;
+}
+
+
+static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ const u8 *addr2, const u8 *password,
+ size_t password_len)
+{
+ u8 counter, k = 4;
+ u8 addrs[2 * ETH_ALEN];
+ const u8 *addr[2];
+ size_t len[2];
+ int found = 0;
+ struct crypto_ec_point *pwe_tmp;
+
+ if (sae->tmp->pwe_ecc == NULL) {
+ sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
+ if (sae->tmp->pwe_ecc == NULL)
+ return -1;
+ }
+ pwe_tmp = crypto_ec_point_init(sae->tmp->ec);
+ if (pwe_tmp == NULL)
+ return -1;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+
+ /*
+ * H(salt, ikm) = HMAC-SHA256(salt, ikm)
+ * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
+ * password || counter)
+ */
+ sae_pwd_seed_key(addr1, addr2, addrs);
+
+ addr[0] = password;
+ len[0] = password_len;
+ addr[1] = &counter;
+ len[1] = sizeof(counter);
+
+ /*
+ * Continue for at least k iterations to protect against side-channel
+ * attacks that attempt to determine the number of iterations required
+ * in the loop.
+ */
+ for (counter = 1; counter < k || !found; counter++) {
+ u8 pwd_seed[SHA256_MAC_LEN];
+ int res;
+
+ if (counter > 200) {
+ /* This should not happen in practice */
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
+ pwd_seed) < 0)
+ break;
+ res = sae_test_pwd_seed_ecc(sae, pwd_seed,
+ found ? pwe_tmp :
+ sae->tmp->pwe_ecc);
+ if (res < 0)
+ break;
+ if (res == 0)
+ continue;
+ if (found) {
+ wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was "
+ "already selected)");
+ } else {
+ wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+ found = 1;
+ }
+ }
+
+ crypto_ec_point_deinit(pwe_tmp, 1);
+
+ return found ? 0 : -1;
+}
+
+
+static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+ const u8 *addr2, const u8 *password,
+ size_t password_len)
+{
+ u8 counter;
+ u8 addrs[2 * ETH_ALEN];
+ const u8 *addr[2];
+ size_t len[2];
+ int found = 0;
+
+ if (sae->tmp->pwe_ffc == NULL) {
+ sae->tmp->pwe_ffc = crypto_bignum_init();
+ if (sae->tmp->pwe_ffc == NULL)
+ return -1;
+ }
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+
+ /*
+ * H(salt, ikm) = HMAC-SHA256(salt, ikm)
+ * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
+ * password || counter)
+ */
+ sae_pwd_seed_key(addr1, addr2, addrs);
+
+ addr[0] = password;
+ len[0] = password_len;
+ addr[1] = &counter;
+ len[1] = sizeof(counter);
+
+ for (counter = 1; !found; counter++) {
+ u8 pwd_seed[SHA256_MAC_LEN];
+ int res;
+
+ if (counter > 200) {
+ /* This should not happen in practice */
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
+ pwd_seed) < 0)
+ break;
+ res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
+ if (res < 0)
+ break;
+ if (res > 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+ found = 1;
+ }
+ }
+
+ return found ? 0 : -1;
+}
+
+
+static int sae_derive_commit_element_ecc(struct sae_data *sae,
+ struct crypto_bignum *mask)
+{
+ /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
+ if (!sae->tmp->own_commit_element_ecc) {
+ sae->tmp->own_commit_element_ecc =
+ crypto_ec_point_init(sae->tmp->ec);
+ if (!sae->tmp->own_commit_element_ecc)
+ return -1;
+ }
+
+ if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
+ sae->tmp->own_commit_element_ecc) < 0 ||
+ crypto_ec_point_invert(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int sae_derive_commit_element_ffc(struct sae_data *sae,
+ struct crypto_bignum *mask)
+{
+ /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
+ if (!sae->tmp->own_commit_element_ffc) {
+ sae->tmp->own_commit_element_ffc = crypto_bignum_init();
+ if (!sae->tmp->own_commit_element_ffc)
+ return -1;
+ }
+
+ if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
+ sae->tmp->own_commit_element_ffc) < 0 ||
+ crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
+ sae->tmp->prime,
+ sae->tmp->own_commit_element_ffc) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int sae_derive_commit(struct sae_data *sae)
+{
+ struct crypto_bignum *mask;
+ int ret = -1;
+
+ mask = sae_get_rand_and_mask(sae);
+ if (mask == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
+ return -1;
+ }
+
+ /* commit-scalar = (rand + mask) modulo r */
+ if (!sae->tmp->own_commit_scalar) {
+ sae->tmp->own_commit_scalar = crypto_bignum_init();
+ if (!sae->tmp->own_commit_scalar)
+ goto fail;
+ }
+ crypto_bignum_add(sae->tmp->sae_rand, mask,
+ sae->tmp->own_commit_scalar);
+ crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
+ sae->tmp->own_commit_scalar);
+
+ if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0)
+ goto fail;
+ if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ crypto_bignum_deinit(mask, 1);
+ return ret;
+}
+
+
+int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
+ const u8 *password, size_t password_len,
+ struct sae_data *sae)
+{
+ if (sae->tmp == NULL)
+ return -1;
+ if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
+ password_len) < 0)
+ return -1;
+ if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
+ password_len) < 0)
+ return -1;
+ if (sae_derive_commit(sae) < 0)
+ return -1;
+ return 0;
+}
+
+
+static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
+{
+ struct crypto_ec_point *K;
+ int ret = -1;
+
+ K = crypto_ec_point_init(sae->tmp->ec);
+ if (K == NULL)
+ goto fail;
+
+ /*
+ * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
+ * PEER-COMMIT-ELEMENT)))
+ * If K is identity element (point-at-infinity), reject
+ * k = F(K) (= x coordinate)
+ */
+
+ if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
+ sae->peer_commit_scalar, K) < 0 ||
+ crypto_ec_point_add(sae->tmp->ec, K,
+ sae->tmp->peer_commit_element_ecc, K) < 0 ||
+ crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
+ crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
+ crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
+
+ ret = 0;
+fail:
+ crypto_ec_point_deinit(K, 1);
+ return ret;
+}
+
+
+static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
+{
+ struct crypto_bignum *K;
+ int ret = -1;
+
+ K = crypto_bignum_init();
+ if (K == NULL)
+ goto fail;
+
+ /*
+ * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
+ * PEER-COMMIT-ELEMENT)))
+ * If K is identity element (one), reject.
+ * k = F(K) (= x coordinate)
+ */
+
+ if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
+ sae->tmp->prime, K) < 0 ||
+ crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
+ sae->tmp->prime, K) < 0 ||
+ crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
+ ||
+ crypto_bignum_is_one(K) ||
+ crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
+
+ ret = 0;
+fail:
+ crypto_bignum_deinit(K, 1);
+ return ret;
+}
+
+
+static int sae_derive_keys(struct sae_data *sae, const u8 *k)
+{
+ u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
+ u8 keyseed[SHA256_MAC_LEN];
+ u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+ struct crypto_bignum *tmp;
+ int ret = -1;
+
+ tmp = crypto_bignum_init();
+ if (tmp == NULL)
+ goto fail;
+
+ /* keyseed = H(<0>32, k)
+ * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+ * (commit-scalar + peer-commit-scalar) modulo r)
+ * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
+ */
+
+ os_memset(null_key, 0, sizeof(null_key));
+ hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
+ keyseed);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
+
+ crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
+ tmp);
+ crypto_bignum_mod(tmp, sae->tmp->order, tmp);
+ crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+ sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
+ val, sae->tmp->prime_len, keys, sizeof(keys));
+ os_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_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);
+
+ ret = 0;
+fail:
+ crypto_bignum_deinit(tmp, 0);
+ return ret;
+}
+
+
+int sae_process_commit(struct sae_data *sae)
+{
+ u8 k[SAE_MAX_PRIME_LEN];
+ if (sae->tmp == NULL ||
+ (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
+ (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
+ sae_derive_keys(sae, k) < 0)
+ return -1;
+ return 0;
+}
+
+
+void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token)
+{
+ u8 *pos;
+
+ if (sae->tmp == NULL)
+ return;
+
+ wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
+ if (token) {
+ wpabuf_put_buf(buf, token);
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
+ wpabuf_head(token), wpabuf_len(token));
+ }
+ pos = wpabuf_put(buf, sae->tmp->prime_len);
+ crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
+ sae->tmp->prime_len, sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
+ pos, sae->tmp->prime_len);
+ if (sae->tmp->ec) {
+ pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
+ crypto_ec_point_to_bin(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc,
+ pos, pos + sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
+ pos, sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
+ pos + sae->tmp->prime_len, sae->tmp->prime_len);
+ } else {
+ pos = wpabuf_put(buf, sae->tmp->prime_len);
+ crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
+ sae->tmp->prime_len, sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
+ pos, sae->tmp->prime_len);
+ }
+}
+
+
+u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
+{
+ if (allowed_groups) {
+ int i;
+ for (i = 0; allowed_groups[i] > 0; i++) {
+ if (allowed_groups[i] == group)
+ break;
+ }
+ if (allowed_groups[i] != group) {
+ wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
+ "enabled in the current configuration",
+ group);
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+ }
+
+ if (sae->state == SAE_COMMITTED && group != sae->group) {
+ wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+
+ if (group != sae->group && sae_set_group(sae, group) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+ group);
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+
+ if (sae->tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (sae->tmp->dh && !allowed_groups) {
+ wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
+ "explicit configuration enabling it", group);
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
+ const u8 *end, const u8 **token,
+ size_t *token_len)
+{
+ if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
+ size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
+ sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
+ if (token)
+ *token = *pos;
+ if (token_len)
+ *token_len = tlen;
+ *pos += tlen;
+ } else {
+ if (token)
+ *token = NULL;
+ if (token_len)
+ *token_len = 0;
+ }
+}
+
+
+static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
+ const u8 *end)
+{
+ struct crypto_bignum *peer_scalar;
+
+ if (*pos + sae->tmp->prime_len > end) {
+ wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
+ if (peer_scalar == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ /*
+ * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
+ * the peer and it is in Authenticated state, the new Commit Message
+ * shall be dropped if the peer-scalar is identical to the one used in
+ * the existing protocol instance.
+ */
+ if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
+ crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
+ "peer-commit-scalar");
+ crypto_bignum_deinit(peer_scalar, 0);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ /* 0 < scalar < r */
+ if (crypto_bignum_is_zero(peer_scalar) ||
+ crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
+ crypto_bignum_deinit(peer_scalar, 0);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+
+ crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+ sae->peer_commit_scalar = peer_scalar;
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
+ *pos, sae->tmp->prime_len);
+ *pos += sae->tmp->prime_len;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
+ const u8 *end)
+{
+ u8 prime[SAE_MAX_ECC_PRIME_LEN];
+
+ if (pos + 2 * sae->tmp->prime_len > end) {
+ wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
+ "commit-element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+ sae->tmp->prime_len) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ /* element x and y coordinates < p */
+ if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
+ os_memcmp(pos + sae->tmp->prime_len, prime,
+ sae->tmp->prime_len) >= 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
+ "element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
+ pos, sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
+ pos + sae->tmp->prime_len, sae->tmp->prime_len);
+
+ crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
+ sae->tmp->peer_commit_element_ecc =
+ crypto_ec_point_from_bin(sae->tmp->ec, pos);
+ if (sae->tmp->peer_commit_element_ecc == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
+ sae->tmp->peer_commit_element_ecc)) {
+ wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
+ const u8 *end)
+{
+ struct crypto_bignum *res;
+
+ if (pos + sae->tmp->prime_len > end) {
+ wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
+ "commit-element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
+ sae->tmp->prime_len);
+
+ crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
+ sae->tmp->peer_commit_element_ffc =
+ crypto_bignum_init_set(pos, sae->tmp->prime_len);
+ if (sae->tmp->peer_commit_element_ffc == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
+ crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
+ crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc,
+ sae->tmp->prime) >= 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ /* scalar-op(r, ELEMENT) = 1 modulo p */
+ res = crypto_bignum_init();
+ if (res == NULL ||
+ crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
+ sae->tmp->order, sae->tmp->prime, res) < 0 ||
+ !crypto_bignum_is_one(res)) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
+ crypto_bignum_deinit(res, 0);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ crypto_bignum_deinit(res, 0);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
+ const u8 *end)
+{
+ if (sae->tmp->dh)
+ return sae_parse_commit_element_ffc(sae, pos, end);
+ return sae_parse_commit_element_ecc(sae, pos, end);
+}
+
+
+u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
+ const u8 **token, size_t *token_len, int *allowed_groups)
+{
+ const u8 *pos = data, *end = data + len;
+ u16 res;
+
+ /* Check Finite Cyclic Group */
+ if (pos + 2 > end)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+ pos += 2;
+
+ /* Optional Anti-Clogging Token */
+ sae_parse_commit_token(sae, &pos, end, token, token_len);
+
+ /* commit-scalar */
+ res = sae_parse_commit_scalar(sae, &pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+
+ /* commit-element */
+ return sae_parse_commit_element(sae, pos, end);
+}
+
+
+static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const u8 *element1, size_t element1_len,
+ const struct crypto_bignum *scalar2,
+ const u8 *element2, size_t element2_len,
+ u8 *confirm)
+{
+ const u8 *addr[5];
+ size_t len[5];
+ u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
+
+ /* Confirm
+ * CN(key, X, Y, Z, ...) =
+ * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
+ * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
+ * peer-commit-scalar, PEER-COMMIT-ELEMENT)
+ * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
+ * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
+ */
+ addr[0] = sc;
+ len[0] = 2;
+ crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+ sae->tmp->prime_len);
+ addr[1] = scalar_b1;
+ len[1] = sae->tmp->prime_len;
+ addr[2] = element1;
+ len[2] = element1_len;
+ crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+ sae->tmp->prime_len);
+ addr[3] = scalar_b2;
+ len[3] = sae->tmp->prime_len;
+ addr[4] = element2;
+ len[4] = element2_len;
+ hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
+ confirm);
+}
+
+
+static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_ec_point *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_ec_point *element2,
+ u8 *confirm)
+{
+ u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
+ u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
+
+ crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+ element_b1 + sae->tmp->prime_len);
+ crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+ element_b2 + sae->tmp->prime_len);
+
+ sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
+ scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+}
+
+
+static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_bignum *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_bignum *element2,
+ u8 *confirm)
+{
+ u8 element_b1[SAE_MAX_PRIME_LEN];
+ u8 element_b2[SAE_MAX_PRIME_LEN];
+
+ crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+ sae->tmp->prime_len);
+ crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+ sae->tmp->prime_len);
+
+ sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+ scalar2, element_b2, sae->tmp->prime_len, confirm);
+}
+
+
+void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
+{
+ const u8 *sc;
+
+ if (sae->tmp == NULL)
+ return;
+
+ /* Send-Confirm */
+ sc = wpabuf_put(buf, 0);
+ wpabuf_put_le16(buf, sae->send_confirm);
+ sae->send_confirm++;
+
+ if (sae->tmp->ec)
+ sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ wpabuf_put(buf, SHA256_MAC_LEN));
+ else
+ sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ wpabuf_put(buf, SHA256_MAC_LEN));
+}
+
+
+int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
+{
+ u8 verifier[SHA256_MAC_LEN];
+
+ if (len < 2 + SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
+
+ if (sae->tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
+ return -1;
+ }
+
+ if (sae->tmp->ec)
+ sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ verifier);
+ else
+ sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ verifier);
+
+ if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
+ wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
+ data + 2, SHA256_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
+ verifier, SHA256_MAC_LEN);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/common/sae.h b/contrib/wpa/src/common/sae.h
new file mode 100644
index 0000000..3ebf40c
--- /dev/null
+++ b/contrib/wpa/src/common/sae.h
@@ -0,0 +1,67 @@
+/*
+ * Simultaneous authentication of equals
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SAE_H
+#define SAE_H
+
+#define SAE_KCK_LEN 32
+#define SAE_PMK_LEN 32
+#define SAE_PMKID_LEN 16
+#define SAE_KEYSEED_KEY_LEN 32
+#define SAE_MAX_PRIME_LEN 512
+#define SAE_MAX_ECC_PRIME_LEN 66
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+
+struct sae_temporary_data {
+ u8 kck[SAE_KCK_LEN];
+ struct crypto_bignum *own_commit_scalar;
+ struct crypto_bignum *own_commit_element_ffc;
+ struct crypto_ec_point *own_commit_element_ecc;
+ struct crypto_bignum *peer_commit_element_ffc;
+ struct crypto_ec_point *peer_commit_element_ecc;
+ struct crypto_ec_point *pwe_ecc;
+ struct crypto_bignum *pwe_ffc;
+ struct crypto_bignum *sae_rand;
+ struct crypto_ec *ec;
+ int prime_len;
+ const struct dh_group *dh;
+ const struct crypto_bignum *prime;
+ const struct crypto_bignum *order;
+ struct crypto_bignum *prime_buf;
+ struct crypto_bignum *order_buf;
+ struct wpabuf *anti_clogging_token;
+};
+
+struct sae_data {
+ enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
+ u16 send_confirm;
+ u8 pmk[SAE_PMK_LEN];
+ struct crypto_bignum *peer_commit_scalar;
+ int group;
+ int sync;
+ struct sae_temporary_data *tmp;
+};
+
+int sae_set_group(struct sae_data *sae, int group);
+void sae_clear_temp_data(struct sae_data *sae);
+void sae_clear_data(struct sae_data *sae);
+
+int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
+ const u8 *password, size_t password_len,
+ struct sae_data *sae);
+int sae_process_commit(struct sae_data *sae);
+void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token);
+u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
+ const u8 **token, size_t *token_len, int *allowed_groups);
+void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
+int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
+u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
+
+#endif /* SAE_H */
diff --git a/contrib/wpa/src/common/tnc.h b/contrib/wpa/src/common/tnc.h
new file mode 100644
index 0000000..108acf9
--- /dev/null
+++ b/contrib/wpa/src/common/tnc.h
@@ -0,0 +1,121 @@
+/*
+ * TNC - Common defines
+ * Copyright (c) 2007-2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TNC_H
+#define TNC_H
+
+typedef unsigned long TNC_UInt32;
+typedef unsigned char *TNC_BufferReference;
+
+typedef TNC_UInt32 TNC_IMVID;
+typedef TNC_UInt32 TNC_IMCID;
+typedef TNC_UInt32 TNC_ConnectionID;
+typedef TNC_UInt32 TNC_ConnectionState;
+typedef TNC_UInt32 TNC_RetryReason;
+typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
+typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
+typedef TNC_UInt32 TNC_MessageType;
+typedef TNC_MessageType *TNC_MessageTypeList;
+typedef TNC_UInt32 TNC_VendorID;
+typedef TNC_UInt32 TNC_Subtype;
+typedef TNC_UInt32 TNC_MessageSubtype;
+typedef TNC_UInt32 TNC_Version;
+typedef TNC_UInt32 TNC_Result;
+typedef TNC_UInt32 TNC_AttributeID;
+
+typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
+ TNC_IMVID imvID,
+ char *functionName,
+ void **pOutfunctionPointer);
+typedef TNC_Result (*TNC_TNCS_ReportMessageTypesPointer)(
+ TNC_IMVID imvID,
+ TNC_MessageTypeList supportedTypes,
+ TNC_UInt32 typeCount);
+typedef TNC_Result (*TNC_TNCS_SendMessagePointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_MessageType messageType);
+typedef TNC_Result (*TNC_TNCS_RequestHandshakeRetryPointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_RetryReason reason);
+typedef TNC_Result (*TNC_TNCS_ProvideRecommendationPointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_IMV_Action_Recommendation recommendation,
+ TNC_IMV_Evaluation_Result evaluation);
+typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
+ TNC_IMCID imcID,
+ char *functionName,
+ void **pOutfunctionPointer);
+typedef TNC_Result (*TNC_TNCC_SendMessagePointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_MessageType messageType);
+typedef TNC_Result (*TNC_TNCC_ReportMessageTypesPointer)(
+ TNC_IMCID imcID,
+ TNC_MessageTypeList supportedTypes,
+ TNC_UInt32 typeCount);
+typedef TNC_Result (*TNC_TNCC_RequestHandshakeRetryPointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_RetryReason reason);
+
+#define TNC_IFIMV_VERSION_1 1
+#define TNC_IFIMC_VERSION_1 1
+
+#define TNC_RESULT_SUCCESS 0
+#define TNC_RESULT_NOT_INITIALIZED 1
+#define TNC_RESULT_ALREADY_INITIALIZED 2
+#define TNC_RESULT_NO_COMMON_VERSION 3
+#define TNC_RESULT_CANT_RETRY 4
+#define TNC_RESULT_WONT_RETRY 5
+#define TNC_RESULT_INVALID_PARAMETER 6
+#define TNC_RESULT_CANT_RESPOND 7
+#define TNC_RESULT_ILLEGAL_OPERATION 8
+#define TNC_RESULT_OTHER 9
+#define TNC_RESULT_FATAL 10
+
+#define TNC_CONNECTION_STATE_CREATE 0
+#define TNC_CONNECTION_STATE_HANDSHAKE 1
+#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
+#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
+#define TNC_CONNECTION_STATE_ACCESS_NONE 4
+#define TNC_CONNECTION_STATE_DELETE 5
+
+#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
+#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
+
+/* TNCC-TNCS Message Types */
+#define TNC_TNCCS_RECOMMENDATION 0x00000001
+#define TNC_TNCCS_ERROR 0x00000002
+#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
+#define TNC_TNCCS_REASONSTRINGS 0x00000004
+
+/* Possible TNC_IMV_Action_Recommendation values: */
+enum IMV_Action_Recommendation {
+ TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
+ TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
+};
+
+/* Possible TNC_IMV_Evaluation_Result values: */
+enum IMV_Evaluation_Result {
+ TNC_IMV_EVALUATION_RESULT_COMPLIANT,
+ TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
+ TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
+ TNC_IMV_EVALUATION_RESULT_ERROR,
+ TNC_IMV_EVALUATION_RESULT_DONT_KNOW
+};
+
+#endif /* TNC_H */
diff --git a/contrib/wpa/src/common/version.h b/contrib/wpa/src/common/version.h
index 04ed0ac..e39a8db 100644
--- a/contrib/wpa/src/common/version.h
+++ b/contrib/wpa/src/common/version.h
@@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "2.0" VERSION_STR_POSTFIX
+#define VERSION_STR "2.4" 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 8d7a11c..de81d53 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-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, 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 "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "ieee802_11_defs.h"
@@ -19,9 +20,35 @@
#include "wpa_common.h"
+static unsigned int wpa_kck_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
+static unsigned int wpa_kek_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 32;
+ return 16;
+}
+
+
+unsigned int wpa_mic_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @key_len: KCK length in octets
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
* @buf: Pointer to the beginning of the EAPOL header (version field)
* @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
@@ -37,18 +64,18 @@
* happened during final editing of the standard and the correct behavior is
* defined in the last draft (IEEE 802.11i/D10).
*/
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
- u8 *mic)
+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[SHA1_MAC_LEN];
+ u8 hash[SHA384_MAC_LEN];
switch (ver) {
#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
- return hmac_md5(key, 16, buf, len, mic);
+ return hmac_md5(key, key_len, buf, len, mic);
#endif /* CONFIG_FIPS */
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
- if (hmac_sha1(key, 16, buf, len, hash))
+ if (hmac_sha1(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
@@ -56,6 +83,30 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
case WPA_KEY_INFO_TYPE_AES_128_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_HS20
+ case WPA_KEY_MGMT_OSEN:
+ return omac1_aes_128(key, buf, len, mic);
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_SUITEB
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ if (hmac_sha256(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, MD5_MAC_LEN);
+ break;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ break;
+#endif /* CONFIG_SUITEB192 */
+ default:
+ return -1;
+ }
+ break;
default:
return -1;
}
@@ -74,8 +125,9 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
* @nonce1: ANonce or SNonce
* @nonce2: SNonce or ANonce
* @ptk: Buffer for pairwise transient key
- * @ptk_len: Length of PTK
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
@@ -86,12 +138,14 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
* Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
* Min(INonce, PNonce) || Max(INonce, PNonce))
*/
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
- const u8 *addr1, const u8 *addr2,
- const u8 *nonce1, const u8 *nonce2,
- u8 *ptk, size_t ptk_len, int use_sha256)
+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)
{
u8 data[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 (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
@@ -111,27 +165,44 @@ void 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);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
- ptk, ptk_len);
+ tmp, ptk_len);
else
#endif /* CONFIG_IEEE80211W */
- sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
- ptk_len);
+ sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len);
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
MAC2STR(addr1), MAC2STR(addr2));
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
- wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
+
+ os_memcpy(ptk->kck, tmp, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
+
+ os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
+
+ 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);
+
+ os_memset(tmp, 0, sizeof(tmp));
+ return 0;
}
#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
- u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+ const u8 *ap_addr, u8 transaction_seqnum,
+ const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic)
@@ -139,6 +210,12 @@ int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
u8 *buf, *pos;
size_t buf_len;
+ if (kck_len != 16) {
+ wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
+ (unsigned int) kck_len);
+ return -1;
+ }
+
buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
buf = os_malloc(buf_len);
if (buf == NULL)
@@ -335,7 +412,6 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
#endif /* CONFIG_IEEE80211R */
-#ifndef CONFIG_NO_WPA2
static int rsn_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
@@ -354,6 +430,18 @@ static int rsn_selector_to_bitfield(const u8 *s)
#endif /* CONFIG_IEEE80211W */
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
return WPA_CIPHER_GCMP;
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
+ return WPA_CIPHER_CCMP_256;
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
+ return WPA_CIPHER_GCMP_256;
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
+ return WPA_CIPHER_BIP_GMAC_128;
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
+ return WPA_CIPHER_BIP_GMAC_256;
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
+ return WPA_CIPHER_BIP_CMAC_256;
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
+ return WPA_CIPHER_GTK_NOT_USED;
return 0;
}
@@ -382,9 +470,32 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
return WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
+ 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;
return 0;
}
-#endif /* CONFIG_NO_WPA2 */
+
+
+static int wpa_cipher_valid_group(int cipher)
+{
+ return wpa_cipher_valid_pairwise(cipher) ||
+ cipher == WPA_CIPHER_WEP104 ||
+ cipher == WPA_CIPHER_WEP40 ||
+ cipher == WPA_CIPHER_GTK_NOT_USED;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_cipher_valid_mgmt_group(int cipher)
+{
+ return cipher == WPA_CIPHER_AES_128_CMAC ||
+ cipher == WPA_CIPHER_BIP_GMAC_128 ||
+ cipher == WPA_CIPHER_BIP_GMAC_256 ||
+ cipher == WPA_CIPHER_BIP_CMAC_256;
+}
+#endif /* CONFIG_IEEE80211W */
/**
@@ -397,7 +508,6 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
-#ifndef CONFIG_NO_WPA2
const struct rsn_ie_hdr *hdr;
const u8 *pos;
int left;
@@ -443,13 +553,11 @@ 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);
-#ifdef CONFIG_IEEE80211W
- if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
- wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
- "cipher", __func__);
+ if (!wpa_cipher_valid_group(data->group_cipher)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
+ __func__, data->group_cipher);
return -1;
}
-#endif /* CONFIG_IEEE80211W */
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
} else if (left > 0) {
@@ -463,7 +571,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+ if (count == 0 || count > left / RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
"count %u left %u", __func__, count, left);
return -4;
@@ -491,7 +599,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+ if (count == 0 || count > left / RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
"count %u left %u", __func__, count, left);
return -6;
@@ -514,17 +622,17 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
}
if (left >= 2) {
- data->num_pmkid = WPA_GET_LE16(pos);
+ u16 num_pmkid = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (left < (int) data->num_pmkid * PMKID_LEN) {
+ if (num_pmkid > (unsigned int) left / PMKID_LEN) {
wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
- "(num_pmkid=%lu left=%d)",
- __func__, (unsigned long) data->num_pmkid,
- left);
+ "(num_pmkid=%u left=%d)",
+ __func__, num_pmkid, left);
data->num_pmkid = 0;
return -9;
} else {
+ data->num_pmkid = num_pmkid;
data->pmkid = pos;
pos += data->num_pmkid * PMKID_LEN;
left -= data->num_pmkid * PMKID_LEN;
@@ -534,7 +642,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
#ifdef CONFIG_IEEE80211W
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
- if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+ 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);
@@ -546,14 +654,12 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
#endif /* CONFIG_IEEE80211W */
if (left > 0) {
- wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
- __func__, left);
+ wpa_hexdump(MSG_DEBUG,
+ "wpa_parse_wpa_ie_rsn: ignore trailing bytes",
+ pos, left);
}
return 0;
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
@@ -643,7 +749,7 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+ if (count == 0 || count > left / WPA_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
"count %u left %u", __func__, count, left);
return -4;
@@ -664,7 +770,7 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+ if (count == 0 || count > left / WPA_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
"count %u left %u", __func__, count, left);
return -6;
@@ -687,8 +793,9 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
}
if (left > 0) {
- wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
- __func__, left);
+ wpa_hexdump(MSG_DEBUG,
+ "wpa_parse_wpa_ie_wpa: ignore trailing bytes",
+ pos, left);
}
return 0;
@@ -812,15 +919,17 @@ void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
*
* IEEE Std 802.11r-2008 - 8.5.1.5.5
*/
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
- const u8 *pmk_r1_name,
- u8 *ptk, size_t ptk_len, u8 *ptk_name)
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+ const u8 *sta_addr, const u8 *bssid,
+ const u8 *pmk_r1_name,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
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;
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
@@ -836,7 +945,12 @@ void 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;
- sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+ ptk->kck_len = wpa_kck_len(akmp);
+ ptk->kek_len = wpa_kek_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);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -857,6 +971,19 @@ void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
sha256_vector(6, addr, len, hash);
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);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_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);
+
+ os_memset(tmp, 0, sizeof(tmp));
+
+ return 0;
}
#endif /* CONFIG_IEEE80211R */
@@ -896,6 +1023,72 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
}
+#ifdef CONFIG_SUITEB
+/**
+ * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA256_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+ if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
+ return -1;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ return 0;
+}
+#endif /* CONFIG_SUITEB */
+
+
+#ifdef CONFIG_SUITEB192
+/**
+ * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA384_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+ if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
+ return -1;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ return 0;
+}
+#endif /* CONFIG_SUITEB192 */
+
+
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)
@@ -918,6 +1111,12 @@ const char * wpa_cipher_txt(int cipher)
return "CCMP+TKIP";
case WPA_CIPHER_GCMP:
return "GCMP";
+ case WPA_CIPHER_GCMP_256:
+ return "GCMP-256";
+ case WPA_CIPHER_CCMP_256:
+ return "CCMP-256";
+ case WPA_CIPHER_GTK_NOT_USED:
+ return "GTK_NOT_USED";
default:
return "UNKNOWN";
}
@@ -959,12 +1158,52 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
#endif /* CONFIG_IEEE80211W */
+ case WPA_KEY_MGMT_WPS:
+ return "WPS";
+ case WPA_KEY_MGMT_SAE:
+ return "SAE";
+ case WPA_KEY_MGMT_FT_SAE:
+ return "FT-SAE";
+ case WPA_KEY_MGMT_OSEN:
+ return "OSEN";
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ return "WPA2-EAP-SUITE-B";
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return "WPA2-EAP-SUITE-B-192";
default:
return "UNKNOWN";
}
}
+u32 wpa_akm_to_suite(int akm)
+{
+ if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
+ return WLAN_AKM_SUITE_FT_8021X;
+ if (akm & WPA_KEY_MGMT_FT_PSK)
+ return WLAN_AKM_SUITE_FT_PSK;
+ if (akm & WPA_KEY_MGMT_IEEE8021X)
+ return WLAN_AKM_SUITE_8021X;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
+ return WLAN_AKM_SUITE_8021X_SHA256;
+ if (akm & WPA_KEY_MGMT_IEEE8021X)
+ return WLAN_AKM_SUITE_8021X;
+ if (akm & WPA_KEY_MGMT_PSK_SHA256)
+ return WLAN_AKM_SUITE_PSK_SHA256;
+ if (akm & WPA_KEY_MGMT_PSK)
+ return WLAN_AKM_SUITE_PSK;
+ if (akm & WPA_KEY_MGMT_CCKM)
+ return WLAN_AKM_SUITE_CCKM;
+ if (akm & WPA_KEY_MGMT_OSEN)
+ return WLAN_AKM_SUITE_OSEN;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+ return WLAN_AKM_SUITE_8021X_SUITE_B;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ return 0;
+}
+
+
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len)
@@ -1084,8 +1323,15 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
int wpa_cipher_key_len(int cipher)
{
switch (cipher) {
+ case WPA_CIPHER_CCMP_256:
+ case WPA_CIPHER_GCMP_256:
+ case WPA_CIPHER_BIP_GMAC_256:
+ case WPA_CIPHER_BIP_CMAC_256:
+ return 32;
case WPA_CIPHER_CCMP:
case WPA_CIPHER_GCMP:
+ case WPA_CIPHER_AES_128_CMAC:
+ case WPA_CIPHER_BIP_GMAC_128:
return 16;
case WPA_CIPHER_TKIP:
return 32;
@@ -1102,6 +1348,8 @@ int wpa_cipher_key_len(int cipher)
int wpa_cipher_rsc_len(int cipher)
{
switch (cipher) {
+ case WPA_CIPHER_CCMP_256:
+ case WPA_CIPHER_GCMP_256:
case WPA_CIPHER_CCMP:
case WPA_CIPHER_GCMP:
case WPA_CIPHER_TKIP:
@@ -1118,6 +1366,10 @@ int wpa_cipher_rsc_len(int cipher)
int wpa_cipher_to_alg(int cipher)
{
switch (cipher) {
+ case WPA_CIPHER_CCMP_256:
+ return WPA_ALG_CCMP_256;
+ case WPA_CIPHER_GCMP_256:
+ return WPA_ALG_GCMP_256;
case WPA_CIPHER_CCMP:
return WPA_ALG_CCMP;
case WPA_CIPHER_GCMP:
@@ -1127,6 +1379,14 @@ int wpa_cipher_to_alg(int cipher)
case WPA_CIPHER_WEP104:
case WPA_CIPHER_WEP40:
return WPA_ALG_WEP;
+ case WPA_CIPHER_AES_128_CMAC:
+ return WPA_ALG_IGTK;
+ case WPA_CIPHER_BIP_GMAC_128:
+ return WPA_ALG_BIP_GMAC_128;
+ case WPA_CIPHER_BIP_GMAC_256:
+ return WPA_ALG_BIP_GMAC_256;
+ case WPA_CIPHER_BIP_CMAC_256:
+ return WPA_ALG_BIP_CMAC_256;
}
return WPA_ALG_NONE;
}
@@ -1134,7 +1394,9 @@ int wpa_cipher_to_alg(int cipher)
int wpa_cipher_valid_pairwise(int cipher)
{
- return cipher == WPA_CIPHER_CCMP ||
+ return cipher == WPA_CIPHER_CCMP_256 ||
+ cipher == WPA_CIPHER_GCMP_256 ||
+ cipher == WPA_CIPHER_CCMP ||
cipher == WPA_CIPHER_GCMP ||
cipher == WPA_CIPHER_TKIP;
}
@@ -1142,6 +1404,10 @@ int wpa_cipher_valid_pairwise(int cipher)
u32 wpa_cipher_to_suite(int proto, int cipher)
{
+ if (cipher & WPA_CIPHER_CCMP_256)
+ return RSN_CIPHER_SUITE_CCMP_256;
+ if (cipher & WPA_CIPHER_GCMP_256)
+ return RSN_CIPHER_SUITE_GCMP_256;
if (cipher & WPA_CIPHER_CCMP)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
@@ -1159,58 +1425,252 @@ u32 wpa_cipher_to_suite(int proto, int cipher)
if (cipher & WPA_CIPHER_NONE)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
+ if (cipher & WPA_CIPHER_GTK_NOT_USED)
+ return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
+ if (cipher & WPA_CIPHER_AES_128_CMAC)
+ return RSN_CIPHER_SUITE_AES_128_CMAC;
+ if (cipher & WPA_CIPHER_BIP_GMAC_128)
+ return RSN_CIPHER_SUITE_BIP_GMAC_128;
+ if (cipher & WPA_CIPHER_BIP_GMAC_256)
+ return RSN_CIPHER_SUITE_BIP_GMAC_256;
+ if (cipher & WPA_CIPHER_BIP_CMAC_256)
+ return RSN_CIPHER_SUITE_BIP_CMAC_256;
return 0;
}
-int rsn_cipher_put_suites(u8 *pos, int ciphers)
+int rsn_cipher_put_suites(u8 *start, int ciphers)
{
- int num_suites = 0;
+ u8 *pos = start;
+ if (ciphers & WPA_CIPHER_CCMP_256) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
+ pos += RSN_SELECTOR_LEN;
+ }
+ if (ciphers & WPA_CIPHER_GCMP_256) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
+ pos += RSN_SELECTOR_LEN;
+ }
if (ciphers & WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
pos += RSN_SELECTOR_LEN;
- num_suites++;
}
if (ciphers & WPA_CIPHER_GCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
pos += RSN_SELECTOR_LEN;
- num_suites++;
}
if (ciphers & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
pos += RSN_SELECTOR_LEN;
- num_suites++;
}
if (ciphers & WPA_CIPHER_NONE) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
pos += RSN_SELECTOR_LEN;
- num_suites++;
}
- return num_suites;
+ return (pos - start) / RSN_SELECTOR_LEN;
}
-int wpa_cipher_put_suites(u8 *pos, int ciphers)
+int wpa_cipher_put_suites(u8 *start, int ciphers)
{
- int num_suites = 0;
+ u8 *pos = start;
if (ciphers & WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
pos += WPA_SELECTOR_LEN;
- num_suites++;
}
if (ciphers & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
pos += WPA_SELECTOR_LEN;
- num_suites++;
}
if (ciphers & WPA_CIPHER_NONE) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
pos += WPA_SELECTOR_LEN;
- num_suites++;
}
- return num_suites;
+ return (pos - start) / RSN_SELECTOR_LEN;
+}
+
+
+int wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
+{
+ if (ciphers & WPA_CIPHER_CCMP_256)
+ return WPA_CIPHER_CCMP_256;
+ if (ciphers & WPA_CIPHER_GCMP_256)
+ return WPA_CIPHER_GCMP_256;
+ if (ciphers & WPA_CIPHER_CCMP)
+ return WPA_CIPHER_CCMP;
+ if (ciphers & WPA_CIPHER_GCMP)
+ return WPA_CIPHER_GCMP;
+ if (ciphers & WPA_CIPHER_TKIP)
+ return WPA_CIPHER_TKIP;
+ if (none_allowed && (ciphers & WPA_CIPHER_NONE))
+ return WPA_CIPHER_NONE;
+ return -1;
+}
+
+
+int wpa_pick_group_cipher(int ciphers)
+{
+ if (ciphers & WPA_CIPHER_CCMP_256)
+ return WPA_CIPHER_CCMP_256;
+ if (ciphers & WPA_CIPHER_GCMP_256)
+ return WPA_CIPHER_GCMP_256;
+ if (ciphers & WPA_CIPHER_CCMP)
+ return WPA_CIPHER_CCMP;
+ if (ciphers & WPA_CIPHER_GCMP)
+ return WPA_CIPHER_GCMP;
+ if (ciphers & WPA_CIPHER_GTK_NOT_USED)
+ return WPA_CIPHER_GTK_NOT_USED;
+ if (ciphers & WPA_CIPHER_TKIP)
+ return WPA_CIPHER_TKIP;
+ if (ciphers & WPA_CIPHER_WEP104)
+ return WPA_CIPHER_WEP104;
+ if (ciphers & WPA_CIPHER_WEP40)
+ return WPA_CIPHER_WEP40;
+ return -1;
+}
+
+
+int wpa_parse_cipher(const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = os_strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (*start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (os_strcmp(start, "CCMP-256") == 0)
+ val |= WPA_CIPHER_CCMP_256;
+ else if (os_strcmp(start, "GCMP-256") == 0)
+ val |= WPA_CIPHER_GCMP_256;
+ else if (os_strcmp(start, "CCMP") == 0)
+ val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "GCMP") == 0)
+ val |= WPA_CIPHER_GCMP;
+ else if (os_strcmp(start, "TKIP") == 0)
+ val |= WPA_CIPHER_TKIP;
+ else if (os_strcmp(start, "WEP104") == 0)
+ val |= WPA_CIPHER_WEP104;
+ else if (os_strcmp(start, "WEP40") == 0)
+ val |= WPA_CIPHER_WEP40;
+ else if (os_strcmp(start, "NONE") == 0)
+ val |= WPA_CIPHER_NONE;
+ else if (os_strcmp(start, "GTK_NOT_USED") == 0)
+ val |= WPA_CIPHER_GTK_NOT_USED;
+ else {
+ os_free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ os_free(buf);
+
+ return val;
+}
+
+
+int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
+{
+ char *pos = start;
+ int ret;
+
+ if (ciphers & WPA_CIPHER_CCMP_256) {
+ ret = os_snprintf(pos, end - pos, "%sCCMP-256",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_GCMP_256) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP-256",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_CCMP) {
+ ret = os_snprintf(pos, end - pos, "%sCCMP",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_TKIP) {
+ ret = os_snprintf(pos, end - pos, "%sTKIP",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_WEP104) {
+ ret = os_snprintf(pos, end - pos, "%sWEP104",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_WEP40) {
+ ret = os_snprintf(pos, end - pos, "%sWEP40",
+ 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);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ return pos - start;
+}
+
+
+int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
+{
+ int pairwise = 0;
+
+ /* Select group cipher based on the enabled pairwise cipher suites */
+ if (wpa & 1)
+ pairwise |= wpa_pairwise;
+ if (wpa & 2)
+ pairwise |= rsn_pairwise;
+
+ if (pairwise & WPA_CIPHER_TKIP)
+ return WPA_CIPHER_TKIP;
+ if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
+ return WPA_CIPHER_GCMP;
+ if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
+ WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
+ return WPA_CIPHER_GCMP_256;
+ if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
+ WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
+ return WPA_CIPHER_CCMP_256;
+ return WPA_CIPHER_CCMP;
}
diff --git a/contrib/wpa/src/common/wpa_common.h b/contrib/wpa/src/common/wpa_common.h
index 20c79d8..091e317 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-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,14 @@
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
+#define WPA_ALLOWED_PAIRWISE_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \
+WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
+#define WPA_ALLOWED_GROUP_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \
+WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
+WPA_CIPHER_GTK_NOT_USED)
+
#define WPA_SELECTOR_LEN 4
#define WPA_VERSION 1
#define RSN_SELECTOR_LEN 4
@@ -54,7 +62,12 @@
#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_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_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
+#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
@@ -64,11 +77,14 @@
#endif
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
-#ifdef CONFIG_IEEE80211W
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
-#endif /* CONFIG_IEEE80211W */
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_CIPHER_SUITE_CCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
+#define RSN_CIPHER_SUITE_BIP_GMAC_128 RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_CIPHER_SUITE_BIP_GMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_CIPHER_SUITE_BIP_CMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
@@ -92,6 +108,9 @@
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
+#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
+
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
@@ -109,6 +128,7 @@
#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
+#define WPA_IGTK_MAX_LEN 32
#endif /* CONFIG_IEEE80211W */
@@ -137,6 +157,7 @@
/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
+#define WPA_KEY_INFO_TYPE_AKM_DEFINED 0
#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
@@ -170,22 +191,38 @@ struct wpa_eapol_key {
/* 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 */
+} STRUCT_PACKED;
+
+#define WPA_EAPOL_KEY_MIC_MAX_LEN 24
+#define WPA_KCK_MAX_LEN 24
+#define WPA_KEK_MAX_LEN 32
+#define WPA_TK_MAX_LEN 32
+
/**
* struct wpa_ptk - WPA Pairwise Transient Key
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
*/
struct wpa_ptk {
- u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
- u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
- u8 tk1[16]; /* Temporal Key 1 (TK1) */
- union {
- u8 tk2[16]; /* Temporal Key 2 (TK2) */
- struct {
- u8 tx_mic_key[8];
- u8 rx_mic_key[8];
- } auth;
- } u;
-} STRUCT_PACKED;
+ 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) */
+ size_t kck_len;
+ size_t kek_len;
+ size_t tk_len;
+};
/* WPA IE version 1
@@ -263,10 +300,11 @@ struct rsn_error_kde {
} STRUCT_PACKED;
#ifdef CONFIG_IEEE80211W
+#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
struct wpa_igtk_kde {
u8 keyid[2];
u8 pn[6];
- u8 igtk[WPA_IGTK_LEN];
+ u8 igtk[WPA_IGTK_MAX_LEN];
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211W */
@@ -305,16 +343,17 @@ struct rsn_rdie {
#endif /* _MSC_VER */
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
- u8 *mic);
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
- const u8 *addr1, const u8 *addr2,
- const u8 *nonce1, const u8 *nonce2,
- u8 *ptk, size_t ptk_len, int use_sha256);
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+ const u8 *buf, size_t len, u8 *mic);
+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);
#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
- u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+ const u8 *ap_addr, u8 transaction_seqnum,
+ const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
@@ -327,10 +366,10 @@ void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name);
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
- const u8 *pmk_r1_name,
- u8 *ptk, size_t ptk_len, u8 *ptk_name);
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+ const u8 *sta_addr, const u8 *bssid,
+ const u8 *pmk_r1_name,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
@@ -352,9 +391,30 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256);
+#ifdef CONFIG_SUITEB
+int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB */
+static inline int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ return -1;
+}
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB192 */
+static inline int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, u8 *pmkid)
+{
+ return -1;
+}
+#endif /* CONFIG_SUITEB192 */
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
+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);
@@ -387,8 +447,15 @@ int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
int wpa_cipher_to_alg(int cipher);
int wpa_cipher_valid_pairwise(int cipher);
+int wpa_cipher_valid_mgmt_group(int cipher);
u32 wpa_cipher_to_suite(int proto, int cipher);
int rsn_cipher_put_suites(u8 *pos, int ciphers);
int wpa_cipher_put_suites(u8 *pos, int ciphers);
+int wpa_pick_pairwise_cipher(int ciphers, int none_allowed);
+int wpa_pick_group_cipher(int ciphers);
+int wpa_parse_cipher(const char *value);
+int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
+int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
+unsigned int wpa_mic_len(int akmp);
#endif /* WPA_COMMON_H */
diff --git a/contrib/wpa/src/common/wpa_ctrl.c b/contrib/wpa/src/common/wpa_ctrl.c
index 58cbe6a..ccaaf1b 100644
--- a/contrib/wpa/src/common/wpa_ctrl.c
+++ b/contrib/wpa/src/common/wpa_ctrl.c
@@ -25,6 +25,10 @@
#include "private/android_filesystem_config.h"
#endif /* ANDROID */
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+#include <net/if.h>
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+
#include "wpa_ctrl.h"
#include "common.h"
@@ -46,8 +50,13 @@
struct wpa_ctrl {
#ifdef CONFIG_CTRL_IFACE_UDP
int s;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ struct sockaddr_in6 local;
+ struct sockaddr_in6 dest;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in local;
struct sockaddr_in dest;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
char *cookie;
char *remote_ifname;
char *remote_ip;
@@ -82,10 +91,12 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
int tries = 0;
int flags;
- ctrl = os_malloc(sizeof(*ctrl));
+ if (ctrl_path == NULL)
+ return NULL;
+
+ ctrl = os_zalloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
- os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
@@ -100,7 +111,7 @@ try_again:
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
(int) getpid(), counter);
- if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+ if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
@@ -126,13 +137,27 @@ try_again:
#ifdef ANDROID
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+
+ if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
+ if (socket_local_client_connect(
+ ctrl->s, ctrl_path + 9,
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_DGRAM) < 0) {
+ close(ctrl->s);
+ unlink(ctrl->local.sun_path);
+ os_free(ctrl);
+ return NULL;
+ }
+ return ctrl;
+ }
+
/*
* If the ctrl_path isn't an absolute pathname, assume that
* it's the name of a socket in the Android reserved namespace.
* Otherwise, it's a normal UNIX domain socket appearing in the
* filesystem.
*/
- if (ctrl_path != NULL && *ctrl_path != '/') {
+ if (*ctrl_path != '/') {
char buf[21];
os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
if (socket_local_client_connect(
@@ -149,12 +174,18 @@ try_again:
#endif /* ANDROID */
ctrl->dest.sun_family = AF_UNIX;
- res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
- sizeof(ctrl->dest.sun_path));
- if (res >= sizeof(ctrl->dest.sun_path)) {
- close(ctrl->s);
- os_free(ctrl);
- return NULL;
+ if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
+ ctrl->dest.sun_path[0] = '\0';
+ os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
+ sizeof(ctrl->dest.sun_path) - 1);
+ } else {
+ res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
+ sizeof(ctrl->dest.sun_path));
+ if (res >= sizeof(ctrl->dest.sun_path)) {
+ close(ctrl->s);
+ os_free(ctrl);
+ return NULL;
+ }
}
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
@@ -206,7 +237,6 @@ void wpa_ctrl_cleanup(void)
struct dirent entry;
struct dirent *result;
size_t dirnamelen;
- int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
size_t maxcopy;
char pathname[PATH_MAX];
char *namep;
@@ -223,11 +253,8 @@ void wpa_ctrl_cleanup(void)
namep = pathname + dirnamelen;
maxcopy = PATH_MAX - dirnamelen;
while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
- if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
- prefixlen) == 0) {
- if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
- unlink(pathname);
- }
+ if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+ unlink(pathname);
}
closedir(dir);
}
@@ -255,24 +282,37 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
struct hostent *h;
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
- ctrl = os_malloc(sizeof(*ctrl));
+ ctrl = os_zalloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
- os_memset(ctrl, 0, sizeof(*ctrl));
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (ctrl->s < 0) {
perror("socket");
os_free(ctrl);
return NULL;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ ctrl->local.sin6_family = AF_INET6;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ ctrl->local.sin6_addr = in6addr_any;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+ inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->local.sin_family = AF_INET;
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
ctrl->local.sin_addr.s_addr = INADDR_ANY;
#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
@@ -280,14 +320,24 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
return NULL;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ ctrl->dest.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
+ ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->dest.sin_family = AF_INET;
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
if (ctrl_path) {
char *port, *name;
int port_id;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ char *scope;
+ int scope_id = 0;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
name = os_strdup(ctrl_path);
if (name == NULL) {
@@ -295,7 +345,11 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
os_free(ctrl);
return NULL;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ port = os_strchr(name, ',');
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
port = os_strchr(name, ':');
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (port) {
port_id = atoi(&port[1]);
@@ -303,7 +357,16 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
} else
port_id = WPA_CTRL_IFACE_PORT;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ scope = os_strchr(name, '%');
+ if (scope) {
+ scope_id = if_nametoindex(&scope[1]);
+ scope[0] = '\0';
+ }
+ h = gethostbyname2(name, AF_INET6);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
h = gethostbyname(name);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->remote_ip = os_strdup(name);
os_free(name);
if (h == NULL) {
@@ -313,16 +376,33 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
os_free(ctrl);
return NULL;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ ctrl->dest.sin6_scope_id = scope_id;
+ ctrl->dest.sin6_port = htons(port_id);
+ os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
ctrl->dest.sin_port = htons(port_id);
- os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr,
- h->h_length);
+ os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
} else
ctrl->remote_ip = os_strdup("localhost");
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
- perror("connect");
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ char addr[INET6_ADDRSTRLEN];
+ wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
+ inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
+ sizeof(ctrl->dest)),
+ ntohs(ctrl->dest.sin6_port),
+ strerror(errno));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
+ inet_ntoa(ctrl->dest.sin_addr),
+ ntohs(ctrl->dest.sin_port),
+ strerror(errno));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
close(ctrl->s);
os_free(ctrl->remote_ip);
os_free(ctrl);
@@ -372,7 +452,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
- struct os_time started_at;
+ struct os_reltime started_at;
int res;
fd_set rfds;
const char *_cmd;
@@ -411,12 +491,12 @@ retry_send:
* longer before giving up.
*/
if (started_at.sec == 0)
- os_get_time(&started_at);
+ os_get_reltime(&started_at);
else {
- struct os_time n;
- os_get_time(&n);
+ struct os_reltime n;
+ os_get_reltime(&n);
/* Try for a few seconds. */
- if (n.sec > started_at.sec + 5)
+ if (os_reltime_expired(&n, &started_at, 5))
goto send_err;
}
os_sleep(1, 0);
@@ -561,7 +641,7 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
ctrl_path);
#endif /* UNICODE */
- if (ret < 0 || ret >= 256) {
+ if (os_snprintf_error(256, ret)) {
os_free(ctrl);
return NULL;
}
diff --git a/contrib/wpa/src/common/wpa_ctrl.h b/contrib/wpa/src/common/wpa_ctrl.h
index bb9b558..1d19fc5 100644
--- a/contrib/wpa/src/common/wpa_ctrl.h
+++ b/contrib/wpa/src/common/wpa_ctrl.h
@@ -42,8 +42,12 @@ extern "C" {
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
/** EAP peer certificate from TLS */
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
+/** EAP peer certificate alternative subject name component from TLS */
+#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT "
/** EAP TLS certificate chain validation error */
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
+/** EAP status */
+#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
/** EAP authentication completed successfully */
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
/** EAP authentication failed (EAP-Failure received) */
@@ -52,15 +56,34 @@ extern "C" {
#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
/** Temporarily disabled network block re-enabled */
#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
+/** New scan started */
+#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+/** Scan command failed */
+#define WPA_EVENT_SCAN_FAILED "CTRL-EVENT-SCAN-FAILED "
/** wpa_supplicant state change */
#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
/** A new BSS entry was added (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
+/** Change in the signal level was reported by the driver */
+#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
+/** Regulatory domain channel */
+#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
+/** RSN IBSS 4-way handshakes completed with specified peer */
+#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
+
+/** Notification of frequency conflict due to a concurrent operation.
+ *
+ * The indicated network is disabled and needs to be re-enabled before it can
+ * be used again.
+ */
+#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
+/** Frequency ranges that the driver recommends to avoid */
+#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
@@ -82,6 +105,10 @@ extern "C" {
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
/** WPS enrollment attempt timed out and was terminated */
#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
+/* PBC mode was activated */
+#define WPS_EVENT_ACTIVE "WPS-PBC-ACTIVE "
+/* PBC mode was disabled */
+#define WPS_EVENT_DISABLE "WPS-PBC-DISABLE "
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
@@ -95,6 +122,20 @@ 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 "
+/* MESH events */
+#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
+#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
+#define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
+#define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
+/** Mesh SAE authentication failure. Wrong password suspected. */
+#define MESH_SAE_AUTH_FAILURE "MESH-SAE-AUTH-FAILURE "
+#define MESH_SAE_AUTH_BLOCKED "MESH-SAE-AUTH-BLOCKED "
+
+/* WMM AC events */
+#define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED "
+#define WMM_AC_EVENT_TSPEC_REMOVED "TSPEC-REMOVED "
+#define WMM_AC_EVENT_TSPEC_REQ_FAILED "TSPEC-REQ-FAILED "
+
/** P2P device found */
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
@@ -126,14 +167,55 @@ extern "C" {
#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
/* parameters: <src addr> <update indicator> <TLVs> */
#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
+#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_FIND_STOPPED "P2P-FIND-STOPPED "
+#define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
+#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE "
+#define P2P_EVENT_NFC_BOTH_GO "P2P-NFC-BOTH-GO "
+#define P2P_EVENT_NFC_PEER_CLIENT "P2P-NFC-PEER-CLIENT "
+#define P2P_EVENT_NFC_WHILE_CLIENT "P2P-NFC-WHILE-CLIENT "
+#define P2P_EVENT_FALLBACK_TO_GO_NEG "P2P-FALLBACK-TO-GO-NEG "
+#define P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED "P2P-FALLBACK-TO-GO-NEG-ENABLED "
+
+/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
+#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
+#define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP "
+
+#define P2P_EVENT_P2PS_PROVISION_START "P2PS-PROV-START "
+#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
#define INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_BLACKLISTED "INTERWORKING-BLACKLISTED "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
+#define INTERWORKING_SELECTED "INTERWORKING-SELECTED "
+
+/* Credential block added; parameters: <id> */
+#define CRED_ADDED "CRED-ADDED "
+/* Credential block modified; parameters: <id> <field> */
+#define CRED_MODIFIED "CRED-MODIFIED "
+/* Credential block removed; parameters: <id> */
+#define CRED_REMOVED "CRED-REMOVED "
#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
+/* parameters: <addr> <dialog_token> <freq> */
+#define GAS_QUERY_START "GAS-QUERY-START "
+/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
+#define GAS_QUERY_DONE "GAS-QUERY-DONE "
+
+/* parameters: <addr> <result> */
+#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+
+#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
+#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
+
+#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
+#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
+
+#define RRM_EVENT_NEIGHBOR_REP_RXED "RRM-NEIGHBOR-REP-RECEIVED "
+#define RRM_EVENT_NEIGHBOR_REP_FAILED "RRM-NEIGHBOR-REP-REQUEST-FAILED "
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
@@ -146,10 +228,33 @@ extern "C" {
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
+#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
+
+#define AP_EVENT_ENABLED "AP-ENABLED "
+#define AP_EVENT_DISABLED "AP-DISABLED "
+
+#define INTERFACE_ENABLED "INTERFACE-ENABLED "
+#define INTERFACE_DISABLED "INTERFACE-DISABLED "
+
+#define ACS_EVENT_STARTED "ACS-STARTED "
+#define ACS_EVENT_COMPLETED "ACS-COMPLETED "
+#define ACS_EVENT_FAILED "ACS-FAILED "
+
+#define DFS_EVENT_RADAR_DETECTED "DFS-RADAR-DETECTED "
+#define DFS_EVENT_NEW_CHANNEL "DFS-NEW-CHANNEL "
+#define DFS_EVENT_CAC_START "DFS-CAC-START "
+#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
+#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
+
+#define AP_CSA_FINISHED "AP-CSA-FINISHED "
+
+/* BSS Transition Management Response frame received */
+#define BSS_TM_RESP "BSS-TM-RESP "
/* BSS command information masks */
-#define WPA_BSS_MASK_ALL 0xFFFFFFFF
+#define WPA_BSS_MASK_ALL 0xFFFDFFFF
#define WPA_BSS_MASK_ID BIT(0)
#define WPA_BSS_MASK_BSSID BIT(1)
#define WPA_BSS_MASK_FREQ BIT(2)
@@ -167,6 +272,30 @@ extern "C" {
#define WPA_BSS_MASK_P2P_SCAN BIT(14)
#define WPA_BSS_MASK_INTERNETW BIT(15)
#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
+#define WPA_BSS_MASK_DELIM BIT(17)
+#define WPA_BSS_MASK_MESH_SCAN BIT(18)
+#define WPA_BSS_MASK_SNR BIT(19)
+#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20)
+
+
+/* VENDOR_ELEM_* frame id values */
+enum wpa_vendor_elem_frame {
+ VENDOR_ELEM_PROBE_REQ_P2P = 0,
+ VENDOR_ELEM_PROBE_RESP_P2P = 1,
+ VENDOR_ELEM_PROBE_RESP_P2P_GO = 2,
+ VENDOR_ELEM_BEACON_P2P_GO = 3,
+ VENDOR_ELEM_P2P_PD_REQ = 4,
+ VENDOR_ELEM_P2P_PD_RESP = 5,
+ VENDOR_ELEM_P2P_GO_NEG_REQ = 6,
+ VENDOR_ELEM_P2P_GO_NEG_RESP = 7,
+ VENDOR_ELEM_P2P_GO_NEG_CONF = 8,
+ VENDOR_ELEM_P2P_INV_REQ = 9,
+ VENDOR_ELEM_P2P_INV_RESP = 10,
+ VENDOR_ELEM_P2P_ASSOC_REQ = 11,
+ VENDOR_ELEM_P2P_ASSOC_RESP = 12,
+ VENDOR_ELEM_ASSOC_REQ = 13,
+ NUM_VENDOR_ELEM_FRAMES
+};
/* wpa_supplicant/hostapd control interface access */
@@ -256,9 +385,10 @@ int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
* @reply_len: Length of the reply buffer
* Returns: 0 on success, -1 on failure
*
- * This function will receive a pending control interface message. This
- * function will block if no messages are available. The received response will
- * be written to reply and reply_len is set to the actual length of the reply.
+ * This function will receive a pending control interface message. The received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply.
+
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
* must have been used to register the control interface as an event monitor.
*/
@@ -293,8 +423,6 @@ int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
-char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
-
#ifdef ANDROID
/**
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
@@ -312,6 +440,8 @@ void wpa_ctrl_cleanup(void);
#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
#endif /* CONFIG_CTRL_IFACE_UDP */
diff --git a/contrib/wpa/src/common/wpa_helpers.c b/contrib/wpa/src/common/wpa_helpers.c
new file mode 100644
index 0000000..28913b9
--- /dev/null
+++ b/contrib/wpa/src/common/wpa_helpers.c
@@ -0,0 +1,292 @@
+/*
+ * wpa_supplicant ctrl_iface helpers
+ * Copyright (c) 2010-2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <time.h>
+
+#include "common.h"
+#include "wpa_ctrl.h"
+#include "wpa_helpers.h"
+
+
+char *wpas_ctrl_path = "/var/run/wpa_supplicant/";
+static int default_timeout = 60;
+
+
+static struct wpa_ctrl * wpa_open_ctrl(const char *ifname)
+{
+ char buf[128];
+ struct wpa_ctrl *ctrl;
+
+ os_snprintf(buf, sizeof(buf), "%s%s", wpas_ctrl_path, ifname);
+ ctrl = wpa_ctrl_open(buf);
+ if (ctrl == NULL)
+ printf("wpa_command: wpa_ctrl_open(%s) failed\n", buf);
+ return ctrl;
+}
+
+
+int wpa_command(const char *ifname, const char *cmd)
+{
+ struct wpa_ctrl *ctrl;
+ char buf[128];
+ size_t len;
+
+ printf("wpa_command(ifname='%s', cmd='%s')\n", ifname, cmd);
+ ctrl = wpa_open_ctrl(ifname);
+ if (ctrl == NULL)
+ return -1;
+ len = sizeof(buf);
+ if (wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL) < 0) {
+ printf("wpa_command: wpa_ctrl_request failed\n");
+ wpa_ctrl_close(ctrl);
+ return -1;
+ }
+ wpa_ctrl_close(ctrl);
+ buf[len] = '\0';
+ if (strncmp(buf, "FAIL", 4) == 0) {
+ printf("wpa_command: Command failed (FAIL received)\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+int wpa_command_resp(const char *ifname, const char *cmd,
+ char *resp, size_t resp_size)
+{
+ struct wpa_ctrl *ctrl;
+ size_t len;
+
+ printf("wpa_command(ifname='%s', cmd='%s')\n", ifname, cmd);
+ ctrl = wpa_open_ctrl(ifname);
+ if (ctrl == NULL)
+ return -1;
+ len = resp_size;
+ if (wpa_ctrl_request(ctrl, cmd, strlen(cmd), resp, &len, NULL) < 0) {
+ printf("wpa_command: wpa_ctrl_request failed\n");
+ wpa_ctrl_close(ctrl);
+ return -1;
+ }
+ wpa_ctrl_close(ctrl);
+ resp[len] = '\0';
+ return 0;
+}
+
+
+struct wpa_ctrl * open_wpa_mon(const char *ifname)
+{
+ struct wpa_ctrl *ctrl;
+
+ ctrl = wpa_open_ctrl(ifname);
+ if (ctrl == NULL)
+ return NULL;
+ if (wpa_ctrl_attach(ctrl) < 0) {
+ wpa_ctrl_close(ctrl);
+ return NULL;
+ }
+
+ return ctrl;
+}
+
+
+int get_wpa_cli_event2(struct wpa_ctrl *mon,
+ const char *event, const char *event2,
+ char *buf, size_t buf_size)
+{
+ int fd, ret;
+ fd_set rfd;
+ char *pos;
+ struct timeval tv;
+ time_t start, now;
+
+ printf("Waiting for wpa_cli event %s\n", event);
+ fd = wpa_ctrl_get_fd(mon);
+ if (fd < 0)
+ return -1;
+
+ time(&start);
+ while (1) {
+ size_t len;
+
+ FD_ZERO(&rfd);
+ FD_SET(fd, &rfd);
+ tv.tv_sec = default_timeout;
+ tv.tv_usec = 0;
+ ret = select(fd + 1, &rfd, NULL, NULL, &tv);
+ if (ret == 0) {
+ printf("Timeout on waiting for event %s\n", event);
+ return -1;
+ }
+ if (ret < 0) {
+ printf("select: %s\n", strerror(errno));
+ return -1;
+ }
+ len = buf_size;
+ if (wpa_ctrl_recv(mon, buf, &len) < 0) {
+ printf("Failure while waiting for event %s\n", event);
+ return -1;
+ }
+ if (len == buf_size)
+ len--;
+ buf[len] = '\0';
+
+ pos = strchr(buf, '>');
+ if (pos &&
+ (strncmp(pos + 1, event, strlen(event)) == 0 ||
+ (event2 &&
+ strncmp(pos + 1, event2, strlen(event2)) == 0)))
+ return 0; /* Event found */
+
+ time(&now);
+ if ((int) (now - start) > default_timeout) {
+ printf("Timeout on waiting for event %s\n", event);
+ return -1;
+ }
+ }
+}
+
+
+int get_wpa_cli_event(struct wpa_ctrl *mon,
+ const char *event, char *buf, size_t buf_size)
+{
+ return get_wpa_cli_event2(mon, event, NULL, buf, buf_size);
+}
+
+
+int get_wpa_status(const char *ifname, const char *field, char *obuf,
+ size_t obuf_size)
+{
+ struct wpa_ctrl *ctrl;
+ char buf[4096];
+ char *pos, *end;
+ size_t len, flen;
+
+ ctrl = wpa_open_ctrl(ifname);
+ if (ctrl == NULL)
+ return -1;
+ len = sizeof(buf);
+ if (wpa_ctrl_request(ctrl, "STATUS", 6, buf, &len, NULL) < 0) {
+ wpa_ctrl_close(ctrl);
+ return -1;
+ }
+ wpa_ctrl_close(ctrl);
+ buf[len] = '\0';
+
+ flen = strlen(field);
+ pos = buf;
+ while (pos + flen < buf + len) {
+ if (pos > buf) {
+ if (*pos != '\n') {
+ pos++;
+ continue;
+ }
+ pos++;
+ }
+ if (strncmp(pos, field, flen) != 0 || pos[flen] != '=') {
+ pos++;
+ continue;
+ }
+ pos += flen + 1;
+ end = strchr(pos, '\n');
+ if (end == NULL)
+ return -1;
+ *end++ = '\0';
+ if (end - pos > (int) obuf_size)
+ return -1;
+ memcpy(obuf, pos, end - pos);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int wait_ip_addr(const char *ifname, int timeout)
+{
+ char ip[30];
+ int count = timeout;
+ struct wpa_ctrl *ctrl;
+
+ while (count > 0) {
+ printf("%s: ifname='%s' - %d seconds remaining\n",
+ __func__, ifname, count);
+ count--;
+ if (get_wpa_status(ifname, "ip_address", ip, sizeof(ip)) == 0
+ && strlen(ip) > 0) {
+ printf("IP address found: '%s'\n", ip);
+ return 0;
+ }
+ ctrl = wpa_open_ctrl(ifname);
+ if (ctrl == NULL)
+ return -1;
+ wpa_ctrl_close(ctrl);
+ sleep(1);
+ }
+ printf("%s: Could not get IP address for ifname='%s'", __func__,
+ ifname);
+ return -1;
+}
+
+
+int add_network(const char *ifname)
+{
+ char res[30];
+
+ if (wpa_command_resp(ifname, "ADD_NETWORK", res, sizeof(res)) < 0)
+ return -1;
+ return atoi(res);
+}
+
+
+int set_network(const char *ifname, int id, const char *field,
+ const char *value)
+{
+ char buf[200];
+ snprintf(buf, sizeof(buf), "SET_NETWORK %d %s %s", id, field, value);
+ return wpa_command(ifname, buf);
+}
+
+
+int set_network_quoted(const char *ifname, int id, const char *field,
+ const char *value)
+{
+ char buf[200];
+ snprintf(buf, sizeof(buf), "SET_NETWORK %d %s \"%s\"",
+ id, field, value);
+ return wpa_command(ifname, buf);
+}
+
+
+int add_cred(const char *ifname)
+{
+ char res[30];
+
+ if (wpa_command_resp(ifname, "ADD_CRED", res, sizeof(res)) < 0)
+ return -1;
+ return atoi(res);
+}
+
+
+int set_cred(const char *ifname, int id, const char *field, const char *value)
+{
+ char buf[200];
+ snprintf(buf, sizeof(buf), "SET_CRED %d %s %s", id, field, value);
+ return wpa_command(ifname, buf);
+}
+
+
+int set_cred_quoted(const char *ifname, int id, const char *field,
+ const char *value)
+{
+ char buf[200];
+ snprintf(buf, sizeof(buf), "SET_CRED %d %s \"%s\"",
+ id, field, value);
+ return wpa_command(ifname, buf);
+}
diff --git a/contrib/wpa/src/common/wpa_helpers.h b/contrib/wpa/src/common/wpa_helpers.h
new file mode 100644
index 0000000..54c2872
--- /dev/null
+++ b/contrib/wpa/src/common/wpa_helpers.h
@@ -0,0 +1,37 @@
+/*
+ * wpa_supplicant ctrl_iface helpers
+ * Copyright (c) 2010-2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_HELPERS_H
+#define WPA_HELPERS_H
+
+int wpa_command(const char *ifname, const char *cmd);
+int wpa_command_resp(const char *ifname, const char *cmd,
+ char *resp, size_t resp_size);
+int get_wpa_status(const char *ifname, const char *field, char *obuf,
+ size_t obuf_size);
+
+struct wpa_ctrl * open_wpa_mon(const char *ifname);
+int wait_ip_addr(const char *ifname, int timeout);
+int get_wpa_cli_event(struct wpa_ctrl *mon,
+ const char *event, char *buf, size_t buf_size);
+int get_wpa_cli_event2(struct wpa_ctrl *mon,
+ const char *event, const char *event2,
+ char *buf, size_t buf_size);
+
+int add_network(const char *ifname);
+int set_network(const char *ifname, int id, const char *field,
+ const char *value);
+int set_network_quoted(const char *ifname, int id, const char *field,
+ const char *value);
+int add_cred(const char *ifname);
+int set_cred(const char *ifname, int id, const char *field, const char *value);
+int set_cred_quoted(const char *ifname, int id, const char *field,
+ const char *value);
+
+#endif /* WPA_HELPERS_H */
diff --git a/contrib/wpa/src/crypto/aes-ccm.c b/contrib/wpa/src/crypto/aes-ccm.c
index d14670d..cf22778 100644
--- a/contrib/wpa/src/crypto/aes-ccm.c
+++ b/contrib/wpa/src/crypto/aes-ccm.c
@@ -203,7 +203,7 @@ int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
aes_encrypt_deinit(aes);
- if (os_memcmp(x, t, M) != 0) {
+ if (os_memcmp_const(x, t, M) != 0) {
wpa_printf(MSG_EXCESSIVE, "CCM: Auth mismatch");
return -1;
}
diff --git a/contrib/wpa/src/crypto/aes-eax.c b/contrib/wpa/src/crypto/aes-eax.c
index 21941c6..15a09f8 100644
--- a/contrib/wpa/src/crypto/aes-eax.c
+++ b/contrib/wpa/src/crypto/aes-eax.c
@@ -71,7 +71,7 @@ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
ret = 0;
fail:
- os_free(buf);
+ bin_clear_free(buf, buf_len);
return ret;
}
diff --git a/contrib/wpa/src/crypto/aes-gcm.c b/contrib/wpa/src/crypto/aes-gcm.c
index 3d91c71..84294d2 100644
--- a/contrib/wpa/src/crypto/aes-gcm.c
+++ b/contrib/wpa/src/crypto/aes-gcm.c
@@ -310,7 +310,7 @@ int aes_gcm_ad(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
aes_encrypt_deinit(aes);
- if (os_memcmp(tag, T, 16) != 0) {
+ if (os_memcmp_const(tag, T, 16) != 0) {
wpa_printf(MSG_EXCESSIVE, "GCM: Tag mismatch");
return -1;
}
diff --git a/contrib/wpa/src/crypto/aes-omac1.c b/contrib/wpa/src/crypto/aes-omac1.c
index 27895eb..375db57 100644
--- a/contrib/wpa/src/crypto/aes-omac1.c
+++ b/contrib/wpa/src/crypto/aes-omac1.c
@@ -1,5 +1,5 @@
/*
- * One-key CBC MAC (OMAC1) hash with AES-128
+ * One-key CBC MAC (OMAC1) hash with AES
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -27,8 +27,9 @@ static void gf_mulx(u8 *pad)
/**
- * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: 128-bit key for the hash operation
+ * omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES
+ * @key: Key for the hash operation
+ * @key_len: Key length in octets
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
@@ -39,15 +40,15 @@ static void gf_mulx(u8 *pad)
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end;
size_t i, e, left, total_len;
- ctx = aes_encrypt_init(key, 16);
+ ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, AES_BLOCK_SIZE);
@@ -65,6 +66,13 @@ int omac1_aes_128_vector(const u8 *key, size_t num_elem,
for (i = 0; i < AES_BLOCK_SIZE; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
+ /*
+ * Stop if there are no more bytes to process
+ * since there are no more entries in the array.
+ */
+ if (i + 1 == AES_BLOCK_SIZE &&
+ left == AES_BLOCK_SIZE)
+ break;
e++;
pos = addr[e];
end = pos + len[e];
@@ -83,6 +91,12 @@ int omac1_aes_128_vector(const u8 *key, size_t num_elem,
for (i = 0; i < left; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
+ /*
+ * Stop if there are no more bytes to process
+ * since there are no more entries in the array.
+ */
+ if (i + 1 == left)
+ break;
e++;
pos = addr[e];
end = pos + len[e];
@@ -101,6 +115,26 @@ int omac1_aes_128_vector(const u8 *key, size_t num_elem,
/**
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 128-bit key for the hash operation
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+/**
* omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
* @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
@@ -116,3 +150,21 @@ 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);
}
+
+
+/**
+ * omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC)
+ * @key: 256-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
diff --git a/contrib/wpa/src/crypto/aes-siv.c b/contrib/wpa/src/crypto/aes-siv.c
new file mode 100644
index 0000000..5ac82c2
--- /dev/null
+++ b/contrib/wpa/src/crypto/aes-siv.c
@@ -0,0 +1,188 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, 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 "aes.h"
+#include "aes_wrap.h"
+#include "aes_siv.h"
+
+
+static const u8 zero[AES_BLOCK_SIZE];
+
+
+static void dbl(u8 *pad)
+{
+ int i, carry;
+
+ carry = pad[0] & 0x80;
+ for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+ pad[AES_BLOCK_SIZE - 1] <<= 1;
+ if (carry)
+ pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+static void xor(u8 *a, const u8 *b)
+{
+ int i;
+
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ *a++ ^= *b++;
+}
+
+
+static void xorend(u8 *a, int alen, const u8 *b, int blen)
+{
+ int i;
+
+ if (alen < blen)
+ return;
+
+ for (i = 0; i < blen; i++)
+ a[alen - blen + i] ^= b[i];
+}
+
+
+static void pad_block(u8 *pad, const u8 *addr, size_t len)
+{
+ os_memset(pad, 0, AES_BLOCK_SIZE);
+ os_memcpy(pad, addr, len);
+
+ if (len < AES_BLOCK_SIZE)
+ pad[len] = 0x80;
+}
+
+
+static int aes_s2v(const u8 *key, 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;
+
+ if (!num_elem) {
+ os_memcpy(tmp, zero, sizeof(zero));
+ tmp[AES_BLOCK_SIZE - 1] = 1;
+ return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ }
+
+ ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_elem - 1; i++) {
+ ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+ if (ret)
+ return ret;
+
+ dbl(tmp);
+ xor(tmp, tmp2);
+ }
+ if (len[i] >= AES_BLOCK_SIZE) {
+ buf = os_malloc(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);
+ bin_clear_free(buf, len[i]);
+ return ret;
+ }
+
+ dbl(tmp);
+ pad_block(tmp2, addr[i], len[i]);
+ xor(tmp, tmp2);
+
+ return omac1_aes_128(key, tmp, sizeof(tmp), 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)
+{
+ const u8 *_addr[6];
+ size_t _len[6];
+ const u8 *k1 = key, *k2 = key + 16;
+ u8 v[AES_BLOCK_SIZE];
+ size_t i;
+ u8 *iv, *crypt_pw;
+
+ if (num_elem > ARRAY_SIZE(_addr) - 1)
+ return -1;
+
+ for (i = 0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = pw;
+ _len[num_elem] = pwlen;
+
+ if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+ return -1;
+
+ iv = out;
+ crypt_pw = out + AES_BLOCK_SIZE;
+
+ os_memcpy(iv, v, AES_BLOCK_SIZE);
+ os_memcpy(crypt_pw, pw, pwlen);
+
+ /* 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);
+}
+
+
+int aes_siv_decrypt(const u8 *key, 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;
+ 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)
+ return -1;
+ crypt_len = iv_c_len - AES_BLOCK_SIZE;
+
+ for (i = 0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = out;
+ _len[num_elem] = crypt_len;
+
+ os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
+ os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
+
+ iv[8] &= 0x7f;
+ iv[12] &= 0x7f;
+
+ ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+ if (ret)
+ return ret;
+
+ ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+ if (ret)
+ return ret;
+ if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
+ return 0;
+
+ return -1;
+}
diff --git a/contrib/wpa/src/crypto/aes-unwrap.c b/contrib/wpa/src/crypto/aes-unwrap.c
index 9dd5160..ec793d9 100644
--- a/contrib/wpa/src/crypto/aes-unwrap.c
+++ b/contrib/wpa/src/crypto/aes-unwrap.c
@@ -1,5 +1,5 @@
/*
- * AES key unwrap (128-bit KEK, RFC3394)
+ * AES key unwrap (RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -14,26 +14,29 @@
#include "aes_wrap.h"
/**
- * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (RFC3394)
* @kek: Key encryption key (KEK)
+ * @kek_len: Length of KEK in octets
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
* @plain: Plaintext key, n * 64 bits
* Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
*/
-int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
{
- u8 a[8], *r, b[16];
+ u8 a[8], *r, b[AES_BLOCK_SIZE];
int i, j;
void *ctx;
+ unsigned int t;
/* 1) Initialize variables. */
os_memcpy(a, cipher, 8);
r = plain;
os_memcpy(r, cipher + 8, 8 * n);
- ctx = aes_decrypt_init(kek, 16);
+ ctx = aes_decrypt_init(kek, kek_len);
if (ctx == NULL)
return -1;
@@ -48,7 +51,11 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
r = plain + (n - 1) * 8;
for (i = n; i >= 1; i--) {
os_memcpy(b, a, 8);
- b[7] ^= n * j + i;
+ t = n * j + i;
+ b[7] ^= t;
+ b[6] ^= t >> 8;
+ b[5] ^= t >> 16;
+ b[4] ^= t >> 24;
os_memcpy(b + 8, r, 8);
aes_decrypt(ctx, b, b);
diff --git a/contrib/wpa/src/crypto/aes-wrap.c b/contrib/wpa/src/crypto/aes-wrap.c
index 89d6f94..7ed34e8 100644
--- a/contrib/wpa/src/crypto/aes-wrap.c
+++ b/contrib/wpa/src/crypto/aes-wrap.c
@@ -1,5 +1,5 @@
/*
- * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * AES Key Wrap Algorithm (RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -14,19 +14,21 @@
#include "aes_wrap.h"
/**
- * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * @kek: 16-octet Key encryption key (KEK)
+ * aes_wrap - Wrap keys with AES Key Wrap Algorithm (RFC3394)
+ * @kek: Key encryption key (KEK)
+ * @kek_len: Length of KEK in octets
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @plain: Plaintext key to be wrapped, n * 64 bits
* @cipher: Wrapped key, (n + 1) * 64 bits
* Returns: 0 on success, -1 on failure
*/
-int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
- u8 *a, *r, b[16];
+ u8 *a, *r, b[AES_BLOCK_SIZE];
int i, j;
void *ctx;
+ unsigned int t;
a = cipher;
r = cipher + 8;
@@ -35,7 +37,7 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
os_memset(a, 0xa6, 8);
os_memcpy(r, plain, 8 * n);
- ctx = aes_encrypt_init(kek, 16);
+ ctx = aes_encrypt_init(kek, kek_len);
if (ctx == NULL)
return -1;
@@ -53,7 +55,11 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
os_memcpy(b + 8, r, 8);
aes_encrypt(ctx, b, b);
os_memcpy(a, b, 8);
- a[7] ^= n * j + i;
+ t = n * j + i;
+ a[7] ^= t;
+ a[6] ^= t >> 8;
+ a[5] ^= t >> 16;
+ a[4] ^= t >> 24;
os_memcpy(r, b + 8, 8);
r += 8;
}
diff --git a/contrib/wpa/src/crypto/aes_siv.h b/contrib/wpa/src/crypto/aes_siv.h
new file mode 100644
index 0000000..463cf65
--- /dev/null
+++ b/contrib/wpa/src/crypto/aes_siv.h
@@ -0,0 +1,19 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#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,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out);
+
+#endif /* AES_SIV_H */
diff --git a/contrib/wpa/src/crypto/aes_wrap.h b/contrib/wpa/src/crypto/aes_wrap.h
index 0433c04..4a14209 100644
--- a/contrib/wpa/src/crypto/aes_wrap.h
+++ b/contrib/wpa/src/crypto/aes_wrap.h
@@ -1,8 +1,8 @@
/*
* AES-based functions
*
- * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - AES Key Wrap Algorithm (RFC3394)
+ * - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
@@ -18,13 +18,20 @@
#ifndef AES_WRAP_H
#define AES_WRAP_H
-int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
-int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int __must_check aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain,
+ u8 *cipher);
+int __must_check aes_unwrap(const u8 *kek, size_t kek_len, int n,
+ const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_vector(const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac);
int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len,
u8 *mac);
int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
+int __must_check 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_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
diff --git a/contrib/wpa/src/crypto/crypto.h b/contrib/wpa/src/crypto/crypto.h
index 26b9acf..f2d5662 100644
--- a/contrib/wpa/src/crypto/crypto.h
+++ b/contrib/wpa/src/crypto/crypto.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / wrapper functions for crypto libraries
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Wrapper functions for crypto libraries
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -271,6 +271,10 @@ struct crypto_private_key;
*/
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
+struct crypto_public_key *
+crypto_public_key_import_parts(const u8 *n, size_t n_len,
+ const u8 *e, size_t e_len);
+
/**
* crypto_private_key_import - Import an RSA private key
* @key: Key buffer (DER encoded RSA private key)
@@ -457,4 +461,319 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
*/
int crypto_get_random(void *buf, size_t len);
+
+/**
+ * struct crypto_bignum - bignum
+ *
+ * Internal data structure for bignum implementation. The contents is specific
+ * to the used crypto library.
+ */
+struct crypto_bignum;
+
+/**
+ * crypto_bignum_init - Allocate memory for bignum
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init(void);
+
+/**
+ * crypto_bignum_init_set - Allocate memory for bignum and set the value
+ * @buf: Buffer with unsigned binary value
+ * @len: Length of buf in octets
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
+
+/**
+ * crypto_bignum_deinit - Free bignum
+ * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
+ * @clear: Whether to clear the value from memory
+ */
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear);
+
+/**
+ * crypto_bignum_to_bin - Set binary buffer to unsigned bignum
+ * @a: Bignum
+ * @buf: Buffer for the binary number
+ * @len: Length of @buf in octets
+ * @padlen: Length in octets to pad the result to or 0 to indicate no padding
+ * Returns: Number of octets written on success, -1 on failure
+ */
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen);
+
+/**
+ * crypto_bignum_add - c = a + b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_add(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_mod - c = a % b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a % b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_mod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_exptmod - Modular exponentiation: d = a^b (mod c)
+ * @a: Bignum; base
+ * @b: Bignum; exponent
+ * @c: Bignum; modulus
+ * @d: Bignum; used to store the result of a^b (mod c)
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_exptmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
+ * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_sub - c = a - b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a - b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_sub(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_div - c = a / b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a / b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_div(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_mulmod - d = a * b (mod c)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum
+ * @d: Bignum; used to store the result of (a * b) % c
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
+ * crypto_bignum_cmp - Compare two bignums
+ * @a: Bignum
+ * @b: Bignum
+ * Returns: -1 if a < b, 0 if a == b, or 1 if a > b
+ */
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+ const struct crypto_bignum *b);
+
+/**
+ * crypto_bignum_bits - Get size of a bignum in bits
+ * @a: Bignum
+ * Returns: Number of bits in the bignum
+ */
+int crypto_bignum_bits(const struct crypto_bignum *a);
+
+/**
+ * crypto_bignum_is_zero - Is the given bignum zero
+ * @a: Bignum
+ * Returns: 1 if @a is zero or 0 if not
+ */
+int crypto_bignum_is_zero(const struct crypto_bignum *a);
+
+/**
+ * crypto_bignum_is_one - Is the given bignum one
+ * @a: Bignum
+ * Returns: 1 if @a is one or 0 if not
+ */
+int crypto_bignum_is_one(const struct crypto_bignum *a);
+
+/**
+ * struct crypto_ec - Elliptic curve context
+ *
+ * Internal data structure for EC implementation. The contents is specific
+ * to the used crypto library.
+ */
+struct crypto_ec;
+
+/**
+ * crypto_ec_init - Initialize elliptic curve context
+ * @group: Identifying number for the ECC group (IANA "Group Description"
+ * attribute registrty for RFC 2409)
+ * Returns: Pointer to EC context or %NULL on failure
+ */
+struct crypto_ec * crypto_ec_init(int group);
+
+/**
+ * crypto_ec_deinit - Deinitialize elliptic curve context
+ * @e: EC context from crypto_ec_init()
+ */
+void crypto_ec_deinit(struct crypto_ec *e);
+
+/**
+ * crypto_ec_prime_len - Get length of the prime in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the prime defining the group
+ */
+size_t crypto_ec_prime_len(struct crypto_ec *e);
+
+/**
+ * crypto_ec_prime_len_bits - Get length of the prime in bits
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the prime defining the group in bits
+ */
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
+
+/**
+ * crypto_ec_get_prime - Get prime defining an EC group
+ * @e: EC context from crypto_ec_init()
+ * Returns: Prime (bignum) defining the group
+ */
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
+
+/**
+ * crypto_ec_get_order - Get order of an EC group
+ * @e: EC context from crypto_ec_init()
+ * Returns: Order (bignum) of the group
+ */
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+
+/**
+ * struct crypto_ec_point - Elliptic curve point
+ *
+ * Internal data structure for EC implementation to represent a point. The
+ * contents is specific to the used crypto library.
+ */
+struct crypto_ec_point;
+
+/**
+ * crypto_ec_point_init - Initialize data for an EC point
+ * @e: EC context from crypto_ec_init()
+ * Returns: Pointer to EC point data or %NULL on failure
+ */
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
+
+/**
+ * crypto_ec_point_deinit - Deinitialize EC point data
+ * @p: EC point data from crypto_ec_point_init()
+ * @clear: Whether to clear the EC point value from memory
+ */
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
+
+/**
+ * crypto_ec_point_to_bin - Write EC point value as binary data
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point data from crypto_ec_point_init()
+ * @x: Buffer for writing the binary data for x coordinate or %NULL if not used
+ * @y: Buffer for writing the binary data for y coordinate or %NULL if not used
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to write an EC point as binary data in a format
+ * that has the x and y coordinates in big endian byte order fields padded to
+ * the length of the prime defining the group.
+ */
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y);
+
+/**
+ * crypto_ec_point_from_bin - Create EC point from binary data
+ * @e: EC context from crypto_ec_init()
+ * @val: Binary data to read the EC point from
+ * Returns: Pointer to EC point data or %NULL on failure
+ *
+ * This function readers x and y coordinates of the EC point from the provided
+ * buffer assuming the values are in big endian byte order with fields padded to
+ * the length of the prime defining the group.
+ */
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val);
+
+/**
+ * crypto_bignum_add - c = a + b
+ * @e: EC context from crypto_ec_init()
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c);
+
+/**
+ * crypto_bignum_mul - res = b * p
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * @b: Bignum
+ * @res: EC point; used to store the result of b * p
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res);
+
+/**
+ * crypto_ec_point_invert - Compute inverse of an EC point
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point to invert (and result of the operation)
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p);
+
+/**
+ * crypto_ec_point_solve_y_coord - Solve y coordinate for an x coordinate
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point to use for the returning the result
+ * @x: x coordinate
+ * @y_bit: y-bit (0 or 1) for selecting the y value to use
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+ struct crypto_ec_point *p,
+ const struct crypto_bignum *x, int y_bit);
+
+/**
+ * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * Returns: 1 if the specified EC point is the neutral element of the group or
+ * 0 if not
+ */
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+ const struct crypto_ec_point *p);
+
+/**
+ * crypto_ec_point_is_on_curve - Check whether EC point is on curve
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * Returns: 1 if the specified EC point is on the curve or 0 if not
+ */
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+ const struct crypto_ec_point *p);
+
#endif /* CRYPTO_H */
diff --git a/contrib/wpa/src/crypto/crypto_internal-rsa.c b/contrib/wpa/src/crypto/crypto_internal-rsa.c
index 54209fa..dc7f350 100644
--- a/contrib/wpa/src/crypto/crypto_internal-rsa.c
+++ b/contrib/wpa/src/crypto/crypto_internal-rsa.c
@@ -26,6 +26,15 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
}
+struct crypto_public_key *
+crypto_public_key_import_parts(const u8 *n, size_t n_len,
+ const u8 *e, size_t e_len)
+{
+ return (struct crypto_public_key *)
+ crypto_rsa_import_public_key_parts(n, n_len, e, e_len);
+}
+
+
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd)
diff --git a/contrib/wpa/src/crypto/crypto_module_tests.c b/contrib/wpa/src/crypto/crypto_module_tests.c
new file mode 100644
index 0000000..7137c27
--- /dev/null
+++ b/contrib/wpa/src/crypto/crypto_module_tests.c
@@ -0,0 +1,1679 @@
+/*
+ * crypto 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "crypto/aes_siv.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/aes.h"
+#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+
+
+static int test_siv(void)
+{
+#ifdef CONFIG_MESH
+ /* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+ u8 key[] = {
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ u8 ad[] = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+ };
+ u8 plaintext[] = {
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+ };
+ u8 iv_c[] = {
+ 0x85, 0x63, 0x2d, 0x07, 0xc6, 0xe8, 0xf3, 0x7f,
+ 0x95, 0x0a, 0xcd, 0x32, 0x0a, 0x2e, 0xcc, 0x93,
+ 0x40, 0xc0, 0x2b, 0x96, 0x90, 0xc4, 0xdc, 0x04,
+ 0xda, 0xef, 0x7f, 0x6a, 0xfe, 0x5c
+ };
+ /* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+ u8 key_2[] = {
+ 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+ };
+ u8 ad1_2[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0xde, 0xad, 0xda, 0xda, 0xde, 0xad, 0xda, 0xda,
+ 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+ 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00
+ };
+ u8 ad2_2[] = {
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
+ 0x90, 0xa0
+ };
+ u8 nonce_2[] = {
+ 0x09, 0xf9, 0x11, 0x02, 0x9d, 0x74, 0xe3, 0x5b,
+ 0xd8, 0x41, 0x56, 0xc5, 0x63, 0x56, 0x88, 0xc0
+ };
+ u8 plaintext_2[] = {
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x6c, 0x61,
+ 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x74,
+ 0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20,
+ 0x53, 0x49, 0x56, 0x2d, 0x41, 0x45, 0x53
+ };
+ u8 iv_c_2[] = {
+ 0x7b, 0xdb, 0x6e, 0x3b, 0x43, 0x26, 0x67, 0xeb,
+ 0x06, 0xf4, 0xd1, 0x4b, 0xff, 0x2f, 0xbd, 0x0f,
+ 0xcb, 0x90, 0x0f, 0x2f, 0xdd, 0xbe, 0x40, 0x43,
+ 0x26, 0x60, 0x19, 0x65, 0xc8, 0x89, 0xbf, 0x17,
+ 0xdb, 0xa7, 0x7c, 0xeb, 0x09, 0x4f, 0xa6, 0x63,
+ 0xb7, 0xa3, 0xf7, 0x48, 0xba, 0x8a, 0xf8, 0x29,
+ 0xea, 0x64, 0xad, 0x54, 0x4a, 0x27, 0x2e, 0x9c,
+ 0x48, 0x5b, 0x62, 0xa3, 0xfd, 0x5c, 0x0d
+ };
+ u8 out[2 * AES_BLOCK_SIZE + sizeof(plaintext_2)];
+ const u8 *addr[3];
+ size_t len[3];
+
+ /* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+ addr[0] = ad;
+ len[0] = sizeof(ad);
+
+ if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
+ 1, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, iv_c, sizeof(iv_c)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode encryption returned invalid cipher text");
+ return 1;
+ }
+
+ if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, plaintext, sizeof(plaintext)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ /* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+ addr[0] = ad1_2;
+ len[0] = sizeof(ad1_2);
+ addr[1] = ad2_2;
+ len[1] = sizeof(ad2_2);
+ addr[2] = nonce_2;
+ len[2] = sizeof(nonce_2);
+
+ if (aes_siv_encrypt(key_2, plaintext_2, sizeof(plaintext_2),
+ 3, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, iv_c_2, sizeof(iv_c_2)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode encryption returned invalid cipher text");
+ return 1;
+ }
+
+ if (aes_siv_decrypt(key_2, iv_c_2, sizeof(iv_c_2), 3, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, plaintext_2, sizeof(plaintext_2)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "AES-SIV test cases passed");
+#endif /* CONFIG_MESH */
+
+ return 0;
+}
+
+
+/* OMAC1 AES-128 test vectors from
+ * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
+ * which are same as the examples from NIST SP800-38B
+ * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ */
+
+struct omac1_test_vector {
+ u8 k[16];
+ u8 msg[64];
+ int msg_len;
+ u8 tag[16];
+};
+
+static struct omac1_test_vector omac1_test_vectors[] =
+{
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { },
+ 0,
+ { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ 16,
+ { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+ 40,
+ { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+ 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+ 64,
+ { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+ },
+};
+
+
+static int test_omac1_vector(struct omac1_test_vector *tv, unsigned int i)
+{
+ u8 key[] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ u8 msg[] = { 0x12, 0x34, 0x56 };
+ u8 result[24], result2[24];
+ const u8 *addr[3];
+ size_t len[3];
+
+ if (omac1_aes_128(tv->k, tv->msg, tv->msg_len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR, "OMAC1-AES-128 test vector %u failed", i);
+ return 1;
+ }
+
+ if (tv->msg_len > 1) {
+
+ addr[0] = tv->msg;
+ len[0] = 1;
+ addr[1] = tv->msg + 1;
+ len[1] = tv->msg_len - 1;
+
+ if (omac1_aes_128_vector(tv->k, 2, addr, len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR,
+ "OMAC1-AES-128(vector) test vector %u failed",
+ i);
+ return 1;
+ }
+
+ addr[0] = tv->msg;
+ len[0] = tv->msg_len - 2;
+ addr[1] = tv->msg + tv->msg_len - 2;
+ len[1] = 1;
+ addr[2] = tv->msg + tv->msg_len - 1;
+ len[2] = 1;
+
+ if (omac1_aes_128_vector(tv->k, 3, addr, len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR,
+ "OMAC1-AES-128(vector2) test vector %u failed",
+ i);
+ return 1;
+ }
+ }
+
+ addr[0] = &msg[0];
+ len[0] = 1;
+ addr[1] = &msg[1];
+ len[1] = 1;
+ addr[2] = &msg[2];
+ len[2] = 1;
+ if (omac1_aes_128(key, msg, sizeof(msg), result) ||
+ omac1_aes_128_vector(key, 3, addr, len, result2) ||
+ os_memcmp(result, result2, 16) != 0) {
+ wpa_printf(MSG_ERROR, "OMAC1-AES-128 short test mismatch");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int test_omac1(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(omac1_test_vectors); i++) {
+ if (test_omac1_vector(&omac1_test_vectors[i], i))
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "OMAC1-AES-128 test cases passed");
+
+ return 0;
+}
+
+
+static int test_eax(void)
+{
+#ifdef EAP_PSK
+ u8 msg[] = { 0xF7, 0xFB };
+ u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
+ 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
+ u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
+ 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
+ u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
+ u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
+ 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
+ 0x67, 0xE5 };
+ u8 data[sizeof(msg)], tag[AES_BLOCK_SIZE];
+
+ os_memcpy(data, msg, sizeof(msg));
+ if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ wpa_printf(MSG_ERROR, "AES-128 EAX mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(data, cipher, sizeof(data)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode encryption returned invalid cipher text");
+ return 1;
+ }
+ if (os_memcmp(tag, cipher + sizeof(data), AES_BLOCK_SIZE) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode encryption returned invalid tag");
+ return 1;
+ }
+
+ if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ wpa_printf(MSG_ERROR, "AES-128 EAX mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(data, msg, sizeof(data)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "AES-128 EAX mode test cases passed");
+#endif /* EAP_PSK */
+
+ return 0;
+}
+
+
+static int test_cbc(void)
+{
+ struct cbc_test_vector {
+ u8 key[16];
+ u8 iv[16];
+ u8 plain[32];
+ u8 cipher[32];
+ size_t len;
+ } vectors[] = {
+ {
+ { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+ 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+ { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+ 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+ "Single block msg",
+ { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
+ 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
+ 16
+ },
+ {
+ { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+ 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+ { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+ 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+ { 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 },
+ { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
+ 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
+ 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
+ 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
+ 32
+ }
+ };
+ int ret = 0;
+ u8 *buf;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+ struct cbc_test_vector *tv = &vectors[i];
+
+ buf = os_malloc(tv->len);
+ if (buf == NULL) {
+ ret++;
+ break;
+ }
+
+ os_memcpy(buf, tv->plain, tv->len);
+ if (aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len) ||
+ os_memcmp(buf, tv->cipher, tv->len) != 0) {
+ wpa_printf(MSG_ERROR, "AES-CBC encrypt %d failed", i);
+ ret++;
+ }
+
+ os_memcpy(buf, tv->cipher, tv->len);
+ if (aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len) ||
+ os_memcmp(buf, tv->plain, tv->len) != 0) {
+ wpa_printf(MSG_ERROR, "AES-CBC decrypt %d failed", i);
+ ret++;
+ }
+
+ os_free(buf);
+ }
+
+ return ret;
+}
+
+
+static int test_ecb(void)
+{
+#ifdef EAP_PSK
+ struct ecb_test_vector {
+ char *key;
+ char *plaintext;
+ char *ciphertext;
+ } vectors[] = {
+ /* CAVS 11.1 - ECBGFSbox128.rsp */
+ {
+ "00000000000000000000000000000000",
+ "f34481ec3cc627bacd5dc3fb08f273e6",
+ "0336763e966d92595a567cc9ce537f5e"
+ },
+ {
+ "00000000000000000000000000000000",
+ "9798c4640bad75c7c3227db910174e72",
+ "a9a1631bf4996954ebc093957b234589"
+ },
+ {
+ "00000000000000000000000000000000",
+ "96ab5c2ff612d9dfaae8c31f30c42168",
+ "ff4f8391a6a40ca5b25d23bedd44a597"
+ },
+ {
+ "00000000000000000000000000000000",
+ "6a118a874519e64e9963798a503f1d35",
+ "dc43be40be0e53712f7e2bf5ca707209"
+ },
+ {
+ "00000000000000000000000000000000",
+ "cb9fceec81286ca3e989bd979b0cb284",
+ "92beedab1895a94faa69b632e5cc47ce"
+ },
+ {
+ "00000000000000000000000000000000",
+ "b26aeb1874e47ca8358ff22378f09144",
+ "459264f4798f6a78bacb89c15ed3d601"
+ },
+ {
+ "00000000000000000000000000000000",
+ "58c8e00b2631686d54eab84b91f0aca1",
+ "08a4e2efec8a8e3312ca7460b9040bbf"
+ },
+ /* CAVS 11.1 - ECBKeySbox128.rsp */
+ {
+ "10a58869d74be5a374cf867cfb473859",
+ "00000000000000000000000000000000",
+ "6d251e6944b051e04eaa6fb4dbf78465"
+ },
+ {
+ "caea65cdbb75e9169ecd22ebe6e54675",
+ "00000000000000000000000000000000",
+ "6e29201190152df4ee058139def610bb",
+ }
+ };
+ int ret = 0;
+ unsigned int i;
+ u8 key[16], plain[16], cipher[16], out[16];
+
+ for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+ struct ecb_test_vector *tv = &vectors[i];
+
+ if (hexstr2bin(tv->key, key, sizeof(key)) ||
+ hexstr2bin(tv->plaintext, plain, sizeof(plain)) ||
+ hexstr2bin(tv->ciphertext, cipher, sizeof(cipher))) {
+ wpa_printf(MSG_ERROR, "Invalid AES-ECB test vector %u",
+ i);
+ ret++;
+ continue;
+ }
+
+ if (aes_128_encrypt_block(key, plain, out) < 0 ||
+ os_memcmp(out, cipher, 16) != 0) {
+ wpa_printf(MSG_ERROR, "AES-ECB encrypt %u failed", i);
+ ret++;
+ }
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "AES ECB mode test cases passed");
+
+ return ret;
+#endif /* EAP_PSK */
+
+ return 0;
+}
+
+
+static int test_key_wrap(void)
+{
+ int ret = 0;
+
+ /* RFC 3394 - Test vector 4.1 */
+ u8 kek41[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ u8 plain41[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt41[] = {
+ 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
+ 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
+ 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
+ };
+ /* RFC 3394 - Test vector 4.2 */
+ u8 kek42[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+ };
+ u8 plain42[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt42[] = {
+ 0x96, 0x77, 0x8B, 0x25, 0xAE, 0x6C, 0xA4, 0x35,
+ 0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
+ 0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
+ };
+ /* RFC 3394 - Test vector 4.3 */
+ u8 kek43[] = {
+ 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
+ };
+ u8 plain43[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt43[] = {
+ 0x64, 0xE8, 0xC3, 0xF9, 0xCE, 0x0F, 0x5B, 0xA2,
+ 0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
+ 0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
+ };
+ /* RFC 3394 - Test vector 4.4 */
+ u8 kek44[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+ };
+ u8 plain44[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+ u8 crypt44[] = {
+ 0x03, 0x1D, 0x33, 0x26, 0x4E, 0x15, 0xD3, 0x32,
+ 0x68, 0xF2, 0x4E, 0xC2, 0x60, 0x74, 0x3E, 0xDC,
+ 0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
+ 0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
+ };
+ /* RFC 3394 - Test vector 4.5 */
+ u8 kek45[] = {
+ 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
+ };
+ u8 plain45[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+ u8 crypt45[] = {
+ 0xA8, 0xF9, 0xBC, 0x16, 0x12, 0xC6, 0x8B, 0x3F,
+ 0xF6, 0xE6, 0xF4, 0xFB, 0xE3, 0x0E, 0x71, 0xE4,
+ 0x76, 0x9C, 0x8B, 0x80, 0xA3, 0x2C, 0xB8, 0x95,
+ 0x8C, 0xD5, 0xD1, 0x7D, 0x6B, 0x25, 0x4D, 0xA1,
+ };
+ /* RFC 3394 - Test vector 4.6 */
+ u8 kek46[] = {
+ 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
+ };
+ u8 plain46[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+ };
+ u8 crypt46[] = {
+ 0x28, 0xC9, 0xF4, 0x04, 0xC4, 0xB8, 0x10, 0xF4,
+ 0xCB, 0xCC, 0xB3, 0x5C, 0xFB, 0x87, 0xF8, 0x26,
+ 0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26,
+ 0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99, 0xF4, 0x3B,
+ 0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21
+ };
+ u8 result[40];
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.1");
+ if (aes_wrap(kek41, sizeof(kek41), sizeof(plain41) / 8, plain41,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-128 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt41, sizeof(crypt41)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-128 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek41, sizeof(kek41), sizeof(plain41) / 8, crypt41,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-128 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain41, sizeof(plain41)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-128 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.2");
+ if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt42, sizeof(crypt42)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek42, sizeof(kek42), sizeof(plain42) / 8, crypt42,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain42, sizeof(plain42)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.3");
+ if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt43, sizeof(crypt43)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek43, sizeof(kek43), sizeof(plain43) / 8, crypt43,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain43, sizeof(plain43)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.4");
+ if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt44, sizeof(crypt44)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek44, sizeof(kek44), sizeof(plain44) / 8, crypt44,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain44, sizeof(plain44)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.5");
+ if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt45, sizeof(crypt45)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek45, sizeof(kek45), sizeof(plain45) / 8, crypt45,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain45, sizeof(plain45)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.6");
+ if (aes_wrap(kek46, sizeof(kek46), sizeof(plain46) / 8, plain46,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt46, sizeof(crypt46)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek46, sizeof(kek46), sizeof(plain46) / 8, crypt46,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain46, sizeof(plain46)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "AES key wrap/unwrap test cases passed");
+
+ return ret;
+}
+
+
+static int test_md5(void)
+{
+ struct {
+ char *data;
+ char *hash;
+ } tests[] = {
+ {
+ "",
+ "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
+ "\xe9\x80\x09\x98\xec\xf8\x42\x7e"
+ },
+ {
+ "a",
+ "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
+ "\x31\xc3\x99\xe2\x69\x77\x26\x61"
+ },
+ {
+ "abc",
+ "\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
+ "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
+ },
+ {
+ "message digest",
+ "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
+ "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"
+ },
+ {
+ "abcdefghijklmnopqrstuvwxyz",
+ "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
+ "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"
+ },
+ {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789",
+ "\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
+ "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"
+ },
+ {
+ "12345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890",
+ "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
+ "\xac\x49\xda\x2e\x21\x07\xb6\x7a"
+ }
+ };
+ unsigned int i;
+ u8 hash[16];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ wpa_printf(MSG_INFO, "MD5 test case %d", i);
+
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ if (md5_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, tests[i].hash, 16) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ addr[1] = (u8 *) tests[i].data + 1;
+ len[1] = strlen(tests[i].data) - 1;
+ if (md5_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, tests[i].hash, 16) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "MD5 test cases passed");
+
+ return errors;
+}
+
+
+static int test_eap_fast(void)
+{
+#ifdef EAP_FAST
+ /* RFC 4851, Appendix B.1 */
+ const u8 pac_key[] = {
+ 0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
+ 0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
+ 0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
+ 0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
+ };
+ const u8 seed[] = {
+ 0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
+ 0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
+ 0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
+ 0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
+ 0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
+ 0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
+ 0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
+ 0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
+ };
+ const u8 master_secret[] = {
+ 0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
+ 0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
+ 0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
+ 0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
+ 0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
+ 0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
+ };
+ const u8 key_block[] = {
+ 0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
+ 0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
+ 0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
+ 0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
+ 0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
+ 0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
+ 0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
+ 0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
+ 0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
+ 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+ 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+ 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+ 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+ 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+ };
+ const u8 sks[] = {
+ 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+ 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+ 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+ 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+ 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+ };
+ const u8 isk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const u8 imck[] = {
+ 0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
+ 0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
+ 0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
+ 0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
+ 0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
+ 0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
+ 0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
+ 0x15, 0xEC, 0x57, 0x7B
+ };
+ const u8 msk[] = {
+ 0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
+ 0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
+ 0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
+ 0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
+ 0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
+ 0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
+ 0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
+ 0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
+ };
+ const u8 emsk[] = {
+ 0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B,
+ 0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55,
+ 0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D,
+ 0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9,
+ 0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54,
+ 0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A,
+ 0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44,
+ 0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9
+ };
+ /* RFC 4851, Appendix B.2 */
+ u8 tlv[] = {
+ 0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
+ 0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
+ 0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
+ 0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
+ 0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
+ 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+ 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+ 0x05, 0xC5, 0x5B, 0xB7
+ };
+ const u8 compound_mac[] = {
+ 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+ 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+ 0x05, 0xC5, 0x5B, 0xB7
+ };
+ u8 buf[512];
+ const u8 *simck, *cmk;
+ int errors = 0;
+
+ wpa_printf(MSG_INFO, "EAP-FAST test cases");
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / master_secret");
+ if (sha1_t_prf(pac_key, sizeof(pac_key),
+ "PAC to master secret label hash",
+ seed, sizeof(seed), buf, sizeof(master_secret)) < 0 ||
+ os_memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- PRF (TLS, SHA1/MD5) test case / key_block");
+ if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
+ "key expansion", seed, sizeof(seed),
+ buf, sizeof(key_block)) ||
+ os_memcmp(key_block, buf, sizeof(key_block)) != 0) {
+ wpa_printf(MSG_INFO, "PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / IMCK");
+ if (sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
+ isk, sizeof(isk), buf, sizeof(imck)) < 0 ||
+ os_memcmp(imck, buf, sizeof(imck)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ simck = imck;
+ cmk = imck + 40;
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / MSK");
+ if (sha1_t_prf(simck, 40, "Session Key Generating Function",
+ (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+ os_memcmp(msk, buf, sizeof(msk)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / EMSK");
+ if (sha1_t_prf(simck, 40, "Extended Session Key Generating Function",
+ (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+ os_memcmp(emsk, buf, sizeof(emsk)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- Compound MAC test case");
+ os_memset(tlv + sizeof(tlv) - 20, 0, 20);
+ if (hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20) < 0 ||
+ os_memcmp(tlv + sizeof(tlv) - 20, compound_mac,
+ sizeof(compound_mac)) != 0) {
+ wpa_printf(MSG_INFO, "Compound MAC test - FAILED!");
+ errors++;
+ }
+
+ return errors;
+#else /* EAP_FAST */
+ return 0;
+#endif /* EAP_FAST */
+}
+
+
+static u8 key0[] =
+{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+};
+static u8 data0[] = "Hi There";
+static u8 prf0[] =
+{
+ 0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
+ 0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
+ 0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
+ 0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
+ 0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
+ 0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
+ 0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
+ 0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
+};
+
+static u8 key1[] = "Jefe";
+static u8 data1[] = "what do ya want for nothing?";
+static u8 prf1[] =
+{
+ 0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
+ 0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
+ 0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
+ 0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
+ 0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
+ 0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
+ 0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
+ 0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
+};
+
+
+static u8 key2[] =
+{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+};
+static u8 data2[] =
+{
+ 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
+};
+static u8 prf2[] =
+{
+ 0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
+ 0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
+ 0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
+ 0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
+ 0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
+ 0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
+ 0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
+ 0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
+};
+
+
+struct passphrase_test {
+ char *passphrase;
+ char *ssid;
+ char psk[32];
+};
+
+static struct passphrase_test passphrase_tests[] =
+{
+ {
+ "password",
+ "IEEE",
+ {
+ 0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
+ 0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
+ 0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
+ 0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
+ }
+ },
+ {
+ "ThisIsAPassword",
+ "ThisIsASSID",
+ {
+ 0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
+ 0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
+ 0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
+ 0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
+ }
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+ {
+ 0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
+ 0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
+ 0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
+ 0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
+ }
+ },
+};
+
+#define NUM_PASSPHRASE_TESTS ARRAY_SIZE(passphrase_tests)
+
+
+struct rfc6070_test {
+ char *p;
+ char *s;
+ int c;
+ char dk[32];
+ size_t dk_len;
+};
+
+static struct rfc6070_test rfc6070_tests[] =
+{
+ {
+ "password",
+ "salt",
+ 1,
+ {
+ 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+ 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+ 0x2f, 0xe0, 0x37, 0xa6
+ },
+ 20
+ },
+ {
+ "password",
+ "salt",
+ 2,
+ {
+ 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+ 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+ 0xd8, 0xde, 0x89, 0x57
+ },
+ 20
+ },
+ {
+ "password",
+ "salt",
+ 4096,
+ {
+ 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+ 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+ 0x65, 0xa4, 0x29, 0xc1
+ },
+ 20
+ },
+#if 0 /* This takes quite long to derive.. */
+ {
+ "password",
+ "salt",
+ 16777216,
+ {
+ 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
+ 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
+ 0x26, 0x34, 0xe9, 0x84
+ },
+ 20
+ },
+#endif
+ {
+ "passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ 4096,
+ {
+ 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+ 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+ 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+ 0x38
+ },
+ 25
+ },
+#if 0 /* \0 not currently supported in passphrase parameters.. */
+ {
+ "pass\0word",
+ "sa\0lt",
+ 4096,
+ {
+ 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+ 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3
+ },
+ 16
+ },
+#endif
+};
+
+#define NUM_RFC6070_TESTS ARRAY_SIZE(rfc6070_tests)
+
+
+static int test_sha1(void)
+{
+ u8 res[512];
+ int ret = 0;
+ unsigned int i;
+
+ wpa_printf(MSG_INFO, "PRF-SHA1 test cases:");
+
+ if (sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
+ res, sizeof(prf0)) == 0 &&
+ os_memcmp(res, prf0, sizeof(prf0)) == 0)
+ wpa_printf(MSG_INFO, "Test case 0 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 0 - FAILED!");
+ ret++;
+ }
+
+ if (sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
+ res, sizeof(prf1)) == 0 &&
+ os_memcmp(res, prf1, sizeof(prf1)) == 0)
+ wpa_printf(MSG_INFO, "Test case 1 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 1 - FAILED!");
+ ret++;
+ }
+
+ if (sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
+ res, sizeof(prf2)) == 0 &&
+ os_memcmp(res, prf2, sizeof(prf2)) == 0)
+ wpa_printf(MSG_INFO, "Test case 2 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 2 - FAILED!");
+ ret++;
+ }
+
+ ret += test_eap_fast();
+
+ wpa_printf(MSG_INFO, "PBKDF2-SHA1 Passphrase test cases:");
+ for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
+ u8 psk[32];
+ struct passphrase_test *test = &passphrase_tests[i];
+
+ if (pbkdf2_sha1(test->passphrase,
+ (const u8 *) test->ssid, strlen(test->ssid),
+ 4096, psk, 32) == 0 &&
+ os_memcmp(psk, test->psk, 32) == 0)
+ wpa_printf(MSG_INFO, "Test case %d - OK", i);
+ else {
+ wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+ ret++;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "PBKDF2-SHA1 test cases (RFC 6070):");
+ for (i = 0; i < NUM_RFC6070_TESTS; i++) {
+ u8 dk[25];
+ struct rfc6070_test *test = &rfc6070_tests[i];
+
+ if (pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
+ test->c, dk, test->dk_len) == 0 &&
+ os_memcmp(dk, test->dk, test->dk_len) == 0)
+ wpa_printf(MSG_INFO, "Test case %d - OK", i);
+ else {
+ wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+ ret++;
+ }
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "SHA1 test cases passed");
+ return ret;
+}
+
+
+struct {
+ char *data;
+ u8 hash[32];
+} tests[] = {
+ {
+ "abc",
+ {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+ }
+ },
+ {
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ {
+ 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
+ }
+ }
+};
+
+struct hmac_test {
+ u8 key[80];
+ size_t key_len;
+ u8 data[128];
+ size_t data_len;
+ u8 hash[32];
+} hmac_tests[] = {
+ /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+ {
+ {
+ 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
+ },
+ 32,
+ "abc", 3,
+ {
+ 0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a,
+ 0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
+ 0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
+ 0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
+ }
+ },
+ {
+ {
+ 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
+ },
+ 32,
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ 56,
+ {
+ 0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08,
+ 0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
+ 0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
+ 0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
+ }
+ },
+ {
+ {
+ 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
+ },
+ 32,
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ 112,
+ {
+ 0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34,
+ 0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
+ 0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
+ 0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
+ }
+ },
+ {
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ },
+ 32,
+ "Hi There",
+ 8,
+ {
+ 0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6,
+ 0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
+ 0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
+ 0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+ }
+ },
+ {
+ "Jefe",
+ 4,
+ "what do ya want for nothing?",
+ 28,
+ {
+ 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+ 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+ 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+ 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ }
+ },
+ {
+ {
+ 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
+ },
+ 32,
+ {
+ 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,
+ {
+ 0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea,
+ 0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
+ 0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
+ 0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+ }
+ },
+ {
+ {
+ 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
+ },
+ 37,
+ {
+ 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,
+ {
+ 0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74,
+ 0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
+ 0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
+ 0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+ }
+ },
+ {
+ {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+ },
+ 32,
+ "Test With Truncation",
+ 20,
+ {
+ 0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b,
+ 0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
+ 0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
+ 0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
+ }
+ },
+ {
+ {
+ 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
+ },
+ 80,
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ 54,
+ {
+ 0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09,
+ 0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
+ 0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
+ 0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+ }
+ },
+ {
+ {
+ 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
+ },
+ 80,
+ "Test Using Larger Than Block-Size Key and Larger Than One "
+ "Block-Size Data",
+ 73,
+ {
+ 0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3,
+ 0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
+ 0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
+ 0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+ }
+ }
+};
+
+
+static int test_sha256(void)
+{
+ unsigned int i;
+ u8 hash[32];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ wpa_printf(MSG_INFO, "SHA256 test case %d:", i + 1);
+
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ sha256_vector(1, addr, len, hash);
+ if (memcmp(hash, tests[i].hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = 1;
+ addr[1] = (u8 *) tests[i].data + 1;
+ len[1] = strlen(tests[i].data) - 1;
+ sha256_vector(2, addr, len, hash);
+ if (memcmp(hash, tests[i].hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+ struct hmac_test *t = &hmac_tests[i];
+
+ wpa_printf(MSG_INFO, "HMAC-SHA256 test case %d:", i + 1);
+
+ if (hmac_sha256(t->key, t->key_len, t->data, t->data_len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ addr[0] = t->data;
+ len[0] = t->data_len;
+ if (hmac_sha256_vector(t->key, t->key_len, 1, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 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_sha256_vector(t->key, t->key_len, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Test IEEE 802.11r KDF");
+ sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4,
+ hash, sizeof(hash));
+ /* TODO: add proper test case for this */
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "SHA256 test cases passed");
+ return errors;
+}
+
+
+static int test_ms_funcs(void)
+{
+ /* Test vector from RFC2759 example */
+ char *username = "User";
+ char *password = "clientPass";
+ u8 auth_challenge[] = {
+ 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
+ 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
+ };
+ u8 peer_challenge[] = {
+ 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
+ 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
+ };
+ u8 password_hash[] = {
+ 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
+ 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
+ };
+ u8 nt_response[] = {
+ 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
+ 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
+ 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
+ };
+ u8 password_hash_hash[] = {
+ 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
+ 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
+ };
+ u8 authenticator_response[] = {
+ 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
+ 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
+ 0x93, 0x2C, 0xDA, 0x56
+ };
+ u8 master_key[] = {
+ 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
+ 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
+ };
+ u8 send_start_key[] = {
+ 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
+ 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
+ };
+ u8 buf[32];
+ int errors = 0;
+
+ if (nt_password_hash((u8 *) password, os_strlen(password), buf) ||
+ os_memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
+ wpa_printf(MSG_ERROR, "nt_password_hash failed");
+ errors++;
+ }
+
+ if (generate_nt_response(auth_challenge, peer_challenge,
+ (u8 *) username, os_strlen(username),
+ (u8 *) password, os_strlen(password), buf) ||
+ os_memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
+ wpa_printf(MSG_ERROR, "generate_nt_response failed");
+ errors++;
+ }
+
+ if (hash_nt_password_hash(password_hash, buf) ||
+ os_memcmp(password_hash_hash, buf,
+ sizeof(password_hash_hash)) != 0) {
+ wpa_printf(MSG_ERROR, "hash_nt_password_hash failed");
+ errors++;
+ }
+
+ if (generate_authenticator_response((u8 *) password,
+ os_strlen(password),
+ peer_challenge, auth_challenge,
+ (u8 *) username,
+ os_strlen(username),
+ nt_response, buf) ||
+ os_memcmp(authenticator_response, buf,
+ sizeof(authenticator_response)) != 0) {
+ wpa_printf(MSG_ERROR, "generate_authenticator_response failed");
+ errors++;
+ }
+
+ if (get_master_key(password_hash_hash, nt_response, buf) ||
+ os_memcmp(master_key, buf, sizeof(master_key)) != 0) {
+ wpa_printf(MSG_ERROR, "get_master_key failed");
+ errors++;
+ }
+
+ if (get_asymetric_start_key(master_key, buf, sizeof(send_start_key),
+ 1, 1) ||
+ os_memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
+ wpa_printf(MSG_ERROR, "get_asymetric_start_key failed");
+ errors++;
+ }
+
+ if (errors)
+ wpa_printf(MSG_ERROR, "ms_funcs: %d errors", errors);
+ else
+ wpa_printf(MSG_INFO, "ms_funcs test cases passed");
+
+ return errors;
+}
+
+
+int crypto_module_tests(void)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "crypto module tests");
+ if (test_siv() ||
+ test_omac1() ||
+ test_eax() ||
+ test_cbc() ||
+ test_ecb() ||
+ test_key_wrap() ||
+ test_md5() ||
+ test_sha1() ||
+ test_sha256() ||
+ test_ms_funcs())
+ ret = -1;
+
+ return ret;
+}
diff --git a/contrib/wpa/src/crypto/crypto_nss.c b/contrib/wpa/src/crypto/crypto_nss.c
deleted file mode 100644
index acd0a55..0000000
--- a/contrib/wpa/src/crypto/crypto_nss.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Crypto wrapper functions for NSS
- * 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 "includes.h"
-#include <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prtime.h>
-#include <nspr/prinrval.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nss/sechash.h>
-#include <nss/pk11pub.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-static int nss_hash(HASH_HashType type, unsigned int max_res_len,
- size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *mac)
-{
- HASHContext *ctx;
- size_t i;
- unsigned int reslen;
-
- ctx = HASH_Create(type);
- if (ctx == NULL)
- return -1;
-
- HASH_Begin(ctx);
- for (i = 0; i < num_elem; i++)
- HASH_Update(ctx, addr[i], len[i]);
- HASH_End(ctx, mac, &reslen, max_res_len);
- HASH_Destroy(ctx);
-
- return 0;
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
- PK11Context *ctx = NULL;
- PK11SlotInfo *slot;
- SECItem *param = NULL;
- PK11SymKey *symkey = NULL;
- SECItem item;
- int olen;
- u8 pkey[8], next, tmp;
- int i;
-
- /* Add parity bits to the key */
- next = 0;
- for (i = 0; i < 7; i++) {
- tmp = key[i];
- pkey[i] = (tmp >> i) | next | 1;
- next = tmp << (7 - i);
- }
- pkey[i] = next | 1;
-
- slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
- if (slot == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
- goto out;
- }
-
- item.type = siBuffer;
- item.data = pkey;
- item.len = 8;
- symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
- CKA_ENCRYPT, &item, NULL);
- if (symkey == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
- goto out;
- }
-
- param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
- if (param == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
- goto out;
- }
-
- ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
- symkey, param);
- if (ctx == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
- "CKM_DES_ECB) failed");
- goto out;
- }
-
- if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
- SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
- goto out;
- }
-
-out:
- if (ctx)
- PK11_DestroyContext(ctx, PR_TRUE);
- if (symkey)
- PK11_FreeSymKey(symkey);
- if (param)
- SECITEM_FreeItem(param, PR_TRUE);
-}
-
-
-int rc4_skip(const u8 *key, size_t keylen, size_t skip,
- u8 *data, size_t data_len)
-{
- return -1;
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
-}
-
-
-int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *mac)
-{
- return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
-}
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
- return NULL;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
- return NULL;
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
- const u8 *power, size_t power_len,
- const u8 *modulus, size_t modulus_len,
- u8 *result, size_t *result_len)
-{
- return -1;
-}
-
-
-struct crypto_cipher {
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
- const u8 *iv, const u8 *key,
- size_t key_len)
-{
- return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
- u8 *crypt, size_t len)
-{
- return -1;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
- u8 *plain, size_t len)
-{
- return -1;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-}
diff --git a/contrib/wpa/src/crypto/crypto_openssl.c b/contrib/wpa/src/crypto/crypto_openssl.c
index 711e312..f158ef4 100644
--- a/contrib/wpa/src/crypto/crypto_openssl.c
+++ b/contrib/wpa/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Wrapper functions for OpenSSL libcrypto
+ * 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.
@@ -19,23 +19,21 @@
#ifdef CONFIG_OPENSSL_CMAC
#include <openssl/cmac.h>
#endif /* CONFIG_OPENSSL_CMAC */
+#ifdef CONFIG_ECC
+#include <openssl/ec.h>
+#endif /* CONFIG_ECC */
#include "common.h"
#include "wpabuf.h"
#include "dh_group5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
#include "crypto.h"
-#if OPENSSL_VERSION_NUMBER < 0x00907000
-#define DES_key_schedule des_key_schedule
-#define DES_cblock des_cblock
-#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
-#define DES_ecb_encrypt(input, output, ks, enc) \
- des_ecb_encrypt((input), (output), *(ks), (enc))
-#endif /* openssl < 0.9.7 */
-
static BIGNUM * get_group5_prime(void)
{
-#if OPENSSL_VERSION_NUMBER < 0x00908000
+#ifdef OPENSSL_IS_BORINGSSL
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,
@@ -55,20 +53,11 @@ 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 < 0.9.8 */
+#else /* OPENSSL_IS_BORINGSSL */
return get_rfc3526_prime_1536(NULL);
-#endif /* openssl < 0.9.8 */
+#endif /* OPENSSL_IS_BORINGSSL */
}
-#if OPENSSL_VERSION_NUMBER < 0x00908000
-#ifndef OPENSSL_NO_SHA256
-#ifndef OPENSSL_FIPS
-#define NO_SHA256_WRAPPER
-#endif
-#endif
-
-#endif /* openssl < 0.9.8 */
-
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
#endif
@@ -125,7 +114,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
}
pkey[i] = next | 1;
- DES_set_key(&pkey, &ks);
+ DES_set_key((DES_cblock *) &pkey, &ks);
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
}
@@ -194,8 +183,10 @@ 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();
}
@@ -251,7 +242,7 @@ void aes_encrypt_deinit(void *ctx)
"in AES encrypt", len);
}
EVP_CIPHER_CTX_cleanup(c);
- os_free(c);
+ bin_clear_free(c, sizeof(*c));
}
@@ -302,7 +293,34 @@ void aes_decrypt_deinit(void *ctx)
"in AES decrypt", len);
}
EVP_CIPHER_CTX_cleanup(c);
- os_free(ctx);
+ bin_clear_free(c, sizeof(*c));
+}
+
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+ AES_KEY actx;
+ int res;
+
+ if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
+ return -1;
+ res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+ return res <= 0 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
+{
+ AES_KEY actx;
+ int res;
+
+ if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
+ return -1;
+ res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+ return res <= 0 ? -1 : 0;
}
@@ -335,10 +353,10 @@ int crypto_mod_exp(const u8 *base, size_t base_len,
ret = 0;
error:
- BN_free(bn_base);
- BN_free(bn_exp);
- BN_free(bn_modulus);
- BN_free(bn_result);
+ BN_clear_free(bn_base);
+ BN_clear_free(bn_exp);
+ BN_clear_free(bn_modulus);
+ BN_clear_free(bn_result);
BN_CTX_free(ctx);
return ret;
}
@@ -373,9 +391,11 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
case 16:
cipher = EVP_aes_128_cbc();
break;
+#ifndef OPENSSL_IS_BORINGSSL
case 24:
cipher = EVP_aes_192_cbc();
break;
+#endif /* OPENSSL_IS_BORINGSSL */
case 32:
cipher = EVP_aes_256_cbc();
break;
@@ -498,8 +518,8 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
return dh;
err:
- wpabuf_free(pubkey);
- wpabuf_free(privkey);
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
}
@@ -566,13 +586,13 @@ struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
if (keylen < 0)
goto err;
wpabuf_put(res, keylen);
- BN_free(pub_key);
+ BN_clear_free(pub_key);
return res;
err:
- BN_free(pub_key);
- wpabuf_free(res);
+ BN_clear_free(pub_key);
+ wpabuf_clear_free(res);
return NULL;
}
@@ -629,7 +649,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
#else /* openssl < 0.9.9 */
if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
return NULL;
}
#endif /* openssl < 0.9.9 */
@@ -655,7 +675,7 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
return -2;
if (mac == NULL || len == NULL) {
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
return 0;
}
@@ -667,7 +687,7 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
res = HMAC_Final(&ctx->ctx, mac, &mdlen);
#endif /* openssl < 0.9.9 */
HMAC_CTX_cleanup(&ctx->ctx);
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
if (res == 1) {
*len = mdlen;
@@ -678,43 +698,26 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
}
-int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
- int iterations, u8 *buf, size_t buflen)
-{
-#if OPENSSL_VERSION_NUMBER < 0x00908000
- if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
- (unsigned char *) ssid,
- ssid_len, 4096, buflen, buf) != 1)
- return -1;
-#else /* openssl < 0.9.8 */
- if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
- ssid_len, 4096, buflen, buf) != 1)
- return -1;
-#endif /* openssl < 0.9.8 */
- return 0;
-}
-
-
-int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+static int openssl_hmac_vector(const EVP_MD *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_CTX ctx;
size_t i;
- unsigned int mdlen;
int res;
HMAC_CTX_init(&ctx);
#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL);
+ HMAC_Init_ex(&ctx, key, key_len, type, NULL);
#else /* openssl < 0.9.9 */
- if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+ if (HMAC_Init_ex(&ctx, key, key_len, type, NULL) != 1)
return -1;
#endif /* openssl < 0.9.9 */
for (i = 0; i < num_elem; i++)
HMAC_Update(&ctx, addr[i], len[i]);
- mdlen = 20;
#if OPENSSL_VERSION_NUMBER < 0x00909000
HMAC_Final(&ctx, mac, &mdlen);
res = 1;
@@ -727,6 +730,43 @@ int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
}
+#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 openssl_hmac_vector(EVP_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 pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+ ssid_len, iterations, buflen, buf) != 1)
+ return -1;
+ return 0;
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector(EVP_sha1(), 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)
{
@@ -739,42 +779,37 @@ int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
- HMAC_CTX ctx;
- size_t i;
- unsigned int mdlen;
- int res;
+ return openssl_hmac_vector(EVP_sha256(), key, key_len, num_elem, addr,
+ len, mac, 32);
+}
- HMAC_CTX_init(&ctx);
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL);
-#else /* openssl < 0.9.9 */
- if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1)
- return -1;
-#endif /* openssl < 0.9.9 */
- for (i = 0; i < num_elem; i++)
- HMAC_Update(&ctx, addr[i], len[i]);
+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);
+}
- mdlen = 32;
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Final(&ctx, mac, &mdlen);
- res = 1;
-#else /* openssl < 0.9.9 */
- res = HMAC_Final(&ctx, mac, &mdlen);
-#endif /* openssl < 0.9.9 */
- HMAC_CTX_cleanup(&ctx);
+#endif /* CONFIG_SHA256 */
- return res == 1 ? 0 : -1;
+
+#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 openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
+ len, mac, 32);
}
-int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+int hmac_sha384(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);
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
}
-#endif /* CONFIG_SHA256 */
+#endif /* CONFIG_SHA384 */
int crypto_get_random(void *buf, size_t len)
@@ -786,8 +821,8 @@ int crypto_get_random(void *buf, size_t len)
#ifdef CONFIG_OPENSSL_CMAC
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+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_CTX *ctx;
int ret = -1;
@@ -797,8 +832,15 @@ int omac1_aes_128_vector(const u8 *key, size_t num_elem,
if (ctx == NULL)
return -1;
- if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ if (key_len == 32) {
+ if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
+ goto fail;
+ } else if (key_len == 16) {
+ if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ goto fail;
+ } else {
goto fail;
+ }
for (i = 0; i < num_elem; i++) {
if (!CMAC_Update(ctx, addr[i], len[i]))
goto fail;
@@ -813,8 +855,425 @@ fail:
}
+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);
+}
#endif /* CONFIG_OPENSSL_CMAC */
+
+
+struct crypto_bignum * crypto_bignum_init(void)
+{
+ return (struct crypto_bignum *) BN_new();
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+ BIGNUM *bn = BN_bin2bn(buf, len, NULL);
+ return (struct crypto_bignum *) bn;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+ if (clear)
+ BN_clear_free((BIGNUM *) n);
+ else
+ BN_free((BIGNUM *) n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen)
+{
+ int num_bytes, offset;
+
+ if (padlen > buflen)
+ return -1;
+
+ num_bytes = BN_num_bytes((const BIGNUM *) a);
+ if ((size_t) num_bytes > buflen)
+ return -1;
+ if (padlen > (size_t) num_bytes)
+ offset = padlen - num_bytes;
+ else
+ offset = 0;
+
+ os_memset(buf, 0, offset);
+ BN_bn2bin((const BIGNUM *) a, buf + offset);
+
+ return num_bytes + offset;
+}
+
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ return BN_add((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
+ 0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
+ bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ BIGNUM *res;
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
+ (const BIGNUM *) b, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
+ 0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
+ (const BIGNUM *) b, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod_mul((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+ const struct crypto_bignum *b)
+{
+ return BN_cmp((const BIGNUM *) a, (const BIGNUM *) b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+ return BN_num_bits((const BIGNUM *) a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+ return BN_is_zero((const BIGNUM *) a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+ return BN_is_one((const BIGNUM *) a);
+}
+
+
+#ifdef CONFIG_ECC
+
+struct crypto_ec {
+ EC_GROUP *group;
+ BN_CTX *bnctx;
+ BIGNUM *prime;
+ BIGNUM *order;
+};
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+ struct crypto_ec *e;
+ int nid;
+
+ /* Map from IANA registry for IKE D-H groups to OpenSSL NID */
+ switch (group) {
+ case 19:
+ nid = NID_X9_62_prime256v1;
+ break;
+ case 20:
+ nid = NID_secp384r1;
+ break;
+ case 21:
+ nid = NID_secp521r1;
+ break;
+ case 25:
+ nid = NID_X9_62_prime192v1;
+ break;
+ case 26:
+ nid = NID_secp224r1;
+ break;
+ default:
+ return NULL;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return NULL;
+
+ e->bnctx = BN_CTX_new();
+ e->group = EC_GROUP_new_by_curve_name(nid);
+ e->prime = BN_new();
+ e->order = BN_new();
+ if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
+ e->order == NULL ||
+ !EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) ||
+ !EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
+ crypto_ec_deinit(e);
+ e = NULL;
+ }
+
+ return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec *e)
+{
+ if (e == NULL)
+ return;
+ BN_clear_free(e->order);
+ BN_clear_free(e->prime);
+ EC_GROUP_free(e->group);
+ BN_CTX_free(e->bnctx);
+ os_free(e);
+}
+
+
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
+{
+ if (e == NULL)
+ return NULL;
+ return (struct crypto_ec_point *) EC_POINT_new(e->group);
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+ return BN_num_bytes(e->prime);
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+ return BN_num_bits(e->prime);
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+ if (clear)
+ EC_POINT_clear_free((EC_POINT *) p);
+ else
+ EC_POINT_free((EC_POINT *) p);
+}
+
+
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+ BIGNUM *x_bn, *y_bn;
+ int ret = -1;
+ int len = BN_num_bytes(e->prime);
+
+ x_bn = BN_new();
+ y_bn = BN_new();
+
+ if (x_bn && y_bn &&
+ EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point,
+ x_bn, y_bn, e->bnctx)) {
+ if (x) {
+ crypto_bignum_to_bin((struct crypto_bignum *) x_bn,
+ x, len, len);
+ }
+ if (y) {
+ crypto_bignum_to_bin((struct crypto_bignum *) y_bn,
+ y, len, len);
+ }
+ ret = 0;
+ }
+
+ BN_clear_free(x_bn);
+ BN_clear_free(y_bn);
+ return ret;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val)
+{
+ BIGNUM *x, *y;
+ EC_POINT *elem;
+ int len = BN_num_bytes(e->prime);
+
+ x = BN_bin2bn(val, len, NULL);
+ y = BN_bin2bn(val + len, len, NULL);
+ elem = EC_POINT_new(e->group);
+ if (x == NULL || y == NULL || elem == NULL) {
+ BN_clear_free(x);
+ BN_clear_free(y);
+ EC_POINT_clear_free(elem);
+ return NULL;
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
+ e->bnctx)) {
+ EC_POINT_clear_free(elem);
+ elem = NULL;
+ }
+
+ BN_clear_free(x);
+ BN_clear_free(y);
+
+ return (struct crypto_ec_point *) elem;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c)
+{
+ return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a,
+ (const EC_POINT *) b, e->bnctx) ? 0 : -1;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res)
+{
+ return EC_POINT_mul(e->group, (EC_POINT *) res, NULL,
+ (const EC_POINT *) p, (const BIGNUM *) b, e->bnctx)
+ ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+ return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+ struct crypto_ec_point *p,
+ const struct crypto_bignum *x, int y_bit)
+{
+ if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p,
+ (const BIGNUM *) x, y_bit,
+ e->bnctx) ||
+ !EC_POINT_is_on_curve(e->group, (EC_POINT *) p, e->bnctx))
+ return -1;
+ return 0;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return EC_POINT_is_at_infinity(e->group, (const EC_POINT *) p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p, e->bnctx);
+}
+
+#endif /* CONFIG_ECC */
diff --git a/contrib/wpa/src/crypto/dh_groups.c b/contrib/wpa/src/crypto/dh_groups.c
index f757b6b..d3b2631 100644
--- a/contrib/wpa/src/crypto/dh_groups.c
+++ b/contrib/wpa/src/crypto/dh_groups.c
@@ -35,6 +35,20 @@ static const u8 dh_group1_prime[96] = {
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group1_order[96] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1D, 0x1B, 0x10,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 4306, B.2. Group 2 - 1024 Bit MODP
* Generator: 2
@@ -59,6 +73,24 @@ static const u8 dh_group2_prime[128] = {
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group2_order[128] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
#endif /* ALL_DH_GROUPS */
@@ -93,6 +125,32 @@ static const u8 dh_group5_prime[192] = {
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group5_order[192] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x11, 0xB9, 0x93,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
#ifdef ALL_DH_GROUPS
@@ -135,6 +193,40 @@ static const u8 dh_group14_prime[256] = {
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group14_order[256] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x56, 0x55, 0x34,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 4. Group 15 - 3072 Bit MODP
* Generator: 2
@@ -191,6 +283,56 @@ static const u8 dh_group15_prime[384] = {
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group15_order[384] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x9D, 0x69, 0x65,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 5. Group 16 - 4096 Bit MODP
* Generator: 2
@@ -263,6 +405,72 @@ static const u8 dh_group16_prime[512] = {
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group16_order[512] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+ 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+ 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+ 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+ 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+ 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+ 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+ 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+ 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+ 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+ 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+ 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+ 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+ 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+ 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+ 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+ 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x03, 0x18, 0xCC,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 6. Group 17 - 6144 Bit MODP
* Generator: 2
@@ -367,6 +575,104 @@ static const u8 dh_group17_prime[768] = {
0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group17_order[768] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+ 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+ 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+ 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+ 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+ 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+ 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+ 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+ 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+ 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+ 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+ 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+ 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+ 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+ 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+ 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+ 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
+ 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13,
+ 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F,
+ 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE,
+ 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87,
+ 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7,
+ 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18,
+ 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
+ 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76,
+ 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D,
+ 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5,
+ 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1,
+ 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F,
+ 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76,
+ 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
+ 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B,
+ 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41,
+ 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F,
+ 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79,
+ 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F,
+ 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62,
+ 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
+ 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC,
+ 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0,
+ 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94,
+ 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B,
+ 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8,
+ 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE,
+ 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
+ 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34,
+ 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77,
+ 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B,
+ 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xE6, 0x20, 0x12,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 7. Group 18 - 8192 Bit MODP
* Generator: 2
@@ -503,29 +809,367 @@ static const u8 dh_group18_prime[1024] = {
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group18_order[1024] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+ 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+ 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+ 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+ 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+ 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+ 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+ 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+ 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+ 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+ 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+ 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+ 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+ 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+ 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+ 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+ 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
+ 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13,
+ 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F,
+ 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE,
+ 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87,
+ 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7,
+ 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18,
+ 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
+ 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76,
+ 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D,
+ 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5,
+ 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1,
+ 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F,
+ 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76,
+ 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
+ 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B,
+ 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41,
+ 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F,
+ 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79,
+ 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F,
+ 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62,
+ 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
+ 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC,
+ 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0,
+ 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94,
+ 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B,
+ 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8,
+ 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE,
+ 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
+ 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34,
+ 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77,
+ 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B,
+ 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xDF, 0x08, 0xAC,
+ 0xBA, 0x51, 0xC9, 0x37, 0x89, 0x7F, 0x72, 0xF2,
+ 0x1C, 0x3B, 0xBE, 0x5B, 0x54, 0x99, 0x6F, 0xC6,
+ 0x6C, 0x5F, 0x62, 0x68, 0x39, 0xDC, 0x98, 0xDD,
+ 0x1D, 0xE4, 0x19, 0x5B, 0x46, 0xCE, 0xE9, 0x80,
+ 0x3A, 0x0F, 0xD3, 0xDF, 0xC5, 0x7E, 0x23, 0xF6,
+ 0x92, 0xBB, 0x7B, 0x49, 0xB5, 0xD2, 0x12, 0x33,
+ 0x1D, 0x55, 0xB1, 0xCE, 0x2D, 0x72, 0x7A, 0xB4,
+ 0x1A, 0x11, 0xDA, 0x3A, 0x15, 0xF8, 0xE4, 0xBC,
+ 0x11, 0xC7, 0x8B, 0x65, 0xF1, 0xCE, 0xB2, 0x96,
+ 0xF1, 0xFE, 0xDC, 0x5F, 0x7E, 0x42, 0x45, 0x6C,
+ 0x91, 0x11, 0x17, 0x02, 0x52, 0x01, 0xBE, 0x03,
+ 0x89, 0xF5, 0xAB, 0xD4, 0x0D, 0x11, 0xF8, 0x63,
+ 0x9A, 0x39, 0xFE, 0x32, 0x36, 0x75, 0x18, 0x35,
+ 0xA5, 0xE5, 0xE4, 0x43, 0x17, 0xC1, 0xC2, 0xEE,
+ 0xFD, 0x4E, 0xA5, 0xBF, 0xD1, 0x60, 0x43, 0xF4,
+ 0x3C, 0xB4, 0x19, 0x81, 0xF6, 0xAD, 0xEE, 0x9D,
+ 0x03, 0x15, 0x9E, 0x7A, 0xD9, 0xD1, 0x3C, 0x53,
+ 0x36, 0x95, 0x09, 0xFC, 0x1F, 0xA2, 0x7C, 0x16,
+ 0xEF, 0x98, 0x87, 0x70, 0x3A, 0x55, 0xB5, 0x1B,
+ 0x22, 0xCB, 0xF4, 0x4C, 0xD0, 0x12, 0xAE, 0xE0,
+ 0xB2, 0x79, 0x8E, 0x62, 0x84, 0x23, 0x42, 0x8E,
+ 0xFC, 0xD5, 0xA4, 0x0C, 0xAE, 0xF6, 0xBF, 0x50,
+ 0xD8, 0xEA, 0x88, 0x5E, 0xBF, 0x73, 0xA6, 0xB9,
+ 0xFD, 0x79, 0xB5, 0xE1, 0x8F, 0x67, 0xD1, 0x34,
+ 0x1A, 0xC8, 0x23, 0x7A, 0x75, 0xC3, 0xCF, 0xC9,
+ 0x20, 0x04, 0xA1, 0xC5, 0xA4, 0x0E, 0x36, 0x6B,
+ 0xC4, 0x4D, 0x00, 0x17, 0x6A, 0xF7, 0x1C, 0x15,
+ 0xE4, 0x8C, 0x86, 0xD3, 0x7E, 0x01, 0x37, 0x23,
+ 0xCA, 0xAC, 0x72, 0x23, 0xAB, 0x3B, 0xF4, 0xD5,
+ 0x4F, 0x18, 0x28, 0x71, 0x3B, 0x2B, 0x4A, 0x6F,
+ 0xE4, 0x0F, 0xAB, 0x74, 0x40, 0x5C, 0xB7, 0x38,
+ 0xB0, 0x64, 0xC0, 0x6E, 0xCC, 0x76, 0xE9, 0xEF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/*
+ * RFC 5114, 2.1.
+ * Group 22 - 1024-bit MODP Group with 160-bit Prime Order Subgroup
+ */
+static const u8 dh_group22_generator[] = {
+ 0xA4, 0xD1, 0xCB, 0xD5, 0xC3, 0xFD, 0x34, 0x12,
+ 0x67, 0x65, 0xA4, 0x42, 0xEF, 0xB9, 0x99, 0x05,
+ 0xF8, 0x10, 0x4D, 0xD2, 0x58, 0xAC, 0x50, 0x7F,
+ 0xD6, 0x40, 0x6C, 0xFF, 0x14, 0x26, 0x6D, 0x31,
+ 0x26, 0x6F, 0xEA, 0x1E, 0x5C, 0x41, 0x56, 0x4B,
+ 0x77, 0x7E, 0x69, 0x0F, 0x55, 0x04, 0xF2, 0x13,
+ 0x16, 0x02, 0x17, 0xB4, 0xB0, 0x1B, 0x88, 0x6A,
+ 0x5E, 0x91, 0x54, 0x7F, 0x9E, 0x27, 0x49, 0xF4,
+ 0xD7, 0xFB, 0xD7, 0xD3, 0xB9, 0xA9, 0x2E, 0xE1,
+ 0x90, 0x9D, 0x0D, 0x22, 0x63, 0xF8, 0x0A, 0x76,
+ 0xA6, 0xA2, 0x4C, 0x08, 0x7A, 0x09, 0x1F, 0x53,
+ 0x1D, 0xBF, 0x0A, 0x01, 0x69, 0xB6, 0xA2, 0x8A,
+ 0xD6, 0x62, 0xA4, 0xD1, 0x8E, 0x73, 0xAF, 0xA3,
+ 0x2D, 0x77, 0x9D, 0x59, 0x18, 0xD0, 0x8B, 0xC8,
+ 0x85, 0x8F, 0x4D, 0xCE, 0xF9, 0x7C, 0x2A, 0x24,
+ 0x85, 0x5E, 0x6E, 0xEB, 0x22, 0xB3, 0xB2, 0xE5
+};
+static const u8 dh_group22_prime[] = {
+ 0xB1, 0x0B, 0x8F, 0x96, 0xA0, 0x80, 0xE0, 0x1D,
+ 0xDE, 0x92, 0xDE, 0x5E, 0xAE, 0x5D, 0x54, 0xEC,
+ 0x52, 0xC9, 0x9F, 0xBC, 0xFB, 0x06, 0xA3, 0xC6,
+ 0x9A, 0x6A, 0x9D, 0xCA, 0x52, 0xD2, 0x3B, 0x61,
+ 0x60, 0x73, 0xE2, 0x86, 0x75, 0xA2, 0x3D, 0x18,
+ 0x98, 0x38, 0xEF, 0x1E, 0x2E, 0xE6, 0x52, 0xC0,
+ 0x13, 0xEC, 0xB4, 0xAE, 0xA9, 0x06, 0x11, 0x23,
+ 0x24, 0x97, 0x5C, 0x3C, 0xD4, 0x9B, 0x83, 0xBF,
+ 0xAC, 0xCB, 0xDD, 0x7D, 0x90, 0xC4, 0xBD, 0x70,
+ 0x98, 0x48, 0x8E, 0x9C, 0x21, 0x9A, 0x73, 0x72,
+ 0x4E, 0xFF, 0xD6, 0xFA, 0xE5, 0x64, 0x47, 0x38,
+ 0xFA, 0xA3, 0x1A, 0x4F, 0xF5, 0x5B, 0xCC, 0xC0,
+ 0xA1, 0x51, 0xAF, 0x5F, 0x0D, 0xC8, 0xB4, 0xBD,
+ 0x45, 0xBF, 0x37, 0xDF, 0x36, 0x5C, 0x1A, 0x65,
+ 0xE6, 0x8C, 0xFD, 0xA7, 0x6D, 0x4D, 0xA7, 0x08,
+ 0xDF, 0x1F, 0xB2, 0xBC, 0x2E, 0x4A, 0x43, 0x71
+};
+static const u8 dh_group22_order[] = {
+ 0xF5, 0x18, 0xAA, 0x87, 0x81, 0xA8, 0xDF, 0x27,
+ 0x8A, 0xBA, 0x4E, 0x7D, 0x64, 0xB7, 0xCB, 0x9D,
+ 0x49, 0x46, 0x23, 0x53
+};
+
+/*
+ * RFC 5114, 2.2.
+ * Group 23 - 2048-bit MODP Group with 224-bit Prime Order Subgroup
+ */
+static const u8 dh_group23_generator[] = {
+ 0xAC, 0x40, 0x32, 0xEF, 0x4F, 0x2D, 0x9A, 0xE3,
+ 0x9D, 0xF3, 0x0B, 0x5C, 0x8F, 0xFD, 0xAC, 0x50,
+ 0x6C, 0xDE, 0xBE, 0x7B, 0x89, 0x99, 0x8C, 0xAF,
+ 0x74, 0x86, 0x6A, 0x08, 0xCF, 0xE4, 0xFF, 0xE3,
+ 0xA6, 0x82, 0x4A, 0x4E, 0x10, 0xB9, 0xA6, 0xF0,
+ 0xDD, 0x92, 0x1F, 0x01, 0xA7, 0x0C, 0x4A, 0xFA,
+ 0xAB, 0x73, 0x9D, 0x77, 0x00, 0xC2, 0x9F, 0x52,
+ 0xC5, 0x7D, 0xB1, 0x7C, 0x62, 0x0A, 0x86, 0x52,
+ 0xBE, 0x5E, 0x90, 0x01, 0xA8, 0xD6, 0x6A, 0xD7,
+ 0xC1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4A,
+ 0xF4, 0xD0, 0x27, 0x27, 0x5A, 0xC1, 0x34, 0x8B,
+ 0xB8, 0xA7, 0x62, 0xD0, 0x52, 0x1B, 0xC9, 0x8A,
+ 0xE2, 0x47, 0x15, 0x04, 0x22, 0xEA, 0x1E, 0xD4,
+ 0x09, 0x93, 0x9D, 0x54, 0xDA, 0x74, 0x60, 0xCD,
+ 0xB5, 0xF6, 0xC6, 0xB2, 0x50, 0x71, 0x7C, 0xBE,
+ 0xF1, 0x80, 0xEB, 0x34, 0x11, 0x8E, 0x98, 0xD1,
+ 0x19, 0x52, 0x9A, 0x45, 0xD6, 0xF8, 0x34, 0x56,
+ 0x6E, 0x30, 0x25, 0xE3, 0x16, 0xA3, 0x30, 0xEF,
+ 0xBB, 0x77, 0xA8, 0x6F, 0x0C, 0x1A, 0xB1, 0x5B,
+ 0x05, 0x1A, 0xE3, 0xD4, 0x28, 0xC8, 0xF8, 0xAC,
+ 0xB7, 0x0A, 0x81, 0x37, 0x15, 0x0B, 0x8E, 0xEB,
+ 0x10, 0xE1, 0x83, 0xED, 0xD1, 0x99, 0x63, 0xDD,
+ 0xD9, 0xE2, 0x63, 0xE4, 0x77, 0x05, 0x89, 0xEF,
+ 0x6A, 0xA2, 0x1E, 0x7F, 0x5F, 0x2F, 0xF3, 0x81,
+ 0xB5, 0x39, 0xCC, 0xE3, 0x40, 0x9D, 0x13, 0xCD,
+ 0x56, 0x6A, 0xFB, 0xB4, 0x8D, 0x6C, 0x01, 0x91,
+ 0x81, 0xE1, 0xBC, 0xFE, 0x94, 0xB3, 0x02, 0x69,
+ 0xED, 0xFE, 0x72, 0xFE, 0x9B, 0x6A, 0xA4, 0xBD,
+ 0x7B, 0x5A, 0x0F, 0x1C, 0x71, 0xCF, 0xFF, 0x4C,
+ 0x19, 0xC4, 0x18, 0xE1, 0xF6, 0xEC, 0x01, 0x79,
+ 0x81, 0xBC, 0x08, 0x7F, 0x2A, 0x70, 0x65, 0xB3,
+ 0x84, 0xB8, 0x90, 0xD3, 0x19, 0x1F, 0x2B, 0xFA
+};
+static const u8 dh_group23_prime[] = {
+ 0xAD, 0x10, 0x7E, 0x1E, 0x91, 0x23, 0xA9, 0xD0,
+ 0xD6, 0x60, 0xFA, 0xA7, 0x95, 0x59, 0xC5, 0x1F,
+ 0xA2, 0x0D, 0x64, 0xE5, 0x68, 0x3B, 0x9F, 0xD1,
+ 0xB5, 0x4B, 0x15, 0x97, 0xB6, 0x1D, 0x0A, 0x75,
+ 0xE6, 0xFA, 0x14, 0x1D, 0xF9, 0x5A, 0x56, 0xDB,
+ 0xAF, 0x9A, 0x3C, 0x40, 0x7B, 0xA1, 0xDF, 0x15,
+ 0xEB, 0x3D, 0x68, 0x8A, 0x30, 0x9C, 0x18, 0x0E,
+ 0x1D, 0xE6, 0xB8, 0x5A, 0x12, 0x74, 0xA0, 0xA6,
+ 0x6D, 0x3F, 0x81, 0x52, 0xAD, 0x6A, 0xC2, 0x12,
+ 0x90, 0x37, 0xC9, 0xED, 0xEF, 0xDA, 0x4D, 0xF8,
+ 0xD9, 0x1E, 0x8F, 0xEF, 0x55, 0xB7, 0x39, 0x4B,
+ 0x7A, 0xD5, 0xB7, 0xD0, 0xB6, 0xC1, 0x22, 0x07,
+ 0xC9, 0xF9, 0x8D, 0x11, 0xED, 0x34, 0xDB, 0xF6,
+ 0xC6, 0xBA, 0x0B, 0x2C, 0x8B, 0xBC, 0x27, 0xBE,
+ 0x6A, 0x00, 0xE0, 0xA0, 0xB9, 0xC4, 0x97, 0x08,
+ 0xB3, 0xBF, 0x8A, 0x31, 0x70, 0x91, 0x88, 0x36,
+ 0x81, 0x28, 0x61, 0x30, 0xBC, 0x89, 0x85, 0xDB,
+ 0x16, 0x02, 0xE7, 0x14, 0x41, 0x5D, 0x93, 0x30,
+ 0x27, 0x82, 0x73, 0xC7, 0xDE, 0x31, 0xEF, 0xDC,
+ 0x73, 0x10, 0xF7, 0x12, 0x1F, 0xD5, 0xA0, 0x74,
+ 0x15, 0x98, 0x7D, 0x9A, 0xDC, 0x0A, 0x48, 0x6D,
+ 0xCD, 0xF9, 0x3A, 0xCC, 0x44, 0x32, 0x83, 0x87,
+ 0x31, 0x5D, 0x75, 0xE1, 0x98, 0xC6, 0x41, 0xA4,
+ 0x80, 0xCD, 0x86, 0xA1, 0xB9, 0xE5, 0x87, 0xE8,
+ 0xBE, 0x60, 0xE6, 0x9C, 0xC9, 0x28, 0xB2, 0xB9,
+ 0xC5, 0x21, 0x72, 0xE4, 0x13, 0x04, 0x2E, 0x9B,
+ 0x23, 0xF1, 0x0B, 0x0E, 0x16, 0xE7, 0x97, 0x63,
+ 0xC9, 0xB5, 0x3D, 0xCF, 0x4B, 0xA8, 0x0A, 0x29,
+ 0xE3, 0xFB, 0x73, 0xC1, 0x6B, 0x8E, 0x75, 0xB9,
+ 0x7E, 0xF3, 0x63, 0xE2, 0xFF, 0xA3, 0x1F, 0x71,
+ 0xCF, 0x9D, 0xE5, 0x38, 0x4E, 0x71, 0xB8, 0x1C,
+ 0x0A, 0xC4, 0xDF, 0xFE, 0x0C, 0x10, 0xE6, 0x4F
+};
+static const u8 dh_group23_order[] = {
+ 0x80, 0x1C, 0x0D, 0x34, 0xC5, 0x8D, 0x93, 0xFE,
+ 0x99, 0x71, 0x77, 0x10, 0x1F, 0x80, 0x53, 0x5A,
+ 0x47, 0x38, 0xCE, 0xBC, 0xBF, 0x38, 0x9A, 0x99,
+ 0xB3, 0x63, 0x71, 0xEB
+};
+
+/*
+ * RFC 5114, 2.3.
+ * Group 24 - 2048-bit MODP Group with 256-bit Prime Order Subgroup
+ */
+static const u8 dh_group24_generator[] = {
+ 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B,
+ 0x2E, 0x77, 0x50, 0x66, 0x60, 0xED, 0xBD, 0x48,
+ 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54,
+ 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25,
+ 0x10, 0xDB, 0xC1, 0x50, 0x77, 0xBE, 0x46, 0x3F,
+ 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55,
+ 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1,
+ 0xBC, 0x37, 0x73, 0xBF, 0x7E, 0x8C, 0x6F, 0x62,
+ 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18,
+ 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65,
+ 0x01, 0x96, 0xF9, 0x31, 0xC7, 0x7A, 0x57, 0xF2,
+ 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B,
+ 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62,
+ 0x8A, 0xC3, 0x76, 0xD2, 0x82, 0xD6, 0xED, 0x38,
+ 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83,
+ 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93,
+ 0xB5, 0x04, 0x5A, 0xF2, 0x76, 0x71, 0x64, 0xE1,
+ 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55,
+ 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80,
+ 0xD0, 0x52, 0xB9, 0x85, 0xD1, 0x82, 0xEA, 0x0A,
+ 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14,
+ 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9,
+ 0xB7, 0xD2, 0xBB, 0xD2, 0xDF, 0x01, 0x61, 0x99,
+ 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15,
+ 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37,
+ 0x7F, 0xD0, 0x28, 0x37, 0x0D, 0xF9, 0x2B, 0x52,
+ 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6,
+ 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3,
+ 0x2F, 0x63, 0x07, 0x84, 0x90, 0xF0, 0x0E, 0xF8,
+ 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51,
+ 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82,
+ 0x66, 0x4B, 0x4C, 0x0F, 0x6C, 0xC4, 0x16, 0x59
+};
+static const u8 dh_group24_prime[] = {
+ 0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C,
+ 0xFF, 0xBB, 0xD1, 0x9C, 0x65, 0x19, 0x59, 0x99,
+ 0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2,
+ 0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00,
+ 0xE0, 0x0D, 0xF8, 0xF1, 0xD6, 0x19, 0x57, 0xD4,
+ 0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30,
+ 0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA,
+ 0x3B, 0xF4, 0x29, 0x6D, 0x83, 0x0E, 0x9A, 0x7C,
+ 0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD,
+ 0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED,
+ 0x91, 0xF9, 0xE6, 0x72, 0x5B, 0x47, 0x58, 0xC0,
+ 0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B,
+ 0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88,
+ 0xB9, 0x41, 0xF5, 0x4E, 0xB1, 0xE5, 0x9B, 0xB8,
+ 0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C,
+ 0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76,
+ 0xB6, 0x3A, 0xCA, 0xE1, 0xCA, 0xA6, 0xB7, 0x90,
+ 0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E,
+ 0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB,
+ 0x3A, 0xD8, 0x34, 0x77, 0x96, 0x52, 0x4D, 0x8E,
+ 0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9,
+ 0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25,
+ 0x1C, 0xCA, 0xCB, 0x83, 0xE6, 0xB4, 0x86, 0xF6,
+ 0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26,
+ 0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56,
+ 0xDE, 0xD4, 0x01, 0x0A, 0xBD, 0x0B, 0xE6, 0x21,
+ 0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3,
+ 0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03,
+ 0xA4, 0xB5, 0x43, 0x30, 0xC1, 0x98, 0xAF, 0x12,
+ 0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F,
+ 0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA,
+ 0xDB, 0x09, 0x4A, 0xE9, 0x1E, 0x1A, 0x15, 0x97
+};
+static const u8 dh_group24_order[] = {
+ 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97,
+ 0xB4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9D, 0xA2,
+ 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B,
+ 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3
+};
#endif /* ALL_DH_GROUPS */
-#define DH_GROUP(id) \
+#define DH_GROUP(id,safe) \
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
-dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
+dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
+dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
static struct dh_group dh_groups[] = {
- DH_GROUP(5),
+ DH_GROUP(5, 1),
#ifdef ALL_DH_GROUPS
- DH_GROUP(1),
- DH_GROUP(2),
- DH_GROUP(14),
- DH_GROUP(15),
- DH_GROUP(16),
- DH_GROUP(17),
- DH_GROUP(18)
+ DH_GROUP(1, 1),
+ DH_GROUP(2, 1),
+ DH_GROUP(14, 1),
+ DH_GROUP(15, 1),
+ DH_GROUP(16, 1),
+ DH_GROUP(17, 1),
+ DH_GROUP(18, 1),
+ DH_GROUP(22, 0),
+ DH_GROUP(23, 0),
+ DH_GROUP(24, 0)
#endif /* ALL_DH_GROUPS */
};
-#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
+#define NUM_DH_GROUPS ARRAY_SIZE(dh_groups)
const struct dh_group * dh_groups_get(int id)
@@ -554,14 +1198,14 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
if (dh == NULL)
return NULL;
- wpabuf_free(*priv);
+ wpabuf_clear_free(*priv);
*priv = wpabuf_alloc(dh->prime_len);
if (*priv == NULL)
return NULL;
if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
{
- wpabuf_free(*priv);
+ wpabuf_clear_free(*priv);
*priv = NULL;
return NULL;
}
@@ -580,7 +1224,7 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
wpabuf_head(*priv), wpabuf_len(*priv),
dh->prime, dh->prime_len, wpabuf_mhead(pv),
&pv_len) < 0) {
- wpabuf_free(pv);
+ wpabuf_clear_free(pv);
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
return NULL;
}
@@ -616,7 +1260,7 @@ struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
wpabuf_head(own_private), wpabuf_len(own_private),
dh->prime, dh->prime_len,
wpabuf_mhead(shared), &shared_len) < 0) {
- wpabuf_free(shared);
+ wpabuf_clear_free(shared);
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
return NULL;
}
diff --git a/contrib/wpa/src/crypto/dh_groups.h b/contrib/wpa/src/crypto/dh_groups.h
index 225f006..d0e74b9 100644
--- a/contrib/wpa/src/crypto/dh_groups.h
+++ b/contrib/wpa/src/crypto/dh_groups.h
@@ -15,6 +15,9 @@ struct dh_group {
size_t generator_len;
const u8 *prime;
size_t prime_len;
+ const u8 *order;
+ size_t order_len;
+ unsigned int safe_prime:1;
};
const struct dh_group * dh_groups_get(int id);
diff --git a/contrib/wpa/src/crypto/fips_prf_cryptoapi.c b/contrib/wpa/src/crypto/fips_prf_cryptoapi.c
deleted file mode 100644
index dca93a3..0000000
--- a/contrib/wpa/src/crypto/fips_prf_cryptoapi.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * FIPS 186-2 PRF for Microsoft CryptoAPI
- * 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 "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
- /* FIX: how to do this with CryptoAPI? */
- return -1;
-}
diff --git a/contrib/wpa/src/crypto/fips_prf_gnutls.c b/contrib/wpa/src/crypto/fips_prf_gnutls.c
deleted file mode 100644
index 947e6f6..0000000
--- a/contrib/wpa/src/crypto/fips_prf_gnutls.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * FIPS 186-2 PRF for libgcrypt
- * Copyright (c) 2004-2009, 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 <gcrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
- /* FIX: how to do this with libgcrypt? */
- return -1;
-}
diff --git a/contrib/wpa/src/crypto/fips_prf_nss.c b/contrib/wpa/src/crypto/fips_prf_nss.c
deleted file mode 100644
index 2c962f4..0000000
--- a/contrib/wpa/src/crypto/fips_prf_nss.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * FIPS 186-2 PRF for NSS
- * 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 "includes.h"
-#include <openssl/sha.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
- return -1;
-}
diff --git a/contrib/wpa/src/crypto/md5.c b/contrib/wpa/src/crypto/md5.c
index db2b8cc..f64dfd3 100644
--- a/contrib/wpa/src/crypto/md5.c
+++ b/contrib/wpa/src/crypto/md5.c
@@ -30,6 +30,7 @@ int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
u8 tk[16];
const u8 *_addr[6];
size_t i, _len[6];
+ int res;
if (num_elem > 5) {
/*
@@ -85,7 +86,10 @@ int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
_len[0] = 64;
_addr[1] = mac;
_len[1] = MD5_MAC_LEN;
- return md5_vector(2, _addr, _len, mac);
+ res = md5_vector(2, _addr, _len, mac);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memset(tk, 0, sizeof(tk));
+ return res;
}
diff --git a/contrib/wpa/src/crypto/milenage.c b/contrib/wpa/src/crypto/milenage.c
index a7f9c6a..6edea57 100644
--- a/contrib/wpa/src/crypto/milenage.c
+++ b/contrib/wpa/src/crypto/milenage.c
@@ -217,7 +217,7 @@ int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
for (i = 0; i < 6; i++)
sqn[i] = auts[i] ^ ak[i];
if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
- memcmp(mac_s, auts + 6, 8) != 0)
+ os_memcmp_const(mac_s, auts + 6, 8) != 0)
return -1;
return 0;
}
@@ -312,7 +312,7 @@ int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
- if (os_memcmp(mac_a, autn + 8, 8) != 0) {
+ if (os_memcmp_const(mac_a, autn + 8, 8) != 0) {
wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
autn + 8, 8);
diff --git a/contrib/wpa/src/crypto/ms_funcs.c b/contrib/wpa/src/crypto/ms_funcs.c
index b2bbab2..49a5c1c 100644
--- a/contrib/wpa/src/crypto/ms_funcs.c
+++ b/contrib/wpa/src/crypto/ms_funcs.c
@@ -58,6 +58,7 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
WPA_PUT_LE16(ucs2_buffer + j,
((c & 0xF) << 12) |
((c2 & 0x3F) << 6) | (c3 & 0x3F));
+ j += 2;
}
}
}
diff --git a/contrib/wpa/src/crypto/random.c b/contrib/wpa/src/crypto/random.c
index 053740e..bc758aa 100644
--- a/contrib/wpa/src/crypto/random.c
+++ b/contrib/wpa/src/crypto/random.c
@@ -232,12 +232,8 @@ int random_pool_ready(void)
*/
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
- int error = errno;
- perror("open(/dev/random)");
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+ strerror(errno));
return -1;
}
@@ -417,12 +413,8 @@ void random_init(const char *entropy_file)
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
- int error = errno;
- perror("open(/dev/random)");
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+ strerror(errno));
return;
}
wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
diff --git a/contrib/wpa/src/crypto/sha1-internal.c b/contrib/wpa/src/crypto/sha1-internal.c
index 10bf153..24bc3ff 100644
--- a/contrib/wpa/src/crypto/sha1-internal.c
+++ b/contrib/wpa/src/crypto/sha1-internal.c
@@ -19,6 +19,7 @@ typedef struct SHA1Context SHA1_CTX;
void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
+#ifdef CONFIG_CRYPTO_INTERNAL
/**
* sha1_vector - SHA-1 hash for data vector
* @num_elem: Number of elements in the data vector
@@ -38,6 +39,7 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
SHA1Final(mac, &ctx);
return 0;
}
+#endif /* CONFIG_CRYPTO_INTERNAL */
/* ===== start - public domain SHA1 implementation ===== */
diff --git a/contrib/wpa/src/crypto/sha1-prf.c b/contrib/wpa/src/crypto/sha1-prf.c
index 90b9e74..4b2d137 100644
--- a/contrib/wpa/src/crypto/sha1-prf.c
+++ b/contrib/wpa/src/crypto/sha1-prf.c
@@ -61,6 +61,7 @@ int sha1_prf(const u8 *key, size_t key_len, const char *label,
}
counter++;
}
+ os_memset(hash, 0, sizeof(hash));
return 0;
}
diff --git a/contrib/wpa/src/crypto/sha1.c b/contrib/wpa/src/crypto/sha1.c
index d48c77d..8fce139 100644
--- a/contrib/wpa/src/crypto/sha1.c
+++ b/contrib/wpa/src/crypto/sha1.c
@@ -30,6 +30,7 @@ int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
unsigned char tk[20];
const u8 *_addr[6];
size_t _len[6], i;
+ int ret;
if (num_elem > 5) {
/*
@@ -84,7 +85,9 @@ int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
_len[0] = 64;
_addr[1] = mac;
_len[1] = SHA1_MAC_LEN;
- return sha1_vector(2, _addr, _len, mac);
+ ret = sha1_vector(2, _addr, _len, mac);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ return ret;
}
diff --git a/contrib/wpa/src/crypto/sha256-kdf.c b/contrib/wpa/src/crypto/sha256-kdf.c
new file mode 100644
index 0000000..d8a1beb
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha256-kdf.c
@@ -0,0 +1,76 @@
+/*
+ * HMAC-SHA256 KDF (RFC 5295)
+ * Copyright (c) 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 "sha256.h"
+
+
+/**
+ * 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
+ * @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.
+ */
+int hmac_sha256_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[SHA256_MAC_LEN];
+ u8 iter = 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+ size_t pos, clen;
+
+ addr[0] = T;
+ len[0] = SHA256_MAC_LEN;
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ addr[2] = seed;
+ len[2] = seed_len;
+ addr[3] = &iter;
+ len[3] = 1;
+
+ if (hmac_sha256_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+ return -1;
+
+ pos = 0;
+ for (;;) {
+ clen = outlen - pos;
+ if (clen > SHA256_MAC_LEN)
+ clen = SHA256_MAC_LEN;
+ os_memcpy(out + pos, T, clen);
+ pos += clen;
+
+ if (pos == outlen)
+ break;
+
+ if (iter == 255) {
+ os_memset(out, 0, outlen);
+ return -1;
+ }
+ iter++;
+
+ if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
+ {
+ os_memset(out, 0, outlen);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha256-prf.c b/contrib/wpa/src/crypto/sha256-prf.c
index 0da6d13..79791c0 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-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,12 +29,36 @@
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
+ sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+}
+
+
+/**
+ * sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bits of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key. If the requested buf_len is not divisible by eight, the least
+ * significant 1-7 bits of the last octet in the output are not part of the
+ * requested output.
+ */
+void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
+{
u16 counter = 1;
size_t pos, plen;
u8 hash[SHA256_MAC_LEN];
const u8 *addr[4];
size_t len[4];
u8 counter_le[2], length_le[2];
+ size_t buf_len = (buf_len_bits + 7) / 8;
addr[0] = counter_le;
len[0] = 2;
@@ -45,7 +69,7 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
addr[3] = length_le;
len[3] = sizeof(length_le);
- WPA_PUT_LE16(length_le, buf_len * 8);
+ WPA_PUT_LE16(length_le, buf_len_bits);
pos = 0;
while (pos < buf_len) {
plen = buf_len - pos;
@@ -57,8 +81,20 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
} else {
hmac_sha256_vector(key, key_len, 4, addr, len, hash);
os_memcpy(&buf[pos], hash, plen);
+ pos += plen;
break;
}
counter++;
}
+
+ /*
+ * Mask out unused bits in the last octet if it does not use all the
+ * bits.
+ */
+ if (buf_len_bits % 8) {
+ u8 mask = 0xff << (8 - buf_len_bits % 8);
+ buf[pos - 1] &= mask;
+ }
+
+ os_memset(hash, 0, sizeof(hash));
}
diff --git a/contrib/wpa/src/crypto/sha256.h b/contrib/wpa/src/crypto/sha256.h
index fcac800..b15f511 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-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,8 +17,14 @@ int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
#endif /* SHA256_H */
diff --git a/contrib/wpa/src/crypto/sha384.h b/contrib/wpa/src/crypto/sha384.h
new file mode 100644
index 0000000..e6a1fe4
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384.h
@@ -0,0 +1,19 @@
+/*
+ * SHA384 hash implementation and interface functions
+ * 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 SHA384_H
+#define SHA384_H
+
+#define SHA384_MAC_LEN 48
+
+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);
+
+#endif /* SHA384_H */
diff --git a/contrib/wpa/src/crypto/tls.h b/contrib/wpa/src/crypto/tls.h
index b61e439..9ae95a6 100644
--- a/contrib/wpa/src/crypto/tls.h
+++ b/contrib/wpa/src/crypto/tls.h
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface definition
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -40,9 +40,14 @@ enum tls_fail_reason {
TLS_FAIL_SUBJECT_MISMATCH = 5,
TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
TLS_FAIL_BAD_CERTIFICATE = 7,
- TLS_FAIL_SERVER_CHAIN_PROBE = 8
+ TLS_FAIL_SERVER_CHAIN_PROBE = 8,
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
+ TLS_FAIL_DOMAIN_MISMATCH = 10,
};
+
+#define TLS_MAX_ALT_SUBJECT 10
+
union tls_event_data {
struct {
int depth;
@@ -58,6 +63,8 @@ union tls_event_data {
const struct wpabuf *cert;
const u8 *hash;
size_t hash_len;
+ const char *altsubject[TLS_MAX_ALT_SUBJECT];
+ int num_altsubject;
} peer_cert;
struct {
@@ -73,6 +80,7 @@ struct tls_config {
const char *pkcs11_module_path;
int fips_mode;
int cert_in_cb;
+ const char *openssl_ciphers;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@@ -82,6 +90,11 @@ struct tls_config {
#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
+#define TLS_CONN_REQUEST_OCSP BIT(3)
+#define TLS_CONN_REQUIRE_OCSP BIT(4)
+#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
+#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
+#define TLS_CONN_EAP_FAST BIT(7)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -94,6 +107,12 @@ 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.
+ * @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.
* @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
@@ -116,7 +135,10 @@ struct tls_config {
* specific for now)
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
+ * @openssl_ciphers: OpenSSL cipher configuration
* @flags: Parameter options (TLS_CONN_*)
+ * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
+ * or %NULL if OCSP is not enabled
*
* TLS connection parameters to be configured with tls_connection_set_params()
* and tls_global_set_params().
@@ -133,6 +155,8 @@ struct tls_connection_params {
const char *ca_path;
const char *subject_match;
const char *altsubject_match;
+ const char *suffix_match;
+ const char *domain_match;
const char *client_cert;
const u8 *client_cert_blob;
size_t client_cert_blob_len;
@@ -151,8 +175,10 @@ struct tls_connection_params {
const char *key_id;
const char *cert_id;
const char *ca_cert_id;
+ const char *openssl_ciphers;
unsigned int flags;
+ const char *ocsp_stapling_response;
};
@@ -526,4 +552,21 @@ int __must_check tls_connection_set_session_ticket_cb(
void *tls_ctx, struct tls_connection *conn,
tls_session_ticket_cb cb, void *ctx);
+void tls_connection_set_log_cb(struct tls_connection *conn,
+ void (*log_cb)(void *ctx, const char *msg),
+ void *ctx);
+
+#define TLS_BREAK_VERIFY_DATA BIT(0)
+#define TLS_BREAK_SRV_KEY_X_HASH BIT(1)
+#define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2)
+#define TLS_DHE_PRIME_511B BIT(3)
+#define TLS_DHE_PRIME_767B BIT(4)
+#define TLS_DHE_PRIME_15 BIT(5)
+#define TLS_DHE_PRIME_58B BIT(6)
+#define TLS_DHE_NON_PRIME BIT(7)
+
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
+
+int tls_get_library_version(char *buf, size_t buf_len);
+
#endif /* TLS_H */
diff --git a/contrib/wpa/src/crypto/tls_gnutls.c b/contrib/wpa/src/crypto/tls_gnutls.c
index a5d72f4..65db6fc 100644
--- a/contrib/wpa/src/crypto/tls_gnutls.c
+++ b/contrib/wpa/src/crypto/tls_gnutls.c
@@ -12,61 +12,15 @@
#ifdef PKCS12_FUNCS
#include <gnutls/pkcs12.h>
#endif /* PKCS12_FUNCS */
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+#include <gnutls/ocsp.h>
+#endif /* 3.1.3 */
#include "common.h"
+#include "crypto/crypto.h"
#include "tls.h"
-#define WPA_TLS_RANDOM_SIZE 32
-#define WPA_TLS_MASTER_SIZE 48
-
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x010302
-/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
- * use of internal structures to get the master_secret and
- * {server,client}_random.
- */
-#define GNUTLS_INTERNAL_STRUCTURE_HACK
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
-
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-/*
- * It looks like gnutls does not provide access to client/server_random and
- * master_key. This is somewhat unfortunate since these are needed for key
- * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
- * hack that copies the gnutls_session_int definition from gnutls_int.h so that
- * we can get the needed information.
- */
-
-typedef u8 uint8;
-typedef unsigned char opaque;
-typedef struct {
- uint8 suite[2];
-} cipher_suite_st;
-
-typedef struct {
- gnutls_connection_end_t entity;
- gnutls_kx_algorithm_t kx_algorithm;
- gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
- gnutls_mac_algorithm_t read_mac_algorithm;
- gnutls_compression_method_t read_compression_algorithm;
- gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
- gnutls_mac_algorithm_t write_mac_algorithm;
- gnutls_compression_method_t write_compression_algorithm;
- cipher_suite_st current_cipher_suite;
- opaque master_secret[WPA_TLS_MASTER_SIZE];
- opaque client_random[WPA_TLS_RANDOM_SIZE];
- opaque server_random[WPA_TLS_RANDOM_SIZE];
- /* followed by stuff we are not interested in */
-} security_parameters_st;
-
-struct gnutls_session_int {
- security_parameters_st security_parameters;
- /* followed by things we are not interested in */
-};
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
static int tls_gnutls_ref_count = 0;
struct tls_global {
@@ -78,17 +32,23 @@ struct tls_global {
int params_set;
gnutls_certificate_credentials_t xcred;
+
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+ int cert_in_cb;
};
struct tls_connection {
- gnutls_session session;
- char *subject_match, *altsubject_match;
+ struct tls_global *global;
+ gnutls_session_t session;
int read_alerts, write_alerts, failed;
u8 *pre_shared_secret;
size_t pre_shared_secret_len;
int established;
int verify_peer;
+ unsigned int disable_time_checks:1;
struct wpabuf *push_buf;
struct wpabuf *pull_buf;
@@ -96,9 +56,16 @@ struct tls_connection {
int params_set;
gnutls_certificate_credentials_t xcred;
+
+ char *suffix_match;
+ char *domain_match;
+ unsigned int flags;
};
+static int tls_connection_verify_peer(gnutls_session_t session);
+
+
static void tls_log_func(int level, const char *msg)
{
char *s, *pos;
@@ -125,23 +92,15 @@ static void tls_log_func(int level, const char *msg)
}
-extern int wpa_debug_show_keys;
-
void * tls_init(const struct tls_config *conf)
{
struct tls_global *global;
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- /* Because of the horrible hack to get master_secret and client/server
- * random, we need to make sure that the gnutls version is something
- * that is expected to have same structure definition for the session
- * data.. */
- const char *ver;
- const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
- "1.3.2",
- NULL };
- int i;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+ if (tls_gnutls_ref_count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Library version %s (runtime) - %s (build)",
+ gnutls_check_version(NULL), GNUTLS_VERSION);
+ }
global = os_zalloc(sizeof(*global));
if (global == NULL)
@@ -153,28 +112,16 @@ void * tls_init(const struct tls_config *conf)
}
tls_gnutls_ref_count++;
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- ver = gnutls_check_version(NULL);
- if (ver == NULL) {
- tls_deinit(global);
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
- for (i = 0; ok_ver[i]; i++) {
- if (strcmp(ok_ver[i], ver) == 0)
- break;
- }
- if (ok_ver[i] == NULL) {
- wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
- "to be tested and enabled in tls_gnutls.c", ver);
- tls_deinit(global);
- return NULL;
- }
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-
gnutls_global_set_log_function(tls_log_func);
if (wpa_debug_show_keys)
gnutls_global_set_log_level(11);
+
+ if (conf) {
+ global->event_cb = conf->event_cb;
+ global->cb_ctx = conf->cb_ctx;
+ global->cert_in_cb = conf->cert_in_cb;
+ }
+
return global;
}
@@ -201,7 +148,7 @@ int tls_get_errors(void *ssl_ctx)
}
-static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -230,7 +177,7 @@ static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
}
-static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -248,12 +195,7 @@ static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
static int tls_gnutls_init_session(struct tls_global *global,
struct tls_connection *conn)
{
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
const char *err;
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
- const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
- const int protos[2] = { GNUTLS_TLS1, 0 };
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
int ret;
ret = gnutls_init(&conn->session,
@@ -268,7 +210,6 @@ static int tls_gnutls_init_session(struct tls_global *global,
if (ret < 0)
goto fail;
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
&err);
if (ret < 0) {
@@ -276,19 +217,11 @@ static int tls_gnutls_init_session(struct tls_global *global,
"'%s'", err);
goto fail;
}
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
- ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
- if (ret < 0)
- goto fail;
-
- ret = gnutls_protocol_set_priority(conn->session, protos);
- if (ret < 0)
- goto fail;
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
gnutls_transport_set_pull_function(conn->session, tls_pull_func);
gnutls_transport_set_push_function(conn->session, tls_push_func);
- gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
+ gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
+ gnutls_session_set_ptr(conn->session, conn);
return 0;
@@ -309,6 +242,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->global = global;
if (tls_gnutls_init_session(global, conn)) {
os_free(conn);
@@ -344,10 +278,10 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
gnutls_certificate_free_credentials(conn->xcred);
gnutls_deinit(conn->session);
os_free(conn->pre_shared_secret);
- os_free(conn->subject_match);
- os_free(conn->altsubject_match);
wpabuf_free(conn->push_buf);
wpabuf_free(conn->pull_buf);
+ os_free(conn->suffix_match);
+ os_free(conn->domain_match);
os_free(conn);
}
@@ -405,104 +339,6 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
}
-#if 0
-static int tls_match_altsubject(X509 *cert, const char *match)
-{
- GENERAL_NAME *gen;
- char *field, *tmp;
- void *ext;
- int i, found = 0;
- size_t len;
-
- ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
-
- for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
- gen = sk_GENERAL_NAME_value(ext, i);
- switch (gen->type) {
- case GEN_EMAIL:
- field = "EMAIL";
- break;
- case GEN_DNS:
- field = "DNS";
- break;
- case GEN_URI:
- field = "URI";
- break;
- default:
- field = NULL;
- wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
- "unsupported type=%d", gen->type);
- break;
- }
-
- if (!field)
- continue;
-
- wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
- field, gen->d.ia5->data);
- len = os_strlen(field) + 1 +
- strlen((char *) gen->d.ia5->data) + 1;
- tmp = os_malloc(len);
- if (tmp == NULL)
- continue;
- snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
- if (strstr(tmp, match))
- found++;
- os_free(tmp);
- }
-
- return found;
-}
-#endif
-
-
-#if 0
-static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
-{
- char buf[256];
- X509 *err_cert;
- int err, depth;
- SSL *ssl;
- struct tls_connection *conn;
- char *match, *altmatch;
-
- err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
- err = X509_STORE_CTX_get_error(x509_ctx);
- depth = X509_STORE_CTX_get_error_depth(x509_ctx);
- ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
- SSL_get_ex_data_X509_STORE_CTX_idx());
- X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
-
- conn = SSL_get_app_data(ssl);
- match = conn ? conn->subject_match : NULL;
- altmatch = conn ? conn->altsubject_match : NULL;
-
- if (!preverify_ok) {
- wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
- " error %d (%s) depth %d for '%s'", err,
- X509_verify_cert_error_string(err), depth, buf);
- } else {
- wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
- "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
- preverify_ok, err,
- X509_verify_cert_error_string(err), depth, buf);
- if (depth == 0 && match && strstr(buf, match) == NULL) {
- wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
- "match with '%s'", buf, match);
- preverify_ok = 0;
- } else if (depth == 0 && altmatch &&
- !tls_match_altsubject(err_cert, altmatch)) {
- wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
- "'%s' not found", altmatch);
- preverify_ok = 0;
- }
- }
-
- return preverify_ok;
-}
-#endif
-
-
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
@@ -511,73 +347,142 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (conn == NULL || params == NULL)
return -1;
- os_free(conn->subject_match);
- conn->subject_match = NULL;
if (params->subject_match) {
- conn->subject_match = os_strdup(params->subject_match);
- if (conn->subject_match == NULL)
- return -1;
+ wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
+ return -1;
}
- os_free(conn->altsubject_match);
- conn->altsubject_match = NULL;
if (params->altsubject_match) {
- conn->altsubject_match = os_strdup(params->altsubject_match);
- if (conn->altsubject_match == NULL)
+ wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
+ return -1;
+ }
+
+ os_free(conn->suffix_match);
+ conn->suffix_match = NULL;
+ if (params->suffix_match) {
+ conn->suffix_match = os_strdup(params->suffix_match);
+ if (conn->suffix_match == NULL)
return -1;
}
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (params->domain_match) {
+ conn->domain_match = os_strdup(params->domain_match);
+ if (conn->domain_match == NULL)
+ return -1;
+ }
+#else /* < 3.3.0 */
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
+ return -1;
+ }
+#endif /* >= 3.3.0 */
+
+ conn->flags = params->flags;
+
+ if (params->openssl_ciphers) {
+ wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+
/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
if (params->ca_cert) {
- conn->verify_peer = 1;
+ wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
+ params->ca_cert);
ret = gnutls_certificate_set_x509_trust_file(
- conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+ conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
- "in PEM format: %s", params->ca_cert,
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
+ params->ca_cert,
gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_trust_file(
conn->xcred, params->ca_cert,
- GNUTLS_X509_FMT_DER);
+ GNUTLS_X509_FMT_PEM);
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "Failed to read CA cert "
- "'%s' in DER format: %s",
+ wpa_printf(MSG_DEBUG,
+ "Failed to read CA cert '%s' in PEM format: %s",
params->ca_cert,
gnutls_strerror(ret));
return -1;
}
}
+ } else if (params->ca_cert_blob) {
+ gnutls_datum_t ca;
+
+ ca.data = (unsigned char *) params->ca_cert_blob;
+ ca.size = params->ca_cert_blob_len;
+
+ ret = gnutls_certificate_set_x509_trust_mem(
+ conn->xcred, &ca, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to parse CA cert in DER format: %s",
+ gnutls_strerror(ret));
+ ret = gnutls_certificate_set_x509_trust_mem(
+ conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to parse CA cert in PEM format: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
+ }
+ } else if (params->ca_path) {
+ wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
+ return -1;
+ }
+
+ conn->disable_time_checks = 0;
+ if (params->ca_cert || params->ca_cert_blob) {
+ conn->verify_peer = 1;
+ gnutls_certificate_set_verify_function(
+ conn->xcred, tls_connection_verify_peer);
if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
gnutls_certificate_set_verify_flags(
conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+ conn->disable_time_checks = 1;
gnutls_certificate_set_verify_flags(
conn->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
}
if (params->client_cert && params->private_key) {
- /* TODO: private_key_passwd? */
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_file2(
+ conn->xcred, params->client_cert, params->private_key,
+ GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
+#else
+ /* private_key_passwd not (easily) supported here */
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert, params->private_key,
- GNUTLS_X509_FMT_PEM);
+ GNUTLS_X509_FMT_DER);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
- "in PEM format: %s", gnutls_strerror(ret));
+ "in DER format: %s", gnutls_strerror(ret));
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_file2(
+ conn->xcred, params->client_cert,
+ params->private_key, GNUTLS_X509_FMT_PEM,
+ params->private_key_passwd, 0);
+#else
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert,
- params->private_key, GNUTLS_X509_FMT_DER);
+ params->private_key, GNUTLS_X509_FMT_PEM);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
- "cert/key in DER format: %s",
+ "cert/key in PEM format: %s",
gnutls_strerror(ret));
return ret;
}
@@ -586,7 +491,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
params->private_key_passwd);
@@ -596,7 +500,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
} else
pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
#endif /* PKCS12_FUNCS */
if (!pkcs12_ok) {
@@ -604,8 +507,82 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
"included");
return -1;
}
+ } else if (params->client_cert_blob && params->private_key_blob) {
+ gnutls_datum_t cert, key;
+
+ cert.data = (unsigned char *) params->client_cert_blob;
+ cert.size = params->client_cert_blob_len;
+ key.data = (unsigned char *) params->private_key_blob;
+ key.size = params->private_key_blob_len;
+
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_mem2(
+ conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
+ params->private_key_passwd, 0);
+#else
+ /* private_key_passwd not (easily) supported here */
+ ret = gnutls_certificate_set_x509_key_mem(
+ conn->xcred, &cert, &key, 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));
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_mem2(
+ conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
+ params->private_key_passwd, 0);
+#else
+ /* private_key_passwd not (easily) supported here */
+ ret = gnutls_certificate_set_x509_key_mem(
+ conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
+#endif
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to read client "
+ "cert/key in PEM format: %s",
+ gnutls_strerror(ret));
+ return ret;
+ }
+ }
+ } else if (params->private_key_blob) {
+#ifdef PKCS12_FUNCS
+ gnutls_datum_t key;
+
+ key.data = (unsigned char *) params->private_key_blob;
+ key.size = params->private_key_blob_len;
+
+ /* Try to load in PKCS#12 format */
+ ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
+ conn->xcred, &key, GNUTLS_X509_FMT_DER,
+ params->private_key_passwd);
+ if (ret != 0) {
+ wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+ "PKCS#12 format: %s", gnutls_strerror(ret));
+ return -1;
+ }
+#else /* PKCS12_FUNCS */
+ wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
+ return -1;
+#endif /* PKCS12_FUNCS */
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
+ ret = gnutls_ocsp_status_request_enable_client(conn->session,
+ NULL, 0, NULL);
+ if (ret != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: Failed to enable OCSP client");
+ return -1;
+ }
+ }
+#else /* 3.1.3 */
+ if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: OCSP not supported by this version of GnuTLS");
+ return -1;
+ }
+#endif /* 3.1.3 */
+
conn->params_set = 1;
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
@@ -643,17 +620,17 @@ int tls_global_set_params(void *tls_ctx,
if (params->ca_cert) {
ret = gnutls_certificate_set_x509_trust_file(
- global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+ global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
- "in PEM format: %s", params->ca_cert,
+ "in DER format: %s", params->ca_cert,
gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_trust_file(
global->xcred, params->ca_cert,
- GNUTLS_X509_FMT_DER);
+ GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert "
- "'%s' in DER format: %s",
+ "'%s' in PEM format: %s",
params->ca_cert,
gnutls_strerror(ret));
goto fail;
@@ -666,29 +643,27 @@ int tls_global_set_params(void *tls_ctx,
GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
gnutls_certificate_set_verify_flags(
global->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
}
if (params->client_cert && params->private_key) {
/* TODO: private_key_passwd? */
ret = gnutls_certificate_set_x509_key_file(
global->xcred, params->client_cert,
- params->private_key, GNUTLS_X509_FMT_PEM);
+ params->private_key, GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
- "in PEM format: %s", gnutls_strerror(ret));
+ "in DER format: %s", gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_key_file(
global->xcred, params->client_cert,
- params->private_key, GNUTLS_X509_FMT_DER);
+ params->private_key, GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
- "cert/key in DER format: %s",
+ "cert/key in PEM format: %s",
gnutls_strerror(ret));
goto fail;
}
@@ -697,7 +672,6 @@ int tls_global_set_params(void *tls_ctx,
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
global->xcred, params->private_key,
GNUTLS_X509_FMT_DER, params->private_key_passwd);
@@ -707,7 +681,6 @@ int tls_global_set_params(void *tls_ctx,
goto fail;
} else
pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
#endif /* PKCS12_FUNCS */
if (!pkcs12_ok) {
@@ -752,37 +725,23 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- security_parameters_st *sec;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#if GNUTLS_VERSION_NUMBER >= 0x030012
+ gnutls_datum_t client, server;
if (conn == NULL || conn->session == NULL || keys == NULL)
return -1;
os_memset(keys, 0, sizeof(*keys));
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- sec = &conn->session->security_parameters;
- keys->master_key = sec->master_secret;
- keys->master_key_len = WPA_TLS_MASTER_SIZE;
- keys->client_random = sec->client_random;
- keys->server_random = sec->server_random;
-#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
- keys->client_random =
- (u8 *) gnutls_session_get_client_random(conn->session);
- keys->server_random =
- (u8 *) gnutls_session_get_server_random(conn->session);
- /* No access to master_secret */
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
- keys->client_random_len = WPA_TLS_RANDOM_SIZE;
- keys->server_random_len = WPA_TLS_RANDOM_SIZE;
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
+ gnutls_session_get_random(conn->session, &client, &server);
+ keys->client_random = client.data;
+ keys->server_random = server.data;
+ keys->client_random_len = client.size;
+ keys->server_random_len = client.size;
return 0;
+#else /* 3.0.18 */
+ return -1;
+#endif /* 3.0.18 */
}
@@ -790,86 +749,317 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
if (conn == NULL || conn->session == NULL)
return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
server_random_first, 0, NULL, out_len, (char *) out);
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+}
+
+
+static void gnutls_tls_fail_event(struct tls_connection *conn,
+ const gnutls_datum_t *cert, int depth,
+ const char *subject, const char *err_str,
+ enum tls_fail_reason reason)
+{
+ union tls_event_data ev;
+ struct tls_global *global = conn->global;
+ struct wpabuf *cert_buf = NULL;
+
+ if (global->event_cb == NULL)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.depth = depth;
+ ev.cert_fail.subject = subject ? subject : "";
+ ev.cert_fail.reason = reason;
+ ev.cert_fail.reason_txt = err_str;
+ if (cert) {
+ cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
+ ev.cert_fail.cert = cert_buf;
+ }
+ global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ wpabuf_free(cert_buf);
+}
+
+
+#if GNUTLS_VERSION_NUMBER < 0x030300
+static int server_eku_purpose(gnutls_x509_crt_t cert)
+{
+ unsigned int i;
+
+ for (i = 0; ; i++) {
+ char oid[128];
+ size_t oid_size = sizeof(oid);
+ int res;
+
+ res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
+ &oid_size, NULL);
+ if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ if (i == 0) {
+ /* No EKU - assume any use allowed */
+ return 1;
+ }
+ break;
+ }
+
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
+ if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
+ os_strcmp(oid, GNUTLS_KP_ANY) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* < 3.3.0 */
+
+
+static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
+ gnutls_alert_description_t *err)
+{
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ gnutls_datum_t response, buf;
+ gnutls_ocsp_resp_t resp;
+ unsigned int cert_status;
+ int res;
+
+ if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
+ return 0;
+
+ if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: No valid OCSP response received");
+ goto ocsp_error;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
+ return 0;
+ }
+
+ /*
+ * GnuTLS has already verified the OCSP response in
+ * check_ocsp_response() and rejected handshake if the certificate was
+ * found to be revoked. However, if the response indicates that the
+ * status is unknown, handshake continues and reaches here. We need to
+ * re-import the OCSP response to check for unknown certificate status,
+ * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
+ * gnutls_ocsp_resp_verify_direct() calls.
+ */
+
+ res = gnutls_ocsp_status_request_get(session, &response);
+ if (res != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: OCSP response was received, but it was not valid");
+ goto ocsp_error;
+ }
+
+ if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
+ goto ocsp_error;
+
+ res = gnutls_ocsp_resp_import(resp, &response);
+ if (res != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: Could not parse received OCSP response: %s",
+ gnutls_strerror(res));
+ gnutls_ocsp_resp_deinit(resp);
+ goto ocsp_error;
+ }
+
+ res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
+ if (res == GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
+ gnutls_free(buf.data);
+ }
+
+ res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
+ NULL, &cert_status, NULL,
+ NULL, NULL, NULL);
+ gnutls_ocsp_resp_deinit(resp);
+ if (res != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: Failed to extract OCSP information: %s",
+ gnutls_strerror(res));
+ goto ocsp_error;
+ }
+
+ if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
+ } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP cert status: revoked");
+ goto ocsp_error;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP cert status: unknown");
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP)
+ goto ocsp_error;
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP was not required, so allow connection to continue");
+ }
+
+ return 0;
+
+ocsp_error:
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "bad certificate status response",
+ TLS_FAIL_REVOKED);
+ *err = GNUTLS_A_CERTIFICATE_REVOKED;
return -1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#else /* GnuTLS 3.1.3 or newer */
+ return 0;
+#endif /* GnuTLS 3.1.3 or newer */
}
-static int tls_connection_verify_peer(struct tls_connection *conn,
- gnutls_alert_description_t *err)
+static int tls_connection_verify_peer(gnutls_session_t session)
{
+ struct tls_connection *conn;
unsigned int status, num_certs, i;
struct os_time now;
const gnutls_datum_t *certs;
gnutls_x509_crt_t cert;
+ gnutls_alert_description_t err;
+ int res;
+
+ conn = gnutls_session_get_ptr(session);
+ if (!conn->verify_peer) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: No peer certificate verification enabled");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ {
+ gnutls_typed_vdata_st data[1];
+ unsigned int elements = 0;
- if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
+ os_memset(data, 0, sizeof(data));
+ if (!conn->global->server) {
+ data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
+ data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
+ elements++;
+ }
+ res = gnutls_certificate_verify_peers(session, data, 1,
+ &status);
+ }
+#else /* < 3.3.0 */
+ res = gnutls_certificate_verify_peers2(session, &status);
+#endif
+ if (res < 0) {
wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
"certificate chain");
- *err = GNUTLS_A_INTERNAL_ERROR;
- return -1;
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
+ }
+
+#if GNUTLS_VERSION_NUMBER >= 0x030104
+ {
+ gnutls_datum_t info;
+ int ret, type;
+
+ type = gnutls_certificate_type_get(session);
+ ret = gnutls_certificate_verification_status_print(status, type,
+ &info, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Failed to print verification status");
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
+ }
+ wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
+ gnutls_free(info.data);
+ }
+#endif /* GnuTLS 3.1.4 or newer */
+
+ certs = gnutls_certificate_get_peers(session, &num_certs);
+ if (certs == NULL || num_certs == 0) {
+ wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
+ err = GNUTLS_A_UNKNOWN_CA;
+ goto out;
}
if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
- *err = GNUTLS_A_INTERNAL_ERROR;
if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
"algorithm");
- *err = GNUTLS_A_INSUFFICIENT_SECURITY;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate uses insecure algorithm",
+ TLS_FAIL_BAD_CERTIFICATE);
+ err = GNUTLS_A_INSUFFICIENT_SECURITY;
+ goto out;
}
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (status & GNUTLS_CERT_NOT_ACTIVATED) {
wpa_printf(MSG_INFO, "TLS: Certificate not yet "
"activated");
- *err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate not yet valid",
+ TLS_FAIL_NOT_YET_VALID);
+ err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ goto out;
}
if (status & GNUTLS_CERT_EXPIRED) {
wpa_printf(MSG_INFO, "TLS: Certificate expired");
- *err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate has expired",
+ TLS_FAIL_EXPIRED);
+ err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ goto out;
}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
- return -1;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "untrusted certificate",
+ TLS_FAIL_UNTRUSTED);
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
}
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
"known issuer");
- *err = GNUTLS_A_UNKNOWN_CA;
- return -1;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
+ TLS_FAIL_UNTRUSTED);
+ err = GNUTLS_A_UNKNOWN_CA;
+ goto out;
}
if (status & GNUTLS_CERT_REVOKED) {
wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
- *err = GNUTLS_A_CERTIFICATE_REVOKED;
- return -1;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ err = GNUTLS_A_CERTIFICATE_REVOKED;
+ goto out;
}
- os_get_time(&now);
-
- certs = gnutls_certificate_get_peers(conn->session, &num_certs);
- if (certs == NULL) {
- wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
- "received");
- *err = GNUTLS_A_UNKNOWN_CA;
- return -1;
+ if (status != 0) {
+ wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
+ status);
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
}
+ if (check_ocsp(conn, session, &err))
+ goto out;
+
+ os_get_time(&now);
+
for (i = 0; i < num_certs; i++) {
char *buf;
size_t len;
if (gnutls_x509_crt_init(&cert) < 0) {
wpa_printf(MSG_INFO, "TLS: Certificate initialization "
"failed");
- *err = GNUTLS_A_BAD_CERTIFICATE;
- return -1;
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ goto out;
}
if (gnutls_x509_crt_import(cert, &certs[i],
@@ -877,8 +1067,8 @@ static int tls_connection_verify_peer(struct tls_connection *conn,
wpa_printf(MSG_INFO, "TLS: Could not parse peer "
"certificate %d/%d", i + 1, num_certs);
gnutls_x509_crt_deinit(cert);
- *err = GNUTLS_A_BAD_CERTIFICATE;
- return -1;
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ goto out;
}
gnutls_x509_crt_get_dn(cert, NULL, &len);
@@ -891,26 +1081,128 @@ static int tls_connection_verify_peer(struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
i + 1, num_certs, buf);
- if (i == 0) {
- /* TODO: validate subject_match and altsubject_match */
+ if (conn->global->event_cb) {
+ struct wpabuf *cert_buf = NULL;
+ union tls_event_data ev;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+ const u8 *_addr[1];
+ size_t _len[1];
+#endif /* CONFIG_SHA256 */
+
+ os_memset(&ev, 0, sizeof(ev));
+ if (conn->global->cert_in_cb) {
+ cert_buf = wpabuf_alloc_copy(certs[i].data,
+ certs[i].size);
+ ev.peer_cert.cert = cert_buf;
+ }
+#ifdef CONFIG_SHA256
+ _addr[0] = certs[i].data;
+ _len[0] = certs[i].size;
+ 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 = i;
+ ev.peer_cert.subject = buf;
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert_buf);
}
- os_free(buf);
+ if (i == 0) {
+ if (conn->suffix_match &&
+ !gnutls_x509_crt_check_hostname(
+ cert, conn->suffix_match)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain suffix match '%s' not found",
+ conn->suffix_match);
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "Domain suffix mismatch",
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ goto out;
+ }
- if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
- gnutls_x509_crt_get_activation_time(cert) > now.sec) {
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ if (conn->domain_match &&
+ !gnutls_x509_crt_check_hostname2(
+ cert, conn->domain_match,
+ GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain match '%s' not found",
+ conn->domain_match);
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ goto out;
+ }
+#endif /* >= 3.3.0 */
+
+ /* TODO: validate altsubject_match.
+ * For now, any such configuration is rejected in
+ * tls_connection_set_params() */
+
+#if GNUTLS_VERSION_NUMBER < 0x030300
+ /*
+ * gnutls_certificate_verify_peers() not available, so
+ * need to check EKU separately.
+ */
+ if (!conn->global->server &&
+ !server_eku_purpose(cert)) {
+ wpa_printf(MSG_WARNING,
+ "GnuTLS: No server EKU");
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "No server EKU",
+ TLS_FAIL_BAD_CERTIFICATE);
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ goto out;
+ }
+#endif /* < 3.3.0 */
+ }
+
+ if (!conn->disable_time_checks &&
+ (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
+ gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
"not valid at this time",
i + 1, num_certs);
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "Certificate is not valid at this time",
+ TLS_FAIL_EXPIRED);
gnutls_x509_crt_deinit(cert);
- *err = GNUTLS_A_CERTIFICATE_EXPIRED;
- return -1;
+ os_free(buf);
+ err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ goto out;
}
+ os_free(buf);
+
gnutls_x509_crt_deinit(cert);
}
+ if (conn->global->event_cb != NULL)
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
+
return 0;
+
+out:
+ conn->failed++;
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
+ return GNUTLS_E_CERTIFICATE_ERROR;
}
@@ -968,6 +1260,8 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
ret = gnutls_handshake(conn->session);
if (ret < 0) {
+ gnutls_alert_description_t alert;
+
switch (ret) {
case GNUTLS_E_AGAIN:
if (global->server && conn->established &&
@@ -978,10 +1272,20 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
}
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(
- gnutls_alert_get(conn->session)));
+ __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);
+ ev.alert.description = ev.alert.type;
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_ALERT, &ev);
+ }
/* continue */
default:
wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
@@ -990,18 +1294,21 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
}
} else {
size_t size;
- gnutls_alert_description_t err;
- if (conn->verify_peer &&
- tls_connection_verify_peer(conn, &err)) {
- wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
- "failed validation");
- conn->failed++;
- gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
- goto out;
+ wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
+
+#if GNUTLS_VERSION_NUMBER >= 0x03010a
+ {
+ char *desc;
+
+ desc = gnutls_session_get_desc(conn->session);
+ if (desc) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
+ gnutls_free(desc);
+ }
}
+#endif /* GnuTLS 3.1.10 or newer */
- wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
conn->established = 1;
if (conn->push_buf == NULL) {
/* Need to return something to get final TLS ACK. */
@@ -1025,7 +1332,6 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
*appl_data = gnutls_get_appl_data(conn);
}
-out:
out_data = conn->push_buf;
conn->push_buf = NULL;
return out_data;
@@ -1190,3 +1496,10 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
{
return -1;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
+ GNUTLS_VERSION, gnutls_check_version(NULL));
+}
diff --git a/contrib/wpa/src/crypto/tls_internal.c b/contrib/wpa/src/crypto/tls_internal.c
index 91f0690..0c955da 100644
--- a/contrib/wpa/src/crypto/tls_internal.c
+++ b/contrib/wpa/src/crypto/tls_internal.c
@@ -28,6 +28,7 @@ struct tls_global {
struct tls_connection {
struct tlsv1_client *client;
struct tlsv1_server *server;
+ struct tls_global *global;
};
@@ -85,6 +86,7 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->global = global;
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (!global->server) {
@@ -109,6 +111,28 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
}
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags)
+{
+ if (conn->server)
+ tlsv1_server_set_test_flags(conn->server, flags);
+}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void tls_connection_set_log_cb(struct tls_connection *conn,
+ void (*log_cb)(void *ctx, const char *msg),
+ void *ctx)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ tlsv1_server_set_log_cb(conn->server, log_cb, ctx);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+}
+
+
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
{
if (conn == NULL)
@@ -166,6 +190,31 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (cred == NULL)
return -1;
+ if (params->subject_match) {
+ wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+ return -1;
+ }
+
+ if (params->altsubject_match) {
+ wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+ return -1;
+ }
+
+ if (params->suffix_match) {
+ wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+ return -1;
+ }
+
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ return -1;
+ }
+
+ if (params->openssl_ciphers) {
+ wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+
if (tlsv1_set_ca_cert(cred, params->ca_cert,
params->ca_cert_blob, params->ca_cert_blob_len,
params->ca_path)) {
@@ -628,3 +677,9 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "internal");
+}
diff --git a/contrib/wpa/src/crypto/tls_none.c b/contrib/wpa/src/crypto/tls_none.c
index 1a1092a..a6d210a 100644
--- a/contrib/wpa/src/crypto/tls_none.c
+++ b/contrib/wpa/src/crypto/tls_none.c
@@ -192,3 +192,9 @@ unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "none");
+}
diff --git a/contrib/wpa/src/crypto/tls_nss.c b/contrib/wpa/src/crypto/tls_nss.c
deleted file mode 100644
index c53c192..0000000
--- a/contrib/wpa/src/crypto/tls_nss.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * SSL/TLS interface functions for NSS
- * 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 "includes.h"
-#include <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prio.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nspr/prinit.h>
-#include <nspr/prerror.h>
-#include <nspr/prmem.h>
-#include <nss/nss.h>
-#include <nss/nssilckt.h>
-#include <nss/ssl.h>
-#include <nss/pk11func.h>
-#include <nss/secerr.h>
-
-#include "common.h"
-#include "tls.h"
-
-static int tls_nss_ref_count = 0;
-
-static PRDescIdentity nss_layer_id;
-
-
-struct tls_connection {
- PRFileDesc *fd;
-
- int established;
- int verify_peer;
- u8 *push_buf, *pull_buf, *pull_buf_offset;
- size_t push_buf_len, pull_buf_len;
-};
-
-
-static PRStatus nss_io_close(PRFileDesc *fd)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O close");
- return PR_SUCCESS;
-}
-
-
-static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
- PRInt32 iov_size, PRIntervalTime timeout)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- struct tls_connection *conn = (struct tls_connection *) fd->secret;
- u8 *end;
-
- wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
-
- if (conn->pull_buf == NULL) {
- wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
- return PR_FAILURE;
- }
-
- end = conn->pull_buf + conn->pull_buf_len;
- if (end - conn->pull_buf_offset < amount)
- amount = end - conn->pull_buf_offset;
- os_memcpy(buf, conn->pull_buf_offset, amount);
- conn->pull_buf_offset += amount;
- if (conn->pull_buf_offset == end) {
- wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
- os_free(conn->pull_buf);
- conn->pull_buf = conn->pull_buf_offset = NULL;
- conn->pull_buf_len = 0;
- } else {
- wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
- __func__,
- (unsigned long) (end - conn->pull_buf_offset));
- }
- return amount;
-}
-
-
-static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- struct tls_connection *conn = (struct tls_connection *) fd->secret;
- u8 *nbuf;
-
- wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
- wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
-
- nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
- if (nbuf == NULL) {
- wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
- "data to be sent");
- return PR_FAILURE;
- }
- os_memcpy(nbuf + conn->push_buf_len, buf, amount);
- conn->push_buf = nbuf;
- conn->push_buf_len += amount;
-
- return amount;
-}
-
-
-static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
- PRIntn flags, PRNetAddr *addr,
- PRIntervalTime timeout)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
- PRIntn flags, const PRNetAddr *addr,
- PRIntervalTime timeout)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
- return PR_FAILURE;
-}
-
-
-static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
-
- /*
- * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
- * fake IPv4 address to work around this even though we are not really
- * using TCP.
- */
- os_memset(addr, 0, sizeof(*addr));
- addr->inet.family = PR_AF_INET;
-
- return PR_SUCCESS;
-}
-
-
-static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
- PRSocketOptionData *data)
-{
- switch (data->option) {
- case PR_SockOpt_Nonblocking:
- wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
- data->value.non_blocking = PR_TRUE;
- return PR_SUCCESS;
- default:
- wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
- data->option);
- return PR_FAILURE;
- }
-}
-
-
-static const PRIOMethods nss_io = {
- PR_DESC_LAYERED,
- nss_io_close,
- nss_io_read,
- nss_io_write,
- NULL /* available */,
- NULL /* available64 */,
- NULL /* fsync */,
- NULL /* fseek */,
- NULL /* fseek64 */,
- NULL /* fileinfo */,
- NULL /* fileinfo64 */,
- nss_io_writev,
- NULL /* connect */,
- NULL /* accept */,
- NULL /* bind */,
- NULL /* listen */,
- NULL /* shutdown */,
- nss_io_recv,
- nss_io_send,
- nss_io_recvfrom,
- nss_io_sendto,
- NULL /* poll */,
- NULL /* acceptread */,
- NULL /* transmitfile */,
- NULL /* getsockname */,
- nss_io_getpeername,
- NULL /* reserved_fn_6 */,
- NULL /* reserved_fn_5 */,
- nss_io_getsocketoption,
- NULL /* setsocketoption */,
- NULL /* sendfile */,
- NULL /* connectcontinue */,
- NULL /* reserved_fn_3 */,
- NULL /* reserved_fn_2 */,
- NULL /* reserved_fn_1 */,
- NULL /* reserved_fn_0 */
-};
-
-
-static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
-{
- wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
- return NULL;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
- char *dir;
-
- tls_nss_ref_count++;
- if (tls_nss_ref_count > 1)
- return (void *) 1;
-
- PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
-
- nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
-
- PK11_SetPasswordFunc(nss_password_cb);
-
- dir = getenv("SSL_DIR");
- if (dir) {
- if (NSS_Init(dir) != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
- "failed", dir);
- return NULL;
- }
- } else {
- if (NSS_NoDB_Init(NULL) != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
- "failed");
- return NULL;
- }
- }
-
- if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
- SECSuccess ||
- SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
- SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
- SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
- return NULL;
- }
-
- if (NSS_SetDomesticPolicy() != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
- return NULL;
- }
-
- return (void *) 1;
-}
-
-void tls_deinit(void *ssl_ctx)
-{
- tls_nss_ref_count--;
- if (tls_nss_ref_count == 0) {
- if (NSS_Shutdown() != SECSuccess)
- wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
- }
-}
-
-
-int tls_get_errors(void *tls_ctx)
-{
- return 0;
-}
-
-
-static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
-{
- struct tls_connection *conn = arg;
- SECStatus res = SECSuccess;
- PRErrorCode err;
- CERTCertificate *cert;
- char *subject, *issuer;
-
- err = PR_GetError();
- if (IS_SEC_ERROR(err))
- wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
- "%d)", err - SEC_ERROR_BASE);
- else
- wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
- err);
- cert = SSL_PeerCertificate(fd);
- subject = CERT_NameToAscii(&cert->subject);
- issuer = CERT_NameToAscii(&cert->issuer);
- wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
- subject, issuer);
- CERT_DestroyCertificate(cert);
- PR_Free(subject);
- PR_Free(issuer);
- if (conn->verify_peer)
- res = SECFailure;
-
- return res;
-}
-
-
-static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
-{
- struct tls_connection *conn = client_data;
- wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
- conn->established = 1;
-}
-
-
-struct tls_connection * tls_connection_init(void *tls_ctx)
-{
- struct tls_connection *conn;
-
- conn = os_zalloc(sizeof(*conn));
- if (conn == NULL)
- return NULL;
-
- conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
- if (conn->fd == NULL) {
- os_free(conn);
- return NULL;
- }
- conn->fd->secret = (void *) conn;
-
- conn->fd = SSL_ImportFD(NULL, conn->fd);
- if (conn->fd == NULL) {
- os_free(conn);
- return NULL;
- }
-
- if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
- SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
- SECSuccess ||
- SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
- SECSuccess ||
- SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
- SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
- SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
- SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: Failed to set options");
- PR_Close(conn->fd);
- os_free(conn);
- return NULL;
- }
-
- SSL_ResetHandshake(conn->fd, PR_FALSE);
-
- return conn;
-}
-
-
-void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
-{
- PR_Close(conn->fd);
- os_free(conn->push_buf);
- os_free(conn->pull_buf);
- os_free(conn);
-}
-
-
-int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
-{
- return conn->established;
-}
-
-
-int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
- const struct tls_connection_params *params)
-{
- wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
- return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
- const struct tls_connection_params *params)
-{
- return -1;
-}
-
-
-int tls_global_set_verify(void *tls_ctx, int check_crl)
-{
- return -1;
-}
-
-
-int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer)
-{
- conn->verify_peer = verify_peer;
- return 0;
-}
-
-
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
-{
- /* NSS does not export master secret or client/server random. */
- return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- u8 *out, size_t out_len)
-{
- if (conn == NULL || server_random_first) {
- wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
- "(server_random_first=%d)",
- server_random_first);
- return -1;
- }
-
- if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
- SECSuccess) {
- wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
- "(label='%s' out_len=%d", label, (int) out_len);
- return -1;
- }
-
- return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- struct wpabuf *out_data;
-
- wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
- in_data ? (unsigned int) wpabuf_len(in_data) : 0);
-
- if (appl_data)
- *appl_data = NULL;
-
- if (in_data && wpabuf_len(in_data) > 0) {
- if (conn->pull_buf) {
- wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
- "pull_buf", __func__,
- (unsigned long) conn->pull_buf_len);
- os_free(conn->pull_buf);
- }
- conn->pull_buf = os_malloc(wpabuf_len(in_data));
- if (conn->pull_buf == NULL)
- return NULL;
- os_memcpy(conn->pull_buf, wpabuf_head(in_data),
- wpabuf_len(in_data));
- conn->pull_buf_offset = conn->pull_buf;
- conn->pull_buf_len = wpabuf_len(in_data);
- }
-
- SSL_ForceHandshake(conn->fd);
-
- if (conn->established && conn->push_buf == NULL) {
- /* Need to return something to get final TLS ACK. */
- conn->push_buf = os_malloc(1);
- }
-
- if (conn->push_buf == NULL)
- return NULL;
- out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
- if (out_data == NULL)
- os_free(conn->push_buf);
- conn->push_buf = NULL;
- conn->push_buf_len = 0;
- return out_data;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- PRInt32 res;
- struct wpabuf *buf;
-
- wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
- (int) wpabuf_len(in_data));
- res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
- 0);
- if (res < 0) {
- wpa_printf(MSG_ERROR, "NSS: Encryption failed");
- return NULL;
- }
- if (conn->push_buf == NULL)
- return NULL;
- buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
- if (buf == NULL)
- os_free(conn->push_buf);
- conn->push_buf = NULL;
- conn->push_buf_len = 0;
- return buf;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- PRInt32 res;
- struct wpabuf *out;
-
- wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
- (int) wpabuf_len(in_data));
- if (conn->pull_buf) {
- wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
- "pull_buf", __func__,
- (unsigned long) conn->pull_buf_len);
- os_free(conn->pull_buf);
- }
- conn->pull_buf = os_malloc(wpabuf_len(in_data));
- if (conn->pull_buf == NULL)
- return NULL;
- os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
- conn->pull_buf_offset = conn->pull_buf;
- conn->pull_buf_len = wpabuf_len(in_data);
-
- /*
- * Even though we try to disable TLS compression, it is possible that
- * this cannot be done with all TLS libraries. Add extra buffer space
- * to handle the possibility of the decrypted data being longer than
- * input data.
- */
- out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
- if (out == NULL)
- return NULL;
-
- res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
- wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
- if (res < 0) {
- wpabuf_free(out);
- return NULL;
- }
- wpabuf_put(out, res);
-
- return out;
-}
-
-
-int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
- u8 *ciphers)
-{
- return -1;
-}
-
-
-int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
- char *buf, size_t buflen)
-{
- return -1;
-}
-
-
-int tls_connection_enable_workaround(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
- int ext_type, const u8 *data,
- size_t data_len)
-{
- return -1;
-}
-
-
-int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_get_write_alerts(void *tls_ctx,
- struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
- struct tls_connection *conn,
- tls_session_ticket_cb cb,
- void *ctx)
-{
- return -1;
-}
diff --git a/contrib/wpa/src/crypto/tls_openssl.c b/contrib/wpa/src/crypto/tls_openssl.c
index 2c3db47..52db8fc 100644
--- a/contrib/wpa/src/crypto/tls_openssl.c
+++ b/contrib/wpa/src/crypto/tls_openssl.c
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, 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,11 @@
#ifndef CONFIG_SMARTCARD
#ifndef OPENSSL_NO_ENGINE
+#ifndef ANDROID
#define OPENSSL_NO_ENGINE
#endif
#endif
+#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
@@ -22,51 +24,74 @@
#include <openssl/engine.h>
#endif /* OPENSSL_NO_ENGINE */
-#ifdef ANDROID
-#include <openssl/pem.h>
-#include "keystore_get.h"
-#endif /* ANDROID */
-
#include "common.h"
#include "crypto.h"
#include "tls.h"
-#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
-#define OPENSSL_d2i_TYPE const unsigned char **
-#else
-#define OPENSSL_d2i_TYPE unsigned char **
+#if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data)
+#define OPENSSL_SUPPORTS_CTX_APP_DATA
#endif
-#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
-#ifdef SSL_OP_NO_TICKET
-/*
- * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
- * 2008-11-15. This version uses a bit different API compared to the old patch.
- */
-#define CONFIG_OPENSSL_TICKET_OVERRIDE
+#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)
#endif
+
+#if defined(OPENSSL_IS_BORINGSSL)
+/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
+typedef size_t stack_index_t;
+#else
+typedef int stack_index_t;
#endif
+#ifdef SSL_set_tlsext_status_type
+#ifndef OPENSSL_NO_TLSEXT
+#define HAVE_OCSP
+#include <openssl/ocsp.h>
+#endif /* OPENSSL_NO_TLSEXT */
+#endif /* SSL_set_tlsext_status_type */
+
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include <keystore/keystore_get.h>
+
+static BIO * BIO_from_keystore(const char *key)
+{
+ BIO *bio = NULL;
+ uint8_t *value = NULL;
+ int length = keystore_get(key, strlen(key), &value);
+ if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+ BIO_write(bio, value, length);
+ free(value);
+ return bio;
+}
+#endif /* ANDROID */
+
static int tls_openssl_ref_count = 0;
-struct tls_global {
+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_global *tls_global = NULL;
+static struct tls_context *tls_global = NULL;
struct tls_connection {
+ struct tls_context *context;
+ SSL_CTX *ssl_ctx;
SSL *ssl;
BIO *ssl_in, *ssl_out;
#ifndef OPENSSL_NO_ENGINE
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
- char *subject_match, *altsubject_match;
+ char *subject_match, *altsubject_match, *suffix_match, *domain_match;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
@@ -79,13 +104,32 @@ struct tls_connection {
unsigned int ca_cert_verify:1;
unsigned int cert_probe:1;
unsigned int server_cert_only:1;
+ unsigned int invalid_hb_used:1;
u8 srv_cert_hash[32];
unsigned int flags;
+
+ X509 *peer_cert;
+ X509 *peer_issuer;
+ X509 *peer_issuer_issuer;
};
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+ struct tls_context *context = os_zalloc(sizeof(*context));
+ if (context == NULL)
+ return NULL;
+ if (conf) {
+ context->event_cb = conf->event_cb;
+ context->cb_ctx = conf->cb_ctx;
+ context->cert_in_cb = conf->cert_in_cb;
+ }
+ return context;
+}
+
+
#ifdef CONFIG_NO_STDOUT_DEBUG
static void _tls_show_errors(void)
@@ -351,7 +395,8 @@ static int tls_cryptoapi_cert(SSL *ssl, const char *name)
goto err;
}
- cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
+ cert = d2i_X509(NULL,
+ (const unsigned char **) &priv->cert->pbCertEncoded,
priv->cert->cbCertEncoded);
if (cert == NULL) {
wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
@@ -451,7 +496,8 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
}
while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
- cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
+ cert = d2i_X509(NULL,
+ (const unsigned char **) &ctx->pbCertEncoded,
ctx->cbCertEncoded);
if (cert == NULL) {
wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
@@ -511,6 +557,7 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
wpa_printf(MSG_DEBUG, "SSL: %s:%s",
str, SSL_state_string_long(ssl));
} else if (where & SSL_CB_ALERT) {
+ struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
where & SSL_CB_READ ?
"read (remote end reported an error)" :
@@ -518,21 +565,19 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
if ((ret >> 8) == SSL3_AL_FATAL) {
- struct tls_connection *conn =
- SSL_get_app_data((SSL *) ssl);
if (where & SSL_CB_READ)
conn->read_alerts++;
else
conn->write_alerts++;
}
- if (tls_global->event_cb != NULL) {
+ if (conn->context->event_cb != NULL) {
union tls_event_data ev;
+ struct tls_context *context = conn->context;
os_memset(&ev, 0, sizeof(ev));
ev.alert.is_local = !(where & SSL_CB_READ);
ev.alert.type = SSL_alert_type_string_long(ret);
ev.alert.description = SSL_alert_desc_string_long(ret);
- tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT,
- &ev);
+ context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
}
} else if (where & SSL_CB_EXIT && ret <= 0) {
wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
@@ -644,12 +689,15 @@ static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
NULL, NULL
};
- if (!pkcs11_so_path || !pkcs11_module_path)
+ if (!pkcs11_so_path)
return 0;
pre_cmd[1] = pkcs11_so_path;
pre_cmd[3] = engine_id;
- post_cmd[1] = pkcs11_module_path;
+ if (pkcs11_module_path)
+ post_cmd[1] = pkcs11_module_path;
+ else
+ post_cmd[0] = NULL;
wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
pkcs11_so_path);
@@ -690,17 +738,13 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
void * tls_init(const struct tls_config *conf)
{
SSL_CTX *ssl;
+ struct tls_context *context;
+ const char *ciphers;
if (tls_openssl_ref_count == 0) {
- tls_global = os_zalloc(sizeof(*tls_global));
- if (tls_global == NULL)
+ tls_global = context = tls_context_new(conf);
+ if (context == NULL)
return NULL;
- if (conf) {
- tls_global->event_cb = conf->event_cb;
- tls_global->cb_ctx = conf->cb_ctx;
- tls_global->cert_in_cb = conf->cert_in_cb;
- }
-
#ifdef CONFIG_FIPS
#ifdef OPENSSL_FIPS
if (conf && conf->fips_mode) {
@@ -727,7 +771,7 @@ void * tls_init(const struct tls_config *conf)
#endif /* CONFIG_FIPS */
SSL_load_error_strings();
SSL_library_init();
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+#ifndef OPENSSL_NO_SHA256
EVP_add_digest(EVP_sha256());
#endif /* OPENSSL_NO_SHA256 */
/* TODO: if /dev/urandom is available, PRNG is seeded
@@ -746,23 +790,48 @@ void * tls_init(const struct tls_config *conf)
#endif /* OPENSSL_NO_RC2 */
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
+ } else {
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ /* Newer OpenSSL can store app-data per-SSL */
+ context = tls_context_new(conf);
+ if (context == NULL)
+ return NULL;
+#else /* OPENSSL_SUPPORTS_CTX_APP_DATA */
+ context = tls_global;
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
}
tls_openssl_ref_count++;
- ssl = SSL_CTX_new(TLSv1_method());
- if (ssl == NULL)
+ ssl = SSL_CTX_new(SSLv23_method());
+ if (ssl == NULL) {
+ tls_openssl_ref_count--;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ if (context != tls_global)
+ os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
+ if (tls_openssl_ref_count == 0) {
+ os_free(tls_global);
+ tls_global = NULL;
+ }
return NULL;
+ }
+
+ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ SSL_CTX_set_app_data(ssl, context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
#ifndef OPENSSL_NO_ENGINE
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+ ERR_load_ENGINE_strings();
+ ENGINE_load_dynamic();
+
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
conf->pkcs11_module_path)) {
- wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
- ERR_load_ENGINE_strings();
- ENGINE_load_dynamic();
-
if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
conf->pkcs11_module_path)) {
@@ -772,6 +841,18 @@ void * tls_init(const struct tls_config *conf)
}
#endif /* OPENSSL_NO_ENGINE */
+ if (conf && conf->openssl_ciphers)
+ ciphers = conf->openssl_ciphers;
+ else
+ ciphers = "DEFAULT:!EXP:!LOW";
+ if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to set cipher string '%s'",
+ ciphers);
+ tls_deinit(ssl);
+ return NULL;
+ }
+
return ssl;
}
@@ -779,6 +860,11 @@ void * tls_init(const struct tls_config *conf)
void tls_deinit(void *ssl_ctx)
{
SSL_CTX *ssl = ssl_ctx;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ if (context != tls_global)
+ os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
@@ -787,9 +873,11 @@ void tls_deinit(void *ssl_ctx)
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
CRYPTO_cleanup_all_ex_data();
- ERR_remove_state(0);
+ ERR_remove_thread_state(NULL);
ERR_free_strings();
EVP_cleanup();
+ os_free(tls_global->ocsp_stapling_response);
+ tls_global->ocsp_stapling_response = NULL;
os_free(tls_global);
tls_global = NULL;
}
@@ -806,16 +894,11 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
return -1;
}
- if (pin == NULL) {
- wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
- return -1;
- }
- if (key_id == NULL) {
- wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
- return -1;
- }
ERR_clear_error();
+#ifdef ANDROID
+ ENGINE_load_dynamic();
+#endif
conn->engine = ENGINE_by_id(engine_id);
if (!conn->engine) {
wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
@@ -830,20 +913,35 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
}
wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
- if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+#ifndef ANDROID
+ if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
- /* load private key first in-case PIN is required for cert */
- conn->private_key = ENGINE_load_private_key(conn->engine,
- key_id, NULL, NULL);
- if (!conn->private_key) {
- wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
- " '%s' [%s]", key_id,
- ERR_error_string(ERR_get_error(), NULL));
- ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
- goto err;
+#endif
+ if (key_id) {
+ /*
+ * Ensure that the ENGINE does not attempt to use the OpenSSL
+ * UI system to obtain a PIN, if we didn't provide one.
+ */
+ struct {
+ const void *password;
+ const char *prompt_info;
+ } key_cb = { "", NULL };
+
+ /* load private key first in-case PIN is required for cert */
+ conn->private_key = ENGINE_load_private_key(conn->engine,
+ key_id, NULL,
+ &key_cb);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR,
+ "ENGINE: cannot load private key with id '%s' [%s]",
+ key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ goto err;
+ }
}
/* handle a certificate and/or CA certificate */
@@ -910,15 +1008,41 @@ int tls_get_errors(void *ssl_ctx)
return count;
}
+
+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);
+ 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);
+ if (payload_len + 3 > len) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected");
+ conn->invalid_hb_used = 1;
+ }
+ }
+}
+
+
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
SSL_CTX *ssl = ssl_ctx;
struct tls_connection *conn;
long options;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ struct tls_context *context = SSL_CTX_get_app_data(ssl);
+#else /* OPENSSL_SUPPORTS_CTX_APP_DATA */
+ struct tls_context *context = tls_global;
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->ssl_ctx = ssl_ctx;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
tls_show_errors(MSG_INFO, __func__,
@@ -927,7 +1051,10 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
return NULL;
}
+ conn->context = context;
SSL_set_app_data(conn->ssl, conn);
+ SSL_set_msg_callback(conn->ssl, tls_msg_cb);
+ SSL_set_msg_callback_arg(conn->ssl, conn);
options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_SINGLE_DH_USE;
#ifdef SSL_OP_NO_COMPRESSION
@@ -968,6 +1095,8 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
tls_engine_deinit(conn);
os_free(conn->subject_match);
os_free(conn->altsubject_match);
+ os_free(conn->suffix_match);
+ os_free(conn->domain_match);
os_free(conn->session_ticket);
os_free(conn);
}
@@ -998,7 +1127,8 @@ static int tls_match_altsubject_component(X509 *cert, int type,
{
GENERAL_NAME *gen;
void *ext;
- int i, found = 0;
+ int found = 0;
+ stack_index_t i;
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
@@ -1058,6 +1188,112 @@ 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 i, match_len;
+
+ /* Check for embedded nuls that could mess up suffix matching */
+ for (i = 0; i < len; i++) {
+ if (val[i] == '\0') {
+ wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
+ return 0;
+ }
+ }
+
+ match_len = os_strlen(match);
+ if (match_len > len || (full && match_len != len))
+ return 0;
+
+ if (os_strncasecmp((const char *) val + len - match_len, match,
+ match_len) != 0)
+ return 0; /* no match */
+
+ if (match_len == len)
+ return 1; /* exact match */
+
+ if (val[len - match_len - 1] == '.')
+ return 1; /* full label match completes suffix match */
+
+ wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+ return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int tls_match_suffix(X509 *cert, const char *match, 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;
+ stack_index_t j;
+ int dns_name = 0;
+ X509_NAME *name;
+
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+ full ? "": "suffix ", match);
+
+ ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+ for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
+ gen = sk_GENERAL_NAME_value(ext, j);
+ if (gen->type != GEN_DNS)
+ continue;
+ dns_name++;
+ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
+ gen->d.dNSName->data,
+ gen->d.dNSName->length);
+ if (domain_suffix_match(gen->d.dNSName->data,
+ gen->d.dNSName->length, match, full) ==
+ 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+ full ? "Match" : "Suffix match");
+ return 1;
+ }
+ }
+
+ if (dns_name) {
+ wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+ return 0;
+ }
+
+ name = X509_get_subject_name(cert);
+ i = -1;
+ for (;;) {
+ X509_NAME_ENTRY *e;
+ ASN1_STRING *cn;
+
+ i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
+ if (i == -1)
+ break;
+ e = X509_NAME_get_entry(name, i);
+ if (e == NULL)
+ continue;
+ cn = X509_NAME_ENTRY_get_data(e);
+ if (cn == NULL)
+ continue;
+ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
+ cn->data, cn->length);
+ if (domain_suffix_match(cn->data, cn->length, match, 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;
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
static enum tls_fail_reason openssl_tls_fail_reason(int err)
{
switch (err) {
@@ -1122,8 +1358,9 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
{
union tls_event_data ev;
struct wpabuf *cert = NULL;
+ struct tls_context *context = conn->context;
- if (tls_global->event_cb == NULL)
+ if (context->event_cb == NULL)
return;
cert = get_x509_cert(err_cert);
@@ -1134,7 +1371,7 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
ev.cert_fail.subject = subject;
ev.cert_fail.reason_txt = err_str;
ev.cert_fail.cert = cert;
- tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
wpabuf_free(cert);
}
@@ -1145,15 +1382,21 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
{
struct wpabuf *cert = NULL;
union tls_event_data ev;
+ struct tls_context *context = conn->context;
+ char *altsubject[TLS_MAX_ALT_SUBJECT];
+ int alt, num_altsubject = 0;
+ GENERAL_NAME *gen;
+ void *ext;
+ stack_index_t i;
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
- if (tls_global->event_cb == NULL)
+ if (context->event_cb == NULL)
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe || tls_global->cert_in_cb) {
+ if (conn->cert_probe || context->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
@@ -1171,8 +1414,52 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
#endif /* CONFIG_SHA256 */
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
- tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+
+ 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;
+
+ if (num_altsubject == TLS_MAX_ALT_SUBJECT)
+ break;
+ gen = sk_GENERAL_NAME_value(ext, i);
+ if (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI)
+ continue;
+
+ pos = os_malloc(10 + gen->d.ia5->length + 1);
+ if (pos == NULL)
+ break;
+ altsubject[num_altsubject++] = 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->d.ia5->data, gen->d.ia5->length);
+ pos += gen->d.ia5->length;
+ *pos = '\0';
+ }
+
+ for (alt = 0; alt < num_altsubject; alt++)
+ ev.peer_cert.altsubject[alt] = altsubject[alt];
+ ev.peer_cert.num_altsubject = num_altsubject;
+
+ context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
+ for (alt = 0; alt < num_altsubject; alt++)
+ os_free(altsubject[alt]);
}
@@ -1183,10 +1470,14 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
int err, depth;
SSL *ssl;
struct tls_connection *conn;
- char *match, *altmatch;
+ struct tls_context *context;
+ char *match, *altmatch, *suffix_match, *domain_match;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+ if (!err_cert)
+ return 0;
+
err = X509_STORE_CTX_get_error(x509_ctx);
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
@@ -1196,8 +1487,19 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
conn = SSL_get_app_data(ssl);
if (conn == NULL)
return 0;
+
+ if (depth == 0)
+ conn->peer_cert = err_cert;
+ else if (depth == 1)
+ conn->peer_issuer = err_cert;
+ else if (depth == 2)
+ conn->peer_issuer_issuer = err_cert;
+
+ context = conn->context;
match = conn->subject_match;
altmatch = conn->altsubject_match;
+ suffix_match = conn->suffix_match;
+ domain_match = conn->domain_match;
if (!preverify_ok && !conn->ca_cert_verify)
preverify_ok = 1;
@@ -1214,7 +1516,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
err_str = X509_verify_cert_error_string(err);
#ifdef CONFIG_SHA256
- if (preverify_ok && depth == 0 && conn->server_cert_only) {
+ /*
+ * 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) {
@@ -1232,6 +1538,14 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
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,
+ "OpenSSL: Ignore validation issues for a pinned server certificate");
+ preverify_ok = 1;
}
wpabuf_free(cert);
}
@@ -1266,6 +1580,22 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"AltSubject mismatch",
TLS_FAIL_ALTSUBJECT_MISMATCH);
+ } else if (depth == 0 && suffix_match &&
+ !tls_match_suffix(err_cert, suffix_match, 0)) {
+ wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
+ suffix_match);
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain suffix mismatch",
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ } else 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;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
} else
openssl_tls_cert_event(conn, err_cert, depth, buf);
@@ -1278,9 +1608,9 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
TLS_FAIL_SERVER_CHAIN_PROBE);
}
- if (preverify_ok && tls_global->event_cb != NULL)
- tls_global->event_cb(tls_global->cb_ctx,
- TLS_CERT_CHAIN_SUCCESS, NULL);
+ if (preverify_ok && context->event_cb != NULL)
+ context->event_cb(context->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
return preverify_ok;
}
@@ -1293,7 +1623,7 @@ static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
X509_LOOKUP *lookup;
int ret = 0;
- lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
+ lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
X509_LOOKUP_file());
if (lookup == NULL) {
tls_show_errors(MSG_WARNING, __func__,
@@ -1319,36 +1649,24 @@ static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
#endif /* OPENSSL_NO_STDIO */
-#ifdef ANDROID
-static BIO * BIO_from_keystore(const char *key)
-{
- BIO *bio = NULL;
- char value[KEYSTORE_MESSAGE_SIZE];
- int length = keystore_get(key, strlen(key), value);
- if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
- BIO_write(bio, value, length);
- return bio;
-}
-#endif /* ANDROID */
-
-
static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
const char *ca_cert, const u8 *ca_cert_blob,
size_t ca_cert_blob_len, const char *ca_path)
{
SSL_CTX *ssl_ctx = _ssl_ctx;
+ X509_STORE *store;
/*
* Remove previously configured trusted CA certificates before adding
* new ones.
*/
- X509_STORE_free(ssl_ctx->cert_store);
- ssl_ctx->cert_store = X509_STORE_new();
- if (ssl_ctx->cert_store == NULL) {
+ store = X509_STORE_new();
+ if (store == NULL) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
"certificate store", __func__);
return -1;
}
+ SSL_CTX_set_cert_store(ssl_ctx, store);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
conn->ca_cert_verify = 1;
@@ -1392,7 +1710,8 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
}
if (ca_cert_blob) {
- X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
+ X509 *cert = d2i_X509(NULL,
+ (const unsigned char **) &ca_cert_blob,
ca_cert_blob_len);
if (cert == NULL) {
tls_show_errors(MSG_WARNING, __func__,
@@ -1400,7 +1719,8 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
return -1;
}
- if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+ cert)) {
unsigned long err = ERR_peek_error();
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert_blob to "
@@ -1426,7 +1746,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
BIO *bio = BIO_from_keystore(&ca_cert[11]);
STACK_OF(X509_INFO) *stack = NULL;
- int i;
+ stack_index_t i;
if (bio) {
stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
@@ -1541,7 +1861,9 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
static int tls_connection_set_subject_match(struct tls_connection *conn,
const char *subject_match,
- const char *altsubject_match)
+ const char *altsubject_match,
+ const char *suffix_match,
+ const char *domain_match)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -1559,6 +1881,22 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
return -1;
}
+ os_free(conn->suffix_match);
+ conn->suffix_match = NULL;
+ if (suffix_match) {
+ conn->suffix_match = os_strdup(suffix_match);
+ if (conn->suffix_match == NULL)
+ return -1;
+ }
+
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (domain_match) {
+ conn->domain_match = os_strdup(domain_match);
+ if (conn->domain_match == NULL)
+ return -1;
+ }
+
return 0;
}
@@ -1813,7 +2151,7 @@ static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
#ifdef PKCS12_FUNCS
PKCS12 *p12;
- p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
+ p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
if (p12 == NULL) {
tls_show_errors(MSG_INFO, __func__,
"Failed to use PKCS#12 blob");
@@ -1894,20 +2232,21 @@ static int tls_connection_engine_ca_cert(void *_ssl_ctx,
#ifndef OPENSSL_NO_ENGINE
X509 *cert;
SSL_CTX *ssl_ctx = _ssl_ctx;
+ X509_STORE *store;
if (tls_engine_get_cert(conn, ca_cert_id, &cert))
return -1;
/* start off the same as tls_connection_ca_cert */
- X509_STORE_free(ssl_ctx->cert_store);
- ssl_ctx->cert_store = X509_STORE_new();
- if (ssl_ctx->cert_store == NULL) {
+ store = X509_STORE_new();
+ if (store == NULL) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
"certificate store", __func__);
X509_free(cert);
return -1;
}
- if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ SSL_CTX_set_cert_store(ssl_ctx, store);
+ if (!X509_STORE_add_cert(store, cert)) {
unsigned long err = ERR_peek_error();
tls_show_errors(MSG_WARNING, __func__,
"Failed to add CA certificate from engine "
@@ -2022,26 +2361,6 @@ static int tls_connection_private_key(void *_ssl_ctx,
break;
}
-#ifdef ANDROID
- if (!ok && private_key &&
- os_strncmp("keystore://", private_key, 11) == 0) {
- BIO *bio = BIO_from_keystore(&private_key[11]);
- EVP_PKEY *pkey = NULL;
- if (bio) {
- pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
- BIO_free(bio);
- }
- if (pkey) {
- if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Private key "
- "from keystore");
- ok = 1;
- }
- EVP_PKEY_free(pkey);
- }
- }
-#endif /* ANDROID */
-
while (!ok && private_key) {
#ifndef OPENSSL_NO_STDIO
if (SSL_use_PrivateKey_file(conn->ssl, private_key,
@@ -2463,10 +2782,25 @@ openssl_connection_handshake(struct tls_connection *conn,
out_data = openssl_handshake(conn, in_data, server);
if (out_data == NULL)
return NULL;
+ if (conn->invalid_hb_used) {
+ wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
+ wpabuf_free(out_data);
+ return NULL;
+ }
if (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
*appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
+ if (conn->invalid_hb_used) {
+ wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
+ if (appl_data) {
+ wpabuf_free(*appl_data);
+ *appl_data = NULL;
+ }
+ wpabuf_free(out_data);
+ return NULL;
+ }
+
return out_data;
}
@@ -2568,13 +2902,23 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
}
wpabuf_put(buf, res);
+ if (conn->invalid_hb_used) {
+ wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
+ wpabuf_free(buf);
+ return NULL;
+ }
+
return buf;
}
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
}
@@ -2615,7 +2959,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
return -1;
}
ret = os_snprintf(pos, end - pos, ":%s", suite);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
@@ -2670,15 +3014,9 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL || conn->ssl == NULL || ext_type != 35)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
data_len) != 1)
return -1;
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
- if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
- data_len) != 1)
- return -1;
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
return 0;
}
@@ -2709,36 +3047,332 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
}
+#ifdef HAVE_OCSP
+
+static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ OCSP_RESPONSE_print(out, rsp, 0);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (!txt) {
+ BIO_free(out);
+ return;
+ }
+
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
+ }
+ os_free(txt);
+ BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static void debug_print_cert(X509 *cert, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ X509_print(out, cert);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (!txt) {
+ BIO_free(out);
+ return;
+ }
+
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
+ }
+ os_free(txt);
+
+ BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int ocsp_resp_cb(SSL *s, void *arg)
+{
+ struct tls_connection *conn = arg;
+ const unsigned char *p;
+ int len, status, reason;
+ OCSP_RESPONSE *rsp;
+ OCSP_BASICRESP *basic;
+ OCSP_CERTID *id;
+ ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
+ X509_STORE *store;
+ STACK_OF(X509) *certs = NULL;
+
+ len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+ if (!p) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+ return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
+
+ rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+ if (!rsp) {
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
+ return 0;
+ }
+
+ ocsp_debug_print_resp(rsp);
+
+ status = OCSP_response_status(rsp);
+ if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
+ status, OCSP_response_status_str(status));
+ return 0;
+ }
+
+ basic = OCSP_response_get1_basic(rsp);
+ if (!basic) {
+ wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
+ return 0;
+ }
+
+ store = SSL_CTX_get_cert_store(conn->ssl_ctx);
+ if (conn->peer_issuer) {
+ debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
+
+ if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to certificate store");
+ }
+ certs = sk_X509_new_null();
+ if (certs) {
+ X509 *cert;
+ cert = X509_dup(conn->peer_issuer);
+ if (cert && !sk_X509_push(certs, cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to OCSP responder trust store");
+ X509_free(cert);
+ sk_X509_free(certs);
+ certs = NULL;
+ }
+ if (certs && conn->peer_issuer_issuer) {
+ cert = X509_dup(conn->peer_issuer_issuer);
+ if (cert && !sk_X509_push(certs, cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
+ X509_free(cert);
+ }
+ }
+ }
+ }
+
+ status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
+ sk_X509_pop_free(certs, X509_free);
+ if (status <= 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "OpenSSL: OCSP response failed verification");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
+
+ if (!conn->peer_cert) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return 0;
+ }
+
+ if (!conn->peer_issuer) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return 0;
+ }
+
+ id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+ if (!id) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return 0;
+ }
+
+ if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+ &this_update, &next_update)) {
+ wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
+ (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
+ " (OCSP not required)");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+ }
+
+ if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
+ tls_show_errors(MSG_INFO, __func__,
+ "OpenSSL: OCSP status times invalid");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return 0;
+ }
+
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
+ OCSP_cert_status_str(status));
+
+ if (status == V_OCSP_CERTSTATUS_GOOD)
+ return 1;
+ if (status == V_OCSP_CERTSTATUS_REVOKED)
+ return 0;
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
+ return 1;
+}
+
+
+static int ocsp_status_cb(SSL *s, void *arg)
+{
+ char *tmp;
+ char *resp;
+ size_t len;
+
+ if (tls_global->ocsp_stapling_response == NULL) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
+ return SSL_TLSEXT_ERR_OK;
+ }
+
+ resp = os_readfile(tls_global->ocsp_stapling_response, &len);
+ if (resp == NULL) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
+ /* TODO: Build OCSPResponse with responseStatus = internalError
+ */
+ return SSL_TLSEXT_ERR_OK;
+ }
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
+ tmp = OPENSSL_malloc(len);
+ if (tmp == NULL) {
+ os_free(resp);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ os_memcpy(tmp, resp, len);
+ os_free(resp);
+ SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+#endif /* HAVE_OCSP */
+
+
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
int ret;
unsigned long err;
+ int can_pkcs11 = 0;
+ const char *key_id = params->key_id;
+ 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;
if (conn == NULL)
return -1;
+ /*
+ * If the engine isn't explicitly configured, and any of the
+ * cert/key fields are actually PKCS#11 URIs, then automatically
+ * use the PKCS#11 ENGINE.
+ */
+ if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
+ can_pkcs11 = 1;
+
+ if (!key_id && params->private_key && can_pkcs11 &&
+ os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ key_id = params->private_key;
+ }
+
+ if (!cert_id && params->client_cert && can_pkcs11 &&
+ os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ cert_id = params->client_cert;
+ }
+
+ if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
+ os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ ca_cert_id = params->ca_cert;
+ }
+
+ /* If we need to automatically enable the PKCS#11 ENGINE, do so. */
+ if (can_pkcs11 == 2 && !engine_id)
+ engine_id = "pkcs11";
+
+ if (params->flags & TLS_CONN_EAP_FAST) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Use TLSv1_method() for EAP-FAST");
+ if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to set TLSv1_method() for EAP-FAST");
+ return -1;
+ }
+ }
+
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
__func__, ERR_error_string(err, NULL));
}
- if (params->engine) {
+ if (engine_id) {
wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
- ret = tls_engine_init(conn, params->engine_id, params->pin,
- params->key_id, params->cert_id,
- params->ca_cert_id);
+ ret = tls_engine_init(conn, engine_id, params->pin,
+ key_id, cert_id, ca_cert_id);
if (ret)
return ret;
}
if (tls_connection_set_subject_match(conn,
params->subject_match,
- params->altsubject_match))
+ params->altsubject_match,
+ params->suffix_match,
+ params->domain_match))
return -1;
- if (params->engine && params->ca_cert_id) {
+ if (engine_id && ca_cert_id) {
if (tls_connection_engine_ca_cert(tls_ctx, conn,
- params->ca_cert_id))
+ ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
params->ca_cert_blob,
@@ -2746,15 +3380,15 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
params->ca_path))
return -1;
- if (params->engine && params->cert_id) {
- if (tls_connection_engine_client_cert(conn, params->cert_id))
+ if (engine_id && cert_id) {
+ if (tls_connection_engine_client_cert(conn, cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_client_cert(conn, params->client_cert,
params->client_cert_blob,
params->client_cert_blob_len))
return -1;
- if (params->engine && params->key_id) {
+ if (engine_id && key_id) {
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
@@ -2774,13 +3408,45 @@ 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) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+#ifdef SSL_clear_options
else
SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
+#ifdef SSL_OP_NO_TLSv1_1
+ if (params->flags & TLS_CONN_DISABLE_TLSv1_1)
+ SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_1);
+ else
+ SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_1);
+#endif /* SSL_OP_NO_TLSv1_1 */
+#ifdef SSL_OP_NO_TLSv1_2
+ if (params->flags & TLS_CONN_DISABLE_TLSv1_2)
+ SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_2);
+ else
+ SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_2);
+#endif /* SSL_OP_NO_TLSv1_2 */
+
+#ifdef HAVE_OCSP
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ SSL_CTX *ssl_ctx = tls_ctx;
+ SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
+ SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
+ SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
+ }
+#endif /* HAVE_OCSP */
+
conn->flags = params->flags;
tls_get_errors(tls_ctx);
@@ -2816,13 +3482,34 @@ int tls_global_set_params(void *tls_ctx,
return -1;
}
+ if (params->openssl_ciphers &&
+ SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+#ifdef SSL_CTX_clear_options
else
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
+#ifdef HAVE_OCSP
+ SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
+ SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
+ os_free(tls_global->ocsp_stapling_response);
+ if (params->ocsp_stapling_response)
+ tls_global->ocsp_stapling_response =
+ os_strdup(params->ocsp_stapling_response);
+ else
+ tls_global->ocsp_stapling_response = NULL;
+#endif /* HAVE_OCSP */
+
return 0;
}
@@ -2875,9 +3562,15 @@ unsigned int tls_capabilities(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
+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)
+#else /* OPENSSL_IS_BORINGSSL */
static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
SSL_CIPHER **cipher, void *arg)
+#endif /* OPENSSL_IS_BORINGSSL */
{
struct tls_connection *conn = arg;
int ret;
@@ -2901,7 +3594,6 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
}
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
int len, void *arg)
{
@@ -2927,62 +3619,6 @@ static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
return 1;
}
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-static void tls_hello_ext_cb(SSL *s, int client_server, int type,
- unsigned char *data, int len, void *arg)
-{
- struct tls_connection *conn = arg;
-
- if (conn == NULL || conn->session_ticket_cb == NULL)
- return;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
- type, len);
-
- if (type == TLSEXT_TYPE_session_ticket && !client_server) {
- os_free(conn->session_ticket);
- conn->session_ticket = NULL;
-
- wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
- "extension", data, len);
- conn->session_ticket = os_malloc(len);
- if (conn->session_ticket == NULL)
- return;
-
- os_memcpy(conn->session_ticket, data, len);
- conn->session_ticket_len = len;
- }
-}
-#else /* SSL_OP_NO_TICKET */
-static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
-{
- struct tls_connection *conn = arg;
-
- if (conn == NULL || conn->session_ticket_cb == NULL)
- return 0;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
- ext->type, ext->length);
-
- os_free(conn->session_ticket);
- conn->session_ticket = NULL;
-
- if (ext->type == 35) {
- wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
- "extension", ext->data, ext->length);
- conn->session_ticket = os_malloc(ext->length);
- if (conn->session_ticket == NULL)
- return SSL_AD_INTERNAL_ERROR;
-
- os_memcpy(conn->session_ticket, ext->data, ext->length);
- conn->session_ticket_len = ext->length;
- }
-
- return 0;
-}
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
@@ -2999,33 +3635,12 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
conn) != 1)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl,
tls_session_ticket_ext_cb, conn);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
- SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
- SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
- if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
- conn) != 1)
- return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
} else {
if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
- SSL_set_tlsext_debug_callback(conn->ssl, NULL);
- SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
- if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
- return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
}
return 0;
@@ -3033,3 +3648,11 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
return -1;
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+ OPENSSL_VERSION_TEXT,
+ SSLeay_version(SSLEAY_VERSION));
+}
diff --git a/contrib/wpa/src/crypto/tls_schannel.c b/contrib/wpa/src/crypto/tls_schannel.c
index 2c2daa8..31a2c94 100644
--- a/contrib/wpa/src/crypto/tls_schannel.c
+++ b/contrib/wpa/src/crypto/tls_schannel.c
@@ -692,6 +692,31 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (conn == NULL)
return -1;
+ if (params->subject_match) {
+ wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+ return -1;
+ }
+
+ if (params->altsubject_match) {
+ wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+ return -1;
+ }
+
+ if (params->suffix_match) {
+ wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+ return -1;
+ }
+
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ return -1;
+ }
+
+ if (params->openssl_ciphers) {
+ wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+
if (global->my_cert_store == NULL &&
(global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
NULL) {
@@ -730,3 +755,9 @@ unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "schannel");
+}
diff --git a/contrib/wpa/src/drivers/driver.h b/contrib/wpa/src/drivers/driver.h
index 7ee71aa..03bd1a7 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,14 +20,51 @@
#define WPA_SUPPLICANT_DRIVER_VERSION 4
#include "common/defs.h"
+#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
-#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
-#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_NO_IR 0x00000002
#define HOSTAPD_CHAN_RADAR 0x00000008
#define HOSTAPD_CHAN_HT40PLUS 0x00000010
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
#define HOSTAPD_CHAN_HT40 0x00000040
+#define HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED 0x00000080
+
+#define HOSTAPD_CHAN_DFS_UNKNOWN 0x00000000
+#define HOSTAPD_CHAN_DFS_USABLE 0x00000100
+#define HOSTAPD_CHAN_DFS_UNAVAILABLE 0x00000200
+#define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
+#define HOSTAPD_CHAN_DFS_MASK 0x00000300
+
+#define HOSTAPD_CHAN_VHT_10_70 0x00000800
+#define HOSTAPD_CHAN_VHT_30_50 0x00001000
+#define HOSTAPD_CHAN_VHT_50_30 0x00002000
+#define HOSTAPD_CHAN_VHT_70_10 0x00004000
+
+#define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
+#define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
+
+/**
+ * enum reg_change_initiator - Regulatory change initiator
+ */
+enum reg_change_initiator {
+ REGDOM_SET_BY_CORE,
+ REGDOM_SET_BY_USER,
+ REGDOM_SET_BY_DRIVER,
+ REGDOM_SET_BY_COUNTRY_IE,
+ REGDOM_BEACON_HINT,
+};
+
+/**
+ * enum reg_type - Regulatory change types
+ */
+enum reg_type {
+ REGDOM_TYPE_UNKNOWN,
+ REGDOM_TYPE_COUNTRY,
+ REGDOM_TYPE_WORLD,
+ REGDOM_TYPE_CUSTOM_WORLD,
+ REGDOM_TYPE_INTERSECTION,
+};
/**
* struct hostapd_channel_data - Channel information
@@ -49,12 +86,38 @@ struct hostapd_channel_data {
int flag;
/**
- * max_tx_power - maximum transmit power in dBm
+ * max_tx_power - Regulatory transmit power limit in dBm
*/
u8 max_tx_power;
+
+ /**
+ * survey_list - Linked list of surveys (struct freq_survey)
+ */
+ struct dl_list survey_list;
+
+ /**
+ * min_nf - Minimum observed noise floor, in dBm, based on all
+ * surveyed channel data
+ */
+ s8 min_nf;
+
+#ifdef CONFIG_ACS
+ /**
+ * interference_factor - Computed interference factor on this
+ * channel (used internally in src/ap/acs.c; driver wrappers do not
+ * need to set this)
+ */
+ long double interference_factor;
+#endif /* CONFIG_ACS */
+
+ /**
+ * dfs_cac_ms - DFS CAC time in milliseconds
+ */
+ unsigned int dfs_cac_ms;
};
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
/**
* struct hostapd_hw_modes - Supported hardware mode information
@@ -117,16 +180,24 @@ struct hostapd_hw_modes {
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
#define IEEE80211_MODE_AP 2
+#define IEEE80211_MODE_MESH 5
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
+#define IEEE80211_CAP_RRM 0x1000
+
+/* DMG (60 GHz) IEEE 802.11ad */
+/* type - bits 0..1 */
+#define IEEE80211_CAP_DMG_MASK 0x0003
+#define IEEE80211_CAP_DMG_IBSS 0x0001 /* Tx by: STA */
+#define IEEE80211_CAP_DMG_PBSS 0x0002 /* Tx by: PCP */
+#define IEEE80211_CAP_DMG_AP 0x0003 /* Tx by: AP */
#define WPA_SCAN_QUAL_INVALID BIT(0)
#define WPA_SCAN_NOISE_INVALID BIT(1)
#define WPA_SCAN_LEVEL_INVALID BIT(2)
#define WPA_SCAN_LEVEL_DBM BIT(3)
-#define WPA_SCAN_AUTHENTICATED BIT(4)
#define WPA_SCAN_ASSOCIATED BIT(5)
/**
@@ -142,6 +213,9 @@ struct hostapd_hw_modes {
* @tsf: Timestamp
* @age: Age of the information in milliseconds (i.e., how many milliseconds
* ago the last Beacon or Probe Response frame was received)
+ * @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)
* @ie_len: length of the following IE field in octets
* @beacon_ie_len: length of the following Beacon IE field in octets
*
@@ -153,6 +227,11 @@ struct hostapd_hw_modes {
* constructed of the IEs that are available. This field will also need to
* include SSID in IE format. All drivers are encouraged to be extended to
* report all IEs to make it easier to support future additions.
+ *
+ * This structure data is followed by ie_len octets of IEs from Probe Response
+ * frame (or if the driver does not indicate source of IEs, these may also be
+ * from Beacon frame). After the first set of IEs, another set of IEs may follow
+ * (with beacon_ie_len octets of data) if the driver provides both IE sets.
*/
struct wpa_scan_res {
unsigned int flags;
@@ -165,25 +244,23 @@ struct wpa_scan_res {
int level;
u64 tsf;
unsigned int age;
+ unsigned int est_throughput;
+ int snr;
size_t ie_len;
size_t beacon_ie_len;
- /*
- * Followed by ie_len octets of IEs from Probe Response frame (or if
- * the driver does not indicate source of IEs, these may also be from
- * Beacon frame). After the first set of IEs, another set of IEs may
- * follow (with beacon_ie_len octets of data) if the driver provides
- * both IE sets.
- */
+ /* Followed by ie_len + beacon_ie_len octets of IE data */
};
/**
* struct wpa_scan_results - Scan results
* @res: Array of pointers to allocated variable length scan result entries
* @num: Number of entries in the scan result array
+ * @fetch_time: Time when the results were fetched from the driver
*/
struct wpa_scan_results {
struct wpa_scan_res **res;
size_t num;
+ struct os_reltime fetch_time;
};
/**
@@ -289,7 +366,51 @@ struct wpa_driver_scan_params {
* Mbps from the support rates element(s) in the Probe Request frames
* and not to transmit the frames at any of those rates.
*/
- u8 p2p_probe;
+ unsigned int p2p_probe:1;
+
+ /**
+ * only_new_results - Request driver to report only new results
+ *
+ * This is used to request the driver to report only BSSes that have
+ * been detected after this scan request has been started, i.e., to
+ * flush old cached BSS entries.
+ */
+ unsigned int only_new_results:1;
+
+ /**
+ * low_priority - Requests driver to use a lower scan priority
+ *
+ * This is used to request the driver to use a lower scan priority
+ * if it supports such a thing.
+ */
+ unsigned int low_priority:1;
+
+ /**
+ * mac_addr_rand - Requests driver to randomize MAC address
+ */
+ unsigned int mac_addr_rand:1;
+
+ /**
+ * mac_addr - MAC address used with randomization. The address cannot be
+ * a multicast one, i.e., bit 0 of byte 0 should not be set.
+ */
+ const u8 *mac_addr;
+
+ /**
+ * mac_addr_mask - MAC address mask used with randomization.
+ *
+ * Bits that are 0 in the mask should be randomized. Bits that are 1 in
+ * the mask should be taken as is from mac_addr. The mask should not
+ * allow the generation of a multicast address, i.e., bit 0 of byte 0
+ * must be set.
+ */
+ const u8 *mac_addr_mask;
+
+ /*
+ * NOTE: Whenever adding new parameters here, please make sure
+ * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
+ * matching changes.
+ */
};
/**
@@ -314,16 +435,96 @@ struct wpa_driver_auth_params {
*/
int p2p;
+ /**
+ * sae_data - SAE elements for Authentication frame
+ *
+ * This buffer starts with the Authentication transaction sequence
+ * number field. If SAE is not used, this pointer is %NULL.
+ */
const u8 *sae_data;
- size_t sae_data_len;
+ /**
+ * sae_data_len - Length of sae_data buffer in octets
+ */
+ size_t sae_data_len;
};
+/**
+ * enum wps_mode - WPS mode
+ */
enum wps_mode {
- WPS_MODE_NONE /* no WPS provisioning being used */,
- WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
- WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
- */
+ /**
+ * WPS_MODE_NONE - No WPS provisioning being used
+ */
+ WPS_MODE_NONE,
+
+ /**
+ * WPS_MODE_OPEN - WPS provisioning with AP that is in open mode
+ */
+ WPS_MODE_OPEN,
+
+ /**
+ * WPS_MODE_PRIVACY - WPS provisioning with AP that is using protection
+ */
+ WPS_MODE_PRIVACY
+};
+
+/**
+ * struct hostapd_freq_params - Channel parameters
+ */
+struct hostapd_freq_params {
+ /**
+ * mode - Mode/band (HOSTAPD_MODE_IEEE80211A, ..)
+ */
+ enum hostapd_hw_mode mode;
+
+ /**
+ * freq - Primary channel center frequency in MHz
+ */
+ int freq;
+
+ /**
+ * channel - Channel number
+ */
+ int channel;
+
+ /**
+ * ht_enabled - Whether HT is enabled
+ */
+ int ht_enabled;
+
+ /**
+ * sec_channel_offset - Secondary channel offset for HT40
+ *
+ * 0 = HT40 disabled,
+ * -1 = HT40 enabled, secondary channel below primary,
+ * 1 = HT40 enabled, secondary channel above primary
+ */
+ int sec_channel_offset;
+
+ /**
+ * vht_enabled - Whether VHT is enabled
+ */
+ int vht_enabled;
+
+ /**
+ * center_freq1 - Segment 0 center frequency in MHz
+ *
+ * Valid for both HT and VHT.
+ */
+ int center_freq1;
+
+ /**
+ * center_freq2 - Segment 1 center frequency in MHz
+ *
+ * Non-zero only for bandwidth 80 and an 80+80 channel
+ */
+ int center_freq2;
+
+ /**
+ * bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
+ */
+ int bandwidth;
};
/**
@@ -338,6 +539,16 @@ struct wpa_driver_associate_params {
const u8 *bssid;
/**
+ * bssid_hint - BSSID of a proposed AP
+ *
+ * This indicates which BSS has been found a suitable candidate for
+ * initial association for drivers that use driver/firmwate-based BSS
+ * selection. Unlike the @bssid parameter, @bssid_hint does not limit
+ * the driver from selecting other BSSes in the ESS.
+ */
+ const u8 *bssid_hint;
+
+ /**
* ssid - The selected SSID
*/
const u8 *ssid;
@@ -348,11 +559,19 @@ struct wpa_driver_associate_params {
size_t ssid_len;
/**
- * freq - Frequency of the channel the selected AP is using
- * Frequency that the selected AP is using (in MHz as
- * reported in the scan results)
+ * freq - channel parameters
*/
- int freq;
+ struct hostapd_freq_params freq;
+
+ /**
+ * freq_hint - Frequency of the channel the proposed AP is using
+ *
+ * This provides a channel on which a suitable BSS has been found as a
+ * hint for the driver. Unlike the @freq parameter, @freq_hint does not
+ * limit the driver from selecting other channels for
+ * driver/firmware-based BSS selection.
+ */
+ int freq_hint;
/**
* bg_scan_period - Background scan period in seconds, 0 to disable
@@ -362,6 +581,11 @@ struct wpa_driver_associate_params {
int bg_scan_period;
/**
+ * beacon_int - Beacon interval for IBSS or 0 to use driver default
+ */
+ int beacon_int;
+
+ /**
* wpa_ie - WPA information element for (Re)Association Request
* WPA information element to be included in (Re)Association
* Request (including information element id and length). Use
@@ -392,25 +616,25 @@ struct wpa_driver_associate_params {
unsigned int wpa_proto;
/**
- * pairwise_suite - Selected pairwise cipher suite
+ * pairwise_suite - Selected pairwise cipher suite (WPA_CIPHER_*)
*
* This is usually ignored if @wpa_ie is used.
*/
- enum wpa_cipher pairwise_suite;
+ unsigned int pairwise_suite;
/**
- * group_suite - Selected group cipher suite
+ * group_suite - Selected group cipher suite (WPA_CIPHER_*)
*
* This is usually ignored if @wpa_ie is used.
*/
- enum wpa_cipher group_suite;
+ unsigned int group_suite;
/**
- * key_mgmt_suite - Selected key management suite
+ * key_mgmt_suite - Selected key management suite (WPA_KEY_MGMT_*)
*
* This is usually ignored if @wpa_ie is used.
*/
- enum wpa_key_mgmt key_mgmt_suite;
+ unsigned int key_mgmt_suite;
/**
* auth_alg - Allowed authentication algorithms
@@ -548,17 +772,61 @@ struct wpa_driver_associate_params {
int fixed_bssid;
/**
+ * fixed_freq - Fix control channel in IBSS mode
+ * 0 = don't fix control channel (default)
+ * 1 = fix control channel; this prevents IBSS merging with another
+ * channel
+ */
+ int fixed_freq;
+
+ /**
* disable_ht - Disable HT (IEEE 802.11n) for this connection
*/
int disable_ht;
/**
- * HT Capabilities over-rides. Only bits set in the mask will be used,
- * and not all values are used by the kernel anyway. Currently, MCS,
- * MPDU and MSDU fields are used.
+ * htcaps - HT Capabilities over-rides
+ *
+ * Only bits set in the mask will be used, and not all values are used
+ * by the kernel anyway. Currently, MCS, MPDU and MSDU fields are used.
+ *
+ * Pointer to struct ieee80211_ht_capabilities.
+ */
+ const u8 *htcaps;
+
+ /**
+ * htcaps_mask - HT Capabilities over-rides mask
+ *
+ * Pointer to struct ieee80211_ht_capabilities.
+ */
+ const u8 *htcaps_mask;
+
+#ifdef CONFIG_VHT_OVERRIDES
+ /**
+ * disable_vht - Disable VHT for this connection
+ */
+ int disable_vht;
+
+ /**
+ * VHT capability overrides.
*/
- const u8 *htcaps; /* struct ieee80211_ht_capabilities * */
- const u8 *htcaps_mask; /* struct ieee80211_ht_capabilities * */
+ const struct ieee80211_vht_capabilities *vhtcaps;
+ const struct ieee80211_vht_capabilities *vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
+
+ /**
+ * req_key_mgmt_offload - Request key management offload for connection
+ *
+ * Request key management offload for this connection if the device
+ * supports it.
+ */
+ int req_key_mgmt_offload;
+
+ /**
+ * Flag for indicating whether this association includes support for
+ * RRM (Radio Resource Measurements)
+ */
+ int rrm_used;
};
enum hide_ssid {
@@ -567,11 +835,21 @@ enum hide_ssid {
HIDDEN_SSID_ZERO_CONTENTS
};
+struct wowlan_triggers {
+ u8 any;
+ u8 disconnect;
+ u8 magic_pkt;
+ u8 gtk_rekey_failure;
+ u8 eap_identity_req;
+ u8 four_way_handshake;
+ u8 rfkill_release;
+};
+
struct wpa_driver_ap_params {
/**
* head - Beacon head from IEEE 802.11 header to IEs before TIM IE
*/
- const u8 *head;
+ u8 *head;
/**
* head_len - Length of the head buffer in octets
@@ -581,7 +859,7 @@ struct wpa_driver_ap_params {
/**
* tail - Beacon tail following TIM IE
*/
- const u8 *tail;
+ u8 *tail;
/**
* tail_len - Length of the tail buffer in octets
@@ -612,7 +890,7 @@ struct wpa_driver_ap_params {
* This is used by drivers that reply to Probe Requests internally in
* AP mode and require the full Probe Response template.
*/
- const u8 *proberesp;
+ u8 *proberesp;
/**
* proberesp_len - Length of the proberesp buffer in octets
@@ -745,9 +1023,64 @@ struct wpa_driver_ap_params {
int ap_max_inactivity;
/**
+ * ctwindow - Client Traffic Window (in TUs)
+ */
+ u8 p2p_go_ctwindow;
+
+ /**
+ * smps_mode - SMPS mode
+ *
+ * SMPS mode to be used by the AP, specified as the relevant bits of
+ * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
+ */
+ unsigned int smps_mode;
+
+ /**
* disable_dgaf - Whether group-addressed frames are disabled
*/
int disable_dgaf;
+
+ /**
+ * osen - Whether OSEN security is enabled
+ */
+ int osen;
+
+ /**
+ * freq - Channel parameters for dynamic bandwidth changes
+ */
+ struct hostapd_freq_params *freq;
+
+ /**
+ * reenable - Whether this is to re-enable beaconing
+ */
+ int reenable;
+};
+
+struct wpa_driver_mesh_bss_params {
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+ /*
+ * TODO: Other mesh configuration parameters would go here.
+ * See NL80211_MESHCONF_* for all the mesh config parameters.
+ */
+ unsigned int flags;
+ int peer_link_timeout;
+};
+
+struct wpa_driver_mesh_join_params {
+ const u8 *meshid;
+ int meshid_len;
+ const int *basic_rates;
+ const u8 *ies;
+ int ie_len;
+ struct hostapd_freq_params freq;
+ int beacon_int;
+ int max_peer_links;
+ struct wpa_driver_mesh_bss_params conf;
+#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
+#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002
+#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004
+#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
+ unsigned int flags;
};
/**
@@ -762,6 +1095,9 @@ struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_KEY_MGMT_FT 0x00000020
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK 0x00000040
#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK 0x00000080
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B 0x00000100
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 0x00000200
+ /** Bitfield of supported key management suites */
unsigned int key_mgmt;
#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001
@@ -770,83 +1106,132 @@ struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008
#define WPA_DRIVER_CAPA_ENC_WEP128 0x00000010
#define WPA_DRIVER_CAPA_ENC_GCMP 0x00000020
+#define WPA_DRIVER_CAPA_ENC_GCMP_256 0x00000040
+#define WPA_DRIVER_CAPA_ENC_CCMP_256 0x00000080
+#define WPA_DRIVER_CAPA_ENC_BIP 0x00000100
+#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_128 0x00000200
+#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256 0x00000400
+#define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256 0x00000800
+#define WPA_DRIVER_CAPA_ENC_GTK_NOT_USED 0x00001000
+ /** Bitfield of supported cipher suites */
unsigned int enc;
#define WPA_DRIVER_AUTH_OPEN 0x00000001
#define WPA_DRIVER_AUTH_SHARED 0x00000002
#define WPA_DRIVER_AUTH_LEAP 0x00000004
+ /** Bitfield of supported IEEE 802.11 authentication algorithms */
unsigned int auth;
-/* Driver generated WPA/RSN IE */
+/** Driver generated WPA/RSN IE */
#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001
-/* Driver needs static WEP key setup after association command */
+/** Driver needs static WEP key setup after association command */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-/* unused: 0x00000004 */
-/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+/** Driver takes care of all DFS operations */
+#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
+/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
-/* Driver provides separate commands for authentication and association (SME in
+/** Driver provides separate commands for authentication and association (SME in
* wpa_supplicant). */
#define WPA_DRIVER_FLAGS_SME 0x00000020
-/* Driver supports AP mode */
+/** Driver supports AP mode */
#define WPA_DRIVER_FLAGS_AP 0x00000040
-/* Driver needs static WEP key setup after association has been completed */
+/** Driver needs static WEP key setup after association has been completed */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080
-/* Driver takes care of P2P management operations */
-#define WPA_DRIVER_FLAGS_P2P_MGMT 0x00000100
-/* Driver supports concurrent P2P operations */
+/** Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
+#define WPA_DRIVER_FLAGS_HT_2040_COEX 0x00000100
+/** Driver supports concurrent P2P operations */
#define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200
-/*
+/**
* Driver uses the initial interface as a dedicated management interface, i.e.,
* it cannot be used for P2P group operations or non-P2P purposes.
*/
#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400
-/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+/** This interface is P2P capable (P2P GO or P2P Client) */
#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800
-/* Driver supports concurrent operations on multiple channels */
-#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT 0x00001000
-/*
+/** Driver supports station and key removal when stopping an AP */
+#define WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT 0x00001000
+/**
* Driver uses the initial interface for P2P management interface and non-P2P
* purposes (e.g., connect to infra AP), but this interface cannot be used for
* P2P group operations.
*/
#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 0x00002000
-/*
+/**
* Driver is known to use sane error codes, i.e., when it indicates that
* something (e.g., association) fails, there was indeed a failure and the
* operation does not end up getting completed successfully later.
*/
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
-/* Driver supports off-channel TX */
+/** Driver supports off-channel TX */
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
-/* Driver indicates TX status events for EAPOL Data frames */
+/** Driver indicates TX status events for EAPOL Data frames */
#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000
-/* Driver indicates TX status events for Deauth/Disassoc frames */
+/** Driver indicates TX status events for Deauth/Disassoc frames */
#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000
-/* Driver supports roaming (BSS selection) in firmware */
+/** Driver supports roaming (BSS selection) in firmware */
#define WPA_DRIVER_FLAGS_BSS_SELECTION 0x00040000
-/* Driver supports operating as a TDLS peer */
+/** Driver supports operating as a TDLS peer */
#define WPA_DRIVER_FLAGS_TDLS_SUPPORT 0x00080000
-/* Driver requires external TDLS setup/teardown/discovery */
+/** Driver requires external TDLS setup/teardown/discovery */
#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP 0x00100000
-/* Driver indicates support for Probe Response offloading in AP mode */
+/** Driver indicates support for Probe Response offloading in AP mode */
#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD 0x00200000
-/* Driver supports U-APSD in AP mode */
+/** Driver supports U-APSD in AP mode */
#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000
-/* Driver supports inactivity timer in AP mode */
+/** Driver supports inactivity timer in AP mode */
#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000
-/* Driver expects user space implementation of MLME in AP mode */
+/** Driver expects user space implementation of MLME in AP mode */
#define WPA_DRIVER_FLAGS_AP_MLME 0x01000000
-/* Driver supports SAE with user space SME */
+/** Driver supports SAE with user space SME */
#define WPA_DRIVER_FLAGS_SAE 0x02000000
-/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+/** Driver makes use of OBSS scan mechanism in wpa_supplicant */
#define WPA_DRIVER_FLAGS_OBSS_SCAN 0x04000000
- unsigned int flags;
-
+/** Driver supports IBSS (Ad-hoc) mode */
+#define WPA_DRIVER_FLAGS_IBSS 0x08000000
+/** Driver supports radar detection */
+#define WPA_DRIVER_FLAGS_RADAR 0x10000000
+/** Driver supports a dedicated interface for P2P Device */
+#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE 0x20000000
+/** Driver supports QoS Mapping */
+#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000
+/** Driver supports CSA in AP mode */
+#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000
+/** Driver supports mesh */
+#define WPA_DRIVER_FLAGS_MESH 0x0000000100000000ULL
+/** Driver support ACS offload */
+#define WPA_DRIVER_FLAGS_ACS_OFFLOAD 0x0000000200000000ULL
+/** Driver supports key management offload */
+#define WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD 0x0000000400000000ULL
+/** Driver supports TDLS channel switching */
+#define WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH 0x0000000800000000ULL
+/** Driver supports IBSS with HT datarates */
+#define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL
+/** Driver supports IBSS with VHT datarates */
+#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
+ u64 flags;
+
+#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
+#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
+ unsigned int smps_modes;
+
+ unsigned int wmm_ac_supported:1;
+
+ unsigned int mac_addr_rand_scan_supported:1;
+ unsigned int mac_addr_rand_sched_scan_supported:1;
+
+ /** Maximum number of supported active probe SSIDs */
int max_scan_ssids;
+
+ /** Maximum number of supported active probe SSIDs for sched_scan */
int max_sched_scan_ssids;
+
+ /** Whether sched_scan (offloaded scanning) is supported */
int sched_scan_supported;
+
+ /** Maximum number of supported match sets for sched_scan */
int max_match_sets;
/**
@@ -864,15 +1249,51 @@ struct wpa_driver_capa {
* probe_resp_offloads - Bitmap of supported protocols by the driver
* for Probe Response offloading.
*/
-/* Driver Probe Response offloading support for WPS ver. 1 */
+/** Driver Probe Response offloading support for WPS ver. 1 */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS 0x00000001
-/* Driver Probe Response offloading support for WPS ver. 2 */
+/** Driver Probe Response offloading support for WPS ver. 2 */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2 0x00000002
-/* Driver Probe Response offloading support for P2P */
+/** Driver Probe Response offloading support for P2P */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P 0x00000004
-/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+/** Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
unsigned int probe_resp_offloads;
+
+ unsigned int max_acl_mac_addrs;
+
+ /**
+ * Number of supported concurrent channels
+ */
+ unsigned int num_multichan_concurrent;
+
+ /**
+ * extended_capa - extended capabilities in driver/device
+ *
+ * Must be allocated and freed by driver and the pointers must be
+ * valid for the lifetime of the driver, i.e., freed in deinit()
+ */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
+ struct wowlan_triggers wowlan_triggers;
+
+/** Driver adds the DS Params Set IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES 0x00000001
+/** Driver adds the WFA TPC IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES 0x00000002
+/** Driver handles quiet period requests */
+#define WPA_DRIVER_FLAGS_QUIET 0x00000004
+/**
+ * Driver is capable of inserting the current TX power value into the body of
+ * transmitted frames.
+ * Background: Some Action frames include a TPC Report IE. This IE contains a
+ * TX power field, which has to be updated by lower layers. One such Action
+ * frame is Link Measurement Report (part of RRM). Another is TPC Report (part
+ * of spectrum management). Note that this insertion takes place at a fixed
+ * offset, namely the 6th byte in the Action frame body.
+ */
+#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
+ u32 rrm_flags;
};
@@ -898,19 +1319,32 @@ struct hostapd_sta_add_params {
size_t supp_rates_len;
u16 listen_interval;
const struct ieee80211_ht_capabilities *ht_capabilities;
+ const struct ieee80211_vht_capabilities *vht_capabilities;
+ int vht_opmode_enabled;
+ u8 vht_opmode;
u32 flags; /* bitmask of WPA_STA_* flags */
+ u32 flags_mask; /* unset bits in flags */
+#ifdef CONFIG_MESH
+ enum mesh_plink_state plink_state;
+#endif /* CONFIG_MESH */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
+ const u8 *ext_capab;
+ size_t ext_capab_len;
+ const u8 *supp_channels;
+ size_t supp_channels_len;
+ const u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
};
-struct hostapd_freq_params {
- int mode;
- int freq;
- int channel;
- int ht_enabled;
- int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
- * secondary channel below primary, 1 = HT40
- * enabled, secondary channel above primary */
+struct mac_address {
+ u8 addr[ETH_ALEN];
+};
+
+struct hostapd_acl_params {
+ u8 acl_policy;
+ unsigned int num_mac_acl;
+ struct mac_address mac_acl[0];
};
enum wpa_driver_if_type {
@@ -948,16 +1382,25 @@ enum wpa_driver_if_type {
* WPA_IF_P2P_GROUP - P2P Group interface (will become either
* WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
*/
- WPA_IF_P2P_GROUP
+ WPA_IF_P2P_GROUP,
+
+ /**
+ * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+ * abstracted P2P Device function in the driver
+ */
+ WPA_IF_P2P_DEVICE,
+
+ /*
+ * WPA_IF_MESH - Mesh interface
+ */
+ WPA_IF_MESH,
};
struct wpa_init_params {
void *global_priv;
const u8 *bssid;
const char *ifname;
- const u8 *ssid;
- size_t ssid_len;
- const char *test_socket;
+ const char *driver_params;
int use_pae_group_addr;
char **bridge;
size_t num_bridge;
@@ -986,17 +1429,7 @@ struct wpa_bss_params {
#define WPA_STA_SHORT_PREAMBLE BIT(2)
#define WPA_STA_MFP BIT(3)
#define WPA_STA_TDLS_PEER BIT(4)
-
-/**
- * struct p2p_params - P2P parameters for driver-based P2P management
- */
-struct p2p_params {
- const char *dev_name;
- u8 pri_dev_type[8];
-#define DRV_MAX_SEC_DEV_TYPES 5
- u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8];
- size_t num_sec_dev_types;
-};
+#define WPA_STA_AUTHENTICATED BIT(5)
enum tdls_oper {
TDLS_DISCOVERY_REQ,
@@ -1025,6 +1458,17 @@ 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
+};
+
/**
* struct wpa_signal_info - Information about channel signal quality
*/
@@ -1032,11 +1476,121 @@ struct wpa_signal_info {
u32 frequency;
int above_threshold;
int current_signal;
+ int avg_signal;
int current_noise;
int current_txrate;
+ enum chan_width chanwidth;
+ int center_frq1;
+ int center_frq2;
+};
+
+/**
+ * struct beacon_data - Beacon data
+ * @head: Head portion of Beacon frame (before TIM IE)
+ * @tail: Tail portion of Beacon frame (after TIM IE)
+ * @beacon_ies: Extra information element(s) to add into Beacon frames or %NULL
+ * @proberesp_ies: Extra information element(s) to add into Probe Response
+ * frames or %NULL
+ * @assocresp_ies: Extra information element(s) to add into (Re)Association
+ * Response frames or %NULL
+ * @probe_resp: Probe Response frame template
+ * @head_len: Length of @head
+ * @tail_len: Length of @tail
+ * @beacon_ies_len: Length of beacon_ies in octets
+ * @proberesp_ies_len: Length of proberesp_ies in octets
+ * @proberesp_ies_len: Length of proberesp_ies in octets
+ * @probe_resp_len: Length of probe response template (@probe_resp)
+ */
+struct beacon_data {
+ u8 *head, *tail;
+ u8 *beacon_ies;
+ u8 *proberesp_ies;
+ u8 *assocresp_ies;
+ u8 *probe_resp;
+
+ size_t head_len, tail_len;
+ size_t beacon_ies_len;
+ size_t proberesp_ies_len;
+ size_t assocresp_ies_len;
+ size_t probe_resp_len;
+};
+
+/**
+ * struct csa_settings - Settings for channel switch command
+ * @cs_count: Count in Beacon frames (TBTT) to perform the switch
+ * @block_tx: 1 - block transmission for CSA period
+ * @freq_params: Next channel frequency parameter
+ * @beacon_csa: Beacon/probe resp/asooc resp info for CSA period
+ * @beacon_after: Next beacon/probe resp/asooc resp info
+ * @counter_offset_beacon: Offset to the count field in beacon's tail
+ * @counter_offset_presp: Offset to the count field in probe resp.
+ */
+struct csa_settings {
+ u8 cs_count;
+ u8 block_tx;
+
+ struct hostapd_freq_params freq_params;
+ struct beacon_data beacon_csa;
+ struct beacon_data beacon_after;
+
+ u16 counter_offset_beacon;
+ u16 counter_offset_presp;
+};
+
+/* TDLS peer capabilities for send_tdls_mgmt() */
+enum tdls_peer_capability {
+ TDLS_PEER_HT = BIT(0),
+ TDLS_PEER_VHT = BIT(1),
+ TDLS_PEER_WMM = BIT(2),
+};
+
+/* valid info in the wmm_params struct */
+enum wmm_params_valid_info {
+ WMM_PARAMS_UAPSD_QUEUES_INFO = BIT(0),
};
/**
+ * struct wmm_params - WMM parameterss configured for this association
+ * @info_bitmap: Bitmap of valid wmm_params info; indicates what fields
+ * of the struct contain valid information.
+ * @uapsd_queues: Bitmap of ACs configured for uapsd (valid only if
+ * %WMM_PARAMS_UAPSD_QUEUES_INFO is set)
+ */
+struct wmm_params {
+ u8 info_bitmap;
+ u8 uapsd_queues;
+};
+
+#ifdef CONFIG_MACSEC
+struct macsec_init_params {
+ Boolean always_include_sci;
+ Boolean use_es;
+ Boolean use_scb;
+};
+#endif /* CONFIG_MACSEC */
+
+enum drv_br_port_attr {
+ DRV_BR_PORT_ATTR_PROXYARP,
+ DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+};
+
+enum drv_br_net_param {
+ DRV_BR_NET_PARAM_GARP_ACCEPT,
+};
+
+struct drv_acs_params {
+ /* Selected mode (HOSTAPD_MODE_*) */
+ enum hostapd_hw_mode hw_mode;
+
+ /* Indicates whether HT is enabled */
+ int ht_enabled;
+
+ /* Indicates whether HT40 is enabled */
+ int ht40_enabled;
+};
+
+
+/**
* struct wpa_driver_ops - Driver interface API definition
*
* This structure defines the API that each driver interface needs to implement
@@ -1085,7 +1639,9 @@ struct wpa_driver_ops {
* @priv: private driver interface data
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
* %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
- * %WPA_ALG_GCMP);
+ * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
+ * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256,
+ * %WPA_ALG_BIP_CMAC_256);
* %WPA_ALG_NONE clears the key.
* @addr: Address of the peer STA (BSSID of the current AP when setting
* pairwise key in station mode), ff:ff:ff:ff:ff:ff for
@@ -1319,27 +1875,6 @@ struct wpa_driver_ops {
const u8 * (*get_mac_addr)(void *priv);
/**
- * send_eapol - Optional function for sending EAPOL packets
- * @priv: private driver interface data
- * @dest: Destination MAC address
- * @proto: Ethertype
- * @data: EAPOL packet starting with IEEE 802.1X header
- * @data_len: Size of the EAPOL packet
- *
- * Returns: 0 on success, -1 on failure
- *
- * This optional function can be used to override l2_packet operations
- * with driver specific functionality. If this function pointer is set,
- * l2_packet module is not used at all and the driver interface code is
- * responsible for receiving and sending all EAPOL packets. The
- * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
- * event. The driver interface is required to implement get_mac_addr()
- * handler if send_eapol() is used.
- */
- int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
- const u8 *data, size_t data_len);
-
- /**
* set_operstate - Sets device operating state to DORMANT or UP
* @priv: private driver interface data
* @state: 0 = dormant, 1 = up
@@ -1414,22 +1949,6 @@ struct wpa_driver_ops {
size_t ies_len);
/**
- * send_ft_action - Send FT Action frame (IEEE 802.11r)
- * @priv: Private driver interface data
- * @action: Action field value
- * @target_ap: Target AP address
- * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
- * @ies_len: Length of FT IEs in bytes
- * Returns: 0 on success, -1 on failure
- *
- * The supplicant uses this callback to request the driver to transmit
- * an FT Action frame (action category 6) for over-the-DS fast BSS
- * transition.
- */
- int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
- const u8 *ies, size_t ies_len);
-
- /**
* get_scan_results2 - Fetch the latest scan results
* @priv: private driver interface data
*
@@ -1450,6 +1969,14 @@ struct wpa_driver_ops {
int (*set_country)(void *priv, const char *alpha2);
/**
+ * get_country - Get country
+ * @priv: Private driver interface data
+ * @alpha2: Buffer for returning country code (at least 3 octets)
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*get_country)(void *priv, char *alpha2);
+
+ /**
* global_init - Global driver initialization
* Returns: Pointer to private data (global), %NULL on failure
*
@@ -1543,6 +2070,16 @@ struct wpa_driver_ops {
int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
/**
+ * set_acl - Set ACL in AP mode
+ * @priv: Private driver interface data
+ * @params: Parameters to configure ACL
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is used only for the drivers which support MAC address ACL.
+ */
+ int (*set_acl)(void *priv, struct hostapd_acl_params *params);
+
+ /**
* hapd_init - Initialize driver interface (hostapd only)
* @hapd: Pointer to hostapd context
* @params: Configuration for the driver wrapper
@@ -1825,12 +2362,13 @@ struct wpa_driver_ops {
* (this may differ from the requested addr if the driver cannot
* change interface address)
* @bridge: Bridge interface to use or %NULL if no bridge configured
+ * @use_existing: Whether to allow existing interface to be used
* Returns: 0 on success, -1 on failure
*/
int (*if_add)(void *priv, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
- const char *bridge);
+ const char *bridge, int use_existing);
/**
* if_remove - Remove a virtual interface
@@ -1892,7 +2430,7 @@ struct wpa_driver_ops {
* @session_timeout: Session timeout for the station
* Returns: 0 on success, -1 on failure
*/
- int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
+ int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
u32 session_timeout);
/**
@@ -1951,10 +2489,12 @@ struct wpa_driver_ops {
* @val: 1 = bind to 4-address WDS; 0 = unbind
* @bridge_ifname: Bridge interface to use for the WDS station or %NULL
* to indicate that bridge is not to be used
+ * @ifname_wds: Buffer to return the interface name for the new WDS
+ * station or %NULL to indicate name is not returned.
* Returns: 0 on success, -1 on failure
*/
int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
- const char *bridge_ifname);
+ const char *bridge_ifname, char *ifname_wds);
/**
* send_action - Transmit an Action frame
@@ -2005,7 +2545,7 @@ struct wpa_driver_ops {
*
* This command is used to request the driver to remain awake on the
* specified channel for the specified duration and report received
- * Action frames with EVENT_RX_ACTION events. Optionally, received
+ * Action frames with EVENT_RX_MGMT events. Optionally, received
* Probe Request frames may also be requested to be reported by calling
* probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ.
*
@@ -2056,8 +2596,9 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure (or if not supported)
*
* This optional function can be used to disable AP mode related
- * configuration and change the driver mode to station mode to allow
- * normal station operations like scanning to be completed.
+ * configuration. If the interface was not dynamically added,
+ * change the driver mode to station mode to allow normal station
+ * operations like scanning to be completed.
*/
int (*deinit_ap)(void *priv);
@@ -2066,8 +2607,9 @@ struct wpa_driver_ops {
* @priv: Private driver interface data
* Returns: 0 on success, -1 on failure (or if not supported)
*
- * This optional function can be used to disable P2P client mode. It
- * can be used to change the interface type back to station mode.
+ * This optional function can be used to disable P2P client mode. If the
+ * interface was not dynamically added, change the interface type back
+ * to station mode.
*/
int (*deinit_p2p_cli)(void *priv);
@@ -2185,228 +2727,14 @@ struct wpa_driver_ops {
const char * (*get_radio_name)(void *priv);
/**
- * p2p_find - Start P2P Device Discovery
- * @priv: Private driver interface data
- * @timeout: Timeout for find operation in seconds or 0 for no timeout
- * @type: Device Discovery type (enum p2p_discovery_type)
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_find)(void *priv, unsigned int timeout, int type);
-
- /**
- * p2p_stop_find - Stop P2P Device Discovery
- * @priv: Private driver interface data
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_stop_find)(void *priv);
-
- /**
- * p2p_listen - Start P2P Listen state for specified duration
- * @priv: Private driver interface data
- * @timeout: Listen state duration in milliseconds
- * Returns: 0 on success, -1 on failure
- *
- * This function can be used to request the P2P module to keep the
- * device discoverable on the listen channel for an extended set of
- * time. At least in its current form, this is mainly used for testing
- * purposes and may not be of much use for normal P2P operations.
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_listen)(void *priv, unsigned int timeout);
-
- /**
- * p2p_connect - Start P2P group formation (GO negotiation)
- * @priv: Private driver interface data
- * @peer_addr: MAC address of the peer P2P client
- * @wps_method: enum p2p_wps_method value indicating config method
- * @go_intent: Local GO intent value (1..15)
- * @own_interface_addr: Intended interface address to use with the
- * group
- * @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create persistent group
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method,
- int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group);
-
- /**
- * wps_success_cb - Report successfully completed WPS provisioning
- * @priv: Private driver interface data
- * @peer_addr: Peer address
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to report successfully completed WPS
- * provisioning during group formation in both GO/Registrar and
- * client/Enrollee roles.
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*wps_success_cb)(void *priv, const u8 *peer_addr);
-
- /**
- * p2p_group_formation_failed - Report failed WPS provisioning
- * @priv: Private driver interface data
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to report failed group formation. This can
- * happen either due to failed WPS provisioning or due to 15 second
- * timeout during the provisioning phase.
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_group_formation_failed)(void *priv);
-
- /**
- * p2p_set_params - Set P2P parameters
- * @priv: Private driver interface data
- * @params: P2P parameters
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_set_params)(void *priv, const struct p2p_params *params);
-
- /**
- * p2p_prov_disc_req - Send Provision Discovery Request
- * @priv: Private driver interface data
- * @peer_addr: MAC address of the peer P2P client
- * @config_methods: WPS Config Methods value (only one bit set)
- * Returns: 0 on success, -1 on failure
- *
- * This function can be used to request a discovered P2P peer to
- * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared
- * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The
- * Provision Discovery Request frame is transmitted once immediately
- * and if no response is received, the frame will be sent again
- * whenever the target device is discovered during device dsicovery
- * (start with a p2p_find() call). Response from the peer is indicated
- * with the EVENT_P2P_PROV_DISC_RESPONSE event.
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
- u16 config_methods, int join);
-
- /**
- * p2p_sd_request - Schedule a service discovery query
- * @priv: Private driver interface data
- * @dst: Destination peer or %NULL to apply for all peers
- * @tlvs: P2P Service Query TLV(s)
- * Returns: Reference to the query or 0 on failure
- *
- * Response to the query is indicated with the
- * EVENT_P2P_SD_RESPONSE driver event.
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- u64 (*p2p_sd_request)(void *priv, const u8 *dst,
- const struct wpabuf *tlvs);
-
- /**
- * p2p_sd_cancel_request - Cancel a pending service discovery query
- * @priv: Private driver interface data
- * @req: Query reference from p2p_sd_request()
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_sd_cancel_request)(void *priv, u64 req);
-
- /**
- * p2p_sd_response - Send response to a service discovery query
- * @priv: Private driver interface data
- * @freq: Frequency from EVENT_P2P_SD_REQUEST event
- * @dst: Destination address from EVENT_P2P_SD_REQUEST event
- * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event
- * @resp_tlvs: P2P Service Response TLV(s)
- * Returns: 0 on success, -1 on failure
- *
- * This function is called as a response to the request indicated with
- * the EVENT_P2P_SD_REQUEST driver event.
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_sd_response)(void *priv, int freq, const u8 *dst,
- u8 dialog_token,
- const struct wpabuf *resp_tlvs);
-
- /**
- * p2p_service_update - Indicate a change in local services
- * @priv: Private driver interface data
- * Returns: 0 on success, -1 on failure
- *
- * This function needs to be called whenever there is a change in
- * availability of the local services. This will increment the
- * Service Update Indicator value which will be used in SD Request and
- * Response frames.
- *
- * This function is only used if the driver implements P2P management,
- * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
- * struct wpa_driver_capa.
- */
- int (*p2p_service_update)(void *priv);
-
- /**
- * p2p_reject - Reject peer device (explicitly block connections)
- * @priv: Private driver interface data
- * @addr: MAC address of the peer
- * Returns: 0 on success, -1 on failure
- */
- int (*p2p_reject)(void *priv, const u8 *addr);
-
- /**
- * p2p_invite - Invite a P2P Device into a group
- * @priv: Private driver interface data
- * @peer: Device Address of the peer P2P Device
- * @role: Local role in the group
- * @bssid: Group BSSID or %NULL if not known
- * @ssid: Group SSID
- * @ssid_len: Length of ssid in octets
- * @go_dev_addr: Forced GO Device Address or %NULL if none
- * @persistent_group: Whether this is to reinvoke a persistent group
- * Returns: 0 on success, -1 on failure
- */
- int (*p2p_invite)(void *priv, const u8 *peer, int role,
- const u8 *bssid, const u8 *ssid, size_t ssid_len,
- const u8 *go_dev_addr, int persistent_group);
-
- /**
* send_tdls_mgmt - for sending TDLS management packets
* @priv: private driver interface data
* @dst: Destination (peer) MAC address
* @action_code: TDLS action code for the mssage
* @dialog_token: Dialog Token to use in the message (if needed)
* @status_code: Status Code or Reason Code to use (if needed)
+ * @peer_capab: TDLS peer capability (TDLS_PEER_* bitfield)
+ * @initiator: Is the current end the TDLS link initiator
* @buf: TDLS IEs to add to the message
* @len: Length of buf in octets
* Returns: 0 on success, negative (<0) on failure
@@ -2415,8 +2743,8 @@ struct wpa_driver_ops {
* responsible for receiving and sending all TDLS packets.
*/
int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
- u8 dialog_token, u16 status_code,
- const u8 *buf, size_t len);
+ u8 dialog_token, u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf, size_t len);
/**
* tdls_oper - Ask the driver to perform high-level TDLS operations
@@ -2443,10 +2771,65 @@ struct wpa_driver_ops {
u8 *buf, u16 *buf_len);
/**
+ * set_qos_map - Set QoS Map
+ * @priv: Private driver interface data
+ * @qos_map_set: QoS Map
+ * @qos_map_set_len: Length of QoS Map
+ */
+ int (*set_qos_map)(void *priv, const u8 *qos_map_set,
+ u8 qos_map_set_len);
+
+ /**
+ * br_add_ip_neigh - Add a neigh to the bridge ip neigh table
+ * @priv: Private driver interface data
+ * @version: IP version of the IP address, 4 or 6
+ * @ipaddr: IP address for the neigh entry
+ * @prefixlen: IP address prefix length
+ * @addr: Corresponding MAC address
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_add_ip_neigh)(void *priv, u8 version, const u8 *ipaddr,
+ int prefixlen, const u8 *addr);
+
+ /**
+ * br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table
+ * @priv: Private driver interface data
+ * @version: IP version of the IP address, 4 or 6
+ * @ipaddr: IP address for the neigh entry
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_delete_ip_neigh)(void *priv, u8 version, const u8 *ipaddr);
+
+ /**
+ * br_port_set_attr - Set a bridge port attribute
+ * @attr: Bridge port attribute to set
+ * @val: Value to be set
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_port_set_attr)(void *priv, enum drv_br_port_attr attr,
+ unsigned int val);
+
+ /**
+ * br_port_set_attr - Set a bridge network parameter
+ * @param: Bridge parameter to set
+ * @val: Value to be set
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_set_net_param)(void *priv, enum drv_br_net_param param,
+ unsigned int val);
+
+ /**
+ * set_wowlan - Set wake-on-wireless triggers
+ * @priv: Private driver interface data
+ * @triggers: wowlan triggers
+ */
+ int (*set_wowlan)(void *priv, const struct wowlan_triggers *triggers);
+
+ /**
* signal_poll - Get current connection information
* @priv: Private driver interface data
* @signal_info: Connection info structure
- */
+ */
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
/**
@@ -2463,18 +2846,57 @@ struct wpa_driver_ops {
*/
int (*set_authmode)(void *priv, int authmode);
+#ifdef ANDROID
+ /**
+ * driver_cmd - Execute driver-specific command
+ * @priv: Private driver interface data
+ * @cmd: Command to execute
+ * @buf: Return buffer
+ * @buf_len: Buffer length
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
+#endif /* ANDROID */
+
+ /**
+ * vendor_cmd - Execute vendor specific command
+ * @priv: Private driver interface data
+ * @vendor_id: Vendor id
+ * @subcmd: Vendor command id
+ * @data: Vendor command parameters (%NULL if no parameters)
+ * @data_len: Data length
+ * @buf: Return buffer (%NULL to ignore reply)
+ * Returns: 0 on success, negative (<0) on failure
+ *
+ * This function handles vendor specific commands that are passed to
+ * the driver/device. The command is identified by vendor id and
+ * command id. Parameters can be passed as argument to the command
+ * in the data buffer. Reply (if any) will be filled in the supplied
+ * return buffer.
+ *
+ * The exact driver behavior is driver interface and vendor specific. As
+ * an example, this will be converted to a vendor specific cfg80211
+ * command in case of the nl80211 driver interface.
+ */
+ int (*vendor_cmd)(void *priv, unsigned int vendor_id,
+ unsigned int subcmd, const u8 *data, size_t data_len,
+ struct wpabuf *buf);
+
/**
* set_rekey_info - Set rekey information
* @priv: Private driver interface data
* @kek: Current KEK
+ * @kek_len: KEK length in octets
* @kck: Current KCK
+ * @kck_len: KCK length in octets
* @replay_ctr: Current EAPOL-Key Replay Counter
*
* This optional function can be used to provide information for the
* driver/firmware to process EAPOL-Key frames in Group Key Handshake
* while the host (including wpa_supplicant) is sleeping.
*/
- void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+ void (*set_rekey_info)(void *priv, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
/**
@@ -2595,13 +3017,370 @@ struct wpa_driver_ops {
* switch_channel - Announce channel switch and migrate the GO to the
* given frequency
* @priv: Private driver interface data
- * @freq: Frequency in MHz
+ * @settings: Settings for CSA period and new channel
* Returns: 0 on success, -1 on failure
*
* This function is used to move the GO to the legacy STA channel to
* avoid frequency conflict in single channel concurrency.
*/
- int (*switch_channel)(void *priv, unsigned int freq);
+ int (*switch_channel)(void *priv, struct csa_settings *settings);
+
+ /**
+ * add_tx_ts - Add traffic stream
+ * @priv: Private driver interface data
+ * @tsid: Traffic stream ID
+ * @addr: Receiver address
+ * @user_prio: User priority of the traffic stream
+ * @admitted_time: Admitted time for this TS in units of
+ * 32 microsecond periods (per second).
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*add_tx_ts)(void *priv, u8 tsid, const u8 *addr, u8 user_prio,
+ u16 admitted_time);
+
+ /**
+ * del_tx_ts - Delete traffic stream
+ * @priv: Private driver interface data
+ * @tsid: Traffic stream ID
+ * @addr: Receiver address
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*del_tx_ts)(void *priv, u8 tsid, const u8 *addr);
+
+ /**
+ * Enable channel-switching with TDLS peer
+ * @priv: Private driver interface data
+ * @addr: MAC address of the TDLS peer
+ * @oper_class: Operating class of the switch channel
+ * @params: Channel specification
+ * Returns: 0 on success, -1 on failure
+ *
+ * The function indicates to driver that it can start switching to a
+ * different channel with a specified TDLS peer. The switching is
+ * assumed on until canceled with tdls_disable_channel_switch().
+ */
+ int (*tdls_enable_channel_switch)(
+ void *priv, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params);
+
+ /**
+ * Disable channel switching with TDLS peer
+ * @priv: Private driver interface data
+ * @addr: MAC address of the TDLS peer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function indicates to the driver that it should stop switching
+ * with a given TDLS peer.
+ */
+ int (*tdls_disable_channel_switch)(void *priv, const u8 *addr);
+
+ /**
+ * start_dfs_cac - Listen for radar interference on the channel
+ * @priv: Private driver interface data
+ * @freq: Channel parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*start_dfs_cac)(void *priv, struct hostapd_freq_params *freq);
+
+ /**
+ * stop_ap - Removes beacon from AP
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ *
+ * This optional function can be used to disable AP mode related
+ * configuration. Unlike deinit_ap, it does not change to station
+ * mode.
+ */
+ int (*stop_ap)(void *priv);
+
+ /**
+ * get_survey - Retrieve survey data
+ * @priv: Private driver interface data
+ * @freq: If set, survey data for the specified frequency is only
+ * being requested. If not set, all survey data is requested.
+ * Returns: 0 on success, -1 on failure
+ *
+ * Use this to retrieve:
+ *
+ * - the observed channel noise floor
+ * - the amount of time we have spent on the channel
+ * - the amount of time during which we have spent on the channel that
+ * the radio has determined the medium is busy and we cannot
+ * transmit
+ * - the amount of time we have spent receiving data
+ * - the amount of time we have spent transmitting data
+ *
+ * This data can be used for spectrum heuristics. One example is
+ * Automatic Channel Selection (ACS). The channel survey data is
+ * kept on a linked list on the channel data, one entry is added
+ * for each survey. The min_nf of the channel is updated for each
+ * survey.
+ */
+ int (*get_survey)(void *priv, unsigned int freq);
+
+ /**
+ * status - Get driver interface status information
+ * @priv: Private driver interface data
+ * @buf: Buffer for printing tou the status information
+ * @buflen: Maximum length of the buffer
+ * Returns: Length of written status information or -1 on failure
+ */
+ int (*status)(void *priv, char *buf, size_t buflen);
+
+ /**
+ * roaming - Set roaming policy for driver-based BSS selection
+ * @priv: Private driver interface data
+ * @allowed: Whether roaming within ESS is allowed
+ * @bssid: Forced BSSID if roaming is disabled or %NULL if not set
+ * Returns: Length of written status information or -1 on failure
+ *
+ * This optional callback can be used to update roaming policy from the
+ * associate() command (bssid being set there indicates that the driver
+ * should not roam before getting this roaming() call to allow roaming.
+ * If the driver does not indicate WPA_DRIVER_FLAGS_BSS_SELECTION
+ * capability, roaming policy is handled within wpa_supplicant and there
+ * is no need to implement or react to this callback.
+ */
+ int (*roaming)(void *priv, int allowed, const u8 *bssid);
+
+ /**
+ * set_mac_addr - Set MAC address
+ * @priv: Private driver interface data
+ * @addr: MAC address to use or %NULL for setting back to permanent
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_mac_addr)(void *priv, const u8 *addr);
+
+#ifdef CONFIG_MACSEC
+ int (*macsec_init)(void *priv, struct macsec_init_params *params);
+
+ int (*macsec_deinit)(void *priv);
+
+ /**
+ * 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)
+ */
+ int (*enable_protect_frames)(void *priv, Boolean enabled);
+
+ /**
+ * 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)
+ */
+ int (*set_replay_protect)(void *priv, Boolean enabled, u32 window);
+
+ /**
+ * 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);
+
+ /**
+ * 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)
+ */
+ int (*enable_controlled_port)(void *priv, Boolean enabled);
+
+ /**
+ * get_receive_lowest_pn - Get receive lowest pn
+ * @priv: Private driver interface data
+ * @channel: secure channel
+ * @an: association number
+ * @lowest_pn: lowest accept pn
+ * 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);
+
+ /**
+ * get_transmit_next_pn - Get transmit next pn
+ * @priv: Private driver interface data
+ * @channel: secure channel
+ * @an: association number
+ * @next_pn: next pn
+ * 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);
+
+ /**
+ * set_transmit_next_pn - Set transmit next pn
+ * @priv: Private driver interface data
+ * @channel: secure channel
+ * @an: association number
+ * @next_pn: next pn
+ * 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);
+
+ /**
+ * get_available_receive_sc - get available receive channel
+ * @priv: Private driver interface data
+ * @channel: secure channel
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+ int (*get_available_receive_sc)(void *priv, u32 *channel);
+
+ /**
+ * 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
+ * @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 validation);
+
+ /**
+ * delete_receive_sc - delete secure connection for receiving
+ * @priv: private driver interface data from init()
+ * @channel: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*delete_receive_sc)(void *priv, u32 channel);
+
+ /**
+ * 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
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*create_receive_sa)(void *priv, u32 channel, u8 an,
+ u32 lowest_pn, const u8 *sak);
+
+ /**
+ * enable_receive_sa - enable the SA for receive
+ * @priv: private driver interface data from init()
+ * @channel: secure channel
+ * @an: association number
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*enable_receive_sa)(void *priv, u32 channel, u8 an);
+
+ /**
+ * disable_receive_sa - disable SA for receive
+ * @priv: private driver interface data from init()
+ * @channel: secure channel index
+ * @an: association number
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*disable_receive_sa)(void *priv, u32 channel, u8 an);
+
+ /**
+ * 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)
+ */
+ int (*get_available_transmit_sc)(void *priv, u32 *channel);
+
+ /**
+ * 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
+ * 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);
+
+ /**
+ * delete_transmit_sc - delete secure connection for transmit
+ * @priv: private driver interface data from init()
+ * @channel: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*delete_transmit_sc)(void *priv, u32 channel);
+
+ /**
+ * 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
+ * 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);
+
+ /**
+ * enable_transmit_sa - enable SA for transmit
+ * @priv: private driver interface data from init()
+ * @channel: secure channel
+ * @an: association number
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*enable_transmit_sa)(void *priv, u32 channel, u8 an);
+
+ /**
+ * disable_transmit_sa - disable SA for transmit
+ * @priv: private driver interface data from init()
+ * @channel: secure channel
+ * @an: association number
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
+#endif /* CONFIG_MACSEC */
+
+ /**
+ * init_mesh - Driver specific initialization for mesh
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*init_mesh)(void *priv);
+
+ /**
+ * join_mesh - Join a mesh network
+ * @priv: Private driver interface data
+ * @params: Mesh configuration parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*join_mesh)(void *priv,
+ struct wpa_driver_mesh_join_params *params);
+
+ /**
+ * leave_mesh - Leave a mesh network
+ * @priv: Private driver interface data
+ * Returns 0 on success, -1 on failure
+ */
+ int (*leave_mesh)(void *priv);
+
+ /**
+ * do_acs - Automatically select channel
+ * @priv: Private driver interface data
+ * @params: Parameters for ACS
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to offload ACS to the driver if the driver
+ * indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD).
+ */
+ int (*do_acs)(void *priv, struct drv_acs_params *params);
};
@@ -2790,11 +3569,6 @@ enum wpa_event_type {
EVENT_ASSOC_TIMED_OUT,
/**
- * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received
- */
- EVENT_FT_RRB_RX,
-
- /**
* EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS
*/
EVENT_WPS_BUTTON_PUSHED,
@@ -2815,15 +3589,6 @@ enum wpa_event_type {
EVENT_RX_MGMT,
/**
- * EVENT_RX_ACTION - Action frame received
- *
- * This event is used to indicate when an Action frame has been
- * received. Information about the received frame is included in
- * union wpa_event_data::rx_action.
- */
- EVENT_RX_ACTION,
-
- /**
* EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started
*
* This event is used to indicate when the driver has started the
@@ -2843,13 +3608,6 @@ enum wpa_event_type {
EVENT_CANCEL_REMAIN_ON_CHANNEL,
/**
- * EVENT_MLME_RX - Report reception of frame for MLME (test use only)
- *
- * This event is used only by driver_test.c and userspace MLME.
- */
- EVENT_MLME_RX,
-
- /**
* EVENT_RX_PROBE_REQ - Indicate received Probe Request frame
*
* This event is used to indicate when a Probe Request frame has been
@@ -2877,9 +3635,7 @@ enum wpa_event_type {
* EVENT_EAPOL_RX - Report received EAPOL frame
*
* When in AP mode with hostapd, this event is required to be used to
- * deliver the receive EAPOL frames from the driver. With
- * %wpa_supplicant, this event is used only if the send_eapol() handler
- * is used to override the use of l2_packet for EAPOL frame TX.
+ * deliver the receive EAPOL frames from the driver.
*/
EVENT_EAPOL_RX,
@@ -2927,7 +3683,8 @@ enum wpa_event_type {
* the driver does not support radar detection and another virtual
* interfaces caused the operating channel to change. Other similar
* resource conflicts could also trigger this for station mode
- * interfaces.
+ * interfaces. This event can be propagated when channel switching
+ * fails.
*/
EVENT_INTERFACE_UNAVAILABLE,
@@ -2970,38 +3727,6 @@ enum wpa_event_type {
EVENT_STATION_LOW_ACK,
/**
- * EVENT_P2P_DEV_FOUND - Report a discovered P2P device
- *
- * This event is used only if the driver implements P2P management
- * internally. Event data is stored in
- * union wpa_event_data::p2p_dev_found.
- */
- EVENT_P2P_DEV_FOUND,
-
- /**
- * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request
- *
- * This event is used only if the driver implements P2P management
- * internally. Event data is stored in
- * union wpa_event_data::p2p_go_neg_req_rx.
- */
- EVENT_P2P_GO_NEG_REQ_RX,
-
- /**
- * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation
- *
- * This event is used only if the driver implements P2P management
- * internally. Event data is stored in
- * union wpa_event_data::p2p_go_neg_completed.
- */
- EVENT_P2P_GO_NEG_COMPLETED,
-
- EVENT_P2P_PROV_DISC_REQUEST,
- EVENT_P2P_PROV_DISC_RESPONSE,
- EVENT_P2P_SD_REQUEST,
- EVENT_P2P_SD_RESPONSE,
-
- /**
* EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
*/
EVENT_IBSS_PEER_LOST,
@@ -3046,11 +3771,138 @@ enum wpa_event_type {
*
* This event can be used to request a WNM operation to be performed.
*/
- EVENT_WNM
+ EVENT_WNM,
+
+ /**
+ * EVENT_CONNECT_FAILED_REASON - Connection failure reason in AP mode
+ *
+ * This event indicates that the driver reported a connection failure
+ * with the specified client (for example, max client reached, etc.) in
+ * AP mode.
+ */
+ EVENT_CONNECT_FAILED_REASON,
+
+ /**
+ * EVENT_DFS_RADAR_DETECTED - Notify of radar detection
+ *
+ * A radar has been detected on the supplied frequency, hostapd should
+ * react accordingly (e.g., change channel).
+ */
+ EVENT_DFS_RADAR_DETECTED,
+
+ /**
+ * EVENT_DFS_CAC_FINISHED - Notify that channel availability check has been completed
+ *
+ * After a successful CAC, the channel can be marked clear and used.
+ */
+ EVENT_DFS_CAC_FINISHED,
+
+ /**
+ * EVENT_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
+ * external influences.
+ */
+ EVENT_DFS_CAC_ABORTED,
+
+ /**
+ * EVENT_DFS_NOP_FINISHED - Notify that non-occupancy period is over
+ *
+ * The channel which was previously unavailable is now available again.
+ */
+ EVENT_DFS_NOP_FINISHED,
+
+ /**
+ * EVENT_SURVEY - Received survey data
+ *
+ * This event gets triggered when a driver query is issued for survey
+ * data and the requested data becomes available. The returned data is
+ * stored in struct survey_results. The results provide at most one
+ * survey entry for each frequency and at minimum will provide one
+ * survey entry for one frequency. The survey data can be os_malloc()'d
+ * and then os_free()'d, so the event callback must only copy data.
+ */
+ EVENT_SURVEY,
+
+ /**
+ * EVENT_SCAN_STARTED - Scan started
+ *
+ * This indicates that driver has started a scan operation either based
+ * on a request from wpa_supplicant/hostapd or from another application.
+ * EVENT_SCAN_RESULTS is used to indicate when the scan has been
+ * completed (either successfully or by getting cancelled).
+ */
+ EVENT_SCAN_STARTED,
+
+ /**
+ * EVENT_AVOID_FREQUENCIES - Received avoid frequency range
+ *
+ * This event indicates a set of frequency ranges that should be avoided
+ * to reduce issues due to interference or internal co-existence
+ * information in the driver.
+ */
+ EVENT_AVOID_FREQUENCIES,
+
+ /**
+ * EVENT_NEW_PEER_CANDIDATE - new (unknown) mesh peer notification
+ */
+ EVENT_NEW_PEER_CANDIDATE,
+
+ /**
+ * EVENT_ACS_CHANNEL_SELECTED - Received selected channels by ACS
+ *
+ * Indicates a pair of primary and secondary channels chosen by ACS
+ * in device.
+ */
+ EVENT_ACS_CHANNEL_SELECTED,
+
+ /**
+ * EVENT_DFS_CAC_STARTED - Notify that channel availability check has
+ * been started.
+ *
+ * This event indicates that channel availability check has been started
+ * on a DFS frequency by a driver that supports DFS Offload.
+ */
+ EVENT_DFS_CAC_STARTED,
};
/**
+ * struct freq_survey - Channel survey info
+ *
+ * @ifidx: Interface index in which this survey was observed
+ * @freq: Center of frequency of the surveyed channel
+ * @nf: Channel noise floor in dBm
+ * @channel_time: Amount of time in ms the radio spent on the channel
+ * @channel_time_busy: Amount of time in ms the radio detected some signal
+ * that indicated to the radio the channel was not clear
+ * @channel_time_rx: Amount of time the radio spent receiving data
+ * @channel_time_tx: Amount of time the radio spent transmitting data
+ * @filled: bitmask indicating which fields have been reported, see
+ * SURVEY_HAS_* defines.
+ * @list: Internal list pointers
+ */
+struct freq_survey {
+ u32 ifidx;
+ unsigned int freq;
+ s8 nf;
+ u64 channel_time;
+ u64 channel_time_busy;
+ u64 channel_time_rx;
+ u64 channel_time_tx;
+ unsigned int filled;
+ struct dl_list list;
+};
+
+#define SURVEY_HAS_NF BIT(0)
+#define SURVEY_HAS_CHAN_TIME BIT(1)
+#define SURVEY_HAS_CHAN_TIME_BUSY BIT(2)
+#define SURVEY_HAS_CHAN_TIME_RX BIT(3)
+#define SURVEY_HAS_CHAN_TIME_TX BIT(4)
+
+
+/**
* union wpa_event_data - Additional data for wpa_supplicant_event() calls
*/
union wpa_event_data {
@@ -3132,9 +3984,62 @@ union wpa_event_data {
unsigned int freq;
/**
+ * wmm_params - WMM parameters used in this association.
+ */
+ struct wmm_params wmm_params;
+
+ /**
* addr - Station address (for AP mode)
*/
const u8 *addr;
+
+ /**
+ * The following is the key management offload information
+ * @authorized
+ * @key_replay_ctr
+ * @key_replay_ctr_len
+ * @ptk_kck
+ * @ptk_kek_len
+ * @ptk_kek
+ * @ptk_kek_len
+ */
+
+ /**
+ * authorized - Status of key management offload,
+ * 1 = successful
+ */
+ int authorized;
+
+ /**
+ * key_replay_ctr - Key replay counter value last used
+ * in a valid EAPOL-Key frame
+ */
+ const u8 *key_replay_ctr;
+
+ /**
+ * key_replay_ctr_len - The length of key_replay_ctr
+ */
+ size_t key_replay_ctr_len;
+
+ /**
+ * ptk_kck - The derived PTK KCK
+ */
+ const u8 *ptk_kck;
+
+ /**
+ * ptk_kek_len - The length of ptk_kck
+ */
+ size_t ptk_kck_len;
+
+ /**
+ * ptk_kek - The derived PTK KEK
+ */
+ const u8 *ptk_kek;
+
+ /**
+ * ptk_kek_len - The length of ptk_kek
+ */
+ size_t ptk_kek_len;
} assoc_info;
/**
@@ -3243,7 +4148,8 @@ union wpa_event_data {
u8 peer[ETH_ALEN];
enum {
TDLS_REQUEST_SETUP,
- TDLS_REQUEST_TEARDOWN
+ TDLS_REQUEST_TEARDOWN,
+ TDLS_REQUEST_DISCOVER,
} oper;
u16 reason_code; /* for teardown */
} tdls;
@@ -3344,15 +4250,6 @@ union wpa_event_data {
} timeout_event;
/**
- * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events
- */
- struct ft_rrb_rx {
- const u8 *src;
- const u8 *data;
- size_t data_len;
- } ft_rrb_rx;
-
- /**
* struct tx_status - Data for EVENT_TX_STATUS events
*/
struct tx_status {
@@ -3380,48 +4277,26 @@ union wpa_event_data {
const u8 *frame;
size_t frame_len;
u32 datarate;
- int ssi_signal; /* dBm */
- } rx_mgmt;
-
- /**
- * struct rx_action - Data for EVENT_RX_ACTION events
- */
- struct rx_action {
- /**
- * da - Destination address of the received Action frame
- */
- const u8 *da;
-
- /**
- * sa - Source address of the received Action frame
- */
- const u8 *sa;
-
- /**
- * bssid - Address 3 of the received Action frame
- */
- const u8 *bssid;
-
- /**
- * category - Action frame category
- */
- u8 category;
/**
- * data - Action frame body after category field
+ * drv_priv - Pointer to store driver private BSS information
+ *
+ * If not set to NULL, this is used for comparison with
+ * hostapd_data->drv_priv to determine which BSS should process
+ * the frame.
*/
- const u8 *data;
+ void *drv_priv;
/**
- * len - Length of data in octets
+ * freq - Frequency (in MHz) on which the frame was received
*/
- size_t len;
+ int freq;
/**
- * freq - Frequency (in MHz) on which the frame was received
+ * ssi_signal - Signal strength in dBm (or 0 if not available)
*/
- int freq;
- } rx_action;
+ int ssi_signal;
+ } rx_mgmt;
/**
* struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events
@@ -3458,17 +4333,6 @@ union wpa_event_data {
} scan_info;
/**
- * struct mlme_rx - Data for EVENT_MLME_RX events
- */
- struct mlme_rx {
- const u8 *buf;
- size_t len;
- int freq;
- int channel;
- int ssi;
- } mlme_rx;
-
- /**
* struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events
*/
struct rx_probe_req {
@@ -3561,66 +4425,6 @@ union wpa_event_data {
} low_ack;
/**
- * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND
- */
- struct p2p_dev_found {
- const u8 *addr;
- const u8 *dev_addr;
- const u8 *pri_dev_type;
- const char *dev_name;
- u16 config_methods;
- u8 dev_capab;
- u8 group_capab;
- } p2p_dev_found;
-
- /**
- * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX
- */
- struct p2p_go_neg_req_rx {
- const u8 *src;
- u16 dev_passwd_id;
- } p2p_go_neg_req_rx;
-
- /**
- * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED
- */
- struct p2p_go_neg_completed {
- struct p2p_go_neg_results *res;
- } p2p_go_neg_completed;
-
- struct p2p_prov_disc_req {
- const u8 *peer;
- u16 config_methods;
- const u8 *dev_addr;
- const u8 *pri_dev_type;
- const char *dev_name;
- u16 supp_config_methods;
- u8 dev_capab;
- u8 group_capab;
- } p2p_prov_disc_req;
-
- struct p2p_prov_disc_resp {
- const u8 *peer;
- u16 config_methods;
- } p2p_prov_disc_resp;
-
- struct p2p_sd_req {
- int freq;
- const u8 *sa;
- u8 dialog_token;
- u16 update_indic;
- const u8 *tlvs;
- size_t tlvs_len;
- } p2p_sd_req;
-
- struct p2p_sd_resp {
- const u8 *sa;
- u16 update_indic;
- const u8 *tlvs;
- size_t tlvs_len;
- } p2p_sd_resp;
-
- /**
* struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST
*/
struct ibss_peer_lost {
@@ -3665,12 +4469,99 @@ union wpa_event_data {
* @freq: Frequency of new channel in MHz
* @ht_enabled: Whether this is an HT channel
* @ch_offset: Secondary channel offset
+ * @ch_width: Channel width
+ * @cf1: Center frequency 1
+ * @cf2: Center frequency 2
*/
struct ch_switch {
int freq;
int ht_enabled;
int ch_offset;
+ enum chan_width ch_width;
+ int cf1;
+ int cf2;
} ch_switch;
+
+ /**
+ * struct connect_failed - Data for EVENT_CONNECT_FAILED_REASON
+ * @addr: Remote client address
+ * @code: Reason code for connection failure
+ */
+ struct connect_failed_reason {
+ u8 addr[ETH_ALEN];
+ enum {
+ MAX_CLIENT_REACHED,
+ BLOCKED_CLIENT
+ } code;
+ } connect_failed_reason;
+
+ /**
+ * struct dfs_event - Data for radar detected events
+ * @freq: Frequency of the channel in MHz
+ */
+ struct dfs_event {
+ int freq;
+ int ht_enabled;
+ int chan_offset;
+ enum chan_width chan_width;
+ int cf1;
+ int cf2;
+ } dfs_event;
+
+ /**
+ * survey_results - Survey result data for EVENT_SURVEY
+ * @freq_filter: Requested frequency survey filter, 0 if request
+ * was for all survey data
+ * @survey_list: Linked list of survey data (struct freq_survey)
+ */
+ struct survey_results {
+ unsigned int freq_filter;
+ struct dl_list survey_list; /* struct freq_survey */
+ } survey_results;
+
+ /**
+ * channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
+ * @initiator: Initiator of the regulatory change
+ * @type: Regulatory change type
+ * @alpha2: Country code (or "" if not available)
+ */
+ struct channel_list_changed {
+ enum reg_change_initiator initiator;
+ enum reg_type type;
+ char alpha2[3];
+ } channel_list_changed;
+
+ /**
+ * freq_range - List of frequency ranges
+ *
+ * This is used as the data with EVENT_AVOID_FREQUENCIES.
+ */
+ struct wpa_freq_range_list freq_range;
+
+ /**
+ * struct mesh_peer
+ *
+ * @peer: Peer address
+ * @ies: Beacon IEs
+ * @ie_len: Length of @ies
+ *
+ * Notification of new candidate mesh peer.
+ */
+ struct mesh_peer {
+ const u8 *peer;
+ const u8 *ies;
+ size_t ie_len;
+ } mesh_peer;
+
+ /**
+ * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
+ * @pri_channel: Selected primary channel
+ * @sec_channel: Selected secondary channel
+ */
+ struct acs_selected_channels {
+ u8 pri_channel;
+ u8 sec_channel;
+ } acs_selected_channels;
};
/**
@@ -3729,4 +4620,17 @@ void wpa_scan_results_free(struct wpa_scan_results *res);
/* Convert wpa_event_type to a string for logging */
const char * event_to_string(enum wpa_event_type event);
+/* Convert chan_width to a string for logging and control interfaces */
+const char * channel_width_to_string(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);
+
+/* NULL terminated array of linked in driver wrappers */
+extern struct wpa_driver_ops *wpa_drivers[];
+
#endif /* DRIVER_H */
diff --git a/contrib/wpa/src/drivers/driver_bsd.c b/contrib/wpa/src/drivers/driver_bsd.c
index d3bca6f..63b0e19 100644
--- a/contrib/wpa/src/drivers/driver_bsd.c
+++ b/contrib/wpa/src/drivers/driver_bsd.c
@@ -62,36 +62,11 @@ 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 enum ieee80211_opmode
-get80211opmode(struct bsd_driver_data *drv)
-{
- struct ifmediareq ifmr;
-
- (void) memset(&ifmr, 0, sizeof(ifmr));
- (void) strncpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
-
- if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
- if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
- if (ifmr.ifm_current & IFM_FLAG0)
- return IEEE80211_M_AHDEMO;
- else
- return IEEE80211_M_IBSS;
- }
- if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
- return IEEE80211_M_HOSTAP;
- if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
- return IEEE80211_M_MONITOR;
- if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
- return IEEE80211_M_MBSS;
- }
- return IEEE80211_M_STA;
-}
-
-
static int
bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
{
@@ -288,7 +263,8 @@ bsd_ctrl_iface(void *priv, int enable)
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
return -1;
}
@@ -303,7 +279,8 @@ bsd_ctrl_iface(void *priv, int enable)
}
if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
return -1;
}
@@ -311,18 +288,14 @@ bsd_ctrl_iface(void *priv, int enable)
}
static int
-bsd_commit(void *priv)
-{
- return bsd_ctrl_iface(priv, 1);
-}
-
-static int
bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
size_t seq_len, const u8 *key, size_t key_len)
{
struct ieee80211req_key wk;
+#ifdef IEEE80211_KEY_NOREPLAY
struct bsd_driver_data *drv = priv;
+#endif /* IEEE80211_KEY_NOREPLAY */
wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
"seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -378,13 +351,15 @@ bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
#ifndef HOSTAPD
+#ifdef IEEE80211_KEY_NOREPLAY
/*
* Ignore replay failures in IBSS and AHDEMO mode.
*/
if (drv->opmode == IEEE80211_M_IBSS ||
drv->opmode == IEEE80211_M_AHDEMO)
wk.ik_flags |= IEEE80211_KEY_NOREPLAY;
-#endif
+#endif /* IEEE80211_KEY_NOREPLAY */
+#endif /* HOSTAPD */
wk.ik_keylen = key_len;
if (seq) {
#ifdef WORDS_BIGENDIAN
@@ -430,22 +405,24 @@ bsd_configure_wpa(void *priv, struct wpa_bss_params *params)
v = IEEE80211_CIPHER_NONE;
break;
default:
- printf("Unknown group key cipher %u\n",
- params->wpa_group);
+ wpa_printf(MSG_INFO, "Unknown group key cipher %u",
+ params->wpa_group);
return -1;
}
wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
__func__, ciphernames[v], v);
if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
- printf("Unable to set group key cipher to %u (%s)\n",
- v, ciphernames[v]);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key cipher to %u (%s)",
+ v, ciphernames[v]);
return -1;
}
if (v == IEEE80211_CIPHER_WEP) {
/* key length is done only for specific ciphers */
v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
- printf("Unable to set group key length to %u\n", v);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key length to %u", v);
return -1;
}
}
@@ -459,7 +436,8 @@ bsd_configure_wpa(void *priv, struct wpa_bss_params *params)
v |= 1<<IEEE80211_CIPHER_NONE;
wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
- printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ wpa_printf(MSG_INFO,
+ "Unable to set pairwise key ciphers to 0x%x", v);
return -1;
}
@@ -467,8 +445,9 @@ bsd_configure_wpa(void *priv, struct wpa_bss_params *params)
__func__, params->wpa_key_mgmt);
if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
params->wpa_key_mgmt)) {
- printf("Unable to set key management algorithms to 0x%x\n",
- params->wpa_key_mgmt);
+ wpa_printf(MSG_INFO,
+ "Unable to set key management algorithms to 0x%x",
+ params->wpa_key_mgmt);
return -1;
}
@@ -478,14 +457,15 @@ bsd_configure_wpa(void *priv, struct wpa_bss_params *params)
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
__func__, params->rsn_preauth);
if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
- printf("Unable to set RSN capabilities to 0x%x\n", v);
+ wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
+ v);
return -1;
}
#endif /* IEEE80211_IOC_APPIE */
wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
- printf("Unable to set WPA to %u\n", params->wpa);
+ wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
return -1;
}
return 0;
@@ -520,26 +500,6 @@ bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
return bsd_ctrl_iface(priv, 1);
}
-static int
-bsd_set_sta_authorized(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
-{
- int authorized = -1;
-
- /* For now, only support setting Authorized flag */
- if (flags_or & WPA_STA_AUTHORIZED)
- authorized = 1;
- if (!(flags_and & WPA_STA_AUTHORIZED))
- authorized = 0;
-
- if (authorized < 0)
- return 0;
-
- return bsd_send_mlme_param(priv, authorized ?
- IEEE80211_MLME_AUTHORIZE :
- IEEE80211_MLME_UNAUTHORIZE, 0, addr);
-}
-
static void
bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
{
@@ -553,7 +513,8 @@ bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
memset(&ie, 0, sizeof(ie));
memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
- printf("Failed to get WPA/RSN information element.\n");
+ wpa_printf(MSG_INFO,
+ "Failed to get WPA/RSN information element");
goto no_ie;
}
iebuf = ie.wpa_ie;
@@ -632,7 +593,7 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
return 0;
}
-static int
+static size_t
rtbuf_len(void)
{
size_t len;
@@ -640,7 +601,7 @@ rtbuf_len(void)
int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
- wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__,
+ wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
strerror(errno));
len = 2048;
}
@@ -698,7 +659,7 @@ bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
wk.ik_keyix = idx;
if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
- printf("Failed to get encryption.\n");
+ wpa_printf(MSG_INFO, "Failed to get encryption");
return -1;
}
@@ -722,7 +683,7 @@ bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
}
-static int
+static int
bsd_flush(void *priv)
{
u8 allsta[IEEE80211_ADDR_LEN];
@@ -769,37 +730,26 @@ static void
bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
{
struct bsd_driver_data *drv = ctx;
- char *buf;
struct if_announcemsghdr *ifan;
struct rt_msghdr *rtm;
struct ieee80211_michael_event *mic;
struct ieee80211_join_event *join;
struct ieee80211_leave_event *leave;
- int n, len;
+ int n;
union wpa_event_data data;
- len = rtbuf_len();
-
- buf = os_malloc(len);
- if (buf == NULL) {
- wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
- return;
- }
-
- n = read(sock, buf, len);
+ n = read(sock, drv->event_buf, drv->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
- os_free(buf);
return;
}
- rtm = (struct rt_msghdr *) buf;
+ rtm = (struct rt_msghdr *) drv->event_buf;
if (rtm->rtm_version != RTM_VERSION) {
wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
rtm->rtm_version);
- os_free(buf);
return;
}
ifan = (struct if_announcemsghdr *) rtm;
@@ -840,7 +790,6 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
}
break;
}
- os_free(buf);
}
static void
@@ -857,14 +806,23 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
drv = os_zalloc(sizeof(struct bsd_driver_data));
if (drv == NULL) {
- printf("Could not allocate memory for bsd driver data\n");
+ wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data");
+ return NULL;
+ }
+
+ drv->event_buf_len = rtbuf_len();
+
+ drv->event_buf = os_malloc(drv->event_buf_len);
+ if (drv->event_buf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
goto bad;
}
drv->hapd = hapd;
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
goto bad;
}
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
@@ -882,7 +840,8 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
if (drv->route < 0) {
- perror("socket(PF_ROUTE,SOCK_RAW)");
+ 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,
@@ -900,6 +859,7 @@ bad:
l2_packet_deinit(drv->sock_xmit);
if (drv->sock >= 0)
close(drv->sock);
+ os_free(drv->event_buf);
if (drv != NULL)
os_free(drv);
return NULL;
@@ -920,9 +880,37 @@ bsd_deinit(void *priv)
close(drv->sock);
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
+ os_free(drv->event_buf);
os_free(drv);
}
+
+static int
+bsd_commit(void *priv)
+{
+ return bsd_ctrl_iface(priv, 1);
+}
+
+
+static int
+bsd_set_sta_authorized(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ int authorized = -1;
+
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WPA_STA_AUTHORIZED)
+ authorized = 1;
+ if (!(flags_and & WPA_STA_AUTHORIZED))
+ authorized = 0;
+
+ if (authorized < 0)
+ return 0;
+
+ return bsd_send_mlme_param(priv, authorized ?
+ IEEE80211_MLME_AUTHORIZE :
+ IEEE80211_MLME_UNAUTHORIZE, 0, addr);
+}
#else /* HOSTAPD */
static int
@@ -1100,9 +1088,9 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
return -1;
- privacy = !(params->pairwise_suite == CIPHER_NONE &&
- params->group_suite == CIPHER_NONE &&
- params->key_mgmt_suite == KEY_MGMT_NONE &&
+ privacy = !(params->pairwise_suite == WPA_CIPHER_NONE &&
+ params->group_suite == WPA_CIPHER_NONE &&
+ params->key_mgmt_suite == WPA_KEY_MGMT_NONE &&
params->wpa_ie_len == 0);
wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
@@ -1198,7 +1186,6 @@ static void
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
{
struct bsd_driver_data *drv = sock_ctx;
- char *buf;
struct if_announcemsghdr *ifan;
struct if_msghdr *ifm;
struct rt_msghdr *rtm;
@@ -1206,30 +1193,20 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
struct ieee80211_michael_event *mic;
struct ieee80211_leave_event *leave;
struct ieee80211_join_event *join;
- int n, len;
-
- len = rtbuf_len();
+ int n;
- buf = os_malloc(len);
- if (buf == NULL) {
- wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
- return;
- }
-
- n = read(sock, buf, len);
+ n = read(sock, drv->event_buf, drv->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
- os_free(buf);
return;
}
- rtm = (struct rt_msghdr *) buf;
+ rtm = (struct rt_msghdr *) drv->event_buf;
if (rtm->rtm_version != RTM_VERSION) {
wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
rtm->rtm_version);
- os_free(buf);
return;
}
os_memset(&event, 0, sizeof(event));
@@ -1244,7 +1221,6 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
case IFAN_DEPARTURE:
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
default:
- os_free(buf);
return;
}
wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
@@ -1317,7 +1293,6 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
}
break;
}
- os_free(buf);
}
static void
@@ -1368,7 +1343,12 @@ wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
*pos++ = 1;
*pos++ = sr->isr_erp;
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len + sr->isr_meshid_len,
+ sr->isr_ie_len);
+#else
os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
+#endif
pos += sr->isr_ie_len;
result->ie_len = pos - (u8 *)(result + 1);
@@ -1500,6 +1480,33 @@ static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
return 0;
}
+static enum ieee80211_opmode
+get80211opmode(struct bsd_driver_data *drv)
+{
+ struct ifmediareq ifmr;
+
+ (void) memset(&ifmr, 0, sizeof(ifmr));
+ (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
+
+ if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+ if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
+ if (ifmr.ifm_current & IFM_FLAG0)
+ return IEEE80211_M_AHDEMO;
+ else
+ return IEEE80211_M_IBSS;
+ }
+ if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+ return IEEE80211_M_HOSTAP;
+ if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+ return IEEE80211_M_MONITOR;
+#ifdef IEEE80211_M_MBSS
+ if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
+ return IEEE80211_M_MBSS;
+#endif /* IEEE80211_M_MBSS */
+ }
+ return IEEE80211_M_STA;
+}
+
static void *
wpa_driver_bsd_init(void *ctx, const char *ifname)
{
@@ -1510,6 +1517,15 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
+
+ drv->event_buf_len = rtbuf_len();
+
+ drv->event_buf = os_malloc(drv->event_buf_len);
+ if (drv->event_buf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+ goto fail1;
+ }
+
/*
* NB: We require the interface name be mappable to an index.
* This implies we do not support having wpa_supplicant
@@ -1564,6 +1580,7 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
fail:
close(drv->sock);
fail1:
+ os_free(drv->event_buf);
os_free(drv);
return NULL;
#undef GETPARAM
@@ -1589,6 +1606,7 @@ wpa_driver_bsd_deinit(void *priv)
l2_packet_deinit(drv->sock_xmit);
(void) close(drv->route); /* ioctl socket */
(void) close(drv->sock); /* event socket */
+ os_free(drv->event_buf);
os_free(drv);
}
diff --git a/contrib/wpa/src/drivers/driver_common.c b/contrib/wpa/src/drivers/driver_common.c
index 418cf1a..aebea8c 100644
--- a/contrib/wpa/src/drivers/driver_common.c
+++ b/contrib/wpa/src/drivers/driver_common.c
@@ -44,15 +44,12 @@ const char * event_to_string(enum wpa_event_type event)
E2S(ASSOC_REJECT);
E2S(AUTH_TIMED_OUT);
E2S(ASSOC_TIMED_OUT);
- E2S(FT_RRB_RX);
E2S(WPS_BUTTON_PUSHED);
E2S(TX_STATUS);
E2S(RX_FROM_UNKNOWN);
E2S(RX_MGMT);
- E2S(RX_ACTION);
E2S(REMAIN_ON_CHANNEL);
E2S(CANCEL_REMAIN_ON_CHANNEL);
- E2S(MLME_RX);
E2S(RX_PROBE_REQ);
E2S(NEW_STA);
E2S(EAPOL_RX);
@@ -65,13 +62,6 @@ const char * event_to_string(enum wpa_event_type event)
E2S(UNPROT_DEAUTH);
E2S(UNPROT_DISASSOC);
E2S(STATION_LOW_ACK);
- E2S(P2P_DEV_FOUND);
- E2S(P2P_GO_NEG_REQ_RX);
- E2S(P2P_GO_NEG_COMPLETED);
- E2S(P2P_PROV_DISC_REQUEST);
- E2S(P2P_PROV_DISC_RESPONSE);
- E2S(P2P_SD_REQUEST);
- E2S(P2P_SD_RESPONSE);
E2S(IBSS_PEER_LOST);
E2S(DRIVER_GTK_REKEY);
E2S(SCHED_SCAN_STOPPED);
@@ -79,8 +69,152 @@ const char * event_to_string(enum wpa_event_type event)
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
E2S(WNM);
+ E2S(CONNECT_FAILED_REASON);
+ E2S(DFS_RADAR_DETECTED);
+ E2S(DFS_CAC_FINISHED);
+ E2S(DFS_CAC_ABORTED);
+ E2S(DFS_NOP_FINISHED);
+ E2S(SURVEY);
+ E2S(SCAN_STARTED);
+ E2S(AVOID_FREQUENCIES);
+ E2S(NEW_PEER_CANDIDATE);
+ E2S(ACS_CHANNEL_SELECTED);
+ E2S(DFS_CAC_STARTED);
}
return "UNKNOWN";
#undef E2S
}
+
+
+const char * channel_width_to_string(enum chan_width width)
+{
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ return "20 MHz (no HT)";
+ case CHAN_WIDTH_20:
+ return "20 MHz";
+ case CHAN_WIDTH_40:
+ return "40 MHz";
+ case CHAN_WIDTH_80:
+ return "80 MHz";
+ case CHAN_WIDTH_80P80:
+ return "80+80 MHz";
+ case CHAN_WIDTH_160:
+ return "160 MHz";
+ default:
+ return "unknown";
+ }
+}
+
+
+int ht_supported(const struct hostapd_hw_modes *mode)
+{
+ if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
+ /*
+ * The driver did not indicate whether it supports HT. Assume
+ * it does to avoid connection issues.
+ */
+ return 1;
+ }
+
+ /*
+ * IEEE Std 802.11n-2009 20.1.1:
+ * An HT non-AP STA shall support all EQM rates for one spatial stream.
+ */
+ return mode->mcs_set[0] == 0xff;
+}
+
+
+int vht_supported(const struct hostapd_hw_modes *mode)
+{
+ if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
+ /*
+ * The driver did not indicate whether it supports VHT. Assume
+ * it does to avoid connection issues.
+ */
+ return 1;
+ }
+
+ /*
+ * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
+ * TODO: Verify if this complies with the standard
+ */
+ return (mode->vht_mcs_set[0] & 0x3) != 3;
+}
+
+
+static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
+ int capa_trigger, u8 *param_trigger)
+{
+ if (os_strcmp(start, trigger) != 0)
+ return 0;
+ if (!capa_trigger)
+ return 0;
+
+ *param_trigger = 1;
+ return 1;
+}
+
+
+struct wowlan_triggers *
+wpa_get_wowlan_triggers(const char *wowlan_triggers,
+ const struct wpa_driver_capa *capa)
+{
+ struct wowlan_triggers *triggers;
+ char *start, *end, *buf;
+ int last;
+
+ if (!wowlan_triggers)
+ return NULL;
+
+ buf = os_strdup(wowlan_triggers);
+ if (buf == NULL)
+ return NULL;
+
+ triggers = os_zalloc(sizeof(*triggers));
+ if (triggers == NULL)
+ goto out;
+
+#define CHECK_TRIGGER(trigger) \
+ wpa_check_wowlan_trigger(start, #trigger, \
+ capa->wowlan_triggers.trigger, \
+ &triggers->trigger)
+
+ start = buf;
+ while (*start != '\0') {
+ while (isblank(*start))
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (!isblank(*end) && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+
+ if (!CHECK_TRIGGER(any) &&
+ !CHECK_TRIGGER(disconnect) &&
+ !CHECK_TRIGGER(magic_pkt) &&
+ !CHECK_TRIGGER(gtk_rekey_failure) &&
+ !CHECK_TRIGGER(eap_identity_req) &&
+ !CHECK_TRIGGER(four_way_handshake) &&
+ !CHECK_TRIGGER(rfkill_release)) {
+ wpa_printf(MSG_DEBUG,
+ "Unknown/unsupported wowlan trigger '%s'",
+ start);
+ os_free(triggers);
+ triggers = NULL;
+ goto out;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+#undef CHECK_TRIGGER
+
+out:
+ os_free(buf);
+ return triggers;
+}
diff --git a/contrib/wpa/src/drivers/driver_macsec_qca.c b/contrib/wpa/src/drivers/driver_macsec_qca.c
new file mode 100644
index 0000000..3eae2f8
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_macsec_qca.c
@@ -0,0 +1,891 @@
+/*
+ * Wired Ethernet driver interface for QCA MACsec driver
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <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__ */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/defs.h"
+#include "common/ieee802_1x_defs.h"
+#include "driver.h"
+
+#include "nss_macsec_secy.h"
+#include "nss_macsec_secy_rx.h"
+#include "nss_macsec_secy_tx.h"
+
+#define MAXSC 16
+
+/* TCI field definition */
+#define TCI_ES 0x40
+#define TCI_SC 0x20
+#define TCI_SCB 0x10
+#define TCI_E 0x08
+#define TCI_C 0x04
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+struct macsec_qca_data {
+ char ifname[IFNAMSIZ + 1];
+ u32 secy_id;
+ void *ctx;
+
+ int sock; /* raw packet socket for driver access */
+ int pf_sock;
+ int membership, multi, iff_allmulti, iff_up;
+
+ /* shadow */
+ Boolean always_include_sci;
+ Boolean use_es;
+ Boolean use_scb;
+ 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;
+}
+
+
+static void __macsec_drv_init(struct macsec_qca_data *drv)
+{
+ int ret = 0;
+ fal_rx_ctl_filt_t rx_ctl_filt;
+ fal_tx_ctl_filt_t tx_ctl_filt;
+
+ wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
+
+ /* Enable Secy and Let EAPoL bypass */
+ ret = nss_macsec_secy_en_set(drv->secy_id, TRUE);
+ if (ret)
+ wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
+
+ ret = nss_macsec_secy_sc_sa_mapping_mode_set(drv->secy_id,
+ FAL_SC_SA_MAP_1_4);
+ if (ret)
+ wpa_printf(MSG_ERROR,
+ "nss_macsec_secy_sc_sa_mapping_mode_set: FAIL");
+
+ os_memset(&rx_ctl_filt, 0, sizeof(rx_ctl_filt));
+ rx_ctl_filt.bypass = 1;
+ rx_ctl_filt.match_type = IG_CTL_COMPARE_ETHER_TYPE;
+ rx_ctl_filt.match_mask = 0xffff;
+ rx_ctl_filt.ether_type_da_range = 0x888e;
+ ret = nss_macsec_secy_rx_ctl_filt_set(drv->secy_id, 0, &rx_ctl_filt);
+ if (ret)
+ wpa_printf(MSG_ERROR, "nss_macsec_secy_rx_ctl_filt_set: FAIL");
+
+ os_memset(&tx_ctl_filt, 0, sizeof(tx_ctl_filt));
+ tx_ctl_filt.bypass = 1;
+ tx_ctl_filt.match_type = EG_CTL_COMPARE_ETHER_TYPE;
+ tx_ctl_filt.match_mask = 0xffff;
+ tx_ctl_filt.ether_type_da_range = 0x888e;
+ ret = nss_macsec_secy_tx_ctl_filt_set(drv->secy_id, 0, &tx_ctl_filt);
+ if (ret)
+ wpa_printf(MSG_ERROR, "nss_macsec_secy_tx_ctl_filt_set: FAIL");
+}
+
+
+static void __macsec_drv_deinit(struct macsec_qca_data *drv)
+{
+ nss_macsec_secy_en_set(drv->secy_id, FALSE);
+ nss_macsec_secy_rx_sc_del_all(drv->secy_id);
+ nss_macsec_secy_tx_sc_del_all(drv->secy_id);
+}
+
+
+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)
+ drv->secy_id = 1;
+ else if (os_memcmp("eth3", drv->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__);
+ 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;
+}
+
+
+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);
+
+ os_free(drv);
+}
+
+
+static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
+{
+ struct macsec_qca_data *drv = priv;
+
+ drv->always_include_sci = params->always_include_sci;
+ drv->use_es = params->use_es;
+ drv->use_scb = params->use_scb;
+
+ wpa_printf(MSG_DEBUG, "%s: es=%d, scb=%d, sci=%d",
+ __func__, drv->use_es, drv->use_scb,
+ drv->always_include_sci);
+
+ __macsec_drv_init(drv);
+
+ return 0;
+}
+
+
+static int macsec_qca_macsec_deinit(void *priv)
+{
+ struct macsec_qca_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ __macsec_drv_deinit(drv);
+
+ return 0;
+}
+
+
+static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ drv->protect_frames = enabled;
+
+ return ret;
+}
+
+
+static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
+ unsigned int window)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d, win=%u",
+ __func__, enabled, window);
+
+ drv->replay_protect = enabled;
+ drv->replay_window = window;
+
+ return ret;
+}
+
+
+static int macsec_qca_set_current_cipher_suite(void *priv, const u8 *cs,
+ size_t cs_len)
+{
+ u8 default_cs_id[] = CS_ID_GCM_AES_128;
+
+ 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);
+ return -1;
+ }
+
+ /* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
+ wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
+
+ return 0;
+}
+
+
+static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: enable=%d", __func__, enabled);
+
+ ret += nss_macsec_secy_controlled_port_en_set(drv->secy_id, enabled);
+
+ return ret;
+}
+
+
+static int macsec_qca_get_receive_lowest_pn(void *priv, u32 channel, u8 an,
+ u32 *lowest_pn)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+ u32 next_pn = 0;
+ bool enabled = FALSE;
+ u32 win;
+
+ ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, an,
+ &next_pn);
+ ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
+ &enabled);
+ ret += nss_macsec_secy_rx_sc_anti_replay_window_get(drv->secy_id,
+ channel, &win);
+
+ if (enabled)
+ *lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
+ else
+ *lowest_pn = next_pn;
+
+ wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, *lowest_pn);
+
+ return ret;
+}
+
+
+static int macsec_qca_get_transmit_next_pn(void *priv, u32 channel, u8 an,
+ u32 *next_pn)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, an,
+ next_pn);
+
+ wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, *next_pn);
+
+ return ret;
+}
+
+
+int macsec_qca_set_transmit_next_pn(void *priv, u32 channel, u8 an, u32 next_pn)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, an,
+ next_pn);
+
+ wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, next_pn);
+
+ return ret;
+}
+
+
+static int macsec_qca_get_available_receive_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_rx_sc_in_used_get(drv->secy_id, sc_ch,
+ &in_use);
+ if (ret)
+ continue;
+
+ if (!in_use) {
+ *channel = sc_ch;
+ wpa_printf(MSG_DEBUG, "%s: channel=%d",
+ __func__, *channel);
+ return 0;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
+
+ return -1;
+}
+
+
+static int macsec_qca_create_receive_sc(void *priv, u32 channel,
+ const u8 *sci_addr, u16 sci_port,
+ unsigned int conf_offset,
+ int validation)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+ fal_rx_prc_lut_t entry;
+ fal_rx_sc_validate_frame_e vf;
+ enum validate_frames validate_frames = validation;
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
+
+ /* rx prc lut */
+ 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_mask = 0xf;
+
+ entry.valid = 1;
+ entry.channel = channel;
+ entry.action = FAL_RX_PRC_ACTION_PROCESS;
+ entry.offset = conf_offset;
+
+ /* rx validate frame */
+ if (validate_frames == Strict)
+ vf = FAL_RX_SC_VALIDATE_FRAME_STRICT;
+ else if (validate_frames == Checked)
+ vf = FAL_RX_SC_VALIDATE_FRAME_CHECK;
+ else
+ vf = FAL_RX_SC_VALIDATE_FRAME_DISABLED;
+
+ ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
+ ret += nss_macsec_secy_rx_sc_create(drv->secy_id, channel);
+ ret += nss_macsec_secy_rx_sc_validate_frame_set(drv->secy_id, channel,
+ vf);
+ ret += nss_macsec_secy_rx_sc_replay_protect_set(drv->secy_id, channel,
+ drv->replay_protect);
+ ret += nss_macsec_secy_rx_sc_anti_replay_window_set(drv->secy_id,
+ channel,
+ drv->replay_window);
+
+ return ret;
+}
+
+
+static int macsec_qca_delete_receive_sc(void *priv, u32 channel)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+ fal_rx_prc_lut_t entry;
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
+
+ /* rx prc lut */
+ os_memset(&entry, 0, sizeof(entry));
+
+ ret += nss_macsec_secy_rx_sc_del(drv->secy_id, channel);
+ ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
+
+ return ret;
+}
+
+
+static int macsec_qca_create_receive_sa(void *priv, u32 channel, u8 an,
+ u32 lowest_pn, const u8 *sak)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+ fal_rx_sak_t rx_sak;
+ int i = 0;
+
+ wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
+ __func__, channel, an, lowest_pn);
+
+ os_memset(&rx_sak, 0, sizeof(rx_sak));
+ for (i = 0; i < 16; i++)
+ rx_sak.sak[i] = sak[15 - i];
+
+ 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);
+
+ return ret;
+}
+
+
+static int macsec_qca_enable_receive_sa(void *priv, u32 channel, u8 an)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+
+ ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, TRUE);
+
+ return ret;
+}
+
+
+static int macsec_qca_disable_receive_sa(void *priv, u32 channel, u8 an)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+
+ ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, FALSE);
+
+ return ret;
+}
+
+
+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)
+ continue;
+
+ if (!in_use) {
+ *channel = sc_ch;
+ wpa_printf(MSG_DEBUG, "%s: channel=%d",
+ __func__, *channel);
+ return 0;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
+
+ return -1;
+}
+
+
+static int macsec_qca_create_transmit_sc(void *priv, u32 channel,
+ const u8 *sci_addr, u16 sci_port,
+ unsigned int conf_offset)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+ fal_tx_class_lut_t entry;
+ u8 psci[ETH_ALEN + 2];
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
+
+ /* class lut */
+ os_memset(&entry, 0, sizeof(entry));
+
+ entry.valid = 1;
+ 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;
+
+ 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);
+ ret += nss_macsec_secy_tx_sc_protect_set(drv->secy_id, channel,
+ drv->protect_frames);
+ ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
+ channel,
+ conf_offset);
+
+ return ret;
+}
+
+
+static int macsec_qca_delete_transmit_sc(void *priv, u32 channel)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+ fal_tx_class_lut_t entry;
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
+
+ /* class lut */
+ os_memset(&entry, 0, sizeof(entry));
+
+ ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
+ ret += nss_macsec_secy_tx_sc_del(drv->secy_id, channel);
+
+ return ret;
+}
+
+
+static int macsec_qca_create_transmit_sa(void *priv, u32 channel, u8 an,
+ u32 next_pn, Boolean confidentiality,
+ const u8 *sak)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+ u8 tci = 0;
+ fal_tx_sak_t tx_sak;
+ int i;
+
+ wpa_printf(MSG_DEBUG,
+ "%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
+ __func__, channel, an, next_pn, confidentiality);
+
+ if (drv->always_include_sci)
+ tci |= TCI_SC;
+ else if (drv->use_es)
+ tci |= TCI_ES;
+ else if (drv->use_scb)
+ tci |= TCI_SCB;
+
+ if (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];
+
+ 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);
+ 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);
+
+ return ret;
+}
+
+
+static int macsec_qca_enable_transmit_sa(void *priv, u32 channel, u8 an)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+
+ ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, TRUE);
+
+ return ret;
+}
+
+
+static int macsec_qca_disable_transmit_sa(void *priv, u32 channel, u8 an)
+{
+ struct macsec_qca_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+
+ ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, FALSE);
+
+ return ret;
+}
+
+
+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,
+ .init = macsec_qca_init,
+ .deinit = macsec_qca_deinit,
+
+ .macsec_init = macsec_qca_macsec_init,
+ .macsec_deinit = macsec_qca_macsec_deinit,
+ .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,
+ .enable_controlled_port = macsec_qca_enable_controlled_port,
+ .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,
+ .enable_transmit_sa = macsec_qca_enable_transmit_sa,
+ .disable_transmit_sa = macsec_qca_disable_transmit_sa,
+};
diff --git a/contrib/wpa/src/drivers/driver_ndis.c b/contrib/wpa/src/drivers/driver_ndis.c
index 8149a92..bf19a58 100644
--- a/contrib/wpa/src/drivers/driver_ndis.c
+++ b/contrib/wpa/src/drivers/driver_ndis.c
@@ -1075,8 +1075,8 @@ wpa_driver_ndis_associate(void *priv,
/* Try to continue anyway */
}
- if (params->key_mgmt_suite == KEY_MGMT_NONE ||
- params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_NONE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
/* Re-set WEP keys if static WEP configuration is used. */
int i;
for (i = 0; i < 4; i++) {
@@ -1103,12 +1103,12 @@ wpa_driver_ndis_associate(void *priv,
priv_mode = Ndis802_11PrivFilterAcceptAll;
} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
priv_mode = Ndis802_11PrivFilter8021xWEP;
- if (params->key_mgmt_suite == KEY_MGMT_PSK)
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
auth_mode = Ndis802_11AuthModeWPA2PSK;
else
auth_mode = Ndis802_11AuthModeWPA2;
#ifdef CONFIG_WPS
- } else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
+ } else if (params->key_mgmt_suite == WPA_KEY_MGMT_WPS) {
auth_mode = Ndis802_11AuthModeOpen;
priv_mode = Ndis802_11PrivFilterAcceptAll;
if (params->wps == WPS_MODE_PRIVACY) {
@@ -1130,35 +1130,35 @@ wpa_driver_ndis_associate(void *priv,
#endif /* CONFIG_WPS */
} else {
priv_mode = Ndis802_11PrivFilter8021xWEP;
- if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_WPA_NONE)
auth_mode = Ndis802_11AuthModeWPANone;
- else if (params->key_mgmt_suite == KEY_MGMT_PSK)
+ else if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
auth_mode = Ndis802_11AuthModeWPAPSK;
else
auth_mode = Ndis802_11AuthModeWPA;
}
switch (params->pairwise_suite) {
- case CIPHER_CCMP:
+ case WPA_CIPHER_CCMP:
encr = Ndis802_11Encryption3Enabled;
break;
- case CIPHER_TKIP:
+ case WPA_CIPHER_TKIP:
encr = Ndis802_11Encryption2Enabled;
break;
- case CIPHER_WEP40:
- case CIPHER_WEP104:
+ case WPA_CIPHER_WEP40:
+ case WPA_CIPHER_WEP104:
encr = Ndis802_11Encryption1Enabled;
break;
- case CIPHER_NONE:
+ case WPA_CIPHER_NONE:
#ifdef CONFIG_WPS
if (params->wps == WPS_MODE_PRIVACY) {
encr = Ndis802_11Encryption1Enabled;
break;
}
#endif /* CONFIG_WPS */
- if (params->group_suite == CIPHER_CCMP)
+ if (params->group_suite == WPA_CIPHER_CCMP)
encr = Ndis802_11Encryption3Enabled;
- else if (params->group_suite == CIPHER_TKIP)
+ else if (params->group_suite == WPA_CIPHER_TKIP)
encr = Ndis802_11Encryption2Enabled;
else
encr = Ndis802_11EncryptionDisabled;
@@ -2111,14 +2111,8 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
dlen = dpos - desc;
else
dlen = os_strlen(desc);
- drv->adapter_desc = os_malloc(dlen + 1);
- if (drv->adapter_desc) {
- os_memcpy(drv->adapter_desc, desc, dlen);
- drv->adapter_desc[dlen] = '\0';
- }
-
+ drv->adapter_desc = dup_binstr(desc, dlen);
os_free(b);
-
if (drv->adapter_desc == NULL)
return -1;
@@ -2285,14 +2279,8 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
} else {
dlen = os_strlen(desc[i]);
}
- drv->adapter_desc = os_malloc(dlen + 1);
- if (drv->adapter_desc) {
- os_memcpy(drv->adapter_desc, desc[i], dlen);
- drv->adapter_desc[dlen] = '\0';
- }
-
+ drv->adapter_desc = dup_binstr(desc[i], dlen);
os_free(names);
-
if (drv->adapter_desc == NULL)
return -1;
diff --git a/contrib/wpa/src/drivers/driver_nl80211.h b/contrib/wpa/src/drivers/driver_nl80211.h
new file mode 100644
index 0000000..802589a
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211.h
@@ -0,0 +1,274 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - definitions
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_NL80211_H
+#define DRIVER_NL80211_H
+
+#include "nl80211_copy.h"
+#include "utils/list.h"
+#include "driver.h"
+
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#endif /* CONFIG_LIBNL20 */
+
+struct nl80211_global {
+ struct dl_list interfaces;
+ int if_add_ifindex;
+ u64 if_add_wdevid;
+ int if_add_wdevid_set;
+ struct netlink_data *netlink;
+ struct nl_cb *nl_cb;
+ struct nl_handle *nl;
+ int nl80211_id;
+ int ioctl_sock; /* socket for ioctl() use */
+
+ struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+ struct dl_list list;
+ struct dl_list bsss;
+ struct dl_list drvs;
+
+ struct nl_handle *nl_beacons;
+ struct nl_cb *nl_cb;
+
+ int wiphy_idx;
+};
+
+struct i802_bss {
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *next;
+ int ifindex;
+ int br_ifindex;
+ u64 wdev_id;
+ char ifname[IFNAMSIZ + 1];
+ char brname[IFNAMSIZ];
+ unsigned int beacon_set:1;
+ unsigned int added_if_into_bridge:1;
+ unsigned int added_bridge:1;
+ unsigned int in_deinit:1;
+ unsigned int wdev_id_set:1;
+ unsigned int added_if:1;
+ unsigned int static_ap:1;
+
+ u8 addr[ETH_ALEN];
+
+ int freq;
+ int bandwidth;
+ int if_dynamic;
+
+ void *ctx;
+ struct nl_handle *nl_preq, *nl_mgmt;
+ struct nl_cb *nl_cb;
+
+ struct nl80211_wiphy_data *wiphy_data;
+ struct dl_list wiphy_list;
+};
+
+struct wpa_driver_nl80211_data {
+ struct nl80211_global *global;
+ struct dl_list list;
+ struct dl_list wiphy_list;
+ char phyname[32];
+ u8 perm_addr[ETH_ALEN];
+ void *ctx;
+ int ifindex;
+ int if_removed;
+ int if_disabled;
+ int ignore_if_down_event;
+ struct rfkill_data *rfkill;
+ struct wpa_driver_capa capa;
+ u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+ int has_capability;
+
+ int operstate;
+
+ int scan_complete_events;
+ enum scan_states {
+ NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+ SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+ SCHED_SCAN_RESULTS
+ } scan_state;
+
+ u8 auth_bssid[ETH_ALEN];
+ u8 auth_attempt_bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 prev_bssid[ETH_ALEN];
+ int associated;
+ u8 ssid[32];
+ size_t ssid_len;
+ enum nl80211_iftype nlmode;
+ enum nl80211_iftype ap_scan_as_station;
+ unsigned int assoc_freq;
+
+ int monitor_sock;
+ int monitor_ifidx;
+ int monitor_refcount;
+
+ unsigned int disabled_11b_rates:1;
+ unsigned int pending_remain_on_chan:1;
+ unsigned int in_interface_list:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int scan_for_auth:1;
+ unsigned int retry_auth:1;
+ unsigned int use_monitor:1;
+ unsigned int ignore_next_local_disconnect:1;
+ unsigned int ignore_next_local_deauth:1;
+ unsigned int hostapd:1;
+ unsigned int start_mode_ap:1;
+ unsigned int start_iface_up:1;
+ unsigned int test_use_roc_tx:1;
+ unsigned int ignore_deauth_event:1;
+ unsigned int vendor_cmd_test_avail:1;
+ unsigned int roaming_vendor_cmd_avail:1;
+ unsigned int dfs_vendor_cmd_avail:1;
+ unsigned int have_low_prio_scan:1;
+ unsigned int force_connect_cmd:1;
+ unsigned int addr_changed:1;
+ unsigned int get_features_vendor_cmd_avail:1;
+ unsigned int set_rekey_offload:1;
+ unsigned int p2p_go_ctwindow_supported:1;
+
+ u64 remain_on_chan_cookie;
+ u64 send_action_cookie;
+
+ unsigned int last_mgmt_freq;
+
+ struct wpa_driver_scan_filter *filter_ssids;
+ size_t num_filter_ssids;
+
+ struct i802_bss *first_bss;
+
+ int eapol_tx_sock;
+
+ int eapol_sock; /* socket for EAPOL frames */
+
+ struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+
+ int default_if_indices[16];
+ int *if_indices;
+ int num_if_indices;
+
+ /* From failed authentication command */
+ int auth_freq;
+ u8 auth_bssid_[ETH_ALEN];
+ u8 auth_ssid[32];
+ size_t auth_ssid_len;
+ int auth_alg;
+ u8 *auth_ie;
+ size_t auth_ie_len;
+ u8 auth_wep_key[4][16];
+ size_t auth_wep_key_len[4];
+ int auth_wep_tx_keyidx;
+ int auth_local_state_change;
+ int auth_p2p;
+};
+
+struct nl_msg;
+
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int flags, uint8_t cmd);
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+ uint8_t cmd);
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data);
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg, int use_existing);
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx);
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv);
+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,
+ int ifindex);
+int is_ap_interface(enum nl80211_iftype nlmode);
+int is_sta_interface(enum nl80211_iftype nlmode);
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv);
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig);
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig_change);
+int nl80211_get_wiphy_index(struct i802_bss *bss);
+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 nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack);
+
+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);
+
+int process_global_event(struct nl_msg *msg, void *arg);
+int process_bss_event(struct nl_msg *msg, void *arg);
+
+#ifdef ANDROID
+int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
+int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params);
+int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+ size_t buf_len);
+
+#ifdef ANDROID_P2P
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
+#endif /* ANDROID */
+
+
+/* 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);
+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);
+
+#endif /* DRIVER_NL80211_H */
diff --git a/contrib/wpa/src/drivers/driver_nl80211_android.c b/contrib/wpa/src/drivers/driver_nl80211_android.c
new file mode 100644
index 0000000..3cc9a65
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211_android.c
@@ -0,0 +1,220 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Android specific
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "driver_nl80211.h"
+#include "android_drv.h"
+
+
+typedef struct android_wifi_priv_cmd {
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+ drv_errors++;
+ if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv_errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ char buf[MAX_DRV_CMD_SIZE];
+ int ret;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ os_memset(buf, 0, sizeof(buf));
+ os_strlcpy(buf, cmd, sizeof(buf));
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = sizeof(buf);
+ priv_cmd.total_len = sizeof(buf);
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+ __func__);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+ return 0;
+}
+
+
+int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ int ret = 0, i = 0, bp;
+ char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+ bp = WEXT_PNOSETUP_HEADER_SIZE;
+ os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+ buf[bp++] = WEXT_PNO_TLV_PREFIX;
+ buf[bp++] = WEXT_PNO_TLV_VERSION;
+ buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+ buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+ while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+ /* Check that there is enough space needed for 1 more SSID, the
+ * other sections and null termination */
+ if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+ WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+ break;
+ wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ buf[bp++] = WEXT_PNO_SSID_SECTION;
+ buf[bp++] = params->ssids[i].ssid_len;
+ os_memcpy(&buf[bp], params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ bp += params->ssids[i].ssid_len;
+ i++;
+ }
+
+ buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+ WEXT_PNO_SCAN_INTERVAL);
+ bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+ buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_REPEAT);
+ bp += WEXT_PNO_REPEAT_LENGTH;
+
+ buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_MAX_REPEAT);
+ bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = bp;
+ priv_cmd.total_len = bp;
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+ ret);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+
+ return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+int android_pno_stop(struct i802_bss *bss)
+{
+ return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+
+#ifdef ANDROID_P2P
+#ifdef ANDROID_P2P_STUB
+
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
+{
+ return 0;
+}
+
+
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
+{
+ return 0;
+}
+
+
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
+{
+ return -1;
+}
+
+
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp)
+{
+ return 0;
+}
+
+#endif /* ANDROID_P2P_STUB */
+#endif /* ANDROID_P2P */
+
+
+int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+ return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+
+
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
+{
+ /*
+ * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+ * need to work around that.
+ */
+ struct nl_cache *cache = NULL;
+ struct genl_family *nl80211 = NULL;
+ int id = -1;
+
+ if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache");
+ goto fail;
+ }
+
+ nl80211 = genl_ctrl_search_by_name(cache, name);
+ if (nl80211 == NULL)
+ goto fail;
+
+ id = genl_family_get_id(nl80211);
+
+fail:
+ if (nl80211)
+ genl_family_put(nl80211);
+ if (cache)
+ nl_cache_free(cache);
+
+ return id;
+}
diff --git a/contrib/wpa/src/drivers/driver_nl80211_capa.c b/contrib/wpa/src/drivers/driver_nl80211_capa.c
new file mode 100644
index 0000000..e0d1d23
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211_capa.c
@@ -0,0 +1,1532 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Capabilities
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "driver_nl80211.h"
+
+
+static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+{
+ u32 *feat = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+ *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+ return NL_SKIP;
+}
+
+
+static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+{
+ u32 feat = 0;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return 0;
+
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES)) {
+ nlmsg_free(msg);
+ return 0;
+ }
+
+ if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+ return feat;
+
+ return 0;
+}
+
+
+struct wiphy_info_data {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_driver_capa *capa;
+
+ unsigned int num_multichan_concurrent;
+
+ unsigned int error:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int monitor_supported:1;
+ unsigned int auth_supported:1;
+ unsigned int connect_supported:1;
+ unsigned int p2p_go_supported:1;
+ unsigned int p2p_client_supported:1;
+ unsigned int p2p_go_ctwindow_supported:1;
+ unsigned int p2p_concurrent:1;
+ unsigned int channel_switch_supported:1;
+ unsigned int set_qos_map_supported:1;
+ unsigned int have_low_prio_scan:1;
+ unsigned int wmm_ac_supported:1;
+ unsigned int mac_addr_rand_scan_supported:1;
+ unsigned int mac_addr_rand_sched_scan_supported:1;
+};
+
+
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+ unsigned int prot = 0;
+
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+ return prot;
+}
+
+
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_mode;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_mode, tb, i) {
+ switch (nla_type(nl_mode)) {
+ case NL80211_IFTYPE_AP:
+ info->capa->flags |= WPA_DRIVER_FLAGS_AP;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ info->capa->flags |= WPA_DRIVER_FLAGS_MESH;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ info->capa->flags |=
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ info->p2p_go_supported = 1;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ info->p2p_client_supported = 1;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ info->monitor_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
+ struct nlattr *nl_combi)
+{
+ struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+ struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+ struct nlattr *nl_limit, *nl_mode;
+ int err, rem_limit, rem_mode;
+ int combination_has_p2p = 0, combination_has_mgd = 0;
+ static struct nla_policy
+ iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+ [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+ [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+ [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
+ },
+ iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+ [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+ [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+ };
+
+ err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+ nl_combi, iface_combination_policy);
+ if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+ !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+ !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+ return 0; /* broken combination */
+
+ if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+ info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
+
+ nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
+ rem_limit) {
+ err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
+ nl_limit, iface_limit_policy);
+ if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+ return 0; /* broken combination */
+
+ nla_for_each_nested(nl_mode,
+ tb_limit[NL80211_IFACE_LIMIT_TYPES],
+ rem_mode) {
+ int ift = nla_type(nl_mode);
+ if (ift == NL80211_IFTYPE_P2P_GO ||
+ ift == NL80211_IFTYPE_P2P_CLIENT)
+ combination_has_p2p = 1;
+ if (ift == NL80211_IFTYPE_STATION)
+ combination_has_mgd = 1;
+ }
+ if (combination_has_p2p && combination_has_mgd)
+ break;
+ }
+
+ if (combination_has_p2p && combination_has_mgd) {
+ unsigned int num_channels =
+ nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
+
+ info->p2p_concurrent = 1;
+ if (info->num_multichan_concurrent < num_channels)
+ info->num_multichan_concurrent = num_channels;
+ }
+
+ return 0;
+}
+
+
+static void wiphy_info_iface_comb(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_combi;
+ int rem_combi;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_combi, tb, rem_combi) {
+ if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
+ break;
+ }
+}
+
+
+static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_cmd;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_cmd, tb, i) {
+ switch (nla_get_u32(nl_cmd)) {
+ case NL80211_CMD_AUTHENTICATE:
+ info->auth_supported = 1;
+ break;
+ case NL80211_CMD_CONNECT:
+ info->connect_supported = 1;
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ info->capa->sched_scan_supported = 1;
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ info->poll_command_supported = 1;
+ break;
+ case NL80211_CMD_CHANNEL_SWITCH:
+ info->channel_switch_supported = 1;
+ break;
+ case NL80211_CMD_SET_QOS_MAP:
+ info->set_qos_map_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ int i, num;
+ u32 *ciphers;
+
+ if (tb == NULL)
+ return;
+
+ num = nla_len(tb) / sizeof(u32);
+ ciphers = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ u32 c = ciphers[i];
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+ c >> 24, (c >> 16) & 0xff,
+ (c >> 8) & 0xff, c & 0xff);
+ switch (c) {
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ if (tb)
+ capa->max_remain_on_chan = nla_get_u32(tb);
+}
+
+
+static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
+ struct nlattr *ext_setup)
+{
+ if (tdls == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+ if (ext_setup) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+ }
+}
+
+
+static void wiphy_info_feature_flags(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ u32 flags;
+ struct wpa_driver_capa *capa = info->capa;
+
+ if (tb == NULL)
+ return;
+
+ flags = nla_get_u32(tb);
+
+ if (flags & NL80211_FEATURE_SK_TX_STATUS)
+ info->data_tx_status = 1;
+
+ if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+ capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+ if (flags & NL80211_FEATURE_SAE)
+ capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+ if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+ capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+
+ if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
+ capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
+
+ if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH;
+ }
+
+ if (flags & NL80211_FEATURE_P2P_GO_CTWIN)
+ info->p2p_go_ctwindow_supported = 1;
+
+ if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
+ info->have_low_prio_scan = 1;
+
+ if (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)
+ info->mac_addr_rand_scan_supported = 1;
+
+ if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
+ info->mac_addr_rand_sched_scan_supported = 1;
+
+ if (flags & NL80211_FEATURE_STATIC_SMPS)
+ capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
+
+ if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
+ capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
+
+ if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
+ info->wmm_ac_supported = 1;
+
+ if (flags & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES;
+
+ if (flags & NL80211_FEATURE_WFA_TPC_IE_IN_PROBES)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES;
+
+ if (flags & NL80211_FEATURE_QUIET)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_QUIET;
+
+ if (flags & NL80211_FEATURE_TX_POWER_INSERTION)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_TX_POWER_INSERTION;
+
+ if (flags & NL80211_FEATURE_HT_IBSS)
+ capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS;
+}
+
+
+static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ u32 protocols;
+
+ if (tb == NULL)
+ return;
+
+ protocols = nla_get_u32(tb);
+ wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
+ "mode");
+ capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+ capa->probe_resp_offloads = probe_resp_offload_support(protocols);
+}
+
+
+static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
+
+ if (tb == NULL)
+ return;
+
+ if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
+ tb, NULL))
+ return;
+
+ if (triggers[NL80211_WOWLAN_TRIG_ANY])
+ capa->wowlan_triggers.any = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
+ capa->wowlan_triggers.disconnect = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
+ capa->wowlan_triggers.magic_pkt = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
+ capa->wowlan_triggers.gtk_rekey_failure = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
+ capa->wowlan_triggers.eap_identity_req = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
+ capa->wowlan_triggers.four_way_handshake = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
+ capa->wowlan_triggers.rfkill_release = 1;
+}
+
+
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wiphy_info_data *info = arg;
+ struct wpa_driver_capa *capa = info->capa;
+ struct wpa_driver_nl80211_data *drv = info->drv;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_WIPHY_NAME])
+ os_strlcpy(drv->phyname,
+ nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+ sizeof(drv->phyname));
+ if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
+ capa->max_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+ capa->max_sched_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+ capa->max_match_sets =
+ nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
+ if (tb[NL80211_ATTR_MAC_ACL_MAX])
+ capa->max_acl_mac_addrs =
+ nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
+ wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
+ wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
+ wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
+ wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
+
+ if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+ "off-channel TX");
+ capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+ }
+
+ if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+ capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+ }
+
+ wiphy_info_max_roc(capa,
+ tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
+
+ if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+ capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
+
+ wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
+ tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
+
+ if (tb[NL80211_ATTR_DEVICE_AP_SME])
+ info->device_ap_sme = 1;
+
+ wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_probe_resp_offload(capa,
+ tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+
+ if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+ drv->extended_capa == NULL) {
+ drv->extended_capa =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa) {
+ os_memcpy(drv->extended_capa,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ drv->extended_capa_len =
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+ }
+ drv->extended_capa_mask =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+ if (drv->extended_capa_mask) {
+ os_memcpy(drv->extended_capa_mask,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+ } else {
+ os_free(drv->extended_capa);
+ drv->extended_capa = NULL;
+ drv->extended_capa_len = 0;
+ }
+ }
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl;
+ int rem;
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
+ struct nl80211_vendor_cmd_info *vinfo;
+ if (nla_len(nl) != sizeof(*vinfo)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+ continue;
+ }
+ vinfo = nla_data(nl);
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_TEST:
+ drv->vendor_cmd_test_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+ drv->dfs_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+ drv->get_features_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
+ vinfo->vendor_id, vinfo->subcmd);
+ }
+ }
+
+ if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
+ struct nlattr *nl;
+ int rem;
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
+ struct nl80211_vendor_cmd_info *vinfo;
+ if (nla_len(nl) != sizeof(*vinfo)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+ continue;
+ }
+ vinfo = nla_data(nl);
+ wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
+ vinfo->vendor_id, vinfo->subcmd);
+ }
+ }
+
+ wiphy_info_wowlan_triggers(capa,
+ tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
+
+ if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
+ capa->max_stations =
+ nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
+ struct wiphy_info_data *info)
+{
+ u32 feat;
+ struct nl_msg *msg;
+ int flags = 0;
+
+ os_memset(info, 0, sizeof(*info));
+ info->capa = &drv->capa;
+ info->drv = drv;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ flags = NLM_F_DUMP;
+ msg = nl80211_cmd_msg(drv->first_bss, flags, NL80211_CMD_GET_WIPHY);
+ if (!msg || nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+ return -1;
+
+ if (info->auth_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
+ else if (!info->connect_supported) {
+ wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+ "authentication/association or connect commands");
+ info->error = 1;
+ }
+
+ if (info->p2p_go_supported && info->p2p_client_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+ if (info->p2p_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+ "interface (driver advertised support)");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+ }
+ if (info->num_multichan_concurrent > 1) {
+ wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+ "concurrent (driver advertised support)");
+ drv->capa.num_multichan_concurrent =
+ info->num_multichan_concurrent;
+ }
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+ wpa_printf(MSG_DEBUG, "nl80211: use P2P_DEVICE support");
+
+ /* default to 5000 since early versions of mac80211 don't set it */
+ if (!drv->capa.max_remain_on_chan)
+ drv->capa.max_remain_on_chan = 5000;
+
+ if (info->channel_switch_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
+ drv->capa.wmm_ac_supported = info->wmm_ac_supported;
+
+ drv->capa.mac_addr_rand_sched_scan_supported =
+ info->mac_addr_rand_sched_scan_supported;
+ drv->capa.mac_addr_rand_scan_supported =
+ info->mac_addr_rand_scan_supported;
+
+ return 0;
+}
+
+
+static int dfs_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ int *dfs_capability_ptr = 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_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
+ u32 val;
+ val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
+ wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
+ val);
+ *dfs_capability_ptr = val;
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int dfs_capability = 0;
+ int ret;
+
+ if (!drv->dfs_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_DFS_CAPABILITY)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
+ if (!ret && dfs_capability)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
+}
+
+
+struct features_info {
+ u8 *flags;
+ size_t flags_len;
+};
+
+
+static int features_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct features_info *info = arg;
+ struct nlattr *nl_vend, *attr;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ if (nl_vend) {
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
+ if (attr) {
+ info->flags = nla_data(attr);
+ info->flags_len = nla_len(attr);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static int check_feature(enum qca_wlan_vendor_features feature,
+ struct features_info *info)
+{
+ size_t idx = feature / 8;
+
+ return (idx < info->flags_len) &&
+ (info->flags[idx] & BIT(feature % 8));
+}
+
+
+static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct features_info info;
+ int ret;
+
+ if (!drv->get_features_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_FEATURES)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ os_memset(&info, 0, sizeof(info));
+ ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
+ if (ret || !info.flags)
+ return;
+
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
+}
+
+
+int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
+{
+ struct wiphy_info_data info;
+ if (wpa_driver_nl80211_get_info(drv, &info))
+ return -1;
+
+ if (info.error)
+ return -1;
+
+ drv->has_capability = 1;
+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+ /*
+ * As all cfg80211 drivers must support cases where the AP interface is
+ * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
+ * case that the user space daemon has crashed, they must be able to
+ * cleanup all stations and key entries in the AP tear down flow. Thus,
+ * this flag can/should always be set for cfg80211 drivers.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
+
+ if (!info.device_ap_sme) {
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+
+ /*
+ * No AP SME is currently assumed to also indicate no AP MLME
+ * in the driver/firmware.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+ }
+
+ drv->device_ap_sme = info.device_ap_sme;
+ drv->poll_command_supported = info.poll_command_supported;
+ drv->data_tx_status = info.data_tx_status;
+ drv->p2p_go_ctwindow_supported = info.p2p_go_ctwindow_supported;
+ if (info.set_qos_map_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
+ drv->have_low_prio_scan = info.have_low_prio_scan;
+
+ /*
+ * If poll command and tx status are supported, mac80211 is new enough
+ * to have everything we need to not need monitor interfaces.
+ */
+ drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
+
+ if (drv->device_ap_sme && drv->use_monitor) {
+ /*
+ * Non-mac80211 drivers may not support monitor interface.
+ * Make sure we do not get stuck with incorrect capability here
+ * by explicitly testing this.
+ */
+ if (!info.monitor_supported) {
+ wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+ "with device_ap_sme since no monitor mode "
+ "support detected");
+ drv->use_monitor = 0;
+ }
+ }
+
+ /*
+ * If we aren't going to use monitor interfaces, but the
+ * driver doesn't support data TX status, we won't get TX
+ * status for EAPOL frames.
+ */
+ if (!drv->use_monitor && !info.data_tx_status)
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+ qca_nl80211_check_dfs_capa(drv);
+ qca_nl80211_get_features(drv);
+
+ return 0;
+}
+
+
+struct phy_info_arg {
+ u16 *num_modes;
+ struct hostapd_hw_modes *modes;
+ int last_mode, last_chan_idx;
+};
+
+static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
+ struct nlattr *ampdu_factor,
+ struct nlattr *ampdu_density,
+ struct nlattr *mcs_set)
+{
+ if (capa)
+ mode->ht_capab = nla_get_u16(capa);
+
+ if (ampdu_factor)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
+
+ if (ampdu_density)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
+
+ if (mcs_set && nla_len(mcs_set) >= 16) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->mcs_set, mcs, 16);
+ }
+}
+
+
+static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *capa,
+ struct nlattr *mcs_set)
+{
+ if (capa)
+ mode->vht_capab = nla_get_u32(capa);
+
+ if (mcs_set && nla_len(mcs_set) >= 8) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->vht_mcs_set, mcs, 8);
+ }
+}
+
+
+static void phy_info_freq(struct hostapd_hw_modes *mode,
+ struct hostapd_channel_data *chan,
+ struct nlattr *tb_freq[])
+{
+ u8 channel;
+ chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ chan->flag = 0;
+ chan->dfs_cac_ms = 0;
+ if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+ chan->chan = channel;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ chan->flag |= HOSTAPD_CHAN_DISABLED;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
+ chan->flag |= HOSTAPD_CHAN_NO_IR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ chan->flag |= HOSTAPD_CHAN_RADAR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY])
+ chan->flag |= HOSTAPD_CHAN_INDOOR_ONLY;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
+ chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+ enum nl80211_dfs_state state =
+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+
+ switch (state) {
+ case NL80211_DFS_USABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+ break;
+ case NL80211_DFS_AVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+ break;
+ case NL80211_DFS_UNAVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+ break;
+ }
+ }
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
+ chan->dfs_cac_ms = nla_get_u32(
+ tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
+ }
+}
+
+
+static int phy_info_freqs(struct phy_info_arg *phy_info,
+ struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
+ };
+ int new_channels = 0;
+ struct hostapd_channel_data *channel;
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ struct nlattr *nl_freq;
+ int rem_freq, idx;
+
+ if (tb == NULL)
+ return NL_OK;
+
+ nla_for_each_nested(nl_freq, tb, rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ new_channels++;
+ }
+
+ channel = os_realloc_array(mode->channels,
+ mode->num_channels + new_channels,
+ sizeof(struct hostapd_channel_data));
+ if (!channel)
+ return NL_SKIP;
+
+ mode->channels = channel;
+ mode->num_channels += new_channels;
+
+ idx = phy_info->last_chan_idx;
+
+ nla_for_each_nested(nl_freq, tb, rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ phy_info_freq(mode, &mode->channels[idx], tb_freq);
+ idx++;
+ }
+ phy_info->last_chan_idx = idx;
+
+ return NL_OK;
+}
+
+
+static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+ { .type = NLA_FLAG },
+ };
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ struct nlattr *nl_rate;
+ int rem_rate, idx;
+
+ if (tb == NULL)
+ return NL_OK;
+
+ nla_for_each_nested(nl_rate, tb, rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->num_rates++;
+ }
+
+ mode->rates = os_calloc(mode->num_rates, sizeof(int));
+ if (!mode->rates)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_rate, tb, rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->rates[idx] = nla_get_u32(
+ tb_rate[NL80211_BITRATE_ATTR_RATE]);
+ idx++;
+ }
+
+ return NL_OK;
+}
+
+
+static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
+{
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ struct hostapd_hw_modes *mode;
+ int ret;
+
+ if (phy_info->last_mode != nl_band->nla_type) {
+ mode = os_realloc_array(phy_info->modes,
+ *phy_info->num_modes + 1,
+ sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
+
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ os_memset(mode, 0, sizeof(*mode));
+ mode->mode = NUM_HOSTAPD_MODES;
+ mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
+ HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
+
+ /*
+ * Unsupported VHT MCS stream is defined as value 3, so the VHT
+ * MCS RX/TX map must be initialized with 0xffff to mark all 8
+ * possible streams as unsupported. This will be overridden if
+ * driver advertises VHT support.
+ */
+ mode->vht_mcs_set[0] = 0xff;
+ mode->vht_mcs_set[1] = 0xff;
+ mode->vht_mcs_set[4] = 0xff;
+ mode->vht_mcs_set[5] = 0xff;
+
+ *(phy_info->num_modes) += 1;
+ phy_info->last_mode = nl_band->nla_type;
+ phy_info->last_chan_idx = 0;
+ } else
+ mode = &phy_info->modes[*(phy_info->num_modes) - 1];
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
+ tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+ phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
+ tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+ ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ if (ret != NL_OK)
+ return ret;
+ ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+ if (ret != NL_OK)
+ return ret;
+
+ return NL_OK;
+}
+
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+ struct nlattr *nl_band;
+ int rem_band;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
+ {
+ int res = phy_info_band(phy_info, nl_band);
+ if (res != NL_OK)
+ return res;
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+ u16 *num_modes)
+{
+ u16 m;
+ struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
+ int i, mode11g_idx = -1;
+
+ /* heuristic to set up modes */
+ for (m = 0; m < *num_modes; m++) {
+ if (!modes[m].num_channels)
+ continue;
+ if (modes[m].channels[0].freq < 4000) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+ for (i = 0; i < modes[m].num_rates; i++) {
+ if (modes[m].rates[i] > 200) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+ break;
+ }
+ }
+ } else if (modes[m].channels[0].freq > 50000)
+ modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* If only 802.11g mode is included, use it to construct matching
+ * 802.11b mode data. */
+
+ for (m = 0; m < *num_modes; m++) {
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
+ return modes; /* 802.11b already included */
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+ mode11g_idx = m;
+ }
+
+ if (mode11g_idx < 0)
+ return modes; /* 2.4 GHz band not supported at all */
+
+ nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
+ if (nmodes == NULL)
+ return modes; /* Could not add 802.11b mode */
+
+ mode = &nmodes[*num_modes];
+ os_memset(mode, 0, sizeof(*mode));
+ (*num_modes)++;
+ modes = nmodes;
+
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+
+ mode11g = &modes[mode11g_idx];
+ mode->num_channels = mode11g->num_channels;
+ mode->channels = os_malloc(mode11g->num_channels *
+ sizeof(struct hostapd_channel_data));
+ if (mode->channels == NULL) {
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+ os_memcpy(mode->channels, mode11g->channels,
+ mode11g->num_channels * sizeof(struct hostapd_channel_data));
+
+ mode->num_rates = 0;
+ mode->rates = os_malloc(4 * sizeof(int));
+ if (mode->rates == NULL) {
+ os_free(mode->channels);
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+
+ for (i = 0; i < mode11g->num_rates; i++) {
+ if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
+ mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
+ continue;
+ mode->rates[mode->num_rates] = mode11g->rates[i];
+ mode->num_rates++;
+ if (mode->num_rates == 4)
+ break;
+ }
+
+ if (mode->num_rates == 0) {
+ os_free(mode->channels);
+ os_free(mode->rates);
+ (*num_modes)--;
+ return modes; /* No 802.11b rates */
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
+ "information");
+
+ return modes;
+}
+
+
+static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40;
+ }
+}
+
+
+static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (!(chan->flag & HOSTAPD_CHAN_HT40))
+ continue;
+ if (chan->freq - 30 >= start && chan->freq - 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40MINUS;
+ if (chan->freq + 10 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40PLUS;
+ }
+}
+
+
+static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
+ struct phy_info_arg *results)
+{
+ u16 m;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ int c;
+ struct hostapd_hw_modes *mode = &results->modes[m];
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if ((u32) chan->freq - 10 >= start &&
+ (u32) chan->freq + 10 <= end)
+ chan->max_tx_power = max_eirp;
+ }
+ }
+}
+
+
+static void nl80211_reg_rule_ht40(u32 start, u32 end,
+ struct phy_info_arg *results)
+{
+ u16 m;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ nl80211_set_ht40_mode(&results->modes[m], start, end);
+ }
+}
+
+
+static void nl80211_reg_rule_sec(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 20)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
+ }
+}
+
+
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+ if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+ if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+ if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+ }
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 80)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ /* TODO: use a real VHT support indication */
+ if (!results->modes[m].vht_capab)
+ continue;
+
+ nl80211_set_vht_mode(&results->modes[m], start, end);
+ }
+}
+
+
+static const char * dfs_domain_name(enum nl80211_dfs_regions region)
+{
+ switch (region) {
+ case NL80211_DFS_UNSET:
+ return "DFS-UNSET";
+ case NL80211_DFS_FCC:
+ return "DFS-FCC";
+ case NL80211_DFS_ETSI:
+ return "DFS-ETSI";
+ case NL80211_DFS_JP:
+ return "DFS-JP";
+ default:
+ return "DFS-invalid";
+ }
+}
+
+
+static int nl80211_get_reg(struct nl_msg *msg, void *arg)
+{
+ struct phy_info_arg *results = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *nl_rule;
+ struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
+ int rem_rule;
+ static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
+ };
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
+ !tb_msg[NL80211_ATTR_REG_RULES]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
+ "available");
+ return NL_SKIP;
+ }
+
+ if (tb_msg[NL80211_ATTR_DFS_REGION]) {
+ enum nl80211_dfs_regions dfs_domain;
+ dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
+ (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
+ dfs_domain_name(dfs_domain));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+ (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
+ continue;
+ start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+ max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+ if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+ max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+ if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
+ flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
+ start, end, max_bw, max_eirp,
+ flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
+ flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
+ flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
+ flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
+ "",
+ flags & NL80211_RRF_DFS ? " (DFS)" : "",
+ flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
+ flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
+ flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
+ if (max_bw >= 40)
+ nl80211_reg_rule_ht40(start, end, results);
+ if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+ nl80211_reg_rule_max_eirp(start, end, max_eirp,
+ results);
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_sec(tb_rule, results);
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_vht(tb_rule, results);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+ struct phy_info_arg *results)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+}
+
+
+struct hostapd_hw_modes *
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ u32 feat;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int nl_flags = 0;
+ struct nl_msg *msg;
+ struct phy_info_arg result = {
+ .num_modes = num_modes,
+ .modes = NULL,
+ .last_mode = -1,
+ };
+
+ *num_modes = 0;
+ *flags = 0;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl_flags = NLM_F_DUMP;
+ if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) ||
+ nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ nl80211_set_regulatory_flags(drv, &result);
+ return wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
+ }
+
+ return NULL;
+}
diff --git a/contrib/wpa/src/drivers/driver_nl80211_event.c b/contrib/wpa/src/drivers/driver_nl80211_event.c
new file mode 100644
index 0000000..87e412d
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211_event.c
@@ -0,0 +1,2029 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Event processing
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "driver_nl80211.h"
+
+
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+ switch (cmd) {
+ C2S(NL80211_CMD_UNSPEC)
+ C2S(NL80211_CMD_GET_WIPHY)
+ C2S(NL80211_CMD_SET_WIPHY)
+ C2S(NL80211_CMD_NEW_WIPHY)
+ C2S(NL80211_CMD_DEL_WIPHY)
+ C2S(NL80211_CMD_GET_INTERFACE)
+ C2S(NL80211_CMD_SET_INTERFACE)
+ C2S(NL80211_CMD_NEW_INTERFACE)
+ C2S(NL80211_CMD_DEL_INTERFACE)
+ C2S(NL80211_CMD_GET_KEY)
+ C2S(NL80211_CMD_SET_KEY)
+ C2S(NL80211_CMD_NEW_KEY)
+ C2S(NL80211_CMD_DEL_KEY)
+ C2S(NL80211_CMD_GET_BEACON)
+ C2S(NL80211_CMD_SET_BEACON)
+ C2S(NL80211_CMD_START_AP)
+ C2S(NL80211_CMD_STOP_AP)
+ C2S(NL80211_CMD_GET_STATION)
+ C2S(NL80211_CMD_SET_STATION)
+ C2S(NL80211_CMD_NEW_STATION)
+ C2S(NL80211_CMD_DEL_STATION)
+ C2S(NL80211_CMD_GET_MPATH)
+ C2S(NL80211_CMD_SET_MPATH)
+ C2S(NL80211_CMD_NEW_MPATH)
+ C2S(NL80211_CMD_DEL_MPATH)
+ C2S(NL80211_CMD_SET_BSS)
+ C2S(NL80211_CMD_SET_REG)
+ C2S(NL80211_CMD_REQ_SET_REG)
+ C2S(NL80211_CMD_GET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+ C2S(NL80211_CMD_GET_REG)
+ C2S(NL80211_CMD_GET_SCAN)
+ C2S(NL80211_CMD_TRIGGER_SCAN)
+ C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCAN_ABORTED)
+ C2S(NL80211_CMD_REG_CHANGE)
+ C2S(NL80211_CMD_AUTHENTICATE)
+ C2S(NL80211_CMD_ASSOCIATE)
+ C2S(NL80211_CMD_DEAUTHENTICATE)
+ C2S(NL80211_CMD_DISASSOCIATE)
+ C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+ C2S(NL80211_CMD_REG_BEACON_HINT)
+ C2S(NL80211_CMD_JOIN_IBSS)
+ C2S(NL80211_CMD_LEAVE_IBSS)
+ C2S(NL80211_CMD_TESTMODE)
+ C2S(NL80211_CMD_CONNECT)
+ C2S(NL80211_CMD_ROAM)
+ C2S(NL80211_CMD_DISCONNECT)
+ C2S(NL80211_CMD_SET_WIPHY_NETNS)
+ C2S(NL80211_CMD_GET_SURVEY)
+ C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+ C2S(NL80211_CMD_SET_PMKSA)
+ C2S(NL80211_CMD_DEL_PMKSA)
+ C2S(NL80211_CMD_FLUSH_PMKSA)
+ C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+ C2S(NL80211_CMD_REGISTER_FRAME)
+ C2S(NL80211_CMD_FRAME)
+ C2S(NL80211_CMD_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_POWER_SAVE)
+ C2S(NL80211_CMD_GET_POWER_SAVE)
+ C2S(NL80211_CMD_SET_CQM)
+ C2S(NL80211_CMD_NOTIFY_CQM)
+ C2S(NL80211_CMD_SET_CHANNEL)
+ C2S(NL80211_CMD_SET_WDS_PEER)
+ C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+ C2S(NL80211_CMD_JOIN_MESH)
+ C2S(NL80211_CMD_LEAVE_MESH)
+ C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+ C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+ C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+ C2S(NL80211_CMD_GET_WOWLAN)
+ C2S(NL80211_CMD_SET_WOWLAN)
+ C2S(NL80211_CMD_START_SCHED_SCAN)
+ C2S(NL80211_CMD_STOP_SCHED_SCAN)
+ C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+ C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+ C2S(NL80211_CMD_PMKSA_CANDIDATE)
+ C2S(NL80211_CMD_TDLS_OPER)
+ C2S(NL80211_CMD_TDLS_MGMT)
+ C2S(NL80211_CMD_UNEXPECTED_FRAME)
+ C2S(NL80211_CMD_PROBE_CLIENT)
+ C2S(NL80211_CMD_REGISTER_BEACONS)
+ C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+ C2S(NL80211_CMD_SET_NOACK_MAP)
+ C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+ C2S(NL80211_CMD_START_P2P_DEVICE)
+ C2S(NL80211_CMD_STOP_P2P_DEVICE)
+ C2S(NL80211_CMD_CONN_FAILED)
+ C2S(NL80211_CMD_SET_MCAST_RATE)
+ C2S(NL80211_CMD_SET_MAC_ACL)
+ C2S(NL80211_CMD_RADAR_DETECT)
+ C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+ C2S(NL80211_CMD_UPDATE_FT_IES)
+ C2S(NL80211_CMD_FT_EVENT)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+ C2S(NL80211_CMD_GET_COALESCE)
+ C2S(NL80211_CMD_SET_COALESCE)
+ C2S(NL80211_CMD_CHANNEL_SWITCH)
+ C2S(NL80211_CMD_VENDOR)
+ C2S(NL80211_CMD_SET_QOS_MAP)
+ C2S(NL80211_CMD_ADD_TX_TS)
+ C2S(NL80211_CMD_DEL_TX_TS)
+ default:
+ return "NL80211_CMD_UNKNOWN";
+ }
+#undef C2S
+}
+
+
+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore auth event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
+
+ os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+ os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+ event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ event.auth.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
+ event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
+ if (len > 24 + sizeof(mgmt->u.auth)) {
+ event.auth.ies = mgmt->u.auth.variable;
+ event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
+}
+
+
+static void nl80211_parse_wmm_params(struct nlattr *wmm_attr,
+ struct wmm_params *wmm_params)
+{
+ struct nlattr *wmm_info[NL80211_STA_WME_MAX + 1];
+ static struct nla_policy wme_policy[NL80211_STA_WME_MAX + 1] = {
+ [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
+ };
+
+ if (!wmm_attr ||
+ nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr,
+ wme_policy) ||
+ !wmm_info[NL80211_STA_WME_UAPSD_QUEUES])
+ return;
+
+ wmm_params->uapsd_queues =
+ nla_get_u8(wmm_info[NL80211_STA_WME_UAPSD_QUEUES]);
+ wmm_params->info_bitmap |= WMM_PARAMS_UAPSD_QUEUES_INFO;
+}
+
+
+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len, struct nlattr *wmm)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 status;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore assoc event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Associate event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
+
+ status = le_to_host16(mgmt->u.assoc_resp.status_code);
+ if (status != WLAN_STATUS_SUCCESS) {
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_reject.bssid = mgmt->bssid;
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_reject.resp_ies =
+ (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_reject.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
+ event.assoc_reject.status_code = status;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+ os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_info.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
+
+ event.assoc_info.freq = drv->assoc_freq;
+
+ nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *status,
+ struct nlattr *addr, struct nlattr *req_ie,
+ struct nlattr *resp_ie,
+ struct nlattr *authorized,
+ struct nlattr *key_replay_ctr,
+ struct nlattr *ptk_kck,
+ struct nlattr *ptk_kek)
+{
+ union wpa_event_data event;
+ u16 status_code;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
+ "when using userspace SME", cmd);
+ return;
+ }
+
+ status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
+
+ if (cmd == NL80211_CMD_CONNECT) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
+ status_code, drv->ignore_next_local_disconnect);
+ } else if (cmd == NL80211_CMD_ROAM) {
+ wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
+ if (addr)
+ event.assoc_reject.bssid = nla_data(addr);
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (!event.assoc_reject.bssid ||
+ (os_memcmp(event.assoc_reject.bssid,
+ drv->auth_attempt_bssid,
+ ETH_ALEN) != 0)) {
+ /*
+ * Ignore the event that came without a BSSID or
+ * for the old connection since this is likely
+ * not relevant to the new Connect command.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore connection failure event triggered during reassociation");
+ return;
+ }
+ }
+ if (resp_ie) {
+ event.assoc_reject.resp_ies = nla_data(resp_ie);
+ event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+ }
+ event.assoc_reject.status_code = status_code;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ if (addr) {
+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+ }
+
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
+ if (resp_ie) {
+ event.assoc_info.resp_ies = nla_data(resp_ie);
+ event.assoc_info.resp_ies_len = nla_len(resp_ie);
+ }
+
+ event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+
+ if (authorized && nla_get_u8(authorized)) {
+ event.assoc_info.authorized = 1;
+ wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
+ }
+ if (key_replay_ctr) {
+ event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr);
+ event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr);
+ }
+ if (ptk_kck) {
+ event.assoc_info.ptk_kck = nla_data(ptk_kck);
+ event.assoc_info.ptk_kck_len = nla_len(ptk_kck);
+ }
+ if (ptk_kek) {
+ event.assoc_info.ptk_kek = nla_data(ptk_kek);
+ event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *reason, struct nlattr *addr,
+ struct nlattr *by_ap)
+{
+ union wpa_event_data data;
+ unsigned int locally_generated = by_ap == NULL;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two disassociation events that could
+ * confuse the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event when using userspace SME");
+ return;
+ }
+
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event triggered during reassociation");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+ "disconnect but got another disconnect "
+ "event first");
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+ nl80211_mark_disconnected(drv);
+ os_memset(&data, 0, sizeof(data));
+ if (reason)
+ data.deauth_info.reason_code = nla_get_u16(reason);
+ data.deauth_info.locally_generated = by_ap == NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
+{
+ int freq1 = 0;
+
+ switch (convert2width(width)) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ return 0;
+ case CHAN_WIDTH_40:
+ freq1 = cf1 - 10;
+ break;
+ case CHAN_WIDTH_80:
+ freq1 = cf1 - 30;
+ break;
+ case CHAN_WIDTH_160:
+ freq1 = cf1 - 70;
+ break;
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_80P80:
+ /* FIXME: implement this */
+ return 0;
+ }
+
+ return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2)
+{
+ struct i802_bss *bss;
+ union wpa_event_data data;
+ int ht_enabled = 1;
+ int chan_offset = 0;
+ int ifidx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+ if (!freq)
+ return;
+
+ ifidx = nla_get_u32(ifindex);
+ bss = get_bss_ifindex(drv, ifidx);
+ if (bss == NULL) {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+ ifidx);
+ return;
+ }
+
+ if (type) {
+ enum nl80211_channel_type ch_type = nla_get_u32(type);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type);
+ switch (ch_type) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
+ } else if (bw && cf1) {
+ /* This can happen for example with VHT80 ch switch */
+ chan_offset = calculate_chan_offset(nla_get_u32(bw),
+ nla_get_u32(freq),
+ nla_get_u32(cf1),
+ cf2 ? nla_get_u32(cf2) : 0);
+ } else {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
+ }
+
+ os_memset(&data, 0, sizeof(data));
+ data.ch_switch.freq = nla_get_u32(freq);
+ data.ch_switch.ht_enabled = ht_enabled;
+ data.ch_switch.ch_offset = chan_offset;
+ if (bw)
+ data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+ if (cf1)
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
+
+ bss->freq = data.ch_switch.freq;
+
+ wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *addr)
+{
+ union wpa_event_data event;
+ enum wpa_event_type ev;
+
+ if (nla_len(addr) != ETH_ALEN)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+ cmd, MAC2STR((u8 *) nla_data(addr)));
+
+ if (cmd == NL80211_CMD_AUTHENTICATE)
+ ev = EVENT_AUTH_TIMED_OUT;
+ else if (cmd == NL80211_CMD_ASSOCIATE)
+ ev = EVENT_ASSOC_TIMED_OUT;
+ else
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, ev, &event);
+}
+
+
+static void mlme_event_mgmt(struct i802_bss *bss,
+ struct nlattr *freq, struct nlattr *sig,
+ const u8 *frame, size_t len)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 fc, stype;
+ int ssi_signal = 0;
+ int rx_freq = 0;
+
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
+ return;
+ }
+
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ if (sig)
+ ssi_signal = (s32) nla_get_u32(sig);
+
+ os_memset(&event, 0, sizeof(event));
+ if (freq) {
+ event.rx_mgmt.freq = nla_get_u32(freq);
+ rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: RX frame sa=" 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,
+ le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
+ (unsigned int) len);
+ event.rx_mgmt.frame = frame;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.drv_priv = bss;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+}
+
+
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *cookie, const u8 *frame,
+ size_t len, struct nlattr *ack)
+{
+ union wpa_event_data event;
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
+ if (!is_ap_interface(drv->nlmode)) {
+ u64 cookie_val;
+
+ if (!cookie)
+ return;
+
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+ " cookie=0%llx%s (ack=%d)",
+ (long long unsigned int) cookie_val,
+ cookie_val == drv->send_action_cookie ?
+ " (match)" : " (unknown)", ack != NULL);
+ if (cookie_val != drv->send_action_cookie)
+ return;
+ }
+
+ hdr = (const struct ieee80211_hdr *) frame;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = frame;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ const u8 *bssid = NULL;
+ u16 reason_code = 0;
+
+ if (type == EVENT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len >= 24) {
+ bssid = mgmt->bssid;
+
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ !drv->associated &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+ /*
+ * Avoid issues with some roaming cases where
+ * disconnection event for the old AP may show up after
+ * we have started connection with the new AP.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
+ return;
+ }
+
+ if (drv->associated != 0 &&
+ os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
+ /*
+ * We have presumably received this deauth as a
+ * response to a clear_state_mismatch() outgoing
+ * deauth. Don't let it take us offline!
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
+ "from Unknown BSSID " MACSTR " -- ignoring",
+ MAC2STR(bssid));
+ return;
+ }
+ }
+
+ nl80211_mark_disconnected(drv);
+ os_memset(&event, 0, sizeof(event));
+
+ /* Note: Same offset for Reason Code in both frame subtypes */
+ if (len >= 24 + sizeof(mgmt->u.deauth))
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+ if (type == EVENT_DISASSOC) {
+ event.disassoc_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ event.disassoc_info.addr = bssid;
+ event.disassoc_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.disassoc.variable) {
+ event.disassoc_info.ie = mgmt->u.disassoc.variable;
+ event.disassoc_info.ie_len = frame + len -
+ mgmt->u.disassoc.variable;
+ }
+ } else {
+ 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;
+ 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) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
+ }
+ event.deauth_info.addr = bssid;
+ event.deauth_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.deauth.variable) {
+ event.deauth_info.ie = mgmt->u.deauth.variable;
+ event.deauth_info.ie_len = frame + len -
+ mgmt->u.deauth.variable;
+ }
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 reason_code = 0;
+
+ if (type == EVENT_UNPROT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
+ if (len < 24)
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+
+ os_memset(&event, 0, sizeof(event));
+ /* Note: Same offset for Reason Code in both frame subtypes */
+ if (len >= 24 + sizeof(mgmt->u.deauth))
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+ if (type == EVENT_UNPROT_DISASSOC) {
+ event.unprot_disassoc.sa = mgmt->sa;
+ event.unprot_disassoc.da = mgmt->da;
+ event.unprot_disassoc.reason_code = reason_code;
+ } else {
+ event.unprot_deauth.sa = mgmt->sa;
+ event.unprot_deauth.da = mgmt->da;
+ event.unprot_deauth.reason_code = reason_code;
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event(struct i802_bss *bss,
+ enum nl80211_commands cmd, struct nlattr *frame,
+ struct nlattr *addr, struct nlattr *timed_out,
+ struct nlattr *freq, struct nlattr *ack,
+ struct nlattr *cookie, struct nlattr *sig,
+ struct nlattr *wmm)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const u8 *data;
+ size_t len;
+
+ if (timed_out && addr) {
+ mlme_timeout_event(drv, cmd, addr);
+ return;
+ }
+
+ if (frame == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLME event %d (%s) without frame data",
+ cmd, nl80211_command_to_string(cmd));
+ return;
+ }
+
+ data = nla_data(frame);
+ len = nla_len(frame);
+ if (len < 4 + 2 * ETH_ALEN) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+ MACSTR ") - too short",
+ cmd, nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr));
+ return;
+ }
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+ ") A1=" MACSTR " A2=" MACSTR, cmd,
+ nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr), MAC2STR(data + 4),
+ MAC2STR(data + 4 + ETH_ALEN));
+ if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+ os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+ "for foreign address", bss->ifname);
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
+ nla_data(frame), nla_len(frame));
+
+ switch (cmd) {
+ case NL80211_CMD_AUTHENTICATE:
+ mlme_event_auth(drv, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_ASSOCIATE:
+ mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm);
+ break;
+ case NL80211_CMD_DEAUTHENTICATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_DISASSOCIATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_FRAME:
+ mlme_event_mgmt(bss, freq, sig, nla_data(frame),
+ nla_len(frame));
+ break;
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+ nla_len(frame), ack);
+ break;
+ case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_UNPROT_DISASSOCIATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
+ os_memset(&data, 0, sizeof(data));
+ if (tb[NL80211_ATTR_MAC]) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
+ nla_data(tb[NL80211_ATTR_MAC]),
+ nla_len(tb[NL80211_ATTR_MAC]));
+ data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
+ }
+ if (tb[NL80211_ATTR_KEY_SEQ]) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
+ nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+ nla_len(tb[NL80211_ATTR_KEY_SEQ]));
+ }
+ if (tb[NL80211_ATTR_KEY_TYPE]) {
+ enum nl80211_key_type key_type =
+ nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
+ wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
+ if (key_type == NL80211_KEYTYPE_PAIRWISE)
+ data.michael_mic_failure.unicast = 1;
+ } else
+ data.michael_mic_failure.unicast = 1;
+
+ if (tb[NL80211_ATTR_KEY_IDX]) {
+ u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
+ wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
+ }
+
+ wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ unsigned int freq;
+
+ if (tb[NL80211_ATTR_MAC] == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
+ "event");
+ return;
+ }
+ os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ drv->associated = 1;
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
+ MAC2STR(drv->bssid));
+
+ freq = nl80211_get_assoc_freq(drv);
+ if (freq) {
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
+ freq);
+ drv->first_bss->freq = freq;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
+ int cancel_event, struct nlattr *tb[])
+{
+ unsigned int freq, chan_type, duration;
+ union wpa_event_data data;
+ u64 cookie;
+
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ else
+ freq = 0;
+
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
+ chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ else
+ chan_type = 0;
+
+ if (tb[NL80211_ATTR_DURATION])
+ duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
+ else
+ duration = 0;
+
+ if (tb[NL80211_ATTR_COOKIE])
+ cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ else
+ cookie = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
+ "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
+ cancel_event, freq, chan_type, duration,
+ (long long unsigned int) cookie,
+ cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
+
+ if (cookie != drv->remain_on_chan_cookie)
+ return; /* not for us */
+
+ if (cancel_event)
+ drv->pending_remain_on_chan = 0;
+
+ os_memset(&data, 0, sizeof(data));
+ data.remain_on_channel.freq = freq;
+ data.remain_on_channel.duration = duration;
+ wpa_supplicant_event(drv->ctx, cancel_event ?
+ EVENT_CANCEL_REMAIN_ON_CHANNEL :
+ EVENT_REMAIN_ON_CHANNEL, &data);
+}
+
+
+static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ os_memset(&data, 0, sizeof(data));
+
+ if (tb[NL80211_ATTR_IE]) {
+ data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
+ data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
+ }
+
+ if (tb[NL80211_ATTR_IE_RIC]) {
+ data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
+ data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
+ }
+
+ if (tb[NL80211_ATTR_MAC])
+ os_memcpy(data.ft_ies.target_ap,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
+ MAC2STR(data.ft_ies.target_ap));
+
+ wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+ struct nlattr *tb[])
+{
+ union wpa_event_data event;
+ struct nlattr *nl;
+ int rem;
+ struct scan_info *info;
+#define MAX_REPORT_FREQS 50
+ int freqs[MAX_REPORT_FREQS];
+ int num_freqs = 0;
+
+ if (drv->scan_for_auth) {
+ drv->scan_for_auth = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+ "cfg80211 BSS entry");
+ wpa_driver_nl80211_authenticate_retry(drv);
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ info = &event.scan_info;
+ info->aborted = aborted;
+
+ if (tb[NL80211_ATTR_SCAN_SSIDS]) {
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
+ struct wpa_driver_scan_ssid *s =
+ &info->ssids[info->num_ssids];
+ s->ssid = nla_data(nl);
+ s->ssid_len = nla_len(nl);
+ wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+ wpa_ssid_txt(s->ssid, s->ssid_len));
+ info->num_ssids++;
+ if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ char msg[200], *pos, *end;
+ int res;
+
+ pos = msg;
+ end = pos + sizeof(msg);
+ *pos = '\0';
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+ {
+ freqs[num_freqs] = nla_get_u32(nl);
+ res = os_snprintf(pos, end - pos, " %d",
+ freqs[num_freqs]);
+ if (!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 nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+ [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
+ [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+ };
+ struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+ enum nl80211_cqm_rssi_threshold_event event;
+ union wpa_event_data ed;
+ struct wpa_signal_info sig;
+ int res;
+
+ if (tb[NL80211_ATTR_CQM] == NULL ||
+ nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
+ cqm_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
+ return;
+ }
+
+ os_memset(&ed, 0, sizeof(ed));
+
+ if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+ os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+ return;
+ }
+
+ if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+ return;
+ event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
+
+ if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+ "event: RSSI high");
+ ed.signal_change.above_threshold = 1;
+ } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+ "event: RSSI low");
+ ed.signal_change.above_threshold = 0;
+ } else
+ return;
+
+ res = nl80211_get_link_signal(drv, &sig);
+ if (res == 0) {
+ ed.signal_change.current_signal = sig.current_signal;
+ ed.signal_change.current_txrate = sig.current_txrate;
+ wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
+ sig.current_signal, sig.current_txrate);
+ }
+
+ res = nl80211_get_link_noise(drv, &sig);
+ if (res == 0) {
+ ed.signal_change.current_noise = sig.current_noise;
+ wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
+ sig.current_noise);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
+}
+
+
+static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ const u8 *addr;
+ union wpa_event_data data;
+
+ if (drv->nlmode != NL80211_IFTYPE_MESH_POINT ||
+ !tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
+ return;
+
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR,
+ MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ data.mesh_peer.peer = addr;
+ data.mesh_peer.ies = nla_data(tb[NL80211_ATTR_IE]);
+ data.mesh_peer.ie_len = nla_len(tb[NL80211_ATTR_IE]);
+ wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data);
+}
+
+
+static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
+ struct i802_bss *bss,
+ struct nlattr **tb)
+{
+ u8 *addr;
+ union wpa_event_data data;
+
+ if (tb[NL80211_ATTR_MAC] == NULL)
+ return;
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
+
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+ u8 *ies = NULL;
+ size_t ies_len = 0;
+ if (tb[NL80211_ATTR_IE]) {
+ ies = nla_data(tb[NL80211_ATTR_IE]);
+ ies_len = nla_len(tb[NL80211_ATTR_IE]);
+ }
+ wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
+ drv_event_assoc(bss->ctx, addr, ies, ies_len, 0);
+ return;
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
+ wpa_supplicant_event(bss->ctx, EVENT_IBSS_RSN_START, &data);
+}
+
+
+static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u8 *addr;
+ union wpa_event_data data;
+
+ if (tb[NL80211_ATTR_MAC] == NULL)
+ return;
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
+ MAC2STR(addr));
+
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+ drv_event_disassoc(drv->ctx, addr);
+ return;
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+}
+
+
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+ static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+ [NL80211_REKEY_DATA_KEK] = {
+ .minlen = NL80211_KEK_LEN,
+ .maxlen = NL80211_KEK_LEN,
+ },
+ [NL80211_REKEY_DATA_KCK] = {
+ .minlen = NL80211_KCK_LEN,
+ .maxlen = NL80211_KCK_LEN,
+ },
+ [NL80211_REKEY_DATA_REPLAY_CTR] = {
+ .minlen = NL80211_REPLAY_CTR_LEN,
+ .maxlen = NL80211_REPLAY_CTR_LEN,
+ },
+ };
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ !tb[NL80211_ATTR_REKEY_DATA] ||
+ nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+ tb[NL80211_ATTR_REKEY_DATA], rekey_policy) ||
+ !rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+ MAC2STR(data.driver_gtk_rekey.bssid));
+ data.driver_gtk_rekey.replay_ctr =
+ nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+ data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+ static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+ [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+ [NL80211_PMKSA_CANDIDATE_BSSID] = {
+ .minlen = ETH_ALEN,
+ .maxlen = ETH_ALEN,
+ },
+ [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+ };
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
+ if (!tb[NL80211_ATTR_PMKSA_CANDIDATE] ||
+ nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+ tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy) ||
+ !cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+ !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid,
+ nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+ data.pmkid_candidate.index =
+ nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+ data.pmkid_candidate.preauth =
+ cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.client_poll.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+ switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+ case NL80211_TDLS_SETUP:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_SETUP;
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+ break;
+ case NL80211_TDLS_DISCOVERY_REQ:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: TDLS discovery request for peer " MACSTR,
+ MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_DISCOVER;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+ "event");
+ return;
+ }
+ if (tb[NL80211_ATTR_REASON_CODE]) {
+ data.tdls.reason_code =
+ nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
+static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ u32 reason;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.connect_failed_reason.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+ switch (reason) {
+ case NL80211_CONN_FAIL_MAX_CLIENTS:
+ wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+ data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+ break;
+ case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+ wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+ " tried to connect",
+ MAC2STR(data.connect_failed_reason.addr));
+ data.connect_failed_reason.code = BLOCKED_CLIENT;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+ "%u", reason);
+ return;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ enum nl80211_radar_event event_type;
+
+ if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+ /* Check HT params */
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ data.dfs_event.ht_enabled = 1;
+ data.dfs_event.chan_offset = 0;
+
+ switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+ case NL80211_CHAN_NO_HT:
+ data.dfs_event.ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ data.dfs_event.chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ data.dfs_event.chan_offset = -1;
+ break;
+ }
+ }
+
+ /* Get VHT params */
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ data.dfs_event.chan_width =
+ convert2width(nla_get_u32(
+ tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+ data.dfs_event.freq, data.dfs_event.ht_enabled,
+ data.dfs_event.chan_offset, data.dfs_event.chan_width,
+ data.dfs_event.cf1, data.dfs_event.cf2);
+
+ switch (event_type) {
+ case NL80211_RADAR_DETECTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+ break;
+ case NL80211_RADAR_CAC_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+ break;
+ case NL80211_RADAR_CAC_ABORTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+ break;
+ case NL80211_RADAR_NOP_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+ "received", event_type);
+ break;
+ }
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+ int wds)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data event;
+
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.bssid = bss->addr;
+ event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+ event.rx_from_unknown.wds = wds;
+
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ u32 i, count;
+ union wpa_event_data event;
+ struct wpa_freq_range *range = NULL;
+ const struct qca_avoid_freq_list *freq_range;
+
+ freq_range = (const struct qca_avoid_freq_list *) data;
+ if (len < sizeof(freq_range->count))
+ return;
+
+ count = freq_range->count;
+ if (len < sizeof(freq_range->count) +
+ count * sizeof(struct qca_avoid_freq_range)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
+ (unsigned int) len);
+ return;
+ }
+
+ if (count > 0) {
+ range = os_calloc(count, sizeof(struct wpa_freq_range));
+ if (range == NULL)
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ for (i = 0; i < count; i++) {
+ unsigned int idx = event.freq_range.num;
+ range[idx].min = freq_range->range[i].start_freq;
+ range[idx].max = freq_range->range[i].end_freq;
+ wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
+ range[idx].min, range[idx].max);
+ if (range[idx].min > range[idx].max) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
+ continue;
+ }
+ event.freq_range.num++;
+ }
+ event.freq_range.range = range;
+
+ wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
+
+ os_free(range);
+}
+
+
+static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS channel selection vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.acs_selected_channels.pri_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+ event.acs_selected_channels.sec_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
+}
+
+
+static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1];
+ u8 *bssid;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Key management roam+auth vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] ||
+ nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED])
+ return;
+
+ bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]);
+ wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid));
+
+ mlme_event_connect(drv, NL80211_CMD_ROAM, NULL,
+ 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],
+ 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]);
+}
+
+
+static void qca_nl80211_dfs_offload_radar_event(
+ struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length)
+{
+ union wpa_event_data data;
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: DFS offload radar vendor event received");
+
+ if (nla_parse(tb, NL80211_ATTR_MAX,
+ (struct nlattr *) msg, length, NULL))
+ return;
+
+ if (!tb[NL80211_ATTR_WIPHY_FREQ]) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Error parsing WIPHY_FREQ in FS offload radar vendor event");
+ return;
+ }
+
+ os_memset(&data, 0, sizeof(data));
+ data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+ data.dfs_event.freq);
+
+ /* Check HT params */
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ data.dfs_event.ht_enabled = 1;
+ data.dfs_event.chan_offset = 0;
+
+ switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+ case NL80211_CHAN_NO_HT:
+ data.dfs_event.ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ data.dfs_event.chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ data.dfs_event.chan_offset = -1;
+ break;
+ }
+ }
+
+ /* Get VHT params */
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ data.dfs_event.chan_width =
+ convert2width(nla_get_u32(
+ tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, "
+ "offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+ data.dfs_event.freq, data.dfs_event.ht_enabled,
+ data.dfs_event.chan_offset, data.dfs_event.chan_width,
+ data.dfs_event.cf1, data.dfs_event.cf2);
+
+ switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unknown DFS offload radar event %d received",
+ subcmd);
+ break;
+ }
+}
+
+
+static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
+ u32 subcmd, u8 *data, size_t len)
+{
+ switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_TEST:
+ wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
+ qca_nl80211_avoid_freq(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
+ qca_nl80211_key_mgmt_auth(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ qca_nl80211_acs_select_ch(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
+ qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore unsupported QCA vendor event %u",
+ subcmd);
+ break;
+ }
+}
+
+
+static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u32 vendor_id, subcmd, wiphy = 0;
+ int wiphy_idx;
+ u8 *data = NULL;
+ size_t len = 0;
+
+ if (!tb[NL80211_ATTR_VENDOR_ID] ||
+ !tb[NL80211_ATTR_VENDOR_SUBCMD])
+ return;
+
+ vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
+ subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
+
+ if (tb[NL80211_ATTR_WIPHY])
+ wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
+ wiphy, vendor_id, subcmd);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
+ len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
+ }
+
+ wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
+ if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
+ wiphy, wiphy_idx);
+ return;
+ }
+
+ switch (vendor_id) {
+ case OUI_QCA:
+ nl80211_vendor_event_qca(drv, subcmd, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
+ break;
+ }
+}
+
+
+static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+ enum nl80211_reg_initiator init;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+
+ if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
+ wpa_printf(MSG_DEBUG, " * initiator=%d", init);
+ switch (init) {
+ case NL80211_REGDOM_SET_BY_CORE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+ break;
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
+ break;
+ }
+
+ if (tb[NL80211_ATTR_REG_TYPE]) {
+ enum nl80211_reg_type type;
+ type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
+ wpa_printf(MSG_DEBUG, " * type=%d", type);
+ switch (type) {
+ case NL80211_REGDOM_TYPE_COUNTRY:
+ data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
+ break;
+ case NL80211_REGDOM_TYPE_WORLD:
+ data.channel_list_changed.type = REGDOM_TYPE_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_CUSTOM_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_INTERSECTION:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_INTERSECTION;
+ break;
+ }
+ }
+
+ if (tb[NL80211_ATTR_REG_ALPHA2]) {
+ os_strlcpy(data.channel_list_changed.alpha2,
+ nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
+ sizeof(data.channel_list_changed.alpha2));
+ wpa_printf(MSG_DEBUG, " * alpha2=%s",
+ data.channel_list_changed.alpha2);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+ struct nlattr **tb)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+ cmd, nl80211_command_to_string(cmd), bss->ifname);
+
+ if (cmd == NL80211_CMD_ROAM &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ /*
+ * Device will use roam+auth vendor event to indicate
+ * roaming, so ignore the regular roam event.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
+ cmd);
+ return;
+ }
+
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+ (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+ cmd == NL80211_CMD_SCAN_ABORTED)) {
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+ }
+
+ switch (cmd) {
+ case NL80211_CMD_TRIGGER_SCAN:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+ drv->scan_state = SCAN_STARTED;
+ if (drv->scan_for_auth) {
+ /*
+ * Cannot indicate EVENT_SCAN_STARTED here since we skip
+ * EVENT_SCAN_RESULTS in scan_for_auth case and the
+ * upper layer implementation could get confused about
+ * scanning state.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
+ break;
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+ drv->scan_state = SCHED_SCAN_STARTED;
+ break;
+ case NL80211_CMD_SCHED_SCAN_STOPPED:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+ drv->scan_state = SCHED_SCAN_STOPPED;
+ wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+ break;
+ case NL80211_CMD_NEW_SCAN_RESULTS:
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New scan results available");
+ drv->scan_state = SCAN_COMPLETED;
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ send_scan_event(drv, 0, tb);
+ break;
+ case NL80211_CMD_SCHED_SCAN_RESULTS:
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New sched scan results available");
+ drv->scan_state = SCHED_SCAN_RESULTS;
+ send_scan_event(drv, 0, tb);
+ break;
+ case NL80211_CMD_SCAN_ABORTED:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+ drv->scan_state = SCAN_ABORTED;
+ /*
+ * Need to indicate that scan results are available in order
+ * not to make wpa_supplicant stop its scanning.
+ */
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ send_scan_event(drv, 1, tb);
+ break;
+ case NL80211_CMD_AUTHENTICATE:
+ case NL80211_CMD_ASSOCIATE:
+ case NL80211_CMD_DEAUTHENTICATE:
+ case NL80211_CMD_DISASSOCIATE:
+ case NL80211_CMD_FRAME_TX_STATUS:
+ case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+ case NL80211_CMD_UNPROT_DISASSOCIATE:
+ mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM],
+ tb[NL80211_ATTR_STA_WME]);
+ break;
+ case NL80211_CMD_CONNECT:
+ case NL80211_CMD_ROAM:
+ mlme_event_connect(drv, cmd,
+ tb[NL80211_ATTR_STATUS_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_REQ_IE],
+ tb[NL80211_ATTR_RESP_IE],
+ NULL, NULL, NULL, NULL);
+ break;
+ case NL80211_CMD_CH_SWITCH_NOTIFY:
+ mlme_event_ch_switch(drv,
+ tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ tb[NL80211_ATTR_CHANNEL_WIDTH],
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2]);
+ break;
+ case NL80211_CMD_DISCONNECT:
+ mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
+ break;
+ case NL80211_CMD_MICHAEL_MIC_FAILURE:
+ mlme_event_michael_mic_failure(bss, tb);
+ break;
+ case NL80211_CMD_JOIN_IBSS:
+ mlme_event_join_ibss(drv, tb);
+ break;
+ case NL80211_CMD_REMAIN_ON_CHANNEL:
+ mlme_event_remain_on_channel(drv, 0, tb);
+ break;
+ case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
+ mlme_event_remain_on_channel(drv, 1, tb);
+ break;
+ case NL80211_CMD_NOTIFY_CQM:
+ nl80211_cqm_event(drv, tb);
+ break;
+ case NL80211_CMD_REG_CHANGE:
+ 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);
+ 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);
+ break;
+ case NL80211_CMD_SET_REKEY_OFFLOAD:
+ nl80211_rekey_offload_event(drv, tb);
+ break;
+ case NL80211_CMD_PMKSA_CANDIDATE:
+ nl80211_pmksa_candidate_event(drv, tb);
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ nl80211_client_probe_event(drv, tb);
+ break;
+ case NL80211_CMD_TDLS_OPER:
+ nl80211_tdls_oper_event(drv, tb);
+ break;
+ case NL80211_CMD_CONN_FAILED:
+ nl80211_connect_failed_event(drv, tb);
+ break;
+ case NL80211_CMD_FT_EVENT:
+ mlme_event_ft_event(drv, tb);
+ break;
+ case NL80211_CMD_RADAR_DETECT:
+ nl80211_radar_event(drv, tb);
+ break;
+ case NL80211_CMD_STOP_AP:
+ nl80211_stop_ap(drv, tb);
+ break;
+ case NL80211_CMD_VENDOR:
+ nl80211_vendor_event(drv, tb);
+ break;
+ case NL80211_CMD_NEW_PEER_CANDIDATE:
+ nl80211_new_peer_candidate(drv, tb);
+ break;
+ default:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", cmd);
+ break;
+ }
+}
+
+
+int process_global_event(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_global *global = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct wpa_driver_nl80211_data *drv, *tmp;
+ int ifidx = -1;
+ struct i802_bss *bss;
+ u64 wdev_id = 0;
+ int wdev_id_set = 0;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_IFINDEX])
+ ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ else if (tb[NL80211_ATTR_WDEV]) {
+ wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wdev_id_set = 1;
+ }
+
+ dl_list_for_each_safe(drv, tmp, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if ((ifidx == -1 && !wdev_id_set) ||
+ ifidx == bss->ifindex ||
+ (wdev_id_set && bss->wdev_id_set &&
+ wdev_id == bss->wdev_id)) {
+ do_process_drv_event(bss, gnlh->cmd, tb);
+ return NL_SKIP;
+ }
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d wdev 0x%llx)",
+ gnlh->cmd, ifidx, (long long unsigned int) wdev_id);
+ }
+
+ return NL_SKIP;
+}
+
+
+int process_bss_event(struct nl_msg *msg, void *arg)
+{
+ struct i802_bss *bss = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+ gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+ bss->ifname);
+
+ switch (gnlh->cmd) {
+ case NL80211_CMD_FRAME:
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM],
+ tb[NL80211_ATTR_STA_WME]);
+ break;
+ case NL80211_CMD_UNEXPECTED_FRAME:
+ nl80211_spurious_frame(bss, tb, 0);
+ break;
+ case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+ nl80211_spurious_frame(bss, tb, 1);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", gnlh->cmd);
+ break;
+ }
+
+ return NL_SKIP;
+}
diff --git a/contrib/wpa/src/drivers/driver_nl80211_monitor.c b/contrib/wpa/src/drivers/driver_nl80211_monitor.c
new file mode 100644
index 0000000..45385da
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211_monitor.c
@@ -0,0 +1,491 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - AP monitor interface
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "linux_ioctl.h"
+#include "radiotap_iter.h"
+#include "driver_nl80211.h"
+
+
+static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = buf;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ok;
+ wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len)
+{
+ struct ieee80211_hdr *hdr = (void *)buf;
+ u16 fc;
+ union wpa_event_data event;
+
+ if (len < sizeof(*hdr))
+ return;
+
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+ event.rx_from_unknown.addr = hdr->addr2;
+ event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+ (WLAN_FC_FROMDS | WLAN_FC_TODS);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void handle_frame(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len, int datarate, int ssi_signal)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case WLAN_FC_TYPE_MGMT:
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.datarate = datarate;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ /* can only get here with PS-Poll frames */
+ wpa_printf(MSG_DEBUG, "CTRL");
+ from_unknown_sta(drv, buf, len);
+ break;
+ case WLAN_FC_TYPE_DATA:
+ from_unknown_sta(drv, buf, len);
+ break;
+ }
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct ieee80211_radiotap_iterator iter;
+ int ret;
+ int datarate = 0, ssi_signal = 0;
+ int injected = 0, failed = 0, rxflags = 0;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+ strerror(errno));
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
+ return;
+ }
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+ ret);
+ return;
+ }
+ switch (iter.this_arg_index) {
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ len -= 4;
+ break;
+ case IEEE80211_RADIOTAP_RX_FLAGS:
+ rxflags = 1;
+ break;
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ injected = 1;
+ failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+ IEEE80211_RADIOTAP_F_TX_FAIL;
+ break;
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
+ break;
+ case IEEE80211_RADIOTAP_CHANNEL:
+ /* TODO: convert from freq/flags to channel number */
+ break;
+ case IEEE80211_RADIOTAP_RATE:
+ datarate = *iter.this_arg * 5;
+ break;
+ case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+ ssi_signal = (s8) *iter.this_arg;
+ break;
+ }
+ }
+
+ if (rxflags && injected)
+ return;
+
+ if (!injected)
+ handle_frame(drv, buf + iter._max_length,
+ len - iter._max_length, datarate, ssi_signal);
+ else
+ handle_tx_callback(drv->ctx, buf + iter._max_length,
+ len - iter._max_length, !failed);
+}
+
+
+/*
+ * we post-process the filter code later and rewrite
+ * this to the offset to the last instruction
+ */
+#define PASS 0xFF
+#define FAIL 0xFE
+
+static struct sock_filter msock_filter_insns[] = {
+ /*
+ * do a little-endian load of the radiotap length field
+ */
+ /* load lower byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
+ /* put it into X (== index register) */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+ /* load upper byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
+ /* left-shift it by 8 */
+ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
+ /* or with X */
+ BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
+ /* put result into X */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+
+ /*
+ * Allow management frames through, this also gives us those
+ * management frames that we sent ourselves with status
+ */
+ /* load the lower byte of the IEEE 802.11 frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off frame type and version */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
+ /* accept frame if it's both 0, fall through otherwise */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
+
+ /*
+ * TODO: add a bit to radiotap RX flags that indicates
+ * that the sending station is not associated, then
+ * add a filter here that filters on our DA and that flag
+ * to allow us to deauth frames to that bad station.
+ *
+ * For now allow all To DS data frames through.
+ */
+ /* load the IEEE 802.11 frame control field */
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
+ /* mask off frame type, version and DS status */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
+ /* accept frame if version 0, type 2 and To DS, fall through otherwise
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
+
+#if 0
+ /*
+ * drop non-data frames
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
+ /* drop non-data frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
+#endif
+ /* load the upper byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
+ /* mask off toDS/fromDS */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
+ /* accept WDS frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
+
+ /*
+ * add header length to index
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
+ /* right shift it by 6 to give 0 or 2 */
+ BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
+ /* add data frame header length */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
+ /* add index, was start of 802.11 header */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
+ /* move to index, now start of LL header */
+ BPF_STMT(BPF_MISC | BPF_TAX, 0),
+
+ /*
+ * Accept empty data frames, we use those for
+ * polling activity.
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
+
+ /*
+ * Accept EAPOL frames
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
+
+ /* keep these last two statements or change the code below */
+ /* return 0 == "DROP" */
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ /* return ~0 == "keep all" */
+ BPF_STMT(BPF_RET | BPF_K, ~0),
+};
+
+static struct sock_fprog msock_filter = {
+ .len = ARRAY_SIZE(msock_filter_insns),
+ .filter = msock_filter_insns,
+};
+
+
+static int add_monitor_filter(int s)
+{
+ int idx;
+
+ /* rewrite all PASS/FAIL jump offsets */
+ for (idx = 0; idx < msock_filter.len; idx++) {
+ struct sock_filter *insn = &msock_filter_insns[idx];
+
+ if (BPF_CLASS(insn->code) == BPF_JMP) {
+ if (insn->code == (BPF_JMP|BPF_JA)) {
+ if (insn->k == PASS)
+ insn->k = msock_filter.len - idx - 2;
+ else if (insn->k == FAIL)
+ insn->k = msock_filter.len - idx - 3;
+ }
+
+ if (insn->jt == PASS)
+ insn->jt = msock_filter.len - idx - 2;
+ else if (insn->jt == FAIL)
+ insn->jt = msock_filter.len - idx - 3;
+
+ if (insn->jf == PASS)
+ insn->jf = msock_filter.len - idx - 2;
+ else if (insn->jf == FAIL)
+ insn->jf = msock_filter.len - idx - 3;
+ }
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
+ &msock_filter, sizeof(msock_filter))) {
+ wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+ if (drv->monitor_refcount > 0)
+ drv->monitor_refcount--;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+ drv->monitor_refcount);
+ if (drv->monitor_refcount > 0)
+ return;
+
+ if (drv->monitor_ifidx >= 0) {
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ drv->monitor_ifidx = -1;
+ }
+ if (drv->monitor_sock >= 0) {
+ eloop_unregister_read_sock(drv->monitor_sock);
+ close(drv->monitor_sock);
+ drv->monitor_sock = -1;
+ }
+}
+
+
+int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval;
+ socklen_t optlen;
+
+ if (drv->monitor_ifidx >= 0) {
+ drv->monitor_refcount++;
+ wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+ drv->monitor_refcount);
+ return 0;
+ }
+
+ if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
+ /*
+ * P2P interface name is of the format p2p-%s-%d. For monitor
+ * interface name corresponding to P2P GO, replace "p2p-" with
+ * "mon-" to retain the same interface name length and to
+ * indicate that it is a monitor interface.
+ */
+ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
+ } else {
+ /* Non-P2P interface with AP functionality. */
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
+ }
+
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+ 0, NULL, NULL, 0);
+
+ if (drv->monitor_ifidx == -EOPNOTSUPP) {
+ /*
+ * This is backward compatibility for a few versions of
+ * the kernel only that didn't advertise the right
+ * attributes for the only driver that then supported
+ * AP mode w/o monitor -- ath6kl.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
+ "monitor interface type - try to run without it");
+ drv->device_ap_sme = 1;
+ }
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
+ goto error;
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = drv->monitor_ifidx;
+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->monitor_sock < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ if (add_monitor_filter(drv->monitor_sock)) {
+ wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
+ "interface; do filtering in user space");
+ /* This works, but will cost in performance. */
+ }
+
+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
+ goto error;
+ }
+
+ drv->monitor_refcount++;
+ return 0;
+ error:
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+}
+
+
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack)
+{
+ __u8 rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+ 0x00, /* padding */
+ 0x00, 0x00, /* RX and TX flags to indicate that */
+ 0x00, 0x00, /* this is the injected frame directly */
+ };
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void *) data,
+ .iov_len = len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+ int res;
+ u16 txflags = 0;
+
+ if (encrypt)
+ rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+ if (drv->monitor_sock < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
+ "for %s", __func__);
+ return -1;
+ }
+
+ if (noack)
+ txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+ WPA_PUT_LE16(&rtap_hdr[12], txflags);
+
+ res = sendmsg(drv->monitor_sock, &msg, 0);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
diff --git a/contrib/wpa/src/drivers/driver_nl80211_scan.c b/contrib/wpa/src/drivers/driver_nl80211_scan.c
new file mode 100644
index 0000000..3911f48
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_nl80211_scan.c
@@ -0,0 +1,775 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "driver_nl80211.h"
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+ struct wpa_scan_results *scan_results = arg;
+ struct wpa_scan_res *scan_res;
+ size_t i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+ return NL_SKIP;
+ }
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+ "attributes");
+ return NL_SKIP;
+ }
+
+ if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+ return NL_SKIP;
+
+ for (i = 0; i < scan_results->num; ++i) {
+ scan_res = scan_results->res[i];
+ if (!scan_res)
+ continue;
+ if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+ scan_res->freq)
+ continue;
+ if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+ continue;
+ scan_res->noise = (s8)
+ nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_scan_results *scan_res)
+{
+ struct nl_msg *msg;
+
+ msg = 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);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Driver private data
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+ }
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static struct nl_msg *
+nl80211_scan_common(struct i802_bss *bss, u8 cmd,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ size_t i;
+ u32 scan_flags = 0;
+
+ msg = nl80211_cmd_msg(bss, 0, cmd);
+ if (!msg)
+ return NULL;
+
+ if (params->num_ssids) {
+ struct nlattr *ssids;
+
+ ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
+ if (ssids == NULL)
+ goto fail;
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid))
+ goto fail;
+ }
+ nla_nest_end(msg, ssids);
+ }
+
+ if (params->extra_ies) {
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
+ if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+ params->extra_ies))
+ goto fail;
+ }
+
+ if (params->freqs) {
+ struct nlattr *freqs;
+ freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+ if (freqs == NULL)
+ goto fail;
+ for (i = 0; params->freqs[i]; i++) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
+ "MHz", params->freqs[i]);
+ if (nla_put_u32(msg, i + 1, params->freqs[i]))
+ goto fail;
+ }
+ nla_nest_end(msg, freqs);
+ }
+
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ if (params->only_new_results) {
+ wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
+ scan_flags |= NL80211_SCAN_FLAG_FLUSH;
+ }
+
+ 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, NL80211_ATTR_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, NL80211_ATTR_MAC_MASK, ETH_ALEN,
+ params->mac_addr_mask))
+ goto fail;
+ }
+ }
+
+ if (scan_flags &&
+ nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
+ goto fail;
+
+ return msg;
+
+fail:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_nl80211_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1, timeout;
+ struct nl_msg *msg = NULL;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+ drv->scan_for_auth = 0;
+
+ msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
+ if (!msg)
+ return -1;
+
+ if (params->p2p_probe) {
+ struct nlattr *rates;
+
+ wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+ rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+ if (rates == NULL)
+ goto 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, NL80211_ATTR_TX_NO_CCK_RATE))
+ goto fail;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ if (drv->hostapd && is_ap_interface(drv->nlmode)) {
+ enum nl80211_iftype old_mode = drv->nlmode;
+
+ /*
+ * mac80211 does not allow scan requests in AP mode, so
+ * try to do this in station mode.
+ */
+ if (wpa_driver_nl80211_set_mode(
+ bss, NL80211_IFTYPE_STATION))
+ goto fail;
+
+ if (wpa_driver_nl80211_scan(bss, params)) {
+ wpa_driver_nl80211_set_mode(bss, old_mode);
+ goto fail;
+ }
+
+ /* Restore AP mode when processing scan results */
+ drv->ap_scan_as_station = old_mode;
+ ret = 0;
+ } else
+ goto fail;
+ }
+
+ drv->scan_state = SCAN_REQUESTED;
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 10;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver events to notify when scan is
+ * complete, so use longer timeout to avoid race conditions
+ * with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_sched_scan(void *priv,
+ struct wpa_driver_scan_params *params,
+ u32 interval)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ struct nl_msg *msg;
+ size_t i;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+ msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
+ goto fail;
+
+ if ((drv->num_filter_ssids &&
+ (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+ params->filter_rssi) {
+ struct nlattr *match_sets;
+ match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+ if (match_sets == NULL)
+ goto fail;
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ struct nlattr *match_set_ssid;
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "nl80211: Sched scan filter SSID",
+ drv->filter_ssids[i].ssid,
+ drv->filter_ssids[i].ssid_len);
+
+ match_set_ssid = nla_nest_start(msg, i + 1);
+ if (match_set_ssid == NULL ||
+ nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+ drv->filter_ssids[i].ssid_len,
+ drv->filter_ssids[i].ssid) ||
+ (params->filter_rssi &&
+ nla_put_u32(msg,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi)))
+ goto fail;
+
+ nla_nest_end(msg, match_set_ssid);
+ }
+
+ /*
+ * Due to backward compatibility code, newer kernels treat this
+ * matchset (with only an RSSI filter) as the default for all
+ * other matchsets, unless it's the only one, in which case the
+ * matchset will actually allow all SSIDs above the RSSI.
+ */
+ if (params->filter_rssi) {
+ struct nlattr *match_set_rssi;
+ match_set_rssi = nla_nest_start(msg, 0);
+ if (match_set_rssi == NULL ||
+ nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi))
+ goto fail;
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan RSSI filter %d dBm",
+ params->filter_rssi);
+ nla_nest_end(msg, match_set_rssi);
+ }
+
+ nla_nest_end(msg, match_sets);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ /* TODO: if we get an error here, we should fall back to normal scan */
+
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+ "ret=%d (%s)", ret, strerror(-ret));
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+ "scan interval %d msec", ret, interval);
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret;
+ struct nl_msg *msg;
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_stop(bss);
+#endif /* ANDROID */
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Sched scan stop failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Sched scan stop sent");
+ }
+
+ return ret;
+}
+
+
+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+{
+ const u8 *end, *pos;
+
+ if (ies == NULL)
+ return NULL;
+
+ pos = ies;
+ end = ies + ies_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == ie)
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
+static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *ssid;
+ size_t i;
+
+ if (drv->filter_ssids == NULL)
+ return 0;
+
+ ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid == NULL)
+ return 1;
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ if (ssid[1] == drv->filter_ssids[i].ssid_len &&
+ os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
+ 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+ [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
+ [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+ };
+ struct nl80211_bss_info_arg *_arg = arg;
+ struct wpa_scan_results *res = _arg->res;
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ const u8 *ie, *beacon_ie;
+ size_t ie_len, beacon_ie_len;
+ u8 *pos;
+ size_t i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS])
+ return NL_SKIP;
+ if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy))
+ return NL_SKIP;
+ if (bss[NL80211_BSS_STATUS]) {
+ enum nl80211_bss_status status;
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ _arg->assoc_freq =
+ nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ _arg->assoc_freq);
+ }
+ if (status == NL80211_BSS_STATUS_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;
+ if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ } else {
+ ie = NULL;
+ ie_len = 0;
+ }
+ if (bss[NL80211_BSS_BEACON_IES]) {
+ beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
+ beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
+ } else {
+ beacon_ie = NULL;
+ beacon_ie_len = 0;
+ }
+
+ if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+ ie ? ie_len : beacon_ie_len))
+ return NL_SKIP;
+
+ r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
+ if (r == NULL)
+ return NL_SKIP;
+ if (bss[NL80211_BSS_BSSID])
+ os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+ ETH_ALEN);
+ if (bss[NL80211_BSS_FREQUENCY])
+ r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ if (bss[NL80211_BSS_BEACON_INTERVAL])
+ r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+ if (bss[NL80211_BSS_CAPABILITY])
+ r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+ r->flags |= WPA_SCAN_NOISE_INVALID;
+ if (bss[NL80211_BSS_SIGNAL_MBM]) {
+ r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+ r->level /= 100; /* mBm to dBm */
+ r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
+ } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
+ r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
+ r->flags |= WPA_SCAN_QUAL_INVALID;
+ } else
+ r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
+ if (bss[NL80211_BSS_TSF])
+ r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ if (bss[NL80211_BSS_SEEN_MS_AGO])
+ r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
+ r->ie_len = ie_len;
+ pos = (u8 *) (r + 1);
+ if (ie) {
+ os_memcpy(pos, ie, ie_len);
+ pos += ie_len;
+ }
+ r->beacon_ie_len = beacon_ie_len;
+ if (beacon_ie)
+ os_memcpy(pos, beacon_ie, beacon_ie_len);
+
+ if (bss[NL80211_BSS_STATUS]) {
+ enum nl80211_bss_status status;
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ switch (status) {
+ case NL80211_BSS_STATUS_ASSOCIATED:
+ r->flags |= WPA_SCAN_ASSOCIATED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * cfg80211 maintains separate BSS table entries for APs if the same
+ * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
+ * not use frequency as a separate key in the BSS table, so filter out
+ * duplicated entries. Prefer associated BSS entry in such a case in
+ * order to get the correct frequency into the BSS table. Similarly,
+ * prefer newer entries over older.
+ */
+ for (i = 0; i < res->num; i++) {
+ const u8 *s1, *s2;
+ if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
+ continue;
+
+ s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
+ res->res[i]->ie_len, WLAN_EID_SSID);
+ s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
+ if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
+ os_memcmp(s1, s2, 2 + s1[1]) != 0)
+ continue;
+
+ /* Same BSSID,SSID was already included in scan results */
+ wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
+ "for " MACSTR, MAC2STR(r->bssid));
+
+ if (((r->flags & WPA_SCAN_ASSOCIATED) &&
+ !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
+ r->age < res->res[i]->age) {
+ os_free(res->res[i]);
+ res->res[i] = r;
+ } else
+ os_free(r);
+ return NL_SKIP;
+ }
+
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return NL_SKIP;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+
+ return NL_SKIP;
+}
+
+
+static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr)
+{
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
+ "mismatch (" MACSTR ")", MAC2STR(addr));
+ wpa_driver_nl80211_mlme(drv, addr,
+ NL80211_CMD_DEAUTHENTICATE,
+ WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+ }
+}
+
+
+static void wpa_driver_nl80211_check_bss_status(
+ struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
+{
+ size_t i;
+
+ for (i = 0; i < res->num; i++) {
+ struct wpa_scan_res *r = res->res[i];
+
+ if (r->flags & WPA_SCAN_ASSOCIATED) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+ "indicate BSS status with " MACSTR
+ " as associated",
+ MAC2STR(r->bssid));
+ if (is_sta_interface(drv->nlmode) &&
+ !drv->associated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Local state "
+ "(not associated) does not match "
+ "with BSS state");
+ clear_state_mismatch(drv, r->bssid);
+ } else if (is_sta_interface(drv->nlmode) &&
+ os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
+ 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Local state "
+ "(associated with " MACSTR ") does "
+ "not match with BSS state",
+ MAC2STR(drv->bssid));
+ clear_state_mismatch(drv, r->bssid);
+ clear_state_mismatch(drv, drv->bssid);
+ }
+ }
+ }
+}
+
+
+static struct wpa_scan_results *
+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct wpa_scan_results *res;
+ int ret;
+ struct nl80211_bss_info_arg arg;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return NULL;
+ if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
+ NL80211_CMD_GET_SCAN))) {
+ wpa_scan_results_free(res);
+ return NULL;
+ }
+
+ arg.drv = drv;
+ arg.res = res;
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+ "BSSes)", (unsigned long) res->num);
+ nl80211_get_noise_for_scan_results(drv, res);
+ return res;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ wpa_scan_results_free(res);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct wpa_scan_results *res;
+
+ res = nl80211_get_scan_results(drv);
+ if (res)
+ wpa_driver_nl80211_check_bss_status(drv, res);
+ return res;
+}
+
+
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+ struct wpa_scan_results *res;
+ size_t i;
+
+ res = nl80211_get_scan_results(drv);
+ if (res == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+ for (i = 0; i < res->num; i++) {
+ struct wpa_scan_res *r = res->res[i];
+ wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
+ (int) i, (int) res->num, MAC2STR(r->bssid),
+ r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+ }
+
+ wpa_scan_results_free(res);
+}
diff --git a/contrib/wpa/src/drivers/driver_openbsd.c b/contrib/wpa/src/drivers/driver_openbsd.c
new file mode 100644
index 0000000..e94eda0
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_openbsd.c
@@ -0,0 +1,136 @@
+/*
+ * Driver interaction with OpenBSD net80211 layer
+ * Copyright (c) 2013, Mark Kettenis
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+
+struct openbsd_driver_data {
+ char ifname[IFNAMSIZ + 1];
+ void *ctx;
+
+ int sock; /* open socket for 802.11 ioctls */
+};
+
+
+static int
+wpa_driver_openbsd_get_ssid(void *priv, u8 *ssid)
+{
+ struct openbsd_driver_data *drv = priv;
+ struct ieee80211_nwid nwid;
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *)&nwid;
+ if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+ nwid.i_len > IEEE80211_NWID_LEN)
+ return -1;
+
+ os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
+ return nwid.i_len;
+}
+
+static int
+wpa_driver_openbsd_get_bssid(void *priv, u8 *bssid)
+{
+ struct openbsd_driver_data *drv = priv;
+ struct ieee80211_bssid id;
+
+ os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name));
+ if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0)
+ return -1;
+
+ os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN);
+ return 0;
+}
+
+
+static int
+wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ return 0;
+}
+
+
+static int
+wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+ const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key, size_t key_len)
+{
+ struct openbsd_driver_data *drv = priv;
+ struct ieee80211_keyavail keyavail;
+
+ if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+ return -1;
+
+ memset(&keyavail, 0, sizeof(keyavail));
+ os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
+ if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
+ return -1;
+ memcpy(keyavail.i_key, key, key_len);
+
+ if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
+ return -1;
+
+ return 0;
+}
+
+static void *
+wpa_driver_openbsd_init(void *ctx, const char *ifname)
+{
+ struct openbsd_driver_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0)
+ goto fail;
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ return drv;
+
+fail:
+ os_free(drv);
+ return NULL;
+}
+
+
+static void
+wpa_driver_openbsd_deinit(void *priv)
+{
+ struct openbsd_driver_data *drv = priv;
+
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_openbsd_ops = {
+ .name = "openbsd",
+ .desc = "OpenBSD 802.11 support",
+ .get_ssid = wpa_driver_openbsd_get_ssid,
+ .get_bssid = wpa_driver_openbsd_get_bssid,
+ .get_capa = wpa_driver_openbsd_get_capa,
+ .set_key = wpa_driver_openbsd_set_key,
+ .init = wpa_driver_openbsd_init,
+ .deinit = wpa_driver_openbsd_deinit,
+};
diff --git a/contrib/wpa/src/drivers/driver_privsep.c b/contrib/wpa/src/drivers/driver_privsep.c
index ed88e71..de23fbd 100644
--- a/contrib/wpa/src/drivers/driver_privsep.c
+++ b/contrib/wpa/src/drivers/driver_privsep.c
@@ -35,7 +35,7 @@ static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
(struct sockaddr *) &drv->priv_addr,
sizeof(drv->priv_addr));
if (res < 0)
- perror("sendto");
+ wpa_printf(MSG_ERROR, "sendto: %s", strerror(errno));
return res < 0 ? -1 : 0;
}
@@ -59,7 +59,8 @@ static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
msg.msg_namelen = sizeof(drv->priv_addr);
if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
- perror("sendmsg(cmd_socket)");
+ wpa_printf(MSG_ERROR, "sendmsg(cmd_socket): %s",
+ strerror(errno));
return -1;
}
@@ -74,14 +75,15 @@ static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
tv.tv_usec = 0;
res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno != EINTR) {
- perror("select");
+ wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
return -1;
}
if (FD_ISSET(drv->cmd_socket, &rfds)) {
res = recv(drv->cmd_socket, reply, *reply_len, 0);
if (res < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s",
+ strerror(errno));
return -1;
}
*reply_len = res;
@@ -228,7 +230,7 @@ static int wpa_driver_privsep_associate(
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
- __func__, priv, params->freq, params->pairwise_suite,
+ __func__, priv, params->freq.freq, params->pairwise_suite,
params->group_suite, params->key_mgmt_suite,
params->auth_alg, params->mode);
@@ -241,7 +243,9 @@ static int wpa_driver_privsep_associate(
os_memcpy(data->bssid, params->bssid, ETH_ALEN);
os_memcpy(data->ssid, params->ssid, params->ssid_len);
data->ssid_len = params->ssid_len;
- data->freq = params->freq;
+ data->hwmode = params->freq.mode;
+ data->freq = params->freq.freq;
+ data->channel = params->freq.channel;
data->pairwise_suite = params->pairwise_suite;
data->group_suite = params->group_suite;
data->key_mgmt_suite = params->key_mgmt_suite;
@@ -439,7 +443,8 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
res = recvfrom(sock, buf, buflen, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(priv_socket)");
+ wpa_printf(MSG_ERROR, "recvfrom(priv_socket): %s",
+ strerror(errno));
os_free(buf);
return;
}
@@ -629,7 +634,7 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->priv_socket < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_socket_path);
drv->own_socket_path = NULL;
return -1;
@@ -640,7 +645,9 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("privsep-set-params priv-sock: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "privsep-set-params priv-sock: bind(PF_UNIX): %s",
+ strerror(errno));
close(drv->priv_socket);
drv->priv_socket = -1;
unlink(drv->own_socket_path);
@@ -654,7 +661,7 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->cmd_socket < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_cmd_path);
drv->own_cmd_path = NULL;
return -1;
@@ -665,7 +672,9 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
- perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "privsep-set-params cmd-sock: bind(PF_UNIX): %s",
+ strerror(errno));
close(drv->cmd_socket);
drv->cmd_socket = -1;
unlink(drv->own_cmd_path);
diff --git a/contrib/wpa/src/drivers/driver_wired.c b/contrib/wpa/src/drivers/driver_wired.c
index 48ae011..960bd89 100644
--- a/contrib/wpa/src/drivers/driver_wired.c
+++ b/contrib/wpa/src/drivers/driver_wired.c
@@ -100,7 +100,7 @@ static int wired_multicast_membership(int sock, int ifindex,
if (setsockopt(sock, SOL_PACKET,
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
- perror("setsockopt");
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
return -1;
}
return 0;
@@ -158,7 +158,7 @@ static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -176,7 +176,7 @@ static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -209,19 +209,21 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
if (drv->sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ 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)) {
- printf("Could not register read socket\n");
+ 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) {
- perror("ioctl(SIOCGIFINDEX)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
return -1;
}
@@ -232,7 +234,7 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
addr.sll_ifindex);
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -247,26 +249,28 @@ 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) {
- perror("ioctl(SIOCGIFHWADDR)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
+ strerror(errno));
return -1;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- printf("Invalid HW-addr family 0x%04x\n",
- ifr.ifr_hwaddr.sa_family);
+ wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
+ ifr.ifr_hwaddr.sa_family);
return -1;
}
os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
/* setup dhcp listen socket for sta detection */
if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- perror("socket call failed for dhcp");
+ wpa_printf(MSG_ERROR, "socket call failed for dhcp: %s",
+ strerror(errno));
return -1;
}
if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
NULL)) {
- printf("Could not register read socket\n");
+ wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
@@ -277,12 +281,14 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
sizeof(n)) == -1) {
- perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+ wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_REUSEADDR]: %s",
+ strerror(errno));
return -1;
}
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
sizeof(n)) == -1) {
- perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+ wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_BROADCAST]: %s",
+ strerror(errno));
return -1;
}
@@ -290,13 +296,15 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
(char *) &ifr, sizeof(ifr)) < 0) {
- perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
+ wpa_printf(MSG_ERROR,
+ "setsockopt[SOL_SOCKET,SO_BINDTODEVICE]: %s",
+ strerror(errno));
return -1;
}
if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
sizeof(struct sockaddr)) == -1) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -320,8 +328,9 @@ static int wired_send_eapol(void *priv, const u8 *addr,
len = sizeof(*hdr) + data_len;
hdr = os_zalloc(len);
if (hdr == NULL) {
- printf("malloc() failed for wired_send_eapol(len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO,
+ "malloc() failed for wired_send_eapol(len=%lu)",
+ (unsigned long) len);
return -1;
}
@@ -337,9 +346,9 @@ static int wired_send_eapol(void *priv, const u8 *addr,
os_free(hdr);
if (res < 0) {
- perror("wired_send_eapol: send");
- printf("wired_send_eapol - packet len: %lu - failed\n",
- (unsigned long) len);
+ wpa_printf(MSG_ERROR,
+ "wired_send_eapol - packet len: %lu - failed: send: %s",
+ (unsigned long) len, strerror(errno));
}
return res;
@@ -353,7 +362,8 @@ static void * wired_driver_hapd_init(struct hostapd_data *hapd,
drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
if (drv == NULL) {
- printf("Could not allocate memory for wired driver data\n");
+ wpa_printf(MSG_INFO,
+ "Could not allocate memory for wired driver data");
return NULL;
}
@@ -374,11 +384,15 @@ static void wired_driver_hapd_deinit(void *priv)
{
struct wpa_driver_wired_data *drv = priv;
- if (drv->sock >= 0)
+ if (drv->sock >= 0) {
+ eloop_unregister_read_sock(drv->sock);
close(drv->sock);
+ }
- if (drv->dhcp_sock >= 0)
+ if (drv->dhcp_sock >= 0) {
+ eloop_unregister_read_sock(drv->dhcp_sock);
close(drv->dhcp_sock);
+ }
os_free(drv);
}
@@ -414,14 +428,15 @@ static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ 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) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -438,7 +453,7 @@ static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -446,7 +461,8 @@ static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags & 0xffff;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -454,6 +470,7 @@ static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
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;
@@ -461,23 +478,26 @@ static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status)
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ 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) {
- perror("ioctl[SIOCGIFMEDIA]");
+ 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);
+ *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)
{
@@ -490,7 +510,7 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -524,7 +544,8 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -547,7 +568,7 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
#ifdef __linux__
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->pf_sock < 0)
- perror("socket(PF_PACKET)");
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
#else /* __linux__ */
drv->pf_sock = -1;
#endif /* __linux__ */
@@ -587,11 +608,16 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
__func__);
drv->iff_allmulti = 1;
}
- 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);
+#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;
}
diff --git a/contrib/wpa/src/drivers/drivers.c b/contrib/wpa/src/drivers/drivers.c
index a92eddf..f0c3bb3 100644
--- a/contrib/wpa/src/drivers/drivers.c
+++ b/contrib/wpa/src/drivers/drivers.c
@@ -6,8 +6,9 @@
* See README for more details.
*/
-#include "includes.h"
-
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "driver.h"
#ifdef CONFIG_DRIVER_WEXT
extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
@@ -18,21 +19,22 @@ extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
#ifdef CONFIG_DRIVER_HOSTAP
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
-extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
-#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
+#endif /* CONFIG_DRIVER_OPENBSD */
#ifdef CONFIG_DRIVER_NDIS
extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
#endif /* CONFIG_DRIVER_NDIS */
#ifdef CONFIG_DRIVER_WIRED
extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
#endif /* CONFIG_DRIVER_WIRED */
-#ifdef CONFIG_DRIVER_TEST
-extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
-#endif /* CONFIG_DRIVER_TEST */
+#ifdef CONFIG_DRIVER_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;
@@ -47,30 +49,30 @@ extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
struct wpa_driver_ops *wpa_drivers[] =
{
-#ifdef CONFIG_DRIVER_WEXT
- &wpa_driver_wext_ops,
-#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_NL80211
&wpa_driver_nl80211_ops,
#endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_WEXT
+ &wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
- &wpa_driver_madwifi_ops,
-#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+ &wpa_driver_openbsd_ops,
+#endif /* CONFIG_DRIVER_OPENBSD */
#ifdef CONFIG_DRIVER_NDIS
&wpa_driver_ndis_ops,
#endif /* CONFIG_DRIVER_NDIS */
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
-#ifdef CONFIG_DRIVER_TEST
- &wpa_driver_test_ops,
-#endif /* CONFIG_DRIVER_TEST */
+#ifdef CONFIG_DRIVER_MACSEC_QCA
+ &wpa_driver_macsec_qca_ops,
+#endif /* CONFIG_DRIVER_MACSEC_QCA */
#ifdef CONFIG_DRIVER_ROBOSWITCH
&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
diff --git a/contrib/wpa/src/drivers/linux_defines.h b/contrib/wpa/src/drivers/linux_defines.h
new file mode 100644
index 0000000..a107479
--- /dev/null
+++ b/contrib/wpa/src/drivers/linux_defines.h
@@ -0,0 +1,46 @@
+/*
+ * Linux defines for values that are not yet included in common C libraries
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_DEFINES_H
+#define LINUX_DEFINES_H
+
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+# define SO_WIFI_STATUS 0x0025
+# elif defined(__parisc__)
+# define SO_WIFI_STATUS 0x4022
+# else
+# define SO_WIFI_STATUS 41
+# endif
+
+# define SCM_WIFI_STATUS SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS 4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP 16
+#endif
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+#endif /* LINUX_DEFINES_H */
diff --git a/contrib/wpa/src/eap_common/eap_common.c b/contrib/wpa/src/eap_common/eap_common.c
index 7b077cb..1de1328 100644
--- a/contrib/wpa/src/eap_common/eap_common.c
+++ b/contrib/wpa/src/eap_common/eap_common.c
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -203,3 +203,86 @@ EapType eap_get_type(const struct wpabuf *msg)
return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
}
+
+
+#ifdef CONFIG_ERP
+int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
+ int stop_at_keyname)
+{
+ os_memset(tlvs, 0, sizeof(*tlvs));
+
+ while (pos < end) {
+ u8 tlv_type, tlv_len;
+
+ tlv_type = *pos++;
+ switch (tlv_type) {
+ case EAP_ERP_TV_RRK_LIFETIME:
+ case EAP_ERP_TV_RMSK_LIFETIME:
+ /* 4-octet TV */
+ if (pos + 4 > end) {
+ wpa_printf(MSG_DEBUG, "EAP: Too short TV");
+ return -1;
+ }
+ pos += 4;
+ break;
+ case EAP_ERP_TLV_DOMAIN_NAME:
+ case EAP_ERP_TLV_KEYNAME_NAI:
+ case EAP_ERP_TLV_CRYPTOSUITES:
+ case EAP_ERP_TLV_AUTHORIZATION_INDICATION:
+ case EAP_ERP_TLV_CALLED_STATION_ID:
+ case EAP_ERP_TLV_CALLING_STATION_ID:
+ case EAP_ERP_TLV_NAS_IDENTIFIER:
+ case EAP_ERP_TLV_NAS_IP_ADDRESS:
+ case EAP_ERP_TLV_NAS_IPV6_ADDRESS:
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "EAP: Too short TLV");
+ return -1;
+ }
+ tlv_len = *pos++;
+ if (tlv_len > (unsigned) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "EAP: Truncated TLV");
+ return -1;
+ }
+ if (tlv_type == EAP_ERP_TLV_KEYNAME_NAI) {
+ if (tlvs->keyname) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: More than one keyName-NAI");
+ return -1;
+ }
+ tlvs->keyname = pos;
+ tlvs->keyname_len = tlv_len;
+ if (stop_at_keyname)
+ return 0;
+ } else if (tlv_type == EAP_ERP_TLV_DOMAIN_NAME) {
+ tlvs->domain = pos;
+ tlvs->domain_len = tlv_len;
+ }
+ pos += tlv_len;
+ break;
+ default:
+ if (tlv_type >= 128 && tlv_type <= 191) {
+ /* Undefined TLV */
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too short TLV");
+ return -1;
+ }
+ tlv_len = *pos++;
+ if (tlv_len > (unsigned) (end - pos)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Truncated TLV");
+ return -1;
+ }
+ pos += tlv_len;
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "EAP: Unknown TV/TLV type %u",
+ tlv_type);
+ pos = end;
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_ERP */
diff --git a/contrib/wpa/src/eap_common/eap_common.h b/contrib/wpa/src/eap_common/eap_common.h
index 8850c1f..e62f167 100644
--- a/contrib/wpa/src/eap_common/eap_common.h
+++ b/contrib/wpa/src/eap_common/eap_common.h
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, 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,14 @@
#include "wpabuf.h"
+struct erp_tlvs {
+ const u8 *keyname;
+ const u8 *domain;
+
+ u8 keyname_len;
+ u8 domain_len;
+};
+
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
const u8 * eap_hdr_validate(int vendor, EapType eap_type,
const struct wpabuf *msg, size_t *plen);
@@ -19,5 +27,7 @@ struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
void eap_update_len(struct wpabuf *msg);
u8 eap_get_id(const struct wpabuf *msg);
EapType eap_get_type(const struct wpabuf *msg);
+int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
+ int stop_at_keyname);
#endif /* EAP_COMMON_H */
diff --git a/contrib/wpa/src/eap_common/eap_defs.h b/contrib/wpa/src/eap_common/eap_defs.h
index 0d247c4..54f26ca 100644
--- a/contrib/wpa/src/eap_common/eap_defs.h
+++ b/contrib/wpa/src/eap_common/eap_defs.h
@@ -1,6 +1,6 @@
/*
* EAP server/peer: Shared EAP definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,11 +27,39 @@ struct eap_hdr {
#endif /* _MSC_VER */
enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
- EAP_CODE_FAILURE = 4 };
+ EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 };
/* EAP Request and Response data begins with one octet Type. Success and
* Failure do not have additional data. */
+/* Type field in EAP-Initiate and EAP-Finish messages */
+enum eap_erp_type {
+ EAP_ERP_TYPE_REAUTH_START = 1,
+ EAP_ERP_TYPE_REAUTH = 2,
+};
+
+/* ERP TV/TLV types */
+enum eap_erp_tlv_type {
+ EAP_ERP_TLV_KEYNAME_NAI = 1,
+ EAP_ERP_TV_RRK_LIFETIME = 2,
+ EAP_ERP_TV_RMSK_LIFETIME = 3,
+ EAP_ERP_TLV_DOMAIN_NAME = 4,
+ EAP_ERP_TLV_CRYPTOSUITES = 5,
+ EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6,
+ EAP_ERP_TLV_CALLED_STATION_ID = 128,
+ EAP_ERP_TLV_CALLING_STATION_ID = 129,
+ EAP_ERP_TLV_NAS_IDENTIFIER = 130,
+ EAP_ERP_TLV_NAS_IP_ADDRESS = 131,
+ EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132,
+};
+
+/* ERP Cryptosuite */
+enum eap_erp_cryptosuite {
+ EAP_ERP_CS_HMAC_SHA256_64 = 1,
+ EAP_ERP_CS_HMAC_SHA256_128 = 2,
+ EAP_ERP_CS_HMAC_SHA256_256 = 3,
+};
+
/*
* EAP Method Types as allocated by IANA:
* http://www.iana.org/assignments/eap-numbers
@@ -63,6 +91,7 @@ typedef enum {
EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
EAP_TYPE_GPSK = 51 /* RFC 5433 */,
EAP_TYPE_PWD = 52 /* RFC 5931 */,
+ EAP_TYPE_EKE = 53 /* RFC 6124 */,
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
} EapType;
@@ -71,14 +100,19 @@ typedef enum {
enum {
EAP_VENDOR_IETF = 0,
EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
- EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */,
- EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */
+ EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance (moved to WBA) */,
+ EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */,
+ EAP_VENDOR_WFA_NEW = 40808 /* Wi-Fi Alliance */
};
#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP
#define EAP_VENDOR_TYPE_UNAUTH_TLS 1
+#define EAP_VENDOR_WFA_UNAUTH_TLS 13
+
#define EAP_MSK_LEN 64
#define EAP_EMSK_LEN 64
+#define EAP_EMSK_NAME_LEN 8
+#define ERP_MAX_KEY_LEN 64
#endif /* EAP_DEFS_H */
diff --git a/contrib/wpa/src/eap_common/eap_eke_common.c b/contrib/wpa/src/eap_common/eap_eke_common.c
new file mode 100644
index 0000000..4dfdb3f
--- /dev/null
+++ b/contrib/wpa/src/eap_common/eap_eke_common.c
@@ -0,0 +1,768 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, 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/aes.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "eap_common/eap_defs.h"
+#include "eap_eke_common.h"
+
+
+static int eap_eke_dh_len(u8 group)
+{
+ switch (group) {
+ case EAP_EKE_DHGROUP_EKE_2:
+ return 128;
+ case EAP_EKE_DHGROUP_EKE_5:
+ return 192;
+ case EAP_EKE_DHGROUP_EKE_14:
+ return 256;
+ case EAP_EKE_DHGROUP_EKE_15:
+ return 384;
+ case EAP_EKE_DHGROUP_EKE_16:
+ return 512;
+ }
+
+ return -1;
+}
+
+
+static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
+{
+ int dhlen;
+
+ dhlen = eap_eke_dh_len(dhgroup);
+ if (dhlen < 0)
+ return -1;
+ if (encr != EAP_EKE_ENCR_AES128_CBC)
+ return -1;
+ return AES_BLOCK_SIZE + dhlen;
+}
+
+
+static const struct dh_group * eap_eke_dh_group(u8 group)
+{
+ switch (group) {
+ case EAP_EKE_DHGROUP_EKE_2:
+ return dh_groups_get(2);
+ case EAP_EKE_DHGROUP_EKE_5:
+ return dh_groups_get(5);
+ case EAP_EKE_DHGROUP_EKE_14:
+ return dh_groups_get(14);
+ case EAP_EKE_DHGROUP_EKE_15:
+ return dh_groups_get(15);
+ case EAP_EKE_DHGROUP_EKE_16:
+ return dh_groups_get(16);
+ }
+
+ return NULL;
+}
+
+
+static int eap_eke_dh_generator(u8 group)
+{
+ switch (group) {
+ case EAP_EKE_DHGROUP_EKE_2:
+ return 5;
+ case EAP_EKE_DHGROUP_EKE_5:
+ return 31;
+ case EAP_EKE_DHGROUP_EKE_14:
+ return 11;
+ case EAP_EKE_DHGROUP_EKE_15:
+ return 5;
+ case EAP_EKE_DHGROUP_EKE_16:
+ return 5;
+ }
+
+ return -1;
+}
+
+
+static int eap_eke_pnonce_len(u8 mac)
+{
+ int mac_len;
+
+ if (mac == EAP_EKE_MAC_HMAC_SHA1)
+ mac_len = SHA1_MAC_LEN;
+ else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+ mac_len = SHA256_MAC_LEN;
+ else
+ return -1;
+
+ return AES_BLOCK_SIZE + 16 + mac_len;
+}
+
+
+static int eap_eke_pnonce_ps_len(u8 mac)
+{
+ int mac_len;
+
+ if (mac == EAP_EKE_MAC_HMAC_SHA1)
+ mac_len = SHA1_MAC_LEN;
+ else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+ mac_len = SHA256_MAC_LEN;
+ else
+ return -1;
+
+ return AES_BLOCK_SIZE + 2 * 16 + mac_len;
+}
+
+
+static int eap_eke_prf_len(u8 prf)
+{
+ if (prf == EAP_EKE_PRF_HMAC_SHA1)
+ return 20;
+ if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+ return 32;
+ return -1;
+}
+
+
+static int eap_eke_nonce_len(u8 prf)
+{
+ int prf_len;
+
+ prf_len = eap_eke_prf_len(prf);
+ if (prf_len < 0)
+ return -1;
+
+ if (prf_len > 2 * 16)
+ return (prf_len + 1) / 2;
+
+ return 16;
+}
+
+
+static int eap_eke_auth_len(u8 prf)
+{
+ switch (prf) {
+ case EAP_EKE_PRF_HMAC_SHA1:
+ return SHA1_MAC_LEN;
+ case EAP_EKE_PRF_HMAC_SHA2_256:
+ return SHA256_MAC_LEN;
+ }
+
+ return -1;
+}
+
+
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
+{
+ int generator;
+ u8 gen;
+ const struct dh_group *dh;
+ size_t pub_len, i;
+
+ generator = eap_eke_dh_generator(group);
+ if (generator < 0 || generator > 255)
+ return -1;
+ gen = generator;
+
+ dh = eap_eke_dh_group(group);
+ if (dh == NULL)
+ return -1;
+
+ /* x = random number 2 .. p-1 */
+ if (random_get_bytes(ret_priv, dh->prime_len))
+ return -1;
+ if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ ret_priv[0] = 0;
+ }
+ for (i = 0; i < dh->prime_len - 1; i++) {
+ if (ret_priv[i])
+ break;
+ }
+ if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
+ ret_priv, dh->prime_len);
+
+ /* y = g ^ x (mod p) */
+ pub_len = dh->prime_len;
+ if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
+ dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
+ return -1;
+ if (pub_len < dh->prime_len) {
+ size_t pad = dh->prime_len - pub_len;
+ os_memmove(ret_pub + pad, ret_pub, pub_len);
+ os_memset(ret_pub, 0, pad);
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
+ ret_pub, dh->prime_len);
+
+ return 0;
+}
+
+
+static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, const u8 *data2, size_t data2_len,
+ u8 *res)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ size_t num_elem = 1;
+
+ addr[0] = data;
+ len[0] = data_len;
+ if (data2) {
+ num_elem++;
+ addr[1] = data2;
+ len[1] = data2_len;
+ }
+
+ if (prf == EAP_EKE_PRF_HMAC_SHA1)
+ return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
+ if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+ return hmac_sha256_vector(key, key_len, num_elem, addr, len,
+ res);
+ return -1;
+}
+
+
+static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *res, size_t len)
+{
+ u8 hash[SHA1_MAC_LEN];
+ u8 idx;
+ const u8 *addr[3];
+ size_t vlen[3];
+ int ret;
+
+ idx = 0;
+ addr[0] = hash;
+ vlen[0] = SHA1_MAC_LEN;
+ addr[1] = data;
+ vlen[1] = data_len;
+ addr[2] = &idx;
+ vlen[2] = 1;
+
+ while (len > 0) {
+ idx++;
+ if (idx == 1)
+ ret = hmac_sha1_vector(key, key_len, 2, &addr[1],
+ &vlen[1], hash);
+ else
+ ret = hmac_sha1_vector(key, key_len, 3, addr, vlen,
+ hash);
+ if (ret < 0)
+ return -1;
+ if (len > SHA1_MAC_LEN) {
+ os_memcpy(res, hash, SHA1_MAC_LEN);
+ res += SHA1_MAC_LEN;
+ len -= SHA1_MAC_LEN;
+ } else {
+ os_memcpy(res, hash, len);
+ len = 0;
+ }
+ }
+
+ return 0;
+}
+
+
+static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *res, size_t len)
+{
+ u8 hash[SHA256_MAC_LEN];
+ u8 idx;
+ const u8 *addr[3];
+ size_t vlen[3];
+ int ret;
+
+ idx = 0;
+ addr[0] = hash;
+ vlen[0] = SHA256_MAC_LEN;
+ addr[1] = data;
+ vlen[1] = data_len;
+ addr[2] = &idx;
+ vlen[2] = 1;
+
+ while (len > 0) {
+ idx++;
+ if (idx == 1)
+ ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
+ &vlen[1], hash);
+ else
+ ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
+ hash);
+ if (ret < 0)
+ return -1;
+ if (len > SHA256_MAC_LEN) {
+ os_memcpy(res, hash, SHA256_MAC_LEN);
+ res += SHA256_MAC_LEN;
+ len -= SHA256_MAC_LEN;
+ } else {
+ os_memcpy(res, hash, len);
+ len = 0;
+ }
+ }
+
+ return 0;
+}
+
+
+static int eap_eke_prfplus(u8 prf, const u8 *key, size_t key_len,
+ const u8 *data, size_t data_len, u8 *res, size_t len)
+{
+ if (prf == EAP_EKE_PRF_HMAC_SHA1)
+ return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res,
+ len);
+ if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+ return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
+ res, len);
+ return -1;
+}
+
+
+int eap_eke_derive_key(struct eap_eke_session *sess,
+ const u8 *password, size_t password_len,
+ const u8 *id_s, size_t id_s_len, const u8 *id_p,
+ size_t id_p_len, u8 *key)
+{
+ u8 zeros[EAP_EKE_MAX_HASH_LEN];
+ u8 temp[EAP_EKE_MAX_HASH_LEN];
+ size_t key_len = 16; /* Only AES-128-CBC is used here */
+ u8 *id;
+
+ /* temp = prf(0+, password) */
+ os_memset(zeros, 0, sess->prf_len);
+ if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
+ password, password_len, NULL, 0, temp) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
+ temp, sess->prf_len);
+
+ /* key = prf+(temp, ID_S | ID_P) */
+ id = os_malloc(id_s_len + id_p_len);
+ if (id == NULL)
+ return -1;
+ os_memcpy(id, id_s, id_s_len);
+ os_memcpy(id + id_s_len, id_p, id_p_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
+ id, id_s_len + id_p_len);
+ if (eap_eke_prfplus(sess->prf, temp, sess->prf_len,
+ id, id_s_len + id_p_len, key, key_len) < 0) {
+ os_free(id);
+ return -1;
+ }
+ os_free(id);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
+ key, key_len);
+
+ return 0;
+}
+
+
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+ u8 *ret_dhcomp)
+{
+ u8 pub[EAP_EKE_MAX_DH_LEN];
+ int dh_len;
+ u8 iv[AES_BLOCK_SIZE];
+
+ dh_len = eap_eke_dh_len(sess->dhgroup);
+ if (dh_len < 0)
+ return -1;
+
+ /*
+ * DHComponent = Encr(key, y)
+ *
+ * All defined DH groups use primes that have length devisible by 16, so
+ * no need to do extra padding for y (= pub).
+ */
+ if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+ return -1;
+ if (random_get_bytes(iv, AES_BLOCK_SIZE))
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
+ iv, AES_BLOCK_SIZE);
+ os_memcpy(pub, dhpub, dh_len);
+ if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
+ return -1;
+ os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
+ os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
+ ret_dhcomp, AES_BLOCK_SIZE + dh_len);
+
+ return 0;
+}
+
+
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+ const u8 *dhpriv, const u8 *peer_dhcomp)
+{
+ u8 zeros[EAP_EKE_MAX_HASH_LEN];
+ u8 peer_pub[EAP_EKE_MAX_DH_LEN];
+ u8 modexp[EAP_EKE_MAX_DH_LEN];
+ size_t len;
+ const struct dh_group *dh;
+
+ if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+ return -1;
+
+ dh = eap_eke_dh_group(sess->dhgroup);
+ if (dh == NULL)
+ return -1;
+
+ /* Decrypt peer DHComponent */
+ os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
+ if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey",
+ peer_pub, dh->prime_len);
+
+ /* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
+ len = dh->prime_len;
+ if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
+ dh->prime, dh->prime_len, modexp, &len) < 0)
+ return -1;
+ if (len < dh->prime_len) {
+ size_t pad = dh->prime_len - len;
+ os_memmove(modexp + pad, modexp, len);
+ os_memset(modexp, 0, pad);
+ }
+
+ os_memset(zeros, 0, sess->auth_len);
+ if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
+ NULL, 0, sess->shared_secret) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
+ sess->shared_secret, sess->auth_len);
+
+ return 0;
+}
+
+
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+ const u8 *id_s, size_t id_s_len,
+ const u8 *id_p, size_t id_p_len)
+{
+ u8 buf[EAP_EKE_MAX_KE_LEN + EAP_EKE_MAX_KI_LEN];
+ size_t ke_len, ki_len;
+ u8 *data;
+ size_t data_len;
+ const char *label = "EAP-EKE Keys";
+ size_t label_len;
+
+ /*
+ * Ke | Ki = prf+(SharedSecret, "EAP-EKE Keys" | ID_S | ID_P)
+ * Ke = encryption key
+ * Ki = integrity protection key
+ * Length of each key depends on the selected algorithms.
+ */
+
+ if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+ ke_len = 16;
+ else
+ return -1;
+
+ if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+ ki_len = 20;
+ else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+ ki_len = 32;
+ else
+ return -1;
+
+ label_len = os_strlen(label);
+ data_len = label_len + id_s_len + id_p_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ os_memcpy(data, label, label_len);
+ os_memcpy(data + label_len, id_s, id_s_len);
+ os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
+ if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+ data, data_len, buf, ke_len + ki_len) < 0) {
+ os_free(data);
+ return -1;
+ }
+
+ os_memcpy(sess->ke, buf, ke_len);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
+ os_memcpy(sess->ki, buf + ke_len, ki_len);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
+
+ os_free(data);
+ return 0;
+}
+
+
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+ const u8 *id_s, size_t id_s_len,
+ const u8 *id_p, size_t id_p_len,
+ const u8 *nonce_p, const u8 *nonce_s)
+{
+ u8 *data, *pos;
+ size_t data_len;
+ const char *label = "EAP-EKE Ka";
+ size_t label_len;
+
+ /*
+ * Ka = prf+(SharedSecret, "EAP-EKE Ka" | ID_S | ID_P | Nonce_P |
+ * Nonce_S)
+ * Ka = authentication key
+ * Length of the key depends on the selected algorithms.
+ */
+
+ label_len = os_strlen(label);
+ data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ os_memcpy(pos, label, label_len);
+ pos += label_len;
+ os_memcpy(pos, id_s, id_s_len);
+ pos += id_s_len;
+ os_memcpy(pos, id_p, id_p_len);
+ pos += id_p_len;
+ os_memcpy(pos, nonce_p, sess->nonce_len);
+ pos += sess->nonce_len;
+ os_memcpy(pos, nonce_s, sess->nonce_len);
+ if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+ data, data_len, sess->ka, sess->prf_len) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
+
+ return 0;
+}
+
+
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+ const u8 *id_s, size_t id_s_len,
+ const u8 *id_p, size_t id_p_len,
+ const u8 *nonce_p, const u8 *nonce_s,
+ u8 *msk, u8 *emsk)
+{
+ u8 *data, *pos;
+ size_t data_len;
+ const char *label = "EAP-EKE Exported Keys";
+ size_t label_len;
+ u8 buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+ /*
+ * MSK | EMSK = prf+(SharedSecret, "EAP-EKE Exported Keys" | ID_S |
+ * ID_P | Nonce_P | Nonce_S)
+ */
+
+ label_len = os_strlen(label);
+ data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ os_memcpy(pos, label, label_len);
+ pos += label_len;
+ os_memcpy(pos, id_s, id_s_len);
+ pos += id_s_len;
+ os_memcpy(pos, id_p, id_p_len);
+ pos += id_p_len;
+ os_memcpy(pos, nonce_p, sess->nonce_len);
+ pos += sess->nonce_len;
+ os_memcpy(pos, nonce_s, sess->nonce_len);
+ if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+ data, data_len, buf, EAP_MSK_LEN + EAP_EMSK_LEN) <
+ 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+
+ os_memcpy(msk, buf, EAP_MSK_LEN);
+ os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+ os_memset(buf, 0, sizeof(buf));
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
+
+ return 0;
+}
+
+
+static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
+ u8 *res)
+{
+ if (mac == EAP_EKE_MAC_HMAC_SHA1)
+ return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
+ if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+ return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
+ return -1;
+}
+
+
+int eap_eke_prot(struct eap_eke_session *sess,
+ const u8 *data, size_t data_len,
+ u8 *prot, size_t *prot_len)
+{
+ size_t block_size, icv_len, pad;
+ u8 *pos, *iv, *e;
+
+ if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+ block_size = AES_BLOCK_SIZE;
+ else
+ return -1;
+
+ if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+ icv_len = SHA1_MAC_LEN;
+ else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+ icv_len = SHA256_MAC_LEN;
+ else
+ return -1;
+
+ pad = data_len % block_size;
+ if (pad)
+ pad = block_size - pad;
+
+ if (*prot_len < block_size + data_len + pad + icv_len) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+ }
+ pos = prot;
+
+ if (random_get_bytes(pos, block_size))
+ return -1;
+ iv = pos;
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
+ pos += block_size;
+
+ e = pos;
+ os_memcpy(pos, data, data_len);
+ pos += data_len;
+ if (pad) {
+ if (random_get_bytes(pos, pad))
+ return -1;
+ pos += pad;
+ }
+
+ if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
+ return -1;
+
+ if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+ return -1;
+ pos += icv_len;
+
+ *prot_len = pos - prot;
+ return 0;
+}
+
+
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+ const u8 *prot, size_t prot_len,
+ u8 *data, size_t *data_len)
+{
+ size_t block_size, icv_len;
+ u8 icv[EAP_EKE_MAX_HASH_LEN];
+
+ if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+ block_size = AES_BLOCK_SIZE;
+ else
+ return -1;
+
+ if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+ icv_len = SHA1_MAC_LEN;
+ else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+ icv_len = SHA256_MAC_LEN;
+ else
+ return -1;
+
+ if (prot_len < 2 * block_size + icv_len)
+ return -1;
+ if ((prot_len - icv_len) % block_size)
+ return -1;
+
+ if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
+ prot_len - block_size - icv_len, icv) < 0)
+ return -1;
+ if (os_memcmp_const(icv, prot + prot_len - icv_len, icv_len) != 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
+ return -1;
+ }
+
+ if (*data_len < prot_len - block_size - icv_len) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data");
+ return -1;
+ }
+
+ *data_len = prot_len - block_size - icv_len;
+ os_memcpy(data, prot + block_size, *data_len);
+ if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
+ data, *data_len);
+
+ return 0;
+}
+
+
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+ const struct wpabuf *msgs, u8 *auth)
+{
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
+ sess->ka, sess->auth_len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
+ return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
+ (const u8 *) label, os_strlen(label),
+ wpabuf_head(msgs), wpabuf_len(msgs), auth);
+}
+
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+ u8 prf, u8 mac)
+{
+ sess->dhgroup = dhgroup;
+ sess->encr = encr;
+ sess->prf = prf;
+ sess->mac = mac;
+
+ sess->prf_len = eap_eke_prf_len(prf);
+ if (sess->prf_len < 0)
+ return -1;
+ sess->nonce_len = eap_eke_nonce_len(prf);
+ if (sess->nonce_len < 0)
+ return -1;
+ sess->auth_len = eap_eke_auth_len(prf);
+ if (sess->auth_len < 0)
+ return -1;
+ sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
+ if (sess->dhcomp_len < 0)
+ return -1;
+ sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
+ if (sess->pnonce_len < 0)
+ return -1;
+ sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
+ if (sess->pnonce_ps_len < 0)
+ return -1;
+
+ return 0;
+}
+
+
+void eap_eke_session_clean(struct eap_eke_session *sess)
+{
+ os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
+ os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
+ os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
+ os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
+}
diff --git a/contrib/wpa/src/eap_common/eap_eke_common.h b/contrib/wpa/src/eap_common/eap_eke_common.h
new file mode 100644
index 0000000..a4c0422
--- /dev/null
+++ b/contrib/wpa/src/eap_common/eap_eke_common.h
@@ -0,0 +1,114 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_EKE_COMMON_H
+#define EAP_EKE_COMMON_H
+
+/* EKE Exchange */
+#define EAP_EKE_ID 1
+#define EAP_EKE_COMMIT 2
+#define EAP_EKE_CONFIRM 3
+#define EAP_EKE_FAILURE 4
+
+/* Diffie-Hellman Group Registry */
+#define EAP_EKE_DHGROUP_EKE_2 1
+#define EAP_EKE_DHGROUP_EKE_5 2
+#define EAP_EKE_DHGROUP_EKE_14 3 /* mandatory to implement */
+#define EAP_EKE_DHGROUP_EKE_15 4
+#define EAP_EKE_DHGROUP_EKE_16 5
+
+/* Encryption Algorithm Registry */
+#define EAP_EKE_ENCR_AES128_CBC 1 /* mandatory to implement */
+
+/* Pseudo Random Function Registry */
+#define EAP_EKE_PRF_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_PRF_HMAC_SHA2_256 2
+
+/* Keyed Message Digest (MAC) Registry */
+#define EAP_EKE_MAC_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_MAC_HMAC_SHA2_256 2
+
+/* Identity Type Registry */
+#define EAP_EKE_ID_OPAQUE 1
+#define EAP_EKE_ID_NAI 2
+#define EAP_EKE_ID_IPv4 3
+#define EAP_EKE_ID_IPv6 4
+#define EAP_EKE_ID_FQDN 5
+#define EAP_EKE_ID_DN 6
+
+/* Failure-Code */
+#define EAP_EKE_FAIL_NO_ERROR 1
+#define EAP_EKE_FAIL_PROTO_ERROR 2
+#define EAP_EKE_FAIL_PASSWD_NOT_FOUND 3
+#define EAP_EKE_FAIL_AUTHENTICATION_FAIL 4
+#define EAP_EKE_FAIL_AUTHORIZATION_FAIL 5
+#define EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN 6
+#define EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR 0xffffffff
+
+#define EAP_EKE_MAX_DH_LEN 512
+#define EAP_EKE_MAX_HASH_LEN 32
+#define EAP_EKE_MAX_KEY_LEN 16
+#define EAP_EKE_MAX_KE_LEN 16
+#define EAP_EKE_MAX_KI_LEN 32
+#define EAP_EKE_MAX_KA_LEN 32
+#define EAP_EKE_MAX_NONCE_LEN 16
+
+struct eap_eke_session {
+ /* Selected proposal */
+ u8 dhgroup;
+ u8 encr;
+ u8 prf;
+ u8 mac;
+
+ u8 shared_secret[EAP_EKE_MAX_HASH_LEN];
+ u8 ke[EAP_EKE_MAX_KE_LEN];
+ u8 ki[EAP_EKE_MAX_KI_LEN];
+ u8 ka[EAP_EKE_MAX_KA_LEN];
+
+ int prf_len;
+ int nonce_len;
+ int auth_len;
+ int dhcomp_len;
+ int pnonce_len;
+ int pnonce_ps_len;
+};
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+ u8 prf, u8 mac);
+void eap_eke_session_clean(struct eap_eke_session *sess);
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub);
+int eap_eke_derive_key(struct eap_eke_session *sess,
+ const u8 *password, size_t password_len,
+ const u8 *id_s, size_t id_s_len, const u8 *id_p,
+ size_t id_p_len, u8 *key);
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+ u8 *ret_dhcomp);
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+ const u8 *dhpriv, const u8 *peer_dhcomp);
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+ const u8 *id_s, size_t id_s_len,
+ const u8 *id_p, size_t id_p_len);
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+ const u8 *id_s, size_t id_s_len,
+ const u8 *id_p, size_t id_p_len,
+ const u8 *nonce_p, const u8 *nonce_s);
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+ const u8 *id_s, size_t id_s_len,
+ const u8 *id_p, size_t id_p_len,
+ const u8 *nonce_p, const u8 *nonce_s,
+ u8 *msk, u8 *emsk);
+int eap_eke_prot(struct eap_eke_session *sess,
+ const u8 *data, size_t data_len,
+ u8 *prot, size_t *prot_len);
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+ const u8 *prot, size_t prot_len,
+ u8 *data, size_t *data_len);
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+ const struct wpabuf *msgs, u8 *auth);
+
+#endif /* EAP_EKE_COMMON_H */
diff --git a/contrib/wpa/src/eap_common/eap_fast_common.c b/contrib/wpa/src/eap_common/eap_fast_common.c
index 04b987d..fceb1b0 100644
--- a/contrib/wpa/src/eap_common/eap_fast_common.c
+++ b/contrib/wpa/src/eap_common/eap_fast_common.c
@@ -174,7 +174,7 @@ void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
- int tlv_type, u8 *pos, int len)
+ int tlv_type, u8 *pos, size_t len)
{
switch (tlv_type) {
case EAP_TLV_EAP_PAYLOAD_TLV:
diff --git a/contrib/wpa/src/eap_common/eap_fast_common.h b/contrib/wpa/src/eap_common/eap_fast_common.h
index 8955617..d59a845 100644
--- a/contrib/wpa/src/eap_common/eap_fast_common.h
+++ b/contrib/wpa/src/eap_common/eap_fast_common.h
@@ -102,6 +102,6 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
- int tlv_type, u8 *pos, int len);
+ int tlv_type, u8 *pos, size_t len);
#endif /* EAP_FAST_H */
diff --git a/contrib/wpa/src/eap_common/eap_gpsk_common.c b/contrib/wpa/src/eap_common/eap_gpsk_common.c
index 7d106dd..8c7ae27 100644
--- a/contrib/wpa/src/eap_common/eap_gpsk_common.c
+++ b/contrib/wpa/src/eap_common/eap_gpsk_common.c
@@ -284,7 +284,6 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
u8 *pk, size_t *pk_len)
{
u8 *seed, *pos;
- size_t seed_len;
int ret;
wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
@@ -296,8 +295,7 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
/* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */
- seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
- seed = os_malloc(seed_len);
+ seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len);
if (seed == NULL) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
"for key derivation");
@@ -313,17 +311,18 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
pos += EAP_GPSK_RAND_LEN;
os_memcpy(pos, id_server, id_server_len);
pos += id_server_len;
- wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed);
switch (specifier) {
case EAP_GPSK_CIPHER_AES:
- ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
+ ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, pos - seed,
msk, emsk, sk, sk_len,
pk, pk_len);
break;
#ifdef EAP_GPSK_SHA256
case EAP_GPSK_CIPHER_SHA256:
- ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
+ ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed,
+ pos - seed,
msk, emsk, sk, sk_len);
break;
#endif /* EAP_GPSK_SHA256 */
@@ -340,6 +339,139 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
}
+static int eap_gpsk_derive_mid_helper(u32 csuite_specifier,
+ u8 *kdf_out, size_t kdf_out_len,
+ const u8 *psk, const u8 *seed,
+ size_t seed_len, u8 method_type)
+{
+ u8 *pos, *data;
+ size_t data_len;
+ int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
+ u8 *buf, size_t len);
+
+ gkdf = NULL;
+ switch (csuite_specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ gkdf = eap_gpsk_gkdf_cmac;
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ gkdf = eap_gpsk_gkdf_sha256;
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in "
+ "Session-Id derivation", csuite_specifier);
+ return -1;
+ }
+
+#define SID_LABEL "Method ID"
+ /* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */
+ data_len = strlen(SID_LABEL) + 1 + 6 + seed_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ os_memcpy(pos, SID_LABEL, strlen(SID_LABEL));
+ pos += strlen(SID_LABEL);
+#undef SID_LABEL
+ os_memcpy(pos, &method_type, 1);
+ pos += 1;
+ WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
+ pos += 4;
+ WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
+ pos += 2;
+ os_memcpy(pos, seed, seed_len); /* inputString */
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation",
+ data, data_len);
+
+ if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len);
+
+ return 0;
+}
+
+
+/**
+ * eap_gpsk_session_id - Derive EAP-GPSK Session ID
+ * @psk: Pre-shared key
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_peer: 32-byte RAND_Peer
+ * @rand_server: 32-byte RAND_Server
+ * @id_peer: ID_Peer
+ * @id_peer_len: Length of ID_Peer
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @method_type: EAP Authentication Method Type
+ * @sid: Buffer for 17-byte Session ID
+ * @sid_len: Buffer for returning length of Session ID
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_peer, const u8 *rand_server,
+ const u8 *id_peer, size_t id_peer_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 method_type, u8 *sid, size_t *sid_len)
+{
+ u8 *seed, *pos;
+ u8 kdf_out[16];
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)",
+ vendor, specifier);
+
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+ /*
+ * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
+ * (= seed)
+ * KS = 16, CSuite_Sel = 0x00000000 0x0001
+ * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+ * CSuite_Sel || inputString)
+ */
+ seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len);
+ if (seed == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+ "for Session-Id derivation");
+ return -1;
+ }
+
+ pos = seed;
+ os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_peer, id_peer_len);
+ pos += id_peer_len;
+ os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_server, id_server_len);
+ pos += id_server_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed);
+
+ ret = eap_gpsk_derive_mid_helper(specifier,
+ kdf_out, sizeof(kdf_out),
+ psk, seed, pos - seed,
+ method_type);
+
+ sid[0] = method_type;
+ os_memcpy(sid + 1, kdf_out, sizeof(kdf_out));
+ *sid_len = 1 + sizeof(kdf_out);
+
+ os_free(seed);
+
+ return ret;
+}
+
+
/**
* eap_gpsk_mic_len - Get the length of the MIC
* @vendor: CSuite/Vendor
diff --git a/contrib/wpa/src/eap_common/eap_gpsk_common.h b/contrib/wpa/src/eap_common/eap_gpsk_common.h
index e3d2b6b..fbcd547 100644
--- a/contrib/wpa/src/eap_common/eap_gpsk_common.h
+++ b/contrib/wpa/src/eap_common/eap_gpsk_common.h
@@ -53,6 +53,12 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
const u8 *id_server, size_t id_server_len,
u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
u8 *pk, size_t *pk_len);
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_peer, const u8 *rand_server,
+ const u8 *id_peer, size_t id_peer_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 method_type, u8 *sid, size_t *sid_len);
size_t eap_gpsk_mic_len(int vendor, int specifier);
int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
int specifier, const u8 *data, size_t len, u8 *mic);
diff --git a/contrib/wpa/src/eap_common/eap_ikev2_common.c b/contrib/wpa/src/eap_common/eap_ikev2_common.c
index 6095fd8..585c79c 100644
--- a/contrib/wpa/src/eap_common/eap_ikev2_common.c
+++ b/contrib/wpa/src/eap_common/eap_ikev2_common.c
@@ -52,22 +52,12 @@ struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
{
struct wpabuf *msg;
-#ifdef CCNS_PL
- msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
- if (msg == NULL) {
- wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
- "for fragment ack");
- return NULL;
- }
- wpabuf_put_u8(msg, 0); /* Flags */
-#else /* CCNS_PL */
msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
if (msg == NULL) {
wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
"for fragment ack");
return NULL;
}
-#endif /* CCNS_PL */
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
@@ -110,7 +100,7 @@ int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
return -1;
}
- if (os_memcmp(icv, end - icv_len, icv_len) != 0) {
+ if (os_memcmp_const(icv, end - icv_len, icv_len) != 0) {
wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
icv, icv_len);
diff --git a/contrib/wpa/src/eap_common/eap_ikev2_common.h b/contrib/wpa/src/eap_common/eap_ikev2_common.h
index 329ccc4..e7502d7 100644
--- a/contrib/wpa/src/eap_common/eap_ikev2_common.h
+++ b/contrib/wpa/src/eap_common/eap_ikev2_common.h
@@ -9,16 +9,9 @@
#ifndef EAP_IKEV2_COMMON_H
#define EAP_IKEV2_COMMON_H
-#ifdef CCNS_PL
-/* incorrect bit order */
-#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01
-#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02
-#define IKEV2_FLAGS_ICV_INCLUDED 0x04
-#else /* CCNS_PL */
#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80
#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40
#define IKEV2_FLAGS_ICV_INCLUDED 0x20
-#endif /* CCNS_PL */
#define IKEV2_FRAGMENT_SIZE 1400
diff --git a/contrib/wpa/src/eap_common/eap_pax_common.c b/contrib/wpa/src/eap_common/eap_pax_common.c
index b3bbacc..0e80ef5 100644
--- a/contrib/wpa/src/eap_common/eap_pax_common.c
+++ b/contrib/wpa/src/eap_common/eap_pax_common.c
@@ -121,10 +121,11 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
* @mk: Buffer for the derived Master Key
* @ck: Buffer for the derived Confirmation Key
* @ick: Buffer for the derived Integrity Check Key
+ * @mid: Buffer for the derived Method ID
* Returns: 0 on success, -1 on failure
*/
int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
- u8 *mk, u8 *ck, u8 *ick)
+ u8 *mk, u8 *ck, u8 *ick, u8 *mid)
{
wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
@@ -132,13 +133,16 @@ int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
- e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick) ||
+ eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Method ID",
+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MID_LEN, mid))
return -1;
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MID", mid, EAP_PAX_MID_LEN);
return 0;
}
diff --git a/contrib/wpa/src/eap_common/eap_pax_common.h b/contrib/wpa/src/eap_common/eap_pax_common.h
index fb03df2..e6cdf4d 100644
--- a/contrib/wpa/src/eap_common/eap_pax_common.h
+++ b/contrib/wpa/src/eap_common/eap_pax_common.h
@@ -74,6 +74,7 @@ enum {
#define EAP_PAX_MK_LEN 16
#define EAP_PAX_CK_LEN 16
#define EAP_PAX_ICK_LEN 16
+#define EAP_PAX_MID_LEN 16
int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
@@ -86,6 +87,6 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
const u8 *data3, size_t data3_len,
u8 *mac);
int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
- u8 *mk, u8 *ck, u8 *ick);
+ u8 *mk, u8 *ck, u8 *ick, u8 *mid);
#endif /* EAP_PAX_COMMON_H */
diff --git a/contrib/wpa/src/eap_common/eap_pwd_common.c b/contrib/wpa/src/eap_common/eap_pwd_common.c
index 7d6e6b8..631c363 100644
--- a/contrib/wpa/src/eap_common/eap_pwd_common.c
+++ b/contrib/wpa/src/eap_common/eap_pwd_common.c
@@ -106,9 +106,11 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
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;
@@ -263,18 +265,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
fail:
EC_GROUP_free(grp->group);
grp->group = NULL;
- EC_POINT_free(grp->pwe);
+ EC_POINT_clear_free(grp->pwe);
grp->pwe = NULL;
- BN_free(grp->order);
+ BN_clear_free(grp->order);
grp->order = NULL;
- BN_free(grp->prime);
+ BN_clear_free(grp->prime);
grp->prime = NULL;
ret = 1;
}
/* cleanliness and order.... */
- BN_free(cofactor);
- BN_free(x_candidate);
- BN_free(rnd);
+ BN_clear_free(cofactor);
+ BN_clear_free(x_candidate);
+ BN_clear_free(rnd);
os_free(prfbuf);
return ret;
@@ -284,11 +286,10 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
BIGNUM *peer_scalar, BIGNUM *server_scalar,
u8 *confirm_peer, u8 *confirm_server,
- u32 *ciphersuite, u8 *msk, u8 *emsk)
+ u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id)
{
struct crypto_hash *hash;
u8 mk[SHA256_MAC_LEN], *cruft;
- u8 session_id[SHA256_MAC_LEN + 1];
u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
int offset;
diff --git a/contrib/wpa/src/eap_common/eap_pwd_common.h b/contrib/wpa/src/eap_common/eap_pwd_common.h
index 816e58c..c54c441 100644
--- a/contrib/wpa/src/eap_common/eap_pwd_common.h
+++ b/contrib/wpa/src/eap_common/eap_pwd_common.h
@@ -59,7 +59,7 @@ struct eap_pwd_id {
int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *,
int, u8 *);
int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *,
- u8 *, u8 *, u32 *, u8 *, u8 *);
+ u8 *, u8 *, u32 *, u8 *, u8 *, u8 *);
struct crypto_hash * eap_pwd_h_init(void);
void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
diff --git a/contrib/wpa/src/eap_common/eap_sim_common.c b/contrib/wpa/src/eap_common/eap_sim_common.c
index e1773bf..2adc3b3 100644
--- a/contrib/wpa/src/eap_common/eap_sim_common.c
+++ b/contrib/wpa/src/eap_common/eap_sim_common.c
@@ -198,7 +198,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
hmac, EAP_SIM_MAC_LEN);
os_free(tmp);
- return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+ return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@@ -393,7 +393,7 @@ int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
hmac, EAP_SIM_MAC_LEN);
os_free(tmp);
- return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+ return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@@ -893,7 +893,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
"AT_KDF attributes - ignore this");
- continue;
+ break;
}
attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
attr->kdf_count++;
@@ -972,7 +972,6 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
struct eap_sim_msg {
struct wpabuf *buf;
size_t mac, iv, encr; /* index from buf */
- int type;
};
@@ -986,7 +985,6 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
if (msg == NULL)
return NULL;
- msg->type = type;
msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
if (msg->buf == NULL) {
os_free(msg);
@@ -1006,7 +1004,8 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
}
-struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
+ const u8 *k_aut,
const u8 *extra, size_t extra_len)
{
struct eap_hdr *eap;
@@ -1019,7 +1018,7 @@ struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
eap->length = host_to_be16(wpabuf_len(msg->buf));
#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
- if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
+ if (k_aut && msg->mac && type == EAP_TYPE_AKA_PRIME) {
eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
wpabuf_len(msg->buf),
(u8 *) wpabuf_mhead(msg->buf) +
diff --git a/contrib/wpa/src/eap_common/eap_sim_common.h b/contrib/wpa/src/eap_common/eap_sim_common.h
index 6021bd2..daeb0e2 100644
--- a/contrib/wpa/src/eap_common/eap_sim_common.h
+++ b/contrib/wpa/src/eap_common/eap_sim_common.h
@@ -211,7 +211,8 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
struct eap_sim_msg;
struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype);
-struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
+ const u8 *k_aut,
const u8 *extra, size_t extra_len);
void eap_sim_msg_free(struct eap_sim_msg *msg);
u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
diff --git a/contrib/wpa/src/eap_common/ikev2_common.c b/contrib/wpa/src/eap_common/ikev2_common.c
index 376fcad..4f9e64e 100644
--- a/contrib/wpa/src/eap_common/ikev2_common.c
+++ b/contrib/wpa/src/eap_common/ikev2_common.c
@@ -21,7 +21,7 @@ static struct ikev2_integ_alg ikev2_integ_algs[] = {
{ AUTH_HMAC_MD5_96, 16, 12 }
};
-#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
+#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs)
static struct ikev2_prf_alg ikev2_prf_algs[] = {
@@ -29,7 +29,7 @@ static struct ikev2_prf_alg ikev2_prf_algs[] = {
{ PRF_HMAC_MD5, 16, 16 }
};
-#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
+#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs)
static struct ikev2_encr_alg ikev2_encr_algs[] = {
@@ -37,7 +37,7 @@ static struct ikev2_encr_alg ikev2_encr_algs[] = {
{ ENCR_3DES, 24, 8 }
};
-#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
+#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs)
const struct ikev2_integ_alg * ikev2_get_integ(int id)
@@ -173,46 +173,12 @@ const struct ikev2_encr_alg * ikev2_get_encr(int id)
}
-#ifdef CCNS_PL
-/* from des.c */
-struct des3_key_s {
- u32 ek[3][32];
- u32 dk[3][32];
-};
-
-void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
-void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
-void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
-#endif /* CCNS_PL */
-
-
int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
const u8 *plain, u8 *crypt, size_t len)
{
struct crypto_cipher *cipher;
int encr_alg;
-#ifdef CCNS_PL
- if (alg == ENCR_3DES) {
- struct des3_key_s des3key;
- size_t i, blocks;
- u8 *pos;
-
- /* ECB mode is used incorrectly for 3DES!? */
- if (key_len != 24) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
- return -1;
- }
- des3_key_setup(key, &des3key);
-
- blocks = len / 8;
- pos = crypt;
- for (i = 0; i < blocks; i++) {
- des3_encrypt(pos, &des3key, pos);
- pos += 8;
- }
- } else {
-#endif /* CCNS_PL */
switch (alg) {
case ENCR_3DES:
encr_alg = CRYPTO_CIPHER_ALG_3DES;
@@ -237,9 +203,6 @@ int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
return -1;
}
crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
- }
-#endif /* CCNS_PL */
return 0;
}
@@ -251,31 +214,6 @@ int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
struct crypto_cipher *cipher;
int encr_alg;
-#ifdef CCNS_PL
- if (alg == ENCR_3DES) {
- struct des3_key_s des3key;
- size_t i, blocks;
-
- /* ECB mode is used incorrectly for 3DES!? */
- if (key_len != 24) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
- return -1;
- }
- des3_key_setup(key, &des3key);
-
- if (len % 8) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted "
- "length");
- return -1;
- }
- blocks = len / 8;
- for (i = 0; i < blocks; i++) {
- des3_decrypt(crypt, &des3key, plain);
- plain += 8;
- crypt += 8;
- }
- } else {
-#endif /* CCNS_PL */
switch (alg) {
case ENCR_3DES:
encr_alg = CRYPTO_CIPHER_ALG_3DES;
@@ -300,9 +238,6 @@ int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
return -1;
}
crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
- }
-#endif /* CCNS_PL */
return 0;
}
@@ -316,25 +251,29 @@ int ikev2_parse_payloads(struct ikev2_payloads *payloads,
os_memset(payloads, 0, sizeof(*payloads));
while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
- int plen, pdatalen;
+ unsigned int plen, pdatalen, left;
const u8 *pdata;
wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
next_payload);
- if (end - pos < (int) sizeof(*phdr)) {
+ if (end < pos)
+ return -1;
+ left = end - pos;
+ if (left < sizeof(*phdr)) {
wpa_printf(MSG_INFO, "IKEV2: Too short message for "
"payload header (left=%ld)",
(long) (end - pos));
+ return -1;
}
phdr = (const struct ikev2_payload_hdr *) pos;
plen = WPA_GET_BE16(phdr->payload_length);
- if (plen < (int) sizeof(*phdr) || pos + plen > end) {
+ if (plen < sizeof(*phdr) || plen > left) {
wpa_printf(MSG_INFO, "IKEV2: Invalid payload header "
"length %d", plen);
return -1;
}
wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x"
- " Payload Length: %d",
+ " Payload Length: %u",
phdr->next_payload, phdr->flags, plen);
pdata = (const u8 *) (phdr + 1);
@@ -542,7 +481,7 @@ u8 * ikev2_decrypt_payload(int encr_id, int integ_id,
"hash");
return NULL;
}
- if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) {
+ if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) {
wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
"Data");
return NULL;
@@ -706,10 +645,6 @@ int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
keys->SK_integ_len = integ->key_len;
keys->SK_encr_len = encr->key_len;
keys->SK_prf_len = prf->key_len;
-#ifdef CCNS_PL
- /* Uses encryption key length for SK_d; should be PRF length */
- keys->SK_d_len = keys->SK_encr_len;
-#endif /* CCNS_PL */
keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
diff --git a/contrib/wpa/src/eap_common/ikev2_common.h b/contrib/wpa/src/eap_common/ikev2_common.h
index 45c970b..8a7982a 100644
--- a/contrib/wpa/src/eap_common/ikev2_common.h
+++ b/contrib/wpa/src/eap_common/ikev2_common.h
@@ -70,11 +70,7 @@ struct ikev2_transform {
/* Current IKEv2 version from RFC 4306 */
#define IKEV2_MjVer 2
#define IKEV2_MnVer 0
-#ifdef CCNS_PL
-#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4))
-#else /* CCNS_PL */
#define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer))
-#endif /* CCNS_PL */
/* IKEv2 Exchange Types */
enum {
diff --git a/contrib/wpa/src/eap_peer/eap.c b/contrib/wpa/src/eap_peer/eap.c
index a4c9b25..35433f3 100644
--- a/contrib/wpa/src/eap_peer/eap.c
+++ b/contrib/wpa/src/eap_peer/eap.c
@@ -1,6 +1,6 @@
/*
* EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, 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,7 @@
#include "ext_password.h"
#include "crypto/crypto.h"
#include "crypto/tls.h"
+#include "crypto/sha256.h"
#include "common/wpa_ctrl.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_i.h"
@@ -92,6 +93,15 @@ static void eap_notify_status(struct eap_sm *sm, const char *status,
}
+static void eap_sm_free_key(struct eap_sm *sm)
+{
+ if (sm->eapKeyData) {
+ bin_clear_free(sm->eapKeyData, sm->eapKeyDataLen);
+ sm->eapKeyData = NULL;
+ }
+}
+
+
static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
{
ext_password_free(sm->ext_pw_buf);
@@ -144,11 +154,13 @@ SM_STATE(EAP, INITIALIZE)
SM_ENTRY(EAP, INITIALIZE);
if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
- !sm->prev_failure) {
+ !sm->prev_failure &&
+ sm->last_config == eap_get_config(sm)) {
wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
"fast reauthentication");
sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
} else {
+ sm->last_config = eap_get_config(sm);
eap_deinit_prev_method(sm, "INITIALIZE");
}
sm->selectedMethod = EAP_TYPE_NONE;
@@ -159,8 +171,9 @@ SM_STATE(EAP, INITIALIZE)
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
eapol_set_bool(sm, EAPOL_eapFail, FALSE);
- os_free(sm->eapKeyData);
- sm->eapKeyData = NULL;
+ eap_sm_free_key(sm);
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = NULL;
sm->eapKeyAvailable = FALSE;
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
sm->lastId = -1; /* new session - make sure this does not match with
@@ -177,6 +190,9 @@ SM_STATE(EAP, INITIALIZE)
eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
sm->num_rounds = 0;
sm->prev_failure = 0;
+ sm->expected_failure = 0;
+ sm->reauthInit = FALSE;
+ sm->erp_seq = (u32) -1;
}
@@ -340,6 +356,267 @@ nak:
}
+#ifdef CONFIG_ERP
+
+static char * eap_home_realm(struct eap_sm *sm)
+{
+ struct eap_peer_config *config = eap_get_config(sm);
+ char *realm;
+ size_t i, realm_len;
+
+ if (!config)
+ return NULL;
+
+ if (config->identity) {
+ for (i = 0; i < config->identity_len; i++) {
+ if (config->identity[i] == '@')
+ break;
+ }
+ if (i < config->identity_len) {
+ realm_len = config->identity_len - i - 1;
+ realm = os_malloc(realm_len + 1);
+ if (realm == NULL)
+ return NULL;
+ os_memcpy(realm, &config->identity[i + 1], realm_len);
+ realm[realm_len] = '\0';
+ return realm;
+ }
+ }
+
+ if (config->anonymous_identity) {
+ for (i = 0; i < config->anonymous_identity_len; i++) {
+ if (config->anonymous_identity[i] == '@')
+ break;
+ }
+ if (i < config->anonymous_identity_len) {
+ realm_len = config->anonymous_identity_len - i - 1;
+ realm = os_malloc(realm_len + 1);
+ if (realm == NULL)
+ return NULL;
+ os_memcpy(realm, &config->anonymous_identity[i + 1],
+ realm_len);
+ realm[realm_len] = '\0';
+ return realm;
+ }
+ }
+
+ return os_strdup("");
+}
+
+
+static struct eap_erp_key *
+eap_erp_get_key(struct eap_sm *sm, const char *realm)
+{
+ struct eap_erp_key *erp;
+
+ dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
+ char *pos;
+
+ pos = os_strchr(erp->keyname_nai, '@');
+ if (!pos)
+ continue;
+ pos++;
+ if (os_strcmp(pos, realm) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+
+
+static struct eap_erp_key *
+eap_erp_get_key_nai(struct eap_sm *sm, const char *nai)
+{
+ struct eap_erp_key *erp;
+
+ dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
+ if (os_strcmp(erp->keyname_nai, nai) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+
+
+static void eap_peer_erp_free_key(struct eap_erp_key *erp)
+{
+ dl_list_del(&erp->list);
+ bin_clear_free(erp, sizeof(*erp));
+}
+
+
+static void eap_erp_remove_keys_realm(struct eap_sm *sm, const char *realm)
+{
+ struct eap_erp_key *erp;
+
+ while ((erp = eap_erp_get_key(sm, realm)) != NULL) {
+ wpa_printf(MSG_DEBUG, "EAP: Delete old ERP key %s",
+ erp->keyname_nai);
+ eap_peer_erp_free_key(erp);
+ }
+}
+
+#endif /* CONFIG_ERP */
+
+
+void eap_peer_erp_free_keys(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+ struct eap_erp_key *erp, *tmp;
+
+ dl_list_for_each_safe(erp, tmp, &sm->erp_keys, struct eap_erp_key, list)
+ eap_peer_erp_free_key(erp);
+#endif /* CONFIG_ERP */
+}
+
+
+static void eap_peer_erp_init(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+ u8 *emsk = NULL;
+ size_t emsk_len = 0;
+ u8 EMSKname[EAP_EMSK_NAME_LEN];
+ u8 len[2];
+ char *realm;
+ size_t realm_len, nai_buf_len;
+ struct eap_erp_key *erp = NULL;
+ int pos;
+
+ realm = eap_home_realm(sm);
+ if (!realm)
+ return;
+ realm_len = os_strlen(realm);
+ wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
+ eap_erp_remove_keys_realm(sm, realm);
+
+ nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + realm_len;
+ if (nai_buf_len > 253) {
+ /*
+ * keyName-NAI has a maximum length of 253 octet to fit in
+ * RADIUS attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long realm for ERP keyName-NAI maximum length");
+ goto fail;
+ }
+ nai_buf_len++; /* null termination */
+ erp = os_zalloc(sizeof(*erp) + nai_buf_len);
+ if (erp == NULL)
+ goto fail;
+
+ 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");
+ goto fail;
+ }
+
+ 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) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
+
+ pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
+ EMSKname, EAP_EMSK_NAME_LEN);
+ erp->keyname_nai[pos] = '@';
+ os_memcpy(&erp->keyname_nai[pos + 1], realm, realm_len);
+
+ WPA_PUT_BE16(len, emsk_len);
+ if (hmac_sha256_kdf(emsk, emsk_len,
+ "EAP Re-authentication Root Key@ietf.org",
+ len, sizeof(len), erp->rRK, emsk_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
+ goto fail;
+ }
+ erp->rRK_len = emsk_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, 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) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
+ goto fail;
+ }
+ erp->rIK_len = erp->rRK_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
+
+ wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s", erp->keyname_nai);
+ dl_list_add(&sm->erp_keys, &erp->list);
+ erp = NULL;
+fail:
+ bin_clear_free(emsk, emsk_len);
+ bin_clear_free(erp, sizeof(*erp));
+ os_free(realm);
+#endif /* CONFIG_ERP */
+}
+
+
+#ifdef CONFIG_ERP
+static int eap_peer_erp_reauth_start(struct eap_sm *sm,
+ const struct eap_hdr *hdr, size_t len)
+{
+ char *realm;
+ struct eap_erp_key *erp;
+ struct wpabuf *msg;
+ u8 hash[SHA256_MAC_LEN];
+
+ realm = eap_home_realm(sm);
+ if (!realm)
+ return -1;
+
+ erp = eap_erp_get_key(sm, realm);
+ os_free(realm);
+ realm = NULL;
+ if (!erp)
+ return -1;
+
+ if (erp->next_seq >= 65536)
+ return -1; /* SEQ has range of 0..65535 */
+
+ /* TODO: check rRK lifetime expiration */
+
+ wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
+ erp->keyname_nai, erp->next_seq);
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+ 1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
+ EAP_CODE_INITIATE, hdr->identifier);
+ if (msg == NULL)
+ return -1;
+
+ wpabuf_put_u8(msg, 0x20); /* Flags: R=0 B=0 L=1 */
+ wpabuf_put_be16(msg, erp->next_seq);
+
+ wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
+ wpabuf_put_u8(msg, os_strlen(erp->keyname_nai));
+ wpabuf_put_str(msg, erp->keyname_nai);
+
+ wpabuf_put_u8(msg, EAP_ERP_CS_HMAC_SHA256_128); /* Cryptosuite */
+
+ if (hmac_sha256(erp->rIK, erp->rIK_len,
+ wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
+ wpabuf_free(msg);
+ return -1;
+ }
+ 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++;
+ wpabuf_free(sm->eapRespData);
+ sm->eapRespData = msg;
+ sm->reauthInit = TRUE;
+ return 0;
+}
+#endif /* CONFIG_ERP */
+
+
/*
* The method processing happens here. The request from the authenticator is
* processed, and an appropriate response packet is built.
@@ -386,10 +663,11 @@ SM_STATE(EAP, METHOD)
sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
eapReqData);
wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
- "methodState=%s decision=%s",
+ "methodState=%s decision=%s eapRespData=%p",
ret.ignore ? "TRUE" : "FALSE",
eap_sm_method_state_txt(ret.methodState),
- eap_sm_decision_txt(ret.decision));
+ eap_sm_decision_txt(ret.decision),
+ sm->eapRespData);
sm->ignore = ret.ignore;
if (sm->ignore)
@@ -400,9 +678,22 @@ SM_STATE(EAP, METHOD)
if (sm->m->isKeyAvailable && sm->m->getKey &&
sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
- os_free(sm->eapKeyData);
+ 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);
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = NULL;
+ if (sm->m->getSessionId) {
+ sm->eapSessionId = sm->m->getSessionId(
+ sm, sm->eap_method_priv,
+ &sm->eapSessionIdLen);
+ wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+ sm->eapSessionId, sm->eapSessionIdLen);
+ }
+ if (config->erp && sm->m->get_emsk && sm->eapSessionId)
+ eap_peer_erp_init(sm);
}
}
@@ -421,10 +712,13 @@ SM_STATE(EAP, SEND_RESPONSE)
sm->lastId = sm->reqId;
sm->lastRespData = wpabuf_dup(sm->eapRespData);
eapol_set_bool(sm, EAPOL_eapResp, TRUE);
- } else
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP: No eapRespData available");
sm->lastRespData = NULL;
+ }
eapol_set_bool(sm, EAPOL_eapReq, FALSE);
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+ sm->reauthInit = FALSE;
}
@@ -640,6 +934,15 @@ static int eap_peer_req_is_duplicate(struct eap_sm *sm)
}
+static int eap_peer_sm_allow_canned(struct eap_sm *sm)
+{
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ return config && config->phase1 &&
+ os_strstr(config->phase1, "allow_canned_success=1");
+}
+
+
static void eap_peer_sm_step_received(struct eap_sm *sm)
{
int duplicate = eap_peer_req_is_duplicate(sm);
@@ -653,6 +956,17 @@ static void eap_peer_sm_step_received(struct eap_sm *sm)
(sm->reqId == sm->lastId ||
eap_success_workaround(sm, sm->reqId, sm->lastId)))
SM_ENTER(EAP, SUCCESS);
+ else if (sm->workaround && sm->lastId == -1 && sm->rxSuccess &&
+ !sm->rxFailure && !sm->rxReq && eap_peer_sm_allow_canned(sm))
+ SM_ENTER(EAP, SUCCESS); /* EAP-Success prior any EAP method */
+ else if (sm->workaround && sm->lastId == -1 && sm->rxFailure &&
+ !sm->rxReq && sm->methodState != METHOD_CONT &&
+ eap_peer_sm_allow_canned(sm))
+ SM_ENTER(EAP, FAILURE); /* EAP-Failure prior any EAP method */
+ else if (sm->workaround && sm->rxSuccess && !sm->rxFailure &&
+ !sm->rxReq && sm->methodState != METHOD_CONT &&
+ eap_peer_sm_allow_canned(sm))
+ SM_ENTER(EAP, SUCCESS); /* EAP-Success after Identity */
else if (sm->methodState != METHOD_CONT &&
((sm->rxFailure &&
sm->decision != DECISION_UNCOND_SUCC) ||
@@ -684,6 +998,8 @@ static void eap_peer_sm_step_received(struct eap_sm *sm)
else if (sm->selectedMethod == EAP_TYPE_LEAP &&
(sm->rxSuccess || sm->rxResp))
SM_ENTER(EAP, METHOD);
+ else if (sm->reauthInit)
+ SM_ENTER(EAP, SEND_RESPONSE);
else
SM_ENTER(EAP, DISCARD);
}
@@ -713,8 +1029,19 @@ static void eap_peer_sm_step_local(struct eap_sm *sm)
SM_ENTER(EAP, SEND_RESPONSE);
break;
case EAP_METHOD:
+ /*
+ * Note: RFC 4137 uses methodState == DONE && decision == FAIL
+ * as the condition. eapRespData == NULL here is used to allow
+ * final EAP method response to be sent without having to change
+ * all methods to either use methodState MAY_CONT or leaving
+ * decision to something else than FAIL in cases where the only
+ * expected response is EAP-Failure.
+ */
if (sm->ignore)
SM_ENTER(EAP, DISCARD);
+ else if (sm->methodState == METHOD_DONE &&
+ sm->decision == DECISION_FAIL && !sm->eapRespData)
+ SM_ENTER(EAP, FAILURE);
else
SM_ENTER(EAP, SEND_RESPONSE);
break;
@@ -891,6 +1218,7 @@ static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
"EAP authentication started");
+ eap_notify_status(sm, "started", "");
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
&msg_len);
@@ -926,6 +1254,8 @@ static int mnc_len_from_imsi(const char *imsi)
mcc_str[3] = '\0';
mcc = atoi(mcc_str);
+ if (mcc == 228)
+ return 2; /* Networks in Switzerland use 2-digit MNC */
if (mcc == 244)
return 2; /* Networks in Finland use 2-digit MNC */
@@ -1192,6 +1522,219 @@ static struct wpabuf * eap_sm_buildNotify(int id)
}
+static void eap_peer_initiate(struct eap_sm *sm, const struct eap_hdr *hdr,
+ size_t len)
+{
+#ifdef CONFIG_ERP
+ const u8 *pos = (const u8 *) (hdr + 1);
+ const u8 *end = ((const u8 *) hdr) + len;
+ struct erp_tlvs parse;
+
+ if (len < sizeof(*hdr) + 1) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Initiate");
+ return;
+ }
+
+ if (*pos != EAP_ERP_TYPE_REAUTH_START) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Ignored unexpected EAP-Initiate Type=%u",
+ *pos);
+ return;
+ }
+
+ pos++;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too short EAP-Initiate/Re-auth-Start");
+ return;
+ }
+ pos++; /* Reserved */
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth-Start TVs/TLVs",
+ pos, end - pos);
+
+ if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
+ goto invalid;
+
+ if (parse.domain) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP: EAP-Initiate/Re-auth-Start - Domain name",
+ parse.domain, parse.domain_len);
+ /* TODO: Derivation of domain specific keys for local ER */
+ }
+
+ if (eap_peer_erp_reauth_start(sm, hdr, len) == 0)
+ return;
+
+invalid:
+#endif /* CONFIG_ERP */
+ wpa_printf(MSG_DEBUG,
+ "EAP: EAP-Initiate/Re-auth-Start - No suitable ERP keys available - try to start full EAP authentication");
+ eapol_set_bool(sm, EAPOL_eapTriggerStart, TRUE);
+}
+
+
+static 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);
+ const u8 *end = ((const u8 *) hdr) + len;
+ const u8 *start;
+ struct erp_tlvs parse;
+ u8 flags;
+ u16 seq;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ struct eap_erp_key *erp;
+ int max_len;
+ char nai[254];
+ u8 seed[4];
+ int auth_tag_ok = 0;
+
+ if (len < sizeof(*hdr) + 1) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Finish");
+ return;
+ }
+
+ if (*pos != EAP_ERP_TYPE_REAUTH) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Ignored unexpected EAP-Finish Type=%u", *pos);
+ return;
+ }
+
+ if (len < sizeof(*hdr) + 4) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Ignored too short EAP-Finish/Re-auth");
+ return;
+ }
+
+ pos++;
+ flags = *pos++;
+ seq = WPA_GET_BE16(pos);
+ pos += 2;
+ wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
+
+ if (seq != sm->erp_seq) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Unexpected EAP-Finish/Re-auth SEQ=%u", seq);
+ return;
+ }
+
+ /*
+ * Parse TVs/TLVs. Since we do not yet know the length of the
+ * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
+ * just try to find the keyName-NAI first so that we can check the
+ * Authentication Tag.
+ */
+ if (erp_parse_tlvs(pos, end, &parse, 1) < 0)
+ return;
+
+ if (!parse.keyname) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No keyName-NAI in EAP-Finish/Re-auth Packet");
+ return;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Finish/Re-auth - keyName-NAI",
+ parse.keyname, parse.keyname_len);
+ if (parse.keyname_len > 253) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long keyName-NAI in EAP-Finish/Re-auth");
+ return;
+ }
+ os_memcpy(nai, parse.keyname, parse.keyname_len);
+ nai[parse.keyname_len] = '\0';
+
+ erp = eap_erp_get_key_nai(sm, nai);
+ if (!erp) {
+ wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
+ nai);
+ return;
+ }
+
+ /* Is there enough room for Cryptosuite and Authentication Tag? */
+ start = parse.keyname + parse.keyname_len;
+ max_len = end - start;
+ hash_len = 16;
+ if (max_len < 1 + (int) hash_len) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Not enough room for Authentication Tag");
+ if (flags & 0x80)
+ goto no_auth_tag;
+ return;
+ }
+ if (end[-17] != EAP_ERP_CS_HMAC_SHA256_128) {
+ wpa_printf(MSG_DEBUG, "EAP: Different Cryptosuite used");
+ if (flags & 0x80)
+ goto no_auth_tag;
+ return;
+ }
+
+ if (hmac_sha256(erp->rIK, erp->rIK_len, (const u8 *) hdr,
+ end - ((const u8 *) hdr) - hash_len, hash) < 0)
+ return;
+ if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag mismatch");
+ return;
+ }
+ auth_tag_ok = 1;
+ end -= 1 + hash_len;
+
+no_auth_tag:
+ /*
+ * Parse TVs/TLVs again now that we know the exact part of the buffer
+ * that contains them.
+ */
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Finish/Re-Auth TVs/TLVs",
+ pos, end - pos);
+ if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
+ return;
+
+ if (flags & 0x80 || !auth_tag_ok) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: EAP-Finish/Re-auth indicated failure");
+ eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ "EAP authentication failed");
+ sm->prev_failure = 1;
+ wpa_printf(MSG_DEBUG,
+ "EAP: Drop ERP key to try full authentication on next attempt");
+ eap_peer_erp_free_key(erp);
+ return;
+ }
+
+ eap_sm_free_key(sm);
+ sm->eapKeyDataLen = 0;
+ sm->eapKeyData = os_malloc(erp->rRK_len);
+ if (!sm->eapKeyData)
+ return;
+ sm->eapKeyDataLen = erp->rRK_len;
+
+ WPA_PUT_BE16(seed, seq);
+ WPA_PUT_BE16(&seed[2], erp->rRK_len);
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "Re-authentication Master Session Key@ietf.org",
+ seed, sizeof(seed),
+ sm->eapKeyData, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
+ eap_sm_free_key(sm);
+ return;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
+ sm->eapKeyData, sm->eapKeyDataLen);
+ sm->eapKeyAvailable = TRUE;
+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ "EAP re-authentication completed successfully");
+#endif /* CONFIG_ERP */
+}
+
+
static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
{
const struct eap_hdr *hdr;
@@ -1283,6 +1826,12 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
eap_notify_status(sm, "completion", "failure");
sm->rxFailure = TRUE;
break;
+ case EAP_CODE_INITIATE:
+ eap_peer_initiate(sm, hdr, plen);
+ break;
+ case EAP_CODE_FINISH:
+ eap_peer_finish(sm, hdr, plen);
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
"code %d", hdr->code);
@@ -1329,6 +1878,8 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
sm->eapol_cb->notify_cert(sm->eapol_ctx,
data->peer_cert.depth,
data->peer_cert.subject,
+ data->peer_cert.altsubject,
+ data->peer_cert.num_altsubject,
hash_hex, data->peer_cert.cert);
break;
case TLS_ALERT:
@@ -1374,11 +1925,13 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
sm->msg_ctx = msg_ctx;
sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
sm->wps = conf->wps;
+ dl_list_init(&sm->erp_keys);
os_memset(&tlsconf, 0, sizeof(tlsconf));
tlsconf.opensc_engine_path = conf->opensc_engine_path;
tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
+ tlsconf.openssl_ciphers = conf->openssl_ciphers;
#ifdef CONFIG_FIPS
tlsconf.fips_mode = 1;
#endif /* CONFIG_FIPS */
@@ -1420,6 +1973,7 @@ void eap_peer_sm_deinit(struct eap_sm *sm)
if (sm->ssl_ctx2)
tls_deinit(sm->ssl_ctx2);
tls_deinit(sm->ssl_ctx);
+ eap_peer_erp_free_keys(sm);
os_free(sm);
}
@@ -1459,8 +2013,9 @@ void eap_sm_abort(struct eap_sm *sm)
sm->lastRespData = NULL;
wpabuf_free(sm->eapRespData);
sm->eapRespData = NULL;
- os_free(sm->eapKeyData);
- sm->eapKeyData = NULL;
+ eap_sm_free_key(sm);
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = NULL;
/* This is not clearly specified in the EAP statemachines draft, but
* it seems necessary to make sure that some of the EAPOL variables get
@@ -1567,7 +2122,7 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
len = os_snprintf(buf, buflen,
"EAP state=%s\n",
eap_sm_state_txt(sm->EAP_state));
- if (len < 0 || (size_t) len >= buflen)
+ if (os_snprintf_error(buflen, len))
return 0;
if (sm->selectedMethod != EAP_TYPE_NONE) {
@@ -1586,7 +2141,7 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
ret = os_snprintf(buf + len, buflen - len,
"selectedMethod=%d (EAP-%s)\n",
sm->selectedMethod, name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -1607,7 +2162,7 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
eap_sm_method_state_txt(sm->methodState),
eap_sm_decision_txt(sm->decision),
sm->ClientTimeout);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
@@ -1622,7 +2177,8 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
const char *msg, size_t msglen)
{
struct eap_peer_config *config;
- char *txt = NULL, *tmp;
+ const char *txt = NULL;
+ char *tmp;
if (sm == NULL)
return;
@@ -1665,6 +2221,9 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
case WPA_CTRL_REQ_EAP_PASSPHRASE:
config->pending_req_passphrase++;
break;
+ case WPA_CTRL_REQ_SIM:
+ txt = msg;
+ break;
default:
return;
}
@@ -1776,6 +2335,17 @@ void eap_sm_request_passphrase(struct eap_sm *sm)
/**
+ * eap_sm_request_sim - Request external SIM processing
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @req: EAP method specific request
+ */
+void eap_sm_request_sim(struct eap_sm *sm, const char *req)
+{
+ eap_sm_request(sm, WPA_CTRL_REQ_SIM, req, os_strlen(req));
+}
+
+
+/**
* eap_sm_notify_ctrl_attached - Notification of attached monitor
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
*
@@ -2001,6 +2571,8 @@ const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
+ if (hash)
+ *hash = 0;
*len = wpabuf_len(sm->ext_pw_buf);
return wpabuf_head(sm->ext_pw_buf);
}
@@ -2158,6 +2730,28 @@ void eap_notify_lower_layer_success(struct eap_sm *sm)
/**
+ * eap_get_eapSessionId - Get Session-Id from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the session
+ * Returns: Pointer to the EAP Session-Id or %NULL on failure
+ *
+ * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
+ * only after a successful authentication. EAP state machine continues to manage
+ * the Session-Id and the caller must not change or free the returned data.
+ */
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
+{
+ if (sm == NULL || sm->eapSessionId == NULL) {
+ *len = 0;
+ return NULL;
+ }
+
+ *len = sm->eapSessionIdLen;
+ return sm->eapSessionId;
+}
+
+
+/**
* eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @len: Pointer to variable that will be set to number of bytes in the key
@@ -2266,6 +2860,17 @@ void eap_set_force_disabled(struct eap_sm *sm, int disabled)
}
+/**
+ * eap_set_external_sim - Set external_sim flag
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @external_sim: Whether external SIM/USIM processing is used
+ */
+void eap_set_external_sim(struct eap_sm *sm, int external_sim)
+{
+ sm->external_sim = external_sim;
+}
+
+
/**
* eap_notify_pending - Notify that EAP method is ready to re-process a request
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
@@ -2337,3 +2942,9 @@ void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
if (sm->eapol_cb->set_anon_id)
sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
}
+
+
+int eap_peer_was_failure_expected(struct eap_sm *sm)
+{
+ return sm->expected_failure;
+}
diff --git a/contrib/wpa/src/eap_peer/eap.h b/contrib/wpa/src/eap_peer/eap.h
index 8bccef1..702463b 100644
--- a/contrib/wpa/src/eap_peer/eap.h
+++ b/contrib/wpa/src/eap_peer/eap.h
@@ -94,7 +94,14 @@ enum eapol_bool_var {
*
* EAP state machines reads this value.
*/
- EAPOL_altReject
+ EAPOL_altReject,
+
+ /**
+ * EAPOL_eapTriggerStart - EAP-based trigger to send EAPOL-Start
+ *
+ * EAP state machine writes this value.
+ */
+ EAPOL_eapTriggerStart
};
/**
@@ -221,10 +228,13 @@ struct eapol_callbacks {
* @ctx: eapol_ctx from eap_peer_sm_init() call
* @depth: Depth in certificate chain (0 = server)
* @subject: Subject of the peer certificate
+ * @altsubject: Select fields from AltSubject of the peer certificate
+ * @num_altsubject: Number of altsubject values
* @cert_hash: SHA-256 hash of the certificate
* @cert: Peer certificate
*/
void (*notify_cert)(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash, const struct wpabuf *cert);
/**
@@ -236,6 +246,14 @@ struct eapol_callbacks {
void (*notify_status)(void *ctx, const char *status,
const char *parameter);
+#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);
+#endif /* CONFIG_EAP_PROXY */
+
/**
* set_anon_id - Set or add anonymous identity
* @ctx: eapol_ctx from eap_peer_sm_init() call
@@ -268,6 +286,14 @@ struct eap_config {
*/
const char *pkcs11_module_path;
/**
+ * openssl_ciphers - 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.
+ */
+ const char *openssl_ciphers;
+ /**
* wps - WPS context data
*
* This is only used by EAP-WSC and can be left %NULL if not available.
@@ -296,6 +322,7 @@ void eap_sm_request_new_password(struct eap_sm *sm);
void eap_sm_request_pin(struct eap_sm *sm);
void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len);
void eap_sm_request_passphrase(struct eap_sm *sm);
+void eap_sm_request_sim(struct eap_sm *sm, const char *req);
void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
u32 eap_get_phase2_type(const char *name, int *vendor);
struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
@@ -303,9 +330,11 @@ struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
void eap_set_force_disabled(struct eap_sm *sm, int disabled);
+void eap_set_external_sim(struct eap_sm *sm, int external_sim);
int eap_key_available(struct eap_sm *sm);
void eap_notify_success(struct eap_sm *sm);
void eap_notify_lower_layer_success(struct eap_sm *sm);
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
@@ -317,6 +346,8 @@ int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
struct ext_password_data;
void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
+int eap_peer_was_failure_expected(struct eap_sm *sm);
+void eap_peer_erp_free_keys(struct eap_sm *sm);
#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa/src/eap_peer/eap_aka.c b/contrib/wpa/src/eap_peer/eap_aka.c
index 59861cb..0662ae7 100644
--- a/contrib/wpa/src/eap_peer/eap_aka.c
+++ b/contrib/wpa/src/eap_peer/eap_aka.c
@@ -42,7 +42,7 @@ struct eap_aka_data {
u8 *last_eap_identity;
size_t last_eap_identity_len;
enum {
- CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
+ CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
struct wpabuf *id_msgs;
@@ -64,8 +64,6 @@ static const char * eap_aka_state_txt(int state)
return "CONTINUE";
case RESULT_SUCCESS:
return "RESULT_SUCCESS";
- case RESULT_FAILURE:
- return "RESULT_FAILURE";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -128,6 +126,21 @@ static void * eap_aka_prime_init(struct eap_sm *sm)
#endif /* EAP_AKA_PRIME */
+static void eap_aka_clear_keys(struct eap_aka_data *data, int reauth)
+{
+ if (!reauth) {
+ os_memset(data->mk, 0, EAP_SIM_MK_LEN);
+ os_memset(data->k_aut, 0, EAP_AKA_PRIME_K_AUT_LEN);
+ os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
+ os_memset(data->k_re, 0, EAP_AKA_PRIME_K_RE_LEN);
+ }
+ os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
+ os_memset(data->emsk, 0, EAP_EMSK_LEN);
+ os_memset(data->autn, 0, EAP_AKA_AUTN_LEN);
+ os_memset(data->auts, 0, EAP_AKA_AUTS_LEN);
+}
+
+
static void eap_aka_deinit(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
@@ -137,11 +150,95 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv)
os_free(data->last_eap_identity);
wpabuf_free(data->id_msgs);
os_free(data->network_name);
+ eap_aka_clear_keys(data, 0);
os_free(data);
}
}
+static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data)
+{
+ char req[200], *pos, *end;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Use external USIM processing");
+ pos = req;
+ end = pos + sizeof(req);
+ pos += os_snprintf(pos, end - pos, "UMTS-AUTH");
+ pos += os_snprintf(pos, end - pos, ":");
+ pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN);
+ pos += os_snprintf(pos, end - pos, ":");
+ wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN);
+
+ eap_sm_request_sim(sm, req);
+ return 1;
+}
+
+
+static int eap_aka_ext_sim_result(struct eap_sm *sm, struct eap_aka_data *data,
+ struct eap_peer_config *conf)
+{
+ char *resp, *pos;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Use result from external USIM processing");
+
+ resp = conf->external_sim_resp;
+ conf->external_sim_resp = NULL;
+
+ if (os_strncmp(resp, "UMTS-AUTS:", 10) == 0) {
+ pos = resp + 10;
+ if (hexstr2bin(pos, data->auts, EAP_AKA_AUTS_LEN) < 0)
+ goto invalid;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: AUTS", data->auts,
+ EAP_AKA_AUTS_LEN);
+ os_free(resp);
+ return -2;
+ }
+
+ if (os_strncmp(resp, "UMTS-AUTH:", 10) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized external USIM processing response");
+ os_free(resp);
+ return -1;
+ }
+
+ pos = resp + 10;
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: RAND", data->rand, EAP_AKA_RAND_LEN);
+
+ if (hexstr2bin(pos, data->ik, EAP_AKA_IK_LEN) < 0)
+ goto invalid;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, EAP_AKA_IK_LEN);
+ pos += EAP_AKA_IK_LEN * 2;
+ if (*pos != ':')
+ goto invalid;
+ pos++;
+
+ if (hexstr2bin(pos, data->ck, EAP_AKA_CK_LEN) < 0)
+ goto invalid;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, EAP_AKA_CK_LEN);
+ pos += EAP_AKA_CK_LEN * 2;
+ if (*pos != ':')
+ goto invalid;
+ pos++;
+
+ data->res_len = os_strlen(pos) / 2;
+ if (data->res_len > EAP_AKA_RES_MAX_LEN) {
+ data->res_len = 0;
+ goto invalid;
+ }
+ if (hexstr2bin(pos, data->res, data->res_len) < 0)
+ goto invalid;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: RES", data->res, data->res_len);
+
+ os_free(resp);
+ return 0;
+
+invalid:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Invalid external USIM processing UMTS-AUTH response");
+ os_free(resp);
+ return -1;
+}
+
+
static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
{
struct eap_peer_config *conf;
@@ -151,6 +248,14 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
conf = eap_get_config(sm);
if (conf == NULL)
return -1;
+
+ if (sm->external_sim) {
+ if (conf->external_sim_resp)
+ return eap_aka_ext_sim_result(sm, data, conf);
+ else
+ return eap_aka_ext_sim_req(sm, data);
+ }
+
if (conf->pcsc) {
return scard_umts_auth(sm->scard_ctx, data->rand,
data->autn, data->res, &data->res_len,
@@ -205,7 +310,7 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
{
u8 autn[EAP_AKA_AUTN_LEN];
os_memset(autn, '1', EAP_AKA_AUTN_LEN);
- if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
+ if (os_memcmp_const(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
"with expected value");
return -1;
@@ -225,7 +330,7 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
#else /* CONFIG_USIM_HARDCODED */
- wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith "
+ wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorithm "
"enabled");
return -1;
@@ -420,7 +525,7 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
#endif /* EAP_AKA_PRIME */
sha1_vector(1, &addr, &len, hash);
- if (os_memcmp(hash, checkcode, hash_len) != 0) {
+ if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
return -1;
}
@@ -443,7 +548,7 @@ static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
EAP_AKA_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -460,7 +565,7 @@ static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
"(id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -479,7 +584,7 @@ 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);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -523,7 +628,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
identity, identity_len);
}
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -545,7 +650,8 @@ static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, (u8 *) "",
+ 0);
}
@@ -587,7 +693,7 @@ static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, nonce_s,
EAP_SIM_NONCE_S_LEN);
}
@@ -621,7 +727,7 @@ static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
+ return eap_sim_msg_finish(msg, data->eap_method, k_aut, (u8 *) "", 0);
}
@@ -701,7 +807,7 @@ static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
EAP_AKA_SUBTYPE_CHALLENGE);
wpa_printf(MSG_DEBUG, " AT_KDF");
eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -861,6 +967,9 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
"failed (AUTN seq# -> AUTS)");
return eap_aka_synchronization_failure(data, id);
+ } else if (res > 0) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Wait for external USIM processing");
+ return NULL;
} else if (res) {
wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
return eap_aka_client_error(data, id,
@@ -931,7 +1040,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_aka_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -1147,7 +1256,7 @@ static struct wpabuf * eap_aka_process_reauthentication(
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_aka_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -1253,9 +1362,7 @@ done:
*/
ret->methodState = data->use_result_ind ?
METHOD_DONE : METHOD_MAY_CONT;
- } else if (data->state == RESULT_FAILURE)
- ret->methodState = METHOD_CONT;
- else if (data->state == RESULT_SUCCESS)
+ } else if (data->state == RESULT_SUCCESS)
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
@@ -1282,6 +1389,7 @@ static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
data->id_msgs = NULL;
data->use_result_ind = 0;
data->kdf_negotiation = 0;
+ eap_aka_clear_keys(data, 1);
}
@@ -1340,6 +1448,28 @@ static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = data->eap_method;
+ os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_aka_data *data = priv;
@@ -1374,6 +1504,7 @@ int eap_peer_aka_register(void)
eap->process = eap_aka_process;
eap->isKeyAvailable = eap_aka_isKeyAvailable;
eap->getKey = eap_aka_getKey;
+ eap->getSessionId = eap_aka_get_session_id;
eap->has_reauth_data = eap_aka_has_reauth_data;
eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
eap->init_for_reauth = eap_aka_init_for_reauth;
@@ -1404,6 +1535,7 @@ int eap_peer_aka_prime_register(void)
eap->process = eap_aka_process;
eap->isKeyAvailable = eap_aka_isKeyAvailable;
eap->getKey = eap_aka_getKey;
+ eap->getSessionId = eap_aka_get_session_id;
eap->has_reauth_data = eap_aka_has_reauth_data;
eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
eap->init_for_reauth = eap_aka_init_for_reauth;
diff --git a/contrib/wpa/src/eap_peer/eap_config.h b/contrib/wpa/src/eap_peer/eap_config.h
index ed90919..2b1a1d5 100644
--- a/contrib/wpa/src/eap_peer/eap_config.h
+++ b/contrib/wpa/src/eap_peer/eap_config.h
@@ -1,6 +1,6 @@
/*
* EAP peer configuration data
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -157,7 +157,7 @@ struct eap_peer_config {
*
* If left out, this will be asked through control interface.
*/
- u8 *private_key_passwd;
+ char *private_key_passwd;
/**
* dh_file - File path to DH/DSA parameters file (in PEM format)
@@ -186,6 +186,10 @@ struct eap_peer_config {
* 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
+ * 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;
@@ -208,6 +212,39 @@ struct eap_peer_config {
u8 *altsubject_match;
/**
+ * domain_suffix_match - Constraint for server domain name
+ *
+ * If set, this FQDN is used as a suffix match requirement for the
+ * server certificate in SubjectAltName dNSName element(s). If a
+ * matching dNSName is found, this constraint is met. If no dNSName
+ * values are present, this constraint is matched against 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.
+ *
+ * For example, domain_suffix_match=example.com would match
+ * test.example.com but would not match test-example.com.
+ */
+ char *domain_suffix_match;
+
+ /**
+ * domain_match - Constraint for server domain name
+ *
+ * If set, this FQDN is used as a full 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 full match comparison. This behavior is similar to
+ * domain_suffix_match, but has the requirement of a full match, i.e.,
+ * 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".
+ */
+ char *domain_match;
+
+ /**
* ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
*
* This file can have one or more trusted CA certificates. If ca_cert2
@@ -271,7 +308,7 @@ struct eap_peer_config {
* This field is like private_key_passwd, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *private_key2_passwd;
+ char *private_key2_passwd;
/**
* dh_file2 - File path to DH/DSA parameters file (in PEM format)
@@ -303,6 +340,22 @@ struct eap_peer_config {
u8 *altsubject_match2;
/**
+ * domain_suffix_match2 - Constraint for server domain name
+ *
+ * This field is like domain_suffix_match, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ char *domain_suffix_match2;
+
+ /**
+ * domain_match2 - Constraint for server domain name
+ *
+ * This field is like domain_match, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ char *domain_match2;
+
+ /**
* eap_methods - Allowed EAP methods
*
* (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
@@ -365,6 +418,16 @@ struct eap_peer_config {
*
* EAP-WSC (WPS) uses following options: pin=Device_Password and
* uuid=Device_UUID
+ *
+ * For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
+ * used to configure a mode that allows EAP-Success (and EAP-Failure)
+ * without going through authentication step. Some switches use such
+ * sequence when forcing the port to be authorized/unauthorized or as a
+ * fallback option if the authentication server is unreachable. By
+ * default, wpa_supplicant discards such frames to protect against
+ * potential attacks by rogue devices, but this option can be used to
+ * disable that protection for cases where the server/authenticator does
+ * not need to be authenticated.
*/
char *phase1;
@@ -372,7 +435,9 @@ struct eap_peer_config {
* phase2 - Phase2 (inner authentication with TLS tunnel) parameters
*
* String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
- * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS.
+ * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can
+ * be used to disable MSCHAPv2 password retry in authentication failure
+ * cases.
*/
char *phase2;
@@ -634,6 +699,46 @@ struct eap_peer_config {
* password field is the name of that external entry
*/
u32 flags;
+
+ /**
+ * ocsp - Whether to use/require OCSP to check server certificate
+ *
+ * 0 = do not use OCSP stapling (TLS certificate status extension)
+ * 1 = try to use OCSP stapling, but not require response
+ * 2 = require valid OCSP stapling response
+ */
+ int ocsp;
+
+ /**
+ * external_sim_resp - Response from external SIM processing
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request external
+ * SIM/USIM processing.
+ */
+ char *external_sim_resp;
+
+ /**
+ * sim_num - User selected SIM identifier
+ *
+ * This variable is used for identifying which SIM is used if the system
+ * has more than one.
+ */
+ int sim_num;
+
+ /**
+ * openssl_ciphers - OpenSSL cipher string
+ *
+ * This is an OpenSSL specific configuration option for configuring the
+ * ciphers for this connection. If not set, the default cipher suite
+ * list is used.
+ */
+ char *openssl_ciphers;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ */
+ int erp;
};
diff --git a/contrib/wpa/src/eap_peer/eap_eke.c b/contrib/wpa/src/eap_peer/eap_eke.c
new file mode 100644
index 0000000..9fec66c
--- /dev/null
+++ b/contrib/wpa/src/eap_peer/eap_eke.c
@@ -0,0 +1,765 @@
+/*
+ * EAP peer method: EAP-EKE (RFC 6124)
+ * Copyright (c) 2013, 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/random.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+struct eap_eke_data {
+ enum {
+ IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
+ } state;
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 *peerid;
+ size_t peerid_len;
+ u8 *serverid;
+ size_t serverid_len;
+ u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+ struct eap_eke_session sess;
+ u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+ u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+ struct wpabuf *msgs;
+ u8 dhgroup; /* forced DH group or 0 to allow all supported */
+ u8 encr; /* forced encryption algorithm or 0 to allow all supported */
+ u8 prf; /* forced PRF or 0 to allow all supported */
+ u8 mac; /* forced MAC or 0 to allow all supported */
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+ switch (state) {
+ case IDENTITY:
+ return "IDENTITY";
+ case COMMIT:
+ return "COMMIT";
+ case CONFIRM:
+ return "CONFIRM";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "?";
+ }
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+ eap_eke_state_txt(data->state), eap_eke_state_txt(state));
+ data->state = state;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+ struct eap_eke_data *data;
+ const u8 *identity, *password;
+ size_t identity_len, password_len;
+ const char *phase1;
+
+ password = eap_get_config_password(sm, &password_len);
+ if (!password) {
+ wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
+ return NULL;
+ }
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ eap_eke_state(data, IDENTITY);
+
+ identity = eap_get_config_identity(sm, &identity_len);
+ if (identity) {
+ data->peerid = os_malloc(identity_len);
+ if (data->peerid == NULL) {
+ eap_eke_deinit(sm, data);
+ return NULL;
+ }
+ os_memcpy(data->peerid, identity, identity_len);
+ data->peerid_len = identity_len;
+ }
+
+ phase1 = eap_get_config_phase1(sm);
+ if (phase1) {
+ const char *pos;
+
+ pos = os_strstr(phase1, "dhgroup=");
+ if (pos) {
+ data->dhgroup = atoi(pos + 8);
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u",
+ data->dhgroup);
+ }
+
+ pos = os_strstr(phase1, "encr=");
+ if (pos) {
+ data->encr = atoi(pos + 5);
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u",
+ data->encr);
+ }
+
+ pos = os_strstr(phase1, "prf=");
+ if (pos) {
+ data->prf = atoi(pos + 4);
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u",
+ data->prf);
+ }
+
+ pos = os_strstr(phase1, "mac=");
+ if (pos) {
+ data->mac = atoi(pos + 4);
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u",
+ data->mac);
+ }
+ }
+
+ return data;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_eke_data *data = priv;
+ eap_eke_session_clean(&data->sess);
+ os_free(data->serverid);
+ os_free(data->peerid);
+ wpabuf_free(data->msgs);
+ bin_clear_free(data, sizeof(*data));
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
+ size_t length, u8 eke_exch)
+{
+ struct wpabuf *msg;
+ size_t plen;
+
+ plen = 1 + length;
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+ EAP_CODE_RESPONSE, id);
+ if (msg == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+ return NULL;
+ }
+
+ wpabuf_put_u8(msg, eke_exch);
+
+ return msg;
+}
+
+
+static int eap_eke_supp_dhgroup(u8 dhgroup)
+{
+ return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
+ dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
+ dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
+ dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
+ dhgroup == EAP_EKE_DHGROUP_EKE_16;
+}
+
+
+static int eap_eke_supp_encr(u8 encr)
+{
+ return encr == EAP_EKE_ENCR_AES128_CBC;
+}
+
+
+static int eap_eke_supp_prf(u8 prf)
+{
+ return prf == EAP_EKE_PRF_HMAC_SHA1 ||
+ prf == EAP_EKE_PRF_HMAC_SHA2_256;
+}
+
+
+static int eap_eke_supp_mac(u8 mac)
+{
+ return mac == EAP_EKE_MAC_HMAC_SHA1 ||
+ mac == EAP_EKE_MAC_HMAC_SHA2_256;
+}
+
+
+static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ u32 failure_code)
+{
+ struct wpabuf *resp;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
+ failure_code);
+
+ resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE);
+ if (resp)
+ wpabuf_put_be32(resp, failure_code);
+
+ os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+ eap_eke_session_clean(&data->sess);
+
+ eap_eke_state(data, FAILURE);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = FALSE;
+
+ return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ const u8 *payload,
+ size_t payload_len)
+{
+ struct wpabuf *resp;
+ unsigned num_prop, i;
+ const u8 *pos, *end;
+ const u8 *prop = NULL;
+ u8 idtype;
+
+ if (data->state != IDENTITY) {
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
+
+ if (payload_len < 2 + 4) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ pos = payload;
+ end = payload + payload_len;
+
+ num_prop = *pos++;
+ pos++; /* Ignore Reserved field */
+
+ if (pos + num_prop * 4 > end) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
+ num_prop);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ for (i = 0; i < num_prop; i++) {
+ const u8 *tmp = pos;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
+ i, pos[0], pos[1], pos[2], pos[3]);
+ pos += 4;
+
+ if ((data->dhgroup && data->dhgroup != *tmp) ||
+ !eap_eke_supp_dhgroup(*tmp))
+ continue;
+ tmp++;
+ if ((data->encr && data->encr != *tmp) ||
+ !eap_eke_supp_encr(*tmp))
+ continue;
+ tmp++;
+ if ((data->prf && data->prf != *tmp) ||
+ !eap_eke_supp_prf(*tmp))
+ continue;
+ tmp++;
+ if ((data->mac && data->mac != *tmp) ||
+ !eap_eke_supp_mac(*tmp))
+ continue;
+
+ prop = tmp - 3;
+ if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
+ prop[3]) < 0) {
+ prop = NULL;
+ continue;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
+ break;
+ }
+
+ if (prop == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
+ }
+
+ pos += (num_prop - i - 1) * 4;
+
+ if (pos == end) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ idtype = *pos++;
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
+ pos, end - pos);
+ os_free(data->serverid);
+ data->serverid = os_malloc(end - pos);
+ if (data->serverid == NULL) {
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ os_memcpy(data->serverid, pos, end - pos);
+ data->serverid_len = end - pos;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
+
+ resp = eap_eke_build_msg(data, eap_get_id(reqData),
+ 2 + 4 + 1 + data->peerid_len,
+ EAP_EKE_ID);
+ if (resp == NULL) {
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ wpabuf_put_u8(resp, 1); /* NumProposals */
+ wpabuf_put_u8(resp, 0); /* Reserved */
+ wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
+ wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
+ if (data->peerid)
+ wpabuf_put_data(resp, data->peerid, data->peerid_len);
+
+ wpabuf_free(data->msgs);
+ data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
+ if (data->msgs == NULL) {
+ wpabuf_free(resp);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ wpabuf_put_buf(data->msgs, reqData);
+ wpabuf_put_buf(data->msgs, resp);
+
+ eap_eke_state(data, COMMIT);
+
+ return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
+ struct eap_eke_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ const u8 *payload,
+ size_t payload_len)
+{
+ struct wpabuf *resp;
+ const u8 *pos, *end, *dhcomp;
+ size_t prot_len;
+ u8 *rpos;
+ u8 key[EAP_EKE_MAX_KEY_LEN];
+ u8 pub[EAP_EKE_MAX_DH_LEN];
+ const u8 *password;
+ size_t password_len;
+
+ if (data->state != COMMIT) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
+
+ password = eap_get_config_password(sm, &password_len);
+ if (password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+ }
+
+ pos = payload;
+ end = payload + payload_len;
+
+ if (pos + data->sess.dhcomp_len > end) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
+ pos, data->sess.dhcomp_len);
+ dhcomp = pos;
+ pos += data->sess.dhcomp_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+ /*
+ * temp = prf(0+, password)
+ * key = prf+(temp, ID_S | ID_P)
+ */
+ if (eap_eke_derive_key(&data->sess, password, password_len,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, key) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ /*
+ * y_p = g ^ x_p (mod p)
+ * x_p = random number 2 .. p-1
+ */
+ if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+ os_memset(key, 0, sizeof(key));
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
+ {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+ os_memset(key, 0, sizeof(key));
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ if (eap_eke_derive_ke_ki(&data->sess,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+ os_memset(key, 0, sizeof(key));
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
+
+ resp = eap_eke_build_msg(data, eap_get_id(reqData),
+ data->sess.dhcomp_len + data->sess.pnonce_len,
+ EAP_EKE_COMMIT);
+ if (resp == NULL) {
+ os_memset(key, 0, sizeof(key));
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ /* DHComponent_P = Encr(key, y_p) */
+ rpos = wpabuf_put(resp, data->sess.dhcomp_len);
+ if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
+ os_memset(key, 0, sizeof(key));
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ os_memset(key, 0, sizeof(key));
+
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+ rpos, data->sess.dhcomp_len);
+
+ if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
+ wpabuf_free(resp);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+ data->nonce_p, data->sess.nonce_len);
+ prot_len = wpabuf_tailroom(resp);
+ if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
+ wpabuf_put(resp, 0), &prot_len) < 0) {
+ wpabuf_free(resp);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
+ wpabuf_put(resp, 0), prot_len);
+ wpabuf_put(resp, prot_len);
+
+ /* TODO: CBValue */
+
+ if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
+ < 0) {
+ wpabuf_free(resp);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ wpabuf_put_buf(data->msgs, reqData);
+ wpabuf_put_buf(data->msgs, resp);
+
+ eap_eke_state(data, CONFIRM);
+
+ return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ const u8 *payload,
+ size_t payload_len)
+{
+ struct wpabuf *resp;
+ const u8 *pos, *end;
+ size_t prot_len;
+ u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+ u8 auth_s[EAP_EKE_MAX_HASH_LEN];
+ size_t decrypt_len;
+ u8 *auth;
+
+ if (data->state != CONFIRM) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
+ data->state);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
+
+ pos = payload;
+ end = payload + payload_len;
+
+ if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PROTO_ERROR);
+ }
+
+ decrypt_len = sizeof(nonces);
+ if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
+ nonces, &decrypt_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ }
+ if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
+ wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
+ nonces, 2 * data->sess.nonce_len);
+ if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ }
+
+ os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
+ data->sess.nonce_len);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+ data->nonce_s, data->sess.nonce_len);
+
+ if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len,
+ data->nonce_p, data->nonce_s) < 0) {
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
+ {
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
+ if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len,
+ data->sess.prf_len) != 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
+
+ resp = eap_eke_build_msg(data, eap_get_id(reqData),
+ data->sess.pnonce_len + data->sess.prf_len,
+ EAP_EKE_CONFIRM);
+ if (resp == NULL) {
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ prot_len = wpabuf_tailroom(resp);
+ if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
+ wpabuf_put(resp, 0), &prot_len) < 0) {
+ wpabuf_free(resp);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ wpabuf_put(resp, prot_len);
+
+ auth = wpabuf_put(resp, data->sess.prf_len);
+ if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
+ wpabuf_free(resp);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
+
+ if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len,
+ data->nonce_s, data->nonce_p,
+ data->msk, data->emsk) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+ wpabuf_free(resp);
+ return eap_eke_build_fail(data, ret, reqData,
+ EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ }
+
+ os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+ eap_eke_session_clean(&data->sess);
+
+ eap_eke_state(data, SUCCESS);
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
+ ret->allowNotifications = FALSE;
+
+ return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ const u8 *payload,
+ size_t payload_len)
+{
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
+
+ if (payload_len < 4) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+ } else {
+ u32 code;
+ code = WPA_GET_BE32(payload);
+ wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
+ }
+
+ return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR);
+}
+
+
+static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData)
+{
+ struct eap_eke_data *data = priv;
+ struct wpabuf *resp;
+ const u8 *pos, *end;
+ size_t len;
+ u8 eke_exch;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
+ if (pos == NULL || len < 1) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ end = pos + len;
+ eke_exch = *pos++;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ switch (eke_exch) {
+ case EAP_EKE_ID:
+ resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
+ break;
+ case EAP_EKE_COMMIT:
+ resp = eap_eke_process_commit(sm, data, ret, reqData,
+ pos, end - pos);
+ break;
+ case EAP_EKE_CONFIRM:
+ resp = eap_eke_process_confirm(data, ret, reqData,
+ pos, end - pos);
+ break;
+ case EAP_EKE_FAILURE:
+ resp = eap_eke_process_failure(data, ret, reqData,
+ pos, end - pos);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (ret->methodState == METHOD_DONE)
+ ret->allowNotifications = FALSE;
+
+ return resp;
+}
+
+
+static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_eke_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_eke_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->msk, EAP_MSK_LEN);
+ *len = EAP_MSK_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_eke_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
+int eap_peer_eke_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_eke_init;
+ eap->deinit = eap_eke_deinit;
+ eap->process = eap_eke_process;
+ eap->isKeyAvailable = eap_eke_isKeyAvailable;
+ eap->getKey = eap_eke_getKey;
+ eap->get_emsk = eap_eke_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa/src/eap_peer/eap_fast.c b/contrib/wpa/src/eap_peer/eap_fast.c
index 7ca5288..68d7fba 100644
--- a/contrib/wpa/src/eap_peer/eap_fast.c
+++ b/contrib/wpa/src/eap_peer/eap_fast.c
@@ -53,6 +53,8 @@ struct eap_fast_data {
int session_ticket_used;
u8 key_data[EAP_FAST_KEY_LEN];
+ u8 *session_id;
+ size_t id_len;
u8 emsk[EAP_EMSK_LEN];
int success;
@@ -147,14 +149,16 @@ static void * eap_fast_init(struct eap_sm *sm)
struct eap_fast_data *data;
struct eap_peer_config *config = eap_get_config(sm);
+ if (config == NULL)
+ return NULL;
+
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
data->fast_version = EAP_FAST_VERSION;
data->max_pac_list_len = 10;
- if (config && config->phase1 &&
- eap_fast_parse_phase1(data, config->phase1) < 0) {
+ if (config->phase1 && eap_fast_parse_phase1(data, config->phase1) < 0) {
eap_fast_deinit(sm, data);
return NULL;
}
@@ -194,14 +198,22 @@ static void * eap_fast_init(struct eap_sm *sm)
"workarounds");
}
+ if (!config->pac_file) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC file configured");
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+
if (data->use_pac_binary_format &&
eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
eap_fast_deinit(sm, data);
return NULL;
}
if (!data->use_pac_binary_format &&
eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to load PAC file");
eap_fast_deinit(sm, data);
return NULL;
}
@@ -238,6 +250,9 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
pac = pac->next;
eap_fast_free_pac(prev);
}
+ 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);
os_free(data);
}
@@ -754,7 +769,7 @@ static struct wpabuf * eap_fast_process_crypto_binding(
"MAC calculation", (u8 *) _bind, bind_len);
hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len,
_bind->compound_mac);
- res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
+ res = os_memcmp_const(cmac, _bind->compound_mac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
cmac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
@@ -785,6 +800,21 @@ static struct wpabuf * eap_fast_process_crypto_binding(
return NULL;
}
+ if (!data->anon_provisioning && data->phase2_success) {
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(
+ sm, &data->ssl, EAP_TYPE_FAST, &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
+ "Session-Id");
+ wpabuf_free(resp);
+ return NULL;
+ }
+ }
+
pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
pos, _bind, cmk);
@@ -1029,6 +1059,7 @@ static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm,
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
"- Provisioning completed successfully");
+ sm->expected_failure = 1;
} else {
/*
* This is PAC refreshing, i.e., normal authentication that is
@@ -1051,7 +1082,8 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
struct eap_fast_tlv_parse *tlv,
struct wpabuf **resp)
{
- int mandatory, tlv_type, len, res;
+ int mandatory, tlv_type, res;
+ size_t len;
u8 *pos, *end;
os_memset(tlv, 0, sizeof(*tlv));
@@ -1065,13 +1097,14 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return -1;
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
- "TLV type %d length %d%s",
- tlv_type, len, mandatory ? " (mandatory)" : "");
+ "TLV type %d length %u%s",
+ tlv_type, (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
if (res == -2)
@@ -1226,6 +1259,7 @@ static int eap_fast_process_decrypted(struct eap_sm *sm,
"provisioning completed successfully.");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
+ sm->expected_failure = 1;
} else {
wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
"completed successfully.");
@@ -1604,6 +1638,10 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
os_free(data);
return NULL;
}
+ os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
+ os_memset(data->emsk, 0, EAP_EMSK_LEN);
+ os_free(data->session_id);
+ data->session_id = NULL;
if (data->phase2_priv && data->phase2_method &&
data->phase2_method->init_for_reauth)
data->phase2_method->init_for_reauth(sm, data->phase2_priv);
@@ -1628,7 +1666,7 @@ static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
ret = os_snprintf(buf + len, buflen - len,
"EAP-FAST Phase2 method=%s\n",
data->phase2_method->name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
@@ -1662,6 +1700,25 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+ u8 *id;
+
+ if (!data->success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_fast_data *data = priv;
@@ -1696,6 +1753,7 @@ int eap_peer_fast_register(void)
eap->process = eap_fast_process;
eap->isKeyAvailable = eap_fast_isKeyAvailable;
eap->getKey = eap_fast_getKey;
+ eap->getSessionId = eap_fast_get_session_id;
eap->get_status = eap_fast_get_status;
#if 0
eap->has_reauth_data = eap_fast_has_reauth_data;
diff --git a/contrib/wpa/src/eap_peer/eap_fast_pac.c b/contrib/wpa/src/eap_peer/eap_fast_pac.c
index 8c480b9..89e604e 100644
--- a/contrib/wpa/src/eap_peer/eap_fast_pac.c
+++ b/contrib/wpa/src/eap_peer/eap_fast_pac.c
@@ -330,6 +330,8 @@ static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root,
static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
char *pos)
{
+ if (!pos)
+ return "Cannot parse pac type";
pac->pac_type = atoi(pos);
if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
@@ -502,28 +504,28 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
end = *buf + *buf_len;
ret = os_snprintf(*pos, end - *pos, "%s=", field);
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
*pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
ret = os_snprintf(*pos, end - *pos, "\n");
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
if (txt) {
ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
for (i = 0; i < len; i++) {
ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
}
ret = os_snprintf(*pos, end - *pos, "\n");
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
}
@@ -576,7 +578,7 @@ static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
ret = os_snprintf(*pos, *buf + *buf_len - *pos,
"START\nPAC-Type=%d\n", pac->pac_type);
- if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ if (os_snprintf_error(*buf + *buf_len - *pos, ret))
return -1;
*pos += ret;
@@ -598,7 +600,7 @@ static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
return -1;
}
ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
- if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ if (os_snprintf_error(*buf + *buf_len - *pos, ret))
return -1;
*pos += ret;
@@ -630,7 +632,7 @@ int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
return -1;
ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
- if (ret < 0 || ret >= buf + buf_len - pos) {
+ if (os_snprintf_error(buf + buf_len - pos, ret)) {
os_free(buf);
return -1;
}
@@ -712,7 +714,7 @@ static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end)
+ if (len > (unsigned int) (end - pos))
break;
if (type == PAC_TYPE_A_ID) {
@@ -797,7 +799,9 @@ int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
pos = buf + 6;
end = buf + len;
while (pos < end) {
- if (end - pos < 2 + 32 + 2 + 2)
+ u16 val;
+
+ if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2)
goto parse_fail;
pac = os_zalloc(sizeof(*pac));
@@ -808,19 +812,23 @@ int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
pos += 2;
os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
pos += EAP_FAST_PAC_KEY_LEN;
- pac->pac_opaque_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (pos + pac->pac_opaque_len + 2 > end)
+ if (val > end - pos)
goto parse_fail;
+ pac->pac_opaque_len = val;
pac->pac_opaque = os_malloc(pac->pac_opaque_len);
if (pac->pac_opaque == NULL)
goto parse_fail;
os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
pos += pac->pac_opaque_len;
- pac->pac_info_len = WPA_GET_BE16(pos);
+ if (2 > end - pos)
+ goto parse_fail;
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (pos + pac->pac_info_len > end)
+ if (val > end - pos)
goto parse_fail;
+ pac->pac_info_len = val;
pac->pac_info = os_malloc(pac->pac_info_len);
if (pac->pac_info == NULL)
goto parse_fail;
diff --git a/contrib/wpa/src/eap_peer/eap_gpsk.c b/contrib/wpa/src/eap_peer/eap_gpsk.c
index 2bd0d48..c54bf11 100644
--- a/contrib/wpa/src/eap_peer/eap_gpsk.c
+++ b/contrib/wpa/src/eap_peer/eap_gpsk.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-GPSK (RFC 5433)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,8 +23,8 @@ struct eap_gpsk_data {
size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len;
- u8 session_id;
- int session_id_set;
+ u8 session_id[128];
+ size_t id_len;
u8 *id_peer;
size_t id_peer_len;
u8 *id_server;
@@ -33,6 +33,7 @@ struct eap_gpsk_data {
int specifier; /* CSuite/Specifier */
u8 *psk;
size_t psk_len;
+ u16 forced_cipher; /* force cipher or 0 to allow all supported */
};
@@ -80,6 +81,7 @@ static void * eap_gpsk_init(struct eap_sm *sm)
struct eap_gpsk_data *data;
const u8 *identity, *password;
size_t identity_len, password_len;
+ const char *phase1;
password = eap_get_config_password(sm, &password_len);
if (password == NULL) {
@@ -103,6 +105,18 @@ static void * eap_gpsk_init(struct eap_sm *sm)
data->id_peer_len = identity_len;
}
+ phase1 = eap_get_config_phase1(sm);
+ if (phase1) {
+ const char *pos;
+
+ pos = os_strstr(phase1, "cipher=");
+ if (pos) {
+ data->forced_cipher = atoi(pos + 7);
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
+ data->forced_cipher);
+ }
+ }
+
data->psk = os_malloc(password_len);
if (data->psk == NULL) {
eap_gpsk_deinit(sm, data);
@@ -120,8 +134,11 @@ static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
struct eap_gpsk_data *data = priv;
os_free(data->id_server);
os_free(data->id_peer);
- os_free(data->psk);
- os_free(data);
+ if (data->psk) {
+ os_memset(data->psk, 0, data->psk_len);
+ os_free(data->psk);
+ }
+ bin_clear_free(data, sizeof(*data));
}
@@ -195,7 +212,9 @@ static int eap_gpsk_select_csuite(struct eap_sm *sm,
i, vendor, specifier);
if (data->vendor == EAP_GPSK_VENDOR_IETF &&
data->specifier == EAP_GPSK_CIPHER_RESERVED &&
- eap_gpsk_supported_ciphersuite(vendor, specifier)) {
+ eap_gpsk_supported_ciphersuite(vendor, specifier) &&
+ (!data->forced_cipher || data->forced_cipher == specifier))
+ {
data->vendor = vendor;
data->specifier = specifier;
}
@@ -220,6 +239,8 @@ static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
size_t *list_len,
const u8 *pos, const u8 *end)
{
+ size_t len;
+
if (pos == NULL)
return NULL;
@@ -227,23 +248,25 @@ static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
return NULL;
}
- *list_len = WPA_GET_BE16(pos);
+ len = WPA_GET_BE16(pos);
pos += 2;
- if (end - pos < (int) *list_len) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
return NULL;
}
- if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
+ if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
- (unsigned long) *list_len);
+ (unsigned long) len);
return NULL;
}
- *list = pos;
- pos += *list_len;
- if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
+ if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
return NULL;
+ *list = pos;
+ *list_len = len;
+ pos += len;
+
return pos;
}
@@ -273,6 +296,7 @@ static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
&csuite_list_len, pos, end);
if (pos == NULL) {
+ ret->methodState = METHOD_DONE;
eap_gpsk_state(data, FAILURE);
return NULL;
}
@@ -354,6 +378,21 @@ static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
return NULL;
}
+ if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
+ data->vendor, data->specifier,
+ data->rand_peer, data->rand_server,
+ data->id_peer, data->id_peer_len,
+ data->id_server, data->id_server_len,
+ EAP_TYPE_GPSK,
+ data->session_id, &data->id_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+ eap_gpsk_state(data, FAILURE);
+ wpabuf_free(resp);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+ data->session_id, data->id_len);
+
/* No PD_Payload_1 */
wpabuf_put_be16(resp, 0);
@@ -529,7 +568,7 @@ static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
return NULL;
}
- if (os_memcmp(mic, pos, miclen) != 0) {
+ if (os_memcmp_const(mic, pos, miclen) != 0) {
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
@@ -708,6 +747,24 @@ static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(data->id_len);
+ if (sid == NULL)
+ return NULL;
+ os_memcpy(sid, data->session_id, data->id_len);
+ *len = data->id_len;
+
+ return sid;
+}
+
+
int eap_peer_gpsk_register(void)
{
struct eap_method *eap;
@@ -724,6 +781,7 @@ int eap_peer_gpsk_register(void)
eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
eap->getKey = eap_gpsk_getKey;
eap->get_emsk = eap_gpsk_get_emsk;
+ eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_peer/eap_i.h b/contrib/wpa/src/eap_peer/eap_i.h
index dd94317..2d7fdea 100644
--- a/contrib/wpa/src/eap_peer/eap_i.h
+++ b/contrib/wpa/src/eap_peer/eap_i.h
@@ -1,6 +1,6 @@
/*
* EAP peer state machines internal structures (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#define EAP_I_H
#include "wpabuf.h"
+#include "utils/list.h"
#include "eap_peer/eap.h"
#include "eap_common/eap_common.h"
@@ -261,9 +262,32 @@ struct eap_method {
* private data or this function may derive the key.
*/
u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+ /**
+ * getSessionId - Get EAP method specific Session-Id
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Pointer to a variable to store Session-Id length
+ * Returns: Session-Id or %NULL if not available
+ *
+ * This function can be used to get the Session-Id from the EAP method.
+ * The Session-Id may already be stored in the method-specific private
+ * data or this function may derive the Session-Id.
+ */
+ u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
};
+struct eap_erp_key {
+ struct dl_list list;
+ size_t rRK_len;
+ size_t rIK_len;
+ u8 rRK[ERP_MAX_KEY_LEN];
+ u8 rIK[ERP_MAX_KEY_LEN];
+ u32 next_seq;
+ char keyname_nai[];
+};
+
/**
* struct eap_sm - EAP state machine data
*/
@@ -298,6 +322,8 @@ struct eap_sm {
Boolean eapKeyAvailable; /* peer to lower layer */
u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */
+ u8 *eapSessionId; /* peer to lower layer */
+ size_t eapSessionIdLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
Boolean changed;
@@ -306,6 +332,8 @@ struct eap_sm {
void *eap_method_priv;
int init_phase2;
int fast_reauth;
+ Boolean reauthInit; /* send EAP-Identity/Re-auth */
+ u32 erp_seq;
Boolean rxResp /* LEAP only */;
Boolean leap_done;
@@ -330,9 +358,16 @@ struct eap_sm {
struct wps_context *wps;
int prev_failure;
+ struct eap_peer_config *last_config;
struct ext_password_data *ext_pw;
struct wpabuf *ext_pw_buf;
+
+ int external_sim;
+
+ unsigned int expected_failure:1;
+
+ struct dl_list erp_keys; /* struct eap_erp_key */
};
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/contrib/wpa/src/eap_peer/eap_ikev2.c b/contrib/wpa/src/eap_peer/eap_ikev2.c
index a227f8b..b5ef71b 100644
--- a/contrib/wpa/src/eap_peer/eap_ikev2.c
+++ b/contrib/wpa/src/eap_peer/eap_ikev2.c
@@ -1,6 +1,6 @@
/*
* EAP-IKEv2 peer (RFC 5106)
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -60,6 +60,7 @@ static void * eap_ikev2_init(struct eap_sm *sm)
struct eap_ikev2_data *data;
const u8 *identity, *password;
size_t identity_len, password_len;
+ int fragment_size;
identity = eap_get_config_identity(sm, &identity_len);
if (identity == NULL) {
@@ -71,7 +72,11 @@ static void * eap_ikev2_init(struct eap_sm *sm)
if (data == NULL)
return NULL;
data->state = WAIT_START;
- data->fragment_size = IKEV2_FRAGMENT_SIZE;
+ fragment_size = eap_get_config_fragment_size(sm);
+ if (fragment_size <= 0)
+ data->fragment_size = IKEV2_FRAGMENT_SIZE;
+ else
+ data->fragment_size = fragment_size;
data->ikev2.state = SA_INIT;
data->ikev2.peer_auth = PEER_AUTH_SECRET;
data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
@@ -108,7 +113,7 @@ static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
wpabuf_free(data->in_buf);
wpabuf_free(data->out_buf);
ikev2_responder_deinit(&data->ikev2);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -149,12 +154,6 @@ static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
send_len -= 4;
}
}
-#ifdef CCNS_PL
- /* Some issues figuring out the length of the message if Message Length
- * field not included?! */
- if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
- flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
-#endif /* CCNS_PL */
plen = 1 + send_len;
if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
@@ -246,7 +245,8 @@ static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
const struct wpabuf *reqData,
- u8 flags, const u8 *pos, const u8 **end)
+ u8 flags, const u8 *pos, const u8 **end,
+ int frag_ack)
{
if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
int icv_len = eap_ikev2_validate_icv(
@@ -256,7 +256,7 @@ static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
return -1;
/* Hide Integrity Checksum Data from further processing */
*end -= icv_len;
- } else if (data->keys_ready) {
+ } else if (data->keys_ready && !frag_ack) {
wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
"included integrity checksum");
return -1;
@@ -301,6 +301,13 @@ static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
if (data->in_buf == NULL) {
/* First fragment of the message */
+ if (message_length > 50000) {
+ /* Limit maximum memory allocation */
+ wpa_printf(MSG_DEBUG,
+ "EAP-IKEV2: Ignore too long message");
+ ret->ignore = TRUE;
+ return NULL;
+ }
data->in_buf = wpabuf_alloc(message_length);
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
@@ -315,6 +322,7 @@ static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
(unsigned long) wpabuf_tailroom(data->in_buf));
}
+ ret->ignore = FALSE;
return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
}
@@ -346,7 +354,9 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
else
flags = *pos++;
- if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) {
+ if (eap_ikev2_process_icv(data, reqData, flags, pos, &end,
+ data->state == WAIT_FRAG_ACK && len == 0) < 0)
+ {
ret->ignore = TRUE;
return NULL;
}
@@ -373,12 +383,7 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
"Message Length %u", flags, message_length);
if (data->state == WAIT_FRAG_ACK) {
-#ifdef CCNS_PL
- if (len > 1) /* Empty Flags field included in ACK */
-#else /* CCNS_PL */
- if (len != 0)
-#endif /* CCNS_PL */
- {
+ if (len != 0) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
"in WAIT_FRAG_ACK state");
ret->ignore = TRUE;
@@ -475,6 +480,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ikev2_data *data = priv;
+ u8 *sid;
+ size_t sid_len;
+ size_t offset;
+
+ if (data->state != DONE || !data->keymat_ok)
+ return NULL;
+
+ sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+ sid = os_malloc(sid_len);
+ if (sid) {
+ offset = 0;
+ sid[offset] = EAP_TYPE_IKEV2;
+ offset++;
+ os_memcpy(sid + offset, data->ikev2.i_nonce,
+ data->ikev2.i_nonce_len);
+ offset += data->ikev2.i_nonce_len;
+ os_memcpy(sid + offset, data->ikev2.r_nonce,
+ data->ikev2.r_nonce_len);
+ *len = sid_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+ sid, sid_len);
+ }
+
+ return sid;
+}
+
+
int eap_peer_ikev2_register(void)
{
struct eap_method *eap;
@@ -492,6 +527,7 @@ int eap_peer_ikev2_register(void)
eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
eap->getKey = eap_ikev2_getKey;
eap->get_emsk = eap_ikev2_get_emsk;
+ eap->getSessionId = eap_ikev2_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_peer/eap_leap.c b/contrib/wpa/src/eap_peer/eap_leap.c
index df34013..e0f8bcf 100644
--- a/contrib/wpa/src/eap_peer/eap_leap.c
+++ b/contrib/wpa/src/eap_peer/eap_leap.c
@@ -244,7 +244,7 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
ret->methodState = METHOD_DONE;
ret->allowNotifications = FALSE;
- if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
+ if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
"response - authentication failed");
wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
@@ -383,6 +383,9 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
*len = LEAP_KEY_LEN;
+ os_memset(pw_hash, 0, sizeof(pw_hash));
+ os_memset(pw_hash_hash, 0, sizeof(pw_hash_hash));
+
return key;
}
diff --git a/contrib/wpa/src/eap_peer/eap_methods.c b/contrib/wpa/src/eap_peer/eap_methods.c
index 83a1457..1bdd81e 100644
--- a/contrib/wpa/src/eap_peer/eap_methods.c
+++ b/contrib/wpa/src/eap_peer/eap_methods.c
@@ -103,7 +103,7 @@ size_t eap_get_names(char *buf, size_t buflen)
for (m = eap_methods; m; m = m->next) {
ret = os_snprintf(pos, end - pos, "%s%s",
m == eap_methods ? "" : " ", m->name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
@@ -133,7 +133,7 @@ char ** eap_get_names_as_string_array(size_t *num)
for (m = eap_methods; m; m = m->next)
array_len++;
- array = os_zalloc(sizeof(char *) * (array_len + 1));
+ array = os_calloc(array_len + 1, sizeof(char *));
if (array == NULL)
return NULL;
diff --git a/contrib/wpa/src/eap_peer/eap_methods.h b/contrib/wpa/src/eap_peer/eap_methods.h
index 4994ff1..e35c919 100644
--- a/contrib/wpa/src/eap_peer/eap_methods.h
+++ b/contrib/wpa/src/eap_peer/eap_methods.h
@@ -86,6 +86,7 @@ static inline int eap_peer_method_unload(struct eap_method *method)
int eap_peer_md5_register(void);
int eap_peer_tls_register(void);
int eap_peer_unauth_tls_register(void);
+int eap_peer_wfa_unauth_tls_register(void);
int eap_peer_mschapv2_register(void);
int eap_peer_peap_register(void);
int eap_peer_ttls_register(void);
@@ -105,5 +106,6 @@ int eap_peer_ikev2_register(void);
int eap_peer_vendor_test_register(void);
int eap_peer_tnc_register(void);
int eap_peer_pwd_register(void);
+int eap_peer_eke_register(void);
#endif /* EAP_METHODS_H */
diff --git a/contrib/wpa/src/eap_peer/eap_mschapv2.c b/contrib/wpa/src/eap_peer/eap_mschapv2.c
index fb6c282..9e486e7 100644
--- a/contrib/wpa/src/eap_peer/eap_mschapv2.c
+++ b/contrib/wpa/src/eap_peer/eap_mschapv2.c
@@ -140,7 +140,7 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
os_free(data->peer_challenge);
os_free(data->auth_challenge);
wpabuf_free(data->prev_challenge);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -303,18 +303,23 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm,
WPA_EVENT_PASSWORD_CHANGED
"EAP-MSCHAPV2: Password changed successfully");
data->prev_error = 0;
- os_free(config->password);
+ bin_clear_free(config->password, config->password_len);
if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
/* TODO: update external storage */
} else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
config->password = os_malloc(16);
config->password_len = 16;
- if (config->password) {
- nt_password_hash(config->new_password,
- config->new_password_len,
- config->password);
+ if (config->password &&
+ nt_password_hash(config->new_password,
+ config->new_password_len,
+ config->password)) {
+ bin_clear_free(config->password,
+ config->password_len);
+ config->password = NULL;
+ config->password_len = 0;
}
- os_free(config->new_password);
+ bin_clear_free(config->new_password,
+ config->new_password_len);
} else {
config->password = config->new_password;
config->password_len = config->new_password_len;
@@ -467,6 +472,13 @@ static int eap_mschapv2_failure_txt(struct eap_sm *sm,
pos += 2;
msg = pos;
}
+ if (data->prev_error == ERROR_AUTHENTICATION_FAILURE && retry &&
+ config && config->phase2 &&
+ os_strstr(config->phase2, "mschapv2_retry=0")) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-MSCHAPV2: mark password retry disabled based on local configuration");
+ retry = 0;
+ }
wpa_msg(sm->msg_ctx, MSG_WARNING,
"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
"%d)",
@@ -549,15 +561,17 @@ static struct wpabuf * eap_mschapv2_change_password(
/* Encrypted-Hash */
if (pwhash) {
u8 new_password_hash[16];
- nt_password_hash(new_password, new_password_len,
- new_password_hash);
+ if (nt_password_hash(new_password, new_password_len,
+ new_password_hash))
+ goto fail;
nt_password_hash_encrypted_with_block(password,
new_password_hash,
cp->encr_hash);
} else {
- old_nt_password_hash_encrypted_with_new_nt_password_hash(
- new_password, new_password_len,
- password, password_len, cp->encr_hash);
+ if (old_nt_password_hash_encrypted_with_new_nt_password_hash(
+ new_password, new_password_len,
+ password, password_len, cp->encr_hash))
+ goto fail;
}
/* Peer-Challenge */
@@ -594,9 +608,13 @@ static struct wpabuf * eap_mschapv2_change_password(
/* Likewise, generate master_key here since we have the needed data
* available. */
- nt_password_hash(new_password, new_password_len, password_hash);
- hash_nt_password_hash(password_hash, password_hash_hash);
- get_master_key(password_hash_hash, cp->nt_response, data->master_key);
+ if (nt_password_hash(new_password, new_password_len, password_hash) ||
+ hash_nt_password_hash(password_hash, password_hash_hash) ||
+ get_master_key(password_hash_hash, cp->nt_response,
+ data->master_key)) {
+ data->auth_response_valid = 0;
+ goto fail;
+ }
data->master_key_valid = 1;
/* Flags */
@@ -644,10 +662,8 @@ static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
* must allocate a large enough temporary buffer to create that since
* the received message does not include nul termination.
*/
- buf = os_malloc(len + 1);
+ buf = dup_binstr(msdata, len);
if (buf) {
- os_memcpy(buf, msdata, len);
- buf[len] = '\0';
retry = eap_mschapv2_failure_txt(sm, data, buf);
os_free(buf);
}
diff --git a/contrib/wpa/src/eap_peer/eap_pax.c b/contrib/wpa/src/eap_peer/eap_pax.c
index 7f87052..6d1ff20 100644
--- a/contrib/wpa/src/eap_peer/eap_pax.c
+++ b/contrib/wpa/src/eap_peer/eap_pax.c
@@ -38,6 +38,7 @@ struct eap_pax_data {
u8 mk[EAP_PAX_MK_LEN];
u8 ck[EAP_PAX_CK_LEN];
u8 ick[EAP_PAX_ICK_LEN];
+ u8 mid[EAP_PAX_MID_LEN];
};
@@ -86,7 +87,7 @@ static void eap_pax_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
os_free(data->cid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -178,8 +179,8 @@ static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
data->rand.r.y, EAP_PAX_RAND_LEN);
if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
- data->mk, data->ck, data->ick) < 0)
- {
+ data->mk, data->ck, data->ick,
+ data->mid) < 0) {
ret->ignore = TRUE;
return NULL;
}
@@ -278,7 +279,7 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
(u8 *) data->cid, data->cid_len, NULL, 0, mac);
- if (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) {
+ if (os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
"received");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
@@ -415,7 +416,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
icvbuf);
}
- if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
+ if (os_memcmp_const(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
"message");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
@@ -501,6 +502,26 @@ static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pax_data *data = priv;
+ u8 *sid;
+
+ if (data->state != PAX_DONE)
+ return NULL;
+
+ sid = os_malloc(1 + EAP_PAX_MID_LEN);
+ if (sid == NULL)
+ return NULL;
+
+ *len = 1 + EAP_PAX_MID_LEN;
+ sid[0] = EAP_TYPE_PAX;
+ os_memcpy(sid + 1, data->mid, EAP_PAX_MID_LEN);
+
+ return sid;
+}
+
+
int eap_peer_pax_register(void)
{
struct eap_method *eap;
@@ -517,6 +538,7 @@ int eap_peer_pax_register(void)
eap->isKeyAvailable = eap_pax_isKeyAvailable;
eap->getKey = eap_pax_getKey;
eap->get_emsk = eap_pax_get_emsk;
+ eap->getSessionId = eap_pax_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_peer/eap_peap.c b/contrib/wpa/src/eap_peer/eap_peap.c
index 7fff145..86a18bb 100644
--- a/contrib/wpa/src/eap_peer/eap_peap.c
+++ b/contrib/wpa/src/eap_peer/eap_peap.c
@@ -22,7 +22,6 @@
/* Maximum supported PEAP version
* 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
* 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
- * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
*/
#define EAP_PEAP_VERSION 1
@@ -56,6 +55,8 @@ struct eap_peap_data {
int resuming; /* starting a resumed session */
int reauth; /* reauthentication */
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
struct wpabuf *pending_phase2_req;
enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
@@ -169,6 +170,15 @@ 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);
+ data->key_data = NULL;
+ }
+}
+
+
static void eap_peap_deinit(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
@@ -178,7 +188,8 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
data->phase2_method->deinit(sm, data->phase2_priv);
os_free(data->phase2_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
- os_free(data->key_data);
+ eap_peap_free_key(data);
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -312,8 +323,6 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
len[1] = 1;
tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
- if (data->peap_version >= 2)
- tlv_type |= EAP_TLV_TYPE_MANDATORY;
wpabuf_put_be16(buf, tlv_type);
wpabuf_put_be16(buf, 56);
@@ -423,7 +432,7 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
buf, sizeof(buf));
hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
- if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
"cryptobinding TLV");
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
@@ -577,33 +586,6 @@ static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
}
-static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
-{
- struct wpabuf *e;
- struct eap_tlv_hdr *tlv;
-
- if (buf == NULL)
- return NULL;
-
- /* Encapsulate EAP packet in EAP-Payload TLV */
- wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
- e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
- if (e == NULL) {
- wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
- "for TLV encapsulation");
- wpabuf_free(buf);
- return NULL;
- }
- tlv = wpabuf_put(e, sizeof(*tlv));
- tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
- EAP_TLV_EAP_PAYLOAD_TLV);
- tlv->length = host_to_be16(wpabuf_len(buf));
- wpabuf_put_buf(e, buf);
- wpabuf_free(buf);
- return e;
-}
-
-
static int eap_peap_phase2_request(struct eap_sm *sm,
struct eap_peap_data *data,
struct eap_method_ret *ret,
@@ -834,49 +816,6 @@ continue_req:
in_decrypted = nmsg;
}
- if (data->peap_version >= 2) {
- struct eap_tlv_hdr *tlv;
- struct wpabuf *nmsg;
-
- if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
- "EAP TLV");
- wpabuf_free(in_decrypted);
- return 0;
- }
- tlv = wpabuf_mhead(in_decrypted);
- if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
- EAP_TLV_EAP_PAYLOAD_TLV) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
- wpabuf_free(in_decrypted);
- return 0;
- }
- if (sizeof(*tlv) + be_to_host16(tlv->length) >
- wpabuf_len(in_decrypted)) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
- "length");
- wpabuf_free(in_decrypted);
- return 0;
- }
- hdr = (struct eap_hdr *) (tlv + 1);
- if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
- "EAP packet in EAP TLV");
- wpabuf_free(in_decrypted);
- return 0;
- }
-
- nmsg = wpabuf_alloc(be_to_host16(hdr->length));
- if (nmsg == NULL) {
- wpabuf_free(in_decrypted);
- return 0;
- }
-
- wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
- wpabuf_free(in_decrypted);
- in_decrypted = nmsg;
- }
-
hdr = wpabuf_mhead(in_decrypted);
if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
@@ -993,11 +932,6 @@ continue_req:
wpa_hexdump_buf_key(MSG_DEBUG,
"EAP-PEAP: Encrypting Phase 2 data", resp);
/* PEAP version changes */
- if (data->peap_version >= 2) {
- resp = eap_peapv2_tlv_eap_payload(resp);
- if (resp == NULL)
- return -1;
- }
if (wpabuf_len(resp) >= 5 &&
wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
eap_get_type(resp) == EAP_TYPE_TLV)
@@ -1080,7 +1014,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
char *label;
wpa_printf(MSG_DEBUG,
"EAP-PEAP: TLS done, proceed to Phase 2");
- os_free(data->key_data);
+ eap_peap_free_key(data);
/* draft-josefsson-ppext-eap-tls-eap-05.txt
* specifies that PEAPv1 would use "client PEAP
* encryption" as the label. However, most existing
@@ -1088,7 +1022,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
* label, "client EAP encryption", instead. Use the old
* label by default, but allow it to be configured with
* phase1 parameter peaplabel=1. */
- if (data->peap_version > 1 || data->force_new_label)
+ if (data->force_new_label)
label = "client PEAP encryption";
else
label = "client EAP encryption";
@@ -1107,6 +1041,20 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
"derive key");
}
+ os_free(data->session_id);
+ data->session_id =
+ eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_PEAP,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-PEAP: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
+ "derive Session-Id");
+ }
+
if (sm->workaround && data->resuming) {
/*
* At least few RADIUS servers (Aegis v1.1.6;
@@ -1176,8 +1124,9 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
- os_free(data->key_data);
- data->key_data = NULL;
+ eap_peap_free_key(data);
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -1207,7 +1156,7 @@ static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
"EAP-PEAPv%d Phase2 method=%s\n",
data->peap_version,
data->phase2_method->name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
@@ -1260,6 +1209,25 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL || !data->phase2_success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_peap_register(void)
{
struct eap_method *eap;
@@ -1279,6 +1247,7 @@ int eap_peer_peap_register(void)
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)
diff --git a/contrib/wpa/src/eap_peer/eap_proxy.h b/contrib/wpa/src/eap_peer/eap_proxy.h
new file mode 100644
index 0000000..23cdbe6
--- /dev/null
+++ b/contrib/wpa/src/eap_peer/eap_proxy.h
@@ -0,0 +1,49 @@
+/*
+ * EAP proxy definitions
+ * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PROXY_H
+#define EAP_PROXY_H
+
+struct eap_proxy_sm;
+struct eapol_callbacks;
+struct eap_sm;
+struct eap_peer_config;
+
+enum eap_proxy_status {
+ EAP_PROXY_FAILURE = 0x00,
+ EAP_PROXY_SUCCESS
+};
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx);
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy);
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm);
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len);
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm);
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm);
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+ int eapReqDataLen);
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+ int verbose);
+
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+ size_t *imsi_len);
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+ struct eap_peer_config *config);
+
+#endif /* EAP_PROXY_H */
diff --git a/contrib/wpa/src/eap_peer/eap_proxy_dummy.c b/contrib/wpa/src/eap_peer/eap_proxy_dummy.c
new file mode 100644
index 0000000..d84f012
--- /dev/null
+++ b/contrib/wpa/src/eap_peer/eap_proxy_dummy.c
@@ -0,0 +1,77 @@
+/*
+ * EAP proxy - dummy implementation for build testing
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_proxy.h"
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx)
+{
+ return NULL;
+}
+
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy)
+{
+}
+
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm)
+{
+ return 0;
+}
+
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len)
+{
+ return NULL;
+}
+
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm)
+{
+ return NULL;
+}
+
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm)
+{
+ return 0;
+}
+
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+ int eapReqDataLen)
+{
+ return EAP_PROXY_FAILURE;
+}
+
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+ int verbose)
+{
+ return 0;
+}
+
+
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+ size_t *imsi_len)
+{
+ return -1;
+}
+
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+ struct eap_peer_config *config)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/eap_peer/eap_psk.c b/contrib/wpa/src/eap_peer/eap_psk.c
index d618fcf..f012663 100644
--- a/contrib/wpa/src/eap_peer/eap_psk.c
+++ b/contrib/wpa/src/eap_peer/eap_psk.c
@@ -21,6 +21,7 @@
struct eap_psk_data {
enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
u8 rand_p[EAP_PSK_RAND_LEN];
+ u8 rand_s[EAP_PSK_RAND_LEN];
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
u8 *id_s, *id_p;
size_t id_s_len, id_p_len;
@@ -75,7 +76,7 @@ static void eap_psk_deinit(struct eap_sm *sm, void *priv)
struct eap_psk_data *data = priv;
os_free(data->id_s);
os_free(data->id_p);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -112,6 +113,7 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
EAP_PSK_RAND_LEN);
+ os_memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
os_free(data->id_s);
data->id_s_len = len - sizeof(*hdr1);
data->id_s = os_malloc(data->id_s_len);
@@ -235,7 +237,7 @@ static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
return NULL;
}
os_free(buf);
- if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
"message");
ret->methodState = METHOD_DONE;
@@ -434,6 +436,28 @@ static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_psk_data *data = priv;
+ u8 *id;
+
+ if (data->state != PSK_DONE)
+ return NULL;
+
+ *len = 1 + 2 * EAP_PSK_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_PSK;
+ os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_psk_data *data = priv;
@@ -468,6 +492,7 @@ int eap_peer_psk_register(void)
eap->process = eap_psk_process;
eap->isKeyAvailable = eap_psk_isKeyAvailable;
eap->getKey = eap_psk_getKey;
+ eap->getSessionId = eap_psk_get_session_id;
eap->get_emsk = eap_psk_get_emsk;
ret = eap_peer_method_register(eap);
diff --git a/contrib/wpa/src/eap_peer/eap_pwd.c b/contrib/wpa/src/eap_peer/eap_pwd.c
index 267d0a5..059bbee 100644
--- a/contrib/wpa/src/eap_peer/eap_pwd.c
+++ b/contrib/wpa/src/eap_peer/eap_pwd.c
@@ -16,7 +16,8 @@
struct eap_pwd_data {
enum {
- PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
+ PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req,
+ SUCCESS_ON_FRAG_COMPLETION, SUCCESS, FAILURE
} state;
u8 *id_peer;
size_t id_peer_len;
@@ -42,6 +43,7 @@ struct eap_pwd_data {
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
+ u8 session_id[1 + SHA256_MAC_LEN];
BN_CTX *bnctx;
};
@@ -57,6 +59,8 @@ static const char * eap_pwd_state_txt(int state)
return "PWD-Commit-Req";
case PWD_Confirm_Req:
return "PWD-Confirm-Req";
+ case SUCCESS_ON_FRAG_COMPLETION:
+ return "SUCCESS_ON_FRAG_COMPLETION";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -81,6 +85,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
struct eap_pwd_data *data;
const u8 *identity, *password;
size_t identity_len, password_len;
+ int fragment_size;
password = eap_get_config_password(sm, &password_len);
if (password == NULL) {
@@ -118,7 +123,7 @@ 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);
- os_free(data->id_peer);
+ bin_clear_free(data->id_peer, data->id_peer_len);
os_free(data);
return NULL;
}
@@ -127,7 +132,11 @@ static void * eap_pwd_init(struct eap_sm *sm)
data->out_frag_pos = data->in_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
- data->mtu = 1020; /* default from RFC 5931, make it configurable! */
+ fragment_size = eap_get_config_fragment_size(sm);
+ if (fragment_size <= 0)
+ data->mtu = 1020; /* default from RFC 5931 */
+ else
+ data->mtu = fragment_size;
data->state = PWD_ID_Req;
@@ -139,24 +148,26 @@ static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
- BN_free(data->private_value);
- BN_free(data->server_scalar);
- BN_free(data->my_scalar);
- BN_free(data->k);
+ BN_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_free(data->my_element);
- EC_POINT_free(data->server_element);
- os_free(data->id_peer);
- os_free(data->id_server);
- os_free(data->password);
+ EC_POINT_clear_free(data->my_element);
+ EC_POINT_clear_free(data->server_element);
+ 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_free(data->grp->pwe);
- BN_free(data->grp->order);
- BN_free(data->grp->prime);
+ EC_POINT_clear_free(data->grp->pwe);
+ BN_clear_free(data->grp->order);
+ BN_clear_free(data->grp->prime);
os_free(data->grp);
}
- os_free(data);
+ wpabuf_free(data->inbuf);
+ wpabuf_free(data->outbuf);
+ bin_clear_free(data, sizeof(*data));
}
@@ -179,6 +190,25 @@ static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pwd_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ id = os_malloc(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;
+}
+
+
static void
eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
struct eap_method_ret *ret,
@@ -222,8 +252,8 @@ 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);
- if ((data->grp = (EAP_PWD_group *) os_malloc(sizeof(EAP_PWD_group))) ==
- NULL) {
+ data->grp = os_zalloc(sizeof(EAP_PWD_group));
+ if (data->grp == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
"group");
eap_pwd_state(data, FAILURE);
@@ -287,11 +317,15 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
- BN_rand_range(data->private_value, data->grp->order);
- BN_rand_range(mask, data->grp->order);
- BN_add(data->my_scalar, data->private_value, mask);
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx);
+ if (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)) {
@@ -306,7 +340,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
goto fin;
}
- BN_free(mask);
+ BN_clear_free(mask);
if (((x = BN_new()) == NULL) ||
((y = BN_new()) == NULL)) {
@@ -441,11 +475,11 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
fin:
os_free(scalar);
os_free(element);
- BN_free(x);
- BN_free(y);
- BN_free(cofactor);
- EC_POINT_free(K);
- EC_POINT_free(point);
+ BN_clear_free(x);
+ BN_clear_free(y);
+ BN_clear_free(cofactor);
+ EC_POINT_clear_free(K);
+ EC_POINT_clear_free(point);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
else
@@ -559,7 +593,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
eap_pwd_h_final(hash, conf);
ptr = (u8 *) payload;
- if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+ if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
goto fin;
}
@@ -637,7 +671,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
if (compute_keys(data->grp, data->bnctx, data->k,
data->my_scalar, data->server_scalar, conf, ptr,
- &cs, data->msk, data->emsk) < 0) {
+ &cs, data->msk, data->emsk, data->session_id) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
"EMSK");
goto fin;
@@ -650,16 +684,15 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- os_free(cruft);
- BN_free(x);
- BN_free(y);
- ret->methodState = METHOD_DONE;
+ bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+ BN_clear_free(x);
+ BN_clear_free(y);
if (data->outbuf == NULL) {
+ ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
eap_pwd_state(data, FAILURE);
} else {
- ret->decision = DECISION_UNCOND_SUCC;
- eap_pwd_state(data, SUCCESS);
+ eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
}
}
@@ -736,6 +769,11 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
data->out_frag_pos == 0 ? "last" : "next",
(int) len);
+ if (data->state == SUCCESS_ON_FRAG_COMPLETION) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ eap_pwd_state(data, SUCCESS);
+ }
return resp;
}
@@ -748,6 +786,8 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
tot_len = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose "
"total length = %d", tot_len);
+ if (tot_len > 15000)
+ return NULL;
data->inbuf = wpabuf_alloc(tot_len);
if (data->inbuf == NULL) {
wpa_printf(MSG_INFO, "Out of memory to buffer "
@@ -768,6 +808,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
(int) data->in_frag_pos,
(int) wpabuf_len(data->inbuf));
wpabuf_free(data->inbuf);
+ data->inbuf = NULL;
data->in_frag_pos = 0;
return NULL;
}
@@ -819,11 +860,15 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
*/
if (data->in_frag_pos) {
wpabuf_free(data->inbuf);
+ data->inbuf = NULL;
data->in_frag_pos = 0;
}
- if (data->outbuf == NULL)
+ if (data->outbuf == NULL) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
return NULL; /* generic failure */
+ }
/*
* we have output! Do we need to fragment it?
@@ -866,6 +911,11 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
wpabuf_free(data->outbuf);
data->outbuf = NULL;
data->out_frag_pos = 0;
+ if (data->state == SUCCESS_ON_FRAG_COMPLETION) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ eap_pwd_state(data, SUCCESS);
+ }
}
return resp;
@@ -902,7 +952,6 @@ int eap_peer_pwd_register(void)
struct eap_method *eap;
int ret;
- EVP_add_digest(EVP_sha256());
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
if (eap == NULL)
@@ -913,6 +962,7 @@ int eap_peer_pwd_register(void)
eap->process = eap_pwd_process;
eap->isKeyAvailable = eap_pwd_key_available;
eap->getKey = eap_pwd_getkey;
+ eap->getSessionId = eap_pwd_get_session_id;
eap->get_emsk = eap_pwd_get_emsk;
ret = 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 e072f46..7d14907 100644
--- a/contrib/wpa/src/eap_peer/eap_sake.c
+++ b/contrib/wpa/src/eap_peer/eap_sake.c
@@ -108,7 +108,7 @@ static void eap_sake_deinit(struct eap_sm *sm, void *priv)
struct eap_sake_data *data = priv;
os_free(data->serverid);
os_free(data->peerid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -315,7 +315,7 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
data->peerid, data->peerid_len, 0,
wpabuf_head(reqData), wpabuf_len(reqData),
attr.mic_s, mic_s);
- if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
+ 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);
ret->methodState = METHOD_DONE;
@@ -452,6 +452,28 @@ static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_SAKE_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SAKE;
+ os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
+ os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_sake_data *data = priv;
@@ -485,6 +507,7 @@ int eap_peer_sake_register(void)
eap->process = eap_sake_process;
eap->isKeyAvailable = eap_sake_isKeyAvailable;
eap->getKey = eap_sake_getKey;
+ eap->getSessionId = eap_sake_get_session_id;
eap->get_emsk = eap_sake_get_emsk;
ret = eap_peer_method_register(eap);
diff --git a/contrib/wpa/src/eap_peer/eap_sim.c b/contrib/wpa/src/eap_peer/eap_sim.c
index c936a44..bd06df7 100644
--- a/contrib/wpa/src/eap_peer/eap_sim.c
+++ b/contrib/wpa/src/eap_peer/eap_sim.c
@@ -43,7 +43,7 @@ struct eap_sim_data {
u8 *last_eap_identity;
size_t last_eap_identity_len;
enum {
- CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
+ CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
int result_ind, use_result_ind;
};
@@ -57,8 +57,6 @@ static const char * eap_sim_state_txt(int state)
return "CONTINUE";
case RESULT_SUCCESS:
return "RESULT_SUCCESS";
- case RESULT_FAILURE:
- return "RESULT_FAILURE";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -132,6 +130,20 @@ static void * eap_sim_init(struct eap_sm *sm)
}
+static void eap_sim_clear_keys(struct eap_sim_data *data, int reauth)
+{
+ if (!reauth) {
+ os_memset(data->mk, 0, EAP_SIM_MK_LEN);
+ os_memset(data->k_aut, 0, EAP_SIM_K_AUT_LEN);
+ os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
+ }
+ os_memset(data->kc, 0, 3 * EAP_SIM_KC_LEN);
+ os_memset(data->sres, 0, 3 * EAP_SIM_SRES_LEN);
+ os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
+ os_memset(data->emsk, 0, EAP_EMSK_LEN);
+}
+
+
static void eap_sim_deinit(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
@@ -140,11 +152,86 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv)
os_free(data->pseudonym);
os_free(data->reauth_id);
os_free(data->last_eap_identity);
+ eap_sim_clear_keys(data, 0);
os_free(data);
}
}
+static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data)
+{
+ char req[200], *pos, *end;
+ size_t i;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing");
+ pos = req;
+ end = pos + sizeof(req);
+ pos += os_snprintf(pos, end - pos, "GSM-AUTH");
+ for (i = 0; i < data->num_chal; i++) {
+ pos += os_snprintf(pos, end - pos, ":");
+ pos += wpa_snprintf_hex(pos, end - pos, data->rand[i],
+ GSM_RAND_LEN);
+ }
+
+ eap_sm_request_sim(sm, req);
+ return 1;
+}
+
+
+static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data,
+ struct eap_peer_config *conf)
+{
+ char *resp, *pos;
+ size_t i;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Use result from external SIM processing");
+
+ resp = conf->external_sim_resp;
+ conf->external_sim_resp = NULL;
+
+ if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response");
+ os_free(resp);
+ return -1;
+ }
+
+ pos = resp + 9;
+ for (i = 0; i < data->num_chal; i++) {
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
+ data->rand[i], GSM_RAND_LEN);
+
+ if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0)
+ goto invalid;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
+ data->kc[i], EAP_SIM_KC_LEN);
+ pos += EAP_SIM_KC_LEN * 2;
+ if (*pos != ':')
+ goto invalid;
+ pos++;
+
+ if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0)
+ goto invalid;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
+ data->sres[i], EAP_SIM_SRES_LEN);
+ pos += EAP_SIM_SRES_LEN * 2;
+ if (i + 1 < data->num_chal) {
+ if (*pos != ':')
+ goto invalid;
+ pos++;
+ }
+ }
+
+ os_free(resp);
+ return 0;
+
+invalid:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response");
+ os_free(resp);
+ return -1;
+}
+
+
static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
{
struct eap_peer_config *conf;
@@ -154,6 +241,14 @@ static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
conf = eap_get_config(sm);
if (conf == NULL)
return -1;
+
+ if (sm->external_sim) {
+ if (conf->external_sim_resp)
+ return eap_sim_ext_sim_result(sm, data, conf);
+ else
+ return eap_sim_ext_sim_req(sm, data);
+ }
+
if (conf->pcsc) {
if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
data->sres[0], data->kc[0]) ||
@@ -369,7 +464,7 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
}
@@ -422,7 +517,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
identity, identity_len);
}
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
}
@@ -440,7 +535,8 @@ static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
+ (u8 *) data->sres,
data->num_chal * EAP_SIM_SRES_LEN);
}
@@ -482,7 +578,7 @@ static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, nonce_s,
EAP_SIM_NONCE_S_LEN);
}
@@ -516,7 +612,7 @@ static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, k_aut, (u8 *) "", 0);
}
@@ -605,6 +701,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
const u8 *identity;
size_t identity_len;
struct eap_sim_attrs eattr;
+ int res;
wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
data->reauth = 0;
@@ -648,8 +745,13 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
data->num_chal = attr->num_chal;
-
- if (eap_sim_gsm_auth(sm, data)) {
+
+ res = eap_sim_gsm_auth(sm, data);
+ if (res > 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing");
+ return NULL;
+ }
+ if (res) {
wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
return eap_sim_client_error(data, id,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
@@ -700,7 +802,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_sim_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -864,9 +966,11 @@ static struct wpabuf * eap_sim_process_reauthentication(
}
if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
+ struct wpabuf *res;
wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
"(%d <= %d)", eattr.counter, data->counter);
data->counter_too_small = eattr.counter;
+
/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
* reauth_id must not be used to start a new reauthentication.
* However, since it was used in the last EAP-Response-Identity
@@ -877,8 +981,11 @@ static struct wpabuf * eap_sim_process_reauthentication(
data->last_eap_identity_len = data->reauth_id_len;
data->reauth_id = NULL;
data->reauth_id_len = 0;
+
+ res = eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
os_free(decrypted);
- return eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
+
+ return res;
}
data->counter = eattr.counter;
@@ -896,7 +1003,7 @@ static struct wpabuf * eap_sim_process_reauthentication(
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_sim_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -995,9 +1102,7 @@ done:
DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
ret->methodState = data->use_result_ind ?
METHOD_DONE : METHOD_MAY_CONT;
- } else if (data->state == RESULT_FAILURE)
- ret->methodState = METHOD_CONT;
- else if (data->state == RESULT_SUCCESS)
+ } else if (data->state == RESULT_SUCCESS)
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
@@ -1020,6 +1125,7 @@ static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
struct eap_sim_data *data = priv;
eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
data->use_result_ind = 0;
+ eap_sim_clear_keys(data, 1);
}
@@ -1084,6 +1190,29 @@ static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SIM;
+ os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+ os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
+ EAP_SIM_NONCE_MT_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_sim_data *data = priv;
@@ -1118,6 +1247,7 @@ int eap_peer_sim_register(void)
eap->process = eap_sim_process;
eap->isKeyAvailable = eap_sim_isKeyAvailable;
eap->getKey = eap_sim_getKey;
+ eap->getSessionId = eap_sim_get_session_id;
eap->has_reauth_data = eap_sim_has_reauth_data;
eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
eap->init_for_reauth = eap_sim_init_for_reauth;
diff --git a/contrib/wpa/src/eap_peer/eap_tls.c b/contrib/wpa/src/eap_peer/eap_tls.c
index 061a72b..5aa3fd5 100644
--- a/contrib/wpa/src/eap_peer/eap_tls.c
+++ b/contrib/wpa/src/eap_peer/eap_tls.c
@@ -21,6 +21,8 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv);
struct eap_tls_data {
struct eap_ssl_data ssl;
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
void *ssl_ctx;
u8 eap_type;
};
@@ -96,13 +98,50 @@ static void * eap_unauth_tls_init(struct eap_sm *sm)
#endif /* EAP_UNAUTH_TLS */
+#ifdef CONFIG_HS20
+static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+
+ data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+ sm->ssl_ctx;
+
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
+ EAP_WFA_UNAUTH_TLS_TYPE)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+ eap_tls_deinit(sm, data);
+ return NULL;
+ }
+
+ data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
+
+ return data;
+}
+#endif /* CONFIG_HS20 */
+
+
+static void eap_tls_free_key(struct eap_tls_data *data)
+{
+ if (data->key_data) {
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ data->key_data = NULL;
+ }
+}
+
+
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
if (data == NULL)
return;
eap_peer_tls_ssl_deinit(sm, &data->ssl);
- os_free(data->key_data);
+ eap_tls_free_key(data);
+ os_free(data->session_id);
os_free(data);
}
@@ -151,7 +190,7 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- os_free(data->key_data);
+ eap_tls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
"client EAP encryption",
EAP_TLS_KEY_LEN +
@@ -165,6 +204,17 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
} else {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
}
+
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_TLS,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
+ }
}
@@ -226,8 +276,9 @@ static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
- os_free(data->key_data);
- data->key_data = NULL;
+ eap_tls_free_key(data);
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -289,6 +340,25 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_tls_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_tls_register(void)
{
struct eap_method *eap;
@@ -304,6 +374,7 @@ int eap_peer_tls_register(void)
eap->process = eap_tls_process;
eap->isKeyAvailable = eap_tls_isKeyAvailable;
eap->getKey = eap_tls_getKey;
+ eap->getSessionId = eap_tls_get_session_id;
eap->get_status = eap_tls_get_status;
eap->has_reauth_data = eap_tls_has_reauth_data;
eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
@@ -346,3 +417,35 @@ int eap_peer_unauth_tls_register(void)
return ret;
}
#endif /* EAP_UNAUTH_TLS */
+
+
+#ifdef CONFIG_HS20
+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,
+ EAP_VENDOR_WFA_UNAUTH_TLS,
+ "WFA-UNAUTH-TLS");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_wfa_unauth_tls_init;
+ eap->deinit = eap_tls_deinit;
+ eap->process = eap_tls_process;
+ eap->isKeyAvailable = eap_tls_isKeyAvailable;
+ eap->getKey = eap_tls_getKey;
+ eap->get_status = eap_tls_get_status;
+ eap->has_reauth_data = eap_tls_has_reauth_data;
+ eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+ eap->init_for_reauth = eap_tls_init_for_reauth;
+ eap->get_emsk = eap_tls_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
+#endif /* 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 aedd85a..8710781 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, 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,10 @@ static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
code, identifier);
+ if (type == EAP_WFA_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
+ EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
+ code, identifier);
return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
identifier);
}
@@ -64,6 +68,14 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
if (os_strstr(txt, "tls_disable_session_ticket=0"))
params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
+ 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"))
+ params->flags &= ~TLS_CONN_DISABLE_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"))
+ params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
}
@@ -78,6 +90,8 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
params->dh_file = (char *) config->dh_file;
params->subject_match = (char *) config->subject_match;
params->altsubject_match = (char *) config->altsubject_match;
+ params->suffix_match = config->domain_suffix_match;
+ params->domain_match = config->domain_match;
params->engine = config->engine;
params->engine_id = config->engine_id;
params->pin = config->pin;
@@ -99,6 +113,8 @@ static void eap_tls_params_from_conf2(struct tls_connection_params *params,
params->dh_file = (char *) config->dh_file2;
params->subject_match = (char *) config->subject_match2;
params->altsubject_match = (char *) config->altsubject_match2;
+ params->suffix_match = config->domain_suffix_match2;
+ params->domain_match = config->domain_match2;
params->engine = config->engine2;
params->engine_id = config->engine2_id;
params->pin = config->pin2;
@@ -133,6 +149,8 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
} else {
wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
eap_tls_params_from_conf1(params, config);
+ if (data->eap_type == EAP_TYPE_FAST)
+ params->flags |= TLS_CONN_EAP_FAST;
}
/*
@@ -153,6 +171,8 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
return -1;
}
+ params->openssl_ciphers = config->openssl_ciphers;
+
return 0;
}
@@ -164,6 +184,10 @@ static int eap_tls_init_connection(struct eap_sm *sm,
{
int res;
+ if (config->ocsp)
+ params->flags |= TLS_CONN_REQUEST_OCSP;
+ if (config->ocsp == 2)
+ params->flags |= TLS_CONN_REQUIRE_OCSP;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
@@ -340,6 +364,47 @@ fail:
/**
+ * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len)
+{
+ struct tls_keys keys;
+ u8 *out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+
+ if (keys.client_random == NULL || keys.server_random == NULL)
+ return NULL;
+
+ *len = 1 + keys.client_random_len + keys.server_random_len;
+ out = os_malloc(*len);
+ if (out == NULL)
+ return NULL;
+
+ /* Session-Id = EAP type || client.random || server.random */
+ out[0] = eap_type;
+ os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+ os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ return out;
+}
+
+
+/**
* eap_peer_tls_reassemble_fragment - Reassemble a received fragment
* @data: Data for TLS processing
* @in_data: Next incoming TLS segment
@@ -731,8 +796,11 @@ int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
{
ret = os_snprintf(buf + len, buflen - len,
- "EAP TLS cipher=%s\n", name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ "EAP TLS cipher=%s\n"
+ "tls_session_reused=%d\n",
+ name, tls_connection_resumed(data->ssl_ctx,
+ data->conn));
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
@@ -786,6 +854,10 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
&left);
+ else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
+ EAP_VENDOR_WFA_UNAUTH_TLS, reqData,
+ &left);
else
pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
&left);
diff --git a/contrib/wpa/src/eap_peer/eap_tls_common.h b/contrib/wpa/src/eap_peer/eap_tls_common.h
index 91d3a25..390c216 100644
--- a/contrib/wpa/src/eap_peer/eap_tls_common.h
+++ b/contrib/wpa/src/eap_peer/eap_tls_common.h
@@ -87,6 +87,7 @@ struct eap_ssl_data {
/* dummy type used as a flag for UNAUTH-TLS */
#define EAP_UNAUTH_TLS_TYPE 255
+#define EAP_WFA_UNAUTH_TLS_TYPE 254
int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
@@ -94,6 +95,9 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len);
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
EapType eap_type, int peap_version,
u8 id, const u8 *in_data, size_t in_len,
diff --git a/contrib/wpa/src/eap_peer/eap_tnc.c b/contrib/wpa/src/eap_peer/eap_tnc.c
index bc13647..25b9f12 100644
--- a/contrib/wpa/src/eap_peer/eap_tnc.c
+++ b/contrib/wpa/src/eap_peer/eap_tnc.c
@@ -243,7 +243,8 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
message_length = WPA_GET_BE32(pos);
pos += 4;
- if (message_length < (u32) (end - pos)) {
+ if (message_length < (u32) (end - pos) ||
+ message_length > 75000) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
diff --git a/contrib/wpa/src/eap_peer/eap_ttls.c b/contrib/wpa/src/eap_peer/eap_ttls.c
index 9360a42..b5c028b 100644
--- a/contrib/wpa/src/eap_peer/eap_ttls.c
+++ b/contrib/wpa/src/eap_peer/eap_ttls.c
@@ -54,6 +54,8 @@ struct eap_ttls_data {
int resuming; /* starting a resumed session */
int reauth; /* reauthentication */
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
struct wpabuf *pending_phase2_req;
@@ -131,6 +133,15 @@ static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
}
+static void eap_ttls_free_key(struct eap_ttls_data *data)
+{
+ if (data->key_data) {
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ data->key_data = NULL;
+ }
+}
+
+
static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
@@ -139,7 +150,8 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
eap_ttls_phase2_eap_deinit(sm, data);
os_free(data->phase2_eap_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
- os_free(data->key_data);
+ eap_ttls_free_key(data);
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -210,10 +222,11 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
static int eap_ttls_v0_derive_key(struct eap_sm *sm,
struct eap_ttls_data *data)
{
- os_free(data->key_data);
+ eap_ttls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
"ttls keying material",
- EAP_TLS_KEY_LEN);
+ EAP_TLS_KEY_LEN +
+ EAP_EMSK_LEN);
if (!data->key_data) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
return -1;
@@ -221,6 +234,20 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
data->key_data, EAP_TLS_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+ data->key_data + EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
+
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_TTLS,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
+ }
return 0;
}
@@ -478,16 +505,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
wpabuf_put(msg, pos - buf);
*resp = msg;
- if (sm->workaround) {
- /* At least FreeRADIUS seems to be terminating
- * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
- * packet. */
- wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
- "allow success without tunneled response");
- ret->methodState = METHOD_MAY_CONT;
- ret->decision = DECISION_COND_SUCC;
- }
-
return 0;
#else /* EAP_MSCHAPv2 */
wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
@@ -978,6 +995,7 @@ 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);
return -1;
}
wpabuf_free(resp);
@@ -1526,8 +1544,9 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
- os_free(data->key_data);
- data->key_data = NULL;
+ eap_ttls_free_key(data);
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -1553,7 +1572,7 @@ static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
ret = os_snprintf(buf + len, buflen - len,
"EAP-TTLSv%d Phase2 method=",
data->ttls_version);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
switch (data->phase2_type) {
@@ -1578,7 +1597,7 @@ static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
ret = 0;
break;
}
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -1612,6 +1631,44 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL || !data->phase2_success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
+static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *key;
+
+ if (data->key_data == NULL)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+
+ return key;
+}
+
+
int eap_peer_ttls_register(void)
{
struct eap_method *eap;
@@ -1627,10 +1684,12 @@ int eap_peer_ttls_register(void)
eap->process = eap_ttls_process;
eap->isKeyAvailable = eap_ttls_isKeyAvailable;
eap->getKey = eap_ttls_getKey;
+ eap->getSessionId = eap_ttls_get_session_id;
eap->get_status = eap_ttls_get_status;
eap->has_reauth_data = eap_ttls_has_reauth_data;
eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
eap->init_for_reauth = eap_ttls_init_for_reauth;
+ eap->get_emsk = eap_ttls_get_emsk;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_peer/eap_vendor_test.c b/contrib/wpa/src/eap_peer/eap_vendor_test.c
index 040d1e7..b61057e 100644
--- a/contrib/wpa/src/eap_peer/eap_vendor_test.c
+++ b/contrib/wpa/src/eap_peer/eap_vendor_test.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: Test method for vendor specific (expanded) EAP type
- * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,31 +14,36 @@
#include "common.h"
#include "eap_i.h"
-#ifdef TEST_PENDING_REQUEST
#include "eloop.h"
-#endif /* TEST_PENDING_REQUEST */
#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
#define EAP_VENDOR_TYPE 0xfcfbfaf9
-/* #define TEST_PENDING_REQUEST */
-
struct eap_vendor_test_data {
enum { INIT, CONFIRM, SUCCESS } state;
int first_try;
+ int test_pending_req;
};
static void * eap_vendor_test_init(struct eap_sm *sm)
{
struct eap_vendor_test_data *data;
+ const u8 *password;
+ size_t password_len;
+
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
data->state = INIT;
data->first_try = 1;
+
+ password = eap_get_config_password(sm, &password_len);
+ data->test_pending_req = password && password_len == 7 &&
+ os_memcmp(password, "pending", 7) == 0;
+
return data;
}
@@ -50,7 +55,6 @@ static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv)
}
-#ifdef TEST_PENDING_REQUEST
static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
{
struct eap_sm *sm = eloop_ctx;
@@ -58,7 +62,6 @@ static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
"request");
eap_notify_pending(sm);
}
-#endif /* TEST_PENDING_REQUEST */
static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
@@ -98,8 +101,7 @@ static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
}
if (data->state == CONFIRM) {
-#ifdef TEST_PENDING_REQUEST
- if (data->first_try) {
+ if (data->test_pending_req && data->first_try) {
data->first_try = 0;
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
"pending request");
@@ -108,7 +110,6 @@ static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
NULL);
return NULL;
}
-#endif /* TEST_PENDING_REQUEST */
}
ret->ignore = FALSE;
diff --git a/contrib/wpa/src/eap_peer/eap_wsc.c b/contrib/wpa/src/eap_peer/eap_wsc.c
index d007a57..7ce0a53 100644
--- a/contrib/wpa/src/eap_peer/eap_wsc.c
+++ b/contrib/wpa/src/eap_peer/eap_wsc.c
@@ -77,35 +77,47 @@ static int eap_wsc_new_ap_settings(struct wps_credential *cred,
else
len = end - pos;
if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
- hexstr2bin(pos, cred->ssid, len / 2))
+ hexstr2bin(pos, cred->ssid, len / 2)) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid");
return -1;
+ }
cred->ssid_len = len / 2;
pos = os_strstr(params, "new_auth=");
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth");
return -1;
+ }
if (os_strncmp(pos + 9, "OPEN", 4) == 0)
cred->auth_type = WPS_AUTH_OPEN;
else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
cred->auth_type = WPS_AUTH_WPAPSK;
else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
cred->auth_type = WPS_AUTH_WPA2PSK;
- else
+ else {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth");
return -1;
+ }
pos = os_strstr(params, "new_encr=");
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr");
return -1;
+ }
if (os_strncmp(pos + 9, "NONE", 4) == 0)
cred->encr_type = WPS_ENCR_NONE;
+#ifdef CONFIG_TESTING_OPTIONS
else if (os_strncmp(pos + 9, "WEP", 3) == 0)
cred->encr_type = WPS_ENCR_WEP;
+#endif /* CONFIG_TESTING_OPTIONS */
else if (os_strncmp(pos + 9, "TKIP", 4) == 0)
cred->encr_type = WPS_ENCR_TKIP;
else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
cred->encr_type = WPS_ENCR_AES;
- else
+ else {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr");
return -1;
+ }
pos = os_strstr(params, "new_key=");
if (pos == NULL)
@@ -117,8 +129,10 @@ static int eap_wsc_new_ap_settings(struct wps_credential *cred,
else
len = end - pos;
if ((len & 1) || len > 2 * sizeof(cred->key) ||
- hexstr2bin(pos, cred->key, len / 2))
+ hexstr2bin(pos, cred->key, len / 2)) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key");
return -1;
+ }
cred->key_len = len / 2;
return 1;
@@ -132,13 +146,13 @@ static void * eap_wsc_init(struct eap_sm *sm)
size_t identity_len;
int registrar;
struct wps_config cfg;
- const char *pos;
+ const char *pos, *end;
const char *phase1;
struct wps_context *wps;
struct wps_credential new_ap_settings;
int res;
- u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
int nfc = 0;
+ u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN];
wps = sm->wps;
if (wps == NULL) {
@@ -186,15 +200,8 @@ static void * eap_wsc_init(struct eap_sm *sm)
while (*pos != '\0' && *pos != ' ')
pos++;
cfg.pin_len = pos - (const char *) cfg.pin;
- if (cfg.pin_len >= WPS_OOB_DEVICE_PASSWORD_MIN_LEN * 2 &&
- cfg.pin_len <= WPS_OOB_DEVICE_PASSWORD_LEN * 2 &&
- hexstr2bin((const char *) cfg.pin, dev_pw,
- cfg.pin_len / 2) == 0) {
- /* Convert OOB Device Password to binary */
- cfg.pin = dev_pw;
- cfg.pin_len /= 2;
- }
- if (cfg.pin_len == 6 && os_strncmp(pos, "nfc-pw", 6) == 0) {
+ if (cfg.pin_len == 6 &&
+ os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) {
cfg.pin = NULL;
cfg.pin_len = 0;
nfc = 1;
@@ -205,6 +212,15 @@ static void * eap_wsc_init(struct eap_sm *sm)
cfg.pbc = 1;
}
+ pos = os_strstr(phase1, "dev_pw_id=");
+ if (pos) {
+ u16 id = atoi(pos + 10);
+ if (id == DEV_PW_NFC_CONNECTION_HANDOVER)
+ nfc = 1;
+ if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER)
+ cfg.dev_pw_id = id;
+ }
+
if (cfg.pin == NULL && !cfg.pbc && !nfc) {
wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
"configuration data");
@@ -212,13 +228,29 @@ static void * eap_wsc_init(struct eap_sm *sm)
return NULL;
}
- pos = os_strstr(phase1, "dev_pw_id=");
- if (pos && cfg.pin)
- cfg.dev_pw_id = atoi(pos + 10);
+ pos = os_strstr(phase1, " pkhash=");
+ if (pos) {
+ size_t len;
+ pos += 8;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN ||
+ hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) {
+ wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash");
+ os_free(data);
+ return NULL;
+ }
+ cfg.peer_pubkey_hash = pkhash;
+ }
res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
if (res < 0) {
os_free(data);
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
+ "settings");
return NULL;
}
if (res == 1) {
@@ -230,6 +262,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
+ wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
return NULL;
}
res = eap_get_config_fragment_size(sm);
@@ -429,7 +462,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
message_length = WPA_GET_BE16(pos);
pos += 2;
- if (message_length < end - pos) {
+ if (message_length < end - pos || message_length > 50000) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
"Length");
ret->ignore = TRUE;
diff --git a/contrib/wpa/src/eap_peer/ikev2.c b/contrib/wpa/src/eap_peer/ikev2.c
index fcf4712..55ab72a 100644
--- a/contrib/wpa/src/eap_peer/ikev2.c
+++ b/contrib/wpa/src/eap_peer/ikev2.c
@@ -72,27 +72,10 @@ static int ikev2_derive_keys(struct ikev2_responder_data *data)
os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
pos += IKEV2_SPI_LEN;
os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
-#ifdef CCNS_PL
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- {
- int i;
- u8 *tmp = pos - IKEV2_SPI_LEN;
- /* Incorrect byte re-ordering on little endian hosts.. */
- for (i = 0; i < IKEV2_SPI_LEN; i++)
- *tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i];
- for (i = 0; i < IKEV2_SPI_LEN; i++)
- *tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i];
- }
-#endif
-#endif /* CCNS_PL */
/* SKEYSEED = prf(Ni | Nr, g^ir) */
/* Use zero-padding per RFC 4306, Sect. 2.14 */
pad_len = data->dh->prime_len - wpabuf_len(shared);
-#ifdef CCNS_PL
- /* Shared secret is not zero-padded correctly */
- pad_len = 0;
-#endif /* CCNS_PL */
pad = os_zalloc(pad_len ? pad_len : 1);
if (pad == NULL) {
wpabuf_free(shared);
@@ -179,21 +162,12 @@ static int ikev2_parse_transform(struct ikev2_proposal_data *prop,
"Transform Attr for AES");
break;
}
-#ifdef CCNS_PL
- if (WPA_GET_BE16(pos) != 0x001d /* ?? */) {
- wpa_printf(MSG_DEBUG, "IKEV2: Not a "
- "Key Size attribute for "
- "AES");
- break;
- }
-#else /* CCNS_PL */
if (WPA_GET_BE16(pos) != 0x800e) {
wpa_printf(MSG_DEBUG, "IKEV2: Not a "
"Key Size attribute for "
"AES");
break;
}
-#endif /* CCNS_PL */
if (WPA_GET_BE16(pos + 2) != 128) {
wpa_printf(MSG_DEBUG, "IKEV2: "
"Unsupported AES key size "
@@ -239,7 +213,7 @@ static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
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;
@@ -395,7 +369,7 @@ static int ikev2_process_kei(struct ikev2_responder_data *data,
}
if (kei_len < 4 + 96) {
- wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
+ wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload");
return -1;
}
@@ -456,14 +430,6 @@ static int ikev2_process_ni(struct ikev2_responder_data *data,
return -1;
}
-#ifdef CCNS_PL
- /* Zeros are removed incorrectly from the beginning of the nonces */
- while (ni_len > 1 && *ni == 0) {
- ni_len--;
- ni++;
- }
-#endif /* CCNS_PL */
-
data->i_nonce_len = ni_len;
os_memcpy(data->i_nonce, ni, ni_len);
wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni",
@@ -599,7 +565,7 @@ static int ikev2_process_auth_secret(struct ikev2_responder_data *data,
return -1;
if (auth_len != prf->hash_len ||
- os_memcmp(auth, auth_data, auth_len) != 0) {
+ os_memcmp_const(auth, auth_data, auth_len) != 0) {
wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
auth, auth_len);
@@ -887,16 +853,7 @@ static int ikev2_build_sar1(struct ikev2_responder_data *data,
phdr->flags = 0;
p = wpabuf_put(msg, sizeof(*p));
-#ifdef CCNS_PL
- /* Seems to require that the Proposal # is 1 even though RFC 4306
- * Sect 3.3.1 has following requirement "When a proposal is accepted,
- * all of the proposal numbers in the SA payload MUST be the same and
- * MUST match the number on the proposal sent that was accepted.".
- */
- p->proposal_num = 1;
-#else /* CCNS_PL */
p->proposal_num = data->proposal.proposal_num;
-#endif /* CCNS_PL */
p->protocol_id = IKEV2_PROTOCOL_IKE;
p->num_transforms = 4;
@@ -906,11 +863,7 @@ static int ikev2_build_sar1(struct ikev2_responder_data *data,
WPA_PUT_BE16(t->transform_id, data->proposal.encr);
if (data->proposal.encr == ENCR_AES_CBC) {
/* Transform Attribute: Key Len = 128 bits */
-#ifdef CCNS_PL
- wpabuf_put_be16(msg, 0x001d); /* ?? */
-#else /* CCNS_PL */
wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
-#endif /* CCNS_PL */
wpabuf_put_be16(msg, 128); /* 128-bit key */
}
plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
@@ -1082,11 +1035,7 @@ static int ikev2_build_notification(struct ikev2_responder_data *data,
phdr = wpabuf_put(msg, sizeof(*phdr));
phdr->next_payload = next_payload;
phdr->flags = 0;
-#ifdef CCNS_PL
- wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */
-#else /* CCNS_PL */
wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */
-#endif /* CCNS_PL */
wpabuf_put_u8(msg, 0); /* SPI Size */
wpabuf_put_be16(msg, data->error_type);
@@ -1130,13 +1079,6 @@ static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data)
data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
if (random_get_bytes(data->r_nonce, data->r_nonce_len))
return NULL;
-#ifdef CCNS_PL
- /* Zeros are removed incorrectly from the beginning of the nonces in
- * key derivation; as a workaround, make sure Nr does not start with
- * zero.. */
- if (data->r_nonce[0] == 0)
- data->r_nonce[0] = 1;
-#endif /* CCNS_PL */
wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len);
msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500);
@@ -1257,6 +1199,7 @@ static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data)
wpabuf_free(msg);
return NULL;
}
+ wpabuf_free(plain);
data->state = IKEV2_FAILED;
} else {
/* HDR, N */
diff --git a/contrib/wpa/src/eap_peer/mschapv2.c b/contrib/wpa/src/eap_peer/mschapv2.c
index 37e6735..9bc7370 100644
--- a/contrib/wpa/src/eap_peer/mschapv2.c
+++ b/contrib/wpa/src/eap_peer/mschapv2.c
@@ -117,8 +117,8 @@ int mschapv2_verify_auth_response(const u8 *auth_response,
buf[0] != 'S' || buf[1] != '=' ||
hexstr2bin((char *) (buf + 2), recv_response,
MSCHAPV2_AUTH_RESPONSE_LEN) ||
- os_memcmp(auth_response, recv_response,
- MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
+ os_memcmp_const(auth_response, recv_response,
+ MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
return -1;
return 0;
}
diff --git a/contrib/wpa/src/eap_peer/tncc.c b/contrib/wpa/src/eap_peer/tncc.c
index f5edfd5..7ca956e 100644
--- a/contrib/wpa/src/eap_peer/tncc.c
+++ b/contrib/wpa/src/eap_peer/tncc.c
@@ -13,6 +13,7 @@
#include "common.h"
#include "base64.h"
+#include "common/tnc.h"
#include "tncc.h"
#include "eap_common/eap_tlv_common.h"
#include "eap_common/eap_defs.h"
@@ -25,7 +26,9 @@
#endif /* UNICODE */
+#ifndef TNC_CONFIG_FILE
#define TNC_CONFIG_FILE "/etc/tnc_config"
+#endif /* TNC_CONFIG_FILE */
#define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
#define IF_TNCCS_START \
"<?xml version=\"1.0\"?>\n" \
@@ -38,56 +41,6 @@
/* TNC IF-IMC */
-typedef unsigned long TNC_UInt32;
-typedef unsigned char *TNC_BufferReference;
-
-typedef TNC_UInt32 TNC_IMCID;
-typedef TNC_UInt32 TNC_ConnectionID;
-typedef TNC_UInt32 TNC_ConnectionState;
-typedef TNC_UInt32 TNC_RetryReason;
-typedef TNC_UInt32 TNC_MessageType;
-typedef TNC_MessageType *TNC_MessageTypeList;
-typedef TNC_UInt32 TNC_VendorID;
-typedef TNC_UInt32 TNC_MessageSubtype;
-typedef TNC_UInt32 TNC_Version;
-typedef TNC_UInt32 TNC_Result;
-
-typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
- TNC_IMCID imcID,
- char *functionName,
- void **pOutfunctionPointer);
-
-#define TNC_RESULT_SUCCESS 0
-#define TNC_RESULT_NOT_INITIALIZED 1
-#define TNC_RESULT_ALREADY_INITIALIZED 2
-#define TNC_RESULT_NO_COMMON_VERSION 3
-#define TNC_RESULT_CANT_RETRY 4
-#define TNC_RESULT_WONT_RETRY 5
-#define TNC_RESULT_INVALID_PARAMETER 6
-#define TNC_RESULT_CANT_RESPOND 7
-#define TNC_RESULT_ILLEGAL_OPERATION 8
-#define TNC_RESULT_OTHER 9
-#define TNC_RESULT_FATAL 10
-
-#define TNC_CONNECTION_STATE_CREATE 0
-#define TNC_CONNECTION_STATE_HANDSHAKE 1
-#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
-#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
-#define TNC_CONNECTION_STATE_ACCESS_NONE 4
-#define TNC_CONNECTION_STATE_DELETE 5
-
-#define TNC_IFIMC_VERSION_1 1
-
-#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
-#define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
-
-/* TNCC-TNCS Message Types */
-#define TNC_TNCCS_RECOMMENDATION 0x00000001
-#define TNC_TNCCS_ERROR 0x00000002
-#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
-#define TNC_TNCCS_REASONSTRINGS 0x00000004
-
-
/* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
enum {
SSOH_MS_MACHINE_INVENTORY = 1,
@@ -741,12 +694,10 @@ 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;
- buf = os_malloc(len + 1);
+ buf = dup_binstr(msg, len);
if (buf == NULL)
return TNCCS_PROCESS_ERROR;
- os_memcpy(buf, msg, len);
- buf[len] = '\0';
start = os_strstr(buf, "<TNCCS-Batch ");
end = os_strstr(buf, "</TNCCS-Batch>");
if (start == NULL || end == NULL || start > end) {
@@ -1141,8 +1092,10 @@ static int tncc_read_config(struct tncc_data *tncc)
int error = 0;
imc = tncc_parse_imc(pos + 4, line_end, &error);
- if (error)
+ if (error) {
+ os_free(config);
return -1;
+ }
if (imc) {
if (last == NULL)
tncc->imc = imc;
diff --git a/contrib/wpa/src/eap_server/eap.h b/contrib/wpa/src/eap_server/eap.h
index f2a7cd7..9de6cb6 100644
--- a/contrib/wpa/src/eap_server/eap.h
+++ b/contrib/wpa/src/eap_server/eap.h
@@ -1,6 +1,6 @@
/*
* hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#define EAP_H
#include "common/defs.h"
+#include "utils/list.h"
#include "eap_common/eap_defs.h"
#include "eap_server/eap_methods.h"
#include "wpabuf.h"
@@ -32,8 +33,11 @@ struct eap_user {
* nt_password_hash() */
int phase2;
int force_version;
+ unsigned int remediation:1;
+ unsigned int macacl:1;
int ttls_auth; /* bitfield of
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
+ struct hostapd_radius_attr *accept_attr;
};
struct eap_eapol_interface {
@@ -55,6 +59,8 @@ struct eap_eapol_interface {
struct wpabuf *eapReqData;
u8 *eapKeyData;
size_t eapKeyDataLen;
+ u8 *eapSessionId;
+ size_t eapSessionIdLen;
Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
/* AAA interface to full authenticator variables */
@@ -75,10 +81,27 @@ struct eap_eapol_interface {
Boolean aaaTimeout;
};
+struct eap_server_erp_key {
+ struct dl_list list;
+ size_t rRK_len;
+ size_t rIK_len;
+ u8 rRK[ERP_MAX_KEY_LEN];
+ u8 rIK[ERP_MAX_KEY_LEN];
+ u32 recv_seq;
+ u8 cryptosuite;
+ char keyname_nai[];
+};
+
struct eapol_callbacks {
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
+ void (*log_msg)(void *ctx, const char *msg);
+ int (*get_erp_send_reauth_start)(void *ctx);
+ const char * (*get_erp_domain)(void *ctx);
+ struct eap_server_erp_key * (*erp_get_key)(void *ctx,
+ const char *keyname);
+ int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
};
struct eap_config {
@@ -104,6 +127,14 @@ struct eap_config {
int fragment_size;
int pbc_in_m1;
+
+ const u8 *server_id;
+ size_t server_id_len;
+ int erp;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u32 tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
};
diff --git a/contrib/wpa/src/eap_server/eap_i.h b/contrib/wpa/src/eap_server/eap_i.h
index f92704a..7d72309 100644
--- a/contrib/wpa/src/eap_server/eap_i.h
+++ b/contrib/wpa/src/eap_server/eap_i.h
@@ -88,6 +88,19 @@ struct eap_method {
* private data or this function may derive the key.
*/
u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+ /**
+ * getSessionId - Get EAP method specific Session-Id
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Pointer to a variable to store Session-Id length
+ * Returns: Session-Id or %NULL if not available
+ *
+ * This function can be used to get the Session-Id from the EAP method.
+ * The Session-Id may already be stored in the method-specific private
+ * data or this function may derive the Session-Id.
+ */
+ u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
};
/**
@@ -103,7 +116,8 @@ struct eap_sm {
EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
- EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2
+ EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2,
+ EAP_INITIATE_REAUTH_START, EAP_INITIATE_RECEIVED
} EAP_state;
/* Constants */
@@ -125,6 +139,7 @@ struct eap_sm {
/* Short-term (not maintained between packets) */
Boolean rxResp;
+ Boolean rxInitiate;
int respId;
EapType respMethod;
int respVendor;
@@ -132,7 +147,7 @@ struct eap_sm {
Boolean ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
- DECISION_PASSTHROUGH
+ DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
} decision;
/* Miscellaneous variables */
@@ -188,10 +203,23 @@ struct eap_sm {
int fragment_size;
int pbc_in_m1;
+
+ const u8 *server_id;
+ size_t server_id_len;
+
+ Boolean initiate_reauth_start_sent;
+ Boolean try_initiate_reauth;
+ int erp;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u32 tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
};
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
int phase2);
+void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len);
#endif /* EAP_I_H */
diff --git a/contrib/wpa/src/eap_server/eap_methods.h b/contrib/wpa/src/eap_server/eap_methods.h
index bc810a9..0baa327 100644
--- a/contrib/wpa/src/eap_server/eap_methods.h
+++ b/contrib/wpa/src/eap_server/eap_methods.h
@@ -27,6 +27,7 @@ int eap_server_identity_register(void);
int eap_server_md5_register(void);
int eap_server_tls_register(void);
int eap_server_unauth_tls_register(void);
+int eap_server_wfa_unauth_tls_register(void);
int eap_server_mschapv2_register(void);
int eap_server_peap_register(void);
int eap_server_tlv_register(void);
@@ -45,5 +46,6 @@ int eap_server_wsc_register(void);
int eap_server_ikev2_register(void);
int eap_server_tnc_register(void);
int eap_server_pwd_register(void);
+int eap_server_eke_register(void);
#endif /* EAP_SERVER_METHODS_H */
diff --git a/contrib/wpa/src/eap_server/eap_server.c b/contrib/wpa/src/eap_server/eap_server.c
index 15f7e22..bd919e5 100644
--- a/contrib/wpa/src/eap_server/eap_server.c
+++ b/contrib/wpa/src/eap_server/eap_server.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,6 +15,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha256.h"
#include "eap_i.h"
#include "state_machine.h"
#include "common/wpa_ctrl.h"
@@ -44,6 +45,73 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm);
static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
+{
+ if (sm->eapol_cb->get_erp_send_reauth_start)
+ return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
+ return 0;
+}
+
+
+static const char * eap_get_erp_domain(struct eap_sm *sm)
+{
+ if (sm->eapol_cb->get_erp_domain)
+ return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
+ return NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm,
+ const char *keyname)
+{
+ if (sm->eapol_cb->erp_get_key)
+ return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname);
+ return NULL;
+}
+
+
+static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp)
+{
+ if (sm->eapol_cb->erp_add_key)
+ return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp);
+ return -1;
+}
+
+#endif /* CONFIG_ERP */
+
+
+static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
+ u8 id)
+{
+ const char *domain;
+ size_t plen = 1;
+ struct wpabuf *msg;
+ size_t domain_len = 0;
+
+ domain = eap_get_erp_domain(sm);
+ if (domain) {
+ domain_len = os_strlen(domain);
+ plen += 2 + domain_len;
+ }
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH_START, plen,
+ EAP_CODE_INITIATE, id);
+ if (msg == NULL)
+ return NULL;
+ wpabuf_put_u8(msg, 0); /* Reserved */
+ if (domain) {
+ /* Domain name TLV */
+ wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
+ wpabuf_put_u8(msg, domain_len);
+ wpabuf_put_data(msg, domain, domain_len);
+ }
+
+ return msg;
+}
+
+
static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
{
if (src == NULL)
@@ -119,6 +187,32 @@ int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
}
+void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+
+ if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->log_msg == NULL)
+ return;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ va_start(ap, fmt);
+ vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+
+ sm->eapol_cb->log_msg(sm->eapol_ctx, buf);
+
+ os_free(buf);
+}
+
+
SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
@@ -138,13 +232,17 @@ SM_STATE(EAP, INITIALIZE)
eap_server_clear_identity(sm);
}
+ sm->try_initiate_reauth = FALSE;
sm->currentId = -1;
sm->eap_if.eapSuccess = FALSE;
sm->eap_if.eapFail = FALSE;
sm->eap_if.eapTimeout = FALSE;
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
+ os_free(sm->eap_if.eapSessionId);
+ sm->eap_if.eapSessionId = NULL;
+ sm->eap_if.eapSessionIdLen = 0;
sm->eap_if.eapKeyAvailable = FALSE;
sm->eap_if.eapRestart = FALSE;
@@ -310,6 +408,95 @@ SM_STATE(EAP, METHOD_REQUEST)
}
+static void eap_server_erp_init(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+ u8 *emsk = NULL;
+ size_t emsk_len = 0;
+ u8 EMSKname[EAP_EMSK_NAME_LEN];
+ u8 len[2];
+ const char *domain;
+ size_t domain_len, nai_buf_len;
+ struct eap_server_erp_key *erp = NULL;
+ int pos;
+
+ domain = eap_get_erp_domain(sm);
+ if (!domain)
+ return;
+
+ domain_len = os_strlen(domain);
+
+ nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len;
+ if (nai_buf_len > 253) {
+ /*
+ * keyName-NAI has a maximum length of 253 octet to fit in
+ * RADIUS attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long realm for ERP keyName-NAI maximum length");
+ return;
+ }
+ nai_buf_len++; /* null termination */
+ erp = os_zalloc(sizeof(*erp) + nai_buf_len);
+ if (erp == NULL)
+ goto fail;
+ erp->recv_seq = (u32) -1;
+
+ 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");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
+
+ WPA_PUT_BE16(len, 8);
+ if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
+ "EMSK", len, sizeof(len),
+ EMSKname, EAP_EMSK_NAME_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
+
+ pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
+ EMSKname, EAP_EMSK_NAME_LEN);
+ erp->keyname_nai[pos] = '@';
+ os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len);
+
+ WPA_PUT_BE16(len, emsk_len);
+ if (hmac_sha256_kdf(emsk, emsk_len,
+ "EAP Re-authentication Root Key@ietf.org",
+ len, sizeof(len), erp->rRK, emsk_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
+ goto fail;
+ }
+ erp->rRK_len = emsk_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, 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) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
+ goto fail;
+ }
+ erp->rIK_len = erp->rRK_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
+
+ if (eap_erp_add_key(sm, erp) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s",
+ erp->keyname_nai);
+ erp = NULL;
+ }
+
+fail:
+ bin_clear_free(emsk, emsk_len);
+ bin_clear_free(erp, sizeof(*erp));
+#endif /* CONFIG_ERP */
+}
+
+
SM_STATE(EAP, METHOD_RESPONSE)
{
SM_ENTRY(EAP, METHOD_RESPONSE);
@@ -320,7 +507,7 @@ SM_STATE(EAP, METHOD_RESPONSE)
sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
if (sm->m->isDone(sm, sm->eap_method_priv)) {
eap_sm_Policy_update(sm, NULL, 0);
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
if (sm->m->getKey) {
sm->eap_if.eapKeyData = sm->m->getKey(
sm, sm->eap_method_priv,
@@ -329,6 +516,18 @@ SM_STATE(EAP, METHOD_RESPONSE)
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
}
+ os_free(sm->eap_if.eapSessionId);
+ sm->eap_if.eapSessionId = NULL;
+ if (sm->m->getSessionId) {
+ sm->eap_if.eapSessionId = sm->m->getSessionId(
+ sm, sm->eap_method_priv,
+ &sm->eap_if.eapSessionIdLen);
+ wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+ sm->eap_if.eapSessionId,
+ sm->eap_if.eapSessionIdLen);
+ }
+ if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+ eap_server_erp_init(sm);
sm->methodState = METHOD_END;
} else {
sm->methodState = METHOD_CONTINUE;
@@ -343,6 +542,8 @@ SM_STATE(EAP, PROPOSE_METHOD)
SM_ENTRY(EAP, PROPOSE_METHOD);
+ sm->try_initiate_reauth = FALSE;
+try_another_method:
type = eap_sm_Policy_getNextMethod(sm, &vendor);
if (vendor == EAP_VENDOR_IETF)
sm->currentMethod = type;
@@ -360,8 +561,15 @@ SM_STATE(EAP, PROPOSE_METHOD)
"method %d", sm->currentMethod);
sm->m = NULL;
sm->currentMethod = EAP_TYPE_NONE;
+ goto try_another_method;
}
}
+ if (sm->m == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method");
+ eap_log_msg(sm, "Could not find suitable EAP method");
+ sm->decision = DECISION_FAILURE;
+ return;
+ }
if (sm->currentMethod == EAP_TYPE_IDENTITY ||
sm->currentMethod == EAP_TYPE_NOTIFICATION)
sm->methodState = METHOD_CONTINUE;
@@ -370,6 +578,8 @@ SM_STATE(EAP, PROPOSE_METHOD)
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u", vendor, sm->currentMethod);
+ eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
+ vendor, sm->currentMethod);
}
@@ -456,12 +666,326 @@ SM_STATE(EAP, SUCCESS)
}
+SM_STATE(EAP, INITIATE_REAUTH_START)
+{
+ SM_ENTRY(EAP, INITIATE_REAUTH_START);
+
+ sm->initiate_reauth_start_sent = TRUE;
+ sm->try_initiate_reauth = TRUE;
+ sm->currentId = eap_sm_nextId(sm, sm->currentId);
+ wpa_printf(MSG_DEBUG,
+ "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
+ sm->currentId);
+ sm->lastId = sm->currentId;
+ wpabuf_free(sm->eap_if.eapReqData);
+ sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
+ sm->currentId);
+ wpabuf_free(sm->lastReqData);
+ sm->lastReqData = NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static void erp_send_finish_reauth(struct eap_sm *sm,
+ struct eap_server_erp_key *erp, u8 id,
+ u8 flags, u16 seq, const char *nai)
+{
+ size_t plen;
+ struct wpabuf *msg;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ u8 seed[4];
+
+ if (erp) {
+ switch (erp->cryptosuite) {
+ case EAP_ERP_CS_HMAC_SHA256_256:
+ hash_len = 32;
+ break;
+ case EAP_ERP_CS_HMAC_SHA256_128:
+ hash_len = 16;
+ break;
+ default:
+ return;
+ }
+ } else
+ hash_len = 0;
+
+ plen = 1 + 2 + 2 + os_strlen(nai);
+ if (hash_len)
+ plen += 1 + hash_len;
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH, plen,
+ EAP_CODE_FINISH, id);
+ if (msg == NULL)
+ return;
+ wpabuf_put_u8(msg, flags);
+ wpabuf_put_be16(msg, seq);
+
+ wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
+ wpabuf_put_u8(msg, os_strlen(nai));
+ wpabuf_put_str(msg, nai);
+
+ if (erp) {
+ wpabuf_put_u8(msg, erp->cryptosuite);
+ if (hmac_sha256(erp->rIK, erp->rIK_len,
+ wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
+ wpabuf_free(msg);
+ return;
+ }
+ wpabuf_put_data(msg, hash, hash_len);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)",
+ flags & 0x80 ? "failure" : "success");
+
+ sm->lastId = sm->currentId;
+ sm->currentId = id;
+ wpabuf_free(sm->eap_if.eapReqData);
+ sm->eap_if.eapReqData = msg;
+ wpabuf_free(sm->lastReqData);
+ sm->lastReqData = NULL;
+
+ if (flags & 0x80) {
+ sm->eap_if.eapFail = TRUE;
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ MACSTR, MAC2STR(sm->peer_addr));
+ return;
+ }
+
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ sm->eap_if.eapKeyDataLen = 0;
+ sm->eap_if.eapKeyData = os_malloc(erp->rRK_len);
+ if (!sm->eap_if.eapKeyData)
+ return;
+
+ WPA_PUT_BE16(seed, seq);
+ WPA_PUT_BE16(&seed[2], erp->rRK_len);
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "Re-authentication Master Session Key@ietf.org",
+ seed, sizeof(seed),
+ sm->eap_if.eapKeyData, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
+ bin_clear_free(sm->eap_if.eapKeyData, erp->rRK_len);
+ sm->eap_if.eapKeyData = NULL;
+ return;
+ }
+ sm->eap_if.eapKeyDataLen = erp->rRK_len;
+ sm->eap_if.eapKeyAvailable = TRUE;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
+ sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ sm->eap_if.eapSuccess = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ MACSTR, MAC2STR(sm->peer_addr));
+}
+
+
+SM_STATE(EAP, INITIATE_RECEIVED)
+{
+ const u8 *pos, *end, *start, *tlvs, *hdr;
+ const struct eap_hdr *ehdr;
+ size_t len;
+ u8 flags;
+ u16 seq;
+ char nai[254];
+ struct eap_server_erp_key *erp;
+ int max_len;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ struct erp_tlvs parse;
+ u8 resp_flags = 0x80; /* default to failure; cleared on success */
+
+ SM_ENTRY(EAP, INITIATE_RECEIVED);
+
+ sm->rxInitiate = FALSE;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+ sm->eap_if.eapRespData, &len);
+ if (pos == NULL) {
+ wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
+ goto fail;
+ }
+ hdr = wpabuf_head(sm->eap_if.eapRespData);
+ ehdr = wpabuf_head(sm->eap_if.eapRespData);
+
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len);
+ if (len < 4) {
+ wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth");
+ goto fail;
+ }
+ end = pos + len;
+
+ flags = *pos++;
+ seq = WPA_GET_BE16(pos);
+ pos += 2;
+ wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
+ tlvs = pos;
+
+ /*
+ * Parse TVs/TLVs. Since we do not yet know the length of the
+ * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
+ * just try to find the keyName-NAI first so that we can check the
+ * Authentication Tag.
+ */
+ if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0)
+ goto fail;
+
+ if (!parse.keyname) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet");
+ goto fail;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
+ parse.keyname, parse.keyname_len);
+ if (parse.keyname_len > 253) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth");
+ goto fail;
+ }
+ os_memcpy(nai, parse.keyname, parse.keyname_len);
+ nai[parse.keyname_len] = '\0';
+
+ if (!sm->eap_server) {
+ /*
+ * In passthrough case, EAP-Initiate/Re-auth replaces
+ * EAP Identity exchange. Use keyName-NAI as the user identity
+ * and forward EAP-Initiate/Re-auth to the backend
+ * authentication server.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Use keyName-NAI as user identity for backend authentication");
+ eap_server_clear_identity(sm);
+ sm->identity = (u8 *) dup_binstr(parse.keyname,
+ parse.keyname_len);
+ if (!sm->identity)
+ goto fail;
+ sm->identity_len = parse.keyname_len;
+ return;
+ }
+
+ erp = eap_erp_get_key(sm, nai);
+ if (!erp) {
+ wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
+ nai);
+ goto report_error;
+ }
+
+ if (erp->recv_seq != (u32) -1 && erp->recv_seq >= seq) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: SEQ=%u replayed (already received SEQ=%u)",
+ seq, erp->recv_seq);
+ goto fail;
+ }
+
+ /* Is there enough room for Cryptosuite and Authentication Tag? */
+ start = parse.keyname + parse.keyname_len;
+ max_len = end - start;
+ if (max_len <
+ 1 + (erp->cryptosuite == EAP_ERP_CS_HMAC_SHA256_256 ? 32 : 16)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Not enough room for Authentication Tag");
+ goto fail;
+ }
+
+ switch (erp->cryptosuite) {
+ case EAP_ERP_CS_HMAC_SHA256_256:
+ if (end[-33] != erp->cryptosuite) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Different Cryptosuite used");
+ goto fail;
+ }
+ hash_len = 32;
+ break;
+ case EAP_ERP_CS_HMAC_SHA256_128:
+ if (end[-17] != erp->cryptosuite) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Different Cryptosuite used");
+ goto fail;
+ }
+ hash_len = 16;
+ break;
+ default:
+ hash_len = 0;
+ break;
+ }
+
+ if (hash_len) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - hash_len, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag mismatch");
+ goto fail;
+ }
+ }
+
+ /* Check if any supported CS results in matching tag */
+ if (!hash_len && max_len >= 1 + 32 &&
+ end[-33] == EAP_ERP_CS_HMAC_SHA256_256) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - 32, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - 32, hash, 32) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag match using HMAC-SHA256-256");
+ hash_len = 32;
+ erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_256;
+ }
+ }
+
+ if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - 16, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - 16, hash, 16) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag match using HMAC-SHA256-128");
+ hash_len = 16;
+ erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128;
+ }
+ }
+
+ if (!hash_len) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No supported cryptosuite matched Authentication Tag");
+ goto fail;
+ }
+ end -= 1 + hash_len;
+
+ /*
+ * Parse TVs/TLVs again now that we know the exact part of the buffer
+ * that contains them.
+ */
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
+ tlvs, end - tlvs);
+ if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u",
+ erp->keyname_nai, seq);
+ erp->recv_seq = seq;
+ resp_flags &= ~0x80; /* R=0 - success */
+
+report_error:
+ erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai);
+ return;
+
+fail:
+ sm->ignore = TRUE;
+}
+
+#endif /* CONFIG_ERP */
+
+
SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
{
SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
wpabuf_free(sm->eap_if.aaaEapRespData);
sm->eap_if.aaaEapRespData = NULL;
+ sm->try_initiate_reauth = FALSE;
}
@@ -596,7 +1120,7 @@ SM_STATE(EAP, SUCCESS2)
if (sm->eap_if.aaaEapKeyAvailable) {
EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
} else {
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
}
@@ -655,9 +1179,14 @@ SM_STEP(EAP)
SM_ENTER(EAP, INITIALIZE);
break;
case EAP_IDLE:
- if (sm->eap_if.retransWhile == 0)
- SM_ENTER(EAP, RETRANSMIT);
- else if (sm->eap_if.eapResp)
+ if (sm->eap_if.retransWhile == 0) {
+ if (sm->try_initiate_reauth) {
+ sm->try_initiate_reauth = FALSE;
+ SM_ENTER(EAP, SELECT_ACTION);
+ } else {
+ SM_ENTER(EAP, RETRANSMIT);
+ }
+ } else if (sm->eap_if.eapResp)
SM_ENTER(EAP, RECEIVED);
break;
case EAP_RETRANSMIT:
@@ -680,12 +1209,17 @@ SM_STEP(EAP)
sm->respVendor == EAP_VENDOR_IETF &&
sm->respVendorMethod == sm->currentMethod)))
SM_ENTER(EAP, INTEGRITY_CHECK);
+#ifdef CONFIG_ERP
+ else if (sm->rxInitiate)
+ SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
else {
wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
"rxResp=%d respId=%d currentId=%d "
"respMethod=%d currentMethod=%d",
sm->rxResp, sm->respId, sm->currentId,
sm->respMethod, sm->currentMethod);
+ eap_log_msg(sm, "Discard received EAP message");
SM_ENTER(EAP, DISCARD);
}
break;
@@ -702,6 +1236,15 @@ SM_STEP(EAP)
SM_ENTER(EAP, METHOD_RESPONSE);
break;
case EAP_METHOD_REQUEST:
+ if (sm->m == NULL) {
+ /*
+ * This transition is not mentioned in RFC 4137, but it
+ * is needed to handle cleanly a case where EAP method
+ * initialization fails.
+ */
+ SM_ENTER(EAP, FAILURE);
+ break;
+ }
SM_ENTER(EAP, SEND_REQUEST);
break;
case EAP_METHOD_RESPONSE:
@@ -758,9 +1301,22 @@ SM_STEP(EAP)
SM_ENTER(EAP, SUCCESS);
else if (sm->decision == DECISION_PASSTHROUGH)
SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
+ else if (sm->decision == DECISION_INITIATE_REAUTH_START)
+ SM_ENTER(EAP, INITIATE_REAUTH_START);
+#ifdef CONFIG_ERP
+ else if (sm->eap_server && sm->erp && sm->rxInitiate)
+ SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
else
SM_ENTER(EAP, PROPOSE_METHOD);
break;
+ case EAP_INITIATE_REAUTH_START:
+ SM_ENTER(EAP, SEND_REQUEST);
+ break;
+ case EAP_INITIATE_RECEIVED:
+ if (!sm->eap_server)
+ SM_ENTER(EAP, SELECT_ACTION);
+ break;
case EAP_TIMEOUT_FAILURE:
break;
case EAP_FAILURE:
@@ -830,6 +1386,12 @@ static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
{
int rto, i;
+ if (sm->try_initiate_reauth) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
+ return 1;
+ }
+
if (methodTimeout) {
/*
* EAP method (either internal or through AAA server, provided
@@ -883,6 +1445,7 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
/* parse rxResp, respId, respMethod */
sm->rxResp = FALSE;
+ sm->rxInitiate = FALSE;
sm->respId = -1;
sm->respMethod = EAP_TYPE_NONE;
sm->respVendor = EAP_VENDOR_IETF;
@@ -909,6 +1472,8 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
if (hdr->code == EAP_CODE_RESPONSE)
sm->rxResp = TRUE;
+ else if (hdr->code == EAP_CODE_INITIATE)
+ sm->rxInitiate = TRUE;
if (plen > sizeof(*hdr)) {
u8 *pos = (u8 *) (hdr + 1);
@@ -926,10 +1491,10 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
}
}
- wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
- "respMethod=%u respVendor=%u respVendorMethod=%u",
- sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
- sm->respVendorMethod);
+ wpa_printf(MSG_DEBUG,
+ "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
+ sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod,
+ sm->respVendor, sm->respVendorMethod);
}
@@ -1170,6 +1735,13 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
return DECISION_CONTINUE;
}
+ if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
+ !sm->initiate_reauth_start_sent) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
+ return DECISION_INITIATE_REAUTH_START;
+ }
+
if (sm->identity == NULL || sm->currentId == -1) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
"yet -> CONTINUE");
@@ -1214,7 +1786,7 @@ static void eap_user_free(struct eap_user *user)
{
if (user == NULL)
return;
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
user->password = NULL;
os_free(user);
}
@@ -1278,6 +1850,13 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
sm->fragment_size = conf->fragment_size;
sm->pwd_group = conf->pwd_group;
sm->pbc_in_m1 = conf->pbc_in_m1;
+ sm->server_id = conf->server_id;
+ sm->server_id_len = conf->server_id_len;
+ sm->erp = conf->erp;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ sm->tls_test_flags = conf->tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
@@ -1300,7 +1879,8 @@ void eap_server_sm_deinit(struct eap_sm *sm)
if (sm->m && sm->eap_method_priv)
sm->m->reset(sm, sm->eap_method_priv);
wpabuf_free(sm->eap_if.eapReqData);
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ os_free(sm->eap_if.eapSessionId);
wpabuf_free(sm->lastReqData);
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
@@ -1309,7 +1889,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
os_free(sm->eap_fast_a_id_info);
wpabuf_free(sm->eap_if.aaaEapReqData);
wpabuf_free(sm->eap_if.aaaEapRespData);
- os_free(sm->eap_if.aaaEapKeyData);
+ bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
eap_user_free(sm->user);
wpabuf_free(sm->assoc_wps_ie);
wpabuf_free(sm->assoc_p2p_ie);
diff --git a/contrib/wpa/src/eap_server/eap_server_aka.c b/contrib/wpa/src/eap_server/eap_server_aka.c
index 469b9a0..db9b6aa 100644
--- a/contrib/wpa/src/eap_server/eap_server_aka.c
+++ b/contrib/wpa/src/eap_server/eap_server_aka.c
@@ -241,7 +241,7 @@ static void eap_aka_reset(struct eap_sm *sm, void *priv)
os_free(data->next_reauth_id);
wpabuf_free(data->id_msgs);
os_free(data->network_name);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -336,7 +336,7 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
else
sha1_vector(1, &addr, &len, hash);
- if (os_memcmp(hash, checkcode, hash_len) != 0) {
+ if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
return -1;
}
@@ -377,7 +377,7 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
}
- buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
+ buf = eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
if (eap_aka_add_id_msg(data, buf) < 0) {
wpabuf_free(buf);
return NULL;
@@ -534,7 +534,7 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
}
@@ -581,7 +581,7 @@ static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
}
@@ -620,7 +620,7 @@ static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
}
@@ -963,7 +963,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
*/
if (attr->res == NULL || attr->res_len < data->res_len ||
attr->res_len_bits != data->res_len * 8 ||
- os_memcmp(attr->res, data->res, data->res_len) != 0) {
+ os_memcmp_const(attr->res, data->res, data->res_len) != 0) {
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
"include valid AT_RES (attr len=%lu, res len=%lu "
"bits, expected %lu bits)",
@@ -1040,6 +1040,7 @@ static void eap_aka_process_sync_failure(struct eap_sm *sm,
data->auts_reported = 1;
/* Remain in CHALLENGE state to re-try after resynchronization */
+ eap_aka_fullauth(sm, data);
}
@@ -1293,6 +1294,28 @@ static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = data->eap_method;
+ os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_aka_register(void)
{
struct eap_method *eap;
@@ -1312,6 +1335,7 @@ int eap_server_aka_register(void)
eap->getKey = eap_aka_getKey;
eap->isSuccess = eap_aka_isSuccess;
eap->get_emsk = eap_aka_get_emsk;
+ eap->getSessionId = eap_aka_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
@@ -1341,6 +1365,7 @@ int eap_server_aka_prime_register(void)
eap->getKey = eap_aka_getKey;
eap->isSuccess = eap_aka_isSuccess;
eap->get_emsk = eap_aka_get_emsk;
+ eap->getSessionId = eap_aka_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_eke.c b/contrib/wpa/src/eap_server/eap_server_eke.c
new file mode 100644
index 0000000..966f511
--- /dev/null
+++ b/contrib/wpa/src/eap_server/eap_server_eke.c
@@ -0,0 +1,793 @@
+/*
+ * hostapd / EAP-EKE (RFC 6124) server
+ * Copyright (c) 2013, 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/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+
+struct eap_eke_data {
+ enum {
+ IDENTITY, COMMIT, CONFIRM, FAILURE_REPORT, SUCCESS, FAILURE
+ } state;
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 *peerid;
+ size_t peerid_len;
+ u8 peerid_type;
+ u8 serverid_type;
+ u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+ u8 key[EAP_EKE_MAX_KEY_LEN];
+ struct eap_eke_session sess;
+ u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+ u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+ struct wpabuf *msgs;
+ int phase2;
+ u32 failure_code;
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+ switch (state) {
+ case IDENTITY:
+ return "IDENTITY";
+ case COMMIT:
+ return "COMMIT";
+ case CONFIRM:
+ return "CONFIRM";
+ case FAILURE_REPORT:
+ return "FAILURE_REPORT";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "?";
+ }
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+ eap_eke_state_txt(data->state),
+ eap_eke_state_txt(state));
+ data->state = state;
+}
+
+
+static void eap_eke_fail(struct eap_eke_data *data, u32 code)
+{
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code);
+ data->failure_code = code;
+ eap_eke_state(data, FAILURE_REPORT);
+}
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+ struct eap_eke_data *data;
+ size_t i;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ eap_eke_state(data, IDENTITY);
+
+ data->serverid_type = EAP_EKE_ID_OPAQUE;
+ for (i = 0; i < sm->server_id_len; i++) {
+ if (sm->server_id[i] == '.' &&
+ data->serverid_type == EAP_EKE_ID_OPAQUE)
+ data->serverid_type = EAP_EKE_ID_FQDN;
+ if (sm->server_id[i] == '@')
+ data->serverid_type = EAP_EKE_ID_NAI;
+ }
+
+ data->phase2 = sm->init_phase2;
+
+ return data;
+}
+
+
+static void eap_eke_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_eke_data *data = priv;
+ eap_eke_session_clean(&data->sess);
+ os_free(data->peerid);
+ wpabuf_free(data->msgs);
+ bin_clear_free(data, sizeof(*data));
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data,
+ u8 id, size_t length, u8 eke_exch)
+{
+ struct wpabuf *msg;
+ size_t plen;
+
+ plen = 1 + length;
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+ EAP_CODE_REQUEST, id);
+ if (msg == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+ return NULL;
+ }
+
+ wpabuf_put_u8(msg, eke_exch);
+
+ return msg;
+}
+
+
+static int supported_proposal(const u8 *pos)
+{
+ if (pos[0] == EAP_EKE_DHGROUP_EKE_16 &&
+ pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+ pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+ pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+ return 1;
+
+ if (pos[0] == EAP_EKE_DHGROUP_EKE_15 &&
+ pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+ pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+ pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+ return 1;
+
+ if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+ pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+ pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+ pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+ return 1;
+
+ if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+ pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+ pos[2] == EAP_EKE_PRF_HMAC_SHA1 &&
+ pos[3] == EAP_EKE_MAC_HMAC_SHA1)
+ return 1;
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id)
+{
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x",
+ data->failure_code);
+
+ msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
+ if (msg == NULL) {
+ eap_eke_state(data, FAILURE);
+ return NULL;
+ }
+ wpabuf_put_be32(msg, data->failure_code);
+
+ return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm,
+ struct eap_eke_data *data,
+ u8 id)
+{
+ struct wpabuf *msg;
+ size_t plen;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
+
+ plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+ msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
+ if (msg == NULL)
+ return NULL;
+
+ wpabuf_put_u8(msg, 4); /* NumProposals */
+ wpabuf_put_u8(msg, 0); /* Reserved */
+
+ /* Proposal - DH Group 16 with AES128-CBC and SHA256 */
+ wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */
+ wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+ wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+ wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+ /* Proposal - DH Group 15 with AES128-CBC and SHA256 */
+ wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */
+ wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+ wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+ wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+ /* Proposal - DH Group 14 with AES128-CBC and SHA256 */
+ wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+ wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+ wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+ wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+ /*
+ * Proposal - DH Group 14 with AES128-CBC and SHA1
+ * (mandatory to implement algorithms)
+ */
+ wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+ wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+ wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */
+ wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */
+
+ /* Server IDType + Identity */
+ wpabuf_put_u8(msg, data->serverid_type);
+ wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+
+ wpabuf_free(data->msgs);
+ data->msgs = wpabuf_dup(msg);
+ if (data->msgs == NULL) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm,
+ struct eap_eke_data *data, u8 id)
+{
+ struct wpabuf *msg;
+ u8 pub[EAP_EKE_MAX_DH_LEN];
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");
+
+ if (sm->user == NULL || sm->user->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured");
+ eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+ return eap_eke_build_failure(data, id);
+ }
+
+ if (eap_eke_derive_key(&data->sess, sm->user->password,
+ sm->user->password_len,
+ sm->server_id, sm->server_id_len,
+ data->peerid, data->peerid_len, data->key) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+
+ msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
+ EAP_EKE_COMMIT);
+ if (msg == NULL) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+
+ /*
+ * y_s = g ^ x_s (mod p)
+ * x_s = random number 2 .. p-1
+ * temp = prf(0+, password)
+ * key = prf+(temp, ID_S | ID_P)
+ * DHComponent_S = Encr(key, y_s)
+ */
+
+ if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+
+ if (eap_eke_dhcomp(&data->sess, data->key, pub,
+ wpabuf_put(msg, data->sess.dhcomp_len))
+ < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+ wpabuf_free(msg);
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+
+ if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) {
+ wpabuf_free(msg);
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+ wpabuf_put_buf(data->msgs, msg);
+
+ return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm,
+ struct eap_eke_data *data, u8 id)
+{
+ struct wpabuf *msg;
+ size_t plen, prot_len;
+ u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+ u8 *auth;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm");
+
+ plen = data->sess.pnonce_ps_len + data->sess.prf_len;
+ msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM);
+ if (msg == NULL) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+
+ if (random_get_bytes(data->nonce_s, data->sess.nonce_len)) {
+ wpabuf_free(msg);
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+ data->nonce_s, data->sess.nonce_len);
+
+ os_memcpy(nonces, data->nonce_p, data->sess.nonce_len);
+ os_memcpy(nonces + data->sess.nonce_len, data->nonce_s,
+ data->sess.nonce_len);
+ prot_len = wpabuf_tailroom(msg);
+ if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len,
+ wpabuf_put(msg, 0), &prot_len) < 0) {
+ wpabuf_free(msg);
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+ wpabuf_put(msg, prot_len);
+
+ if (eap_eke_derive_ka(&data->sess,
+ sm->server_id, sm->server_id_len,
+ data->peerid, data->peerid_len,
+ data->nonce_p, data->nonce_s) < 0) {
+ wpabuf_free(msg);
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+
+ auth = wpabuf_put(msg, data->sess.prf_len);
+ if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth) < 0) {
+ wpabuf_free(msg);
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return eap_eke_build_failure(data, id);
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len);
+
+ return msg;
+}
+
+
+static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+ struct eap_eke_data *data = priv;
+
+ switch (data->state) {
+ case IDENTITY:
+ return eap_eke_build_identity(sm, data, id);
+ case COMMIT:
+ return eap_eke_build_commit(sm, data, id);
+ case CONFIRM:
+ return eap_eke_build_confirm(sm, data, id);
+ case FAILURE_REPORT:
+ return eap_eke_build_failure(data, id);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Unknown state %d in buildReq",
+ data->state);
+ break;
+ }
+ return NULL;
+}
+
+
+static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_eke_data *data = priv;
+ size_t len;
+ const u8 *pos;
+ u8 eke_exch;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+ if (pos == NULL || len < 1) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
+ return TRUE;
+ }
+
+ eke_exch = *pos;
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
+
+ if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
+ return FALSE;
+
+ if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
+ return FALSE;
+
+ if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
+ return FALSE;
+
+ if (eke_exch == EAP_EKE_FAILURE)
+ return FALSE;
+
+ wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d",
+ eke_exch, data->state);
+
+ return TRUE;
+}
+
+
+static void eap_eke_process_identity(struct eap_sm *sm,
+ struct eap_eke_data *data,
+ const struct wpabuf *respData,
+ const u8 *payload, size_t payloadlen)
+{
+ const u8 *pos, *end;
+ int i;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");
+
+ if (data->state != IDENTITY) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ pos = payload;
+ end = payload + payloadlen;
+
+ if (pos + 2 + 4 + 1 > end) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload");
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ if (*pos != 1) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)",
+ *pos);
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ pos += 2;
+
+ if (!supported_proposal(pos)) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)",
+ pos[0], pos[1], pos[2], pos[3]);
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
+ pos[0], pos[1], pos[2], pos[3]);
+ if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) <
+ 0) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+ pos += 4;
+
+ data->peerid_type = *pos++;
+ os_free(data->peerid);
+ data->peerid = os_malloc(end - pos);
+ if (data->peerid == NULL) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+ os_memcpy(data->peerid, pos, end - pos);
+ data->peerid_len = end - pos;
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
+ data->peerid, data->peerid_len);
+
+ if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
+ eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+ return;
+ }
+
+ for (i = 0; i < EAP_MAX_METHODS; i++) {
+ if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+ sm->user->methods[i].method == EAP_TYPE_EKE)
+ break;
+ }
+ if (i == EAP_MAX_METHODS) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE");
+ eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+ return;
+ }
+
+ if (sm->user->password == NULL || sm->user->password_len == 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer");
+ eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+ return;
+ }
+
+ if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+ wpabuf_put_buf(data->msgs, respData);
+
+ eap_eke_state(data, COMMIT);
+}
+
+
+static void eap_eke_process_commit(struct eap_sm *sm,
+ struct eap_eke_data *data,
+ const struct wpabuf *respData,
+ const u8 *payload, size_t payloadlen)
+{
+ const u8 *pos, *end, *dhcomp, *pnonce;
+ size_t decrypt_len;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
+
+ if (data->state != COMMIT) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ pos = payload;
+ end = payload + payloadlen;
+
+ if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+ pos, data->sess.dhcomp_len);
+ dhcomp = pos;
+ pos += data->sess.dhcomp_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
+ pnonce = pos;
+ pos += data->sess.pnonce_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+ if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp)
+ < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+
+ if (eap_eke_derive_ke_ki(&data->sess,
+ sm->server_id, sm->server_id_len,
+ data->peerid, data->peerid_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+
+ decrypt_len = sizeof(data->nonce_p);
+ if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
+ data->nonce_p, &decrypt_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
+ eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ return;
+ }
+ if (decrypt_len < (size_t) data->sess.nonce_len) {
+ wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P");
+ eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ return;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+ data->nonce_p, data->sess.nonce_len);
+
+ if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+ wpabuf_put_buf(data->msgs, respData);
+
+ eap_eke_state(data, CONFIRM);
+}
+
+
+static void eap_eke_process_confirm(struct eap_sm *sm,
+ struct eap_eke_data *data,
+ const struct wpabuf *respData,
+ const u8 *payload, size_t payloadlen)
+{
+ size_t decrypt_len;
+ u8 nonce[EAP_EKE_MAX_NONCE_LEN];
+ u8 auth_p[EAP_EKE_MAX_HASH_LEN];
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+ if (data->state != CONFIRM) {
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+ if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
+ eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+ return;
+ }
+
+ decrypt_len = sizeof(nonce);
+ if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len,
+ nonce, &decrypt_len) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S");
+ eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ return;
+ }
+ if (decrypt_len < (size_t) data->sess.nonce_len) {
+ wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S");
+ eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ return;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
+ nonce, data->sess.nonce_len);
+ if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S");
+ eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ return;
+ }
+
+ if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P");
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
+ if (os_memcmp_const(auth_p, payload + data->sess.pnonce_len,
+ data->sess.prf_len) != 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
+ eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+ return;
+ }
+
+ if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+ data->peerid, data->peerid_len,
+ data->nonce_s, data->nonce_p,
+ data->msk, data->emsk) < 0) {
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+ eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+ return;
+ }
+
+ os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+ os_memset(data->key, 0, sizeof(data->key));
+ eap_eke_session_clean(&data->sess);
+
+ eap_eke_state(data, SUCCESS);
+}
+
+
+static void eap_eke_process_failure(struct eap_sm *sm,
+ struct eap_eke_data *data,
+ const struct wpabuf *respData,
+ const u8 *payload, size_t payloadlen)
+{
+ u32 code;
+
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure");
+
+ if (payloadlen < 4) {
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+ eap_eke_state(data, FAILURE);
+ return;
+ }
+
+ code = WPA_GET_BE32(payload);
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code);
+
+ eap_eke_state(data, FAILURE);
+}
+
+
+static void eap_eke_process(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_eke_data *data = priv;
+ u8 eke_exch;
+ size_t len;
+ const u8 *pos, *end;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+ if (pos == NULL || len < 1)
+ return;
+
+ eke_exch = *pos;
+ end = pos + len;
+ pos++;
+
+ wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
+
+ switch (eke_exch) {
+ case EAP_EKE_ID:
+ eap_eke_process_identity(sm, data, respData, pos, end - pos);
+ break;
+ case EAP_EKE_COMMIT:
+ eap_eke_process_commit(sm, data, respData, pos, end - pos);
+ break;
+ case EAP_EKE_CONFIRM:
+ eap_eke_process_confirm(sm, data, respData, pos, end - pos);
+ break;
+ case EAP_EKE_FAILURE:
+ eap_eke_process_failure(sm, data, respData, pos, end - pos);
+ break;
+ }
+}
+
+
+static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_eke_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_eke_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->msk, EAP_MSK_LEN);
+ *len = EAP_MSK_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_eke_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
+static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_eke_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+int eap_server_eke_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_eke_init;
+ eap->reset = eap_eke_reset;
+ eap->buildReq = eap_eke_buildReq;
+ eap->check = eap_eke_check;
+ eap->process = eap_eke_process;
+ eap->isDone = eap_eke_isDone;
+ eap->getKey = eap_eke_getKey;
+ eap->isSuccess = eap_eke_isSuccess;
+ eap->get_emsk = eap_eke_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa/src/eap_server/eap_server_fast.c b/contrib/wpa/src/eap_server/eap_server_fast.c
index fcb80dc..6745100 100644
--- a/contrib/wpa/src/eap_server/eap_server_fast.c
+++ b/contrib/wpa/src/eap_server/eap_server_fast.c
@@ -161,8 +161,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
return 0;
}
- if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
- pac_opaque, buf) < 0) {
+ if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+ (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
"PAC-Opaque");
os_free(buf);
@@ -186,8 +186,7 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
switch (*pos) {
case PAC_OPAQUE_TYPE_PAD:
- pos = end;
- break;
+ goto done;
case PAC_OPAQUE_TYPE_KEY:
if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
@@ -218,6 +217,7 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
pos += 2 + pos[1];
}
+done:
if (pac_key == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
@@ -511,7 +511,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv)
os_free(data->key_block_p);
wpabuf_free(data->pending_phase2_resp);
os_free(data->identity);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -730,8 +730,8 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
os_free(pac_buf);
return NULL;
}
- if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
- pac_opaque) < 0) {
+ if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+ pac_len / 8, pac_buf, pac_opaque) < 0) {
os_free(pac_buf);
os_free(pac_opaque);
return NULL;
@@ -819,6 +819,9 @@ static int eap_fast_encrypt_phase2(struct eap_sm *sm,
encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
wpabuf_free(plain);
+ if (!encr)
+ return -1;
+
if (data->ssl.tls_out && piggyback) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
"(len=%d) with last Phase 1 Message (len=%d "
@@ -1016,7 +1019,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
if (m->check(sm, priv, &buf)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
"ignore the packet");
- next_type = eap_fast_req_failure(sm, data);
+ eap_fast_req_failure(sm, data);
return;
}
@@ -1123,7 +1126,8 @@ static void eap_fast_process_phase2_eap(struct eap_sm *sm,
static int eap_fast_parse_tlvs(struct wpabuf *data,
struct eap_fast_tlv_parse *tlv)
{
- int mandatory, tlv_type, len, res;
+ int mandatory, tlv_type, res;
+ size_t len;
u8 *pos, *end;
os_memset(tlv, 0, sizeof(*tlv));
@@ -1136,13 +1140,14 @@ static int eap_fast_parse_tlvs(struct wpabuf *data,
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return -1;
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
- "TLV type %d length %d%s",
- tlv_type, len, mandatory ? " (mandatory)" : "");
+ "TLV type %d length %u%s",
+ tlv_type, (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
if (res == -2)
@@ -1196,7 +1201,7 @@ static int eap_fast_validate_crypto_binding(
return -1;
}
- if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
+ if (os_memcmp_const(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
(data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
"Crypto-Binding");
@@ -1210,7 +1215,7 @@ static int eap_fast_validate_crypto_binding(
(u8 *) b, bind_len);
hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
b->compound_mac);
- if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
+ if (os_memcmp_const(cmac, b->compound_mac, sizeof(cmac)) != 0) {
wpa_hexdump(MSG_MSGDUMP,
"EAP-FAST: Calculated Compound MAC",
b->compound_mac, sizeof(cmac));
@@ -1587,6 +1592,18 @@ static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_FAST,
+ len);
+}
+
+
int eap_server_fast_register(void)
{
struct eap_method *eap;
@@ -1606,6 +1623,7 @@ int eap_server_fast_register(void)
eap->getKey = eap_fast_getKey;
eap->get_emsk = eap_fast_get_emsk;
eap->isSuccess = eap_fast_isSuccess;
+ eap->getSessionId = eap_fast_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_gpsk.c b/contrib/wpa/src/eap_server/eap_server_gpsk.c
index 2853c48..50f15c3 100644
--- a/contrib/wpa/src/eap_server/eap_server_gpsk.c
+++ b/contrib/wpa/src/eap_server/eap_server_gpsk.c
@@ -24,10 +24,10 @@ struct eap_gpsk_data {
size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len;
+ u8 session_id[128];
+ size_t id_len;
u8 *id_peer;
size_t id_peer_len;
- u8 *id_server;
- size_t id_server_len;
#define MAX_NUM_CSUITES 2
struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
size_t csuite_count;
@@ -71,11 +71,6 @@ static void * eap_gpsk_init(struct eap_sm *sm)
return NULL;
data->state = GPSK_1;
- /* TODO: add support for configuring ID_Server */
- data->id_server = (u8 *) os_strdup("hostapd");
- if (data->id_server)
- data->id_server_len = os_strlen((char *) data->id_server);
-
data->csuite_count = 0;
if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
EAP_GPSK_CIPHER_AES)) {
@@ -101,9 +96,8 @@ static void * eap_gpsk_init(struct eap_sm *sm)
static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
- os_free(data->id_server);
os_free(data->id_peer);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -123,7 +117,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
data->rand_server, EAP_GPSK_RAND_LEN);
- len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
+ len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
data->csuite_count * sizeof(struct eap_gpsk_csuite);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -135,8 +129,8 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
}
wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
- wpabuf_put_be16(req, data->id_server_len);
- wpabuf_put_data(req, data->id_server, data->id_server_len);
+ wpabuf_put_be16(req, sm->server_id_len);
+ wpabuf_put_data(req, sm->server_id, sm->server_id_len);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
wpabuf_put_be16(req,
data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -158,7 +152,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
- len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len +
+ len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
sizeof(struct eap_gpsk_csuite) + 2 + miclen;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -174,8 +168,8 @@ static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
- wpabuf_put_be16(req, data->id_server_len);
- wpabuf_put_data(req, data->id_server, data->id_server_len);
+ wpabuf_put_be16(req, sm->server_id_len);
+ wpabuf_put_data(req, sm->server_id, sm->server_id_len);
csuite = wpabuf_put(req, sizeof(*csuite));
WPA_PUT_BE32(csuite->vendor, data->vendor);
WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -301,8 +295,8 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
eap_gpsk_state(data, FAILURE);
return;
}
- if (alen != data->id_server_len ||
- os_memcmp(pos, data->id_server, alen) != 0) {
+ if (alen != sm->server_id_len ||
+ os_memcmp(pos, sm->server_id, alen) != 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
"GPSK-2 did not match");
eap_gpsk_state(data, FAILURE);
@@ -416,7 +410,7 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- data->id_server, data->id_server_len,
+ sm->server_id, sm->server_id_len,
data->msk, data->emsk,
data->sk, &data->sk_len,
data->pk, &data->pk_len) < 0) {
@@ -425,6 +419,21 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
return;
}
+ if (eap_gpsk_derive_session_id(sm->user->password,
+ sm->user->password_len,
+ data->vendor, data->specifier,
+ data->rand_peer, data->rand_server,
+ data->id_peer, data->id_peer_len,
+ sm->server_id, sm->server_id_len,
+ EAP_TYPE_GPSK,
+ data->session_id, &data->id_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+ data->session_id, data->id_len);
+
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
if (end - pos < (int) miclen) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
@@ -441,7 +450,7 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
eap_gpsk_state(data, FAILURE);
return;
}
- if (os_memcmp(mic, pos, miclen) != 0) {
+ if (os_memcmp_const(mic, pos, miclen) != 0) {
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
@@ -510,7 +519,7 @@ static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
eap_gpsk_state(data, FAILURE);
return;
}
- if (os_memcmp(mic, pos, miclen) != 0) {
+ if (os_memcmp_const(mic, pos, miclen) != 0) {
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
@@ -601,6 +610,24 @@ static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(data->id_len);
+ if (sid == NULL)
+ return NULL;
+ os_memcpy(sid, data->session_id, data->id_len);
+ *len = data->id_len;
+
+ return sid;
+}
+
+
int eap_server_gpsk_register(void)
{
struct eap_method *eap;
@@ -620,6 +647,7 @@ int eap_server_gpsk_register(void)
eap->getKey = eap_gpsk_getKey;
eap->isSuccess = eap_gpsk_isSuccess;
eap->get_emsk = eap_gpsk_get_emsk;
+ eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_gtc.c b/contrib/wpa/src/eap_server/eap_server_gtc.c
index f423106..98ac3c6 100644
--- a/contrib/wpa/src/eap_server/eap_server_gtc.c
+++ b/contrib/wpa/src/eap_server/eap_server_gtc.c
@@ -175,7 +175,7 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv,
}
if (rlen != sm->user->password_len ||
- os_memcmp(pos, sm->user->password, rlen) != 0) {
+ os_memcmp_const(pos, sm->user->password, rlen) != 0) {
wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
data->state = FAILURE;
} else {
diff --git a/contrib/wpa/src/eap_server/eap_server_identity.c b/contrib/wpa/src/eap_server/eap_server_identity.c
index 51dc4e8..4501533 100644
--- a/contrib/wpa/src/eap_server/eap_server_identity.c
+++ b/contrib/wpa/src/eap_server/eap_server_identity.c
@@ -102,6 +102,7 @@ static void eap_identity_process(struct eap_sm *sm, void *priv,
struct eap_identity_data *data = priv;
const u8 *pos;
size_t len;
+ char *buf;
if (data->pick_up) {
if (eap_identity_check(sm, data, respData)) {
@@ -119,6 +120,12 @@ static void eap_identity_process(struct eap_sm *sm, void *priv,
return; /* Should not happen - frame already validated */
wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
+ buf = os_malloc(len * 4 + 1);
+ if (buf) {
+ printf_encode(buf, len * 4 + 1, pos, len);
+ eap_log_msg(sm, "EAP-Response/Identity '%s'", buf);
+ os_free(buf);
+ }
if (sm->identity)
sm->update_user = TRUE;
os_free(sm->identity);
diff --git a/contrib/wpa/src/eap_server/eap_server_ikev2.c b/contrib/wpa/src/eap_server/eap_server_ikev2.c
index 42aaca2..16e6276 100644
--- a/contrib/wpa/src/eap_server/eap_server_ikev2.c
+++ b/contrib/wpa/src/eap_server/eap_server_ikev2.c
@@ -103,8 +103,11 @@ 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 = (u8 *) os_strdup("hostapd");
- data->ikev2.IDi_len = 7;
+ data->ikev2.IDi = os_malloc(sm->server_id_len);
+ if (data->ikev2.IDi == NULL)
+ goto failed;
+ os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len);
+ data->ikev2.IDi_len = sm->server_id_len;
data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
data->ikev2.cb_ctx = sm;
@@ -124,7 +127,7 @@ static void eap_ikev2_reset(struct eap_sm *sm, void *priv)
wpabuf_free(data->in_buf);
wpabuf_free(data->out_buf);
ikev2_initiator_deinit(&data->ikev2);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -253,7 +256,8 @@ static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
const struct wpabuf *respData,
- u8 flags, const u8 *pos, const u8 **end)
+ u8 flags, const u8 *pos, const u8 **end,
+ int frag_ack)
{
if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
int icv_len = eap_ikev2_validate_icv(
@@ -263,7 +267,7 @@ static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
return -1;
/* Hide Integrity Checksum Data from further processing */
*end -= icv_len;
- } else if (data->keys_ready) {
+ } else if (data->keys_ready && !frag_ack) {
wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
"included integrity checksum");
return -1;
@@ -305,6 +309,12 @@ static int eap_ikev2_process_fragment(struct eap_ikev2_data *data,
if (data->in_buf == NULL) {
/* First fragment of the message */
+ if (message_length > 50000) {
+ /* Limit maximum memory allocation */
+ wpa_printf(MSG_DEBUG,
+ "EAP-IKEV2: Ignore too long message");
+ return -1;
+ }
data->in_buf = wpabuf_alloc(message_length);
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
@@ -362,7 +372,9 @@ static void eap_ikev2_process(struct eap_sm *sm, void *priv,
} else
flags = *pos++;
- if (eap_ikev2_process_icv(data, respData, flags, pos, &end) < 0) {
+ if (eap_ikev2_process_icv(data, respData, flags, pos, &end,
+ data->state == WAIT_FRAG_ACK && len == 0) < 0)
+ {
eap_ikev2_state(data, FAIL);
return;
}
@@ -505,6 +517,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ikev2_data *data = priv;
+ u8 *sid;
+ size_t sid_len;
+ size_t offset;
+
+ if (data->state != DONE || !data->keymat_ok)
+ return NULL;
+
+ sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+ sid = os_malloc(sid_len);
+ if (sid) {
+ offset = 0;
+ sid[offset] = EAP_TYPE_IKEV2;
+ offset++;
+ os_memcpy(sid + offset, data->ikev2.i_nonce,
+ data->ikev2.i_nonce_len);
+ offset += data->ikev2.i_nonce_len;
+ os_memcpy(sid + offset, data->ikev2.r_nonce,
+ data->ikev2.r_nonce_len);
+ *len = sid_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+ sid, sid_len);
+ }
+
+ return sid;
+}
+
+
int eap_server_ikev2_register(void)
{
struct eap_method *eap;
@@ -525,6 +567,7 @@ int eap_server_ikev2_register(void)
eap->getKey = eap_ikev2_getKey;
eap->isSuccess = eap_ikev2_isSuccess;
eap->get_emsk = eap_ikev2_get_emsk;
+ eap->getSessionId = eap_ikev2_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_md5.c b/contrib/wpa/src/eap_server/eap_server_md5.c
index 5a5e290..71e8d59 100644
--- a/contrib/wpa/src/eap_server/eap_server_md5.c
+++ b/contrib/wpa/src/eap_server/eap_server_md5.c
@@ -126,7 +126,7 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
return;
}
- if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) {
+ if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) {
wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
data->state = SUCCESS;
} else {
diff --git a/contrib/wpa/src/eap_server/eap_server_methods.c b/contrib/wpa/src/eap_server/eap_server_methods.c
index 0209fad..9e9dc93 100644
--- a/contrib/wpa/src/eap_server/eap_server_methods.c
+++ b/contrib/wpa/src/eap_server/eap_server_methods.c
@@ -153,7 +153,7 @@ void eap_server_unregister_methods(void)
* eap_server_get_name - Get EAP method name for the given EAP type
* @vendor: EAP Vendor-Id (0 = IETF)
* @type: EAP method type
- * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ * Returns: EAP method name, e.g., TLS, or "unknown" if not found
*
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
@@ -167,5 +167,5 @@ const char * eap_server_get_name(int vendor, EapType type)
if (m->vendor == vendor && m->method == type)
return m->name;
}
- return NULL;
+ return "unknown";
}
diff --git a/contrib/wpa/src/eap_server/eap_server_mschapv2.c b/contrib/wpa/src/eap_server/eap_server_mschapv2.c
index 8d3dd52..05848d2 100644
--- a/contrib/wpa/src/eap_server/eap_server_mschapv2.c
+++ b/contrib/wpa/src/eap_server/eap_server_mschapv2.c
@@ -91,7 +91,7 @@ static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
return;
os_free(data->peer_challenge);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -100,7 +100,6 @@ static struct wpabuf * eap_mschapv2_build_challenge(
{
struct wpabuf *req;
struct eap_mschapv2_hdr *ms;
- char *name = "hostapd"; /* TODO: make this configurable */
size_t ms_len;
if (!data->auth_challenge_from_tls &&
@@ -111,7 +110,7 @@ static struct wpabuf * eap_mschapv2_build_challenge(
return NULL;
}
- ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
+ ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
@@ -133,7 +132,7 @@ static struct wpabuf * eap_mschapv2_build_challenge(
wpabuf_put(req, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
data->auth_challenge, CHALLENGE_LEN);
- wpabuf_put_data(req, name, os_strlen(name));
+ wpabuf_put_data(req, sm->server_id, sm->server_id_len);
return req;
}
@@ -291,6 +290,7 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
const u8 *username, *user;
size_t username_len, user_len;
int res;
+ char *buf;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
&len);
@@ -330,6 +330,13 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
+ buf = os_malloc(name_len * 4 + 1);
+ if (buf) {
+ printf_encode(buf, name_len * 4 + 1, name, name_len);
+ eap_log_msg(sm, "EAP-MSCHAPV2 Name '%s'", buf);
+ os_free(buf);
+ }
+
/* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present). */
@@ -386,7 +393,7 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
return;
}
- if (os_memcmp(nt_response, expected, 24) == 0) {
+ if (os_memcmp_const(nt_response, expected, 24) == 0) {
const u8 *pw_hash;
u8 pw_hash_buf[16], pw_hash_hash[16];
@@ -407,13 +414,16 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
}
pw_hash = pw_hash_buf;
}
- generate_authenticator_response_pwhash(
- pw_hash, peer_challenge, data->auth_challenge,
- username, username_len, nt_response,
- data->auth_response);
-
- hash_nt_password_hash(pw_hash, pw_hash_hash);
- get_master_key(pw_hash_hash, nt_response, data->master_key);
+ if (generate_authenticator_response_pwhash(
+ pw_hash, peer_challenge, data->auth_challenge,
+ username, username_len, nt_response,
+ data->auth_response) < 0 ||
+ hash_nt_password_hash(pw_hash, pw_hash_hash) < 0 ||
+ get_master_key(pw_hash_hash, nt_response,
+ data->master_key)) {
+ data->state = FAILURE;
+ return;
+ }
data->master_key_valid = 1;
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
data->master_key, MSCHAPV2_KEY_LEN);
diff --git a/contrib/wpa/src/eap_server/eap_server_pax.c b/contrib/wpa/src/eap_server/eap_server_pax.c
index 35a42ad..0e6b4a0 100644
--- a/contrib/wpa/src/eap_server/eap_server_pax.c
+++ b/contrib/wpa/src/eap_server/eap_server_pax.c
@@ -36,6 +36,7 @@ struct eap_pax_data {
u8 mk[EAP_PAX_MK_LEN];
u8 ck[EAP_PAX_CK_LEN];
u8 ick[EAP_PAX_ICK_LEN];
+ u8 mid[EAP_PAX_MID_LEN];
int keys_set;
char *cid;
size_t cid_len;
@@ -64,7 +65,7 @@ static void eap_pax_reset(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
os_free(data->cid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -148,7 +149,6 @@ static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
(u8 *) data->cid, data->cid_len, NULL, 0, pos);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
pos, EAP_PAX_MAC_LEN);
- pos += EAP_PAX_MAC_LEN;
/* Optional ADE could be added here, if needed */
@@ -268,7 +268,7 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
wpabuf_mhead(respData),
wpabuf_len(respData) - EAP_PAX_ICV_LEN,
NULL, 0, NULL, 0, icvbuf);
- if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
+ if (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);
@@ -287,7 +287,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
struct eap_pax_hdr *resp;
u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
const u8 *pos;
- size_t len, left;
+ size_t len, left, cid_len;
int i;
if (data->state != PAX_STD_1)
@@ -320,7 +320,12 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
return;
}
- data->cid_len = WPA_GET_BE16(pos);
+ cid_len = WPA_GET_BE16(pos);
+ if (cid_len > 1500) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Too long CID");
+ return;
+ }
+ data->cid_len = cid_len;
os_free(data->cid);
data->cid = os_malloc(data->cid_len);
if (data->cid == NULL) {
@@ -383,7 +388,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
data->rand.e, data->mk, data->ck,
- data->ick) < 0) {
+ data->ick, data->mid) < 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
"key derivation");
data->state = FAILURE;
@@ -395,7 +400,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
data->rand.r.x, EAP_PAX_RAND_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
(u8 *) data->cid, data->cid_len, mac);
- if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
+ if (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)",
@@ -417,7 +422,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
wpabuf_head(respData),
wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
icvbuf);
- if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
+ if (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);
@@ -537,6 +542,26 @@ static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pax_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(1 + EAP_PAX_MID_LEN);
+ if (sid == NULL)
+ return NULL;
+
+ *len = 1 + EAP_PAX_MID_LEN;
+ sid[0] = EAP_TYPE_PAX;
+ os_memcpy(sid + 1, data->mid, EAP_PAX_MID_LEN);
+
+ return sid;
+}
+
+
int eap_server_pax_register(void)
{
struct eap_method *eap;
@@ -556,6 +581,7 @@ int eap_server_pax_register(void)
eap->getKey = eap_pax_getKey;
eap->isSuccess = eap_pax_isSuccess;
eap->get_emsk = eap_pax_get_emsk;
+ eap->getSessionId = eap_pax_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_peap.c b/contrib/wpa/src/eap_server/eap_server_peap.c
index 68253c4..faa0fd2 100644
--- a/contrib/wpa/src/eap_server/eap_server_peap.c
+++ b/contrib/wpa/src/eap_server/eap_server_peap.c
@@ -22,7 +22,6 @@
/* Maximum supported PEAP version
* 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
* 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
- * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
*/
#define EAP_PEAP_VERSION 1
@@ -99,33 +98,6 @@ static void eap_peap_state(struct eap_peap_data *data, int state)
}
-static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
-{
- struct wpabuf *e;
- struct eap_tlv_hdr *tlv;
-
- if (buf == NULL)
- return NULL;
-
- /* Encapsulate EAP packet in EAP-Payload TLV */
- wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
- e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
- if (e == NULL) {
- wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
- "for TLV encapsulation");
- wpabuf_free(buf);
- return NULL;
- }
- tlv = wpabuf_put(e, sizeof(*tlv));
- tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
- EAP_TLV_EAP_PAYLOAD_TLV);
- tlv->length = host_to_be16(wpabuf_len(buf));
- wpabuf_put_buf(e, buf);
- wpabuf_free(buf);
- return e;
-}
-
-
static void eap_peap_req_success(struct eap_sm *sm,
struct eap_peap_data *data)
{
@@ -200,7 +172,7 @@ static void eap_peap_reset(struct eap_sm *sm, void *priv)
wpabuf_free(data->pending_phase2_resp);
os_free(data->phase2_key);
wpabuf_free(data->soh_response);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -239,8 +211,6 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
return NULL;
}
buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
- if (data->peap_version >= 2 && buf)
- buf = eap_peapv2_tlv_eap_payload(buf);
if (buf == NULL)
return NULL;
@@ -374,12 +344,14 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
size_t mlen;
mlen = 6; /* Result TLV */
- if (data->crypto_binding != NO_BINDING)
+ if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
+ data->crypto_binding != NO_BINDING) {
mlen += 60; /* Cryptobinding TLV */
#ifdef EAP_SERVER_TNC
- if (data->soh_response)
- mlen += wpabuf_len(data->soh_response);
+ if (data->soh_response)
+ mlen += wpabuf_len(data->soh_response);
#endif /* EAP_SERVER_TNC */
+ }
buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
EAP_CODE_REQUEST, id);
@@ -425,8 +397,6 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
len[1] = 1;
tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
- if (data->peap_version >= 2)
- tlv_type |= EAP_TLV_TYPE_MANDATORY;
wpabuf_put_be16(buf, tlv_type);
wpabuf_put_be16(buf, 56);
@@ -505,8 +475,7 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
return eap_peap_build_start(sm, data, id);
case PHASE1:
case PHASE1_ID2:
- if (data->peap_version < 2 &&
- tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
"starting Phase2");
eap_peap_state(data, PHASE2_START);
@@ -626,7 +595,7 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
buf[60] = EAP_TYPE_PEAP;
hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
- if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
"cryptobinding TLV");
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
@@ -1079,47 +1048,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
wpabuf_free(in_decrypted);
in_decrypted = nbuf;
- } else if (data->peap_version >= 2) {
- struct eap_tlv_hdr *tlv;
- struct wpabuf *nmsg;
-
- if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
- "EAP TLV");
- wpabuf_free(in_decrypted);
- return;
- }
- tlv = wpabuf_mhead(in_decrypted);
- if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) !=
- EAP_TLV_EAP_PAYLOAD_TLV) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
- wpabuf_free(in_decrypted);
- return;
- }
- if (sizeof(*tlv) + be_to_host16(tlv->length) >
- wpabuf_len(in_decrypted)) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
- "length");
- wpabuf_free(in_decrypted);
- return;
- }
- hdr = (struct eap_hdr *) (tlv + 1);
- if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
- "EAP packet in EAP TLV");
- wpabuf_free(in_decrypted);
- return;
- }
-
- nmsg = wpabuf_alloc(be_to_host16(hdr->length));
- if (nmsg == NULL) {
- wpabuf_free(in_decrypted);
- return;
- }
-
- wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
- wpabuf_free(in_decrypted);
- in_decrypted = nmsg;
}
hdr = wpabuf_head(in_decrypted);
@@ -1168,53 +1096,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
}
-static int eap_peapv2_start_phase2(struct eap_sm *sm,
- struct eap_peap_data *data)
-{
- struct wpabuf *buf, *buf2;
-
- wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
- "payload in the same message");
- eap_peap_state(data, PHASE1_ID2);
- if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
- return -1;
-
- /* TODO: which Id to use here? */
- buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
- if (buf == NULL)
- return -1;
-
- buf2 = eap_peapv2_tlv_eap_payload(buf);
- if (buf2 == NULL)
- return -1;
-
- wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);
-
- buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
- buf2);
- wpabuf_free(buf2);
-
- if (buf == NULL) {
- wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
- "data");
- return -1;
- }
-
- wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
- buf);
-
- /* Append TLS data into the pending buffer after the Server Finished */
- if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) {
- wpabuf_free(buf);
- return -1;
- }
- wpabuf_put_buf(data->ssl.tls_out, buf);
- wpabuf_free(buf);
-
- return 0;
-}
-
-
static int eap_peap_process_version(struct eap_sm *sm, void *priv,
int peer_version)
{
@@ -1249,14 +1130,6 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
eap_peap_state(data, FAILURE);
break;
}
-
- if (data->peap_version >= 2 &&
- tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- if (eap_peapv2_start_phase2(sm, data)) {
- eap_peap_state(data, FAILURE);
- break;
- }
- }
break;
case PHASE2_START:
eap_peap_state(data, PHASE2_ID);
@@ -1358,6 +1231,18 @@ static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
+ len);
+}
+
+
int eap_server_peap_register(void)
{
struct eap_method *eap;
@@ -1376,6 +1261,7 @@ int eap_server_peap_register(void)
eap->isDone = eap_peap_isDone;
eap->getKey = eap_peap_getKey;
eap->isSuccess = eap_peap_isSuccess;
+ eap->getSessionId = eap_peap_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_psk.c b/contrib/wpa/src/eap_server/eap_server_psk.c
index 0cd9799..12b5d25 100644
--- a/contrib/wpa/src/eap_server/eap_server_psk.c
+++ b/contrib/wpa/src/eap_server/eap_server_psk.c
@@ -22,8 +22,8 @@ struct eap_psk_data {
enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
u8 rand_s[EAP_PSK_RAND_LEN];
u8 rand_p[EAP_PSK_RAND_LEN];
- u8 *id_p, *id_s;
- size_t id_p_len, id_s_len;
+ u8 *id_p;
+ size_t id_p_len;
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
@@ -38,8 +38,6 @@ static void * eap_psk_init(struct eap_sm *sm)
if (data == NULL)
return NULL;
data->state = PSK_1;
- data->id_s = (u8 *) "hostapd";
- data->id_s_len = 7;
return data;
}
@@ -49,7 +47,7 @@ static void eap_psk_reset(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
os_free(data->id_p);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -70,7 +68,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
data->rand_s, EAP_PSK_RAND_LEN);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
- sizeof(*psk) + data->id_s_len,
+ sizeof(*psk) + sm->server_id_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -82,7 +80,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
psk = wpabuf_put(req, sizeof(*psk));
psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
- wpabuf_put_data(req, data->id_s, data->id_s_len);
+ wpabuf_put_data(req, sm->server_id, sm->server_id_len);
return req;
}
@@ -112,13 +110,13 @@ static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
- buflen = data->id_s_len + EAP_PSK_RAND_LEN;
+ buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL)
goto fail;
- os_memcpy(buf, data->id_s, data->id_s_len);
- os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(buf, sm->server_id, sm->server_id_len);
+ os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
os_free(buf);
goto fail;
@@ -296,7 +294,7 @@ static void eap_psk_process_2(struct eap_sm *sm,
os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
- buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
+ buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL) {
data->state = FAILURE;
@@ -304,8 +302,8 @@ static void eap_psk_process_2(struct eap_sm *sm,
}
os_memcpy(buf, data->id_p, data->id_p_len);
pos = buf + data->id_p_len;
- os_memcpy(pos, data->id_s, data->id_s_len);
- pos += data->id_s_len;
+ os_memcpy(pos, sm->server_id, sm->server_id_len);
+ pos += sm->server_id_len;
os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
@@ -316,7 +314,7 @@ static void eap_psk_process_2(struct eap_sm *sm,
}
os_free(buf);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN);
- if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P");
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P",
mac, EAP_PSK_MAC_LEN);
@@ -487,6 +485,28 @@ static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_psk_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_PSK_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_PSK;
+ os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_psk_register(void)
{
struct eap_method *eap;
@@ -506,6 +526,7 @@ int eap_server_psk_register(void)
eap->getKey = eap_psk_getKey;
eap->isSuccess = eap_psk_isSuccess;
eap->get_emsk = eap_psk_get_emsk;
+ eap->getSessionId = eap_psk_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_pwd.c b/contrib/wpa/src/eap_server/eap_server_pwd.c
index b61061b..943af0d1 100644
--- a/contrib/wpa/src/eap_server/eap_server_pwd.c
+++ b/contrib/wpa/src/eap_server/eap_server_pwd.c
@@ -45,6 +45,7 @@ struct eap_pwd_data {
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
+ u8 session_id[1 + SHA256_MAC_LEN];
BN_CTX *bnctx;
};
@@ -105,7 +106,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
if (data->password == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
"fail");
- os_free(data->id_server);
+ bin_clear_free(data->id_server, data->id_server_len);
os_free(data);
return NULL;
}
@@ -115,15 +116,16 @@ static void * eap_pwd_init(struct eap_sm *sm)
data->bnctx = BN_CTX_new();
if (data->bnctx == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
- os_free(data->password);
- os_free(data->id_server);
+ bin_clear_free(data->password, data->password_len);
+ bin_clear_free(data->id_server, data->id_server_len);
os_free(data);
return NULL;
}
data->in_frag_pos = data->out_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
- data->mtu = 1020; /* default from RFC 5931, make it configurable! */
+ /* use default MTU from RFC 5931 if not configured otherwise */
+ data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
return data;
}
@@ -133,24 +135,26 @@ static void eap_pwd_reset(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
- BN_free(data->private_value);
- BN_free(data->peer_scalar);
- BN_free(data->my_scalar);
- BN_free(data->k);
+ BN_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_free(data->my_element);
- EC_POINT_free(data->peer_element);
- os_free(data->id_peer);
- os_free(data->id_server);
- os_free(data->password);
+ EC_POINT_clear_free(data->my_element);
+ EC_POINT_clear_free(data->peer_element);
+ 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_free(data->grp->pwe);
- BN_free(data->grp->order);
- BN_free(data->grp->prime);
+ EC_POINT_clear_free(data->grp->pwe);
+ BN_clear_free(data->grp->order);
+ BN_clear_free(data->grp->prime);
os_free(data->grp);
}
- os_free(data);
+ wpabuf_free(data->inbuf);
+ wpabuf_free(data->outbuf);
+ bin_clear_free(data, sizeof(*data));
}
@@ -206,11 +210,15 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
goto fin;
}
- BN_rand_range(data->private_value, data->grp->order);
- BN_rand_range(mask, data->grp->order);
- BN_add(data->my_scalar, data->private_value, mask);
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx);
+ if (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");
+ goto fin;
+ }
if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
data->grp->pwe, mask, data->bnctx)) {
@@ -226,7 +234,7 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
"fail");
goto fin;
}
- BN_free(mask);
+ BN_clear_free(mask);
if (((x = BN_new()) == NULL) ||
((y = BN_new()) == NULL)) {
@@ -278,8 +286,8 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
fin:
os_free(scalar);
os_free(element);
- BN_free(x);
- BN_free(y);
+ BN_clear_free(x);
+ BN_clear_free(y);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
@@ -402,9 +410,9 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- os_free(cruft);
- BN_free(x);
- BN_free(y);
+ bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+ BN_clear_free(x);
+ BN_clear_free(y);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
@@ -523,6 +531,7 @@ eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
*/
if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
wpabuf_free(data->outbuf);
+ data->outbuf = NULL;
data->out_frag_pos = 0;
}
@@ -595,7 +604,8 @@ 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);
- if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) {
+ data->grp = os_zalloc(sizeof(EAP_PWD_group));
+ if (data->grp == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
"group");
return;
@@ -718,11 +728,11 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
res = 1;
fin:
- EC_POINT_free(K);
- EC_POINT_free(point);
- BN_free(cofactor);
- BN_free(x);
- BN_free(y);
+ EC_POINT_clear_free(K);
+ EC_POINT_clear_free(point);
+ BN_clear_free(cofactor);
+ BN_clear_free(x);
+ BN_clear_free(y);
if (res)
eap_pwd_state(data, PWD_Confirm_Req);
@@ -829,7 +839,7 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
eap_pwd_h_final(hash, conf);
ptr = (u8 *) payload;
- if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+ if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
"verify");
goto fin;
@@ -838,15 +848,16 @@ 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,
data->peer_scalar, data->my_scalar, conf,
- data->my_confirm, &cs, data->msk, data->emsk) < 0)
+ data->my_confirm, &cs, data->msk, data->emsk,
+ data->session_id) < 0)
eap_pwd_state(data, FAILURE);
else
eap_pwd_state(data, SUCCESS);
fin:
- os_free(cruft);
- BN_free(x);
- BN_free(y);
+ bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+ BN_clear_free(x);
+ BN_clear_free(y);
}
@@ -893,6 +904,8 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
tot_len = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
"length = %d", tot_len);
+ if (tot_len > 15000)
+ return;
data->inbuf = wpabuf_alloc(tot_len);
if (data->inbuf == NULL) {
wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
@@ -949,6 +962,7 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
*/
if (data->in_frag_pos) {
wpabuf_free(data->inbuf);
+ data->inbuf = NULL;
data->in_frag_pos = 0;
}
}
@@ -1006,6 +1020,25 @@ static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
}
+static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pwd_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ id = os_malloc(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;
+}
+
+
int eap_server_pwd_register(void)
{
struct eap_method *eap;
@@ -1014,8 +1047,6 @@ int eap_server_pwd_register(void)
struct timezone tz;
u32 sr;
- EVP_add_digest(EVP_sha256());
-
sr = 0xdeaddada;
(void) gettimeofday(&tp, &tz);
sr ^= (tp.tv_sec ^ tp.tv_usec);
@@ -1036,6 +1067,7 @@ int eap_server_pwd_register(void)
eap->getKey = eap_pwd_getkey;
eap->get_emsk = eap_pwd_get_emsk;
eap->isSuccess = eap_pwd_is_success;
+ eap->getSessionId = eap_pwd_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_sake.c b/contrib/wpa/src/eap_server/eap_server_sake.c
index f72e1bf..de70777 100644
--- a/contrib/wpa/src/eap_server/eap_server_sake.c
+++ b/contrib/wpa/src/eap_server/eap_server_sake.c
@@ -27,8 +27,6 @@ struct eap_sake_data {
u8 session_id;
u8 *peerid;
size_t peerid_len;
- u8 *serverid;
- size_t serverid_len;
};
@@ -77,11 +75,6 @@ static void * eap_sake_init(struct eap_sm *sm)
wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
data->session_id);
- /* TODO: add support for configuring SERVERID */
- data->serverid = (u8 *) os_strdup("hostapd");
- if (data->serverid)
- data->serverid_len = os_strlen((char *) data->serverid);
-
return data;
}
@@ -89,9 +82,8 @@ static void * eap_sake_init(struct eap_sm *sm)
static void eap_sake_reset(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
- os_free(data->serverid);
os_free(data->peerid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -131,8 +123,7 @@ static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
plen = 4;
- if (data->serverid)
- plen += 2 + data->serverid_len;
+ plen += 2 + sm->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
if (msg == NULL) {
data->state = FAILURE;
@@ -142,11 +133,9 @@ static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
- if (data->serverid) {
- wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
- eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- data->serverid, data->serverid_len);
- }
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+ eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+ sm->server_id, sm->server_id_len);
return msg;
}
@@ -169,9 +158,7 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
data->rand_s, EAP_SAKE_RAND_LEN);
- plen = 2 + EAP_SAKE_RAND_LEN;
- if (data->serverid)
- plen += 2 + data->serverid_len;
+ plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
if (msg == NULL) {
data->state = FAILURE;
@@ -182,11 +169,9 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
data->rand_s, EAP_SAKE_RAND_LEN);
- if (data->serverid) {
- wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
- eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- data->serverid, data->serverid_len);
- }
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+ eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+ sm->server_id, sm->server_id_len);
return msg;
}
@@ -213,7 +198,7 @@ static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- data->serverid, data->serverid_len,
+ sm->server_id, sm->server_id_len,
data->peerid, data->peerid_len, 0,
wpabuf_head(msg), wpabuf_len(msg), mic, mic))
{
@@ -362,11 +347,11 @@ static void eap_sake_process_challenge(struct eap_sm *sm,
(u8 *) &data->tek, data->msk, data->emsk);
eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- data->serverid, data->serverid_len,
+ sm->server_id, sm->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p);
- if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+ 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);
return;
@@ -399,11 +384,11 @@ static void eap_sake_process_confirm(struct eap_sm *sm,
}
eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- data->serverid, data->serverid_len,
+ sm->server_id, sm->server_id_len,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p);
- if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+ 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);
} else
@@ -510,6 +495,28 @@ static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_SAKE_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SAKE;
+ os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
+ os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_sake_register(void)
{
struct eap_method *eap;
@@ -529,6 +536,7 @@ int eap_server_sake_register(void)
eap->getKey = eap_sake_getKey;
eap->isSuccess = eap_sake_isSuccess;
eap->get_emsk = eap_sake_get_emsk;
+ eap->getSessionId = eap_sake_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_sim.c b/contrib/wpa/src/eap_server/eap_server_sim.c
index b531241..ddfb71c 100644
--- a/contrib/wpa/src/eap_server/eap_server_sim.c
+++ b/contrib/wpa/src/eap_server/eap_server_sim.c
@@ -94,7 +94,7 @@ static void eap_sim_reset(struct eap_sm *sm, void *priv)
struct eap_sim_data *data = priv;
os_free(data->next_pseudonym);
os_free(data->next_reauth_id);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -140,7 +140,7 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
ver[1] = EAP_SIM_VERSION;
eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
ver, sizeof(ver));
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
}
@@ -240,8 +240,8 @@ static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt,
- EAP_SIM_NONCE_MT_LEN);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
}
@@ -278,7 +278,7 @@ static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
}
@@ -317,7 +317,7 @@ static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
}
@@ -820,6 +820,29 @@ static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SIM;
+ os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+ os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
+ EAP_SIM_NONCE_MT_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_sim_register(void)
{
struct eap_method *eap;
@@ -839,6 +862,7 @@ int eap_server_sim_register(void)
eap->getKey = eap_sim_getKey;
eap->isSuccess = eap_sim_isSuccess;
eap->get_emsk = eap_sim_get_emsk;
+ eap->getSessionId = eap_sim_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_tls.c b/contrib/wpa/src/eap_server/eap_server_tls.c
index 447f47c..58cfe8a 100644
--- a/contrib/wpa/src/eap_server/eap_server_tls.c
+++ b/contrib/wpa/src/eap_server/eap_server_tls.c
@@ -94,6 +94,28 @@ static void * eap_unauth_tls_init(struct eap_sm *sm)
#endif /* EAP_SERVER_UNAUTH_TLS */
+#ifdef CONFIG_HS20
+static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = START;
+
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+ eap_tls_reset(sm, data);
+ return NULL;
+ }
+
+ data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
+ return data;
+}
+#endif /* CONFIG_HS20 */
+
+
static void eap_tls_reset(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
@@ -178,6 +200,10 @@ static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
&len);
+ else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
+ EAP_VENDOR_WFA_UNAUTH_TLS, respData,
+ &len);
else
pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
respData, &len);
@@ -261,7 +287,7 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (emsk)
os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
EAP_EMSK_LEN);
- os_free(eapKeyData);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
} else
emsk = NULL;
@@ -284,6 +310,18 @@ static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_tls_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
+ len);
+}
+
+
int eap_server_tls_register(void)
{
struct eap_method *eap;
@@ -303,6 +341,7 @@ int eap_server_tls_register(void)
eap->getKey = eap_tls_getKey;
eap->isSuccess = eap_tls_isSuccess;
eap->get_emsk = eap_tls_get_emsk;
+ eap->getSessionId = eap_tls_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
@@ -340,3 +379,34 @@ int eap_server_unauth_tls_register(void)
return ret;
}
#endif /* EAP_SERVER_UNAUTH_TLS */
+
+
+#ifdef CONFIG_HS20
+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,
+ EAP_VENDOR_WFA_UNAUTH_TLS,
+ "WFA-UNAUTH-TLS");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_wfa_unauth_tls_init;
+ eap->reset = eap_tls_reset;
+ eap->buildReq = eap_tls_buildReq;
+ eap->check = eap_tls_check;
+ eap->process = eap_tls_process;
+ eap->isDone = eap_tls_isDone;
+ eap->getKey = eap_tls_getKey;
+ eap->isSuccess = eap_tls_isSuccess;
+ eap->get_emsk = eap_tls_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
+#endif /* 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 9efb5b2..56916c4 100644
--- a/contrib/wpa/src/eap_server/eap_server_tls_common.c
+++ b/contrib/wpa/src/eap_server/eap_server_tls_common.c
@@ -25,14 +25,32 @@ struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
code, identifier);
+ else if (type == EAP_WFA_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
+ EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
+ code, identifier);
return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
identifier);
}
+#ifdef CONFIG_TLS_INTERNAL
+static void eap_server_tls_log_cb(void *ctx, const char *msg)
+{
+ struct eap_sm *sm = ctx;
+ eap_log_msg(sm, "TLS: %s", msg);
+}
+#endif /* CONFIG_TLS_INTERNAL */
+
+
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer)
{
+ if (sm->ssl_ctx == NULL) {
+ wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
+ return -1;
+ }
+
data->eap = sm;
data->phase2 = sm->init_phase2;
@@ -43,6 +61,13 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
return -1;
}
+#ifdef CONFIG_TLS_INTERNAL
+ tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm);
+#ifdef CONFIG_TESTING_OPTIONS
+ tls_connection_set_test_flags(data->conn, sm->tls_test_flags);
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_TLS_INTERNAL */
+
if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
@@ -115,6 +140,47 @@ fail:
}
+/**
+ * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len)
+{
+ struct tls_keys keys;
+ u8 *out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+
+ if (keys.client_random == NULL || keys.server_random == NULL)
+ return NULL;
+
+ *len = 1 + keys.client_random_len + keys.server_random_len;
+ out = os_malloc(*len);
+ if (out == NULL)
+ return NULL;
+
+ /* Session-Id = EAP type || client.random || server.random */
+ out[0] = eap_type;
+ os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+ os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ return out;
+}
+
+
struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
int eap_type, int version, u8 id)
{
@@ -388,6 +454,10 @@ int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
&left);
+ else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
+ EAP_VENDOR_WFA_UNAUTH_TLS, respData,
+ &left);
else
pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
&left);
diff --git a/contrib/wpa/src/eap_server/eap_server_tnc.c b/contrib/wpa/src/eap_server/eap_server_tnc.c
index 67a3dfa..21bd26f 100644
--- a/contrib/wpa/src/eap_server/eap_server_tnc.c
+++ b/contrib/wpa/src/eap_server/eap_server_tnc.c
@@ -480,7 +480,8 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv,
message_length = WPA_GET_BE32(pos);
pos += 4;
- if (message_length < (u32) (end - pos)) {
+ if (message_length < (u32) (end - pos) ||
+ message_length > 75000) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
diff --git a/contrib/wpa/src/eap_server/eap_server_ttls.c b/contrib/wpa/src/eap_server/eap_server_ttls.c
index 647bd2f..12a31b0 100644
--- a/contrib/wpa/src/eap_server/eap_server_ttls.c
+++ b/contrib/wpa/src/eap_server/eap_server_ttls.c
@@ -336,7 +336,7 @@ static void eap_ttls_reset(struct eap_sm *sm, void *priv)
data->phase2_method->reset(sm, data->phase2_priv);
eap_server_tls_ssl_deinit(sm, &data->ssl);
wpabuf_free(data->pending_phase2_eap_resp);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -409,7 +409,7 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2(
RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
*pos++ = data->mschapv2_ident;
ret = os_snprintf((char *) pos, end - pos, "S=");
- if (ret >= 0 && ret < end - pos)
+ if (!os_snprintf_error(end - pos, ret))
pos += ret;
pos += wpa_snprintf_hex_uppercase(
(char *) pos, end - pos, data->mschapv2_auth_response,
@@ -509,8 +509,8 @@ static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
}
if (sm->user->password_len != user_password_len ||
- os_memcmp(sm->user->password, user_password, user_password_len) !=
- 0) {
+ os_memcmp_const(sm->user->password, user_password,
+ user_password_len) != 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password");
eap_ttls_state(data, FAILURE);
return;
@@ -558,7 +558,8 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
return;
}
- if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 ||
+ if (os_memcmp_const(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN)
+ != 0 ||
password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch");
os_free(chal);
@@ -571,7 +572,8 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
chap_md5(password[0], sm->user->password, sm->user->password_len,
challenge, challenge_len, hash);
- if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
+ if (os_memcmp_const(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) ==
+ 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
eap_ttls_state(data, SUCCESS);
} else {
@@ -616,7 +618,8 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
return;
}
- if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 ||
+ if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN)
+ != 0 ||
response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch");
os_free(chal);
@@ -631,7 +634,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
nt_challenge_response(challenge, sm->user->password,
sm->user->password_len, nt_response);
- if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
+ if (os_memcmp_const(nt_response, response + 2 + 24, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
eap_ttls_state(data, SUCCESS);
} else {
@@ -703,7 +706,8 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
return;
}
- if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 ||
+ if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN)
+ != 0 ||
response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch");
os_free(chal);
@@ -736,7 +740,7 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
}
rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
- if (os_memcmp(nt_response, rx_resp, 24) == 0) {
+ if (os_memcmp_const(nt_response, rx_resp, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
"NT-Response");
data->mschapv2_resp_ok = 1;
@@ -984,6 +988,16 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
}
if (parse.user_name) {
+ char *nbuf;
+ nbuf = os_malloc(parse.user_name_len * 4 + 1);
+ if (nbuf) {
+ printf_encode(nbuf, parse.user_name_len * 4 + 1,
+ parse.user_name,
+ parse.user_name_len);
+ eap_log_msg(sm, "TTLS-User-Name '%s'", nbuf);
+ os_free(nbuf);
+ }
+
os_free(sm->identity);
sm->identity = os_malloc(parse.user_name_len);
if (sm->identity == NULL) {
@@ -1167,6 +1181,50 @@ static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TTLS,
+ len);
+}
+
+
+static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *eapKeyData, *emsk;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+ "ttls keying material",
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (eapKeyData) {
+ emsk = os_malloc(EAP_EMSK_LEN);
+ if (emsk)
+ os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ } else
+ emsk = NULL;
+
+ if (emsk) {
+ *len = EAP_EMSK_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+ emsk, EAP_EMSK_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive EMSK");
+ }
+
+ return emsk;
+}
+
+
int eap_server_ttls_register(void)
{
struct eap_method *eap;
@@ -1185,6 +1243,8 @@ int eap_server_ttls_register(void)
eap->isDone = eap_ttls_isDone;
eap->getKey = eap_ttls_getKey;
eap->isSuccess = eap_ttls_isSuccess;
+ eap->getSessionId = eap_ttls_get_session_id;
+ eap->get_emsk = eap_ttls_get_emsk;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/contrib/wpa/src/eap_server/eap_server_wsc.c b/contrib/wpa/src/eap_server/eap_server_wsc.c
index 97ec0c0..9d9c28d 100644
--- a/contrib/wpa/src/eap_server/eap_server_wsc.c
+++ b/contrib/wpa/src/eap_server/eap_server_wsc.c
@@ -380,7 +380,7 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv,
message_length = WPA_GET_BE16(pos);
pos += 2;
- if (message_length < end - pos) {
+ if (message_length < end - pos || message_length > 50000) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
"Length");
return;
diff --git a/contrib/wpa/src/eap_server/eap_sim_db.c b/contrib/wpa/src/eap_server/eap_sim_db.c
index 257013e..acf5435 100644
--- a/contrib/wpa/src/eap_server/eap_sim_db.c
+++ b/contrib/wpa/src/eap_server/eap_sim_db.c
@@ -38,7 +38,6 @@ struct eap_sim_db_pending {
char imsi[20];
enum { PENDING, SUCCESS, FAILURE } state;
void *cb_session_ctx;
- struct os_time timestamp;
int aka;
union {
struct {
@@ -574,16 +573,14 @@ static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
char buf[1000], *pos, *cmd, *imsi;
int res;
- res = recv(sock, buf, sizeof(buf), 0);
+ res = recv(sock, buf, sizeof(buf) - 1, 0);
if (res < 0)
return;
+ buf[res] = '\0';
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
"external source", (u8 *) buf, res);
if (res == 0)
return;
- if (res >= (int) sizeof(buf))
- res = sizeof(buf) - 1;
- buf[res] = '\0';
if (data->get_complete_cb == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
@@ -630,7 +627,7 @@ static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (data->sock < 0) {
- perror("socket(eap_sim_db)");
+ wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
return -1;
}
@@ -640,8 +637,13 @@ static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
"/tmp/eap_sim_db_%d-%d", getpid(), counter++);
os_free(data->local_sock);
data->local_sock = os_strdup(addr.sun_path);
+ if (data->local_sock == NULL) {
+ close(data->sock);
+ data->sock = -1;
+ return -1;
+ }
if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(eap_sim_db)");
+ wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
close(data->sock);
data->sock = -1;
return -1;
@@ -651,12 +653,16 @@ static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("connect(eap_sim_db)");
+ wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
+ strerror(errno));
wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
(u8 *) addr.sun_path,
os_strlen(addr.sun_path));
close(data->sock);
data->sock = -1;
+ unlink(data->local_sock);
+ os_free(data->local_sock);
+ data->local_sock = NULL;
return -1;
}
@@ -804,7 +810,8 @@ static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
if (send(data->sock, msg, len, 0) < 0) {
_errno = errno;
- perror("send[EAP-SIM DB UNIX]");
+ wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+ strerror(errno));
}
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
@@ -816,7 +823,8 @@ static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
"external server");
if (send(data->sock, msg, len, 0) < 0) {
- perror("send[EAP-SIM DB UNIX]");
+ wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
+ strerror(errno));
return -1;
}
}
@@ -914,12 +922,13 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return EAP_SIM_DB_FAILURE;
len += ret;
@@ -932,7 +941,6 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
if (entry == NULL)
return EAP_SIM_DB_FAILURE;
- os_get_time(&entry->timestamp);
os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
entry->cb_session_ctx = cb_session_ctx;
entry->state = PENDING;
@@ -957,7 +965,7 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
pos = id;
end = id + sizeof(buf) * 2 + 2;
*pos++ = prefix;
- pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
+ wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
return id;
}
@@ -1378,7 +1386,8 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
@@ -1392,7 +1401,6 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
if (entry == NULL)
return EAP_SIM_DB_FAILURE;
- os_get_time(&entry->timestamp);
entry->aka = 1;
os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
entry->cb_session_ctx = cb_session_ctx;
@@ -1443,19 +1451,20 @@ int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return -1;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return -1;
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
auts, EAP_AKA_AUTS_LEN);
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return -1;
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
@@ -1480,7 +1489,6 @@ int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
*/
char * sim_get_username(const u8 *identity, size_t identity_len)
{
- char *username;
size_t pos;
if (identity == NULL)
@@ -1491,11 +1499,5 @@ char * sim_get_username(const u8 *identity, size_t identity_len)
break;
}
- username = os_malloc(pos + 1);
- if (username == NULL)
- return NULL;
- os_memcpy(username, identity, pos);
- username[pos] = '\0';
-
- return username;
+ return dup_binstr(identity, pos);
}
diff --git a/contrib/wpa/src/eap_server/eap_tls_common.h b/contrib/wpa/src/eap_server/eap_tls_common.h
index 11f5827..ddf90b8 100644
--- a/contrib/wpa/src/eap_server/eap_tls_common.h
+++ b/contrib/wpa/src/eap_server/eap_tls_common.h
@@ -64,6 +64,7 @@ struct eap_ssl_data {
/* dummy type used as a flag for UNAUTH-TLS */
#define EAP_UNAUTH_TLS_TYPE 255
+#define EAP_WFA_UNAUTH_TLS_TYPE 254
struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
@@ -73,6 +74,9 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
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);
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len);
struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
int eap_type, int version, u8 id);
struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);
diff --git a/contrib/wpa/src/eap_server/ikev2.c b/contrib/wpa/src/eap_server/ikev2.c
index 0e77efb..632598f 100644
--- a/contrib/wpa/src/eap_server/ikev2.c
+++ b/contrib/wpa/src/eap_server/ikev2.c
@@ -633,7 +633,7 @@ static int ikev2_process_auth_secret(struct ikev2_initiator_data *data,
return -1;
if (auth_len != prf->hash_len ||
- os_memcmp(auth, auth_data, auth_len) != 0) {
+ os_memcmp_const(auth, auth_data, auth_len) != 0) {
wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
auth, auth_len);
@@ -990,7 +990,7 @@ static int ikev2_build_kei(struct ikev2_initiator_data *data,
*/
wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
wpabuf_put_buf(msg, pv);
- os_free(pv);
+ wpabuf_free(pv);
plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
WPA_PUT_BE16(phdr->payload_length, plen);
diff --git a/contrib/wpa/src/eap_server/tncs.c b/contrib/wpa/src/eap_server/tncs.c
index 5e332ae..dc6f689 100644
--- a/contrib/wpa/src/eap_server/tncs.c
+++ b/contrib/wpa/src/eap_server/tncs.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "base64.h"
+#include "common/tnc.h"
#include "tncs.h"
#include "eap_common/eap_tlv_common.h"
#include "eap_common/eap_defs.h"
@@ -19,7 +20,9 @@
/* TODO: TNCS must be thread-safe; review the code and add locking etc. if
* needed.. */
+#ifndef TNC_CONFIG_FILE
#define TNC_CONFIG_FILE "/etc/tnc_config"
+#endif /* TNC_CONFIG_FILE */
#define IF_TNCCS_START \
"<?xml version=\"1.0\"?>\n" \
"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
@@ -31,75 +34,6 @@
/* TNC IF-IMV */
-typedef unsigned long TNC_UInt32;
-typedef unsigned char *TNC_BufferReference;
-
-typedef TNC_UInt32 TNC_IMVID;
-typedef TNC_UInt32 TNC_ConnectionID;
-typedef TNC_UInt32 TNC_ConnectionState;
-typedef TNC_UInt32 TNC_RetryReason;
-typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
-typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
-typedef TNC_UInt32 TNC_MessageType;
-typedef TNC_MessageType *TNC_MessageTypeList;
-typedef TNC_UInt32 TNC_VendorID;
-typedef TNC_UInt32 TNC_Subtype;
-typedef TNC_UInt32 TNC_Version;
-typedef TNC_UInt32 TNC_Result;
-typedef TNC_UInt32 TNC_AttributeID;
-
-typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
- TNC_IMVID imvID,
- char *functionName,
- void **pOutfunctionPointer);
-
-#define TNC_RESULT_SUCCESS 0
-#define TNC_RESULT_NOT_INITIALIZED 1
-#define TNC_RESULT_ALREADY_INITIALIZED 2
-#define TNC_RESULT_NO_COMMON_VERSION 3
-#define TNC_RESULT_CANT_RETRY 4
-#define TNC_RESULT_WONT_RETRY 5
-#define TNC_RESULT_INVALID_PARAMETER 6
-#define TNC_RESULT_CANT_RESPOND 7
-#define TNC_RESULT_ILLEGAL_OPERATION 8
-#define TNC_RESULT_OTHER 9
-#define TNC_RESULT_FATAL 10
-
-#define TNC_CONNECTION_STATE_CREATE 0
-#define TNC_CONNECTION_STATE_HANDSHAKE 1
-#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
-#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
-#define TNC_CONNECTION_STATE_ACCESS_NONE 4
-#define TNC_CONNECTION_STATE_DELETE 5
-
-#define TNC_IFIMV_VERSION_1 1
-
-#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
-#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
-
-/* TNCC-TNCS Message Types */
-#define TNC_TNCCS_RECOMMENDATION 0x00000001
-#define TNC_TNCCS_ERROR 0x00000002
-#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
-#define TNC_TNCCS_REASONSTRINGS 0x00000004
-
-/* Possible TNC_IMV_Action_Recommendation values: */
-enum IMV_Action_Recommendation {
- TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
- TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
- TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
- TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
-};
-
-/* Possible TNC_IMV_Evaluation_Result values: */
-enum IMV_Evaluation_Result {
- TNC_IMV_EVALUATION_RESULT_COMPLIANT,
- TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
- TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
- TNC_IMV_EVALUATION_RESULT_ERROR,
- TNC_IMV_EVALUATION_RESULT_DONT_KNOW
-};
-
struct tnc_if_imv {
struct tnc_if_imv *next;
char *name;
@@ -851,12 +785,10 @@ enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
unsigned char *decoded;
size_t decoded_len;
- buf = os_malloc(len + 1);
+ buf = dup_binstr(msg, len);
if (buf == NULL)
return TNCCS_PROCESS_ERROR;
- os_memcpy(buf, msg, len);
- buf[len] = '\0';
start = os_strstr(buf, "<TNCCS-Batch ");
end = os_strstr(buf, "</TNCCS-Batch>");
if (start == NULL || end == NULL || start > end) {
@@ -1183,6 +1115,9 @@ int tncs_global_init(void)
{
struct tnc_if_imv *imv;
+ if (tncs_global_data)
+ return 0;
+
tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
if (tncs_global_data == NULL)
return -1;
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_dump.c b/contrib/wpa/src/eapol_auth/eapol_auth_dump.c
index b6e0b13..5579582 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_dump.c
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_dump.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.1X-2004 Authenticator - State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -118,108 +118,172 @@ static inline const char * ctrl_dir_state_txt(int s)
}
-void eapol_auth_dump_state(FILE *f, const char *prefix,
- struct eapol_state_machine *sm)
+int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf,
+ size_t buflen)
{
- fprintf(f, "%sEAPOL state machine:\n", prefix);
- fprintf(f, "%s aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix,
- sm->aWhile, sm->quietWhile, sm->reAuthWhen);
+ char *pos, *end;
+ int ret;
+
+ pos = buf;
+ end = pos + buflen;
+
+ ret = os_snprintf(pos, end - pos, "aWhile=%d\nquietWhile=%d\n"
+ "reAuthWhen=%d\n",
+ sm->aWhile, sm->quietWhile, sm->reAuthWhen);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
#define _SB(b) ((b) ? "TRUE" : "FALSE")
- fprintf(f,
- "%s authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n"
- "%s authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n"
- "%s eapSuccess=%s eapTimeout=%s initialize=%s "
- "keyAvailable=%s\n"
- "%s keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n"
- "%s portEnabled=%s portValid=%s reAuthenticate=%s\n",
- prefix, _SB(sm->authAbort), _SB(sm->authFail),
- port_state_txt(sm->authPortStatus), _SB(sm->authStart),
- prefix, _SB(sm->authTimeout), _SB(sm->authSuccess),
- _SB(sm->eap_if->eapFail), _SB(sm->eapolEap),
- prefix, _SB(sm->eap_if->eapSuccess),
- _SB(sm->eap_if->eapTimeout),
- _SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable),
- prefix, _SB(sm->keyDone), _SB(sm->keyRun),
- _SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
- prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid),
- _SB(sm->reAuthenticate));
-
- fprintf(f, "%s Authenticator PAE:\n"
- "%s state=%s\n"
- "%s eapolLogoff=%s eapolStart=%s eapRestart=%s\n"
- "%s portMode=%s reAuthCount=%d\n"
- "%s quietPeriod=%d reAuthMax=%d\n"
- "%s authEntersConnecting=%d\n"
- "%s authEapLogoffsWhileConnecting=%d\n"
- "%s authEntersAuthenticating=%d\n"
- "%s authAuthSuccessesWhileAuthenticating=%d\n"
- "%s authAuthTimeoutsWhileAuthenticating=%d\n"
- "%s authAuthFailWhileAuthenticating=%d\n"
- "%s authAuthEapStartsWhileAuthenticating=%d\n"
- "%s authAuthEapLogoffWhileAuthenticating=%d\n"
- "%s authAuthReauthsWhileAuthenticated=%d\n"
- "%s authAuthEapStartsWhileAuthenticated=%d\n"
- "%s authAuthEapLogoffWhileAuthenticated=%d\n",
- prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
- _SB(sm->eapolLogoff), _SB(sm->eapolStart),
- _SB(sm->eap_if->eapRestart),
- prefix, port_type_txt(sm->portMode), sm->reAuthCount,
- prefix, sm->quietPeriod, sm->reAuthMax,
- prefix, sm->authEntersConnecting,
- prefix, sm->authEapLogoffsWhileConnecting,
- prefix, sm->authEntersAuthenticating,
- prefix, sm->authAuthSuccessesWhileAuthenticating,
- prefix, sm->authAuthTimeoutsWhileAuthenticating,
- prefix, sm->authAuthFailWhileAuthenticating,
- prefix, sm->authAuthEapStartsWhileAuthenticating,
- prefix, sm->authAuthEapLogoffWhileAuthenticating,
- prefix, sm->authAuthReauthsWhileAuthenticated,
- prefix, sm->authAuthEapStartsWhileAuthenticated,
- prefix, sm->authAuthEapLogoffWhileAuthenticated);
-
- fprintf(f, "%s Backend Authentication:\n"
- "%s state=%s\n"
- "%s eapNoReq=%s eapReq=%s eapResp=%s\n"
- "%s serverTimeout=%d\n"
- "%s backendResponses=%d\n"
- "%s backendAccessChallenges=%d\n"
- "%s backendOtherRequestsToSupplicant=%d\n"
- "%s backendAuthSuccesses=%d\n"
- "%s backendAuthFails=%d\n",
- prefix, prefix,
- be_auth_state_txt(sm->be_auth_state),
- prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq),
- _SB(sm->eap_if->eapResp),
- prefix, sm->serverTimeout,
- prefix, sm->backendResponses,
- prefix, sm->backendAccessChallenges,
- prefix, sm->backendOtherRequestsToSupplicant,
- prefix, sm->backendAuthSuccesses,
- prefix, sm->backendAuthFails);
-
- fprintf(f, "%s Reauthentication Timer:\n"
- "%s state=%s\n"
- "%s reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
- reauth_timer_state_txt(sm->reauth_timer_state), prefix,
- sm->reAuthPeriod, _SB(sm->reAuthEnabled));
-
- fprintf(f, "%s Authenticator Key Transmit:\n"
- "%s state=%s\n", prefix, prefix,
- auth_key_tx_state_txt(sm->auth_key_tx_state));
-
- fprintf(f, "%s Key Receive:\n"
- "%s state=%s\n"
- "%s rxKey=%s\n", prefix, prefix,
- key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
-
- fprintf(f, "%s Controlled Directions:\n"
- "%s state=%s\n"
- "%s adminControlledDirections=%s "
- "operControlledDirections=%s\n"
- "%s operEdge=%s\n", prefix, prefix,
- ctrl_dir_state_txt(sm->ctrl_dir_state),
- prefix, ctrl_dir_txt(sm->adminControlledDirections),
- ctrl_dir_txt(sm->operControlledDirections),
- prefix, _SB(sm->operEdge));
+ ret = os_snprintf(pos, end - pos,
+ "authAbort=%s\n"
+ "authFail=%s\n"
+ "authPortStatus=%s\n"
+ "authStart=%s\n"
+ "authTimeout=%s\n"
+ "authSuccess=%s\n"
+ "eapFail=%s\n"
+ "eapolEap=%s\n"
+ "eapSuccess=%s\n"
+ "eapTimeout=%s\n"
+ "initialize=%s\n"
+ "keyAvailable=%s\n"
+ "keyDone=%s\n"
+ "keyRun=%s\n"
+ "keyTxEnabled=%s\n"
+ "portControl=%s\n"
+ "portEnabled=%s\n"
+ "portValid=%s\n"
+ "reAuthenticate=%s\n",
+ _SB(sm->authAbort),
+ _SB(sm->authFail),
+ port_state_txt(sm->authPortStatus),
+ _SB(sm->authStart),
+ _SB(sm->authTimeout),
+ _SB(sm->authSuccess),
+ _SB(sm->eap_if->eapFail),
+ _SB(sm->eapolEap),
+ _SB(sm->eap_if->eapSuccess),
+ _SB(sm->eap_if->eapTimeout),
+ _SB(sm->initialize),
+ _SB(sm->eap_if->eapKeyAvailable),
+ _SB(sm->keyDone), _SB(sm->keyRun),
+ _SB(sm->keyTxEnabled),
+ port_type_txt(sm->portControl),
+ _SB(sm->eap_if->portEnabled),
+ _SB(sm->portValid),
+ _SB(sm->reAuthenticate));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos,
+ "auth_pae_state=%s\n"
+ "eapolLogoff=%s\n"
+ "eapolStart=%s\n"
+ "eapRestart=%s\n"
+ "portMode=%s\n"
+ "reAuthCount=%d\n"
+ "quietPeriod=%d\n"
+ "reAuthMax=%d\n"
+ "authEntersConnecting=%d\n"
+ "authEapLogoffsWhileConnecting=%d\n"
+ "authEntersAuthenticating=%d\n"
+ "authAuthSuccessesWhileAuthenticating=%d\n"
+ "authAuthTimeoutsWhileAuthenticating=%d\n"
+ "authAuthFailWhileAuthenticating=%d\n"
+ "authAuthEapStartsWhileAuthenticating=%d\n"
+ "authAuthEapLogoffWhileAuthenticating=%d\n"
+ "authAuthReauthsWhileAuthenticated=%d\n"
+ "authAuthEapStartsWhileAuthenticated=%d\n"
+ "authAuthEapLogoffWhileAuthenticated=%d\n",
+ auth_pae_state_txt(sm->auth_pae_state),
+ _SB(sm->eapolLogoff),
+ _SB(sm->eapolStart),
+ _SB(sm->eap_if->eapRestart),
+ port_type_txt(sm->portMode),
+ sm->reAuthCount,
+ sm->quietPeriod, sm->reAuthMax,
+ sm->authEntersConnecting,
+ sm->authEapLogoffsWhileConnecting,
+ sm->authEntersAuthenticating,
+ sm->authAuthSuccessesWhileAuthenticating,
+ sm->authAuthTimeoutsWhileAuthenticating,
+ sm->authAuthFailWhileAuthenticating,
+ sm->authAuthEapStartsWhileAuthenticating,
+ sm->authAuthEapLogoffWhileAuthenticating,
+ sm->authAuthReauthsWhileAuthenticated,
+ sm->authAuthEapStartsWhileAuthenticated,
+ sm->authAuthEapLogoffWhileAuthenticated);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos,
+ "be_auth_state=%s\n"
+ "eapNoReq=%s\n"
+ "eapReq=%s\n"
+ "eapResp=%s\n"
+ "serverTimeout=%d\n"
+ "backendResponses=%d\n"
+ "backendAccessChallenges=%d\n"
+ "backendOtherRequestsToSupplicant=%d\n"
+ "backendAuthSuccesses=%d\n"
+ "backendAuthFails=%d\n",
+ be_auth_state_txt(sm->be_auth_state),
+ _SB(sm->eap_if->eapNoReq),
+ _SB(sm->eap_if->eapReq),
+ _SB(sm->eap_if->eapResp),
+ sm->serverTimeout,
+ sm->backendResponses,
+ sm->backendAccessChallenges,
+ sm->backendOtherRequestsToSupplicant,
+ sm->backendAuthSuccesses,
+ sm->backendAuthFails);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos,
+ "reauth_timer_state=%s\n"
+ "reAuthPeriod=%d\n"
+ "reAuthEnabled=%s\n",
+ reauth_timer_state_txt(sm->reauth_timer_state),
+ sm->reAuthPeriod,
+ _SB(sm->reAuthEnabled));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos,
+ "auth_key_tx_state=%s\n",
+ auth_key_tx_state_txt(sm->auth_key_tx_state));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos,
+ "key_rx_state=%s\n"
+ "rxKey=%s\n",
+ key_rx_state_txt(sm->key_rx_state),
+ _SB(sm->rxKey));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos,
+ "ctrl_dir_state=%s\n"
+ "adminControlledDirections=%s\n"
+ "operControlledDirections=%s\n"
+ "operEdge=%s\n",
+ ctrl_dir_state_txt(sm->ctrl_dir_state),
+ ctrl_dir_txt(sm->adminControlledDirections),
+ ctrl_dir_txt(sm->operControlledDirections),
+ _SB(sm->operEdge));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
#undef _SB
+
+ return pos - buf;
}
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm.c b/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
index c3ccb46..0df6eb5 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.1X-2004 Authenticator - EAPOL state machine
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -43,6 +43,7 @@ sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
static void eapol_sm_step_run(struct eapol_state_machine *sm);
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
static void eapol_auth_initialize(struct eapol_state_machine *sm);
+static void eapol_auth_conf_free(struct eapol_auth_config *conf);
static void eapol_auth_logger(struct eapol_authenticator *eapol,
@@ -219,7 +220,8 @@ SM_STATE(AUTH_PAE, DISCONNECTED)
sm->eapolLogoff = FALSE;
if (!from_initialize) {
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
- sm->flags & EAPOL_SM_PREAUTH);
+ sm->flags & EAPOL_SM_PREAUTH,
+ sm->remediation);
}
}
@@ -276,7 +278,7 @@ SM_STATE(AUTH_PAE, HELD)
eap_server_get_name(0, sm->eap_type_supp));
}
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
- sm->flags & EAPOL_SM_PREAUTH);
+ sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
}
@@ -302,7 +304,7 @@ SM_STATE(AUTH_PAE, AUTHENTICATED)
eap_server_get_name(0, sm->eap_type_authsrv),
extra);
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
- sm->flags & EAPOL_SM_PREAUTH);
+ sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
}
@@ -830,6 +832,9 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
eap_conf.fragment_size = eapol->conf.fragment_size;
eap_conf.pwd_group = eapol->conf.pwd_group;
eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
+ eap_conf.server_id = eapol->conf.server_id;
+ eap_conf.server_id_len = eapol->conf.server_id_len;
+ eap_conf.erp = eapol->conf.erp;
sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
if (sm->eap == NULL) {
eapol_auth_free(sm);
@@ -848,6 +853,11 @@ 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;
+
return sm;
}
@@ -999,8 +1009,13 @@ static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
struct eap_user *user)
{
struct eapol_state_machine *sm = ctx;
- return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
- identity_len, phase2, user);
+ int ret;
+
+ ret = sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
+ identity_len, phase2, user);
+ if (user->remediation)
+ sm->remediation = 1;
+ return ret;
}
@@ -1012,10 +1027,44 @@ static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
}
+static int eapol_sm_get_erp_send_reauth_start(void *ctx)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->conf.erp_send_reauth_start;
+}
+
+
+static const char * eapol_sm_get_erp_domain(void *ctx)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->conf.erp_domain;
+}
+
+
+static struct eap_server_erp_key * eapol_sm_erp_get_key(void *ctx,
+ const char *keyname)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->cb.erp_get_key(sm->eapol->conf.ctx, keyname);
+}
+
+
+static int eapol_sm_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->cb.erp_add_key(sm->eapol->conf.ctx, erp);
+}
+
+
static struct eapol_callbacks eapol_cb =
{
eapol_sm_get_eap_user,
- eapol_sm_get_eap_req_id_text
+ eapol_sm_get_eap_req_id_text,
+ NULL,
+ eapol_sm_get_erp_send_reauth_start,
+ eapol_sm_get_erp_domain,
+ eapol_sm_erp_get_key,
+ eapol_sm_erp_add_key,
};
@@ -1045,6 +1094,8 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
os_free(dst->eap_req_id_text);
dst->pwd_group = src->pwd_group;
dst->pbc_in_m1 = src->pbc_in_m1;
+ dst->server_id = src->server_id;
+ dst->server_id_len = src->server_id_len;
if (src->eap_req_id_text) {
dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
if (dst->eap_req_id_text == NULL)
@@ -1058,16 +1109,16 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
}
if (src->pac_opaque_encr_key) {
dst->pac_opaque_encr_key = os_malloc(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);
- if (dst->eap_fast_a_id == NULL) {
- os_free(dst->eap_req_id_text);
- return -1;
- }
+ 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;
@@ -1075,11 +1126,8 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
dst->eap_fast_a_id = NULL;
if (src->eap_fast_a_id_info) {
dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
- if (dst->eap_fast_a_id_info == NULL) {
- os_free(dst->eap_req_id_text);
- os_free(dst->eap_fast_a_id);
- return -1;
- }
+ if (dst->eap_fast_a_id_info == NULL)
+ goto fail;
} else
dst->eap_fast_a_id_info = NULL;
dst->eap_fast_prov = src->eap_fast_prov;
@@ -1089,7 +1137,23 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
dst->tnc = src->tnc;
dst->wps = src->wps;
dst->fragment_size = src->fragment_size;
+
+ os_free(dst->erp_domain);
+ if (src->erp_domain) {
+ dst->erp_domain = os_strdup(src->erp_domain);
+ if (dst->erp_domain == NULL)
+ goto fail;
+ } else {
+ dst->erp_domain = NULL;
+ }
+ dst->erp_send_reauth_start = src->erp_send_reauth_start;
+ dst->erp = src->erp;
+
return 0;
+
+fail:
+ eapol_auth_conf_free(dst);
+ return -1;
}
@@ -1103,6 +1167,8 @@ static void eapol_auth_conf_free(struct eapol_auth_config *conf)
conf->eap_fast_a_id = NULL;
os_free(conf->eap_fast_a_id_info);
conf->eap_fast_a_id_info = NULL;
+ os_free(conf->erp_domain);
+ conf->erp_domain = NULL;
}
@@ -1110,6 +1176,7 @@ 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)
@@ -1135,6 +1202,14 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
eapol->cb.abort_auth = cb->abort_auth;
eapol->cb.tx_key = cb->tx_key;
eapol->cb.eapol_event = cb->eapol_event;
+ 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 b50bbdd..ebed19a 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
@@ -24,6 +24,9 @@ struct eapol_auth_config {
void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
+ int erp_send_reauth_start;
+ char *erp_domain; /* a copy of this will be allocated */
+ int erp; /* Whether ERP is enabled on authentication server */
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@@ -37,12 +40,15 @@ struct eapol_auth_config {
int fragment_size;
u16 pwd_group;
int pbc_in_m1;
+ const u8 *server_id;
+ size_t server_id_len;
/* Opaque context pointer to owner data for callback functions */
void *ctx;
};
struct eap_user;
+struct eap_server_erp_key;
typedef enum {
EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
@@ -58,7 +64,8 @@ struct eapol_auth_cb {
size_t datalen);
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
size_t datalen);
- void (*finished)(void *ctx, void *sta_ctx, int success, int preauth);
+ void (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
+ int remediation);
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
int (*sta_entry_alive)(void *ctx, const u8 *addr);
@@ -68,6 +75,9 @@ struct eapol_auth_cb {
void (*abort_auth)(void *ctx, void *sta_ctx);
void (*tx_key)(void *ctx, void *sta_ctx);
void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type);
+ struct eap_server_erp_key * (*erp_get_key)(void *ctx,
+ const char *keyname);
+ int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
};
@@ -81,8 +91,8 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
const char *identity, const char *radius_cui);
void eapol_auth_free(struct eapol_state_machine *sm);
void eapol_auth_step(struct eapol_state_machine *sm);
-void eapol_auth_dump_state(FILE *f, const char *prefix,
- struct eapol_state_machine *sm);
+int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf,
+ size_t buflen);
int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
#endif /* EAPOL_AUTH_SM_H */
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h b/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
index d7f893a..a29b49c 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
@@ -30,6 +30,9 @@ struct eapol_authenticator {
u8 *default_wep_key;
u8 default_wep_key_idx;
+
+ u32 acct_multi_session_id_hi;
+ u32 acct_multi_session_id_lo;
};
@@ -173,6 +176,11 @@ struct eapol_state_machine {
struct eapol_authenticator *eapol;
void *sta; /* station context pointer to use in callbacks */
+
+ int remediation;
+
+ u32 acct_multi_session_id_hi;
+ u32 acct_multi_session_id_lo;
};
#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 f90fb62..9cc234a 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_proxy.h"
#include "eapol_supp_sm.h"
#define STATE_MACHINE_DATA struct eapol_sm
@@ -127,6 +128,7 @@ struct eapol_sm {
struct wpabuf *eapReqData; /* for EAP */
Boolean altAccept; /* for EAP */
Boolean altReject; /* for EAP */
+ Boolean eapTriggerStart;
Boolean replay_counter_valid;
u8 last_replay_counter[16];
struct eapol_config conf;
@@ -136,6 +138,13 @@ struct eapol_sm {
Boolean cached_pmk;
Boolean unicast_key_received, broadcast_key_received;
+
+ Boolean force_authorized_update;
+
+#ifdef CONFIG_EAP_PROXY
+ Boolean use_eap_proxy;
+ struct eap_proxy_sm *eap_proxy;
+#endif /* CONFIG_EAP_PROXY */
};
@@ -205,7 +214,6 @@ SM_STATE(SUPP_PAE, LOGOFF)
SM_ENTRY(SUPP_PAE, LOGOFF);
eapol_sm_txLogoff(sm);
sm->logoffSent = TRUE;
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
}
@@ -215,8 +223,8 @@ SM_STATE(SUPP_PAE, DISCONNECTED)
SM_ENTRY(SUPP_PAE, DISCONNECTED);
sm->sPortMode = Auto;
sm->startCount = 0;
+ sm->eapTriggerStart = FALSE;
sm->logoffSent = FALSE;
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
sm->suppAbort = TRUE;
@@ -238,6 +246,11 @@ SM_STATE(SUPP_PAE, CONNECTING)
{
int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
SM_ENTRY(SUPP_PAE, CONNECTING);
+
+ if (sm->eapTriggerStart)
+ send_start = 1;
+ sm->eapTriggerStart = FALSE;
+
if (send_start) {
sm->startWhen = sm->startPeriod;
sm->startCount++;
@@ -249,12 +262,14 @@ SM_STATE(SUPP_PAE, CONNECTING)
* delay authentication. Use a short timeout to send the first
* EAPOL-Start if Authenticator does not start authentication.
*/
-#ifdef CONFIG_WPS
- /* Reduce latency on starting WPS negotiation. */
- sm->startWhen = 1;
-#else /* CONFIG_WPS */
- sm->startWhen = 3;
-#endif /* CONFIG_WPS */
+ if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
+ /* Reduce latency on starting WPS negotiation. */
+ wpa_printf(MSG_DEBUG,
+ "EAPOL: Using shorter startWhen for WPS");
+ sm->startWhen = 1;
+ } else {
+ sm->startWhen = 2;
+ }
}
eapol_enable_timer_tick(sm);
sm->eapolEap = FALSE;
@@ -281,7 +296,6 @@ SM_STATE(SUPP_PAE, HELD)
SM_ENTRY(SUPP_PAE, HELD);
sm->heldWhile = sm->heldPeriod;
eapol_enable_timer_tick(sm);
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
sm->cb_status = EAPOL_CB_FAILURE;
}
@@ -290,7 +304,6 @@ SM_STATE(SUPP_PAE, HELD)
SM_STATE(SUPP_PAE, AUTHENTICATED)
{
SM_ENTRY(SUPP_PAE, AUTHENTICATED);
- sm->suppPortStatus = Authorized;
eapol_sm_set_port_authorized(sm);
sm->cb_status = EAPOL_CB_SUCCESS;
}
@@ -306,7 +319,6 @@ SM_STATE(SUPP_PAE, RESTART)
SM_STATE(SUPP_PAE, S_FORCE_AUTH)
{
SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
- sm->suppPortStatus = Authorized;
eapol_sm_set_port_authorized(sm);
sm->sPortMode = ForceAuthorized;
}
@@ -315,7 +327,6 @@ SM_STATE(SUPP_PAE, S_FORCE_AUTH)
SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
{
SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
sm->sPortMode = ForceUnauthorized;
eapol_sm_txLogoff(sm);
@@ -382,6 +393,8 @@ SM_STEP(SUPP_PAE)
SM_ENTER(SUPP_PAE, HELD);
else if (sm->suppTimeout)
SM_ENTER(SUPP_PAE, CONNECTING);
+ else if (sm->eapTriggerStart)
+ SM_ENTER(SUPP_PAE, CONNECTING);
break;
case SUPP_PAE_HELD:
if (sm->heldWhile == 0)
@@ -463,6 +476,17 @@ SM_STATE(SUPP_BE, SUCCESS)
sm->keyRun = TRUE;
sm->suppSuccess = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ if (eap_proxy_key_available(sm->eap_proxy)) {
+ /* New key received - clear IEEE 802.1X EAPOL-Key replay
+ * counter */
+ sm->replay_counter_valid = FALSE;
+ }
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
+
if (eap_key_available(sm->eap)) {
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
@@ -706,8 +730,8 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
hmac_md5(keydata.sign_key, sign_key_len,
sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
key->key_signature);
- if (os_memcmp(orig_key_sign, key->key_signature,
- IEEE8021X_KEY_SIGN_LEN) != 0) {
+ if (os_memcmp_const(orig_key_sign, key->key_signature,
+ IEEE8021X_KEY_SIGN_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
"EAPOL-Key packet");
os_memcpy(key->key_signature, orig_key_sign,
@@ -806,6 +830,19 @@ static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
+
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Get EAP Response from EAP Proxy */
+ resp = eap_proxy_get_eapRespData(sm->eap_proxy);
+ if (resp == NULL) {
+ wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
+ "response data not available");
+ return;
+ }
+ } else
+#endif /* CONFIG_EAP_PROXY */
+
resp = eap_get_eapRespData(sm->eap);
if (resp == NULL) {
wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
@@ -850,14 +887,24 @@ static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
{
- if (sm->ctx->port_cb)
+ int cb;
+
+ cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
+ sm->force_authorized_update = FALSE;
+ sm->suppPortStatus = Authorized;
+ if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 1);
}
static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
{
- if (sm->ctx->port_cb)
+ int cb;
+
+ cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
+ sm->force_authorized_update = FALSE;
+ sm->suppPortStatus = Unauthorized;
+ if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 0);
}
@@ -883,6 +930,13 @@ void eapol_sm_step(struct eapol_sm *sm)
SM_STEP_RUN(SUPP_PAE);
SM_STEP_RUN(KEY_RX);
SM_STEP_RUN(SUPP_BE);
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Drive the EAP proxy state machine */
+ if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
+ sm->changed = TRUE;
+ } else
+#endif /* CONFIG_EAP_PROXY */
if (eap_peer_sm_step(sm->eap))
sm->changed = TRUE;
if (!sm->changed)
@@ -897,9 +951,15 @@ void eapol_sm_step(struct eapol_sm *sm)
}
if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
- int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
+ enum eapol_supp_result result;
+ if (sm->cb_status == EAPOL_CB_SUCCESS)
+ result = EAPOL_SUPP_RESULT_SUCCESS;
+ else if (eap_peer_was_failure_expected(sm->eap))
+ result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+ else
+ result = EAPOL_SUPP_RESULT_FAILURE;
sm->cb_status = EAPOL_CB_IN_PROGRESS;
- sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
+ sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
}
}
@@ -1048,7 +1108,7 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
"suppPortStatus=%s\n",
eapol_supp_pae_state(sm->SUPP_PAE_state),
eapol_port_status(sm->suppPortStatus));
- if (len < 0 || (size_t) len >= buflen)
+ if (os_snprintf_error(buflen, len))
return 0;
if (verbose) {
@@ -1065,11 +1125,18 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
sm->maxStart,
eapol_port_control(sm->portControl),
eapol_supp_be_state(sm->SUPP_BE_state));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy)
+ len += eap_proxy_sm_get_status(sm->eap_proxy,
+ buf + len, buflen - len,
+ verbose);
+ else
+#endif /* CONFIG_EAP_PROXY */
len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
return len;
@@ -1112,7 +1179,7 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
"Authorized" : "Unauthorized",
sm->SUPP_BE_state);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
@@ -1140,7 +1207,7 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
sm->dot1xSuppLastEapolFrameVersion,
MAC2STR(sm->dot1xSuppLastEapolFrameSource));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -1186,7 +1253,7 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
return 0;
}
#ifdef CONFIG_WPS
- if (sm->conf.workaround &&
+ if (sm->conf.wps && sm->conf.workaround &&
plen < len - sizeof(*hdr) &&
hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
@@ -1214,6 +1281,24 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
switch (hdr->type) {
case IEEE802_1X_TYPE_EAP_PACKET:
+ if (sm->conf.workaround) {
+ /*
+ * An AP has been reported to send out EAP message with
+ * undocumented code 10 at some point near the
+ * completion of EAP authentication. This can result in
+ * issues with the unexpected EAP message triggering
+ * restart of EAPOL authentication. Avoid this by
+ * skipping the message without advancing the state
+ * machine.
+ */
+ const struct eap_hdr *ehdr =
+ (const struct eap_hdr *) (hdr + 1);
+ if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
+ break;
+ }
+ }
+
if (sm->cached_pmk) {
/* Trying to use PMKSA caching, but Authenticator did
* not seem to have a matching entry. Need to restart
@@ -1227,6 +1312,16 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
"frame");
sm->eapolEap = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ eap_proxy_packet_update(
+ sm->eap_proxy,
+ wpabuf_mhead_u8(sm->eapReqData),
+ wpabuf_len(sm->eapReqData));
+ wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
+ "EAP Req updated");
+ }
+#endif /* CONFIG_EAP_PROXY */
eapol_sm_step(sm);
}
break;
@@ -1261,6 +1356,13 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
eapol_sm_step(sm);
}
break;
+#ifdef CONFIG_MACSEC
+ case IEEE802_1X_TYPE_EAPOL_MKA:
+ wpa_printf(MSG_EXCESSIVE,
+ "EAPOL type %d will be handled by MKA",
+ hdr->type);
+ break;
+#endif /* CONFIG_MACSEC */
default:
wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
hdr->type);
@@ -1299,6 +1401,8 @@ void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
return;
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
"portEnabled=%d", enabled);
+ if (sm->portEnabled != enabled)
+ sm->force_authorized_update = TRUE;
sm->portEnabled = enabled;
eapol_sm_step(sm);
}
@@ -1387,6 +1491,9 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
return;
sm->config = config;
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
+#endif /* CONFIG_EAP_PROXY */
if (conf == NULL)
return;
@@ -1395,10 +1502,18 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
sm->conf.workaround = conf->workaround;
+ sm->conf.wps = conf->wps;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Using EAP Proxy, so skip EAP state machine update */
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
eap_set_force_disabled(sm->eap, conf->eap_disabled);
+ eap_set_external_sim(sm->eap, conf->external_sim);
}
}
@@ -1419,6 +1534,22 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
const u8 *eap_key;
size_t eap_len;
+#ifdef CONFIG_EAP_PROXY
+ if (sm && sm->use_eap_proxy) {
+ /* Get key from EAP proxy */
+ if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
+ wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
+ return -1;
+ }
+ eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
+ if (eap_key == NULL) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
+ "eapKeyData");
+ return -1;
+ }
+ goto key_fetched;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm == NULL || !eap_key_available(sm->eap)) {
wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
return -1;
@@ -1428,6 +1559,9 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
return -1;
}
+#ifdef CONFIG_EAP_PROXY
+key_fetched:
+#endif /* CONFIG_EAP_PROXY */
if (len > eap_len) {
wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
"available (len=%lu)",
@@ -1442,6 +1576,24 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
/**
+ * eapol_sm_get_session_id - Get EAP Session-Id
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the session
+ * Returns: Pointer to the EAP Session-Id or %NULL on failure
+ *
+ * The Session-Id is available only after a successful authentication.
+ */
+const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
+{
+ if (sm == NULL || !eap_key_available(sm->eap)) {
+ wpa_printf(MSG_DEBUG, "EAPOL: EAP Session-Id not available");
+ return NULL;
+ }
+ return eap_get_eapSessionId(sm->eap, len);
+}
+
+
+/**
* eapol_sm_notify_logoff - Notification of logon/logoff commands
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @logoff: Whether command was logoff
@@ -1452,6 +1604,10 @@ void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
{
if (sm) {
sm->userLogoff = logoff;
+ if (!logoff) {
+ /* If there is a delayed txStart queued, start now. */
+ sm->startWhen = 0;
+ }
eapol_sm_step(sm);
}
}
@@ -1478,21 +1634,15 @@ void eapol_sm_notify_cached(struct eapol_sm *sm)
/**
* eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @attempt: Whether PMKSA caching is tried
*
- * Notify EAPOL state machines whether PMKSA caching is used.
+ * Notify EAPOL state machines if PMKSA caching is used.
*/
-void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
{
if (sm == NULL)
return;
- if (attempt) {
- wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
- sm->cached_pmk = TRUE;
- } else {
- wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
- sm->cached_pmk = FALSE;
- }
+ wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
+ sm->cached_pmk = TRUE;
}
@@ -1504,7 +1654,6 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm)
return;
sm->cached_pmk = FALSE;
sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
/* Make sure we do not start sending EAPOL-Start frames first, but
@@ -1676,6 +1825,8 @@ static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
return sm->altAccept;
case EAPOL_altReject:
return sm->altReject;
+ case EAPOL_eapTriggerStart:
+ return sm->eapTriggerStart;
}
return FALSE;
}
@@ -1715,6 +1866,9 @@ static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
case EAPOL_altReject:
sm->altReject = value;
break;
+ case EAPOL_eapTriggerStart:
+ sm->eapTriggerStart = value;
+ break;
}
}
@@ -1802,13 +1956,14 @@ static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
- const char *cert_hash,
+ const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert)
{
struct eapol_sm *sm = ctx;
if (sm->ctx->cert_cb)
- sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
- cert_hash, cert);
+ sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
@@ -1822,6 +1977,17 @@ static void eapol_sm_notify_status(void *ctx, const char *status,
}
+#ifdef CONFIG_EAP_PROXY
+static void eapol_sm_eap_proxy_cb(void *ctx)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->eap_proxy_cb)
+ sm->ctx->eap_proxy_cb(sm->ctx->ctx);
+}
+#endif /* CONFIG_EAP_PROXY */
+
+
static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct eapol_sm *sm = ctx;
@@ -1845,6 +2011,9 @@ static struct eapol_callbacks eapol_cb =
eapol_sm_eap_param_needed,
eapol_sm_notify_cert,
eapol_sm_notify_status,
+#ifdef CONFIG_EAP_PROXY
+ eapol_sm_eap_proxy_cb,
+#endif /* CONFIG_EAP_PROXY */
eapol_sm_set_anon_id
};
@@ -1880,6 +2049,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
conf.opensc_engine_path = ctx->opensc_engine_path;
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
+ conf.openssl_ciphers = ctx->openssl_ciphers;
conf.wps = ctx->wps;
conf.cert_in_cb = ctx->cert_in_cb;
@@ -1889,7 +2059,16 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
return NULL;
}
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = FALSE;
+ sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
+ if (sm->eap_proxy == NULL) {
+ wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
+ }
+#endif /* CONFIG_EAP_PROXY */
+
/* Initialize EAPOL state machines */
+ sm->force_authorized_update = TRUE;
sm->initialize = TRUE;
eapol_sm_step(sm);
sm->initialize = FALSE;
@@ -1915,6 +2094,9 @@ void eapol_sm_deinit(struct eapol_sm *sm)
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
eap_peer_sm_deinit(sm->eap);
+#ifdef CONFIG_EAP_PROXY
+ eap_proxy_deinit(sm->eap_proxy);
+#endif /* CONFIG_EAP_PROXY */
os_free(sm->last_rx_key);
wpabuf_free(sm->eapReqData);
os_free(sm->ctx);
@@ -1936,3 +2118,22 @@ int eapol_sm_failed(struct eapol_sm *sm)
return 0;
return !sm->eapSuccess && sm->eapFail;
}
+
+
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
+{
+#ifdef CONFIG_EAP_PROXY
+ if (sm->eap_proxy == NULL)
+ return -1;
+ return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
+#else /* CONFIG_EAP_PROXY */
+ return -1;
+#endif /* CONFIG_EAP_PROXY */
+}
+
+
+void eapol_sm_erp_flush(struct eapol_sm *sm)
+{
+ if (sm)
+ eap_peer_erp_free_keys(sm->eap);
+}
diff --git a/contrib/wpa/src/eapol_supp/eapol_supp_sm.h b/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
index c4b87da..1309ff7 100644
--- a/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
+++ b/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
@@ -53,11 +53,29 @@ struct eapol_config {
* eap_disabled - Whether EAP is disabled
*/
int eap_disabled;
+
+ /**
+ * external_sim - Use external processing for SIM/USIM operations
+ */
+ int external_sim;
+
+#define EAPOL_LOCAL_WPS_IN_USE BIT(0)
+#define EAPOL_PEER_IS_WPS20_AP BIT(1)
+ /**
+ * wps - Whether this connection is used for WPS
+ */
+ int wps;
};
struct eapol_sm;
struct wpa_config_blob;
+enum eapol_supp_result {
+ EAPOL_SUPP_RESULT_FAILURE,
+ EAPOL_SUPP_RESULT_SUCCESS,
+ EAPOL_SUPP_RESULT_EXPECTED_FAILURE
+};
+
/**
* struct eapol_ctx - Global (for all networks) EAPOL state machine context
*/
@@ -78,7 +96,7 @@ struct eapol_ctx {
/**
* cb - Function to be called when EAPOL negotiation has been completed
* @eapol: Pointer to EAPOL state machine data
- * @success: Whether the authentication was completed successfully
+ * @result: Whether the authentication was completed successfully
* @ctx: Pointer to context data (cb_ctx)
*
* This optional callback function will be called when the EAPOL
@@ -86,7 +104,8 @@ struct eapol_ctx {
* EAPOL state machine to process the key and terminate the EAPOL state
* machine. Currently, this is used only in RSN pre-authentication.
*/
- void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
+ void (*cb)(struct eapol_sm *eapol, enum eapol_supp_result result,
+ void *ctx);
/**
* cb_ctx - Callback context for cb()
@@ -193,6 +212,15 @@ struct eapol_ctx {
const char *pkcs11_module_path;
/**
+ * openssl_ciphers - 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.
+ */
+ const char *openssl_ciphers;
+
+ /**
* wps - WPS context data
*
* This is only used by EAP-WSC and can be left %NULL if not available.
@@ -220,10 +248,13 @@ struct eapol_ctx {
* @ctx: Callback context (ctx)
* @depth: Depth in certificate chain (0 = server)
* @subject: Subject of the peer certificate
+ * @altsubject: Select fields from AltSubject of the peer certificate
+ * @num_altsubject: Number of altsubject values
* @cert_hash: SHA-256 hash of the certificate
* @cert: Peer certificate
*/
void (*cert_cb)(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash, const struct wpabuf *cert);
/**
@@ -240,6 +271,14 @@ struct eapol_ctx {
void (*status_cb)(void *ctx, const char *status,
const char *parameter);
+#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);
+#endif /* CONFIG_EAP_PROXY */
+
/**
* set_anon_id - Set or add anonymous identity
* @ctx: eapol_ctx from eap_peer_sm_init() call
@@ -273,9 +312,10 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
struct eap_peer_config *config,
const struct eapol_config *conf);
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
+const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len);
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
void eapol_sm_notify_cached(struct eapol_sm *sm);
-void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt);
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm);
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl);
void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm);
@@ -287,6 +327,8 @@ const char * eapol_sm_get_method_name(struct eapol_sm *sm);
void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
struct ext_password_data *ext);
int eapol_sm_failed(struct eapol_sm *sm);
+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);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
@@ -346,13 +388,20 @@ static inline int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
{
return -1;
}
+static inline const u8 *
+eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
+{
+ return NULL;
+}
static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
{
}
static inline void eapol_sm_notify_cached(struct eapol_sm *sm)
{
}
-#define eapol_sm_notify_pmkid_attempt(sm, attempt) do { } while (0)
+static inline void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
+{
+}
#define eapol_sm_register_scard_ctx(sm, ctx) do { } while (0)
static inline void eapol_sm_notify_portControl(struct eapol_sm *sm,
PortControl portControl)
@@ -386,6 +435,9 @@ static inline int eapol_sm_failed(struct eapol_sm *sm)
{
return 0;
}
+static inline void eapol_sm_erp_flush(struct eapol_sm *sm)
+{
+}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SUPP_SM_H */
diff --git a/contrib/wpa/src/l2_packet/l2_packet.h b/contrib/wpa/src/l2_packet/l2_packet.h
index dd825b5..2a45245 100644
--- a/contrib/wpa/src/l2_packet/l2_packet.h
+++ b/contrib/wpa/src/l2_packet/l2_packet.h
@@ -39,6 +39,11 @@ struct l2_ethhdr {
#pragma pack(pop)
#endif /* _MSC_VER */
+enum l2_packet_filter_type {
+ L2_PACKET_FILTER_DHCP,
+ L2_PACKET_FILTER_NDISC,
+};
+
/**
* l2_packet_init - Initialize l2_packet interface
* @ifname: Interface name
@@ -63,6 +68,19 @@ struct l2_packet_data * l2_packet_init(
void *rx_callback_ctx, int l2_hdr);
/**
+ * l2_packet_init_bridge - Like l2_packet_init() but with bridge workaround
+ *
+ * This version of l2_packet_init() can be used to enable a workaround for Linux
+ * packet socket in case of a station interface in a bridge.
+ */
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr);
+
+/**
* l2_packet_deinit - Deinitialize l2_packet interface
* @l2: Pointer to internal l2_packet data from l2_packet_init()
*/
@@ -121,4 +139,16 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len);
*/
void l2_packet_notify_auth_start(struct l2_packet_data *l2);
+/**
+ * l2_packet_set_packet_filter - Set socket filter for l2_packet
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @type: enum l2_packet_filter_type, type of filter
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to set the socket filter for l2_packet socket.
+ *
+ */
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type);
+
#endif /* L2_PACKET_H */
diff --git a/contrib/wpa/src/l2_packet/l2_packet_freebsd.c b/contrib/wpa/src/l2_packet/l2_packet_freebsd.c
index 2e9a04c..aa83648 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_freebsd.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_freebsd.c
@@ -256,6 +256,18 @@ struct l2_packet_data * l2_packet_init(
}
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ rx_callback_ctx, l2_hdr);
+}
+
+
void l2_packet_deinit(struct l2_packet_data *l2)
{
if (l2 != NULL) {
@@ -308,3 +320,10 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
{
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/l2_packet/l2_packet_ndis.c b/contrib/wpa/src/l2_packet/l2_packet_ndis.c
index 23b8ddc..7167781 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_ndis.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_ndis.c
@@ -450,6 +450,18 @@ struct l2_packet_data * l2_packet_init(
}
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ rx_callback_ctx, l2_hdr);
+}
+
+
void l2_packet_deinit(struct l2_packet_data *l2)
{
if (l2 == NULL)
@@ -514,3 +526,10 @@ int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
{
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/l2_packet/l2_packet_none.c b/contrib/wpa/src/l2_packet/l2_packet_none.c
index b01e830..307fc6d 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_none.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_none.c
@@ -84,12 +84,25 @@ struct l2_packet_data * l2_packet_init(
* TODO: open connection for receiving frames
*/
l2->fd = -1;
- eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+ if (l2->fd >= 0)
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
return l2;
}
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ rx_callback_ctx, l2_hdr);
+}
+
+
void l2_packet_deinit(struct l2_packet_data *l2)
{
if (l2 == NULL)
@@ -115,3 +128,10 @@ void l2_packet_notify_auth_start(struct l2_packet_data *l2)
{
/* This function can be left empty */
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/l2_packet/l2_packet_privsep.c b/contrib/wpa/src/l2_packet/l2_packet_privsep.c
index 6b117ca..e26ca20 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_privsep.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_privsep.c
@@ -44,7 +44,7 @@ static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
msg.msg_namelen = sizeof(l2->priv_addr);
if (sendmsg(l2->fd, &msg, 0) < 0) {
- perror("L2: sendmsg(cmd)");
+ wpa_printf(MSG_ERROR, "L2: sendmsg(cmd): %s", strerror(errno));
return -1;
}
@@ -82,7 +82,8 @@ int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
msg.msg_namelen = sizeof(l2->priv_addr);
if (sendmsg(l2->fd, &msg, 0) < 0) {
- perror("L2: sendmsg(packet_send)");
+ wpa_printf(MSG_ERROR, "L2: sendmsg(packet_send): %s",
+ strerror(errno));
return -1;
}
@@ -102,7 +103,8 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
&fromlen);
if (res < 0) {
- perror("l2_packet_receive - recvfrom");
+ wpa_printf(MSG_ERROR, "l2_packet_receive - recvfrom: %s",
+ strerror(errno));
return;
}
if (res < ETH_ALEN) {
@@ -162,7 +164,7 @@ struct l2_packet_data * l2_packet_init(
l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if (l2->fd < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(l2->own_socket_path);
l2->own_socket_path = NULL;
os_free(l2);
@@ -173,7 +175,8 @@ struct l2_packet_data * l2_packet_init(
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("l2-pkt-privsep: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "l2-pkt-privsep: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
@@ -191,14 +194,14 @@ struct l2_packet_data * l2_packet_init(
tv.tv_usec = 0;
res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno != EINTR) {
- perror("select");
+ wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
goto fail;
}
if (FD_ISSET(l2->fd, &rfds)) {
res = recv(l2->fd, reply, sizeof(reply), 0);
if (res < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
goto fail;
}
} else {
@@ -228,6 +231,18 @@ fail:
}
+struct l2_packet_data * l2_packet_init_bridge(
+ const char *br_ifname, const char *ifname, const u8 *own_addr,
+ unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ rx_callback_ctx, l2_hdr);
+}
+
+
void l2_packet_deinit(struct l2_packet_data *l2)
{
if (l2 == NULL)
@@ -259,3 +274,10 @@ void l2_packet_notify_auth_start(struct l2_packet_data *l2)
{
wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/p2p/p2p.c b/contrib/wpa/src/p2p/p2p.c
index b994a44..6adb3dc 100644
--- a/contrib/wpa/src/p2p/p2p.c
+++ b/contrib/wpa/src/p2p/p2p.c
@@ -13,6 +13,8 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -42,21 +44,32 @@ static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx);
* P2P_PEER_EXPIRATION_AGE - Number of seconds after which inactive peer
* entries will be removed
*/
-#define P2P_PEER_EXPIRATION_AGE 300
+#ifndef P2P_PEER_EXPIRATION_AGE
+#define P2P_PEER_EXPIRATION_AGE 60
+#endif /* P2P_PEER_EXPIRATION_AGE */
#define P2P_PEER_EXPIRATION_INTERVAL (P2P_PEER_EXPIRATION_AGE / 2)
static void p2p_expire_peers(struct p2p_data *p2p)
{
struct p2p_device *dev, *n;
- struct os_time now;
+ struct os_reltime now;
size_t i;
- os_get_time(&now);
+ os_get_reltime(&now);
dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec)
continue;
+ if (dev == p2p->go_neg_peer) {
+ /*
+ * GO Negotiation is in progress with the peer, so
+ * don't expire the peer entry until GO Negotiation
+ * fails or times out.
+ */
+ continue;
+ }
+
if (p2p->cfg->go_connected &&
p2p->cfg->go_connected(p2p->cfg->cb_ctx,
dev->info.p2p_device_addr)) {
@@ -64,7 +77,7 @@ static void p2p_expire_peers(struct p2p_data *p2p)
* We are connected as a client to a group in which the
* peer is the GO, so do not expire the peer entry.
*/
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
continue;
}
@@ -78,12 +91,12 @@ static void p2p_expire_peers(struct p2p_data *p2p)
* The peer is connected as a client in a group where
* we are the GO, so do not expire the peer entry.
*/
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
continue;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Expiring old peer "
- "entry " MACSTR, MAC2STR(dev->info.p2p_device_addr));
+ p2p_dbg(p2p, "Expiring old peer entry " MACSTR,
+ MAC2STR(dev->info.p2p_device_addr));
dl_list_del(&dev->list);
p2p_device_free(p2p, dev);
}
@@ -128,16 +141,31 @@ static const char * p2p_state_txt(int state)
return "INVITE";
case P2P_INVITE_LISTEN:
return "INVITE_LISTEN";
- case P2P_SEARCH_WHEN_READY:
- return "SEARCH_WHEN_READY";
- case P2P_CONTINUE_SEARCH_WHEN_READY:
- return "CONTINUE_SEARCH_WHEN_READY";
default:
return "?";
}
}
+const char * p2p_get_state_txt(struct p2p_data *p2p)
+{
+ return p2p_state_txt(p2p->state);
+}
+
+
+struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p)
+{
+ return p2p ? p2p->p2ps_adv_list : NULL;
+}
+
+
+void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr)
+{
+ if (p2p && intended_addr)
+ os_memcpy(p2p->intended_addr, intended_addr, ETH_ALEN);
+}
+
+
u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
{
struct p2p_device *dev = NULL;
@@ -168,16 +196,23 @@ void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr)
void p2p_set_state(struct p2p_data *p2p, int new_state)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
+ p2p_dbg(p2p, "State %s -> %s",
p2p_state_txt(p2p->state), p2p_state_txt(new_state));
p2p->state = new_state;
+
+ if (new_state == P2P_IDLE && p2p->pending_channel) {
+ p2p_dbg(p2p, "Apply change in listen channel");
+ p2p->cfg->reg_class = p2p->pending_reg_class;
+ p2p->cfg->channel = p2p->pending_channel;
+ p2p->pending_reg_class = 0;
+ p2p->pending_channel = 0;
+ }
}
void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Set timeout (state=%s): %u.%06u sec",
+ p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec",
p2p_state_txt(p2p->state), sec, usec);
eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
@@ -186,30 +221,40 @@ void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
void p2p_clear_timeout(struct p2p_data *p2p)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear timeout (state=%s)",
- p2p_state_txt(p2p->state));
+ p2p_dbg(p2p, "Clear timeout (state=%s)", p2p_state_txt(p2p->state));
eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
}
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status)
+void p2p_go_neg_failed(struct p2p_data *p2p, int status)
{
struct p2p_go_neg_results res;
- p2p_clear_timeout(p2p);
- p2p_set_state(p2p, P2P_IDLE);
- if (p2p->go_neg_peer)
- p2p->go_neg_peer->wps_method = WPS_NOT_READY;
+ struct p2p_device *peer = p2p->go_neg_peer;
+
+ if (!peer)
+ return;
+
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+ if (p2p->state != P2P_SEARCH) {
+ /*
+ * Clear timeouts related to GO Negotiation if no new p2p_find
+ * has been started.
+ */
+ p2p_clear_timeout(p2p);
+ p2p_set_state(p2p, P2P_IDLE);
+ }
+
+ peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
+ peer->wps_method = WPS_NOT_READY;
+ peer->oob_pw_id = 0;
+ wpabuf_free(peer->go_neg_conf);
+ peer->go_neg_conf = NULL;
p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res));
res.status = status;
- if (peer) {
- os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
- ETH_ALEN);
- os_memcpy(res.peer_interface_addr, peer->intended_addr,
- ETH_ALEN);
- }
+ os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
+ os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
}
@@ -220,19 +265,23 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
int freq;
struct wpabuf *ies;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Starting short listen state (state=%s)",
+ p2p_dbg(p2p, "Starting short listen state (state=%s)",
p2p_state_txt(p2p->state));
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
- p2p->cfg->channel);
+ if (p2p->pending_listen_freq) {
+ /* We have a pending p2p_listen request */
+ p2p_dbg(p2p, "p2p_listen command pending already");
+ return;
+ }
+
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
return;
}
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
p2p->min_disc_int) * 100;
if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
@@ -243,24 +292,22 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
tu = p2p->cfg->max_listen * 1000 / 1024;
if (tu == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip listen state "
- "since duration was 0 TU");
+ p2p_dbg(p2p, "Skip listen state since duration was 0 TU");
p2p_set_timeout(p2p, 0, 0);
return;
}
- p2p->pending_listen_freq = freq;
- p2p->pending_listen_sec = 0;
- p2p->pending_listen_usec = 1024 * tu;
-
ies = p2p_build_probe_resp_ies(p2p);
if (ies == NULL)
return;
+ p2p->pending_listen_freq = freq;
+ p2p->pending_listen_sec = 0;
+ p2p->pending_listen_usec = 1024 * tu;
+
if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000,
ies) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to start listen mode");
+ p2p_dbg(p2p, "Failed to start listen mode");
p2p->pending_listen_freq = 0;
}
wpabuf_free(ies);
@@ -272,30 +319,29 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
int freq;
struct wpabuf *ies;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Going to listen(only) state");
+ p2p_dbg(p2p, "Going to listen(only) state");
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
- p2p->cfg->channel);
+ if (p2p->pending_listen_freq) {
+ /* We have a pending p2p_listen request */
+ p2p_dbg(p2p, "p2p_listen command pending already");
+ return -1;
+ }
+
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
return -1;
}
- p2p->pending_listen_freq = freq;
p2p->pending_listen_sec = timeout / 1000;
p2p->pending_listen_usec = (timeout % 1000) * 1000;
if (p2p->p2p_scan_running) {
if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: p2p_scan running - connect is already "
- "pending - skip listen");
+ p2p_dbg(p2p, "p2p_scan running - connect is already pending - skip listen");
return 0;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: p2p_scan running - delay start of listen state");
+ p2p_dbg(p2p, "p2p_scan running - delay start of listen state");
p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
return 0;
}
@@ -304,9 +350,10 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
if (ies == NULL)
return -1;
+ p2p->pending_listen_freq = freq;
+
if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, timeout, ies) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to start listen mode");
+ p2p_dbg(p2p, "Failed to start listen mode");
p2p->pending_listen_freq = 0;
wpabuf_free(ies);
return -1;
@@ -322,8 +369,10 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
static void p2p_device_clear_reported(struct p2p_data *p2p)
{
struct p2p_device *dev;
- dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
dev->flags &= ~P2P_DEV_REPORTED;
+ dev->sd_reqs = 0;
+ }
}
@@ -384,13 +433,11 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
count++;
if (oldest == NULL ||
- os_time_before(&dev->last_seen, &oldest->last_seen))
+ os_reltime_before(&dev->last_seen, &oldest->last_seen))
oldest = dev;
}
if (count + 1 > p2p->cfg->max_peers && oldest) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Remove oldest peer entry to make room for a new "
- "peer");
+ p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer");
dl_list_del(&oldest->list);
p2p_device_free(p2p, oldest);
}
@@ -489,7 +536,7 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
os_memcpy(dev->interface_addr, cli->p2p_interface_addr,
ETH_ALEN);
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN);
os_memcpy(dev->member_in_go_iface, go_interface_addr,
ETH_ALEN);
@@ -499,8 +546,8 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
}
-static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
- const struct p2p_message *msg)
+static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev,
+ int probe_req, const struct p2p_message *msg)
{
os_memcpy(dev->info.device_name, msg->device_name,
sizeof(dev->info.device_name));
@@ -570,9 +617,77 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
}
if (!probe_req) {
- dev->info.config_methods = msg->config_methods ?
+ u16 new_config_methods;
+ new_config_methods = msg->config_methods ?
msg->config_methods : msg->wps_config_methods;
+ if (new_config_methods &&
+ dev->info.config_methods != new_config_methods) {
+ p2p_dbg(p2p, "Update peer " MACSTR
+ " config_methods 0x%x -> 0x%x",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->info.config_methods,
+ new_config_methods);
+ dev->info.config_methods = new_config_methods;
+ }
+ }
+}
+
+
+static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
+ size_t ies_len)
+{
+ const u8 *pos, *end;
+ u8 id, len;
+
+ wpabuf_free(dev->info.vendor_elems);
+ dev->info.vendor_elems = NULL;
+
+ end = ies + ies_len;
+
+ for (pos = ies; pos + 1 < end; pos += len) {
+ id = *pos++;
+ len = *pos++;
+
+ if (pos + len > end)
+ break;
+
+ if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
+ continue;
+
+ if (len >= 4) {
+ u32 type = WPA_GET_BE32(pos);
+
+ if (type == WPA_IE_VENDOR_TYPE ||
+ type == WMM_IE_VENDOR_TYPE ||
+ type == WPS_IE_VENDOR_TYPE ||
+ type == P2P_IE_VENDOR_TYPE ||
+ type == WFD_IE_VENDOR_TYPE)
+ continue;
+ }
+
+ /* Unknown vendor element - make raw IE data available */
+ if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0)
+ break;
+ wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len);
+ }
+}
+
+
+static int p2p_compare_wfd_info(struct p2p_device *dev,
+ const struct p2p_message *msg)
+{
+ if (dev->info.wfd_subelems && msg->wfd_subelems) {
+ if (dev->info.wfd_subelems->used != msg->wfd_subelems->used)
+ return 1;
+
+ return os_memcmp(dev->info.wfd_subelems->buf,
+ msg->wfd_subelems->buf,
+ dev->info.wfd_subelems->used);
}
+ if (dev->info.wfd_subelems || msg->wfd_subelems)
+ return 1;
+
+ return 0;
}
@@ -583,7 +698,7 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
* P2P Device Address or P2P Interface Address)
* @level: Signal level (signal strength of the received frame from the peer)
* @freq: Frequency on which the Beacon or Probe Response frame was received
- * @age_ms: Age of the information in milliseconds
+ * @rx_time: Time when the result was received
* @ies: IEs from the Beacon or Probe Response frame
* @ies_len: Length of ies buffer in octets
* @scan_res: Whether this was based on scan results
@@ -595,19 +710,19 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
* Info attributes.
*/
int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
- unsigned int age_ms, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len, int scan_res)
{
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
+ int wfd_changed;
int i;
- struct os_time time_now, time_tmp_age, entry_ts;
+ struct os_reltime time_now;
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ies, ies_len, &msg)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to parse P2P IE for a device entry");
+ p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
p2p_parse_free(&msg);
return -1;
}
@@ -617,18 +732,15 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
else if (msg.device_id)
p2p_dev_addr = msg.device_id;
else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore scan data without P2P Device Info or "
- "P2P Device Id");
+ p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
p2p_parse_free(&msg);
return -1;
}
if (!is_zero_ether_addr(p2p->peer_filter) &&
os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer "
- "filter for " MACSTR " due to peer filter",
- MAC2STR(p2p_dev_addr));
+ p2p_dbg(p2p, "Do not add peer filter for " MACSTR
+ " due to peer filter", MAC2STR(p2p_dev_addr));
p2p_parse_free(&msg);
return 0;
}
@@ -639,22 +751,27 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
return -1;
}
- os_get_time(&time_now);
- time_tmp_age.sec = age_ms / 1000;
- time_tmp_age.usec = (age_ms % 1000) * 1000;
- os_time_sub(&time_now, &time_tmp_age, &entry_ts);
+ if (rx_time == NULL) {
+ os_get_reltime(&time_now);
+ rx_time = &time_now;
+ }
/*
* Update the device entry only if the new peer
* entry is newer than the one previously stored.
*/
- if (dev->last_seen.usec > 0 &&
- os_time_before(&entry_ts, &dev->last_seen)) {
+ if (dev->last_seen.sec > 0 &&
+ os_reltime_before(rx_time, &dev->last_seen)) {
+ p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)",
+ (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec,
+ (unsigned int) dev->last_seen.sec,
+ (unsigned int) dev->last_seen.usec);
p2p_parse_free(&msg);
return -1;
}
- os_memcpy(&dev->last_seen, &entry_ts, sizeof(struct os_time));
+ os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
@@ -668,6 +785,12 @@ 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);
+ 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) {
int ds_freq;
@@ -676,18 +799,15 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
else
ds_freq = 2407 + *msg.ds_params * 5;
if (freq != ds_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Update Listen frequency based on DS "
- "Parameter Set IE: %d -> %d MHz",
+ p2p_dbg(p2p, "Update Listen frequency based on DS Parameter Set IE: %d -> %d MHz",
freq, ds_freq);
freq = ds_freq;
}
}
if (dev->listen_freq && dev->listen_freq != freq && scan_res) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Update Listen frequency based on scan "
- "results (" MACSTR " %d -> %d MHz (DS param %d)",
+ p2p_dbg(p2p, "Update Listen frequency based on scan results ("
+ MACSTR " %d -> %d MHz (DS param %d)",
MAC2STR(dev->info.p2p_device_addr), dev->listen_freq,
freq, msg.ds_params ? *msg.ds_params : -1);
}
@@ -698,7 +818,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
}
dev->info.level = level;
- p2p_copy_wps_info(dev, 0, &msg);
+ p2p_copy_wps_info(p2p, dev, 0, &msg);
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
wpabuf_free(dev->info.wps_vendor_ext[i]);
@@ -714,6 +834,8 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
break;
}
+ wfd_changed = p2p_compare_wfd_info(dev, &msg);
+
if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
@@ -726,17 +848,39 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
p2p_parse_free(&msg);
- if (p2p_pending_sd_req(p2p, dev))
- dev->flags |= P2P_DEV_SD_SCHEDULE;
+ p2p_update_peer_vendor_elems(dev, ies, ies_len);
- if (dev->flags & P2P_DEV_REPORTED)
+ if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+ (!msg.adv_service_instance ||
+ (dev->flags & P2P_DEV_P2PS_REPORTED)))
return 0;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer found with Listen frequency %d MHz", freq);
+ p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
+ freq, (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
if (dev->flags & P2P_DEV_USER_REJECTED) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Do not report rejected device");
+ p2p_dbg(p2p, "Do not report rejected device");
+ return 0;
+ }
+
+ if (dev->info.config_methods == 0 &&
+ (freq == 2412 || freq == 2437 || freq == 2462)) {
+ /*
+ * If we have only seen a Beacon frame from a GO, we do not yet
+ * know what WPS config methods it supports. Since some
+ * applications use config_methods value from P2P-DEVICE-FOUND
+ * events, postpone reporting this peer until we've fully
+ * discovered its capabilities.
+ *
+ * At least for now, do this only if the peer was detected on
+ * one of the social channels since that peer can be easily be
+ * found again and there are no limitations of having to use
+ * passive scan on this channels, so this can be done through
+ * Probe Response frame that includes the config_methods
+ * information.
+ */
+ p2p_dbg(p2p, "Do not report peer " MACSTR
+ " with unknown config methods", MAC2STR(addr));
return 0;
}
@@ -744,6 +888,9 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
!(dev->flags & P2P_DEV_REPORTED_ONCE));
dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+ if (msg.adv_service_instance)
+ dev->flags |= P2P_DEV_P2PS_REPORTED;
+
return 0;
}
@@ -756,8 +903,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
/*
* If GO Negotiation is in progress, report that it has failed.
*/
- p2p_go_neg_failed(p2p, dev, -1);
- p2p->go_neg_peer = NULL;
+ p2p_go_neg_failed(p2p, -1);
}
if (p2p->invite_peer == dev)
p2p->invite_peer = NULL;
@@ -777,6 +923,9 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
}
wpabuf_free(dev->info.wfd_subelems);
+ wpabuf_free(dev->info.vendor_elems);
+ wpabuf_free(dev->go_neg_conf);
+ wpabuf_free(dev->info.p2ps_instance);
os_free(dev);
}
@@ -824,9 +973,8 @@ static int p2p_get_next_prog_freq(struct p2p_data *p2p)
channel = c->reg_class[cl].channel[ch];
}
- freq = p2p_channel_to_freq(p2p->cfg->country, reg_class, channel);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Next progressive search "
- "channel: reg_class %u channel %u -> %d MHz",
+ freq = p2p_channel_to_freq(reg_class, channel);
+ p2p_dbg(p2p, "Next progressive search channel: reg_class %u channel %u -> %d MHz",
reg_class, channel, freq);
p2p->last_prog_scan_class = reg_class;
p2p->last_prog_scan_chan = channel;
@@ -845,9 +993,7 @@ static void p2p_search(struct p2p_data *p2p)
int res;
if (p2p->drv_in_listen) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
- "in Listen state - wait for it to end before "
- "continuing");
+ p2p_dbg(p2p, "Driver is still in Listen state - wait for it to end before continuing");
return;
}
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -855,31 +1001,18 @@ static void p2p_search(struct p2p_data *p2p)
if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
(freq = p2p_get_next_prog_freq(p2p)) > 0) {
type = P2P_SCAN_SOCIAL_PLUS_ONE;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
- "(+ freq %u)", freq);
+ p2p_dbg(p2p, "Starting search (+ freq %u)", freq);
} else {
type = P2P_SCAN_SOCIAL;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search");
+ p2p_dbg(p2p, "Starting search");
}
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
p2p->num_req_dev_types, p2p->req_dev_types,
p2p->find_dev_id, pw_id);
if (res < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Scan request failed");
+ p2p_dbg(p2p, "Scan request schedule failed");
p2p_continue_find(p2p);
- } else if (res == 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
- "p2p_scan at this point - will try again after "
- "previous scan completes");
- p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY);
- } else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
}
}
@@ -887,21 +1020,35 @@ static void p2p_search(struct p2p_data *p2p)
static void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct p2p_data *p2p = eloop_ctx;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Find timeout -> stop");
+ p2p_dbg(p2p, "Find timeout -> stop");
p2p_stop_find(p2p);
}
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status)
+{
+ if (status != 0) {
+ p2p_dbg(p2p, "Scan request failed");
+ /* Do continue find even for the first p2p_find_scan */
+ p2p_continue_find(p2p);
+ } else {
+ p2p_dbg(p2p, "Running p2p_scan");
+ p2p->p2p_scan_running = 1;
+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+ eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
+ p2p, NULL);
+ }
+}
+
+
static int p2p_run_after_scan(struct p2p_data *p2p)
{
struct p2p_device *dev;
enum p2p_after_scan op;
if (p2p->after_scan_tx) {
- /* TODO: schedule p2p_run_after_scan to be called from TX
- * status callback(?) */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
- "Action frame at p2p_scan completion");
+ p2p->after_scan_tx_in_progress = 1;
+ p2p_dbg(p2p, "Send pending Action frame at p2p_scan completion");
p2p->cfg->send_action(p2p->cfg->cb_ctx,
p2p->after_scan_tx->freq,
p2p->after_scan_tx->dst,
@@ -921,19 +1068,16 @@ static int p2p_run_after_scan(struct p2p_data *p2p)
case P2P_AFTER_SCAN_NOTHING:
break;
case P2P_AFTER_SCAN_LISTEN:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
- "requested Listen state");
+ p2p_dbg(p2p, "Start previously requested Listen state");
p2p_listen(p2p, p2p->pending_listen_sec * 1000 +
p2p->pending_listen_usec / 1000);
return 1;
case P2P_AFTER_SCAN_CONNECT:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously "
- "requested connect with " MACSTR,
+ p2p_dbg(p2p, "Start previously requested connect with " MACSTR,
MAC2STR(p2p->after_scan_peer));
dev = p2p_get_device(p2p, p2p->after_scan_peer);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer not "
- "known anymore");
+ p2p_dbg(p2p, "Peer not known anymore");
break;
}
p2p_connect_send(p2p, dev);
@@ -948,8 +1092,7 @@ static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct p2p_data *p2p = eloop_ctx;
int running;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan timeout "
- "(running=%d)", p2p->p2p_scan_running);
+ p2p_dbg(p2p, "p2p_scan timeout (running=%d)", p2p->p2p_scan_running);
running = p2p->p2p_scan_running;
/* Make sure we recover from missed scan results callback */
p2p->p2p_scan_running = 0;
@@ -967,18 +1110,51 @@ static void p2p_free_req_dev_types(struct p2p_data *p2p)
}
+static int p2ps_gen_hash(struct p2p_data *p2p, const char *str, u8 *hash)
+{
+ u8 buf[SHA256_MAC_LEN];
+ char str_buf[256];
+ const u8 *adv_array;
+ size_t i, adv_len;
+
+ if (!str || !hash)
+ return 0;
+
+ if (!str[0]) {
+ os_memcpy(hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+ return 1;
+ }
+
+ adv_array = (u8 *) str_buf;
+ adv_len = os_strlen(str);
+
+ for (i = 0; str[i] && i < adv_len; i++) {
+ if (str[i] >= 'A' && str[i] <= 'Z')
+ str_buf[i] = str[i] - 'A' + 'a';
+ else
+ str_buf[i] = str[i];
+ }
+
+ if (sha256_vector(1, &adv_array, &adv_len, buf))
+ return 0;
+
+ os_memcpy(hash, buf, P2PS_HASH_LEN);
+ return 1;
+}
+
+
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay)
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_count, const char **seek, int freq)
{
int res;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)",
- type);
+ p2p_dbg(p2p, "Starting find (type=%d)", type);
+ os_get_reltime(&p2p->find_start);
if (p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
- "already running");
+ p2p_dbg(p2p, "p2p_scan is already running");
}
p2p_free_req_dev_types(p2p);
@@ -998,6 +1174,47 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
} else
p2p->find_dev_id = NULL;
+ if (seek_count == 0 || !seek) {
+ /* Not an ASP search */
+ p2p->p2ps_seek = 0;
+ } else if (seek_count == 1 && seek && (!seek[0] || !seek[0][0])) {
+ /*
+ * An empty seek string means no hash values, but still an ASP
+ * search.
+ */
+ p2p->p2ps_seek_count = 0;
+ p2p->p2ps_seek = 1;
+ } else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {
+ u8 buf[P2PS_HASH_LEN];
+ int i;
+
+ p2p->p2ps_seek_count = seek_count;
+ for (i = 0; i < seek_count; i++) {
+ if (!p2ps_gen_hash(p2p, seek[i], buf))
+ continue;
+
+ /* If asking for wildcard, don't do others */
+ if (os_memcmp(buf, p2p->wild_card_hash,
+ P2PS_HASH_LEN) == 0) {
+ p2p->p2ps_seek_count = 0;
+ break;
+ }
+
+ os_memcpy(&p2p->query_hash[i * P2PS_HASH_LEN], buf,
+ P2PS_HASH_LEN);
+ }
+ p2p->p2ps_seek = 1;
+ } else {
+ p2p->p2ps_seek_count = 0;
+ p2p->p2ps_seek = 1;
+ }
+
+ /* Special case to perform wildcard search */
+ if (p2p->p2ps_seek_count == 0 && p2p->p2ps_seek) {
+ p2p->p2ps_seek_count = 1;
+ os_memcpy(&p2p->query_hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+ }
+
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p_clear_timeout(p2p);
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
@@ -1013,6 +1230,19 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
p2p, NULL);
switch (type) {
case P2P_FIND_START_WITH_FULL:
+ if (freq > 0) {
+ /*
+ * Start with the specified channel and then move to
+ * social channels only scans.
+ */
+ res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
+ P2P_SCAN_SPECIFIC, freq,
+ p2p->num_req_dev_types,
+ p2p->req_dev_types, dev_id,
+ DEV_PW_DEFAULT);
+ break;
+ }
+ /* fall through */
case P2P_FIND_PROGRESSIVE:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
p2p->num_req_dev_types,
@@ -1029,22 +1259,12 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
return -1;
}
- if (res == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
- } else if (res == 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
- "p2p_scan at this point - will try again after "
- "previous scan completes");
- res = 0;
- p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
- eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
- } else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
- "p2p_scan");
+ 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 */
+ res = 0; /* do not report failure */
+ } else if (res != 0) {
+ p2p_dbg(p2p, "Failed to start p2p_scan");
p2p_set_state(p2p, P2P_IDLE);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
}
@@ -1053,47 +1273,33 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
}
-int p2p_other_scan_completed(struct p2p_data *p2p)
-{
- if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) {
- p2p_set_state(p2p, P2P_SEARCH);
- p2p_search(p2p);
- return 1;
- }
- if (p2p->state != P2P_SEARCH_WHEN_READY)
- return 0;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
- "now that previous scan was completed");
- if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
- p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id, p2p->search_delay) < 0)
- return 0;
- return 1;
-}
-
-
void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
+ p2p_dbg(p2p, "Stopping find");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
- if (p2p->state == P2P_SEARCH)
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+ if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
+ p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
+
+ p2p->p2ps_seek_count = 0;
+
p2p_set_state(p2p, P2P_IDLE);
p2p_free_req_dev_types(p2p);
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
+ if (p2p->go_neg_peer)
+ p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
p2p->go_neg_peer = NULL;
p2p->sd_peer = NULL;
p2p->invite_peer = NULL;
p2p_stop_listen_for_freq(p2p, freq);
+ p2p->send_action_in_progress = 0;
}
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
{
if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen "
- "since we are on correct channel for response");
+ p2p_dbg(p2p, "Skip stop_listen since we are on correct channel for response");
return;
}
if (p2p->in_listen) {
@@ -1106,38 +1312,51 @@ void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
* when the operation gets canceled, so clear the internal
* variable that is tracking driver state.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear "
- "drv_in_listen (%d)", p2p->drv_in_listen);
+ p2p_dbg(p2p, "Clear drv_in_listen (%d)", p2p->drv_in_listen);
p2p->drv_in_listen = 0;
}
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
}
+void p2p_stop_listen(struct p2p_data *p2p)
+{
+ if (p2p->state != P2P_LISTEN_ONLY) {
+ p2p_dbg(p2p, "Skip stop_listen since not in listen_only state.");
+ return;
+ }
+
+ p2p_stop_listen_for_freq(p2p, 0);
+ p2p_set_state(p2p, P2P_IDLE);
+}
+
+
void p2p_stop_find(struct p2p_data *p2p)
{
+ p2p->pending_listen_freq = 0;
p2p_stop_find_for_freq(p2p, 0);
}
static int p2p_prepare_channel_pref(struct p2p_data *p2p,
unsigned int force_freq,
- unsigned int pref_freq)
+ unsigned int pref_freq, int go)
{
u8 op_class, op_channel;
unsigned int freq = force_freq ? force_freq : pref_freq;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_class, &op_channel) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported frequency %u MHz", freq);
+ p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
+ if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
+ p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
return -1;
}
- if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Frequency %u MHz (oper_class %u channel %u) not "
- "allowed for P2P", freq, op_class, op_channel);
+ if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) &&
+ (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
+ op_channel))) {
+ p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
+ freq, op_class, op_channel);
return -1;
}
@@ -1161,34 +1380,74 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p,
static void p2p_prepare_channel_best(struct p2p_data *p2p)
{
u8 op_class, op_channel;
+ const int op_classes_5ghz[] = { 124, 115, 0 };
+ const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+ const int op_classes_vht[] = { 128, 0 };
+
+ p2p_dbg(p2p, "Prepare channel best");
if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_overall) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
- &op_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
- "overall channel as operating channel preference");
+ p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
+ == 0) {
+ p2p_dbg(p2p, "Select best overall channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_5) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
- &op_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
- "channel as operating channel preference");
+ p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel)
+ == 0) {
+ p2p_dbg(p2p, "Select best 5 GHz channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_24) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
- &op_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
- "GHz channel as operating channel preference");
+ p2p_freq_to_channel(p2p->best_freq_24, &op_class,
+ &op_channel) == 0) {
+ p2p_dbg(p2p, "Select best 2.4 GHz channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
- } else {
+ } else if (p2p->cfg->num_pref_chan > 0 &&
+ p2p_channels_includes(&p2p->cfg->channels,
+ p2p->cfg->pref_chan[0].op_class,
+ p2p->cfg->pref_chan[0].chan)) {
+ p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
+ p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
+ p2p->op_channel = p2p->cfg->pref_chan[0].chan;
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible VHT channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_ht40,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible HT40 channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_5ghz,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible 5 GHz channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
+ } else if (p2p_channels_includes(&p2p->cfg->channels,
+ p2p->cfg->op_reg_class,
+ p2p->cfg->op_channel)) {
+ p2p_dbg(p2p, "Select pre-configured channel as operating channel preference");
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
+ } else if (p2p_channel_random_social(&p2p->cfg->channels,
+ &p2p->op_reg_class,
+ &p2p->op_channel) == 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 {
+ /* Select any random available channel from the first available
+ * operating class */
+ p2p_channel_select(&p2p->cfg->channels, NULL,
+ &p2p->op_reg_class,
+ &p2p->op_channel);
+ p2p_dbg(p2p, "Select random available channel %d from operating class %d as operating channel preference",
+ p2p->op_channel, p2p->op_reg_class);
}
os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -1202,6 +1461,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* @dev: Selected peer device
* @force_freq: Forced frequency in MHz or 0 if not forced
* @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * @go: Whether the local end will be forced to be GO
* Returns: 0 on success, -1 on failure (channel not supported for P2P)
*
* This function is used to do initial operating channel selection for GO
@@ -1209,18 +1469,27 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* may be further optimized in p2p_reselect_channel() once the peer information
* is available.
*/
-static int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
- unsigned int force_freq, unsigned int pref_freq)
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ unsigned int force_freq, unsigned int pref_freq, int go)
{
+ p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
if (force_freq || pref_freq) {
- if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
+ 0)
return -1;
} else {
p2p_prepare_channel_best(p2p);
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Own preference for operation channel: "
- "Operating Class %u Channel %u%s",
+ p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
+ if (go)
+ p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
+ else if (!force_freq)
+ p2p_channels_union_inplace(&p2p->channels,
+ &p2p->cfg->cli_channels);
+ p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
+
+ p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
p2p->op_reg_class, p2p->op_channel,
force_freq ? " (forced)" : "");
@@ -1258,40 +1527,38 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg, unsigned int pref_freq)
+ int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Request to start group negotiation - peer=" MACSTR
+ p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
- " wps_method=%d persistent_group=%d pd_before_go_neg=%d",
+ " wps_method=%d persistent_group=%d pd_before_go_neg=%d "
+ "oob_pw_id=%u",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group, pd_before_go_neg);
+ wps_method, persistent_group, pd_before_go_neg, oob_pw_id);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot connect to unknown P2P Device " MACSTR,
+ p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR,
MAC2STR(peer_addr));
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ go_intent == 15) < 0)
return -1;
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot connect to P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
" that is in a group and is not discoverable",
MAC2STR(peer_addr));
return -1;
}
if (dev->oper_freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot connect to P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
" with incomplete information",
MAC2STR(peer_addr));
return -1;
@@ -1319,8 +1586,18 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
if (pd_before_go_neg)
dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
- else
+ else {
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+ /*
+ * Assign dialog token and tie breaker here to use the same
+ * values in each retry within the same GO Negotiation exchange.
+ */
+ dev->dialog_token++;
+ if (dev->dialog_token == 0)
+ dev->dialog_token = 1;
+ dev->tie_breaker = p2p->next_tie_breaker;
+ p2p->next_tie_breaker = !p2p->next_tie_breaker;
+ }
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
@@ -1337,19 +1614,17 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
* new GO Negotiation, e.g., when the pending frame was from a
* previous attempt at starting a GO Negotiation.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
- "previous pending Action frame TX that was waiting "
- "for p2p_scan completion");
+ p2p_dbg(p2p, "Dropped previous pending Action frame TX that was waiting for p2p_scan completion");
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
}
dev->wps_method = wps_method;
+ dev->oob_pw_id = oob_pw_id;
dev->status = P2P_SC_SUCCESS;
if (p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: p2p_scan running - delay connect send");
+ p2p_dbg(p2p, "p2p_scan running - delay connect send");
p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT;
os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
return 0;
@@ -1365,26 +1640,25 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- unsigned int pref_freq)
+ unsigned int pref_freq, u16 oob_pw_id)
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Request to authorize group negotiation - peer=" MACSTR
+ p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
- " wps_method=%d persistent_group=%d",
+ " wps_method=%d persistent_group=%d oob_pw_id=%u",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group);
+ wps_method, persistent_group, oob_pw_id);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot authorize unknown P2P Device " MACSTR,
+ p2p_dbg(p2p, "Cannot authorize unknown P2P Device " MACSTR,
MAC2STR(peer_addr));
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
+ 15) < 0)
return -1;
p2p->ssid_set = 0;
@@ -1405,6 +1679,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
dev->wps_method = wps_method;
+ dev->oob_pw_id = oob_pw_id;
dev->status = P2P_SC_SUCCESS;
return 0;
@@ -1414,18 +1689,16 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
struct p2p_device *dev, struct p2p_message *msg)
{
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
- p2p_copy_wps_info(dev, 0, msg);
+ p2p_copy_wps_info(p2p, dev, 0, msg);
if (msg->listen_channel) {
int freq;
- freq = p2p_channel_to_freq((char *) msg->listen_channel,
- msg->listen_channel[3],
+ freq = p2p_channel_to_freq(msg->listen_channel[3],
msg->listen_channel[4]);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown peer Listen channel: "
+ p2p_dbg(p2p, "Unknown peer Listen channel: "
"country=%c%c(0x%02x) reg_class=%u channel=%u",
msg->listen_channel[0],
msg->listen_channel[1],
@@ -1433,8 +1706,8 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
msg->listen_channel[3],
msg->listen_channel[4]);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update "
- "peer " MACSTR " Listen channel: %u -> %u MHz",
+ p2p_dbg(p2p, "Update peer " MACSTR
+ " Listen channel: %u -> %u MHz",
MAC2STR(dev->info.p2p_device_addr),
dev->listen_freq, freq);
dev->listen_freq = freq;
@@ -1448,12 +1721,9 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Completed device entry based on data from "
- "GO Negotiation Request");
+ p2p_dbg(p2p, "Completed device entry based on data from GO Negotiation Request");
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Created device entry based on GO Neg Req: "
+ p2p_dbg(p2p, "Created device entry based on GO Neg Req: "
MACSTR " dev_capab=0x%x group_capab=0x%x name='%s' "
"listen_freq=%d",
MAC2STR(dev->info.p2p_device_addr),
@@ -1464,8 +1734,7 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
dev->flags &= ~P2P_DEV_GROUP_CLIENT_ONLY;
if (dev->flags & P2P_DEV_USER_REJECTED) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Do not report rejected device");
+ p2p_dbg(p2p, "Do not report rejected device");
return;
}
@@ -1487,8 +1756,15 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len)
int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
{
- p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
- p2p_random(params->passphrase, 8);
+ if (p2p->ssid_set) {
+ os_memcpy(params->ssid, p2p->ssid, p2p->ssid_len);
+ params->ssid_len = p2p->ssid_len;
+ } else {
+ p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
+ }
+ p2p->ssid_set = 0;
+
+ p2p_random(params->passphrase, p2p->cfg->passphrase_len);
return 0;
}
@@ -1498,13 +1774,9 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
struct p2p_go_neg_results res;
int go = peer->go_state == LOCAL_GO;
struct p2p_channels intersection;
- int freqs;
- size_t i, j;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation with " MACSTR " completed (%s will be "
- "GO)", MAC2STR(peer->info.p2p_device_addr),
- go ? "local end" : "peer");
+ p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
+ MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
os_memset(&res, 0, sizeof(res));
res.role_go = go;
@@ -1520,12 +1792,11 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
if (go) {
/* Setup AP mode for WPS provisioning */
- res.freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->op_reg_class,
+ res.freq = p2p_channel_to_freq(p2p->op_reg_class,
p2p->op_channel);
os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
res.ssid_len = p2p->ssid_len;
- p2p_random(res.passphrase, 8);
+ p2p_random(res.passphrase, p2p->cfg->passphrase_len);
} else {
res.freq = peer->oper_freq;
if (p2p->ssid_len) {
@@ -1534,31 +1805,28 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
}
}
+ p2p_channels_dump(p2p, "own channels", &p2p->channels);
+ p2p_channels_dump(p2p, "peer channels", &peer->channels);
p2p_channels_intersect(&p2p->channels, &peer->channels,
&intersection);
- freqs = 0;
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c = &intersection.reg_class[i];
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- for (j = 0; j < c->channels; j++) {
- int freq;
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- freq = p2p_channel_to_freq(peer->country, c->reg_class,
- c->channel[j]);
- if (freq < 0)
- continue;
- res.freq_list[freqs++] = freq;
- }
+ if (go) {
+ p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal",
+ &intersection);
}
+ p2p_channels_to_freqs(&intersection, res.freq_list,
+ P2P_MAX_CHANNELS);
+
res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
p2p_clear_timeout(p2p);
p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
peer->wps_method = WPS_NOT_READY;
+ peer->oob_pw_id = 0;
+ wpabuf_free(peer->go_neg_conf);
+ peer->go_neg_conf = NULL;
p2p_set_state(p2p, P2P_PROVISIONING);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
@@ -1568,8 +1836,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: RX P2P Public Action from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "RX P2P Public Action from " MACSTR, MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len);
if (len < 1)
@@ -1605,8 +1872,7 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1);
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported P2P Public Action frame type %d",
+ p2p_dbg(p2p, "Unsupported P2P Public Action frame type %d",
data[0]);
break;
}
@@ -1624,20 +1890,15 @@ static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
case WLAN_PA_VENDOR_SPECIFIC:
data++;
len--;
- if (len < 3)
+ if (len < 4)
return;
- if (WPA_GET_BE24(data) != OUI_WFA)
+ if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
return;
- data += 3;
- len -= 3;
- if (len < 1)
- return;
-
- if (*data != P2P_OUI_TYPE)
- return;
+ data += 4;
+ len -= 4;
- p2p_rx_p2p_action(p2p, sa, data + 1, len - 1, freq);
+ p2p_rx_p2p_action(p2p, sa, data, len, freq);
break;
case WLAN_PA_GAS_INITIAL_REQ:
p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq);
@@ -1670,27 +1931,20 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
if (len < 4)
return;
- if (WPA_GET_BE24(data) != OUI_WFA)
- return;
- data += 3;
- len -= 3;
-
- if (*data != P2P_OUI_TYPE)
+ if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
return;
- data++;
- len--;
+ data += 4;
+ len -= 4;
/* P2P action frame */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: RX P2P Action from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "RX P2P Action from " MACSTR, MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Action contents", data, len);
if (len < 1)
return;
switch (data[0]) {
case P2P_NOA:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - Notice of Absence");
+ p2p_dbg(p2p, "Received P2P Action - Notice of Absence");
/* TODO */
break;
case P2P_PRESENCE_REQ:
@@ -1703,8 +1957,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq);
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - unknown type %u", data[0]);
+ p2p_dbg(p2p, "Received P2P Action - unknown type %u", data[0]);
break;
}
}
@@ -1715,8 +1968,17 @@ static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx)
struct p2p_data *p2p = eloop_ctx;
if (p2p->go_neg_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_go_neg_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p->go_neg_peer->status = P2P_SC_SUCCESS;
+ /*
+ * Set new timeout to make sure a previously set one does not expire
+ * too quickly while waiting for the GO Negotiation to complete.
+ */
+ p2p_set_timeout(p2p, 0, 500000);
p2p_connect_send(p2p, p2p->go_neg_peer);
}
@@ -1726,8 +1988,13 @@ static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx)
struct p2p_data *p2p = eloop_ctx;
if (p2p->invite_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_invite_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
- p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr);
+ p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+ p2p->invite_dev_pw_id);
}
@@ -1760,7 +2027,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
if (dev) {
if (dev->country[0] == 0 && msg.listen_channel)
os_memcpy(dev->country, msg.listen_channel, 3);
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
p2p_parse_free(&msg);
return; /* already known */
}
@@ -1771,17 +2038,16 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
return;
}
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
dev->flags |= P2P_DEV_PROBE_REQ_ONLY;
if (msg.listen_channel) {
os_memcpy(dev->country, msg.listen_channel, 3);
- dev->listen_freq = p2p_channel_to_freq(dev->country,
- msg.listen_channel[3],
+ dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3],
msg.listen_channel[4]);
}
- p2p_copy_wps_info(dev, 1, &msg);
+ p2p_copy_wps_info(p2p, dev, 1, &msg);
if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
@@ -1790,8 +2056,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
p2p_parse_free(&msg);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Created device entry based on Probe Req: " MACSTR
+ p2p_dbg(p2p, "Created device entry based on Probe Req: " MACSTR
" dev_capab=0x%x group_capab=0x%x name='%s' listen_freq=%d",
MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
dev->info.group_capab, dev->info.device_name,
@@ -1807,7 +2072,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
dev = p2p_get_device(p2p, addr);
if (dev) {
- os_get_time(&dev->last_seen);
+ os_get_reltime(&dev->last_seen);
return dev; /* already known */
}
@@ -1870,11 +2135,12 @@ int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps)
attr.num_req_dev_type))
return 1; /* Own Primary Device Type matches */
- for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
+ for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) {
if (dev_type_list_match(p2p->cfg->sec_dev_type[i],
attr.req_dev_type,
attr.num_req_dev_type))
- return 1; /* Own Secondary Device Type matches */
+ return 1; /* Own Secondary Device Type matches */
+ }
/* No matching device type found */
return 0;
@@ -1893,6 +2159,12 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
extra = wpabuf_len(p2p->wfd_ie_probe_resp);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
+
+ if (p2p->query_count)
+ extra += MAX_SVC_ADV_IE_LEN;
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -1902,13 +2174,21 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
}
- p2p_build_wps_ie(p2p, buf, pw_id, 1);
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for Probe Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_probe_resp)
wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
+ wpabuf_put_buf(buf,
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
+
/* P2P IE */
len = p2p_buf_add_ie_hdr(buf);
p2p_buf_add_capability(buf, p2p->dev_capab &
@@ -1919,40 +2199,35 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
p2p_buf_add_device_info(buf, p2p, NULL);
p2p_buf_update_ie_hdr(buf, len);
+ if (p2p->query_count) {
+ p2p_buf_add_service_instance(buf, p2p, p2p->query_count,
+ p2p->query_hash,
+ p2p->p2ps_adv_list);
+ }
+
return buf;
}
-static int is_11b(u8 rate)
+static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
{
- return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
-}
+ struct p2ps_advertisement *adv_data;
+ p2p_dbg(p2p, "ASP find - ASP list: %p", p2p->p2ps_adv_list);
-static int supp_rates_11b_only(struct ieee802_11_elems *elems)
-{
- int num_11b = 0, num_others = 0;
- int i;
+ /* Wildcard always matches if we have actual services */
+ if (os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
+ return p2p->p2ps_adv_list != NULL;
- if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
- return 0;
-
- for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
- if (is_11b(elems->supp_rates[i]))
- num_11b++;
- else
- num_others++;
- }
-
- for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
- i++) {
- if (is_11b(elems->ext_supp_rates[i]))
- num_11b++;
- else
- num_others++;
+ adv_data = p2p->p2ps_adv_list;
+ while (adv_data) {
+ p2p_dbg(p2p, "ASP hash: %x =? %x", hash[0], adv_data->hash[0]);
+ if (os_memcmp(hash, adv_data->hash, P2PS_HASH_LEN) == 0)
+ return 1;
+ adv_data = adv_data->next;
}
- return num_11b > 0 && num_others == 0;
+ return 0;
}
@@ -1966,19 +2241,16 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
struct p2p_message msg;
struct wpabuf *ies;
- if (!p2p->in_listen || !p2p->drv_in_listen) {
- /* not in Listen state - ignore Probe Request */
- return P2P_PREQ_NOT_LISTEN;
- }
-
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
/* Ignore invalid Probe Request frames */
+ p2p_dbg(p2p, "Could not parse Probe Request frame - ignore it");
return P2P_PREQ_MALFORMED;
}
if (elems.p2p == NULL) {
/* not a P2P probe - ignore it */
+ p2p_dbg(p2p, "Not a P2P probe - ignore it");
return P2P_PREQ_NOT_P2P;
}
@@ -1986,11 +2258,15 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
/* Not sent to the broadcast address or our P2P Device Address
*/
+ p2p_dbg(p2p, "Probe Req DA " MACSTR " not ours - ignore it",
+ MAC2STR(dst));
return P2P_PREQ_NOT_PROCESSED;
}
if (bssid && !is_broadcast_ether_addr(bssid)) {
/* Not sent to the Wildcard BSSID */
+ p2p_dbg(p2p, "Probe Req BSSID " MACSTR " not wildcard - ignore it",
+ MAC2STR(bssid));
return P2P_PREQ_NOT_PROCESSED;
}
@@ -1998,23 +2274,86 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
0) {
/* not using P2P Wildcard SSID - ignore */
+ p2p_dbg(p2p, "Probe Req not using P2P Wildcard SSID - ignore it");
return P2P_PREQ_NOT_PROCESSED;
}
if (supp_rates_11b_only(&elems)) {
/* Indicates support for 11b rates only */
+ p2p_dbg(p2p, "Probe Req with 11b rates only supported - ignore it");
return P2P_PREQ_NOT_P2P;
}
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
/* Could not parse P2P attributes */
+ p2p_dbg(p2p, "Could not parse P2P attributes in Probe Req - ignore it");
return P2P_PREQ_NOT_P2P;
}
+ p2p->p2ps_svc_found = 0;
+
+ if (msg.service_hash && msg.service_hash_count) {
+ const u8 *hash = msg.service_hash;
+ u8 *dest = p2p->query_hash;
+ u8 i;
+
+ p2p->query_count = 0;
+ for (i = 0; i < msg.service_hash_count; i++) {
+ if (p2p_service_find_asp(p2p, hash)) {
+ p2p->p2ps_svc_found = 1;
+
+ if (!os_memcmp(hash, p2p->wild_card_hash,
+ P2PS_HASH_LEN)) {
+ /* We found match(es) but wildcard
+ * will return all */
+ p2p->query_count = 1;
+ os_memcpy(p2p->query_hash, hash,
+ P2PS_HASH_LEN);
+ break;
+ }
+
+ /* Save each matching hash */
+ if (p2p->query_count < P2P_MAX_QUERY_HASH) {
+ os_memcpy(dest, hash, P2PS_HASH_LEN);
+ dest += P2PS_HASH_LEN;
+ p2p->query_count++;
+ } else {
+ /* We found match(es) but too many to
+ * return all */
+ p2p->query_count = 0;
+ break;
+ }
+ }
+ hash += P2PS_HASH_LEN;
+ }
+
+ p2p_dbg(p2p, "ASP adv found: %d", p2p->p2ps_svc_found);
+
+ /* Probed hash unknown */
+ if (!p2p->p2ps_svc_found) {
+ p2p_parse_free(&msg);
+ return P2P_PREQ_NOT_PROCESSED;
+ }
+ } else {
+ /* This is not a P2PS Probe Request */
+ p2p->query_count = 0;
+ p2p_dbg(p2p, "No P2PS Hash in Probe Request");
+
+ if (!p2p->in_listen || !p2p->drv_in_listen) {
+ /* not in Listen state - ignore Probe Request */
+ p2p_dbg(p2p, "Not in Listen state (in_listen=%d drv_in_listen=%d) - ignore Probe Request",
+ p2p->in_listen, p2p->drv_in_listen);
+ p2p_parse_free(&msg);
+ return P2P_PREQ_NOT_LISTEN;
+ }
+ }
+
if (msg.device_id &&
os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
/* Device ID did not match */
+ p2p_dbg(p2p, "Probe Req requested Device ID " MACSTR " did not match - ignore it",
+ MAC2STR(msg.device_id));
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -2023,6 +2362,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_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -2030,11 +2370,11 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
if (!p2p->cfg->send_probe_resp) {
/* Response generated elsewhere */
+ p2p_dbg(p2p, "Probe Resp generated elsewhere - do not generate additional response");
return P2P_PREQ_NOT_PROCESSED;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Reply to P2P Probe Request in Listen state");
+ p2p_dbg(p2p, "Reply to P2P Probe Request in Listen state");
/*
* We do not really have a specific BSS that this frame is advertising,
@@ -2106,27 +2446,28 @@ p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
+ p2p->query_count = 0;
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
p2p->go_neg_peer &&
os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
- == 0) {
+ == 0 &&
+ !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
/* Received a Probe Request from GO Negotiation peer */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Found GO Negotiation peer - try to start GO "
- "negotiation from timeout");
+ p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout");
+ eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
return P2P_PREQ_PROCESSED;
}
if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
p2p->invite_peer &&
+ (p2p->invite_peer->flags & P2P_DEV_WAIT_INV_REQ_ACK) &&
os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN)
== 0) {
/* Received a Probe Request from Invite peer */
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Found Invite peer - try to start Invite from "
- "timeout");
+ p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
+ eloop_cancel_timeout(p2p_invite_start, p2p, NULL);
eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
return P2P_PREQ_PROCESSED;
}
@@ -2203,6 +2544,9 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
extra = wpabuf_len(p2p->wfd_ie_assoc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
+
/*
* (Re)Association Request - P2P IE
* P2P Capability attribute (shall be present)
@@ -2218,6 +2562,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
+ wpabuf_put_buf(tmp,
+ p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
+
peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
lpos = p2p_buf_add_ie_hdr(tmp);
@@ -2256,6 +2604,132 @@ int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end)
}
+struct p2ps_advertisement *
+p2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id)
+{
+ struct p2ps_advertisement *adv_data;
+
+ if (!p2p)
+ return NULL;
+
+ adv_data = p2p->p2ps_adv_list;
+ while (adv_data) {
+ if (adv_data->id == adv_id)
+ return adv_data;
+ adv_data = adv_data->next;
+ }
+
+ return NULL;
+}
+
+
+int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id)
+{
+ struct p2ps_advertisement *adv_data;
+ struct p2ps_advertisement **prior;
+
+ if (!p2p)
+ return -1;
+
+ adv_data = p2p->p2ps_adv_list;
+ prior = &p2p->p2ps_adv_list;
+ while (adv_data) {
+ if (adv_data->id == adv_id) {
+ p2p_dbg(p2p, "Delete ASP adv_id=0x%x", adv_id);
+ *prior = adv_data->next;
+ os_free(adv_data);
+ return 0;
+ }
+ prior = &adv_data->next;
+ adv_data = adv_data->next;
+ }
+
+ return -1;
+}
+
+
+int p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
+ const char *adv_str, u8 svc_state, u16 config_methods,
+ const char *svc_info)
+{
+ struct p2ps_advertisement *adv_data, *tmp, **prev;
+ u8 buf[P2PS_HASH_LEN];
+ size_t adv_data_len, adv_len, info_len = 0;
+
+ if (!p2p || !adv_str || !adv_str[0])
+ return -1;
+
+ if (!(config_methods & p2p->cfg->config_methods)) {
+ p2p_dbg(p2p, "Config methods not supported svc: 0x%x dev: 0x%x",
+ config_methods, p2p->cfg->config_methods);
+ return -1;
+ }
+
+ if (!p2ps_gen_hash(p2p, adv_str, buf))
+ return -1;
+
+ if (svc_info)
+ info_len = os_strlen(svc_info);
+ adv_len = os_strlen(adv_str);
+ adv_data_len = sizeof(struct p2ps_advertisement) + adv_len + 1 +
+ info_len + 1;
+
+ adv_data = os_zalloc(adv_data_len);
+ if (!adv_data)
+ return -1;
+
+ os_memcpy(adv_data->hash, buf, P2PS_HASH_LEN);
+ adv_data->id = adv_id;
+ adv_data->state = svc_state;
+ adv_data->config_methods = config_methods & p2p->cfg->config_methods;
+ adv_data->auto_accept = (u8) auto_accept;
+ os_memcpy(adv_data->svc_name, adv_str, adv_len);
+
+ if (svc_info && info_len) {
+ adv_data->svc_info = &adv_data->svc_name[adv_len + 1];
+ os_memcpy(adv_data->svc_info, svc_info, info_len);
+ }
+
+ /*
+ * Group Advertisements by service string. They do not need to be
+ * sorted, but groups allow easier Probe Response instance grouping
+ */
+ tmp = p2p->p2ps_adv_list;
+ prev = &p2p->p2ps_adv_list;
+ while (tmp) {
+ if (tmp->id == adv_data->id) {
+ if (os_strcmp(tmp->svc_name, adv_data->svc_name) != 0) {
+ os_free(adv_data);
+ return -1;
+ }
+ adv_data->next = tmp->next;
+ *prev = adv_data;
+ os_free(tmp);
+ goto inserted;
+ } else {
+ if (os_strcmp(tmp->svc_name, adv_data->svc_name) == 0) {
+ adv_data->next = tmp->next;
+ tmp->next = adv_data;
+ goto inserted;
+ }
+ }
+ prev = &tmp->next;
+ tmp = tmp->next;
+ }
+
+ /* No svc_name match found */
+ adv_data->next = p2p->p2ps_adv_list;
+ p2p->p2ps_adv_list = adv_data;
+
+inserted:
+ p2p_dbg(p2p,
+ "Added ASP advertisement adv_id=0x%x config_methods=0x%x svc_state=0x%x adv_str='%s'",
+ adv_id, adv_data->config_methods, svc_state, adv_str);
+
+ return 0;
+}
+
+
int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
{
struct p2p_message msg;
@@ -2301,24 +2775,20 @@ static void p2p_clear_go_neg(struct p2p_data *p2p)
void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
{
if (p2p->go_neg_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending Group Formation - "
- "ignore WPS registration success notification");
+ p2p_dbg(p2p, "No pending Group Formation - ignore WPS registration success notification");
return; /* No pending Group Formation */
}
if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) !=
0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore WPS registration success notification "
- "for " MACSTR " (GO Negotiation peer " MACSTR ")",
+ p2p_dbg(p2p, "Ignore WPS registration success notification for "
+ MACSTR " (GO Negotiation peer " MACSTR ")",
MAC2STR(mac_addr),
MAC2STR(p2p->go_neg_peer->intended_addr));
return; /* Ignore unexpected peer address */
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Group Formation completed successfully with " MACSTR,
+ p2p_dbg(p2p, "Group Formation completed successfully with " MACSTR,
MAC2STR(mac_addr));
p2p_clear_go_neg(p2p);
@@ -2328,14 +2798,11 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
void p2p_group_formation_failed(struct p2p_data *p2p)
{
if (p2p->go_neg_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending Group Formation - "
- "ignore group formation failure notification");
+ p2p_dbg(p2p, "No pending Group Formation - ignore group formation failure notification");
return; /* No pending Group Formation */
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Group Formation failed with " MACSTR,
+ p2p_dbg(p2p, "Group Formation failed with " MACSTR,
MAC2STR(p2p->go_neg_peer->intended_addr));
p2p_clear_go_neg(p2p);
@@ -2346,7 +2813,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
- if (cfg->max_peers < 1)
+ if (cfg->max_peers < 1 ||
+ cfg->passphrase_len < 8 || cfg->passphrase_len > 63)
return NULL;
p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));
@@ -2375,11 +2843,14 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->cfg->num_pref_chan = 0;
}
+ p2ps_gen_hash(p2p, P2PS_WILD_HASH_STR, p2p->wild_card_hash);
+
p2p->min_disc_int = 1;
p2p->max_disc_int = 3;
p2p->max_disc_tu = -1;
- os_get_random(&p2p->next_tie_breaker, 1);
+ if (os_get_random(&p2p->next_tie_breaker, 1) < 0)
+ p2p->next_tie_breaker = 0;
p2p->next_tie_breaker &= 0x01;
if (cfg->sd_request)
p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
@@ -2395,6 +2866,11 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->go_timeout = 100;
p2p->client_timeout = 20;
+ p2p->num_p2p_sd_queries = 0;
+
+ p2p_dbg(p2p, "initialized");
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
return p2p;
}
@@ -2402,6 +2878,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
void p2p_deinit(struct p2p_data *p2p)
{
+ struct p2ps_advertisement *adv, *prev;
+
#ifdef CONFIG_WIFI_DISPLAY
wpabuf_free(p2p->wfd_ie_beacon);
wpabuf_free(p2p->wfd_ie_probe_req);
@@ -2419,6 +2897,8 @@ void p2p_deinit(struct p2p_data *p2p)
eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+ eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p_flush(p2p);
p2p_free_req_dev_types(p2p);
os_free(p2p->cfg->dev_name);
@@ -2428,9 +2908,19 @@ void p2p_deinit(struct p2p_data *p2p)
os_free(p2p->cfg->serial_number);
os_free(p2p->cfg->pref_chan);
os_free(p2p->groups);
+ os_free(p2p->p2ps_prov);
wpabuf_free(p2p->sd_resp);
os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
+ os_free(p2p->no_go_freq.range);
+
+ adv = p2p->p2ps_adv_list;
+ while (adv) {
+ prev = adv;
+ adv = adv->next;
+ os_free(prev);
+ }
+
os_free(p2p);
}
@@ -2458,13 +2948,15 @@ int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr)
if (dev == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unauthorizing " MACSTR,
- MAC2STR(addr));
+ p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
- if (p2p->go_neg_peer == dev)
+ if (p2p->go_neg_peer == dev) {
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p->go_neg_peer = NULL;
+ }
dev->wps_method = WPS_NOT_READY;
+ dev->oob_pw_id = 0;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
@@ -2619,55 +3111,105 @@ 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)
+{
+ 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)
+ return 1;
+
+ if (dev->req_config_methods &&
+ !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
+ p2p_dbg(p2p, "Send pending Provision Discovery Request to "
+ MACSTR " (config methods 0x%x)",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->req_config_methods);
+ if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
void p2p_continue_find(struct p2p_data *p2p)
{
struct p2p_device *dev;
+ int found;
+
p2p_set_state(p2p, P2P_SEARCH);
+
+ /* Continue from the device following the last iteration */
+ found = 0;
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (dev->flags & P2P_DEV_SD_SCHEDULE) {
- if (p2p_start_sd(p2p, dev) == 0)
- return;
- else
- break;
- } else if (dev->req_config_methods &&
- !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provision Discovery Request to "
- MACSTR " (config methods 0x%x)",
- MAC2STR(dev->info.p2p_device_addr),
- dev->req_config_methods);
- if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
- return;
+ if (dev == p2p->last_p2p_find_oper) {
+ found = 1;
+ continue;
+ }
+ if (!found)
+ continue;
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
+ return;
}
}
+ /*
+ * Wrap around to the beginning of the list and continue until the last
+ * iteration device.
+ */
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
+ return;
+ }
+ if (dev == p2p->last_p2p_find_oper)
+ break;
+ }
+
p2p_listen_in_find(p2p, 1);
}
static void p2p_sd_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery Query TX callback: success=%d",
+ p2p_dbg(p2p, "Service Discovery Query TX callback: success=%d",
success);
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (!success) {
- if (p2p->sd_peer) {
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
- p2p->sd_peer = NULL;
- }
- p2p_continue_find(p2p);
+ if (p2p->sd_peer)
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->sd_peer = NULL;
+ if (p2p->state != P2P_IDLE)
+ p2p_continue_find(p2p);
return;
}
if (p2p->sd_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No SD peer entry known");
- p2p_continue_find(p2p);
+ p2p_dbg(p2p, "No SD peer entry known");
+ if (p2p->state != P2P_IDLE)
+ p2p_continue_find(p2p);
return;
}
+ if (p2p->sd_query && p2p->sd_query->for_all_peers) {
+ /* Update the pending broadcast SD query count for this device
+ */
+ p2p->sd_peer->sd_pending_bcast_queries--;
+
+ /*
+ * If there are no pending broadcast queries for this device,
+ * mark it as done (-1).
+ */
+ if (p2p->sd_peer->sd_pending_bcast_queries == 0)
+ p2p->sd_peer->sd_pending_bcast_queries = -1;
+ }
+
/* Wait for response from the peer */
p2p_set_state(p2p, P2P_SD_DURING_FIND);
p2p_set_timeout(p2p, 0, 200000);
@@ -2682,9 +3224,6 @@ static void p2p_retry_pd(struct p2p_data *p2p)
{
struct p2p_device *dev;
- if (p2p->state != P2P_IDLE)
- return;
-
/*
* Retry the prov disc req attempt only for the peer that the user had
* requested.
@@ -2697,13 +3236,13 @@ static void p2p_retry_pd(struct p2p_data *p2p)
if (!dev->req_config_methods)
continue;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provision Discovery Request to "
+ p2p_dbg(p2p, "Send pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
p2p_send_prov_disc_req(p2p, dev,
- dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
+ dev->flags & P2P_DEV_PD_FOR_JOIN,
+ p2p->pd_force_freq);
return;
}
}
@@ -2711,8 +3250,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request TX callback: success=%d",
+ p2p_dbg(p2p, "Provision Discovery Request TX callback: success=%d",
success);
/*
@@ -2759,11 +3297,71 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
}
+static int p2p_check_after_scan_tx_continuation(struct p2p_data *p2p)
+{
+ if (p2p->after_scan_tx_in_progress) {
+ p2p->after_scan_tx_in_progress = 0;
+ if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
+ p2p_run_after_scan(p2p))
+ return 1;
+ if (p2p->state == P2P_SEARCH) {
+ p2p_dbg(p2p, "Continue find after after_scan_tx completion");
+ p2p_continue_find(p2p);
+ }
+ }
+
+ return 0;
+}
+
+
+static void p2p_prov_disc_resp_cb(struct p2p_data *p2p, int success)
+{
+ p2p_dbg(p2p, "Provision Discovery Response TX callback: success=%d",
+ success);
+
+ 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 (!success)
+ goto continue_search;
+
+ if (!p2p->cfg->prov_disc_resp_cb ||
+ p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1)
+ goto continue_search;
+
+ p2p_dbg(p2p,
+ "Post-Provision Discovery operations started - do not try to continue other P2P operations");
+ return;
+
+continue_search:
+ p2p_check_after_scan_tx_continuation(p2p);
+}
+
+
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- unsigned int age, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len)
{
- p2p_add_device(p2p, bssid, freq, age, level, ies, ies_len, 1);
+ if (os_reltime_before(rx_time, &p2p->find_start)) {
+ /*
+ * The driver may have cached (e.g., in cfg80211 BSS table) the
+ * scan results for relatively long time. To avoid reporting
+ * stale information, update P2P peers only based on results
+ * that have based on frames received after the last p2p_find
+ * operation was started.
+ */
+ p2p_dbg(p2p, "Ignore old scan result for " MACSTR
+ " (rx_time=%u.%06u)",
+ MAC2STR(bssid), (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
+ return 0;
+ }
+
+ p2p_add_device(p2p, bssid, freq, rx_time, level, ies, ies_len, 1);
return 0;
}
@@ -2772,8 +3370,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
void p2p_scan_res_handled(struct p2p_data *p2p)
{
if (!p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan was not "
- "running, but scan results received");
+ p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
}
p2p->p2p_scan_running = 0;
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
@@ -2787,6 +3384,7 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
{
+ u8 dev_capab;
u8 *len;
#ifdef CONFIG_WIFI_DISPLAY
@@ -2794,9 +3392,20 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
+ wpabuf_put_buf(ies,
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
+
len = p2p_buf_add_ie_hdr(ies);
- p2p_buf_add_capability(ies, p2p->dev_capab &
- ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+
+ dev_capab = p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+
+ /* P2PS requires Probe Request frames to include SD bit */
+ if (p2p->p2ps_seek && p2p->p2ps_seek_count)
+ dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
+
+ p2p_buf_add_capability(ies, dev_capab, 0);
+
if (dev_id)
p2p_buf_add_device_id(ies, dev_id);
if (p2p->cfg->reg_class && p2p->cfg->channel)
@@ -2806,6 +3415,10 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
if (p2p->ext_listen_interval)
p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
p2p->ext_listen_interval);
+
+ if (p2p->p2ps_seek && p2p->p2ps_seek_count)
+ p2p_buf_add_service_hash(ies, p2p);
+
/* TODO: p2p_buf_add_operating_channel() if GO */
p2p_buf_update_ie_hdr(ies, len);
}
@@ -2820,6 +3433,10 @@ size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
len += wpabuf_len(p2p->wfd_ie_probe_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p && p2p->vendor_elem &&
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
+ len += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
+
return len;
}
@@ -2833,14 +3450,12 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
{
struct p2p_device *dev = p2p->go_neg_peer;
+ int timeout;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Request TX callback: success=%d",
- success);
+ p2p_dbg(p2p, "GO Negotiation Request TX callback: success=%d", success);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending GO Negotiation");
+ p2p_dbg(p2p, "No pending GO Negotiation");
return;
}
@@ -2857,9 +3472,7 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
if (!success &&
(dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) &&
!is_zero_ether_addr(dev->member_in_go_dev)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer " MACSTR " did not acknowledge request - "
- "try to use device discoverability through its GO",
+ p2p_dbg(p2p, "Peer " MACSTR " did not acknowledge request - try to use device discoverability through its GO",
MAC2STR(dev->info.p2p_device_addr));
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_send_dev_disc_req(p2p, dev);
@@ -2871,35 +3484,56 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
* channel.
*/
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, success ? 200000 : 100000);
+ timeout = success ? 500000 : 100000;
+ if (!success && p2p->go_neg_peer &&
+ (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
+ unsigned int r;
+ /*
+ * Peer is expected to wait our response and we will skip the
+ * listen phase. Add some randomness to the wait time here to
+ * make it less likely to hit cases where we could end up in
+ * sync with peer not listening.
+ */
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
+ timeout += r % 100000;
+ }
+ p2p_set_timeout(p2p, 0, timeout);
}
static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Response TX callback: success=%d",
+ p2p_dbg(p2p, "GO Negotiation Response TX callback: success=%d",
success);
if (!p2p->go_neg_peer && p2p->state == P2P_PROVISIONING) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore TX callback event - GO Negotiation is "
- "not running anymore");
+ p2p_dbg(p2p, "Ignore TX callback event - GO Negotiation is not running anymore");
return;
}
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, 250000);
+ p2p_set_timeout(p2p, 0, 500000);
}
-static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success)
+static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success,
+ const u8 *addr)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Response (failure) TX callback: "
- "success=%d", success);
+ p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
- p2p_go_neg_failed(p2p, p2p->go_neg_peer,
- p2p->go_neg_peer->status);
+ p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
+ return;
+ }
+
+ if (success) {
+ struct p2p_device *dev;
+ dev = p2p_get_device(p2p, addr);
+ if (dev &&
+ dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+ dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
}
+
+ if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
+ p2p_continue_find(p2p);
}
@@ -2908,16 +3542,45 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation Confirm TX callback: result=%d",
- result);
- p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
if (result == P2P_SEND_ACTION_FAILED) {
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p_go_neg_failed(p2p, -1);
return;
}
+
+ dev = p2p->go_neg_peer;
+
if (result == P2P_SEND_ACTION_NO_ACK) {
/*
+ * Retry GO Negotiation Confirmation
+ * P2P_GO_NEG_CNF_MAX_RETRY_COUNT times if we did not receive
+ * ACK for confirmation.
+ */
+ if (dev && dev->go_neg_conf &&
+ dev->go_neg_conf_sent <= P2P_GO_NEG_CNF_MAX_RETRY_COUNT) {
+ p2p_dbg(p2p, "GO Negotiation Confirm retry %d",
+ dev->go_neg_conf_sent);
+ p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
+ if (p2p_send_action(p2p, dev->go_neg_conf_freq,
+ dev->info.p2p_device_addr,
+ p2p->cfg->dev_addr,
+ dev->info.p2p_device_addr,
+ wpabuf_head(dev->go_neg_conf),
+ wpabuf_len(dev->go_neg_conf), 0) >=
+ 0) {
+ dev->go_neg_conf_sent++;
+ return;
+ }
+ p2p_dbg(p2p, "Failed to re-send Action frame");
+
+ /*
+ * Continue with the assumption that the first attempt
+ * went through and just the ACK frame was lost.
+ */
+ }
+
+ /*
* It looks like the TX status for GO Negotiation Confirm is
* often showing failure even when the peer has actually
* received the frame. Since the peer may change channels
@@ -2927,13 +3590,11 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
* peer did indeed receive the frame, continue regardless of
* the TX status.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Assume GO Negotiation Confirm TX was actually "
- "received by the peer even though Ack was not "
- "reported");
+ p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
}
- dev = p2p->go_neg_peer;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+
if (dev == NULL)
return;
@@ -2948,16 +3609,20 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
enum p2p_pending_action_state state;
int success;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Action frame TX callback (state=%d freq=%u dst=" MACSTR
- " src=" MACSTR " bssid=" MACSTR " result=%d",
+ p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
+ " src=" MACSTR " bssid=" MACSTR " result=%d p2p_state=%s)",
p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
- MAC2STR(bssid), result);
+ MAC2STR(bssid), result, p2p_state_txt(p2p->state));
success = result == P2P_SEND_ACTION_SUCCESS;
state = p2p->pending_action_state;
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
switch (state) {
case P2P_NO_PENDING_ACTION:
+ if (p2p->send_action_in_progress) {
+ p2p->send_action_in_progress = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ }
+ p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_GO_NEG_REQUEST:
p2p_go_neg_req_cb(p2p, success);
@@ -2966,7 +3631,7 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
p2p_go_neg_resp_cb(p2p, success);
break;
case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
- p2p_go_neg_resp_failure_cb(p2p, success);
+ p2p_go_neg_resp_failure_cb(p2p, success, dst);
break;
case P2P_PENDING_GO_NEG_CONFIRM:
p2p_go_neg_conf_cb(p2p, result);
@@ -2977,6 +3642,9 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
case P2P_PENDING_PD:
p2p_prov_disc_cb(p2p, success);
break;
+ case P2P_PENDING_PD_RESPONSE:
+ p2p_prov_disc_resp_cb(p2p, success);
+ break;
case P2P_PENDING_INVITATION_REQUEST:
p2p_invitation_req_cb(p2p, success);
break;
@@ -2993,6 +3661,8 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
p2p_go_disc_req_cb(p2p, success);
break;
}
+
+ p2p->after_scan_tx_in_progress = 0;
}
@@ -3000,23 +3670,18 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
unsigned int duration)
{
if (freq == p2p->pending_client_disc_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Client discoverability remain-awake completed");
+ p2p_dbg(p2p, "Client discoverability remain-awake completed");
p2p->pending_client_disc_freq = 0;
return;
}
if (freq != p2p->pending_listen_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected listen callback for freq=%u "
- "duration=%u (pending_listen_freq=%u)",
+ p2p_dbg(p2p, "Unexpected listen callback for freq=%u duration=%u (pending_listen_freq=%u)",
freq, duration, p2p->pending_listen_freq);
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Starting Listen timeout(%u,%u) on freq=%u based on "
- "callback",
+ p2p_dbg(p2p, "Starting Listen timeout(%u,%u) on freq=%u based on callback",
p2p->pending_listen_sec, p2p->pending_listen_usec,
p2p->pending_listen_freq);
p2p->in_listen = 1;
@@ -3037,18 +3702,15 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver ended Listen "
- "state (freq=%u)", freq);
+ p2p_dbg(p2p, "Driver ended Listen state (freq=%u)", freq);
p2p->drv_in_listen = 0;
if (p2p->in_listen)
return 0; /* Internal timeout will trigger the next step */
if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
if (p2p->go_neg_peer->connect_reqs >= 120) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Timeout on sending GO Negotiation "
- "Request without getting response");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
+ p2p_go_neg_failed(p2p, -1);
return 0;
}
@@ -3065,9 +3727,7 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
* operation while in p2p_find. Avoid an attempt to
* restart a scan here.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan "
- "already in progress - do not try to start a "
- "new one");
+ p2p_dbg(p2p, "p2p_scan already in progress - do not try to start a new one");
return 1;
}
if (p2p->pending_listen_freq) {
@@ -3076,15 +3736,12 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
* offchannel operation for some reason. p2p_search()
* will be started from internal timeout.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Listen "
- "operation did not seem to start - delay "
- "search phase to avoid busy loop");
+ p2p_dbg(p2p, "Listen operation did not seem to start - delay search phase to avoid busy loop");
p2p_set_timeout(p2p, 0, 100000);
return 1;
}
if (p2p->search_delay) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
- "search operation by %u ms",
+ p2p_dbg(p2p, "Delay search operation by %u ms",
p2p->search_delay);
p2p_set_timeout(p2p, p2p->search_delay / 1000,
(p2p->search_delay % 1000) * 1000);
@@ -3103,10 +3760,21 @@ static void p2p_timeout_connect(struct p2p_data *p2p)
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (p2p->go_neg_peer &&
(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Wait for GO "
- "Negotiation Confirm timed out - assume GO "
- "Negotiation failed");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
+ p2p_go_neg_failed(p2p, -1);
+ return;
+ }
+ if (p2p->go_neg_peer &&
+ (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) &&
+ p2p->go_neg_peer->connect_reqs < 120) {
+ p2p_dbg(p2p, "Peer expected to wait our response - skip listen");
+ p2p_connect_send(p2p, p2p->go_neg_peer);
+ return;
+ }
+ if (p2p->go_neg_peer && p2p->go_neg_peer->oob_go_neg_freq > 0) {
+ p2p_dbg(p2p, "Skip connect-listen since GO Neg channel known (OOB)");
+ p2p_set_state(p2p, P2P_CONNECT_LISTEN);
+ p2p_set_timeout(p2p, 0, 30000);
return;
}
p2p_set_state(p2p, P2P_CONNECT_LISTEN);
@@ -3118,17 +3786,13 @@ static void p2p_timeout_connect_listen(struct p2p_data *p2p)
{
if (p2p->go_neg_peer) {
if (p2p->drv_in_listen) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is "
- "still in Listen state; wait for it to "
- "complete");
+ p2p_dbg(p2p, "Driver is still in Listen state; wait for it to complete");
return;
}
if (p2p->go_neg_peer->connect_reqs >= 120) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Timeout on sending GO Negotiation "
- "Request without getting response");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
+ p2p_go_neg_failed(p2p, -1);
return;
}
@@ -3141,13 +3805,13 @@ static void p2p_timeout_connect_listen(struct p2p_data *p2p)
static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
{
- /*
- * TODO: could remain constantly in Listen state for some time if there
- * are no other concurrent uses for the radio. For now, go to listen
- * state once per second to give other uses a chance to use the radio.
- */
p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
- p2p_set_timeout(p2p, 0, 500000);
+
+ if (p2p->cfg->is_concurrent_session_active &&
+ p2p->cfg->is_concurrent_session_active(p2p->cfg->cb_ctx))
+ p2p_set_timeout(p2p, 0, 500000);
+ else
+ p2p_set_timeout(p2p, 0, 200000);
}
@@ -3156,23 +3820,11 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
struct p2p_device *dev = p2p->go_neg_peer;
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown GO Neg peer - stop GO Neg wait");
+ p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
return;
}
- dev->wait_count++;
- if (dev->wait_count >= 120) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Timeout on waiting peer to become ready for GO "
- "Negotiation");
- p2p_go_neg_failed(p2p, dev, -1);
- return;
- }
-
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Go to Listen state while waiting for the peer to become "
- "ready for GO Negotiation");
+ p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
p2p_listen_in_find(p2p, 0);
}
@@ -3180,11 +3832,9 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery Query timeout");
+ p2p_dbg(p2p, "Service Discovery Query timeout");
if (p2p->sd_peer) {
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
p2p->sd_peer = NULL;
}
p2p_continue_find(p2p);
@@ -3193,8 +3843,7 @@ static void p2p_timeout_sd_during_find(struct p2p_data *p2p)
static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request timeout");
+ p2p_dbg(p2p, "Provision Discovery Request timeout");
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_continue_find(p2p);
}
@@ -3202,6 +3851,9 @@ static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
{
+ u32 adv_id = 0;
+ u8 *adv_mac = NULL;
+
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
/*
@@ -3212,8 +3864,7 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
if (!p2p->user_initiated_pd)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: User initiated Provision Discovery Request timeout");
+ p2p_dbg(p2p, "User initiated Provision Discovery Request timeout");
if (p2p->pd_retries) {
p2p->pd_retries--;
@@ -3231,12 +3882,18 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
for_join = 1;
}
+ if (p2p->p2ps_prov) {
+ adv_id = p2p->p2ps_prov->adv_id;
+ adv_mac = p2p->p2ps_prov->adv_mac;
+ }
+
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
p2p->pending_pd_devaddr,
for_join ?
P2P_PROV_DISC_TIMEOUT_JOIN :
- P2P_PROV_DISC_TIMEOUT);
+ P2P_PROV_DISC_TIMEOUT,
+ adv_id, adv_mac, NULL);
p2p_reset_pending_pd(p2p);
}
}
@@ -3251,8 +3908,7 @@ static void p2p_timeout_invite(struct p2p_data *p2p)
* Better remain on operating channel instead of listen channel
* when running a group.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Inviting in "
- "active GO role - wait on operating channel");
+ p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel");
p2p_set_timeout(p2p, 0, 100000);
return;
}
@@ -3265,14 +3921,15 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p)
if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) {
p2p_set_state(p2p, P2P_INVITE);
p2p_invite_send(p2p, p2p->invite_peer,
- p2p->invite_go_dev_addr);
+ p2p->invite_go_dev_addr, p2p->invite_dev_pw_id);
} else {
if (p2p->invite_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request retry limit reached");
+ p2p_dbg(p2p, "Invitation Request retry limit reached");
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(
- p2p->cfg->cb_ctx, -1, NULL);
+ p2p->cfg->cb_ctx, -1, NULL, NULL,
+ p2p->invite_peer->info.p2p_device_addr,
+ 0, 0);
}
p2p_set_state(p2p, P2P_IDLE);
}
@@ -3283,10 +3940,13 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct p2p_data *p2p = eloop_ctx;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Timeout (state=%s)",
- p2p_state_txt(p2p->state));
+ p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
p2p->in_listen = 0;
+ if (p2p->drv_in_listen) {
+ p2p_dbg(p2p, "Driver is still in listen state - stop it");
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ }
switch (p2p->state) {
case P2P_IDLE:
@@ -3299,8 +3959,7 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
if (p2p->pending_action_state == P2P_PENDING_PD)
p2p_timeout_prov_disc_req(p2p);
if (p2p->search_delay && !p2p->in_search_delay) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
- "search operation by %u ms",
+ p2p_dbg(p2p, "Delay search operation by %u ms",
p2p->search_delay);
p2p->in_search_delay = 1;
p2p_set_timeout(p2p, p2p->search_delay / 1000,
@@ -3324,9 +3983,7 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
p2p_timeout_prov_disc_req(p2p);
if (p2p->ext_listen_only) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Extended Listen Timing - Listen State "
- "completed");
+ p2p_dbg(p2p, "Extended Listen Timing - Listen State completed");
p2p->ext_listen_only = 0;
p2p_set_state(p2p, P2P_IDLE);
}
@@ -3351,10 +4008,6 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
case P2P_INVITE_LISTEN:
p2p_timeout_invite_listen(p2p);
break;
- case P2P_SEARCH_WHEN_READY:
- break;
- case P2P_CONTINUE_SEARCH_WHEN_READY:
- break;
}
}
@@ -3364,11 +4017,10 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr)
struct p2p_device *dev;
dev = p2p_get_device(p2p, peer_addr);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Local request to reject "
- "connection attempts by peer " MACSTR, MAC2STR(peer_addr));
+ p2p_dbg(p2p, "Local request to reject connection attempts by peer "
+ MACSTR, MAC2STR(peer_addr));
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
- " unknown", MAC2STR(peer_addr));
+ p2p_dbg(p2p, "Peer " MACSTR " unknown", MAC2STR(peer_addr));
return -1;
}
dev->status = P2P_SC_FAIL_REJECTED_BY_USER;
@@ -3388,6 +4040,10 @@ const char * p2p_wps_method_text(enum p2p_wps_method method)
return "Keypad";
case WPS_PBC:
return "PBC";
+ case WPS_NFC:
+ return "NFC";
+ case WPS_P2PS:
+ return "P2PS";
}
return "??";
@@ -3438,7 +4094,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
struct p2p_device *dev;
int res;
char *pos, *end;
- struct os_time now;
+ struct os_reltime now;
if (info == NULL)
return -1;
@@ -3449,7 +4105,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
pos = buf;
end = buf + buflen;
- os_get_time(&now);
+ os_get_reltime(&now);
res = os_snprintf(pos, end - pos,
"age=%d\n"
"listen_freq=%d\n"
@@ -3464,9 +4120,8 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"country=%c%c\n"
"oper_freq=%d\n"
"req_config_methods=0x%x\n"
- "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+ "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
"status=%d\n"
- "wait_count=%u\n"
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
dev->listen_freq,
@@ -3487,13 +4142,12 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
dev->flags & P2P_DEV_REPORTED ? "[REPORTED]" : "",
dev->flags & P2P_DEV_NOT_YET_READY ?
"[NOT_YET_READY]" : "",
- dev->flags & P2P_DEV_SD_INFO ? "[SD_INFO]" : "",
- dev->flags & P2P_DEV_SD_SCHEDULE ? "[SD_SCHEDULE]" :
- "",
dev->flags & P2P_DEV_PD_PEER_DISPLAY ?
"[PD_PEER_DISPLAY]" : "",
dev->flags & P2P_DEV_PD_PEER_KEYPAD ?
"[PD_PEER_KEYPAD]" : "",
+ dev->flags & P2P_DEV_PD_PEER_P2PS ?
+ "[PD_PEER_P2PS]" : "",
dev->flags & P2P_DEV_USER_REJECTED ?
"[USER_REJECTED]" : "",
dev->flags & P2P_DEV_PEER_WAITING_RESPONSE ?
@@ -3511,9 +4165,8 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
dev->flags & P2P_DEV_PD_FOR_JOIN ?
"[PD_FOR_JOIN]" : "",
dev->status,
- dev->wait_count,
dev->invitation_reqs);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -3523,7 +4176,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"ext_listen_interval=%u\n",
dev->ext_listen_period,
dev->ext_listen_interval);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -3533,7 +4186,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"oper_ssid=%s\n",
wpa_ssid_txt(dev->oper_ssid,
dev->oper_ssid_len));
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -3541,7 +4194,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
#ifdef CONFIG_WIFI_DISPLAY
if (dev->info.wfd_subelems) {
res = os_snprintf(pos, end - pos, "wfd_subelems=");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -3550,7 +4203,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
wpabuf_len(dev->info.wfd_subelems));
res = os_snprintf(pos, end - pos, "\n");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -3569,12 +4222,10 @@ int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
{
if (enabled) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
- "discoverability enabled");
+ p2p_dbg(p2p, "Client discoverability enabled");
p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client "
- "discoverability disabled");
+ p2p_dbg(p2p, "Client discoverability disabled");
p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
}
}
@@ -3623,9 +4274,9 @@ int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
{
struct wpabuf *req;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send Presence Request to "
- "GO " MACSTR " (own interface " MACSTR ") freq=%u dur1=%u "
- "int1=%u dur2=%u int2=%u",
+ p2p_dbg(p2p, "Send Presence Request to GO " MACSTR
+ " (own interface " MACSTR ") freq=%u dur1=%u int1=%u "
+ "dur2=%u int2=%u",
MAC2STR(go_interface_addr), MAC2STR(own_interface_addr),
freq, duration1, interval1, duration2, interval2);
@@ -3638,8 +4289,7 @@ int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
if (p2p_send_action(p2p, freq, go_interface_addr, own_interface_addr,
go_interface_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(req);
@@ -3685,8 +4335,7 @@ static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
u8 noa[50];
int noa_len;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - P2P Presence Request");
+ p2p_dbg(p2p, "Received P2P Action - P2P Presence Request");
for (g = 0; g < p2p->num_groups; g++) {
if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]),
@@ -3696,23 +4345,20 @@ static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
}
}
if (group == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore P2P Presence Request for unknown group "
+ p2p_dbg(p2p, "Ignore P2P Presence Request for unknown group "
MACSTR, MAC2STR(da));
return;
}
if (p2p_parse(data, len, &msg) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to parse P2P Presence Request");
+ p2p_dbg(p2p, "Failed to parse P2P Presence Request");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
parsed = 1;
if (msg.noa == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No NoA attribute in P2P Presence Request");
+ p2p_dbg(p2p, "No NoA attribute in P2P Presence Request");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
@@ -3736,8 +4382,7 @@ fail:
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, rx_freq, sa, da, da,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(resp);
}
@@ -3748,33 +4393,32 @@ static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da,
{
struct p2p_message msg;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received P2P Action - P2P Presence Response");
+ p2p_dbg(p2p, "Received P2P Action - P2P Presence Response");
if (p2p_parse(data, len, &msg) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to parse P2P Presence Response");
+ p2p_dbg(p2p, "Failed to parse P2P Presence Response");
return;
}
if (msg.status == NULL || msg.noa == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Status or NoA attribute in P2P Presence "
- "Response");
+ p2p_dbg(p2p, "No Status or NoA attribute in P2P Presence Response");
p2p_parse_free(&msg);
return;
}
+ if (p2p->cfg->presence_resp) {
+ p2p->cfg->presence_resp(p2p->cfg->cb_ctx, sa, *msg.status,
+ msg.noa, msg.noa_len);
+ }
+
if (*msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: P2P Presence Request was rejected: status %u",
+ p2p_dbg(p2p, "P2P Presence Request was rejected: status %u",
*msg.status);
p2p_parse_free(&msg);
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: P2P Presence Request was accepted");
+ p2p_dbg(p2p, "P2P Presence Request was accepted");
wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA",
msg.noa, msg.noa_len);
/* TODO: process NoA */
@@ -3793,6 +4437,15 @@ static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx)
p2p_ext_listen_timeout, p2p, NULL);
}
+ if ((p2p->cfg->is_p2p_in_progress &&
+ p2p->cfg->is_p2p_in_progress(p2p->cfg->cb_ctx)) ||
+ (p2p->pending_action_state == P2P_PENDING_PD &&
+ p2p->pd_retries > 0)) {
+ p2p_dbg(p2p, "Operation in progress - skip Extended Listen timeout (%s)",
+ p2p_state_txt(p2p->state));
+ return;
+ }
+
if (p2p->state == P2P_LISTEN_ONLY && p2p->ext_listen_only) {
/*
* This should not really happen, but it looks like the Listen
@@ -3800,25 +4453,20 @@ static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx)
* running at an inconvenient time. As a workaround, allow new
* Extended Listen operation to be started.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Previous "
- "Extended Listen operation had not been completed - "
- "try again");
+ p2p_dbg(p2p, "Previous Extended Listen operation had not been completed - try again");
p2p->ext_listen_only = 0;
p2p_set_state(p2p, P2P_IDLE);
}
if (p2p->state != P2P_IDLE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip Extended "
- "Listen timeout in active state (%s)",
- p2p_state_txt(p2p->state));
+ p2p_dbg(p2p, "Skip Extended Listen timeout in active state (%s)", p2p_state_txt(p2p->state));
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Extended Listen timeout");
+ p2p_dbg(p2p, "Extended Listen timeout");
p2p->ext_listen_only = 1;
if (p2p_listen(p2p, p2p->ext_listen_period) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
- "Listen state for Extended Listen Timing");
+ p2p_dbg(p2p, "Failed to start Listen state for Extended Listen Timing");
p2p->ext_listen_only = 0;
}
}
@@ -3829,25 +4477,22 @@ int p2p_ext_listen(struct p2p_data *p2p, unsigned int period,
{
if (period > 65535 || interval > 65535 || period > interval ||
(period == 0 && interval > 0) || (period > 0 && interval == 0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid Extended Listen Timing request: "
- "period=%u interval=%u", period, interval);
+ p2p_dbg(p2p, "Invalid Extended Listen Timing request: period=%u interval=%u",
+ period, interval);
return -1;
}
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
if (interval == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Disabling Extended Listen Timing");
+ p2p_dbg(p2p, "Disabling Extended Listen Timing");
p2p->ext_listen_period = 0;
p2p->ext_listen_interval = 0;
return 0;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Enabling Extended Listen Timing: period %u msec, "
- "interval %u msec", period, interval);
+ p2p_dbg(p2p, "Enabling Extended Listen Timing: period %u msec, interval %u msec",
+ period, interval);
p2p->ext_listen_period = period;
p2p->ext_listen_interval = interval;
p2p->ext_listen_interval_sec = interval / 1000;
@@ -3872,11 +4517,12 @@ void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ie, ie_len, &msg))
return;
- if (msg.minor_reason_code == NULL)
+ if (msg.minor_reason_code == NULL) {
+ p2p_parse_free(&msg);
return;
+ }
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Deauthentication notification BSSID " MACSTR
+ p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR
" reason_code=%u minor_reason_code=%u",
MAC2STR(bssid), reason_code, *msg.minor_reason_code);
@@ -3895,11 +4541,12 @@ void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ie, ie_len, &msg))
return;
- if (msg.minor_reason_code == NULL)
+ if (msg.minor_reason_code == NULL) {
+ p2p_parse_free(&msg);
return;
+ }
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Disassociation notification BSSID " MACSTR
+ p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR
" reason_code=%u minor_reason_code=%u",
MAC2STR(bssid), reason_code, *msg.minor_reason_code);
@@ -3910,34 +4557,65 @@ void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
{
if (enabled) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
- "Device operations enabled");
+ p2p_dbg(p2p, "Managed P2P Device operations enabled");
p2p->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED;
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P "
- "Device operations disabled");
+ p2p_dbg(p2p, "Managed P2P Device operations disabled");
p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED;
}
}
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel)
{
- if (p2p_channel_to_freq(p2p->cfg->country, reg_class, channel) < 0)
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+}
+
+
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced)
+{
+ if (p2p_channel_to_freq(reg_class, channel) < 0)
+ return -1;
+
+ /*
+ * Listen channel was set in configuration or set by control interface;
+ * cannot override it.
+ */
+ if (p2p->cfg->channel_forced && forced == 0) {
+ p2p_dbg(p2p,
+ "Listen channel was previously configured - do not override based on optimization");
return -1;
+ }
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: "
- "reg_class %u channel %u", reg_class, channel);
- p2p->cfg->reg_class = reg_class;
- p2p->cfg->channel = channel;
+ p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
+ reg_class, channel);
+
+ if (p2p->state == P2P_IDLE) {
+ p2p->cfg->reg_class = reg_class;
+ p2p->cfg->channel = channel;
+ p2p->cfg->channel_forced = forced;
+ } else {
+ p2p_dbg(p2p, "Defer setting listen channel");
+ p2p->pending_reg_class = reg_class;
+ p2p->pending_channel = channel;
+ p2p->pending_channel_forced = forced;
+ }
return 0;
}
+u8 p2p_get_listen_channel(struct p2p_data *p2p)
+{
+ return p2p->cfg->channel;
+}
+
+
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
{
- wpa_hexdump_ascii(MSG_DEBUG, "P2P: New SSID postfix", postfix, len);
+ p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
if (postfix == NULL) {
p2p->cfg->ssid_postfix_len = 0;
return 0;
@@ -3953,12 +4631,11 @@ int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
int cfg_op_channel)
{
- if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
- < 0)
+ if (p2p_channel_to_freq(op_reg_class, op_channel) < 0)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
- "reg_class %u channel %u", op_reg_class, op_channel);
+ p2p_dbg(p2p, "Set Operating channel: reg_class %u channel %u",
+ op_reg_class, op_channel);
p2p->cfg->op_reg_class = op_reg_class;
p2p->cfg->op_channel = op_channel;
p2p->cfg->cfg_op_channel = cfg_op_channel;
@@ -3988,6 +4665,31 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
}
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list)
+{
+ struct wpa_freq_range *tmp;
+
+ if (list == NULL || list->num == 0) {
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = NULL;
+ p2p->no_go_freq.num = 0;
+ return 0;
+ }
+
+ tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
+ if (tmp == NULL)
+ return -1;
+ os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = tmp;
+ p2p->no_go_freq.num = list->num;
+ p2p_dbg(p2p, "Updated no GO chan list");
+
+ return 0;
+}
+
+
int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
@@ -4014,18 +4716,16 @@ void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr)
{
os_memcpy(p2p->peer_filter, addr, ETH_ALEN);
if (is_zero_ether_addr(p2p->peer_filter))
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Disable peer "
- "filter");
+ p2p_dbg(p2p, "Disable peer filter");
else
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Enable peer "
- "filter for " MACSTR, MAC2STR(p2p->peer_filter));
+ p2p_dbg(p2p, "Enable peer filter for " MACSTR,
+ MAC2STR(p2p->peer_filter));
}
void p2p_set_cross_connect(struct p2p_data *p2p, int enabled)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Cross connection %s",
- enabled ? "enabled" : "disabled");
+ p2p_dbg(p2p, "Cross connection %s", enabled ? "enabled" : "disabled");
if (p2p->cross_connect == enabled)
return;
p2p->cross_connect = enabled;
@@ -4046,16 +4746,22 @@ int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr)
void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Intra BSS distribution %s",
+ p2p_dbg(p2p, "Intra BSS distribution %s",
enabled ? "enabled" : "disabled");
p2p->cfg->p2p_intra_bss = enabled;
}
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update channel list");
+ p2p_dbg(p2p, "Update channel list");
os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ os_memcpy(&p2p->cfg->cli_channels, cli_chan,
+ sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
}
@@ -4064,11 +4770,9 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
size_t len, unsigned int wait_time)
{
if (p2p->p2p_scan_running) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay Action "
- "frame TX until p2p_scan completes");
+ p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
if (p2p->after_scan_tx) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped "
- "previous pending Action frame TX");
+ p2p_dbg(p2p, "Dropped previous pending Action frame TX");
os_free(p2p->after_scan_tx);
}
p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) +
@@ -4093,14 +4797,21 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
int freq_overall)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Best channel: 2.4 GHz: %d,"
- " 5 GHz: %d, overall: %d", freq_24, freq_5, freq_overall);
+ p2p_dbg(p2p, "Best channel: 2.4 GHz: %d, 5 GHz: %d, overall: %d",
+ freq_24, freq_5, freq_overall);
p2p->best_freq_24 = freq_24;
p2p->best_freq_5 = freq_5;
p2p->best_freq_overall = freq_overall;
}
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq)
+{
+ p2p_dbg(p2p, "Own frequency preference: %d MHz", freq);
+ p2p->own_freq_preference = freq;
+}
+
+
const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p)
{
if (p2p == NULL || p2p->go_neg_peer == NULL)
@@ -4129,7 +4840,7 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
dev = dl_list_first(&dev->list,
struct p2p_device,
list);
- if (&dev->list == &p2p->devices)
+ if (!dev || &dev->list == &p2p->devices)
return NULL;
} while (dev->flags & P2P_DEV_PROBE_REQ_ONLY);
}
@@ -4141,7 +4852,7 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
dev = dl_list_first(&dev->list,
struct p2p_device,
list);
- if (&dev->list == &p2p->devices)
+ if (!dev || &dev->list == &p2p->devices)
return NULL;
}
}
@@ -4154,8 +4865,7 @@ int p2p_in_progress(struct p2p_data *p2p)
{
if (p2p == NULL)
return 0;
- if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY ||
- p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY)
+ if (p2p->state == P2P_SEARCH)
return 2;
return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
}
@@ -4171,13 +4881,6 @@ void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
}
-void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
-{
- if (p2p && p2p->search_delay < delay)
- p2p->search_delay = delay;
-}
-
-
#ifdef CONFIG_WIFI_DISPLAY
static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
@@ -4187,7 +4890,7 @@ static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
for (g = 0; g < p2p->num_groups; g++) {
group = p2p->groups[g];
- p2p_group_update_ies(group);
+ p2p_group_force_beacon_update_ies(group);
}
}
@@ -4312,9 +5015,322 @@ int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
p2p->min_disc_int = min_disc_int;
p2p->max_disc_int = max_disc_int;
p2p->max_disc_tu = max_disc_tu;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set discoverable interval: "
- "min=%d max=%d max_tu=%d", min_disc_int, max_disc_int,
- max_disc_tu);
+ p2p_dbg(p2p, "Set discoverable interval: min=%d max=%d max_tu=%d",
+ min_disc_int, max_disc_int, max_disc_tu);
return 0;
}
+
+
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[500];
+
+ if (!p2p->cfg->debug_print)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+ va_end(ap);
+ p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_DEBUG, buf);
+}
+
+
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[500];
+
+ if (!p2p->cfg->debug_print)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+ va_end(ap);
+ p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_INFO, buf);
+}
+
+
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[500];
+
+ if (!p2p->cfg->debug_print)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+ va_end(ap);
+ p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf);
+}
+
+
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data)
+{
+ struct p2p_device *dev, *n;
+
+ dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
+ peer_callback(&dev->info, user_data);
+ }
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ struct wpabuf *buf;
+ u8 op_class, channel;
+ enum p2p_role_indication role = P2P_DEVICE_NOT_IN_GROUP;
+
+ buf = wpabuf_alloc(1000);
+ if (buf == NULL)
+ return NULL;
+
+ op_class = p2p->cfg->reg_class;
+ channel = p2p->cfg->channel;
+
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+ p2p_buf_add_device_info(buf, p2p, NULL);
+
+ if (p2p->num_groups > 0) {
+ int freq = p2p_group_get_freq(p2p->groups[0]);
+ role = P2P_GO_IN_A_GROUP;
+ if (p2p_freq_to_channel(freq, &op_class, &channel) < 0) {
+ p2p_dbg(p2p,
+ "Unknown GO operating frequency %d MHz for NFC handover",
+ freq);
+ wpabuf_free(buf);
+ return NULL;
+ }
+ } else if (client_freq > 0) {
+ role = P2P_CLIENT_IN_A_GROUP;
+ if (p2p_freq_to_channel(client_freq, &op_class, &channel) < 0) {
+ p2p_dbg(p2p,
+ "Unknown client operating frequency %d MHz for NFC handover",
+ client_freq);
+ wpabuf_free(buf);
+ return NULL;
+ }
+ }
+
+ p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class,
+ channel, role);
+
+ if (p2p->num_groups > 0) {
+ /* Limit number of clients to avoid very long message */
+ p2p_buf_add_group_info(p2p->groups[0], buf, 5);
+ p2p_group_buf_add_id(p2p->groups[0], buf);
+ } else if (client_freq > 0 &&
+ go_dev_addr && !is_zero_ether_addr(go_dev_addr) &&
+ ssid && ssid_len > 0) {
+ /*
+ * Add the optional P2P Group ID to indicate in which group this
+ * device is a P2P Client.
+ */
+ p2p_buf_add_group_id(buf, go_dev_addr, ssid, ssid_len);
+ }
+
+ return buf;
+}
+
+
+struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
+ ssid_len);
+}
+
+
+struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
+ ssid_len);
+}
+
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+ struct p2p_nfc_params *params)
+{
+ struct p2p_message msg;
+ struct p2p_device *dev;
+ const u8 *p2p_dev_addr;
+ int freq;
+ enum p2p_role_indication role;
+
+ params->next_step = NO_ACTION;
+
+ if (p2p_parse_ies_separate(params->wsc_attr, params->wsc_len,
+ params->p2p_attr, params->p2p_len, &msg)) {
+ p2p_dbg(p2p, "Failed to parse WSC/P2P attributes from NFC");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.p2p_device_addr)
+ p2p_dev_addr = msg.p2p_device_addr;
+ else if (msg.device_id)
+ p2p_dev_addr = msg.device_id;
+ else {
+ p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.oob_dev_password) {
+ os_memcpy(params->oob_dev_pw, msg.oob_dev_password,
+ msg.oob_dev_password_len);
+ params->oob_dev_pw_len = msg.oob_dev_password_len;
+ }
+
+ dev = p2p_create_device(p2p, p2p_dev_addr);
+ if (dev == NULL) {
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ params->peer = &dev->info;
+
+ os_get_reltime(&dev->last_seen);
+ dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
+ p2p_copy_wps_info(p2p, dev, 0, &msg);
+
+ if (!msg.oob_go_neg_channel) {
+ p2p_dbg(p2p, "OOB GO Negotiation Channel attribute not included");
+ return -1;
+ }
+
+ if (msg.oob_go_neg_channel[3] == 0 &&
+ msg.oob_go_neg_channel[4] == 0)
+ freq = 0;
+ else
+ freq = p2p_channel_to_freq(msg.oob_go_neg_channel[3],
+ msg.oob_go_neg_channel[4]);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
+ return -1;
+ }
+ role = msg.oob_go_neg_channel[5];
+
+ if (role == P2P_GO_IN_A_GROUP) {
+ p2p_dbg(p2p, "Peer OOB GO operating channel: %u MHz", freq);
+ params->go_freq = freq;
+ } else if (role == P2P_CLIENT_IN_A_GROUP) {
+ p2p_dbg(p2p, "Peer (client) OOB GO operating channel: %u MHz",
+ freq);
+ params->go_freq = freq;
+ } else
+ p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq);
+ dev->oob_go_neg_freq = freq;
+
+ if (!params->sel && role != P2P_GO_IN_A_GROUP) {
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Own listen channel not known");
+ return -1;
+ }
+ p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz", freq);
+ dev->oob_go_neg_freq = freq;
+ }
+
+ if (msg.group_id) {
+ os_memcpy(params->go_dev_addr, msg.group_id, ETH_ALEN);
+ params->go_ssid_len = msg.group_id_len - ETH_ALEN;
+ os_memcpy(params->go_ssid, msg.group_id + ETH_ALEN,
+ params->go_ssid_len);
+ }
+
+ if (dev->flags & P2P_DEV_USER_REJECTED) {
+ p2p_dbg(p2p, "Do not report rejected device");
+ p2p_parse_free(&msg);
+ return 0;
+ }
+
+ if (!(dev->flags & P2P_DEV_REPORTED)) {
+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, p2p_dev_addr, &dev->info,
+ !(dev->flags & P2P_DEV_REPORTED_ONCE));
+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+ }
+ p2p_parse_free(&msg);
+
+ if (role == P2P_GO_IN_A_GROUP && p2p->num_groups > 0)
+ params->next_step = BOTH_GO;
+ else if (role == P2P_GO_IN_A_GROUP)
+ params->next_step = JOIN_GROUP;
+ else if (role == P2P_CLIENT_IN_A_GROUP) {
+ dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY;
+ params->next_step = PEER_CLIENT;
+ } else if (p2p->num_groups > 0)
+ params->next_step = AUTH_JOIN;
+ else if (params->sel)
+ params->next_step = INIT_GO_NEG;
+ else
+ params->next_step = RESP_GO_NEG;
+
+ return 0;
+}
+
+
+void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
+ int go_intent,
+ const u8 *own_interface_addr)
+{
+
+ p2p->authorized_oob_dev_pw_id = dev_pw_id;
+ if (dev_pw_id == 0) {
+ p2p_dbg(p2p, "NFC OOB Password unauthorized for static handover");
+ return;
+ }
+
+ p2p_dbg(p2p, "NFC OOB Password (id=%u) authorized for static handover",
+ dev_pw_id);
+
+ p2p->go_intent = go_intent;
+ os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len)
+{
+ if (len < 8 || len > 63)
+ return -1;
+ p2p->cfg->passphrase_len = len;
+ return 0;
+}
+
+
+void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem)
+{
+ p2p->vendor_elem = vendor_elem;
+}
+
+
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct p2p_data *p2p = eloop_ctx;
+
+ p2p_dbg(p2p,
+ "Timeout on waiting peer to become ready for GO Negotiation");
+ p2p_go_neg_failed(p2p, -1);
+}
diff --git a/contrib/wpa/src/p2p/p2p.h b/contrib/wpa/src/p2p/p2p.h
index 2d8b2c2..2402db6 100644
--- a/contrib/wpa/src/p2p/p2p.h
+++ b/contrib/wpa/src/p2p/p2p.h
@@ -9,6 +9,18 @@
#ifndef P2P_H
#define P2P_H
+#include "wps/wps_defs.h"
+
+/* P2P ASP Setup Capability */
+#define P2PS_SETUP_NONE 0
+#define P2PS_SETUP_NEW BIT(0)
+#define P2PS_SETUP_CLIENT BIT(1)
+#define P2PS_SETUP_GROUP_OWNER BIT(2)
+
+#define P2PS_WILD_HASH_STR "org.wi-fi.wfds"
+#define P2PS_HASH_LEN 6
+#define P2P_MAX_QUERY_HASH 6
+
/**
* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
*/
@@ -50,7 +62,8 @@ struct p2p_channels {
};
enum p2p_wps_method {
- WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+ WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC, WPS_NFC,
+ WPS_P2PS
};
/**
@@ -77,6 +90,8 @@ struct p2p_go_neg_results {
int ht40;
+ int vht;
+
/**
* ssid - SSID of the group
*/
@@ -138,11 +153,99 @@ struct p2p_go_neg_results {
unsigned int peer_config_timeout;
};
+struct p2ps_provision {
+ /**
+ * status - Remote returned provisioning status code
+ */
+ int status;
+
+ /**
+ * adv_id - P2PS Advertisement ID
+ */
+ u32 adv_id;
+
+ /**
+ * session_id - P2PS Session ID
+ */
+ u32 session_id;
+
+ /**
+ * method - WPS Method (to be) used to establish session
+ */
+ u16 method;
+
+ /**
+ * conncap - Connection Capabilities negotiated between P2P peers
+ */
+ u8 conncap;
+
+ /**
+ * role - Info about the roles to be used for this connection
+ */
+ u8 role;
+
+ /**
+ * session_mac - MAC address of the peer that started the session
+ */
+ u8 session_mac[ETH_ALEN];
+
+ /**
+ * adv_mac - MAC address of the peer advertised the service
+ */
+ u8 adv_mac[ETH_ALEN];
+
+ /**
+ * info - Vendor defined extra Provisioning information
+ */
+ char info[0];
+};
+
+struct p2ps_advertisement {
+ struct p2ps_advertisement *next;
+
+ /**
+ * svc_info - Pointer to (internal) Service defined information
+ */
+ char *svc_info;
+
+ /**
+ * id - P2PS Advertisement ID
+ */
+ u32 id;
+
+ /**
+ * config_methods - WPS Methods which are allowed for this service
+ */
+ u16 config_methods;
+
+ /**
+ * state - Current state of the service: 0 - Out Of Service, 1-255 Vendor defined
+ */
+ u8 state;
+
+ /**
+ * auto_accept - Automatically Accept provisioning request if possible.
+ */
+ u8 auto_accept;
+
+ /**
+ * hash - 6 octet Service Name has to match against incoming Probe Requests
+ */
+ u8 hash[P2PS_HASH_LEN];
+
+ /**
+ * svc_name - NULL Terminated UTF-8 Service Name, and svc_info storage
+ */
+ char svc_name[0];
+};
+
+
struct p2p_data;
enum p2p_scan_type {
P2P_SCAN_SOCIAL,
P2P_SCAN_FULL,
+ P2P_SCAN_SPECIFIC,
P2P_SCAN_SOCIAL_PLUS_ONE
};
@@ -226,6 +329,19 @@ struct p2p_peer_info {
* wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
*/
struct wpabuf *wfd_subelems;
+
+ /**
+ * vendor_elems - Unrecognized vendor elements
+ *
+ * This buffer includes any other vendor element than P2P, WPS, and WFD
+ * IE(s) from the frame that was used to discover the peer.
+ */
+ struct wpabuf *vendor_elems;
+
+ /**
+ * p2ps_instance - P2PS Application Service Info
+ */
+ struct wpabuf *p2ps_instance;
};
enum p2p_prov_disc_status {
@@ -233,6 +349,7 @@ enum p2p_prov_disc_status {
P2P_PROV_DISC_TIMEOUT,
P2P_PROV_DISC_REJECTED,
P2P_PROV_DISC_TIMEOUT_JOIN,
+ P2P_PROV_DISC_INFO_UNAVAILABLE,
};
struct p2p_channel {
@@ -263,6 +380,12 @@ struct p2p_config {
u8 channel;
/**
+ * channel_forced - the listen channel was forced by configuration
+ * or by control interface and cannot be overridden
+ */
+ u8 channel_forced;
+
+ /**
* Regulatory class for own operational channel
*/
u8 op_reg_class;
@@ -287,6 +410,20 @@ struct p2p_config {
struct p2p_channels channels;
/**
+ * cli_channels - Additional client channels
+ *
+ * This list of channels (if any) will be used when advertising local
+ * channels during GO Negotiation or Invitation for the cases where the
+ * local end may become the client. This may allow the peer to become a
+ * GO on additional channels if it supports these options. The main use
+ * case for this is to include passive-scan channels on devices that may
+ * not know their current location and have configured most channels to
+ * not allow initiation of radition (i.e., another device needs to take
+ * master responsibilities).
+ */
+ struct p2p_channels cli_channels;
+
+ /**
* num_pref_chan - Number of pref_chan entries
*/
unsigned int num_pref_chan;
@@ -371,15 +508,26 @@ struct p2p_config {
unsigned int max_listen;
/**
- * msg_ctx - Context to use with wpa_msg() calls
+ * passphrase_len - Passphrase length (8..63)
+ *
+ * This parameter controls the length of the random passphrase that is
+ * generated at the GO.
*/
- void *msg_ctx;
+ unsigned int passphrase_len;
/**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
+ /**
+ * debug_print - Debug print
+ * @ctx: Callback context from cb_ctx
+ * @level: Debug verbosity level (MSG_*)
+ * @msg: Debug message
+ */
+ void (*debug_print)(void *ctx, int level, const char *msg);
+
/* Callbacks to request lower layer driver operations */
@@ -398,7 +546,8 @@ struct p2p_config {
* operation to be completed. Type type argument specifies which type
* of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
* social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
- * indicates that all channels are to be scanned.
+ * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC
+ * request a scan of a single channel specified by freq.
* @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
* plus one extra channel specified by freq.
*
@@ -545,6 +694,12 @@ struct p2p_config {
void (*dev_lost)(void *ctx, const u8 *dev_addr);
/**
+ * find_stopped - Notification of a p2p_find operation stopping
+ * @ctx: Callback context from cb_ctx
+ */
+ void (*find_stopped)(void *ctx);
+
+ /**
* go_neg_req_rx - Notification of a receive GO Negotiation Request
* @ctx: Callback context from cb_ctx
* @src: Source address of the message triggering this notification
@@ -656,6 +811,9 @@ struct p2p_config {
* @ctx: Callback context from cb_ctx
* @peer: Source address of the response
* @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+ * @adv_id: If non-zero, then the adv_id of the PD Request
+ * @adv_mac: P2P Device Address of the advertizer
+ * @deferred_session_resp: Deferred session response sent by advertizer
*
* This callback is used to indicate either a failure or no response
* to an earlier provision discovery request.
@@ -664,7 +822,9 @@ struct p2p_config {
* is not used or failures do not need to be indicated.
*/
void (*prov_disc_fail)(void *ctx, const u8 *peer,
- enum p2p_prov_disc_status status);
+ enum p2p_prov_disc_status status,
+ u32 adv_id, const u8 *adv_mac,
+ const char *deferred_session_resp);
/**
* invitation_process - Optional callback for processing Invitations
@@ -680,6 +840,9 @@ struct p2p_config {
* @persistent_group: Whether this is an invitation to reinvoke a
* persistent group (instead of invitation to join an active
* group)
+ * @channels: Available operating channels for the group
+ * @dev_pw_id: Device Password ID for NFC static handover or -1 if not
+ * used
* Returns: Status code (P2P_SC_*)
*
* This optional callback can be used to implement persistent reconnect
@@ -700,7 +863,9 @@ struct p2p_config {
u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group);
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels,
+ int dev_pw_id);
/**
* invitation_received - Callback on Invitation Request RX
@@ -729,6 +894,11 @@ struct p2p_config {
* @ctx: Callback context from cb_ctx
* @status: Negotiation result (Status Code)
* @bssid: P2P Group BSSID or %NULL if not received
+ * @channels: Available operating channels for the group
+ * @addr: Peer address
+ * @freq: Frequency (in MHz) indicated during invitation or 0
+ * @peer_oper_freq: Operating frequency (in MHz) advertized by the peer
+ * during invitation or 0
*
* This callback is used to indicate result of an Invitation procedure
* started with a call to p2p_invite(). The indicated status code is
@@ -736,7 +906,9 @@ struct p2p_config {
* (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a
* local failure in transmitting the Invitation Request.
*/
- void (*invitation_result)(void *ctx, int status, const u8 *bssid);
+ void (*invitation_result)(void *ctx, int status, const u8 *bssid,
+ const struct p2p_channels *channels,
+ const u8 *addr, int freq, int peer_oper_freq);
/**
* go_connected - Check whether we are connected to a GO
@@ -746,6 +918,111 @@ struct p2p_config {
* or 0 if not.
*/
int (*go_connected)(void *ctx, const u8 *dev_addr);
+
+ /**
+ * presence_resp - Callback on Presence Response
+ * @ctx: Callback context from cb_ctx
+ * @src: Source address (GO's P2P Interface Address)
+ * @status: Result of the request (P2P_SC_*)
+ * @noa: Returned NoA value
+ * @noa_len: Length of the NoA buffer in octets
+ */
+ void (*presence_resp)(void *ctx, const u8 *src, u8 status,
+ const u8 *noa, size_t noa_len);
+
+ /**
+ * is_concurrent_session_active - Check whether concurrent session is
+ * active on other virtual interfaces
+ * @ctx: Callback context from cb_ctx
+ * Returns: 1 if concurrent session is active on other virtual interface
+ * or 0 if not.
+ */
+ int (*is_concurrent_session_active)(void *ctx);
+
+ /**
+ * is_p2p_in_progress - Check whether P2P operation is in progress
+ * @ctx: Callback context from cb_ctx
+ * Returns: 1 if P2P operation (e.g., group formation) is in progress
+ * or 0 if not.
+ */
+ int (*is_p2p_in_progress)(void *ctx);
+
+ /**
+ * Determine if we have a persistent group we share with remote peer
+ * @ctx: Callback context from cb_ctx
+ * @addr: Peer device address to search for
+ * @ssid: Persistent group SSID or %NULL if any
+ * @ssid_len: Length of @ssid
+ * @go_dev_addr: Buffer for returning intended GO P2P Device Address
+ * @ret_ssid: Buffer for returning group SSID
+ * @ret_ssid_len: Buffer for returning length of @ssid
+ * Returns: 1 if a matching persistent group was found, 0 otherwise
+ */
+ int (*get_persistent_group)(void *ctx, const u8 *addr, const u8 *ssid,
+ size_t ssid_len, u8 *go_dev_addr,
+ u8 *ret_ssid, size_t *ret_ssid_len);
+
+ /**
+ * Get information about a possible local GO role
+ * @ctx: Callback context from cb_ctx
+ * @intended_addr: Buffer for returning intended GO interface address
+ * @ssid: Buffer for returning group SSID
+ * @ssid_len: Buffer for returning length of @ssid
+ * @group_iface: Buffer for returning whether a separate group interface
+ * would be used
+ * Returns: 1 if GO info found, 0 otherwise
+ *
+ * This is used to compose New Group settings (SSID, and intended
+ * address) during P2PS provisioning if results of provisioning *might*
+ * 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);
+
+ /**
+ * remove_stale_groups - Remove stale P2PS groups
+ *
+ * Because P2PS stages *potential* GOs, and remote devices can remove
+ * credentials unilaterally, we need to make sure we don't let stale
+ * unusable groups build up.
+ */
+ int (*remove_stale_groups)(void *ctx, const u8 *peer, const u8 *go,
+ const u8 *ssid, size_t ssid_len);
+
+ /**
+ * p2ps_prov_complete - P2PS provisioning complete
+ *
+ * When P2PS provisioning completes (successfully or not) we must
+ * transmit all of the results to the upper layers.
+ */
+ void (*p2ps_prov_complete)(void *ctx, u8 status, const u8 *dev,
+ const u8 *adv_mac, const u8 *ses_mac,
+ const u8 *grp_mac, u32 adv_id, u32 ses_id,
+ u8 conncap, int passwd_id,
+ const u8 *persist_ssid,
+ size_t persist_ssid_size, int response_done,
+ int prov_start, const char *session_info);
+
+ /**
+ * prov_disc_resp_cb - Callback for indicating completion of PD Response
+ * @ctx: Callback context from cb_ctx
+ * Returns: 1 if operation was started, 0 otherwise
+ *
+ * This callback can be used to perform any pending actions after
+ * provisioning. It is mainly used for P2PS pending group creation.
+ */
+ int (*prov_disc_resp_cb)(void *ctx);
+
+ /**
+ * p2ps_group_capability - Determine group capability
+ *
+ * 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.
+ */
+ u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role);
};
@@ -852,12 +1129,26 @@ enum p2p_discovery_type {
* requested device types.
* @dev_id: Device ID to search for or %NULL to find all devices
* @search_delay: Extra delay in milliseconds between search iterations
+ * @seek_count: Number of ASP Service Strings in the seek_string array
+ * @seek_string: ASP Service Strings to query for in Probe Requests
+ * @freq: Requested first scan frequency (in MHz) to modify type ==
+ * P2P_FIND_START_WITH_FULL behavior. 0 = Use normal full scan.
+ * If p2p_find is already in progress, this parameter is ignored and full
+ * scan will be executed.
* Returns: 0 on success, -1 on failure
*/
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay);
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_count, const char **seek_string, int freq);
+
+/**
+ * p2p_notify_scan_trigger_status - Indicate scan trigger status
+ * @p2p: P2P module context from p2p_init()
+ * @status: 0 on success, -1 on failure
+ */
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status);
/**
* p2p_stop_find - Stop P2P Find (Device Discovery)
@@ -889,6 +1180,12 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq);
int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
/**
+ * p2p_stop_listen - Stop P2P Listen
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_stop_listen(struct p2p_data *p2p);
+
+/**
* p2p_connect - Start P2P group formation (GO negotiation)
* @p2p: P2P module context from p2p_init()
* @peer_addr: MAC address of the peer P2P client
@@ -914,7 +1211,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg, unsigned int pref_freq);
+ int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id);
/**
* p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -942,7 +1239,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- unsigned int pref_freq);
+ unsigned int pref_freq, u16 oob_pw_id);
/**
* p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -956,6 +1253,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
* p2p_prov_disc_req - Send Provision Discovery Request
* @p2p: P2P module context from p2p_init()
* @peer_addr: MAC address of the peer P2P client
+ * @p2ps_prov: Provisioning info for P2PS
* @config_methods: WPS Config Methods value (only one bit set)
* @join: Whether this is used by a client joining an active group
* @force_freq: Forced TX frequency for the frame (mainly for the join case)
@@ -971,7 +1269,8 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
* indicated with the p2p_config::prov_disc_resp() callback.
*/
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
- u16 config_methods, int join, int force_freq,
+ struct p2ps_provision *p2ps_prov, u16 config_methods,
+ int join, int force_freq,
int user_initiated_pd);
/**
@@ -1042,12 +1341,16 @@ enum p2p_invite_role {
* @force_freq: The only allowed channel frequency in MHz or 0
* @go_dev_addr: Forced GO Device Address or %NULL if none
* @persistent_group: Whether this is to reinvoke a persistent group
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ * force_freq == 0)
+ * @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover
+ * case or -1 if not used
* Returns: 0 on success, -1 on failure
*/
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group);
+ int persistent_group, unsigned int pref_freq, int dev_pw_id);
/**
* p2p_presence_req - Request GO presence
@@ -1183,7 +1486,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
* @p2p: P2P module context from p2p_init()
* @bssid: BSSID of the scan result
* @freq: Frequency of the channel on which the device was found in MHz
- * @age: Age of the scan result in milliseconds
+ * @rx_time: Time when the result was received
* @level: Signal level (signal strength of the received Beacon/Probe Response
* frame)
* @ies: Pointer to IEs from the scan result
@@ -1205,7 +1508,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
* start of a pending operation, e.g., to start a pending GO negotiation.
*/
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- unsigned int age, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len);
/**
@@ -1312,6 +1615,11 @@ struct p2p_group_config {
size_t ssid_len;
/**
+ * freq - Operating channel of the group
+ */
+ int freq;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -1587,7 +1895,24 @@ void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
*/
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel);
+/**
+ * p2p_config_get_random_social - Return a random social channel
+ * @p2p: P2P config
+ * @op_class: Selected operating class
+ * @op_channel: Selected social channel
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used before p2p_init is called. A random social channel
+ * from supports bands 2.4 GHz (channels 1,6,11) and 60 GHz (channel 2) is
+ * returned on success.
+ */
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel);
+
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced);
+
+u8 p2p_get_listen_channel(struct p2p_data *p2p);
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
@@ -1614,6 +1939,12 @@ int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr);
*/
void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+ unsigned int freq);
+
+int p2p_channels_to_freqs(const struct p2p_channels *channels,
+ int *freq_list, unsigned int max_len);
+
/**
* p2p_supported_freq - Check whether channel is supported for P2P
* @p2p: P2P module context from p2p_init()
@@ -1622,7 +1953,34 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
*/
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+/**
+ * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_supported_freq_cli - Check whether channel is supported for P2P client operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_get_pref_freq - Get channel from preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @channels: List of channels
+ * Returns: Preferred channel
+ */
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+ const struct p2p_channels *channels);
+
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan);
/**
* p2p_set_best_channels - Update best channel information
@@ -1634,6 +1992,17 @@ void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
int freq_overall);
+/**
+ * p2p_set_own_freq_preference - Set own preference for channel
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Frequency (MHz) of the preferred channel or 0 if no preference
+ *
+ * This function can be used to set a preference on the operating channel based
+ * on frequencies used on the other virtual interfaces that share the same
+ * radio. If non-zero, this is used to try to avoid multi-channel concurrency.
+ */
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq);
+
const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
/**
@@ -1644,11 +2013,18 @@ const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
unsigned int p2p_get_group_num_members(struct p2p_group *group);
/**
+ * p2p_client_limit_reached - Check if client limit is reached
+ * @group: P2P group context from p2p_group_init()
+ * Returns: 1 if no of clients limit reached
+ */
+int p2p_client_limit_reached(struct p2p_group *group);
+
+/**
* p2p_iterate_group_members - Iterate group members
* @group: P2P group context from p2p_group_init()
* @next: iteration pointer, must be a pointer to a void * that is set to %NULL
* on the first call and not modified later
- * Returns: A P2P Interface Address for each call and %NULL for no more members
+ * Returns: A P2P Device Address for each call and %NULL for no more members
*/
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
@@ -1670,6 +2046,26 @@ const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr);
/**
+ * p2p_group_get_config - Get the group configuration
+ * @group: P2P group context from p2p_group_init()
+ * Returns: The group configuration pointer
+ */
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group);
+
+/**
+ * p2p_loop_on_all_groups - Run the given callback on all groups
+ * @p2p: P2P module context from p2p_init()
+ * @group_callback: The callback function pointer
+ * @user_data: Some user data pointer which can be %NULL
+ *
+ * The group_callback function can stop the iteration by returning 0.
+ */
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data);
+
+/**
* p2p_get_peer_found - Get P2P peer info structure of a found peer
* @p2p: P2P module context from p2p_init()
* @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1719,18 +2115,21 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
const struct p2p_channel *pref_chan);
/**
- * p2p_in_progress - Check whether a P2P operation is progress
+ * p2p_set_no_go_freq - Set no GO channel ranges
* @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ * @list: Channel ranges or %NULL to remove restriction
+ * Returns: 0 on success, -1 on failure
*/
-int p2p_in_progress(struct p2p_data *p2p);
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list);
/**
- * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation was started
+ * Returns: 0 if P2P module is idle, 1 if an operation is in progress but not
+ * in search state, or 2 if search state operation is in progress
*/
-int p2p_other_scan_completed(struct p2p_data *p2p);
+int p2p_in_progress(struct p2p_data *p2p);
const char * p2p_wps_method_text(enum p2p_wps_method method);
@@ -1743,8 +2142,6 @@ const char * p2p_wps_method_text(enum p2p_wps_method method);
void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
u8 client_timeout);
-void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
-
int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
@@ -1780,4 +2177,71 @@ struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
int max_disc_tu);
+/**
+ * p2p_get_state_txt - Get current P2P state for debug purposes
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Name of the current P2P module state
+ *
+ * It should be noted that the P2P module state names are internal information
+ * and subject to change at any point, i.e., this information should be used
+ * mainly for debugging purposes.
+ */
+const char * p2p_get_state_txt(struct p2p_data *p2p);
+
+struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len);
+struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p,
+ int client_freq,
+ const u8 *go_dev_addr,
+ const u8 *ssid, size_t ssid_len);
+
+struct p2p_nfc_params {
+ int sel;
+ const u8 *wsc_attr;
+ size_t wsc_len;
+ const u8 *p2p_attr;
+ size_t p2p_len;
+
+ enum {
+ NO_ACTION, JOIN_GROUP, AUTH_JOIN, INIT_GO_NEG, RESP_GO_NEG,
+ BOTH_GO, PEER_CLIENT
+ } next_step;
+ struct p2p_peer_info *peer;
+ u8 oob_dev_pw[WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_LEN];
+ size_t oob_dev_pw_len;
+ int go_freq;
+ u8 go_dev_addr[ETH_ALEN];
+ u8 go_ssid[32];
+ size_t go_ssid_len;
+};
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+ struct p2p_nfc_params *params);
+
+void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
+ int go_intent,
+ const u8 *own_interface_addr);
+
+int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len);
+
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data);
+
+void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem);
+
+void p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr);
+
+struct p2ps_advertisement *
+p2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id);
+int p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
+ const char *adv_str, u8 svc_state,
+ u16 config_methods, const char *svc_info);
+int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id);
+struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p);
+
#endif /* P2P_H */
diff --git a/contrib/wpa/src/p2p/p2p_build.c b/contrib/wpa/src/p2p/p2p_build.c
index 5838d35..92c92066 100644
--- a/contrib/wpa/src/p2p/p2p_build.c
+++ b/contrib/wpa/src/p2p/p2p_build.c
@@ -17,8 +17,7 @@
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token)
{
wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpabuf_put_u8(buf, subtype); /* OUI Subtype */
wpabuf_put_u8(buf, dialog_token);
@@ -31,8 +30,7 @@ void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
{
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpabuf_put_u8(buf, subtype); /* OUI Subtype */
wpabuf_put_u8(buf, dialog_token);
@@ -47,8 +45,7 @@ u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf)
/* P2P IE header */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(buf, 1); /* IE length to be filled */
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpa_printf(MSG_DEBUG, "P2P: * P2P IE header");
return len;
}
@@ -167,15 +164,18 @@ void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
if (peer->wps_method == WPS_PBC)
methods |= WPS_CONFIG_PUSHBUTTON;
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 |
- WPS_CONFIG_KEYPAD);
+ WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS);
} else {
methods |= WPS_CONFIG_PUSHBUTTON;
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+ methods |= WPS_CONFIG_P2PS;
}
wpabuf_put_be16(buf, methods);
@@ -258,6 +258,7 @@ void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr,
wpabuf_put_data(buf, ssid, ssid_len);
wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
MAC2STR(dev_addr));
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len);
}
@@ -327,13 +328,282 @@ void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
}
-static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
- const char *val)
+void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
+ u8 oper_class, u8 channel,
+ enum p2p_role_indication role)
+{
+ /* OOB Group Owner Negotiation Channel */
+ wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL);
+ wpabuf_put_le16(buf, 6);
+ wpabuf_put_data(buf, country, 3);
+ wpabuf_put_u8(buf, oper_class); /* Operating Class */
+ wpabuf_put_u8(buf, channel); /* Channel Number */
+ wpabuf_put_u8(buf, (u8) role); /* Role indication */
+ wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating "
+ "Class %u Channel %u Role %d",
+ oper_class, channel, role);
+}
+
+
+void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
+{
+ if (!p2p)
+ return;
+
+ /* Service Hash */
+ wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
+ wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+ wpabuf_put_data(buf, p2p->query_hash,
+ p2p->p2ps_seek_count * P2PS_HASH_LEN);
+ wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
+ p2p->query_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+}
+
+
+void p2p_buf_add_session_info(struct wpabuf *buf, const char *info)
+{
+ size_t info_len = 0;
+
+ if (info && info[0])
+ info_len = os_strlen(info);
+
+ /* Session Information Data Info */
+ wpabuf_put_u8(buf, P2P_ATTR_SESSION_INFORMATION_DATA);
+ wpabuf_put_le16(buf, (u16) info_len);
+
+ if (info) {
+ wpabuf_put_data(buf, info, info_len);
+ wpa_printf(MSG_DEBUG, "P2P: * Session Info Data (%s)", info);
+ }
+}
+
+
+void p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap)
+{
+ /* Connection Capability Info */
+ wpabuf_put_u8(buf, P2P_ATTR_CONNECTION_CAPABILITY);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_u8(buf, connection_cap);
+ wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
+ connection_cap);
+}
+
+
+void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac)
+{
+ if (!buf || !mac)
+ return;
+
+ /* Advertisement ID Info */
+ wpabuf_put_u8(buf, P2P_ATTR_ADVERTISEMENT_ID);
+ wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
+ wpabuf_put_le32(buf, id);
+ wpabuf_put_data(buf, mac, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID (%x) " MACSTR,
+ id, MAC2STR(mac));
+}
+
+
+void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
+ u8 hash_count, const u8 *hash,
+ struct p2ps_advertisement *adv_list)
+{
+ struct p2ps_advertisement *adv;
+ struct wpabuf *tmp_buf;
+ u8 *tag_len = NULL, *ie_len = NULL;
+ size_t svc_len = 0, remaining = 0, total_len = 0;
+
+ if (!adv_list || !hash)
+ return;
+
+ /* Allocate temp buffer, allowing for overflow of 1 instance */
+ tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
+ if (!tmp_buf)
+ return;
+
+ for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
+ adv = adv->next) {
+ u8 count = hash_count;
+ const u8 *test = hash;
+
+ while (count--) {
+ /* Check for wildcard */
+ if (os_memcmp(test, p2p->wild_card_hash,
+ P2PS_HASH_LEN) == 0) {
+ total_len = MAX_SVC_ADV_LEN + 1;
+ goto wild_hash;
+ }
+
+ if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0)
+ goto hash_match;
+
+ test += P2PS_HASH_LEN;
+ }
+
+ /* No matches found - Skip this Adv Instance */
+ continue;
+
+hash_match:
+ if (!tag_len) {
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+ remaining = 255 - 4;
+ if (!ie_len) {
+ wpabuf_put_u8(tmp_buf,
+ P2P_ATTR_ADVERTISED_SERVICE);
+ ie_len = wpabuf_put(tmp_buf, sizeof(u16));
+ remaining -= (sizeof(u8) + sizeof(u16));
+ }
+ }
+
+ svc_len = os_strlen(adv->svc_name);
+
+ if (7 + svc_len + total_len > MAX_SVC_ADV_LEN) {
+ /* Can't fit... return wildcard */
+ total_len = MAX_SVC_ADV_LEN + 1;
+ break;
+ }
+
+ if (remaining <= (sizeof(adv->id) +
+ sizeof(adv->config_methods))) {
+ size_t front = remaining;
+ size_t back = (sizeof(adv->id) +
+ sizeof(adv->config_methods)) - front;
+ u8 holder[sizeof(adv->id) +
+ sizeof(adv->config_methods)];
+
+ /* This works even if front or back == 0 */
+ WPA_PUT_LE32(holder, adv->id);
+ WPA_PUT_BE16(&holder[sizeof(adv->id)],
+ adv->config_methods);
+ wpabuf_put_data(tmp_buf, holder, front);
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+ wpabuf_put_data(tmp_buf, &holder[front], back);
+ remaining = 255 - (sizeof(adv->id) +
+ sizeof(adv->config_methods)) - back;
+ } else {
+ wpabuf_put_le32(tmp_buf, adv->id);
+ wpabuf_put_be16(tmp_buf, adv->config_methods);
+ remaining -= (sizeof(adv->id) +
+ sizeof(adv->config_methods));
+ }
+
+ /* We are guaranteed at least one byte for svc_len */
+ wpabuf_put_u8(tmp_buf, svc_len);
+ remaining -= sizeof(u8);
+
+ if (remaining < svc_len) {
+ size_t front = remaining;
+ size_t back = svc_len - front;
+
+ wpabuf_put_data(tmp_buf, adv->svc_name, front);
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+
+ /* In rare cases, we must split across 3 attributes */
+ if (back > 255 - 4) {
+ wpabuf_put_data(tmp_buf,
+ &adv->svc_name[front], 255 - 4);
+ back -= 255 - 4;
+ front += 255 - 4;
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+ tag_len = p2p_buf_add_ie_hdr(tmp_buf);
+ }
+
+ wpabuf_put_data(tmp_buf, &adv->svc_name[front], back);
+ remaining = 255 - 4 - back;
+ } else {
+ wpabuf_put_data(tmp_buf, adv->svc_name, svc_len);
+ remaining -= svc_len;
+ }
+
+ /* adv_id config_methods svc_string */
+ total_len += sizeof(u32) + sizeof(u16) + sizeof(u8) + svc_len;
+ }
+
+ if (tag_len)
+ p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+
+ if (ie_len)
+ WPA_PUT_LE16(ie_len, (u16) total_len);
+
+wild_hash:
+ /* If all fit, return matching instances, otherwise the wildcard */
+ if (total_len <= MAX_SVC_ADV_LEN) {
+ wpabuf_put_buf(buf, tmp_buf);
+ } else {
+ char *wild_card = P2PS_WILD_HASH_STR;
+ u8 wild_len;
+
+ /* Insert wildcard instance */
+ tag_len = p2p_buf_add_ie_hdr(buf);
+ wpabuf_put_u8(buf, P2P_ATTR_ADVERTISED_SERVICE);
+ ie_len = wpabuf_put(buf, sizeof(u16));
+
+ wild_len = (u8) os_strlen(wild_card);
+ wpabuf_put_le32(buf, 0);
+ wpabuf_put_be16(buf, 0);
+ wpabuf_put_u8(buf, wild_len);
+ wpabuf_put_data(buf, wild_card, wild_len);
+
+ WPA_PUT_LE16(ie_len, 4 + 2 + 1 + wild_len);
+ p2p_buf_update_ie_hdr(buf, tag_len);
+ }
+
+ wpabuf_free(tmp_buf);
+}
+
+
+void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac)
+{
+ if (!buf || !mac)
+ return;
+
+ /* Session ID Info */
+ wpabuf_put_u8(buf, P2P_ATTR_SESSION_ID);
+ wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
+ wpabuf_put_le32(buf, id);
+ wpabuf_put_data(buf, mac, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "P2P: * Session ID Info (%x) " MACSTR,
+ id, MAC2STR(mac));
+}
+
+
+void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask)
+{
+ if (!buf || !len || !mask)
+ return;
+
+ /* Feature Capability */
+ wpabuf_put_u8(buf, P2P_ATTR_FEATURE_CAPABILITY);
+ wpabuf_put_le16(buf, len);
+ wpabuf_put_data(buf, mask, len);
+ wpa_printf(MSG_DEBUG, "P2P: * Feature Capability (%d)", len);
+}
+
+
+void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
+ const u8 *ssid, size_t ssid_len)
+{
+ /* P2P Group ID */
+ wpabuf_put_u8(buf, P2P_ATTR_PERSISTENT_GROUP);
+ wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
+ wpabuf_put_data(buf, dev_addr, ETH_ALEN);
+ wpabuf_put_data(buf, ssid, ssid_len);
+ wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
+ MAC2STR(dev_addr));
+}
+
+
+static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
+ const char *val)
{
size_t len;
- wpabuf_put_be16(buf, attr);
len = val ? os_strlen(val) : 0;
+ if (wpabuf_tailroom(buf) < 4 + len)
+ return -1;
+ wpabuf_put_be16(buf, attr);
#ifndef CONFIG_WPS_STRICT
if (len == 0) {
/*
@@ -341,36 +611,46 @@ static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
* attributes. As a workaround, send a space character if the
* device attribute string is empty.
*/
+ if (wpabuf_tailroom(buf) < 3)
+ return -1;
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, ' ');
- return;
+ return 0;
}
#endif /* CONFIG_WPS_STRICT */
wpabuf_put_be16(buf, len);
if (val)
wpabuf_put_data(buf, val, len);
+ return 0;
}
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr)
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr)
{
u8 *len;
int i;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(buf, 1);
wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
- wps_build_version(buf);
+ if (wps_build_version(buf) < 0)
+ return -1;
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_WPS_STATE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
}
if (pw_id >= 0) {
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
/* Device Password ID */
wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
wpabuf_put_be16(buf, 2);
@@ -380,33 +660,47 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
- wps_build_uuid_e(buf, p2p->cfg->uuid);
- p2p_add_wps_string(buf, ATTR_MANUFACTURER,
- p2p->cfg->manufacturer);
- p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name);
- p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
- p2p->cfg->model_number);
- p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
- p2p->cfg->serial_number);
-
+ if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MANUFACTURER,
+ p2p->cfg->manufacturer) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NAME,
+ p2p->cfg->model_name) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
+ p2p->cfg->model_number) < 0 ||
+ p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
+ p2p->cfg->serial_number) < 0)
+ return -1;
+
+ if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
+ return -1;
wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
- p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name);
+ if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
+ < 0)
+ return -1;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
wpabuf_put_be16(buf, 2);
wpabuf_put_be16(buf, p2p->cfg->config_methods);
}
- wps_build_wfa_ext(buf, 0, NULL, 0);
+ if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+ return -1;
if (all_attr && p2p->cfg->num_sec_dev_types) {
+ if (wpabuf_tailroom(buf) <
+ 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
+ return -1;
wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
p2p->cfg->num_sec_dev_types);
@@ -428,4 +722,6 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
p2p_buf_update_ie_hdr(buf, len);
+
+ return 0;
}
diff --git a/contrib/wpa/src/p2p/p2p_dev_disc.c b/contrib/wpa/src/p2p/p2p_dev_disc.c
index c976b7c..86bae1a 100644
--- a/contrib/wpa/src/p2p/p2p_dev_disc.c
+++ b/contrib/wpa/src/p2p/p2p_dev_disc.c
@@ -42,8 +42,7 @@ static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p,
void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Device Discoverability Request TX callback: success=%d",
+ p2p_dbg(p2p, "Device Discoverability Request TX callback: success=%d",
success);
if (!success) {
@@ -56,9 +55,7 @@ void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO acknowledged Device Discoverability Request - wait "
- "for response");
+ p2p_dbg(p2p, "GO acknowledged Device Discoverability Request - wait for response");
/*
* TODO: is the remain-on-channel from Action frame TX long enough for
* most cases or should we try to increase its duration and/or start
@@ -71,12 +68,11 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
{
struct p2p_device *go;
struct wpabuf *req;
+ unsigned int wait_time;
go = p2p_get_device(p2p, dev->member_in_go_dev);
if (go == NULL || dev->oper_freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Could not find peer entry for GO and frequency "
- "to send Device Discoverability Request");
+ p2p_dbg(p2p, "Could not find peer entry for GO and frequency to send Device Discoverability Request");
return -1;
}
@@ -84,8 +80,7 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
if (req == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Device Discoverability Request to GO " MACSTR
+ p2p_dbg(p2p, "Sending Device Discoverability Request to GO " MACSTR
" for client " MACSTR,
MAC2STR(go->info.p2p_device_addr),
MAC2STR(dev->info.p2p_device_addr));
@@ -94,11 +89,13 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr,
ETH_ALEN);
p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST;
+ wait_time = 1000;
+ if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
+ wait_time = p2p->cfg->max_listen;
if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr,
p2p->cfg->dev_addr, go->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 1000) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(req);
/* TODO: how to recover from failure? */
return -1;
@@ -131,8 +128,7 @@ static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status)
void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Device Discoverability Response TX callback: success=%d",
+ p2p_dbg(p2p, "Device Discoverability Response TX callback: success=%d",
success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
}
@@ -147,8 +143,7 @@ static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
if (resp == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Device Discoverability Response to " MACSTR
+ p2p_dbg(p2p, "Sending Device Discoverability Response to " MACSTR
" (status %u freq %d)",
MAC2STR(addr), status, freq);
@@ -156,8 +151,7 @@ static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(resp);
@@ -170,17 +164,14 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
struct p2p_message msg;
size_t g;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Device Discoverability Request from " MACSTR
+ p2p_dbg(p2p, "Received Device Discoverability Request from " MACSTR
" (freq=%d)", MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
return;
if (msg.dialog_token == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid Dialog Token 0 (must be nonzero) in "
- "Device Discoverability Request");
+ p2p_dbg(p2p, "Invalid Dialog Token 0 (must be nonzero) in Device Discoverability Request");
p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
@@ -188,9 +179,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
}
if (msg.device_id == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: P2P Device ID attribute missing from Device "
- "Discoverability Request");
+ p2p_dbg(p2p, "P2P Device ID attribute missing from Device Discoverability Request");
p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
@@ -200,9 +189,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
for (g = 0; g < p2p->num_groups; g++) {
if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa,
rx_freq) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled "
- "GO Discoverability Request for the target "
- "device");
+ p2p_dbg(p2p, "Scheduled GO Discoverability Request for the target device");
/*
* P2P group code will use a callback to indicate TX
* status, so that we can reply to the request once the
@@ -217,9 +204,7 @@ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
}
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client "
- "was not found in any group or did not support client "
- "discoverability");
+ p2p_dbg(p2p, "Requested client was not found in any group or did not support client discoverability");
p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
p2p_parse_free(&msg);
@@ -233,15 +218,13 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
struct p2p_device *go;
u8 status;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Device Discoverability Response from " MACSTR,
+ p2p_dbg(p2p, "Received Device Discoverability Response from " MACSTR,
MAC2STR(sa));
go = p2p->pending_client_disc_go;
if (go == NULL ||
os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected "
- "Device Discoverability Response");
+ p2p_dbg(p2p, "Ignore unexpected Device Discoverability Response");
return;
}
@@ -254,9 +237,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
}
if (msg.dialog_token != go->dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device "
- "Discoverability Response with unexpected dialog "
- "token %u (expected %u)",
+ p2p_dbg(p2p, "Ignore Device Discoverability Response with unexpected dialog token %u (expected %u)",
msg.dialog_token, go->dialog_token);
p2p_parse_free(&msg);
return;
@@ -265,17 +246,14 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
status = *msg.status;
p2p_parse_free(&msg);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Device Discoverability Response status %u", status);
+ p2p_dbg(p2p, "Device Discoverability Response status %u", status);
if (p2p->go_neg_peer == NULL ||
os_memcmp(p2p->pending_client_disc_addr,
p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 ||
os_memcmp(p2p->go_neg_peer->member_in_go_dev,
go->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending "
- "operation with the client discoverability peer "
- "anymore");
+ p2p_dbg(p2p, "No pending operation with the client discoverability peer anymore");
return;
}
@@ -284,8 +262,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
* Peer is expected to be awake for at least 100 TU; try to
* connect immediately.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Client discoverability request succeeded");
+ p2p_dbg(p2p, "Client discoverability request succeeded");
if (p2p->state == P2P_CONNECT) {
/*
* Change state to force the timeout to start in
@@ -301,8 +278,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
* Client discoverability request failed; try to connect from
* timeout.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Client discoverability request failed");
+ p2p_dbg(p2p, "Client discoverability request failed");
p2p_set_timeout(p2p, 0, 500000);
}
@@ -311,14 +287,12 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
void p2p_go_disc_req_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Discoverability Request TX callback: success=%d",
+ p2p_dbg(p2p, "GO Discoverability Request TX callback: success=%d",
success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (p2p->pending_dev_disc_dialog_token == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device "
- "Discoverability Request");
+ p2p_dbg(p2p, "No pending Device Discoverability Request");
return;
}
@@ -338,9 +312,7 @@ void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
unsigned int tu;
struct wpabuf *ies;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Discoverability Request - remain awake for "
- "100 TU");
+ p2p_dbg(p2p, "Received GO Discoverability Request - remain awake for 100 TU");
ies = p2p_build_probe_resp_ies(p2p);
if (ies == NULL)
@@ -351,9 +323,7 @@ void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
tu = 100;
if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000,
ies) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to start listen mode for client "
- "discoverability");
+ p2p_dbg(p2p, "Failed to start listen mode for client discoverability");
}
wpabuf_free(ies);
}
diff --git a/contrib/wpa/src/p2p/p2p_go_neg.c b/contrib/wpa/src/p2p/p2p_go_neg.c
index 2fdc47f..98abf9d 100644
--- a/contrib/wpa/src/p2p/p2p_go_neg.c
+++ b/contrib/wpa/src/p2p/p2p_go_neg.c
@@ -9,7 +9,9 @@
#include "includes.h"
#include "common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -49,8 +51,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
os_memcpy(dev->country, pos, 3);
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Peer country", pos, 3);
if (pos[2] != 0x04 && os_memcmp(pos, p2p->cfg->country, 2) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Mismatching country (ours=%c%c peer's=%c%c)",
+ p2p_info(p2p, "Mismatching country (ours=%c%c peer's=%c%c)",
p2p->cfg->country[0], p2p->cfg->country[1],
pos[0], pos[1]);
return -1;
@@ -61,8 +62,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
cl->reg_class = *pos++;
if (pos + 1 + pos[0] > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: Invalid peer Channel List");
+ p2p_info(p2p, "Invalid peer Channel List");
return -1;
}
channels = *pos++;
@@ -76,14 +76,12 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
}
p2p_channels_intersect(own, &dev->channels, &intersection);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own reg_classes %d "
- "peer reg_classes %d intersection reg_classes %d",
+ p2p_dbg(p2p, "Own reg_classes %d peer reg_classes %d intersection reg_classes %d",
(int) own->reg_classes,
(int) dev->channels.reg_classes,
(int) intersection.reg_classes);
if (intersection.reg_classes == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- "P2P: No common channels found");
+ p2p_info(p2p, "No common channels found");
return -1;
}
return 0;
@@ -107,6 +105,10 @@ u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
return DEV_PW_USER_SPECIFIED;
case WPS_PBC:
return DEV_PW_PUSHBUTTON;
+ case WPS_NFC:
+ return DEV_PW_NFC_CONNECTION_HANDOVER;
+ case WPS_P2PS:
+ return DEV_PW_P2PS_DEFAULT;
default:
return DEV_PW_DEFAULT;
}
@@ -122,6 +124,10 @@ static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
return "Keypad";
case WPS_PBC:
return "PBC";
+ case WPS_NFC:
+ return "NFC";
+ case WPS_P2PS:
+ return "P2PS";
default:
return "??";
}
@@ -135,19 +141,20 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
u8 *len;
u8 group_capab;
size_t extra = 0;
+ u16 pw_id;
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
- peer->dialog_token++;
- if (peer->dialog_token == 0)
- peer->dialog_token = 1;
p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
len = p2p_buf_add_ie_hdr(buf);
@@ -164,9 +171,7 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p_buf_add_capability(buf, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
- p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
- p2p->next_tie_breaker);
- p2p->next_tie_breaker = !p2p->next_tie_breaker;
+ p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
p2p->cfg->channel);
@@ -181,13 +186,23 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+ pw_id = p2p_wps_method_pw_id(peer->wps_method);
+ if (peer->oob_pw_id)
+ pw_id = peer->oob_pw_id;
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+
return buf;
}
@@ -199,8 +214,7 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
u16 config_method;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use PD-before-GO-Neg workaround for " MACSTR,
+ p2p_dbg(p2p, "Use PD-before-GO-Neg workaround for " MACSTR,
MAC2STR(dev->info.p2p_device_addr));
if (dev->wps_method == WPS_PIN_DISPLAY)
config_method = WPS_CONFIG_KEYPAD;
@@ -208,17 +222,20 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
config_method = WPS_CONFIG_DISPLAY;
else if (dev->wps_method == WPS_PBC)
config_method = WPS_CONFIG_PUSHBUTTON;
+ else if (dev->wps_method == WPS_P2PS)
+ config_method = WPS_CONFIG_P2PS;
else
return -1;
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
- config_method, 0, 0, 1);
+ NULL, config_method, 0, 0, 1);
}
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+ if (dev->oob_go_neg_freq > 0)
+ freq = dev->oob_go_neg_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send GO Negotiation Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send GO Negotiation Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
@@ -226,18 +243,17 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
req = p2p_build_go_neg_req(p2p, dev);
if (req == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending GO Negotiation Request");
+ p2p_dbg(p2p, "Sending GO Negotiation Request");
p2p_set_state(p2p, P2P_CONNECT);
p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->connect_reqs++;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), 500) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
/* Use P2P find to recover and retry */
p2p_set_timeout(p2p, 0, 0);
} else
@@ -258,15 +274,18 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
u8 *len;
u8 group_capab;
size_t extra = 0;
+ u16 pw_id;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Building GO Negotiation Response");
+ p2p_dbg(p2p, "Building GO Negotiation Response");
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -294,8 +313,7 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
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) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
- "Channel attribute");
+ p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
p2p->op_reg_class,
@@ -322,15 +340,22 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf,
- p2p_wps_method_pw_id(peer ? peer->wps_method :
- WPS_NOT_READY), 0);
+ pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY);
+ if (peer && peer->oob_pw_id)
+ pw_id = peer->oob_pw_id;
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
return buf;
}
@@ -354,16 +379,41 @@ void p2p_reselect_channel(struct p2p_data *p2p,
int freq;
u8 op_reg_class, op_channel;
unsigned int i;
+ const int op_classes_5ghz[] = { 124, 115, 0 };
+ const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
+ const int op_classes_vht[] = { 128, 0 };
+
+ if (p2p->own_freq_preference > 0 &&
+ p2p_freq_to_channel(p2p->own_freq_preference,
+ &op_reg_class, &op_channel) == 0 &&
+ p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+ p2p_dbg(p2p, "Pick own channel preference (reg_class %u channel %u) from intersection",
+ op_reg_class, op_channel);
+ p2p->op_reg_class = op_reg_class;
+ p2p->op_channel = op_channel;
+ return;
+ }
+
+ if (p2p->best_freq_overall > 0 &&
+ p2p_freq_to_channel(p2p->best_freq_overall,
+ &op_reg_class, &op_channel) == 0 &&
+ p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+ p2p_dbg(p2p, "Pick best overall channel (reg_class %u channel %u) from intersection",
+ op_reg_class, op_channel);
+ p2p->op_reg_class = op_reg_class;
+ p2p->op_channel = op_channel;
+ return;
+ }
/* First, try to pick the best channel from another band */
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class,
- p2p->op_channel);
+ freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel);
if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+ !p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel) &&
+ p2p_freq_to_channel(p2p->best_freq_5,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 5 GHz "
- "channel (reg_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Pick best 5 GHz channel (reg_class %u channel %u) from intersection",
op_reg_class, op_channel);
p2p->op_reg_class = op_reg_class;
p2p->op_channel = op_channel;
@@ -371,11 +421,12 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+ !p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel) &&
+ p2p_freq_to_channel(p2p->best_freq_24,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 2.4 GHz "
- "channel (reg_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Pick best 2.4 GHz channel (reg_class %u channel %u) from intersection",
op_reg_class, op_channel);
p2p->op_reg_class = op_reg_class;
p2p->op_channel = op_channel;
@@ -389,27 +440,34 @@ void p2p_reselect_channel(struct p2p_data *p2p,
p2p->cfg->pref_chan[i].chan)) {
p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class;
p2p->op_channel = p2p->cfg->pref_chan[i].chan;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick "
- "highest preferred chnnel (op_class %u "
- "channel %u) from intersection",
+ p2p_dbg(p2p, "Pick highest preferred channel (op_class %u channel %u) from intersection",
p2p->op_reg_class, p2p->op_channel);
return;
}
}
+ /* Try a channel where we might be able to use VHT */
+ if (p2p_channel_select(intersection, op_classes_vht,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible VHT channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
/* Try a channel where we might be able to use HT40 */
- for (i = 0; i < intersection->reg_classes; i++) {
- struct p2p_reg_class *c = &intersection->reg_class[i];
- if (c->reg_class == 116 || c->reg_class == 117 ||
- c->reg_class == 126 || c->reg_class == 127) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Pick possible HT40 channel (reg_class "
- "%u channel %u) from intersection",
- c->reg_class, c->channel[0]);
- p2p->op_reg_class = c->reg_class;
- p2p->op_channel = c->channel[0];
- return;
- }
+ if (p2p_channel_select(intersection, op_classes_ht40,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible HT40 channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
+ /* Prefer a 5 GHz channel */
+ if (p2p_channel_select(intersection, op_classes_5ghz,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
}
/*
@@ -419,9 +477,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
*/
if (p2p_channels_includes(intersection, p2p->op_reg_class,
p2p->op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Using original operating class and channel "
- "(op_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Using original operating class and channel (op_class %u channel %u) from intersection",
p2p->op_reg_class, p2p->op_channel);
return;
}
@@ -431,55 +487,48 @@ void p2p_reselect_channel(struct p2p_data *p2p,
* no better options seems to be available.
*/
cl = &intersection->reg_class[0];
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick another channel "
- "(reg_class %u channel %u) from intersection",
+ p2p_dbg(p2p, "Pick another channel (reg_class %u channel %u) from intersection",
cl->reg_class, cl->channel[0]);
p2p->op_reg_class = cl->reg_class;
p2p->op_channel = cl->channel[0];
}
-static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
- u8 *status)
+int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ u8 *status)
{
- struct p2p_channels intersection;
- size_t i;
-
- p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+ struct p2p_channels tmp, intersection;
+
+ p2p_channels_dump(p2p, "own channels", &p2p->channels);
+ p2p_channels_dump(p2p, "peer channels", &dev->channels);
+ p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp);
+ p2p_channels_dump(p2p, "intersection", &tmp);
+ p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp);
+ p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection);
+ p2p_channels_dump(p2p, "intersection with local channel list",
+ &intersection);
if (intersection.reg_classes == 0 ||
intersection.reg_class[0].channels == 0) {
*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
return -1;
}
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c;
- c = &intersection.reg_class[i];
- wpa_printf(MSG_DEBUG, "P2P: reg_class %u", c->reg_class);
- wpa_hexdump(MSG_DEBUG, "P2P: channels",
- c->channel, c->channels);
- }
-
if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
p2p->op_channel)) {
if (dev->flags & P2P_DEV_FORCE_FREQ) {
*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer does "
- "not support the forced channel");
+ p2p_dbg(p2p, "Peer does not support the forced channel");
return -1;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
- "channel (op_class %u channel %u) not acceptable to "
- "the peer", p2p->op_reg_class, p2p->op_channel);
+ p2p_dbg(p2p, "Selected operating channel (op_class %u channel %u) not acceptable to the peer",
+ p2p->op_reg_class, p2p->op_channel);
p2p_reselect_channel(p2p, &intersection);
} else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
!p2p->cfg->cfg_op_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Try to optimize "
- "channel selection with peer information received; "
- "previously selected op_class %u channel %u",
+ p2p_dbg(p2p, "Try to optimize channel selection with peer information received; previously selected op_class %u channel %u",
p2p->op_reg_class, p2p->op_channel);
p2p_reselect_channel(p2p, &intersection);
}
@@ -503,17 +552,14 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
int tie_breaker = 0;
int freq;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Negotiation Request from " MACSTR
- "(freq=%d)", MAC2STR(sa), rx_freq);
+ p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)",
+ MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
return;
if (!msg.capability) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Capability attribute missing from GO "
- "Negotiation Request");
+ p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request");
#ifdef CONFIG_P2P_STRICT
goto fail;
#endif /* CONFIG_P2P_STRICT */
@@ -522,53 +568,42 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
if (msg.go_intent)
tie_breaker = *msg.go_intent & 0x01;
else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory GO Intent attribute missing from GO "
- "Negotiation Request");
+ p2p_dbg(p2p, "Mandatory GO Intent attribute missing from GO Negotiation Request");
#ifdef CONFIG_P2P_STRICT
goto fail;
#endif /* CONFIG_P2P_STRICT */
}
if (!msg.config_timeout) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Configuration Timeout attribute "
- "missing from GO Negotiation Request");
+ p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Request");
#ifdef CONFIG_P2P_STRICT
goto fail;
#endif /* CONFIG_P2P_STRICT */
}
if (!msg.listen_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen Channel attribute received");
+ p2p_dbg(p2p, "No Listen Channel attribute received");
goto fail;
}
if (!msg.operating_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Operating Channel attribute received");
+ p2p_dbg(p2p, "No Operating Channel attribute received");
goto fail;
}
if (!msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Channel List attribute received");
+ p2p_dbg(p2p, "No Channel List attribute received");
goto fail;
}
if (!msg.intended_addr) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Intended P2P Interface Address attribute "
- "received");
+ p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
goto fail;
}
if (!msg.p2p_device_info) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No P2P Device Info attribute received");
+ p2p_dbg(p2p, "No P2P Device Info attribute received");
goto fail;
}
if (os_memcmp(msg.p2p_device_addr, sa, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected GO Negotiation Request SA=" MACSTR
+ p2p_dbg(p2p, "Unexpected GO Negotiation Request SA=" MACSTR
" != dev_addr=" MACSTR,
MAC2STR(sa), MAC2STR(msg.p2p_device_addr));
goto fail;
@@ -577,133 +612,177 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
dev = p2p_get_device(p2p, sa);
if (msg.status && *msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected Status attribute (%d) in GO "
- "Negotiation Request", *msg.status);
+ p2p_dbg(p2p, "Unexpected Status attribute (%d) in GO Negotiation Request",
+ *msg.status);
+ if (dev && p2p->go_neg_peer == dev &&
+ *msg.status == P2P_SC_FAIL_REJECTED_BY_USER) {
+ /*
+ * This mechanism for using Status attribute in GO
+ * Negotiation Request is not compliant with the P2P
+ * specification, but some deployed devices use it to
+ * indicate rejection of GO Negotiation in a case where
+ * they have sent out GO Negotiation Response with
+ * status 1. The P2P specification explicitly disallows
+ * this. To avoid unnecessary interoperability issues
+ * and extra frames, mark the pending negotiation as
+ * failed and do not reply to this GO Negotiation
+ * Request frame.
+ */
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p_go_neg_failed(p2p, *msg.status);
+ p2p_parse_free(&msg);
+ return;
+ }
goto fail;
}
if (dev == NULL)
dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg);
- else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
+ else if ((dev->flags & P2P_DEV_PROBE_REQ_ONLY) ||
+ !(dev->flags & P2P_DEV_REPORTED))
p2p_add_dev_info(p2p, sa, dev, &msg);
+ else if (!dev->listen_freq && !dev->oper_freq) {
+ /*
+ * This may happen if the peer entry was added based on PD
+ * Request and no Probe Request/Response frame has been received
+ * from this peer (or that information has timed out).
+ */
+ p2p_dbg(p2p, "Update peer " MACSTR
+ " based on GO Neg Req since listen/oper freq not known",
+ MAC2STR(dev->info.p2p_device_addr));
+ p2p_add_dev_info(p2p, sa, dev, &msg);
+ }
+
+ if (p2p->go_neg_peer && p2p->go_neg_peer == dev)
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+
if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: User has rejected this peer");
+ p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
- } else if (dev == NULL || dev->wps_method == WPS_NOT_READY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Not ready for GO negotiation with " MACSTR,
+ } else if (dev == NULL ||
+ (dev->wps_method == WPS_NOT_READY &&
+ (p2p->authorized_oob_dev_pw_id == 0 ||
+ p2p->authorized_oob_dev_pw_id !=
+ msg.dev_password_id))) {
+ p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
- if (dev)
- dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
p2p->cfg->go_neg_req_rx(p2p->cfg->cb_ctx, sa,
msg.dev_password_id);
} else if (p2p->go_neg_peer && p2p->go_neg_peer != dev) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Already in Group Formation with another peer");
+ p2p_dbg(p2p, "Already in Group Formation with another peer");
status = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
} else {
int go;
if (!p2p->go_neg_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting "
- "GO Negotiation with previously authorized "
- "peer");
+ p2p_dbg(p2p, "Starting GO Negotiation with previously authorized peer");
if (!(dev->flags & P2P_DEV_FORCE_FREQ)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use default channel settings");
+ p2p_dbg(p2p, "Use default channel settings");
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
sizeof(struct p2p_channels));
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use previously configured "
- "forced channel settings");
+ p2p_dbg(p2p, "Use previously configured forced channel settings");
}
}
dev->flags &= ~P2P_DEV_NOT_YET_READY;
if (!msg.go_intent) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No GO Intent attribute received");
+ p2p_dbg(p2p, "No GO Intent attribute received");
goto fail;
}
if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid GO Intent value (%u) received",
+ p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
*msg.go_intent >> 1);
goto fail;
}
if (dev->go_neg_req_sent &&
os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Do not reply since peer has higher "
- "address and GO Neg Request already sent");
+ p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent");
p2p_parse_free(&msg);
return;
}
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
if (go < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Incompatible GO Intent");
+ p2p_dbg(p2p, "Incompatible GO Intent");
status = P2P_SC_FAIL_BOTH_GO_INTENT_15;
goto fail;
}
if (p2p_peer_channels(p2p, dev, msg.channel_list,
msg.channel_list_len) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Display");
+ p2p_dbg(p2p, "PIN from peer Display");
if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_USER_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer entered PIN on Keypad");
+ p2p_dbg(p2p, "Peer entered PIN on Keypad");
if (dev->wps_method != WPS_PIN_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_PUSHBUTTON:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer using pushbutton");
+ p2p_dbg(p2p, "Peer using pushbutton");
if (dev->wps_method != WPS_PBC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ case DEV_PW_P2PS_DEFAULT:
+ p2p_dbg(p2p, "Peer using P2PS pin");
+ if (dev->wps_method != WPS_P2PS) {
+ p2p_dbg(p2p,
+ "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported Device Password ID %d",
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(
+ dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
+#ifdef CONFIG_WPS_NFC
+ if (p2p->authorized_oob_dev_pw_id &&
+ msg.dev_password_id ==
+ p2p->authorized_oob_dev_pw_id) {
+ p2p_dbg(p2p, "Using static handover with our device password from NFC Tag");
+ dev->wps_method = WPS_NFC;
+ dev->oob_pw_id = p2p->authorized_oob_dev_pw_id;
+ break;
+ }
+#endif /* CONFIG_WPS_NFC */
+ p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
@@ -713,20 +792,17 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
goto fail;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
- dev->oper_freq = p2p_channel_to_freq((const char *)
- msg.operating_channel,
- msg.operating_channel[3],
+ dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
msg.operating_channel[4]);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
- "channel preference: %d MHz", dev->oper_freq);
+ p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+ dev->oper_freq);
if (msg.config_timeout) {
dev->go_timeout = msg.config_timeout[0];
dev->client_timeout = msg.config_timeout[1];
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
if (p2p->state != P2P_IDLE)
p2p_stop_find_for_freq(p2p, rx_freq);
p2p_set_state(p2p, P2P_GO_NEG);
@@ -734,6 +810,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
dev->dialog_token = msg.dialog_token;
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
status = P2P_SC_SUCCESS;
}
@@ -745,17 +822,14 @@ fail:
p2p_parse_free(&msg);
if (resp == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending GO Negotiation Response");
+ p2p_dbg(p2p, "Sending GO Negotiation Response");
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
wpabuf_free(resp);
return;
}
@@ -778,9 +852,8 @@ 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), 250) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(resp), wpabuf_len(resp), 500) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(resp);
@@ -798,14 +871,16 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
u8 group_capab;
size_t extra = 0;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Building GO Negotiation Confirm");
+ p2p_dbg(p2p, "Building GO Negotiation Confirm");
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -850,6 +925,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
return buf;
}
@@ -858,20 +936,17 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
struct p2p_device *dev;
- struct wpabuf *conf;
int go = -1;
struct p2p_message msg;
u8 status = P2P_SC_SUCCESS;
int freq;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Negotiation Response from " MACSTR
+ p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR
" (freq=%d)", MAC2STR(sa), rx_freq);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
dev != p2p->go_neg_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Not ready for GO negotiation with " MACSTR,
+ p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
return;
}
@@ -880,45 +955,42 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
return;
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Was not expecting GO Negotiation Response - "
- "ignore");
+ p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore");
p2p_parse_free(&msg);
return;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
if (msg.dialog_token != dev->dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected Dialog Token %u (expected %u)",
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
return;
}
if (!msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Status attribute received");
+ p2p_dbg(p2p, "No Status attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (*msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation rejected: status %d",
- *msg.status);
+ p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
dev->go_neg_req_sent = 0;
if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Wait for the peer to become ready for "
- "GO Negotiation");
+ p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
dev->flags |= P2P_DEV_NOT_YET_READY;
- dev->wait_count = 0;
- p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p,
+ NULL);
+ eloop_register_timeout(120, 0, p2p_go_neg_wait_timeout,
+ p2p, NULL);
+ if (p2p->state == P2P_CONNECT_LISTEN)
+ p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
+ else
+ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
p2p_set_timeout(p2p, 0, 0);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Stop GO Negotiation attempt");
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_dbg(p2p, "Stop GO Negotiation attempt");
+ p2p_go_neg_failed(p2p, *msg.status);
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_parse_free(&msg);
@@ -926,9 +998,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
if (!msg.capability) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Capability attribute missing from GO "
- "Negotiation Response");
+ p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -936,9 +1006,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
if (!msg.p2p_device_info) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory P2P Device Info attribute missing "
- "from GO Negotiation Response");
+ p2p_dbg(p2p, "Mandatory P2P Device Info attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -946,22 +1014,18 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
if (!msg.intended_addr) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Intended P2P Interface Address attribute "
- "received");
+ p2p_dbg(p2p, "No Intended P2P Interface Address attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (!msg.go_intent) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No GO Intent attribute received");
+ p2p_dbg(p2p, "No GO Intent attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid GO Intent value (%u) received",
+ p2p_dbg(p2p, "Invalid GO Intent value (%u) received",
*msg.go_intent >> 1);
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -969,8 +1033,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
if (go < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Incompatible GO Intent");
+ p2p_dbg(p2p, "Incompatible GO Intent");
status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
goto fail;
}
@@ -980,20 +1043,14 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p->ssid_len = msg.group_id_len - ETH_ALEN;
os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
} else if (!go) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory P2P Group ID attribute missing from "
- "GO Negotiation Response");
+ p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Response");
p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
-#endif /* CONFIG_P2P_STRICT */
}
if (!msg.config_timeout) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Configuration Timeout attribute "
- "missing from GO Negotiation Response");
+ p2p_dbg(p2p, "Mandatory Configuration Timeout attribute missing from GO Negotiation Response");
#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
@@ -1008,76 +1065,81 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
* Note: P2P Client may omit Operating Channel attribute to
* indicate it does not have a preference.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Operating Channel attribute received");
+ p2p_dbg(p2p, "No Operating Channel attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (!msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Channel List attribute received");
+ p2p_dbg(p2p, "No Channel List attribute received");
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
if (p2p_peer_channels(p2p, dev, msg.channel_list,
msg.channel_list_len) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
if (msg.operating_channel) {
- dev->oper_freq = p2p_channel_to_freq((const char *)
- msg.operating_channel,
- msg.operating_channel[3],
+ dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
msg.operating_channel[4]);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
- "channel preference: %d MHz", dev->oper_freq);
+ p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
+ dev->oper_freq);
} else
dev->oper_freq = 0;
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Display");
+ p2p_dbg(p2p, "PIN from peer Display");
if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_USER_SPECIFIED:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer entered PIN on Keypad");
+ p2p_dbg(p2p, "Peer entered PIN on Keypad");
if (dev->wps_method != WPS_PIN_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
case DEV_PW_PUSHBUTTON:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer using pushbutton");
+ p2p_dbg(p2p, "Peer using pushbutton");
if (dev->wps_method != WPS_PBC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ case DEV_PW_P2PS_DEFAULT:
+ p2p_dbg(p2p, "P2P: Peer using P2PS default pin");
+ if (dev->wps_method != WPS_P2PS) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
p2p_wps_method_str(dev->wps_method));
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
break;
default:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported Device Password ID %d",
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
+ p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
@@ -1089,18 +1151,19 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p_set_state(p2p, P2P_GO_NEG);
p2p_clear_timeout(p2p);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
fail:
- conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status,
- msg.operating_channel, go);
+ /* Store GO Negotiation Confirmation to allow retransmission */
+ wpabuf_free(dev->go_neg_conf);
+ dev->go_neg_conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token,
+ status, msg.operating_channel,
+ go);
p2p_parse_free(&msg);
- if (conf == NULL)
+ if (dev->go_neg_conf == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending GO Negotiation Confirm");
+ p2p_dbg(p2p, "Sending GO Negotiation Confirm");
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -1110,13 +1173,22 @@ fail:
freq = rx_freq;
else
freq = dev->listen_freq;
+
+ dev->go_neg_conf_freq = freq;
+ dev->go_neg_conf_sent = 0;
+
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
- wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
- p2p_go_neg_failed(p2p, dev, -1);
+ wpabuf_head(dev->go_neg_conf),
+ wpabuf_len(dev->go_neg_conf), 200) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
+ p2p_go_neg_failed(p2p, -1);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ } else
+ dev->go_neg_conf_sent++;
+ if (status != P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "GO Negotiation failed");
+ p2p_go_neg_failed(p2p, status);
}
- wpabuf_free(conf);
}
@@ -1126,22 +1198,18 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
struct p2p_device *dev;
struct p2p_message msg;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GO Negotiation Confirm from " MACSTR,
+ p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR,
MAC2STR(sa));
dev = p2p_get_device(p2p, sa);
if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
dev != p2p->go_neg_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Not ready for GO negotiation with " MACSTR,
+ p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
return;
}
if (p2p->pending_action_state == P2P_PENDING_GO_NEG_RESPONSE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopped waiting "
- "for TX status on GO Negotiation Response since we "
- "already received Confirmation");
+ p2p_dbg(p2p, "Stopped waiting for TX status on GO Negotiation Response since we already received Confirmation");
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
}
@@ -1149,31 +1217,28 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
return;
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Was not expecting GO Negotiation Confirm - "
- "ignore");
+ p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore");
+ p2p_parse_free(&msg);
return;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (msg.dialog_token != dev->dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected Dialog Token %u (expected %u)",
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
return;
}
if (!msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Status attribute received");
+ p2p_dbg(p2p, "No Status attribute received");
p2p_parse_free(&msg);
return;
}
if (*msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Negotiation rejected: status %d",
- *msg.status);
+ p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
return;
}
@@ -1183,30 +1248,31 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
p2p->ssid_len = msg.group_id_len - ETH_ALEN;
os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len);
} else if (dev->go_state == REMOTE_GO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory P2P Group ID attribute missing from "
- "GO Negotiation Confirmation");
+ p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Confirmation");
p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
+ p2p_go_neg_failed(p2p, P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
return;
-#endif /* CONFIG_P2P_STRICT */
}
if (!msg.operating_channel) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Operating Channel attribute missing "
- "from GO Negotiation Confirmation");
+ p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
#ifdef CONFIG_P2P_STRICT
p2p_parse_free(&msg);
return;
#endif /* CONFIG_P2P_STRICT */
+ } else if (dev->go_state == REMOTE_GO) {
+ int oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
+ msg.operating_channel[4]);
+ if (oper_freq != dev->oper_freq) {
+ p2p_dbg(p2p, "Updated peer (GO) operating channel preference from %d MHz to %d MHz",
+ dev->oper_freq, oper_freq);
+ dev->oper_freq = oper_freq;
+ }
}
if (!msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Operating Channel attribute missing "
- "from GO Negotiation Confirmation");
+ p2p_dbg(p2p, "Mandatory Operating Channel attribute missing from GO Negotiation Confirmation");
#ifdef CONFIG_P2P_STRICT
p2p_parse_free(&msg);
return;
@@ -1220,9 +1286,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
* This should not happen since GO negotiation has already
* been completed.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected GO Neg state - do not know which end "
- "becomes GO");
+ p2p_dbg(p2p, "Unexpected GO Neg state - do not know which end becomes GO");
return;
}
@@ -1234,8 +1298,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
* the group so that we will remain on the current channel to
* acknowledge any possible retransmission from the peer.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: 20 ms wait on current "
- "channel before starting group");
+ p2p_dbg(p2p, "20 ms wait on current channel before starting group");
os_sleep(0, 20000);
p2p_go_complete(p2p, dev);
diff --git a/contrib/wpa/src/p2p/p2p_group.c b/contrib/wpa/src/p2p/p2p_group.c
index 8687320..41ca99f 100644
--- a/contrib/wpa/src/p2p/p2p_group.c
+++ b/contrib/wpa/src/p2p/p2p_group.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
@@ -154,6 +155,7 @@ 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;
p2p_buf_add_capability(ie, dev_capab, group_capab);
}
@@ -169,6 +171,39 @@ static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa)
}
+static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+ size_t len;
+
+ if (subelems == NULL)
+ return NULL;
+
+ len = wpabuf_len(subelems) + 100;
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
+
+
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
{
struct wpabuf *ie;
@@ -180,6 +215,10 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
extra = wpabuf_len(group->p2p->wfd_ie_beacon);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
+ extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
+
ie = wpabuf_alloc(257 + extra);
if (ie == NULL)
return NULL;
@@ -189,6 +228,11 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
+ wpabuf_put_buf(ie,
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
+
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
@@ -345,8 +389,8 @@ wifi_display_build_go_ie(struct p2p_group *group)
} else {
WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
2);
- wpa_printf(MSG_DEBUG, "WFD: WFD Session Info: %u descriptors",
- count);
+ p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors",
+ count);
}
wfd_ie = wifi_display_encaps(wfd_subelems);
@@ -364,46 +408,69 @@ static void wifi_display_group_update(struct p2p_group *group)
#endif /* CONFIG_WIFI_DISPLAY */
-static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
+void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf,
+ int max_clients)
{
u8 *group_info;
- struct wpabuf *ie;
+ int count = 0;
struct p2p_group_member *m;
- u8 *len;
- size_t extra = 0;
-#ifdef CONFIG_WIFI_DISPLAY
- if (group->wfd_ie)
- extra += wpabuf_len(group->wfd_ie);
-#endif /* CONFIG_WIFI_DISPLAY */
+ p2p_dbg(group->p2p, "* P2P Group Info");
+ group_info = wpabuf_put(buf, 0);
+ wpabuf_put_u8(buf, P2P_ATTR_GROUP_INFO);
+ wpabuf_put_le16(buf, 0); /* Length to be filled */
+ for (m = group->members; m; m = m->next) {
+ p2p_client_info(buf, m);
+ count++;
+ if (max_clients >= 0 && count >= max_clients)
+ break;
+ }
+ WPA_PUT_LE16(group_info + 1,
+ (u8 *) wpabuf_put(buf, 0) - group_info - 3);
+}
- ie = wpabuf_alloc(257 + extra);
- if (ie == NULL)
- return NULL;
-#ifdef CONFIG_WIFI_DISPLAY
- if (group->wfd_ie)
- wpabuf_put_buf(ie, group->wfd_ie);
-#endif /* CONFIG_WIFI_DISPLAY */
+void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf)
+{
+ p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid,
+ group->cfg->ssid_len);
+}
- len = p2p_buf_add_ie_hdr(ie);
- p2p_group_add_common_ies(group, ie);
- p2p_group_add_noa(ie, group->noa);
+static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
+{
+ struct wpabuf *p2p_subelems, *ie;
+
+ p2p_subelems = wpabuf_alloc(500);
+ if (p2p_subelems == NULL)
+ return NULL;
+
+ p2p_group_add_common_ies(group, p2p_subelems);
+ p2p_group_add_noa(p2p_subelems, group->noa);
/* P2P Device Info */
- p2p_buf_add_device_info(ie, group->p2p, NULL);
-
- /* P2P Group Info */
- group_info = wpabuf_put(ie, 0);
- wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
- wpabuf_put_le16(ie, 0); /* Length to be filled */
- for (m = group->members; m; m = m->next)
- p2p_client_info(ie, m);
- WPA_PUT_LE16(group_info + 1,
- (u8 *) wpabuf_put(ie, 0) - group_info - 3);
+ p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
- p2p_buf_update_ie_hdr(ie, len);
+ /* P2P Group Info: Only when at least one P2P Client is connected */
+ if (group->members)
+ p2p_buf_add_group_info(group, p2p_subelems, -1);
+
+ ie = p2p_group_encaps_probe_resp(p2p_subelems);
+ wpabuf_free(p2p_subelems);
+
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]) {
+ struct wpabuf *extra;
+ extra = wpabuf_dup(group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]);
+ ie = wpabuf_concat(extra, ie);
+ }
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie) {
+ struct wpabuf *wfd = wpabuf_dup(group->wfd_ie);
+ ie = wpabuf_concat(wfd, ie);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
return ie;
}
@@ -537,6 +604,8 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
if (group == NULL)
return -1;
+ p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0);
+
m = os_zalloc(sizeof(*m));
if (m == NULL)
return -1;
@@ -556,7 +625,7 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
m->next = group->members;
group->members = m;
group->num_members++;
- wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
+ p2p_dbg(group->p2p, "Add client " MACSTR
" to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
m->client_info ? 1 : 0,
@@ -582,6 +651,10 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
extra = wpabuf_len(group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP])
+ extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]);
+
/*
* (Re)Association Response - P2P IE
* Status attribute (shall be present when association request is
@@ -597,6 +670,11 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
wpabuf_put_buf(resp, group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP])
+ wpabuf_put_buf(resp,
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]);
+
rlen = p2p_buf_add_ie_hdr(resp);
if (status != P2P_SC_SUCCESS)
p2p_buf_add_status(resp, status);
@@ -609,8 +687,8 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
{
if (p2p_group_remove_member(group, addr)) {
- wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
- "client " MACSTR " from group; num_members=%u/%u",
+ p2p_dbg(group->p2p, "Remove client " MACSTR
+ " from group; num_members=%u/%u",
MAC2STR(addr), group->num_members,
group->cfg->max_clients);
if (group->num_members == group->cfg->max_clients - 1)
@@ -822,20 +900,18 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
m = p2p_group_get_client(group, dev_id);
if (m == NULL || m->client_info == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this "
- "group " MACSTR,
- MAC2STR(group->cfg->interface_addr));
+ p2p_dbg(group->p2p, "Requested client was not in this group "
+ MACSTR, MAC2STR(group->cfg->interface_addr));
return -1;
}
if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_printf(MSG_DEBUG, "P2P: Requested client does not support "
- "client discoverability");
+ p2p_dbg(group->p2p, "Requested client does not support client discoverability");
return -1;
}
- wpa_printf(MSG_DEBUG, "P2P: Schedule GO Discoverability Request to be "
- "sent to " MACSTR, MAC2STR(dev_id));
+ p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to "
+ MACSTR, MAC2STR(dev_id));
req = p2p_build_go_disc_req();
if (req == NULL)
@@ -850,8 +926,7 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
group->cfg->interface_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
wpabuf_free(req);
@@ -876,7 +951,7 @@ u8 p2p_group_presence_req(struct p2p_group *group,
m = p2p_group_get_client_iface(group, client_interface_addr);
if (m == NULL || m->client_info == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Client was not in this group");
+ p2p_dbg(group->p2p, "Client was not in this group");
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
}
@@ -889,9 +964,9 @@ u8 p2p_group_presence_req(struct p2p_group *group,
else
curr_noa_len = -1;
if (curr_noa_len < 0)
- wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA");
+ p2p_dbg(group->p2p, "Failed to fetch current NoA");
else if (curr_noa_len == 0)
- wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized");
+ p2p_dbg(group->p2p, "No NoA being advertized");
else
wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
curr_noa_len);
@@ -906,10 +981,22 @@ u8 p2p_group_presence_req(struct p2p_group *group,
unsigned int p2p_get_group_num_members(struct p2p_group *group)
{
+ if (!group)
+ return 0;
+
return group->num_members;
}
+int p2p_client_limit_reached(struct p2p_group *group)
+{
+ if (!group || !group->cfg)
+ return 1;
+
+ return group->num_members >= group->cfg->max_clients;
+}
+
+
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
{
struct p2p_group_member *iter = *next;
@@ -924,7 +1011,7 @@ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
if (!iter)
return NULL;
- return iter->addr;
+ return iter->dev_addr;
}
@@ -951,3 +1038,36 @@ int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
group->cfg->ssid_len) == 0;
}
+
+
+void p2p_group_force_beacon_update_ies(struct p2p_group *group)
+{
+ group->beacon_update = 1;
+ p2p_group_update_ies(group);
+}
+
+
+int p2p_group_get_freq(struct p2p_group *group)
+{
+ return group->cfg->freq;
+}
+
+
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group)
+{
+ return group->cfg;
+}
+
+
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data)
+{
+ unsigned int i;
+
+ for (i = 0; i < p2p->num_groups; i++) {
+ if (!group_callback(p2p->groups[i], user_data))
+ break;
+ }
+}
diff --git a/contrib/wpa/src/p2p/p2p_i.h b/contrib/wpa/src/p2p/p2p_i.h
index 27fef01..6af19ce 100644
--- a/contrib/wpa/src/p2p/p2p_i.h
+++ b/contrib/wpa/src/p2p/p2p_i.h
@@ -12,6 +12,17 @@
#include "utils/list.h"
#include "p2p.h"
+#define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
+
+enum p2p_role_indication;
+
+/*
+ * To force Service Instances to fit within a single P2P Tag, MAX_SVC_ADV_LEN
+ * must equal 248 or less. Must have a minimum size of 19.
+ */
+#define MAX_SVC_ADV_LEN 600
+#define MAX_SVC_ADV_IE_LEN (9 + MAX_SVC_ADV_LEN + (5 * (MAX_SVC_ADV_LEN / 240)))
+
enum p2p_go_state {
UNKNOWN_GO,
LOCAL_GO,
@@ -23,9 +34,11 @@ enum p2p_go_state {
*/
struct p2p_device {
struct dl_list list;
- struct os_time last_seen;
+ struct os_reltime last_seen;
int listen_freq;
+ int oob_go_neg_freq;
enum p2p_wps_method wps_method;
+ u16 oob_pw_id;
struct p2p_peer_info info;
@@ -52,6 +65,7 @@ struct p2p_device {
int go_neg_req_sent;
enum p2p_go_state go_state;
u8 dialog_token;
+ u8 tie_breaker;
u8 intended_addr[ETH_ALEN];
char country[3];
@@ -76,8 +90,6 @@ struct p2p_device {
#define P2P_DEV_PROBE_REQ_ONLY BIT(0)
#define P2P_DEV_REPORTED BIT(1)
#define P2P_DEV_NOT_YET_READY BIT(2)
-#define P2P_DEV_SD_INFO BIT(3)
-#define P2P_DEV_SD_SCHEDULE BIT(4)
#define P2P_DEV_PD_PEER_DISPLAY BIT(5)
#define P2P_DEV_PD_PEER_KEYPAD BIT(6)
#define P2P_DEV_USER_REJECTED BIT(7)
@@ -91,18 +103,40 @@ struct p2p_device {
#define P2P_DEV_REPORTED_ONCE BIT(15)
#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
#define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
+#define P2P_DEV_NO_PREF_CHAN BIT(18)
+#define P2P_DEV_WAIT_INV_REQ_ACK BIT(19)
+#define P2P_DEV_P2PS_REPORTED BIT(20)
+#define P2P_DEV_PD_PEER_P2PS BIT(21)
unsigned int flags;
int status; /* enum p2p_status_code */
unsigned int wait_count;
unsigned int connect_reqs;
unsigned int invitation_reqs;
+ unsigned int sd_reqs;
u16 ext_listen_period;
u16 ext_listen_interval;
u8 go_timeout;
u8 client_timeout;
+
+ /**
+ * go_neg_conf_sent - Number of GO Negotiation Confirmation retries
+ */
+ u8 go_neg_conf_sent;
+
+ /**
+ * freq - Frquency on which the GO Negotiation Confirmation is sent
+ */
+ int go_neg_conf_freq;
+
+ /**
+ * go_neg_conf - GO Negotiation Confirmation frame
+ */
+ struct wpabuf *go_neg_conf;
+
+ int sd_pending_bcast_queries;
};
struct p2p_sd_query {
@@ -203,16 +237,6 @@ struct p2p_data {
* P2P_INVITE_LISTEN - Listen during Invite
*/
P2P_INVITE_LISTEN,
-
- /**
- * P2P_SEARCH_WHEN_READY - Waiting to start Search
- */
- P2P_SEARCH_WHEN_READY,
-
- /**
- * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search
- */
- P2P_CONTINUE_SEARCH_WHEN_READY,
} state;
/**
@@ -245,8 +269,17 @@ struct p2p_data {
*/
struct p2p_device *invite_peer;
+ /**
+ * last_p2p_find_oper - Pointer to last pre-find operation peer
+ */
+ struct p2p_device *last_p2p_find_oper;
+
const u8 *invite_go_dev_addr;
u8 invite_go_dev_addr_buf[ETH_ALEN];
+ int invite_dev_pw_id;
+
+ unsigned int retry_invite_req:1;
+ unsigned int retry_invite_req_sent:1;
/**
* sd_peer - Pointer to Service Discovery peer
@@ -258,6 +291,12 @@ struct p2p_data {
*/
struct p2p_sd_query *sd_query;
+ /**
+ * num_p2p_sd_queries - Total number of broadcast SD queries present in
+ * the list
+ */
+ int num_p2p_sd_queries;
+
/* GO Negotiation data */
/**
@@ -314,6 +353,8 @@ struct p2p_data {
*/
struct p2p_channels channels;
+ struct wpa_freq_range_list no_go_freq;
+
enum p2p_pending_action_state {
P2P_NO_PENDING_ACTION,
P2P_PENDING_GO_NEG_REQUEST,
@@ -322,6 +363,7 @@ struct p2p_data {
P2P_PENDING_GO_NEG_CONFIRM,
P2P_PENDING_SD,
P2P_PENDING_PD,
+ P2P_PENDING_PD_RESPONSE,
P2P_PENDING_INVITATION_REQUEST,
P2P_PENDING_INVITATION_RESPONSE,
P2P_PENDING_DEV_DISC_REQUEST,
@@ -383,6 +425,8 @@ struct p2p_data {
} start_after_scan;
u8 after_scan_peer[ETH_ALEN];
struct p2p_pending_action_tx *after_scan_tx;
+ unsigned int after_scan_tx_in_progress:1;
+ unsigned int send_action_in_progress:1;
/* Requested device types for find/search */
unsigned int num_req_dev_types;
@@ -390,6 +434,8 @@ struct p2p_data {
u8 *find_dev_id;
u8 find_dev_id_buf[ETH_ALEN];
+ struct os_reltime find_start; /* time of last p2p_find start */
+
struct p2p_group **groups;
size_t num_groups;
@@ -413,6 +459,7 @@ struct p2p_data {
int best_freq_24;
int best_freq_5;
int best_freq_overall;
+ int own_freq_preference;
/**
* wps_vendor_ext - WPS Vendor Extensions to add
@@ -436,6 +483,14 @@ struct p2p_data {
*/
int pd_retries;
+ /**
+ * pd_force_freq - Forced frequency for PD retries or 0 to auto-select
+ *
+ * This is is used during PD retries for join-a-group case to use the
+ * correct operating frequency determined from a BSS entry for the GO.
+ */
+ int pd_force_freq;
+
u8 go_timeout;
u8 client_timeout;
@@ -443,6 +498,20 @@ struct p2p_data {
unsigned int search_delay;
int in_search_delay;
+ u8 pending_reg_class;
+ u8 pending_channel;
+ u8 pending_channel_forced;
+
+ /* ASP Support */
+ struct p2ps_advertisement *p2ps_adv_list;
+ struct p2ps_provision *p2ps_prov;
+ u8 wild_card_hash[P2PS_HASH_LEN];
+ u8 query_hash[P2P_MAX_QUERY_HASH * P2PS_HASH_LEN];
+ u8 query_count;
+ u8 p2ps_seek;
+ u8 p2ps_seek_count;
+ u8 p2ps_svc_found;
+
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie_beacon;
struct wpabuf *wfd_ie_probe_req;
@@ -456,6 +525,10 @@ struct p2p_data {
struct wpabuf *wfd_assoc_bssid;
struct wpabuf *wfd_coupled_sink_info;
#endif /* CONFIG_WIFI_DISPLAY */
+
+ u16 authorized_oob_dev_pw_id;
+
+ struct wpabuf **vendor_elem;
};
/**
@@ -497,6 +570,8 @@ struct p2p_message {
const u8 *minor_reason_code;
+ const u8 *oob_go_neg_channel;
+
/* P2P Device Info */
const u8 *p2p_device_info;
size_t p2p_device_info_len;
@@ -508,6 +583,7 @@ struct p2p_message {
/* WPS IE */
u16 dev_password_id;
+ int dev_password_id_present;
u16 wps_config_methods;
const u8 *wps_pri_dev_type;
const u8 *wps_sec_dev_type_list;
@@ -522,12 +598,39 @@ struct p2p_message {
size_t model_number_len;
const u8 *serial_number;
size_t serial_number_len;
+ const u8 *oob_dev_password;
+ size_t oob_dev_password_len;
/* DS Parameter Set IE */
const u8 *ds_params;
/* SSID IE */
const u8 *ssid;
+
+ /* P2PS */
+ u8 service_hash_count;
+ const u8 *service_hash;
+
+ const u8 *session_info;
+ size_t session_info_len;
+
+ const u8 *conn_cap;
+
+ const u8 *adv_id;
+ const u8 *adv_mac;
+
+ const u8 *adv_service_instance;
+ size_t adv_service_instance_len;
+
+ const u8 *session_id;
+ const u8 *session_mac;
+
+ const u8 *feature_cap;
+ size_t feature_cap_len;
+
+ const u8 *persistent_dev;
+ const u8 *persistent_ssid;
+ size_t persistent_ssid_len;
};
@@ -551,19 +654,33 @@ struct p2p_group_info {
/* p2p_utils.c */
int p2p_random(char *buf, size_t len);
-int p2p_channel_to_freq(const char *country, int reg_class, int channel);
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
- u8 *channel);
+int p2p_channel_to_freq(int op_class, int channel);
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b);
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res);
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list);
int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
u8 channel);
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+ const struct p2p_channels *chan);
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+ u8 *op_class, u8 *op_channel);
+int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
+ u8 *op_channel);
/* p2p_parse.c */
int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg);
int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg);
+int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
+ size_t p2p_len, struct p2p_message *msg);
void p2p_parse_free(struct p2p_message *msg);
int p2p_attr_text(struct wpabuf *data, char *buf, char *end);
int p2p_group_info_parse(const u8 *gi, size_t gi_len,
@@ -586,7 +703,12 @@ u8 p2p_group_presence_req(struct p2p_group *group,
int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
size_t group_id_len);
void p2p_group_update_ies(struct p2p_group *group);
+void p2p_group_force_beacon_update_ies(struct p2p_group *group);
struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
+void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf,
+ int max_clients);
+void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf);
+int p2p_group_get_freq(struct p2p_group *group);
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
@@ -618,8 +740,23 @@ void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
u16 interval);
void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr);
+void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
+ u8 oper_class, u8 channel,
+ enum p2p_role_indication role);
+void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p);
+void p2p_buf_add_session_info(struct wpabuf *buf, const char *info);
+void p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap);
+void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac);
+void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
+ u8 count, const u8 *hash,
+ struct p2ps_advertisement *adv_list);
+void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac);
+void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len,
+ const u8 *mask);
+void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
+ const u8 *ssid, size_t ssid_len);
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -665,7 +802,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len);
int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
- const u8 *go_dev_addr);
+ const u8 *go_dev_addr, int dev_pw_id);
void p2p_invitation_req_cb(struct p2p_data *p2p, int success);
void p2p_invitation_resp_cb(struct p2p_data *p2p, int success);
@@ -693,13 +830,12 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
struct p2p_device *dev, struct p2p_message *msg);
int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
- unsigned int age_ms, int level, const u8 *ies,
+ struct os_reltime *rx_time, int level, const u8 *ies,
size_t ies_len, int scan_res);
struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
const u8 *addr);
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status);
+void p2p_go_neg_failed(struct p2p_data *p2p, int status);
void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer);
int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
@@ -710,5 +846,17 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time);
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ unsigned int force_freq, unsigned int pref_freq,
+ int go);
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ u8 *status);
+void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
#endif /* P2P_I_H */
diff --git a/contrib/wpa/src/p2p/p2p_invitation.c b/contrib/wpa/src/p2p/p2p_invitation.c
index 983dd6b..558c6dd 100644
--- a/contrib/wpa/src/p2p/p2p_invitation.c
+++ b/contrib/wpa/src/p2p/p2p_invitation.c
@@ -10,13 +10,15 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "p2p_i.h"
#include "p2p.h"
static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
struct p2p_device *peer,
- const u8 *go_dev_addr)
+ const u8 *go_dev_addr,
+ int dev_pw_id)
{
struct wpabuf *buf;
u8 *len;
@@ -44,6 +46,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
extra = wpabuf_len(wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -62,8 +67,11 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
p2p->client_timeout);
p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
P2P_INVITATION_FLAGS_TYPE : 0);
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
- p2p->op_reg_class, p2p->op_channel);
+ if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT ||
+ !(peer->flags & P2P_DEV_NO_PREF_CHAN))
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->op_reg_class,
+ p2p->op_channel);
if (p2p->inv_bssid_set)
p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
@@ -82,6 +90,14 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
wpabuf_put_buf(buf, wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
+ if (dev_pw_id >= 0) {
+ /* WSC IE in Invitation Request for NFC static handover */
+ p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
+ }
+
return buf;
}
@@ -158,13 +174,12 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
u8 group_bssid[ETH_ALEN], *bssid;
int op_freq = 0;
u8 reg_class = 0, channel = 0;
- struct p2p_channels intersection, *channels = NULL;
+ struct p2p_channels all_channels, intersection, *channels = NULL;
int persistent;
os_memset(group_bssid, 0, sizeof(group_bssid));
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Invitation Request from " MACSTR " (freq=%d)",
+ p2p_dbg(p2p, "Received Invitation Request from " MACSTR " (freq=%d)",
MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
@@ -172,14 +187,12 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request from unknown peer "
- MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Invitation Request from unknown peer " MACSTR,
+ MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request add device failed "
+ p2p_dbg(p2p, "Invitation Request add device failed "
MACSTR, MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
goto fail;
@@ -187,18 +200,16 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
dev = p2p_get_device(p2p, sa);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Reject Invitation Request from unknown "
- "peer " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Reject Invitation Request from unknown peer "
+ MACSTR, MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
goto fail;
}
}
if (!msg.group_id || !msg.channel_list) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory attribute missing in Invitation "
- "Request from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Mandatory attribute missing in Invitation Request from "
+ MACSTR, MAC2STR(sa));
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
}
@@ -211,46 +222,61 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
* the request was for a persistent group if the attribute is
* missing.
*/
- wpa_printf(MSG_DEBUG, "P2P: Mandatory Invitation Flags "
- "attribute missing from Invitation Request");
+ p2p_dbg(p2p, "Mandatory Invitation Flags attribute missing from Invitation Request");
persistent = 1;
}
- if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
+ p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels,
+ &all_channels);
+
+ if (p2p_peer_channels_check(p2p, &all_channels, dev,
msg.channel_list, msg.channel_list_len) <
0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
+ p2p_dbg(p2p, "No common channels found");
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
+ p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "own client channels", &all_channels);
+ p2p_channels_dump(p2p, "peer channels", &dev->channels);
+ p2p_channels_intersect(&all_channels, &dev->channels,
+ &intersection);
+ p2p_channels_dump(p2p, "intersection", &intersection);
+
if (p2p->cfg->invitation_process) {
status = p2p->cfg->invitation_process(
p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
- &go, group_bssid, &op_freq, persistent);
+ &go, group_bssid, &op_freq, persistent, &intersection,
+ msg.dev_password_id_present ? msg.dev_password_id : -1);
+ }
+
+ if (go) {
+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ &intersection);
+ p2p_channels_dump(p2p, "intersection(GO)", &intersection);
+ if (intersection.reg_classes == 0) {
+ p2p_dbg(p2p, "No common channels found (GO)");
+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ goto fail;
+ }
}
if (op_freq) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invitation "
- "processing forced frequency %d MHz", op_freq);
- if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
- &reg_class, &channel) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown forced freq %d MHz from "
- "invitation_process()", op_freq);
+ p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
+ op_freq);
+ if (p2p_freq_to_channel(op_freq, &reg_class, &channel) < 0) {
+ p2p_dbg(p2p, "Unknown forced freq %d MHz from invitation_process()",
+ op_freq);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
if (!p2p_channels_includes(&intersection, reg_class, channel))
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: forced freq %d MHz not in the supported "
- "channels interaction", op_freq);
+ p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+ op_freq);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
@@ -258,28 +284,21 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
if (status == P2P_SC_SUCCESS)
channels = &intersection;
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No forced channel from invitation processing - "
- "figure out best one to use");
+ p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
/* Default to own configuration as a starting point */
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own default "
- "op_class %d channel %d",
+ p2p_dbg(p2p, "Own default op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
/* Use peer preference if specified and compatible */
if (msg.operating_channel) {
int req_freq;
req_freq = p2p_channel_to_freq(
- (const char *) msg.operating_channel,
msg.operating_channel[3],
msg.operating_channel[4]);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer "
- "operating channel preference: %d MHz",
+ p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
req_freq);
if (req_freq > 0 &&
p2p_channels_includes(&intersection,
@@ -287,56 +306,47 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
msg.operating_channel[4])) {
p2p->op_reg_class = msg.operating_channel[3];
p2p->op_channel = msg.operating_channel[4];
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Use peer preference op_class %d "
- "channel %d",
+ p2p_dbg(p2p, "Use peer preference op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot use peer channel "
- "preference");
+ p2p_dbg(p2p, "Cannot use peer channel preference");
}
}
- if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
+ /* Reselect the channel only for the case of the GO */
+ if (go &&
+ !p2p_channels_includes(&intersection, p2p->op_reg_class,
p2p->op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Initially selected channel (op_class %d "
- "channel %d) not in channel intersection - try "
- "to reselect",
+ p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect",
p2p->op_reg_class, p2p->op_channel);
p2p_reselect_channel(p2p, &intersection);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Re-selection result: op_class %d "
- "channel %d",
+ p2p_dbg(p2p, "Re-selection result: op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
if (!p2p_channels_includes(&intersection,
p2p->op_reg_class,
p2p->op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer does not support selected "
- "operating channel (reg_class=%u "
- "channel=%u)",
+ p2p_dbg(p2p, "Peer does not support selected operating channel (reg_class=%u channel=%u)",
p2p->op_reg_class, p2p->op_channel);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
+ } else if (go && !(dev->flags & P2P_DEV_FORCE_FREQ) &&
+ !p2p->cfg->cfg_op_channel) {
+ p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p_reselect_channel(p2p, &intersection);
}
- op_freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->op_reg_class,
+ op_freq = p2p_channel_to_freq(p2p->op_reg_class,
p2p->op_channel);
if (op_freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown operational channel "
- "(country=%c%c reg_class=%u channel=%u)",
+ p2p_dbg(p2p, "Unknown operational channel (country=%c%c reg_class=%u channel=%u)",
p2p->cfg->country[0], p2p->cfg->country[1],
p2p->op_reg_class, p2p->op_channel);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
- "channel - %d MHz", op_freq);
+ p2p_dbg(p2p, "Selected operating channel - %d MHz", op_freq);
if (status == P2P_SC_SUCCESS) {
reg_class = p2p->op_reg_class;
@@ -359,12 +369,10 @@ fail:
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
goto out;
}
@@ -378,12 +386,17 @@ fail:
p2p->inv_group_bssid_ptr = p2p->inv_group_bssid;
} else
p2p->inv_group_bssid_ptr = NULL;
- if (msg.group_id_len - ETH_ALEN <= 32) {
- os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
- msg.group_id_len - ETH_ALEN);
- p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
+ if (msg.group_id) {
+ if (msg.group_id_len - ETH_ALEN <= 32) {
+ os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
+ msg.group_id_len - ETH_ALEN);
+ p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
+ }
+ os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN);
+ } else {
+ p2p->inv_ssid_len = 0;
+ os_memset(p2p->inv_go_dev_addr, 0, ETH_ALEN);
}
- os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN);
p2p->inv_status = status;
p2p->inv_op_freq = op_freq;
@@ -391,8 +404,7 @@ fail:
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
}
out:
@@ -406,40 +418,120 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
{
struct p2p_device *dev;
struct p2p_message msg;
+ struct p2p_channels intersection, *channels = NULL;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Invitation Response from " MACSTR,
+ p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
MAC2STR(sa));
dev = p2p_get_device(p2p, sa);
if (dev == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Invitation Response from unknown peer "
+ p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
if (dev != p2p->invite_peer) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore unexpected Invitation Response from peer "
+ p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
- if (p2p_parse(data, len, &msg))
+ if (p2p_parse(data, len, &msg)) {
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
+ }
if (!msg.status) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Mandatory Status attribute missing in "
- "Invitation Response from " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
+ MACSTR, MAC2STR(sa));
p2p_parse_free(&msg);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
- if (p2p->cfg->invitation_result)
+ /*
+ * We should not really receive a replayed response twice since
+ * duplicate frames are supposed to be dropped. However, not all drivers
+ * do that for pre-association frames. We did not use to verify dialog
+ * token matches for invitation response frames, but that check can be
+ * safely used to drop a replayed response to the previous Invitation
+ * Request in case the suggested operating channel was changed. This
+ * allows a duplicated reject frame to be dropped with the assumption
+ * that the real response follows after it.
+ */
+ if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+ p2p->retry_invite_req_sent &&
+ msg.dialog_token != dev->dialog_token) {
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
+ msg.dialog_token, dev->dialog_token);
+ p2p_parse_free(&msg);
+ return;
+ }
+
+ if (*msg.status == P2P_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->retry_invite_req = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ p2p_set_state(p2p, P2P_INVITE);
+ p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p->retry_invite_req_sent = 1;
+ p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+ p2p->invite_dev_pw_id);
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->retry_invite_req = 0;
+
+ if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
+ MACSTR, MAC2STR(sa));
+#ifdef CONFIG_P2P_STRICT
+ p2p_parse_free(&msg);
+ return;
+#endif /* CONFIG_P2P_STRICT */
+ /* Try to survive without peer channel list */
+ channels = &p2p->channels;
+ } else if (!msg.channel_list) {
+ /* Non-success cases are not required to include Channel List */
+ channels = &p2p->channels;
+ } else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0) {
+ p2p_dbg(p2p, "No common channels found");
+ p2p_parse_free(&msg);
+ return;
+ } else {
+ p2p_channels_intersect(&p2p->channels, &dev->channels,
+ &intersection);
+ channels = &intersection;
+ }
+
+ if (p2p->cfg->invitation_result) {
+ int peer_oper_freq = 0;
+ int freq = p2p_channel_to_freq(p2p->op_reg_class,
+ p2p->op_channel);
+ if (freq < 0)
+ freq = 0;
+
+ if (msg.operating_channel) {
+ peer_oper_freq = p2p_channel_to_freq(
+ msg.operating_channel[3],
+ msg.operating_channel[4]);
+ if (peer_oper_freq < 0)
+ peer_oper_freq = 0;
+ }
+
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
- msg.group_bssid);
+ msg.group_bssid, channels, sa,
+ freq, peer_oper_freq);
+ }
p2p_parse_free(&msg);
@@ -450,38 +542,39 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
- const u8 *go_dev_addr)
+ const u8 *go_dev_addr, int dev_pw_id)
{
struct wpabuf *req;
int freq;
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+ if (freq <= 0)
+ freq = dev->oob_go_neg_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send Invitation Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send Invitation Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
- req = p2p_build_invitation_req(p2p, dev, go_dev_addr);
+ req = p2p_build_invitation_req(p2p, dev, go_dev_addr, dev_pw_id);
if (req == NULL)
return -1;
if (p2p->state != P2P_IDLE)
p2p_stop_listen_for_freq(p2p, freq);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Invitation Request");
+ p2p_dbg(p2p, "Sending Invitation Request");
p2p_set_state(p2p, P2P_INVITE);
p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
p2p->invite_peer = dev;
dev->invitation_reqs++;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), 500) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
/* Use P2P find to recover and retry */
p2p_set_timeout(p2p, 0, 0);
+ } else {
+ dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK;
}
wpabuf_free(req);
@@ -492,31 +585,34 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Request TX callback: success=%d", success);
+ p2p_dbg(p2p, "Invitation Request TX callback: success=%d", success);
if (p2p->invite_peer == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No pending Invite");
+ p2p_dbg(p2p, "No pending Invite");
return;
}
+ if (success)
+ p2p->invite_peer->flags &= ~P2P_DEV_WAIT_INV_REQ_ACK;
+
/*
* Use P2P find, if needed, to find the other device from its listen
* channel.
*/
p2p_set_state(p2p, P2P_INVITE);
- p2p_set_timeout(p2p, 0, 100000);
+ p2p_set_timeout(p2p, 0, success ? 500000 : 100000);
}
void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
{
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation Response TX callback: success=%d", success);
+ p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- if (success && p2p->cfg->invitation_received) {
+ if (!success)
+ p2p_dbg(p2p, "Assume Invitation Response was actually received by the peer even though Ack was not reported");
+
+ if (p2p->cfg->invitation_received) {
p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
p2p->inv_sa,
p2p->inv_group_bssid_ptr,
@@ -531,41 +627,55 @@ void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group)
+ int persistent_group, unsigned int pref_freq, int dev_pw_id)
{
struct p2p_device *dev;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Request to invite peer " MACSTR " role=%d persistent=%d "
+ p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d "
"force_freq=%u",
MAC2STR(peer), role, persistent_group, force_freq);
if (bssid)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation for BSSID " MACSTR, MAC2STR(bssid));
+ p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid));
if (go_dev_addr) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invitation for GO Device Address " MACSTR,
+ p2p_dbg(p2p, "Invitation for GO Device Address " MACSTR,
MAC2STR(go_dev_addr));
os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN);
p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf;
} else
p2p->invite_go_dev_addr = NULL;
- wpa_hexdump_ascii(MSG_DEBUG, "P2P: Invitation for SSID",
+ wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID",
ssid, ssid_len);
+ if (dev_pw_id >= 0) {
+ p2p_dbg(p2p, "Invitation to use Device Password ID %d",
+ dev_pw_id);
+ }
+ p2p->invite_dev_pw_id = dev_pw_id;
+ p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO &&
+ persistent_group && !force_freq;
+ p2p->retry_invite_req_sent = 0;
dev = p2p_get_device(p2p, peer);
- if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot invite unknown P2P Device " MACSTR,
+ if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&
+ dev->oob_go_neg_freq <= 0)) {
+ p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR,
MAC2STR(peer));
return -1;
}
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ role != P2P_INVITE_ROLE_CLIENT) < 0)
+ return -1;
+
+ if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
+ !pref_freq)
+ dev->flags |= P2P_DEV_NO_PREF_CHAN;
+ else
+ dev->flags &= ~P2P_DEV_NO_PREF_CHAN;
+
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot invite a P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot invite a P2P Device " MACSTR
" that is in a group and is not discoverable",
MAC2STR(peer));
}
@@ -574,26 +684,6 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
dev->invitation_reqs = 0;
- if (force_freq) {
- if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
- &p2p->op_reg_class, &p2p->op_channel) <
- 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported frequency %u MHz",
- force_freq);
- return -1;
- }
- p2p->channels.reg_classes = 1;
- p2p->channels.reg_class[0].channels = 1;
- p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
- p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
- } else {
- p2p->op_reg_class = p2p->cfg->op_reg_class;
- p2p->op_channel = p2p->cfg->op_channel;
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- }
-
if (p2p->state != P2P_IDLE)
p2p_stop_find(p2p);
@@ -604,5 +694,5 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
os_memcpy(p2p->inv_ssid, ssid, ssid_len);
p2p->inv_ssid_len = ssid_len;
p2p->inv_persistent = persistent_group;
- return p2p_invite_send(p2p, dev, go_dev_addr);
+ return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id);
}
diff --git a/contrib/wpa/src/p2p/p2p_parse.c b/contrib/wpa/src/p2p/p2p_parse.c
index 097a31d..fd6a461 100644
--- a/contrib/wpa/src/p2p/p2p_parse.c
+++ b/contrib/wpa/src/p2p/p2p_parse.c
@@ -268,6 +268,125 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u",
*msg->minor_reason_code);
break;
+ case P2P_ATTR_OOB_GO_NEG_CHANNEL:
+ if (len < 6) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg "
+ "Channel attribute (length %d)", len);
+ return -1;
+ }
+ msg->oob_go_neg_channel = data;
+ wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: "
+ "Country %c%c(0x%02x) Operating Class %d "
+ "Channel Number %d Role %d",
+ data[0], data[1], data[2], data[3], data[4],
+ data[5]);
+ break;
+ case P2P_ATTR_SERVICE_HASH:
+ if (len < P2PS_HASH_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Service Hash (length %u)",
+ len);
+ return -1;
+ }
+ msg->service_hash_count = len / P2PS_HASH_LEN;
+ msg->service_hash = data;
+ wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len);
+ break;
+ case P2P_ATTR_SESSION_INFORMATION_DATA:
+ msg->session_info = data;
+ msg->session_info_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p",
+ len, data);
+ break;
+ case P2P_ATTR_CONNECTION_CAPABILITY:
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Connection Capability (length %u)",
+ len);
+ return -1;
+ }
+ msg->conn_cap = data;
+ wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
+ *msg->conn_cap);
+ break;
+ case P2P_ATTR_ADVERTISEMENT_ID:
+ if (len < 10) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Advertisement ID (length %u)",
+ len);
+ return -1;
+ }
+ msg->adv_id = data;
+ msg->adv_mac = &data[sizeof(u32)];
+ wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x",
+ WPA_GET_LE32(data));
+ break;
+ case P2P_ATTR_ADVERTISED_SERVICE:
+ if (len < 8) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Service Instance (length %u)",
+ len);
+ return -1;
+ }
+ msg->adv_service_instance = data;
+ msg->adv_service_instance_len = len;
+ if (len <= 255 + 8) {
+ char str[256];
+ u8 namelen;
+
+ namelen = data[6];
+ if (namelen > len - 7)
+ break;
+ os_memcpy(str, &data[7], namelen);
+ str[namelen] = '\0';
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s",
+ WPA_GET_LE32(data), str);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p",
+ data);
+ }
+ break;
+ case P2P_ATTR_SESSION_ID:
+ if (len < sizeof(u32) + ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Session ID Info (length %u)",
+ len);
+ return -1;
+ }
+ msg->session_id = data;
+ msg->session_mac = &data[sizeof(u32)];
+ wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR,
+ WPA_GET_LE32(data), MAC2STR(msg->session_mac));
+ break;
+ case P2P_ATTR_FEATURE_CAPABILITY:
+ if (!len) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Feature Capability (length %u)",
+ len);
+ return -1;
+ }
+ msg->feature_cap = data;
+ msg->feature_cap_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len);
+ break;
+ case P2P_ATTR_PERSISTENT_GROUP:
+ {
+ if (len < ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Persistent Group Info (length %u)",
+ len);
+ return -1;
+ }
+
+ msg->persistent_dev = data;
+ msg->persistent_ssid_len = len - ETH_ALEN;
+ msg->persistent_ssid = &data[ETH_ALEN];
+ wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s",
+ MAC2STR(msg->persistent_dev),
+ wpa_ssid_txt(msg->persistent_ssid,
+ msg->persistent_ssid_len));
+ break;
+ }
default:
wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
"(length %d)", id, len);
@@ -296,23 +415,27 @@ int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
while (pos < end) {
u16 attr_len;
- if (pos + 2 >= end) {
+ u8 id;
+
+ if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
return -1;
}
- attr_len = WPA_GET_LE16(pos + 1);
+ id = *pos++;
+ attr_len = WPA_GET_LE16(pos);
+ pos += 2;
wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
- pos[0], attr_len);
- if (pos + 3 + attr_len > end) {
+ id, attr_len);
+ if (attr_len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
"(len=%u left=%d)",
- attr_len, (int) (end - pos - 3));
+ attr_len, (int) (end - pos));
wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
return -1;
}
- if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
+ if (p2p_parse_attribute(id, pos, attr_len, msg))
return -1;
- pos += 3 + attr_len;
+ pos += attr_len;
}
return 0;
@@ -340,6 +463,7 @@ static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id);
wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d",
msg->dev_password_id);
+ msg->dev_password_id_present = 1;
}
if (attr.primary_dev_type) {
char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -367,6 +491,9 @@ static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
msg->serial_number = attr.serial_number;
msg->serial_number_len = attr.serial_number_len;
+ msg->oob_dev_password = attr.oob_dev_password;
+ msg->oob_dev_password_len = attr.oob_dev_password_len;
+
return 0;
}
@@ -450,6 +577,33 @@ int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg)
}
+int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
+ size_t p2p_len, struct p2p_message *msg)
+{
+ os_memset(msg, 0, sizeof(*msg));
+
+ msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len);
+ if (msg->wps_attributes &&
+ p2p_parse_wps_ie(msg->wps_attributes, msg)) {
+ p2p_parse_free(msg);
+ return -1;
+ }
+
+ msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len);
+ if (msg->p2p_attributes &&
+ p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
+ if (msg->p2p_attributes)
+ wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
+ msg->p2p_attributes);
+ p2p_parse_free(msg);
+ return -1;
+ }
+
+ return 0;
+}
+
+
/**
* p2p_parse_free - Free temporary data from P2P parsing
* @msg: Parsed attributes
@@ -559,7 +713,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
"dev=" MACSTR " iface=" MACSTR,
MAC2STR(cli->p2p_device_addr),
MAC2STR(cli->p2p_interface_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -570,7 +724,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
wps_dev_type_bin2str(cli->pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -579,7 +733,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
wps_dev_type_bin2str(
&cli->sec_dev_types[s * 8],
devtype, sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -594,7 +748,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
}
ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -628,7 +782,7 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
"p2p_dev_capab=0x%x\n"
"p2p_group_capab=0x%x\n",
msg.capability[0], msg.capability[1]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -640,14 +794,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
wps_dev_type_bin2str(msg.pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
msg.device_name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -655,14 +809,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
"\n",
MAC2STR(msg.p2p_device_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
msg.config_methods);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
diff --git a/contrib/wpa/src/p2p/p2p_pd.c b/contrib/wpa/src/p2p/p2p_pd.c
index ca33f17..328b1e0 100644
--- a/contrib/wpa/src/p2p/p2p_pd.c
+++ b/contrib/wpa/src/p2p/p2p_pd.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -39,20 +40,145 @@ 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)
+{
+ int found;
+ u8 intended_addr[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+ int group_iface;
+
+ if (!p2p->cfg->get_go_info)
+ return;
+
+ found = p2p->cfg->get_go_info(
+ p2p->cfg->cb_ctx, intended_addr, ssid,
+ &ssid_len, &group_iface);
+ if (found) {
+ p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
+ ssid, ssid_len);
+ p2p_buf_add_intended_addr(buf, intended_addr);
+ } else {
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
+
+ /* Add pre-composed P2P Group ID */
+ p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
+ p2p->ssid, p2p->ssid_len);
+
+ if (group_iface)
+ p2p_buf_add_intended_addr(
+ buf, p2p->intended_addr);
+ else
+ p2p_buf_add_intended_addr(
+ buf, p2p->cfg->dev_addr);
+ }
+}
+
+
+static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
+ struct wpabuf *buf, u16 config_methods)
+{
+ struct p2ps_provision *prov = p2p->p2ps_prov;
+ u8 feat_cap_mask[] = { 1, 0 };
+ int shared_group = 0;
+ u8 ssid[32];
+ size_t ssid_len;
+ u8 go_dev_addr[ETH_ALEN];
+
+ /* 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 (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);
+ }
+
+ /* Add Operating Channel if conncap includes GO */
+ if (shared_group ||
+ (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
+ P2PS_SETUP_NEW))) {
+ u8 tmp;
+
+ p2p_go_select_channel(p2p, dev, &tmp);
+
+ if (p2p->op_reg_class && p2p->op_channel)
+ 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])
+ p2p_buf_add_session_info(buf, prov->info);
+
+ 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);
+ }
+
+ 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);
+
+ p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
+ feat_cap_mask);
+
+ if (shared_group)
+ p2p_buf_add_persistent_group_info(buf, go_dev_addr,
+ ssid, ssid_len);
+}
+
+
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
- u8 dialog_token,
- u16 config_methods,
- struct p2p_device *go)
+ struct p2p_device *dev,
+ int join)
{
struct wpabuf *buf;
u8 *len;
size_t extra = 0;
+ u8 dialog_token = dev->dialog_token;
+ u16 config_methods = dev->req_config_methods;
+ struct p2p_device *go = join ? dev : NULL;
+ u8 group_capab;
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_prov_disc_req)
extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
+
+ if (p2p->p2ps_prov)
+ extra += os_strlen(p2p->p2ps_prov->info) + 1 +
+ sizeof(struct p2ps_provision);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -60,10 +186,23 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
len = p2p_buf_add_ie_hdr(buf);
+
+ group_capab = 0;
+ if (p2p->p2ps_prov) {
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ if (p2p->cross_connect)
+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+ if (p2p->cfg->p2p_intra_bss)
+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+ }
p2p_buf_add_capability(buf, p2p->dev_capab &
- ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
p2p_buf_add_device_info(buf, p2p, NULL);
- if (go) {
+ if (p2p->p2ps_prov) {
+ p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods);
+ } else if (go) {
p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
go->oper_ssid, go->oper_ssid_len);
}
@@ -77,18 +216,27 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
+
return buf;
}
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
+ struct p2p_device *dev,
u8 dialog_token,
+ enum p2p_status_code status,
u16 config_methods,
+ u32 adv_id,
const u8 *group_id,
- size_t group_id_len)
+ size_t group_id_len,
+ const u8 *persist_ssid,
+ size_t persist_ssid_len)
{
struct wpabuf *buf;
size_t extra = 0;
+ int persist = 0;
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
@@ -111,12 +259,106 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
extra = wpabuf_len(wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
- buf = wpabuf_alloc(100 + extra);
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
+ /* Add P2P IE for P2PS */
+ if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) {
+ u8 feat_cap_mask[] = { 1, 0 };
+ u8 *len = p2p_buf_add_ie_hdr(buf);
+ struct p2ps_provision *prov = p2p->p2ps_prov;
+ u8 group_capab;
+
+ if (!status && prov->status != -1)
+ status = prov->status;
+
+ p2p_buf_add_status(buf, status);
+ group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP |
+ P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ if (p2p->cross_connect)
+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+ if (p2p->cfg->p2p_intra_bss)
+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
+ p2p_buf_add_device_info(buf, p2p, NULL);
+
+ if (persist_ssid && p2p->cfg->get_persistent_group &&
+ (status == P2P_SC_SUCCESS ||
+ status == P2P_SC_SUCCESS_DEFERRED)) {
+ u8 ssid[32];
+ size_t ssid_len;
+ u8 go_dev_addr[ETH_ALEN];
+
+ persist = p2p->cfg->get_persistent_group(
+ p2p->cfg->cb_ctx,
+ dev->info.p2p_device_addr,
+ persist_ssid, persist_ssid_len, go_dev_addr,
+ ssid, &ssid_len);
+ if (persist)
+ p2p_buf_add_persistent_group_info(
+ buf, go_dev_addr, ssid, ssid_len);
+ }
+
+ if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER))
+ p2ps_add_new_group_info(p2p, 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 (p2p->op_reg_class && p2p->op_channel)
+ 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 (!persist && (status == P2P_SC_SUCCESS ||
+ status == P2P_SC_SUCCESS_DEFERRED))
+ p2p_buf_add_connection_capability(buf, prov->conncap);
+
+ p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
+
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
+
+ p2p_buf_add_session_id(buf, prov->session_id,
+ prov->session_mac);
+
+ p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
+ feat_cap_mask);
+ p2p_buf_update_ie_hdr(buf, len);
+ } else if (status != P2P_SC_SUCCESS || adv_id) {
+ u8 *len = p2p_buf_add_ie_hdr(buf);
+
+ p2p_buf_add_status(buf, status);
+
+ if (p2p->p2ps_prov)
+ p2p_buf_add_advertisement_id(buf, adv_id,
+ p2p->p2ps_prov->adv_mac);
+
+ p2p_buf_update_ie_hdr(buf, len);
+ }
+
/* WPS IE with Config Methods attribute */
p2p_build_wps_ie_config_methods(buf, config_methods);
@@ -125,38 +367,74 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
wpabuf_put_buf(buf, wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
+
return buf;
}
+static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
+ u32 session_id, u16 method,
+ const u8 *session_mac, const u8 *adv_mac)
+{
+ struct p2ps_provision *tmp;
+
+ if (!p2p->p2ps_prov) {
+ p2p->p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + 1);
+ if (!p2p->p2ps_prov)
+ return -1;
+ } else {
+ os_memset(p2p->p2ps_prov, 0, sizeof(struct p2ps_provision) + 1);
+ }
+
+ tmp = p2p->p2ps_prov;
+ tmp->adv_id = adv_id;
+ tmp->session_id = session_id;
+ tmp->method = method;
+ os_memcpy(tmp->session_mac, session_mac, ETH_ALEN);
+ os_memcpy(tmp->adv_mac, adv_mac, ETH_ALEN);
+ tmp->info[0] = '\0';
+
+ return 0;
+}
+
+
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
struct p2p_message msg;
struct p2p_device *dev;
int freq;
- int reject = 1;
+ enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
struct wpabuf *resp;
+ u32 adv_id = 0;
+ struct p2ps_advertisement *p2ps_adv = NULL;
+ u8 conncap = P2PS_SETUP_NEW;
+ u8 auto_accept = 0;
+ u32 session_id = 0;
+ u8 session_mac[ETH_ALEN];
+ u8 adv_mac[ETH_ALEN];
+ u8 group_mac[ETH_ALEN];
+ int passwd_id = DEV_PW_DEFAULT;
+ u16 config_methods;
if (p2p_parse(data, len, &msg))
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Provision Discovery Request from " MACSTR
+ p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
" with config methods 0x%x (freq=%d)",
MAC2STR(sa), msg.wps_config_methods, rx_freq);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request from "
- "unknown peer " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
+ MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
0)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Provision Discovery Request add device "
- "failed " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "Provision Discovery Request add device failed "
+ MACSTR, MAC2STR(sa));
}
} else if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
@@ -165,13 +443,13 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
if (!(msg.wps_config_methods &
(WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
- WPS_CONFIG_PUSHBUTTON))) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
- "Config Methods in Provision Discovery Request");
+ WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_P2PS))) {
+ p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
goto out;
}
- if (msg.group_id) {
+ /* 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],
@@ -180,64 +458,319 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
break;
}
if (i == p2p->num_groups) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PD "
- "request for unknown P2P Group ID - reject");
+ p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
goto out;
}
}
- if (dev)
+ if (dev) {
dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
- P2P_DEV_PD_PEER_KEYPAD);
+ P2P_DEV_PD_PEER_KEYPAD |
+ P2P_DEV_PD_PEER_P2PS);
+
+ /* 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);
+ }
+ }
if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ p2p_dbg(p2p, "Peer " MACSTR
" requested us to show a PIN on display", MAC2STR(sa));
if (dev)
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+ passwd_id = DEV_PW_USER_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ p2p_dbg(p2p, "Peer " MACSTR
" requested us to write its PIN using keypad",
MAC2STR(sa));
if (dev)
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;
+ passwd_id = DEV_PW_P2PS_DEFAULT;
}
- reject = 0;
+ reject = P2P_SC_SUCCESS;
+
+ os_memset(session_mac, 0, ETH_ALEN);
+ os_memset(adv_mac, 0, ETH_ALEN);
+ os_memset(group_mac, 0, ETH_ALEN);
+
+ if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
+ (msg.status || msg.conn_cap)) {
+ u8 remote_conncap;
+
+ if (msg.intended_addr)
+ os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
+
+ 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);
+ adv_id = WPA_GET_LE32(msg.adv_id);
+
+ if (!msg.status)
+ p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+
+ p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
+
+ if (msg.conn_cap)
+ conncap = *msg.conn_cap;
+ remote_conncap = conncap;
+
+ 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);
+
+ 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 (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;
+ }
+ } 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)) {
+ 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;
+ }
+
+ 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;
+
+ conncap = p2p->cfg->p2ps_group_capability(
+ p2p->cfg->cb_ctx, remote_conncap,
+ p2p->p2ps_prov->conncap);
+
+ p2p_dbg(p2p,
+ "Conncap: local:%d remote:%d result:%d",
+ p2p->p2ps_prov->conncap,
+ remote_conncap, conncap);
+
+ /*
+ * 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;
+
+ /* Reject this "Deferred Accept* if incompatible
+ * conncap or method */
+ if (!conncap ||
+ !(msg.wps_config_methods & method))
+ reject =
+ P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ else
+ reject = P2P_SC_SUCCESS;
+
+ p2p->p2ps_prov->status = reject;
+ p2p->p2ps_prov->conncap = conncap;
+ }
+ }
+ }
out:
- resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
- reject ? 0 : msg.wps_config_methods,
- msg.group_id, msg.group_id_len);
+ if (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);
if (resp == NULL) {
p2p_parse_free(&msg);
return;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Sending Provision Discovery Response");
+ p2p_dbg(p2p, "Sending Provision Discovery Response");
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unknown regulatory class/channel");
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
wpabuf_free(resp);
p2p_parse_free(&msg);
return;
}
- p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+ 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) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
- }
+ p2p_dbg(p2p, "Failed to send Action frame");
+ } else
+ p2p->send_action_in_progress = 1;
wpabuf_free(resp);
- if (!reject && p2p->cfg->prov_disc_req) {
+ if (!p2p->cfg->p2ps_prov_complete) {
+ /* Don't emit anything */
+ } else if (msg.status && *msg.status != P2P_SC_SUCCESS &&
+ *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+ reject = *msg.status;
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
+ sa, adv_mac, session_mac,
+ NULL, adv_id, session_id,
+ 0, 0, msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 0, NULL);
+ } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
+ p2p->p2ps_prov) {
+ p2p->p2ps_prov->status = reject;
+ p2p->p2ps_prov->conncap = conncap;
+
+ if (reject != P2P_SC_SUCCESS)
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
+ sa, adv_mac, session_mac,
+ NULL, adv_id,
+ session_id, conncap, 0,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len, 0,
+ 0, NULL);
+ else
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
+ *msg.status,
+ sa, adv_mac, session_mac,
+ group_mac, adv_id,
+ session_id, conncap,
+ passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len, 0,
+ 0, NULL);
+ } 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,
+ adv_mac, session_mac, group_mac,
+ adv_id, session_id, conncap,
+ passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 0, NULL);
+ } else if (msg.status) {
+ } else if (auto_accept && reject == P2P_SC_SUCCESS) {
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
+ sa, adv_mac, session_mac,
+ group_mac, adv_id, session_id,
+ conncap, passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 0, NULL);
+ } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
+ (!msg.session_info || !msg.session_info_len)) {
+ p2p->p2ps_prov->method = msg.wps_config_methods;
+
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
+ sa, adv_mac, session_mac,
+ group_mac, adv_id, session_id,
+ conncap, passwd_id,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ 0, 1, NULL);
+ } 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);
+
+ if (buf) {
+ p2p->p2ps_prov->method = msg.wps_config_methods;
+
+ utf8_escape((char *) msg.session_info, buf_len,
+ buf, 2 * buf_len + 1);
+
+ p2p->cfg->p2ps_prov_complete(
+ p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
+ adv_mac, session_mac, group_mac, adv_id,
+ session_id, conncap, passwd_id,
+ msg.persistent_ssid, msg.persistent_ssid_len,
+ 0, 1, buf);
+
+ os_free(buf);
+ }
+ }
+
+ if (reject == P2P_SC_SUCCESS && p2p->cfg->prov_disc_req) {
const u8 *dev_addr = sa;
if (msg.p2p_device_addr)
dev_addr = msg.p2p_device_addr;
@@ -259,30 +792,63 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
{
struct p2p_message msg;
struct p2p_device *dev;
- u16 report_config_methods = 0;
+ u16 report_config_methods = 0, req_config_methods;
+ u8 status = P2P_SC_SUCCESS;
int success = 0;
+ u32 adv_id = 0;
+ u8 conncap = P2PS_SETUP_NEW;
+ u8 adv_mac[ETH_ALEN];
+ u8 group_mac[ETH_ALEN];
+ int passwd_id = DEV_PW_DEFAULT;
if (p2p_parse(data, len, &msg))
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Provision Discovery Response from " MACSTR
+ /* Parse the P2PS members present */
+ if (msg.status)
+ status = *msg.status;
+
+ if (msg.intended_addr)
+ os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
+ else
+ os_memset(group_mac, 0, ETH_ALEN);
+
+ if (msg.adv_mac)
+ os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+ else
+ os_memset(adv_mac, 0, ETH_ALEN);
+
+ if (msg.adv_id)
+ adv_id = WPA_GET_LE32(msg.adv_id);
+
+ if (msg.conn_cap) {
+ conncap = *msg.conn_cap;
+
+ /* Switch bits to local relative */
+ switch (conncap) {
+ case P2PS_SETUP_GROUP_OWNER:
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+ case P2PS_SETUP_CLIENT:
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ break;
+ }
+ }
+
+ p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
" with config methods 0x%x",
MAC2STR(sa), msg.wps_config_methods);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || !dev->req_config_methods) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Provision Discovery Response from "
- MACSTR " with no pending request", MAC2STR(sa));
+ p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
+ " with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return;
}
if (dev->dialog_token != msg.dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Provision Discovery Response with "
- "unexpected Dialog Token %u (expected %u)",
+ p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
return;
@@ -294,6 +860,12 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
}
/*
+ * Use a local copy of the requested config methods since
+ * p2p_reset_pending_pd() can clear this in the peer entry.
+ */
+ req_config_methods = dev->req_config_methods;
+
+ /*
* If the response is from the peer to whom a user initiated request
* was sent earlier, we reset that state info here.
*/
@@ -301,28 +873,114 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
p2p_reset_pending_pd(p2p);
- if (msg.wps_config_methods != dev->req_config_methods) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
- "our Provision Discovery Request");
+ if (msg.wps_config_methods != req_config_methods) {
+ p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
+ msg.wps_config_methods, req_config_methods);
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
- P2P_PROV_DISC_REJECTED);
+ P2P_PROV_DISC_REJECTED,
+ adv_id, adv_mac, NULL);
p2p_parse_free(&msg);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
goto out;
}
- report_config_methods = dev->req_config_methods;
+ report_config_methods = req_config_methods;
dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
- P2P_DEV_PD_PEER_KEYPAD);
- if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ P2P_DEV_PD_PEER_KEYPAD |
+ P2P_DEV_PD_PEER_P2PS);
+ if (req_config_methods & WPS_CONFIG_DISPLAY) {
+ p2p_dbg(p2p, "Peer " MACSTR
" accepted to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+ passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
+ p2p_dbg(p2p, "Peer " MACSTR
" accepted to write our PIN using keypad",
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+ passwd_id = DEV_PW_USER_SPECIFIED;
+ } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+ p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
+ MAC2STR(sa));
+ dev->flags |= P2P_DEV_PD_PEER_P2PS;
+ passwd_id = DEV_PW_P2PS_DEFAULT;
+ }
+
+ if ((msg.conn_cap || msg.persistent_dev) &&
+ msg.adv_id &&
+ (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
+ p2p->p2ps_prov) {
+ if (p2p->cfg->p2ps_prov_complete) {
+ 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);
+ }
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ }
+
+ if (status != P2P_SC_SUCCESS &&
+ status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
+ status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) {
+ if (p2p->cfg->p2ps_prov_complete)
+ 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,
+ 0, 0, NULL, 0, 1, 0, NULL);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ }
+
+ if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+ if (p2p->cfg->remove_stale_groups) {
+ p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx,
+ dev->info.p2p_device_addr,
+ NULL, NULL, 0);
+ }
+
+ if (msg.session_info && msg.session_info_len) {
+ size_t info_len = msg.session_info_len;
+ char *deferred_sess_resp = os_malloc(2 * info_len + 1);
+
+ if (!deferred_sess_resp) {
+ p2p_parse_free(&msg);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ goto out;
+ }
+ utf8_escape((char *) msg.session_info, info_len,
+ deferred_sess_resp, 2 * info_len + 1);
+
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(
+ p2p->cfg->cb_ctx, sa,
+ P2P_PROV_DISC_INFO_UNAVAILABLE,
+ adv_id, adv_mac,
+ deferred_sess_resp);
+ os_free(deferred_sess_resp);
+ } else
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(
+ p2p->cfg->cb_ctx, sa,
+ P2P_PROV_DISC_INFO_UNAVAILABLE,
+ adv_id, adv_mac, NULL);
+ } else if (msg.wps_config_methods != dev->req_config_methods ||
+ status != P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "Peer rejected our Provision Discovery Request");
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+ P2P_PROV_DISC_REJECTED, 0,
+ NULL, NULL);
+ p2p_parse_free(&msg);
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+ goto out;
}
/* Store the provisioning info */
@@ -335,10 +993,8 @@ out:
dev->req_config_methods = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Start GO Neg after the PD-before-GO-Neg "
- "workaround with " MACSTR,
- MAC2STR(dev->info.p2p_device_addr));
+ p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
+ MACSTR, MAC2STR(dev->info.p2p_device_addr));
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
p2p_connect_send(p2p, dev);
return;
@@ -346,6 +1002,11 @@ out:
if (success && p2p->cfg->prov_disc_resp)
p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
report_config_methods);
+
+ if (p2p->state == P2P_PD_DURING_FIND) {
+ p2p_clear_timeout(p2p);
+ p2p_continue_find(p2p);
+ }
}
@@ -361,9 +1022,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
freq = dev->listen_freq > 0 ? dev->listen_freq :
dev->oper_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send Provision Discovery Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send Provision Discovery Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
@@ -371,8 +1031,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cannot use PD with P2P Device " MACSTR
+ p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
" that is in a group and is not discoverable",
MAC2STR(dev->info.p2p_device_addr));
return -1;
@@ -380,9 +1039,33 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
/* TODO: use device discoverability request through GO */
}
- req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
- dev->req_config_methods,
- join ? dev : NULL);
+ if (p2p->p2ps_prov) {
+ if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) {
+ if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
+ dev->req_config_methods = WPS_CONFIG_KEYPAD;
+ else if (p2p->p2ps_prov->method == WPS_CONFIG_KEYPAD)
+ dev->req_config_methods = WPS_CONFIG_DISPLAY;
+ else
+ dev->req_config_methods = WPS_CONFIG_P2PS;
+ } else {
+ /* Order of preference, based on peer's capabilities */
+ if (p2p->p2ps_prov->method)
+ dev->req_config_methods =
+ p2p->p2ps_prov->method;
+ else if (dev->info.config_methods & WPS_CONFIG_P2PS)
+ dev->req_config_methods = WPS_CONFIG_P2PS;
+ else if (dev->info.config_methods & WPS_CONFIG_DISPLAY)
+ dev->req_config_methods = WPS_CONFIG_DISPLAY;
+ else
+ dev->req_config_methods = WPS_CONFIG_KEYPAD;
+ }
+ p2p_dbg(p2p,
+ "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);
+ }
+
+ req = p2p_build_prov_disc_req(p2p, dev, join);
if (req == NULL)
return -1;
@@ -392,8 +1075,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(req);
return -1;
}
@@ -406,6 +1088,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
+ struct p2ps_provision *p2ps_prov,
u16 config_methods, int join, int force_freq,
int user_initiated_pd)
{
@@ -415,20 +1098,30 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
if (dev == NULL)
dev = p2p_get_device_interface(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
- "Discovery Request destination " MACSTR
+ p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
" not yet known", MAC2STR(peer_addr));
+ os_free(p2ps_prov);
return -1;
}
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
- "Request with " MACSTR " (config methods 0x%x)",
+ p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
+ " (config methods 0x%x)",
MAC2STR(peer_addr), config_methods);
- if (config_methods == 0)
+ if (config_methods == 0 && !p2ps_prov) {
+ os_free(p2ps_prov);
return -1;
+ }
+
+ if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
+ p2p->p2ps_prov) {
+ /* Use cached method from deferred provisioning */
+ p2ps_prov->method = p2p->p2ps_prov->method;
+ }
/* Reset provisioning info */
dev->wps_prov_info = 0;
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = p2ps_prov;
dev->req_config_methods = config_methods;
if (join)
@@ -438,14 +1131,14 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
p2p->state != P2P_LISTEN_ONLY) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
- "operations; postpone Provision Discovery Request "
- "with " MACSTR " (config methods 0x%x)",
+ p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
+ MACSTR " (config methods 0x%x)",
MAC2STR(peer_addr), config_methods);
return 0;
}
p2p->user_initiated_pd = user_initiated_pd;
+ p2p->pd_force_freq = force_freq;
if (p2p->user_initiated_pd)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
@@ -481,4 +1174,5 @@ void p2p_reset_pending_pd(struct p2p_data *p2p)
p2p->user_initiated_pd = 0;
os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
p2p->pd_retries = 0;
+ p2p->pd_force_freq = 0;
}
diff --git a/contrib/wpa/src/p2p/p2p_sd.c b/contrib/wpa/src/p2p/p2p_sd.c
index abe1d6b..1a2af04 100644
--- a/contrib/wpa/src/p2p/p2p_sd.c
+++ b/contrib/wpa/src/p2p/p2p_sd.c
@@ -52,6 +52,7 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
{
struct p2p_sd_query *q;
int wsd = 0;
+ int count = 0;
if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
return NULL; /* peer does not support SD */
@@ -64,15 +65,52 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
/* Use WSD only if the peer indicates support or it */
if (q->wsd && !wsd)
continue;
- if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
- return q;
+ /* if the query is a broadcast query */
+ if (q->for_all_peers) {
+ /*
+ * check if there are any broadcast queries pending for
+ * this device
+ */
+ if (dev->sd_pending_bcast_queries <= 0)
+ return NULL;
+ /* query number that needs to be send to the device */
+ if (count == dev->sd_pending_bcast_queries - 1)
+ goto found;
+ count++;
+ }
if (!q->for_all_peers &&
os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
0)
- return q;
+ goto found;
}
return NULL;
+
+found:
+ if (dev->sd_reqs > 100) {
+ p2p_dbg(p2p, "Too many SD request attempts to " MACSTR
+ " - skip remaining queries",
+ MAC2STR(dev->info.p2p_device_addr));
+ return NULL;
+ }
+ return q;
+}
+
+
+static void p2p_decrease_sd_bc_queries(struct p2p_data *p2p, int query_number)
+{
+ struct p2p_device *dev;
+
+ p2p->num_p2p_sd_queries--;
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (query_number <= dev->sd_pending_bcast_queries - 1) {
+ /*
+ * Query not yet sent to the device and it is to be
+ * removed, so update the pending count.
+ */
+ dev->sd_pending_bcast_queries--;
+ }
+ }
}
@@ -80,10 +118,16 @@ static int p2p_unlink_sd_query(struct p2p_data *p2p,
struct p2p_sd_query *query)
{
struct p2p_sd_query *q, *prev;
+ int query_number = 0;
+
q = p2p->sd_queries;
prev = NULL;
while (q) {
if (q == query) {
+ /* If the query is a broadcast query, decrease one from
+ * all the devices */
+ if (query->for_all_peers)
+ p2p_decrease_sd_bc_queries(p2p, query_number);
if (prev)
prev->next = q->next;
else
@@ -92,6 +136,8 @@ static int p2p_unlink_sd_query(struct p2p_data *p2p,
p2p->sd_query = NULL;
return 1;
}
+ if (q->for_all_peers)
+ query_number++;
prev = q;
q = q->next;
}
@@ -118,6 +164,7 @@ void p2p_free_sd_queries(struct p2p_data *p2p)
q = q->next;
p2p_free_sd_query(prev);
}
+ p2p->num_p2p_sd_queries = 0;
}
@@ -133,8 +180,7 @@ static struct wpabuf * p2p_build_sd_query(u16 update_indic,
/* ANQP Query Request Frame */
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
wpabuf_put_buf(buf, tlvs);
gas_anqp_set_element_len(buf, len_pos);
@@ -157,8 +203,7 @@ static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
wpabuf_head(req), wpabuf_len(req), 200) < 0)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(req);
}
@@ -181,8 +226,7 @@ static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
if (tlvs) {
/* ANQP Query Response Frame */
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
/* Service Update Indicator */
wpabuf_put_le16(buf, update_indic);
wpabuf_put_buf(buf, tlvs);
@@ -213,8 +257,7 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
/* ANQP Query Response Frame */
wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, P2P_OUI_TYPE);
+ wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
/* Service Update Indicator */
wpabuf_put_le16(buf, update_indic);
}
@@ -232,12 +275,12 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
int ret = 0;
struct p2p_sd_query *query;
int freq;
+ unsigned int wait_time;
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
if (freq <= 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No Listen/Operating frequency known for the "
- "peer " MACSTR " to send SD Request",
+ p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
+ MACSTR " to send SD Request",
MAC2STR(dev->info.p2p_device_addr));
return -1;
}
@@ -246,23 +289,25 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
if (query == NULL)
return -1;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Start Service Discovery with " MACSTR,
+ p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
MAC2STR(dev->info.p2p_device_addr));
req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
if (req == NULL)
return -1;
+ dev->sd_reqs++;
p2p->sd_peer = dev;
p2p->sd_query = query;
p2p->pending_action_state = P2P_PENDING_SD;
+ wait_time = 5000;
+ if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
+ wait_time = p2p->cfg->max_listen;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 5000) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
ret = -1;
}
@@ -290,8 +335,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0)
return;
@@ -300,14 +344,12 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
return;
dialog_token = *pos++;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GAS Initial Request from " MACSTR " (dialog token %u, "
- "freq %d)",
+ p2p_dbg(p2p, "GAS Initial Request from " MACSTR
+ " (dialog token %u, freq %d)",
MAC2STR(sa), dialog_token, rx_freq);
if (*pos != WLAN_EID_ADV_PROTO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected IE in GAS Initial Request: %u", *pos);
+ p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos);
return;
}
pos++;
@@ -315,15 +357,13 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
slen = *pos++;
next = pos + slen;
if (next > end || slen < 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid IE in GAS Initial Request");
+ p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
return;
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported GAS advertisement protocol id %u",
+ p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
*pos);
return;
}
@@ -342,8 +382,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
if (pos + 4 > end)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+ p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -351,30 +390,21 @@ 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) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid ANQP Query Request length");
+ p2p_dbg(p2p, "Invalid ANQP Query Request length");
return;
}
- if (WPA_GET_BE24(pos) != OUI_WFA) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+ if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+ WPA_GET_BE32(pos));
return;
}
- pos += 3;
-
- if (*pos != P2P_OUI_TYPE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP vendor type %u", *pos);
- return;
- }
- pos++;
+ pos += 4;
if (pos + 2 > end)
return;
update_indic = WPA_GET_LE16(pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Update Indicator: %u", update_indic);
+ p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
pos += 2;
p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
@@ -390,8 +420,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
/* TODO: fix the length limit to match with the maximum frame length */
if (wpabuf_len(resp_tlvs) > 1400) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response long "
- "enough to require fragmentation");
+ p2p_dbg(p2p, "SD response long enough to require fragmentation");
if (p2p->sd_resp) {
/*
* TODO: Could consider storing the fragmented response
@@ -400,14 +429,12 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
* Though, that would eat more memory, so there are
* also benefits to just using a single buffer.
*/
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
- "previous SD response");
+ p2p_dbg(p2p, "Drop previous SD response");
wpabuf_free(p2p->sd_resp);
}
p2p->sd_resp = wpabuf_dup(resp_tlvs);
if (p2p->sd_resp == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR, "P2P: Failed to "
- "allocate SD response fragmentation area");
+ p2p_err(p2p, "Failed to allocate SD response fragmentation area");
return;
}
os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
@@ -417,8 +444,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
1, p2p->srv_update_indic, NULL);
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response fits "
- "in initial response");
+ p2p_dbg(p2p, "SD response fits in initial response");
resp = p2p_build_sd_response(dialog_token,
WLAN_STATUS_SUCCESS, 0,
p2p->srv_update_indic, resp_tlvs);
@@ -430,8 +456,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
}
@@ -451,21 +476,18 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore unexpected GAS Initial Response from "
+ p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
MACSTR, MAC2STR(sa));
return;
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_clear_timeout(p2p);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GAS Initial Response from " MACSTR " (len=%d)",
+ p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)",
MAC2STR(sa), (int) len);
if (len < 5 + 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Too short GAS Initial Response frame");
+ p2p_dbg(p2p, "Too short GAS Initial Response frame");
return;
}
@@ -475,20 +497,16 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos += 2;
comeback_delay = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: dialog_token=%u status_code=%u comeback_delay=%u",
+ p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u",
dialog_token, status_code, comeback_delay);
if (status_code) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery failed: status code %u",
+ p2p_dbg(p2p, "Service Discovery failed: status code %u",
status_code);
return;
}
if (*pos != WLAN_EID_ADV_PROTO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected IE in GAS Initial Response: %u",
- *pos);
+ p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos);
return;
}
pos++;
@@ -496,15 +514,13 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
slen = *pos++;
next = pos + slen;
if (next > end || slen < 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid IE in GAS Initial Response");
+ p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
return;
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported GAS advertisement protocol id %u",
+ p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
*pos);
return;
}
@@ -512,27 +528,22 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
if (pos + 2 > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
- "Response");
+ p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
- slen);
+ p2p_dbg(p2p, "Query Response Length: %d", slen);
if (pos + slen > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
- "Response data");
+ p2p_dbg(p2p, "Not enough Query Response data");
return;
}
end = pos + slen;
if (comeback_delay) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Fragmented "
- "response - request fragments");
+ p2p_dbg(p2p, "Fragmented response - request fragments");
if (p2p->sd_rx_resp) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop "
- "old SD reassembly buffer");
+ p2p_dbg(p2p, "Drop old SD reassembly buffer");
wpabuf_free(p2p->sd_rx_resp);
p2p->sd_rx_resp = NULL;
}
@@ -544,8 +555,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
if (pos + 4 > end)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+ p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -553,41 +563,29 @@ 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) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid ANQP Query Response length");
+ p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
- if (WPA_GET_BE24(pos) != OUI_WFA) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+ if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+ WPA_GET_BE32(pos));
return;
}
- pos += 3;
-
- if (*pos != P2P_OUI_TYPE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP vendor type %u", *pos);
- return;
- }
- pos++;
+ pos += 4;
if (pos + 2 > end)
return;
update_indic = WPA_GET_LE16(pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Update Indicator: %u", update_indic);
+ p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
pos += 2;
- p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
p2p->sd_peer = NULL;
if (p2p->sd_query) {
if (!p2p->sd_query->for_all_peers) {
struct p2p_sd_query *q;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Remove completed SD query %p",
+ p2p_dbg(p2p, "Remove completed SD query %p",
p2p->sd_query);
q = p2p->sd_query;
p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -615,22 +613,20 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
if (len < 1)
return;
dialog_token = *data;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dialog Token: %u",
- dialog_token);
+ p2p_dbg(p2p, "Dialog Token: %u", dialog_token);
if (dialog_token != p2p->sd_resp_dialog_token) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
- "response fragment for dialog token %u", dialog_token);
+ p2p_dbg(p2p, "No pending SD response fragment for dialog token %u",
+ dialog_token);
return;
}
if (p2p->sd_resp == NULL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
- "response fragment available");
+ p2p_dbg(p2p, "No pending SD response fragment available");
return;
}
if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD "
- "response fragment for " MACSTR, MAC2STR(sa));
+ p2p_dbg(p2p, "No pending SD response fragment for " MACSTR,
+ MAC2STR(sa));
return;
}
@@ -647,19 +643,16 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
wpabuf_len(p2p->sd_resp));
if (resp == NULL)
return;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send GAS Comeback "
- "Response (frag_id %d more=%d frag_len=%d)",
+ p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)",
p2p->sd_frag_id, more, (int) frag_len);
p2p->sd_frag_id++;
p2p->sd_resp_pos += frag_len;
if (more) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: %d more bytes "
- "remain to be sent",
+ p2p_dbg(p2p, "%d more bytes remain to be sent",
(int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos));
} else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: All fragments of "
- "SD response sent");
+ p2p_dbg(p2p, "All fragments of SD response sent");
wpabuf_free(p2p->sd_resp);
p2p->sd_resp = NULL;
}
@@ -668,8 +661,7 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Failed to send Action frame");
+ p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
}
@@ -692,21 +684,18 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore unexpected GAS Comeback Response from "
+ p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
MACSTR, MAC2STR(sa));
return;
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_clear_timeout(p2p);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received GAS Comeback Response from " MACSTR " (len=%d)",
+ p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
MAC2STR(sa), (int) len);
if (len < 6 + 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Too short GAS Comeback Response frame");
+ p2p_dbg(p2p, "Too short GAS Comeback Response frame");
return;
}
@@ -719,22 +708,19 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos++;
comeback_delay = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
+ p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
"comeback_delay=%u",
dialog_token, status_code, frag_id, more_frags,
comeback_delay);
/* TODO: check frag_id match */
if (status_code) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Discovery failed: status code %u",
+ p2p_dbg(p2p, "Service Discovery failed: status code %u",
status_code);
return;
}
if (*pos != WLAN_EID_ADV_PROTO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unexpected IE in GAS Comeback Response: %u",
+ p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
*pos);
return;
}
@@ -743,15 +729,13 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
slen = *pos++;
next = pos + slen;
if (next > end || slen < 2) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid IE in GAS Comeback Response");
+ p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
return;
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported GAS advertisement protocol id %u",
+ p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
*pos);
return;
}
@@ -759,22 +743,18 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
if (pos + 2 > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query "
- "Response");
+ p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d",
- slen);
+ p2p_dbg(p2p, "Query Response Length: %d", slen);
if (pos + slen > end) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query "
- "Response data");
+ p2p_dbg(p2p, "Not enough Query Response data");
return;
}
if (slen == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Query Response "
- "data");
+ p2p_dbg(p2p, "No Query Response data");
return;
}
end = pos + slen;
@@ -791,77 +771,60 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
if (pos + 4 > end)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
+ p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
slen = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
- "length: %u", slen);
+ p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
if (slen < 3 + 1) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid ANQP Query Response length");
+ p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
if (pos + 4 > end)
return;
- if (WPA_GET_BE24(pos) != OUI_WFA) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
+ if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
+ WPA_GET_BE32(pos));
return;
}
- pos += 3;
-
- if (*pos != P2P_OUI_TYPE) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported ANQP vendor type %u", *pos);
- return;
- }
- pos++;
+ pos += 4;
if (pos + 2 > end)
return;
p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Service Update Indicator: %u", p2p->sd_rx_update_indic);
+ p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
pos += 2;
skip_nqp_header:
if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
return;
wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Current SD reassembly "
- "buffer length: %u",
+ p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
(unsigned int) wpabuf_len(p2p->sd_rx_resp));
if (more_frags) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: More fragments "
- "remains");
+ p2p_dbg(p2p, "More fragments remains");
/* TODO: what would be a good size limit? */
if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
wpabuf_free(p2p->sd_rx_resp);
p2p->sd_rx_resp = NULL;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too long "
- "SD response - drop it");
+ p2p_dbg(p2p, "Too long SD response - drop it");
return;
}
p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
return;
}
- p2p->sd_peer->flags |= P2P_DEV_SD_INFO;
- p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE;
p2p->sd_peer = NULL;
if (p2p->sd_query) {
if (!p2p->sd_query->for_all_peers) {
struct p2p_sd_query *q;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Remove completed SD query %p",
+ p2p_dbg(p2p, "Remove completed SD query %p",
p2p->sd_query);
q = p2p->sd_query;
p2p_unlink_sd_query(p2p, p2p->sd_query);
@@ -904,12 +867,20 @@ void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
q->next = p2p->sd_queries;
p2p->sd_queries = q;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q);
+ p2p_dbg(p2p, "Added SD Query %p", q);
if (dst == NULL) {
struct p2p_device *dev;
- dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
- dev->flags &= ~P2P_DEV_SD_INFO;
+
+ p2p->num_p2p_sd_queries++;
+
+ /* Update all the devices for the newly added broadcast query */
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (dev->sd_pending_bcast_queries <= 0)
+ dev->sd_pending_bcast_queries = 1;
+ else
+ dev->sd_pending_bcast_queries++;
+ }
}
return q;
@@ -938,8 +909,7 @@ void p2p_sd_service_update(struct p2p_data *p2p)
int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
{
if (p2p_unlink_sd_query(p2p, req)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Cancel pending SD query %p", req);
+ p2p_dbg(p2p, "Cancel pending SD query %p", req);
p2p_free_sd_query(req);
return 0;
}
diff --git a/contrib/wpa/src/p2p/p2p_utils.c b/contrib/wpa/src/p2p/p2p_utils.c
index bcc690d..f32751d 100644
--- a/contrib/wpa/src/p2p/p2p_utils.c
+++ b/contrib/wpa/src/p2p/p2p_utils.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "common/ieee802_11_common.h"
#include "p2p_i.h"
@@ -46,127 +47,69 @@ int p2p_random(char *buf, size_t len)
}
-static int p2p_channel_to_freq_j4(int reg_class, int channel)
-{
- /* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */
- /* TODO: more regulatory classes */
- switch (reg_class) {
- case 81:
- /* channels 1..13 */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 82:
- /* channel 14 */
- if (channel != 14)
- return -1;
- return 2414 + 5 * channel;
- case 83: /* channels 1..9; 40 MHz */
- case 84: /* channels 5..13; 40 MHz */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 115: /* channels 36,40,44,48; indoor only */
- case 118: /* channels 52,56,60,64; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 116: /* channels 36,44; 40 MHz; indoor only */
- case 117: /* channels 40,48; 40 MHz; indoor only */
- case 119: /* channels 52,60; 40 MHz; dfs */
- case 120: /* channels 56,64; 40 MHz; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- }
- return -1;
-}
-
-
/**
* p2p_channel_to_freq - Convert channel info to frequency
- * @country: Country code
- * @reg_class: Regulatory class
+ * @op_class: Operating class
* @channel: Channel number
* Returns: Frequency in MHz or -1 if the specified channel is unknown
*/
-int p2p_channel_to_freq(const char *country, int reg_class, int channel)
+int p2p_channel_to_freq(int op_class, int channel)
{
- if (country[2] == 0x04)
- return p2p_channel_to_freq_j4(reg_class, channel);
-
- /* These are mainly for backwards compatibility; to be removed */
- switch (reg_class) {
- case 1: /* US/1, EU/1, JP/1 = 5 GHz, channels 36,40,44,48 */
- if (channel < 36 || channel > 48)
- return -1;
- return 5000 + 5 * channel;
- case 3: /* US/3 = 5 GHz, channels 149,153,157,161 */
- case 5: /* US/5 = 5 GHz, channels 149,153,157,161 */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 4: /* EU/4 = 2.407 GHz, channels 1..13 */
- case 12: /* US/12 = 2.407 GHz, channels 1..11 */
- case 30: /* JP/30 = 2.407 GHz, channels 1..13 */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 31: /* JP/31 = 2.414 GHz, channel 14 */
- if (channel != 14)
- return -1;
- return 2414 + 5 * channel;
- }
-
- return -1;
+ return ieee80211_chan_to_freq(NULL, op_class, channel);
}
/**
* p2p_freq_to_channel - Convert frequency into channel info
- * @country: Country code
- * @reg_class: Buffer for returning regulatory class
+ * @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: 0 on success, -1 if the specified frequency is unknown
*/
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
- u8 *channel)
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
{
/* TODO: more operating classes */
if (freq >= 2412 && freq <= 2472) {
- *reg_class = 81; /* 2.407 GHz, channels 1..13 */
+ if ((freq - 2407) % 5)
+ return -1;
+
+ *op_class = 81; /* 2.407 GHz, channels 1..13 */
*channel = (freq - 2407) / 5;
return 0;
}
if (freq == 2484) {
- *reg_class = 82; /* channel 14 */
+ *op_class = 82; /* channel 14 */
*channel = 14;
return 0;
}
if (freq >= 5180 && freq <= 5240) {
- *reg_class = 115; /* 5 GHz, channels 36..48 */
+ if ((freq - 5000) % 5)
+ return -1;
+
+ *op_class = 115; /* 5 GHz, channels 36..48 */
*channel = (freq - 5000) / 5;
return 0;
}
if (freq >= 5745 && freq <= 5805) {
- *reg_class = 124; /* 5 GHz, channels 149..161 */
+ if ((freq - 5000) % 5)
+ return -1;
+
+ *op_class = 124; /* 5 GHz, channels 149..161 */
*channel = (freq - 5000) / 5;
return 0;
}
+ if (freq >= 58320 && freq <= 64800) {
+ if ((freq - 58320) % 2160)
+ return -1;
+
+ *op_class = 180; /* 60 GHz, channels 1..4 */
+ *channel = (freq - 56160) / 2160;
+ return 0;
+ }
+
return -1;
}
@@ -230,6 +173,115 @@ void p2p_channels_intersect(const struct p2p_channels *a,
}
+static void p2p_op_class_union(struct p2p_reg_class *cl,
+ const struct p2p_reg_class *b_cl)
+{
+ size_t i, j;
+
+ for (i = 0; i < b_cl->channels; i++) {
+ for (j = 0; j < cl->channels; j++) {
+ if (b_cl->channel[i] == cl->channel[j])
+ break;
+ }
+ if (j == cl->channels) {
+ if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ return;
+ cl->channel[cl->channels++] = b_cl->channel[i];
+ }
+ }
+}
+
+
+/**
+ * p2p_channels_union_inplace - Inplace union of channel lists
+ * @res: Input data and place for returning union of the channel sets
+ * @b: Second set of channels
+ */
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b)
+{
+ size_t i, j;
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+ if (cl->reg_class != b_cl->reg_class)
+ continue;
+ p2p_op_class_union(cl, b_cl);
+ }
+ }
+
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ if (cl->reg_class == b_cl->reg_class)
+ break;
+ }
+
+ if (i == res->reg_classes) {
+ if (res->reg_classes == P2P_MAX_REG_CLASSES)
+ return;
+ os_memcpy(&res->reg_class[res->reg_classes++],
+ b_cl, sizeof(struct p2p_reg_class));
+ }
+ }
+}
+
+
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res)
+{
+ os_memcpy(res, a, sizeof(*res));
+ p2p_channels_union_inplace(res, b);
+}
+
+
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list)
+{
+ size_t o, c;
+
+ if (list == NULL)
+ return;
+
+ o = 0;
+ while (o < chan->reg_classes) {
+ struct p2p_reg_class *op = &chan->reg_class[o];
+
+ c = 0;
+ while (c < op->channels) {
+ int freq = p2p_channel_to_freq(op->reg_class,
+ op->channel[c]);
+ if (freq > 0 && freq_range_list_includes(list, freq)) {
+ op->channels--;
+ os_memmove(&op->channel[c],
+ &op->channel[c + 1],
+ op->channels - c);
+ } else
+ c++;
+ }
+
+ if (op->channels == 0) {
+ chan->reg_classes--;
+ os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
+ (chan->reg_classes - o) *
+ sizeof(struct p2p_reg_class));
+ } else
+ o++;
+ }
+}
+
+
/**
* p2p_channels_includes - Check whether a channel is included in the list
* @channels: List of supported channels
@@ -254,12 +306,208 @@ int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
}
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+ unsigned int freq)
+{
+ size_t i, j;
+ for (i = 0; i < channels->reg_classes; i++) {
+ const struct p2p_reg_class *reg = &channels->reg_class[i];
+ for (j = 0; j < reg->channels; j++) {
+ if (p2p_channel_to_freq(reg->reg_class,
+ reg->channel[j]) == (int) freq)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
{
u8 op_reg_class, op_channel;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_reg_class, &op_channel) < 0)
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
return 0;
return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
op_channel);
}
+
+
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) &&
+ !freq_range_list_includes(&p2p->no_go_freq, freq);
+}
+
+
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) ||
+ p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+ op_channel);
+}
+
+
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+ const struct p2p_channels *channels)
+{
+ unsigned int i;
+ int freq = 0;
+ const struct p2p_channels *tmpc = channels ?
+ channels : &p2p->cfg->channels;
+
+ if (tmpc == NULL)
+ return 0;
+
+ for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+ freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
+ p2p->cfg->pref_chan[i].chan);
+ if (p2p_channels_includes_freq(tmpc, freq))
+ return freq;
+ }
+ return 0;
+}
+
+
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+ const struct p2p_channels *chan)
+{
+ char buf[500], *pos, *end;
+ size_t i, j;
+ int ret;
+
+ pos = buf;
+ end = pos + sizeof(buf);
+
+ for (i = 0; i < chan->reg_classes; i++) {
+ const struct p2p_reg_class *c;
+ c = &chan->reg_class[i];
+ ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+
+ for (j = 0; j < c->channels; j++) {
+ ret = os_snprintf(pos, end - pos, "%s%u",
+ j == 0 ? "" : ",",
+ c->channel[j]);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+ }
+ *pos = '\0';
+
+ p2p_dbg(p2p, "%s:%s", title, buf);
+}
+
+
+static u8 p2p_channel_pick_random(const u8 *channels, unsigned int num_channels)
+{
+ unsigned int r;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
+ r %= num_channels;
+ return channels[r];
+}
+
+
+int p2p_channel_select(struct p2p_channels *chans, const int *classes,
+ u8 *op_class, u8 *op_channel)
+{
+ unsigned int i, j;
+
+ for (j = 0; classes == NULL || classes[j]; j++) {
+ for (i = 0; i < chans->reg_classes; i++) {
+ struct p2p_reg_class *c = &chans->reg_class[i];
+
+ if (c->channels == 0)
+ continue;
+
+ if (classes == NULL || c->reg_class == classes[j]) {
+ /*
+ * Pick one of the available channels in the
+ * operating class at random.
+ */
+ *op_class = c->reg_class;
+ *op_channel = p2p_channel_pick_random(
+ c->channel, c->channels);
+ return 0;
+ }
+ }
+ if (classes == NULL)
+ break;
+ }
+
+ return -1;
+}
+
+
+int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
+ u8 *op_channel)
+{
+ 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))
+ chan[num_channels++] = 1;
+ if (p2p_channels_includes(chans, 81, 6))
+ chan[num_channels++] = 6;
+ if (p2p_channels_includes(chans, 81, 11))
+ chan[num_channels++] = 11;
+
+ /* Try to find available social channels from 60 GHz */
+ if (p2p_channels_includes(chans, 180, 2))
+ chan[num_channels++] = 2;
+
+ if (num_channels == 0)
+ return -1;
+
+ *op_channel = p2p_channel_pick_random(chan, num_channels);
+ if (*op_channel == 2)
+ *op_class = 180;
+ else
+ *op_class = 81;
+
+ return 0;
+}
+
+
+int p2p_channels_to_freqs(const struct p2p_channels *channels, int *freq_list,
+ unsigned int max_len)
+{
+ unsigned int i, idx;
+
+ if (!channels || max_len == 0)
+ return 0;
+
+ for (i = 0, idx = 0; i < channels->reg_classes; i++) {
+ const struct p2p_reg_class *c = &channels->reg_class[i];
+ unsigned int j;
+
+ if (idx + 1 == max_len)
+ break;
+ for (j = 0; j < c->channels; j++) {
+ int freq;
+ if (idx + 1 == max_len)
+ break;
+ freq = p2p_channel_to_freq(c->reg_class,
+ c->channel[j]);
+ if (freq < 0)
+ continue;
+ freq_list[idx++] = freq;
+ }
+ }
+
+ freq_list[idx] = 0;
+
+ return idx;
+}
diff --git a/contrib/wpa/src/pae/Makefile b/contrib/wpa/src/pae/Makefile
new file mode 100644
index 0000000..9c41962
--- /dev/null
+++ b/contrib/wpa/src/pae/Makefile
@@ -0,0 +1,8 @@
+all:
+ @echo Nothing to be made.
+
+clean:
+ rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
diff --git a/contrib/wpa/src/pae/ieee802_1x_cp.c b/contrib/wpa/src/pae/ieee802_1x_cp.c
new file mode 100644
index 0000000..cf43c59
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_cp.c
@@ -0,0 +1,744 @@
+/*
+ * IEEE 802.1X-2010 Controlled Port of PAE state machine - CP state machine
+ * Copyright (c) 2013-2014, 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/defs.h"
+#include "common/ieee802_1x_defs.h"
+#include "utils/state_machine.h"
+#include "ieee802_1x_kay.h"
+#include "ieee802_1x_secy_ops.h"
+#include "pae/ieee802_1x_cp.h"
+
+#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;
+
+/* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
+enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
+
+struct ieee802_1x_cp_sm {
+ enum cp_states {
+ CP_BEGIN, CP_INIT, CP_CHANGE, CP_ALLOWED, CP_AUTHENTICATED,
+ CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT,
+ CP_TRANSMITTING, CP_ABANDON, CP_RETIRE
+ } CP_state;
+ Boolean changed;
+
+ /* CP -> Client */
+ Boolean port_valid;
+
+ /* 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;
+ Boolean new_sak; /* clear by CP */
+ struct ieee802_1x_mka_ki distributed_ki;
+ u8 distributed_an;
+ Boolean using_receive_sas;
+ Boolean all_receiving;
+ Boolean server_transmitting;
+ Boolean using_transmit_sa;
+
+ /* CP -> KaY */
+ struct ieee802_1x_mka_ki *lki;
+ u8 lan;
+ Boolean ltx;
+ Boolean lrx;
+ struct ieee802_1x_mka_ki *oki;
+ u8 oan;
+ Boolean otx;
+ Boolean orx;
+
+ /* CP -> SecY */
+ Boolean protect_frames;
+ enum validate_frames validate_frames;
+
+ Boolean replay_protect;
+ u32 replay_window;
+
+ u8 *current_cipher_suite;
+ enum confidentiality_offset confidentiality_offset;
+ Boolean controlled_port_enabled;
+
+ /* SecY -> CP */
+ Boolean port_enabled; /* SecY->CP */
+
+ /* private */
+ u32 transmit_when;
+ u32 transmit_delay;
+ u32 retire_when;
+ u32 retire_delay;
+
+ /* not defined IEEE Std 802.1X-2010 */
+ struct ieee802_1x_kay *kay;
+};
+
+static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx,
+ void *timeout_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;
+}
+
+
+static int changed_connect(struct ieee802_1x_cp_sm *sm)
+{
+ return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm);
+}
+
+
+SM_STATE(CP, INIT)
+{
+ SM_ENTRY(CP, INIT);
+
+ sm->controlled_port_enabled = FALSE;
+ secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
+
+ sm->port_valid = FALSE;
+
+ os_free(sm->lki);
+ sm->lki = NULL;
+ sm->ltx = FALSE;
+ sm->lrx = FALSE;
+
+ os_free(sm->oki);
+ sm->oki = NULL;
+ sm->otx = FALSE;
+ sm->orx = FALSE;
+
+ sm->port_enabled = TRUE;
+ sm->chgd_server = FALSE;
+}
+
+
+SM_STATE(CP, CHANGE)
+{
+ SM_ENTRY(CP, CHANGE);
+
+ sm->port_valid = FALSE;
+ sm->controlled_port_enabled = FALSE;
+ secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
+
+ if (sm->lki)
+ ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
+ if (sm->oki)
+ ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+}
+
+
+SM_STATE(CP, ALLOWED)
+{
+ SM_ENTRY(CP, ALLOWED);
+
+ sm->protect_frames = FALSE;
+ sm->replay_protect = FALSE;
+ sm->validate_frames = Checked;
+
+ sm->port_valid = FALSE;
+ sm->controlled_port_enabled = TRUE;
+
+ secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
+ secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
+ secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
+}
+
+
+SM_STATE(CP, AUTHENTICATED)
+{
+ SM_ENTRY(CP, AUTHENTICATED);
+
+ sm->protect_frames = FALSE;
+ sm->replay_protect = FALSE;
+ sm->validate_frames = Checked;
+
+ sm->port_valid = FALSE;
+ sm->controlled_port_enabled = TRUE;
+
+ secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
+ secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
+ secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
+}
+
+
+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;
+
+ /* 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);
+
+ sm->confidentiality_offset = sm->cipher_offset;
+
+ sm->port_valid = TRUE;
+
+ secy_cp_control_confidentiality_offset(sm->kay,
+ sm->confidentiality_offset);
+ secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
+ secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
+}
+
+
+SM_STATE(CP, RECEIVE)
+{
+ SM_ENTRY(CP, RECEIVE);
+ /* RECEIVE state machine not keep with Figure 12-2 in
+ * IEEE Std 802.1X-2010 */
+ sm->oki = sm->lki;
+ sm->oan = sm->lan;
+ sm->otx = sm->ltx;
+ sm->orx = sm->lrx;
+ ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
+ sm->otx, sm->orx);
+
+ sm->lki = os_malloc(sizeof(*sm->lki));
+ if (!sm->lki) {
+ wpa_printf(MSG_ERROR, "CP-%s: Out of memory", __func__);
+ return;
+ }
+ os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki));
+ sm->lan = sm->distributed_an;
+ sm->ltx = FALSE;
+ sm->lrx = FALSE;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
+ ieee802_1x_kay_create_sas(sm->kay, sm->lki);
+ ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki);
+ sm->new_sak = FALSE;
+ sm->all_receiving = FALSE;
+}
+
+
+SM_STATE(CP, RECEIVING)
+{
+ SM_ENTRY(CP, RECEIVING);
+
+ sm->lrx = TRUE;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
+ sm->transmit_when = sm->transmit_delay;
+ eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
+ eloop_register_timeout(sm->transmit_when / 1000, 0,
+ ieee802_1x_cp_transmit_when_timeout, sm, NULL);
+ /* the electedSelf have been set before CP entering to RECEIVING
+ * but the CP will transmit from RECEIVING to READY under
+ * the !electedSelf when KaY is not key server */
+ ieee802_1x_cp_sm_step(sm);
+ sm->using_receive_sas = FALSE;
+ sm->server_transmitting = FALSE;
+}
+
+
+SM_STATE(CP, READY)
+{
+ SM_ENTRY(CP, READY);
+
+ ieee802_1x_kay_enable_new_info(sm->kay);
+}
+
+
+SM_STATE(CP, TRANSMIT)
+{
+ SM_ENTRY(CP, TRANSMIT);
+
+ sm->controlled_port_enabled = TRUE;
+ secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
+ sm->ltx = TRUE;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
+ ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki);
+ sm->all_receiving = FALSE;
+ sm->server_transmitting = FALSE;
+}
+
+
+SM_STATE(CP, TRANSMITTING)
+{
+ SM_ENTRY(CP, TRANSMITTING);
+ sm->retire_when = sm->orx ? sm->retire_delay : 0;
+ sm->otx = FALSE;
+ ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
+ sm->otx, sm->orx);
+ ieee802_1x_kay_enable_new_info(sm->kay);
+ eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
+ eloop_register_timeout(sm->retire_when / 1000, 0,
+ ieee802_1x_cp_retire_when_timeout, sm, NULL);
+ sm->using_transmit_sa = FALSE;
+}
+
+
+SM_STATE(CP, ABANDON)
+{
+ SM_ENTRY(CP, ABANDON);
+ sm->lrx = FALSE;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
+ ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
+
+ os_free(sm->lki);
+ sm->lki = NULL;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
+ sm->new_sak = FALSE;
+}
+
+
+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;
+ sm->orx = FALSE;
+ sm->otx = FALSE;
+ ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
+ sm->otx, sm->orx);
+}
+
+
+/**
+ * CP state machine handler entry
+ */
+SM_STEP(CP)
+{
+ if (!sm->port_enabled)
+ SM_ENTER(CP, INIT);
+
+ switch (sm->CP_state) {
+ case CP_BEGIN:
+ SM_ENTER(CP, INIT);
+ break;
+
+ case CP_INIT:
+ SM_ENTER(CP, CHANGE);
+ break;
+
+ case CP_CHANGE:
+ if (sm->connect == UNAUTHENTICATED)
+ SM_ENTER(CP, ALLOWED);
+ else if (sm->connect == AUTHENTICATED)
+ SM_ENTER(CP, AUTHENTICATED);
+ else if (sm->connect == SECURE)
+ SM_ENTER(CP, SECURED);
+ break;
+
+ case CP_ALLOWED:
+ if (sm->connect != UNAUTHENTICATED)
+ SM_ENTER(CP, CHANGE);
+ break;
+
+ case CP_AUTHENTICATED:
+ if (sm->connect != AUTHENTICATED)
+ SM_ENTER(CP, CHANGE);
+ break;
+
+ case CP_SECURED:
+ if (changed_connect(sm))
+ SM_ENTER(CP, CHANGE);
+ else if (sm->new_sak)
+ SM_ENTER(CP, RECEIVE);
+ break;
+
+ case CP_RECEIVE:
+ if (sm->using_receive_sas)
+ SM_ENTER(CP, RECEIVING);
+ break;
+
+ case CP_RECEIVING:
+ if (sm->new_sak || changed_connect(sm))
+ SM_ENTER(CP, ABANDON);
+ if (!sm->elected_self)
+ SM_ENTER(CP, READY);
+ if (sm->elected_self &&
+ (sm->all_receiving || !sm->transmit_when))
+ SM_ENTER(CP, TRANSMIT);
+ break;
+
+ case CP_TRANSMIT:
+ if (sm->using_transmit_sa)
+ SM_ENTER(CP, TRANSMITTING);
+ break;
+
+ case CP_TRANSMITTING:
+ if (!sm->retire_when || changed_connect(sm))
+ SM_ENTER(CP, RETIRE);
+ break;
+
+ case CP_RETIRE:
+ if (changed_connect(sm))
+ SM_ENTER(CP, CHANGE);
+ else if (sm->new_sak)
+ SM_ENTER(CP, RECEIVE);
+ break;
+
+ case CP_READY:
+ if (sm->new_sak || changed_connect(sm))
+ SM_ENTER(CP, RECEIVE);
+ if (sm->server_transmitting)
+ SM_ENTER(CP, TRANSMIT);
+ break;
+ case CP_ABANDON:
+ if (changed_connect(sm))
+ SM_ENTER(CP, RETIRE);
+ else if (sm->new_sak)
+ SM_ENTER(CP, RECEIVE);
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "CP: the state machine is not defined");
+ break;
+ }
+}
+
+
+/**
+ * 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 *sm;
+
+ sm = os_zalloc(sizeof(*sm));
+ if (sm == NULL) {
+ wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
+ return NULL;
+ }
+
+ sm->kay = kay;
+
+ sm->port_valid = FALSE;
+
+ 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->controlled_port_enabled = FALSE;
+
+ sm->lki = NULL;
+ sm->lrx = FALSE;
+ sm->ltx = FALSE;
+ sm->oki = NULL;
+ 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->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_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;
+}
+
+
+static void ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm *sm)
+{
+ enum cp_states prev_state;
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ prev_state = sm->CP_state;
+ SM_STEP_RUN(CP);
+ if (prev_state == sm->CP_state)
+ break;
+ }
+}
+
+
+static void ieee802_1x_cp_step_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = eloop_ctx;
+ ieee802_1x_cp_step_run(sm);
+}
+
+
+/**
+ * ieee802_1x_cp_sm_deinit -
+ */
+void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm)
+{
+ wpa_printf(MSG_DEBUG, "CP: state machine removed");
+ if (!sm)
+ return;
+
+ eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
+ eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
+ 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);
+}
+
+
+/**
+ * ieee802_1x_cp_connect_pending
+ */
+void ieee802_1x_cp_connect_pending(void *cp_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+
+ sm->connect = PENDING;
+}
+
+
+/**
+ * ieee802_1x_cp_connect_unauthenticated
+ */
+void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = (struct ieee802_1x_cp_sm *)cp_ctx;
+
+ sm->connect = UNAUTHENTICATED;
+}
+
+
+/**
+ * ieee802_1x_cp_connect_authenticated
+ */
+void ieee802_1x_cp_connect_authenticated(void *cp_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+
+ sm->connect = AUTHENTICATED;
+}
+
+
+/**
+ * ieee802_1x_cp_connect_secure
+ */
+void ieee802_1x_cp_connect_secure(void *cp_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+
+ sm->connect = SECURE;
+}
+
+
+/**
+ * ieee802_1x_cp_set_chgdserver -
+ */
+void ieee802_1x_cp_signal_chgdserver(void *cp_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+
+ sm->chgd_server = TRUE;
+}
+
+
+/**
+ * ieee802_1x_cp_set_electedself -
+ */
+void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->elected_self = 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)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ os_memcpy(sm->cipher_suite, pid, CS_ID_LEN);
+}
+
+
+/**
+ * ieee802_1x_cp_set_offset -
+ */
+void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->cipher_offset = offset;
+}
+
+
+/**
+ * ieee802_1x_cp_signal_newsak -
+ */
+void ieee802_1x_cp_signal_newsak(void *cp_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->new_sak = TRUE;
+}
+
+
+/**
+ * ieee802_1x_cp_set_distributedki -
+ */
+void ieee802_1x_cp_set_distributedki(void *cp_ctx,
+ const struct ieee802_1x_mka_ki *dki)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ os_memcpy(&sm->distributed_ki, dki, sizeof(struct ieee802_1x_mka_ki));
+}
+
+
+/**
+ * ieee802_1x_cp_set_distributedan -
+ */
+void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->distributed_an = an;
+}
+
+
+/**
+ * ieee802_1x_cp_set_usingreceivesas -
+ */
+void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->using_receive_sas = status;
+}
+
+
+/**
+ * ieee802_1x_cp_set_allreceiving -
+ */
+void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->all_receiving = status;
+}
+
+
+/**
+ * ieee802_1x_cp_set_servertransmitting -
+ */
+void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->server_transmitting = status;
+}
+
+
+/**
+ * ieee802_1x_cp_set_usingtransmitsas -
+ */
+void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->using_transmit_sa = status;
+}
+
+
+/**
+ * ieee802_1x_cp_sm_step - Advance EAPOL state machines
+ * @sm: EAPOL state machine
+ *
+ * This function is called to advance CP state machines after any change
+ * that could affect their state.
+ */
+void ieee802_1x_cp_sm_step(void *cp_ctx)
+{
+ /*
+ * Run ieee802_1x_cp_step_run from a registered timeout
+ * to make sure that other possible timeouts/events are processed
+ * and to avoid long function call chains.
+ */
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
+ eloop_register_timeout(0, 0, ieee802_1x_cp_step_cb, sm, NULL);
+}
+
+
+static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = eloop_ctx;
+ sm->retire_when = 0;
+ ieee802_1x_cp_step_run(sm);
+}
+
+
+static void
+ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ieee802_1x_cp_sm *sm = eloop_ctx;
+ sm->transmit_when = 0;
+ ieee802_1x_cp_step_run(sm);
+}
diff --git a/contrib/wpa/src/pae/ieee802_1x_cp.h b/contrib/wpa/src/pae/ieee802_1x_cp.h
new file mode 100644
index 0000000..773c930
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_cp.h
@@ -0,0 +1,50 @@
+/*
+ * IEEE Std 802.1X-2010 Controlled Port of PAE state machine - CP state machine
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_1X_CP_H
+#define IEEE802_1X_CP_H
+
+#include "common/defs.h"
+#include "common/ieee802_1x_defs.h"
+
+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);
+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);
+void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx);
+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_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,
+ const struct ieee802_1x_mka_ki *dki);
+void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an);
+void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status);
+void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status);
+void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status);
+void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status);
+
+#endif /* IEEE802_1X_CP_H */
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay.c b/contrib/wpa/src/pae/ieee802_1x_kay.c
new file mode 100644
index 0000000..ef74430
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_kay.c
@@ -0,0 +1,3541 @@
+/*
+ * IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <time.h>
+#include "includes.h"
+#include "common.h"
+#include "list.h"
+#include "eloop.h"
+#include "wpabuf.h"
+#include "state_machine.h"
+#include "l2_packet/l2_packet.h"
+#include "common/eapol_common.h"
+#include "crypto/aes_wrap.h"
+#include "ieee802_1x_cp.h"
+#include "ieee802_1x_key.h"
+#include "ieee802_1x_kay.h"
+#include "ieee802_1x_kay_i.h"
+#include "ieee802_1x_secy_ops.h"
+
+
+#define DEFAULT_SA_KEY_LEN 16
+#define DEFAULT_ICV_LEN 16
+#define MAX_ICV_LEN 32 /* 32 bytes, 256 bits */
+
+#define PENDING_PN_EXHAUSTION 0xC0000000
+
+/* 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;
+
+/* IEEE802.1AE-2006 Table 14-1 MACsec Cipher Suites */
+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 */
+ },
+};
+#define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
+#define DEFAULT_CS_INDEX 0
+
+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 */
+ },
+};
+#define MKA_ALG_TABLE_SIZE (ARRAY_SIZE(mka_alg_tbl))
+
+
+static int is_ki_equal(struct ieee802_1x_mka_ki *ki1,
+ struct ieee802_1x_mka_ki *ki2)
+{
+ return os_memcmp(ki1->mi, ki2->mi, MI_LEN) == 0 &&
+ ki1->kn == ki2->kn;
+}
+
+
+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;
+ hdr->length = (len >> 8) & 0x0f;
+ hdr->length1 = len & 0xff;
+}
+
+
+static unsigned int get_mka_param_body_len(const void *body)
+{
+ const struct ieee802_1x_mka_hdr *hdr = body;
+ return (hdr->length << 8) | hdr->length1;
+}
+
+
+static int get_mka_param_body_type(const void *body)
+{
+ const struct ieee802_1x_mka_hdr *hdr = body;
+ return hdr->type;
+}
+
+
+/**
+ * ieee802_1x_mka_dump_basic_body -
+ */
+static void
+ieee802_1x_mka_dump_basic_body(struct ieee802_1x_mka_basic_body *body)
+{
+ size_t body_len;
+
+ if (!body)
+ return;
+
+ 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",
+ 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));
+}
+
+
+/**
+ * ieee802_1x_mka_dump_peer_body -
+ */
+static void
+ieee802_1x_mka_dump_peer_body(struct ieee802_1x_mka_peer_body *body)
+{
+ size_t body_len;
+ size_t i;
+ u8 *mi;
+ u32 mn;
+
+ if (body == NULL)
+ return;
+
+ 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);
+ } 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);
+ }
+
+ 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));
+ }
+}
+
+
+/**
+ * ieee802_1x_mka_dump_dist_sak_body -
+ */
+static void
+ieee802_1x_mka_dump_dist_sak_body(struct ieee802_1x_mka_dist_sak_body *body)
+{
+ size_t body_len;
+
+ if (body == NULL)
+ return;
+
+ 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",
+ body->confid_offset);
+ wpa_printf(MSG_INFO, "\tBody Length...........: %d", (int) body_len);
+ if (!body_len)
+ return;
+
+ wpa_printf(MSG_INFO, "\tKey Number............: %d",
+ be_to_host32(body->kn));
+ wpa_hexdump(MSG_INFO, "\tAES Key Wrap of SAK...:", body->sak, 24);
+}
+
+
+static const char * yes_no(int val)
+{
+ return val ? "Yes" : "No";
+}
+
+
+/**
+ * ieee802_1x_mka_dump_sak_use_body -
+ */
+static void
+ieee802_1x_mka_dump_sak_use_body(struct ieee802_1x_mka_sak_use_body *body)
+{
+ int body_len;
+
+ if (body == NULL)
+ return;
+
+ body_len = get_mka_param_body_len(body);
+ wpa_printf(MSG_DEBUG, "*** MACsec SAK Use ***");
+ 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, "\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 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",
+ be_to_host32(body->okn));
+ wpa_printf(MSG_DEBUG, "\tOld Lowest PN........: %u",
+ be_to_host32(body->olpn));
+}
+
+
+/**
+ * ieee802_1x_kay_get_participant -
+ */
+static struct ieee802_1x_mka_participant *
+ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn)
+{
+ 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,
+ participant->ckn.len) == 0)
+ return participant;
+ }
+
+ wpa_printf(MSG_DEBUG, "KaY: participant is not found");
+
+ return NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_get_principal_participant -
+ */
+static struct ieee802_1x_mka_participant *
+ieee802_1x_kay_get_principal_participant(struct ieee802_1x_kay *kay)
+{
+ struct ieee802_1x_mka_participant *participant;
+
+ dl_list_for_each(participant, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ if (participant->principal)
+ return participant;
+ }
+
+ wpa_printf(MSG_DEBUG, "KaY: principal participant is not founded");
+ return NULL;
+}
+
+
+static struct ieee802_1x_kay_peer * get_peer_mi(struct dl_list *peers,
+ const u8 *mi)
+{
+ struct ieee802_1x_kay_peer *peer;
+
+ dl_list_for_each(peer, peers, struct ieee802_1x_kay_peer, list) {
+ if (os_memcmp(peer->mi, mi, MI_LEN) == 0)
+ return peer;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_is_in_potential_peer
+ */
+static Boolean
+ieee802_1x_kay_is_in_potential_peer(
+ struct ieee802_1x_mka_participant *participant, const u8 *mi)
+{
+ return get_peer_mi(&participant->potential_peers, mi) != NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_is_in_live_peer
+ */
+static Boolean
+ieee802_1x_kay_is_in_live_peer(
+ struct ieee802_1x_mka_participant *participant, const u8 *mi)
+{
+ return get_peer_mi(&participant->live_peers, mi) != NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_is_in_peer
+ */
+static Boolean
+ieee802_1x_kay_is_in_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);
+}
+
+
+/**
+ * ieee802_1x_kay_get_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_get_peer(struct ieee802_1x_mka_participant *participant,
+ const u8 *mi)
+{
+ struct ieee802_1x_kay_peer *peer;
+
+ peer = get_peer_mi(&participant->live_peers, 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);
+}
+
+
+/**
+ * ieee802_1x_kay_get_cipher_suite
+ */
+static struct macsec_ciphersuite *
+ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
+ u8 *cs_id)
+{
+ unsigned int i;
+
+ for (i = 0; i < CS_TABLE_SIZE; i++) {
+ if (os_memcmp(cipher_suite_tbl[i].id, cs_id, CS_ID_LEN) == 0)
+ break;
+ }
+ if (i >= CS_TABLE_SIZE)
+ return NULL;
+
+ return &cipher_suite_tbl[i];
+}
+
+
+/**
+ * ieee802_1x_kay_get_peer_sci
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_get_peer_sci(struct ieee802_1x_mka_participant *participant,
+ const struct ieee802_1x_mka_sci *sci)
+{
+ struct ieee802_1x_kay_peer *peer;
+
+ dl_list_for_each(peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
+ 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)
+ return peer;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_init_receive_sa -
+ */
+static struct receive_sa *
+ieee802_1x_kay_init_receive_sa(struct receive_sc *psc, u8 an, u32 lowest_pn,
+ struct data_key *key)
+{
+ struct receive_sa *psa;
+
+ if (!psc || !key)
+ return NULL;
+
+ psa = os_zalloc(sizeof(*psa));
+ if (!psa) {
+ wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
+ return NULL;
+ }
+
+ psa->pkey = key;
+ psa->lowest_pn = lowest_pn;
+ psa->next_pn = lowest_pn;
+ psa->an = an;
+ psa->sc = psc;
+
+ os_get_time(&psa->created_time);
+ psa->in_use = FALSE;
+
+ 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);
+
+ return psa;
+}
+
+
+/**
+ * ieee802_1x_kay_deinit_receive_sa -
+ */
+static void ieee802_1x_kay_deinit_receive_sa(struct receive_sa *psa)
+{
+ psa->pkey = NULL;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Delete receive SA(an: %d) of SC(channel: %d)",
+ psa->an, psa->sc->channel);
+ dl_list_del(&psa->list);
+ os_free(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)
+{
+ struct receive_sc *psc;
+
+ if (!psci)
+ return NULL;
+
+ psc = os_zalloc(sizeof(*psc));
+ if (!psc) {
+ wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
+ return NULL;
+ }
+
+ 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));
+
+ return psc;
+}
+
+
+/**
+ * ieee802_1x_kay_deinit_receive_sc -
+ **/
+static void
+ieee802_1x_kay_deinit_receive_sc(
+ struct ieee802_1x_mka_participant *participant, struct receive_sc *psc)
+{
+ struct receive_sa *psa, *pre_sa;
+
+ wpa_printf(MSG_DEBUG, "KaY: Delete receive SC(channel: %d)",
+ psc->channel);
+ 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);
+ }
+ dl_list_del(&psc->list);
+ os_free(psc);
+}
+
+
+/**
+ * ieee802_1x_kay_create_live_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
+ 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) {
+ wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+ return NULL;
+ }
+
+ os_memcpy(peer->mi, mi, MI_LEN);
+ peer->mn = mn;
+ peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+ peer->sak_used = FALSE;
+ 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)
+ return NULL;
+
+ 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);
+
+ return peer;
+}
+
+
+/**
+ * ieee802_1x_kay_create_potential_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_create_potential_peer(
+ struct ieee802_1x_mka_participant *participant, const u8 *mi, u32 mn)
+{
+ struct ieee802_1x_kay_peer *peer;
+
+ peer = os_zalloc(sizeof(*peer));
+ if (peer == NULL) {
+ wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+ 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);
+
+ return peer;
+}
+
+
+/**
+ * ieee802_1x_kay_move_live_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_move_live_peer(struct ieee802_1x_mka_participant *participant,
+ u8 *mi, u32 mn)
+{
+ 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;
+ }
+
+ 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);
+
+ 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)
+ return NULL;
+
+ dl_list_add(&participant->rxsc_list, &rxsc->list);
+ secy_create_receive_sc(participant->kay, rxsc);
+
+ return peer;
+}
+
+
+
+/**
+ * ieee802_1x_mka_basic_body_present -
+ */
+static Boolean
+ieee802_1x_mka_basic_body_present(
+ struct ieee802_1x_mka_participant *participant)
+{
+ return TRUE;
+}
+
+
+/**
+ * ieee802_1x_mka_basic_body_length -
+ */
+static int
+ieee802_1x_mka_basic_body_length(struct ieee802_1x_mka_participant *participant)
+{
+ int length;
+
+ length = sizeof(struct ieee802_1x_mka_basic_body);
+ length += participant->ckn.len;
+ return (length + 0x3) & ~0x3;
+}
+
+
+/**
+ * ieee802_1x_mka_encode_basic_body
+ */
+static int
+ieee802_1x_mka_encode_basic_body(
+ struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf)
+{
+ struct ieee802_1x_mka_basic_body *body;
+ struct ieee802_1x_kay *kay = participant->kay;
+ unsigned int length = ieee802_1x_mka_basic_body_length(participant);
+
+ body = wpabuf_put(buf, length);
+
+ body->version = kay->mka_version;
+ body->priority = kay->actor_priority;
+ 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;
+ 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);
+
+ 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,
+ sizeof(body->algo_agility));
+
+ os_memcpy(body->ckn, participant->ckn.name, participant->ckn.len);
+
+ ieee802_1x_mka_dump_basic_body(body);
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_decode_basic_body -
+ */
+static struct ieee802_1x_mka_participant *
+ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
+ size_t msg_len)
+{
+ struct ieee802_1x_mka_participant *participant;
+ const struct ieee802_1x_mka_basic_body *body;
+ struct ieee802_1x_kay_peer *peer;
+
+ 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)",
+ body->version, MKA_VERSION_ID);
+ }
+ if (kay->is_obliged_key_server && body->key_server) {
+ wpa_printf(MSG_DEBUG, "I must be as key server");
+ return NULL;
+ }
+
+ participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+ if (!participant) {
+ wpa_printf(MSG_DEBUG, "Peer is not included in my CA");
+ 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)
+ return NULL;
+ participant->mn = 0;
+ }
+
+ os_memcpy(participant->current_peer_id.mi, body->actor_mi, MI_LEN);
+ participant->current_peer_id.mn = be_to_host32(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);
+
+ /* 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?
+ */
+ peer = ieee802_1x_kay_get_peer_sci(participant,
+ &body->actor_sci);
+ if (peer) {
+ wpa_printf(MSG_WARNING,
+ "KaY: duplicated SCI detected, Maybe active attacker");
+ dl_list_del(&peer->list);
+ os_free(peer);
+ }
+
+ peer = ieee802_1x_kay_create_potential_peer(
+ participant, body->actor_mi,
+ be_to_host32(body->actor_mn));
+ if (!peer)
+ return NULL;
+
+ peer->macsec_desired = body->macsec_desired;
+ peer->macsec_capbility = body->macsec_capbility;
+ 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->is_key_server = (Boolean) body->key_server;
+ peer->key_server_priority = body->priority;
+ } else {
+ wpa_printf(MSG_WARNING, "KaY: The peer MN have received");
+ return NULL;
+ }
+
+ return participant;
+}
+
+
+/**
+ * ieee802_1x_mka_live_peer_body_present
+ */
+static Boolean
+ieee802_1x_mka_live_peer_body_present(
+ struct ieee802_1x_mka_participant *participant)
+{
+ return !dl_list_empty(&participant->live_peers);
+}
+
+
+/**
+ * ieee802_1x_kay_get_live_peer_length
+ */
+static int
+ieee802_1x_mka_get_live_peer_length(
+ struct ieee802_1x_mka_participant *participant)
+{
+ int len = MKA_HDR_LEN;
+ struct ieee802_1x_kay_peer *peer;
+
+ dl_list_for_each(peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list)
+ len += sizeof(struct ieee802_1x_mka_peer_id);
+
+ return (len + 0x3) & ~0x3;
+}
+
+
+/**
+ * ieee802_1x_mka_encode_live_peer_body -
+ */
+static int
+ieee802_1x_mka_encode_live_peer_body(
+ struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf)
+{
+ struct ieee802_1x_mka_peer_body *body;
+ struct ieee802_1x_kay_peer *peer;
+ unsigned int length;
+ struct ieee802_1x_mka_peer_id *body_peer;
+
+ length = ieee802_1x_mka_get_live_peer_length(participant);
+ body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_peer_body));
+
+ body->type = MKA_LIVE_PEER_LIST;
+ set_mka_param_body_len(body, length - MKA_HDR_LEN);
+
+ dl_list_for_each(peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ body_peer = wpabuf_put(buf,
+ 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);
+ return 0;
+}
+
+/**
+ * ieee802_1x_mka_potential_peer_body_present
+ */
+static Boolean
+ieee802_1x_mka_potential_peer_body_present(
+ struct ieee802_1x_mka_participant *participant)
+{
+ return !dl_list_empty(&participant->potential_peers);
+}
+
+
+/**
+ * ieee802_1x_kay_get_potential_peer_length
+ */
+static int
+ieee802_1x_mka_get_potential_peer_length(
+ struct ieee802_1x_mka_participant *participant)
+{
+ int len = MKA_HDR_LEN;
+ struct ieee802_1x_kay_peer *peer;
+
+ dl_list_for_each(peer, &participant->potential_peers,
+ struct ieee802_1x_kay_peer, list)
+ len += sizeof(struct ieee802_1x_mka_peer_id);
+
+ return (len + 0x3) & ~0x3;
+}
+
+
+/**
+ * ieee802_1x_mka_encode_potential_peer_body -
+ */
+static int
+ieee802_1x_mka_encode_potential_peer_body(
+ struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf)
+{
+ struct ieee802_1x_mka_peer_body *body;
+ struct ieee802_1x_kay_peer *peer;
+ unsigned int length;
+ struct ieee802_1x_mka_peer_id *body_peer;
+
+ length = ieee802_1x_mka_get_potential_peer_length(participant);
+ body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_peer_body));
+
+ body->type = MKA_POTENTIAL_PEER_LIST;
+ set_mka_param_body_len(body, length - MKA_HDR_LEN);
+
+ dl_list_for_each(peer, &participant->potential_peers,
+ struct ieee802_1x_kay_peer, list) {
+ body_peer = wpabuf_put(buf,
+ 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);
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_i_in_peerlist -
+ */
+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;
+ const u8 *pos;
+ size_t i;
+
+ 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);
+ 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)) {
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+
+ if (included)
+ return TRUE;
+
+SKIP_PEER:
+ left_len -= body_len + MKA_HDR_LEN;
+ pos += body_len + MKA_HDR_LEN;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ * ieee802_1x_mka_decode_live_peer_body -
+ */
+static int ieee802_1x_mka_decode_live_peer_body(
+ struct ieee802_1x_mka_participant *participant,
+ const u8 *peer_msg, size_t msg_len)
+{
+ 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;
+
+ is_included = ieee802_1x_kay_is_in_live_peer(
+ participant, participant->current_peer_id.mi);
+
+ hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
+ body_len = get_mka_param_body_len(hdr);
+
+ 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);
+
+ /* 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;
+ }
+ continue;
+ }
+ if (!is_included)
+ continue;
+
+ peer = ieee802_1x_kay_get_peer(participant, peer_mi);
+ if (NULL != 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;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_decode_potential_peer_body -
+ */
+static int
+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;
+ size_t body_len;
+ u32 peer_mn;
+ const u8 *peer_mi;
+ size_t i;
+
+ hdr = (struct ieee802_1x_mka_hdr *) peer_msg;
+ body_len = get_mka_param_body_len(hdr);
+
+ 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);
+
+ /* 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;
+ }
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_sak_use_body_present
+ */
+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;
+}
+
+
+/**
+ * ieee802_1x_mka_get_sak_use_length
+ */
+static int
+ieee802_1x_mka_get_sak_use_length(
+ struct ieee802_1x_mka_participant *participant)
+{
+ int length = MKA_HDR_LEN;
+
+ 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;
+}
+
+
+/**
+ *
+ */
+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;
+ 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;
+ }
+ }
+ }
+
+ if (lpn == 0)
+ lpn = 1;
+
+ return lpn;
+}
+
+
+/**
+ * ieee802_1x_mka_encode_sak_use_body -
+ */
+static int
+ieee802_1x_mka_encode_sak_use_body(
+ struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf)
+{
+ struct ieee802_1x_mka_sak_use_body *body;
+ 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->type = MKA_SAK_USE;
+ set_mka_param_body_len(body, length - MKA_HDR_LEN);
+
+ if (length == MKA_HDR_LEN) {
+ body->ptx = TRUE;
+ body->prx = TRUE;
+ body->lan = 0;
+ body->lrx = FALSE;
+ body->ltx = FALSE;
+ body->delay_protect = FALSE;
+ return 0;
+ }
+
+ /* data protect, lowest accept packet number */
+ body->delay_protect = participant->kay->macsec_replay_protect;
+ pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
+ if (pn > participant->kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
+ if (participant->is_key_server)
+ participant->new_sak = TRUE;
+ }
+
+ body->llpn = host_to_be32(pn);
+ pn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
+ 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;
+
+ /* 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));
+ body->lkn = host_to_be32(participant->lki.kn);
+ body->lrx = participant->lrx;
+ body->ltx = participant->ltx;
+
+ /* old key: rx, tx, key server member identifier key number */
+ body->oan = participant->oan;
+ if (participant->oki.kn != participant->lki.kn &&
+ participant->oki.kn != 0) {
+ body->otx = TRUE;
+ body->orx = TRUE;
+ os_memcpy(body->osrv_mi, participant->oki.mi,
+ sizeof(body->osrv_mi));
+ body->okn = host_to_be32(participant->oki.kn);
+ } else {
+ body->otx = FALSE;
+ body->orx = FALSE;
+ }
+
+ /* 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;
+ }
+
+ ieee802_1x_mka_dump_sak_use_body(body);
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_decode_sak_use_body -
+ */
+static int
+ieee802_1x_mka_decode_sak_use_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_sak_use_body *body;
+ struct ieee802_1x_kay_peer *peer;
+ struct transmit_sa *txsa;
+ struct data_key *sa_key = NULL;
+ size_t body_len;
+ struct ieee802_1x_mka_ki ki;
+ u32 lpn;
+ Boolean all_receiving;
+ Boolean founded;
+
+ if (!participant->principal) {
+ wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
+ return -1;
+ }
+ 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");
+ return -1;
+ }
+
+ hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
+ body_len = get_mka_param_body_len(hdr);
+ body = (struct ieee802_1x_mka_sak_use_body *) mka_msg;
+ ieee802_1x_mka_dump_sak_use_body(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);
+ return -1;
+ }
+
+ /* TODO: what action should I take when peer does not support MACsec */
+ if (body_len == 0) {
+ wpa_printf(MSG_WARNING, "KaY: Peer does not support MACsec");
+ return 0;
+ }
+
+ /* TODO: when the plain tx or rx of peer is true, should I change
+ * the attribute of controlled port
+ */
+ if (body->prx)
+ wpa_printf(MSG_WARNING, "KaY: peer's plain rx are TRUE");
+
+ if (body->ptx)
+ wpa_printf(MSG_WARNING, "KaY: peer's plain tx are TRUE");
+
+ /* check latest key is valid */
+ if (body->ltx || body->lrx) {
+ founded = FALSE;
+ os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
+ ki.kn = ntohl(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;
+ break;
+ }
+ }
+ if (!founded) {
+ wpa_printf(MSG_WARNING, "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 &&
+ 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);
+ }
+ }
+
+ /* check old key is valid */
+ if (body->otx || body->orx) {
+ if (os_memcmp(participant->oki.mi, body->osrv_mi,
+ sizeof(participant->oki.mi)) != 0 ||
+ ntohl(body->okn) != participant->oki.kn ||
+ body->oan != participant->oan) {
+ wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
+ return -1;
+ }
+ }
+
+ /* TODO: how to set the MACsec hardware when delay_protect is true */
+ if (body->delay_protect && (!ntohl(body->llpn) || !ntohl(body->olpn))) {
+ wpa_printf(MSG_WARNING,
+ "KaY: Lowest packet number should greater than 0 when delay_protect is TRUE");
+ return -1;
+ }
+
+ /* check all live peer have used the sak for receiving sa */
+ all_receiving = TRUE;
+ dl_list_for_each(peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (!peer->sak_used) {
+ all_receiving = FALSE;
+ break;
+ }
+ }
+ 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);
+ }
+
+ /* if i'm key server, and detects peer member pn exhaustion, rekey.*/
+ lpn = ntohl(body->llpn);
+ if (lpn > participant->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 (!founded) {
+ wpa_printf(MSG_WARNING, "KaY: Can't find txsa");
+ 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);
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_dist_sak_body_present
+ */
+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;
+}
+
+
+/**
+ * ieee802_1x_kay_get_dist_sak_length
+ */
+static int
+ieee802_1x_mka_get_dist_sak_length(
+ struct ieee802_1x_mka_participant *participant)
+{
+ int length;
+ int cs_index = participant->kay->macsec_csindex;
+
+ if (participant->advised_desired) {
+ 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;
+}
+
+
+/**
+ * ieee802_1x_mka_encode_dist_sak_body -
+ */
+static int
+ieee802_1x_mka_encode_dist_sak_body(
+ struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf)
+{
+ struct ieee802_1x_mka_dist_sak_body *body;
+ struct data_key *sak;
+ unsigned int length;
+ int cs_index;
+ int sak_pos;
+
+ length = ieee802_1x_mka_get_dist_sak_length(participant);
+ body = wpabuf_put(buf, length);
+ body->type = MKA_DISTRIBUTED_SAK;
+ set_mka_param_body_len(body, length - MKA_HDR_LEN);
+ if (length == MKA_HDR_LEN) {
+ body->confid_offset = 0;
+ body->dan = 0;
+ return 0;
+ }
+
+ sak = participant->new_key;
+ 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 != DEFAULT_CS_INDEX) {
+ os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN);
+ sak_pos = CS_ID_LEN;
+ }
+ if (aes_wrap(participant->kek.key, 16,
+ cipher_suite_tbl[cs_index].sak_len / 8,
+ sak->key, body->sak + sak_pos)) {
+ wpa_printf(MSG_ERROR, "KaY: AES wrap failed");
+ return -1;
+ }
+
+ ieee802_1x_mka_dump_dist_sak_body(body);
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_init_data_key -
+ */
+static struct data_key *
+ieee802_1x_kay_init_data_key(const struct key_conf *conf)
+{
+ 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;
+ os_get_time(&pkey->created_time);
+
+ pkey->user = 1;
+
+ return pkey;
+}
+
+
+/**
+ * ieee802_1x_kay_decode_dist_sak_body -
+ */
+static int
+ieee802_1x_mka_decode_dist_sak_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_dist_sak_body *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;
+
+ 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);
+ return -1;
+ }
+
+ if (!participant->principal) {
+ wpa_printf(MSG_ERROR,
+ "KaY: I can't accept the distributed SAK as I am not principal");
+ return -1;
+ }
+ if (participant->is_key_server) {
+ wpa_printf(MSG_ERROR,
+ "KaY: I can't accept the distributed SAK as myself is key server ");
+ return -1;
+ }
+ if (!participant->kay->macsec_desired ||
+ participant->kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
+ wpa_printf(MSG_ERROR,
+ "KaY: I am not MACsec-desired or without MACsec capable");
+ return -1;
+ }
+
+ peer = ieee802_1x_kay_get_live_peer(participant,
+ participant->current_peer_id.mi);
+ if (!peer) {
+ wpa_printf(MSG_ERROR,
+ "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) {
+ 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;
+ 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;
+ 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);
+
+ body = (struct ieee802_1x_mka_dist_sak_body *)mka_msg;
+ ieee802_1x_mka_dump_dist_sak_body(body);
+ dl_list_for_each(sa_key, &participant->sak_list, struct data_key, list)
+ {
+ 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");
+ return 0;
+ }
+ }
+ if (body_len == 28) {
+ sak_len = DEFAULT_SA_KEY_LEN;
+ wrap_sak = body->sak;
+ participant->kay->macsec_csindex = DEFAULT_CS_INDEX;
+ } else {
+ cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
+ if (!cs) {
+ wpa_printf(MSG_ERROR,
+ "KaY: I can't support the Cipher Suite advised by key server");
+ return -1;
+ }
+ sak_len = cs->sak_len;
+ wrap_sak = body->sak + CS_ID_LEN;
+ participant->kay->macsec_csindex = cs->index;
+ }
+
+ unwrap_sak = os_zalloc(sak_len);
+ if (!unwrap_sak) {
+ 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)) {
+ 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;
+
+ conf->key = os_zalloc(conf->key_len);
+ if (!conf->key) {
+ wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+ os_free(unwrap_sak);
+ os_free(conf);
+ return -1;
+ }
+
+ os_memcpy(conf->key, unwrap_sak, conf->key_len);
+
+ os_memcpy(&sak_ki.mi, &participant->current_peer_id.mi,
+ sizeof(sak_ki.mi));
+ sak_ki.kn = be_to_host32(body->kn);
+
+ 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;
+ }
+
+ 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);
+
+ participant->to_use_sak = TRUE;
+
+ os_free(unwrap_sak);
+ os_free(conf->key);
+ os_free(conf);
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_icv_body_present
+ */
+static Boolean
+ieee802_1x_mka_icv_body_present(struct ieee802_1x_mka_participant *participant)
+{
+ return TRUE;
+}
+
+
+/**
+ * ieee802_1x_kay_get_icv_length
+ */
+static int
+ieee802_1x_mka_get_icv_length(struct ieee802_1x_mka_participant *participant)
+{
+ int length;
+
+ length = sizeof(struct ieee802_1x_mka_icv_body);
+ length += mka_alg_tbl[participant->kay->mka_algindex].icv_len;
+
+ return (length + 0x3) & ~0x3;
+}
+
+
+/**
+ * ieee802_1x_mka_encode_icv_body -
+ */
+static int
+ieee802_1x_mka_encode_icv_body(struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf)
+{
+ struct ieee802_1x_mka_icv_body *body;
+ unsigned int length;
+ u8 cmac[MAX_ICV_LEN];
+
+ length = ieee802_1x_mka_get_icv_length(participant);
+ if (length != DEFAULT_ICV_LEN) {
+ body = wpabuf_put(buf, MKA_HDR_LEN);
+ body->type = MKA_ICV_INDICATOR;
+ set_mka_param_body_len(body, length - MKA_HDR_LEN);
+ }
+
+ 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");
+ return -1;
+ }
+
+ 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);
+ }
+
+ return 0;
+}
+
+/**
+ * ieee802_1x_mka_decode_icv_body -
+ */
+static 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;
+ size_t body_len;
+ size_t left_len;
+ int 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);
+ body_type = get_mka_param_body_type(hdr);
+
+ if (left_len < (body_len + MKA_HDR_LEN))
+ break;
+
+ if (body_type != MKA_ICV_INDICATOR) {
+ left_len -= MKA_HDR_LEN + body_len;
+ pos += MKA_HDR_LEN + body_len;
+ continue;
+ }
+
+ body = (struct ieee802_1x_mka_icv_body *)pos;
+ if (body_len
+ < mka_alg_tbl[participant->kay->mka_algindex].icv_len) {
+ return NULL;
+ }
+
+ return body->icv;
+ }
+
+ return (u8 *) (mka_msg + msg_len - DEFAULT_ICV_LEN);
+}
+
+
+/**
+ * ieee802_1x_mka_decode_dist_cak_body-
+ */
+static int
+ieee802_1x_mka_decode_dist_cak_body(
+ struct ieee802_1x_mka_participant *participant,
+ const u8 *mka_msg, size_t msg_len)
+{
+ struct ieee802_1x_mka_hdr *hdr;
+ size_t body_len;
+
+ hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
+ 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);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_decode_kmd_body -
+ */
+static int
+ieee802_1x_mka_decode_kmd_body(
+ struct ieee802_1x_mka_participant *participant,
+ const u8 *mka_msg, size_t msg_len)
+{
+ struct ieee802_1x_mka_hdr *hdr;
+ size_t body_len;
+
+ hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
+ 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);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_mka_decode_announce_body -
+ */
+static int ieee802_1x_mka_decode_announce_body(
+ struct ieee802_1x_mka_participant *participant,
+ const u8 *mka_msg, size_t msg_len)
+{
+ return 0;
+}
+
+
+static struct mka_param_body_handler mak_body_handler[] = {
+ /* basic parameter set */
+ {
+ ieee802_1x_mka_encode_basic_body,
+ NULL,
+ ieee802_1x_mka_basic_body_length,
+ ieee802_1x_mka_basic_body_present
+ },
+
+ /* 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
+ },
+
+ /* 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
+ },
+
+ /* 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
+ },
+
+ /* distribute 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
+ },
+
+ /* distribute cak parameter set */
+ {
+ NULL,
+ ieee802_1x_mka_decode_dist_cak_body,
+ NULL,
+ NULL
+ },
+
+ /* kmd parameter set */
+ {
+ NULL,
+ ieee802_1x_mka_decode_kmd_body,
+ NULL,
+ NULL
+ },
+
+ /* announce parameter set */
+ {
+ NULL,
+ ieee802_1x_mka_decode_announce_body,
+ NULL,
+ NULL
+ },
+
+ /* icv parameter set */
+ {
+ ieee802_1x_mka_encode_icv_body,
+ NULL,
+ ieee802_1x_mka_get_icv_length,
+ ieee802_1x_mka_icv_body_present
+ },
+};
+
+
+/**
+ * ieee802_1x_kay_deinit_data_key -
+ */
+void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
+{
+ if (!pkey)
+ return;
+
+ pkey->user--;
+ if (pkey->user > 1)
+ return;
+
+ dl_list_del(&pkey->list);
+ os_free(pkey->key);
+ os_free(pkey);
+}
+
+
+/**
+ * ieee802_1x_kay_generate_new_sak -
+ */
+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;
+
+ /* check condition for generating a fresh SAK:
+ * must have one live peer
+ * and MKA life time elapse since last distribution
+ * or potential peer is empty
+ */
+ if (dl_list_empty(&participant->live_peers)) {
+ wpa_printf(MSG_ERROR,
+ "KaY: Live peers list must not empty when generating fresh SAK");
+ return -1;
+ }
+
+ /* FIXME: A fresh SAK not generated until
+ * the live peer list contains at least one peer and
+ * MKA life time has elapsed since the prior SAK was first distributed,
+ * or the Key server's potential peer is empty
+ * but I can't understand the second item, so
+ * here only check first item and ingore
+ * && (!dl_list_empty(&participant->potential_peers))) {
+ */
+ 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__);
+ 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);
+ wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+ return -1;
+ }
+
+ ctx_len = conf->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;
+ }
+ 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;
+ dl_list_for_each(peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ os_memcpy(context + ctx_offset, peer->mi, sizeof(peer->mi));
+ ctx_offset += sizeof(peer->mi);
+ }
+ os_memcpy(context + ctx_offset, participant->mi,
+ sizeof(participant->mi));
+ 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);
+ } else {
+ wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
+ os_free(conf->key);
+ os_free(conf);
+ os_free(context);
+ return -1;
+ }
+ 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;
+
+ sa_key = ieee802_1x_kay_init_data_key(conf);
+ if (!sa_key) {
+ os_free(conf->key);
+ os_free(conf);
+ os_free(context);
+ return -1;
+ }
+ participant->new_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_sm_step(kay->cp);
+ ieee802_1x_cp_set_offset(kay->cp, conf->offset);
+ 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_signal_newsak(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+
+ dl_list_for_each(peer, &participant->live_peers,
+ 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;
+
+ participant->kay->dist_time = time(NULL);
+
+ os_free(conf->key);
+ os_free(conf);
+ os_free(context);
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_elect_key_server - elect the key server
+ * when to elect: whenever the live peers list changes
+ */
+static int
+ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
+{
+ struct ieee802_1x_kay_peer *peer;
+ struct ieee802_1x_kay_peer *key_server = NULL;
+ struct ieee802_1x_kay *kay = participant->kay;
+ Boolean i_is_key_server;
+ int i;
+
+ if (participant->is_obliged_key_server) {
+ participant->new_sak = TRUE;
+ participant->to_dist_sak = FALSE;
+ ieee802_1x_cp_set_electedself(kay->cp, TRUE);
+ return 0;
+ }
+
+ /* elect the key server among the peers */
+ dl_list_for_each(peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (!peer->is_key_server)
+ continue;
+
+ if (!key_server) {
+ key_server = peer;
+ continue;
+ }
+
+ if (peer->key_server_priority <
+ key_server->key_server_priority) {
+ 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) {
+ 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;
+ }
+ }
+ }
+ }
+
+ if (!key_server && !i_is_key_server) {
+ participant->principal = FALSE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = FALSE;
+ return 0;
+ }
+
+ 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))) {
+ ieee802_1x_cp_signal_chgdserver(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
+
+ participant->is_key_server = TRUE;
+ participant->principal = TRUE;
+ participant->new_sak = TRUE;
+ wpa_printf(MSG_DEBUG, "KaY: I is 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) {
+ ieee802_1x_cp_set_electedself(kay->cp, FALSE);
+ if (os_memcmp(&kay->key_server_sci, &key_server->sci,
+ sizeof(kay->key_server_sci))) {
+ ieee802_1x_cp_signal_chgdserver(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
+
+ participant->is_key_server = FALSE;
+ participant->principal = TRUE;
+ participant->is_elected = TRUE;
+
+ os_memcpy(&kay->key_server_sci, &key_server->sci,
+ sizeof(kay->key_server_sci));
+ kay->key_server_priority = key_server->key_server_priority;
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_decide_macsec_use - the key server determinate
+ * how to use MACsec: whether use MACsec and its capability
+ * protectFrames will be advised if the key server and one of its live peers are
+ * MACsec capable and one of those request MACsec protection
+ */
+static int
+ieee802_1x_kay_decide_macsec_use(
+ struct ieee802_1x_mka_participant *participant)
+{
+ struct ieee802_1x_kay *kay = participant->kay;
+ struct ieee802_1x_kay_peer *peer;
+ enum macsec_cap less_capability;
+ Boolean has_peer;
+
+ if (!participant->is_key_server)
+ return -1;
+
+ /* key server self is MACsec-desired and requesting MACsec */
+ if (!kay->macsec_desired) {
+ participant->advised_desired = FALSE;
+ return -1;
+ }
+ if (kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
+ participant->advised_desired = FALSE;
+ return -1;
+ }
+ less_capability = kay->macsec_capable;
+
+ /* at least one of peers is MACsec-desired and requesting MACsec */
+ has_peer = FALSE;
+ dl_list_for_each(peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (!peer->macsec_desired)
+ continue;
+
+ if (peer->macsec_capbility == MACSEC_CAP_NOT_IMPLEMENTED)
+ continue;
+
+ less_capability = (less_capability < peer->macsec_capbility) ?
+ less_capability : peer->macsec_capbility;
+ has_peer = TRUE;
+ }
+
+ if (has_peer) {
+ participant->advised_desired = TRUE;
+ participant->advised_capability = less_capability;
+ kay->authenticated = FALSE;
+ kay->secured = TRUE;
+ kay->failed = FALSE;
+ ieee802_1x_cp_connect_secure(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ } else {
+ participant->advised_desired = FALSE;
+ participant->advised_capability = MACSEC_CAP_NOT_IMPLEMENTED;
+ participant->to_use_sak = FALSE;
+ kay->authenticated = TRUE;
+ kay->secured = FALSE;
+ kay->failed = FALSE;
+ kay->ltx_kn = 0;
+ kay->ltx_an = 0;
+ kay->lrx_kn = 0;
+ kay->lrx_an = 0;
+ kay->otx_kn = 0;
+ kay->otx_an = 0;
+ kay->orx_kn = 0;
+ kay->orx_an = 0;
+ ieee802_1x_cp_connect_authenticated(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
+
+ return 0;
+}
+
+static const u8 pae_group_addr[ETH_ALEN] = {
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03
+};
+
+
+/**
+ * ieee802_1x_kay_encode_mkpdu -
+ */
+static int
+ieee802_1x_kay_encode_mkpdu(struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *pbuf)
+{
+ unsigned int i;
+ struct ieee8023_hdr *ether_hdr;
+ struct ieee802_1x_hdr *eapol_hdr;
+
+ ether_hdr = wpabuf_put(pbuf, sizeof(*ether_hdr));
+ os_memcpy(ether_hdr->dest, pae_group_addr, sizeof(ether_hdr->dest));
+ os_memcpy(ether_hdr->src, participant->kay->actor_sci.addr,
+ sizeof(ether_hdr->dest));
+ ether_hdr->ethertype = host_to_be16(ETH_P_EAPOL);
+
+ 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))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ieee802_1x_participant_send_mkpdu -
+ */
+static int
+ieee802_1x_participant_send_mkpdu(
+ struct ieee802_1x_mka_participant *participant)
+{
+ struct wpabuf *buf;
+ struct ieee802_1x_kay *kay = participant->kay;
+ size_t length = 0;
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "KaY: to enpacket and send the MKPDU");
+ 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);
+ }
+
+ buf = wpabuf_alloc(length);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "KaY: out of memory");
+ return -1;
+ }
+
+ if (ieee802_1x_kay_encode_mkpdu(participant, buf)) {
+ wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail!");
+ return -1;
+ }
+
+ l2_packet_send(kay->l2_mka, NULL, 0, wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+
+ kay->active = TRUE;
+ participant->active = TRUE;
+
+ return 0;
+}
+
+
+static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa);
+/**
+ * ieee802_1x_participant_timer -
+ */
+static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ieee802_1x_mka_participant *participant;
+ struct ieee802_1x_kay *kay;
+ struct ieee802_1x_kay_peer *peer, *pre_peer;
+ time_t now = time(NULL);
+ Boolean lp_changed;
+ struct receive_sc *rxsc, *pre_rxsc;
+ struct transmit_sa *txsa, *pre_txsa;
+
+ participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
+ kay = participant->kay;
+ 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;
+ }
+ }
+
+ /* 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;
+ }
+ } else {
+ participant->mka_life = 0;
+ }
+ }
+
+ lp_changed = FALSE;
+ dl_list_for_each_safe(peer, pre_peer, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (now > peer->expire) {
+ wpa_printf(MSG_DEBUG, "KaY: Live peer removed");
+ wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
+ sizeof(peer->mi));
+ wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
+ 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);
+ ieee802_1x_kay_deinit_receive_sc(
+ participant, rxsc);
+ }
+ }
+ dl_list_del(&peer->list);
+ os_free(peer);
+ lp_changed = TRUE;
+ }
+ }
+
+ if (lp_changed) {
+ if (dl_list_empty(&participant->live_peers)) {
+ participant->advised_desired = FALSE;
+ participant->advised_capability =
+ MACSEC_CAP_NOT_IMPLEMENTED;
+ participant->to_use_sak = FALSE;
+ kay->authenticated = TRUE;
+ kay->secured = FALSE;
+ kay->failed = FALSE;
+ kay->ltx_kn = 0;
+ kay->ltx_an = 0;
+ kay->lrx_kn = 0;
+ kay->lrx_an = 0;
+ kay->otx_kn = 0;
+ kay->otx_an = 0;
+ kay->orx_kn = 0;
+ kay->orx_an = 0;
+ 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_cp_connect_authenticated(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ } else {
+ ieee802_1x_kay_elect_key_server(participant);
+ ieee802_1x_kay_decide_macsec_use(participant);
+ }
+ }
+
+ dl_list_for_each_safe(peer, pre_peer, &participant->potential_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (now > peer->expire) {
+ wpa_printf(MSG_DEBUG, "KaY: Potential peer removed");
+ wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
+ sizeof(peer->mi));
+ wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
+ dl_list_del(&peer->list);
+ os_free(peer);
+ }
+ }
+
+ if (participant->new_sak) {
+ if (!ieee802_1x_kay_generate_new_sak(participant))
+ participant->to_dist_sak = TRUE;
+
+ participant->new_sak = FALSE;
+ }
+
+ if (participant->retry_count < MAX_RETRY_CNT) {
+ ieee802_1x_participant_send_mkpdu(participant);
+ participant->retry_count++;
+ }
+
+ eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
+ ieee802_1x_participant_timer,
+ participant, NULL);
+}
+
+
+/**
+ * ieee802_1x_kay_init_transmit_sa -
+ */
+static struct transmit_sa *
+ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
+ struct data_key *key)
+{
+ struct transmit_sa *psa;
+
+ key->tx_latest = TRUE;
+ key->rx_latest = TRUE;
+
+ psa = os_zalloc(sizeof(*psa));
+ if (!psa) {
+ wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
+ return NULL;
+ }
+
+ if (key->confidentiality_offset >= CONFIDENTIALITY_OFFSET_0 &&
+ key->confidentiality_offset <= CONFIDENTIALITY_OFFSET_50)
+ psa->confidentiality = TRUE;
+ else
+ psa->confidentiality = FALSE;
+
+ psa->an = an;
+ psa->pkey = key;
+ psa->next_pn = next_PN;
+ psa->sc = psc;
+
+ os_get_time(&psa->created_time);
+ psa->in_use = FALSE;
+
+ 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);
+
+ return psa;
+}
+
+
+/**
+ * ieee802_1x_kay_deinit_transmit_sa -
+ */
+static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa)
+{
+ psa->pkey = NULL;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Delete transmit SA(an: %d) of SC(channel: %d)",
+ psa->an, psa->sc->channel);
+ dl_list_del(&psa->list);
+ os_free(psa);
+}
+
+
+/**
+ * init_transmit_sc -
+ */
+static struct transmit_sc *
+ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci,
+ int channel)
+{
+ struct transmit_sc *psc;
+
+ psc = os_zalloc(sizeof(*psc));
+ if (!psc) {
+ wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
+ return NULL;
+ }
+ os_memcpy(&psc->sci, sci, sizeof(psc->sci));
+ psc->channel = channel;
+
+ os_get_time(&psc->created_time);
+ psc->transmitting = FALSE;
+ psc->encoding_sa = FALSE;
+ 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));
+
+ return psc;
+}
+
+
+/**
+ * ieee802_1x_kay_deinit_transmit_sc -
+ */
+static void
+ieee802_1x_kay_deinit_transmit_sc(
+ struct ieee802_1x_mka_participant *participant, struct transmit_sc *psc)
+{
+ 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);
+ }
+
+ os_free(psc);
+}
+
+
+/****************** Interface between CP and KAY *********************/
+/**
+ * ieee802_1x_kay_set_latest_sa_attr -
+ */
+int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *lki, u8 lan,
+ Boolean ltx, Boolean lrx)
+{
+ struct ieee802_1x_mka_participant *principal;
+
+ principal = ieee802_1x_kay_get_principal_participant(kay);
+ if (!principal)
+ return -1;
+
+ if (!lki)
+ os_memset(&principal->lki, 0, sizeof(principal->lki));
+ else
+ os_memcpy(&principal->lki, lki, sizeof(principal->lki));
+
+ principal->lan = lan;
+ principal->ltx = ltx;
+ principal->lrx = lrx;
+ if (!lki) {
+ kay->ltx_kn = 0;
+ kay->lrx_kn = 0;
+ } else {
+ kay->ltx_kn = lki->kn;
+ kay->lrx_kn = lki->kn;
+ }
+ kay->ltx_an = lan;
+ kay->lrx_an = lan;
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_set_old_sa_attr -
+ */
+int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *oki,
+ u8 oan, Boolean otx, Boolean orx)
+{
+ struct ieee802_1x_mka_participant *principal;
+
+ principal = ieee802_1x_kay_get_principal_participant(kay);
+ if (!principal)
+ return -1;
+
+ if (!oki)
+ os_memset(&principal->oki, 0, sizeof(principal->oki));
+ else
+ os_memcpy(&principal->oki, oki, sizeof(principal->oki));
+
+ principal->oan = oan;
+ principal->otx = otx;
+ principal->orx = orx;
+
+ if (!oki) {
+ kay->otx_kn = 0;
+ kay->orx_kn = 0;
+ } else {
+ kay->otx_kn = oki->kn;
+ kay->orx_kn = oki->kn;
+ }
+ kay->otx_an = oan;
+ kay->orx_an = oan;
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_create_sas -
+ */
+int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *lki)
+{
+ struct data_key *sa_key, *latest_sak;
+ struct ieee802_1x_mka_participant *principal;
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
+ struct transmit_sa *txsa;
+
+ principal = ieee802_1x_kay_get_principal_participant(kay);
+ if (!principal)
+ return -1;
+
+ latest_sak = NULL;
+ dl_list_for_each(sa_key, &principal->sak_list, struct data_key, list) {
+ if (is_ki_equal(&sa_key->key_identifier, lki)) {
+ sa_key->rx_latest = TRUE;
+ sa_key->tx_latest = TRUE;
+ latest_sak = sa_key;
+ principal->to_use_sak = TRUE;
+ } else {
+ sa_key->rx_latest = FALSE;
+ sa_key->tx_latest = FALSE;
+ }
+ }
+ if (!latest_sak) {
+ wpa_printf(MSG_ERROR, "lki related sak not found");
+ return -1;
+ }
+
+ dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
+ rxsa = ieee802_1x_kay_init_receive_sa(rxsc, latest_sak->an, 1,
+ latest_sak);
+ if (!rxsa)
+ return -1;
+
+ secy_create_receive_sa(kay, rxsa);
+ }
+
+ txsa = ieee802_1x_kay_init_transmit_sa(principal->txsc, latest_sak->an,
+ 1, latest_sak);
+ if (!txsa)
+ return -1;
+
+ secy_create_transmit_sa(kay, txsa);
+
+
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_delete_sas -
+ */
+int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *ki)
+{
+ struct data_key *sa_key, *pre_key;
+ struct transmit_sa *txsa, *pre_txsa;
+ struct receive_sa *rxsa, *pre_rxsa;
+ struct receive_sc *rxsc;
+ struct ieee802_1x_mka_participant *principal;
+
+ wpa_printf(MSG_DEBUG, "KaY: Entry into %s", __func__);
+ principal = ieee802_1x_kay_get_principal_participant(kay);
+ if (!principal)
+ return -1;
+
+ /* 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);
+ }
+ }
+
+ /* 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);
+ }
+ }
+ }
+
+ /* remove the sak */
+ 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)) {
+ ieee802_1x_kay_deinit_data_key(sa_key);
+ break;
+ }
+ if (principal->new_key == sa_key)
+ principal->new_key = NULL;
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_enable_tx_sas -
+ */
+int ieee802_1x_kay_enable_tx_sas(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *lki)
+{
+ struct ieee802_1x_mka_participant *principal;
+ struct transmit_sa *txsa;
+
+ principal = ieee802_1x_kay_get_principal_participant(kay);
+ if (!principal)
+ return -1;
+
+ dl_list_for_each(txsa, &principal->txsc->sa_list, struct transmit_sa,
+ list) {
+ if (is_ki_equal(&txsa->pkey->key_identifier, lki)) {
+ txsa->in_use = TRUE;
+ secy_enable_transmit_sa(kay, txsa);
+ ieee802_1x_cp_set_usingtransmitas(
+ principal->kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(principal->kay->cp);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_enable_rx_sas -
+ */
+int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *lki)
+{
+ struct ieee802_1x_mka_participant *principal;
+ struct receive_sa *rxsa;
+ struct receive_sc *rxsc;
+
+ principal = ieee802_1x_kay_get_principal_participant(kay);
+ if (!principal)
+ return -1;
+
+ 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, lki)) {
+ rxsa->in_use = TRUE;
+ secy_enable_receive_sa(kay, rxsa);
+ ieee802_1x_cp_set_usingreceivesas(
+ principal->kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(principal->kay->cp);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_enable_new_info -
+ */
+int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
+{
+ struct ieee802_1x_mka_participant *principal;
+
+ principal = ieee802_1x_kay_get_principal_participant(kay);
+ if (!principal)
+ return -1;
+
+ if (principal->retry_count < MAX_RETRY_CNT) {
+ ieee802_1x_participant_send_mkpdu(principal);
+ principal->retry_count++;
+ }
+
+ return 0;
+}
+
+
+/**
+ * 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
+ */
+static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
+ const u8 *buf, size_t len)
+{
+ struct ieee8023_hdr *eth_hdr;
+ struct ieee802_1x_hdr *eapol_hdr;
+ struct ieee802_1x_mka_hdr *mka_hdr;
+ struct ieee802_1x_mka_basic_body *body;
+ size_t mka_msg_len;
+ struct ieee802_1x_mka_participant *participant;
+ size_t body_len;
+ u8 icv[MAX_ICV_LEN];
+ u8 *msg_icv;
+
+ 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 */
+ if (os_memcmp(eth_hdr->dest, pae_group_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_MSGDUMP,
+ "KaY: ethernet destination address is not PAE group address");
+ return -1;
+ }
+
+ /* MKPDU should not 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");
+ return -1;
+ }
+ /* MKPDU should multiple 4 octets */
+ if ((mka_msg_len % 4) != 0) {
+ wpa_printf(MSG_MSGDUMP,
+ "KaY: MKPDU is not multiple of 4 octets");
+ return -1;
+ }
+
+ 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);
+ return -1;
+ }
+
+ /* CKN should be owned by I */
+ participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+ if (!participant) {
+ wpa_printf(MSG_DEBUG, "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");
+ return -1;
+ }
+
+ /* ICV check */
+ /*
+ * The ICV will comprise the final octets of the packet body, whatever
+ * 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,
+ buf, len - mka_alg_tbl[kay->mka_algindex].icv_len, icv)) {
+ wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
+ 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");
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_ERROR, "KaY: No ICV");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_decode_mkpdu -
+ */
+static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
+ const u8 *buf, size_t len)
+{
+ struct ieee802_1x_mka_participant *participant;
+ struct ieee802_1x_mka_hdr *hdr;
+ size_t body_len;
+ size_t left_len;
+ int body_type;
+ int i;
+ const u8 *pos;
+ Boolean my_included;
+ Boolean handled[256];
+
+ if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
+ return -1;
+
+ /* handle basic parameter set */
+ pos = buf + sizeof(struct ieee8023_hdr) + sizeof(struct ieee802_1x_hdr);
+ left_len = len - sizeof(struct ieee8023_hdr) -
+ sizeof(struct ieee802_1x_hdr);
+ participant = ieee802_1x_mka_decode_basic_body(kay, pos, left_len);
+ if (!participant)
+ return -1;
+
+ /* to skip basic parameter set */
+ hdr = (struct ieee802_1x_mka_hdr *) pos;
+ body_len = get_mka_param_body_len(hdr);
+ 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) {
+ /* 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(
+ participant,
+ participant->current_peer_id.mi,
+ 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);
+ }
+ }
+
+ /*
+ * Handle other parameter set than basic parameter set.
+ * Each parameter set should be present only once.
+ */
+ for (i = 0; i < 256; i++)
+ handled[i] = FALSE;
+
+ handled[0] = TRUE;
+ while (left_len > MKA_HDR_LEN + DEFAULT_ICV_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_ICV_INDICATOR)
+ return 0;
+
+ 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;
+ }
+
+ if (handled[body_type])
+ goto next_para_set;
+
+ handled[body_type] = TRUE;
+ if (mak_body_handler[body_type].body_rx) {
+ mak_body_handler[body_type].body_rx
+ (participant, pos, left_len);
+ } else {
+ wpa_printf(MSG_ERROR,
+ "The type %d not supported in this MKA version %d",
+ body_type, MKA_VERSION_ID);
+ }
+
+next_para_set:
+ pos += body_len + MKA_HDR_LEN;
+ left_len -= body_len + MKA_HDR_LEN;
+ }
+
+ kay->active = TRUE;
+ participant->retry_count = 0;
+ participant->active = TRUE;
+
+ return 0;
+}
+
+
+
+static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct ieee802_1x_kay *kay = ctx;
+ struct ieee8023_hdr *eth_hdr;
+ struct ieee802_1x_hdr *eapol_hdr;
+
+ /* must contain at least ieee8023_hdr + ieee802_1x_hdr */
+ if (len < sizeof(*eth_hdr) + sizeof(*eapol_hdr)) {
+ wpa_printf(MSG_MSGDUMP, "KaY: EAPOL frame too short (%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ 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)",
+ (unsigned long) len,
+ (unsigned long) ntohs(eapol_hdr->length));
+ return;
+ }
+
+ 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 ||
+ eapol_hdr->type != IEEE802_1X_TYPE_EAPOL_MKA)
+ return;
+
+ wpa_hexdump(MSG_DEBUG, "RX EAPOL-MKA: ", buf, len);
+ if (dl_list_empty(&kay->participant_list)) {
+ wpa_printf(MSG_ERROR, "KaY: no MKA participant instance");
+ return;
+ }
+
+ ieee802_1x_kay_decode_mkpdu(kay, buf, len);
+}
+
+
+/**
+ * ieee802_1x_kay_init -
+ */
+struct ieee802_1x_kay *
+ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
+ const char *ifname, const u8 *addr)
+{
+ struct ieee802_1x_kay *kay;
+
+ kay = os_zalloc(sizeof(*kay));
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+ return NULL;
+ }
+
+ kay->ctx = ctx;
+
+ kay->enable = TRUE;
+ kay->active = FALSE;
+
+ kay->authenticated = FALSE;
+ kay->secured = FALSE;
+ kay->failed = FALSE;
+ kay->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;
+
+ /* While actor acts as a key server, shall distribute sakey */
+ kay->dist_kn = 1;
+ kay->dist_an = 0;
+ kay->dist_time = 0;
+
+ kay->pn_exhaustion = PENDING_PN_EXHAUSTION;
+ kay->macsec_csindex = DEFAULT_CS_INDEX;
+ kay->mka_algindex = DEFAULT_MKA_ALG_INDEX;
+ kay->mka_version = MKA_VERSION_ID;
+
+ os_memcpy(kay->algo_agility, mka_algo_agility,
+ sizeof(kay->algo_agility));
+
+ dl_list_init(&kay->participant_list);
+
+ if (policy == DO_NOT_SECURE) {
+ kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
+ kay->macsec_desired = FALSE;
+ kay->macsec_protect = FALSE;
+ kay->macsec_validate = Disabled;
+ kay->macsec_replay_protect = FALSE;
+ kay->macsec_replay_window = 0;
+ kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
+ } else {
+ kay->macsec_capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
+ kay->macsec_desired = TRUE;
+ kay->macsec_protect = TRUE;
+ kay->macsec_validate = Strict;
+ kay->macsec_replay_protect = FALSE;
+ kay->macsec_replay_window = 0;
+ kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
+ }
+
+ 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);
+
+ 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;
+ }
+
+ if (policy == DO_NOT_SECURE) {
+ ieee802_1x_cp_connect_authenticated(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ } else {
+ kay->l2_mka = l2_packet_init(kay->if_name, NULL, ETH_P_PAE,
+ kay_l2_receive, kay, 1);
+ 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;
+ }
+ }
+
+ return kay;
+}
+
+
+/**
+ * ieee802_1x_kay_deinit -
+ */
+void
+ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay)
+{
+ struct ieee802_1x_mka_participant *participant;
+
+ if (!kay)
+ return;
+
+ wpa_printf(MSG_DEBUG, "KaY: state machine removed");
+
+ while (!dl_list_empty(&kay->participant_list)) {
+ participant = dl_list_entry(kay->participant_list.next,
+ struct ieee802_1x_mka_participant,
+ list);
+ ieee802_1x_kay_delete_mka(kay, &participant->ckn);
+ }
+
+ ieee802_1x_cp_sm_deinit(kay->cp);
+ secy_deinit_macsec(kay);
+
+ if (kay->l2_mka) {
+ l2_packet_deinit(kay->l2_mka);
+ kay->l2_mka = NULL;
+ }
+
+ os_free(kay->ctx);
+ os_free(kay);
+}
+
+
+/**
+ * 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,
+ enum mka_created_mode mode, Boolean is_authenticator)
+{
+ struct ieee802_1x_mka_participant *participant;
+ unsigned int usecs;
+
+ 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");
+ return NULL;
+ }
+ if (ckn->len > MAX_CKN_LEN) {
+ wpa_printf(MSG_ERROR, "KaY: CKN is out of range(<=32 bytes)");
+ return NULL;
+ }
+ if (!kay->enable) {
+ wpa_printf(MSG_ERROR, "KaY: Now is at disable state");
+ return NULL;
+ }
+
+ participant = os_zalloc(sizeof(*participant));
+ if (!participant) {
+ wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+ return NULL;
+ }
+
+ participant->ckn.len = ckn->len;
+ os_memcpy(participant->ckn.name, ckn->name, ckn->len);
+ participant->cak.len = cak->len;
+ os_memcpy(participant->cak.key, cak->key, cak->len);
+ if (life)
+ participant->cak_life = life + time(NULL);
+
+ switch (mode) {
+ case EAP_EXCHANGE:
+ if (is_authenticator) {
+ participant->is_obliged_key_server = TRUE;
+ participant->can_be_key_server = TRUE;
+ participant->is_key_server = TRUE;
+ participant->principal = TRUE;
+
+ os_memcpy(&kay->key_server_sci, &kay->actor_sci,
+ sizeof(kay->key_server_sci));
+ kay->key_server_priority = kay->actor_priority;
+ participant->is_elected = TRUE;
+ } else {
+ participant->is_obliged_key_server = FALSE;
+ participant->can_be_key_server = FALSE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = TRUE;
+ }
+ break;
+
+ default:
+ participant->is_obliged_key_server = FALSE;
+ participant->can_be_key_server = TRUE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = FALSE;
+ break;
+ }
+
+ participant->cached = FALSE;
+
+ participant->active = FALSE;
+ participant->participant = FALSE;
+ participant->retain = FALSE;
+ participant->activate = DEFAULT;
+
+ if (participant->is_key_server)
+ participant->principal = TRUE;
+
+ dl_list_init(&participant->live_peers);
+ dl_list_init(&participant->potential_peers);
+
+ participant->retry_count = 0;
+ participant->kay = kay;
+
+ if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ goto fail;
+ participant->mn = 0;
+
+ participant->lrx = FALSE;
+ participant->ltx = FALSE;
+ participant->orx = FALSE;
+ participant->otx = FALSE;
+ participant->to_dist_sak = FALSE;
+ participant->to_use_sak = FALSE;
+ participant->new_sak = FALSE;
+ 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);
+ 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);
+
+ /* to derive KEK from CAK and CKN */
+ participant->kek.len = mka_alg_tbl[kay->mka_algindex].kek_len;
+ if (mka_alg_tbl[kay->mka_algindex].kek_trfm(participant->cak.key,
+ participant->ckn.name,
+ participant->ckn.len,
+ participant->kek.key)) {
+ wpa_printf(MSG_ERROR, "KaY: Derived KEK 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;
+ if (mka_alg_tbl[kay->mka_algindex].ick_trfm(participant->cak.key,
+ participant->ckn.name,
+ participant->ckn.len,
+ participant->ick.key)) {
+ wpa_printf(MSG_ERROR, "KaY: Derived ICK 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);
+ eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
+ participant, NULL);
+ participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
+ usecs / 1000000;
+
+ return participant;
+
+fail:
+ os_free(participant);
+ return NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_delete_mka -
+ */
+void
+ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn)
+{
+ struct ieee802_1x_mka_participant *participant;
+ struct ieee802_1x_kay_peer *peer;
+ struct data_key *sak;
+ struct receive_sc *rxsc;
+
+ if (!kay || !ckn)
+ return;
+
+ wpa_printf(MSG_DEBUG, "KaY: participant removed");
+
+ /* get the participant */
+ participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+ if (!participant) {
+ wpa_hexdump(MSG_DEBUG, "KaY: participant is not found",
+ ckn->name, ckn->len);
+ return;
+ }
+
+ dl_list_del(&participant->list);
+
+ /* remove live peer */
+ while (!dl_list_empty(&participant->live_peers)) {
+ peer = dl_list_entry(participant->live_peers.next,
+ struct ieee802_1x_kay_peer, list);
+ dl_list_del(&peer->list);
+ os_free(peer);
+ }
+
+ /* remove potential peer */
+ while (!dl_list_empty(&participant->potential_peers)) {
+ peer = dl_list_entry(participant->potential_peers.next,
+ struct ieee802_1x_kay_peer, list);
+ dl_list_del(&peer->list);
+ os_free(peer);
+ }
+
+ /* remove sak */
+ while (!dl_list_empty(&participant->sak_list)) {
+ sak = dl_list_entry(participant->sak_list.next,
+ struct data_key, list);
+ dl_list_del(&sak->list);
+ os_free(sak->key);
+ os_free(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));
+ os_memset(&participant->kek, 0, sizeof(participant->kek));
+ os_memset(&participant->ick, 0, sizeof(participant->ick));
+ os_free(participant);
+}
+
+
+/**
+ * ieee802_1x_kay_mka_participate -
+ */
+void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
+ struct mka_key_name *ckn,
+ Boolean status)
+{
+ struct ieee802_1x_mka_participant *participant;
+
+ if (!kay || !ckn)
+ return;
+
+ participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+ if (!participant)
+ return;
+
+ participant->active = status;
+}
+
+
+/**
+ * ieee802_1x_kay_new_sak -
+ */
+int
+ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay)
+{
+ struct ieee802_1x_mka_participant *participant;
+
+ if (!kay)
+ return -1;
+
+ participant = ieee802_1x_kay_get_principal_participant(kay);
+ if (!participant)
+ return -1;
+
+ participant->new_sak = TRUE;
+ wpa_printf(MSG_DEBUG, "KaY: new SAK signal");
+
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_kay_change_cipher_suite -
+ */
+int
+ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
+{
+ struct ieee802_1x_mka_participant *participant;
+
+ if (!kay)
+ return -1;
+
+ if ((unsigned int) cs_index >= CS_TABLE_SIZE) {
+ wpa_printf(MSG_ERROR,
+ "KaY: Configured cipher suite index is out of range");
+ return -1;
+ }
+ if (kay->macsec_csindex == cs_index)
+ return -2;
+
+ if (cs_index == 0)
+ kay->macsec_desired = FALSE;
+
+ kay->macsec_csindex = cs_index;
+ kay->macsec_capable = cipher_suite_tbl[kay->macsec_csindex].capable;
+
+ participant = ieee802_1x_kay_get_principal_participant(kay);
+ if (participant) {
+ wpa_printf(MSG_INFO, "KaY: Cipher Suite changed");
+ participant->new_sak = TRUE;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay.h b/contrib/wpa/src/pae/ieee802_1x_kay.h
new file mode 100644
index 0000000..064417e
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_kay.h
@@ -0,0 +1,194 @@
+/*
+ * IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_1X_KAY_H
+#define IEEE802_1X_KAY_H
+
+#include "utils/list.h"
+#include "common/defs.h"
+#include "common/ieee802_1x_defs.h"
+
+struct macsec_init_params;
+struct ieee802_1x_cp_conf;
+
+#define MI_LEN 12
+#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_LIFE_TIME 6000
+#define MKA_SAK_RETIRE_TIME 3000
+
+struct ieee802_1x_mka_ki {
+ u8 mi[MI_LEN];
+ u32 kn;
+};
+
+struct ieee802_1x_mka_sci {
+ u8 addr[ETH_ALEN];
+ u16 port;
+};
+
+struct mka_key {
+ u8 key[MAX_KEY_LEN];
+ size_t len;
+};
+
+struct mka_key_name {
+ u8 name[MAX_CKN_LEN];
+ size_t len;
+};
+
+enum mka_created_mode {
+ PSK,
+ EAP_EXCHANGE,
+ DISTRIBUTED,
+ CACHED,
+};
+
+struct ieee802_1x_kay_ctx {
+ /* pointer to arbitrary upper level context */
+ void *ctx;
+
+ /* abstract wpa driver interface */
+ int (*macsec_init)(void *ctx, struct macsec_init_params *params);
+ int (*macsec_deinit)(void *ctx);
+ int (*enable_protect_frames)(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 (*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,
+ 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,
+ 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);
+};
+
+struct ieee802_1x_kay {
+ Boolean enable;
+ Boolean active;
+
+ Boolean authenticated;
+ Boolean secured;
+ Boolean failed;
+
+ struct ieee802_1x_mka_sci actor_sci;
+ u8 actor_priority;
+ struct ieee802_1x_mka_sci key_server_sci;
+ u8 key_server_priority;
+
+ enum macsec_cap macsec_capable;
+ Boolean macsec_desired;
+ Boolean macsec_protect;
+ Boolean macsec_replay_protect;
+ u32 macsec_replay_window;
+ enum validate_frames macsec_validate;
+ enum confidentiality_offset macsec_confidentiality;
+
+ u32 ltx_kn;
+ u8 ltx_an;
+ u32 lrx_kn;
+ u8 lrx_an;
+
+ u32 otx_kn;
+ u8 otx_an;
+ u32 orx_kn;
+ u8 orx_an;
+
+ /* not defined in IEEE802.1X */
+ struct ieee802_1x_kay_ctx *ctx;
+ Boolean is_key_server;
+ Boolean is_obliged_key_server;
+ char if_name[IFNAMSIZ];
+
+ int macsec_csindex; /* MACsec cipher suite table index */
+ int mka_algindex; /* MKA alg table index */
+
+ u32 dist_kn;
+ u8 dist_an;
+ time_t dist_time;
+
+ u8 mka_version;
+ u8 algo_agility[4];
+ u32 sc_ch;
+
+ u32 pn_exhaustion;
+ Boolean port_enable;
+ Boolean rx_enable;
+ Boolean tx_enable;
+
+ struct dl_list participant_list;
+ enum macsec_policy policy;
+
+ struct ieee802_1x_cp_sm *cp;
+
+ struct l2_packet_data *l2_mka;
+
+ enum validate_frames vf;
+ enum confidentiality_offset co;
+};
+
+
+struct ieee802_1x_kay *
+ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
+ 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,
+ u32 life, enum mka_created_mode mode,
+ Boolean is_authenticator);
+void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
+ struct mka_key_name *ckn);
+void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
+ struct mka_key_name *ckn,
+ 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);
+
+int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *lki, u8 lan,
+ Boolean ltx, Boolean lrx);
+int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *oki,
+ u8 oan, Boolean otx, Boolean orx);
+int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *lki);
+int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *ki);
+int ieee802_1x_kay_enable_tx_sas(struct ieee802_1x_kay *kay,
+ struct ieee802_1x_mka_ki *lki);
+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);
+
+#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
new file mode 100644
index 0000000..bdad3a5
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_kay_i.h
@@ -0,0 +1,419 @@
+/*
+ * IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_1X_KAY_I_H
+#define IEEE802_1X_KAY_I_H
+
+#include "utils/list.h"
+#include "common/defs.h"
+#include "common/ieee802_1x_defs.h"
+
+#define MKA_VERSION_ID 1
+
+/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 */
+enum mka_packet_type {
+ MKA_BASIC_PARAMETER_SET = MKA_VERSION_ID,
+ MKA_LIVE_PEER_LIST = 1,
+ MKA_POTENTIAL_PEER_LIST = 2,
+ MKA_SAK_USE = 3,
+ MKA_DISTRIBUTED_SAK = 4,
+ MKA_DISTRIBUTED_CAK = 5,
+ MKA_KMD = 6,
+ MKA_ANNOUNCEMENT = 7,
+ MKA_ICV_INDICATOR = 255
+};
+
+#define ICV_LEN 16 /* 16 bytes */
+#define SAK_WRAPPED_LEN 24
+/* KN + Wrapper SAK */
+#define DEFAULT_DIS_SAK_BODY_LENGTH (SAK_WRAPPED_LEN + 4)
+#define MAX_RETRY_CNT 5
+
+struct ieee802_1x_kay;
+
+struct ieee802_1x_mka_peer_id {
+ u8 mi[MI_LEN];
+ u32 mn;
+};
+
+struct ieee802_1x_kay_peer {
+ struct ieee802_1x_mka_sci sci;
+ u8 mi[MI_LEN];
+ u32 mn;
+ time_t expire;
+ Boolean is_key_server;
+ u8 key_server_priority;
+ Boolean macsec_desired;
+ enum macsec_cap macsec_capbility;
+ 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 */
+
+ struct dl_list list;
+};
+
+struct macsec_ciphersuite {
+ u8 id[CS_ID_LEN];
+ 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 */
+};
+
+#define DEFAULT_MKA_ALG_INDEX 0
+
+/* See IEEE Std 802.1X-2010, 9.16 MKA management */
+struct ieee802_1x_mka_participant {
+ /* used for active and potential participant */
+ struct mka_key_name ckn;
+ struct mka_key cak;
+ Boolean cached;
+
+ /* used by management to monitor and control activation */
+ Boolean active;
+ Boolean participant;
+ Boolean retain;
+
+ enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
+
+ /* used for active participant */
+ Boolean principal;
+ struct dl_list live_peers;
+ struct dl_list potential_peers;
+
+ /* not defined in IEEE 802.1X */
+ struct dl_list list;
+
+ struct mka_key kek;
+ struct mka_key ick;
+
+ struct ieee802_1x_mka_ki lki;
+ u8 lan;
+ Boolean ltx;
+ Boolean lrx;
+
+ struct ieee802_1x_mka_ki oki;
+ u8 oan;
+ Boolean otx;
+ Boolean orx;
+
+ Boolean is_key_server;
+ Boolean is_obliged_key_server;
+ Boolean can_be_key_server;
+ Boolean is_elected;
+
+ struct dl_list sak_list;
+ struct dl_list rxsc_list;
+
+ struct transmit_sc *txsc;
+
+ u8 mi[MI_LEN];
+ u32 mn;
+
+ 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;
+ Boolean to_use_sak;
+ Boolean new_sak;
+
+ Boolean advised_desired;
+ enum macsec_cap advised_capability;
+
+ struct data_key *new_key;
+ u32 retry_count;
+
+ struct ieee802_1x_kay *kay;
+};
+
+struct ieee802_1x_mka_hdr {
+ /* octet 1 */
+ u32 type:8;
+ /* octet 2 */
+ u32 reserve:8;
+ /* octet 3 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u32 length:4;
+ u32 reserve1:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 reserve1:4;
+ u32 length:4;
+#else
+#error "Please fix <bits/endian.h>"
+#endif
+ /* octet 4 */
+ u32 length1:8;
+};
+
+#define MKA_HDR_LEN sizeof(struct ieee802_1x_mka_hdr)
+
+struct ieee802_1x_mka_basic_body {
+ /* octet 1 */
+ u32 version:8;
+ /* octet 2 */
+ u32 priority:8;
+ /* octet 3 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u32 length:4;
+ u32 macsec_capbility:2;
+ u32 macsec_desired:1;
+ u32 key_server:1;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 key_server:1;
+ u32 macsec_desired:1;
+ u32 macsec_capbility:2;
+ u32 length:4;
+#endif
+ /* octet 4 */
+ u32 length1:8;
+
+ struct ieee802_1x_mka_sci actor_sci;
+ u8 actor_mi[MI_LEN];
+ u32 actor_mn;
+ u8 algo_agility[4];
+
+ /* followed by CAK Name*/
+ u8 ckn[0];
+};
+
+struct ieee802_1x_mka_peer_body {
+ /* octet 1 */
+ u32 type:8;
+ /* octet 2 */
+ u32 reserve:8;
+ /* octet 3 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u32 length:4;
+ u32 reserve1:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 reserve1:4;
+ u32 length:4;
+#endif
+ /* octet 4 */
+ u32 length1:8;
+
+ u8 peer[0];
+ /* followed by Peers */
+};
+
+struct ieee802_1x_mka_sak_use_body {
+ /* octet 1 */
+ u32 type:8;
+ /* 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;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 lan:2;
+ u32 ltx:1;
+ u32 lrx:1;
+ u32 oan:2;
+ u32 otx:1;
+ u32 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;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 ptx:1;
+ u32 prx:1;
+ u32 reserve:1;
+ u32 delay_protect:1;
+ u32 length:4;
+#endif
+
+ /* octet 4 */
+ u32 length1:8;
+
+ /* octet 5 - 16 */
+ u8 lsrv_mi[MI_LEN];
+ /* octet 17 - 20 */
+ u32 lkn;
+ /* octet 21 - 24 */
+ u32 llpn;
+
+ /* octet 25 - 36 */
+ u8 osrv_mi[MI_LEN];
+ /* octet 37 - 40 */
+ u32 okn;
+ /* octet 41 - 44 */
+ u32 olpn;
+};
+
+
+struct ieee802_1x_mka_dist_sak_body {
+ /* octet 1 */
+ u32 type:8;
+ /* octet 2 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u32 reserve:4;
+ u32 confid_offset:2;
+ u32 dan:2;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 dan:2;
+ u32 confid_offset:2;
+ u32 reserve:4;
+#endif
+ /* octet 3 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u32 length:4;
+ u32 reserve1:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 reserve1:4;
+ u32 length:4;
+#endif
+ /* octet 4 */
+ u32 length1:8;
+ /* octet 5 - 8 */
+ u32 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 ieee802_1x_mka_icv_body {
+ /* octet 1 */
+ u32 type:8;
+ /* octet 2 */
+ u32 reserve:8;
+ /* octet 3 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u32 length:4;
+ u32 reserve1:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u32 reserve1:4;
+ u32 length:4;
+#endif
+ /* octet 4 */
+ u32 length1:8;
+
+ /* octet 5 - */
+ u8 icv[0];
+};
+
+#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
new file mode 100644
index 0000000..9a8d923
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_key.c
@@ -0,0 +1,189 @@
+/*
+ * IEEE 802.1X-2010 Key Hierarchy
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * SAK derivation specified in IEEE Std 802.1X-2010, Clause 6.2
+*/
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "crypto/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "ieee802_1x_key.h"
+
+
+static void joint_two_mac(const u8 *mac1, const u8 *mac2, u8 *out)
+{
+ if (os_memcmp(mac1, mac2, ETH_ALEN) < 0) {
+ os_memcpy(out, mac1, ETH_ALEN);
+ os_memcpy(out + ETH_ALEN, mac2, ETH_ALEN);
+ } else {
+ os_memcpy(out, mac2, ETH_ALEN);
+ os_memcpy(out + ETH_ALEN, mac1, ETH_ALEN);
+ }
+}
+
+
+/* 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)
+{
+ const int h = 128;
+ const int r = 8;
+ int i, n;
+ int lab_len, ctx_len, ret_len, buf_len;
+ u8 *buf;
+
+ lab_len = os_strlen(label);
+ ctx_len = (ctx_bits + 7) / 8;
+ ret_len = ((ret_bits & 0xffff) + 7) / 8;
+ buf_len = lab_len + ctx_len + 4;
+
+ os_memset(ret, 0, ret_len);
+
+ n = (ret_bits + h - 1) / h;
+ if (n > ((0x1 << r) - 1))
+ return -1;
+
+ buf = os_zalloc(buf_len);
+ if (buf == NULL)
+ return -1;
+
+ os_memcpy(buf + 1, label, lab_len);
+ os_memcpy(buf + lab_len + 2, context, ctx_len);
+ WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
+
+ for (i = 0; i < n; i++) {
+ buf[0] = (u8) (i + 1);
+ if (omac1_aes_128(kdk, buf, buf_len, ret)) {
+ os_free(buf);
+ return -1;
+ }
+ ret = ret + h / 8;
+ }
+ os_free(buf);
+ return 0;
+}
+
+
+/********** AES-CMAC-128 **********/
+/**
+ * ieee802_1x_cak_128bits_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)
+{
+ 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);
+}
+
+
+/**
+ * ieee802_1x_ckn_128bits_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 res;
+ u8 *context;
+ size_t ctx_len = sid_bytes + ETH_ALEN * 2;
+
+ context = os_zalloc(ctx_len);
+ if (!context) {
+ wpa_printf(MSG_ERROR, "MKA-%s: out of memory", __func__);
+ return -1;
+ }
+ 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);
+ os_free(context);
+ return res;
+}
+
+
+/**
+ * ieee802_1x_kek_128bits_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)
+{
+ u8 context[16];
+
+ /* First 16 octets of CKN, with null octets appended to pad if needed */
+ 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);
+}
+
+
+/**
+ * ieee802_1x_ick_128bits_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)
+{
+ u8 context[16];
+
+ /* First 16 octets of CKN, with null octets appended to pad if needed */
+ 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);
+}
+
+
+/**
+ * ieee802_1x_icv_128bits_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)
+{
+ if (omac1_aes_128(ick, msg, msg_bytes, icv)) {
+ wpa_printf(MSG_ERROR, "MKA: omac1_aes_128 failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * ieee802_1x_sak_128bits_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)
+{
+ return aes_kdf_128(cak, "IEEE8021 SAK", ctx, ctx_bytes * 8, 128, sak);
+}
diff --git a/contrib/wpa/src/pae/ieee802_1x_key.h b/contrib/wpa/src/pae/ieee802_1x_key.h
new file mode 100644
index 0000000..ea318ea
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_key.h
@@ -0,0 +1,26 @@
+/*
+ * IEEE 802.1X-2010 Key Hierarchy
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#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);
+
+#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
new file mode 100644
index 0000000..fbe05dc
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_secy_ops.c
@@ -0,0 +1,492 @@
+ /*
+ * SecY Operations
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/defs.h"
+#include "drivers/driver.h"
+#include "pae/ieee802_1x_kay.h"
+#include "pae/ieee802_1x_kay_i.h"
+#include "pae/ieee802_1x_secy_ops.h"
+
+
+int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
+ enum validate_frames vf)
+{
+ kay->vf = vf;
+ return 0;
+}
+
+
+int secy_cp_control_protect_frames(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_protect_frames) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy enable_protect_frames operation not supported");
+ return -1;
+ }
+
+ return ops->enable_protect_frames(ops->ctx, enabled);
+}
+
+
+int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
+{
+ 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->set_replay_protect) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy set_replay_protect operation not supported");
+ return -1;
+ }
+
+ return ops->set_replay_protect(ops->ctx, enabled, win);
+}
+
+
+int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
+ const u8 *cs, size_t cs_len)
+{
+ 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->set_current_cipher_suite) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy set_current_cipher_suite operation not supported");
+ return -1;
+ }
+
+ return ops->set_current_cipher_suite(ops->ctx, cs, cs_len);
+}
+
+
+int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
+ enum confidentiality_offset co)
+{
+ kay->co = co;
+ return 0;
+}
+
+
+int secy_cp_control_enable_port(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_controlled_port) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy enable_controlled_port operation not supported");
+ return -1;
+ }
+
+ return ops->enable_controlled_port(ops->ctx, enabled);
+}
+
+
+int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
+ struct receive_sa *rxsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->get_receive_lowest_pn) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy get_receive_lowest_pn operation not supported");
+ return -1;
+ }
+
+ return ops->get_receive_lowest_pn(ops->ctx,
+ rxsa->sc->channel,
+ rxsa->an,
+ &rxsa->lowest_pn);
+}
+
+
+int secy_get_transmit_next_pn(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->get_transmit_next_pn) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy get_receive_lowest_pn operation not supported");
+ return -1;
+ }
+
+ return ops->get_transmit_next_pn(ops->ctx,
+ txsa->sc->channel,
+ txsa->an,
+ &txsa->next_pn);
+}
+
+
+int secy_set_transmit_next_pn(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->set_transmit_next_pn) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy get_receive_lowest_pn operation not supported");
+ return -1;
+ }
+
+ return ops->set_transmit_next_pn(ops->ctx,
+ txsa->sc->channel,
+ txsa->an,
+ txsa->next_pn);
+}
+
+
+int secy_get_available_receive_sc(struct ieee802_1x_kay *kay, u32 *channel)
+{
+ 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->get_available_receive_sc) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy get_available_receive_sc operation not supported");
+ return -1;
+ }
+
+ return ops->get_available_receive_sc(ops->ctx, channel);
+}
+
+
+int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsc) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->create_receive_sc) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy create_receive_sc operation not supported");
+ return -1;
+ }
+
+ return ops->create_receive_sc(ops->ctx, rxsc->channel, &rxsc->sci,
+ kay->vf, kay->co);
+}
+
+
+int secy_delete_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsc) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->delete_receive_sc) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy delete_receive_sc operation not supported");
+ return -1;
+ }
+
+ return ops->delete_receive_sc(ops->ctx, rxsc->channel);
+}
+
+
+int secy_create_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->create_receive_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy create_receive_sa operation not supported");
+ return -1;
+ }
+
+ return ops->create_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an,
+ rxsa->lowest_pn, rxsa->pkey->key);
+}
+
+
+int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->enable_receive_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy enable_receive_sa operation not supported");
+ return -1;
+ }
+
+ rxsa->enable_receive = TRUE;
+
+ return ops->enable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
+}
+
+
+int secy_disable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->disable_receive_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy disable_receive_sa operation not supported");
+ return -1;
+ }
+
+ rxsa->enable_receive = FALSE;
+
+ return ops->disable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
+}
+
+
+int secy_get_available_transmit_sc(struct ieee802_1x_kay *kay, u32 *channel)
+{
+ 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->get_available_transmit_sc) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy get_available_transmit_sc operation not supported");
+ return -1;
+ }
+
+ return ops->get_available_transmit_sc(ops->ctx, channel);
+}
+
+
+int secy_create_transmit_sc(struct ieee802_1x_kay *kay,
+ struct transmit_sc *txsc)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !txsc) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->create_transmit_sc) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy create_transmit_sc operation not supported");
+ return -1;
+ }
+
+ return ops->create_transmit_sc(ops->ctx, txsc->channel, &txsc->sci,
+ kay->co);
+}
+
+
+int secy_delete_transmit_sc(struct ieee802_1x_kay *kay,
+ struct transmit_sc *txsc)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !txsc) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->delete_transmit_sc) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy delete_transmit_sc operation not supported");
+ return -1;
+ }
+
+ return ops->delete_transmit_sc(ops->ctx, txsc->channel);
+}
+
+
+int secy_create_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->create_transmit_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy create_transmit_sa operation not supported");
+ return -1;
+ }
+
+ return ops->create_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an,
+ txsa->next_pn, txsa->confidentiality,
+ txsa->pkey->key);
+}
+
+
+int secy_enable_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->enable_transmit_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy enable_transmit_sa operation not supported");
+ return -1;
+ }
+
+ txsa->enable_transmit = TRUE;
+
+ return ops->enable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
+}
+
+
+int secy_disable_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->disable_transmit_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy disable_transmit_sa operation not supported");
+ return -1;
+ }
+
+ txsa->enable_transmit = FALSE;
+
+ return ops->disable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
+}
+
+
+int secy_init_macsec(struct ieee802_1x_kay *kay)
+{
+ int ret;
+ struct ieee802_1x_kay_ctx *ops;
+ struct macsec_init_params params;
+
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->macsec_init) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy macsec_init operation not supported");
+ return -1;
+ }
+
+ params.use_es = FALSE;
+ params.use_scb = FALSE;
+ params.always_include_sci = TRUE;
+
+ ret = ops->macsec_init(ops->ctx, &params);
+
+ return ret;
+}
+
+
+int secy_deinit_macsec(struct ieee802_1x_kay *kay)
+{
+ 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_deinit) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy macsec_deinit operation not supported");
+ return -1;
+ }
+
+ return ops->macsec_deinit(ops->ctx);
+}
diff --git a/contrib/wpa/src/pae/ieee802_1x_secy_ops.h b/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
new file mode 100644
index 0000000..295b823
--- /dev/null
+++ b/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
@@ -0,0 +1,62 @@
+ /*
+ * SecY Operations
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_1X_SECY_OPS_H
+#define IEEE802_1X_SECY_OPS_H
+
+#include "common/defs.h"
+#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);
+
+/****** CP -> SecY ******/
+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_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_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_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_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_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_enable_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *txsa);
+int secy_disable_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *txsa);
+
+#endif /* IEEE802_1X_SECY_OPS_H */
diff --git a/contrib/wpa/src/radius/radius.c b/contrib/wpa/src/radius/radius.c
index d1feec9..8d878a4 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -231,9 +231,32 @@ static struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
- { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
+ { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_LOCATION_INFO, "Location-Information",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES,
+ "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES,
+ "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_REQUESTED_LOCATION_INFO, "Requested-Location-Info",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher",
+ RADIUS_ATTR_HEXDUMP },
};
-#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
+#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
static struct radius_attr_type *radius_get_attr_type(u8 type)
@@ -249,25 +272,17 @@ static struct radius_attr_type *radius_get_attr_type(u8 type)
}
-static void print_char(char c)
-{
- if (c >= 32 && c < 127)
- printf("%c", c);
- else
- printf("<%02x>", c);
-}
-
-
static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
{
struct radius_attr_type *attr;
- int i, len;
+ int len;
unsigned char *pos;
+ char buf[1000];
attr = radius_get_attr_type(hdr->type);
- printf(" Attribute %d (%s) length=%d\n",
- hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
+ wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
+ hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
return;
@@ -277,47 +292,50 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
switch (attr->data_type) {
case RADIUS_ATTR_TEXT:
- printf(" Value: '");
- for (i = 0; i < len; i++)
- print_char(pos[i]);
- printf("'\n");
+ printf_encode(buf, sizeof(buf), pos, len);
+ wpa_printf(MSG_INFO, " Value: '%s'", buf);
break;
case RADIUS_ATTR_IP:
if (len == 4) {
struct in_addr addr;
os_memcpy(&addr, pos, 4);
- printf(" Value: %s\n", inet_ntoa(addr));
- } else
- printf(" Invalid IP address length %d\n", len);
+ wpa_printf(MSG_INFO, " Value: %s",
+ inet_ntoa(addr));
+ } else {
+ wpa_printf(MSG_INFO, " Invalid IP address length %d",
+ len);
+ }
break;
#ifdef CONFIG_IPV6
case RADIUS_ATTR_IPV6:
if (len == 16) {
- char buf[128];
const char *atxt;
struct in6_addr *addr = (struct in6_addr *) pos;
atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
- printf(" Value: %s\n", atxt ? atxt : "?");
- } else
- printf(" Invalid IPv6 address length %d\n", len);
+ wpa_printf(MSG_INFO, " Value: %s",
+ atxt ? atxt : "?");
+ } else {
+ wpa_printf(MSG_INFO, " Invalid IPv6 address length %d",
+ len);
+ }
break;
#endif /* CONFIG_IPV6 */
case RADIUS_ATTR_HEXDUMP:
case RADIUS_ATTR_UNDIST:
- printf(" Value:");
- for (i = 0; i < len; i++)
- printf(" %02x", pos[i]);
- printf("\n");
+ wpa_snprintf_hex(buf, sizeof(buf), pos, len);
+ wpa_printf(MSG_INFO, " Value: %s", buf);
break;
case RADIUS_ATTR_INT32:
if (len == 4)
- printf(" Value: %u\n", WPA_GET_BE32(pos));
+ wpa_printf(MSG_INFO, " Value: %u",
+ WPA_GET_BE32(pos));
else
- printf(" Invalid INT32 length %d\n", len);
+ wpa_printf(MSG_INFO, " Invalid INT32 length %d",
+ len);
break;
default:
@@ -330,9 +348,9 @@ void radius_msg_dump(struct radius_msg *msg)
{
size_t i;
- printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
- msg->hdr->code, radius_code_string(msg->hdr->code),
- msg->hdr->identifier, be_to_host16(msg->hdr->length));
+ wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
+ msg->hdr->code, radius_code_string(msg->hdr->code),
+ msg->hdr->identifier, be_to_host16(msg->hdr->length));
for (i = 0; i < msg->attr_used; i++) {
struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
@@ -384,7 +402,7 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
auth, MD5_MAC_LEN);
if (attr == NULL) {
- printf("WARNING: Could not add Message-Authenticator\n");
+ wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
return -1;
}
msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
@@ -473,6 +491,27 @@ void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
}
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_authenticator)
+{
+ const u8 *addr[2];
+ size_t len[2];
+
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+ os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
+ addr[0] = wpabuf_head(msg->buf);
+ len[0] = wpabuf_len(msg->buf);
+ addr[1] = secret;
+ len[1] = secret_len;
+ md5_vector(2, addr, len, msg->hdr->authenticator);
+
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
+ }
+}
+
+
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len)
{
@@ -491,7 +530,7 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
- return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
+ return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
}
@@ -518,7 +557,7 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
- if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
+ if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
return 1;
for (i = 0; i < msg->attr_used; i++) {
@@ -551,7 +590,7 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
os_memcpy(msg->hdr->authenticator, orig_authenticator,
sizeof(orig_authenticator));
- return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
+ return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0;
}
@@ -585,7 +624,7 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
struct radius_attr_hdr *attr;
if (data_len > RADIUS_MAX_ATTR_LEN) {
- printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
+ wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
(unsigned long) data_len);
return NULL;
}
@@ -756,8 +795,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
tmp = radius_get_attr_hdr(msg, i);
if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
if (attr != NULL) {
- printf("Multiple Message-Authenticator "
- "attributes in RADIUS message\n");
+ wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
return 1;
}
attr = tmp;
@@ -765,7 +803,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
}
if (attr == NULL) {
- printf("No Message-Authenticator attribute found\n");
+ wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
return 1;
}
@@ -785,8 +823,8 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
sizeof(orig_authenticator));
}
- if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
- printf("Invalid Message-Authenticator!\n");
+ if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
return 1;
}
@@ -802,7 +840,7 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
u8 hash[MD5_MAC_LEN];
if (sent_msg == NULL) {
- printf("No matching Access-Request message found\n");
+ wpa_printf(MSG_INFO, "No matching Access-Request message found");
return 1;
}
@@ -822,8 +860,8 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
- if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
- printf("Response Authenticator invalid!\n");
+ if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "Response Authenticator invalid!");
return 1;
}
@@ -918,7 +956,6 @@ static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
vhdr = (struct radius_attr_vendor *) pos;
if (vhdr->vendor_length > left ||
vhdr->vendor_length < sizeof(*vhdr)) {
- left = 0;
break;
}
if (vhdr->vendor_type != subtype) {
@@ -956,13 +993,17 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
/* key: 16-bit salt followed by encrypted key info */
- if (len < 2 + 16)
+ if (len < 2 + 16) {
+ wpa_printf(MSG_DEBUG, "RADIUS: %s: Len is too small: %d",
+ __func__, (int) len);
return NULL;
+ }
pos = key + 2;
left = len - 2;
if (left % 16) {
- printf("Invalid ms key len %lu\n", (unsigned long) left);
+ wpa_printf(MSG_INFO, "RADIUS: Invalid ms key len %lu",
+ (unsigned long) left);
return NULL;
}
@@ -996,7 +1037,7 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
}
if (plain[0] == 0 || plain[0] > plen - 1) {
- printf("Failed to decrypt MPPE key\n");
+ wpa_printf(MSG_INFO, "RADIUS: Failed to decrypt MPPE key");
os_free(plain);
return NULL;
}
@@ -1085,6 +1126,10 @@ radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->send_len);
+ if (!keys->send) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to decrypt send key");
+ }
os_free(key);
}
@@ -1096,6 +1141,10 @@ radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->recv_len);
+ if (!keys->recv) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to decrypt recv key");
+ }
os_free(key);
}
@@ -1204,30 +1253,55 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
}
-/* Add User-Password attribute to a RADIUS message and encrypt it as specified
- * in RFC 2865, Chap. 5.2 */
-struct radius_attr_hdr *
-radius_msg_add_attr_user_password(struct radius_msg *msg,
- const u8 *data, size_t data_len,
- const u8 *secret, size_t secret_len)
+int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
+ size_t len)
{
- u8 buf[128];
- size_t padlen, i, buf_len, pos;
+ struct radius_attr_hdr *attr;
+ u8 *buf, *pos;
+ size_t alen;
+
+ alen = 4 + 2 + len;
+ buf = os_malloc(alen);
+ if (buf == NULL)
+ return 0;
+ pos = buf;
+ WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA);
+ pos += 4;
+ *pos++ = subtype;
+ *pos++ = 2 + len;
+ os_memcpy(pos, data, len);
+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+ buf, alen);
+ os_free(buf);
+ if (attr == NULL)
+ return 0;
+
+ return 1;
+}
+
+
+int radius_user_password_hide(struct radius_msg *msg,
+ const u8 *data, size_t data_len,
+ const u8 *secret, size_t secret_len,
+ u8 *buf, size_t buf_len)
+{
+ size_t padlen, i, pos;
const u8 *addr[2];
size_t len[2];
u8 hash[16];
- if (data_len > 128)
- return NULL;
+ if (data_len + 16 > buf_len)
+ return -1;
os_memcpy(buf, data, data_len);
- buf_len = data_len;
padlen = data_len % 16;
- if (padlen && data_len < sizeof(buf)) {
+ if (padlen && data_len < buf_len) {
padlen = 16 - padlen;
os_memset(buf + data_len, 0, padlen);
- buf_len += padlen;
+ buf_len = data_len + padlen;
+ } else {
+ buf_len = data_len;
}
addr[0] = secret;
@@ -1253,8 +1327,27 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
pos += 16;
}
+ return buf_len;
+}
+
+
+/* Add User-Password attribute to a RADIUS message and encrypt it as specified
+ * in RFC 2865, Chap. 5.2 */
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+ const u8 *data, size_t data_len,
+ const u8 *secret, size_t secret_len)
+{
+ u8 buf[128];
+ int res;
+
+ res = radius_user_password_hide(msg, data, data_len,
+ secret, secret_len, buf, sizeof(buf));
+ if (res < 0)
+ return NULL;
+
return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
- buf, buf_len);
+ buf, res);
}
diff --git a/contrib/wpa/src/radius/radius.h b/contrib/wpa/src/radius/radius.h
index 2031054..5977339 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, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -90,7 +90,21 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
- RADIUS_ATTR_ERROR_CAUSE = 101
+ RADIUS_ATTR_ERROR_CAUSE = 101,
+ RADIUS_ATTR_EAP_KEY_NAME = 102,
+ RADIUS_ATTR_OPERATOR_NAME = 126,
+ RADIUS_ATTR_LOCATION_INFO = 127,
+ RADIUS_ATTR_LOCATION_DATA = 128,
+ RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES = 129,
+ RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES = 130,
+ RADIUS_ATTR_LOCATION_CAPABLE = 131,
+ RADIUS_ATTR_REQUESTED_LOCATION_INFO = 132,
+ RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
+ RADIUS_ATTR_WLAN_HESSID = 181,
+ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186,
+ RADIUS_ATTR_WLAN_GROUP_CIPHER = 187,
+ RADIUS_ATTR_WLAN_AKM_SUITE = 188,
+ RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189,
};
@@ -163,6 +177,18 @@ enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
};
+
+/* Hotspot 2.0 - WFA Vendor-specific RADIUS Attributes */
+#define RADIUS_VENDOR_ID_WFA 40808
+
+enum {
+ RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION = 1,
+ RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION = 2,
+ 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,
+};
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@@ -204,6 +230,9 @@ int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
const struct radius_hdr *req_hdr);
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len,
+ const u8 *req_authenticator);
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,
@@ -234,6 +263,12 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
const u8 *secret, size_t secret_len,
const u8 *send_key, size_t send_key_len,
const u8 *recv_key, size_t recv_key_len);
+int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
+ size_t len);
+int radius_user_password_hide(struct radius_msg *msg,
+ const u8 *data, size_t data_len,
+ const u8 *secret, size_t secret_len,
+ u8 *buf, size_t buf_len);
struct radius_attr_hdr *
radius_msg_add_attr_user_password(struct radius_msg *msg,
const u8 *data, size_t data_len,
diff --git a/contrib/wpa/src/radius/radius_client.c b/contrib/wpa/src/radius/radius_client.c
index 425ad93..693f61e 100644
--- a/contrib/wpa/src/radius/radius_client.c
+++ b/contrib/wpa/src/radius/radius_client.c
@@ -1,6 +1,6 @@
/*
* RADIUS client
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -122,7 +122,7 @@ struct radius_msg_list {
/**
* last_attempt - Time of the last transmission attempt
*/
- struct os_time last_attempt;
+ struct os_reltime last_attempt;
/**
* shared_secret - Shared secret with the target RADIUS server
@@ -236,6 +236,8 @@ radius_change_server(struct radius_client_data *radius,
int sock, int sock6, int auth);
static int radius_client_init_acct(struct radius_client_data *radius);
static int radius_client_init_auth(struct radius_client_data *radius);
+static void radius_client_auth_failover(struct radius_client_data *radius);
+static void radius_client_acct_failover(struct radius_client_data *radius);
static void radius_client_msg_free(struct radius_msg_list *req)
@@ -295,26 +297,34 @@ int radius_client_register(struct radius_client_data *radius,
}
-static void radius_client_handle_send_error(struct radius_client_data *radius,
- int s, RadiusType msg_type)
+/*
+ * Returns >0 if message queue was flushed (i.e., the message that triggered
+ * the error is not available anymore)
+ */
+static int radius_client_handle_send_error(struct radius_client_data *radius,
+ int s, RadiusType msg_type)
{
#ifndef CONFIG_NATIVE_WINDOWS
int _errno = errno;
- perror("send[RADIUS]");
+ wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
- _errno == EBADF) {
+ _errno == EBADF || _errno == ENETUNREACH) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Send failed - maybe interface status changed -"
" try to connect again");
- eloop_unregister_read_sock(s);
- close(s);
- if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
+ if (msg_type == RADIUS_ACCT ||
+ msg_type == RADIUS_ACCT_INTERIM) {
radius_client_init_acct(radius);
- else
+ return 0;
+ } else {
radius_client_init_auth(radius);
+ return 1;
+ }
}
#endif /* CONFIG_NATIVE_WINDOWS */
+
+ return 0;
}
@@ -325,9 +335,18 @@ static int radius_client_retransmit(struct radius_client_data *radius,
struct hostapd_radius_servers *conf = radius->conf;
int s;
struct wpabuf *buf;
+ size_t prev_num_msgs;
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM) {
+ if (radius->acct_sock < 0)
+ radius_client_init_acct(radius);
+ if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
+ prev_num_msgs = radius->num_msgs;
+ radius_client_acct_failover(radius);
+ if (prev_num_msgs != radius->num_msgs)
+ return 0;
+ }
s = radius->acct_sock;
if (entry->attempts == 0)
conf->acct_server->requests++;
@@ -336,6 +355,14 @@ static int radius_client_retransmit(struct radius_client_data *radius,
conf->acct_server->retransmissions++;
}
} else {
+ if (radius->auth_sock < 0)
+ radius_client_init_auth(radius);
+ if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
+ prev_num_msgs = radius->num_msgs;
+ radius_client_auth_failover(radius);
+ if (prev_num_msgs != radius->num_msgs)
+ return 0;
+ }
s = radius->auth_sock;
if (entry->attempts == 0)
conf->auth_server->requests++;
@@ -344,6 +371,11 @@ static int radius_client_retransmit(struct radius_client_data *radius,
conf->auth_server->retransmissions++;
}
}
+ if (s < 0) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: No valid socket for retransmission");
+ return 1;
+ }
/* retransmit; remove entry if too many attempts */
entry->attempts++;
@@ -351,18 +383,20 @@ static int radius_client_retransmit(struct radius_client_data *radius,
HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
radius_msg_get_hdr(entry->msg)->identifier);
- os_get_time(&entry->last_attempt);
+ os_get_reltime(&entry->last_attempt);
buf = radius_msg_get_buf(entry->msg);
- if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
- radius_client_handle_send_error(radius, s, entry->msg_type);
+ if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ if (radius_client_handle_send_error(radius, s, entry->msg_type)
+ > 0)
+ return 0;
+ }
entry->next_try = now + entry->next_wait;
entry->next_wait *= 2;
if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
- printf("Removing un-ACKed RADIUS message due to too many "
- "failed retransmit attempts\n");
+ wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
return 1;
}
@@ -374,21 +408,23 @@ 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_time now;
+ struct os_reltime now;
os_time_t first;
struct radius_msg_list *entry, *prev, *tmp;
int auth_failover = 0, acct_failover = 0;
- char abuf[50];
+ size_t prev_num_msgs;
+ int s;
entry = radius->msgs;
if (!entry)
return;
- os_get_time(&now);
+ os_get_reltime(&now);
first = 0;
prev = NULL;
while (entry) {
+ prev_num_msgs = radius->num_msgs;
if (now.sec >= entry->next_try &&
radius_client_retransmit(radius, entry, now.sec)) {
if (prev)
@@ -403,7 +439,18 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
continue;
}
- if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
+ if (prev_num_msgs != radius->num_msgs) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Message removed from queue - restart from beginning");
+ entry = radius->msgs;
+ prev = NULL;
+ 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++;
@@ -429,60 +476,76 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
(long int) (first - now.sec));
}
- if (auth_failover && conf->num_auth_servers > 1) {
- struct hostapd_radius_server *next, *old;
- old = conf->auth_server;
- hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_NOTICE,
- "No response from Authentication server "
- "%s:%d - failover",
- hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
- old->port);
-
- for (entry = radius->msgs; entry; entry = entry->next) {
- if (entry->msg_type == RADIUS_AUTH)
- old->timeouts++;
- }
+ 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);
+}
- next = old + 1;
- if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
- next = conf->auth_servers;
- conf->auth_server = next;
- radius_change_server(radius, next, old,
- radius->auth_serv_sock,
- radius->auth_serv_sock6, 1);
+
+static void radius_client_auth_failover(struct radius_client_data *radius)
+{
+ struct hostapd_radius_servers *conf = radius->conf;
+ struct hostapd_radius_server *next, *old;
+ struct radius_msg_list *entry;
+ char abuf[50];
+
+ old = conf->auth_server;
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_NOTICE,
+ "No response from Authentication server %s:%d - failover",
+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+ old->port);
+
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (entry->msg_type == RADIUS_AUTH)
+ old->timeouts++;
}
- if (acct_failover && conf->num_acct_servers > 1) {
- struct hostapd_radius_server *next, *old;
- old = conf->acct_server;
- hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_NOTICE,
- "No response from Accounting server "
- "%s:%d - failover",
- hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
- old->port);
+ next = old + 1;
+ if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
+ next = conf->auth_servers;
+ conf->auth_server = next;
+ radius_change_server(radius, next, old,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1);
+}
- for (entry = radius->msgs; entry; entry = entry->next) {
- if (entry->msg_type == RADIUS_ACCT ||
- entry->msg_type == RADIUS_ACCT_INTERIM)
- old->timeouts++;
- }
- next = old + 1;
- if (next > &conf->acct_servers[conf->num_acct_servers - 1])
- next = conf->acct_servers;
- conf->acct_server = next;
- radius_change_server(radius, next, old,
- radius->acct_serv_sock,
- radius->acct_serv_sock6, 0);
+static void radius_client_acct_failover(struct radius_client_data *radius)
+{
+ struct hostapd_radius_servers *conf = radius->conf;
+ struct hostapd_radius_server *next, *old;
+ struct radius_msg_list *entry;
+ char abuf[50];
+
+ old = conf->acct_server;
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_NOTICE,
+ "No response from Accounting server %s:%d - failover",
+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+ old->port);
+
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (entry->msg_type == RADIUS_ACCT ||
+ entry->msg_type == RADIUS_ACCT_INTERIM)
+ old->timeouts++;
}
+
+ next = old + 1;
+ if (next > &conf->acct_servers[conf->num_acct_servers - 1])
+ next = conf->acct_servers;
+ conf->acct_server = next;
+ radius_change_server(radius, next, old,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0);
}
static void radius_client_update_timeout(struct radius_client_data *radius)
{
- struct os_time now;
+ struct os_reltime now;
os_time_t first;
struct radius_msg_list *entry;
@@ -498,7 +561,7 @@ static void radius_client_update_timeout(struct radius_client_data *radius)
first = entry->next_try;
}
- os_get_time(&now);
+ os_get_reltime(&now);
if (first < now.sec)
first = now.sec;
eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
@@ -526,7 +589,7 @@ static void radius_client_list_add(struct radius_client_data *radius,
entry = os_zalloc(sizeof(*entry));
if (entry == NULL) {
- printf("Failed to add RADIUS packet into retransmit list\n");
+ wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
radius_msg_free(msg);
return;
}
@@ -537,7 +600,7 @@ static void radius_client_list_add(struct radius_client_data *radius,
entry->msg_type = msg_type;
entry->shared_secret = shared_secret;
entry->shared_secret_len = shared_secret_len;
- os_get_time(&entry->last_attempt);
+ os_get_reltime(&entry->last_attempt);
entry->first_try = entry->last_attempt.sec;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
entry->attempts = 1;
@@ -547,8 +610,7 @@ static void radius_client_list_add(struct radius_client_data *radius,
radius_client_update_timeout(radius);
if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
- printf("Removing the oldest un-ACKed RADIUS packet due to "
- "retransmit list limits.\n");
+ wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
prev = NULL;
while (entry->next) {
prev = entry;
@@ -635,7 +697,11 @@ int radius_client_send(struct radius_client_data *radius,
}
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
- if (conf->acct_server == NULL) {
+ if (conf->acct_server && radius->acct_sock < 0)
+ radius_client_init_acct(radius);
+
+ if (conf->acct_server == NULL || radius->acct_sock < 0 ||
+ conf->acct_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -649,7 +715,11 @@ int radius_client_send(struct radius_client_data *radius,
s = radius->acct_sock;
conf->acct_server->requests++;
} else {
- if (conf->auth_server == NULL) {
+ if (conf->auth_server && radius->auth_sock < 0)
+ radius_client_init_auth(radius);
+
+ if (conf->auth_server == NULL || radius->auth_sock < 0 ||
+ conf->auth_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -694,7 +764,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
struct radius_rx_handler *handlers;
size_t num_handlers, i;
struct radius_msg_list *req, *prev_req;
- struct os_time now;
+ struct os_reltime now;
struct hostapd_radius_server *rconf;
int invalid_authenticator = 0;
@@ -710,21 +780,20 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
if (len < 0) {
- perror("recv[RADIUS]");
+ wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
return;
}
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
"server", len);
if (len == sizeof(buf)) {
- printf("Possibly too long UDP frame for our buffer - "
- "dropping it\n");
+ wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
return;
}
msg = radius_msg_parse(buf, len);
if (msg == NULL) {
- printf("Parsing incoming RADIUS frame failed\n");
+ wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
rconf->malformed_responses++;
return;
}
@@ -775,7 +844,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
goto fail;
}
- os_get_time(&now);
+ os_get_reltime(&now);
roundtrip = (now.sec - req->last_attempt.sec) * 100 +
(now.usec - req->last_attempt.usec) / 10000;
hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
@@ -954,9 +1023,10 @@ radius_change_server(struct radius_client_data *radius,
hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
nserv->port);
- if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
- os_memcmp(nserv->shared_secret, oserv->shared_secret,
- nserv->shared_secret_len) != 0) {
+ if (oserv && oserv != nserv &&
+ (nserv->shared_secret_len != oserv->shared_secret_len ||
+ os_memcmp(nserv->shared_secret, oserv->shared_secret,
+ nserv->shared_secret_len) != 0)) {
/* Pending RADIUS packets used different shared secret, so
* they need to be modified. Update accounting message
* authenticators here. Authentication messages are removed
@@ -974,7 +1044,8 @@ radius_change_server(struct radius_client_data *radius,
}
/* Reset retry counters for the new server */
- for (entry = radius->msgs; entry; entry = entry->next) {
+ for (entry = radius->msgs; oserv && oserv != nserv && entry;
+ entry = entry->next) {
if ((auth && entry->msg_type != RADIUS_AUTH) ||
(!auth && entry->msg_type != RADIUS_ACCT))
continue;
@@ -1015,6 +1086,13 @@ radius_change_server(struct radius_client_data *radius,
return -1;
}
+ if (sel_sock < 0) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
+ nserv->addr.af, sock, sock6, auth);
+ return -1;
+ }
+
if (conf->force_client_addr) {
switch (conf->client_addr.af) {
case AF_INET:
@@ -1041,13 +1119,14 @@ radius_change_server(struct radius_client_data *radius,
}
if (bind(sel_sock, cl_addr, claddrlen) < 0) {
- perror("bind[radius]");
+ wpa_printf(MSG_INFO, "bind[radius]: %s",
+ strerror(errno));
return -1;
}
}
if (connect(sel_sock, addr, addrlen) < 0) {
- perror("connect[radius]");
+ wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
return -1;
}
@@ -1055,19 +1134,23 @@ radius_change_server(struct radius_client_data *radius,
switch (nserv->addr.af) {
case AF_INET:
claddrlen = sizeof(claddr);
- getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
- wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
- inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
+ if (getsockname(sel_sock, (struct sockaddr *) &claddr,
+ &claddrlen) == 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntoa(claddr.sin_addr),
+ ntohs(claddr.sin_port));
+ }
break;
#ifdef CONFIG_IPV6
case AF_INET6: {
claddrlen = sizeof(claddr6);
- getsockname(sel_sock, (struct sockaddr *) &claddr6,
- &claddrlen);
- wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
- inet_ntop(AF_INET6, &claddr6.sin6_addr,
- abuf, sizeof(abuf)),
- ntohs(claddr6.sin6_port));
+ if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
+ &claddrlen) == 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntop(AF_INET6, &claddr6.sin6_addr,
+ abuf, sizeof(abuf)),
+ ntohs(claddr6.sin6_port));
+ }
break;
}
#endif /* CONFIG_IPV6 */
@@ -1093,18 +1176,28 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
conf->auth_server != conf->auth_servers) {
oserv = conf->auth_server;
conf->auth_server = conf->auth_servers;
- radius_change_server(radius, conf->auth_server, oserv,
- radius->auth_serv_sock,
- radius->auth_serv_sock6, 1);
+ if (radius_change_server(radius, conf->auth_server, oserv,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1) < 0) {
+ conf->auth_server = oserv;
+ radius_change_server(radius, oserv, conf->auth_server,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1);
+ }
}
if (radius->acct_sock >= 0 && conf->acct_servers &&
conf->acct_server != conf->acct_servers) {
oserv = conf->acct_server;
conf->acct_server = conf->acct_servers;
- radius_change_server(radius, conf->acct_server, oserv,
- radius->acct_serv_sock,
- radius->acct_serv_sock6, 0);
+ if (radius_change_server(radius, conf->acct_server, oserv,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0) < 0) {
+ conf->acct_server = oserv;
+ radius_change_server(radius, oserv, conf->acct_server,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0);
+ }
}
if (conf->retry_primary_interval)
@@ -1123,21 +1216,62 @@ static int radius_client_disable_pmtu_discovery(int s)
r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
sizeof(action));
if (r == -1)
- wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
- "%s", strerror(errno));
+ wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
+ strerror(errno));
#endif
return r;
}
+static void radius_close_auth_sockets(struct radius_client_data *radius)
+{
+ radius->auth_sock = -1;
+
+ if (radius->auth_serv_sock >= 0) {
+ eloop_unregister_read_sock(radius->auth_serv_sock);
+ close(radius->auth_serv_sock);
+ radius->auth_serv_sock = -1;
+ }
+#ifdef CONFIG_IPV6
+ if (radius->auth_serv_sock6 >= 0) {
+ eloop_unregister_read_sock(radius->auth_serv_sock6);
+ close(radius->auth_serv_sock6);
+ radius->auth_serv_sock6 = -1;
+ }
+#endif /* CONFIG_IPV6 */
+}
+
+
+static void radius_close_acct_sockets(struct radius_client_data *radius)
+{
+ radius->acct_sock = -1;
+
+ if (radius->acct_serv_sock >= 0) {
+ eloop_unregister_read_sock(radius->acct_serv_sock);
+ close(radius->acct_serv_sock);
+ radius->acct_serv_sock = -1;
+ }
+#ifdef CONFIG_IPV6
+ if (radius->acct_serv_sock6 >= 0) {
+ eloop_unregister_read_sock(radius->acct_serv_sock6);
+ close(radius->acct_serv_sock6);
+ radius->acct_serv_sock6 = -1;
+ }
+#endif /* CONFIG_IPV6 */
+}
+
+
static int radius_client_init_auth(struct radius_client_data *radius)
{
struct hostapd_radius_servers *conf = radius->conf;
int ok = 0;
+ radius_close_auth_sockets(radius);
+
radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (radius->auth_serv_sock < 0)
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
else {
radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
ok++;
@@ -1146,7 +1280,8 @@ static int radius_client_init_auth(struct radius_client_data *radius)
#ifdef CONFIG_IPV6
radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
if (radius->auth_serv_sock6 < 0)
- perror("socket[PF_INET6,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+ strerror(errno));
else
ok++;
#endif /* CONFIG_IPV6 */
@@ -1162,8 +1297,8 @@ static int radius_client_init_auth(struct radius_client_data *radius)
eloop_register_read_sock(radius->auth_serv_sock,
radius_client_receive, radius,
(void *) RADIUS_AUTH)) {
- printf("Could not register read socket for authentication "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
+ radius_close_auth_sockets(radius);
return -1;
}
@@ -1172,8 +1307,8 @@ static int radius_client_init_auth(struct radius_client_data *radius)
eloop_register_read_sock(radius->auth_serv_sock6,
radius_client_receive, radius,
(void *) RADIUS_AUTH)) {
- printf("Could not register read socket for authentication "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
+ radius_close_auth_sockets(radius);
return -1;
}
#endif /* CONFIG_IPV6 */
@@ -1187,9 +1322,12 @@ static int radius_client_init_acct(struct radius_client_data *radius)
struct hostapd_radius_servers *conf = radius->conf;
int ok = 0;
+ radius_close_acct_sockets(radius);
+
radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (radius->acct_serv_sock < 0)
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
else {
radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
ok++;
@@ -1198,7 +1336,8 @@ static int radius_client_init_acct(struct radius_client_data *radius)
#ifdef CONFIG_IPV6
radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
if (radius->acct_serv_sock6 < 0)
- perror("socket[PF_INET6,SOCK_DGRAM]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
+ strerror(errno));
else
ok++;
#endif /* CONFIG_IPV6 */
@@ -1214,8 +1353,8 @@ static int radius_client_init_acct(struct radius_client_data *radius)
eloop_register_read_sock(radius->acct_serv_sock,
radius_client_receive, radius,
(void *) RADIUS_ACCT)) {
- printf("Could not register read socket for accounting "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
+ radius_close_acct_sockets(radius);
return -1;
}
@@ -1224,8 +1363,8 @@ static int radius_client_init_acct(struct radius_client_data *radius)
eloop_register_read_sock(radius->acct_serv_sock6,
radius_client_receive, radius,
(void *) RADIUS_ACCT)) {
- printf("Could not register read socket for accounting "
- "server\n");
+ wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
+ radius_close_acct_sockets(radius);
return -1;
}
#endif /* CONFIG_IPV6 */
@@ -1287,16 +1426,8 @@ void radius_client_deinit(struct radius_client_data *radius)
if (!radius)
return;
- if (radius->auth_serv_sock >= 0)
- eloop_unregister_read_sock(radius->auth_serv_sock);
- if (radius->acct_serv_sock >= 0)
- eloop_unregister_read_sock(radius->acct_serv_sock);
-#ifdef CONFIG_IPV6
- if (radius->auth_serv_sock6 >= 0)
- eloop_unregister_read_sock(radius->auth_serv_sock6);
- if (radius->acct_serv_sock6 >= 0)
- eloop_unregister_read_sock(radius->acct_serv_sock6);
-#endif /* CONFIG_IPV6 */
+ radius_close_auth_sockets(radius);
+ radius_close_acct_sockets(radius);
eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
diff --git a/contrib/wpa/src/radius/radius_das.c b/contrib/wpa/src/radius/radius_das.c
index bded965..39ceea8 100644
--- a/contrib/wpa/src/radius/radius_das.c
+++ b/contrib/wpa/src/radius/radius_das.c
@@ -1,6 +1,6 @@
/*
* RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
- * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -16,9 +16,6 @@
#include "radius_das.h"
-extern int wpa_debug_level;
-
-
struct radius_das_data {
int sock;
u8 *shared_secret;
@@ -41,11 +38,17 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
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_IPV6
+ RADIUS_ATTR_NAS_IPV6_ADDRESS,
+#endif /* CONFIG_IPV6 */
0
};
int error = 405;
@@ -70,6 +73,36 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
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))
@@ -97,6 +130,12 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
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;
@@ -115,6 +154,12 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
"%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_SUCCESS:
error = 0;
break;
@@ -200,7 +245,8 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
(u8 *) &val, 4);
if (res == 4) {
u32 timestamp = ntohl(val);
- if (abs(now.sec - timestamp) > das->time_window) {
+ if ((unsigned int) abs(now.sec - timestamp) >
+ das->time_window) {
wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
"Event-Timestamp (%u; local time %u) in "
"packet from %s:%d - drop",
@@ -284,7 +330,7 @@ static int radius_das_open_socket(int port)
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno));
return -1;
}
@@ -292,7 +338,7 @@ static int radius_das_open_socket(int port)
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno));
close(s);
return -1;
}
diff --git a/contrib/wpa/src/radius/radius_das.h b/contrib/wpa/src/radius/radius_das.h
index 738b18b..ce731d4 100644
--- a/contrib/wpa/src/radius/radius_das.h
+++ b/contrib/wpa/src/radius/radius_das.h
@@ -14,15 +14,25 @@ struct radius_das_data;
enum radius_das_res {
RADIUS_DAS_SUCCESS,
RADIUS_DAS_NAS_MISMATCH,
- RADIUS_DAS_SESSION_NOT_FOUND
+ RADIUS_DAS_SESSION_NOT_FOUND,
+ RADIUS_DAS_MULTI_SESSION_MATCH,
};
struct radius_das_attrs {
+ /* NAS identification attributes */
+ const u8 *nas_ip_addr;
+ const u8 *nas_identifier;
+ size_t nas_identifier_len;
+ const u8 *nas_ipv6_addr;
+
+ /* Session identification attributes */
const u8 *sta_addr;
const u8 *user_name;
size_t user_name_len;
const u8 *acct_session_id;
size_t acct_session_id_len;
+ const u8 *acct_multi_session_id;
+ size_t acct_multi_session_id_len;
const u8 *cui;
size_t cui_len;
};
diff --git a/contrib/wpa/src/radius/radius_server.c b/contrib/wpa/src/radius/radius_server.c
index 5b2d711..85a485e 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, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -8,11 +8,16 @@
#include "includes.h"
#include <net/if.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "common.h"
#include "radius.h"
#include "eloop.h"
#include "eap_server/eap.h"
+#include "ap/ap_config.h"
+#include "crypto/tls.h"
#include "radius_server.h"
/**
@@ -49,6 +54,13 @@ struct radius_server_counters {
u32 bad_authenticators;
u32 packets_dropped;
u32 unknown_types;
+
+ u32 acct_requests;
+ u32 invalid_acct_requests;
+ u32 acct_responses;
+ u32 malformed_acct_requests;
+ u32 acct_bad_authenticators;
+ u32 unknown_acct_types;
};
/**
@@ -61,6 +73,8 @@ struct radius_session {
unsigned int sess_id;
struct eap_sm *eap;
struct eap_eapol_interface *eap_if;
+ char *username; /* from User-Name attribute */
+ char *nas_ip;
struct radius_msg *last_msg;
char *last_from_addr;
@@ -70,6 +84,11 @@ struct radius_session {
u8 last_identifier;
struct radius_msg *last_reply;
u8 last_authenticator[16];
+
+ unsigned int remediation:1;
+ unsigned int macacl:1;
+
+ struct hostapd_radius_attr *accept_attr;
};
/**
@@ -99,6 +118,11 @@ struct radius_server_data {
int auth_sock;
/**
+ * acct_sock - Socket for RADIUS accounting messages
+ */
+ int acct_sock;
+
+ /**
* clients - List of authorized RADIUS clients
*/
struct radius_client *clients;
@@ -223,6 +247,25 @@ struct radius_server_data {
u16 pwd_group;
/**
+ * server_id - Server identity
+ */
+ const char *server_id;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
+ int erp;
+
+ const char *erp_domain;
+
+ struct dl_list erp_keys; /* struct eap_server_erp_key */
+
+ /**
* wps - Wi-Fi Protected Setup context
*
* If WPS is used with an external RADIUS server (which is quite
@@ -239,7 +282,7 @@ struct radius_server_data {
/**
* start_time - Timestamp of server start
*/
- struct os_time start_time;
+ struct os_reltime start_time;
/**
* counters - Statistics counters for server operations
@@ -290,10 +333,15 @@ struct radius_server_data {
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
-};
+ char *subscr_remediation_url;
+ u8 subscr_remediation_method;
+
+#ifdef CONFIG_SQLITE
+ sqlite3 *db;
+#endif /* CONFIG_SQLITE */
+};
-extern int wpa_debug_level;
#define RADIUS_DEBUG(args...) \
wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
@@ -309,6 +357,52 @@ 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);
+void srv_log(struct radius_session *sess, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
+void srv_log(struct radius_session *sess, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ va_start(ap, fmt);
+ vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+
+ RADIUS_DEBUG("[0x%x %s] %s", sess->sess_id, sess->nas_ip, buf);
+
+#ifdef CONFIG_SQLITE
+ if (sess->server->db) {
+ char *sql;
+ sql = sqlite3_mprintf("INSERT INTO authlog"
+ "(timestamp,session,nas_ip,username,note)"
+ " VALUES ("
+ "strftime('%%Y-%%m-%%d %%H:%%M:%%f',"
+ "'now'),%u,%Q,%Q,%Q)",
+ sess->sess_id, sess->nas_ip,
+ sess->username, buf);
+ if (sql) {
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
+ NULL) != SQLITE_OK) {
+ RADIUS_ERROR("Failed to add authlog entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+ }
+ }
+#endif /* CONFIG_SQLITE */
+
+ os_free(buf);
+}
+
static struct radius_client *
radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
@@ -374,6 +468,8 @@ static void radius_server_session_free(struct radius_server_data *data,
radius_msg_free(sess->last_msg);
os_free(sess->last_from_addr);
radius_msg_free(sess->last_reply);
+ os_free(sess->username);
+ os_free(sess->nas_ip);
os_free(sess);
data->num_sess--;
}
@@ -453,47 +549,125 @@ radius_server_new_session(struct radius_server_data *data,
}
+#ifdef CONFIG_TESTING_OPTIONS
+static void radius_server_testing_options_tls(struct radius_session *sess,
+ const char *tls,
+ struct eap_config *eap_conf)
+{
+ int test = atoi(tls);
+
+ switch (test) {
+ case 1:
+ srv_log(sess, "TLS test - break VerifyData");
+ eap_conf->tls_test_flags = TLS_BREAK_VERIFY_DATA;
+ break;
+ case 2:
+ srv_log(sess, "TLS test - break ServerKeyExchange ServerParams hash");
+ eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_HASH;
+ break;
+ case 3:
+ srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature");
+ eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE;
+ break;
+ case 4:
+ srv_log(sess, "TLS test - RSA-DHE using a short 511-bit prime");
+ eap_conf->tls_test_flags = TLS_DHE_PRIME_511B;
+ break;
+ case 5:
+ srv_log(sess, "TLS test - RSA-DHE using a short 767-bit prime");
+ eap_conf->tls_test_flags = TLS_DHE_PRIME_767B;
+ break;
+ case 6:
+ srv_log(sess, "TLS test - RSA-DHE using a bogus 15 \"prime\"");
+ eap_conf->tls_test_flags = TLS_DHE_PRIME_15;
+ break;
+ case 7:
+ srv_log(sess, "TLS test - RSA-DHE using a short 58-bit prime in long container");
+ eap_conf->tls_test_flags = TLS_DHE_PRIME_58B;
+ break;
+ case 8:
+ srv_log(sess, "TLS test - RSA-DHE using a non-prime");
+ eap_conf->tls_test_flags = TLS_DHE_NON_PRIME;
+ break;
+ default:
+ srv_log(sess, "Unrecognized TLS test");
+ break;
+ }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+static void radius_server_testing_options(struct radius_session *sess,
+ struct eap_config *eap_conf)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ const char *pos;
+
+ pos = os_strstr(sess->username, "@test-");
+ if (pos == NULL)
+ return;
+ pos += 6;
+ if (os_strncmp(pos, "tls-", 4) == 0)
+ radius_server_testing_options_tls(sess, pos + 4, eap_conf);
+ else
+ srv_log(sess, "Unrecognized test: %s", pos);
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
static struct radius_session *
radius_server_get_new_session(struct radius_server_data *data,
struct radius_client *client,
- struct radius_msg *msg)
+ struct radius_msg *msg, const char *from_addr)
{
u8 *user;
size_t user_len;
int res;
struct radius_session *sess;
struct eap_config eap_conf;
+ struct eap_user tmp;
RADIUS_DEBUG("Creating a new session");
- user = os_malloc(256);
- if (user == NULL) {
- return NULL;
- }
- res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
- if (res < 0 || res > 256) {
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &user,
+ &user_len, NULL) < 0) {
RADIUS_DEBUG("Could not get User-Name");
- os_free(user);
return NULL;
}
- user_len = res;
RADIUS_DUMP_ASCII("User-Name", user, user_len);
- res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
- os_free(user);
+ 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);
- if (res == 0) {
- RADIUS_DEBUG("Matching user entry found");
- sess = radius_server_new_session(data, client);
- if (sess == NULL) {
- RADIUS_DEBUG("Failed to create a new session");
- return NULL;
- }
- } else {
+ if (res != 0) {
RADIUS_DEBUG("User-Name not found from user database");
return NULL;
}
+ RADIUS_DEBUG("Matching user entry found");
+ sess = radius_server_new_session(data, client);
+ if (sess == NULL) {
+ RADIUS_DEBUG("Failed to create a new session");
+ return NULL;
+ }
+ sess->accept_attr = tmp.accept_attr;
+ sess->macacl = tmp.macacl;
+
+ sess->username = os_malloc(user_len * 4 + 1);
+ if (sess->username == NULL) {
+ radius_server_session_free(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);
+ return NULL;
+ }
+
+ srv_log(sess, "New session created");
+
os_memset(&eap_conf, 0, sizeof(eap_conf));
eap_conf.ssl_ctx = data->ssl_ctx;
eap_conf.msg_ctx = data->msg_ctx;
@@ -511,6 +685,10 @@ radius_server_get_new_session(struct radius_server_data *data,
eap_conf.tnc = data->tnc;
eap_conf.wps = data->wps;
eap_conf.pwd_group = data->pwd_group;
+ eap_conf.server_id = (const u8 *) data->server_id;
+ eap_conf.server_id_len = os_strlen(data->server_id);
+ eap_conf.erp = data->erp;
+ radius_server_testing_options(sess, &eap_conf);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
&eap_conf);
if (sess->eap == NULL) {
@@ -605,12 +783,134 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
}
}
+#ifdef CONFIG_HS20
+ if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation &&
+ data->subscr_remediation_url) {
+ u8 *buf;
+ size_t url_len = os_strlen(data->subscr_remediation_url);
+ buf = os_malloc(1 + url_len);
+ if (buf == NULL) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+ buf[0] = data->subscr_remediation_method;
+ os_memcpy(&buf[1], data->subscr_remediation_url, url_len);
+ 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);
+ } else if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation) {
+ u8 buf[1];
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
+ buf, 0)) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
+ }
+ }
+#endif /* CONFIG_HS20 */
+
if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
radius_msg_free(msg);
return NULL;
}
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+ struct hostapd_radius_attr *attr;
+ for (attr = sess->accept_attr; attr; attr = attr->next) {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+ }
+ }
+ }
+
+ if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
+ client->shared_secret_len,
+ hdr->authenticator) < 0) {
+ RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+ }
+
+ return msg;
+}
+
+
+static struct radius_msg *
+radius_server_macacl(struct radius_server_data *data,
+ struct radius_client *client,
+ struct radius_session *sess,
+ struct radius_msg *request)
+{
+ struct radius_msg *msg;
+ int code;
+ struct radius_hdr *hdr = radius_msg_get_hdr(request);
+ u8 *pw;
+ size_t pw_len;
+
+ code = RADIUS_CODE_ACCESS_ACCEPT;
+
+ if (radius_msg_get_attr_ptr(request, RADIUS_ATTR_USER_PASSWORD, &pw,
+ &pw_len, NULL) < 0) {
+ RADIUS_DEBUG("Could not get User-Password");
+ code = RADIUS_CODE_ACCESS_REJECT;
+ } else {
+ int res;
+ struct eap_user tmp;
+
+ os_memset(&tmp, 0, sizeof(tmp));
+ res = data->get_eap_user(data->conf_ctx, (u8 *) sess->username,
+ os_strlen(sess->username), 0, &tmp);
+ if (res || !tmp.macacl || tmp.password == NULL) {
+ RADIUS_DEBUG("No MAC ACL user entry");
+ bin_clear_free(tmp.password, tmp.password_len);
+ code = RADIUS_CODE_ACCESS_REJECT;
+ } else {
+ u8 buf[128];
+ res = radius_user_password_hide(
+ request, tmp.password, tmp.password_len,
+ (u8 *) client->shared_secret,
+ client->shared_secret_len,
+ buf, sizeof(buf));
+ bin_clear_free(tmp.password, tmp.password_len);
+
+ if (res < 0 || pw_len != (size_t) res ||
+ os_memcmp_const(pw, buf, res) != 0) {
+ RADIUS_DEBUG("Incorrect User-Password");
+ code = RADIUS_CODE_ACCESS_REJECT;
+ }
+ }
+ }
+
+ msg = radius_msg_new(code, hdr->identifier);
+ if (msg == NULL) {
+ RADIUS_DEBUG("Failed to allocate reply message");
+ return NULL;
+ }
+
+ if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
+ RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+ struct hostapd_radius_attr *attr;
+ for (attr = sess->accept_attr; attr; attr = attr->next) {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+ }
+ }
+ }
+
if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
client->shared_secret_len,
hdr->authenticator) < 0) {
@@ -672,7 +972,7 @@ static int radius_server_reject(struct radius_server_data *data,
buf = radius_msg_get_buf(msg);
if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
(struct sockaddr *) from, sizeof(*from)) < 0) {
- perror("sendto[RADIUS SRV]");
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno));
ret = -1;
}
@@ -719,7 +1019,8 @@ static int radius_server_request(struct radius_server_data *data,
from_addr, from_port);
return -1;
} else {
- sess = radius_server_get_new_session(data, client, msg);
+ sess = radius_server_get_new_session(data, client, msg,
+ from_addr);
if (sess == NULL) {
RADIUS_DEBUG("Could not create a new session");
radius_server_reject(data, client, msg, from, fromlen,
@@ -743,7 +1044,8 @@ static int radius_server_request(struct radius_server_data *data,
wpabuf_len(buf), 0,
(struct sockaddr *) from, fromlen);
if (res < 0) {
- perror("sendto[RADIUS SRV]");
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+ strerror(errno));
}
return 0;
}
@@ -754,6 +1056,12 @@ static int radius_server_request(struct radius_server_data *data,
}
eap = radius_msg_get_eap(msg);
+ if (eap == NULL && sess->macacl) {
+ reply = radius_server_macacl(data, client, sess, msg);
+ if (reply == NULL)
+ return -1;
+ goto send_reply;
+ }
if (eap == NULL) {
RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
from_addr);
@@ -804,9 +1112,14 @@ 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)
+ srv_log(sess, "EAP authentication failed");
+ else if (sess->eap_if->eapSuccess)
+ srv_log(sess, "EAP authentication succeeded");
reply = radius_server_encapsulate_eap(data, client, sess, msg);
+send_reply:
if (reply) {
struct wpabuf *buf;
struct radius_hdr *hdr;
@@ -818,10 +1131,12 @@ static int radius_server_request(struct radius_server_data *data,
switch (radius_msg_get_hdr(reply)->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
+ srv_log(sess, "Sending Access-Accept");
data->counters.access_accepts++;
client->counters.access_accepts++;
break;
case RADIUS_CODE_ACCESS_REJECT:
+ srv_log(sess, "Sending Access-Reject");
data->counters.access_rejects++;
client->counters.access_rejects++;
break;
@@ -835,7 +1150,8 @@ static int radius_server_request(struct radius_server_data *data,
wpabuf_len(buf), 0,
(struct sockaddr *) from, fromlen);
if (res < 0) {
- perror("sendto[RADIUS SRV]");
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+ strerror(errno));
}
radius_msg_free(sess->last_reply);
sess->last_reply = reply;
@@ -890,7 +1206,8 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
(struct sockaddr *) &from.ss, &fromlen);
if (len < 0) {
- perror("recvfrom[radius_server]");
+ wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+ strerror(errno));
goto fail;
}
@@ -971,6 +1288,140 @@ fail:
}
+static void radius_server_receive_acct(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct radius_server_data *data = eloop_ctx;
+ u8 *buf = NULL;
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+ } from;
+ socklen_t fromlen;
+ int len, res;
+ struct radius_client *client = NULL;
+ struct radius_msg *msg = NULL, *resp = NULL;
+ char abuf[50];
+ int from_port = 0;
+ struct radius_hdr *hdr;
+ struct wpabuf *rbuf;
+
+ buf = os_malloc(RADIUS_MAX_MSG_LEN);
+ if (buf == NULL) {
+ goto fail;
+ }
+
+ fromlen = sizeof(from);
+ len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
+ (struct sockaddr *) &from.ss, &fromlen);
+ if (len < 0) {
+ wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+#ifdef CONFIG_IPV6
+ if (data->ipv6) {
+ if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
+ sizeof(abuf)) == NULL)
+ abuf[0] = '\0';
+ from_port = ntohs(from.sin6.sin6_port);
+ RADIUS_DEBUG("Received %d bytes from %s:%d",
+ len, abuf, from_port);
+
+ client = radius_server_get_client(data,
+ (struct in_addr *)
+ &from.sin6.sin6_addr, 1);
+ }
+#endif /* CONFIG_IPV6 */
+
+ if (!data->ipv6) {
+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+ from_port = ntohs(from.sin.sin_port);
+ RADIUS_DEBUG("Received %d bytes from %s:%d",
+ len, abuf, from_port);
+
+ client = radius_server_get_client(data, &from.sin.sin_addr, 0);
+ }
+
+ RADIUS_DUMP("Received data", buf, len);
+
+ if (client == NULL) {
+ RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
+ data->counters.invalid_acct_requests++;
+ goto fail;
+ }
+
+ msg = radius_msg_parse(buf, len);
+ if (msg == NULL) {
+ RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
+ data->counters.malformed_acct_requests++;
+ client->counters.malformed_acct_requests++;
+ goto fail;
+ }
+
+ os_free(buf);
+ buf = NULL;
+
+ if (wpa_debug_level <= MSG_MSGDUMP) {
+ radius_msg_dump(msg);
+ }
+
+ if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) {
+ RADIUS_DEBUG("Unexpected RADIUS code %d",
+ radius_msg_get_hdr(msg)->code);
+ data->counters.unknown_acct_types++;
+ client->counters.unknown_acct_types++;
+ goto fail;
+ }
+
+ data->counters.acct_requests++;
+ client->counters.acct_requests++;
+
+ if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret,
+ client->shared_secret_len)) {
+ RADIUS_DEBUG("Invalid Authenticator from %s", abuf);
+ data->counters.acct_bad_authenticators++;
+ client->counters.acct_bad_authenticators++;
+ goto fail;
+ }
+
+ /* TODO: Write accounting information to a file or database */
+
+ hdr = radius_msg_get_hdr(msg);
+
+ resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier);
+ if (resp == NULL)
+ goto fail;
+
+ radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
+ client->shared_secret_len,
+ hdr->authenticator);
+
+ RADIUS_DEBUG("Reply to %s:%d", abuf, from_port);
+ if (wpa_debug_level <= MSG_MSGDUMP) {
+ radius_msg_dump(resp);
+ }
+ rbuf = radius_msg_get_buf(resp);
+ data->counters.acct_responses++;
+ client->counters.acct_responses++;
+ res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0,
+ (struct sockaddr *) &from.ss, fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+ strerror(errno));
+ }
+
+fail:
+ radius_msg_free(resp);
+ radius_msg_free(msg);
+ os_free(buf);
+}
+
+
static int radius_server_disable_pmtu_discovery(int s)
{
int r = -1;
@@ -994,7 +1445,7 @@ static int radius_server_open_socket(int port)
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno));
return -1;
}
@@ -1004,7 +1455,7 @@ static int radius_server_open_socket(int port)
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
close(s);
return -1;
}
@@ -1021,7 +1472,8 @@ static int radius_server_open_socket6(int port)
s = socket(PF_INET6, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket[IPv6]");
+ wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s",
+ strerror(errno));
return -1;
}
@@ -1030,7 +1482,7 @@ static int radius_server_open_socket6(int port)
os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(port);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
close(s);
return -1;
}
@@ -1183,8 +1635,8 @@ radius_server_read_clients(const char *client_file, int ipv6)
break;
}
entry->shared_secret_len = os_strlen(entry->shared_secret);
- entry->addr.s_addr = addr.s_addr;
if (!ipv6) {
+ entry->addr.s_addr = addr.s_addr;
val = 0;
for (i = 0; i < mask; i++)
val |= 1 << (31 - i);
@@ -1241,8 +1693,7 @@ radius_server_init(struct radius_server_conf *conf)
#ifndef CONFIG_IPV6
if (conf->ipv6) {
- fprintf(stderr, "RADIUS server compiled without IPv6 "
- "support.\n");
+ wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support");
return NULL;
}
#endif /* CONFIG_IPV6 */
@@ -1251,7 +1702,8 @@ radius_server_init(struct radius_server_conf *conf)
if (data == NULL)
return NULL;
- os_get_time(&data->start_time);
+ dl_list_init(&data->erp_keys);
+ os_get_reltime(&data->start_time);
data->conf_ctx = conf->conf_ctx;
data->eap_sim_db_priv = conf->eap_sim_db_priv;
data->ssl_ctx = conf->ssl_ctx;
@@ -1280,6 +1732,7 @@ radius_server_init(struct radius_server_conf *conf)
data->tnc = conf->tnc;
data->wps = conf->wps;
data->pwd_group = conf->pwd_group;
+ data->server_id = conf->server_id;
if (conf->eap_req_id_text) {
data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
if (data->eap_req_id_text) {
@@ -1288,6 +1741,25 @@ radius_server_init(struct radius_server_conf *conf)
data->eap_req_id_text_len = conf->eap_req_id_text_len;
}
}
+ data->erp = conf->erp;
+ data->erp_domain = conf->erp_domain;
+
+ if (conf->subscr_remediation_url) {
+ data->subscr_remediation_url =
+ os_strdup(conf->subscr_remediation_url);
+ }
+ data->subscr_remediation_method = conf->subscr_remediation_method;
+
+#ifdef CONFIG_SQLITE
+ if (conf->sqlite_file) {
+ if (sqlite3_open(conf->sqlite_file, &data->db)) {
+ RADIUS_ERROR("Could not open SQLite file '%s'",
+ conf->sqlite_file);
+ radius_server_deinit(data);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_SQLITE */
#ifdef CONFIG_RADIUS_TEST
if (conf->dump_msk_file)
@@ -1297,7 +1769,7 @@ radius_server_init(struct radius_server_conf *conf)
data->clients = radius_server_read_clients(conf->client_file,
conf->ipv6);
if (data->clients == NULL) {
- printf("No RADIUS clients configured.\n");
+ wpa_printf(MSG_ERROR, "No RADIUS clients configured");
radius_server_deinit(data);
return NULL;
}
@@ -1309,8 +1781,7 @@ radius_server_init(struct radius_server_conf *conf)
#endif /* CONFIG_IPV6 */
data->auth_sock = radius_server_open_socket(conf->auth_port);
if (data->auth_sock < 0) {
- printf("Failed to open UDP socket for RADIUS authentication "
- "server\n");
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
radius_server_deinit(data);
return NULL;
}
@@ -1321,11 +1792,52 @@ radius_server_init(struct radius_server_conf *conf)
return NULL;
}
+ if (conf->acct_port) {
+#ifdef CONFIG_IPV6
+ if (conf->ipv6)
+ data->acct_sock = radius_server_open_socket6(
+ conf->acct_port);
+ else
+#endif /* CONFIG_IPV6 */
+ data->acct_sock = radius_server_open_socket(conf->acct_port);
+ if (data->acct_sock < 0) {
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
+ radius_server_deinit(data);
+ return NULL;
+ }
+ if (eloop_register_read_sock(data->acct_sock,
+ radius_server_receive_acct,
+ data, NULL)) {
+ radius_server_deinit(data);
+ return NULL;
+ }
+ } else {
+ data->acct_sock = -1;
+ }
+
return data;
}
/**
+ * radius_server_erp_flush - Flush all ERP keys
+ * @data: RADIUS server context from radius_server_init()
+ */
+void radius_server_erp_flush(struct radius_server_data *data)
+{
+ struct eap_server_erp_key *erp;
+
+ if (data == NULL)
+ return;
+ while ((erp = dl_list_first(&data->erp_keys, struct eap_server_erp_key,
+ list)) != NULL) {
+ dl_list_del(&erp->list);
+ bin_clear_free(erp, sizeof(*erp));
+ }
+}
+
+
+/**
* radius_server_deinit - Deinitialize RADIUS server
* @data: RADIUS server context from radius_server_init()
*/
@@ -1339,6 +1851,11 @@ void radius_server_deinit(struct radius_server_data *data)
close(data->auth_sock);
}
+ if (data->acct_sock >= 0) {
+ eloop_unregister_read_sock(data->acct_sock);
+ close(data->acct_sock);
+ }
+
radius_server_free_clients(data, data->clients);
os_free(data->pac_opaque_encr_key);
@@ -1348,6 +1865,15 @@ void radius_server_deinit(struct radius_server_data *data)
#ifdef CONFIG_RADIUS_TEST
os_free(data->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
+ os_free(data->subscr_remediation_url);
+
+#ifdef CONFIG_SQLITE
+ if (data->db)
+ sqlite3_close(data->db);
+#endif /* CONFIG_SQLITE */
+
+ radius_server_erp_flush(data);
+
os_free(data);
}
@@ -1365,7 +1891,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
int ret, uptime;
unsigned int idx;
char *end, *pos;
- struct os_time now;
+ struct os_reltime now;
struct radius_client *cli;
/* RFC 2619 - RADIUS Authentication Server MIB */
@@ -1376,7 +1902,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
pos = buf;
end = buf + buflen;
- os_get_time(&now);
+ os_get_reltime(&now);
uptime = (now.sec - data->start_time.sec) * 100 +
((now.usec - data->start_time.usec) / 10000) % 100;
ret = os_snprintf(pos, end - pos,
@@ -1386,7 +1912,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
"radiusAuthServResetTime=0\n"
"radiusAuthServConfigReset=4\n",
uptime);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
*pos = '\0';
return pos - buf;
}
@@ -1402,7 +1928,13 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
"radiusAuthServTotalMalformedAccessRequests=%u\n"
"radiusAuthServTotalBadAuthenticators=%u\n"
"radiusAuthServTotalPacketsDropped=%u\n"
- "radiusAuthServTotalUnknownTypes=%u\n",
+ "radiusAuthServTotalUnknownTypes=%u\n"
+ "radiusAccServTotalRequests=%u\n"
+ "radiusAccServTotalInvalidRequests=%u\n"
+ "radiusAccServTotalResponses=%u\n"
+ "radiusAccServTotalMalformedRequests=%u\n"
+ "radiusAccServTotalBadAuthenticators=%u\n"
+ "radiusAccServTotalUnknownTypes=%u\n",
data->counters.access_requests,
data->counters.invalid_requests,
data->counters.dup_access_requests,
@@ -1412,8 +1944,14 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
data->counters.malformed_access_requests,
data->counters.bad_authenticators,
data->counters.packets_dropped,
- data->counters.unknown_types);
- if (ret < 0 || ret >= end - pos) {
+ data->counters.unknown_types,
+ data->counters.acct_requests,
+ data->counters.invalid_acct_requests,
+ data->counters.acct_responses,
+ data->counters.malformed_acct_requests,
+ data->counters.acct_bad_authenticators,
+ data->counters.unknown_acct_types);
+ if (os_snprintf_error(end - pos, ret)) {
*pos = '\0';
return pos - buf;
}
@@ -1426,7 +1964,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
if (inet_ntop(AF_INET6, &cli->addr6, abuf,
sizeof(abuf)) == NULL)
abuf[0] = '\0';
- if (inet_ntop(AF_INET6, &cli->mask6, abuf,
+ if (inet_ntop(AF_INET6, &cli->mask6, mbuf,
sizeof(mbuf)) == NULL)
mbuf[0] = '\0';
}
@@ -1447,7 +1985,13 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
"radiusAuthServMalformedAccessRequests=%u\n"
"radiusAuthServBadAuthenticators=%u\n"
"radiusAuthServPacketsDropped=%u\n"
- "radiusAuthServUnknownTypes=%u\n",
+ "radiusAuthServUnknownTypes=%u\n"
+ "radiusAccServTotalRequests=%u\n"
+ "radiusAccServTotalInvalidRequests=%u\n"
+ "radiusAccServTotalResponses=%u\n"
+ "radiusAccServTotalMalformedRequests=%u\n"
+ "radiusAccServTotalBadAuthenticators=%u\n"
+ "radiusAccServTotalUnknownTypes=%u\n",
idx,
abuf, mbuf,
cli->counters.access_requests,
@@ -1458,8 +2002,14 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
cli->counters.malformed_access_requests,
cli->counters.bad_authenticators,
cli->counters.packets_dropped,
- cli->counters.unknown_types);
- if (ret < 0 || ret >= end - pos) {
+ cli->counters.unknown_types,
+ cli->counters.acct_requests,
+ cli->counters.invalid_acct_requests,
+ cli->counters.acct_responses,
+ cli->counters.malformed_acct_requests,
+ cli->counters.acct_bad_authenticators,
+ cli->counters.unknown_acct_types);
+ if (os_snprintf_error(end - pos, ret)) {
*pos = '\0';
return pos - buf;
}
@@ -1476,9 +2026,16 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity,
{
struct radius_session *sess = ctx;
struct radius_server_data *data = sess->server;
-
- return data->get_eap_user(data->conf_ctx, identity, identity_len,
- phase2, user);
+ int ret;
+
+ ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
+ phase2, user);
+ if (ret == 0 && user) {
+ sess->accept_attr = user->accept_attr;
+ sess->remediation = user->remediation;
+ sess->macacl = user->macacl;
+ }
+ return ret;
}
@@ -1491,10 +2048,64 @@ static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
}
+static void radius_server_log_msg(void *ctx, const char *msg)
+{
+ struct radius_session *sess = ctx;
+ srv_log(sess, "EAP: %s", msg);
+}
+
+
+#ifdef CONFIG_ERP
+
+static const char * radius_server_get_erp_domain(void *ctx)
+{
+ struct radius_session *sess = ctx;
+ struct radius_server_data *data = sess->server;
+
+ return data->erp_domain;
+}
+
+
+static struct eap_server_erp_key *
+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;
+}
+
+
+static int radius_server_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+ struct radius_session *sess = ctx;
+ struct radius_server_data *data = sess->server;
+
+ dl_list_add(&data->erp_keys, &erp->list);
+ return 0;
+}
+
+#endif /* CONFIG_ERP */
+
+
static struct eapol_callbacks radius_server_eapol_cb =
{
.get_eap_user = radius_server_get_eap_user,
.get_eap_req_id_text = radius_server_get_eap_req_id_text,
+ .log_msg = radius_server_log_msg,
+#ifdef CONFIG_ERP
+ .get_erp_send_reauth_start = NULL,
+ .get_erp_domain = radius_server_get_erp_domain,
+ .erp_get_key = radius_server_erp_get_key,
+ .erp_add_key = radius_server_erp_add_key,
+#endif /* CONFIG_ERP */
};
@@ -1521,8 +2132,6 @@ void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
sess = s;
break;
}
- if (sess)
- break;
}
if (sess)
break;
diff --git a/contrib/wpa/src/radius/radius_server.h b/contrib/wpa/src/radius/radius_server.h
index 82466c3..ca4e38c 100644
--- a/contrib/wpa/src/radius/radius_server.h
+++ b/contrib/wpa/src/radius/radius_server.h
@@ -22,6 +22,11 @@ struct radius_server_conf {
int auth_port;
/**
+ * acct_port - UDP port to listen to as an accounting server
+ */
+ int acct_port;
+
+ /**
* client_file - RADIUS client configuration file
*
* This file contains the RADIUS clients and the shared secret to be
@@ -35,6 +40,11 @@ struct radius_server_conf {
char *client_file;
/**
+ * sqlite_file - SQLite database for storing debug log information
+ */
+ const char *sqlite_file;
+
+ /**
* conf_ctx - Context pointer for callbacks
*
* This is used as the ctx argument in get_eap_user() calls.
@@ -144,6 +154,23 @@ struct radius_server_conf {
u16 pwd_group;
/**
+ * server_id - Server identity
+ */
+ const char *server_id;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
+ int erp;
+
+ const char *erp_domain;
+
+ /**
* wps - Wi-Fi Protected Setup context
*
* If WPS is used with an external RADIUS server (which is quite
@@ -199,12 +226,16 @@ struct radius_server_conf {
#ifdef CONFIG_RADIUS_TEST
const char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
+
+ char *subscr_remediation_url;
+ u8 subscr_remediation_method;
};
struct radius_server_data *
radius_server_init(struct radius_server_conf *conf);
+void radius_server_erp_flush(struct radius_server_data *data);
void radius_server_deinit(struct radius_server_data *data);
int radius_server_get_mib(struct radius_server_data *data, char *buf,
diff --git a/contrib/wpa/src/rsn_supp/peerkey.c b/contrib/wpa/src/rsn_supp/peerkey.c
index f2bac34..79764d9 100644
--- a/contrib/wpa/src/rsn_supp/peerkey.c
+++ b/contrib/wpa/src/rsn_supp/peerkey.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, 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.
@@ -65,6 +65,7 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
{
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;
@@ -79,6 +80,7 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
(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 |
@@ -112,8 +114,8 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
"(mui %d error_type %d)", mui, error_type);
}
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, err->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
+ ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
return 0;
}
@@ -126,6 +128,7 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
{
size_t rlen;
struct wpa_eapol_key *reply;
+ struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *pos;
size_t kde_len;
u16 key_info;
@@ -140,6 +143,7 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
(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 |
@@ -164,8 +168,8 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ 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;
}
@@ -217,23 +221,17 @@ static int wpa_supplicant_process_smk_m2(
return -1;
}
- cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
- if (cipher & WPA_CIPHER_CCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
- cipher = WPA_CIPHER_CCMP;
- } else if (cipher & WPA_CIPHER_GCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
- cipher = WPA_CIPHER_GCMP;
- } else if (cipher & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
- cipher = WPA_CIPHER_TKIP;
- } else {
+ 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
@@ -246,11 +244,7 @@ static int wpa_supplicant_process_smk_m2(
os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
peerkey->rsnie_i_len = kde.rsn_ie_len;
peerkey->cipher = cipher;
-#ifdef CONFIG_IEEE80211W
- if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ peerkey->akmp = ie.key_mgmt;
if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -294,14 +288,14 @@ static int wpa_supplicant_process_smk_m2(
* @mac_p: Peer MAC address
* @inonce: Initiator Nonce
* @mac_i: Initiator MAC address
- * @use_sha256: Whether to use SHA256-based KDF
+ * @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 use_sha256)
+ int akmp)
{
char *title = "SMK Name";
const u8 *addr[5];
@@ -316,7 +310,7 @@ static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
addr[4] = mac_i;
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
else
#endif /* CONFIG_IEEE80211W */
@@ -377,7 +371,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
mbuf, mlen, NULL);
}
@@ -432,8 +426,9 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
- ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+ wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
+ peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
+ msg->key_mic);
}
@@ -496,17 +491,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
peerkey->rsnie_p_len = kde->rsn_ie_len;
os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
- cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
- if (cipher & WPA_CIPHER_CCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
- peerkey->cipher = WPA_CIPHER_CCMP;
- } else if (cipher & WPA_CIPHER_GCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
- peerkey->cipher = WPA_CIPHER_GCMP;
- } else if (cipher & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
- peerkey->cipher = WPA_CIPHER_TKIP;
- } else {
+ 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,
@@ -515,6 +502,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
/* TODO: abort negotiation */
return -1;
}
+ wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+ wpa_cipher_txt(cipher));
+ peerkey->cipher = cipher;
return 0;
}
@@ -527,7 +517,6 @@ static int wpa_supplicant_process_smk_m45(
struct wpa_peerkey *peerkey;
struct wpa_eapol_ie_parse kde;
u32 lifetime;
- struct os_time now;
if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
@@ -579,22 +568,20 @@ static int wpa_supplicant_process_smk_m45(
lifetime = WPA_GET_BE32(kde.lifetime);
wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
if (lifetime > 1000000000)
- lifetime = 1000000000; /* avoid overflowing expiration time */
+ lifetime = 1000000000; /* avoid overflowing eloop time */
peerkey->lifetime = lifetime;
- os_get_time(&now);
- peerkey->expiration = now.sec + lifetime;
eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
sm, peerkey);
if (peerkey->initiator) {
rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
peerkey->inonce, sm->own_addr, peerkey->smkid,
- peerkey->use_sha256);
+ 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->use_sha256);
+ peerkey->akmp);
}
wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
@@ -667,11 +654,11 @@ static int wpa_supplicant_process_smk_error(
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)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse ie;
- const u8 *kde;
- size_t len, kde_buf_len;
+ size_t kde_buf_len;
struct wpa_ptk *stk;
u8 buf[8], *kde_buf, *pos;
be32 lifetime;
@@ -682,14 +669,13 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
os_memset(&ie, 0, sizeof(ie));
/* RSN: msg 1/4 should contain SMKID for the selected SMK */
- kde = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
- if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
+ wpa_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(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ 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;
@@ -709,12 +695,11 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
sm->own_addr, peerkey->addr,
peerkey->pnonce, key->key_nonce,
- (u8 *) stk, sizeof(*stk),
- peerkey->use_sha256);
+ stk, peerkey->akmp, peerkey->cipher);
/* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
- os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
- os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+ 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 +
@@ -747,7 +732,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *kde)
{
u32 lifetime;
- struct os_time now;
if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
return;
@@ -766,8 +750,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
lifetime, peerkey->lifetime);
peerkey->lifetime = lifetime;
- os_get_time(&now);
- peerkey->expiration = now.sec + lifetime;
eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
sm, peerkey);
@@ -777,11 +759,10 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
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)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
- const u8 *keydata;
- size_t len;
wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
@@ -790,16 +771,14 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
* from the peer. It may also include Lifetime KDE. */
- keydata = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
- if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
+ 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(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ 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;
@@ -826,11 +805,11 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
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)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
- const u8 *keydata;
- size_t len, key_len;
+ size_t key_len;
const u8 *_key;
u8 key_buf[32], rsc[6];
@@ -841,10 +820,8 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
* Lifetime KDE. */
- keydata = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
- if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
+ wpa_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;
@@ -875,15 +852,15 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
WPA_GET_BE16(key->key_info),
- NULL, 0, &peerkey->stk))
+ &peerkey->stk))
return;
- _key = (u8 *) peerkey->stk.tk1;
+ _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, peerkey->stk.u.auth.rx_mic_key, 8);
- os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+ os_memcpy(key_buf + 16, _key + 24, 8);
+ os_memcpy(key_buf + 24, _key + 16, 8);
_key = key_buf;
key_len = 32;
} else
@@ -892,10 +869,12 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
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));
}
@@ -911,7 +890,7 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
os_memset(rsc, 0, 6);
if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
- rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+ 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.");
@@ -932,27 +911,27 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
*/
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key_192 *key, u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[16];
+ 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,
- (u8 *) &peerkey->stk, sizeof(peerkey->stk),
- peerkey->use_sha256);
+ &peerkey->stk, peerkey->akmp, peerkey->cipher);
peerkey->stk_set = 1;
}
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (peerkey->tstk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ 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 {
@@ -961,14 +940,15 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
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, 16);
- wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ 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;
@@ -1037,10 +1017,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
return -1;
peerkey->initiator = 1;
os_memcpy(peerkey->addr, peer, ETH_ALEN);
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(sm->key_mgmt))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ 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,
@@ -1107,8 +1084,8 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
MACSTR ")", MAC2STR(peer));
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, req->key_mic);
+ 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;
@@ -1127,28 +1104,32 @@ void peerkey_deinit(struct wpa_sm *sm)
while (peerkey) {
prev = peerkey;
peerkey = peerkey->next;
- os_free(prev);
+ 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)
+ 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);
+ 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);
+ 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);
+ wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver,
+ key_data, key_data_len);
}
}
diff --git a/contrib/wpa/src/rsn_supp/peerkey.h b/contrib/wpa/src/rsn_supp/peerkey.h
index b8845f7..6ccd948 100644
--- a/contrib/wpa/src/rsn_supp/peerkey.h
+++ b/contrib/wpa/src/rsn_supp/peerkey.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, 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.
@@ -24,11 +24,10 @@ struct wpa_peerkey {
int smk_complete;
u8 smkid[PMKID_LEN];
u32 lifetime;
- os_time_t expiration;
int cipher; /* Selected cipher (WPA_CIPHER_*) */
u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
int replay_counter_set;
- int use_sha256; /* whether AKMP indicate SHA256-based derivations */
+ int akmp;
struct wpa_ptk stk, tstk;
int stk_set, tstk_set;
@@ -39,10 +38,11 @@ struct wpa_peerkey {
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ 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);
+ 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);
@@ -61,7 +61,8 @@ peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
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)
+ struct wpa_eapol_key *key, u16 key_info, u16 ver,
+ const u8 *key_data, size_t key_data_len)
{
}
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.c b/contrib/wpa/src/rsn_supp/pmksa_cache.c
index df67583..ef7b683 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.c
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-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.
@@ -15,7 +15,7 @@
#include "wpa_i.h"
#include "pmksa_cache.h"
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
static const int pmksa_cache_max_entries = 32;
@@ -35,7 +35,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);
+ bin_clear_free(entry, sizeof(*entry));
}
@@ -53,9 +53,9 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
pmksa->pmksa = entry->next;
@@ -80,13 +80,13 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
{
int sec;
struct rsn_pmksa_cache_entry *entry;
- struct os_time now;
+ struct os_reltime now;
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
if (pmksa->pmksa == NULL)
return;
- os_get_time(&now);
+ os_get_reltime(&now);
sec = pmksa->pmksa->expiration - now.sec;
if (sec < 0)
sec = 0;
@@ -109,6 +109,8 @@ 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)
+ * @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
@@ -122,22 +124,31 @@ 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)
{
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
- struct os_time now;
+ struct os_reltime now;
if (pmk_len > PMK_LEN)
return NULL;
+ if (wpa_key_mgmt_suite_b(akmp) && !kck)
+ return NULL;
+
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
- os_get_time(&now);
+ 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));
+ os_get_reltime(&now);
entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
@@ -152,9 +163,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
while (pos) {
if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
if (pos->pmk_len == pmk_len &&
- os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
- os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
- 0) {
+ os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
+ os_memcmp_const(pos->pmkid, entry->pmkid,
+ PMKID_LEN) == 0) {
wpa_printf(MSG_DEBUG, "WPA: reusing previous "
"PMKSA entry");
os_free(entry);
@@ -164,17 +175,23 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
pmksa->pmksa = pos->next;
else
prev->next = pos->next;
- wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
- "the current AP");
- pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
/*
* If OKC is used, there may be other PMKSA cache
* entries based on the same PMK. These needs to be
* flushed so that a new entry can be created based on
- * the new PMK.
+ * the new PMK. Only clear other entries if they have a
+ * matching PMK and this PMK has been used successfully
+ * with the current AP, i.e., if opportunistic flag has
+ * been cleared in wpa_supplicant_key_neg_complete().
*/
- pmksa_cache_flush(pmksa, network_ctx);
+ wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+ "the current AP and any PMKSA cache entry "
+ "that was based on the old PMK");
+ if (!pos->opportunistic)
+ pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
+ pos->pmk_len);
+ pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
break;
}
prev = pos;
@@ -235,15 +252,22 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
+ * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk_len: PMK length
*/
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+ const u8 *pmk, size_t pmk_len)
{
struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
int removed = 0;
entry = pmksa->pmksa;
while (entry) {
- if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+ if ((entry->network_ctx == network_ctx ||
+ network_ctx == NULL) &&
+ (pmk == NULL ||
+ (pmk_len == entry->pmk_len &&
+ os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
"for " MACSTR, MAC2STR(entry->aa));
if (prev)
@@ -320,6 +344,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *new_entry;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+ NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp);
if (new_entry == NULL)
@@ -453,13 +478,13 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
int i, ret;
char *pos = buf;
struct rsn_pmksa_cache_entry *entry;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
ret = os_snprintf(pos, buf + len - pos,
"Index / AA / PMKID / expiration (in seconds) / "
"opportunistic\n");
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
i = 0;
@@ -468,7 +493,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
i++;
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
i, MAC2STR(entry->aa));
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
@@ -476,7 +501,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
(int) (entry->expiration - now.sec),
entry->opportunistic);
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
entry = entry->next;
@@ -509,4 +534,4 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
return pmksa;
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.h b/contrib/wpa/src/rsn_supp/pmksa_cache.h
index f318c52..f8e040e 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.h
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.h
@@ -44,7 +44,7 @@ enum pmksa_free_reason {
PMKSA_EXPIRE,
};
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -57,6 +57,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
@@ -66,13 +67,14 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
void *network_ctx, const u8 *aa);
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+ const u8 *pmk, size_t pmk_len);
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
static inline struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int reason),
+ void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm)
{
return (void *) -1;
@@ -103,6 +105,7 @@ static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
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)
{
return NULL;
@@ -121,10 +124,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
}
static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
- void *network_ctx)
+ void *network_ctx,
+ const u8 *pmk, size_t pmk_len)
{
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
#endif /* PMKSA_CACHE_H */
diff --git a/contrib/wpa/src/rsn_supp/preauth.c b/contrib/wpa/src/rsn_supp/preauth.c
index ab61867..c6534af 100644
--- a/contrib/wpa/src/rsn_supp/preauth.c
+++ b/contrib/wpa/src/rsn_supp/preauth.c
@@ -1,6 +1,6 @@
/*
* RSN pre-authentication (supplicant)
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,7 +18,7 @@
#include "wpa_i.h"
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
#define PMKID_CANDIDATE_PRIO_SCAN 1000
@@ -70,13 +70,14 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
}
-static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
+ enum eapol_supp_result result,
void *ctx)
{
struct wpa_sm *sm = ctx;
u8 pmk[PMK_LEN];
- if (success) {
+ if (result == EAPOL_SUPP_RESULT_SUCCESS) {
int res, pmk_len;
pmk_len = PMK_LEN;
res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
@@ -93,6 +94,7 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
pmk, pmk_len);
sm->pmk_len = pmk_len;
pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+ NULL, 0,
sm->preauth_bssid, sm->own_addr,
sm->network_ctx,
WPA_KEY_MGMT_IEEE8021X);
@@ -100,13 +102,14 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: failed to get master session key from "
"pre-auth EAPOL state machines");
- success = 0;
+ result = EAPOL_SUPP_RESULT_FAILURE;
}
}
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
MACSTR " %s", MAC2STR(sm->preauth_bssid),
- success ? "completed successfully" : "failed");
+ result == EAPOL_SUPP_RESULT_SUCCESS ? "completed successfully" :
+ "failed");
rsn_preauth_deinit(sm);
rsn_preauth_candidate_process(sm);
@@ -169,6 +172,7 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
{
struct eapol_config eapol_conf;
struct eapol_ctx *ctx;
+ int ret;
if (sm->preauth_eapol)
return -1;
@@ -194,14 +198,16 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
"packet processing (bridge) for "
"pre-authentication");
- return -2;
+ ret = -2;
+ goto fail;
}
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
- return -4;
+ ret = -4;
+ goto fail;
}
ctx->ctx = sm->ctx->ctx;
ctx->msg_ctx = sm->ctx->ctx;
@@ -219,7 +225,8 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
os_free(ctx);
wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
"state machines for pre-authentication");
- return -3;
+ ret = -3;
+ goto fail;
}
os_memset(&eapol_conf, 0, sizeof(eapol_conf));
eapol_conf.accept_802_1x_keys = 0;
@@ -244,6 +251,15 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
rsn_preauth_timeout, sm, NULL);
return 0;
+
+fail:
+ if (sm->l2_preauth_br) {
+ l2_packet_deinit(sm->l2_preauth_br);
+ sm->l2_preauth_br = NULL;
+ }
+ l2_packet_deinit(sm->l2_preauth);
+ sm->l2_preauth = NULL;
+ return ret;
}
@@ -296,7 +312,9 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
sm->proto != WPA_PROTO_RSN ||
wpa_sm_get_state(sm) != WPA_COMPLETED ||
(sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
@@ -389,6 +407,18 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
dl_list_for_each(pos, &sm->pmksa_candidates,
struct rsn_pmksa_candidate, list) {
if (cand->priority <= pos->priority) {
+ if (!pos->list.prev) {
+ /*
+ * This cannot really happen in pracrice since
+ * pos was fetched from the list and the prev
+ * pointer must be set. It looks like clang
+ * static analyzer gets confused with the
+ * dl_list_del(&cand->list) call above and ends
+ * up assuming pos->list.prev could be NULL.
+ */
+ os_free(cand);
+ return;
+ }
dl_list_add(pos->list.prev, &cand->list);
cand = NULL;
break;
@@ -485,7 +515,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
if (sm->preauth_eapol) {
ret = os_snprintf(pos, end - pos, "Pre-authentication "
"EAPOL state machines:\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
res = eapol_sm_get_status(sm->preauth_eapol,
@@ -508,4 +538,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm)
return sm->preauth_eapol != NULL;
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa/src/rsn_supp/preauth.h b/contrib/wpa/src/rsn_supp/preauth.h
index 27d3112c..277f066 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;
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
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 and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
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 and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
#endif /* PREAUTH_H */
diff --git a/contrib/wpa/src/rsn_supp/tdls.c b/contrib/wpa/src/rsn_supp/tdls.c
index 7646ca8..c1d7749 100644
--- a/contrib/wpa/src/rsn_supp/tdls.c
+++ b/contrib/wpa/src/rsn_supp/tdls.c
@@ -33,12 +33,15 @@
#define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8)
#define TDLS_TESTING_DECLINE_RESP BIT(9)
#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10)
+#define TDLS_TESTING_WRONG_MIC BIT(11)
unsigned int tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
#define TPK_LIFETIME 43200 /* 12 hours */
-#define TPK_RETRY_COUNT 3
-#define TPK_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M1_RETRY_COUNT 3
+#define TPK_M1_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M2_RETRY_COUNT 10
+#define TPK_M2_TIMEOUT 500 /* in milliseconds */
#define TDLS_MIC_LEN 16
@@ -79,6 +82,10 @@ struct wpa_tdls_frame {
static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer);
+static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr,
+ u16 reason_code);
#define TDLS_MAX_IE_LEN 80
@@ -86,6 +93,7 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
struct wpa_tdls_peer {
struct wpa_tdls_peer *next;
+ unsigned int reconfig_key:1;
int initiator; /* whether this end was initiator for TDLS setup */
u8 addr[ETH_ALEN]; /* other end MAC address */
u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
@@ -104,6 +112,7 @@ struct wpa_tdls_peer {
} tpk;
int tpk_set;
int tpk_success;
+ int tpk_in_progress;
struct tpk_timer {
u8 dest[ETH_ALEN];
@@ -112,6 +121,7 @@ struct wpa_tdls_peer {
u8 action_code; /* TDLS frame type */
u8 dialog_token;
u16 status_code;
+ u32 peer_capab;
int buf_len; /* length of TPK message for retransmission */
u8 *buf; /* buffer for TPK message */
} sm_tmr;
@@ -120,6 +130,27 @@ struct wpa_tdls_peer {
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
+
+ struct ieee80211_ht_capabilities *ht_capabilities;
+ struct ieee80211_vht_capabilities *vht_capabilities;
+
+ u8 qos_info;
+
+ u16 aid;
+
+ u8 *ext_capab;
+ size_t ext_capab_len;
+
+ u8 *supp_channels;
+ size_t supp_channels_len;
+
+ u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+
+ u8 wmm_capable;
+
+ /* channel switch currently enabled */
+ int chan_switch_enabled;
};
@@ -189,26 +220,30 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf, size_t len)
+ u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf, size_t len)
{
return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token,
- status_code, buf, len);
+ status_code, peer_capab, initiator, buf,
+ len);
}
static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
- u8 dialog_token, u16 status_code,
- const u8 *msg, size_t msg_len)
+ u8 dialog_token, u16 status_code, u32 peer_capab,
+ int initiator, const u8 *msg, size_t msg_len)
{
struct wpa_tdls_peer *peer;
wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u "
- "dialog_token=%u status_code=%u msg_len=%u",
+ "dialog_token=%u status_code=%u peer_capab=%u initiator=%d "
+ "msg_len=%u",
MAC2STR(dest), action_code, dialog_token, status_code,
- (unsigned int) msg_len);
+ peer_capab, initiator, (unsigned int) msg_len);
if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token,
- status_code, msg, msg_len)) {
+ status_code, peer_capab, initiator, msg,
+ msg_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to send message "
"(action_code=%u)", action_code);
return -1;
@@ -233,14 +268,20 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- peer->sm_tmr.count = TPK_RETRY_COUNT;
- peer->sm_tmr.timer = TPK_TIMEOUT;
+ if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+ peer->sm_tmr.count = TPK_M2_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M2_TIMEOUT;
+ } else {
+ peer->sm_tmr.count = TPK_M1_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M1_TIMEOUT;
+ }
/* Copy message to resend on timeout */
os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
peer->sm_tmr.action_code = action_code;
peer->sm_tmr.dialog_token = dialog_token;
peer->sm_tmr.status_code = status_code;
+ peer->sm_tmr.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);
@@ -250,28 +291,21 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
"(action_code=%u)", action_code);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
return 0;
}
static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
- u16 reason_code, int free_peer)
+ u16 reason_code)
{
int ret;
- if (sm->tdls_external_setup) {
- ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
-
- /* disable the link after teardown was sent */
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
- } else {
- ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
- }
-
- if (sm->tdls_external_setup || free_peer)
- wpa_tdls_peer_free(sm, peer);
+ ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+ /* disable the link after teardown was sent */
+ wpa_tdls_disable_peer_link(sm, peer);
return ret;
}
@@ -285,7 +319,6 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
if (peer->sm_tmr.count) {
peer->sm_tmr.count--;
- peer->sm_tmr.timer = TPK_TIMEOUT;
wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
"(action_code=%u)",
@@ -305,6 +338,8 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
peer->sm_tmr.action_code,
peer->sm_tmr.dialog_token,
peer->sm_tmr.status_code,
+ peer->sm_tmr.peer_capab,
+ peer->initiator,
peer->sm_tmr.buf,
peer->sm_tmr.buf_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to retry "
@@ -312,14 +347,15 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
}
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
} else {
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
wpa_tdls_do_teardown(sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
}
@@ -535,7 +571,7 @@ static int wpa_supplicant_verify_tdls_mic(u8 trans_seq,
wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid,
peer->rsnie_p, timeoutie, (u8 *) ftie,
mic);
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - "
"dropping packet");
wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC",
@@ -562,7 +598,7 @@ static int wpa_supplicant_verify_tdls_mic_teardown(
if (peer->tpk_set) {
wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode,
dtoken, lnkid, (u8 *) ftie, mic);
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - "
"dropping packet");
return -1;
@@ -597,29 +633,78 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
" - tear down", MAC2STR(peer->addr));
wpa_tdls_do_teardown(sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
}
-static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer)
+{
+ struct wpa_tdls_peer *cur, *prev;
+
+ cur = sm->tdls;
+ prev = NULL;
+ while (cur && cur != peer) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur != peer) {
+ wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR
+ " to remove it from the list",
+ MAC2STR(peer->addr));
+ return;
+ }
+
+ if (prev)
+ prev->next = peer->next;
+ else
+ sm->tdls = peer->next;
+}
+
+
+static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR,
MAC2STR(peer->addr));
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+ peer->reconfig_key = 0;
peer->initiator = 0;
+ peer->tpk_in_progress = 0;
os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = NULL;
+ os_free(peer->ht_capabilities);
+ peer->ht_capabilities = NULL;
+ os_free(peer->vht_capabilities);
+ peer->vht_capabilities = NULL;
+ os_free(peer->ext_capab);
+ peer->ext_capab = NULL;
+ os_free(peer->supp_channels);
+ peer->supp_channels = NULL;
+ os_free(peer->supp_oper_classes);
+ peer->supp_oper_classes = NULL;
peer->rsnie_i_len = peer->rsnie_p_len = 0;
peer->cipher = 0;
+ peer->qos_info = 0;
+ peer->wmm_capable = 0;
peer->tpk_set = peer->tpk_success = 0;
+ peer->chan_switch_enabled = 0;
os_memset(&peer->tpk, 0, sizeof(peer->tpk));
os_memset(peer->inonce, 0, WPA_NONCE_LEN);
os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
}
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+ wpa_tdls_peer_clear(sm, peer);
+ wpa_tdls_peer_remove_from_list(sm, peer);
+ os_free(peer);
+}
+
+
static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
struct wpa_tdls_lnkid *lnkid)
{
@@ -636,7 +721,8 @@ static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
}
-int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr,
+ u16 reason_code)
{
struct wpa_tdls_peer *peer;
struct wpa_tdls_ftie *ftie;
@@ -660,6 +746,13 @@ int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
return 0;
}
+ /* Cancel active channel switch before teardown */
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR
+ " to base channel", MAC2STR(addr));
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+ }
+
dialog_token = peer->dtoken;
wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
@@ -715,13 +808,9 @@ skip_ies:
/* request driver to send Teardown using this FTIE */
wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf,
- pos - rbuf);
+ reason_code, 0, peer->initiator, rbuf, pos - rbuf);
os_free(rbuf);
- /* clear the Peerkey statemachine */
- wpa_tdls_peer_free(sm, peer);
-
return 0;
}
@@ -750,11 +839,19 @@ int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
return -1;
}
- return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+ return wpa_tdls_do_teardown(sm, peer, reason_code);
+}
+
+
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer)
+{
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_peer_free(sm, peer);
}
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
@@ -763,13 +860,52 @@ void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
break;
}
- if (peer) {
+ if (!peer || !peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " not connected - cannot teardown unreachable link",
+ MAC2STR(addr));
+ return;
+ }
+
+ if (wpa_tdls_is_external_setup(sm)) {
+ /*
+ * Get us on the base channel, disable the link, send a
+ * teardown packet through the AP, and then reset link data.
+ */
+ if (peer->chan_switch_enabled)
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+ wpa_tdls_send_teardown(sm, addr,
+ WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
wpa_tdls_peer_free(sm, peer);
+ } else {
+ wpa_tdls_disable_peer_link(sm, peer);
}
}
+const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return "disabled";
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer == NULL)
+ return "peer does not exist";
+
+ if (!peer->tpk_success)
+ return "peer not connected";
+
+ return "connected";
+}
+
+
static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -803,10 +939,15 @@ static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
" (reason code %u)", MAC2STR(src_addr), reason_code);
ielen = len - (pos - buf); /* start of IE in buf */
- if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown");
- return -1;
- }
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs may add arbitrary padding to the
+ * end of short TDLS frames and that would look like invalid IEs.
+ */
+ if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0)
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in Teardown - ignore as an interop workaround");
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS "
@@ -839,11 +980,7 @@ skip_ftie:
* Request the driver to disable the direct link and clear associated
* keys.
*/
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-
- /* clear the Peerkey statemachine */
- wpa_tdls_peer_free(sm, peer);
-
+ wpa_tdls_disable_peer_link(sm, peer);
return 0;
}
@@ -853,25 +990,37 @@ skip_ftie:
* appropriate status code mentioning reason for error/failure.
* @dst - MAC addr of Peer station
* @tdls_action - TDLS frame type for which error code is sent
+ * @initiator - was this end the initiator of the connection
* @status - status code mentioning reason
*/
static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
- u8 tdls_action, u8 dialog_token, u16 status)
+ u8 tdls_action, u8 dialog_token, int initiator,
+ u16 status)
{
wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR
" (action=%u status=%u)",
MAC2STR(dst), tdls_action, status);
return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
- NULL, 0);
+ 0, initiator, NULL, 0);
}
static struct wpa_tdls_peer *
-wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing)
{
struct wpa_tdls_peer *peer;
+ if (existing)
+ *existing = 0;
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) {
+ if (existing)
+ *existing = 1;
+ return peer; /* re-use existing entry */
+ }
+ }
+
wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
MAC2STR(addr));
@@ -897,6 +1046,7 @@ static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
u8 *rbuf, *pos, *count_pos;
u16 count;
struct rsn_ie_hdr *hdr;
+ int status;
if (!wpa_tdls_get_privacy(sm)) {
wpa_printf(MSG_DEBUG, "TDLS: No security used on the link");
@@ -1057,11 +1207,11 @@ skip_ies:
"Handshake Message 1 (peer " MACSTR ")",
MAC2STR(peer->addr));
- wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
- rbuf, pos - rbuf);
+ status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST,
+ 1, 0, 0, peer->initiator, rbuf, pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1075,6 +1225,7 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
u32 lifetime;
struct wpa_tdls_timeoutie timeoutie;
struct wpa_tdls_ftie *ftie;
+ int status;
buf_len = 0;
if (wpa_tdls_get_privacy(sm)) {
@@ -1138,13 +1289,20 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
/* compute MIC before sending */
wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_WRONG_MIC) {
+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC");
+ ftie->mic[0] ^= 0x01;
+ }
+#endif /* CONFIG_TDLS_TESTING */
skip_ies:
- wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
- rbuf, pos - rbuf);
+ status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
+ dtoken, 0, 0, peer->initiator, rbuf,
+ pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1158,6 +1316,8 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
struct wpa_tdls_ftie *ftie;
struct wpa_tdls_timeoutie timeoutie;
u32 lifetime;
+ int status;
+ u32 peer_capab = 0;
buf_len = 0;
if (wpa_tdls_get_privacy(sm)) {
@@ -1219,13 +1379,28 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
/* compute MIC before sending */
wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_WRONG_MIC) {
+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC");
+ ftie->mic[0] ^= 0x01;
+ }
+#endif /* CONFIG_TDLS_TESTING */
skip_ies:
- wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0,
- rbuf, pos - rbuf);
+
+ if (peer->vht_capabilities)
+ peer_capab |= TDLS_PEER_VHT;
+ if (peer->ht_capabilities)
+ peer_capab |= TDLS_PEER_HT;
+ if (peer->wmm_capable)
+ peer_capab |= TDLS_PEER_WMM;
+
+ status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
+ dtoken, 0, peer_capab, peer->initiator,
+ rbuf, pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1233,11 +1408,85 @@ static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
struct wpa_tdls_peer *peer,
u8 dialog_token)
{
+ size_t buf_len = 0;
+ struct wpa_tdls_timeoutie timeoutie;
+ u16 rsn_capab;
+ u8 *rbuf, *pos, *count_pos;
+ u16 count;
+ struct rsn_ie_hdr *hdr;
+ int status;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
"(peer " MACSTR ")", MAC2STR(peer->addr));
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_rsn_ies;
+
+ /* Filling RSN IE */
+ hdr = (struct rsn_ie_hdr *) peer->rsnie_i;
+ hdr->elem_id = WLAN_EID_RSN;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ pos += RSN_SELECTOR_LEN;
+ count_pos = pos;
+ pos += 2;
+ count = 0;
- return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
- dialog_token, 0, NULL, 0);
+ /*
+ * AES-CCMP is the default encryption preferred for TDLS, so
+ * RSN IE is filled only with CCMP cipher suite.
+ * Note: TKIP is not used to encrypt TDLS link.
+ *
+ * Regardless of the cipher used on the AP connection, select CCMP
+ * here.
+ */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ pos += RSN_SELECTOR_LEN;
+ count++;
+ WPA_PUT_LE16(count_pos, count);
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+ pos += RSN_SELECTOR_LEN;
+
+ rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+ rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+ WPA_PUT_LE16(pos, rsn_capab);
+ pos += 2;
+ hdr->len = (pos - (u8 *) hdr) - 2;
+ peer->rsnie_i_len = pos - peer->rsnie_i;
+
+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for Discovery Response",
+ (u8 *) hdr, hdr->len + 2);
+skip_rsn_ies:
+ buf_len = 0;
+ if (wpa_tdls_get_privacy(sm)) {
+ /* Peer RSN IE, Lifetime */
+ buf_len += peer->rsnie_i_len +
+ sizeof(struct wpa_tdls_timeoutie);
+ }
+ rbuf = os_zalloc(buf_len + 1);
+ if (rbuf == NULL) {
+ wpa_tdls_peer_free(sm, peer);
+ return -1;
+ }
+ pos = rbuf;
+
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_ies;
+ /* Initiator RSN IE */
+ pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
+ /* Lifetime */
+ peer->lifetime = TPK_LIFETIME;
+ pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+ sizeof(timeoutie), peer->lifetime);
+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
+skip_ies:
+ status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+ dialog_token, 0, 0, 0, rbuf, pos - rbuf);
+ os_free(rbuf);
+
+ return status;
}
@@ -1263,10 +1512,17 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+ /*
+ * Some APs will tack on a weird IE to the end of a TDLS
+ * discovery request packet. This needn't fail the response,
+ * since the required IE are verified separately.
+ */
if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
len - (sizeof(struct wpa_tdls_frame) + 1),
- &kde) < 0)
- return -1;
+ &kde) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in Discovery Request - ignore as an interop workaround");
+ }
if (!kde.lnkid) {
wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
@@ -1282,7 +1538,7 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
return -1;
}
- peer = wpa_tdls_add_peer(sm, addr);
+ peer = wpa_tdls_add_peer(sm, addr, NULL);
if (peer == NULL)
return -1;
@@ -1298,7 +1554,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
MACSTR, MAC2STR(addr));
return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
- 1, 0, NULL, 0);
+ 1, 0, 0, 1, NULL, 0);
}
@@ -1309,25 +1565,189 @@ static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
return -1;
}
+ peer->supp_rates_len = merge_byte_arrays(
+ peer->supp_rates, sizeof(peer->supp_rates),
+ kde->supp_rates + 2, kde->supp_rates_len - 2,
+ kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
+ kde->ext_supp_rates_len - 2);
+ return 0;
+}
+
+
+static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ht_capabilities ||
+ kde->ht_capabilities_len <
+ sizeof(struct ieee80211_ht_capabilities) ) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->ht_capabilities) {
+ peer->ht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+ if (peer->ht_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->ht_capabilities, kde->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities",
+ (u8 *) peer->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+
+ return 0;
+}
+
+
+static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->vht_capabilities ||
+ kde->vht_capabilities_len <
+ sizeof(struct ieee80211_vht_capabilities) ) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->vht_capabilities) {
+ peer->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (peer->vht_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->vht_capabilities, kde->vht_capabilities,
+ sizeof(struct ieee80211_vht_capabilities));
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer VHT capabilities",
+ (u8 *) peer->vht_capabilities,
+ sizeof(struct ieee80211_vht_capabilities));
+
+ return 0;
+}
- peer->supp_rates_len = kde->supp_rates_len - 2;
- if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
- peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
- os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
- if (kde->ext_supp_rates) {
- int clen = kde->ext_supp_rates_len - 2;
- if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
- clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
- os_memcpy(peer->supp_rates + peer->supp_rates_len,
- kde->ext_supp_rates + 2, clen);
- peer->supp_rates_len += clen;
+static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ext_capab) {
+ wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) {
+ /* Need to allocate buffer to fit the new information */
+ os_free(peer->ext_capab);
+ peer->ext_capab = os_zalloc(kde->ext_capab_len - 2);
+ if (peer->ext_capab == NULL)
+ return -1;
}
+ peer->ext_capab_len = kde->ext_capab_len - 2;
+ os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len);
+
return 0;
}
+static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ struct wmm_information_element *wmm;
+
+ if (!kde->wmm) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported WMM capabilities received");
+ return 0;
+ }
+
+ if (kde->wmm_len < sizeof(struct wmm_information_element)) {
+ wpa_printf(MSG_DEBUG, "TDLS: Invalid supported WMM capabilities received");
+ return -1;
+ }
+
+ wmm = (struct wmm_information_element *) kde->wmm;
+ peer->qos_info = wmm->qos_info;
+
+ peer->wmm_capable = 1;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info);
+ return 0;
+}
+
+
+static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->supp_channels) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported channels received");
+ return 0;
+ }
+
+ if (!peer->supp_channels ||
+ peer->supp_channels_len < kde->supp_channels_len) {
+ os_free(peer->supp_channels);
+ peer->supp_channels = os_zalloc(kde->supp_channels_len);
+ if (peer->supp_channels == NULL)
+ return -1;
+ }
+
+ peer->supp_channels_len = kde->supp_channels_len;
+
+ os_memcpy(peer->supp_channels, kde->supp_channels,
+ peer->supp_channels_len);
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels",
+ (u8 *) peer->supp_channels, peer->supp_channels_len);
+ return 0;
+}
+
+
+static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->supp_oper_classes) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received");
+ return 0;
+ }
+
+ if (!peer->supp_oper_classes ||
+ peer->supp_oper_classes_len < kde->supp_oper_classes_len) {
+ os_free(peer->supp_oper_classes);
+ peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len);
+ if (peer->supp_oper_classes == NULL)
+ return -1;
+ }
+
+ peer->supp_oper_classes_len = kde->supp_oper_classes_len;
+ os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes,
+ peer->supp_oper_classes_len);
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes",
+ (u8 *) peer->supp_oper_classes,
+ peer->supp_oper_classes_len);
+ return 0;
+}
+
+
+static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+ int add)
+{
+ return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid,
+ peer->capability,
+ peer->supp_rates, peer->supp_rates_len,
+ peer->ht_capabilities,
+ peer->vht_capabilities,
+ peer->qos_info, peer->wmm_capable,
+ peer->ext_capab, peer->ext_capab_len,
+ peer->supp_channels,
+ peer->supp_channels_len,
+ peer->supp_oper_classes,
+ peer->supp_oper_classes_len);
+}
+
+
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1363,17 +1783,44 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
- existing_peer = 1;
- break;
- }
- }
+ peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer);
+ if (peer == NULL)
+ goto error;
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, src_addr);
- if (peer == NULL)
- goto error;
+ /* If found, use existing entry instead of adding a new one;
+ * how to handle the case where both ends initiate at the
+ * same time? */
+ if (existing_peer) {
+ if (peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
+ "direct link is enabled - tear down the "
+ "old link first");
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
+ } else if (peer->initiator) {
+ /*
+ * An entry is already present, so check if we already
+ * sent a TDLS Setup Request. If so, compare MAC
+ * addresses and let the STA with the lower MAC address
+ * continue as the initiator. The other negotiation is
+ * terminated.
+ */
+ if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Discard request "
+ "from peer with higher address "
+ MACSTR, MAC2STR(src_addr));
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "TDLS: Accept request "
+ "from peer with lower address "
+ MACSTR " (terminate previously "
+ "initiated negotiation",
+ MAC2STR(src_addr));
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+ peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
+ }
+ }
}
/* capability information */
@@ -1381,10 +1828,15 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
cpos += 2;
ielen = len - (cpos - buf); /* start of IE in buf */
- if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1");
- goto error;
- }
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs may add arbitrary padding to the
+ * end of short TDLS frames and that would look like invalid IEs.
+ */
+ if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0)
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in TPK M1 - ignore as an interop workaround");
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
@@ -1396,7 +1848,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
- status = WLAN_STATUS_NOT_IN_SAME_BSS;
+ status = WLAN_STATUS_REQUEST_DECLINED;
goto error;
}
@@ -1406,20 +1858,39 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_vht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_channels(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
+ /* Overwrite with the qos_info obtained in WMM IE */
+ if (copy_peer_wmm_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->aid = kde.aid;
+
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
- break;
- }
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, src_addr);
- if (peer == NULL)
- goto error;
- }
+ peer = wpa_tdls_add_peer(sm, src_addr, NULL);
+ if (peer == NULL)
+ goto error;
wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
"TDLS setup - send own request");
peer->initiator = 1;
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0);
wpa_tdls_send_tpk_m1(sm, peer);
}
@@ -1502,52 +1973,6 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
}
skip_rsn:
- /* If found, use existing entry instead of adding a new one;
- * how to handle the case where both ends initiate at the
- * same time? */
- if (existing_peer) {
- if (peer->tpk_success) {
- wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
- "direct link is enabled - tear down the "
- "old link first");
-#if 0
- /* TODO: Disabling the link would be more proper
- * operation here, but it seems to trigger a race with
- * some drivers handling the new request frame. */
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-#else
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
- src_addr);
- else
- wpa_tdls_del_key(sm, peer);
-#endif
- wpa_tdls_peer_free(sm, peer);
- }
-
- /*
- * An entry is already present, so check if we already sent a
- * TDLS Setup Request. If so, compare MAC addresses and let the
- * STA with the lower MAC address continue as the initiator.
- * The other negotiation is terminated.
- */
- if (peer->initiator) {
- if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
- wpa_printf(MSG_DEBUG, "TDLS: Discard request "
- "from peer with higher address "
- MACSTR, MAC2STR(src_addr));
- return -1;
- } else {
- wpa_printf(MSG_DEBUG, "TDLS: Accept request "
- "from peer with lower address "
- MACSTR " (terminate previously "
- "initiated negotiation",
- MAC2STR(src_addr));
- wpa_tdls_peer_free(sm, peer);
- }
- }
- }
-
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
@@ -1572,16 +1997,26 @@ skip_rsn:
}
ftie = (struct wpa_tdls_ftie *) kde.ftie;
- os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
peer->rsnie_i_len = kde.rsn_ie_len;
peer->cipher = cipher;
- if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->ctx, MSG_WARNING,
- "TDLS: Failed to get random data for responder nonce");
- wpa_tdls_peer_free(sm, peer);
- goto error;
+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
+ /*
+ * There is no point in updating the RNonce for every obtained
+ * TPK M1 frame (e.g., retransmission due to timeout) with the
+ * same INonce (SNonce in FTIE). However, if the TPK M1 is
+ * retransmitted with a different INonce, update the RNonce
+ * since this is for a new TDLS session.
+ */
+ wpa_printf(MSG_DEBUG,
+ "TDLS: New TPK M1 INonce - generate new RNonce");
+ os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
+ if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "TDLS: Failed to get random data for responder nonce");
+ goto error;
+ }
}
#if 0
@@ -1634,27 +2069,41 @@ skip_rsn:
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
skip_rsn_check:
- /* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT)
+ goto skip_add_peer;
+#endif /* CONFIG_TDLS_TESTING */
+
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 1) < 0)
+ goto error;
+
+#ifdef CONFIG_TDLS_TESTING
+skip_add_peer:
+#endif /* CONFIG_TDLS_TESTING */
+ peer->tpk_in_progress = 1;
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
- wpa_tdls_disable_link(sm, peer->addr);
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
goto error;
}
return 0;
error:
- wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken,
+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
status);
+ if (peer)
+ wpa_tdls_peer_free(sm, peer);
return -1;
}
-static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
peer->tpk_success = 1;
+ peer->tpk_in_progress = 0;
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
if (wpa_tdls_get_privacy(sm)) {
u32 lifetime = peer->lifetime;
@@ -1675,11 +2124,14 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
#endif /* CONFIG_TDLS_TESTING */
}
- /* add supported rates and capabilities to the TDLS peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
- peer->supp_rates, peer->supp_rates_len);
+ if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
+ wpa_printf(MSG_INFO, "TDLS: Could not configure key to the "
+ "driver");
+ return -1;
+ }
+ peer->reconfig_key = 0;
- wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
+ return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
}
@@ -1698,6 +2150,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
int ielen;
u16 status;
const u8 *pos;
+ int ret = 0;
wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
"(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -1710,10 +2163,23 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
"TPK M2: " MACSTR, MAC2STR(src_addr));
return -1;
}
+ if (!peer->initiator) {
+ /*
+ * This may happen if both devices try to initiate TDLS at the
+ * same time and we accept the TPK M1 from the peer in
+ * wpa_tdls_process_tpk_m1() and clear our previous state.
+ */
+ wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so "
+ "ignore TPK M2 from " MACSTR, MAC2STR(src_addr));
+ return -1;
+ }
wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
- if (len < 3 + 2 + 1)
+ if (len < 3 + 2 + 1) {
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
+ }
+
pos = buf;
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
status = WPA_GET_LE16(pos);
@@ -1722,8 +2188,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -1734,18 +2199,25 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken);
- if (len < 3 + 2 + 1 + 2)
+ if (len < 3 + 2 + 1 + 2) {
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
+ }
/* capability information */
peer->capability = WPA_GET_LE16(pos);
pos += 2;
ielen = len - (pos - buf); /* start of IE in buf */
- if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2");
- goto error;
- }
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs may add arbitrary padding to the
+ * end of short TDLS frames and that would look like invalid IEs.
+ */
+ if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0)
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in TPK M2 - ignore as an interop workaround");
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_DECLINE_RESP) {
@@ -1773,6 +2245,29 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_vht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_channels(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
+ /* Overwrite with the qos_info obtained in WMM IE */
+ if (copy_peer_wmm_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->aid = kde.aid;
+
if (!wpa_tdls_get_privacy(sm)) {
peer->rsnie_p_len = 0;
peer->cipher = WPA_CIPHER_NONE;
@@ -1788,6 +2283,13 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
kde.rsn_ie, kde.rsn_ie_len);
+ if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
+ wpa_printf(MSG_INFO,
+ "TDLS: Too long Responder RSN IE in TPK M2");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto error;
+ }
+
/*
* FIX: bitwise comparison of RSN IE is not the correct way of
* validation this. It can be different, but certain fields must
@@ -1863,30 +2365,52 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
(u8 *) timeoutie, ftie) < 0) {
/* Discard the frame */
wpa_tdls_del_key(sm, peer);
- wpa_tdls_peer_free(sm, peer);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
- wpa_tdls_set_key(sm, peer);
+ if (wpa_tdls_set_key(sm, peer) < 0) {
+ /*
+ * Some drivers may not be able to config the key prior to full
+ * STA entry having been configured.
+ */
+ wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+ "STA entry is complete");
+ peer->reconfig_key = 1;
+ }
skip_rsn:
peer->dtoken = dtoken;
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
"TPK Handshake Message 3");
- wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
-
- wpa_tdls_enable_link(sm, peer);
+ if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0)
+ goto error;
- return 0;
+ if (!peer->tpk_success) {
+ /*
+ * Enable Link only when tpk_success is 0, signifying that this
+ * processing of TPK M2 frame is not because of a retransmission
+ * during TDLS setup handshake.
+ */
+ ret = wpa_tdls_enable_link(sm, peer);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+ wpa_tdls_do_teardown(
+ sm, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ }
+ }
+ return ret;
error:
- wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1,
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -1903,6 +2427,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
u16 status;
const u8 *pos;
u32 lifetime;
+ int ret = 0;
wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
"(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -1918,7 +2443,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
if (len < 3 + 3)
- return -1;
+ goto error;
pos = buf;
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
@@ -1927,21 +2452,26 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (status != 0) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
- return -1;
+ goto error;
}
pos += 2 /* status code */ + 1 /* dialog token */;
ielen = len - (pos - buf); /* start of IE in buf */
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs piggy-back broken IEs to the end
+ * of a TDLS Confirm packet, which will fail the link if we don't ignore
+ * this error.
+ */
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
- return -1;
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse KDEs in TPK M3 - ignore as an interop workaround");
}
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
(u8 *) kde.lnkid, kde.lnkid_len);
@@ -1949,7 +2479,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS");
- return -1;
+ goto error;
}
if (!wpa_tdls_get_privacy(sm))
@@ -1957,7 +2487,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
kde.ftie, sizeof(*ftie));
@@ -1965,7 +2495,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (kde.rsn_ie == NULL) {
wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3",
kde.rsn_ie, kde.rsn_ie_len);
@@ -1973,24 +2503,24 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) {
wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match "
"with the one sent in TPK M2");
- return -1;
+ goto error;
}
if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does "
"not match with FTIE ANonce used in TPK M2");
- return -1;
+ goto error;
}
if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not "
"match with FTIE SNonce used in TPK M1");
- return -1;
+ goto error;
}
if (kde.key_lifetime == NULL) {
wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3");
- return -1;
+ goto error;
}
timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3",
@@ -2001,25 +2531,46 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (lifetime != peer->lifetime) {
wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
"TPK M3 (expected %u)", lifetime, peer->lifetime);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
- return -1;
+ goto error;
}
if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid,
(u8 *) timeoutie, ftie) < 0) {
wpa_tdls_del_key(sm, peer);
- wpa_tdls_peer_free(sm, peer);
- return -1;
+ goto error;
}
- if (wpa_tdls_set_key(sm, peer) < 0)
- return -1;
+ if (wpa_tdls_set_key(sm, peer) < 0) {
+ /*
+ * Some drivers may not be able to config the key prior to full
+ * STA entry having been configured.
+ */
+ wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+ "STA entry is complete");
+ peer->reconfig_key = 1;
+ }
skip_rsn:
- wpa_tdls_enable_link(sm, peer);
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
- return 0;
+ if (!peer->tpk_success) {
+ /*
+ * Enable Link only when tpk_success is 0, signifying that this
+ * processing of TPK M3 frame is not because of a retransmission
+ * during TDLS setup handshake.
+ */
+ ret = wpa_tdls_enable_link(sm, peer);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+ goto error;
+ }
+ }
+ return ret;
+error:
+ wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ return -1;
}
@@ -2069,26 +2620,28 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
return -1;
}
- /* Find existing entry and if found, use that instead of adding
- * a new one */
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
- break;
- }
+ peer = wpa_tdls_add_peer(sm, addr, NULL);
+ if (peer == NULL)
+ return -1;
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, addr);
- if (peer == NULL)
- return -1;
+ if (peer->tpk_in_progress) {
+ wpa_printf(MSG_DEBUG, "TDLS: Setup is already in progress with the peer");
+ return 0;
}
peer->initiator = 1;
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+ if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) {
+ wpa_tdls_disable_peer_link(sm, peer);
+ return -1;
+ }
+
+ peer->tpk_in_progress = 1;
if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
- wpa_tdls_disable_link(sm, peer->addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -2096,12 +2649,12 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
}
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
if (sm->tdls_disabled || !sm->tdls_supported)
- return -1;
+ return;
for (peer = sm->tdls; peer; peer = peer->next) {
if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
@@ -2109,17 +2662,16 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
}
if (peer == NULL || !peer->tpk_success)
- return -1;
+ return;
if (sm->tdls_external_setup) {
/*
* Disable previous link to allow renegotiation to be completed
* on AP path.
*/
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_do_teardown(sm, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
-
- return wpa_tdls_start(sm, addr);
}
@@ -2218,7 +2770,8 @@ int wpa_tdls_init(struct wpa_sm *sm)
* are assumed to perform everything internally
*/
if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
- &sm->tdls_external_setup) < 0) {
+ &sm->tdls_external_setup,
+ &sm->tdls_chan_switch) < 0) {
sm->tdls_supported = 1;
sm->tdls_external_setup = 0;
}
@@ -2227,17 +2780,43 @@ int wpa_tdls_init(struct wpa_sm *sm)
"driver", sm->tdls_supported ? "" : " not");
wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
sm->tdls_external_setup ? "external" : "internal");
+ wpa_printf(MSG_DEBUG, "TDLS: Driver %s TDLS channel switching",
+ sm->tdls_chan_switch ? "supports" : "does not support");
return 0;
}
+void wpa_tdls_teardown_peers(struct wpa_sm *sm)
+{
+ struct wpa_tdls_peer *peer, *tmp;
+
+ if (!sm)
+ return;
+ peer = sm->tdls;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
+
+ while (peer) {
+ tmp = peer->next;
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
+ MAC2STR(peer->addr));
+ if (sm->tdls_external_setup)
+ wpa_tdls_do_teardown(sm, peer,
+ WLAN_REASON_DEAUTH_LEAVING);
+ else
+ wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+
+ peer = tmp;
+ }
+}
+
+
static void wpa_tdls_remove_peers(struct wpa_sm *sm)
{
struct wpa_tdls_peer *peer, *tmp;
peer = sm->tdls;
- sm->tdls = NULL;
while (peer) {
int res;
@@ -2246,7 +2825,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm)
wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)",
MAC2STR(peer->addr), res);
wpa_tdls_peer_free(sm, peer);
- os_free(peer);
peer = tmp;
}
}
@@ -2285,39 +2863,61 @@ void wpa_tdls_disassoc(struct wpa_sm *sm)
}
-static int wpa_tdls_prohibited(const u8 *ies, size_t len)
+static int wpa_tdls_prohibited(struct wpa_eapol_ie_parse *elems)
{
- struct wpa_eapol_ie_parse elems;
-
- if (ies == NULL)
- return 0;
+ /* bit 38 - TDLS Prohibited */
+ return !!(elems->ext_capab[2 + 4] & 0x40);
+}
- if (wpa_supplicant_parse_ies(ies, len, &elems) < 0)
- return 0;
- if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
- return 0;
-
- /* bit 38 - TDLS Prohibited */
- return !!(elems.ext_capab[2 + 4] & 0x40);
+static int wpa_tdls_chan_switch_prohibited(struct wpa_eapol_ie_parse *elems)
+{
+ /* bit 39 - TDLS Channel Switch Prohibited */
+ return !!(elems->ext_capab[2 + 4] & 0x80);
}
void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
{
- sm->tdls_prohibited = wpa_tdls_prohibited(ies, len);
+ struct wpa_eapol_ie_parse elems;
+
+ sm->tdls_prohibited = 0;
+ sm->tdls_chan_switch_prohibited = 0;
+
+ if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+ elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ return;
+
+ sm->tdls_prohibited = wpa_tdls_prohibited(&elems);
wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS",
sm->tdls_prohibited ? "prohibited" : "allowed");
+ sm->tdls_chan_switch_prohibited =
+ wpa_tdls_chan_switch_prohibited(&elems);
+ wpa_printf(MSG_DEBUG, "TDLS: TDLS channel switch %s in the target BSS",
+ sm->tdls_chan_switch_prohibited ? "prohibited" : "allowed");
}
void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
{
- if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) {
+ struct wpa_eapol_ie_parse elems;
+
+ if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+ elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ return;
+
+ if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) {
wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on "
"(Re)Association Response IEs");
sm->tdls_prohibited = 1;
}
+
+ if (!sm->tdls_chan_switch_prohibited &&
+ wpa_tdls_chan_switch_prohibited(&elems)) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: TDLS channel switch prohibited based on (Re)Association Response IEs");
+ sm->tdls_chan_switch_prohibited = 1;
+ }
}
@@ -2332,3 +2932,78 @@ int wpa_tdls_is_external_setup(struct wpa_sm *sm)
{
return sm->tdls_external_setup;
}
+
+
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ struct hostapd_freq_params *freq_params)
+{
+ struct wpa_tdls_peer *peer;
+ int ret;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ if (!sm->tdls_chan_switch) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching not supported by the driver");
+ return -1;
+ }
+
+ if (sm->tdls_chan_switch_prohibited) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel");
+ return -1;
+ }
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer == NULL || !peer->tpk_success) {
+ wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR
+ " not found for channel switching", MAC2STR(addr));
+ return -1;
+ }
+
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " already has channel switching enabled",
+ MAC2STR(addr));
+ return 0;
+ }
+
+ ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr,
+ oper_class, freq_params);
+ if (!ret)
+ peer->chan_switch_enabled = 1;
+
+ return ret;
+}
+
+
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!peer || !peer->chan_switch_enabled) {
+ wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for "
+ MACSTR, MAC2STR(addr));
+ return -1;
+ }
+
+ /* ignore the return value */
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+
+ peer->chan_switch_enabled = 0;
+ return 0;
+}
diff --git a/contrib/wpa/src/rsn_supp/wpa.c b/contrib/wpa/src/rsn_supp/wpa.c
index 9283aa79..127e246 100644
--- a/contrib/wpa/src/rsn_supp/wpa.c
+++ b/contrib/wpa/src/rsn_supp/wpa.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-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,7 @@
* 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
* @ver: Version field from Key Info
* @dest: Destination address for the frame
* @proto: Ethertype (usually ETH_P_EAPOL)
@@ -34,10 +35,12 @@
* @msg_len: Length of message
* @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
*/
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+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)
{
+ size_t mic_len = wpa_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
@@ -56,14 +59,15 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
}
}
if (key_mic &&
- wpa_eapol_key_mic(kck, ver, msg, msg_len, 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 MIC", ver);
+ "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+ ver, sm->key_mgmt);
goto out;
}
- wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
- wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
+ 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);
eapol_sm_notify_tx_eapol_key(sm->eapol);
@@ -84,12 +88,17 @@ out:
*/
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
{
- size_t rlen;
+ 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;
+ u8 bssid[ETH_ALEN], *rbuf, *key_mic;
- if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
+ if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(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))
ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@@ -102,12 +111,16 @@ 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);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ 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)
@@ -122,15 +135,39 @@ 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);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
+ if (!(key_info & WPA_KEY_INFO_MIC))
+ key_mic = NULL;
+ else
+ key_mic = reply192->key_mic; /* same offset in reply */
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Sending EAPOL-Key Request (error=%d "
"pairwise=%d ptk_set=%d len=%lu)",
error, pairwise, sm->ptk_set, (unsigned long) rlen);
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
- reply->key_mic : NULL);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
+}
+
+
+static void wpa_supplicant_key_mgmt_set_pmk(struct wpa_sm *sm)
+{
+#ifdef CONFIG_IEEE80211R
+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->xxkey, sm->xxkey_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set low order 256 bits of MSK for key management offload");
+ } else {
+#endif /* CONFIG_IEEE80211R */
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->pmk, sm->pmk_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set PMK for key management offload");
+#ifdef CONFIG_IEEE80211R
+ }
+#endif /* CONFIG_IEEE80211R */
}
@@ -158,7 +195,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (pmkid && sm->cur_pmksa &&
- os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+ os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
wpa_sm_set_pmk_from_pmksa(sm);
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
@@ -194,10 +231,13 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
+ wpa_supplicant_key_mgmt_set_pmk(sm);
if (sm->proto == WPA_PROTO_RSN &&
+ !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,
+ NULL, 0,
src_addr, sm->own_addr,
sm->network_ctx,
sm->key_mgmt);
@@ -231,7 +271,9 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
- !wpa_key_mgmt_ft(sm->key_mgmt)) {
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
+ {
/* Send EAPOL-Start to trigger full EAP authentication. */
u8 *buf;
size_t buflen;
@@ -273,9 +315,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
u8 *rsn_ie_buf = NULL;
if (wpa_ie == NULL) {
@@ -317,19 +360,23 @@ 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);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*reply) + wpa_ie_len,
+ NULL, hdrlen + wpa_ie_len,
&rlen, (void *) &reply);
if (rbuf == NULL) {
os_free(rsn_ie_buf);
return -1;
}
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ 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);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -338,47 +385,52 @@ 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);
- WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
- os_memcpy(reply + 1, wpa_ie, wpa_ie_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);
+ }
os_free(rsn_ie_buf);
os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
- return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
+ return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
- sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->key_mgmt));
- return 0;
+ 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);
}
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse ie;
struct wpa_ptk *ptk;
- u8 buf[8];
int res;
+ u8 *kde, *kde_buf = NULL;
+ size_t kde_len;
if (wpa_sm_get_network_ctx(sm) == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
@@ -392,20 +444,17 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
os_memset(&ie, 0, sizeof(ie));
-#ifndef CONFIG_NO_WPA2
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
/* RSN: msg 1/4 should contain PMKID for the selected PMK */
- const u8 *_buf = (const u8 *) (key + 1);
- size_t len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
- if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+ 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)
goto failed;
if (ie.pmkid) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
"Authenticator", ie.pmkid, PMKID_LEN);
}
}
-#endif /* CONFIG_NO_WPA2 */
res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
if (res == -2) {
@@ -431,21 +480,49 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
* been verified when processing message 3/4. */
ptk = &sm->tptk;
wpa_derive_ptk(sm, src_addr, key, ptk);
- /* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
- os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
- os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+ if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
+ u8 buf[8];
+ /* Supplicant: swap tx/rx Mic keys */
+ os_memcpy(buf, &ptk->tk[16], 8);
+ os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
+ os_memcpy(&ptk->tk[24], buf, 8);
+ os_memset(buf, 0, sizeof(buf));
+ }
sm->tptk_set = 1;
+ kde = sm->assoc_wpa_ie;
+ kde_len = sm->assoc_wpa_ie_len;
+
+#ifdef CONFIG_P2P
+ if (sm->p2p) {
+ kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
+ if (kde_buf) {
+ u8 *pos;
+ wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
+ "into EAPOL-Key 2/4");
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
+ }
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
- sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
- ptk))
+ kde, kde_len, ptk))
goto failed;
+ os_free(kde_buf);
os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
return;
failed:
+ os_free(kde_buf);
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -537,7 +614,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
key_rsc = null_rsc;
} else {
key_rsc = key->key_rsc;
@@ -545,7 +622,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
}
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
- (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sm->ptk.tk, keylen) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set PTK to the "
"driver (alg=%d keylen=%d bssid=" MACSTR ")",
@@ -553,6 +630,9 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
return -1;
}
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@@ -625,6 +705,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to the driver "
"(Group only)");
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return -1;
}
} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
@@ -634,8 +715,10 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
"WPA: Failed to set GTK to "
"the driver (alg=%d keylen=%d keyidx=%d)",
gd->alg, gd->gtk_len, gd->keyidx);
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return -1;
}
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return 0;
}
@@ -664,7 +747,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
const u8 *gtk, size_t gtk_len,
int key_info)
{
-#ifndef CONFIG_NO_WPA2
struct wpa_gtk_data gd;
/*
@@ -691,21 +773,21 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
os_memcpy(gd.gtk, gtk, gtk_len);
gd.gtk_len = gtk_len;
- if (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)) {
+ if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
+ (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gtk_len, gtk_len,
+ &gd.key_rsc_len, &gd.alg) ||
+ wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Failed to install GTK");
+ os_memset(&gd, 0, sizeof(gd));
return -1;
}
+ os_memset(&gd, 0, sizeof(gd));
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info & WPA_KEY_INFO_SECURE);
return 0;
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
@@ -713,13 +795,15 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+ if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
if (ie->igtk) {
+ size_t len;
const struct wpa_igtk_kde *igtk;
u16 keyidx;
- if (ie->igtk_len != sizeof(*igtk))
+ len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
return -1;
igtk = (const struct wpa_igtk_kde *) ie->igtk;
keyidx = WPA_GET_LE16(igtk->keyid);
@@ -727,15 +811,16 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
"pn %02x%02x%02x%02x%02x%02x",
keyidx, MAC2STR(igtk->pn));
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
- igtk->igtk, WPA_IGTK_LEN);
+ igtk->igtk, len);
if (keyidx > 4095) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid IGTK KeyID %d", keyidx);
return -1;
}
- if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
- igtk->igtk, WPA_IGTK_LEN) < 0) {
+ igtk->igtk, len) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to configure IGTK to the driver");
return -1;
@@ -868,7 +953,8 @@ static int ft_validate_rsnie(struct wpa_sm *sm,
return -1;
}
- if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
+ if (os_memcmp_const(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+ {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"FT: PMKR1Name mismatch in "
"FT 4-way handshake message 3/4");
@@ -988,49 +1074,49 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
* @key: Pointer to the EAPOL-Key frame header
* @ver: Version bits from EAPOL-Key Key Info
* @key_info: Key Info
- * @kde: KDEs to include the EAPOL-Key frame
- * @kde_len: Length of KDEs
* @ptk: PTK to use for keyed hash and encryption
* Returns: 0 on success, -1 on failure
*/
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
u16 ver, u16 key_info,
- const u8 *kde, size_t kde_len,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
-
- if (kde)
- wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
+ 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);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply) + kde_len,
- &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ 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;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, kde_len);
- if (kde)
- os_memcpy(reply + 1, kde, kde_len);
+ 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);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
@@ -1038,10 +1124,10 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
- u16 key_info, keylen, len;
- const u8 *pos;
+ u16 key_info, keylen;
struct wpa_eapol_ie_parse ie;
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
@@ -1050,10 +1136,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
key_info = WPA_GET_BE16(key->key_info);
- pos = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
- if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1067,7 +1151,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
- if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
+ if (ie.igtk &&
+ wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
+ ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN +
+ (unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid IGTK KDE length %lu",
(unsigned long) ie.igtk_len);
@@ -1095,8 +1182,16 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
+#ifdef CONFIG_P2P
+ if (ie.ip_addr_alloc) {
+ os_memcpy(sm->p2p_ip_addr, ie.ip_addr_alloc, 3 * 4);
+ wpa_hexdump(MSG_DEBUG, "P2P: IP address info",
+ sm->p2p_ip_addr, sizeof(sm->p2p_ip_addr));
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
- NULL, 0, &sm->ptk)) {
+ &sm->ptk)) {
goto failed;
}
@@ -1118,7 +1213,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
- if (ie.gtk &&
+ if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+ wpa_supplicant_key_neg_complete(sm, sm->bssid,
+ key_info & WPA_KEY_INFO_SECURE);
+ } else if (ie.gtk &&
wpa_supplicant_pairwise_gtk(sm, key,
ie.gtk, ie.gtk_len, key_info) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1132,8 +1230,21 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
- wpa_sm_set_rekey_offload(sm);
+ if (ie.gtk)
+ wpa_sm_set_rekey_offload(sm);
+
+ if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ struct rsn_pmksa_cache_entry *sa;
+
+ sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
+ }
+ sm->msg_3_of_4_ok = 1;
return;
failed:
@@ -1193,22 +1304,15 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- size_t keydatalen, int key_info,
- size_t extra_len, u16 ver,
- struct wpa_gtk_data *gd)
+ const u8 *key_data,
+ size_t key_data_len, u16 key_info,
+ u16 ver, struct wpa_gtk_data *gd)
{
size_t maxkeylen;
- u8 ek[32];
+ u16 gtk_len;
- gd->gtk_len = WPA_GET_BE16(key->key_length);
- maxkeylen = keydatalen;
- if (keydatalen > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "WPA: Truncated EAPOL-Key packet: "
- "key_data_length=%lu > extra_len=%lu",
- (unsigned long) keydatalen, (unsigned long) extra_len);
- return -1;
- }
+ gtk_len = WPA_GET_BE16(key->key_length);
+ maxkeylen = key_data_len;
if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen < 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1219,45 +1323,50 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
maxkeylen -= 8;
}
- if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gd->gtk_len, maxkeylen,
+ if (gtk_len > maxkeylen ||
+ wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
return -1;
+ gd->gtk_len = gtk_len;
gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
WPA_KEY_INFO_KEY_INDEX_SHIFT;
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
- os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
- if (keydatalen > sizeof(gd->gtk)) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
+ u8 ek[32];
+ if (key_data_len > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: RC4 key data too long (%lu)",
- (unsigned long) keydatalen);
+ (unsigned long) key_data_len);
return -1;
}
- os_memcpy(gd->gtk, key + 1, keydatalen);
- if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
+ os_memcpy(ek, key->key_iv, 16);
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
+ os_memcpy(gd->gtk, key_data, key_data_len);
+ if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) {
+ os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
return -1;
}
+ os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
- if (keydatalen % 8) {
+ if (maxkeylen % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported AES-WRAP len %lu",
- (unsigned long) keydatalen);
+ (unsigned long) maxkeylen);
return -1;
}
if (maxkeylen > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES-WRAP key data "
"too long (keydatalen=%lu maxkeylen=%lu)",
- (unsigned long) keydatalen,
+ (unsigned long) key_data_len,
(unsigned long) maxkeylen);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
- (const u8 *) (key + 1), gd->gtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, maxkeylen / 8,
+ key_data, gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - could not decrypt "
"GTK");
@@ -1278,32 +1387,41 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
int ver, u16 key_info)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ 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);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ 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;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ 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);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
return 0;
}
@@ -1312,12 +1430,19 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- int extra_len, u16 ver)
+ const u8 *key_data,
+ size_t key_data_len, u16 ver)
{
- u16 key_info, keydatalen;
+ u16 key_info;
int rekey, ret;
struct wpa_gtk_data gd;
+ if (!sm->msg_3_of_4_ok) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Group Key Handshake started prior to completion of 4-way handshake");
+ goto failed;
+ }
+
os_memset(&gd, 0, sizeof(gd));
rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
@@ -1325,17 +1450,15 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
key_info = WPA_GET_BE16(key->key_info);
- keydatalen = WPA_GET_BE16(key->key_data_length);
- if (sm->proto == WPA_PROTO_RSN) {
- ret = wpa_supplicant_process_1_of_2_rsn(sm,
- (const u8 *) (key + 1),
- keydatalen, key_info,
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
+ ret = wpa_supplicant_process_1_of_2_rsn(sm, key_data,
+ key_data_len, key_info,
&gd);
} else {
- ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
- key_info, extra_len,
- ver, &gd);
+ ret = wpa_supplicant_process_1_of_2_wpa(sm, key, key_data,
+ key_data_len,
+ key_info, ver, &gd);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
@@ -1346,6 +1469,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
goto failed;
+ os_memset(&gd, 0, sizeof(gd));
if (rekey) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Group rekeying "
@@ -1353,34 +1477,37 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
wpa_sm_cancel_auth_timeout(sm);
wpa_sm_set_state(sm, WPA_COMPLETED);
-
- wpa_sm_set_rekey_offload(sm);
} else {
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info &
WPA_KEY_INFO_SECURE);
}
+
+ wpa_sm_set_rekey_offload(sm);
+
return;
failed:
+ os_memset(&gd, 0, sizeof(gd));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_eapol_key *key,
+ struct wpa_eapol_key_192 *key,
u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
int ok = 0;
+ size_t mic_len = wpa_mic_len(sm->key_mgmt);
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (sm->tptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ 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) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
@@ -1389,14 +1516,15 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
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));
}
}
if (!ok && sm->ptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ 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) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
@@ -1421,12 +1549,11 @@ 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, u16 ver,
+ u8 *key_data, size_t *key_data_len)
{
- u16 keydatalen = WPA_GET_BE16(key->key_data_length);
-
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
if (!sm->ptk_set) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
@@ -1436,49 +1563,53 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
/* Decrypt key data here so that this operation does not need
* to be implemented separately for each message type. */
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
u8 ek[32];
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
- if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
+ if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
+ os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
return -1;
}
+ os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
- ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
+ sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt)) {
u8 *buf;
- if (keydatalen % 8) {
+ if (*key_data_len < 8 || *key_data_len % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Unsupported AES-WRAP len %d",
- keydatalen);
+ "WPA: Unsupported AES-WRAP len %u",
+ (unsigned int) *key_data_len);
return -1;
}
- keydatalen -= 8; /* AES-WRAP adds 8 bytes */
- buf = os_malloc(keydatalen);
+ *key_data_len -= 8; /* AES-WRAP adds 8 bytes */
+ buf = os_malloc(*key_data_len);
if (buf == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
- if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
- (u8 *) (key + 1), buf)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
+ key_data, buf)) {
os_free(buf);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
- os_memcpy(key + 1, buf, keydatalen);
+ os_memcpy(key_data, buf, *key_data_len);
os_free(buf);
- WPA_PUT_BE16(key->key_data_length, keydatalen);
+ WPA_PUT_BE16(key->key_data_length, *key_data_len);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported key_info type %d", ver);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
return 0;
}
@@ -1498,7 +1629,9 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm)
static void wpa_eapol_key_dump(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ unsigned int key_data_len,
+ const u8 *mic, unsigned int mic_len)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
u16 key_info = WPA_GET_BE16(key->key_info);
@@ -1520,15 +1653,14 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
" key_length=%u key_data_length=%u",
- WPA_GET_BE16(key->key_length),
- WPA_GET_BE16(key->key_data_length));
+ WPA_GET_BE16(key->key_length), key_data_len);
wpa_hexdump(MSG_DEBUG, " replay_counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16);
wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8);
wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8);
- wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16);
+ wpa_hexdump(MSG_DEBUG, " key_mic", mic, mic_len);
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
@@ -1552,34 +1684,34 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
- size_t plen, data_len, extra_len;
- struct ieee802_1x_hdr *hdr;
+ 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;
+ u8 *tmp = NULL;
int ret = -1;
struct wpa_peerkey *peerkey = NULL;
+ u8 *key_data;
+ size_t mic_len, keyhdrlen;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- if (len < sizeof(*hdr) + sizeof(*key)) {
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (len < sizeof(*hdr) + keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame too short to be a WPA "
"EAPOL-Key (len %lu, expecting at least %lu)",
(unsigned long) len,
- (unsigned long) sizeof(*hdr) + sizeof(*key));
+ (unsigned long) sizeof(*hdr) + keyhdrlen);
return 0;
}
- tmp = os_malloc(len);
- if (tmp == NULL)
- return -1;
- os_memcpy(tmp, buf, len);
-
- hdr = (struct ieee802_1x_hdr *) tmp;
- key = (struct wpa_eapol_key *) (hdr + 1);
+ hdr = (const struct ieee802_1x_hdr *) buf;
plen = be_to_host16(hdr->length);
data_len = plen + sizeof(*hdr);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -1596,7 +1728,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
- if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
+ if (plen > len - sizeof(*hdr) || plen < keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame payload size %lu "
"invalid (frame size %lu)",
@@ -1604,6 +1737,27 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
+ if (data_len < len) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: ignoring %lu bytes after the IEEE 802.1X data",
+ (unsigned long) len - data_len);
+ }
+
+ /*
+ * 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);
+ 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);
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1613,28 +1767,53 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
- wpa_eapol_key_dump(sm, key);
- eapol_sm_notify_lower_layer_success(sm->eapol, 0);
- wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
- if (data_len < len) {
- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: ignoring %lu bytes after the IEEE 802.1X data",
- (unsigned long) len - data_len);
+ 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);
+
+ if (key_data_len > plen - keyhdrlen) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
+ "frame - key_data overflow (%u > %u)",
+ (unsigned int) key_data_len,
+ (unsigned int) (plen - keyhdrlen));
+ goto out;
}
+
+ eapol_sm_notify_lower_layer_success(sm->eapol, 0);
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
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) &&
+ 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)",
+ ver);
+ goto out;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
@@ -1647,7 +1826,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
- if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ 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_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
@@ -1656,6 +1837,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) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@@ -1669,11 +1851,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Backwards compatibility: allow invalid "
"version for non-CCMP group keys");
+ } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used");
} else
goto out;
- }
- if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+ !wpa_key_mgmt_suite_b(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 "
"descriptor version (%d) is not 2", ver);
@@ -1743,31 +1928,21 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
- wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+ wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
goto out;
#ifdef CONFIG_PEERKEY
if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
- peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
+ peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
+ data_len))
goto out;
#endif /* CONFIG_PEERKEY */
- extra_len = data_len - sizeof(*hdr) - sizeof(*key);
-
- if (WPA_GET_BE16(key->key_data_length) > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
- "frame - key_data overflow (%d > %lu)",
- WPA_GET_BE16(key->key_data_length),
- (unsigned long) extra_len);
- goto out;
- }
- extra_len = WPA_GET_BE16(key->key_data_length);
-
- if (sm->proto == WPA_PROTO_RSN &&
+ if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- if (wpa_supplicant_decrypt_key_data(sm, key, ver))
+ if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
+ &key_data_len))
goto out;
- extra_len = WPA_GET_BE16(key->key_data_length);
}
if (key_info & WPA_KEY_INFO_KEY_TYPE) {
@@ -1779,24 +1954,28 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
if (peerkey) {
/* PeerKey 4-Way Handshake */
- peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
+ peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_MIC) {
/* 3/4 4-Way Handshake */
- wpa_supplicant_process_3_of_4(sm, key, ver);
+ wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
+ key_data_len);
} else {
/* 1/4 4-Way Handshake */
wpa_supplicant_process_1_of_4(sm, src_addr, key,
- ver);
+ 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, extra_len, key_info,
+ peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
ver);
} else {
if (key_info & WPA_KEY_INFO_MIC) {
/* 1/2 Group Key Handshake */
wpa_supplicant_process_1_of_2(sm, src_addr, key,
- extra_len, ver);
+ key_data, key_data_len,
+ ver);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: EAPOL-Key (Group) without Mic bit - "
@@ -1807,7 +1986,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 1;
out:
- os_free(tmp);
+ bin_clear_free(tmp, data_len);
return ret;
}
@@ -1817,7 +1996,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
{
switch (sm->key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
- return (sm->proto == WPA_PROTO_RSN ?
+ return ((sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
case WPA_KEY_MGMT_PSK:
@@ -1842,6 +2022,10 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
WPA_AUTH_KEY_MGMT_CCKM);
case WPA_KEY_MGMT_WPA_NONE:
return WPA_AUTH_KEY_MGMT_NONE;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
default:
return 0;
}
@@ -1899,7 +2083,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
sm->dot11RSNAConfigPMKLifetime,
sm->dot11RSNAConfigPMKReauthThreshold,
sm->dot11RSNAConfigSATimeout);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
@@ -1926,7 +2110,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
sm->group_cipher)),
sm->dot11RSNA4WayHandshakeFailures);
- if (ret >= 0 && (size_t) ret < buflen)
+ if (!os_snprintf_error(buflen - len, ret))
len += ret;
return (int) len;
@@ -2024,6 +2208,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
os_free(sm->assoc_wpa_ie);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ wpa_sm_drop_sa(sm);
os_free(sm->ctx);
peerkey_deinit(sm);
#ifdef CONFIG_IEEE80211R
@@ -2080,12 +2265,18 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
*/
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
sm->ptk_set = 0;
+ os_memset(&sm->ptk, 0, sizeof(sm->ptk));
sm->tptk_set = 0;
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
}
#ifdef CONFIG_TDLS
wpa_tdls_assoc(sm);
#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_P2P
+ os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
+#endif /* CONFIG_P2P */
}
@@ -2098,6 +2289,9 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
*/
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)
@@ -2105,6 +2299,11 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
#ifdef CONFIG_TDLS
wpa_tdls_disassoc(sm);
#endif /* CONFIG_TDLS */
+
+ /* Keys are not needed in the WPA state machine anymore */
+ wpa_sm_drop_sa(sm);
+
+ sm->msg_3_of_4_ok = 0;
}
@@ -2113,10 +2312,12 @@ 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
+ * @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)
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *bssid)
{
if (sm == NULL)
return;
@@ -2129,6 +2330,12 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
sm->xxkey_len = pmk_len;
os_memcpy(sm->xxkey, pmk, pmk_len);
#endif /* CONFIG_IEEE80211R */
+
+ if (bssid) {
+ pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+ bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ }
}
@@ -2208,6 +2415,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
} else
sm->ssid_len = 0;
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
+ sm->p2p = config->p2p;
} else {
sm->network_ctx = NULL;
sm->peerkey_enabled = 0;
@@ -2217,6 +2425,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->eap_conf_ctx = NULL;
sm->ssid_len = 0;
sm->wpa_ptk_rekey = 0;
+ sm->p2p = 0;
}
}
@@ -2327,44 +2536,6 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
/**
- * wpa_sm_get_param - Get WPA state machine parameters
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @param: Parameter field
- * Returns: Parameter value
- */
-unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
-{
- if (sm == NULL)
- return 0;
-
- switch (param) {
- case RSNA_PMK_LIFETIME:
- return sm->dot11RSNAConfigPMKLifetime;
- case RSNA_PMK_REAUTH_THRESHOLD:
- return sm->dot11RSNAConfigPMKReauthThreshold;
- case RSNA_SA_TIMEOUT:
- return sm->dot11RSNAConfigSATimeout;
- case WPA_PARAM_PROTO:
- return sm->proto;
- case WPA_PARAM_PAIRWISE:
- return sm->pairwise_cipher;
- case WPA_PARAM_GROUP:
- return sm->group_cipher;
- case WPA_PARAM_KEY_MGMT:
- return sm->key_mgmt;
-#ifdef CONFIG_IEEE80211W
- case WPA_PARAM_MGMT_GROUP:
- return sm->mgmt_group_cipher;
-#endif /* CONFIG_IEEE80211W */
- case WPA_PARAM_RSN_ENABLED:
- return sm->rsn_enabled;
- default:
- return 0;
- }
-}
-
-
-/**
* wpa_sm_get_status - Get WPA state machine
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @buf: Buffer for status information
@@ -2389,7 +2560,7 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
wpa_cipher_txt(sm->pairwise_cipher),
wpa_cipher_txt(sm->group_cipher),
wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2402,7 +2573,7 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
ret = os_snprintf(pos, end - pos, "pmf=%d\n",
(rsn.capabilities &
WPA_CAPABILITY_MFPR) ? 2 : 1);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -2412,6 +2583,21 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
}
+int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+ struct wpa_ie_data rsn;
+
+ if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+ return 0;
+
+ if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
+ rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
+ return 1;
+
+ return 0;
+}
+
+
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -2586,11 +2772,7 @@ 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)
{
-#ifndef CONFIG_NO_WPA2
return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
@@ -2602,6 +2784,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+#ifdef CONFIG_IEEE80211R
+ os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+ os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+#endif /* CONFIG_IEEE80211R */
}
@@ -2621,38 +2808,29 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
{
-#ifndef CONFIG_NO_WPA2
- pmksa_cache_flush(sm->pmksa, network_ctx);
-#endif /* CONFIG_NO_WPA2 */
+ pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
}
#ifdef CONFIG_WNM
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
{
- struct wpa_gtk_data gd;
-#ifdef CONFIG_IEEE80211W
- struct wpa_igtk_kde igd;
- u16 keyidx;
-#endif /* CONFIG_IEEE80211W */
u16 keyinfo;
u8 keylen; /* plaintext key len */
u8 *key_rsc;
- os_memset(&gd, 0, sizeof(gd));
-#ifdef CONFIG_IEEE80211W
- os_memset(&igd, 0, sizeof(igd));
-#endif /* CONFIG_IEEE80211W */
-
- keylen = wpa_cipher_key_len(sm->group_cipher);
- gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
- gd.alg = wpa_cipher_to_alg(sm->group_cipher);
- if (gd.alg == WPA_ALG_NONE) {
- wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
- return -1;
- }
-
if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+ struct wpa_gtk_data gd;
+
+ os_memset(&gd, 0, sizeof(gd));
+ keylen = wpa_cipher_key_len(sm->group_cipher);
+ gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+ gd.alg = wpa_cipher_to_alg(sm->group_cipher);
+ if (gd.alg == WPA_ALG_NONE) {
+ wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+ return -1;
+ }
+
key_rsc = buf + 5;
keyinfo = WPA_GET_LE16(buf + 2);
gd.gtk_len = keylen;
@@ -2670,27 +2848,37 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
gd.gtk, gd.gtk_len);
if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+ os_memset(&gd, 0, sizeof(gd));
wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
"WNM mode");
return -1;
}
+ os_memset(&gd, 0, sizeof(gd));
#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+ struct wpa_igtk_kde igd;
+ u16 keyidx;
+
+ os_memset(&igd, 0, sizeof(igd));
+ keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
os_memcpy(igd.keyid, buf + 2, 2);
os_memcpy(igd.pn, buf + 4, 6);
keyidx = WPA_GET_LE16(igd.keyid);
- os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN);
+ os_memcpy(igd.igtk, buf + 10, keylen);
wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
- igd.igtk, WPA_IGTK_LEN);
- if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+ igd.igtk, keylen);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
keyidx, 0, igd.pn, sizeof(igd.pn),
- igd.igtk, WPA_IGTK_LEN) < 0) {
+ igd.igtk, keylen) < 0) {
wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
"WNM mode");
+ os_memset(&igd, 0, sizeof(igd));
return -1;
}
+ os_memset(&igd, 0, sizeof(igd));
#endif /* CONFIG_IEEE80211W */
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
@@ -2700,3 +2888,67 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
return 0;
}
#endif /* CONFIG_WNM */
+
+
+#ifdef CONFIG_PEERKEY
+int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_peerkey *peerkey;
+
+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+ if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!peerkey)
+ return 0;
+
+ wpa_sm_rx_eapol(sm, src_addr, buf, len);
+
+ return 1;
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_P2P
+
+int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
+{
+ if (sm == NULL || WPA_GET_BE32(sm->p2p_ip_addr) == 0)
+ return -1;
+ os_memcpy(buf, sm->p2p_ip_addr, 3 * 4);
+ return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter)
+{
+ if (rx_replay_counter == NULL)
+ return;
+
+ os_memcpy(sm->rx_replay_counter, rx_replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ sm->rx_replay_counter_set = 1;
+ wpa_printf(MSG_DEBUG, "Updated key 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)
+{
+ if (ptk_kck && ptk_kck_len <= WPA_KCK_MAX_LEN) {
+ os_memcpy(sm->ptk.kck, ptk_kck, ptk_kck_len);
+ sm->ptk.kck_len = ptk_kck_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KCK");
+ }
+ if (ptk_kek && ptk_kek_len <= WPA_KEK_MAX_LEN) {
+ os_memcpy(sm->ptk.kek, ptk_kek, ptk_kek_len);
+ sm->ptk.kek_len = ptk_kek_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KEK");
+ }
+ sm->ptk_set = 1;
+}
diff --git a/contrib/wpa/src/rsn_supp/wpa.h b/contrib/wpa/src/rsn_supp/wpa.h
index 791974c..e163b70 100644
--- a/contrib/wpa/src/rsn_supp/wpa.h
+++ b/contrib/wpa/src/rsn_supp/wpa.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,10 +12,12 @@
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
struct wpa_sm;
struct eapol_sm;
struct wpa_config_blob;
+struct hostapd_freq_params;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -50,17 +52,31 @@ struct wpa_sm_ctx {
int (*mark_authenticated)(void *ctx, const u8 *target_ap);
#ifdef CONFIG_TDLS
int (*tdls_get_capa)(void *ctx, int *tdls_supported,
- int *tdls_ext_setup);
+ int *tdls_ext_setup, int *tdls_chan_switch);
int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf, size_t len);
+ u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf, size_t len);
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
- int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+ int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
u16 capability, const u8 *supp_rates,
- size_t supp_rates_len);
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, int wmm, const u8 *ext_capab,
+ size_t ext_capab_len, const u8 *supp_channels,
+ size_t supp_channels_len,
+ const u8 *supp_oper_classes,
+ size_t supp_oper_classes_len);
+ int (*tdls_enable_channel_switch)(
+ void *ctx, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params);
+ int (*tdls_disable_channel_switch)(void *ctx, const u8 *addr);
#endif /* CONFIG_TDLS */
- void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+ void (*set_rekey_offload)(void *ctx, const u8 *kek, size_t kek_len,
+ 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);
};
@@ -87,6 +103,7 @@ struct rsn_supp_config {
const u8 *ssid;
size_t ssid_len;
int wpa_ptk_rekey;
+ int p2p;
};
#ifndef CONFIG_NO_WPA
@@ -95,7 +112,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
void wpa_sm_deinit(struct wpa_sm *sm);
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
void wpa_sm_notify_disassoc(struct wpa_sm *sm);
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len);
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ 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);
@@ -113,11 +131,10 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
unsigned int value);
-unsigned int wpa_sm_get_param(struct wpa_sm *sm,
- enum wpa_sm_conf_params param);
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
+int wpa_sm_pmf_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -136,6 +153,13 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
+
+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);
+
#else /* CONFIG_NO_WPA */
static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -227,14 +251,13 @@ static inline int wpa_sm_set_param(struct wpa_sm *sm,
return -1;
}
-static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm,
- enum wpa_sm_conf_params param)
+static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
+ size_t buflen, int verbose)
{
return 0;
}
-static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
- size_t buflen, int verbose)
+static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
{
return 0;
}
@@ -291,15 +314,33 @@ static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
{
}
+static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm,
+ const u8 *rx_replay_counter)
+{
+}
+
+static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
+ const u8 *ptk_kek)
+{
+}
+
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_PEERKEY
int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
+int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len);
#else /* CONFIG_PEERKEY */
static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
{
return -1;
}
+
+static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ return 0;
+}
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
@@ -310,6 +351,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len);
int wpa_ft_is_completed(struct wpa_sm *sm);
+void wpa_reset_ft_completed(struct wpa_sm *sm);
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr);
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
@@ -341,6 +383,10 @@ static inline int wpa_ft_is_completed(struct wpa_sm *sm)
return 0;
}
+static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+}
+
static inline int
wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *src_addr)
@@ -355,15 +401,20 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_teardown_peers(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
+const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+int wpa_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);
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
diff --git a/contrib/wpa/src/rsn_supp/wpa_ft.c b/contrib/wpa/src/rsn_supp/wpa_ft.c
index 2df060c..06dea05 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-2007, 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.
@@ -19,8 +19,7 @@
#ifdef CONFIG_IEEE80211R
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *anonce = key->key_nonce;
@@ -43,13 +42,9 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
- sm->bssid, sm->pmk_r1_name,
- (u8 *) ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
- return 0;
+ 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);
}
@@ -134,6 +129,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
* @anonce: ANonce or %NULL if not yet available
* @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
* @kck: 128-bit KCK for MIC or %NULL if no MIC is used
+ * @kck_len: KCK length in octets
* @target_ap: Target AP address
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
@@ -144,7 +140,8 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
*/
static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *anonce, const u8 *pmk_name,
- const u8 *kck, const u8 *target_ap,
+ const u8 *kck, size_t kck_len,
+ const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
const u8 *ap_mdie)
{
@@ -207,6 +204,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
else {
wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
sm->key_mgmt);
@@ -296,7 +295,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
/* Information element count */
ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
ric_ies_len);
- if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
+ 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,
@@ -331,7 +330,7 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
- sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
@@ -358,7 +357,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -374,7 +373,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *ric_ies, size_t ric_ies_len)
{
u8 *ft_ies;
- size_t ft_ies_len, ptk_len;
+ size_t ft_ies_len;
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
@@ -400,8 +399,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
}
- if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+ if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
"enabled for this connection");
return -1;
@@ -441,7 +439,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -457,7 +456,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
"RSNIE");
return -1;
@@ -475,16 +475,14 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
- ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
- bssid, sm->pmk_r1_name,
- (u8 *) &sm->ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+ 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)
+ return -1;
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
- sm->pmk_r1_name, sm->ptk.kck, bssid,
+ sm->pmk_r1_name,
+ sm->ptk.kck, sm->ptk.kck_len, bssid,
ric_ies, ric_ies_len,
parse.mdie ? parse.mdie - 2 : NULL);
if (ft_ies) {
@@ -526,14 +524,20 @@ int wpa_ft_is_completed(struct wpa_sm *sm)
if (sm == NULL)
return 0;
- if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_FT_PSK)
+ if (!wpa_key_mgmt_ft(sm->key_mgmt))
return 0;
return sm->ft_completed;
}
+void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+ if (sm != NULL)
+ sm->ft_completed = 0;
+}
+
+
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
size_t gtk_elem_len)
{
@@ -557,7 +561,8 @@ 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, gtk_len / 8, gtk_elem + 11, gtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
+ gtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt GTK");
return -1;
@@ -589,6 +594,13 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
}
wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
+ if (sm->group_cipher == WPA_CIPHER_TKIP) {
+ /* Swap Tx/Rx keys for Michael MIC */
+ u8 tmp[8];
+ os_memcpy(tmp, gtk + 16, 8);
+ os_memcpy(gtk + 16, gtk + 24, 8);
+ os_memcpy(gtk + 24, tmp, 8);
+ }
if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
@@ -629,7 +641,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
return -1;
}
- if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
+ igtk_elem + 9, igtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt IGTK");
return -1;
@@ -660,12 +673,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
unsigned int count;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
- if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+ if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
"enabled for this connection");
return -1;
@@ -714,7 +726,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -729,14 +742,15 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
+ if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocResp");
return -1;
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
return -1;
@@ -752,7 +766,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
+ if (wpa_ft_mic(sm->ptk.kck, sm->ptk.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,
@@ -762,7 +776,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
@@ -788,9 +802,12 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
if (parse.ric) {
wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
parse.ric, parse.ric_len);
- /* TODO: parse response and inform driver about results */
+ /* TODO: parse response and inform driver about results when
+ * using wpa_supplicant SME */
}
+ wpa_printf(MSG_DEBUG, "FT: Completed successfully");
+
return 0;
}
@@ -818,7 +835,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/contrib/wpa/src/rsn_supp/wpa_i.h b/contrib/wpa/src/rsn_supp/wpa_i.h
index 9f9e641..965a9c1 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-2010, 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.
@@ -23,6 +23,7 @@ struct wpa_sm {
size_t pmk_len;
struct wpa_ptk ptk, tptk;
int ptk_set, tptk_set;
+ unsigned int msg_3_of_4_ok:1;
u8 snonce[WPA_NONCE_LEN];
u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
int renew_snonce;
@@ -58,6 +59,7 @@ struct wpa_sm {
u8 ssid[32];
size_t ssid_len;
int wpa_ptk_rekey;
+ int p2p;
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -91,6 +93,7 @@ struct wpa_sm {
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
int tdls_prohibited;
+ int tdls_chan_switch_prohibited;
int tdls_disabled;
/* The driver supports TDLS */
@@ -101,6 +104,9 @@ struct wpa_sm {
* to it via tdls_mgmt.
*/
int tdls_external_setup;
+
+ /* The driver supports TDLS channel switching */
+ int tdls_chan_switch;
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
@@ -122,6 +128,10 @@ struct wpa_sm {
u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
size_t assoc_resp_ies_len;
#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_P2P
+ u8 p2p_ip_addr[3 * 4];
+#endif /* CONFIG_P2P */
};
@@ -245,30 +255,34 @@ static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
{
if (!sm->ctx->set_rekey_offload)
return;
- sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
- sm->ptk.kck, sm->rx_replay_counter);
+ sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek, sm->ptk.kek_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->rx_replay_counter);
}
#ifdef CONFIG_TDLS
static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
int *tdls_supported,
- int *tdls_ext_setup)
+ int *tdls_ext_setup,
+ int *tdls_chan_switch)
{
if (sm->ctx->tdls_get_capa)
return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
- tdls_ext_setup);
+ tdls_ext_setup, tdls_chan_switch);
return -1;
}
static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf,
+ u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf,
size_t len)
{
if (sm->ctx->send_tdls_mgmt)
return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
dialog_token, status_code,
- buf, len);
+ peer_capab, initiator, buf,
+ len);
return -1;
}
@@ -282,18 +296,60 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
static inline int
wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
- u16 capability, const u8 *supp_rates,
- size_t supp_rates_len)
+ u16 aid, u16 capability, const u8 *supp_rates,
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, int wmm, const u8 *ext_capab,
+ size_t ext_capab_len, const u8 *supp_channels,
+ size_t supp_channels_len, const u8 *supp_oper_classes,
+ size_t supp_oper_classes_len)
{
if (sm->ctx->tdls_peer_addset)
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
- capability, supp_rates,
- supp_rates_len);
+ aid, capability, supp_rates,
+ supp_rates_len, ht_capab,
+ vht_capab, qosinfo, wmm,
+ ext_capab, ext_capab_len,
+ supp_channels,
+ supp_channels_len,
+ supp_oper_classes,
+ supp_oper_classes_len);
+ return -1;
+}
+
+static inline int
+wpa_sm_tdls_enable_channel_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ const struct hostapd_freq_params *freq_params)
+{
+ if (sm->ctx->tdls_enable_channel_switch)
+ return sm->ctx->tdls_enable_channel_switch(sm->ctx->ctx, addr,
+ oper_class,
+ freq_params);
+ return -1;
+}
+
+static inline int
+wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ if (sm->ctx->tdls_disable_channel_switch)
+ return sm->ctx->tdls_disable_channel_switch(sm->ctx->ctx, addr);
return -1;
}
#endif /* CONFIG_TDLS */
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+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);
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
@@ -304,12 +360,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
u16 ver, u16 key_info,
- const u8 *kde, size_t kde_len,
struct wpa_ptk *ptk);
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len);
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk);
void wpa_tdls_assoc(struct wpa_sm *sm);
void wpa_tdls_disassoc(struct wpa_sm *sm);
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.c b/contrib/wpa/src/rsn_supp/wpa_ie.c
index 3d75365..cb334df 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-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -107,7 +107,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int key_mgmt, int mgmt_group_cipher,
struct wpa_sm *sm)
{
-#ifndef CONFIG_NO_WPA2
u8 *pos;
struct rsn_ie_hdr *hdr;
u16 capab;
@@ -174,6 +173,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
+ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ 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);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -202,7 +205,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
}
#ifdef CONFIG_IEEE80211W
- if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+ if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
if (!sm->cur_pmksa) {
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
@@ -210,7 +213,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
}
/* Management Group Cipher Suite */
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ mgmt_group_cipher));
pos += RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
@@ -220,12 +224,67 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
+#ifdef CONFIG_HS20
+static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
+ int pairwise_cipher, int group_cipher,
+ int key_mgmt)
+{
+ u8 *pos, *len;
+ u32 suite;
+
+ if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
+ return -1;
+
+ pos = wpa_ie;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ len = pos++; /* to be filled */
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = HS20_OSEN_OUI_TYPE;
+
+ /* Group Data Cipher Suite */
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+ if (suite == 0) {
+ wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
+ group_cipher);
+ return -1;
+ }
+ RSN_SELECTOR_PUT(pos, suite);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Pairwise Cipher Suite Count and List */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+ if (suite == 0 ||
+ (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+ pairwise_cipher != WPA_CIPHER_NONE)) {
+ wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
+ pairwise_cipher);
+ return -1;
+ }
+ RSN_SELECTOR_PUT(pos, suite);
+ pos += RSN_SELECTOR_LEN;
+
+ /* AKM Suite Count and List */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+ pos += RSN_SELECTOR_LEN;
+
+ *len = pos - len - 1;
+
+ WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
+
+ return pos - wpa_ie;
+}
+#endif /* CONFIG_HS20 */
+
+
/**
* wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -241,6 +300,13 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
sm->group_cipher,
sm->key_mgmt, sm->mgmt_group_cipher,
sm);
+#ifdef CONFIG_HS20
+ else if (sm->proto == WPA_PROTO_OSEN)
+ return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
+ sm->pairwise_cipher,
+ sm->group_cipher,
+ sm->key_mgmt);
+#endif /* CONFIG_HS20 */
else
return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
sm->pairwise_cipher,
@@ -250,6 +316,42 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ unsigned int oui;
+
+ if (pos[1] < 4) {
+ wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
+ pos[1]);
+ return 1;
+ }
+
+ oui = WPA_GET_BE24(&pos[2]);
+ if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+ if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+ ie->wmm, ie->wmm_len);
+ } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+ ie->wmm, ie->wmm_len);
+ }
+ }
+ return 0;
+}
+
+
+/**
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
* @pos: Pointer to the IE header
* @end: Pointer to the end of the Key Data buffer
@@ -349,6 +451,25 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_P2P
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+ ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: IP Address Allocation in EAPOL-Key",
+ ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+#endif /* CONFIG_P2P */
+
return 0;
}
@@ -427,6 +548,31 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
ie->ext_supp_rates = pos;
ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP) {
+ ie->ht_capabilities = pos + 2;
+ ie->ht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_VHT_AID) {
+ if (pos[1] >= 2)
+ ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
+ } else if (*pos == WLAN_EID_VHT_CAP) {
+ ie->vht_capabilities = pos + 2;
+ ie->vht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
+ } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+ ie->supp_channels = pos + 2;
+ ie->supp_channels_len = pos[1];
+ } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+ /*
+ * The value of the Length field of the Supported
+ * Operating Classes element is between 2 and 253.
+ * Silently skip invalid elements to avoid interop
+ * issues when trying to use the value.
+ */
+ if (pos[1] >= 2 && pos[1] <= 253) {
+ ie->supp_oper_classes = pos + 2;
+ ie->supp_oper_classes_len = pos[1];
+ }
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
@@ -435,6 +581,14 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
ret = 0;
break;
}
+
+ ret = wpa_parse_vendor_specific(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
} else {
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
"Key Data IE", pos, 2 + pos[1]);
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.h b/contrib/wpa/src/rsn_supp/wpa_ie.h
index 5afdfe9..0fc42cc 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ie.h
+++ b/contrib/wpa/src/rsn_supp/wpa_ie.h
@@ -49,6 +49,22 @@ struct wpa_eapol_ie_parse {
size_t supp_rates_len;
const u8 *ext_supp_rates;
size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ size_t ht_capabilities_len;
+ const u8 *vht_capabilities;
+ size_t vht_capabilities_len;
+ const u8 *supp_channels;
+ size_t supp_channels_len;
+ const u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+ u8 qosinfo;
+ u16 aid;
+ const u8 *wmm;
+ size_t wmm_len;
+#ifdef CONFIG_P2P
+ const u8 *ip_addr_req;
+ const u8 *ip_addr_alloc;
+#endif /* CONFIG_P2P */
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/contrib/wpa/src/tls/asn1.c b/contrib/wpa/src/tls/asn1.c
index 53acd53..cec1092 100644
--- a/contrib/wpa/src/tls/asn1.c
+++ b/contrib/wpa/src/tls/asn1.c
@@ -1,6 +1,6 @@
/*
* ASN.1 DER parsing
- * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, 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,17 @@
#include "common.h"
#include "asn1.h"
+struct asn1_oid asn1_sha1_oid = {
+ .oid = { 1, 3, 14, 3, 2, 26 },
+ .len = 6
+};
+
+struct asn1_oid asn1_sha256_oid = {
+ .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
+ .len = 9
+};
+
+
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
{
const u8 *pos, *end;
@@ -140,7 +151,7 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
}
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
+void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
{
char *pos = buf;
size_t i;
@@ -155,7 +166,7 @@ void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
ret = os_snprintf(pos, buf + len - pos,
"%s%lu",
i == 0 ? "" : ".", oid->oid[i]);
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
break;
pos += ret;
}
@@ -204,3 +215,19 @@ unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
return val;
}
+
+
+int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
+{
+ size_t i;
+
+ if (a->len != b->len)
+ return 0;
+
+ for (i = 0; i < a->len; i++) {
+ if (a->oid[i] != b->oid[i])
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/contrib/wpa/src/tls/asn1.h b/contrib/wpa/src/tls/asn1.h
index 6342c4cc7..7475007 100644
--- a/contrib/wpa/src/tls/asn1.h
+++ b/contrib/wpa/src/tls/asn1.h
@@ -60,7 +60,11 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
const u8 **next);
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
+void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len);
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
+int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b);
+
+extern struct asn1_oid asn1_sha1_oid;
+extern struct asn1_oid asn1_sha256_oid;
#endif /* ASN1_H */
diff --git a/contrib/wpa/src/tls/libtommath.c b/contrib/wpa/src/tls/libtommath.c
index 741b442..3fb8fbe 100644
--- a/contrib/wpa/src/tls/libtommath.c
+++ b/contrib/wpa/src/tls/libtommath.c
@@ -42,6 +42,9 @@
/* Include faster sqr at the cost of about 0.5 kB in code */
#define BN_FAST_S_MP_SQR_C
+/* About 0.25 kB of code, but ~1.7kB of stack space! */
+#define BN_FAST_S_MP_MUL_DIGS_C
+
#else /* LTM_FAST */
#define BN_MP_DIV_SMALL
@@ -139,7 +142,9 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
static int s_mp_sqr(mp_int * a, mp_int * b);
static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+#endif
#ifdef BN_MP_INIT_MULTI_C
static int mp_init_multi(mp_int *mp, ...);
@@ -671,6 +676,9 @@ static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
#ifdef BN_MP_EXPTMOD_FAST_C
}
#endif
+ if (dr == 0) {
+ /* avoid compiler warnings about possibly unused variable */
+ }
}
@@ -2339,12 +2347,14 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* can we use the fast multiplier? */
if (((digs) < MP_WARRAY) &&
MIN (a->used, b->used) <
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_digs (a, b, c, digs);
}
+#endif
if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
return res;
@@ -2397,6 +2407,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
/* Fast (comba) multiplier
*
* This is the fast column-array [comba] multiplier. It is
@@ -2482,6 +2493,7 @@ static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
mp_clamp (c);
return MP_OKAY;
}
+#endif /* BN_FAST_S_MP_MUL_DIGS_C */
/* init an mp_init for a given size */
diff --git a/contrib/wpa/src/tls/pkcs1.c b/contrib/wpa/src/tls/pkcs1.c
index b6fde5e..141ac50 100644
--- a/contrib/wpa/src/tls/pkcs1.c
+++ b/contrib/wpa/src/tls/pkcs1.c
@@ -1,6 +1,6 @@
/*
* PKCS #1 (RSA Encryption)
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +9,9 @@
#include "includes.h"
#include "common.h"
+#include "crypto/crypto.h"
#include "rsa.h"
+#include "asn1.h"
#include "pkcs1.h"
@@ -113,6 +115,11 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
pos++;
if (pos == end)
return -1;
+ if (pos - out - 2 < 8) {
+ /* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+ wpa_printf(MSG_INFO, "LibTomCrypt: Too short padding");
+ return -1;
+ }
pos++;
*outlen -= pos - out;
@@ -142,35 +149,26 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
* BT = 00 or 01
* PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
* k = length of modulus in octets
+ *
+ * Based on 10.1.3, "The block type shall be 01" for a signature.
*/
if (len < 3 + 8 + 16 /* min hash len */ ||
- plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
+ plain[0] != 0x00 || plain[1] != 0x01) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
return -1;
}
pos = plain + 3;
- if (plain[1] == 0x00) {
- /* BT = 00 */
- if (plain[2] != 0x00) {
- wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
- "PS (BT=00)");
- return -1;
- }
- while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
- pos++;
- } else {
- /* BT = 01 */
- if (plain[2] != 0xff) {
- wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
- "PS (BT=01)");
- return -1;
- }
- while (pos < plain + len && *pos == 0xff)
- pos++;
+ /* BT = 01 */
+ if (plain[2] != 0xff) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+ "PS (BT=01)");
+ return -1;
}
+ while (pos < plain + len && *pos == 0xff)
+ pos++;
if (pos - plain - 2 < 8) {
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
@@ -193,3 +191,130 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
return 0;
}
+
+
+int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
+ const u8 *s, size_t s_len,
+ const struct asn1_oid *hash_alg,
+ const u8 *hash, size_t hash_len)
+{
+ int res;
+ u8 *decrypted;
+ size_t decrypted_len;
+ const u8 *pos, *end, *next, *da_end;
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+
+ decrypted = os_malloc(s_len);
+ if (decrypted == NULL)
+ return -1;
+ decrypted_len = s_len;
+ res = crypto_public_key_decrypt_pkcs1(pk, s, s_len, decrypted,
+ &decrypted_len);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "PKCS #1: RSA decrypt failed");
+ os_free(decrypted);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "Decrypted(S)", decrypted, decrypted_len);
+
+ /*
+ * PKCS #1 v1.5, 10.1.2:
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest
+ * }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ *
+ */
+ if (asn1_get_next(decrypted, decrypted_len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Expected SEQUENCE (DigestInfo) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(decrypted);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /*
+ * X.509:
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Expected SEQUENCE (AlgorithmIdentifier) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(decrypted);
+ return -1;
+ }
+ da_end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Failed to parse digestAlgorithm");
+ os_free(decrypted);
+ return -1;
+ }
+
+ if (!asn1_oid_equal(&oid, hash_alg)) {
+ char txt[100], txt2[100];
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ asn1_oid_to_str(hash_alg, txt2, sizeof(txt2));
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Hash alg OID mismatch: was %s, expected %s",
+ txt, txt2);
+ os_free(decrypted);
+ return -1;
+ }
+
+ /* Digest ::= OCTET STRING */
+ pos = da_end;
+ end = decrypted + decrypted_len;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Expected OCTETSTRING (Digest) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(decrypted);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Decrypted Digest",
+ hdr.payload, hdr.length);
+
+ if (hdr.length != hash_len ||
+ os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
+ wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash");
+ os_free(decrypted);
+ return -1;
+ }
+
+ os_free(decrypted);
+
+ if (hdr.payload + hdr.length != end) {
+ wpa_printf(MSG_INFO,
+ "PKCS #1: Extra data after signature - reject");
+
+ wpa_hexdump(MSG_DEBUG, "PKCS #1: Extra data",
+ hdr.payload + hdr.length,
+ end - hdr.payload - hdr.length);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/tls/pkcs1.h b/contrib/wpa/src/tls/pkcs1.h
index ed64def..f37ebf3 100644
--- a/contrib/wpa/src/tls/pkcs1.h
+++ b/contrib/wpa/src/tls/pkcs1.h
@@ -9,6 +9,9 @@
#ifndef PKCS1_H
#define PKCS1_H
+struct crypto_public_key;
+struct asn1_oid;
+
int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
int use_private, const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
@@ -18,5 +21,9 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
+int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
+ const u8 *s, size_t s_len,
+ const struct asn1_oid *hash_alg,
+ const u8 *hash, size_t hash_len);
#endif /* PKCS1_H */
diff --git a/contrib/wpa/src/tls/rsa.c b/contrib/wpa/src/tls/rsa.c
index 125c420..0b7b530 100644
--- a/contrib/wpa/src/tls/rsa.c
+++ b/contrib/wpa/src/tls/rsa.c
@@ -1,6 +1,6 @@
/*
* RSA
- * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -116,6 +116,29 @@ error:
}
+struct crypto_rsa_key *
+crypto_rsa_import_public_key_parts(const u8 *n, size_t n_len,
+ const u8 *e, size_t e_len)
+{
+ struct crypto_rsa_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (key == NULL)
+ return NULL;
+
+ key->n = bignum_init();
+ key->e = bignum_init();
+ if (key->n == NULL || key->e == NULL ||
+ bignum_set_unsigned_bin(key->n, n, n_len) < 0 ||
+ bignum_set_unsigned_bin(key->e, e, e_len) < 0) {
+ crypto_rsa_free(key);
+ return NULL;
+ }
+
+ return key;
+}
+
+
/**
* crypto_rsa_import_private_key - Import an RSA private key
* @buf: Key buffer (DER encoded RSA private key)
diff --git a/contrib/wpa/src/tls/rsa.h b/contrib/wpa/src/tls/rsa.h
index c236a9d..b65818e 100644
--- a/contrib/wpa/src/tls/rsa.h
+++ b/contrib/wpa/src/tls/rsa.h
@@ -14,6 +14,9 @@ struct crypto_rsa_key;
struct crypto_rsa_key *
crypto_rsa_import_public_key(const u8 *buf, size_t len);
struct crypto_rsa_key *
+crypto_rsa_import_public_key_parts(const u8 *n, size_t n_len,
+ const u8 *e, size_t e_len);
+struct crypto_rsa_key *
crypto_rsa_import_private_key(const u8 *buf, size_t len);
size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key);
int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
diff --git a/contrib/wpa/src/tls/tlsv1_client.c b/contrib/wpa/src/tls/tlsv1_client.c
index 12148b6..facdd65 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-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -459,10 +459,15 @@ struct tlsv1_client * tlsv1_client_init(void)
count = 0;
suites = conn->cipher_suites;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
@@ -565,8 +570,26 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
- cipher = "ADH-AES-128-SHA256";
+ case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC3-SHA";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ cipher = "ADH-RC4-MD5";
+ break;
+ case TLS_DH_anon_WITH_DES_CBC_SHA:
+ cipher = "ADH-DES-SHA";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ cipher = "ADH-DES-CBC3-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "AES-128-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "DHE-RSA-AES-128-SHA";
break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
@@ -574,15 +597,30 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- cipher = "AES-256-SHA256";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ cipher = "DHE-RSA-AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- cipher = "AES-128-SHA";
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ cipher = "ADH-AES-256-SHA";
break;
case TLS_RSA_WITH_AES_128_CBC_SHA256:
cipher = "AES-128-SHA256";
break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "AES-256-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "DHE-RSA-AES-128-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "DHE-RSA-AES-256-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ cipher = "ADH-AES-128-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ cipher = "ADH-AES-256-SHA256";
+ break;
default:
return -1;
}
diff --git a/contrib/wpa/src/tls/tlsv1_client_read.c b/contrib/wpa/src/tls/tlsv1_client_read.c
index 3269ecf..9ce9680 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-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -409,10 +409,38 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
}
+static unsigned int count_bits(const u8 *val, size_t len)
+{
+ size_t i;
+ unsigned int bits;
+ u8 tmp;
+
+ for (i = 0; i < len; i++) {
+ if (val[i])
+ break;
+ }
+ if (i == len)
+ return 0;
+
+ bits = (len - i - 1) * 8;
+ tmp = val[i];
+ while (tmp) {
+ bits++;
+ tmp >>= 1;
+ }
+
+ return bits;
+}
+
+
static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ tls_key_exchange key_exchange)
{
- const u8 *pos, *end;
+ const u8 *pos, *end, *server_params, *server_params_end;
+ u8 alert;
+ unsigned int bits;
+ u16 val;
tlsv1_client_free_dh(conn);
@@ -421,11 +449,20 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (end - pos < 3)
goto fail;
- conn->dh_p_len = WPA_GET_BE16(pos);
+ server_params = pos;
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
- (unsigned long) conn->dh_p_len);
+ if (val == 0 || val > (size_t) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %u", val);
+ goto fail;
+ }
+ conn->dh_p_len = val;
+ bits = count_bits(pos, conn->dh_p_len);
+ if (bits < 768) {
+ wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)",
+ bits);
+ wpa_hexdump(MSG_DEBUG, "TLSv1: Rejected DH prime",
+ pos, conn->dh_p_len);
goto fail;
}
conn->dh_p = os_malloc(conn->dh_p_len);
@@ -438,10 +475,11 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (end - pos < 3)
goto fail;
- conn->dh_g_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+ if (val == 0 || val > (size_t) (end - pos))
goto fail;
+ conn->dh_g_len = val;
conn->dh_g = os_malloc(conn->dh_g_len);
if (conn->dh_g == NULL)
goto fail;
@@ -454,10 +492,11 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (end - pos < 3)
goto fail;
- conn->dh_ys_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+ if (val == 0 || val > (size_t) (end - pos))
goto fail;
+ conn->dh_ys_len = val;
conn->dh_ys = os_malloc(conn->dh_ys_len);
if (conn->dh_ys == NULL)
goto fail;
@@ -465,6 +504,59 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
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];
+ int hlen;
+
+ if (conn->rl.tls_version == TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used
+ * signature and hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ if (end - pos < 2)
+ goto fail;
+ if (pos[0] != TLS_HASH_ALG_SHA256 ||
+ pos[1] != TLS_SIGN_ALG_RSA) {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
+ pos[0], pos[1]);
+ goto fail;
+ }
+ pos += 2;
+
+ hlen = tlsv12_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ server_params_end - server_params, hash);
+#else /* CONFIG_TLSV12 */
+ goto fail;
+#endif /* CONFIG_TLSV12 */
+ } else {
+ hlen = tls_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ server_params_end - server_params, hash);
+ }
+
+ if (hlen < 0)
+ goto fail;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
+ hash, hlen);
+
+ if (tls_verify_signature(conn->rl.tls_version,
+ conn->server_rsa_key,
+ hash, hlen, pos, end - pos,
+ &alert) < 0)
+ goto fail;
+ }
return 0;
@@ -543,8 +635,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
- if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
- if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+ if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon ||
+ suite->key_exchange == TLS_KEY_X_DHE_RSA)) {
+ if (tlsv1_process_diffie_hellman(conn, pos, len,
+ suite->key_exchange) < 0) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -871,8 +965,10 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data, TLS_VERIFY_DATA_LEN);
- if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
return -1;
}
diff --git a/contrib/wpa/src/tls/tlsv1_client_write.c b/contrib/wpa/src/tls/tlsv1_client_write.c
index d789efb..d192f44 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-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -205,7 +205,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
}
-static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
{
/* ClientDiffieHellmanPublic */
u8 *csecret, *csecret_start, *dh_yc, *shared;
@@ -399,8 +399,8 @@ static int tls_write_client_key_exchange(struct tlsv1_client *conn,
hs_length = pos;
pos += 3;
/* body - ClientKeyExchange */
- if (keyx == TLS_KEY_X_DH_anon) {
- if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+ if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) {
+ if (tlsv1_key_x_dh(conn, &pos, end) < 0)
return -1;
} else {
if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
@@ -432,7 +432,6 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
size_t rlen, hlen, clen;
u8 hash[100], *hpos;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
pos = *msgpos;
@@ -505,21 +504,17 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
} else {
#endif /* CONFIG_TLSV12 */
- if (alg == SIGN_ALG_RSA) {
- hlen = MD5_MAC_LEN;
- if (conn->verify.md5_cert == NULL ||
- crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
- {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.md5_cert = NULL;
- crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
- conn->verify.sha1_cert = NULL;
- return -1;
- }
- hpos += MD5_MAC_LEN;
- } else
- crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
@@ -532,8 +527,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
}
conn->verify.sha1_cert = NULL;
- if (alg == SIGN_ALG_RSA)
- hlen += MD5_MAC_LEN;
+ hlen += MD5_MAC_LEN;
#ifdef CONFIG_TLSV12
}
diff --git a/contrib/wpa/src/tls/tlsv1_common.c b/contrib/wpa/src/tls/tlsv1_common.c
index d212862..dabc12a 100644
--- a/contrib/wpa/src/tls/tlsv1_common.c
+++ b/contrib/wpa/src/tls/tlsv1_common.c
@@ -1,6 +1,6 @@
/*
* TLSv1 common routines
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, 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 "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "x509v3.h"
@@ -33,6 +34,10 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
TLS_HASH_SHA },
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_DHE_RSA, TLS_CIPHER_DES_CBC,
+ TLS_HASH_SHA},
+ { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
@@ -41,24 +46,31 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
};
-#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+#define NUM_TLS_CIPHER_SUITES ARRAY_SIZE(tls_cipher_suites)
static const struct tls_cipher_data tls_ciphers[] = {
@@ -84,7 +96,7 @@ static const struct tls_cipher_data tls_ciphers[] = {
CRYPTO_CIPHER_ALG_AES }
};
-#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+#define NUM_TLS_CIPHER_DATA ARRAY_SIZE(tls_ciphers)
/**
@@ -320,3 +332,161 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
outlen);
}
+
+
+#ifdef CONFIG_TLSV12
+int tlsv12_key_x_server_params_hash(u16 tls_version,
+ const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash)
+{
+ size_t hlen;
+ struct crypto_hash *ctx;
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, 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;
+
+ return hlen;
+}
+#endif /* CONFIG_TLSV12 */
+
+
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash)
+{
+ u8 *hpos;
+ size_t hlen;
+ struct crypto_hash *ctx;
+
+ hpos = hash;
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, 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 = MD5_MAC_LEN;
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+ return -1;
+ hpos += hlen;
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, 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 = hash + sizeof(hash) - hpos;
+ if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
+ return -1;
+ hpos += hlen;
+ return hpos - hash;
+}
+
+
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+ const u8 *data, size_t data_len,
+ const u8 *pos, size_t len, u8 *alert)
+{
+ u8 *buf;
+ const u8 *end = pos + len;
+ const u8 *decrypted;
+ u16 slen;
+ size_t buflen;
+
+ if (end - pos < 2) {
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ slen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < slen) {
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ if (end - pos > slen) {
+ wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
+ pos + slen, end - pos - slen);
+ end = pos + slen;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+ if (pk == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ buflen = end - pos;
+ buf = os_malloc(end - pos);
+ if (buf == NULL) {
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+ if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+ decrypted = buf;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+ decrypted, buflen);
+
+#ifdef CONFIG_TLSV12
+ if (tls_version >= TLS_VERSION_1_2) {
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+ * H
+ */
+ if (buflen >= 19 + 32 &&
+ os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+ "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+ {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
+ decrypted = buf + 19;
+ buflen -= 19;
+ } else {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+ }
+#endif /* CONFIG_TLSV12 */
+
+ if (buflen != data_len ||
+ os_memcmp_const(decrypted, data, data_len) != 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+
+ os_free(buf);
+
+ return 0;
+}
diff --git a/contrib/wpa/src/tls/tlsv1_common.h b/contrib/wpa/src/tls/tlsv1_common.h
index f28c0cd..26e68af 100644
--- a/contrib/wpa/src/tls/tlsv1_common.h
+++ b/contrib/wpa/src/tls/tlsv1_common.h
@@ -1,6 +1,6 @@
/*
* TLSv1 common definitions
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -257,5 +257,16 @@ 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,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash);
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash);
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+ const u8 *data, size_t data_len,
+ const u8 *pos, size_t len, u8 *alert);
#endif /* TLSV1_COMMON_H */
diff --git a/contrib/wpa/src/tls/tlsv1_record.c b/contrib/wpa/src/tls/tlsv1_record.c
index 3bec3be..0c6897a 100644
--- a/contrib/wpa/src/tls/tlsv1_record.c
+++ b/contrib/wpa/src/tls/tlsv1_record.c
@@ -456,7 +456,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
return -1;
}
if (hlen != rl->hash_size ||
- os_memcmp(hash, out_data + plen, hlen) != 0 ||
+ os_memcmp_const(hash, out_data + plen, hlen) != 0 ||
force_mac_error) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
"received message (force_mac_error=%d)",
diff --git a/contrib/wpa/src/tls/tlsv1_server.c b/contrib/wpa/src/tls/tlsv1_server.c
index 2880309..93ae488 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-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, 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,31 @@
*/
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ va_start(ap, fmt);
+ vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+
+ wpa_printf(MSG_DEBUG, "TLSv1: %s", buf);
+ if (conn->log_cb)
+ conn->log_cb(conn->log_cb_ctx, buf);
+
+ os_free(buf);
+}
+
+
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
{
conn->alert_level = level;
@@ -250,8 +275,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
out_pos, &olen, &alert);
if (used < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
- "failed");
+ tlsv1_server_log(conn, "Record layer processing failed");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
@@ -265,14 +289,13 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (olen < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Alert "
- "underflow");
+ tlsv1_server_log(conn, "Alert underflow");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
- out_pos[0], out_pos[1]);
+ tlsv1_server_log(conn, "Received alert %d:%d",
+ out_pos[0], out_pos[1]);
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
/* Continue processing */
pos += used;
@@ -285,13 +308,23 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
}
if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
- "0x%x", pos[0]);
+ tlsv1_server_log(conn, "Unexpected content type 0x%x",
+ pos[0]);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH |
+ TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client ApplData received after invalid handshake");
+ conn->test_failure_reported = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -361,8 +394,15 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
count = 0;
suites = conn->cipher_suites;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
@@ -476,14 +516,56 @@ int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
+ case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC3-SHA";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ cipher = "ADH-RC4-MD5";
+ break;
+ case TLS_DH_anon_WITH_DES_CBC_SHA:
+ cipher = "ADH-DES-SHA";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ cipher = "ADH-DES-CBC3-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "AES-128-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "DHE-RSA-AES-128-SHA";
+ break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
break;
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- cipher = "AES-128-SHA";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ cipher = "DHE-RSA-AES-256-SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ cipher = "ADH-AES-256-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "AES-128-SHA256";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "AES-256-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "DHE-RSA-AES-128-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "DHE-RSA-AES-256-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ cipher = "ADH-AES-128-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ cipher = "ADH-AES-256-SHA256";
break;
default:
return -1;
@@ -618,3 +700,125 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
}
+
+
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+ void (*cb)(void *ctx, const char *msg), void *ctx)
+{
+ conn->log_cb = cb;
+ conn->log_cb_ctx = ctx;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
+{
+ conn->test_flags = flags;
+}
+
+
+static const u8 test_tls_prime15[1] = {
+ 15
+};
+
+static const u8 test_tls_prime511b[64] = {
+ 0x50, 0xfb, 0xf1, 0xae, 0x01, 0xf1, 0xfe, 0xe6,
+ 0xe1, 0xae, 0xdc, 0x1e, 0xbe, 0xfb, 0x9e, 0x58,
+ 0x9a, 0xd7, 0x54, 0x9d, 0x6b, 0xb3, 0x78, 0xe2,
+ 0x39, 0x7f, 0x30, 0x01, 0x25, 0xa1, 0xf9, 0x7c,
+ 0x55, 0x0e, 0xa1, 0x15, 0xcc, 0x36, 0x34, 0xbb,
+ 0x6c, 0x8b, 0x64, 0x45, 0x15, 0x7f, 0xd3, 0xe7,
+ 0x31, 0xc8, 0x8e, 0x56, 0x8e, 0x95, 0xdc, 0xea,
+ 0x9e, 0xdf, 0xf7, 0x56, 0xdd, 0xb0, 0x34, 0xdb
+};
+
+static const u8 test_tls_prime767b[96] = {
+ 0x4c, 0xdc, 0xb8, 0x21, 0x20, 0x9d, 0xe8, 0xa3,
+ 0x53, 0xd9, 0x1c, 0x18, 0xc1, 0x3a, 0x58, 0x67,
+ 0xa7, 0x85, 0xf9, 0x28, 0x9b, 0xce, 0xc0, 0xd1,
+ 0x05, 0x84, 0x61, 0x97, 0xb2, 0x86, 0x1c, 0xd0,
+ 0xd1, 0x96, 0x23, 0x29, 0x8c, 0xc5, 0x30, 0x68,
+ 0x3e, 0xf9, 0x05, 0xba, 0x60, 0xeb, 0xdb, 0xee,
+ 0x2d, 0xdf, 0x84, 0x65, 0x49, 0x87, 0x90, 0x2a,
+ 0xc9, 0x8e, 0x34, 0x63, 0x6d, 0x9a, 0x2d, 0x32,
+ 0x1c, 0x46, 0xd5, 0x4e, 0x20, 0x20, 0x90, 0xac,
+ 0xd5, 0x48, 0x79, 0x99, 0x0c, 0xe6, 0xed, 0xbf,
+ 0x79, 0xc2, 0x47, 0x50, 0x95, 0x38, 0x38, 0xbc,
+ 0xde, 0xb0, 0xd2, 0xe8, 0x97, 0xcb, 0x22, 0xbb
+};
+
+static const u8 test_tls_prime58[128] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0xc1, 0xba, 0xc8, 0x25, 0xbe, 0x2d, 0xf3
+};
+
+static const u8 test_tls_non_prime[] = {
+ /*
+ * This is not a prime and the value has the following factors:
+ * 13736783488716579923 * 16254860191773456563 * 18229434976173670763 *
+ * 11112313018289079419 * 10260802278580253339 * 12394009491575311499 *
+ * 12419059668711064739 * 14317973192687985827 * 10498605410533203179 *
+ * 16338688760390249003 * 11128963991123878883 * 12990532258280301419 *
+ * 3
+ */
+ 0x0C, 0x8C, 0x36, 0x9C, 0x6F, 0x71, 0x2E, 0xA7,
+ 0xAB, 0x32, 0xD3, 0x0F, 0x68, 0x3D, 0xB2, 0x6D,
+ 0x81, 0xDD, 0xC4, 0x84, 0x0D, 0x9C, 0x6E, 0x36,
+ 0x29, 0x70, 0xF3, 0x1E, 0x9A, 0x42, 0x0B, 0x67,
+ 0x82, 0x6B, 0xB1, 0xF2, 0xAF, 0x55, 0x28, 0xE7,
+ 0xDB, 0x67, 0x6C, 0xF7, 0x6B, 0xAC, 0xAC, 0xE5,
+ 0xF7, 0x9F, 0xD4, 0x63, 0x55, 0x70, 0x32, 0x7C,
+ 0x70, 0xFB, 0xAF, 0xB8, 0xEB, 0x37, 0xCF, 0x3F,
+ 0xFE, 0x94, 0x73, 0xF9, 0x7A, 0xC7, 0x12, 0x2E,
+ 0x9B, 0xB4, 0x7D, 0x08, 0x60, 0x83, 0x43, 0x52,
+ 0x83, 0x1E, 0xA5, 0xFC, 0xFA, 0x87, 0x12, 0xF4,
+ 0x64, 0xE2, 0xCE, 0x71, 0x17, 0x72, 0xB6, 0xAB
+};
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+ size_t *dh_p_len)
+{
+ *dh_p = conn->cred->dh_p;
+ *dh_p_len = conn->cred->dh_p_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_DHE_PRIME_511B) {
+ tlsv1_server_log(conn, "TESTING: Use short 511-bit prime with DHE");
+ *dh_p = test_tls_prime511b;
+ *dh_p_len = sizeof(test_tls_prime511b);
+ } else if (conn->test_flags & TLS_DHE_PRIME_767B) {
+ tlsv1_server_log(conn, "TESTING: Use short 767-bit prime with DHE");
+ *dh_p = test_tls_prime767b;
+ *dh_p_len = sizeof(test_tls_prime767b);
+ } else if (conn->test_flags & TLS_DHE_PRIME_15) {
+ tlsv1_server_log(conn, "TESTING: Use bogus 15 \"prime\" with DHE");
+ *dh_p = test_tls_prime15;
+ *dh_p_len = sizeof(test_tls_prime15);
+ } else if (conn->test_flags & TLS_DHE_PRIME_58B) {
+ tlsv1_server_log(conn, "TESTING: Use short 58-bit prime in long container with DHE");
+ *dh_p = test_tls_prime58;
+ *dh_p_len = sizeof(test_tls_prime58);
+ } else if (conn->test_flags & TLS_DHE_NON_PRIME) {
+ tlsv1_server_log(conn, "TESTING: Use claim non-prime as the DHE prime");
+ *dh_p = test_tls_non_prime;
+ *dh_p_len = sizeof(test_tls_non_prime);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+}
diff --git a/contrib/wpa/src/tls/tlsv1_server.h b/contrib/wpa/src/tls/tlsv1_server.h
index a18c69e..b2b28d1 100644
--- a/contrib/wpa/src/tls/tlsv1_server.h
+++ b/contrib/wpa/src/tls/tlsv1_server.h
@@ -45,4 +45,9 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
tlsv1_server_session_ticket_cb cb,
void *ctx);
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+ void (*cb)(void *ctx, const char *msg), void *ctx);
+
+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 1f61533..96d79b3 100644
--- a/contrib/wpa/src/tls/tlsv1_server_i.h
+++ b/contrib/wpa/src/tls/tlsv1_server_i.h
@@ -51,13 +51,24 @@ struct tlsv1_server {
tlsv1_server_session_ticket_cb session_ticket_cb;
void *session_ticket_cb_ctx;
+ void (*log_cb)(void *ctx, const char *msg);
+ void *log_cb_ctx;
+
int use_session_ticket;
u8 *dh_secret;
size_t dh_secret_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u32 test_flags;
+ int test_failure_reported;
+#endif /* CONFIG_TESTING_OPTIONS */
};
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
int tlsv1_server_derive_keys(struct tlsv1_server *conn,
const u8 *pre_master_secret,
@@ -67,5 +78,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
u8 description, size_t *out_len);
int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
const u8 *buf, size_t *len);
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+ size_t *dh_p_len);
#endif /* TLSV1_SERVER_I_H */
diff --git a/contrib/wpa/src/tls/tlsv1_server_read.c b/contrib/wpa/src/tls/tlsv1_server_read.c
index 6f6539b..0f237ba 100644
--- a/contrib/wpa/src/tls/tlsv1_server_read.c
+++ b/contrib/wpa/src/tls/tlsv1_server_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, 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,25 @@ static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
size_t *in_len);
+static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE |
+ TLS_DHE_PRIME_511B | TLS_DHE_PRIME_767B | TLS_DHE_PRIME_15 |
+ TLS_DHE_PRIME_58B | TLS_DHE_NON_PRIME)) &&
+ suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
+ suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
+ suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
+ suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
+ suite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ return 1;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return 0;
+}
+
+
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -38,8 +57,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
u16 ext_type, ext_len;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -53,13 +72,13 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ClientHello)", *pos);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientHello)",
+ *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
+ tlsv1_server_log(conn, "Received ClientHello");
pos++;
/* uint24 length */
len = WPA_GET_BE24(pos);
@@ -78,13 +97,13 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
if (end - pos < 2)
goto decode_error;
conn->client_version = WPA_GET_BE16(pos);
- wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
- conn->client_version >> 8, conn->client_version & 0xff);
+ tlsv1_server_log(conn, "Client version %d.%d",
+ conn->client_version >> 8,
+ conn->client_version & 0xff);
if (conn->client_version < TLS_VERSION_1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
- "ClientHello %u.%u",
- conn->client_version >> 8,
- conn->client_version & 0xff);
+ tlsv1_server_log(conn, "Unexpected protocol version in ClientHello %u.%u",
+ conn->client_version >> 8,
+ conn->client_version & 0xff);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
@@ -101,8 +120,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
conn->rl.tls_version = TLS_VERSION_1_1;
else
conn->rl.tls_version = conn->client_version;
- wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
- tls_version_str(conn->rl.tls_version));
+ tlsv1_server_log(conn, "Using TLS v%s",
+ tls_version_str(conn->rl.tls_version));
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
@@ -137,6 +156,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
cipher_suite = 0;
for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+ if (testing_cipher_suite_filter(conn, conn->cipher_suites[i]))
+ continue;
c = pos;
for (j = 0; j < num_suites; j++) {
u16 tmp = WPA_GET_BE16(c);
@@ -149,8 +170,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
}
pos += num_suites * 2;
if (!cipher_suite) {
- wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
- "available");
+ tlsv1_server_log(conn, "No supported cipher suite available");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
@@ -180,16 +200,15 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
compr_null_found = 1;
}
if (!compr_null_found) {
- wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
- "compression");
+ tlsv1_server_log(conn, "Client does not accept NULL compression");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
if (end - pos == 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
- "end of ClientHello: 0x%02x", *pos);
+ tlsv1_server_log(conn, "Unexpected extra octet in the end of ClientHello: 0x%02x",
+ *pos);
goto decode_error;
}
@@ -198,12 +217,11 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
ext_len = WPA_GET_BE16(pos);
pos += 2;
- wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
- "extensions", ext_len);
+ tlsv1_server_log(conn, "%u bytes of ClientHello extensions",
+ ext_len);
if (end - pos != ext_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
- "extension list length %u (expected %u)",
- ext_len, (unsigned int) (end - pos));
+ tlsv1_server_log(conn, "Invalid ClientHello extension list length %u (expected %u)",
+ ext_len, (unsigned int) (end - pos));
goto decode_error;
}
@@ -216,8 +234,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
while (pos < end) {
if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_type field");
+ tlsv1_server_log(conn, "Invalid extension_type field");
goto decode_error;
}
@@ -225,8 +242,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
pos += 2;
if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_data length field");
+ tlsv1_server_log(conn, "Invalid extension_data length field");
goto decode_error;
}
@@ -234,13 +250,12 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
pos += 2;
if (end - pos < ext_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_data field");
+ tlsv1_server_log(conn, "Invalid extension_data field");
goto decode_error;
}
- wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
- "type %u", ext_type);
+ tlsv1_server_log(conn, "ClientHello Extension type %u",
+ ext_type);
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
"Extension data", pos, ext_len);
@@ -260,14 +275,13 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
*in_len = end - in_data;
- wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
- "ServerHello");
+ tlsv1_server_log(conn, "ClientHello OK - proceed to ServerHello");
conn->state = SERVER_HELLO;
return 0;
decode_error:
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
+ tlsv1_server_log(conn, "Failed to decode ClientHello");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -284,8 +298,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
int reason;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -295,8 +309,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
- "(len=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short Certificate message (len=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -308,9 +322,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Unexpected Certificate message length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -318,8 +331,7 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
if (conn->verify_peer) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
- "Certificate");
+ tlsv1_server_log(conn, "Client did not include Certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -329,17 +341,15 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
in_len);
}
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected Certificate/"
- "ClientKeyExchange)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected Certificate/ClientKeyExchange)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG,
- "TLSv1: Received Certificate (certificate_list len %lu)",
- (unsigned long) len);
+ tlsv1_server_log(conn, "Received Certificate (certificate_list len %lu)",
+ (unsigned long) len);
/*
* opaque ASN.1Cert<2^24-1>;
@@ -352,8 +362,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
end = pos + len;
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
- "(left=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short Certificate (left=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -363,10 +373,9 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
pos += 3;
if ((size_t) (end - pos) != list_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
- "length (len=%lu left=%lu)",
- (unsigned long) list_len,
- (unsigned long) (end - pos));
+ tlsv1_server_log(conn, "Unexpected certificate_list length (len=%lu left=%lu)",
+ (unsigned long) list_len,
+ (unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -375,8 +384,7 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
idx = 0;
while (pos < end) {
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "certificate_list");
+ tlsv1_server_log(conn, "Failed to parse certificate_list");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
@@ -387,25 +395,23 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
pos += 3;
if ((size_t) (end - pos) < cert_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
- "length (len=%lu left=%lu)",
- (unsigned long) cert_len,
- (unsigned long) (end - pos));
+ tlsv1_server_log(conn, "Unexpected certificate length (len=%lu left=%lu)",
+ (unsigned long) cert_len,
+ (unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
- (unsigned long) idx, (unsigned long) cert_len);
+ tlsv1_server_log(conn, "Certificate %lu (len %lu)",
+ (unsigned long) idx, (unsigned long) cert_len);
if (idx == 0) {
crypto_public_key_free(conn->client_rsa_key);
if (tls_parse_cert(pos, cert_len,
&conn->client_rsa_key)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
+ tlsv1_server_log(conn, "Failed to parse the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
@@ -415,8 +421,7 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
cert = x509_certificate_parse(pos, cert_len);
if (cert == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
+ tlsv1_server_log(conn, "Failed to parse the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
@@ -436,8 +441,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
&reason, 0) < 0) {
int tls_reason;
- wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
- "validation failed (reason=%d)", reason);
+ tlsv1_server_log(conn, "Server certificate chain validation failed (reason=%d)",
+ reason);
switch (reason) {
case X509_VALIDATE_BAD_CERTIFICATE:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -494,9 +499,8 @@ static int tls_process_client_key_exchange_rsa(
encr_len = WPA_GET_BE16(pos);
pos += 2;
if (pos + encr_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
- "format: encr_len=%u left=%u",
- encr_len, (unsigned int) (end - pos));
+ tlsv1_server_log(conn, "Invalid ClientKeyExchange format: encr_len=%u left=%u",
+ encr_len, (unsigned int) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -539,15 +543,13 @@ static int tls_process_client_key_exchange_rsa(
}
if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
- "length %lu", (unsigned long) outlen);
+ tlsv1_server_log(conn, "Unexpected PreMasterSecret length %lu",
+ (unsigned long) outlen);
use_random = 1;
}
if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
- "ClientKeyExchange does not match with version in "
- "ClientHello");
+ tlsv1_server_log(conn, "Client version in ClientKeyExchange does not match with version in ClientHello");
use_random = 1;
}
@@ -582,7 +584,7 @@ static int tls_process_client_key_exchange_rsa(
}
-static int tls_process_client_key_exchange_dh_anon(
+static int tls_process_client_key_exchange_dh(
struct tlsv1_server *conn, const u8 *pos, const u8 *end)
{
const u8 *dh_yc;
@@ -590,6 +592,8 @@ static int tls_process_client_key_exchange_dh_anon(
u8 *shared;
size_t shared_len;
int res;
+ const u8 *dh_p;
+ size_t dh_p_len;
/*
* struct {
@@ -600,6 +604,7 @@ static int tls_process_client_key_exchange_dh_anon(
* } ClientDiffieHellmanPublic;
*/
+ tlsv1_server_log(conn, "ClientDiffieHellmanPublic received");
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
pos, end - pos);
@@ -612,8 +617,7 @@ static int tls_process_client_key_exchange_dh_anon(
}
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
- "length");
+ tlsv1_server_log(conn, "Invalid client public value length");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -622,9 +626,9 @@ static int tls_process_client_key_exchange_dh_anon(
dh_yc_len = WPA_GET_BE16(pos);
dh_yc = pos + 2;
- if (dh_yc + dh_yc_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
- "(length %d)", dh_yc_len);
+ if (dh_yc_len > end - dh_yc) {
+ tlsv1_server_log(conn, "Client public value overflow (length %d)",
+ dh_yc_len);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -641,7 +645,9 @@ static int tls_process_client_key_exchange_dh_anon(
return -1;
}
- shared_len = conn->cred->dh_p_len;
+ tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
+
+ shared_len = dh_p_len;
shared = os_malloc(shared_len);
if (shared == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
@@ -653,8 +659,7 @@ static int tls_process_client_key_exchange_dh_anon(
/* shared = Yc^secret mod p */
if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
- conn->dh_secret_len,
- conn->cred->dh_p, conn->cred->dh_p_len,
+ conn->dh_secret_len, dh_p, dh_p_len,
shared, &shared_len)) {
os_free(shared);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -695,8 +700,8 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
const struct tls_cipher_suite *suite;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -706,8 +711,8 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
- "(Left=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short ClientKeyExchange (Left=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -719,9 +724,8 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Mismatch in ClientKeyExchange length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -730,14 +734,14 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ClientKeyExchange)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientKeyExchange)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
+ tlsv1_server_log(conn, "Received ClientKeyExchange");
wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
@@ -747,11 +751,11 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
else
keyx = suite->key_exchange;
- if (keyx == TLS_KEY_X_DH_anon &&
- tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
+ if ((keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) &&
+ tls_process_client_key_exchange_dh(conn, pos, end) < 0)
return -1;
- if (keyx != TLS_KEY_X_DH_anon &&
+ if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA &&
tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
return -1;
@@ -769,15 +773,13 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
const u8 *pos, *end;
size_t left, len;
u8 type;
- size_t hlen, buflen;
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
- u16 slen;
+ size_t hlen;
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+ u8 alert;
if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
if (conn->verify_peer) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
- "CertificateVerify");
+ tlsv1_server_log(conn, "Client did not include CertificateVerify");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -788,8 +790,8 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
}
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -799,8 +801,8 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
- "message (len=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short CertificateVerify message (len=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -812,9 +814,8 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
- "message length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Unexpected CertificateVerify message length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -823,14 +824,14 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected CertificateVerify)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected CertificateVerify)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
+ tlsv1_server_log(conn, "Received CertificateVerify");
/*
* struct {
@@ -881,21 +882,17 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
} else {
#endif /* CONFIG_TLSV12 */
- if (alg == SIGN_ALG_RSA) {
- hlen = MD5_MAC_LEN;
- if (conn->verify.md5_cert == NULL ||
- crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
- {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.md5_cert = NULL;
- crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
- conn->verify.sha1_cert = NULL;
- return -1;
- }
- hpos += MD5_MAC_LEN;
- } else
- crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
@@ -908,8 +905,7 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
}
conn->verify.sha1_cert = NULL;
- if (alg == SIGN_ALG_RSA)
- hlen += MD5_MAC_LEN;
+ hlen += MD5_MAC_LEN;
#ifdef CONFIG_TLSV12
}
@@ -917,90 +913,13 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
- if (end - pos < 2) {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- slen = WPA_GET_BE16(pos);
- pos += 2;
- if (end - pos < slen) {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
+ if (tls_verify_signature(conn->rl.tls_version, conn->client_rsa_key,
+ hash, hlen, pos, end - pos, &alert) < 0) {
+ tlsv1_server_log(conn, "Invalid Signature in CertificateVerify");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
- if (conn->client_rsa_key == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
- "signature");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- buflen = end - pos;
- buf = os_malloc(end - pos);
- if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
- pos, end - pos, buf, &buflen) < 0)
- {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
-
- wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
- buf, buflen);
-
-#ifdef CONFIG_TLSV12
- if (conn->rl.tls_version >= TLS_VERSION_1_2) {
- /*
- * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
- *
- * DigestInfo ::= SEQUENCE {
- * digestAlgorithm DigestAlgorithm,
- * digest OCTET STRING
- * }
- *
- * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
- *
- * DER encoded DigestInfo for SHA256 per RFC 3447:
- * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
- * H
- */
- if (buflen >= 19 + 32 &&
- os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
- "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
- {
- wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
- "SHA-256");
- os_memmove(buf, buf + 19, buflen - 19);
- buflen -= 19;
- } else {
- wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
- "DigestInfo");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
- }
-#endif /* CONFIG_TLSV12 */
-
- if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
- "CertificateVerify - did not match with calculated "
- "hash");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
-
- os_free(buf);
-
*in_len = end - in_data;
conn->state = CHANGE_CIPHER_SPEC;
@@ -1017,8 +936,8 @@ static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
size_t left;
if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected ChangeCipherSpec; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -1028,21 +947,21 @@ static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
left = *in_len;
if (left < 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+ tlsv1_server_log(conn, "Too short ChangeCipherSpec");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
if (*pos != TLS_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received data 0x%x", *pos);
+ tlsv1_server_log(conn, "Expected ChangeCipherSpec; received data 0x%x",
+ *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+ tlsv1_server_log(conn, "Received ChangeCipherSpec");
if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
"for record layer");
@@ -1067,9 +986,48 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
u8 verify_data[TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_15) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after bogus DHE \"prime\" 15");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_58B) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after short 58-bit DHE prime in long container");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_511B) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-WARNING: Client Finished received after short 511-bit DHE prime (insecure)");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_767B) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after 767-bit DHE prime (relatively insecure)");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_NON_PRIME) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after non-prime claimed as DHE prime");
+ conn->test_failure_reported = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Finished; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -1079,9 +1037,8 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
- "Finished",
- (unsigned long) left);
+ tlsv1_server_log(conn, "Too short record (left=%lu) forFinished",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -1101,18 +1058,16 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
- "(len=%lu > left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Too short buffer for Finished (len=%lu > left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (len != TLS_VERIFY_DATA_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
- "in Finished: %lu (expected %d)",
- (unsigned long) len, TLS_VERIFY_DATA_LEN);
+ tlsv1_server_log(conn, "Unexpected verify_data length in Finished: %lu (expected %d)",
+ (unsigned long) len, TLS_VERIFY_DATA_LEN);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -1174,19 +1129,18 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
verify_data, TLS_VERIFY_DATA_LEN);
- if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
- wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ tlsv1_server_log(conn, "Mismatch in verify_data");
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+ tlsv1_server_log(conn, "Received Finished");
*in_len = end - in_data;
if (conn->use_session_ticket) {
/* Abbreviated handshake using session ticket; RFC 4507 */
- wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
- "successfully");
+ tlsv1_server_log(conn, "Abbreviated handshake completed successfully");
conn->state = ESTABLISHED;
} else {
/* Full handshake */
@@ -1202,13 +1156,12 @@ int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
{
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (*len < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+ tlsv1_server_log(conn, "Alert underflow");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
- buf[0], buf[1]);
+ tlsv1_server_log(conn, "Received alert %d:%d", buf[0], buf[1]);
*len = 2;
conn->state = FAILED;
return -1;
@@ -1240,9 +1193,8 @@ int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
return -1;
break;
default:
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
- "while processing received message",
- conn->state);
+ tlsv1_server_log(conn, "Unexpected state %d while processing received message",
+ conn->state);
return -1;
}
diff --git a/contrib/wpa/src/tls/tlsv1_server_write.c b/contrib/wpa/src/tls/tlsv1_server_write.c
index 6d8e55ed..15e6692 100644
--- a/contrib/wpa/src/tls/tlsv1_server_write.c
+++ b/contrib/wpa/src/tls/tlsv1_server_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -48,7 +48,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+ tlsv1_server_log(conn, "Send ServerHello");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -104,8 +104,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
conn->client_random, conn->server_random,
conn->master_secret);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
- "indicated failure");
+ tlsv1_server_log(conn, "SessionTicket callback indicated failure");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_HANDSHAKE_FAILURE);
return -1;
@@ -170,7 +169,7 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+ tlsv1_server_log(conn, "Send Certificate");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -245,10 +244,12 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
{
tls_key_exchange keyx;
const struct tls_cipher_suite *suite;
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
size_t rlen;
u8 *dh_ys;
size_t dh_ys_len;
+ const u8 *dh_p;
+ size_t dh_p_len;
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
if (suite == NULL)
@@ -261,8 +262,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
return 0;
}
- if (keyx != TLS_KEY_X_DH_anon) {
- /* TODO? */
+ if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
"supported with key exchange type %d", keyx);
return -1;
@@ -275,8 +275,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
return -1;
}
+ tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
+
os_free(conn->dh_secret);
- conn->dh_secret_len = conn->cred->dh_p_len;
+ conn->dh_secret_len = dh_p_len;
conn->dh_secret = os_malloc(conn->dh_secret_len);
if (conn->dh_secret == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
@@ -295,8 +297,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
return -1;
}
- if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
- 0)
+ if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0)
conn->dh_secret[0] = 0; /* make sure secret < p */
pos = conn->dh_secret;
@@ -311,7 +312,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
conn->dh_secret, conn->dh_secret_len);
/* Ys = g^secret mod p */
- dh_ys_len = conn->cred->dh_p_len;
+ dh_ys_len = dh_p_len;
dh_ys = os_malloc(dh_ys_len);
if (dh_ys == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
@@ -322,8 +323,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
}
if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
conn->dh_secret, conn->dh_secret_len,
- conn->cred->dh_p, conn->cred->dh_p_len,
- dh_ys, &dh_ys_len)) {
+ dh_p, dh_p_len, dh_ys, &dh_ys_len)) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(dh_ys);
@@ -354,7 +354,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+ tlsv1_server_log(conn, "Send ServerKeyExchange");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -369,8 +369,9 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos += 3;
/* body - ServerDHParams */
+ server_params = pos;
/* dh_p */
- if (pos + 2 + conn->cred->dh_p_len > end) {
+ if (pos + 2 + dh_p_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_p");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -378,10 +379,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
os_free(dh_ys);
return -1;
}
- WPA_PUT_BE16(pos, conn->cred->dh_p_len);
+ WPA_PUT_BE16(pos, dh_p_len);
pos += 2;
- os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
- pos += conn->cred->dh_p_len;
+ os_memcpy(pos, dh_p, dh_p_len);
+ pos += dh_p_len;
/* dh_g */
if (pos + 2 + conn->cred->dh_g_len > end) {
@@ -412,6 +413,138 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos += dh_ys_len;
os_free(dh_ys);
+ /*
+ * select (SignatureAlgorithm)
+ * { case anonymous: struct { };
+ * case rsa:
+ * digitally-signed struct {
+ * opaque md5_hash[16];
+ * opaque sha_hash[20];
+ * };
+ * case dsa:
+ * digitally-signed struct {
+ * opaque sha_hash[20];
+ * };
+ * } Signature;
+ *
+ * md5_hash
+ * MD5(ClientHello.random + ServerHello.random + ServerParams);
+ *
+ * sha_hash
+ * SHA(ClientHello.random + ServerHello.random + ServerParams);
+ */
+
+ if (keyx == TLS_KEY_X_DHE_RSA) {
+ u8 hash[100];
+ u8 *signed_start;
+ size_t clen;
+ int hlen;
+
+ 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->server_random, server_params,
+ pos - server_params, hash + 19);
+
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used
+ * signature and hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ if (hlen < 0 || pos + 2 > end) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ *pos++ = TLS_HASH_ALG_SHA256;
+ *pos++ = TLS_SIGN_ALG_RSA;
+
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
+ * 04 20 || H
+ */
+ hlen += 19;
+ os_memcpy(hash,
+ "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+ "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+
+#else /* CONFIG_TLSV12 */
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+#endif /* CONFIG_TLSV12 */
+ } else {
+ hlen = tls_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ pos - server_params, hash);
+ }
+
+ if (hlen < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
+ hash, hlen);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
+ tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
+ hash[hlen - 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /*
+ * RFC 2246, 4.7:
+ * In digital signing, one-way hash functions are used as input
+ * for a signing algorithm. A digitally-signed element is
+ * encoded as an opaque vector <0..2^16-1>, where the length is
+ * specified by the signing algorithm and key.
+ *
+ * In RSA signing, a 36-byte structure of two hashes (one SHA
+ * and one MD5) is signed (encrypted with the private key). It
+ * is encoded with PKCS #1 block type 0 or type 1 as described
+ * in [PKCS1].
+ */
+ signed_start = pos; /* length to be filled */
+ pos += 2;
+ clen = end - pos;
+ if (conn->cred == NULL ||
+ crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+ pos, &clen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE16(signed_start, clen);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
+ tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
+ pos[clen - 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ pos += clen;
+ }
+
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
@@ -445,7 +578,7 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+ tlsv1_server_log(conn, "Send CertificateRequest");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -505,7 +638,7 @@ static int tls_write_server_hello_done(struct tlsv1_server *conn,
size_t rlen;
u8 payload[4];
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+ tlsv1_server_log(conn, "Send ServerHelloDone");
/* opaque fragment[TLSPlaintext.length] */
@@ -541,7 +674,7 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
size_t rlen;
u8 payload[1];
- wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+ tlsv1_server_log(conn, "Send ChangeCipherSpec");
payload[0] = TLS_CHANGE_CIPHER_SPEC;
@@ -578,7 +711,7 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+ tlsv1_server_log(conn, "Send Finished");
/* Encrypted Handshake Message: Finished */
@@ -635,6 +768,12 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
+ tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
+ verify_data[1 + 3 + 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
/* Handshake */
pos = hs_start = verify_data;
@@ -736,7 +875,7 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
*out_len = pos - msg;
- wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+ tlsv1_server_log(conn, "Handshake completed successfully");
conn->state = ESTABLISHED;
return msg;
@@ -755,8 +894,8 @@ u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
/* Abbreviated handshake was already completed. */
return NULL;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
- "generating reply", conn->state);
+ tlsv1_server_log(conn, "Unexpected state %d while generating reply",
+ conn->state);
return NULL;
}
}
@@ -767,7 +906,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
{
u8 *alert, *pos, *length;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+ tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
*out_len = 0;
alert = os_malloc(10);
diff --git a/contrib/wpa/src/tls/x509v3.c b/contrib/wpa/src/tls/x509v3.c
index 87c5178..742af32 100644
--- a/contrib/wpa/src/tls/x509v3.c
+++ b/contrib/wpa/src/tls/x509v3.c
@@ -443,17 +443,16 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
return -1;
}
- val = os_malloc(hdr.length + 1);
+ val = dup_binstr(hdr.payload, hdr.length);
if (val == NULL) {
x509_free_name(name);
return -1;
}
- os_memcpy(val, hdr.payload, hdr.length);
- val[hdr.length] = '\0';
if (os_strlen(val) != hdr.length) {
wpa_printf(MSG_INFO, "X509: Reject certificate with "
"embedded NUL byte in a string (%s[NUL])",
val);
+ os_free(val);
x509_free_name(name);
return -1;
}
@@ -513,7 +512,7 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len)
ret = os_snprintf(pos, end - pos, "%s=%s, ",
x509_name_attr_str(name->attr[i].type),
name->attr[i].value);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
goto done;
pos += ret;
}
@@ -528,7 +527,7 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len)
if (name->email) {
ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
name->email);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
goto done;
pos += ret;
}
@@ -1349,7 +1348,8 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
/* TODO: parse UniqueIdentifier ::= BIT STRING */
- if (hdr.payload + hdr.length == end)
+ pos = hdr.payload + hdr.length;
+ if (pos == end)
return 0;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
@@ -1367,7 +1367,8 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
/* TODO: parse UniqueIdentifier ::= BIT STRING */
- if (hdr.payload + hdr.length == end)
+ pos = hdr.payload + hdr.length;
+ if (pos == end)
return 0;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
@@ -1775,13 +1776,22 @@ skip_digest_oid:
}
if (hdr.length != hash_len ||
- os_memcmp(hdr.payload, hash, hdr.length) != 0) {
+ os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
"with calculated tbsCertificate hash");
os_free(data);
return -1;
}
+ if (hdr.payload + hdr.length < data + data_len) {
+ wpa_hexdump(MSG_INFO,
+ "X509: Extra data after certificate signature hash",
+ hdr.payload + hdr.length,
+ data + data_len - hdr.payload - hdr.length);
+ os_free(data);
+ return -1;
+ }
+
os_free(data);
wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
diff --git a/contrib/wpa/src/utils/base64.c b/contrib/wpa/src/utils/base64.c
index af1307f..d44f290 100644
--- a/contrib/wpa/src/utils/base64.c
+++ b/contrib/wpa/src/utils/base64.c
@@ -48,9 +48,11 @@ 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];
- *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
- *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+ *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];
in += 3;
line_len += 4;
@@ -61,14 +63,14 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
}
if (end - in) {
- *pos++ = base64_table[in[0] >> 2];
+ *pos++ = base64_table[(in[0] >> 2) & 0x3f];
if (end - in == 1) {
- *pos++ = base64_table[(in[0] & 0x03) << 4];
+ *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
*pos++ = '=';
} else {
- *pos++ = base64_table[((in[0] & 0x03) << 4) |
- (in[1] >> 4)];
- *pos++ = base64_table[(in[1] & 0x0f) << 2];
+ *pos++ = base64_table[(((in[0] & 0x03) << 4) |
+ (in[1] >> 4)) & 0x3f];
+ *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
}
*pos++ = '=';
line_len += 4;
diff --git a/contrib/wpa/src/utils/bitfield.c b/contrib/wpa/src/utils/bitfield.c
new file mode 100644
index 0000000..8dcec39
--- /dev/null
+++ b/contrib/wpa/src/utils/bitfield.c
@@ -0,0 +1,89 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, 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 "bitfield.h"
+
+
+struct bitfield {
+ u8 *bits;
+ size_t max_bits;
+};
+
+
+struct bitfield * bitfield_alloc(size_t max_bits)
+{
+ struct bitfield *bf;
+
+ bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8);
+ if (bf == NULL)
+ return NULL;
+ bf->bits = (u8 *) (bf + 1);
+ bf->max_bits = max_bits;
+ return bf;
+}
+
+
+void bitfield_free(struct bitfield *bf)
+{
+ os_free(bf);
+}
+
+
+void bitfield_set(struct bitfield *bf, size_t bit)
+{
+ if (bit >= bf->max_bits)
+ return;
+ bf->bits[bit / 8] |= BIT(bit % 8);
+}
+
+
+void bitfield_clear(struct bitfield *bf, size_t bit)
+{
+ if (bit >= bf->max_bits)
+ return;
+ bf->bits[bit / 8] &= ~BIT(bit % 8);
+}
+
+
+int bitfield_is_set(struct bitfield *bf, size_t bit)
+{
+ if (bit >= bf->max_bits)
+ return 0;
+ return !!(bf->bits[bit / 8] & BIT(bit % 8));
+}
+
+
+static int first_zero(u8 val)
+{
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (!(val & 0x01))
+ return i;
+ val >>= 1;
+ }
+ return -1;
+}
+
+
+int bitfield_get_first_zero(struct bitfield *bf)
+{
+ size_t i;
+ for (i = 0; i < (bf->max_bits + 7) / 8; i++) {
+ if (bf->bits[i] != 0xff)
+ break;
+ }
+ if (i == (bf->max_bits + 7) / 8)
+ return -1;
+ i = i * 8 + first_zero(bf->bits[i]);
+ if (i >= bf->max_bits)
+ return -1;
+ return i;
+}
diff --git a/contrib/wpa/src/utils/bitfield.h b/contrib/wpa/src/utils/bitfield.h
new file mode 100644
index 0000000..7050a20
--- /dev/null
+++ b/contrib/wpa/src/utils/bitfield.h
@@ -0,0 +1,21 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BITFIELD_H
+#define BITFIELD_H
+
+struct bitfield;
+
+struct bitfield * bitfield_alloc(size_t max_bits);
+void bitfield_free(struct bitfield *bf);
+void bitfield_set(struct bitfield *bf, size_t bit);
+void bitfield_clear(struct bitfield *bf, size_t bit);
+int bitfield_is_set(struct bitfield *bf, size_t bit);
+int bitfield_get_first_zero(struct bitfield *bf);
+
+#endif /* BITFIELD_H */
diff --git a/contrib/wpa/src/utils/browser-android.c b/contrib/wpa/src/utils/browser-android.c
new file mode 100644
index 0000000..9ce1a5c
--- /dev/null
+++ b/contrib/wpa/src/utils/browser-android.c
@@ -0,0 +1,128 @@
+/*
+ * Hotspot 2.0 client - Web browser using Android browser
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "wps/http_server.h"
+#include "browser.h"
+
+
+struct browser_data {
+ int success;
+};
+
+
+static void browser_timeout(void *eloop_data, void *user_ctx)
+{
+ wpa_printf(MSG_INFO, "Timeout on waiting browser interaction to "
+ "complete");
+ eloop_terminate();
+}
+
+
+static void http_req(void *ctx, struct http_request *req)
+{
+ struct browser_data *data = ctx;
+ struct wpabuf *resp;
+ const char *url;
+ int done = 0;
+
+ url = http_request_get_uri(req);
+ wpa_printf(MSG_INFO, "Browser response received: %s", url);
+
+ if (os_strcmp(url, "/") == 0) {
+ data->success = 1;
+ done = 1;
+ } else if (os_strncmp(url, "/osu/", 5) == 0) {
+ data->success = atoi(url + 5);
+ done = 1;
+ }
+
+ resp = wpabuf_alloc(1);
+ if (resp == NULL) {
+ http_request_deinit(req);
+ if (done)
+ eloop_terminate();
+ return;
+ }
+
+ if (done) {
+ eloop_cancel_timeout(browser_timeout, NULL, NULL);
+ eloop_register_timeout(0, 500000, browser_timeout, &data, NULL);
+ }
+
+ http_request_send_and_deinit(req, resp);
+}
+
+
+int hs20_web_browser(const char *url)
+{
+ struct http_server *http;
+ struct in_addr addr;
+ struct browser_data data;
+ pid_t pid;
+
+ wpa_printf(MSG_INFO, "Launching Android browser to %s", url);
+
+ os_memset(&data, 0, sizeof(data));
+
+ if (eloop_init() < 0) {
+ wpa_printf(MSG_ERROR, "eloop_init failed");
+ return -1;
+ }
+ addr.s_addr = htonl((127 << 24) | 1);
+ http = http_server_init(&addr, 12345, http_req, &data);
+ if (http == NULL) {
+ wpa_printf(MSG_ERROR, "http_server_init failed");
+ eloop_destroy();
+ return -1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
+ http_server_deinit(http);
+ eloop_destroy();
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ char *argv[9];
+
+ argv[0] = "browser-android";
+ argv[1] = "start";
+ argv[2] = "-a";
+ 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;
+
+ execv("/system/bin/am", argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ exit(0);
+ return -1;
+ }
+
+ eloop_register_timeout(30, 0, browser_timeout, &data, NULL);
+ eloop_run();
+ eloop_cancel_timeout(browser_timeout, &data, NULL);
+ http_server_deinit(http);
+ eloop_destroy();
+
+ wpa_printf(MSG_INFO, "Closing Android browser");
+ if (system("/system/bin/input keyevent KEYCODE_HOME") != 0) {
+ wpa_printf(MSG_INFO, "Failed to inject keyevent");
+ }
+
+ return data.success;
+}
diff --git a/contrib/wpa/src/utils/browser-system.c b/contrib/wpa/src/utils/browser-system.c
new file mode 100644
index 0000000..aed3970
--- /dev/null
+++ b/contrib/wpa/src/utils/browser-system.c
@@ -0,0 +1,119 @@
+/*
+ * Hotspot 2.0 client - Web browser using system browser
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "wps/http_server.h"
+#include "browser.h"
+
+
+struct browser_data {
+ int success;
+};
+
+
+static void browser_timeout(void *eloop_data, void *user_ctx)
+{
+ wpa_printf(MSG_INFO, "Timeout on waiting browser interaction to "
+ "complete");
+ eloop_terminate();
+}
+
+
+static void http_req(void *ctx, struct http_request *req)
+{
+ struct browser_data *data = ctx;
+ struct wpabuf *resp;
+ const char *url;
+ int done = 0;
+
+ url = http_request_get_uri(req);
+ wpa_printf(MSG_INFO, "Browser response received: %s", url);
+
+ if (os_strcmp(url, "/") == 0) {
+ data->success = 1;
+ done = 1;
+ } else if (os_strncmp(url, "/osu/", 5) == 0) {
+ data->success = atoi(url + 5);
+ done = 1;
+ }
+
+ resp = wpabuf_alloc(1);
+ if (resp == NULL) {
+ http_request_deinit(req);
+ if (done)
+ eloop_terminate();
+ return;
+ }
+
+ if (done) {
+ eloop_cancel_timeout(browser_timeout, NULL, NULL);
+ eloop_register_timeout(0, 500000, browser_timeout, &data, NULL);
+ }
+
+ http_request_send_and_deinit(req, resp);
+}
+
+
+int hs20_web_browser(const char *url)
+{
+ struct http_server *http;
+ struct in_addr addr;
+ struct browser_data data;
+ pid_t pid;
+
+ wpa_printf(MSG_INFO, "Launching system browser to %s", url);
+
+ os_memset(&data, 0, sizeof(data));
+
+ if (eloop_init() < 0) {
+ wpa_printf(MSG_ERROR, "eloop_init failed");
+ return -1;
+ }
+ addr.s_addr = htonl((127 << 24) | 1);
+ http = http_server_init(&addr, 12345, http_req, &data);
+ if (http == NULL) {
+ wpa_printf(MSG_ERROR, "http_server_init failed");
+ eloop_destroy();
+ return -1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
+ http_server_deinit(http);
+ eloop_destroy();
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ char *argv[3];
+
+ argv[0] = "browser-system";
+ argv[1] = (void *) url;
+ argv[2] = NULL;
+
+ execv("/usr/bin/x-www-browser", argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ exit(0);
+ return -1;
+ }
+
+ eloop_register_timeout(120, 0, browser_timeout, &data, NULL);
+ eloop_run();
+ eloop_cancel_timeout(browser_timeout, &data, NULL);
+ http_server_deinit(http);
+ eloop_destroy();
+
+ /* TODO: Close browser */
+
+ return data.success;
+}
diff --git a/contrib/wpa/src/utils/browser-wpadebug.c b/contrib/wpa/src/utils/browser-wpadebug.c
new file mode 100644
index 0000000..5fc40fa
--- /dev/null
+++ b/contrib/wpa/src/utils/browser-wpadebug.c
@@ -0,0 +1,136 @@
+/*
+ * Hotspot 2.0 client - Web browser using wpadebug on Android
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "wps/http_server.h"
+#include "browser.h"
+
+
+struct browser_data {
+ int success;
+};
+
+
+static void browser_timeout(void *eloop_data, void *user_ctx)
+{
+ wpa_printf(MSG_INFO, "Timeout on waiting browser interaction to "
+ "complete");
+ eloop_terminate();
+}
+
+
+static void http_req(void *ctx, struct http_request *req)
+{
+ struct browser_data *data = ctx;
+ struct wpabuf *resp;
+ const char *url;
+ int done = 0;
+
+ url = http_request_get_uri(req);
+ wpa_printf(MSG_INFO, "Browser response received: %s", url);
+
+ if (os_strcmp(url, "/") == 0) {
+ data->success = 1;
+ done = 1;
+ } else if (os_strncmp(url, "/osu/", 5) == 0) {
+ data->success = atoi(url + 5);
+ done = 1;
+ }
+
+ resp = wpabuf_alloc(100);
+ if (resp == NULL) {
+ http_request_deinit(req);
+ if (done)
+ eloop_terminate();
+ return;
+ }
+ wpabuf_put_str(resp, "User input completed");
+
+ if (done) {
+ eloop_cancel_timeout(browser_timeout, NULL, NULL);
+ eloop_register_timeout(0, 500000, browser_timeout, &data, NULL);
+ }
+
+ http_request_send_and_deinit(req, resp);
+}
+
+
+int hs20_web_browser(const char *url)
+{
+ struct http_server *http;
+ struct in_addr addr;
+ struct browser_data data;
+ pid_t pid;
+
+ wpa_printf(MSG_INFO, "Launching wpadebug browser to %s", url);
+
+ os_memset(&data, 0, sizeof(data));
+
+ if (eloop_init() < 0) {
+ wpa_printf(MSG_ERROR, "eloop_init failed");
+ return -1;
+ }
+ addr.s_addr = htonl((127 << 24) | 1);
+ http = http_server_init(&addr, 12345, http_req, &data);
+ if (http == NULL) {
+ wpa_printf(MSG_ERROR, "http_server_init failed");
+ eloop_destroy();
+ return -1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
+ http_server_deinit(http);
+ eloop_destroy();
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ char *argv[12];
+
+ argv[0] = "browser-wpadebug";
+ argv[1] = "start";
+ argv[2] = "-a";
+ argv[3] = "android.action.MAIN";
+ argv[4] = "-c";
+ argv[5] = "android.intent.category.LAUNCHER";
+ argv[6] = "-n";
+ argv[7] = "w1.fi.wpadebug/.WpaWebViewActivity";
+ argv[8] = "-e";
+ argv[9] = "w1.fi.wpadebug.URL";
+ argv[10] = (void *) url;
+ argv[11] = NULL;
+
+ execv("/system/bin/am", argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ exit(0);
+ return -1;
+ }
+
+ eloop_register_timeout(300, 0, browser_timeout, &data, NULL);
+ eloop_run();
+ eloop_cancel_timeout(browser_timeout, &data, NULL);
+ http_server_deinit(http);
+ eloop_destroy();
+
+ wpa_printf(MSG_INFO, "Closing Android browser");
+ if (os_exec("/system/bin/am",
+ "start -a android.action.MAIN "
+ "-c android.intent.category.LAUNCHER "
+ "-n w1.fi.wpadebug/.WpaWebViewActivity "
+ "-e w1.fi.wpadebug.URL FINISH", 1) != 0) {
+ wpa_printf(MSG_INFO, "Failed to close wpadebug browser");
+ }
+
+ return data.success;
+}
diff --git a/contrib/wpa/src/utils/browser.c b/contrib/wpa/src/utils/browser.c
new file mode 100644
index 0000000..9cf6152
--- /dev/null
+++ b/contrib/wpa/src/utils/browser.c
@@ -0,0 +1,219 @@
+/*
+ * Hotspot 2.0 client - Web browser using WebKit
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <webkit/webkit.h>
+
+#include "common.h"
+#include "browser.h"
+
+
+struct browser_context {
+ GtkWidget *win;
+ int success;
+ int progress;
+ char *hover_link;
+ char *title;
+};
+
+static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
+{
+ wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
+ gtk_main_quit();
+}
+
+
+static void browser_update_title(struct browser_context *ctx)
+{
+ char buf[100];
+
+ if (ctx->hover_link) {
+ gtk_window_set_title(GTK_WINDOW(ctx->win), ctx->hover_link);
+ return;
+ }
+
+ if (ctx->progress == 100) {
+ gtk_window_set_title(GTK_WINDOW(ctx->win),
+ ctx->title ? ctx->title :
+ "Hotspot 2.0 client");
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "[%d%%] %s", ctx->progress,
+ ctx->title ? ctx->title : "Hotspot 2.0 client");
+ gtk_window_set_title(GTK_WINDOW(ctx->win), buf);
+}
+
+
+static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
+ struct browser_context *ctx)
+{
+ ctx->progress = 100 * webkit_web_view_get_progress(view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
+ ctx->progress);
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec,
+ struct browser_context *ctx)
+{
+ int status = webkit_web_view_get_load_status(view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
+ __func__, status, webkit_web_view_get_uri(view));
+}
+
+
+static void view_cb_resource_request_starting(WebKitWebView *view,
+ WebKitWebFrame *frame,
+ WebKitWebResource *res,
+ WebKitNetworkRequest *req,
+ WebKitNetworkResponse *resp,
+ struct browser_context *ctx)
+{
+ const gchar *uri = webkit_network_request_get_uri(req);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
+ if (g_str_has_suffix(uri, "/favicon.ico"))
+ webkit_network_request_set_uri(req, "about:blank");
+ if (g_str_has_prefix(uri, "osu://")) {
+ ctx->success = atoi(uri + 6);
+ gtk_main_quit();
+ }
+ if (g_str_has_prefix(uri, "http://localhost:12345")) {
+ /*
+ * This is used as a special trigger to indicate that the
+ * user exchange has been completed.
+ */
+ ctx->success = 1;
+ gtk_main_quit();
+ }
+}
+
+
+static gboolean view_cb_mime_type_policy_decision(
+ WebKitWebView *view, WebKitWebFrame *frame, WebKitNetworkRequest *req,
+ gchar *mime, WebKitWebPolicyDecision *policy,
+ struct browser_context *ctx)
+{
+ wpa_printf(MSG_DEBUG, "BROWSER:%s mime=%s", __func__, mime);
+
+ if (!webkit_web_view_can_show_mime_type(view, mime)) {
+ webkit_web_policy_decision_download(policy);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static gboolean view_cb_download_requested(WebKitWebView *view,
+ WebKitDownload *dl,
+ struct browser_context *ctx)
+{
+ const gchar *uri;
+ uri = webkit_download_get_uri(dl);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
+ return FALSE;
+}
+
+
+static void view_cb_hovering_over_link(WebKitWebView *view, gchar *title,
+ gchar *uri, struct browser_context *ctx)
+{
+ wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s uri=%s", __func__, title,
+ uri);
+ os_free(ctx->hover_link);
+ if (uri)
+ ctx->hover_link = os_strdup(uri);
+ else
+ ctx->hover_link = NULL;
+
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame,
+ const char *title,
+ struct browser_context *ctx)
+{
+ wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
+ os_free(ctx->title);
+ ctx->title = os_strdup(title);
+ browser_update_title(ctx);
+}
+
+
+int hs20_web_browser(const char *url)
+{
+ GtkWidget *scroll;
+ SoupSession *s;
+ WebKitWebView *view;
+ WebKitWebSettings *settings;
+ struct browser_context ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+ if (!gtk_init_check(NULL, NULL))
+ return -1;
+
+ s = webkit_get_default_session();
+ g_object_set(G_OBJECT(s), "ssl-ca-file",
+ "/etc/ssl/certs/ca-certificates.crt", NULL);
+ 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_default_size(GTK_WINDOW(ctx.win), 800, 600);
+
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+
+ g_signal_connect(G_OBJECT(ctx.win), "destroy",
+ G_CALLBACK(win_cb_destroy), &ctx);
+
+ view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ g_signal_connect(G_OBJECT(view), "notify::progress",
+ G_CALLBACK(view_cb_notify_progress), &ctx);
+ g_signal_connect(G_OBJECT(view), "notify::load-status",
+ G_CALLBACK(view_cb_notify_load_status), &ctx);
+ g_signal_connect(G_OBJECT(view), "resource-request-starting",
+ G_CALLBACK(view_cb_resource_request_starting), &ctx);
+ g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
+ G_CALLBACK(view_cb_mime_type_policy_decision), &ctx);
+ g_signal_connect(G_OBJECT(view), "download-requested",
+ G_CALLBACK(view_cb_download_requested), &ctx);
+ g_signal_connect(G_OBJECT(view), "hovering-over-link",
+ G_CALLBACK(view_cb_hovering_over_link), &ctx);
+ g_signal_connect(G_OBJECT(view), "title-changed",
+ G_CALLBACK(view_cb_title_changed), &ctx);
+
+ gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
+ gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
+
+ gtk_widget_grab_focus(GTK_WIDGET(view));
+ gtk_widget_show_all(ctx.win);
+
+ settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "user-agent",
+ "Mozilla/5.0 (X11; U; Unix; en-US) "
+ "AppleWebKit/537.15 (KHTML, like Gecko) "
+ "hs20-client/1.0", NULL);
+ g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
+
+ webkit_web_view_load_uri(view, url);
+
+ gtk_main();
+ gtk_widget_destroy(ctx.win);
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ free(ctx.hover_link);
+ free(ctx.title);
+ return ctx.success;
+}
diff --git a/contrib/wpa/src/utils/browser.h b/contrib/wpa/src/utils/browser.h
new file mode 100644
index 0000000..aaa0eed
--- /dev/null
+++ b/contrib/wpa/src/utils/browser.h
@@ -0,0 +1,21 @@
+/*
+ * Hotspot 2.0 client - Web browser
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BROWSER_H
+#define BROWSER_H
+
+#ifdef CONFIG_NO_BROWSER
+static inline int hs20_web_browser(const char *url)
+{
+ return -1;
+}
+#else /* CONFIG_NO_BROWSER */
+int hs20_web_browser(const char *url);
+#endif /* CONFIG_NO_BROWSER */
+
+#endif /* BROWSER_H */
diff --git a/contrib/wpa/src/utils/build_config.h b/contrib/wpa/src/utils/build_config.h
index f947388..c6f4e43 100644
--- a/contrib/wpa/src/utils/build_config.h
+++ b/contrib/wpa/src/utils/build_config.h
@@ -47,31 +47,4 @@
#endif /* USE_INTERNAL_CRYPTO */
#endif /* CONFIG_WIN32_DEFAULTS */
-#ifdef CONFIG_XCODE_DEFAULTS
-#define CONFIG_DRIVER_OSX
-#define CONFIG_BACKEND_FILE
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define CONFIG_CTRL_IFACE
-#define CONFIG_CTRL_IFACE_UNIX
-#define CONFIG_DEBUG_FILE
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_TNC
-#define CONFIG_WPS
-#define EAP_WSC
-
-#ifdef USE_INTERNAL_CRYPTO
-#define CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#endif /* USE_INTERNAL_CRYPTO */
-#endif /* CONFIG_XCODE_DEFAULTS */
-
#endif /* BUILD_CONFIG_H */
diff --git a/contrib/wpa/src/utils/common.c b/contrib/wpa/src/utils/common.c
index e636984..5fd795f 100644
--- a/contrib/wpa/src/utils/common.c
+++ b/contrib/wpa/src/utils/common.c
@@ -36,6 +36,25 @@ int hex2byte(const char *hex)
}
+static const char * hwaddr_parse(const char *txt, u8 *addr)
+{
+ size_t i;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ int a;
+
+ a = hex2byte(txt);
+ if (a < 0)
+ return NULL;
+ txt += 2;
+ addr[i] = a;
+ if (i < ETH_ALEN - 1 && *txt++ != ':')
+ return NULL;
+ }
+ return txt;
+}
+
+
/**
* hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
* @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
@@ -44,25 +63,46 @@ int hex2byte(const char *hex)
*/
int hwaddr_aton(const char *txt, u8 *addr)
{
- int i;
+ return hwaddr_parse(txt, addr) ? 0 : -1;
+}
- for (i = 0; i < 6; i++) {
- int a, b;
- a = hex2num(*txt++);
- if (a < 0)
- return -1;
- b = hex2num(*txt++);
- if (b < 0)
- return -1;
- *addr++ = (a << 4) | b;
- if (i < 5 && *txt++ != ':')
+/**
+ * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format)
+ * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
+ * @maskable: Flag to indicate whether a mask is allowed
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
+{
+ const char *r;
+
+ /* parse address part */
+ r = hwaddr_parse(txt, addr);
+ if (!r)
+ return -1;
+
+ /* check for optional mask */
+ if (*r == '\0' || isspace(*r)) {
+ /* no mask specified, assume default */
+ os_memset(mask, 0xff, ETH_ALEN);
+ } else if (maskable && *r == '/') {
+ /* mask specified and allowed */
+ r = hwaddr_parse(r + 1, mask);
+ /* parser error? */
+ if (!r)
return -1;
+ } else {
+ /* mask specified but not allowed or trailing garbage */
+ return -1;
}
return 0;
}
+
/**
* hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
* @txt: MAC address as a string (e.g., "001122334455")
@@ -144,6 +184,30 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len)
}
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask)
+{
+ size_t i;
+ int print_mask = 0;
+ int res;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if (mask[i] != 0xff) {
+ print_mask = 1;
+ break;
+ }
+ }
+
+ if (print_mask)
+ res = os_snprintf(buf, len, MACSTR "/" MACSTR,
+ MAC2STR(addr), MAC2STR(mask));
+ else
+ res = os_snprintf(buf, len, MACSTR, MAC2STR(addr));
+ if (os_snprintf_error(len, res))
+ return -1;
+ return res;
+}
+
+
/**
* inc_byte_array - Increment arbitrary length byte array by one
* @counter: Pointer to byte array
@@ -183,6 +247,35 @@ void wpa_get_ntp_timestamp(u8 *buf)
os_memcpy(buf + 4, (u8 *) &tmp, 4);
}
+/**
+ * wpa_scnprintf - Simpler-to-use snprintf function
+ * @buf: Output buffer
+ * @size: Buffer size
+ * @fmt: format
+ *
+ * Simpler snprintf version that doesn't require further error checks - the
+ * return value only indicates how many bytes were actually written, excluding
+ * the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough).
+ */
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (!size)
+ return 0;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0)
+ return 0;
+ if ((size_t) ret >= size)
+ return size - 1;
+
+ return ret;
+}
static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
size_t len, int uppercase)
@@ -195,7 +288,7 @@ static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
for (i = 0; i < len; i++) {
ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
data[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return pos - buf;
}
@@ -350,7 +443,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
size_t i;
for (i = 0; i < len; i++) {
- if (txt + 4 > end)
+ if (txt + 4 >= end)
break;
switch (data[i]) {
@@ -362,7 +455,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
*txt++ = '\\';
*txt++ = '\\';
break;
- case '\e':
+ case '\033':
*txt++ = '\\';
*txt++ = 'e';
break;
@@ -400,7 +493,7 @@ size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
int val;
while (*pos) {
- if (len == maxlen)
+ if (len + 1 >= maxlen)
break;
switch (*pos) {
case '\\':
@@ -427,7 +520,7 @@ size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
pos++;
break;
case 'e':
- buf[len++] = '\e';
+ buf[len++] = '\033';
pos++;
break;
case 'x':
@@ -468,6 +561,8 @@ size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
break;
}
}
+ if (maxlen > len)
+ buf[len] = '\0';
return len;
}
@@ -517,11 +612,9 @@ char * wpa_config_parse_string(const char *value, size_t *len)
if (pos == NULL || pos[1] != '\0')
return NULL;
*len = pos - value;
- str = os_malloc(*len + 1);
+ str = dup_binstr(value, *len);
if (str == NULL)
return NULL;
- os_memcpy(str, value, *len);
- str[*len] = '\0';
return str;
} else if (*value == 'P' && value[1] == '"') {
const char *pos;
@@ -532,11 +625,9 @@ char * wpa_config_parse_string(const char *value, size_t *len)
if (pos == NULL || pos[1] != '\0')
return NULL;
tlen = pos - value;
- tstr = os_malloc(tlen + 1);
+ tstr = dup_binstr(value, tlen);
if (tstr == NULL)
return NULL;
- os_memcpy(tstr, value, tlen);
- tstr[tlen] = '\0';
str = os_malloc(tlen + 1);
if (str == NULL) {
@@ -610,3 +701,364 @@ size_t merge_byte_arrays(u8 *res, size_t res_len,
return len;
}
+
+
+char * dup_binstr(const void *src, size_t len)
+{
+ char *res;
+
+ if (src == NULL)
+ return NULL;
+ res = os_malloc(len + 1);
+ if (res == NULL)
+ return NULL;
+ os_memcpy(res, src, len);
+ res[len] = '\0';
+
+ return res;
+}
+
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
+{
+ struct wpa_freq_range *freq = NULL, *n;
+ unsigned int count = 0;
+ const char *pos, *pos2, *pos3;
+
+ /*
+ * Comma separated list of frequency ranges.
+ * For example: 2412-2432,2462,5000-6000
+ */
+ pos = value;
+ while (pos && pos[0]) {
+ n = os_realloc_array(freq, count + 1,
+ sizeof(struct wpa_freq_range));
+ if (n == NULL) {
+ os_free(freq);
+ return -1;
+ }
+ freq = n;
+ freq[count].min = atoi(pos);
+ pos2 = os_strchr(pos, '-');
+ pos3 = os_strchr(pos, ',');
+ if (pos2 && (!pos3 || pos2 < pos3)) {
+ pos2++;
+ freq[count].max = atoi(pos2);
+ } else
+ freq[count].max = freq[count].min;
+ pos = pos3;
+ if (pos)
+ pos++;
+ count++;
+ }
+
+ os_free(res->range);
+ res->range = freq;
+ res->num = count;
+
+ return 0;
+}
+
+
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+ unsigned int freq)
+{
+ unsigned int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0; i < list->num; i++) {
+ if (freq >= list->range[i].min && freq <= list->range[i].max)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+char * freq_range_list_str(const struct wpa_freq_range_list *list)
+{
+ char *buf, *pos, *end;
+ size_t maxlen;
+ unsigned int i;
+ int res;
+
+ if (list->num == 0)
+ return NULL;
+
+ maxlen = list->num * 30;
+ buf = os_malloc(maxlen);
+ if (buf == NULL)
+ return NULL;
+ pos = buf;
+ end = buf + maxlen;
+
+ for (i = 0; i < list->num; i++) {
+ struct wpa_freq_range *range = &list->range[i];
+
+ if (range->min == range->max)
+ res = os_snprintf(pos, end - pos, "%s%u",
+ i == 0 ? "" : ",", range->min);
+ else
+ res = os_snprintf(pos, end - pos, "%s%u-%u",
+ i == 0 ? "" : ",",
+ range->min, range->max);
+ if (os_snprintf_error(end - pos, res)) {
+ os_free(buf);
+ return NULL;
+ }
+ pos += res;
+ }
+
+ return buf;
+}
+
+
+int int_array_len(const int *a)
+{
+ int i;
+ for (i = 0; a && a[i]; i++)
+ ;
+ return i;
+}
+
+
+void int_array_concat(int **res, const int *a)
+{
+ int reslen, alen, i;
+ int *n;
+
+ reslen = int_array_len(*res);
+ alen = int_array_len(a);
+
+ n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
+ if (n == NULL) {
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
+ for (i = 0; i <= alen; i++)
+ n[reslen + i] = a[i];
+ *res = n;
+}
+
+
+static int freq_cmp(const void *a, const void *b)
+{
+ int _a = *(int *) a;
+ int _b = *(int *) b;
+
+ if (_a == 0)
+ return 1;
+ if (_b == 0)
+ return -1;
+ return _a - _b;
+}
+
+
+void int_array_sort_unique(int *a)
+{
+ int alen;
+ int i, j;
+
+ if (a == NULL)
+ return;
+
+ alen = int_array_len(a);
+ qsort(a, alen, sizeof(int), freq_cmp);
+
+ i = 0;
+ j = 1;
+ while (a[i] && a[j]) {
+ if (a[i] == a[j]) {
+ j++;
+ continue;
+ }
+ a[++i] = a[j++];
+ }
+ if (a[i])
+ i++;
+ a[i] = 0;
+}
+
+
+void int_array_add_unique(int **res, int a)
+{
+ int reslen;
+ int *n;
+
+ for (reslen = 0; *res && (*res)[reslen]; reslen++) {
+ if ((*res)[reslen] == a)
+ return; /* already in the list */
+ }
+
+ n = os_realloc_array(*res, reslen + 2, sizeof(int));
+ if (n == NULL) {
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
+
+ n[reslen] = a;
+ n[reslen + 1] = 0;
+
+ *res = n;
+}
+
+
+void str_clear_free(char *str)
+{
+ if (str) {
+ size_t len = os_strlen(str);
+ os_memset(str, 0, len);
+ os_free(str);
+ }
+}
+
+
+void bin_clear_free(void *bin, size_t len)
+{
+ if (bin) {
+ os_memset(bin, 0, len);
+ os_free(bin);
+ }
+}
+
+
+int random_mac_addr(u8 *addr)
+{
+ if (os_get_random(addr, ETH_ALEN) < 0)
+ return -1;
+ addr[0] &= 0xfe; /* unicast */
+ addr[0] |= 0x02; /* locally administered */
+ return 0;
+}
+
+
+int random_mac_addr_keep_oui(u8 *addr)
+{
+ if (os_get_random(addr + 3, 3) < 0)
+ return -1;
+ addr[0] &= 0xfe; /* unicast */
+ addr[0] |= 0x02; /* locally administered */
+ return 0;
+}
+
+
+/**
+ * str_token - Get next token from a string
+ * @buf: String to tokenize. Note that the string might be modified.
+ * @delim: String of delimiters
+ * @context: Pointer to save our context. Should be initialized with
+ * NULL on the first call, and passed for any further call.
+ * Returns: The next token, NULL if there are no more valid tokens.
+ */
+char * str_token(char *str, const char *delim, char **context)
+{
+ char *end, *pos = str;
+
+ if (*context)
+ pos = *context;
+
+ while (*pos && os_strchr(delim, *pos))
+ pos++;
+ if (!*pos)
+ return NULL;
+
+ end = pos + 1;
+ while (*end && !os_strchr(delim, *end))
+ end++;
+
+ if (*end)
+ *end++ = '\0';
+
+ *context = end;
+ return pos;
+}
+
+
+size_t utf8_unescape(const char *inp, size_t in_size,
+ char *outp, size_t out_size)
+{
+ size_t res_size = 0;
+
+ if (!inp || !outp)
+ return 0;
+
+ if (!in_size)
+ in_size = os_strlen(inp);
+
+ /* Advance past leading single quote */
+ if (*inp == '\'' && in_size) {
+ inp++;
+ in_size--;
+ }
+
+ while (in_size--) {
+ if (res_size >= out_size)
+ return 0;
+
+ switch (*inp) {
+ case '\'':
+ /* Terminate on bare single quote */
+ *outp = '\0';
+ return res_size;
+
+ case '\\':
+ if (!in_size--)
+ return 0;
+ inp++;
+ /* fall through */
+
+ default:
+ *outp++ = *inp++;
+ res_size++;
+ }
+ }
+
+ /* NUL terminate if space allows */
+ if (res_size < out_size)
+ *outp = '\0';
+
+ return res_size;
+}
+
+
+size_t utf8_escape(const char *inp, size_t in_size,
+ char *outp, size_t out_size)
+{
+ size_t res_size = 0;
+
+ if (!inp || !outp)
+ return 0;
+
+ /* inp may or may not be NUL terminated, but must be if 0 size
+ * is specified */
+ if (!in_size)
+ in_size = os_strlen(inp);
+
+ while (in_size--) {
+ if (res_size++ >= out_size)
+ return 0;
+
+ switch (*inp) {
+ case '\\':
+ case '\'':
+ if (res_size++ >= out_size)
+ return 0;
+ *outp++ = '\\';
+ /* fall through */
+
+ default:
+ *outp++ = *inp++;
+ break;
+ }
+ }
+
+ /* NUL terminate if space allows */
+ if (res_size < out_size)
+ *outp = '\0';
+
+ return res_size;
+}
diff --git a/contrib/wpa/src/utils/common.h b/contrib/wpa/src/utils/common.h
index 5fc916c..576e8e7 100644
--- a/contrib/wpa/src/utils/common.h
+++ b/contrib/wpa/src/utils/common.h
@@ -164,6 +164,7 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define be_to_host16(n) wpa_swap_16(n)
#define host_to_be16(n) wpa_swap_16(n)
#define le_to_host32(n) (n)
+#define host_to_le32(n) (n)
#define be_to_host32(n) wpa_swap_32(n)
#define host_to_be32(n) wpa_swap_32(n)
@@ -205,6 +206,7 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define be_to_host16(n) (n)
#define host_to_be16(n) (n)
#define le_to_host32(n) bswap_32(n)
+#define host_to_le32(n) bswap_32(n)
#define be_to_host32(n) (n)
#define host_to_be32(n) (n)
#define le_to_host64(n) bswap_64(n)
@@ -224,74 +226,113 @@ static inline unsigned int wpa_swap_32(unsigned int v)
/* Macros for handling unaligned memory accesses */
-#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
-#define WPA_PUT_BE16(a, val) \
- do { \
- (a)[0] = ((u16) (val)) >> 8; \
- (a)[1] = ((u16) (val)) & 0xff; \
- } while (0)
-
-#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
-#define WPA_PUT_LE16(a, val) \
- do { \
- (a)[1] = ((u16) (val)) >> 8; \
- (a)[0] = ((u16) (val)) & 0xff; \
- } while (0)
-
-#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
- ((u32) (a)[2]))
-#define WPA_PUT_BE24(a, val) \
- do { \
- (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \
- (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
- (a)[2] = (u8) (((u32) (val)) & 0xff); \
- } while (0)
-
-#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
- (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
-#define WPA_PUT_BE32(a, val) \
- do { \
- (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
- (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
- (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
- (a)[3] = (u8) (((u32) (val)) & 0xff); \
- } while (0)
-
-#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
- (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
-#define WPA_PUT_LE32(a, val) \
- do { \
- (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \
- (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \
- (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
- (a)[0] = (u8) (((u32) (val)) & 0xff); \
- } while (0)
-
-#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
- (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
- (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
- (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
-#define WPA_PUT_BE64(a, val) \
- do { \
- (a)[0] = (u8) (((u64) (val)) >> 56); \
- (a)[1] = (u8) (((u64) (val)) >> 48); \
- (a)[2] = (u8) (((u64) (val)) >> 40); \
- (a)[3] = (u8) (((u64) (val)) >> 32); \
- (a)[4] = (u8) (((u64) (val)) >> 24); \
- (a)[5] = (u8) (((u64) (val)) >> 16); \
- (a)[6] = (u8) (((u64) (val)) >> 8); \
- (a)[7] = (u8) (((u64) (val)) & 0xff); \
- } while (0)
-
-#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
- (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
- (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
- (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
+static inline u16 WPA_GET_BE16(const u8 *a)
+{
+ return (a[0] << 8) | a[1];
+}
+
+static inline void WPA_PUT_BE16(u8 *a, u16 val)
+{
+ a[0] = val >> 8;
+ a[1] = val & 0xff;
+}
+
+static inline u16 WPA_GET_LE16(const u8 *a)
+{
+ return (a[1] << 8) | a[0];
+}
+
+static inline void WPA_PUT_LE16(u8 *a, u16 val)
+{
+ a[1] = val >> 8;
+ a[0] = val & 0xff;
+}
+
+static inline u32 WPA_GET_BE24(const u8 *a)
+{
+ return (a[0] << 16) | (a[1] << 8) | a[2];
+}
+
+static inline void WPA_PUT_BE24(u8 *a, u32 val)
+{
+ a[0] = (val >> 16) & 0xff;
+ a[1] = (val >> 8) & 0xff;
+ a[2] = val & 0xff;
+}
+
+static inline u32 WPA_GET_BE32(const u8 *a)
+{
+ return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
+}
+
+static inline void WPA_PUT_BE32(u8 *a, u32 val)
+{
+ a[0] = (val >> 24) & 0xff;
+ a[1] = (val >> 16) & 0xff;
+ a[2] = (val >> 8) & 0xff;
+ a[3] = val & 0xff;
+}
+
+static inline u32 WPA_GET_LE32(const u8 *a)
+{
+ return (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
+}
+
+static inline void WPA_PUT_LE32(u8 *a, u32 val)
+{
+ a[3] = (val >> 24) & 0xff;
+ a[2] = (val >> 16) & 0xff;
+ a[1] = (val >> 8) & 0xff;
+ a[0] = val & 0xff;
+}
+
+static inline u64 WPA_GET_BE64(const u8 *a)
+{
+ return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
+ (((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
+ (((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
+ (((u64) a[6]) << 8) | ((u64) a[7]);
+}
+
+static inline void WPA_PUT_BE64(u8 *a, u64 val)
+{
+ a[0] = val >> 56;
+ a[1] = val >> 48;
+ a[2] = val >> 40;
+ a[3] = val >> 32;
+ a[4] = val >> 24;
+ a[5] = val >> 16;
+ a[6] = val >> 8;
+ a[7] = val & 0xff;
+}
+
+static inline u64 WPA_GET_LE64(const u8 *a)
+{
+ return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
+ (((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
+ (((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
+ (((u64) a[1]) << 8) | ((u64) a[0]);
+}
+
+static inline void WPA_PUT_LE64(u8 *a, u64 val)
+{
+ a[7] = val >> 56;
+ a[6] = val >> 48;
+ a[5] = val >> 40;
+ a[4] = val >> 32;
+ a[3] = val >> 24;
+ a[2] = val >> 16;
+ a[1] = val >> 8;
+ a[0] = val & 0xff;
+}
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
+#ifndef ETH_HLEN
+#define ETH_HLEN 14
+#endif
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
@@ -422,17 +463,29 @@ typedef u64 __bitwise le64;
#endif /* __GNUC__ */
#endif /* __must_check */
+#ifndef __maybe_unused
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define __maybe_unused __attribute__((unused))
+#else
+#define __maybe_unused
+#endif /* __GNUC__ */
+#endif /* __must_check */
+
int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
int hwaddr_compact_aton(const char *txt, u8 *addr);
int hwaddr_aton2(const char *txt, u8 *addr);
int hex2byte(const char *hex);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
void inc_byte_array(u8 *counter, size_t len);
void wpa_get_ntp_timestamp(u8 *buf);
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
size_t len);
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+
#ifdef CONFIG_NATIVE_WINDOWS
void wpa_unicode2ascii_inplace(TCHAR *str);
TCHAR * wpa_strdup_tchar(const char *str);
@@ -451,6 +504,7 @@ int is_hex(const u8 *data, size_t len);
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len);
+char * dup_binstr(const void *src, size_t len);
static inline int is_zero_ether_addr(const u8 *a)
{
@@ -467,6 +521,39 @@ static inline int is_broadcast_ether_addr(const u8 *a)
#include "wpa_debug.h"
+struct wpa_freq_range_list {
+ struct wpa_freq_range {
+ unsigned int min;
+ unsigned int max;
+ } *range;
+ unsigned int num;
+};
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+ unsigned int freq);
+char * freq_range_list_str(const struct wpa_freq_range_list *list);
+
+int int_array_len(const int *a);
+void int_array_concat(int **res, const int *a);
+void int_array_sort_unique(int *a);
+void int_array_add_unique(int **res, int a);
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+void str_clear_free(char *str);
+void bin_clear_free(void *bin, size_t len);
+
+int random_mac_addr(u8 *addr);
+int random_mac_addr_keep_oui(u8 *addr);
+
+char * str_token(char *str, const char *delim, char **context);
+size_t utf8_escape(const char *inp, size_t in_size,
+ char *outp, size_t out_size);
+size_t utf8_unescape(const char *inp, size_t in_size,
+ char *outp, size_t out_size);
+
+
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
* networking socket uses that do not really result in a real problem and
diff --git a/contrib/wpa/src/utils/edit.c b/contrib/wpa/src/utils/edit.c
index b01e08d..d340bfa 100644
--- a/contrib/wpa/src/utils/edit.c
+++ b/contrib/wpa/src/utils/edit.c
@@ -14,7 +14,7 @@
#include "list.h"
#include "edit.h"
-#define CMD_BUF_LEN 256
+#define CMD_BUF_LEN 4096
static char cmdbuf[CMD_BUF_LEN];
static int cmdbuf_pos = 0;
static int cmdbuf_len = 0;
@@ -345,7 +345,7 @@ static void insert_char(int c)
static void process_cmd(void)
{
-
+ currbuf_valid = 0;
if (cmdbuf_len == 0) {
printf("\n%s> ", ps2 ? ps2 : "");
fflush(stdout);
diff --git a/contrib/wpa/src/utils/edit_readline.c b/contrib/wpa/src/utils/edit_readline.c
index add26fa..c2a5bca 100644
--- a/contrib/wpa/src/utils/edit_readline.c
+++ b/contrib/wpa/src/utils/edit_readline.c
@@ -167,9 +167,9 @@ void edit_deinit(const char *history_file,
if (filter_cb && filter_cb(edit_cb_ctx, p)) {
h = remove_history(where_history());
if (h) {
- os_free(h->line);
+ free(h->line);
free(h->data);
- os_free(h);
+ free(h);
} else
next_history();
} else
diff --git a/contrib/wpa/src/utils/edit_simple.c b/contrib/wpa/src/utils/edit_simple.c
index a095ea6..13173cb 100644
--- a/contrib/wpa/src/utils/edit_simple.c
+++ b/contrib/wpa/src/utils/edit_simple.c
@@ -13,7 +13,7 @@
#include "edit.h"
-#define CMD_BUF_LEN 256
+#define CMD_BUF_LEN 4096
static char cmdbuf[CMD_BUF_LEN];
static int cmdbuf_pos = 0;
static const char *ps2 = NULL;
diff --git a/contrib/wpa/src/utils/eloop.c b/contrib/wpa/src/utils/eloop.c
index d01ae64..4a565eb 100644
--- a/contrib/wpa/src/utils/eloop.c
+++ b/contrib/wpa/src/utils/eloop.c
@@ -7,17 +7,28 @@
*/
#include "includes.h"
+#include <assert.h>
#include "common.h"
#include "trace.h"
#include "list.h"
#include "eloop.h"
+#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
+#error Do not define both of poll and epoll
+#endif
+
+#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL)
+#define CONFIG_ELOOP_SELECT
+#endif
+
#ifdef CONFIG_ELOOP_POLL
-#include <assert.h>
#include <poll.h>
#endif /* CONFIG_ELOOP_POLL */
+#ifdef CONFIG_ELOOP_EPOLL
+#include <sys/epoll.h>
+#endif /* CONFIG_ELOOP_EPOLL */
struct eloop_sock {
int sock;
@@ -31,7 +42,7 @@ struct eloop_sock {
struct eloop_timeout {
struct dl_list list;
- struct os_time time;
+ struct os_reltime time;
void *eloop_data;
void *user_data;
eloop_timeout_handler handler;
@@ -50,7 +61,11 @@ struct eloop_signal {
struct eloop_sock_table {
int count;
struct eloop_sock *table;
+#ifdef CONFIG_ELOOP_EPOLL
+ eloop_event_type type;
+#else /* CONFIG_ELOOP_EPOLL */
int changed;
+#endif /* CONFIG_ELOOP_EPOLL */
};
struct eloop_data {
@@ -63,6 +78,13 @@ struct eloop_data {
struct pollfd *pollfds;
struct pollfd **pollfds_map;
#endif /* CONFIG_ELOOP_POLL */
+#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 */
struct eloop_sock_table readers;
struct eloop_sock_table writers;
struct eloop_sock_table exceptions;
@@ -75,7 +97,6 @@ struct eloop_data {
int pending_terminate;
int terminate;
- int reader_table_changed;
};
static struct eloop_data eloop;
@@ -128,6 +149,17 @@ int eloop_init(void)
{
os_memset(&eloop, 0, sizeof(eloop));
dl_list_init(&eloop.timeout);
+#ifdef CONFIG_ELOOP_EPOLL
+ eloop.epollfd = epoll_create1(0);
+ if (eloop.epollfd < 0) {
+ wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n",
+ __func__, strerror(errno));
+ return -1;
+ }
+ eloop.readers.type = EVENT_TYPE_READ;
+ eloop.writers.type = EVENT_TYPE_WRITE;
+ eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
+#endif /* CONFIG_ELOOP_EPOLL */
#ifdef WPA_TRACE
signal(SIGSEGV, eloop_sigsegv_handler);
#endif /* WPA_TRACE */
@@ -139,6 +171,11 @@ 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 eloop_sock *temp_table;
+ struct epoll_event ev, *temp_events;
+ int next;
+#endif /* CONFIG_ELOOP_EPOLL */
struct eloop_sock *tmp;
int new_max_sock;
@@ -174,12 +211,41 @@ 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,
+ sizeof(struct eloop_sock));
+ if (temp_table == NULL)
+ return -1;
+
+ eloop.epoll_max_fd = next;
+ eloop.epoll_table = temp_table;
+ }
+
+ 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));
+ return -1;
+ }
+
+ eloop.epoll_max_event_num = next;
+ eloop.epoll_events = temp_events;
+ }
+#endif /* CONFIG_ELOOP_EPOLL */
eloop_trace_sock_remove_ref(table);
tmp = os_realloc_array(table->table, table->count + 1,
sizeof(struct eloop_sock));
- if (tmp == NULL)
+ if (tmp == NULL) {
+ eloop_trace_sock_add_ref(table);
return -1;
+ }
tmp[table->count].sock = sock;
tmp[table->count].eloop_data = eloop_data;
@@ -190,9 +256,38 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
table->table = tmp;
eloop.max_sock = new_max_sock;
eloop.count++;
+#ifndef CONFIG_ELOOP_EPOLL
table->changed = 1;
+#endif /* CONFIG_ELOOP_EPOLL */
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));
+ return -1;
+ }
+ os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1],
+ sizeof(struct eloop_sock));
+#endif /* CONFIG_ELOOP_EPOLL */
return 0;
}
@@ -219,8 +314,18 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
}
table->count--;
eloop.count--;
+#ifndef CONFIG_ELOOP_EPOLL
table->changed = 1;
+#endif /* CONFIG_ELOOP_EPOLL */
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));
+ return;
+ }
+ os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock));
+#endif /* CONFIG_ELOOP_EPOLL */
}
@@ -362,7 +467,9 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
max_pollfd_map, POLLERR | POLLHUP);
}
-#else /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_POLL */
+
+#ifdef CONFIG_ELOOP_SELECT
static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
fd_set *fds)
@@ -374,8 +481,10 @@ static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
if (table->table == NULL)
return;
- for (i = 0; i < table->count; i++)
+ for (i = 0; i < table->count; i++) {
+ assert(table->table[i].sock >= 0);
FD_SET(table->table[i].sock, fds);
+ }
}
@@ -399,7 +508,24 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
}
}
-#endif /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_SELECT */
+
+
+#ifdef CONFIG_ELOOP_EPOLL
+static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
+{
+ struct eloop_sock *table;
+ int i;
+
+ for (i = 0; i < nfds; i++) {
+ table = &eloop.epoll_table[events[i].data.fd];
+ if (table->handler == NULL)
+ continue;
+ table->handler(table->sock, table->eloop_data,
+ table->user_data);
+ }
+}
+#endif /* CONFIG_ELOOP_EPOLL */
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
@@ -459,6 +585,7 @@ int eloop_register_sock(int sock, eloop_event_type type,
{
struct eloop_sock_table *table;
+ assert(sock >= 0);
table = eloop_get_sock_table(type);
return eloop_sock_table_add_sock(table, sock, handler,
eloop_data, user_data);
@@ -484,7 +611,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
timeout = os_zalloc(sizeof(*timeout));
if (timeout == NULL)
return -1;
- if (os_get_time(&timeout->time) < 0) {
+ if (os_get_reltime(&timeout->time) < 0) {
os_free(timeout);
return -1;
}
@@ -514,7 +641,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
/* Maintain timeouts in order of increasing time */
dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
- if (os_time_before(&timeout->time, &tmp->time)) {
+ if (os_reltime_before(&timeout->time, &tmp->time)) {
dl_list_add(tmp->list.prev, &timeout->list);
return 0;
}
@@ -556,6 +683,33 @@ int eloop_cancel_timeout(eloop_timeout_handler handler,
}
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data,
+ struct os_reltime *remaining)
+{
+ struct eloop_timeout *timeout, *prev;
+ int removed = 0;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ remaining->sec = remaining->usec = 0;
+
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data) &&
+ (timeout->user_data == user_data)) {
+ removed = 1;
+ if (os_reltime_before(&now, &timeout->time))
+ os_reltime_sub(&timeout->time, &now, remaining);
+ eloop_remove_timeout(timeout);
+ break;
+ }
+ }
+ return removed;
+}
+
+
int eloop_is_timeout_registered(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
@@ -572,6 +726,70 @@ int eloop_is_timeout_registered(eloop_timeout_handler handler,
}
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+ eloop_timeout_handler handler, void *eloop_data,
+ void *user_data)
+{
+ struct os_reltime now, requested, remaining;
+ struct eloop_timeout *tmp;
+
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data) {
+ requested.sec = req_secs;
+ requested.usec = req_usecs;
+ os_get_reltime(&now);
+ os_reltime_sub(&tmp->time, &now, &remaining);
+ if (os_reltime_before(&requested, &remaining)) {
+ eloop_cancel_timeout(handler, eloop_data,
+ user_data);
+ eloop_register_timeout(requested.sec,
+ requested.usec,
+ handler, eloop_data,
+ user_data);
+ return 1;
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+ eloop_timeout_handler handler, void *eloop_data,
+ void *user_data)
+{
+ struct os_reltime now, requested, remaining;
+ struct eloop_timeout *tmp;
+
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data) {
+ requested.sec = req_secs;
+ requested.usec = req_usecs;
+ os_get_reltime(&now);
+ os_reltime_sub(&tmp->time, &now, &remaining);
+ if (os_reltime_before(&remaining, &requested)) {
+ eloop_cancel_timeout(handler, eloop_data,
+ user_data);
+ eloop_register_timeout(requested.sec,
+ requested.usec,
+ handler, eloop_data,
+ user_data);
+ return 1;
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
#ifndef CONFIG_NATIVE_WINDOWS
static void eloop_handle_alarm(int sig)
{
@@ -682,20 +900,24 @@ void eloop_run(void)
#ifdef CONFIG_ELOOP_POLL
int num_poll_fds;
int timeout_ms = 0;
-#else /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_POLL */
+#ifdef CONFIG_ELOOP_SELECT
fd_set *rfds, *wfds, *efds;
struct timeval _tv;
-#endif /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_SELECT */
+#ifdef CONFIG_ELOOP_EPOLL
+ int timeout_ms = -1;
+#endif /* CONFIG_ELOOP_EPOLL */
int res;
- struct os_time tv, now;
+ struct os_reltime tv, now;
-#ifndef CONFIG_ELOOP_POLL
+#ifdef CONFIG_ELOOP_SELECT
rfds = os_malloc(sizeof(*rfds));
wfds = os_malloc(sizeof(*wfds));
efds = os_malloc(sizeof(*efds));
if (rfds == NULL || wfds == NULL || efds == NULL)
goto out;
-#endif /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_SELECT */
while (!eloop.terminate &&
(!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
@@ -704,17 +926,18 @@ void eloop_run(void)
timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
list);
if (timeout) {
- os_get_time(&now);
- if (os_time_before(&now, &timeout->time))
- os_time_sub(&timeout->time, &now, &tv);
+ os_get_reltime(&now);
+ if (os_reltime_before(&now, &timeout->time))
+ os_reltime_sub(&timeout->time, &now, &tv);
else
tv.sec = tv.usec = 0;
-#ifdef CONFIG_ELOOP_POLL
+#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
timeout_ms = tv.sec * 1000 + tv.usec / 1000;
-#else /* CONFIG_ELOOP_POLL */
+#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
+#ifdef CONFIG_ELOOP_SELECT
_tv.tv_sec = tv.sec;
_tv.tv_usec = tv.usec;
-#endif /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_SELECT */
}
#ifdef CONFIG_ELOOP_POLL
@@ -724,30 +947,44 @@ void eloop_run(void)
eloop.max_pollfd_map);
res = poll(eloop.pollfds, num_poll_fds,
timeout ? timeout_ms : -1);
-
- if (res < 0 && errno != EINTR && errno != 0) {
- perror("poll");
- goto out;
- }
-#else /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_POLL */
+#ifdef CONFIG_ELOOP_SELECT
eloop_sock_table_set_fds(&eloop.readers, rfds);
eloop_sock_table_set_fds(&eloop.writers, wfds);
eloop_sock_table_set_fds(&eloop.exceptions, efds);
res = select(eloop.max_sock + 1, rfds, wfds, efds,
timeout ? &_tv : NULL);
+#endif /* CONFIG_ELOOP_SELECT */
+#ifdef CONFIG_ELOOP_EPOLL
+ if (eloop.count == 0) {
+ res = 0;
+ } else {
+ res = epoll_wait(eloop.epollfd, eloop.epoll_events,
+ eloop.count, timeout_ms);
+ }
+#endif /* CONFIG_ELOOP_EPOLL */
if (res < 0 && errno != EINTR && errno != 0) {
- perror("select");
+ wpa_printf(MSG_ERROR, "eloop: %s: %s",
+#ifdef CONFIG_ELOOP_POLL
+ "poll"
+#endif /* CONFIG_ELOOP_POLL */
+#ifdef CONFIG_ELOOP_SELECT
+ "select"
+#endif /* CONFIG_ELOOP_SELECT */
+#ifdef CONFIG_ELOOP_EPOLL
+ "epoll"
+#endif /* CONFIG_ELOOP_EPOLL */
+ , strerror(errno));
goto out;
}
-#endif /* CONFIG_ELOOP_POLL */
eloop_process_pending_signals();
/* check if some registered timeouts have occurred */
timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
list);
if (timeout) {
- os_get_time(&now);
- if (!os_time_before(&now, &timeout->time)) {
+ os_get_reltime(&now);
+ if (!os_reltime_before(&now, &timeout->time)) {
void *eloop_data = timeout->eloop_data;
void *user_data = timeout->user_data;
eloop_timeout_handler handler =
@@ -765,19 +1002,24 @@ void eloop_run(void)
eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
&eloop.exceptions, eloop.pollfds_map,
eloop.max_pollfd_map);
-#else /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_POLL */
+#ifdef CONFIG_ELOOP_SELECT
eloop_sock_table_dispatch(&eloop.readers, rfds);
eloop_sock_table_dispatch(&eloop.writers, wfds);
eloop_sock_table_dispatch(&eloop.exceptions, efds);
-#endif /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_SELECT */
+#ifdef CONFIG_ELOOP_EPOLL
+ eloop_sock_table_dispatch(eloop.epoll_events, res);
+#endif /* CONFIG_ELOOP_EPOLL */
}
+ eloop.terminate = 0;
out:
-#ifndef CONFIG_ELOOP_POLL
+#ifdef CONFIG_ELOOP_SELECT
os_free(rfds);
os_free(wfds);
os_free(efds);
-#endif /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_SELECT */
return;
}
@@ -791,9 +1033,9 @@ void eloop_terminate(void)
void eloop_destroy(void)
{
struct eloop_timeout *timeout, *prev;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
dl_list_for_each_safe(timeout, prev, &eloop.timeout,
struct eloop_timeout, list) {
int sec, usec;
@@ -821,6 +1063,11 @@ void eloop_destroy(void)
os_free(eloop.pollfds);
os_free(eloop.pollfds_map);
#endif /* CONFIG_ELOOP_POLL */
+#ifdef CONFIG_ELOOP_EPOLL
+ os_free(eloop.epoll_table);
+ os_free(eloop.epoll_events);
+ close(eloop.epollfd);
+#endif /* CONFIG_ELOOP_EPOLL */
}
@@ -843,7 +1090,13 @@ void eloop_wait_for_read_sock(int sock)
pfd.events = POLLIN;
poll(&pfd, 1, -1);
-#else /* CONFIG_ELOOP_POLL */
+#endif /* CONFIG_ELOOP_POLL */
+#if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
+ /*
+ * We can use epoll() here. But epoll() requres 4 system calls.
+ * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
+ * epoll fd. So select() is better for performance here.
+ */
fd_set rfds;
if (sock < 0)
@@ -852,5 +1105,9 @@ void eloop_wait_for_read_sock(int sock)
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
select(sock + 1, &rfds, NULL, NULL, NULL);
-#endif /* CONFIG_ELOOP_POLL */
+#endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
}
+
+#ifdef CONFIG_ELOOP_SELECT
+#undef CONFIG_ELOOP_SELECT
+#endif /* CONFIG_ELOOP_SELECT */
diff --git a/contrib/wpa/src/utils/eloop.h b/contrib/wpa/src/utils/eloop.h
index db03a73..07b8c0d 100644
--- a/contrib/wpa/src/utils/eloop.h
+++ b/contrib/wpa/src/utils/eloop.h
@@ -195,6 +195,21 @@ int eloop_cancel_timeout(eloop_timeout_handler handler,
void *eloop_data, void *user_data);
/**
+ * eloop_cancel_timeout_one - Cancel a single timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * @remaining: Time left on the cancelled timer
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeout registered with
+ * eloop_register_timeout() and return the remaining time left.
+ */
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data,
+ struct os_reltime *remaining);
+
+/**
* eloop_is_timeout_registered - Check if a timeout is already registered
* @handler: Matching callback function
* @eloop_data: Matching eloop_data
@@ -208,6 +223,40 @@ int eloop_is_timeout_registered(eloop_timeout_handler handler,
void *eloop_data, void *user_data);
/**
+ * eloop_deplete_timeout - Deplete a timeout that is already registered
+ * @req_secs: Requested number of seconds to the timeout
+ * @req_usecs: Requested number of microseconds to the timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no
+ * timeout matched
+ *
+ * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
+ * deplete the timeout if remaining time is more than the requested time.
+ */
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+ eloop_timeout_handler handler, void *eloop_data,
+ void *user_data);
+
+/**
+ * eloop_replenish_timeout - Replenish a timeout that is already registered
+ * @req_secs: Requested number of seconds to the timeout
+ * @req_usecs: Requested number of microseconds to the timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no
+ * timeout matched
+ *
+ * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
+ * replenish the timeout if remaining time is less than the requested time.
+ */
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+ eloop_timeout_handler handler, void *eloop_data,
+ void *user_data);
+
+/**
* eloop_register_signal - Register handler for signals
* @sig: Signal number (e.g., SIGHUP)
* @handler: Callback function to be called when the signal is received
diff --git a/contrib/wpa/src/utils/eloop_none.c b/contrib/wpa/src/utils/eloop_none.c
deleted file mode 100644
index c67ece4..0000000
--- a/contrib/wpa/src/utils/eloop_none.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Event loop - empty template (basic structure, but no OS specific operations)
- * Copyright (c) 2002-2005, 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"
-
-
-struct eloop_sock {
- int sock;
- void *eloop_data;
- void *user_data;
- void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
-};
-
-struct eloop_timeout {
- struct os_time time;
- void *eloop_data;
- void *user_data;
- void (*handler)(void *eloop_ctx, void *sock_ctx);
- struct eloop_timeout *next;
-};
-
-struct eloop_signal {
- int sig;
- void *user_data;
- void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
- int signaled;
-};
-
-struct eloop_data {
- int max_sock, reader_count;
- struct eloop_sock *readers;
-
- struct eloop_timeout *timeout;
-
- int signal_count;
- struct eloop_signal *signals;
- int signaled;
- int pending_terminate;
-
- int terminate;
- int reader_table_changed;
-};
-
-static struct eloop_data eloop;
-
-
-int eloop_init(void)
-{
- memset(&eloop, 0, sizeof(eloop));
- return 0;
-}
-
-
-int eloop_register_read_sock(int sock,
- void (*handler)(int sock, void *eloop_ctx,
- void *sock_ctx),
- void *eloop_data, void *user_data)
-{
- struct eloop_sock *tmp;
-
- tmp = (struct eloop_sock *)
- realloc(eloop.readers,
- (eloop.reader_count + 1) * sizeof(struct eloop_sock));
- if (tmp == NULL)
- return -1;
-
- tmp[eloop.reader_count].sock = sock;
- tmp[eloop.reader_count].eloop_data = eloop_data;
- tmp[eloop.reader_count].user_data = user_data;
- tmp[eloop.reader_count].handler = handler;
- eloop.reader_count++;
- eloop.readers = tmp;
- if (sock > eloop.max_sock)
- eloop.max_sock = sock;
- eloop.reader_table_changed = 1;
-
- return 0;
-}
-
-
-void eloop_unregister_read_sock(int sock)
-{
- int i;
-
- if (eloop.readers == NULL || eloop.reader_count == 0)
- return;
-
- for (i = 0; i < eloop.reader_count; i++) {
- if (eloop.readers[i].sock == sock)
- break;
- }
- if (i == eloop.reader_count)
- return;
- if (i != eloop.reader_count - 1) {
- memmove(&eloop.readers[i], &eloop.readers[i + 1],
- (eloop.reader_count - i - 1) *
- sizeof(struct eloop_sock));
- }
- eloop.reader_count--;
- eloop.reader_table_changed = 1;
-}
-
-
-int eloop_register_timeout(unsigned int secs, unsigned int usecs,
- void (*handler)(void *eloop_ctx, void *timeout_ctx),
- void *eloop_data, void *user_data)
-{
- struct eloop_timeout *timeout, *tmp, *prev;
-
- timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
- if (timeout == NULL)
- return -1;
- os_get_time(&timeout->time);
- timeout->time.sec += secs;
- timeout->time.usec += usecs;
- while (timeout->time.usec >= 1000000) {
- timeout->time.sec++;
- timeout->time.usec -= 1000000;
- }
- timeout->eloop_data = eloop_data;
- timeout->user_data = user_data;
- timeout->handler = handler;
- timeout->next = NULL;
-
- if (eloop.timeout == NULL) {
- eloop.timeout = timeout;
- return 0;
- }
-
- prev = NULL;
- tmp = eloop.timeout;
- while (tmp != NULL) {
- if (os_time_before(&timeout->time, &tmp->time))
- break;
- prev = tmp;
- tmp = tmp->next;
- }
-
- if (prev == NULL) {
- timeout->next = eloop.timeout;
- eloop.timeout = timeout;
- } else {
- timeout->next = prev->next;
- prev->next = timeout;
- }
-
- return 0;
-}
-
-
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
- void *eloop_data, void *user_data)
-{
- struct eloop_timeout *timeout, *prev, *next;
- int removed = 0;
-
- prev = NULL;
- timeout = eloop.timeout;
- while (timeout != NULL) {
- next = timeout->next;
-
- if (timeout->handler == handler &&
- (timeout->eloop_data == eloop_data ||
- eloop_data == ELOOP_ALL_CTX) &&
- (timeout->user_data == user_data ||
- user_data == ELOOP_ALL_CTX)) {
- if (prev == NULL)
- eloop.timeout = next;
- else
- prev->next = next;
- free(timeout);
- removed++;
- } else
- prev = timeout;
-
- timeout = next;
- }
-
- return removed;
-}
-
-
-int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
- void *timeout_ctx),
- void *eloop_data, void *user_data)
-{
- struct eloop_timeout *tmp;
-
- tmp = eloop.timeout;
- while (tmp != NULL) {
- if (tmp->handler == handler &&
- tmp->eloop_data == eloop_data &&
- tmp->user_data == user_data)
- return 1;
-
- tmp = tmp->next;
- }
-
- return 0;
-}
-
-
-/* TODO: replace with suitable signal handler */
-#if 0
-static void eloop_handle_signal(int sig)
-{
- int i;
-
- eloop.signaled++;
- for (i = 0; i < eloop.signal_count; i++) {
- if (eloop.signals[i].sig == sig) {
- eloop.signals[i].signaled++;
- break;
- }
- }
-}
-#endif
-
-
-static void eloop_process_pending_signals(void)
-{
- int i;
-
- if (eloop.signaled == 0)
- return;
- eloop.signaled = 0;
-
- if (eloop.pending_terminate) {
- eloop.pending_terminate = 0;
- }
-
- for (i = 0; i < eloop.signal_count; i++) {
- if (eloop.signals[i].signaled) {
- eloop.signals[i].signaled = 0;
- eloop.signals[i].handler(eloop.signals[i].sig,
- eloop.user_data,
- eloop.signals[i].user_data);
- }
- }
-}
-
-
-int eloop_register_signal(int sig,
- void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
- void *user_data)
-{
- struct eloop_signal *tmp;
-
- tmp = (struct eloop_signal *)
- realloc(eloop.signals,
- (eloop.signal_count + 1) *
- sizeof(struct eloop_signal));
- if (tmp == NULL)
- return -1;
-
- tmp[eloop.signal_count].sig = sig;
- tmp[eloop.signal_count].user_data = user_data;
- tmp[eloop.signal_count].handler = handler;
- tmp[eloop.signal_count].signaled = 0;
- eloop.signal_count++;
- eloop.signals = tmp;
-
- /* TODO: register signal handler */
-
- return 0;
-}
-
-
-int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
- void *user_data)
-{
-#if 0
- /* TODO: for example */
- int ret = eloop_register_signal(SIGINT, handler, user_data);
- if (ret == 0)
- ret = eloop_register_signal(SIGTERM, handler, user_data);
- return ret;
-#endif
- return 0;
-}
-
-
-int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
- void *user_data)
-{
-#if 0
- /* TODO: for example */
- return eloop_register_signal(SIGHUP, handler, user_data);
-#endif
- return 0;
-}
-
-
-void eloop_run(void)
-{
- int i;
- struct os_time tv, now;
-
- while (!eloop.terminate &&
- (eloop.timeout || eloop.reader_count > 0)) {
- if (eloop.timeout) {
- os_get_time(&now);
- if (os_time_before(&now, &eloop.timeout->time))
- os_time_sub(&eloop.timeout->time, &now, &tv);
- else
- tv.sec = tv.usec = 0;
- }
-
- /*
- * TODO: wait for any event (read socket ready, timeout (tv),
- * signal
- */
- os_sleep(1, 0); /* just a dummy wait for testing */
-
- eloop_process_pending_signals();
-
- /* check if some registered timeouts have occurred */
- if (eloop.timeout) {
- struct eloop_timeout *tmp;
-
- os_get_time(&now);
- if (!os_time_before(&now, &eloop.timeout->time)) {
- tmp = eloop.timeout;
- eloop.timeout = eloop.timeout->next;
- tmp->handler(tmp->eloop_data,
- tmp->user_data);
- free(tmp);
- }
-
- }
-
- eloop.reader_table_changed = 0;
- for (i = 0; i < eloop.reader_count; i++) {
- /*
- * TODO: call each handler that has pending data to
- * read
- */
- if (0 /* TODO: eloop.readers[i].sock ready */) {
- eloop.readers[i].handler(
- eloop.readers[i].sock,
- eloop.readers[i].eloop_data,
- eloop.readers[i].user_data);
- if (eloop.reader_table_changed)
- break;
- }
- }
- }
-}
-
-
-void eloop_terminate(void)
-{
- eloop.terminate = 1;
-}
-
-
-void eloop_destroy(void)
-{
- struct eloop_timeout *timeout, *prev;
-
- timeout = eloop.timeout;
- while (timeout != NULL) {
- prev = timeout;
- timeout = timeout->next;
- free(prev);
- }
- free(eloop.readers);
- free(eloop.signals);
-}
-
-
-int eloop_terminated(void)
-{
- return eloop.terminate;
-}
-
-
-void eloop_wait_for_read_sock(int sock)
-{
- /*
- * TODO: wait for the file descriptor to have something available for
- * reading
- */
-}
diff --git a/contrib/wpa/src/utils/eloop_win.c b/contrib/wpa/src/utils/eloop_win.c
index 1fafeb2..de47fb2 100644
--- a/contrib/wpa/src/utils/eloop_win.c
+++ b/contrib/wpa/src/utils/eloop_win.c
@@ -1,6 +1,6 @@
/*
* Event loop based on Windows events and WaitForMultipleObjects
- * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#include <winsock2.h>
#include "common.h"
+#include "list.h"
#include "eloop.h"
@@ -29,11 +30,11 @@ struct eloop_event {
};
struct eloop_timeout {
- struct os_time time;
+ struct dl_list list;
+ struct os_reltime time;
void *eloop_data;
void *user_data;
eloop_timeout_handler handler;
- struct eloop_timeout *next;
};
struct eloop_signal {
@@ -51,7 +52,7 @@ struct eloop_data {
size_t event_count;
struct eloop_event *events;
- struct eloop_timeout *timeout;
+ struct dl_list timeout;
int signal_count;
struct eloop_signal *signals;
@@ -74,6 +75,7 @@ static struct eloop_data eloop;
int eloop_init(void)
{
os_memset(&eloop, 0, sizeof(eloop));
+ dl_list_init(&eloop.timeout);
eloop.num_handles = 1;
eloop.handles = os_malloc(eloop.num_handles *
sizeof(eloop.handles[0]));
@@ -236,13 +238,16 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
- struct eloop_timeout *timeout, *tmp, *prev;
+ struct eloop_timeout *timeout, *tmp;
os_time_t now_sec;
- timeout = os_malloc(sizeof(*timeout));
+ timeout = os_zalloc(sizeof(*timeout));
if (timeout == NULL)
return -1;
- os_get_time(&timeout->time);
+ if (os_get_reltime(&timeout->time) < 0) {
+ os_free(timeout);
+ return -1;
+ }
now_sec = timeout->time.sec;
timeout->time.sec += secs;
if (timeout->time.sec < now_sec) {
@@ -263,85 +268,156 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
timeout->eloop_data = eloop_data;
timeout->user_data = user_data;
timeout->handler = handler;
- timeout->next = NULL;
- if (eloop.timeout == NULL) {
- eloop.timeout = timeout;
- return 0;
+ /* Maintain timeouts in order of increasing time */
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (os_reltime_before(&timeout->time, &tmp->time)) {
+ dl_list_add(tmp->list.prev, &timeout->list);
+ return 0;
+ }
}
+ dl_list_add_tail(&eloop.timeout, &timeout->list);
- prev = NULL;
- tmp = eloop.timeout;
- while (tmp != NULL) {
- if (os_time_before(&timeout->time, &tmp->time))
- break;
- prev = tmp;
- tmp = tmp->next;
- }
+ return 0;
+}
- if (prev == NULL) {
- timeout->next = eloop.timeout;
- eloop.timeout = timeout;
- } else {
- timeout->next = prev->next;
- prev->next = timeout;
- }
- return 0;
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+ dl_list_del(&timeout->list);
+ os_free(timeout);
}
int eloop_cancel_timeout(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
- struct eloop_timeout *timeout, *prev, *next;
+ struct eloop_timeout *timeout, *prev;
int removed = 0;
- prev = NULL;
- timeout = eloop.timeout;
- while (timeout != NULL) {
- next = timeout->next;
-
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
if (timeout->handler == handler &&
(timeout->eloop_data == eloop_data ||
eloop_data == ELOOP_ALL_CTX) &&
(timeout->user_data == user_data ||
user_data == ELOOP_ALL_CTX)) {
- if (prev == NULL)
- eloop.timeout = next;
- else
- prev->next = next;
- os_free(timeout);
+ eloop_remove_timeout(timeout);
removed++;
- } else
- prev = timeout;
-
- timeout = next;
+ }
}
return removed;
}
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data,
+ struct os_reltime *remaining)
+{
+ struct eloop_timeout *timeout, *prev;
+ int removed = 0;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ remaining->sec = remaining->usec = 0;
+
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data) &&
+ (timeout->user_data == user_data)) {
+ removed = 1;
+ if (os_reltime_before(&now, &timeout->time))
+ os_reltime_sub(&timeout->time, &now, remaining);
+ eloop_remove_timeout(timeout);
+ break;
+ }
+ }
+ return removed;
+}
+
+
int eloop_is_timeout_registered(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_timeout *tmp;
- tmp = eloop.timeout;
- while (tmp != NULL) {
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
if (tmp->handler == handler &&
tmp->eloop_data == eloop_data &&
tmp->user_data == user_data)
return 1;
-
- tmp = tmp->next;
}
return 0;
}
+int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
+ eloop_timeout_handler handler, void *eloop_data,
+ void *user_data)
+{
+ struct os_reltime now, requested, remaining;
+ struct eloop_timeout *tmp;
+
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data) {
+ requested.sec = req_secs;
+ requested.usec = req_usecs;
+ os_get_reltime(&now);
+ os_reltime_sub(&tmp->time, &now, &remaining);
+ if (os_reltime_before(&requested, &remaining)) {
+ eloop_cancel_timeout(handler, eloop_data,
+ user_data);
+ eloop_register_timeout(requested.sec,
+ requested.usec,
+ handler, eloop_data,
+ user_data);
+ return 1;
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
+ eloop_timeout_handler handler, void *eloop_data,
+ void *user_data)
+{
+ struct os_reltime now, requested, remaining;
+ struct eloop_timeout *tmp;
+
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data) {
+ requested.sec = req_secs;
+ requested.usec = req_usecs;
+ os_get_reltime(&now);
+ os_reltime_sub(&tmp->time, &now, &remaining);
+ if (os_reltime_before(&remaining, &requested)) {
+ eloop_cancel_timeout(handler, eloop_data,
+ user_data);
+ eloop_register_timeout(requested.sec,
+ requested.usec,
+ handler, eloop_data,
+ user_data);
+ return 1;
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
/* TODO: replace with suitable signal handler */
#if 0
static void eloop_handle_signal(int sig)
@@ -456,18 +532,21 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
void eloop_run(void)
{
- struct os_time tv, now;
- DWORD count, ret, timeout, err;
+ struct os_reltime tv, now;
+ DWORD count, ret, timeout_val, err;
size_t i;
while (!eloop.terminate &&
- (eloop.timeout || eloop.reader_count > 0 ||
+ (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0 ||
eloop.event_count > 0)) {
+ struct eloop_timeout *timeout;
tv.sec = tv.usec = 0;
- if (eloop.timeout) {
- os_get_time(&now);
- if (os_time_before(&now, &eloop.timeout->time))
- os_time_sub(&eloop.timeout->time, &now, &tv);
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
+ os_get_reltime(&now);
+ if (os_reltime_before(&now, &timeout->time))
+ os_reltime_sub(&timeout->time, &now, &tv);
}
count = 0;
@@ -480,10 +559,10 @@ void eloop_run(void)
if (eloop.term_event)
eloop.handles[count++] = eloop.term_event;
- if (eloop.timeout)
- timeout = tv.sec * 1000 + tv.usec / 1000;
+ if (timeout)
+ timeout_val = tv.sec * 1000 + tv.usec / 1000;
else
- timeout = INFINITE;
+ timeout_val = INFINITE;
if (count > MAXIMUM_WAIT_OBJECTS) {
printf("WaitForMultipleObjects: Too many events: "
@@ -493,26 +572,27 @@ void eloop_run(void)
}
#ifdef _WIN32_WCE
ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
- timeout);
+ timeout_val);
#else /* _WIN32_WCE */
ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
- timeout, TRUE);
+ timeout_val, TRUE);
#endif /* _WIN32_WCE */
err = GetLastError();
eloop_process_pending_signals();
/* check if some registered timeouts have occurred */
- if (eloop.timeout) {
- struct eloop_timeout *tmp;
-
- os_get_time(&now);
- if (!os_time_before(&now, &eloop.timeout->time)) {
- tmp = eloop.timeout;
- eloop.timeout = eloop.timeout->next;
- tmp->handler(tmp->eloop_data,
- tmp->user_data);
- os_free(tmp);
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
+ os_get_reltime(&now);
+ if (!os_reltime_before(&now, &timeout->time)) {
+ void *eloop_data = timeout->eloop_data;
+ void *user_data = timeout->user_data;
+ eloop_timeout_handler handler =
+ timeout->handler;
+ eloop_remove_timeout(timeout);
+ handler(eloop_data, user_data);
}
}
@@ -571,11 +651,9 @@ void eloop_destroy(void)
{
struct eloop_timeout *timeout, *prev;
- timeout = eloop.timeout;
- while (timeout != NULL) {
- prev = timeout;
- timeout = timeout->next;
- os_free(prev);
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ eloop_remove_timeout(timeout);
}
os_free(eloop.readers);
os_free(eloop.signals);
diff --git a/contrib/wpa/src/utils/ext_password_test.c b/contrib/wpa/src/utils/ext_password_test.c
index 3801bb8..b3a4552 100644
--- a/contrib/wpa/src/utils/ext_password_test.c
+++ b/contrib/wpa/src/utils/ext_password_test.c
@@ -36,7 +36,7 @@ static void ext_password_test_deinit(void *ctx)
{
struct ext_password_test_data *data = ctx;
- os_free(data->params);
+ str_clear_free(data->params);
os_free(data);
}
diff --git a/contrib/wpa/src/utils/http-utils.h b/contrib/wpa/src/utils/http-utils.h
new file mode 100644
index 0000000..8d4399a
--- /dev/null
+++ b/contrib/wpa/src/utils/http-utils.h
@@ -0,0 +1,63 @@
+/*
+ * HTTP wrapper
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HTTP_UTILS_H
+#define HTTP_UTILS_H
+
+struct http_ctx;
+
+struct http_othername {
+ char *oid;
+ u8 *data;
+ size_t len;
+};
+
+#define HTTP_MAX_CERT_LOGO_HASH 32
+
+struct http_logo {
+ char *alg_oid;
+ u8 *hash;
+ size_t hash_len;
+ char *uri;
+};
+
+struct http_cert {
+ char **dnsname;
+ unsigned int num_dnsname;
+ struct http_othername *othername;
+ unsigned int num_othername;
+ struct http_logo *logo;
+ unsigned int num_logo;
+};
+
+int soap_init_client(struct http_ctx *ctx, const char *address,
+ const char *ca_fname, const char *username,
+ const char *password, const char *client_cert,
+ const char *client_key);
+int soap_reinit_client(struct http_ctx *ctx);
+xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node);
+
+struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx);
+void http_ocsp_set(struct http_ctx *ctx, int val);
+void http_deinit_ctx(struct http_ctx *ctx);
+
+int http_download_file(struct http_ctx *ctx, const char *url,
+ const char *fname, const char *ca_fname);
+char * http_post(struct http_ctx *ctx, const char *url, const char *data,
+ const char *content_type, const char *ext_hdr,
+ const char *ca_fname,
+ const char *username, const char *password,
+ const char *client_cert, const char *client_key,
+ size_t *resp_len);
+void http_set_cert_cb(struct http_ctx *ctx,
+ int (*cb)(void *ctx, struct http_cert *cert),
+ void *cb_ctx);
+const char * http_get_err(struct http_ctx *ctx);
+void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname);
+
+#endif /* HTTP_UTILS_H */
diff --git a/contrib/wpa/src/utils/http_curl.c b/contrib/wpa/src/utils/http_curl.c
new file mode 100644
index 0000000..b38cf79
--- /dev/null
+++ b/contrib/wpa/src/utils/http_curl.c
@@ -0,0 +1,1641 @@
+/*
+ * HTTP wrapper for libcurl
+ * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <curl/curl.h>
+#ifdef EAP_TLS_OPENSSL
+#include <openssl/ssl.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+
+#ifdef SSL_set_tlsext_status_type
+#ifndef OPENSSL_NO_TLSEXT
+#define HAVE_OCSP
+#include <openssl/err.h>
+#include <openssl/ocsp.h>
+#endif /* OPENSSL_NO_TLSEXT */
+#endif /* SSL_set_tlsext_status_type */
+#endif /* EAP_TLS_OPENSSL */
+
+#include "common.h"
+#include "xml-utils.h"
+#include "http-utils.h"
+
+
+struct http_ctx {
+ void *ctx;
+ struct xml_node_ctx *xml;
+ CURL *curl;
+ struct curl_slist *curl_hdr;
+ char *svc_address;
+ char *svc_ca_fname;
+ char *svc_username;
+ char *svc_password;
+ char *svc_client_cert;
+ char *svc_client_key;
+ char *curl_buf;
+ size_t curl_buf_len;
+
+ int (*cert_cb)(void *ctx, struct http_cert *cert);
+ void *cert_cb_ctx;
+
+ enum {
+ NO_OCSP, OPTIONAL_OCSP, MANDATORY_OCSP
+ } ocsp;
+ X509 *peer_cert;
+ X509 *peer_issuer;
+ X509 *peer_issuer_issuer;
+
+ const char *last_err;
+};
+
+
+static void clear_curl(struct http_ctx *ctx)
+{
+ if (ctx->curl) {
+ curl_easy_cleanup(ctx->curl);
+ ctx->curl = NULL;
+ }
+ if (ctx->curl_hdr) {
+ curl_slist_free_all(ctx->curl_hdr);
+ ctx->curl_hdr = NULL;
+ }
+}
+
+
+static void clone_str(char **dst, const char *src)
+{
+ os_free(*dst);
+ if (src)
+ *dst = os_strdup(src);
+ else
+ *dst = NULL;
+}
+
+
+static void debug_dump(struct http_ctx *ctx, const char *title,
+ const char *buf, size_t len)
+{
+ char *txt;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] < 32 && buf[i] != '\t' && buf[i] != '\n' &&
+ buf[i] != '\r') {
+ wpa_hexdump_ascii(MSG_MSGDUMP, title, buf, len);
+ return;
+ }
+ }
+
+ txt = os_malloc(len + 1);
+ if (txt == NULL)
+ return;
+ os_memcpy(txt, buf, len);
+ txt[len] = '\0';
+ while (len > 0) {
+ len--;
+ if (txt[len] == '\n' || txt[len] == '\r')
+ txt[len] = '\0';
+ else
+ break;
+ }
+ wpa_printf(MSG_MSGDUMP, "%s[%s]", title, txt);
+ os_free(txt);
+}
+
+
+static int curl_cb_debug(CURL *curl, curl_infotype info, char *buf, size_t len,
+ void *userdata)
+{
+ struct http_ctx *ctx = userdata;
+ switch (info) {
+ case CURLINFO_TEXT:
+ debug_dump(ctx, "CURLINFO_TEXT", buf, len);
+ break;
+ case CURLINFO_HEADER_IN:
+ debug_dump(ctx, "CURLINFO_HEADER_IN", buf, len);
+ break;
+ case CURLINFO_HEADER_OUT:
+ debug_dump(ctx, "CURLINFO_HEADER_OUT", buf, len);
+ break;
+ case CURLINFO_DATA_IN:
+ debug_dump(ctx, "CURLINFO_DATA_IN", buf, len);
+ break;
+ case CURLINFO_DATA_OUT:
+ debug_dump(ctx, "CURLINFO_DATA_OUT", buf, len);
+ break;
+ case CURLINFO_SSL_DATA_IN:
+ wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_IN - %d",
+ (int) len);
+ break;
+ case CURLINFO_SSL_DATA_OUT:
+ wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_OUT - %d",
+ (int) len);
+ break;
+ case CURLINFO_END:
+ wpa_printf(MSG_DEBUG, "debug - CURLINFO_END - %d",
+ (int) len);
+ break;
+ }
+ return 0;
+}
+
+
+static size_t curl_cb_write(void *ptr, size_t size, size_t nmemb,
+ void *userdata)
+{
+ struct http_ctx *ctx = userdata;
+ char *n;
+ n = os_realloc(ctx->curl_buf, ctx->curl_buf_len + size * nmemb + 1);
+ if (n == NULL)
+ return 0;
+ ctx->curl_buf = n;
+ os_memcpy(n + ctx->curl_buf_len, ptr, size * nmemb);
+ n[ctx->curl_buf_len + size * nmemb] = '\0';
+ ctx->curl_buf_len += size * nmemb;
+ return size * nmemb;
+}
+
+
+#ifdef EAP_TLS_OPENSSL
+
+static void debug_dump_cert(const char *title, X509 *cert)
+{
+ BIO *out;
+ char *txt;
+ size_t rlen;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ int res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_MSGDUMP, "%s:\n%s", title, txt);
+ }
+ os_free(txt);
+ }
+ BIO_free(out);
+}
+
+
+static void add_alt_name_othername(struct http_ctx *ctx, struct http_cert *cert,
+ OTHERNAME *o)
+{
+ char txt[100];
+ int res;
+ struct http_othername *on;
+ ASN1_TYPE *val;
+
+ on = os_realloc_array(cert->othername, cert->num_othername + 1,
+ sizeof(struct http_othername));
+ if (on == NULL)
+ return;
+ cert->othername = on;
+ on = &on[cert->num_othername];
+ os_memset(on, 0, sizeof(*on));
+
+ res = OBJ_obj2txt(txt, sizeof(txt), o->type_id, 1);
+ if (res < 0 || res >= (int) sizeof(txt))
+ return;
+
+ on->oid = os_strdup(txt);
+ if (on->oid == NULL)
+ return;
+
+ val = o->value;
+ on->data = val->value.octet_string->data;
+ on->len = val->value.octet_string->length;
+
+ cert->num_othername++;
+}
+
+
+static void add_alt_name_dns(struct http_ctx *ctx, struct http_cert *cert,
+ ASN1_STRING *name)
+{
+ char *buf;
+ char **n;
+
+ buf = NULL;
+ if (ASN1_STRING_to_UTF8((unsigned char **) &buf, name) < 0)
+ return;
+
+ n = os_realloc_array(cert->dnsname, cert->num_dnsname + 1,
+ sizeof(char *));
+ if (n == NULL)
+ return;
+
+ cert->dnsname = n;
+ n[cert->num_dnsname] = buf;
+ cert->num_dnsname++;
+}
+
+
+static void add_alt_name(struct http_ctx *ctx, struct http_cert *cert,
+ const GENERAL_NAME *name)
+{
+ switch (name->type) {
+ case GEN_OTHERNAME:
+ add_alt_name_othername(ctx, cert, name->d.otherName);
+ break;
+ case GEN_DNS:
+ add_alt_name_dns(ctx, cert, name->d.dNSName);
+ break;
+ }
+}
+
+
+static void add_alt_names(struct http_ctx *ctx, struct http_cert *cert,
+ GENERAL_NAMES *names)
+{
+ int num, i;
+
+ num = sk_GENERAL_NAME_num(names);
+ for (i = 0; i < num; i++) {
+ const GENERAL_NAME *name;
+ name = sk_GENERAL_NAME_value(names, i);
+ add_alt_name(ctx, cert, name);
+ }
+}
+
+
+/* RFC 3709 */
+
+typedef struct {
+ X509_ALGOR *hashAlg;
+ ASN1_OCTET_STRING *hashValue;
+} HashAlgAndValue;
+
+typedef struct {
+ STACK_OF(HashAlgAndValue) *refStructHash;
+ STACK_OF(ASN1_IA5STRING) *refStructURI;
+} LogotypeReference;
+
+typedef struct {
+ ASN1_IA5STRING *mediaType;
+ STACK_OF(HashAlgAndValue) *logotypeHash;
+ STACK_OF(ASN1_IA5STRING) *logotypeURI;
+} LogotypeDetails;
+
+typedef struct {
+ int type;
+ union {
+ ASN1_INTEGER *numBits;
+ ASN1_INTEGER *tableSize;
+ } d;
+} LogotypeImageResolution;
+
+typedef struct {
+ ASN1_INTEGER *type; /* LogotypeImageType ::= INTEGER */
+ ASN1_INTEGER *fileSize;
+ ASN1_INTEGER *xSize;
+ ASN1_INTEGER *ySize;
+ LogotypeImageResolution *resolution;
+ ASN1_IA5STRING *language;
+} LogotypeImageInfo;
+
+typedef struct {
+ LogotypeDetails *imageDetails;
+ LogotypeImageInfo *imageInfo;
+} LogotypeImage;
+
+typedef struct {
+ ASN1_INTEGER *fileSize;
+ ASN1_INTEGER *playTime;
+ ASN1_INTEGER *channels;
+ ASN1_INTEGER *sampleRate;
+ ASN1_IA5STRING *language;
+} LogotypeAudioInfo;
+
+typedef struct {
+ LogotypeDetails *audioDetails;
+ LogotypeAudioInfo *audioInfo;
+} LogotypeAudio;
+
+typedef struct {
+ STACK_OF(LogotypeImage) *image;
+ STACK_OF(LogotypeAudio) *audio;
+} LogotypeData;
+
+typedef struct {
+ int type;
+ union {
+ LogotypeData *direct;
+ LogotypeReference *indirect;
+ } d;
+} LogotypeInfo;
+
+typedef struct {
+ ASN1_OBJECT *logotypeType;
+ LogotypeInfo *info;
+} OtherLogotypeInfo;
+
+typedef struct {
+ STACK_OF(LogotypeInfo) *communityLogos;
+ LogotypeInfo *issuerLogo;
+ LogotypeInfo *subjectLogo;
+ STACK_OF(OtherLogotypeInfo) *otherLogos;
+} LogotypeExtn;
+
+ASN1_SEQUENCE(HashAlgAndValue) = {
+ ASN1_SIMPLE(HashAlgAndValue, hashAlg, X509_ALGOR),
+ ASN1_SIMPLE(HashAlgAndValue, hashValue, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(HashAlgAndValue);
+
+ASN1_SEQUENCE(LogotypeReference) = {
+ ASN1_SEQUENCE_OF(LogotypeReference, refStructHash, HashAlgAndValue),
+ ASN1_SEQUENCE_OF(LogotypeReference, refStructURI, ASN1_IA5STRING)
+} ASN1_SEQUENCE_END(LogotypeReference);
+
+ASN1_SEQUENCE(LogotypeDetails) = {
+ ASN1_SIMPLE(LogotypeDetails, mediaType, ASN1_IA5STRING),
+ ASN1_SEQUENCE_OF(LogotypeDetails, logotypeHash, HashAlgAndValue),
+ ASN1_SEQUENCE_OF(LogotypeDetails, logotypeURI, ASN1_IA5STRING)
+} ASN1_SEQUENCE_END(LogotypeDetails);
+
+ASN1_CHOICE(LogotypeImageResolution) = {
+ ASN1_IMP(LogotypeImageResolution, d.numBits, ASN1_INTEGER, 1),
+ ASN1_IMP(LogotypeImageResolution, d.tableSize, ASN1_INTEGER, 2)
+} ASN1_CHOICE_END(LogotypeImageResolution);
+
+ASN1_SEQUENCE(LogotypeImageInfo) = {
+ ASN1_IMP_OPT(LogotypeImageInfo, type, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(LogotypeImageInfo, fileSize, ASN1_INTEGER),
+ ASN1_SIMPLE(LogotypeImageInfo, xSize, ASN1_INTEGER),
+ ASN1_SIMPLE(LogotypeImageInfo, ySize, ASN1_INTEGER),
+ ASN1_OPT(LogotypeImageInfo, resolution, LogotypeImageResolution),
+ ASN1_IMP_OPT(LogotypeImageInfo, language, ASN1_IA5STRING, 4),
+} ASN1_SEQUENCE_END(LogotypeImageInfo);
+
+ASN1_SEQUENCE(LogotypeImage) = {
+ ASN1_SIMPLE(LogotypeImage, imageDetails, LogotypeDetails),
+ ASN1_OPT(LogotypeImage, imageInfo, LogotypeImageInfo)
+} ASN1_SEQUENCE_END(LogotypeImage);
+
+ASN1_SEQUENCE(LogotypeAudioInfo) = {
+ ASN1_SIMPLE(LogotypeAudioInfo, fileSize, ASN1_INTEGER),
+ ASN1_SIMPLE(LogotypeAudioInfo, playTime, ASN1_INTEGER),
+ ASN1_SIMPLE(LogotypeAudioInfo, channels, ASN1_INTEGER),
+ ASN1_IMP_OPT(LogotypeAudioInfo, sampleRate, ASN1_INTEGER, 3),
+ ASN1_IMP_OPT(LogotypeAudioInfo, language, ASN1_IA5STRING, 4)
+} ASN1_SEQUENCE_END(LogotypeAudioInfo);
+
+ASN1_SEQUENCE(LogotypeAudio) = {
+ ASN1_SIMPLE(LogotypeAudio, audioDetails, LogotypeDetails),
+ ASN1_OPT(LogotypeAudio, audioInfo, LogotypeAudioInfo)
+} ASN1_SEQUENCE_END(LogotypeAudio);
+
+ASN1_SEQUENCE(LogotypeData) = {
+ ASN1_SEQUENCE_OF_OPT(LogotypeData, image, LogotypeImage),
+ ASN1_IMP_SEQUENCE_OF_OPT(LogotypeData, audio, LogotypeAudio, 1)
+} ASN1_SEQUENCE_END(LogotypeData);
+
+ASN1_CHOICE(LogotypeInfo) = {
+ ASN1_IMP(LogotypeInfo, d.direct, LogotypeData, 0),
+ ASN1_IMP(LogotypeInfo, d.indirect, LogotypeReference, 1)
+} ASN1_CHOICE_END(LogotypeInfo);
+
+ASN1_SEQUENCE(OtherLogotypeInfo) = {
+ ASN1_SIMPLE(OtherLogotypeInfo, logotypeType, ASN1_OBJECT),
+ ASN1_SIMPLE(OtherLogotypeInfo, info, LogotypeInfo)
+} ASN1_SEQUENCE_END(OtherLogotypeInfo);
+
+ASN1_SEQUENCE(LogotypeExtn) = {
+ ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, communityLogos, LogotypeInfo, 0),
+ ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 1),
+ ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 2),
+ ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, otherLogos, OtherLogotypeInfo, 3)
+} ASN1_SEQUENCE_END(LogotypeExtn);
+
+IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn);
+
+#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))
+#define sk_LogotypeImage_value(st, i) SKM_sk_value(LogotypeImage, (st), (i))
+#define sk_LogotypeAudio_num(st) SKM_sk_num(LogotypeAudio, (st))
+#define sk_LogotypeAudio_value(st, i) SKM_sk_value(LogotypeAudio, (st), (i))
+#define sk_HashAlgAndValue_num(st) SKM_sk_num(HashAlgAndValue, (st))
+#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))
+
+
+static void add_logo(struct http_ctx *ctx, struct http_cert *hcert,
+ HashAlgAndValue *hash, ASN1_IA5STRING *uri)
+{
+ char txt[100];
+ int res, len;
+ struct http_logo *n;
+
+ if (hash == NULL || uri == NULL)
+ return;
+
+ res = OBJ_obj2txt(txt, sizeof(txt), hash->hashAlg->algorithm, 1);
+ if (res < 0 || res >= (int) sizeof(txt))
+ return;
+
+ n = os_realloc_array(hcert->logo, hcert->num_logo + 1,
+ sizeof(struct http_logo));
+ if (n == NULL)
+ return;
+ hcert->logo = n;
+ n = &hcert->logo[hcert->num_logo];
+ os_memset(n, 0, sizeof(*n));
+
+ n->alg_oid = os_strdup(txt);
+ if (n->alg_oid == NULL)
+ return;
+
+ n->hash_len = ASN1_STRING_length(hash->hashValue);
+ n->hash = os_malloc(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);
+ if (n->uri == NULL) {
+ os_free(n->alg_oid);
+ os_free(n->hash);
+ return;
+ }
+ os_memcpy(n->uri, ASN1_STRING_data(uri), len);
+ n->uri[len] = '\0';
+
+ hcert->num_logo++;
+}
+
+
+static void add_logo_direct(struct http_ctx *ctx, struct http_cert *hcert,
+ LogotypeData *data)
+{
+ int i, num;
+
+ if (data->image == NULL)
+ return;
+
+ num = sk_LogotypeImage_num(data->image);
+ for (i = 0; i < num; i++) {
+ LogotypeImage *image;
+ LogotypeDetails *details;
+ int j, hash_num, uri_num;
+ HashAlgAndValue *found_hash = NULL;
+
+ image = sk_LogotypeImage_value(data->image, i);
+ if (image == NULL)
+ continue;
+
+ details = image->imageDetails;
+ if (details == NULL)
+ continue;
+
+ hash_num = sk_HashAlgAndValue_num(details->logotypeHash);
+ for (j = 0; j < hash_num; j++) {
+ HashAlgAndValue *hash;
+ char txt[100];
+ int res;
+ hash = sk_HashAlgAndValue_value(details->logotypeHash,
+ j);
+ if (hash == NULL)
+ continue;
+ res = OBJ_obj2txt(txt, sizeof(txt),
+ hash->hashAlg->algorithm, 1);
+ if (res < 0 || res >= (int) sizeof(txt))
+ continue;
+ if (os_strcmp(txt, "2.16.840.1.101.3.4.2.1") == 0) {
+ found_hash = hash;
+ break;
+ }
+ }
+
+ if (!found_hash) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No SHA256 hash found for the logo");
+ continue;
+ }
+
+ uri_num = sk_ASN1_IA5STRING_num(details->logotypeURI);
+ for (j = 0; j < uri_num; j++) {
+ ASN1_IA5STRING *uri;
+ uri = sk_ASN1_IA5STRING_value(details->logotypeURI, j);
+ add_logo(ctx, hcert, found_hash, uri);
+ }
+ }
+}
+
+
+static void add_logo_indirect(struct http_ctx *ctx, struct http_cert *hcert,
+ LogotypeReference *ref)
+{
+ int j, hash_num, uri_num;
+
+ hash_num = sk_HashAlgAndValue_num(ref->refStructHash);
+ uri_num = sk_ASN1_IA5STRING_num(ref->refStructURI);
+ if (hash_num != uri_num) {
+ wpa_printf(MSG_INFO, "Unexpected LogotypeReference array size difference %d != %d",
+ hash_num, uri_num);
+ return;
+ }
+
+ for (j = 0; j < hash_num; j++) {
+ HashAlgAndValue *hash;
+ ASN1_IA5STRING *uri;
+ hash = sk_HashAlgAndValue_value(ref->refStructHash, j);
+ uri = sk_ASN1_IA5STRING_value(ref->refStructURI, j);
+ add_logo(ctx, hcert, hash, uri);
+ }
+}
+
+
+static void i2r_HashAlgAndValue(HashAlgAndValue *hash, BIO *out, int indent)
+{
+ int i;
+ const unsigned char *data;
+
+ BIO_printf(out, "%*shashAlg: ", indent, "");
+ i2a_ASN1_OBJECT(out, hash->hashAlg->algorithm);
+ BIO_printf(out, "\n");
+
+ BIO_printf(out, "%*shashValue: ", indent, "");
+ data = hash->hashValue->data;
+ for (i = 0; i < hash->hashValue->length; i++)
+ BIO_printf(out, "%s%02x", i > 0 ? ":" : "", data[i]);
+ BIO_printf(out, "\n");
+}
+
+static void i2r_LogotypeDetails(LogotypeDetails *details, BIO *out, int indent)
+{
+ int i, num;
+
+ BIO_printf(out, "%*sLogotypeDetails\n", indent, "");
+ if (details->mediaType) {
+ BIO_printf(out, "%*smediaType: ", indent, "");
+ ASN1_STRING_print(out, details->mediaType);
+ BIO_printf(out, "\n");
+ }
+
+ num = details->logotypeHash ?
+ sk_HashAlgAndValue_num(details->logotypeHash) : 0;
+ for (i = 0; i < num; i++) {
+ HashAlgAndValue *hash;
+ hash = sk_HashAlgAndValue_value(details->logotypeHash, i);
+ i2r_HashAlgAndValue(hash, out, indent);
+ }
+
+ num = details->logotypeURI ?
+ sk_ASN1_IA5STRING_num(details->logotypeURI) : 0;
+ for (i = 0; i < num; i++) {
+ ASN1_IA5STRING *uri;
+ uri = sk_ASN1_IA5STRING_value(details->logotypeURI, i);
+ BIO_printf(out, "%*slogotypeURI: ", indent, "");
+ ASN1_STRING_print(out, uri);
+ BIO_printf(out, "\n");
+ }
+}
+
+static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent)
+{
+ long val;
+
+ BIO_printf(out, "%*sLogotypeImageInfo\n", indent, "");
+ if (info->type) {
+ val = ASN1_INTEGER_get(info->type);
+ BIO_printf(out, "%*stype: %ld\n", indent, "", val);
+ } else {
+ BIO_printf(out, "%*stype: default (1)\n", indent, "");
+ }
+ 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 */
+ }
+ if (info->language) {
+ BIO_printf(out, "%*slanguage: ", indent, "");
+ ASN1_STRING_print(out, info->language);
+ BIO_printf(out, "\n");
+ }
+}
+
+static void i2r_LogotypeImage(LogotypeImage *image, BIO *out, int indent)
+{
+ BIO_printf(out, "%*sLogotypeImage\n", indent, "");
+ if (image->imageDetails) {
+ i2r_LogotypeDetails(image->imageDetails, out, indent + 4);
+ }
+ if (image->imageInfo) {
+ i2r_LogotypeImageInfo(image->imageInfo, out, indent + 4);
+ }
+}
+
+static void i2r_LogotypeData(LogotypeData *data, const char *title, BIO *out,
+ int indent)
+{
+ int i, num;
+
+ BIO_printf(out, "%*s%s - LogotypeData\n", indent, "", title);
+
+ num = data->image ? sk_LogotypeImage_num(data->image) : 0;
+ for (i = 0; i < num; i++) {
+ LogotypeImage *image = sk_LogotypeImage_value(data->image, i);
+ i2r_LogotypeImage(image, out, indent + 4);
+ }
+
+ num = data->audio ? sk_LogotypeAudio_num(data->audio) : 0;
+ for (i = 0; i < num; i++) {
+ BIO_printf(out, "%*saudio: TODO\n", indent, "");
+ }
+}
+
+static void i2r_LogotypeReference(LogotypeReference *ref, const char *title,
+ BIO *out, int indent)
+{
+ int i, hash_num, uri_num;
+
+ BIO_printf(out, "%*s%s - LogotypeReference\n", indent, "", title);
+
+ hash_num = ref->refStructHash ?
+ sk_HashAlgAndValue_num(ref->refStructHash) : 0;
+ uri_num = ref->refStructURI ?
+ sk_ASN1_IA5STRING_num(ref->refStructURI) : 0;
+ if (hash_num != uri_num) {
+ BIO_printf(out, "%*sUnexpected LogotypeReference array size difference %d != %d\n",
+ indent, "", hash_num, uri_num);
+ return;
+ }
+
+ for (i = 0; i < hash_num; i++) {
+ HashAlgAndValue *hash;
+ ASN1_IA5STRING *uri;
+
+ hash = sk_HashAlgAndValue_value(ref->refStructHash, i);
+ i2r_HashAlgAndValue(hash, out, indent);
+
+ uri = sk_ASN1_IA5STRING_value(ref->refStructURI, i);
+ BIO_printf(out, "%*srefStructURI: ", indent, "");
+ ASN1_STRING_print(out, uri);
+ BIO_printf(out, "\n");
+ }
+}
+
+static void i2r_LogotypeInfo(LogotypeInfo *info, const char *title, BIO *out,
+ int indent)
+{
+ switch (info->type) {
+ case 0:
+ i2r_LogotypeData(info->d.direct, title, out, indent);
+ break;
+ case 1:
+ i2r_LogotypeReference(info->d.indirect, title, out, indent);
+ break;
+ }
+}
+
+static void debug_print_logotypeext(LogotypeExtn *logo)
+{
+ BIO *out;
+ int i, num;
+ int indent = 0;
+
+ out = BIO_new_fp(stdout, BIO_NOCLOSE);
+ if (out == NULL)
+ return;
+
+ if (logo->communityLogos) {
+ num = sk_LogotypeInfo_num(logo->communityLogos);
+ for (i = 0; i < num; i++) {
+ LogotypeInfo *info;
+ info = sk_LogotypeInfo_value(logo->communityLogos, i);
+ i2r_LogotypeInfo(info, "communityLogo", out, indent);
+ }
+ }
+
+ if (logo->issuerLogo) {
+ i2r_LogotypeInfo(logo->issuerLogo, "issuerLogo", out, indent );
+ }
+
+ if (logo->subjectLogo) {
+ i2r_LogotypeInfo(logo->subjectLogo, "subjectLogo", out, indent);
+ }
+
+ if (logo->otherLogos) {
+ BIO_printf(out, "%*sotherLogos - TODO\n", indent, "");
+ }
+
+ BIO_free(out);
+}
+
+
+static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert,
+ X509 *cert)
+{
+ ASN1_OBJECT *obj;
+ int pos;
+ X509_EXTENSION *ext;
+ ASN1_OCTET_STRING *os;
+ LogotypeExtn *logo;
+ const unsigned char *data;
+ int i, num;
+
+ obj = OBJ_txt2obj("1.3.6.1.5.5.7.1.12", 0);
+ if (obj == NULL)
+ return;
+
+ pos = X509_get_ext_by_OBJ(cert, obj, -1);
+ if (pos < 0) {
+ wpa_printf(MSG_INFO, "No logotype extension included");
+ return;
+ }
+
+ wpa_printf(MSG_INFO, "Parsing logotype extension");
+ ext = X509_get_ext(cert, pos);
+ if (!ext) {
+ wpa_printf(MSG_INFO, "Could not get logotype extension");
+ return;
+ }
+
+ os = X509_EXTENSION_get_data(ext);
+ if (os == NULL) {
+ wpa_printf(MSG_INFO, "Could not get logotype extension data");
+ return;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "logotypeExtn",
+ ASN1_STRING_data(os), ASN1_STRING_length(os));
+
+ data = ASN1_STRING_data(os);
+ logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os));
+ if (logo == NULL) {
+ wpa_printf(MSG_INFO, "Failed to parse logotypeExtn");
+ return;
+ }
+
+ if (wpa_debug_level < MSG_INFO)
+ debug_print_logotypeext(logo);
+
+ if (!logo->communityLogos) {
+ wpa_printf(MSG_INFO, "No communityLogos included");
+ LogotypeExtn_free(logo);
+ return;
+ }
+
+ num = sk_LogotypeInfo_num(logo->communityLogos);
+ for (i = 0; i < num; i++) {
+ LogotypeInfo *info;
+ info = sk_LogotypeInfo_value(logo->communityLogos, i);
+ switch (info->type) {
+ case 0:
+ add_logo_direct(ctx, hcert, info->d.direct);
+ break;
+ case 1:
+ add_logo_indirect(ctx, hcert, info->d.indirect);
+ break;
+ }
+ }
+
+ LogotypeExtn_free(logo);
+}
+
+
+static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert,
+ X509 *cert, GENERAL_NAMES **names)
+{
+ os_memset(hcert, 0, sizeof(*hcert));
+
+ *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (*names)
+ add_alt_names(ctx, hcert, *names);
+
+ add_logotype_ext(ctx, hcert, cert);
+}
+
+
+static void parse_cert_free(struct http_cert *hcert, GENERAL_NAMES *names)
+{
+ unsigned int i;
+
+ for (i = 0; i < hcert->num_dnsname; i++)
+ OPENSSL_free(hcert->dnsname[i]);
+ os_free(hcert->dnsname);
+
+ for (i = 0; i < hcert->num_othername; i++)
+ os_free(hcert->othername[i].oid);
+ os_free(hcert->othername);
+
+ for (i = 0; i < hcert->num_logo; i++) {
+ os_free(hcert->logo[i].alg_oid);
+ os_free(hcert->logo[i].hash);
+ os_free(hcert->logo[i].uri);
+ }
+ os_free(hcert->logo);
+
+ sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
+}
+
+
+static int validate_server_cert(struct http_ctx *ctx, X509 *cert)
+{
+ GENERAL_NAMES *names;
+ struct http_cert hcert;
+ int ret;
+
+ if (ctx->cert_cb == NULL)
+ return 0;
+
+ if (0) {
+ BIO *out;
+ out = BIO_new_fp(stdout, BIO_NOCLOSE);
+ X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
+ BIO_free(out);
+ }
+
+ parse_cert(ctx, &hcert, cert, &names);
+ ret = ctx->cert_cb(ctx->cert_cb_ctx, &hcert);
+ parse_cert_free(&hcert, names);
+
+ return ret;
+}
+
+
+void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname)
+{
+ BIO *in, *out;
+ X509 *cert;
+ GENERAL_NAMES *names;
+ struct http_cert hcert;
+ unsigned int i;
+
+ in = BIO_new_file(fname, "r");
+ if (in == NULL) {
+ wpa_printf(MSG_ERROR, "Could not read '%s'", fname);
+ return;
+ }
+
+ cert = d2i_X509_bio(in, NULL);
+ BIO_free(in);
+
+ if (cert == NULL) {
+ wpa_printf(MSG_ERROR, "Could not parse certificate");
+ return;
+ }
+
+ out = BIO_new_fp(stdout, BIO_NOCLOSE);
+ if (out) {
+ X509_print_ex(out, cert, XN_FLAG_COMPAT,
+ X509_FLAG_COMPAT);
+ BIO_free(out);
+ }
+
+ wpa_printf(MSG_INFO, "Additional parsing information:");
+ parse_cert(ctx, &hcert, cert, &names);
+ for (i = 0; i < hcert.num_othername; i++) {
+ if (os_strcmp(hcert.othername[i].oid,
+ "1.3.6.1.4.1.40808.1.1.1") == 0) {
+ char *name = os_zalloc(hcert.othername[i].len + 1);
+ if (name) {
+ os_memcpy(name, hcert.othername[i].data,
+ hcert.othername[i].len);
+ wpa_printf(MSG_INFO,
+ "id-wfa-hotspot-friendlyName: %s",
+ name);
+ os_free(name);
+ }
+ wpa_hexdump_ascii(MSG_INFO,
+ "id-wfa-hotspot-friendlyName",
+ hcert.othername[i].data,
+ hcert.othername[i].len);
+ } else {
+ wpa_printf(MSG_INFO, "subjAltName[othername]: oid=%s",
+ hcert.othername[i].oid);
+ wpa_hexdump_ascii(MSG_INFO, "unknown othername",
+ hcert.othername[i].data,
+ hcert.othername[i].len);
+ }
+ }
+ parse_cert_free(&hcert, names);
+
+ X509_free(cert);
+}
+
+
+static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+ struct http_ctx *ctx;
+ X509 *cert;
+ int err, depth;
+ char buf[256];
+ X509_NAME *name;
+ const char *err_str;
+ SSL *ssl;
+ SSL_CTX *ssl_ctx;
+
+ ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ ssl_ctx = ssl->ctx;
+ ctx = SSL_CTX_get_app_data(ssl_ctx);
+
+ wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify");
+
+ err = X509_STORE_CTX_get_error(x509_ctx);
+ err_str = X509_verify_cert_error_string(err);
+ depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+ cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+ if (!cert) {
+ wpa_printf(MSG_INFO, "No server certificate available");
+ ctx->last_err = "No server certificate available";
+ return 0;
+ }
+
+ if (depth == 0)
+ ctx->peer_cert = cert;
+ else if (depth == 1)
+ ctx->peer_issuer = cert;
+ else if (depth == 2)
+ ctx->peer_issuer_issuer = cert;
+
+ name = X509_get_subject_name(cert);
+ X509_NAME_oneline(name, buf, sizeof(buf));
+ wpa_printf(MSG_INFO, "Server certificate chain - depth=%d err=%d (%s) subject=%s",
+ depth, err, err_str, buf);
+ debug_dump_cert("Server certificate chain - certificate", cert);
+
+ if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0)
+ return 0;
+
+ if (!preverify_ok)
+ ctx->last_err = "TLS validation failed";
+
+ return preverify_ok;
+}
+
+
+#ifdef HAVE_OCSP
+
+static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
+{
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ OCSP_RESPONSE_print(out, rsp, 0);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (!txt) {
+ BIO_free(out);
+ return;
+ }
+
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_MSGDUMP, "OpenSSL: OCSP Response\n%s", txt);
+ }
+ os_free(txt);
+ BIO_free(out);
+}
+
+
+static void tls_show_errors(const char *func, const char *txt)
+{
+ unsigned long err;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - %s %s",
+ func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: pending error: %s",
+ ERR_error_string(err, NULL));
+ }
+}
+
+
+static int ocsp_resp_cb(SSL *s, void *arg)
+{
+ struct http_ctx *ctx = arg;
+ const unsigned char *p;
+ int len, status, reason;
+ OCSP_RESPONSE *rsp;
+ OCSP_BASICRESP *basic;
+ OCSP_CERTID *id;
+ ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
+ X509_STORE *store;
+ STACK_OF(X509) *certs = NULL;
+
+ len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+ if (!p) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+ if (ctx->ocsp == MANDATORY_OCSP)
+ ctx->last_err = "No OCSP response received";
+ return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
+
+ rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+ if (!rsp) {
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
+ ctx->last_err = "Failed to parse OCSP response";
+ return 0;
+ }
+
+ ocsp_debug_print_resp(rsp);
+
+ status = OCSP_response_status(rsp);
+ if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
+ status, OCSP_response_status_str(status));
+ ctx->last_err = "OCSP responder error";
+ return 0;
+ }
+
+ basic = OCSP_response_get1_basic(rsp);
+ if (!basic) {
+ wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
+ ctx->last_err = "Could not find BasicOCSPResponse";
+ return 0;
+ }
+
+ store = SSL_CTX_get_cert_store(s->ctx);
+ if (ctx->peer_issuer) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer");
+ debug_dump_cert("OpenSSL: Issuer certificate",
+ ctx->peer_issuer);
+
+ if (X509_STORE_add_cert(store, ctx->peer_issuer) != 1) {
+ tls_show_errors(__func__,
+ "OpenSSL: Could not add issuer to certificate store");
+ }
+ certs = sk_X509_new_null();
+ if (certs) {
+ X509 *cert;
+ cert = X509_dup(ctx->peer_issuer);
+ if (cert && !sk_X509_push(certs, cert)) {
+ tls_show_errors(
+ __func__,
+ "OpenSSL: Could not add issuer to OCSP responder trust store");
+ X509_free(cert);
+ sk_X509_free(certs);
+ certs = NULL;
+ }
+ if (certs && ctx->peer_issuer_issuer) {
+ cert = X509_dup(ctx->peer_issuer_issuer);
+ if (cert && !sk_X509_push(certs, cert)) {
+ tls_show_errors(
+ __func__,
+ "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
+ X509_free(cert);
+ }
+ }
+ }
+ }
+
+ status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
+ sk_X509_pop_free(certs, X509_free);
+ if (status <= 0) {
+ tls_show_errors(__func__,
+ "OpenSSL: OCSP response failed verification");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ ctx->last_err = "OCSP response failed verification";
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
+
+ if (!ctx->peer_cert) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ ctx->last_err = "Peer certificate not available for OCSP status check";
+ return 0;
+ }
+
+ if (!ctx->peer_issuer) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ ctx->last_err = "Peer issuer certificate not available for OCSP status check";
+ return 0;
+ }
+
+ 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");
+ 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)) {
+ wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
+ (ctx->ocsp == MANDATORY_OCSP) ? "" :
+ " (OCSP not required)");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ if (ctx->ocsp == MANDATORY_OCSP)
+
+ ctx->last_err = "Could not find current server certificate from OCSP response";
+ return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1;
+ }
+
+ if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
+ tls_show_errors(__func__, "OpenSSL: OCSP status times invalid");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ ctx->last_err = "OCSP status times invalid";
+ return 0;
+ }
+
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
+ OCSP_cert_status_str(status));
+
+ if (status == V_OCSP_CERTSTATUS_GOOD)
+ return 1;
+ if (status == V_OCSP_CERTSTATUS_REVOKED) {
+ ctx->last_err = "Server certificate has been revoked";
+ return 0;
+ }
+ if (ctx->ocsp == MANDATORY_OCSP) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
+ ctx->last_err = "OCSP status unknown";
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
+ return 1;
+}
+
+
+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;
+ int ret;
+
+ ssl->method = real_ssl_method;
+ s->method = real_ssl_method;
+
+ ret = s->method->ssl_new(s);
+ SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp);
+
+ return ret;
+}
+
+#endif /* HAVE_OCSP */
+
+
+static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm)
+{
+ struct http_ctx *ctx = parm;
+ SSL_CTX *ssl = sslctx;
+
+ wpa_printf(MSG_DEBUG, "curl_cb_ssl");
+ SSL_CTX_set_app_data(ssl, ctx);
+ SSL_CTX_set_verify(ssl, SSL_VERIFY_PEER, curl_cb_ssl_verify);
+
+#ifdef HAVE_OCSP
+ if (ctx->ocsp != NO_OCSP) {
+ SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb);
+ SSL_CTX_set_tlsext_status_arg(ssl, ctx);
+
+ /*
+ * Use a temporary SSL_METHOD to get a callback on SSL_new()
+ * from libcurl since there is no proper callback registration
+ * available for this.
+ */
+ os_memset(&patch_ssl_method, 0, sizeof(patch_ssl_method));
+ patch_ssl_method.ssl_new = curl_patch_ssl_new;
+ real_ssl_method = ssl->method;
+ ssl->method = &patch_ssl_method;
+ }
+#endif /* HAVE_OCSP */
+
+ return CURLE_OK;
+}
+
+#endif /* EAP_TLS_OPENSSL */
+
+
+static CURL * setup_curl_post(struct http_ctx *ctx, const char *address,
+ const char *ca_fname, const char *username,
+ const char *password, const char *client_cert,
+ const char *client_key)
+{
+ CURL *curl;
+
+ wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s "
+ "username=%s", address, ca_fname, username);
+
+ curl = curl_easy_init();
+ if (curl == NULL)
+ return NULL;
+
+ curl_easy_setopt(curl, CURLOPT_URL, address);
+ curl_easy_setopt(curl, CURLOPT_POST, 1L);
+ if (ca_fname) {
+ curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
+#ifdef EAP_TLS_OPENSSL
+ curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl);
+ curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx);
+#endif /* EAP_TLS_OPENSSL */
+ } else {
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ }
+ if (client_cert && client_key) {
+ curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert);
+ curl_easy_setopt(curl, CURLOPT_SSLKEY, client_key);
+ }
+ /* TODO: use curl_easy_getinfo() with CURLINFO_CERTINFO to fetch
+ * information about the server certificate */
+ curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L);
+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug);
+ curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_cb_write);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx);
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+ if (username) {
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
+ curl_easy_setopt(curl, CURLOPT_USERNAME, username);
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
+ }
+
+ return curl;
+}
+
+
+static int post_init_client(struct http_ctx *ctx, const char *address,
+ const char *ca_fname, const char *username,
+ const char *password, const char *client_cert,
+ const char *client_key)
+{
+ char *pos;
+ int count;
+
+ clone_str(&ctx->svc_address, address);
+ clone_str(&ctx->svc_ca_fname, ca_fname);
+ clone_str(&ctx->svc_username, username);
+ clone_str(&ctx->svc_password, password);
+ clone_str(&ctx->svc_client_cert, client_cert);
+ clone_str(&ctx->svc_client_key, client_key);
+
+ /*
+ * Workaround for Apache "Hostname 'FOO' provided via SNI and hostname
+ * 'foo' provided via HTTP are different.
+ */
+ for (count = 0, pos = ctx->svc_address; count < 3 && pos && *pos;
+ pos++) {
+ if (*pos == '/')
+ count++;
+ *pos = tolower(*pos);
+ }
+
+ ctx->curl = setup_curl_post(ctx, ctx->svc_address, ca_fname, username,
+ password, client_cert, client_key);
+ if (ctx->curl == NULL)
+ return -1;
+
+ return 0;
+}
+
+
+int soap_init_client(struct http_ctx *ctx, const char *address,
+ const char *ca_fname, const char *username,
+ const char *password, const char *client_cert,
+ const char *client_key)
+{
+ if (post_init_client(ctx, address, ca_fname, username, password,
+ client_cert, client_key) < 0)
+ return -1;
+
+ ctx->curl_hdr = curl_slist_append(ctx->curl_hdr,
+ "Content-Type: application/soap+xml");
+ ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "SOAPAction: ");
+ ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "Expect:");
+ curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->curl_hdr);
+
+ return 0;
+}
+
+
+int soap_reinit_client(struct http_ctx *ctx)
+{
+ char *address = NULL;
+ char *ca_fname = NULL;
+ char *username = NULL;
+ char *password = NULL;
+ char *client_cert = NULL;
+ char *client_key = NULL;
+ int ret;
+
+ clear_curl(ctx);
+
+ clone_str(&address, ctx->svc_address);
+ clone_str(&ca_fname, ctx->svc_ca_fname);
+ clone_str(&username, ctx->svc_username);
+ clone_str(&password, ctx->svc_password);
+ clone_str(&client_cert, ctx->svc_client_cert);
+ clone_str(&client_key, ctx->svc_client_key);
+
+ ret = soap_init_client(ctx, address, ca_fname, username, password,
+ client_cert, client_key);
+ os_free(address);
+ os_free(ca_fname);
+ str_clear_free(username);
+ str_clear_free(password);
+ os_free(client_cert);
+ os_free(client_key);
+ return ret;
+}
+
+
+static void free_curl_buf(struct http_ctx *ctx)
+{
+ os_free(ctx->curl_buf);
+ ctx->curl_buf = NULL;
+ ctx->curl_buf_len = 0;
+}
+
+
+xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node)
+{
+ char *str;
+ xml_node_t *envelope, *ret, *resp, *n;
+ CURLcode res;
+ long http = 0;
+
+ ctx->last_err = NULL;
+
+ wpa_printf(MSG_DEBUG, "SOAP: Sending message");
+ envelope = soap_build_envelope(ctx->xml, node);
+ str = xml_node_to_str(ctx->xml, envelope);
+ xml_node_free(ctx->xml, envelope);
+ wpa_printf(MSG_MSGDUMP, "SOAP[%s]", str);
+
+ curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDS, str);
+ free_curl_buf(ctx);
+
+ res = curl_easy_perform(ctx->curl);
+ if (res != CURLE_OK) {
+ if (!ctx->last_err)
+ ctx->last_err = curl_easy_strerror(res);
+ wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
+ ctx->last_err);
+ os_free(str);
+ free_curl_buf(ctx);
+ return NULL;
+ }
+ os_free(str);
+
+ curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &http);
+ wpa_printf(MSG_DEBUG, "SOAP: Server response code %ld", http);
+ if (http != 200) {
+ ctx->last_err = "HTTP download failed";
+ wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http);
+ free_curl_buf(ctx);
+ return NULL;
+ }
+
+ if (ctx->curl_buf == NULL)
+ return NULL;
+
+ wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ctx->curl_buf);
+ resp = xml_node_from_buf(ctx->xml, ctx->curl_buf);
+ free_curl_buf(ctx);
+ if (resp == NULL) {
+ wpa_printf(MSG_INFO, "Could not parse SOAP response");
+ ctx->last_err = "Could not parse SOAP response";
+ return NULL;
+ }
+
+ ret = soap_get_body(ctx->xml, resp);
+ if (ret == NULL) {
+ wpa_printf(MSG_INFO, "Could not get SOAP body");
+ ctx->last_err = "Could not get SOAP body";
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "SOAP body localname: '%s'",
+ xml_node_get_localname(ctx->xml, ret));
+ n = xml_node_copy(ctx->xml, ret);
+ xml_node_free(ctx->xml, resp);
+
+ return n;
+}
+
+
+struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx)
+{
+ struct http_ctx *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+ ctx->ctx = upper_ctx;
+ ctx->xml = xml_ctx;
+ ctx->ocsp = OPTIONAL_OCSP;
+
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ return ctx;
+}
+
+
+void http_ocsp_set(struct http_ctx *ctx, int val)
+{
+ if (val == 0)
+ ctx->ocsp = NO_OCSP;
+ else if (val == 1)
+ ctx->ocsp = OPTIONAL_OCSP;
+ if (val == 2)
+ ctx->ocsp = MANDATORY_OCSP;
+}
+
+
+void http_deinit_ctx(struct http_ctx *ctx)
+{
+ clear_curl(ctx);
+ os_free(ctx->curl_buf);
+ curl_global_cleanup();
+
+ os_free(ctx->svc_address);
+ os_free(ctx->svc_ca_fname);
+ str_clear_free(ctx->svc_username);
+ str_clear_free(ctx->svc_password);
+ os_free(ctx->svc_client_cert);
+ os_free(ctx->svc_client_key);
+
+ os_free(ctx);
+}
+
+
+int http_download_file(struct http_ctx *ctx, const char *url,
+ const char *fname, const char *ca_fname)
+{
+ CURL *curl;
+ FILE *f;
+ CURLcode res;
+ long http = 0;
+
+ ctx->last_err = NULL;
+
+ wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)",
+ url, fname, ca_fname);
+ curl = curl_easy_init();
+ if (curl == NULL)
+ return -1;
+
+ f = fopen(fname, "wb");
+ if (f == NULL) {
+ curl_easy_cleanup(curl);
+ return -1;
+ }
+
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ if (ca_fname) {
+ curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
+ curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L);
+ } else {
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ }
+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug);
+ curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ res = curl_easy_perform(curl);
+ if (res != CURLE_OK) {
+ if (!ctx->last_err)
+ ctx->last_err = curl_easy_strerror(res);
+ wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
+ ctx->last_err);
+ curl_easy_cleanup(curl);
+ fclose(f);
+ return -1;
+ }
+
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http);
+ wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http);
+ if (http != 200) {
+ ctx->last_err = "HTTP download failed";
+ wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http);
+ curl_easy_cleanup(curl);
+ fclose(f);
+ return -1;
+ }
+
+ curl_easy_cleanup(curl);
+ fclose(f);
+
+ return 0;
+}
+
+
+char * http_post(struct http_ctx *ctx, const char *url, const char *data,
+ const char *content_type, const char *ext_hdr,
+ const char *ca_fname,
+ const char *username, const char *password,
+ const char *client_cert, const char *client_key,
+ size_t *resp_len)
+{
+ long http = 0;
+ CURLcode res;
+ char *ret;
+ CURL *curl;
+ struct curl_slist *curl_hdr = NULL;
+
+ ctx->last_err = NULL;
+ wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url);
+ curl = setup_curl_post(ctx, url, ca_fname, username, password,
+ client_cert, client_key);
+ if (curl == NULL)
+ return NULL;
+
+ if (content_type) {
+ char ct[200];
+ snprintf(ct, sizeof(ct), "Content-Type: %s", content_type);
+ curl_hdr = curl_slist_append(curl_hdr, ct);
+ }
+ if (ext_hdr)
+ curl_hdr = curl_slist_append(curl_hdr, ext_hdr);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_hdr);
+
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+ free_curl_buf(ctx);
+
+ res = curl_easy_perform(curl);
+ if (res != CURLE_OK) {
+ if (!ctx->last_err)
+ ctx->last_err = curl_easy_strerror(res);
+ wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
+ ctx->last_err);
+ free_curl_buf(ctx);
+ return NULL;
+ }
+
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http);
+ wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http);
+ if (http != 200) {
+ ctx->last_err = "HTTP POST failed";
+ wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http);
+ free_curl_buf(ctx);
+ return NULL;
+ }
+
+ if (ctx->curl_buf == NULL)
+ return NULL;
+
+ ret = ctx->curl_buf;
+ if (resp_len)
+ *resp_len = ctx->curl_buf_len;
+ ctx->curl_buf = NULL;
+ ctx->curl_buf_len = 0;
+
+ wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret);
+
+ return ret;
+}
+
+
+void http_set_cert_cb(struct http_ctx *ctx,
+ int (*cb)(void *ctx, struct http_cert *cert),
+ void *cb_ctx)
+{
+ ctx->cert_cb = cb;
+ ctx->cert_cb_ctx = cb_ctx;
+}
+
+
+const char * http_get_err(struct http_ctx *ctx)
+{
+ return ctx->last_err;
+}
diff --git a/contrib/wpa/src/utils/ip_addr.c b/contrib/wpa/src/utils/ip_addr.c
index 3647c76..92a3590 100644
--- a/contrib/wpa/src/utils/ip_addr.c
+++ b/contrib/wpa/src/utils/ip_addr.c
@@ -33,30 +33,6 @@ const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
}
-int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b)
-{
- if (a == NULL && b == NULL)
- return 0;
- if (a == NULL || b == NULL)
- return 1;
-
- switch (a->af) {
- case AF_INET:
- if (a->u.v4.s_addr != b->u.v4.s_addr)
- return 1;
- break;
-#ifdef CONFIG_IPV6
- case AF_INET6:
- if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0)
- return 1;
- break;
-#endif /* CONFIG_IPV6 */
- }
-
- return 0;
-}
-
-
int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
{
#ifndef CONFIG_NATIVE_WINDOWS
diff --git a/contrib/wpa/src/utils/ip_addr.h b/contrib/wpa/src/utils/ip_addr.h
index 79ac20c..0670411 100644
--- a/contrib/wpa/src/utils/ip_addr.h
+++ b/contrib/wpa/src/utils/ip_addr.h
@@ -22,7 +22,6 @@ struct hostapd_ip_addr {
const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
size_t buflen);
-int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
#endif /* IP_ADDR_H */
diff --git a/contrib/wpa/src/utils/list.h b/contrib/wpa/src/utils/list.h
index 6881130..ee2f485 100644
--- a/contrib/wpa/src/utils/list.h
+++ b/contrib/wpa/src/utils/list.h
@@ -17,6 +17,8 @@ struct dl_list {
struct dl_list *prev;
};
+#define DL_LIST_HEAD_INIT(l) { &(l), &(l) }
+
static inline void dl_list_init(struct dl_list *list)
{
list->next = list;
diff --git a/contrib/wpa/src/utils/os.h b/contrib/wpa/src/utils/os.h
index ad20834..77250d6 100644
--- a/contrib/wpa/src/utils/os.h
+++ b/contrib/wpa/src/utils/os.h
@@ -23,6 +23,11 @@ struct os_time {
os_time_t usec;
};
+struct os_reltime {
+ os_time_t sec;
+ os_time_t usec;
+};
+
/**
* os_get_time - Get current time (sec, usec)
* @t: Pointer to buffer for the time
@@ -30,21 +35,84 @@ struct os_time {
*/
int os_get_time(struct os_time *t);
+/**
+ * os_get_reltime - Get relative time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_reltime(struct os_reltime *t);
+
+
+/* Helpers for handling struct os_time */
+
+static inline int os_time_before(struct os_time *a, struct os_time *b)
+{
+ return (a->sec < b->sec) ||
+ (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_time_sub(struct os_time *a, struct os_time *b,
+ struct os_time *res)
+{
+ res->sec = a->sec - b->sec;
+ res->usec = a->usec - b->usec;
+ if (res->usec < 0) {
+ res->sec--;
+ res->usec += 1000000;
+ }
+}
+
+
+/* Helpers for handling struct os_reltime */
+
+static inline int os_reltime_before(struct os_reltime *a,
+ struct os_reltime *b)
+{
+ return (a->sec < b->sec) ||
+ (a->sec == b->sec && a->usec < b->usec);
+}
+
+
+static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b,
+ struct os_reltime *res)
+{
+ res->sec = a->sec - b->sec;
+ res->usec = a->usec - b->usec;
+ if (res->usec < 0) {
+ res->sec--;
+ res->usec += 1000000;
+ }
+}
+
+
+static inline void os_reltime_age(struct os_reltime *start,
+ struct os_reltime *age)
+{
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, start, age);
+}
+
+
+static inline int os_reltime_expired(struct os_reltime *now,
+ struct os_reltime *ts,
+ os_time_t timeout_secs)
+{
+ struct os_reltime age;
+
+ os_reltime_sub(now, ts, &age);
+ return (age.sec > timeout_secs) ||
+ (age.sec == timeout_secs && age.usec > 0);
+}
-/* Helper macros for handling struct os_time */
-#define os_time_before(a, b) \
- ((a)->sec < (b)->sec || \
- ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+static inline int os_reltime_initialized(struct os_reltime *t)
+{
+ return t->sec != 0 || t->usec != 0;
+}
-#define os_time_sub(a, b, res) do { \
- (res)->sec = (a)->sec - (b)->sec; \
- (res)->usec = (a)->usec - (b)->usec; \
- if ((res)->usec < 0) { \
- (res)->sec--; \
- (res)->usec += 1000000; \
- } \
-} while (0)
/**
* os_mktime - Convert broken-down time into seconds since 1970-01-01
@@ -172,6 +240,13 @@ int os_unsetenv(const char *name);
char * os_readfile(const char *name, size_t *len);
/**
+ * os_file_exists - Check whether the specified file exists
+ * @fname: Path and name of the file
+ * Returns: 1 if the file exists or 0 if not
+ */
+int os_file_exists(const char *fname);
+
+/**
* os_zalloc - Allocate and zero memory
* @size: Number of bytes to allocate
* Returns: Pointer to allocated and zeroed memory or %NULL on failure
@@ -361,15 +436,6 @@ int os_strcmp(const char *s1, const char *s2);
int os_strncmp(const char *s1, const char *s2, size_t n);
/**
- * os_strncpy - Copy a string
- * @dest: Destination
- * @src: Source
- * @n: Maximum number of characters to copy
- * Returns: dest
- */
-char * os_strncpy(char *dest, const char *src, size_t n);
-
-/**
* os_strstr - Locate a substring
* @haystack: String (haystack) to search from
* @needle: Needle to search from haystack
@@ -465,9 +531,6 @@ char * os_strdup(const char *s);
#ifndef os_strncmp
#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
#endif
-#ifndef os_strncpy
-#define os_strncpy(d, s, n) strncpy((d), (s), (n))
-#endif
#ifndef os_strrchr
#define os_strrchr(s, c) strrchr((s), (c))
#endif
@@ -486,6 +549,12 @@ char * os_strdup(const char *s);
#endif /* OS_NO_C_LIB_DEFINES */
+static inline int os_snprintf_error(size_t size, int res)
+{
+ return res < 0 || (unsigned int) res >= size;
+}
+
+
static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
{
if (size && nmemb > (~(size_t) 0) / size)
@@ -493,6 +562,21 @@ static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
return os_realloc(ptr, nmemb * size);
}
+/**
+ * os_remove_in_array - Remove a member from an array by index
+ * @ptr: Pointer to the array
+ * @nmemb: Current member count of the array
+ * @size: The size per member of the array
+ * @idx: Index of the member to be removed
+ */
+static inline void os_remove_in_array(void *ptr, size_t nmemb, size_t size,
+ size_t idx)
+{
+ if (idx < nmemb - 1)
+ os_memmove(((unsigned char *) ptr) + idx * size,
+ ((unsigned char *) ptr) + (idx + 1) * size,
+ (nmemb - idx - 1) * size);
+}
/**
* os_strlcpy - Copy a string with size bound and NUL-termination
@@ -506,6 +590,32 @@ static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
*/
size_t os_strlcpy(char *dest, const char *src, size_t siz);
+/**
+ * os_memcmp_const - Constant time memory comparison
+ * @a: First buffer to compare
+ * @b: Second buffer to compare
+ * @len: Number of octets to compare
+ * Returns: 0 if buffers are equal, non-zero if not
+ *
+ * This function is meant for comparing passwords or hash values where
+ * difference in execution time could provide external observer information
+ * about the location of the difference in the memory buffers. The return value
+ * does not behave like os_memcmp(), i.e., os_memcmp_const() cannot be used to
+ * sort items into a defined order. Unlike os_memcmp(), execution time of
+ * os_memcmp_const() does not depend on the contents of the compared memory
+ * buffers, but only on the total compared length.
+ */
+int os_memcmp_const(const void *a, const void *b, size_t len);
+
+/**
+ * os_exec - Execute an external program
+ * @program: Path to the program
+ * @arg: Command line argument string
+ * @wait_completion: Whether to wait until the program execution completes
+ * Returns: 0 on success, -1 on error
+ */
+int os_exec(const char *program, const char *arg, int wait_completion);
+
#ifdef OS_REJECT_C_LIB_FUNCTIONS
#define malloc OS_DO_NOT_USE_malloc
diff --git a/contrib/wpa/src/utils/os_internal.c b/contrib/wpa/src/utils/os_internal.c
index e4b7fdb..77733ad 100644
--- a/contrib/wpa/src/utils/os_internal.c
+++ b/contrib/wpa/src/utils/os_internal.c
@@ -17,9 +17,11 @@
*/
#include "includes.h"
+#include <time.h>
+#include <sys/wait.h>
#undef OS_REJECT_C_LIB_FUNCTIONS
-#include "os.h"
+#include "common.h"
void os_sleep(os_time_t sec, os_time_t usec)
{
@@ -41,6 +43,17 @@ int os_get_time(struct os_time *t)
}
+int os_get_reltime(struct os_reltime *t)
+{
+ int res;
+ struct timeval tv;
+ res = gettimeofday(&tv, NULL);
+ t->sec = tv.tv_sec;
+ t->usec = tv.tv_usec;
+ return res;
+}
+
+
int os_mktime(int year, int month, int day, int hour, int min, int sec,
os_time_t *t)
{
@@ -85,7 +98,7 @@ int os_gmtime(os_time_t t, struct os_tm *tm)
int os_daemonize(const char *pid_file)
{
if (daemon(0, 0)) {
- perror("daemon");
+ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
return -1;
}
@@ -156,8 +169,8 @@ char * os_rel2abs_path(const char *rel_path)
}
}
- cwd_len = strlen(cwd);
- rel_len = strlen(rel_path);
+ cwd_len = os_strlen(cwd);
+ rel_len = os_strlen(rel_path);
ret_len = cwd_len + 1 + rel_len + 1;
ret = os_malloc(ret_len);
if (ret) {
@@ -452,6 +465,20 @@ 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)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res;
+
+ for (res = 0, i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return res;
+}
+
+
char * os_strstr(const char *haystack, const char *needle)
{
size_t len = os_strlen(needle);
@@ -481,3 +508,57 @@ int os_snprintf(char *str, size_t size, const char *format, ...)
str[size - 1] = '\0';
return ret;
}
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ pid_t pid;
+ int pid_status;
+
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ const int MAX_ARG = 30;
+ char *_program, *_arg, *pos;
+ char *argv[MAX_ARG + 1];
+ int i;
+
+ _program = os_strdup(program);
+ _arg = os_strdup(arg);
+
+ argv[0] = _program;
+
+ i = 1;
+ pos = _arg;
+ while (i < MAX_ARG && pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[i++] = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ *pos++ = '\0';
+ }
+ argv[i] = NULL;
+
+ execv(program, argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ os_free(_program);
+ os_free(_arg);
+ exit(0);
+ return -1;
+ }
+
+ if (wait_completion) {
+ /* wait for the child process to complete in the parent */
+ waitpid(pid, &pid_status, 0);
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/utils/os_none.c b/contrib/wpa/src/utils/os_none.c
index cabf73b..83fe025 100644
--- a/contrib/wpa/src/utils/os_none.c
+++ b/contrib/wpa/src/utils/os_none.c
@@ -26,6 +26,12 @@ int os_get_time(struct os_time *t)
}
+int os_get_reltime(struct os_reltime *t)
+{
+ return -1;
+}
+
+
int os_mktime(int year, int month, int day, int hour, int min, int sec,
os_time_t *t)
{
@@ -212,6 +218,11 @@ size_t os_strlcpy(char *dest, const char *src, size_t size)
}
+int os_memcmp_const(const void *a, const void *b, size_t len)
+{
+ return 0;
+}
+
char * os_strstr(const char *haystack, const char *needle)
{
return NULL;
@@ -223,3 +234,9 @@ int os_snprintf(char *str, size_t size, const char *format, ...)
return 0;
}
#endif /* OS_NO_C_LIB_DEFINES */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/utils/os_unix.c b/contrib/wpa/src/utils/os_unix.c
index fea511b..34cb87a 100644
--- a/contrib/wpa/src/utils/os_unix.c
+++ b/contrib/wpa/src/utils/os_unix.c
@@ -9,23 +9,24 @@
#include "includes.h"
#include <time.h>
+#include <sys/wait.h>
#ifdef ANDROID
-#include <linux/capability.h>
-#include <linux/prctl.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <private/android_filesystem_config.h>
#endif /* ANDROID */
#include "os.h"
+#include "common.h"
#ifdef WPA_TRACE
-#include "common.h"
#include "wpa_debug.h"
#include "trace.h"
#include "list.h"
-static struct dl_list alloc_list;
+static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
#define ALLOC_MAGIC 0xa84ef1b2
#define FREED_MAGIC 0x67fd487a
@@ -60,6 +61,43 @@ int os_get_time(struct os_time *t)
}
+int os_get_reltime(struct os_reltime *t)
+{
+#if defined(CLOCK_BOOTTIME)
+ static clockid_t clock_id = CLOCK_BOOTTIME;
+#elif defined(CLOCK_MONOTONIC)
+ static clockid_t clock_id = CLOCK_MONOTONIC;
+#else
+ static clockid_t clock_id = CLOCK_REALTIME;
+#endif
+ struct timespec ts;
+ int res;
+
+ while (1) {
+ res = clock_gettime(clock_id, &ts);
+ if (res == 0) {
+ t->sec = ts.tv_sec;
+ t->usec = ts.tv_nsec / 1000;
+ return 0;
+ }
+ switch (clock_id) {
+#ifdef CLOCK_BOOTTIME
+ case CLOCK_BOOTTIME:
+ clock_id = CLOCK_MONOTONIC;
+ break;
+#endif
+#ifdef CLOCK_MONOTONIC
+ case CLOCK_MONOTONIC:
+ clock_id = CLOCK_REALTIME;
+ break;
+#endif
+ case CLOCK_REALTIME:
+ return -1;
+ }
+ }
+}
+
+
int os_mktime(int year, int month, int day, int hour, int min, int sec,
os_time_t *t)
{
@@ -240,6 +278,9 @@ char * os_rel2abs_path(const char *rel_path)
size_t len = 128, cwd_len, rel_len, ret_len;
int last_errno;
+ if (!rel_path)
+ return NULL;
+
if (rel_path[0] == '/')
return os_strdup(rel_path);
@@ -284,11 +325,15 @@ int os_program_init(void)
* We ignore errors here since errors are normal if we
* are already running as non-root.
*/
+#ifdef ANDROID_SETGROUPS_OVERRIDE
+ gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
+#else /* ANDROID_SETGROUPS_OVERRIDE */
gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+#endif /* ANDROID_SETGROUPS_OVERRIDE */
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
- setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+ setgroups(ARRAY_SIZE(groups), groups);
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
@@ -303,9 +348,6 @@ int os_program_init(void)
capset(&header, &cap);
#endif /* ANDROID */
-#ifdef WPA_TRACE
- dl_list_init(&alloc_list);
-#endif /* WPA_TRACE */
return 0;
}
@@ -390,6 +432,16 @@ 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;
+}
+
+
#ifndef WPA_TRACE
void * os_zalloc(size_t size)
{
@@ -423,11 +475,121 @@ 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)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res;
+
+ for (res = 0, i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return res;
+}
+
+
#ifdef WPA_TRACE
+#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
+char wpa_trace_fail_func[256] = { 0 };
+unsigned int wpa_trace_fail_after;
+
+static int testing_fail_alloc(void)
+{
+ const char *func[WPA_TRACE_LEN];
+ size_t i, res, len;
+ char *pos, *next;
+ int match;
+
+ if (!wpa_trace_fail_after)
+ return 0;
+
+ res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
+ i = 0;
+ if (i < res && os_strcmp(func[i], __func__) == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_malloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_calloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_realloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_strdup") == 0)
+ i++;
+
+ pos = wpa_trace_fail_func;
+
+ match = 0;
+ while (i < res) {
+ int allow_skip = 1;
+ int maybe = 0;
+
+ if (*pos == '=') {
+ allow_skip = 0;
+ pos++;
+ } else if (*pos == '?') {
+ maybe = 1;
+ pos++;
+ }
+ next = os_strchr(pos, ';');
+ if (next)
+ len = next - pos;
+ else
+ len = os_strlen(pos);
+ if (os_memcmp(pos, func[i], len) != 0) {
+ if (maybe && next) {
+ pos = next + 1;
+ continue;
+ }
+ if (allow_skip) {
+ i++;
+ continue;
+ }
+ return 0;
+ }
+ if (!next) {
+ match = 1;
+ break;
+ }
+ pos = next + 1;
+ i++;
+ }
+ if (!match)
+ return 0;
+
+ wpa_trace_fail_after--;
+ if (wpa_trace_fail_after == 0) {
+ wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
+ wpa_trace_fail_func);
+ for (i = 0; i < res; i++)
+ wpa_printf(MSG_INFO, "backtrace[%d] = %s",
+ (int) i, func[i]);
+ return 1;
+ }
+
+ return 0;
+}
+
+#else
+
+static inline int testing_fail_alloc(void)
+{
+ return 0;
+}
+#endif
+
void * os_malloc(size_t size)
{
struct os_alloc_trace *a;
+
+ if (testing_fail_alloc())
+ return NULL;
+
a = malloc(sizeof(*a) + size);
if (a == NULL)
return NULL;
@@ -513,3 +675,57 @@ char * os_strdup(const char *s)
}
#endif /* WPA_TRACE */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ pid_t pid;
+ int pid_status;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ const int MAX_ARG = 30;
+ char *_program, *_arg, *pos;
+ char *argv[MAX_ARG + 1];
+ int i;
+
+ _program = os_strdup(program);
+ _arg = os_strdup(arg);
+
+ argv[0] = _program;
+
+ i = 1;
+ pos = _arg;
+ while (i < MAX_ARG && pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[i++] = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ *pos++ = '\0';
+ }
+ argv[i] = NULL;
+
+ execv(program, argv);
+ perror("execv");
+ os_free(_program);
+ os_free(_arg);
+ exit(0);
+ return -1;
+ }
+
+ if (wait_completion) {
+ /* wait for the child process to complete in the parent */
+ waitpid(pid, &pid_status, 0);
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/utils/os_win32.c b/contrib/wpa/src/utils/os_win32.c
index 163cebe..296ea13 100644
--- a/contrib/wpa/src/utils/os_win32.c
+++ b/contrib/wpa/src/utils/os_win32.c
@@ -12,6 +12,7 @@
#include <wincrypt.h>
#include "os.h"
+#include "common.h"
void os_sleep(os_time_t sec, os_time_t usec)
{
@@ -47,6 +48,17 @@ int os_get_time(struct os_time *t)
}
+int os_get_reltime(struct os_reltime *t)
+{
+ /* consider using performance counters or so instead */
+ struct os_time now;
+ int res = os_get_time(&now);
+ t->sec = now.sec;
+ t->usec = now.usec;
+ return res;
+}
+
+
int os_mktime(int year, int month, int day, int hour, int min, int sec,
os_time_t *t)
{
@@ -233,3 +245,23 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz)
return s - src - 1;
}
+
+
+int os_memcmp_const(const void *a, const void *b, size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res;
+
+ for (res = 0, i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return res;
+}
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ return -1;
+}
diff --git a/contrib/wpa/src/utils/pcsc_funcs.c b/contrib/wpa/src/utils/pcsc_funcs.c
index 08510d0..6f5ea93 100644
--- a/contrib/wpa/src/utils/pcsc_funcs.c
+++ b/contrib/wpa/src/utils/pcsc_funcs.c
@@ -281,77 +281,82 @@ static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
pos, end - pos);
- while (pos + 1 < end) {
+ while (end - pos >= 2) {
+ unsigned char type, len;
+
+ type = pos[0];
+ len = pos[1];
wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d",
- pos[0], pos[1]);
- if (pos + 2 + pos[1] > end)
+ type, len);
+ pos += 2;
+
+ if (len > (unsigned int) (end - pos))
break;
- switch (pos[0]) {
+ switch (type) {
case USIM_TLV_FILE_DESC:
wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_FILE_ID:
wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_DF_NAME:
wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_PROPR_INFO:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary "
- "information TLV", pos + 2, pos[1]);
+ "information TLV", pos, len);
break;
case USIM_TLV_LIFE_CYCLE_STATUS:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status "
- "Integer TLV", pos + 2, pos[1]);
+ "Integer TLV", pos, len);
break;
case USIM_TLV_FILE_SIZE:
wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV",
- pos + 2, pos[1]);
- if ((pos[1] == 1 || pos[1] == 2) && file_len) {
- if (pos[1] == 1)
- *file_len = (int) pos[2];
+ pos, len);
+ if ((len == 1 || len == 2) && file_len) {
+ if (len == 1)
+ *file_len = (int) pos[0];
else
- *file_len = ((int) pos[2] << 8) |
- (int) pos[3];
+ *file_len = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
*file_len);
}
break;
case USIM_TLV_TOTAL_FILE_SIZE:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_PIN_STATUS_TEMPLATE:
wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template "
- "DO TLV", pos + 2, pos[1]);
- if (pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
- pos[3] >= 1 && ps_do) {
+ "DO TLV", pos, len);
+ if (len >= 2 && pos[0] == USIM_PS_DO_TAG &&
+ pos[1] >= 1 && ps_do) {
wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
- pos[4]);
- *ps_do = (int) pos[4];
+ pos[2]);
+ *ps_do = (int) pos[2];
}
break;
case USIM_TLV_SHORT_FILE_ID:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File "
- "Identifier (SFI) TLV", pos + 2, pos[1]);
+ "Identifier (SFI) TLV", pos, len);
break;
case USIM_TLV_SECURITY_ATTR_8B:
case USIM_TLV_SECURITY_ATTR_8C:
case USIM_TLV_SECURITY_ATTR_AB:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute "
- "TLV", pos + 2, pos[1]);
+ "TLV", pos, len);
break;
default:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV",
- pos, 2 + pos[1]);
+ pos, len);
break;
}
- pos += 2 + pos[1];
+ pos += len;
if (pos == end)
return 0;
@@ -397,10 +402,12 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
unsigned char rid[5];
unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
} *efdir;
- unsigned char buf[127];
+ unsigned char buf[127], *aid_pos;
size_t blen;
+ unsigned int aid_len = 0;
efdir = (struct efdir *) buf;
+ aid_pos = &buf[4];
blen = sizeof(buf);
if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
@@ -449,14 +456,15 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
continue;
}
- if (efdir->aid_len < 1 || efdir->aid_len > 16) {
- wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
- efdir->aid_len);
+ aid_len = efdir->aid_len;
+ if (aid_len < 1 || aid_len > 16) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %u",
+ aid_len);
continue;
}
wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
- efdir->rid, efdir->aid_len);
+ aid_pos, aid_len);
if (efdir->appl_code[0] == 0x10 &&
efdir->appl_code[1] == 0x02) {
@@ -472,30 +480,28 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
return -1;
}
- if (efdir->aid_len > maxlen) {
+ if (aid_len > maxlen) {
wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
return -1;
}
- os_memcpy(aid, efdir->rid, efdir->aid_len);
+ os_memcpy(aid, aid_pos, aid_len);
- return efdir->aid_len;
+ return aid_len;
}
/**
* scard_init - Initialize SIM/USIM connection using PC/SC
- * @sim_type: Allowed SIM types (SIM, USIM, or both)
* @reader: Reader name prefix to search for
* Returns: Pointer to private data structure, or %NULL on failure
*
* This function is used to initialize SIM/USIM connection. PC/SC is used to
- * open connection to the SIM/USIM card and the card is verified to support the
- * selected sim_type. In addition, local flag is set if a PIN is needed to
- * access some of the card functions. Once the connection is not needed
- * anymore, scard_deinit() can be used to close it.
+ * open connection to the SIM/USIM card. In addition, local flag is set if a
+ * PIN is needed to access some of the card functions. Once the connection is
+ * not needed anymore, scard_deinit() can be used to close it.
*/
-struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
+struct scard_data * scard_init(const char *reader)
{
long ret;
unsigned long len, pos;
@@ -612,20 +618,14 @@ struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
blen = sizeof(buf);
- scard->sim_type = SCARD_GSM_SIM;
- if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
- wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
- if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
- SCARD_USIM, NULL, 0)) {
- wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
- if (sim_type == SCARD_USIM_ONLY)
- goto failed;
- wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
- scard->sim_type = SCARD_GSM_SIM;
- } else {
- wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
- scard->sim_type = SCARD_USIM;
- }
+ wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
+ if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
+ SCARD_USIM, NULL, 0)) {
+ wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported. Trying to use GSM SIM");
+ scard->sim_type = SCARD_GSM_SIM;
+ } else {
+ wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
+ scard->sim_type = SCARD_USIM;
}
if (scard->sim_type == SCARD_GSM_SIM) {
@@ -1104,7 +1104,7 @@ int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
}
if (scard->sim_type == SCARD_GSM_SIM) {
- blen = (buf[2] << 8) | buf[3];
+ blen = WPA_GET_BE16(&buf[2]);
} else {
int file_size;
if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
@@ -1178,7 +1178,7 @@ int scard_get_mnc_len(struct scard_data *scard)
}
if (scard->sim_type == SCARD_GSM_SIM) {
- file_size = (buf[2] << 8) | buf[3];
+ file_size = WPA_GET_BE16(&buf[2]);
} else {
if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
return -3;
@@ -1245,6 +1245,7 @@ int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
cmd[4] = 17;
cmd[5] = 16;
os_memcpy(cmd + 6, _rand, 16);
+ get_resp[0] = USIM_CLA;
}
len = sizeof(resp);
ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
@@ -1413,6 +1414,12 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
pos += IK_LEN;
wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
+ if (end > pos) {
+ wpa_hexdump(MSG_DEBUG,
+ "SCARD: Ignore extra data in end",
+ pos, end - pos);
+ }
+
return 0;
}
diff --git a/contrib/wpa/src/utils/pcsc_funcs.h b/contrib/wpa/src/utils/pcsc_funcs.h
index b4ebc99..eacd2a2 100644
--- a/contrib/wpa/src/utils/pcsc_funcs.h
+++ b/contrib/wpa/src/utils/pcsc_funcs.h
@@ -9,15 +9,8 @@
#ifndef PCSC_FUNCS_H
#define PCSC_FUNCS_H
-typedef enum {
- SCARD_GSM_SIM_ONLY,
- SCARD_USIM_ONLY,
- SCARD_TRY_BOTH
-} scard_sim_type;
-
-
#ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type, const char *reader);
+struct scard_data * scard_init(const char *reader);
void scard_deinit(struct scard_data *scard);
int scard_set_pin(struct scard_data *scard, const char *pin);
@@ -34,7 +27,7 @@ int scard_supports_umts(struct scard_data *scard);
#else /* PCSC_FUNCS */
-#define scard_init(s, r) NULL
+#define scard_init(r) NULL
#define scard_deinit(s) do { } while (0)
#define scard_set_pin(s, p) -1
#define scard_get_imsi(s, i, l) -1
diff --git a/contrib/wpa/src/utils/platform.h b/contrib/wpa/src/utils/platform.h
new file mode 100644
index 0000000..46cfe78
--- /dev/null
+++ b/contrib/wpa/src/utils/platform.h
@@ -0,0 +1,21 @@
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+#include "includes.h"
+#include "common.h"
+
+#define le16_to_cpu le_to_host16
+#define le32_to_cpu le_to_host32
+
+#define get_unaligned(p) \
+({ \
+ struct packed_dummy_struct { \
+ typeof(*(p)) __val; \
+ } __attribute__((packed)) *__ptr = (void *) (p); \
+ \
+ __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)))
+
+#endif /* PLATFORM_H */
diff --git a/contrib/wpa/src/utils/radiotap.c b/contrib/wpa/src/utils/radiotap.c
index 804473f..f8f815a 100644
--- a/contrib/wpa/src/utils/radiotap.c
+++ b/contrib/wpa/src/utils/radiotap.c
@@ -2,6 +2,7 @@
* Radiotap parser
*
* Copyright 2007 Andy Green <andy@warmcat.com>
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,34 +11,44 @@
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
- * See README and COPYING for more details.
- *
- *
- * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
- * I only modified some things on top to ease syncing should bugs be found.
+ * See COPYING for more details.
*/
-
-#include "includes.h"
-
-#include "common.h"
#include "radiotap_iter.h"
-
-#define le16_to_cpu le_to_host16
-#define le32_to_cpu le_to_host32
-#define __le32 uint32_t
-#define ulong unsigned long
-#define unlikely(cond) (cond)
-#define get_unaligned(p) \
-({ \
- struct packed_dummy_struct { \
- typeof(*(p)) __val; \
- } __attribute__((packed)) *__ptr = (void *) (p); \
- \
- __ptr->__val; \
-})
+#include "platform.h"
/* function prototypes and related defs are in radiotap_iter.h */
+static const struct radiotap_align_size rtap_namespace_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
+ [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
+ [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
+ [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
+ /*
+ * add more here as they are defined in radiotap.h
+ */
+};
+
+static const struct ieee80211_radiotap_namespace radiotap_ns = {
+ .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]),
+ .align_size = rtap_namespace_sizes,
+};
+
/**
* ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
* @iterator: radiotap_iterator to initialize
@@ -73,38 +84,53 @@
* get_unaligned((type *)iterator.this_arg) to dereference
* iterator.this_arg for type "type" safely on all arches.
*
- * Example code:
- * See Documentation/networking/radiotap-headers.txt
+ * Example code: parse.c
*/
int ieee80211_radiotap_iterator_init(
- struct ieee80211_radiotap_iterator *iterator,
- struct ieee80211_radiotap_header *radiotap_header,
- int max_length)
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
{
+ /* must at least have the radiotap header */
+ if (max_length < (int)sizeof(struct ieee80211_radiotap_header))
+ return -EINVAL;
+
/* Linux only supports version 0 radiotap format */
if (radiotap_header->it_version)
return -EINVAL;
/* sanity check for allowed length and radiotap length field */
- if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ if (max_length < get_unaligned_le16(&radiotap_header->it_len))
return -EINVAL;
- iterator->rtheader = radiotap_header;
- iterator->max_length = le16_to_cpu(get_unaligned(
- &radiotap_header->it_len));
- iterator->arg_index = 0;
- iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
- &radiotap_header->it_present));
- iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
- iterator->this_arg = NULL;
+ iterator->_rtheader = radiotap_header;
+ iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
+ iterator->_arg_index = 0;
+ iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
+ iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
+ iterator->_next_ns_data = NULL;
+ iterator->_reset_on_ext = 0;
+ iterator->_next_bitmap = &radiotap_header->it_present;
+ iterator->_next_bitmap++;
+ iterator->_vns = vns;
+ iterator->current_namespace = &radiotap_ns;
+ iterator->is_radiotap_ns = 1;
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+ iterator->n_overrides = 0;
+ iterator->overrides = NULL;
+#endif
/* find payload start allowing for extended bitmap(s) */
- if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
- while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
- (1<<IEEE80211_RADIOTAP_EXT)) {
- iterator->arg += sizeof(u32);
+ if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
+ if ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
+ (unsigned long)iterator->_max_length)
+ return -EINVAL;
+ while (get_unaligned_le32(iterator->_arg) &
+ (1 << IEEE80211_RADIOTAP_EXT)) {
+ iterator->_arg += sizeof(uint32_t);
/*
* check for insanity where the present bitmaps
@@ -112,12 +138,14 @@ int ieee80211_radiotap_iterator_init(
* stated radiotap header length
*/
- if (((ulong)iterator->arg - (ulong)iterator->rtheader)
- > (ulong)iterator->max_length)
+ if ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader +
+ sizeof(uint32_t) >
+ (unsigned long)iterator->_max_length)
return -EINVAL;
}
- iterator->arg += sizeof(u32);
+ iterator->_arg += sizeof(uint32_t);
/*
* no need to check again for blowing past stated radiotap
@@ -126,11 +154,59 @@ int ieee80211_radiotap_iterator_init(
*/
}
+ iterator->this_arg = iterator->_arg;
+ iterator->this_arg_index = 0;
+ iterator->this_arg_size = 0;
+
/* we are all initialized happily */
return 0;
}
+static void find_ns(struct ieee80211_radiotap_iterator *iterator,
+ uint32_t oui, uint8_t subns)
+{
+ int i;
+
+ iterator->current_namespace = NULL;
+
+ if (!iterator->_vns)
+ return;
+
+ for (i = 0; i < iterator->_vns->n_ns; i++) {
+ if (iterator->_vns->ns[i].oui != oui)
+ continue;
+ if (iterator->_vns->ns[i].subns != subns)
+ continue;
+
+ iterator->current_namespace = &iterator->_vns->ns[i];
+ break;
+ }
+}
+
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+static int find_override(struct ieee80211_radiotap_iterator *iterator,
+ int *align, int *size)
+{
+ int i;
+
+ if (!iterator->overrides)
+ return 0;
+
+ for (i = 0; i < iterator->n_overrides; i++) {
+ if (iterator->_arg_index == iterator->overrides[i].field) {
+ *align = iterator->overrides[i].align;
+ *size = iterator->overrides[i].size;
+ if (!*align) /* erroneous override */
+ return 0;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
/**
* ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
@@ -156,99 +232,106 @@ int ieee80211_radiotap_iterator_init(
*/
int ieee80211_radiotap_iterator_next(
- struct ieee80211_radiotap_iterator *iterator)
+ struct ieee80211_radiotap_iterator *iterator)
{
-
- /*
- * small length lookup table for all radiotap types we heard of
- * starting from b0 in the bitmap, so we can walk the payload
- * area of the radiotap header
- *
- * There is a requirement to pad args, so that args
- * of a given length must begin at a boundary of that length
- * -- but note that compound args are allowed (eg, 2 x u16
- * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
- * a reliable indicator of alignment requirement.
- *
- * upper nybble: content alignment for arg
- * lower nybble: content length for arg
- */
-
- static const u8 rt_sizes[] = {
- [IEEE80211_RADIOTAP_TSFT] = 0x88,
- [IEEE80211_RADIOTAP_FLAGS] = 0x11,
- [IEEE80211_RADIOTAP_RATE] = 0x11,
- [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
- [IEEE80211_RADIOTAP_FHSS] = 0x22,
- [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
- [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
- [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
- [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
- [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
- [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
- [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
- [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
- [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
- [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
- [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
- [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
- [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
- /*
- * add more here as they are defined in
- * include/net/ieee80211_radiotap.h
- */
- };
-
- /*
- * for every radiotap entry we can at
- * least skip (by knowing the length)...
- */
-
- while (iterator->arg_index < (int) sizeof(rt_sizes)) {
+ while (1) {
int hit = 0;
- int pad;
+ int pad, align, size, subns;
+ uint32_t oui;
+
+ /* if no more EXT bits, that's it */
+ if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
+ !(iterator->_bitmap_shifter & 1))
+ return -ENOENT;
- if (!(iterator->bitmap_shifter & 1))
+ if (!(iterator->_bitmap_shifter & 1))
goto next_entry; /* arg not present */
+ /* get alignment/size of data */
+ switch (iterator->_arg_index % 32) {
+ case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
+ case IEEE80211_RADIOTAP_EXT:
+ align = 1;
+ size = 0;
+ break;
+ case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
+ align = 2;
+ size = 6;
+ break;
+ default:
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+ if (find_override(iterator, &align, &size)) {
+ /* all set */
+ } else
+#endif
+ if (!iterator->current_namespace ||
+ iterator->_arg_index >= iterator->current_namespace->n_bits) {
+ if (iterator->current_namespace == &radiotap_ns)
+ return -ENOENT;
+ align = 0;
+ } else {
+ align = iterator->current_namespace->align_size[iterator->_arg_index].align;
+ size = iterator->current_namespace->align_size[iterator->_arg_index].size;
+ }
+ if (!align) {
+ /* skip all subsequent data */
+ iterator->_arg = iterator->_next_ns_data;
+ /* give up on this namespace */
+ iterator->current_namespace = NULL;
+ goto next_entry;
+ }
+ break;
+ }
+
/*
* arg is present, account for alignment padding
- * 8-bit args can be at any alignment
- * 16-bit args must start on 16-bit boundary
- * 32-bit args must start on 32-bit boundary
- * 64-bit args must start on 64-bit boundary
- *
- * note that total arg size can differ from alignment of
- * elements inside arg, so we use upper nybble of length
- * table to base alignment on
*
- * also note: these alignments are ** relative to the
- * start of the radiotap header **. There is no guarantee
+ * Note that these alignments are relative to the start
+ * of the radiotap header. There is no guarantee
* that the radiotap header itself is aligned on any
* kind of boundary.
*
- * the above is why get_unaligned() is used to dereference
- * multibyte elements from the radiotap area
+ * The above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area.
*/
- pad = (((ulong)iterator->arg) -
- ((ulong)iterator->rtheader)) &
- ((rt_sizes[iterator->arg_index] >> 4) - 1);
+ pad = ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader) & (align - 1);
if (pad)
- iterator->arg +=
- (rt_sizes[iterator->arg_index] >> 4) - pad;
+ iterator->_arg += align - pad;
+
+ if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
+ int vnslen;
+
+ if ((unsigned long)iterator->_arg + size -
+ (unsigned long)iterator->_rtheader >
+ (unsigned long)iterator->_max_length)
+ return -EINVAL;
+
+ oui = (*iterator->_arg << 16) |
+ (*(iterator->_arg + 1) << 8) |
+ *(iterator->_arg + 2);
+ subns = *(iterator->_arg + 3);
+
+ find_ns(iterator, oui, subns);
+
+ vnslen = get_unaligned_le16(iterator->_arg + 4);
+ iterator->_next_ns_data = iterator->_arg + size + vnslen;
+ if (!iterator->current_namespace)
+ size += vnslen;
+ }
/*
* this is what we will return to user, but we need to
* move on first so next call has something fresh to test
*/
- iterator->this_arg_index = iterator->arg_index;
- iterator->this_arg = iterator->arg;
- hit = 1;
+ iterator->this_arg_index = iterator->_arg_index;
+ iterator->this_arg = iterator->_arg;
+ iterator->this_arg_size = size;
/* internally move on the size of this arg */
- iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+ iterator->_arg += size;
/*
* check for insanity where we are given a bitmap that
@@ -257,31 +340,57 @@ int ieee80211_radiotap_iterator_next(
* max_length on the last arg, never exceeding it.
*/
- if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
- (ulong) iterator->max_length)
+ if ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader >
+ (unsigned long)iterator->_max_length)
return -EINVAL;
- next_entry:
- iterator->arg_index++;
- if (unlikely((iterator->arg_index & 31) == 0)) {
- /* completed current u32 bitmap */
- if (iterator->bitmap_shifter & 1) {
- /* b31 was set, there is more */
- /* move to next u32 bitmap */
- iterator->bitmap_shifter = le32_to_cpu(
- get_unaligned(iterator->next_bitmap));
- iterator->next_bitmap++;
- } else
- /* no more bitmaps: end */
- iterator->arg_index = sizeof(rt_sizes);
- } else /* just try the next bit */
- iterator->bitmap_shifter >>= 1;
+ /* these special ones are valid in each bitmap word */
+ switch (iterator->_arg_index % 32) {
+ case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
+ iterator->_reset_on_ext = 1;
+
+ iterator->is_radiotap_ns = 0;
+ /*
+ * If parser didn't register this vendor
+ * namespace with us, allow it to show it
+ * as 'raw. Do do that, set argument index
+ * to vendor namespace.
+ */
+ iterator->this_arg_index =
+ IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
+ if (!iterator->current_namespace)
+ hit = 1;
+ goto next_entry;
+ case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
+ iterator->_reset_on_ext = 1;
+ iterator->current_namespace = &radiotap_ns;
+ iterator->is_radiotap_ns = 1;
+ goto next_entry;
+ case IEEE80211_RADIOTAP_EXT:
+ /*
+ * bit 31 was set, there is more
+ * -- move to next u32 bitmap
+ */
+ iterator->_bitmap_shifter =
+ get_unaligned_le32(iterator->_next_bitmap);
+ iterator->_next_bitmap++;
+ if (iterator->_reset_on_ext)
+ iterator->_arg_index = 0;
+ else
+ iterator->_arg_index++;
+ iterator->_reset_on_ext = 0;
+ break;
+ default:
+ /* we've got a hit! */
+ hit = 1;
+ next_entry:
+ iterator->_bitmap_shifter >>= 1;
+ iterator->_arg_index++;
+ }
/* if we found a valid arg earlier, return it now */
if (hit)
return 0;
}
-
- /* we don't know how to handle any more args, we're done */
- return -ENOENT;
}
diff --git a/contrib/wpa/src/utils/radiotap.h b/contrib/wpa/src/utils/radiotap.h
index 137288f..0572e7c 100644
--- a/contrib/wpa/src/utils/radiotap.h
+++ b/contrib/wpa/src/utils/radiotap.h
@@ -1,6 +1,3 @@
-/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
-/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
-
/*-
* Copyright (c) 2003, 2004 David Young. All rights reserved.
*
@@ -178,6 +175,14 @@ struct ieee80211_radiotap_header {
*
* Number of unicast retries a transmitted frame used.
*
+ * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless
+ *
+ * Contains a bitmap of known fields/flags, the flags, and
+ * the MCS index.
+ *
+ * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitlesss
+ *
+ * Contains the AMPDU information for the subframe.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
@@ -198,6 +203,13 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TX_FLAGS = 15,
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+
+ IEEE80211_RADIOTAP_MCS = 19,
+ IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
+
+ /* valid in every it_present bitmap, even vendor namespaces */
+ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
+ IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
IEEE80211_RADIOTAP_EXT = 31
};
@@ -230,8 +242,10 @@ enum ieee80211_radiotap_type {
* 802.11 header and payload
* (to 32-bit boundary)
*/
+#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* frame failed FCS check */
+
/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */
/* For IEEE80211_RADIOTAP_TX_FLAGS */
#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
@@ -240,4 +254,38 @@ enum ieee80211_radiotap_type {
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ACK */
+/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
+#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
+#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
+#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
+#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
+#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
+#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
+
+/* For IEEE80211_RADIOTAP_MCS */
+#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01
+#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02
+#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04
+#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08
+#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10
+#define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20
+#define IEEE80211_RADIOTAP_MCS_HAVE_NESS 0x40
+#define IEEE80211_RADIOTAP_MCS_NESS_BIT1 0x80
+
+
+#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03
+#define IEEE80211_RADIOTAP_MCS_BW_20 0
+#define IEEE80211_RADIOTAP_MCS_BW_40 1
+#define IEEE80211_RADIOTAP_MCS_BW_20L 2
+#define IEEE80211_RADIOTAP_MCS_BW_20U 3
+#define IEEE80211_RADIOTAP_MCS_SGI 0x04
+#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
+#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
+#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60
+#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5
+#define IEEE80211_RADIOTAP_MCS_STBC_1 1
+#define IEEE80211_RADIOTAP_MCS_STBC_2 2
+#define IEEE80211_RADIOTAP_MCS_STBC_3 3
+#define IEEE80211_RADIOTAP_MCS_NESS_BIT0 0x80
+
#endif /* IEEE80211_RADIOTAP_H */
diff --git a/contrib/wpa/src/utils/radiotap_iter.h b/contrib/wpa/src/utils/radiotap_iter.h
index 2e0e872..b768c85 100644
--- a/contrib/wpa/src/utils/radiotap_iter.h
+++ b/contrib/wpa/src/utils/radiotap_iter.h
@@ -1,56 +1,96 @@
-/*
- * Radiotap parser
- *
- * Copyright 2007 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
#ifndef __RADIOTAP_ITER_H
#define __RADIOTAP_ITER_H
+#include <stdint.h>
#include "radiotap.h"
/* Radiotap header iteration
* implemented in radiotap.c
*/
+
+struct radiotap_override {
+ uint8_t field;
+ uint8_t align:4, size:4;
+};
+
+struct radiotap_align_size {
+ uint8_t align:4, size:4;
+};
+
+struct ieee80211_radiotap_namespace {
+ const struct radiotap_align_size *align_size;
+ int n_bits;
+ uint32_t oui;
+ uint8_t subns;
+};
+
+struct ieee80211_radiotap_vendor_namespaces {
+ const struct ieee80211_radiotap_namespace *ns;
+ int n_ns;
+};
+
/**
* struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
- * @rtheader: pointer to the radiotap header we are walking through
- * @max_length: length of radiotap header in cpu byte ordering
- * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
- * @this_arg: pointer to current radiotap arg
- * @arg_index: internal next argument index
- * @arg: internal next argument pointer
- * @next_bitmap: internal pointer to next present u32
- * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ * @this_arg_index: index of current arg, valid after each successful call
+ * to ieee80211_radiotap_iterator_next()
+ * @this_arg: pointer to current radiotap arg; it is valid after each
+ * call to ieee80211_radiotap_iterator_next() but also after
+ * ieee80211_radiotap_iterator_init() where it will point to
+ * the beginning of the actual data portion
+ * @this_arg_size: length of the current arg, for convenience
+ * @current_namespace: pointer to the current namespace definition
+ * (or internally %NULL if the current namespace is unknown)
+ * @is_radiotap_ns: indicates whether the current namespace is the default
+ * radiotap namespace or not
+ *
+ * @overrides: override standard radiotap fields
+ * @n_overrides: number of overrides
+ *
+ * @_rtheader: pointer to the radiotap header we are walking through
+ * @_max_length: length of radiotap header in cpu byte ordering
+ * @_arg_index: next argument index
+ * @_arg: next argument pointer
+ * @_next_bitmap: internal pointer to next present u32
+ * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ * @_vns: vendor namespace definitions
+ * @_next_ns_data: beginning of the next namespace's data
+ * @_reset_on_ext: internal; reset the arg index to 0 when going to the
+ * next bitmap word
+ *
+ * Describes the radiotap parser state. Fields prefixed with an underscore
+ * must not be used by users of the parser, only by the parser internally.
*/
struct ieee80211_radiotap_iterator {
- struct ieee80211_radiotap_header *rtheader;
- int max_length;
- int this_arg_index;
+ struct ieee80211_radiotap_header *_rtheader;
+ const struct ieee80211_radiotap_vendor_namespaces *_vns;
+ const struct ieee80211_radiotap_namespace *current_namespace;
+
+ unsigned char *_arg, *_next_ns_data;
+ uint32_t *_next_bitmap;
+
unsigned char *this_arg;
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+ const struct radiotap_override *overrides;
+ int n_overrides;
+#endif
+ int this_arg_index;
+ int this_arg_size;
+
+ int is_radiotap_ns;
- int arg_index;
- unsigned char *arg;
- uint32_t *next_bitmap;
- uint32_t bitmap_shifter;
+ int _max_length;
+ int _arg_index;
+ uint32_t _bitmap_shifter;
+ int _reset_on_ext;
};
extern int ieee80211_radiotap_iterator_init(
- struct ieee80211_radiotap_iterator *iterator,
- struct ieee80211_radiotap_header *radiotap_header,
- int max_length);
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns);
extern int ieee80211_radiotap_iterator_next(
- struct ieee80211_radiotap_iterator *iterator);
+ struct ieee80211_radiotap_iterator *iterator);
#endif /* __RADIOTAP_ITER_H */
diff --git a/contrib/wpa/src/utils/trace.c b/contrib/wpa/src/utils/trace.c
index 6795d41..8484d27 100644
--- a/contrib/wpa/src/utils/trace.c
+++ b/contrib/wpa/src/utils/trace.c
@@ -18,11 +18,9 @@ static struct dl_list active_references =
#ifdef WPA_TRACE_BFD
#include <bfd.h>
-#ifdef __linux__
-#include <demangle.h>
-#else /* __linux__ */
-#include <libiberty/demangle.h>
-#endif /* __linux__ */
+
+#define DMGL_PARAMS (1 << 0)
+#define DMGL_ANSI (1 << 1)
static char *prg_fname = NULL;
static bfd *cached_abfd = NULL;
@@ -35,7 +33,7 @@ static void get_prg_fname(void)
os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
len = readlink(exe, fname, sizeof(fname) - 1);
if (len < 0 || len >= (int) sizeof(fname)) {
- perror("readlink");
+ wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
return;
}
fname[len] = '\0';
@@ -162,7 +160,7 @@ static void wpa_trace_bfd_addr(void *pc)
if (abfd == NULL)
return;
- data.pc = (bfd_vma) pc;
+ data.pc = (bfd_hostptr_t) pc;
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -187,6 +185,7 @@ static void wpa_trace_bfd_addr(void *pc)
wpa_printf(MSG_INFO, " %s() %s:%u",
name, filename, data.line);
free(aname);
+ aname = NULL;
data.found = bfd_find_inliner_info(abfd, &data.filename,
&data.function, &data.line);
@@ -202,7 +201,7 @@ static const char * wpa_trace_bfd_addr2func(void *pc)
if (abfd == NULL)
return NULL;
- data.pc = (bfd_vma) pc;
+ data.pc = (bfd_hostptr_t) pc;
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -244,6 +243,53 @@ void wpa_trace_dump_funcname(const char *title, void *pc)
wpa_trace_bfd_addr(pc);
}
+
+size_t wpa_trace_calling_func(const char *buf[], size_t len)
+{
+ bfd *abfd;
+ void *btrace_res[WPA_TRACE_LEN];
+ int i, btrace_num;
+ size_t pos = 0;
+
+ if (len == 0)
+ return 0;
+ if (len > WPA_TRACE_LEN)
+ len = WPA_TRACE_LEN;
+
+ wpa_trace_bfd_init();
+ abfd = cached_abfd;
+ if (!abfd)
+ return 0;
+
+ btrace_num = backtrace(btrace_res, len);
+ if (btrace_num < 1)
+ return 0;
+
+ for (i = 0; i < btrace_num; i++) {
+ struct bfd_data data;
+
+ data.pc = (bfd_hostptr_t) btrace_res[i];
+ data.found = FALSE;
+ bfd_map_over_sections(abfd, find_addr_sect, &data);
+
+ while (data.found) {
+ if (data.function &&
+ (pos > 0 ||
+ os_strcmp(data.function, __func__) != 0)) {
+ buf[pos++] = data.function;
+ if (pos == len)
+ return pos;
+ }
+
+ data.found = bfd_find_inliner_info(abfd, &data.filename,
+ &data.function,
+ &data.line);
+ }
+ }
+
+ return pos;
+}
+
#else /* WPA_TRACE_BFD */
#define wpa_trace_bfd_init() do { } while (0)
diff --git a/contrib/wpa/src/utils/trace.h b/contrib/wpa/src/utils/trace.h
index 38f43fb..43ed86c 100644
--- a/contrib/wpa/src/utils/trace.h
+++ b/contrib/wpa/src/utils/trace.h
@@ -40,6 +40,7 @@ void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr);
dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \
} while (0)
void wpa_trace_check_ref(const void *addr);
+size_t wpa_trace_calling_func(const char *buf[], size_t len);
#else /* WPA_TRACE */
diff --git a/contrib/wpa/src/utils/utils_module_tests.c b/contrib/wpa/src/utils/utils_module_tests.c
new file mode 100644
index 0000000..4b97dad
--- /dev/null
+++ b/contrib/wpa/src/utils/utils_module_tests.c
@@ -0,0 +1,423 @@
+/*
+ * utils 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/bitfield.h"
+#include "utils/ext_password.h"
+#include "utils/trace.h"
+#include "utils/base64.h"
+
+
+struct printf_test_data {
+ u8 *data;
+ size_t len;
+ char *encoded;
+};
+
+static const struct printf_test_data printf_tests[] = {
+ { (u8 *) "abcde", 5, "abcde" },
+ { (u8 *) "a\0b\nc\ed\re\tf\"\\", 13, "a\\0b\\nc\\ed\\re\\tf\\\"\\\\" },
+ { (u8 *) "\x00\x31\x00\x32\x00\x39", 6, "\\x001\\0002\\09" },
+ { (u8 *) "\n\n\n", 3, "\n\12\x0a" },
+ { (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12,
+ "\\xc3\\xa5\xc3\\xa4\\xc3\\xb6\\xc3\\x85\\xc3\\x84\\xc3\\x96" },
+ { (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12,
+ "\\303\\245\\303\\244\\303\\266\\303\\205\\303\\204\\303\\226" },
+ { (u8 *) "\xe5\xe4\xf6\xc5\xc4\xd6", 6,
+ "\\xe5\\xe4\\xf6\\xc5\\xc4\\xd6" },
+ { NULL, 0, NULL }
+};
+
+
+static int printf_encode_decode_tests(void)
+{
+ int i;
+ size_t binlen;
+ char buf[100];
+ u8 bin[100];
+ int errors = 0;
+
+ wpa_printf(MSG_INFO, "printf encode/decode tests");
+
+ for (i = 0; printf_tests[i].data; i++) {
+ const struct printf_test_data *test = &printf_tests[i];
+ printf_encode(buf, sizeof(buf), test->data, test->len);
+ wpa_printf(MSG_INFO, "%d: -> \"%s\"", i, buf);
+
+ binlen = printf_decode(bin, sizeof(bin), buf);
+ if (binlen != test->len ||
+ os_memcmp(bin, test->data, binlen) != 0) {
+ wpa_hexdump(MSG_ERROR, "Error in decoding#1",
+ bin, binlen);
+ errors++;
+ }
+
+ binlen = printf_decode(bin, sizeof(bin), test->encoded);
+ if (binlen != test->len ||
+ os_memcmp(bin, test->data, binlen) != 0) {
+ wpa_hexdump(MSG_ERROR, "Error in decoding#2",
+ bin, binlen);
+ errors++;
+ }
+ }
+
+ buf[5] = 'A';
+ printf_encode(buf, 5, (const u8 *) "abcde", 5);
+ if (buf[5] != 'A') {
+ wpa_printf(MSG_ERROR, "Error in bounds checking#1");
+ errors++;
+ }
+
+ for (i = 5; i < 10; i++) {
+ buf[i] = 'A';
+ printf_encode(buf, i, (const u8 *) "\xdd\xdd\xdd\xdd\xdd", 5);
+ if (buf[i] != 'A') {
+ wpa_printf(MSG_ERROR, "Error in bounds checking#2(%d)",
+ i);
+ errors++;
+ }
+ }
+
+ if (printf_decode(bin, 3, "abcde") != 2)
+ errors++;
+
+ if (printf_decode(bin, 3, "\\xa") != 1 || bin[0] != 10)
+ errors++;
+
+ if (printf_decode(bin, 3, "\\a") != 1 || bin[0] != 'a')
+ errors++;
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d printf test(s) failed", errors);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int bitfield_tests(void)
+{
+ struct bitfield *bf;
+ int i;
+ int errors = 0;
+
+ wpa_printf(MSG_INFO, "bitfield tests");
+
+ bf = bitfield_alloc(123);
+ if (bf == NULL)
+ return -1;
+
+ for (i = 0; i < 123; i++) {
+ if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+ errors++;
+ if (i > 0 && bitfield_is_set(bf, i - 1))
+ errors++;
+ bitfield_set(bf, i);
+ if (!bitfield_is_set(bf, i))
+ errors++;
+ bitfield_clear(bf, i);
+ if (bitfield_is_set(bf, i))
+ errors++;
+ }
+
+ for (i = 123; i < 200; i++) {
+ if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+ errors++;
+ if (i > 0 && bitfield_is_set(bf, i - 1))
+ errors++;
+ bitfield_set(bf, i);
+ if (bitfield_is_set(bf, i))
+ errors++;
+ bitfield_clear(bf, i);
+ if (bitfield_is_set(bf, i))
+ errors++;
+ }
+
+ for (i = 0; i < 123; i++) {
+ if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+ errors++;
+ bitfield_set(bf, i);
+ if (!bitfield_is_set(bf, i))
+ errors++;
+ }
+
+ for (i = 0; i < 123; i++) {
+ if (!bitfield_is_set(bf, i))
+ errors++;
+ bitfield_clear(bf, i);
+ if (bitfield_is_set(bf, i))
+ errors++;
+ }
+
+ for (i = 0; i < 123; i++) {
+ if (bitfield_get_first_zero(bf) != i)
+ errors++;
+ bitfield_set(bf, i);
+ }
+ if (bitfield_get_first_zero(bf) != -1)
+ errors++;
+ for (i = 0; i < 123; i++) {
+ if (!bitfield_is_set(bf, i))
+ errors++;
+ bitfield_clear(bf, i);
+ if (bitfield_get_first_zero(bf) != i)
+ errors++;
+ bitfield_set(bf, i);
+ }
+ if (bitfield_get_first_zero(bf) != -1)
+ errors++;
+
+ bitfield_free(bf);
+
+ bf = bitfield_alloc(8);
+ if (bf == NULL)
+ return -1;
+ if (bitfield_get_first_zero(bf) != 0)
+ errors++;
+ for (i = 0; i < 8; i++)
+ bitfield_set(bf, i);
+ if (bitfield_get_first_zero(bf) != -1)
+ errors++;
+ bitfield_free(bf);
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d bitfield test(s) failed", errors);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int int_array_tests(void)
+{
+ int test1[] = { 1, 2, 3, 4, 5, 6, 0 };
+ int test2[] = { 1, -1, 0 };
+ int test3[] = { 1, 1, 1, -1, 2, 3, 4, 1, 2, 0 };
+ int test3_res[] = { -1, 1, 2, 3, 4, 0 };
+ int errors = 0;
+ int len;
+
+ wpa_printf(MSG_INFO, "int_array tests");
+
+ if (int_array_len(test1) != 6 ||
+ int_array_len(test2) != 2)
+ errors++;
+
+ int_array_sort_unique(test3);
+ len = int_array_len(test3_res);
+ if (int_array_len(test3) != len)
+ errors++;
+ else if (os_memcmp(test3, test3_res, len * sizeof(int)) != 0)
+ errors++;
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d int_array test(s) failed", errors);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int ext_password_tests(void)
+{
+ struct ext_password_data *data;
+ int ret = 0;
+ struct wpabuf *pw;
+
+ wpa_printf(MSG_INFO, "ext_password tests");
+
+ data = ext_password_init("unknown", "foo");
+ if (data != NULL)
+ return -1;
+
+ data = ext_password_init("test", NULL);
+ if (data == NULL)
+ return -1;
+ pw = ext_password_get(data, "foo");
+ if (pw != NULL)
+ ret = -1;
+ ext_password_free(pw);
+
+ ext_password_deinit(data);
+
+ pw = ext_password_get(NULL, "foo");
+ if (pw != NULL)
+ ret = -1;
+ ext_password_free(pw);
+
+ return ret;
+}
+
+
+static int trace_tests(void)
+{
+ wpa_printf(MSG_INFO, "trace tests");
+
+ wpa_trace_show("test backtrace");
+ wpa_trace_dump_funcname("test funcname", trace_tests);
+
+ return 0;
+}
+
+
+static int base64_tests(void)
+{
+ int errors = 0;
+ unsigned char *res;
+ size_t res_len;
+
+ wpa_printf(MSG_INFO, "base64 tests");
+
+ res = base64_encode((const unsigned char *) "", ~0, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_encode((const unsigned char *) "=", 1, &res_len);
+ if (!res || res_len != 5 || res[0] != 'P' || res[1] != 'Q' ||
+ res[2] != '=' || res[3] != '=' || res[4] != '\n')
+ errors++;
+ os_free(res);
+
+ res = base64_encode((const unsigned char *) "=", 1, NULL);
+ if (!res || res[0] != 'P' || res[1] != 'Q' ||
+ res[2] != '=' || res[3] != '=' || res[4] != '\n')
+ errors++;
+ os_free(res);
+
+ res = base64_decode((const unsigned char *) "", 0, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_decode((const unsigned char *) "a", 1, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_decode((const unsigned char *) "====", 4, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_decode((const unsigned char *) "PQ==", 4, &res_len);
+ if (!res || res_len != 1 || res[0] != '=')
+ errors++;
+ os_free(res);
+
+ res = base64_decode((const unsigned char *) "P.Q-=!=*", 8, &res_len);
+ if (!res || res_len != 1 || res[0] != '=')
+ errors++;
+ os_free(res);
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d base64 test(s) failed", errors);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int common_tests(void)
+{
+ char buf[3];
+ u8 addr[ETH_ALEN] = { 1, 2, 3, 4, 5, 6 };
+ u8 bin[3];
+ int errors = 0;
+ struct wpa_freq_range_list ranges;
+
+ wpa_printf(MSG_INFO, "common tests");
+
+ if (hwaddr_mask_txt(buf, 3, addr, addr) != -1)
+ errors++;
+
+ if (wpa_scnprintf(buf, 0, "hello") != 0 ||
+ wpa_scnprintf(buf, 3, "hello") != 2)
+ errors++;
+
+ if (wpa_snprintf_hex(buf, 0, addr, ETH_ALEN) != 0 ||
+ wpa_snprintf_hex(buf, 3, addr, ETH_ALEN) != 2)
+ errors++;
+
+ if (merge_byte_arrays(bin, 3, addr, ETH_ALEN, NULL, 0) != 3 ||
+ merge_byte_arrays(bin, 3, NULL, 0, addr, ETH_ALEN) != 3)
+ errors++;
+
+ if (dup_binstr(NULL, 0) != NULL)
+ errors++;
+
+ if (freq_range_list_includes(NULL, 0) != 0)
+ errors++;
+
+ os_memset(&ranges, 0, sizeof(ranges));
+ if (freq_range_list_parse(&ranges, "") != 0 ||
+ freq_range_list_includes(&ranges, 0) != 0 ||
+ freq_range_list_str(&ranges) != NULL)
+ errors++;
+
+ if (utf8_unescape(NULL, 0, buf, sizeof(buf)) != 0 ||
+ utf8_unescape("a", 1, NULL, 0) != 0 ||
+ utf8_unescape("a\\", 2, buf, sizeof(buf)) != 0 ||
+ utf8_unescape("abcde", 5, buf, sizeof(buf)) != 0 ||
+ utf8_unescape("abc", 3, buf, 3) != 3)
+ errors++;
+
+ if (utf8_unescape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a')
+ errors++;
+
+ if (utf8_unescape("\\b", 2, buf, sizeof(buf)) != 1 || buf[0] != 'b')
+ errors++;
+
+ if (utf8_escape(NULL, 0, buf, sizeof(buf)) != 0 ||
+ utf8_escape("a", 1, NULL, 0) != 0 ||
+ utf8_escape("abcde", 5, buf, sizeof(buf)) != 0 ||
+ utf8_escape("a\\bcde", 6, buf, sizeof(buf)) != 0 ||
+ utf8_escape("ab\\cde", 6, buf, sizeof(buf)) != 0 ||
+ utf8_escape("abc\\de", 6, buf, sizeof(buf)) != 0 ||
+ utf8_escape("abc", 3, buf, 3) != 3)
+ errors++;
+
+ if (utf8_escape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a')
+ errors++;
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d common test(s) failed", errors);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int utils_module_tests(void)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "utils module tests");
+
+ if (printf_encode_decode_tests() < 0 ||
+ ext_password_tests() < 0 ||
+ trace_tests() < 0 ||
+ bitfield_tests() < 0 ||
+ base64_tests() < 0 ||
+ common_tests() < 0 ||
+ int_array_tests() < 0)
+ ret = -1;
+
+ return ret;
+}
diff --git a/contrib/wpa/src/utils/uuid.c b/contrib/wpa/src/utils/uuid.c
index 2aa4bcb..0f224f9 100644
--- a/contrib/wpa/src/utils/uuid.c
+++ b/contrib/wpa/src/utils/uuid.c
@@ -55,7 +55,7 @@ int uuid_bin2str(const u8 *bin, char *str, size_t max_len)
bin[4], bin[5], bin[6], bin[7],
bin[8], bin[9], bin[10], bin[11],
bin[12], bin[13], bin[14], bin[15]);
- if (len < 0 || (size_t) len >= max_len)
+ if (os_snprintf_error(max_len, len))
return -1;
return 0;
}
diff --git a/contrib/wpa/src/utils/wpa_debug.c b/contrib/wpa/src/utils/wpa_debug.c
index 5511ef1..0d11905 100644
--- a/contrib/wpa/src/utils/wpa_debug.c
+++ b/contrib/wpa/src/utils/wpa_debug.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -375,19 +375,19 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
#endif /* CONFIG_ANDROID_LOG */
}
-void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
+void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
{
_wpa_hexdump(level, title, buf, len, 1);
}
-void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
+void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
{
_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
}
-static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
size_t len, int show)
{
size_t i, llen;
@@ -407,7 +407,7 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
/* can do ascii processing in userspace */
for (i = 0; i < len; i++)
fprintf(wpa_debug_tracing_file,
- " %02x", buf[i]);
+ " %02x", pos[i]);
}
fflush(wpa_debug_tracing_file);
}
@@ -495,13 +495,14 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
}
-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
+void wpa_hexdump_ascii(int level, const char *title, const void *buf,
+ size_t len)
{
_wpa_hexdump_ascii(level, title, buf, len, 1);
}
-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
size_t len)
{
_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
@@ -554,6 +555,8 @@ int wpa_debug_open_file(const char *path)
#ifndef _WIN32
setvbuf(out_file, NULL, _IOLBF, 0);
#endif /* _WIN32 */
+#else /* CONFIG_DEBUG_FILE */
+ (void)path;
#endif /* CONFIG_DEBUG_FILE */
return 0;
}
@@ -571,6 +574,14 @@ void wpa_debug_close_file(void)
#endif /* CONFIG_DEBUG_FILE */
}
+
+void wpa_debug_setup_stdout(void)
+{
+#ifndef _WIN32
+ setvbuf(stdout, NULL, _IOLBF, 0);
+#endif /* _WIN32 */
+}
+
#endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -595,10 +606,14 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
- const int buflen = 2048;
+ int buflen;
int len;
char prefix[130];
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
buf = os_malloc(buflen);
if (buf == NULL) {
wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
@@ -612,7 +627,7 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...)
if (ifname) {
int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
ifname);
- if (res < 0 || res >= (int) sizeof(prefix))
+ if (os_snprintf_error(sizeof(prefix), res))
prefix[0] = '\0';
}
}
@@ -620,7 +635,7 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...)
va_end(ap);
wpa_printf(level, "%s%s", prefix, buf);
if (wpa_msg_cb)
- wpa_msg_cb(ctx, level, buf, len);
+ wpa_msg_cb(ctx, level, 0, buf, len);
os_free(buf);
}
@@ -629,12 +644,16 @@ void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
- const int buflen = 2048;
+ int buflen;
int len;
if (!wpa_msg_cb)
return;
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
buf = os_malloc(buflen);
if (buf == NULL) {
wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
@@ -644,9 +663,92 @@ void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
va_start(ap, fmt);
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
- wpa_msg_cb(ctx, level, buf, len);
+ wpa_msg_cb(ctx, level, 0, buf, len);
+ os_free(buf);
+}
+
+
+void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+ int len;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate "
+ "message buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_printf(level, "%s", buf);
+ if (wpa_msg_cb)
+ wpa_msg_cb(ctx, level, 1, buf, len);
+ os_free(buf);
+}
+
+
+void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+ int len;
+
+ if (!wpa_msg_cb)
+ return;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR,
+ "wpa_msg_global_ctrl: Failed to allocate message buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_msg_cb(ctx, level, 1, buf, len);
+ os_free(buf);
+}
+
+
+void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+ int len;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
+ "message buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_printf(level, "%s", buf);
+ if (wpa_msg_cb)
+ wpa_msg_cb(ctx, level, 2, buf, len);
os_free(buf);
}
+
#endif /* CONFIG_NO_WPA_MSG */
@@ -664,9 +766,13 @@ void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
{
va_list ap;
char *buf;
- const int buflen = 2048;
+ int buflen;
int len;
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
buf = os_malloc(buflen);
if (buf == NULL) {
wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
diff --git a/contrib/wpa/src/utils/wpa_debug.h b/contrib/wpa/src/utils/wpa_debug.h
index 339c749..400bea9 100644
--- a/contrib/wpa/src/utils/wpa_debug.h
+++ b/contrib/wpa/src/utils/wpa_debug.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, 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 "wpabuf.h"
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
/* Debugging function - conditional printf and hex dump. Driver wrappers can
* use these for debugging purposes. */
@@ -30,6 +34,7 @@ enum {
#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
#define wpa_debug_open_file(p) do { } while (0)
#define wpa_debug_close_file() do { } while (0)
+#define wpa_debug_setup_stdout() do { } while (0)
#define wpa_dbg(args...) do { } while (0)
static inline int wpa_debug_reopen_file(void)
@@ -42,6 +47,7 @@ static inline int wpa_debug_reopen_file(void)
int wpa_debug_open_file(const char *path);
int wpa_debug_reopen_file(void);
void wpa_debug_close_file(void);
+void wpa_debug_setup_stdout(void);
/**
* wpa_debug_printf_timestamp - Print timestamp for debug output
@@ -77,7 +83,7 @@ PRINTF_FORMAT(2, 3);
* output may be directed to stdout, stderr, and/or syslog based on
* configuration. The contents of buf is printed out has hex dump.
*/
-void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
+void wpa_hexdump(int level, const char *title, const void *buf, size_t len);
static inline void wpa_hexdump_buf(int level, const char *title,
const struct wpabuf *buf)
@@ -99,7 +105,7 @@ static inline void wpa_hexdump_buf(int level, const char *title,
* like wpa_hexdump(), but by default, does not include secret keys (passwords,
* etc.) in debug output.
*/
-void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
+void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len);
static inline void wpa_hexdump_buf_key(int level, const char *title,
const struct wpabuf *buf)
@@ -121,7 +127,7 @@ static inline void wpa_hexdump_buf_key(int level, const char *title,
* the hex numbers and ASCII characters (for printable range) are shown. 16
* bytes per line will be shown.
*/
-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii(int level, const char *title, const void *buf,
size_t len);
/**
@@ -138,7 +144,7 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
* bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
* default, does not include secret keys (passwords, etc.) in debug output.
*/
-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
size_t len);
/*
@@ -155,6 +161,9 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
#ifdef CONFIG_NO_WPA_MSG
#define wpa_msg(args...) do { } while (0)
#define wpa_msg_ctrl(args...) do { } while (0)
+#define wpa_msg_global(args...) do { } while (0)
+#define wpa_msg_global_ctrl(args...) do { } while (0)
+#define wpa_msg_no_global(args...) do { } while (0)
#define wpa_msg_register_cb(f) do { } while (0)
#define wpa_msg_register_ifname_cb(f) do { } while (0)
#else /* CONFIG_NO_WPA_MSG */
@@ -189,8 +198,53 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
-typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
- size_t len);
+/**
+ * wpa_msg_global - Global printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg(), but it sends the output as a global event,
+ * i.e., without being specific to an interface. For backwards compatibility,
+ * an old style event is also delivered on one of the interfaces (the one
+ * specified by the context data).
+ */
+void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+/**
+ * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg_global(), but it sends the output only to the
+ * attached global ctrl_iface monitors. In other words, it can be used for
+ * frequent events that do not need to be sent to syslog.
+ */
+void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+/**
+ * wpa_msg_no_global - Conditional printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg(), but it does not send the output as a global
+ * event.
+ */
+void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, int global,
+ const char *txt, size_t len);
/**
* wpa_msg_register_cb - Register callback function for wpa_msg() messages
diff --git a/contrib/wpa/src/utils/wpabuf.c b/contrib/wpa/src/utils/wpabuf.c
index b257b36..7aafa0a 100644
--- a/contrib/wpa/src/utils/wpabuf.c
+++ b/contrib/wpa/src/utils/wpabuf.c
@@ -205,6 +205,15 @@ void wpabuf_free(struct wpabuf *buf)
}
+void wpabuf_clear_free(struct wpabuf *buf)
+{
+ if (buf) {
+ os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf));
+ wpabuf_free(buf);
+ }
+}
+
+
void * wpabuf_put(struct wpabuf *buf, size_t len)
{
void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
diff --git a/contrib/wpa/src/utils/wpabuf.h b/contrib/wpa/src/utils/wpabuf.h
index dbce925..c3ef1ba 100644
--- a/contrib/wpa/src/utils/wpabuf.h
+++ b/contrib/wpa/src/utils/wpabuf.h
@@ -32,6 +32,7 @@ struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
struct wpabuf * wpabuf_dup(const struct wpabuf *src);
void wpabuf_free(struct wpabuf *buf);
+void wpabuf_clear_free(struct wpabuf *buf);
void * wpabuf_put(struct wpabuf *buf, size_t len);
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
diff --git a/contrib/wpa/src/utils/xml-utils.c b/contrib/wpa/src/utils/xml-utils.c
new file mode 100644
index 0000000..4916d29
--- /dev/null
+++ b/contrib/wpa/src/utils/xml-utils.c
@@ -0,0 +1,471 @@
+/*
+ * Generic XML helper functions
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "xml-utils.h"
+
+
+static xml_node_t * get_node_uri_iter(struct xml_node_ctx *ctx,
+ xml_node_t *root, char *uri)
+{
+ char *end;
+ xml_node_t *node;
+ const char *name;
+
+ end = strchr(uri, '/');
+ if (end)
+ *end++ = '\0';
+
+ node = root;
+ xml_node_for_each_sibling(ctx, node) {
+ xml_node_for_each_check(ctx, node);
+ name = xml_node_get_localname(ctx, node);
+ if (strcasecmp(name, uri) == 0)
+ break;
+ }
+
+ if (node == NULL)
+ return NULL;
+
+ if (end) {
+ return get_node_uri_iter(ctx, xml_node_first_child(ctx, node),
+ end);
+ }
+
+ return node;
+}
+
+
+xml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root,
+ const char *uri)
+{
+ char *search;
+ xml_node_t *node;
+
+ search = os_strdup(uri);
+ if (search == NULL)
+ return NULL;
+
+ node = get_node_uri_iter(ctx, root, search);
+
+ os_free(search);
+ return node;
+}
+
+
+static xml_node_t * get_node_iter(struct xml_node_ctx *ctx,
+ xml_node_t *root, const char *path)
+{
+ char *end;
+ xml_node_t *node;
+ const char *name;
+
+ end = os_strchr(path, '/');
+ if (end)
+ *end++ = '\0';
+
+ xml_node_for_each_child(ctx, node, root) {
+ xml_node_for_each_check(ctx, node);
+ name = xml_node_get_localname(ctx, node);
+ if (os_strcasecmp(name, path) == 0)
+ break;
+ }
+
+ if (node == NULL)
+ return NULL;
+ if (end)
+ return get_node_iter(ctx, node, end);
+ return node;
+}
+
+
+xml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root,
+ const char *path)
+{
+ char *search;
+ xml_node_t *node;
+
+ search = os_strdup(path);
+ if (search == NULL)
+ return NULL;
+
+ node = get_node_iter(ctx, root, search);
+
+ os_free(search);
+ return node;
+}
+
+
+xml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root,
+ const char *path)
+{
+ xml_node_t *node;
+ xml_node_t *match;
+
+ xml_node_for_each_child(ctx, node, root) {
+ xml_node_for_each_check(ctx, node);
+ match = get_node(ctx, node, path);
+ if (match)
+ return match;
+ }
+
+ return NULL;
+}
+
+
+xml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name)
+{
+ xml_node_t *node;
+ char *buf, *buf2, *start;
+ size_t len;
+
+ buf = os_readfile(name, &len);
+ if (buf == NULL)
+ return NULL;
+ buf2 = os_realloc(buf, len + 1);
+ if (buf2 == NULL) {
+ os_free(buf);
+ return NULL;
+ }
+ buf = buf2;
+ buf[len] = '\0';
+
+ start = os_strstr(buf, "<!DOCTYPE ");
+ if (start) {
+ char *pos = start + 1;
+ int count = 1;
+ while (*pos) {
+ if (*pos == '<')
+ count++;
+ else if (*pos == '>') {
+ count--;
+ if (count == 0) {
+ pos++;
+ break;
+ }
+ }
+ pos++;
+ }
+ if (count == 0) {
+ /* Remove DOCTYPE to allow the file to be parsed */
+ os_memset(start, ' ', pos - start);
+ }
+ }
+
+ node = xml_node_from_buf(ctx, buf);
+ os_free(buf);
+
+ return node;
+}
+
+
+int node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node)
+{
+ FILE *f;
+ char *str;
+
+ str = xml_node_to_str(ctx, node);
+ if (str == NULL)
+ return -1;
+
+ f = fopen(fname, "w");
+ if (!f) {
+ os_free(str);
+ return -1;
+ }
+
+ fprintf(f, "%s\n", str);
+ os_free(str);
+ fclose(f);
+
+ return 0;
+}
+
+
+static char * get_val(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ char *val, *pos;
+
+ val = xml_node_get_text(ctx, node);
+ if (val == NULL)
+ return NULL;
+ pos = val;
+ while (*pos) {
+ if (*pos != ' ' && *pos != '\t' && *pos != '\r' && *pos != '\n')
+ return val;
+ pos++;
+ }
+
+ return NULL;
+}
+
+
+static char * add_path(const char *prev, const char *leaf)
+{
+ size_t len;
+ char *new_uri;
+
+ if (prev == NULL)
+ return NULL;
+
+ len = os_strlen(prev) + 1 + os_strlen(leaf) + 1;
+ new_uri = os_malloc(len);
+ if (new_uri)
+ os_snprintf(new_uri, len, "%s/%s", prev, leaf);
+
+ return new_uri;
+}
+
+
+static void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out,
+ xml_node_t *in, const char *uri)
+{
+ xml_node_t *node;
+ xml_node_t *tnds;
+ const char *name;
+ char *val;
+ char *new_uri;
+
+ xml_node_for_each_child(ctx, node, in) {
+ xml_node_for_each_check(ctx, node);
+ name = xml_node_get_localname(ctx, node);
+
+ tnds = xml_node_create(ctx, out, NULL, "Node");
+ if (tnds == NULL)
+ return;
+ xml_node_create_text(ctx, tnds, NULL, "NodeName", name);
+
+ if (uri)
+ 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);
+ }
+
+ new_uri = add_path(uri, name);
+ node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri);
+ os_free(new_uri);
+ }
+}
+
+
+static int add_ddfname(struct xml_node_ctx *ctx, xml_node_t *parent,
+ const char *urn)
+{
+ xml_node_t *node;
+
+ node = xml_node_create(ctx, parent, NULL, "RTProperties");
+ if (node == NULL)
+ return -1;
+ node = xml_node_create(ctx, node, NULL, "Type");
+ if (node == NULL)
+ return -1;
+ xml_node_create_text(ctx, node, NULL, "DDFName", urn);
+ return 0;
+}
+
+
+xml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo,
+ int use_path, const char *urn, const char *ns_uri)
+{
+ xml_node_t *root;
+ xml_node_t *node;
+ const char *name;
+
+ root = xml_node_create_root(ctx, ns_uri, NULL, NULL, "MgmtTree");
+ if (root == NULL)
+ return NULL;
+
+ xml_node_create_text(ctx, root, NULL, "VerDTD", "1.2");
+
+ name = xml_node_get_localname(ctx, mo);
+
+ node = xml_node_create(ctx, root, NULL, "Node");
+ if (node == NULL)
+ goto fail;
+ xml_node_create_text(ctx, node, NULL, "NodeName", name);
+ if (urn)
+ add_ddfname(ctx, node, urn);
+
+ node_to_tnds(ctx, use_path ? root : node, mo, use_path ? name : NULL);
+
+ return root;
+
+fail:
+ xml_node_free(ctx, root);
+ return NULL;
+}
+
+
+static xml_node_t * get_first_child_node(struct xml_node_ctx *ctx,
+ xml_node_t *node,
+ const char *name)
+{
+ const char *lname;
+ xml_node_t *child;
+
+ xml_node_for_each_child(ctx, child, node) {
+ xml_node_for_each_check(ctx, child);
+ lname = xml_node_get_localname(ctx, child);
+ if (os_strcasecmp(lname, name) == 0)
+ return child;
+ }
+
+ return NULL;
+}
+
+
+static char * get_node_text(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *node_name)
+{
+ node = get_first_child_node(ctx, node, node_name);
+ if (node == NULL)
+ return NULL;
+ return xml_node_get_text(ctx, node);
+}
+
+
+static xml_node_t * add_mo_node(struct xml_node_ctx *ctx, xml_node_t *root,
+ xml_node_t *node, const char *uri)
+{
+ char *nodename, *value, *path;
+ xml_node_t *parent;
+
+ nodename = get_node_text(ctx, node, "NodeName");
+ if (nodename == NULL)
+ return NULL;
+ value = get_node_text(ctx, node, "Value");
+
+ if (root == NULL) {
+ root = xml_node_create_root(ctx, NULL, NULL, NULL,
+ nodename);
+ if (root && value)
+ xml_node_set_text(ctx, root, value);
+ } else {
+ if (uri == NULL) {
+ xml_node_get_text_free(ctx, nodename);
+ xml_node_get_text_free(ctx, value);
+ return NULL;
+ }
+ path = get_node_text(ctx, node, "Path");
+ if (path)
+ uri = path;
+ parent = get_node_uri(ctx, root, uri);
+ xml_node_get_text_free(ctx, path);
+ if (parent == NULL) {
+ printf("Could not find URI '%s'\n", uri);
+ xml_node_get_text_free(ctx, nodename);
+ xml_node_get_text_free(ctx, value);
+ return NULL;
+ }
+ if (value)
+ xml_node_create_text(ctx, parent, NULL, nodename,
+ value);
+ else
+ xml_node_create(ctx, parent, NULL, nodename);
+ }
+
+ xml_node_get_text_free(ctx, nodename);
+ xml_node_get_text_free(ctx, value);
+
+ return root;
+}
+
+
+static xml_node_t * tnds_to_mo_iter(struct xml_node_ctx *ctx, xml_node_t *root,
+ xml_node_t *node, const char *uri)
+{
+ xml_node_t *child;
+ const char *name;
+ char *nodename;
+
+ xml_node_for_each_sibling(ctx, node) {
+ xml_node_for_each_check(ctx, node);
+
+ nodename = get_node_text(ctx, node, "NodeName");
+ if (nodename == NULL)
+ return NULL;
+
+ name = xml_node_get_localname(ctx, node);
+ if (strcmp(name, "Node") == 0) {
+ if (root && !uri) {
+ printf("Invalid TNDS tree structure - "
+ "multiple top level nodes\n");
+ xml_node_get_text_free(ctx, nodename);
+ return NULL;
+ }
+ root = add_mo_node(ctx, root, node, uri);
+ }
+
+ child = get_first_child_node(ctx, node, "Node");
+ if (child) {
+ if (uri == NULL)
+ tnds_to_mo_iter(ctx, root, child, nodename);
+ else {
+ char *new_uri;
+ new_uri = add_path(uri, nodename);
+ tnds_to_mo_iter(ctx, root, child, new_uri);
+ os_free(new_uri);
+ }
+ }
+ xml_node_get_text_free(ctx, nodename);
+ }
+
+ return root;
+}
+
+
+xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds)
+{
+ const char *name;
+ xml_node_t *node;
+
+ name = xml_node_get_localname(ctx, tnds);
+ if (name == NULL || os_strcmp(name, "MgmtTree") != 0)
+ return NULL;
+
+ node = get_first_child_node(ctx, tnds, "Node");
+ if (!node)
+ return NULL;
+ return tnds_to_mo_iter(ctx, NULL, node, NULL);
+}
+
+
+xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ xml_node_t *envelope, *body;
+ xml_namespace_t *ns;
+
+ envelope = xml_node_create_root(
+ ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns,
+ "Envelope");
+ if (envelope == NULL)
+ return NULL;
+ body = xml_node_create(ctx, envelope, ns, "Body");
+ xml_node_add_child(ctx, body, node);
+ return envelope;
+}
+
+
+xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap)
+{
+ xml_node_t *body, *child;
+
+ body = get_node_uri(ctx, soap, "Envelope/Body");
+ if (body == NULL)
+ return NULL;
+ xml_node_for_each_child(ctx, child, body) {
+ xml_node_for_each_check(ctx, child);
+ return child;
+ }
+ return NULL;
+}
diff --git a/contrib/wpa/src/utils/xml-utils.h b/contrib/wpa/src/utils/xml-utils.h
new file mode 100644
index 0000000..fb6208c
--- /dev/null
+++ b/contrib/wpa/src/utils/xml-utils.h
@@ -0,0 +1,97 @@
+/*
+ * Generic XML helper functions
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef XML_UTILS_H
+#define XML_UTILS_H
+
+struct xml_node_ctx;
+typedef struct xml_node xml_node_t;
+typedef struct xml_namespace_foo xml_namespace_t;
+
+/* XML library wrappers */
+
+int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *xml_schema_fname, char **ret_err);
+int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *dtd_fname, char **ret_err);
+void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node);
+xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node);
+xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf);
+const char * xml_node_get_localname(struct xml_node_ctx *ctx,
+ xml_node_t *node);
+char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node);
+void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node);
+void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent,
+ xml_node_t *child);
+xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri,
+ const char *ns_prefix,
+ xml_namespace_t **ret_ns, const char *name);
+xml_node_t * xml_node_create(struct xml_node_ctx *ctx, xml_node_t *parent,
+ xml_namespace_t *ns, const char *name);
+xml_node_t * xml_node_create_text(struct xml_node_ctx *ctx,
+ xml_node_t *parent, xml_namespace_t *ns,
+ const char *name, const char *value);
+xml_node_t * xml_node_create_text_ns(struct xml_node_ctx *ctx,
+ xml_node_t *parent, const char *ns_uri,
+ const char *name, const char *value);
+void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *value);
+int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node,
+ xml_namespace_t *ns, const char *name, const char *value);
+char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
+ char *name);
+char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *ns_uri, char *name);
+void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val);
+xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx,
+ xml_node_t *parent);
+xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx,
+ xml_node_t *node);
+int xml_node_is_element(struct xml_node_ctx *ctx, xml_node_t *node);
+char * xml_node_get_text(struct xml_node_ctx *ctx, xml_node_t *node);
+void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val);
+char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node,
+ int *ret_len);
+xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node);
+
+#define xml_node_for_each_child(ctx, child, parent) \
+for (child = xml_node_first_child(ctx, parent); \
+ child; \
+ child = xml_node_next_sibling(ctx, child))
+
+#define xml_node_for_each_sibling(ctx, node) \
+for (; \
+ node; \
+ node = xml_node_next_sibling(ctx, node))
+
+#define xml_node_for_each_check(ctx, child) \
+if (!xml_node_is_element(ctx, child)) \
+ continue
+
+
+struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx,
+ const void *env);
+void xml_node_deinit_ctx(struct xml_node_ctx *ctx);
+
+
+xml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root,
+ const char *uri);
+xml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root,
+ const char *path);
+xml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root,
+ const char *path);
+xml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name);
+int node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node);
+xml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo,
+ int use_path, const char *urn, const char *ns_uri);
+xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds);
+
+xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node);
+xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap);
+
+#endif /* XML_UTILS_H */
diff --git a/contrib/wpa/src/utils/xml_libxml2.c b/contrib/wpa/src/utils/xml_libxml2.c
new file mode 100644
index 0000000..c928394
--- /dev/null
+++ b/contrib/wpa/src/utils/xml_libxml2.c
@@ -0,0 +1,457 @@
+/*
+ * XML wrapper for libxml2
+ * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#define LIBXML_VALID_ENABLED
+#include <libxml/tree.h>
+#include <libxml/xmlschemastypes.h>
+
+#include "common.h"
+#include "base64.h"
+#include "xml-utils.h"
+
+
+struct xml_node_ctx {
+ void *ctx;
+};
+
+
+struct str_buf {
+ char *buf;
+ size_t len;
+};
+
+#define MAX_STR 1000
+
+static void add_str(void *ctx_ptr, const char *fmt, ...)
+{
+ struct str_buf *str = ctx_ptr;
+ va_list ap;
+ char *n;
+ int len;
+
+ n = os_realloc(str->buf, str->len + MAX_STR + 2);
+ if (n == NULL)
+ return;
+ str->buf = n;
+
+ va_start(ap, fmt);
+ len = vsnprintf(str->buf + str->len, MAX_STR, fmt, ap);
+ va_end(ap);
+ if (len >= MAX_STR)
+ len = MAX_STR - 1;
+ str->len += len;
+ str->buf[str->len] = '\0';
+}
+
+
+int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *xml_schema_fname, char **ret_err)
+{
+ xmlDocPtr doc;
+ xmlNodePtr n;
+ xmlSchemaParserCtxtPtr pctx;
+ xmlSchemaValidCtxtPtr vctx;
+ xmlSchemaPtr schema;
+ int ret;
+ struct str_buf errors;
+
+ if (ret_err)
+ *ret_err = NULL;
+
+ doc = xmlNewDoc((xmlChar *) "1.0");
+ if (doc == NULL)
+ return -1;
+ n = xmlDocCopyNode((xmlNodePtr) node, doc, 1);
+ if (n == NULL) {
+ xmlFreeDoc(doc);
+ return -1;
+ }
+ xmlDocSetRootElement(doc, n);
+
+ os_memset(&errors, 0, sizeof(errors));
+
+ pctx = xmlSchemaNewParserCtxt(xml_schema_fname);
+ xmlSchemaSetParserErrors(pctx, (xmlSchemaValidityErrorFunc) add_str,
+ (xmlSchemaValidityWarningFunc) add_str,
+ &errors);
+ schema = xmlSchemaParse(pctx);
+ xmlSchemaFreeParserCtxt(pctx);
+
+ vctx = xmlSchemaNewValidCtxt(schema);
+ xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc) add_str,
+ (xmlSchemaValidityWarningFunc) add_str,
+ &errors);
+
+ ret = xmlSchemaValidateDoc(vctx, doc);
+ xmlSchemaFreeValidCtxt(vctx);
+ xmlFreeDoc(doc);
+ xmlSchemaFree(schema);
+
+ if (ret == 0) {
+ os_free(errors.buf);
+ return 0;
+ } else if (ret > 0) {
+ if (ret_err)
+ *ret_err = errors.buf;
+ else
+ os_free(errors.buf);
+ return -1;
+ } else {
+ if (ret_err)
+ *ret_err = errors.buf;
+ else
+ os_free(errors.buf);
+ return -1;
+ }
+}
+
+
+int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *dtd_fname, char **ret_err)
+{
+ xmlDocPtr doc;
+ xmlNodePtr n;
+ xmlValidCtxt vctx;
+ xmlDtdPtr dtd;
+ int ret;
+ struct str_buf errors;
+
+ if (ret_err)
+ *ret_err = NULL;
+
+ doc = xmlNewDoc((xmlChar *) "1.0");
+ if (doc == NULL)
+ return -1;
+ n = xmlDocCopyNode((xmlNodePtr) node, doc, 1);
+ if (n == NULL) {
+ xmlFreeDoc(doc);
+ return -1;
+ }
+ xmlDocSetRootElement(doc, n);
+
+ os_memset(&errors, 0, sizeof(errors));
+
+ dtd = xmlParseDTD(NULL, (const xmlChar *) dtd_fname);
+ if (dtd == NULL) {
+ xmlFreeDoc(doc);
+ return -1;
+ }
+
+ os_memset(&vctx, 0, sizeof(vctx));
+ vctx.userData = &errors;
+ vctx.error = add_str;
+ vctx.warning = add_str;
+ ret = xmlValidateDtd(&vctx, doc, dtd);
+ xmlFreeDoc(doc);
+ xmlFreeDtd(dtd);
+
+ if (ret == 1) {
+ os_free(errors.buf);
+ return 0;
+ } else {
+ if (ret_err)
+ *ret_err = errors.buf;
+ else
+ os_free(errors.buf);
+ return -1;
+ }
+}
+
+
+void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ xmlFreeNode((xmlNodePtr) node);
+}
+
+
+xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ return (xml_node_t *) ((xmlNodePtr) node)->parent;
+}
+
+
+xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf)
+{
+ xmlDocPtr doc;
+ xmlNodePtr node;
+
+ doc = xmlParseMemory(buf, strlen(buf));
+ if (doc == NULL)
+ return NULL;
+ node = xmlDocGetRootElement(doc);
+ node = xmlCopyNode(node, 1);
+ xmlFreeDoc(doc);
+
+ return (xml_node_t *) node;
+}
+
+
+const char * xml_node_get_localname(struct xml_node_ctx *ctx,
+ xml_node_t *node)
+{
+ return (const char *) ((xmlNodePtr) node)->name;
+}
+
+
+char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ xmlChar *buf;
+ int bufsiz;
+ char *ret, *pos;
+ xmlNodePtr n = (xmlNodePtr) node;
+ xmlDocPtr doc;
+
+ doc = xmlNewDoc((xmlChar *) "1.0");
+ n = xmlDocCopyNode(n, doc, 1);
+ xmlDocSetRootElement(doc, n);
+ xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0);
+ xmlFreeDoc(doc);
+ pos = (char *) buf;
+ if (strncmp(pos, "<?xml", 5) == 0) {
+ pos = strchr(pos, '>');
+ if (pos)
+ pos++;
+ while (pos && (*pos == '\r' || *pos == '\n'))
+ pos++;
+ }
+ if (pos)
+ ret = os_strdup(pos);
+ else
+ ret = NULL;
+ xmlFree(buf);
+
+ if (ret) {
+ pos = ret;
+ if (pos[0]) {
+ while (pos[1])
+ pos++;
+ }
+ while (pos >= ret && *pos == '\n')
+ *pos-- = '\0';
+ }
+
+ return ret;
+}
+
+
+void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ xmlUnlinkNode((xmlNodePtr) node);
+}
+
+
+void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent,
+ xml_node_t *child)
+{
+ xmlAddChild((xmlNodePtr) parent, (xmlNodePtr) child);
+}
+
+
+xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri,
+ const char *ns_prefix,
+ xml_namespace_t **ret_ns, const char *name)
+{
+ xmlNodePtr node;
+ xmlNsPtr ns = NULL;
+
+ node = xmlNewNode(NULL, (const xmlChar *) name);
+ if (node == NULL)
+ return NULL;
+ if (ns_uri) {
+ ns = xmlNewNs(node, (const xmlChar *) ns_uri,
+ (const xmlChar *) ns_prefix);
+ xmlSetNs(node, ns);
+ }
+
+ if (ret_ns)
+ *ret_ns = (xml_namespace_t *) ns;
+
+ return (xml_node_t *) node;
+}
+
+
+xml_node_t * xml_node_create(struct xml_node_ctx *ctx, xml_node_t *parent,
+ xml_namespace_t *ns, const char *name)
+{
+ xmlNodePtr node;
+ node = xmlNewChild((xmlNodePtr) parent, (xmlNsPtr) ns,
+ (const xmlChar *) name, NULL);
+ return (xml_node_t *) node;
+}
+
+
+xml_node_t * xml_node_create_text(struct xml_node_ctx *ctx,
+ xml_node_t *parent, xml_namespace_t *ns,
+ const char *name, const char *value)
+{
+ xmlNodePtr node;
+ node = xmlNewTextChild((xmlNodePtr) parent, (xmlNsPtr) ns,
+ (const xmlChar *) name, (const xmlChar *) value);
+ return (xml_node_t *) node;
+}
+
+
+xml_node_t * xml_node_create_text_ns(struct xml_node_ctx *ctx,
+ xml_node_t *parent, const char *ns_uri,
+ const char *name, const char *value)
+{
+ xmlNodePtr node;
+ xmlNsPtr ns;
+
+ node = xmlNewTextChild((xmlNodePtr) parent, NULL,
+ (const xmlChar *) name, (const xmlChar *) value);
+ ns = xmlNewNs(node, (const xmlChar *) ns_uri, NULL);
+ xmlSetNs(node, ns);
+ return (xml_node_t *) node;
+}
+
+
+void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *value)
+{
+ /* TODO: escape XML special chars in value */
+ xmlNodeSetContent((xmlNodePtr) node, (xmlChar *) value);
+}
+
+
+int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node,
+ xml_namespace_t *ns, const char *name, const char *value)
+{
+ xmlAttrPtr attr;
+
+ if (ns) {
+ attr = xmlNewNsProp((xmlNodePtr) node, (xmlNsPtr) ns,
+ (const xmlChar *) name,
+ (const xmlChar *) value);
+ } else {
+ attr = xmlNewProp((xmlNodePtr) node, (const xmlChar *) name,
+ (const xmlChar *) value);
+ }
+
+ return attr ? 0 : -1;
+}
+
+
+char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
+ char *name)
+{
+ return (char *) xmlGetNoNsProp((xmlNodePtr) node,
+ (const xmlChar *) name);
+}
+
+
+char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node,
+ const char *ns_uri, char *name)
+{
+ return (char *) xmlGetNsProp((xmlNodePtr) node, (const xmlChar *) name,
+ (const xmlChar *) ns_uri);
+}
+
+
+void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val)
+{
+ if (val)
+ xmlFree((xmlChar *) val);
+}
+
+
+xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx,
+ xml_node_t *parent)
+{
+ return (xml_node_t *) ((xmlNodePtr) parent)->children;
+}
+
+
+xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx,
+ xml_node_t *node)
+{
+ return (xml_node_t *) ((xmlNodePtr) node)->next;
+}
+
+
+int xml_node_is_element(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ return ((xmlNodePtr) node)->type == XML_ELEMENT_NODE;
+}
+
+
+char * xml_node_get_text(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ if (xmlChildElementCount((xmlNodePtr) node) > 0)
+ return NULL;
+ return (char *) xmlNodeGetContent((xmlNodePtr) node);
+}
+
+
+void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val)
+{
+ if (val)
+ xmlFree((xmlChar *) val);
+}
+
+
+char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node,
+ int *ret_len)
+{
+ char *txt;
+ unsigned char *ret;
+ size_t len;
+
+ txt = xml_node_get_text(ctx, node);
+ if (txt == NULL)
+ return NULL;
+
+ ret = base64_decode((unsigned char *) txt, strlen(txt), &len);
+ if (ret_len)
+ *ret_len = len;
+ xml_node_get_text_free(ctx, txt);
+ if (ret == NULL)
+ return NULL;
+ txt = os_malloc(len + 1);
+ if (txt == NULL) {
+ os_free(ret);
+ return NULL;
+ }
+ os_memcpy(txt, ret, len);
+ txt[len] = '\0';
+ return txt;
+}
+
+
+xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node)
+{
+ if (node == NULL)
+ return NULL;
+ return (xml_node_t *) xmlCopyNode((xmlNodePtr) node, 1);
+}
+
+
+struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx,
+ const void *env)
+{
+ struct xml_node_ctx *xctx;
+
+ xctx = os_zalloc(sizeof(*xctx));
+ if (xctx == NULL)
+ return NULL;
+ xctx->ctx = upper_ctx;
+
+ LIBXML_TEST_VERSION
+
+ return xctx;
+}
+
+
+void xml_node_deinit_ctx(struct xml_node_ctx *ctx)
+{
+ xmlSchemaCleanupTypes();
+ xmlCleanupParser();
+ xmlMemoryDump();
+ os_free(ctx);
+}
diff --git a/contrib/wpa/src/wps/http_client.c b/contrib/wpa/src/wps/http_client.c
index c6d6c7f..0290013 100644
--- a/contrib/wpa/src/wps/http_client.c
+++ b/contrib/wpa/src/wps/http_client.c
@@ -92,7 +92,7 @@ static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
(unsigned long) wpabuf_len(c->req),
(unsigned long) wpabuf_len(c->req) - c->req_pos);
- res = send(c->sd, wpabuf_head(c->req) + c->req_pos,
+ res = send(c->sd, wpabuf_head_u8(c->req) + c->req_pos,
wpabuf_len(c->req) - c->req_pos, 0);
if (res < 0) {
wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
diff --git a/contrib/wpa/src/wps/http_server.c b/contrib/wpa/src/wps/http_server.c
index 6ca3214..ac088c4 100644
--- a/contrib/wpa/src/wps/http_server.c
+++ b/contrib/wpa/src/wps/http_server.c
@@ -232,6 +232,7 @@ struct http_server * http_server_init(struct in_addr *addr, int port,
{
struct sockaddr_in sin;
struct http_server *srv;
+ int on = 1;
srv = os_zalloc(sizeof(*srv));
if (srv == NULL)
@@ -242,6 +243,15 @@ struct http_server * http_server_init(struct in_addr *addr, int port,
srv->fd = socket(AF_INET, SOCK_STREAM, 0);
if (srv->fd < 0)
goto fail;
+
+ if (setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "HTTP: setsockopt(SO_REUSEADDR) failed: %s",
+ strerror(errno));
+ /* try to continue anyway */
+ }
+
if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
goto fail;
if (port < 0)
diff --git a/contrib/wpa/src/wps/httpread.c b/contrib/wpa/src/wps/httpread.c
index ad4f4a1..2f08f37 100644
--- a/contrib/wpa/src/wps/httpread.c
+++ b/contrib/wpa/src/wps/httpread.c
@@ -67,8 +67,6 @@ struct httpread {
int timeout_seconds; /* 0 or total duration timeout period */
/* dynamically used information follows */
- int sd_registered; /* nonzero if we need to unregister socket */
- int to_registered; /* nonzero if we need to unregister timeout */
int got_hdr; /* nonzero when header is finalized */
char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */
@@ -129,19 +127,6 @@ static int word_eq(char *s1, char *s2)
}
-/* convert hex to binary
- * Requires that c have been previously tested true with isxdigit().
- */
-static int hex_value(int c)
-{
- if (isdigit(c))
- return c - '0';
- if (islower(c))
- return 10 + c - 'a';
- return 10 + c - 'A';
-}
-
-
static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
/* httpread_destroy -- if h is non-NULL, clean up
@@ -156,12 +141,8 @@ void httpread_destroy(struct httpread *h)
if (!h)
return;
- if (h->to_registered)
- eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
- h->to_registered = 0;
- if (h->sd_registered)
- eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
- h->sd_registered = 0;
+ eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
+ eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
os_free(h->body);
os_free(h->uri);
os_memset(h, 0, sizeof(*h)); /* aid debugging */
@@ -176,7 +157,6 @@ static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
{
struct httpread *h = user_ctx;
wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
- h->to_registered = 0; /* is self-cancelling */
(*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
}
@@ -295,8 +275,7 @@ static int httpread_hdr_analyze(struct httpread *h)
int c = *rawuri;
if (c == '%' &&
isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
- *uri++ = (hex_value(rawuri[1]) << 4) |
- hex_value(rawuri[2]);
+ *uri++ = hex2byte(rawuri + 1);
rawuri += 3;
} else {
*uri++ = c;
@@ -434,8 +413,8 @@ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
*/
if (httpread_debug >= 10)
wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
- h->got_body = 1;
- goto got_file;
+ h->got_body = 1;
+ goto got_file;
}
rbp = readbuf;
@@ -638,7 +617,6 @@ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
* We do NOT support trailers except to skip them --
* this is supported (generally) by the http spec.
*/
- bbp = h->body + h->body_nbytes;
for (;;) {
int c;
if (nread <= 0)
@@ -703,15 +681,11 @@ got_file:
* and just in case somehow we don't get destroyed right away,
* unregister now.
*/
- if (h->sd_registered)
- eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
- h->sd_registered = 0;
+ eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
/* The application can destroy us whenever they feel like...
* cancel timeout.
*/
- if (h->to_registered)
- eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
- h->to_registered = 0;
+ eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
(*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
}
@@ -749,21 +723,17 @@ struct httpread * httpread_create(
h->max_bytes = max_bytes;
h->timeout_seconds = timeout_seconds;
- if (timeout_seconds > 0) {
- if (eloop_register_timeout(timeout_seconds, 0,
- httpread_timeout_handler,
- NULL, h)) {
- /* No way to recover (from malloc failure) */
- goto fail;
- }
- h->to_registered = 1;
+ if (timeout_seconds > 0 &&
+ eloop_register_timeout(timeout_seconds, 0,
+ httpread_timeout_handler, NULL, h)) {
+ /* No way to recover (from malloc failure) */
+ goto fail;
}
if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
NULL, h)) {
/* No way to recover (from malloc failure) */
goto fail;
}
- h->sd_registered = 1;
return h;
fail:
diff --git a/contrib/wpa/src/wps/ndef.c b/contrib/wpa/src/wps/ndef.c
index a48a2d7..d45dfc8 100644
--- a/contrib/wpa/src/wps/ndef.c
+++ b/contrib/wpa/src/wps/ndef.c
@@ -30,6 +30,7 @@ struct ndef_record {
};
static char wifi_handover_type[] = "application/vnd.wfa.wsc";
+static char p2p_handover_type[] = "application/vnd.wfa.p2p";
static int ndef_parse_record(const u8 *data, u32 size,
struct ndef_record *record)
@@ -147,7 +148,8 @@ static struct wpabuf * ndef_build_record(u8 flags, void *type,
static int wifi_filter(struct ndef_record *record)
{
- if (record->type_length != os_strlen(wifi_handover_type))
+ if (record->type == NULL ||
+ record->type_length != os_strlen(wifi_handover_type))
return 0;
if (os_memcmp(record->type, wifi_handover_type,
os_strlen(wifi_handover_type)) != 0)
@@ -170,76 +172,27 @@ struct wpabuf * ndef_build_wifi(const struct wpabuf *buf)
}
-struct wpabuf * ndef_build_wifi_hr(void)
+static int p2p_filter(struct ndef_record *record)
{
- struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
- struct wpabuf *carrier, *hc;
-
- rn = wpabuf_alloc(2);
- if (rn == NULL)
- return NULL;
- wpabuf_put_be16(rn, os_random() & 0xffff);
-
- cr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "cr", 2,
- NULL, 0, rn);
- wpabuf_free(rn);
-
- if (cr == NULL)
- return NULL;
-
- ac_payload = wpabuf_alloc(4);
- if (ac_payload == NULL) {
- wpabuf_free(cr);
- return NULL;
- }
- wpabuf_put_u8(ac_payload, 0x01); /* Carrier Flags: CRS=1 "active" */
- wpabuf_put_u8(ac_payload, 0x01); /* Carrier Data Reference Length */
- wpabuf_put_u8(ac_payload, '0'); /* Carrier Data Reference: "0" */
- wpabuf_put_u8(ac_payload, 0); /* Aux Data Reference Count */
-
- ac = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "ac", 2,
- NULL, 0, ac_payload);
- wpabuf_free(ac_payload);
- if (ac == NULL) {
- wpabuf_free(cr);
- return NULL;
- }
-
- hr_payload = wpabuf_alloc(1 + wpabuf_len(cr) + wpabuf_len(ac));
- if (hr_payload == NULL) {
- wpabuf_free(cr);
- wpabuf_free(ac);
- return NULL;
- }
+ if (record->type == NULL ||
+ record->type_length != os_strlen(p2p_handover_type))
+ return 0;
+ if (os_memcmp(record->type, p2p_handover_type,
+ os_strlen(p2p_handover_type)) != 0)
+ return 0;
+ return 1;
+}
- wpabuf_put_u8(hr_payload, 0x12); /* Connection Handover Version 1.2 */
- wpabuf_put_buf(hr_payload, cr);
- wpabuf_put_buf(hr_payload, ac);
- wpabuf_free(cr);
- wpabuf_free(ac);
- hr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "Hr", 2,
- NULL, 0, hr_payload);
- wpabuf_free(hr_payload);
- if (hr == NULL)
- return NULL;
+struct wpabuf * ndef_parse_p2p(const struct wpabuf *buf)
+{
+ return ndef_parse_records(buf, p2p_filter);
+}
- carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
- if (carrier == NULL) {
- wpabuf_free(hr);
- return NULL;
- }
- wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
- wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
- wpabuf_put_str(carrier, wifi_handover_type);
-
- hc = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
- "0", 1, carrier);
- wpabuf_free(carrier);
- if (hc == NULL) {
- wpabuf_free(hr);
- return NULL;
- }
- return wpabuf_concat(hr, hc);
+struct wpabuf * ndef_build_p2p(const struct wpabuf *buf)
+{
+ return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
+ FLAG_TNF_RFC2046, p2p_handover_type,
+ os_strlen(p2p_handover_type), NULL, 0, buf);
}
diff --git a/contrib/wpa/src/wps/wps.c b/contrib/wpa/src/wps/wps.c
index 2575705..2c68be8 100644
--- a/contrib/wpa/src/wps/wps.c
+++ b/contrib/wpa/src/wps/wps.c
@@ -18,6 +18,7 @@
#ifdef CONFIG_WPS_TESTING
int wps_version_number = 0x20;
int wps_testing_dummy_cred = 0;
+int wps_corrupt_pkhash = 0;
#endif /* CONFIG_WPS_TESTING */
@@ -53,12 +54,22 @@ struct wps_data * wps_init(const struct wps_config *cfg)
}
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);
}
#ifdef CONFIG_WPS_NFC
+ if (cfg->pin == NULL &&
+ cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
+ data->dev_pw_id = cfg->dev_pw_id;
+
if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+ /* Keep AP PIN as alternative Device Password */
+ data->alt_dev_pw_id = data->dev_pw_id;
+ data->alt_dev_password = data->dev_password;
+ data->alt_dev_password_len = data->dev_password_len;
+
data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
- os_free(data->dev_password);
data->dev_password =
os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
if (data->dev_password == NULL) {
@@ -69,6 +80,8 @@ struct wps_data * wps_init(const struct wps_config *cfg)
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);
}
#endif /* CONFIG_WPS_NFC */
@@ -76,7 +89,7 @@ struct wps_data * wps_init(const struct wps_config *cfg)
if (cfg->pbc) {
/* Use special PIN '00000000' for PBC */
data->dev_pw_id = DEV_PW_PUSHBUTTON;
- os_free(data->dev_password);
+ bin_clear_free(data->dev_password, data->dev_password_len);
data->dev_password = (u8 *) os_strdup("00000000");
if (data->dev_password == NULL) {
os_free(data);
@@ -109,7 +122,8 @@ struct wps_data * wps_init(const struct wps_config *cfg)
data->new_ap_settings =
os_malloc(sizeof(*data->new_ap_settings));
if (data->new_ap_settings == NULL) {
- os_free(data->dev_password);
+ bin_clear_free(data->dev_password,
+ data->dev_password_len);
os_free(data);
return NULL;
}
@@ -125,6 +139,12 @@ struct wps_data * wps_init(const struct wps_config *cfg)
data->use_psk_key = cfg->use_psk_key;
data->pbc_in_m1 = cfg->pbc_in_m1;
+ if (cfg->peer_pubkey_hash) {
+ os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN);
+ data->peer_pubkey_hash_set = 1;
+ }
+
return data;
}
@@ -154,12 +174,12 @@ void wps_deinit(struct wps_data *data)
wpabuf_free(data->dh_pubkey_e);
wpabuf_free(data->dh_pubkey_r);
wpabuf_free(data->last_msg);
- os_free(data->dev_password);
- os_free(data->new_psk);
+ bin_clear_free(data->dev_password, data->dev_password_len);
+ bin_clear_free(data->alt_dev_password, data->alt_dev_password_len);
+ bin_clear_free(data->new_psk, data->new_psk_len);
wps_device_data_free(&data->peer_dev);
- os_free(data->new_ap_settings);
+ bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings));
dh5_free(data->dh_ctx);
- os_free(data->nfc_pw_token);
os_free(data);
}
@@ -488,17 +508,15 @@ struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
wps_build_config_methods(ie, dev->config_methods) ||
wps_build_uuid_e(ie, uuid) ||
wps_build_primary_dev_type(dev, ie) ||
- wps_build_rf_bands(dev, ie) ||
+ wps_build_rf_bands(dev, ie, 0) ||
wps_build_assoc_state(NULL, ie) ||
wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
wps_build_dev_password_id(ie, pw_id) ||
-#ifdef CONFIG_WPS2
wps_build_manufacturer(dev, ie) ||
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) ||
-#endif /* CONFIG_WPS2 */
wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
||
wps_build_secondary_dev_type(dev, ie)
@@ -507,13 +525,6 @@ struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
return NULL;
}
-#ifndef CONFIG_WPS2
- if (dev->p2p && wps_build_dev_name(dev, ie)) {
- wpabuf_free(ie);
- return NULL;
- }
-#endif /* CONFIG_WPS2 */
-
return wps_ie_encapsulate(ie);
}
@@ -549,7 +560,7 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
"wps_state=configured\n");
else
ret = 0;
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -557,7 +568,7 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
if (attr.ap_setup_locked && *attr.ap_setup_locked) {
ret = os_snprintf(pos, end - pos,
"wps_ap_setup_locked=1\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -565,7 +576,7 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
if (attr.selected_registrar && *attr.selected_registrar) {
ret = os_snprintf(pos, end - pos,
"wps_selected_registrar=1\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -574,7 +585,7 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
ret = os_snprintf(pos, end - pos,
"wps_device_password_id=%u\n",
WPA_GET_BE16(attr.dev_password_id));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -584,7 +595,7 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
"wps_selected_registrar_config_methods="
"0x%04x\n",
WPA_GET_BE16(attr.sel_reg_config_methods));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -596,7 +607,7 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
wps_dev_type_bin2str(attr.primary_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -615,7 +626,7 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
str[i] = '\0';
ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
os_free(str);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -624,10 +635,27 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
ret = os_snprintf(pos, end - pos,
"wps_config_methods=0x%04x\n",
WPA_GET_BE16(attr.config_methods));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
return pos - buf;
}
+
+
+const char * wps_ei_str(enum wps_error_indication ei)
+{
+ switch (ei) {
+ case WPS_EI_NO_ERROR:
+ return "No Error";
+ case WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED:
+ return "TKIP Only Prohibited";
+ case WPS_EI_SECURITY_WEP_PROHIBITED:
+ return "WEP Prohibited";
+ case WPS_EI_AUTH_FAILURE:
+ return "Authentication Failure";
+ default:
+ return "Unknown";
+ }
+}
diff --git a/contrib/wpa/src/wps/wps.h b/contrib/wpa/src/wps/wps.h
index c6b7099..0a7f65d 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -42,7 +42,6 @@ struct wps_parse_attr;
* @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
* this may be %NULL, if not used
* @cred_attr_len: Length of cred_attr in octets
- * @ap_channel: AP channel
*/
struct wps_credential {
u8 ssid[32];
@@ -55,7 +54,6 @@ struct wps_credential {
u8 mac_addr[ETH_ALEN];
const u8 *cred_attr;
size_t cred_attr_len;
- u16 ap_channel;
};
#define WPS_DEV_TYPE_LEN 8
@@ -183,6 +181,11 @@ struct wps_config {
* PBC with the AP.
*/
int pbc_in_m1;
+
+ /**
+ * peer_pubkey_hash - Peer public key hash or %NULL if not known
+ */
+ const u8 *peer_pubkey_hash;
};
struct wps_data * wps_init(const struct wps_config *cfg);
@@ -246,14 +249,15 @@ struct wps_registrar_config {
* new_psk_cb - Callback for new PSK
* @ctx: Higher layer context data (cb_ctx)
* @mac_addr: MAC address of the Enrollee
+ * @p2p_dev_addr: P2P Device Address of the Enrollee or all zeros if not
* @psk: The new PSK
* @psk_len: The length of psk in octets
* Returns: 0 on success, -1 on failure
*
* This callback is called when a new per-device PSK is provisioned.
*/
- int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
- size_t psk_len);
+ int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr,
+ const u8 *psk, size_t psk_len);
/**
* set_ie_cb - Callback for WPS IE changes
@@ -382,6 +386,14 @@ struct wps_registrar_config {
* dualband - Whether this is a concurrent dualband AP
*/
int dualband;
+
+ /**
+ * force_per_enrollee_psk - Force per-Enrollee random PSK
+ *
+ * This forces per-Enrollee random PSK to be generated even if a default
+ * PSK is set for a network.
+ */
+ int force_per_enrollee_psk;
};
@@ -420,6 +432,16 @@ enum wps_event {
WPS_EV_PBC_TIMEOUT,
/**
+ * WPS_EV_PBC_ACTIVE - PBC mode was activated
+ */
+ WPS_EV_PBC_ACTIVE,
+
+ /**
+ * WPS_EV_PBC_DISABLE - PBC mode was disabled
+ */
+ WPS_EV_PBC_DISABLE,
+
+ /**
* WPS_EV_ER_AP_ADD - ER: AP added
*/
WPS_EV_ER_AP_ADD,
@@ -487,11 +509,17 @@ union wps_event_data {
int msg;
u16 config_error;
u16 error_indication;
+ u8 peer_macaddr[ETH_ALEN];
} fail;
+ struct wps_event_success {
+ u8 peer_macaddr[ETH_ALEN];
+ } success;
+
struct wps_event_pwd_auth_fail {
int enrollee;
int part;
+ u8 peer_macaddr[ETH_ALEN];
} pwd_auth_fail;
struct wps_event_er_ap {
@@ -640,6 +668,16 @@ struct wps_context {
u16 auth_types;
/**
+ * encr_types - Current AP encryption type (WPS_ENCR_*)
+ */
+ u16 ap_encr_type;
+
+ /**
+ * ap_auth_type - Current AP authentication types (WPS_AUTH_*)
+ */
+ u16 ap_auth_type;
+
+ /**
* network_key - The current Network Key (PSK) or %NULL to generate new
*
* If %NULL, Registrar will generate per-device PSK. In addition, AP
@@ -730,6 +768,13 @@ struct wps_context {
union wps_event_data *data);
/**
+ * rf_band_cb - Fetch currently used RF band
+ * @ctx: Higher layer context data (cb_ctx)
+ * Return: Current used RF band or 0 if not known
+ */
+ int (*rf_band_cb)(void *ctx);
+
+ /**
* cb_ctx: Higher layer context data for callbacks
*/
void *cb_ctx;
@@ -769,10 +814,12 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
struct wps_credential *cred);
int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
const u8 *pubkey_hash, u16 pw_id,
- const u8 *dev_pw, size_t dev_pw_len);
+ const u8 *dev_pw, size_t dev_pw_len,
+ int pk_hash_provided_oob);
int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
const u8 *oob_dev_pw,
size_t oob_dev_pw_len);
+void wps_registrar_flush(struct wps_registrar *reg);
int wps_build_credential_wrap(struct wpabuf *msg,
const struct wps_credential *cred);
@@ -783,9 +830,11 @@ unsigned int wps_generate_pin(void);
int wps_pin_str_valid(const char *pin);
void wps_free_pending_msgs(struct upnp_pending_message *msgs);
-struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
+ int channel);
int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
int wps_attr_text(struct wpabuf *data, char *buf, char *end);
+const char * wps_ei_str(enum wps_error_indication ei);
struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname,
const char *filter);
@@ -793,14 +842,22 @@ void wps_er_refresh(struct wps_er *er);
void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx);
void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
u16 sel_reg_config_methods);
-int wps_er_pbc(struct wps_er *er, const u8 *uuid);
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len);
-int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr);
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr);
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len);
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
const struct wps_credential *cred);
-int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len, const struct wps_credential *cred);
-struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid);
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len,
+ const struct wps_credential *cred);
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+ struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+ const u8 *addr);
+struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
+ struct wps_context *wps, const u8 *uuid,
+ const u8 *addr, struct wpabuf *pubkey);
int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
@@ -810,14 +867,29 @@ u16 wps_config_methods_str2bin(const char *str);
struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
const struct wpabuf *pubkey,
const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+ struct wpabuf *dev_pw);
+int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey);
struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
struct wpabuf **privkey,
struct wpabuf **dev_pw);
+struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
+ struct wpabuf *nfc_dh_pubkey);
+struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
+ struct wpabuf *nfc_dh_pubkey,
+ const u8 *bssid, int freq);
+struct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx,
+ struct wpabuf *nfc_dh_pubkey);
+struct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx,
+ int nfc_dev_pw_id,
+ struct wpabuf *nfc_dh_pubkey,
+ struct wpabuf *nfc_dev_pw);
/* ndef.c */
struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
-struct wpabuf * ndef_build_wifi_hr(void);
+struct wpabuf * ndef_parse_p2p(const struct wpabuf *buf);
+struct wpabuf * ndef_build_p2p(const struct wpabuf *buf);
#ifdef CONFIG_WPS_STRICT
int wps_validate_beacon(const struct wpabuf *wps_ie);
diff --git a/contrib/wpa/src/wps/wps_attr_build.c b/contrib/wpa/src/wps/wps_attr_build.c
index 29aee8e..b689357 100644
--- a/contrib/wpa/src/wps/wps_attr_build.c
+++ b/contrib/wpa/src/wps/wps_attr_build.c
@@ -24,23 +24,46 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
wpa_printf(MSG_DEBUG, "WPS: * Public Key");
wpabuf_free(wps->dh_privkey);
- if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
+ wps->dh_privkey = NULL;
+ if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
+ wps->wps->dh_ctx) {
wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
+ if (wps->wps->dh_pubkey == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: wps->wps->dh_pubkey == NULL");
+ return -1;
+ }
wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
wps->dh_ctx = wps->wps->dh_ctx;
wps->wps->dh_ctx = NULL;
pubkey = wpabuf_dup(wps->wps->dh_pubkey);
#ifdef CONFIG_WPS_NFC
- } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
- wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
+ } else if ((wps->dev_pw_id >= 0x10 ||
+ wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) &&
+ (wps->wps->ap ||
+ (wps->wps->ap_nfc_dh_pubkey &&
+ wps->wps->ap_nfc_dev_pw_id ==
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)) &&
+ (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id ||
+ wps->wps->ap_nfc_dh_pubkey)) {
wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+ if (wps->wps->ap_nfc_dh_privkey == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: wps->wps->ap_nfc_dh_privkey == NULL");
+ return -1;
+ }
+ if (wps->wps->ap_nfc_dh_pubkey == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: wps->wps->ap_nfc_dh_pubkey == NULL");
+ return -1;
+ }
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);
#endif /* CONFIG_WPS_NFC */
} else {
wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
- wps->dh_privkey = NULL;
dh5_free(wps->dh_ctx);
wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
pubkey = wpabuf_zeropad(pubkey, 192);
@@ -102,6 +125,8 @@ int wps_build_config_methods(struct wpabuf *msg, u16 methods)
int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
{
+ if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * UUID-E");
wpabuf_put_be16(msg, ATTR_UUID_E);
wpabuf_put_be16(msg, WPS_UUID_LEN);
@@ -167,6 +192,8 @@ int wps_build_version(struct wpabuf *msg)
* backwards compatibility reasons. The real version negotiation is
* done with Version2.
*/
+ if (wpabuf_tailroom(msg) < 5)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)");
wpabuf_put_be16(msg, ATTR_VERSION);
wpabuf_put_be16(msg, 1);
@@ -178,9 +205,17 @@ 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)
{
-#ifdef CONFIG_WPS2
u8 *len;
+#ifdef CONFIG_WPS_TESTING
+ if (WPS_VERSION == 0x10)
+ return 0;
+#endif /* CONFIG_WPS_TESTING */
+
+ if (wpabuf_tailroom(msg) <
+ 7 + 3 + (req_to_enroll ? 3 : 0) +
+ (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0))
+ return -1;
wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
len = wpabuf_put(msg, 2); /* to be filled */
wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
@@ -210,10 +245,11 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
}
WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
-#endif /* CONFIG_WPS2 */
#ifdef CONFIG_WPS_TESTING
if (WPS_VERSION > 0x20) {
+ if (wpabuf_tailroom(msg) < 5)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra "
"attribute");
wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
@@ -258,9 +294,10 @@ int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
{
u16 auth_types = WPS_AUTH_TYPES;
-#ifdef CONFIG_WPS2
+ /* WPA/WPA2-Enterprise enrollment not supported through WPS */
+ auth_types &= ~WPS_AUTH_WPA;
+ auth_types &= ~WPS_AUTH_WPA2;
auth_types &= ~WPS_AUTH_SHARED;
-#endif /* CONFIG_WPS2 */
wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags");
wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
wpabuf_put_be16(msg, 2);
@@ -272,9 +309,7 @@ int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
{
u16 encr_types = WPS_ENCR_TYPES;
-#ifdef CONFIG_WPS2
encr_types &= ~WPS_ENCR_WEP;
-#endif /* CONFIG_WPS2 */
wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags");
wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
wpabuf_put_be16(msg, 2);
@@ -356,15 +391,31 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
const u8 *addr[1];
u8 pubkey_hash[WPS_HASH_LEN];
+ wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password (dev_pw_id=%u)",
+ dev_pw_id);
addr[0] = wpabuf_head(pubkey);
hash_len = wpabuf_len(pubkey);
sha256_vector(1, addr, &hash_len, pubkey_hash);
+#ifdef CONFIG_WPS_TESTING
+ if (wps_corrupt_pkhash) {
+ wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
+ pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_printf(MSG_INFO, "WPS: Testing - corrupt public key hash");
+ pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN - 2]++;
+ }
+#endif /* CONFIG_WPS_TESTING */
wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
+ wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
+ pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
wpabuf_put_be16(msg, dev_pw_id);
- wpabuf_put_data(msg, dev_pw, dev_pw_len);
+ if (dev_pw) {
+ wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
+ dev_pw, dev_pw_len);
+ wpabuf_put_data(msg, dev_pw, dev_pw_len);
+ }
return 0;
}
@@ -401,3 +452,34 @@ struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
return ie;
}
+
+
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr)
+{
+ wpa_printf(MSG_DEBUG, "WPS: * MAC Address (" MACSTR ")",
+ MAC2STR(addr));
+ wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+ wpabuf_put_be16(msg, ETH_ALEN);
+ wpabuf_put_data(msg, addr, ETH_ALEN);
+ return 0;
+}
+
+
+int wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands)
+{
+ wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", rf_bands);
+ wpabuf_put_be16(msg, ATTR_RF_BANDS);
+ wpabuf_put_be16(msg, 1);
+ wpabuf_put_u8(msg, rf_bands);
+ return 0;
+}
+
+
+int wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel)
+{
+ wpa_printf(MSG_DEBUG, "WPS: * AP Channel (%u)", ap_channel);
+ wpabuf_put_be16(msg, ATTR_AP_CHANNEL);
+ wpabuf_put_be16(msg, 2);
+ wpabuf_put_be16(msg, ap_channel);
+ return 0;
+}
diff --git a/contrib/wpa/src/wps/wps_attr_parse.c b/contrib/wpa/src/wps/wps_attr_parse.c
index 3999b1b8..40bc1ad 100644
--- a/contrib/wpa/src/wps/wps_attr_parse.c
+++ b/contrib/wpa/src/wps/wps_attr_parse.c
@@ -59,6 +59,14 @@ static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
}
attr->settings_delay_time = pos;
break;
+ case WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS:
+ if (len != 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Configuration Methods length %u",
+ len);
+ return -1;
+ }
+ attr->registrar_configuration_methods = pos;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
"Extension subelement %u", id);
@@ -75,7 +83,7 @@ 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 (pos + 2 <= end) {
id = *pos++;
elen = *pos++;
if (pos + elen > end)
@@ -263,10 +271,13 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
attr->dev_password_id = pos;
break;
case ATTR_OOB_DEVICE_PASSWORD:
- if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
- WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+ if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
- WPS_OOB_DEVICE_PASSWORD_LEN) {
+ WPS_OOB_DEVICE_PASSWORD_LEN ||
+ (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_MIN_LEN &&
+ WPA_GET_BE16(pos + WPS_OOB_PUBKEY_HASH_LEN) !=
+ DEV_PW_NFC_CONNECTION_HANDOVER)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
"Password length %u", len);
return -1;
@@ -410,22 +421,6 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
}
attr->mac_addr = pos;
break;
- case ATTR_KEY_PROVIDED_AUTO:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
- "Automatically length %u", len);
- return -1;
- }
- attr->key_prov_auto = pos;
- break;
- case ATTR_802_1X_ENABLED:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
- "length %u", len);
- return -1;
- }
- attr->dot1x_enabled = pos;
- break;
case ATTR_SELECTED_REGISTRAR:
if (len != 1) {
wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
@@ -497,14 +492,6 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
attr->network_key = pos;
attr->network_key_len = len;
break;
- case ATTR_EAP_TYPE:
- attr->eap_type = pos;
- attr->eap_type_len = len;
- break;
- case ATTR_EAP_IDENTITY:
- attr->eap_identity = pos;
- attr->eap_identity_len = len;
- break;
case ATTR_AP_SETUP_LOCKED:
if (len != 1) {
wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
diff --git a/contrib/wpa/src/wps/wps_attr_parse.h b/contrib/wpa/src/wps/wps_attr_parse.h
index 88e51a4..82c4739 100644
--- a/contrib/wpa/src/wps/wps_attr_parse.h
+++ b/contrib/wpa/src/wps/wps_attr_parse.h
@@ -47,8 +47,6 @@ struct wps_parse_attr {
const u8 *network_idx; /* 1 octet */
const u8 *network_key_idx; /* 1 octet */
const u8 *mac_addr; /* ETH_ALEN (6) octets */
- const u8 *key_prov_auto; /* 1 octet (Bool) */
- const u8 *dot1x_enabled; /* 1 octet (Bool) */
const u8 *selected_registrar; /* 1 octet (Bool) */
const u8 *request_type; /* 1 octet */
const u8 *response_type; /* 1 octet */
@@ -57,6 +55,7 @@ struct wps_parse_attr {
const u8 *network_key_shareable; /* 1 octet (Bool) */
const u8 *request_to_enroll; /* 1 octet (Bool) */
const u8 *ap_channel; /* 2 octets */
+ const u8 *registrar_configuration_methods; /* 2 octets */
/* variable length fields */
const u8 *manufacturer;
@@ -77,10 +76,6 @@ struct wps_parse_attr {
size_t ssid_len;
const u8 *network_key; /* <= 64 octets */
size_t network_key_len;
- const u8 *eap_type; /* <= 8 octets */
- size_t eap_type_len;
- const u8 *eap_identity; /* <= 64 octets */
- size_t eap_identity_len;
const u8 *authorized_macs; /* <= 30 octets */
size_t authorized_macs_len;
const u8 *sec_dev_type_list; /* <= 128 octets */
diff --git a/contrib/wpa/src/wps/wps_attr_process.c b/contrib/wpa/src/wps/wps_attr_process.c
index b81f106..eadb22f 100644
--- a/contrib/wpa/src/wps/wps_attr_process.c
+++ b/contrib/wpa/src/wps/wps_attr_process.c
@@ -41,7 +41,7 @@ int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
- if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+ if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
return -1;
}
@@ -71,7 +71,7 @@ int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
}
hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
- if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+ if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
return -1;
}
@@ -207,70 +207,6 @@ static int wps_process_cred_mac_addr(struct wps_credential *cred,
}
-static int wps_process_cred_eap_type(struct wps_credential *cred,
- const u8 *eap_type, size_t eap_type_len)
-{
- if (eap_type == NULL)
- return 0; /* optional attribute */
-
- wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
-
- return 0;
-}
-
-
-static int wps_process_cred_eap_identity(struct wps_credential *cred,
- const u8 *identity,
- size_t identity_len)
-{
- if (identity == NULL)
- return 0; /* optional attribute */
-
- wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
- identity, identity_len);
-
- return 0;
-}
-
-
-static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
- const u8 *key_prov_auto)
-{
- if (key_prov_auto == NULL)
- return 0; /* optional attribute */
-
- wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
- *key_prov_auto);
-
- return 0;
-}
-
-
-static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
- const u8 *dot1x_enabled)
-{
- if (dot1x_enabled == NULL)
- return 0; /* optional attribute */
-
- wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
-
- return 0;
-}
-
-
-static int wps_process_cred_ap_channel(struct wps_credential *cred,
- const u8 *ap_channel)
-{
- if (ap_channel == NULL)
- return 0; /* optional attribute */
-
- cred->ap_channel = WPA_GET_BE16(ap_channel);
- wpa_printf(MSG_DEBUG, "WPS: AP Channel: %u", cred->ap_channel);
-
- return 0;
-}
-
-
static int wps_workaround_cred_key(struct wps_credential *cred)
{
if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
@@ -310,14 +246,7 @@ int wps_process_cred(struct wps_parse_attr *attr,
wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
wps_process_cred_network_key(cred, attr->network_key,
attr->network_key_len) ||
- wps_process_cred_mac_addr(cred, attr->mac_addr) ||
- wps_process_cred_eap_type(cred, attr->eap_type,
- attr->eap_type_len) ||
- wps_process_cred_eap_identity(cred, attr->eap_identity,
- attr->eap_identity_len) ||
- wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
- wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled) ||
- wps_process_cred_ap_channel(cred, attr->ap_channel))
+ wps_process_cred_mac_addr(cred, attr->mac_addr))
return -1;
return wps_workaround_cred_key(cred);
diff --git a/contrib/wpa/src/wps/wps_common.c b/contrib/wpa/src/wps/wps_common.c
index 68d9f0a..c1ede6a 100644
--- a/contrib/wpa/src/wps/wps_common.c
+++ b/contrib/wpa/src/wps/wps_common.c
@@ -9,6 +9,8 @@
#include "includes.h"
#include "common.h"
+#include "common/defs.h"
+#include "common/ieee802_11_common.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "crypto/dh_group5.h"
@@ -16,6 +18,7 @@
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "wps_i.h"
+#include "wps_dev_attr.h"
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
@@ -266,7 +269,7 @@ int wps_pin_str_valid(const char *pin)
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
- u16 config_error, u16 error_indication)
+ u16 config_error, u16 error_indication, const u8 *mac_addr)
{
union wps_event_data data;
@@ -277,20 +280,26 @@ void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
data.fail.msg = msg;
data.fail.config_error = config_error;
data.fail.error_indication = error_indication;
+ os_memcpy(data.fail.peer_macaddr, mac_addr, ETH_ALEN);
wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
}
-void wps_success_event(struct wps_context *wps)
+void wps_success_event(struct wps_context *wps, const u8 *mac_addr)
{
+ union wps_event_data data;
+
if (wps->event_cb == NULL)
return;
- wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.success.peer_macaddr, mac_addr, ETH_ALEN);
+ wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, &data);
}
-void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part,
+ const u8 *mac_addr)
{
union wps_event_data data;
@@ -300,6 +309,7 @@ void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
os_memset(&data, 0, sizeof(data));
data.pwd_auth_fail.enrollee = enrollee;
data.pwd_auth_fail.part = part;
+ os_memcpy(data.pwd_auth_fail.peer_macaddr, mac_addr, ETH_ALEN);
wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
}
@@ -322,9 +332,28 @@ void wps_pbc_timeout_event(struct wps_context *wps)
}
+void wps_pbc_active_event(struct wps_context *wps)
+{
+ if (wps->event_cb == NULL)
+ return;
+
+ wps->event_cb(wps->cb_ctx, WPS_EV_PBC_ACTIVE, NULL);
+}
+
+
+void wps_pbc_disable_event(struct wps_context *wps)
+{
+ if (wps->event_cb == NULL)
+ return;
+
+ wps->event_cb(wps->cb_ctx, WPS_EV_PBC_DISABLE, NULL);
+}
+
+
#ifdef CONFIG_WPS_OOB
-struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
+ int channel)
{
struct wps_data data;
struct wpabuf *plain;
@@ -340,13 +369,41 @@ struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
data.wps = wps;
data.auth_type = wps->auth_types;
data.encr_type = wps->encr_types;
- if (wps_build_version(plain) ||
- wps_build_cred(&data, plain) ||
+ if (wps_build_cred(&data, plain) ||
+ (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)) {
+ os_free(data.new_psk);
wpabuf_free(plain);
return NULL;
}
+ if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk &&
+ wps->ap) {
+ struct wps_credential cred;
+
+ wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
+ "on credential token generation");
+
+ os_memset(&cred, 0, sizeof(cred));
+ os_memcpy(cred.ssid, wps->ssid, wps->ssid_len);
+ cred.ssid_len = wps->ssid_len;
+ cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
+ cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
+ os_memcpy(cred.key, data.new_psk, data.new_psk_len);
+ cred.key_len = data.new_psk_len;
+
+ wps->wps_state = WPS_STATE_CONFIGURED;
+ wpa_hexdump_ascii_key(MSG_DEBUG,
+ "WPS: Generated random passphrase",
+ data.new_psk, data.new_psk_len);
+ if (wps->cred_cb)
+ wps->cred_cb(wps->cb_ctx, &cred);
+ }
+
+ os_free(data.new_psk);
+
return plain;
}
@@ -361,8 +418,7 @@ struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
if (data == NULL)
return NULL;
- if (wps_build_version(data) ||
- wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
+ 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)) {
wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
@@ -433,7 +489,7 @@ char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
WPA_GET_BE16(&dev_type[6]));
- if (ret < 0 || (unsigned int) ret >= buf_len)
+ if (os_snprintf_error(buf_len, ret))
return NULL;
return buf;
@@ -475,12 +531,13 @@ u16 wps_config_methods_str2bin(const char *str)
if (str == NULL) {
/* Default to enabling methods based on build configuration */
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS2
methods |= WPS_CONFIG_VIRT_DISPLAY;
-#endif /* CONFIG_WPS2 */
#ifdef CONFIG_WPS_NFC
methods |= WPS_CONFIG_NFC_INTERFACE;
#endif /* CONFIG_WPS_NFC */
+#ifdef CONFIG_P2P
+ methods |= WPS_CONFIG_P2PS;
+#endif /* CONFIG_P2P */
} else {
if (os_strstr(str, "ethernet"))
methods |= WPS_CONFIG_ETHERNET;
@@ -498,7 +555,6 @@ u16 wps_config_methods_str2bin(const char *str)
methods |= WPS_CONFIG_PUSHBUTTON;
if (os_strstr(str, "keypad"))
methods |= WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS2
if (os_strstr(str, "virtual_display"))
methods |= WPS_CONFIG_VIRT_DISPLAY;
if (os_strstr(str, "physical_display"))
@@ -507,7 +563,8 @@ u16 wps_config_methods_str2bin(const char *str)
methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
if (os_strstr(str, "physical_push_button"))
methods |= WPS_CONFIG_PHY_PUSHBUTTON;
-#endif /* CONFIG_WPS2 */
+ if (os_strstr(str, "p2ps"))
+ methods |= WPS_CONFIG_P2PS;
}
return methods;
@@ -562,12 +619,59 @@ struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+ struct wpabuf *dev_pw)
+{
+ struct wpabuf *ret;
+
+ if (pubkey == NULL || dev_pw == NULL)
+ return NULL;
+
+ ret = wps_build_nfc_pw_token(id, pubkey, dev_pw);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey)
+{
+ struct wpabuf *priv = NULL, *pub = NULL;
+ void *dh_ctx;
+
+ dh_ctx = dh5_init(&priv, &pub);
+ if (dh_ctx == NULL)
+ return -1;
+ pub = wpabuf_zeropad(pub, 192);
+ if (pub == NULL) {
+ wpabuf_free(priv);
+ return -1;
+ }
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub);
+ dh5_free(dh_ctx);
+
+ wpabuf_free(*pubkey);
+ *pubkey = pub;
+ wpabuf_free(*privkey);
+ *privkey = priv;
+
+ return 0;
+}
+
+
struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
struct wpabuf **privkey,
struct wpabuf **dev_pw)
{
- struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
- void *dh_ctx;
+ struct wpabuf *pw;
u16 val;
pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
@@ -581,31 +685,223 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
return NULL;
}
- dh_ctx = dh5_init(&priv, &pub);
- if (dh_ctx == NULL) {
+ if (wps_nfc_gen_dh(pubkey, privkey) < 0) {
wpabuf_free(pw);
return NULL;
}
- dh5_free(dh_ctx);
*id = 0x10 + val % 0xfff0;
- wpabuf_free(*pubkey);
- *pubkey = pub;
- wpabuf_free(*privkey);
- *privkey = priv;
wpabuf_free(*dev_pw);
*dev_pw = pw;
- ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
- if (ndef && ret) {
- struct wpabuf *tmp;
- tmp = ndef_build_wifi(ret);
- wpabuf_free(ret);
- if (tmp == NULL)
- return NULL;
- ret = tmp;
+ return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
+}
+
+
+struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
+ struct wpabuf *nfc_dh_pubkey)
+{
+ struct wpabuf *msg;
+ void *len;
+
+ if (ctx == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+ "handover request");
+
+ if (nfc_dh_pubkey == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+ "configured");
+ return NULL;
}
- return ret;
+ msg = wpabuf_alloc(1000);
+ if (msg == NULL)
+ return msg;
+ len = wpabuf_put(msg, 2);
+
+ 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)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
+
+ return msg;
+}
+
+
+static int wps_build_ssid(struct wpabuf *msg, struct wps_context *wps)
+{
+ wpa_printf(MSG_DEBUG, "WPS: * SSID");
+ wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID in Connection Handover Select",
+ wps->ssid, wps->ssid_len);
+ wpabuf_put_be16(msg, ATTR_SSID);
+ wpabuf_put_be16(msg, wps->ssid_len);
+ wpabuf_put_data(msg, wps->ssid, wps->ssid_len);
+ return 0;
+}
+
+
+static int wps_build_ap_freq(struct wpabuf *msg, int freq)
+{
+ enum hostapd_hw_mode mode;
+ u8 channel, rf_band;
+ u16 ap_channel;
+
+ if (freq <= 0)
+ return 0;
+
+ mode = ieee80211_freq_to_chan(freq, &channel);
+ if (mode == NUM_HOSTAPD_MODES)
+ return 0; /* Unknown channel */
+
+ if (mode == HOSTAPD_MODE_IEEE80211G || mode == HOSTAPD_MODE_IEEE80211B)
+ rf_band = WPS_RF_24GHZ;
+ else if (mode == HOSTAPD_MODE_IEEE80211A)
+ rf_band = WPS_RF_50GHZ;
+ else
+ return 0; /* Unknown band */
+ ap_channel = channel;
+
+ if (wps_build_rf_bands_attr(msg, rf_band) ||
+ wps_build_ap_channel(msg, ap_channel))
+ return -1;
+
+ return 0;
+}
+
+
+struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
+ struct wpabuf *nfc_dh_pubkey,
+ const u8 *bssid, int freq)
+{
+ struct wpabuf *msg;
+ void *len;
+
+ if (ctx == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+ "handover select");
+
+ if (nfc_dh_pubkey == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+ "configured");
+ return NULL;
+ }
+
+ msg = wpabuf_alloc(1000);
+ if (msg == NULL)
+ return msg;
+ len = wpabuf_put(msg, 2);
+
+ if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
+ nfc_dh_pubkey, NULL, 0) ||
+ 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)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
+
+ return msg;
}
+
+
+struct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx,
+ struct wpabuf *nfc_dh_pubkey)
+{
+ struct wpabuf *msg;
+
+ if (ctx == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+ "handover request (P2P)");
+
+ if (nfc_dh_pubkey == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No NFC DH Public Key configured");
+ return NULL;
+ }
+
+ msg = wpabuf_alloc(1000);
+ if (msg == NULL)
+ return msg;
+
+ if (wps_build_manufacturer(&ctx->dev, msg) ||
+ wps_build_model_name(&ctx->dev, msg) ||
+ wps_build_model_number(&ctx->dev, msg) ||
+ wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
+ nfc_dh_pubkey, NULL, 0) ||
+ 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)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+struct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx,
+ int nfc_dev_pw_id,
+ struct wpabuf *nfc_dh_pubkey,
+ struct wpabuf *nfc_dev_pw)
+{
+ struct wpabuf *msg;
+ const u8 *dev_pw;
+ size_t dev_pw_len;
+
+ if (ctx == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+ "handover select (P2P)");
+
+ if (nfc_dh_pubkey == NULL ||
+ (nfc_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
+ nfc_dev_pw == NULL)) {
+ wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+ "configured");
+ return NULL;
+ }
+
+ msg = wpabuf_alloc(1000);
+ if (msg == NULL)
+ return msg;
+
+ if (nfc_dev_pw) {
+ dev_pw = wpabuf_head(nfc_dev_pw);
+ dev_pw_len = wpabuf_len(nfc_dev_pw);
+ } else {
+ dev_pw = NULL;
+ dev_pw_len = 0;
+ }
+
+ if (wps_build_manufacturer(&ctx->dev, msg) ||
+ wps_build_model_name(&ctx->dev, msg) ||
+ wps_build_model_number(&ctx->dev, msg) ||
+ wps_build_oob_dev_pw(msg, nfc_dev_pw_id, nfc_dh_pubkey,
+ dev_pw, dev_pw_len) ||
+ 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)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/contrib/wpa/src/wps/wps_defs.h b/contrib/wpa/src/wps/wps_defs.h
index 2f42603..25cd14a 100644
--- a/contrib/wpa/src/wps/wps_defs.h
+++ b/contrib/wpa/src/wps/wps_defs.h
@@ -13,15 +13,12 @@
extern int wps_version_number;
extern int wps_testing_dummy_cred;
+extern int wps_corrupt_pkhash;
#define WPS_VERSION wps_version_number
#else /* CONFIG_WPS_TESTING */
-#ifdef CONFIG_WPS2
#define WPS_VERSION 0x20
-#else /* CONFIG_WPS2 */
-#define WPS_VERSION 0x10
-#endif /* CONFIG_WPS2 */
#endif /* CONFIG_WPS_TESTING */
@@ -145,7 +142,8 @@ enum {
WFA_ELEM_AUTHORIZEDMACS = 0x01,
WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
- WFA_ELEM_SETTINGS_DELAY_TIME = 0x04
+ WFA_ELEM_SETTINGS_DELAY_TIME = 0x04,
+ WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05
};
/* Device Password ID */
@@ -155,7 +153,9 @@ enum wps_dev_password_id {
DEV_PW_MACHINE_SPECIFIED = 0x0002,
DEV_PW_REKEY = 0x0003,
DEV_PW_PUSHBUTTON = 0x0004,
- DEV_PW_REGISTRAR_SPECIFIED = 0x0005
+ DEV_PW_REGISTRAR_SPECIFIED = 0x0005,
+ DEV_PW_NFC_CONNECTION_HANDOVER = 0x0007,
+ DEV_PW_P2PS_DEFAULT = 0x0008
};
/* Message Type */
@@ -180,7 +180,7 @@ enum wps_msg_type {
/* Authentication Type Flags */
#define WPS_AUTH_OPEN 0x0001
#define WPS_AUTH_WPAPSK 0x0002
-#define WPS_AUTH_SHARED 0x0004
+#define WPS_AUTH_SHARED 0x0004 /* deprecated */
#define WPS_AUTH_WPA 0x0008
#define WPS_AUTH_WPA2 0x0010
#define WPS_AUTH_WPA2PSK 0x0020
@@ -189,7 +189,7 @@ enum wps_msg_type {
/* Encryption Type Flags */
#define WPS_ENCR_NONE 0x0001
-#define WPS_ENCR_WEP 0x0002
+#define WPS_ENCR_WEP 0x0002 /* deprecated */
#define WPS_ENCR_TKIP 0x0004
#define WPS_ENCR_AES 0x0008
#define WPS_ENCR_TYPES (WPS_ENCR_NONE | WPS_ENCR_WEP | WPS_ENCR_TKIP | \
@@ -215,7 +215,9 @@ enum wps_config_error {
WPS_CFG_SETUP_LOCKED = 15,
WPS_CFG_MSG_TIMEOUT = 16,
WPS_CFG_REG_SESS_TIMEOUT = 17,
- WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
+ WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18,
+ WPS_CFG_60G_CHAN_NOT_SUPPORTED = 19,
+ WPS_CFG_PUBLIC_KEY_HASH_MISMATCH = 20
};
/* Vendor specific Error Indication for WPS event messages */
@@ -223,6 +225,7 @@ enum wps_error_indication {
WPS_EI_NO_ERROR,
WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,
WPS_EI_SECURITY_WEP_PROHIBITED,
+ WPS_EI_AUTH_FAILURE,
NUM_WPS_EI_VALUES
};
@@ -240,12 +243,11 @@ enum wps_error_indication {
#define WPS_CONFIG_NFC_INTERFACE 0x0040
#define WPS_CONFIG_PUSHBUTTON 0x0080
#define WPS_CONFIG_KEYPAD 0x0100
-#ifdef CONFIG_WPS2
#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_P2PS 0x1000
#define WPS_CONFIG_VIRT_DISPLAY 0x2008
#define WPS_CONFIG_PHY_DISPLAY 0x4008
-#endif /* CONFIG_WPS2 */
/* Connection Type Flags */
#define WPS_CONN_ESS 0x01
@@ -279,30 +281,71 @@ enum wps_dev_categ {
WPS_DEV_DISPLAY = 7,
WPS_DEV_MULTIMEDIA = 8,
WPS_DEV_GAMING = 9,
- WPS_DEV_PHONE = 10
+ WPS_DEV_PHONE = 10,
+ WPS_DEV_AUDIO = 11,
};
enum wps_dev_subcateg {
WPS_DEV_COMPUTER_PC = 1,
WPS_DEV_COMPUTER_SERVER = 2,
WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
+ WPS_DEV_COMPUTER_ULTRA_MOBILE = 4,
+ WPS_DEV_COMPUTER_NOTEBOOK = 5,
+ WPS_DEV_COMPUTER_DESKTOP = 6,
+ WPS_DEV_COMPUTER_MID = 7,
+ WPS_DEV_COMPUTER_NETBOOK = 8,
+ WPS_DEV_COMPUTER_TABLET = 9,
+ WPS_DEV_INPUT_KEYBOARD = 1,
+ WPS_DEV_INPUT_MOUSE = 2,
+ WPS_DEV_INPUT_JOYSTICK = 3,
+ WPS_DEV_INPUT_TRACKBALL = 4,
+ WPS_DEV_INPUT_GAMING = 5,
+ WPS_DEV_INPUT_REMOTE = 6,
+ WPS_DEV_INPUT_TOUCHSCREEN = 7,
+ WPS_DEV_INPUT_BIOMETRIC_READER = 8,
+ WPS_DEV_INPUT_BARCODE_READER = 9,
WPS_DEV_PRINTER_PRINTER = 1,
WPS_DEV_PRINTER_SCANNER = 2,
+ WPS_DEV_PRINTER_FAX = 3,
+ WPS_DEV_PRINTER_COPIER = 4,
+ WPS_DEV_PRINTER_ALL_IN_ONE = 5,
WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
+ WPS_DEV_CAMERA_VIDEO = 2,
+ WPS_DEV_CAMERA_WEB = 3,
+ WPS_DEV_CAMERA_SECURITY = 4,
WPS_DEV_STORAGE_NAS = 1,
WPS_DEV_NETWORK_INFRA_AP = 1,
WPS_DEV_NETWORK_INFRA_ROUTER = 2,
WPS_DEV_NETWORK_INFRA_SWITCH = 3,
+ WPS_DEV_NETWORK_INFRA_GATEWAY = 4,
+ WPS_DEV_NETWORK_INFRA_BRIDGE = 5,
WPS_DEV_DISPLAY_TV = 1,
WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
WPS_DEV_DISPLAY_PROJECTOR = 3,
+ WPS_DEV_DISPLAY_MONITOR = 4,
WPS_DEV_MULTIMEDIA_DAR = 1,
WPS_DEV_MULTIMEDIA_PVR = 2,
WPS_DEV_MULTIMEDIA_MCX = 3,
+ WPS_DEV_MULTIMEDIA_SET_TOP_BOX = 4,
+ WPS_DEV_MULTIMEDIA_MEDIA_SERVER = 5,
+ WPS_DEV_MULTIMEDIA_PORTABLE_VIDEO_PLAYER = 6,
WPS_DEV_GAMING_XBOX = 1,
WPS_DEV_GAMING_XBOX360 = 2,
WPS_DEV_GAMING_PLAYSTATION = 3,
- WPS_DEV_PHONE_WINDOWS_MOBILE = 1
+ WPS_DEV_GAMING_GAME_CONSOLE = 4,
+ WPS_DEV_GAMING_PORTABLE_DEVICE = 5,
+ WPS_DEV_PHONE_WINDOWS_MOBILE = 1,
+ WPS_DEV_PHONE_SINGLE_MODE = 2,
+ WPS_DEV_PHONE_DUAL_MODE = 3,
+ WPS_DEV_PHONE_SP_SINGLE_MODE = 4,
+ WPS_DEV_PHONE_SP_DUAL_MODE = 5,
+ WPS_DEV_AUDIO_TUNER_RECV = 1,
+ WPS_DEV_AUDIO_SPEAKERS = 2,
+ WPS_DEV_AUDIO_PMP = 3,
+ WPS_DEV_AUDIO_HEADSET = 4,
+ WPS_DEV_AUDIO_HEADPHONES = 5,
+ WPS_DEV_AUDIO_MICROPHONE = 6,
+ WPS_DEV_AUDIO_HOME_THEATRE = 7,
};
diff --git a/contrib/wpa/src/wps/wps_dev_attr.c b/contrib/wpa/src/wps/wps_dev_attr.c
index 3c94a43..0d01211 100644
--- a/contrib/wpa/src/wps/wps_dev_attr.c
+++ b/contrib/wpa/src/wps/wps_dev_attr.c
@@ -85,8 +85,7 @@ int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg)
}
-static int wps_build_serial_number(struct wps_device_data *dev,
- struct wpabuf *msg)
+int wps_build_serial_number(struct wps_device_data *dev, struct wpabuf *msg)
{
size_t len;
wpa_printf(MSG_DEBUG, "WPS: * Serial Number");
@@ -217,13 +216,10 @@ int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)
}
-int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg,
+ u8 rf_band)
{
- wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", dev->rf_bands);
- wpabuf_put_be16(msg, ATTR_RF_BANDS);
- wpabuf_put_be16(msg, 1);
- wpabuf_put_u8(msg, dev->rf_bands);
- return 0;
+ return wps_build_rf_bands_attr(msg, rf_band ? rf_band : dev->rf_bands);
}
@@ -257,11 +253,9 @@ static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
os_free(dev->manufacturer);
- dev->manufacturer = os_malloc(str_len + 1);
+ dev->manufacturer = dup_binstr(str, str_len);
if (dev->manufacturer == NULL)
return -1;
- os_memcpy(dev->manufacturer, str, str_len);
- dev->manufacturer[str_len] = '\0';
return 0;
}
@@ -278,11 +272,9 @@ static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
os_free(dev->model_name);
- dev->model_name = os_malloc(str_len + 1);
+ dev->model_name = dup_binstr(str, str_len);
if (dev->model_name == NULL)
return -1;
- os_memcpy(dev->model_name, str, str_len);
- dev->model_name[str_len] = '\0';
return 0;
}
@@ -299,11 +291,9 @@ static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
os_free(dev->model_number);
- dev->model_number = os_malloc(str_len + 1);
+ dev->model_number = dup_binstr(str, str_len);
if (dev->model_number == NULL)
return -1;
- os_memcpy(dev->model_number, str, str_len);
- dev->model_number[str_len] = '\0';
return 0;
}
@@ -320,11 +310,9 @@ static int wps_process_serial_number(struct wps_device_data *dev,
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
os_free(dev->serial_number);
- dev->serial_number = os_malloc(str_len + 1);
+ dev->serial_number = dup_binstr(str, str_len);
if (dev->serial_number == NULL)
return -1;
- os_memcpy(dev->serial_number, str, str_len);
- dev->serial_number[str_len] = '\0';
return 0;
}
@@ -341,11 +329,9 @@ static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
os_free(dev->device_name);
- dev->device_name = os_malloc(str_len + 1);
+ dev->device_name = dup_binstr(str, str_len);
if (dev->device_name == NULL)
return -1;
- os_memcpy(dev->device_name, str, str_len);
- dev->device_name[str_len] = '\0';
return 0;
}
@@ -418,25 +404,6 @@ int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
}
-void wps_device_data_dup(struct wps_device_data *dst,
- const struct wps_device_data *src)
-{
- if (src->device_name)
- dst->device_name = os_strdup(src->device_name);
- if (src->manufacturer)
- dst->manufacturer = os_strdup(src->manufacturer);
- if (src->model_name)
- dst->model_name = os_strdup(src->model_name);
- if (src->model_number)
- dst->model_number = os_strdup(src->model_number);
- if (src->serial_number)
- dst->serial_number = os_strdup(src->serial_number);
- os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
- dst->os_version = src->os_version;
- dst->rf_bands = src->rf_bands;
-}
-
-
void wps_device_data_free(struct wps_device_data *dev)
{
os_free(dev->device_name);
diff --git a/contrib/wpa/src/wps/wps_dev_attr.h b/contrib/wpa/src/wps/wps_dev_attr.h
index 200c9c4..c9034ad 100644
--- a/contrib/wpa/src/wps/wps_dev_attr.h
+++ b/contrib/wpa/src/wps/wps_dev_attr.h
@@ -14,11 +14,13 @@ struct wps_parse_attr;
int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_serial_number(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg);
-int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg,
+ u8 rf_band);
int wps_build_primary_dev_type(struct wps_device_data *dev,
struct wpabuf *msg);
int wps_build_secondary_dev_type(struct wps_device_data *dev,
@@ -28,8 +30,6 @@ 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);
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
-void wps_device_data_dup(struct wps_device_data *dst,
- const struct wps_device_data *src);
void wps_device_data_free(struct wps_device_data *dev);
int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_req_dev_type(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 837b941..89957b1 100644
--- a/contrib/wpa/src/wps/wps_enrollee.c
+++ b/contrib/wpa/src/wps/wps_enrollee.c
@@ -16,16 +16,6 @@
#include "wps_dev_attr.h"
-static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
-{
- wpa_printf(MSG_DEBUG, "WPS: * MAC Address");
- wpabuf_put_be16(msg, ATTR_MAC_ADDR);
- wpabuf_put_be16(msg, ETH_ALEN);
- wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN);
- return 0;
-}
-
-
static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
{
u8 state;
@@ -140,16 +130,14 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
* workaround.
*/
config_methods &= ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
}
if (wps_build_version(msg) ||
wps_build_msg_type(msg, WPS_M1) ||
wps_build_uuid_e(msg, wps->uuid_e) ||
- wps_build_mac_addr(wps, msg) ||
+ wps_build_mac_addr(msg, wps->mac_addr_e) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_public_key(wps, msg) ||
wps_build_auth_type_flags(wps, msg) ||
@@ -158,7 +146,8 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
wps_build_config_methods(msg, config_methods) ||
wps_build_wps_state(wps, msg) ||
wps_build_device_attrs(&wps->wps->dev, msg) ||
- wps_build_rf_bands(&wps->wps->dev, msg) ||
+ wps_build_rf_bands(&wps->wps->dev, msg,
+ wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
wps_build_assoc_state(wps, msg) ||
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
@@ -186,6 +175,12 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps)
}
wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+ if (wps->wps->ap && random_pool_ready() != 1) {
+ wpa_printf(MSG_INFO,
+ "WPS: Not enough entropy in random pool to proceed - do not allow AP PIN to be used");
+ return NULL;
+ }
+
msg = wpabuf_alloc(1000);
if (msg == NULL)
return NULL;
@@ -252,17 +247,19 @@ static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
{
- u16 auth_type = wps->wps->auth_types;
+ u16 auth_type = wps->wps->ap_auth_type;
- /* Select the best authentication type */
+ /*
+ * Work around issues with Windows 7 WPS implementation not liking
+ * multiple Authentication Type bits in M7 AP Settings attribute by
+ * showing only the most secure option from current configuration.
+ */
if (auth_type & WPS_AUTH_WPA2PSK)
auth_type = WPS_AUTH_WPA2PSK;
else if (auth_type & WPS_AUTH_WPAPSK)
auth_type = WPS_AUTH_WPAPSK;
else if (auth_type & WPS_AUTH_OPEN)
auth_type = WPS_AUTH_OPEN;
- else if (auth_type & WPS_AUTH_SHARED)
- auth_type = WPS_AUTH_SHARED;
wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type);
wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
@@ -274,19 +271,18 @@ static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
{
- u16 encr_type = wps->wps->encr_types;
+ u16 encr_type = wps->wps->ap_encr_type;
- /* Select the best encryption type */
- if (wps->wps->auth_types & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
+ /*
+ * Work around issues with Windows 7 WPS implementation not liking
+ * multiple Encryption Type bits in M7 AP Settings attribute by
+ * showing only the most secure option from current configuration.
+ */
+ if (wps->wps->ap_auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
if (encr_type & WPS_ENCR_AES)
encr_type = WPS_ENCR_AES;
else if (encr_type & WPS_ENCR_TKIP)
encr_type = WPS_ENCR_TKIP;
- } else {
- if (encr_type & WPS_ENCR_WEP)
- encr_type = WPS_ENCR_WEP;
- else if (encr_type & WPS_ENCR_NONE)
- encr_type = WPS_ENCR_NONE;
}
wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type);
@@ -299,7 +295,35 @@ static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
{
- wpa_printf(MSG_DEBUG, "WPS: * Network Key");
+ if ((wps->wps->ap_auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) &&
+ wps->wps->network_key_len == 0) {
+ char hex[65];
+ u8 psk[32];
+ /* Generate a random per-device PSK */
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(psk, sizeof(psk)) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
+ psk, sizeof(psk));
+ wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)",
+ (unsigned int) wps->new_psk_len * 2);
+ wpa_snprintf_hex(hex, sizeof(hex), psk, sizeof(psk));
+ wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
+ wpabuf_put_be16(msg, sizeof(psk) * 2);
+ wpabuf_put_data(msg, hex, sizeof(psk) * 2);
+ if (wps->wps->registrar) {
+ wps_cb_new_psk(wps->wps->registrar,
+ wps->peer_dev.mac_addr,
+ wps->p2p_dev_addr, psk, sizeof(psk));
+ }
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)",
+ (unsigned int) wps->wps->network_key_len);
wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
wpabuf_put_be16(msg, wps->wps->network_key_len);
wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
@@ -319,6 +343,9 @@ static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)
static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
{
+ const u8 *start, *end;
+ int ret;
+
if (wps->wps->ap_settings) {
wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)");
wpabuf_put_data(plain, wps->wps->ap_settings,
@@ -326,11 +353,19 @@ static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
return 0;
}
- return wps_build_cred_ssid(wps, plain) ||
+ wpa_printf(MSG_DEBUG, "WPS: * AP Settings based on current configuration");
+ start = wpabuf_put(plain, 0);
+ ret = wps_build_cred_ssid(wps, plain) ||
wps_build_cred_mac_addr(wps, plain) ||
wps_build_cred_auth_type(wps, plain) ||
wps_build_cred_encr_type(wps, plain) ||
wps_build_cred_network_key(wps, plain);
+ end = wpabuf_put(plain, 0);
+
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Plaintext AP Settings",
+ start, end - start);
+
+ return ret;
}
@@ -402,7 +437,7 @@ static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
if (wps->wps->ap)
wps->state = RECV_ACK;
else {
- wps_success_event(wps->wps);
+ wps_success_event(wps->wps, wps->peer_dev.mac_addr);
wps->state = WPS_FINISHED;
}
return msg;
@@ -523,6 +558,24 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
return -1;
}
+ if (wps->peer_pubkey_hash_set) {
+ u8 hash[WPS_HASH_LEN];
+ sha256_vector(1, &pk, &pk_len, hash);
+ if (os_memcmp_const(hash, wps->peer_pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch");
+ wpa_hexdump(MSG_DEBUG, "WPS: Received public key",
+ pk, pk_len);
+ wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key "
+ "hash", hash, WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash",
+ wps->peer_pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN);
+ wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
+ return -1;
+ }
+ }
+
wpabuf_free(wps->dh_pubkey_r);
wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
if (wps->dh_pubkey_r == NULL)
@@ -588,11 +641,11 @@ static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 1, 1);
+ wps_pwd_auth_fail_event(wps->wps, 1, 1, wps->peer_dev.mac_addr);
return -1;
}
@@ -628,11 +681,11 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 1, 2);
+ wps_pwd_auth_fail_event(wps->wps, 1, 2, wps->peer_dev.mac_addr);
return -1;
}
@@ -679,7 +732,6 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
#endif /* CONFIG_WPS_STRICT */
}
-#ifdef CONFIG_WPS2
if (!(wps->cred.encr_type &
(WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) {
if (wps->cred.encr_type & WPS_ENCR_WEP) {
@@ -693,7 +745,6 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
"invalid encr_type 0x%x", wps->cred.encr_type);
return -1;
}
-#endif /* CONFIG_WPS2 */
if (wps->wps->cred_cb) {
wps->cred.cred_attr = cred - 4;
@@ -780,7 +831,6 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
#endif /* CONFIG_WPS_STRICT */
}
-#ifdef CONFIG_WPS2
if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES)))
{
if (cred.encr_type & WPS_ENCR_WEP) {
@@ -794,7 +844,6 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
"invalid encr_type 0x%x", cred.encr_type);
return -1;
}
-#endif /* CONFIG_WPS2 */
#ifdef CONFIG_WPS_STRICT
if (wps2) {
@@ -811,7 +860,6 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
}
#endif /* CONFIG_WPS_STRICT */
-#ifdef CONFIG_WPS2
if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP)
{
wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
@@ -825,7 +873,6 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
"WPAPSK+WPA2PSK");
cred.auth_type |= WPS_AUTH_WPA2PSK;
}
-#endif /* CONFIG_WPS2 */
if (wps->wps->cred_cb) {
cred.cred_attr = wpabuf_head(attrs);
@@ -837,6 +884,63 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
}
+static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
+{
+ u16 id;
+
+ if (dev_pw_id == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
+ return -1;
+ }
+
+ id = WPA_GET_BE16(dev_pw_id);
+ if (wps->dev_pw_id == id) {
+ wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
+ return 0;
+ }
+
+#ifdef CONFIG_P2P
+ if ((id == DEV_PW_DEFAULT &&
+ wps->dev_pw_id == DEV_PW_REGISTRAR_SPECIFIED) ||
+ (id == DEV_PW_REGISTRAR_SPECIFIED &&
+ wps->dev_pw_id == DEV_PW_DEFAULT)) {
+ /*
+ * Common P2P use cases indicate whether the PIN is from the
+ * client or GO using Device Password Id in M1/M2 in a way that
+ * does not look fully compliant with WSC specification. Anyway,
+ * this is deployed and needs to be allowed, so ignore changes
+ * between Registrar-Specified and Default PIN.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Allow PIN Device Password ID "
+ "change");
+ return 0;
+ }
+#endif /* CONFIG_P2P */
+
+ wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
+ "ID from %u to %u", wps->dev_pw_id, id);
+
+ if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Workaround - ignore PBC-to-PIN change");
+ return 0;
+ }
+
+ if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
+ wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
+ bin_clear_free(wps->dev_password, wps->dev_password_len);
+ wps->dev_pw_id = wps->alt_dev_pw_id;
+ wps->dev_password = wps->alt_dev_password;
+ wps->dev_password_len = wps->alt_dev_password_len;
+ wps->alt_dev_password = NULL;
+ wps->alt_dev_password_len = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+
static enum wps_process_res wps_process_m2(struct wps_data *wps,
const struct wpabuf *msg,
struct wps_parse_attr *attr)
@@ -852,7 +956,8 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
- wps_process_uuid_r(wps, attr->uuid_r)) {
+ wps_process_uuid_r(wps, attr->uuid_r) ||
+ wps_process_dev_pw_id(wps, attr->dev_password_id)) {
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -880,6 +985,38 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
return WPS_CONTINUE;
}
+#ifdef CONFIG_WPS_NFC
+ if (wps->peer_pubkey_hash_set) {
+ struct wpabuf *decrypted;
+ struct wps_parse_attr eattr;
+
+ decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+ attr->encr_settings_len);
+ if (decrypted == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt "
+ "Encrypted Settings attribute");
+ wps->state = SEND_WSC_NACK;
+ return WPS_CONTINUE;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted "
+ "Settings attribute");
+ if (wps_parse_msg(decrypted, &eattr) < 0 ||
+ wps_process_key_wrap_auth(wps, decrypted,
+ eattr.key_wrap_auth) ||
+ wps_process_creds(wps, eattr.cred, eattr.cred_len,
+ eattr.num_cred, attr->version2 != NULL)) {
+ wpabuf_free(decrypted);
+ wps->state = SEND_WSC_NACK;
+ return WPS_CONTINUE;
+ }
+ wpabuf_free(decrypted);
+
+ wps->state = WPS_MSG_DONE;
+ return WPS_CONTINUE;
+ }
+#endif /* CONFIG_WPS_NFC */
+
wps->state = SEND_M3;
return WPS_CONTINUE;
}
@@ -1162,7 +1299,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m4(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M4, wps->config_error,
- wps->error_indication);
+ wps->error_indication,
+ wps->peer_dev.mac_addr);
break;
case WPS_M6:
if (wps_validate_m6(msg) < 0)
@@ -1170,7 +1308,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m6(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M6, wps->config_error,
- wps->error_indication);
+ wps->error_indication,
+ wps->peer_dev.mac_addr);
break;
case WPS_M8:
if (wps_validate_m8(msg) < 0)
@@ -1178,7 +1317,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m8(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M8, wps->config_error,
- wps->error_indication);
+ wps->error_indication,
+ wps->peer_dev.mac_addr);
break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
@@ -1241,7 +1381,7 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
if (wps->state == RECV_ACK && wps->wps->ap) {
wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
"completed successfully");
- wps_success_event(wps->wps);
+ wps_success_event(wps->wps, wps->peer_dev.mac_addr);
wps->state = WPS_FINISHED;
return WPS_DONE;
}
@@ -1306,15 +1446,15 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
switch (wps->state) {
case RECV_M4:
wps_fail_event(wps->wps, WPS_M3, config_error,
- wps->error_indication);
+ wps->error_indication, wps->peer_dev.mac_addr);
break;
case RECV_M6:
wps_fail_event(wps->wps, WPS_M5, config_error,
- wps->error_indication);
+ wps->error_indication, wps->peer_dev.mac_addr);
break;
case RECV_M8:
wps_fail_event(wps->wps, WPS_M7, config_error,
- wps->error_indication);
+ wps->error_indication, wps->peer_dev.mac_addr);
break;
default:
break;
diff --git a/contrib/wpa/src/wps/wps_er.c b/contrib/wpa/src/wps/wps_er.c
index 95a0dec..078ff72 100644
--- a/contrib/wpa/src/wps/wps_er.c
+++ b/contrib/wpa/src/wps/wps_er.c
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -97,13 +97,16 @@ static void wps_er_sta_remove_all(struct wps_er_ap *ap)
static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
- struct in_addr *addr, const u8 *uuid)
+ struct in_addr *addr, const u8 *uuid,
+ const u8 *mac_addr)
{
struct wps_er_ap *ap;
dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
(uuid == NULL ||
- os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0))
+ os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
+ (mac_addr == NULL ||
+ os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
return ap;
}
return NULL;
@@ -182,10 +185,8 @@ static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
dl_list_del(&ap->list);
wps_er_ap_free(ap);
- if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) {
- eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
+ if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing))
wps_er_deinit_finish(er, NULL);
- }
}
@@ -290,7 +291,7 @@ int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr)
struct wps_er_ap *ap;
struct wps_er_ap_settings *settings;
- ap = wps_er_ap_get(er, addr, NULL);
+ ap = wps_er_ap_get(er, addr, NULL, NULL);
if (ap == NULL || ap->ap_settings == NULL)
return -1;
@@ -578,12 +579,15 @@ static void wps_er_parse_device_description(struct wps_er_ap *ap,
wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
ap->udn = xml_get_first_item(data, "UDN");
- wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
- pos = os_strstr(ap->udn, "uuid:");
- if (pos) {
- pos += 5;
- if (uuid_str2bin(pos, ap->uuid) < 0)
- wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN");
+ if (ap->udn) {
+ wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
+ pos = os_strstr(ap->udn, "uuid:");
+ if (pos) {
+ pos += 5;
+ if (uuid_str2bin(pos, ap->uuid) < 0)
+ wpa_printf(MSG_DEBUG,
+ "WPS ER: Invalid UUID in UDN");
+ }
}
ap->upc = xml_get_first_item(data, "UPC");
@@ -636,7 +640,7 @@ void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
{
struct wps_er_ap *ap;
- ap = wps_er_ap_get(er, addr, uuid);
+ ap = wps_er_ap_get(er, addr, uuid, NULL);
if (ap) {
/* Update advertisement timeout */
eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
@@ -793,52 +797,31 @@ static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
if (attr->manufacturer) {
os_free(sta->manufacturer);
- sta->manufacturer = os_malloc(attr->manufacturer_len + 1);
- if (sta->manufacturer) {
- os_memcpy(sta->manufacturer, attr->manufacturer,
- attr->manufacturer_len);
- sta->manufacturer[attr->manufacturer_len] = '\0';
- }
+ sta->manufacturer = dup_binstr(attr->manufacturer,
+ attr->manufacturer_len);
}
if (attr->model_name) {
os_free(sta->model_name);
- sta->model_name = os_malloc(attr->model_name_len + 1);
- if (sta->model_name) {
- os_memcpy(sta->model_name, attr->model_name,
- attr->model_name_len);
- sta->model_name[attr->model_name_len] = '\0';
- }
+ sta->model_name = dup_binstr(attr->model_name,
+ attr->model_name_len);
}
if (attr->model_number) {
os_free(sta->model_number);
- sta->model_number = os_malloc(attr->model_number_len + 1);
- if (sta->model_number) {
- os_memcpy(sta->model_number, attr->model_number,
- attr->model_number_len);
- sta->model_number[attr->model_number_len] = '\0';
- }
+ sta->model_number = dup_binstr(attr->model_number,
+ attr->model_number_len);
}
if (attr->serial_number) {
os_free(sta->serial_number);
- sta->serial_number = os_malloc(attr->serial_number_len + 1);
- if (sta->serial_number) {
- os_memcpy(sta->serial_number, attr->serial_number,
- attr->serial_number_len);
- sta->serial_number[attr->serial_number_len] = '\0';
- }
+ sta->serial_number = dup_binstr(attr->serial_number,
+ attr->serial_number_len);
}
if (attr->dev_name) {
os_free(sta->dev_name);
- sta->dev_name = os_malloc(attr->dev_name_len + 1);
- if (sta->dev_name) {
- os_memcpy(sta->dev_name, attr->dev_name,
- attr->dev_name_len);
- sta->dev_name[attr->dev_name_len] = '\0';
- }
+ sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
}
eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
@@ -1289,6 +1272,22 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
/* Limit event_id to < 32 bits to avoid issues with atoi() */
er->event_id &= 0x0fffffff;
+ if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
+ const char *pos, *end;
+ pos = filter + 7;
+ end = os_strchr(pos, ' ');
+ if (end) {
+ size_t len = end - pos;
+ os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
+ len + 1 : sizeof(er->ifname));
+ filter = end + 1;
+ } else {
+ os_strlcpy(er->ifname, pos, sizeof(er->ifname));
+ filter = NULL;
+ }
+ er->forced_ifname = 1;
+ }
+
if (filter) {
if (inet_aton(filter, &er->filter_addr) == 0) {
wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
@@ -1299,10 +1298,10 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
"with %s", filter);
}
- if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text,
+ if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
er->mac_addr)) {
wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
- "for %s. Does it have IP address?", ifname);
+ "for %s. Does it have IP address?", er->ifname);
wps_er_deinit(er, NULL, NULL);
return NULL;
}
@@ -1349,9 +1348,19 @@ static void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
struct wps_er *er = eloop_data;
void (*deinit_done_cb)(void *ctx);
void *deinit_done_ctx;
+ struct wps_er_ap *ap, *tmp;
wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
+ dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap,
+ list) {
+ wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it",
+ inet_ntoa(ap->addr), ap->location);
+ dl_list_del(&ap->list);
+ wps_er_ap_free(ap);
+ }
+
+ eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
deinit_done_cb = er->deinit_done_cb;
deinit_done_ctx = er->deinit_done_ctx;
os_free(er->ip_addr_text);
@@ -1484,11 +1493,9 @@ static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
{
-#ifdef CONFIG_WPS2
wpabuf_put_be16(msg, ATTR_UUID_R);
wpabuf_put_be16(msg, WPS_UUID_LEN);
wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
-#endif /* CONFIG_WPS2 */
return 0;
}
@@ -1500,9 +1507,7 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
struct wps_er_ap *ap;
struct wps_registrar *reg = er->wps->registrar;
const u8 *auth_macs;
-#ifdef CONFIG_WPS2
u8 bcast[ETH_ALEN];
-#endif /* CONFIG_WPS2 */
size_t count;
union wps_event_data data;
@@ -1516,13 +1521,11 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
return;
auth_macs = wps_authorized_macs(reg, &count);
-#ifdef CONFIG_WPS2
if (count == 0) {
os_memset(bcast, 0xff, ETH_ALEN);
auth_macs = bcast;
count = 1;
}
-#endif /* CONFIG_WPS2 */
if (wps_build_version(msg) ||
wps_er_build_selected_registrar(msg, sel_reg) ||
@@ -1555,7 +1558,7 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
}
-int wps_er_pbc(struct wps_er *er, const u8 *uuid)
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
{
int res;
struct wps_er_ap *ap;
@@ -1569,11 +1572,14 @@ int wps_er_pbc(struct wps_er *er, const u8 *uuid)
return -2;
}
- ap = wps_er_ap_get(er, NULL, uuid);
+ if (uuid)
+ ap = wps_er_ap_get(er, NULL, uuid, NULL);
+ else
+ ap = NULL;
if (ap == NULL) {
struct wps_er_sta *sta = NULL;
dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
- sta = wps_er_sta_get(ap, NULL, uuid);
+ sta = wps_er_sta_get(ap, addr, uuid);
if (sta) {
uuid = ap->uuid;
break;
@@ -1619,6 +1625,19 @@ static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
}
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
+{
+ struct wps_er_ap *ap;
+ dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+ struct wps_er_sta *sta;
+ sta = wps_er_sta_get(ap, addr, NULL);
+ if (sta)
+ return sta->uuid;
+ }
+ return NULL;
+}
+
+
static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
enum http_client_event event)
{
@@ -1877,20 +1896,22 @@ static int wps_er_send_get_device_info(struct wps_er_ap *ap,
}
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len)
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len)
{
struct wps_er_ap *ap;
if (er == NULL)
return -1;
- ap = wps_er_ap_get(er, NULL, uuid);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
if (ap == NULL) {
wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
"request");
return -1;
}
+ if (uuid == NULL)
+ uuid = ap->uuid;
if (ap->wps) {
wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
"with the AP - cannot start learn");
@@ -1908,7 +1929,7 @@ int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
}
-int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
const struct wps_credential *cred)
{
struct wps_er_ap *ap;
@@ -1916,7 +1937,7 @@ int wps_er_set_config(struct wps_er *er, const u8 *uuid,
if (er == NULL)
return -1;
- ap = wps_er_ap_get(er, NULL, uuid);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
if (ap == NULL) {
wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
"request");
@@ -1960,20 +1981,23 @@ static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
}
-int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len, const struct wps_credential *cred)
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len,
+ const struct wps_credential *cred)
{
struct wps_er_ap *ap;
if (er == NULL)
return -1;
- ap = wps_er_ap_get(er, NULL, uuid);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
if (ap == NULL) {
wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
"request");
return -1;
}
+ if (uuid == NULL)
+ uuid = ap->uuid;
if (ap->wps) {
wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
"with the AP - cannot start config");
@@ -1999,16 +2023,39 @@ int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
#ifdef CONFIG_WPS_NFC
-struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid)
+
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+ struct wps_credential *cred)
{
- struct wps_er_ap *ap;
struct wpabuf *ret;
struct wps_data data;
+ ret = wpabuf_alloc(500);
+ if (ret == NULL)
+ return NULL;
+
+ os_memset(&data, 0, sizeof(data));
+ data.wps = wps;
+ data.use_cred = cred;
+ if (wps_build_cred(&data, ret) ||
+ wps_build_wfa_ext(ret, 0, NULL, 0)) {
+ wpabuf_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+ const u8 *addr)
+{
+ struct wps_er_ap *ap;
+
if (er == NULL)
return NULL;
- ap = wps_er_ap_get(er, NULL, uuid);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
if (ap == NULL)
return NULL;
if (ap->ap_settings == NULL) {
@@ -2017,20 +2064,32 @@ struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid)
return NULL;
}
- ret = wpabuf_alloc(500);
- if (ret == NULL)
+ return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
+}
+
+
+struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
+ struct wps_context *wps, const u8 *uuid,
+ const u8 *addr, struct wpabuf *pubkey)
+{
+ struct wps_er_ap *ap;
+
+ if (er == NULL)
return NULL;
- os_memset(&data, 0, sizeof(data));
- data.wps = er->wps;
- data.use_cred = ap->ap_settings;
- if (wps_build_version(ret) ||
- wps_build_cred(&data, ret) ||
- wps_build_wfa_ext(ret, 0, NULL, 0)) {
- wpabuf_free(ret);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
+ if (ap == NULL)
+ return NULL;
+ if (ap->ap_settings == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+ "selected AP");
return NULL;
}
- return ret;
+ os_memcpy(wps->ssid, ap->ap_settings->ssid, ap->ap_settings->ssid_len);
+ wps->ssid_len = ap->ap_settings->ssid_len;
+
+ return wps_build_nfc_handover_sel(wps, pubkey, addr, 0);
}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/contrib/wpa/src/wps/wps_er.h b/contrib/wpa/src/wps/wps_er.h
index 6119647..4b48ff6 100644
--- a/contrib/wpa/src/wps/wps_er.h
+++ b/contrib/wpa/src/wps/wps_er.h
@@ -76,6 +76,7 @@ struct wps_er_ap_settings {
struct wps_er {
struct wps_context *wps;
char ifname[17];
+ int forced_ifname;
u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
char *ip_addr_text; /* IP address of network i.f. we use */
unsigned ip_addr; /* IP address of network i.f. we use (host order) */
diff --git a/contrib/wpa/src/wps/wps_er_ssdp.c b/contrib/wpa/src/wps/wps_er_ssdp.c
index f9f6e6c..e381fec 100644
--- a/contrib/wpa/src/wps/wps_er_ssdp.c
+++ b/contrib/wpa/src/wps/wps_er_ssdp.c
@@ -166,7 +166,9 @@ int wps_er_ssdp_init(struct wps_er *er)
return -1;
}
- er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
+ er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr,
+ er->forced_ifname ?
+ er->ifname : NULL);
if (er->multicast_sd < 0) {
wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
"for SSDP");
diff --git a/contrib/wpa/src/wps/wps_i.h b/contrib/wpa/src/wps/wps_i.h
index 8110894..f7154f8 100644
--- a/contrib/wpa/src/wps/wps_i.h
+++ b/contrib/wpa/src/wps/wps_i.h
@@ -71,6 +71,12 @@ struct wps_data {
size_t dev_password_len;
u16 dev_pw_id;
int pbc;
+ u8 *alt_dev_password;
+ size_t alt_dev_password_len;
+ u16 alt_dev_pw_id;
+
+ u8 peer_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+ int peer_pubkey_hash_set;
/**
* request_type - Request Type attribute from (Re)AssocReq
@@ -131,11 +137,14 @@ void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
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,
- u16 config_error, u16 error_indication);
-void wps_success_event(struct wps_context *wps);
-void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
+ u16 config_error, u16 error_indication, const u8 *mac_addr);
+void wps_success_event(struct wps_context *wps, const u8 *mac_addr);
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part,
+ const u8 *mac_addr);
void wps_pbc_overlap_event(struct wps_context *wps);
void wps_pbc_timeout_event(struct wps_context *wps);
+void wps_pbc_active_event(struct wps_context *wps);
+void wps_pbc_disable_event(struct wps_context *wps);
struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
@@ -166,6 +175,9 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
const struct wpabuf *pubkey, const u8 *dev_pw,
size_t dev_pw_len);
struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
+int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr);
+int wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands);
+int wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel);
/* wps_attr_process.c */
int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
@@ -193,11 +205,14 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
int wps_device_store(struct wps_registrar *reg,
struct wps_device_data *dev, const u8 *uuid);
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+ u16 dev_pw_id);
const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
int wps_registrar_pbc_overlap(struct wps_registrar *reg,
const u8 *addr, const u8 *uuid_e);
void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
struct wps_nfc_pw_token *token);
+int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
+ const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len);
#endif /* WPS_I_H */
diff --git a/contrib/wpa/src/wps/wps_module_tests.c b/contrib/wpa/src/wps/wps_module_tests.c
new file mode 100644
index 0000000..6800e86
--- /dev/null
+++ b/contrib/wpa/src/wps/wps_module_tests.c
@@ -0,0 +1,337 @@
+/*
+ * WPS module tests
+ * Copyright (c) 2014, 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 "wps_attr_parse.h"
+
+struct wps_attr_parse_test {
+ const char *data;
+ int result;
+ int extra;
+};
+
+struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
+ /* Empty message */
+ { "", 0, 0 },
+ /* Truncated attribute header */
+ { "10", -1, 0 },
+ { "1010", -1, 0 },
+ { "101000", -1, 0 },
+ /* Attribute overflow */
+ { "10100001", -1, 0 },
+#ifdef CONFIG_WPS_STRICT
+ { "10270000001057000101", -1, 0 },
+ { "1027000010570001010000000000", -1, 0 },
+#else /* CONFIG_WPS_STRICT */
+ /* Network Key workaround */
+ { "10270000001057000101", 0, 1 },
+ { "10230000001057000101", -1, 0 },
+ { "10270000101057000101", -1, 0 },
+ /* Mac OS X 10.6 padding workaround */
+ { "1027000010570001010000000000", 0, 1 },
+ { "1027000010570001010000000000000001000000", -1, 0 },
+#endif /* CONFIG_WPS_STRICT */
+ /* Version */
+ { "104a000110", 0, 0 },
+ { "104a0000", -1, 0 },
+ /* Message Type */
+ { "1022000101", 0, 0 },
+ { "10220000", -1, 0 },
+ /* Enrollee Nonce */
+ { "101a001000112233445566778899aabbccddeeff", 0, 0 },
+ { "101a00111122334455667788990011223344556677", -1, 0 },
+ /* Registrar Nonce */
+ { "1039001000112233445566778899aabbccddeeff", 0, 0 },
+ { "103900111122334455667788990011223344556677", -1, 0 },
+ /* UUID-E */
+ { "1047001000112233445566778899aabbccddeeff", 0, 0 },
+ { "10470000", -1, 0 },
+ { "104700111122334455667788990011223344556677", -1, 0 },
+ /* UUID-R */
+ { "1048001000112233445566778899aabbccddeeff", 0, 0 },
+ { "10480000", -1, 0 },
+ { "104800111122334455667788990011223344556677", -1, 0 },
+ /* Auth Type Flags */
+ { "100400021122", 0, 0 },
+ { "10040001ff", -1, 0 },
+ /* Encr Type Flags */
+ { "101000021122", 0, 0 },
+ { "10100001ff", -1, 0 },
+ /* Connection Type Flags */
+ { "100d0001ff", 0, 0 },
+ { "100d0002ffff", -1, 0 },
+ /* Config Methods */
+ { "10080002ffff", 0, 0 },
+ { "10080001ff", -1, 0 },
+ /* Selected Registrar Config Methods */
+ { "10530002ffff", 0, 0 },
+ { "10530001ff", -1, 0 },
+ /* Primary Device Type */
+ { "105400081122334455667788", 0, 0 },
+ { "105400111122334455667788990011223344556677", -1, 0 },
+ /* RF Bands */
+ { "103c0001ff", 0, 0 },
+ { "103c0002ffff", -1, 0 },
+ /* Association State */
+ { "10020002ffff", 0, 0 },
+ { "10020001ff", -1, 0 },
+ /* Config Error */
+ { "100900020001", 0, 0 },
+ { "10090001ff", -1, 0 },
+ /* Device Password ID */
+ { "101200020004", 0, 0 },
+ { "10120001ff", -1, 0 },
+ /* OOB Device Password */
+ { "102c001611223344556677889900112233445566778899000007", 0, 0 },
+ { "102c0036112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344", 0, 0 },
+ { "102c0001ff", -1, 0 },
+ { "102c003711223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455", -1, 0 },
+ { "102c002511223344556677889900112233445566778899001122334455667788990011223344556677", -1, 0 },
+ /* OS Version */
+ { "102d000411223344", 0, 0 },
+ { "102d00111122334455667788990011223344556677", -1, 0 },
+ /* WPS State */
+ { "1044000101", 0, 0 },
+ { "10440002ffff", -1, 0 },
+ /* Authenticator */
+ { "100500081122334455667788", 0, 0 },
+ { "10050000", -1, 0 },
+ { "100500111122334455667788990011223344556677", -1, 0 },
+ /* R-Hash1 */
+ { "103d00201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+ { "103d0000", -1, 0 },
+ { "103d0021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+ /* R-Hash2 */
+ { "103e00201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+ { "103e0000", -1, 0 },
+ { "103e0021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+ /* E-Hash1 */
+ { "101400201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+ { "10140000", -1, 0 },
+ { "10140021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+ /* E-Hash2 */
+ { "101500201122334455667788990011223344556677889900112233445566778899001122", 0, 0 },
+ { "10150000", -1, 0 },
+ { "10150021112233445566778899001122334455667788990011223344556677889900112233", -1, 0 },
+ /* R-SNonce1 */
+ { "103f001011223344556677889900112233445566", 0, 0 },
+ { "103f0000", -1, 0 },
+ { "103f00111122334455667788990011223344556677", -1, 0 },
+ /* R-SNonce2 */
+ { "1040001011223344556677889900112233445566", 0, 0 },
+ { "10400000", -1, 0 },
+ { "104000111122334455667788990011223344556677", -1, 0 },
+ /* E-SNonce1 */
+ { "1016001011223344556677889900112233445566", 0, 0 },
+ { "10160000", -1, 0 },
+ { "101600111122334455667788990011223344556677", -1, 0 },
+ /* E-SNonce2 */
+ { "1017001011223344556677889900112233445566", 0, 0 },
+ { "10170000", -1, 0 },
+ { "101700111122334455667788990011223344556677", -1, 0 },
+ /* Key Wrap Authenticator */
+ { "101e00081122334455667788", 0, 0 },
+ { "101e0000", -1, 0 },
+ { "101e0009112233445566778899", -1, 0 },
+ /* Authentication Type */
+ { "100300020001", 0, 0 },
+ { "10030001ff", -1, 0 },
+ /* Encryption Type */
+ { "100f00020001", 0, 0 },
+ { "100f0001ff", -1, 0 },
+ /* Network Index */
+ { "1026000101", 0, 0 },
+ { "10260002ffff", -1, 0 },
+ /* Network Key Index */
+ { "1028000101", 0, 3 },
+ { "10280002ffff", -1, 0 },
+ /* MAC Address */
+ { "10200006112233445566", 0, 0 },
+ { "10200000", -1, 0 },
+ { "1020000711223344556677", -1, 0 },
+ /* Selected Registrar */
+ { "1041000101", 0, 0 },
+ { "10410002ffff", -1, 0 },
+ /* Request Type */
+ { "103a000101", 0, 0 },
+ { "103a0002ffff", -1, 0 },
+ /* Response Type */
+ { "103b000101", 0, 0 },
+ { "103b0002ffff", -1, 0 },
+ /* Manufacturer */
+ { "10210000", 0, 0 },
+ /* Model Name */
+ { "10230000", 0, 0 },
+ /* Model Number */
+ { "10240000", 0, 0 },
+ /* Serial Number */
+ { "10420000", 0, 0 },
+ /* Device Name */
+ { "10110000", 0, 0 },
+ /* Public Key */
+ { "10320000", 0, 0 },
+ /* Enc Settings */
+ { "10180000", 0, 0 },
+ /* SSID */
+ { "10450000", 0, 0 },
+ /* AP Setup Locked */
+ { "1057000101", 0, 0 },
+ { "10570002ffff", -1, 0 },
+ /* Requested Device Type */
+ { "106a00081122334455667788", 0, 0 },
+ { "106a0000", -1, 0 },
+ { "106a0009112233445566778899", -1, 0 },
+ /* More than maximum Requested Device Type attributes */
+ { "106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788106a00081122334455667788", 0, 4 },
+ /* Secondary Device Type List */
+ { "105500081122334455667788", 0, 0 },
+ { "1055000711223344556677", -1, 0 },
+ { "1055008811223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566", -1, 0 },
+ /* AP Channel */
+ { "100100020001", 0, 0 },
+ { "1001000101", -1, 0 },
+ /* Skip invalid Vendor Extension */
+ { "10490000", 0, 0 },
+ { "1049000100", 0, 0 },
+ { "104900020000", 0, 0 },
+ /* Too long unknown vendor extension */
+ { "10490401"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "112233445566778899001122334455667788990011223344556677889900"
+ "1122334455", -1, 0 },
+ /* Maximum unknown vendor extensions */
+ { "10490003111111104900032222221049000333333310490003444444104900035555551049000366666610490003777777104900038888881049000399999910490003AAAAAA", 0, 5 },
+ /* More than maximum unknown vendor extensions */
+ { "10490003111111104900032222221049000333333310490003444444104900035555551049000366666610490003777777104900038888881049000399999910490003AAAAAA10490003BBBBBB", -1, 0 },
+ /* WFA vendor extensions */
+ { "1049000300372a", 0, 0 },
+ { "1049000400372a00", 0, 0 },
+ { "1049000500372a0001", 0, 0 },
+ { "1049001600372a0001ff0100020101030101040101ff00fe0101", 0, 6 },
+ /* Invalid Version2 length */
+ { "1049000500372a0000", -1, 0 },
+ /* Invalid Network Key Shareable length */
+ { "1049000500372a0200", -1, 0 },
+ /* Invalid Requedt To Enroll length */
+ { "1049000500372a0300", -1, 0 },
+ /* Invalid Settings Delay Time length */
+ { "1049000500372a0400", -1, 0 },
+ /* More than maximum Credential attributes */
+ { "100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000100e0000", 0, 2 },
+};
+
+
+static int wps_attr_parse_tests(void)
+{
+ struct wps_parse_attr attr;
+ unsigned int i;
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "WPS attribute parsing tests");
+
+ for (i = 0; i < ARRAY_SIZE(wps_attr_parse_test_cases); i++) {
+ struct wpabuf *buf;
+ size_t len;
+ struct wps_attr_parse_test *test =
+ &wps_attr_parse_test_cases[i];
+
+ len = os_strlen(test->data) / 2;
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(test->data, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+ if (wps_parse_msg(buf, &attr) != test->result) {
+ wpa_printf(MSG_ERROR, "WPS attribute parsing test %u failed: %s",
+ i, test->data);
+ ret = -1;
+ }
+ switch (test->extra) {
+ case 1:
+ if (!attr.network_key || !attr.ap_setup_locked)
+ ret = -1;
+ break;
+ case 2:
+ if (attr.num_cred != MAX_CRED_COUNT)
+ ret = -1;
+ break;
+ case 3:
+ if (!attr.network_key_idx)
+ ret = -1;
+ break;
+ case 4:
+ if (attr.num_req_dev_type != MAX_REQ_DEV_TYPE_COUNT)
+ ret = -1;
+ break;
+ case 5:
+ if (attr.num_vendor_ext != MAX_WPS_PARSE_VENDOR_EXT)
+ ret = -1;
+ break;
+ case 6:
+ if (!attr.version2 ||
+ !attr.authorized_macs ||
+ !attr.network_key_shareable ||
+ !attr.request_to_enroll ||
+ !attr.settings_delay_time)
+ ret = -1;
+ break;
+ }
+ wpabuf_free(buf);
+ }
+
+ return ret;
+}
+
+
+int wps_module_tests(void)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "WPS module tests");
+
+ if (wps_attr_parse_tests() < 0)
+ ret = -1;
+
+ return ret;
+}
diff --git a/contrib/wpa/src/wps/wps_registrar.c b/contrib/wpa/src/wps/wps_registrar.c
index b650a3c..48b7e12 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -31,16 +31,18 @@
struct wps_nfc_pw_token {
struct dl_list list;
u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+ unsigned int peer_pk_hash_known:1;
u16 pw_id;
- u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+ u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1];
size_t dev_pw_len;
+ int pk_hash_provided_oob; /* whether own PK hash was provided OOB */
};
static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)
{
dl_list_del(&token->list);
- os_free(token);
+ bin_clear_free(token, sizeof(*token));
}
@@ -82,14 +84,14 @@ struct wps_uuid_pin {
#define PIN_LOCKED BIT(0)
#define PIN_EXPIRES BIT(1)
int flags;
- struct os_time expiration;
+ struct os_reltime expiration;
u8 enrollee_addr[ETH_ALEN];
};
static void wps_free_pin(struct wps_uuid_pin *pin)
{
- os_free(pin->pin);
+ bin_clear_free(pin->pin, pin->pin_len);
os_free(pin);
}
@@ -113,7 +115,7 @@ struct wps_pbc_session {
struct wps_pbc_session *next;
u8 addr[ETH_ALEN];
u8 uuid_e[WPS_UUID_LEN];
- struct os_time timestamp;
+ struct os_reltime timestamp;
};
@@ -142,8 +144,8 @@ struct wps_registrar {
int pbc;
int selected_registrar;
- int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
- size_t psk_len);
+ int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr,
+ const u8 *psk, size_t psk_len);
int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
struct wpabuf *probe_resp_ie);
void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
@@ -171,6 +173,7 @@ struct wps_registrar {
int sel_reg_config_methods_override;
int static_wep_only;
int dualband;
+ int force_per_enrollee_psk;
struct wps_registrar_device *devices;
@@ -182,7 +185,9 @@ struct wps_registrar {
u8 p2p_dev_addr[ETH_ALEN];
u8 pbc_ignore_uuid[WPS_UUID_LEN];
- struct os_time pbc_ignore_start;
+#ifdef WPS_WORKAROUNDS
+ struct os_reltime pbc_ignore_start;
+#endif /* WPS_WORKAROUNDS */
};
@@ -310,9 +315,9 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
const u8 *addr, const u8 *uuid_e)
{
struct wps_pbc_session *pbc, *prev = NULL;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
pbc = reg->pbc_sessions;
while (pbc) {
@@ -346,7 +351,8 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
pbc = pbc->next;
while (pbc) {
- if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
+ if (os_reltime_expired(&now, &pbc->timestamp,
+ WPS_PBC_WALK_TIME)) {
prev->next = NULL;
wps_free_pbc_sessions(pbc);
break;
@@ -394,9 +400,9 @@ int wps_registrar_pbc_overlap(struct wps_registrar *reg,
int count = 0;
struct wps_pbc_session *pbc;
struct wps_pbc_session *first = NULL;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap");
@@ -412,9 +418,9 @@ int wps_registrar_pbc_overlap(struct wps_registrar *reg,
MAC2STR(pbc->addr));
wpa_hexdump(MSG_DEBUG, "WPS: UUID-E",
pbc->uuid_e, WPS_UUID_LEN);
- if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
- wpa_printf(MSG_DEBUG, "WPS: PBC walk time has "
- "expired");
+ if (os_reltime_expired(&now, &pbc->timestamp,
+ WPS_PBC_WALK_TIME)) {
+ wpa_printf(MSG_DEBUG, "WPS: PBC walk time has expired");
break;
}
if (first &&
@@ -532,7 +538,6 @@ static int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg,
static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
{
*methods |= WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) ==
WPS_CONFIG_VIRT_PUSHBUTTON)
*methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
@@ -550,7 +555,6 @@ static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
*/
*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
}
-#endif /* CONFIG_WPS2 */
}
@@ -562,10 +566,8 @@ static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
return 0;
methods = reg->wps->config_methods;
methods &= ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
if (reg->pbc)
wps_set_pushbutton(&methods, reg->wps->config_methods);
if (reg->sel_reg_config_methods_override >= 0)
@@ -588,10 +590,8 @@ static int wps_build_probe_config_methods(struct wps_registrar *reg,
* external Registrars.
*/
methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods);
wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
wpabuf_put_be16(msg, 2);
@@ -611,13 +611,11 @@ const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)
{
*count = 0;
-#ifdef CONFIG_WPS2
while (*count < WPS_MAX_AUTHORIZED_MACS) {
if (is_zero_ether_addr(reg->authorized_macs_union[*count]))
break;
(*count)++;
}
-#endif /* CONFIG_WPS2 */
return (const u8 *) reg->authorized_macs_union;
}
@@ -667,6 +665,7 @@ wps_registrar_init(struct wps_context *wps,
reg->sel_reg_config_methods_override = -1;
reg->static_wep_only = cfg->static_wep_only;
reg->dualband = cfg->dualband;
+ reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
if (wps_set_ie(reg)) {
wps_registrar_deinit(reg);
@@ -677,6 +676,22 @@ wps_registrar_init(struct wps_context *wps,
}
+void wps_registrar_flush(struct wps_registrar *reg)
+{
+ if (reg == NULL)
+ return;
+ wps_free_pins(&reg->pins);
+ wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, 0);
+ wps_free_pbc_sessions(reg->pbc_sessions);
+ reg->pbc_sessions = NULL;
+ wps_free_devices(reg->devices);
+ reg->devices = NULL;
+#ifdef WPS_WORKAROUNDS
+ reg->pbc_ignore_start.sec = 0;
+#endif /* WPS_WORKAROUNDS */
+}
+
+
/**
* wps_registrar_deinit - Deinitialize WPS Registrar data
* @reg: Registrar data from wps_registrar_init()
@@ -687,11 +702,8 @@ void wps_registrar_deinit(struct wps_registrar *reg)
return;
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
- wps_free_pins(&reg->pins);
- wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, 0);
- wps_free_pbc_sessions(reg->pbc_sessions);
+ wps_registrar_flush(reg);
wpabuf_free(reg->extra_cred);
- wps_free_devices(reg->devices);
os_free(reg);
}
@@ -746,7 +758,7 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
if (timeout) {
p->flags |= PIN_EXPIRES;
- os_get_time(&p->expiration);
+ os_get_reltime(&p->expiration);
p->expiration.sec += timeout;
}
@@ -766,7 +778,7 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
else
wps_registrar_add_authorized_mac(
reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
wps_registrar_set_selected_timeout,
@@ -788,20 +800,20 @@ static void wps_registrar_remove_pin(struct wps_registrar *reg,
addr = pin->enrollee_addr;
wps_registrar_remove_authorized_mac(reg, addr);
wps_remove_pin(pin);
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
}
static void wps_registrar_expire_pins(struct wps_registrar *reg)
{
struct wps_uuid_pin *pin, *prev;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
{
if ((pin->flags & PIN_EXPIRES) &&
- os_time_before(&pin->expiration, &now)) {
+ os_reltime_before(&pin->expiration, &now)) {
wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
pin->uuid, WPS_UUID_LEN);
wps_registrar_remove_pin(reg, pin);
@@ -827,7 +839,7 @@ static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,
{
if (dev_pw && pin->pin &&
(dev_pw_len != pin->pin_len ||
- os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0))
+ os_memcmp_const(dev_pw, pin->pin, dev_pw_len) != 0))
continue; /* different PIN */
if (pin->wildcard_uuid) {
wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
@@ -951,7 +963,7 @@ static void wps_registrar_stop_pbc(struct wps_registrar *reg)
os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
wps_registrar_remove_authorized_mac(reg,
(u8 *) "\xff\xff\xff\xff\xff\xff");
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
}
@@ -999,8 +1011,9 @@ int wps_registrar_button_pushed(struct wps_registrar *reg,
os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
wps_registrar_add_authorized_mac(reg,
(u8 *) "\xff\xff\xff\xff\xff\xff");
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
+ wps_pbc_active_event(reg->wps);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
@@ -1014,6 +1027,7 @@ static void wps_registrar_pbc_completed(struct wps_registrar *reg)
wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode");
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
wps_registrar_stop_pbc(reg);
+ wps_pbc_disable_event(reg->wps);
}
@@ -1022,7 +1036,7 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg)
wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
reg->selected_registrar = 0;
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
}
@@ -1033,7 +1047,9 @@ void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
wps_registrar_remove_pbc_session(registrar,
uuid_e, NULL);
wps_registrar_pbc_completed(registrar);
- os_get_time(&registrar->pbc_ignore_start);
+#ifdef WPS_WORKAROUNDS
+ os_get_reltime(&registrar->pbc_ignore_start);
+#endif /* WPS_WORKAROUNDS */
os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN);
} else {
wps_registrar_pin_completed(registrar);
@@ -1136,9 +1152,9 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
#ifdef WPS_WORKAROUNDS
if (reg->pbc_ignore_start.sec &&
os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) {
- struct os_time now, dur;
- os_get_time(&now);
- os_time_sub(&now, &reg->pbc_ignore_start, &dur);
+ struct os_reltime now, dur;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &reg->pbc_ignore_start, &dur);
if (dur.sec >= 0 && dur.sec < 5) {
wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation "
"based on Probe Request from the Enrollee "
@@ -1159,13 +1175,14 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
}
-static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
- const u8 *psk, size_t psk_len)
+int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
+ const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len)
{
if (reg->new_psk_cb == NULL)
return 0;
- return reg->new_psk_cb(reg->cb_ctx, mac_addr, psk, psk_len);
+ return reg->new_psk_cb(reg->cb_ctx, mac_addr, p2p_dev_addr, psk,
+ psk_len);
}
@@ -1205,10 +1222,8 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg)
if (reg->selected_registrar) {
methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
if (reg->pbc)
wps_set_pushbutton(&methods, reg->wps->config_methods);
}
@@ -1263,7 +1278,7 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_sel_reg_dev_password_id(reg, beacon) ||
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)) ||
+ (reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon, 0)) ||
wps_build_wfa_ext(beacon, 0, auth_macs, count) ||
wps_build_vendor_ext(&reg->wps->dev, beacon)) {
wpabuf_free(beacon);
@@ -1293,7 +1308,7 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_uuid_e(probe, reg->wps->uuid) ||
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)) ||
+ (reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe, 0)) ||
wps_build_wfa_ext(probe, 0, auth_macs, count) ||
wps_build_vendor_ext(&reg->wps->dev, probe)) {
wpabuf_free(beacon);
@@ -1341,7 +1356,7 @@ static int wps_get_dev_password(struct wps_data *wps)
const u8 *pin;
size_t pin_len = 0;
- os_free(wps->dev_password);
+ bin_clear_free(wps->dev_password, wps->dev_password_len);
wps->dev_password = NULL;
if (wps->pbc) {
@@ -1350,18 +1365,40 @@ static int wps_get_dev_password(struct wps_data *wps)
pin_len = 8;
#ifdef CONFIG_WPS_NFC
} else if (wps->nfc_pw_token) {
+ if (wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
+ {
+ wpa_printf(MSG_DEBUG, "WPS: Using NFC connection "
+ "handover and abbreviated WPS handshake "
+ "without Device Password");
+ return 0;
+ }
wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC "
"Password Token");
pin = wps->nfc_pw_token->dev_pw;
pin_len = wps->nfc_pw_token->dev_pw_len;
+ } else if (wps->dev_pw_id >= 0x10 &&
+ wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id &&
+ wps->wps->ap_nfc_dev_pw) {
+ wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from own NFC Password Token");
+ pin = wpabuf_head(wps->wps->ap_nfc_dev_pw);
+ pin_len = wpabuf_len(wps->wps->ap_nfc_dev_pw);
#endif /* CONFIG_WPS_NFC */
} else {
pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
&pin_len);
+ if (pin && wps->dev_pw_id >= 0x10) {
+ wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device "
+ "Password ID, but PIN found");
+ /*
+ * See whether Enrollee is willing to use PIN instead.
+ */
+ wps->dev_pw_id = DEV_PW_DEFAULT;
+ }
}
if (pin == NULL) {
wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
- "the Enrollee");
+ "the Enrollee (context %p registrar %p)",
+ wps->wps, wps->wps->registrar);
wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
&wps->peer_dev);
return -1;
@@ -1518,18 +1555,6 @@ static int wps_build_cred_network_key(struct wpabuf *msg,
}
-static int wps_build_cred_mac_addr(struct wpabuf *msg,
- const struct wps_credential *cred)
-{
- wpa_printf(MSG_DEBUG, "WPS: * MAC Address (" MACSTR ")",
- MAC2STR(cred->mac_addr));
- wpabuf_put_be16(msg, ATTR_MAC_ADDR);
- wpabuf_put_be16(msg, ETH_ALEN);
- wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
- return 0;
-}
-
-
static int wps_build_credential(struct wpabuf *msg,
const struct wps_credential *cred)
{
@@ -1538,7 +1563,7 @@ static int wps_build_credential(struct wpabuf *msg,
wps_build_cred_auth_type(msg, cred) ||
wps_build_cred_encr_type(msg, cred) ||
wps_build_cred_network_key(msg, cred) ||
- wps_build_cred_mac_addr(msg, cred))
+ wps_build_mac_addr(msg, cred->mac_addr))
return -1;
return 0;
}
@@ -1587,8 +1612,6 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->auth_type = WPS_AUTH_WPAPSK;
else if (wps->auth_type & WPS_AUTH_OPEN)
wps->auth_type = WPS_AUTH_OPEN;
- else if (wps->auth_type & WPS_AUTH_SHARED)
- wps->auth_type = WPS_AUTH_SHARED;
else {
wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x",
wps->auth_type);
@@ -1608,10 +1631,12 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
return -1;
}
} else {
- if (wps->encr_type & WPS_ENCR_WEP)
- wps->encr_type = WPS_ENCR_WEP;
- else if (wps->encr_type & WPS_ENCR_NONE)
+ if (wps->encr_type & WPS_ENCR_NONE)
wps->encr_type = WPS_ENCR_NONE;
+#ifdef CONFIG_TESTING_OPTIONS
+ else if (wps->encr_type & WPS_ENCR_WEP)
+ wps->encr_type = WPS_ENCR_WEP;
+#endif /* CONFIG_TESTING_OPTIONS */
else {
wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
"type for non-WPA/WPA2 mode");
@@ -1628,8 +1653,12 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
!wps->wps->registrar->disable_auto_conf) {
u8 r[16];
/* Generate a random passphrase */
- if (random_get_bytes(r, sizeof(r)) < 0)
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(r, sizeof(r)) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
return -1;
+ }
os_free(wps->new_psk);
wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
if (wps->new_psk == NULL)
@@ -1642,13 +1671,15 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->new_psk, wps->new_psk_len);
os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
wps->cred.key_len = wps->new_psk_len;
- } else if (wps->use_psk_key && wps->wps->psk_set) {
+ } else if (!wps->wps->registrar->force_per_enrollee_psk &&
+ wps->use_psk_key && wps->wps->psk_set) {
char hex[65];
wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
os_memcpy(wps->cred.key, hex, 32 * 2);
wps->cred.key_len = 32 * 2;
- } else if (wps->wps->network_key) {
+ } else if (!wps->wps->registrar->force_per_enrollee_psk &&
+ wps->wps->network_key) {
os_memcpy(wps->cred.key, wps->wps->network_key,
wps->wps->network_key_len);
wps->cred.key_len = wps->wps->network_key_len;
@@ -1660,7 +1691,10 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->new_psk = os_malloc(wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
- if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
os_free(wps->new_psk);
wps->new_psk = NULL;
return -1;
@@ -1768,6 +1802,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
static struct wpabuf * wps_build_m2(struct wps_data *wps)
{
struct wpabuf *msg;
+ int config_in_m2 = 0;
if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0)
return NULL;
@@ -1792,19 +1827,47 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
wps_build_conn_type_flags(wps, msg) ||
wps_build_config_methods_r(wps->wps->registrar, msg) ||
wps_build_device_attrs(&wps->wps->dev, msg) ||
- wps_build_rf_bands(&wps->wps->dev, msg) ||
+ wps_build_rf_bands(&wps->wps->dev, msg,
+ wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
wps_build_assoc_state(wps, msg) ||
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_authenticator(wps, msg)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+#ifdef CONFIG_WPS_NFC
+ if (wps->nfc_pw_token && wps->nfc_pw_token->pk_hash_provided_oob &&
+ wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
+ /*
+ * Use abbreviated handshake since public key hash allowed
+ * Enrollee to validate our public key similarly to how Enrollee
+ * public key was validated. There is no need to validate Device
+ * Password in this case.
+ */
+ struct wpabuf *plain = wpabuf_alloc(500);
+ if (plain == NULL ||
+ wps_build_cred(wps, plain) ||
+ wps_build_key_wrap_auth(wps, plain) ||
+ wps_build_encr_settings(wps, msg, plain)) {
+ wpabuf_free(msg);
+ wpabuf_free(plain);
+ return NULL;
+ }
+ wpabuf_free(plain);
+ config_in_m2 = 1;
+ }
+#endif /* CONFIG_WPS_NFC */
+
+ if (wps_build_authenticator(wps, msg)) {
wpabuf_free(msg);
return NULL;
}
wps->int_reg = 1;
- wps->state = RECV_M3;
+ wps->state = config_in_m2 ? RECV_DONE : RECV_M3;
return msg;
}
@@ -1833,7 +1896,8 @@ static struct wpabuf * wps_build_m2d(struct wps_data *wps)
wps_build_conn_type_flags(wps, msg) ||
wps_build_config_methods_r(wps->wps->registrar, msg) ||
wps_build_device_attrs(&wps->wps->dev, msg) ||
- wps_build_rf_bands(&wps->wps->dev, msg) ||
+ wps_build_rf_bands(&wps->wps->dev, msg,
+ wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
wps_build_assoc_state(wps, msg) ||
wps_build_config_error(msg, err) ||
wps_build_os_version(&wps->wps->dev, msg) ||
@@ -2167,11 +2231,11 @@ static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 0, 1);
+ wps_pwd_auth_fail_event(wps->wps, 0, 1, wps->mac_addr_e);
return -1;
}
@@ -2207,12 +2271,12 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does "
"not match with the pre-committed value");
wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 0, 2);
+ wps_pwd_auth_fail_event(wps->wps, 0, 2, wps->mac_addr_e);
return -1;
}
@@ -2514,9 +2578,13 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
if (wps->dev_pw_id < 0x10 &&
wps->dev_pw_id != DEV_PW_DEFAULT &&
+ wps->dev_pw_id != DEV_PW_P2PS_DEFAULT &&
wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
+#ifdef CONFIG_WPS_NFC
+ wps->dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
+#endif /* CONFIG_WPS_NFC */
(wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
!wps->wps->registrar->pbc)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
@@ -2526,14 +2594,17 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
}
#ifdef CONFIG_WPS_NFC
- if (wps->dev_pw_id >= 0x10) {
+ if (wps->dev_pw_id >= 0x10 ||
+ wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
struct wps_nfc_pw_token *token;
const u8 *addr[1];
u8 hash[WPS_HASH_LEN];
+ wpa_printf(MSG_DEBUG, "WPS: Searching for NFC token match for id=%d (ctx %p registrar %p)",
+ wps->dev_pw_id, wps->wps, wps->wps->registrar);
token = wps_get_nfc_pw_token(
&wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
- if (token) {
+ if (token && token->peer_pk_hash_known) {
wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
"Password Token");
dl_list_del(&token->list);
@@ -2541,12 +2612,24 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
addr[0] = attr->public_key;
sha256_vector(1, addr, &attr->public_key_len, hash);
- if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash,
- WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+ if (os_memcmp_const(hash,
+ wps->nfc_pw_token->pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN) != 0) {
wpa_printf(MSG_ERROR, "WPS: Public Key hash "
"mismatch");
- return WPS_FAILURE;
+ wps->state = SEND_M2D;
+ wps->config_error =
+ WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
+ return WPS_CONTINUE;
}
+ } else if (token) {
+ wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
+ "Password Token (no peer PK hash)");
+ wps->nfc_pw_token = token;
+ } else if (wps->dev_pw_id >= 0x10 &&
+ wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id &&
+ wps->wps->ap_nfc_dev_pw) {
+ wpa_printf(MSG_DEBUG, "WPS: Found match with own NFC Password Token");
}
}
#endif /* CONFIG_WPS_NFC */
@@ -2564,7 +2647,7 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
wps_pbc_overlap_event(wps->wps);
wps_fail_event(wps->wps, WPS_M1,
WPS_CFG_MULTIPLE_PBC_DETECTED,
- WPS_EI_NO_ERROR);
+ WPS_EI_NO_ERROR, wps->mac_addr_e);
wps->wps->registrar->force_pbc_overlap = 1;
return WPS_CONTINUE;
}
@@ -2894,7 +2977,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m3(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M3, wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case WPS_M5:
if (wps_validate_m5(msg) < 0)
@@ -2902,7 +2985,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m5(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M5, wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case WPS_M7:
if (wps_validate_m7(msg) < 0)
@@ -2910,7 +2993,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m7(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M7, wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
@@ -3056,19 +3139,19 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
switch (old_state) {
case RECV_M3:
wps_fail_event(wps->wps, WPS_M2, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case RECV_M5:
wps_fail_event(wps->wps, WPS_M4, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case RECV_M7:
wps_fail_event(wps->wps, WPS_M6, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case RECV_DONE:
wps_fail_event(wps->wps, WPS_M8, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
default:
break;
@@ -3164,7 +3247,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
if (wps->new_psk) {
if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e,
- wps->new_psk, wps->new_psk_len)) {
+ wps->p2p_dev_addr, wps->new_psk,
+ wps->new_psk_len)) {
wpa_printf(MSG_DEBUG, "WPS: Failed to configure the "
"new PSK");
}
@@ -3180,7 +3264,9 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
wps->uuid_e,
wps->p2p_dev_addr);
wps_registrar_pbc_completed(wps->wps->registrar);
- os_get_time(&wps->wps->registrar->pbc_ignore_start);
+#ifdef WPS_WORKAROUNDS
+ os_get_reltime(&wps->wps->registrar->pbc_ignore_start);
+#endif /* WPS_WORKAROUNDS */
os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e,
WPS_UUID_LEN);
} else {
@@ -3189,7 +3275,7 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
/* TODO: maintain AuthorizedMACs somewhere separately for each ER and
* merge them into APs own list.. */
- wps_success_event(wps->wps);
+ wps_success_event(wps->wps, wps->mac_addr_e);
return WPS_DONE;
}
@@ -3258,7 +3344,7 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
wps->state = SEND_WSC_NACK;
wps_fail_event(wps->wps, WPS_WSC_DONE,
wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
}
return ret;
default:
@@ -3283,7 +3369,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
"unselect internal Registrar");
reg->selected_registrar = 0;
reg->pbc = 0;
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
}
@@ -3355,7 +3441,8 @@ static void wps_registrar_sel_reg_union(struct wps_registrar *reg)
* This function is called when selected registrar state changes, e.g., when an
* AP receives a SetSelectedRegistrar UPnP message.
*/
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
+ u16 dev_pw_id)
{
wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
@@ -3371,15 +3458,14 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
u16 methods;
methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
if (reg->pbc) {
reg->sel_reg_dev_password_id_override =
DEV_PW_PUSHBUTTON;
wps_set_pushbutton(&methods, reg->wps->config_methods);
- }
+ } else if (dev_pw_id)
+ reg->sel_reg_dev_password_id_override = dev_pw_id;
wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
"(pbc=%d)", reg->pbc);
reg->sel_reg_config_methods_override = methods;
@@ -3423,7 +3509,7 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
d->dev.model_name ? d->dev.model_name : "",
d->dev.model_number ? d->dev.model_number : "",
d->dev.serial_number ? d->dev.serial_number : "");
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -3434,8 +3520,7 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
int wps_registrar_config_ap(struct wps_registrar *reg,
struct wps_credential *cred)
{
-#ifdef CONFIG_WPS2
- printf("encr_type=0x%x\n", cred->encr_type);
+ wpa_printf(MSG_DEBUG, "WPS: encr_type=0x%x", cred->encr_type);
if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP |
WPS_ENCR_AES))) {
if (cred->encr_type & WPS_ENCR_WEP) {
@@ -3462,7 +3547,6 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
"WPAPSK+WPA2PSK");
cred->auth_type |= WPS_AUTH_WPA2PSK;
}
-#endif /* CONFIG_WPS2 */
if (reg->wps->cred_cb)
return reg->wps->cred_cb(reg->wps->cb_ctx, cred);
@@ -3475,23 +3559,39 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
const u8 *pubkey_hash, u16 pw_id,
- const u8 *dev_pw, size_t dev_pw_len)
+ const u8 *dev_pw, size_t dev_pw_len,
+ int pk_hash_provided_oob)
{
struct wps_nfc_pw_token *token;
if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN)
return -1;
+ if (pw_id == DEV_PW_NFC_CONNECTION_HANDOVER &&
+ (pubkey_hash == NULL || !pk_hash_provided_oob)) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected NFC Password Token "
+ "addition - missing public key hash");
+ return -1;
+ }
+
wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, pw_id);
token = os_zalloc(sizeof(*token));
if (token == NULL)
return -1;
- os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+ token->peer_pk_hash_known = pubkey_hash != NULL;
+ if (pubkey_hash)
+ os_memcpy(token->pubkey_hash, pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN);
token->pw_id = pw_id;
- os_memcpy(token->dev_pw, dev_pw, dev_pw_len);
- token->dev_pw_len = dev_pw_len;
+ token->pk_hash_provided_oob = pk_hash_provided_oob;
+ if (dev_pw) {
+ wpa_snprintf_hex_uppercase((char *) token->dev_pw,
+ sizeof(token->dev_pw),
+ dev_pw, dev_pw_len);
+ token->dev_pw_len = dev_pw_len * 2;
+ }
dl_list_add(&reg->nfc_pw_tokens, &token->list);
@@ -3499,12 +3599,15 @@ int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
reg->pbc = 0;
wps_registrar_add_authorized_mac(reg,
(u8 *) "\xff\xff\xff\xff\xff\xff");
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, pw_id);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
wps_registrar_set_selected_timeout,
reg, NULL);
+ wpa_printf(MSG_DEBUG, "WPS: Added NFC Device Password %u to Registrar",
+ pw_id);
+
return 0;
}
@@ -3517,8 +3620,7 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
u16 id;
size_t dev_pw_len;
- if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
- WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+ if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
WPS_OOB_DEVICE_PASSWORD_LEN)
return -1;
@@ -3537,7 +3639,7 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len);
return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw,
- dev_pw_len);
+ dev_pw_len, 0);
}
@@ -3546,7 +3648,15 @@ void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
{
wps_registrar_remove_authorized_mac(reg,
(u8 *) "\xff\xff\xff\xff\xff\xff");
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
+
+ /*
+ * Free the NFC password token if it was used only for a single protocol
+ * run. The static handover case uses the same password token multiple
+ * times, so do not free that case here.
+ */
+ if (token->peer_pk_hash_known)
+ os_free(token);
}
#endif /* CONFIG_WPS_NFC */
diff --git a/contrib/wpa/src/wps/wps_upnp.c b/contrib/wpa/src/wps/wps_upnp.c
index 09a46a2..933d734 100644
--- a/contrib/wpa/src/wps/wps_upnp.c
+++ b/contrib/wpa/src/wps/wps_upnp.c
@@ -227,6 +227,8 @@ void format_date(struct wpabuf *buf)
t = time(NULL);
date = gmtime(&t);
+ if (date == NULL)
+ return;
wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT",
&weekday_str[date->tm_wday * 4], date->tm_mday,
&month_str[date->tm_mon * 4], date->tm_year + 1900,
@@ -249,13 +251,16 @@ void format_date(struct wpabuf *buf)
* use for constructing UUIDs for subscriptions. Presumably any method from
* rfc4122 is good enough; I've chosen random number method.
*/
-static void uuid_make(u8 uuid[UUID_LEN])
+static int uuid_make(u8 uuid[UUID_LEN])
{
- os_get_random(uuid, UUID_LEN);
+ if (os_get_random(uuid, UUID_LEN) < 0)
+ return -1;
/* Replace certain bits as specified in rfc4122 or X.667 */
uuid[6] &= 0x0f; uuid[6] |= (4 << 4); /* version 4 == random gen */
uuid[8] &= 0x3f; uuid[8] |= 0x80;
+
+ return 0;
}
@@ -322,11 +327,9 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
url_len -= 7;
/* Make a copy of the string to allow modification during parsing */
- scratch_mem = os_malloc(url_len + 1);
+ scratch_mem = dup_binstr(url, url_len);
if (scratch_mem == NULL)
goto fail;
- os_memcpy(scratch_mem, url, url_len);
- scratch_mem[url_len] = '\0';
wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem);
host = scratch_mem;
path = os_strchr(host, '/');
@@ -434,23 +437,6 @@ static void subscr_addr_list_create(struct subscription *s,
}
-int send_wpabuf(int fd, struct wpabuf *buf)
-{
- wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message",
- (unsigned long) wpabuf_len(buf));
- errno = 0;
- if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) !=
- (int) wpabuf_len(buf)) {
- wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: "
- "errno=%d (%s)",
- errno, strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-
static void wpabuf_put_property(struct wpabuf *buf, const char *name,
const char *value)
{
@@ -482,14 +468,14 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
const char *format_tail = "</e:propertyset>\n";
- struct os_time now;
+ struct os_reltime now;
if (dl_list_empty(&sm->subscriptions)) {
/* optimize */
return;
}
- if (os_get_time(&now) == 0) {
+ if (os_get_reltime(&now) == 0) {
if (now.sec != sm->last_event_sec) {
sm->last_event_sec = now.sec;
sm->num_events_in_sec = 1;
@@ -613,7 +599,10 @@ 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);
- wps_build_wfa_ext(msg, 0, NULL, 0);
+ if (wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
return msg;
}
@@ -714,10 +703,12 @@ struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
if (dl_list_len(&sm->subscriptions) >= MAX_SUBSCRIPTIONS) {
s = dl_list_first(&sm->subscriptions, struct subscription,
list);
- wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, "
- "trashing oldest");
- dl_list_del(&s->list);
- subscription_destroy(s);
+ if (s) {
+ wpa_printf(MSG_INFO,
+ "WPS UPnP: Too many subscriptions, trashing oldest");
+ dl_list_del(&s->list);
+ subscription_destroy(s);
+ }
}
s = os_zalloc(sizeof(*s));
@@ -728,7 +719,10 @@ struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
s->sm = sm;
s->timeout_time = expire;
- uuid_make(s->uuid);
+ if (uuid_make(s->uuid) < 0) {
+ subscription_destroy(s);
+ return NULL;
+ }
subscr_addr_list_create(s, callback_urls);
if (dl_list_empty(&s->addr_list)) {
wpa_printf(MSG_DEBUG, "WPS UPnP: No valid callback URLs in "
@@ -984,6 +978,7 @@ static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
web_listener_stop(sm);
+ ssdp_listener_stop(sm);
upnp_wps_free_msearchreply(&sm->msearch_replies);
upnp_wps_free_subscriptions(&sm->subscriptions, NULL);
@@ -997,7 +992,6 @@ static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
if (sm->multicast_sd >= 0)
close(sm->multicast_sd);
sm->multicast_sd = -1;
- ssdp_listener_stop(sm);
sm->started = 0;
}
diff --git a/contrib/wpa/src/wps/wps_upnp_ap.c b/contrib/wpa/src/wps/wps_upnp_ap.c
index 54ed98f..2949f14 100644
--- a/contrib/wpa/src/wps/wps_upnp_ap.c
+++ b/contrib/wpa/src/wps/wps_upnp_ap.c
@@ -22,7 +22,7 @@ static void upnp_er_set_selected_timeout(void *eloop_ctx, void *timeout_ctx)
struct wps_registrar *reg = timeout_ctx;
wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar from ER timed out");
s->selected_registrar = 0;
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
}
@@ -61,17 +61,15 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
os_memcpy(s->authorized_macs, attr.authorized_macs,
count * ETH_ALEN);
} else if (!attr.version2) {
-#ifdef CONFIG_WPS2
wpa_printf(MSG_DEBUG, "WPS: Add broadcast "
"AuthorizedMACs for WPS 1.0 ER");
os_memset(s->authorized_macs, 0xff, ETH_ALEN);
-#endif /* CONFIG_WPS2 */
}
eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
upnp_er_set_selected_timeout, s, reg);
}
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
return 0;
}
@@ -83,5 +81,5 @@ void upnp_er_remove_notification(struct wps_registrar *reg,
s->selected_registrar = 0;
eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
if (reg)
- wps_registrar_selected_registrar_changed(reg);
+ wps_registrar_selected_registrar_changed(reg, 0);
}
diff --git a/contrib/wpa/src/wps/wps_upnp_i.h b/contrib/wpa/src/wps/wps_upnp_i.h
index 7f3c561..f289fe6 100644
--- a/contrib/wpa/src/wps/wps_upnp_i.h
+++ b/contrib/wpa/src/wps/wps_upnp_i.h
@@ -158,7 +158,6 @@ void subscription_destroy(struct subscription *s);
struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
const u8 uuid[UUID_LEN]);
void subscr_addr_delete(struct subscr_addr *a);
-int send_wpabuf(int fd, struct wpabuf *buf);
int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
u8 mac[ETH_ALEN]);
@@ -171,7 +170,7 @@ void ssdp_listener_stop(struct upnp_wps_device_sm *sm);
int ssdp_listener_start(struct upnp_wps_device_sm *sm);
int ssdp_listener_open(void);
int add_ssdp_network(const char *net_if);
-int ssdp_open_multicast_sock(u32 ip_addr);
+int ssdp_open_multicast_sock(u32 ip_addr, const char *forced_ifname);
int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
/* wps_upnp_web.c */
diff --git a/contrib/wpa/src/wps/wps_upnp_ssdp.c b/contrib/wpa/src/wps/wps_upnp_ssdp.c
index 17a8207..26a740d 100644
--- a/contrib/wpa/src/wps/wps_upnp_ssdp.c
+++ b/contrib/wpa/src/wps/wps_upnp_ssdp.c
@@ -3,7 +3,7 @@
* Copyright (c) 2000-2003 Intel Corporation
* Copyright (c) 2006-2007 Sony Corporation
* Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
*
* See wps_upnp.c for more details on licensing and code history.
*/
@@ -13,6 +13,9 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/route.h>
+#ifdef __linux__
+#include <net/if.h>
+#endif /* __linux__ */
#include "common.h"
#include "uuid.h"
@@ -131,6 +134,8 @@ next_advertisement(struct upnp_wps_device_sm *sm,
*islast = 0;
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
+ if (!iface)
+ return NULL;
uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
msg = wpabuf_alloc(800); /* more than big enough */
if (msg == NULL)
@@ -312,7 +317,8 @@ static void advertisement_state_machine_handler(void *eloop_data,
* (see notes above)
*/
next_timeout_msec = 0;
- os_get_random((void *) &r, sizeof(r));
+ if (os_get_random((void *) &r, sizeof(r)) < 0)
+ r = 32768;
next_timeout_sec = UPNP_CACHE_SEC / 4 +
(((UPNP_CACHE_SEC / 4) * r) >> 16);
sm->advertise_count++;
@@ -584,6 +590,8 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
&sm->interfaces,
struct upnp_wps_device_interface,
list);
+ if (!iface)
+ continue;
data += os_strlen("uuid:");
uuid_bin2str(iface->wps->uuid, uuid_string,
sizeof(uuid_string));
@@ -854,7 +862,7 @@ fail:
}
-int ssdp_open_multicast_sock(u32 ip_addr)
+int ssdp_open_multicast_sock(u32 ip_addr, const char *forced_ifname)
{
int sd;
/* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
@@ -865,6 +873,22 @@ int ssdp_open_multicast_sock(u32 ip_addr)
if (sd < 0)
return -1;
+ if (forced_ifname) {
+#ifdef __linux__
+ struct ifreq req;
+ os_memset(&req, 0, sizeof(req));
+ os_strlcpy(req.ifr_name, forced_ifname, sizeof(req.ifr_name));
+ if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &req,
+ sizeof(req)) < 0) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Failed to bind "
+ "multicast socket to ifname %s: %s",
+ forced_ifname, strerror(errno));
+ close(sd);
+ return -1;
+ }
+#endif /* __linux__ */
+ }
+
#if 0 /* maybe ok if we sometimes block on writes */
if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) {
close(sd);
@@ -924,7 +948,7 @@ int ssdp_open_multicast_sock(u32 ip_addr)
*/
int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
{
- sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
+ sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr, NULL);
if (sm->multicast_sd < 0)
return -1;
return 0;
diff --git a/contrib/wpa/src/wps/wps_upnp_web.c b/contrib/wpa/src/wps/wps_upnp_web.c
index ce0bede..b1cf571 100644
--- a/contrib/wpa/src/wps/wps_upnp_web.c
+++ b/contrib/wpa/src/wps/wps_upnp_web.c
@@ -179,15 +179,12 @@ static const char *wps_device_xml_postfix =
/* format_wps_device_xml -- produce content of "file" wps_device.xml
* (UPNP_WPS_DEVICE_XML_FILE)
*/
-static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
+static void format_wps_device_xml(struct upnp_wps_device_interface *iface,
+ struct upnp_wps_device_sm *sm,
struct wpabuf *buf)
{
const char *s;
char uuid_string[80];
- struct upnp_wps_device_interface *iface;
-
- iface = dl_list_first(&sm->interfaces,
- struct upnp_wps_device_interface, list);
wpabuf_put_str(buf, wps_device_xml_prefix);
@@ -319,13 +316,15 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
+ if (iface == NULL) {
+ http_request_deinit(hreq);
+ return;
+ }
/*
* It is not required that filenames be case insensitive but it is
* allowed and cannot hurt here.
*/
- if (filename == NULL)
- filename = "(null)"; /* just in case */
if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
req = GET_DEVICE_XML_FILE;
@@ -393,7 +392,7 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
switch (req) {
case GET_DEVICE_XML_FILE:
- format_wps_device_xml(sm, buf);
+ format_wps_device_xml(iface, sm, buf);
break;
case GET_SCPD_XML_FILE:
wpabuf_put_str(buf, wps_scpd_xml);
@@ -421,13 +420,14 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
- peer = &iface->peer;
wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
- if (iface->ctx->ap_pin == NULL)
+ if (!iface || iface->ctx->ap_pin == NULL)
return HTTP_INTERNAL_SERVER_ERROR;
+ peer = &iface->peer;
+
/*
* Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
* registration over UPnP with the AP acting as an Enrollee. It should
@@ -475,6 +475,8 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
+ if (!iface)
+ return HTTP_INTERNAL_SERVER_ERROR;
/*
* PutMessage is used by external UPnP-based Registrar to perform WPS
@@ -948,7 +950,7 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
end = os_strchr(h, '\n');
- for (; end != NULL; h = end + 1) {
+ while (end) {
/* Option line by option line */
h = end + 1;
end = os_strchr(h, '\n');
@@ -996,13 +998,11 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
h++;
len = end - h;
os_free(callback_urls);
- callback_urls = os_malloc(len + 1);
+ callback_urls = dup_binstr(h, len);
if (callback_urls == NULL) {
ret = HTTP_INTERNAL_SERVER_ERROR;
goto error;
}
- os_memcpy(callback_urls, h, len);
- callback_urls[len] = 0;
continue;
}
/* SID is only for renewal */
@@ -1157,7 +1157,7 @@ static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
end = os_strchr(h, '\n');
- for (; end != NULL; h = end + 1) {
+ while (end) {
/* Option line by option line */
h = end + 1;
end = os_strchr(h, '\n');
@@ -1175,7 +1175,6 @@ static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
.....
}
#endif
- /* SID is only for renewal */
match = "SID:";
match_len = os_strlen(match);
if (os_strncasecmp(h, match, match_len) == 0) {
@@ -1198,6 +1197,20 @@ static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
got_uuid = 1;
continue;
}
+
+ match = "NT:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ ret = HTTP_BAD_REQUEST;
+ goto send_msg;
+ }
+
+ match = "CALLBACK:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ ret = HTTP_BAD_REQUEST;
+ goto send_msg;
+ }
}
if (got_uuid) {
@@ -1211,6 +1224,10 @@ static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
sa->domain_and_port : "-null-");
dl_list_del(&s->list);
subscription_destroy(s);
+ } else {
+ wpa_printf(MSG_INFO, "WPS UPnP: Could not find matching subscription to unsubscribe");
+ ret = HTTP_PRECONDITION_FAILED;
+ goto send_msg;
}
} else {
wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
diff --git a/contrib/wpa/src/wps/wps_validate.c b/contrib/wpa/src/wps/wps_validate.c
index e366256..1c6a14b 100644
--- a/contrib/wpa/src/wps/wps_validate.c
+++ b/contrib/wpa/src/wps/wps_validate.c
@@ -267,7 +267,7 @@ static int wps_validate_config_error(const u8 *config_error, int mandatory)
return 0;
}
val = WPA_GET_BE16(config_error);
- if (val > 18) {
+ if (val > 20) {
wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration Error "
"attribute value 0x%04x", val);
return -1;
@@ -290,7 +290,7 @@ static int wps_validate_dev_password_id(const u8 *dev_password_id,
return 0;
}
val = WPA_GET_BE16(dev_password_id);
- if (val >= 0x0006 && val <= 0x000f) {
+ if (val >= 0x0008 && val <= 0x000f) {
wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Device Password ID "
"attribute value 0x%04x", val);
return -1;
diff --git a/contrib/wpa/wpa_supplicant/ChangeLog b/contrib/wpa/wpa_supplicant/ChangeLog
index 8abafb2..1ac79b4 100644
--- a/contrib/wpa/wpa_supplicant/ChangeLog
+++ b/contrib/wpa/wpa_supplicant/ChangeLog
@@ -1,5 +1,377 @@
ChangeLog for wpa_supplicant
+2015-03-15 - v2.4
+ * allow OpenSSL cipher configuration to be set for internal EAP server
+ (openssl_ciphers parameter)
+ * fixed number of small issues based on hwsim test case failures and
+ static analyzer reports
+ * P2P:
+ - add new=<0/1> flag to P2P-DEVICE-FOUND events
+ - add passive channels in invitation response from P2P Client
+ - enable nl80211 P2P_DEVICE support by default
+ - fix regresssion in disallow_freq preventing search on social
+ channels
+ - fix regressions in P2P SD query processing
+ - try to re-invite with social operating channel if no common channels
+ in invitation
+ - allow cross connection on parent interface (this fixes number of
+ use cases with nl80211)
+ - add support for P2P services (P2PS)
+ - add p2p_go_ctwindow configuration parameter to allow GO CTWindow to
+ be configured
+ * increase postponing of EAPOL-Start by one second with AP/GO that
+ supports WPS 2.0 (this makes it less likely to trigger extra roundtrip
+ of identity frames)
+ * add support for PMKSA caching with SAE
+ * add support for control mesh BSS (IEEE 802.11s) operations
+ * fixed number of issues with D-Bus P2P commands
+ * fixed regression in ap_scan=2 special case for WPS
+ * fixed macsec_validate configuration
+ * add a workaround for incorrectly behaving APs that try to use
+ EAPOL-Key descriptor version 3 when the station supports PMF even if
+ PMF is not enabled on the AP
+ * allow TLS v1.1 and v1.2 to be negotiated by default; previous behavior
+ of disabling these can be configured to work around issues with broken
+ servers with phase1="tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1"
+ * add support for Suite B (128-bit and 192-bit level) key management and
+ cipher suites
+ * add WMM-AC support (WMM_AC_ADDTS/WMM_AC_DELTS)
+ * improved BSS Transition Management processing
+ * add support for neighbor report
+ * add support for link measurement
+ * fixed expiration of BSS entry with all-zeros BSSID
+ * add optional LAST_ID=x argument to LIST_NETWORK to allow all
+ configured networks to be listed even with huge number of network
+ profiles
+ * add support for EAP Re-Authentication Protocol (ERP)
+ * fixed EAP-IKEv2 fragmentation reassembly
+ * improved PKCS#11 configuration for OpenSSL
+ * set stdout to be line-buffered
+ * add TDLS channel switch configuration
+ * add support for MAC address randomization in scans with nl80211
+ * enable HT for IBSS if supported by the driver
+ * add BSSID black and white lists (bssid_blacklist, bssid_whitelist)
+ * add support for domain_suffix_match with GnuTLS
+ * add OCSP stapling client support with GnuTLS
+ * include peer certificate in EAP events even without a separate probe
+ operation; old behavior can be restored with cert_in_cb=0
+ * add peer ceritficate alt subject name to EAP events
+ (CTRL-EVENT-EAP-PEER-ALT)
+ * add domain_match network profile parameter (similar to
+ domain_suffix_match, but full match is required)
+ * enable AP/GO mode HT Tx STBC automatically based on driver support
+ * add ANQP-QUERY-DONE event to provide information on ANQP parsing
+ status
+ * allow passive scanning to be forced with passive_scan=1
+ * add a workaround for Linux packet socket behavior when interface is in
+ bridge
+ * increase 5 GHz band preference in BSS selection (estimate SNR, if info
+ not available from driver; estimate maximum throughput based on common
+ HT/VHT/specific TX rate support)
+ * add INTERWORKING_ADD_NETWORK ctrl_iface command; this can be used to
+ implement Interworking network selection behavior in upper layers
+ software components
+ * add optional reassoc_same_bss_optim=1 (disabled by default)
+ optimization to avoid unnecessary Authentication frame exchange
+ * extend TDLS frame padding workaround to cover all packets
+ * allow wpa_supplicant to recover nl80211 functionality if the cfg80211
+ module gets removed and reloaded without restarting wpa_supplicant
+ * allow hostapd DFS implementation to be used in wpa_supplicant AP mode
+
+2014-10-09 - v2.3
+ * fixed number of minor issues identified in static analyzer warnings
+ * fixed wfd_dev_info to be more careful and not read beyond the buffer
+ when parsing invalid information for P2P-DEVICE-FOUND
+ * extended P2P and GAS query operations to support drivers that have
+ maximum remain-on-channel time below 1000 ms (500 ms is the current
+ minimum supported value)
+ * added p2p_search_delay parameter to make the default p2p_find delay
+ configurable
+ * improved P2P operating channel selection for various multi-channel
+ concurrency cases
+ * fixed some TDLS failure cases to clean up driver state
+ * fixed dynamic interface addition cases with nl80211 to avoid adding
+ ifindex values to incorrect interface to skip foreign interface events
+ properly
+ * added TDLS workaround for some APs that may add extra data to the
+ end of a short frame
+ * fixed EAP-AKA' message parser with multiple AT_KDF attributes
+ * added configuration option (p2p_passphrase_len) to allow longer
+ passphrases to be generated for P2P groups
+ * fixed IBSS channel configuration in some corner cases
+ * improved HT/VHT/QoS parameter setup for TDLS
+ * modified D-Bus interface for P2P peers/groups
+ * started to use constant time comparison for various password and hash
+ values to reduce possibility of any externally measurable timing
+ differences
+ * extended explicit clearing of freed memory and expired keys to avoid
+ keeping private data in memory longer than necessary
+ * added optional scan_id parameter to the SCAN command to allow manual
+ scan requests for active scans for specific configured SSIDs
+ * fixed CTRL-EVENT-REGDOM-CHANGE event init parameter value
+ * added option to set Hotspot 2.0 Rel 2 update_identifier in network
+ configuration to support external configuration
+ * modified Android PNO functionality to send Probe Request frames only
+ for hidden SSIDs (based on scan_ssid=1)
+ * added generic mechanism for adding vendor elements into frames at
+ runtime (VENDOR_ELEM_ADD, VENDOR_ELEM_GET, VENDOR_ELEM_REMOVE)
+ * added fields to show unrecognized vendor elements in P2P_PEER
+ * removed EAP-TTLS/MSCHAPv2 interoperability workaround so that
+ MS-CHAP2-Success is required to be present regardless of
+ eap_workaround configuration
+ * modified EAP fast session resumption to allow results to be used only
+ with the same network block that generated them
+ * extended freq_list configuration to apply for sched_scan as well as
+ normal scan
+ * modified WPS to merge mixed-WPA/WPA2 credentials from a single session
+ * fixed nl80211/RTM_DELLINK processing when a P2P GO interface is
+ removed from a bridge
+ * fixed number of small P2P issues to make negotiations more robust in
+ corner cases
+ * added experimental support for using temporary, random local MAC
+ address (mac_addr and preassoc_mac_addr parameters); this is disabled
+ by default (i.e., previous behavior of using permanent address is
+ maintained if configuration is not changed)
+ * added D-Bus interface for setting/clearing WFD IEs
+ * fixed TDLS AID configuration for VHT
+ * modified -m<conf> configuration file to be used only for the P2P
+ non-netdev management device and do not load this for the default
+ station interface or load the station interface configuration for
+ the P2P management interface
+ * fixed external MAC address changes while wpa_supplicant is running
+ * started to enable HT (if supported by the driver) for IBSS
+ * fixed wpa_cli action script execution to use more robust mechanism
+ (CVE-2014-3686)
+
+2014-06-04 - v2.2
+ * added DFS indicator to get_capability freq
+ * added/fixed nl80211 functionality
+ - BSSID/frequency hint for driver-based BSS selection
+ - fix tearing down WDS STA interfaces
+ - support vendor specific driver command
+ (VENDOR <vendor id> <sub command id> [<hex formatted data>])
+ - GO interface teardown optimization
+ - allow beacon interval to be configured for IBSS
+ - add SHA256-based AKM suites to CONNECT/ASSOCIATE commands
+ * removed unused NFC_RX_HANDOVER_REQ and NFC_RX_HANDOVER_SEL control
+ interface commands (the more generic NFC_REPORT_HANDOVER is now used)
+ * fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding;
+ this fixes password with include UTF-8 characters that use
+ three-byte encoding EAP methods that use NtPasswordHash
+ * fixed couple of sequencies where radio work items could get stuck,
+ e.g., when rfkill blocking happens during scanning or when
+ scan-for-auth workaround is used
+ * P2P enhancements/fixes
+ - enable enable U-APSD on GO automatically if the driver indicates
+ support for this
+ - fixed some service discovery cases with broadcast queries not being
+ sent to all stations
+ - fixed Probe Request frame triggering invitation to trigger only a
+ single invitation instance even if multiple Probe Request frames are
+ received
+ - fixed a potential NULL pointer dereference crash when processing an
+ invalid Invitation Request frame
+ - add optional configuration file for the P2P_DEVICE parameters
+ - optimize scan for GO during persistent group invocation
+ - fix possible segmentation fault when PBC overlap is detected while
+ using a separate P2P group interface
+ - improve GO Negotiation robustness by allowing GO Negotiation
+ Confirmation to be retransmitted
+ - do use freed memory on device found event when P2P NFC
+ * added phase1 network parameter options for disabling TLS v1.1 and v1.2
+ to allow workarounds with misbehaving AAA servers
+ (tls_disable_tlsv1_1=1 and tls_disable_tlsv1_2=1)
+ * added support for OCSP stapling to validate AAA server certificate
+ during TLS exchange
+ * Interworking/Hotspot 2.0 enhancements
+ - prefer the last added network in Interworking connection to make the
+ behavior more consistent with likely user expectation
+ - roaming partner configuration (roaming_partner within a cred block)
+ - support Hotspot 2.0 Release 2
+ * "hs20_anqp_get <BSSID> 8" to request OSU Providers list
+ * "hs20_icon_request <BSSID> <icon filename>" to request icon files
+ * "fetch_osu" and "cancel_osu_fetch" to start/stop full OSU provider
+ search (all suitable APs in scan results)
+ * OSEN network for online signup connection
+ * min_{dl,ul}_bandwidth_{home,roaming} cred parameters
+ * max_bss_load cred parameter
+ * req_conn_capab cred parameter
+ * sp_priority cred parameter
+ * ocsp cred parameter
+ * slow down automatic connection attempts on EAP failure to meet
+ required behavior (no more than 10 retries within a 10-minute
+ interval)
+ * sample implementation of online signup client (both SPP and
+ OMA-DM protocols) (hs20/client/*)
+ - fixed GAS indication for additional comeback delay with status
+ code 95
+ - extend ANQP_GET to accept Hotspot 2.0 subtypes
+ ANQP_GET <addr> <info id>[,<info id>]...
+ [,hs20:<subtype>][...,hs20:<subtype>]
+ - add control interface events CRED-ADDED <id>,
+ CRED-MODIFIED <id> <field>, CRED-REMOVED <id>
+ - add "GET_CRED <id> <field>" command
+ - enable FT for the connection automatically if the AP advertises
+ support for this
+ - fix a case where auto_interworking=1 could end up stopping scanning
+ * fixed TDLS interoperability issues with supported operating class in
+ some deployed stations
+ * internal TLS implementation enhancements/fixes
+ - add SHA256-based cipher suites
+ - add DHE-RSA cipher suites
+ - fix X.509 validation of PKCS#1 signature to check for extra data
+ * fixed PTK derivation for CCMP-256 and GCMP-256
+ * added "reattach" command for fast reassociate-back-to-same-BSS
+ * allow PMF to be enabled for AP mode operation with the ieee80211w
+ parameter
+ * added "get_capability tdls" command
+ * added option to set config blobs through control interface with
+ "SET blob <name> <hexdump>"
+ * D-Bus interface extensions/fixes
+ - make p2p_no_group_iface configurable
+ - declare ServiceDiscoveryRequest method properly
+ - export peer's device address as a property
+ - make reassociate command behave like the control interface one,
+ i.e., to allow connection from disconnected state
+ * added optional "freq=<channel ranges>" parameter to SET pno
+ * added optional "freq=<channel ranges>" parameter to SELECT_NETWORK
+ * fixed OBSS scan result processing for 20/40 MHz co-ex report
+ * remove WPS 1.0 only support, i.e., WSC 2.0 support is now enabled
+ whenever CONFIG_WPS=y is set
+ * fixed regression in parsing of WNM Sleep Mode exit key data
+ * fixed potential segmentation fault and memory leaks in WNM neighbor
+ report processing
+ * EAP-pwd fixes
+ - fragmentation of PWD-Confirm-Resp
+ - fix memory leak when fragmentation is used
+ - fix possible segmentation fault on EAP method deinit if an invalid
+ group is negotiated
+ * added MACsec/IEEE Std 802.1X-2010 PAE implementation (currently
+ available only with the macsec_qca driver wrapper)
+ * fixed EAP-SIM counter-too-small message
+ * added 'dup_network <id_s> <id_d> <name>' command; this can be used to
+ clone the psk field without having toextract it from wpa_supplicant
+ * fixed GSM authentication on USIM
+ * added support for usin epoll in eloop (CONFIG_ELOOP_EPOLL=y)
+ * fixed some concurrent virtual interface cases with dedicated P2P
+ management interface to not catch events from removed interface (this
+ could result in the management interface getting disabled)
+ * fixed a memory leak in SAE random number generation
+ * fixed off-by-one bounds checking in printf_encode()
+ - this could result in some control interface ATTACH command cases
+ terminating wpa_supplicant
+ * fixed EAPOL-Key exchange when GCMP is used with SHA256-based AKM
+ * various bug fixes
+
+2014-02-04 - v2.1
+ * added support for simultaneous authentication of equals (SAE) for
+ stronger password-based authentication with WPA2-Personal
+ * improved P2P negotiation and group formation robustness
+ - avoid unnecessary Dialog Token value changes during retries
+ - avoid more concurrent scanning cases during full group formation
+ sequence
+ - do not use potentially obsolete scan result data from driver
+ cache for peer discovery/updates
+ - avoid undesired re-starting of GO negotiation based on Probe
+ Request frames
+ - increase GO Negotiation and Invitation timeouts to address busy
+ environments and peers that take long time to react to messages,
+ e.g., due to power saving
+ - P2P Device interface type
+ * improved P2P channel selection (use more peer information and allow
+ more local options)
+ * added support for optional per-device PSK assignment by P2P GO
+ (wpa_cli p2p_set per_sta_psk <0/1>)
+ * added P2P_REMOVE_CLIENT for removing a client from P2P groups
+ (including persistent groups); this can be used to securely remove
+ a client from a group if per-device PSKs are used
+ * added more configuration flexibility for allowed P2P GO/client
+ channels (p2p_no_go_freq list and p2p_add_cli_chan=0/1)
+ * added nl80211 functionality
+ - VHT configuration for nl80211
+ - MFP (IEEE 802.11w) information for nl80211 command API
+ - support split wiphy dump
+ - FT (IEEE 802.11r) with driver-based SME
+ - use advertised number of supported concurrent channels
+ - QoS Mapping configuration
+ * improved TDLS negotiation robustness
+ * added more TDLS peer parameters to be configured to the driver
+ * optimized connection time by allowing recently received scan results
+ to be used instead of having to run through a new scan
+ * fixed ctrl_iface BSS command iteration with RANGE argument and no
+ exact matches; also fixed argument parsing for some cases with
+ multiple arguments
+ * added 'SCAN TYPE=ONLY' ctrl_iface command to request manual scan
+ without executing roaming/network re-selection on scan results
+ * added Session-Id derivation for EAP peer methods
+ * added fully automated regression testing with mac80211_hwsim
+ * changed configuration parser to reject invalid integer values
+ * allow AP/Enrollee to be specified with BSSID instead of UUID for
+ WPS ER operations
+ * disable network block temporarily on repeated connection failures
+ * changed the default driver interface from wext to nl80211 if both are
+ included in the build
+ * remove duplicate networks if WPS provisioning is run multiple times
+ * remove duplicate networks when Interworking network selection uses the
+ same network
+ * added global freq_list configuration to allow scan frequencies to be
+ limited for all cases instead of just for a specific network block
+ * added support for BSS Transition Management
+ * added option to use "IFNAME=<ifname> " prefix to use the global
+ control interface connection to perform per-interface commands;
+ similarly, allow global control interface to be used as a monitor
+ interface to receive events from all interfaces
+ * fixed OKC-based PMKSA cache entry clearing
+ * fixed TKIP group key configuration with FT
+ * added support for using OCSP stapling to validate server certificate
+ (ocsp=1 as optional and ocsp=2 as mandatory)
+ * added EAP-EKE peer
+ * added peer restart detection for IBSS RSN
+ * added domain_suffix_match (and domain_suffix_match2 for Phase 2
+ EAP-TLS) to specify additional constraint for the server certificate
+ domain name
+ * added support for external SIM/USIM processing in EAP-SIM, EAP-AKA,
+ and EAP-AKA' (CTRL-REQ-SIM and CTRL-RSP-SIM commands over control
+ interface)
+ * added global bgscan configuration option as a default for all network
+ blocks that do not specify their own bgscan parameters
+ * added D-Bus methods for TDLS
+ * added more control to scan requests
+ - "SCAN freq=<freq list>" can be used to specify which channels are
+ scanned (comma-separated frequency ranges in MHz)
+ - "SCAN passive=1" can be used to request a passive scan (no Probe
+ Request frames are sent)
+ - "SCAN use_id" can be used to request a scan id to be returned and
+ included in event messages related to this specific scan operation
+ - "SCAN only_new=1" can be used to request the driver/cfg80211 to
+ report only BSS entries that have been updated during this scan
+ round
+ - these optional arguments to the SCAN command can be combined with
+ each other
+ * modified behavior on externally triggered scans
+ - avoid concurrent operations requiring full control of the radio when
+ an externally triggered scan is detected
+ - do not use results for internal roaming decision
+ * added a new cred block parameter 'temporary' to allow credential
+ blocks to be stored separately even if wpa_supplicant configuration
+ file is used to maintain other network information
+ * added "radio work" framework to schedule exclusive radio operations
+ for off-channel functionality
+ - reduce issues with concurrent operations that try to control which
+ channel is used
+ - allow external programs to request exclusive radio control in a way
+ that avoids conflicts with wpa_supplicant
+ * added support for using Protected Dual of Public Action frames for
+ GAS/ANQP exchanges when associated with PMF
+ * added support for WPS+NFC updates and P2P+NFC
+ - improved protocol for WPS
+ - P2P group formation/join based on NFC connection handover
+ - new IPv4 address assignment for P2P groups (ip_addr_* configuration
+ parameters on the GO) to replace DHCP
+ - option to fetch and report alternative carrier records for external
+ NFC operations
+ * various bug fixes
+
2013-01-12 - v2.0
* removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
* removed unmaintained driver wrappers broadcom, iphone, osx, ralink,
diff --git a/contrib/wpa/wpa_supplicant/README b/contrib/wpa/wpa_supplicant/README
index a06e5c1..f9c65d2 100644
--- a/contrib/wpa/wpa_supplicant/README
+++ b/contrib/wpa/wpa_supplicant/README
@@ -1,7 +1,7 @@
WPA Supplicant
==============
-Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
@@ -115,13 +115,15 @@ Current hardware/software requirements:
- NetBSD-current
- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
- drivers:
- Linux drivers that support WPA/WPA2 configuration with the generic
- Linux wireless extensions (WE-18 or newer). Even though there are
+ Linux drivers that support cfg80211/nl80211. Even though there are
number of driver specific interface included in wpa_supplicant, please
- note that Linux drivers are moving to use generic wireless extensions
- and driver_wext (-Dwext on wpa_supplicant command line) should be the
- default option to start with before falling back to driver specific
- interface.
+ note that Linux drivers are moving to use generic wireless configuration
+ interface driver_nl80211 (-Dnl80211 on wpa_supplicant command line)
+ should be the default option to start with before falling back to driver
+ specific interface.
+
+ Linux drivers that support WPA/WPA2 configuration with the generic
+ Linux wireless extensions (WE-18 or newer). Obsoleted by nl80211.
In theory, any driver that supports Linux wireless extensions can be
used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
@@ -408,9 +410,10 @@ Command line options
usage:
wpa_supplicant [-BddfhKLqqtuvwW] [-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>] \
- [-p<driver_param>] [-b<br_ifname>] ...]
+ [-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
options:
-b = optional bridge interface name
@@ -422,6 +425,7 @@ options:
-D = driver name (can be multiple drivers: nl80211,wext)
-f = Log output to default log location (normally /tmp)
-g = global ctrl_interface
+ -G = global ctrl_interface group
-K = include keys (passwords, etc.) in debug output
-t = include timestamp in debug messages
-h = show this help text
@@ -434,8 +438,10 @@ options:
-w = wait for interface to be added, if needed
-W = wait for a control interface monitor before starting
-N = start describing new interface
+ -m = Configuration file for the P2P Device
drivers:
+ nl80211 = Linux nl80211/cfg80211
wext = Linux wireless extensions (generic)
wired = wpa_supplicant wired Ethernet driver
roboswitch = wpa_supplicant Broadcom switch driver
@@ -477,7 +483,7 @@ 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:
-wpa_supplicant -cw.conf -Dwext -iwlan0 -bbr0
+wpa_supplicant -cw.conf -Dnl80211 -iwlan0 -bbr0
Configuration file
@@ -869,10 +875,10 @@ network (SSID):
# Start wpa_supplicant in the background
wpa_supplicant -g/var/run/wpa_supplicant-global -B
-# Add a new interface (wlan0, no configuration file, driver=wext, and
+# Add a new interface (wlan0, no configuration file, driver=nl80211, and
# enable control interface)
wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \
- "" wext /var/run/wpa_supplicant
+ "" nl80211 /var/run/wpa_supplicant
# Configure a network using the newly added network interface:
wpa_cli -iwlan0 add_network
@@ -933,7 +939,7 @@ Example configuration:
chmod 0750 /var/run/wpa_priv
- start wpa_priv as root (e.g., from system startup scripts) with the
enabled interfaces configured on the command line:
- wpa_priv -B -P /var/run/wpa_priv.pid wext:ath0
+ wpa_priv -B -P /var/run/wpa_priv.pid nl80211:wlan0
- run wpa_supplicant as non-root with a user that is in wpapriv group:
wpa_supplicant -i ath0 -c wpa_supplicant.conf
@@ -944,3 +950,105 @@ can be started when an interface is added (hotplug/udev/etc. scripts).
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.
+
+
+Linux capabilities instead of privileged process
+------------------------------------------------
+
+wpa_supplicant performs operations that need special permissions, e.g.,
+to control the network connection. Traditionally this has been achieved
+by running wpa_supplicant as a privileged process with effective user id
+0 (root). Linux capabilities can be used to provide restricted set of
+capabilities to match the functions needed by wpa_supplicant. The
+minimum set of capabilities needed for the operations is CAP_NET_ADMIN
+and CAP_NET_RAW.
+
+setcap(8) can be used to set file capabilities. For example:
+
+sudo setcap cap_net_raw,cap_net_admin+ep wpa_supplicant
+
+Please note that this would give anyone being able to run that
+wpa_supplicant binary access to the additional capabilities. This can
+further be limited by file owner/group and mode bits. For example:
+
+sudo chown wpas wpa_supplicant
+sudo chmod 0100 wpa_supplicant
+
+This combination of setcap, chown, and chmod commands would allow wpas
+user to execute wpa_supplicant with additional network admin/raw
+capabilities.
+
+Common way style of creating a control interface socket in
+/var/run/wpa_supplicant could not be done by this user, but this
+directory could be created before starting the wpa_supplicant and set to
+suitable mode to allow wpa_supplicant to create sockets
+there. Alternatively, other directory or abstract socket namespace could
+be used for the control interface.
+
+
+External requests for radio control
+-----------------------------------
+
+External programs can request wpa_supplicant to not start offchannel
+operations during other tasks that may need exclusive control of the
+radio. The RADIO_WORK control interface command can be used for this.
+
+"RADIO_WORK add <name> [freq=<MHz>] [timeout=<seconds>]" command can be
+used to reserve a slot for radio access. If freq is specified, other
+radio work items on the same channel may be completed in
+parallel. Otherwise, all other radio work items are blocked during
+execution. Timeout is set to 10 seconds by default to avoid blocking
+wpa_supplicant operations for excessive time. If a longer (or shorter)
+safety timeout is needed, that can be specified with the optional
+timeout parameter. This command returns an identifier for the radio work
+item.
+
+Once the radio work item has been started, "EXT-RADIO-WORK-START <id>"
+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
+happened. "RADIO_WORK done <id>" can also be used to cancel items that
+have not yet been started.
+
+For example, in wpa_cli interactive mode:
+
+> radio_work add test
+1
+<3>EXT-RADIO-WORK-START 1
+> radio_work show
+ext:test@wlan0:0:1:2.487797
+> radio_work done 1
+OK
+> radio_work show
+
+
+> radio_work done 3
+OK
+> radio_work show
+ext:test freq=2412 timeout=30@wlan0:2412:1:28.583483
+<3>EXT-RADIO-WORK-TIMEOUT 2
+
+
+> radio_work add test2 freq=2412 timeout=60
+5
+<3>EXT-RADIO-WORK-START 5
+> radio_work add test3
+6
+> radio_work add test4
+7
+> radio_work show
+ext:test2 freq=2412 timeout=60@wlan0:2412:1:9.751844
+ext:test3@wlan0:0:0:5.071812
+ext:test4@wlan0:0:0:3.143870
+> radio_work done 6
+OK
+> radio_work show
+ext:test2 freq=2412 timeout=60@wlan0:2412:1:16.287869
+ext:test4@wlan0:0:0:9.679895
+> radio_work done 5
+OK
+<3>EXT-RADIO-WORK-START 7
+<3>EXT-RADIO-WORK-TIMEOUT 7
diff --git a/contrib/wpa/wpa_supplicant/README-HS20 b/contrib/wpa/wpa_supplicant/README-HS20
index 5669c55..161dc06 100644
--- a/contrib/wpa/wpa_supplicant/README-HS20
+++ b/contrib/wpa/wpa_supplicant/README-HS20
@@ -109,6 +109,8 @@ Credentials can be pre-configured for automatic network selection:
#
# credential fields:
#
+# temporary: Whether this credential is temporary and not to be saved
+#
# priority: Priority group
# By default, all networks and credentials get the same priority group
# (0). This field can be used to give higher priority for credentials
@@ -166,9 +168,25 @@ Credentials can be pre-configured for automatic network selection:
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
-# domain: Home service provider FQDN
+# domain_suffix_match: Constraint for server domain name
+# If set, this FQDN is 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. Suffix match here means that the
+# host/domain name is compared one label at a time starting from the
+# top-level domain and all the labels in @domain_suffix_match shall be
+# included in the certificate. The certificate may include additional
+# sub-level labels in addition to the required labels.
+#
+# For example, domain_suffix_match=example.com would match
+# test.example.com but would not match test-example.com.
+#
+# domain: Home service provider FQDN(s)
# This is used to compare against the Domain Name List to figure out
-# whether the AP is operated by the Home SP.
+# whether the AP is operated by the Home SP. Multiple domain entries can
+# be used to configure alternative FQDNs that will be considered home
+# networks.
#
# roaming_consortium: Roaming Consortium OI
# If roaming_consortium_len is non-zero, this field contains the
@@ -195,6 +213,65 @@ Credentials can be pre-configured for automatic network selection:
# matching with the network. Multiple entries can be used to specify more
# than one SSID.
#
+# roaming_partner: Roaming partner information
+# This optional field can be used to configure preferences between roaming
+# partners. The field is a string in following format:
+# <FQDN>,<0/1 exact match>,<priority>,<* or country code>
+# (non-exact match means any subdomain matches the entry; priority is in
+# 0..255 range with 0 being the highest priority)
+#
+# update_identifier: PPS MO ID
+# (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+#
+# provisioning_sp: FQDN of the SP that provisioned the credential
+# This optional field can be used to keep track of the SP that provisioned
+# the credential to find the PPS MO (./Wi-Fi/<provisioning_sp>).
+#
+# 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
+# provisioning_sp value). The range of this priority is 0-255 with 0
+# being the highest and 255 the lower priority.
+#
+# Minimum backhaul threshold (PPS/<X+>/Policy/MinBackhauldThreshold/*)
+# These fields can be used to specify minimum download/upload backhaul
+# bandwidth that is preferred for the credential. This constraint is
+# ignored if the AP does not advertise WAN Metrics information or if the
+# limit would prevent any connection. Values are in kilobits per second.
+# min_dl_bandwidth_home
+# min_ul_bandwidth_home
+# min_dl_bandwidth_roaming
+# min_ul_bandwidth_roaming
+#
+# max_bss_load: Maximum BSS Load Channel Utilization (1..255)
+# (PPS/<X+>/Policy/MaximumBSSLoadValue)
+# This value is used as the maximum channel utilization for network
+# selection purposes for home networks. If the AP does not advertise
+# BSS Load or if the limit would prevent any connection, this constraint
+# will be ignored.
+#
+# req_conn_capab: Required connection capability
+# (PPS/<X+>/Policy/RequiredProtoPortTuple)
+# This value is used to configure set of required protocol/port pairs that
+# a roaming network shall support (include explicitly in Connection
+# Capability ANQP element). This constraint is ignored if the AP does not
+# advertise Connection Capability or if this constraint would prevent any
+# network connection. This policy is not used in home networks.
+# Format: <protocol>[:<comma-separated list of ports]
+# Multiple entries can be used to list multiple requirements.
+# For example, number of common TCP protocols:
+# req_conn_capab=6:22,80,443
+# For example, IPSec/IKE:
+# req_conn_capab=17:500
+# req_conn_capab=50
+#
+# ocsp: Whether to use/require OCSP to check server certificate
+# 0 = do not use OCSP stapling (TLS certificate status extension)
+# 1 = try to use OCSP stapling, but not require response
+# 2 = require valid OCSP stapling response
+#
+# sim_num: Identifier for which SIM to use in multi-SIM devices
+#
# for example:
#
#cred={
@@ -203,6 +280,7 @@ Credentials can be pre-configured for automatic network selection:
# password="password"
# ca_cert="/etc/wpa_supplicant/ca.pem"
# domain="example.com"
+# domain_suffix_match="example.com"
#}
#
#cred={
@@ -252,6 +330,8 @@ OK
OK
> set_cred 0 priority 1
OK
+> set_cred 0 temporary 1
+OK
Add a SIM credential using a simulated SIM/USIM card for testing:
@@ -267,6 +347,17 @@ OK
Note: the return value of add_cred is used as the first argument to
the following set_cred commands.
+Add a SIM credential using a external SIM/USIM processing:
+
+> set external_sim 1
+OK
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 eap SIM
+OK
+
Add a WPA2-Enterprise network:
diff --git a/contrib/wpa/wpa_supplicant/README-P2P b/contrib/wpa/wpa_supplicant/README-P2P
index 5e98c95..6a5b032 100644
--- a/contrib/wpa/wpa_supplicant/README-P2P
+++ b/contrib/wpa/wpa_supplicant/README-P2P
@@ -72,7 +72,8 @@ over the main control interface.
Device Discovery
p2p_find [timeout in seconds] [type=<social|progressive>] \
- [dev_id=<addr>] [delay=<search delay in ms>]
+ [dev_id=<addr>] [dev_type=<device type>] \
+ [delay=<search delay in ms>] [seek=<service name>] [freq=<MHz>]
The default behavior is to run a single full scan in the beginning and
then scan only social channels. type=social will scan only social
@@ -80,13 +81,37 @@ channels, i.e., it skips the initial full scan. type=progressive is
like the default behavior, but it will scan through all the channels
progressively one channel at the time in the Search state rounds. This
will help in finding new groups or groups missed during the initial
-full scan.
+full scan. When the type parameter is not included (i.e., full scan), the
+optional freq parameter can be used to override the first scan to use only
+the specified channel after which only social channels are scanned.
The optional dev_id option can be used to specify a single P2P peer to
search for. The optional delay parameter can be used to request an extra
delay to be used between search iterations (e.g., to free up radio
resources for concurrent operations).
+The optional dev_type option can be used to specify a single device type
+(primary or secondary) to search for, e.g.,
+"p2p_find dev_type=1-0050F204-1".
+
+
+With one or more seek arguments, the command sends Probe Request frames
+for a P2PS service. For example,
+p2p_find 5 dev_id=11:22:33:44:55:66 seek=alt.example.chat seek=alt.example.video
+
+Parameters description:
+ Timeout - Optional ASCII base-10-encoded u16. If missing, request will not
+ time out and must be canceled manually
+ dev_id - Optional to request responses from a single known remote device
+ Service Name - Mandatory UTF-8 string for ASP seeks
+ Service name must match the remote service being advertised exactly
+ (no prefix matching).
+ Service name may be empty, in which case all ASP services will be
+ returned, and may be filtered with p2p_serv_disc_req settings, and
+ p2p_serv_asp_resp results.
+ Multiple service names may be requested, but if it exceeds internal
+ limit, it will automatically revert to requesting all ASP services.
+
p2p_listen [timeout in seconds]
Start Listen-only state (become discoverable without searching for
@@ -123,9 +148,9 @@ parameter can be used to request wpa_supplicant to automatically figure
out whether the peer device is operating as a GO and if so, use
join-a-group style PD instead of GO Negotiation style PD.
-p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
+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] [provdisc]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto]
Start P2P group formation with a discovered P2P peer. This includes
optional group owner negotiation, group interface setup, provisioning,
@@ -166,7 +191,71 @@ used prior to starting GO Negotiation as a workaround with some deployed
P2P implementations that require this to allow the user to accept the
connection.
-p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40]
+"auto" can be used to request wpa_supplicant to automatically figure
+out whether the peer device is operating as a GO and if so, use
+join-a-group operation rather than GO Negotiation.
+
+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.
+
+For example:
+p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join
+ (WPS Method = P2PS default)
+
+p2p_connect 02:0a:f5:85:11:00 45629034 keypad persistent
+ (WPS Method = PIN)
+
+p2p_asp_provision <peer MAC address> <adv_id=peer adv id>
+ <adv_mac=peer MAC address> [role=2|4|1] <session=session id>
+ <session_mac=initiator mac address>
+ [info='service info'] <method=Default|keypad|Display>
+
+This command starts provision discovery with the P2PS enabled peer device.
+
+For example,
+p2p_asp_provision 00:11:22:33:44:55 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 session=12ab34 session_mac=00:11:22:33:44:55 info='name=john' method=1000
+
+Parameter description:
+ MAC address - Mandatory
+ adv_id - Mandatory remote Advertising ID of service connection is being
+ established for
+ adv_mac - Mandatory MAC address that owns/registered the service
+ role - Optional
+ 2 (group client only) or 4 (group owner only)
+ if not present (or 1) role is negotiated by the two peers.
+ session - Mandatory Session ID of the first session to be established
+ session_mac - Mandatory MAC address that owns/initiated the session
+ method - Optional method to request for provisioning (1000 - P2PS Default,
+ 100 - Keypad(PIN), 8 - Display(PIN))
+ info - Optional UTF-8 string. Hint for service to indicate possible usage
+ parameters - Escape single quote & backslash:
+ with a backslash 0x27 == ' == \', and 0x5c == \ == \\
+
+p2p_asp_provision_resp <peer mac address> <adv_id= local adv id>
+ <adv_mac=local MAC address> <role=1|2|4> <status=0>
+ <session=session id> <session_mac=peer MAC address>
+
+This command sends a provision discovery response from responder side.
+
+For example,
+p2p_asp_provision_resp 00:55:44:33:22:11 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 status=0 session=12ab34 session_mac=00:11:22:33:44:55
+
+Parameters definition:
+ MAC address - Mandatory
+ adv_id - Mandatory local Advertising ID of service connection is being
+ established for
+ adv_mac - Mandatory MAC address that owns/registered the service
+ role - Optional 2 (group client only) or 4 (group owner only)
+ if not present (or 1) role is negotiated by the two peers.
+ status - Mandatory Acceptance/Rejection code of Provisioning
+ session - Mandatory Session ID of the first session to be established
+ session_mac - Mandatory MAC address that owns/initiated the session
+
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+ [ht40] [vht]
Set up a P2P group owner manually (i.e., without group owner
negotiation with a specific peer). This is also known as autonomous
@@ -199,8 +288,80 @@ P2P group interface (if one was used) that is in the WPS provisioning
step. If the WPS provisioning step has been completed, the group is not
terminated.
+p2p_remove_client <peer's P2P Device Address|iface=<interface address>>
+
+This command can be used to remove the specified client from all groups
+(operating and persistent) from the local GO. Note that the peer device
+can rejoin the group if it is in possession of a valid key. See p2p_set
+per_sta_psk command below for more details on how the peer can be
+removed securely.
+
Service Discovery
+p2p_service_add asp <auto accept> <adv id> <status 0/1> <Config Methods>
+ <Service name> [Service Information] [Response Info]
+
+This command can be used to search for a P2PS service which includes
+Play, Send, Display, and Print service. The parameters for this command
+are "asp" to identify the command as P2PS one, auto accept value,
+advertisement id which uniquely identifies the service requests, state
+of the service whether the service is available or not, config methods
+which can be either P2PS method or PIN method, service name followed by
+two optional parameters service information, and response info.
+
+For example,
+p2p_service_add asp 1 4d6fc7 0 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234'
+
+Parameters definition:
+ asp - Mandatory for ASP service registration
+ auto accept - Mandatory ASCII hex-encoded boolean (0 == no auto-accept,
+ 1 == auto-accept ANY role, 2 == auto-accept CLIENT role,
+ 4 == auto-accept GO role)
+ Advertisement ID - Mandatory non-zero ASCII hex-encoded u32
+ (Must be unique/not yet exist in svc db)
+ State - Mandatory ASCII hex-encoded u8 (0 -- Svc not available,
+ 1 -- Svc available, 2-0xff Application defined)
+ Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config
+ methods)
+ Service Name - Mandatory UTF-8 string
+ Service Information - Optional UTF-8 string
+ Escape single quote & backslash with a backslash:
+ 0x27 == ' == \', and 0x5c == \ == \\
+ Session response information - Optional (used only if auto accept is TRUE)
+ UTF-8 string
+ Escape single quote & backslash with a backslash:
+ 0x27 == ' == \', and 0x5c == \ == \\
+
+p2p_service_rep asp <auto accept> <adv id> <status 0/1> <Config Methods>
+ <Service name> [Service Information] [Response Info]
+
+This command can be used to replace the existing service request
+attributes from the initiator side. The replacement is only allowed if
+the advertisement id issued in the command matches with any one entry in
+the list of existing SD queries. If advertisement id doesn't match the
+command returns a failure.
+
+For example,
+p2p_service_rep asp 1 4d6fc7 1 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234'
+
+Parameters definition:
+ asp - Mandatory for ASP service registration
+ auto accept - Mandatory ASCII hex-encoded boolean (1 == true, 0 == false)
+ Advertisement ID - Mandatory non-zero ASCII hex-encoded u32
+ (Must already exist in svc db)
+ State - Mandatory ASCII hex-encoded u8 (can be used to indicate svc
+ available or not available for instance)
+ Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config
+ methods)
+ Service Name - Mandatory UTF-8 string (Must match existing string in svc db)
+ Service Information - Optional UTF-8 string
+ Escape single quote & backslash with a backslash:
+ 0x27 == ' == \', and 0x5c == \ == \\
+ Session response information - Optional (used only if auto accept is TRUE)
+ UTF-8 string
+ Escape single quote & backslash with a backslash:
+ 0x27 == ' == \', and 0x5c == \ == \\
+
p2p_serv_disc_req
Schedule a P2P service discovery request. The parameters for this
@@ -216,15 +377,27 @@ discovery protocols and requests this to be sent to all discovered
peers (note: this can result in long response frames). The pending
requests are sent during device discovery (see p2p_find).
-Only a single pending wildcard query is supported, but there can be
-multiple pending peer device specific queries (each will be sent in
-sequence whenever the peer is found).
+There can be multiple pending peer device specific queries (each will be
+sent in sequence whenever the peer is found).
This command returns an identifier for the pending query (e.g.,
"1f77628") that can be used to cancel the request. Directed requests
will be automatically removed when the specified peer has replied to
it.
+Service Query TLV has following format:
+Length (2 octets, little endian) - length of following data
+Service Protocol Type (1 octet) - see the table below
+Service Transaction ID (1 octet) - nonzero identifier for the TLV
+Query Data (Length - 2 octets of data) - service protocol specific data
+
+Service Protocol Types:
+0 = All service protocols
+1 = Bonjour
+2 = UPnP
+3 = WS-Discovery
+4 = Wi-Fi Display
+
For UPnP, an alternative command format can be used to specify a
single query TLV (i.e., a service discovery for a specific UPnP
service):
@@ -270,6 +443,27 @@ p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5
+p2p_serv_disc_req <Unicast|Broadcast mac address> asp <Transaction ID>
+ <Service Name> [Service Information]
+
+The command can be used for service discovery for P2PS enabled devices.
+
+For example: p2p_serv_disc_req 00:00:00:00:00:00 asp a1 alt.example 'john'
+
+Parameters definition:
+ MAC address - Mandatory Existing
+ asp - Mandatory for ASP queries
+ Transaction ID - Mandatory non-zero ASCII hex-encoded u8 for GAS
+ Service Name Prefix - Mandatory UTF-8 string.
+ Will match from beginning of remote Service Name
+ Service Information Substring - Optional UTF-8 string
+ If Service Information Substring is not included, all services matching
+ Service Name Prefix will be returned.
+ If Service Information Substring is included, both the Substring and the
+ Service Name Prefix must match for service to be returned.
+ If remote service has no Service Information, all Substring searches
+ will fail.
+
p2p_serv_disc_cancel_req <query identifier>
Cancel a pending P2P service discovery request. This command takes a
@@ -345,6 +539,11 @@ p2p_service_del upnp <version hex> <service>
Remove a local UPnP service from internal SD query processing.
+p2p_service_del asp <adv id>
+
+Removes the local asp service from internal SD query list.
+For example: p2p_service_del asp 4d6fc7
+
p2p_service_flush
Remove all local services from internal SD query processing.
@@ -352,7 +551,8 @@ 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]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+ [pref=<MHz>]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
persistent group (e.g., persistent=4). If the peer device is the GO of
@@ -361,7 +561,11 @@ used to specify which device to invite. go_dev_addr parameter can be
used to override the GO device address for Invitation Request should
it be not known for some reason (this should not be needed in most
cases). When reinvoking a persistent group, the GO device can specify
-the frequency for the group with the freq parameter.
+the frequency for the group with the freq parameter. When reinvoking a
+persistent group, the P2P client device can use freq parameter to force
+a specific operating channel (or invitation failure if GO rejects that)
+or pref parameter to request a specific channel (while allowing GO to
+select to use another channel, if needed).
Group Operations
@@ -391,9 +595,11 @@ p2p_presence_req [<duration> <interval>] [<duration> <interval>]
Send a P2P Presence Request to the GO (this is only available when
acting as a P2P client). If no duration/interval pairs are given, the
request indicates that this client has no special needs for GO
-presence. the first parameter pair gives the preferred duration and
+presence. The first parameter pair gives the preferred duration and
interval values in microseconds. If the second pair is included, that
-indicates which value would be acceptable.
+indicates which value would be acceptable. This command returns OK
+immediately and the response from the GO is indicated in a
+P2P-PRESENCE-RESPONSE event message.
Parameters
@@ -439,6 +645,20 @@ Set postfix string to be added to the automatically generated P2P SSID
(DIRECT-<two random characters>). For example, postfix of "-testing"
could result in the SSID becoming DIRECT-ab-testing.
+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
+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
+learned previously is still valid. It should be noted that the default
+passphrase on the GO that is normally used to allow legacy stations to
+connect through manual configuration does not change here, so if that is
+shared, devices with knowledge of that passphrase can still connect.
+
set <field> <value>
Set global configuration parameters which may also affect P2P
@@ -507,6 +727,13 @@ set country <two character country code>
Set country code (this is included in some P2P messages).
+set p2p_search_delay <delay>
+
+Set p2p_search_delay which adds extra delay in milliseconds between
+concurrent search iterations to make p2p_find friendlier to concurrent
+operations by avoiding it from taking 100% of radio resources. The
+default value is 500 ms.
+
Status
p2p_peers [discovered]
@@ -551,6 +778,63 @@ remove_network <network id>
Remove a network entry from configuration.
+P2PS Events/Responses:
+
+P2PS-PROV-START: This events gets triggered when provisioning is issued for
+either seeker or advertiser.
+
+For example,
+P2PS-PROV-START 00:55:44:33:22:11 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 info='xxxx'
+
+Parameters definition:
+ MAC address - always
+ adv_id - always ASCII hex-encoded u32
+ adv_mac - always MAC address that owns/registered the service
+ conncap - always mask of 0x01 (new), 0x02 (group client), 0x04 (group owner)
+ bits
+ session - always Session ID of the first session to be established
+ session_mac - always MAC address that owns/initiated the session
+ info - if available, UTF-8 string
+ Escaped single quote & backslash with a backslash:
+ \' == 0x27 == ', and \\ == 0x5c == \
+
+P2PS-PROV-DONE: When provisioning is completed then this event gets triggered.
+
+For example,
+P2PS-PROV-DONE 00:11:22:33:44:55 status=0 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 [dev_passwd_id=8 | go=p2p-wlan0-0 | join=11:22:33:44:55:66 | persist=0]
+
+Parameters definition:
+ MAC address - always main device address of peer. May be different from MAC
+ ultimately connected to.
+ status - always ascii hex-encoded u8 (0 == success, 12 == deferred success)
+ adv_id - always ascii hex-encoded u32
+ adv_mac - always MAC address that owns/registered the service
+ conncap - always One of: 1 (new), 2 (group client), 4 (group owner) bits
+ session - always Session ID of the first session to be established
+ session_mac - always MAC address that owns/initiated the session
+ dev_passwd_id - only if conncap value == 1 (New GO negotiation)
+ 8 - "p2ps" password must be passed in p2p_connect command
+ 1 - "display" password must be passed in p2p_connect command
+ 5 - "keypad" password must be passed in p2p_connect command
+ join only - if conncap value == 2 (Client Only). Display password and "join"
+ must be passed in p2p_connect and address must be the MAC specified
+ go only - if conncap value == 4 (GO Only). Interface name must be set with a
+ password
+ persist - only if previous persistent group existed between peers and shall
+ be re-used. Group is restarted by sending "p2p_group_add persistent=0"
+ where value is taken from P2P-PROV-DONE
+
+Extended Events/Response
+
+P2P-DEVICE-FOUND 00:11:22:33:44:55 p2p_dev_addr=00:11:22:33:44:55 pri_dev_type=0-00000000-0 name='' config_methods=0x108 dev_capab=0x21 group_capab=0x0 adv_id=111 asp_svc=alt.example.chat
+
+Parameters definition:
+ adv_id - if ASP ASCII hex-encoded u32. If it is reporting the
+ "wildcard service", this value will be 0
+ asp_svc - if ASP this is the service string. If it is reporting the
+ "wildcard service", this value will be org.wi-fi.wfds
+
+
wpa_cli action script
---------------------
diff --git a/contrib/wpa/wpa_supplicant/README-WPS b/contrib/wpa/wpa_supplicant/README-WPS
index 1ea9843..b884f67 100644
--- a/contrib/wpa/wpa_supplicant/README-WPS
+++ b/contrib/wpa/wpa_supplicant/README-WPS
@@ -60,7 +60,6 @@ driver interface:
CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
-CONFIG_WPS2=y
If you want to enable WPS external registrar (ER) functionality, you
will also need to add following line:
@@ -259,16 +258,16 @@ wps_er_start [IP address]
wps_er_stop
- stop WPS ER functionality
-wps_er_learn <UUID> <AP PIN>
+wps_er_learn <UUID|BSSID> <AP PIN>
- learn AP configuration
-wps_er_set_config <UUID> <network id>
+wps_er_set_config <UUID|BSSID> <network id>
- use AP configuration from a locally configured network (e.g., from
wps_reg command); this does not change the AP's configuration, but
only prepares a configuration to be used when enrolling a new device
to the AP
-wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
+wps_er_config <UUID|BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
- examples:
wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678
wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE ""
@@ -277,10 +276,10 @@ wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
<encr> must be one of the following: NONE WEP TKIP CCMP
-wps_er_pbc <Enrollee UUID>
+wps_er_pbc <Enrollee UUID|MAC address>
- accept an Enrollee PBC using External Registrar
-wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+wps_er_pin <Enrollee UUID|"any"|MAC address> <PIN> [Enrollee MAC address]
- add an Enrollee PIN to External Registrar
- if Enrollee UUID is not known, "any" can be used to add a wildcard PIN
- if the MAC address of the enrollee is known, it should be configured
@@ -336,6 +335,20 @@ wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
tokens during manufacturing (each station needs to have its own random
keys).
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token when wpa_supplicant is controlling an AP
+interface (AP or P2P GO). The output value from this command is a
+hexdump of the current AP configuration (WPS parameter requests this to
+include only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+The "wps_nfc_config_token <WPS/NDEF> <network id>" command can be used
+to build an NFC configuration token based on a locally configured
+network.
+
If the station includes NFC interface and reads an NFC tag with a MIME
media type "application/vnd.wfa.wsc", the NDEF message payload (with or
without NDEF encapsulation) can be delivered to wpa_supplicant using the
@@ -352,26 +365,35 @@ the ER functionality has been started (wps_er_start), the NFC password
token is used to enable enrollment of a new station (that was the source
of the NFC password token).
-"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
-contents of a Handover Request Message for connection handover. The
-first argument selects the format of the output data and the second
-argument selects which type of connection handover is requested (WPS =
-Wi-Fi handover as specified in WSC 2.0).
-
-"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
-contents of a Handover Select Message for connection handover when this
-does not depend on the contents of the Handover Request Message. The
-first argument selects the format of the output data and the second
-argument selects which type of connection handover is requested (WPS =
-Wi-Fi handover as specified in WSC 2.0).
-
-"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
-of NFC connection handover request. The payload may include multiple
-carriers the the applicable ones are matched based on the media
-type. The reply data is contents for the Handover Select Message
-(hexdump).
-
-"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
-of NFC connection handover select. The payload may include multiple
-carriers the the applicable ones are matched based on the media
-type.
+"nfc_get_handover_req <NDEF> <WPS-CR>" command can be used to build the
+WPS carrier record for a Handover Request Message for connection
+handover. The first argument selects the format of the output data and
+the second argument selects which type of connection handover is
+requested (WPS-CR = Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS> [UUID|BSSID]" command can be used to
+build the contents of a Handover Select Message for connection handover
+when this does not depend on the contents of the Handover Request
+Message. The first argument selects the format of the output data and
+the second argument selects which type of connection handover is
+requested (WPS = Wi-Fi handover as specified in WSC 2.0). If the options
+UUID|BSSID argument is included, this is a request to build the handover
+message for the specified AP when wpa_supplicant is operating as a WPS
+ER.
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" can be used as an alternative way for
+reporting completed NFC connection handover. The first parameter
+indicates whether the local device initiated or responded to the
+connection handover and the carrier records are the selected carrier
+from the handover request and select messages as a hexdump.
+
+The "wps_er_nfc_config_token <WPS/NDEF> <UUID|BSSID>" command can be
+used to build an NFC configuration token for the specified AP when
+wpa_supplicant is operating as a WPS ER. The output value from this
+command is a hexdump of the selected AP configuration (WPS parameter
+requests this to include only the WPS attributes; NDEF parameter
+requests additional NDEF encapsulation to be included). This data needs
+to be written to an NFC tag with an external program. Once written, the
+NFC configuration token can be used to touch an NFC interface on a
+station to provision the credentials needed to access the network.
diff --git a/contrib/wpa/wpa_supplicant/ap.c b/contrib/wpa/wpa_supplicant/ap.c
index c1e4acf..7ecf7a8 100644
--- a/contrib/wpa/wpa_supplicant/ap.c
+++ b/contrib/wpa/wpa_supplicant/ap.c
@@ -14,6 +14,8 @@
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "crypto/dh_group5.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
@@ -24,6 +26,7 @@
#include "ap/ieee802_1x.h"
#include "ap/wps_hostapd.h"
#include "ap/ctrl_iface_ap.h"
+#include "ap/dfs.h"
#include "wps/wps.h"
#include "common/ieee802_11_defs.h"
#include "config_ssid.h"
@@ -41,38 +44,42 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#endif /* CONFIG_WPS */
-static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- struct hostapd_config *conf)
+#ifdef CONFIG_IEEE80211N
+static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+ struct hostapd_config *conf,
+ struct hostapd_hw_modes *mode)
{
- struct hostapd_bss_config *bss = &conf->bss[0];
- int pairwise;
+#ifdef CONFIG_P2P
+ u8 center_chan = 0;
+ u8 channel = conf->channel;
- conf->driver = wpa_s->driver;
+ if (!conf->secondary_channel)
+ goto no_vht;
- os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ if (!center_chan)
+ goto no_vht;
- if (ssid->frequency == 0) {
- /* default channel 11 */
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = 11;
- } else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = (ssid->frequency - 2407) / 5;
- } else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
- (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
- conf->channel = (ssid->frequency - 5000) / 5;
- } else if (ssid->frequency >= 56160 + 2160 * 1 &&
- ssid->frequency <= 56160 + 2160 * 4) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
- conf->channel = (ssid->frequency - 56160) / 2160;
- } else {
- wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
- ssid->frequency);
- return -1;
- }
+ /* Use 80 MHz channel */
+ conf->vht_oper_chwidth = 1;
+ conf->vht_oper_centr_freq_seg0_idx = center_chan;
+ return;
+no_vht:
+ conf->vht_oper_centr_freq_seg0_idx =
+ channel + conf->secondary_channel * 2;
+#else /* CONFIG_P2P */
+ conf->vht_oper_centr_freq_seg0_idx =
+ conf->channel + conf->secondary_channel * 2;
+#endif /* CONFIG_P2P */
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
+{
/* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */
@@ -126,13 +133,50 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_SHORT_GI20MHZ |
HT_CAP_INFO_SHORT_GI40MHZ |
HT_CAP_INFO_RX_STBC_MASK |
+ HT_CAP_INFO_TX_STBC |
HT_CAP_INFO_MAX_AMSDU_SIZE);
+
+ if (mode->vht_capab && ssid->vht) {
+ conf->ieee80211ac = 1;
+ wpas_conf_ap_vht(wpa_s, conf, mode);
+ }
}
}
#endif /* CONFIG_IEEE80211N */
+}
+
+
+static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
+{
+ struct hostapd_bss_config *bss = conf->bss[0];
+
+ conf->driver = wpa_s->driver;
+
+ 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);
+ return -1;
+ }
+
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
+ if (ieee80211_is_dfs(ssid->frequency) && 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];
+ }
#ifdef CONFIG_P2P
- if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
+ (ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)) {
/* Remove 802.11b rates from supported and basic rate sets */
int *list = os_malloc(4 * sizeof(int));
if (list) {
@@ -159,6 +203,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
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,
+ 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,
+ 4);
+ }
#endif /* CONFIG_P2P */
if (ssid->ssid_len == 0) {
@@ -179,7 +234,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
if (ssid->psk_set) {
- os_free(bss->ssid.wpa_psk);
+ bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
return -1;
@@ -210,23 +265,29 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
if (ssid->dtim_period)
bss->dtim_period = ssid->dtim_period;
+ else if (wpa_s->conf->dtim_period)
+ bss->dtim_period = wpa_s->conf->dtim_period;
+
+ if (ssid->beacon_int)
+ conf->beacon_int = ssid->beacon_int;
+ else if (wpa_s->conf->beacon_int)
+ conf->beacon_int = wpa_s->conf->beacon_int;
- /* Select group cipher based on the enabled pairwise cipher suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
+#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 (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
- WPA_CIPHER_GCMP)
- bss->wpa_group = WPA_CIPHER_GCMP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
+#endif /* CONFIG_P2P */
+
+ 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->wpa && bss->ieee802_1x)
bss->ssid.security_policy = SECURITY_WPA;
@@ -257,6 +318,23 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->rsn_pairwise = WPA_CIPHER_NONE;
}
+ if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) &&
+ (bss->wpa_group == WPA_CIPHER_CCMP ||
+ bss->wpa_group == WPA_CIPHER_GCMP ||
+ bss->wpa_group == WPA_CIPHER_CCMP_256 ||
+ bss->wpa_group == WPA_CIPHER_GCMP_256)) {
+ /*
+ * Strong ciphers do not need frequent rekeying, so increase
+ * the default GTK rekeying period to 24 hours.
+ */
+ bss->wpa_group_rekey = 86400;
+ }
+
+#ifdef CONFIG_IEEE80211W
+ if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT)
+ bss->ieee80211w = ssid->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+
#ifdef CONFIG_WPS
/*
* Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -266,12 +344,11 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
if (bss->ssid.security_policy != SECURITY_WPA_PSK &&
bss->ssid.security_policy != SECURITY_PLAINTEXT)
goto no_wps;
-#ifdef CONFIG_WPS2
if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
- (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+ (!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ||
+ !(bss->wpa & 2)))
goto no_wps; /* WPS2 does not allow WPA/TKIP-only
* configuration */
-#endif /* CONFIG_WPS2 */
bss->eap_server = 1;
if (!ssid->ignore_broadcast_ssid)
@@ -311,6 +388,11 @@ no_wps:
bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
+ if (wpa_s->conf->ap_vendor_elements) {
+ bss->vendor_elements =
+ wpabuf_dup(wpa_s->conf->ap_vendor_elements);
+ }
+
return 0;
}
@@ -320,16 +402,16 @@ static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
#ifdef CONFIG_P2P
struct wpa_supplicant *wpa_s = ctx;
const struct ieee80211_mgmt *mgmt;
- size_t hdr_len;
mgmt = (const struct ieee80211_mgmt *) buf;
- hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
- if (hdr_len > len)
+ if (len < IEEE80211_HDRLEN + 1)
+ return;
+ if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
return;
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
mgmt->u.action.category,
- &mgmt->u.action.u.vs_public_action.action,
- len - hdr_len, freq);
+ buf + IEEE80211_HDRLEN + 1,
+ len - IEEE80211_HDRLEN - 1, freq);
#endif /* CONFIG_P2P */
}
@@ -367,21 +449,32 @@ static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
}
+#ifdef CONFIG_P2P
+static void ap_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr,
+ const u8 *psk, size_t psk_len)
+{
+
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL)
+ return;
+ wpas_p2p_new_psk_cb(wpa_s, mac_addr, p2p_dev_addr, psk, psk_len);
+}
+#endif /* CONFIG_P2P */
+
+
static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
{
#ifdef CONFIG_P2P
struct wpa_supplicant *wpa_s = ctx;
const struct ieee80211_mgmt *mgmt;
- size_t hdr_len;
mgmt = (const struct ieee80211_mgmt *) buf;
- hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
- if (hdr_len > len)
+ if (len < IEEE80211_HDRLEN + 1)
return -1;
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
mgmt->u.action.category,
- &mgmt->u.action.u.vs_public_action.action,
- len - hdr_len, freq);
+ buf + IEEE80211_HDRLEN + 1,
+ len - IEEE80211_HDRLEN - 1, freq);
#endif /* CONFIG_P2P */
return 0;
}
@@ -391,23 +484,17 @@ static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal)
{
-#ifdef CONFIG_P2P
struct wpa_supplicant *wpa_s = ctx;
return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
ssi_signal);
-#else /* CONFIG_P2P */
- return 0;
-#endif /* CONFIG_P2P */
}
static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
const u8 *uuid_e)
{
-#ifdef CONFIG_P2P
struct wpa_supplicant *wpa_s = ctx;
wpas_p2p_wps_success(wpa_s, mac_addr, 1);
-#endif /* CONFIG_P2P */
}
@@ -445,41 +532,33 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
switch (ssid->mode) {
- case WPAS_MODE_INFRA:
- params.mode = IEEE80211_MODE_INFRA;
- break;
- case WPAS_MODE_IBSS:
- params.mode = IEEE80211_MODE_IBSS;
- break;
case WPAS_MODE_AP:
case WPAS_MODE_P2P_GO:
case WPAS_MODE_P2P_GROUP_FORMATION:
params.mode = IEEE80211_MODE_AP;
break;
+ default:
+ return -1;
}
- params.freq = ssid->frequency;
+ if (ssid->frequency == 0)
+ ssid->frequency = 2462; /* default channel 11 */
+ params.freq.freq = ssid->frequency;
params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
else
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
- params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
-
- if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
- wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_GCMP)
- wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
- wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
- wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- else {
+ params.key_mgmt_suite = wpa_s->key_mgmt;
+
+ wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher,
+ 1);
+ if (wpa_s->pairwise_cipher < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
"cipher.");
return -1;
}
- params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+ params.pairwise_suite = wpa_s->pairwise_cipher;
params.group_suite = params.pairwise_suite;
#ifdef CONFIG_P2P
@@ -490,9 +569,14 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
if (wpa_s->parent->set_ap_uapsd)
params.uapsd = wpa_s->parent->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))
+ params.freq.freq = 0; /* set channel after CAC */
+
if (wpa_drv_associate(wpa_s, &params) < 0) {
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
return -1;
@@ -503,7 +587,11 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
+ hapd_iface->smps_modes = wpa_s->drv_smps_modes;
hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
+ hapd_iface->extended_capa = wpa_s->extended_capa;
+ hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
+ hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
if (conf == NULL) {
@@ -516,8 +604,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
sizeof(wpa_s->conf->wmm_ac_params));
if (params.uapsd > 0) {
- conf->bss->wmm_enabled = 1;
- conf->bss->wmm_uapsd = 1;
+ conf->bss[0]->wmm_enabled = 1;
+ conf->bss[0]->wmm_uapsd = 1;
}
if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
@@ -528,9 +616,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_P2P
if (ssid->mode == WPAS_MODE_P2P_GO)
- conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+ conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
- conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+ conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
P2P_GROUP_FORMATION;
#endif /* CONFIG_P2P */
@@ -545,7 +633,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
for (i = 0; i < conf->num_bss; i++) {
hapd_iface->bss[i] =
hostapd_alloc_bss_data(hapd_iface, conf,
- &conf->bss[i]);
+ conf->bss[i]);
if (hapd_iface->bss[i] == NULL) {
wpa_supplicant_ap_deinit(wpa_s);
return -1;
@@ -566,12 +654,18 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
#ifdef CONFIG_P2P
+ hapd_iface->bss[i]->new_psk_cb = ap_new_psk_cb;
+ hapd_iface->bss[i]->new_psk_cb_ctx = wpa_s;
hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
ssid);
#endif /* CONFIG_P2P */
hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
+#ifdef CONFIG_TESTING_OPTIONS
+ hapd_iface->bss[i]->ext_eapol_frame_io =
+ wpa_s->ext_eapol_frame_io;
+#endif /* CONFIG_TESTING_OPTIONS */
}
os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
@@ -579,6 +673,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
wpa_s->current_ssid = ssid;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
@@ -602,16 +697,19 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
return;
wpa_s->current_ssid = NULL;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->assoc_freq = 0;
-#ifdef CONFIG_P2P
- if (wpa_s->ap_iface->bss)
- wpa_s->ap_iface->bss[0]->p2p_group = NULL;
- wpas_p2p_group_deinit(wpa_s);
-#endif /* CONFIG_P2P */
+ wpas_p2p_ap_deinit(wpa_s);
+ wpa_s->ap_iface->driver_ap_teardown =
+ !!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
hostapd_interface_deinit(wpa_s->ap_iface);
hostapd_interface_free(wpa_s->ap_iface);
wpa_s->ap_iface = NULL;
wpa_drv_deinit_ap(wpa_s);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+ " reason=%d locally_generated=1",
+ MAC2STR(wpa_s->own_addr), WLAN_REASON_DEAUTH_LEAVING);
}
@@ -630,6 +728,8 @@ void ap_eapol_tx_status(void *ctx, const u8 *dst,
{
#ifdef NEED_AP_MLME
struct wpa_supplicant *wpa_s = ctx;
+ if (!wpa_s->ap_iface)
+ return;
hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
#endif /* NEED_AP_MLME */
}
@@ -738,9 +838,14 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
if (pin == NULL) {
unsigned int rpin = wps_generate_pin();
ret_len = os_snprintf(buf, buflen, "%08d", rpin);
+ if (os_snprintf_error(buflen, ret_len))
+ return -1;
pin = buf;
- } else
+ } else if (buf) {
ret_len = os_snprintf(buf, buflen, "%s", pin);
+ if (os_snprintf_error(buflen, ret_len))
+ return -1;
+ }
ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
timeout);
@@ -830,7 +935,7 @@ int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
return -1;
hapd = wpa_s->ap_iface->bss[0];
ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
- if (ret < 0 || ret >= (int) sizeof(pin_txt))
+ if (os_snprintf_error(sizeof(pin_txt), ret))
return -1;
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(pin_txt);
@@ -866,6 +971,47 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
hapd->conf->ap_pin = NULL;
}
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_hs_cr(hapd, ndef);
+}
+
+
+int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_report_handover(hapd, req, sel);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
#endif /* CONFIG_WPS */
@@ -874,30 +1020,45 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
- if (wpa_s->ap_iface == NULL)
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else if (wpa_s->ifmsh)
+ hapd = wpa_s->ifmsh->bss[0];
+ else
return -1;
- return hostapd_ctrl_iface_sta_first(wpa_s->ap_iface->bss[0],
- buf, buflen);
+ return hostapd_ctrl_iface_sta_first(hapd, buf, buflen);
}
int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen)
{
- if (wpa_s->ap_iface == NULL)
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else if (wpa_s->ifmsh)
+ hapd = wpa_s->ifmsh->bss[0];
+ else
return -1;
- return hostapd_ctrl_iface_sta(wpa_s->ap_iface->bss[0], txtaddr,
- buf, buflen);
+ return hostapd_ctrl_iface_sta(hapd, txtaddr, buf, buflen);
}
int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen)
{
- if (wpa_s->ap_iface == NULL)
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else if (wpa_s->ifmsh)
+ hapd = wpa_s->ifmsh->bss[0];
+ else
return -1;
- return hostapd_ctrl_iface_sta_next(wpa_s->ap_iface->bss[0], txtaddr,
- buf, buflen);
+ return hostapd_ctrl_iface_sta_next(hapd, txtaddr, buf, buflen);
}
@@ -943,7 +1104,7 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
wpa_cipher_txt(conf->wpa_group),
wpa_key_mgmt_txt(conf->wpa_key_mgmt,
conf->wpa));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
return pos - buf;
@@ -965,9 +1126,9 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_P2P
if (ssid->mode == WPAS_MODE_P2P_GO)
- iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+ iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER;
else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
- iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+ iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER |
P2P_GROUP_FORMATION;
#endif /* CONFIG_P2P */
@@ -981,14 +1142,40 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
}
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings)
+{
+#ifdef NEED_AP_MLME
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return -1;
+
+ return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+#else /* NEED_AP_MLME */
+ return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
+{
+ struct csa_settings settings;
+ int ret = hostapd_parse_csa_settings(pos, &settings);
+
+ if (ret)
+ return ret;
+
+ return ap_switch_channel(wpa_s, &settings);
+}
+
+
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset)
+ int offset, int width, int cf1, int cf2)
{
if (!wpa_s->ap_iface)
return;
wpa_s->assoc_freq = freq;
- hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+ hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1);
}
@@ -1031,3 +1218,122 @@ int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
return 0;
}
+
+
+#ifdef CONFIG_WPS_NFC
+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_data *hapd;
+ struct wps_context *wps;
+
+ if (!wpa_s->ap_iface)
+ return -1;
+ 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) {
+ wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known");
+ return -1;
+ }
+
+ dh5_free(wps->dh_ctx);
+ wpabuf_free(wps->dh_pubkey);
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = wpabuf_dup(
+ wpa_s->parent->conf->wps_nfc_dh_privkey);
+ wps->dh_pubkey = wpabuf_dup(
+ wpa_s->parent->conf->wps_nfc_dh_pubkey);
+ if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+ wps->dh_ctx = NULL;
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
+ return -1;
+ }
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+ if (wps->dh_ctx == NULL)
+ return -1;
+
+ return wps_registrar_add_nfc_pw_token(hapd->wps->registrar, pubkey_hash,
+ pw_id,
+ pw ? wpabuf_head(pw) : NULL,
+ pw ? wpabuf_len(pw) : 0, 1);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (!wpa_s->ap_iface)
+ return -1;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_ctrl_iface_stop_ap(hapd);
+}
+
+
+#ifdef NEED_AP_MLME
+void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_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,
+ 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)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_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,
+ 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)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_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,
+ 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)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_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,
+ 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)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_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,
+ radar->ht_enabled, radar->chan_offset,
+ radar->chan_width, radar->cf1, radar->cf2);
+}
+#endif /* NEED_AP_MLME */
diff --git a/contrib/wpa/wpa_supplicant/ap.h b/contrib/wpa/wpa_supplicant/ap.h
index 536064f..3f4151d 100644
--- a/contrib/wpa/wpa_supplicant/ap.h
+++ b/contrib/wpa/wpa_supplicant/ap.h
@@ -50,7 +50,47 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr);
void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+int ap_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings);
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset);
+ int offset, int width, int cf1, int cf2);
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef);
+#ifdef CONFIG_AP
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef);
+#else /* CONFIG_AP */
+static inline struct wpabuf *
+wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ return NULL;
+}
+#endif /* CONFIG_AP */
+
+int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
+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 wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
+
+void wpas_event_dfs_radar_detected(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);
#endif /* AP_H */
diff --git a/contrib/wpa/wpa_supplicant/bgscan.c b/contrib/wpa/wpa_supplicant/bgscan.c
index 9a9bd52..f74cdbf 100644
--- a/contrib/wpa/wpa_supplicant/bgscan.c
+++ b/contrib/wpa/wpa_supplicant/bgscan.c
@@ -31,9 +31,9 @@ static const struct bgscan_ops * bgscan_modules[] = {
};
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const char *name)
{
- const char *name = ssid->bgscan;
const char *params;
size_t nlen;
int i;
@@ -41,7 +41,7 @@ int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
bgscan_deinit(wpa_s);
if (name == NULL)
- return 0;
+ 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 e9d15fc..9131e4e 100644
--- a/contrib/wpa/wpa_supplicant/bgscan.h
+++ b/contrib/wpa/wpa_supplicant/bgscan.h
@@ -29,7 +29,8 @@ struct bgscan_ops {
#ifdef CONFIG_BGSCAN
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const char *name);
void bgscan_deinit(struct wpa_supplicant *wpa_s);
int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -41,7 +42,7 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
#else /* CONFIG_BGSCAN */
static inline int bgscan_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid, const char name)
{
return 0;
}
diff --git a/contrib/wpa/wpa_supplicant/bgscan_learn.c b/contrib/wpa/wpa_supplicant/bgscan_learn.c
index 07d31e4..a320cc4 100644
--- a/contrib/wpa/wpa_supplicant/bgscan_learn.c
+++ b/contrib/wpa/wpa_supplicant/bgscan_learn.c
@@ -34,7 +34,7 @@ struct bgscan_learn_data {
int signal_threshold;
int short_interval; /* use if signal < threshold */
int long_interval; /* use if signal > threshold */
- struct os_time last_bgscan;
+ struct os_reltime last_bgscan;
char *fname;
struct dl_list bss;
int *supp_freqs;
@@ -240,17 +240,14 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
if (data->supp_freqs == NULL)
return freqs;
- idx = data->probe_idx + 1;
- while (idx != data->probe_idx) {
- if (data->supp_freqs[idx] == 0) {
- if (data->probe_idx == 0)
- break;
- idx = 0;
- }
+ idx = data->probe_idx;
+ do {
if (!in_array(freqs, data->supp_freqs[idx])) {
wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
"%u", data->supp_freqs[idx]);
- data->probe_idx = idx;
+ data->probe_idx = idx + 1;
+ if (data->supp_freqs[data->probe_idx] == 0)
+ data->probe_idx = 0;
n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
return freqs;
@@ -262,7 +259,9 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
}
idx++;
- }
+ if (data->supp_freqs[idx] == 0)
+ idx = 0;
+ } while (idx != data->probe_idx);
return freqs;
}
@@ -295,7 +294,7 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
int ret;
ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
freqs[i]);
- if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+ if (os_snprintf_error(msg + sizeof(msg) - pos, ret))
break;
pos += ret;
}
@@ -311,7 +310,7 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
eloop_register_timeout(data->scan_interval, 0,
bgscan_learn_timeout, data, NULL);
} else
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
os_free(freqs);
}
@@ -363,6 +362,9 @@ static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
for (j = 0; j < modes[i].num_channels; j++) {
if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
+ /* some hw modes (e.g. 11b & 11g) contain same freqs */
+ if (in_array(freqs, modes[i].channels[j].freq))
+ continue;
n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
continue;
@@ -419,6 +421,14 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
data->scan_interval = data->short_interval;
+ if (data->signal_threshold) {
+ /* Poll for signal info to set initial scan interval */
+ struct wpa_signal_info siginfo;
+ if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+ siginfo.current_signal >= data->signal_threshold)
+ data->scan_interval = data->long_interval;
+ }
+
eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
data, NULL);
@@ -428,7 +438,7 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
* us skip an immediate new scan in cases where the current signal
* level is below the bgscan threshold.
*/
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
return data;
}
@@ -555,7 +565,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above,
{
struct bgscan_learn_data *data = priv;
int scan = 0;
- struct os_time now;
+ struct os_reltime now;
if (data->short_interval == data->long_interval ||
data->signal_threshold == 0)
@@ -569,7 +579,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above,
wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan "
"interval");
data->scan_interval = data->short_interval;
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 1)
scan = 1;
} else if (data->scan_interval == data->short_interval && above) {
@@ -584,7 +594,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above,
* Signal dropped further 4 dB. Request a new scan if we have
* not yet scanned in a while.
*/
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 10)
scan = 1;
}
diff --git a/contrib/wpa/wpa_supplicant/bgscan_simple.c b/contrib/wpa/wpa_supplicant/bgscan_simple.c
index 479f703..a467cc5 100644
--- a/contrib/wpa/wpa_supplicant/bgscan_simple.c
+++ b/contrib/wpa/wpa_supplicant/bgscan_simple.c
@@ -26,7 +26,7 @@ struct bgscan_simple_data {
int max_short_scans; /* maximum times we short-scan before back-off */
int short_interval; /* use if signal < threshold */
int long_interval; /* use if signal > threshold */
- struct os_time last_bgscan;
+ struct os_reltime last_bgscan;
};
@@ -75,7 +75,7 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
*/
data->short_scan_count--;
}
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
}
}
@@ -159,7 +159,7 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
* us skip an immediate new scan in cases where the current signal
* level is below the bgscan threshold.
*/
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
return data;
}
@@ -211,7 +211,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
{
struct bgscan_simple_data *data = priv;
int scan = 0;
- struct os_time now;
+ struct os_reltime now;
if (data->short_interval == data->long_interval ||
data->signal_threshold == 0)
@@ -225,7 +225,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
"bgscan interval");
data->scan_interval = data->short_interval;
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 1 &&
data->short_scan_count <= data->max_short_scans)
/*
@@ -259,7 +259,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
* Signal dropped further 4 dB. Request a new scan if we have
* not yet scanned in a while.
*/
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 10)
scan = 1;
}
diff --git a/contrib/wpa/wpa_supplicant/bss.c b/contrib/wpa/wpa_supplicant/bss.c
index 87b7db8..b4c47e2 100644
--- a/contrib/wpa/wpa_supplicant/bss.c
+++ b/contrib/wpa/wpa_supplicant/bss.c
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2012, 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.
@@ -85,6 +85,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
+ ANQP_DUP(capability_list);
ANQP_DUP(venue_name);
ANQP_DUP(network_auth_type);
ANQP_DUP(roaming_consortium);
@@ -94,10 +95,12 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
ANQP_DUP(domain_name);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
+ ANQP_DUP(hs20_capability_list);
ANQP_DUP(hs20_operator_friendly_name);
ANQP_DUP(hs20_wan_metrics);
ANQP_DUP(hs20_connection_capability);
ANQP_DUP(hs20_operating_class);
+ ANQP_DUP(hs20_osu_providers_list);
#endif /* CONFIG_HS20 */
#undef ANQP_DUP
@@ -153,6 +156,7 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
}
#ifdef CONFIG_INTERWORKING
+ wpabuf_free(anqp->capability_list);
wpabuf_free(anqp->venue_name);
wpabuf_free(anqp->network_auth_type);
wpabuf_free(anqp->roaming_consortium);
@@ -162,16 +166,43 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
wpabuf_free(anqp->domain_name);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
+ wpabuf_free(anqp->hs20_capability_list);
wpabuf_free(anqp->hs20_operator_friendly_name);
wpabuf_free(anqp->hs20_wan_metrics);
wpabuf_free(anqp->hs20_connection_capability);
wpabuf_free(anqp->hs20_operating_class);
+ wpabuf_free(anqp->hs20_osu_providers_list);
#endif /* CONFIG_HS20 */
os_free(anqp);
}
+static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *old_bss,
+ struct wpa_bss *new_bss)
+{
+ struct wpa_radio_work *work;
+ struct wpa_connect_work *cwork;
+
+ work = radio_work_pending(wpa_s, "sme-connect");
+ if (!work)
+ work = radio_work_pending(wpa_s, "connect");
+ if (!work)
+ return;
+
+ cwork = work->ctx;
+ if (cwork->bss != old_bss)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "Update BSS pointer for the pending connect radio work");
+ cwork->bss = new_bss;
+ if (!new_bss)
+ cwork->bss_removed = 1;
+}
+
+
static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const char *reason)
{
@@ -188,6 +219,7 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
}
}
+ wpa_bss_update_pending_connect(wpa_s, bss, NULL);
dl_list_del(&bss->list);
dl_list_del(&bss->list_id);
wpa_s->num_bss--;
@@ -224,10 +256,27 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
-static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+static void calculate_update_time(const struct os_reltime *fetch_time,
+ unsigned int age_ms,
+ struct os_reltime *update_time)
{
os_time_t usec;
+ update_time->sec = fetch_time->sec;
+ update_time->usec = fetch_time->usec;
+ update_time->sec -= age_ms / 1000;
+ usec = (age_ms % 1000) * 1000;
+ if (update_time->usec < usec) {
+ update_time->sec--;
+ update_time->usec += 1000000;
+ }
+ update_time->usec -= usec;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+ struct os_reltime *fetch_time)
+{
dst->flags = src->flags;
os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
dst->freq = src->freq;
@@ -237,15 +286,10 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
dst->noise = src->noise;
dst->level = src->level;
dst->tsf = src->tsf;
+ dst->est_throughput = src->est_throughput;
+ dst->snr = src->snr;
- os_get_time(&dst->last_update);
- dst->last_update.sec -= src->age / 1000;
- usec = (src->age % 1000) * 1000;
- if (dst->last_update.usec < usec) {
- dst->last_update.sec--;
- dst->last_update.usec += 1000000;
- }
- dst->last_update.usec -= usec;
+ calculate_update_time(fetch_time, src->age, &dst->last_update);
}
@@ -268,8 +312,9 @@ static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
return bss == wpa_s->current_bss ||
- os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
- os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+ (!is_zero_ether_addr(bss->bssid) &&
+ (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+ os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0));
}
@@ -315,7 +360,8 @@ static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
const u8 *ssid, size_t ssid_len,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res,
+ struct os_reltime *fetch_time)
{
struct wpa_bss *bss;
@@ -324,7 +370,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
return NULL;
bss->id = wpa_s->bss_next_id++;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
os_memcpy(bss->ssid, ssid, ssid_len);
bss->ssid_len = ssid_len;
bss->ie_len = res->ie_len;
@@ -332,6 +378,14 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
wpa_bss_set_hessid(bss);
+ if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
+ wpa_bss_remove_oldest(wpa_s) != 0) {
+ wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
+ "because all BSSes are in use. We should normally "
+ "not get here!", (int) wpa_s->num_bss + 1);
+ wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
+ }
+
dl_list_add_tail(&wpa_s->bss, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
wpa_s->num_bss++;
@@ -339,13 +393,6 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
" SSID '%s'",
bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
- if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
- wpa_bss_remove_oldest(wpa_s) != 0) {
- wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
- "because all BSSes are in use. We should normally "
- "not get here!", (int) wpa_s->num_bss);
- wpa_s->conf->bss_max_count = wpa_s->num_bss;
- }
return bss;
}
@@ -475,21 +522,39 @@ static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
if (changes & WPA_BSS_RATES_CHANGED_FLAG)
wpas_notify_bss_rates_changed(wpa_s, bss->id);
+
+ wpas_notify_bss_seen(wpa_s, bss->id);
}
static struct wpa_bss *
wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res, struct os_reltime *fetch_time)
{
u32 changes;
changes = wpa_bss_compare_res(bss, res);
bss->scan_miss_count = 0;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
/* Move the entry to the end of the list */
dl_list_del(&bss->list);
+#ifdef CONFIG_P2P
+ if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
+ /*
+ * This can happen when non-P2P station interface runs a scan
+ * without P2P IE in the Probe Request frame. P2P GO would reply
+ * to that with a Probe Response that does not include P2P IE.
+ * Do not update the IEs in this BSS entry to avoid such loss of
+ * information that may be needed for P2P operations to
+ * determine group information.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
+ MACSTR " since that would remove P2P IE information",
+ MAC2STR(bss->bssid));
+ } else
+#endif /* CONFIG_P2P */
if (bss->ie_len + bss->beacon_ie_len >=
res->ie_len + res->beacon_ie_len) {
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
@@ -511,6 +576,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
if (wpa_s->current_bss == bss)
wpa_s->current_bss = nbss;
+ wpa_bss_update_pending_connect(wpa_s, bss, nbss);
bss = nbss;
os_memcpy(bss + 1, res + 1,
res->ie_len + res->beacon_ie_len);
@@ -551,17 +617,35 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
* wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
* @wpa_s: Pointer to wpa_supplicant data
* @res: Scan result
+ * @fetch_time: Time when the result was fetched from the driver
*
* This function updates a BSS table entry (or adds one) based on a scan result.
* This is called separately for each scan result between the calls to
* wpa_bss_update_start() and wpa_bss_update_end().
*/
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res,
+ struct os_reltime *fetch_time)
{
- const u8 *ssid, *p2p;
+ const u8 *ssid, *p2p, *mesh;
struct wpa_bss *bss;
+ if (wpa_s->conf->ignore_old_scan_res) {
+ struct os_reltime update;
+ calculate_update_time(fetch_time, res->age, &update);
+ if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
+ struct os_reltime age;
+ os_reltime_sub(&wpa_s->scan_trigger_time, &update,
+ &age);
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
+ "table entry that is %u.%06u seconds older "
+ "than our scan trigger",
+ (unsigned int) age.sec,
+ (unsigned int) age.usec);
+ return;
+ }
+ }
+
ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
if (ssid == NULL) {
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
@@ -593,11 +677,26 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
/* TODO: add option for ignoring BSSes we are not interested in
* (to save memory) */
+
+ mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
+ if (mesh && mesh[1] <= 32)
+ ssid = mesh;
+
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
if (bss == NULL)
- bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
- else
- bss = wpa_bss_update(wpa_s, bss, res);
+ bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
+ else {
+ bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
+ if (wpa_s->last_scan_res) {
+ unsigned int i;
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (bss == wpa_s->last_scan_res[i]) {
+ /* Already in the list */
+ return;
+ }
+ }
+ }
+ }
if (bss == NULL)
return;
@@ -616,7 +715,8 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
wpa_s->last_scan_res_size = siz;
}
- wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
+ if (wpa_s->last_scan_res)
+ wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
}
@@ -676,26 +776,10 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
{
struct wpa_bss *bss, *n;
- wpa_s->last_scan_full = 0;
- os_get_time(&wpa_s->last_scan);
+ os_get_reltime(&wpa_s->last_scan);
if (!new_scan)
return; /* do not expire entries without new scan */
- if (info && !info->aborted && !info->freqs) {
- size_t i;
- if (info->num_ssids == 0) {
- wpa_s->last_scan_full = 1;
- } else {
- for (i = 0; i < info->num_ssids; i++) {
- if (info->ssids[i].ssid == NULL ||
- info->ssids[i].ssid_len == 0) {
- wpa_s->last_scan_full = 1;
- break;
- }
- }
- }
- }
-
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_in_use(wpa_s, bss))
continue;
@@ -709,10 +793,8 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
}
}
- wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u "
- "last_scan_full=%d",
- wpa_s->last_scan_res_used, wpa_s->last_scan_res_size,
- wpa_s->last_scan_full);
+ wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
+ wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
}
@@ -726,19 +808,19 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
{
struct wpa_bss *bss, *n;
- struct os_time t;
+ struct os_reltime t;
if (dl_list_empty(&wpa_s->bss))
return;
- os_get_time(&t);
+ os_get_reltime(&t);
t.sec -= age;
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_in_use(wpa_s, bss))
continue;
- if (os_time_before(&bss->last_update, &t)) {
+ if (os_reltime_before(&bss->last_update, &t)) {
wpa_bss_remove(wpa_s, bss, __func__);
} else
break;
@@ -782,6 +864,8 @@ void wpa_bss_flush(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss, *n;
+ wpa_s->clear_driver_scan_cache = 1;
+
if (wpa_s->bss.next == NULL)
return; /* BSS table not yet initialized */
@@ -824,6 +908,34 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
}
+/**
+ * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
+ * find the entry that has the most recent update. This can help in finding the
+ * correct entry in cases where the SSID of the AP may have changed recently
+ * (e.g., in WPS reconfiguration cases).
+ */
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bss *bss, *found = NULL;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
+ continue;
+ if (found == NULL ||
+ os_reltime_before(&found->last_update, &bss->last_update))
+ found = bss;
+ }
+ return found;
+}
+
+
#ifdef CONFIG_P2P
/**
* wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
@@ -865,6 +977,29 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
/**
+ * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @idf: Smallest allowed identifier assigned for the entry
+ * @idf: Largest allowed identifier assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
+ * smallest id value to be fetched within the specified range without the
+ * caller having to know the exact id.
+ */
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl)
+{
+ struct wpa_bss *bss;
+ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+ if (bss->id >= idf && bss->id <= idl)
+ return bss;
+ }
+ return NULL;
+}
+
+
+/**
* wpa_bss_get_ie - Fetch a specified information element from a BSS entry
* @bss: BSS table entry
* @ie: Information element identitifier (WLAN_EID_*)
@@ -922,6 +1057,43 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
/**
+ * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ *
+ * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+ u32 vendor_type)
+{
+ const u8 *end, *pos;
+
+ if (bss->beacon_ie_len == 0)
+ return NULL;
+
+ pos = (const u8 *) (bss + 1);
+ pos += bss->ie_len;
+ end = pos + bss->beacon_ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ vendor_type == WPA_GET_BE32(&pos[2]))
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
+/**
* wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
* @bss: BSS table entry
* @vendor_type: Vendor type (four octets starting the IE payload)
diff --git a/contrib/wpa/wpa_supplicant/bss.h b/contrib/wpa/wpa_supplicant/bss.h
index 01f6c59..634aa3c 100644
--- a/contrib/wpa/wpa_supplicant/bss.h
+++ b/contrib/wpa/wpa_supplicant/bss.h
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2010, 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.
@@ -26,6 +26,7 @@ struct wpa_bss_anqp {
/** Number of BSS entries referring to this ANQP data instance */
unsigned int users;
#ifdef CONFIG_INTERWORKING
+ struct wpabuf *capability_list;
struct wpabuf *venue_name;
struct wpabuf *network_auth_type;
struct wpabuf *roaming_consortium;
@@ -35,10 +36,12 @@ struct wpa_bss_anqp {
struct wpabuf *domain_name;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
+ struct wpabuf *hs20_capability_list;
struct wpabuf *hs20_operator_friendly_name;
struct wpabuf *hs20_wan_metrics;
struct wpabuf *hs20_connection_capability;
struct wpabuf *hs20_operating_class;
+ struct wpabuf *hs20_osu_providers_list;
#endif /* CONFIG_HS20 */
};
@@ -84,7 +87,11 @@ struct wpa_bss {
/** Timestamp of last Beacon/Probe Response frame */
u64 tsf;
/** Time of the last update (i.e., Beacon or Probe Response RX) */
- struct os_time last_update;
+ struct os_reltime last_update;
+ /** Estimated throughput in kbps */
+ unsigned int est_throughput;
+ /** Signal-to-noise ratio in dB */
+ int snr;
/** ANQP data */
struct wpa_bss_anqp *anqp;
/** Length of the following IE field in octets (from Probe Response) */
@@ -97,7 +104,8 @@ struct wpa_bss {
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 wpa_scan_res *res,
+ struct os_reltime *fetch_time);
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);
@@ -108,11 +116,17 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ssid, size_t ssid_len);
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid);
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
+const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
+ u32 vendor_type);
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
u32 vendor_type);
struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
@@ -122,4 +136,15 @@ 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);
+static inline int bss_is_dmg(const struct wpa_bss *bss)
+{
+ return bss->freq > 45000;
+}
+
+static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
+{
+ if (bss != NULL && new_level < 0)
+ bss->level = new_level;
+}
+
#endif /* BSS_H */
diff --git a/contrib/wpa/wpa_supplicant/config.c b/contrib/wpa/wpa_supplicant/config.c
index 0fab07a..8e6cd20 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#include "common.h"
#include "utils/uuid.h"
+#include "utils/ip_addr.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -178,10 +179,17 @@ static int wpa_config_parse_int(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
{
- int *dst;
+ int val, *dst;
+ char *end;
dst = (int *) (((u8 *) ssid) + (long) data->param1);
- *dst = atoi(value);
+ val = strtol(value, &end, 0);
+ if (*end) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+ line, value);
+ return -1;
+ }
+ *dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
if (data->param3 && *dst < (long) data->param3) {
@@ -217,7 +225,7 @@ static char * wpa_config_write_int(const struct parse_data *data,
if (value == NULL)
return NULL;
res = os_snprintf(value, 20, "%d", *src);
- if (res < 0 || res >= 20) {
+ if (os_snprintf_error(20, res)) {
os_free(value);
return NULL;
}
@@ -227,6 +235,99 @@ static char * wpa_config_write_int(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_addr_list(const struct parse_data *data,
+ int line, const char *value,
+ u8 **list, size_t *num, char *name,
+ u8 abort_on_error, u8 masked)
+{
+ const char *pos;
+ u8 *buf, *n, addr[2 * ETH_ALEN];
+ size_t count;
+
+ buf = NULL;
+ count = 0;
+
+ pos = value;
+ while (pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+
+ if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) {
+ if (abort_on_error || count == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid %s address '%s'",
+ line, name, value);
+ os_free(buf);
+ return -1;
+ }
+ /* continue anyway since this could have been from a
+ * truncated configuration file line */
+ wpa_printf(MSG_INFO,
+ "Line %d: Ignore likely truncated %s address '%s'",
+ line, name, pos);
+ } else {
+ n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN);
+ if (n == NULL) {
+ os_free(buf);
+ return -1;
+ }
+ buf = n;
+ os_memmove(buf + 2 * ETH_ALEN, buf,
+ count * 2 * ETH_ALEN);
+ os_memcpy(buf, addr, 2 * ETH_ALEN);
+ count++;
+ wpa_printf(MSG_MSGDUMP,
+ "%s: addr=" MACSTR " mask=" MACSTR,
+ name, MAC2STR(addr),
+ MAC2STR(&addr[ETH_ALEN]));
+ }
+
+ pos = os_strchr(pos, ' ');
+ }
+
+ os_free(*list);
+ *list = buf;
+ *num = count;
+
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_addr_list(const struct parse_data *data,
+ const u8 *list, size_t num, char *name)
+{
+ char *value, *end, *pos;
+ int res;
+ size_t i;
+
+ if (list == NULL || num == 0)
+ return NULL;
+
+ value = os_malloc(2 * 20 * num);
+ if (value == NULL)
+ return NULL;
+ pos = value;
+ end = value + 2 * 20 * num;
+
+ for (i = num; i > 0; i--) {
+ const u8 *a = list + (i - 1) * 2 * ETH_ALEN;
+ const u8 *m = a + ETH_ALEN;
+
+ if (i < num)
+ *pos++ = ' ';
+ res = hwaddr_mask_txt(pos, end - pos, a, m);
+ if (res < 0) {
+ os_free(value);
+ return NULL;
+ }
+ pos += res;
+ }
+
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
static int wpa_config_parse_bssid(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -262,7 +363,7 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
if (value == NULL)
return NULL;
res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
- if (res < 0 || res >= 20) {
+ if (os_snprintf_error(20, res)) {
os_free(value);
return NULL;
}
@@ -272,13 +373,57 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
#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)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_blacklist,
+ &ssid->num_bssid_blacklist,
+ "bssid_blacklist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
+ ssid->num_bssid_blacklist,
+ "bssid_blacklist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_whitelist,
+ &ssid->num_bssid_whitelist,
+ "bssid_whitelist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
+ ssid->num_bssid_whitelist,
+ "bssid_whitelist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
static int wpa_config_parse_psk(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
#ifdef CONFIG_EXT_PASSWORD
if (os_strncmp(value, "ext:", 4) == 0) {
- os_free(ssid->passphrase);
+ str_clear_free(ssid->passphrase);
ssid->passphrase = NULL;
ssid->psk_set = 0;
os_free(ssid->ext_psk);
@@ -314,12 +459,10 @@ static int wpa_config_parse_psk(const struct parse_data *data,
os_memcmp(ssid->passphrase, value, len) == 0)
return 0;
ssid->psk_set = 0;
- os_free(ssid->passphrase);
- ssid->passphrase = os_malloc(len + 1);
+ str_clear_free(ssid->passphrase);
+ ssid->passphrase = dup_binstr(value, len);
if (ssid->passphrase == NULL)
return -1;
- os_memcpy(ssid->passphrase, value, len);
- ssid->passphrase[len] = '\0';
return 0;
#else /* CONFIG_NO_PBKDF2 */
wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
@@ -335,7 +478,7 @@ static int wpa_config_parse_psk(const struct parse_data *data,
return -1;
}
- os_free(ssid->passphrase);
+ str_clear_free(ssid->passphrase);
ssid->passphrase = NULL;
ssid->psk_set = 1;
@@ -352,9 +495,15 @@ static char * wpa_config_write_psk(const struct parse_data *data,
if (ssid->ext_psk) {
size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
char *buf = os_malloc(len);
+ int res;
+
if (buf == NULL)
return NULL;
- os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ if (os_snprintf_error(len, res)) {
+ os_free(buf);
+ buf = NULL;
+ }
return buf;
}
#endif /* CONFIG_EXT_PASSWORD */
@@ -399,6 +548,8 @@ static int wpa_config_parse_proto(const struct parse_data *data,
else if (os_strcmp(start, "RSN") == 0 ||
os_strcmp(start, "WPA2") == 0)
val |= WPA_PROTO_RSN;
+ else if (os_strcmp(start, "OSEN") == 0)
+ val |= WPA_PROTO_OSEN;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
line, start);
@@ -427,28 +578,41 @@ static int wpa_config_parse_proto(const struct parse_data *data,
static char * wpa_config_write_proto(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- int first = 1, ret;
+ int ret;
char *buf, *pos, *end;
- pos = buf = os_zalloc(10);
+ pos = buf = os_zalloc(20);
if (buf == NULL)
return NULL;
- end = buf + 10;
+ end = buf + 20;
if (ssid->proto & WPA_PROTO_WPA) {
- ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sWPA",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
- first = 0;
}
if (ssid->proto & WPA_PROTO_RSN) {
- ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sRSN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return buf;
+ pos += ret;
+ }
+
+ if (ssid->proto & WPA_PROTO_OSEN) {
+ ret = os_snprintf(pos, end - pos, "%sOSEN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
- first = 0;
+ }
+
+ if (pos == buf) {
+ os_free(buf);
+ buf = NULL;
}
return buf;
@@ -510,6 +674,18 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
else if (os_strcmp(start, "FT-SAE") == 0)
val |= WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_HS20
+ else if (os_strcmp(start, "OSEN") == 0)
+ val |= WPA_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_SUITEB
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -541,15 +717,15 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
char *buf, *pos, *end;
int ret;
- pos = buf = os_zalloc(50);
+ pos = buf = os_zalloc(100);
if (buf == NULL)
return NULL;
- end = buf + 50;
+ end = buf + 100;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -559,7 +735,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -569,7 +745,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -579,7 +755,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
ret = os_snprintf(pos, end - pos, "%sNONE",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -589,7 +765,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -597,160 +773,157 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
}
#ifdef CONFIG_IEEE80211R
- if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
- pos += os_snprintf(pos, end - pos, "%sFT-PSK",
- pos == buf ? "" : " ");
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+ ret = os_snprintf(pos, end - pos, "%sFT-PSK",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
- if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
- pos += os_snprintf(pos, end - pos, "%sFT-EAP",
- pos == buf ? "" : " ");
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+ ret = os_snprintf(pos, end - pos, "%sFT-EAP",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
- if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
- pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
- pos == buf ? "" : " ");
-
- if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
- pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
- pos == buf ? "" : " ");
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_WPS
- if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
- pos += os_snprintf(pos, end - pos, "%sWPS",
- pos == buf ? "" : " ");
-#endif /* CONFIG_WPS */
-
- return buf;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_cipher(int line, const char *value)
-{
- int val = 0, last;
- char *start, *end, *buf;
-
- buf = os_strdup(value);
- if (buf == NULL)
- return -1;
- start = buf;
-
- while (*start != '\0') {
- while (*start == ' ' || *start == '\t')
- start++;
- if (*start == '\0')
- break;
- end = start;
- while (*end != ' ' && *end != '\t' && *end != '\0')
- end++;
- last = *end == '\0';
- *end = '\0';
- if (os_strcmp(start, "CCMP") == 0)
- val |= WPA_CIPHER_CCMP;
- else if (os_strcmp(start, "GCMP") == 0)
- val |= WPA_CIPHER_GCMP;
- else if (os_strcmp(start, "TKIP") == 0)
- val |= WPA_CIPHER_TKIP;
- else if (os_strcmp(start, "WEP104") == 0)
- val |= WPA_CIPHER_WEP104;
- else if (os_strcmp(start, "WEP40") == 0)
- val |= WPA_CIPHER_WEP40;
- else if (os_strcmp(start, "NONE") == 0)
- val |= WPA_CIPHER_NONE;
- else {
- wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
- line, start);
- os_free(buf);
- return -1;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
}
-
- if (last)
- break;
- start = end + 1;
+ pos += ret;
}
- os_free(buf);
- if (val == 0) {
- wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
- line);
- return -1;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
- return val;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_cipher(int cipher)
-{
- char *buf, *pos, *end;
- int ret;
-
- pos = buf = os_zalloc(50);
- if (buf == NULL)
- return NULL;
- end = buf + 50;
+#endif /* CONFIG_IEEE80211W */
- if (cipher & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP",
+#ifdef CONFIG_WPS
+ if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ ret = os_snprintf(pos, end - pos, "%sWPS",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
pos += ret;
}
+#endif /* CONFIG_WPS */
- if (cipher & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP",
+#ifdef CONFIG_SAE
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
pos += ret;
}
- if (cipher & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP",
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sFT-SAE",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
pos += ret;
}
+#endif /* CONFIG_SAE */
- if (cipher & WPA_CIPHER_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
+#ifdef CONFIG_HS20
+ if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) {
+ ret = os_snprintf(pos, end - pos, "%sOSEN",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
pos += ret;
}
+#endif /* CONFIG_HS20 */
- if (cipher & WPA_CIPHER_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40",
+#ifdef CONFIG_SUITEB
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
pos += ret;
}
+#endif /* CONFIG_SUITEB */
- if (cipher & WPA_CIPHER_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE",
+#ifdef CONFIG_SUITEB192
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
pos += ret;
}
+#endif /* CONFIG_SUITEB192 */
+
+ if (pos == buf) {
+ os_free(buf);
+ buf = NULL;
+ }
+
+ return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_cipher(int line, const char *value)
+{
+ int val = wpa_parse_cipher(value);
+ if (val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, value);
+ return -1;
+ }
+ if (val == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+ line);
+ return -1;
+ }
+ return val;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_cipher(int cipher)
+{
+ char *buf = os_zalloc(50);
+ if (buf == NULL)
+ return NULL;
+
+ if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) {
+ os_free(buf);
+ return NULL;
+ }
return buf;
}
@@ -765,8 +938,7 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
- WPA_CIPHER_NONE)) {
+ if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) {
wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
"(0x%x).", line, val);
return -1;
@@ -795,8 +967,7 @@ static int wpa_config_parse_group(const struct parse_data *data,
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
- WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) {
+ if (val & ~WPA_ALLOWED_GROUP_CIPHERS) {
wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
"(0x%x).", line, val);
return -1;
@@ -884,7 +1055,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
ret = os_snprintf(pos, end - pos, "%sOPEN",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -894,7 +1065,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
ret = os_snprintf(pos, end - pos, "%sSHARED",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -904,21 +1075,24 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
ret = os_snprintf(pos, end - pos, "%sLEAP",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
pos += ret;
}
+ if (pos == buf) {
+ os_free(buf);
+ buf = NULL;
+ }
+
return buf;
}
#endif /* NO_CONFIG_WRITE */
-static int * wpa_config_parse_freqs(const struct parse_data *data,
- struct wpa_ssid *ssid, int line,
- const char *value)
+static int * wpa_config_parse_int_array(const char *value)
{
int *freqs;
size_t used, len;
@@ -965,9 +1139,13 @@ static int wpa_config_parse_scan_freq(const struct parse_data *data,
{
int *freqs;
- freqs = wpa_config_parse_freqs(data, ssid, line, value);
+ freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
os_free(ssid->scan_freq);
ssid->scan_freq = freqs;
@@ -981,9 +1159,13 @@ static int wpa_config_parse_freq_list(const struct parse_data *data,
{
int *freqs;
- freqs = wpa_config_parse_freqs(data, ssid, line, value);
+ freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
os_free(ssid->freq_list);
ssid->freq_list = freqs;
@@ -1014,7 +1196,7 @@ static char * wpa_config_write_freqs(const struct parse_data *data,
for (i = 0; freqs[i]; i++) {
ret = os_snprintf(pos, end - pos, "%s%u",
i == 0 ? "" : " ", freqs[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -1137,7 +1319,7 @@ static char * wpa_config_write_eap(const struct parse_data *data,
if (name) {
ret = os_snprintf(pos, end - pos, "%s%s",
pos == buf ? "" : " ", name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
@@ -1157,7 +1339,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
if (os_strcmp(value, "NULL") == 0) {
wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
- os_free(ssid->eap.password);
+ bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = NULL;
ssid->eap.password_len = 0;
return 0;
@@ -1168,7 +1350,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
char *name = os_strdup(value + 4);
if (name == NULL)
return -1;
- os_free(ssid->eap.password);
+ bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = (u8 *) name;
ssid->eap.password_len = os_strlen(name);
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
@@ -1190,7 +1372,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
(u8 *) tmp, res_len);
- os_free(ssid->eap.password);
+ bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = (u8 *) tmp;
ssid->eap.password_len = res_len;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
@@ -1219,7 +1401,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
- os_free(ssid->eap.password);
+ bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = hash;
ssid->eap.password_len = 16;
ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
@@ -1289,9 +1471,9 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
line, (unsigned int) *len);
}
os_memcpy(key, buf, *len);
- os_free(buf);
+ str_clear_free(buf);
res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
- if (res >= 0 && (size_t) res < sizeof(title))
+ if (!os_snprintf_error(sizeof(title), res))
wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
return 0;
}
@@ -1378,57 +1560,60 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
#ifdef CONFIG_P2P
-static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
+static int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
- const char *pos;
- u8 *buf, *n, addr[ETH_ALEN];
- size_t count;
+ if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+ os_strcmp(value, "any") == 0) {
+ os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN);
+ wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any");
+ return 0;
+ }
+ if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.",
+ line, value);
+ return -1;
+ }
+ ssid->bssid_set = 1;
+ wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR,
+ MAC2STR(ssid->go_p2p_dev_addr));
+ return 0;
+}
- buf = NULL;
- count = 0;
- pos = value;
- while (pos && *pos) {
- while (*pos == ' ')
- pos++;
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value;
+ int res;
- if (hwaddr_aton(pos, addr)) {
- if (count == 0) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "p2p_client_list address '%s'.",
- line, value);
- os_free(buf);
- return -1;
- }
- /* continue anyway since this could have been from a
- * truncated configuration file line */
- wpa_printf(MSG_INFO, "Line %d: Ignore likely "
- "truncated p2p_client_list address '%s'",
- line, pos);
- } else {
- n = os_realloc_array(buf, count + 1, ETH_ALEN);
- if (n == NULL) {
- os_free(buf);
- return -1;
- }
- buf = n;
- os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
- os_memcpy(buf, addr, ETH_ALEN);
- count++;
- wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
- addr, ETH_ALEN);
- }
+ if (is_zero_ether_addr(ssid->go_p2p_dev_addr))
+ return NULL;
- pos = os_strchr(pos, ' ');
+ value = os_malloc(20);
+ if (value == NULL)
+ return NULL;
+ res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
+ if (os_snprintf_error(20, res)) {
+ os_free(value);
+ return NULL;
}
+ value[20 - 1] = '\0';
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
- os_free(ssid->p2p_client_list);
- ssid->p2p_client_list = buf;
- ssid->num_p2p_clients = count;
- return 0;
+static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->p2p_client_list,
+ &ssid->num_p2p_clients,
+ "p2p_client_list", 0, 0);
}
@@ -1436,39 +1621,107 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- char *value, *end, *pos;
- int res;
- size_t i;
+ return wpa_config_write_addr_list(data, ssid->p2p_client_list,
+ ssid->num_p2p_clients,
+ "p2p_client_list");
+}
+#endif /* NO_CONFIG_WRITE */
- if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
- return NULL;
- value = os_malloc(20 * ssid->num_p2p_clients);
- if (value == NULL)
- return NULL;
+static int wpa_config_parse_psk_list(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ struct psk_list_entry *p;
+ const char *pos;
+
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return -1;
+
pos = value;
- end = value + 20 * ssid->num_p2p_clients;
+ if (os_strncmp(pos, "P2P-", 4) == 0) {
+ p->p2p = 1;
+ pos += 4;
+ }
- for (i = ssid->num_p2p_clients; i > 0; i--) {
- res = os_snprintf(pos, end - pos, MACSTR " ",
- MAC2STR(ssid->p2p_client_list +
- (i - 1) * ETH_ALEN));
- if (res < 0 || res >= end - pos) {
- os_free(value);
- return NULL;
- }
- pos += res;
+ if (hwaddr_aton(pos, p->addr)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'",
+ line, pos);
+ os_free(p);
+ return -1;
+ }
+ pos += 17;
+ if (*pos != '-') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'",
+ line, pos);
+ os_free(p);
+ return -1;
}
+ pos++;
- if (pos > value)
- pos[-1] = '\0';
+ if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'",
+ line, pos);
+ os_free(p);
+ return -1;
+ }
- return value;
+ dl_list_add(&ssid->psk_list, &p->list);
+
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_psk_list(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return NULL;
}
#endif /* NO_CONFIG_WRITE */
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_MESH
+
+static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ int *rates = wpa_config_parse_int_array(value);
+
+ if (rates == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'",
+ line, value);
+ return -1;
+ }
+ if (rates[0] == 0) {
+ os_free(rates);
+ rates = NULL;
+ }
+
+ os_free(ssid->mesh_basic_rates);
+ ssid->mesh_basic_rates = rates;
+
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_freqs(data, ssid->mesh_basic_rates);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MESH */
+
+
/* Helper macros for network block parser */
#ifdef OFFSET
@@ -1560,6 +1813,8 @@ static const struct parse_data ssid_fields[] = {
{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
+ { FUNC(bssid_blacklist) },
+ { FUNC(bssid_whitelist) },
{ FUNC_KEY(psk) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
@@ -1582,6 +1837,8 @@ static const struct parse_data ssid_fields[] = {
{ STRe(dh_file) },
{ STRe(subject_match) },
{ STRe(altsubject_match) },
+ { STRe(domain_suffix_match) },
+ { STRe(domain_match) },
{ STRe(ca_cert2) },
{ STRe(ca_path2) },
{ STRe(client_cert2) },
@@ -1590,6 +1847,8 @@ static const struct parse_data ssid_fields[] = {
{ STRe(dh_file2) },
{ STRe(subject_match2) },
{ STRe(altsubject_match2) },
+ { STRe(domain_suffix_match2) },
+ { STRe(domain_match2) },
{ STRe(phase1) },
{ STRe(phase2) },
{ STRe(pcsc) },
@@ -1606,6 +1865,9 @@ static const struct parse_data ssid_fields[] = {
{ INTe(engine) },
{ INTe(engine2) },
{ INT(eapol_flags) },
+ { INTe(sim_num) },
+ { STRe(openssl_ciphers) },
+ { INTe(erp) },
#endif /* IEEE8021X_EAPOL */
{ FUNC_KEY(wep_key0) },
{ FUNC_KEY(wep_key1) },
@@ -1617,8 +1879,14 @@ static const struct parse_data ssid_fields[] = {
{ INT(eap_workaround) },
{ STRe(pac_file) },
{ INTe(fragment_size) },
+ { INTe(ocsp) },
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+ { INT_RANGE(mode, 0, 5) },
+ { INT_RANGE(no_auto_peer, 0, 1) },
+#else /* CONFIG_MESH */
{ INT_RANGE(mode, 0, 4) },
+#endif /* CONFIG_MESH */
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 2) },
{ STR(id_str) },
@@ -1628,23 +1896,64 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
+ { INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_MESH
+ { FUNC(mesh_basic_rates) },
+ { INT(dot11MeshMaxRetries) },
+ { INT(dot11MeshRetryTimeout) },
+ { INT(dot11MeshConfirmTimeout) },
+ { INT(dot11MeshHoldingTimeout) },
+#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P
+ { FUNC(go_p2p_dev_addr) },
{ FUNC(p2p_client_list) },
+ { FUNC(psk_list) },
#endif /* CONFIG_P2P */
#ifdef CONFIG_HT_OVERRIDES
{ INT_RANGE(disable_ht, 0, 1) },
{ INT_RANGE(disable_ht40, -1, 1) },
{ INT_RANGE(disable_sgi, 0, 1) },
+ { INT_RANGE(disable_ldpc, 0, 1) },
+ { INT_RANGE(ht40_intolerant, 0, 1) },
{ INT_RANGE(disable_max_amsdu, -1, 1) },
{ INT_RANGE(ampdu_factor, -1, 3) },
{ INT_RANGE(ampdu_density, -1, 7) },
{ STR(ht_mcs) },
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ { INT_RANGE(disable_vht, 0, 1) },
+ { INT(vht_capa) },
+ { INT(vht_capa_mask) },
+ { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
+#endif /* CONFIG_VHT_OVERRIDES */
{ INT(ap_max_inactivity) },
{ INT(dtim_period) },
+ { INT(beacon_int) },
+#ifdef CONFIG_MACSEC
+ { INT_RANGE(macsec_policy, 0, 1) },
+#endif /* CONFIG_MACSEC */
+#ifdef CONFIG_HS20
+ { INT(update_identifier) },
+#endif /* CONFIG_HS20 */
+ { INT_RANGE(mac_addr, 0, 2) },
};
#undef OFFSET
@@ -1663,7 +1972,7 @@ static const struct parse_data ssid_fields[] = {
#undef _FUNC
#undef FUNC
#undef FUNC_KEY
-#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields)
/**
@@ -1754,29 +2063,33 @@ int wpa_config_update_prio_list(struct wpa_config *config)
static void eap_peer_config_free(struct eap_peer_config *eap)
{
os_free(eap->eap_methods);
- os_free(eap->identity);
+ bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
- os_free(eap->password);
+ bin_clear_free(eap->password, eap->password_len);
os_free(eap->ca_cert);
os_free(eap->ca_path);
os_free(eap->client_cert);
os_free(eap->private_key);
- os_free(eap->private_key_passwd);
+ str_clear_free(eap->private_key_passwd);
os_free(eap->dh_file);
os_free(eap->subject_match);
os_free(eap->altsubject_match);
+ os_free(eap->domain_suffix_match);
+ os_free(eap->domain_match);
os_free(eap->ca_cert2);
os_free(eap->ca_path2);
os_free(eap->client_cert2);
os_free(eap->private_key2);
- os_free(eap->private_key2_passwd);
+ str_clear_free(eap->private_key2_passwd);
os_free(eap->dh_file2);
os_free(eap->subject_match2);
os_free(eap->altsubject_match2);
+ os_free(eap->domain_suffix_match2);
+ os_free(eap->domain_match2);
os_free(eap->phase1);
os_free(eap->phase2);
os_free(eap->pcsc);
- os_free(eap->pin);
+ str_clear_free(eap->pin);
os_free(eap->engine_id);
os_free(eap->key_id);
os_free(eap->cert_id);
@@ -1784,12 +2097,14 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
os_free(eap->key2_id);
os_free(eap->cert2_id);
os_free(eap->ca_cert2_id);
- os_free(eap->pin2);
+ str_clear_free(eap->pin2);
os_free(eap->engine2_id);
os_free(eap->otp);
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
- os_free(eap->new_password);
+ bin_clear_free(eap->new_password, eap->new_password_len);
+ str_clear_free(eap->external_sim_resp);
+ os_free(eap->openssl_ciphers);
}
#endif /* IEEE8021X_EAPOL */
@@ -1803,8 +2118,10 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
*/
void wpa_config_free_ssid(struct wpa_ssid *ssid)
{
+ struct psk_list_entry *psk;
+
os_free(ssid->ssid);
- os_free(ssid->passphrase);
+ str_clear_free(ssid->passphrase);
os_free(ssid->ext_psk);
#ifdef IEEE8021X_EAPOL
eap_peer_config_free(&ssid->eap);
@@ -1814,33 +2131,70 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->freq_list);
os_free(ssid->bgscan);
os_free(ssid->p2p_client_list);
+ os_free(ssid->bssid_blacklist);
+ os_free(ssid->bssid_whitelist);
#ifdef CONFIG_HT_OVERRIDES
os_free(ssid->ht_mcs);
#endif /* CONFIG_HT_OVERRIDES */
- os_free(ssid);
+#ifdef CONFIG_MESH
+ os_free(ssid->mesh_basic_rates);
+#endif /* CONFIG_MESH */
+ while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
+ list))) {
+ dl_list_del(&psk->list);
+ bin_clear_free(psk, sizeof(*psk));
+ }
+ bin_clear_free(ssid, sizeof(*ssid));
}
void wpa_config_free_cred(struct wpa_cred *cred)
{
+ size_t i;
+
os_free(cred->realm);
- os_free(cred->username);
- os_free(cred->password);
+ str_clear_free(cred->username);
+ str_clear_free(cred->password);
os_free(cred->ca_cert);
os_free(cred->client_cert);
os_free(cred->private_key);
- os_free(cred->private_key_passwd);
+ str_clear_free(cred->private_key_passwd);
os_free(cred->imsi);
- os_free(cred->milenage);
+ str_clear_free(cred->milenage);
+ for (i = 0; i < cred->num_domain; i++)
+ os_free(cred->domain[i]);
os_free(cred->domain);
+ os_free(cred->domain_suffix_match);
os_free(cred->eap_method);
os_free(cred->phase1);
os_free(cred->phase2);
os_free(cred->excluded_ssid);
+ os_free(cred->roaming_partner);
+ os_free(cred->provisioning_sp);
+ for (i = 0; i < cred->num_req_conn_capab; i++)
+ os_free(cred->req_conn_capab_port[i]);
+ os_free(cred->req_conn_capab_port);
+ os_free(cred->req_conn_capab_proto);
os_free(cred);
}
+void wpa_config_flush_blobs(struct wpa_config *config)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+ struct wpa_config_blob *blob, *prev;
+
+ blob = config->blobs;
+ config->blobs = NULL;
+ while (blob) {
+ prev = blob;
+ blob = blob->next;
+ wpa_config_free_blob(prev);
+ }
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
/**
* wpa_config_free - Free configuration data
* @config: Configuration data from wpa_config_read()
@@ -1850,11 +2204,9 @@ void wpa_config_free_cred(struct wpa_cred *cred)
*/
void wpa_config_free(struct wpa_config *config)
{
-#ifndef CONFIG_NO_CONFIG_BLOBS
- struct wpa_config_blob *blob, *prevblob;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
struct wpa_ssid *ssid, *prev = NULL;
struct wpa_cred *cred, *cprev;
+ int i;
ssid = config->ssid;
while (ssid) {
@@ -1870,24 +2222,19 @@ void wpa_config_free(struct wpa_config *config)
wpa_config_free_cred(cprev);
}
-#ifndef CONFIG_NO_CONFIG_BLOBS
- blob = config->blobs;
- prevblob = NULL;
- while (blob) {
- prevblob = blob;
- blob = blob->next;
- wpa_config_free_blob(prevblob);
- }
-#endif /* CONFIG_NO_CONFIG_BLOBS */
+ wpa_config_flush_blobs(config);
wpabuf_free(config->wps_vendor_ext_m1);
+ for (i = 0; i < MAX_WPS_VENDOR_EXT; i++)
+ wpabuf_free(config->wps_vendor_ext[i]);
os_free(config->ctrl_interface);
os_free(config->ctrl_interface_group);
os_free(config->opensc_engine_path);
os_free(config->pkcs11_engine_path);
os_free(config->pkcs11_module_path);
+ os_free(config->openssl_ciphers);
os_free(config->pcsc_reader);
- os_free(config->pcsc_pin);
+ str_clear_free(config->pcsc_pin);
os_free(config->driver_param);
os_free(config->device_name);
os_free(config->manufacturer);
@@ -1898,11 +2245,18 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->p2p_ssid_postfix);
os_free(config->pssid);
os_free(config->p2p_pref_chan);
+ os_free(config->p2p_no_go_freq.range);
os_free(config->autoscan);
+ os_free(config->freq_list);
wpabuf_free(config->wps_nfc_dh_pubkey);
wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw);
os_free(config->ext_password_backend);
+ os_free(config->sae_groups);
+ wpabuf_free(config->ap_vendor_elements);
+ os_free(config->osu_dir);
+ os_free(config->bgscan);
+ os_free(config->wowlan_triggers);
os_free(config);
}
@@ -1977,6 +2331,7 @@ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
if (ssid == NULL)
return NULL;
ssid->id = id;
+ dl_list_init(&ssid->psk_list);
if (last)
last->next = ssid;
else
@@ -2035,19 +2390,46 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
+ ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+ ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
+ ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
+ ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
+ ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
+#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->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ ssid->vht_rx_mcs_nss_1 = -1;
+ ssid->vht_rx_mcs_nss_2 = -1;
+ ssid->vht_rx_mcs_nss_3 = -1;
+ ssid->vht_rx_mcs_nss_4 = -1;
+ ssid->vht_rx_mcs_nss_5 = -1;
+ ssid->vht_rx_mcs_nss_6 = -1;
+ ssid->vht_rx_mcs_nss_7 = -1;
+ ssid->vht_rx_mcs_nss_8 = -1;
+ ssid->vht_tx_mcs_nss_1 = -1;
+ ssid->vht_tx_mcs_nss_2 = -1;
+ ssid->vht_tx_mcs_nss_3 = -1;
+ ssid->vht_tx_mcs_nss_4 = -1;
+ ssid->vht_tx_mcs_nss_5 = -1;
+ ssid->vht_tx_mcs_nss_6 = -1;
+ ssid->vht_tx_mcs_nss_7 = -1;
+ ssid->vht_tx_mcs_nss_8 = -1;
+#endif /* CONFIG_VHT_OVERRIDES */
ssid->proactive_key_caching = -1;
#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
#endif /* CONFIG_IEEE80211W */
+ ssid->mac_addr = -1;
}
@@ -2244,7 +2626,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
wpa_printf(MSG_DEBUG, "Do not allow "
"key_data field to be "
"exposed");
- os_free(res);
+ str_clear_free(res);
return os_strdup("*");
}
@@ -2279,17 +2661,93 @@ void wpa_config_update_psk(struct wpa_ssid *ssid)
}
+static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred,
+ const char *value)
+{
+ u8 *proto;
+ int **port;
+ int *ports, *nports;
+ const char *pos;
+ unsigned int num_ports;
+
+ proto = os_realloc_array(cred->req_conn_capab_proto,
+ cred->num_req_conn_capab + 1, sizeof(u8));
+ if (proto == NULL)
+ return -1;
+ cred->req_conn_capab_proto = proto;
+
+ port = os_realloc_array(cred->req_conn_capab_port,
+ cred->num_req_conn_capab + 1, sizeof(int *));
+ if (port == NULL)
+ return -1;
+ cred->req_conn_capab_port = port;
+
+ proto[cred->num_req_conn_capab] = atoi(value);
+
+ pos = os_strchr(value, ':');
+ if (pos == NULL) {
+ port[cred->num_req_conn_capab] = NULL;
+ cred->num_req_conn_capab++;
+ return 0;
+ }
+ pos++;
+
+ ports = NULL;
+ num_ports = 0;
+
+ while (*pos) {
+ nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
+ if (nports == NULL) {
+ os_free(ports);
+ return -1;
+ }
+ ports = nports;
+ ports[num_ports++] = atoi(pos);
+
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
+ if (nports == NULL) {
+ os_free(ports);
+ return -1;
+ }
+ ports = nports;
+ ports[num_ports] = -1;
+
+ port[cred->num_req_conn_capab] = ports;
+ cred->num_req_conn_capab++;
+ return 0;
+}
+
+
int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
const char *value, int line)
{
char *val;
size_t len;
+ if (os_strcmp(var, "temporary") == 0) {
+ cred->temporary = atoi(value);
+ return 0;
+ }
+
if (os_strcmp(var, "priority") == 0) {
cred->priority = atoi(value);
return 0;
}
+ if (os_strcmp(var, "sp_priority") == 0) {
+ int prio = atoi(value);
+ if (prio < 0 || prio > 255)
+ return -1;
+ cred->sp_priority = prio;
+ return 0;
+ }
+
if (os_strcmp(var, "pcsc") == 0) {
cred->pcsc = atoi(value);
return 0;
@@ -2314,12 +2772,55 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
if (os_strcmp(var, "password") == 0 &&
os_strncmp(value, "ext:", 4) == 0) {
- os_free(cred->password);
+ str_clear_free(cred->password);
cred->password = os_strdup(value);
cred->ext_password = 1;
return 0;
}
+ if (os_strcmp(var, "update_identifier") == 0) {
+ cred->update_identifier = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "min_dl_bandwidth_home") == 0) {
+ cred->min_dl_bandwidth_home = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "min_ul_bandwidth_home") == 0) {
+ cred->min_ul_bandwidth_home = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) {
+ cred->min_dl_bandwidth_roaming = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) {
+ cred->min_ul_bandwidth_roaming = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "max_bss_load") == 0) {
+ cred->max_bss_load = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "req_conn_capab") == 0)
+ return wpa_config_set_cred_req_conn_capab(cred, value);
+
+ if (os_strcmp(var, "ocsp") == 0) {
+ cred->ocsp = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "sim_num") == 0) {
+ cred->sim_num = atoi(value);
+ return 0;
+ }
+
val = wpa_config_parse_string(value, &len);
if (val == NULL) {
wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
@@ -2334,13 +2835,13 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
}
if (os_strcmp(var, "username") == 0) {
- os_free(cred->username);
+ str_clear_free(cred->username);
cred->username = val;
return 0;
}
if (os_strcmp(var, "password") == 0) {
- os_free(cred->password);
+ str_clear_free(cred->password);
cred->password = val;
cred->ext_password = 0;
return 0;
@@ -2365,7 +2866,7 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
}
if (os_strcmp(var, "private_key_passwd") == 0) {
- os_free(cred->private_key_passwd);
+ str_clear_free(cred->private_key_passwd);
cred->private_key_passwd = val;
return 0;
}
@@ -2377,14 +2878,28 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
}
if (os_strcmp(var, "milenage") == 0) {
- os_free(cred->milenage);
+ str_clear_free(cred->milenage);
cred->milenage = val;
return 0;
}
+ if (os_strcmp(var, "domain_suffix_match") == 0) {
+ os_free(cred->domain_suffix_match);
+ cred->domain_suffix_match = val;
+ return 0;
+ }
+
if (os_strcmp(var, "domain") == 0) {
- os_free(cred->domain);
- cred->domain = val;
+ char **new_domain;
+ new_domain = os_realloc_array(cred->domain,
+ cred->num_domain + 1,
+ sizeof(char *));
+ if (new_domain == NULL) {
+ os_free(val);
+ return -1;
+ }
+ new_domain[cred->num_domain++] = val;
+ cred->domain = new_domain;
return 0;
}
@@ -2414,6 +2929,21 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
return 0;
}
+ if (os_strcmp(var, "required_roaming_consortium") == 0) {
+ if (len < 3 || len > sizeof(cred->required_roaming_consortium))
+ {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "required_roaming_consortium length %d "
+ "(3..15 expected)", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(cred->required_roaming_consortium, val, len);
+ cred->required_roaming_consortium_len = len;
+ os_free(val);
+ return 0;
+ }
+
if (os_strcmp(var, "excluded_ssid") == 0) {
struct excluded_ssid *e;
@@ -2442,6 +2972,69 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
return 0;
}
+ if (os_strcmp(var, "roaming_partner") == 0) {
+ struct roaming_partner *p;
+ char *pos;
+
+ p = os_realloc_array(cred->roaming_partner,
+ cred->num_roaming_partner + 1,
+ sizeof(struct roaming_partner));
+ if (p == NULL) {
+ os_free(val);
+ return -1;
+ }
+ cred->roaming_partner = p;
+
+ p = &cred->roaming_partner[cred->num_roaming_partner];
+
+ pos = os_strchr(val, ',');
+ if (pos == NULL) {
+ os_free(val);
+ return -1;
+ }
+ *pos++ = '\0';
+ if (pos - val - 1 >= (int) sizeof(p->fqdn)) {
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(p->fqdn, val, pos - val);
+
+ p->exact_match = atoi(pos);
+
+ pos = os_strchr(pos, ',');
+ if (pos == NULL) {
+ os_free(val);
+ return -1;
+ }
+ *pos++ = '\0';
+
+ p->priority = atoi(pos);
+
+ pos = os_strchr(pos, ',');
+ if (pos == NULL) {
+ os_free(val);
+ return -1;
+ }
+ *pos++ = '\0';
+
+ if (os_strlen(pos) >= sizeof(p->country)) {
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(p->country, pos, os_strlen(pos) + 1);
+
+ cred->num_roaming_partner++;
+ os_free(val);
+
+ return 0;
+ }
+
+ if (os_strcmp(var, "provisioning_sp") == 0) {
+ os_free(cred->provisioning_sp);
+ cred->provisioning_sp = val;
+ return 0;
+ }
+
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var);
@@ -2453,6 +3046,281 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
}
+static char * alloc_int_str(int val)
+{
+ const unsigned int bufsize = 20;
+ char *buf;
+ int res;
+
+ buf = os_malloc(bufsize);
+ if (buf == NULL)
+ return NULL;
+ res = os_snprintf(buf, bufsize, "%d", val);
+ if (os_snprintf_error(bufsize, res)) {
+ os_free(buf);
+ buf = NULL;
+ }
+ return buf;
+}
+
+
+static char * alloc_strdup(const char *str)
+{
+ if (str == NULL)
+ return NULL;
+ return os_strdup(str);
+}
+
+
+char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
+{
+ if (os_strcmp(var, "temporary") == 0)
+ return alloc_int_str(cred->temporary);
+
+ if (os_strcmp(var, "priority") == 0)
+ return alloc_int_str(cred->priority);
+
+ if (os_strcmp(var, "sp_priority") == 0)
+ return alloc_int_str(cred->sp_priority);
+
+ if (os_strcmp(var, "pcsc") == 0)
+ return alloc_int_str(cred->pcsc);
+
+ if (os_strcmp(var, "eap") == 0) {
+ if (!cred->eap_method)
+ return NULL;
+ return alloc_strdup(eap_get_name(cred->eap_method[0].vendor,
+ cred->eap_method[0].method));
+ }
+
+ if (os_strcmp(var, "update_identifier") == 0)
+ return alloc_int_str(cred->update_identifier);
+
+ if (os_strcmp(var, "min_dl_bandwidth_home") == 0)
+ return alloc_int_str(cred->min_dl_bandwidth_home);
+
+ if (os_strcmp(var, "min_ul_bandwidth_home") == 0)
+ return alloc_int_str(cred->min_ul_bandwidth_home);
+
+ if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0)
+ return alloc_int_str(cred->min_dl_bandwidth_roaming);
+
+ if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0)
+ return alloc_int_str(cred->min_ul_bandwidth_roaming);
+
+ if (os_strcmp(var, "max_bss_load") == 0)
+ return alloc_int_str(cred->max_bss_load);
+
+ if (os_strcmp(var, "req_conn_capab") == 0) {
+ unsigned int i;
+ char *buf, *end, *pos;
+ int ret;
+
+ if (!cred->num_req_conn_capab)
+ return NULL;
+
+ buf = os_malloc(4000);
+ if (buf == NULL)
+ return NULL;
+ pos = buf;
+ end = pos + 4000;
+ for (i = 0; i < cred->num_req_conn_capab; i++) {
+ int *ports;
+
+ ret = os_snprintf(pos, end - pos, "%s%u",
+ i > 0 ? "\n" : "",
+ cred->req_conn_capab_proto[i]);
+ if (os_snprintf_error(end - pos, ret))
+ return buf;
+ pos += ret;
+
+ ports = cred->req_conn_capab_port[i];
+ if (ports) {
+ int j;
+ for (j = 0; ports[j] != -1; j++) {
+ ret = os_snprintf(pos, end - pos,
+ "%s%d",
+ j > 0 ? "," : ":",
+ ports[j]);
+ if (os_snprintf_error(end - pos, ret))
+ return buf;
+ pos += ret;
+ }
+ }
+ }
+
+ return buf;
+ }
+
+ if (os_strcmp(var, "ocsp") == 0)
+ return alloc_int_str(cred->ocsp);
+
+ if (os_strcmp(var, "realm") == 0)
+ return alloc_strdup(cred->realm);
+
+ if (os_strcmp(var, "username") == 0)
+ return alloc_strdup(cred->username);
+
+ if (os_strcmp(var, "password") == 0) {
+ if (!cred->password)
+ return NULL;
+ return alloc_strdup("*");
+ }
+
+ if (os_strcmp(var, "ca_cert") == 0)
+ return alloc_strdup(cred->ca_cert);
+
+ if (os_strcmp(var, "client_cert") == 0)
+ return alloc_strdup(cred->client_cert);
+
+ if (os_strcmp(var, "private_key") == 0)
+ return alloc_strdup(cred->private_key);
+
+ if (os_strcmp(var, "private_key_passwd") == 0) {
+ if (!cred->private_key_passwd)
+ return NULL;
+ return alloc_strdup("*");
+ }
+
+ if (os_strcmp(var, "imsi") == 0)
+ return alloc_strdup(cred->imsi);
+
+ if (os_strcmp(var, "milenage") == 0) {
+ if (!(cred->milenage))
+ return NULL;
+ return alloc_strdup("*");
+ }
+
+ if (os_strcmp(var, "domain_suffix_match") == 0)
+ return alloc_strdup(cred->domain_suffix_match);
+
+ if (os_strcmp(var, "domain") == 0) {
+ unsigned int i;
+ char *buf, *end, *pos;
+ int ret;
+
+ if (!cred->num_domain)
+ return NULL;
+
+ buf = os_malloc(4000);
+ if (buf == NULL)
+ return NULL;
+ pos = buf;
+ end = pos + 4000;
+
+ for (i = 0; i < cred->num_domain; i++) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ i > 0 ? "\n" : "", cred->domain[i]);
+ if (os_snprintf_error(end - pos, ret))
+ return buf;
+ pos += ret;
+ }
+
+ return buf;
+ }
+
+ if (os_strcmp(var, "phase1") == 0)
+ return alloc_strdup(cred->phase1);
+
+ if (os_strcmp(var, "phase2") == 0)
+ return alloc_strdup(cred->phase2);
+
+ if (os_strcmp(var, "roaming_consortium") == 0) {
+ size_t buflen;
+ char *buf;
+
+ if (!cred->roaming_consortium_len)
+ return NULL;
+ buflen = cred->roaming_consortium_len * 2 + 1;
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return NULL;
+ wpa_snprintf_hex(buf, buflen, cred->roaming_consortium,
+ cred->roaming_consortium_len);
+ return buf;
+ }
+
+ if (os_strcmp(var, "required_roaming_consortium") == 0) {
+ size_t buflen;
+ char *buf;
+
+ if (!cred->required_roaming_consortium_len)
+ return NULL;
+ buflen = cred->required_roaming_consortium_len * 2 + 1;
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return NULL;
+ wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len);
+ return buf;
+ }
+
+ if (os_strcmp(var, "excluded_ssid") == 0) {
+ unsigned int i;
+ char *buf, *end, *pos;
+
+ if (!cred->num_excluded_ssid)
+ return NULL;
+
+ buf = os_malloc(4000);
+ if (buf == NULL)
+ return NULL;
+ pos = buf;
+ end = pos + 4000;
+
+ for (i = 0; i < cred->num_excluded_ssid; i++) {
+ struct excluded_ssid *e;
+ int ret;
+
+ e = &cred->excluded_ssid[i];
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ i > 0 ? "\n" : "",
+ wpa_ssid_txt(e->ssid, e->ssid_len));
+ if (os_snprintf_error(end - pos, ret))
+ return buf;
+ pos += ret;
+ }
+
+ return buf;
+ }
+
+ if (os_strcmp(var, "roaming_partner") == 0) {
+ unsigned int i;
+ char *buf, *end, *pos;
+
+ if (!cred->num_roaming_partner)
+ return NULL;
+
+ buf = os_malloc(4000);
+ if (buf == NULL)
+ return NULL;
+ pos = buf;
+ end = pos + 4000;
+
+ for (i = 0; i < cred->num_roaming_partner; i++) {
+ struct roaming_partner *p;
+ int ret;
+
+ p = &cred->roaming_partner[i];
+ ret = os_snprintf(pos, end - pos, "%s%s,%d,%u,%s",
+ i > 0 ? "\n" : "",
+ p->fqdn, p->exact_match, p->priority,
+ p->country);
+ if (os_snprintf_error(end - pos, ret))
+ return buf;
+ pos += ret;
+ }
+
+ return buf;
+ }
+
+ if (os_strcmp(var, "provisioning_sp") == 0)
+ return alloc_strdup(cred->provisioning_sp);
+
+ return NULL;
+}
+
+
struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
{
struct wpa_cred *cred;
@@ -2487,6 +3355,7 @@ struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
if (cred == NULL)
return NULL;
cred->id = id;
+ cred->sim_num = DEFAULT_USER_SELECTED_SIM;
if (last)
last->next = cred;
else
@@ -2567,7 +3436,7 @@ void wpa_config_free_blob(struct wpa_config_blob *blob)
{
if (blob) {
os_free(blob->name);
- os_free(blob->data);
+ bin_clear_free(blob->data, blob->len);
os_free(blob);
}
}
@@ -2627,19 +3496,29 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
return NULL;
config->eapol_version = DEFAULT_EAPOL_VERSION;
config->ap_scan = DEFAULT_AP_SCAN;
+ config->user_mpm = DEFAULT_USER_MPM;
+ config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
+ config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
config->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
+ config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
+ config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW;
config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
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->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+ config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
config->wmm_ac_params[0] = ac_be;
config->wmm_ac_params[1] = ac_bk;
config->wmm_ac_params[2] = ac_vi;
config->wmm_ac_params[3] = ac_vo;
+ config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
+ config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
+ config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
+ config->cert_in_cb = DEFAULT_CERT_IN_CB;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2679,6 +3558,8 @@ struct global_parse_data {
char *name;
int (*parser)(const struct global_parse_data *data,
struct wpa_config *config, int line, const char *value);
+ int (*get)(const char *name, struct wpa_config *config, long offset,
+ char *buf, size_t buflen, int pretty_print);
void *param1, *param2, *param3;
unsigned int changed_flag;
};
@@ -2688,9 +3569,18 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
{
- int *dst;
+ int val, *dst;
+ char *end;
+
dst = (int *) (((u8 *) config) + (long) data->param1);
- *dst = atoi(pos);
+ val = strtol(pos, &end, 0);
+ if (*end) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+ line, pos);
+ return -1;
+ }
+ *dst = val;
+
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
if (data->param2 && *dst < (long) data->param2) {
@@ -2748,6 +3638,27 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
}
+static int wpa_config_process_bgscan(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ size_t len;
+ char *tmp;
+ int res;
+
+ tmp = wpa_config_parse_string(pos, &len);
+ if (tmp == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to parse %s",
+ line, data->name);
+ return -1;
+ }
+
+ res = wpa_global_config_parse_str(data, config, line, tmp);
+ os_free(tmp);
+ return res;
+}
+
+
static int wpa_global_config_parse_bin(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
@@ -2777,6 +3688,48 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
}
+static int wpa_config_process_freq_list(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *value)
+{
+ int *freqs;
+
+ freqs = wpa_config_parse_int_array(value);
+ if (freqs == NULL)
+ return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
+ os_free(config->freq_list);
+ config->freq_list = freqs;
+ return 0;
+}
+
+
+#ifdef CONFIG_P2P
+static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ u32 *dst;
+ struct hostapd_ip_addr addr;
+
+ if (hostapd_parse_ip_addr(pos, &addr) < 0)
+ return -1;
+ if (addr.af != AF_INET)
+ return -1;
+
+ dst = (u32 *) (((u8 *) config) + (long) data->param1);
+ os_memcpy(dst, &addr.u.v4.s_addr, 4);
+ wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
+ WPA_GET_BE32((u8 *) dst));
+
+ return 0;
+}
+#endif /* CONFIG_P2P */
+
+
static int wpa_config_process_country(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
@@ -2961,6 +3914,26 @@ fail:
wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
return -1;
}
+
+
+static int wpa_config_process_p2p_no_go_freq(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ int ret;
+
+ ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
+ config->p2p_no_go_freq.num);
+
+ return 0;
+}
+
#endif /* CONFIG_P2P */
@@ -2978,36 +3951,151 @@ static int wpa_config_process_hessid(
}
+static int wpa_config_process_sae_groups(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ int *groups = wpa_config_parse_int_array(pos);
+ if (groups == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
+ line, pos);
+ return -1;
+ }
+
+ os_free(config->sae_groups);
+ config->sae_groups = groups;
+
+ return 0;
+}
+
+
+static int wpa_config_process_ap_vendor_elements(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct wpabuf *tmp;
+ int len = os_strlen(pos) / 2;
+ u8 *p;
+
+ if (!len) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
+ line);
+ return -1;
+ }
+
+ tmp = wpabuf_alloc(len);
+ if (tmp) {
+ p = wpabuf_put(tmp, len);
+
+ if (hexstr2bin(pos, p, len)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "ap_vendor_elements", line);
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ wpabuf_free(config->ap_vendor_elements);
+ config->ap_vendor_elements = tmp;
+ } else {
+ wpa_printf(MSG_ERROR, "Cannot allocate memory for "
+ "ap_vendor_elements");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static int wpa_config_process_no_ctrl_interface(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
+ os_free(config->ctrl_interface);
+ config->ctrl_interface = NULL;
+ return 0;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+static int wpa_config_get_int(const char *name, struct wpa_config *config,
+ long offset, char *buf, size_t buflen,
+ int pretty_print)
+{
+ int *val = (int *) (((u8 *) config) + (long) offset);
+
+ if (pretty_print)
+ return os_snprintf(buf, buflen, "%s=%d\n", name, *val);
+ return os_snprintf(buf, buflen, "%d", *val);
+}
+
+
+static int wpa_config_get_str(const char *name, struct wpa_config *config,
+ long offset, char *buf, size_t buflen,
+ int pretty_print)
+{
+ char **val = (char **) (((u8 *) config) + (long) offset);
+ int res;
+
+ if (pretty_print)
+ res = os_snprintf(buf, buflen, "%s=%s\n", name,
+ *val ? *val : "null");
+ else if (!*val)
+ return -1;
+ else
+ res = os_snprintf(buf, buflen, "%s", *val);
+ if (os_snprintf_error(buflen, res))
+ res = -1;
+
+ return res;
+}
+
+
#ifdef OFFSET
#undef OFFSET
#endif /* OFFSET */
/* OFFSET: Get offset of a variable within the wpa_config structure */
#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
-#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
-#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
-#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
+#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL
+#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL
+#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f)
#define INT(f) _INT(f), NULL, NULL
#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
-#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
+#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f)
#define STR(f) _STR(f), NULL, NULL
#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
-#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
+#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL
+#define IPV4(f) #f, wpa_global_config_parse_ipv4, NULL, OFFSET(f), NULL, NULL
static const struct global_parse_data global_fields[] = {
#ifdef CONFIG_CTRL_IFACE
{ STR(ctrl_interface), 0 },
+ { FUNC_NO_VAR(no_ctrl_interface), 0 },
{ STR(ctrl_interface_group), 0 } /* deprecated */,
#endif /* CONFIG_CTRL_IFACE */
+#ifdef CONFIG_MACSEC
+ { INT_RANGE(eapol_version, 1, 3), 0 },
+#else /* CONFIG_MACSEC */
{ INT_RANGE(eapol_version, 1, 2), 0 },
+#endif /* CONFIG_MACSEC */
{ INT(ap_scan), 0 },
+ { FUNC(bgscan), 0 },
+#ifdef CONFIG_MESH
+ { INT(user_mpm), 0 },
+ { INT_RANGE(max_peer_links, 0, 255), 0 },
+ { INT(mesh_max_inactivity), 0 },
+#endif /* CONFIG_MESH */
{ INT(disable_scan_offload), 0 },
{ INT(fast_reauth), 0 },
{ STR(opensc_engine_path), 0 },
{ STR(pkcs11_engine_path), 0 },
{ STR(pkcs11_module_path), 0 },
+ { STR(openssl_ciphers), 0 },
{ STR(pcsc_reader), 0 },
{ STR(pcsc_pin), 0 },
+ { INT(external_sim), 0 },
{ STR(driver_param), 0 },
{ INT(dot11RSNAConfigPMKLifetime), 0 },
{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
@@ -3033,17 +4121,29 @@ static const struct global_parse_data global_fields[] = {
{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
{ INT(p2p_listen_reg_class), 0 },
{ INT(p2p_listen_channel), 0 },
- { INT(p2p_oper_reg_class), 0 },
- { INT(p2p_oper_channel), 0 },
+ { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
+ { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
{ INT_RANGE(p2p_go_intent, 0, 15), 0 },
{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
{ INT(p2p_group_idle), 0 },
+ { INT_RANGE(p2p_passphrase_len, 8, 63),
+ CFG_CHANGED_P2P_PASSPHRASE_LEN },
{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+ { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
+ { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
+ { INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
{ INT(p2p_go_ht40), 0 },
+ { INT(p2p_go_vht), 0 },
{ INT(p2p_disabled), 0 },
+ { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
{ INT(p2p_no_group_iface), 0 },
+ { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
+ { IPV4(ip_addr_go), 0 },
+ { IPV4(ip_addr_mask), 0 },
+ { IPV4(ip_addr_start), 0 },
+ { IPV4(ip_addr_end), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
@@ -3061,15 +4161,34 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(access_network_type, 0, 15), 0 },
{ INT_RANGE(pbc_in_m1, 0, 1), 0 },
{ STR(autoscan), 0 },
- { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
- { BIN(wps_nfc_dh_pubkey), 0 },
- { BIN(wps_nfc_dh_privkey), 0 },
- { BIN(wps_nfc_dev_pw), 0 },
+ { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
+ CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
{ STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
{ INT(p2p_go_max_inactivity), 0 },
{ INT_RANGE(auto_interworking, 0, 1), 0 },
{ INT(okc), 0 },
{ INT(pmf), 0 },
+ { FUNC(sae_groups), 0 },
+ { INT(dtim_period), 0 },
+ { INT(beacon_int), 0 },
+ { FUNC(ap_vendor_elements), 0 },
+ { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
+ { FUNC(freq_list), 0 },
+ { INT(scan_cur_freq), 0 },
+ { INT(sched_scan_interval), 0 },
+ { INT(tdls_external_control), 0},
+ { STR(osu_dir), 0 },
+ { STR(wowlan_triggers), 0 },
+ { INT(p2p_search_delay), 0},
+ { INT(mac_addr), 0 },
+ { INT(rand_addr_lifetime), 0 },
+ { INT(preassoc_mac_addr), 0 },
+ { INT(key_mgmt_offload), 0},
+ { INT(passive_scan), 0 },
+ { INT(reassoc_same_bss_optim), 0 },
};
#undef FUNC
@@ -3080,7 +4199,52 @@ static const struct global_parse_data global_fields[] = {
#undef STR
#undef STR_RANGE
#undef BIN
-#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+#undef IPV4
+#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
+
+
+int wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen)
+{
+ int result = 0;
+ size_t i;
+
+ for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+ const struct global_parse_data *field = &global_fields[i];
+ int tmp;
+
+ if (!field->get)
+ continue;
+
+ tmp = field->get(field->name, config, (long) field->param1,
+ buf, buflen, 1);
+ if (tmp < 0)
+ return -1;
+ buf += tmp;
+ buflen -= tmp;
+ result += tmp;
+ }
+ return result;
+}
+
+
+int wpa_config_get_value(const char *name, struct wpa_config *config,
+ char *buf, size_t buflen)
+{
+ size_t i;
+
+ for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+ const struct global_parse_data *field = &global_fields[i];
+
+ if (os_strcmp(name, field->name) != 0)
+ continue;
+ if (!field->get)
+ break;
+ return field->get(name, config, (long) field->param1,
+ buf, buflen, 0);
+ }
+
+ return -1;
+}
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
@@ -3100,6 +4264,8 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
"parse '%s'.", line, pos);
ret = -1;
}
+ if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
+ config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag;
break;
}
diff --git a/contrib/wpa/wpa_supplicant/config.h b/contrib/wpa/wpa_supplicant/config.h
index bb70b9c..34b754e 100644
--- a/contrib/wpa/wpa_supplicant/config.h
+++ b/contrib/wpa/wpa_supplicant/config.h
@@ -15,15 +15,25 @@
#else /* CONFIG_NO_SCAN_PROCESSING */
#define DEFAULT_AP_SCAN 1
#endif /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_USER_MPM 1
+#define DEFAULT_MAX_PEER_LINKS 99
+#define DEFAULT_MESH_MAX_INACTIVITY 300
#define DEFAULT_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
+#define DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN 0
#define DEFAULT_BSS_MAX_COUNT 200
#define DEFAULT_BSS_EXPIRATION_AGE 180
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
#define DEFAULT_MAX_NUM_STA 128
#define DEFAULT_ACCESS_NETWORK_TYPE 15
+#define DEFAULT_SCAN_CUR_FREQ 0
+#define DEFAULT_P2P_SEARCH_DELAY 500
+#define DEFAULT_RAND_ADDR_LIFETIME 60
+#define DEFAULT_KEY_MGMT_OFFLOAD 1
+#define DEFAULT_CERT_IN_CB 1
+#define DEFAULT_P2P_GO_CTWINDOW 0
#include "config_ssid.h"
#include "wps/wps.h"
@@ -51,6 +61,11 @@ struct wpa_cred {
int id;
/**
+ * temporary - Whether this credential is temporary and not to be saved
+ */
+ int temporary;
+
+ /**
* priority - Priority group
*
* By default, all networks and credentials get the same priority group
@@ -149,12 +164,37 @@ struct wpa_cred {
char *milenage;
/**
- * domain - Home service provider FQDN
+ * domain_suffix_match - Constraint for server domain name
+ *
+ * If set, this FQDN is 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. Suffix match here means that the
+ * host/domain name is compared one label at a time starting from the
+ * top-level domain and all the labels in @domain_suffix_match shall be
+ * included in the certificate. The certificate may include additional
+ * sub-level labels in addition to the required labels.
+ *
+ * For example, domain_suffix_match=example.com would match
+ * test.example.com but would not match test-example.com.
+ */
+ char *domain_suffix_match;
+
+ /**
+ * domain - Home service provider FQDN(s)
*
* This is used to compare against the Domain Name List to figure out
- * whether the AP is operated by the Home SP.
+ * whether the AP is operated by the Home SP. Multiple domain entries
+ * can be used to configure alternative FQDNs that will be considered
+ * home networks.
+ */
+ char **domain;
+
+ /**
+ * num_domain - Number of FQDNs in the domain array
*/
- char *domain;
+ size_t num_domain;
/**
* roaming_consortium - Roaming Consortium OI
@@ -174,6 +214,9 @@ struct wpa_cred {
*/
size_t roaming_consortium_len;
+ u8 required_roaming_consortium[15];
+ size_t required_roaming_consortium_len;
+
/**
* eap_method - EAP method to use
*
@@ -202,6 +245,66 @@ struct wpa_cred {
size_t ssid_len;
} *excluded_ssid;
size_t num_excluded_ssid;
+
+ struct roaming_partner {
+ char fqdn[128];
+ int exact_match;
+ u8 priority;
+ char country[3];
+ } *roaming_partner;
+ size_t num_roaming_partner;
+
+ int update_identifier;
+
+ /**
+ * provisioning_sp - FQDN of the SP that provisioned the credential
+ */
+ char *provisioning_sp;
+
+ /**
+ * 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
+ * provisioning_sp value). The range of this priority is 0-255 with 0
+ * being the highest and 255 the lower priority.
+ */
+ int sp_priority;
+
+ unsigned int min_dl_bandwidth_home;
+ unsigned int min_ul_bandwidth_home;
+ unsigned int min_dl_bandwidth_roaming;
+ unsigned int min_ul_bandwidth_roaming;
+
+ /**
+ * max_bss_load - Maximum BSS Load Channel Utilization (1..255)
+ * This value is used as the maximum channel utilization for network
+ * selection purposes for home networks. If the AP does not advertise
+ * BSS Load or if the limit would prevent any connection, this
+ * constraint will be ignored.
+ */
+ unsigned int max_bss_load;
+
+ unsigned int num_req_conn_capab;
+ u8 *req_conn_capab_proto;
+ int **req_conn_capab_port;
+
+ /**
+ * ocsp - Whether to use/require OCSP to check server certificate
+ *
+ * 0 = do not use OCSP stapling (TLS certificate status extension)
+ * 1 = try to use OCSP stapling, but not require response
+ * 2 = require valid OCSP stapling response
+ */
+ int ocsp;
+
+ /**
+ * sim_num - User selected SIM identifier
+ *
+ * This variable is used for identifying which SIM is used if the system
+ * has more than one.
+ */
+ int sim_num;
};
@@ -220,6 +323,8 @@ struct wpa_cred {
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
+#define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
+#define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -299,6 +404,18 @@ struct wpa_config {
int ap_scan;
/**
+ * bgscan - Background scan and roaming parameters or %NULL if none
+ *
+ * This is an optional set of parameters for background scanning and
+ * roaming within a network (ESS). For more detailed information see
+ * ssid block documentation.
+ *
+ * The variable defines default bgscan behavior for all BSS station
+ * networks except for those which have their own bgscan configuration.
+ */
+ char *bgscan;
+
+ /**
* disable_scan_offload - Disable automatic offloading of scan requests
*
* By default, %wpa_supplicant tries to offload scanning if the driver
@@ -406,6 +523,15 @@ struct wpa_config {
char *pkcs11_module_path;
/**
+ * openssl_ciphers - 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.
+ */
+ char *openssl_ciphers;
+
+ /**
* pcsc_reader - PC/SC reader name prefix
*
* If not %NULL, PC/SC reader with a name that matches this prefix is
@@ -423,6 +549,11 @@ struct wpa_config {
char *pcsc_pin;
/**
+ * external_sim - Use external processing for SIM/USIM operations
+ */
+ int external_sim;
+
+ /**
* driver_param - Driver interface parameters
*
* This text string is passed to the selected driver interface with the
@@ -570,6 +701,10 @@ struct wpa_config {
int p2p_intra_bss;
unsigned int num_p2p_pref_chan;
struct p2p_channel *p2p_pref_chan;
+ struct wpa_freq_range_list p2p_no_go_freq;
+ int p2p_add_cli_chan;
+ int p2p_ignore_shared_freq;
+ int p2p_optimize_listen_chan;
struct wpabuf *wps_vendor_ext_m1;
@@ -598,6 +733,14 @@ struct wpa_config {
int p2p_group_idle;
/**
+ * p2p_passphrase_len - Passphrase length (8..63) for P2P GO
+ *
+ * This parameter controls the length of the random passphrase that is
+ * generated at the GO.
+ */
+ unsigned int p2p_passphrase_len;
+
+ /**
* bss_max_count - Maximum number of BSS entries to keep in memory
*/
unsigned int bss_max_count;
@@ -643,6 +786,22 @@ struct wpa_config {
unsigned int max_num_sta;
/**
+ * freq_list - Array of allowed scan frequencies or %NULL for all
+ *
+ * This is an optional zero-terminated array of frequencies in
+ * megahertz (MHz) to allow for narrowing scanning range.
+ */
+ int *freq_list;
+
+ /**
+ * scan_cur_freq - Whether to scan only the current channel
+ *
+ * If true, attempt to scan only the current channel if any other
+ * VIFs on this radio are already associated on a particular channel.
+ */
+ int scan_cur_freq;
+
+ /**
* changed_parameters - Bitmap of changed parameters since last update
*/
unsigned int changed_parameters;
@@ -706,6 +865,15 @@ struct wpa_config {
char *autoscan;
/**
+ * wps_nfc_pw_from_config - NFC Device Password was read from config
+ *
+ * This parameter can be determined whether the NFC Device Password was
+ * included in the configuration (1) or generated dynamically (0). Only
+ * the former case is re-written back to the configuration file.
+ */
+ int wps_nfc_pw_from_config;
+
+ /**
* wps_nfc_dev_pw_id - NFC Device Password ID for password token
*/
int wps_nfc_dev_pw_id;
@@ -765,6 +933,24 @@ struct wpa_config {
int p2p_go_ht40;
/**
+ * p2p_go_vht - Default mode for VHT 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_vht;
+
+ /**
+ * p2p_go_ctwindow - CTWindow to use when operating as GO
+ *
+ * By default: 0 (no CTWindow). Values 0-127 can be used to indicate
+ * the length of the CTWindow in TUs.
+ */
+ int p2p_go_ctwindow;
+
+ /**
* p2p_disabled - Whether P2P operations are disabled for this interface
*/
int p2p_disabled;
@@ -797,6 +983,186 @@ struct wpa_config {
* this default behavior.
*/
enum mfp_options pmf;
+
+ /**
+ * sae_groups - Preference list of enabled groups for SAE
+ *
+ * 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.
+ */
+ int *sae_groups;
+
+ /**
+ * dtim_period - Default DTIM period in Beacon intervals
+ *
+ * This parameter can be used to set the default value for network
+ * blocks that do not specify dtim_period.
+ */
+ int dtim_period;
+
+ /**
+ * beacon_int - Default Beacon interval in TU
+ *
+ * This parameter can be used to set the default value for network
+ * blocks that do not specify beacon_int.
+ */
+ int beacon_int;
+
+ /**
+ * ap_vendor_elements: Vendor specific elements for Beacon/ProbeResp
+ *
+ * This parameter can be used to define additional vendor specific
+ * elements for Beacon and Probe Response frames in AP/P2P GO mode. The
+ * format for these element(s) is a hexdump of the raw information
+ * elements (id+len+payload for one or more elements).
+ */
+ struct wpabuf *ap_vendor_elements;
+
+ /**
+ * ignore_old_scan_res - Ignore scan results older than request
+ *
+ * The driver may have a cache of scan results that makes it return
+ * information that is older than our scan trigger. This parameter can
+ * be used to configure such old information to be ignored instead of
+ * allowing it to update the internal BSS table.
+ */
+ int ignore_old_scan_res;
+
+ /**
+ * sched_scan_interval - schedule scan interval
+ */
+ unsigned int sched_scan_interval;
+
+ /**
+ * tdls_external_control - External control for TDLS setup requests
+ *
+ * Enable TDLS mode where external programs are given the control
+ * to specify the TDLS link to get established to the driver. The
+ * driver requests the TDLS setup to the supplicant only for the
+ * specified TDLS peers.
+ */
+ int tdls_external_control;
+
+ u8 ip_addr_go[4];
+ u8 ip_addr_mask[4];
+ u8 ip_addr_start[4];
+ u8 ip_addr_end[4];
+
+ /**
+ * osu_dir - OSU provider information directory
+ *
+ * If set, allow FETCH_OSU control interface command to be used to fetch
+ * OSU provider information into all APs and store the results in this
+ * directory.
+ */
+ char *osu_dir;
+
+ /**
+ * wowlan_triggers - Wake-on-WLAN triggers
+ *
+ * If set, these wowlan triggers will be configured.
+ */
+ char *wowlan_triggers;
+
+ /**
+ * p2p_search_delay - Extra delay between concurrent search iterations
+ *
+ * Add extra delay (in milliseconds) between search iterations when
+ * there is a concurrent operation to make p2p_find friendlier to
+ * concurrent operations by avoiding it from taking 100% of radio
+ * resources.
+ */
+ unsigned int p2p_search_delay;
+
+ /**
+ * mac_addr - MAC address policy default
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address for each ESS connection
+ * 2 = like 1, but maintain OUI (with local admin bit set)
+ *
+ * By default, permanent MAC address is used unless policy is changed by
+ * the per-network mac_addr parameter. Global mac_addr=1 can be used to
+ * change this default behavior.
+ */
+ int mac_addr;
+
+ /**
+ * rand_addr_lifetime - Lifetime of random MAC address in seconds
+ */
+ unsigned int rand_addr_lifetime;
+
+ /**
+ * preassoc_mac_addr - Pre-association 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 preassoc_mac_addr;
+
+ /**
+ * key_mgmt_offload - Use key management offload
+ *
+ * Key management offload should be used if the device supports it.
+ * Key management offload is the capability of a device operating as
+ * a station to do the exchange necessary to establish temporal keys
+ * during initial RSN connection, after roaming, or during a PTK
+ * rekeying operation.
+ */
+ int key_mgmt_offload;
+
+ /**
+ * user_mpm - MPM residency
+ *
+ * 0: MPM lives in driver.
+ * 1: wpa_supplicant handles peering and station allocation.
+ *
+ * If AMPE or SAE is enabled, the MPM is always in userspace.
+ */
+ int user_mpm;
+
+ /**
+ * max_peer_links - Maximum number of peer links
+ *
+ * Maximum number of mesh peering currently maintained by the STA.
+ */
+ int max_peer_links;
+
+ /**
+ * cert_in_cb - Whether to include a peer certificate dump in events
+ *
+ * This controls whether peer certificates for authentication server and
+ * its certificate chain are included in EAP peer certificate events.
+ */
+ int cert_in_cb;
+
+ /**
+ * mesh_max_inactivity - Timeout in seconds to detect STA inactivity
+ *
+ * This timeout value is used in mesh STA to clean up inactive stations.
+ * By default: 300 seconds.
+ */
+ int mesh_max_inactivity;
+
+ /**
+ * passive_scan - Whether to force passive scan for network connection
+ *
+ * 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.
+ */
+ int passive_scan;
+
+ /**
+ * reassoc_same_bss_optim - Whether to optimize reassoc-to-same-BSS
+ */
+ int reassoc_same_bss_optim;
};
@@ -815,6 +1181,11 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
int line);
int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
const char *value);
+int wpa_config_dump_values(struct wpa_config *config, char *buf,
+ size_t buflen);
+int wpa_config_get_value(const char *name, struct wpa_config *config,
+ char *buf, size_t buflen);
+
char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
@@ -828,6 +1199,7 @@ void wpa_config_set_blob(struct wpa_config *config,
struct wpa_config_blob *blob);
void wpa_config_free_blob(struct wpa_config_blob *blob);
int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+void wpa_config_flush_blobs(struct wpa_config *config);
struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
@@ -835,6 +1207,7 @@ int wpa_config_remove_cred(struct wpa_config *config, int id);
void wpa_config_free_cred(struct wpa_cred *cred);
int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
const char *value, int line);
+char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var);
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param);
@@ -855,6 +1228,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
* wpa_config_read - Read and parse configuration database
* @name: Name of the configuration (e.g., path and file name for the
* configuration file)
+ * @cfgp: Pointer to previously allocated configuration data or %NULL if none
* Returns: Pointer to allocated configuration data or %NULL on failure
*
* This function reads configuration data, parses its contents, and allocates
@@ -863,7 +1237,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
*
* Each configuration backend needs to implement this function.
*/
-struct wpa_config * wpa_config_read(const char *name);
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp);
/**
* wpa_config_write - Write or update configuration data
diff --git a/contrib/wpa/wpa_supplicant/config_file.c b/contrib/wpa/wpa_supplicant/config_file.c
index 8f32cc8..3d3a6e4 100644
--- a/contrib/wpa/wpa_supplicant/config_file.c
+++ b/contrib/wpa/wpa_supplicant/config_file.c
@@ -11,6 +11,9 @@
*/
#include "includes.h"
+#ifdef ANDROID
+#include <sys/stat.h>
+#endif /* ANDROID */
#include "common.h"
#include "config.h"
@@ -143,6 +146,15 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
ssid->group_cipher &= ~WPA_CIPHER_CCMP;
}
+ if (ssid->mode == WPAS_MODE_MESH &&
+ (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
+ ssid->key_mgmt != WPA_KEY_MGMT_SAE)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: key_mgmt for mesh network should be open or SAE",
+ line);
+ errors++;
+ }
+
return errors;
}
@@ -158,6 +170,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
ssid = os_zalloc(sizeof(*ssid));
if (ssid == NULL)
return NULL;
+ dl_list_init(&ssid->psk_list);
ssid->id = id;
wpa_config_set_network_defaults(ssid);
@@ -218,6 +231,7 @@ static struct wpa_cred * wpa_config_read_cred(FILE *f, int *line, int id)
if (cred == NULL)
return NULL;
cred->id = id;
+ cred->sim_num = DEFAULT_USER_SELECTED_SIM;
while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
if (os_strcmp(pos, "}") == 0) {
@@ -345,23 +359,34 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
#endif /* CONFIG_NO_CONFIG_BLOBS */
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
FILE *f;
char buf[512], *pos;
int errors = 0, line = 0;
- struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
- struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
+ struct wpa_ssid *ssid, *tail, *head;
+ struct wpa_cred *cred, *cred_tail, *cred_head;
struct wpa_config *config;
int id = 0;
int cred_id = 0;
- config = wpa_config_alloc_empty(NULL, NULL);
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate config file "
"structure");
return NULL;
}
+ tail = head = config->ssid;
+ while (tail && tail->next)
+ tail = tail->next;
+ cred_tail = cred_head = config->cred;
+ while (cred_tail && cred_tail->next)
+ cred_tail = cred_tail->next;
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
@@ -586,7 +611,7 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
int res;
res = os_snprintf(field, sizeof(field), "wep_key%d", idx);
- if (res < 0 || (size_t) res >= sizeof(field))
+ if (os_snprintf_error(sizeof(field), res))
return;
value = wpa_config_get(ssid, field);
if (value) {
@@ -597,6 +622,16 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
#ifdef CONFIG_P2P
+
+static void write_go_p2p_dev_addr(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "go_p2p_dev_addr");
+ if (value == NULL)
+ return;
+ fprintf(f, "\tgo_p2p_dev_addr=%s\n", value);
+ os_free(value);
+}
+
static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
{
char *value = wpa_config_get(ssid, "p2p_client_list");
@@ -605,6 +640,20 @@ static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
fprintf(f, "\tp2p_client_list=%s\n", value);
os_free(value);
}
+
+
+static void write_psk_list(FILE *f, struct wpa_ssid *ssid)
+{
+ struct psk_list_entry *psk;
+ char hex[32 * 2 + 1];
+
+ dl_list_for_each(psk, &ssid->psk_list, struct psk_list_entry, list) {
+ wpa_snprintf_hex(hex, sizeof(hex), psk->psk, sizeof(psk->psk));
+ fprintf(f, "\tpsk_list=%s" MACSTR "-%s\n",
+ psk->p2p ? "P2P-" : "", MAC2STR(psk->addr), hex);
+ }
+}
+
#endif /* CONFIG_P2P */
@@ -621,6 +670,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(ssid);
INT(scan_ssid);
write_bssid(f, ssid);
+ write_str(f, "bssid_blacklist", ssid);
+ write_str(f, "bssid_whitelist", ssid);
write_psk(f, ssid);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
@@ -630,6 +681,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
write_auth_alg(f, ssid);
STR(bgscan);
STR(autoscan);
+ STR(scan_freq);
#ifdef IEEE8021X_EAPOL
write_eap(f, ssid);
STR(identity);
@@ -643,6 +695,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(dh_file);
STR(subject_match);
STR(altsubject_match);
+ STR(domain_suffix_match);
+ STR(domain_match);
STR(ca_cert2);
STR(ca_path2);
STR(client_cert2);
@@ -651,6 +705,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(dh_file2);
STR(subject_match2);
STR(altsubject_match2);
+ STR(domain_suffix_match2);
+ STR(domain_match2);
STR(phase1);
STR(phase2);
STR(pcsc);
@@ -667,6 +723,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INTe(engine);
INTe(engine2);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+ STR(openssl_ciphers);
+ INTe(erp);
#endif /* IEEE8021X_EAPOL */
for (i = 0; i < 4; i++)
write_wep_key(f, i, ssid);
@@ -676,20 +734,78 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INTe(ocsp);
+ INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM);
#endif /* IEEE8021X_EAPOL */
INT(mode);
+ INT(no_auto_peer);
INT(frequency);
+ INT(fixed_freq);
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(peerkey);
+ INT(mixed_cell);
#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_P2P
+ write_go_p2p_dev_addr(f, ssid);
write_p2p_client_list(f, ssid);
+ write_psk_list(f, ssid);
#endif /* CONFIG_P2P */
+ INT(ap_max_inactivity);
+ INT(dtim_period);
+ INT(beacon_int);
+#ifdef CONFIG_MACSEC
+ INT(macsec_policy);
+#endif /* CONFIG_MACSEC */
+#ifdef CONFIG_HS20
+ INT(update_identifier);
+#endif /* CONFIG_HS20 */
+ write_int(f, "mac_addr", ssid->mac_addr, -1);
+#ifdef CONFIG_MESH
+ STR(mesh_basic_rates);
+ INT_DEF(dot11MeshMaxRetries, DEFAULT_MESH_MAX_RETRIES);
+ INT_DEF(dot11MeshRetryTimeout, DEFAULT_MESH_RETRY_TIMEOUT);
+ INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT);
+ INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
+#endif /* CONFIG_MESH */
+ INT(wpa_ptk_rekey);
+ INT(ignore_broadcast_ssid);
+#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(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU);
+ INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR);
+ INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY);
+ STR(ht_mcs);
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ INT(disable_vht);
+ INT(vht_capa);
+ INT(vht_capa_mask);
+ INT_DEF(vht_rx_mcs_nss_1, -1);
+ INT_DEF(vht_rx_mcs_nss_2, -1);
+ INT_DEF(vht_rx_mcs_nss_3, -1);
+ INT_DEF(vht_rx_mcs_nss_4, -1);
+ INT_DEF(vht_rx_mcs_nss_5, -1);
+ INT_DEF(vht_rx_mcs_nss_6, -1);
+ INT_DEF(vht_rx_mcs_nss_7, -1);
+ INT_DEF(vht_rx_mcs_nss_8, -1);
+ INT_DEF(vht_tx_mcs_nss_1, -1);
+ INT_DEF(vht_tx_mcs_nss_2, -1);
+ INT_DEF(vht_tx_mcs_nss_3, -1);
+ INT_DEF(vht_tx_mcs_nss_4, -1);
+ INT_DEF(vht_tx_mcs_nss_5, -1);
+ INT_DEF(vht_tx_mcs_nss_6, -1);
+ INT_DEF(vht_tx_mcs_nss_7, -1);
+ INT_DEF(vht_tx_mcs_nss_8, -1);
+#endif /* CONFIG_VHT_OVERRIDES */
#undef STR
#undef INT
@@ -699,6 +815,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
{
+ size_t i;
+
if (cred->priority)
fprintf(f, "\tpriority=%d\n", cred->priority);
if (cred->pcsc)
@@ -724,10 +842,12 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
if (cred->milenage)
fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
- if (cred->domain)
- fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+ for (i = 0; i < cred->num_domain; i++)
+ fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]);
+ if (cred->domain_suffix_match)
+ fprintf(f, "\tdomain_suffix_match=\"%s\"\n",
+ cred->domain_suffix_match);
if (cred->roaming_consortium_len) {
- size_t i;
fprintf(f, "\troaming_consortium=");
for (i = 0; i < cred->roaming_consortium_len; i++)
fprintf(f, "%02x", cred->roaming_consortium[i]);
@@ -737,14 +857,15 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
const char *name;
name = eap_get_name(cred->eap_method[0].vendor,
cred->eap_method[0].method);
- fprintf(f, "\teap=%s\n", name);
+ if (name)
+ fprintf(f, "\teap=%s\n", name);
}
if (cred->phase1)
fprintf(f, "\tphase1=\"%s\"\n", cred->phase1);
if (cred->phase2)
fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
if (cred->excluded_ssid) {
- size_t i, j;
+ size_t j;
for (i = 0; i < cred->num_excluded_ssid; i++) {
struct excluded_ssid *e = &cred->excluded_ssid[i];
fprintf(f, "\texcluded_ssid=");
@@ -753,6 +874,70 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
fprintf(f, "\n");
}
}
+ if (cred->roaming_partner) {
+ for (i = 0; i < cred->num_roaming_partner; i++) {
+ struct roaming_partner *p = &cred->roaming_partner[i];
+ fprintf(f, "\troaming_partner=\"%s,%d,%u,%s\"\n",
+ p->fqdn, p->exact_match, p->priority,
+ p->country);
+ }
+ }
+ if (cred->update_identifier)
+ fprintf(f, "\tupdate_identifier=%d\n", cred->update_identifier);
+
+ if (cred->provisioning_sp)
+ fprintf(f, "\tprovisioning_sp=\"%s\"\n", cred->provisioning_sp);
+ if (cred->sp_priority)
+ fprintf(f, "\tsp_priority=%d\n", cred->sp_priority);
+
+ if (cred->min_dl_bandwidth_home)
+ fprintf(f, "\tmin_dl_bandwidth_home=%u\n",
+ cred->min_dl_bandwidth_home);
+ if (cred->min_ul_bandwidth_home)
+ fprintf(f, "\tmin_ul_bandwidth_home=%u\n",
+ cred->min_ul_bandwidth_home);
+ if (cred->min_dl_bandwidth_roaming)
+ fprintf(f, "\tmin_dl_bandwidth_roaming=%u\n",
+ cred->min_dl_bandwidth_roaming);
+ if (cred->min_ul_bandwidth_roaming)
+ fprintf(f, "\tmin_ul_bandwidth_roaming=%u\n",
+ cred->min_ul_bandwidth_roaming);
+
+ if (cred->max_bss_load)
+ fprintf(f, "\tmax_bss_load=%u\n",
+ cred->max_bss_load);
+
+ if (cred->ocsp)
+ fprintf(f, "\tocsp=%d\n", cred->ocsp);
+
+ if (cred->num_req_conn_capab) {
+ for (i = 0; i < cred->num_req_conn_capab; i++) {
+ int *ports;
+
+ fprintf(f, "\treq_conn_capab=%u",
+ cred->req_conn_capab_proto[i]);
+ ports = cred->req_conn_capab_port[i];
+ if (ports) {
+ int j;
+ for (j = 0; ports[j] != -1; j++) {
+ fprintf(f, "%s%d", j > 0 ? "," : ":",
+ ports[j]);
+ }
+ }
+ fprintf(f, "\n");
+ }
+ }
+
+ if (cred->required_roaming_consortium_len) {
+ fprintf(f, "\trequired_roaming_consortium=");
+ for (i = 0; i < cred->required_roaming_consortium_len; i++)
+ fprintf(f, "%02x",
+ cred->required_roaming_consortium[i]);
+ fprintf(f, "\n");
+ }
+
+ if (cred->sim_num != DEFAULT_USER_SELECTED_SIM)
+ fprintf(f, "\tsim_num=%d\n", cred->sim_num);
}
@@ -816,6 +1001,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->pkcs11_module_path)
fprintf(f, "pkcs11_module_path=%s\n",
config->pkcs11_module_path);
+ if (config->openssl_ciphers)
+ fprintf(f, "openssl_ciphers=%s\n", config->openssl_ciphers);
if (config->pcsc_reader)
fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader);
if (config->pcsc_pin)
@@ -898,6 +1085,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "p2p_intra_bss=%u\n", config->p2p_intra_bss);
if (config->p2p_group_idle)
fprintf(f, "p2p_group_idle=%u\n", config->p2p_group_idle);
+ if (config->p2p_passphrase_len)
+ fprintf(f, "p2p_passphrase_len=%u\n",
+ config->p2p_passphrase_len);
if (config->p2p_pref_chan) {
unsigned int i;
fprintf(f, "p2p_pref_chan=");
@@ -908,13 +1098,33 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
fprintf(f, "\n");
}
+ if (config->p2p_no_go_freq.num) {
+ char *val = freq_range_list_str(&config->p2p_no_go_freq);
+ if (val) {
+ fprintf(f, "p2p_no_go_freq=%s\n", val);
+ os_free(val);
+ }
+ }
+ if (config->p2p_add_cli_chan)
+ fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
+ if (config->p2p_optimize_listen_chan !=
+ DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN)
+ fprintf(f, "p2p_optimize_listen_chan=%d\n",
+ config->p2p_optimize_listen_chan);
if (config->p2p_go_ht40)
fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+ if (config->p2p_go_vht)
+ fprintf(f, "p2p_go_vht=%u\n", config->p2p_go_vht);
+ if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
+ fprintf(f, "p2p_go_ctwindow=%u\n", config->p2p_go_ctwindow);
if (config->p2p_disabled)
fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
if (config->p2p_no_group_iface)
fprintf(f, "p2p_no_group_iface=%u\n",
config->p2p_no_group_iface);
+ if (config->p2p_ignore_shared_freq)
+ fprintf(f, "p2p_ignore_shared_freq=%u\n",
+ config->p2p_ignore_shared_freq);
#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
@@ -950,12 +1160,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
#endif /* CONFIG_INTERWORKING */
if (config->pbc_in_m1)
fprintf(f, "pbc_in_m1=%u\n", config->pbc_in_m1);
- if (config->wps_nfc_dev_pw_id)
- fprintf(f, "wps_nfc_dev_pw_id=%d\n",
- config->wps_nfc_dev_pw_id);
- write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
- write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
- write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+ if (config->wps_nfc_pw_from_config) {
+ if (config->wps_nfc_dev_pw_id)
+ fprintf(f, "wps_nfc_dev_pw_id=%d\n",
+ config->wps_nfc_dev_pw_id);
+ write_global_bin(f, "wps_nfc_dh_pubkey",
+ config->wps_nfc_dh_pubkey);
+ write_global_bin(f, "wps_nfc_dh_privkey",
+ config->wps_nfc_dh_privkey);
+ write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+ }
if (config->ext_password_backend)
fprintf(f, "ext_password_backend=%s\n",
@@ -970,6 +1184,102 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "okc=%d\n", config->okc);
if (config->pmf)
fprintf(f, "pmf=%d\n", config->pmf);
+ if (config->dtim_period)
+ fprintf(f, "dtim_period=%d\n", config->dtim_period);
+ if (config->beacon_int)
+ fprintf(f, "beacon_int=%d\n", config->beacon_int);
+
+ if (config->sae_groups) {
+ int i;
+ fprintf(f, "sae_groups=");
+ for (i = 0; config->sae_groups[i] >= 0; i++) {
+ fprintf(f, "%s%d", i > 0 ? " " : "",
+ config->sae_groups[i]);
+ }
+ fprintf(f, "\n");
+ }
+
+ if (config->ap_vendor_elements) {
+ int i, len = wpabuf_len(config->ap_vendor_elements);
+ const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
+ if (len > 0) {
+ fprintf(f, "ap_vendor_elements=");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ }
+
+ if (config->ignore_old_scan_res)
+ fprintf(f, "ignore_old_scan_res=%d\n",
+ config->ignore_old_scan_res);
+
+ if (config->freq_list && config->freq_list[0]) {
+ int i;
+ fprintf(f, "freq_list=");
+ for (i = 0; config->freq_list[i]; i++) {
+ fprintf(f, "%s%u", i > 0 ? " " : "",
+ config->freq_list[i]);
+ }
+ fprintf(f, "\n");
+ }
+ if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
+ fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);
+
+ if (config->sched_scan_interval)
+ fprintf(f, "sched_scan_interval=%u\n",
+ config->sched_scan_interval);
+
+ if (config->external_sim)
+ fprintf(f, "external_sim=%d\n", config->external_sim);
+
+ if (config->tdls_external_control)
+ fprintf(f, "tdls_external_control=%d\n",
+ config->tdls_external_control);
+
+ if (config->wowlan_triggers)
+ fprintf(f, "wowlan_triggers=%s\n",
+ config->wowlan_triggers);
+
+ if (config->bgscan)
+ fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
+
+ if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
+ fprintf(f, "p2p_search_delay=%u\n",
+ config->p2p_search_delay);
+
+ if (config->mac_addr)
+ fprintf(f, "mac_addr=%d\n", config->mac_addr);
+
+ if (config->rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME)
+ fprintf(f, "rand_addr_lifetime=%u\n",
+ config->rand_addr_lifetime);
+
+ if (config->preassoc_mac_addr)
+ fprintf(f, "preassoc_mac_addr=%d\n", config->preassoc_mac_addr);
+
+ if (config->key_mgmt_offload != DEFAULT_KEY_MGMT_OFFLOAD)
+ fprintf(f, "key_mgmt_offload=%u\n", config->key_mgmt_offload);
+
+ if (config->user_mpm != DEFAULT_USER_MPM)
+ fprintf(f, "user_mpm=%d\n", config->user_mpm);
+
+ if (config->max_peer_links != DEFAULT_MAX_PEER_LINKS)
+ fprintf(f, "max_peer_links=%d\n", config->max_peer_links);
+
+ if (config->cert_in_cb != DEFAULT_CERT_IN_CB)
+ fprintf(f, "cert_in_cb=%d\n", config->cert_in_cb);
+
+ if (config->mesh_max_inactivity != DEFAULT_MESH_MAX_INACTIVITY)
+ fprintf(f, "mesh_max_inactivity=%d\n",
+ config->mesh_max_inactivity);
+
+ if (config->passive_scan)
+ fprintf(f, "passive_scan=%d\n", config->passive_scan);
+
+ if (config->reassoc_same_bss_optim)
+ fprintf(f, "reassoc_same_bss_optim=%d\n",
+ config->reassoc_same_bss_optim);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -985,18 +1295,29 @@ int wpa_config_write(const char *name, struct wpa_config *config)
struct wpa_config_blob *blob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
int ret = 0;
+ const char *orig_name = name;
+ int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
+ char *tmp_name = os_malloc(tmp_len);
+
+ if (tmp_name) {
+ os_snprintf(tmp_name, tmp_len, "%s.tmp", name);
+ name = tmp_name;
+ }
wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
f = fopen(name, "w");
if (f == NULL) {
wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
+ os_free(tmp_name);
return -1;
}
wpa_config_write_global(f, config);
for (cred = config->cred; cred; cred = cred->next) {
+ if (cred->temporary)
+ continue;
fprintf(f, "\ncred={\n");
wpa_config_write_cred(f, cred);
fprintf(f, "}\n");
@@ -1023,8 +1344,21 @@ int wpa_config_write(const char *name, struct wpa_config *config)
fclose(f);
+ if (tmp_name) {
+ int chmod_ret = 0;
+
+#ifdef ANDROID
+ chmod_ret = chmod(tmp_name,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+#endif /* ANDROID */
+ if (chmod_ret != 0 || rename(tmp_name, orig_name) != 0)
+ ret = -1;
+
+ os_free(tmp_name);
+ }
+
wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
- name, ret ? "un" : "");
+ orig_name, ret ? "un" : "");
return ret;
#else /* CONFIG_NO_CONFIG_WRITE */
return -1;
diff --git a/contrib/wpa/wpa_supplicant/config_none.c b/contrib/wpa/wpa_supplicant/config_none.c
index 589ea36..2aac28f 100644
--- a/contrib/wpa/wpa_supplicant/config_none.c
+++ b/contrib/wpa/wpa_supplicant/config_none.c
@@ -17,11 +17,16 @@
#include "base64.h"
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
struct wpa_config *config;
- config = wpa_config_alloc_empty(NULL, NULL);
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
return NULL;
/* TODO: fill in configuration data */
diff --git a/contrib/wpa/wpa_supplicant/config_ssid.h b/contrib/wpa/wpa_supplicant/config_ssid.h
index 9ac67c7..7c826cf 100644
--- a/contrib/wpa/wpa_supplicant/config_ssid.h
+++ b/contrib/wpa/wpa_supplicant/config_ssid.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Network configuration structures
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#define CONFIG_SSID_H
#include "common/defs.h"
+#include "utils/list.h"
#include "eap_peer/eap_config.h"
#define MAX_SSID_LEN 32
@@ -26,12 +27,25 @@
#define DEFAULT_FRAGMENT_SIZE 1398
#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_MESH_MAX_RETRIES 2
+#define DEFAULT_MESH_RETRY_TIMEOUT 40
+#define DEFAULT_MESH_CONFIRM_TIMEOUT 40
+#define DEFAULT_MESH_HOLDING_TIMEOUT 40
#define DEFAULT_DISABLE_HT 0
#define DEFAULT_DISABLE_HT40 0
#define DEFAULT_DISABLE_SGI 0
+#define DEFAULT_DISABLE_LDPC 0
#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
+
+struct psk_list_entry {
+ struct dl_list list;
+ u8 addr[ETH_ALEN];
+ u8 psk[32];
+ u8 p2p;
+};
/**
* struct wpa_ssid - Network configuration data
@@ -118,11 +132,28 @@ struct wpa_ssid {
u8 bssid[ETH_ALEN];
/**
+ * bssid_blacklist - List of inacceptable BSSIDs
+ */
+ u8 *bssid_blacklist;
+ size_t num_bssid_blacklist;
+
+ /**
+ * bssid_blacklist - List of acceptable BSSIDs
+ */
+ u8 *bssid_whitelist;
+ size_t num_bssid_whitelist;
+
+ /**
* bssid_set - Whether BSSID is configured for this network
*/
int bssid_set;
/**
+ * go_p2p_dev_addr - GO's P2P Device Address or all zeros if not set
+ */
+ u8 go_p2p_dev_addr[ETH_ALEN];
+
+ /**
* psk - WPA pre-shared key (256 bits)
*/
u8 psk[32];
@@ -302,12 +333,15 @@ struct wpa_ssid {
* 4 = P2P Group Formation (used internally; not in configuration
* files)
*
- * Note: IBSS can only be used with key_mgmt NONE (plaintext and
- * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
- * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
- * following network block options: proto=WPA, key_mgmt=WPA-NONE,
- * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
- * be set (either directly or using ASCII passphrase).
+ * 5 = Mesh
+ *
+ * Note: IBSS can only be used with key_mgmt NONE (plaintext and static
+ * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
+ * (fixed group key TKIP/CCMP) is available for backwards compatibility,
+ * but its use is deprecated. WPA-None requires following network block
+ * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or
+ * CCMP, but not both), and psk must also be set (either directly or
+ * using ASCII passphrase).
*/
enum wpas_mode {
WPAS_MODE_INFRA = 0,
@@ -315,6 +349,7 @@ struct wpa_ssid {
WPAS_MODE_AP = 2,
WPAS_MODE_P2P_GO = 3,
WPAS_MODE_P2P_GROUP_FORMATION = 4,
+ WPAS_MODE_MESH = 5,
} mode;
/**
@@ -384,8 +419,29 @@ struct wpa_ssid {
*/
int frequency;
+ /**
+ * fixed_freq - Use fixed frequency for IBSS
+ */
+ int fixed_freq;
+
+ /**
+ * mesh_basic_rates - BSS Basic rate set for mesh network
+ *
+ */
+ int *mesh_basic_rates;
+
+ /**
+ * Mesh network plink parameters
+ */
+ int dot11MeshMaxRetries;
+ int dot11MeshRetryTimeout; /* msec */
+ int dot11MeshConfirmTimeout; /* msec */
+ int dot11MeshHoldingTimeout; /* msec */
+
int ht40;
+ int vht;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -456,6 +512,11 @@ struct wpa_ssid {
#endif /* P2P_MAX_STORED_CLIENTS */
/**
+ * psk_list - Per-client PSKs (struct psk_list_entry)
+ */
+ struct dl_list psk_list;
+
+ /**
* p2p_group - Network generated as a P2P group (used internally)
*/
int p2p_group;
@@ -504,6 +565,19 @@ struct wpa_ssid {
int disable_sgi;
/**
+ * disable_ldpc - Disable LDPC for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_ldpc;
+
+ /**
+ * ht40_intolerant - Indicate 40 MHz intolerant for this network
+ */
+ int ht40_intolerant;
+
+ /**
* disable_max_amsdu - Disable MAX A-MSDU
*
* A-MDSU will be 3839 bytes when disabled, or 7935
@@ -534,6 +608,35 @@ struct wpa_ssid {
char *ht_mcs;
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ /**
+ * disable_vht - Disable VHT (IEEE 802.11ac) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_vht;
+
+ /**
+ * vht_capa - VHT capabilities to use
+ */
+ unsigned int vht_capa;
+
+ /**
+ * vht_capa_mask - mask for VHT capabilities
+ */
+ unsigned int vht_capa_mask;
+
+ int vht_rx_mcs_nss_1, vht_rx_mcs_nss_2,
+ vht_rx_mcs_nss_3, vht_rx_mcs_nss_4,
+ vht_rx_mcs_nss_5, vht_rx_mcs_nss_6,
+ vht_rx_mcs_nss_7, vht_rx_mcs_nss_8;
+ int vht_tx_mcs_nss_1, vht_tx_mcs_nss_2,
+ vht_tx_mcs_nss_3, vht_tx_mcs_nss_4,
+ vht_tx_mcs_nss_5, vht_tx_mcs_nss_6,
+ vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
+#endif /* CONFIG_VHT_OVERRIDES */
+
/**
* ap_max_inactivity - Timeout in seconds to detect STA's inactivity
*
@@ -549,6 +652,11 @@ struct wpa_ssid {
int dtim_period;
/**
+ * beacon_int - Beacon interval (default: 100 TU)
+ */
+ int beacon_int;
+
+ /**
* auth_failures - Number of consecutive authentication failures
*/
unsigned int auth_failures;
@@ -556,7 +664,7 @@ struct wpa_ssid {
/**
* disabled_until - Network block disabled until this time if non-zero
*/
- struct os_time disabled_until;
+ struct os_reltime disabled_until;
/**
* parent_cred - Pointer to parent wpa_cred entry
@@ -566,6 +674,44 @@ struct wpa_ssid {
* dereferences since it may not be updated in all cases.
*/
void *parent_cred;
+
+#ifdef CONFIG_MACSEC
+ /**
+ * macsec_policy - Determines the policy for MACsec secure session
+ *
+ * 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.
+ */
+ int macsec_policy;
+#endif /* CONFIG_MACSEC */
+
+#ifdef CONFIG_HS20
+ int update_identifier;
+#endif /* CONFIG_HS20 */
+
+ unsigned int wps_run;
+
+ /**
+ * mac_addr - MAC address policy
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address for each ESS connection
+ * 2 = like 1, but maintain OUI (with local admin bit set)
+ *
+ * Internally, special value -1 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
+ */
+ int mac_addr;
+
+ /**
+ * no_auto_peer - Do not automatically peer with compatible mesh peers
+ *
+ * When unset, the reception of a beacon from a another mesh peer in
+ * this MBSS will trigger a peering attempt.
+ */
+ int no_auto_peer;
};
#endif /* CONFIG_SSID_H */
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface.c b/contrib/wpa/wpa_supplicant/ctrl_iface.c
index 864dd7d..b4aefb6 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface.c
@@ -1,19 +1,26 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2012, 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.
*/
#include "utils/includes.h"
+#ifdef CONFIG_TESTING_OPTIONS
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#endif /* CONFIG_TESTING_OPTIONS */
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/uuid.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "crypto/tls.h"
+#include "ap/hostapd.h"
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
@@ -39,98 +46,16 @@
#include "blacklist.h"
#include "autoscan.h"
#include "wnm_sta.h"
-
-extern struct wpa_driver_ops *wpa_drivers[];
+#include "offchannel.h"
+#include "drivers/driver.h"
+#include "mesh.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,
char *buf, int len);
-
-
-static int pno_start(struct wpa_supplicant *wpa_s)
-{
- int ret;
- size_t i, num_ssid;
- struct wpa_ssid *ssid;
- struct wpa_driver_scan_params params;
-
- if (wpa_s->pno)
- return 0;
-
- if (wpa_s->wpa_state == WPA_SCANNING) {
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_cancel_scan(wpa_s);
- }
-
- os_memset(&params, 0, sizeof(params));
-
- num_ssid = 0;
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- if (!wpas_network_disabled(wpa_s, ssid))
- num_ssid++;
- ssid = ssid->next;
- }
- if (num_ssid > WPAS_MAX_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;
- }
-
- if (num_ssid == 0) {
- wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
- return -1;
- }
-
- params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
- num_ssid);
- if (params.filter_ssids == NULL)
- return -1;
- i = 0;
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- if (!wpas_network_disabled(wpa_s, ssid)) {
- params.ssids[i].ssid = ssid->ssid;
- params.ssids[i].ssid_len = ssid->ssid_len;
- params.num_ssids++;
- os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
- ssid->ssid_len);
- params.filter_ssids[i].ssid_len = ssid->ssid_len;
- params.num_filter_ssids++;
- i++;
- if (i == num_ssid)
- break;
- }
- ssid = ssid->next;
- }
-
- if (wpa_s->conf->filter_rssi)
- params.filter_rssi = wpa_s->conf->filter_rssi;
-
- ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
- os_free(params.filter_ssids);
- if (ret == 0)
- wpa_s->pno = 1;
- return ret;
-}
-
-
-static int pno_stop(struct wpa_supplicant *wpa_s)
-{
- int ret = 0;
-
- if (wpa_s->pno) {
- wpa_s->pno = 0;
- ret = wpa_drv_stop_sched_scan(wpa_s);
- }
-
- if (wpa_s->wpa_state == WPA_SCANNING)
- wpa_supplicant_req_scan(wpa_s, 0, 0);
-
- return ret;
-}
-
+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)
{
@@ -178,7 +103,7 @@ static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
struct wpa_ssid *c;
/*
- * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+ * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
* SSID_SPEC ::= ssid <SSID_HEX>
* BSSID_SPEC ::= bssid <BSSID_HEX>
*/
@@ -284,6 +209,7 @@ static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
wpa_s->sme.prev_bssid_set = 0;
#endif /* CONFIG_SME */
wpa_s->reassociate = 1;
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -291,6 +217,72 @@ static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
}
+#ifndef CONFIG_NO_CONFIG_BLOBS
+static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
+{
+ char *name = pos;
+ struct wpa_config_blob *blob;
+ size_t len;
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
+ blob = os_zalloc(sizeof(*blob));
+ if (blob == NULL)
+ return -1;
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(len / 2);
+ if (blob->name == NULL || blob->data == NULL) {
+ wpa_config_free_blob(blob);
+ return -1;
+ }
+
+ if (hexstr2bin(pos, blob->data, len / 2) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
+ wpa_config_free_blob(blob);
+ return -1;
+ }
+ blob->len = len / 2;
+
+ wpa_config_set_blob(wpa_s->conf, blob);
+
+ return 0;
+}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
+static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *params;
+ char *pos;
+ int *freqs = NULL;
+ int ret;
+
+ if (atoi(cmd)) {
+ params = os_strchr(cmd, ' ');
+ os_free(wpa_s->manual_sched_scan_freqs);
+ if (params) {
+ params++;
+ pos = os_strstr(params, "freq=");
+ if (pos)
+ freqs = freq_range_to_channel_list(wpa_s,
+ pos + 5);
+ }
+ wpa_s->manual_sched_scan_freqs = freqs;
+ ret = wpas_start_pno(wpa_s);
+ } else {
+ ret = wpas_stop_pno(wpa_s);
+ }
+ return ret;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -348,17 +340,21 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wps_testing_dummy_cred = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
wps_testing_dummy_cred);
+ } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+ wps_corrupt_pkhash = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+ wps_corrupt_pkhash);
#endif /* CONFIG_WPS_TESTING */
} else if (os_strcasecmp(cmd, "ampdu") == 0) {
if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
ret = -1;
+#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 */
-#ifdef CONFIG_TDLS
} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
int disabled = atoi(value);
wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
@@ -370,10 +366,7 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_tdls_enable(wpa_s->wpa, !disabled);
#endif /* CONFIG_TDLS */
} else if (os_strcasecmp(cmd, "pno") == 0) {
- if (atoi(value))
- ret = pno_start(wpa_s);
- else
- ret = pno_stop(wpa_s);
+ ret = wpas_ctrl_pno(wpa_s, value);
} else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
int disabled = atoi(value);
if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
@@ -420,7 +413,11 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
- wifi_display_enable(wpa_s->global, !!atoi(value));
+ int enabled = !!atoi(value);
+ if (enabled && !wpa_s->global->p2p)
+ ret = -1;
+ else
+ wifi_display_enable(wpa_s->global, enabled);
#endif /* CONFIG_WIFI_DISPLAY */
} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
ret = set_bssid_filter(wpa_s, value);
@@ -428,6 +425,35 @@ 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_TESTING_OPTIONS
+ } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
+ wpa_s->ext_mgmt_frame_handling = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
+ wpa_s->ext_eapol_frame_io = !!atoi(value);
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
+ wpa_s->ext_eapol_frame_io;
+ }
+#endif /* CONFIG_AP */
+ } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
+ wpa_s->extra_roc_dur = atoi(value);
+ } else if (os_strcasecmp(cmd, "test_failure") == 0) {
+ wpa_s->test_failure = atoi(value);
+#endif /* CONFIG_TESTING_OPTIONS */
+#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) {
+ if (os_strcmp(value, "AUTO") == 0)
+ wpa_s->setband = WPA_SETBAND_AUTO;
+ else if (os_strcmp(value, "5G") == 0)
+ wpa_s->setband = WPA_SETBAND_5G;
+ else if (os_strcmp(value, "2G") == 0)
+ wpa_s->setband = WPA_SETBAND_2G;
+ else
+ ret = -1;
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -455,15 +481,29 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
wpa_s->conf->country[1]);
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
- res = os_snprintf(buf, buflen, "%d",
- wpa_s->global->wifi_display);
- if (res < 0 || (unsigned int) res >= buflen)
+ int enabled;
+ if (wpa_s->global->p2p == NULL ||
+ wpa_s->global->p2p_disabled)
+ enabled = 0;
+ else
+ enabled = wpa_s->global->wifi_display;
+ res = os_snprintf(buf, buflen, "%d", enabled);
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_TESTING_GET_GTK
+ } else if (os_strcmp(cmd, "gtk") == 0) {
+ if (wpa_s->last_gtk_len == 0)
return -1;
+ res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
+ wpa_s->last_gtk_len);
return res;
-#endif /* CONFIG_WIFI_DISPLAY */
+#endif /* CONFIG_TESTING_GET_GTK */
+ } else if (os_strcmp(cmd, "tls_library") == 0) {
+ res = tls_get_library_version(buf, buflen);
+ } else {
+ res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
}
- if (res < 0 || (unsigned int) res >= buflen)
+ if (os_snprintf_error(buflen, res))
return -1;
return res;
}
@@ -554,13 +594,16 @@ static int wpa_supplicant_ctrl_iface_tdls_setup(
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
MAC2STR(peer));
- ret = wpa_tdls_reneg(wpa_s->wpa, peer);
- if (ret) {
- if (wpa_tdls_is_external_setup(wpa_s->wpa))
- ret = wpa_tdls_start(wpa_s->wpa, peer);
- else
- ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
- }
+ if ((wpa_s->conf->tdls_external_control) &&
+ wpa_tdls_is_external_setup(wpa_s->wpa))
+ return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
+ wpa_tdls_remove(wpa_s->wpa, peer);
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_start(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
return ret;
}
@@ -570,6 +613,14 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown(
struct wpa_supplicant *wpa_s, char *addr)
{
u8 peer[ETH_ALEN];
+ int ret;
+
+ if (os_strcmp(addr, "*") == 0) {
+ /* remove everyone */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
+ wpa_tdls_teardown_peers(wpa_s->wpa);
+ return 0;
+ }
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
@@ -580,13 +631,187 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown(
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
MAC2STR(peer));
- return wpa_tdls_teardown_link(wpa_s->wpa, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ if ((wpa_s->conf->tdls_external_control) &&
+ wpa_tdls_is_external_setup(wpa_s->wpa))
+ return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_teardown_link(
+ wpa_s->wpa, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ return ret;
+}
+
+
+static int ctrl_iface_get_capability_tdls(
+ struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+ int ret;
+
+ ret = os_snprintf(buf, buflen, "%s\n",
+ wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
+ "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+ return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 peer[ETH_ALEN];
+ struct hostapd_freq_params freq_params;
+ u8 oper_class;
+ char *pos, *end;
+
+ if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Only supported with external setup");
+ return -1;
+ }
+
+ os_memset(&freq_params, 0, sizeof(freq_params));
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ oper_class = strtol(pos, &end, 10);
+ if (pos == end) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Invalid op class provided");
+ return -1;
+ }
+
+ pos = end;
+ freq_params.freq = atoi(pos);
+ if (freq_params.freq == 0) {
+ wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
+ return -1;
+ }
+
+#define SET_FREQ_SETTING(str) \
+ do { \
+ const char *pos2 = os_strstr(pos, " " #str "="); \
+ if (pos2) { \
+ pos2 += sizeof(" " #str "=") - 1; \
+ freq_params.str = atoi(pos2); \
+ } \
+ } while (0)
+
+ SET_FREQ_SETTING(center_freq1);
+ SET_FREQ_SETTING(center_freq2);
+ SET_FREQ_SETTING(bandwidth);
+ SET_FREQ_SETTING(sec_channel_offset);
+#undef SET_FREQ_SETTING
+
+ freq_params.ht_enabled = !!os_strstr(pos, " ht");
+ freq_params.vht_enabled = !!os_strstr(pos, " vht");
+
+ if (hwaddr_aton(cmd, peer)) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
+ cmd);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE 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" : "");
+
+ return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
+ &freq_params);
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 peer[ETH_ALEN];
+
+ if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Only supported with external setup");
+ return -1;
+ }
+
+ if (hwaddr_aton(cmd, peer)) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
+ cmd);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
+ MAC2STR(peer));
+
+ return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
}
#endif /* CONFIG_TDLS */
+static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *token, *context = NULL;
+ struct wmm_ac_ts_setup_params params = {
+ .tsid = 0xff,
+ .direction = 0xff,
+ };
+
+ while ((token = str_token(cmd, " ", &context))) {
+ if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
+ sscanf(token, "up=%i", &params.user_priority) == 1 ||
+ sscanf(token, "nominal_msdu_size=%i",
+ &params.nominal_msdu_size) == 1 ||
+ sscanf(token, "mean_data_rate=%i",
+ &params.mean_data_rate) == 1 ||
+ sscanf(token, "min_phy_rate=%i",
+ &params.minimum_phy_rate) == 1 ||
+ sscanf(token, "sba=%i",
+ &params.surplus_bandwidth_allowance) == 1)
+ continue;
+
+ if (os_strcasecmp(token, "downlink") == 0) {
+ params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
+ } else if (os_strcasecmp(token, "uplink") == 0) {
+ params.direction = WMM_TSPEC_DIRECTION_UPLINK;
+ } else if (os_strcasecmp(token, "bidi") == 0) {
+ params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
+ } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
+ params.fixed_nominal_msdu = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
+ token);
+ return -1;
+ }
+
+ }
+
+ return wpas_wmm_ac_addts(wpa_s, &params);
+}
+
+
+static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 tsid = atoi(cmd);
+
+ return wpas_wmm_ac_delts(wpa_s, tsid);
+}
+
+
#ifdef CONFIG_IEEE80211R
static int wpa_supplicant_ctrl_iface_ft_ds(
struct wpa_supplicant *wpa_s, char *addr)
@@ -700,7 +925,7 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
if (ret < 0)
return -1;
ret = os_snprintf(buf, buflen, "%s", pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -712,7 +937,7 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
done:
/* Return the generated PIN */
ret = os_snprintf(buf, buflen, "%08d", ret);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -749,14 +974,14 @@ static int wpa_supplicant_ctrl_iface_wps_check_pin(
if (!wps_pin_valid(pin_val)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
}
ret = os_snprintf(buf, buflen, "%s", pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
@@ -775,7 +1000,41 @@ static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
else if (hwaddr_aton(cmd, bssid))
return -1;
- return wpas_wps_start_nfc(wpa_s, _bssid);
+ return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
+ 0, 0);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos)
+ *pos++ = '\0';
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
}
@@ -814,6 +1073,15 @@ static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
size_t len;
struct wpabuf *buf;
int ret;
+ char *freq;
+ int forced_freq = 0;
+
+ freq = strstr(pos, " freq=");
+ if (freq) {
+ *freq = '\0';
+ freq += 6;
+ forced_freq = atoi(freq);
+ }
len = os_strlen(pos);
if (len & 0x01)
@@ -828,7 +1096,7 @@ static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
return -1;
}
- ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+ ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
wpabuf_free(buf);
return ret;
@@ -836,12 +1104,13 @@ static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
- char *reply, size_t max_len)
+ char *reply, size_t max_len,
+ int ndef)
{
struct wpabuf *buf;
int res;
- buf = wpas_wps_nfc_handover_req(wpa_s);
+ buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
if (buf == NULL)
return -1;
@@ -856,36 +1125,77 @@ static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_P2P
+static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
+ return -1;
+ }
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+#endif /* CONFIG_P2P */
+
+
static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
char *cmd, char *reply,
size_t max_len)
{
char *pos;
+ int ndef;
pos = os_strchr(cmd, ' ');
if (pos == NULL)
return -1;
*pos++ = '\0';
- if (os_strcmp(cmd, "NDEF") != 0)
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
return -1;
- if (os_strcmp(pos, "WPS") == 0) {
- return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
- max_len);
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ if (!ndef)
+ return -1;
+ return wpas_ctrl_nfc_get_handover_req_wps(
+ wpa_s, reply, max_len, ndef);
+ }
+
+#ifdef CONFIG_P2P
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_p2p(
+ wpa_s, reply, max_len, ndef);
}
+#endif /* CONFIG_P2P */
return -1;
}
static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
- char *reply, size_t max_len)
+ char *reply, size_t max_len,
+ int ndef, int cr, char *uuid)
{
struct wpabuf *buf;
int res;
- buf = wpas_wps_nfc_handover_sel(wpa_s);
+ buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
if (buf == NULL)
return -1;
@@ -900,79 +1210,188 @@ static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_P2P
+static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef, int tag)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+#endif /* CONFIG_P2P */
+
+
static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
char *cmd, char *reply,
size_t max_len)
{
- char *pos;
+ char *pos, *pos2;
+ int ndef;
pos = os_strchr(cmd, ' ');
if (pos == NULL)
return -1;
*pos++ = '\0';
- if (os_strcmp(cmd, "NDEF") != 0)
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
return -1;
- if (os_strcmp(pos, "WPS") == 0) {
- return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
- max_len);
+ pos2 = os_strchr(pos, ' ');
+ if (pos2)
+ *pos2++ = '\0';
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ if (!ndef)
+ return -1;
+ return wpas_ctrl_nfc_get_handover_sel_wps(
+ wpa_s, reply, max_len, ndef,
+ os_strcmp(pos, "WPS-CR") == 0, pos2);
}
+#ifdef CONFIG_P2P
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 0);
+ }
+
+ if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 1);
+ }
+#endif /* CONFIG_P2P */
+
return -1;
}
-static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
- char *cmd, char *reply,
- size_t max_len)
+static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ char *cmd)
{
size_t len;
- struct wpabuf *buf;
+ struct wpabuf *req, *sel;
int ret;
+ char *pos, *role, *type, *pos2;
+#ifdef CONFIG_P2P
+ char *freq;
+ int forced_freq = 0;
- len = os_strlen(cmd);
- if (len & 0x01)
- return -1;
- len /= 2;
+ freq = strstr(cmd, " freq=");
+ if (freq) {
+ *freq = '\0';
+ freq += 6;
+ forced_freq = atoi(freq);
+ }
+#endif /* CONFIG_P2P */
- buf = wpabuf_alloc(len);
- if (buf == NULL)
- return -1;
- if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
- wpabuf_free(buf);
+ role = cmd;
+ pos = os_strchr(role, ' ');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
return -1;
}
+ *pos++ = '\0';
- ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
- wpabuf_free(buf);
+ type = pos;
+ pos = os_strchr(type, ' ');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
+ return -1;
+ }
+ *pos++ = '\0';
- return ret;
-}
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
+ return -1;
+ }
+ *pos2++ = '\0';
+ len = os_strlen(pos);
+ if (len & 0x01) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
+ return -1;
+ }
+ len /= 2;
-static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
- char *cmd)
-{
- size_t len;
- struct wpabuf *buf;
- int ret;
+ req = wpabuf_alloc(len);
+ if (req == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
+ return -1;
+ }
+ if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
+ wpabuf_free(req);
+ return -1;
+ }
- len = os_strlen(cmd);
- if (len & 0x01)
+ len = os_strlen(pos2);
+ if (len & 0x01) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
+ wpabuf_free(req);
return -1;
+ }
len /= 2;
- buf = wpabuf_alloc(len);
- if (buf == NULL)
+ sel = wpabuf_alloc(len);
+ if (sel == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
+ wpabuf_free(req);
return -1;
- if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
- wpabuf_free(buf);
+ }
+ if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
+ wpabuf_free(req);
+ wpabuf_free(sel);
return -1;
}
- ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
- wpabuf_free(buf);
+ wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
+ role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
+
+ if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
+ ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+#ifdef CONFIG_AP
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
+ {
+ ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
+ if (ret < 0)
+ ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_P2P
+ } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
+ forced_freq);
+#endif /* CONFIG_P2P */
+ } else {
+ wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+ "reported: role=%s type=%s", role, type);
+ ret = -1;
+ }
+ wpabuf_free(req);
+ wpabuf_free(sel);
+
+ if (ret)
+ wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
return ret;
}
@@ -1282,7 +1701,14 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
{
char *pos, *end, tmp[30];
int res, verbose, wps, ret;
+#ifdef CONFIG_HS20
+ const u8 *hs20;
+#endif /* CONFIG_HS20 */
+ const u8 *sess_id;
+ size_t sess_id_len;
+ if (os_strcmp(params, "-DRIVER") == 0)
+ return wpa_drv_status(wpa_s, buf, buflen);
verbose = os_strcmp(params, "-VERBOSE") == 0;
wps = os_strcmp(params, "-WPS") == 0;
pos = buf;
@@ -1291,7 +1717,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid = wpa_s->current_ssid;
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
MAC2STR(wpa_s->bssid));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ ret = os_snprintf(pos, end - pos, "freq=%u\n",
+ wpa_s->assoc_freq);
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (ssid) {
@@ -1309,7 +1740,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
wpa_ssid_txt(_ssid, ssid_len),
ssid->id);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -1320,7 +1751,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
ret = os_snprintf(pos, end - pos,
"passphrase=%s\n",
ssid->passphrase);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1328,7 +1759,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
ret = os_snprintf(pos, end - pos,
"id_str=%s\n",
ssid->id_str);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1359,7 +1790,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
ret = 0;
break;
}
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1373,16 +1804,29 @@ 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_SAE
+ if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
+#ifdef CONFIG_AP
+ !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+ wpa_s->sme.sae.state == SAE_ACCEPTED) {
+ ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
+ wpa_s->sme.sae.group);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
wpa_supplicant_state_txt(wpa_s->wpa_state));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (wpa_s->l2 &&
l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1391,7 +1835,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
if (wpa_s->global->p2p) {
ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
"\n", MAC2STR(wpa_s->global->p2p_dev_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1399,17 +1843,23 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
MAC2STR(wpa_s->own_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
#ifdef CONFIG_HS20
if (wpa_s->current_bss &&
- wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+ (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+ HS20_IE_VENDOR_TYPE)) &&
wpa_s->wpa_proto == WPA_PROTO_RSN &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
- ret = os_snprintf(pos, end - pos, "hs20=1\n");
- if (ret < 0 || ret >= end - pos)
+ int release = 1;
+ if (hs20[1] >= 5) {
+ u8 rel_num = (hs20[6] & 0xf0) >> 4;
+ release = rel_num + 1;
+ }
+ ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1419,17 +1869,43 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
char *type;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ size_t i;
+
if (wpa_s->current_ssid->parent_cred != cred)
continue;
- if (!cred->domain)
- continue;
+ if (cred->provisioning_sp) {
+ ret = os_snprintf(pos, end - pos,
+ "provisioning_sp=%s\n",
+ cred->provisioning_sp);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (!cred->domain)
+ goto no_domain;
+
+ i = 0;
+ if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
+ struct wpabuf *names =
+ wpa_s->current_bss->anqp->domain_name;
+ for (i = 0; names && i < cred->num_domain; i++)
+ {
+ if (domain_name_list_contains(
+ names, cred->domain[i], 1))
+ break;
+ }
+ if (i == cred->num_domain)
+ i = 0; /* show first entry by default */
+ }
ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
- cred->domain);
- if (ret < 0 || ret >= end - pos)
+ cred->domain[i]);
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
+ no_domain:
if (wpa_s->current_bss == NULL ||
wpa_s->current_bss->anqp == NULL)
res = -1;
@@ -1445,7 +1921,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
type = "unknown";
ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -1462,10 +1938,66 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
pos += res;
}
+ sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
+ if (sess_id) {
+ char *start = pos;
+
+ ret = os_snprintf(pos, end - pos, "eap_session_id=");
+ if (os_snprintf_error(end - pos, ret))
+ return start - buf;
+ pos += ret;
+ ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
+ if (ret <= 0)
+ return start - buf;
+ pos += ret;
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return start - buf;
+ pos += ret;
+ }
+
res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
if (res >= 0)
pos += res;
+#ifdef CONFIG_WPS
+ {
+ char uuid_str[100];
+ uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
+ ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_WPS */
+
+#ifdef ANDROID
+ /*
+ * Allow using the STATUS command with default behavior, say for debug,
+ * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE
+ * events with STATUS-NO_EVENTS.
+ */
+ if (os_strcmp(params, "-NO_EVENTS")) {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
+ "id=%d state=%d BSSID=" MACSTR " SSID=%s",
+ wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
+ wpa_s->wpa_state,
+ MAC2STR(wpa_s->bssid),
+ wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
+ wpa_ssid_txt(wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len) : "");
+ if (wpa_s->wpa_state == WPA_COMPLETED) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
+ "- connection to " MACSTR
+ " completed %s [id=%d id_str=%s]",
+ MAC2STR(wpa_s->bssid), "(auth)",
+ ssid ? ssid->id : -1,
+ ssid && ssid->id_str ? ssid->id_str : "");
+ }
+ }
+#endif /* ANDROID */
+
return pos - buf;
}
@@ -1521,7 +2053,7 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
while (e) {
ret = os_snprintf(pos, end - pos, MACSTR "\n",
MAC2STR(e->bssid));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
e = e->next;
@@ -1547,19 +2079,16 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
* skipped when processing scan results.
*/
ret = wpa_blacklist_add(wpa_s, bssid);
- if (ret != 0)
+ if (ret < 0)
return -1;
ret = wpa_blacklist_add(wpa_s, bssid);
- if (ret != 0)
+ if (ret < 0)
return -1;
os_memcpy(buf, "OK\n", 3);
return 3;
}
-extern int wpa_debug_level;
-extern int wpa_debug_timestamp;
-
static const char * debug_level_str(int level)
{
switch (level) {
@@ -1606,10 +2135,6 @@ static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
char *pos, *end, *stamp;
int ret;
- if (cmd == NULL) {
- return -1;
- }
-
/* cmd: "LOG_LEVEL [<level>]" */
if (*cmd == '\0') {
pos = buf;
@@ -1618,7 +2143,7 @@ static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
"Timestamp: %d\n",
debug_level_str(wpa_debug_level),
wpa_debug_timestamp);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
ret = 0;
return ret;
@@ -1651,9 +2176,9 @@ static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_ctrl_iface_list_networks(
- struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+ struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
{
- char *pos, *end;
+ char *pos, *end, *prev;
struct wpa_ssid *ssid;
int ret;
@@ -1661,17 +2186,29 @@ static int wpa_supplicant_ctrl_iface_list_networks(
end = buf + buflen;
ret = os_snprintf(pos, end - pos,
"network id / ssid / bssid / flags\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
ssid = wpa_s->conf->ssid;
+
+ /* skip over ssids until we find next one */
+ if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) {
+ int last_id = atoi(cmd + 8);
+ if (last_id != -1) {
+ while (ssid != NULL && ssid->id <= last_id) {
+ ssid = ssid->next;
+ }
+ }
+ }
+
while (ssid) {
+ prev = pos;
ret = os_snprintf(pos, end - pos, "%d\t%s",
ssid->id,
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ if (os_snprintf_error(end - pos, ret))
+ return prev - buf;
pos += ret;
if (ssid->bssid_set) {
ret = os_snprintf(pos, end - pos, "\t" MACSTR,
@@ -1679,8 +2216,8 @@ static int wpa_supplicant_ctrl_iface_list_networks(
} else {
ret = os_snprintf(pos, end - pos, "\tany");
}
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ if (os_snprintf_error(end - pos, ret))
+ return prev - buf;
pos += ret;
ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
ssid == wpa_s->current_ssid ?
@@ -1690,12 +2227,12 @@ static int wpa_supplicant_ctrl_iface_list_networks(
"[TEMP-DISABLED]" : "",
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
"");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ if (os_snprintf_error(end - pos, ret))
+ return prev - buf;
pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ if (os_snprintf_error(end - pos, ret))
+ return prev - buf;
pos += ret;
ssid = ssid->next;
@@ -1707,54 +2244,15 @@ static int wpa_supplicant_ctrl_iface_list_networks(
static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
{
- int first = 1, ret;
+ int ret;
ret = os_snprintf(pos, end - pos, "-");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ ret = wpa_write_ciphers(pos, end, cipher, "+");
+ if (ret < 0)
return pos;
pos += ret;
- if (cipher & WPA_CIPHER_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
return pos;
}
@@ -1763,91 +2261,122 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
const u8 *ie, size_t ie_len)
{
struct wpa_ie_data data;
- int first, ret;
+ char *start;
+ int ret;
ret = os_snprintf(pos, end - pos, "[%s-", proto);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
ret = os_snprintf(pos, end - pos, "?]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
return pos;
}
- first = 1;
+ start = pos;
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
- ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sEAP",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
- ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sPSK",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sNone",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
- first = 0;
}
#ifdef CONFIG_IEEE80211R
if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sFT/EAP",
- first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "%sFT/PSK",
- first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sFT/SAE",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
- first = 0;
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
- first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
- first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
- first = 0;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SUITEB
+ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB */
+
+#ifdef CONFIG_SUITEB192
+ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB192 */
+
pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
ret = os_snprintf(pos, end - pos, "-preauth");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
@@ -1867,17 +2396,15 @@ static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
return pos;
if (wps_is_selected_pbc_registrar(wps_ie))
txt = "[WPS-PBC]";
-#ifdef CONFIG_WPS2
else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
txt = "[WPS-AUTH]";
-#endif /* CONFIG_WPS2 */
else if (wps_is_selected_pin_registrar(wps_ie))
txt = "[WPS-PIN]";
else
txt = "[WPS]";
ret = os_snprintf(pos, end - pos, "%s", txt);
- if (ret >= 0 && ret < end - pos)
+ if (!os_snprintf_error(end - pos, ret))
pos += ret;
wpabuf_free(wps_ie);
return pos;
@@ -1906,9 +2433,12 @@ static int wpa_supplicant_ctrl_iface_scan_result(
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *p2p;
+ const u8 *ie, *ie2, *p2p, *mesh;
+ mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (!p2p)
+ p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
0)
@@ -1919,44 +2449,78 @@ static int wpa_supplicant_ctrl_iface_scan_result(
ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
MAC2STR(bss->bssid), bss->freq, bss->level);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
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, 2 + ie2[1]);
+ if (ie2) {
+ pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
+ ie2, 2 + ie2[1]);
+ }
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
ret = os_snprintf(pos, end - pos, "[WEP]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
- if (bss->caps & IEEE80211_CAP_IBSS) {
- ret = os_snprintf(pos, end - pos, "[IBSS]");
- if (ret < 0 || ret >= end - pos)
+ if (mesh) {
+ ret = os_snprintf(pos, end - pos, "[MESH]");
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
- if (bss->caps & IEEE80211_CAP_ESS) {
- ret = os_snprintf(pos, end - pos, "[ESS]");
- if (ret < 0 || ret >= end - pos)
+ if (bss_is_dmg(bss)) {
+ const char *s;
+ ret = os_snprintf(pos, end - pos, "[DMG]");
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
+ switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
+ case IEEE80211_CAP_DMG_IBSS:
+ s = "[IBSS]";
+ break;
+ case IEEE80211_CAP_DMG_AP:
+ s = "[ESS]";
+ break;
+ case IEEE80211_CAP_DMG_PBSS:
+ s = "[PBSS]";
+ break;
+ default:
+ s = "";
+ break;
+ }
+ ret = os_snprintf(pos, end - pos, "%s", s);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ } else {
+ if (bss->caps & IEEE80211_CAP_IBSS) {
+ ret = os_snprintf(pos, end - pos, "[IBSS]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (bss->caps & IEEE80211_CAP_ESS) {
+ ret = os_snprintf(pos, end - pos, "[ESS]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
}
if (p2p) {
ret = os_snprintf(pos, end - pos, "[P2P]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
#ifdef CONFIG_HS20
if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
ret = os_snprintf(pos, end - pos, "[HS20]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
@@ -1964,12 +2528,12 @@ static int wpa_supplicant_ctrl_iface_scan_result(
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
@@ -1988,7 +2552,7 @@ static int wpa_supplicant_ctrl_iface_scan_results(
end = buf + buflen;
ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
"flags / ssid\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2004,14 +2568,125 @@ static int wpa_supplicant_ctrl_iface_scan_results(
}
+#ifdef CONFIG_MESH
+
+static int wpa_supplicant_ctrl_iface_mesh_interface_add(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ char *pos, ifname[IFNAMSIZ + 1];
+
+ ifname[0] = '\0';
+
+ pos = os_strstr(cmd, "ifname=");
+ if (pos) {
+ pos += 7;
+ os_strlcpy(ifname, pos, sizeof(ifname));
+ }
+
+ if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
+ return -1;
+
+ os_strlcpy(reply, ifname, max_len);
+ return os_strlen(ifname);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_group_add(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: Could not find network id=%d", id);
+ return -1;
+ }
+ if (ssid->mode != WPAS_MODE_MESH) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
+ return -1;
+ }
+ if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
+ ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
+ wpa_printf(MSG_ERROR,
+ "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
+ return -1;
+ }
+
+ /*
+ * TODO: If necessary write our own group_add function,
+ * for now we can reuse select_network
+ */
+ wpa_supplicant_select_network(wpa_s, ssid);
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_group_remove(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct wpa_supplicant *orig;
+ struct wpa_global *global;
+ int found = 0;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
+
+ global = wpa_s->global;
+ orig = wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (os_strcmp(wpa_s->ifname, cmd) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ wpa_printf(MSG_ERROR,
+ "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
+ cmd);
+ return -1;
+ }
+ if (wpa_s->mesh_if_created && wpa_s == orig) {
+ wpa_printf(MSG_ERROR,
+ "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
+ return -1;
+ }
+
+ wpa_s->reassociate = 0;
+ wpa_s->disconnected = 1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ /*
+ * TODO: If necessary write our own group_remove function,
+ * for now we can reuse deauthenticate
+ */
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+ if (wpa_s->mesh_if_created)
+ wpa_supplicant_remove_iface(global, wpa_s, 0);
+
+ return 0;
+}
+
+#endif /* CONFIG_MESH */
+
+
static int wpa_supplicant_ctrl_iface_select_network(
struct wpa_supplicant *wpa_s, char *cmd)
{
int id;
struct wpa_ssid *ssid;
+ char *pos;
/* cmd: "<network id>" or "any" */
- if (os_strcmp(cmd, "any") == 0) {
+ if (os_strncmp(cmd, "any", 3) == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
ssid = NULL;
} else {
@@ -2031,6 +2706,16 @@ static int wpa_supplicant_ctrl_iface_select_network(
}
}
+ pos = os_strstr(cmd, " freq=");
+ 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;
+ }
+ }
+
wpa_supplicant_select_network(wpa_s, ssid);
return 0;
@@ -2125,7 +2810,7 @@ static int wpa_supplicant_ctrl_iface_add_network(
wpa_config_set_network_defaults(ssid);
ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -2136,18 +2821,14 @@ static int wpa_supplicant_ctrl_iface_remove_network(
{
int id;
struct wpa_ssid *ssid;
+ int was_disabled;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- struct wpa_ssid *remove_ssid = ssid;
- id = ssid->id;
- ssid = ssid->next;
- wpas_notify_network_removed(wpa_s, remove_ssid);
- wpa_config_remove_network(wpa_s->conf, id);
- }
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
eapol_sm_invalidate_cached_session(wpa_s->eapol);
if (wpa_s->current_ssid) {
#ifdef CONFIG_SME
@@ -2155,9 +2836,20 @@ static int wpa_supplicant_ctrl_iface_remove_network(
#endif /* CONFIG_SME */
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ struct wpa_ssid *remove_ssid = ssid;
+ id = ssid->id;
+ ssid = ssid->next;
+ if (wpa_s->last_ssid == remove_ssid)
+ wpa_s->last_ssid = NULL;
+ wpas_notify_network_removed(wpa_s, remove_ssid);
+ wpa_config_remove_network(wpa_s->conf, id);
+ }
return 0;
}
@@ -2173,6 +2865,9 @@ static int wpa_supplicant_ctrl_iface_remove_network(
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;
@@ -2188,16 +2883,59 @@ static int wpa_supplicant_ctrl_iface_remove_network(
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ 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) {
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;
+}
+
+
+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) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
+ "variable '%s'", name);
+ return -1;
+ }
+
+ if (os_strcmp(name, "bssid") != 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 ((os_strcmp(name, "psk") == 0 &&
+ value[0] == '"' && ssid->ssid_len) ||
+ (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
+ wpa_config_update_psk(ssid);
+ else if (os_strcmp(name, "priority") == 0)
+ wpa_config_update_prio_list(wpa_s->conf);
+
return 0;
}
@@ -2205,9 +2943,10 @@ static int wpa_supplicant_ctrl_iface_remove_network(
static int wpa_supplicant_ctrl_iface_set_network(
struct wpa_supplicant *wpa_s, char *cmd)
{
- int id;
+ int id, ret, prev_bssid_set, prev_disabled;
struct wpa_ssid *ssid;
char *name, *value;
+ u8 prev_bssid[ETH_ALEN];
/* cmd: "<network id> <variable name> <value>" */
name = os_strchr(cmd, ' ');
@@ -2233,32 +2972,21 @@ static int wpa_supplicant_ctrl_iface_set_network(
return -1;
}
- if (wpa_config_set(ssid, name, value, 0) < 0) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
- "variable '%s'", name);
- return -1;
- }
-
- if (os_strcmp(name, "bssid") != 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);
- }
+ prev_bssid_set = ssid->bssid_set;
+ prev_disabled = ssid->disabled;
+ os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
+ ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
+ value);
+ if (ret == 0 &&
+ (ssid->bssid_set != prev_bssid_set ||
+ os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
+ wpas_notify_network_bssid_set_changed(wpa_s, ssid);
- if ((os_strcmp(name, "psk") == 0 &&
- value[0] == '"' && ssid->ssid_len) ||
- (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
- wpa_config_update_psk(ssid);
- else if (os_strcmp(name, "priority") == 0)
- wpa_config_update_prio_list(wpa_s->conf);
+ if (prev_disabled != ssid->disabled &&
+ (prev_disabled == 2 || ssid->disabled == 2))
+ wpas_notify_network_type_changed(wpa_s, ssid);
- return 0;
+ return ret;
}
@@ -2306,6 +3034,59 @@ static int wpa_supplicant_ctrl_iface_get_network(
}
+static int wpa_supplicant_ctrl_iface_dup_network(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct wpa_ssid *ssid_s, *ssid_d;
+ char *name, *id, *value;
+ int id_s, id_d, ret;
+
+ /* cmd: "<src network id> <dst network id> <variable name>" */
+ id = os_strchr(cmd, ' ');
+ if (id == NULL)
+ return -1;
+ *id++ = '\0';
+
+ name = os_strchr(id, ' ');
+ if (name == NULL)
+ return -1;
+ *name++ = '\0';
+
+ id_s = atoi(cmd);
+ id_d = atoi(id);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: DUP_NETWORK id=%d -> %d name='%s'",
+ id_s, id_d, name);
+
+ ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
+ if (ssid_s == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+ "network id=%d", id_s);
+ return -1;
+ }
+
+ ssid_d = wpa_config_get_network(wpa_s->conf, id_d);
+ if (ssid_d == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+ "network id=%d", id_d);
+ return -1;
+ }
+
+ value = wpa_config_get(ssid_s, name);
+ if (value == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
+ "variable '%s'", name);
+ return -1;
+ }
+
+ ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid_d, name,
+ value);
+
+ os_free(value);
+
+ return ret;
+}
+
+
static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
@@ -2317,7 +3098,7 @@ static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
end = buf + buflen;
ret = os_snprintf(pos, end - pos,
"cred id / realm / username / domain / imsi\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2326,9 +3107,9 @@ static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
cred->id, cred->realm ? cred->realm : "",
cred->username ? cred->username : "",
- cred->domain ? cred->domain : "",
+ cred->domain ? cred->domain[0] : "",
cred->imsi ? cred->imsi : "");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2351,8 +3132,10 @@ static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
if (cred == NULL)
return -1;
+ wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
+
ret = os_snprintf(buf, buflen, "%d\n", cred->id);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -2363,19 +3146,32 @@ static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
{
struct wpa_ssid *ssid;
char str[20];
+ int id;
- if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+ if (cred == NULL) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
return -1;
}
+ id = cred->id;
+ if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+ return -1;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
+
/* Remove any network entry created based on the removed credential */
ssid = wpa_s->conf->ssid;
while (ssid) {
if (ssid->parent_cred == cred) {
+ int res;
+
wpa_printf(MSG_DEBUG, "Remove network id %d since it "
"used the removed credential", ssid->id);
- os_snprintf(str, sizeof(str), "%d", ssid->id);
+ res = os_snprintf(str, sizeof(str), "%d", ssid->id);
+ if (os_snprintf_error(sizeof(str), res))
+ str[sizeof(str) - 1] = '\0';
ssid = ssid->next;
wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
} else
@@ -2392,7 +3188,8 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
int id;
struct wpa_cred *cred, *prev;
- /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
+ /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
+ * "provisioning_sp=<FQDN> */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
cred = wpa_s->conf->cred;
@@ -2411,8 +3208,29 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
while (cred) {
prev = cred;
cred = cred->next;
- if (prev->domain &&
- os_strcmp(prev->domain, cmd + 8) == 0)
+ if (prev->domain) {
+ size_t i;
+ for (i = 0; i < prev->num_domain; i++) {
+ if (os_strcmp(prev->domain[i], cmd + 8)
+ != 0)
+ continue;
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ break;
+ }
+ }
+ }
+ return 0;
+ }
+
+ if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
+ cmd + 16);
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ if (prev->provisioning_sp &&
+ os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
wpas_ctrl_remove_cred(wpa_s, prev);
}
return 0;
@@ -2463,10 +3281,57 @@ static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
return -1;
}
+ wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name);
+
return 0;
}
+static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
+{
+ int id;
+ size_t res;
+ struct wpa_cred *cred;
+ char *name, *value;
+
+ /* cmd: "<cred id> <variable name>" */
+ name = os_strchr(cmd, ' ');
+ if (name == NULL)
+ return -1;
+ *name++ = '\0';
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'",
+ id, name);
+
+ cred = wpa_config_get_cred(wpa_s->conf, id);
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+ id);
+ return -1;
+ }
+
+ value = wpa_config_get_cred_no_key(cred, name);
+ if (value == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'",
+ name);
+ return -1;
+ }
+
+ res = os_strlcpy(buf, value, buflen);
+ if (res >= buflen) {
+ os_free(value);
+ return -1;
+ }
+
+ os_free(value);
+
+ return res;
+}
+
+
#ifndef CONFIG_NO_CONFIG_WRITE
static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
{
@@ -2492,13 +3357,39 @@ static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_NO_CONFIG_WRITE */
+struct cipher_info {
+ unsigned int capa;
+ const char *name;
+ int group_only;
+};
+
+static const struct cipher_info ciphers[] = {
+ { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
+ { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
+ { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
+ { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
+ { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
+ { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+ { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
+ { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+};
+
+static const struct cipher_info ciphers_group_mgmt[] = {
+ { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
+ { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
+ { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
+ { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
+};
+
+
static int ctrl_iface_get_capability_pairwise(int res, char *strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
char *pos, *end;
size_t len;
+ unsigned int i;
pos = buf;
end = pos + buflen;
@@ -2512,36 +3403,15 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
return len;
}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
+ for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+ if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ pos == buf ? "" : " ",
+ ciphers[i].name);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
}
return pos - buf;
@@ -2552,9 +3422,10 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
char *pos, *end;
size_t len;
+ unsigned int i;
pos = buf;
end = pos + buflen;
@@ -2568,45 +3439,44 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
return len;
}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
+ for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+ if (capa->enc & ciphers[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ pos == buf ? "" : " ",
+ ciphers[i].name);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
+ return pos - buf;
+}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
- if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
+static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
+ struct wpa_driver_capa *capa,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+ unsigned int i;
- if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
+ pos = buf;
+ end = pos + buflen;
+
+ if (res < 0)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
+ if (capa->enc & ciphers_group_mgmt[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ pos == buf ? "" : " ",
+ ciphers_group_mgmt[i].name);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
}
return pos - buf;
@@ -2635,14 +3505,14 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
}
ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
ret = os_snprintf(pos, end - pos, " WPA-EAP");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -2650,18 +3520,35 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
ret = os_snprintf(pos, end - pos, " WPA-PSK");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
ret = os_snprintf(pos, end - pos, " WPA-NONE");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_SUITEB
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB192 */
+
return pos - buf;
}
@@ -2670,7 +3557,7 @@ static int ctrl_iface_get_capability_proto(int res, char *strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
char *pos, *end;
size_t len;
@@ -2688,31 +3575,32 @@ static int ctrl_iface_get_capability_proto(int res, char *strict,
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sRSN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- first = 0;
}
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sWPA",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- first = 0;
}
return pos - buf;
}
-static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
+static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
+ int res, char *strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
char *pos, *end;
size_t len;
@@ -2729,30 +3617,89 @@ static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
}
if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
- ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sOPEN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- first = 0;
}
if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
ret = os_snprintf(pos, end - pos, "%sSHARED",
- first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- first = 0;
}
if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
- ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ ret = os_snprintf(pos, end - pos, "%sLEAP",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+#ifdef CONFIG_SAE
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+
+ return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_modes(int res, char *strict,
+ struct wpa_driver_capa *capa,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+ size_t len;
+
+ pos = buf;
+ end = pos + buflen;
+
+ if (res < 0) {
+ if (strict)
+ return 0;
+ len = os_strlcpy(buf, "IBSS AP", buflen);
+ if (len >= buflen)
+ return -1;
+ return len;
+ }
+
+ if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
+ ret = os_snprintf(pos, end - pos, "%sIBSS",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- first = 0;
}
+ if (capa->flags & WPA_DRIVER_FLAGS_AP) {
+ ret = os_snprintf(pos, end - pos, "%sAP",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+#ifdef CONFIG_MESH
+ if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
+ ret = os_snprintf(pos, end - pos, "%sMESH",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_MESH */
+
return pos - buf;
}
@@ -2785,7 +3732,7 @@ static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
continue;
}
ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
chnl = wpa_s->hw.modes[j].channels;
@@ -2793,12 +3740,69 @@ static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct hostapd_channel_data *chnl;
+ int ret, i, j;
+ char *pos, *end, *hmode;
+
+ pos = buf;
+ end = pos + buflen;
+
+ for (j = 0; j < wpa_s->hw.num_modes; j++) {
+ switch (wpa_s->hw.modes[j].mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ hmode = "B";
+ break;
+ case HOSTAPD_MODE_IEEE80211G:
+ hmode = "G";
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ hmode = "A";
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ hmode = "AD";
+ break;
+ default:
+ continue;
+ }
+ ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
+ hmode);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ chnl = wpa_s->hw.modes[j].channels;
+ for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+ if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
+ chnl[i].chan, chnl[i].freq,
+ chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
+ " (NO_IR)" : "",
+ chnl[i].flag & HOSTAPD_CHAN_RADAR ?
+ " (DFS)" : "");
+
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -2845,6 +3849,10 @@ static int wpa_supplicant_ctrl_iface_get_capability(
return ctrl_iface_get_capability_group(res, strict, &capa,
buf, buflen);
+ if (os_strcmp(field, "group_mgmt") == 0)
+ return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
+ buf, buflen);
+
if (os_strcmp(field, "key_mgmt") == 0)
return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
buf, buflen);
@@ -2854,12 +3862,33 @@ static int wpa_supplicant_ctrl_iface_get_capability(
buf, buflen);
if (os_strcmp(field, "auth_alg") == 0)
- return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
- buf, buflen);
+ return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
+ &capa, buf, buflen);
+
+ if (os_strcmp(field, "modes") == 0)
+ return ctrl_iface_get_capability_modes(res, strict, &capa,
+ buf, buflen);
if (os_strcmp(field, "channels") == 0)
return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
+ if (os_strcmp(field, "freq") == 0)
+ return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
+
+#ifdef CONFIG_TDLS
+ if (os_strcmp(field, "tdls") == 0)
+ return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
+#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_ERP
+ if (os_strcmp(field, "erp") == 0) {
+ res = os_snprintf(buf, buflen, "ERP");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_EPR */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -2880,20 +3909,20 @@ static char * anqp_add_hex(char *pos, char *end, const char *title,
return start;
ret = os_snprintf(pos, end - pos, "%s=", title);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return start;
pos += ret;
d = wpabuf_head_u8(data);
for (i = 0; i < wpabuf_len(data); i++) {
ret = os_snprintf(pos, end - pos, "%02x", *d++);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return start;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return start;
pos += ret;
@@ -2915,7 +3944,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_ID) {
ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -2923,14 +3952,14 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_BSSID) {
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
MAC2STR(bss->bssid));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_FREQ) {
ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -2938,7 +3967,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_BEACON_INT) {
ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
bss->beacon_int);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -2946,28 +3975,28 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_CAPABILITIES) {
ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
bss->caps);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_QUAL) {
ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_NOISE) {
ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_LEVEL) {
ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -2975,45 +4004,45 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_TSF) {
ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
(unsigned long long) bss->tsf);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_AGE) {
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
ret = os_snprintf(pos, end - pos, "age=%d\n",
(int) (now.sec - bss->last_update.sec));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_IE) {
ret = os_snprintf(pos, end - pos, "ie=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
ie = (const u8 *) (bss + 1);
for (i = 0; i < bss->ie_len; i++) {
ret = os_snprintf(pos, end - pos, "%02x", *ie++);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_FLAGS) {
ret = os_snprintf(pos, end - pos, "flags=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
@@ -3028,39 +4057,66 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
ret = os_snprintf(pos, end - pos, "[WEP]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
- if (bss->caps & IEEE80211_CAP_IBSS) {
- ret = os_snprintf(pos, end - pos, "[IBSS]");
- if (ret < 0 || ret >= end - pos)
+ if (bss_is_dmg(bss)) {
+ const char *s;
+ ret = os_snprintf(pos, end - pos, "[DMG]");
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
- }
- if (bss->caps & IEEE80211_CAP_ESS) {
- ret = os_snprintf(pos, end - pos, "[ESS]");
- if (ret < 0 || ret >= end - pos)
+ switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
+ case IEEE80211_CAP_DMG_IBSS:
+ s = "[IBSS]";
+ break;
+ case IEEE80211_CAP_DMG_AP:
+ s = "[ESS]";
+ break;
+ case IEEE80211_CAP_DMG_PBSS:
+ s = "[PBSS]";
+ break;
+ default:
+ s = "";
+ break;
+ }
+ ret = os_snprintf(pos, end - pos, "%s", s);
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
+ } else {
+ if (bss->caps & IEEE80211_CAP_IBSS) {
+ ret = os_snprintf(pos, end - pos, "[IBSS]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+ if (bss->caps & IEEE80211_CAP_ESS) {
+ ret = os_snprintf(pos, end - pos, "[ESS]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
}
- if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+ if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+ wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
ret = os_snprintf(pos, end - pos, "[P2P]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
#ifdef CONFIG_HS20
if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
ret = os_snprintf(pos, end - pos, "[HS20]");
- if (ret < 0 || ret >= end - pos)
- return -1;
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
pos += ret;
}
#endif /* CONFIG_HS20 */
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3068,7 +4124,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_SSID) {
ret = os_snprintf(pos, end - pos, "ssid=%s\n",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3101,8 +4157,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
WFD_IE_VENDOR_TYPE);
if (wfd) {
ret = os_snprintf(pos, end - pos, "wfd_subelems=");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ if (os_snprintf_error(end - pos, ret)) {
+ wpabuf_free(wfd);
+ return 0;
+ }
pos += ret;
pos += wpa_snprintf_hex(pos, end - pos,
@@ -3111,8 +4169,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
wpabuf_free(wfd);
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
pos += ret;
}
}
@@ -3121,6 +4179,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;
+ pos = anqp_add_hex(pos, end, "anqp_capability_list",
+ anqp->capability_list);
pos = anqp_add_hex(pos, end, "anqp_venue_name",
anqp->venue_name);
pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
@@ -3135,16 +4195,54 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos = anqp_add_hex(pos, end, "anqp_domain_name",
anqp->domain_name);
#ifdef CONFIG_HS20
+ pos = anqp_add_hex(pos, end, "hs20_capability_list",
+ anqp->hs20_capability_list);
pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
anqp->hs20_operator_friendly_name);
pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
anqp->hs20_wan_metrics);
pos = anqp_add_hex(pos, end, "hs20_connection_capability",
anqp->hs20_connection_capability);
+ pos = anqp_add_hex(pos, end, "hs20_operating_class",
+ anqp->hs20_operating_class);
+ pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
+ anqp->hs20_osu_providers_list);
#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_MESH
+ 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)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_MESH */
+
+ if (mask & WPA_BSS_MASK_SNR) {
+ ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
+ ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
+ bss->est_throughput);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_DELIM) {
+ ret = os_snprintf(pos, end - pos, "====\n");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
return pos - buf;
}
@@ -3160,7 +4258,7 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
struct dl_list *next;
int ret = 0;
int len;
- char *ctmp;
+ char *ctmp, *end = buf + buflen;
unsigned long mask = WPA_BSS_MASK_ALL;
if (os_strncmp(cmd, "RANGE=", 6) == 0) {
@@ -3178,10 +4276,17 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
return 0;
}
- id1 = atoi(cmd + 6);
- bss = wpa_bss_get_id(wpa_s, id1);
- id2 = atoi(ctmp + 1);
- if (id2 == 0)
+ if (*(cmd + 6) == '-')
+ id1 = 0;
+ else
+ id1 = atoi(cmd + 6);
+ ctmp++;
+ if (*ctmp >= '0' && *ctmp <= '9')
+ id2 = atoi(ctmp);
+ else
+ id2 = (unsigned int) -1;
+ bss = wpa_bss_get_id_range(wpa_s, id1, id2);
+ if (id2 == (unsigned int) -1)
bsslast = dl_list_last(&wpa_s->bss_id,
struct wpa_bss,
list_id);
@@ -3203,8 +4308,10 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
}
}
}
- } else if (os_strcmp(cmd, "FIRST") == 0)
+ } else if (os_strncmp(cmd, "FIRST", 5) == 0)
bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
+ else if (os_strncmp(cmd, "LAST", 4) == 0)
+ bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
else if (os_strncmp(cmd, "ID-", 3) == 0) {
i = atoi(cmd + 3);
bss = wpa_bss_get_id(wpa_s, i);
@@ -3257,8 +4364,21 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
ret += len;
buf += len;
buflen -= len;
- if (bss == bsslast)
+ if (bss == bsslast) {
+ if ((mask & WPA_BSS_MASK_DELIM) && len &&
+ (bss == dl_list_last(&wpa_s->bss_id,
+ struct wpa_bss, list_id))) {
+ int res;
+
+ res = os_snprintf(buf - 5, end - buf + 5,
+ "####\n");
+ if (os_snprintf_error(end - buf + 5, res)) {
+ wpa_printf(MSG_DEBUG,
+ "Could not add end delim");
+ }
+ }
break;
+ }
next = bss->list_id.next;
if (next == &wpa_s->bss_id)
break;
@@ -3301,7 +4421,7 @@ static int wpa_supplicant_ctrl_iface_bss_expire_count(
}
-static int wpa_supplicant_ctrl_iface_bss_flush(
+static void wpa_supplicant_ctrl_iface_bss_flush(
struct wpa_supplicant *wpa_s, char *cmd)
{
int flush_age = atoi(cmd);
@@ -3310,10 +4430,10 @@ static int wpa_supplicant_ctrl_iface_bss_flush(
wpa_bss_flush(wpa_s);
else
wpa_bss_flush_by_age(wpa_s, flush_age);
- return 0;
}
+#ifdef CONFIG_TESTING_OPTIONS
static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
@@ -3335,6 +4455,7 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
wpa_sm_drop_sa(wpa_s->wpa);
}
+#endif /* CONFIG_TESTING_OPTIONS */
static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
@@ -3355,7 +4476,13 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+ "configuration known for the target AP");
+ return -1;
+ }
+
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
if (!bss) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
"from BSS table");
@@ -3367,12 +4494,6 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
* allow roaming to other networks
*/
- if (!ssid) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
- "configuration known for the target AP");
- return -1;
- }
-
wpa_s->reassociate = 1;
wpa_supplicant_connect(wpa_s, bss, ssid);
@@ -3387,9 +4508,18 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
unsigned int timeout = atoi(cmd);
enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+ u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
char *pos;
unsigned int search_delay;
+ const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
+ u8 seek_count = 0;
+ int freq = 0;
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "Reject P2P_FIND since interface is disabled");
+ return -1;
+ }
if (os_strstr(cmd, "type=social"))
type = P2P_FIND_ONLY_SOCIAL;
else if (os_strstr(cmd, "type=progressive"))
@@ -3403,6 +4533,14 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
_dev_id = dev_id;
}
+ pos = os_strstr(cmd, "dev_type=");
+ if (pos) {
+ pos += 9;
+ if (wps_dev_type_str2bin(pos, dev_type) < 0)
+ return -1;
+ _dev_type = dev_type;
+ }
+
pos = os_strstr(cmd, "delay=");
if (pos) {
pos += 6;
@@ -3410,8 +4548,181 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
} else
search_delay = wpas_p2p_search_delay(wpa_s);
- return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
- search_delay);
+ /* Must be searched for last, because it adds nul termination */
+ pos = os_strstr(cmd, " seek=");
+ while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
+ char *term;
+
+ term = os_strchr(pos + 1, ' ');
+ _seek[seek_count++] = pos + 6;
+ seek = _seek;
+ pos = os_strstr(pos + 6, " seek=");
+
+ if (term)
+ *term = '\0';
+ }
+ if (seek_count > P2P_MAX_QUERY_HASH) {
+ seek[0] = NULL;
+ seek_count = 1;
+ }
+
+ pos = os_strstr(cmd, "freq=");
+ if (pos) {
+ pos += 5;
+ freq = atoi(pos);
+ if (freq <= 0)
+ return -1;
+ }
+
+ return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
+ _dev_id, search_delay, seek_count, seek, freq);
+}
+
+
+static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
+{
+ struct p2ps_provision *p2ps_prov;
+ char *pos;
+ size_t info_len = 0;
+ char *info = NULL;
+ u8 role = P2PS_SETUP_NONE;
+ long long unsigned val;
+
+ pos = os_strstr(cmd, "info=");
+ if (pos) {
+ pos += 5;
+ info_len = os_strlen(pos);
+
+ if (info_len) {
+ info = os_malloc(info_len + 1);
+ if (info) {
+ info_len = utf8_unescape(pos, info_len,
+ info, info_len + 1);
+ } else
+ info_len = 0;
+ }
+ }
+
+ p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
+ if (p2ps_prov == NULL) {
+ os_free(info);
+ return NULL;
+ }
+
+ if (info) {
+ os_memcpy(p2ps_prov->info, info, info_len);
+ p2ps_prov->info[info_len] = '\0';
+ os_free(info);
+ }
+
+ pos = os_strstr(cmd, "status=");
+ if (pos)
+ p2ps_prov->status = atoi(pos + 7);
+ else
+ p2ps_prov->status = -1;
+
+ pos = os_strstr(cmd, "adv_id=");
+ if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
+ goto invalid_args;
+ p2ps_prov->adv_id = val;
+
+ pos = os_strstr(cmd, "method=");
+ if (pos)
+ p2ps_prov->method = strtol(pos + 7, NULL, 16);
+ else
+ p2ps_prov->method = 0;
+
+ pos = os_strstr(cmd, "session=");
+ if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
+ goto invalid_args;
+ p2ps_prov->session_id = val;
+
+ pos = os_strstr(cmd, "adv_mac=");
+ if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
+ goto invalid_args;
+
+ pos = os_strstr(cmd, "session_mac=");
+ if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
+ goto invalid_args;
+
+ /* force conncap with tstCap (no sanity checks) */
+ pos = os_strstr(cmd, "tstCap=");
+ if (pos) {
+ role = strtol(pos + 7, NULL, 16);
+ } else {
+ pos = os_strstr(cmd, "role=");
+ if (pos) {
+ role = strtol(pos + 5, NULL, 16);
+ if (role != P2PS_SETUP_CLIENT &&
+ role != P2PS_SETUP_GROUP_OWNER)
+ role = P2PS_SETUP_NONE;
+ }
+ }
+ p2ps_prov->role = role;
+
+ return p2ps_prov;
+
+invalid_args:
+ os_free(p2ps_prov);
+ return NULL;
+}
+
+
+static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct p2ps_provision *p2ps_prov;
+ char *pos;
+
+ /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
+
+ wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+
+ p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+ if (!p2ps_prov)
+ return -1;
+
+ if (p2ps_prov->status < 0) {
+ os_free(p2ps_prov);
+ return -1;
+ }
+
+ return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+ p2ps_prov);
+}
+
+
+static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct p2ps_provision *p2ps_prov;
+ char *pos;
+
+ /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
+ * session=<ses_id> mac=<ses_mac> [info=<infodata>]
+ */
+
+ wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+
+ p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+ if (!p2ps_prov)
+ return -1;
+
+ return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+ p2ps_prov);
}
@@ -3431,12 +4742,20 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
int go_intent = -1;
int freq = 0;
int pd;
- int ht40;
+ int ht40, vht;
+
+ if (!wpa_s->global->p2p_init_wpa_s)
+ return -1;
+ if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
+ wpa_s->global->p2p_init_wpa_s->ifname);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ }
- /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+ /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] */
+ * [ht40] [vht] [auto] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -3464,7 +4783,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
- ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ 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;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -3495,6 +4816,8 @@ 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);
@@ -3505,7 +4828,7 @@ 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);
+ ht40, vht);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -3518,7 +4841,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
return -1;
if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
ret = os_snprintf(buf, buflen, "%08d", new_pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -3531,6 +4854,11 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
{
unsigned int timeout = atoi(cmd);
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "Reject P2P_LISTEN since interface is disabled");
+ return -1;
+ }
return wpas_p2p_listen(wpa_s, timeout);
}
@@ -3556,7 +4884,7 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
else if (os_strstr(pos, " auto") != NULL)
use = WPAS_P2P_PD_AUTO;
- return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
+ return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
}
@@ -3609,6 +4937,40 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
} else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
#endif /* CONFIG_WIFI_DISPLAY */
+ } else if (os_strncmp(pos, "asp ", 4) == 0) {
+ char *svc_str;
+ char *svc_info = NULL;
+ u32 id;
+
+ pos += 4;
+ if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
+ return -1;
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
+ return -1;
+
+ svc_str = pos + 1;
+
+ pos = os_strchr(svc_str, ' ');
+
+ if (pos)
+ *pos++ = '\0';
+
+ /* All remaining data is the svc_info string */
+ if (pos && pos[0] && pos[0] != ' ') {
+ len = os_strlen(pos);
+
+ /* Unescape in place */
+ len = utf8_unescape(pos, len, pos, len);
+ if (len > 0xff)
+ return -1;
+
+ svc_info = pos;
+ }
+
+ ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
+ svc_str, svc_info);
} else {
len = os_strlen(pos);
if (len & 1)
@@ -3628,7 +4990,7 @@ static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
if (ref == 0)
return -1;
res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
- if (res < 0 || (unsigned) res >= buflen)
+ if (os_snprintf_error(buflen, res))
return -1;
return res;
}
@@ -3771,6 +5133,106 @@ static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
}
+static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
+ u8 replace, char *cmd)
+{
+ char *pos;
+ char *adv_str;
+ u32 auto_accept, adv_id, svc_state, config_methods;
+ char *svc_info = NULL;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ /* Auto-Accept value is mandatory, and must be one of the
+ * single values (0, 1, 2, 4) */
+ auto_accept = atoi(cmd);
+ switch (auto_accept) {
+ case P2PS_SETUP_NONE: /* No auto-accept */
+ case P2PS_SETUP_NEW:
+ case P2PS_SETUP_CLIENT:
+ case P2PS_SETUP_GROUP_OWNER:
+ break;
+ default:
+ return -1;
+ }
+
+ /* Advertisement ID is mandatory */
+ cmd = pos;
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
+ if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
+ return -1;
+
+ /* Only allow replacements if exist, and adds if not */
+ if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
+ if (!replace)
+ return -1;
+ } else {
+ if (replace)
+ return -1;
+ }
+
+ /* svc_state between 0 - 0xff is mandatory */
+ if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
+ return -1;
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+
+ /* config_methods is mandatory */
+ pos++;
+ if (sscanf(pos, "%x", &config_methods) != 1)
+ return -1;
+
+ if (!(config_methods &
+ (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
+ return -1;
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+
+ pos++;
+ adv_str = pos;
+
+ /* Advertisement string is mandatory */
+ if (!pos[0] || pos[0] == ' ')
+ return -1;
+
+ /* Terminate svc string */
+ pos = os_strchr(pos, ' ');
+ if (pos != NULL)
+ *pos++ = '\0';
+
+ /* Service and Response Information are optional */
+ if (pos && pos[0]) {
+ size_t len;
+
+ /* Note the bare ' included, which cannot exist legally
+ * in unescaped string. */
+ svc_info = os_strstr(pos, "svc_info='");
+
+ if (svc_info) {
+ svc_info += 9;
+ len = os_strlen(svc_info);
+ utf8_unescape(svc_info, len, svc_info, len);
+ }
+ }
+
+ return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
+ (u8) svc_state, (u16) config_methods,
+ svc_info);
+}
+
+
static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos;
@@ -3784,6 +5246,8 @@ static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
return p2p_ctrl_service_add_bonjour(wpa_s, pos);
if (os_strcmp(cmd, "upnp") == 0)
return p2p_ctrl_service_add_upnp(wpa_s, pos);
+ if (os_strcmp(cmd, "asp") == 0)
+ return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
return -1;
}
@@ -3831,6 +5295,17 @@ static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
}
+static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u32 adv_id;
+
+ if (sscanf(cmd, "%x", &adv_id) != 1)
+ return -1;
+
+ return wpas_p2p_service_del_asp(wpa_s, adv_id);
+}
+
+
static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos;
@@ -3844,6 +5319,25 @@ static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
return p2p_ctrl_service_del_bonjour(wpa_s, pos);
if (os_strcmp(cmd, "upnp") == 0)
return p2p_ctrl_service_del_upnp(wpa_s, pos);
+ if (os_strcmp(cmd, "asp") == 0)
+ return p2p_ctrl_service_del_asp(wpa_s, pos);
+ wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+ return -1;
+}
+
+
+static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "asp") == 0)
+ return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
+
wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
return -1;
}
@@ -3868,8 +5362,8 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
int id;
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
- int freq = 0;
- int ht40;
+ int freq = 0, pref_freq = 0;
+ int ht40, vht;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -3895,9 +5389,20 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
}
- ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ pos = os_strstr(cmd, " pref=");
+ if (pos) {
+ pos += 6;
+ pref_freq = atoi(pos);
+ if (pref_freq <= 0)
+ return -1;
+ }
+
+ 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;
- return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
+ pref_freq);
}
@@ -3944,7 +5449,8 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- char *cmd, int freq, int ht40)
+ char *cmd, int freq, int ht40,
+ int vht)
{
int id;
struct wpa_ssid *ssid;
@@ -3958,31 +5464,34 @@ 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, ht40);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
+ NULL, 0);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
- int freq = 0, ht40;
+ int freq = 0, ht40, vht;
char *pos;
pos = os_strstr(cmd, "freq=");
if (pos)
freq = atoi(pos + 5);
- ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ 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;
if (os_strncmp(cmd, "persistent=", 11) == 0)
return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
- ht40);
+ ht40, vht);
if (os_strcmp(cmd, "persistent") == 0 ||
os_strncmp(cmd, "persistent ", 11) == 0)
- return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+ return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
if (os_strncmp(cmd, "freq=", 5) == 0)
- return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
if (ht40)
- return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
cmd);
@@ -4049,7 +5558,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
info->dev_capab,
info->group_capab,
info->level);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -4060,7 +5569,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
wps_dev_type_bin2str(t, devtype,
sizeof(devtype)));
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -4068,7 +5577,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
if (ssid) {
res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -4078,6 +5587,22 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
return pos - buf;
pos += res;
+ if (info->vendor_elems) {
+ res = os_snprintf(pos, end - pos, "vendor_elems=");
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ pos += wpa_snprintf_hex(pos, end - pos,
+ wpabuf_head(info->vendor_elems),
+ wpabuf_len(info->vendor_elems));
+
+ res = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+
return pos - buf;
}
@@ -4085,48 +5610,21 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
const char *param)
{
- struct wpa_freq_range *freq = NULL, *n;
- unsigned int count = 0, i;
- const char *pos, *pos2, *pos3;
+ unsigned int i;
if (wpa_s->global->p2p == NULL)
return -1;
- /*
- * param includes comma separated frequency range.
- * For example: 2412-2432,2462,5000-6000
- */
- pos = param;
- while (pos && pos[0]) {
- n = os_realloc_array(freq, count + 1,
- sizeof(struct wpa_freq_range));
- if (n == NULL) {
- os_free(freq);
- return -1;
- }
- freq = n;
- freq[count].min = atoi(pos);
- pos2 = os_strchr(pos, '-');
- pos3 = os_strchr(pos, ',');
- if (pos2 && (!pos3 || pos2 < pos3)) {
- pos2++;
- freq[count].max = atoi(pos2);
- } else
- freq[count].max = freq[count].min;
- pos = pos3;
- if (pos)
- pos++;
- count++;
- }
+ if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
+ return -1;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
+ struct wpa_freq_range *freq;
+ freq = &wpa_s->global->p2p_disallow_freq.range[i];
wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
- freq[i].min, freq[i].max);
+ freq->min, freq->max);
}
- os_free(wpa_s->global->p2p_disallow_freq);
- wpa_s->global->p2p_disallow_freq = freq;
- wpa_s->global->num_p2p_disallow_freq = count;
wpas_p2p_update_channel_list(wpa_s);
return 0;
}
@@ -4157,7 +5655,7 @@ 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));
+ atoi(param), 1);
}
if (os_strcmp(cmd, "ssid_postfix") == 0) {
@@ -4317,6 +5815,21 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
max_disc_int, max_disc_tu);
}
+ if (os_strcmp(cmd, "per_sta_psk") == 0) {
+ wpa_s->global->p2p_per_sta_psk = !!atoi(param);
+ return 0;
+ }
+
+#ifdef CONFIG_WPS_NFC
+ if (os_strcmp(cmd, "nfc_tag") == 0)
+ return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
+#endif /* CONFIG_WPS_NFC */
+
+ if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
+ wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
+ return 0;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
@@ -4324,6 +5837,16 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
}
+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;
+ wpas_p2p_stop_find(wpa_s);
+ if (wpa_s->global->p2p)
+ p2p_flush(wpa_s->global->p2p);
+}
+
+
static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *pos2;
@@ -4373,11 +5896,92 @@ static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
return wpas_p2p_ext_listen(wpa_s, period, interval);
}
+
+static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ u8 peer[ETH_ALEN];
+ int iface_addr = 0;
+
+ pos = cmd;
+ if (os_strncmp(pos, "iface=", 6) == 0) {
+ iface_addr = 1;
+ pos += 6;
+ }
+ if (hwaddr_aton(pos, peer))
+ return -1;
+
+ wpas_p2p_remove_client(wpa_s, peer, iface_addr);
+ return 0;
+}
+
#endif /* CONFIG_P2P */
+static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
+{
+ struct wpa_freq_range_list ranges;
+ int *freqs = NULL;
+ struct hostapd_hw_modes *mode;
+ u16 i;
+
+ if (wpa_s->hw.modes == NULL)
+ return NULL;
+
+ os_memset(&ranges, 0, sizeof(ranges));
+ if (freq_range_list_parse(&ranges, val) < 0)
+ return NULL;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ int j;
+
+ mode = &wpa_s->hw.modes[i];
+ for (j = 0; j < mode->num_channels; j++) {
+ unsigned int freq;
+
+ if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ freq = mode->channels[j].freq;
+ if (!freq_range_list_includes(&ranges, freq))
+ continue;
+
+ int_array_add_unique(&freqs, freq);
+ }
+ }
+
+ os_free(ranges.range);
+ return freqs;
+}
+
+
#ifdef CONFIG_INTERWORKING
-static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+
+static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
+{
+ int auto_sel = 0;
+ int *freqs = NULL;
+
+ if (param) {
+ char *pos;
+
+ auto_sel = os_strstr(param, "auto") != NULL;
+
+ pos = os_strstr(param, "freq=");
+ if (pos) {
+ freqs = freq_range_to_channel_list(wpa_s, pos + 5);
+ if (freqs == NULL)
+ return -1;
+ }
+
+ }
+
+ return interworking_select(wpa_s, auto_sel, freqs);
+}
+
+
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
+ int only_add)
{
u8 bssid[ETH_ALEN];
struct wpa_bss *bss;
@@ -4394,7 +5998,28 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
return -1;
}
- return interworking_connect(wpa_s, bss);
+ if (bss->ssid_len == 0) {
+ int found = 0;
+
+ wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
+ " does not have SSID information", MAC2STR(bssid));
+
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
+ list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+ bss->ssid_len > 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+ wpa_printf(MSG_DEBUG,
+ "Found another matching BSS entry with SSID");
+ }
+
+ return interworking_connect(wpa_s, bss, only_add);
}
@@ -4406,15 +6031,29 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
#define MAX_ANQP_INFO_ID 100
u16 id[MAX_ANQP_INFO_ID];
size_t num_id = 0;
+ u32 subtypes = 0;
used = hwaddr_aton2(dst, dst_addr);
if (used < 0)
return -1;
pos = dst + used;
+ if (*pos == ' ')
+ pos++;
while (num_id < MAX_ANQP_INFO_ID) {
- id[num_id] = atoi(pos);
- if (id[num_id])
- num_id++;
+ if (os_strncmp(pos, "hs20:", 5) == 0) {
+#ifdef CONFIG_HS20
+ int num = atoi(pos + 5);
+ if (num <= 0 || num > 31)
+ return -1;
+ subtypes |= BIT(num);
+#else /* CONFIG_HS20 */
+ return -1;
+#endif /* CONFIG_HS20 */
+ } else {
+ id[num_id] = atoi(pos);
+ if (id[num_id])
+ num_id++;
+ }
pos = os_strchr(pos + 1, ',');
if (pos == NULL)
break;
@@ -4424,7 +6063,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (num_id == 0)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id);
+ return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
}
@@ -4500,9 +6139,8 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
int used;
char *pos;
size_t resp_len, start, requested_len;
-
- if (!wpa_s->last_gas_resp)
- return -1;
+ struct wpabuf *resp;
+ int ret;
used = hwaddr_aton2(cmd, addr);
if (used < 0)
@@ -4513,11 +6151,18 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
pos++;
dialog_token = atoi(pos);
- if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
- dialog_token != wpa_s->last_gas_dialog_token)
+ if (wpa_s->last_gas_resp &&
+ os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
+ dialog_token == wpa_s->last_gas_dialog_token)
+ resp = wpa_s->last_gas_resp;
+ else if (wpa_s->prev_gas_resp &&
+ os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
+ dialog_token == wpa_s->prev_gas_dialog_token)
+ resp = wpa_s->prev_gas_resp;
+ else
return -1;
- resp_len = wpabuf_len(wpa_s->last_gas_resp);
+ resp_len = wpabuf_len(resp);
start = 0;
requested_len = resp_len;
@@ -4538,9 +6183,24 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
if (requested_len * 2 + 1 > buflen)
return os_snprintf(buf, buflen, "FAIL-Too long response");
- return wpa_snprintf_hex(buf, buflen,
- wpabuf_head_u8(wpa_s->last_gas_resp) + start,
- requested_len);
+ ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
+ requested_len);
+
+ if (start + requested_len == resp_len) {
+ /*
+ * Free memory by dropping the response after it has been
+ * fetched.
+ */
+ if (resp == wpa_s->prev_gas_resp) {
+ wpabuf_free(wpa_s->prev_gas_resp);
+ wpa_s->prev_gas_resp = NULL;
+ } else {
+ wpabuf_free(wpa_s->last_gas_resp);
+ wpa_s->last_gas_resp = NULL;
+ }
+ }
+
+ return ret;
}
#endif /* CONFIG_INTERWORKING */
@@ -4558,6 +6218,8 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (used < 0)
return -1;
pos = dst + used;
+ if (*pos == ' ')
+ pos++;
for (;;) {
int num = atoi(pos);
if (num <= 0 || num > 31)
@@ -4628,7 +6290,7 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
if (len == 0 && cred && cred->realm)
return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
- if (len % 1)
+ if (len & 1)
return -1;
len /= 2;
buf = os_malloc(len);
@@ -4647,16 +6309,28 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
return ret;
}
-#endif /* CONFIG_HS20 */
-
-static int wpa_supplicant_ctrl_iface_sta_autoconnect(
- struct wpa_supplicant *wpa_s, char *cmd)
+static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
{
- wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
- return 0;
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *icon;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ while (cmd[used] == ' ')
+ used++;
+ icon = &cmd[used];
+
+ 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));
}
+#endif /* CONFIG_HS20 */
+
#ifdef CONFIG_AUTOSCAN
@@ -4739,6 +6413,19 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
return ret;
}
+
+static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int query_reason;
+
+ query_reason = atoi(cmd);
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
+ query_reason);
+
+ return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+}
+
#endif /* CONFIG_WNM */
@@ -4747,18 +6434,49 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
{
struct wpa_signal_info si;
int ret;
+ char *pos, *end;
ret = wpa_drv_signal_poll(wpa_s, &si);
if (ret)
return -1;
- ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+ pos = buf;
+ end = buf + buflen;
+
+ ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
"NOISE=%d\nFREQUENCY=%u\n",
si.current_signal, si.current_txrate / 1000,
si.current_noise, si.frequency);
- if (ret < 0 || (unsigned int) ret > buflen)
+ if (os_snprintf_error(end - pos, ret))
return -1;
- return ret;
+ pos += ret;
+
+ if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
+ ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+ channel_width_to_string(si.chanwidth));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ 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 (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (si.avg_signal) {
+ ret = os_snprintf(pos, end - pos,
+ "AVG_RSSI=%d\n", si.avg_signal);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ return pos - buf;
}
@@ -4774,32 +6492,1346 @@ static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
- if (ret < 0 || (size_t) ret > buflen)
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+ return ret;
+}
+
+
+#ifdef ANDROID
+static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+
+ ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+ if (ret == 0) {
+ if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ if (p2p) {
+ char country[3];
+ country[0] = cmd[8];
+ country[1] = cmd[9];
+ country[2] = 0x04;
+ p2p_set_country(p2p, country);
+ }
+ }
+ ret = os_snprintf(buf, buflen, "%s\n", "OK");
+ if (os_snprintf_error(buflen, ret))
+ ret = -1;
+ }
+ return ret;
+}
+#endif /* ANDROID */
+
+
+static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos;
+ u8 *data = NULL;
+ unsigned int vendor_id, subcmd;
+ struct wpabuf *reply;
+ size_t data_len = 0;
+
+ /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+ vendor_id = strtoul(cmd, &pos, 16);
+ if (!isblank(*pos))
+ return -EINVAL;
+
+ subcmd = strtoul(pos, &pos, 10);
+
+ if (*pos != '\0') {
+ if (!isblank(*pos++))
+ return -EINVAL;
+ data_len = os_strlen(pos);
+ }
+
+ if (data_len) {
+ data_len /= 2;
+ data = os_malloc(data_len);
+ if (!data)
+ return -1;
+
+ if (hexstr2bin(pos, data, data_len)) {
+ wpa_printf(MSG_DEBUG,
+ "Vendor command: wrong parameter format");
+ os_free(data);
+ return -EINVAL;
+ }
+ }
+
+ reply = wpabuf_alloc((buflen - 1) / 2);
+ if (!reply) {
+ os_free(data);
+ return -1;
+ }
+
+ ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
+ reply);
+
+ if (ret == 0)
+ ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
+ wpabuf_len(reply));
+
+ wpabuf_free(reply);
+ os_free(data);
+
+ return ret;
+}
+
+
+static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
+ wpa_s->global->p2p_init_wpa_s : wpa_s;
+#endif /* CONFIG_P2P */
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+
+#ifdef CONFIG_P2P
+ 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;
+ p2p_wpa_s->conf->num_sec_device_types = 0;
+ p2p_wpa_s->p2p_disable_ip_addr_req = 0;
+ os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
+ p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
+ p2p_wpa_s->global->pending_p2ps_group = 0;
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS_TESTING
+ wps_version_number = 0x20;
+ wps_testing_dummy_cred = 0;
+ wps_corrupt_pkhash = 0;
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_WPS
+ wpa_s->wps_fragment_size = 0;
+ wpas_wps_cancel(wpa_s);
+ wps_registrar_flush(wpa_s->wps->registrar);
+#endif /* CONFIG_WPS */
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+
+#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);
+ wpa_tdls_enable(wpa_s->wpa, 1);
+#endif /* CONFIG_TDLS */
+
+ eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+ wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+
+ wpa_s->no_keep_alive = 0;
+ wpa_s->own_disconnect_req = 0;
+
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = NULL;
+ wpa_s->disallow_aps_bssid_count = 0;
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = NULL;
+ wpa_s->disallow_aps_ssid_count = 0;
+
+ wpa_s->set_sta_uapsd = 0;
+ wpa_s->sta_uapsd = 0;
+
+ wpa_drv_radio_disable(wpa_s, 0);
+ wpa_blacklist_clear(wpa_s);
+ wpa_s->extra_blacklist_count = 0;
+ wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
+ wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+ wpa_config_flush_blobs(wpa_s->conf);
+ wpa_s->conf->auto_interworking = 0;
+ wpa_s->conf->okc = 0;
+
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+ rsn_preauth_deinit(wpa_s->wpa);
+
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
+ wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
+ eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+
+ radio_remove_works(wpa_s, NULL, 1);
+ wpa_s->ext_work_in_progress = 0;
+
+ wpa_s->next_ssid = NULL;
+
+#ifdef CONFIG_INTERWORKING
+ hs20_cancel_fetch_osu(wpa_s);
+#endif /* CONFIG_INTERWORKING */
+
+ wpa_s->ext_mgmt_frame_handling = 0;
+ wpa_s->ext_eapol_frame_io = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_s->extra_roc_dur = 0;
+ wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_s->disconnected = 0;
+ os_free(wpa_s->next_scan_freqs);
+ wpa_s->next_scan_freqs = NULL;
+
+ wpa_bss_flush(wpa_s);
+ if (!dl_list_empty(&wpa_s->bss)) {
+ wpa_printf(MSG_DEBUG,
+ "BSS table not empty after flush: %u entries, current_bss=%p bssid="
+ MACSTR " pending_bssid=" MACSTR,
+ dl_list_len(&wpa_s->bss), wpa_s->current_bss,
+ MAC2STR(wpa_s->bssid),
+ MAC2STR(wpa_s->pending_bssid));
+ }
+}
+
+
+static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct wpa_radio_work *work;
+ char *pos, *end;
+ struct os_reltime now, diff;
+
+ pos = buf;
+ end = buf + buflen;
+
+ os_get_reltime(&now);
+
+ dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+ {
+ int ret;
+
+ os_reltime_sub(&now, &work->time, &diff);
+ ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
+ work->type, work->wpa_s->ifname, work->freq,
+ work->started, diff.sec, diff.usec);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
+static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_radio_work *work = eloop_ctx;
+ struct wpa_external_work *ework = work->ctx;
+
+ wpa_dbg(work->wpa_s, MSG_DEBUG,
+ "Timing out external radio work %u (%s)",
+ ework->id, work->type);
+ wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
+ work->wpa_s->ext_work_in_progress = 0;
+ radio_work_done(work);
+ os_free(ework);
+}
+
+
+static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_external_work *ework = work->ctx;
+
+ if (deinit) {
+ if (work->started)
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
+ work, NULL);
+
+ os_free(ework);
+ return;
+ }
+
+ wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
+ ework->id, ework->type);
+ wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
+ work->wpa_s->ext_work_in_progress = 1;
+ if (!ework->timeout)
+ ework->timeout = 10;
+ eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
+ work, NULL);
+}
+
+
+static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ struct wpa_external_work *ework;
+ char *pos, *pos2;
+ size_t type_len;
+ int ret;
+ unsigned int freq = 0;
+
+ /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
+
+ ework = os_zalloc(sizeof(*ework));
+ if (ework == NULL)
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos) {
+ type_len = pos - cmd;
+ pos++;
+
+ pos2 = os_strstr(pos, "freq=");
+ if (pos2)
+ freq = atoi(pos2 + 5);
+
+ pos2 = os_strstr(pos, "timeout=");
+ if (pos2)
+ ework->timeout = atoi(pos2 + 8);
+ } else {
+ type_len = os_strlen(cmd);
+ }
+ if (4 + type_len >= sizeof(ework->type))
+ type_len = sizeof(ework->type) - 4 - 1;
+ os_strlcpy(ework->type, "ext:", sizeof(ework->type));
+ os_memcpy(ework->type + 4, cmd, type_len);
+ ework->type[4 + type_len] = '\0';
+
+ wpa_s->ext_work_id++;
+ if (wpa_s->ext_work_id == 0)
+ wpa_s->ext_work_id++;
+ ework->id = wpa_s->ext_work_id;
+
+ if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
+ ework) < 0) {
+ os_free(ework);
+ return -1;
+ }
+
+ ret = os_snprintf(buf, buflen, "%u", ework->id);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+ return ret;
+}
+
+
+static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct wpa_radio_work *work;
+ unsigned int id = atoi(cmd);
+
+ dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+ {
+ struct wpa_external_work *ework;
+
+ if (os_strncmp(work->type, "ext:", 4) != 0)
+ continue;
+ ework = work->ctx;
+ if (id && ework->id != id)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Completed external radio work %u (%s)",
+ ework->id, ework->type);
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
+ wpa_s->ext_work_in_progress = 0;
+ radio_work_done(work);
+ os_free(ework);
+ return 3; /* "OK\n" */
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ if (os_strcmp(cmd, "show") == 0)
+ return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
+ if (os_strncmp(cmd, "add ", 4) == 0)
+ return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
+ if (os_strncmp(cmd, "done ", 5) == 0)
+ return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
+ return -1;
+}
+
+
+void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio_work *work, *tmp;
+
+ if (!wpa_s || !wpa_s->radio)
+ return;
+
+ dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
+ struct wpa_radio_work, list) {
+ struct wpa_external_work *ework;
+
+ if (os_strncmp(work->type, "ext:", 4) != 0)
+ continue;
+ ework = work->ctx;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Flushing%s external radio work %u (%s)",
+ work->started ? " started" : "", ework->id,
+ ework->type);
+ if (work->started)
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
+ work, NULL);
+ radio_work_done(work);
+ os_free(ework);
+ }
+}
+
+
+static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
+static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
+ unsigned int *scan_id_count, int scan_id[])
+{
+ const char *pos = value;
+
+ while (pos) {
+ if (*pos == ' ' || *pos == '\0')
+ break;
+ if (*scan_id_count == MAX_SCAN_ID)
+ return -1;
+ scan_id[(*scan_id_count)++] = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos)
+ pos++;
+ }
+
+ return 0;
+}
+
+
+static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
+ char *reply, int reply_size, int *reply_len)
+{
+ char *pos;
+ unsigned int manual_scan_passive = 0;
+ unsigned int manual_scan_use_id = 0;
+ unsigned int manual_scan_only_new = 0;
+ unsigned int scan_only = 0;
+ unsigned int scan_id_count = 0;
+ int scan_id[MAX_SCAN_ID];
+ void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+ int *manual_scan_freqs = NULL;
+
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ *reply_len = -1;
+ return;
+ }
+
+ if (radio_work_pending(wpa_s, "scan")) {
+ wpa_printf(MSG_DEBUG,
+ "Pending scan scheduled - reject new request");
+ *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+ return;
+ }
+
+ if (params) {
+ if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
+ scan_only = 1;
+
+ pos = os_strstr(params, "freq=");
+ if (pos) {
+ manual_scan_freqs = freq_range_to_channel_list(wpa_s,
+ pos + 5);
+ if (manual_scan_freqs == NULL) {
+ *reply_len = -1;
+ goto done;
+ }
+ }
+
+ pos = os_strstr(params, "passive=");
+ if (pos)
+ manual_scan_passive = !!atoi(pos + 8);
+
+ pos = os_strstr(params, "use_id=");
+ if (pos)
+ manual_scan_use_id = atoi(pos + 7);
+
+ pos = os_strstr(params, "only_new=1");
+ if (pos)
+ manual_scan_only_new = 1;
+
+ pos = os_strstr(params, "scan_id=");
+ if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
+ scan_id) < 0) {
+ *reply_len = -1;
+ goto done;
+ }
+ }
+
+ if (scan_only)
+ scan_res_handler = scan_only_handler;
+ else if (wpa_s->scan_res_handler == scan_only_handler)
+ scan_res_handler = NULL;
+ else
+ scan_res_handler = wpa_s->scan_res_handler;
+
+ if (!wpa_s->sched_scanning && !wpa_s->scanning &&
+ ((wpa_s->wpa_state <= WPA_SCANNING) ||
+ (wpa_s->wpa_state == WPA_COMPLETED))) {
+ wpa_s->manual_scan_passive = manual_scan_passive;
+ wpa_s->manual_scan_use_id = manual_scan_use_id;
+ wpa_s->manual_scan_only_new = manual_scan_only_new;
+ wpa_s->scan_id_count = scan_id_count;
+ os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
+ wpa_s->scan_res_handler = scan_res_handler;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = manual_scan_freqs;
+ manual_scan_freqs = NULL;
+
+ wpa_s->normal_scans = 0;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->manual_scan_use_id) {
+ wpa_s->manual_scan_id++;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+ wpa_s->manual_scan_id);
+ *reply_len = os_snprintf(reply, reply_size, "%u\n",
+ wpa_s->manual_scan_id);
+ }
+ } else if (wpa_s->sched_scanning) {
+ wpa_s->manual_scan_passive = manual_scan_passive;
+ wpa_s->manual_scan_use_id = manual_scan_use_id;
+ wpa_s->manual_scan_only_new = manual_scan_only_new;
+ wpa_s->scan_id_count = scan_id_count;
+ os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
+ wpa_s->scan_res_handler = scan_res_handler;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = manual_scan_freqs;
+ manual_scan_freqs = NULL;
+
+ wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->manual_scan_use_id) {
+ wpa_s->manual_scan_id++;
+ *reply_len = os_snprintf(reply, reply_size, "%u\n",
+ wpa_s->manual_scan_id);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+ wpa_s->manual_scan_id);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
+ *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+ }
+
+done:
+ os_free(manual_scan_freqs);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+static void wpas_ctrl_iface_mgmt_tx_cb(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_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
+ " src=" MACSTR " bssid=" MACSTR " result=%s",
+ freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
+ "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
+ "NO_ACK" : "FAILED"));
+}
+
+
+static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
+ int res, used;
+ int freq = 0, no_cck = 0, wait_time = 0;
+
+ /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
+ * <action=Action frame payload> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, da);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+ used = hwaddr_aton2(pos, bssid);
+ if (used < 0)
+ return -1;
+ pos += used;
+
+ param = os_strstr(pos, " freq=");
+ if (param) {
+ param += 6;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " no_cck=");
+ if (param) {
+ param += 8;
+ no_cck = atoi(param);
+ }
+
+ param = os_strstr(pos, " wait_time=");
+ if (param) {
+ param += 11;
+ wait_time = atoi(param);
+ }
+
+ param = os_strstr(pos, " action=");
+ if (param == NULL)
+ return -1;
+ param += 8;
+
+ 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;
+ }
+
+ res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
+ buf, len, wait_time,
+ wpas_ctrl_iface_mgmt_tx_cb, no_cck);
+ os_free(buf);
+ return res;
+}
+
+
+static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
+ offchannel_send_action_done(wpa_s);
+}
+
+
+static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos, *param;
+ union wpa_event_data event;
+ enum wpa_event_type ev;
+
+ /* <event name> [parameters..] */
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd);
+
+ pos = cmd;
+ param = os_strchr(pos, ' ');
+ if (param)
+ *param++ = '\0';
+
+ os_memset(&event, 0, sizeof(event));
+
+ if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) {
+ ev = EVENT_INTERFACE_ENABLED;
+ } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
+ ev = EVENT_INTERFACE_DISABLED;
+ } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
+ ev = EVENT_AVOID_FREQUENCIES;
+ if (param == NULL)
+ param = "";
+ if (freq_range_list_parse(&event.freq_range, param) < 0)
+ return -1;
+ wpa_supplicant_event(wpa_s, ev, &event);
+ os_free(event.freq_range.range);
+ return 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
+ cmd);
+ return -1;
+ }
+
+ wpa_supplicant_event(wpa_s, ev, &event);
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ u8 src[ETH_ALEN], *buf;
+ int used;
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
+ os_free(buf);
+
+ return 0;
+}
+
+
+static u16 ipv4_hdr_checksum(const void *buf, size_t len)
+{
+ size_t i;
+ u32 sum = 0;
+ const u16 *pos = buf;
+
+ for (i = 0; i < len / 2; i++)
+ sum += *pos++;
+
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return sum ^ 0xffff;
+}
+
+
+#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)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const struct ether_header *eth;
+ const struct iphdr *ip;
+ const u8 *pos;
+ unsigned int i;
+
+ if (len != HWSIM_PACKETLEN)
+ return;
+
+ eth = (const struct ether_header *) buf;
+ ip = (const struct iphdr *) (eth + 1);
+ pos = (const u8 *) (ip + 1);
+
+ if (ip->ihl != 5 || ip->version != 4 ||
+ ntohs(ip->tot_len) != HWSIM_IP_LEN)
+ return;
+
+ for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+ if (*pos != (u8) i)
+ return;
+ pos++;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+}
+
+
+static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int enabled = atoi(cmd);
+
+ if (!enabled) {
+ if (wpa_s->l2_test) {
+ l2_packet_deinit(wpa_s->l2_test);
+ wpa_s->l2_test = NULL;
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
+ }
+ return 0;
+ }
+
+ if (wpa_s->l2_test)
+ return 0;
+
+ wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
+ ETHERTYPE_IP, wpas_data_test_rx,
+ wpa_s, 1);
+ if (wpa_s->l2_test == NULL)
+ return -1;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst[ETH_ALEN], src[ETH_ALEN];
+ char *pos;
+ int used;
+ long int val;
+ u8 tos;
+ u8 buf[HWSIM_PACKETLEN];
+ struct ether_header *eth;
+ struct iphdr *ip;
+ u8 *dpos;
+ unsigned int i;
+
+ if (wpa_s->l2_test == NULL)
+ return -1;
+
+ /* format: <dst> <src> <tos> */
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, dst);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+
+ val = strtol(pos, NULL, 0);
+ if (val < 0 || val > 0xff)
+ return -1;
+ tos = val;
+
+ eth = (struct ether_header *) buf;
+ os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
+ os_memcpy(eth->ether_shost, src, ETH_ALEN);
+ eth->ether_type = htons(ETHERTYPE_IP);
+ ip = (struct iphdr *) (eth + 1);
+ os_memset(ip, 0, sizeof(*ip));
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->ttl = 64;
+ ip->tos = tos;
+ ip->tot_len = htons(HWSIM_IP_LEN);
+ ip->protocol = 1;
+ ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->daddr = htonl(192 << 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++)
+ *dpos++ = i;
+
+ if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, buf,
+ HWSIM_PACKETLEN) < 0)
+ return -1;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
+ " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ u8 *buf;
+ struct ether_header *eth;
+ struct l2_packet_data *l2 = NULL;
+ size_t len;
+ u16 ethertype;
+ int res = -1;
+
+ len = os_strlen(cmd);
+ if (len & 1 || len < ETH_HLEN * 2)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
return -1;
+
+ if (hexstr2bin(cmd, buf, len) < 0)
+ goto done;
+
+ eth = (struct ether_header *) buf;
+ ethertype = ntohs(eth->ether_type);
+
+ l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
+ wpas_data_test_rx, wpa_s, 1);
+ if (l2 == NULL)
+ goto done;
+
+ res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
+done:
+ if (l2)
+ l2_packet_deinit(l2);
+ os_free(buf);
+
+ return res < 0 ? -1 : 0;
+}
+
+
+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);
+ pos = os_strchr(cmd, ':');
+ if (pos) {
+ pos++;
+ os_strlcpy(wpa_trace_fail_func, pos,
+ sizeof(wpa_trace_fail_func));
+ } else {
+ wpa_trace_fail_after = 0;
+ }
+ return 0;
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+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 */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
+{
+ 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;
+
+ 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 */
+}
+
+
+static struct wpa_supplicant *
+wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
+ enum wpa_vendor_elem_frame frame)
+{
+ 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;
+ }
+}
+
+
+static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos = cmd;
+ int frame;
+ size_t len;
+ struct wpabuf *buf;
+ struct ieee802_11_elems elems;
+
+ frame = atoi(pos);
+ if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
+ return -1;
+ wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ pos++;
+
+ len = os_strlen(pos);
+ if (len == 0)
+ return 0;
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) ==
+ ParseFailed) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ if (wpa_s->vendor_elem[frame] == NULL) {
+ wpa_s->vendor_elem[frame] = buf;
+ wpas_ctrl_vendor_elem_update(wpa_s);
+ return 0;
+ }
+
+ if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
+ wpabuf_free(buf);
+ wpas_ctrl_vendor_elem_update(wpa_s);
+
+ return 0;
+}
+
+
+static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ int frame = atoi(cmd);
+
+ if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
+ return -1;
+ wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+
+ if (wpa_s->vendor_elem[frame] == NULL)
+ return 0;
+
+ return wpa_snprintf_hex(buf, buflen,
+ wpabuf_head_u8(wpa_s->vendor_elem[frame]),
+ wpabuf_len(wpa_s->vendor_elem[frame]));
+}
+
+
+static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos = cmd;
+ int frame;
+ size_t len;
+ u8 *buf;
+ struct ieee802_11_elems elems;
+ u8 *ie, *end;
+
+ frame = atoi(pos);
+ if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
+ return -1;
+ wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ pos++;
+
+ if (*pos == '*') {
+ wpabuf_free(wpa_s->vendor_elem[frame]);
+ wpa_s->vendor_elem[frame] = NULL;
+ wpas_ctrl_vendor_elem_update(wpa_s);
+ return 0;
+ }
+
+ if (wpa_s->vendor_elem[frame] == NULL)
+ return -1;
+
+ len = os_strlen(pos);
+ if (len == 0)
+ return 0;
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) {
+ os_free(buf);
+ 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;
+ }
+
+ os_free(buf);
+
+ return -1;
+}
+
+
+static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ 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 {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+ }
+}
+
+
+static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ struct wpa_ssid ssid;
+ struct wpa_ssid *ssid_p = NULL;
+ int ret = 0;
+
+ if (os_strncmp(cmd, " ssid=", 6) == 0) {
+ ssid.ssid_len = os_strlen(cmd + 6);
+ if (ssid.ssid_len > 32)
+ return -1;
+ ssid.ssid = (u8 *) (cmd + 6);
+ ssid_p = &ssid;
+ }
+
+ ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+ wpas_ctrl_neighbor_rep_cb,
+ wpa_s);
+
return ret;
}
+static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
+{
+ eapol_sm_erp_flush(wpa_s->eapol);
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *token, *context = NULL;
+ unsigned int enable = ~0, type = 0;
+ u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
+ u8 *addr = NULL, *mask = NULL;
+
+ while ((token = str_token(cmd, " ", &context))) {
+ if (os_strcasecmp(token, "scan") == 0) {
+ type |= MAC_ADDR_RAND_SCAN;
+ } else if (os_strcasecmp(token, "sched") == 0) {
+ type |= MAC_ADDR_RAND_SCHED_SCAN;
+ } else if (os_strcasecmp(token, "pno") == 0) {
+ type |= MAC_ADDR_RAND_PNO;
+ } else if (os_strcasecmp(token, "all") == 0) {
+ type = wpa_s->mac_addr_rand_supported;
+ } else if (os_strncasecmp(token, "enable=", 7) == 0) {
+ enable = atoi(token + 7);
+ } else if (os_strncasecmp(token, "addr=", 5) == 0) {
+ addr = _addr;
+ if (hwaddr_aton(token + 5, addr)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid MAC address: %s",
+ token);
+ return -1;
+ }
+ } else if (os_strncasecmp(token, "mask=", 5) == 0) {
+ mask = _mask;
+ if (hwaddr_aton(token + 5, mask)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid MAC address mask: %s",
+ token);
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
+ token);
+ return -1;
+ }
+ }
+
+ if (!type) {
+ wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
+ 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");
+ return -1;
+ }
+
+ if (!enable) {
+ wpas_mac_addr_rand_scan_clear(wpa_s, type);
+ if (wpa_s->pno) {
+ if (type & MAC_ADDR_RAND_PNO) {
+ wpas_stop_pno(wpa_s);
+ wpas_start_pno(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);
+ }
+ return 0;
+ }
+
+ if ((addr && !mask) || (!addr && mask)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
+ return -1;
+ }
+
+ if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+ wpa_printf(MSG_INFO,
+ "CTRL: MAC_RAND_SCAN cannot allow multicast address");
+ return -1;
+ }
+
+ if (type & MAC_ADDR_RAND_SCAN) {
+ wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+ addr, mask);
+ }
+
+ if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+ wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+ addr, mask);
+
+ 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 (type & MAC_ADDR_RAND_PNO) {
+ wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+ addr, mask);
+ if (wpa_s->pno) {
+ wpas_stop_pno(wpa_s);
+ wpas_start_pno(wpa_s);
+ }
+ }
+
+ return 0;
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
char *reply;
const int reply_size = 4096;
- int ctrl_rsp = 0;
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, "WPS_NFC_TAG_READ", 16) == 0 ||
- os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
+ os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+ if (wpa_debug_show_keys)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Control interface command '%s'", buf);
+ else
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Control interface command '%s [REMOVED]'",
+ os_strncmp(buf, WPA_CTRL_RSP,
+ os_strlen(WPA_CTRL_RSP)) == 0 ?
+ WPA_CTRL_RSP : "SET_NETWORK");
+ } 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",
(const u8 *) buf, os_strlen(buf));
} else {
int level = MSG_DEBUG;
if (os_strcmp(buf, "PING") == 0)
level = MSG_EXCESSIVE;
- wpa_hexdump_ascii(level, "RX ctrl_iface",
- (const u8 *) buf, os_strlen(buf));
wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
}
@@ -4826,13 +7858,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
if (reply_len >= 0) {
- int res;
- res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
- reply_size - reply_len);
- if (res < 0)
- reply_len = -1;
- else
- reply_len += res;
+ reply_len += eapol_sm_get_mib(wpa_s->eapol,
+ reply + reply_len,
+ reply_size - reply_len);
}
} else if (os_strncmp(buf, "STATUS", 6) == 0) {
reply_len = wpa_supplicant_ctrl_iface_status(
@@ -4840,9 +7868,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "PMKSA") == 0) {
reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
reply_size);
+ } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
} else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
+ } else if (os_strncmp(buf, "DUMP", 4) == 0) {
+ reply_len = wpa_config_dump_values(wpa_s->conf,
+ reply, reply_size);
} else if (os_strncmp(buf, "GET ", 4) == 0) {
reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
reply, reply_size);
@@ -4855,6 +7888,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
else
wpas_request_connection(wpa_s);
+ } else if (os_strcmp(buf, "REATTACH") == 0) {
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
+ !wpa_s->current_ssid)
+ reply_len = -1;
+ else {
+ wpa_s->reattach = 1;
+ wpas_request_connection(wpa_s);
+ }
} else if (os_strcmp(buf, "RECONNECT") == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
@@ -4907,6 +7948,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+ wpa_s, buf + 21, reply, reply_size);
} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
wpa_s, buf + 14, reply, reply_size);
@@ -4920,11 +7964,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
reply_len = wpas_ctrl_nfc_get_handover_sel(
wpa_s, buf + 21, reply, reply_size);
- } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
- reply_len = wpas_ctrl_nfc_rx_handover_req(
- wpa_s, buf + 20, reply, reply_size);
- } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
- if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
reply_len = -1;
#endif /* CONFIG_WPS_NFC */
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
@@ -4943,8 +7984,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_wps_er_start(wpa_s, buf + 13))
reply_len = -1;
} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
- if (wpas_wps_er_stop(wpa_s))
- reply_len = -1;
+ wpas_wps_er_stop(wpa_s);
} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
reply_len = -1;
@@ -4983,15 +8023,36 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_MESH
+ } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+ wpa_s, buf + 19, reply, reply_size);
+ } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+ wpa_s, "", reply, reply_size);
+ } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
+ buf + 18))
+ reply_len = -1;
+#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
- if (p2p_ctrl_find(wpa_s, buf + 9))
+ if (p2p_ctrl_find(wpa_s, buf + 8))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_FIND") == 0) {
if (p2p_ctrl_find(wpa_s, ""))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
wpas_p2p_stop_find(wpa_s);
+ } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
+ if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
+ if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
+ reply_len = -1;
} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
reply_size);
@@ -5005,7 +8066,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_p2p_group_remove(wpa_s, buf + 17))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
- if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
+ if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
reply_len = -1;
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -5037,6 +8098,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
+ if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
reply_len = -1;
@@ -5050,10 +8114,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
- os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
- wpa_s->force_long_sd = 0;
- if (wpa_s->global->p2p)
- p2p_flush(wpa_s->global->p2p);
+ p2p_ctrl_flush(wpa_s);
} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
reply_len = -1;
@@ -5072,6 +8133,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
+ if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
+ reply_len = -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -5087,13 +8151,26 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
interworking_stop_fetch_anqp(wpa_s);
- } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
- if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
- NULL) < 0)
+ } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
+ if (ctrl_interworking_select(wpa_s, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
+ if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
- if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+ if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
+ int id;
+
+ id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
+ if (id < 0)
reply_len = -1;
+ else {
+ reply_len = os_snprintf(reply, reply_size, "%d\n", id);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
if (get_anqp(wpa_s, buf + 9) < 0)
reply_len = -1;
@@ -5111,14 +8188,28 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
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)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
+ if (hs20_fetch_osu(wpa_s) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
+ hs20_cancel_fetch_osu(wpa_s);
#endif /* CONFIG_HS20 */
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
{
if (wpa_supplicant_ctrl_iface_ctrl_rsp(
wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
reply_len = -1;
- else
- ctrl_rsp = 1;
+ else {
+ /*
+ * Notify response from timeout to allow the control
+ * interface response to be sent first.
+ */
+ eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
+ wpa_s, NULL);
+ }
} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
if (wpa_supplicant_reload_configuration(wpa_s))
reply_len = -1;
@@ -5133,9 +8224,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
reply_len = wpa_supplicant_ctrl_iface_log_level(
wpa_s, buf + 9, reply, reply_size);
+ } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_list_networks(
+ wpa_s, buf + 14, reply, reply_size);
} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_list_networks(
- wpa_s, reply, reply_size);
+ wpa_s, NULL, reply, reply_size);
} else if (os_strcmp(buf, "DISCONNECT") == 0) {
#ifdef CONFIG_SME
wpa_s->sme.prev_bssid_set = 0;
@@ -5147,29 +8241,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
} else if (os_strcmp(buf, "SCAN") == 0) {
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
- reply_len = -1;
- else {
- if (!wpa_s->sched_scanning && !wpa_s->scanning &&
- ((wpa_s->wpa_state <= WPA_SCANNING) ||
- (wpa_s->wpa_state == WPA_COMPLETED))) {
- wpa_s->normal_scans = 0;
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG, "Stop ongoing "
- "sched_scan to allow requested "
- "full scan to proceed");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else {
- wpa_printf(MSG_DEBUG, "Ongoing scan action - "
- "reject new request");
- reply_len = os_snprintf(reply, reply_size,
- "FAIL-BUSY\n");
- }
- }
+ wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
+ } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
+ wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
@@ -5194,6 +8268,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
reply_len = wpa_supplicant_ctrl_iface_get_network(
wpa_s, buf + 12, reply, reply_size);
+ } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
+ if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12))
+ reply_len = -1;
} else if (os_strcmp(buf, "LIST_CREDS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_list_creds(
wpa_s, reply, reply_size);
@@ -5206,6 +8283,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
reply_len = -1;
+ } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9,
+ reply,
+ reply_size);
#ifndef CONFIG_NO_CONFIG_WRITE
} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
@@ -5244,19 +8325,26 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
reply_len = -1;
+ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+ if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "STOP_AP") == 0) {
+ if (wpas_ap_stop_ap(wpa_s))
+ reply_len = -1;
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
} else if (os_strcmp(buf, "RESUME") == 0) {
wpas_notify_resume(wpa_s->global);
+#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcmp(buf, "DROP_SA") == 0) {
wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
+#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
reply_len = -1;
} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
- if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
- reply_len = -1;
+ wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
} else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
reply_len = -1;
@@ -5265,8 +8353,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
buf + 17))
reply_len = -1;
} else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
- if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
- reply_len = -1;
+ wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
#ifdef CONFIG_TDLS
} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
@@ -5277,7 +8364,23 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
+ buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
+ if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
+ buf + 24))
+ reply_len = -1;
#endif /* CONFIG_TDLS */
+ } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
+ reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
+ if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
+ if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
+ reply_len = -1;
} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
reply_size);
@@ -5289,6 +8392,14 @@ 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 */
+#ifdef ANDROID
+ } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
+ reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
+ reply_size);
+#endif /* ANDROID */
+ } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
+ reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
+ reply_size);
} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
pmksa_cache_clear_current(wpa_s->wpa);
eapol_sm_request_reauth(wpa_s->eapol);
@@ -5296,7 +8407,59 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
reply_len = -1;
+ } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
+ if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
+ reply_len = -1;
#endif /* CONFIG_WNM */
+ } else if (os_strcmp(buf, "FLUSH") == 0) {
+ wpa_supplicant_ctrl_iface_flush(wpa_s);
+ } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
+ reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
+ reply_size);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
+ if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
+ 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, "DRIVER_EVENT ", 13) == 0) {
+ if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
+ if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
+ if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
+ if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
+ if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+ if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+ reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
+#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)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) {
+ reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
+ 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))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
+ wpas_ctrl_iface_erp_flush(wpa_s);
+ } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
+ if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -5307,9 +8470,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = 5;
}
- if (ctrl_rsp)
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
*resp_len = reply_len;
return reply;
}
@@ -5388,7 +8548,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
if (wpa_supplicant_get_iface(global, iface.ifname))
return -1;
- return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
+ return wpa_supplicant_add_iface(global, &iface, NULL) ? 0 : -1;
}
@@ -5450,7 +8610,7 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
tmp->drv_name, tmp->ifname,
tmp->desc ? tmp->desc : "");
- if (res < 0 || res >= end - pos) {
+ if (os_snprintf_error(end - pos, res)) {
*pos = '\0';
break;
}
@@ -5476,7 +8636,7 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
while (wpa_s) {
res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
- if (res < 0 || res >= end - pos) {
+ if (os_snprintf_error(end - pos, res)) {
*pos = '\0';
break;
}
@@ -5487,6 +8647,247 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
}
+static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
+ const char *ifname,
+ char *cmd, size_t *resp_len)
+{
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (os_strcmp(ifname, wpa_s->ifname) == 0)
+ break;
+ }
+
+ if (wpa_s == NULL) {
+ char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
+ if (resp)
+ *resp_len = os_strlen(resp);
+ else
+ *resp_len = 1;
+ return resp;
+ }
+
+ return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
+}
+
+
+static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
+ char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_P2P
+ static const char * cmd[] = {
+ "LIST_NETWORKS",
+ "P2P_FIND",
+ "P2P_STOP_FIND",
+ "P2P_LISTEN",
+ "P2P_GROUP_ADD",
+ "P2P_GET_PASSPHRASE",
+ "P2P_SERVICE_UPDATE",
+ "P2P_SERVICE_FLUSH",
+ "P2P_FLUSH",
+ "P2P_CANCEL",
+ "P2P_PRESENCE_REQ",
+ "P2P_EXT_LISTEN",
+ NULL
+ };
+ static const char * prefix[] = {
+#ifdef ANDROID
+ "DRIVER ",
+#endif /* ANDROID */
+ "GET_NETWORK ",
+ "REMOVE_NETWORK ",
+ "P2P_FIND ",
+ "P2P_CONNECT ",
+ "P2P_LISTEN ",
+ "P2P_GROUP_REMOVE ",
+ "P2P_GROUP_ADD ",
+ "P2P_PROV_DISC ",
+ "P2P_SERV_DISC_REQ ",
+ "P2P_SERV_DISC_CANCEL_REQ ",
+ "P2P_SERV_DISC_RESP ",
+ "P2P_SERV_DISC_EXTERNAL ",
+ "P2P_SERVICE_ADD ",
+ "P2P_SERVICE_DEL ",
+ "P2P_SERVICE_REP ",
+ "P2P_REJECT ",
+ "P2P_INVITE ",
+ "P2P_PEER ",
+ "P2P_SET ",
+ "P2P_UNAUTHORIZE ",
+ "P2P_PRESENCE_REQ ",
+ "P2P_EXT_LISTEN ",
+ "P2P_REMOVE_CLIENT ",
+ "WPS_NFC_TOKEN ",
+ "WPS_NFC_TAG_READ ",
+ "NFC_GET_HANDOVER_SEL ",
+ "NFC_GET_HANDOVER_REQ ",
+ "NFC_REPORT_HANDOVER ",
+ "P2P_ASP_PROVISION ",
+ "P2P_ASP_PROVISION_RESP ",
+ NULL
+ };
+ int found = 0;
+ int i;
+
+ if (global->p2p_init_wpa_s == NULL)
+ return NULL;
+
+ for (i = 0; !found && cmd[i]; i++) {
+ if (os_strcmp(buf, cmd[i]) == 0)
+ found = 1;
+ }
+
+ for (i = 0; !found && prefix[i]; i++) {
+ if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
+ found = 1;
+ }
+
+ if (found)
+ return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+ buf, resp_len);
+#endif /* CONFIG_P2P */
+ return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
+ char *buf, size_t *resp_len)
+{
+#ifdef CONFIG_WIFI_DISPLAY
+ if (global->p2p_init_wpa_s == NULL)
+ return NULL;
+ if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
+ os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
+ return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
+ buf, resp_len);
+#endif /* CONFIG_WIFI_DISPLAY */
+ return NULL;
+}
+
+
+static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
+ char *buf, size_t *resp_len)
+{
+ char *ret;
+
+ ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
+ if (ret)
+ return ret;
+
+ ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
+ if (ret)
+ return ret;
+
+ return NULL;
+}
+
+
+static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
+{
+ char *value;
+
+ value = os_strchr(cmd, ' ');
+ if (value == NULL)
+ return -1;
+ *value++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(global, !!atoi(value));
+ return 0;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ /* Restore cmd to its original value to allow redirection */
+ value[-1] = ' ';
+
+ return -1;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
+{
+ int ret = 0, saved = 0;
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (!wpa_s->conf->update_config) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
+ continue;
+ }
+
+ if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
+ ret = 1;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
+ saved++;
+ }
+ }
+
+ if (!saved && !ret) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated");
+ ret = 1;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int wpas_global_ctrl_iface_status(struct wpa_global *global,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ int ret;
+ struct wpa_supplicant *wpa_s;
+
+ pos = buf;
+ end = buf + buflen;
+
+#ifdef CONFIG_P2P
+ if (global->p2p && !global->p2p_disabled) {
+ ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+ "\n"
+ "p2p_state=%s\n",
+ MAC2STR(global->p2p_dev_addr),
+ p2p_get_state_txt(global->p2p));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ } else if (global->p2p) {
+ ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+ ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
+ !!global->wifi_display);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ ret = os_snprintf(pos, end - pos, "ifname=%s\n"
+ "address=" MACSTR "\n",
+ wpa_s->ifname, MAC2STR(wpa_s->own_addr));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
char *buf, size_t *resp_len)
{
@@ -5495,6 +8896,20 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
int reply_len;
int level = MSG_DEBUG;
+ if (os_strncmp(buf, "IFNAME=", 7) == 0) {
+ char *pos = os_strchr(buf + 7, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ return wpas_global_ctrl_iface_ifname(global,
+ buf + 7, pos,
+ resp_len);
+ }
+ }
+
+ reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
+ if (reply)
+ return reply;
+
if (os_strcmp(buf, "PING") == 0)
level = MSG_EXCESSIVE;
wpa_hexdump_ascii(level, "RX global ctrl_iface",
@@ -5530,6 +8945,37 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
wpas_notify_suspend(global);
} else if (os_strcmp(buf, "RESUME") == 0) {
wpas_notify_resume(global);
+ } else if (os_strncmp(buf, "SET ", 4) == 0) {
+ if (wpas_global_ctrl_iface_set(global, buf + 4)) {
+#ifdef CONFIG_P2P
+ if (global->p2p_init_wpa_s) {
+ os_free(reply);
+ /* Check if P2P redirection would work for this
+ * command. */
+ return wpa_supplicant_ctrl_iface_process(
+ global->p2p_init_wpa_s,
+ buf, resp_len);
+ }
+#endif /* CONFIG_P2P */
+ reply_len = -1;
+ }
+#ifndef CONFIG_NO_CONFIG_WRITE
+ } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+ if (wpas_global_ctrl_iface_save_config(global))
+ reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ } else if (os_strcmp(buf, "STATUS") == 0) {
+ reply_len = wpas_global_ctrl_iface_status(global, reply,
+ 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 */
+ } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+ if (wpa_debug_reopen_file() < 0)
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface.h b/contrib/wpa/wpa_supplicant/ctrl_iface.h
index a329ef3..d54cc07 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface.h
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface.h
@@ -32,7 +32,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len);
/**
- * wpa_supplicant_ctrl_iface_process - Process global ctrl_iface command
+ * wpa_supplicant_global_ctrl_iface_process - Process global ctrl_iface command
* @global: Pointer to global data from wpa_supplicant_init()
* @buf: Received command buffer (nul terminated string)
* @resp_len: Variable to be set to the response length
@@ -113,6 +113,8 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
void wpa_supplicant_global_ctrl_iface_deinit(
struct ctrl_iface_global_priv *priv);
+void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s);
+
#else /* CONFIG_CTRL_IFACE */
static inline struct ctrl_iface_priv *
@@ -148,6 +150,10 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
{
}
+static inline void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE */
#endif /* CTRL_IFACE_H */
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
index fd417ff..dc02db2 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -423,7 +423,7 @@ static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
}
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
index 994f9b1..bf6a3df 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
@@ -30,7 +30,11 @@
*/
struct wpa_ctrl_dst {
struct wpa_ctrl_dst *next;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ struct sockaddr_in6 addr;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in addr;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
socklen_t addrlen;
int debug_level;
int errors;
@@ -51,43 +55,73 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+#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)
{
struct wpa_ctrl_dst *dst;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_UDP_IPV6 */
dst = os_zalloc(sizeof(*dst));
if (dst == NULL)
return -1;
- os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in));
+ os_memcpy(&dst->addr, from, sizeof(*from));
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
dst->next = priv->ctrl_dst;
priv->ctrl_dst = 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)),
+ ntohs(from->sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
return 0;
}
static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+#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)
{
struct wpa_ctrl_dst *dst, *prev = NULL;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
dst = priv->ctrl_dst;
while (dst) {
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ if (from->sin6_port == dst->addr.sin6_port &&
+ !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
+ sizeof(from->sin6_addr))) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s:%d",
+ inet_ntop(AF_INET6, &from->sin6_addr, addr,
+ sizeof(*from)),
+ ntohs(from->sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
from->sin_port == dst->addr.sin_port) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
+ "%s:%d", inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (prev == NULL)
priv->ctrl_dst = dst->next;
else
prev->next = dst->next;
os_free(dst);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
- "%s:%d", inet_ntoa(from->sin_addr),
- ntohs(from->sin_port));
return 0;
}
prev = dst;
@@ -98,21 +132,38 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
+#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,
char *level)
{
struct wpa_ctrl_dst *dst;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
dst = priv->ctrl_dst;
while (dst) {
+#if CONFIG_CTRL_IFACE_UDP_IPV6
+ if (from->sin6_port == dst->addr.sin6_port &&
+ !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
+ sizeof(from->sin6_addr))) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level %s:%d",
+ inet_ntop(AF_INET6, &from->sin6_addr, addr,
+ sizeof(*from)),
+ ntohs(from->sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
from->sin_port == dst->addr.sin_port) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
"level %s:%d", inet_ntoa(from->sin_addr),
ntohs(from->sin_port));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
dst->debug_level = atoi(level);
return 0;
}
@@ -150,7 +201,14 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
struct ctrl_iface_priv *priv = sock_ctx;
char buf[256], *pos;
int res;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ struct sockaddr_in6 from;
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+ char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in from;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
socklen_t fromlen = sizeof(from);
char *reply = NULL;
size_t reply_len = 0;
@@ -160,11 +218,19 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
+ if (os_strcmp(addr, "::1")) {
+ wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
+ addr);
+ }
+#else /* 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
@@ -176,6 +242,7 @@ static void wpa_supplicant_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';
@@ -255,7 +322,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
}
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -269,8 +336,14 @@ struct ctrl_iface_priv *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
struct ctrl_iface_priv *priv;
- struct sockaddr_in addr;
int port = WPA_CTRL_IFACE_PORT;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ struct sockaddr_in6 addr;
+ int domain = PF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ struct sockaddr_in addr;
+ int domain = PF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -282,26 +355,39 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->ctrl_interface == NULL)
return priv;
- priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ priv->sock = socket(domain, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_INET)");
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
goto fail;
}
os_memset(&addr, 0, sizeof(addr));
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ addr.sin6_family = AF_INET6;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin6_addr = in6addr_any;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+ inet_pton(AF_INET6, "::1", &addr.sin6_addr);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
addr.sin_family = AF_INET;
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
addr.sin_addr.s_addr = INADDR_ANY;
#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
try_again:
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ addr.sin6_port = htons(port);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
addr.sin_port = htons(port);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
port--;
if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
goto try_again;
- perror("bind(AF_INET)");
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
goto fail;
}
@@ -331,13 +417,13 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
eloop_unregister_read_sock(priv->sock);
if (priv->ctrl_dst) {
/*
- * Wait a second before closing the control socket if
+ * Wait before closing the control socket if
* there are any attached monitors in order to allow
* them to receive any pending messages.
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
"monitors to receive messages");
- os_sleep(1, 0);
+ os_sleep(0, 100000);
}
close(priv->sock);
priv->sock = -1;
@@ -362,6 +448,9 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
int idx;
char *sbuf;
int llen;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
dst = priv->ctrl_dst;
if (priv->sock < 0 || dst == NULL)
@@ -381,13 +470,22 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
while (dst) {
next = dst->next;
if (level >= dst->debug_level) {
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
+ inet_ntop(AF_INET6, &dst->addr.sin6_addr,
+ addr, sizeof(dst->addr)),
+ ntohs(dst->addr.sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
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,
(struct sockaddr *) &dst->addr,
sizeof(dst->addr)) < 0) {
- perror("sendto(CTRL_IFACE monitor)");
+ wpa_printf(MSG_ERROR,
+ "sendto(CTRL_IFACE monitor): %s",
+ strerror(errno));
dst->errors++;
if (dst->errors > 10) {
wpa_supplicant_ctrl_iface_detach(
@@ -456,7 +554,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
@@ -539,7 +638,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_INET)");
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
goto fail;
}
@@ -557,7 +656,7 @@ try_again:
if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
goto try_again;
- perror("bind(AF_INET)");
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
goto fail;
}
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
index f792863..b1ac766 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -47,19 +47,37 @@ struct ctrl_iface_priv {
struct wpa_supplicant *wpa_s;
int sock;
struct dl_list ctrl_dst;
+ int android_control_socket;
};
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+struct ctrl_iface_global_priv {
+ struct wpa_global *global;
+ int sock;
+ struct dl_list ctrl_dst;
+ int android_control_socket;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
+ struct dl_list *ctrl_dst,
int level, const char *buf,
- size_t len);
+ size_t len,
+ struct ctrl_iface_priv *priv,
+ struct ctrl_iface_global_priv *gp);
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv);
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv);
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
struct sockaddr_un *from,
- socklen_t fromlen)
+ socklen_t fromlen, int global)
{
struct wpa_ctrl_dst *dst;
+ char addr_txt[200];
dst = os_zalloc(sizeof(*dst));
if (dst == NULL)
@@ -67,31 +85,36 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
- dl_list_add(&priv->ctrl_dst, &dst->list);
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
- (u8 *) from->sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path));
+ 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;
}
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
struct sockaddr_un *from,
socklen_t fromlen)
{
struct wpa_ctrl_dst *dst;
- dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
+ 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);
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
- (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
return 0;
}
}
@@ -113,11 +136,13 @@ static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
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));
+ 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;
}
}
@@ -135,27 +160,30 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
- char *reply = NULL;
+ char *reply = NULL, *reply_buf = NULL;
size_t reply_len = 0;
int new_attached = 0;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
if (os_strcmp(buf, "ATTACH") == 0) {
- if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+ if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
+ fromlen, 0))
reply_len = 1;
else {
new_attached = 1;
reply_len = 2;
}
} else if (os_strcmp(buf, "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;
@@ -166,21 +194,49 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
else
reply_len = 2;
} else {
- reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
- &reply_len);
+ reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+ &reply_len);
+ reply = reply_buf;
+ }
+
+ if (!reply && reply_len == 1) {
+ reply = "FAIL\n";
+ reply_len = 5;
+ } else if (!reply && reply_len == 2) {
+ reply = "OK\n";
+ reply_len = 3;
}
if (reply) {
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
- fromlen);
- os_free(reply);
- } 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);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ int _errno = errno;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "ctrl_iface sendto failed: %d - %s",
+ _errno, strerror(_errno));
+ if (_errno == ENOBUFS || _errno == EAGAIN) {
+ /*
+ * The socket send buffer could be full. This
+ * may happen if client programs are not
+ * receiving their pending messages. Close and
+ * reopen the socket as a workaround to avoid
+ * getting stuck being unable to send any new
+ * responses.
+ */
+ sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+ if (sock < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
+ }
+ }
+ if (new_attached) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
+ new_attached = 0;
+ wpa_supplicant_ctrl_iface_detach(
+ &priv->ctrl_dst, &from, fromlen);
+ }
+ }
}
+ os_free(reply_buf);
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -191,7 +247,7 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
{
char *buf;
size_t len;
- char *pbuf, *dir = NULL, *gid_str = NULL;
+ char *pbuf, *dir = NULL;
int res;
if (wpa_s->conf->ctrl_interface == NULL)
@@ -201,12 +257,11 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
if (pbuf == NULL)
return NULL;
if (os_strncmp(pbuf, "DIR=", 4) == 0) {
+ char *gid_str;
dir = pbuf + 4;
gid_str = os_strstr(dir, " GROUP=");
- if (gid_str) {
+ if (gid_str)
*gid_str = '\0';
- gid_str += 7;
- }
} else
dir = pbuf;
@@ -218,7 +273,7 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
}
res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
- if (res < 0 || (size_t) res >= len) {
+ if (os_snprintf_error(len, res)) {
os_free(pbuf);
os_free(buf);
return NULL;
@@ -240,20 +295,38 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
}
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
- if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+
+ if (wpa_s == NULL)
return;
- wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+
+ if (global != 2 && wpa_s->global->ctrl_iface) {
+ struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
+ if (!dl_list_empty(&priv->ctrl_dst)) {
+ wpa_supplicant_ctrl_iface_send(wpa_s, global ? NULL :
+ wpa_s->ifname,
+ priv->sock,
+ &priv->ctrl_dst,
+ level, txt, len, NULL,
+ priv);
+ }
+ }
+
+ if (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);
}
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
{
- struct ctrl_iface_priv *priv;
struct sockaddr_un addr;
char *fname = NULL;
gid_t gid = 0;
@@ -263,16 +336,6 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
char *endp;
int flags;
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
- dl_list_init(&priv->ctrl_dst);
- priv->wpa_s = wpa_s;
- priv->sock = -1;
-
- if (wpa_s->conf->ctrl_interface == NULL)
- return priv;
-
buf = os_strdup(wpa_s->conf->ctrl_interface);
if (buf == NULL)
goto fail;
@@ -280,8 +343,10 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
wpa_s->conf->ctrl_interface);
priv->sock = android_get_control_socket(addr.sun_path);
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
+ priv->android_control_socket = 1;
goto havesock;
+ }
#endif /* ANDROID */
if (os_strncmp(buf, "DIR=", 4) == 0) {
dir = buf + 4;
@@ -300,7 +365,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
- perror("mkdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s",
+ dir, strerror(errno));
goto fail;
}
}
@@ -344,7 +410,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
if (gid_set && chown(dir, -1, gid) < 0) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ dir, (int) gid, strerror(errno));
goto fail;
}
@@ -364,7 +431,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -386,15 +453,15 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
goto fail;
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("supp-ctrl-iface-init: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -411,12 +478,14 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
if (gid_set && chown(fname, -1, gid) < 0) {
- perror("chown[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ fname, (int) gid, strerror(errno));
goto fail;
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s",
+ fname, strerror(errno));
goto fail;
}
os_free(fname);
@@ -433,7 +502,8 @@ havesock:
if (flags >= 0) {
flags |= O_NONBLOCK;
if (fcntl(priv->sock, F_SETFL, flags) < 0) {
- perror("fcntl(ctrl, O_NONBLOCK)");
+ wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+ strerror(errno));
/* Not fatal, continue on.*/
}
}
@@ -443,18 +513,71 @@ havesock:
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
os_free(buf);
- return priv;
+ return 0;
fail:
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
close(priv->sock);
- os_free(priv);
+ priv->sock = -1;
+ }
if (fname) {
unlink(fname);
os_free(fname);
}
os_free(buf);
- return NULL;
+ return -1;
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ dl_list_init(&priv->ctrl_dst);
+ priv->wpa_s = wpa_s;
+ priv->sock = -1;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return priv;
+
+ if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
+{
+ int res;
+
+ if (priv->sock <= 0)
+ return -1;
+
+ /*
+ * On Android, the control socket being used may be the socket
+ * that is created when wpa_supplicant is started as a /init.*.rc
+ * service. Such a socket is maintained as a key-value pair in
+ * Android's environment. Closing this control socket would leave us
+ * in a bad state with an invalid socket descriptor.
+ */
+ if (priv->android_control_socket)
+ return priv->sock;
+
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ priv->sock = -1;
+ res = wpas_ctrl_iface_open_sock(wpa_s, priv);
+ if (res < 0)
+ return -1;
+ return priv->sock;
}
@@ -464,17 +587,17 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
if (priv->sock > -1) {
char *fname;
- char *buf, *dir = NULL, *gid_str = NULL;
+ char *buf, *dir = NULL;
eloop_unregister_read_sock(priv->sock);
if (!dl_list_empty(&priv->ctrl_dst)) {
/*
- * Wait a second before closing the control socket if
+ * Wait before closing the control socket if
* there are any attached monitors in order to allow
* them to receive any pending messages.
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
"monitors to receive messages");
- os_sleep(1, 0);
+ os_sleep(0, 100000);
}
close(priv->sock);
priv->sock = -1;
@@ -484,16 +607,17 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
os_free(fname);
}
+ if (priv->wpa_s->conf->ctrl_interface == NULL)
+ goto free_dst;
buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
if (buf == NULL)
goto free_dst;
if (os_strncmp(buf, "DIR=", 4) == 0) {
+ char *gid_str;
dir = buf + 4;
gid_str = os_strstr(dir, " GROUP=");
- if (gid_str) {
+ if (gid_str)
*gid_str = '\0';
- gid_str += 7;
- }
} else
dir = buf;
@@ -503,7 +627,9 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ dir, strerror(errno));
}
}
os_free(buf);
@@ -519,63 +645,109 @@ free_dst:
/**
* wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
- * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @ifname: Interface name for global control socket or %NULL
+ * @sock: Local socket fd
+ * @ctrl_dst: List of attached listeners
* @level: Priority level of the message
* @buf: Message data
* @len: Message length
*
* Send a packet to all monitor programs attached to the control interface.
*/
-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 dl_list *ctrl_dst,
int level, const char *buf,
- size_t len)
+ size_t len,
+ struct ctrl_iface_priv *priv,
+ struct ctrl_iface_global_priv *gp)
{
struct wpa_ctrl_dst *dst, *next;
char levelstr[10];
int idx, res;
struct msghdr msg;
- struct iovec io[2];
+ struct iovec io[5];
- if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
+ if (sock < 0 || dl_list_empty(ctrl_dst))
return;
res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
- if (res < 0 || (size_t) res >= sizeof(levelstr))
+ if (os_snprintf_error(sizeof(levelstr), res))
return;
- io[0].iov_base = levelstr;
- io[0].iov_len = os_strlen(levelstr);
- io[1].iov_base = (char *) buf;
- io[1].iov_len = len;
+ idx = 0;
+ if (ifname) {
+ io[idx].iov_base = "IFNAME=";
+ io[idx].iov_len = 7;
+ idx++;
+ io[idx].iov_base = (char *) ifname;
+ io[idx].iov_len = os_strlen(ifname);
+ idx++;
+ io[idx].iov_base = " ";
+ io[idx].iov_len = 1;
+ idx++;
+ }
+ io[idx].iov_base = levelstr;
+ io[idx].iov_len = os_strlen(levelstr);
+ idx++;
+ io[idx].iov_base = (char *) buf;
+ io[idx].iov_len = len;
+ idx++;
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
- msg.msg_iovlen = 2;
+ msg.msg_iovlen = idx;
- idx = 0;
- dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst,
- list) {
- if (level >= dst->debug_level) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
- (u8 *) dst->addr.sun_path, dst->addrlen -
- offsetof(struct sockaddr_un, sun_path));
- msg.msg_name = (void *) &dst->addr;
- msg.msg_namelen = dst->addrlen;
- if (sendmsg(priv->sock, &msg, 0) < 0) {
- int _errno = errno;
- wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
- "%d - %s",
- idx, errno, strerror(errno));
- dst->errors++;
- if (dst->errors > 1000 ||
- (_errno != ENOBUFS && dst->errors > 10) ||
- _errno == ENOENT) {
- wpa_supplicant_ctrl_iface_detach(
- priv, &dst->addr,
- dst->addrlen);
- }
- } else
- dst->errors = 0;
+ dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
+ int _errno;
+ char addr_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;
+ if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor sent successfully to %s",
+ addr_txt);
+ dst->errors = 0;
+ continue;
+ }
+
+ _errno = errno;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s",
+ addr_txt, errno, strerror(errno));
+ 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);
+ wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
+ dst->addrlen);
+ }
+
+ if (_errno == ENOBUFS || _errno == EAGAIN) {
+ /*
+ * The socket send buffer could be full. This may happen
+ * if client programs are not receiving their pending
+ * messages. Close and reopen the socket as a workaround
+ * to avoid getting stuck being unable to send any new
+ * responses.
+ */
+ if (priv)
+ sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+ else if (gp)
+ sock = wpas_ctrl_iface_global_reinit(
+ wpa_s->global, gp);
+ else
+ break;
+ if (sock < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Failed to reinitialize ctrl_iface socket");
+ break;
+ }
}
- idx++;
}
}
@@ -595,27 +767,41 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
continue;
}
buf[res] = '\0';
if (os_strcmp(buf, "ATTACH") == 0) {
/* handle ATTACH signal of first monitor interface */
- if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
- fromlen)) {
- sendto(priv->sock, "OK\n", 3, 0,
- (struct sockaddr *) &from, fromlen);
+ if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+ &from, fromlen,
+ 0)) {
+ if (sendto(priv->sock, "OK\n", 3, 0,
+ (struct sockaddr *) &from, fromlen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
/* OK to continue */
return;
} else {
- sendto(priv->sock, "FAIL\n", 5, 0,
- (struct sockaddr *) &from, fromlen);
+ if (sendto(priv->sock, "FAIL\n", 5, 0,
+ (struct sockaddr *) &from, fromlen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
} else {
/* return FAIL for all other signals */
- sendto(priv->sock, "FAIL\n", 5, 0,
- (struct sockaddr *) &from, fromlen);
+ if (sendto(priv->sock, "FAIL\n", 5, 0,
+ (struct sockaddr *) &from, fromlen) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
}
}
@@ -623,72 +809,107 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
/* Global ctrl_iface */
-struct ctrl_iface_global_priv {
- struct wpa_global *global;
- int sock;
-};
-
-
static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct wpa_global *global = eloop_ctx;
- char buf[256];
+ struct ctrl_iface_global_priv *priv = sock_ctx;
+ char buf[4096];
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
- char *reply;
+ char *reply = NULL, *reply_buf = NULL;
size_t reply_len;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
- reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
- &reply_len);
+ if (os_strcmp(buf, "ATTACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
+ fromlen, 1))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else if (os_strcmp(buf, "DETACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
+ fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else {
+ reply_buf = wpa_supplicant_global_ctrl_iface_process(
+ global, buf, &reply_len);
+ reply = reply_buf;
+ }
+
+ if (!reply && reply_len == 1) {
+ reply = "FAIL\n";
+ reply_len = 5;
+ } else if (!reply && reply_len == 2) {
+ reply = "OK\n";
+ reply_len = 3;
+ }
if (reply) {
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
- fromlen);
- os_free(reply);
- } else if (reply_len) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
+ os_free(reply_buf);
}
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv)
{
- struct ctrl_iface_global_priv *priv;
struct sockaddr_un addr;
+ const char *ctrl = global->params.ctrl_interface;
+ int flags;
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
- priv->global = global;
- priv->sock = -1;
-
- if (global->params.ctrl_interface == NULL)
- return priv;
+ wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
#ifdef ANDROID
- priv->sock = android_get_control_socket(global->params.ctrl_interface);
- if (priv->sock >= 0)
+ if (os_strncmp(ctrl, "@android:", 9) == 0) {
+ priv->sock = android_get_control_socket(ctrl + 9);
+ if (priv->sock < 0) {
+ wpa_printf(MSG_ERROR, "Failed to open Android control "
+ "socket '%s'", ctrl + 9);
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
+ ctrl + 9);
+ priv->android_control_socket = 1;
goto havesock;
-#endif /* ANDROID */
+ }
- wpa_printf(MSG_DEBUG, "Global control interface '%s'",
- global->params.ctrl_interface);
+ if (os_strncmp(ctrl, "@abstract:", 10) != 0) {
+ /*
+ * Backwards compatibility - try to open an Android control
+ * socket and if that fails, assume this was a UNIX domain
+ * socket instead.
+ */
+ priv->sock = android_get_control_socket(ctrl);
+ if (priv->sock >= 0) {
+ wpa_printf(MSG_DEBUG,
+ "Using Android control socket '%s'",
+ ctrl);
+ priv->android_control_socket = 1;
+ goto havesock;
+ }
+ }
+#endif /* ANDROID */
priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -697,66 +918,203 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
addr.sun_len = sizeof(addr);
#endif /* __FreeBSD__ */
addr.sun_family = AF_UNIX;
- os_strlcpy(addr.sun_path, global->params.ctrl_interface,
- sizeof(addr.sun_path));
+
+ if (os_strncmp(ctrl, "@abstract:", 10) == 0) {
+ addr.sun_path[0] = '\0';
+ os_strlcpy(addr.sun_path + 1, ctrl + 10,
+ sizeof(addr.sun_path) - 1);
+ if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
+ "bind(PF_UNIX;%s) failed: %s",
+ ctrl, strerror(errno));
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
+ ctrl + 10);
+ goto havesock;
+ }
+
+ os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("supp-global-ctrl-iface-init (will try fixup): "
- "bind(PF_UNIX)");
+ wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s",
+ ctrl, strerror(errno));
if (connect(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
" allow connections - assuming it was left"
"over from forced program termination");
- if (unlink(global->params.ctrl_interface) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- global->params.ctrl_interface);
+ if (unlink(ctrl) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ ctrl, strerror(errno));
goto fail;
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("supp-glb-iface-init: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s",
+ ctrl, strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
"ctrl_iface socket '%s'",
- global->params.ctrl_interface);
+ ctrl);
} else {
wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
"be in use - cannot override it");
wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
"not used anymore",
- global->params.ctrl_interface);
+ ctrl);
goto fail;
}
}
-#ifdef ANDROID
+ wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl);
+
+ if (global->params.ctrl_interface_group) {
+ char *gid_str = global->params.ctrl_interface_group;
+ gid_t gid = 0;
+ struct group *grp;
+ char *endp;
+
+ grp = getgrnam(gid_str);
+ if (grp) {
+ gid = grp->gr_gid;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ (int) gid, gid_str);
+ } else {
+ /* Group name not found - try to parse this as gid */
+ gid = strtol(gid_str, &endp, 10);
+ if (*gid_str == '\0' || *endp != '\0') {
+ wpa_printf(MSG_ERROR, "CTRL: Invalid group "
+ "'%s'", gid_str);
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ (int) gid);
+ }
+ if (chown(ctrl, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR,
+ "chown[global_ctrl_interface=%s,gid=%d]: %s",
+ ctrl, (int) gid, strerror(errno));
+ goto fail;
+ }
+
+ if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR,
+ "chmod[global_ctrl_interface=%s]: %s",
+ ctrl, strerror(errno));
+ goto fail;
+ }
+ } else {
+ if (chmod(ctrl, S_IRWXU) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "chmod[global_ctrl_interface=%s](S_IRWXU): %s",
+ ctrl, strerror(errno));
+ /* continue anyway since group change was not required
+ */
+ }
+ }
+
havesock:
-#endif /* ANDROID */
+
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(priv->sock, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+ wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+ strerror(errno));
+ /* Not fatal, continue on.*/
+ }
+ }
+
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
- global, NULL);
+ global, priv);
- return priv;
+ return 0;
fail:
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
close(priv->sock);
- os_free(priv);
- return NULL;
+ priv->sock = -1;
+ }
+ return -1;
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ dl_list_init(&priv->ctrl_dst);
+ priv->global = global;
+ priv->sock = -1;
+
+ if (global->params.ctrl_interface == NULL)
+ return priv;
+
+ if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+ return priv;
+}
+
+
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv)
+{
+ int res;
+
+ if (priv->sock <= 0)
+ return -1;
+
+ /*
+ * On Android, the control socket being used may be the socket
+ * that is created when wpa_supplicant is started as a /init.*.rc
+ * service. Such a socket is maintained as a key-value pair in
+ * Android's environment. Closing this control socket would leave us
+ * in a bad state with an invalid socket descriptor.
+ */
+ if (priv->android_control_socket)
+ return priv->sock;
+
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ priv->sock = -1;
+ res = wpas_global_ctrl_iface_open_sock(global, priv);
+ if (res < 0)
+ return -1;
+ return priv->sock;
}
void
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
{
+ struct wpa_ctrl_dst *dst, *prev;
+
if (priv->sock >= 0) {
eloop_unregister_read_sock(priv->sock);
close(priv->sock);
}
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)
+ os_free(dst);
os_free(priv);
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/Makefile b/contrib/wpa/wpa_supplicant/dbus/Makefile
index d64c65c..f355ebe 100644
--- a/contrib/wpa/wpa_supplicant/dbus/Makefile
+++ b/contrib/wpa/wpa_supplicant/dbus/Makefile
@@ -1,7 +1,7 @@
all: libwpadbus.a
clean:
- rm -f *~ *.o *.d
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov
rm -f libwpadbus.a
install:
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
index 5d0e31e..7ef6cad 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
@@ -17,6 +17,7 @@
#include "dbus_common_i.h"
#include "dbus_new.h"
#include "dbus_old.h"
+#include "../wpa_supplicant_i.h"
#ifndef SIGPOLL
@@ -164,6 +165,7 @@ static void process_timeout(void *eloop_ctx, void *sock_ctx)
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
{
struct wpas_dbus_priv *priv = data;
+
if (!dbus_timeout_get_enabled(timeout))
return TRUE;
@@ -179,6 +181,7 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
static void remove_timeout(DBusTimeout *timeout, void *data)
{
struct wpas_dbus_priv *priv = data;
+
eloop_cancel_timeout(process_timeout, priv, timeout);
dbus_timeout_set_data(timeout, NULL, NULL);
}
@@ -243,8 +246,7 @@ static int integrate_with_eloop(struct wpas_dbus_priv *priv)
remove_timeout,
timeout_toggled, priv,
NULL)) {
- wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
- "functions");
+ wpa_printf(MSG_ERROR, "dbus: Failed to set callback functions");
return -1;
}
@@ -257,6 +259,22 @@ static int integrate_with_eloop(struct wpas_dbus_priv *priv)
}
+static DBusHandlerResult disconnect_filter(DBusConnection *conn,
+ DBusMessage *message, void *data)
+{
+ struct wpas_dbus_priv *priv = data;
+
+ if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
+ "Disconnected")) {
+ wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
+ dbus_connection_set_exit_on_disconnect(conn, FALSE);
+ wpa_supplicant_terminate_proc(priv->global);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
{
DBusError error;
@@ -265,9 +283,13 @@ static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
/* Get a reference to the system bus */
dbus_error_init(&error);
priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
- if (!priv->con) {
- wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
- "bus: %s - %s", error.name, error.message);
+ if (priv->con) {
+ dbus_connection_add_filter(priv->con, disconnect_filter, priv,
+ NULL);
+ } else {
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not acquire the system bus: %s - %s",
+ error.name, error.message);
ret = -1;
}
dbus_error_free(&error);
@@ -289,7 +311,7 @@ static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
* FIXME: is there a better solution to this problem?
*/
eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
- priv->con, NULL);
+ priv->con, NULL);
return 0;
}
@@ -300,10 +322,15 @@ static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
if (priv->con) {
eloop_cancel_timeout(dispatch_initial_dbus_messages,
priv->con, NULL);
+ eloop_cancel_timeout(process_timeout, priv, ELOOP_ALL_CTX);
+
dbus_connection_set_watch_functions(priv->con, NULL, NULL,
NULL, NULL, NULL);
dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
NULL, NULL, NULL);
+ dbus_connection_remove_filter(priv->con, disconnect_filter,
+ priv);
+
dbus_connection_unref(priv->con);
}
@@ -320,26 +347,14 @@ struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
return NULL;
priv->global = global;
- if (wpas_dbus_init_common(priv) < 0) {
- wpas_dbus_deinit(priv);
- return NULL;
- }
-
+ if (wpas_dbus_init_common(priv) < 0 ||
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
- if (wpas_dbus_ctrl_iface_init(priv) < 0) {
- wpas_dbus_deinit(priv);
- return NULL;
- }
+ wpas_dbus_ctrl_iface_init(priv) < 0 ||
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
#ifdef CONFIG_CTRL_IFACE_DBUS
- if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
- wpas_dbus_deinit(priv);
- return NULL;
- }
+ wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 ||
#endif /* CONFIG_CTRL_IFACE_DBUS */
-
- if (wpas_dbus_init_common_finish(priv) < 0) {
+ wpas_dbus_init_common_finish(priv) < 0) {
wpas_dbus_deinit(priv);
return NULL;
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c
index 61a9430..a0c44eb 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -66,7 +66,7 @@ dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
const char * wpa_dbus_type_as_string(const int type)
{
- switch(type) {
+ switch (type) {
case DBUS_TYPE_BYTE:
return DBUS_TYPE_BYTE_AS_STRING;
case DBUS_TYPE_BOOLEAN:
@@ -106,11 +106,8 @@ static dbus_bool_t _wpa_dbus_add_dict_entry_start(
iter_dict_entry))
return FALSE;
- if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
- &key))
- return FALSE;
-
- return TRUE;
+ return dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
+ &key);
}
@@ -120,10 +117,8 @@ static dbus_bool_t _wpa_dbus_add_dict_entry_end(
{
if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
return FALSE;
- if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
- return FALSE;
- return TRUE;
+ return dbus_message_iter_close_container(iter_dict, iter_dict_entry);
}
@@ -143,22 +138,15 @@ static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
return FALSE;
if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
- key, value_type))
- return FALSE;
-
- if (!dbus_message_iter_open_container(&iter_dict_entry,
+ key, value_type) ||
+ !dbus_message_iter_open_container(&iter_dict_entry,
DBUS_TYPE_VARIANT,
- type_as_string, &iter_dict_val))
- return FALSE;
-
- if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
+ type_as_string, &iter_dict_val) ||
+ !dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
return FALSE;
- if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
- &iter_dict_val))
- return FALSE;
-
- return TRUE;
+ return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+ &iter_dict_val);
}
@@ -170,17 +158,13 @@ static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
dbus_uint32_t i;
if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
- key, DBUS_TYPE_ARRAY))
- return FALSE;
-
- if (!dbus_message_iter_open_container(&iter_dict_entry,
+ key, DBUS_TYPE_ARRAY) ||
+ !dbus_message_iter_open_container(&iter_dict_entry,
DBUS_TYPE_VARIANT,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
- &iter_dict_val))
- return FALSE;
-
- if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
+ &iter_dict_val) ||
+ !dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&iter_array))
return FALSE;
@@ -195,11 +179,8 @@ static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
return FALSE;
- if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
- &iter_dict_val))
- return FALSE;
-
- return TRUE;
+ return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+ &iter_dict_val);
}
@@ -428,9 +409,7 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
const char *value,
const dbus_uint32_t value_len)
{
- if (!key)
- return FALSE;
- if (!value && (value_len != 0))
+ if (!key || (!value && value_len != 0))
return FALSE;
return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
value_len);
@@ -465,27 +444,20 @@ dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
err = os_snprintf(array_type, sizeof(array_type),
DBUS_TYPE_ARRAY_AS_STRING "%s",
type);
- if (err < 0 || err > (int) sizeof(array_type))
+ if (os_snprintf_error(sizeof(array_type), err))
return FALSE;
- if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
- return FALSE;
-
- if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
- key, DBUS_TYPE_ARRAY))
- return FALSE;
-
- if (!dbus_message_iter_open_container(iter_dict_entry,
+ if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+ !_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
+ key, DBUS_TYPE_ARRAY) ||
+ !dbus_message_iter_open_container(iter_dict_entry,
DBUS_TYPE_VARIANT,
array_type,
iter_dict_val))
return FALSE;
- if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
- type, iter_array))
- return FALSE;
-
- return TRUE;
+ return dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
+ type, iter_array);
}
@@ -542,10 +514,8 @@ dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
DBusMessageIter iter_bytes;
size_t i;
- if (!iter_array || !value)
- return FALSE;
-
- if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+ if (!iter_array || !value ||
+ !dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&iter_bytes))
return FALSE;
@@ -557,10 +527,7 @@ dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
return FALSE;
}
- if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
- return FALSE;
-
- return TRUE;
+ return dbus_message_iter_close_container(iter_array, &iter_bytes);
}
@@ -586,17 +553,12 @@ dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
DBusMessageIter *iter_dict_val,
DBusMessageIter *iter_array)
{
- if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
- return FALSE;
-
- if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
+ if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+ !dbus_message_iter_close_container(iter_dict_val, iter_array))
return FALSE;
- if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
- iter_dict_val))
- return FALSE;
-
- return TRUE;
+ return _wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
+ iter_dict_val);
}
@@ -619,12 +581,8 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
dbus_uint32_t i;
- if (!key)
- return FALSE;
- if (!items && (num_items != 0))
- return FALSE;
-
- if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
+ if (!key || (!items && num_items != 0) ||
+ !wpa_dbus_dict_begin_string_array(iter_dict, key,
&iter_dict_entry, &iter_dict_val,
&iter_array))
return FALSE;
@@ -635,11 +593,8 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
return FALSE;
}
- if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
- &iter_dict_val, &iter_array))
- return FALSE;
-
- return TRUE;
+ return wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
+ &iter_dict_val, &iter_array);
}
@@ -662,12 +617,9 @@ dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
dbus_uint32_t i;
- if (!key)
- return FALSE;
- if (!items && (num_items != 0))
- return FALSE;
-
- if (!wpa_dbus_dict_begin_array(iter_dict, key,
+ if (!key ||
+ (!items && num_items != 0) ||
+ !wpa_dbus_dict_begin_array(iter_dict, key,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
&iter_dict_entry, &iter_dict_val,
@@ -681,11 +633,8 @@ dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
return FALSE;
}
- if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
- &iter_dict_val, &iter_array))
- return FALSE;
-
- return TRUE;
+ return wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+ &iter_dict_val, &iter_array);
}
@@ -707,16 +656,25 @@ dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
DBusMessageIter *iter_dict,
DBusError *error)
{
+ int type;
+
+ wpa_printf(MSG_MSGDUMP, "%s: start reading a dict entry", __func__);
if (!iter || !iter_dict) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "[internal] missing message iterators");
+ "[internal] missing message iterators");
return FALSE;
}
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+ type = dbus_message_iter_get_arg_type(iter);
+ if (type != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+ wpa_printf(MSG_DEBUG,
+ "%s: unexpected message argument types (arg=%c element=%c)",
+ __func__, type,
+ type != DBUS_TYPE_ARRAY ? '?' :
+ dbus_message_iter_get_element_type(iter));
dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
- "unexpected message argument types");
+ "unexpected message argument types");
return FALSE;
}
@@ -742,7 +700,6 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
if (!buffer)
return FALSE;
- entry->bytearray_value = buffer;
entry->array_len = 0;
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
char byte;
@@ -753,21 +710,22 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
BYTE_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
- wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
- "entry_get_byte_array out of "
- "memory trying to retrieve the "
- "string array");
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to retrieve the string array",
+ __func__);
goto done;
}
buffer = nbuffer;
}
- entry->bytearray_value = buffer;
dbus_message_iter_get_basic(iter, &byte);
- entry->bytearray_value[count] = byte;
+ buffer[count] = byte;
entry->array_len = ++count;
dbus_message_iter_next(iter);
}
+ entry->bytearray_value = buffer;
+ wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
+ entry->bytearray_value, entry->array_len);
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
@@ -790,18 +748,16 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
struct wpa_dbus_dict_entry *entry)
{
dbus_uint32_t count = 0;
- dbus_bool_t success = FALSE;
char **buffer, **nbuffer;
entry->strarray_value = NULL;
+ entry->array_len = 0;
entry->array_type = DBUS_TYPE_STRING;
buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
if (buffer == NULL)
return FALSE;
- entry->strarray_value = buffer;
- entry->array_len = 0;
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
const char *value;
char *str;
@@ -811,29 +767,31 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
buffer, count + STR_ARRAY_CHUNK_SIZE,
STR_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
- os_free(buffer);
- wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
- "entry_get_string_array out of "
- "memory trying to retrieve the "
- "string array");
- goto done;
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to retrieve the string array",
+ __func__);
+ goto fail;
}
buffer = nbuffer;
}
- entry->strarray_value = buffer;
dbus_message_iter_get_basic(iter, &value);
+ wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
+ __func__, wpa_debug_show_keys ? value : "[omitted]");
str = os_strdup(value);
if (str == NULL) {
- wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
- "string_array out of memory trying to "
- "duplicate the string array");
- goto done;
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to duplicate the string array",
+ __func__);
+ goto fail;
}
- entry->strarray_value[count] = str;
- entry->array_len = ++count;
+ buffer[count++] = str;
dbus_message_iter_next(iter);
}
+ entry->strarray_value = buffer;
+ entry->array_len = count;
+ wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
+ __func__, entry->array_len);
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
@@ -841,10 +799,15 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
entry->strarray_value = NULL;
}
- success = TRUE;
+ return TRUE;
-done:
- return success;
+fail:
+ while (count > 0) {
+ count--;
+ os_free(buffer[count]);
+ }
+ os_free(buffer);
+ return FALSE;
}
@@ -856,15 +819,31 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
{
struct wpa_dbus_dict_entry tmpentry;
size_t buflen = 0;
- int i;
-
- if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
- return FALSE;
+ int i, type;
entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
entry->array_len = 0;
entry->binarray_value = NULL;
+ type = dbus_message_iter_get_arg_type(iter);
+ wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
+ if (type == DBUS_TYPE_INVALID) {
+ /* Likely an empty array of arrays */
+ return TRUE;
+ }
+ if (type != DBUS_TYPE_ARRAY) {
+ wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
+ __func__, type);
+ return FALSE;
+ }
+
+ type = dbus_message_iter_get_element_type(iter);
+ if (type != DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
+ __func__, type);
+ return FALSE;
+ }
+
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
DBusMessageIter iter_array;
@@ -881,8 +860,10 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
}
dbus_message_iter_recurse(iter, &iter_array);
+ os_memset(&tmpentry, 0, sizeof(tmpentry));
+ tmpentry.type = DBUS_TYPE_ARRAY;
if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
- == FALSE)
+ == FALSE)
goto cleanup;
entry->binarray_value[entry->array_len] =
@@ -895,6 +876,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
entry->array_len++;
dbus_message_iter_next(iter);
}
+ wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
+ __func__, entry->array_len);
return TRUE;
@@ -915,12 +898,11 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array(
dbus_bool_t success = FALSE;
DBusMessageIter iter_array;
- if (!entry)
- return FALSE;
+ wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
dbus_message_iter_recurse(iter_dict_val, &iter_array);
- switch (array_type) {
+ switch (array_type) {
case DBUS_TYPE_BYTE:
success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
entry);
@@ -932,7 +914,10 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array(
break;
case DBUS_TYPE_ARRAY:
success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
+ break;
default:
+ wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
+ __func__, array_type);
break;
}
@@ -947,42 +932,72 @@ static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
switch (entry->type) {
case DBUS_TYPE_OBJECT_PATH:
+ dbus_message_iter_get_basic(iter, &v);
+ wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
+ __func__, v);
+ entry->str_value = os_strdup(v);
+ if (entry->str_value == NULL)
+ return FALSE;
+ break;
case DBUS_TYPE_STRING:
dbus_message_iter_get_basic(iter, &v);
+ wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
+ __func__, wpa_debug_show_keys ? v : "[omitted]");
entry->str_value = os_strdup(v);
if (entry->str_value == NULL)
return FALSE;
break;
case DBUS_TYPE_BOOLEAN:
dbus_message_iter_get_basic(iter, &entry->bool_value);
+ wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
+ __func__, entry->bool_value);
break;
case DBUS_TYPE_BYTE:
dbus_message_iter_get_basic(iter, &entry->byte_value);
+ wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
+ __func__, entry->byte_value);
break;
case DBUS_TYPE_INT16:
dbus_message_iter_get_basic(iter, &entry->int16_value);
+ wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
+ __func__, entry->int16_value);
break;
case DBUS_TYPE_UINT16:
dbus_message_iter_get_basic(iter, &entry->uint16_value);
+ wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
+ __func__, entry->uint16_value);
break;
case DBUS_TYPE_INT32:
dbus_message_iter_get_basic(iter, &entry->int32_value);
+ wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
+ __func__, entry->int32_value);
break;
case DBUS_TYPE_UINT32:
dbus_message_iter_get_basic(iter, &entry->uint32_value);
+ wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
+ __func__, entry->uint32_value);
break;
case DBUS_TYPE_INT64:
dbus_message_iter_get_basic(iter, &entry->int64_value);
+ wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
+ __func__, (long long int) entry->int64_value);
break;
case DBUS_TYPE_UINT64:
dbus_message_iter_get_basic(iter, &entry->uint64_value);
+ wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
+ __func__,
+ (unsigned long long int) entry->uint64_value);
break;
case DBUS_TYPE_DOUBLE:
dbus_message_iter_get_basic(iter, &entry->double_value);
+ wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
+ __func__, entry->double_value);
break;
case DBUS_TYPE_ARRAY:
return _wpa_dbus_dict_entry_get_array(iter, entry);
default:
+ wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
+ __func__, entry->type);
return FALSE;
}
@@ -1013,26 +1028,40 @@ dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
int type;
const char *key;
- if (!iter_dict || !entry)
- goto error;
-
- if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
+ if (!iter_dict || !entry ||
+ dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
+ wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
goto error;
+ }
dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
dbus_message_iter_get_basic(&iter_dict_entry, &key);
+ wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
entry->key = key;
- if (!dbus_message_iter_next(&iter_dict_entry))
+ if (!dbus_message_iter_next(&iter_dict_entry)) {
+ wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
goto error;
+ }
type = dbus_message_iter_get_arg_type(&iter_dict_entry);
- if (type != DBUS_TYPE_VARIANT)
+ if (type != DBUS_TYPE_VARIANT) {
+ wpa_printf(MSG_DEBUG,
+ "%s: unexpected dict entry variant type: %c",
+ __func__, type);
goto error;
+ }
dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
- if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
+ wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
+ __func__, entry->type);
+ entry->array_type = DBUS_TYPE_INVALID;
+ if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
+ wpa_printf(MSG_DEBUG,
+ "%s: failed to fetch dict values from variant",
+ __func__);
goto error;
+ }
dbus_message_iter_next(iter_dict);
return TRUE;
@@ -1087,6 +1116,8 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
os_free(entry->bytearray_value);
break;
case DBUS_TYPE_STRING:
+ if (!entry->strarray_value)
+ break;
for (i = 0; i < entry->array_len; i++)
os_free(entry->strarray_value[i]);
os_free(entry->strarray_value);
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h
index 9666349..b068431 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -72,28 +72,28 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
/* Manual construction and addition of array elements */
dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
- const char *key, const char *type,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array);
+ const char *key, const char *type,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
- const char *key,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array);
+ const char *key,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
- const char *elem);
+ const char *elem);
dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
const u8 *value,
size_t value_len);
dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array);
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
static inline dbus_bool_t
wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
@@ -120,7 +120,11 @@ dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
* Reading a dict from a DBusMessage
*/
-#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+/*
+ * Used only in struct wpa_dbus_dict_entry::array_type internally to identify
+ * special binary array case.
+ */
+#define WPAS_DBUS_TYPE_BINARRAY ((int) '@')
struct wpa_dbus_dict_entry {
int type; /** the dbus type of the dict entry's value */
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
index 8bc6618..30ef03a 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
@@ -24,6 +24,7 @@
#include "dbus_common_i.h"
#include "dbus_new_handlers_p2p.h"
#include "p2p/p2p.h"
+#include "../p2p_supplicant.h"
#ifdef CONFIG_AP /* until needed by something else */
@@ -74,8 +75,7 @@ static DBusHandlerResult noc_filter(DBusConnection *conn,
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
- {
+ for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (wpa_s->preq_notify_peer != NULL &&
os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
(new_owner == NULL || os_strlen(new_owner) == 0)) {
@@ -147,22 +147,14 @@ static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &wpa_s->dbus_new_path))
- goto err;
-
- if (properties) {
- if (!wpa_dbus_get_object_properties(
- iface, wpa_s->dbus_new_path,
- WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &wpa_s->dbus_new_path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(
+ iface, wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -228,7 +220,7 @@ void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success)
/**
- * wpas_dbus_signal_blob - Send a BSS related event signal
+ * wpas_dbus_signal_bss - Send a BSS related event signal
* @wpa_s: %wpa_supplicant network interface data
* @bss_obj_path: BSS object path
* @sig_name: signal name - BSSAdded or BSSRemoved
@@ -258,22 +250,14 @@ static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &bss_obj_path))
- goto err;
-
- if (properties) {
- if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
- WPAS_DBUS_NEW_IFACE_BSS,
- &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &bss_obj_path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(iface, bss_obj_path,
+ WPAS_DBUS_NEW_IFACE_BSS,
+ &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -406,23 +390,14 @@ static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
path = net_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
-
- if (properties) {
- if (!wpa_dbus_get_object_properties(
- iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
- &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(
+ iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+ &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -512,19 +487,12 @@ void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &net_ptr))
- goto err;
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field))
- goto err;
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
- goto err;
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &net_ptr) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -542,6 +510,7 @@ void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
{
char path[WPAS_DBUS_OBJECT_PATH_MAX];
+
os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
wpa_s->dbus_new_path, ssid->id);
@@ -709,9 +678,9 @@ void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
- char *auth_type[6]; /* we have six possible authorization types */
+ char *auth_type[5]; /* we have five possible authentication types */
int at_num = 0;
- char *encr_type[4]; /* we have four possible encryption types */
+ char *encr_type[3]; /* we have three possible encryption types */
int et_num = 0;
iface = wpa_s->global->dbus;
@@ -734,34 +703,25 @@ void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
auth_type[at_num++] = "open";
if (cred->auth_type & WPS_AUTH_WPAPSK)
auth_type[at_num++] = "wpa-psk";
- if (cred->auth_type & WPS_AUTH_SHARED)
- auth_type[at_num++] = "shared";
if (cred->auth_type & WPS_AUTH_WPA)
auth_type[at_num++] = "wpa-eap";
if (cred->auth_type & WPS_AUTH_WPA2)
auth_type[at_num++] = "wpa2-eap";
if (cred->auth_type & WPS_AUTH_WPA2PSK)
- auth_type[at_num++] =
- "wpa2-psk";
+ auth_type[at_num++] = "wpa2-psk";
if (cred->encr_type & WPS_ENCR_NONE)
encr_type[et_num++] = "none";
- if (cred->encr_type & WPS_ENCR_WEP)
- encr_type[et_num++] = "wep";
if (cred->encr_type & WPS_ENCR_TKIP)
encr_type[et_num++] = "tkip";
if (cred->encr_type & WPS_ENCR_AES)
encr_type[et_num++] = "aes";
- if (wpa_s->current_ssid) {
- if (!wpa_dbus_dict_append_byte_array(
- &dict_iter, "BSSID",
- (const char *) wpa_s->current_ssid->bssid,
- ETH_ALEN))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
+ if ((wpa_s->current_ssid &&
+ !wpa_dbus_dict_append_byte_array(
+ &dict_iter, "BSSID",
+ (const char *) wpa_s->current_ssid->bssid, ETH_ALEN)) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
(const char *) cred->ssid,
cred->ssid_len) ||
!wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
@@ -788,6 +748,8 @@ nomem:
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
@@ -808,29 +770,23 @@ void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
- !wpa_dbus_dict_append_string(&dict_iter, "subject", subject))
- goto nomem;
-
- if (cert_hash &&
- !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash))
- goto nomem;
-
- if (cert &&
- !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
- wpabuf_head(cert),
- wpabuf_len(cert)))
- goto nomem;
-
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto nomem;
-
- dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
+ (altsubject && num_altsubject &&
+ !wpa_dbus_dict_append_string_array(&dict_iter, "altsubject",
+ altsubject, num_altsubject)) ||
+ (cert_hash &&
+ !wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
+ cert_hash)) ||
+ (cert &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
+ wpabuf_head(cert),
+ wpabuf_len(cert))) ||
+ !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);
}
@@ -856,16 +812,83 @@ void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
- ||
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) ||
!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
&parameter))
- goto nomem;
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
- dbus_connection_send(iface->con, msg, NULL);
-nomem:
+/**
+ * wpas_dbus_signal_sta - Send a station related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ * @sig_name: signal name - StaAuthorized or StaDeauthorized
+ *
+ * Notify listeners about event related with station
+ */
+static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta, const char *sig_name)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX];
+ char *dev_mac;
+
+ os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta));
+ dev_mac = sta_mac;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
+ if (msg == NULL)
+ return;
+
+ if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &dev_mac,
+ DBUS_TYPE_INVALID))
+ dbus_connection_send(iface->con, msg, NULL);
+ else
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
dbus_message_unref(msg);
+
+ wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'",
+ sta_mac, sig_name);
+}
+
+
+/**
+ * wpas_dbus_signal_sta_authorized - Send a STA authorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a new station has been authorized
+ */
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized");
+}
+
+
+/**
+ * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a station has been deauthorized
+ */
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized");
}
@@ -880,37 +903,40 @@ nomem:
void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
const char *role)
{
-
DBusMessage *msg;
- DBusMessageIter iter;
+ DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface = wpa_s->global->dbus;
- char *ifname = wpa_s->ifname;
+ struct wpa_supplicant *parent;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
- msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ msg = dbus_message_new_signal(parent->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"GroupFinished");
if (msg == NULL)
return;
dbus_message_iter_init_append(msg, &iter);
-
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) {
- wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
- "signal -not enough memory for ifname ");
- goto err;
- }
-
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role))
- wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
- "signal -not enough memory for role ");
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter,
+ "interface_object",
+ wpa_s->dbus_new_path) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "role", role) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+ wpa_s->dbus_groupobj_path) ||
+ !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);
-
-err:
dbus_message_unref(msg);
}
@@ -956,6 +982,9 @@ void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
if (request || !status) {
if (config_methods & WPS_CONFIG_DISPLAY)
_signal = request ?
@@ -970,9 +999,10 @@ void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
"ProvisionDiscoveryPBCResponse";
else
return; /* Unknown or un-supported method */
- } else if (!request && status)
+ } else {
/* Explicit check for failure response */
_signal = "ProvisionDiscoveryFailure";
+ }
add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
(!request && !status &&
@@ -1041,6 +1071,9 @@ void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
wpa_s->dbus_new_path, MAC2STR(src));
@@ -1086,6 +1119,69 @@ static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
}
+struct group_changed_data {
+ struct wpa_supplicant *wpa_s;
+ struct p2p_peer_info *info;
+};
+
+
+static int match_group_where_peer_is_client(struct p2p_group *group,
+ void *user_data)
+{
+ struct group_changed_data *data = user_data;
+ const struct p2p_group_config *cfg;
+ struct wpa_supplicant *wpa_s_go;
+
+ if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
+ return 1;
+
+ cfg = p2p_group_get_config(group);
+
+ wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
+ 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);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void signal_peer_groups_changed(struct p2p_peer_info *info,
+ void *user_data)
+{
+ struct group_changed_data *data = user_data;
+ struct wpa_supplicant *wpa_s_go;
+
+ 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,
+ info->p2p_device_addr);
+ return;
+ }
+
+ data->info = info;
+ p2p_loop_on_all_groups(data->wpa_s->global->p2p,
+ match_group_where_peer_is_client, data);
+ data->info = NULL;
+}
+
+
+static void peer_groups_changed(struct wpa_supplicant *wpa_s)
+{
+ struct group_changed_data data;
+
+ os_memset(&data, 0, sizeof(data));
+ data.wpa_s = wpa_s;
+
+ p2p_loop_on_known_peers(wpa_s->global->p2p,
+ signal_peer_groups_changed, &data);
+}
+
+
/**
* wpas_dbus_signal_p2p_group_started - Signals P2P group has
* started. Emitted when a group is successfully started
@@ -1104,58 +1200,56 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
- char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ struct wpa_supplicant *parent;
- iface = wpa_s->parent->global->dbus;
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
+ iface = parent->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
- if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+ if (wpa_s->dbus_groupobj_path == NULL)
return;
/* New interface has been created for this group */
- msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+ msg = dbus_message_new_signal(parent->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"GroupStarted");
-
if (msg == NULL)
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto nomem;
-
/*
* In case the device supports creating a separate interface the
* DBus client will need to know the object path for the interface
* object this group was created on, so include it here.
*/
- if (!wpa_dbus_dict_append_object_path(&dict_iter,
- "interface_object",
- wpa_s->dbus_new_path))
- goto nomem;
-
- if (!wpa_dbus_dict_append_string(&dict_iter, "role",
- client ? "client" : "GO"))
- goto nomem;
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
- group_obj_path) ||
- !wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto nomem;
-
- dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter,
+ "interface_object",
+ wpa_s->dbus_new_path) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "role",
+ client ? "client" : "GO") ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+ wpa_s->dbus_groupobj_path) ||
+ !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);
+ if (client)
+ peer_groups_changed(wpa_s);
+ }
dbus_message_unref(msg);
}
/**
*
- * Method to emit GONeogtiation Success or Failure signals based
+ * Method to emit GONegotiation Success or Failure signals based
* on status.
* @status: Status of the GO neg request. 0 for success, other for errors.
*/
@@ -1173,6 +1267,9 @@ void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
iface = wpa_s->global->dbus;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_memset(freqs, 0, sizeof(freqs));
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
@@ -1191,9 +1288,8 @@ void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto err;
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
path) ||
!wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
goto err;
@@ -1202,15 +1298,10 @@ void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
int i = 0;
int freq_list_num = 0;
- if (res->role_go) {
- if (!wpa_dbus_dict_append_byte_array(
- &dict_iter, "passphrase",
- (const char *) res->passphrase,
- sizeof(res->passphrase)))
- goto err;
- }
-
- if (!wpa_dbus_dict_append_string(&dict_iter, "role_go",
+ if ((res->role_go &&
+ !wpa_dbus_dict_append_string(&dict_iter, "passphrase",
+ res->passphrase)) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "role_go",
res->role_go ? "GO" :
"client") ||
!wpa_dbus_dict_append_int32(&dict_iter, "frequency",
@@ -1245,22 +1336,16 @@ void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
DBUS_TYPE_INT32_AS_STRING,
&iter_dict_entry,
&iter_dict_val,
- &iter_dict_array))
- goto err;
-
- if (!dbus_message_iter_append_fixed_array(&iter_dict_array,
+ &iter_dict_array) ||
+ !dbus_message_iter_append_fixed_array(&iter_dict_array,
DBUS_TYPE_INT32,
&f_array,
- freq_list_num))
- goto err;
-
- if (!wpa_dbus_dict_end_array(&dict_iter,
+ freq_list_num) ||
+ !wpa_dbus_dict_end_array(&dict_iter,
&iter_dict_entry,
&iter_dict_val,
- &iter_dict_array))
- goto err;
-
- if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
+ &iter_dict_array) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
res->persistent_group) ||
!wpa_dbus_dict_append_uint32(&dict_iter,
"peer_config_timeout",
@@ -1292,13 +1377,16 @@ void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
- wpa_printf(MSG_INFO, "%s\n", __func__);
+ wpa_printf(MSG_DEBUG, "%s", __func__);
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
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,
"InvitationResult");
@@ -1307,23 +1395,16 @@ void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
- goto nomem;
- if (bssid) {
- if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
- (const char *) bssid,
- ETH_ALEN))
- goto nomem;
- }
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto nomem;
-
- dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "status", status) ||
+ (bssid &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+ (const char *) bssid,
+ 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);
}
@@ -1335,15 +1416,16 @@ nomem:
* constructed using p2p i/f addr used for connecting.
*
* @wpa_s: %wpa_supplicant network interface data
- * @member_addr: addr (p2p i/f) of the peer joining the group
+ * @peer_addr: P2P Device Address of the peer joining the group
*/
void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
- const u8 *member)
+ const u8 *peer_addr)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
DBusMessageIter iter;
- char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ struct wpa_supplicant *parent;
iface = wpa_s->global->dbus;
@@ -1354,10 +1436,14 @@ void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
if (!wpa_s->dbus_groupobj_path)
return;
- os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
COMPACT_MACSTR,
- wpa_s->dbus_groupobj_path, MAC2STR(member));
+ parent->dbus_new_path, MAC2STR(peer_addr));
msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
WPAS_DBUS_NEW_IFACE_P2P_GROUP,
@@ -1366,18 +1452,14 @@ void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
return;
dbus_message_iter_init_append(msg, &iter);
- path = groupmember_obj_path;
+ path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
-
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &path)) {
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ } else {
+ dbus_connection_send(iface->con, msg, NULL);
+ wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+ }
dbus_message_unref(msg);
}
@@ -1386,18 +1468,19 @@ err:
*
* Method to emit a signal for a peer disconnecting the group.
* The signal will carry path to the group member object
- * constructed using p2p i/f addr used for connecting.
+ * constructed using the P2P Device Address of the peer.
*
* @wpa_s: %wpa_supplicant network interface data
- * @member_addr: addr (p2p i/f) of the peer joining the group
+ * @peer_addr: P2P Device Address of the peer joining the group
*/
void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
- const u8 *member)
+ const u8 *peer_addr)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
DBusMessageIter iter;
- char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ struct wpa_supplicant *parent;
iface = wpa_s->global->dbus;
@@ -1408,10 +1491,14 @@ void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
if (!wpa_s->dbus_groupobj_path)
return;
- os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
COMPACT_MACSTR,
- wpa_s->dbus_groupobj_path, MAC2STR(member));
+ parent->dbus_new_path, MAC2STR(peer_addr));
msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
WPAS_DBUS_NEW_IFACE_P2P_GROUP,
@@ -1420,19 +1507,15 @@ void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
return;
dbus_message_iter_init_append(msg, &iter);
- path = groupmember_obj_path;
+ path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
-
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
- "signal");
+ &path)) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Failed to construct PeerDisconnected signal");
+ } else {
+ dbus_connection_send(iface->con, msg, NULL);
+ wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+ }
dbus_message_unref(msg);
}
@@ -1459,22 +1542,26 @@ void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
+ /* Check if this is a known peer */
+ if (!p2p_peer_known(wpa_s->global->p2p, sa))
+ return;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"ServiceDiscoveryRequest");
if (msg == NULL)
return;
- /* Check if this is a known peer */
- if (!p2p_peer_known(wpa_s->global->p2p, sa))
- goto error;
-
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
@@ -1482,11 +1569,8 @@ void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
path = peer_obj_path;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto error;
-
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
path) ||
!wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
!wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
@@ -1497,13 +1581,9 @@ void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
(const char *) tlvs,
tlvs_len) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto error;
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-error:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -1528,22 +1608,26 @@ void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
+ /* Check if this is a known peer */
+ if (!p2p_peer_known(wpa_s->global->p2p, sa))
+ return;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "ServiceDiscoveryResponse");
+ "ServiceDiscoveryResponse");
if (msg == NULL)
return;
- /* Check if this is a known peer */
- if (!p2p_peer_known(wpa_s->global->p2p, sa))
- goto error;
-
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
@@ -1551,10 +1635,8 @@ void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
path = peer_obj_path;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto error;
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
path) ||
!wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
update_indic) ||
@@ -1562,17 +1644,13 @@ void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
(const char *) tlvs,
tlvs_len) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto error;
-
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-error:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
+
/**
* wpas_dbus_signal_persistent_group - Send a persistent group related
* event signal
@@ -1598,6 +1676,9 @@ static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
wpa_s->dbus_new_path, id);
@@ -1611,23 +1692,15 @@ static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
path = pgrp_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
-
- if (properties) {
- if (!wpa_dbus_get_object_properties(
- iface, pgrp_obj_path,
- WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
+ &path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(
+ iface, pgrp_obj_path,
+ WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
dbus_message_unref(msg);
}
@@ -1686,6 +1759,9 @@ void wpas_dbus_signal_p2p_wps_failed(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,
"WpsFailed");
@@ -1707,7 +1783,7 @@ void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
dbus_message_unref(msg);
}
-#endif /*CONFIG_P2P*/
+#endif /* CONFIG_P2P */
/**
@@ -1808,9 +1884,15 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
case WPAS_DBUS_BSS_PROP_RSN:
prop = "RSN";
break;
+ case WPAS_DBUS_BSS_PROP_WPS:
+ prop = "WPS";
+ break;
case WPAS_DBUS_BSS_PROP_IES:
prop = "IEs";
break;
+ case WPAS_DBUS_BSS_PROP_AGE:
+ prop = "Age";
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -1895,7 +1977,7 @@ static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
+ (WPADBusMethodHandler) wpas_dbus_handler_create_interface,
{
{ "args", "a{sv}", ARG_IN },
{ "path", "o", ARG_OUT },
@@ -1903,29 +1985,20 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
}
},
{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_interface,
{
{ "path", "o", ARG_IN },
END_ARGS
}
},
{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
+ (WPADBusMethodHandler) wpas_dbus_handler_get_interface,
{
{ "ifname", "s", ARG_IN },
{ "path", "o", ARG_OUT },
END_ARGS
}
},
-#ifdef CONFIG_AUTOSCAN
- { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
- {
- { "arg", "s", ARG_IN },
- END_ARGS
- }
- },
-#endif /* CONFIG_AUTOSCAN */
{ NULL, NULL, NULL, { END_ARGS } }
};
@@ -1954,6 +2027,12 @@ static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
wpas_dbus_getter_global_capabilities,
NULL
},
+#ifdef CONFIG_WIFI_DISPLAY
+ { "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay",
+ wpas_dbus_getter_global_wfd_ies,
+ wpas_dbus_setter_global_wfd_ies
+ },
+#endif /* CONFIG_WIFI_DISPLAY */
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -1971,14 +2050,6 @@ static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
END_ARGS
}
},
- { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
- {
- { "path", "o", ARG_OUT },
- { "field", "s", ARG_OUT },
- { "text", "s", ARG_OUT },
- END_ARGS
- }
- },
/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
{
@@ -2005,8 +2076,8 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
return -1;
}
@@ -2120,16 +2191,16 @@ int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
net_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
/* allocate memory for handlers arguments */
arg = os_zalloc(sizeof(struct network_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create arguments for method");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for method");
goto err;
}
@@ -2244,6 +2315,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
wpas_dbus_getter_bss_ies,
NULL
},
+ { "Age", WPAS_DBUS_NEW_IFACE_BSS, "u",
+ wpas_dbus_getter_bss_age,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -2331,15 +2406,15 @@ int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
arg = os_zalloc(sizeof(struct bss_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create arguments for handler");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for handler");
goto err;
}
arg->wpa_s = wpa_s;
@@ -2372,20 +2447,27 @@ err:
static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_scan,
+ (WPADBusMethodHandler) wpas_dbus_handler_scan,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
+ { "SignalPoll", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_signal_poll,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
+ (WPADBusMethodHandler) wpas_dbus_handler_disconnect,
{
END_ARGS
}
},
{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
+ (WPADBusMethodHandler) wpas_dbus_handler_add_network,
{
{ "args", "a{sv}", ARG_IN },
{ "path", "o", ARG_OUT },
@@ -2393,33 +2475,39 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+ (WPADBusMethodHandler) wpas_dbus_handler_reassociate,
+ {
+ END_ARGS
+ }
+ },
+ { "Reattach", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_reattach,
{
END_ARGS
}
},
{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_network,
{
{ "path", "o", ARG_IN },
END_ARGS
}
},
{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_all_networks,
{
END_ARGS
}
},
{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
+ (WPADBusMethodHandler) wpas_dbus_handler_select_network,
{
{ "path", "o", ARG_IN },
END_ARGS
}
},
{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+ (WPADBusMethodHandler) wpas_dbus_handler_network_reply,
{
{ "path", "o", ARG_IN },
{ "field", "s", ARG_IN },
@@ -2427,8 +2515,9 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+#ifndef CONFIG_NO_CONFIG_BLOBS
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
+ (WPADBusMethodHandler) wpas_dbus_handler_add_blob,
{
{ "name", "s", ARG_IN },
{ "data", "ay", ARG_IN },
@@ -2436,7 +2525,7 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
+ (WPADBusMethodHandler) wpas_dbus_handler_get_blob,
{
{ "name", "s", ARG_IN },
{ "data", "ay", ARG_OUT },
@@ -2444,15 +2533,25 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_blob,
{
{ "name", "s", ARG_IN },
END_ARGS
}
},
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+ { "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler)
+ wpas_dbus_handler_set_pkcs11_engine_and_module_path,
+ {
+ { "pkcs11_engine_path", "s", ARG_IN },
+ { "pkcs11_module_path", "s", ARG_IN },
+ END_ARGS
+ }
+ },
#ifdef CONFIG_WPS
{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
- (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
+ (WPADBusMethodHandler) wpas_dbus_handler_wps_start,
{
{ "args", "a{sv}", ARG_IN },
{ "output", "a{sv}", ARG_OUT },
@@ -2462,41 +2561,41 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_find,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_stop_find,
{
END_ARGS
}
},
{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_listen,
{
{ "timeout", "i", ARG_IN },
END_ARGS
}
},
{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_extendedlisten,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_presence_request,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_prov_disc_req,
{
{ "peer", "o", ARG_IN },
{ "config_method", "s", ARG_IN },
@@ -2504,7 +2603,7 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_connect,
{
{ "args", "a{sv}", ARG_IN },
{ "generated_pin", "s", ARG_OUT },
@@ -2512,94 +2611,88 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_group_add,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_invite,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_disconnect,
{
END_ARGS
}
},
{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_rejectpeer,
{
{ "peer", "o", ARG_IN },
END_ARGS
}
},
{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
{
END_ARGS
}
},
{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_add_service,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_delete_service,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush_service,
{
END_ARGS
}
},
{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_req,
{
{ "args", "a{sv}", ARG_IN },
+ { "ref", "t", ARG_OUT },
END_ARGS
}
},
{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_res,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_cancel_req,
{
{ "args", "t", ARG_IN },
END_ARGS
}
},
{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
- {
- END_ARGS
- }
- },
- { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_update,
{
- { "arg", "i", ARG_IN },
END_ARGS
}
},
{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_serv_disc_external,
{
{ "arg", "i", ARG_IN },
END_ARGS
@@ -2629,7 +2722,7 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
},
#endif /* CONFIG_P2P */
{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
+ (WPADBusMethodHandler) wpas_dbus_handler_flush_bss,
{
{ "age", "u", ARG_IN },
END_ARGS
@@ -2649,6 +2742,58 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
#endif /* CONFIG_AP */
+ { "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_eap_logoff,
+ {
+ END_ARGS
+ }
+ },
+ { "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_eap_logon,
+ {
+ END_ARGS
+ }
+ },
+#ifdef CONFIG_AUTOSCAN
+ { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_autoscan,
+ {
+ { "arg", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_TDLS
+ { "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover,
+ {
+ { "peer_address", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "TDLSSetup", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_setup,
+ {
+ { "peer_address", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "TDLSStatus", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_status,
+ {
+ { "peer_address", "s", ARG_IN },
+ { "status", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "TDLSTeardown", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_teardown,
+ {
+ { "peer_address", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_TDLS */
{ NULL, NULL, NULL, { END_ARGS } }
};
@@ -2725,11 +2870,23 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
wpas_dbus_getter_scan_interval,
wpas_dbus_setter_scan_interval
},
+ { "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_pkcs11_engine_path,
+ NULL
+ },
+ { "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_pkcs11_module_path,
+ NULL
+ },
#ifdef CONFIG_WPS
{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
wpas_dbus_getter_process_credentials,
wpas_dbus_setter_process_credentials
},
+ { "ConfigMethods", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_config_methods,
+ wpas_dbus_setter_config_methods
+ },
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
@@ -2845,16 +3002,9 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
},
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
- { "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- {
- { "states", "a{ss}", ARG_OUT },
- END_ARGS
- }
- },
{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
{ "path", "o", ARG_OUT },
- { "properties", "a{sv}", ARG_OUT },
END_ARGS
}
},
@@ -2917,12 +3067,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
},
{ "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
+ { "properties", "a{sv}", ARG_OUT },
END_ARGS
}
},
{ "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
- { "status", "i", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
END_ARGS
}
},
@@ -2941,8 +3092,7 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
},
{ "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
- { "ifname", "s", ARG_OUT },
- { "role", "s", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
END_ARGS
}
},
@@ -3000,6 +3150,26 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
+ { "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "name", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "name", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ { "field", "s", ARG_OUT },
+ { "text", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
{ NULL, NULL, { END_ARGS } }
};
@@ -3026,8 +3196,8 @@ int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
@@ -3062,7 +3232,7 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL)
+ if (ctrl_iface == NULL || wpa_s->dbus_new_path == NULL)
return 0;
wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
@@ -3127,11 +3297,25 @@ static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
wpas_dbus_getter_p2p_peer_ies,
NULL
},
+ { "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ wpas_dbus_getter_p2p_peer_device_address,
+ NULL
+ },
+ { "Groups", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ao",
+ wpas_dbus_getter_p2p_peer_groups,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
-
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_P2P_PEER,
+ {
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
{ NULL, NULL, { END_ARGS } }
};
@@ -3155,6 +3339,9 @@ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
DBusMessageIter iter;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
@@ -3174,15 +3361,10 @@ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
&path))
- goto err;
-
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
dbus_message_unref(msg);
}
@@ -3240,6 +3422,9 @@ int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
if (ctrl_iface == NULL)
return 0;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
wpa_s->dbus_new_path, MAC2STR(dev_addr));
@@ -3248,16 +3433,16 @@ int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
peer_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
/* allocate memory for handlers arguments */
arg = os_zalloc(sizeof(struct peer_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create arguments for method");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for method");
goto err;
}
@@ -3299,6 +3484,10 @@ int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
if (wpa_s == NULL || wpa_s->global == NULL ||
wpa_s->dbus_new_path == NULL)
return 0;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
@@ -3315,6 +3504,23 @@ int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
}
+void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ wpa_dbus_mark_property_changed(wpa_s->global->dbus, peer_obj_path,
+ WPAS_DBUS_NEW_IFACE_P2P_PEER, "Groups");
+}
+
+
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,
@@ -3411,8 +3617,8 @@ void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
group_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
@@ -3449,6 +3655,9 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
if (wpa_s == NULL || wpa_s->global == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return;
@@ -3460,6 +3669,8 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
return;
}
+ peer_groups_changed(wpa_s);
+
wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
wpa_s->dbus_groupobj_path);
@@ -3471,109 +3682,6 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
}
static const struct wpa_dbus_property_desc
-wpas_dbus_p2p_groupmember_properties[] = {
- { NULL, NULL, NULL, NULL, NULL }
-};
-
-/**
- * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember
- * object with dbus
- * @wpa_s: wpa_supplicant interface structure
- * @p2p_if_addr: i/f addr of the device joining this group
- *
- * Registers p2p groupmember representing object with dbus
- */
-void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
- const u8 *p2p_if_addr)
-{
- struct wpas_dbus_priv *ctrl_iface;
- struct wpa_dbus_object_desc *obj_desc = NULL;
- struct groupmember_handler_args *arg;
- char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s == NULL || wpa_s->global == NULL)
- return;
-
- ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL)
- return;
-
- if (!wpa_s->dbus_groupobj_path)
- return;
-
- os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
- wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
-
- 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;
- }
-
- /* allocate memory for handlers arguments */
- arg = os_zalloc(sizeof(struct groupmember_handler_args));
- if (!arg) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create arguments for method");
- goto err;
- }
-
- arg->wpa_s = wpa_s;
- os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN);
-
- wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
- wpas_dbus_p2p_groupmember_properties, NULL);
-
- if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path,
- wpa_s->ifname, obj_desc))
- goto err;
-
- wpa_printf(MSG_INFO,
- "dbus: Registered group member object '%s' successfully",
- groupmember_obj_path);
- return;
-
-err:
- free_dbus_object_desc(obj_desc);
-}
-
-/**
- * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember
- * object with dbus
- * @wpa_s: wpa_supplicant interface structure
- * @p2p_if_addr: i/f addr of the device joining this group
- *
- * Unregisters p2p groupmember representing object with dbus
- */
-void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
- const u8 *p2p_if_addr)
-{
- struct wpas_dbus_priv *ctrl_iface;
- char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s == NULL || wpa_s->global == NULL)
- return;
-
- ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL)
- return;
-
- if (!wpa_s->dbus_groupobj_path)
- return;
-
- os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
- wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
-
- wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
-}
-
-
-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,
@@ -3610,6 +3718,9 @@ int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
return -1; /* should we return w/o complaining? */
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
@@ -3626,8 +3737,8 @@ int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
pgrp_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
- "object description");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to create object description");
goto err;
}
@@ -3638,8 +3749,8 @@ int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
/* allocate memory for handlers arguments */
arg = os_zalloc(sizeof(struct network_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
- "arguments for method");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to create arguments for method");
goto err;
}
@@ -3689,6 +3800,10 @@ int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
if (wpa_s == NULL || wpa_s->global == NULL ||
wpa_s->dbus_new_path == NULL)
return 0;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h
index 363a7e5..d162d2b 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h
@@ -41,6 +41,7 @@ enum wpas_dbus_bss_prop {
WPAS_DBUS_BSS_PROP_RSN,
WPAS_DBUS_BSS_PROP_WPS,
WPAS_DBUS_BSS_PROP_IES,
+ WPAS_DBUS_BSS_PROP_AGE,
};
#define WPAS_DBUS_OBJECT_PATH_MAX 150
@@ -79,11 +80,7 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_NEW_P2P_PEERS_PART "Peers"
#define WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
-#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "Members"
-#define WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
- WPAS_DBUS_NEW_INTERFACE ".GroupMember"
-
-/* Errors */
+/* Top-level Errors */
#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
WPAS_DBUS_NEW_INTERFACE ".UnknownError"
#define WPAS_DBUS_ERROR_INVALID_ARGS \
@@ -91,6 +88,8 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_ERROR_IFACE_EXISTS \
WPAS_DBUS_NEW_INTERFACE ".InterfaceExists"
+#define WPAS_DBUS_ERROR_IFACE_DISABLED \
+ WPAS_DBUS_NEW_INTERFACE ".InterfaceDisabled"
#define WPAS_DBUS_ERROR_IFACE_UNKNOWN \
WPAS_DBUS_NEW_INTERFACE ".InterfaceUnknown"
@@ -118,6 +117,9 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
+/* Interface-level errors */
+#define WPAS_DBUS_ERROR_IFACE_SCAN_ERROR \
+ WPAS_DBUS_NEW_IFACE_INTERFACE ".ScanError"
void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
@@ -172,6 +174,8 @@ int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
+void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
const char *role);
void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
@@ -196,10 +200,6 @@ int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
int nid);
void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
int status, const u8 *bssid);
-void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
- const u8 *p2p_if_addr);
-void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
- const u8 *p2p_if_addr);
void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
const u8 *member);
void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
@@ -215,6 +215,8 @@ void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert);
void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
@@ -222,6 +224,10 @@ void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
const u8 *ie, size_t ie_len, u32 ssi_signal);
void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
const char *status, const char *parameter);
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta);
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta);
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
@@ -351,6 +357,12 @@ static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
}
static inline void
+wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+}
+
+static inline void
wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
const char *role)
{
@@ -474,6 +486,8 @@ wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth,
const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
@@ -493,6 +507,18 @@ static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
{
}
+static inline
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+}
+
+static inline
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+}
+
#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 5e06932..f2e62ca 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2,7 +2,7 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
- * 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.
@@ -27,18 +27,15 @@
#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
#include "dbus_common_i.h"
+#include "drivers/driver.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-static const char *debug_strings[] = {
+static const char * const debug_strings[] = {
"excessive", "msgdump", "debug", "info", "warning", "error", NULL
};
/**
- * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
+ * wpas_dbus_error_unknown_error - Return a new UnknownError error message
* @message: Pointer to incoming dbus message this error refers to
* @arg: Optional string appended to error message
* Returns: a dbus error message
@@ -48,20 +45,6 @@ static const char *debug_strings[] = {
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
const char *arg)
{
- /*
- * This function can be called as a result of a failure
- * within internal getter calls, which will call this function
- * with a NULL message parameter. However, dbus_message_new_error
- * looks very unkindly (i.e, abort()) on a NULL message, so
- * in this case, we should not call it.
- */
- if (message == NULL) {
- wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
- "called with NULL message (arg=%s)",
- arg ? arg : "N/A");
- return NULL;
- }
-
return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
arg);
}
@@ -76,9 +59,9 @@ DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
*/
static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
{
- return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
- "wpa_supplicant knows nothing about "
- "this interface.");
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "wpa_supplicant knows nothing about this interface.");
}
@@ -91,9 +74,9 @@ static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
*/
static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
{
- return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
- "There is no such a network in this "
- "interface.");
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+ "There is no such a network in this interface.");
}
@@ -109,9 +92,9 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
{
DBusMessage *reply;
- reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
- "Did not receive correct message "
- "arguments.");
+ reply = dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_INVALID_ARGS,
+ "Did not receive correct message arguments.");
if (arg != NULL)
dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
DBUS_TYPE_INVALID);
@@ -120,7 +103,31 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
}
-static const char *dont_quote[] = {
+/**
+ * wpas_dbus_error_scan_error - Return a new ScanError error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * @error: Optional string to be used as the error message
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return a scan error
+ */
+static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+ const char *error)
+{
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+ error);
+}
+
+
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
+{
+ wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+
+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
@@ -129,6 +136,7 @@ static const char *dont_quote[] = {
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;
@@ -215,7 +223,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
ret = os_snprintf(value, size, "\"%s\"",
entry.str_value);
- if (ret < 0 || (size_t) ret != (size - 1))
+ if (os_snprintf_error(size, ret))
goto error;
} else {
value = os_strdup(entry.str_value);
@@ -229,7 +237,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
ret = os_snprintf(value, size, "%u",
entry.uint32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else if (entry.type == DBUS_TYPE_INT32) {
value = os_zalloc(size);
@@ -238,7 +246,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
ret = os_snprintf(value, size, "%d",
entry.int32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else
goto error;
@@ -246,6 +254,19 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
if (wpa_config_set(ssid, entry.key, value, 0) < 0)
goto error;
+ if (os_strcmp(entry.key, "bssid") != 0 &&
+ os_strcmp(entry.key, "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 ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
(os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
@@ -254,6 +275,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
wpa_config_update_prio_list(wpa_s->conf);
os_free(value);
+ value = NULL;
wpa_dbus_dict_entry_clear(&entry);
}
@@ -287,27 +309,21 @@ dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
if (!dbus_type_is_basic(type)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: given type is not basic", __func__);
+ "%s: given type is not basic", __func__);
return FALSE;
}
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- wpa_dbus_type_as_string(type),
- &variant_iter))
- goto error;
-
- if (!dbus_message_iter_append_basic(&variant_iter, type, val))
- goto error;
-
- if (!dbus_message_iter_close_container(iter, &variant_iter))
- goto error;
+ wpa_dbus_type_as_string(type),
+ &variant_iter) ||
+ !dbus_message_iter_append_basic(&variant_iter, type, val) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: error constructing reply", __func__);
+ return FALSE;
+ }
return TRUE;
-
-error:
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: error constructing reply", __func__);
- return FALSE;
}
@@ -370,7 +386,7 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
if (!dbus_type_is_basic(type)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: given type is not basic", __func__);
+ "%s: given type is not basic", __func__);
return FALSE;
}
@@ -378,20 +394,15 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
type_str[1] = sub_type_str[0];
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- type_str, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 1", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ type_str, &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
sub_type_str, &array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 2", __func__);
+ "%s: failed to construct message", __func__);
return FALSE;
}
- switch(type) {
+ switch (type) {
case DBUS_TYPE_BYTE:
case DBUS_TYPE_BOOLEAN:
element_size = 1;
@@ -417,24 +428,24 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
break;
default:
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: unknown element type %d", __func__, type);
+ "%s: unknown element type %d", __func__, type);
return FALSE;
}
for (i = 0; i < array_len; i++) {
- dbus_message_iter_append_basic(&array_iter, type,
- array + i * element_size);
- }
-
- if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 3", __func__);
- return FALSE;
+ if (!dbus_message_iter_append_basic(&array_iter, type,
+ array + i * element_size)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 2.5",
+ __func__);
+ return FALSE;
+ }
}
- if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 4", __func__);
+ "%s: failed to construct message 3", __func__);
return FALSE;
}
@@ -477,34 +488,25 @@ dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
inner_type_str[1] = sub_type_str[0];
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- type_str, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 1", __func__);
- return FALSE;
- }
- if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ type_str, &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
inner_type_str, &array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 2", __func__);
+ "%s: failed to construct message", __func__);
return FALSE;
}
- for (i = 0; i < array_len; i++) {
+ for (i = 0; i < array_len && array[i]; i++) {
wpa_dbus_dict_bin_array_add_element(&array_iter,
wpabuf_head(array[i]),
wpabuf_len(array[i]));
}
- if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to close message 2", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to close message 1", __func__);
+ "%s: failed to close message", __func__);
return FALSE;
}
@@ -542,30 +544,34 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
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, "Driver") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ if (os_strcmp(entry.key, "Driver") == 0 &&
+ 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 (!os_strcmp(entry.key, "Ifname") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ goto oom;
+ } else if (os_strcmp(entry.key, "Ifname") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(ifname);
ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (ifname == NULL)
- goto error;
- } else if (!os_strcmp(entry.key, "ConfigFile") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ goto oom;
+ } else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
+ 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 (!os_strcmp(entry.key, "BridgeIfname") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ goto oom;
+ } else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
+ 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;
+ goto oom;
} else {
wpa_dbus_dict_entry_clear(&entry);
goto error;
@@ -580,28 +586,30 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
* an error if we already control it.
*/
if (wpa_supplicant_get_iface(global, ifname) != NULL) {
- reply = dbus_message_new_error(message,
- WPAS_DBUS_ERROR_IFACE_EXISTS,
- "wpa_supplicant already "
- "controls this interface.");
+ reply = dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_IFACE_EXISTS,
+ "wpa_supplicant already controls this interface.");
} else {
struct wpa_supplicant *wpa_s;
struct wpa_interface iface;
+
os_memset(&iface, 0, sizeof(iface));
iface.driver = driver;
iface.ifname = ifname;
iface.confname = confname;
iface.bridge_ifname = bridge_ifname;
/* Otherwise, have wpa_supplicant attach to it. */
- if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+ wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
+ if (wpa_s) {
const char *path = wpa_s->dbus_new_path;
+
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
- &path, DBUS_TYPE_INVALID);
+ &path, DBUS_TYPE_INVALID);
} else {
reply = wpas_dbus_error_unknown_error(
- message, "wpa_supplicant couldn't grab this "
- "interface.");
+ message,
+ "wpa_supplicant couldn't grab this interface.");
}
}
@@ -615,6 +623,9 @@ out:
error:
reply = wpas_dbus_error_invalid_args(message, NULL);
goto out;
+oom:
+ reply = wpas_dbus_error_no_memory(message);
+ goto out;
}
@@ -644,8 +655,8 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
reply = wpas_dbus_error_iface_unknown(message);
else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
reply = wpas_dbus_error_unknown_error(
- message, "wpa_supplicant couldn't remove this "
- "interface.");
+ message,
+ "wpa_supplicant couldn't remove this interface.");
}
return reply;
@@ -679,13 +690,11 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
path = wpa_s->dbus_new_path;
reply = dbus_message_new_method_return(message);
if (reply == NULL)
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
dbus_message_unref(reply);
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
}
return reply;
@@ -728,8 +737,8 @@ 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)
+ DBusError *error,
+ void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_timestamp, error);
@@ -784,8 +793,8 @@ dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
if (val < 0 ||
wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
wpa_debug_show_keys)) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
- "level value");
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "wrong debug level value");
return FALSE;
}
@@ -935,8 +944,8 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
* and P2P that are determined at compile time.
*/
dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+ DBusError *error,
+ void *user_data)
{
const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
size_t num_items = 0;
@@ -965,8 +974,8 @@ static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
char **type, DBusMessage **reply)
{
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Type must be a string");
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
message, "Wrong Type value type. String required");
return -1;
@@ -988,36 +997,36 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
int len;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
- "must be an array of arrays of bytes");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ssids must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong SSIDs value type. Array of arrays of "
- "bytes required");
+ message,
+ "Wrong SSIDs value type. Array of arrays of bytes required");
return -1;
}
dbus_message_iter_recurse(var, &array_iter);
if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
- {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
- "must be an array of arrays of bytes");
+ dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ssids must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong SSIDs value type. Array of arrays of "
- "bytes required");
+ message,
+ "Wrong SSIDs value type. Array of arrays of bytes required");
return -1;
}
- while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
- {
+ while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Too many ssids specified on scan dbus "
- "call");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Too many ssids specified on scan dbus call",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Too many ssids specified. Specify "
- "at most four");
+ message,
+ "Too many ssids specified. Specify at most four");
return -1;
}
@@ -1027,9 +1036,8 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
if (len > MAX_SSID_LEN) {
wpa_printf(MSG_DEBUG,
- "wpas_dbus_handler_scan[dbus]: "
- "SSID too long (len=%d max_len=%d)",
- len, MAX_SSID_LEN);
+ "%s[dbus]: SSID too long (len=%d max_len=%d)",
+ __func__, len, MAX_SSID_LEN);
*reply = wpas_dbus_error_invalid_args(
message, "Invalid SSID: too long");
return -1;
@@ -1038,12 +1046,7 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
if (len != 0) {
ssid = os_malloc(len);
if (ssid == NULL) {
- wpa_printf(MSG_DEBUG,
- "wpas_dbus_handler_scan[dbus]: "
- "out of memory. Cannot allocate "
- "memory for SSID");
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
os_memcpy(ssid, val, len);
@@ -1075,28 +1078,28 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
int len;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
- "be an array of arrays of bytes");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ies must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong IEs value type. Array of arrays of "
- "bytes required");
+ message,
+ "Wrong IEs value type. Array of arrays of bytes required");
return -1;
}
dbus_message_iter_recurse(var, &array_iter);
if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
- {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
- "be an array of arrays of bytes");
+ dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ies must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
message, "Wrong IEs value type. Array required");
return -1;
}
- while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
- {
+ while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
@@ -1107,12 +1110,8 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
nies = os_realloc(ies, ies_len + len);
if (nies == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "out of memory. Cannot allocate memory for "
- "IE");
os_free(ies);
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
ies = nies;
@@ -1138,11 +1137,12 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
int freqs_num = 0;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Channels must be an array of structs");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Channels must be an array of structs",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong Channels value type. Array of structs "
- "required");
+ message,
+ "Wrong Channels value type. Array of structs required");
return -1;
}
@@ -1150,11 +1150,11 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
wpa_printf(MSG_DEBUG,
- "wpas_dbus_handler_scan[dbus]: Channels must be an "
- "array of structs");
+ "%s[dbus]: Channels must be an array of structs",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong Channels value type. Array of structs "
- "required");
+ message,
+ "Wrong Channels value type. Array of structs required");
return -1;
}
@@ -1166,14 +1166,14 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
DBUS_TYPE_UINT32) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Channel must by specified by struct of "
- "two UINT32s %c",
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
+ __func__,
dbus_message_iter_get_arg_type(
&sub_array_iter));
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong Channel struct. Two UINT32s "
- "required");
+ message,
+ "Wrong Channel struct. Two UINT32s required");
os_free(freqs);
return -1;
}
@@ -1182,9 +1182,9 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
if (!dbus_message_iter_next(&sub_array_iter) ||
dbus_message_iter_get_arg_type(&sub_array_iter) !=
DBUS_TYPE_UINT32) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Channel must by specified by struct of "
- "two UINT32s");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Channel must by specified by struct of two UINT32s",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
message,
"Wrong Channel struct. Two UINT32s required");
@@ -1204,11 +1204,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
freqs = nfreqs;
}
if (freqs == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "out of memory. can't allocate memory for "
- "freqs");
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
@@ -1223,10 +1219,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
os_free(freqs);
freqs = nfreqs;
if (freqs == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "out of memory. Can't allocate memory for freqs");
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
freqs[freqs_num] = 0;
@@ -1236,6 +1229,23 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message,
}
+static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
+ DBusMessageIter *var,
+ dbus_bool_t *allow,
+ DBusMessage **reply)
+{
+ if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
+ __func__);
+ *reply = wpas_dbus_error_invalid_args(
+ message, "Wrong Type value type. Boolean required");
+ return -1;
+ }
+ dbus_message_iter_get_basic(var, allow);
+ return 0;
+}
+
+
/**
* wpas_dbus_handler_scan - Request a wireless scan on an interface
* @message: Pointer to incoming dbus message
@@ -1254,6 +1264,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
char *key = NULL, *type = NULL;
struct wpa_driver_scan_params params;
size_t i;
+ dbus_bool_t allow_roam = 1;
os_memset(&params, 0, sizeof(params));
@@ -1262,7 +1273,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
dbus_message_iter_recurse(&iter, &dict_iter);
while (dbus_message_iter_get_arg_type(&dict_iter) ==
- DBUS_TYPE_DICT_ENTRY) {
+ DBUS_TYPE_DICT_ENTRY) {
dbus_message_iter_recurse(&dict_iter, &entry_iter);
dbus_message_iter_get_basic(&entry_iter, &key);
dbus_message_iter_next(&entry_iter);
@@ -1284,9 +1295,15 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
if (wpas_dbus_get_scan_channels(message, &variant_iter,
&params, &reply) < 0)
goto out;
+ } else if (os_strcmp(key, "AllowRoam") == 0) {
+ if (wpas_dbus_get_scan_allow_roam(message,
+ &variant_iter,
+ &allow_roam,
+ &reply) < 0)
+ goto out;
} else {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Unknown argument %s", key);
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
+ __func__, key);
reply = wpas_dbus_error_invalid_args(message, key);
goto out;
}
@@ -1295,27 +1312,31 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
}
if (!type) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Scan type not specified");
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
+ __func__);
reply = wpas_dbus_error_invalid_args(message, key);
goto out;
}
- if (!os_strcmp(type, "passive")) {
+ if (os_strcmp(type, "passive") == 0) {
if (params.num_ssids || params.extra_ies_len) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "SSIDs or IEs specified for passive scan.");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: SSIDs or IEs specified for passive scan.",
+ __func__);
reply = wpas_dbus_error_invalid_args(
- message, "You can specify only Channels in "
- "passive scan");
+ message,
+ "You can specify only Channels in passive scan");
goto out;
} else if (params.freqs && params.freqs[0]) {
- wpa_supplicant_trigger_scan(wpa_s, &params);
+ if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+ reply = wpas_dbus_error_scan_error(
+ message, "Scan request rejected");
+ }
} else {
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
- } else if (!os_strcmp(type, "active")) {
+ } else if (os_strcmp(type, "active") == 0) {
if (!params.num_ssids) {
/* Add wildcard ssid */
params.num_ssids++;
@@ -1323,15 +1344,21 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
#ifdef CONFIG_AUTOSCAN
autoscan_deinit(wpa_s);
#endif /* CONFIG_AUTOSCAN */
- wpa_supplicant_trigger_scan(wpa_s, &params);
+ if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+ reply = wpas_dbus_error_scan_error(
+ message, "Scan request rejected");
+ }
} else {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Unknown scan type: %s", type);
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
+ __func__, type);
reply = wpas_dbus_error_invalid_args(message,
"Wrong scan type");
goto out;
}
+ if (!allow_roam)
+ wpa_s->scan_res_handler = scan_only_handler;
+
out:
for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
os_free((u8 *) params.ssids[i].ssid);
@@ -1341,6 +1368,72 @@ out:
}
+/**
+ * wpas_dbus_handler_signal_poll - Request immediate signal properties
+ * @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 "SignalPoll" method call of a network device. Requests
+ * that wpa_supplicant read signal properties like RSSI, noise, and link
+ * speed and return them.
+ */
+DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ struct wpa_signal_info si;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, iter_dict, variant_iter;
+ int ret;
+
+ ret = wpa_drv_signal_poll(wpa_s, &si);
+ if (ret) {
+ return dbus_message_new_error(message, DBUS_ERROR_FAILED,
+ "Failed to read signal");
+ }
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL)
+ goto nomem;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+ si.current_signal) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+ si.current_txrate / 1000) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+ si.current_noise) ||
+ !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+ si.frequency) ||
+ (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
+ !wpa_dbus_dict_append_string(
+ &iter_dict, "width",
+ channel_width_to_string(si.chanwidth))) ||
+ (si.center_frq1 > 0 && si.center_frq2 > 0 &&
+ (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+ si.center_frq1) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+ si.center_frq2))) ||
+ (si.avg_signal &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+ si.avg_signal)) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(&iter, &variant_iter))
+ goto nomem;
+
+ return reply;
+
+nomem:
+ if (reply)
+ dbus_message_unref(reply);
+ return wpas_dbus_error_no_memory(message);
+}
+
+
/*
* wpas_dbus_handler_disconnect - Terminate the current connection
* @message: Pointer to incoming dbus message
@@ -1387,12 +1480,11 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
- wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
- "can't add new interface.");
+ wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
+ __func__);
reply = wpas_dbus_error_unknown_error(
message,
- "wpa_supplicant could not add "
- "a network on this interface.");
+ "wpa_supplicant could not add a network on this interface.");
goto err;
}
wpas_notify_network_added(wpa_s, ssid);
@@ -1401,9 +1493,9 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
- "control interface couldn't set network "
- "properties");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: control interface couldn't set network properties",
+ __func__);
reply = wpas_dbus_reply_new_from_error(message, &error,
DBUS_ERROR_INVALID_ARGS,
"Failed to add network");
@@ -1418,15 +1510,13 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
reply = dbus_message_new_method_return(message);
if (reply == NULL) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
@@ -1442,10 +1532,10 @@ err:
/**
- * wpas_dbus_handler_reassociate - Reassociate to current AP
+ * wpas_dbus_handler_reassociate - Reassociate
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NotConnected DBus error message if not connected
+ * Returns: InterfaceDisabled DBus error message if disabled
* or NULL otherwise.
*
* Handler function for "Reassociate" method call of network interface.
@@ -1453,7 +1543,30 @@ err:
DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
+ wpas_request_connection(wpa_s);
+ return NULL;
+ }
+
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
+ "This interface is disabled");
+}
+
+
+/**
+ * wpas_dbus_handler_reattach - Reattach to current AP
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NotConnected DBus error message if not connected
+ * or NULL otherwise.
+ *
+ * Handler function for "Reattach" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
if (wpa_s->current_ssid != NULL) {
+ wpa_s->reattach = 1;
wpas_request_connection(wpa_s);
return NULL;
}
@@ -1476,16 +1589,19 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
+ int was_disabled;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
if (iface == NULL || net_id == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
@@ -1505,25 +1621,32 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *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) {
wpa_printf(MSG_ERROR,
- "wpas_dbus_handler_remove_network[dbus]: "
- "error occurred when removing network %d", id);
+ "%s[dbus]: error occurred when removing network %d",
+ __func__, id);
reply = wpas_dbus_error_unknown_error(
- message, "error removing the specified network on "
- "this interface.");
+ message,
+ "error removing the specified network on is interface.");
goto out;
}
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
out:
os_free(iface);
- os_free(net_id);
return reply;
}
@@ -1536,9 +1659,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
wpa_printf(MSG_ERROR,
- "wpas_dbus_handler_remove_all_networks[dbus]: "
- "error occurred when removing network %d",
- ssid->id);
+ "%s[dbus]: error occurred when removing network %d",
+ __func__, ssid->id);
return;
}
@@ -1559,6 +1681,9 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
DBusMessage * wpas_dbus_handler_remove_all_networks(
DBusMessage *message, struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
/* NB: could check for failure and return an error */
wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
return NULL;
@@ -1578,7 +1703,7 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
@@ -1587,7 +1712,9 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
if (iface == NULL || net_id == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
@@ -1612,7 +1739,6 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
out:
os_free(iface);
- os_free(net_id);
return reply;
}
@@ -1631,20 +1757,22 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
#ifdef IEEE8021X_EAPOL
DBusMessage *reply = NULL;
const char *op, *field, *value;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_STRING, &field,
- DBUS_TYPE_STRING, &value,
- DBUS_TYPE_INVALID))
+ DBUS_TYPE_OBJECT_PATH, &op,
+ DBUS_TYPE_STRING, &field,
+ DBUS_TYPE_STRING, &value,
+ DBUS_TYPE_INVALID))
return wpas_dbus_error_invalid_args(message, NULL);
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
if (iface == NULL || net_id == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
@@ -1674,7 +1802,6 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
out:
os_free(iface);
- os_free(net_id);
return reply;
#else /* IEEE8021X_EAPOL */
wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
@@ -1683,6 +1810,8 @@ out:
}
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
/**
* wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
* @message: Pointer to incoming dbus message
@@ -1718,26 +1847,18 @@ DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
blob = os_zalloc(sizeof(*blob));
if (!blob) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
blob->data = os_malloc(blob_len);
- if (!blob->data) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ 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;
- blob->name = os_strdup(blob_name);
- if (!blob->name) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto err;
- }
wpa_config_set_blob(wpa_s->conf, blob);
wpas_notify_blob_added(wpa_s, blob->name);
@@ -1782,39 +1903,21 @@ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
}
reply = dbus_message_new_method_return(message);
- if (!reply) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
- }
+ if (!reply)
+ return wpas_dbus_error_no_memory(message);
dbus_message_iter_init_append(reply, &iter);
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
- &array_iter)) {
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+ &(blob->data), blob->len) ||
+ !dbus_message_iter_close_container(&iter, &array_iter)) {
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
- }
-
- if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
- &(blob->data), blob->len)) {
- dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
- }
-
- if (!dbus_message_iter_close_container(&iter, &array_iter)) {
- dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
+ reply = wpas_dbus_error_no_memory(message);
}
-out:
return reply;
}
@@ -1847,6 +1950,9 @@ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
/*
* wpas_dbus_handler_flush_bss - Flush the BSS cache
* @message: Pointer to incoming dbus message
@@ -1893,11 +1999,10 @@ DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
if (arg != NULL && os_strlen(arg) > 0) {
char *tmp;
+
tmp = os_strdup(arg);
if (tmp == NULL) {
- reply = dbus_message_new_error(message,
- DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
} else {
os_free(wpa_s->conf->autoscan);
wpa_s->conf->autoscan = tmp;
@@ -1920,6 +2025,258 @@ DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
#endif /* CONFIG_AUTOSCAN */
+/*
+ * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogoff" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "EAPLogin" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ return NULL;
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
+ u8 *peer_address, DBusMessage **error)
+{
+ const char *peer_string;
+
+ *error = NULL;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &peer_string,
+ DBUS_TYPE_INVALID)) {
+ *error = wpas_dbus_error_invalid_args(message, NULL);
+ return -1;
+ }
+
+ if (hwaddr_aton(peer_string, peer_address)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
+ func_name, peer_string);
+ *error = wpas_dbus_error_invalid_args(
+ message, "Invalid hardware address format");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_discover - Discover 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 "TDLSDiscover" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_discover(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_DISCOVER " MACSTR, MAC2STR(peer));
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+ if (ret) {
+ return wpas_dbus_error_unknown_error(
+ message, "error performing TDLS discovery");
+ }
+
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_setup - Setup TDLS session
+ * @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 "TDLSSetup" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_setup(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_SETUP " MACSTR, MAC2STR(peer));
+
+ wpa_tdls_remove(wpa_s->wpa, peer);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_start(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
+ if (ret) {
+ return wpas_dbus_error_unknown_error(
+ message, "error performing TDLS setup");
+ }
+
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_status - Return TDLS session status
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A string representing the state of the link to this TDLS peer
+ *
+ * Handler function for "TDLSStatus" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 peer[ETH_ALEN];
+ DBusMessage *reply;
+ const char *tdls_status;
+
+ if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
+ return reply;
+
+ wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
+
+ tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_STRING,
+ &tdls_status, DBUS_TYPE_INVALID);
+ return reply;
+}
+
+
+/*
+ * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
+ * @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 "TDLSTeardown" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_tdls_teardown(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_TEARDOWN " MACSTR, MAC2STR(peer));
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_teardown_link(
+ wpa_s->wpa, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ if (ret) {
+ return wpas_dbus_error_unknown_error(
+ message, "error performing TDLS teardown");
+ }
+
+ return NULL;
+}
+
+#endif /* CONFIG_TDLS */
+
+
+/**
+ * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing an error on failure or NULL on success
+ *
+ * Sets the PKCS #11 engine and module path.
+ */
+DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter;
+ char *value = NULL;
+ char *pkcs11_engine_path = NULL;
+ char *pkcs11_module_path = NULL;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &value);
+ if (value == NULL) {
+ return dbus_message_new_error(
+ message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid pkcs11_engine_path argument");
+ }
+ /* Empty path defaults to NULL */
+ if (os_strlen(value))
+ pkcs11_engine_path = value;
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &value);
+ if (value == NULL) {
+ os_free(pkcs11_engine_path);
+ return dbus_message_new_error(
+ message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid pkcs11_module_path argument");
+ }
+ /* Empty path defaults to NULL */
+ if (os_strlen(value))
+ pkcs11_module_path = value;
+
+ if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
+ pkcs11_module_path))
+ return dbus_message_new_error(
+ message, DBUS_ERROR_FAILED,
+ "Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
+
+ wpa_dbus_mark_property_changed(
+ wpa_s->global->dbus, wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
+ wpa_dbus_mark_property_changed(
+ wpa_s->global->dbus, wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
+
+ return NULL;
+}
+
+
/**
* wpas_dbus_getter_capabilities - Return interface capabilities
* @iter: Pointer to incoming dbus message iter
@@ -1940,10 +2297,8 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *scans[] = { "active", "passive", "ssid" };
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
goto nomem;
res = wpa_drv_get_capa(wpa_s, &capa);
@@ -1951,42 +2306,35 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
/***** pairwise cipher */
if (res < 0) {
const char *args[] = {"ccmp", "tkip", "none"};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "gcmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "tkip"))
- goto nomem;
- }
-
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "none"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp")) ||
+ ((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))
@@ -1998,48 +2346,38 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *args[] = {
"ccmp", "tkip", "wep104", "wep40"
};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Group", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "gcmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "tkip"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wep104"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wep40"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp")) ||
+ ((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))
@@ -2057,34 +2395,28 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "KeyMgmt", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
- "none"))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+ &iter_array) ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "none") ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
"ieee8021x"))
goto nomem;
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-eap"))
+ &iter_array, "wpa-eap") ||
+ ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa-ft-eap")))
goto nomem;
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-eap"))
- goto nomem;
-
/* TODO: Ensure that driver actually supports sha256 encryption. */
#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
@@ -2096,14 +2428,13 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-psk"))
+ &iter_array, "wpa-psk") ||
+ ((capa.key_mgmt &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa-ft-psk")))
goto nomem;
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-psk"))
- goto nomem;
-
/* TODO: Ensure that driver actually supports sha256 encryption. */
#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
@@ -2112,11 +2443,10 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
#endif /* CONFIG_IEEE80211W */
}
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-none"))
- goto nomem;
- }
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "wpa-none"))
+ goto nomem;
#ifdef CONFIG_WPS
@@ -2135,32 +2465,25 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
/***** WPA protocol */
if (res < 0) {
const char *args[] = { "rsn", "wpa" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Protocol", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "rsn"))
- goto nomem;
- }
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &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))
@@ -2170,9 +2493,10 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
/***** auth alg */
if (res < 0) {
const char *args[] = { "open", "shared", "leap" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "AuthAlg", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
@@ -2181,25 +2505,16 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
&iter_array))
goto nomem;
- if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "open"))
- goto nomem;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "shared"))
- goto nomem;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "leap"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ if (((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))
@@ -2208,39 +2523,25 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
/***** Scan */
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
- sizeof(scans) / sizeof(char *)))
+ ARRAY_SIZE(scans)))
goto nomem;
/***** Modes */
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "infrastructure"))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ad-hoc"))
- goto nomem;
-
- if (res >= 0) {
- if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ap"))
- goto nomem;
- }
-
- if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "p2p"))
- goto nomem;
- }
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &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_AP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ap")) ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "p2p")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -2255,9 +2556,8 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
goto nomem;
}
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
@@ -2318,7 +2618,7 @@ 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)
+ void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
@@ -2440,6 +2740,7 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t reason = wpa_s->disconnect_reason;
+
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
&reason, error);
}
@@ -2694,8 +2995,8 @@ dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
const char *driver;
if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
- "wpa_s has no driver set");
+ wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
+ __func__);
dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
__func__);
return FALSE;
@@ -2815,6 +3116,7 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
{
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);
}
@@ -2889,14 +3191,6 @@ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
unsigned int i = 0, num = 0;
dbus_bool_t success = FALSE;
- if (wpa_s->conf == NULL) {
- wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
- "networks list.", __func__);
- dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
- "occurred getting the networks list", __func__);
- return FALSE;
- }
-
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
if (!network_is_persistent_group(ssid))
num++;
@@ -2913,7 +3207,8 @@ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
continue;
paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
if (paths[i] == NULL) {
- dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
goto out;
}
@@ -2936,6 +3231,56 @@ out:
/**
+ * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 engine path
+ *
+ * Getter for "PKCS11EnginePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(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);
+}
+
+
+/**
+ * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: A dbus message containing the PKCS #11 module path
+ *
+ * Getter for "PKCS11ModulePath" property.
+ */
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(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);
+}
+
+
+/**
* wpas_dbus_getter_blobs - Get all blobs defined for this interface
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3004,7 +3349,7 @@ static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
if (!res) {
wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
- func_name, args->id);
+ func_name, args->id);
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: BSS %d not found",
func_name, args->id);
@@ -3109,11 +3454,22 @@ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
res = get_bss_helper(args, error, __func__);
if (!res)
return FALSE;
-
- if (res->caps & IEEE80211_CAP_IBSS)
- mode = "ad-hoc";
- else
- mode = "infrastructure";
+ if (bss_is_dmg(res)) {
+ switch (res->caps & IEEE80211_CAP_DMG_MASK) {
+ case IEEE80211_CAP_DMG_PBSS:
+ case IEEE80211_CAP_DMG_IBSS:
+ mode = "ad-hoc";
+ break;
+ case IEEE80211_CAP_DMG_AP:
+ mode = "infrastructure";
+ break;
+ }
+ } else {
+ if (res->caps & IEEE80211_CAP_IBSS)
+ mode = "ad-hoc";
+ else
+ mode = "infrastructure";
+ }
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&mode, error);
@@ -3233,8 +3589,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
- const char *pairwise[3]; /* max 3 pairwise ciphers is supported */
- const char *key_mgmt[7]; /* max 7 key managements may be supported */
+ const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
+ const char *key_mgmt[9]; /* max 9 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3258,6 +3614,14 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
key_mgmt[n++] = "wpa-ft-eap";
if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
key_mgmt[n++] = "wpa-eap-sha256";
+#ifdef CONFIG_SUITEB
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+ key_mgmt[n++] = "wpa-eap-suite-b";
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ key_mgmt[n++] = "wpa-eap-suite-b-192";
+#endif /* CONFIG_SUITEB192 */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -3282,6 +3646,12 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
case WPA_CIPHER_WEP104:
group = "wep104";
break;
+ case WPA_CIPHER_CCMP_256:
+ group = "ccmp-256";
+ break;
+ case WPA_CIPHER_GCMP_256:
+ group = "gcmp-256";
+ break;
default:
group = "";
break;
@@ -3298,6 +3668,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
pairwise[n++] = "ccmp";
if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
pairwise[n++] = "gcmp";
+ if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
+ pairwise[n++] = "ccmp-256";
+ if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
+ pairwise[n++] = "gcmp-256";
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
pairwise, n))
@@ -3321,9 +3695,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
goto nomem;
}
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
@@ -3357,12 +3730,10 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
os_memset(&wpa_data, 0, sizeof(wpa_data));
ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
- if (ie) {
- if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "failed to parse WPA IE");
- return FALSE;
- }
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "failed to parse WPA IE");
+ return FALSE;
}
return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3392,12 +3763,10 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
os_memset(&wpa_data, 0, sizeof(wpa_data));
ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
- if (ie) {
- if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "failed to parse RSN IE");
- return FALSE;
- }
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "failed to parse RSN IE");
+ return FALSE;
}
return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3429,10 +3798,8 @@ dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
return FALSE;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
goto nomem;
#ifdef CONFIG_WPS
@@ -3442,15 +3809,14 @@ dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
type = "pbc";
else if (wps_is_selected_pin_registrar(wps_ie))
type = "pin";
+
+ wpabuf_free(wps_ie);
}
#endif /* CONFIG_WPS */
- if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
- goto nomem;
-
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
@@ -3487,6 +3853,35 @@ dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
/**
+ * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
+ * @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 BSS age
+ */
+dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
+ void *user_data)
+{
+ struct bss_handler_args *args = user_data;
+ struct wpa_bss *res;
+ struct os_reltime now, diff = { 0, 0 };
+ u32 age;
+
+ res = get_bss_helper(args, error, __func__);
+ if (!res)
+ return FALSE;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &res->last_update, &diff);
+ age = diff.sec > 0 ? diff.sec : 0;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
+ error);
+}
+
+
+/**
* wpas_dbus_getter_enabled - Check whether network is enabled or disabled
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3643,8 +4038,7 @@ DBusMessage * wpas_dbus_handler_subscribe_preq(
name = os_strdup(dbus_message_get_sender(message));
if (!name)
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- "out of memory");
+ return wpas_dbus_error_no_memory(message);
wpa_s->preq_notify_peer = name;
@@ -3724,28 +4118,22 @@ void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto fail;
- if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
- (const char *) addr,
- ETH_ALEN))
- goto fail;
- if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
- (const char *) dst,
- ETH_ALEN))
- goto fail;
- if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
- (const char *) bssid,
- ETH_ALEN))
- goto fail;
- if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
- (const char *) ie,
- ie_len))
- goto fail;
- if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
- ssi_signal))
- goto fail;
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+ (const char *) addr,
+ ETH_ALEN)) ||
+ (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+ (const char *) dst,
+ ETH_ALEN)) ||
+ (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+ (const char *) bssid,
+ ETH_ALEN)) ||
+ (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+ (const char *) ie,
+ ie_len)) ||
+ (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+ ssi_signal)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
goto fail;
dbus_connection_send(priv->con, msg, NULL);
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
index aa56550..6113db5 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -55,8 +55,8 @@ dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
void *user_data);
dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
DBusError *error,
@@ -87,6 +87,9 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -101,6 +104,9 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -122,12 +128,21 @@ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+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);
@@ -212,6 +227,14 @@ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
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);
@@ -248,6 +271,9 @@ dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
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);
@@ -272,10 +298,28 @@ 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);
+
+DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+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_error_invalid_args(DBusMessage *message,
const char *arg);
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
const char *arg);
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message);
DBusMessage * wpas_dbus_handler_subscribe_preq(
DBusMessage *message, struct wpa_supplicant *wpa_s);
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 30e0eb3..0eff763 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -26,6 +26,7 @@
#include "ap/wps_hostapd.h"
#include "../p2p_supplicant.h"
+#include "../wifi_display.h"
/**
* Parses out the mac address from the peer object path.
@@ -34,9 +35,9 @@
* @addr - out param must be of ETH_ALEN size
* Returns 0 if valid (including MAC), -1 otherwise
*/
-static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+static int parse_peer_object_path(const char *peer_path, u8 addr[ETH_ALEN])
{
- char *p;
+ const char *p;
if (!peer_path)
return -1;
@@ -56,12 +57,12 @@ static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
*
* Convenience function to create and return an invalid persistent group error.
*/
-static DBusMessage * wpas_dbus_error_persistent_group_unknown(
- DBusMessage *message)
+static DBusMessage *
+wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
{
- return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
- "There is no such persistent group in "
- "this P2P device.");
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+ "There is no such persistent group in this P2P device.");
}
@@ -73,7 +74,7 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
DBusMessageIter iter;
DBusMessageIter iter_dict;
unsigned int timeout = 0;
- enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
+ enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
int num_req_dev_types = 0;
unsigned int i;
u8 *req_dev_types = NULL;
@@ -88,12 +89,12 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "Timeout") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ if (os_strcmp(entry.key, "Timeout") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
timeout = entry.uint32_value;
} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != WPAS_DBUS_TYPE_BINARRAY)
goto error_clear;
os_free(req_dev_types);
@@ -104,20 +105,20 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
for (i = 0; i < entry.array_len; i++) {
if (wpabuf_len(entry.binarray_value[i]) !=
- WPS_DEV_TYPE_LEN)
+ WPS_DEV_TYPE_LEN)
goto error_clear;
os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
wpabuf_head(entry.binarray_value[i]),
WPS_DEV_TYPE_LEN);
}
num_req_dev_types = entry.array_len;
- } else if (!os_strcmp(entry.key, "DiscoveryType") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "start_with_full"))
+ } else if (os_strcmp(entry.key, "DiscoveryType") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "start_with_full") == 0)
type = P2P_FIND_START_WITH_FULL;
- else if (!os_strcmp(entry.str_value, "social"))
+ else if (os_strcmp(entry.str_value, "social") == 0)
type = P2P_FIND_ONLY_SOCIAL;
- else if (!os_strcmp(entry.str_value, "progressive"))
+ else if (os_strcmp(entry.str_value, "progressive") == 0)
type = P2P_FIND_PROGRESSIVE;
else
goto error_clear;
@@ -126,8 +127,11 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
wpa_dbus_dict_entry_clear(&entry);
}
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL, 0);
+ NULL, 0, 0, NULL, 0);
os_free(req_dev_types);
return reply;
@@ -143,6 +147,9 @@ error:
DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
wpas_p2p_stop_find(wpa_s);
return NULL;
}
@@ -161,6 +168,9 @@ DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
return wpas_dbus_error_invalid_args(message, NULL);
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to call wpas_p2p_reject method.");
@@ -176,12 +186,16 @@ DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
DBUS_TYPE_INVALID))
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
+
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
- if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+ "Could not start P2P listen");
+ }
return NULL;
}
@@ -205,17 +219,20 @@ DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "period") &&
- (entry.type == DBUS_TYPE_INT32))
+ if (os_strcmp(entry.key, "period") == 0 &&
+ entry.type == DBUS_TYPE_INT32)
period = entry.uint32_value;
- else if (!os_strcmp(entry.key, "interval") &&
- (entry.type == DBUS_TYPE_INT32))
+ else if (os_strcmp(entry.key, "interval") == 0 &&
+ entry.type == DBUS_TYPE_INT32)
interval = entry.uint32_value;
else
goto error_clear;
wpa_dbus_dict_entry_clear(&entry);
}
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_ext_listen(wpa_s, period, interval))
return wpas_dbus_error_unknown_error(
message, "failed to initiate a p2p_ext_listen.");
@@ -247,16 +264,16 @@ DBusMessage * wpas_dbus_handler_p2p_presence_request(
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "duration1") &&
- (entry.type == DBUS_TYPE_INT32))
+ if (os_strcmp(entry.key, "duration1") == 0 &&
+ entry.type == DBUS_TYPE_INT32)
dur1 = entry.uint32_value;
- else if (!os_strcmp(entry.key, "interval1") &&
+ else if (os_strcmp(entry.key, "interval1") == 0 &&
entry.type == DBUS_TYPE_INT32)
int1 = entry.uint32_value;
- else if (!os_strcmp(entry.key, "duration2") &&
+ else if (os_strcmp(entry.key, "duration2") == 0 &&
entry.type == DBUS_TYPE_INT32)
dur2 = entry.uint32_value;
- else if (!os_strcmp(entry.key, "interval2") &&
+ else if (os_strcmp(entry.key, "interval2") == 0 &&
entry.type == DBUS_TYPE_INT32)
int2 = entry.uint32_value;
else
@@ -264,6 +281,10 @@ DBusMessage * wpas_dbus_handler_p2p_presence_request(
wpa_dbus_dict_entry_clear(&entry);
}
+
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to invoke presence request.");
@@ -288,7 +309,6 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
int persistent_group = 0;
int freq = 0;
char *iface = NULL;
- char *net_id_str = NULL;
unsigned int group_id = 0;
struct wpa_ssid *ssid;
@@ -301,15 +321,16 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto inv_args;
- if (!os_strcmp(entry.key, "persistent") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "frequency") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ if (os_strcmp(entry.key, "persistent") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ persistent_group = entry.bool_value;
+ } else if (os_strcmp(entry.key, "frequency") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
freq = entry.int32_value;
if (freq <= 0)
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "persistent_group_object") &&
+ } else if (os_strcmp(entry.key, "persistent_group_object") ==
+ 0 &&
entry.type == DBUS_TYPE_OBJECT_PATH)
pg_object_path = os_strdup(entry.str_value);
else
@@ -318,15 +339,21 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
wpa_dbus_dict_entry_clear(&entry);
}
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (pg_object_path != NULL) {
+ char *net_id_str;
+
/*
* A persistent group Object Path is defined meaning we want
* to re-invoke a persistent group.
*/
- iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
- &net_id_str, NULL);
- if (iface == NULL ||
+ iface = wpas_dbus_new_decompose_object_path(
+ pg_object_path, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+ &net_id_str);
+ if (iface == NULL || net_id_str == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply =
wpas_dbus_error_invalid_args(message,
@@ -346,18 +373,18 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
- if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
+ NULL, 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))
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
goto inv_args;
out:
os_free(pg_object_path);
- os_free(net_id_str);
os_free(iface);
return reply;
inv_args_clear:
@@ -392,8 +419,7 @@ static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
"P2P is not available for this interface");
}
dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "P2P is not available for this "
- "interface");
+ "P2P is not available for this interface");
return FALSE;
}
return TRUE;
@@ -408,6 +434,9 @@ DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
return reply;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->force_long_sd = 0;
p2p_flush(wpa_s->global->p2p);
@@ -448,42 +477,42 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto inv_args;
- if (!os_strcmp(entry.key, "peer") &&
- (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ if (os_strcmp(entry.key, "peer") == 0 &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "persistent") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "join") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- join = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "authorize_only") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "frequency") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ } else if (os_strcmp(entry.key, "persistent") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ persistent_group = entry.bool_value;
+ } else if (os_strcmp(entry.key, "join") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ join = entry.bool_value;
+ } else if (os_strcmp(entry.key, "authorize_only") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ authorize_only = entry.bool_value;
+ } else if (os_strcmp(entry.key, "frequency") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
freq = entry.int32_value;
if (freq <= 0)
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "go_intent") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ } else if (os_strcmp(entry.key, "go_intent") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
go_intent = entry.int32_value;
if ((go_intent < 0) || (go_intent > 15))
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "wps_method") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "pbc"))
+ } else if (os_strcmp(entry.key, "wps_method") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "pbc") == 0)
wps_method = WPS_PBC;
- else if (!os_strcmp(entry.str_value, "pin"))
+ else if (os_strcmp(entry.str_value, "pin") == 0)
wps_method = WPS_PIN_DISPLAY;
- else if (!os_strcmp(entry.str_value, "display"))
+ else if (os_strcmp(entry.str_value, "display") == 0)
wps_method = WPS_PIN_DISPLAY;
- else if (!os_strcmp(entry.str_value, "keypad"))
+ else if (os_strcmp(entry.str_value, "keypad") == 0)
wps_method = WPS_PIN_KEYPAD;
else
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "pin") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ } else if (os_strcmp(entry.key, "pin") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
pin = os_strdup(entry.str_value);
} else
goto inv_args_clear;
@@ -491,24 +520,28 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
wpa_dbus_dict_entry_clear(&entry);
}
- if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
- (parse_peer_object_path(peer_object_path, addr) < 0) ||
+ if (wps_method == WPS_NOT_READY ||
+ parse_peer_object_path(peer_object_path, addr) < 0 ||
!p2p_peer_known(wpa_s->global->p2p, addr))
goto inv_args;
/*
* Validate the wps_method specified and the pin value.
*/
- if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
+ if ((!pin || !pin[0]) && wps_method == WPS_PIN_KEYPAD)
goto inv_args;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, -1, 0, 0);
+ go_intent, freq, -1, 0, 0, 0);
if (new_pin >= 0) {
char npin[9];
char *generated_pin;
+
os_snprintf(npin, sizeof(npin), "%08d", new_pin);
generated_pin = npin;
reply = dbus_message_new_method_return(message);
@@ -517,8 +550,8 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
} else {
switch (new_pin) {
case -2:
- err_msg = "connect failed due to channel "
- "unavailability.";
+ err_msg =
+ "connect failed due to channel unavailability.";
iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
break;
@@ -564,7 +597,6 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
char *peer_object_path = NULL;
char *pg_object_path = NULL;
char *iface = NULL;
- char *net_id_str = NULL;
u8 peer_addr[ETH_ALEN];
unsigned int group_id = 0;
int persistent = 0;
@@ -582,12 +614,13 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto err;
- if (!os_strcmp(entry.key, "peer") &&
- (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ if (os_strcmp(entry.key, "peer") == 0 &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
- } else if (!os_strcmp(entry.key, "persistent_group_object") &&
- (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ } else if (os_strcmp(entry.key, "persistent_group_object") ==
+ 0 &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
pg_object_path = os_strdup(entry.str_value);
persistent = 1;
wpa_dbus_dict_entry_clear(&entry);
@@ -597,21 +630,25 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
}
}
- if (!peer_object_path ||
- (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
- !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
+ if (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
+ !p2p_peer_known(wpa_s->global->p2p, peer_addr))
goto err;
- }
+
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
if (persistent) {
+ char *net_id_str;
/*
* A group ID is defined meaning we want to re-invoke a
* persistent group
*/
- iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
- &net_id_str, NULL);
- if (iface == NULL ||
+ iface = wpas_dbus_new_decompose_object_path(
+ pg_object_path,
+ WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+ &net_id_str);
+ if (iface == NULL || net_id_str == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message,
pg_object_path);
@@ -630,7 +667,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) {
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
+ 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -649,6 +687,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
}
out:
+ os_free(iface);
os_free(pg_object_path);
os_free(peer_object_path);
return reply;
@@ -687,8 +726,11 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
os_strcmp(config_method, "pushbutton"))
return wpas_dbus_error_invalid_args(message, NULL);
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
- WPAS_P2P_PD_FOR_GO_NEG) < 0)
+ WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to send provision discovery request");
@@ -716,6 +758,9 @@ dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
return FALSE;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
"a{sv}", &variant_iter) ||
!wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
@@ -729,8 +774,8 @@ dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
/* Primary device type */
if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
- (char *)wpa_s->conf->device_type,
- WPS_DEV_TYPE_LEN))
+ (char *) wpa_s->conf->device_type,
+ WPS_DEV_TYPE_LEN))
goto err_no_mem;
/* Secondary device types */
@@ -765,65 +810,37 @@ dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
wpa_s->conf->wps_vendor_ext[i];
}
- if (num_vendor_extensions &&
- !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
- "VendorExtension",
- vendor_ext,
- num_vendor_extensions))
- goto err_no_mem;
-
- /* GO Intent */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
- wpa_s->conf->p2p_go_intent))
- goto err_no_mem;
-
- /* Persistent Reconnect */
- if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
- wpa_s->conf->persistent_reconnect))
- goto err_no_mem;
-
- /* Listen Reg Class */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
- wpa_s->conf->p2p_listen_reg_class))
- goto err_no_mem;
-
- /* Listen Channel */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
- wpa_s->conf->p2p_listen_channel))
- goto err_no_mem;
-
- /* Oper Reg Class */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
- wpa_s->conf->p2p_oper_reg_class))
- goto err_no_mem;
-
- /* Oper Channel */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
- wpa_s->conf->p2p_oper_channel))
- goto err_no_mem;
-
- /* SSID Postfix */
- if (wpa_s->conf->p2p_ssid_postfix &&
- !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
- wpa_s->conf->p2p_ssid_postfix))
- goto err_no_mem;
-
- /* Intra Bss */
- if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
- wpa_s->conf->p2p_intra_bss))
- goto err_no_mem;
-
- /* Group Idle */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
- wpa_s->conf->p2p_group_idle))
- goto err_no_mem;
-
- /* Dissasociation low ack */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
- wpa_s->conf->disassoc_low_ack))
- goto err_no_mem;
-
- if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+ if ((num_vendor_extensions &&
+ !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+ "VendorExtension",
+ vendor_ext,
+ num_vendor_extensions)) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+ wpa_s->conf->p2p_go_intent) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
+ wpa_s->conf->persistent_reconnect) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+ wpa_s->conf->p2p_listen_reg_class) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+ wpa_s->conf->p2p_listen_channel) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+ wpa_s->conf->p2p_oper_reg_class) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+ wpa_s->conf->p2p_oper_channel) ||
+ (wpa_s->conf->p2p_ssid_postfix &&
+ !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+ wpa_s->conf->p2p_ssid_postfix)) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+ wpa_s->conf->p2p_intra_bss) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+ wpa_s->conf->p2p_group_idle) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+ wpa_s->conf->disassoc_low_ack) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
+ wpa_s->conf->p2p_no_group_iface) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
+ wpa_s->conf->p2p_search_delay) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
!dbus_message_iter_close_container(iter, &variant_iter))
goto err_no_mem;
@@ -847,6 +864,9 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
return FALSE;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
dbus_message_iter_recurse(iter, &variant_iter);
if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
return FALSE;
@@ -902,8 +922,8 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
wpa_s->conf->changed_parameters |=
CFG_CHANGED_SEC_DEVICE_TYPE;
} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
(entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
goto error;
@@ -919,30 +939,30 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
} else
wpa_s->conf->wps_vendor_ext[i] = NULL;
}
- } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
- (entry.type == DBUS_TYPE_UINT32) &&
+ } else if (os_strcmp(entry.key, "GOIntent") == 0 &&
+ entry.type == DBUS_TYPE_UINT32 &&
(entry.uint32_value <= 15))
wpa_s->conf->p2p_go_intent = entry.uint32_value;
- else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
- (entry.type == DBUS_TYPE_BOOLEAN))
+ else if (os_strcmp(entry.key, "PersistentReconnect") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN)
wpa_s->conf->persistent_reconnect = entry.bool_value;
- else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ else if (os_strcmp(entry.key, "ListenRegClass") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_LISTEN_CHANNEL;
- } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ } else if (os_strcmp(entry.key, "ListenChannel") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_listen_channel = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_LISTEN_CHANNEL;
- } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ } else if (os_strcmp(entry.key, "OperRegClass") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_OPER_CHANNEL;
- } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ } else if (os_strcmp(entry.key, "OperChannel") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_oper_channel = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_OPER_CHANNEL;
@@ -961,17 +981,23 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_SSID_POSTFIX;
- } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
+ } else if (os_strcmp(entry.key, "IntraBss") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
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, "GroupIdle") == 0) &&
- (entry.type == DBUS_TYPE_UINT32))
+ } else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
+ entry.type == DBUS_TYPE_UINT32)
wpa_s->conf->p2p_group_idle = entry.uint32_value;
else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
entry.type == DBUS_TYPE_UINT32)
wpa_s->conf->disassoc_low_ack = entry.uint32_value;
+ else if (os_strcmp(entry.key, "NoGroupIface") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN)
+ wpa_s->conf->p2p_no_group_iface = entry.bool_value;
+ else if (os_strcmp(entry.key, "p2p_search_delay") == 0 &&
+ entry.type == DBUS_TYPE_UINT32)
+ wpa_s->conf->p2p_search_delay = entry.uint32_value;
else
goto error;
@@ -1125,6 +1151,7 @@ dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
break;
default:
str = "device";
+ break;
}
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
@@ -1240,8 +1267,8 @@ 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)
+ DBusError *error,
+ void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1265,8 +1292,8 @@ 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)
+ DBusError *error,
+ void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1290,8 +1317,8 @@ 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)
+ DBusError *error,
+ void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1349,8 +1376,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
peer_args->p2p_device_addr, 0);
if (info == NULL) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "failed to find peer");
+ dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
return FALSE;
}
@@ -1358,18 +1384,13 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
- &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 1", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
&array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 2", __func__);
+ "%s: failed to construct message 1", __func__);
return FALSE;
}
@@ -1384,29 +1405,14 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
if (!dbus_message_iter_open_container(
&array_iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
- &inner_array_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct "
- "message 3 (%d)",
- __func__, i);
- return FALSE;
- }
-
- if (!dbus_message_iter_append_fixed_array(
+ &inner_array_iter) ||
+ !dbus_message_iter_append_fixed_array(
&inner_array_iter, DBUS_TYPE_BYTE,
- &sec_dev_type_list, WPS_DEV_TYPE_LEN)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct "
- "message 4 (%d)",
- __func__, i);
- return FALSE;
- }
-
- if (!dbus_message_iter_close_container(
+ &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
+ !dbus_message_iter_close_container(
&array_iter, &inner_array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct "
- "message 5 (%d)",
+ "%s: failed to construct message 2 (%d)",
__func__, i);
return FALSE;
}
@@ -1415,15 +1421,10 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
}
}
- if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 6", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_close_container(iter, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 7", __func__);
+ "%s: failed to construct message 3", __func__);
return FALSE;
}
@@ -1436,7 +1437,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
void *user_data)
{
struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
- int i, num;
+ unsigned int i, num = 0;
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1449,7 +1450,8 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
}
/* Add WPS vendor extensions attribute */
- for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+ os_memset(vendor_extension, 0, sizeof(vendor_extension));
+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
if (info->wps_vendor_ext[i] == NULL)
continue;
vendor_extension[num] = info->wps_vendor_ext[i];
@@ -1468,11 +1470,149 @@ 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 success;
- /* struct peer_handler_args *peer_args = 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 == NULL) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "failed to find peer");
+ return FALSE;
+ }
+
+ if (info->wfd_subelems == NULL)
+ 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->wfd_subelems->buf,
+ info->wfd_subelems->used, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(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 == NULL) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "failed to find peer");
+ return FALSE;
+ }
+
+ return wpas_dbus_simple_array_property_getter(
+ iter, DBUS_TYPE_BYTE, (char *) info->p2p_device_addr,
+ ETH_ALEN, error);
+}
+
+
+struct peer_group_data {
+ struct wpa_supplicant *wpa_s;
+ const struct p2p_peer_info *info;
+ char **paths;
+ unsigned int nb_paths;
+ int error;
+};
+
+
+static int match_group_where_peer_is_client(struct p2p_group *group,
+ void *user_data)
+{
+ struct peer_group_data *data = user_data;
+ const struct p2p_group_config *cfg;
+ struct wpa_supplicant *wpa_s_go;
+ char **paths;
+
+ if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
+ return 1;
+
+ cfg = p2p_group_get_config(group);
+
+ wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
+ cfg->ssid_len);
+ if (wpa_s_go == NULL)
+ return 1;
+
+ paths = os_realloc_array(data->paths, data->nb_paths + 1,
+ sizeof(char *));
+ if (paths == NULL)
+ goto out_of_memory;
+
+ data->paths = paths;
+ data->paths[data->nb_paths] = wpa_s_go->dbus_groupobj_path;
+ data->nb_paths++;
+
+ return 1;
+
+out_of_memory:
+ data->error = ENOMEM;
+ return 0;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct peer_handler_args *peer_args = user_data;
+ const struct p2p_peer_info *info;
+ struct peer_group_data data;
+ struct wpa_supplicant *wpa_s, *wpa_s_go;
+ dbus_bool_t success = FALSE;
+
+ info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+ peer_args->p2p_device_addr, 0);
+ if (info == NULL) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "failed to find peer");
+ return FALSE;
+ }
+
+ os_memset(&data, 0, sizeof(data));
+
+ wpa_s = peer_args->wpa_s;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
+ wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
+ if (wpa_s_go) {
+ data.paths = os_calloc(1, sizeof(char *));
+ if (data.paths == NULL)
+ goto out_of_memory;
+ data.paths[0] = wpa_s_go->dbus_groupobj_path;
+ data.nb_paths = 1;
+ }
- success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
- NULL, 0, error);
+ data.wpa_s = peer_args->wpa_s;
+ data.info = info;
+
+ p2p_loop_on_all_groups(peer_args->wpa_s->global->p2p,
+ match_group_where_peer_is_client, &data);
+ if (data.error)
+ goto out_of_memory;
+
+ if (data.paths == NULL) {
+ return wpas_dbus_simple_array_property_getter(
+ iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
+ }
+
+ success = wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_OBJECT_PATH,
+ data.paths,
+ data.nb_paths, error);
+ goto out;
+
+out_of_memory:
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+out:
+ os_free(data.paths);
return success;
}
@@ -1496,15 +1636,6 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
unsigned int i = 0, num = 0;
dbus_bool_t success = FALSE;
- if (wpa_s->conf == NULL) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "An error occurred getting persistent groups list",
- __func__);
- dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
- "occurred getting persistent groups list");
- return FALSE;
- }
-
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
if (network_is_persistent_group(ssid))
num++;
@@ -1617,12 +1748,12 @@ DBusMessage * wpas_dbus_handler_add_persistent_group(
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "Cannot add new persistent group", __func__);
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Cannot add new persistent group",
+ __func__);
reply = wpas_dbus_error_unknown_error(
message,
- "wpa_supplicant could not add "
- "a persistent group on this interface.");
+ "wpa_supplicant could not add a persistent group on this interface.");
goto err;
}
@@ -1635,13 +1766,12 @@ DBusMessage * wpas_dbus_handler_add_persistent_group(
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
- wpa_printf(MSG_DEBUG, "dbus: %s: "
- "Control interface could not set persistent group "
- "properties", __func__);
- reply = wpas_dbus_reply_new_from_error(message, &error,
- DBUS_ERROR_INVALID_ARGS,
- "Failed to set network "
- "properties");
+ wpa_printf(MSG_DEBUG,
+ "dbus: %s: Control interface could not set persistent group properties",
+ __func__);
+ reply = wpas_dbus_reply_new_from_error(
+ message, &error, DBUS_ERROR_INVALID_ARGS,
+ "Failed to set network properties");
dbus_error_free(&error);
goto err;
}
@@ -1653,15 +1783,13 @@ DBusMessage * wpas_dbus_handler_add_persistent_group(
reply = dbus_message_new_method_return(message);
if (reply == NULL) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
@@ -1691,7 +1819,7 @@ DBusMessage * wpas_dbus_handler_remove_persistent_group(
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *persistent_group_id = NULL;
+ char *iface = NULL, *persistent_group_id;
int id;
struct wpa_ssid *ssid;
@@ -1702,10 +1830,11 @@ DBusMessage * wpas_dbus_handler_remove_persistent_group(
* Extract the network ID and ensure the network is actually a child of
* this interface.
*/
- iface = wpas_dbus_new_decompose_object_path(op, 1,
- &persistent_group_id,
- NULL);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ iface = wpas_dbus_new_decompose_object_path(
+ op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+ &persistent_group_id);
+ if (iface == NULL || persistent_group_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
@@ -1725,19 +1854,17 @@ DBusMessage * wpas_dbus_handler_remove_persistent_group(
wpas_notify_persistent_group_removed(wpa_s, ssid);
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "error occurred when removing persistent group %d",
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: error occurred when removing persistent group %d",
__func__, id);
reply = wpas_dbus_error_unknown_error(
message,
- "error removing the specified persistent group on "
- "this interface.");
+ "error removing the specified persistent group on this interface.");
goto out;
}
out:
os_free(iface);
- os_free(persistent_group_id);
return reply;
}
@@ -1748,8 +1875,8 @@ static void remove_persistent_group(struct wpa_supplicant *wpa_s,
wpas_notify_persistent_group_removed(wpa_s, ssid);
if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "error occurred when removing persistent group %d",
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: error occurred when removing persistent group %d",
__func__, ssid->id);
return;
}
@@ -1826,9 +1953,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
if (!paths[i])
goto out_of_memory;
os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
"/" COMPACT_MACSTR,
- wpa_s->dbus_groupobj_path, MAC2STR(addr));
+ wpa_s->parent->dbus_new_path, MAC2STR(addr));
i++;
}
@@ -1857,6 +1984,7 @@ dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
+
if (wpa_s->current_ssid == NULL)
return FALSE;
return wpas_dbus_simple_array_property_getter(
@@ -1917,15 +2045,14 @@ dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- u8 role = wpas_get_p2p_role(wpa_s);
- char *p_pass = NULL;
+ char *p_pass;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
- /* Verify correct role for this property */
- if (role == WPAS_P2P_ROLE_GO) {
- if (wpa_s->current_ssid == NULL)
- return FALSE;
- p_pass = wpa_s->current_ssid->passphrase;
- } else
+ if (ssid == NULL)
+ return FALSE;
+
+ p_pass = ssid->passphrase;
+ if (!p_pass)
p_pass = "";
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -1938,20 +2065,20 @@ dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- u8 role = wpas_get_p2p_role(wpa_s);
u8 *p_psk = NULL;
u8 psk_len = 0;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
- /* Verify correct role for this property */
- if (role == WPAS_P2P_ROLE_CLIENT) {
- if (wpa_s->current_ssid == NULL)
- return FALSE;
- p_psk = wpa_s->current_ssid->psk;
- psk_len = 32;
+ if (ssid == NULL)
+ return FALSE;
+
+ if (ssid->psk_set) {
+ p_psk = ssid->psk;
+ psk_len = sizeof(ssid->psk);
}
return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
- &p_psk, psk_len, error);
+ p_psk, psk_len, error);
}
@@ -1962,8 +2089,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
struct wpa_supplicant *wpa_s = user_data;
struct hostapd_data *hapd;
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
- int num_vendor_ext = 0;
- int i;
+ unsigned int i, num_vendor_ext = 0;
+
+ os_memset(vendor_ext, 0, sizeof(vendor_ext));
/* Verify correct role for this property */
if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
@@ -1974,11 +2102,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
if (hapd->conf->wps_vendor_ext[i] == NULL)
- vendor_ext[i] = NULL;
- else {
- vendor_ext[num_vendor_ext++] =
- hapd->conf->wps_vendor_ext[i];
- }
+ continue;
+ vendor_ext[num_vendor_ext++] =
+ hapd->conf->wps_vendor_ext[i];
}
}
@@ -1987,7 +2113,7 @@ dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
DBUS_TYPE_BYTE,
vendor_ext,
num_vendor_ext,
- error);
+ error);
}
@@ -1996,7 +2122,7 @@ dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- DBusMessageIter variant_iter, iter_dict;
+ DBusMessageIter variant_iter, iter_dict, array_iter, sub;
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
unsigned int i;
struct hostapd_data *hapd = NULL;
@@ -2008,6 +2134,82 @@ dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
return FALSE;
dbus_message_iter_recurse(iter, &variant_iter);
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ /*
+ * This is supposed to be array of bytearrays (aay), but the earlier
+ * implementation used a dict with "WPSVendorExtensions" as the key in
+ * this setter function which does not match the format used by the
+ * getter function. For backwards compatibility, allow both formats to
+ * be used in the setter.
+ */
+ if (dbus_message_iter_get_element_type(&variant_iter) ==
+ DBUS_TYPE_ARRAY) {
+ /* This is the proper format matching the getter */
+ struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
+
+ dbus_message_iter_recurse(&variant_iter, &array_iter);
+
+ if (dbus_message_iter_get_arg_type(&array_iter) !=
+ DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&array_iter) !=
+ DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: Not an array of array of bytes");
+ return FALSE;
+ }
+
+ i = 0;
+ os_memset(vals, 0, sizeof(vals));
+
+ while (dbus_message_iter_get_arg_type(&array_iter) ==
+ DBUS_TYPE_ARRAY) {
+ char *val;
+ int len;
+
+ if (i == MAX_WPS_VENDOR_EXTENSIONS) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: Too many WPSVendorExtensions values");
+ i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+ break;
+ }
+
+ dbus_message_iter_recurse(&array_iter, &sub);
+ dbus_message_iter_get_fixed_array(&sub, &val, &len);
+ wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
+ val, len);
+ vals[i] = wpabuf_alloc_copy(val, len);
+ if (vals[i] == NULL) {
+ i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+ break;
+ }
+ i++;
+ dbus_message_iter_next(&array_iter);
+ }
+
+ if (i > MAX_WPS_VENDOR_EXTENSIONS) {
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(vals[i]);
+ return FALSE;
+ }
+
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+ wpabuf_free(hapd->conf->wps_vendor_ext[i]);
+ hapd->conf->wps_vendor_ext[i] = vals[i];
+ }
+
+ hostapd_update_wps(hapd);
+
+ return TRUE;
+ }
+
+ if (dbus_message_iter_get_element_type(&variant_iter) !=
+ DBUS_TYPE_DICT_ENTRY)
+ return FALSE;
+
+ wpa_printf(MSG_DEBUG,
+ "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
return FALSE;
@@ -2025,6 +2227,7 @@ dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
goto error;
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+ wpabuf_free(hapd->conf->wps_vendor_ext[i]);
if (i < entry.array_len) {
hapd->conf->wps_vendor_ext[i] =
entry.binarray_value[i];
@@ -2073,30 +2276,31 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "service_type") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "upnp"))
+ if (os_strcmp(entry.key, "service_type") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "upnp") == 0)
upnp = 1;
- else if (!os_strcmp(entry.str_value, "bonjour"))
+ else if (os_strcmp(entry.str_value, "bonjour") == 0)
bonjour = 1;
else
goto error_clear;
- } else if (!os_strcmp(entry.key, "version") &&
- entry.type == DBUS_TYPE_INT32) {
+ } else if (os_strcmp(entry.key, "version") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
version = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "service") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ } 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")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
+ } else if (os_strcmp(entry.key, "query") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
query = wpabuf_alloc_copy(
entry.bytearray_value,
entry.array_len);
- } else if (!os_strcmp(entry.key, "response")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
+ } else if (os_strcmp(entry.key, "response") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
resp = wpabuf_alloc_copy(entry.bytearray_value,
entry.array_len);
@@ -2111,8 +2315,6 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
goto error;
- os_free(service);
- service = NULL;
} else if (bonjour == 1) {
if (query == NULL || resp == NULL)
goto error;
@@ -2124,6 +2326,7 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
} else
goto error;
+ os_free(service);
return reply;
error_clear:
wpa_dbus_dict_entry_clear(&entry);
@@ -2158,11 +2361,11 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "service_type") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "upnp"))
+ if (os_strcmp(entry.key, "service_type") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "upnp") == 0)
upnp = 1;
- else if (!os_strcmp(entry.str_value, "bonjour"))
+ else if (os_strcmp(entry.str_value, "bonjour") == 0)
bonjour = 1;
else
goto error_clear;
@@ -2173,13 +2376,14 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
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") &&
+ if (os_strcmp(entry.key, "version") == 0 &&
entry.type == DBUS_TYPE_INT32)
version = entry.uint32_value;
- else if (!os_strcmp(entry.key, "service") &&
- entry.type == DBUS_TYPE_STRING)
+ else if (os_strcmp(entry.key, "service") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(service);
service = os_strdup(entry.str_value);
- else
+ } else
goto error_clear;
wpa_dbus_dict_entry_clear(&entry);
@@ -2189,7 +2393,6 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
goto error;
ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
- os_free(service);
if (ret != 0)
goto error;
} else if (bonjour == 1) {
@@ -2197,10 +2400,11 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "query")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
+ 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);
@@ -2216,14 +2420,17 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
ret = wpas_p2p_service_del_bonjour(wpa_s, query);
if (ret != 0)
goto error;
- wpabuf_free(query);
} else
goto error;
+ wpabuf_free(query);
+ os_free(service);
return reply;
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
+ wpabuf_free(query);
+ os_free(service);
return wpas_dbus_error_invalid_args(message, NULL);
}
@@ -2259,22 +2466,22 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
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, "peer_object") &&
+ if (os_strcmp(entry.key, "peer_object") == 0 &&
entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "service_type") &&
+ } else if (os_strcmp(entry.key, "service_type") == 0 &&
entry.type == DBUS_TYPE_STRING) {
- if (!os_strcmp(entry.str_value, "upnp"))
+ if (os_strcmp(entry.str_value, "upnp") == 0)
upnp = 1;
else
goto error_clear;
- } else if (!os_strcmp(entry.key, "version") &&
+ } else if (os_strcmp(entry.key, "version") == 0 &&
entry.type == DBUS_TYPE_INT32) {
version = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "service") &&
+ } else if (os_strcmp(entry.key, "service") == 0 &&
entry.type == DBUS_TYPE_STRING) {
service = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "tlv")) {
+ } else if (os_strcmp(entry.key, "tlv") == 0) {
if (entry.type != DBUS_TYPE_ARRAY ||
entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
@@ -2352,16 +2559,17 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "peer_object") &&
+ if (os_strcmp(entry.key, "peer_object") == 0 &&
entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "frequency") &&
+ } else if (os_strcmp(entry.key, "frequency") == 0 &&
entry.type == DBUS_TYPE_INT32) {
freq = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "dialog_token") &&
- entry.type == DBUS_TYPE_UINT32) {
+ } else if (os_strcmp(entry.key, "dialog_token") == 0 &&
+ (entry.type == DBUS_TYPE_UINT32 ||
+ entry.type == DBUS_TYPE_INT32)) {
dlg_tok = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "tlvs")) {
+ } else if (os_strcmp(entry.key, "tlvs") == 0) {
if (entry.type != DBUS_TYPE_ARRAY ||
entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
@@ -2372,12 +2580,9 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
wpa_dbus_dict_entry_clear(&entry);
}
- if (!peer_object_path ||
- (parse_peer_object_path(peer_object_path, addr) < 0) ||
- !p2p_peer_known(wpa_s->global->p2p, addr))
- goto error;
-
- if (tlv == NULL)
+ if (parse_peer_object_path(peer_object_path, addr) < 0 ||
+ !p2p_peer_known(wpa_s->global->p2p, addr) ||
+ tlv == NULL)
goto error;
wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
@@ -2405,7 +2610,7 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
if (req == 0)
goto error;
- if (!wpas_p2p_sd_cancel_request(wpa_s, req))
+ if (wpas_p2p_sd_cancel_request(wpa_s, req) < 0)
goto error;
return NULL;
@@ -2436,3 +2641,77 @@ DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
return NULL;
}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
+ DBusError *error, void *user_data)
+{
+ struct wpa_global *global = user_data;
+ struct wpabuf *ie;
+ dbus_bool_t ret;
+
+ ie = wifi_display_get_wfd_ie(global);
+ if (ie == NULL)
+ return wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_BYTE,
+ NULL, 0, error);
+
+ ret = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ wpabuf_head(ie),
+ wpabuf_len(ie), error);
+ wpabuf_free(ie);
+
+ return ret;
+}
+
+
+dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
+ DBusError *error, void *user_data)
+{
+ struct wpa_global *global = user_data;
+ DBusMessageIter variant, array;
+ struct wpabuf *ie = NULL;
+ const u8 *data;
+ int len;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+ goto err;
+
+ dbus_message_iter_recurse(iter, &variant);
+ if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
+ goto err;
+
+ dbus_message_iter_recurse(&variant, &array);
+ dbus_message_iter_get_fixed_array(&array, &data, &len);
+ if (len == 0) {
+ wifi_display_enable(global, 0);
+ wifi_display_deinit(global);
+
+ return TRUE;
+ }
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ goto err;
+
+ wpabuf_put_data(ie, data, len);
+ if (wifi_display_subelem_set_from_ies(global, ie) != 0)
+ goto err;
+
+ if (global->wifi_display == 0)
+ wifi_display_enable(global, 1);
+
+ wpabuf_free(ie);
+
+ return TRUE;
+err:
+ wpabuf_free(ie);
+
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
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 a11b3c8..fdaccba 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -14,11 +14,6 @@ struct peer_handler_args {
u8 p2p_device_addr[ETH_ALEN];
};
-struct groupmember_handler_args {
- struct wpa_supplicant *wpa_s;
- u8 member_addr[ETH_ALEN];
-};
-
/*
* P2P Device methods
*/
@@ -114,39 +109,47 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
*/
dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ 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);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ 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);
+ 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);
+
/*
* P2P Group properties
*/
@@ -207,5 +210,16 @@ DBusMessage * wpas_dbus_handler_remove_persistent_group(
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);
+
+#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 4ad5e7e..a94a0e5 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -41,8 +41,8 @@ static int wpas_dbus_handler_wps_role(DBusMessage *message,
dbus_message_iter_recurse(entry_iter, &variant_iter);
if (dbus_message_iter_get_arg_type(&variant_iter) !=
DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
- "string required");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Role type, string required");
*reply = wpas_dbus_error_invalid_args(message,
"Role must be a string");
return -1;
@@ -70,10 +70,9 @@ static int wpas_dbus_handler_wps_type(DBusMessage *message,
char *val;
dbus_message_iter_recurse(entry_iter, &variant_iter);
- if (dbus_message_iter_get_arg_type(&variant_iter) !=
- DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
- "string required");
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Type type, string required");
*reply = wpas_dbus_error_invalid_args(message,
"Type must be a string");
return -1;
@@ -105,8 +104,8 @@ static int wpas_dbus_handler_wps_bssid(DBusMessage *message,
if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(&variant_iter) !=
DBUS_TYPE_BYTE) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
- "byte array required");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Bssid type, byte array required");
*reply = wpas_dbus_error_invalid_args(
message, "Bssid must be a byte array");
return -1;
@@ -114,8 +113,8 @@ static int wpas_dbus_handler_wps_bssid(DBusMessage *message,
dbus_message_iter_recurse(&variant_iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &params->bssid, &len);
if (len != ETH_ALEN) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
- "%d", len);
+ wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length %d",
+ len);
*reply = wpas_dbus_error_invalid_args(message,
"Bssid is wrong length");
return -1;
@@ -132,10 +131,9 @@ static int wpas_dbus_handler_wps_pin(DBusMessage *message,
DBusMessageIter variant_iter;
dbus_message_iter_recurse(entry_iter, &variant_iter);
- if (dbus_message_iter_get_arg_type(&variant_iter) !=
- DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
- "string required");
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Pin type, string required");
*reply = wpas_dbus_error_invalid_args(message,
"Pin must be a string");
return -1;
@@ -158,8 +156,8 @@ static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message,
if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(&variant_iter) !=
DBUS_TYPE_BYTE) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
- "P2PDeviceAddress type, byte array required");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong P2PDeviceAddress type, byte array required");
*reply = wpas_dbus_error_invalid_args(
message, "P2PDeviceAddress must be a byte array");
return -1;
@@ -168,11 +166,11 @@ static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message,
dbus_message_iter_get_fixed_array(&array_iter, &params->p2p_dev_addr,
&len);
if (len != ETH_ALEN) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
- "P2PDeviceAddress length %d", len);
- *reply = wpas_dbus_error_invalid_args(message,
- "P2PDeviceAddress "
- "has wrong length");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong P2PDeviceAddress length %d",
+ len);
+ *reply = wpas_dbus_error_invalid_args(
+ message, "P2PDeviceAddress has wrong length");
return -1;
}
return 0;
@@ -249,54 +247,54 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
dbus_message_iter_next(&dict_iter);
}
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface && params.type == 1) {
+ if (params.pin == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Pin required for registrar role");
+ return wpas_dbus_error_invalid_args(
+ message, "Pin required for registrar role.");
+ }
+ ret = wpa_supplicant_ap_wps_pin(wpa_s,
+ params.bssid,
+ params.pin,
+ npin, sizeof(npin), 0);
+ } else if (wpa_s->ap_iface) {
+ ret = wpa_supplicant_ap_wps_pbc(wpa_s,
+ params.bssid,
+ params.p2p_dev_addr);
+ } else
+#endif /* CONFIG_AP */
if (params.role == 0) {
wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
return wpas_dbus_error_invalid_args(message,
"Role not specified");
- } else if (params.role == 1 && params.type == 0) {
+ } else if (params.role == 2) {
+ if (params.pin == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Pin required for registrar role");
+ return wpas_dbus_error_invalid_args(
+ message, "Pin required for registrar role.");
+ }
+ ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
+ NULL);
+ } else if (params.type == 0) {
wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
return wpas_dbus_error_invalid_args(message,
"Type not specified");
- } else if (params.role == 2 && params.pin == NULL) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
- "registrar role");
- return wpas_dbus_error_invalid_args(
- message, "Pin required for registrar role.");
- }
-
- if (params.role == 2)
- ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
- NULL);
- else if (params.type == 1) {
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface)
- ret = wpa_supplicant_ap_wps_pin(wpa_s,
- params.bssid,
- params.pin,
- npin, sizeof(npin), 0);
- else
-#endif /* CONFIG_AP */
- {
- 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);
- }
+ } else if (params.type == 1) {
+ 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);
} else {
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface)
- ret = wpa_supplicant_ap_wps_pbc(wpa_s,
- params.bssid,
- params.p2p_dev_addr);
- else
-#endif /* CONFIG_AP */
ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
}
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
- "role %s and key %s",
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start wpas_wps_failed in role %s and key %s",
(params.role == 1 ? "enrollee" : "registrar"),
(params.type == 0 ? "" :
(params.type == 1 ? "pin" : "pbc")));
@@ -305,31 +303,16 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
}
reply = dbus_message_new_method_return(message);
- if (!reply) {
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- }
+ if (!reply)
+ return wpas_dbus_error_no_memory(message);
dbus_message_iter_init_append(reply, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ (os_strlen(npin) > 0 &&
+ !wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
dbus_message_unref(reply);
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- }
-
- if (os_strlen(npin) > 0) {
- if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
- dbus_message_unref(reply);
- return dbus_message_new_error(message,
- DBUS_ERROR_NO_MEMORY,
- NULL);
- }
- }
-
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
- dbus_message_unref(reply);
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
}
return reply;
@@ -351,7 +334,8 @@ dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
+ dbus_bool_t process = wpa_s->conf->wps_cred_processing != 1;
+
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&process, error);
}
@@ -378,7 +362,7 @@ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
&process_credentials))
return FALSE;
- old_pc = (wpa_s->conf->wps_cred_processing != 1);
+ old_pc = wpa_s->conf->wps_cred_processing != 1;
wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
@@ -389,3 +373,62 @@ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
return TRUE;
}
+
+
+/**
+ * wpas_dbus_getter_config_methods - Get current WPS configuration methods
+ * @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 "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)
+{
+ 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);
+}
+
+
+/**
+ * wpas_dbus_setter_config_methods - Set WPS configuration methods
+ * @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 "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)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *new_methods;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ new_methods = os_strdup(methods);
+ if (!new_methods)
+ return FALSE;
+
+ os_free(wpa_s->conf->config_methods);
+ wpa_s->conf->config_methods = new_methods;
+
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_CONFIG_METHODS;
+ 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 cfa6a15..15b0901 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -15,6 +15,7 @@
#include "dbus_common_i.h"
#include "dbus_new.h"
#include "dbus_new_helpers.h"
+#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
@@ -38,27 +39,25 @@ static dbus_bool_t fill_dict_with_properties(
if (!dbus_message_iter_open_container(dict_iter,
DBUS_TYPE_DICT_ENTRY,
- NULL, &entry_iter)) {
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
- "no memory");
- return FALSE;
- }
- if (!dbus_message_iter_append_basic(&entry_iter,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
DBUS_TYPE_STRING,
- &dsc->dbus_property)) {
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
- "no memory");
- return FALSE;
- }
+ &dsc->dbus_property))
+ goto error;
/* An error getting a property fails the request entirely */
if (!dsc->getter(&entry_iter, error, user_data))
return FALSE;
- dbus_message_iter_close_container(dict_iter, &entry_iter);
+ if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
+ goto error;
}
return TRUE;
+
+error:
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
}
@@ -75,43 +74,38 @@ static dbus_bool_t fill_dict_with_properties(
* with properties names as keys and theirs values as values.
*/
static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
- struct wpa_dbus_object_desc *obj_dsc)
+ struct wpa_dbus_object_desc *obj_dsc)
{
DBusMessage *reply;
DBusMessageIter iter, dict_iter;
DBusError error;
reply = dbus_message_new_method_return(message);
- if (reply == NULL) {
- wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
- __func__);
- return NULL;
- }
+ if (reply == NULL)
+ return wpas_dbus_error_no_memory(message);
dbus_message_iter_init_append(reply, &iter);
if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
- wpa_printf(MSG_ERROR, "%s: out of memory creating reply",
- __func__);
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- "out of memory");
- return reply;
+ return wpas_dbus_error_no_memory(message);
}
dbus_error_init(&error);
if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
- interface, obj_dsc->user_data, &error))
- {
+ interface, obj_dsc->user_data, &error)) {
dbus_message_unref(reply);
- reply = wpas_dbus_reply_new_from_error(message, &error,
- DBUS_ERROR_INVALID_ARGS,
- "No readable properties"
- " in this interface");
+ reply = wpas_dbus_reply_new_from_error(
+ message, &error, DBUS_ERROR_INVALID_ARGS,
+ "No readable properties in this interface");
dbus_error_free(&error);
return reply;
}
- wpa_dbus_dict_close_write(&iter, &dict_iter);
+ if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
+ dbus_message_unref(reply);
+ return wpas_dbus_error_no_memory(message);
+ }
+
return reply;
}
@@ -132,8 +126,9 @@ static int is_signature_correct(DBusMessage *message,
for (arg = method_dsc->args; arg && arg->name; arg++) {
if (arg->dir == ARG_IN) {
size_t blen = registered_sig + MAX_SIG_LEN - pos;
+
ret = os_snprintf(pos, blen, "%s", arg->type);
- if (ret < 0 || (size_t) ret >= blen)
+ if (os_snprintf_error(blen, ret))
return 0;
pos += ret;
}
@@ -267,10 +262,13 @@ properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
}
if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
- WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
+ WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) {
+ wpa_printf(MSG_MSGDUMP, "%s: Get(%s)", __func__, property);
return properties_get(message, property_dsc,
obj_dsc->user_data);
+ }
+ wpa_printf(MSG_MSGDUMP, "%s: Set(%s)", __func__, property);
return properties_set(message, property_dsc, obj_dsc->user_data);
}
@@ -292,8 +290,7 @@ static DBusMessage * properties_handler(DBusMessage *message,
!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
/* First argument: interface name (DBUS_TYPE_STRING) */
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- {
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
return dbus_message_new_error(message,
DBUS_ERROR_INVALID_ARGS,
NULL);
@@ -349,8 +346,7 @@ static DBusMessage * msg_method_handler(DBusMessage *message,
NULL);
}
- return method_dsc->method_handler(message,
- obj_dsc->user_data);
+ return method_dsc->method_handler(message, obj_dsc->user_data);
}
@@ -385,8 +381,9 @@ static DBusHandlerResult message_handler(DBusConnection *connection,
if (!method || !path || !msg_interface)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
- msg_interface, method, path);
+ wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s) [%s]",
+ msg_interface, method, path,
+ dbus_message_get_signature(message));
/* if message is introspection method call */
if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
@@ -398,8 +395,7 @@ static DBusHandlerResult message_handler(DBusConnection *connection,
#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
reply = dbus_message_new_error(
message, DBUS_ERROR_UNKNOWN_METHOD,
- "wpa_supplicant was compiled without "
- "introspection support.");
+ "wpa_supplicant was compiled without introspection support.");
#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
WPAS_DBUS_INTERFACE_MAX)) {
@@ -452,6 +448,7 @@ static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
free_dbus_object_desc(obj_dsc);
}
+
/**
* wpa_dbus_ctrl_iface_init - Initialize dbus control interface
* @application_data: Pointer to application specific data structure
@@ -479,30 +476,28 @@ int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
obj_desc->path = os_strdup(dbus_path);
/* Register the message handler for the global dbus interface */
- if (!dbus_connection_register_object_path(iface->con,
- dbus_path, &wpa_vtable,
- obj_desc)) {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message "
- "handler");
+ if (!dbus_connection_register_object_path(iface->con, dbus_path,
+ &wpa_vtable, obj_desc)) {
+ 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, dbus_service,
- 0, &error)) {
+ switch (dbus_bus_request_name(iface->con, 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");
+ 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);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not request service name: %s %s",
+ error.name, error.message);
break;
}
dbus_error_free(&error);
@@ -526,14 +521,12 @@ int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
*
* Registers a new interface with dbus and assigns it a dbus object path.
*/
-int wpa_dbus_register_object_per_iface(
- struct wpas_dbus_priv *ctrl_iface,
- const char *path, const char *ifname,
- struct wpa_dbus_object_desc *obj_desc)
+int wpa_dbus_register_object_per_iface(struct wpas_dbus_priv *ctrl_iface,
+ const char *path, const char *ifname,
+ struct wpa_dbus_object_desc *obj_desc)
{
DBusConnection *con;
DBusError error;
-
DBusObjectPathVTable vtable = {
&free_dbus_object_desc_cb, &message_handler,
NULL, NULL, NULL, NULL
@@ -551,14 +544,12 @@ int wpa_dbus_register_object_per_iface(
/* Register the message handler for the interface functions */
if (!dbus_connection_try_register_object_path(con, path, &vtable,
obj_desc, &error)) {
- if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) {
+ if (os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
} else {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message "
- "handler for interface %s object %s",
- ifname, path);
- wpa_printf(MSG_ERROR, "dbus error: %s", error.name);
- wpa_printf(MSG_ERROR, "dbus: %s", error.message);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not set up message handler for interface %s object %s (error: %s message: %s)",
+ ifname, path, error.name, error.message);
}
dbus_error_free(&error);
return -1;
@@ -588,13 +579,14 @@ int wpa_dbus_unregister_object_per_iface(
dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
- "private data: %s", __func__, path);
- } else {
- eloop_cancel_timeout(flush_object_timeout_handler, con,
- obj_desc);
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Could not obtain object's private data: %s",
+ __func__, path);
+ return 0;
}
+ eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
+
if (!dbus_connection_unregister_object_path(con, path))
return -1;
@@ -623,24 +615,22 @@ static dbus_bool_t put_changed_properties(
if (!dbus_message_iter_open_container(dict_iter,
DBUS_TYPE_DICT_ENTRY,
- NULL, &entry_iter))
- return FALSE;
-
- if (!dbus_message_iter_append_basic(&entry_iter,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
DBUS_TYPE_STRING,
&dsc->dbus_property))
return FALSE;
dbus_error_init(&error);
if (!dsc->getter(&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",
- __func__, dsc->dbus_property,
- error.name, error.message);
+ if (dbus_error_is_set(&error)) {
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Cannot get new value of property %s: (%s) %s",
+ __func__, dsc->dbus_property,
+ error.name, error.message);
} else {
- wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
- "new value of property %s",
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Cannot get new value of property %s",
__func__, dsc->dbus_property);
}
dbus_error_free(&error);
@@ -670,38 +660,23 @@ static void do_send_prop_changed_signal(
dbus_message_iter_init_append(msg, &signal_iter);
if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
- &interface))
- goto err;
-
- /* Changed properties dict */
- if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
- "{sv}", &dict_iter))
- goto err;
-
- if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0))
- goto err;
-
- if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
- goto err;
-
- /* Invalidated properties array (empty) */
- if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
- "s", &dict_iter))
- goto err;
-
- if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
- goto err;
-
- dbus_connection_send(con, msg, NULL);
+ &interface) ||
+ /* Changed properties dict */
+ !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+ "{sv}", &dict_iter) ||
+ !put_changed_properties(obj_dsc, interface, &dict_iter, 0) ||
+ !dbus_message_iter_close_container(&signal_iter, &dict_iter) ||
+ /* Invalidated properties array (empty) */
+ !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+ "s", &dict_iter) ||
+ !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+ wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+ __func__);
+ } else {
+ dbus_connection_send(con, msg, NULL);
+ }
-out:
dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
- __func__);
- goto out;
}
@@ -719,25 +694,16 @@ static void do_send_deprecated_prop_changed_signal(
dbus_message_iter_init_append(msg, &signal_iter);
if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
- "{sv}", &dict_iter))
- goto err;
-
- if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
- goto err;
-
- if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
- goto err;
-
- dbus_connection_send(con, msg, NULL);
+ "{sv}", &dict_iter) ||
+ !put_changed_properties(obj_dsc, interface, &dict_iter, 1) ||
+ !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+ wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+ __func__);
+ } else {
+ dbus_connection_send(con, msg, NULL);
+ }
-out:
dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
- __func__);
- goto out;
}
@@ -769,8 +735,9 @@ static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx)
DBusConnection *con = eloop_ctx;
struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
- wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties "
- "of object %s", __func__, obj_desc->path);
+ wpa_printf(MSG_DEBUG,
+ "dbus: %s: Timeout - sending changed properties of object %s",
+ __func__, obj_desc->path);
wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
}
@@ -840,7 +807,6 @@ void wpa_dbus_flush_object_changed_properties(DBusConnection *con,
return;
eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
- dsc = obj_desc->properties;
for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property;
dsc++, i++) {
if (obj_desc->prop_changed_flags == NULL ||
@@ -882,8 +848,9 @@ void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
dbus_connection_get_object_path_data(iface->con, path,
(void **) &obj_desc);
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
- "could not obtain object's private data: %s", path);
+ wpa_printf(MSG_ERROR,
+ "dbus: wpa_dbus_property_changed: could not obtain object's private data: %s",
+ path);
return;
}
@@ -896,13 +863,14 @@ void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
}
if (!dsc || !dsc->dbus_property) {
- wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
- "no property %s in object %s", property, path);
+ wpa_printf(MSG_ERROR,
+ "dbus: wpa_dbus_property_changed: no property %s in object %s",
+ property, path);
return;
}
if (!eloop_is_timeout_registered(flush_object_timeout_handler,
- iface->con, obj_desc->path)) {
+ iface->con, obj_desc)) {
eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
flush_object_timeout_handler,
iface->con, obj_desc);
@@ -934,8 +902,9 @@ dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
dbus_connection_get_object_path_data(iface->con, path,
(void **) &obj_desc);
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
- "private data: %s", __func__, path);
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: could not obtain object's private data: %s",
+ __func__, path);
return FALSE;
}
@@ -949,10 +918,11 @@ dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
interface, obj_desc->user_data,
&error)) {
- wpa_printf(MSG_ERROR, "dbus: %s: failed to get object"
- " properties: (%s) %s", __func__,
- dbus_error_is_set(&error) ? error.name : "none",
- dbus_error_is_set(&error) ? error.message : "none");
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: failed to get object properties: (%s) %s",
+ __func__,
+ dbus_error_is_set(&error) ? error.name : "none",
+ dbus_error_is_set(&error) ? error.message : "none");
dbus_error_free(&error);
return FALSE;
}
@@ -963,29 +933,34 @@ dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
/**
* wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
* @path: The dbus object path
- * @p2p_persistent_group: indicates whether to parse the path as a P2P
- * persistent group object
- * @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
+ * @sep: Separating part (e.g., "Networks" or "PersistentGroups")
+ * @item: (out) The part following the specified separator, if any
+ * Returns: The object path of the 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.
+ * For a given object path, decomposes the object path into object id and
+ * requested part, if those parts exist. The caller is responsible for freeing
+ * the returned value. The *item pointer points to that allocated value and must
+ * not be freed separately.
+ *
+ * As an example, path = "/fi/w1/wpa_supplicant1/Interfaces/1/Networks/0" and
+ * sep = "Networks" would result in "/fi/w1/wpa_supplicant1/Interfaces/1"
+ * getting returned and *items set to point to "0".
*/
-char *wpas_dbus_new_decompose_object_path(const char *path,
- int p2p_persistent_group,
- char **network,
- char **bssid)
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+ char **item)
{
const unsigned int dev_path_prefix_len =
os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
char *obj_path_only;
- char *next_sep;
+ char *pos;
+ size_t sep_len;
- /* Be a bit paranoid about path */
- if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
- dev_path_prefix_len))
- return NULL;
+ *item = NULL;
+
+ /* Verify that this starts with our interface prefix */
+ if (os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+ dev_path_prefix_len) != 0)
+ return NULL; /* not our path */
/* Ensure there's something at the end of the path */
if ((path + dev_path_prefix_len)[0] == '\0')
@@ -995,39 +970,20 @@ char *wpas_dbus_new_decompose_object_path(const char *path,
if (obj_path_only == NULL)
return NULL;
- next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
- if (next_sep != NULL) {
- const char *net_part = os_strstr(
- next_sep, p2p_persistent_group ?
- WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
- WPAS_DBUS_NEW_NETWORKS_PART "/");
- const char *bssid_part = os_strstr(
- next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
-
- if (network && net_part) {
- /* Deal with a request for a configured network */
- const char *net_name = net_part +
- os_strlen(p2p_persistent_group ?
- WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
- "/" :
- WPAS_DBUS_NEW_NETWORKS_PART "/");
- *network = NULL;
- if (os_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 +
- os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
- if (os_strlen(bssid_name))
- *bssid = os_strdup(bssid_name);
- else
- *bssid = NULL;
- }
+ pos = obj_path_only + dev_path_prefix_len;
+ pos = os_strchr(pos, '/');
+ if (pos == NULL)
+ return obj_path_only; /* no next item on the path */
- /* Cut off interface object path before "/" */
- *next_sep = '\0';
- }
+ /* Separate network interface prefix from the path */
+ *pos++ = '\0';
+
+ sep_len = os_strlen(sep);
+ if (os_strncmp(pos, sep, sep_len) != 0 || pos[sep_len] != '/')
+ return obj_path_only; /* no match */
+ /* return a pointer to the requested item */
+ *item = pos + sep_len + 1;
return obj_path_only;
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h
index 6d31ad5..6e2c1f1 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -12,13 +12,13 @@
#include <dbus/dbus.h>
-typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message,
- void *user_data);
-typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
+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);
+typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
struct wpa_dbus_object_desc {
DBusConnection *connection;
@@ -137,10 +137,8 @@ void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
DBusMessage * wpa_dbus_introspect(DBusMessage *message,
struct wpa_dbus_object_desc *obj_dsc);
-char *wpas_dbus_new_decompose_object_path(const char *path,
- int p2p_persistent_group,
- char **network,
- char **bssid);
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+ char **item);
DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message,
DBusError *error,
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
index 3b090c0..6209c67 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -37,14 +37,16 @@ static struct interfaces * add_interface(struct dl_list *list,
iface = os_zalloc(sizeof(struct interfaces));
if (!iface)
return NULL;
+ iface->dbus_interface = os_strdup(dbus_interface);
iface->xml = wpabuf_alloc(6000);
- if (iface->xml == NULL) {
+ if (iface->dbus_interface == NULL || iface->xml == NULL) {
+ os_free(iface->dbus_interface);
+ wpabuf_free(iface->xml);
os_free(iface);
return NULL;
}
wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface);
dl_list_add_tail(list, &iface->list);
- iface->dbus_interface = os_strdup(dbus_interface);
return iface;
}
@@ -96,6 +98,7 @@ static void extract_interfaces_methods(
{
const struct wpa_dbus_method_desc *dsc;
struct interfaces *iface;
+
for (dsc = methods; dsc && dsc->dbus_method; dsc++) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
@@ -110,6 +113,7 @@ static void extract_interfaces_signals(
{
const struct wpa_dbus_signal_desc *dsc;
struct interfaces *iface;
+
for (dsc = signals; dsc && dsc->dbus_signal; dsc++) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
@@ -124,6 +128,7 @@ static void extract_interfaces_properties(
{
const struct wpa_dbus_property_desc *dsc;
struct interfaces *iface;
+
for (dsc = properties; dsc && dsc->dbus_property; dsc++) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
@@ -154,14 +159,14 @@ static void extract_interfaces(struct dl_list *list,
static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
{
struct interfaces *iface, *n;
+
dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) {
wpabuf_put_buf(xml, iface->xml);
wpabuf_put_str(xml, "</interface>");
} else {
- wpa_printf(MSG_DEBUG, "dbus: Not enough room for "
- "add_interfaces inspect data: tailroom %u, "
- "add %u",
+ wpa_printf(MSG_DEBUG,
+ "dbus: Not enough room for add_interfaces inspect data: tailroom %u, add %u",
(unsigned int) wpabuf_tailroom(xml),
(unsigned int) wpabuf_len(iface->xml));
}
@@ -229,6 +234,7 @@ static void add_wpas_interfaces(struct wpabuf *xml,
struct wpa_dbus_object_desc *obj_dsc)
{
struct dl_list ifaces;
+
dl_list_init(&ifaces);
extract_interfaces(&ifaces, obj_dsc);
add_interfaces(&ifaces, xml);
@@ -270,6 +276,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
reply = dbus_message_new_method_return(message);
if (reply) {
const char *intro_str = wpabuf_head(xml);
+
dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
DBUS_TYPE_INVALID);
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old.c
index 5f298e7..45bb402 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old.c
@@ -92,9 +92,9 @@ char * wpas_dbus_decompose_object_path(const char *path, char **network,
*/
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.");
+ return dbus_message_new_error(
+ message, WPAS_ERROR_INVALID_IFACE,
+ "wpa_supplicant knows nothing about this interface.");
}
@@ -216,8 +216,12 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
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);
+ &bssid);
if (iface_obj_path == NULL) {
reply = wpas_dbus_new_invalid_iface_error(message);
goto out;
@@ -227,7 +231,7 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
* 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) {
+ iface_obj_path) != wpa_s) {
reply = wpas_dbus_new_invalid_iface_error(message);
goto out;
}
@@ -235,6 +239,7 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
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);
@@ -268,30 +273,32 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
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"))
+ else if (os_strcmp(method, "wpsPbc") == 0)
reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
- else if (!os_strcmp(method, "wpsPin"))
+ else if (os_strcmp(method, "wpsPin") == 0)
reply = wpas_dbus_iface_wps_pin(message, wpa_s);
- else if (!os_strcmp(method, "wpsReg"))
+ 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"))
+ 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);
}
-out:
os_free(iface_obj_path);
os_free(network);
os_free(bssid);
@@ -326,6 +333,10 @@ static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
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;
@@ -379,8 +390,8 @@ void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
WPAS_DBUS_IFACE_INTERFACE,
"ScanResultsAvailable");
if (_signal == NULL) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
- "results signal");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to send scan results signal");
return;
}
dbus_connection_send(iface->con, _signal, NULL);
@@ -424,29 +435,21 @@ void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
"StateChange");
if (_signal == NULL) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_state_change: "
- "could not create dbus signal; likely out of "
- "memory");
+ "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 (new_state_str == NULL || old_state_str == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_state_change: "
- "Could not convert state strings");
- goto out;
- }
if (!dbus_message_append_args(_signal,
- DBUS_TYPE_STRING, &new_state_str,
- DBUS_TYPE_STRING, &old_state_str,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_STRING, &new_state_str,
+ DBUS_TYPE_STRING, &old_state_str,
+ DBUS_TYPE_INVALID)) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_state_change: "
- "Not enough memory to construct state change "
- "signal");
+ "dbus: %s: Not enough memory to construct state change signal",
+ __func__);
goto out;
}
@@ -478,18 +481,18 @@ void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
WPAS_DBUS_IFACE_INTERFACE,
"Scanning");
if (_signal == NULL) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
- "results signal");
+ 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_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");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to construct signal");
}
dbus_message_unref(_signal);
}
@@ -514,19 +517,18 @@ void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
"WpsCred");
if (_signal == NULL) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_wps_cred: "
- "Could not create dbus signal; likely out of "
- "memory");
+ "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,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
&cred->cred_attr, cred->cred_attr_len,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_INVALID)) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_wps_cred: "
- "Not enough memory to construct signal");
+ "dbus: %s: Not enough memory to construct signal",
+ __func__);
goto out;
}
@@ -565,9 +567,8 @@ void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
"Certification");
if (_signal == NULL) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_certification: "
- "Could not create dbus signal; likely out of "
- "memory");
+ "dbus: %s: Could not create dbus signal; likely out of memory",
+ __func__);
return;
}
@@ -576,15 +577,15 @@ void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
cert_hex_len = cert ? wpabuf_len(cert) : 0;
if (!dbus_message_append_args(_signal,
- DBUS_TYPE_INT32,&depth,
+ DBUS_TYPE_INT32, &depth,
DBUS_TYPE_STRING, &subject,
- DBUS_TYPE_STRING, &hash,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ DBUS_TYPE_STRING, &hash,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
&cert_hex, cert_hex_len,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_INVALID)) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_certification: "
- "Not enough memory to construct signal");
+ "dbus: %s: Not enough memory to construct signal",
+ __func__);
goto out;
}
@@ -616,8 +617,7 @@ int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
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");
+ wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
return -1;
}
@@ -631,12 +631,13 @@ int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
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");
+ 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);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not request service name: %s %s",
+ error.name, error.message);
break;
}
dbus_error_free(&error);
@@ -685,8 +686,9 @@ int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
/* 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);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not set up message handler for interface %s",
+ wpa_s->ifname);
return -1;
}
@@ -710,7 +712,7 @@ int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL)
+ if (ctrl_iface == NULL || wpa_s->dbus_path == NULL)
return 0;
con = ctrl_iface->con;
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old.h
index e668231..451a9f8 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old.h
@@ -82,7 +82,7 @@ void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
const struct wpabuf *cert);
char * wpas_dbus_decompose_object_path(const char *path, char **network,
- char **bssid);
+ char **bssid);
int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
@@ -104,7 +104,12 @@ wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
{
}
-#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0)
+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,
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c
index 68e5515..773ee8b 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -25,10 +25,6 @@
#include "dbus_old_handlers.h"
#include "dbus_dict_helpers.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
/**
* wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
* @message: Pointer to incoming dbus message this error refers to
@@ -41,9 +37,9 @@ DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
{
DBusMessage *reply;
- reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
- "Did not receive correct message "
- "arguments.");
+ 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);
@@ -116,25 +112,29 @@ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
if (!strcmp(entry.key, "driver") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ 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)) {
+ 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)) {
+ 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)) {
+ 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)
@@ -151,13 +151,13 @@ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
* 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.");
+ 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;
@@ -165,17 +165,17 @@ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
iface.confname = confname;
iface.bridge_ifname = bridge_ifname;
/* Otherwise, have wpa_supplicant attach to it. */
- if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+ wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
+ if (wpa_s) {
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);
+ &path, DBUS_TYPE_INVALID);
} else {
- reply = dbus_message_new_error(message,
- WPAS_ERROR_ADD_ERROR,
- "wpa_supplicant "
- "couldn't grab this "
- "interface.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_ADD_ERROR,
+ "wpa_supplicant couldn't grab this interface.");
}
}
@@ -226,10 +226,9 @@ DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
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.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_REMOVE_ERROR,
+ "wpa_supplicant couldn't remove this interface.");
}
out:
@@ -256,8 +255,8 @@ DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
struct wpa_supplicant *wpa_s;
if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &ifname,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_STRING, &ifname,
+ DBUS_TYPE_INVALID)) {
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
goto out;
}
@@ -271,8 +270,8 @@ DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
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);
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
out:
return reply;
@@ -298,10 +297,10 @@ DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
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)) {
+ 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);
}
@@ -350,7 +349,7 @@ DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- DBusMessage *reply = NULL;
+ DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter sub_iter;
struct wpa_bss *bss;
@@ -358,9 +357,10 @@ DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
/* Create and initialize the return message */
reply = dbus_message_new_method_return(message);
dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING,
- &sub_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) {
@@ -374,13 +374,21 @@ DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
"%s/" WPAS_DBUS_BSSIDS_PART "/"
WPAS_DBUS_BSSID_FORMAT,
wpa_s->dbus_path, MAC2STR(bss->bssid));
- dbus_message_iter_append_basic(&sub_iter,
- DBUS_TYPE_OBJECT_PATH, &path);
+ if (!dbus_message_iter_append_basic(&sub_iter,
+ DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto error;
}
- dbus_message_iter_close_container(&iter, &sub_iter);
+ 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");
}
@@ -400,84 +408,56 @@ DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
{
DBusMessage *reply;
DBusMessageIter iter, iter_dict;
- const u8 *ie;
+ const u8 *wpa_ie, *rsn_ie, *wps_ie;
/* Dump the properties into a dbus message */
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;
+ 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);
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
+ 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))
- goto error;
-
- ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
- (const char *) (ie + 2),
- ie[1]))
- goto error;
- }
-
- ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
- (const char *) ie,
- ie[1] + 2))
- goto error;
- }
-
- ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
- (const char *) ie,
- ie[1] + 2))
- goto error;
- }
-
- ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
- (const char *) ie,
- ie[1] + 2))
- goto error;
- }
-
- if (bss->freq) {
- if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
- bss->freq))
- goto error;
+ 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.");
}
- if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
- bss->caps))
- goto error;
- if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
- goto error;
- if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
- goto error;
- if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
- goto error;
- if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
- wpa_bss_get_max_rate(bss) * 500000))
- 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 "
- "BSSID properties.");
}
@@ -537,37 +517,27 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
if (res < 0) {
if (!strict) {
const char *args[] = {"CCMP", "TKIP", "NONE"};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "pairwise", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto error;
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP"))
- goto error;
- }
-
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "NONE"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &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))
@@ -580,9 +550,10 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
const char *args[] = {
"CCMP", "TKIP", "WEP104", "WEP40"
};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "group", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -592,31 +563,19 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
&iter_array))
goto error;
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP104"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP40"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ 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))
@@ -632,45 +591,30 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "key_mgmt", args,
- sizeof(args) / sizeof(char*)))
+ 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))
- goto error;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
- "NONE"))
- goto error;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
- "IEEE8021X"))
- goto error;
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-EAP"))
- goto error;
- }
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-PSK"))
- goto error;
- }
-
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-NONE"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &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))
@@ -681,33 +625,26 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
if (res < 0) {
if (!strict) {
const char *args[] = { "RSN", "WPA" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "proto", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto error;
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "RSN"))
- goto error;
- }
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &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))
@@ -718,37 +655,27 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
if (res < 0) {
if (!strict) {
const char *args[] = { "OPEN", "SHARED", "LEAP" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "auth_alg", args,
- sizeof(args) / sizeof(char*)))
+ 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))
- goto error;
-
- if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "OPEN"))
- goto error;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "SHARED"))
- goto error;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "LEAP"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &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))
@@ -763,9 +690,9 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
error:
if (reply)
dbus_message_unref(reply);
- return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning "
- "interface capabilities.");
+ return dbus_message_new_error(
+ message, WPAS_ERROR_INTERNAL_ERROR,
+ "an internal error occurred returning interface capabilities.");
}
@@ -786,10 +713,9 @@ DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
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.");
+ 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);
@@ -829,15 +755,15 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
struct wpa_ssid *ssid;
if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_INVALID)) {
+ 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) {
+ if (iface == NULL || net_id == NULL) {
reply = wpas_dbus_new_invalid_network_error(message);
goto out;
}
@@ -857,17 +783,17 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
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.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
+ "error removing the specified on this interface.");
goto out;
}
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
reply = wpas_dbus_new_success_reply(message);
out:
@@ -877,7 +803,7 @@ out:
}
-static const char *dont_quote[] = {
+static const char const *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
"bssid", NULL
@@ -887,8 +813,9 @@ static const char *dont_quote[] = {
static dbus_bool_t should_quote_opt(const char *key)
{
int i = 0;
+
while (dont_quote[i] != NULL) {
- if (strcmp(key, dont_quote[i]) == 0)
+ if (os_strcmp(key, dont_quote[i]) == 0)
return FALSE;
i++;
}
@@ -959,7 +886,7 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
goto error;
ret = os_snprintf(value, size, "\"%s\"",
entry.str_value);
- if (ret < 0 || (size_t) ret != (size - 1))
+ if (os_snprintf_error(size, ret))
goto error;
} else {
value = os_strdup(entry.str_value);
@@ -972,7 +899,7 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
goto error;
ret = os_snprintf(value, size, "%u",
entry.uint32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else if (entry.type == DBUS_TYPE_INT32) {
value = os_zalloc(size);
@@ -980,7 +907,7 @@ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
goto error;
ret = os_snprintf(value, size, "%d",
entry.int32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else
goto error;
@@ -1093,7 +1020,8 @@ DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
goto out;
}
/* Ensure the object path really points to this interface */
- if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
+ if (network == NULL ||
+ os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
reply = wpas_dbus_new_invalid_network_error(message);
goto out;
}
@@ -1203,25 +1131,30 @@ DBusMessage * wpas_dbus_iface_set_smartcard_modules(
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
if (!strcmp(entry.key, "opensc_engine_path") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ 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)) {
+ 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)) {
+ 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;
}
- wpa_dbus_dict_entry_clear(&entry);
}
os_free(wpa_s->conf->opensc_engine_path);
@@ -1292,14 +1225,16 @@ DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
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");
+ 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
@@ -1364,7 +1299,7 @@ DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
blob->len = entry.array_len;
os_memcpy(blob->data, (u8 *) entry.bytearray_value,
entry.array_len);
- if (blob->name == NULL || blob->data == NULL) {
+ if (blob->name == NULL) {
wpa_config_free_blob(blob);
reply = dbus_message_new_error(
message, WPAS_ERROR_ADD_ERROR,
@@ -1403,8 +1338,8 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
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))
+ 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);
@@ -1414,8 +1349,7 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
dbus_message_iter_get_basic(&array, &name);
if (!os_strlen(name))
err_msg = "Invalid blob name.";
-
- if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
+ else if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
err_msg = "Error removing blob.";
else
wpas_notify_blob_removed(wpa_s, name);
@@ -1429,6 +1363,8 @@ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
return wpas_dbus_new_success_reply(message);
}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
/**
* wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h
index 825bc6d..e60ad06 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h
@@ -58,13 +58,13 @@ DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
+ 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);
+ struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_smartcard_modules(
DBusMessage *message, struct wpa_supplicant *wpa_s);
@@ -76,7 +76,7 @@ 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);
+ struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c
index bb79382..5309a53 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c
@@ -36,7 +36,7 @@ DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
DBUS_TYPE_INVALID))
return wpas_dbus_new_invalid_opts_error(message, NULL);
- if (!os_strcmp(arg_bssid, "any"))
+ 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);
@@ -46,10 +46,9 @@ DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
}
if (ret < 0) {
- return dbus_message_new_error(message,
- WPAS_ERROR_WPS_PBC_ERROR,
- "Could not start PBC "
- "negotiation");
+ return dbus_message_new_error(
+ message, WPAS_ERROR_WPS_PBC_ERROR,
+ "Could not start PBC negotiation");
}
return wpas_dbus_new_success_reply(message);
@@ -73,12 +72,13 @@ DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
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"))
+ if (os_strcmp(arg_bssid, "any") == 0)
_bssid = NULL;
else if (!hwaddr_aton(arg_bssid, bssid))
_bssid = bssid;
@@ -104,15 +104,12 @@ DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
if (reply == NULL)
return NULL;
- if (ret == 0) {
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
- DBUS_TYPE_INVALID);
- } else {
- char npin[9];
+ if (ret > 0) {
os_snprintf(npin, sizeof(npin), "%08d", ret);
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin,
- DBUS_TYPE_INVALID);
+ pin = npin;
}
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
+ DBUS_TYPE_INVALID);
return reply;
}
@@ -138,9 +135,7 @@ DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
return wpas_dbus_new_invalid_opts_error(message, NULL);
- if (!os_strcmp(arg_bssid, "any"))
- ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL);
- else if (!hwaddr_aton(arg_bssid, bssid))
+ 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,
@@ -149,7 +144,7 @@ DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
if (ret < 0) {
return dbus_message_new_error(message,
- WPAS_ERROR_WPS_PBC_ERROR,
+ WPAS_ERROR_WPS_REG_ERROR,
"Could not request credentials");
}
diff --git a/contrib/wpa/wpa_supplicant/defconfig b/contrib/wpa/wpa_supplicant/defconfig
index 711b407..7f627fd 100644
--- a/contrib/wpa/wpa_supplicant/defconfig
+++ b/contrib/wpa/wpa_supplicant/defconfig
@@ -20,63 +20,6 @@
# used to fix build issues on such systems (krb5.h not found).
#CFLAGS += -I/usr/include/kerberos
-# Example configuration for various cross-compilation platforms
-
-#### sveasoft (e.g., for Linksys WRT54G) ######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
-#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
-###############################################################################
-
-#### openwrt (e.g., for Linksys WRT54G) #######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
-# -I../WRT54GS/release/src/include
-#LIBS = -lssl
-###############################################################################
-
-
-# Driver interface for Host AP driver
-CONFIG_DRIVER_HOSTAP=y
-
-# Driver interface for Agere driver
-#CONFIG_DRIVER_HERMES=y
-# Change include directories to match with the local setup
-#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
-#CFLAGS += -I../../include/wireless
-
-# Driver interface for madwifi driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_MADWIFI=y
-# Set include directory to the madwifi source tree
-#CFLAGS += -I../../madwifi
-
-# Driver interface for ndiswrapper
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_NDISWRAPPER=y
-
-# Driver interface for Atmel driver
-CONFIG_DRIVER_ATMEL=y
-
-# Driver interface for old Broadcom driver
-# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
-# Linux wireless extensions and does not need (or even work) with the old
-# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
-#CONFIG_DRIVER_BROADCOM=y
-# Example path for wlioctl.h; change to match your configuration
-#CFLAGS += -I/opt/WRT54GS/release/src/include
-
-# Driver interface for Intel ipw2100/2200 driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_IPW=y
-
-# Driver interface for Ralink driver
-#CONFIG_DRIVER_RALINK=y
-
# 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
@@ -88,6 +31,19 @@ CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -111,9 +67,6 @@ CONFIG_DRIVER_NL80211=y
# wpa_supplicant.
# CONFIG_USE_NDISUIO=y
-# Driver interface for development testing
-#CONFIG_DRIVER_TEST=y
-
# Driver interface for wired Ethernet drivers
CONFIG_DRIVER_WIRED=y
@@ -147,10 +100,9 @@ CONFIG_EAP_PEAP=y
CONFIG_EAP_TTLS=y
# EAP-FAST
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
-# to add the needed functions.
+# 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
# EAP-GTC
@@ -197,8 +149,6 @@ CONFIG_EAP_LEAP=y
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
-# Enable WSC 2.0 support
-#CONFIG_WPS2=y
# Enable WPS external registrar functionality
#CONFIG_WPS_ER=y
# Disable credentials for an open network by default when acting as a WPS
@@ -210,6 +160,9 @@ CONFIG_EAP_LEAP=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
@@ -225,14 +178,19 @@ CONFIG_SMARTCARD=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.
@@ -258,11 +216,6 @@ CONFIG_CTRL_IFACE=y
# 35-50 kB in code size.
#CONFIG_NO_WPA=y
-# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
-# save about 1 kB in code size when building only WPA-Personal (no EAP support)
-# or 6 kB if building for WPA-Enterprise.
-#CONFIG_NO_WPA2=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
@@ -297,7 +250,7 @@ CONFIG_BACKEND=file
# main_none = Very basic example (development use only)
#CONFIG_MAIN=main
-# Select wrapper for operatins system and C library specific functions
+# Select wrapper for operating system and C library specific functions
# unix = UNIX/POSIX like systems (default)
# win32 = Windows systems
# none = Empty template
@@ -306,12 +259,14 @@ CONFIG_BACKEND=file
# Select event loop implementation
# eloop = select() loop (default)
# eloop_win = Windows events and WaitForMultipleObject() loop
-# eloop_none = Empty template
#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
+
# Select layer 2 packet implementation
# linux = Linux packet socket (default)
# pcap = libpcap/libdnet/WinPcap
@@ -420,6 +375,10 @@ CONFIG_PEERKEY=y
# 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
@@ -479,6 +438,10 @@ CONFIG_PEERKEY=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
@@ -492,6 +455,9 @@ CONFIG_PEERKEY=y
# Hotspot 2.0
#CONFIG_HS20=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
@@ -504,9 +470,17 @@ CONFIG_PEERKEY=y
# more information on P2P operations.
#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
+# 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.
+# See wpa_supplicant.conf for more information on autoscan usage.
#
# Enabling directly a module will enable autoscan support.
# For exponential module:
diff --git a/contrib/wpa/wpa_supplicant/driver_i.h b/contrib/wpa/wpa_supplicant/driver_i.h
index 847600d..65b430d 100644
--- a/contrib/wpa/wpa_supplicant/driver_i.h
+++ b/contrib/wpa/wpa_supplicant/driver_i.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Internal driver interface wrappers
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -65,9 +65,35 @@ static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_init_mesh(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->init_mesh)
+ return wpa_s->driver->init_mesh(wpa_s->drv_priv);
+ return -1;
+}
+
+static inline int wpa_drv_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_mesh_join_params *params)
+{
+ if (wpa_s->driver->join_mesh)
+ return wpa_s->driver->join_mesh(wpa_s->drv_priv, params);
+ return -1;
+}
+
+static inline int wpa_drv_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->leave_mesh)
+ return wpa_s->driver->leave_mesh(wpa_s->drv_priv);
+ return -1;
+}
+
static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->test_failure == WPAS_TEST_FAILURE_SCAN_TRIGGER)
+ return -EBUSY;
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->driver->scan2)
return wpa_s->driver->scan2(wpa_s->drv_priv, params);
return -1;
@@ -117,11 +143,16 @@ static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid)
static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
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)
-{
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ if (alg != WPA_ALG_NONE) {
+ if (key_idx >= 0 && key_idx <= 6)
+ wpa_s->keys_cleared &= ~BIT(key_idx);
+ else
+ wpa_s->keys_cleared = 0;
+ }
if (wpa_s->driver->set_key) {
- wpa_s->keys_cleared = 0;
return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
alg, addr, key_idx, set_tx,
seq, seq_len, key, key_len);
@@ -129,6 +160,17 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
+ const u8 *addr, int reason_code)
+{
+ if (wpa_s->driver->sta_deauth) {
+ return wpa_s->driver->sta_deauth(wpa_s->drv_priv,
+ wpa_s->own_addr, addr,
+ reason_code);
+ }
+ return -1;
+}
+
static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
const u8 *addr, int reason_code)
{
@@ -190,6 +232,14 @@ static inline const char * wpa_drv_get_ifname(struct wpa_supplicant *wpa_s)
return NULL;
}
+static inline const char *
+wpa_driver_get_radio_name(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->get_radio_name)
+ return wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+ return NULL;
+}
+
static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s)
{
if (wpa_s->driver->get_mac_addr) {
@@ -198,16 +248,6 @@ static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s)
return NULL;
}
-static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
- const u8 *dst, u16 proto,
- const u8 *data, size_t data_len)
-{
- if (wpa_s->driver->send_eapol)
- return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto,
- data, data_len);
- return -1;
-}
-
static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
int state)
{
@@ -264,16 +304,6 @@ static inline int wpa_drv_update_ft_ies(struct wpa_supplicant *wpa_s,
return -1;
}
-static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s,
- u8 action, const u8 *target_ap,
- const u8 *ies, size_t ies_len)
-{
- if (wpa_s->driver->send_ft_action)
- return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action,
- target_ap, ies, ies_len);
- return -1;
-}
-
static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
struct wpa_driver_ap_params *params)
{
@@ -369,7 +399,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);
+ if_addr, bridge, 0);
return -1;
}
@@ -505,188 +535,359 @@ static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu)
return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu);
}
-static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s,
- unsigned int timeout, int type)
+static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
+ const u8 *dst, u8 action_code,
+ u8 dialog_token, u16 status_code,
+ u32 peer_capab, int initiator,
+ const u8 *buf, size_t len)
+{
+ if (wpa_s->driver->send_tdls_mgmt) {
+ return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
+ action_code, dialog_token,
+ status_code, peer_capab,
+ initiator, buf, len);
+ }
+ return -1;
+}
+
+static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
+ enum tdls_oper oper, const u8 *peer)
+{
+ if (!wpa_s->driver->tdls_oper)
+ return -1;
+ return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
+}
+
+#ifdef ANDROID
+static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf, size_t buf_len)
+{
+ if (!wpa_s->driver->driver_cmd)
+ return -1;
+ return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len);
+}
+#endif /* ANDROID */
+
+static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
+ const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
+ const u8 *replay_ctr)
+{
+ if (!wpa_s->driver->set_rekey_info)
+ return;
+ wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kek_len,
+ kck, kck_len, replay_ctr);
+}
+
+static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
+ int disabled)
{
- if (!wpa_s->driver->p2p_find)
+ if (!wpa_s->driver->radio_disable)
return -1;
- return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type);
+ return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled);
}
-static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s)
+static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
+ struct csa_settings *settings)
{
- if (!wpa_s->driver->p2p_stop_find)
+ if (!wpa_s->driver->switch_channel)
return -1;
- return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv);
+ return wpa_s->driver->switch_channel(wpa_s->drv_priv, settings);
}
-static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s,
- unsigned int timeout)
+static inline int wpa_drv_add_ts(struct wpa_supplicant *wpa_s, u8 tsid,
+ const u8 *address, u8 user_priority,
+ u16 admitted_time)
{
- if (!wpa_s->driver->p2p_listen)
+ if (!wpa_s->driver->add_tx_ts)
return -1;
- return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout);
+ return wpa_s->driver->add_tx_ts(wpa_s->drv_priv, tsid, address,
+ user_priority, admitted_time);
}
-static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr, int wps_method,
- int go_intent,
- const u8 *own_interface_addr,
- unsigned int force_freq,
- int persistent_group)
+static inline int wpa_drv_del_ts(struct wpa_supplicant *wpa_s, u8 tid,
+ const u8 *address)
{
- if (!wpa_s->driver->p2p_connect)
+ if (!wpa_s->driver->del_tx_ts)
return -1;
- return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr,
- wps_method, go_intent,
- own_interface_addr, force_freq,
- persistent_group);
+ return wpa_s->driver->del_tx_ts(wpa_s->drv_priv, tid, address);
}
-static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr)
+static inline int wpa_drv_tdls_enable_channel_switch(
+ struct wpa_supplicant *wpa_s, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *freq_params)
{
- if (!wpa_s->driver->wps_success_cb)
+ if (!wpa_s->driver->tdls_enable_channel_switch)
return -1;
- return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr);
+ return wpa_s->driver->tdls_enable_channel_switch(wpa_s->drv_priv, addr,
+ oper_class,
+ freq_params);
}
static inline int
-wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+wpa_drv_tdls_disable_channel_switch(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
{
- if (!wpa_s->driver->p2p_group_formation_failed)
+ if (!wpa_s->driver->tdls_disable_channel_switch)
return -1;
- return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv);
+ return wpa_s->driver->tdls_disable_channel_switch(wpa_s->drv_priv,
+ addr);
}
-static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s,
- const struct p2p_params *params)
+static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
+ enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len)
{
- if (!wpa_s->driver->p2p_set_params)
+ if (!wpa_s->driver->wnm_oper)
return -1;
- return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params);
+ return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf,
+ buf_len);
}
-static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr,
- u16 config_methods, int join)
+static inline int wpa_drv_status(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
{
- if (!wpa_s->driver->p2p_prov_disc_req)
+ if (!wpa_s->driver->status)
return -1;
- return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
- config_methods, join);
+ return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen);
}
-static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
- const u8 *dst,
- const struct wpabuf *tlvs)
+static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
+ const u8 *qos_map_set, u8 qos_map_set_len)
{
- if (!wpa_s->driver->p2p_sd_request)
- return 0;
- return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs);
+ if (!wpa_s->driver->set_qos_map)
+ return -1;
+ return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set,
+ qos_map_set_len);
}
-static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s,
- u64 req)
+static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
+ const struct wowlan_triggers *triggers)
{
- if (!wpa_s->driver->p2p_sd_cancel_request)
+ if (!wpa_s->driver->set_wowlan)
return -1;
- return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req);
+ return wpa_s->driver->set_wowlan(wpa_s->drv_priv, triggers);
}
-static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s,
- int freq, const u8 *dst,
- u8 dialog_token,
- const struct wpabuf *resp_tlvs)
+static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s,
+ int vendor_id, int subcmd, const u8 *data,
+ size_t data_len, struct wpabuf *buf)
{
- if (!wpa_s->driver->p2p_sd_response)
+ if (!wpa_s->driver->vendor_cmd)
return -1;
- return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst,
- dialog_token, resp_tlvs);
+ return wpa_s->driver->vendor_cmd(wpa_s->drv_priv, vendor_id, subcmd,
+ data, data_len, buf);
}
-static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s)
+static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed,
+ const u8 *bssid)
{
- if (!wpa_s->driver->p2p_service_update)
+ if (!wpa_s->driver->roaming)
return -1;
- return wpa_s->driver->p2p_service_update(wpa_s->drv_priv);
+ return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid);
}
-static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s,
- const u8 *addr)
+static inline int wpa_drv_set_mac_addr(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
{
- if (!wpa_s->driver->p2p_reject)
+ if (!wpa_s->driver->set_mac_addr)
return -1;
- return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr);
+ return wpa_s->driver->set_mac_addr(wpa_s->drv_priv, addr);
}
-static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
- const u8 *peer, int role, const u8 *bssid,
- const u8 *ssid, size_t ssid_len,
- const u8 *go_dev_addr,
- int persistent_group)
+
+#ifdef CONFIG_MACSEC
+
+static inline int wpa_drv_macsec_init(struct wpa_supplicant *wpa_s,
+ struct macsec_init_params *params)
{
- if (!wpa_s->driver->p2p_invite)
+ if (!wpa_s->driver->macsec_init)
return -1;
- return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid,
- ssid, ssid_len, go_dev_addr,
- persistent_group);
+ return wpa_s->driver->macsec_init(wpa_s->drv_priv, params);
}
-static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
- const u8 *dst, u8 action_code,
- u8 dialog_token, u16 status_code,
- const u8 *buf, size_t len)
+static inline int wpa_drv_macsec_deinit(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->driver->send_tdls_mgmt) {
- return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
- action_code, dialog_token,
- status_code, buf, len);
- }
- return -1;
+ if (!wpa_s->driver->macsec_deinit)
+ return -1;
+ return wpa_s->driver->macsec_deinit(wpa_s->drv_priv);
}
-static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
- enum tdls_oper oper, const u8 *peer)
+static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
+ Boolean enabled)
{
- if (!wpa_s->driver->tdls_oper)
+ if (!wpa_s->driver->enable_protect_frames)
return -1;
- return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
+ return wpa_s->driver->enable_protect_frames(wpa_s->drv_priv, enabled);
}
-static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
- const u8 *kek, const u8 *kck,
- const u8 *replay_ctr)
+static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
+ Boolean enabled, u32 window)
{
- if (!wpa_s->driver->set_rekey_info)
- return;
- wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+ if (!wpa_s->driver->set_replay_protect)
+ return -1;
+ return wpa_s->driver->set_replay_protect(wpa_s->drv_priv, enabled,
+ window);
}
-static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
- int disabled)
+static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s,
+ const u8 *cs, size_t cs_len)
{
- if (!wpa_s->driver->radio_disable)
+ if (!wpa_s->driver->set_current_cipher_suite)
return -1;
- return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled);
+ return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs,
+ cs_len);
}
-static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
- unsigned int freq)
+static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
+ Boolean enabled)
{
- if (!wpa_s->driver->switch_channel)
+ if (!wpa_s->driver->enable_controlled_port)
return -1;
- return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
+ return wpa_s->driver->enable_controlled_port(wpa_s->drv_priv, enabled);
}
-static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
- enum wnm_oper oper, const u8 *peer,
- u8 *buf, u16 *buf_len)
+static inline int wpa_drv_get_receive_lowest_pn(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an,
+ u32 *lowest_pn)
{
- if (!wpa_s->driver->wnm_oper)
+ if (!wpa_s->driver->get_receive_lowest_pn)
return -1;
- return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf,
- buf_len);
+ return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, channel,
+ an, lowest_pn);
+}
+
+static inline int wpa_drv_get_transmit_next_pn(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an,
+ u32 *next_pn)
+{
+ 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);
+}
+
+static inline int wpa_drv_set_transmit_next_pn(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an,
+ u32 next_pn)
+{
+ 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);
+}
+
+static inline int wpa_drv_get_available_receive_sc(struct wpa_supplicant *wpa_s,
+ u32 *channel)
+{
+ if (!wpa_s->driver->get_available_receive_sc)
+ return -1;
+ return wpa_s->driver->get_available_receive_sc(wpa_s->drv_priv,
+ channel);
+}
+
+static inline int
+wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, u32 channel,
+ const u8 *sci_addr, u16 sci_port,
+ 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);
+}
+
+static inline int wpa_drv_delete_receive_sc(struct wpa_supplicant *wpa_s,
+ u32 channel)
+{
+ if (!wpa_s->driver->delete_receive_sc)
+ return -1;
+ return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, channel);
+}
+
+static inline int wpa_drv_create_receive_sa(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an,
+ u32 lowest_pn, const u8 *sak)
+{
+ 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);
+}
+
+static inline int wpa_drv_enable_receive_sa(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an)
+{
+ if (!wpa_s->driver->enable_receive_sa)
+ return -1;
+ return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, channel, an);
+}
+
+static inline int wpa_drv_disable_receive_sa(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an)
+{
+ if (!wpa_s->driver->disable_receive_sa)
+ return -1;
+ return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, channel, an);
+}
+
+static inline int
+wpa_drv_get_available_transmit_sc(struct wpa_supplicant *wpa_s, u32 *channel)
+{
+ if (!wpa_s->driver->get_available_transmit_sc)
+ return -1;
+ return wpa_s->driver->get_available_transmit_sc(wpa_s->drv_priv,
+ channel);
+}
+
+static inline int
+wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, u32 channel,
+ const u8 *sci_addr, u16 sci_port,
+ 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,
+ conf_offset);
+}
+
+static inline int wpa_drv_delete_transmit_sc(struct wpa_supplicant *wpa_s,
+ u32 channel)
+{
+ if (!wpa_s->driver->delete_transmit_sc)
+ return -1;
+ return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, channel);
+}
+
+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)
+{
+ 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);
+}
+
+static inline int wpa_drv_enable_transmit_sa(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an)
+{
+ if (!wpa_s->driver->enable_transmit_sa)
+ return -1;
+ return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, channel, an);
+}
+
+static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s,
+ u32 channel, u8 an)
+{
+ if (!wpa_s->driver->disable_transmit_sa)
+ return -1;
+ return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, channel, an);
}
+#endif /* CONFIG_MACSEC */
#endif /* DRIVER_I_H */
diff --git a/contrib/wpa/wpa_supplicant/eap_proxy_dummy.mak b/contrib/wpa/wpa_supplicant/eap_proxy_dummy.mak
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/eap_proxy_dummy.mak
diff --git a/contrib/wpa/wpa_supplicant/eap_proxy_dummy.mk b/contrib/wpa/wpa_supplicant/eap_proxy_dummy.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/eap_proxy_dummy.mk
diff --git a/contrib/wpa/wpa_supplicant/eap_register.c b/contrib/wpa/wpa_supplicant/eap_register.c
index d1eb4ff..ece5716 100644
--- a/contrib/wpa/wpa_supplicant/eap_register.c
+++ b/contrib/wpa/wpa_supplicant/eap_register.c
@@ -40,6 +40,13 @@ int eap_register_methods(void)
ret = eap_peer_unauth_tls_register();
#endif /* EAP_UNAUTH_TLS */
+#ifdef EAP_TLS
+#ifdef CONFIG_HS20
+ if (ret == 0)
+ ret = eap_peer_wfa_unauth_tls_register();
+#endif /* CONFIG_HS20 */
+#endif /* EAP_TLS */
+
#ifdef EAP_MSCHAPv2
if (ret == 0)
ret = eap_peer_mschapv2_register();
@@ -135,6 +142,11 @@ int eap_register_methods(void)
ret = eap_peer_pwd_register();
#endif /* EAP_PWD */
+#ifdef EAP_EKE
+ if (ret == 0)
+ ret = eap_peer_eke_register();
+#endif /* EAP_EKE */
+
#ifdef EAP_SERVER_IDENTITY
if (ret == 0)
ret = eap_server_identity_register();
diff --git a/contrib/wpa/wpa_supplicant/eapol_test.c b/contrib/wpa/wpa_supplicant/eapol_test.c
index 80fe2c6..9b7af30 100644
--- a/contrib/wpa/wpa_supplicant/eapol_test.c
+++ b/contrib/wpa/wpa_supplicant/eapol_test.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - test code
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,18 +21,15 @@
#include "eloop.h"
#include "utils/base64.h"
#include "rsn_supp/wpa.h"
-#include "eap_peer/eap_i.h"
#include "wpa_supplicant_i.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "common/wpa_ctrl.h"
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
+#include "wpas_glue.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
struct wpa_driver_ops *wpa_drivers[] = { NULL };
@@ -49,6 +46,7 @@ struct eapol_test_data {
int eapol_test_num_reauths;
int no_mppe_keys;
int num_mppe_ok, num_mppe_mismatch;
+ int req_eap_key_name;
u8 radius_identifier;
struct radius_msg *last_recv_radius;
@@ -61,6 +59,8 @@ struct eapol_test_data {
u8 authenticator_pmk[PMK_LEN];
size_t authenticator_pmk_len;
+ u8 authenticator_eap_key_name[256];
+ size_t authenticator_eap_key_name_len;
int radius_access_accept_received;
int radius_access_reject_received;
int auth_timed_out;
@@ -73,6 +73,9 @@ struct eapol_test_data {
struct extra_radius_attr *extra_attrs;
FILE *server_cert_file;
+
+ const char *pcsc_reader;
+ const char *pcsc_pin;
};
static struct eapol_test_data eapol_test;
@@ -211,6 +214,13 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
goto fail;
}
+ if (e->req_eap_key_name &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_EAP_KEY_NAME, (u8 *) "\0",
+ 1)) {
+ printf("Could not add EAP-Key-Name\n");
+ goto fail;
+ }
+
if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &e->own_ip_addr, 4)) {
@@ -336,6 +346,8 @@ static int eapol_test_compare_pmk(struct eapol_test_data *e)
{
u8 pmk[PMK_LEN];
int ret = 1;
+ const u8 *sess_id;
+ size_t sess_id_len;
if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN);
@@ -364,14 +376,37 @@ static int eapol_test_compare_pmk(struct eapol_test_data *e)
else if (!e->no_mppe_keys)
e->num_mppe_ok++;
+ sess_id = eapol_sm_get_session_id(e->wpa_s->eapol, &sess_id_len);
+ if (!sess_id)
+ return ret;
+ if (e->authenticator_eap_key_name_len == 0) {
+ wpa_printf(MSG_INFO, "No EAP-Key-Name received from server");
+ return ret;
+ }
+
+ if (e->authenticator_eap_key_name_len != sess_id_len ||
+ os_memcmp(e->authenticator_eap_key_name, sess_id, sess_id_len) != 0)
+ {
+ wpa_printf(MSG_INFO,
+ "Locally derived EAP Session-Id does not match EAP-Key-Name from server");
+ wpa_hexdump(MSG_DEBUG, "EAP Session-Id", sess_id, sess_id_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-Key-Name from server",
+ e->authenticator_eap_key_name,
+ e->authenticator_eap_key_name_len);
+ } else {
+ wpa_printf(MSG_INFO,
+ "Locally derived EAP Session-Id matches EAP-Key-Name from server");
+ }
+
return ret;
}
-static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
+static void eapol_sm_cb(struct eapol_sm *eapol, enum eapol_supp_result result,
+ void *ctx)
{
struct eapol_test_data *e = ctx;
- printf("eapol_sm_cb: success=%d\n", success);
+ printf("eapol_sm_cb: result=%d\n", result);
e->eapol_test_num_reauths--;
if (e->eapol_test_num_reauths < 0)
eloop_terminate();
@@ -396,7 +431,56 @@ static void eapol_test_write_cert(FILE *f, const char *subject,
}
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+ const char *default_txt)
+{
+ struct eapol_test_data *e = ctx;
+ struct wpa_supplicant *wpa_s = e->wpa_s;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const char *field_name, *txt = NULL;
+ char *buf;
+ size_t buflen;
+ int len;
+
+ if (ssid == NULL)
+ return;
+
+ field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+ &txt);
+ if (field_name == NULL) {
+ wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+ field);
+ return;
+ }
+
+ buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ len = os_snprintf(buf, buflen,
+ WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+ field_name, ssid->id, txt);
+ if (os_snprintf_error(buflen, len)) {
+ os_free(buf);
+ return;
+ }
+ if (ssid->ssid && buflen > len + ssid->ssid_len) {
+ os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+ len += ssid->ssid_len;
+ buf[len] = '\0';
+ }
+ buf[buflen - 1] = '\0';
+ wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+ os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_test_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
@@ -426,6 +510,14 @@ static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
eapol_test_write_cert(e->server_cert_file,
subject, cert);
}
+
+ if (altsubject) {
+ int i;
+
+ for (i = 0; i < num_altsubject; i++)
+ wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "depth=%d %s", depth, altsubject[i]);
+ }
}
@@ -485,6 +577,8 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
+ ctx->eap_param_needed = eapol_test_eap_param_needed;
ctx->cert_cb = eapol_test_cert_cb;
ctx->cert_in_cb = 1;
ctx->set_anon_id = eapol_test_set_anon_id;
@@ -502,6 +596,7 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
eapol_conf.required_keys = 0;
eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
+ eapol_conf.external_sim = wpa_s->conf->external_sim;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
@@ -701,6 +796,8 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e,
size_t shared_secret_len)
{
struct radius_ms_mppe_keys *keys;
+ u8 *buf;
+ size_t len;
keys = radius_msg_get_ms_keys(msg, req, shared_secret,
shared_secret_len);
@@ -739,6 +836,14 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e,
os_free(keys->recv);
os_free(keys);
}
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
+ NULL) == 0) {
+ os_memcpy(e->authenticator_eap_key_name, buf, len);
+ e->authenticator_eap_key_name_len = len;
+ } else {
+ e->authenticator_eap_key_name_len = 0;
+ }
}
@@ -833,7 +938,11 @@ static void wpa_init_conf(struct eapol_test_data *e,
*pos++ = a[3];
}
#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
- inet_aton(authsrv, &as->addr.u.v4);
+ if (inet_aton(authsrv, &as->addr.u.v4) < 0) {
+ wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
+ authsrv);
+ assert(0);
+ }
#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
as->addr.af = AF_INET;
as->port = port;
@@ -862,7 +971,7 @@ static void wpa_init_conf(struct eapol_test_data *e,
}
-static int scard_test(void)
+static int scard_test(struct eapol_test_data *e)
{
struct scard_data *scard;
size_t len;
@@ -893,10 +1002,10 @@ static int scard_test(void)
unsigned char aka_ik[IK_LEN];
unsigned char aka_ck[CK_LEN];
- scard = scard_init(SCARD_TRY_BOTH, NULL);
+ scard = scard_init(e->pcsc_reader);
if (scard == NULL)
return -1;
- if (scard_set_pin(scard, "1234")) {
+ if (scard_set_pin(scard, e->pcsc_pin)) {
wpa_printf(MSG_WARNING, "PIN validation failed");
scard_deinit(scard);
return -1;
@@ -971,7 +1080,7 @@ failed:
}
-static int scard_get_triplets(int argc, char *argv[])
+static int scard_get_triplets(struct eapol_test_data *e, int argc, char *argv[])
{
struct scard_data *scard;
size_t len;
@@ -993,7 +1102,7 @@ static int scard_get_triplets(int argc, char *argv[])
wpa_debug_level = 99;
}
- scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
+ scard = scard_init(e->pcsc_reader);
if (scard == NULL) {
printf("Failed to open smartcard connection\n");
return -1;
@@ -1047,11 +1156,12 @@ static void eapol_test_terminate(int sig, void *signal_ctx)
static void usage(void)
{
printf("usage:\n"
- "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
+ "eapol_test [-enWS] -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"
- " [-N<attr spec>] \\\n"
+ " [-N<attr spec>] [-R<PC/SC reader>] "
+ "[-P<PC/SC PIN>] \\\n"
" [-A<client IP>]\n"
"eapol_test scard\n"
"eapol_test sim <PIN> <num triplets> [debug]\n"
@@ -1067,6 +1177,7 @@ static void usage(void)
" -A<client IP> = IP address of the client, default: select "
"automatically\n"
" -r<count> = number of re-authentications\n"
+ " -e = Request EAP-Key-Name\n"
" -W = wait for a control interface monitor before starting\n"
" -S = save configuration after authentication\n"
" -n = no MPPE keys expected\n"
@@ -1095,6 +1206,7 @@ static void usage(void)
int main(int argc, char *argv[])
{
+ struct wpa_global global;
struct wpa_supplicant wpa_s;
int c, ret = 1, wait_for_monitor = 0, save_config = 0;
char *as_addr = "127.0.0.1";
@@ -1114,12 +1226,13 @@ int main(int argc, char *argv[])
os_memset(&eapol_test, 0, sizeof(eapol_test));
eapol_test.connect_info = "CONNECT 11Mbps 802.11b";
os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN);
+ eapol_test.pcsc_pin = "1234";
wpa_debug_level = 0;
wpa_debug_show_keys = 1;
for (;;) {
- c = getopt(argc, argv, "a:A:c:C:M:nN:o:p:r:s:St:W");
+ c = getopt(argc, argv, "a:A:c:C:eM:nN:o:p:P:r:R:s:St:W");
if (c < 0)
break;
switch (c) {
@@ -1135,6 +1248,9 @@ int main(int argc, char *argv[])
case 'C':
eapol_test.connect_info = optarg;
break;
+ case 'e':
+ eapol_test.req_eap_key_name = 1;
+ break;
case 'M':
if (hwaddr_aton(optarg, eapol_test.own_addr)) {
usage();
@@ -1157,9 +1273,15 @@ int main(int argc, char *argv[])
case 'p':
as_port = atoi(optarg);
break;
+ case 'P':
+ eapol_test.pcsc_pin = optarg;
+ break;
case 'r':
eapol_test.eapol_test_num_reauths = atoi(optarg);
break;
+ case 'R':
+ eapol_test.pcsc_reader = optarg;
+ break;
case 's':
as_secret = optarg;
break;
@@ -1207,11 +1329,11 @@ int main(int argc, char *argv[])
}
if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
- return scard_test();
+ return scard_test(&eapol_test);
}
if (argc > optind && os_strcmp(argv[optind], "sim") == 0) {
- return scard_get_triplets(argc - optind - 1,
+ return scard_get_triplets(&eapol_test, argc - optind - 1,
&argv[optind + 1]);
}
@@ -1231,9 +1353,13 @@ int main(int argc, char *argv[])
return -1;
}
+ os_memset(&global, 0, sizeof(global));
os_memset(&wpa_s, 0, sizeof(wpa_s));
+ wpa_s.global = &global;
eapol_test.wpa_s = &wpa_s;
- wpa_s.conf = wpa_config_read(conf);
+ dl_list_init(&wpa_s.bss);
+ dl_list_init(&wpa_s.bss_id);
+ wpa_s.conf = wpa_config_read(conf, NULL);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", conf);
return -1;
@@ -1243,6 +1369,11 @@ int main(int argc, char *argv[])
return -1;
}
+ if (eapol_test.pcsc_reader) {
+ os_free(wpa_s.conf->pcsc_reader);
+ wpa_s.conf->pcsc_reader = os_strdup(eapol_test.pcsc_reader);
+ }
+
wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
cli_addr);
wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
diff --git a/contrib/wpa/wpa_supplicant/events.c b/contrib/wpa/wpa_supplicant/events.c
index baca363..d275ca4 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -42,17 +42,26 @@
#include "scan.h"
#include "offchannel.h"
#include "interworking.h"
+#include "mesh.h"
+#include "mesh_mpm.h"
+#include "wmm_ac.h"
+
+
+#ifndef CONFIG_NO_SCAN_PROCESSING
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+ int new_scan, int own_request);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- struct os_time now;
+ struct os_reltime now;
if (ssid == NULL || ssid->disabled_until.sec == 0)
return 0;
- os_get_time(&now);
+ os_get_reltime(&now);
if (ssid->disabled_until.sec > now.sec)
return ssid->disabled_until.sec - now.sec;
@@ -62,13 +71,46 @@ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
}
+static struct wpa_bss * wpa_supplicant_get_new_bss(
+ struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_bss *bss = NULL;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (ssid->ssid_len > 0)
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+ if (!bss)
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+
+ return bss;
+}
+
+
+static void wpa_supplicant_update_current_bss(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+
+ if (!bss) {
+ wpa_supplicant_update_scan_results(wpa_s);
+
+ /* Get the BSS from the new scan results */
+ bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+ }
+
+ if (bss)
+ wpa_s->current_bss = bss;
+}
+
+
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid, *old_ssid;
int res;
- if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
+ if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) {
+ wpa_supplicant_update_current_bss(wpa_s);
return 0;
+ }
wpa_dbg(wpa_s, MSG_DEBUG, "Select network based on association "
"information");
@@ -102,8 +144,9 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
u8 wpa_ie[80];
size_t wpa_ie_len = sizeof(wpa_ie);
- wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len);
+ if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+ wpa_ie, &wpa_ie_len) < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites");
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
}
@@ -112,6 +155,9 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
eapol_sm_invalidate_cached_session(wpa_s->eapol);
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
+
+ wpa_supplicant_update_current_bss(wpa_s);
+
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)
@@ -129,6 +175,15 @@ void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx)
wpa_s->countermeasures = 0;
wpa_drv_set_countermeasures(wpa_s, 0);
wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
+
+ /*
+ * It is possible that the device is sched scanning, which means
+ * that a connection attempt will be done only when we receive
+ * scan results. However, in this case, it would be preferable
+ * to scan and connect immediately, so cancel the sched_scan and
+ * issue a regular scan flow.
+ */
+ wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
}
@@ -156,20 +211,12 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
+ sme_clear_on_disassoc(wpa_s);
#ifdef CONFIG_P2P
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
#endif /* CONFIG_P2P */
wpa_s->current_bss = NULL;
wpa_s->assoc_freq = 0;
-#ifdef CONFIG_IEEE80211R
-#ifdef CONFIG_SME
- if (wpa_s->sme.ft_ies)
- sme_update_ft_ies(wpa_s, NULL, NULL, 0);
-#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211R */
if (bssid_changed)
wpas_notify_bssid_changed(wpa_s);
@@ -180,7 +227,10 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->key_mgmt = 0;
+
+ wpas_rrm_reset(wpa_s);
}
@@ -199,7 +249,7 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
ie.pmkid + i * PMKID_LEN,
NULL, NULL, 0);
if (pmksa_set == 0) {
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
break;
}
}
@@ -265,12 +315,13 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
{
#ifdef IEEE8021X_EAPOL
#ifdef PCSC_FUNCS
- int aka = 0, sim = 0, type;
+ int aka = 0, sim = 0;
- if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+ if ((ssid != NULL && ssid->eap.pcsc == NULL) ||
+ wpa_s->scard != NULL || wpa_s->conf->external_sim)
return 0;
- if (ssid->eap.eap_methods == NULL) {
+ if (ssid == NULL || ssid->eap.eap_methods == NULL) {
sim = 1;
aka = 1;
} else {
@@ -304,14 +355,8 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
"(sim=%d aka=%d) - initialize PCSC", sim, aka);
- if (sim && aka)
- type = SCARD_TRY_BOTH;
- else if (aka)
- type = SCARD_USIM_ONLY;
- else
- type = SCARD_GSM_SIM_ONLY;
- wpa_s->scard = scard_init(type, NULL);
+ wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
if (wpa_s->scard == NULL) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
"(pcsc-lite)");
@@ -327,10 +372,24 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
#ifndef CONFIG_NO_SCAN_PROCESSING
+
+static int has_wep_key(struct wpa_ssid *ssid)
+{
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
struct wpa_ssid *ssid)
{
- int i, privacy = 0;
+ int privacy = 0;
if (ssid->mixed_cell)
return 1;
@@ -340,12 +399,9 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
return 1;
#endif /* CONFIG_WPS */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i]) {
- privacy = 1;
- break;
- }
- }
+ if (has_wep_key(ssid))
+ privacy = 1;
+
#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
@@ -356,6 +412,9 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
if (wpa_key_mgmt_wpa(ssid->key_mgmt))
privacy = 1;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)
+ privacy = 1;
+
if (bss->caps & IEEE80211_CAP_PRIVACY)
return privacy;
return !privacy;
@@ -426,8 +485,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) ==
+ wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
"frame protection");
@@ -497,6 +555,12 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
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");
+ return 1;
+ }
+
if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
return 1;
@@ -523,24 +587,6 @@ static int freq_allowed(int *freqs, int freq)
}
-static int ht_supported(const struct hostapd_hw_modes *mode)
-{
- if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
- /*
- * The driver did not indicate whether it supports HT. Assume
- * it does to avoid connection issues.
- */
- return 1;
- }
-
- /*
- * IEEE Std 802.11n-2009 20.1.1:
- * An HT non-AP STA shall support all EQM rates for one spatial stream.
- */
- return mode->mcs_set[0] == 0xff;
-}
-
-
static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
@@ -606,6 +652,18 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
continue;
}
+ /* There's also a VHT selector for 802.11ac */
+ 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");
+ return 0;
+ }
+ continue;
+ }
+
if (!flagged)
continue;
@@ -620,9 +678,10 @@ 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",
- r / 10, r % 10);
+ 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;
}
}
@@ -632,15 +691,60 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
}
+/*
+ * Test whether BSS is in an ESS.
+ * This is done differently in DMG (60 GHz) and non-DMG bands
+ */
+static int bss_is_ess(struct wpa_bss *bss)
+{
+ if (bss_is_dmg(bss)) {
+ return (bss->caps & IEEE80211_CAP_DMG_MASK) ==
+ IEEE80211_CAP_DMG_AP;
+ }
+
+ return ((bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+ IEEE80211_CAP_ESS);
+}
+
+
+static int match_mac_mask(const u8 *addr_a, const u8 *addr_b, const u8 *mask)
+{
+ size_t i;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if ((addr_a[i] & mask[i]) != (addr_b[i] & mask[i]))
+ return 0;
+ }
+ return 1;
+}
+
+
+static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++) {
+ const u8 *a = list + i * ETH_ALEN * 2;
+ const u8 *m = a + ETH_ALEN;
+
+ if (match_mac_mask(a, addr, m))
+ return 1;
+ }
+ return 0;
+}
+
+
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
- struct wpa_ssid *group)
+ struct wpa_ssid *group,
+ int only_first_ssid)
{
u8 wpa_ie_len, rsn_ie_len;
int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
+ int osen;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
@@ -648,11 +752,18 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
+ 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%s",
+ "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%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,
- wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
+ 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) {
@@ -692,7 +803,7 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
- for (ssid = group; ssid; ssid = ssid->pnext) {
+ for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
int res;
@@ -747,10 +858,28 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
+ /* check blacklist */
+ 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");
+ continue;
+ }
+
+ /* if there is a whitelist, only accept those APs */
+ 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");
+ continue;
+ }
+
if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
continue;
- if (!wpa &&
+ if (!osen && !wpa &&
!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
@@ -759,15 +888,26 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
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");
+ continue;
+ }
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
+ 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");
continue;
}
- if (bss->caps & IEEE80211_CAP_IBSS) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - IBSS (adhoc) "
- "network");
+ if (!bss_is_ess(bss)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network");
continue;
}
@@ -784,6 +924,39 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
}
#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");
+ continue;
+ }
+
+ if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+ struct wpabuf *p2p_ie;
+ u8 dev_addr[ETH_ALEN];
+
+ ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (ie == NULL) {
+ 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");
+ 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");
+ wpabuf_free(p2p_ie);
+ continue;
+ }
+ wpabuf_free(p2p_ie);
+ }
+
/*
* TODO: skip the AP if its P2P IE has Group Formation
* bit set in the P2P Group Capability Bitmap and we
@@ -803,16 +976,22 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
static struct wpa_bss *
wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
struct wpa_ssid *group,
- struct wpa_ssid **selected_ssid)
+ struct wpa_ssid **selected_ssid,
+ int only_first_ssid)
{
unsigned int i;
- wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
- group->priority);
+ if (only_first_ssid)
+ wpa_dbg(wpa_s, MSG_DEBUG, "Try to find BSS matching pre-selected network id=%d",
+ group->id);
+ else
+ wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
+ group->priority);
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
struct wpa_bss *bss = wpa_s->last_scan_res[i];
- *selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group);
+ *selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
+ only_first_ssid);
if (!*selected_ssid)
continue;
wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
@@ -826,22 +1005,41 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
}
-static struct wpa_bss *
-wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
- struct wpa_ssid **selected_ssid)
+struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **selected_ssid)
{
struct wpa_bss *selected = NULL;
int prio;
+ struct wpa_ssid *next_ssid = NULL;
if (wpa_s->last_scan_res == NULL ||
wpa_s->last_scan_res_used == 0)
return NULL; /* no scan results from last update */
+ if (wpa_s->next_ssid) {
+ struct wpa_ssid *ssid;
+
+ /* check that next_ssid is still valid */
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->next_ssid)
+ break;
+ }
+ next_ssid = ssid;
+ wpa_s->next_ssid = NULL;
+ }
+
while (selected == NULL) {
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
+ if (next_ssid && next_ssid->priority ==
+ wpa_s->conf->pssid[prio]->priority) {
+ selected = wpa_supplicant_select_bss(
+ wpa_s, next_ssid, selected_ssid, 1);
+ if (selected)
+ break;
+ }
selected = wpa_supplicant_select_bss(
wpa_s, wpa_s->conf->pssid[prio],
- selected_ssid);
+ selected_ssid, 0);
if (selected)
break;
}
@@ -872,9 +1070,6 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request "
"since there are no enabled networks");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-#ifdef CONFIG_P2P
- wpa_s->sta_scan_pending = 0;
-#endif /* CONFIG_P2P */
return;
}
@@ -891,8 +1086,12 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
"PBC session overlap");
#ifdef CONFIG_P2P
- if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1)
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT ||
+ wpa_s->p2p_in_provisioning) {
+ eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb,
+ wpa_s, NULL);
return -1;
+ }
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS
@@ -901,6 +1100,15 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
return -1;
}
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Considering connect request: reassociate: %d selected: "
+ MACSTR " bssid: " MACSTR " pending: " MACSTR
+ " wpa_state: %s ssid=%p current_ssid=%p",
+ wpa_s->reassociate, MAC2STR(selected->bssid),
+ MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ ssid, wpa_s->current_ssid);
+
/*
* Do not trigger new association unless the BSSID has changed or if
* reassociation is requested. If we are in process of associating with
@@ -910,22 +1118,21 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
(os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
((wpa_s->wpa_state != WPA_ASSOCIATING &&
wpa_s->wpa_state != WPA_AUTHENTICATING) ||
- os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
- 0))) {
+ (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+ 0) ||
+ (is_zero_ether_addr(wpa_s->pending_bssid) &&
+ ssid != wpa_s->current_ssid)))) {
if (wpa_supplicant_scard_init(wpa_s, ssid)) {
wpa_supplicant_req_new_scan(wpa_s, 10, 0);
return 0;
}
- wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
- "reassociate: %d selected: "MACSTR " bssid: " MACSTR
- " pending: " MACSTR " wpa_state: %s",
- wpa_s->reassociate, MAC2STR(selected->bssid),
- MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
- wpa_supplicant_state_txt(wpa_s->wpa_state));
+ wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
+ MAC2STR(selected->bssid));
wpa_supplicant_associate(wpa_s, selected, ssid);
} else {
- wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
- "selected AP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
+ "connect with the selected AP");
}
return 0;
@@ -944,7 +1151,8 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
if (wpas_network_disabled(wpa_s, ssid))
continue;
if (ssid->mode == IEEE80211_MODE_IBSS ||
- ssid->mode == IEEE80211_MODE_AP)
+ ssid->mode == IEEE80211_MODE_AP ||
+ ssid->mode == IEEE80211_MODE_MESH)
return ssid;
}
}
@@ -1016,10 +1224,14 @@ 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",
- MAC2STR(current_bss->bssid), current_bss->level);
- wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
- MAC2STR(selected->bssid), selected->level);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
+ " level=%d snr=%d est_throughput=%u",
+ MAC2STR(current_bss->bssid), 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,
+ selected->snr, selected->est_throughput);
if (wpa_s->current_ssid->bssid_set &&
os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) ==
@@ -1029,6 +1241,12 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
return 1;
}
+ if (selected->est_throughput > current_bss->est_throughput + 5000) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation - selected BSS has better estimated throughput");
+ return 1;
+ }
+
if (current_bss->level < 0 && current_bss->level > selected->level) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
@@ -1064,9 +1282,11 @@ 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. */
static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+ union wpa_event_data *data,
+ int own_request)
{
- struct wpa_scan_results *scan_res;
+ struct wpa_scan_results *scan_res = NULL;
+ int ret = 0;
int ap = 0;
#ifndef CONFIG_NO_RANDOM_POOL
size_t i, num;
@@ -1079,33 +1299,20 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpa_supplicant_notify_scanning(wpa_s, 0);
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete &&
- !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending &&
- !wpa_s->scan_res_handler) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "stopped scan processing");
- wpa_s->sta_scan_pending = 1;
- wpa_supplicant_req_scan(wpa_s, 5, 0);
- return -1;
- }
- }
- wpa_s->sta_scan_pending = 0;
-#endif /* CONFIG_P2P */
-
scan_res = wpa_supplicant_get_scan_results(wpa_s,
data ? &data->scan_info :
NULL, 1);
if (scan_res == NULL) {
- if (wpa_s->conf->ap_scan == 2 || ap)
+ if (wpa_s->conf->ap_scan == 2 || ap ||
+ wpa_s->scan_res_handler == scan_only_handler)
+ return -1;
+ if (!own_request)
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);
- return -1;
+ ret = -1;
+ goto scan_work_done;
}
#ifndef CONFIG_NO_RANDOM_POOL
@@ -1124,16 +1331,16 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_NO_RANDOM_POOL */
- if (wpa_s->scan_res_handler) {
+ if (own_request && wpa_s->scan_res_handler &&
+ (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) {
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);
-
- wpa_scan_results_free(scan_res);
- return -2;
+ ret = -2;
+ goto scan_work_done;
}
if (ap) {
@@ -1142,63 +1349,90 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
if (wpa_s->ap_iface->scan_cb)
wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
#endif /* CONFIG_AP */
- wpa_scan_results_free(scan_res);
- return 0;
+ goto scan_work_done;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
- wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ 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);
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+ 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;
+ } else {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ }
wpas_notify_scan_results(wpa_s);
wpas_notify_scan_done(wpa_s, 1);
- if (sme_proc_obss_scan(wpa_s) > 0) {
+ if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) {
+ 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;
}
- if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
- wpa_scan_results_free(scan_res);
- return 0;
- }
+ if (wnm_scan_process(wpa_s, 1) > 0)
+ goto scan_work_done;
- if (autoscan_notify_scan(wpa_s, scan_res)) {
- wpa_scan_results_free(scan_res);
- return 0;
- }
+ if (sme_proc_obss_scan(wpa_s) > 0)
+ goto scan_work_done;
+
+ if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
+ goto scan_work_done;
+
+ if (autoscan_notify_scan(wpa_s, scan_res))
+ goto scan_work_done;
if (wpa_s->disconnected) {
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
- wpa_scan_results_free(scan_res);
- return 0;
+ goto scan_work_done;
}
if (!wpas_driver_bss_selection(wpa_s) &&
- bgscan_notify_scan(wpa_s, scan_res) == 1) {
- wpa_scan_results_free(scan_res);
- return 0;
- }
+ bgscan_notify_scan(wpa_s, scan_res) == 1)
+ goto scan_work_done;
wpas_wps_update_ap_info(wpa_s, scan_res);
wpa_scan_results_free(scan_res);
- return wpas_select_network_from_last_scan(wpa_s);
+ if (wpa_s->scan_work) {
+ struct wpa_radio_work *work = wpa_s->scan_work;
+ wpa_s->scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
+
+scan_work_done:
+ wpa_scan_results_free(scan_res);
+ if (wpa_s->scan_work) {
+ struct wpa_radio_work *work = wpa_s->scan_work;
+ wpa_s->scan_work = NULL;
+ radio_work_done(work);
+ }
+ return ret;
}
-int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
+ int new_scan, int own_request)
{
struct wpa_bss *selected;
struct wpa_ssid *ssid = NULL;
+ if (wpa_s->p2p_mgmt)
+ return 0; /* no normal connection on p2p_mgmt interface */
+
selected = wpa_supplicant_pick_network(wpa_s, &ssid);
if (selected) {
int skip;
skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
if (skip) {
- wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+ if (new_scan)
+ wpa_supplicant_rsn_preauth_scan_results(wpa_s);
return 0;
}
@@ -1206,30 +1440,52 @@ int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
return -1;
}
- wpa_supplicant_rsn_preauth_scan_results(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.
*/
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) {
wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
wpa_supplicant_associate(wpa_s, NULL, ssid);
- wpa_supplicant_rsn_preauth_scan_results(wpa_s);
- } else {
+ if (new_scan)
+ wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+ } else if (own_request) {
+ /*
+ * No SSID found. If SCAN results are as a result of
+ * own scan request and not due to a scan request on
+ * another shared interface, try another scan.
+ */
int timeout_sec = wpa_s->scan_interval;
int timeout_usec = 0;
#ifdef CONFIG_P2P
- if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+ int res;
+
+ res = wpas_p2p_scan_no_go_seen(wpa_s);
+ if (res == 2)
+ return 2;
+ if (res == 1)
return 0;
- if (wpa_s->p2p_in_provisioning) {
+ if (wpa_s->p2p_in_provisioning ||
+ wpa_s->show_group_started ||
+ wpa_s->p2p_in_invitation) {
/*
* Use shorter wait during P2P Provisioning
- * state to speed up group formation.
+ * state and during P2P join-a-group operation
+ * to speed up group formation.
*/
timeout_sec = 0;
timeout_usec = 250000;
@@ -1251,6 +1507,16 @@ int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
return 1;
}
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_WPS
+ if (wpa_s->after_wps > 0 || wpas_wps_searching(wpa_s)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Use shorter wait during WPS processing");
+ timeout_sec = 0;
+ timeout_usec = 500000;
+ wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+ timeout_usec);
+ return 0;
+ }
+#endif /* CONFIG_WPS */
if (wpa_supplicant_req_sched_scan(wpa_s))
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
timeout_usec);
@@ -1260,13 +1526,21 @@ int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
}
-static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
{
- const char *rn, *rn2;
struct wpa_supplicant *ifs;
+ int res;
- if (_wpa_supplicant_event_scan_results(wpa_s, data) != 0) {
+ res = _wpa_supplicant_event_scan_results(wpa_s, data, 1);
+ if (res == 2) {
+ /*
+ * Interface may have been removed, so must not dereference
+ * wpa_s after this.
+ */
+ return 1;
+ }
+ if (res != 0) {
/*
* If no scan results could be fetched, then no need to
* notify those interfaces that did not actually request
@@ -1274,39 +1548,48 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
* interface, do not notify other interfaces to avoid concurrent
* operations during a connection attempt.
*/
- return;
+ return 0;
}
/*
- * Check other interfaces to see if they have the same radio-name. If
+ * Check other interfaces to see if they share the same radio. If
* so, they get updated with this same scan info.
*/
- if (!wpa_s->driver->get_radio_name)
- return;
-
- rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
- if (rn == NULL || rn[0] == '\0')
- return;
-
- wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
- "sharing same radio (%s) in event_scan_results", rn);
-
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs == wpa_s || !ifs->driver->get_radio_name)
- continue;
-
- rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
- if (rn2 && os_strcmp(rn, rn2) == 0) {
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs != wpa_s) {
wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
"sibling", ifs->ifname);
- _wpa_supplicant_event_scan_results(ifs, data);
+ _wpa_supplicant_event_scan_results(ifs, data, 0);
}
}
+
+ return 0;
}
#endif /* CONFIG_NO_SCAN_PROCESSING */
+int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+ struct os_reltime now;
+
+ if (wpa_s->last_scan_res_used <= 0)
+ return -1;
+
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
+ wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
+ return -1;
+ }
+
+ return wpas_select_network_from_last_scan(wpa_s, 0, 1);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
#ifdef CONFIG_WNM
static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
@@ -1387,11 +1670,51 @@ void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s)
}
+#ifdef CONFIG_INTERWORKING
+
+static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
+ size_t len)
+{
+ int res;
+
+ wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len);
+ res = wpa_drv_set_qos_map(wpa_s, qos_map, len);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver");
+ }
+
+ return res;
+}
+
+
+static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+
+ if (ies == NULL)
+ return;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+ if (elems.qos_map_set) {
+ wpas_qos_map_set(wpa_s, elems.qos_map_set,
+ elems.qos_map_set_len);
+ }
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
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
+ u8 bssid[ETH_ALEN];
+#endif /* CONFIG_IEEE80211R */
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
if (data->assoc_info.req_ies)
@@ -1408,6 +1731,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+ interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+#endif /* CONFIG_INTERWORKING */
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -1446,7 +1773,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
- u8 bssid[ETH_ALEN];
if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
@@ -1504,6 +1830,23 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SME */
+ /* Process FT when SME is in the driver */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ wpa_ft_is_completed(wpa_s->wpa)) {
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ wpa_ft_validate_reassoc_resp(wpa_s->wpa,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of "
+ "Reassociation Response failed");
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_INVALID_IE);
+ return -1;
+ }
+ wpa_dbg(wpa_s, MSG_DEBUG, "FT: Reassociation Response done");
+ }
+
wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */
@@ -1560,21 +1903,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
-static struct wpa_bss * wpa_supplicant_get_new_bss(
- struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
- struct wpa_bss *bss = NULL;
- struct wpa_ssid *ssid = wpa_s->current_ssid;
-
- if (ssid->ssid_len > 0)
- bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
- if (!bss)
- bss = wpa_bss_get_bssid(wpa_s, bssid);
-
- return bss;
-}
-
-
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{
const u8 *bss_wpa = NULL, *bss_rsn = NULL;
@@ -1604,10 +1932,11 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
{
u8 bssid[ETH_ALEN];
int ft_completed;
- struct wpa_driver_capa capa;
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
+ if (!data)
+ return;
hostapd_notif_assoc(wpa_s->ap_iface->bss[0],
data->assoc_info.addr,
data->assoc_info.req_ies,
@@ -1645,20 +1974,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
return;
}
- if (wpa_s->current_ssid) {
- struct wpa_bss *bss = NULL;
-
- bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
- if (!bss) {
- wpa_supplicant_update_scan_results(wpa_s);
-
- /* Get the BSS from the new scan results */
- bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
- }
-
- if (bss)
- wpa_s->current_bss = bss;
- }
if (wpa_s->conf->ap_scan == 1 &&
wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
@@ -1671,6 +1986,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_SME
os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
wpa_s->sme.prev_bssid_set = 1;
+ wpa_s->sme.last_unprot_disconnect.sec = 0;
#endif /* CONFIG_SME */
wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
@@ -1706,6 +2022,17 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
(wpa_s->current_ssid &&
wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+ if (wpa_s->current_ssid &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
+ /*
+ * Set the key after having received joined-IBSS event
+ * from the driver.
+ */
+ wpa_supplicant_set_wpa_none_key(wpa_s,
+ wpa_s->current_ssid);
+ }
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
} else if (!ft_completed) {
@@ -1746,9 +2073,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->last_eapol_matches_bssid = 0;
if (wpa_s->pending_eapol_rx) {
- struct os_time now, age;
- os_get_time(&now);
- os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
+ 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 &&
os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
0) {
@@ -1766,8 +2093,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
- wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
- capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) {
+ wpa_s->current_ssid &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
}
@@ -1791,6 +2118,15 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IBSS_RSN */
wpas_wps_notify_assoc(wpa_s, bssid);
+
+ if (data) {
+ wmm_ac_notify_assoc(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ &data->assoc_info.wmm_params);
+
+ if (wpa_s->reassoc_same_bss)
+ wmm_ac_restore_tspecs(wpa_s);
+ }
}
@@ -1881,13 +2217,18 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
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");
- wpas_auth_failed(wpa_s);
- }
- if (!wpa_s->auto_reconnect_disabled ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+ if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
+ return; /* P2P group removed */
+ wpas_auth_failed(wpa_s, "WRONG_KEY");
+ }
+ if (!wpa_s->disconnected &&
+ (!wpa_s->auto_reconnect_disabled ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS ||
+ wpas_wps_searching(wpa_s))) {
wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
- "reconnect (wps=%d wpa_state=%d)",
+ "reconnect (wps=%d/%d wpa_state=%d)",
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
+ wpas_wps_searching(wpa_s),
wpa_s->wpa_state);
if (wpa_s->wpa_state == WPA_COMPLETED &&
wpa_s->current_ssid &&
@@ -1927,7 +2268,6 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
wpas_notify_disconnect_reason(wpa_s);
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
- wpa_s->keys_cleared = 0;
wpa_clear_keys(wpa_s, wpa_s->bssid);
}
last_ssid = wpa_s->current_ssid;
@@ -1938,7 +2278,12 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
wpa_s->current_ssid = last_ssid;
}
- if (fast_reconnect) {
+ if (fast_reconnect &&
+ !wpas_network_disabled(wpa_s, fast_reconnect_ssid) &&
+ !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)) {
#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,
@@ -1947,6 +2292,14 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
wpa_supplicant_req_scan(wpa_s, 0, 100000);
}
#endif /* CONFIG_NO_SCAN_PROCESSING */
+ } else if (fast_reconnect) {
+ /*
+ * Could not reconnect to the same BSS due to network being
+ * disabled. Use a new scan to match the alternative behavior
+ * above, i.e., to continue automatic reconnection attempt in a
+ * way that enforces disabled network rules.
+ */
+ wpa_supplicant_req_scan(wpa_s, 0, 100000);
}
}
@@ -1971,13 +2324,13 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
int pairwise;
- struct os_time t;
+ struct os_reltime t;
wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
pairwise = (data && data->michael_mic_failure.unicast);
- os_get_time(&t);
- if ((wpa_s->last_michael_mic_error &&
- t.sec - wpa_s->last_michael_mic_error <= 60) ||
+ os_get_reltime(&t);
+ if ((wpa_s->last_michael_mic_error.sec &&
+ !os_reltime_expired(&t, &wpa_s->last_michael_mic_error, 60)) ||
wpa_s->pending_mic_error_report) {
if (wpa_s->pending_mic_error_report) {
/*
@@ -2055,7 +2408,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
}
- wpa_s->last_michael_mic_error = t.sec;
+ wpa_s->last_michael_mic_error = t;
wpa_s->mic_errors_seen++;
}
@@ -2090,7 +2443,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
"driver after interface was added");
}
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
break;
case EVENT_INTERFACE_REMOVED:
wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
@@ -2099,10 +2451,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = NULL;
-#ifdef CONFIG_IBSS_RSN
- ibss_rsn_deinit(wpa_s->ibss_rsn);
- wpa_s->ibss_rsn = NULL;
-#endif /* CONFIG_IBSS_RSN */
#ifdef CONFIG_TERMINATE_ONLASTIF
/* check if last interface */
if (!any_interfaces(wpa_s->global->ifaces))
@@ -2133,11 +2481,23 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
return;
switch (data->tdls.oper) {
case TDLS_REQUEST_SETUP:
- wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+ wpa_tdls_remove(wpa_s->wpa, data->tdls.peer);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+ else
+ wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer);
break;
case TDLS_REQUEST_TEARDOWN:
- wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
- data->tdls.reason_code);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
+ data->tdls.reason_code);
+ else
+ wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN,
+ data->tdls.peer);
+ break;
+ case TDLS_REQUEST_DISCOVER:
+ wpa_tdls_send_discovery_request(wpa_s->wpa,
+ data->tdls.peer);
break;
}
}
@@ -2200,6 +2560,23 @@ static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
}
+
+
+static void wpa_supplicant_event_ibss_auth(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (ssid == NULL)
+ return;
+
+ /* check if the ssid is correctly configured as IBSS/RSN */
+ if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
+ return;
+
+ ibss_rsn_handle_auth(wpa_s->ibss_rsn, data->rx_mgmt.frame,
+ data->rx_mgmt.frame_len);
+}
#endif /* CONFIG_IBSS_RSN */
@@ -2283,12 +2660,393 @@ static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
}
+static void wpas_event_disconnect(struct wpa_supplicant *wpa_s, const u8 *addr,
+ u16 reason_code, int locally_generated,
+ const u8 *ie, size_t ie_len, int deauth)
+{
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface && addr) {
+ hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], addr);
+ return;
+ }
+
+ if (wpa_s->ap_iface) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in AP mode");
+ return;
+ }
+#endif /* CONFIG_AP */
+
+ if (!locally_generated)
+ wpa_s->own_disconnect_req = 0;
+
+ wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated);
+
+ if (((reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+ ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+ (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+ eapol_sm_failed(wpa_s->eapol))) &&
+ !wpa_s->eap_expected_failure))
+ wpas_auth_failed(wpa_s, "AUTH_FAILED");
+
+#ifdef CONFIG_P2P
+ if (deauth && reason_code > 0) {
+ if (wpas_p2p_deauth_notif(wpa_s, addr, reason_code, ie, ie_len,
+ locally_generated) > 0) {
+ /*
+ * The interface was removed, so cannot continue
+ * processing any additional operations after this.
+ */
+ return;
+ }
+ }
+#endif /* CONFIG_P2P */
+
+ wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
+ locally_generated);
+}
+
+
+static void wpas_event_disassoc(struct wpa_supplicant *wpa_s,
+ struct disassoc_info *info)
+{
+ u16 reason_code = 0;
+ int locally_generated = 0;
+ const u8 *addr = NULL;
+ const u8 *ie = NULL;
+ size_t ie_len = 0;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
+
+ if (info) {
+ addr = info->addr;
+ ie = info->ie;
+ ie_len = info->ie_len;
+ reason_code = info->reason_code;
+ locally_generated = info->locally_generated;
+ wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code,
+ locally_generated ? " (locally generated)" : "");
+ if (addr)
+ wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+ MAC2STR(addr));
+ wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
+ ie, ie_len);
+ }
+
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface && info && info->addr) {
+ hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], info->addr);
+ return;
+ }
+
+ if (wpa_s->ap_iface) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in AP mode");
+ return;
+ }
+#endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+ if (info) {
+ wpas_p2p_disassoc_notif(
+ wpa_s, info->addr, reason_code, info->ie, info->ie_len,
+ locally_generated);
+ }
+#endif /* CONFIG_P2P */
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ sme_event_disassoc(wpa_s, info);
+
+ wpas_event_disconnect(wpa_s, addr, reason_code, locally_generated,
+ ie, ie_len, 0);
+}
+
+
+static void wpas_event_deauth(struct wpa_supplicant *wpa_s,
+ struct deauth_info *info)
+{
+ u16 reason_code = 0;
+ int locally_generated = 0;
+ const u8 *addr = NULL;
+ const u8 *ie = NULL;
+ size_t ie_len = 0;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Deauthentication notification");
+
+ if (info) {
+ addr = info->addr;
+ ie = info->ie;
+ ie_len = info->ie_len;
+ reason_code = info->reason_code;
+ locally_generated = info->locally_generated;
+ wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+ reason_code,
+ locally_generated ? " (locally generated)" : "");
+ if (addr) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+ MAC2STR(addr));
+ }
+ wpa_hexdump(MSG_DEBUG, "Deauthentication frame IE(s)",
+ ie, ie_len);
+ }
+
+ wpa_reset_ft_completed(wpa_s->wpa);
+
+ wpas_event_disconnect(wpa_s, addr, reason_code,
+ locally_generated, ie, ie_len, 1);
+}
+
+
+static const char * reg_init_str(enum reg_change_initiator init)
+{
+ switch (init) {
+ case REGDOM_SET_BY_CORE:
+ return "CORE";
+ case REGDOM_SET_BY_USER:
+ return "USER";
+ case REGDOM_SET_BY_DRIVER:
+ return "DRIVER";
+ case REGDOM_SET_BY_COUNTRY_IE:
+ return "COUNTRY_IE";
+ case REGDOM_BEACON_HINT:
+ return "BEACON_HINT";
+ }
+ return "?";
+}
+
+
+static const char * reg_type_str(enum reg_type type)
+{
+ switch (type) {
+ case REGDOM_TYPE_UNKNOWN:
+ return "UNKNOWN";
+ case REGDOM_TYPE_COUNTRY:
+ return "COUNTRY";
+ case REGDOM_TYPE_WORLD:
+ return "WORLD";
+ case REGDOM_TYPE_CUSTOM_WORLD:
+ return "CUSTOM_WORLD";
+ case REGDOM_TYPE_INTERSECTION:
+ return "INTERSECTION";
+ }
+ return "?";
+}
+
+
+static void wpa_supplicant_update_channel_list(
+ struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
+{
+ struct wpa_supplicant *ifs;
+
+ 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 (wpa_s->drv_priv == NULL)
+ return; /* Ignore event during drv initialization */
+
+ free_hw_features(wpa_s);
+ wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+ wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
+ wpas_p2p_update_channel_list(wpa_s);
+
+ /*
+ * Check other interfaces to see if they share the same radio. If
+ * so, they get updated with this same hw mode info.
+ */
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs != wpa_s) {
+ wpa_printf(MSG_DEBUG, "%s: Updating hw mode",
+ ifs->ifname);
+ free_hw_features(ifs);
+ ifs->hw.modes = wpa_drv_get_hw_feature_data(
+ ifs, &ifs->hw.num_modes, &ifs->hw.flags);
+ }
+ }
+}
+
+
+static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
+ const u8 *frame, size_t len, int freq,
+ int rssi)
+{
+ const struct ieee80211_mgmt *mgmt;
+ const u8 *payload;
+ size_t plen;
+ u8 category;
+
+ if (len < IEEE80211_HDRLEN + 2)
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ payload = frame + IEEE80211_HDRLEN;
+ category = *payload++;
+ plen = len - IEEE80211_HDRLEN - 1;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
+ " Category=%u DataLen=%d freq=%d MHz",
+ MAC2STR(mgmt->sa), category, (int) plen, freq);
+
+ if (category == WLAN_ACTION_WMM) {
+ wmm_ac_rx_action(wpa_s, mgmt->da, mgmt->sa, payload, plen);
+ return;
+ }
+
+#ifdef CONFIG_IEEE80211R
+ if (category == WLAN_ACTION_FT) {
+ ft_rx_action(wpa_s, payload, plen);
+ return;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_SME
+ if (category == WLAN_ACTION_SA_QUERY) {
+ sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen);
+ return;
+ }
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_WNM
+ if (mgmt->u.action.category == WLAN_ACTION_WNM) {
+ ieee802_11_rx_wnm_action(wpa_s, mgmt, len);
+ return;
+ }
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_GAS
+ if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC ||
+ mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) &&
+ gas_query_rx(wpa_s->gas, mgmt->da, mgmt->sa, mgmt->bssid,
+ mgmt->u.action.category,
+ payload, plen, freq) == 0)
+ return;
+#endif /* CONFIG_GAS */
+
+#ifdef CONFIG_TDLS
+ if (category == WLAN_ACTION_PUBLIC && plen >= 4 &&
+ payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "TDLS: Received Discovery Response from " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_INTERWORKING
+ if (category == WLAN_ACTION_QOS && plen >= 1 &&
+ payload[0] == QOS_QOS_MAP_CONFIG) {
+ const u8 *pos = payload + 1;
+ size_t qlen = plen - 1;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) == 0 &&
+ qlen > 2 && pos[0] == WLAN_EID_QOS_MAP_SET &&
+ pos[1] <= qlen - 2 && pos[1] >= 16)
+ wpas_qos_map_set(wpa_s, pos + 2, pos[1]);
+ return;
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ 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;
+ }
+
+ if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ payload[0] == WLAN_RRM_LINK_MEASUREMENT_REQUEST) {
+ wpas_rrm_handle_link_measurement_request(wpa_s, mgmt->sa,
+ payload + 1, plen - 1,
+ rssi);
+ return;
+ }
+
+ wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+ category, payload, plen, freq);
+ if (wpa_s->ifmsh)
+ mesh_mpm_action_rx(wpa_s, mgmt, len);
+}
+
+
+static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *event)
+{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *ifs;
+#endif /* CONFIG_P2P */
+ struct wpa_freq_range_list *list;
+ char *str = NULL;
+
+ list = &event->freq_range;
+
+ if (list->num)
+ str = freq_range_list_str(list);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AVOID_FREQ "ranges=%s",
+ str ? str : "");
+
+#ifdef CONFIG_P2P
+ if (freq_range_list_parse(&wpa_s->global->p2p_go_avoid_freq, str)) {
+ wpa_dbg(wpa_s, MSG_ERROR, "%s: Failed to parse freq range",
+ __func__);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Update channel list based on frequency avoid event");
+ wpas_p2p_update_channel_list(wpa_s);
+ }
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ int freq;
+ if (!ifs->current_ssid ||
+ !ifs->current_ssid->p2p_group ||
+ (ifs->current_ssid->mode != WPAS_MODE_P2P_GO &&
+ ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION))
+ continue;
+
+ freq = ifs->current_ssid->frequency;
+ if (!freq_range_list_includes(list, freq)) {
+ wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating frequency %d MHz in safe range",
+ freq);
+ continue;
+ }
+
+ wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating in unsafe frequency %d MHz",
+ freq);
+ /* TODO: Consider using CSA or removing the group within
+ * wpa_supplicant */
+ wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
+ }
+#endif /* CONFIG_P2P */
+
+ os_free(str);
+}
+
+
+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);
+ 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);
+ }
+ 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);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
- u16 reason_code = 0;
- int locally_generated = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
event != EVENT_INTERFACE_ENABLED &&
@@ -2325,129 +3083,62 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
case EVENT_ASSOC:
wpa_supplicant_event_assoc(wpa_s, data);
+ if (data && data->assoc_info.authorized)
+ wpa_supplicant_event_assoc_auth(wpa_s, data);
break;
case EVENT_DISASSOC:
- wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
- if (data) {
- wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
- data->disassoc_info.reason_code,
- data->disassoc_info.locally_generated ?
- " (locally generated)" : "");
- if (data->disassoc_info.addr)
- wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
- MAC2STR(data->disassoc_info.addr));
- }
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
- hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
- data->disassoc_info.addr);
- break;
- }
- if (wpa_s->ap_iface) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in "
- "AP mode");
- break;
- }
-#endif /* CONFIG_AP */
- if (data) {
- reason_code = data->disassoc_info.reason_code;
- locally_generated =
- data->disassoc_info.locally_generated;
- wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
- data->disassoc_info.ie,
- data->disassoc_info.ie_len);
-#ifdef CONFIG_P2P
- wpas_p2p_disassoc_notif(
- wpa_s, data->disassoc_info.addr, reason_code,
- data->disassoc_info.ie,
- data->disassoc_info.ie_len,
- locally_generated);
-#endif /* CONFIG_P2P */
- }
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
- sme_event_disassoc(wpa_s, data);
- /* fall through */
+ wpas_event_disassoc(wpa_s,
+ data ? &data->disassoc_info : NULL);
+ break;
case EVENT_DEAUTH:
- if (event == EVENT_DEAUTH) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Deauthentication notification");
- if (data) {
- reason_code = data->deauth_info.reason_code;
- locally_generated =
- data->deauth_info.locally_generated;
- wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
- data->deauth_info.reason_code,
- data->deauth_info.locally_generated ?
- " (locally generated)" : "");
- if (data->deauth_info.addr) {
- wpa_dbg(wpa_s, MSG_DEBUG, " * address "
- MACSTR,
- MAC2STR(data->deauth_info.
- addr));
- }
- wpa_hexdump(MSG_DEBUG,
- "Deauthentication frame IE(s)",
- data->deauth_info.ie,
- data->deauth_info.ie_len);
- }
- }
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface && data && data->deauth_info.addr) {
- hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
- data->deauth_info.addr);
- break;
- }
- if (wpa_s->ap_iface) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in "
- "AP mode");
- break;
- }
-#endif /* CONFIG_AP */
- wpa_supplicant_event_disassoc(wpa_s, reason_code,
- locally_generated);
- if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
- ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
- (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
- eapol_sm_failed(wpa_s->eapol)))
- wpas_auth_failed(wpa_s);
-#ifdef CONFIG_P2P
- if (event == EVENT_DEAUTH && data) {
- if (wpas_p2p_deauth_notif(wpa_s,
- data->deauth_info.addr,
- reason_code,
- data->deauth_info.ie,
- data->deauth_info.ie_len,
- locally_generated) > 0) {
- /*
- * The interface was removed, so cannot
- * continue processing any additional
- * operations after this.
- */
- break;
- }
- }
-#endif /* CONFIG_P2P */
- wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
- locally_generated);
+ wpas_event_deauth(wpa_s,
+ data ? &data->deauth_info : NULL);
break;
case EVENT_MICHAEL_MIC_FAILURE:
wpa_supplicant_event_michael_mic_failure(wpa_s, data);
break;
#ifndef CONFIG_NO_SCAN_PROCESSING
- case EVENT_SCAN_RESULTS:
- wpa_supplicant_event_scan_results(wpa_s, data);
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL &&
- wpa_s->wpa_state != WPA_AUTHENTICATING &&
- wpa_s->wpa_state != WPA_ASSOCIATING) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after scan result processing");
+ case EVENT_SCAN_STARTED:
+ os_get_reltime(&wpa_s->scan_start_time);
+ if (wpa_s->own_scan_requested) {
+ struct os_reltime diff;
+
+ 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",
+ diff.sec, diff.usec);
+ wpa_s->own_scan_requested = 0;
+ wpa_s->own_scan_running = 1;
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_use_id) {
+ wpa_msg_ctrl(wpa_s, MSG_INFO,
+ WPA_EVENT_SCAN_STARTED "id=%u",
+ wpa_s->manual_scan_id);
+ } else {
+ wpa_msg_ctrl(wpa_s, MSG_INFO,
+ WPA_EVENT_SCAN_STARTED);
+ }
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
+ wpa_s->radio->external_scan_running = 1;
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
}
- }
-#endif /* CONFIG_P2P */
+ break;
+ case EVENT_SCAN_RESULTS:
+ if (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);
+ wpa_s->scan_start_time.sec = 0;
+ wpa_s->scan_start_time.usec = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
+ diff.sec, diff.usec);
+ }
+ 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;
+ radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
case EVENT_ASSOCINFO:
@@ -2505,10 +3196,24 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
break;
case EVENT_AUTH_TIMED_OUT:
+ /* It is possible to get this event from earlier connection */
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_MESH) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore AUTH_TIMED_OUT in mesh configuration");
+ break;
+ }
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_auth_timed_out(wpa_s, data);
break;
case EVENT_ASSOC_TIMED_OUT:
+ /* It is possible to get this event from earlier connection */
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_MESH) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore ASSOC_TIMED_OUT in mesh configuration");
+ break;
+ }
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_timed_out(wpa_s, data);
break;
@@ -2596,22 +3301,66 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
-#ifdef CONFIG_AP
wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset);
-#endif /* CONFIG_AP */
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
+ break;
+#ifdef NEED_AP_MLME
+ case EVENT_DFS_RADAR_DETECTED:
+ if (data)
+ wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event);
break;
+ case EVENT_DFS_CAC_STARTED:
+ if (data)
+ wpas_event_dfs_cac_started(wpa_s, &data->dfs_event);
+ break;
+ case EVENT_DFS_CAC_FINISHED:
+ if (data)
+ wpas_event_dfs_cac_finished(wpa_s, &data->dfs_event);
+ break;
+ case EVENT_DFS_CAC_ABORTED:
+ 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;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ext_mgmt_frame_handling) {
+ struct rx_mgmt *rx = &data->rx_mgmt;
+ size_t hex_len = 2 * rx->frame_len + 1;
+ char *hex = os_malloc(hex_len);
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len,
+ rx->frame, rx->frame_len);
+ wpa_msg(wpa_s, MSG_INFO, "MGMT-RX freq=%d datarate=%u ssi_signal=%d %s",
+ rx->freq, rx->datarate, rx->ssi_signal,
+ hex);
+ os_free(hex);
+ }
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
mgmt = (const struct ieee80211_mgmt *)
data->rx_mgmt.frame;
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
+#ifdef CONFIG_AP
if (wpa_s->ap_iface == NULL) {
+#endif /* CONFIG_AP */
#ifdef CONFIG_P2P
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
data->rx_mgmt.frame_len > 24) {
@@ -2627,9 +3376,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_IBSS_RSN
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
+ stype == WLAN_FC_STYPE_AUTH &&
+ data->rx_mgmt.frame_len >= 30) {
+ wpa_supplicant_event_ibss_auth(wpa_s, data);
+ break;
+ }
+#endif /* CONFIG_IBSS_RSN */
+
+ if (stype == WLAN_FC_STYPE_ACTION) {
+ wpas_event_rx_mgmt_action(
+ wpa_s, data->rx_mgmt.frame,
+ data->rx_mgmt.frame_len,
+ data->rx_mgmt.freq,
+ data->rx_mgmt.ssi_signal);
+ break;
+ }
+
+ if (wpa_s->ifmsh) {
+ mesh_mpm_mgmt_rx(wpa_s, &data->rx_mgmt);
+ break;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
"management frame in non-AP mode");
break;
+#ifdef CONFIG_AP
}
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
@@ -2645,65 +3419,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
ap_mgmt_rx(wpa_s, &data->rx_mgmt);
- break;
- }
#endif /* CONFIG_AP */
- case EVENT_RX_ACTION:
- wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
- " Category=%u DataLen=%d freq=%d MHz",
- MAC2STR(data->rx_action.sa),
- data->rx_action.category, (int) data->rx_action.len,
- data->rx_action.freq);
-#ifdef CONFIG_IEEE80211R
- if (data->rx_action.category == WLAN_ACTION_FT) {
- ft_rx_action(wpa_s, data->rx_action.data,
- data->rx_action.len);
- break;
- }
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-#ifdef CONFIG_SME
- if (data->rx_action.category == WLAN_ACTION_SA_QUERY) {
- sme_sa_query_rx(wpa_s, data->rx_action.sa,
- data->rx_action.data,
- data->rx_action.len);
- break;
- }
-#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WNM
- if (data->rx_action.category == WLAN_ACTION_WNM) {
- ieee802_11_rx_wnm_action(wpa_s, &data->rx_action);
- break;
- }
-#endif /* CONFIG_WNM */
-#ifdef CONFIG_GAS
- if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
- gas_query_rx(wpa_s->gas, data->rx_action.da,
- data->rx_action.sa, data->rx_action.bssid,
- data->rx_action.data, data->rx_action.len,
- data->rx_action.freq) == 0)
- break;
-#endif /* CONFIG_GAS */
-#ifdef CONFIG_TDLS
- if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
- data->rx_action.len >= 4 &&
- data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
- wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
- "Response from " MACSTR,
- MAC2STR(data->rx_action.sa));
- break;
- }
-#endif /* CONFIG_TDLS */
-#ifdef CONFIG_P2P
- wpas_p2p_rx_action(wpa_s, data->rx_action.da,
- data->rx_action.sa,
- data->rx_action.bssid,
- data->rx_action.category,
- data->rx_action.data,
- data->rx_action.len, data->rx_action.freq);
-#endif /* CONFIG_P2P */
break;
+ }
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
data->rx_probe_req.ie == NULL)
@@ -2720,14 +3438,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
#endif /* CONFIG_AP */
-#ifdef CONFIG_P2P
wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa,
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
data->rx_probe_req.ie_len,
data->rx_probe_req.ssi_signal);
-#endif /* CONFIG_P2P */
break;
case EVENT_REMAIN_ON_CHANNEL:
#ifdef CONFIG_OFFCHANNEL
@@ -2735,93 +3451,32 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s, data->remain_on_channel.freq,
data->remain_on_channel.duration);
#endif /* CONFIG_OFFCHANNEL */
-#ifdef CONFIG_P2P
wpas_p2p_remain_on_channel_cb(
wpa_s, data->remain_on_channel.freq,
data->remain_on_channel.duration);
-#endif /* CONFIG_P2P */
break;
case EVENT_CANCEL_REMAIN_ON_CHANNEL:
#ifdef CONFIG_OFFCHANNEL
offchannel_cancel_remain_on_channel_cb(
wpa_s, data->remain_on_channel.freq);
#endif /* CONFIG_OFFCHANNEL */
-#ifdef CONFIG_P2P
wpas_p2p_cancel_remain_on_channel_cb(
wpa_s, data->remain_on_channel.freq);
-#endif /* CONFIG_P2P */
- break;
-#ifdef CONFIG_P2P
- case EVENT_P2P_DEV_FOUND: {
- struct p2p_peer_info peer_info;
-
- os_memset(&peer_info, 0, sizeof(peer_info));
- if (data->p2p_dev_found.dev_addr)
- os_memcpy(peer_info.p2p_device_addr,
- data->p2p_dev_found.dev_addr, ETH_ALEN);
- if (data->p2p_dev_found.pri_dev_type)
- os_memcpy(peer_info.pri_dev_type,
- data->p2p_dev_found.pri_dev_type,
- sizeof(peer_info.pri_dev_type));
- if (data->p2p_dev_found.dev_name)
- os_strlcpy(peer_info.device_name,
- data->p2p_dev_found.dev_name,
- sizeof(peer_info.device_name));
- peer_info.config_methods = data->p2p_dev_found.config_methods;
- peer_info.dev_capab = data->p2p_dev_found.dev_capab;
- peer_info.group_capab = data->p2p_dev_found.group_capab;
-
- /*
- * FIX: new_device=1 is not necessarily correct. We should
- * maintain a P2P peer database in wpa_supplicant and update
- * this information based on whether the peer is truly new.
- */
- wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1);
- break;
- }
- case EVENT_P2P_GO_NEG_REQ_RX:
- wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src,
- data->p2p_go_neg_req_rx.dev_passwd_id);
- break;
- case EVENT_P2P_GO_NEG_COMPLETED:
- wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res);
- break;
- case EVENT_P2P_PROV_DISC_REQUEST:
- wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer,
- data->p2p_prov_disc_req.config_methods,
- data->p2p_prov_disc_req.dev_addr,
- data->p2p_prov_disc_req.pri_dev_type,
- data->p2p_prov_disc_req.dev_name,
- data->p2p_prov_disc_req.supp_config_methods,
- data->p2p_prov_disc_req.dev_capab,
- data->p2p_prov_disc_req.group_capab,
- NULL, 0);
- break;
- case EVENT_P2P_PROV_DISC_RESPONSE:
- wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
- data->p2p_prov_disc_resp.config_methods);
- break;
- case EVENT_P2P_SD_REQUEST:
- wpas_sd_request(wpa_s, data->p2p_sd_req.freq,
- data->p2p_sd_req.sa,
- data->p2p_sd_req.dialog_token,
- data->p2p_sd_req.update_indic,
- data->p2p_sd_req.tlvs,
- data->p2p_sd_req.tlvs_len);
break;
- case EVENT_P2P_SD_RESPONSE:
- wpas_sd_response(wpa_s, data->p2p_sd_resp.sa,
- data->p2p_sd_resp.update_indic,
- data->p2p_sd_resp.tlvs,
- data->p2p_sd_resp.tlvs_len);
- break;
-#endif /* CONFIG_P2P */
case EVENT_EAPOL_RX:
wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
data->eapol_rx.data,
data->eapol_rx.data_len);
break;
case EVENT_SIGNAL_CHANGE:
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE
+ "above=%d signal=%d noise=%d txrate=%d",
+ data->signal_change.above_threshold,
+ data->signal_change.current_signal,
+ data->signal_change.current_noise,
+ data->signal_change.current_txrate);
+ wpa_bss_update_level(wpa_s->current_bss,
+ data->signal_change.current_signal);
bgscan_notify_signal_change(
wpa_s, data->signal_change.above_threshold,
data->signal_change.current_signal,
@@ -2832,10 +3487,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_supplicant_update_mac_addr(wpa_s);
+ if (wpa_s->p2p_mgmt) {
+ wpa_supplicant_set_state(wpa_s,
+ WPA_DISCONNECTED);
+ break;
+ }
+
#ifdef CONFIG_AP
if (!wpa_s->ap_iface) {
wpa_supplicant_set_state(wpa_s,
WPA_DISCONNECTED);
+ wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else
wpa_supplicant_set_state(wpa_s,
@@ -2848,25 +3510,59 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
case EVENT_INTERFACE_DISABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO ||
+ (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)) {
+ /*
+ * Mark interface disabled if this happens to end up not
+ * being removed as a separate P2P group interface.
+ */
+ wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+ /*
+ * The interface was externally disabled. Remove
+ * it assuming an external entity will start a
+ * new session if needed.
+ */
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->p2p_group)
+ wpas_p2p_interface_unavailable(wpa_s);
+ else
+ wpas_p2p_disconnect(wpa_s);
+ /*
+ * wpa_s instance may have been freed, so must not use
+ * it here anymore.
+ */
+ break;
+ }
+ if (wpa_s->p2p_scan_work && wpa_s->global->p2p &&
+ p2p_in_progress(wpa_s->global->p2p) > 1) {
+ /* This radio work will be cancelled, so clear P2P
+ * state as well.
+ */
+ p2p_stop_find(wpa_s->global->p2p);
+ }
+#endif /* CONFIG_P2P */
+
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ /*
+ * Indicate disconnection to keep ctrl_iface events
+ * consistent.
+ */
+ wpa_supplicant_event_disassoc(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
+ }
wpa_supplicant_mark_disassoc(wpa_s);
+ radio_remove_works(wpa_s, NULL, 0);
+
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
break;
case EVENT_CHANNEL_LIST_CHANGED:
- if (wpa_s->drv_priv == NULL)
- break; /* Ignore event during drv initialization */
-
- free_hw_features(wpa_s);
- wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
- wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
-
-#ifdef CONFIG_P2P
- wpas_p2p_update_channel_list(wpa_s);
-#endif /* CONFIG_P2P */
+ wpa_supplicant_update_channel_list(
+ wpa_s, &data->channel_list_changed);
break;
case EVENT_INTERFACE_UNAVAILABLE:
-#ifdef CONFIG_P2P
wpas_p2p_interface_unavailable(wpa_s);
-#endif /* CONFIG_P2P */
break;
case EVENT_BEST_CHANNEL:
wpa_dbg(wpa_s, MSG_DEBUG, "Best channel event received "
@@ -2876,11 +3572,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s->best_24_freq = data->best_chan.freq_24;
wpa_s->best_5_freq = data->best_chan.freq_5;
wpa_s->best_overall_freq = data->best_chan.freq_overall;
-#ifdef CONFIG_P2P
wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24,
data->best_chan.freq_5,
data->best_chan.freq_overall);
-#endif /* CONFIG_P2P */
break;
case EVENT_UNPROT_DEAUTH:
wpa_supplicant_event_unprot_deauth(wpa_s,
@@ -2898,7 +3592,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
#ifdef CONFIG_TDLS
if (data)
- wpa_tdls_disable_link(wpa_s->wpa, data->low_ack.addr);
+ wpa_tdls_disable_unreachable_link(wpa_s->wpa,
+ data->low_ack.addr);
#endif /* CONFIG_TDLS */
break;
case EVENT_IBSS_PEER_LOST:
@@ -2916,6 +3611,7 @@ 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;
wpa_supplicant_notify_scanning(wpa_s, 0);
@@ -2923,17 +3619,44 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
/*
- * If we timed out, start a new sched scan to continue
- * searching for more SSIDs.
+ * Start a new sched scan to continue searching for more SSIDs
+ * either if timed out or PNO schedule scan is pending.
*/
- if (wpa_s->sched_scan_timed_out)
+ if (wpa_s->sched_scan_timed_out) {
wpa_supplicant_req_sched_scan(wpa_s);
+ } else if (wpa_s->pno_sched_pending) {
+ wpa_s->pno_sched_pending = 0;
+ wpas_start_pno(wpa_s);
+ }
+
break;
case EVENT_WPS_BUTTON_PUSHED:
#ifdef CONFIG_WPS
wpas_wps_start_pbc(wpa_s, NULL, 0);
#endif /* CONFIG_WPS */
break;
+ case EVENT_AVOID_FREQUENCIES:
+ wpa_supplicant_notify_avoid_freq(wpa_s, data);
+ break;
+ case EVENT_CONNECT_FAILED_REASON:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface || !data)
+ break;
+ hostapd_event_connect_failed_reason(
+ wpa_s->ap_iface->bss[0],
+ data->connect_failed_reason.addr,
+ data->connect_failed_reason.code);
+#endif /* CONFIG_AP */
+ break;
+ case EVENT_NEW_PEER_CANDIDATE:
+#ifdef CONFIG_MESH
+ if (!wpa_s->ifmsh || !data)
+ break;
+ wpa_mesh_notify_peer(wpa_s, data->mesh_peer.peer,
+ data->mesh_peer.ies,
+ data->mesh_peer.ie_len);
+#endif /* CONFIG_MESH */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p-action.sh b/contrib/wpa/wpa_supplicant/examples/p2p-action.sh
index 8759f54..797d43a 100755
--- a/contrib/wpa/wpa_supplicant/examples/p2p-action.sh
+++ b/contrib/wpa/wpa_supplicant/examples/p2p-action.sh
@@ -34,13 +34,26 @@ if [ "$CMD" = "P2P-GROUP-STARTED" ]; then
# start with -z to avoid that
dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \
-i $GIFNAME \
- -F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z
+ -F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z -p 0
fi
fi
if [ "$4" = "client" ]; then
kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
rm /var/run/dhclient.leases-$GIFNAME
kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+ ipaddr=`echo "$*" | sed 's/.* ip_addr=\([^ ]*\).*/\1/'`
+ ipmask=`echo "$*" | sed 's/.* ip_mask=\([^ ]*\).*/\1/'`
+ goipaddr=`echo "$*" | sed 's/.* go_ip_addr=\([^ ]*\).*/\1/'`
+ if echo "$ipaddr$ipmask$goipaddr" | grep -q ' '; then
+ ipaddr=""
+ ipmask=""
+ goipaddr=""
+ fi
+ if [ -n "$ipaddr" ]; then
+ sudo ifconfig $GIFNAME "$ipaddr" netmask "$ipmask"
+ sudo ip ro re default via "$goipaddr"
+ exit 0
+ fi
dhclient -pf /var/run/dhclient-$GIFNAME.pid \
-lf /var/run/dhclient.leases-$GIFNAME \
-nw \
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py b/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py
new file mode 100755
index 0000000..91eba28
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py
@@ -0,0 +1,654 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for P2P NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import random
+import threading
+import argparse
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+init_on_touch = False
+in_raw_mode = False
+prev_tcgetattr = 0
+include_wps_req = True
+include_p2p_req = True
+no_input = False
+srv = None
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+
+def summary(txt):
+ print txt
+ if summary_file:
+ with open(summary_file, 'a') as f:
+ f.write(txt + "\n")
+
+def success_report(txt):
+ summary(txt)
+ if success_file:
+ with open(success_file, 'a') as f:
+ f.write(txt + "\n")
+
+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, 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:
+ if ifname:
+ if ifname not in ctrl:
+ continue
+ try:
+ print "Trying to use control interface " + ctrl
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception, e:
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return False
+ cmd = "WPS_NFC_TAG_READ " + str(message).encode("hex")
+ global force_freq
+ if force_freq:
+ cmd = cmd + " freq=" + force_freq
+ if "FAIL" in wpas.request(cmd):
+ return False
+ return True
+
+
+def wpas_get_handover_req():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ res = wpas.request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
+ if "FAIL" in res:
+ return None
+ return res.decode("hex")
+
+def wpas_get_handover_req_wps():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ res = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
+ if "FAIL" in res:
+ return None
+ return res.decode("hex")
+
+
+def wpas_get_handover_sel(tag=False):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ if tag:
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
+ else:
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
+ if "FAIL" in res:
+ return None
+ return res.decode("hex")
+
+
+def wpas_get_handover_sel_wps():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR");
+ if "FAIL" in res:
+ return None
+ return res.rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel, type):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ cmd = "NFC_REPORT_HANDOVER " + type + " P2P " + str(req).encode("hex") + " " + str(sel).encode("hex")
+ global force_freq
+ if force_freq:
+ cmd = cmd + " freq=" + force_freq
+ return wpas.request(cmd)
+
+
+def wpas_report_handover_wsc(req, sel, type):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ cmd = "NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex")
+ if force_freq:
+ cmd = cmd + " freq=" + force_freq
+ return wpas.request(cmd)
+
+
+def p2p_handover_client(llc):
+ message = nfc.ndef.HandoverRequestMessage(version="1.2")
+ message.nonce = random.randint(0, 0xffff)
+
+ global include_p2p_req
+ if include_p2p_req:
+ data = wpas_get_handover_req()
+ 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")
+ 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):"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+
+ data = wpas_get_handover_req_wps()
+ if data:
+ print "Add WPS request in addition to P2P"
+ datamsg = nfc.ndef.Message(data)
+ message.add_carrier(datamsg[0], "active", datamsg[1:])
+
+ print "Handover request:"
+ try:
+ print message.pretty()
+ except Exception, e:
+ print e
+ print str(message).encode("hex")
+
+ client = nfc.handover.HandoverClient(llc)
+ try:
+ summary("Trying to initiate NFC connection handover")
+ client.connect()
+ summary("Connected for handover")
+ except nfc.llcp.ConnectRefused:
+ summary("Handover connection refused")
+ client.close()
+ return
+ except Exception, e:
+ summary("Other exception: " + str(e))
+ client.close()
+ return
+
+ summary("Sending handover request")
+
+ if not client.send(message):
+ summary("Failed to send handover request")
+ client.close()
+ return
+
+ summary("Receiving handover response")
+ message = client._recv()
+ if message is None:
+ summary("No response received")
+ client.close()
+ return
+ if message.type != "urn:nfc:wkt:Hs":
+ summary("Response was not Hs - received: " + message.type)
+ client.close()
+ return
+
+ print "Received message"
+ try:
+ print message.pretty()
+ except Exception, 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
+
+ for carrier in message.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.p2p":
+ 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"
+ client.close()
+ print "Done with handover"
+ global only_one
+ if only_one:
+ print "only_one -> stop loop"
+ global continue_loop
+ continue_loop = False
+
+ global no_wait
+ if no_wait:
+ print "Trying to exit.."
+ global terminate_now
+ terminate_now = True
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+
+ # override to avoid parser error in request/response.pretty() in nfcpy
+ # due to new WSC handover format
+ def _process_request(self, request):
+ summary("received handover request {}".format(request.type))
+ response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
+ if not request.type == 'urn:nfc:wkt:Hr':
+ summary("not a handover request")
+ else:
+ try:
+ request = nfc.ndef.HandoverRequestMessage(request)
+ except nfc.ndef.DecodeError as e:
+ summary("error decoding 'Hr' message: {}".format(e))
+ else:
+ response = self.process_request(request)
+ summary("send handover response {}".format(response.type))
+ return response
+
+ def process_request(self, request):
+ self.ho_server_processing = True
+ clear_raw_mode()
+ print "HandoverServer - request received"
+ try:
+ print "Parsed handover request: " + request.pretty()
+ except Exception, e:
+ print e
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ found = False
+
+ for carrier in request.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.p2p":
+ print "P2P carrier type match - add P2P carrier record"
+ found = True
+ self.received_carrier = carrier.record
+ print "Carrier record:"
+ try:
+ print carrier.record.pretty()
+ except Exception, e:
+ print e
+ data = wpas_get_handover_sel()
+ if data is None:
+ print "Could not get handover select carrier record from wpa_supplicant"
+ continue
+ 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)")
+ else:
+ summary("P2P handover report rejected")
+ break
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+ break
+
+ for carrier in request.carriers:
+ if found:
+ break
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WSC carrier type match - add WSC carrier record"
+ found = True
+ self.received_carrier = carrier.record
+ print "Carrier record:"
+ try:
+ print carrier.record.pretty()
+ except Exception, e:
+ print e
+ data = wpas_get_handover_sel_wps()
+ if data is None:
+ print "Could not get handover select carrier record from wpa_supplicant"
+ continue
+ 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")
+ else:
+ summary("WSC handover report rejected")
+ break
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+ found = True
+ break
+
+ print "Handover select:"
+ try:
+ print sel.pretty()
+ except Exception, e:
+ print e
+ print str(sel).encode("hex")
+
+ summary("Sending handover select")
+ self.success = True
+ return sel
+
+
+def clear_raw_mode():
+ import sys, tty, termios
+ global prev_tcgetattr, in_raw_mode
+ if not in_raw_mode:
+ return
+ fd = sys.stdin.fileno()
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+
+
+def getch():
+ import sys, tty, termios, select
+ global prev_tcgetattr, in_raw_mode
+ fd = sys.stdin.fileno()
+ prev_tcgetattr = termios.tcgetattr(fd)
+ ch = None
+ try:
+ tty.setraw(fd)
+ in_raw_mode = True
+ [i, o, e] = select.select([fd], [], [], 0.05)
+ if i:
+ ch = sys.stdin.read(1)
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+ return ch
+
+
+def p2p_tag_read(tag):
+ success = False
+ if len(tag.ndef.message):
+ for record in tag.ndef.message:
+ 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)
+ break
+ if record.type == "application/vnd.wfa.p2p":
+ summary("P2P tag - send to wpa_supplicant")
+ success = wpas_tag_read(tag.ndef.message)
+ break
+ else:
+ summary("Empty tag")
+
+ if success:
+ success_report("Tag read succeeded")
+
+ return success
+
+
+def rdwr_connected_p2p_write(tag):
+ summary("Tag found - writing - " + str(tag))
+ global p2p_sel_data
+ tag.ndef.message = str(p2p_sel_data)
+ success_report("Tag write succeeded")
+ print "Done - remove tag"
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global p2p_sel_wait_remove
+ return p2p_sel_wait_remove
+
+def wps_write_p2p_handover_sel(clf, wait_remove=True):
+ 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")
+ return
+
+ global p2p_sel_wait_remove
+ p2p_sel_wait_remove = wait_remove
+ global p2p_sel_data
+ 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:"
+ try:
+ print p2p_sel_data.pretty()
+ except Exception, e:
+ print e
+ print str(p2p_sel_data).encode("hex")
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
+
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ summary("Tag connected: " + str(tag))
+
+ if tag.ndef:
+ print "NDEF tag: " + tag.type
+ try:
+ print tag.ndef.message.pretty()
+ except Exception, e:
+ print e
+ success = p2p_tag_read(tag)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ summary("Not an NDEF tag - remove tag")
+ return True
+
+ return not no_wait
+
+
+def llcp_worker(llc):
+ global init_on_touch
+ if init_on_touch:
+ print "Starting handover client"
+ p2p_handover_client(llc)
+ return
+
+ global no_input
+ if no_input:
+ 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)"
+ global srv
+ global wait_connection
+ while not wait_connection and srv.sent_carrier is None:
+ if srv.ho_server_processing:
+ time.sleep(0.025)
+ elif no_input:
+ time.sleep(0.5)
+ else:
+ global include_wps_req, include_p2p_req
+ res = getch()
+ if res == 'i':
+ include_wps_req = True
+ include_p2p_req = True
+ elif res == 'p':
+ include_wps_req = False
+ include_p2p_req = True
+ elif res == 'w':
+ include_wps_req = True
+ include_p2p_req = False
+ else:
+ continue
+ clear_raw_mode()
+ print "Starting handover client"
+ p2p_handover_client(llc)
+ return
+
+ clear_raw_mode()
+ print "Exiting llcp_worker thread"
+
+def llcp_startup(clf, llc):
+ print "Start LLCP server"
+ global srv
+ srv = HandoverServer(llc)
+ return llc
+
+def llcp_connected(llc):
+ print "P2P LLCP connected"
+ global wait_connection
+ wait_connection = False
+ global init_on_touch
+ if not init_on_touch:
+ global srv
+ srv.start()
+ if init_on_touch or not no_input:
+ threading.Thread(target=llcp_worker, args=(llc,)).start()
+ return True
+
+def terminate_loop():
+ global terminate_now
+ return terminate_now
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for P2P and WPS NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--init-on-touch', '-I', action='store_true',
+ help='initiate handover on touch')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--ifname', '-i',
+ help='network interface name')
+ parser.add_argument('--no-wps-req', '-N', action='store_true',
+ help='do not include WPS carrier record in request')
+ parser.add_argument('--no-input', '-a', action='store_true',
+ help='do not use stdout input to initiate handover')
+ parser.add_argument('--tag-read-only', '-t', action='store_true',
+ help='tag read only (do not allow connection handover)')
+ parser.add_argument('--handover-only', action='store_true',
+ help='connection handover only (do not allow tag read)')
+ parser.add_argument('--freq', '-f',
+ help='forced frequency of operating channel in MHz')
+ parser.add_argument('--summary',
+ help='summary file for writing status updates')
+ parser.add_argument('--success',
+ help='success file for writing success update')
+ parser.add_argument('command', choices=['write-p2p-sel'],
+ nargs='?')
+ args = parser.parse_args()
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ global force_freq
+ force_freq = args.freq
+
+ logging.basicConfig(level=args.loglevel)
+
+ global init_on_touch
+ init_on_touch = args.init_on_touch
+
+ if args.ifname:
+ global ifname
+ ifname = args.ifname
+ print "Selected ifname " + ifname
+
+ if args.no_wps_req:
+ global include_wps_req
+ include_wps_req = False
+
+ if args.summary:
+ global summary_file
+ summary_file = args.summary
+
+ if args.success:
+ global success_file
+ success_file = args.success
+
+ if args.no_input:
+ global no_input
+ no_input = True
+
+ clf = nfc.ContactlessFrontend()
+ global wait_connection
+
+ try:
+ if not clf.open("usb"):
+ print "Could not open connection with an NFC device"
+ raise SystemExit
+
+ if args.command == "write-p2p-sel":
+ wps_write_p2p_handover_sel(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ print "Waiting for a tag or peer to be touched"
+ wait_connection = True
+ try:
+ if args.tag_read_only:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected}):
+ break
+ elif args.handover_only:
+ if not clf.connect(llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected},
+ terminate=terminate_loop):
+ break
+ else:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected},
+ llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected},
+ terminate=terminate_loop):
+ break
+ except Exception, e:
+ print "clf.connect failed"
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+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 7c6b0aa..cc2cff2 100755
--- a/contrib/wpa/wpa_supplicant/examples/wps-ap-cli
+++ b/contrib/wpa/wpa_supplicant/examples/wps-ap-cli
@@ -14,11 +14,13 @@ pbc()
enter_pin()
{
echo "Enter a PIN from a station to be enrolled to the network."
- read -p "Enrollee PIN: " pin
+ echo -n "Enrollee PIN: "
+ read pin
cpin=`$CLI wps_check_pin "$pin" | tail -1`
if [ "$cpin" = "FAIL-CHECKSUM" ]; then
echo "Checksum digit is not valid"
- read -p "Do you want to use this PIN (y/n)? " resp
+ echo -n "Do you want to use this PIN (y/n)? "
+ read resp
case "$resp" in
y*)
cpin=`echo "$pin" | sed "s/[^1234567890]//g"`
@@ -50,7 +52,8 @@ main_menu()
echo "3: Show current configuration"
echo "0: Exit wps-ap-cli"
- read -p "Command: " cmd
+ echo -n "Command: "
+ read cmd
case "$cmd" in
1)
diff --git a/contrib/wpa/wpa_supplicant/examples/wps-nfc.py b/contrib/wpa/wpa_supplicant/examples/wps-nfc.py
index 0cfc1f6..7459eb9 100755
--- a/contrib/wpa/wpa_supplicant/examples/wps-nfc.py
+++ b/contrib/wpa/wpa_supplicant/examples/wps-nfc.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
#
# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
-# Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
@@ -9,15 +9,37 @@
import os
import sys
import time
+import random
+import threading
+import argparse
import nfc
import nfc.ndef
import nfc.llcp
import nfc.handover
-import wpactrl
+import logging
+
+import wpaspy
wpas_ctrl = '/var/run/wpa_supplicant'
+srv = None
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+
+def summary(txt):
+ print txt
+ if summary_file:
+ with open(summary_file, 'a') as f:
+ f.write(txt + "\n")
+
+def success_report(txt):
+ summary(txt)
+ if success_file:
+ with open(success_file, 'a') as f:
+ f.write(txt + "\n")
def wpas_connect():
ifaces = []
@@ -34,10 +56,9 @@ def wpas_connect():
for ctrl in ifaces:
try:
- wpas = wpactrl.WPACtrl(ctrl)
+ wpas = wpaspy.Ctrl(ctrl)
return wpas
- except wpactrl.error, error:
- print "Error: ", error
+ except Exception, e:
pass
return None
@@ -45,111 +66,453 @@ def wpas_connect():
def wpas_tag_read(message):
wpas = wpas_connect()
if (wpas == None):
- return
- print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+ return False
+ if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
+ return False
+ return True
+
+def wpas_get_config_token(id=None):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ if id:
+ ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id)
+ else:
+ ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
+
+
+def wpas_get_er_config_token(uuid):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ ret = wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid)
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ ret = wpas.request("WPS_NFC_TOKEN NDEF")
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
def wpas_get_handover_req():
wpas = wpas_connect()
if (wpas == None):
return None
- return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
+ ret = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR")
+ if "FAIL" in ret:
+ return None
+ return ret.rstrip().decode("hex")
-def wpas_put_handover_sel(message):
+def wpas_get_handover_sel(uuid):
wpas = wpas_connect()
if (wpas == None):
- return
- print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
+ return None
+ if uuid is None:
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
+ else:
+ res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip()
+ if "FAIL" in res:
+ return None
+ return res.decode("hex")
-def wps_handover_init(peer):
- print "Trying to initiate WPS handover"
+def wpas_report_handover(req, sel, type):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+
+ # override to avoid parser error in request/response.pretty() in nfcpy
+ # due to new WSC handover format
+ def _process_request(self, request):
+ summary("received handover request {}".format(request.type))
+ response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
+ if not request.type == 'urn:nfc:wkt:Hr':
+ summary("not a handover request")
+ else:
+ try:
+ request = nfc.ndef.HandoverRequestMessage(request)
+ except nfc.ndef.DecodeError as e:
+ summary("error decoding 'Hr' message: {}".format(e))
+ else:
+ response = self.process_request(request)
+ summary("send handover response {}".format(response.type))
+ return response
+
+ def process_request(self, request):
+ self.ho_server_processing = True
+ summary("HandoverServer - request received")
+ try:
+ print "Parsed handover request: " + request.pretty()
+ except Exception, e:
+ print e
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ for carrier in request.carriers:
+ 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")
+ self.sent_carrier = data
+ if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"):
+ success_report("Handover reported successfully (responder)")
+ else:
+ summary("Handover report rejected (responder)")
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+
+ print "Handover select:"
+ try:
+ print sel.pretty()
+ except Exception, e:
+ print e
+ print str(sel).encode("hex")
+
+ summary("Sending handover select")
+ self.success = True
+ return sel
+
+
+def wps_handover_init(llc):
+ summary("Trying to initiate WPS handover")
data = wpas_get_handover_req()
if (data == None):
- print "Could not get handover request message from wpa_supplicant"
+ summary("Could not get handover request carrier record from wpa_supplicant")
return
- print "Handover request from wpa_supplicant: " + data.encode("hex")
- message = nfc.ndef.Message(data)
- print "Parsed handover request: " + message.pretty()
+ print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
- nfc.llcp.activate(peer);
- time.sleep(0.5)
+ 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:])
- client = nfc.handover.HandoverClient()
+ print "Handover request:"
try:
- print "Trying handover";
+ print message.pretty()
+ except Exception, e:
+ print e
+ print str(message).encode("hex")
+
+ client = nfc.handover.HandoverClient(llc)
+ try:
+ summary("Trying to initiate NFC connection handover")
client.connect()
- print "Connected for handover"
+ summary("Connected for handover")
except nfc.llcp.ConnectRefused:
- print "Handover connection refused"
- nfc.llcp.shutdown()
+ summary("Handover connection refused")
+ client.close()
+ return
+ except Exception, e:
+ summary("Other exception: " + str(e))
client.close()
return
- print "Sending handover request"
+ summary("Sending handover request")
if not client.send(message):
- print "Failed to send handover request"
+ summary("Failed to send handover request")
+ client.close()
+ return
- print "Receiving handover response"
+ summary("Receiving handover response")
message = client._recv()
- print "Handover select received"
- print message.pretty()
- wpas_put_handover_sel(message)
+ if message is None:
+ summary("No response received")
+ client.close()
+ return
+ if message.type != "urn:nfc:wkt:Hs":
+ summary("Response was not Hs - received: " + message.type)
+ client.close()
+ return
+
+ print "Received message"
+ try:
+ print message.pretty()
+ except Exception, 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
+
+ for carrier in message.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ 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:
+ summary("Handover report rejected (initiator)")
+ # nfcpy does not support the new format..
+ #wifi = nfc.ndef.WifiConfigRecord(carrier.record)
+ #print wifi.pretty()
print "Remove peer"
- nfc.llcp.shutdown()
client.close()
print "Done with handover"
-
-
-def wps_tag_read(tag):
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+
+ global no_wait
+ if no_wait:
+ print "Trying to exit.."
+ global terminate_now
+ terminate_now = True
+
+def wps_tag_read(tag, wait_remove=True):
+ success = False
if len(tag.ndef.message):
- message = nfc.ndef.Message(tag.ndef.message)
- print "message type " + message.type
-
- for record in message:
+ for record in tag.ndef.message:
print "record type " + record.type
if record.type == "application/vnd.wfa.wsc":
- print "WPS tag - send to wpa_supplicant"
- wpas_tag_read(tag.ndef.message)
+ summary("WPS tag - send to wpa_supplicant")
+ success = wpas_tag_read(tag.ndef.message)
break
else:
- print "Empty tag"
-
- print "Remove tag"
- while tag.is_present:
+ summary("Empty tag")
+
+ if success:
+ success_report("Tag read succeeded")
+
+ if wait_remove:
+ print "Remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+ return success
+
+
+def rdwr_connected_write(tag):
+ summary("Tag found - writing - " + str(tag))
+ global write_data
+ tag.ndef.message = str(write_data)
+ success_report("Tag write succeeded")
+ print "Done - remove tag"
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global write_wait_remove
+ while write_wait_remove and tag.is_present:
time.sleep(0.1)
+def wps_write_config_tag(clf, id=None, wait_remove=True):
+ 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"
+ sys.exit(1)
+ return
+ 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"
+ 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"
+ return
+
+ 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"
+ 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"
+ return
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ summary("Tag connected: " + str(tag))
+
+ if tag.ndef:
+ print "NDEF tag: " + tag.type
+ try:
+ print tag.ndef.message.pretty()
+ except Exception, e:
+ print e
+ success = wps_tag_read(tag, not only_one)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ summary("Not an NDEF tag - remove tag")
+ return True
+
+ return not no_wait
+
+
+def llcp_worker(llc):
+ global arg_uuid
+ if arg_uuid is None:
+ wps_handover_init(llc)
+ print "Exiting llcp_worker thread"
+ return
+
+ global srv
+ global wait_connection
+ while not wait_connection and srv.sent_carrier is None:
+ if srv.ho_server_processing:
+ time.sleep(0.025)
+
+def llcp_startup(clf, llc):
+ global arg_uuid
+ if arg_uuid:
+ print "Start LLCP server"
+ global srv
+ srv = HandoverServer(llc)
+ if arg_uuid is "ap":
+ print "Trying to handle WPS handover"
+ srv.uuid = None
+ else:
+ print "Trying to handle WPS handover with AP " + arg_uuid
+ srv.uuid = arg_uuid
+ return llc
+
+def llcp_connected(llc):
+ print "P2P LLCP connected"
+ global wait_connection
+ wait_connection = False
+ global arg_uuid
+ if arg_uuid:
+ global srv
+ srv.start()
+ else:
+ threading.Thread(target=llcp_worker, args=(llc,)).start()
+ print "llcp_connected returning"
+ return True
+
+
+def terminate_loop():
+ global terminate_now
+ return terminate_now
def main():
clf = nfc.ContactlessFrontend()
+ parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for WPS NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--uuid',
+ help='UUID of an AP (used for WPS ER operations)')
+ parser.add_argument('--id',
+ help='network id (used for WPS ER operations)')
+ parser.add_argument('--summary',
+ help='summary file for writing status updates')
+ parser.add_argument('--success',
+ help='success file for writing success update')
+ parser.add_argument('command', choices=['write-config',
+ 'write-er-config',
+ 'write-password'],
+ nargs='?')
+ args = parser.parse_args()
+
+ global arg_uuid
+ arg_uuid = args.uuid
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ if args.summary:
+ global summary_file
+ summary_file = args.summary
+
+ if args.success:
+ global success_file
+ success_file = args.success
+
+ logging.basicConfig(level=args.loglevel)
+
try:
- while True:
- print "Waiting for a tag or peer to be touched"
+ if not clf.open("usb"):
+ print "Could not open connection with an NFC device"
+ raise SystemExit
- while True:
- general_bytes = nfc.llcp.startup({})
- tag = clf.poll(general_bytes)
- if tag == None:
- continue
+ if args.command == "write-config":
+ wps_write_config_tag(clf, id=args.id, wait_remove=not args.no_wait)
+ raise SystemExit
- if isinstance(tag, nfc.DEP):
- wps_handover_init(tag)
- break
+ if args.command == "write-er-config":
+ wps_write_er_config_tag(clf, args.uuid, wait_remove=not args.no_wait)
+ raise SystemExit
- if tag.ndef:
- wps_tag_read(tag)
- break
+ if args.command == "write-password":
+ wps_write_password_tag(clf, wait_remove=not args.no_wait)
+ raise SystemExit
- if tag:
- print "Not an NDEF tag - remove tag"
- while tag.is_present:
- time.sleep(0.1)
+ global continue_loop
+ while continue_loop:
+ 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},
+ terminate=terminate_loop):
break
+ except Exception, e:
+ print "clf.connect failed"
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
except KeyboardInterrupt:
raise SystemExit
diff --git a/contrib/wpa/wpa_supplicant/gas_query.c b/contrib/wpa/wpa_supplicant/gas_query.c
index 27bcc7a..10ecce7 100644
--- a/contrib/wpa/wpa_supplicant/gas_query.c
+++ b/contrib/wpa/wpa_supplicant/gas_query.c
@@ -1,7 +1,8 @@
/*
* Generic advertisement service (GAS) query
* Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2014, 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.
@@ -13,6 +14,8 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "offchannel.h"
@@ -20,7 +23,7 @@
/** GAS query timeout in seconds */
-#define GAS_QUERY_TIMEOUT_PERIOD 5
+#define GAS_QUERY_TIMEOUT_PERIOD 2
/**
@@ -28,6 +31,7 @@
*/
struct gas_query_pending {
struct dl_list list;
+ struct gas_query *gas;
u8 addr[ETH_ALEN];
u8 dialog_token;
u8 next_frag_id;
@@ -35,8 +39,10 @@ struct gas_query_pending {
unsigned int offchannel_tx_started: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_result result,
const struct wpabuf *adv_proto,
@@ -50,6 +56,8 @@ struct gas_query_pending {
struct gas_query {
struct wpa_supplicant *wpa_s;
struct dl_list pending; /* struct gas_query_pending */
+ struct gas_query_pending *current;
+ struct wpa_radio_work *work;
};
@@ -57,6 +65,16 @@ 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 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_init - Initialize GAS query component
* @wpa_s: Pointer to wpa_supplicant data
@@ -77,10 +95,58 @@ struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
}
+static const char * gas_result_txt(enum gas_query_result result)
+{
+ switch (result) {
+ case GAS_QUERY_SUCCESS:
+ return "SUCCESS";
+ case GAS_QUERY_FAILURE:
+ return "FAILURE";
+ case GAS_QUERY_TIMEOUT:
+ return "TIMEOUT";
+ case GAS_QUERY_PEER_ERROR:
+ return "PEER_ERROR";
+ case GAS_QUERY_INTERNAL_ERROR:
+ return "INTERNAL_ERROR";
+ case GAS_QUERY_CANCELLED:
+ return "CANCELLED";
+ case GAS_QUERY_DELETED_AT_DEINIT:
+ return "DELETED_AT_DEINIT";
+ }
+
+ return "N/A";
+}
+
+
+static void gas_query_free(struct gas_query_pending *query, int del_list)
+{
+ struct gas_query *gas = query->gas;
+
+ if (del_list)
+ dl_list_del(&query->list);
+
+ if (gas->work && gas->work->ctx == query) {
+ radio_work_done(gas->work);
+ gas->work = NULL;
+ }
+
+ wpabuf_free(query->req);
+ wpabuf_free(query->adv_proto);
+ wpabuf_free(query->resp);
+ os_free(query);
+}
+
+
static void gas_query_done(struct gas_query *gas,
struct gas_query_pending *query,
enum gas_query_result result)
{
+ wpa_msg(gas->wpa_s, 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;
if (query->offchannel_tx_started)
offchannel_send_action_done(gas->wpa_s);
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
@@ -88,9 +154,7 @@ static void gas_query_done(struct gas_query *gas,
dl_list_del(&query->list);
query->cb(query->ctx, query->addr, query->dialog_token, result,
query->adv_proto, query->resp, query->status_code);
- wpabuf_free(query->adv_proto);
- wpabuf_free(query->resp);
- os_free(query);
+ gas_query_free(query, 0);
}
@@ -138,17 +202,79 @@ static int gas_query_append(struct gas_query_pending *query, const u8 *data,
}
+static void gas_query_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)
+{
+ struct gas_query_pending *query;
+ struct gas_query *gas = wpa_s->gas;
+ int dur;
+
+ if (gas->current == NULL) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst="
+ MACSTR " result=%d - no query in progress",
+ freq, MAC2STR(dst), result);
+ return;
+ }
+
+ query = gas->current;
+
+ dur = ms_from_time(&query->last_oper);
+ wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+ " result=%d query=%p dialog_token=%u dur=%d ms",
+ freq, MAC2STR(dst), result, 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);
+
+ if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+ 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_FAILED) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_register_timeout(0, 0, gas_query_timeout, gas, query);
+ }
+}
+
+
+static 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 ||
+ os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0)
+ return 0;
+ return wpa_sm_pmf_enabled(wpa_s->wpa);
+}
+
+
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
struct wpabuf *req)
{
- int res;
+ unsigned int wait_time;
+ int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
- "freq=%d", MAC2STR(query->addr),
- (unsigned int) wpabuf_len(req), query->freq);
+ "freq=%d prot=%d", MAC2STR(query->addr),
+ (unsigned int) wpabuf_len(req), query->freq, prot);
+ 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;
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
gas->wpa_s->own_addr, query->addr,
- wpabuf_head(req), wpabuf_len(req), 1000,
- NULL, 0);
+ wpabuf_head(req), wpabuf_len(req),
+ wait_time, gas_query_tx_status, 0);
if (res == 0)
query->offchannel_tx_started = 1;
return res;
@@ -271,6 +397,11 @@ static void gas_query_rx_comeback(struct gas_query *gas,
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_PEER_ERROR);
return;
}
@@ -291,27 +422,42 @@ static void gas_query_rx_comeback(struct gas_query *gas,
/**
- * gas_query_rx - Indicate reception of a Public Action frame
+ * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
* @gas: GAS query data from gas_query_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 frame or -1 if not
*/
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
- const u8 *bssid, const u8 *data, size_t len, int freq)
+ const u8 *bssid, 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 == NULL || len < 4)
return -1;
+ prot = categ == WLAN_ACTION_PROTECTED_DUAL;
+ pmf = pmf_in_use(gas->wpa_s, bssid);
+ 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;
+ }
+
pos = data;
action = *pos++;
dialog_token = *pos++;
@@ -327,6 +473,9 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
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 "
@@ -344,7 +493,10 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
query->status_code = WPA_GET_LE16(pos);
pos += 2;
- if (query->status_code != WLAN_STATUS_SUCCESS) {
+ 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);
@@ -392,17 +544,17 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
resp_len = WPA_GET_LE16(pos);
pos += 2;
- if (pos + resp_len > data + len) {
+ 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 (pos + resp_len < data + len) {
+ if (resp_len < left) {
wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
"after Query Response from " MACSTR,
- (unsigned int) (data + len - pos - resp_len),
- MAC2STR(sa));
+ left - resp_len, MAC2STR(sa));
}
if (action == WLAN_PA_GAS_COMEBACK_RESP)
@@ -421,8 +573,9 @@ static void gas_query_timeout(void *eloop_data, void *user_ctx)
struct gas_query *gas = eloop_data;
struct gas_query_pending *query = user_ctx;
- wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
- MAC2STR(query->addr));
+ 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_TIMEOUT);
}
@@ -441,12 +594,56 @@ static int gas_query_dialog_token_available(struct gas_query *gas,
}
+static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct gas_query_pending *query = work->ctx;
+ struct gas_query *gas = query->gas;
+ struct wpa_supplicant *wpa_s = gas->wpa_s;
+
+ if (deinit) {
+ if (work->started) {
+ gas->work = NULL;
+ gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
+ return;
+ }
+
+ gas_query_free(query, 1);
+ return;
+ }
+
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for GAS");
+ gas_query_free(query, 1);
+ radio_work_done(work);
+ return;
+ }
+
+ gas->work = work;
+
+ if (gas_query_tx(gas, query, query->req) < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+ MACSTR, MAC2STR(query->addr));
+ gas_query_free(query, 1);
+ 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);
+
+}
+
+
/**
* gas_query_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
+ * @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
@@ -461,43 +658,46 @@ 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, 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;
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_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
- " dialog_token %u", MAC2STR(dst), dialog_token);
- if (gas_query_tx(gas, query, req) < 0) {
- wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
- MACSTR, MAC2STR(query->addr));
- dl_list_del(&query->list);
- os_free(query);
+ wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR
+ " dialog_token=%u freq=%d",
+ MAC2STR(query->addr), query->dialog_token, query->freq);
+
+ if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
+ query) < 0) {
+ gas_query_free(query, 1);
return -1;
}
- eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
- gas, query);
-
return dialog_token;
}
diff --git a/contrib/wpa/wpa_supplicant/gas_query.h b/contrib/wpa/wpa_supplicant/gas_query.h
index 5c3d161..ad13490 100644
--- a/contrib/wpa/wpa_supplicant/gas_query.h
+++ b/contrib/wpa/wpa_supplicant/gas_query.h
@@ -17,7 +17,8 @@ struct gas_query;
struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s);
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, const u8 *data, size_t len, int freq);
+ const u8 *bssid, u8 categ, const u8 *data, size_t len,
+ int freq);
/**
* enum gas_query_result - GAS query result
diff --git a/contrib/wpa/wpa_supplicant/hs20_supplicant.c b/contrib/wpa/wpa_supplicant/hs20_supplicant.c
index 1404241..b9cd681 100644
--- a/contrib/wpa/wpa_supplicant/hs20_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/hs20_supplicant.c
@@ -1,12 +1,13 @@
/*
* Copyright (c) 2009, Atheros Communications, Inc.
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
+#include <sys/stat.h>
#include "common.h"
#include "eloop.h"
@@ -14,34 +15,126 @@
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
#include "common/wpa_ctrl.h"
+#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "config.h"
+#include "scan.h"
#include "bss.h"
+#include "blacklist.h"
#include "gas_query.h"
#include "interworking.h"
#include "hs20_supplicant.h"
-void wpas_hs20_add_indication(struct wpabuf *buf)
+#define OSU_MAX_ITEMS 10
+
+struct osu_lang_string {
+ char lang[4];
+ char text[253];
+};
+
+struct osu_icon {
+ u16 width;
+ u16 height;
+ char lang[4];
+ char icon_type[256];
+ char filename[256];
+ unsigned int id;
+ unsigned int failed:1;
+};
+
+struct osu_provider {
+ u8 bssid[ETH_ALEN];
+ u8 osu_ssid[32];
+ u8 osu_ssid_len;
+ char server_uri[256];
+ u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
+ char osu_nai[256];
+ struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
+ size_t friendly_name_count;
+ struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
+ size_t serv_desc_count;
+ struct osu_icon icon[OSU_MAX_ITEMS];
+ size_t icon_count;
+};
+
+
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
{
+ u8 conf;
+
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
- wpabuf_put_u8(buf, 5);
+ wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
- wpabuf_put_u8(buf, 0x00); /* Hotspot Configuration */
+ conf = HS20_VERSION;
+ if (pps_mo_id >= 0)
+ conf |= HS20_PPS_MO_ID_PRESENT;
+ wpabuf_put_u8(buf, conf);
+ if (pps_mo_id >= 0)
+ wpabuf_put_le16(buf, pps_mo_id);
}
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len)
+int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss)
+{
+ if (!wpa_s->conf->hs20 || !ssid)
+ return 0;
+
+ if (ssid->parent_cred)
+ return 1;
+
+ if (bss && !wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE))
+ return 0;
+
+ /*
+ * This may catch some non-Hotspot 2.0 cases, but it is safer to do that
+ * than cause Hotspot 2.0 connections without indication element getting
+ * added. Non-Hotspot 2.0 APs should ignore the unknown vendor element.
+ */
+
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X))
+ return 0;
+ if (!(ssid->pairwise_cipher & WPA_CIPHER_CCMP))
+ return 0;
+ if (ssid->proto != WPA_PROTO_RSN)
+ return 0;
+
+ return 1;
+}
+
+
+int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ struct wpa_cred *cred;
+
+ if (ssid == NULL)
+ return 0;
+
+ if (ssid->update_identifier)
+ return ssid->update_identifier;
+
+ if (ssid->parent_cred == NULL)
+ return 0;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (ssid->parent_cred == cred)
+ return cred->update_identifier;
+ }
+
+ return 0;
+}
+
+
+void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
+ struct wpabuf *buf)
{
- struct wpabuf *buf;
u8 *len_pos;
- buf = gas_anqp_build_initial_req(0, 100 + payload_len);
if (buf == NULL)
- return NULL;
+ return;
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
wpabuf_put_be24(buf, OUI_WFA);
@@ -51,6 +144,11 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
wpabuf_put_u8(buf, 0); /* Reserved */
if (payload)
wpabuf_put_data(buf, payload, payload_len);
+ } else if (stypes == BIT(HS20_STYPE_ICON_REQUEST)) {
+ wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ if (payload)
+ wpabuf_put_data(buf, payload, payload_len);
} else {
u8 i;
wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
@@ -63,6 +161,19 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
gas_anqp_set_element_len(buf, len_pos);
gas_anqp_set_len(buf);
+}
+
+
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len)
+{
+ struct wpabuf *buf;
+
+ buf = gas_anqp_build_initial_req(0, 100 + payload_len);
+ if (buf == NULL)
+ return NULL;
+
+ hs20_put_anqp_req(stypes, payload, payload_len, buf);
return buf;
}
@@ -96,23 +207,161 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
- wpabuf_free(buf);
return ret;
}
+static void hs20_set_osu_access_permission(const char *osu_dir,
+ const char *fname)
+{
+ struct stat statbuf;
+
+ /* Get OSU directory information */
+ if (stat(osu_dir, &statbuf) < 0) {
+ wpa_printf(MSG_WARNING, "Cannot stat the OSU directory %s",
+ osu_dir);
+ return;
+ }
+
+ if (chmod(fname, statbuf.st_mode) < 0) {
+ wpa_printf(MSG_WARNING,
+ "Cannot change the permissions for %s", fname);
+ return;
+ }
+
+ if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+ wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
+ fname);
+ }
+}
+
+static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *pos,
+ size_t slen)
+{
+ char fname[256];
+ int png;
+ FILE *f;
+ u16 data_len;
+
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
+ MAC2STR(sa));
+
+ if (slen < 4) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
+ "value from " MACSTR, MAC2STR(sa));
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos);
+ if (*pos != 0)
+ return -1;
+ pos++;
+ slen--;
+
+ if ((size_t) 1 + pos[0] > slen) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
+ "value from " MACSTR, MAC2STR(sa));
+ return -1;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]);
+ png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0;
+ slen -= 1 + pos[0];
+ pos += 1 + pos[0];
+
+ if (slen < 2) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
+ "value from " MACSTR, MAC2STR(sa));
+ return -1;
+ }
+ data_len = WPA_GET_LE16(pos);
+ pos += 2;
+ slen -= 2;
+
+ if (data_len > slen) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
+ "value from " MACSTR, MAC2STR(sa));
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len);
+ if (wpa_s->conf->osu_dir == NULL)
+ return -1;
+
+ wpa_s->osu_icon_id++;
+ if (wpa_s->osu_icon_id == 0)
+ wpa_s->osu_icon_id++;
+ snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s",
+ wpa_s->conf->osu_dir, wpa_s->osu_icon_id,
+ png ? "png" : "icon");
+ f = fopen(fname, "wb");
+ if (f == NULL)
+ return -1;
+
+ hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
+ if (fwrite(pos, slen, 1, f) != 1) {
+ fclose(f);
+ unlink(fname);
+ return -1;
+ }
+ fclose(f);
+
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
+ return 0;
+}
+
+
+static void hs20_continue_icon_fetch(void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ if (wpa_s->fetch_osu_icon_in_progress)
+ hs20_next_osu_icon(wpa_s);
+}
+
+
+static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
+{
+ size_t i, j;
+ struct os_reltime now, tmp;
+ int dur;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->osu_icon_fetch_start, &tmp);
+ dur = tmp.sec * 1000 + tmp.usec / 1000;
+ wpa_printf(MSG_DEBUG, "HS 2.0: Icon fetch dur=%d ms res=%d",
+ dur, res);
+
+ for (i = 0; i < wpa_s->osu_prov_count; i++) {
+ struct osu_provider *osu = &wpa_s->osu_prov[i];
+ for (j = 0; j < osu->icon_count; j++) {
+ struct osu_icon *icon = &osu->icon[j];
+ if (icon->id || icon->failed)
+ continue;
+ if (res < 0)
+ icon->failed = 1;
+ else
+ icon->id = wpa_s->osu_icon_id;
+ return;
+ }
+ }
+}
+
+
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, const u8 *data, size_t slen)
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen)
{
const u8 *pos = data;
u8 subtype;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
+ int ret;
if (slen < 2)
return;
@@ -131,6 +380,11 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
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) {
+ wpabuf_free(anqp->hs20_capability_list);
+ anqp->hs20_capability_list =
+ wpabuf_alloc_copy(pos, slen);
+ }
break;
case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
@@ -178,8 +432,576 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpabuf_alloc_copy(pos, slen);
}
break;
+ case HS20_STYPE_OSU_PROVIDERS_LIST:
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ " OSU Providers list", MAC2STR(sa));
+ wpa_s->num_prov_found++;
+ if (anqp) {
+ wpabuf_free(anqp->hs20_osu_providers_list);
+ anqp->hs20_osu_providers_list =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_ICON_BINARY_FILE:
+ ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen);
+ if (wpa_s->fetch_osu_icon_in_progress) {
+ hs20_osu_icon_fetch_result(wpa_s, ret);
+ eloop_cancel_timeout(hs20_continue_icon_fetch,
+ wpa_s, NULL);
+ eloop_register_timeout(0, 0, hs20_continue_icon_fetch,
+ wpa_s, NULL);
+ }
+ break;
default:
wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
break;
}
}
+
+
+void hs20_notify_parse_done(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->fetch_osu_icon_in_progress)
+ return;
+ if (eloop_is_timeout_registered(hs20_continue_icon_fetch, wpa_s, NULL))
+ return;
+ /*
+ * We are going through icon fetch, but no icon response was received.
+ * Assume this means the current AP could not provide an answer to avoid
+ * getting stuck in fetch iteration.
+ */
+ hs20_icon_fetch_failed(wpa_s);
+}
+
+
+static void hs20_free_osu_prov_entry(struct osu_provider *prov)
+{
+}
+
+
+void hs20_free_osu_prov(struct wpa_supplicant *wpa_s)
+{
+ size_t i;
+ for (i = 0; i < wpa_s->osu_prov_count; i++)
+ hs20_free_osu_prov_entry(&wpa_s->osu_prov[i]);
+ os_free(wpa_s->osu_prov);
+ wpa_s->osu_prov = NULL;
+ wpa_s->osu_prov_count = 0;
+}
+
+
+static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
+{
+ char fname[256];
+ FILE *f;
+ size_t i, j;
+
+ wpa_s->fetch_osu_info = 0;
+ wpa_s->fetch_osu_icon_in_progress = 0;
+
+ if (wpa_s->conf->osu_dir == NULL) {
+ hs20_free_osu_prov(wpa_s);
+ wpa_s->fetch_anqp_in_progress = 0;
+ return;
+ }
+
+ snprintf(fname, sizeof(fname), "%s/osu-providers.txt",
+ wpa_s->conf->osu_dir);
+ f = fopen(fname, "w");
+ if (f == NULL) {
+ hs20_free_osu_prov(wpa_s);
+ return;
+ }
+
+ hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
+ for (i = 0; i < wpa_s->osu_prov_count; i++) {
+ struct osu_provider *osu = &wpa_s->osu_prov[i];
+ if (i > 0)
+ fprintf(f, "\n");
+ fprintf(f, "OSU-PROVIDER " MACSTR "\n"
+ "uri=%s\n"
+ "methods=%08x\n",
+ MAC2STR(osu->bssid), osu->server_uri, osu->osu_methods);
+ if (osu->osu_ssid_len) {
+ fprintf(f, "osu_ssid=%s\n",
+ wpa_ssid_txt(osu->osu_ssid,
+ osu->osu_ssid_len));
+ }
+ if (osu->osu_nai[0])
+ fprintf(f, "osu_nai=%s\n", osu->osu_nai);
+ for (j = 0; j < osu->friendly_name_count; j++) {
+ fprintf(f, "friendly_name=%s:%s\n",
+ osu->friendly_name[j].lang,
+ osu->friendly_name[j].text);
+ }
+ for (j = 0; j < osu->serv_desc_count; j++) {
+ fprintf(f, "desc=%s:%s\n",
+ osu->serv_desc[j].lang,
+ osu->serv_desc[j].text);
+ }
+ for (j = 0; j < osu->icon_count; j++) {
+ struct osu_icon *icon = &osu->icon[j];
+ if (icon->failed)
+ continue; /* could not fetch icon */
+ fprintf(f, "icon=%u:%u:%u:%s:%s:%s\n",
+ icon->id, icon->width, icon->height, icon->lang,
+ icon->icon_type, icon->filename);
+ }
+ }
+ fclose(f);
+ hs20_free_osu_prov(wpa_s);
+
+ wpa_msg(wpa_s, MSG_INFO, "OSU provider fetch completed");
+ wpa_s->fetch_anqp_in_progress = 0;
+}
+
+
+void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
+{
+ size_t i, j;
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: Ready to fetch next icon");
+
+ for (i = 0; i < wpa_s->osu_prov_count; i++) {
+ struct osu_provider *osu = &wpa_s->osu_prov[i];
+ for (j = 0; j < osu->icon_count; j++) {
+ struct osu_icon *icon = &osu->icon[j];
+ if (icon->id || icon->failed)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: Try to fetch icon '%s' "
+ "from " MACSTR, icon->filename,
+ MAC2STR(osu->bssid));
+ os_get_reltime(&wpa_s->osu_icon_fetch_start);
+ if (hs20_anqp_send_req(wpa_s, osu->bssid,
+ BIT(HS20_STYPE_ICON_REQUEST),
+ (u8 *) icon->filename,
+ os_strlen(icon->filename)) < 0) {
+ icon->failed = 1;
+ continue;
+ }
+ return;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: No more icons to fetch");
+ hs20_osu_fetch_done(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 *pos, size_t len)
+{
+ struct osu_provider *prov;
+ const u8 *end = pos + len;
+ u16 len2;
+ const u8 *pos2;
+ u8 uri_len, osu_method_len, osu_nai_len;
+
+ wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len);
+ prov = os_realloc_array(wpa_s->osu_prov,
+ wpa_s->osu_prov_count + 1,
+ sizeof(*prov));
+ if (prov == NULL)
+ return;
+ wpa_s->osu_prov = prov;
+ prov = &prov[wpa_s->osu_prov_count];
+ os_memset(prov, 0, sizeof(*prov));
+
+ 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;
+
+ /* OSU Friendly Name Length */
+ if (pos + 2 > end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
+ "Friendly Name Length");
+ return;
+ }
+ len2 = WPA_GET_LE16(pos);
+ pos += 2;
+ if (len2 > end - pos) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
+ "Friendly Name Duples");
+ return;
+ }
+ pos2 = pos;
+ pos += len2;
+
+ /* OSU Friendly Name Duples */
+ while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) {
+ struct osu_lang_string *f;
+ if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
+ wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
+ break;
+ }
+ f = &prov->friendly_name[prov->friendly_name_count++];
+ os_memcpy(f->lang, pos2 + 1, 3);
+ os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
+ pos2 += 1 + pos2[0];
+ }
+
+ /* OSU Server URI */
+ if (pos + 1 > end) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Not enough room for OSU Server URI length");
+ return;
+ }
+ uri_len = *pos++;
+ if (uri_len > end - pos) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server "
+ "URI");
+ return;
+ }
+ os_memcpy(prov->server_uri, pos, uri_len);
+ pos += uri_len;
+
+ /* OSU Method list */
+ if (pos + 1 > end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
+ "list length");
+ return;
+ }
+ osu_method_len = pos[0];
+ if (osu_method_len > end - pos - 1) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
+ "list");
+ return;
+ }
+ pos2 = pos + 1;
+ pos += 1 + osu_method_len;
+ while (pos2 < pos) {
+ if (*pos2 < 32)
+ prov->osu_methods |= BIT(*pos2);
+ pos2++;
+ }
+
+ /* Icons Available Length */
+ if (pos + 2 > end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
+ "Available Length");
+ return;
+ }
+ len2 = WPA_GET_LE16(pos);
+ pos += 2;
+ if (len2 > end - pos) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
+ "Available");
+ return;
+ }
+ pos2 = pos;
+ pos += len2;
+
+ /* Icons Available */
+ while (pos2 < pos) {
+ struct osu_icon *icon = &prov->icon[prov->icon_count];
+ u8 flen;
+
+ if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
+ break;
+ }
+
+ icon->width = WPA_GET_LE16(pos2);
+ pos2 += 2;
+ icon->height = WPA_GET_LE16(pos2);
+ pos2 += 2;
+ os_memcpy(icon->lang, pos2, 3);
+ pos2 += 3;
+
+ flen = pos2[0];
+ if (flen > pos - pos2 - 1) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
+ break;
+ }
+ os_memcpy(icon->icon_type, pos2 + 1, flen);
+ pos2 += 1 + flen;
+
+ if (pos2 + 1 > pos) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
+ "Filename length");
+ break;
+ }
+ flen = pos2[0];
+ if (flen > pos - pos2 - 1) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
+ "Filename");
+ break;
+ }
+ os_memcpy(icon->filename, pos2 + 1, flen);
+ pos2 += 1 + flen;
+
+ prov->icon_count++;
+ }
+
+ /* OSU_NAI */
+ if (pos + 1 > end) {
+ 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) {
+ 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;
+
+ /* OSU Service Description Length */
+ if (pos + 2 > end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
+ "Service Description Length");
+ return;
+ }
+ len2 = WPA_GET_LE16(pos);
+ pos += 2;
+ if (len2 > end - pos) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
+ "Service Description Duples");
+ return;
+ }
+ pos2 = pos;
+ pos += len2;
+
+ /* OSU Service Description Duples */
+ while (pos2 + 4 <= pos && 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) {
+ 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;
+ }
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
+ MAC2STR(bss->bssid));
+ wpa_s->osu_prov_count++;
+}
+
+
+void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss;
+ struct wpabuf *prov_anqp;
+ const u8 *pos, *end;
+ u16 len;
+ const u8 *osu_ssid;
+ u8 osu_ssid_len;
+ u8 num_providers;
+
+ hs20_free_osu_prov(wpa_s);
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (bss->anqp == NULL)
+ continue;
+ prov_anqp = bss->anqp->hs20_osu_providers_list;
+ if (prov_anqp == NULL)
+ continue;
+ 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",
+ prov_anqp);
+ pos = wpabuf_head(prov_anqp);
+ end = pos + wpabuf_len(prov_anqp);
+
+ /* OSU SSID */
+ if (pos + 1 > end)
+ continue;
+ if (pos + 1 + pos[0] > end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
+ "OSU SSID");
+ continue;
+ }
+ osu_ssid_len = *pos++;
+ if (osu_ssid_len > 32) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Invalid OSU SSID "
+ "Length %u", osu_ssid_len);
+ continue;
+ }
+ osu_ssid = pos;
+ pos += osu_ssid_len;
+
+ if (pos + 1 > end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
+ "Number of OSU Providers");
+ continue;
+ }
+ num_providers = *pos++;
+ wpa_printf(MSG_DEBUG, "HS 2.0: Number of OSU Providers: %u",
+ num_providers);
+
+ /* OSU Providers */
+ while (pos + 2 < end && 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);
+ pos += len;
+ }
+
+ if (pos != end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Ignored %d bytes of "
+ "extra data after OSU Providers",
+ (int) (end - pos));
+ }
+ }
+
+ wpa_s->fetch_osu_icon_in_progress = 1;
+ hs20_next_osu_icon(wpa_s);
+}
+
+
+static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_printf(MSG_DEBUG, "OSU provisioning fetch scan completed");
+ if (!wpa_s->fetch_osu_waiting_scan) {
+ wpa_printf(MSG_DEBUG, "OSU fetch have been canceled");
+ return;
+ }
+ 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);
+}
+
+
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
+ "interface disabled");
+ return -1;
+ }
+
+ if (wpa_s->scanning) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
+ "scanning");
+ return -1;
+ }
+
+ if (wpa_s->conf->osu_dir == NULL) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
+ "osu_dir not configured");
+ return -1;
+ }
+
+ if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
+ "fetch in progress (%d, %d)",
+ wpa_s->fetch_anqp_in_progress,
+ wpa_s->network_select);
+ return -1;
+ }
+
+ 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);
+
+ return 0;
+}
+
+
+void hs20_start_osu_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->fetch_osu_waiting_scan = 1;
+ wpa_s->num_osu_scans++;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->scan_res_handler = hs20_osu_scan_res_handler;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "Cancel OSU fetch");
+ interworking_stop_fetch_anqp(wpa_s);
+ wpa_s->fetch_osu_waiting_scan = 0;
+ wpa_s->network_select = 0;
+ wpa_s->fetch_osu_info = 0;
+ wpa_s->fetch_osu_icon_in_progress = 0;
+}
+
+
+void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s)
+{
+ hs20_osu_icon_fetch_result(wpa_s, -1);
+ eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
+ eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL);
+}
+
+
+void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
+ const char *url, u8 osu_method)
+{
+ if (url)
+ wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION "%u %s",
+ osu_method, url);
+ else
+ wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION);
+}
+
+
+void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
+ u16 reauth_delay, const char *url)
+{
+ if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Ignore deauthentication imminent notice since PMF was not enabled");
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, HS20_DEAUTH_IMMINENT_NOTICE "%u %u %s",
+ code, reauth_delay, url);
+
+ if (code == HS20_DEAUTH_REASON_CODE_BSS) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to blacklist");
+ wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ /* TODO: For now, disable full ESS since some drivers may not
+ * support disabling per BSS. */
+ if (wpa_s->current_ssid) {
+ struct os_reltime now;
+ os_get_reltime(&now);
+ if (now.sec + reauth_delay <=
+ wpa_s->current_ssid->disabled_until.sec)
+ return;
+ wpa_printf(MSG_DEBUG, "HS 2.0: Disable network for %u seconds (BSS)",
+ reauth_delay);
+ wpa_s->current_ssid->disabled_until.sec =
+ now.sec + reauth_delay;
+ }
+ }
+
+ if (code == HS20_DEAUTH_REASON_CODE_ESS && wpa_s->current_ssid) {
+ struct os_reltime now;
+ os_get_reltime(&now);
+ if (now.sec + reauth_delay <=
+ wpa_s->current_ssid->disabled_until.sec)
+ return;
+ wpa_printf(MSG_DEBUG, "HS 2.0: Disable network for %u seconds",
+ reauth_delay);
+ wpa_s->current_ssid->disabled_until.sec =
+ now.sec + reauth_delay;
+ }
+}
+
+
+void hs20_deinit(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
+ hs20_free_osu_prov(wpa_s);
+}
diff --git a/contrib/wpa/wpa_supplicant/hs20_supplicant.h b/contrib/wpa/wpa_supplicant/hs20_supplicant.h
index 6eb3926..85b5120 100644
--- a/contrib/wpa/wpa_supplicant/hs20_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/hs20_supplicant.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -8,13 +8,34 @@
#ifndef HS20_SUPPLICANT_H
#define HS20_SUPPLICANT_H
-void wpas_hs20_add_indication(struct wpabuf *buf);
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id);
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);
+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,
- const u8 *sa, const u8 *data, size_t slen);
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen);
+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);
+void hs20_notify_parse_done(struct wpa_supplicant *wpa_s);
+
+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_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);
+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_deinit(struct wpa_supplicant *wpa_s);
#endif /* HS20_SUPPLICANT_H */
diff --git a/contrib/wpa/wpa_supplicant/ibss_rsn.c b/contrib/wpa/wpa_supplicant/ibss_rsn.c
index 046f181..d0ae135 100644
--- a/contrib/wpa/wpa_supplicant/ibss_rsn.c
+++ b/contrib/wpa/wpa_supplicant/ibss_rsn.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - IBSS RSN
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,15 +9,21 @@
#include "includes.h"
#include "common.h"
+#include "common/wpa_ctrl.h"
+#include "utils/eloop.h"
#include "l2_packet/l2_packet.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/wpa_ie.h"
#include "ap/wpa_auth.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
+#include "common/ieee802_11_defs.h"
#include "ibss_rsn.h"
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
const u8 *addr)
{
@@ -32,6 +38,7 @@ static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
static void ibss_rsn_free(struct ibss_rsn_peer *peer)
{
+ eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
wpa_auth_sta_deinit(peer->auth);
wpa_sm_deinit(peer->supp);
os_free(peer);
@@ -65,7 +72,7 @@ static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
- return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+ return -1;
}
@@ -113,6 +120,22 @@ static int supp_get_beacon_ie(void *ctx)
}
+static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
+{
+ struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+
+ if ((peer->authentication_status &
+ (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) !=
+ (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH))
+ return;
+ if (peer->authentication_status & IBSS_RSN_REPORTED_PTK)
+ return;
+ peer->authentication_status |= IBSS_RSN_REPORTED_PTK;
+ wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR,
+ MAC2STR(peer->addr));
+}
+
+
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,
@@ -127,6 +150,8 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
if (key_idx == 0) {
+ peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP;
+ ibss_check_rsn_completed(peer);
/*
* In IBSS RSN, the pairwise key from the 4-way handshake
* initiated by the peer with highest MAC address is used.
@@ -205,7 +230,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);
+ wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL);
peer->supp_ie_len = sizeof(peer->supp_ie);
if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
@@ -232,7 +257,8 @@ 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 *prev_psk)
+static const u8 * auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *p2p_dev_addr, const u8 *prev_psk)
{
struct ibss_rsn *ibss_rsn = ctx;
wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
@@ -257,7 +283,7 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
data_len);
- return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len);
+ return -1;
}
@@ -280,6 +306,15 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
if (idx == 0) {
+ if (addr) {
+ struct ibss_rsn_peer *peer;
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer) {
+ peer->authentication_status |=
+ IBSS_RSN_SET_PTK_AUTH;
+ ibss_check_rsn_completed(peer);
+ }
+ }
/*
* In IBSS RSN, the pairwise key from the 4-way handshake
* initiated by the peer with highest MAC address is used.
@@ -296,6 +331,13 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
}
+static void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason)
+{
+ struct ibss_rsn *ibss_rsn = ctx;
+ wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason);
+}
+
+
static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
void *ctx),
void *cb_ctx)
@@ -386,6 +428,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
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);
if (ibss_rsn->auth_group == NULL) {
@@ -402,7 +445,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
struct ibss_rsn_peer *peer)
{
- peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr);
+ peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr, NULL);
if (peer->auth == NULL) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
return -1;
@@ -430,45 +473,152 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
}
-int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
{
- struct ibss_rsn_peer *peer;
+ struct ieee80211_mgmt auth;
+ const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
+ struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
- if (ibss_rsn == NULL)
+ if (wpa_s->driver->send_frame == NULL)
return -1;
- if (ibss_rsn_get_peer(ibss_rsn, addr)) {
- wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant "
- "for peer " MACSTR " already running",
- MAC2STR(addr));
- return 0;
+ os_memset(&auth, 0, sizeof(auth));
+
+ auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_AUTH);
+ os_memcpy(auth.da, da, ETH_ALEN);
+ os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN);
+
+ auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN);
+ auth.u.auth.auth_transaction = host_to_le16(seq);
+ auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+
+ wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
+ seq, MAC2STR(da));
+
+ return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
+ auth_length, 0);
+}
+
+
+static int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer)
+{
+ return peer->authentication_status &
+ (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US);
+}
+
+
+static struct ibss_rsn_peer *
+ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+ struct ibss_rsn_peer *peer;
+ if (ibss_rsn == NULL)
+ return NULL;
+
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer) {
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR
+ " already running", MAC2STR(addr));
+ return peer;
}
- wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
- "Supplicant for peer " MACSTR, MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR,
+ MAC2STR(addr));
peer = os_zalloc(sizeof(*peer));
- if (peer == NULL)
- return -1;
+ if (peer == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory.");
+ return NULL;
+ }
peer->ibss_rsn = ibss_rsn;
os_memcpy(peer->addr, addr, ETH_ALEN);
+ peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED;
- if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk)
- < 0) {
+ if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr,
+ ibss_rsn->psk) < 0) {
ibss_rsn_free(peer);
+ return NULL;
+ }
+
+ peer->next = ibss_rsn->peers;
+ ibss_rsn->peers = peer;
+
+ return peer;
+}
+
+
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ibss_rsn_peer *peer = eloop_ctx;
+
+ /*
+ * Assume peer does not support Authentication exchange or the frame was
+ * lost somewhere - start EAPOL Authenticator.
+ */
+ wpa_printf(MSG_DEBUG,
+ "RSN: Timeout on waiting Authentication frame response from "
+ MACSTR " - start authenticator", MAC2STR(peer->addr));
+
+ peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
+ ibss_rsn_auth_init(peer->ibss_rsn, peer);
+}
+
+
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+ struct ibss_rsn_peer *peer;
+ int res;
+
+ /* if the peer already exists, exit immediately */
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer)
+ return 0;
+
+ peer = ibss_rsn_peer_init(ibss_rsn, addr);
+ if (peer == NULL)
return -1;
+
+ /* Open Authentication: send first Authentication frame */
+ res = ibss_rsn_send_auth(ibss_rsn, addr, 1);
+ if (res) {
+ /*
+ * The driver may not support Authentication frame exchange in
+ * IBSS. Ignore authentication and go through EAPOL exchange.
+ */
+ peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
+ return ibss_rsn_auth_init(ibss_rsn, peer);
+ } else {
+ os_get_reltime(&peer->own_auth_tx);
+ eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL);
}
- if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
- ibss_rsn_free(peer);
+ return 0;
+}
+
+
+static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn,
+ struct ibss_rsn_peer *peer, int reason)
+{
+ int already_started;
+
+ if (ibss_rsn == NULL || peer == NULL)
return -1;
+
+ already_started = ibss_rsn_is_auth_started(peer);
+ peer->authentication_status |= reason;
+
+ if (already_started) {
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already "
+ "started for peer " MACSTR, MAC2STR(peer->addr));
+ return 0;
}
- peer->next = ibss_rsn->peers;
- ibss_rsn->peers = peer;
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator "
+ "for now-authenticated peer " MACSTR, MAC2STR(peer->addr));
- return 0;
+ return ibss_rsn_auth_init(ibss_rsn, peer);
}
@@ -609,10 +759,21 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
return -1;
os_memcpy(tmp, buf, len);
if (supp) {
- wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant");
+ peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
+ MACSTR, MAC2STR(peer->addr));
wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
} else {
- wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator");
+ if (ibss_rsn_is_auth_started(peer) == 0) {
+ wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for "
+ "Authenticator dropped as " MACSTR " is not "
+ "authenticated", MAC2STR(peer->addr));
+ os_free(tmp);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator "
+ "from "MACSTR, MAC2STR(peer->addr));
wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len);
}
os_free(tmp);
@@ -638,8 +799,16 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
* Create new IBSS peer based on an EAPOL message from the peer
* Authenticator.
*/
- if (ibss_rsn_start(ibss_rsn, src_addr) < 0)
+ peer = ibss_rsn_peer_init(ibss_rsn, src_addr);
+ if (peer == NULL)
return -1;
+
+ /* assume the peer is authenticated already */
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer "
+ MACSTR, MAC2STR(src_addr));
+ ibss_rsn_peer_authenticated(ibss_rsn, peer,
+ IBSS_RSN_AUTH_EAPOL_BY_US);
+
return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
buf, len);
}
@@ -647,10 +816,101 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
return 0;
}
-
void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
{
if (ibss_rsn == NULL)
return;
os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
}
+
+
+static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
+ struct ibss_rsn_peer *peer,
+ const u8* addr)
+{
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR,
+ MAC2STR(addr));
+
+ if (peer &&
+ peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
+ if (peer->own_auth_tx.sec) {
+ struct os_reltime now, diff;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &peer->own_auth_tx, &diff);
+ if (diff.sec == 0 && diff.usec < 500000) {
+ wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX",
+ (int) diff.usec);
+ goto skip_reinit;
+ }
+ }
+ /*
+ * A peer sent us an Authentication frame even though it already
+ * started an EAPOL session. We should reinit state machines
+ * here, but it's much more complicated than just deleting and
+ * recreating the state machine
+ */
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station "
+ MACSTR, MAC2STR(addr));
+
+ ibss_rsn_stop(ibss_rsn, addr);
+ peer = NULL;
+ }
+
+ if (!peer) {
+ peer = ibss_rsn_peer_init(ibss_rsn, addr);
+ if (!peer)
+ return;
+
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR,
+ MAC2STR(addr));
+ }
+
+skip_reinit:
+ /* reply with an Authentication frame now, before sending an EAPOL */
+ ibss_rsn_send_auth(ibss_rsn, addr, 2);
+ /* no need to start another AUTH challenge in the other way.. */
+ ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US);
+}
+
+
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+ size_t len)
+{
+ const struct ieee80211_mgmt *header;
+ struct ibss_rsn_peer *peer;
+ size_t auth_length;
+
+ header = (const struct ieee80211_mgmt *) auth_frame;
+ auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
+
+ if (ibss_rsn == NULL || len < auth_length)
+ return;
+
+ if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN ||
+ le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS)
+ return;
+
+ peer = ibss_rsn_get_peer(ibss_rsn, header->sa);
+
+ switch (le_to_host16(header->u.auth.auth_transaction)) {
+ case 1:
+ ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa);
+ break;
+ case 2:
+ wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from "
+ MACSTR, MAC2STR(header->sa));
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from "
+ "unknown STA " MACSTR, MAC2STR(header->sa));
+ break;
+ }
+
+ /* authentication has been completed */
+ eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
+ wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with " MACSTR,
+ MAC2STR(header->sa));
+ ibss_rsn_peer_authenticated(ibss_rsn, peer,
+ IBSS_RSN_AUTH_BY_US);
+ break;
+ }
+}
diff --git a/contrib/wpa/wpa_supplicant/ibss_rsn.h b/contrib/wpa/wpa_supplicant/ibss_rsn.h
index 1da94ab..67fae2d 100644
--- a/contrib/wpa/wpa_supplicant/ibss_rsn.h
+++ b/contrib/wpa/wpa_supplicant/ibss_rsn.h
@@ -11,6 +11,21 @@
struct ibss_rsn;
+/* not authenticated */
+#define IBSS_RSN_AUTH_NOT_AUTHENTICATED 0x00
+/* remote peer sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_PEER 0x01
+/* we sent an AUTH message with seq 1 */
+#define IBSS_RSN_AUTH_BY_US 0x02
+/* we sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_US 0x04
+/* PTK derived as supplicant */
+#define IBSS_RSN_SET_PTK_SUPP 0x08
+/* PTK derived as authenticator */
+#define IBSS_RSN_SET_PTK_AUTH 0x10
+/* PTK completion reported */
+#define IBSS_RSN_REPORTED_PTK 0x20
+
struct ibss_rsn_peer {
struct ibss_rsn_peer *next;
struct ibss_rsn *ibss_rsn;
@@ -23,6 +38,9 @@ struct ibss_rsn_peer {
size_t supp_ie_len;
struct wpa_state_machine *auth;
+ int authentication_status;
+
+ struct os_reltime own_auth_tx;
};
struct ibss_rsn {
@@ -40,5 +58,7 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
const u8 *buf, size_t len);
void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+ size_t len);
#endif /* IBSS_RSN_H */
diff --git a/contrib/wpa/wpa_supplicant/interworking.c b/contrib/wpa/wpa_supplicant/interworking.c
index b8a8bb2..4a39665 100644
--- a/contrib/wpa/wpa_supplicant/interworking.c
+++ b/contrib/wpa/wpa_supplicant/interworking.c
@@ -1,6 +1,7 @@
/*
* Interworking (IEEE 802.11u)
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, 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.
@@ -18,12 +19,15 @@
#include "eap_common/eap_defs.h"
#include "eap_peer/eap.h"
#include "eap_peer/eap_methods.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "config.h"
#include "config_ssid.h"
#include "bss.h"
#include "scan.h"
#include "notify.h"
+#include "driver_i.h"
#include "gas_query.h"
#include "hs20_supplicant.h"
#include "interworking.h"
@@ -42,29 +46,50 @@
#endif
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static struct wpa_cred * interworking_credentials_available_realm(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
+ int *excluded);
+static struct wpa_cred * interworking_credentials_available_3gpp(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
+ int *excluded);
+
+
+static int cred_prio_cmp(const struct wpa_cred *a, const struct wpa_cred *b)
+{
+ if (a->priority > b->priority)
+ return 1;
+ if (a->priority < b->priority)
+ return -1;
+ if (a->provisioning_sp == NULL || b->provisioning_sp == NULL ||
+ os_strcmp(a->provisioning_sp, b->provisioning_sp) != 0)
+ return 0;
+ if (a->sp_priority < b->sp_priority)
+ return 1;
+ if (a->sp_priority > b->sp_priority)
+ return -1;
+ return 0;
+}
static void interworking_reconnect(struct wpa_supplicant *wpa_s)
{
+ unsigned int tried;
+
if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ tried = wpa_s->interworking_fast_assoc_tried;
+ wpa_s->interworking_fast_assoc_tried = 1;
- if (wpa_s->last_scan_res_used > 0) {
- struct os_time now;
- os_get_time(&now);
- if (now.sec - wpa_s->last_scan.sec <= 5) {
- wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
- "are fresh - connect without new scan");
- if (wpas_select_network_from_last_scan(wpa_s) >= 0)
- return;
- }
- }
+ if (!tried && wpa_supplicant_fast_associate(wpa_s) >= 0)
+ return;
+ wpa_s->interworking_fast_assoc_tried = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -103,6 +128,9 @@ static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
{
struct wpa_supplicant *wpa_s = ctx;
+ wpa_printf(MSG_DEBUG, "ANQP: Response callback dst=" MACSTR
+ " dialog_token=%u result=%d status_code=%u",
+ MAC2STR(dst), dialog_token, result, status_code);
anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
status_code);
interworking_next_anqp_fetch(wpa_s);
@@ -116,6 +144,8 @@ static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
if (cred->roaming_consortium_len)
return 1;
+ if (cred->required_roaming_consortium_len)
+ return 1;
}
return 0;
}
@@ -154,13 +184,45 @@ static int cred_with_domain(struct wpa_supplicant *wpa_s)
struct wpa_cred *cred;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- if (cred->domain || cred->pcsc || cred->imsi)
+ if (cred->domain || cred->pcsc || cred->imsi ||
+ cred->roaming_partner)
return 1;
}
return 0;
}
+#ifdef CONFIG_HS20
+
+static int cred_with_min_backhaul(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->min_dl_bandwidth_home ||
+ cred->min_ul_bandwidth_home ||
+ cred->min_dl_bandwidth_roaming ||
+ cred->min_ul_bandwidth_roaming)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_conn_capab(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->num_req_conn_capab)
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_HS20 */
+
+
static int additional_roaming_consortiums(struct wpa_bss *bss)
{
const u8 *ie;
@@ -189,8 +251,9 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
struct wpabuf *extra = NULL;
int all = wpa_s->fetch_all_anqp;
- wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
- MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
+ MAC2STR(bss->bssid));
+ wpa_s->interworking_gas_bss = bss;
info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
if (all) {
@@ -204,8 +267,10 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
if (all || cred_with_nai_realm(wpa_s))
info_ids[num_info_ids++] = ANQP_NAI_REALM;
- if (all || cred_with_3gpp(wpa_s))
+ if (all || cred_with_3gpp(wpa_s)) {
info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
+ wpa_supplicant_scard_init(wpa_s, NULL);
+ }
if (all || cred_with_domain(wpa_s))
info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
@@ -225,13 +290,17 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
wpabuf_put_u8(extra, 0); /* Reserved */
wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
- if (all) {
+ if (all)
wpabuf_put_u8(extra,
HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ if (all || cred_with_min_backhaul(wpa_s))
wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+ if (all || cred_with_conn_capab(wpa_s))
wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+ if (all)
wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
- }
+ if (all)
+ wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST);
gas_anqp_set_element_len(extra, len_pos);
}
#endif /* CONFIG_HS20 */
@@ -244,15 +313,15 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
NULL);
} else
- wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
- "%u", res);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Query started with dialog token %u", res);
- wpabuf_free(buf);
return ret;
}
@@ -411,11 +480,9 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
return NULL;
}
wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
- r->realm = os_malloc(realm_len + 1);
+ r->realm = dup_binstr(pos, realm_len);
if (r->realm == NULL)
return NULL;
- os_memcpy(r->realm, pos, realm_len);
- r->realm[realm_len] = '\0';
pos += realm_len;
if (pos + 1 > f_end) {
@@ -447,20 +514,25 @@ static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
struct nai_realm *realm;
const u8 *pos, *end;
u16 i, num;
+ size_t left;
- if (anqp == NULL || wpabuf_len(anqp) < 2)
+ if (anqp == NULL)
+ return NULL;
+ left = wpabuf_len(anqp);
+ if (left < 2)
return NULL;
pos = wpabuf_head_u8(anqp);
- end = pos + wpabuf_len(anqp);
+ end = pos + left;
num = WPA_GET_LE16(pos);
wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
pos += 2;
+ left -= 2;
- if (num * 5 > end - pos) {
+ if (num > left / 5) {
wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
"enough data (%u octets) for that many realms",
- num, (unsigned int) (end - pos));
+ num, (unsigned int) left);
return NULL;
}
@@ -516,55 +588,91 @@ static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
}
-static int nai_realm_cred_username(struct nai_realm_eap *eap)
+static int nai_realm_cred_username(struct wpa_supplicant *wpa_s,
+ struct nai_realm_eap *eap)
{
- if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+ if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: EAP method not supported: %d",
+ eap->method);
return 0; /* method not supported */
+ }
- if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
+ if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP &&
+ eap->method != EAP_TYPE_FAST) {
/* Only tunneled methods with username/password supported */
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: Method: %d is not TTLS, PEAP, or FAST",
+ eap->method);
return 0;
}
- if (eap->method == EAP_TYPE_PEAP) {
+ if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) {
if (eap->inner_method &&
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+ eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: PEAP/FAST: Inner method not supported: %d",
+ eap->inner_method);
return 0;
+ }
if (!eap->inner_method &&
- eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
+ eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: MSCHAPv2 not supported");
return 0;
+ }
}
if (eap->method == EAP_TYPE_TTLS) {
if (eap->inner_method == 0 && eap->inner_non_eap == 0)
return 1; /* Assume TTLS/MSCHAPv2 is used */
if (eap->inner_method &&
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+ eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: TTLS, but inner not supported: %d",
+ eap->inner_method);
return 0;
+ }
if (eap->inner_non_eap &&
eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
- eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
+ eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: TTLS, inner-non-eap not supported: %d",
+ eap->inner_non_eap);
return 0;
+ }
}
if (eap->inner_method &&
eap->inner_method != EAP_TYPE_GTC &&
- eap->inner_method != EAP_TYPE_MSCHAPV2)
+ eap->inner_method != EAP_TYPE_MSCHAPV2) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: inner-method not GTC or MSCHAPv2: %d",
+ eap->inner_method);
return 0;
+ }
return 1;
}
-static int nai_realm_cred_cert(struct nai_realm_eap *eap)
+static int nai_realm_cred_cert(struct wpa_supplicant *wpa_s,
+ struct nai_realm_eap *eap)
{
- if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+ if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-cert: Method not supported: %d",
+ eap->method);
return 0; /* method not supported */
+ }
if (eap->method != EAP_TYPE_TLS) {
/* Only EAP-TLS supported for credential authentication */
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-cert: Method not TLS: %d",
+ eap->method);
return 0;
}
@@ -572,27 +680,33 @@ static int nai_realm_cred_cert(struct nai_realm_eap *eap)
}
-static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
struct nai_realm *realm)
{
u8 e;
- if (cred == NULL ||
- cred->username == NULL ||
+ if (cred->username == NULL ||
cred->username[0] == '\0' ||
((cred->password == NULL ||
cred->password[0] == '\0') &&
(cred->private_key == NULL ||
- cred->private_key[0] == '\0')))
+ cred->private_key[0] == '\0'))) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-find-eap: incomplete cred info: username: %s password: %s private_key: %s",
+ cred->username ? cred->username : "NULL",
+ cred->password ? cred->password : "NULL",
+ cred->private_key ? cred->private_key : "NULL");
return NULL;
+ }
for (e = 0; e < realm->eap_count; e++) {
struct nai_realm_eap *eap = &realm->eap[e];
if (cred->password && cred->password[0] &&
- nai_realm_cred_username(eap))
+ nai_realm_cred_username(wpa_s, eap))
return eap;
if (cred->private_key && cred->private_key[0] &&
- nai_realm_cred_cert(eap))
+ nai_realm_cred_cert(wpa_s, eap))
return eap;
}
@@ -604,19 +718,29 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
{
- u8 plmn[3];
+ u8 plmn[3], plmn2[3];
const u8 *pos, *end;
u8 udhl;
- /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
+ /*
+ * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
+ * operator is allowed to include only two digits of the MNC, so allow
+ * matches based on both two and three digit MNC assumptions. Since some
+ * SIM/USIM cards may not expose MNC length conveniently, we may be
+ * provided the default MNC length 3 here and as such, checking with MNC
+ * length 2 is justifiable even though 3GPP TS 24.234 does not mention
+ * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
+ * with otherwise matching values would not be good idea in general, so
+ * this should not result in selecting incorrect networks.
+ */
+ /* Match with 3 digit MNC */
plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
- plmn[1] = imsi[2] - '0';
- /* default to MNC length 3 if unknown */
- if (mnc_len != 2)
- plmn[1] |= (imsi[5] - '0') << 4;
- else
- plmn[1] |= 0xf0;
+ plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
+ /* Match with 2 digit MNC */
+ plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
+ plmn2[1] = (imsi[2] - '0') | 0xf0;
+ plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
if (anqp == NULL)
return 0;
@@ -636,6 +760,10 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
}
end = pos + udhl;
+ wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
+ plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
+ imsi, mnc_len);
+
while (pos + 2 <= end) {
u8 iei, len;
const u8 *l_end;
@@ -648,14 +776,20 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
if (iei == 0 && len > 0) {
/* PLMN List */
u8 num, i;
+ wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
+ pos, len);
num = *pos++;
for (i = 0; i < num; i++) {
- if (pos + 3 > end)
+ if (pos + 3 > l_end)
break;
- if (os_memcmp(pos, plmn, 3) == 0)
+ if (os_memcmp(pos, plmn, 3) == 0 ||
+ os_memcmp(pos, plmn2, 3) == 0)
return 1; /* Found matching PLMN */
pos += 3;
}
+ } else {
+ wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
+ pos, len);
}
pos = l_end;
@@ -714,8 +848,8 @@ static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
*pos++ = imsi[4];
*pos++ = imsi[5];
}
- pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
- imsi[0], imsi[1], imsi[2]);
+ os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
+ imsi[0], imsi[1], imsi[2]);
return 0;
}
@@ -732,12 +866,86 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
#endif /* INTERWORKING_3GPP */
+static int already_connected(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid, *sel_ssid;
+ struct wpa_bss *selected;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
+ return 0;
+
+ ssid = wpa_s->current_ssid;
+ if (ssid->parent_cred != cred)
+ return 0;
+
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+ return 0;
+
+ sel_ssid = NULL;
+ selected = wpa_supplicant_pick_network(wpa_s, &sel_ssid);
+ if (selected && sel_ssid && sel_ssid->priority > ssid->priority)
+ return 0; /* higher priority network in scan results */
+
+ return 1;
+}
+
+
+static void remove_duplicate_network(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
+ struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid->parent_cred != cred)
+ continue;
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+ continue;
+
+ break;
+ }
+
+ if (ssid == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
+
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+}
+
+
static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- if (wpa_config_set(ssid, "key_mgmt",
- wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
- "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
+ const char *key_mgmt = NULL;
+#ifdef CONFIG_IEEE80211R
+ int res;
+ struct wpa_driver_capa capa;
+
+ res = wpa_drv_get_capa(wpa_s, &capa);
+ if (res == 0 && capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+ key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
+ "WPA-EAP WPA-EAP-SHA256 FT-EAP" :
+ "WPA-EAP FT-EAP";
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ 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;
@@ -748,12 +956,11 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss)
+ struct wpa_cred *cred,
+ struct wpa_bss *bss, int only_add)
{
#ifdef INTERWORKING_3GPP
- struct wpa_cred *cred;
struct wpa_ssid *ssid;
- const u8 *ie;
int eap_type;
int res;
char prefix;
@@ -761,45 +968,16 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
- for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- char *sep;
- const char *imsi;
- int mnc_len;
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
+ " (3GPP)", MAC2STR(bss->bssid));
-#ifdef PCSC_FUNCS
- if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
- wpa_s->imsi[0]) {
- imsi = wpa_s->imsi;
- mnc_len = wpa_s->mnc_len;
- goto compare;
- }
-#endif /* PCSC_FUNCS */
-
- if (cred->imsi == NULL || !cred->imsi[0] ||
- cred->milenage == NULL || !cred->milenage[0])
- continue;
-
- sep = os_strchr(cred->imsi, '-');
- if (sep == NULL ||
- (sep - cred->imsi != 5 && sep - cred->imsi != 6))
- continue;
- mnc_len = sep - cred->imsi - 3;
- imsi = cred->imsi;
-
-#ifdef PCSC_FUNCS
- compare:
-#endif /* PCSC_FUNCS */
- if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
- break;
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ return wpa_s->current_ssid->id;
}
- if (cred == NULL)
- return -1;
- ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
- if (ie == NULL)
- return -1;
- wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
- MAC2STR(bss->bssid));
+ remove_duplicate_network(wpa_s, cred, bss);
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
@@ -810,11 +988,12 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->priority = cred->priority;
ssid->temporary = 1;
- ssid->ssid = os_zalloc(ie[1] + 1);
+ ssid->ssid = os_zalloc(bss->ssid_len + 1);
if (ssid->ssid == NULL)
goto fail;
- os_memcpy(ssid->ssid, ie + 2, ie[1]);
- ssid->ssid_len = ie[1];
+ os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+ ssid->ssid_len = bss->ssid_len;
+ ssid->eap.sim_num = cred->sim_num;
if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
@@ -847,13 +1026,13 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
break;
}
if (res < 0) {
- wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
- eap_type);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Selected EAP method (%d) not supported", eap_type);
goto fail;
}
if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
+ wpa_msg(wpa_s, MSG_DEBUG, "Failed to set Root NAI");
goto fail;
}
@@ -870,14 +1049,12 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
goto fail;
}
- if (cred->password && cred->password[0] &&
- wpa_config_set_quoted(ssid, "password", cred->password) < 0)
- goto fail;
-
+ wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf);
- interworking_reconnect(wpa_s);
+ if (!only_add)
+ interworking_reconnect(wpa_s);
- return 0;
+ return ssid->id;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -963,6 +1140,27 @@ static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
}
+static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ const u8 *ie;
+
+ if (cred->required_roaming_consortium_len == 0)
+ return 0;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+ if (ie == NULL &&
+ (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+ return 1;
+
+ return !roaming_consortium_match(ie,
+ bss->anqp ?
+ bss->anqp->roaming_consortium : NULL,
+ cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len);
+}
+
+
static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
{
size_t i;
@@ -981,11 +1179,164 @@ 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)
+{
+ int res;
+ unsigned int dl_bandwidth, ul_bandwidth;
+ const u8 *wan;
+ u8 wan_info, dl_load, ul_load;
+ u16 lmd;
+ u32 ul_speed, dl_speed;
+
+ if (!cred->min_dl_bandwidth_home &&
+ !cred->min_ul_bandwidth_home &&
+ !cred->min_dl_bandwidth_roaming &&
+ !cred->min_ul_bandwidth_roaming)
+ return 0; /* No bandwidth constraint specified */
+
+ if (bss->anqp == NULL || bss->anqp->hs20_wan_metrics == NULL)
+ return 0; /* No WAN Metrics known - ignore constraint */
+
+ wan = wpabuf_head(bss->anqp->hs20_wan_metrics);
+ wan_info = wan[0];
+ if (wan_info & BIT(3))
+ return 1; /* WAN link at capacity */
+ lmd = WPA_GET_LE16(wan + 11);
+ if (lmd == 0)
+ return 0; /* Downlink/Uplink Load was not measured */
+ dl_speed = WPA_GET_LE32(wan + 1);
+ ul_speed = WPA_GET_LE32(wan + 5);
+ dl_load = wan[9];
+ ul_load = wan[10];
+
+ if (dl_speed >= 0xffffff)
+ dl_bandwidth = dl_speed / 255 * (255 - dl_load);
+ else
+ dl_bandwidth = dl_speed * (255 - dl_load) / 255;
+
+ if (ul_speed >= 0xffffff)
+ ul_bandwidth = ul_speed / 255 * (255 - ul_load);
+ else
+ ul_bandwidth = ul_speed * (255 - ul_load) / 255;
+
+ res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
+ bss->anqp->domain_name : NULL);
+ if (res > 0) {
+ if (cred->min_dl_bandwidth_home > dl_bandwidth)
+ return 1;
+ if (cred->min_ul_bandwidth_home > ul_bandwidth)
+ return 1;
+ } else {
+ if (cred->min_dl_bandwidth_roaming > dl_bandwidth)
+ return 1;
+ if (cred->min_ul_bandwidth_roaming > ul_bandwidth)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ const u8 *ie;
+ int res;
+
+ if (!cred->max_bss_load)
+ return 0; /* No BSS Load constraint specified */
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_BSS_LOAD);
+ if (ie == NULL || ie[1] < 3)
+ return 0; /* No BSS Load advertised */
+
+ res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
+ bss->anqp->domain_name : NULL);
+ if (res <= 0)
+ return 0; /* Not a home network */
+
+ return ie[4] > cred->max_bss_load;
+}
+
+
+static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
+{
+ while (pos + 4 <= end) {
+ if (pos[0] == proto && pos[3] == 1 /* Open */)
+ return 1;
+ pos += 4;
+ }
+
+ return 0;
+}
+
+
+static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
+ u16 port)
+{
+ while (pos + 4 <= end) {
+ if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
+ pos[3] == 1 /* Open */)
+ return 1;
+ pos += 4;
+ }
+
+ return 0;
+}
+
+
+static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ int res;
+ const u8 *capab, *end;
+ unsigned int i, j;
+ int *ports;
+
+ if (!cred->num_req_conn_capab)
+ return 0; /* No connection capability constraint specified */
+
+ if (bss->anqp == NULL || bss->anqp->hs20_connection_capability == NULL)
+ return 0; /* No Connection Capability known - ignore constraint
+ */
+
+ res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
+ bss->anqp->domain_name : NULL);
+ if (res > 0)
+ return 0; /* No constraint in home network */
+
+ capab = wpabuf_head(bss->anqp->hs20_connection_capability);
+ end = capab + wpabuf_len(bss->anqp->hs20_connection_capability);
+
+ for (i = 0; i < cred->num_req_conn_capab; i++) {
+ ports = cred->req_conn_capab_port[i];
+ if (!ports) {
+ if (!has_proto_match(capab, end,
+ cred->req_conn_capab_proto[i]))
+ return 1;
+ } else {
+ for (j = 0; ports[j] > -1; j++) {
+ if (!has_proto_port_match(
+ capab, end,
+ cred->req_conn_capab_proto[i],
+ ports[j]))
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
static struct wpa_cred * interworking_credentials_available_roaming_consortium(
- struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
+ int *excluded)
{
struct wpa_cred *cred, *selected = NULL;
const u8 *ie;
+ int is_excluded = 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
@@ -1008,14 +1359,33 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
cred->roaming_consortium_len))
continue;
- if (cred_excluded_ssid(cred, bss))
+ if (cred_no_required_oi_match(cred, bss))
continue;
-
- if (selected == NULL ||
- selected->priority < cred->priority)
- selected = cred;
+ if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss))
+ continue;
+ if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss))
+ continue;
+ if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss))
+ continue;
+ if (cred_excluded_ssid(cred, bss)) {
+ if (excluded == NULL)
+ continue;
+ if (selected == NULL) {
+ selected = cred;
+ is_excluded = 1;
+ }
+ } else {
+ if (selected == NULL || is_excluded ||
+ cred_prio_cmp(selected, cred) < 0) {
+ selected = cred;
+ is_excluded = 0;
+ }
+ }
}
+ if (excluded)
+ *excluded = is_excluded;
+
return selected;
}
@@ -1119,18 +1489,33 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
return -1;
+ if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
+ wpa_config_set_quoted(ssid, "domain_suffix_match",
+ cred->domain_suffix_match) < 0)
+ return -1;
+
+ ssid->eap.ocsp = cred->ocsp;
+
return 0;
}
static int interworking_connect_roaming_consortium(
struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
- struct wpa_bss *bss, const u8 *ssid_ie)
+ struct wpa_bss *bss, int only_add)
{
struct wpa_ssid *ssid;
- wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
- "roaming consortium match", MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
+ " based on roaming consortium match", MAC2STR(bss->bssid));
+
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ return wpa_s->current_ssid->id;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
@@ -1140,18 +1525,18 @@ static int interworking_connect_roaming_consortium(
wpa_config_set_network_defaults(ssid);
ssid->priority = cred->priority;
ssid->temporary = 1;
- ssid->ssid = os_zalloc(ssid_ie[1] + 1);
+ ssid->ssid = os_zalloc(bss->ssid_len + 1);
if (ssid->ssid == NULL)
goto fail;
- os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
- ssid->ssid_len = ssid_ie[1];
+ os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+ ssid->ssid_len = bss->ssid_len;
if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
if (cred->eap_method == NULL) {
- wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
- "credential using roaming consortium");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No EAP method set for credential using roaming consortium");
goto fail;
}
@@ -1161,10 +1546,12 @@ static int interworking_connect_roaming_consortium(
cred->eap_method->method == EAP_TYPE_TTLS) < 0)
goto fail;
+ wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf);
- interworking_reconnect(wpa_s);
+ if (!only_add)
+ interworking_reconnect(wpa_s);
- return 0;
+ return ssid->id;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -1173,77 +1560,161 @@ fail:
}
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, int allow_excluded,
+ int only_add)
{
- struct wpa_cred *cred;
+ struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
struct nai_realm *realm;
struct nai_realm_eap *eap = NULL;
u16 count, i;
char buf[100];
- const u8 *ie;
+ int excluded = 0, *excl = allow_excluded ? &excluded : NULL;
+ const char *name;
if (wpa_s->conf->cred == NULL || bss == NULL)
return -1;
- ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
- if (ie == NULL || ie[1] == 0) {
- wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
- MACSTR, MAC2STR(bss->bssid));
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Reject connection to disallowed BSS "
+ MACSTR, MAC2STR(bss->bssid));
return -1;
}
+ wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
+ " for connection (allow_excluded=%d)",
+ MAC2STR(bss->bssid), allow_excluded);
+
if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
/*
* We currently support only HS 2.0 networks and those are
* required to use WPA2-Enterprise.
*/
- wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
- "RSN");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Network does not use RSN");
return -1;
}
- cred = interworking_credentials_available_roaming_consortium(wpa_s,
- bss);
- if (cred)
- return interworking_connect_roaming_consortium(wpa_s, cred,
- bss, ie);
+ cred_rc = interworking_credentials_available_roaming_consortium(
+ wpa_s, bss, 0, excl);
+ if (cred_rc) {
+ 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))
+ excl = NULL;
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss, 0, excl);
+ if (cred) {
+ 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))
+ excl = NULL;
+ }
+
+ cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 0,
+ excl);
+ if (cred_3gpp) {
+ 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))
+ excl = NULL;
+ }
+
+ if (!cred_rc && !cred && !cred_3gpp) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No full credential matches - consider options without BW(etc.) limits");
+ cred_rc = interworking_credentials_available_roaming_consortium(
+ wpa_s, bss, 1, excl);
+ if (cred_rc) {
+ 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))
+ excl = NULL;
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss, 1,
+ excl);
+ if (cred) {
+ 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))
+ excl = NULL;
+ }
+
+ cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss,
+ 1, excl);
+ if (cred_3gpp) {
+ 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))
+ excl = NULL;
+ }
+ }
+
+ if (cred_rc &&
+ (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) &&
+ (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0))
+ return interworking_connect_roaming_consortium(wpa_s, cred_rc,
+ bss, only_add);
+
+ if (cred_3gpp &&
+ (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) {
+ return interworking_connect_3gpp(wpa_s, cred_3gpp, bss,
+ only_add);
+ }
+
+ if (cred == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No matching credentials found for "
+ MACSTR, MAC2STR(bss->bssid));
+ return -1;
+ }
realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
&count);
if (realm == NULL) {
- wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
- "Realm list from " MACSTR, MAC2STR(bss->bssid));
- count = 0;
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Could not parse NAI Realm list from "
+ MACSTR, MAC2STR(bss->bssid));
+ return -1;
}
- for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- for (i = 0; i < count; i++) {
- if (!nai_realm_match(&realm[i], cred->realm))
- continue;
- eap = nai_realm_find_eap(cred, &realm[i]);
- if (eap)
- break;
- }
+ for (i = 0; i < count; i++) {
+ if (!nai_realm_match(&realm[i], cred->realm))
+ continue;
+ eap = nai_realm_find_eap(wpa_s, cred, &realm[i]);
if (eap)
break;
}
if (!eap) {
- if (interworking_connect_3gpp(wpa_s, bss) == 0) {
- if (realm)
- nai_realm_free(realm, count);
- return 0;
- }
-
- wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
- "and EAP method found for " MACSTR,
- MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No matching credentials and EAP method found for "
+ MACSTR, MAC2STR(bss->bssid));
nai_realm_free(realm, count);
return -1;
}
- wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
- MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR,
+ MAC2STR(bss->bssid));
+
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ nai_realm_free(realm, count);
+ return 0;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
@@ -1255,11 +1726,11 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
wpa_config_set_network_defaults(ssid);
ssid->priority = cred->priority;
ssid->temporary = 1;
- ssid->ssid = os_zalloc(ie[1] + 1);
+ ssid->ssid = os_zalloc(bss->ssid_len + 1);
if (ssid->ssid == NULL)
goto fail;
- os_memcpy(ssid->ssid, ie + 2, ie[1]);
- ssid->ssid_len = ie[1];
+ os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+ ssid->ssid_len = bss->ssid_len;
if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
@@ -1308,11 +1779,19 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
}
break;
case EAP_TYPE_PEAP:
- os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
- eap_get_name(EAP_VENDOR_IETF,
- eap->inner_method ?
- eap->inner_method :
- EAP_TYPE_MSCHAPV2));
+ case EAP_TYPE_FAST:
+ if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"",
+ 0) < 0)
+ goto fail;
+ if (wpa_config_set(ssid, "pac_file",
+ "\"blob://pac_interworking\"", 0) < 0)
+ goto fail;
+ name = eap_get_name(EAP_VENDOR_IETF,
+ eap->inner_method ? eap->inner_method :
+ EAP_TYPE_MSCHAPV2);
+ if (name == NULL)
+ goto fail;
+ os_snprintf(buf, sizeof(buf), "\"auth=%s\"", name);
if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
goto fail;
break;
@@ -1326,10 +1805,12 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
nai_realm_free(realm, count);
+ wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf);
- interworking_reconnect(wpa_s);
+ if (!only_add)
+ interworking_reconnect(wpa_s);
- return 0;
+ return ssid->id;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -1339,32 +1820,102 @@ 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)
+{
+ size_t len;
+
+ if (wpa_s->imsi[0] && wpa_s->mnc_len)
+ return 0;
+
+ len = sizeof(wpa_s->imsi) - 1;
+ if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+ scard_deinit(wpa_s->scard);
+ wpa_s->scard = NULL;
+ wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+ return -1;
+ }
+ wpa_s->imsi[len] = '\0';
+ wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+ wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+
+ return 0;
+}
+#endif /* PCSC_FUNCS */
+
+
static struct wpa_cred * interworking_credentials_available_3gpp(
- struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
+ int *excluded)
{
- struct wpa_cred *cred, *selected = NULL;
+ struct wpa_cred *selected = NULL;
+#ifdef INTERWORKING_3GPP
+ struct wpa_cred *cred;
int ret;
+ int is_excluded = 0;
-#ifdef INTERWORKING_3GPP
- if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "interworking-avail-3gpp: not avail, anqp: %p anqp_3gpp: %p",
+ bss->anqp, bss->anqp ? bss->anqp->anqp_3gpp : NULL);
return NULL;
+ }
+
+#ifdef CONFIG_EAP_PROXY
+ if (!wpa_s->imsi[0]) {
+ 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->imsi,
+ &len);
+ if (wpa_s->mnc_len > 0) {
+ wpa_s->imsi[len] = '\0';
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "eap_proxy: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+ } else {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "eap_proxy: IMSI not available");
+ }
+ }
+#endif /* CONFIG_EAP_PROXY */
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
char *sep;
const char *imsi;
int mnc_len;
+ char imsi_buf[16];
+ size_t msin_len;
#ifdef PCSC_FUNCS
- if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
- wpa_s->imsi[0]) {
+ if (cred->pcsc && wpa_s->scard) {
+ if (interworking_pcsc_read_imsi(wpa_s) < 0)
+ continue;
imsi = wpa_s->imsi;
mnc_len = wpa_s->mnc_len;
goto compare;
}
#endif /* PCSC_FUNCS */
+#ifdef CONFIG_EAP_PROXY
+ if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ goto compare;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (cred->imsi == NULL || !cred->imsi[0] ||
- cred->milenage == NULL || !cred->milenage[0])
+ (!wpa_s->conf->external_sim &&
+ (cred->milenage == NULL || !cred->milenage[0])))
continue;
sep = os_strchr(cred->imsi, '-');
@@ -1372,34 +1923,68 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
(sep - cred->imsi != 5 && sep - cred->imsi != 6))
continue;
mnc_len = sep - cred->imsi - 3;
- imsi = cred->imsi;
-
-#ifdef PCSC_FUNCS
+ os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
+ sep++;
+ msin_len = os_strlen(cred->imsi);
+ if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
+ msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
+ os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
+ imsi_buf[3 + mnc_len + msin_len] = '\0';
+ imsi = imsi_buf;
+
+#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
compare:
-#endif /* PCSC_FUNCS */
- wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
- MACSTR, MAC2STR(bss->bssid));
+#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Parsing 3GPP info from " MACSTR,
+ MAC2STR(bss->bssid));
ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
- wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+ wpa_msg(wpa_s, MSG_DEBUG, "PLMN match %sfound",
+ ret ? "" : "not ");
if (ret) {
- if (cred_excluded_ssid(cred, bss))
+ if (cred_no_required_oi_match(cred, bss))
continue;
- if (selected == NULL ||
- selected->priority < cred->priority)
- selected = cred;
+ if (!ignore_bw &&
+ cred_below_min_backhaul(wpa_s, cred, bss))
+ continue;
+ if (!ignore_bw &&
+ cred_over_max_bss_load(wpa_s, cred, bss))
+ continue;
+ if (!ignore_bw &&
+ cred_conn_capab_missing(wpa_s, cred, bss))
+ continue;
+ if (cred_excluded_ssid(cred, bss)) {
+ if (excluded == NULL)
+ continue;
+ if (selected == NULL) {
+ selected = cred;
+ is_excluded = 1;
+ }
+ } else {
+ if (selected == NULL || is_excluded ||
+ cred_prio_cmp(selected, cred) < 0) {
+ selected = cred;
+ is_excluded = 0;
+ }
+ }
}
}
+
+ if (excluded)
+ *excluded = is_excluded;
#endif /* INTERWORKING_3GPP */
return selected;
}
static struct wpa_cred * interworking_credentials_available_realm(
- struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
+ int *excluded)
{
struct wpa_cred *cred, *selected = NULL;
struct nai_realm *realm;
u16 count, i;
+ int is_excluded = 0;
if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
return NULL;
@@ -1407,12 +1992,13 @@ static struct wpa_cred * interworking_credentials_available_realm(
if (wpa_s->conf->cred == NULL)
return NULL;
- wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
- MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
+ MACSTR, MAC2STR(bss->bssid));
realm = nai_realm_parse(bss->anqp->nai_realm, &count);
if (realm == NULL) {
- wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
- "Realm list from " MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Could not parse NAI Realm list from "
+ MACSTR, MAC2STR(bss->bssid));
return NULL;
}
@@ -1423,48 +2009,114 @@ static struct wpa_cred * interworking_credentials_available_realm(
for (i = 0; i < count; i++) {
if (!nai_realm_match(&realm[i], cred->realm))
continue;
- if (nai_realm_find_eap(cred, &realm[i])) {
- if (cred_excluded_ssid(cred, bss))
+ if (nai_realm_find_eap(wpa_s, cred, &realm[i])) {
+ if (cred_no_required_oi_match(cred, bss))
continue;
- if (selected == NULL ||
- selected->priority < cred->priority)
- selected = cred;
+ if (!ignore_bw &&
+ cred_below_min_backhaul(wpa_s, cred, bss))
+ continue;
+ if (!ignore_bw &&
+ cred_over_max_bss_load(wpa_s, cred, bss))
+ continue;
+ if (!ignore_bw &&
+ cred_conn_capab_missing(wpa_s, cred, bss))
+ continue;
+ if (cred_excluded_ssid(cred, bss)) {
+ if (excluded == NULL)
+ continue;
+ if (selected == NULL) {
+ selected = cred;
+ is_excluded = 1;
+ }
+ } else {
+ if (selected == NULL || is_excluded ||
+ cred_prio_cmp(selected, cred) < 0)
+ {
+ selected = cred;
+ is_excluded = 0;
+ }
+ }
break;
+ } else {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: realm-find-eap returned false");
}
}
}
nai_realm_free(realm, count);
+ if (excluded)
+ *excluded = is_excluded;
+
return selected;
}
-static struct wpa_cred * interworking_credentials_available(
- struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static struct wpa_cred * interworking_credentials_available_helper(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
+ int *excluded)
{
struct wpa_cred *cred, *cred2;
+ int excluded1, excluded2;
- cred = interworking_credentials_available_realm(wpa_s, bss);
- cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
- if (cred && cred2 && cred2->priority >= cred->priority)
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
+ MACSTR, MAC2STR(bss->bssid));
+ return NULL;
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss, ignore_bw,
+ &excluded1);
+ cred2 = interworking_credentials_available_3gpp(wpa_s, bss, ignore_bw,
+ &excluded2);
+ if (cred && cred2 &&
+ (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) {
cred = cred2;
- if (!cred)
+ excluded1 = excluded2;
+ }
+ if (!cred) {
cred = cred2;
+ excluded1 = excluded2;
+ }
- cred2 = interworking_credentials_available_roaming_consortium(wpa_s,
- bss);
- if (cred && cred2 && cred2->priority >= cred->priority)
+ cred2 = interworking_credentials_available_roaming_consortium(
+ wpa_s, bss, ignore_bw, &excluded2);
+ if (cred && cred2 &&
+ (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) {
cred = cred2;
- if (!cred)
+ excluded1 = excluded2;
+ }
+ if (!cred) {
cred = cred2;
+ excluded1 = excluded2;
+ }
+ if (excluded)
+ *excluded = excluded1;
return cred;
}
-static int domain_name_list_contains(struct wpabuf *domain_names,
- const char *domain)
+static struct wpa_cred * interworking_credentials_available(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int *excluded)
+{
+ struct wpa_cred *cred;
+
+ if (excluded)
+ *excluded = 0;
+ cred = interworking_credentials_available_helper(wpa_s, bss, 0,
+ excluded);
+ if (cred)
+ return cred;
+ return interworking_credentials_available_helper(wpa_s, bss, 1,
+ excluded);
+}
+
+
+int domain_name_list_contains(struct wpabuf *domain_names,
+ const char *domain, int exact_match)
{
const u8 *pos, *end;
size_t len;
@@ -1482,6 +2134,12 @@ static int domain_name_list_contains(struct wpabuf *domain_names,
if (pos[0] == len &&
os_strncasecmp(domain, (const char *) (pos + 1), 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 (os_strncasecmp(domain, ap + offset, len) == 0)
+ return 1;
+ }
pos += 1 + pos[0];
}
@@ -1494,6 +2152,8 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred,
struct wpabuf *domain_names)
{
+ size_t i;
+ int ret = -1;
#ifdef INTERWORKING_3GPP
char nai[100], *realm;
@@ -1501,33 +2161,46 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
int mnc_len = 0;
if (cred->imsi)
imsi = cred->imsi;
-#ifdef CONFIG_PCSC
- else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
- wpa_s->scard && wpa_s->imsi[0]) {
+#ifdef PCSC_FUNCS
+ else if (cred->pcsc && wpa_s->scard) {
+ if (interworking_pcsc_read_imsi(wpa_s) < 0)
+ return -1;
imsi = wpa_s->imsi;
mnc_len = wpa_s->mnc_len;
}
-#endif /* CONFIG_PCSC */
+#endif /* PCSC_FUNCS */
+#ifdef CONFIG_EAP_PROXY
+ else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (domain_names &&
imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
realm = os_strchr(nai, '@');
if (realm)
realm++;
- wpa_printf(MSG_DEBUG, "Interworking: Search for match "
- "with SIM/USIM domain %s", realm);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Search for match with SIM/USIM domain %s",
+ realm);
if (realm &&
- domain_name_list_contains(domain_names, realm))
+ domain_name_list_contains(domain_names, realm, 1))
return 1;
+ if (realm)
+ ret = 0;
}
#endif /* INTERWORKING_3GPP */
if (domain_names == NULL || cred->domain == NULL)
- return 0;
+ return ret;
- wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
- "home SP FQDN %s", cred->domain);
- if (domain_name_list_contains(domain_names, cred->domain))
- return 1;
+ for (i = 0; i < cred->num_domain; i++) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Search for match with home SP FQDN %s",
+ cred->domain[i]);
+ if (domain_name_list_contains(domain_names, cred->domain[i], 1))
+ return 1;
+ }
return 0;
}
@@ -1577,32 +2250,143 @@ static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
}
+static int roaming_partner_match(struct wpa_supplicant *wpa_s,
+ struct roaming_partner *partner,
+ struct wpabuf *domain_names)
+{
+ wpa_printf(MSG_DEBUG, "Interworking: Comparing roaming_partner info fqdn='%s' exact_match=%d priority=%u country='%s'",
+ partner->fqdn, partner->exact_match, partner->priority,
+ partner->country);
+ wpa_hexdump_ascii(MSG_DEBUG, "Interworking: Domain names",
+ wpabuf_head(domain_names),
+ wpabuf_len(domain_names));
+ if (!domain_name_list_contains(domain_names, partner->fqdn,
+ partner->exact_match))
+ return 0;
+ /* TODO: match Country */
+ return 1;
+}
+
+
+static u8 roaming_prio(struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
+ struct wpa_bss *bss)
+{
+ size_t i;
+
+ if (bss->anqp == NULL || bss->anqp->domain_name == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No ANQP domain name info -> use default roaming partner priority 128");
+ return 128; /* cannot check preference with domain name */
+ }
+
+ if (interworking_home_sp_cred(wpa_s, cred, bss->anqp->domain_name) > 0)
+ {
+ wpa_printf(MSG_DEBUG, "Interworking: Determined to be home SP -> use maximum preference 0 as roaming partner priority");
+ return 0; /* max preference for home SP network */
+ }
+
+ for (i = 0; i < cred->num_roaming_partner; i++) {
+ if (roaming_partner_match(wpa_s, &cred->roaming_partner[i],
+ bss->anqp->domain_name)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Roaming partner preference match - priority %u",
+ cred->roaming_partner[i].priority);
+ return cred->roaming_partner[i].priority;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "Interworking: No roaming partner preference match - use default roaming partner priority 128");
+ return 128;
+}
+
+
+static struct wpa_bss * pick_best_roaming_partner(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *selected,
+ struct wpa_cred *cred)
+{
+ struct wpa_bss *bss;
+ u8 best_prio, prio;
+ struct wpa_cred *cred2;
+
+ /*
+ * Check if any other BSS is operated by a more preferred roaming
+ * partner.
+ */
+
+ best_prio = roaming_prio(wpa_s, cred, selected);
+ wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for selected BSS "
+ MACSTR " (cred=%d)", best_prio, MAC2STR(selected->bssid),
+ cred->id);
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (bss == selected)
+ continue;
+ cred2 = interworking_credentials_available(wpa_s, bss, NULL);
+ if (!cred2)
+ continue;
+ if (!wpa_bss_get_ie(bss, WLAN_EID_RSN))
+ continue;
+ prio = roaming_prio(wpa_s, cred2, bss);
+ wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for BSS "
+ MACSTR " (cred=%d)", prio, MAC2STR(bss->bssid),
+ cred2->id);
+ if (prio < best_prio) {
+ int bh1, bh2, load1, load2, conn1, conn2;
+ bh1 = cred_below_min_backhaul(wpa_s, cred, selected);
+ load1 = cred_over_max_bss_load(wpa_s, cred, selected);
+ conn1 = cred_conn_capab_missing(wpa_s, cred, selected);
+ bh2 = cred_below_min_backhaul(wpa_s, cred2, bss);
+ load2 = cred_over_max_bss_load(wpa_s, cred2, bss);
+ conn2 = cred_conn_capab_missing(wpa_s, cred2, bss);
+ wpa_printf(MSG_DEBUG, "Interworking: old: %d %d %d new: %d %d %d",
+ bh1, load1, conn1, bh2, load2, conn2);
+ if (bh1 || load1 || conn1 || !(bh2 || load2 || conn2)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Better roaming partner " MACSTR " selected", MAC2STR(bss->bssid));
+ best_prio = prio;
+ selected = bss;
+ }
+ }
+ }
+
+ return selected;
+}
+
+
static void interworking_select_network(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
- int selected_prio = -999999, selected_home_prio = -999999;
+ struct wpa_bss *selected2 = NULL, *selected2_home = NULL;
unsigned int count = 0;
const char *type;
int res;
- struct wpa_cred *cred;
+ struct wpa_cred *cred, *selected_cred = NULL;
+ struct wpa_cred *selected_home_cred = NULL;
+ struct wpa_cred *selected2_cred = NULL;
+ struct wpa_cred *selected2_home_cred = NULL;
wpa_s->network_select = 0;
+ wpa_printf(MSG_DEBUG, "Interworking: Select network (auto_select=%d)",
+ wpa_s->auto_select);
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- cred = interworking_credentials_available(wpa_s, bss);
+ int excluded = 0;
+ int bh, bss_load, conn_capab;
+ cred = interworking_credentials_available(wpa_s, bss,
+ &excluded);
if (!cred)
continue;
+
if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
/*
* We currently support only HS 2.0 networks and those
* are required to use WPA2-Enterprise.
*/
- wpa_printf(MSG_DEBUG, "Interworking: Credential match "
- "with " MACSTR " but network does not use "
- "RSN", MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Credential match with " MACSTR
+ " but network does not use RSN",
+ MAC2STR(bss->bssid));
continue;
}
- count++;
+ if (!excluded)
+ count++;
res = interworking_home_sp(wpa_s, bss->anqp ?
bss->anqp->domain_name : NULL);
if (res > 0)
@@ -1611,29 +2395,75 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
type = "roaming";
else
type = "unknown";
- wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
- MAC2STR(bss->bssid), type);
+ bh = cred_below_min_backhaul(wpa_s, cred, bss);
+ bss_load = cred_over_max_bss_load(wpa_s, cred, bss);
+ conn_capab = cred_conn_capab_missing(wpa_s, cred, bss);
+ wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d",
+ excluded ? INTERWORKING_BLACKLISTED : INTERWORKING_AP,
+ MAC2STR(bss->bssid), type,
+ bh ? " below_min_backhaul=1" : "",
+ bss_load ? " over_max_bss_load=1" : "",
+ conn_capab ? " conn_capab_missing=1" : "",
+ cred->id, cred->priority, cred->sp_priority);
+ if (excluded)
+ continue;
if (wpa_s->auto_select ||
(wpa_s->conf->auto_interworking &&
wpa_s->auto_network_select)) {
- if (selected == NULL ||
- cred->priority > selected_prio) {
- selected = bss;
- selected_prio = cred->priority;
- }
- if (res > 0 &&
- (selected_home == NULL ||
- cred->priority > selected_home_prio)) {
- selected_home = bss;
- selected_home_prio = cred->priority;
+ if (bh || bss_load || conn_capab) {
+ if (selected2_cred == NULL ||
+ cred_prio_cmp(cred, selected2_cred) > 0) {
+ wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2");
+ selected2 = bss;
+ selected2_cred = cred;
+ }
+ if (res > 0 &&
+ (selected2_home_cred == NULL ||
+ cred_prio_cmp(cred, selected2_home_cred) >
+ 0)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2_home");
+ selected2_home = bss;
+ selected2_home_cred = cred;
+ }
+ } else {
+ if (selected_cred == NULL ||
+ cred_prio_cmp(cred, selected_cred) > 0) {
+ wpa_printf(MSG_DEBUG, "Interworking: Mark as selected");
+ selected = bss;
+ selected_cred = cred;
+ }
+ if (res > 0 &&
+ (selected_home_cred == NULL ||
+ cred_prio_cmp(cred, selected_home_cred) >
+ 0)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Mark as selected_home");
+ selected_home = bss;
+ selected_home_cred = cred;
+ }
}
}
}
if (selected_home && selected_home != selected &&
- selected_home_prio >= selected_prio) {
+ selected_home_cred &&
+ (selected_cred == NULL ||
+ cred_prio_cmp(selected_home_cred, selected_cred) >= 0)) {
/* Prefer network operated by the Home SP */
+ wpa_printf(MSG_DEBUG, "Interworking: Overrided selected with selected_home");
selected = selected_home;
+ selected_cred = selected_home_cred;
+ }
+
+ if (!selected) {
+ if (selected2_home) {
+ wpa_printf(MSG_DEBUG, "Interworking: Use home BSS with BW limit mismatch since no other network could be selected");
+ selected = selected2_home;
+ selected_cred = selected2_home_cred;
+ } else if (selected2) {
+ wpa_printf(MSG_DEBUG, "Interworking: Use visited BSS with BW limit mismatch since no other network could be selected");
+ selected = selected2;
+ selected_cred = selected2_cred;
+ }
}
if (count == 0) {
@@ -1643,16 +2473,17 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
* have matching APs.
*/
if (interworking_find_network_match(wpa_s)) {
- wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
- "match for enabled network configurations");
- if (wpa_s->auto_select)
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Possible BSS match for enabled network configurations");
+ if (wpa_s->auto_select) {
interworking_reconnect(wpa_s);
- return;
+ return;
+ }
}
if (wpa_s->auto_network_select) {
- wpa_printf(MSG_DEBUG, "Interworking: Continue "
- "scanning after ANQP fetch");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Continue scanning after ANQP fetch");
wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
0);
return;
@@ -1660,10 +2491,22 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
"with matching credentials found");
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ }
+
+ if (selected) {
+ wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR,
+ MAC2STR(selected->bssid));
+ selected = pick_best_roaming_partner(wpa_s, selected,
+ selected_cred);
+ wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR
+ " (after best roaming partner selection)",
+ MAC2STR(selected->bssid));
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
+ MAC2STR(selected->bssid));
+ interworking_connect(wpa_s, selected, 0);
}
-
- if (selected)
- interworking_connect(wpa_s, selected);
}
@@ -1693,9 +2536,10 @@ interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
continue;
- wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
- "already fetched BSSID " MACSTR " and " MACSTR,
- MAC2STR(other->bssid), MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Share ANQP data with already fetched BSSID "
+ MACSTR " and " MACSTR,
+ MAC2STR(other->bssid), MAC2STR(bss->bssid));
other->anqp->users++;
return other->anqp;
}
@@ -1710,8 +2554,21 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
int found = 0;
const u8 *ie;
- if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
+ wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
+ "fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
+ wpa_s->fetch_anqp_in_progress,
+ wpa_s->fetch_osu_icon_in_progress);
+
+ if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress) {
+ wpa_printf(MSG_DEBUG, "Interworking: Stop next-ANQP-fetch");
return;
+ }
+
+ if (wpa_s->fetch_osu_icon_in_progress) {
+ wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
+ hs20_next_osu_icon(wpa_s);
+ return;
+ }
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!(bss->caps & IEEE80211_CAP_ESS))
@@ -1719,6 +2576,9 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
continue; /* AP does not support Interworking */
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
+ continue; /* Disallowed BSS */
if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
if (bss->anqp == NULL) {
@@ -1742,6 +2602,18 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
}
if (found == 0) {
+ if (wpa_s->fetch_osu_info) {
+ if (wpa_s->num_prov_found == 0 &&
+ wpa_s->fetch_osu_waiting_scan &&
+ wpa_s->num_osu_scans < 3) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again");
+ hs20_start_osu_scan(wpa_s);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "Interworking: Next icon");
+ hs20_osu_icon_fetch(wpa_s);
+ return;
+ }
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
wpa_s->fetch_anqp_in_progress = 0;
if (wpa_s->network_select)
@@ -1758,7 +2630,12 @@ void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
wpa_s->fetch_anqp_in_progress = 1;
- interworking_next_anqp_fetch(wpa_s);
+
+ /*
+ * Start actual ANQP operation from eloop call to make sure the loop
+ * does not end up using excessive recursion.
+ */
+ eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s, NULL);
}
@@ -1769,6 +2646,7 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
wpa_s->network_select = 0;
wpa_s->fetch_all_anqp = 1;
+ wpa_s->fetch_osu_info = 0;
interworking_start_fetch_anqp(wpa_s);
@@ -1786,9 +2664,10 @@ 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)
+ u16 info_ids[], size_t num_ids, u32 subtypes)
{
struct wpabuf *buf;
+ struct wpabuf *hs20_buf = NULL;
int ret = 0;
int freq;
struct wpa_bss *bss;
@@ -1803,32 +2682,44 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
if (freq <= 0)
return -1;
- wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
- MAC2STR(dst), (unsigned int) num_ids);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Query Request to " MACSTR " for %u id(s)",
+ MAC2STR(dst), (unsigned int) num_ids);
+
+#ifdef CONFIG_HS20
+ if (subtypes != 0) {
+ hs20_buf = wpabuf_alloc(100);
+ if (hs20_buf == NULL)
+ return -1;
+ hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
+ }
+#endif /* CONFIG_HS20 */
- buf = anqp_build_req(info_ids, num_ids, NULL);
+ buf = anqp_build_req(info_ids, num_ids, hs20_buf);
+ wpabuf_free(hs20_buf);
if (buf == NULL)
return -1;
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
- } else
- wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
- "%u", res);
+ } else {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Query started with dialog token %u", res);
+ }
- wpabuf_free(buf);
return ret;
}
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, u16 info_id,
+ struct wpa_bss *bss, const u8 *sa,
+ u16 info_id,
const u8 *data, size_t slen)
{
const u8 *pos = data;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
#ifdef CONFIG_HS20
u8 type;
@@ -1841,6 +2732,12 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
case ANQP_CAPABILITY_LIST:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" ANQP Capability list", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
+ pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->capability_list);
+ anqp->capability_list = wpabuf_alloc_copy(pos, slen);
+ }
break;
case ANQP_VENUE_NAME:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
@@ -1929,26 +2826,27 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
switch (type) {
case HS20_ANQP_OUI_TYPE:
- hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
- slen);
+ hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
+ pos, slen);
break;
default:
- wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
- "vendor type %u", type);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "HS20: Unsupported ANQP vendor type %u",
+ type);
break;
}
break;
#endif /* CONFIG_HS20 */
default:
- wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
- "vendor-specific ANQP OUI %06x",
- WPA_GET_BE24(pos));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Unsupported vendor-specific ANQP OUI %06x",
+ WPA_GET_BE24(pos));
return;
}
break;
default:
- wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
- "%u", info_id);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Unsupported ANQP Info ID %u", info_id);
break;
}
}
@@ -1964,62 +2862,108 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
const u8 *end;
u16 info_id;
u16 slen;
+ struct wpa_bss *bss = NULL, *tmp;
+ const char *anqp_result = "SUCCESS";
- if (result != GAS_QUERY_SUCCESS)
- return;
+ wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR
+ " dialog_token=%u result=%d status_code=%u",
+ MAC2STR(dst), dialog_token, result, status_code);
+ if (result != GAS_QUERY_SUCCESS) {
+ if (wpa_s->fetch_osu_icon_in_progress)
+ hs20_icon_fetch_failed(wpa_s);
+ anqp_result = "FAILURE";
+ goto out;
+ }
pos = wpabuf_head(adv_proto);
if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
- "Protocol in response");
- return;
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Unexpected Advertisement Protocol in response");
+ if (wpa_s->fetch_osu_icon_in_progress)
+ hs20_icon_fetch_failed(wpa_s);
+ anqp_result = "INVALID_FRAME";
+ goto out;
}
+ /*
+ * If possible, select the BSS entry based on which BSS entry was used
+ * for the request. This can help in cases where multiple BSS entries
+ * may exist for the same AP.
+ */
+ dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
+ if (tmp == wpa_s->interworking_gas_bss &&
+ os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
+ bss = tmp;
+ break;
+ }
+ }
+ if (bss == NULL)
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+
pos = wpabuf_head(resp);
end = pos + wpabuf_len(resp);
while (pos < end) {
- if (pos + 4 > end) {
- wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
- break;
+ unsigned int left = end - pos;
+
+ if (left < 4) {
+ wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Invalid element");
+ anqp_result = "INVALID_FRAME";
+ goto out_parse_done;
}
info_id = WPA_GET_LE16(pos);
pos += 2;
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end) {
- wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
- "for Info ID %u", info_id);
- break;
+ left -= 4;
+ if (left < slen) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Invalid element length for Info ID %u",
+ info_id);
+ anqp_result = "INVALID_FRAME";
+ goto out_parse_done;
}
- interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+ interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
slen);
pos += slen;
}
+
+out_parse_done:
+ hs20_notify_parse_done(wpa_s);
+out:
+ wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
+ MAC2STR(dst), anqp_result);
}
static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
- wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
- "ANQP fetch");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Scan results available - start ANQP fetch");
interworking_start_fetch_anqp(wpa_s);
}
-int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
+ int *freqs)
{
interworking_stop_fetch_anqp(wpa_s);
wpa_s->network_select = 1;
wpa_s->auto_network_select = 0;
wpa_s->auto_select = !!auto_select;
wpa_s->fetch_all_anqp = 0;
- wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
- "selection");
+ wpa_s->fetch_osu_info = 0;
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Start scan for network selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
+ wpa_s->normal_scans = 0;
wpa_s->scan_req = MANUAL_SCAN_REQ;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = freqs;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return 0;
@@ -2032,6 +2976,7 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
const struct wpabuf *resp, u16 status_code)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct wpabuf *n;
wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
" dialog_token=%d status_code=%d resp_len=%d",
@@ -2040,10 +2985,14 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
if (!resp)
return;
- wpabuf_free(wpa_s->last_gas_resp);
- wpa_s->last_gas_resp = wpabuf_dup(resp);
- if (wpa_s->last_gas_resp == NULL)
+ n = wpabuf_dup(resp);
+ if (n == NULL)
return;
+ wpabuf_free(wpa_s->prev_gas_resp);
+ wpa_s->prev_gas_resp = wpa_s->last_gas_resp;
+ os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN);
+ wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token;
+ wpa_s->last_gas_resp = n;
os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
wpa_s->last_gas_dialog_token = dialog_token;
}
@@ -2059,7 +3008,7 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
struct wpa_bss *bss;
int res;
size_t len;
- u8 query_resp_len_limit = 0, pame_bi = 0;
+ u8 query_resp_len_limit = 0;
freq = wpa_s->assoc_freq;
bss = wpa_bss_get_bssid(wpa_s, dst);
@@ -2068,8 +3017,8 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
if (freq <= 0)
return -1;
- wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
- MAC2STR(dst), freq);
+ wpa_msg(wpa_s, MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
+ MAC2STR(dst), freq);
wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
@@ -2083,8 +3032,7 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
/* Advertisement Protocol IE */
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
- wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
- (pame_bi ? 0x80 : 0));
+ wpabuf_put_u8(buf, query_resp_len_limit & 0x7f);
wpabuf_put_buf(buf, adv_proto);
/* GAS Query */
@@ -2096,12 +3044,12 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+ wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
} else
- wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
- "%u", res);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "GAS: Query started with dialog token %u", res);
- wpabuf_free(buf);
return ret;
}
diff --git a/contrib/wpa/wpa_supplicant/interworking.h b/contrib/wpa/wpa_supplicant/interworking.h
index 4a4af82..3743dc0 100644
--- a/contrib/wpa/wpa_supplicant/interworking.h
+++ b/contrib/wpa/wpa_supplicant/interworking.h
@@ -12,7 +12,7 @@
enum gas_query_result;
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
- u16 info_ids[], size_t num_ids);
+ u16 info_ids[], size_t num_ids, u32 subtypes);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -22,11 +22,15 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *query);
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
-int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
+ int *freqs);
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int only_add);
void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred,
struct wpabuf *domain_names);
+int domain_name_list_contains(struct wpabuf *domain_names,
+ const char *domain, int exact_match);
#endif /* INTERWORKING_H */
diff --git a/contrib/wpa/wpa_supplicant/main.c b/contrib/wpa/wpa_supplicant/main.c
index 19f7ce6..2282747 100644
--- a/contrib/wpa/wpa_supplicant/main.c
+++ b/contrib/wpa/wpa_supplicant/main.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / main() function for UNIX like OSes and MinGW
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,8 +14,7 @@
#include "common.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
-
-extern struct wpa_driver_ops *wpa_drivers[];
+#include "p2p_supplicant.h"
static void usage(void)
@@ -23,16 +22,32 @@ static void usage(void)
int i;
printf("%s\n\n%s\n"
"usage:\n"
- " wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
+ " wpa_supplicant [-BddhKLqq"
+#ifdef CONFIG_DEBUG_SYSLOG
+ "s"
+#endif /* CONFIG_DEBUG_SYSLOG */
+ "t"
+#ifdef CONFIG_DBUS
+ "u"
+#endif /* CONFIG_DBUS */
+ "vW] [-P<pid file>] "
"[-g<global ctrl>] \\\n"
+ " [-G<group>] \\\n"
" -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
"[-p<driver_param>] \\\n"
- " [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
- "\\\n"
+ " [-b<br_ifname>] [-e<entropy file>]"
+#ifdef CONFIG_DEBUG_FILE
+ " [-f<debug file>]"
+#endif /* CONFIG_DEBUG_FILE */
+ " \\\n"
" [-o<override driver>] [-O<override ctrl>] \\\n"
" [-N -i<ifname> -c<conf> [-C<ctrl>] "
"[-D<driver>] \\\n"
- " [-p<driver_param>] [-b<br_ifname>] ...]\n"
+#ifdef CONFIG_P2P
+ " [-m<P2P Device config file>] \\\n"
+#endif /* CONFIG_P2P */
+ " [-p<driver_param>] [-b<br_ifname>] [-I<config file>] "
+ "...]\n"
"\n"
"drivers:\n",
wpa_supplicant_version, wpa_supplicant_license);
@@ -50,6 +65,7 @@ static void usage(void)
" -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");
@@ -57,6 +73,7 @@ static void usage(void)
printf(" -f = log output to debug file instead of stdout\n");
#endif /* CONFIG_DEBUG_FILE */
printf(" -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");
@@ -78,11 +95,14 @@ static void usage(void)
#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");
printf("example:\n"
" wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
- wpa_drivers[i] ? wpa_drivers[i]->name : "wext");
+ wpa_drivers[0] ? wpa_drivers[0]->name : "nl80211");
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
@@ -155,7 +175,7 @@ int main(int argc, char *argv[])
for (;;) {
c = getopt(argc, argv,
- "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW");
+ "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
@@ -195,6 +215,9 @@ int main(int argc, char *argv[])
case 'g':
params.ctrl_interface = optarg;
break;
+ case 'G':
+ params.ctrl_interface_group = optarg;
+ break;
case 'h':
usage();
exitcode = 0;
@@ -202,6 +225,9 @@ int main(int argc, char *argv[])
case 'i':
iface->ifname = optarg;
break;
+ case 'I':
+ iface->confanother = optarg;
+ break;
case 'K':
params.wpa_debug_show_keys++;
break;
@@ -209,6 +235,11 @@ int main(int argc, char *argv[])
license();
exitcode = 0;
goto out;
+#ifdef CONFIG_P2P
+ case 'm':
+ iface->conf_p2p_dev = optarg;
+ break;
+#endif /* CONFIG_P2P */
case 'o':
params.override_driver = optarg;
break;
@@ -279,6 +310,8 @@ int main(int argc, char *argv[])
}
for (i = 0; exitcode == 0 && i < iface_count; i++) {
+ struct wpa_supplicant *wpa_s;
+
if ((ifaces[i].confname == NULL &&
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
@@ -289,8 +322,11 @@ int main(int argc, char *argv[])
exitcode = -1;
break;
}
- if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+ wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
+ if (wpa_s == NULL) {
exitcode = -1;
+ break;
+ }
}
if (exitcode == 0)
diff --git a/contrib/wpa/wpa_supplicant/main_none.c b/contrib/wpa/wpa_supplicant/main_none.c
index 010c30a3..4d3caf2 100644
--- a/contrib/wpa/wpa_supplicant/main_none.c
+++ b/contrib/wpa/wpa_supplicant/main_none.c
@@ -28,7 +28,7 @@ int main(int argc, char *argv[])
memset(&iface, 0, sizeof(iface));
/* TODO: set interface parameters */
- if (wpa_supplicant_add_iface(global, &iface) == NULL)
+ if (wpa_supplicant_add_iface(global, &iface, NULL) == NULL)
exitcode = -1;
if (exitcode == 0)
diff --git a/contrib/wpa/wpa_supplicant/mesh.c b/contrib/wpa/wpa_supplicant/mesh.c
new file mode 100644
index 0000000..33b4af3
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/mesh.c
@@ -0,0 +1,540 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc. 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 "utils/eloop.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "ap/sta_info.h"
+#include "ap/hostapd.h"
+#include "ap/ieee802_11.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "notify.h"
+#include "ap.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+#include "mesh.h"
+
+
+static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
+{
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_s->ifmsh = NULL;
+ wpa_s->current_ssid = NULL;
+ os_free(wpa_s->mesh_rsn);
+ wpa_s->mesh_rsn = NULL;
+ /* TODO: leave mesh (stop beacon). This will happen on link down
+ * anyway, so it's not urgent */
+}
+
+
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct hostapd_iface *ifmsh)
+{
+ if (!ifmsh)
+ return;
+
+ if (ifmsh->mconf) {
+ mesh_mpm_deinit(wpa_s, ifmsh);
+ if (ifmsh->mconf->ies) {
+ ifmsh->mconf->ies = NULL;
+ /* We cannot free this struct
+ * because wpa_authenticator on
+ * hostapd side is also using it
+ * for now just set to NULL and
+ * let hostapd code free it.
+ */
+ }
+ os_free(ifmsh->mconf);
+ ifmsh->mconf = NULL;
+ }
+
+ /* take care of shared data */
+ hostapd_interface_deinit(ifmsh);
+ hostapd_interface_free(ifmsh);
+}
+
+
+static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+{
+ struct mesh_conf *conf;
+
+ conf = os_zalloc(sizeof(struct mesh_conf));
+ if (!conf)
+ return NULL;
+
+ os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
+ conf->meshid_len = ssid->ssid_len;
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
+ conf->security |= MESH_CONF_SEC_AUTH |
+ MESH_CONF_SEC_AMPE;
+ else
+ conf->security |= MESH_CONF_SEC_NONE;
+
+ /* defaults */
+ conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
+ conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
+ conf->mesh_cc_id = 0;
+ conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
+ conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
+ conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
+ conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
+ conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
+ conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout;
+
+ return conf;
+}
+
+
+static void wpas_mesh_copy_groups(struct hostapd_data *bss,
+ struct wpa_supplicant *wpa_s)
+{
+ int num_groups;
+ size_t groups_size;
+
+ for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0;
+ num_groups++)
+ ;
+
+ groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]);
+ bss->conf->sae_groups = os_malloc(groups_size);
+ if (bss->conf->sae_groups)
+ os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups,
+ groups_size);
+}
+
+
+static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ 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;
+
+ if (!wpa_s->conf->user_mpm) {
+ /* not much for us to do here */
+ wpa_msg(wpa_s, MSG_WARNING,
+ "user_mpm is not enabled in configuration");
+ return 0;
+ }
+
+ wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
+ if (!ifmsh)
+ return -ENOMEM;
+
+ ifmsh->drv_flags = wpa_s->drv_flags;
+ ifmsh->num_bss = 1;
+ ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
+ sizeof(struct hostapd_data *));
+ if (!ifmsh->bss)
+ goto out_free;
+
+ ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
+ if (!bss)
+ goto out_free;
+
+ 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;
+ wpa_s->current_ssid = ssid;
+
+ /* setup an AP config for auth processing */
+ conf = hostapd_config_defaults();
+ if (!conf)
+ goto out_free;
+
+ bss->conf = *conf->bss;
+ bss->conf->start_disabled = 1;
+ bss->conf->mesh = MESH_ENABLED;
+ bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+ bss->iconf = conf;
+ ifmsh->conf = conf;
+
+ ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
+ os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
+
+ mconf = mesh_config_create(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);
+ }
+ if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
+ ssid->frequency);
+ goto out_free;
+ }
+
+ if (ssid->mesh_basic_rates == NULL) {
+ /*
+ * XXX: Hack! This is so an MPM which correctly sets the ERP
+ * mandatory rates as BSSBasicRateSet doesn't reject us. We
+ * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
+ * this is way easier. This also makes our BSSBasicRateSet
+ * 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));
+ if (!conf->basic_rates)
+ goto out_free;
+ os_memcpy(conf->basic_rates, basic_rates_erp,
+ sizeof(basic_rates_erp));
+ }
+ } else {
+ rate_len = 0;
+ while (1) {
+ if (ssid->mesh_basic_rates[rate_len] < 1)
+ break;
+ rate_len++;
+ }
+ conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
+ if (conf->basic_rates == NULL)
+ goto out_free;
+ os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
+ rate_len * sizeof(int));
+ 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;
+ }
+
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
+ return 0;
+out_free:
+ wpa_supplicant_mesh_deinit(wpa_s);
+ return -ENOMEM;
+}
+
+
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const u8 *ies, size_t ie_len)
+{
+ struct ieee802_11_elems elems;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ "new peer notification for " MACSTR, MAC2STR(addr));
+
+ if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
+ wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
+ MAC2STR(addr));
+ return;
+ }
+ wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
+}
+
+
+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie)
+{
+ /* EID + 0-length (wildcard) mesh-id */
+ size_t ielen = 2;
+
+ if (wpabuf_resize(extra_ie, ielen) == 0) {
+ wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(*extra_ie, 0);
+ }
+}
+
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_driver_mesh_join_params params;
+ int ret = 0;
+
+ if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
+ ret = -ENOENT;
+ 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;
+ if (ssid->beacon_int > 0)
+ 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;
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ 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;
+ } else {
+ params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+ params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ }
+ params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
+
+ if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
+ 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->ies;
+ params.ie_len = wpa_s->ifmsh->mconf->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);
+
+out:
+ return ret;
+}
+
+
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+ int ret = 0;
+
+ wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
+
+ /* Need to send peering close messages first */
+ wpa_supplicant_mesh_deinit(wpa_s);
+
+ ret = wpa_drv_leave_mesh(wpa_s);
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
+
+ wpa_drv_set_operstate(wpa_s, 1);
+
+ return ret;
+}
+
+
+static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
+{
+ struct ieee802_11_elems elems;
+ char *mesh_id, *pos = buf;
+ u8 *bss_basic_rate_set;
+ int bss_basic_rate_set_len, ret, i;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
+ return -1;
+
+ if (elems.mesh_id_len < 1)
+ return 0;
+
+ mesh_id = os_malloc(elems.mesh_id_len + 1);
+ if (mesh_id == NULL)
+ return -1;
+
+ os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
+ mesh_id[elems.mesh_id_len] = '\0';
+ ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
+ os_free(mesh_id);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ if (elems.mesh_config_len > 6) {
+ ret = os_snprintf(pos, end - pos,
+ "active_path_selection_protocol_id=0x%02x\n"
+ "active_path_selection_metric_id=0x%02x\n"
+ "congestion_control_mode_id=0x%02x\n"
+ "synchronization_method_id=0x%02x\n"
+ "authentication_protocol_id=0x%02x\n"
+ "mesh_formation_info=0x%02x\n"
+ "mesh_capability=0x%02x\n",
+ elems.mesh_config[0], elems.mesh_config[1],
+ elems.mesh_config[2], elems.mesh_config[3],
+ elems.mesh_config[4], elems.mesh_config[5],
+ elems.mesh_config[6]);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ bss_basic_rate_set = os_malloc(elems.supp_rates_len +
+ elems.ext_supp_rates_len);
+ if (bss_basic_rate_set == NULL)
+ return -1;
+
+ bss_basic_rate_set_len = 0;
+ for (i = 0; i < elems.supp_rates_len; i++) {
+ if (elems.supp_rates[i] & 0x80) {
+ bss_basic_rate_set[bss_basic_rate_set_len++] =
+ (elems.supp_rates[i] & 0x7f) * 5;
+ }
+ }
+ for (i = 0; i < elems.ext_supp_rates_len; i++) {
+ if (elems.ext_supp_rates[i] & 0x80) {
+ bss_basic_rate_set[bss_basic_rate_set_len++] =
+ (elems.ext_supp_rates[i] & 0x7f) * 5;
+ }
+ }
+ if (bss_basic_rate_set_len > 0) {
+ ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
+ bss_basic_rate_set[0]);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ for (i = 1; i < bss_basic_rate_set_len; i++) {
+ ret = os_snprintf(pos, end - pos, " %d",
+ bss_basic_rate_set[i]);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ os_free(bss_basic_rate_set);
+
+ return pos - buf;
+}
+
+
+int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+ char *end)
+{
+ return mesh_attr_text(ies, ies_len, buf, end);
+}
+
+
+static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
+ size_t len)
+{
+ char *ifname_ptr = wpa_s->ifname;
+ int res;
+
+ res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
+ wpa_s->mesh_if_idx);
+ if (os_snprintf_error(len, res) ||
+ (os_strlen(ifname) >= IFNAMSIZ &&
+ os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
+ /* Try to avoid going over the IFNAMSIZ length limit */
+ res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
+ if (os_snprintf_error(len, res))
+ return -1;
+ }
+ wpa_s->mesh_if_idx++;
+ return 0;
+}
+
+
+int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
+ size_t len)
+{
+ struct wpa_interface iface;
+ struct wpa_supplicant *mesh_wpa_s;
+ u8 addr[ETH_ALEN];
+
+ if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
+ return -1;
+
+ if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
+ NULL) < 0) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Failed to create new mesh interface");
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
+ MACSTR, ifname, MAC2STR(addr));
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.ifname = ifname;
+ iface.driver = wpa_s->driver->name;
+ iface.driver_param = wpa_s->conf->driver_param;
+ iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+
+ mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
+ 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);
+ return -1;
+ }
+ mesh_wpa_s->mesh_if_created = 1;
+ return 0;
+}
diff --git a/contrib/wpa/wpa_supplicant/mesh.h b/contrib/wpa/wpa_supplicant/mesh.h
new file mode 100644
index 0000000..3cb7f1b
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/mesh.h
@@ -0,0 +1,44 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_H
+#define MESH_H
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct hostapd_iface *ifmsh);
+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);
+
+#ifdef CONFIG_MESH
+
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const u8 *ies, size_t ie_len);
+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie);
+
+#else /* CONFIG_MESH */
+
+static inline void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s,
+ const u8 *addr,
+ const u8 *ies, size_t ie_len)
+{
+}
+
+static inline void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie)
+{
+}
+
+#endif /* CONFIG_MESH */
+
+#endif /* MESH_H */
diff --git a/contrib/wpa/wpa_supplicant/mesh_mpm.c b/contrib/wpa/wpa_supplicant/mesh_mpm.c
new file mode 100644
index 0000000..1d6f2be
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/mesh_mpm.c
@@ -0,0 +1,1059 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc. 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ieee802_11.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+
+struct mesh_peer_mgmt_ie {
+ const u8 *proto_id;
+ const u8 *llid;
+ const u8 *plid;
+ const u8 *reason;
+ const u8 *pmk;
+};
+
+static void plink_timer(void *eloop_ctx, void *user_data);
+
+
+enum plink_event {
+ PLINK_UNDEFINED,
+ OPN_ACPT,
+ OPN_RJCT,
+ OPN_IGNR,
+ CNF_ACPT,
+ CNF_RJCT,
+ CNF_IGNR,
+ CLS_ACPT,
+ CLS_IGNR
+};
+
+static const char * const mplstate[] = {
+ [PLINK_LISTEN] = "LISTEN",
+ [PLINK_OPEN_SENT] = "OPEN_SENT",
+ [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [PLINK_CNF_RCVD] = "CNF_RCVD",
+ [PLINK_ESTAB] = "ESTAB",
+ [PLINK_HOLDING] = "HOLDING",
+ [PLINK_BLOCKED] = "BLOCKED"
+};
+
+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"
+};
+
+
+static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
+ u8 action_field,
+ const u8 *ie, size_t len,
+ struct mesh_peer_mgmt_ie *mpm_ie)
+{
+ os_memset(mpm_ie, 0, sizeof(*mpm_ie));
+
+ /* remove optional PMK at end */
+ if (len >= 16) {
+ len -= 16;
+ mpm_ie->pmk = ie + len - 16;
+ }
+
+ if ((action_field == PLINK_OPEN && len != 4) ||
+ (action_field == PLINK_CONFIRM && len != 6) ||
+ (action_field == PLINK_CLOSE && len != 6 && len != 8)) {
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM: Invalid peer mgmt ie");
+ return -1;
+ }
+
+ /* required fields */
+ if (len < 4)
+ return -1;
+ mpm_ie->proto_id = ie;
+ mpm_ie->llid = ie + 2;
+ ie += 4;
+ len -= 4;
+
+ /* close reason is always present at end for close */
+ if (action_field == PLINK_CLOSE) {
+ if (len < 2)
+ return -1;
+ mpm_ie->reason = ie + len - 2;
+ len -= 2;
+ }
+
+ /* plid, present for confirm, and possibly close */
+ if (len)
+ mpm_ie->plid = ie;
+
+ return 0;
+}
+
+
+static int plink_free_count(struct hostapd_data *hapd)
+{
+ if (hapd->max_plinks > hapd->num_plinks)
+ return hapd->max_plinks - hapd->num_plinks;
+ return 0;
+}
+
+
+static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+ if (!elems->supp_rates) {
+ wpa_msg(wpa_s, MSG_ERROR, "no supported rates from " MACSTR,
+ MAC2STR(sta->addr));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (elems->supp_rates_len + elems->ext_supp_rates_len >
+ sizeof(sta->supported_rates)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Invalid supported rates element length " MACSTR
+ " %d+%d", MAC2STR(sta->addr), elems->supp_rates_len,
+ elems->ext_supp_rates_len);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->supported_rates_len = merge_byte_arrays(
+ sta->supported_rates, sizeof(sta->supported_rates),
+ elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+/* return true if elems from a neighbor match this MBSS */
+static Boolean matches_local(struct wpa_supplicant *wpa_s,
+ struct ieee802_11_elems *elems)
+{
+ struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
+
+ if (elems->mesh_config_len < 5)
+ return FALSE;
+
+ return (mconf->meshid_len == elems->mesh_id_len &&
+ os_memcmp(mconf->meshid, elems->mesh_id,
+ elems->mesh_id_len) == 0 &&
+ mconf->mesh_pp_id == elems->mesh_config[0] &&
+ mconf->mesh_pm_id == elems->mesh_config[1] &&
+ mconf->mesh_cc_id == elems->mesh_config[2] &&
+ mconf->mesh_sp_id == elems->mesh_config[3] &&
+ mconf->mesh_auth_id == elems->mesh_config[4]);
+}
+
+
+/* check if local link id is already used with another peer */
+static Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
+{
+ struct sta_info *sta;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->my_lid == llid)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* generate an llid for a link and set to initial state */
+static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ u16 llid;
+
+ do {
+ if (os_get_random((u8 *) &llid, sizeof(llid)) < 0)
+ continue;
+ } while (!llid || llid_in_use(wpa_s, llid));
+
+ sta->my_lid = llid;
+ sta->peer_lid = 0;
+
+ /*
+ * We do not use wpa_mesh_set_plink_state() here because there is no
+ * entry in kernel yet.
+ */
+ sta->plink_state = PLINK_LISTEN;
+}
+
+
+static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum plink_action_field type,
+ u16 close_reason)
+{
+ struct wpabuf *buf;
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ 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;
+ int ampe = conf->security & MESH_CONF_SEC_AMPE;
+ size_t buf_len;
+
+ if (!sta)
+ return;
+
+ buf_len = 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 + 96 + /* AMPE */
+ 2 + 16; /* MIC */
+#ifdef CONFIG_IEEE80211N
+ if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
+ buf_len += 2 + 26 + /* HT capabilities */
+ 2 + 22; /* HT operation */
+ }
+#endif /* CONFIG_IEEE80211N */
+ buf = wpabuf_alloc(buf_len);
+ if (!buf)
+ return;
+
+ cat = wpabuf_mhead_u8(buf);
+ wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
+ wpabuf_put_u8(buf, type);
+
+ if (type != PLINK_CLOSE) {
+ u8 info;
+
+ /* capability info */
+ wpabuf_put_le16(buf, ampe ? IEEE80211_CAP_PRIVACY : 0);
+
+ /* aid */
+ if (type == PLINK_CONFIRM)
+ wpabuf_put_le16(buf, sta->peer_lid);
+
+ /* IE: supp + ext. supp rates */
+ pos = hostapd_eid_supp_rates(bss, supp_rates);
+ pos = hostapd_eid_ext_supp_rates(bss, pos);
+ wpabuf_put_data(buf, supp_rates, pos - supp_rates);
+
+ /* IE: Mesh ID */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(buf, conf->meshid_len);
+ wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+
+ /* IE: mesh conf */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_CONFIG);
+ wpabuf_put_u8(buf, 7);
+ wpabuf_put_u8(buf, conf->mesh_pp_id);
+ wpabuf_put_u8(buf, conf->mesh_pm_id);
+ wpabuf_put_u8(buf, conf->mesh_cc_id);
+ wpabuf_put_u8(buf, conf->mesh_sp_id);
+ wpabuf_put_u8(buf, conf->mesh_auth_id);
+ info = (bss->num_plinks > 63 ? 63 : bss->num_plinks) << 1;
+ /* 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);
+ } else { /* Peer closing frame */
+ /* IE: Mesh ID */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(buf, conf->meshid_len);
+ wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+ }
+
+ /* IE: Mesh Peering Management element */
+ ie_len = 4;
+ if (ampe)
+ ie_len += PMKID_LEN;
+ switch (type) {
+ case PLINK_OPEN:
+ break;
+ case PLINK_CONFIRM:
+ ie_len += 2;
+ add_plid = 1;
+ break;
+ case PLINK_CLOSE:
+ ie_len += 2;
+ add_plid = 1;
+ ie_len += 2; /* reason code */
+ break;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_PEER_MGMT);
+ wpabuf_put_u8(buf, ie_len);
+ /* peering protocol */
+ if (ampe)
+ wpabuf_put_le16(buf, 1);
+ else
+ wpabuf_put_le16(buf, 0);
+ wpabuf_put_le16(buf, sta->my_lid);
+ if (add_plid)
+ wpabuf_put_le16(buf, sta->peer_lid);
+ if (type == PLINK_CLOSE)
+ wpabuf_put_le16(buf, close_reason);
+ if (ampe) {
+ if (sta->sae == NULL) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: no SAE session");
+ goto fail;
+ }
+ mesh_rsn_get_pmkid(wpa_s->mesh_rsn, sta,
+ wpabuf_put(buf, PMKID_LEN));
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
+ 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 */
+
+ if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Mesh MPM: failed to add AMPE and MIC IE");
+ goto fail;
+ }
+
+ 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);
+ if (ret < 0)
+ wpa_msg(wpa_s, MSG_INFO,
+ "Mesh MPM: failed to send peering frame");
+
+fail:
+ wpabuf_free(buf);
+}
+
+
+/* configure peering state in ours and driver's station entry */
+void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum mesh_plink_state state)
+{
+ struct hostapd_sta_add_params params;
+ int ret;
+
+ sta->plink_state = state;
+
+ os_memset(&params, 0, sizeof(params));
+ params.addr = sta->addr;
+ params.plink_state = state;
+ 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
+ ": %d", MAC2STR(sta->addr), ret);
+ }
+}
+
+
+static void mesh_mpm_fsm_restart(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+
+ ap_free_sta(hapd, sta);
+}
+
+
+static void plink_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct sta_info *sta = user_data;
+ u16 reason = 0;
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+
+ switch (sta->plink_state) {
+ case PLINK_OPEN_RCVD:
+ case PLINK_OPEN_SENT:
+ /* retry timer */
+ if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
+ eloop_register_timeout(
+ conf->dot11MeshRetryTimeout / 1000,
+ (conf->dot11MeshRetryTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+ sta->mpm_retries++;
+ break;
+ }
+ reason = WLAN_REASON_MESH_MAX_RETRIES;
+ /* fall through on else */
+
+ case PLINK_CNF_RCVD:
+ /* confirm timer */
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ eloop_register_timeout(conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ case PLINK_HOLDING:
+ /* holding timer */
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* initiate peering with station */
+static void
+mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum mesh_plink_state next_state)
+{
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ eloop_register_timeout(conf->dot11MeshRetryTimeout / 1000,
+ (conf->dot11MeshRetryTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+ wpa_mesh_set_plink_state(wpa_s, sta, next_state);
+}
+
+
+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;
+
+ if (sta) {
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
+ MAC2STR(sta->addr));
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
+{
+ struct hostapd_data *hapd = ifmsh->bss[0];
+
+ /* notify peers we're leaving */
+ ap_for_each_sta(hapd, mesh_mpm_plink_close, wpa_s);
+
+ hapd->num_plinks = 0;
+ hostapd_free_stas(hapd);
+}
+
+
+/* for mesh_rsn to indicate this peer has completed authentication, and we're
+ * ready to start AMPE */
+void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct hostapd_sta_add_params params;
+ struct sta_info *sta;
+ int ret;
+
+ sta = ap_get_sta(data, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_DEBUG, "no such mesh peer");
+ return;
+ }
+
+ /* TODO: Should do nothing if this STA is already authenticated, but
+ * the AP code already sets this flag. */
+ sta->flags |= WLAN_STA_AUTH;
+
+ mesh_rsn_init_ampe_sta(wpa_s, sta);
+
+ os_memset(&params, 0, sizeof(params));
+ params.addr = sta->addr;
+ params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED;
+ params.set = 1;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR,
+ MAC2STR(sta->addr));
+ ret = wpa_drv_sta_add(wpa_s, &params);
+ if (ret) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Driver failed to set " MACSTR ": %d",
+ MAC2STR(sta->addr), ret);
+ }
+
+ if (!sta->my_lid)
+ mesh_mpm_init_link(wpa_s, sta);
+
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+}
+
+/*
+ * Initialize a sta_info structure for a peer and upload it into the driver
+ * in preparation for beginning authentication or peering. This is done when a
+ * Beacon (secure or open mesh) or a peering open frame (for open mesh) is
+ * received from the peer for the first time.
+ */
+static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
+ const u8 *addr,
+ struct ieee802_11_elems *elems)
+{
+ struct hostapd_sta_add_params params;
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct sta_info *sta;
+ int ret;
+
+ sta = ap_get_sta(data, addr);
+ if (!sta) {
+ sta = ap_sta_add(data, addr);
+ if (!sta)
+ return NULL;
+ }
+
+ /* initialize sta */
+ if (copy_supp_rates(wpa_s, sta, elems)) {
+ ap_free_sta(data, sta);
+ return NULL;
+ }
+
+ mesh_mpm_init_link(wpa_s, sta);
+
+#ifdef CONFIG_IEEE80211N
+ copy_sta_ht_capab(data, sta, elems->ht_capabilities,
+ elems->ht_capabilities_len);
+ update_ht_state(data, sta);
+#endif /* CONFIG_IEEE80211N */
+
+ /* 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.listen_interval = 100;
+ params.ht_capabilities = sta->ht_capabilities;
+ params.flags |= WPA_STA_WMM;
+ params.flags_mask |= WPA_STA_AUTHENTICATED;
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ params.flags |= WPA_STA_AUTHORIZED;
+ params.flags |= WPA_STA_AUTHENTICATED;
+ } else {
+ sta->flags |= WLAN_STA_MFP;
+ params.flags |= WPA_STA_MFP;
+ }
+
+ ret = wpa_drv_sta_add(wpa_s, &params);
+ if (ret) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Driver failed to insert " MACSTR ": %d",
+ MAC2STR(addr), ret);
+ ap_free_sta(data, sta);
+ return NULL;
+ }
+
+ return sta;
+}
+
+
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ struct ieee802_11_elems *elems)
+{
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct sta_info *sta;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ sta = mesh_mpm_add_peer(wpa_s, addr, elems);
+ if (!sta)
+ return;
+
+ if (ssid && ssid->no_auto_peer) {
+ 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) {
+ struct os_reltime age;
+ const struct ieee80211_mgmt *mgmt;
+ struct hostapd_frame_info fi;
+
+ mgmt = wpabuf_head(data->mesh_pending_auth);
+ os_reltime_age(&data->mesh_pending_auth_time, &age);
+ if (age.sec < 2 &&
+ os_memcmp(mgmt->sa, addr, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "mesh: Process pending Authentication frame from %u.%06u seconds ago",
+ (unsigned int) age.sec,
+ (unsigned int) age.usec);
+ os_memset(&fi, 0, sizeof(fi));
+ ieee802_11_mgmt(
+ data,
+ wpabuf_head(data->mesh_pending_auth),
+ wpabuf_len(data->mesh_pending_auth),
+ &fi);
+ }
+ wpabuf_free(data->mesh_pending_auth);
+ data->mesh_pending_auth = NULL;
+ }
+ return;
+ }
+
+ if (conf->security == MESH_CONF_SEC_NONE)
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ else
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+}
+
+
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt)
+{
+ struct hostapd_frame_info fi;
+
+ os_memset(&fi, 0, sizeof(fi));
+ fi.datarate = rx_mgmt->datarate;
+ fi.ssi_signal = rx_mgmt->ssi_signal;
+ ieee802_11_mgmt(wpa_s->ifmsh->bss[0], rx_mgmt->frame,
+ rx_mgmt->frame_len, &fi);
+}
+
+
+static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ u8 seq[6] = {};
+
+ wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established",
+ 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_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
+ hapd->num_plinks++;
+
+ sta->flags |= WLAN_STA_ASSOC;
+
+ 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));
+}
+
+
+static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum plink_event event)
+{
+ 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:
+ 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_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
+ 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_OPEN_SENT:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ /* retry timer is left untouched */
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_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_register_timeout(
+ conf->dot11MeshConfirmTimeout / 1000,
+ (conf->dot11MeshConfirmTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_OPEN_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CONFIRM, 0);
+ break;
+ case CNF_ACPT:
+ if (conf->security & MESH_CONF_SEC_AMPE)
+ mesh_rsn_derive_mtk(wpa_s, sta);
+ mesh_mpm_plink_estab(wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_CNF_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_plink_estab(wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CONFIRM, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_ESTAB:
+ switch (event) {
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+
+ wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR
+ " closed with reason %d",
+ MAC2STR(sta->addr), reason);
+
+ wpa_msg_ctrl(wpa_s, MSG_INFO,
+ MESH_PEER_DISCONNECTED MACSTR,
+ MAC2STR(sta->addr));
+
+ hapd->num_plinks--;
+
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CONFIRM, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_HOLDING:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ case OPN_ACPT:
+ case CNF_ACPT:
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = sta->mpm_close_reason;
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Unsupported MPM event %s for state %s",
+ mplevent[event], mplstate[sta->plink_state]);
+ break;
+ }
+}
+
+
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ u8 action_field;
+ 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;
+ 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;
+
+ if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
+ return;
+
+ action_field = mgmt->u.action.u.slf_prot_action.action;
+ if (action_field != PLINK_OPEN &&
+ action_field != PLINK_CONFIRM &&
+ action_field != PLINK_CLOSE)
+ return;
+
+ ies = mgmt->u.action.u.slf_prot_action.variable;
+ ie_len = (const u8 *) mgmt + len -
+ mgmt->u.action.u.slf_prot_action.variable;
+
+ /* at least expect mesh id and peering mgmt */
+ if (ie_len < 2 + 2) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: Ignore too short action frame %u ie_len %u",
+ action_field, (unsigned int) ie_len);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "MPM: Received PLINK action %u", action_field);
+
+ if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) {
+ wpa_printf(MSG_DEBUG, "MPM: Capability 0x%x",
+ WPA_GET_LE16(ies));
+ ies += 2; /* capability */
+ ie_len -= 2;
+ }
+ if (action_field == PLINK_CONFIRM) {
+ wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+ ies += 2; /* aid */
+ ie_len -= 2;
+ }
+
+ /* check for mesh peering, mesh id and mesh config IEs */
+ if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "MPM: Failed to parse PLINK IEs");
+ return;
+ }
+ if (!elems.peer_mgmt) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: No Mesh Peering Management element");
+ return;
+ }
+ if (action_field != PLINK_CLOSE) {
+ if (!elems.mesh_id || !elems.mesh_config) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: No Mesh ID or Mesh Configuration element");
+ return;
+ }
+
+ if (!matches_local(wpa_s, &elems)) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: Mesh ID or Mesh Configuration element do not match local MBSS");
+ return;
+ }
+ }
+
+ ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field,
+ elems.peer_mgmt,
+ elems.peer_mgmt_len,
+ &peer_mgmt_ie);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "MPM: Mesh parsing rejected frame");
+ return;
+ }
+
+ /* the sender's llid is our plid and vice-versa */
+ plid = WPA_GET_LE16(peer_mgmt_ie.llid);
+ if (peer_mgmt_ie.plid)
+ llid = WPA_GET_LE16(peer_mgmt_ie.plid);
+ wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+
+ /*
+ * If this is an open frame from an unknown STA, and this is an
+ * open mesh, then go ahead and add the peer before proceeding.
+ */
+ if (!sta && action_field == PLINK_OPEN &&
+ !(mconf->security & MESH_CONF_SEC_AMPE))
+ sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
+
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "MPM: No STA entry for peer");
+ return;
+ }
+
+#ifdef CONFIG_SAE
+ /* peer is in sae_accepted? */
+ if (sta->sae && sta->sae->state != SAE_ACCEPTED) {
+ wpa_printf(MSG_DEBUG, "MPM: SAE not yet accepted for peer");
+ return;
+ }
+#endif /* CONFIG_SAE */
+
+ 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 (sta->plink_state == PLINK_BLOCKED) {
+ wpa_printf(MSG_DEBUG, "MPM: PLINK_BLOCKED");
+ return;
+ }
+
+ /* Now we will figure out the appropriate event... */
+ switch (action_field) {
+ case PLINK_OPEN:
+ if (plink_free_count(hapd) == 0) {
+ event = OPN_IGNR;
+ 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;
+ } else {
+ sta->peer_lid = plid;
+ event = OPN_ACPT;
+ }
+ break;
+ case PLINK_CONFIRM:
+ if (plink_free_count(hapd) == 0) {
+ event = CNF_IGNR;
+ 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;
+ } else {
+ if (!sta->peer_lid)
+ sta->peer_lid = plid;
+ event = CNF_ACPT;
+ }
+ break;
+ case PLINK_CLOSE:
+ if (sta->plink_state == PLINK_ESTAB)
+ /* Do not check for llid or plid. This does not
+ * follow the standard but since multiple plinks
+ * per cand are not supported, it is necessary in
+ * order to avoid a livelock when MP A sees an
+ * establish peer link to MP B but MP B does not
+ * see it. This can be caused by a timeout in
+ * B's peer link establishment or B being
+ * 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
+ event = CLS_ACPT;
+ break;
+ default:
+ /*
+ * This cannot be hit due to the action_field check above, but
+ * compilers may not be able to figure that out and can warn
+ * about uninitialized event below.
+ */
+ return;
+ }
+ mesh_mpm_fsm(wpa_s, sta, event);
+}
+
+
+/* called by ap_free_sta */
+void mesh_mpm_free_sta(struct sta_info *sta)
+{
+ 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
new file mode 100644
index 0000000..7ebaef0
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/mesh_mpm.h
@@ -0,0 +1,43 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_MPM_H
+#define MESH_MPM_H
+
+/* notify MPM of new mesh peer to be inserted in MPM and driver */
+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 wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum mesh_plink_state state);
+
+#ifdef CONFIG_MESH
+
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len);
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt);
+
+#else /* CONFIG_MESH */
+
+static inline void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+}
+
+static inline void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s,
+ struct rx_mgmt *rx_mgmt)
+{
+}
+
+#endif /* CONFIG_MESH */
+
+#endif /* MESH_MPM_H */
diff --git a/contrib/wpa/wpa_supplicant/mesh_rsn.c b/contrib/wpa/wpa_supplicant/mesh_rsn.c
new file mode 100644
index 0000000..936002d
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/mesh_rsn.c
@@ -0,0 +1,574 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc. 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 "utils/eloop.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "rsn_supp/wpa.h"
+#include "ap/hostapd.h"
+#include "ap/wpa_auth.h"
+#include "ap/sta_info.h"
+#include "ap/ieee802_11.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wpas_glue.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+
+#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;
+
+ if (sta->sae->state != SAE_ACCEPTED) {
+ wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
+ " (attempt %d) ",
+ MAC2STR(sta->addr), sta->sae_auth_retry);
+ wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_FAILURE "addr=" MACSTR,
+ MAC2STR(sta->addr));
+ if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ } else {
+ if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
+ ap_free_sta(wpa_s->ifmsh->bss[0], 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);
+ }
+ sta->sae_auth_retry++;
+ }
+}
+
+
+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 const u8 *auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *p2p_dev_addr, const u8 *prev_psk)
+{
+ 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);
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+ __func__, MAC2STR(addr), prev_psk);
+
+ if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+ if (!sta->sae || prev_psk)
+ return NULL;
+ return sta->sae->pmk;
+ }
+
+ return NULL;
+}
+
+
+static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+ const u8 *addr, int idx, u8 *key, size_t key_len)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+ u8 seq[6];
+
+ os_memset(seq, 0, sizeof(seq));
+
+ if (addr) {
+ wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
+ " key_idx=%d)",
+ __func__, alg, MAC2STR(addr), idx);
+ } else {
+ wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
+ __func__, alg, idx);
+ }
+ wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
+
+ return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
+ 1, seq, 6, key, key_len);
+}
+
+
+static int auth_start_ampe(void *ctx, const u8 *addr)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+
+ if (mesh_rsn->wpa_s->current_ssid->mode != WPAS_MODE_MESH)
+ return -1;
+
+ hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ eloop_cancel_timeout(mesh_auth_timer, mesh_rsn->wpa_s, sta);
+
+ mesh_mpm_auth_peer(mesh_rsn->wpa_s, addr);
+ return 0;
+}
+
+
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+{
+ struct wpa_auth_config conf;
+ struct wpa_auth_callbacks cb;
+ u8 seq[6] = {};
+
+ 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_SAE;
+ conf.wpa_pairwise = WPA_CIPHER_CCMP;
+ conf.rsn_pairwise = WPA_CIPHER_CCMP;
+ conf.wpa_group = WPA_CIPHER_CCMP;
+ 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);
+ 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);
+ return -1;
+ }
+
+ /* group mgmt */
+ wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
+ seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+
+ /* 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));
+
+ return 0;
+}
+
+
+static void mesh_rsn_deinit(struct mesh_rsn *rsn)
+{
+ os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+ wpa_deinit(rsn->auth);
+}
+
+
+struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+ struct mesh_conf *conf)
+{
+ struct mesh_rsn *mesh_rsn;
+ struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
+ const u8 *ie;
+ size_t ie_len;
+
+ mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
+ if (mesh_rsn == NULL)
+ return NULL;
+ mesh_rsn->wpa_s = wpa_s;
+
+ if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+ mesh_rsn_deinit(mesh_rsn);
+ return NULL;
+ }
+
+ bss->wpa_auth = mesh_rsn->auth;
+
+ ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
+ conf->ies = (u8 *) ie;
+ conf->ie_len = ie_len;
+
+ wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+
+ return mesh_rsn;
+}
+
+
+static int index_within_array(const int *array, int idx)
+{
+ int i;
+
+ for (i = 0; i < idx; i++) {
+ if (array[i] == -1)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int mesh_rsn_sae_group(struct wpa_supplicant *wpa_s,
+ struct sae_data *sae)
+{
+ int *groups = wpa_s->ifmsh->bss[0]->conf->sae_groups;
+
+ /* Configuration may have changed, so validate current index */
+ if (!index_within_array(groups, wpa_s->mesh_rsn->sae_group_index))
+ return -1;
+
+ for (;;) {
+ int group = groups[wpa_s->mesh_rsn->sae_group_index];
+
+ if (group <= 0)
+ break;
+ if (sae_set_group(sae, group) == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+ sae->group);
+ return 0;
+ }
+ wpa_s->mesh_rsn->sae_group_index++;
+ }
+
+ return -1;
+}
+
+
+static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct sta_info *sta)
+{
+ if (ssid->passphrase == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
+ return -1;
+ }
+
+ if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group");
+ return -1;
+ }
+
+ return sae_prepare_commit(wpa_s->own_addr, sta->addr,
+ (u8 *) ssid->passphrase,
+ os_strlen(ssid->passphrase), sta->sae);
+}
+
+
+/* initiate new SAE authentication with sta */
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ unsigned int rnd;
+ int ret;
+
+ if (!ssid) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "AUTH: No current_ssid known to initiate new SAE");
+ return -1;
+ }
+
+ if (!sta->sae) {
+ sta->sae = os_zalloc(sizeof(*sta->sae));
+ if (sta->sae == NULL)
+ return -1;
+ }
+
+ if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
+ return -1;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "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;
+
+ eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta);
+ rnd = rand() % MESH_AUTH_TIMEOUT;
+ eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer,
+ wpa_s, sta);
+ return 0;
+}
+
+
+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)));
+}
+
+
+static void
+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];
+
+ /* SAE */
+ RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+
+ if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+ addr1 = myaddr;
+ addr2 = peer;
+ }
+ os_memcpy(context + 4, addr1, ETH_ALEN);
+ os_memcpy(context + 10, addr2, ETH_ALEN);
+
+ sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
+ context, sizeof(context), sta->aek, sizeof(sta->aek));
+}
+
+
+/* derive mesh temporal key from pmk */
+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];
+
+ ptr = context;
+ if (os_memcmp(sta->my_nonce, sta->peer_nonce, 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;
+
+ if (sta->my_lid < sta->peer_lid) {
+ min_lid = host_to_le16(sta->my_lid);
+ max_lid = host_to_le16(sta->peer_lid);
+ } else {
+ min_lid = host_to_le16(sta->peer_lid);
+ max_lid = host_to_le16(sta->my_lid);
+ }
+ 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;
+
+ if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+ min = myaddr;
+ max = peer;
+ } else {
+ min = peer;
+ max = myaddr;
+ }
+ os_memcpy(ptr, min, ETH_ALEN);
+ os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+
+ sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+ "Temporal Key Derivation", context, sizeof(context),
+ sta->mtk, sizeof(sta->mtk));
+ 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) {
+ wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
+ /* TODO: How to handle this more cleanly? */
+ }
+ os_memset(sta->peer_nonce, 0, 32);
+ mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
+}
+
+
+/* insert AMPE and encrypted MIC at @ie.
+ * @mesh_rsn: mesh RSN context
+ * @sta: STA we're sending to
+ * @cat: pointer to category code in frame header.
+ * @buf: wpabuf to add encrypted AMPE and MIC to.
+ * */
+int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
+ const u8 *cat, struct wpabuf *buf)
+{
+ struct ieee80211_ampe_ie *ampe;
+ u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
+ u8 *ampe_ie = NULL, *mic_ie = NULL, *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;
+
+ if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+ wpa_printf(MSG_ERROR, "protect frame: buffer too small");
+ return -EINVAL;
+ }
+
+ ampe_ie = os_zalloc(2 + sizeof(*ampe));
+ 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 = (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 */
+ /* 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);
+
+ /* IE: MIC */
+ mic_ie[0] = WLAN_EID_MIC;
+ mic_ie[1] = AES_BLOCK_SIZE;
+ wpabuf_put_data(buf, mic_ie, 2);
+ /* MIC field is output ciphertext */
+
+ /* encrypt after MIC */
+ mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
+ AES_BLOCK_SIZE);
+
+ if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 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;
+}
+
+
+int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *start, size_t elems_len)
+{
+ int ret = 0;
+ struct ieee80211_ampe_ie *ampe;
+ u8 null_nonce[32] = {};
+ u8 ampe_eid;
+ u8 ampe_ie_len;
+ u8 *ampe_buf, *crypt = NULL;
+ 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 };
+
+ if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
+ return -1;
+ }
+
+ ampe_buf = (u8 *) elems->mic + elems->mic_len;
+ if ((int) elems_len < ampe_buf - start)
+ return -1;
+
+ crypt_len = elems_len - (elems->mic - start);
+ if (crypt_len < 2) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
+ return -1;
+ }
+
+ /* crypt is modified by siv_decrypt */
+ crypt = os_zalloc(crypt_len);
+ if (!crypt) {
+ wpa_printf(MSG_ERROR, "Mesh RSN: out of memory");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ os_memcpy(crypt, elems->mic, crypt_len);
+
+ if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
+ aad, aad_len, ampe_buf)) {
+ wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
+ ret = -1;
+ goto free;
+ }
+
+ ampe_eid = *ampe_buf++;
+ ampe_ie_len = *ampe_buf++;
+
+ if (ampe_eid != WLAN_EID_AMPE ||
+ ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
+ ret = -1;
+ goto free;
+ }
+
+ 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) {
+ 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 */
+free:
+ os_free(crypt);
+ return ret;
+}
diff --git a/contrib/wpa/wpa_supplicant/mesh_rsn.h b/contrib/wpa/wpa_supplicant/mesh_rsn.h
new file mode 100644
index 0000000..b1471b2
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/mesh_rsn.h
@@ -0,0 +1,36 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_RSN_H
+#define MESH_RSN_H
+
+struct mesh_rsn {
+ struct wpa_supplicant *wpa_s;
+ struct wpa_authenticator *auth;
+ u8 mgtk[16];
+#ifdef CONFIG_SAE
+ struct wpabuf *sae_token;
+ int sae_group_index;
+#endif /* CONFIG_SAE */
+};
+
+struct mesh_rsn * mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+ struct mesh_conf *conf);
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid);
+void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta);
+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 *start, size_t elems_len);
+void mesh_auth_timer(void *eloop_ctx, void *user_data);
+
+#endif /* MESH_RSN_H */
diff --git a/contrib/wpa/wpa_supplicant/notify.c b/contrib/wpa/wpa_supplicant/notify.c
index 9251f62..ea7dbdb1 100644
--- a/contrib/wpa/wpa_supplicant/notify.c
+++ b/contrib/wpa/wpa_supplicant/notify.c
@@ -48,6 +48,9 @@ void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
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;
@@ -60,6 +63,9 @@ int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
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);
@@ -72,6 +78,9 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
enum wpa_states new_state,
enum wpa_states old_state)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
/* notify the old DBus API */
wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
old_state);
@@ -79,50 +88,67 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
/* notify the new DBus API */
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
-#ifdef CONFIG_P2P
if (new_state == WPA_COMPLETED)
wpas_p2p_notif_connected(wpa_s);
else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
wpas_p2p_notif_disconnected(wpa_s);
-#endif /* CONFIG_P2P */
sme_state_changed(wpa_s);
#ifdef ANDROID
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
- "id=%d state=%d BSSID=" MACSTR,
+ "id=%d state=%d BSSID=" MACSTR " SSID=%s",
wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
- new_state, MAC2STR(wpa_s->pending_bssid));
+ new_state,
+ MAC2STR(wpa_s->bssid),
+ wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
+ wpa_ssid_txt(wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len) : "");
#endif /* ANDROID */
}
void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
}
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
}
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN);
}
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS);
}
void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_AUTH_MODE);
}
@@ -130,6 +156,9 @@ void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_network_enabled_changed(wpa_s, ssid);
}
@@ -137,6 +166,9 @@ void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_network_selected(wpa_s, ssid->id);
}
@@ -146,12 +178,18 @@ void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
enum wpa_ctrl_req_type rtype,
const char *default_txt)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
}
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);
@@ -162,12 +200,18 @@ void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_scan_done(wpa_s, success);
}
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);
@@ -178,6 +222,9 @@ void wpas_notify_scan_results(struct wpa_supplicant *wpa_s)
void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
const struct wps_credential *cred)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
/* notify the old DBus API */
wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
@@ -190,6 +237,9 @@ void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
struct wps_event_m2d *m2d)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_m2d(wpa_s, m2d);
#endif /* CONFIG_WPS */
@@ -199,6 +249,9 @@ void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_fail(wpa_s, fail);
#endif /* CONFIG_WPS */
@@ -207,6 +260,9 @@ void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_success(wpa_s);
#endif /* CONFIG_WPS */
@@ -216,13 +272,16 @@ void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
/*
* Networks objects created during any P2P activities should not be
* exposed out. They might/will confuse certain non-P2P aware
* applications since these network objects won't behave like
* regular ones.
*/
- if (wpa_s->global->p2p_group_formation != wpa_s)
+ if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
wpas_dbus_register_network(wpa_s, ssid);
}
@@ -248,19 +307,28 @@ void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ if (wpa_s->next_ssid == ssid)
+ wpa_s->next_ssid = NULL;
if (wpa_s->wpa)
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- if (wpa_s->global->p2p_group_formation != wpa_s)
+ if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
wpas_dbus_unregister_network(wpa_s, ssid->id);
-#ifdef CONFIG_P2P
+ if (network_is_persistent_group(ssid))
+ wpas_notify_persistent_group_removed(wpa_s, ssid);
+
wpas_p2p_network_removed(wpa_s, ssid);
-#endif /* CONFIG_P2P */
}
void wpas_notify_bss_added(struct wpa_supplicant *wpa_s,
u8 bssid[], unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_register_bss(wpa_s, bssid, id);
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR,
id, MAC2STR(bssid));
@@ -270,6 +338,9 @@ void wpas_notify_bss_added(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s,
u8 bssid[], unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_unregister_bss(wpa_s, bssid, id);
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_REMOVED "%u " MACSTR,
id, MAC2STR(bssid));
@@ -279,6 +350,9 @@ void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_FREQ, id);
}
@@ -286,6 +360,9 @@ void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_SIGNAL,
id);
}
@@ -294,6 +371,9 @@ void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_PRIVACY,
id);
}
@@ -302,6 +382,9 @@ void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_MODE, id);
}
@@ -309,6 +392,9 @@ void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPA, id);
}
@@ -316,6 +402,9 @@ void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RSN, id);
}
@@ -323,6 +412,9 @@ void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
#endif /* CONFIG_WPS */
@@ -332,6 +424,9 @@ void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_IES, id);
}
@@ -339,18 +434,36 @@ void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RATES, id);
}
+void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_AGE, id);
+}
+
+
void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_blob_added(wpa_s, name);
}
void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_blob_removed(wpa_s, name);
}
@@ -436,9 +549,9 @@ void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid,
const char *role)
{
- wpas_dbus_unregister_p2p_group(wpa_s, ssid);
-
wpas_dbus_signal_p2p_group_removed(wpa_s, role);
+
+ wpas_dbus_unregister_p2p_group(wpa_s, ssid);
}
@@ -535,37 +648,33 @@ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
wpas_p2p_notify_ap_sta_authorized(wpa_s, p2p_dev_addr);
/*
- * Register a group member object corresponding to this peer and
- * emit a PeerJoined signal. This will check if it really is a
- * P2P group.
- */
- wpas_dbus_register_p2p_groupmember(wpa_s, sta);
-
- /*
* Create 'peer-joined' signal on group object -- will also
* check P2P itself.
*/
- wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
+ if (p2p_dev_addr)
+ wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
#endif /* CONFIG_P2P */
+
+ /* Notify listeners a new station has been authorized */
+ wpas_dbus_signal_sta_authorized(wpa_s, sta);
}
static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
- const u8 *sta)
+ const u8 *sta,
+ const u8 *p2p_dev_addr)
{
#ifdef CONFIG_P2P
/*
- * Unregister a group member object corresponding to this peer
- * if this is a P2P group.
- */
- wpas_dbus_unregister_p2p_groupmember(wpa_s, sta);
-
- /*
* Create 'peer-disconnected' signal on group object if this
* is a P2P group.
*/
- wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
+ if (p2p_dev_addr)
+ wpas_dbus_signal_p2p_peer_disconnected(wpa_s, p2p_dev_addr);
#endif /* CONFIG_P2P */
+
+ /* Notify listeners a station has been deauthorized */
+ wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
}
@@ -576,18 +685,18 @@ void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
if (authorized)
wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr);
else
- wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr);
+ wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr, p2p_dev_addr);
}
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *cert_hash,
+ const char *subject, const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert)
{
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
"depth=%d subject='%s'%s%s",
- depth, subject,
- cert_hash ? " hash=" : "",
+ depth, subject, cert_hash ? " hash=" : "",
cert_hash ? cert_hash : "");
if (cert) {
@@ -605,11 +714,20 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
}
}
+ if (altsubject) {
+ int i;
+
+ for (i = 0; i < num_altsubject; i++)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "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, cert_hash, cert);
+ wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
@@ -627,4 +745,41 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
const char *parameter)
{
wpas_dbus_signal_eap_status(wpa_s, status, parameter);
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_EAP_STATUS
+ "status='%s' parameter='%s'",
+ status, parameter);
+}
+
+
+void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (wpa_s->current_ssid != ssid)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Network bssid config changed for the current network - within-ESS roaming %s",
+ ssid->bssid_set ? "disabled" : "enabled");
+
+ wpa_drv_roaming(wpa_s, !ssid->bssid_set,
+ ssid->bssid_set ? ssid->bssid : NULL);
+}
+
+
+void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+ if (ssid->disabled == 2) {
+ /* Changed from normal network profile to persistent group */
+ ssid->disabled = 0;
+ wpas_dbus_unregister_network(wpa_s, ssid->id);
+ ssid->disabled = 2;
+ wpas_dbus_register_persistent_group(wpa_s, ssid);
+ } else {
+ /* Changed from persistent group to normal network profile */
+ wpas_dbus_unregister_persistent_group(wpa_s, ssid->id);
+ wpas_dbus_register_network(wpa_s, ssid);
+ }
+#endif /* CONFIG_P2P */
}
diff --git a/contrib/wpa/wpa_supplicant/notify.h b/contrib/wpa/wpa_supplicant/notify.h
index 58675ac..b268332 100644
--- a/contrib/wpa/wpa_supplicant/notify.h
+++ b/contrib/wpa/wpa_supplicant/notify.h
@@ -71,6 +71,7 @@ void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
unsigned int id);
void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
unsigned int id);
+void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id);
void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name);
void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);
@@ -120,12 +121,17 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *cert_hash,
+ const char *subject, const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert);
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *dst, const u8 *bssid,
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_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
#endif /* NOTIFY_H */
diff --git a/contrib/wpa/wpa_supplicant/offchannel.c b/contrib/wpa/wpa_supplicant/offchannel.c
index 856eca7..63af83a 100644
--- a/contrib/wpa/wpa_supplicant/offchannel.c
+++ b/contrib/wpa/wpa_supplicant/offchannel.c
@@ -12,6 +12,7 @@
#include "common.h"
#include "utils/eloop.h"
#include "wpa_supplicant_i.h"
+#include "p2p_supplicant.h"
#include "driver_i.h"
#include "offchannel.h"
@@ -30,8 +31,7 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
*/
iface = wpa_s->global->ifaces;
while (iface) {
- if (os_memcmp(wpa_s->pending_action_src,
- iface->own_addr, ETH_ALEN) == 0)
+ if (os_memcmp(src, iface->own_addr, ETH_ALEN) == 0)
break;
iface = iface->next;
}
@@ -55,11 +55,12 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
without_roc = wpa_s->pending_action_without_roc;
wpa_s->pending_action_without_roc = 0;
- wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback "
- "(without_roc=%d pending_action_tx=%p)",
- without_roc, wpa_s->pending_action_tx);
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Send Action callback (without_roc=%d pending_action_tx=%p pending_action_tx_done=%d)",
+ without_roc, wpa_s->pending_action_tx,
+ !!wpa_s->pending_action_tx_done);
- if (wpa_s->pending_action_tx == NULL)
+ if (wpa_s->pending_action_tx == NULL || wpa_s->pending_action_tx_done)
return;
/*
@@ -83,6 +84,7 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
wpa_s->off_channel_freq,
iface->assoc_freq);
if (without_roc && wpa_s->off_channel_freq == 0) {
+ unsigned int duration = 200;
/*
* We may get here if wpas_send_action() found us to be
* on the correct channel, but remain-on-channel cancel
@@ -90,9 +92,18 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
*/
wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
"remain-on-channel to send Action frame");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Increase ROC duration %u -> %u",
+ duration,
+ duration + wpa_s->extra_roc_dur);
+ duration += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_drv_remain_on_channel(
- wpa_s, wpa_s->pending_action_freq, 200) <
- 0) {
+ wpa_s, wpa_s->pending_action_freq,
+ duration) < 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
"request driver to remain on "
"channel (%u MHz) for Action Frame "
@@ -159,6 +170,21 @@ void offchannel_send_action_tx_status(
return;
}
+ /* Accept report only if the contents of the frame matches */
+ if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 ||
+ os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx),
+ wpabuf_len(wpa_s->pending_action_tx)) != 0) {
+ wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+ "mismatching contents with pending frame");
+ wpa_hexdump(MSG_MSGDUMP, "TX status frame data",
+ data, data_len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
+
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
@@ -172,6 +198,14 @@ void offchannel_send_action_tx_status(
wpa_s->pending_action_bssid,
data, data_len, result);
}
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_long_listen > 0) {
+ /* Continue the listen */
+ wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
+ wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ }
+#endif /* CONFIG_P2P */
}
@@ -220,6 +254,7 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
MAC2STR(wpa_s->pending_action_dst));
wpabuf_free(wpa_s->pending_action_tx);
}
+ wpa_s->pending_action_tx_done = 0;
wpa_s->pending_action_tx = wpabuf_alloc(len);
if (wpa_s->pending_action_tx == NULL) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
@@ -236,18 +271,21 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
struct wpa_supplicant *iface;
+ int ret;
- iface = wpas_get_tx_interface(wpa_s,
- wpa_s->pending_action_src);
+ iface = wpas_get_tx_interface(wpa_s, src);
wpa_s->action_tx_wait_time = wait_time;
- return wpa_drv_send_action(
+ ret = wpa_drv_send_action(
iface, wpa_s->pending_action_freq,
wait_time, wpa_s->pending_action_dst,
wpa_s->pending_action_src, wpa_s->pending_action_bssid,
wpabuf_head(wpa_s->pending_action_tx),
wpabuf_len(wpa_s->pending_action_tx),
wpa_s->pending_action_no_cck);
+ if (ret == 0)
+ wpa_s->pending_action_tx_done = 1;
+ return ret;
}
if (freq) {
@@ -285,6 +323,15 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
"channel");
if (wait_time > wpa_s->max_remain_on_chan)
wait_time = wpa_s->max_remain_on_chan;
+ else if (wait_time == 0)
+ wait_time = 20;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+ wait_time, wait_time + wpa_s->extra_roc_dur);
+ wait_time += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
"to remain on channel (%u MHz) for Action "
@@ -307,15 +354,18 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
*/
void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
{
- wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
- "notification");
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Action frame sequence done notification: pending_action_tx=%p drv_offchan_tx=%d action_tx_wait_time=%d off_channel_freq=%d roc_waiting_drv_freq=%d",
+ wpa_s->pending_action_tx,
+ !!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX),
+ wpa_s->action_tx_wait_time, wpa_s->off_channel_freq,
+ wpa_s->roc_waiting_drv_freq);
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_drv_send_action_cancel_wait(wpa_s);
-
- if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+ 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;
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.c b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
index 0a09b00..b200ca0 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
@@ -1,6 +1,7 @@
/*
* wpa_supplicant - P2P
* Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,7 +18,11 @@
#include "p2p/p2p.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
+#include "ap/sta_info.h"
+#include "ap/ap_drv_ops.h"
+#include "ap/wps_hostapd.h"
#include "ap/p2p_hostapd.h"
+#include "ap/dfs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
@@ -31,6 +36,7 @@
#include "offchannel.h"
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
+#include "wifi_display.h"
/*
@@ -52,14 +58,32 @@
#ifndef P2P_MAX_INITIAL_CONN_WAIT
/*
* How many seconds to wait for initial 4-way handshake to get completed after
- * WPS provisioning step.
+ * WPS provisioning step or after the re-invocation of a persistent group on a
+ * P2P Client.
*/
#define P2P_MAX_INITIAL_CONN_WAIT 10
#endif /* P2P_MAX_INITIAL_CONN_WAIT */
-#ifndef P2P_CONCURRENT_SEARCH_DELAY
-#define P2P_CONCURRENT_SEARCH_DELAY 500
-#endif /* P2P_CONCURRENT_SEARCH_DELAY */
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step on the GO. This controls the extra time the P2P
+ * operation is considered to be in progress (e.g., to delay other scans) after
+ * WPS provisioning has been completed on the GO during group formation.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
+
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * re-invocation of a persistent group on the GO when the client is expected
+ * to connect automatically (no user interaction).
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */
+
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
enum p2p_group_removal_reason {
P2P_GROUP_REMOVAL_UNKNOWN,
@@ -68,7 +92,9 @@ enum p2p_group_removal_reason {
P2P_GROUP_REMOVAL_REQUESTED,
P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
P2P_GROUP_REMOVAL_UNAVAILABLE,
- P2P_GROUP_REMOVAL_GO_ENDING_SESSION
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
+ P2P_GROUP_REMOVAL_PSK_FAILURE,
+ P2P_GROUP_REMOVAL_FREQ_CONFLICT
};
@@ -76,19 +102,104 @@ static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
static struct wpa_supplicant *
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);
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len);
+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);
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
const u8 *dev_addr, enum p2p_wps_method wps_method,
- int auto_join);
+ int auto_join, int freq,
+ const u8 *ssid, size_t ssid_len);
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
-static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
- int group_added);
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
+static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added);
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+static void wpas_stop_listen(void *ctx);
+static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
+static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
+static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type type);
+
+
+/*
+ * Get the number of concurrent channels that the HW can operate, but that are
+ * currently not in use by any of the wpa_supplicant interfaces.
+ */
+static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
+{
+ int *freqs;
+ int num, unused;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
+
+ num = get_shared_radio_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+ os_free(freqs);
+
+ unused = wpa_s->num_multichan_concurrent - num;
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: num_unused_channels: %d", unused);
+ return unused;
+}
+
+
+/*
+ * Get the frequencies that are currently in use by one or more of the virtual
+ * interfaces, and that are also valid for P2P operation.
+ */
+static unsigned int
+wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *p2p_freqs,
+ unsigned int len)
+{
+ struct wpa_used_freq_data *freqs;
+ unsigned int num, i, j;
+
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
+ if (!freqs)
+ return 0;
+
+ num = get_shared_radio_freqs_data(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ os_memset(p2p_freqs, 0, sizeof(struct wpa_used_freq_data) * len);
+
+ for (i = 0, j = 0; i < num && j < len; i++) {
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
+ p2p_freqs[j++] = freqs[i];
+ }
+
+ os_free(freqs);
+
+ dump_freq_data(wpa_s, "valid for P2P", p2p_freqs, j);
+
+ return j;
+}
+
+
+static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+ if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+ freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz due to p2p_ignore_shared_freq=1 configuration",
+ freq);
+ freq = 0;
+ }
+ p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
+}
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -96,6 +207,12 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
{
size_t i;
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
@@ -104,10 +221,29 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
+ struct os_reltime time_tmp_age, entry_ts;
+ const u8 *ies;
+ size_t ies_len;
+
+ time_tmp_age.sec = bss->age / 1000;
+ time_tmp_age.usec = (bss->age % 1000) * 1000;
+ os_reltime_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
+
+ ies = (const u8 *) (bss + 1);
+ ies_len = bss->ie_len;
+ if (bss->beacon_ie_len > 0 &&
+ !wpa_scan_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ wpa_scan_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ wpa_printf(MSG_DEBUG, "P2P: Use P2P IE(s) from Beacon frame since no P2P IE(s) in Probe Response frames received for "
+ MACSTR, MAC2STR(bss->bssid));
+ ies = ies + ies_len;
+ ies_len = bss->beacon_ie_len;
+ }
+
+
if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
- bss->freq, bss->age, bss->level,
- (const u8 *) (bss + 1),
- bss->ie_len) > 0)
+ bss->freq, &entry_ts, bss->level,
+ ies, ies_len) > 0)
break;
}
@@ -115,91 +251,166 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
}
+static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_driver_scan_params *params = work->ctx;
+ int ret;
+
+ if (deinit) {
+ if (!work->started) {
+ wpa_scan_free_params(params);
+ return;
+ }
+
+ wpa_s->p2p_scan_work = NULL;
+ return;
+ }
+
+ ret = wpa_drv_scan(wpa_s, params);
+ wpa_scan_free_params(params);
+ work->ctx = NULL;
+ if (ret) {
+ radio_work_done(work);
+ p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
+ return;
+ }
+
+ p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
+ 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->p2p_scan_work = work;
+}
+
+
+static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ if (wpa_s->global->p2p_24ghz_social_channels &&
+ (freq == 2412 || freq == 2437 || freq == 2462)) {
+ /*
+ * Search all social channels regardless of whether these have
+ * been disabled for P2P operating channel use to avoid missing
+ * peers.
+ */
+ return 1;
+ }
+ return p2p_supported_freq(wpa_s->global->p2p, freq);
+}
+
+
static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
unsigned int num_req_dev_types,
const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
- struct wpa_supplicant *ifs;
- struct wpa_driver_scan_params params;
- int ret;
+ struct wpa_driver_scan_params *params = NULL;
struct wpabuf *wps_ie, *ies;
- int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+ unsigned int num_channels = 0;
+ int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
size_t ielen;
+ u8 *n, i;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs->sta_scan_pending &&
- wpas_p2p_in_progress(wpa_s) == 2) {
- wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
- "pending station mode scan to be "
- "completed on interface %s", ifs->ifname);
- wpa_s->global->p2p_cb_on_scan_complete = 1;
- wpa_supplicant_req_scan(ifs, 0, 0);
- return 1;
- }
+ if (wpa_s->p2p_scan_work) {
+ wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending");
+ return -1;
}
- os_memset(&params, 0, sizeof(params));
+ params = os_zalloc(sizeof(*params));
+ if (params == NULL)
+ return -1;
/* P2P Wildcard SSID */
- params.num_ssids = 1;
- params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
- params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ params->num_ssids = 1;
+ n = os_malloc(P2P_WILDCARD_SSID_LEN);
+ if (n == NULL)
+ goto fail;
+ os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+ params->ssids[0].ssid = n;
+ params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
num_req_dev_types, req_dev_types);
if (wps_ie == NULL)
- return -1;
+ 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);
- return -1;
+ 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;
- params.extra_ies = wpabuf_head(ies);
- params.extra_ies_len = wpabuf_len(ies);
+ 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 = social_channels;
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
+ sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
+ if (wpas_p2p_search_social_channel(
+ wpa_s, social_channels_freq[i]))
+ params->freqs[num_channels++] =
+ social_channels_freq[i];
+ }
+ params->freqs[num_channels++] = 0;
break;
case P2P_SCAN_FULL:
break;
+ case P2P_SCAN_SPECIFIC:
+ params->freqs = os_calloc(2, sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ params->freqs[0] = freq;
+ params->freqs[1] = 0;
+ break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
- social_channels[3] = freq;
- params.freqs = social_channels;
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 2,
+ sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
+ if (wpas_p2p_search_social_channel(
+ wpa_s, social_channels_freq[i]))
+ params->freqs[num_channels++] =
+ social_channels_freq[i];
+ }
+ if (p2p_supported_freq(wpa_s->global->p2p, freq))
+ params->freqs[num_channels++] = freq;
+ params->freqs[num_channels++] = 0;
break;
}
- ret = wpa_drv_scan(wpa_s, &params);
-
- wpabuf_free(ies);
-
- if (ret) {
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs->scanning ||
- ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
- wpa_s->global->p2p_cb_on_scan_complete = 1;
- ret = 1;
- break;
- }
- }
- } else
- wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ 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)
+ goto fail;
+ return 0;
- return ret;
+fail:
+ wpa_scan_free_params(params);
+ return -1;
}
@@ -243,6 +454,318 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
}
+static void run_wpas_p2p_disconnect(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Complete previously requested removal of %s",
+ wpa_s->ifname);
+ wpas_p2p_disconnect(wpa_s);
+}
+
+
+static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
+ struct wpa_supplicant *calling_wpa_s)
+{
+ if (calling_wpa_s == wpa_s && wpa_s &&
+ wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+ /*
+ * The calling wpa_s instance is going to be removed. Do that
+ * from an eloop callback to keep the instance available until
+ * the caller has returned. This my be needed, e.g., to provide
+ * control interface responses on the per-interface socket.
+ */
+ if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
+ wpa_s, NULL) < 0)
+ return -1;
+ return 0;
+ }
+
+ return wpas_p2p_disconnect(wpa_s);
+}
+
+
+/* Determine total number of clients in active groups where we are the GO */
+static unsigned int p2p_group_go_member_count(struct wpa_supplicant *wpa_s)
+{
+ unsigned int count = 0;
+ struct wpa_ssid *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) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
+ wpa_s, s, s->disabled, s->p2p_group,
+ s->mode);
+ if (!s->disabled && s->p2p_group &&
+ s->mode == WPAS_MODE_P2P_GO) {
+ count += p2p_get_group_num_members(
+ wpa_s->p2p_group);
+ }
+ }
+ }
+
+ return count;
+}
+
+
+/* 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;
+
+ /* 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) */
+ return save;
+}
+
+
+/* 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)
+{
+ struct wpa_ssid *s, *empty = NULL;
+
+ if (!wpa_s)
+ return 0;
+
+ 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;
+ }
+ }
+
+ return empty;
+}
+
+
+/* Find a persistent group where we are the GO */
+static struct wpa_ssid *
+wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *s;
+
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled == 2 && s->mode == WPAS_MODE_P2P_GO)
+ return s;
+ }
+
+ return NULL;
+}
+
+
+static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
+{
+ struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
+ 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_ssid *persistent_go;
+ int p2p_no_group_iface;
+
+ wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
+
+ /*
+ * For non-concurrent capable devices:
+ * If persistent_go, then no new.
+ * If GO, then no client.
+ * If client, then no GO.
+ */
+ go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+ persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+ p2p_no_group_iface = wpa_s->conf->p2p_no_group_iface;
+
+ 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++;
+ }
+ }
+ }
+
+ /* If not concurrent, restrict our choices */
+ if (p2p_no_group_iface) {
+ wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
+
+ if (client)
+ return P2PS_SETUP_NONE;
+
+ if (go_wpa_s) {
+ if (role == P2PS_SETUP_CLIENT ||
+ incoming == P2PS_SETUP_GROUP_OWNER ||
+ p2p_client_limit_reached(go_wpa_s->p2p_group))
+ return P2PS_SETUP_NONE;
+
+ return P2PS_SETUP_GROUP_OWNER;
+ }
+
+ if (persistent_go) {
+ if (role == P2PS_SETUP_NONE || role == P2PS_SETUP_NEW) {
+ if (!incoming)
+ return P2PS_SETUP_GROUP_OWNER |
+ P2PS_SETUP_CLIENT;
+ if (incoming == P2PS_SETUP_NEW) {
+ u8 r;
+
+ if (os_get_random(&r, sizeof(r)) < 0 ||
+ (r & 1))
+ return P2PS_SETUP_CLIENT;
+ return P2PS_SETUP_GROUP_OWNER;
+ }
+ }
+ }
+ }
+
+ /* If a required role has been specified, handle it here */
+ if (role && role != P2PS_SETUP_NEW) {
+ switch (incoming) {
+ 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;
+
+ case P2PS_SETUP_GROUP_OWNER:
+ /*
+ * Must be a complimentary role - cannot be a client to
+ * more than one peer.
+ */
+ if (incoming == role || client)
+ return P2PS_SETUP_NONE;
+
+ return P2PS_SETUP_CLIENT;
+
+ case P2PS_SETUP_CLIENT:
+ /* Must be a complimentary role */
+ if (incoming != role) {
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ goto grp_owner;
+ }
+
+ default:
+ return P2PS_SETUP_NONE;
+ }
+ }
+
+ /*
+ * For now, we only will support ownership of one group, and being a
+ * client of one group. Therefore, if we have either an existing GO
+ * group, or an existing client group, we will not do a new GO
+ * negotiation, but rather try to re-use the existing groups.
+ */
+ switch (incoming) {
+ case P2PS_SETUP_NONE:
+ case P2PS_SETUP_NEW:
+ if (client)
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ else if (!owned_members)
+ conncap = P2PS_SETUP_NEW;
+ else if (incoming == P2PS_SETUP_NONE)
+ conncap = P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT;
+ else
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+
+ case P2PS_SETUP_CLIENT:
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ break;
+
+ case P2PS_SETUP_GROUP_OWNER:
+ if (!client)
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+ if (client)
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ else {
+ u8 r;
+
+ if (os_get_random(&r, sizeof(r)) < 0 ||
+ (r & 1))
+ conncap = P2PS_SETUP_CLIENT;
+ else
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ }
+ break;
+
+ default:
+ return P2PS_SETUP_NONE;
+ }
+
+grp_owner:
+ if ((conncap & P2PS_SETUP_GROUP_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) {
+ p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->own_addr);
+ } else if (!s && !owner) {
+ if (wpas_p2p_add_group_interface(wpa_s,
+ WPA_IF_P2P_GO) < 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to allocate a new interface for the group");
+ return P2PS_SETUP_NONE;
+ }
+ wpa_s->global->pending_group_iface_for_p2ps = 1;
+ p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->pending_interface_addr);
+ }
+ }
+
+ return conncap;
+}
+
+
static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
enum p2p_group_removal_reason removal_reason)
{
@@ -277,16 +800,30 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
(ssid && ssid->mode == WPAS_MODE_INFRA)) {
wpa_s->reassociate = 0;
wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
gtype = "client";
} else
gtype = "GO";
+
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
+ wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
+
+ if (os_strcmp(gtype, "client") == 0) {
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ if (eloop_is_timeout_registered(wpas_p2p_psk_failure_removal,
+ wpa_s, NULL)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: PSK failure removal was scheduled, so use PSK failure as reason for group removal");
+ removal_reason = P2P_GROUP_REMOVAL_PSK_FAILURE;
+ eloop_cancel_timeout(wpas_p2p_psk_failure_removal,
+ wpa_s, NULL);
+ }
+ }
+
if (wpa_s->cross_connect_in_use) {
wpa_s->cross_connect_in_use = 0;
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
- wpa_s->ifname, wpa_s->cross_connect_uplink);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ wpa_s->ifname, wpa_s->cross_connect_uplink);
}
switch (removal_reason) {
case P2P_GROUP_REMOVAL_REQUESTED:
@@ -304,21 +841,40 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
reason = " reason=GO_ENDING_SESSION";
break;
+ case P2P_GROUP_REMOVAL_PSK_FAILURE:
+ reason = " reason=PSK_FAILURE";
+ break;
+ case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
+ reason = " reason=FREQ_CONFLICT";
+ break;
default:
reason = "";
break;
}
if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_REMOVED "%s %s%s",
- wpa_s->ifname, gtype, reason);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_REMOVED "%s %s%s",
+ wpa_s->ifname, gtype, reason);
}
+ if (eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group freq_conflict timeout");
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_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
+ "timeout");
+ wpa_s->p2p_in_provisioning = 0;
+ }
- if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
- wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
+ wpa_s->p2p_in_invitation = 0;
+
+ /*
+ * Make sure wait for the first client does not remain active after the
+ * group has been removed.
+ */
+ wpa_s->global->p2p_go_wait_client.sec = 0;
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
struct wpa_global *global;
@@ -329,6 +885,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
global = wpa_s->global;
ifname = os_strdup(wpa_s->ifname);
type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
+ eloop_cancel_timeout(run_wpas_p2p_disconnect, wpa_s, NULL);
wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
wpa_s = global->ifaces;
if (wpa_s && ifname)
@@ -337,6 +894,21 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
return 1;
}
+ if (!wpa_s->p2p_go_group_formation_completed) {
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
+ }
+
+ wpa_s->show_group_started = 0;
+ os_free(wpa_s->go_params);
+ wpa_s->go_params = NULL;
+
+ 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->waiting_presence_resp = 0;
+
wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
if (ssid && (ssid->p2p_group ||
ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
@@ -359,7 +931,6 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
wpa_config_remove_network(wpa_s->conf, id);
wpa_supplicant_clear_status(wpa_s);
wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_s->sta_scan_pending = 0;
} else {
wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
"found");
@@ -389,6 +960,10 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
bssid = wpa_s->bssid;
bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
+ if (bss == NULL && wpa_s->go_params &&
+ !is_zero_ether_addr(wpa_s->go_params->peer_device_addr))
+ bss = wpa_bss_get_p2p_dev_addr(
+ wpa_s, wpa_s->go_params->peer_device_addr);
if (bss == NULL) {
u8 iface_addr[ETH_ALEN];
if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
@@ -403,6 +978,9 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
}
p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ if (p2p == NULL)
+ p2p = wpa_bss_get_vendor_ie_multi_beacon(bss,
+ P2P_IE_VENDOR_TYPE);
if (p2p == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
"group is persistent - BSS " MACSTR
@@ -509,13 +1087,16 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
s->ssid_len = ssid->ssid_len;
os_memcpy(s->ssid, ssid->ssid, s->ssid_len);
}
+ if (ssid->mode == WPAS_MODE_P2P_GO && wpa_s->global->add_psk) {
+ dl_list_add(&s->psk_list, &wpa_s->global->add_psk->list);
+ wpa_s->global->add_psk = NULL;
+ changed = 1;
+ }
-#ifndef CONFIG_NO_CONFIG_WRITE
if (changed && wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
}
-#endif /* CONFIG_NO_CONFIG_WRITE */
return s->id;
}
@@ -547,7 +1128,7 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
return;
for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, addr,
ETH_ALEN) != 0)
continue;
@@ -555,39 +1136,92 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
return; /* already the most recent entry */
/* move the entry to mark it most recent */
- os_memmove(s->p2p_client_list + i * ETH_ALEN,
- s->p2p_client_list + (i + 1) * ETH_ALEN,
- (s->num_p2p_clients - i - 1) * ETH_ALEN);
+ os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
+ s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
os_memcpy(s->p2p_client_list +
- (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN, addr,
+ ETH_ALEN);
+ os_memset(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
found = 1;
break;
}
if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
n = os_realloc_array(s->p2p_client_list,
- s->num_p2p_clients + 1, ETH_ALEN);
+ s->num_p2p_clients + 1, 2 * ETH_ALEN);
if (n == NULL)
return;
- os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+ os_memcpy(n + s->num_p2p_clients * 2 * ETH_ALEN, addr,
+ ETH_ALEN);
+ os_memset(n + s->num_p2p_clients * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
s->p2p_client_list = n;
s->num_p2p_clients++;
- } else if (!found) {
+ } else if (!found && s->p2p_client_list) {
/* Not enough room for an additional entry - drop the oldest
* entry */
os_memmove(s->p2p_client_list,
- s->p2p_client_list + ETH_ALEN,
- (s->num_p2p_clients - 1) * ETH_ALEN);
+ s->p2p_client_list + 2 * ETH_ALEN,
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN);
os_memcpy(s->p2p_client_list +
- (s->num_p2p_clients - 1) * ETH_ALEN,
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN,
addr, ETH_ALEN);
+ os_memset(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
}
-#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->parent->conf->update_config &&
wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
-#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
+static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s,
+ int go, struct wpa_ssid *ssid, int freq,
+ const u8 *psk, const char *passphrase,
+ const u8 *go_dev_addr, int persistent,
+ const char *extra)
+{
+ const char *ssid_txt;
+ char psk_txt[65];
+
+ if (psk)
+ wpa_snprintf_hex(psk_txt, sizeof(psk_txt), psk, 32);
+ else
+ psk_txt[0] = '\0';
+
+ if (ssid)
+ ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+ else
+ ssid_txt = "";
+
+ if (passphrase && passphrase[0] == '\0')
+ passphrase = NULL;
+
+ /*
+ * 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,
+ P2P_EVENT_GROUP_STARTED
+ "%s %s ssid=\"%s\" freq=%d%s%s%s%s%s go_dev_addr="
+ MACSTR "%s%s",
+ wpa_s->ifname, go ? "GO" : "client", ssid_txt, freq,
+ psk ? " psk=" : "", psk_txt,
+ passphrase ? " passphrase=\"" : "",
+ passphrase ? passphrase : "",
+ passphrase ? "\"" : "",
+ MAC2STR(go_dev_addr),
+ persistent ? " [PERSISTENT]" : "", extra);
+ wpa_printf(MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s %s ssid=\"%s\" freq=%d go_dev_addr=" MACSTR "%s%s",
+ wpa_s->ifname, go ? "GO" : "client", ssid_txt, freq,
+ MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : "",
+ extra);
}
@@ -595,7 +1229,6 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
int success)
{
struct wpa_ssid *ssid;
- const char *ssid_txt;
int client;
int persistent;
u8 go_dev_addr[ETH_ALEN];
@@ -608,18 +1241,23 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
*/
if (wpa_s->global->p2p_group_formation)
wpa_s = wpa_s->global->p2p_group_formation;
- wpa_s->global->p2p_group_formation = NULL;
- wpa_s->p2p_in_provisioning = 0;
+ if (wpa_s->p2p_go_group_formation_completed) {
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
+ }
+ wpa_s->p2p_in_invitation = 0;
+ wpa_s->group_formation_reported = 1;
if (!success) {
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_FORMATION_FAILURE);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_FORMATION_FAILED);
return;
}
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_SUCCESS);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_SUCCESS);
ssid = wpa_s->current_ssid;
if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
@@ -630,7 +1268,6 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
persistent = 0;
if (ssid) {
- ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
client = ssid->mode == WPAS_MODE_INFRA;
if (ssid->mode == WPAS_MODE_P2P_GO) {
persistent = ssid->p2p_persistent_group;
@@ -642,7 +1279,6 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
ssid->ssid,
ssid->ssid_len);
} else {
- ssid_txt = "";
client = wpa_s->p2p_group_interface ==
P2P_GROUP_INTERFACE_CLIENT;
os_memset(go_dev_addr, 0, ETH_ALEN);
@@ -656,25 +1292,13 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
* packets.
*/
wpa_s->show_group_started = 1;
- } else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
- char psk[65];
- wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR
- "%s",
- wpa_s->ifname, ssid_txt, ssid->frequency, psk,
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
- wpas_p2p_cross_connect_setup(wpa_s);
- wpas_p2p_set_group_idle_timeout(wpa_s);
} else {
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname, ssid_txt, ssid ? ssid->frequency : 0,
- ssid && ssid->passphrase ? ssid->passphrase : "",
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+ wpas_p2p_group_started(wpa_s, 1, ssid,
+ ssid ? ssid->frequency : 0,
+ ssid && ssid->passphrase == NULL &&
+ ssid->psk_set ? ssid->psk : NULL,
+ ssid ? ssid->passphrase : NULL,
+ go_dev_addr, persistent, "");
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
}
@@ -682,10 +1306,69 @@ 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);
+ 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)
+ if (!client) {
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+ os_get_reltime(&wpa_s->global->p2p_go_wait_client);
+ }
+}
+
+
+struct send_action_work {
+ unsigned int freq;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ size_t len;
+ unsigned int wait_time;
+ u8 buf[0];
+};
+
+
+static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (!wpa_s->p2p_send_action_work)
+ 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;
+}
+
+
+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;
+ if (awork->wait_time == 0) {
+ os_free(awork);
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+ } else {
+ /*
+ * In theory, this should not be needed, but number of
+ * places in the P2P code is still using non-zero wait
+ * time for the last Action frame in the sequence and
+ * some of these do not call send_action_done().
+ */
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 0, awork->wait_time * 1000,
+ wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ }
+ }
}
@@ -699,10 +1382,10 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
{
enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
+ wpas_p2p_action_tx_clear(wpa_s);
+
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
switch (result) {
case OFFCHANNEL_SEND_ACTION_SUCCESS:
@@ -726,17 +1409,96 @@ 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,
+ P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=no-ACK-to-PD-Req");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
return;
}
}
+static void wpas_send_action_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct send_action_work *awork = work->ctx;
+
+ if (deinit) {
+ if (work->started) {
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ wpa_s->p2p_send_action_work = NULL;
+ offchannel_send_action_done(wpa_s);
+ }
+ os_free(awork);
+ return;
+ }
+
+ if (offchannel_send_action(wpa_s, awork->freq, awork->dst, awork->src,
+ awork->bssid, awork->buf, awork->len,
+ awork->wait_time,
+ wpas_p2p_send_action_tx_status, 1) < 0) {
+ os_free(awork);
+ radio_work_done(work);
+ return;
+ }
+ wpa_s->p2p_send_action_work = work;
+}
+
+
+static int wpas_send_action_work(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid, const u8 *buf,
+ size_t len, unsigned int wait_time)
+{
+ struct send_action_work *awork;
+
+ if (wpa_s->p2p_send_action_work) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending");
+ return -1;
+ }
+
+ awork = os_zalloc(sizeof(*awork) + len);
+ if (awork == NULL)
+ return -1;
+
+ awork->freq = freq;
+ os_memcpy(awork->dst, dst, ETH_ALEN);
+ os_memcpy(awork->src, src, ETH_ALEN);
+ os_memcpy(awork->bssid, bssid, ETH_ALEN);
+ awork->len = len;
+ awork->wait_time = wait_time;
+ os_memcpy(awork->buf, buf, len);
+
+ if (radio_add_work(wpa_s, freq, "p2p-send-action", 0,
+ wpas_send_action_cb, awork) < 0) {
+ os_free(awork);
+ return -1;
+ }
+
+ return 0;
+}
+
+
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)
{
struct wpa_supplicant *wpa_s = ctx;
+ int listen_freq = -1, send_freq = -1;
+
+ 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);
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");
return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
wait_time,
wpas_p2p_send_action_tx_status, 1);
@@ -746,6 +1508,15 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
static void wpas_send_action_done(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+
+ if (wpa_s->p2p_send_action_work) {
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ 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;
+ }
+
offchannel_send_action_done(wpa_s);
}
@@ -766,16 +1537,33 @@ static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
{
- wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
- MAC2STR(res->peer_interface_addr));
+ wpa_s->group_formation_reported = 0;
+ wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR
+ " dev_addr " MACSTR " wps_method %d",
+ MAC2STR(res->peer_interface_addr),
+ MAC2STR(res->peer_device_addr), res->wps_method);
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
res->ssid, res->ssid_len);
wpa_supplicant_ap_deinit(wpa_s);
wpas_copy_go_neg_results(wpa_s, res);
- if (res->wps_method == WPS_PBC)
+ if (res->wps_method == WPS_PBC) {
wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
- else {
+#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 ==
+ DEV_PW_NFC_CONNECTION_HANDOVER ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash :
+ NULL,
+ NULL, 0, 0);
+#endif /* CONFIG_WPS_NFC */
+ } else {
u16 dev_pw_id = DEV_PW_DEFAULT;
+ if (wpa_s->p2p_wps_method == WPS_P2PS)
+ dev_pw_id = DEV_PW_P2PS_DEFAULT;
if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
wpas_wps_start_pin(wpa_s, res->peer_interface_addr,
@@ -784,6 +1572,88 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
}
+static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_ssid *persistent;
+ struct psk_list_entry *psk;
+ struct hostapd_data *hapd;
+
+ if (!wpa_s->ap_iface)
+ return;
+
+ persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+ ssid->ssid_len);
+ if (persistent == NULL)
+ return;
+
+ hapd = wpa_s->ap_iface->bss[0];
+
+ dl_list_for_each(psk, &persistent->psk_list, struct psk_list_entry,
+ list) {
+ struct hostapd_wpa_psk *hpsk;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add persistent group PSK entry for "
+ MACSTR " psk=%d",
+ MAC2STR(psk->addr), psk->p2p);
+ hpsk = os_zalloc(sizeof(*hpsk));
+ if (hpsk == NULL)
+ break;
+ os_memcpy(hpsk->psk, psk->psk, PMK_LEN);
+ if (psk->p2p)
+ os_memcpy(hpsk->p2p_dev_addr, psk->addr, ETH_ALEN);
+ else
+ os_memcpy(hpsk->addr, psk->addr, ETH_ALEN);
+ hpsk->next = hapd->conf->ssid.wpa_psk;
+ hapd->conf->ssid.wpa_psk = hpsk;
+ }
+}
+
+
+static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
+ wpa_s->p2p_group_common_freqs_num);
+
+ 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]);
+}
+
+
+static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params)
+{
+ unsigned int i, len = int_array_len(wpa_s->go_params->freq_list);
+
+ wpa_s->p2p_group_common_freqs_num = 0;
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = os_calloc(len, sizeof(int));
+ if (!wpa_s->p2p_group_common_freqs)
+ return;
+
+ for (i = 0; i < len; i++) {
+ if (!wpa_s->go_params->freq_list[i])
+ break;
+ wpa_s->p2p_group_common_freqs[i] =
+ wpa_s->go_params->freq_list[i];
+ }
+ wpa_s->p2p_group_common_freqs_num = i;
+}
+
+
+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))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
static void p2p_go_configured(void *ctx, void *data)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -791,43 +1661,59 @@ static void p2p_go_configured(void *ctx, void *data)
struct wpa_ssid *ssid;
int network_id = -1;
+ p2p_go_save_group_common_freqs(wpa_s, params);
+ p2p_go_dump_common_freqs(wpa_s);
+
ssid = wpa_s->current_ssid;
if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
if (wpa_s->global->p2p_group_formation == wpa_s)
wpa_s->global->p2p_group_formation = NULL;
- if (os_strlen(params->passphrase) > 0) {
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s", wpa_s->ifname,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->frequency, params->passphrase,
- MAC2STR(wpa_s->global->p2p_dev_addr),
- params->persistent_group ? " [PERSISTENT]" :
- "");
- } else {
- char psk[65];
- wpa_snprintf_hex(psk, sizeof(psk), params->psk,
- sizeof(params->psk));
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d psk=%s "
- "go_dev_addr=" MACSTR "%s", wpa_s->ifname,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->frequency, psk,
- MAC2STR(wpa_s->global->p2p_dev_addr),
- params->persistent_group ? " [PERSISTENT]" :
- "");
- }
-
- if (params->persistent_group)
+ wpas_p2p_group_started(wpa_s, 1, ssid, ssid->frequency,
+ params->passphrase[0] == '\0' ?
+ params->psk : NULL,
+ params->passphrase,
+ wpa_s->global->p2p_dev_addr,
+ params->persistent_group, "");
+ wpa_s->group_formation_reported = 1;
+
+ if (wpa_s->parent->p2ps_join_addr_valid) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2PS: Setting default PIN for " MACSTR,
+ MAC2STR(wpa_s->parent->p2ps_join_addr));
+ wpa_supplicant_ap_wps_pin(wpa_s,
+ wpa_s->parent->p2ps_join_addr,
+ "12345670", NULL, 0, 0);
+ wpa_s->parent->p2ps_join_addr_valid = 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,
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_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
+
+ if (wpa_s->p2p_first_connection_timeout) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Start group formation timeout of %d seconds until first data connection on GO",
+ wpa_s->p2p_first_connection_timeout);
+ 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);
+ eloop_register_timeout(
+ wpa_s->p2p_first_connection_timeout, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+
return;
}
@@ -838,10 +1724,24 @@ static void p2p_go_configured(void *ctx, void *data)
"filtering");
return;
}
- if (params->wps_method == WPS_PBC)
+ if (params->wps_method == WPS_PBC) {
wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
params->peer_device_addr);
- else if (wpa_s->p2p_pin[0])
+#ifdef CONFIG_WPS_NFC
+ } else if (params->wps_method == WPS_NFC) {
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->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);
+#endif /* CONFIG_WPS_NFC */
+ } else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
wpa_s->p2p_pin, NULL, 0, 0);
os_free(wpa_s->go_params);
@@ -869,6 +1769,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
}
wpa_s->show_group_started = 0;
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->group_formation_reported = 0;
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
@@ -878,6 +1780,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
ssid->ht40 = params->ht40;
+ ssid->vht = params->vht;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -887,11 +1790,20 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ ssid->group_cipher = WPA_CIPHER_CCMP;
+ if (params->freq > 56160) {
+ /*
+ * Enable GCMP instead of CCMP as pairwise_cipher and
+ * group_cipher in 60 GHz.
+ */
+ ssid->pairwise_cipher = WPA_CIPHER_GCMP;
+ ssid->group_cipher = WPA_CIPHER_GCMP;
+ }
if (os_strlen(params->passphrase) > 0) {
ssid->passphrase = os_strdup(params->passphrase);
if (ssid->passphrase == NULL) {
- wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to copy "
- "passphrase for GO");
+ wpa_msg_global(wpa_s, MSG_ERROR,
+ "P2P: Failed to copy passphrase for GO");
wpa_config_remove_network(wpa_s->conf, ssid->id);
return;
}
@@ -907,6 +1819,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
wpa_s->ap_configured_cb_data = wpa_s->go_params;
+ wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_s->connect_without_scan = ssid;
wpa_s->reassociate = 1;
wpa_s->disconnected = 0;
@@ -944,6 +1857,41 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d->persistent_reconnect = s->persistent_reconnect;
d->max_num_sta = s->max_num_sta;
d->pbc_in_m1 = s->pbc_in_m1;
+ d->ignore_old_scan_res = s->ignore_old_scan_res;
+ d->beacon_int = s->beacon_int;
+ d->dtim_period = s->dtim_period;
+ d->p2p_go_ctwindow = s->p2p_go_ctwindow;
+ d->disassoc_low_ack = s->disassoc_low_ack;
+ 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) {
+ d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
+ d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
+ }
+}
+
+
+static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
+ char *ifname, size_t len)
+{
+ char *ifname_ptr = wpa_s->ifname;
+
+ if (os_strncmp(wpa_s->ifname, P2P_MGMT_DEVICE_PREFIX,
+ os_strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+ ifname_ptr = os_strrchr(wpa_s->ifname, '-') + 1;
+ }
+
+ os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx);
+ if (os_strlen(ifname) >= IFNAMSIZ &&
+ os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+ int res;
+
+ /* Try to avoid going over the IFNAMSIZ length limit */
+ res = os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+ if (os_snprintf_error(len, res) && len)
+ ifname[len - 1] = '\0';
+ }
}
@@ -964,14 +1912,7 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
return 0;
}
- os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
- wpa_s->p2p_group_idx);
- if (os_strlen(ifname) >= IFNAMSIZ &&
- os_strlen(wpa_s->ifname) < IFNAMSIZ) {
- /* Try to avoid going over the IFNAMSIZ length limit */
- os_snprintf(ifname, sizeof(ifname), "p2p-%d",
- wpa_s->p2p_group_idx);
- }
+ wpas_p2p_get_group_ifname(wpa_s, ifname, sizeof(ifname));
force_ifname[0] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
@@ -1015,6 +1956,7 @@ static void wpas_p2p_remove_pending_group_interface(
wpa_s->pending_interface_name);
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
wpa_s->pending_interface_name[0] = '\0';
+ wpa_s->global->pending_group_iface_for_p2ps = 0;
}
@@ -1041,19 +1983,25 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
os_memset(&iface, 0, sizeof(iface));
iface.ifname = wpa_s->pending_interface_name;
iface.driver = wpa_s->driver->name;
- iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+ if (wpa_s->conf->ctrl_interface == NULL &&
+ wpa_s->parent != wpa_s &&
+ wpa_s->p2p_mgmt &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE))
+ iface.ctrl_interface = wpa_s->parent->conf->ctrl_interface;
+ else
+ iface.ctrl_interface = wpa_s->conf->ctrl_interface;
iface.driver_param = wpa_s->conf->driver_param;
- group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+ group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
if (group_wpa_s == NULL) {
wpa_printf(MSG_ERROR, "P2P: Failed to create new "
"wpa_supplicant interface");
return NULL;
}
wpa_s->pending_interface_name[0] = '\0';
- group_wpa_s->parent = wpa_s;
group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO :
P2P_GROUP_INTERFACE_CLIENT;
wpa_s->global->p2p_group_formation = group_wpa_s;
+ wpa_s->global->pending_group_iface_for_p2ps = 0;
wpas_p2p_clone_config(group_wpa_s, wpa_s);
@@ -1066,15 +2014,44 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
+ wpas_p2p_group_formation_failed(wpa_s);
+}
+
+
+void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
if (wpa_s->global->p2p)
p2p_group_formation_failed(wpa_s->global->p2p);
- else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- wpa_drv_p2p_group_formation_failed(wpa_s);
wpas_group_formation_completed(wpa_s, 0);
}
-void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+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);
+ eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ wpa_s->global->p2p_fail_on_wps_complete = 0;
+}
+
+
+void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->global->p2p_group_formation != wpa_s)
+ return;
+ /* Speed up group formation timeout since this cannot succeed */
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+}
+
+
+static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1085,8 +2062,9 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
}
if (res->status) {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
- res->status);
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_GO_NEG_FAILURE "status=%d",
+ res->status);
wpas_notify_p2p_go_neg_completed(wpa_s, res);
wpas_p2p_remove_pending_group_interface(wpa_s);
return;
@@ -1094,8 +2072,16 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
if (wpa_s->p2p_go_ht40)
res->ht40 = 1;
-
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+ if (wpa_s->p2p_go_vht)
+ res->vht = 1;
+
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
+ "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
+ " wps_method=%s",
+ res->role_go ? "GO" : "client", res->freq, res->ht40,
+ MAC2STR(res->peer_device_addr),
+ MAC2STR(res->peer_interface_addr),
+ p2p_wps_method_text(res->wps_method));
wpas_notify_p2p_go_neg_completed(wpa_s, res);
if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
@@ -1117,6 +2103,9 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_p2p_init_group_interface(wpa_s, res->role_go);
if (group_wpa_s == NULL) {
wpas_p2p_remove_pending_group_interface(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_long_listen_timeout,
+ wpa_s, NULL);
+ wpas_p2p_group_formation_failed(wpa_s);
return;
}
if (group_wpa_s != wpa_s) {
@@ -1152,33 +2141,92 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
}
-void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
- " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
+ " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
}
-void wpas_dev_found(void *ctx, const u8 *addr,
- const struct p2p_peer_info *info,
- int new_device)
+static void wpas_dev_found(void *ctx, const u8 *addr,
+ const struct p2p_peer_info *info,
+ int new_device)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
+ char *wfd_dev_info_hex = NULL;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
- " p2p_dev_addr=" MACSTR
- " pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x",
- MAC2STR(addr), MAC2STR(info->p2p_device_addr),
- wps_dev_type_bin2str(info->pri_dev_type, devtype,
- sizeof(devtype)),
- info->device_name, info->config_methods,
- info->dev_capab, info->group_capab);
+#ifdef CONFIG_WIFI_DISPLAY
+ wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
+ WFD_SUBELEM_DEVICE_INFO);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ if (info->p2ps_instance) {
+ char str[256];
+ const u8 *buf = wpabuf_head(info->p2ps_instance);
+ size_t len = wpabuf_len(info->p2ps_instance);
+
+ while (len) {
+ u32 id;
+ u16 methods;
+ u8 str_len;
+
+ if (len < 4 + 2 + 1)
+ break;
+ id = WPA_GET_LE32(buf);
+ buf += sizeof(u32);
+ methods = WPA_GET_BE16(buf);
+ buf += sizeof(u16);
+ str_len = *buf++;
+ if (str_len > len - 4 - 2 - 1)
+ break;
+ os_memcpy(str, buf, str_len);
+ str[str_len] = '\0';
+ buf += str_len;
+ len -= str_len + sizeof(u32) + sizeof(u16) + sizeof(u8);
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_DEVICE_FOUND MACSTR
+ " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s'"
+ " config_methods=0x%x"
+ " dev_capab=0x%x"
+ " group_capab=0x%x"
+ " adv_id=%x asp_svc=%s%s",
+ MAC2STR(addr),
+ MAC2STR(info->p2p_device_addr),
+ wps_dev_type_bin2str(
+ info->pri_dev_type,
+ devtype, sizeof(devtype)),
+ info->device_name, methods,
+ info->dev_capab, info->group_capab,
+ id, str,
+ info->vendor_elems ?
+ " vendor_elems=1" : "");
+ }
+ goto done;
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
+ " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s' config_methods=0x%x "
+ "dev_capab=0x%x group_capab=0x%x%s%s%s new=%d",
+ MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+ wps_dev_type_bin2str(info->pri_dev_type, devtype,
+ sizeof(devtype)),
+ info->device_name, info->config_methods,
+ info->dev_capab, info->group_capab,
+ wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
+ wfd_dev_info_hex ? wfd_dev_info_hex : "",
+ info->vendor_elems ? " vendor_elems=1" : "",
+ new_device);
+
+done:
+ os_free(wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
@@ -1189,39 +2237,131 @@ static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
- "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
+ "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
wpas_notify_p2p_device_lost(wpa_s, dev_addr);
}
-static int wpas_start_listen(void *ctx, unsigned int freq,
- unsigned int duration,
- const struct wpabuf *probe_resp_ie)
+static void wpas_find_stopped(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+}
+
- wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
+struct wpas_p2p_listen_work {
+ unsigned int freq;
+ unsigned int duration;
+ struct wpabuf *probe_resp_ie;
+};
+
+
+static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork)
+{
+ if (lwork == NULL)
+ return;
+ wpabuf_free(lwork->probe_resp_ie);
+ os_free(lwork);
+}
+
+
+static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_p2p_listen_work *lwork;
+
+ if (!wpa_s->p2p_listen_work)
+ return;
+
+ lwork = wpa_s->p2p_listen_work->ctx;
+ wpas_p2p_listen_work_free(lwork);
+ radio_work_done(wpa_s->p2p_listen_work);
+ wpa_s->p2p_listen_work = NULL;
+}
+
+
+static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpas_p2p_listen_work *lwork = work->ctx;
+ unsigned int duration;
+
+ if (deinit) {
+ if (work->started) {
+ wpa_s->p2p_listen_work = NULL;
+ wpas_stop_listen(wpa_s);
+ }
+ wpas_p2p_listen_work_free(lwork);
+ return;
+ }
+
+ wpa_s->p2p_listen_work = work;
+
+ wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL);
if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
"report received Probe Request frames");
- return -1;
+ wpas_p2p_listen_work_done(wpa_s);
+ return;
}
- wpa_s->pending_listen_freq = freq;
- wpa_s->pending_listen_duration = duration;
+ wpa_s->pending_listen_freq = lwork->freq;
+ wpa_s->pending_listen_duration = lwork->duration;
- if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {
+ duration = lwork->duration;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+ duration, duration + wpa_s->extra_roc_dur);
+ duration += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
"to remain on channel (%u MHz) for Listen "
- "state", freq);
+ "state", lwork->freq);
+ wpas_p2p_listen_work_done(wpa_s);
wpa_s->pending_listen_freq = 0;
- return -1;
+ return;
}
wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = freq;
+ wpa_s->roc_waiting_drv_freq = lwork->freq;
+}
+
+
+static int wpas_start_listen(void *ctx, unsigned int freq,
+ unsigned int duration,
+ const struct wpabuf *probe_resp_ie)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpas_p2p_listen_work *lwork;
+
+ if (wpa_s->p2p_listen_work) {
+ wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists");
+ return -1;
+ }
+
+ lwork = os_zalloc(sizeof(*lwork));
+ if (lwork == NULL)
+ return -1;
+ lwork->freq = freq;
+ lwork->duration = duration;
+ if (probe_resp_ie) {
+ lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie);
+ if (lwork->probe_resp_ie == NULL) {
+ wpas_p2p_listen_work_free(lwork);
+ return -1;
+ }
+ }
+
+ if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb,
+ lwork) < 0) {
+ wpas_p2p_listen_work_free(lwork);
+ return -1;
+ }
return 0;
}
@@ -1237,6 +2377,7 @@ static void wpas_stop_listen(void *ctx)
}
wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
wpa_drv_probe_req_report(wpa_s, 0);
+ wpas_p2p_listen_work_done(wpa_s);
}
@@ -1411,8 +2552,8 @@ wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version,
}
-static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
- u8 srv_trans_id)
+static void wpas_sd_add_empty(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id, u8 status)
{
u8 *len_pos;
@@ -1424,12 +2565,35 @@ static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
wpabuf_put_u8(resp, srv_proto);
wpabuf_put_u8(resp, srv_trans_id);
/* Status Code */
- wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE);
+ wpabuf_put_u8(resp, status);
/* Response Data: empty */
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
}
+static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+ P2P_SD_PROTO_NOT_AVAILABLE);
+}
+
+
+static void wpas_sd_add_bad_request(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id, P2P_SD_BAD_REQUEST);
+}
+
+
+static void wpas_sd_add_not_found(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+ P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+}
+
+
static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *resp, u8 srv_trans_id)
{
@@ -1737,8 +2901,150 @@ static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_WIFI_DISPLAY */
-void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
- u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+static int find_p2ps_substr(struct p2ps_advertisement *adv_data,
+ const u8 *needle, size_t needle_len)
+{
+ const u8 *haystack = (const u8 *) adv_data->svc_info;
+ size_t haystack_len, i;
+
+ /* Allow search term to be empty */
+ if (!needle || !needle_len)
+ return 1;
+
+ if (!haystack)
+ return 0;
+
+ haystack_len = os_strlen(adv_data->svc_info);
+ for (i = 0; i < haystack_len; i++) {
+ if (haystack_len - i < needle_len)
+ break;
+ if (os_memcmp(haystack + i, needle, needle_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpas_sd_req_asp(struct wpa_supplicant *wpa_s,
+ struct wpabuf *resp, u8 srv_trans_id,
+ const u8 *query, size_t query_len)
+{
+ struct p2ps_advertisement *adv_data;
+ const u8 *svc = &query[1];
+ const u8 *info = NULL;
+ size_t svc_len = query[0];
+ size_t info_len = 0;
+ int prefix = 0;
+ u8 *count_pos = NULL;
+ u8 *len_pos = NULL;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: SD Request for ASP", query, query_len);
+
+ if (!wpa_s->global->p2p) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP protocol not available");
+ wpas_sd_add_proto_not_avail(resp, P2P_SERV_P2PS, srv_trans_id);
+ return;
+ }
+
+ /* Info block is optional */
+ if (svc_len + 1 < query_len) {
+ info = &svc[svc_len];
+ info_len = *info++;
+ }
+
+ /* Range check length of svc string and info block */
+ if (svc_len + (info_len ? info_len + 2 : 1) > query_len) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP bad request");
+ wpas_sd_add_bad_request(resp, P2P_SERV_P2PS, srv_trans_id);
+ return;
+ }
+
+ /* Detect and correct for prefix search */
+ if (svc_len && svc[svc_len - 1] == '*') {
+ prefix = 1;
+ svc_len--;
+ }
+
+ for (adv_data = p2p_get_p2ps_adv_list(wpa_s->global->p2p);
+ adv_data; adv_data = adv_data->next) {
+ /* If not a prefix match, reject length mismatches */
+ if (!prefix && svc_len != os_strlen(adv_data->svc_name))
+ continue;
+
+ /* Search each service for request */
+ if (os_memcmp(adv_data->svc_name, svc, svc_len) == 0 &&
+ find_p2ps_substr(adv_data, info, info_len)) {
+ size_t len = os_strlen(adv_data->svc_name);
+ size_t svc_info_len = 0;
+
+ if (adv_data->svc_info)
+ svc_info_len = os_strlen(adv_data->svc_info);
+
+ if (len > 0xff || svc_info_len > 0xffff)
+ return;
+
+ /* Length & Count to be filled as we go */
+ if (!len_pos && !count_pos) {
+ if (wpabuf_tailroom(resp) <
+ len + svc_info_len + 16)
+ return;
+
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_P2PS);
+ wpabuf_put_u8(resp, srv_trans_id);
+ /* Status Code */
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+ count_pos = wpabuf_put(resp, 1);
+ *count_pos = 0;
+ } else if (wpabuf_tailroom(resp) <
+ len + svc_info_len + 10)
+ return;
+
+ if (svc_info_len) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add Svc: %s info: %s",
+ adv_data->svc_name,
+ adv_data->svc_info);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Add Svc: %s",
+ adv_data->svc_name);
+ }
+
+ /* Advertisement ID */
+ wpabuf_put_le32(resp, adv_data->id);
+
+ /* Config Methods */
+ wpabuf_put_be16(resp, adv_data->config_methods);
+
+ /* Service Name */
+ wpabuf_put_u8(resp, (u8) len);
+ wpabuf_put_data(resp, adv_data->svc_name, len);
+
+ /* Service State */
+ wpabuf_put_u8(resp, adv_data->state);
+
+ /* Service Information */
+ wpabuf_put_le16(resp, (u16) svc_info_len);
+ wpabuf_put_data(resp, adv_data->svc_info, svc_info_len);
+
+ /* Update length and count */
+ (*count_pos)++;
+ WPA_PUT_LE16(len_pos,
+ (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+ }
+ }
+
+ /* Return error if no matching svc found */
+ if (count_pos == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP service not found");
+ wpas_sd_add_not_found(resp, P2P_SERV_P2PS, srv_trans_id);
+ }
+}
+
+
+static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+ u16 update_indic, const u8 *tlvs, size_t tlvs_len)
{
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos = tlvs;
@@ -1834,6 +3140,10 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
pos, tlv_end - pos);
break;
#endif /* CONFIG_WIFI_DISPLAY */
+ case P2P_SERV_P2PS:
+ wpas_sd_req_asp(wpa_s, resp, srv_trans_id,
+ pos, tlv_end - pos);
+ break;
default:
wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
"protocol %u", srv_proto);
@@ -1855,8 +3165,82 @@ done:
}
-void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len)
+static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u8 srv_trans_id,
+ const u8 *pos, const u8 *tlv_end)
+{
+ u8 left = *pos++;
+ u32 adv_id;
+ u8 svc_status;
+ u16 config_methods;
+ char svc_str[256];
+
+ while (left-- && pos < tlv_end) {
+ char *buf = NULL;
+ size_t buf_len;
+ u8 svc_len;
+
+ /* Sanity check fixed length+svc_str */
+ if (pos + 6 >= tlv_end)
+ break;
+ svc_len = pos[6];
+ if (pos + svc_len + 10 > tlv_end)
+ break;
+
+ /* Advertisement ID */
+ adv_id = WPA_GET_LE32(pos);
+ pos += sizeof(u32);
+
+ /* Config Methods */
+ config_methods = WPA_GET_BE16(pos);
+ pos += sizeof(u16);
+
+ /* Service Name */
+ pos++; /* svc_len */
+ os_memcpy(svc_str, pos, svc_len);
+ svc_str[svc_len] = '\0';
+ pos += svc_len;
+
+ /* Service Status */
+ svc_status = *pos++;
+
+ /* Service Information Length */
+ buf_len = WPA_GET_LE16(pos);
+ pos += sizeof(u16);
+
+ /* Sanity check buffer length */
+ if (buf_len > (unsigned int) (tlv_end - pos))
+ break;
+
+ if (buf_len) {
+ buf = os_zalloc(2 * buf_len + 1);
+ if (buf) {
+ utf8_escape((const char *) pos, buf_len, buf,
+ 2 * buf_len + 1);
+ }
+ }
+
+ pos += buf_len;
+
+ if (buf) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+ MACSTR " %x %x %x %x %s '%s'",
+ MAC2STR(sa), srv_trans_id, adv_id,
+ svc_status, config_methods, svc_str,
+ buf);
+ os_free(buf);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+ MACSTR " %x %x %x %x %s",
+ MAC2STR(sa), srv_trans_id, adv_id,
+ svc_status, config_methods, svc_str);
+ }
+ }
+}
+
+
+static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
{
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos = tlvs;
@@ -1913,6 +3297,11 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
pos, tlv_end - pos);
+ if (srv_proto == P2P_SERV_P2PS && pos < tlv_end) {
+ wpas_sd_p2ps_serv_response(wpa_s, sa, srv_trans_id,
+ pos, tlv_end);
+ }
+
pos = tlv_end;
}
@@ -1923,8 +3312,6 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
@@ -1951,13 +3338,44 @@ u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
}
+u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
+ const char *svc_str, const char *info_substr)
+{
+ struct wpabuf *tlvs;
+ size_t plen, svc_len, substr_len = 0;
+ u64 ret;
+
+ svc_len = os_strlen(svc_str);
+ if (info_substr)
+ substr_len = os_strlen(info_substr);
+
+ if (svc_len > 0xff || substr_len > 0xff)
+ return 0;
+
+ plen = 1 + 1 + 1 + svc_len + 1 + substr_len;
+ tlvs = wpabuf_alloc(2 + plen);
+ if (tlvs == NULL)
+ return 0;
+
+ wpabuf_put_le16(tlvs, plen);
+ wpabuf_put_u8(tlvs, P2P_SERV_P2PS);
+ wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+ wpabuf_put_u8(tlvs, (u8) svc_len); /* Service String Length */
+ wpabuf_put_data(tlvs, svc_str, svc_len);
+ wpabuf_put_u8(tlvs, (u8) substr_len); /* Info Substring Length */
+ wpabuf_put_data(tlvs, info_substr, substr_len);
+ ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+ wpabuf_free(tlvs);
+
+ return ret;
+}
+
+
#ifdef CONFIG_WIFI_DISPLAY
static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
@@ -2035,8 +3453,6 @@ u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_sd_cancel_request(wpa_s, req);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
return p2p_sd_cancel_request(wpa_s->global->p2p,
@@ -2048,11 +3464,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
const u8 *dst, u8 dialog_token,
const struct wpabuf *resp_tlvs)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
- resp_tlvs);
- return;
- }
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
@@ -2062,10 +3473,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_service_update(wpa_s);
- return;
- }
if (wpa_s->global->p2p)
p2p_sd_service_update(wpa_s->global->p2p);
}
@@ -2105,6 +3512,35 @@ void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s)
}
+int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+ if (adv_id == 0)
+ return 1;
+
+ if (p2p_service_p2ps_id(wpa_s->global->p2p, adv_id))
+ return 1;
+
+ return 0;
+}
+
+
+int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+ return p2p_service_del_asp(wpa_s->global->p2p, adv_id);
+}
+
+
+int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s,
+ int auto_accept, u32 adv_id,
+ const char *adv_str, u8 svc_state,
+ u16 config_methods, const char *svc_info)
+{
+ return p2p_service_add_asp(wpa_s->global->p2p, auto_accept, adv_id,
+ adv_str, svc_state, config_methods,
+ svc_info);
+}
+
+
int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *query, struct wpabuf *resp)
{
@@ -2177,24 +3613,24 @@ static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s,
const u8 *peer, const char *params,
unsigned int generated_pin)
{
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR " %08d%s",
- MAC2STR(peer), generated_pin, params);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR
+ " %08d%s", MAC2STR(peer), generated_pin, params);
}
static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s,
const u8 *peer, const char *params)
{
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR "%s",
- MAC2STR(peer), params);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR
+ "%s", MAC2STR(peer), params);
}
-void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
- const u8 *dev_addr, const u8 *pri_dev_type,
- const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab, const u8 *group_id,
- size_t group_id_len)
+static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+ const u8 *dev_addr, const u8 *pri_dev_type,
+ const char *dev_name, u16 supp_config_methods,
+ u8 dev_capab, u8 group_capab, const u8 *group_id,
+ size_t group_id_len)
{
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -2202,6 +3638,7 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
u8 empty_dev_type[8];
unsigned int generated_pin = 0;
struct wpa_supplicant *group = NULL;
+ int res;
if (group_id) {
for (group = wpa_s->global->ifaces; group; group = group->next)
@@ -2220,15 +3657,17 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
pri_dev_type = empty_dev_type;
}
- os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
- " pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x%s%s",
- MAC2STR(dev_addr),
- wps_dev_type_bin2str(pri_dev_type, devtype,
- sizeof(devtype)),
- dev_name, supp_config_methods, dev_capab, group_capab,
- group ? " group=" : "",
- group ? group->ifname : "");
+ res = os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s' config_methods=0x%x "
+ "dev_capab=0x%x group_capab=0x%x%s%s",
+ MAC2STR(dev_addr),
+ wps_dev_type_bin2str(pri_dev_type, devtype,
+ sizeof(devtype)),
+ dev_name, supp_config_methods, dev_capab, group_capab,
+ group ? " group=" : "",
+ group ? group->ifname : "");
+ if (os_snprintf_error(sizeof(params), res))
+ wpa_printf(MSG_DEBUG, "P2P: PD Request event truncated");
params[sizeof(params) - 1] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY) {
@@ -2238,8 +3677,8 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
} else if (config_methods & WPS_CONFIG_KEYPAD)
wpas_prov_disc_local_keypad(wpa_s, peer, params);
else if (config_methods & WPS_CONFIG_PUSHBUTTON)
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
- "%s", MAC2STR(peer), params);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ
+ MACSTR "%s", MAC2STR(peer), params);
wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
P2P_PROV_DISC_SUCCESS,
@@ -2247,7 +3686,7 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
}
-void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
{
struct wpa_supplicant *wpa_s = ctx;
unsigned int generated_pin = 0;
@@ -2259,15 +3698,19 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
wpa_s->pending_pd_before_join = 0;
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation");
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
return;
}
if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
- wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
- os_snprintf(params, sizeof(params), " peer_go=%d",
- wpa_s->pending_pd_use == AUTO_PD_JOIN);
- else
+ wpa_s->pending_pd_use == AUTO_PD_GO_NEG) {
+ int res;
+
+ res = os_snprintf(params, sizeof(params), " peer_go=%d",
+ wpa_s->pending_pd_use == AUTO_PD_JOIN);
+ if (os_snprintf_error(sizeof(params), res))
+ params[sizeof(params) - 1] = '\0';
+ } else
params[0] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY)
@@ -2277,8 +3720,8 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
wpas_prov_disc_local_display(wpa_s, peer, params,
generated_pin);
} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR
- "%s", MAC2STR(peer), params);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP
+ MACSTR "%s", MAC2STR(peer), params);
wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
P2P_PROV_DISC_SUCCESS,
@@ -2287,13 +3730,18 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
- enum p2p_prov_disc_status status)
+ enum p2p_prov_disc_status status,
+ u32 adv_id, const u8 *adv_mac,
+ const char *deferred_session_resp)
{
struct wpa_supplicant *wpa_s = ctx;
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,
+ P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=PD-failed");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
return;
}
@@ -2303,33 +3751,96 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation (no ACK for PD "
"Req attempts)");
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
return;
}
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
- " p2p_dev_addr=" MACSTR " status=%d",
- MAC2STR(peer), status);
+ if (adv_id && adv_mac && deferred_session_resp) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d adv_id=%x"
+ " deferred_session_resp='%s'",
+ MAC2STR(peer), status, adv_id,
+ deferred_session_resp);
+ } else if (adv_id && adv_mac) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d adv_id=%x",
+ MAC2STR(peer), status, adv_id);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d",
+ MAC2STR(peer), status);
+ }
wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
status, 0, 0);
}
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+ if (channels == NULL)
+ return 1; /* Assume no restrictions */
+ return p2p_channels_includes_freq(channels, freq);
+
+}
+
+
+/**
+ * Pick the best frequency to use from all the currently used frequencies.
+ */
+static int wpas_p2p_pick_best_used_freq(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs,
+ unsigned int num)
+{
+ unsigned int i, c;
+
+ /* find a candidate freq that is supported by P2P */
+ for (c = 0; c < num; c++)
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[c].freq))
+ break;
+
+ if (c == num)
+ return 0;
+
+ /* once we have a candidate, try to find a 'better' one */
+ for (i = c + 1; i < num; i++) {
+ if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
+ continue;
+
+ /*
+ * 1. Infrastructure station interfaces have higher preference.
+ * 2. P2P Clients have higher preference.
+ * 3. All others.
+ */
+ if (freqs[i].flags & WPA_FREQ_USED_BY_INFRA_STATION) {
+ c = i;
+ break;
+ }
+
+ if ((freqs[i].flags & WPA_FREQ_USED_BY_P2P_CLIENT))
+ c = i;
+ }
+ return freqs[c].freq;
+}
+
+
static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group)
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels,
+ int dev_pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
- u8 cur_bssid[ETH_ALEN];
- int res;
+ struct wpa_used_freq_data *freqs;
struct wpa_supplicant *grp;
+ int best_freq;
if (!persistent_group) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
- " to join an active group", MAC2STR(sa));
+ " to join an active group (SSID: %s)",
+ MAC2STR(sa), wpa_ssid_txt(ssid, ssid_len));
if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
(os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
== 0 ||
@@ -2338,6 +3849,21 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
"authorized invitation");
goto accept_inv;
}
+
+#ifdef CONFIG_WPS_NFC
+ if (dev_pw_id >= 0 && wpa_s->p2p_nfc_tag_enabled &&
+ dev_pw_id == wpa_s->p2p_oob_dev_pw_id) {
+ wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag");
+ wpa_s->p2p_wps_method = WPS_NFC;
+ wpa_s->pending_join_wps_method = WPS_NFC;
+ os_memcpy(wpa_s->pending_join_dev_addr,
+ go_dev_addr, ETH_ALEN);
+ os_memcpy(wpa_s->pending_join_iface_addr,
+ bssid, ETH_ALEN);
+ goto accept_inv;
+ }
+#endif /* CONFIG_WPS_NFC */
+
/*
* Do not accept the invitation automatically; notify user and
* request approval.
@@ -2354,7 +3880,12 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
goto accept_inv;
}
- if (!wpa_s->conf->persistent_reconnect)
+ if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
+ os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
+ "invitation to re-invoke a persistent group");
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ } else if (!wpa_s->conf->persistent_reconnect)
return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
for (s = wpa_s->conf->ssid; s; s = s->next) {
@@ -2394,19 +3925,47 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
}
accept_inv:
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 &&
- wpa_s->assoc_freq) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
- "the channel we are already using");
- *force_freq = wpa_s->assoc_freq;
+ wpas_p2p_set_own_freq_preference(wpa_s, 0);
+
+ best_freq = 0;
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
+ if (freqs) {
+ int num_channels = wpa_s->num_multichan_concurrent;
+ int num = wpas_p2p_valid_oper_freqs(wpa_s, freqs, num_channels);
+ best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+ os_free(freqs);
+ }
+
+ /* Get one of the frequencies currently in use */
+ if (best_freq > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces");
+ wpas_p2p_set_own_freq_preference(wpa_s, best_freq);
+
+ if (wpa_s->num_multichan_concurrent < 2 ||
+ wpas_p2p_num_unused_channels(wpa_s) < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces");
+ *force_freq = best_freq;
+ }
}
- res = wpa_drv_shared_freq(wpa_s);
- if (res > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
- "with the channel we are already using on a "
- "shared interface");
- *force_freq = res;
+ if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ if (*go == 0) {
+ /* We are the client */
+ wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
+ "running a GO but we are capable of MCC, "
+ "figure out the best channel to use");
+ *force_freq = 0;
+ } else if (!freq_included(channels, *force_freq)) {
+ /* We are the GO, and *force_freq is not in the
+ * intersection */
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "in intersection but we are capable of MCC, "
+ "figure out the best channel to use",
+ *force_freq);
+ *force_freq = 0;
+ }
}
return P2P_SC_SUCCESS;
@@ -2430,16 +3989,18 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
if (status == P2P_SC_SUCCESS) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
- " was accepted; op_freq=%d MHz",
- MAC2STR(sa), op_freq);
+ " was accepted; op_freq=%d MHz, SSID=%s",
+ MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, go, go ? op_freq : 0, 0);
+ wpa_s, s, go, 0, op_freq, 0, 0, NULL,
+ go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
- wpa_s->p2p_wps_method, 0);
+ wpa_s->p2p_wps_method, 0, op_freq,
+ ssid, ssid_len);
}
return;
}
@@ -2452,44 +4013,131 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
if (!s) {
if (bssid) {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
- "sa=" MACSTR " go_dev_addr=" MACSTR
- " bssid=" MACSTR " unknown-network",
- MAC2STR(sa), MAC2STR(go_dev_addr),
- MAC2STR(bssid));
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " go_dev_addr=" MACSTR
+ " bssid=" MACSTR " unknown-network",
+ MAC2STR(sa), MAC2STR(go_dev_addr),
+ MAC2STR(bssid));
} else {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
- "sa=" MACSTR " go_dev_addr=" MACSTR
- " unknown-network",
- MAC2STR(sa), MAC2STR(go_dev_addr));
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " go_dev_addr=" MACSTR
+ " unknown-network",
+ MAC2STR(sa), MAC2STR(go_dev_addr));
}
return;
}
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR
- " persistent=%d", MAC2STR(sa), s->id);
+ if (s->mode == WPAS_MODE_P2P_GO && op_freq) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " persistent=%d freq=%d",
+ MAC2STR(sa), s->id, op_freq);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+ "sa=" MACSTR " persistent=%d",
+ MAC2STR(sa), s->id);
+ }
+}
+
+
+static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const u8 *peer, int inv)
+{
+ size_t i;
+
+ if (ssid == NULL)
+ return;
+
+ for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
+ if (os_memcmp(ssid->p2p_client_list + i * 2 * ETH_ALEN, peer,
+ ETH_ALEN) == 0)
+ break;
+ }
+ if (i >= ssid->num_p2p_clients || !ssid->p2p_client_list) {
+ if (ssid->mode != WPAS_MODE_P2P_GO &&
+ os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d "
+ "due to invitation result", ssid->id);
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return;
+ }
+ return; /* Peer not found in client list */
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent "
+ "group %d client list%s",
+ MAC2STR(peer), ssid->id,
+ inv ? " due to invitation result" : "");
+ os_memmove(ssid->p2p_client_list + i * 2 * ETH_ALEN,
+ ssid->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (ssid->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
+ ssid->num_p2p_clients--;
+ if (wpa_s->parent->conf->update_config &&
+ wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
}
-static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
+static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
+ const u8 *peer)
+{
+ struct wpa_ssid *ssid;
+
+ wpa_s = wpa_s->global->p2p_invite_group;
+ if (wpa_s == NULL)
+ return; /* No known invitation group */
+ ssid = wpa_s->current_ssid;
+ 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->ssid, ssid->ssid_len);
+ wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
+}
+
+
+static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
+ const struct p2p_channels *channels,
+ const u8 *peer, int neg_freq,
+ int peer_oper_freq)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
+ int freq;
if (bssid) {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
- "status=%d " MACSTR,
- status, MAC2STR(bssid));
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+ "status=%d " MACSTR,
+ status, MAC2STR(bssid));
} else {
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
- "status=%d ", status);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+ "status=%d ", status);
}
wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
- if (wpa_s->pending_invite_ssid_id == -1)
+ wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
+ status, MAC2STR(peer));
+ if (wpa_s->pending_invite_ssid_id == -1) {
+ if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
+ wpas_remove_persistent_client(wpa_s, peer);
return; /* Invitation to active group */
+ }
+
+ if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+ wpa_printf(MSG_DEBUG, "P2P: Waiting for peer to start another "
+ "invitation exchange to indicate readiness for "
+ "re-invocation");
+ }
if (status != P2P_SC_SUCCESS) {
+ if (status == P2P_SC_FAIL_UNKNOWN_GROUP) {
+ ssid = wpa_config_get_network(
+ wpa_s->conf, wpa_s->pending_invite_ssid_id);
+ wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
+ }
wpas_p2p_remove_pending_group_interface(wpa_s);
return;
}
@@ -2514,28 +4162,35 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
"starting persistent group");
os_sleep(0, 50000);
+ if (neg_freq > 0 && ssid->mode == WPAS_MODE_P2P_GO &&
+ freq_included(channels, neg_freq))
+ freq = neg_freq;
+ else if (peer_oper_freq > 0 && ssid->mode != WPAS_MODE_P2P_GO &&
+ freq_included(channels, peer_oper_freq))
+ freq = peer_oper_freq;
+ else
+ freq = 0;
+
+ wpa_printf(MSG_DEBUG, "P2P: Persistent group invitation success - op_freq=%d MHz SSID=%s",
+ freq, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
- wpa_s->p2p_go_ht40);
+ freq,
+ wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+ channels,
+ ssid->mode == WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+ 0);
}
static int wpas_p2p_disallowed_freq(struct wpa_global *global,
unsigned int freq)
{
- unsigned int i;
-
- if (global->p2p_disallow_freq == NULL)
- return 0;
-
- for (i = 0; i < global->num_p2p_disallow_freq; i++) {
- if (freq >= global->p2p_disallow_freq[i].min &&
- freq <= global->p2p_disallow_freq[i].max)
- return 1;
- }
-
- return 0;
+ if (freq_range_list_includes(&global->p2p_go_avoid_freq, freq))
+ return 1;
+ return freq_range_list_includes(&global->p2p_disallow_freq, freq);
}
@@ -2547,10 +4202,15 @@ static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
- struct p2p_channels *chan)
+ struct p2p_channels *chan,
+ struct p2p_channels *cli_chan)
{
int i, cla = 0;
+ wpa_s->global->p2p_24ghz_social_channels = 1;
+
+ os_memset(cli_chan, 0, sizeof(*cli_chan));
+
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
"band");
@@ -2618,6 +4278,10 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
}
+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)
{
@@ -2627,21 +4291,23 @@ static int has_channel(struct wpa_global *global,
freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
chan * 5;
if (wpas_p2p_disallowed_freq(global, freq))
- return 0;
+ return NOT_ALLOWED;
for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].chan == chan) {
if (flags)
*flags = mode->channels[i].flag;
- return !(mode->channels[i].flag &
- (HOSTAPD_CHAN_DISABLED |
- HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_NO_IBSS |
- HOSTAPD_CHAN_RADAR));
+ if (mode->channels[i].flag &
+ (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ return NOT_ALLOWED;
+ if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+ return NO_IR;
+ return ALLOWED;
}
}
- return 0;
+ return NOT_ALLOWED;
}
@@ -2651,7 +4317,7 @@ struct p2p_oper_class_map {
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS } bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160 } bw;
};
static struct p2p_oper_class_map op_class[] = {
@@ -2666,73 +4332,174 @@ static struct p2p_oper_class_map op_class[] = {
{ 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_verify_channel(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode,
- u8 channel, u8 bw)
+static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
{
- int flag;
+ u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+ unsigned int i;
- if (!has_channel(wpa_s->global, mode, channel, &flag))
- return -1;
- if (bw == BW40MINUS &&
- (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
- !has_channel(wpa_s->global, mode, channel - 4, NULL)))
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- if (bw == BW40PLUS &&
- (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
- !has_channel(wpa_s->global, mode, channel + 4, NULL)))
- return 0;
- return 1;
+
+ 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 wpas_p2p_verify_80mhz(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_80mhz(wpa_s, mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+ if (center_chan >= 58 && center_chan <= 138)
+ return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
+
+ /* check all the channels are available */
+ for (i = 0; i < 4; i++) {
+ int adj_chan = center_chan - 6 + 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_70))
+ return NOT_ALLOWED;
+ if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+ return NOT_ALLOWED;
+ if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+ return NOT_ALLOWED;
+ if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_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)
+{
+ int flag = 0;
+ enum chan_allowed res, res2;
+
+ res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+ if (bw == BW40MINUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+ return NOT_ALLOWED;
+ res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+ } else if (bw == BW40PLUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+ return NOT_ALLOWED;
+ res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+ } else if (bw == BW80) {
+ res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+ }
+
+ if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+ return NOT_ALLOWED;
+ if (res == NO_IR || res2 == NO_IR)
+ return NO_IR;
+ return res;
}
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
- struct p2p_channels *chan)
+ struct p2p_channels *chan,
+ struct p2p_channels *cli_chan)
{
struct hostapd_hw_modes *mode;
- int cla, op;
+ int cla, op, cli_cla;
if (wpa_s->hw.modes == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
"of all supported channels; assume dualband "
"support");
- return wpas_p2p_default_channels(wpa_s, chan);
+ return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
}
- cla = 0;
+ cla = cli_cla = 0;
for (op = 0; op_class[op].op_class; op++) {
struct p2p_oper_class_map *o = &op_class[op];
u8 ch;
- struct p2p_reg_class *reg = NULL;
+ struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G)
+ wpa_s->global->p2p_24ghz_social_channels = 1;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
- if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
- continue;
- if (reg == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Add operating "
- "class %u", o->op_class);
- reg = &chan->reg_class[cla];
- cla++;
- reg->reg_class = o->op_class;
+ enum chan_allowed res;
+ res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+ if (res == ALLOWED) {
+ if (reg == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
+ o->op_class);
+ reg = &chan->reg_class[cla];
+ cla++;
+ reg->reg_class = o->op_class;
+ }
+ reg->channel[reg->channels] = ch;
+ reg->channels++;
+ } else if (res == NO_IR &&
+ wpa_s->conf->p2p_add_cli_chan) {
+ if (cli_reg == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
+ o->op_class);
+ cli_reg = &cli_chan->reg_class[cli_cla];
+ cli_cla++;
+ cli_reg->reg_class = o->op_class;
+ }
+ cli_reg->channel[cli_reg->channels] = ch;
+ cli_reg->channels++;
}
- reg->channel[reg->channels] = ch;
- reg->channels++;
}
if (reg) {
wpa_hexdump(MSG_DEBUG, "P2P: Channels",
reg->channel, reg->channels);
}
+ if (cli_reg) {
+ wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)",
+ cli_reg->channel, cli_reg->channels);
+ }
}
chan->reg_classes = cla;
+ cli_chan->reg_classes = cli_cla;
return 0;
}
@@ -2741,7 +4508,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel)
{
- int op, ret;
+ int op;
+ enum chan_allowed ret;
for (op = 0; op_class[op].op_class; op++) {
struct p2p_oper_class_map *o = &op_class[op];
@@ -2752,18 +4520,24 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
o->bw == BW20 || ch != channel)
continue;
ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
- if (ret < 0)
- continue;
- else if (ret > 0)
+ if (ret == ALLOWED)
return (o->bw == BW40MINUS) ? -1 : 1;
- else
- return 0;
}
}
return 0;
}
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+ return 0;
+
+ return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+}
+
+
static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
size_t buf_len)
{
@@ -2780,10 +4554,31 @@ static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
}
-static int wpas_go_connected(void *ctx, const u8 *dev_addr)
+struct wpa_supplicant * wpas_get_p2p_go_iface(struct wpa_supplicant *wpa_s,
+ const u8 *ssid, size_t ssid_len)
{
- struct wpa_supplicant *wpa_s = ctx;
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ struct wpa_ssid *s = wpa_s->current_ssid;
+ if (s == NULL)
+ continue;
+ if (s->mode != WPAS_MODE_P2P_GO &&
+ s->mode != WPAS_MODE_AP &&
+ s->mode != WPAS_MODE_P2P_GROUP_FORMATION)
+ continue;
+ if (s->ssid_len != ssid_len ||
+ os_memcmp(ssid, s->ssid, ssid_len) != 0)
+ continue;
+ return wpa_s;
+ }
+
+ return NULL;
+
+}
+
+struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s,
+ const u8 *peer_dev_addr)
+{
for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
struct wpa_ssid *ssid = wpa_s->current_ssid;
if (ssid == NULL)
@@ -2793,14 +4588,486 @@ static int wpas_go_connected(void *ctx, const u8 *dev_addr)
if (wpa_s->wpa_state != WPA_COMPLETED &&
wpa_s->wpa_state != WPA_GROUP_HANDSHAKE)
continue;
- if (os_memcmp(wpa_s->go_dev_addr, dev_addr, ETH_ALEN) == 0)
+ if (os_memcmp(wpa_s->go_dev_addr, peer_dev_addr, ETH_ALEN) == 0)
+ return wpa_s;
+ }
+
+ return NULL;
+}
+
+
+static int wpas_go_connected(void *ctx, const u8 *dev_addr)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpas_get_p2p_client_iface(wpa_s, dev_addr) != NULL;
+}
+
+
+static int wpas_is_concurrent_session_active(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *ifs;
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs == wpa_s)
+ continue;
+ if (ifs->wpa_state > WPA_ASSOCIATED)
return 1;
}
+ return 0;
+}
+
+
+static void wpas_p2p_debug_print(void *ctx, int level, const char *msg)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_msg_global(wpa_s, level, "P2P: %s", msg);
+}
+
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
+ const char *conf_p2p_dev)
+{
+ struct wpa_interface iface;
+ struct wpa_supplicant *p2pdev_wpa_s;
+ char ifname[100];
+ char force_name[100];
+ int ret;
+
+ ret = os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+ wpa_s->ifname);
+ if (os_snprintf_error(sizeof(ifname), ret))
+ return -1;
+ force_name[0] = '\0';
+ wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
+ ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+ force_name, wpa_s->pending_interface_addr, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
+ return ret;
+ }
+ os_strlcpy(wpa_s->pending_interface_name, ifname,
+ sizeof(wpa_s->pending_interface_name));
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.p2p_mgmt = 1;
+ iface.ifname = wpa_s->pending_interface_name;
+ iface.driver = wpa_s->driver->name;
+ iface.driver_param = wpa_s->conf->driver_param;
+
+ /*
+ * If a P2P Device configuration file was given, use it as the interface
+ * configuration file (instead of using parent's configuration file.
+ */
+ if (conf_p2p_dev) {
+ iface.confname = conf_p2p_dev;
+ iface.ctrl_interface = NULL;
+ } else {
+ iface.confname = wpa_s->confname;
+ iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+ }
+ iface.conf_p2p_dev = NULL;
+
+ p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
+ if (!p2pdev_wpa_s) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
+ return -1;
+ }
+ wpa_s->p2p_dev = p2pdev_wpa_s;
+
+ wpa_s->pending_interface_name[0] = '\0';
return 0;
}
+static void wpas_presence_resp(void *ctx, const u8 *src, u8 status,
+ const u8 *noa, size_t noa_len)
+{
+ struct wpa_supplicant *wpa_s, *intf = ctx;
+ char hex[100];
+
+ for (wpa_s = intf->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_s->waiting_presence_resp)
+ break;
+ }
+ if (!wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No group interface was waiting for presence response");
+ return;
+ }
+ wpa_s->waiting_presence_resp = 0;
+
+ wpa_snprintf_hex(hex, sizeof(hex), noa, noa_len);
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PRESENCE_RESPONSE "src=" MACSTR
+ " status=%u noa=%s", MAC2STR(src), status, hex);
+}
+
+
+static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
+ size_t ssid_len, u8 *go_dev_addr,
+ u8 *ret_ssid, size_t *ret_ssid_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+
+ s = wpas_p2p_get_persistent(wpa_s, addr, ssid, ssid_len);
+ if (s) {
+ os_memcpy(ret_ssid, s->ssid, s->ssid_len);
+ *ret_ssid_len = s->ssid_len;
+ os_memcpy(go_dev_addr, s->bssid, ETH_ALEN);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_get_go_info(void *ctx, u8 *intended_addr,
+ u8 *ssid, size_t *ssid_len, int *group_iface)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+ u8 bssid[ETH_ALEN];
+
+ s = wpas_p2p_group_go_ssid(wpa_s, bssid);
+ if (!s) {
+ s = wpas_p2p_get_persistent_go(wpa_s);
+ if (s)
+ os_memcpy(bssid, s->bssid, ETH_ALEN);
+ }
+
+ *group_iface = wpas_p2p_create_iface(wpa_s);
+ if (!s)
+ return 0;
+
+ os_memcpy(intended_addr, bssid, ETH_ALEN);
+ os_memcpy(ssid, s->ssid, s->ssid_len);
+ *ssid_len = s->ssid_len;
+
+ return 1;
+}
+
+
+static int wpas_remove_stale_groups(void *ctx, const u8 *peer, const u8 *go,
+ const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+ int save_config = 0;
+ size_t i;
+
+ /* Start with our first choice of Persistent Groups */
+ while ((s = wpas_p2p_get_persistent(wpa_s, peer, NULL, 0))) {
+ if (go && ssid && ssid_len &&
+ s->ssid_len == ssid_len &&
+ os_memcmp(go, s->bssid, ETH_ALEN) == 0 &&
+ os_memcmp(ssid, s->ssid, ssid_len) == 0)
+ break;
+
+ /* Remove stale persistent group */
+ if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) {
+ wpa_config_remove_network(wpa_s->conf, s->id);
+ save_config = 1;
+ continue;
+ }
+
+ for (i = 0; i < s->num_p2p_clients; i++) {
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
+ peer, ETH_ALEN) != 0)
+ continue;
+
+ os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
+ s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
+ break;
+ }
+ s->num_p2p_clients--;
+ save_config = 1;
+ }
+
+ if (save_config)
+ p2p_config_write(wpa_s);
+
+ /* Return TRUE if valid SSID remains */
+ return s != NULL;
+}
+
+
+static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
+ const u8 *adv_mac, const u8 *ses_mac,
+ const u8 *grp_mac, u32 adv_id, u32 ses_id,
+ u8 conncap, int passwd_id,
+ const u8 *persist_ssid,
+ size_t persist_ssid_size, int response_done,
+ int prov_start, const char *session_info)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ u8 mac[ETH_ALEN];
+ struct wpa_ssid *persistent_go, *stale, *s;
+ int save_config = 0;
+ struct wpa_supplicant *go_wpa_s;
+
+ if (!dev)
+ return;
+
+ os_memset(mac, 0, ETH_ALEN);
+ if (!adv_mac)
+ adv_mac = mac;
+ if (!ses_mac)
+ ses_mac = mac;
+ if (!grp_mac)
+ grp_mac = mac;
+
+ if (prov_start) {
+ if (session_info == NULL) {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_START MACSTR
+ " adv_id=%x conncap=%x"
+ " adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " dev_passwd_id=%d",
+ MAC2STR(dev), adv_id, conncap,
+ MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_START MACSTR
+ " adv_id=%x conncap=%x"
+ " adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " dev_passwd_id=%d info='%s'",
+ MAC2STR(dev), adv_id, conncap,
+ MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id, session_info);
+ }
+ return;
+ }
+
+ go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+ persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+
+ if (status && status != P2P_SC_SUCCESS_DEFERRED) {
+ if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+ wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+ if (persistent_go && !persistent_go->num_p2p_clients) {
+ /* remove empty persistent GO */
+ wpa_config_remove_network(wpa_s->conf,
+ persistent_go->id);
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+ " status=%d"
+ " adv_id=%x adv_mac=" MACSTR
+ " session=%x mac=" MACSTR,
+ MAC2STR(dev), status,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac));
+ return;
+ }
+
+ /* Clean up stale persistent groups with this device */
+ s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
+ persist_ssid_size);
+ for (;;) {
+ stale = wpas_p2p_get_persistent(wpa_s, dev, NULL, 0);
+ if (!stale)
+ break;
+
+ if (s && s->ssid_len == stale->ssid_len &&
+ os_memcmp(stale->bssid, s->bssid, ETH_ALEN) == 0 &&
+ os_memcmp(stale->ssid, s->ssid, s->ssid_len) == 0)
+ break;
+
+ /* Remove stale persistent group */
+ if (stale->mode != WPAS_MODE_P2P_GO ||
+ stale->num_p2p_clients <= 1) {
+ wpa_config_remove_network(wpa_s->conf, stale->id);
+ } else {
+ size_t i;
+
+ for (i = 0; i < stale->num_p2p_clients; i++) {
+ if (os_memcmp(stale->p2p_client_list +
+ i * ETH_ALEN,
+ dev, ETH_ALEN) == 0) {
+ os_memmove(stale->p2p_client_list +
+ i * ETH_ALEN,
+ stale->p2p_client_list +
+ (i + 1) * ETH_ALEN,
+ (stale->num_p2p_clients -
+ i - 1) * ETH_ALEN);
+ break;
+ }
+ }
+ stale->num_p2p_clients--;
+ }
+ save_config = 1;
+ }
+
+ if (save_config)
+ p2p_config_write(wpa_s);
+
+ if (s) {
+ if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+ wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+ if (persistent_go && s != persistent_go &&
+ !persistent_go->num_p2p_clients) {
+ /* remove empty persistent GO */
+ wpa_config_remove_network(wpa_s->conf,
+ persistent_go->id);
+ /* Save config */
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+ " status=%d"
+ " adv_id=%x adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " persist=%d",
+ MAC2STR(dev), status,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac), s->id);
+ return;
+ }
+
+ if (conncap == P2PS_SETUP_GROUP_OWNER) {
+ const char *go_ifname = NULL;
+ if (!go_wpa_s) {
+ wpa_s->global->pending_p2ps_group = 1;
+
+ if (wpa_s->conf->p2p_no_group_iface)
+ go_ifname = wpa_s->ifname;
+ else if (wpa_s->pending_interface_name[0])
+ go_ifname = wpa_s->pending_interface_name;
+
+ if (!go_ifname) {
+ wpas_p2ps_prov_complete(
+ wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP,
+ dev, adv_mac, ses_mac,
+ NULL, adv_id, ses_id, 0, 0,
+ NULL, 0, 0, 0, NULL);
+ return;
+ }
+
+ /* If PD Resp complete, start up the GO */
+ if (response_done && persistent_go) {
+ wpas_p2p_group_add_persistent(
+ wpa_s, persistent_go,
+ 0, 0, 0, 0, 0, NULL,
+ persistent_go->mode ==
+ WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+ 0);
+ } else if (response_done) {
+ wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ }
+
+ if (passwd_id == DEV_PW_P2PS_DEFAULT) {
+ os_memcpy(wpa_s->p2ps_join_addr, dev, ETH_ALEN);
+ wpa_s->p2ps_join_addr_valid = 1;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2PS: Saving PIN for " MACSTR,
+ MAC2STR(dev));
+ }
+ } else if (passwd_id == DEV_PW_P2PS_DEFAULT) {
+ go_ifname = go_wpa_s->ifname;
+
+ wpa_dbg(go_wpa_s, MSG_DEBUG,
+ "P2P: Setting PIN-1 For " MACSTR, MAC2STR(dev));
+ wpa_supplicant_ap_wps_pin(go_wpa_s, dev, "12345670",
+ NULL, 0, 0);
+
+ os_memcpy(wpa_s->p2ps_join_addr, dev, ETH_ALEN);
+ wpa_s->p2ps_join_addr_valid = 1;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2PS: Saving PIN for " MACSTR, MAC2STR(dev));
+ }
+
+ 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 go=%s",
+ MAC2STR(dev), status, conncap,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id, go_ifname);
+ return;
+ }
+
+ if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+ wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+ if (persistent_go && !persistent_go->num_p2p_clients) {
+ /* remove empty persistent GO */
+ wpa_config_remove_network(wpa_s->conf, persistent_go->id);
+ }
+
+ if (conncap == P2PS_SETUP_CLIENT) {
+ 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,
+ MAC2STR(dev), status, conncap,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id, MAC2STR(grp_mac));
+ } else {
+ 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",
+ MAC2STR(dev), status, conncap,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id);
+ }
+}
+
+
+static int _wpas_p2p_in_progress(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpas_p2p_in_progress(wpa_s);
+}
+
+
+static int wpas_prov_disc_resp_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *persistent_go;
+
+ if (!wpa_s->global->pending_p2ps_group)
+ return 0;
+
+ wpa_s->global->pending_p2ps_group = 0;
+
+ if (wpas_p2p_get_go_group(wpa_s))
+ return 0;
+ persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+
+ if (persistent_go) {
+ wpas_p2p_group_add_persistent(
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, NULL,
+ persistent_go->mode == WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
+ } else {
+ wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ }
+
+ return 1;
+}
+
+
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
@@ -2810,37 +5077,20 @@ static int wpas_go_connected(void *ctx, const u8 *dev_addr)
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
{
struct p2p_config p2p;
- unsigned int r;
int i;
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+ if (wpa_s->conf->p2p_disabled)
return 0;
- if (global->p2p)
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
return 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- struct p2p_params params;
-
- wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
- os_memset(&params, 0, sizeof(params));
- params.dev_name = wpa_s->conf->device_name;
- os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
- WPS_DEV_TYPE_LEN);
- params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
- os_memcpy(params.sec_dev_type,
- wpa_s->conf->sec_device_type,
- params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
-
- if (wpa_drv_p2p_set_params(wpa_s, &params) < 0)
- return -1;
-
+ if (global->p2p)
return 0;
- }
os_memset(&p2p, 0, sizeof(p2p));
- p2p.msg_ctx = wpa_s;
p2p.cb_ctx = wpa_s;
+ p2p.debug_print = wpas_p2p_debug_print;
p2p.p2p_scan = wpas_p2p_scan;
p2p.send_action = wpas_send_action;
p2p.send_action_done = wpas_send_action_done;
@@ -2848,6 +5098,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.go_neg_req_rx = wpas_go_neg_req_rx;
p2p.dev_found = wpas_dev_found;
p2p.dev_lost = wpas_dev_lost;
+ p2p.find_stopped = wpas_find_stopped;
p2p.start_listen = wpas_start_listen;
p2p.stop_listen = wpas_stop_listen;
p2p.send_probe_resp = wpas_send_probe_resp;
@@ -2861,6 +5112,15 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.invitation_result = wpas_invitation_result;
p2p.get_noa = wpas_get_noa;
p2p.go_connected = wpas_go_connected;
+ p2p.presence_resp = wpas_presence_resp;
+ p2p.is_concurrent_session_active = wpas_is_concurrent_session_active;
+ p2p.is_p2p_in_progress = _wpas_p2p_in_progress;
+ p2p.get_persistent_group = wpas_get_persistent_group;
+ p2p.get_go_info = wpas_get_go_info;
+ p2p.remove_stale_groups = wpas_remove_stale_groups;
+ p2p.p2ps_prov_complete = wpas_p2ps_prov_complete;
+ p2p.prov_disc_resp_cb = wpas_prov_disc_resp_cb;
+ p2p.p2ps_group_capability = p2ps_group_capability;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -2874,20 +5134,32 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.config_methods = wpa_s->wps->config_methods;
}
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to configure supported channel list");
+ return -1;
+ }
+
if (wpa_s->conf->p2p_listen_reg_class &&
wpa_s->conf->p2p_listen_channel) {
p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
p2p.channel = wpa_s->conf->p2p_listen_channel;
+ p2p.channel_forced = 1;
} else {
- p2p.reg_class = 81;
/*
* Pick one of the social channels randomly as the listen
* channel.
*/
- os_get_random((u8 *) &r, sizeof(r));
- p2p.channel = 1 + (r % 3) * 5;
+ if (p2p_config_get_random_social(&p2p, &p2p.reg_class,
+ &p2p.channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to select random social channel as listen channel");
+ return -1;
+ }
+ p2p.channel_forced = 0;
}
- wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
+ wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d:%d",
+ p2p.reg_class, p2p.channel);
if (wpa_s->conf->p2p_oper_reg_class &&
wpa_s->conf->p2p_oper_channel) {
@@ -2898,29 +5170,33 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
"%d:%d", p2p.op_reg_class, p2p.op_channel);
} else {
- p2p.op_reg_class = 81;
/*
- * Use random operation channel from (1, 6, 11) if no other
- * preference is indicated.
+ * Use random operation channel from 2.4 GHz band social
+ * channels (1, 6, 11) or band 60 GHz social channel (2) if no
+ * other preference is indicated.
*/
- os_get_random((u8 *) &r, sizeof(r));
- p2p.op_channel = 1 + (r % 3) * 5;
+ if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,
+ &p2p.op_channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to select random social channel as operation channel");
+ return -1;
+ }
p2p.cfg_op_channel = 0;
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
"%d:%d", p2p.op_reg_class, p2p.op_channel);
}
+
+ if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) {
+ p2p.pref_chan = wpa_s->conf->p2p_pref_chan;
+ p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan;
+ }
+
if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
os_memcpy(p2p.country, wpa_s->conf->country, 2);
p2p.country[2] = 0x04;
} else
os_memcpy(p2p.country, "XX\x04", 3);
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
- wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
- "channel list");
- return -1;
- }
-
os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,
WPS_DEV_TYPE_LEN);
@@ -2946,6 +5222,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.max_listen = wpa_s->max_remain_on_chan;
+ if (wpa_s->conf->p2p_passphrase_len >= 8 &&
+ wpa_s->conf->p2p_passphrase_len <= 63)
+ p2p.passphrase_len = wpa_s->conf->p2p_passphrase_len;
+ else
+ p2p.passphrase_len = 8;
+
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
@@ -2958,6 +5240,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
global->p2p, wpa_s->conf->wps_vendor_ext[i]);
}
+ p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);
+
return 0;
}
@@ -2982,12 +5266,28 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
+ eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+ wpas_p2p_listen_work_done(wpa_s);
+ if (wpa_s->p2p_send_action_work) {
+ 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;
+ }
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
+
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
+
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = NULL;
+ wpa_s->p2p_group_common_freqs_num = 0;
/* TODO: remove group interface from the driver if this wpa_s instance
* is on top of a P2P group interface */
@@ -3000,16 +5300,13 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
*
* This function deinitializes the global (per device) P2P module.
*/
-void wpas_p2p_deinit_global(struct wpa_global *global)
+static void wpas_p2p_deinit_global(struct wpa_global *global)
{
struct wpa_supplicant *wpa_s, *tmp;
wpa_s = global->ifaces;
- if (wpa_s)
- wpas_p2p_service_flush(wpa_s);
- if (global->p2p == NULL)
- return;
+ wpas_p2p_service_flush(global->p2p_init_wpa_s);
/* Remove remaining P2P group interfaces */
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
@@ -3044,7 +5341,8 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->conf->p2p_no_group_iface)
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+ 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 |
@@ -3071,12 +5369,6 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
- go_intent, own_interface_addr,
- force_freq, persistent_group);
- }
-
/*
* Increase GO config timeout if HT40 is used since it takes some time
* to scan channels for coex purposes before the BSS can be started.
@@ -3088,7 +5380,9 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
ssid ? ssid->ssid_len : 0,
- wpa_s->p2p_pd_before_go_neg, pref_freq);
+ wpa_s->p2p_pd_before_go_neg, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
@@ -3102,13 +5396,12 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
-
return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
- ssid ? ssid->ssid_len : 0, pref_freq);
+ ssid ? ssid->ssid_len : 0, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
@@ -3124,56 +5417,52 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
if (wpa_s->p2p_auto_pd) {
wpa_s->p2p_auto_pd = 0;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
- " p2p_dev_addr=" MACSTR " status=N/A",
- MAC2STR(wpa_s->pending_join_dev_addr));
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
return;
}
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_FORMATION_FAILURE);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE);
}
}
static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
{
- struct wpa_supplicant *iface;
- int shared_freq;
- u8 bssid[ETH_ALEN];
+ int res;
+ unsigned int num, i;
+ struct wpa_used_freq_data *freqs;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+ if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ /* Multiple channels are supported and not all are in use */
return 0;
+ }
- for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
- if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s)
- continue;
- if (iface->current_ssid == NULL || iface->assoc_freq == 0)
- continue;
- if (iface->current_ssid->mode == WPAS_MODE_AP ||
- iface->current_ssid->mode == WPAS_MODE_P2P_GO)
- shared_freq = iface->current_ssid->frequency;
- else if (wpa_drv_get_bssid(iface, bssid) == 0)
- shared_freq = iface->assoc_freq;
- else
- shared_freq = 0;
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
+ if (!freqs)
+ return 1;
- if (shared_freq && freq != shared_freq) {
- wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s "
- "connected on %d MHz - new connection on "
- "%d MHz", iface->ifname, shared_freq, freq);
- return 1;
+ num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ for (i = 0; i < num; i++) {
+ if (freqs[i].freq == freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
+ freq);
+ res = 0;
+ goto exit_free;
}
}
- shared_freq = wpa_drv_shared_freq(wpa_s);
- if (shared_freq > 0 && shared_freq != freq) {
- wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared "
- "virtual interface connected on %d MHz - new "
- "connection on %d MHz", shared_freq, freq);
- return 1;
- }
+ wpa_printf(MSG_DEBUG, "P2P: No valid operating frequencies");
+ res = 1;
- return 0;
+exit_free:
+ os_free(freqs);
+ return res;
}
@@ -3192,7 +5481,8 @@ static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
return 0;
}
- updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
+ updated = os_reltime_before(&wpa_s->p2p_auto_started,
+ &bss->last_update);
wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
"%ld.%06ld (%supdated in last scan)",
bss->last_update.sec, bss->last_update.usec,
@@ -3205,7 +5495,7 @@ static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss = NULL;
int freq;
u8 iface_addr[ETH_ALEN];
@@ -3227,8 +5517,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
if (join == 0 &&
wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
wpa_s->auto_pd_scan_retry++;
- bss = wpa_bss_get_bssid(wpa_s,
- wpa_s->pending_join_dev_addr);
+ bss = wpa_bss_get_bssid_latest(
+ wpa_s, wpa_s->pending_join_dev_addr);
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
@@ -3237,7 +5527,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
MAC2STR(wpa_s->
pending_join_dev_addr),
freq);
- wpas_p2p_join_scan_req(wpa_s, freq);
+ wpas_p2p_join_scan_req(wpa_s, freq, NULL, 0);
return;
}
}
@@ -3250,13 +5540,14 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
MAC2STR(wpa_s->pending_join_dev_addr), join);
if (p2p_prov_disc_req(wpa_s->global->p2p,
- wpa_s->pending_join_dev_addr,
+ wpa_s->pending_join_dev_addr, NULL,
wpa_s->pending_pd_config_methods, join,
0, wpa_s->user_initiated_pd) < 0) {
wpa_s->p2p_auto_pd = 0;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
- " p2p_dev_addr=" MACSTR " status=N/A",
- MAC2STR(wpa_s->pending_join_dev_addr));
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
}
return;
}
@@ -3267,6 +5558,9 @@ 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,
+ P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=peer-not-running-GO");
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,
@@ -3274,15 +5568,19 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_connect_freq,
wpa_s->p2p_persistent_id,
wpa_s->p2p_pd_before_go_neg,
- wpa_s->p2p_go_ht40);
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht);
return;
}
wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
"try to join the group", join ? "" :
" in older scan");
- if (!join)
+ if (!join) {
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED);
wpa_s->p2p_fallback_to_go_neg = 1;
+ }
}
freq = p2p_get_oper_freq(wpa_s->global->p2p,
@@ -3291,8 +5589,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
p2p_get_interface_addr(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr,
iface_addr) == 0 &&
- os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0)
- {
+ os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0
+ && !wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr)) {
wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface "
"address for join from " MACSTR " to " MACSTR
" based on newly discovered P2P peer entry",
@@ -3308,19 +5606,35 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from P2P peer table: %d MHz", freq);
}
- bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ if (wpa_s->p2p_join_ssid_len) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+ MACSTR " and SSID %s",
+ MAC2STR(wpa_s->pending_join_iface_addr),
+ wpa_ssid_txt(wpa_s->p2p_join_ssid,
+ wpa_s->p2p_join_ssid_len));
+ 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) {
+ 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,
+ wpa_s->pending_join_iface_addr);
+ }
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
- "from BSS table: %d MHz", freq);
+ "from BSS table: %d MHz (SSID %s)", freq,
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
}
if (freq > 0) {
u16 method;
if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_FORMATION_FAILURE
- "reason=FREQ_CONFLICT");
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE
+ "reason=FREQ_CONFLICT");
return;
}
@@ -3361,7 +5675,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
}
if (p2p_prov_disc_req(wpa_s->global->p2p,
- wpa_s->pending_join_dev_addr, method, 1,
+ wpa_s->pending_join_dev_addr,
+ NULL, method, 1,
freq, wpa_s->user_initiated_pd) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
"Discovery Request before joining an "
@@ -3380,11 +5695,12 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
start:
/* Start join operation immediately */
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
}
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len)
{
int ret;
struct wpa_driver_scan_params params;
@@ -3396,8 +5712,16 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
/* P2P Wildcard SSID */
params.num_ssids = 1;
- params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
- params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ if (ssid && ssid_len) {
+ params.ssids[0].ssid = ssid;
+ params.ssids[0].ssid_len = ssid_len;
+ os_memcpy(wpa_s->p2p_join_ssid, ssid, ssid_len);
+ wpa_s->p2p_join_ssid_len = ssid_len;
+ } else {
+ params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+ params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ wpa_s->p2p_join_ssid_len = 0;
+ }
wpa_s->wps->dev.p2p = 1;
wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
@@ -3423,6 +5747,18 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
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;
@@ -3433,8 +5769,11 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
* the new scan results become available.
*/
ret = wpa_drv_scan(wpa_s, &params);
- if (!ret)
+ if (!ret) {
+ os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+ wpa_s->own_scan_requested = 1;
+ }
wpabuf_free(ies);
@@ -3451,18 +5790,23 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- wpas_p2p_join_scan_req(wpa_s, 0);
+ wpas_p2p_join_scan_req(wpa_s, 0, NULL, 0);
}
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
const u8 *dev_addr, enum p2p_wps_method wps_method,
- int auto_join)
+ int auto_join, int op_freq,
+ const u8 *ssid, size_t ssid_len)
{
wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
- MACSTR " dev " MACSTR ")%s",
- MAC2STR(iface_addr), MAC2STR(dev_addr),
+ MACSTR " dev " MACSTR " op_freq=%d)%s",
+ MAC2STR(iface_addr), MAC2STR(dev_addr), op_freq,
auto_join ? " (auto_join)" : "");
+ if (ssid && ssid_len) {
+ wpa_printf(MSG_DEBUG, "P2P: Group SSID specified: %s",
+ wpa_ssid_txt(ssid, ssid_len));
+ }
wpa_s->p2p_auto_pd = 0;
wpa_s->p2p_auto_join = !!auto_join;
@@ -3474,12 +5818,13 @@ static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
wpas_p2p_stop_find(wpa_s);
wpa_s->p2p_join_scan_count = 0;
- wpas_p2p_join_scan(wpa_s, NULL);
+ wpas_p2p_join_scan_req(wpa_s, op_freq, ssid, ssid_len);
return 0;
}
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len)
{
struct wpa_supplicant *group;
struct p2p_go_neg_results res;
@@ -3492,21 +5837,40 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
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;
}
group->p2p_in_provisioning = 1;
- wpa_s->global->p2p_group_formation = wpa_s;
group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
os_memset(&res, 0, sizeof(res));
+ os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
ETH_ALEN);
res.wps_method = wpa_s->pending_join_wps_method;
- bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
- if (bss) {
- res.freq = bss->freq;
- res.ssid_len = bss->ssid_len;
- os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+ if (freq && ssid && ssid_len) {
+ res.freq = 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 (bss) {
+ res.freq = bss->freq;
+ res.ssid_len = bss->ssid_len;
+ os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+ 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));
+ }
}
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
@@ -3531,6 +5895,106 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
}
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+ int *force_freq, int *pref_freq, int go)
+{
+ struct wpa_used_freq_data *freqs;
+ int res, best_freq, num_unused;
+ unsigned int freq_in_use = 0, num, i;
+
+ 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);
+
+ /*
+ * It is possible that the total number of used frequencies is bigger
+ * than the number of frequencies used for P2P, so get the system wide
+ * number of unused frequencies.
+ */
+ num_unused = wpas_p2p_num_unused_channels(wpa_s);
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u num_unused=%d",
+ freq, wpa_s->num_multichan_concurrent, num, num_unused);
+
+ if (freq > 0) {
+ int ret;
+ if (go)
+ ret = p2p_supported_freq(wpa_s->global->p2p, freq);
+ else
+ 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)) {
+ /*
+ * If freq is a DFS channel and DFS is offloaded
+ * to the driver, allow P2P GO to use it.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to the driver",
+ freq);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: The forced channel (%u MHz) is not supported for P2P uses",
+ freq);
+ res = -3;
+ goto exit_free;
+ }
+ }
+
+ for (i = 0; i < num; i++) {
+ if (freqs[i].freq == freq)
+ freq_in_use = 1;
+ }
+
+ if (num_unused <= 0 && !freq_in_use) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels",
+ freq);
+ res = -2;
+ goto exit_free;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+ "requested channel (%u MHz)", freq);
+ *force_freq = freq;
+ goto exit_ok;
+ }
+
+ best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+
+ /* We have a candidate frequency to use */
+ if (best_freq > 0) {
+ if (*pref_freq == 0 && num_unused > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using",
+ best_freq);
+ *pref_freq = best_freq;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
+ best_freq);
+ *force_freq = best_freq;
+ }
+ } else if (num_unused > 0) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Current operating channels are not available for P2P. Try to use another channel");
+ *force_freq = 0;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
+ res = -2;
+ goto exit_free;
+ }
+
+exit_ok:
+ res = 0;
+exit_free:
+ os_free(freqs);
+ return res;
+}
+
+
/**
* wpas_p2p_connect - Request P2P Group Formation to be started
* @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
@@ -3549,6 +6013,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
* @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
* 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
@@ -3557,11 +6022,10 @@ 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 ht40, int vht)
{
- int force_freq = 0, pref_freq = 0, oper_freq = 0;
- u8 bssid[ETH_ALEN];
- int ret = 0;
+ int force_freq = 0, pref_freq = 0;
+ int ret = 0, res;
enum wpa_driver_if_type iftype;
const u8 *if_addr;
struct wpa_ssid *ssid = NULL;
@@ -3576,6 +6040,12 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1;
}
+ os_free(wpa_s->global->add_psk);
+ wpa_s->global->add_psk = NULL;
+
+ wpa_s->global->p2p_fail_on_wps_complete = 0;
+ wpa_s->global->pending_p2ps_group = 0;
+
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
@@ -3590,13 +6060,16 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->p2p_pd_before_go_neg = !!pd;
wpa_s->p2p_go_ht40 = !!ht40;
+ wpa_s->p2p_go_vht = !!vht;
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();
- os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
- ret);
+ 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
@@ -3619,7 +6092,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
dev_addr);
}
if (auto_join) {
- os_get_time(&wpa_s->p2p_auto_started);
+ os_get_reltime(&wpa_s->p2p_auto_started);
wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
"%ld.%06ld",
wpa_s->p2p_auto_started.sec,
@@ -3627,65 +6100,17 @@ 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) < 0)
+ auto_join, freq, NULL, 0) < 0)
return -1;
return ret;
}
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- wpa_s->assoc_freq)
- oper_freq = wpa_s->assoc_freq;
- else {
- oper_freq = wpa_drv_shared_freq(wpa_s);
- if (oper_freq < 0)
- oper_freq = 0;
- }
-
- if (freq > 0) {
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel "
- "(%u MHz) is not supported for P2P uses",
- freq);
- return -3;
- }
-
- if (oper_freq > 0 && freq != oper_freq &&
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "on %u MHz while connected on another "
- "channel (%u MHz)", freq, oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "requested channel (%u MHz)", freq);
- force_freq = freq;
- } else if (oper_freq > 0 &&
- !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
- if (!(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "while connected on non-P2P supported "
- "channel (%u MHz)", oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
- "(%u MHz) not available for P2P - try to use "
- "another channel", oper_freq);
- force_freq = 0;
- } else if (oper_freq > 0 &&
- (wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
- "are already using (%u MHz) on another interface",
- oper_freq);
- pref_freq = oper_freq;
- } else if (oper_freq > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "channel we are already using (%u MHz) on another "
- "interface", oper_freq);
- force_freq = oper_freq;
- }
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ go_intent == 15);
+ if (res)
+ return res;
+ wpas_p2p_set_own_freq_preference(wpa_s,
+ force_freq ? force_freq : pref_freq);
wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
@@ -3738,24 +6163,28 @@ void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
+ wpa_printf(MSG_DEBUG, "P2P: remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u duration=%u)",
+ wpa_s->off_channel_freq, wpa_s->pending_listen_freq,
+ wpa_s->roc_waiting_drv_freq, freq, duration);
+ if (wpa_s->off_channel_freq &&
+ wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
wpa_s->pending_listen_duration);
wpa_s->pending_listen_freq = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d freq=%u duration=%u)",
+ wpa_s->off_channel_freq, wpa_s->pending_listen_freq,
+ freq, duration);
}
}
-static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
- unsigned int timeout)
+int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout)
{
/* Limit maximum Listen state time based on driver limitation. */
if (timeout > wpa_s->max_remain_on_chan)
timeout = wpa_s->max_remain_on_chan;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_listen(wpa_s, timeout);
-
return p2p_listen(wpa_s->global->p2p, timeout);
}
@@ -3775,17 +6204,24 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+ wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
+ if (wpa_s->p2p_long_listen > 0)
+ wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
if (offchannel_pending_action_tx(wpa_s))
return;
- if (wpa_s->p2p_long_listen > 0)
- wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (wpa_s->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ } else {
+ /*
+ * When listen duration is over, stop listen & update p2p_state
+ * to IDLE.
+ */
+ p2p_stop_listen(wpa_s->global->p2p);
}
}
@@ -3806,6 +6242,7 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
{
struct wpa_global *global = wpa_s->global;
+ struct wpa_supplicant *calling_wpa_s = wpa_s;
if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev;
@@ -3813,7 +6250,11 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
while (wpa_s) {
prev = wpa_s;
wpa_s = wpa_s->next;
- wpas_p2p_disconnect(prev);
+ if (prev->p2p_group_interface !=
+ NOT_P2P_GROUP_INTERFACE ||
+ (prev->current_ssid &&
+ prev->current_ssid->p2p_group))
+ wpas_p2p_disconnect_safely(prev, calling_wpa_s);
}
return 0;
}
@@ -3823,94 +6264,275 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
break;
}
- return wpas_p2p_disconnect(wpa_s);
+ return wpas_p2p_disconnect_safely(wpa_s, calling_wpa_s);
+}
+
+
+static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
+{
+ unsigned int r;
+
+ if (freq == 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
+ "band");
+ if (wpa_s->best_24_freq > 0 &&
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_24_freq)) {
+ freq = wpa_s->best_24_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
+ "channel: %d MHz", freq);
+ } else {
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
+ freq = 2412 + (r % 3) * 25;
+ wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
+ "channel: %d MHz", freq);
+ }
+ }
+
+ if (freq == 5) {
+ wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
+ "band");
+ if (wpa_s->best_5_freq > 0 &&
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_5_freq)) {
+ freq = wpa_s->best_5_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
+ "channel: %d MHz", freq);
+ } else {
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
+ freq = 5180 + (r % 4) * 20;
+ if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not select "
+ "5 GHz channel for P2P group");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
+ "channel: %d MHz", 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)) {
+ /*
+ * 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",
+ __func__, freq);
+ return freq;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
+ "(%u MHz) is not supported for P2P uses",
+ freq);
+ return -1;
+ }
+
+ return freq;
+}
+
+
+static int wpas_p2p_select_freq_no_pref(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params,
+ const struct p2p_channels *channels)
+{
+ unsigned int i, r;
+
+ /* first try some random selection of the social channels */
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
+
+ for (i = 0; i < 3; i++) {
+ params->freq = 2412 + ((r + i) % 3) * 25;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ /* try all channels in reg. class 81 */
+ for (i = 0; i < 11; i++) {
+ params->freq = 2412 + i * 5;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ /* try all channels in operating class 115 */
+ for (i = 0; i < 4; i++) {
+ params->freq = 5180 + i * 20;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ /* try all channels in operating class 124 */
+ for (i = 0; i < 4; i++) {
+ params->freq = 5745 + i * 20;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ /* try social channel class 180 channel 2 */
+ params->freq = 58320 + 1 * 2160;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+
+ /* try all channels in reg. class 180 */
+ for (i = 0; i < 4; i++) {
+ params->freq = 58320 + i * 2160;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: No 2.4, 5, or 60 GHz channel allowed");
+ return -1;
+out:
+ wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference known)",
+ params->freq);
+ return 0;
}
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq, int ht40)
+ int freq, int ht40, int vht,
+ const struct p2p_channels *channels)
{
- u8 bssid[ETH_ALEN];
- int res;
+ struct wpa_used_freq_data *freqs;
+ unsigned int pref_freq, cand_freq;
+ unsigned int num, i;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
params->ht40 = ht40;
+ params->vht = vht;
if (freq) {
+ if (!freq_included(channels, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "accepted", freq);
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
"frequency %d MHz", freq);
params->freq = freq;
} else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
wpa_s->conf->p2p_oper_channel >= 1 &&
- wpa_s->conf->p2p_oper_channel <= 11) {
+ wpa_s->conf->p2p_oper_channel <= 11 &&
+ freq_included(channels,
+ 2407 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
- } else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
- wpa_s->conf->p2p_oper_reg_class == 124) {
+ } else if ((wpa_s->conf->p2p_oper_reg_class == 115 ||
+ wpa_s->conf->p2p_oper_reg_class == 116 ||
+ wpa_s->conf->p2p_oper_reg_class == 117 ||
+ wpa_s->conf->p2p_oper_reg_class == 124 ||
+ wpa_s->conf->p2p_oper_reg_class == 126 ||
+ wpa_s->conf->p2p_oper_reg_class == 127) &&
+ freq_included(channels,
+ 5000 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_overall_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_overall_freq)) {
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_overall_freq) &&
+ freq_included(channels, wpa_s->best_overall_freq)) {
params->freq = wpa_s->best_overall_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_24_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq)) {
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_24_freq) &&
+ freq_included(channels, wpa_s->best_24_freq)) {
params->freq = wpa_s->best_24_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_5_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_5_freq)) {
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_5_freq) &&
+ freq_included(channels, wpa_s->best_5_freq)) {
params->freq = wpa_s->best_5_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
"channel %d MHz", params->freq);
+ } else if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p,
+ channels))) {
+ params->freq = pref_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
+ "channels", params->freq);
} else {
- int chan;
- for (chan = 0; chan < 11; chan++) {
- params->freq = 2412 + chan * 5;
- if (!wpas_p2p_disallowed_freq(wpa_s->global,
- params->freq))
- break;
- }
- if (chan == 11) {
- wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
- "allowed");
+ /* no preference, select some channel */
+ if (wpas_p2p_select_freq_no_pref(wpa_s, params, channels) < 0)
return -1;
- }
- wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
- "known)", params->freq);
}
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- wpa_s->assoc_freq && !freq) {
- wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
- "already using");
- params->freq = wpa_s->assoc_freq;
- }
-
- res = wpa_drv_shared_freq(wpa_s);
- if (res > 0 && !freq) {
- wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
- "already using on a shared interface");
- params->freq = res;
- } else if (res > 0 && freq != res &&
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz "
- "while connected on another channel (%u MHz)",
- freq, res);
+ 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);
+
+ cand_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+
+ /* First try the best used frequency if possible */
+ if (!freq && cand_freq > 0 && freq_included(channels, cand_freq)) {
+ params->freq = cand_freq;
+ } else if (!freq) {
+ /* Try any of the used frequencies */
+ for (i = 0; i < num; i++) {
+ if (freq_included(channels, freqs[i].freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+ freqs[i].freq);
+ params->freq = freqs[i].freq;
+ break;
+ }
+ }
+
+ if (i == num) {
+ if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
+ os_free(freqs);
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+ }
+ }
+ } else {
+ for (i = 0; i < num; i++) {
+ if (freqs[i].freq == freq)
+ break;
+ }
+
+ if (i == num) {
+ if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ if (freq)
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
+ os_free(freqs);
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
+ }
+ }
}
+ os_free(freqs);
return 0;
}
@@ -3924,24 +6546,27 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
if (!wpas_p2p_create_iface(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
"operations");
+ wpa_s->p2p_first_connection_timeout = 0;
return wpa_s;
}
if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
WPA_IF_P2P_CLIENT) < 0) {
- wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to add group interface");
+ wpa_msg_global(wpa_s, MSG_ERROR,
+ "P2P: Failed to add group interface");
return NULL;
}
group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
if (group_wpa_s == NULL) {
- wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to initialize group "
- "interface");
+ wpa_msg_global(wpa_s, MSG_ERROR,
+ "P2P: Failed to initialize group interface");
wpas_p2p_remove_pending_group_interface(wpa_s);
return NULL;
}
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname);
+ group_wpa_s->p2p_first_connection_timeout = 0;
return group_wpa_s;
}
@@ -3951,78 +6576,51 @@ 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
+ * @ht40: Start GO with 40 MHz channel width
+ * @vht: Start GO 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 freq, int ht40, int vht)
{
struct p2p_go_neg_results params;
- unsigned int r;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ os_free(wpa_s->global->add_psk);
+ wpa_s->global->add_psk = NULL;
+
/* Make sure we are not running find during connection establishment */
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
wpas_p2p_stop_find_oper(wpa_s);
- if (freq == 2) {
- wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
- "band");
- if (wpa_s->best_24_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq)) {
- freq = wpa_s->best_24_freq;
- wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
- "channel: %d MHz", freq);
- } else {
- os_get_random((u8 *) &r, sizeof(r));
- freq = 2412 + (r % 3) * 25;
- wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
- "channel: %d MHz", freq);
- }
- }
-
- if (freq == 5) {
- wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
- "band");
- if (wpa_s->best_5_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_5_freq)) {
- freq = wpa_s->best_5_freq;
- wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
- "channel: %d MHz", freq);
- } else {
- os_get_random((u8 *) &r, sizeof(r));
- freq = 5180 + (r % 4) * 20;
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: Could not select "
- "5 GHz channel for P2P group");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
- "channel: %d MHz", freq);
- }
- }
-
- if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
- "(%u MHz) is not supported for P2P uses",
- freq);
+ 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))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
return -1;
if (params.freq &&
- !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
- "(%u MHz) is not supported for P2P uses",
- params.freq);
- return -1;
+ !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);
+ return -1;
+ }
}
p2p_go_params(wpa_s->global->p2p, &params);
params.persistent_group = persistent_group;
@@ -4037,13 +6635,15 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *params, int addr_allocated)
+ struct wpa_ssid *params, int addr_allocated,
+ int freq)
{
struct wpa_ssid *ssid;
wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
if (wpa_s == NULL)
return -1;
+ wpa_s->p2p_last_4way_hs_fail = NULL;
wpa_supplicant_ap_deinit(wpa_s);
@@ -4072,9 +6672,16 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
if (params->passphrase)
ssid->passphrase = os_strdup(params->passphrase);
- wpa_supplicant_select_network(wpa_s, ssid);
-
wpa_s->show_group_started = 1;
+ wpa_s->p2p_in_invitation = 1;
+ wpa_s->p2p_invite_go_freq = freq;
+
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+ NULL);
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ wpa_supplicant_select_network(wpa_s, ssid);
return 0;
}
@@ -4082,10 +6689,12 @@ 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 freq, int ht40)
+ int force_freq, int neg_freq, int ht40,
+ int vht, const struct p2p_channels *channels,
+ int connection_timeout)
{
struct p2p_go_neg_results params;
- int go = 0;
+ int go = 0, freq;
if (ssid->disabled != 2 || ssid->ssid == NULL)
return -1;
@@ -4097,18 +6706,39 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
return 0;
}
+ os_free(wpa_s->global->add_psk);
+ wpa_s->global->add_psk = NULL;
+
/* Make sure we are not running find during connection establishment */
wpas_p2p_stop_find_oper(wpa_s);
wpa_s->p2p_fallback_to_go_neg = 0;
+ if (ssid->mode == WPAS_MODE_P2P_GO) {
+ if (force_freq > 0) {
+ freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
+ if (freq < 0)
+ return -1;
+ } else {
+ freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
+ freq = 0;
+ }
+ } else {
+ freq = neg_freq;
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
+ freq = 0;
+ }
+
if (ssid->mode == WPAS_MODE_INFRA)
- return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
+ return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq);
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
return -1;
params.role_go = 1;
@@ -4132,6 +6762,9 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (wpa_s == NULL)
return -1;
+ p2p_channels_to_freqs(channels, params.freq_list, P2P_MAX_CHANNELS);
+
+ wpa_s->p2p_first_connection_timeout = connection_timeout;
wpas_start_wps_go(wpa_s, &params, 0);
return 0;
@@ -4169,9 +6802,14 @@ static void wpas_p2p_idle_update(void *ctx, int idle)
if (!wpa_s->ap_iface)
return;
wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
- if (idle)
+ if (idle) {
+ if (wpa_s->global->p2p_fail_on_wps_complete &&
+ wpa_s->p2p_in_provisioning) {
+ wpas_p2p_grpform_fail_after_wps(wpa_s);
+ return;
+ }
wpas_p2p_set_group_idle_timeout(wpa_s);
- else
+ } else
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
}
@@ -4182,8 +6820,6 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct p2p_group *group;
struct p2p_group_config *cfg;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return NULL;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return NULL;
@@ -4203,6 +6839,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
cfg->max_clients = wpa_s->conf->max_num_sta;
os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
cfg->ssid_len = ssid->ssid_len;
+ cfg->freq = ssid->frequency;
cfg->cb_ctx = wpa_s;
cfg->ie_update = wpas_p2p_ie_update;
cfg->idle_update = wpas_p2p_idle_update;
@@ -4239,6 +6876,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
NULL);
+ wpa_s->p2p_go_group_formation_completed = 1;
if (ssid && ssid->mode == WPAS_MODE_INFRA) {
/*
* Use a separate timeout for initial data connection to
@@ -4246,14 +6884,31 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
* something goes wrong in this step before the P2P group idle
* timeout mechanism is taken into use.
*/
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Re-start group formation timeout (%d seconds) as client for initial connection",
+ P2P_MAX_INITIAL_CONN_WAIT);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
+ } else if (ssid) {
+ /*
+ * Use a separate timeout for initial data connection to
+ * complete to allow the group to be removed automatically if
+ * the client does not complete data connection successfully.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Re-start group formation timeout (%d seconds) as GO for initial connection",
+ 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);
+ /*
+ * Complete group formation on first successful data connection
+ */
+ wpa_s->p2p_go_group_formation_completed = 0;
}
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
- else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- wpa_drv_wps_success_cb(wpa_s, peer_addr);
wpas_group_formation_completed(wpa_s, 1);
}
@@ -4274,18 +6929,55 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
}
wpas_notify_p2p_wps_failed(wpa_s, fail);
+
+ if (wpa_s == wpa_s->global->p2p_group_formation) {
+ /*
+ * Allow some time for the failed WPS negotiation exchange to
+ * complete, but remove the group since group formation cannot
+ * succeed after provisioning failure.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: WPS step failed during group formation - reject connection from timeout");
+ wpa_s->global->p2p_fail_on_wps_complete = 1;
+ eloop_deplete_timeout(0, 50000,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+}
+
+
+int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->p2p_fail_on_wps_complete ||
+ !wpa_s->p2p_in_provisioning)
+ return 0;
+
+ wpas_p2p_grpform_fail_after_wps(wpa_s);
+
+ return 1;
}
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *config_method,
- enum wpas_p2p_prov_disc_use use)
+ enum wpas_p2p_prov_disc_use use,
+ struct p2ps_provision *p2ps_prov)
{
u16 config_methods;
+ wpa_s->global->pending_p2ps_group = 0;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->pending_pd_use = NORMAL_PD;
- if (os_strncmp(config_method, "display", 7) == 0)
+ if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
+ p2ps_prov->conncap = p2ps_group_capability(
+ wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
+ wpa_printf(MSG_DEBUG,
+ "P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
+ __func__, p2ps_prov->conncap,
+ p2ps_prov->adv_id, p2ps_prov->conncap,
+ p2ps_prov->status, p2ps_prov->info);
+
+ config_methods = 0;
+ } else if (os_strncmp(config_method, "display", 7) == 0)
config_methods = WPS_CONFIG_DISPLAY;
else if (os_strncmp(config_method, "keypad", 6) == 0)
config_methods = WPS_CONFIG_KEYPAD;
@@ -4294,6 +6986,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
config_methods = WPS_CONFIG_PUSHBUTTON;
else {
wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
+ os_free(p2ps_prov);
return -1;
}
@@ -4306,7 +6999,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->auto_pd_scan_retry = 0;
wpas_p2p_stop_find(wpa_s);
wpa_s->p2p_join_scan_count = 0;
- os_get_time(&wpa_s->p2p_auto_started);
+ os_get_reltime(&wpa_s->p2p_auto_started);
wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
wpa_s->p2p_auto_started.sec,
wpa_s->p2p_auto_started.usec);
@@ -4314,16 +7007,12 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return 0;
}
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
- config_methods,
- use == WPAS_P2P_PD_FOR_JOIN);
- }
-
- if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+ if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
+ os_free(p2ps_prov);
return -1;
+ }
- return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
+ return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, p2ps_prov,
config_methods, use == WPAS_P2P_PD_FOR_JOIN,
0, 1);
}
@@ -4341,6 +7030,8 @@ 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);
+
wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
"operation request");
offchannel_clear_pending_action_tx(wpa_s);
@@ -4350,14 +7041,12 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay)
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_cnt, const char **seek_string, int freq)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_find(wpa_s, timeout, type);
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
wpa_s->p2p_in_provisioning)
return -1;
@@ -4366,35 +7055,55 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
return p2p_find(wpa_s->global->p2p, timeout, type,
num_req_dev_types, req_dev_types, dev_id,
- search_delay);
+ search_delay, seek_cnt, seek_string, freq);
+}
+
+
+static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+
+ /*
+ * Indicate that results have been processed so that the P2P module can
+ * continue pending tasks.
+ */
+ p2p_scan_res_handled(wpa_s->global->p2p);
}
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->global->p2p_cb_on_scan_complete = 0;
-
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_stop_find(wpa_s);
- return 1;
- }
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
- return 0;
+ if (wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Do not consider the scan results after stop_find");
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore_search;
+ }
}
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
{
- if (wpas_p2p_stop_find_oper(wpa_s) > 0)
- return;
- wpas_p2p_remove_pending_group_interface(wpa_s);
+ wpas_p2p_stop_find_oper(wpa_s);
+ if (!wpa_s->global->pending_group_iface_for_p2ps)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
}
@@ -4454,6 +7163,8 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (wpa_s->global->p2p_disabled)
return -1;
+ if (wpa_s->conf->p2p_disabled)
+ return -1;
if (wpa_s->global->p2p == NULL)
return -1;
if (bss == NULL)
@@ -4519,7 +7230,7 @@ void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
}
-void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
{
p2p_group_deinit(wpa_s->p2p_group);
wpa_s->p2p_group = NULL;
@@ -4535,9 +7246,6 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
{
wpa_s->p2p_long_listen = 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_reject(wpa_s, addr);
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -4548,10 +7256,19 @@ 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 ht40, int vht, int pref_freq)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
+ int force_freq = 0;
+ int res;
+ int no_pref_freq_given = pref_freq == 0;
+
+ wpa_s->global->p2p_invite_group = NULL;
+ if (peer_addr)
+ os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+ else
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
@@ -4579,16 +7296,32 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
}
wpa_s->pending_invite_ssid_id = ssid->id;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len,
- go_dev_addr, 1);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ role == P2P_INVITE_ROLE_GO);
+ if (res)
+ return res;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+ no_pref_freq_given && pref_freq > 0 &&
+ wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz for invitation due to p2p_ignore_shared_freq=1 configuration",
+ pref_freq);
+ pref_freq = 0;
+ }
+
+ /*
+ * Stop any find/listen operations before invitation and possibly
+ * connection establishment.
+ */
+ wpas_p2p_stop_find_oper(wpa_s);
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
+ ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
+ 1, pref_freq, -1);
}
@@ -4601,9 +7334,12 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
u8 *bssid = NULL;
struct wpa_ssid *ssid;
int persistent;
+ int freq = 0, force_freq = 0, pref_freq = 0;
+ int res;
wpa_s->p2p_persistent_go_freq = 0;
wpa_s->p2p_go_ht40 = 0;
+ wpa_s->p2p_go_vht = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -4621,6 +7357,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
return -1;
}
+ wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
ssid->ssid, ssid->ssid_len);
@@ -4630,6 +7367,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
bssid = wpa_s->own_addr;
if (go_dev_addr == NULL)
go_dev_addr = wpa_s->global->p2p_dev_addr;
+ freq = ssid->frequency;
} else {
role = P2P_INVITE_ROLE_CLIENT;
if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -4641,31 +7379,35 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
if (go_dev_addr == NULL &&
!is_zero_ether_addr(wpa_s->go_dev_addr))
go_dev_addr = wpa_s->go_dev_addr;
+ freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+ (int) wpa_s->assoc_freq;
}
wpa_s->parent->pending_invite_ssid_id = -1;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len,
- go_dev_addr, persistent);
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ role == P2P_INVITE_ROLE_ACTIVE_GO);
+ if (res)
+ return res;
+ wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
- go_dev_addr, persistent);
+ ssid->ssid, ssid->ssid_len, force_freq,
+ go_dev_addr, persistent, pref_freq, -1);
}
void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
- const char *ssid_txt;
u8 go_dev_addr[ETH_ALEN];
int network_id = -1;
int persistent;
int freq;
+ u8 ip[3 * 4];
+ char ip_addr[100];
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
@@ -4673,11 +7415,10 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
}
if (!wpa_s->show_group_started || !ssid)
- goto done;
+ return;
wpa_s->show_group_started = 0;
- ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
os_memset(go_dev_addr, 0, ETH_ALEN);
if (ssid->bssid_set)
os_memcpy(go_dev_addr, ssid->bssid, ETH_ALEN);
@@ -4690,52 +7431,41 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
(int) wpa_s->assoc_freq;
- if (ssid->passphrase == NULL && ssid->psk_set) {
- char psk[65];
- wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
- MACSTR "%s",
- wpa_s->ifname, ssid_txt, freq, psk,
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
- } else {
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname, ssid_txt, freq,
- ssid->passphrase ? ssid->passphrase : "",
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+
+ ip_addr[0] = '\0';
+ if (wpa_sm_get_p2p_ip_addr(wpa_s->wpa, ip) == 0) {
+ int res;
+
+ res = os_snprintf(ip_addr, sizeof(ip_addr),
+ " ip_addr=%u.%u.%u.%u "
+ "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
+ ip[0], ip[1], ip[2], ip[3],
+ ip[4], ip[5], ip[6], ip[7],
+ ip[8], ip[9], ip[10], ip[11]);
+ if (os_snprintf_error(sizeof(ip_addr), res))
+ ip_addr[0] = '\0';
}
+ wpas_p2p_group_started(wpa_s, 0, ssid, freq,
+ ssid->passphrase == NULL && ssid->psk_set ?
+ ssid->psk : NULL,
+ ssid->passphrase, go_dev_addr, persistent,
+ 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);
-
-done:
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after successful connection");
- p2p_increase_search_delay(
- wpa_s->global->p2p,
- wpas_p2p_search_delay(wpa_s));
- }
- }
}
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
u32 interval1, u32 duration2, u32 interval2)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
+ int ret;
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -4744,18 +7474,19 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
return -1;
- return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->assoc_freq,
- duration1, interval1, duration2, interval2);
+ ret = p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->assoc_freq,
+ duration1, interval1, duration2, interval2);
+ if (ret == 0)
+ wpa_s->waiting_presence_resp = 1;
+
+ return ret;
}
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
unsigned int interval)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -4857,8 +7588,6 @@ int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return 0;
if (!locally_generated)
p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
@@ -4886,8 +7615,6 @@ void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
if (!locally_generated)
p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
@@ -4964,20 +7691,27 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
u8 reg_class, channel;
int ret;
unsigned int r;
+ u8 channel_forced;
+
if (wpa_s->conf->p2p_listen_reg_class &&
wpa_s->conf->p2p_listen_channel) {
reg_class = wpa_s->conf->p2p_listen_reg_class;
channel = wpa_s->conf->p2p_listen_channel;
+ channel_forced = 1;
} else {
reg_class = 81;
/*
* Pick one of the social channels randomly as the
* listen channel.
*/
- os_get_random((u8 *) &r, sizeof(r));
- channel = 1 + (r % 3) * 5;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ channel = 1;
+ else
+ channel = 1 + (r % 3) * 5;
+ channel_forced = 0;
}
- ret = p2p_set_listen_channel(p2p, reg_class, channel);
+ ret = p2p_set_listen_channel(p2p, reg_class, channel,
+ channel_forced);
if (ret)
wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
"failed: %d", ret);
@@ -4997,8 +7731,10 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
* Use random operation channel from (1, 6, 11)
*if no other preference is indicated.
*/
- os_get_random((u8 *) &r, sizeof(r));
- op_channel = 1 + (r % 3) * 5;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ op_channel = 1;
+ else
+ op_channel = 1 + (r % 3) * 5;
cfg_op_channel = 0;
}
ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
@@ -5014,7 +7750,15 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
"update failed");
}
+
+ if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: No GO channel list "
+ "update failed");
+ }
}
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PASSPHRASE_LEN)
+ p2p_set_passphrase_len(p2p, wpa_s->conf->p2p_passphrase_len);
}
@@ -5032,8 +7776,6 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
wpa_s->global->cross_connection = enabled;
p2p_set_cross_connect(wpa_s->global->p2p, enabled);
@@ -5048,9 +7790,10 @@ 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(iface->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
- iface->ifname, iface->cross_connect_uplink);
+ wpa_msg_global(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ iface->ifname,
+ iface->cross_connect_uplink);
}
}
@@ -5077,9 +7820,9 @@ static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
continue;
iface->cross_connect_in_use = 1;
- wpa_msg(iface->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
- iface->ifname, iface->cross_connect_uplink);
+ wpa_msg_global(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+ iface->ifname, iface->cross_connect_uplink);
}
}
@@ -5097,9 +7840,9 @@ static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
if (!iface->cross_connect_in_use)
continue;
- wpa_msg(iface->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
- iface->ifname, iface->cross_connect_uplink);
+ wpa_msg_global(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ iface->ifname, iface->cross_connect_uplink);
iface->cross_connect_in_use = 0;
}
}
@@ -5142,7 +7885,8 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
if (iface->drv_flags &
WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
continue;
- if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ iface != wpa_s->parent)
continue;
wpa_s->cross_connect_enabled = 1;
@@ -5159,9 +7903,9 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
break;
wpa_s->cross_connect_in_use = 1;
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
- wpa_s->ifname, wpa_s->cross_connect_uplink);
+ wpa_msg_global(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+ wpa_s->ifname, wpa_s->cross_connect_uplink);
break;
}
}
@@ -5177,33 +7921,57 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
"session overlap");
if (wpa_s != wpa_s->parent)
wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
+ wpas_p2p_group_formation_failed(wpa_s);
+ return 1;
+}
- if (wpa_s->global->p2p)
- p2p_group_formation_failed(wpa_s->global->p2p);
-
- eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
- wpas_group_formation_completed(wpa_s, 0);
- return 1;
+void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpas_p2p_notif_pbc_overlap(wpa_s);
}
void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
{
- struct p2p_channels chan;
+ struct p2p_channels chan, cli_chan;
+ struct wpa_supplicant *ifs;
if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
return;
os_memset(&chan, 0, sizeof(chan));
- if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+ os_memset(&cli_chan, 0, sizeof(cli_chan));
+ if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
"channel list");
return;
}
- p2p_update_channel_list(wpa_s->global->p2p, &chan);
+ p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ int freq;
+ if (!ifs->current_ssid ||
+ !ifs->current_ssid->p2p_group ||
+ (ifs->current_ssid->mode != WPAS_MODE_P2P_GO &&
+ ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION))
+ continue;
+ freq = ifs->current_ssid->frequency;
+ if (freq_included(&chan, freq)) {
+ wpa_dbg(ifs, MSG_DEBUG,
+ "P2P GO operating frequency %d MHz in valid range",
+ freq);
+ continue;
+ }
+
+ wpa_dbg(ifs, MSG_DEBUG,
+ "P2P GO operating in invalid frequency %d MHz", freq);
+ /* TODO: Consider using CSA or removing the group within
+ * wpa_supplicant */
+ wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
+ }
}
@@ -5269,6 +8037,11 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_REQUESTED);
break;
+ } else if (wpa_s->p2p_in_invitation) {
+ wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling",
+ wpa_s->ifname);
+ found = 1;
+ wpas_p2p_group_formation_failed(wpa_s);
}
}
@@ -5296,7 +8069,7 @@ void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
int freq_24, int freq_5, int freq_overall)
{
struct p2p_data *p2p = wpa_s->global->p2p;
- if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+ if (p2p == NULL)
return;
p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
}
@@ -5307,7 +8080,7 @@ int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr)
u8 peer[ETH_ALEN];
struct p2p_data *p2p = wpa_s->global->p2p;
- if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+ if (p2p == NULL)
return -1;
if (hwaddr_aton(addr, peer))
@@ -5341,10 +8114,42 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
{
+ int ret;
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
- return p2p_in_progress(wpa_s->global->p2p);
+ ret = p2p_in_progress(wpa_s->global->p2p);
+ if (ret == 0) {
+ /*
+ * Check whether there is an ongoing WPS provisioning step (or
+ * other parts of group formation) on another interface since
+ * p2p_in_progress() does not report this to avoid issues for
+ * scans during such provisioning step.
+ */
+ if (wpa_s->global->p2p_group_formation &&
+ wpa_s->global->p2p_group_formation != wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Another interface (%s) "
+ "in group formation",
+ wpa_s->global->p2p_group_formation->ifname);
+ ret = 1;
+ }
+ }
+
+ if (!ret && wpa_s->global->p2p_go_wait_client.sec) {
+ struct os_reltime now;
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &wpa_s->global->p2p_go_wait_client,
+ P2P_MAX_INITIAL_CONN_WAIT_GO)) {
+ /* Wait for the first client has expired */
+ wpa_s->global->p2p_go_wait_client.sec = 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Waiting for initial client connection during group formation");
+ ret = 1;
+ }
+ }
+
+ return ret;
}
@@ -5384,12 +8189,17 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
(ssid_len != s->ssid_len ||
os_memcmp(ssid, s->ssid, ssid_len) != 0))
continue;
+ if (addr == NULL) {
+ if (s->mode == WPAS_MODE_P2P_GO)
+ return s;
+ continue;
+ }
if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
return s; /* peer is GO in the persistent group */
if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
continue;
for (i = 0; i < s->num_p2p_clients; i++) {
- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
addr, ETH_ALEN) == 0)
return s; /* peer is P2P client in persistent
* group */
@@ -5403,34 +8213,75 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
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) {
+ /*
+ * This can happen if WPS provisioning step is not terminated
+ * cleanly (e.g., P2P Client does not send WSC_Done). Since the
+ * peer was able to connect, there is no need to time out group
+ * formation after this, though. In addition, this is used with
+ * the initial connection wait on the GO as a separate formation
+ * timeout and as such, expected to be hit after the initial WPS
+ * provisioning step.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+
+ if (!wpa_s->p2p_go_group_formation_completed &&
+ !wpa_s->group_formation_reported) {
+ /*
+ * GO has not yet notified group formation success since
+ * the WPS step was not completed cleanly. Do that
+ * notification now since the P2P Client was able to
+ * connect and as such, must have received the
+ * credential from the WPS step.
+ */
+ if (wpa_s->global->p2p)
+ p2p_wps_success_cb(wpa_s->global->p2p, addr);
+ wpas_group_formation_completed(wpa_s, 1);
+ }
+ }
+ if (!wpa_s->p2p_go_group_formation_completed) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first 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;
+ }
+ wpa_s->global->p2p_go_wait_client.sec = 0;
if (addr == NULL)
return;
wpas_p2p_add_persistent_group_client(wpa_s, addr);
}
-static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
- int group_added)
+static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added)
{
struct wpa_supplicant *group = wpa_s;
+ int ret = 0;
+
if (wpa_s->global->p2p_group_formation)
group = wpa_s->global->p2p_group_formation;
wpa_s = wpa_s->parent;
offchannel_send_action_done(wpa_s);
if (group_added)
- wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
+ ret = wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
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_persistent_id,
wpa_s->p2p_pd_before_go_neg,
- wpa_s->p2p_go_ht40);
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht);
+ return ret;
}
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
{
+ int res;
+
if (!wpa_s->p2p_fallback_to_go_neg ||
wpa_s->p2p_in_provisioning <= 5)
return 0;
@@ -5440,45 +8291,1008 @@ 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");
- wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+ wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=GO-not-found");
+ res = wpas_p2p_fallback_to_go_neg(wpa_s, 1);
- return 1;
+ return res == 1 ? 2 : 1;
}
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
{
- const char *rn, *rn2;
struct wpa_supplicant *ifs;
if (wpa_s->wpa_state > WPA_SCANNING) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to "
"concurrent operation",
- P2P_CONCURRENT_SEARCH_DELAY);
- return P2P_CONCURRENT_SEARCH_DELAY;
+ wpa_s->conf->p2p_search_delay);
+ return wpa_s->conf->p2p_search_delay;
}
- if (!wpa_s->driver->get_radio_name)
- return 0;
- rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
- if (rn == NULL || rn[0] == '\0')
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs != wpa_s && ifs->wpa_state > WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
+ "delay due to concurrent operation on "
+ "interface %s",
+ wpa_s->conf->p2p_search_delay,
+ ifs->ifname);
+ return wpa_s->conf->p2p_search_delay;
+ }
+ }
+
+ return 0;
+}
+
+
+static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *s, const u8 *addr,
+ int iface_addr)
+{
+ struct psk_list_entry *psk, *tmp;
+ int changed = 0;
+
+ dl_list_for_each_safe(psk, tmp, &s->psk_list, struct psk_list_entry,
+ list) {
+ if ((iface_addr && !psk->p2p &&
+ os_memcmp(addr, psk->addr, ETH_ALEN) == 0) ||
+ (!iface_addr && psk->p2p &&
+ os_memcmp(addr, psk->addr, ETH_ALEN) == 0)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove persistent group PSK list entry for "
+ MACSTR " p2p=%u",
+ MAC2STR(psk->addr), psk->p2p);
+ dl_list_del(&psk->list);
+ os_free(psk);
+ changed++;
+ }
+ }
+
+ return changed;
+}
+
+
+void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
+ const u8 *p2p_dev_addr,
+ const u8 *psk, size_t psk_len)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_ssid *persistent;
+ struct psk_list_entry *p, *last;
+
+ if (psk_len != sizeof(p->psk))
+ return;
+
+ if (p2p_dev_addr) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR
+ " p2p_dev_addr=" MACSTR,
+ MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
+ if (is_zero_ether_addr(p2p_dev_addr))
+ p2p_dev_addr = NULL;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR,
+ MAC2STR(mac_addr));
+ }
+
+ if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: new_psk_cb during group formation");
+ /* To be added to persistent group once created */
+ if (wpa_s->global->add_psk == NULL) {
+ wpa_s->global->add_psk = os_zalloc(sizeof(*p));
+ if (wpa_s->global->add_psk == NULL)
+ return;
+ }
+ p = wpa_s->global->add_psk;
+ if (p2p_dev_addr) {
+ p->p2p = 1;
+ os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN);
+ } else {
+ p->p2p = 0;
+ os_memcpy(p->addr, mac_addr, ETH_ALEN);
+ }
+ os_memcpy(p->psk, psk, psk_len);
+ return;
+ }
+
+ if (ssid->mode != WPAS_MODE_P2P_GO || !ssid->p2p_persistent_group) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Ignore new_psk_cb on not-persistent GO");
+ return;
+ }
+
+ persistent = wpas_p2p_get_persistent(wpa_s->parent, 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");
+ return;
+ }
+
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return;
+ if (p2p_dev_addr) {
+ p->p2p = 1;
+ os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN);
+ } else {
+ p->p2p = 0;
+ os_memcpy(p->addr, mac_addr, ETH_ALEN);
+ }
+ os_memcpy(p->psk, psk, psk_len);
+
+ if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS &&
+ (last = dl_list_last(&persistent->psk_list,
+ struct psk_list_entry, list))) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove oldest PSK entry for "
+ MACSTR " (p2p=%u) to make room for a new one",
+ MAC2STR(last->addr), last->p2p);
+ dl_list_del(&last->list);
+ os_free(last);
+ }
+
+ wpas_p2p_remove_psk_entry(wpa_s->parent, persistent,
+ p2p_dev_addr ? p2p_dev_addr : mac_addr,
+ p2p_dev_addr == NULL);
+ if (p2p_dev_addr) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add new PSK for p2p_dev_addr="
+ MACSTR, MAC2STR(p2p_dev_addr));
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add new PSK for addr=" MACSTR,
+ MAC2STR(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))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+}
+
+
+static void wpas_p2p_remove_psk(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *s, const u8 *addr,
+ int iface_addr)
+{
+ int res;
+
+ res = wpas_p2p_remove_psk_entry(wpa_s, s, addr, iface_addr);
+ if (res > 0 && wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to update configuration");
+}
+
+
+static void wpas_p2p_remove_client_go(struct wpa_supplicant *wpa_s,
+ const u8 *peer, int iface_addr)
+{
+ struct hostapd_data *hapd;
+ struct hostapd_wpa_psk *psk, *prev, *rem;
+ struct sta_info *sta;
+
+ if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL ||
+ wpa_s->current_ssid->mode != WPAS_MODE_P2P_GO)
+ return;
+
+ /* Remove per-station PSK entry */
+ hapd = wpa_s->ap_iface->bss[0];
+ prev = NULL;
+ psk = hapd->conf->ssid.wpa_psk;
+ while (psk) {
+ if ((iface_addr && os_memcmp(peer, psk->addr, ETH_ALEN) == 0) ||
+ (!iface_addr &&
+ os_memcmp(peer, psk->p2p_dev_addr, ETH_ALEN) == 0)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove operating group PSK entry for "
+ MACSTR " iface_addr=%d",
+ MAC2STR(peer), iface_addr);
+ if (prev)
+ prev->next = psk->next;
+ else
+ hapd->conf->ssid.wpa_psk = psk->next;
+ rem = psk;
+ psk = psk->next;
+ os_free(rem);
+ } else {
+ prev = psk;
+ psk = psk->next;
+ }
+ }
+
+ /* Disconnect from group */
+ if (iface_addr)
+ sta = ap_get_sta(hapd, peer);
+ else
+ sta = ap_get_sta_p2p(hapd, peer);
+ if (sta) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disconnect peer " MACSTR
+ " (iface_addr=%d) from group",
+ MAC2STR(peer), iface_addr);
+ hostapd_drv_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_DEAUTH_LEAVING);
+ ap_sta_deauthenticate(hapd, sta, WLAN_REASON_DEAUTH_LEAVING);
+ }
+}
+
+
+void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
+ int iface_addr)
+{
+ struct wpa_ssid *s;
+ struct wpa_supplicant *w;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove client " MACSTR, MAC2STR(peer));
+
+ /* Remove from any persistent group */
+ for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
+ if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
+ continue;
+ if (!iface_addr)
+ wpas_remove_persistent_peer(wpa_s, s, peer, 0);
+ wpas_p2p_remove_psk(wpa_s->parent, s, peer, iface_addr);
+ }
+
+ /* Remove from any operating group */
+ for (w = wpa_s->global->ifaces; w; w = w->next)
+ wpas_p2p_remove_client_go(w, peer, iface_addr);
+}
+
+
+static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_PSK_FAILURE);
+}
+
+
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+}
+
+
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_supplicant *iface;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (!iface->current_ssid ||
+ iface->current_ssid->frequency == freq ||
+ (iface->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+ !iface->current_ssid->p2p_group))
+ continue;
+
+ /* Remove the connection with least priority */
+ if (!wpas_is_p2p_prioritized(iface)) {
+ /* STA connection has priority over existing
+ * P2P connection, so remove the interface. */
+ wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to single channel concurrent mode frequency conflict");
+ eloop_register_timeout(0, 0,
+ wpas_p2p_group_freq_conflict,
+ iface, NULL);
+ /* If connection in progress is P2P connection, do not
+ * proceed for the connection. */
+ if (wpa_s == iface)
+ return -1;
+ else
+ return 0;
+ } else {
+ /* P2P connection has priority, disable the STA network
+ */
+ wpa_supplicant_disable_network(wpa_s->global->ifaces,
+ ssid);
+ wpa_msg(wpa_s->global->ifaces, MSG_INFO,
+ WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id);
+ os_memset(wpa_s->global->ifaces->pending_bssid, 0,
+ ETH_ALEN);
+ /* If P2P connection is in progress, continue
+ * connecting...*/
+ if (wpa_s == iface)
+ return 0;
+ else
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (ssid == NULL || !ssid->p2p_group)
return 0;
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs == wpa_s || !ifs->driver->get_radio_name)
+ if (wpa_s->p2p_last_4way_hs_fail &&
+ wpa_s->p2p_last_4way_hs_fail == ssid) {
+ u8 go_dev_addr[ETH_ALEN];
+ struct wpa_ssid *persistent;
+
+ if (wpas_p2p_persistent_group(wpa_s, go_dev_addr,
+ ssid->ssid,
+ ssid->ssid_len) <= 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not determine whether 4-way handshake failures were for a persistent group");
+ goto disconnect;
+ }
+
+ 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,
+ 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,
+ P2P_EVENT_PERSISTENT_PSK_FAIL "%d",
+ persistent->id);
+ disconnect:
+ wpa_s->p2p_last_4way_hs_fail = NULL;
+ /*
+ * Remove the group from a timeout to avoid issues with caller
+ * continuing to use the interface if this is on a P2P group
+ * interface.
+ */
+ eloop_register_timeout(0, 0, wpas_p2p_psk_failure_removal,
+ wpa_s, NULL);
+ return 1;
+ }
+
+ wpa_s->p2p_last_4way_hs_fail = ssid;
+ return 0;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf * wpas_p2p_nfc_handover(int ndef, struct wpabuf *wsc,
+ struct wpabuf *p2p)
+{
+ struct wpabuf *ret;
+ size_t wsc_len;
+
+ if (p2p == NULL) {
+ wpabuf_free(wsc);
+ wpa_printf(MSG_DEBUG, "P2P: No p2p buffer for handover");
+ return NULL;
+ }
+
+ wsc_len = wsc ? wpabuf_len(wsc) : 0;
+ ret = wpabuf_alloc(2 + wsc_len + 2 + wpabuf_len(p2p));
+ if (ret == NULL) {
+ wpabuf_free(wsc);
+ wpabuf_free(p2p);
+ return NULL;
+ }
+
+ wpabuf_put_be16(ret, wsc_len);
+ if (wsc)
+ wpabuf_put_buf(ret, wsc);
+ wpabuf_put_be16(ret, wpabuf_len(p2p));
+ wpabuf_put_buf(ret, p2p);
+
+ wpabuf_free(wsc);
+ wpabuf_free(p2p);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "P2P: Generated NFC connection handover message", ret);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_p2p(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to NDEF encapsulate handover request");
+ return NULL;
+ }
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+static int wpas_p2p_cli_freq(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **ssid, u8 *go_dev_addr)
+{
+ struct wpa_supplicant *iface;
+
+ if (go_dev_addr)
+ os_memset(go_dev_addr, 0, ETH_ALEN);
+ if (ssid)
+ *ssid = NULL;
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (iface->wpa_state < WPA_ASSOCIATING ||
+ iface->current_ssid == NULL || iface->assoc_freq == 0 ||
+ !iface->current_ssid->p2p_group ||
+ iface->current_ssid->mode != WPAS_MODE_INFRA)
+ continue;
+ if (ssid)
+ *ssid = iface->current_ssid;
+ if (go_dev_addr)
+ os_memcpy(go_dev_addr, iface->go_dev_addr, ETH_ALEN);
+ return iface->assoc_freq;
+ }
+ return 0;
+}
+
+
+struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct wpabuf *wsc, *p2p;
+ struct wpa_ssid *ssid;
+ u8 go_dev_addr[ETH_ALEN];
+ int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: P2P disabled - cannot build handover request");
+ return NULL;
+ }
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No DH key available for handover request");
+ return NULL;
+ }
+
+ if (cli_freq == 0) {
+ wsc = wps_build_nfc_handover_req_p2p(
+ wpa_s->parent->wps, wpa_s->conf->wps_nfc_dh_pubkey);
+ } else
+ wsc = NULL;
+ p2p = p2p_build_nfc_handover_req(wpa_s->global->p2p, cli_freq,
+ go_dev_addr, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+
+ return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int tag)
+{
+ struct wpabuf *wsc, *p2p;
+ struct wpa_ssid *ssid;
+ u8 go_dev_addr[ETH_ALEN];
+ int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return NULL;
+
+ if (!tag && wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+
+ if (cli_freq == 0) {
+ wsc = wps_build_nfc_handover_sel_p2p(
+ wpa_s->parent->wps,
+ tag ? wpa_s->conf->wps_nfc_dev_pw_id :
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ tag ? wpa_s->conf->wps_nfc_dev_pw : NULL);
+ } else
+ wsc = NULL;
+ p2p = p2p_build_nfc_handover_sel(wpa_s->global->p2p, cli_freq,
+ go_dev_addr, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+
+ return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate join-group based on NFC "
+ "connection handover (freq=%d)",
+ params->go_freq);
+
+ if (params->go_freq && params->go_ssid_len) {
+ wpa_s->p2p_wps_method = WPS_NFC;
+ wpa_s->pending_join_wps_method = WPS_NFC;
+ os_memset(wpa_s->pending_join_iface_addr, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_join_dev_addr, params->go_dev_addr,
+ ETH_ALEN);
+ return wpas_p2p_join_start(wpa_s, params->go_freq,
+ params->go_ssid,
+ params->go_ssid_len);
+ }
+
+ 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);
+}
+
+
+static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params, int tag)
+{
+ int res, persistent;
+ struct wpa_ssid *ssid;
+
+ wpa_printf(MSG_DEBUG, "P2P: Authorize join-group based on NFC "
+ "connection handover");
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ ssid = wpa_s->current_ssid;
+ if (ssid == NULL)
+ continue;
+ if (ssid->mode != WPAS_MODE_P2P_GO)
+ continue;
+ if (wpa_s->ap_iface == NULL)
continue;
+ break;
+ }
+ if (wpa_s == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not find GO interface");
+ return -1;
+ }
+
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->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);
+ if (res)
+ return res;
+
+ if (!tag) {
+ wpa_printf(MSG_DEBUG, "P2P: Negotiated handover - wait for peer to join without invitation");
+ return 0;
+ }
+
+ if (!params->peer ||
+ !(params->peer->dev_capab & P2P_DEV_CAPAB_INVITATION_PROCEDURE))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - invite peer " MACSTR
+ " to join", MAC2STR(params->peer->p2p_device_addr));
+
+ wpa_s->global->p2p_invite_group = wpa_s;
+ persistent = ssid->p2p_persistent_group &&
+ wpas_p2p_get_persistent(wpa_s->parent,
+ params->peer->p2p_device_addr,
+ ssid->ssid, ssid->ssid_len);
+ wpa_s->parent->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);
+}
+
+
+static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params,
+ int forced_freq)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate GO Negotiation based on NFC "
+ "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);
+}
+
+
+static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params,
+ int forced_freq)
+{
+ int res;
- rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
- if (!rn2 || os_strcmp(rn, rn2) != 0)
+ wpa_printf(MSG_DEBUG, "P2P: Authorize GO Negotiation based on NFC "
+ "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);
+ if (res)
+ return res;
+
+ res = wpas_p2p_listen(wpa_s, 60);
+ if (res) {
+ p2p_unauthorize(wpa_s->global->p2p,
+ params->peer->p2p_device_addr);
+ }
+
+ return res;
+}
+
+
+static int wpas_p2p_nfc_connection_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data,
+ int sel, int tag, int forced_freq)
+{
+ const u8 *pos, *end;
+ u16 len, id;
+ struct p2p_nfc_params params;
+ int res;
+
+ os_memset(&params, 0, sizeof(params));
+ params.sel = sel;
+
+ wpa_hexdump_buf(MSG_DEBUG, "P2P: Received NFC tag payload", data);
+
+ pos = wpabuf_head(data);
+ end = pos + wpabuf_len(data);
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of WSC "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
+ "attributes");
+ return -1;
+ }
+ params.wsc_attr = pos;
+ params.wsc_len = len;
+ pos += len;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of P2P "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
+ "attributes");
+ return -1;
+ }
+ params.p2p_attr = pos;
+ params.p2p_len = len;
+ pos += len;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: WSC attributes",
+ params.wsc_attr, params.wsc_len);
+ wpa_hexdump(MSG_DEBUG, "P2P: P2P attributes",
+ params.p2p_attr, params.p2p_len);
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "P2P: Ignored extra data after P2P attributes",
+ pos, end - pos);
+ }
+
+ res = p2p_process_nfc_connection_handover(wpa_s->global->p2p, &params);
+ if (res)
+ return res;
+
+ if (params.next_step == NO_ACTION)
+ return 0;
+
+ if (params.next_step == BOTH_GO) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_BOTH_GO "peer=" MACSTR,
+ MAC2STR(params.peer->p2p_device_addr));
+ return 0;
+ }
+
+ if (params.next_step == PEER_CLIENT) {
+ if (!is_zero_ether_addr(params.go_dev_addr)) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+ "peer=" MACSTR " freq=%d go_dev_addr=" MACSTR
+ " ssid=\"%s\"",
+ MAC2STR(params.peer->p2p_device_addr),
+ params.go_freq,
+ MAC2STR(params.go_dev_addr),
+ wpa_ssid_txt(params.go_ssid,
+ params.go_ssid_len));
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+ "peer=" MACSTR " freq=%d",
+ MAC2STR(params.peer->p2p_device_addr),
+ params.go_freq);
+ }
+ return 0;
+ }
+
+ if (wpas_p2p_cli_freq(wpa_s, NULL, NULL)) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_WHILE_CLIENT "peer="
+ MACSTR, MAC2STR(params.peer->p2p_device_addr));
+ return 0;
+ }
+
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
+
+ if (params.oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "P2P: No peer OOB Dev Pw "
+ "received");
+ return -1;
+ }
+
+ id = WPA_GET_BE16(params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_printf(MSG_DEBUG, "P2P: Peer OOB Dev Pw %u", id);
+ wpa_hexdump(MSG_DEBUG, "P2P: Peer OOB Public Key hash",
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ os_memcpy(wpa_s->p2p_peer_oob_pubkey_hash,
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_s->p2p_peer_oob_pk_hash_known = 1;
+
+ if (tag) {
+ if (id < 0x10) {
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - invalid "
+ "peer OOB Device Password Id %u", id);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - use peer OOB "
+ "Device Password Id %u", id);
+ wpa_hexdump_key(MSG_DEBUG, "P2P: Peer OOB Device Password",
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ wpa_s->p2p_oob_dev_pw_id = id;
+ wpa_s->p2p_oob_dev_pw = wpabuf_alloc_copy(
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ if (wpa_s->p2p_oob_dev_pw == NULL)
+ return -1;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Using abbreviated WPS handshake "
+ "without Device Password");
+ wpa_s->p2p_oob_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ }
+
+ switch (params.next_step) {
+ case NO_ACTION:
+ case BOTH_GO:
+ case PEER_CLIENT:
+ /* already covered above */
+ return 0;
+ case JOIN_GROUP:
+ return wpas_p2p_nfc_join_group(wpa_s, &params);
+ case AUTH_JOIN:
+ return wpas_p2p_nfc_auth_join(wpa_s, &params, tag);
+ case INIT_GO_NEG:
+ return wpas_p2p_nfc_init_go_neg(wpa_s, &params, forced_freq);
+ case RESP_GO_NEG:
+ /* TODO: use own OOB Dev Pw */
+ return wpas_p2p_nfc_resp_go_neg(wpa_s, &params, forced_freq);
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data, int forced_freq)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return -1;
+
+ return wpas_p2p_nfc_connection_handover(wpa_s, data, 1, 1, forced_freq);
+}
+
+
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+ const struct wpabuf *req,
+ const struct wpabuf *sel, int forced_freq)
+{
+ struct wpabuf *tmp;
+ int ret;
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "NFC: P2P connection handover reported");
+
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Req",
+ wpabuf_head(req), wpabuf_len(req));
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Sel",
+ wpabuf_head(sel), wpabuf_len(sel));
+ if (forced_freq)
+ wpa_printf(MSG_DEBUG, "NFC: Forced freq %d", forced_freq);
+ tmp = ndef_parse_p2p(init ? sel : req);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not parse NDEF");
+ return -1;
+ }
+
+ ret = wpas_p2p_nfc_connection_handover(wpa_s, tmp, init, 0,
+ forced_freq);
+ wpabuf_free(tmp);
+
+ return ret;
+}
+
+
+int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
+{
+ const u8 *if_addr;
+ int go_intent = wpa_s->conf->p2p_go_intent;
+ struct wpa_supplicant *iface;
+
+ if (wpa_s->global->p2p == NULL)
+ return -1;
+
+ if (!enabled) {
+ wpa_printf(MSG_DEBUG, "P2P: Disable use of own NFC Tag");
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+ {
+ if (!iface->ap_iface)
+ continue;
+ hostapd_wps_nfc_token_disable(iface->ap_iface->bss[0]);
+ }
+ p2p_set_authorized_oob_dev_pw_id(wpa_s->global->p2p, 0,
+ 0, NULL);
+ if (wpa_s->p2p_nfc_tag_enabled)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
+ wpa_s->p2p_nfc_tag_enabled = 0;
+ return 0;
+ }
+
+ if (wpa_s->global->p2p_disabled)
+ return -1;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+ wpa_s->conf->wps_nfc_dev_pw == NULL ||
+ wpa_s->conf->wps_nfc_dev_pw_id < 0x10) {
+ wpa_printf(MSG_DEBUG, "P2P: NFC password token not configured "
+ "to allow static handover cases");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Enable use of own NFC Tag");
+
+ wpa_s->p2p_oob_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+ if (wpa_s->p2p_oob_dev_pw == NULL)
+ return -1;
+ wpa_s->p2p_peer_oob_pk_hash_known = 0;
+
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO ||
+ wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) {
+ /*
+ * P2P Group Interface present and the command came on group
+ * interface, so enable the token for the current interface.
+ */
+ wpa_s->create_p2p_iface = 0;
+ } else {
+ wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
+ }
+
+ if (wpa_s->create_p2p_iface) {
+ enum wpa_driver_if_type iftype;
+ /* Prepare to add a new interface for the group */
+ iftype = WPA_IF_P2P_GROUP;
+ if (go_intent == 15)
+ iftype = WPA_IF_P2P_GO;
+ if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+ "interface for the group");
+ return -1;
+ }
+
+ if_addr = wpa_s->pending_interface_addr;
+ } else
+ if_addr = wpa_s->own_addr;
+
+ wpa_s->p2p_nfc_tag_enabled = enabled;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ struct hostapd_data *hapd;
+ if (iface->ap_iface == NULL)
continue;
- if (ifs->wpa_state > WPA_SCANNING) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
- "delay due to concurrent operation on "
- "interface %s",
- P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname);
- return P2P_CONCURRENT_SEARCH_DELAY;
+ hapd = iface->ap_iface->bss[0];
+ wpabuf_free(hapd->conf->wps_nfc_dh_pubkey);
+ hapd->conf->wps_nfc_dh_pubkey =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+ wpabuf_free(hapd->conf->wps_nfc_dh_privkey);
+ hapd->conf->wps_nfc_dh_privkey =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+ wpabuf_free(hapd->conf->wps_nfc_dev_pw);
+ hapd->conf->wps_nfc_dev_pw =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+ hapd->conf->wps_nfc_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+
+ if (hostapd_wps_nfc_token_enable(iface->ap_iface->bss[0]) < 0) {
+ wpa_dbg(iface, MSG_DEBUG,
+ "P2P: Failed to enable NFC Tag for GO");
}
}
+ p2p_set_authorized_oob_dev_pw_id(
+ wpa_s->global->p2p, wpa_s->conf->wps_nfc_dev_pw_id, go_intent,
+ if_addr);
return 0;
}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs,
+ unsigned int num)
+{
+ u8 curr_chan, cand, chan;
+ unsigned int i;
+
+ curr_chan = p2p_get_listen_channel(wpa_s->global->p2p);
+ for (i = 0, cand = 0; i < num; i++) {
+ ieee80211_freq_to_chan(freqs[i].freq, &chan);
+ if (curr_chan == chan) {
+ cand = 0;
+ break;
+ }
+
+ if (chan == 1 || chan == 6 || chan == 11)
+ cand = chan;
+ }
+
+ if (cand) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Update Listen channel to %u based on operating channel",
+ cand);
+ p2p_set_listen_channel(wpa_s->global->p2p, 81, cand, 0);
+ }
+}
+
+
+void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_used_freq_data *freqs;
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+
+ /*
+ * If possible, optimize the Listen channel to be a channel that is
+ * already used by one of the other interfaces.
+ */
+ if (!wpa_s->conf->p2p_optimize_listen_chan)
+ return;
+
+ if (!wpa_s->current_ssid || wpa_s->wpa_state != WPA_COMPLETED)
+ return;
+
+ freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
+ if (!freqs)
+ return;
+
+ num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+
+ wpas_p2p_optimize_listen_channel(wpa_s, freqs, num);
+ os_free(freqs);
+}
+
+
+void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+ "the management interface is being removed");
+ wpas_p2p_deinit_global(wpa_s->global);
+ }
+}
+
+
+void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->ap_iface->bss)
+ wpa_s->ap_iface->bss[0]->p2p_group = NULL;
+ wpas_p2p_group_deinit(wpa_s);
+}
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.h b/contrib/wpa/wpa_supplicant/p2p_supplicant.h
index b6ecf14..b786178 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.h
@@ -13,37 +13,42 @@ enum p2p_wps_method;
struct p2p_go_neg_results;
enum p2p_send_action_result;
struct p2p_peer_info;
+struct p2p_channels;
+struct wps_event_fail;
+struct p2ps_provision;
-int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
-void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
-void wpas_p2p_deinit_global(struct wpa_global *global);
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
+ const char *conf_p2p_dev);
+struct wpa_supplicant * wpas_get_p2p_go_iface(struct wpa_supplicant *wpa_s,
+ const u8 *ssid, size_t ssid_len);
+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);
-void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
- unsigned int freq, unsigned int duration);
-void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
- unsigned int freq);
-int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+ int pd, int ht40, int vht);
+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 freq, int ht40, int vht);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq, int ht40);
+ int force_freq, int neg_freq, int ht40,
+ int vht, const struct p2p_channels *channels,
+ int connection_timeout);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
-void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- int registrar);
enum wpas_p2p_prov_disc_use {
WPAS_P2P_PD_FOR_GO_NEG,
WPAS_P2P_PD_FOR_JOIN,
- WPAS_P2P_PD_AUTO
+ WPAS_P2P_PD_AUTO,
+ WPAS_P2P_PD_FOR_ASP
};
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *config_method,
- enum wpas_p2p_prov_disc_use use);
+ enum wpas_p2p_prov_disc_use use,
+ struct p2ps_provision *p2ps_prov);
void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
const u8 *data, size_t data_len,
enum p2p_send_action_result result);
@@ -53,37 +58,19 @@ enum p2p_discovery_type;
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay);
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_cnt, const char **seek_string, int freq);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
+int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
u8 *buf, size_t len, int p2p_group);
-int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
- const u8 *dst, const u8 *bssid,
- const u8 *ie, size_t ie_len,
- int ssi_signal);
-void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
- const u8 *sa, const u8 *bssid,
- u8 category, const u8 *data, size_t len, int freq);
void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
-void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
-void wpas_dev_found(void *ctx, const u8 *addr,
- const struct p2p_peer_info *info,
- int new_device);
-void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res);
-void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id);
-void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
- const u8 *dev_addr, const u8 *pri_dev_type,
- const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab, const u8 *group_id,
- size_t group_id_len);
-void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods);
-void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
- u16 update_indic, const u8 *tlvs, size_t tlvs_len);
-void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len);
+void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
+ const char *svc_str, const char *info_substr);
u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
u8 version, const char *query);
u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
@@ -102,13 +89,17 @@ int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
const char *service);
int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
const char *service);
+int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s, int auto_accept,
+ u32 adv_id, const char *adv_str, u8 svc_state,
+ u16 config_methods, const char *svc_info);
+int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id);
+int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id);
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 ht40, int vht, int pref_freq);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
-void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
u32 interval1, u32 duration2, u32 interval2);
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
@@ -119,25 +110,12 @@ int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
u16 reason_code, const u8 *ie, size_t ie_len,
int locally_generated);
-void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
int duration);
int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled);
-void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s);
-void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s);
-int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
-void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
int wpas_p2p_cancel(struct wpa_supplicant *wpa_s);
-void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
-void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
- int freq_24, int freq_5, int freq_overall);
int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr);
int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
-void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
- struct wps_event_fail *fail);
-int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
-void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid);
struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *ssid,
size_t ssid_len);
@@ -146,6 +124,193 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
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);
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,
+ const u8 *psk, size_t psk_len);
+void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
+ int iface_addr);
+struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef);
+struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int tag);
+int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data, int forced_freq);
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+ const struct wpabuf *req,
+ const struct wpabuf *sel, int forced_freq);
+int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
+void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
+
+#ifdef CONFIG_P2P
+
+int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
+void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
+int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len,
+ int ssi_signal);
+void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+ int registrar);
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+ int freq_24, int freq_5, int freq_overall);
+void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+ const u8 *sa, const u8 *bssid,
+ u8 category, const u8 *data, size_t len, int freq);
+void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq, unsigned int duration);
+void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq);
+void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s);
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s);
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
+int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
+void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
+void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s);
+void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s);
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
+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);
+
+#else /* CONFIG_P2P */
+
+static inline int
+wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s,
+ const u8 *addr,
+ const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len,
+ int ssi_signal)
+{
+ return 0;
+}
+
+static inline void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int registrar)
+{
+}
+
+static inline void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+ int freq_24, int freq_5,
+ int freq_overall)
+{
+}
+
+static inline void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s,
+ const u8 *da,
+ const u8 *sa, const u8 *bssid,
+ u8 category, const u8 *data, size_t len,
+ int freq)
+{
+}
+
+static inline void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ unsigned int duration)
+{
+}
+
+static inline void
+wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq)
+{
+}
+
+static inline void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail)
+{
+}
+
+static inline int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s,
+ const char *ifname)
+{
+ return 0;
+}
+
+#endif /* CONFIG_P2P */
#endif /* P2P_SUPPLICANT_H */
diff --git a/contrib/wpa/wpa_supplicant/preauth_test.c b/contrib/wpa/wpa_supplicant/preauth_test.c
index 3503e65..ed57085 100644
--- a/contrib/wpa/wpa_supplicant/preauth_test.c
+++ b/contrib/wpa/wpa_supplicant/preauth_test.c
@@ -27,9 +27,6 @@
#include "drivers/driver.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
struct wpa_driver_ops *wpa_drivers[] = { NULL };
@@ -309,7 +306,7 @@ int main(int argc, char *argv[])
}
os_memset(&wpa_s, 0, sizeof(wpa_s));
- wpa_s.conf = wpa_config_read(argv[1]);
+ wpa_s.conf = wpa_config_read(argv[1], NULL);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", argv[1]);
return -1;
diff --git a/contrib/wpa/wpa_supplicant/scan.c b/contrib/wpa/wpa_supplicant/scan.c
index d2b671a..805891a 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, 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 "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -21,6 +22,7 @@
#include "notify.h"
#include "bss.h"
#include "scan.h"
+#include "mesh.h"
static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -94,6 +96,10 @@ int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->conf->ssid;
int count = 0, disabled = 0;
+
+ if (wpa_s->p2p_mgmt)
+ return 0; /* no normal network profiles on p2p_mgmt interface */
+
while (ssid) {
if (!wpas_network_disabled(wpa_s, ssid))
count++;
@@ -140,71 +146,69 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
}
-static int int_array_len(const int *a)
-{
- int i;
- for (i = 0; a && a[i]; i++)
- ;
- return i;
-}
-
-
-static void int_array_concat(int **res, const int *a)
+static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
{
- int reslen, alen, i;
- int *n;
-
- reslen = int_array_len(*res);
- alen = int_array_len(a);
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_driver_scan_params *params = work->ctx;
+ int ret;
- n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
- if (n == NULL) {
- os_free(*res);
- *res = NULL;
+ if (deinit) {
+ if (!work->started) {
+ wpa_scan_free_params(params);
+ return;
+ }
+ wpa_supplicant_notify_scanning(wpa_s, 0);
+ wpas_notify_scan_done(wpa_s, 0);
+ wpa_s->scan_work = NULL;
return;
}
- for (i = 0; i <= alen; i++)
- n[reslen + i] = a[i];
- *res = n;
-}
-
-
-static int freq_cmp(const void *a, const void *b)
-{
- int _a = *(int *) a;
- int _b = *(int *) b;
-
- if (_a == 0)
- return 1;
- if (_b == 0)
- return -1;
- return _a - _b;
-}
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for a scan");
+ radio_work_done(work);
+ return;
+ }
-static void int_array_sort_unique(int *a)
-{
- int alen;
- int i, j;
+ wpa_supplicant_notify_scanning(wpa_s, 1);
- if (a == NULL)
- 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);
+ wpa_scan_free_params(params);
+ work->ctx = NULL;
+ if (ret) {
+ int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ;
- alen = int_array_len(a);
- qsort(a, alen, sizeof(int), freq_cmp);
+ if (wpa_s->disconnected)
+ retry = 0;
- i = 0;
- j = 1;
- while (a[i] && a[j]) {
- if (a[i] == a[j]) {
- j++;
- continue;
+ wpa_supplicant_notify_scanning(wpa_s, 0);
+ wpas_notify_scan_done(wpa_s, 0);
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s,
+ wpa_s->scan_prev_wpa_state);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d%s",
+ ret, retry ? " retry=1" : "");
+ radio_work_done(work);
+
+ if (retry) {
+ /* 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);
}
- a[++i] = a[j++];
+ return;
}
- if (a[i])
- i++;
- a[i] = 0;
+
+ os_get_reltime(&wpa_s->scan_trigger_time);
+ wpa_s->scan_runs++;
+ wpa_s->normal_scans++;
+ wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
+ wpa_s->scan_work = work;
}
@@ -217,20 +221,24 @@ static void int_array_sort_unique(int *a)
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
- int ret;
+ struct wpa_driver_scan_params *ctx;
- wpa_supplicant_notify_scanning(wpa_s, 1);
+ if (wpa_s->scan_work) {
+ wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
+ return -1;
+ }
- ret = wpa_drv_scan(wpa_s, params);
- if (ret) {
- wpa_supplicant_notify_scanning(wpa_s, 0);
- wpas_notify_scan_done(wpa_s, 0);
- } else {
- wpa_s->scan_runs++;
- wpa_s->normal_scans++;
+ 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)
+ {
+ wpa_scan_free_params(ctx);
+ return -1;
}
- return ret;
+ return 0;
}
@@ -258,10 +266,9 @@ wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
-static int
-wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- int interval)
+int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ int interval)
{
int ret;
@@ -276,7 +283,7 @@ wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
{
int ret;
@@ -308,7 +315,7 @@ wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
}
if (count == 0)
return NULL;
- ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter));
+ ssids = os_calloc(count, sizeof(struct wpa_driver_scan_filter));
if (ssids == NULL)
return NULL;
@@ -336,7 +343,7 @@ static void wpa_supplicant_optimize_freqs(
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
"preferred frequency %d MHz",
wpa_s->go_params->freq);
- params->freqs = os_zalloc(2 * sizeof(int));
+ params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
params->freqs[0] = wpa_s->go_params->freq;
} else if (wpa_s->p2p_in_provisioning < 8 &&
@@ -350,6 +357,32 @@ static void wpa_supplicant_optimize_freqs(
}
wpa_s->p2p_in_provisioning++;
}
+
+ if (params->freqs == NULL && wpa_s->p2p_in_invitation) {
+ /*
+ * Optimize scan based on GO information during persistent
+ * group reinvocation
+ */
+ if (wpa_s->p2p_in_invitation < 5 &&
+ wpa_s->p2p_invite_go_freq > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
+ wpa_s->p2p_invite_go_freq);
+ params->freqs = os_calloc(2, sizeof(int));
+ if (params->freqs)
+ params->freqs[0] = wpa_s->p2p_invite_go_freq;
+ }
+ wpa_s->p2p_in_invitation++;
+ if (wpa_s->p2p_in_invitation > 20) {
+ /*
+ * This should not really happen since the variable is
+ * cleared on group removal, but if it does happen, make
+ * sure we do not get stuck in special invitation scan
+ * mode.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation");
+ wpa_s->p2p_in_invitation = 0;
+ }
+ }
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS
@@ -360,18 +393,19 @@ static void wpa_supplicant_optimize_freqs(
*/
wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
"that was used during provisioning", wpa_s->wps_freq);
- params->freqs = os_zalloc(2 * sizeof(int));
+ params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
params->freqs[0] = wpa_s->wps_freq;
wpa_s->after_wps--;
- }
+ } else if (wpa_s->after_wps)
+ wpa_s->after_wps--;
if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq)
{
/* Optimize provisioning scan based on already known channel */
wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
wpa_s->wps_freq);
- params->freqs = os_zalloc(2 * sizeof(int));
+ params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
params->freqs[0] = wpa_s->wps_freq;
wpa_s->known_wps_freq = 0; /* only do this once */
@@ -388,11 +422,17 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
return;
wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB);
- wpabuf_put_u8(buf, 4);
+ wpabuf_put_u8(buf, 6);
wpabuf_put_u8(buf, 0x00);
wpabuf_put_u8(buf, 0x00);
wpabuf_put_u8(buf, 0x00);
wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */
+ wpabuf_put_u8(buf, 0x00);
+#ifdef CONFIG_HS20
+ wpabuf_put_u8(buf, 0x40); /* Bit 46 - WNM-Notification */
+#else /* CONFIG_HS20 */
+ wpabuf_put_u8(buf, 0x00);
+#endif /* CONFIG_HS20 */
wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
@@ -444,8 +484,15 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
}
#endif /* CONFIG_P2P */
+ wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie);
+
#endif /* CONFIG_WPS */
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
+ wpas_hs20_add_indication(extra_ie, -1);
+#endif /* CONFIG_HS20 */
+
return extra_ie;
}
@@ -474,59 +521,122 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
return 0;
}
+#endif /* CONFIG_P2P */
-/*
- * Find the operating frequency of any other virtual interface that is using
- * the same radio concurrently.
- */
-static int shared_vif_oper_freq(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)
{
- const char *rn, *rn2;
- struct wpa_supplicant *ifs;
- u8 bssid[ETH_ALEN];
+ u16 i;
- if (!wpa_s->driver->get_radio_name)
- return -1;
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode == mode)
+ return &modes[i];
+ }
- rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
- if (rn == NULL || rn[0] == '\0')
- return -1;
+ return NULL;
+}
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs == wpa_s || !ifs->driver->get_radio_name)
- continue;
- rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
- if (!rn2 || os_strcmp(rn, rn2) != 0)
+static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params)
+{
+ /* Include only supported channels for the specified band */
+ struct hostapd_hw_modes *mode;
+ int count, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ if (mode == NULL) {
+ /* No channels supported in this band - use empty list */
+ params->freqs = os_zalloc(sizeof(int));
+ return;
+ }
+
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ for (count = 0, i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
+ params->freqs[count++] = mode->channels[i].freq;
+ }
+}
+
+
+static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
+{
+ if (wpa_s->hw.modes == NULL)
+ return; /* unknown what channels the driver supports */
+ if (params->freqs)
+ return; /* already using a limited channel set */
+ if (wpa_s->setband == WPA_SETBAND_5G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ params);
+ else if (wpa_s->setband == WPA_SETBAND_2G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+ params);
+}
- if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+
+static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ size_t max_ssids)
+{
+ unsigned int i;
+ struct wpa_ssid *ssid;
+
+ for (i = 0; i < wpa_s->scan_id_count; i++) {
+ unsigned int j;
+
+ ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]);
+ if (!ssid || !ssid->scan_ssid)
continue;
- if (ifs->current_ssid->mode == WPAS_MODE_AP ||
- ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
- return ifs->current_ssid->frequency;
- if (wpa_drv_get_bssid(ifs, bssid) == 0)
- return ifs->assoc_freq;
+ 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++;
}
- return 0;
+ wpa_s->scan_id_count = 0;
}
-#endif /* CONFIG_P2P */
-
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
- enum scan_req_type scan_req = NORMAL_SCAN_REQ;
- int ret;
+ int ret, p2p_in_prog;
struct wpabuf *extra_ie = NULL;
struct wpa_driver_scan_params params;
struct wpa_driver_scan_params *scan_params;
size_t max_ssids;
- enum wpa_states prev_state;
+ 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;
+ }
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
@@ -539,13 +649,20 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
return;
}
+ if (wpa_s->scanning) {
+ /*
+ * If we are already in scanning state, we shall reschedule the
+ * the incoming scan request.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ return;
+ }
+
if (!wpa_supplicant_enabled_networks(wpa_s) &&
wpa_s->scan_req == NORMAL_SCAN_REQ) {
wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-#ifdef CONFIG_P2P
- wpa_s->sta_scan_pending = 0;
-#endif /* CONFIG_P2P */
return;
}
@@ -562,22 +679,24 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
return;
}
-#ifdef CONFIG_P2P
- if (wpas_p2p_in_progress(wpa_s)) {
- if (wpa_s->sta_scan_pending &&
- wpas_p2p_in_progress(wpa_s) == 2 &&
- wpa_s->global->p2p_cb_on_scan_complete) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
- "mode scan during P2P search");
- } else {
- wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
- "while P2P operation is in progress");
- wpa_s->sta_scan_pending = 1;
- wpa_supplicant_req_scan(wpa_s, 5, 0);
- return;
+ ssid = NULL;
+ if (wpa_s->scan_req != MANUAL_SCAN_REQ &&
+ wpa_s->connect_without_scan) {
+ connect_without_scan = 1;
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->connect_without_scan)
+ break;
}
}
-#endif /* CONFIG_P2P */
+
+ p2p_in_prog = wpas_p2p_in_progress(wpa_s);
+ if (p2p_in_prog && p2p_in_prog != 2 &&
+ (!ssid ||
+ (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
+ wpa_supplicant_req_scan(wpa_s, 5, 0);
+ return;
+ }
if (wpa_s->conf->ap_scan == 2)
max_ssids = 1;
@@ -587,12 +706,22 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
max_ssids = WPAS_MAX_SCAN_SSIDS;
}
- scan_req = wpa_s->scan_req;
+ wpa_s->last_scan_req = wpa_s->scan_req;
wpa_s->scan_req = NORMAL_SCAN_REQ;
+ if (connect_without_scan) {
+ wpa_s->connect_without_scan = NULL;
+ if (ssid) {
+ wpa_printf(MSG_DEBUG, "Start a pre-selected network "
+ "without scan step");
+ wpa_supplicant_associate(wpa_s, NULL, ssid);
+ return;
+ }
+ }
+
os_memset(&params, 0, sizeof(params));
- prev_state = wpa_s->wpa_state;
+ wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
if (wpa_s->wpa_state == WPA_DISCONNECTED ||
wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
@@ -605,30 +734,30 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
goto scan;
}
- if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) {
- for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
- if (ssid == wpa_s->connect_without_scan)
- break;
- }
- wpa_s->connect_without_scan = NULL;
- if (ssid) {
- wpa_printf(MSG_DEBUG, "Start a pre-selected network "
- "without scan step");
- wpa_supplicant_associate(wpa_s, NULL, ssid);
- return;
- }
- }
-
#ifdef CONFIG_P2P
if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
- wpa_s->go_params) {
- wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
- "P2P group formation");
+ wpa_s->go_params && !wpa_s->conf->passive_scan) {
+ wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
+ wpa_s->p2p_in_provisioning,
+ wpa_s->show_group_started);
params.ssids[0].ssid = wpa_s->go_params->ssid;
params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
params.num_ssids = 1;
goto ssid_list_set;
}
+
+ if (wpa_s->p2p_in_invitation) {
+ if (wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during invitation");
+ params.ssids[0].ssid = wpa_s->current_ssid->ssid;
+ params.ssids[0].ssid_len =
+ wpa_s->current_ssid->ssid_len;
+ params.num_ssids = 1;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation");
+ }
+ goto ssid_list_set;
+ }
#endif /* CONFIG_P2P */
/* Find the starting point from which to continue scanning */
@@ -643,7 +772,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
}
- if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
+ if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
+ wpa_s->conf->ap_scan == 2) {
wpa_s->connect_without_scan = NULL;
wpa_s->prev_scan_wildcard = 0;
wpa_supplicant_assoc_try(wpa_s, ssid);
@@ -654,6 +784,36 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
* wildcard SSID.
*/
ssid = NULL;
+ } else if (wpa_s->reattach && wpa_s->current_ssid != NULL) {
+ /*
+ * Perform single-channel single-SSID scan for
+ * reassociate-to-same-BSS operation.
+ */
+ /* Setup SSID */
+ ssid = wpa_s->current_ssid;
+ wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
+ ssid->ssid, ssid->ssid_len);
+ params.ssids[0].ssid = ssid->ssid;
+ params.ssids[0].ssid_len = ssid->ssid_len;
+ params.num_ssids = 1;
+
+ /*
+ * Allocate memory for frequency array, allocate one extra
+ * 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;
+ }
+ params.freqs[0] = wpa_s->assoc_freq;
+ params.freqs[1] = 0;
+
+ /*
+ * Reset the reattach flag so that we fall back to full scan if
+ * this scan fails.
+ */
+ wpa_s->reattach = 0;
} else {
struct wpa_ssid *start = ssid, *tssid;
int freqs_set = 0;
@@ -680,7 +840,13 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
ssid = wpa_s->conf->ssid;
}
- for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
+ if (wpa_s->scan_id_count &&
+ wpa_s->last_scan_req == MANUAL_SCAN_REQ)
+ wpa_set_scan_ssids(wpa_s, &params, max_ssids);
+
+ for (tssid = wpa_s->conf->ssid;
+ wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid;
+ tssid = tssid->next) {
if (wpas_network_disabled(wpa_s, tssid))
continue;
if ((params.freqs || !freqs_set) && tssid->scan_freq) {
@@ -721,6 +887,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
"the scan request");
params.num_ssids++;
+ } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_passive && params.num_ssids == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
+ } else if (wpa_s->conf->passive_scan) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Use passive scan based on configuration");
} else {
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
params.num_ssids++;
@@ -734,10 +906,19 @@ ssid_list_set:
wpa_supplicant_optimize_freqs(wpa_s, &params);
extra_ie = wpa_supplicant_extra_ies(wpa_s);
-#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
- wpas_hs20_add_indication(extra_ie);
-#endif /* CONFIG_HS20 */
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_only_new) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to manual only_new=1 scan");
+ params.only_new_results = 1;
+ }
+
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
+ wpa_s->manual_scan_freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels");
+ params.freqs = wpa_s->manual_scan_freqs;
+ wpa_s->manual_scan_freqs = NULL;
+ }
if (params.freqs == NULL && wpa_s->next_scan_freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
@@ -746,6 +927,32 @@ ssid_list_set:
} else
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ wpa_setband_scan_freqs(wpa_s, &params);
+
+ /* See if user specified frequencies. If so, scan only those. */
+ if (wpa_s->conf->freq_list && !params.freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Optimize scan based on conf->freq_list");
+ int_array_concat(&params.freqs, wpa_s->conf->freq_list);
+ }
+
+ /* Use current associated channel? */
+ if (wpa_s->conf->scan_cur_freq && !params.freqs) {
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ params.freqs = os_calloc(num + 1, sizeof(int));
+ if (params.freqs) {
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ if (num > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
+ "current operating channels since "
+ "scan_cur_freq is enabled");
+ } else {
+ os_free(params.freqs);
+ params.freqs = NULL;
+ }
+ }
+ }
params.filter_ssids = wpa_supplicant_build_filter_ssids(
wpa_s->conf, &params.num_filter_ssids);
@@ -755,7 +962,7 @@ ssid_list_set:
}
#ifdef CONFIG_P2P
- if (wpa_s->p2p_in_provisioning ||
+ if (wpa_s->p2p_in_provisioning || wpa_s->p2p_in_invitation ||
(wpa_s->show_group_started && wpa_s->go_params)) {
/*
* The interface may not yet be in P2P mode, so we have to
@@ -765,6 +972,14 @@ ssid_list_set:
}
#endif /* CONFIG_P2P */
+ if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+ params.mac_addr_rand = 1;
+ if (wpa_s->mac_addr_scan) {
+ params.mac_addr = wpa_s->mac_addr_scan;
+ params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
+ }
+ }
+
scan_params = &params;
scan:
@@ -778,44 +993,80 @@ scan:
* station interface when we are not configured to prefer station
* connection and a concurrent operation is already in process.
*/
- if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
+ if (wpa_s->scan_for_connection &&
+ wpa_s->last_scan_req == NORMAL_SCAN_REQ &&
!scan_params->freqs && !params.freqs &&
wpas_is_p2p_prioritized(wpa_s) &&
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
non_p2p_network_enabled(wpa_s)) {
- int freq = shared_vif_oper_freq(wpa_s);
- if (freq > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
- "operating channel (%d MHz) since driver does "
- "not support multi-channel concurrency", freq);
- params.freqs = os_zalloc(sizeof(int) * 2);
- if (params.freqs)
- params.freqs[0] = freq;
- scan_params->freqs = params.freqs;
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ params.freqs = os_calloc(num + 1, sizeof(int));
+ if (params.freqs) {
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ if (num > 0 && num == wpa_s->num_multichan_concurrent) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used");
+ } else {
+ os_free(params.freqs);
+ params.freqs = NULL;
+ }
}
}
#endif /* CONFIG_P2P */
ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
+ if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
+ !wpa_s->manual_scan_freqs) {
+ /* Restore manual_scan_freqs for the next attempt */
+ wpa_s->manual_scan_freqs = params.freqs;
+ params.freqs = NULL;
+ }
+
wpabuf_free(extra_ie);
os_free(params.freqs);
os_free(params.filter_ssids);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
- if (prev_state != wpa_s->wpa_state)
- wpa_supplicant_set_state(wpa_s, prev_state);
+ if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state)
+ wpa_supplicant_set_state(wpa_s,
+ wpa_s->scan_prev_wpa_state);
/* Restore scan_req since we will try to scan again */
- wpa_s->scan_req = scan_req;
+ wpa_s->scan_req = wpa_s->last_scan_req;
wpa_supplicant_req_scan(wpa_s, 1, 0);
} else {
wpa_s->scan_for_connection = 0;
+#ifdef CONFIG_INTERWORKING
+ wpa_s->interworking_fast_assoc_tried = 0;
+#endif /* CONFIG_INTERWORKING */
}
}
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
+{
+ struct os_reltime remaining, new_int;
+ int cancelled;
+
+ cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
+ &remaining);
+
+ new_int.sec = sec;
+ new_int.usec = 0;
+ if (cancelled && os_reltime_before(&remaining, &new_int)) {
+ new_int.sec = remaining.sec;
+ new_int.usec = remaining.usec;
+ }
+
+ if (cancelled) {
+ eloop_register_timeout(new_int.sec, new_int.usec,
+ wpa_supplicant_scan, wpa_s, NULL);
+ }
+ wpa_s->scan_interval = sec;
+}
+
+
/**
* wpa_supplicant_req_scan - Schedule a scan for neighboring access points
* @wpa_s: Pointer to wpa_supplicant data
@@ -827,33 +1078,28 @@ scan:
*/
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
- /* If there's at least one network that should be specifically scanned
- * then don't cancel the scan and reschedule. Some drivers do
- * background scanning which generates frequent scan results, and that
- * causes the specific SSID scan to get continually pushed back and
- * never happen, which causes hidden APs to never get probe-scanned.
- */
- if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
- wpa_s->conf->ap_scan == 1) {
- struct wpa_ssid *ssid = wpa_s->conf->ssid;
+ int res;
- while (ssid) {
- if (!wpas_network_disabled(wpa_s, ssid) &&
- ssid->scan_ssid)
- break;
- ssid = ssid->next;
- }
- if (ssid) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
- "ensure that specific SSID scans occur");
- return;
- }
+ if (wpa_s->p2p_mgmt) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore scan request (%d.%06d sec) on p2p_mgmt interface",
+ sec, usec);
+ return;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
- sec, usec);
- eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
- eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
+ res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
+ NULL);
+ if (res == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
+ sec, usec);
+ } else if (res == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner",
+ sec, usec);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec",
+ sec, usec);
+ eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
+ }
}
@@ -962,7 +1208,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
os_memset(&params, 0, sizeof(params));
/* If we can't allocate space for the filters, we just don't filter */
- params.filter_ssids = os_zalloc(wpa_s->max_match_sets *
+ params.filter_ssids = os_calloc(wpa_s->max_match_sets,
sizeof(struct wpa_driver_scan_filter));
prev_state = wpa_s->wpa_state;
@@ -989,7 +1235,9 @@ 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;
@@ -1063,6 +1311,16 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
params.extra_ies_len = wpabuf_len(extra_ie);
}
+ if (wpa_s->conf->filter_rssi)
+ params.filter_rssi = wpa_s->conf->filter_rssi;
+
+ /* See if user specified frequencies. If so, scan only those. */
+ if (wpa_s->conf->freq_list && !params.freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Optimize scan based on conf->freq_list");
+ int_array_concat(&params.freqs, wpa_s->conf->freq_list);
+ }
+
scan_params = &params;
scan:
@@ -1076,6 +1334,17 @@ scan:
wpa_s->sched_scan_interval);
}
+ wpa_setband_scan_freqs(wpa_s, scan_params);
+
+ if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+ params.mac_addr_rand = 1;
+ if (wpa_s->mac_addr_sched_scan) {
+ params.mac_addr = wpa_s->mac_addr_sched_scan;
+ params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
+ ETH_ALEN;
+ }
+ }
+
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
wpabuf_free(extra_ie);
@@ -1096,8 +1365,16 @@ scan:
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;
+ wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
+ }
}
+ /* If there is no more ssids, start next time from the beginning */
+ if (!ssid)
+ wpa_s->prev_sched_ssid = NULL;
+
return 0;
}
@@ -1117,6 +1394,23 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
/**
+ * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a delayed scheduled scan.
+ */
+void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->sched_scan_supported)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan");
+ eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout,
+ wpa_s, NULL);
+}
+
+
+/**
* wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
* @wpa_s: Pointer to wpa_supplicant data
*
@@ -1234,6 +1528,43 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
/**
+ * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ *
+ * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+ u32 vendor_type)
+{
+ const u8 *end, *pos;
+
+ if (res->beacon_ie_len == 0)
+ return NULL;
+
+ pos = (const u8 *) (res + 1);
+ pos += res->ie_len;
+ end = pos + res->beacon_ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ vendor_type == WPA_GET_BE32(&pos[2]))
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
+/**
* wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
* @res: Scan result entry
* @vendor_type: Vendor type (four octets starting the IE payload)
@@ -1284,18 +1615,19 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
*/
#define GREAT_SNR 30
+#define IS_5GHZ(n) (n > 4000)
+
/* Compare function for sorting scan results. Return >0 if @b is considered
* better. */
static int wpa_scan_result_compar(const void *a, const void *b)
{
-#define IS_5GHZ(n) (n > 4000)
#define MIN(a,b) a < b ? a : b
struct wpa_scan_res **_wa = (void *) a;
struct wpa_scan_res **_wb = (void *) b;
struct wpa_scan_res *wa = *_wa;
struct wpa_scan_res *wb = *_wb;
- int wpa_a, wpa_b, maxrate_a, maxrate_b;
- int snr_a, snr_b;
+ int wpa_a, wpa_b;
+ int snr_a, snr_b, snr_a_full, snr_b_full;
/* WPA/WPA2 support preferred */
wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
@@ -1316,37 +1648,34 @@ static int wpa_scan_result_compar(const void *a, const void *b)
(wb->caps & IEEE80211_CAP_PRIVACY) == 0)
return -1;
- if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) &&
- !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) {
- snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
- snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
+ if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) {
+ snr_a_full = wa->snr;
+ snr_a = MIN(wa->snr, GREAT_SNR);
+ snr_b_full = wb->snr;
+ snr_b = MIN(wa->snr, GREAT_SNR);
} else {
- /* Not suitable information to calculate SNR, so use level */
- snr_a = wa->level;
- snr_b = wb->level;
+ /* Level is not in dBm, so we can't calculate
+ * SNR. Just use raw level (units unknown). */
+ snr_a = snr_a_full = wa->level;
+ snr_b = snr_b_full = wb->level;
}
- /* best/max rate preferred if SNR close enough */
- if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
+ /* if SNR is close, decide by max rate or frequency band */
+ if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
(wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
- maxrate_a = wpa_scan_get_max_rate(wa);
- maxrate_b = wpa_scan_get_max_rate(wb);
- if (maxrate_a != maxrate_b)
- return maxrate_b - maxrate_a;
+ 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;
}
- /* use freq for channel preference */
-
/* all things being equal, use SNR; if SNRs are
* identical, use quality values since some drivers may only report
* that value and leave the signal level zero */
- if (snr_b == snr_a)
+ if (snr_b_full == snr_a_full)
return wb->qual - wa->qual;
- return snr_b - snr_a;
+ return snr_b_full - snr_a_full;
#undef MIN
-#undef IS_5GHZ
}
@@ -1411,19 +1740,22 @@ static void dump_scan_res(struct wpa_scan_results *scan_res)
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *r = scan_res->res[i];
u8 *pos;
- if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
- == WPA_SCAN_LEVEL_DBM) {
- int snr = r->level - r->noise;
+ if (r->flags & WPA_SCAN_LEVEL_DBM) {
+ int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
+
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d snr=%d%s flags=0x%x",
+ "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
MAC2STR(r->bssid), r->freq, r->qual,
- r->noise, r->level, snr,
- snr >= GREAT_SNR ? "*" : "", r->flags);
+ r->noise, noise_valid ? "" : "~", r->level,
+ r->snr, r->snr >= GREAT_SNR ? "*" : "",
+ r->flags,
+ r->age, r->est_throughput);
} else {
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d flags=0x%x",
+ "noise=%d level=%d flags=0x%x age=%u est=%u",
MAC2STR(r->bssid), r->freq, r->qual,
- r->noise, r->level, r->flags);
+ r->noise, r->level, r->flags, r->age,
+ r->est_throughput);
}
pos = (u8 *) (r + 1);
if (r->ie_len)
@@ -1490,6 +1822,188 @@ 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
+ * 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)
+{
+ if (res->flags & WPA_SCAN_NOISE_INVALID) {
+ res->noise = IS_5GHZ(res->freq) ?
+ DEFAULT_NOISE_FLOOR_5GHZ :
+ DEFAULT_NOISE_FLOOR_2GHZ;
+ }
+
+ if (res->flags & WPA_SCAN_LEVEL_DBM) {
+ res->snr = res->level - res->noise;
+ } else {
+ /* Level is not in dBm, so we can't calculate
+ * SNR. Just use raw level (units unknown). */
+ res->snr = res->level;
+ }
+}
+
+
+static unsigned int max_ht20_rate(int snr)
+{
+ if (snr < 6)
+ return 6500; /* HT20 MCS0 */
+ if (snr < 8)
+ return 13000; /* HT20 MCS1 */
+ if (snr < 13)
+ return 19500; /* HT20 MCS2 */
+ if (snr < 17)
+ return 26000; /* HT20 MCS3 */
+ if (snr < 20)
+ return 39000; /* HT20 MCS4 */
+ if (snr < 23)
+ return 52000; /* HT20 MCS5 */
+ if (snr < 24)
+ return 58500; /* HT20 MCS6 */
+ return 65000; /* HT20 MCS7 */
+}
+
+
+static unsigned int max_ht40_rate(int snr)
+{
+ if (snr < 3)
+ return 13500; /* HT40 MCS0 */
+ if (snr < 6)
+ return 27000; /* HT40 MCS1 */
+ if (snr < 10)
+ return 40500; /* HT40 MCS2 */
+ if (snr < 15)
+ return 54000; /* HT40 MCS3 */
+ if (snr < 17)
+ return 81000; /* HT40 MCS4 */
+ if (snr < 22)
+ return 108000; /* HT40 MCS5 */
+ if (snr < 24)
+ return 121500; /* HT40 MCS6 */
+ return 135000; /* HT40 MCS7 */
+}
+
+
+static unsigned int max_vht80_rate(int snr)
+{
+ if (snr < 1)
+ return 0;
+ if (snr < 2)
+ return 29300; /* VHT80 MCS0 */
+ if (snr < 5)
+ return 58500; /* VHT80 MCS1 */
+ if (snr < 9)
+ return 87800; /* VHT80 MCS2 */
+ if (snr < 11)
+ return 117000; /* VHT80 MCS3 */
+ if (snr < 15)
+ return 175500; /* VHT80 MCS4 */
+ if (snr < 16)
+ return 234000; /* VHT80 MCS5 */
+ if (snr < 18)
+ return 263300; /* VHT80 MCS6 */
+ if (snr < 20)
+ return 292500; /* VHT80 MCS7 */
+ if (snr < 22)
+ return 351000; /* VHT80 MCS8 */
+ return 390000; /* VHT80 MCS9 */
+}
+
+
+static 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 */
+ const u8 *ie;
+ unsigned int est, tmp;
+ int snr = res->snr;
+
+ if (res->est_throughput)
+ return;
+
+ /* Get maximum legacy rate */
+ rate = wpa_scan_get_max_rate(res);
+
+ /* Limit based on estimated SNR */
+ if (rate > 1 * 2 && snr < 1)
+ rate = 1 * 2;
+ else if (rate > 2 * 2 && snr < 4)
+ rate = 2 * 2;
+ else if (rate > 6 * 2 && snr < 5)
+ rate = 6 * 2;
+ else if (rate > 9 * 2 && snr < 6)
+ rate = 9 * 2;
+ else if (rate > 12 * 2 && snr < 7)
+ rate = 12 * 2;
+ else if (rate > 18 * 2 && snr < 10)
+ rate = 18 * 2;
+ else if (rate > 24 * 2 && snr < 11)
+ rate = 24 * 2;
+ else if (rate > 36 * 2 && snr < 15)
+ rate = 36 * 2;
+ else if (rate > 48 * 2 && snr < 19)
+ rate = 48 * 2;
+ else if (rate > 54 * 2 && snr < 21)
+ rate = 54 * 2;
+ est = rate * 500;
+
+ if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
+ ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP);
+ if (ie) {
+ tmp = max_ht20_rate(snr);
+ if (tmp > est)
+ est = tmp;
+ }
+ }
+
+ if (capab == CAPAB_HT40 || capab == CAPAB_VHT) {
+ ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2 &&
+ (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
+ tmp = max_ht40_rate(snr);
+ if (tmp > est)
+ est = tmp;
+ }
+ }
+
+ if (capab == CAPAB_VHT) {
+ /* Use +1 to assume VHT is always faster than HT */
+ ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP);
+ if (ie) {
+ tmp = max_ht20_rate(snr) + 1;
+ if (tmp > est)
+ est = tmp;
+
+ ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2 &&
+ (ie[3] &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
+ tmp = max_ht40_rate(snr) + 1;
+ if (tmp > est)
+ est = tmp;
+ }
+
+ ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION);
+ if (ie && ie[1] >= 1 &&
+ (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) {
+ tmp = max_vht80_rate(snr) + 1;
+ if (tmp > est)
+ est = tmp;
+ }
+ }
+ }
+
+ /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
+
+ res->est_throughput = est;
+}
+
+
/**
* wpa_supplicant_get_scan_results - Get scan results
* @wpa_s: Pointer to wpa_supplicant data
@@ -1514,10 +2028,24 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
return NULL;
}
+ if (scan_res->fetch_time.sec == 0) {
+ /*
+ * Make sure we have a valid timestamp if the driver wrapper
+ * does not set this.
+ */
+ os_get_reltime(&scan_res->fetch_time);
+ }
filter_scan_res(wpa_s, scan_res);
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *scan_res_item = scan_res->res[i];
+
+ scan_snr(scan_res_item);
+ scan_est_throughput(wpa_s, scan_res_item);
+ }
+
#ifdef CONFIG_WPS
- if (wpas_wps_in_progress(wpa_s)) {
+ if (wpas_wps_searching(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
"provisioning rules");
compar = wpa_scan_result_wps_compar;
@@ -1530,7 +2058,8 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
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]);
+ wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
+ &scan_res->fetch_time);
wpa_bss_update_end(wpa_s, info, new_scan);
return scan_res;
@@ -1559,3 +2088,341 @@ int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
return 0;
}
+
+
+/**
+ * scan_only_handler - Reports scan results
+ */
+void scan_only_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+ 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;
+ } else {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ }
+ wpas_notify_scan_results(wpa_s);
+ wpas_notify_scan_done(wpa_s, 1);
+ if (wpa_s->scan_work) {
+ struct wpa_radio_work *work = wpa_s->scan_work;
+ wpa_s->scan_work = NULL;
+ radio_work_done(work);
+ }
+}
+
+
+int wpas_scan_scheduled(struct wpa_supplicant *wpa_s)
+{
+ return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
+}
+
+
+struct wpa_driver_scan_params *
+wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
+{
+ struct wpa_driver_scan_params *params;
+ size_t i;
+ u8 *n;
+
+ params = os_zalloc(sizeof(*params));
+ if (params == NULL)
+ return NULL;
+
+ for (i = 0; i < src->num_ssids; i++) {
+ if (src->ssids[i].ssid) {
+ n = os_malloc(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;
+ }
+ }
+ params->num_ssids = src->num_ssids;
+
+ if (src->extra_ies) {
+ n = os_malloc(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));
+ 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) *
+ 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;
+ }
+
+ params->filter_rssi = src->filter_rssi;
+ params->p2p_probe = src->p2p_probe;
+ params->only_new_results = src->only_new_results;
+ params->low_priority = src->low_priority;
+
+ if (src->mac_addr_rand) {
+ params->mac_addr_rand = src->mac_addr_rand;
+
+ if (src->mac_addr && src->mac_addr_mask) {
+ u8 *mac_addr;
+
+ mac_addr = os_malloc(2 * ETH_ALEN);
+ if (!mac_addr)
+ goto failed;
+
+ os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
+ os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
+ ETH_ALEN);
+ params->mac_addr = mac_addr;
+ params->mac_addr_mask = mac_addr + ETH_ALEN;
+ }
+ }
+ return params;
+
+failed:
+ wpa_scan_free_params(params);
+ return NULL;
+}
+
+
+void wpa_scan_free_params(struct wpa_driver_scan_params *params)
+{
+ size_t i;
+
+ if (params == NULL)
+ return;
+
+ for (i = 0; i < params->num_ssids; i++)
+ os_free((u8 *) params->ssids[i].ssid);
+ os_free((u8 *) params->extra_ies);
+ os_free(params->freqs);
+ os_free(params->filter_ssids);
+
+ /*
+ * Note: params->mac_addr_mask points to same memory allocation and
+ * must not be freed separately.
+ */
+ os_free((u8 *) params->mac_addr);
+
+ os_free(params);
+}
+
+
+int wpas_start_pno(struct wpa_supplicant *wpa_s)
+{
+ int ret, interval, prio;
+ size_t i, num_ssid, num_match_ssid;
+ struct wpa_ssid *ssid;
+ struct wpa_driver_scan_params params;
+
+ if (!wpa_s->sched_scan_supported)
+ 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_printf(MSG_ERROR, "PNO: In assoc process");
+ return -EAGAIN;
+ }
+
+ if (wpa_s->wpa_state == WPA_SCANNING) {
+ wpa_supplicant_cancel_scan(wpa_s);
+ if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Schedule PNO on completion of "
+ "ongoing sched scan");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->pno_sched_pending = 1;
+ return 0;
+ }
+ }
+
+ os_memset(&params, 0, sizeof(params));
+
+ num_ssid = num_match_ssid = 0;
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid)) {
+ num_match_ssid++;
+ if (ssid->scan_ssid)
+ num_ssid++;
+ }
+ ssid = ssid->next;
+ }
+
+ if (num_match_ssid == 0) {
+ wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
+ return -1;
+ }
+
+ if (num_match_ssid > num_ssid) {
+ params.num_ssids++; /* wildcard */
+ num_ssid++;
+ }
+
+ if (num_ssid > WPAS_MAX_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;
+ }
+
+ if (num_match_ssid > wpa_s->max_match_sets) {
+ num_match_ssid = wpa_s->max_match_sets;
+ wpa_dbg(wpa_s, MSG_DEBUG, "PNO: Too many SSIDs to match");
+ }
+ params.filter_ssids = os_calloc(num_match_ssid,
+ sizeof(struct wpa_driver_scan_filter));
+ if (params.filter_ssids == NULL)
+ return -1;
+
+ i = 0;
+ prio = 0;
+ ssid = wpa_s->conf->pssid[prio];
+ while (ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid)) {
+ if (ssid->scan_ssid && params.num_ssids < num_ssid) {
+ params.ssids[params.num_ssids].ssid =
+ ssid->ssid;
+ params.ssids[params.num_ssids].ssid_len =
+ ssid->ssid_len;
+ params.num_ssids++;
+ }
+ os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
+ ssid->ssid_len);
+ params.filter_ssids[i].ssid_len = ssid->ssid_len;
+ params.num_filter_ssids++;
+ i++;
+ if (i == num_match_ssid)
+ break;
+ }
+ if (ssid->pnext)
+ ssid = ssid->pnext;
+ else if (prio + 1 == wpa_s->conf->num_prio)
+ break;
+ else
+ ssid = wpa_s->conf->pssid[++prio];
+ }
+
+ 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 (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) {
+ params.mac_addr_rand = 1;
+ if (wpa_s->mac_addr_pno) {
+ params.mac_addr = wpa_s->mac_addr_pno;
+ params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
+ }
+ }
+
+ ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
+ os_free(params.filter_ssids);
+ if (ret == 0)
+ wpa_s->pno = 1;
+ else
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to schedule PNO");
+ return ret;
+}
+
+
+int wpas_stop_pno(struct wpa_supplicant *wpa_s)
+{
+ int ret = 0;
+
+ if (!wpa_s->pno)
+ return 0;
+
+ ret = wpa_supplicant_stop_sched_scan(wpa_s);
+
+ wpa_s->pno = 0;
+ wpa_s->pno_sched_pending = 0;
+
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return ret;
+}
+
+
+void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
+ unsigned int type)
+{
+ type &= MAC_ADDR_RAND_ALL;
+ wpa_s->mac_addr_rand_enable &= ~type;
+
+ if (type & MAC_ADDR_RAND_SCAN) {
+ os_free(wpa_s->mac_addr_scan);
+ wpa_s->mac_addr_scan = NULL;
+ }
+
+ if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+ os_free(wpa_s->mac_addr_sched_scan);
+ wpa_s->mac_addr_sched_scan = NULL;
+ }
+
+ if (type & MAC_ADDR_RAND_PNO) {
+ os_free(wpa_s->mac_addr_pno);
+ wpa_s->mac_addr_pno = NULL;
+ }
+}
+
+
+int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
+ unsigned int type, const u8 *addr,
+ const u8 *mask)
+{
+ u8 *tmp = NULL;
+
+ wpas_mac_addr_rand_scan_clear(wpa_s, type);
+
+ if (addr) {
+ tmp = os_malloc(2 * ETH_ALEN);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, addr, ETH_ALEN);
+ os_memcpy(tmp + ETH_ALEN, mask, ETH_ALEN);
+ }
+
+ if (type == MAC_ADDR_RAND_SCAN) {
+ wpa_s->mac_addr_scan = tmp;
+ } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+ wpa_s->mac_addr_sched_scan = tmp;
+ } else if (type == MAC_ADDR_RAND_PNO) {
+ wpa_s->mac_addr_pno = tmp;
+ } else {
+ wpa_printf(MSG_INFO,
+ "scan: Invalid MAC randomization type=0x%x",
+ type);
+ os_free(tmp);
+ return -1;
+ }
+
+ wpa_s->mac_addr_rand_enable |= type;
+ return 0;
+}
diff --git a/contrib/wpa/wpa_supplicant/scan.h b/contrib/wpa/wpa_supplicant/scan.h
index 5096287..7650f5a 100644
--- a/contrib/wpa/wpa_supplicant/scan.h
+++ b/contrib/wpa/wpa_supplicant/scan.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,6 +15,7 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
int sec, int usec);
int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
int scanning);
@@ -28,9 +29,30 @@ int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s);
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
u32 vendor_type);
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+ u32 vendor_type);
struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
u32 vendor_type);
int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
const u8 *bssid);
+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_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);
#endif /* SCAN_H */
diff --git a/contrib/wpa/wpa_supplicant/sme.c b/contrib/wpa/wpa_supplicant/sme.c
index 77ad1d2..1788113 100644
--- a/contrib/wpa/wpa_supplicant/sme.c
+++ b/contrib/wpa/wpa_supplicant/sme.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - SME
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2014, 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 "common/ieee802_11_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
+#include "common/sae.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
#include "config.h"
@@ -41,20 +42,78 @@ static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
#ifdef CONFIG_SAE
-static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s)
+static int index_within_array(const int *array, int idx)
+{
+ int i;
+ for (i = 0; i < idx; i++) {
+ if (array[i] <= 0)
+ return 0;
+ }
+ return 1;
+}
+
+
+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 };
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ /* Configuration may have changed, so validate current index */
+ if (!index_within_array(groups, wpa_s->sme.sae_group_index))
+ return -1;
+
+ for (;;) {
+ int group = groups[wpa_s->sme.sae_group_index];
+ if (group < 0)
+ break;
+ 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;
+ }
+ wpa_s->sme.sae_group_index++;
+ }
+
+ return -1;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const u8 *bssid)
{
struct wpabuf *buf;
+ size_t len;
+
+ if (ssid->passphrase == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: No password available");
+ return NULL;
+ }
+
+ if (sme_set_sae_group(wpa_s) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
+ return NULL;
+ }
- buf = wpabuf_alloc(4 + 2);
+ if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ (u8 *) ssid->passphrase,
+ os_strlen(ssid->passphrase),
+ &wpa_s->sme.sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+ return NULL;
+ }
+
+ len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+ 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);
- wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
- /* TODO: Anti-Clogging Token (if requested) */
- /* TODO: Scalar */
- /* TODO: Element */
+ sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
return buf;
}
@@ -64,15 +123,13 @@ static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
{
struct wpabuf *buf;
- buf = wpabuf_alloc(4 + 2);
+ buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN);
if (buf == NULL)
return NULL;
wpabuf_put_le16(buf, 2); /* Transaction seq# */
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
- wpabuf_put_le16(buf, wpa_s->sme.sae_send_confirm);
- wpa_s->sme.sae_send_confirm++;
- /* TODO: Confirm */
+ sae_write_confirm(&wpa_s->sme.sae, buf);
return buf;
}
@@ -80,6 +137,60 @@ static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_SAE */
+/**
+ * sme_auth_handle_rrm - Handle RRM aspects of current authentication attempt
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Pointer to the bss which is the target of authentication attempt
+ */
+static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+ const u8 rrm_ie_len = 5;
+ u8 *pos;
+ const u8 *rrm_ie;
+
+ wpa_s->rrm.rrm_used = 0;
+
+ wpa_printf(MSG_DEBUG,
+ "RRM: Determining whether RRM can be used - device support: 0x%x",
+ wpa_s->drv_rrm_flags);
+
+ rrm_ie = wpa_bss_get_ie(bss, WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (!rrm_ie || !(bss->caps & IEEE80211_CAP_RRM)) {
+ wpa_printf(MSG_DEBUG, "RRM: No RRM in network");
+ 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)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Insufficient RRM support in driver - do not use RRM");
+ return;
+ }
+
+ if (sizeof(wpa_s->sme.assoc_req_ie) <
+ wpa_s->sme.assoc_req_ie_len + rrm_ie_len + 2) {
+ wpa_printf(MSG_INFO,
+ "RRM: Unable to use RRM, no room for RRM IE");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Adding RRM IE to Association Request");
+ pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
+ os_memset(pos, 0, 2 + rrm_ie_len);
+ *pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+ *pos++ = rrm_ie_len;
+
+ /* Set supported capabilites flags */
+ if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
+ *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+ wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
+ wpa_s->rrm.rrm_used = 1;
+}
+
+
static void sme_send_authentication(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
int start)
@@ -94,15 +205,19 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IEEE80211R */
int i, bssid_changed;
struct wpabuf *resp = NULL;
- u8 ext_capab[10];
+ u8 ext_capab[18];
int ext_capab_len;
+ int skip_auth;
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
"the network");
+ wpas_connect_work_done(wpa_s);
return;
}
+ skip_auth = wpa_s->conf->reassoc_same_bss_optim &&
+ wpa_s->reassoc_same_bss;
wpa_s->current_bss = bss;
os_memset(&params, 0, sizeof(params));
@@ -141,17 +256,22 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
"0x%x", params.auth_alg);
}
#ifdef CONFIG_SAE
+ wpa_s->sme.sae_pmksa_caching = 0;
if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
const u8 *rsn;
struct wpa_ie_data ied;
rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (rsn &&
- wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
- if (wpa_key_mgmt_sae(ied.key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
- params.auth_alg = WPA_AUTH_ALG_SAE;
- }
+ if (!rsn) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SAE enabled, but target BSS does not advertise RSN");
+ } 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");
+ params.auth_alg = WPA_AUTH_ALG_SAE;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SAE enabled, but target BSS does not advertise SAE AKM for RSN");
}
}
#endif /* CONFIG_SAE */
@@ -180,13 +300,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
wpa_s->current_ssid,
try_opportunistic) == 0)
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ 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,
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;
}
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
@@ -206,6 +327,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
"key management and encryption suites (no "
"scan results)");
+ wpas_connect_work_done(wpa_s);
return;
}
#ifdef CONFIG_WPS
@@ -265,8 +387,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
- wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w;
+ wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data _ie;
@@ -296,21 +417,29 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20) {
+ if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
hs20 = wpabuf_alloc(20);
if (hs20) {
- wpas_hs20_add_indication(hs20);
- 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);
+ 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 */
- ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+ sizeof(ext_capab));
if (ext_capab_len > 0) {
u8 *pos = wpa_s->sme.assoc_req_ie;
if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN)
@@ -322,17 +451,45 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+ 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_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len;
+ if (wpabuf_len(buf) <= len) {
+ 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);
+ }
+ }
+
+ sme_auth_handle_rrm(wpa_s, bss);
+
#ifdef CONFIG_SAE
- if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+ if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
+ pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0)
+ {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
+ params.auth_alg = WPA_AUTH_ALG_OPEN;
+ wpa_s->sme.sae_pmksa_caching = 1;
+ }
+
+ if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
if (start)
- resp = sme_auth_build_sae_commit(wpa_s);
+ resp = sme_auth_build_sae_commit(wpa_s, ssid,
+ bss->bssid);
else
resp = sme_auth_build_sae_confirm(wpa_s);
- if (resp == NULL)
+ if (resp == NULL) {
+ wpas_connection_failed(wpa_s, bss->bssid);
return;
+ }
params.sae_data = wpabuf_head(resp);
params.sae_data_len = wpabuf_len(resp);
- wpa_s->sme.sae_state = start ? SME_SAE_COMMIT : SME_SAE_CONFIRM;
+ wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
}
#endif /* CONFIG_SAE */
@@ -352,6 +509,41 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+#ifdef CONFIG_P2P
+ /*
+ * If multi-channel concurrency is not supported, check for any
+ * frequency conflict. In case of any frequency conflict, remove the
+ * least prioritized connection.
+ */
+ if (wpa_s->num_multichan_concurrent < 2) {
+ int freq, num;
+ num = get_shared_radio_freqs(wpa_s, &freq, 1);
+ if (num > 0 && freq > 0 && freq != params.freq) {
+ wpa_printf(MSG_DEBUG,
+ "Conflicting frequency found (%d != %d)",
+ freq, params.freq);
+ if (wpas_p2p_handle_frequency_conflicts(wpa_s,
+ params.freq,
+ ssid) < 0) {
+ wpas_connection_failed(wpa_s, bss->bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpabuf_free(resp);
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+ }
+ }
+#endif /* CONFIG_P2P */
+
+ if (skip_auth) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "SME: Skip authentication step on reassoc-to-same-BSS");
+ wpabuf_free(resp);
+ sme_associate(wpa_s, ssid->mode, bss->bssid, WLAN_AUTH_OPEN);
+ return;
+ }
+
+
wpa_s->sme.auth_alg = params.auth_alg;
if (wpa_drv_authenticate(wpa_s, &params) < 0) {
wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
@@ -359,6 +551,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpas_connection_failed(wpa_s, bss->bssid);
wpa_supplicant_mark_disassoc(wpa_s);
wpabuf_free(resp);
+ wpas_connect_work_done(wpa_s);
return;
}
@@ -374,78 +567,170 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
-void sme_authenticate(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss, struct wpa_ssid *ssid)
+static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
{
- wpa_s->sme.sae_state = SME_SAE_INIT;
- wpa_s->sme.sae_send_confirm = 0;
- sme_send_authentication(wpa_s, bss, ssid, 1);
-}
-
+ struct wpa_connect_work *cwork = work->ctx;
+ struct wpa_supplicant *wpa_s = work->wpa_s;
-#ifdef CONFIG_SAE
+ if (deinit) {
+ if (work->started)
+ wpa_s->connect_work = NULL;
-static int sme_sae_process_commit(struct wpa_supplicant *wpa_s, const u8 *data,
- size_t len)
-{
- /* Check Finite Cyclic Group */
- if (len < 2)
- return -1;
- if (WPA_GET_LE16(data) != 19) {
- wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
- WPA_GET_LE16(data));
- return -1;
+ wpas_connect_work_free(cwork);
+ return;
}
- /* TODO */
+ wpa_s->connect_work = work;
- return 0;
+ if (cwork->bss_removed ||
+ !wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
+ sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
-static int sme_sae_process_confirm(struct wpa_supplicant *wpa_s, const u8 *data,
- size_t len)
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid)
{
- u16 rc;
+ struct wpa_connect_work *cwork;
- if (len < 2)
- return -1;
- rc = WPA_GET_LE16(data);
- wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+ if (bss == NULL || ssid == NULL)
+ return;
+ if (wpa_s->connect_work) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reject sme_authenticate() call since connect_work exist");
+ return;
+ }
- /* TODO */
- return 0;
+ if (radio_work_pending(wpa_s, "sme-connect")) {
+ /*
+ * The previous sme-connect work might no longer be valid due to
+ * the fact that the BSS list was updated. In addition, it makes
+ * sense to adhere to the 'newer' decision.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Remove previous pending sme-connect");
+ radio_remove_works(wpa_s, "sme-connect", 0);
+ }
+
+ cwork = os_zalloc(sizeof(*cwork));
+ if (cwork == NULL)
+ return;
+ cwork->bss = bss;
+ cwork->ssid = ssid;
+ cwork->sme = 1;
+
+#ifdef CONFIG_SAE
+ wpa_s->sme.sae.state = SAE_NOTHING;
+ wpa_s->sme.sae.send_confirm = 0;
+ wpa_s->sme.sae_group_index = 0;
+#endif /* CONFIG_SAE */
+
+ if (radio_add_work(wpa_s, bss->freq, "sme-connect", 1,
+ sme_auth_start_cb, cwork) < 0)
+ wpas_connect_work_free(cwork);
}
+#ifdef CONFIG_SAE
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len)
{
+ int *groups;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
"status code %u", auth_transaction, status_code);
- wpa_hexdump(MSG_DEBUG, "SME: SAE fields", data, len);
+
+ 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 };
+ u16 group;
+
+ groups = wpa_s->conf->sae_groups;
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ if (len < sizeof(le16)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Too short SAE anti-clogging token request");
+ return -1;
+ }
+ group = WPA_GET_LE16(data);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: SAE anti-clogging token requested (group %u)",
+ group);
+ if (sae_group_allowed(&wpa_s->sme.sae, groups, group) !=
+ WLAN_STATUS_SUCCESS) {
+ wpa_dbg(wpa_s, MSG_ERROR,
+ "SME: SAE group %u of anti-clogging request is invalid",
+ group);
+ return -1;
+ }
+ 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);
+ 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) {
+ 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);
+ return 0;
+ }
if (status_code != WLAN_STATUS_SUCCESS)
return -1;
if (auth_transaction == 1) {
+ groups = wpa_s->conf->sae_groups;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
if (wpa_s->current_bss == NULL ||
wpa_s->current_ssid == NULL)
return -1;
- if (wpa_s->sme.sae_state != SME_SAE_COMMIT)
+ if (wpa_s->sme.sae.state != SAE_COMMITTED)
+ return -1;
+ if (groups && groups[0] <= 0)
+ groups = NULL;
+ if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
+ groups) != WLAN_STATUS_SUCCESS)
return -1;
- if (sme_sae_process_commit(wpa_s, data, len) < 0)
+
+ if (sae_process_commit(&wpa_s->sme.sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
+ "commit");
return -1;
+ }
+
+ 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);
return 0;
} else if (auth_transaction == 2) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
- if (wpa_s->sme.sae_state != SME_SAE_CONFIRM)
+ if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
- if (sme_sae_process_confirm(wpa_s, data, len) < 0)
+ if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0)
return -1;
+ wpa_s->sme.sae.state = SAE_ACCEPTED;
+ sae_clear_temp_data(&wpa_s->sme.sae);
return 1;
}
@@ -499,6 +784,11 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
}
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->pending_bssid);
}
#endif /* CONFIG_SAE */
@@ -515,6 +805,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
return;
}
+ wpas_connect_work_done(wpa_s);
+
switch (data->auth.auth_type) {
case WLAN_AUTH_OPEN:
wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
@@ -562,19 +854,25 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
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 */
os_memset(&params, 0, sizeof(params));
params.bssid = bssid;
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
- params.freq = wpa_s->sme.freq;
+ params.freq.freq = wpa_s->sme.freq;
params.bg_scan_period = wpa_s->current_ssid ?
wpa_s->current_ssid->bg_scan_period : -1;
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;
- params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
- params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
+ params.pairwise_suite = wpa_s->pairwise_cipher;
+ params.group_suite = wpa_s->group_cipher;
+ params.key_mgmt_suite = wpa_s->key_mgmt;
+ params.wpa_proto = wpa_s->wpa_proto;
#ifdef CONFIG_HT_OVERRIDES
os_memset(&htcaps, 0, sizeof(htcaps));
os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
@@ -582,6 +880,13 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
params.htcaps_mask = (u8 *) &htcaps_mask;
wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, &params);
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ os_memset(&vhtcaps, 0, sizeof(vhtcaps));
+ os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
+ params.vhtcaps = &vhtcaps;
+ params.vhtcaps_mask = &vhtcaps_mask;
+ 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) {
params.wpa_ie = wpa_s->sme.ft_ies;
@@ -590,13 +895,14 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
#endif /* CONFIG_IEEE80211R */
params.mode = mode;
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_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "",
- params.freq);
+ params.freq.freq);
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
@@ -614,6 +920,10 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
params.wpa_proto = WPA_PROTO_WPA;
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
elems.wpa_ie_len + 2);
+ } else if (elems.osen) {
+ params.wpa_proto = WPA_PROTO_OSEN;
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.osen - 2,
+ elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
@@ -693,6 +1003,27 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+#ifdef CONFIG_SAE
+ if (wpa_s->sme.sae_pmksa_caching && wpa_s->current_ssid &&
+ wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "PMKSA caching attempt rejected - drop PMKSA cache entry and fall back to SAE authentication");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+ if (wpa_s->current_bss) {
+ struct wpa_bss *bss = wpa_s->current_bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
+ WLAN_REASON_DEAUTH_LEAVING);
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+ }
+#endif /* CONFIG_SAE */
+
/*
* For now, unconditionally terminate the previous authentication. In
* theory, this should not be needed, but mac80211 gets quite confused
@@ -723,7 +1054,7 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
void sme_event_disassoc(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+ struct disassoc_info *info)
{
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
if (wpa_s->sme.prev_bssid_set) {
@@ -793,6 +1124,21 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
}
+void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->sme.prev_bssid_set = 0;
+#ifdef CONFIG_SAE
+ wpabuf_free(wpa_s->sme.sae_token);
+ wpa_s->sme.sae_token = NULL;
+ sae_clear_data(&wpa_s->sme.sae);
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+ if (wpa_s->sme.ft_ies)
+ sme_update_ft_ies(wpa_s, NULL, NULL, 0);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
void sme_deinit(struct wpa_supplicant *wpa_s)
{
os_free(wpa_s->sme.ft_ies);
@@ -801,6 +1147,7 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
#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);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -816,8 +1163,11 @@ static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
struct ieee80211_2040_intol_chan_report *ic_report;
struct wpabuf *buf;
- wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
- MAC2STR(wpa_s->bssid));
+ wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR
+ " (num_channels=%u num_intol=%u)",
+ MAC2STR(wpa_s->bssid), num_channels, num_intol);
+ wpa_hexdump(MSG_DEBUG, "SME: 20/40 BSS Intolerant Channels",
+ chan_list, num_channels);
buf = wpabuf_alloc(2 + /* action.category + action_code */
sizeof(struct ieee80211_2040_bss_coex_ie) +
@@ -855,39 +1205,6 @@ static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
}
-/**
- * enum wpas_band - Frequency band
- * @WPAS_BAND_2GHZ: 2.4 GHz ISM band
- * @WPAS_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
- */
-enum wpas_band {
- WPAS_BAND_2GHZ,
- WPAS_BAND_5GHZ,
- WPAS_BAND_INVALID
-};
-
-/**
- * freq_to_channel - Convert frequency into channel info
- * @channel: Buffer for returning channel number
- * Returns: Band (2 or 5 GHz)
- */
-static enum wpas_band freq_to_channel(int freq, u8 *channel)
-{
- enum wpas_band band = (freq <= 2484) ? WPAS_BAND_2GHZ : WPAS_BAND_5GHZ;
- u8 chan = 0;
-
- if (freq >= 2412 && freq <= 2472)
- chan = (freq - 2407) / 5;
- else if (freq == 2484)
- chan = 14;
- else if (freq >= 5180 && freq <= 5805)
- chan = (freq - 5000) / 5;
-
- *channel = chan;
- return band;
-}
-
-
int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
@@ -924,13 +1241,22 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
/* Skip other band bss */
- if (freq_to_channel(bss->freq, &channel) != WPAS_BAND_2GHZ)
+ enum hostapd_hw_mode mode;
+ mode = ieee80211_freq_to_chan(bss->freq, &channel);
+ if (mode != HOSTAPD_MODE_IEEE80211G &&
+ mode != HOSTAPD_MODE_IEEE80211B)
continue;
ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+ wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR
+ " freq=%u chan=%u ht_cap=0x%x",
+ MAC2STR(bss->bssid), bss->freq, channel, ht_cap);
if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
+ if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+ num_intol++;
+
/* Check whether the channel is already considered */
for (i = 0; i < num_channels; i++) {
if (channel == chan_list[i])
@@ -939,9 +1265,6 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
if (i != num_channels)
continue;
- if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
- num_intol++;
-
chan_list[num_channels++] = channel;
}
}
@@ -966,28 +1289,72 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
}
-static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
- enum hostapd_hw_mode band,
- struct wpa_driver_scan_params *params)
+static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
{
- /* Include only supported channels for the specified band */
+ /* Include only affected channels */
struct hostapd_hw_modes *mode;
int count, i;
+ int start, end;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211G);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
return;
}
+ if (wpa_s->sme.ht_sec_chan == HT_SEC_CHAN_UNKNOWN &&
+ wpa_s->current_bss) {
+ const u8 *ie;
+
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2) {
+ u8 o;
+
+ o = ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+ else if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+ }
+ }
+
+ start = wpa_s->assoc_freq - 10;
+ end = wpa_s->assoc_freq + 10;
+ switch (wpa_s->sme.ht_sec_chan) {
+ case HT_SEC_CHAN_UNKNOWN:
+ /* HT40+ possible on channels 1..9 */
+ if (wpa_s->assoc_freq <= 2452)
+ start -= 20;
+ /* HT40- possible on channels 5-13 */
+ if (wpa_s->assoc_freq >= 2432)
+ end += 20;
+ break;
+ case HT_SEC_CHAN_ABOVE:
+ end += 20;
+ break;
+ case HT_SEC_CHAN_BELOW:
+ start -= 20;
+ break;
+ }
+ wpa_printf(MSG_DEBUG,
+ "OBSS: assoc_freq %d possible affected range %d-%d",
+ wpa_s->assoc_freq, start, end);
+
params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
for (count = 0, i = 0; i < mode->num_channels; i++) {
+ int freq;
+
if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
- params->freqs[count++] = mode->channels[i].freq;
+ freq = mode->channels[i].freq;
+ if (freq - 10 >= end || freq + 10 <= start)
+ continue; /* not affected */
+ params->freqs[count++] = freq;
}
}
@@ -1003,7 +1370,8 @@ static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
os_memset(&params, 0, sizeof(params));
- wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params);
+ wpa_obss_scan_freqs_list(wpa_s, &params);
+ params.low_priority = 1;
wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
if (wpa_supplicant_trigger_scan(wpa_s, &params))
@@ -1027,6 +1395,7 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
wpa_s->sme.sched_obss_scan = 0;
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
if (!enable)
return;
@@ -1090,9 +1459,9 @@ static const unsigned int sa_query_retry_timeout = 201;
static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
{
u32 tu;
- struct os_time now, passed;
- os_get_time(&now);
- os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed);
+ struct os_reltime now, passed;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->sme.sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (sa_query_max_timeout < tu) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out");
@@ -1142,13 +1511,16 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
return;
if (wpa_s->sme.sa_query_count == 0) {
/* Starting a new SA Query procedure */
- os_get_time(&wpa_s->sme.sa_query_start);
+ os_get_reltime(&wpa_s->sme.sa_query_start);
}
trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
wpa_s->sme.sa_query_trans_id = nbuf;
wpa_s->sme.sa_query_count++;
- os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+ if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
+ return;
+ }
timeout = sa_query_retry_timeout;
sec = ((timeout / 1000) * 1024) / 1000;
@@ -1181,15 +1553,12 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *da, u16 reason_code)
{
struct wpa_ssid *ssid;
+ struct os_reltime now;
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
- return;
if (wpa_s->wpa_state != WPA_COMPLETED)
return;
ssid = wpa_s->current_ssid;
- if (ssid == NULL ||
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
return;
if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
return;
@@ -1199,6 +1568,12 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
if (wpa_s->sme.sa_query_count > 0)
return;
+ os_get_reltime(&now);
+ if (wpa_s->sme.last_unprot_disconnect.sec &&
+ !os_reltime_expired(&now, &wpa_s->sme.last_unprot_disconnect, 10))
+ return; /* limit SA Query procedure frequency */
+ wpa_s->sme.last_unprot_disconnect = now;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Unprotected disconnect dropped - "
"possible AP/STA state mismatch - trigger SA Query");
sme_start_sa_query(wpa_s);
diff --git a/contrib/wpa/wpa_supplicant/sme.h b/contrib/wpa/wpa_supplicant/sme.h
index a7cc507..fd5c3b4 100644
--- a/contrib/wpa/wpa_supplicant/sme.h
+++ b/contrib/wpa/wpa_supplicant/sme.h
@@ -25,7 +25,7 @@ void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
union wpa_event_data *data);
void sme_event_disassoc(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data);
+ 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_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
@@ -33,6 +33,7 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
void sme_state_changed(struct wpa_supplicant *wpa_s);
void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
const u8 *prev_pending_bssid);
+void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
void sme_deinit(struct wpa_supplicant *wpa_s);
int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
@@ -74,7 +75,7 @@ static inline void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
}
static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+ struct disassoc_info *info)
{
}
@@ -94,6 +95,10 @@ sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
{
}
+static inline void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
+{
+}
+
static inline void sme_deinit(struct wpa_supplicant *wpa_s)
{
}
diff --git a/contrib/wpa/wpa_supplicant/tests/test_wpa.c b/contrib/wpa/wpa_supplicant/tests/test_wpa.c
index 0d659ad..39971f2 100644
--- a/contrib/wpa/wpa_supplicant/tests/test_wpa.c
+++ b/contrib/wpa/wpa_supplicant/tests/test_wpa.c
@@ -14,11 +14,7 @@
#include "../config.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/wpa_ie.h"
-#include "../hostapd/wpa.h"
-
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
+#include "ap/wpa_auth.h"
struct wpa {
@@ -298,7 +294,7 @@ static int auth_init_group(struct wpa *wpa)
static int auth_init(struct wpa *wpa)
{
- wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr);
+ 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;
diff --git a/contrib/wpa/wpa_supplicant/todo.txt b/contrib/wpa/wpa_supplicant/todo.txt
index b84cccc..4c9f98e 100644
--- a/contrib/wpa/wpa_supplicant/todo.txt
+++ b/contrib/wpa/wpa_supplicant/todo.txt
@@ -5,8 +5,6 @@ To do:
authentication has been completed (cache scard data based on serial#(?)
and try to optimize next connection if the same card is present for next
auth)
-- on disconnect event, could try to associate with another AP if one is
- present in scan results; would need to update scan results periodically..
- if driver/hw is not WPA2 capable, must remove WPA_PROTO_RSN flag from
ssid->proto fields to avoid detecting downgrade attacks when the driver
is not reporting RSN IE, but msg 3/4 has one
@@ -24,14 +22,12 @@ To do:
RFC 3748 Sect. 4.2
- test compilation with gcc -W options (more warnings?)
(Done once; number of unused function arguments still present)
-- add proper support for using dot11RSNAConfigSATimeout
-- ctrl_iface: get/set/remove blob
+- ctrl_iface: get/remove blob
- use doc/docbook/*.sgml and docbook2{txt,html,pdf} to replace README and
web pages including the same information.. i.e., have this information only
in one page; how to build a PDF file with all the SGML included?
- EAP-POTP/RSA SecurID profile (RFC 4793)
- document wpa_gui build and consider adding it to 'make install'
-- test madwifi with pairwise=TKIP group=WEP104
- consider merging hostapd and wpa_supplicant PMKSA cache implementations
- consider redesigning pending EAP requests (identity/password/otp from
ctrl_iface) by moving the retrying of the previous request into EAP
@@ -57,14 +53,11 @@ To do:
- try to work around race in configuring PTK and sending msg 4/4 (some NDIS
drivers with ndiswrapper end up not being able to complete 4-way handshake
in some cases; extra delay before setting the key seems to help)
-- add wpa_secure_memzero() macro and secure implementation (volatile u8*) to
- clear memory; this would be used to clear temporary buffers containing
- private data (e.g., keys); the macro can be defined to NOP in order to save
- space (i.e., no code should depend on the macro doing something)
- make sure that TLS session cache is not shared between EAP types or if it
is, that the cache entries are bound to only one EAP type; e.g., cache entry
created with EAP-TLS must not be allowed to do fast re-auth with EAP-TTLS
-- consider moving eap_tls_build_ack() call into eap_tls_process_helper()
+- consider moving eap_peer_tls_build_ack() call into
+ eap_peer_tls_process_helper()
(it seems to be called always if helper returns 1)
* could need to modify eap_{ttls,peap,fast}_decrypt to do same
- add support for fetching full user cert chain from Windows certificate
diff --git a/contrib/wpa/wpa_supplicant/wifi_display.c b/contrib/wpa/wpa_supplicant/wifi_display.c
index 92ca536..c363b21 100644
--- a/contrib/wpa/wpa_supplicant/wifi_display.c
+++ b/contrib/wpa/wpa_supplicant/wifi_display.c
@@ -16,6 +16,9 @@
#include "wifi_display.h"
+#define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
+
+
int wifi_display_init(struct wpa_global *global)
{
global->wifi_display = 1;
@@ -33,11 +36,42 @@ void wifi_display_deinit(struct wpa_global *global)
}
+struct wpabuf * wifi_display_get_wfd_ie(struct wpa_global *global)
+{
+ struct wpabuf *ie;
+ size_t len;
+ int i;
+
+ if (global->p2p == NULL)
+ return NULL;
+
+ len = 0;
+ for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+ if (global->wfd_subelem[i])
+ len += wpabuf_len(global->wfd_subelem[i]);
+ }
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ return NULL;
+
+ for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+ if (global->wfd_subelem[i])
+ wpabuf_put_buf(ie, global->wfd_subelem[i]);
+ }
+
+ return ie;
+}
+
+
static int wifi_display_update_wfd_ie(struct wpa_global *global)
{
struct wpabuf *ie, *buf;
size_t len, plen;
+ if (global->p2p == NULL)
+ return 0;
+
wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
if (!global->wifi_display) {
@@ -199,15 +233,31 @@ int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
if (pos == NULL)
return -1;
*pos++ = '\0';
- subelem = atoi(cmd);
- if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
- return -1;
len = os_strlen(pos);
if (len & 1)
return -1;
len /= 2;
+ if (os_strcmp(cmd, "all") == 0) {
+ int res;
+
+ e = wpabuf_alloc(len);
+ if (e == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
+ wpabuf_free(e);
+ return -1;
+ }
+ res = wifi_display_subelem_set_from_ies(global, e);
+ wpabuf_free(e);
+ return res;
+ }
+
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
if (len == 0) {
/* Clear subelement */
e = NULL;
@@ -232,11 +282,78 @@ int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
}
+int wifi_display_subelem_set_from_ies(struct wpa_global *global,
+ struct wpabuf *ie)
+{
+ int subelements[MAX_WFD_SUBELEMS] = {};
+ const u8 *pos, *end;
+ unsigned int len, subelem;
+ struct wpabuf *e;
+
+ wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
+ ie, ie ? (unsigned long) wpabuf_len(ie) : 0);
+
+ if (ie == NULL || wpabuf_len(ie) < 6)
+ return -1;
+
+ pos = wpabuf_head(ie);
+ end = pos + wpabuf_len(ie);
+
+ while (end > pos) {
+ if (pos + 3 > end)
+ break;
+
+ len = WPA_GET_BE16(pos + 1) + 3;
+
+ wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
+ *pos, len - 3);
+
+ if (len > (unsigned int) (end - pos))
+ break;
+
+ subelem = *pos;
+ if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) {
+ e = wpabuf_alloc_copy(pos, len);
+ if (e == NULL)
+ return -1;
+
+ wpabuf_free(global->wfd_subelem[subelem]);
+ global->wfd_subelem[subelem] = e;
+ subelements[subelem] = 1;
+ }
+
+ pos += len;
+ }
+
+ for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) {
+ if (subelements[subelem] == 0) {
+ wpabuf_free(global->wfd_subelem[subelem]);
+ global->wfd_subelem[subelem] = NULL;
+ }
+ }
+
+ return wifi_display_update_wfd_ie(global);
+}
+
+
int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
char *buf, size_t buflen)
{
int subelem;
+ if (os_strcmp(cmd, "all") == 0) {
+ struct wpabuf *ie;
+ int res;
+
+ ie = wifi_display_get_wfd_ie(global);
+ if (ie == NULL)
+ return 0;
+ res = wpa_snprintf_hex(buf, buflen, wpabuf_head(ie),
+ wpabuf_len(ie));
+ wpabuf_free(ie);
+ return res;
+ }
+
subelem = atoi(cmd);
if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
return -1;
@@ -249,3 +366,53 @@ int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
1,
wpabuf_len(global->wfd_subelem[subelem]) - 1);
}
+
+
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
+{
+ char *subelem = NULL;
+ const u8 *buf;
+ size_t buflen;
+ size_t i = 0;
+ u16 elen;
+
+ if (!wfd_subelems)
+ return NULL;
+
+ buf = wpabuf_head_u8(wfd_subelems);
+ if (!buf)
+ return NULL;
+
+ buflen = wpabuf_len(wfd_subelems);
+
+ while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
+ elen = WPA_GET_BE16(buf + i + 1);
+ if (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN + elen > buflen)
+ break; /* truncated subelement */
+
+ if (buf[i] == id) {
+ /*
+ * Limit explicitly to an arbitrary length to avoid
+ * unnecessarily large allocations. In practice, this
+ * is limited to maximum frame length anyway, so the
+ * maximum memory allocation here is not really that
+ * large. Anyway, the Wi-Fi Display subelements that
+ * are fetched with this function are even shorter.
+ */
+ if (elen > 1000)
+ break;
+ subelem = os_zalloc(2 * elen + 1);
+ if (!subelem)
+ return NULL;
+ wpa_snprintf_hex(subelem, 2 * elen + 1,
+ buf + i +
+ WIFI_DISPLAY_SUBELEM_HEADER_LEN,
+ elen);
+ break;
+ }
+
+ i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
+ }
+
+ return subelem;
+}
diff --git a/contrib/wpa/wpa_supplicant/wifi_display.h b/contrib/wpa/wpa_supplicant/wifi_display.h
index b75d4f2..0966bdb 100644
--- a/contrib/wpa/wpa_supplicant/wifi_display.h
+++ b/contrib/wpa/wpa_supplicant/wifi_display.h
@@ -13,8 +13,12 @@
int wifi_display_init(struct wpa_global *global);
void wifi_display_deinit(struct wpa_global *global);
void wifi_display_enable(struct wpa_global *global, int enabled);
+struct wpabuf *wifi_display_get_wfd_ie(struct wpa_global *global);
int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
+int wifi_display_subelem_set_from_ies(struct wpa_global *global,
+ struct wpabuf *ie);
int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
char *buf, size_t buflen);
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id);
#endif /* WIFI_DISPLAY_H */
diff --git a/contrib/wpa/wpa_supplicant/wmm_ac.c b/contrib/wpa/wpa_supplicant/wmm_ac.c
new file mode 100644
index 0000000..5625d36
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/wmm_ac.c
@@ -0,0 +1,995 @@
+/*
+ * Wi-Fi Multimedia Admission Control (WMM-AC)
+ * Copyright(c) 2014, Intel Mobile Communication GmbH.
+ * Copyright(c) 2014, Intel Corporation. All rights reserved.
+ *
+ * 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 "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "driver_i.h"
+#include "wmm_ac.h"
+
+static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx);
+
+static const enum wmm_ac up_to_ac[8] = {
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_VI,
+ WMM_AC_VI,
+ WMM_AC_VO,
+ WMM_AC_VO
+};
+
+
+static inline u8 wmm_ac_get_tsid(const struct wmm_tspec_element *tspec)
+{
+ return (tspec->ts_info[0] >> 1) & 0x0f;
+}
+
+
+static u8 wmm_ac_get_direction(const struct wmm_tspec_element *tspec)
+{
+ return (tspec->ts_info[0] >> 5) & 0x03;
+}
+
+
+static u8 wmm_ac_get_user_priority(const struct wmm_tspec_element *tspec)
+{
+ return (tspec->ts_info[1] >> 3) & 0x07;
+}
+
+
+static u8 wmm_ac_direction_to_idx(u8 direction)
+{
+ switch (direction) {
+ case WMM_AC_DIR_UPLINK:
+ return TS_DIR_IDX_UPLINK;
+ case WMM_AC_DIR_DOWNLINK:
+ return TS_DIR_IDX_DOWNLINK;
+ case WMM_AC_DIR_BIDIRECTIONAL:
+ return TS_DIR_IDX_BIDI;
+ default:
+ wpa_printf(MSG_ERROR, "Invalid direction: %d", direction);
+ return WMM_AC_DIR_UPLINK;
+ }
+}
+
+
+static int wmm_ac_add_ts(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct wmm_tspec_element *tspec)
+{
+ struct wmm_tspec_element *_tspec;
+ int ret;
+ u16 admitted_time = le_to_host16(tspec->medium_time);
+ u8 up = wmm_ac_get_user_priority(tspec);
+ u8 ac = up_to_ac[up];
+ u8 dir = wmm_ac_get_direction(tspec);
+ u8 tsid = wmm_ac_get_tsid(tspec);
+ enum ts_dir_idx idx = wmm_ac_direction_to_idx(dir);
+
+ /* should have been verified before, but double-check here */
+ if (wpa_s->tspecs[ac][idx]) {
+ wpa_printf(MSG_ERROR,
+ "WMM AC: tspec (ac=%d, dir=%d) already exists!",
+ ac, dir);
+ return -1;
+ }
+
+ /* copy tspec */
+ _tspec = os_malloc(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,
+ "WMM AC: Add TS: addr=" MACSTR
+ " TSID=%u admitted time=%u, ret=%d",
+ MAC2STR(addr), tsid, admitted_time, ret);
+ if (ret < 0) {
+ os_free(_tspec);
+ return -1;
+ }
+ }
+
+ wpa_s->tspecs[ac][idx] = _tspec;
+
+ wpa_printf(MSG_DEBUG, "Traffic stream was created successfully");
+
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_ADDED
+ "tsid=%d addr=" MACSTR " admitted_time=%d",
+ tsid, MAC2STR(addr), admitted_time);
+
+ return 0;
+}
+
+
+static void wmm_ac_del_ts_idx(struct wpa_supplicant *wpa_s, u8 ac,
+ enum ts_dir_idx dir)
+{
+ struct wmm_tspec_element *tspec = wpa_s->tspecs[ac][dir];
+ u8 tsid;
+
+ if (!tspec)
+ return;
+
+ tsid = wmm_ac_get_tsid(tspec);
+ wpa_printf(MSG_DEBUG, "WMM AC: Del TS ac=%d tsid=%d", ac, tsid);
+
+ /* update the driver in case of uplink/bidi */
+ if (wmm_ac_get_direction(tspec) != WMM_AC_DIR_DOWNLINK)
+ wpa_drv_del_ts(wpa_s, tsid, wpa_s->bssid);
+
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REMOVED
+ "tsid=%d addr=" MACSTR, tsid, MAC2STR(wpa_s->bssid));
+
+ os_free(wpa_s->tspecs[ac][dir]);
+ wpa_s->tspecs[ac][dir] = NULL;
+}
+
+
+static void wmm_ac_del_req(struct wpa_supplicant *wpa_s, int failed)
+{
+ struct wmm_ac_addts_request *req = wpa_s->addts_request;
+
+ if (!req)
+ return;
+
+ if (failed)
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED
+ "tsid=%u", wmm_ac_get_tsid(&req->tspec));
+
+ eloop_cancel_timeout(wmm_ac_addts_req_timeout, wpa_s, req);
+ wpa_s->addts_request = NULL;
+ os_free(req);
+}
+
+
+static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wmm_ac_addts_request *addts_req = timeout_ctx;
+
+ wpa_printf(MSG_DEBUG,
+ "Timeout getting ADDTS response (tsid=%d up=%d)",
+ wmm_ac_get_tsid(&addts_req->tspec),
+ wmm_ac_get_user_priority(&addts_req->tspec));
+
+ wmm_ac_del_req(wpa_s, 1);
+}
+
+
+static int wmm_ac_send_addts_request(struct wpa_supplicant *wpa_s,
+ const struct wmm_ac_addts_request *req)
+{
+ struct wpabuf *buf;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "Sending ADDTS Request to " MACSTR,
+ MAC2STR(req->address));
+
+ /* category + action code + dialog token + status + sizeof(tspec) */
+ buf = wpabuf_alloc(4 + sizeof(req->tspec));
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "WMM AC: Allocation error");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WMM);
+ wpabuf_put_u8(buf, WMM_ACTION_CODE_ADDTS_REQ);
+ wpabuf_put_u8(buf, req->dialog_token);
+ wpabuf_put_u8(buf, 0); /* status code */
+ wpabuf_put_data(buf, &req->tspec, sizeof(req->tspec));
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, req->address,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret) {
+ wpa_printf(MSG_WARNING,
+ "WMM AC: Failed to send ADDTS Request");
+ }
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+static int wmm_ac_send_delts(struct wpa_supplicant *wpa_s,
+ const struct wmm_tspec_element *tspec,
+ const u8 *address)
+{
+ struct wpabuf *buf;
+ int ret;
+
+ /* category + action code + dialog token + status + sizeof(tspec) */
+ buf = wpabuf_alloc(4 + sizeof(*tspec));
+ if (!buf)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "Sending DELTS to " MACSTR, MAC2STR(address));
+
+ /* category + action code + dialog token + status + sizeof(tspec) */
+ wpabuf_put_u8(buf, WLAN_ACTION_WMM);
+ wpabuf_put_u8(buf, WMM_ACTION_CODE_DELTS);
+ wpabuf_put_u8(buf, 0); /* Dialog Token (not used) */
+ wpabuf_put_u8(buf, 0); /* Status Code (not used) */
+ wpabuf_put_data(buf, tspec, sizeof(*tspec));
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, address,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret)
+ wpa_printf(MSG_WARNING, "Failed to send DELTS frame");
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+/* return the AC using the given TSPEC tid */
+static int wmm_ac_find_tsid(struct wpa_supplicant *wpa_s, u8 tsid,
+ enum ts_dir_idx *dir)
+{
+ int ac;
+ enum ts_dir_idx idx;
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ if (wpa_s->tspecs[ac][idx] &&
+ wmm_ac_get_tsid(wpa_s->tspecs[ac][idx]) == tsid) {
+ if (dir)
+ *dir = idx;
+ return ac;
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+static struct wmm_ac_addts_request *
+wmm_ac_build_addts_req(struct wpa_supplicant *wpa_s,
+ const struct wmm_ac_ts_setup_params *params,
+ const u8 *address)
+{
+ struct wmm_ac_addts_request *addts_req;
+ struct wmm_tspec_element *tspec;
+ u8 ac = up_to_ac[params->user_priority];
+ u8 uapsd = wpa_s->wmm_ac_assoc_info->ac_params[ac].uapsd;
+
+ addts_req = os_zalloc(sizeof(*addts_req));
+ if (!addts_req)
+ return NULL;
+
+ tspec = &addts_req->tspec;
+ os_memcpy(addts_req->address, address, ETH_ALEN);
+
+ /* The dialog token cannot be zero */
+ if (++wpa_s->wmm_ac_last_dialog_token == 0)
+ wpa_s->wmm_ac_last_dialog_token++;
+
+ addts_req->dialog_token = wpa_s->wmm_ac_last_dialog_token;
+ tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
+ tspec->length = sizeof(*tspec) - 2; /* reduce eid and length */
+ tspec->oui[0] = 0x00;
+ tspec->oui[1] = 0x50;
+ tspec->oui[2] = 0xf2;
+ tspec->oui_type = WMM_OUI_TYPE;
+ tspec->oui_subtype = WMM_OUI_SUBTYPE_TSPEC_ELEMENT;
+ tspec->version = WMM_VERSION;
+
+ tspec->ts_info[0] = params->tsid << 1;
+ tspec->ts_info[0] |= params->direction << 5;
+ tspec->ts_info[0] |= WMM_AC_ACCESS_POLICY_EDCA << 7;
+ tspec->ts_info[1] = uapsd << 2;
+ tspec->ts_info[1] |= params->user_priority << 3;
+ tspec->ts_info[2] = 0;
+
+ tspec->nominal_msdu_size = host_to_le16(params->nominal_msdu_size);
+ if (params->fixed_nominal_msdu)
+ tspec->nominal_msdu_size |=
+ host_to_le16(WMM_AC_FIXED_MSDU_SIZE);
+
+ tspec->mean_data_rate = host_to_le32(params->mean_data_rate);
+ tspec->minimum_phy_rate = host_to_le32(params->minimum_phy_rate);
+ tspec->surplus_bandwidth_allowance =
+ host_to_le16(params->surplus_bandwidth_allowance);
+
+ return addts_req;
+}
+
+
+static int param_in_range(const char *name, long value,
+ long min_val, long max_val)
+{
+ if (value < min_val || (max_val >= 0 && value > max_val)) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: param %s (%ld) is out of range (%ld-%ld)",
+ name, value, min_val, max_val);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int wmm_ac_should_replace_ts(struct wpa_supplicant *wpa_s,
+ u8 tsid, u8 ac, u8 dir)
+{
+ enum ts_dir_idx idx;
+ int cur_ac, existing_ts = 0, replace_ts = 0;
+
+ cur_ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
+ if (cur_ac >= 0) {
+ if (cur_ac != ac) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: TSID %i already exists on different ac (%d)",
+ tsid, cur_ac);
+ return -1;
+ }
+
+ /* same tsid - this tspec will replace the current one */
+ replace_ts |= BIT(idx);
+ }
+
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ if (wpa_s->tspecs[ac][idx])
+ existing_ts |= BIT(idx);
+ }
+
+ switch (dir) {
+ case WMM_AC_DIR_UPLINK:
+ /* replace existing uplink/bidi tspecs */
+ replace_ts |= existing_ts & (BIT(TS_DIR_IDX_UPLINK) |
+ BIT(TS_DIR_IDX_BIDI));
+ break;
+ case WMM_AC_DIR_DOWNLINK:
+ /* replace existing downlink/bidi tspecs */
+ replace_ts |= existing_ts & (BIT(TS_DIR_IDX_DOWNLINK) |
+ BIT(TS_DIR_IDX_BIDI));
+ break;
+ case WMM_AC_DIR_BIDIRECTIONAL:
+ /* replace all existing tspecs */
+ replace_ts |= existing_ts;
+ break;
+ default:
+ return -1;
+ }
+
+ return replace_ts;
+}
+
+
+static int wmm_ac_ts_req_is_valid(struct wpa_supplicant *wpa_s,
+ const struct wmm_ac_ts_setup_params *params)
+{
+ enum wmm_ac req_ac;
+
+#define PARAM_IN_RANGE(field, min_value, max_value) \
+ param_in_range(#field, params->field, min_value, max_value)
+
+ if (!PARAM_IN_RANGE(tsid, 0, WMM_AC_MAX_TID) ||
+ !PARAM_IN_RANGE(user_priority, 0, WMM_AC_MAX_USER_PRIORITY) ||
+ !PARAM_IN_RANGE(nominal_msdu_size, 1, WMM_AC_MAX_NOMINAL_MSDU) ||
+ !PARAM_IN_RANGE(mean_data_rate, 1, -1) ||
+ !PARAM_IN_RANGE(minimum_phy_rate, 1, -1) ||
+ !PARAM_IN_RANGE(surplus_bandwidth_allowance, WMM_AC_MIN_SBA_UNITY,
+ -1))
+ return 0;
+#undef PARAM_IN_RANGE
+
+ if (!(params->direction == WMM_TSPEC_DIRECTION_UPLINK ||
+ params->direction == WMM_TSPEC_DIRECTION_DOWNLINK ||
+ params->direction == WMM_TSPEC_DIRECTION_BI_DIRECTIONAL)) {
+ wpa_printf(MSG_DEBUG, "WMM AC: invalid TS direction: %d",
+ params->direction);
+ return 0;
+ }
+
+ req_ac = up_to_ac[params->user_priority];
+
+ /* Requested accesss category must have acm */
+ if (!wpa_s->wmm_ac_assoc_info->ac_params[req_ac].acm) {
+ wpa_printf(MSG_DEBUG, "WMM AC: AC %d is not ACM", req_ac);
+ return 0;
+ }
+
+ if (wmm_ac_should_replace_ts(wpa_s, params->tsid, req_ac,
+ params->direction) < 0)
+ return 0;
+
+ return 1;
+}
+
+
+static struct wmm_ac_assoc_data *
+wmm_ac_process_param_elem(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+ struct wmm_parameter_element *wmm_params;
+ struct wmm_ac_assoc_data *assoc_data;
+ int i;
+
+ /* Parsing WMM Parameter Element */
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "WMM AC: could not parse assoc ies");
+ return NULL;
+ }
+
+ if (!elems.wmm) {
+ wpa_printf(MSG_DEBUG, "WMM AC: No WMM IE");
+ return NULL;
+ }
+
+ if (elems.wmm_len != sizeof(*wmm_params)) {
+ wpa_printf(MSG_DEBUG, "WMM AC: Invalid WMM ie length");
+ return NULL;
+ }
+
+ wmm_params = (struct wmm_parameter_element *)(elems.wmm);
+
+ assoc_data = os_zalloc(sizeof(*assoc_data));
+ if (!assoc_data)
+ return NULL;
+
+ for (i = 0; i < WMM_AC_NUM; i++)
+ assoc_data->ac_params[i].acm =
+ !!(wmm_params->ac[i].aci_aifsn & WMM_AC_ACM);
+
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: AC mandatory: AC_BE=%u AC_BK=%u AC_VI=%u AC_VO=%u",
+ assoc_data->ac_params[WMM_AC_BE].acm,
+ assoc_data->ac_params[WMM_AC_BK].acm,
+ assoc_data->ac_params[WMM_AC_VI].acm,
+ assoc_data->ac_params[WMM_AC_VO].acm);
+
+ return assoc_data;
+}
+
+
+static int wmm_ac_init(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len, const struct wmm_params *wmm_params)
+{
+ struct wmm_ac_assoc_data *assoc_data;
+ u8 ac;
+
+ if (wpa_s->wmm_ac_assoc_info) {
+ wpa_printf(MSG_ERROR, "WMM AC: Already initialized");
+ 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");
+ return -1;
+ }
+
+ os_memset(wpa_s->tspecs, 0, sizeof(wpa_s->tspecs));
+ wpa_s->wmm_ac_last_dialog_token = 0;
+ wpa_s->addts_request = NULL;
+
+ assoc_data = wmm_ac_process_param_elem(wpa_s, ies, ies_len);
+ if (!assoc_data)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: U-APSD queues=0x%x",
+ wmm_params->uapsd_queues);
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ assoc_data->ac_params[ac].uapsd =
+ !!(wmm_params->uapsd_queues & BIT(ac));
+ }
+
+ wpa_s->wmm_ac_assoc_info = assoc_data;
+ return 0;
+}
+
+
+static void wmm_ac_del_ts(struct wpa_supplicant *wpa_s, u8 ac, int dir_bitmap)
+{
+ enum ts_dir_idx idx;
+
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ if (!(dir_bitmap & BIT(idx)))
+ continue;
+
+ wmm_ac_del_ts_idx(wpa_s, ac, idx);
+ }
+}
+
+
+static void wmm_ac_deinit(struct wpa_supplicant *wpa_s)
+{
+ int i;
+
+ for (i = 0; i < WMM_AC_NUM; i++)
+ wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL);
+
+ /* delete pending add_ts requset */
+ wmm_ac_del_req(wpa_s, 1);
+
+ os_free(wpa_s->wmm_ac_assoc_info);
+ wpa_s->wmm_ac_assoc_info = NULL;
+}
+
+
+void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len, const struct wmm_params *wmm_params)
+{
+ if (wmm_ac_init(wpa_s, ies, ies_len, wmm_params))
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Valid WMM association, WMM AC is enabled");
+}
+
+
+void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->wmm_ac_assoc_info)
+ return;
+
+ wmm_ac_deinit(wpa_s);
+ wpa_printf(MSG_DEBUG, "WMM AC: WMM AC is disabled");
+}
+
+
+int wpas_wmm_ac_delts(struct wpa_supplicant *wpa_s, u8 tsid)
+{
+ struct wmm_tspec_element tspec;
+ int ac;
+ enum ts_dir_idx dir;
+
+ if (!wpa_s->wmm_ac_assoc_info) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Failed to delete TS, WMM AC is disabled");
+ return -1;
+ }
+
+ ac = wmm_ac_find_tsid(wpa_s, tsid, &dir);
+ if (ac < 0) {
+ wpa_printf(MSG_DEBUG, "WMM AC: TS does not exist");
+ return -1;
+ }
+
+ tspec = *wpa_s->tspecs[ac][dir];
+
+ wmm_ac_del_ts_idx(wpa_s, ac, dir);
+
+ wmm_ac_send_delts(wpa_s, &tspec, wpa_s->bssid);
+
+ return 0;
+}
+
+
+int wpas_wmm_ac_addts(struct wpa_supplicant *wpa_s,
+ struct wmm_ac_ts_setup_params *params)
+{
+ struct wmm_ac_addts_request *addts_req;
+
+ if (!wpa_s->wmm_ac_assoc_info) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Cannot add TS - missing assoc data");
+ return -1;
+ }
+
+ if (wpa_s->addts_request) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: can't add TS - ADDTS request is already pending");
+ return -1;
+ }
+
+ /*
+ * we can setup downlink TS even without driver support.
+ * however, we need driver support for the other directions.
+ */
+ if (params->direction != WMM_AC_DIR_DOWNLINK &&
+ !wpa_s->wmm_ac_supported) {
+ wpa_printf(MSG_DEBUG,
+ "Cannot set uplink/bidi TS without driver support");
+ return -1;
+ }
+
+ if (!wmm_ac_ts_req_is_valid(wpa_s, params))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: TS setup request (addr=" MACSTR
+ " tsid=%u user priority=%u direction=%d)",
+ MAC2STR(wpa_s->bssid), params->tsid,
+ params->user_priority, params->direction);
+
+ addts_req = wmm_ac_build_addts_req(wpa_s, params, wpa_s->bssid);
+ if (!addts_req)
+ return -1;
+
+ if (wmm_ac_send_addts_request(wpa_s, addts_req))
+ goto err;
+
+ /* save as pending and set ADDTS resp timeout to 1 second */
+ wpa_s->addts_request = addts_req;
+ eloop_register_timeout(1, 0, wmm_ac_addts_req_timeout,
+ wpa_s, addts_req);
+ return 0;
+err:
+ os_free(addts_req);
+ return -1;
+}
+
+
+static void wmm_ac_handle_delts(struct wpa_supplicant *wpa_s, const u8 *sa,
+ const struct wmm_tspec_element *tspec)
+{
+ int ac;
+ u8 tsid;
+ enum ts_dir_idx idx;
+
+ tsid = wmm_ac_get_tsid(tspec);
+
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: DELTS frame has been received TSID=%u addr="
+ MACSTR, tsid, MAC2STR(sa));
+
+ ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
+ if (ac < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Ignoring DELTS frame - TSID does not exist");
+ return;
+ }
+
+ wmm_ac_del_ts_idx(wpa_s, ac, idx);
+
+ wpa_printf(MSG_DEBUG,
+ "TS was deleted successfully (tsid=%u address=" MACSTR ")",
+ tsid, MAC2STR(sa));
+}
+
+
+static void wmm_ac_handle_addts_resp(struct wpa_supplicant *wpa_s, const u8 *sa,
+ const u8 resp_dialog_token, const u8 status_code,
+ const struct wmm_tspec_element *tspec)
+{
+ struct wmm_ac_addts_request *req = wpa_s->addts_request;
+ u8 ac, tsid, up, dir;
+ int replace_tspecs;
+
+ tsid = wmm_ac_get_tsid(tspec);
+ dir = wmm_ac_get_direction(tspec);
+ up = wmm_ac_get_user_priority(tspec);
+ ac = up_to_ac[up];
+
+ /* make sure we have a matching addts request */
+ if (!req || req->dialog_token != resp_dialog_token) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: no req with dialog=%u, ignoring frame",
+ resp_dialog_token);
+ return;
+ }
+
+ /* make sure the params are the same */
+ if (os_memcmp(req->address, sa, ETH_ALEN) != 0 ||
+ tsid != wmm_ac_get_tsid(&req->tspec) ||
+ up != wmm_ac_get_user_priority(&req->tspec) ||
+ dir != wmm_ac_get_direction(&req->tspec)) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: ADDTS params do not match, ignoring frame");
+ return;
+ }
+
+ /* delete pending request */
+ wmm_ac_del_req(wpa_s, 0);
+
+ wpa_printf(MSG_DEBUG,
+ "ADDTS response status=%d tsid=%u up=%u direction=%u",
+ status_code, tsid, up, dir);
+
+ if (status_code != WMM_ADDTS_STATUS_ADMISSION_ACCEPTED) {
+ wpa_printf(MSG_INFO, "WMM AC: ADDTS request was rejected");
+ goto err_msg;
+ }
+
+ replace_tspecs = wmm_ac_should_replace_ts(wpa_s, tsid, ac, dir);
+ if (replace_tspecs < 0)
+ goto err_delts;
+
+ wpa_printf(MSG_DEBUG, "ts idx replace bitmap: 0x%x", replace_tspecs);
+
+ /* when replacing tspecs - delete first */
+ wmm_ac_del_ts(wpa_s, ac, replace_tspecs);
+
+ /* Creating a new traffic stream */
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: adding a new TS with TSID=%u address="MACSTR
+ " medium time=%u access category=%d dir=%d ",
+ tsid, MAC2STR(sa),
+ le_to_host16(tspec->medium_time), ac, dir);
+
+ if (wmm_ac_add_ts(wpa_s, sa, tspec))
+ goto err_delts;
+
+ return;
+
+err_delts:
+ /* ask the ap to delete the tspec */
+ wmm_ac_send_delts(wpa_s, tspec, sa);
+err_msg:
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED "tsid=%u",
+ tsid);
+}
+
+
+void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+ const u8 *sa, const u8 *data, size_t len)
+{
+ u8 action;
+ u8 dialog_token;
+ u8 status_code;
+ struct ieee802_11_elems elems;
+ struct wmm_tspec_element *tspec;
+
+ if (wpa_s->wmm_ac_assoc_info == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: WMM AC is disabled, ignoring action frame");
+ return;
+ }
+
+ action = data[0];
+
+ if (action != WMM_ACTION_CODE_ADDTS_RESP &&
+ action != WMM_ACTION_CODE_DELTS) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Unknown action (%d), ignoring action frame",
+ action);
+ return;
+ }
+
+ /* WMM AC action frame */
+ if (os_memcmp(da, wpa_s->own_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WMM AC: frame destination addr="MACSTR
+ " is other than ours, ignoring frame", MAC2STR(da));
+ return;
+ }
+
+ if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WMM AC: ignore frame with sa " MACSTR
+ " different other than our bssid", MAC2STR(da));
+ return;
+ }
+
+ if (len < 2 + sizeof(struct wmm_tspec_element)) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Short ADDTS response ignored (len=%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ data++;
+ len--;
+ dialog_token = data[0];
+ status_code = data[1];
+
+ if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) != ParseOK) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Could not parse WMM AC action from " MACSTR,
+ MAC2STR(sa));
+ return;
+ }
+
+ /* the struct also contains the type and value, so decrease it */
+ if (elems.wmm_tspec_len != sizeof(struct wmm_tspec_element) - 2) {
+ wpa_printf(MSG_DEBUG, "WMM AC: missing or wrong length TSPEC");
+ return;
+ }
+
+ tspec = (struct wmm_tspec_element *)(elems.wmm_tspec - 2);
+
+ wpa_printf(MSG_DEBUG, "WMM AC: RX WMM AC Action from " MACSTR,
+ MAC2STR(sa));
+ wpa_hexdump(MSG_MSGDUMP, "WMM AC: WMM AC Action content", data, len);
+
+ switch (action) {
+ case WMM_ACTION_CODE_ADDTS_RESP:
+ wmm_ac_handle_addts_resp(wpa_s, sa, dialog_token, status_code,
+ tspec);
+ break;
+ case WMM_ACTION_CODE_DELTS:
+ wmm_ac_handle_delts(wpa_s, sa, tspec);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static const char * get_ac_str(u8 ac)
+{
+ switch (ac) {
+ case WMM_AC_BE:
+ return "BE";
+ case WMM_AC_BK:
+ return "BK";
+ case WMM_AC_VI:
+ return "VI";
+ case WMM_AC_VO:
+ return "VO";
+ default:
+ return "N/A";
+ }
+}
+
+
+static const char * get_direction_str(u8 direction)
+{
+ switch (direction) {
+ case WMM_AC_DIR_DOWNLINK:
+ return "Downlink";
+ case WMM_AC_DIR_UPLINK:
+ return "Uplink";
+ case WMM_AC_DIR_BIDIRECTIONAL:
+ return "Bi-directional";
+ default:
+ return "N/A";
+ }
+}
+
+
+int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+ struct wmm_ac_assoc_data *assoc_info = wpa_s->wmm_ac_assoc_info;
+ enum ts_dir_idx idx;
+ int pos = 0;
+ u8 ac, up;
+
+ if (!assoc_info) {
+ return wpa_scnprintf(buf, buflen - pos,
+ "Not associated to a WMM AP, WMM AC is Disabled\n");
+ }
+
+ pos += wpa_scnprintf(buf + pos, buflen - pos, "WMM AC is Enabled\n");
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ int ts_count = 0;
+
+ pos += wpa_scnprintf(buf + pos, buflen - pos,
+ "%s: acm=%d uapsd=%d\n",
+ get_ac_str(ac),
+ assoc_info->ac_params[ac].acm,
+ assoc_info->ac_params[ac].uapsd);
+
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ struct wmm_tspec_element *tspec;
+ u8 dir, tsid;
+ const char *dir_str;
+
+ tspec = wpa_s->tspecs[ac][idx];
+ if (!tspec)
+ continue;
+
+ ts_count++;
+
+ dir = wmm_ac_get_direction(tspec);
+ dir_str = get_direction_str(dir);
+ tsid = wmm_ac_get_tsid(tspec);
+ up = wmm_ac_get_user_priority(tspec);
+
+ pos += wpa_scnprintf(buf + pos, buflen - pos,
+ "\tTSID=%u UP=%u\n"
+ "\tAddress = "MACSTR"\n"
+ "\tWMM AC dir = %s\n"
+ "\tTotal admitted time = %u\n\n",
+ tsid, up,
+ MAC2STR(wpa_s->bssid),
+ dir_str,
+ le_to_host16(tspec->medium_time));
+ }
+
+ if (!ts_count) {
+ pos += wpa_scnprintf(buf + pos, buflen - pos,
+ "\t(No Traffic Stream)\n\n");
+ }
+ }
+
+ return pos;
+}
+
+
+static u8 wmm_ac_get_tspecs_count(struct wpa_supplicant *wpa_s)
+{
+ int ac, dir, tspecs_count = 0;
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+ if (wpa_s->tspecs[ac][dir])
+ tspecs_count++;
+ }
+ }
+
+ return tspecs_count;
+}
+
+
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s)
+{
+ int ac, dir, tspecs_count;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Save last configured tspecs");
+
+ if (!wpa_s->wmm_ac_assoc_info)
+ return;
+
+ tspecs_count = wmm_ac_get_tspecs_count(wpa_s);
+ if (!tspecs_count) {
+ wpa_printf(MSG_DEBUG, "WMM AC: No configured TSPECs");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Saving tspecs");
+
+ wmm_ac_clear_saved_tspecs(wpa_s);
+ wpa_s->last_tspecs = os_calloc(tspecs_count,
+ sizeof(*wpa_s->last_tspecs));
+ if (!wpa_s->last_tspecs) {
+ wpa_printf(MSG_ERROR, "WMM AC: Failed to save tspecs!");
+ return;
+ }
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+ if (!wpa_s->tspecs[ac][dir])
+ continue;
+
+ wpa_s->last_tspecs[wpa_s->last_tspecs_count++] =
+ *wpa_s->tspecs[ac][dir];
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Successfully saved %d TSPECs",
+ wpa_s->last_tspecs_count);
+}
+
+
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->last_tspecs) {
+ wpa_printf(MSG_DEBUG, "WMM AC: Clear saved tspecs");
+ os_free(wpa_s->last_tspecs);
+ wpa_s->last_tspecs = NULL;
+ wpa_s->last_tspecs_count = 0;
+ }
+}
+
+
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ if (!wpa_s->wmm_ac_assoc_info || !wpa_s->last_tspecs_count)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Restore %u saved tspecs",
+ wpa_s->last_tspecs_count);
+
+ for (i = 0; i < wpa_s->last_tspecs_count; i++)
+ wmm_ac_add_ts(wpa_s, wpa_s->bssid, &wpa_s->last_tspecs[i]);
+
+ return 0;
+}
diff --git a/contrib/wpa/wpa_supplicant/wmm_ac.h b/contrib/wpa/wpa_supplicant/wmm_ac.h
new file mode 100644
index 0000000..5171b16
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/wmm_ac.h
@@ -0,0 +1,176 @@
+/*
+ * Wi-Fi Multimedia Admission Control (WMM-AC)
+ * Copyright(c) 2014, Intel Mobile Communication GmbH.
+ * Copyright(c) 2014, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WMM_AC_H
+#define WMM_AC_H
+
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+
+struct wpa_supplicant;
+
+#define WMM_AC_ACCESS_POLICY_EDCA 1
+#define WMM_AC_FIXED_MSDU_SIZE BIT(15)
+
+#define WMM_AC_MAX_TID 7
+#define WMM_AC_MAX_USER_PRIORITY 7
+#define WMM_AC_MIN_SBA_UNITY 0x2000
+#define WMM_AC_MAX_NOMINAL_MSDU 32767
+
+/**
+ * struct wmm_ac_assoc_data - WMM Admission Control Association Data
+ *
+ * This struct will store any relevant WMM association data needed by WMM AC.
+ * In case there is a valid WMM association, an instance of this struct will be
+ * created. In case there is no instance of this struct, the station is not
+ * associated to a valid WMM BSS and hence, WMM AC will not be used.
+ */
+struct wmm_ac_assoc_data {
+ struct {
+ /*
+ * acm - Admission Control Mandatory
+ * In case an access category is ACM, the traffic will have
+ * to be admitted by WMM-AC's admission mechanism before use.
+ */
+ unsigned int acm:1;
+
+ /*
+ * uapsd_queues - Unscheduled Automatic Power Save Delivery
+ * queues.
+ * Indicates whether ACs are configured for U-APSD (or legacy
+ * PS). Storing this value is necessary in order to set the
+ * Power Save Bit (PSB) in ADDTS request Action frames (if not
+ * given).
+ */
+ unsigned int uapsd:1;
+ } ac_params[WMM_AC_NUM];
+};
+
+/**
+ * wmm_ac_dir - WMM Admission Control Direction
+ */
+enum wmm_ac_dir {
+ WMM_AC_DIR_UPLINK = 0,
+ WMM_AC_DIR_DOWNLINK = 1,
+ WMM_AC_DIR_BIDIRECTIONAL = 3
+};
+
+/**
+ * ts_dir_idx - indices of internally saved tspecs
+ *
+ * we can have multiple tspecs (downlink + uplink) per ac.
+ * save them in array, and use the enum to directly access
+ * the respective tspec slot (according to the direction).
+ */
+enum ts_dir_idx {
+ TS_DIR_IDX_UPLINK,
+ TS_DIR_IDX_DOWNLINK,
+ TS_DIR_IDX_BIDI,
+
+ TS_DIR_IDX_COUNT
+};
+#define TS_DIR_IDX_ALL (BIT(TS_DIR_IDX_COUNT) - 1)
+
+/**
+ * struct wmm_ac_addts_request - ADDTS Request Information
+ *
+ * The last sent ADDTS request(s) will be saved as element(s) of this struct in
+ * order to be compared with the received ADDTS response in ADDTS response
+ * action frame handling and should be stored until that point.
+ * In case a new traffic stream will be created/replaced/updated, only its
+ * relevant traffic stream information will be stored as a wmm_ac_ts struct.
+ */
+struct wmm_ac_addts_request {
+ /*
+ * dialog token - Used to link the recived ADDTS response with this
+ * saved ADDTS request when ADDTS response is being handled
+ */
+ u8 dialog_token;
+
+ /*
+ * address - The alleged traffic stream's receiver/transmitter address
+ * Address and TID are used to identify the TS (TID is contained in
+ * TSPEC)
+ */
+ u8 address[ETH_ALEN];
+
+ /*
+ * tspec - Traffic Stream Specification, will be used to compare the
+ * sent TSPEC in ADDTS request to the received TSPEC in ADDTS response
+ * and act accordingly in ADDTS response handling
+ */
+ struct wmm_tspec_element tspec;
+};
+
+
+/**
+ * struct wmm_ac_ts_setup_params - TS setup parameters
+ *
+ * This struct holds parameters which should be provided
+ * to wmm_ac_ts_setup in order to setup a traffic stream
+ */
+struct wmm_ac_ts_setup_params {
+ /*
+ * tsid - Traffic ID
+ * TID and address are used to identify the TS
+ */
+ int tsid;
+
+ /*
+ * direction - Traffic Stream's direction
+ */
+ enum wmm_ac_dir direction;
+
+ /*
+ * user_priority - Traffic Stream's user priority
+ */
+ int user_priority;
+
+ /*
+ * nominal_msdu_size - Nominal MAC service data unit size
+ */
+ int nominal_msdu_size;
+
+ /*
+ * fixed_nominal_msdu - Whether the size is fixed
+ * 0 = Nominal MSDU size is not fixed
+ * 1 = Nominal MSDU size is fixed
+ */
+ int fixed_nominal_msdu;
+
+ /*
+ * surplus_bandwidth_allowance - Specifies excess time allocation
+ */
+ int mean_data_rate;
+
+ /*
+ * minimum_phy_rate - Specifies the minimum supported PHY rate in bps
+ */
+ int minimum_phy_rate;
+
+ /*
+ * surplus_bandwidth_allowance - Specifies excess time allocation
+ */
+ int surplus_bandwidth_allowance;
+};
+
+void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len, const struct wmm_params *wmm_params);
+void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s);
+int wpas_wmm_ac_addts(struct wpa_supplicant *wpa_s,
+ struct wmm_ac_ts_setup_params *params);
+int wpas_wmm_ac_delts(struct wpa_supplicant *wpa_s, u8 tsid);
+void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+ const u8 *sa, const u8 *data, size_t len);
+int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen);
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s);
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s);
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s);
+
+#endif /* WMM_AC_H */
diff --git a/contrib/wpa/wpa_supplicant/wnm_sta.c b/contrib/wpa/wpa_supplicant/wnm_sta.c
index 4d9e453..954de67 100644
--- a/contrib/wpa/wpa_supplicant/wnm_sta.c
+++ b/contrib/wpa/wpa_supplicant/wnm_sta.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WNM
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,12 +10,19 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "rsn_supp/wpa.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 "hs20_supplicant.h"
#define MAX_TFS_IE_LEN 1024
+#define WNM_MAX_NEIGHBOR_REPORT 10
/* get the TFS IE from driver */
@@ -176,7 +183,7 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
/* Install GTK/IGTK */
/* point to key data field */
- ptr = (u8 *) frm + 1 + 1 + 2;
+ ptr = (u8 *) frm + 1 + 2;
end = ptr + key_len_total;
wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
@@ -229,23 +236,29 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
const u8 *frm, int len)
{
/*
- * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
+ * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
* WNM-Sleep Mode IE | TFS Response IE
*/
- u8 *pos = (u8 *) frm; /* point to action field */
- u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
+ u8 *pos = (u8 *) 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;
+ size_t left;
- wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d",
- frm[0], frm[1], key_len_total);
- pos += 4 + key_len_total;
- if (pos > frm + len) {
+ if (len < 3)
+ return;
+ key_len_total = WPA_GET_LE16(frm + 1);
+
+ wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
+ frm[0], key_len_total);
+ left = len - 3;
+ if (key_len_total > left) {
wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
return;
}
+ pos += 3 + key_len_total;
while (pos - frm < len) {
u8 ie_len = *(pos + 1);
if (pos + 2 + ie_len > frm + len) {
@@ -294,17 +307,253 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
}
-static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
- u8 dialog_token, u8 status,
- u8 delay, const u8 *target_bssid)
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
+{
+ int i;
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
+ }
+
+ wpa_s->wnm_num_neighbor_report = 0;
+ os_free(wpa_s->wnm_neighbor_report_elements);
+ wpa_s->wnm_neighbor_report_elements = NULL;
+}
+
+
+static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
+ u8 id, u8 elen, const u8 *pos)
+{
+ switch (id) {
+ case WNM_NEIGHBOR_TSF:
+ if (elen < 2 + 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
+ break;
+ }
+ rep->tsf_offset = WPA_GET_LE16(pos);
+ rep->beacon_int = WPA_GET_LE16(pos + 2);
+ rep->tsf_present = 1;
+ break;
+ case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
+ if (elen < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
+ "country string");
+ break;
+ }
+ os_memcpy(rep->country, pos, 2);
+ rep->country_present = 1;
+ break;
+ case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
+ if (elen < 1) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
+ "candidate");
+ break;
+ }
+ rep->preference = pos[0];
+ rep->preference_present = 1;
+ break;
+ case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
+ rep->bss_term_tsf = WPA_GET_LE64(pos);
+ rep->bss_term_dur = WPA_GET_LE16(pos + 8);
+ rep->bss_term_present = 1;
+ break;
+ case WNM_NEIGHBOR_BEARING:
+ if (elen < 8) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
+ "bearing");
+ break;
+ }
+ rep->bearing = WPA_GET_LE16(pos);
+ rep->distance = WPA_GET_LE32(pos + 2);
+ rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
+ rep->bearing_present = 1;
+ break;
+ case WNM_NEIGHBOR_MEASUREMENT_PILOT:
+ if (elen < 1) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
+ "pilot");
+ break;
+ }
+ os_free(rep->meas_pilot);
+ rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
+ if (rep->meas_pilot == NULL)
+ break;
+ rep->meas_pilot->measurement_pilot = pos[0];
+ rep->meas_pilot->subelem_len = elen - 1;
+ os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
+ break;
+ case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
+ if (elen < 5) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
+ "capabilities");
+ break;
+ }
+ os_memcpy(rep->rm_capab, pos, 5);
+ rep->rm_capab_present = 1;
+ break;
+ case WNM_NEIGHBOR_MULTIPLE_BSSID:
+ if (elen < 1) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
+ break;
+ }
+ os_free(rep->mul_bssid);
+ rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
+ if (rep->mul_bssid == NULL)
+ break;
+ rep->mul_bssid->max_bssid_indicator = pos[0];
+ rep->mul_bssid->subelem_len = elen - 1;
+ os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
+ break;
+ }
+}
+
+
+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;
+
+ if (bss) {
+ const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
+
+ if (elem && elem[1] >= 2)
+ country = (const char *) (elem + 2);
+ }
+
+ return ieee80211_chan_to_freq(country, op_class, chan);
+}
+
+
+static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
+ const u8 *pos, u8 len,
+ struct neighbor_report *rep)
+{
+ u8 left = len;
+
+ if (left < 13) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
+ return;
+ }
+
+ os_memcpy(rep->bssid, pos, ETH_ALEN);
+ rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
+ rep->regulatory_class = *(pos + 10);
+ rep->channel_number = *(pos + 11);
+ rep->phy_type = *(pos + 12);
+
+ pos += 13;
+ left -= 13;
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
+ left -= 2;
+ if (elen > left) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Truncated neighbor report subelement");
+ break;
+ }
+ wnm_parse_neighbor_report_elem(rep, id, elen, pos);
+ left -= elen;
+ pos += elen;
+ }
+
+ rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
+ rep->channel_number);
+}
+
+
+static struct wpa_bss *
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
+{
+
+ u8 i;
+ struct wpa_bss *bss = wpa_s->current_bss;
+ struct wpa_bss *target;
+
+ if (!bss)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
+ MAC2STR(wpa_s->bssid), bss->level);
+
+ 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) {
+ wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
+ MAC2STR(nei->bssid));
+ continue;
+ }
+
+ target = wpa_bss_get_bssid(wpa_s, nei->bssid);
+ if (!target) {
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) not found in scan results",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1);
+ continue;
+ }
+
+ if (bss->ssid_len != target->ssid_len ||
+ os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
+ /*
+ * TODO: Could consider allowing transition to another
+ * ESS if PMF was enabled for the association.
+ */
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) in different ESS",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1);
+ 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)",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1,
+ target->level);
+ continue;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Found an acceptable preferred transition candidate BSS "
+ MACSTR " (RSSI %d)",
+ MAC2STR(nei->bssid), target->level);
+ return target;
+ }
+
+ return NULL;
+}
+
+
+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)
{
u8 buf[1000], *pos;
struct ieee80211_mgmt *mgmt;
size_t len;
+ 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);
+ 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));
@@ -322,13 +571,215 @@ static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
if (target_bssid) {
os_memcpy(pos, target_bssid, ETH_ALEN);
pos += 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;
}
len = pos - (u8 *) &mgmt->u.action.category;
- 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);
+ 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);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Failed to send BSS Transition Management Response");
+ }
+}
+
+
+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;
+
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return 0;
+
+ 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");
+ wnm_deallocate_memory(wpa_s);
+ return 0;
+ }
+
+ if (!wpa_s->current_bss ||
+ os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid,
+ ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
+ return 0;
+ }
+
+ /* Compare the Neighbor Report and scan results */
+ bss = compare_scan_neighbor_results(wpa_s);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
+ status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
+ goto send_bss_resp_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);
+ return 1;
+
+send_bss_resp_fail:
+ if (!reply_on_fail)
+ return 0;
+
+ /* Send reject response for all the failures */
+
+ if (wpa_s->wnm_reply) {
+ wpa_s->wnm_reply = 0;
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ status, 0, NULL);
+ }
+ wnm_deallocate_memory(wpa_s);
+
+ return 0;
+}
+
+
+static int cand_pref_compar(const void *a, const void *b)
+{
+ const struct neighbor_report *aa = a;
+ const struct neighbor_report *bb = b;
+
+ if (!aa->preference_present && !bb->preference_present)
+ return 0;
+ if (!aa->preference_present)
+ return 1;
+ if (!bb->preference_present)
+ return -1;
+ if (bb->preference > aa->preference)
+ return 1;
+ if (bb->preference < aa->preference)
+ return -1;
+ return 0;
+}
+
+
+static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return;
+ qsort(wpa_s->wnm_neighbor_report_elements,
+ wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
+ cand_pref_compar);
+}
+
+
+static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return;
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ wpa_printf(MSG_DEBUG, "%u: " MACSTR
+ " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
+ i, MAC2STR(nei->bssid), nei->bssid_info,
+ nei->regulatory_class,
+ nei->channel_number, nei->phy_type,
+ nei->preference_present ? nei->preference : -1,
+ nei->freq);
+ }
+}
+
+
+static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
+{
+ unsigned int i;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+ int j;
+
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan;
+
+ chan = &mode->channels[j];
+ if (chan->freq == freq &&
+ !(chan->flag & HOSTAPD_CHAN_DISABLED))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
+{
+ int *freqs;
+ int num_freqs = 0;
+ unsigned int i;
+
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return;
+
+ if (wpa_s->hw.modes == NULL)
+ return;
+
+ os_free(wpa_s->next_scan_freqs);
+ wpa_s->next_scan_freqs = NULL;
+
+ freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
+ if (freqs == NULL)
+ return;
+
+ 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->freq <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Unknown neighbor operating frequency for "
+ MACSTR " - scan all channels",
+ MAC2STR(nei->bssid));
+ os_free(freqs);
+ return;
+ }
+ if (chan_supported(wpa_s, nei->freq))
+ add_freq(freqs, &num_freqs, nei->freq);
+ }
+
+ if (num_freqs == 0) {
+ os_free(freqs);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Scan %d frequencies based on transition candidate list",
+ num_freqs);
+ wpa_s->next_scan_freqs = freqs;
}
@@ -336,26 +787,43 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *pos, const u8 *end,
int reply)
{
- u8 dialog_token;
- u8 mode;
- u16 disassoc_timer;
+ unsigned int beacon_int;
+ u8 valid_int;
if (pos + 5 > end)
return;
- dialog_token = pos[0];
- mode = pos[1];
- disassoc_timer = WPA_GET_LE16(pos + 2);
+ if (wpa_s->current_bss)
+ beacon_int = wpa_s->current_bss->beacon_int;
+ else
+ beacon_int = 100; /* best guess */
+
+ wpa_s->wnm_dialog_token = pos[0];
+ wpa_s->wnm_mode = pos[1];
+ wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
+ valid_int = pos[4];
+ wpa_s->wnm_reply = reply;
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
"dialog_token=%u request_mode=0x%x "
"disassoc_timer=%u validity_interval=%u",
- dialog_token, mode, disassoc_timer, pos[4]);
+ wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
+ wpa_s->wnm_dissoc_timer, valid_int);
+
pos += 5;
- if (mode & 0x08)
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ if (pos + 12 > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
+ return;
+ }
+ os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
pos += 12; /* BSS Termination Duration */
- if (mode & 0x10) {
+ }
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
char url[256];
+
if (pos + 1 > end || pos + 1 + pos[0] > end) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
"Management Request (URL)");
@@ -363,14 +831,17 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
os_memcpy(url, pos + 1, pos[0]);
url[pos[0]] = '\0';
- wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
- "session_info_url=%s", url);
+ pos += 1 + pos[0];
+
+ wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
+ wpa_sm_pmf_enabled(wpa_s->wpa),
+ wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
}
- if (mode & 0x04) {
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
- "Disassociation Timer %u", disassoc_timer);
- if (disassoc_timer && !wpa_s->scanning) {
+ "Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
+ if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
/* TODO: mark current BSS less preferred for
* selection */
wpa_printf(MSG_DEBUG, "Trying to find another BSS");
@@ -378,32 +849,282 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
}
- if (reply) {
- /* TODO: add support for reporting Accept */
- wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
- 1 /* Reject - unspecified */,
- 0, NULL);
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+ unsigned int valid_ms;
+
+ wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
+ wnm_deallocate_memory(wpa_s);
+ wpa_s->wnm_neighbor_report_elements = os_calloc(
+ WNM_MAX_NEIGHBOR_REPORT,
+ sizeof(struct neighbor_report));
+ if (wpa_s->wnm_neighbor_report_elements == NULL)
+ return;
+
+ while (pos + 2 <= end &&
+ wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
+ {
+ u8 tag = *pos++;
+ u8 len = *pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
+ tag);
+ if (pos + len > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Truncated request");
+ return;
+ }
+ if (tag == WLAN_EID_NEIGHBOR_REPORT) {
+ struct neighbor_report *rep;
+ rep = &wpa_s->wnm_neighbor_report_elements[
+ wpa_s->wnm_num_neighbor_report];
+ wnm_parse_neighbor_report(wpa_s, pos, len, rep);
+ }
+
+ pos += len;
+ wpa_s->wnm_num_neighbor_report++;
+ }
+ wnm_sort_cand_list(wpa_s);
+ wnm_dump_cand_list(wpa_s);
+ valid_ms = valid_int * beacon_int * 128 / 125;
+ wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
+ valid_ms);
+ os_get_reltime(&wpa_s->wnm_cand_valid_until);
+ wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
+ wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
+ wpa_s->wnm_cand_valid_until.sec +=
+ wpa_s->wnm_cand_valid_until.usec / 1000000;
+ wpa_s->wnm_cand_valid_until.usec %= 1000000;
+ os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
+
+ if (wpa_s->last_scan_res_used > 0) {
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Try to use recent scan results");
+ if (wnm_scan_process(wpa_s, 0) > 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "WNM: No match in previous scan results - try a new scan");
+ }
+ }
+
+ wnm_set_scan_freqs(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (reply) {
+ enum bss_trans_mgmt_status_code status;
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+ status = WNM_BSS_TM_ACCEPT;
+ else {
+ 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);
+ }
+}
+
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+ u8 query_reason)
+{
+ u8 buf[1000], *pos;
+ struct ieee80211_mgmt *mgmt;
+ size_t len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
+ MACSTR " query_reason=%u",
+ MAC2STR(wpa_s->bssid), query_reason);
+
+ 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;
+
+ len = pos - (u8 *) &mgmt->u.action.category;
+
+ 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);
+
+ return ret;
+}
+
+
+static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ int len)
+{
+ const u8 *pos, *end, *next;
+ u8 ie, ie_len;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + 1 < end) {
+ ie = *pos++;
+ ie_len = *pos++;
+ wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
+ ie, ie_len);
+ if (ie_len > end - pos) {
+ wpa_printf(MSG_DEBUG, "WNM: Not enough room for "
+ "subelement");
+ break;
+ }
+ next = pos + ie_len;
+ if (ie_len < 4) {
+ pos = next;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u",
+ WPA_GET_BE24(pos), pos[3]);
+
+#ifdef CONFIG_HS20
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
+ WPA_GET_BE24(pos) == OUI_WFA &&
+ pos[3] == HS20_WNM_SUB_REM_NEEDED) {
+ /* Subscription Remediation subelement */
+ const u8 *ie_end;
+ u8 url_len;
+ char *url;
+ u8 osu_method;
+
+ wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation "
+ "subelement");
+ ie_end = pos + ie_len;
+ pos += 4;
+ url_len = *pos++;
+ if (url_len == 0) {
+ wpa_printf(MSG_DEBUG, "WNM: No Server URL included");
+ url = NULL;
+ osu_method = 1;
+ } else {
+ if (pos + url_len + 1 > ie_end) {
+ wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
+ url_len,
+ (int) (ie_end - pos));
+ break;
+ }
+ url = os_malloc(url_len + 1);
+ if (url == NULL)
+ break;
+ os_memcpy(url, pos, url_len);
+ url[url_len] = '\0';
+ osu_method = pos[url_len];
+ }
+ hs20_rx_subscription_remediation(wpa_s, url,
+ osu_method);
+ os_free(url);
+ pos = next;
+ continue;
+ }
+
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 &&
+ WPA_GET_BE24(pos) == OUI_WFA &&
+ pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) {
+ const u8 *ie_end;
+ u8 url_len;
+ char *url;
+ u8 code;
+ u16 reauth_delay;
+
+ ie_end = pos + ie_len;
+ pos += 4;
+ code = *pos++;
+ reauth_delay = WPA_GET_LE16(pos);
+ pos += 2;
+ url_len = *pos++;
+ wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication "
+ "Imminent - Reason Code %u "
+ "Re-Auth Delay %u URL Length %u",
+ code, reauth_delay, url_len);
+ if (pos + url_len > ie_end)
+ break;
+ url = os_malloc(url_len + 1);
+ if (url == NULL)
+ break;
+ os_memcpy(url, pos, url_len);
+ url[url_len] = '\0';
+ hs20_rx_deauth_imminent_notice(wpa_s, code,
+ reauth_delay, url);
+ os_free(url);
+ pos = next;
+ continue;
+ }
+#endif /* CONFIG_HS20 */
+
+ pos = next;
+ }
+}
+
+
+static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *frm, int len)
+{
+ const u8 *pos, *end;
+ u8 dialog_token, type;
+
+ /* Dialog Token [1] | Type [1] | Subelements */
+
+ if (len < 2 || sa == NULL)
+ return;
+ end = frm + len;
+ pos = frm;
+ dialog_token = *pos++;
+ type = *pos++;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request "
+ "(dialog_token %u type %u sa " MACSTR ")",
+ dialog_token, type, MAC2STR(sa));
+ wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements",
+ pos, end - pos);
+
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not "
+ "from our AP - ignore it");
+ return;
+ }
+
+ switch (type) {
+ case 1:
+ ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos);
+ break;
+ default:
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown "
+ "WNM-Notification type %u", type);
+ break;
}
}
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
- struct rx_action *action)
+ const struct ieee80211_mgmt *mgmt, size_t len)
{
const u8 *pos, *end;
u8 act;
- if (action->data == NULL || action->len == 0)
+ if (len < IEEE80211_HDRLEN + 2)
return;
- pos = action->data;
- end = pos + action->len;
+ pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
act = *pos++;
+ end = ((const u8 *) mgmt) + len;
wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
- act, MAC2STR(action->sa));
+ act, MAC2STR(mgmt->sa));
if (wpa_s->wpa_state < WPA_ASSOCIATED ||
- os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
"frame");
return;
@@ -412,12 +1133,16 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
switch (act) {
case WNM_BSS_TRANS_MGMT_REQ:
ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
- !(action->da[0] & 0x01));
+ !(mgmt->da[0] & 0x01));
break;
case WNM_SLEEP_MODE_RESP:
- ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
+ ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
+ break;
+ case WNM_NOTIFICATION_REQ:
+ ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
break;
default:
+ wpa_printf(MSG_ERROR, "WNM: Unknown request");
break;
}
}
diff --git a/contrib/wpa/wpa_supplicant/wnm_sta.h b/contrib/wpa/wpa_supplicant/wnm_sta.h
index 3f9d88b..8de4348 100644
--- a/contrib/wpa/wpa_supplicant/wnm_sta.h
+++ b/contrib/wpa/wpa_supplicant/wnm_sta.h
@@ -9,13 +9,69 @@
#ifndef WNM_STA_H
#define WNM_STA_H
-struct rx_action;
-struct wpa_supplicant;
+struct measurement_pilot {
+ u8 measurement_pilot;
+ u8 subelem_len;
+ u8 subelems[255];
+};
+
+struct multiple_bssid {
+ u8 max_bssid_indicator;
+ u8 subelem_len;
+ u8 subelems[255];
+};
+
+struct neighbor_report {
+ u8 bssid[ETH_ALEN];
+ u32 bssid_info;
+ u8 regulatory_class;
+ u8 channel_number;
+ u8 phy_type;
+ u8 preference; /* valid if preference_present=1 */
+ u16 tsf_offset; /* valid if tsf_present=1 */
+ u16 beacon_int; /* valid if tsf_present=1 */
+ char country[2]; /* valid if country_present=1 */
+ u8 rm_capab[5]; /* valid if rm_capab_present=1 */
+ u16 bearing; /* valid if bearing_present=1 */
+ u16 rel_height; /* valid if bearing_present=1 */
+ u32 distance; /* valid if bearing_present=1 */
+ u64 bss_term_tsf; /* valid if bss_term_present=1 */
+ u16 bss_term_dur; /* valid if bss_term_present=1 */
+ unsigned int preference_present:1;
+ unsigned int tsf_present:1;
+ unsigned int country_present:1;
+ unsigned int rm_capab_present:1;
+ unsigned int bearing_present:1;
+ unsigned int bss_term_present:1;
+ struct measurement_pilot *meas_pilot;
+ struct multiple_bssid *mul_bssid;
+ int freq;
+};
+
int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
u8 action, u16 intval, struct wpabuf *tfs_req);
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
- struct rx_action *action);
+ const struct ieee80211_mgmt *mgmt, size_t len);
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+ u8 query_reason);
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+
+
+#ifdef CONFIG_WNM
+
+int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+
+#else /* CONFIG_WNM */
+
+static inline int wnm_scan_process(struct wpa_supplicant *wpa_s,
+ int reply_on_fail)
+{
+ return 0;
+}
+
+#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 0c6ef5e..5a0af0d 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-2012, 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.
@@ -28,7 +28,7 @@
static const char *wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
static const char *wpa_cli_license =
@@ -70,7 +70,7 @@ static struct wpa_ctrl *ctrl_conn;
static struct wpa_ctrl *mon_conn;
static int wpa_cli_quit = 0;
static int wpa_cli_attached = 0;
-static int wpa_cli_connected = 0;
+static int wpa_cli_connected = -1;
static int wpa_cli_last_id = 0;
#ifndef CONFIG_CTRL_IFACE_DIR
#define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant"
@@ -81,6 +81,7 @@ 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;
@@ -90,6 +91,7 @@ struct cli_txt_entry {
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 void print_help(const char *cmd);
@@ -173,11 +175,9 @@ static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
end = os_strchr(txt, ' ');
if (end == NULL)
end = txt + os_strlen(txt);
- buf = os_malloc(end - txt + 1);
+ buf = dup_binstr(txt, end - txt);
if (buf == NULL)
return;
- os_memcpy(buf, txt, end - txt);
- buf[end - txt] = '\0';
cli_txt_list_del(txt_list, buf);
os_free(buf);
}
@@ -223,11 +223,9 @@ static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
end = os_strchr(txt, ' ');
if (end == NULL)
end = txt + os_strlen(txt);
- buf = os_malloc(end - txt + 1);
+ buf = dup_binstr(txt, end - txt);
if (buf == NULL)
return -1;
- os_memcpy(buf, txt, end - txt);
- buf[end - txt] = '\0';
ret = cli_txt_list_add(txt_list, buf);
os_free(buf);
return ret;
@@ -335,7 +333,7 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
return -1;
res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
ifname);
- if (res < 0 || res >= flen) {
+ if (os_snprintf_error(flen, res)) {
os_free(cfile);
return -1;
}
@@ -400,7 +398,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)
{
- char buf[2048];
+ char buf[4096];
size_t len;
int ret;
@@ -408,6 +406,12 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
printf("Not connected to wpa_supplicant - 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);
@@ -444,13 +448,13 @@ static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
end = buf + buflen;
res = os_snprintf(pos, end - pos, "%s", cmd);
- if (res < 0 || res >= end - pos)
+ 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 (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
goto fail;
pos += res;
}
@@ -467,7 +471,7 @@ fail:
static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
int argc, char *argv[])
{
- char buf[256];
+ char buf[4096];
if (argc < min_args) {
printf("Invalid %s command - at least %d argument%s "
"required.\n", cmd, min_args,
@@ -492,6 +496,8 @@ static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
return wpa_ctrl_command(ctrl, "STATUS-WPS");
+ if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
return wpa_ctrl_command(ctrl, "STATUS");
}
@@ -526,6 +532,13 @@ static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
+}
+
+
static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
print_help(argc > 0 ? argv[0] : NULL);
@@ -564,52 +577,90 @@ static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static void wpa_cli_show_variables(void)
-{
- printf("set variables:\n"
- " EAPOL::heldPeriod (EAPOL state machine held period, "
- "in seconds)\n"
- " EAPOL::authPeriod (EAPOL state machine authentication "
- "period, in seconds)\n"
- " EAPOL::startPeriod (EAPOL state machine start period, in "
- "seconds)\n"
- " EAPOL::maxStart (EAPOL state machine maximum start "
- "attempts)\n");
- printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
- "seconds)\n"
- " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
- " threshold\n\tpercentage)\n"
- " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
- "security\n\tassociation in seconds)\n");
-}
-
-
static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
- if (argc == 0) {
- wpa_cli_show_variables();
- return 0;
+ if (argc == 1) {
+ res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long SET command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
}
- if (argc != 1 && argc != 2) {
- printf("Invalid SET command: needs two arguments (variable "
- "name and value)\n");
- return -1;
- }
+ return wpa_cli_cmd(ctrl, "SET", 2, argc, argv);
+}
- if (argc == 1)
- res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "SET %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SET command.\n");
- return -1;
+
+static char ** wpa_cli_complete_set(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ /* runtime values */
+ "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod",
+ "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime",
+ "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout",
+ "wps_fragment_size", "wps_version_number", "ampdu",
+ "tdls_testing", "tdls_disabled", "pno", "radio_disabled",
+ "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
+ "no_keep_alive",
+ /* global configuration parameters */
+ "eapol_version", "ap_scan", "disable_scan_offload",
+ "fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
+ "pkcs11_module_path", "openssl_ciphers",
+ "pcsc_reader", "pcsc_pin",
+ "driver_param", "dot11RSNAConfigPMKLifetime",
+ "dot11RSNAConfigPMKReauthThreshold",
+ "dot11RSNAConfigSATimeout",
+ "update_config", "load_dynamic_eap", "uuid", "device_name",
+ "manufacturer", "model_name", "model_number", "serial_number",
+ "device_type", "os_version", "config_methods",
+ "wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
+ "p2p_listen_reg_class", "p2p_listen_channel",
+ "p2p_oper_reg_class", "p2p_oper_channel",
+ "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
+ "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
+ "p2p_no_go_freq",
+ "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
+ "p2p_go_vht",
+ "p2p_ignore_shared_freq", "country", "bss_max_count",
+ "bss_expiration_age", "bss_expiration_scan_count",
+ "filter_ssids", "filter_rssi", "max_num_sta",
+ "disassoc_low_ack", "hs20", "interworking", "hessid",
+ "access_network_type", "pbc_in_m1", "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",
+ "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
+ "ignore_old_scan_res", "freq_list", "external_sim",
+ "tdls_external_control", "p2p_search_delay"
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **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;
+ }
+ return res;
}
- return wpa_ctrl_command(ctrl, cmd);
+
+ if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0)
+ return cli_txt_list_array(&bsses);
+
+ return NULL;
+}
+
+static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DUMP");
}
@@ -638,6 +689,12 @@ static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_reattach(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "REATTACH");
+}
+
+
static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -681,7 +738,7 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
else
res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long BSS_FLUSH command.\n");
return -1;
}
@@ -744,6 +801,13 @@ static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -791,55 +855,10 @@ static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
}
-static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
-{
- int ret;
- char *buf;
- size_t buflen;
-
- if (argc != 1) {
- printf("Invalid 'nfc_rx_handover_req' command - one argument "
- "is required.\n");
- return -1;
- }
-
- buflen = 21 + os_strlen(argv[0]);
- buf = os_malloc(buflen);
- if (buf == NULL)
- return -1;
- os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
-
- ret = wpa_ctrl_command(ctrl, buf);
- os_free(buf);
-
- return ret;
-}
-
-
-static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- int ret;
- char *buf;
- size_t buflen;
-
- if (argc != 1) {
- printf("Invalid 'nfc_rx_handover_sel' command - one argument "
- "is required.\n");
- return -1;
- }
-
- buflen = 21 + os_strlen(argv[0]);
- buf = os_malloc(buflen);
- if (buf == NULL)
- return -1;
- os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
-
- ret = wpa_ctrl_command(ctrl, buf);
- os_free(buf);
-
- return ret;
+ return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
}
#endif /* CONFIG_WPS_NFC */
@@ -894,7 +913,7 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
return -1;
}
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_REG command.\n");
return -1;
}
@@ -1019,7 +1038,7 @@ static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
return -1;
}
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_ER_CONFIG command.\n");
return -1;
}
@@ -1071,14 +1090,14 @@ static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long IDENTITY command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long IDENTITY command.\n");
return -1;
}
@@ -1104,14 +1123,14 @@ static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSWORD command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSWORD command.\n");
return -1;
}
@@ -1138,14 +1157,14 @@ static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long NEW_PASSWORD command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long NEW_PASSWORD command.\n");
return -1;
}
@@ -1171,14 +1190,14 @@ static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PIN command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PIN command.\n");
return -1;
}
@@ -1203,14 +1222,14 @@ static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long OTP command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long OTP command.\n");
return -1;
}
@@ -1221,6 +1240,38 @@ static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i, ret;
+
+ if (argc < 2) {
+ printf("Invalid SIM command: needs two arguments "
+ "(network id and SIM operation response)\n");
+ return -1;
+ }
+
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(end - pos, ret)) {
+ printf("Too long SIM 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 SIM 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[])
{
@@ -1237,14 +1288,14 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSPHRASE command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSPHRASE command.\n");
return -1;
}
@@ -1378,6 +1429,24 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc == 0) {
+ wpa_cli_show_network_variables();
+ return 0;
+ }
+
+ if (argc < 3) {
+ printf("Invalid DUP_NETWORK command: needs three arguments\n"
+ "(src netid, dest netid, and variable name)\n");
+ return -1;
+ }
+
+ return wpa_cli_cmd(ctrl, "DUP_NETWORK", 3, argc, argv);
+}
+
+
static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1410,6 +1479,18 @@ static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_get_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc != 2) {
+ printf("Invalid GET_CRED command: needs two arguments\n"
+ "(cred id, variable name)\n");
+ return -1;
+ }
+
+ return wpa_cli_cmd(ctrl, "GET_CRED", 2, argc, argv);
+}
+
+
static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1433,7 +1514,7 @@ static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- return wpa_ctrl_command(ctrl, "SCAN");
+ return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
}
@@ -1501,8 +1582,12 @@ static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
wpa_cli_close_connection();
os_free(ctrl_ifname);
ctrl_ifname = os_strdup(argv[0]);
+ if (!ctrl_ifname) {
+ printf("Failed to allocate memory\n");
+ return 0;
+ }
- if (wpa_cli_open_connection(ctrl_ifname, 1)) {
+ if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
printf("Connected to interface '%s.\n", ctrl_ifname);
} else {
printf("Could not connect to interface '%s' - re-trying\n",
@@ -1550,7 +1635,7 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
argc > 5 ? argv[5] : "");
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -1640,6 +1725,13 @@ static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
{
return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
}
+
+static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
+}
+
#endif /* CONFIG_AP */
@@ -1655,10 +1747,12 @@ static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+#ifdef CONFIG_TESTING_OPTIONS
static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "DROP_SA");
}
+#endif /* CONFIG_TESTING_OPTIONS */
static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -1667,6 +1761,31 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+#ifdef CONFIG_MESH
+
+static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
+}
+
+#endif /* CONFIG_MESH */
+
+
#ifdef CONFIG_P2P
static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -1711,6 +1830,20 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv);
+}
+
+
static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1795,11 +1928,9 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
{
char cmd[4096];
- if (argc != 2 && argc != 4) {
+ if (argc < 2) {
printf("Invalid P2P_SERV_DISC_REQ command: needs two "
- "arguments (address and TLVs) or four arguments "
- "(address, \"upnp\", version, search target "
- "(SSDP ST:)\n");
+ "or more arguments (address and TLVs)\n");
return -1;
}
@@ -1830,7 +1961,7 @@ static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc,
res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
argv[0], argv[1], argv[2], argv[3]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -1861,27 +1992,25 @@ static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[4096];
- int res;
+ if (argc < 3) {
+ printf("Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n");
+ return -1;
+ }
+
+ return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv);
+}
+
- if (argc != 3 && argc != 4) {
- printf("Invalid P2P_SERVICE_ADD command: needs three or four "
+static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc < 5 || argc > 6) {
+ printf("Invalid P2P_SERVICE_REP command: needs 5-6 "
"arguments\n");
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_SERVICE_ADD %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_SERVICE_ADD %s %s %s",
- argv[0], argv[1], argv[2]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv);
}
@@ -1905,7 +2034,7 @@ static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
res = os_snprintf(cmd, sizeof(cmd),
"P2P_SERVICE_DEL %s %s",
argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -2008,6 +2137,50 @@ static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static char ** wpa_cli_complete_p2p_set(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ "discoverability",
+ "managed",
+ "listen_channel",
+ "ssid_postfix",
+ "noa",
+ "ps",
+ "oppps",
+ "ctwindow",
+ "disabled",
+ "conc_pref",
+ "force_long_sd",
+ "peer_filter",
+ "cross_connect",
+ "go_apsd",
+ "client_apsd",
+ "disallow_freq",
+ "disc_int",
+ "per_sta_psk",
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **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;
+ }
+ return res;
+ }
+
+ if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0)
+ return cli_txt_list_array(&p2p_peers);
+
+ return NULL;
+}
+
+
static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "P2P_FLUSH");
@@ -2058,6 +2231,13 @@ static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
}
+
+static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
+}
+
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
@@ -2076,7 +2256,7 @@ static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
argv[0], argc > 1 ? argv[1] : "");
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -2097,7 +2277,7 @@ static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -2134,6 +2314,13 @@ static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
@@ -2182,6 +2369,37 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
return wpa_ctrl_command(ctrl, cmd);
}
+
+static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[512];
+
+ if (argc < 2) {
+ printf("Command needs two arguments (dst mac addr and "
+ "icon name)\n");
+ return -1;
+ }
+
+ if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0)
+ return -1;
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "FETCH_OSU");
+}
+
+
+static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU");
+}
+
#endif /* CONFIG_HS20 */
@@ -2213,6 +2431,41 @@ static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_wmm_ac_addts(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WMM_AC_ADDTS", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wmm_ac_delts(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WMM_AC_DELTS", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WMM_AC_STATUS");
+}
+
+
+static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2254,6 +2507,12 @@ static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
}
+
+static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv);
+}
+
#endif /* CONFIG_WNM */
@@ -2265,6 +2524,52 @@ static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+#ifdef ANDROID
+static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
+}
+#endif /* ANDROID */
+
+
+static int wpa_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "VENDOR", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "FLUSH");
+}
+
+
+static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
+static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv);
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2312,10 +2617,13 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "quit", wpa_cli_cmd_quit, NULL,
cli_cmd_flag_none,
"= exit wpa_cli" },
- { "set", wpa_cli_cmd_set, NULL,
+ { "set", wpa_cli_cmd_set, wpa_cli_complete_set,
cli_cmd_flag_none,
"= set variables (shows list of variables when run without "
"arguments)" },
+ { "dump", wpa_cli_cmd_dump, NULL,
+ cli_cmd_flag_none,
+ "= dump config variables" },
{ "get", wpa_cli_cmd_get, NULL,
cli_cmd_flag_none,
"<name> = get information" },
@@ -2328,9 +2636,15 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "pmksa", wpa_cli_cmd_pmksa, NULL,
cli_cmd_flag_none,
"= show PMKSA cache" },
+ { "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL,
+ cli_cmd_flag_none,
+ "= flush PMKSA cache entries" },
{ "reassociate", wpa_cli_cmd_reassociate, NULL,
cli_cmd_flag_none,
"= force reassociation" },
+ { "reattach", wpa_cli_cmd_reattach, NULL,
+ cli_cmd_flag_none,
+ "= force reassociation back to the same BSS" },
{ "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = force preauthentication" },
@@ -2354,6 +2668,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
+ { "sim", wpa_cli_cmd_sim, NULL,
+ cli_cmd_flag_sensitive,
+ "<network id> <pin> = report SIM operation result" },
{ "bssid", wpa_cli_cmd_bssid, NULL,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
@@ -2391,6 +2708,10 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "get_network", wpa_cli_cmd_get_network, NULL,
cli_cmd_flag_none,
"<network id> <variable> = get network variables" },
+ { "dup_network", wpa_cli_cmd_dup_network, NULL,
+ cli_cmd_flag_none,
+ "<src network id> <dst network id> <variable> = duplicate network variables"
+ },
{ "list_creds", wpa_cli_cmd_list_creds, NULL,
cli_cmd_flag_none,
"= list configured credentials" },
@@ -2403,6 +2724,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "set_cred", wpa_cli_cmd_set_cred, NULL,
cli_cmd_flag_sensitive,
"<cred id> <variable> <value> = set credential variables" },
+ { "get_cred", wpa_cli_cmd_get_cred, NULL,
+ cli_cmd_flag_none,
+ "<cred id> <variable> = get credential variables" },
{ "save_config", wpa_cli_cmd_save_config, NULL,
cli_cmd_flag_none,
"= save the current configuration" },
@@ -2425,7 +2749,7 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
"<<idx> | <bssid>> = get detailed scan result info" },
{ "get_capability", wpa_cli_cmd_get_capability, NULL,
cli_cmd_flag_none,
- "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> "
+ "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
"= get capabilies" },
{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
cli_cmd_flag_none,
@@ -2481,6 +2805,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: NFC" },
+ { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
+ cli_cmd_flag_none,
+ "<WPS|NDEF> = build configuration token" },
{ "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
cli_cmd_flag_none,
"<WPS|NDEF> = create password token" },
@@ -2493,12 +2820,10 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
cli_cmd_flag_none,
"<NDEF> <WPS> = create NFC handover select" },
- { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+ { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
cli_cmd_flag_none,
- "<hexdump of payload> = report received NFC handover request" },
- { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
- cli_cmd_flag_none,
- "<hexdump of payload> = report received NFC handover select" },
+ "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
+ "NFC handover" },
#endif /* CONFIG_WPS_NFC */
{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
@@ -2548,22 +2873,46 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "disassociate", wpa_cli_cmd_disassociate, NULL,
cli_cmd_flag_none,
"<addr> = disassociate a station" },
+ { "chan_switch", wpa_cli_cmd_chanswitch, NULL,
+ cli_cmd_flag_none,
+ "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
+ " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
+ " = CSA parameters" },
#endif /* CONFIG_AP */
{ "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
{ "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
"= notification of resume/thaw" },
+#ifdef CONFIG_TESTING_OPTIONS
{ "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
"= drop SA without deauth/disassoc (test command)" },
+#endif /* CONFIG_TESTING_OPTIONS */
{ "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
+#ifdef CONFIG_MESH
+ { "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL,
+ cli_cmd_flag_none,
+ "[ifname] = Create a new mesh interface" },
+ { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
+ cli_cmd_flag_none,
+ "<network id> = join a mesh network (disable others)" },
+ { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
+ cli_cmd_flag_none,
+ "<ifname> = Remove mesh group interface" },
+#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
cli_cmd_flag_none,
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
{ "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
"= stop P2P Devices search" },
+ { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL,
+ cli_cmd_flag_none,
+ "<addr> adv_id=<adv_id> conncap=<conncap> [info=<infodata>] = provision with a P2P ASP Device" },
+ { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL,
+ cli_cmd_flag_none,
+ "<addr> adv_id=<adv_id> [role<conncap>] [info=<infodata>] = provision with a P2P ASP Device" },
{ "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
cli_cmd_flag_none,
"<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
@@ -2600,8 +2949,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
"= remove all stored service entries" },
{ "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
cli_cmd_flag_none,
- "<bonjour|upnp> <query|version> <response|service> = add a local "
+ "<bonjour|upnp|asp> <query|version> <response|service> = add a local "
"service" },
+ { "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL,
+ cli_cmd_flag_none,
+ "asp <auto> <adv_id> <svc_state> <svc_string> [<svc_info>] = replace "
+ "local ASP service" },
{ "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> [|service] = remove a local "
@@ -2618,7 +2971,8 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
cli_cmd_flag_none,
"<address> = show information about known P2P peer" },
- { "p2p_set", wpa_cli_cmd_p2p_set, NULL, cli_cmd_flag_none,
+ { "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set,
+ cli_cmd_flag_none,
"<field> <value> = set a P2P parameter" },
{ "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
"= flush P2P state" },
@@ -2634,6 +2988,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
cli_cmd_flag_none,
"[<period> <interval>] = set extended listen timing" },
+ { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
+ "<address|iface=address> = remove a peer from all groups" },
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
@@ -2655,6 +3012,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "interworking_connect", wpa_cli_cmd_interworking_connect,
wpa_cli_complete_bss, cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" },
+ { "interworking_add_network", wpa_cli_cmd_interworking_add_network,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
+ "<BSSID> = connect using Interworking credentials" },
{ "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" },
@@ -2673,6 +3033,14 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
wpa_cli_complete_bss, cli_cmd_flag_none,
"<addr> <home realm> = get HS20 nai home realm list" },
+ { "hs20_icon_request", wpa_cli_cmd_hs20_icon_request,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
+ "<addr> <icon name> = get Hotspot 2.0 OSU icon" },
+ { "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none,
+ "= fetch OSU provider information from all APs" },
+ { "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL,
+ cli_cmd_flag_none,
+ "= cancel fetch_osu command" },
#endif /* CONFIG_HS20 */
{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
cli_cmd_flag_none,
@@ -2686,6 +3054,25 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
cli_cmd_flag_none,
"<addr> = tear down TDLS with <addr>" },
+ { "wmm_ac_addts", wpa_cli_cmd_wmm_ac_addts, NULL,
+ cli_cmd_flag_none,
+ "<uplink/downlink/bidi> <tsid=0..7> <up=0..7> [nominal_msdu_size=#] "
+ "[mean_data_rate=#] [min_phy_rate=#] [sba=#] [fixed_nominal_msdu] "
+ "= add WMM-AC traffic stream" },
+ { "wmm_ac_delts", wpa_cli_cmd_wmm_ac_delts, NULL,
+ cli_cmd_flag_none,
+ "<tsid> = delete WMM-AC traffic stream" },
+ { "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL,
+ cli_cmd_flag_none,
+ "= show status for Wireless Multi-Media Admission-Control" },
+ { "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL,
+ cli_cmd_flag_none,
+ "<addr> <oper class> <freq> [sec_channel_offset=] [center_freq1=] "
+ "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching "
+ "with TDLS peer" },
+ { "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL,
+ cli_cmd_flag_none,
+ "<addr> = disable channel switching with TDLS peer <addr>" },
{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
cli_cmd_flag_none,
"= get signal parameters" },
@@ -2702,9 +3089,34 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
#ifdef CONFIG_WNM
{ "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" },
#endif /* CONFIG_WNM */
{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
"<params..> = Sent unprocessed command" },
+ { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
+ "= flush wpa_supplicant state" },
+#ifdef ANDROID
+ { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none,
+ "<command> = driver private commands" },
+#endif /* ANDROID */
+ { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none,
+ "= radio_work <show/add/done>" },
+ { "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none,
+ "<vendor id> <command id> [<hex formatted command argument>] = Send vendor command"
+ },
+ { "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)"
+ },
+ { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
+ "= flush ERP keys" },
+ { "mac_rand_scan",
+ wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none,
+ "<scan|sched|pno|all> enable=<0/1> [addr=mac-address "
+ "mask=mac-address-mask] = scan MAC randomization"
+ },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -2763,9 +3175,12 @@ static char ** wpa_list_cmd_list(void)
{
char **res;
int i, count;
+ struct cli_txt_entry *e;
- count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
- res = os_calloc(count, sizeof(char *));
+ count = ARRAY_SIZE(wpa_cli_commands);
+ count += dl_list_len(&p2p_groups);
+ count += dl_list_len(&ifnames);
+ res = os_calloc(count + 1, sizeof(char *));
if (res == NULL)
return NULL;
@@ -2775,6 +3190,22 @@ static char ** wpa_list_cmd_list(void)
break;
}
+ dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
+ size_t len = 8 + os_strlen(e->txt);
+ res[i] = os_malloc(len);
+ if (res[i] == NULL)
+ break;
+ os_snprintf(res[i], len, "ifname=%s", e->txt);
+ i++;
+ }
+
+ dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
+ res[i] = os_strdup(e->txt);
+ if (res[i] == NULL)
+ break;
+ i++;
+ }
+
return res;
}
@@ -2806,6 +3237,14 @@ static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
const char *end;
char *cmd;
+ if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
+ end = os_strchr(str, ' ');
+ if (end && pos > end - str) {
+ pos -= end - str + 1;
+ str = end + 1;
+ }
+ }
+
end = os_strchr(str, ' ');
if (end == NULL || str + pos < end)
return wpa_list_cmd_list();
@@ -2827,6 +3266,16 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
int count;
int ret = 0;
+ if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
+ ifname_prefix = argv[0] + 7;
+ argv = &argv[1];
+ argc--;
+ } else
+ ifname_prefix = NULL;
+
+ if (argc == 0)
+ return -1;
+
count = 0;
cmd = wpa_cli_commands;
while (cmd->cmd) {
@@ -2875,28 +3324,19 @@ static int str_match(const char *a, const char *b)
static int wpa_cli_exec(const char *program, const char *arg1,
const char *arg2)
{
- char *cmd;
+ char *arg;
size_t len;
int res;
- int ret = 0;
- len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
- cmd = os_malloc(len);
- if (cmd == NULL)
- return -1;
- res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
- if (res < 0 || (size_t) res >= len) {
- os_free(cmd);
+ len = os_strlen(arg1) + os_strlen(arg2) + 2;
+ arg = os_malloc(len);
+ if (arg == NULL)
return -1;
- }
- cmd[len - 1] = '\0';
-#ifndef _WIN32_WCE
- if (system(cmd) < 0)
- ret = -1;
-#endif /* _WIN32_WCE */
- os_free(cmd);
+ os_snprintf(arg, len, "%s %s", arg1, arg2);
+ res = os_exec(program, arg, 1);
+ os_free(arg);
- return ret;
+ return res;
}
@@ -2904,15 +3344,29 @@ static void wpa_cli_action_process(const char *msg)
{
const char *pos;
char *copy = NULL, *id, *pos2;
+ const char *ifname = ctrl_ifname;
+ char ifname_buf[100];
pos = msg;
+ if (os_strncmp(pos, "IFNAME=", 7) == 0) {
+ const char *end;
+ end = os_strchr(pos + 7, ' ');
+ if (end && (unsigned int) (end - pos) < sizeof(ifname_buf)) {
+ pos += 7;
+ os_memcpy(ifname_buf, pos, end - pos);
+ ifname_buf[end - pos] = '\0';
+ ifname = ifname_buf;
+ pos = end + 1;
+ }
+ }
if (*pos == '<') {
+ const char *prev = pos;
/* skip priority */
pos = os_strchr(pos, '>');
if (pos)
pos++;
else
- pos = msg;
+ pos = prev;
}
if (str_match(pos, WPA_EVENT_CONNECTED)) {
@@ -2946,34 +3400,48 @@ static void wpa_cli_action_process(const char *msg)
os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
- if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
+ if (wpa_cli_connected <= 0 || new_id != wpa_cli_last_id) {
wpa_cli_connected = 1;
wpa_cli_last_id = new_id;
- wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
+ wpa_cli_exec(action_file, ifname, "CONNECTED");
}
} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
if (wpa_cli_connected) {
wpa_cli_connected = 0;
- wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
+ wpa_cli_exec(action_file, ifname, "DISCONNECTED");
}
- } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+ } else if (str_match(pos, MESH_GROUP_STARTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+ } else if (str_match(pos, MESH_GROUP_REMOVED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+ } else if (str_match(pos, MESH_PEER_CONNECTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+ } else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, WPS_EVENT_FAIL)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, AP_STA_CONNECTED)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, AP_STA_DISCONNECTED)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
@@ -3105,7 +3573,7 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
return;
}
while (wpa_ctrl_pending(ctrl) > 0) {
- char buf[256];
+ char buf[4096];
size_t len = sizeof(buf) - 1;
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
buf[len] = '\0';
@@ -3169,10 +3637,18 @@ static int tokenize_cmd(char *cmd, char *argv[])
static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
{
- if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
- printf("Connection to wpa_supplicant lost - trying to "
- "reconnect\n");
- wpa_cli_close_connection();
+ if (ctrl_conn) {
+ int res;
+ char *prefix = ifname_prefix;
+
+ ifname_prefix = NULL;
+ res = _wpa_ctrl_command(ctrl_conn, "PING", 0);
+ ifname_prefix = prefix;
+ if (res) {
+ printf("Connection to wpa_supplicant lost - trying to "
+ "reconnect\n");
+ wpa_cli_close_connection();
+ }
}
if (!ctrl_conn)
wpa_cli_reconnect();
@@ -3235,24 +3711,94 @@ static void start_edit(void)
}
+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";
+ char *pos, *end;
+
+ 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) {
+ pos = os_strstr(pos, "bssid=");
+ if (pos == NULL)
+ break;
+ pos += 6;
+ end = os_strchr(pos, '\n');
+ if (end == NULL)
+ break;
+ *end = '\0';
+ cli_txt_list_add(&bsses, pos);
+ pos = end + 1;
+ }
+}
+
+
+static void update_ifnames(struct wpa_ctrl *ctrl)
+{
+ char buf[4096];
+ size_t len = sizeof(buf);
+ int ret;
+ char *cmd = "INTERFACES";
+ char *pos, *end;
+ char txt[200];
+
+ cli_txt_list_flush(&ifnames);
+
+ 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';
+ ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
+ if (!os_snprintf_error(sizeof(txt), ret))
+ cli_txt_list_add(&ifnames, txt);
+ pos = end + 1;
+ }
+}
+
+
static void try_connection(void *eloop_ctx, void *timeout_ctx)
{
+ if (ctrl_conn)
+ goto done;
+
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
if (!warning_displayed) {
printf("Could not connect to wpa_supplicant: "
- "%s - re-trying\n", ctrl_ifname);
+ "%s - re-trying\n",
+ ctrl_ifname ? ctrl_ifname : "(nil)");
warning_displayed = 1;
}
eloop_register_timeout(1, 0, try_connection, NULL, NULL);
return;
}
+ update_bssid_list(ctrl_conn);
+
if (warning_displayed)
printf("Connection established.\n");
+done:
start_edit();
}
@@ -3268,6 +3814,7 @@ static void wpa_cli_interactive(void)
cli_txt_list_flush(&p2p_peers);
cli_txt_list_flush(&p2p_groups);
cli_txt_list_flush(&bsses);
+ cli_txt_list_flush(&ifnames);
if (edit_started)
edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
os_free(hfile);
@@ -3374,7 +3921,7 @@ static char * wpa_cli_get_default_ifname(void)
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
- char buf[2048], *pos;
+ char buf[4096], *pos;
size_t len;
struct wpa_ctrl *ctrl;
int ret;
@@ -3468,6 +4015,24 @@ int main(int argc, char *argv[])
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");
+ }
+ }
+ }
}
eloop_register_signal_terminate(wpa_cli_terminate, NULL);
@@ -3482,7 +4047,8 @@ int main(int argc, char *argv[])
wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
fprintf(stderr, "Failed to connect to non-global "
"ctrl_ifname: %s error: %s\n",
- ctrl_ifname, strerror(errno));
+ ctrl_ifname ? ctrl_ifname : "(nil)",
+ strerror(errno));
return -1;
}
diff --git a/contrib/wpa/wpa_supplicant/wpa_priv.c b/contrib/wpa/wpa_supplicant/wpa_priv.c
index ad6a080..ac38d69 100644
--- a/contrib/wpa/wpa_supplicant/wpa_priv.c
+++ b/contrib/wpa/wpa_supplicant/wpa_priv.c
@@ -202,7 +202,9 @@ static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface,
if (assoc->ssid_len > 32)
return;
params.ssid_len = assoc->ssid_len;
- params.freq = assoc->freq;
+ params.freq.mode = assoc->hwmode;
+ params.freq.freq = assoc->freq;
+ params.freq.channel = assoc->channel;
if (assoc->wpa_ie_len) {
params.wpa_ie = (u8 *) (assoc + 1);
params.wpa_ie_len = assoc->wpa_ie_len;
@@ -333,7 +335,7 @@ static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
msg.msg_namelen = sizeof(iface->l2_addr);
if (sendmsg(iface->fd, &msg, 0) < 0) {
- perror("sendmsg(l2 rx)");
+ wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
}
}
@@ -465,7 +467,7 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
&fromlen);
if (res < 0) {
- perror("recvfrom");
+ wpa_printf(MSG_ERROR, "recvfrom: %s", strerror(errno));
return;
}
@@ -552,8 +554,6 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
}
-extern struct wpa_driver_ops *wpa_drivers[];
-
static struct wpa_priv_interface *
wpa_priv_interface_init(const char *dir, const char *params)
{
@@ -573,13 +573,11 @@ wpa_priv_interface_init(const char *dir, const char *params)
iface->fd = -1;
len = pos - params;
- iface->driver_name = os_malloc(len + 1);
+ iface->driver_name = dup_binstr(params, len);
if (iface->driver_name == NULL) {
wpa_priv_interface_deinit(iface);
return NULL;
}
- os_memcpy(iface->driver_name, params, len);
- iface->driver_name[len] = '\0';
for (i = 0; wpa_drivers[i]; i++) {
if (os_strcmp(iface->driver_name,
@@ -617,7 +615,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if (iface->fd < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
wpa_priv_interface_deinit(iface);
return NULL;
}
@@ -635,15 +633,16 @@ wpa_priv_interface_init(const char *dir, const char *params)
"allow connections - assuming it was "
"leftover from forced program termination");
if (unlink(iface->sock_name) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- iface->sock_name);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ iface->sock_name, strerror(errno));
goto fail;
}
if (bind(iface->fd, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("wpa-priv-iface-init: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "wpa-priv-iface-init: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -658,7 +657,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
}
if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
- perror("chmod");
+ wpa_printf(MSG_ERROR, "chmod: %s", strerror(errno));
goto fail;
}
@@ -690,7 +689,8 @@ static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event,
msg.msg_namelen = sizeof(iface->drv_addr);
if (sendmsg(iface->fd, &msg, 0) < 0) {
- perror("sendmsg(wpas_socket)");
+ wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
+ strerror(errno));
return -1;
}
@@ -905,7 +905,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
msg.msg_namelen = sizeof(iface->drv_addr);
if (sendmsg(iface->fd, &msg, 0) < 0)
- perror("sendmsg(wpas_socket)");
+ wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
+ strerror(errno));
}
@@ -948,8 +949,6 @@ static void usage(void)
}
-extern int wpa_debug_level;
-
int main(int argc, char *argv[])
{
int c, i;
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.c b/contrib/wpa/wpa_supplicant/wpa_supplicant.c
index 0fb4d0f..19fb890 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-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,6 +17,7 @@
#include "crypto/sha1.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
#include "eap_server/eap_methods.h"
#include "rsn_supp/wpa.h"
#include "eloop.h"
@@ -32,6 +33,7 @@
#include "rsn_supp/pmksa_cache.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "p2p/p2p.h"
#include "blacklist.h"
#include "wpas_glue.h"
@@ -49,10 +51,13 @@
#include "scan.h"
#include "offchannel.h"
#include "hs20_supplicant.h"
+#include "wnm_sta.h"
+#include "wpas_kay.h"
+#include "mesh.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors";
const char *wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -102,11 +107,6 @@ const char *wpa_supplicant_full_license5 =
"\n";
#endif /* CONFIG_NO_STDOUT_DEBUG */
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-extern struct wpa_driver_ops *wpa_drivers[];
-
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -126,13 +126,14 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
-static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
u8 key[32];
size_t keylen;
enum wpa_alg alg;
u8 seq[6] = { 0 };
+ int ret;
/* IBSS/WPA-None uses only one key (Group) for both receiving and
* sending unicast and multicast packets. */
@@ -176,7 +177,9 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ os_memset(key, 0, sizeof(key));
+ return ret;
}
@@ -198,17 +201,6 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
* So, wait a second until scanning again.
*/
wpa_supplicant_req_scan(wpa_s, 1, 0);
-
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after timed out authentication");
- }
- }
-#endif /* CONFIG_P2P */
}
@@ -224,7 +216,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec)
{
- if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+ if (wpa_s->conf->ap_scan == 0 &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
return;
@@ -300,17 +292,37 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
EAPOL_REQUIRE_KEY_BROADCAST;
}
- if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
eapol_conf.required_keys = 0;
}
- if (wpa_s->conf)
- eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+ eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
eapol_conf.eap_disabled =
!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+ eapol_conf.external_sim = wpa_s->conf->external_sim;
+
+#ifdef CONFIG_WPS
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+ eapol_conf.wps |= EAPOL_LOCAL_WPS_IN_USE;
+ if (wpa_s->current_bss) {
+ struct wpabuf *ie;
+ ie = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
+ WPS_IE_VENDOR_TYPE);
+ if (ie) {
+ if (wps_is_20(ie))
+ eapol_conf.wps |=
+ EAPOL_PEER_IS_WPS20_AP;
+ wpabuf_free(ie);
+ }
+ }
+ }
+#endif /* CONFIG_WPS */
+
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
+
+ ieee802_1x_alloc_kay_sm(wpa_s, ssid);
#endif /* IEEE8021X_EAPOL */
}
@@ -386,6 +398,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
+ int i;
+
bgscan_deinit(wpa_s);
autoscan_deinit(wpa_s);
scard_deinit(wpa_s->scard);
@@ -398,6 +412,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
l2_packet_deinit(wpa_s->l2_br);
wpa_s->l2_br = NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ l2_packet_deinit(wpa_s->l2_test);
+ wpa_s->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
struct wpa_ssid *ssid;
@@ -408,6 +426,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
os_free(wpa_s->confname);
wpa_s->confname = NULL;
+ os_free(wpa_s->confanother);
+ wpa_s->confanother = NULL;
+
wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
@@ -418,6 +439,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_tdls_deinit(wpa_s->wpa);
#endif /* CONFIG_TDLS */
+ wmm_ac_clear_saved_tspecs(wpa_s);
pmksa_candidate_free(wpa_s->wpa);
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
@@ -425,6 +447,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_bss_deinit(wpa_s);
+ wpa_supplicant_cancel_delayed_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_cancel_auth_timeout(wpa_s);
eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
@@ -449,9 +472,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_supplicant_ap_deinit(wpa_s);
#endif /* CONFIG_AP */
-#ifdef CONFIG_P2P
wpas_p2p_deinit(wpa_s);
-#endif /* CONFIG_P2P */
#ifdef CONFIG_OFFCHANNEL
offchannel_deinit(wpa_s);
@@ -462,11 +483,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = NULL;
+
+ os_free(wpa_s->manual_sched_scan_freqs);
+ wpa_s->manual_sched_scan_freqs = NULL;
+
+ wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
+
gas_query_deinit(wpa_s->gas);
wpa_s->gas = NULL;
free_hw_features(wpa_s);
+ ieee802_1x_dealloc_kay_sm(wpa_s);
+
os_free(wpa_s->bssid_filter);
wpa_s->bssid_filter = NULL;
@@ -476,14 +507,31 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->disallow_aps_ssid = NULL;
wnm_bss_keep_alive_deinit(wpa_s);
+#ifdef CONFIG_WNM
+ wnm_deallocate_memory(wpa_s);
+#endif /* CONFIG_WNM */
ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL;
wpabuf_free(wpa_s->last_gas_resp);
+ wpa_s->last_gas_resp = NULL;
+ wpabuf_free(wpa_s->prev_gas_resp);
+ wpa_s->prev_gas_resp = NULL;
os_free(wpa_s->last_scan_res);
wpa_s->last_scan_res = NULL;
+
+#ifdef CONFIG_HS20
+ hs20_deinit(wpa_s);
+#endif /* CONFIG_HS20 */
+
+ for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
+ wpabuf_free(wpa_s->vendor_elem[i]);
+ wpa_s->vendor_elem[i] = NULL;
+ }
+
+ wmm_ac_notify_disassoc(wpa_s);
}
@@ -497,29 +545,23 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- if (wpa_s->keys_cleared) {
- /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
- * timing issues with keys being cleared just before new keys
- * are set or just after association or something similar. This
- * shows up in group key handshake failing often because of the
- * client not receiving the first encrypted packets correctly.
- * Skipping some of the extra key clearing steps seems to help
- * in completing group key handshake more reliably. */
- wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - "
- "skip key clearing");
- return;
- }
+ int i, max;
- /* MLME-DELETEKEYS.request */
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
#ifdef CONFIG_IEEE80211W
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+ max = 6;
+#else /* CONFIG_IEEE80211W */
+ max = 4;
#endif /* CONFIG_IEEE80211W */
- if (addr) {
+
+ /* MLME-DELETEKEYS.request */
+ for (i = 0; i < max; i++) {
+ if (wpa_s->keys_cleared & BIT(i))
+ continue;
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+ NULL, 0);
+ }
+ if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+ !is_zero_ether_addr(addr)) {
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
0);
/* MLME-SETPROTECTION.request(None) */
@@ -528,7 +570,7 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
}
- wpa_s->keys_cleared = 1;
+ wpa_s->keys_cleared = (u32) -1;
}
@@ -570,14 +612,26 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
{
+ const char *name;
+
+ if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
+ name = wpa_s->current_ssid->bgscan;
+ else
+ name = wpa_s->conf->bgscan;
+ if (name == NULL || name[0] == '\0')
+ return;
if (wpas_driver_bss_selection(wpa_s))
return;
if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
return;
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
+ return;
+#endif /* CONFIG_P2P */
bgscan_deinit(wpa_s);
- if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
- if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+ if (wpa_s->current_ssid) {
+ if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
"bgscan");
/*
@@ -651,12 +705,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_INTERFACE_DISABLED) {
+ /* Assure normal scan when interface is restored */
+ wpa_s->normal_scans = 0;
+ }
+
+ if (state == WPA_COMPLETED) {
+ wpas_connect_work_done(wpa_s);
+ /* Reinitialize normal_scan counter */
+ wpa_s->normal_scans = 0;
+ }
+
if (state != WPA_SCANNING)
wpa_supplicant_notify_scanning(wpa_s, 0);
if (state == WPA_COMPLETED && wpa_s->new_connection) {
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct wpa_ssid *ssid = wpa_s->current_ssid;
+#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]",
MAC2STR(wpa_s->bssid),
@@ -671,9 +736,8 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_drv_set_supp_port(wpa_s, 1);
#endif /* IEEE8021X_EAPOL */
wpa_s->after_wps = 0;
-#ifdef CONFIG_P2P
+ wpa_s->known_wps_freq = 0;
wpas_p2p_completed(wpa_s);
-#endif /* CONFIG_P2P */
sme_sched_obss_scan(wpa_s, 1);
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
@@ -690,7 +754,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_BGSCAN
if (state == WPA_COMPLETED)
wpa_supplicant_start_bgscan(wpa_s);
- else
+ else if (state < WPA_ASSOCIATED)
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
@@ -700,9 +764,18 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
wpa_supplicant_start_autoscan(wpa_s);
+ if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
+ wmm_ac_notify_disassoc(wpa_s);
+
if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+ /*
+ * Notify the P2P Device interface about a state change in one
+ * of the interfaces.
+ */
+ wpas_p2p_indicate_state_change(wpa_s);
+
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
@@ -716,9 +789,15 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global)
#ifdef CONFIG_WPS
struct wpa_supplicant *wpa_s = global->ifaces;
while (wpa_s) {
+ struct wpa_supplicant *next = wpa_s->next;
if (wpas_wps_terminate_pending(wpa_s) == 1)
pending = 1;
- wpa_s = wpa_s->next;
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
+ (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
+ wpas_p2p_disconnect(wpa_s);
+#endif /* CONFIG_P2P */
+ wpa_s = next;
}
#endif /* CONFIG_WPS */
if (pending)
@@ -769,12 +848,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
if (wpa_s->confname == NULL)
return -1;
- conf = wpa_config_read(wpa_s->confname);
+ conf = wpa_config_read(wpa_s->confname, NULL);
if (conf == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
"file '%s' - exiting", wpa_s->confname);
return -1;
}
+ wpa_config_read(wpa_s->confanother, conf);
+
conf->changed_parameters = (unsigned int) -1;
reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
@@ -789,13 +870,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
eapol_sm_invalidate_cached_session(wpa_s->eapol);
if (wpa_s->current_ssid) {
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
/*
* TODO: should notify EAPOL SM about changes in opensc_engine_path,
- * pkcs11_engine_path, pkcs11_module_path.
+ * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
*/
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
/*
@@ -845,54 +927,6 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
}
-enum wpa_cipher cipher_suite2driver(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_NONE:
- return CIPHER_NONE;
- case WPA_CIPHER_WEP40:
- return CIPHER_WEP40;
- case WPA_CIPHER_WEP104:
- return CIPHER_WEP104;
- case WPA_CIPHER_CCMP:
- return CIPHER_CCMP;
- case WPA_CIPHER_GCMP:
- return CIPHER_GCMP;
- case WPA_CIPHER_TKIP:
- default:
- return CIPHER_TKIP;
- }
-}
-
-
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
-{
- switch (key_mgmt) {
- case WPA_KEY_MGMT_NONE:
- return KEY_MGMT_NONE;
- case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
- return KEY_MGMT_802_1X_NO_WPA;
- case WPA_KEY_MGMT_IEEE8021X:
- return KEY_MGMT_802_1X;
- case WPA_KEY_MGMT_WPA_NONE:
- return KEY_MGMT_WPA_NONE;
- case WPA_KEY_MGMT_FT_IEEE8021X:
- return KEY_MGMT_FT_802_1X;
- case WPA_KEY_MGMT_FT_PSK:
- return KEY_MGMT_FT_PSK;
- case WPA_KEY_MGMT_IEEE8021X_SHA256:
- return KEY_MGMT_802_1X_SHA256;
- case WPA_KEY_MGMT_PSK_SHA256:
- return KEY_MGMT_PSK_SHA256;
- case WPA_KEY_MGMT_WPS:
- return KEY_MGMT_WPS;
- case WPA_KEY_MGMT_PSK:
- default:
- return KEY_MGMT_PSK;
- }
-}
-
-
static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct wpa_ie_data *ie)
@@ -929,9 +963,7 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) ==
- MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
"that does not support management frame protection - "
"reject");
@@ -963,13 +995,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
{
struct wpa_ie_data ie;
int sel, proto;
- const u8 *bss_wpa, *bss_rsn;
+ const u8 *bss_wpa, *bss_rsn, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
} else
- bss_wpa = bss_rsn = NULL;
+ bss_wpa = bss_rsn = bss_osen = NULL;
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -979,17 +1012,63 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
proto = WPA_PROTO_RSN;
} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
- wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
+ wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[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, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
+#ifdef CONFIG_HS20
+ } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) {
+ 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;
+#endif /* CONFIG_HS20 */
} else if (bss) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+ ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
+ ssid->key_mgmt);
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
+ MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len),
+ bss_wpa ? " WPA" : "",
+ bss_rsn ? " RSN" : "",
+ bss_osen ? " OSEN" : "");
+ if (bss_rsn) {
+ wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
+ if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Could not parse RSN element");
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RSN: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+ ie.pairwise_cipher, ie.group_cipher,
+ ie.key_mgmt);
+ }
+ }
+ if (bss_wpa) {
+ wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
+ if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Could not parse WPA element");
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+ ie.pairwise_cipher, ie.group_cipher,
+ ie.key_mgmt);
+ }
+ }
return -1;
} else {
- if (ssid->proto & WPA_PROTO_RSN)
+ if (ssid->proto & WPA_PROTO_OSEN)
+ proto = WPA_PROTO_OSEN;
+ else if (ssid->proto & WPA_PROTO_RSN)
proto = WPA_PROTO_RSN;
else
proto = WPA_PROTO_WPA;
@@ -1022,7 +1101,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
- !!(ssid->proto & WPA_PROTO_RSN));
+ !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
if (bss || !wpa_s->ap_ies_from_associnfo) {
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
@@ -1033,45 +1112,24 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
sel = ie.group_cipher & ssid->group_cipher;
- if (sel & WPA_CIPHER_CCMP) {
- wpa_s->group_cipher = WPA_CIPHER_CCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
- } else if (sel & WPA_CIPHER_GCMP) {
- wpa_s->group_cipher = WPA_CIPHER_GCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP");
- } else if (sel & WPA_CIPHER_TKIP) {
- wpa_s->group_cipher = WPA_CIPHER_TKIP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
- } else if (sel & WPA_CIPHER_WEP104) {
- wpa_s->group_cipher = WPA_CIPHER_WEP104;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
- } else if (sel & WPA_CIPHER_WEP40) {
- wpa_s->group_cipher = WPA_CIPHER_WEP40;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
- } else {
+ 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 "
"cipher");
return -1;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
+ wpa_cipher_txt(wpa_s->group_cipher));
sel = ie.pairwise_cipher & ssid->pairwise_cipher;
- if (sel & WPA_CIPHER_CCMP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
- } else if (sel & WPA_CIPHER_GCMP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP");
- } else if (sel & WPA_CIPHER_TKIP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
- } else if (sel & WPA_CIPHER_NONE) {
- wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
- } else {
+ 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 "
"cipher");
return -1;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
+ wpa_cipher_txt(wpa_s->pairwise_cipher));
sel = ie.key_mgmt & ssid->key_mgmt;
#ifdef CONFIG_SAE
@@ -1079,6 +1137,18 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
if (0) {
+#ifdef CONFIG_SUITEB192
+ } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
+#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_SUITEB
+ } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using KEY_MGMT 802.1X with Suite B");
+#endif /* CONFIG_SUITEB */
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1114,6 +1184,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
+#ifdef CONFIG_HS20
+ } else if (sel & WPA_KEY_MGMT_OSEN) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
+#endif /* CONFIG_HS20 */
} else {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
"authenticated key management type");
@@ -1127,14 +1202,25 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
sel = ie.mgmt_group_cipher;
- if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
!(ie.capabilities & WPA_CAPABILITY_MFPC))
sel = 0;
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 "
"AES-128-CMAC");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ "BIP-GMAC-128");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ "BIP-GMAC-256");
+ } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ "BIP-CMAC-256");
} else {
wpa_s->mgmt_group_cipher = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
@@ -1142,8 +1228,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w));
+ wpas_get_ssid_pmf(wpa_s, ssid));
#endif /* CONFIG_IEEE80211W */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1152,7 +1237,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
- wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
#ifndef CONFIG_NO_PBKDF2
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
ssid->passphrase) {
@@ -1161,7 +1246,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
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);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ os_memset(psk, 0, sizeof(psk));
}
#endif /* CONFIG_NO_PBKDF2 */
#ifdef CONFIG_EXT_PASSWORD
@@ -1197,7 +1283,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);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ os_memset(psk, 0, sizeof(psk));
} else
#endif /* CONFIG_NO_PBKDF2 */
if (wpabuf_len(pw) == 2 * PMK_LEN) {
@@ -1208,7 +1295,8 @@ 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);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ os_memset(psk, 0, sizeof(psk));
} else {
wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
"PSK available");
@@ -1228,33 +1316,209 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
-int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
{
- u32 ext_capab = 0;
- u8 *pos = buf;
+ *pos = 0x00;
+ switch (idx) {
+ case 0: /* Bits 0-7 */
+ break;
+ case 1: /* Bits 8-15 */
+ break;
+ case 2: /* Bits 16-23 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif /* CONFIG_WNM */
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+#endif /* CONFIG_INTERWORKING */
+ break;
+ case 4: /* Bits 32-39 */
#ifdef CONFIG_INTERWORKING
- if (wpa_s->conf->interworking)
- ext_capab |= BIT(31); /* Interworking */
+ if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING)
+ *pos |= 0x01; /* Bit 32 - QoS Map */
#endif /* CONFIG_INTERWORKING */
+ break;
+ case 5: /* Bits 40-47 */
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20)
+ *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_HS20 */
+ break;
+ case 6: /* Bits 48-55 */
+ break;
+ }
+}
-#ifdef CONFIG_WNM
- ext_capab |= BIT(17); /* WNM-Sleep Mode */
- ext_capab |= BIT(19); /* BSS Transition */
-#endif /* CONFIG_WNM */
- if (!ext_capab)
- return 0;
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
+{
+ u8 *pos = buf;
+ u8 len = 6, i;
+
+ if (len < wpa_s->extended_capa_len)
+ len = wpa_s->extended_capa_len;
+ if (buflen < (size_t) len + 2) {
+ wpa_printf(MSG_INFO,
+ "Not enough room for building extended capabilities element");
+ return -1;
+ }
*pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 4;
- WPA_PUT_LE32(pos, ext_capab);
- pos += 4;
+ *pos++ = len;
+ for (i = 0; i < len; i++, pos++) {
+ wpas_ext_capab_byte(wpa_s, pos, i);
+
+ if (i < wpa_s->extended_capa_len) {
+ *pos &= ~wpa_s->extended_capa_mask[i];
+ *pos |= wpa_s->extended_capa[i];
+ }
+ }
+
+ while (len > 0 && buf[1 + len] == 0) {
+ len--;
+ buf[1] = len;
+ }
+ if (len == 0)
+ return 0;
+
+ return 2 + len;
+}
+
+
+static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *test_bss)
+{
+ struct wpa_bss *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (bss == test_bss)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *test_ssid)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == test_ssid)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
+ struct wpa_ssid *test_ssid)
+{
+ if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
+ return 0;
+
+ return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
+}
+
+
+void wpas_connect_work_free(struct wpa_connect_work *cwork)
+{
+ if (cwork == NULL)
+ return;
+ os_free(cwork);
+}
+
+
+void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_connect_work *cwork;
+ struct wpa_radio_work *work = wpa_s->connect_work;
+
+ if (!work)
+ return;
+
+ wpa_s->connect_work = NULL;
+ cwork = work->ctx;
+ work->ctx = NULL;
+ wpas_connect_work_free(cwork);
+ radio_work_done(work);
+}
+
+
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
+{
+ struct os_reltime now;
+ u8 addr[ETH_ALEN];
+
+ os_get_reltime(&now);
+ if (wpa_s->last_mac_addr_style == style &&
+ wpa_s->last_mac_addr_change.sec != 0 &&
+ !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
+ wpa_s->conf->rand_addr_lifetime)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Previously selected random MAC address has not yet expired");
+ return 0;
+ }
+
+ switch (style) {
+ case 1:
+ if (random_mac_addr(addr) < 0)
+ return -1;
+ break;
+ case 2:
+ os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
+ if (random_mac_addr_keep_oui(addr) < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ return -1;
+ }
+
+ os_get_reltime(&wpa_s->last_mac_addr_change);
+ wpa_s->mac_addr_changed = 1;
+ wpa_s->last_mac_addr_style = style;
- return pos - buf;
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -1;
+ }
+
+ wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
+ MAC2STR(addr));
+
+ return 0;
}
+int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
+ !wpa_s->conf->preassoc_mac_addr)
+ return 0;
+
+ return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
+}
+
+
+static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
+
/**
* wpa_supplicant_associate - Request association
* @wpa_s: Pointer to wpa_supplicant data
@@ -1266,22 +1530,42 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
- u8 wpa_ie[200];
- size_t wpa_ie_len;
- int use_crypt, ret, i, bssid_changed;
- int algs = WPA_AUTH_ALG_OPEN;
- enum wpa_cipher cipher_pairwise, cipher_group;
- struct wpa_driver_associate_params params;
- int wep_keys_set = 0;
- struct wpa_driver_capa capa;
- int assoc_failed = 0;
- struct wpa_ssid *old_ssid;
- u8 ext_capab[10];
- int ext_capab_len;
-#ifdef CONFIG_HT_OVERRIDES
- struct ieee80211_ht_capabilities htcaps;
- struct ieee80211_ht_capabilities htcaps_mask;
-#endif /* CONFIG_HT_OVERRIDES */
+ struct wpa_connect_work *cwork;
+ int rand_style;
+
+ if (ssid->mac_addr == -1)
+ rand_style = wpa_s->conf->mac_addr;
+ else
+ rand_style = ssid->mac_addr;
+
+ wmm_ac_clear_saved_tspecs(wpa_s);
+ wpa_s->reassoc_same_bss = 0;
+
+ if (wpa_s->last_ssid == ssid) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+ if (wpa_s->current_bss && wpa_s->current_bss == bss) {
+ wmm_ac_save_tspecs(wpa_s);
+ wpa_s->reassoc_same_bss = 1;
+ }
+ } else if (rand_style > 0) {
+ 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) {
+ if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not restore permanent MAC address");
+ return;
+ }
+ wpa_s->mac_addr_changed = 0;
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
+ }
+ wpa_s->last_ssid = ssid;
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -1298,6 +1582,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+ wpas_p2p_ap_setup_failed(wpa_s);
return;
}
wpa_s->current_bss = bss;
@@ -1308,6 +1594,31 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
+ if (ssid->mode == WPAS_MODE_MESH) {
+#ifdef CONFIG_MESH
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Driver does not support mesh mode");
+ return;
+ }
+ if (bss)
+ ssid->frequency = bss->freq;
+ if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
+ 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);
+#else /* CONFIG_MESH */
+ wpa_msg(wpa_s, MSG_ERROR,
+ "mesh mode support not included in the build");
+#endif /* CONFIG_MESH */
+ return;
+ }
+
#ifdef CONFIG_TDLS
if (bss)
wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
@@ -1320,9 +1631,300 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
+ if (wpa_s->connect_work) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
+ return;
+ }
+
+ if (radio_work_pending(wpa_s, "connect")) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
+ return;
+ }
+
+ cwork = os_zalloc(sizeof(*cwork));
+ if (cwork == NULL)
+ return;
+
+ cwork->bss = bss;
+ cwork->ssid = ssid;
+
+ if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
+ wpas_start_assoc_cb, cwork) < 0) {
+ os_free(cwork);
+ }
+}
+
+
+static int bss_is_ibss(struct wpa_bss *bss)
+{
+ return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+ IEEE80211_CAP_IBSS;
+}
+
+
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_freq_params *freq)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+ 184, 192 };
+ int vht80[] = { 36, 52, 100, 116, 132, 149 };
+ 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;
+ struct hostapd_freq_params vht_freq;
+
+ freq->freq = ssid->frequency;
+
+ for (j = 0; j < wpa_s->last_scan_res_used; j++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[j];
+
+ if (ssid->mode != WPAS_MODE_IBSS)
+ break;
+
+ /* Don't adjust control freq in case of fixed_freq */
+ if (ssid->fixed_freq)
+ break;
+
+ if (!bss_is_ibss(bss))
+ continue;
+
+ if (ssid->ssid_len == bss->ssid_len &&
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "IBSS already found in scan results, adjust control freq: %d",
+ bss->freq);
+ freq->freq = bss->freq;
+ obss_scan = 0;
+ break;
+ }
+ }
+
+ /* For IBSS check HT_IBSS flag */
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
+ return;
+
+ if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
+ wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
+ wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
+ wpa_printf(MSG_DEBUG,
+ "IBSS: WEP/TKIP detected, do not try to enable HT");
+ return;
+ }
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+ 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;
+
+ freq->ht_enabled = ht_supported(mode);
+ if (!freq->ht_enabled)
+ return;
+
+ /* Setup higher BW only for 5 GHz */
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return;
+
+ for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
+ pri_chan = &mode->channels[chan_idx];
+ if (pri_chan->chan == channel)
+ break;
+ pri_chan = NULL;
+ }
+ if (!pri_chan)
+ return;
+
+ /* Check primary channel flags */
+ if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ return;
+
+ /* Check/setup HT40+/HT40- */
+ for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
+ if (ht40plus[j] == channel) {
+ ht40 = 1;
+ break;
+ }
+ }
+
+ /* Find secondary channel */
+ for (i = 0; i < mode->num_channels; i++) {
+ sec_chan = &mode->channels[i];
+ if (sec_chan->chan == channel + ht40 * 4)
+ break;
+ sec_chan = NULL;
+ }
+ if (!sec_chan)
+ return;
+
+ /* Check secondary channel flags */
+ if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ return;
+
+ freq->channel = pri_chan->chan;
+
+ switch (ht40) {
+ case -1:
+ if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
+ return;
+ freq->sec_channel_offset = -1;
+ break;
+ case 1:
+ if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
+ return;
+ freq->sec_channel_offset = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (freq->sec_channel_offset && obss_scan) {
+ struct wpa_scan_results *scan_res;
+
+ scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+ if (scan_res == NULL) {
+ /* Back to HT20 */
+ freq->sec_channel_offset = 0;
+ return;
+ }
+
+ res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
+ sec_chan->chan);
+ switch (res) {
+ case 0:
+ /* Back to HT20 */
+ freq->sec_channel_offset = 0;
+ break;
+ case 1:
+ /* Configuration allowed */
+ break;
+ case 2:
+ /* Switch pri/sec channels */
+ freq->freq = hw_get_freq(mode, sec_chan->chan);
+ freq->sec_channel_offset = -freq->sec_channel_offset;
+ freq->channel = sec_chan->chan;
+ break;
+ default:
+ freq->sec_channel_offset = 0;
+ break;
+ }
+
+ wpa_scan_results_free(scan_res);
+ }
+
+ 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)
+ return;
+
+ /* For IBSS check VHT_IBSS flag */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
+ return;
+
+ vht_freq = *freq;
+
+ vht_freq.vht_enabled = vht_supported(mode);
+ if (!vht_freq.vht_enabled)
+ return;
+
+ /* setup center_freq1, bandwidth */
+ for (j = 0; j < ARRAY_SIZE(vht80); j++) {
+ if (freq->channel >= vht80[j] &&
+ freq->channel < vht80[j] + 16)
+ break;
+ }
+
+ if (j == ARRAY_SIZE(vht80))
+ return;
+
+ for (i = vht80[j]; i < vht80[j] + 16; i += 4) {
+ struct hostapd_channel_data *chan;
+
+ chan = hw_get_channel_chan(mode, i, NULL);
+ if (!chan)
+ return;
+
+ /* Back to HT configuration if channel not usable */
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ return;
+ }
+
+ 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)
+ return;
+
+ *freq = vht_freq;
+
+ wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
+ freq->center_freq1, freq->center_freq2, freq->bandwidth);
+}
+
+
+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[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;
+
+ /* 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)) {
+ 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;
- if (bss && !wpas_driver_bss_selection(wpa_s)) {
+ 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 */
@@ -1350,6 +1952,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
(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);
@@ -1393,14 +1996,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
ssid->proactive_key_caching) &&
(ssid->proto & WPA_PROTO_RSN);
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
- wpa_s->current_ssid,
- try_opportunistic) == 0)
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ ssid, try_opportunistic) == 0)
+ eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
wpa_ie_len = sizeof(wpa_ie);
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;
}
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
@@ -1420,6 +2023,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
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;
}
#ifdef CONFIG_WPS
@@ -1472,37 +2076,70 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"disallows" : "allows");
}
}
+
+ os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20) {
+ if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
hs20 = wpabuf_alloc(20);
if (hs20) {
- wpas_hs20_add_indication(hs20);
- os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
- wpabuf_len(hs20));
- wpa_ie_len += wpabuf_len(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);
}
}
#endif /* CONFIG_HS20 */
- ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
- if (ext_capab_len > 0) {
- u8 *pos = wpa_ie;
- if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
- pos += 2 + pos[1];
- os_memmove(pos + ext_capab_len, pos,
- wpa_ie_len - (pos - wpa_ie));
- wpa_ie_len += ext_capab_len;
- os_memcpy(pos, ext_capab, ext_capab_len);
+ /*
+ * Workaround: Add Extended Capabilities element only if the AP
+ * included this element in Beacon/Probe Response frames. Some older
+ * APs seem to have interoperability issues if this element is
+ * included, so while the standard may require us to include the
+ * element in all cases, it is justifiable to skip it to avoid
+ * interoperability issues.
+ */
+ 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) {
+ u8 *pos = wpa_ie;
+ if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+ pos += 2 + pos[1];
+ os_memmove(pos + ext_capab_len, pos,
+ wpa_ie_len - (pos - wpa_ie));
+ wpa_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
+ }
+ }
+
+ 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;
+ if (wpabuf_len(buf) <= len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpa_ie_len += wpabuf_len(buf);
+ }
}
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
- cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
- cipher_group = cipher_suite2driver(wpa_s->group_cipher);
+ cipher_pairwise = wpa_s->pairwise_cipher;
+ cipher_group = wpa_s->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)
@@ -1526,7 +2163,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
/* Assume that dynamic WEP-104 keys will be used and
* set cipher suites in order for drivers to expect
* encryption. */
- cipher_pairwise = cipher_group = CIPHER_WEP104;
+ cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
}
}
#endif /* IEEE8021X_EAPOL */
@@ -1547,8 +2184,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
MAC2STR(bss->bssid), bss->freq,
ssid->bssid_set);
params.bssid = bss->bssid;
- params.freq = bss->freq;
+ params.freq.freq = bss->freq;
}
+ params.bssid_hint = bss->bssid;
+ params.freq_hint = bss->freq;
} else {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
@@ -1560,14 +2199,24 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.fixed_bssid = 1;
}
- if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
- params.freq == 0)
- params.freq = ssid->frequency; /* Initial channel for IBSS */
+ /* Initial frequency for IBSS/mesh */
+ if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
+ ssid->frequency > 0 && params.freq.freq == 0)
+ ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
+
+ if (ssid->mode == WPAS_MODE_IBSS) {
+ params.fixed_freq = ssid->fixed_freq;
+ if (ssid->beacon_int)
+ params.beacon_int = ssid->beacon_int;
+ else
+ 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.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+ params.key_mgmt_suite = wpa_s->key_mgmt;
params.wpa_proto = wpa_s->wpa_proto;
params.auth_alg = algs;
params.mode = ssid->mode;
@@ -1580,19 +2229,35 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
- (params.key_mgmt_suite == KEY_MGMT_PSK ||
- params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
+ (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
params.passphrase = ssid->passphrase;
if (ssid->psk_set)
params.psk = ssid->psk;
}
+ 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 ||
+ 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 =
+ ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc : ssid->proactive_key_caching;
+ else
+ params.req_key_mgmt_offload = 1;
+
+ if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
+ ssid->psk_set)
+ params.psk = ssid->psk;
+ }
+
params.drop_unencrypted = use_crypt;
#ifdef CONFIG_IEEE80211W
- params.mgmt_frame_protection =
- ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w;
+ params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data ie;
@@ -1621,6 +2286,35 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.htcaps_mask = (u8 *) &htcaps_mask;
wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ os_memset(&vhtcaps, 0, sizeof(vhtcaps));
+ os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
+ params.vhtcaps = &vhtcaps;
+ params.vhtcaps_mask = &vhtcaps_mask;
+ wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_VHT_OVERRIDES */
+
+#ifdef CONFIG_P2P
+ /*
+ * If multi-channel concurrency is not supported, check for any
+ * frequency conflict. In case of any frequency conflict, remove the
+ * least prioritized connection.
+ */
+ if (wpa_s->num_multichan_concurrent < 2) {
+ int freq, num;
+ num = get_shared_radio_freqs(wpa_s, &freq, 1);
+ if (num > 0 && freq > 0 && freq != params.freq.freq) {
+ wpa_printf(MSG_DEBUG,
+ "Assoc conflicting freq found (%d != %d)",
+ freq, params.freq.freq);
+ if (wpas_p2p_handle_frequency_conflicts(
+ wpa_s, params.freq.freq, ssid) < 0) {
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+ }
+ }
+#endif /* CONFIG_P2P */
ret = wpa_drv_associate(wpa_s, &params);
if (ret < 0) {
@@ -1674,8 +2368,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
- if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
- capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
+ if (wep_keys_set &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, ssid);
}
@@ -1702,6 +2396,7 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
{
struct wpa_ssid *old_ssid;
+ wpas_connect_work_done(wpa_s);
wpa_clear_keys(wpa_s, addr);
old_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s);
@@ -1750,6 +2445,18 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
zero_addr = 1;
}
+#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);
+ wpa_supplicant_leave_mesh(wpa_s);
+ }
+#endif /* CONFIG_MESH */
+
if (addr) {
wpa_drv_deauthenticate(wpa_s, addr, reason_code);
os_memset(&event, 0, sizeof(event));
@@ -1763,6 +2470,24 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
wpa_supplicant_clear_connection(wpa_s, addr);
}
+static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (!ssid || !ssid->disabled || ssid->disabled == 2)
+ return;
+
+ ssid->disabled = 0;
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
+ wpas_notify_network_enabled_changed(wpa_s, ssid);
+
+ /*
+ * Try to reassociate since there is no current configuration and a new
+ * network was made available.
+ */
+ if (!wpa_s->current_ssid && !wpa_s->disconnected)
+ wpa_s->reassociate = 1;
+}
+
/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
@@ -1774,48 +2499,21 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- struct wpa_ssid *other_ssid;
- int was_disabled;
-
if (ssid == NULL) {
- for (other_ssid = wpa_s->conf->ssid; other_ssid;
- other_ssid = other_ssid->next) {
- if (other_ssid->disabled == 2)
- continue; /* do not change persistent P2P group
- * data */
- if (other_ssid == wpa_s->current_ssid &&
- other_ssid->disabled)
- wpa_s->reassociate = 1;
-
- was_disabled = other_ssid->disabled;
-
- other_ssid->disabled = 0;
- if (was_disabled)
- wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+ wpa_supplicant_enable_one_network(wpa_s, ssid);
+ } else
+ wpa_supplicant_enable_one_network(wpa_s, ssid);
- if (was_disabled != other_ssid->disabled)
- wpas_notify_network_enabled_changed(
- wpa_s, other_ssid);
- }
- if (wpa_s->reassociate)
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (ssid->disabled && ssid->disabled != 2) {
- if (wpa_s->current_ssid == NULL) {
- /*
- * Try to reassociate since there is no current
- * configuration and a new network was made available.
- */
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->reassociate && !wpa_s->disconnected) {
+ if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
+ "new network to scan filters");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
}
- was_disabled = ssid->disabled;
-
- ssid->disabled = 0;
- wpas_clear_temp_disabled(wpa_s, ssid, 1);
-
- if (was_disabled != ssid->disabled)
- wpas_notify_network_enabled_changed(wpa_s, ssid);
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
}
}
@@ -1834,6 +2532,9 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
int was_disabled;
if (ssid == NULL) {
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
for (other_ssid = wpa_s->conf->ssid; other_ssid;
other_ssid = other_ssid->next) {
was_disabled = other_ssid->disabled;
@@ -1859,8 +2560,15 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
ssid->disabled = 1;
- if (was_disabled != ssid->disabled)
+ if (was_disabled != ssid->disabled) {
wpas_notify_network_enabled_changed(wpa_s, ssid);
+ if (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);
+ }
+ }
}
}
@@ -1878,6 +2586,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
int disconnected = 0;
if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
disconnected = 1;
@@ -1911,12 +2620,21 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
return;
}
- if (ssid)
+ if (ssid) {
wpa_s->current_ssid = ssid;
- wpa_s->connect_without_scan = NULL;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->connect_without_scan =
+ (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
+ } else {
+ wpa_s->connect_without_scan = NULL;
+ }
+
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
+
+ if (wpa_s->connect_without_scan ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
if (ssid)
wpas_notify_network_selected(wpa_s, ssid);
@@ -1924,6 +2642,59 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
/**
+ * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @pkcs11_engine_path: PKCS #11 engine path or NULL
+ * @pkcs11_module_path: PKCS #11 module path or NULL
+ * Returns: 0 on success; -1 on failure
+ *
+ * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid
+ * path. If resetting the EAPOL state machine with the new PKCS #11 engine and
+ * module path fails the paths will be reset to the default value (NULL).
+ */
+int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
+ const char *pkcs11_engine_path,
+ const char *pkcs11_module_path)
+{
+ char *pkcs11_engine_path_copy = NULL;
+ char *pkcs11_module_path_copy = NULL;
+
+ if (pkcs11_engine_path != NULL) {
+ pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path);
+ if (pkcs11_engine_path_copy == NULL)
+ return -1;
+ }
+ if (pkcs11_module_path != NULL) {
+ pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
+ if (pkcs11_module_path_copy == NULL) {
+ os_free(pkcs11_engine_path_copy);
+ return -1;
+ }
+ }
+
+ os_free(wpa_s->conf->pkcs11_engine_path);
+ os_free(wpa_s->conf->pkcs11_module_path);
+ wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy;
+ wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy;
+
+ wpa_sm_set_eapol(wpa_s->wpa, NULL);
+ eapol_sm_deinit(wpa_s->eapol);
+ wpa_s->eapol = NULL;
+ if (wpa_supplicant_init_eapol(wpa_s)) {
+ /* Error -> Reset paths to the default value (NULL) once. */
+ if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL)
+ wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL,
+ NULL);
+
+ return -1;
+ }
+ wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
+
+ return 0;
+}
+
+
+/**
* wpa_supplicant_set_ap_scan - Set AP scan mode for interface
* @wpa_s: wpa_supplicant structure for a network interface
* @ap_scan: AP scan mode
@@ -2021,7 +2792,7 @@ int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
}
wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
scan_interval);
- wpa_s->scan_interval = scan_interval;
+ wpa_supplicant_update_scan_int(wpa_s, scan_interval);
return 0;
}
@@ -2217,6 +2988,16 @@ 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");
+ return;
+ }
+#endif /* CONFIG_PEERKEY */
+
if (wpa_s->wpa_state < WPA_ASSOCIATED ||
(wpa_s->last_eapol_matches_bssid &&
#ifdef CONFIG_AP
@@ -2242,7 +3023,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
if (wpa_s->pending_eapol_rx) {
- os_get_time(&wpa_s->pending_eapol_rx_time);
+ os_get_reltime(&wpa_s->pending_eapol_rx_time);
os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
ETH_ALEN);
}
@@ -2322,12 +3103,9 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->driver->send_eapol) {
- const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
- if (addr)
- os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
- } else if (!(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+ if ((!wpa_s->p2p_mgmt ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
@@ -2346,8 +3124,6 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
return -1;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
- MAC2STR(wpa_s->own_addr));
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
return 0;
@@ -2395,14 +3171,17 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
return -1;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
+ MAC2STR(wpa_s->own_addr));
+ os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
+ wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
if (wpa_s->bridge_ifname[0]) {
wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
"interface '%s'", wpa_s->bridge_ifname);
- wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
- wpa_s->own_addr,
- ETH_P_EAPOL,
- wpa_supplicant_rx_eapol_bridge,
- wpa_s, 1);
+ wpa_s->l2_br = l2_packet_init_bridge(
+ wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+ ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
if (wpa_s->l2_br == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
"connection for the bridge interface '%s'",
@@ -2424,10 +3203,18 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
wpa_s->prev_scan_wildcard = 0;
if (wpa_supplicant_enabled_networks(wpa_s)) {
- if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ interface_count = 0;
+ }
+#ifndef ANDROID
+ if (!wpa_s->p2p_mgmt &&
+ wpa_supplicant_delayed_sched_scan(wpa_s,
+ interface_count % 3,
100000))
- wpa_supplicant_req_scan(wpa_s, interface_count,
+ wpa_supplicant_req_scan(wpa_s, interface_count % 3,
100000);
+#endif /* ANDROID */
interface_count++;
} else
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -2443,7 +3230,8 @@ static int wpa_supplicant_daemon(const char *pid_file)
}
-static struct wpa_supplicant * wpa_supplicant_alloc(void)
+static struct wpa_supplicant *
+wpa_supplicant_alloc(struct wpa_supplicant *parent)
{
struct wpa_supplicant *wpa_s;
@@ -2453,7 +3241,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
wpa_s->scan_req = INITIAL_SCAN_REQ;
wpa_s->scan_interval = 5;
wpa_s->new_connection = 1;
- wpa_s->parent = wpa_s;
+ wpa_s->parent = parent ? parent : wpa_s;
wpa_s->sched_scanning = 0;
return wpa_s;
@@ -2521,7 +3309,7 @@ static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
struct ieee80211_ht_capabilities *htcaps_mask,
int disabled)
{
- u16 msk;
+ le16 msk;
wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
@@ -2594,8 +3382,8 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
int disabled)
{
/* Masking these out disables HT40 */
- u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
- HT_CAP_INFO_SHORT_GI40MHZ);
+ 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);
@@ -2616,8 +3404,8 @@ static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
int disabled)
{
/* Masking these out disables SGI */
- u16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
- HT_CAP_INFO_SHORT_GI40MHZ);
+ 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);
@@ -2632,6 +3420,27 @@ static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
}
+static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ /* 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)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ htcaps_mask->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params)
@@ -2655,11 +3464,83 @@ void wpa_supplicant_apply_ht_overrides(
wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
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);
+
+ if (ssid->ht40_intolerant) {
+ le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
+ htcaps->ht_capabilities_info |= bit;
+ htcaps_mask->ht_capabilities_info |= bit;
+ }
}
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+void wpa_supplicant_apply_vht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ struct ieee80211_vht_capabilities *vhtcaps;
+ struct ieee80211_vht_capabilities *vhtcaps_mask;
+
+ if (!ssid)
+ return;
+
+ params->disable_vht = ssid->disable_vht;
+
+ vhtcaps = (void *) params->vhtcaps;
+ vhtcaps_mask = (void *) params->vhtcaps_mask;
+
+ if (!vhtcaps || !vhtcaps_mask)
+ return;
+
+ vhtcaps->vht_capabilities_info = ssid->vht_capa;
+ vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+
+#ifdef CONFIG_HT_OVERRIDES
+ /* 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;
+
+ max_ampdu = (ssid->vht_capa &
+ VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
+ VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
+
+ max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
+ wpa_set_ampdu_factor(wpa_s,
+ (void *) params->htcaps,
+ (void *) params->htcaps_mask,
+ max_ampdu);
+ }
+#endif /* CONFIG_HT_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); \
+ vhtcaps->vht_supported_mcs_set.tx_map |= \
+ 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); \
+ vhtcaps->vht_supported_mcs_set.rx_map |= \
+ ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \
+ }
+
+ OVERRIDE_MCS(1);
+ OVERRIDE_MCS(2);
+ OVERRIDE_MCS(3);
+ OVERRIDE_MCS(4);
+ OVERRIDE_MCS(5);
+ OVERRIDE_MCS(6);
+ OVERRIDE_MCS(7);
+ OVERRIDE_MCS(8);
+}
+#endif /* CONFIG_VHT_OVERRIDES */
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -2668,7 +3549,7 @@ static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
if (!wpa_s->conf->pcsc_reader)
return 0;
- wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+ wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
if (!wpa_s->scard)
return 1;
@@ -2734,11 +3615,337 @@ int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
}
+static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
+ const struct wpa_driver_capa *capa)
+{
+ struct wowlan_triggers *triggers;
+ int ret = 0;
+
+ if (!wpa_s->conf->wowlan_triggers)
+ return 0;
+
+ triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa);
+ if (triggers) {
+ ret = wpa_drv_wowlan(wpa_s, triggers);
+ os_free(triggers);
+ }
+ return ret;
+}
+
+
+static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
+ const char *rn)
+{
+ struct wpa_supplicant *iface = wpa_s->global->ifaces;
+ struct wpa_radio *radio;
+
+ while (rn && iface) {
+ radio = iface->radio;
+ if (radio && os_strcmp(rn, radio->name) == 0) {
+ wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s",
+ wpa_s->ifname, rn);
+ dl_list_add(&radio->ifaces, &wpa_s->radio_list);
+ return radio;
+ }
+
+ iface = iface->next;
+ }
+
+ wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s",
+ wpa_s->ifname, rn ? rn : "N/A");
+ radio = os_zalloc(sizeof(*radio));
+ if (radio == NULL)
+ return NULL;
+
+ if (rn)
+ os_strlcpy(radio->name, rn, sizeof(radio->name));
+ dl_list_init(&radio->ifaces);
+ dl_list_init(&radio->work);
+ dl_list_add(&radio->ifaces, &wpa_s->radio_list);
+
+ return radio;
+}
+
+
+static void radio_work_free(struct wpa_radio_work *work)
+{
+ if (work->wpa_s->scan_work == work) {
+ /* This should not really happen. */
+ wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
+ work->type, work, work->started);
+ work->wpa_s->scan_work = NULL;
+ }
+
+#ifdef CONFIG_P2P
+ if (work->wpa_s->p2p_scan_work == work) {
+ /* This should not really happen. */
+ wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
+ work->type, work, work->started);
+ work->wpa_s->p2p_scan_work = NULL;
+ }
+#endif /* CONFIG_P2P */
+
+ dl_list_del(&work->list);
+ os_free(work);
+}
+
+
+static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_radio *radio = eloop_ctx;
+ struct wpa_radio_work *work;
+ struct os_reltime now, diff;
+ struct wpa_supplicant *wpa_s;
+
+ work = dl_list_first(&radio->work, struct wpa_radio_work, list);
+ if (work == NULL)
+ 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;
+ }
+
+ 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",
+ work->type, work, diff.sec, diff.usec);
+ work->started = 1;
+ work->time = now;
+ work->cb(work, 0);
+}
+
+
+/*
+ * This function removes both started and pending radio works running on
+ * the provided interface's radio.
+ * Prior to the removal of the radio work, its callback (cb) is called with
+ * deinit set to be 1. Each work's callback is responsible for clearing its
+ * internal data and restoring to a correct state.
+ * @wpa_s: wpa_supplicant data
+ * @type: type of works to be removed
+ * @remove_all: 1 to remove all the works on this radio, 0 to remove only
+ * this interface's works.
+ */
+void radio_remove_works(struct wpa_supplicant *wpa_s,
+ const char *type, int remove_all)
+{
+ struct wpa_radio_work *work, *tmp;
+ struct wpa_radio *radio = wpa_s->radio;
+
+ dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
+ list) {
+ if (type && os_strcmp(type, work->type) != 0)
+ continue;
+
+ /* skip other ifaces' works */
+ if (!remove_all && work->wpa_s != wpa_s)
+ continue;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
+ work->type, work, work->started ? " (started)" : "");
+ work->cb(work, 1);
+ radio_work_free(work);
+ }
+
+ /* in case we removed the started work */
+ radio_work_check_next(wpa_s);
+}
+
+
+static void radio_remove_interface(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio *radio = wpa_s->radio;
+
+ if (!radio)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
+ wpa_s->ifname, radio->name);
+ dl_list_del(&wpa_s->radio_list);
+ radio_remove_works(wpa_s, NULL, 0);
+ wpa_s->radio = NULL;
+ if (!dl_list_empty(&radio->ifaces))
+ return; /* Interfaces remain for this radio */
+
+ wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
+ eloop_cancel_timeout(radio_start_next_work, radio, NULL);
+ os_free(radio);
+}
+
+
+void radio_work_check_next(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio *radio = wpa_s->radio;
+
+ if (dl_list_empty(&radio->work))
+ return;
+ if (wpa_s->ext_work_in_progress) {
+ wpa_printf(MSG_DEBUG,
+ "External radio work in progress - delay start of pending item");
+ return;
+ }
+ eloop_cancel_timeout(radio_start_next_work, radio, NULL);
+ eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
+}
+
+
+/**
+ * radio_add_work - Add a radio work item
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency of the offchannel operation in MHz or 0
+ * @type: Unique identifier for each type of work
+ * @next: Force as the next work to be executed
+ * @cb: Callback function for indicating when radio is available
+ * @ctx: Context pointer for the work (work->ctx in cb())
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to request time for an operation that requires
+ * exclusive radio control. Once the radio is available, the registered callback
+ * function will be called. radio_work_done() must be called once the exclusive
+ * radio operation has been completed, so that the radio is freed for other
+ * operations. The special case of deinit=1 is used to free the context data
+ * during interface removal. That does not allow the callback function to start
+ * the radio operation, i.e., it must free any resources allocated for the radio
+ * work and return.
+ *
+ * The @freq parameter can be used to indicate a single channel on which the
+ * offchannel operation will occur. This may allow multiple radio work
+ * operations to be performed in parallel if they apply for the same channel.
+ * Setting this to 0 indicates that the work item may use multiple channels or
+ * requires exclusive control of the radio.
+ */
+int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
+ const char *type, int next,
+ void (*cb)(struct wpa_radio_work *work, int deinit),
+ void *ctx)
+{
+ struct wpa_radio_work *work;
+ int was_empty;
+
+ work = os_zalloc(sizeof(*work));
+ if (work == NULL)
+ return -1;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
+ os_get_reltime(&work->time);
+ work->freq = freq;
+ work->type = type;
+ work->wpa_s = wpa_s;
+ work->cb = cb;
+ work->ctx = ctx;
+
+ was_empty = dl_list_empty(&wpa_s->radio->work);
+ if (next)
+ dl_list_add(&wpa_s->radio->work, &work->list);
+ else
+ dl_list_add_tail(&wpa_s->radio->work, &work->list);
+ 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);
+ }
+
+ return 0;
+}
+
+
+/**
+ * radio_work_done - Indicate that a radio work item has been completed
+ * @work: Completed work
+ *
+ * This function is called once the callback function registered with
+ * radio_add_work() has completed its work.
+ */
+void radio_work_done(struct wpa_radio_work *work)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct os_reltime now, diff;
+ unsigned int started = work->started;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &work->time, &diff);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
+ work->type, work, started ? "done" : "canceled",
+ diff.sec, diff.usec);
+ radio_work_free(work);
+ if (started)
+ radio_work_check_next(wpa_s);
+}
+
+
+struct wpa_radio_work *
+radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
+{
+ 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 && os_strcmp(work->type, type) == 0)
+ return work;
+ }
+
+ return NULL;
+}
+
+
+static int wpas_init_driver(struct wpa_supplicant *wpa_s,
+ struct wpa_interface *iface)
+{
+ const char *ifname, *driver, *rn;
+
+ driver = iface->driver;
+next_driver:
+ if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+ return -1;
+
+ wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
+ if (wpa_s->drv_priv == NULL) {
+ const char *pos;
+ pos = driver ? os_strchr(driver, ',') : NULL;
+ if (pos) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+ "driver interface - try next driver wrapper");
+ driver = pos + 1;
+ goto next_driver;
+ }
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
+ "interface");
+ return -1;
+ }
+ if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
+ "driver_param '%s'", wpa_s->conf->driver_param);
+ return -1;
+ }
+
+ ifname = wpa_drv_get_ifname(wpa_s);
+ if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
+ "interface name with '%s'", ifname);
+ os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+ }
+
+ rn = wpa_driver_get_radio_name(wpa_s);
+ if (rn && rn[0] == '\0')
+ rn = NULL;
+
+ wpa_s->radio = radio_add_interface(wpa_s, rn);
+ if (wpa_s->radio == NULL)
+ return -1;
+
+ return 0;
+}
+
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
- const char *ifname, *driver;
struct wpa_driver_capa capa;
+ int capa_res;
wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
"'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
@@ -2761,12 +3968,14 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
#else /* CONFIG_BACKEND_FILE */
wpa_s->confname = os_strdup(iface->confname);
#endif /* CONFIG_BACKEND_FILE */
- wpa_s->conf = wpa_config_read(wpa_s->confname);
+ wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR, "Failed to read or parse "
"configuration '%s'.", wpa_s->confname);
return -1;
}
+ wpa_s->confanother = os_rel2abs_path(iface->confanother);
+ wpa_config_read(wpa_s->confanother, wpa_s->conf);
/*
* Override ctrl_interface and driver_param if set on command
@@ -2783,6 +3992,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->conf->driver_param =
os_strdup(iface->driver_param);
}
+
+ if (iface->p2p_mgmt && !iface->ctrl_interface) {
+ os_free(wpa_s->conf->ctrl_interface);
+ wpa_s->conf->ctrl_interface = NULL;
+ }
} else
wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
iface->driver_param);
@@ -2822,37 +4036,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
* L2 receive handler so that association events are processed before
* EAPOL-Key packets if both become available for the same select()
* call. */
- driver = iface->driver;
-next_driver:
- if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
- return -1;
-
- wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
- if (wpa_s->drv_priv == NULL) {
- const char *pos;
- pos = driver ? os_strchr(driver, ',') : NULL;
- if (pos) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
- "driver interface - try next driver wrapper");
- driver = pos + 1;
- goto next_driver;
- }
- wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
- "interface");
+ if (wpas_init_driver(wpa_s, iface) < 0)
return -1;
- }
- if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
- wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
- "driver_param '%s'", wpa_s->conf->driver_param);
- return -1;
- }
-
- ifname = wpa_drv_get_ifname(wpa_s);
- if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
- "interface name with '%s'", ifname);
- os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
- }
if (wpa_supplicant_init_wpa(wpa_s) < 0)
return -1;
@@ -2889,11 +4074,31 @@ next_driver:
wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
&wpa_s->hw.num_modes,
&wpa_s->hw.flags);
+ if (wpa_s->hw.modes) {
+ u16 i;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].vht_capab) {
+ wpa_s->hw_capab = CAPAB_VHT;
+ break;
+ }
- if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+ if (wpa_s->hw.modes[i].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
+ wpa_s->hw_capab = CAPAB_HT40;
+ else if (wpa_s->hw.modes[i].ht_capab &&
+ wpa_s->hw_capab == CAPAB_NO_HT_VHT)
+ wpa_s->hw_capab = CAPAB_HT;
+ }
+ }
+
+ capa_res = wpa_drv_get_capa(wpa_s, &capa);
+ if (capa_res == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
wpa_s->drv_enc = capa.enc;
+ wpa_s->drv_smps_modes = capa.smps_modes;
+ wpa_s->drv_rrm_flags = capa.rrm_flags;
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;
@@ -2901,15 +4106,44 @@ next_driver:
wpa_s->max_match_sets = capa.max_match_sets;
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
wpa_s->max_stations = capa.max_stations;
+ wpa_s->extended_capa = capa.extended_capa;
+ wpa_s->extended_capa_mask = capa.extended_capa_mask;
+ wpa_s->extended_capa_len = capa.extended_capa_len;
+ wpa_s->num_multichan_concurrent =
+ capa.num_multichan_concurrent;
+ wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
+
+ if (capa.mac_addr_rand_scan_supported)
+ wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
+ if (wpa_s->sched_scan_supported &&
+ capa.mac_addr_rand_sched_scan_supported)
+ wpa_s->mac_addr_rand_supported |=
+ (MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
+ /*
+ * Only take p2p_mgmt parameters when P2P Device is supported.
+ * Doing it here as it determines whether l2_packet_init() will be done
+ * during wpa_supplicant_driver_init().
+ */
+ 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;
+
if (wpa_supplicant_driver_init(wpa_s) < 0)
return -1;
#ifdef CONFIG_TDLS
- if (wpa_tdls_init(wpa_s->wpa))
+ if ((!iface->p2p_mgmt ||
+ !(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+ wpa_tdls_init(wpa_s->wpa))
return -1;
#endif /* CONFIG_TDLS */
@@ -2946,22 +4180,45 @@ next_driver:
return -1;
}
-#ifdef CONFIG_P2P
- if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+ if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
return -1;
}
-#endif /* CONFIG_P2P */
if (wpa_bss_init(wpa_s) < 0)
return -1;
+ /*
+ * Set Wake-on-WLAN triggers, if configured.
+ * Note: We don't restore/remove the triggers on shutdown (it doesn't
+ * have effect anyway when the interface is down).
+ */
+ if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
+ return -1;
+
+#ifdef CONFIG_EAP_PROXY
+{
+ size_t len;
+ wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, 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)",
+ wpa_s->imsi, wpa_s->mnc_len);
+ } else {
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+ }
+}
+#endif /* CONFIG_EAP_PROXY */
+
if (pcsc_reader_init(wpa_s) < 0)
return -1;
if (wpas_init_ext_pw(wpa_s) < 0)
return -1;
+ wpas_rrm_reset(wpa_s);
+
return 0;
}
@@ -2969,6 +4226,27 @@ next_driver:
static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
int notify, int terminate)
{
+ struct wpa_global *global = wpa_s->global;
+ struct wpa_supplicant *iface, *prev;
+
+ if (wpa_s == wpa_s->parent)
+ wpas_p2p_group_remove(wpa_s, "*");
+
+ iface = global->ifaces;
+ while (iface) {
+ if (iface == wpa_s || iface->parent != wpa_s) {
+ iface = iface->next;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG,
+ "Remove remaining child interface %s from parent %s",
+ iface->ifname, wpa_s->ifname);
+ prev = iface;
+ iface = iface->next;
+ wpa_supplicant_remove_iface(global, prev, terminate);
+ }
+
+ wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
@@ -2978,14 +4256,10 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
wpa_supplicant_cleanup(wpa_s);
+ wpas_p2p_deinit_iface(wpa_s);
-#ifdef CONFIG_P2P
- if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
- "the management interface is being removed");
- wpas_p2p_deinit_global(wpa_s->global);
- }
-#endif /* CONFIG_P2P */
+ wpas_ctrl_radio_work_flush(wpa_s);
+ radio_remove_interface(wpa_s);
if (wpa_s->drv_priv)
wpa_drv_deinit(wpa_s);
@@ -3001,10 +4275,19 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
wpa_s->ctrl_iface = NULL;
}
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_s->ifmsh = NULL;
+ }
+#endif /* CONFIG_MESH */
+
if (wpa_s->conf != NULL) {
wpa_config_free(wpa_s->conf);
wpa_s->conf = NULL;
}
+
+ os_free(wpa_s);
}
@@ -3012,6 +4295,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
* wpa_supplicant_add_iface - Add a new network interface
* @global: Pointer to global data from wpa_supplicant_init()
* @iface: Interface configuration options
+ * @parent: Parent interface or %NULL to assign new interface as parent
* Returns: Pointer to the created interface or %NULL on failure
*
* This function is used to add new network interfaces for %wpa_supplicant.
@@ -3021,7 +4305,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
* e.g., when a hotplug network adapter is inserted.
*/
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
- struct wpa_interface *iface)
+ struct wpa_interface *iface,
+ struct wpa_supplicant *parent)
{
struct wpa_supplicant *wpa_s;
struct wpa_interface t_iface;
@@ -3030,7 +4315,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
if (global == NULL || iface == NULL)
return NULL;
- wpa_s = wpa_supplicant_alloc();
+ wpa_s = wpa_supplicant_alloc(parent);
if (wpa_s == NULL)
return NULL;
@@ -3055,19 +4340,19 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
wpa_printf(MSG_DEBUG, "Failed to add interface %s",
iface->ifname);
wpa_supplicant_deinit_iface(wpa_s, 0, 0);
- os_free(wpa_s);
return NULL;
}
- /* Notify the control interfaces about new iface */
- if (wpas_notify_iface_added(wpa_s)) {
- wpa_supplicant_deinit_iface(wpa_s, 1, 0);
- os_free(wpa_s);
- return NULL;
- }
+ if (iface->p2p_mgmt == 0) {
+ /* Notify the control interfaces about new iface */
+ if (wpas_notify_iface_added(wpa_s)) {
+ wpa_supplicant_deinit_iface(wpa_s, 1, 0);
+ return NULL;
+ }
- for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
- wpas_notify_network_added(wpa_s, ssid);
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+ wpas_notify_network_added(wpa_s, ssid);
+ }
wpa_s->next = global->ifaces;
global->ifaces = wpa_s;
@@ -3075,6 +4360,16 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+#ifdef CONFIG_P2P
+ if (wpa_s->global->p2p == NULL &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+ wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) < 0) {
+ wpa_printf(MSG_INFO,
+ "P2P: Failed to enable P2P Device interface");
+ /* Try to continue without. P2P will be disabled. */
+ }
+#endif /* CONFIG_P2P */
+
return wpa_s;
}
@@ -3095,6 +4390,10 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
int terminate)
{
struct wpa_supplicant *prev;
+#ifdef CONFIG_MESH
+ unsigned int mesh_if_created = wpa_s->mesh_if_created;
+ char *ifname = NULL;
+#endif /* CONFIG_MESH */
/* Remove interface from the global list of interfaces */
prev = global->ifaces;
@@ -3110,10 +4409,29 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
+#ifdef CONFIG_MESH
+ if (mesh_if_created) {
+ ifname = os_strdup(wpa_s->ifname);
+ if (ifname == NULL) {
+ wpa_dbg(wpa_s, MSG_ERROR,
+ "mesh: Failed to malloc ifname");
+ return -1;
+ }
+ }
+#endif /* CONFIG_MESH */
+
if (global->p2p_group_formation == wpa_s)
global->p2p_group_formation = NULL;
+ if (global->p2p_invite_group == wpa_s)
+ global->p2p_invite_group = NULL;
wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
- os_free(wpa_s);
+
+#ifdef CONFIG_MESH
+ if (mesh_if_created) {
+ wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+ os_free(ifname);
+ }
+#endif /* CONFIG_MESH */
return 0;
}
@@ -3199,7 +4517,10 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
#endif /* CONFIG_NO_WPA_MSG */
- wpa_debug_open_file(params->wpa_debug_file_path);
+ if (params->wpa_debug_file_path)
+ wpa_debug_open_file(params->wpa_debug_file_path);
+ else
+ wpa_debug_setup_stdout();
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
if (params->wpa_debug_tracing) {
@@ -3233,6 +4554,9 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->ctrl_interface)
global->params.ctrl_interface =
os_strdup(params->ctrl_interface);
+ if (params->ctrl_interface_group)
+ global->params.ctrl_interface_group =
+ os_strdup(params->ctrl_interface_group);
if (params->override_driver)
global->params.override_driver =
os_strdup(params->override_driver);
@@ -3274,7 +4598,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
wpa_supplicant_deinit(global);
return NULL;
}
- global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+ global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
if (global->drv_priv == NULL) {
wpa_supplicant_deinit(global);
return NULL;
@@ -3342,9 +4666,6 @@ void wpa_supplicant_deinit(struct wpa_global *global)
#ifdef CONFIG_WIFI_DISPLAY
wifi_display_deinit(global);
#endif /* CONFIG_WIFI_DISPLAY */
-#ifdef CONFIG_P2P
- wpas_p2p_deinit_global(global);
-#endif /* CONFIG_P2P */
while (global->ifaces)
wpa_supplicant_remove_iface(global, global->ifaces, 1);
@@ -3375,10 +4696,13 @@ void wpa_supplicant_deinit(struct wpa_global *global)
os_free(global->params.pid_file);
}
os_free(global->params.ctrl_interface);
+ os_free(global->params.ctrl_interface_group);
os_free(global->params.override_driver);
os_free(global->params.override_ctrl_interface);
- os_free(global->p2p_disallow_freq);
+ os_free(global->p2p_disallow_freq.range);
+ os_free(global->p2p_go_avoid_freq.range);
+ os_free(global->add_psk);
os_free(global);
wpa_debug_close_syslog();
@@ -3407,16 +4731,12 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_P2P
wpas_p2p_update_config(wpa_s);
-#endif /* CONFIG_P2P */
-
wpa_s->conf->changed_parameters = 0;
}
-static void add_freq(int *freqs, int *num_freqs, int freq)
+void add_freq(int *freqs, int *num_freqs, int freq)
{
int i;
@@ -3437,7 +4757,7 @@ static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
int *freqs;
int num_freqs = 0;
- freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+ freqs = os_calloc(max_freqs + 1, sizeof(int));
if (freqs == NULL)
return NULL;
@@ -3470,12 +4790,31 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
int count;
int *freqs = NULL;
+ wpas_connect_work_done(wpa_s);
+
/*
* Remove possible authentication timeout since the connection failed.
*/
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
/*
+ * There is no point in blacklisting the AP if this event is
+ * generated based on local request to disconnect.
+ */
+ if (wpa_s->own_disconnect_req) {
+ wpa_s->own_disconnect_req = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore connection failure due to local request to disconnect");
+ return;
+ }
+ if (wpa_s->disconnected) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
+ "indication since interface has been put into "
+ "disconnected state");
+ return;
+ }
+
+ /*
* Add the failed BSSID into the blacklist and speed up next scan
* attempt if there could be other APs that could accept association.
* The current blacklist count indicates how many times we have tried
@@ -3512,6 +4851,12 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
*/
count += wpa_s->extra_blacklist_count;
+ if (count > 3 && wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG, "Continuous association failures - "
+ "consider temporary network disabling");
+ wpas_auth_failed(wpa_s, "CONN_FAILED");
+ }
+
switch (count) {
case 1:
timeout = 100;
@@ -3539,17 +4884,6 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
*/
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
-
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after failed association");
- }
- }
-#endif /* CONFIG_P2P */
}
@@ -3583,7 +4917,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PASSWORD:
- os_free(eap->password);
+ bin_clear_free(eap->password, eap->password_len);
eap->password = (u8 *) os_strdup(value);
eap->password_len = os_strlen(value);
eap->pending_req_password = 0;
@@ -3591,7 +4925,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
- os_free(eap->new_password);
+ bin_clear_free(eap->new_password, eap->new_password_len);
eap->new_password = (u8 *) os_strdup(value);
eap->new_password_len = os_strlen(value);
eap->pending_req_new_password = 0;
@@ -3599,14 +4933,14 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PIN:
- os_free(eap->pin);
+ str_clear_free(eap->pin);
eap->pin = os_strdup(value);
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_OTP:
- os_free(eap->otp);
+ bin_clear_free(eap->otp, eap->otp_len);
eap->otp = (u8 *) os_strdup(value);
eap->otp_len = os_strlen(value);
os_free(eap->pending_req_otp);
@@ -3614,12 +4948,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
eap->pending_req_otp_len = 0;
break;
case WPA_CTRL_REQ_EAP_PASSPHRASE:
- os_free(eap->private_key_passwd);
- eap->private_key_passwd = (u8 *) os_strdup(value);
+ str_clear_free(eap->private_key_passwd);
+ eap->private_key_passwd = os_strdup(value);
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
break;
+ case WPA_CTRL_REQ_SIM:
+ str_clear_free(eap->external_sim_resp);
+ eap->external_sim_resp = os_strdup(value);
+ break;
default:
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
return -1;
@@ -3639,13 +4977,16 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
int i;
unsigned int drv_enc;
+ if (wpa_s->p2p_mgmt)
+ return 1; /* no normal network profiles on p2p_mgmt interface */
+
if (ssid == NULL)
return 1;
if (ssid->disabled)
return 1;
- if (wpa_s && wpa_s->drv_capa_known)
+ if (wpa_s->drv_capa_known)
drv_enc = wpa_s->drv_enc;
else
drv_enc = (unsigned int) -1;
@@ -3664,13 +5005,37 @@ 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->ext_psk)
+ (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk)
return 1;
return 0;
}
+int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_IEEE80211W
+ if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+ if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
+ !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
+ /*
+ * Driver does not support BIP -- ignore pmf=1 default
+ * since the connection with PMF would fail and the
+ * configuration does not require PMF to be enabled.
+ */
+ return NO_MGMT_FRAME_PROTECTION;
+ }
+
+ return wpa_s->conf->pmf;
+ }
+
+ return ssid->ieee80211w;
+#else /* CONFIG_IEEE80211W */
+ return NO_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
{
if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
@@ -3681,11 +5046,11 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
}
-void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
int dur;
- struct os_time now;
+ struct os_reltime now;
if (ssid == NULL) {
wpa_printf(MSG_DEBUG, "Authentication failure but no known "
@@ -3697,29 +5062,47 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s)
return;
ssid->auth_failures++;
+
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group &&
+ (wpa_s->p2p_in_provisioning || wpa_s->show_group_started)) {
+ /*
+ * Skip the wait time since there is a short timeout on the
+ * connection to a P2P group.
+ */
+ return;
+ }
+#endif /* CONFIG_P2P */
+
if (ssid->auth_failures > 50)
dur = 300;
- else if (ssid->auth_failures > 20)
- dur = 120;
else if (ssid->auth_failures > 10)
- dur = 60;
+ dur = 120;
else if (ssid->auth_failures > 5)
+ dur = 90;
+ else if (ssid->auth_failures > 3)
+ dur = 60;
+ else if (ssid->auth_failures > 2)
dur = 30;
else if (ssid->auth_failures > 1)
dur = 20;
else
dur = 10;
- os_get_time(&now);
+ if (ssid->auth_failures > 1 &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt))
+ dur += os_random() % (ssid->auth_failures * 10);
+
+ os_get_reltime(&now);
if (now.sec + dur <= ssid->disabled_until.sec)
return;
ssid->disabled_until.sec = now.sec + dur;
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
- "id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+ "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->auth_failures, dur);
+ ssid->auth_failures, dur, reason);
}
@@ -3788,9 +5171,375 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
void wpas_request_connection(struct wpa_supplicant *wpa_s)
{
wpa_s->normal_scans = 0;
+ wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_reinit_autoscan(wpa_s);
wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ else
+ wpa_s->reattach = 0;
+}
+
+
+void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
+ struct wpa_used_freq_data *freqs_data,
+ unsigned int len)
+{
+ unsigned int i;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
+ len, title);
+ for (i = 0; i < len; i++) {
+ struct wpa_used_freq_data *cur = &freqs_data[i];
+ wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d, flags=0x%X",
+ i, cur->freq, cur->flags);
+ }
+}
+
+
+/*
+ * Find the operating frequencies of any of the virtual interfaces that
+ * are using the same radio as the current interface, and in addition, get
+ * information about the interface types that are using the frequency.
+ */
+int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs_data,
+ unsigned int len)
+{
+ struct wpa_supplicant *ifs;
+ u8 bssid[ETH_ALEN];
+ int freq;
+ unsigned int idx = 0, i;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Determining shared radio frequencies (max len %u)", len);
+ os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len);
+
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (idx == len)
+ break;
+
+ if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+ continue;
+
+ if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+ ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+ freq = ifs->current_ssid->frequency;
+ else if (wpa_drv_get_bssid(ifs, bssid) == 0)
+ freq = ifs->assoc_freq;
+ else
+ continue;
+
+ /* Hold only distinct freqs */
+ for (i = 0; i < idx; i++)
+ if (freqs_data[i].freq == freq)
+ break;
+
+ if (i == idx)
+ freqs_data[idx++].freq = freq;
+
+ if (ifs->current_ssid->mode == WPAS_MODE_INFRA) {
+ freqs_data[i].flags = ifs->current_ssid->p2p_group ?
+ WPA_FREQ_USED_BY_P2P_CLIENT :
+ WPA_FREQ_USED_BY_INFRA_STATION;
+ }
+ }
+
+ dump_freq_data(wpa_s, "completed iteration", freqs_data, idx);
+ return idx;
+}
+
+
+/*
+ * Find the operating frequencies of any of the virtual interfaces that
+ * are using the same radio as the current interface.
+ */
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+ int *freq_array, unsigned int len)
+{
+ struct wpa_used_freq_data *freqs_data;
+ int num, i;
+
+ os_memset(freq_array, 0, sizeof(int) * len);
+
+ freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data));
+ if (!freqs_data)
+ return -1;
+
+ num = get_shared_radio_freqs_data(wpa_s, freqs_data, len);
+ for (i = 0; i < num; i++)
+ freq_array[i] = freqs_data[i].freq;
+
+ os_free(freqs_data);
+
+ return num;
+}
+
+
+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_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 == 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
+
+/**
+ * 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 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;
+ }
+
+ if (!cb) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Neighbor Report request must provide a callback.");
+ return -EINVAL;
+ }
+
+ /* 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));
+ 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);
+ }
+
+ 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;
+}
+
+
+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.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;
+
+ /* 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(MSG_DEBUG, "RRM: Link measurement report:",
+ wpabuf_head(buf), wpabuf_len(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);
}
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
index 9ad3f8b..9980dbc 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
@@ -70,6 +70,8 @@ ctrl_interface=/var/run/wpa_supplicant
# to make wpa_supplicant interoperate with these APs, the version number is set
# to 1 by default. This configuration value can be used to set it to the new
# version (2).
+# Note: When using MACsec, eapol_version shall be set to 3, which is
+# defined in IEEE Std 802.1X-2010.
eapol_version=1
# AP scanning/selection
@@ -86,6 +88,8 @@ eapol_version=1
# 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.
# 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,
@@ -101,6 +105,30 @@ eapol_version=1
# networks are found, a new IBSS or AP mode network is created.
ap_scan=1
+# 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
+# 0 to use the driver version. When AMPE is enabled, the wpa_supplicant MPM is
+# always used.
+# 0: MPM lives in the driver
+# 1: wpa_supplicant provides an MPM which handles peering (default)
+#user_mpm=1
+
+# Maximum number of peer links (0-255; default: 99)
+# Maximum number of mesh peering currently maintained by the STA.
+#max_peer_links=99
+
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in mesh STA to clean up inactive stations.
+#mesh_max_inactivity=300
+
+# cert_in_cb - Whether to include a peer certificate dump in events
+# This controls whether peer certificates for authentication server and
+# its certificate chain are included in EAP peer certificate events. This is
+# enabled by default.
+#cert_in_cb=1
+
# EAP fast re-authentication
# By default, fast re-authentication is enabled for all EAP methods that
# support it. This variable can be used to disable fast re-authentication.
@@ -119,6 +147,16 @@ fast_reauth=1
# configure the path to the pkcs11 module required by the pkcs11 engine
#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
+# 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.
+# 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
@@ -232,14 +270,14 @@ fast_reauth=1
# This is an optional set of parameters for automatic scanning
# within an interface in following format:
#autoscan=<autoscan module name>:<module parameters>
-# autoscan is like bgscan but on disconnected or inactive state.
-# For instance, on exponential module parameters would be <base>:<limit>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
#autoscan=exponential:3:300
# Which means a delay between scans on a base exponential of 3,
-# up to the limit of 300 seconds (3, 9, 27 ... 300)
-# For periodic module, parameters would be <fixed interval>
+# 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
# filter_ssids - SSID-based scan result filtering
# 0 = do not filter scan results (default)
@@ -256,6 +294,19 @@ fast_reauth=1
# inactive stations.
#p2p_go_max_inactivity=300
+# Passphrase length (8..63) for P2P GO
+#
+# This parameter controls the length of the random passphrase that is
+# generated at the GO. Default: 8.
+#p2p_passphrase_len=8
+
+# Extra delay between concurrent P2P search iterations
+#
+# This value adds extra delay in milliseconds between concurrent search
+# iterations to make p2p_find friendlier to concurrent operations by avoiding
+# it from taking 100% of radio resources. The default value is 500 ms.
+#p2p_search_delay=500
+
# Opportunistic Key Caching (also known as Proactive Key Caching) default
# This parameter can be used to set the default behavior for the
# proactive_key_caching parameter. By default, OKC is disabled unless enabled
@@ -272,6 +323,59 @@ fast_reauth=1
# ieee80211w parameter.
#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:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=21 20 19 26 25
+
+# Default value for DTIM period (if not overridden in network block)
+#dtim_period=2
+
+# Default value for Beacon interval (if not overridden in network block)
+#beacon_int=100
+
+# 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). This is used in AP and P2P GO modes.
+#ap_vendor_elements=dd0411223301
+
+# Ignore scan results older than request
+#
+# The driver may have a cache of scan results that makes it return
+# information that is older than our scan trigger. This parameter can
+# be used to configure such old information to be ignored instead of
+# allowing it to update the internal BSS table.
+#ignore_old_scan_res=0
+
+# scan_cur_freq: Whether to scan only the current frequency
+# 0: Scan all available frequencies. (Default)
+# 1: Scan current operating frequency if another VIF on the same radio
+# is already associated.
+
+# MAC address policy default
+# 0 = use permanent MAC address
+# 1 = use random MAC address for each ESS connection
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#
+# By default, permanent MAC address is used unless policy is changed by
+# the per-network mac_addr parameter. Global mac_addr=1 can be used to
+# change this default behavior.
+#mac_addr=0
+
+# Lifetime of random MAC address in seconds (default: 60)
+#rand_addr_lifetime=60
+
+# MAC address policy for pre-association operations (scanning, ANQP)
+# 0 = use permanent MAC address
+# 1 = use random MAC address
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#preassoc_mac_addr=0
+
# Interworking (IEEE 802.11u)
# Enable Interworking
@@ -299,6 +403,8 @@ fast_reauth=1
#
# credential fields:
#
+# temporary: Whether this credential is temporary and not to be saved
+#
# priority: Priority group
# By default, all networks and credentials get the same priority group
# (0). This field can be used to give higher priority for credentials
@@ -356,9 +462,11 @@ fast_reauth=1
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
-# domain: Home service provider FQDN
+# domain: Home service provider FQDN(s)
# This is used to compare against the Domain Name List to figure out
-# whether the AP is operated by the Home SP.
+# whether the AP is operated by the Home SP. Multiple domain entries can
+# be used to configure alternative FQDNs that will be considered home
+# networks.
#
# roaming_consortium: Roaming Consortium OI
# If roaming_consortium_len is non-zero, this field contains the
@@ -385,6 +493,59 @@ fast_reauth=1
# matching with the network. Multiple entries can be used to specify more
# than one SSID.
#
+# roaming_partner: Roaming partner information
+# This optional field can be used to configure preferences between roaming
+# partners. The field is a string in following format:
+# <FQDN>,<0/1 exact match>,<priority>,<* or country code>
+# (non-exact match means any subdomain matches the entry; priority is in
+# 0..255 range with 0 being the highest priority)
+#
+# update_identifier: PPS MO ID
+# (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+#
+# provisioning_sp: FQDN of the SP that provisioned the credential
+# This optional field can be used to keep track of the SP that provisioned
+# the credential to find the PPS MO (./Wi-Fi/<provisioning_sp>).
+#
+# Minimum backhaul threshold (PPS/<X+>/Policy/MinBackhauldThreshold/*)
+# These fields can be used to specify minimum download/upload backhaul
+# bandwidth that is preferred for the credential. This constraint is
+# ignored if the AP does not advertise WAN Metrics information or if the
+# limit would prevent any connection. Values are in kilobits per second.
+# min_dl_bandwidth_home
+# min_ul_bandwidth_home
+# min_dl_bandwidth_roaming
+# min_ul_bandwidth_roaming
+#
+# max_bss_load: Maximum BSS Load Channel Utilization (1..255)
+# (PPS/<X+>/Policy/MaximumBSSLoadValue)
+# This value is used as the maximum channel utilization for network
+# selection purposes for home networks. If the AP does not advertise
+# BSS Load or if the limit would prevent any connection, this constraint
+# will be ignored.
+#
+# req_conn_capab: Required connection capability
+# (PPS/<X+>/Policy/RequiredProtoPortTuple)
+# This value is used to configure set of required protocol/port pairs that
+# a roaming network shall support (include explicitly in Connection
+# Capability ANQP element). This constraint is ignored if the AP does not
+# advertise Connection Capability or if this constraint would prevent any
+# network connection. This policy is not used in home networks.
+# Format: <protocol>[:<comma-separated list of ports]
+# Multiple entries can be used to list multiple requirements.
+# For example, number of common TCP protocols:
+# req_conn_capab=6,22,80,443
+# For example, IPSec/IKE:
+# req_conn_capab=17:500
+# req_conn_capab=50
+#
+# ocsp: Whether to use/require OCSP to check server certificate
+# 0 = do not use OCSP stapling (TLS certificate status extension)
+# 1 = try to use OCSP stapling, but not require response
+# 2 = require valid OCSP stapling response
+#
+# sim_num: Identifier for which SIM to use in multi-SIM devices
+#
# for example:
#
#cred={
@@ -461,9 +622,10 @@ fast_reauth=1
# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
# 1 = IBSS (ad-hoc, peer-to-peer)
# 2 = AP (access point)
-# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
-# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). WPA-None requires
-# following network block options:
+# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) and
+# WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE (fixed group key
+# TKIP/CCMP) is available for backwards compatibility, but its use is
+# deprecated. WPA-None requires following network block options:
# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
# both), and psk must also be set.
#
@@ -485,6 +647,9 @@ fast_reauth=1
# set, scan results that do not match any of the specified frequencies are not
# considered when selecting a BSS.
#
+# This can also be set on the outside of the network block. In this case,
+# it limits the frequencies that will be scanned.
+#
# bgscan: Background scanning
# wpa_supplicant behavior for background scanning can be specified by
# configuring a bgscan module. These modules are responsible for requesting
@@ -501,6 +666,12 @@ fast_reauth=1
# bgscan="learn:<short bgscan interval in seconds>:<signal strength threshold>:
# <long interval>[:<database file name>]"
# bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
+# Explicitly disable bgscan by setting
+# bgscan=""
+#
+# This option can also be set outside of all network blocks for the bgscan
+# parameter to apply for all the networks that have no specific bgscan
+# parameter.
#
# proto: list of accepted protocols
# WPA = WPA/IEEE 802.11i/D3.0
@@ -565,8 +736,16 @@ fast_reauth=1
# 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, eapol_flags must be set to 0 for the
-# authentication to be completed successfully.
+# Note: When using wired authentication (including macsec_qca driver),
+# 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.
+# 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.
#
# 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
@@ -688,6 +867,10 @@ fast_reauth=1
# sertificate is only accepted if it contains this string in the subject.
# The subject string is in following format:
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
+# Note: Since this is a substring match, this cannot be used securily 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
@@ -696,6 +879,30 @@ fast_reauth=1
# 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
+# 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.
+#
+# 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
+# If set, this FQDN is used as a full 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 full match comparison. This behavior is similar to
+# domain_suffix_match, but has the requirement of a full match, i.e.,
+# 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".
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
# "peapver=1 peaplabel=1")
@@ -724,9 +931,20 @@ fast_reauth=1
# * 2 = require cryptobinding
# EAP-WSC (WPS) uses following options: pin=<Device Password> or
# pbc=1.
+#
+# For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
+# used to configure a mode that allows EAP-Success (and EAP-Failure)
+# without going through authentication step. Some switches use such
+# sequence when forcing the port to be authorized/unauthorized or as a
+# fallback option if the authentication server is unreachable. By default,
+# wpa_supplicant discards such frames to protect against potential attacks
+# by rogue devices, but this option can be used to disable that protection
+# for cases where the server/authenticator does not need to be
+# authenticated.
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
-# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
+# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS). "mschapv2_retry=0" can be
+# used to disable MSCHAPv2 password retry in authentication failure cases.
#
# TLS-based methods can use the following parameters to control TLS behavior
# (these are normally in the phase1 parameter, but can be used also in the
@@ -745,6 +963,10 @@ fast_reauth=1
# EAP workarounds are disabled with eap_workarounds=0.
# For EAP-FAST, this must be set to 0 (or left unconfigured for the
# default value to be used automatically).
+# 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_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
+# that have issues interoperating with updated TLS version)
#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
@@ -758,9 +980,12 @@ fast_reauth=1
# private_key2_passwd: Password for private key file
# dh_file2: File path to DH/DSA parameters file (in PEM format)
# subject_match2: Substring to be matched against the subject of the
-# authentication server certificate.
-# altsubject_match2: Substring to be matched against the alternative subject
-# name of the authentication server certificate.
+# authentication server certificate. See subject_match for more details.
+# altsubject_match2: Semicolon separated string of entries to be matched
+# against the alternative subject name of the authentication server
+# certificate. See altsubject_match documentation for more details.
+# domain_suffix_match2: Constraint for server domain name. See
+# domain_suffix_match for more details.
#
# fragment_size: Maximum EAP fragment size in bytes (default 1398).
# This value limits the fragment size for EAP methods that support
@@ -769,6 +994,17 @@ fast_reauth=1
# interface used for EAPOL. The default value is suitable for most
# cases.
#
+# ocsp: Whether to use/require OCSP to check server certificate
+# 0 = do not use OCSP stapling (TLS certificate status extension)
+# 1 = try to use OCSP stapling, but not require response
+# 2 = require valid OCSP stapling response
+#
+# openssl_ciphers: OpenSSL specific cipher configuration
+# This can be used to override the global openssl_ciphers configuration
+# parameter (see above).
+#
+# erp: Whether EAP Re-authentication Protocol (ERP) is enabled
+#
# EAP-FAST variables:
# pac_file: File path for the PAC entries. wpa_supplicant will need to be able
# to create this file and write updates to it when PAC is being
@@ -815,6 +1051,15 @@ fast_reauth=1
# DTIM period in Beacon intervals for AP mode (default: 2)
#dtim_period=2
+# Beacon interval (default: 100 TU)
+#beacon_int=100
+
+# MAC address policy
+# 0 = use permanent MAC address
+# 1 = use random MAC address for each ESS connection
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#mac_addr=0
+
# disable_ht: Whether HT (802.11n) should be disabled.
# 0 = HT enabled (if AP supports it)
# 1 = HT disabled
@@ -827,6 +1072,14 @@ fast_reauth=1
# 0 = SGI enabled (if AP supports it)
# 1 = SGI disabled
#
+# disable_ldpc: Whether LDPC should be disabled.
+# 0 = LDPC enabled (if AP supports it)
+# 1 = LDPC disabled
+#
+# ht40_intolerant: Whether 40 MHz intolerant should be indicated.
+# 0 = 40 MHz tolerant (default)
+# 1 = 40 MHz intolerant
+#
# ht_mcs: Configure allowed MCS rates.
# Parsed as an array of bytes, in base-16 (ascii-hex)
# ht_mcs="" // Use all available (default)
@@ -838,11 +1091,28 @@ fast_reauth=1
# 0 = Enable MAX-AMSDU if hardware supports it.
# 1 = Disable AMSDU
#
+# ampdu_factor: Maximum A-MPDU Length Exponent
+# Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+#
# ampdu_density: Allow overriding AMPDU density configuration.
# Treated as hint by the kernel.
# -1 = Do not make any changes.
# 0-3 = Set AMPDU density (aka factor) to specified value.
+# disable_vht: Whether VHT should be disabled.
+# 0 = VHT enabled (if AP supports it)
+# 1 = VHT disabled
+#
+# vht_capa: VHT capabilities to set in the override
+# vht_capa_mask: mask of VHT capabilities
+#
+# vht_rx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for RX NSS 1-8
+# vht_tx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for TX NSS 1-8
+# 0: MCS 0-7
+# 1: MCS 0-8
+# 2: MCS 0-9
+# 3: not supported
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
@@ -1089,7 +1359,19 @@ network={
}
-# IBSS/ad-hoc network with WPA-None/TKIP.
+# IBSS/ad-hoc network with RSN
+network={
+ ssid="ibss-rsn"
+ key_mgmt=WPA-PSK
+ proto=RSN
+ psk="12345678"
+ mode=1
+ frequency=2412
+ pairwise=CCMP
+ group=CCMP
+}
+
+# IBSS/ad-hoc network with WPA-None/TKIP (deprecated)
network={
ssid="test adhoc"
mode=1
@@ -1101,6 +1383,23 @@ network={
psk="secret passphrase"
}
+# open mesh network
+network={
+ ssid="test mesh"
+ mode=5
+ frequency=2437
+ key_mgmt=NONE
+}
+
+# secure (SAE + AMPE) network
+network={
+ ssid="secure mesh"
+ mode=5
+ frequency=2437
+ key_mgmt=SAE
+ psk="very secret passphrase"
+}
+
# Catch all example that allows more or less all configuration modes
network={
@@ -1175,3 +1474,39 @@ SGVsbG8gV29ybGQhCg==
network={
key_mgmt=NONE
}
+
+# Example configuration blacklisting two APs - these will be ignored
+# for this network.
+network={
+ ssid="example"
+ psk="very secret passphrase"
+ bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66
+}
+
+# Example configuration limiting AP selection to a specific set of APs;
+# any other AP not matching the masked address will be ignored.
+network={
+ ssid="example"
+ psk="very secret passphrase"
+ bssid_whitelist=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff
+}
+
+# Example config file that will only scan on channel 36.
+freq_list=5180
+network={
+ key_mgmt=NONE
+}
+
+
+# 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
+#}
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
index 544977b..26ff216 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, 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,11 @@
#include "utils/list.h"
#include "common/defs.h"
+#include "common/sae.h"
+#include "common/wpa_ctrl.h"
+#include "wps/wps_defs.h"
#include "config_ssid.h"
+#include "wmm_ac.h"
extern const char *wpa_supplicant_version;
extern const char *wpa_supplicant_license;
@@ -55,6 +59,25 @@ struct wpa_interface {
const char *confname;
/**
+ * confanother - Additional configuration name (file or profile) name
+ *
+ * This can also be %NULL when the additional configuration file is not
+ * used.
+ */
+ const char *confanother;
+
+#ifdef CONFIG_P2P
+ /**
+ * conf_p2p_dev - Configuration file used to hold the
+ * P2P Device configuration parameters.
+ *
+ * This can also be %NULL. In such a case, if a P2P Device dedicated
+ * interfaces is created, the main configuration file will be used.
+ */
+ const char *conf_p2p_dev;
+#endif /* CONFIG_P2P */
+
+ /**
* ctrl_interface - Control interface parameter
*
* If a configuration file is not used, this variable can be used to
@@ -95,6 +118,15 @@ struct wpa_interface {
* receiving of EAPOL frames from an additional interface.
*/
const char *bridge_ifname;
+
+ /**
+ * p2p_mgmt - Interface used for P2P management (P2P Device operations)
+ *
+ * Indicates whether wpas_p2p_init() must be called for this interface.
+ * This is used only when the driver supports a dedicated P2P Device
+ * interface that is not a network interface.
+ */
+ int p2p_mgmt;
};
/**
@@ -146,6 +178,11 @@ struct wpa_params {
char *ctrl_interface;
/**
+ * ctrl_interface_group - Global ctrl_iface group
+ */
+ char *ctrl_interface_group;
+
+ /**
* dbus_ctrl_interface - Enable the DBus control interface
*/
int dbus_ctrl_interface;
@@ -204,12 +241,6 @@ struct p2p_srv_upnp {
char *service;
};
-struct wpa_freq_range {
- unsigned int min;
- unsigned int max;
-};
-
-
/**
* struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
*
@@ -227,27 +258,93 @@ struct wpa_global {
struct p2p_data *p2p;
struct wpa_supplicant *p2p_init_wpa_s;
struct wpa_supplicant *p2p_group_formation;
+ struct wpa_supplicant *p2p_invite_group;
u8 p2p_dev_addr[ETH_ALEN];
+ struct os_reltime p2p_go_wait_client;
struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
int p2p_disabled;
int cross_connection;
- struct wpa_freq_range *p2p_disallow_freq;
- unsigned int num_p2p_disallow_freq;
+ struct wpa_freq_range_list p2p_disallow_freq;
+ struct wpa_freq_range_list p2p_go_avoid_freq;
enum wpa_conc_pref {
WPA_CONC_PREF_NOT_SET,
WPA_CONC_PREF_STA,
WPA_CONC_PREF_P2P
} conc_pref;
- unsigned int p2p_cb_on_scan_complete:1;
+ unsigned int p2p_per_sta_psk:1;
+ unsigned int p2p_fail_on_wps_complete:1;
+ unsigned int p2p_24ghz_social_channels:1;
+ unsigned int pending_p2ps_group:1;
+ unsigned int pending_group_iface_for_p2ps:1;
#ifdef CONFIG_WIFI_DISPLAY
int wifi_display;
#define MAX_WFD_SUBELEMS 10
struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
#endif /* CONFIG_WIFI_DISPLAY */
+
+ struct psk_list_entry *add_psk; /* From group formation */
+};
+
+
+/**
+ * struct wpa_radio - Internal data for per-radio information
+ *
+ * This structure is used to share data about configured interfaces
+ * (struct wpa_supplicant) that share the same physical radio, e.g., to allow
+ * better coordination of offchannel operations.
+ */
+struct wpa_radio {
+ char name[16]; /* from driver_ops get_radio_name() or empty if not
+ * available */
+ unsigned int external_scan_running:1;
+ struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
+ struct dl_list work; /* struct wpa_radio_work::list entries */
+};
+
+/**
+ * struct wpa_radio_work - Radio work item
+ */
+struct wpa_radio_work {
+ struct dl_list list;
+ unsigned int freq; /* known frequency (MHz) or 0 for multiple/unknown */
+ const char *type;
+ struct wpa_supplicant *wpa_s;
+ void (*cb)(struct wpa_radio_work *work, int deinit);
+ void *ctx;
+ unsigned int started:1;
+ struct os_reltime time;
+};
+
+int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
+ const char *type, int next,
+ void (*cb)(struct wpa_radio_work *work, int deinit),
+ void *ctx);
+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_work_check_next(struct wpa_supplicant *wpa_s);
+struct wpa_radio_work *
+radio_work_pending(struct wpa_supplicant *wpa_s, const char *type);
+
+struct wpa_connect_work {
+ unsigned int sme:1;
+ unsigned int bss_removed:1;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid;
};
+int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
+ struct wpa_ssid *test_ssid);
+void wpas_connect_work_free(struct wpa_connect_work *cwork);
+void wpas_connect_work_done(struct wpa_supplicant *wpa_s);
+
+struct wpa_external_work {
+ unsigned int id;
+ char type[100];
+ unsigned int timeout;
+};
/**
* offchannel_send_action_result - Result of offchannel send Action frame
@@ -268,7 +365,7 @@ struct wps_ap_info {
WPS_AP_SEL_REG_OUR
} type;
unsigned int tries;
- struct os_time last_attempt;
+ struct os_reltime last_attempt;
};
struct wpa_ssid_value {
@@ -276,6 +373,44 @@ struct wpa_ssid_value {
size_t ssid_len;
};
+#define WPA_FREQ_USED_BY_INFRA_STATION BIT(0)
+#define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1)
+
+struct wpa_used_freq_data {
+ int freq;
+ unsigned int flags;
+};
+
+#define RRM_NEIGHBOR_REPORT_TIMEOUT 1 /* 1 second for AP to send a report */
+
+/*
+ * struct rrm_data - Data used for managing RRM features
+ */
+struct rrm_data {
+ /* rrm_used - indication regarding the current connection */
+ unsigned int rrm_used:1;
+
+ /*
+ * notify_neighbor_rep - Callback for notifying report requester
+ */
+ void (*notify_neighbor_rep)(void *ctx, struct wpabuf *neighbor_rep);
+
+ /*
+ * neighbor_rep_cb_ctx - Callback context
+ * Received in the callback registration, and sent to the callback
+ * function as a parameter.
+ */
+ void *neighbor_rep_cb_ctx;
+
+ /* next_neighbor_rep_token - Next request's dialog token */
+ u8 next_neighbor_rep_token;
+};
+
+enum wpa_supplicant_test_failure {
+ WPAS_TEST_FAILURE_NONE,
+ WPAS_TEST_FAILURE_SCAN_TRIGGER,
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -286,11 +421,14 @@ struct wpa_ssid_value {
*/
struct wpa_supplicant {
struct wpa_global *global;
+ 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 *next;
struct l2_packet_data *l2;
struct l2_packet_data *l2_br;
unsigned char own_addr[ETH_ALEN];
+ unsigned char perm_addr[ETH_ALEN];
char ifname[100];
#ifdef CONFIG_CTRL_IFACE_DBUS
char *dbus_path;
@@ -305,16 +443,20 @@ struct wpa_supplicant {
char bridge_ifname[16];
char *confname;
+ char *confanother;
+
struct wpa_config *conf;
int countermeasures;
- os_time_t last_michael_mic_error;
+ struct os_reltime last_michael_mic_error;
u8 bssid[ETH_ALEN];
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 */
int disconnected; /* all connections disabled; i.e., do no reassociate
* before this has been cleared */
struct wpa_ssid *current_ssid;
+ struct wpa_ssid *last_ssid;
struct wpa_bss *current_bss;
int ap_ies_from_associnfo;
unsigned int assoc_freq;
@@ -337,6 +479,11 @@ struct wpa_supplicant {
struct wpa_ssid_value *disallow_aps_ssid;
size_t disallow_aps_ssid_count;
+ enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband;
+
+ /* Preferred network for the next connection attempt */
+ struct wpa_ssid *next_ssid;
+
/* previous scan was wildcard when interleaving between
* wildcard scans and specific SSID scan when max_ssids=1 */
int prev_scan_wildcard;
@@ -369,8 +516,7 @@ struct wpa_supplicant {
struct wpa_bss **last_scan_res;
unsigned int last_scan_res_used;
unsigned int last_scan_res_size;
- int last_scan_full;
- struct os_time last_scan;
+ struct os_reltime last_scan;
struct wpa_driver_ops *driver;
int interface_removed; /* whether the network interface has been
@@ -381,6 +527,7 @@ struct wpa_supplicant {
struct ctrl_iface_priv *ctrl_iface;
enum wpa_states wpa_state;
+ struct wpa_radio_work *scan_work;
int scanning;
int sched_scanning;
int new_connection;
@@ -389,14 +536,13 @@ struct wpa_supplicant {
* previous association event */
struct scard_data *scard;
-#ifdef PCSC_FUNCS
char imsi[20];
int mnc_len;
-#endif /* PCSC_FUNCS */
unsigned char last_eapol_src[ETH_ALEN];
- int keys_cleared;
+ unsigned int keys_cleared; /* bitfield of key indexes that the driver is
+ * known not to be configured with a key */
struct wpa_blacklist *blacklist;
@@ -441,16 +587,32 @@ struct wpa_supplicant {
* to be run.
*/
MANUAL_SCAN_REQ
- } scan_req;
+ } scan_req, last_scan_req;
+ enum wpa_states scan_prev_wpa_state;
+ struct os_reltime scan_trigger_time, scan_start_time;
int scan_runs; /* number of scan runs since WPS was started */
int *next_scan_freqs;
+ int *manual_scan_freqs;
+ int *manual_sched_scan_freqs;
+ unsigned int manual_scan_passive:1;
+ unsigned int manual_scan_use_id:1;
+ unsigned int manual_scan_only_new:1;
+ unsigned int own_scan_requested:1;
+ unsigned int own_scan_running:1;
+ unsigned int clear_driver_scan_cache:1;
+ unsigned int manual_scan_id;
int scan_interval; /* time in sec between scans to find suitable AP */
int normal_scans; /* normal scans run before sched_scan */
int scan_for_connection; /* whether the scan request was triggered for
* finding a connection */
+#define MAX_SCAN_ID 16
+ int scan_id[MAX_SCAN_ID];
+ unsigned int scan_id_count;
- unsigned int drv_flags;
+ u64 drv_flags;
unsigned int drv_enc;
+ unsigned int drv_smps_modes;
+ unsigned int drv_rrm_flags;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -458,6 +620,10 @@ struct wpa_supplicant {
*/
unsigned int probe_resp_offloads;
+ /* extended capabilities supported by the driver */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
int max_scan_ssids;
int max_sched_scan_ssids;
int sched_scan_supported;
@@ -472,12 +638,19 @@ struct wpa_supplicant {
struct wps_context *wps;
int wps_success; /* WPS success event received */
struct wps_er *wps_er;
+ unsigned int wps_run;
int blacklist_cleared;
struct wpabuf *pending_eapol_rx;
- struct os_time pending_eapol_rx_time;
+ struct os_reltime pending_eapol_rx_time;
u8 pending_eapol_rx_src[ETH_ALEN];
unsigned int last_eapol_matches_bssid:1;
+ unsigned int eap_expected_failure:1;
+ unsigned int reattach:1; /* reassociation to the same BSS requested */
+ unsigned int mac_addr_changed:1;
+
+ struct os_reltime last_mac_addr_change;
+ int last_mac_addr_style;
struct ibss_rsn *ibss_rsn;
@@ -509,16 +682,20 @@ struct wpa_supplicant {
u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
* sa_query_count octets of pending
* SA Query transaction identifiers */
- struct os_time sa_query_start;
+ struct os_reltime sa_query_start;
+ struct os_reltime last_unprot_disconnect;
+ enum { HT_SEC_CHAN_UNKNOWN,
+ HT_SEC_CHAN_ABOVE,
+ HT_SEC_CHAN_BELOW } ht_sec_chan;
u8 sched_obss_scan;
u16 obss_scan_int;
u16 bss_max_idle_period;
- enum {
- SME_SAE_INIT,
- SME_SAE_COMMIT,
- SME_SAE_CONFIRM
- } sae_state;
- u16 sae_send_confirm;
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+ struct wpabuf *sae_token;
+ int sae_group_index;
+ unsigned int sae_pmksa_caching:1;
+#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -529,6 +706,15 @@ struct wpa_supplicant {
void *ap_configured_cb_data;
#endif /* CONFIG_AP */
+ struct hostapd_iface *ifmsh;
+#ifdef CONFIG_MESH
+ struct mesh_rsn *mesh_rsn;
+ int mesh_if_idx;
+ unsigned int mesh_if_created:1;
+ unsigned int mesh_ht_enabled:1;
+ int mesh_auth_block_duration; /* sec */
+#endif /* CONFIG_MESH */
+
unsigned int off_channel_freq;
struct wpabuf *pending_action_tx;
u8 pending_action_src[ETH_ALEN];
@@ -537,6 +723,7 @@ struct wpa_supplicant {
unsigned int pending_action_freq;
int pending_action_no_cck;
int pending_action_without_roc;
+ unsigned int pending_action_tx_done:1;
void (*pending_action_tx_status_cb)(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -546,7 +733,10 @@ struct wpa_supplicant {
unsigned int roc_waiting_drv_freq;
int action_tx_wait_time;
+ int p2p_mgmt;
+
#ifdef CONFIG_P2P
+ struct wpa_supplicant *p2p_dev;
struct p2p_go_neg_results *go_params;
int create_p2p_iface;
u8 pending_interface_addr[ETH_ALEN];
@@ -568,6 +758,8 @@ struct wpa_supplicant {
u8 p2p_auth_invite[ETH_ALEN];
int p2p_sd_over_ctrl_iface;
int p2p_in_provisioning;
+ int p2p_in_invitation;
+ int p2p_invite_go_freq;
int pending_invite_ssid_id;
int show_group_started;
u8 go_dev_addr[ETH_ALEN];
@@ -575,12 +767,14 @@ struct wpa_supplicant {
u8 pending_join_iface_addr[ETH_ALEN];
u8 pending_join_dev_addr[ETH_ALEN];
int pending_join_wps_method;
+ u8 p2p_join_ssid[32];
+ size_t p2p_join_ssid_len;
int p2p_join_scan_count;
int auto_pd_scan_retry;
int force_long_sd;
u16 pending_pd_config_methods;
enum {
- NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+ NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN, AUTO_PD_ASP
} pending_pd_use;
/*
@@ -604,19 +798,42 @@ struct wpa_supplicant {
*/
char cross_connect_uplink[100];
- unsigned int sta_scan_pending:1;
unsigned int p2p_auto_join:1;
unsigned int p2p_auto_pd: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 user_initiated_pd:1;
+ unsigned int p2p_go_group_formation_completed:1;
+ unsigned int group_formation_reported:1;
+ unsigned int waiting_presence_resp;
+ int p2p_first_connection_timeout;
+ unsigned int p2p_nfc_tag_enabled:1;
+ unsigned int p2p_peer_oob_pk_hash_known:1;
+ unsigned int p2p_disable_ip_addr_req:1;
+ unsigned int p2ps_join_addr_valid:1;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
int p2p_connect_freq;
- struct os_time p2p_auto_started;
+ struct os_reltime p2p_auto_started;
+ struct wpa_ssid *p2p_last_4way_hs_fail;
+ struct wpa_radio_work *p2p_scan_work;
+ struct wpa_radio_work *p2p_listen_work;
+ struct wpa_radio_work *p2p_send_action_work;
+
+ u16 p2p_oob_dev_pw_id; /* OOB Device Password Id for group formation */
+ struct wpabuf *p2p_oob_dev_pw; /* OOB Device Password for group
+ * formation */
+ u8 p2p_peer_oob_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+ u8 p2p_ip_addr_info[3 * 4];
+
+ /* group common frequencies */
+ int *p2p_group_common_freqs;
+ unsigned int p2p_group_common_freqs_num;
+ u8 p2ps_join_addr[ETH_ALEN];
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;
@@ -636,7 +853,6 @@ struct wpa_supplicant {
int after_wps;
int known_wps_freq;
unsigned int wps_freq;
- u16 wps_ap_channel;
int wps_fragment_size;
int auto_reconnect_disabled;
@@ -652,7 +868,18 @@ struct wpa_supplicant {
unsigned int network_select:1;
unsigned int auto_select:1;
unsigned int auto_network_select:1;
+ unsigned int interworking_fast_assoc_tried:1;
unsigned int fetch_all_anqp:1;
+ unsigned int fetch_osu_info:1;
+ unsigned int fetch_osu_waiting_scan:1;
+ unsigned int fetch_osu_icon_in_progress:1;
+ struct wpa_bss *interworking_gas_bss;
+ unsigned int osu_icon_id;
+ struct osu_provider *osu_prov;
+ size_t osu_prov_count;
+ struct os_reltime osu_icon_fetch_start;
+ unsigned int num_osu_scans;
+ unsigned int num_prov_found;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
@@ -661,19 +888,87 @@ struct wpa_supplicant {
u16 num_modes;
u16 flags;
} hw;
+ enum local_hw_capab {
+ CAPAB_NO_HT_VHT,
+ CAPAB_HT,
+ CAPAB_HT40,
+ CAPAB_VHT,
+ } hw_capab;
+#ifdef CONFIG_MACSEC
+ struct ieee802_1x_kay *kay;
+#endif /* CONFIG_MACSEC */
int pno;
+ int pno_sched_pending;
/* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason;
struct ext_password_data *ext_pw;
- struct wpabuf *last_gas_resp;
- u8 last_gas_addr[ETH_ALEN];
- u8 last_gas_dialog_token;
+ struct wpabuf *last_gas_resp, *prev_gas_resp;
+ u8 last_gas_addr[ETH_ALEN], prev_gas_addr[ETH_ALEN];
+ u8 last_gas_dialog_token, prev_gas_dialog_token;
unsigned int no_keep_alive:1;
+ unsigned int ext_mgmt_frame_handling:1;
+ unsigned int ext_eapol_frame_io:1;
+ unsigned int wmm_ac_supported:1;
+ unsigned int ext_work_in_progress:1;
+ unsigned int own_disconnect_req:1;
+
+#define MAC_ADDR_RAND_SCAN BIT(0)
+#define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
+#define MAC_ADDR_RAND_PNO BIT(2)
+#define MAC_ADDR_RAND_ALL (MAC_ADDR_RAND_SCAN | \
+ MAC_ADDR_RAND_SCHED_SCAN | \
+ MAC_ADDR_RAND_PNO)
+ unsigned int mac_addr_rand_supported;
+ unsigned int mac_addr_rand_enable;
+
+ /* MAC Address followed by mask (2 * ETH_ALEN) */
+ u8 *mac_addr_scan;
+ u8 *mac_addr_sched_scan;
+ u8 *mac_addr_pno;
+
+#ifdef CONFIG_WNM
+ u8 wnm_dialog_token;
+ u8 wnm_reply;
+ u8 wnm_num_neighbor_report;
+ u8 wnm_mode;
+ u16 wnm_dissoc_timer;
+ u8 wnm_bss_termination_duration[12];
+ struct neighbor_report *wnm_neighbor_report_elements;
+ struct os_reltime wnm_cand_valid_until;
+ u8 wnm_cand_from_bss[ETH_ALEN];
+#endif /* CONFIG_WNM */
+
+#ifdef CONFIG_TESTING_GET_GTK
+ u8 last_gtk[32];
+ size_t last_gtk_len;
+#endif /* CONFIG_TESTING_GET_GTK */
+
+ unsigned int num_multichan_concurrent;
+ struct wpa_radio_work *connect_work;
+
+ unsigned int ext_work_id;
+
+ struct wpabuf *vendor_elem[NUM_VENDOR_ELEM_FRAMES];
+
+#ifdef CONFIG_TESTING_OPTIONS
+ struct l2_packet_data *l2_test;
+ unsigned int extra_roc_dur;
+ enum wpa_supplicant_test_failure test_failure;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ struct wmm_ac_assoc_data *wmm_ac_assoc_info;
+ struct wmm_tspec_element *tspecs[WMM_AC_NUM][TS_DIR_IDX_COUNT];
+ struct wmm_ac_addts_request *addts_request;
+ u8 wmm_ac_last_dialog_token;
+ struct wmm_tspec_element *last_tspecs;
+ u8 last_tspecs_count;
+
+ struct rrm_data rrm;
};
@@ -681,8 +976,13 @@ struct wpa_supplicant {
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_vht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
@@ -716,6 +1016,9 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
+int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
+ const char *pkcs11_engine_path,
+ const char *pkcs11_module_path);
int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s,
int ap_scan);
int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
@@ -732,7 +1035,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s);
void wpa_show_license(void);
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
- struct wpa_interface *iface);
+ struct wpa_interface *iface,
+ struct wpa_supplicant *parent);
int wpa_supplicant_remove_iface(struct wpa_global *global,
struct wpa_supplicant *wpa_s,
int terminate);
@@ -747,21 +1051,35 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
void wpa_supplicant_terminate_proc(struct wpa_global *global);
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len);
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt);
-enum wpa_cipher cipher_suite2driver(int cipher);
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);
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);
+void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason);
void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int clear_failures);
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);
-int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
+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);
+void add_freq(int *freqs, int *num_freqs, int freq);
+
+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,
+ void (*cb)(void *ctx,
+ struct wpabuf *neighbor_rep),
+ void *cb_ctx);
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len,
+ int rssi);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -778,6 +1096,10 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
const char *field,
const char *value);
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_freq_params *freq);
+
/* events.c */
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
@@ -786,7 +1108,9 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
-int wpas_select_network_from_last_scan(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);
/* eap_register.c */
int eap_register_methods(void);
@@ -802,7 +1126,18 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid)
}
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
+void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
+ struct wpa_used_freq_data *freqs_data,
+ unsigned int len);
+
+int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs_data,
+ unsigned int len);
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+ int *freq_array, unsigned int len);
+
#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 a08eb33..f3f2a64 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf
@@ -1,6 +1,6 @@
##### wpa_supplicant configuration file template #####
update_config=1
-ctrl_interface=wlan0
eapol_version=1
ap_scan=1
fast_reauth=1
+pmf=1
diff --git a/contrib/wpa/wpa_supplicant/wpas_glue.c b/contrib/wpa/wpa_supplicant/wpas_glue.c
index 6f69ddb..1bb82ba 100644
--- a/contrib/wpa/wpa_supplicant/wpas_glue.c
+++ b/contrib/wpa/wpa_supplicant/wpas_glue.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -26,6 +26,7 @@
#include "bss.h"
#include "scan.h"
#include "notify.h"
+#include "wpas_kay.h"
#ifndef CONFIG_NO_CONFIG_BLOBS
@@ -95,11 +96,26 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
u16 proto, const u8 *buf, size_t len)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
+ size_t hex_len = 2 * len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex == NULL)
+ return -1;
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg(wpa_s, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+ MAC2STR(dest), hex);
+ os_free(hex);
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (wpa_s->l2) {
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
}
- return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+ return -1;
}
#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
@@ -141,11 +157,29 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
if (pmksa_cache_get_current(wpa_s->wpa) &&
type == IEEE802_1X_TYPE_EAPOL_START) {
- /* Trying to use PMKSA caching - do not send EAPOL-Start frames
- * since they will trigger full EAPOL authentication. */
- wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
- "EAPOL-Start");
- return -1;
+ /*
+ * We were trying to use PMKSA caching and sending EAPOL-Start
+ * would abort that and trigger full EAPOL authentication.
+ * However, we've already waited for the AP/Authenticator to
+ * start 4-way handshake or EAP authentication, and apparently
+ * it has not done so since the startWhen timer has reached zero
+ * to get the state machine sending EAPOL-Start. This is not
+ * really supposed to happen, but an interoperability issue with
+ * a deployed AP has been identified where the connection fails
+ * due to that AP failing to operate correctly if PMKID is
+ * included in the Association Request frame. To work around
+ * this, assume PMKSA caching failed and try to initiate full
+ * EAP authentication.
+ */
+ if (!wpa_s->current_ssid ||
+ wpa_s->current_ssid->eap_workaround) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Timeout on waiting for the AP to initiate 4-way handshake for PMKSA caching or EAP authentication - try to force it to start EAP authentication");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "RSN: PMKSA caching - do not send EAPOL-Start");
+ return -1;
+ }
}
if (is_zero_ether_addr(wpa_s->bssid)) {
@@ -216,29 +250,50 @@ static void wpa_supplicant_aborted_cached(void *ctx)
}
-static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+static const char * result_str(enum eapol_supp_result result)
+{
+ switch (result) {
+ case EAPOL_SUPP_RESULT_FAILURE:
+ return "FAILURE";
+ case EAPOL_SUPP_RESULT_SUCCESS:
+ return "SUCCESS";
+ case EAPOL_SUPP_RESULT_EXPECTED_FAILURE:
+ return "EXPECTED_FAILURE";
+ }
+ return "?";
+}
+
+
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
+ enum eapol_supp_result result,
void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
int res, pmk_len;
u8 pmk[PMK_LEN];
- wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
- success ? "" : "un");
+ wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s",
+ result_str(result));
if (wpas_wps_eapol_cb(wpa_s) > 0)
return;
- if (!success) {
+ wpa_s->eap_expected_failure = result ==
+ EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+
+ if (result != EAPOL_SUPP_RESULT_SUCCESS) {
/*
* Make sure we do not get stuck here waiting for long EAPOL
* timeout if the AP does not disconnect in case of
* authentication failure.
*/
wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
+ } else {
+ ieee802_1x_notify_create_actor(wpa_s, wpa_s->last_eapol_src);
}
- if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ if (result != EAPOL_SUPP_RESULT_SUCCESS ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
return;
if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
@@ -437,6 +492,13 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
/* Clear the MIC error counter when setting a new PTK. */
wpa_s->mic_errors_seen = 0;
}
+#ifdef CONFIG_TESTING_GET_GTK
+ if (key_idx > 0 && addr && is_broadcast_ether_addr(addr) &&
+ alg != WPA_ALG_NONE && key_len <= sizeof(wpa_s->last_gtk)) {
+ os_memcpy(wpa_s->last_gtk, key, key_len);
+ wpa_s->last_gtk_len = key_len;
+ }
+#endif /* CONFIG_TESTING_GET_GTK */
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
key, key_len);
}
@@ -481,7 +543,44 @@ static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
const u8 *ies, size_t ies_len)
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
+ int ret;
+ u8 *data, *pos;
+ size_t data_len;
+
+ if (action != 1) {
+ wpa_printf(MSG_ERROR, "Unsupported send_ft_action action %d",
+ action);
+ return -1;
+ }
+
+ /*
+ * Action frame payload:
+ * Category[1] = 6 (Fast BSS Transition)
+ * Action[1] = 1 (Fast BSS Transition Request)
+ * STA Address
+ * Target AP Address
+ * FT IEs
+ */
+
+ data_len = 2 + 2 * ETH_ALEN + ies_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ *pos++ = 0x06; /* FT Action category */
+ *pos++ = action;
+ os_memcpy(pos, wpa_s->own_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, target_ap, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, ies, ies_len);
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
+ wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid,
+ data, data_len, 0);
+ os_free(data);
+
+ return ret;
}
@@ -506,18 +605,18 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
}
#endif /* CONFIG_IEEE80211R */
-#endif /* CONFIG_NO_WPA */
-
#ifdef CONFIG_TDLS
static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
- int *tdls_ext_setup)
+ int *tdls_ext_setup,
+ int *tdls_chan_switch)
{
struct wpa_supplicant *wpa_s = ctx;
*tdls_supported = 0;
*tdls_ext_setup = 0;
+ *tdls_chan_switch = 0;
if (!wpa_s->drv_capa_known)
return -1;
@@ -528,18 +627,23 @@ static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
*tdls_ext_setup = 1;
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH)
+ *tdls_chan_switch = 1;
+
return 0;
}
static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf,
+ u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf,
size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
- status_code, buf, len);
+ status_code, peer_capab, initiator, buf,
+ len);
}
@@ -551,27 +655,71 @@ static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
static int wpa_supplicant_tdls_peer_addset(
- void *ctx, const u8 *peer, int add, u16 capability,
- const u8 *supp_rates, size_t supp_rates_len)
+ void *ctx, const u8 *peer, int add, u16 aid, u16 capability,
+ const u8 *supp_rates, size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, int wmm, const u8 *ext_capab, size_t ext_capab_len,
+ const u8 *supp_channels, size_t supp_channels_len,
+ const u8 *supp_oper_classes, size_t supp_oper_classes_len)
{
struct wpa_supplicant *wpa_s = ctx;
struct hostapd_sta_add_params params;
+ os_memset(&params, 0, sizeof(params));
+
params.addr = peer;
- params.aid = 1;
+ params.aid = aid;
params.capability = capability;
params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
- params.ht_capabilities = NULL;
+
+ /*
+ * Don't rely only on qosinfo for WMM capability. It may be 0 even when
+ * present. Allow the WMM IE to also indicate QoS support.
+ */
+ if (wmm || qosinfo)
+ params.flags |= WPA_STA_WMM;
+
+ params.ht_capabilities = ht_capab;
+ params.vht_capabilities = vht_capab;
+ params.qosinfo = qosinfo;
params.listen_interval = 0;
params.supp_rates = supp_rates;
params.supp_rates_len = supp_rates_len;
params.set = !add;
+ params.ext_capab = ext_capab;
+ params.ext_capab_len = ext_capab_len;
+ params.supp_channels = supp_channels;
+ params.supp_channels_len = supp_channels_len;
+ params.supp_oper_classes = supp_oper_classes;
+ params.supp_oper_classes_len = supp_oper_classes_len;
return wpa_drv_sta_add(wpa_s, &params);
}
+
+static int wpa_supplicant_tdls_enable_channel_switch(
+ void *ctx, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_tdls_enable_channel_switch(wpa_s, addr, oper_class,
+ params);
+}
+
+
+static int wpa_supplicant_tdls_disable_channel_switch(void *ctx, const u8 *addr)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_tdls_disable_channel_switch(wpa_s, addr);
+}
+
#endif /* CONFIG_TDLS */
+#endif /* CONFIG_NO_WPA */
+
enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
{
@@ -587,6 +735,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
return WPA_CTRL_REQ_EAP_OTP;
else if (os_strcmp(field, "PASSPHRASE") == 0)
return WPA_CTRL_REQ_EAP_PASSPHRASE;
+ else if (os_strcmp(field, "SIM") == 0)
+ return WPA_CTRL_REQ_SIM;
return WPA_CTRL_REQ_UNKNOWN;
}
@@ -623,6 +773,9 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
*txt = "Private key passphrase";
ret = "PASSPHRASE";
break;
+ case WPA_CTRL_REQ_SIM:
+ ret = "SIM";
+ break;
default:
break;
}
@@ -662,6 +815,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
return;
}
+ wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name);
+
buflen = 100 + os_strlen(txt) + ssid->ssid_len;
buf = os_malloc(buflen);
if (buf == NULL)
@@ -669,7 +824,7 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
len = os_snprintf(buf, buflen,
WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
field_name, ssid->id, txt);
- if (len < 0 || (size_t) len >= buflen) {
+ if (os_snprintf_error(buflen, len)) {
os_free(buf);
return;
}
@@ -687,6 +842,25 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#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->imsi, &len);
+ if (wpa_s->mnc_len > 0) {
+ wpa_s->imsi[len] = '\0';
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+ } else {
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+ }
+}
+#endif /* CONFIG_EAP_PROXY */
+
+
static void wpa_supplicant_port_cb(void *ctx, int authorized)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -705,12 +879,14 @@ static void wpa_supplicant_port_cb(void *ctx, int authorized)
static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
struct wpa_supplicant *wpa_s = ctx;
- wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
+ wpas_notify_certification(wpa_s, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
@@ -779,17 +955,24 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
ctx->eapol_send = wpa_supplicant_eapol_send;
ctx->set_wep_key = wpa_eapol_set_wep_key;
+#ifndef CONFIG_NO_CONFIG_BLOBS
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
ctx->aborted_cached = wpa_supplicant_aborted_cached;
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
ctx->wps = wpa_s->wps;
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
+#ifdef CONFIG_EAP_PROXY
+ ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb;
+#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->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
@@ -807,17 +990,31 @@ 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,
- const u8 *kck,
+static void wpa_supplicant_set_rekey_offload(void *ctx,
+ const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+ 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,
+ size_t pmk_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (wpa_s->conf->key_mgmt_offload)
+ return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
+ NULL, 0, pmk, pmk_len);
+ else
+ return 0;
+}
+
+
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
@@ -857,13 +1054,19 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
ctx->tdls_oper = wpa_supplicant_tdls_oper;
ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+ ctx->tdls_enable_channel_switch =
+ wpa_supplicant_tdls_enable_channel_switch;
+ ctx->tdls_disable_channel_switch =
+ wpa_supplicant_tdls_disable_channel_switch;
#endif /* CONFIG_TDLS */
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
+ ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
"machine");
+ os_free(ctx);
return -1;
}
#endif /* CONFIG_NO_WPA */
@@ -890,6 +1093,22 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len;
conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group && wpa_s->current_bss &&
+ !wpa_s->p2p_disable_ip_addr_req) {
+ struct wpabuf *p2p;
+ p2p = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
+ P2P_IE_VENDOR_TYPE);
+ if (p2p) {
+ u8 group_capab;
+ group_capab = p2p_get_group_capab(p2p);
+ if (group_capab &
+ P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION)
+ conf.p2p = 1;
+ wpabuf_free(p2p);
+ }
+ }
+#endif /* CONFIG_P2P */
}
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
new file mode 100644
index 0000000..354decf
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/wpas_kay.c
@@ -0,0 +1,378 @@
+/*
+ * IEEE 802.1X-2010 KaY Interface
+ * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
+ *
+ * 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"
+#include "eap_peer/eap.h"
+#include "eap_peer/eap_i.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "pae/ieee802_1x_key.h"
+#include "pae/ieee802_1x_kay.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "config_ssid.h"
+#include "driver_i.h"
+#include "wpas_kay.h"
+
+
+#define DEFAULT_KEY_LEN 16
+/* secure Connectivity Association Key Name (CKN) */
+#define DEFAULT_CKN_LEN 16
+
+
+static int wpas_macsec_init(void *priv, struct macsec_init_params *params)
+{
+ return wpa_drv_macsec_init(priv, params);
+}
+
+
+static int wpas_macsec_deinit(void *priv)
+{
+ return wpa_drv_macsec_deinit(priv);
+}
+
+
+static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled)
+{
+ return wpa_drv_enable_protect_frames(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)
+{
+ return wpa_drv_set_current_cipher_suite(wpa_s, cs, cs_len);
+}
+
+
+static int wpas_enable_controlled_port(void *wpa_s, Boolean enabled)
+{
+ return wpa_drv_enable_controlled_port(wpa_s, enabled);
+}
+
+
+static int wpas_get_receive_lowest_pn(void *wpa_s, u32 channel,
+ u8 an, u32 *lowest_pn)
+{
+ return wpa_drv_get_receive_lowest_pn(wpa_s, channel, an, lowest_pn);
+}
+
+
+static int wpas_get_transmit_next_pn(void *wpa_s, u32 channel,
+ u8 an, u32 *next_pn)
+{
+ return wpa_drv_get_transmit_next_pn(wpa_s, channel, an, next_pn);
+}
+
+
+static int wpas_set_transmit_next_pn(void *wpa_s, u32 channel,
+ u8 an, u32 next_pn)
+{
+ return wpa_drv_set_transmit_next_pn(wpa_s, channel, an, next_pn);
+}
+
+
+static int wpas_get_available_receive_sc(void *wpa_s, u32 *channel)
+{
+ return wpa_drv_get_available_receive_sc(wpa_s, channel);
+}
+
+
+static unsigned int conf_offset_val(enum confidentiality_offset co)
+{
+ switch (co) {
+ case CONFIDENTIALITY_OFFSET_30:
+ return 30;
+ break;
+ case CONFIDENTIALITY_OFFSET_50:
+ return 50;
+ default:
+ return 0;
+ }
+}
+
+
+static int wpas_create_receive_sc(void *wpa_s, u32 channel,
+ struct ieee802_1x_mka_sci *sci,
+ 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);
+}
+
+
+static int wpas_delete_receive_sc(void *wpa_s, u32 channel)
+{
+ return wpa_drv_delete_receive_sc(wpa_s, channel);
+}
+
+
+static int wpas_create_receive_sa(void *wpa_s, u32 channel, u8 an,
+ u32 lowest_pn, const u8 *sak)
+{
+ return wpa_drv_create_receive_sa(wpa_s, channel, an, lowest_pn, sak);
+}
+
+
+static int wpas_enable_receive_sa(void *wpa_s, u32 channel, u8 an)
+{
+ return wpa_drv_enable_receive_sa(wpa_s, channel, an);
+}
+
+
+static int wpas_disable_receive_sa(void *wpa_s, u32 channel, u8 an)
+{
+ return wpa_drv_disable_receive_sa(wpa_s, channel, an);
+}
+
+
+static int wpas_get_available_transmit_sc(void *wpa_s, u32 *channel)
+{
+ return wpa_drv_get_available_transmit_sc(wpa_s, channel);
+}
+
+
+static int
+wpas_create_transmit_sc(void *wpa_s, u32 channel,
+ const struct ieee802_1x_mka_sci *sci,
+ enum confidentiality_offset co)
+{
+ return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, sci->port,
+ conf_offset_val(co));
+}
+
+
+static int wpas_delete_transmit_sc(void *wpa_s, u32 channel)
+{
+ return wpa_drv_delete_transmit_sc(wpa_s, channel);
+}
+
+
+static int wpas_create_transmit_sa(void *wpa_s, u32 channel, u8 an,
+ u32 next_pn, Boolean confidentiality,
+ const u8 *sak)
+{
+ return wpa_drv_create_transmit_sa(wpa_s, channel, an, next_pn,
+ confidentiality, sak);
+}
+
+
+static int wpas_enable_transmit_sa(void *wpa_s, u32 channel, u8 an)
+{
+ return wpa_drv_enable_transmit_sa(wpa_s, channel, an);
+}
+
+
+static int wpas_disable_transmit_sa(void *wpa_s, u32 channel, u8 an)
+{
+ return wpa_drv_disable_transmit_sa(wpa_s, channel, an);
+}
+
+
+int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ struct ieee802_1x_kay_ctx *kay_ctx;
+ struct ieee802_1x_kay *res = NULL;
+ enum macsec_policy policy;
+
+ ieee802_1x_dealloc_kay_sm(wpa_s);
+
+ if (!ssid || ssid->macsec_policy == 0)
+ return 0;
+
+ policy = ssid->macsec_policy == 1 ? SHOULD_SECURE : DO_NOT_SECURE;
+
+ kay_ctx = os_zalloc(sizeof(*kay_ctx));
+ if (!kay_ctx)
+ return -1;
+
+ kay_ctx->ctx = wpa_s;
+
+ kay_ctx->macsec_init = wpas_macsec_init;
+ kay_ctx->macsec_deinit = wpas_macsec_deinit;
+ kay_ctx->enable_protect_frames = wpas_enable_protect_frames;
+ 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->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->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->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,
+ wpa_s->own_addr);
+ if (res == NULL) {
+ os_free(kay_ctx);
+ return -1;
+ }
+
+ wpa_s->kay = res;
+
+ return 0;
+}
+
+
+void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->kay)
+ return;
+
+ ieee802_1x_kay_deinit(wpa_s->kay);
+ wpa_s->kay = NULL;
+}
+
+
+static int ieee802_1x_auth_get_session_id(struct wpa_supplicant *wpa_s,
+ const u8 *addr, u8 *sid, size_t *len)
+{
+ const u8 *session_id;
+ size_t id_len, need_len;
+
+ session_id = eapol_sm_get_session_id(wpa_s->eapol, &id_len);
+ if (session_id == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to get SessionID from EAPOL state machines");
+ return -1;
+ }
+
+ need_len = 1 + 2 * SSL3_RANDOM_SIZE;
+ if (need_len > id_len) {
+ wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
+ return -1;
+ }
+
+ os_memcpy(sid, session_id, need_len);
+ *len = need_len;
+
+ return 0;
+}
+
+
+static int ieee802_1x_auth_get_msk(struct wpa_supplicant *wpa_s, const u8 *addr,
+ u8 *msk, size_t *len)
+{
+ u8 key[EAP_MSK_LEN];
+ size_t keylen;
+ struct eapol_sm *sm;
+ int res;
+
+ sm = wpa_s->eapol;
+ if (sm == NULL)
+ return -1;
+
+ keylen = EAP_MSK_LEN;
+ res = eapol_sm_get_key(sm, key, keylen);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to get MSK from EAPOL state machines");
+ return -1;
+ }
+
+ if (keylen > *len)
+ keylen = *len;
+ os_memcpy(msk, key, keylen);
+ *len = keylen;
+
+ return 0;
+}
+
+
+void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr)
+{
+ u8 *sid;
+ size_t sid_len = 128;
+ struct mka_key_name *ckn;
+ struct mka_key *cak;
+ struct mka_key *msk;
+ void *res = NULL;
+
+ if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: External notification - Create MKA for "
+ MACSTR, MAC2STR(peer_addr));
+
+ msk = os_zalloc(sizeof(*msk));
+ sid = os_zalloc(sid_len);
+ ckn = os_zalloc(sizeof(*ckn));
+ cak = os_zalloc(sizeof(*cak));
+ if (!msk || !sid || !ckn || !cak)
+ goto fail;
+
+ msk->len = DEFAULT_KEY_LEN;
+ if (ieee802_1x_auth_get_msk(wpa_s, wpa_s->bssid, msk->key, &msk->len)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
+ goto fail;
+ }
+
+ if (ieee802_1x_auth_get_session_id(wpa_s, wpa_s->bssid, sid, &sid_len))
+ {
+ wpa_printf(MSG_ERROR,
+ "IEEE 802.1X: Could not get EAP Session Id");
+ goto fail;
+ }
+
+ /* 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)) {
+ wpa_printf(MSG_ERROR,
+ "IEEE 802.1X: Deriving CAK failed");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
+
+ /* 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)) {
+ wpa_printf(MSG_ERROR,
+ "IEEE 802.1X: Deriving CKN failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
+
+ res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0,
+ EAP_EXCHANGE, FALSE);
+
+fail:
+ if (msk) {
+ os_memset(msk, 0, sizeof(*msk));
+ os_free(msk);
+ }
+ os_free(sid);
+ os_free(ckn);
+ if (cak) {
+ os_memset(cak, 0, sizeof(*cak));
+ os_free(cak);
+ }
+
+ return res;
+}
diff --git a/contrib/wpa/wpa_supplicant/wpas_kay.h b/contrib/wpa/wpa_supplicant/wpas_kay.h
new file mode 100644
index 0000000..b7236d0
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/wpas_kay.h
@@ -0,0 +1,41 @@
+/*
+ * IEEE 802.1X-2010 KaY Interface
+ * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPAS_KAY_H
+#define WPAS_KAY_H
+
+#ifdef CONFIG_MACSEC
+
+int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+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);
+
+#else /* CONFIG_MACSEC */
+
+static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ return 0;
+}
+
+static inline void *
+ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr)
+{
+ return NULL;
+}
+
+static inline void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s)
+{
+}
+
+#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
new file mode 100644
index 0000000..6af1678
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/wpas_module_tests.c
@@ -0,0 +1,108 @@
+/*
+ * wpa_supplicant module tests
+ * Copyright (c) 2014, 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 "wpa_supplicant_i.h"
+#include "blacklist.h"
+
+
+static int wpas_blacklist_module_tests(void)
+{
+ struct wpa_supplicant wpa_s;
+ int ret = -1;
+
+ os_memset(&wpa_s, 0, sizeof(wpa_s));
+
+ wpa_blacklist_clear(&wpa_s);
+
+ if (wpa_blacklist_get(NULL, NULL) != NULL ||
+ wpa_blacklist_get(NULL, (u8 *) "123456") != NULL ||
+ wpa_blacklist_get(&wpa_s, NULL) != NULL ||
+ wpa_blacklist_get(&wpa_s, (u8 *) "123456") != NULL)
+ goto fail;
+
+ if (wpa_blacklist_add(NULL, NULL) == 0 ||
+ wpa_blacklist_add(NULL, (u8 *) "123456") == 0 ||
+ wpa_blacklist_add(&wpa_s, NULL) == 0)
+ goto fail;
+
+ if (wpa_blacklist_del(NULL, NULL) == 0 ||
+ wpa_blacklist_del(NULL, (u8 *) "123456") == 0 ||
+ wpa_blacklist_del(&wpa_s, NULL) == 0 ||
+ wpa_blacklist_del(&wpa_s, (u8 *) "123456") == 0)
+ goto fail;
+
+ if (wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "444444") < 0 ||
+ wpa_blacklist_del(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_blacklist_del(&wpa_s, (u8 *) "xxxxxx") == 0 ||
+ wpa_blacklist_get(&wpa_s, (u8 *) "xxxxxx") != NULL ||
+ wpa_blacklist_get(&wpa_s, (u8 *) "111111") == NULL ||
+ wpa_blacklist_get(&wpa_s, (u8 *) "222222") == NULL ||
+ wpa_blacklist_get(&wpa_s, (u8 *) "444444") == NULL ||
+ wpa_blacklist_del(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_blacklist_del(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_blacklist_del(&wpa_s, (u8 *) "444444") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ wpa_blacklist_clear(&wpa_s);
+
+ if (ret)
+ wpa_printf(MSG_ERROR, "blacklist module test failure");
+
+ return ret;
+}
+
+
+int wpas_module_tests(void)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "wpa_supplicant module tests");
+
+ if (wpas_blacklist_module_tests() < 0)
+ ret = -1;
+
+#ifdef CONFIG_WPS
+ {
+ int wps_module_tests(void);
+ 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;
+ }
+
+ return ret;
+}
diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.c b/contrib/wpa/wpa_supplicant/wps_supplicant.c
index 8ab5f64..eabe986 100644
--- a/contrib/wpa/wpa_supplicant/wps_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/wps_supplicant.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant / WPS integration
- * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -52,8 +52,30 @@ static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
}
+static void wpas_wps_assoc_with_cred(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int use_fast_assoc = timeout_ctx != NULL;
+
+ wpa_printf(MSG_DEBUG, "WPS: Continuing association after eapol_cb");
+ if (!use_fast_assoc ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 0);
+ eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 1);
+}
+
+
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
+ if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
+ return 1;
+
if (!wpa_s->wps_success &&
wpa_s->current_ssid &&
eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
@@ -84,9 +106,14 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
!(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
int disabled = wpa_s->current_ssid->disabled;
unsigned int freq = wpa_s->assoc_freq;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = NULL;
+ int use_fast_assoc = 0;
+
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
"try to associate with the received credential "
"(freq=%u)", freq);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
if (disabled) {
@@ -98,7 +125,35 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
wpa_s->wps_freq = freq;
wpa_s->normal_scans = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
+ "without a new scan can be used");
+ bss = wpa_supplicant_pick_network(wpa_s, &ssid);
+ if (bss) {
+ struct wpabuf *wps;
+ struct wps_parse_attr attr;
+
+ wps = wpa_bss_get_vendor_ie_multi(bss,
+ WPS_IE_VENDOR_TYPE);
+ if (wps && wps_parse_msg(wps, &attr) == 0 &&
+ attr.wps_state &&
+ *attr.wps_state == WPS_STATE_CONFIGURED)
+ use_fast_assoc = 1;
+ wpabuf_free(wps);
+ }
+
+ /*
+ * Complete the next step from an eloop timeout to allow pending
+ * driver events related to the disconnection to be processed
+ * first. This makes it less likely for disconnection event to
+ * cause problems with the following connection.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Continue association from timeout");
+ wpas_wps_assoc_with_cred_cancel(wpa_s);
+ eloop_register_timeout(0, 10000,
+ wpas_wps_assoc_with_cred, wpa_s,
+ use_fast_assoc ? (void *) 1 :
+ (void *) 0);
return 1;
}
@@ -106,6 +161,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
"for external credential processing");
wpas_clear_wps(wpa_s);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
return 1;
@@ -196,12 +252,107 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
}
+static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *new_ssid)
+{
+ struct wpa_ssid *ssid, *next;
+
+ for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
+ ssid = next, next = ssid ? ssid->next : NULL) {
+ /*
+ * new_ssid has already been added to the list in
+ * wpas_wps_add_network(), so skip it.
+ */
+ if (ssid == new_ssid)
+ continue;
+
+ if (ssid->bssid_set || new_ssid->bssid_set) {
+ if (ssid->bssid_set != new_ssid->bssid_set)
+ continue;
+ if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) !=
+ 0)
+ continue;
+ }
+
+ /* compare SSID */
+ if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
+ continue;
+
+ if (ssid->ssid && new_ssid->ssid) {
+ if (os_memcmp(ssid->ssid, new_ssid->ssid,
+ ssid->ssid_len) != 0)
+ continue;
+ } else if (ssid->ssid || new_ssid->ssid)
+ continue;
+
+ /* compare security parameters */
+ if (ssid->auth_alg != new_ssid->auth_alg ||
+ ssid->key_mgmt != new_ssid->key_mgmt ||
+ (ssid->group_cipher != new_ssid->group_cipher &&
+ !(ssid->group_cipher & new_ssid->group_cipher &
+ WPA_CIPHER_CCMP)))
+ continue;
+
+ /*
+ * Some existing WPS APs will send two creds in case they are
+ * configured for mixed mode operation (WPA+WPA2 and TKIP+CCMP).
+ * Try to merge these two creds if they are received in the same
+ * M8 message.
+ */
+ if (ssid->wps_run && ssid->wps_run == new_ssid->wps_run &&
+ wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+ if (new_ssid->passphrase && ssid->passphrase &&
+ os_strcmp(new_ssid->passphrase, ssid->passphrase) !=
+ 0) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: M8 Creds with different passphrase - do not merge");
+ continue;
+ }
+
+ if (new_ssid->psk_set &&
+ (!ssid->psk_set ||
+ os_memcmp(new_ssid->psk, ssid->psk, 32) != 0)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: M8 Creds with different PSK - do not merge");
+ continue;
+ }
+
+ if ((new_ssid->passphrase && !ssid->passphrase) ||
+ (!new_ssid->passphrase && ssid->passphrase)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: M8 Creds with different passphrase/PSK type - do not merge");
+ continue;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WPS: Workaround - merge likely WPA/WPA2-mixed mode creds in same M8 message");
+ new_ssid->proto |= ssid->proto;
+ new_ssid->pairwise_cipher |= ssid->pairwise_cipher;
+ } else {
+ /*
+ * proto and pairwise_cipher difference matter for
+ * non-mixed-mode creds.
+ */
+ if (ssid->proto != new_ssid->proto ||
+ ssid->pairwise_cipher != new_ssid->pairwise_cipher)
+ continue;
+ }
+
+ /* Remove the duplicated older network entry. */
+ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
+ wpas_notify_network_removed(wpa_s, ssid);
+ if (wpa_s->current_ssid == ssid)
+ wpa_s->current_ssid = NULL;
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ }
+}
+
+
static int wpa_supplicant_wps_cred(void *ctx,
const struct wps_credential *cred)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid = wpa_s->current_ssid;
- u8 key_idx = 0;
u16 auth_type;
#ifdef CONFIG_WPS_REG_DISABLE_OPEN
int registrar = 0;
@@ -247,7 +398,6 @@ static int wpa_supplicant_wps_cred(void *ctx,
}
if (auth_type != WPS_AUTH_OPEN &&
- auth_type != WPS_AUTH_SHARED &&
auth_type != WPS_AUTH_WPAPSK &&
auth_type != WPS_AUTH_WPA2PSK) {
wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
@@ -295,10 +445,22 @@ static int wpa_supplicant_wps_cred(void *ctx,
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
+ if (wpa_s->current_ssid) {
+ /*
+ * Should the GO issue multiple credentials for some
+ * reason, each credential should be marked as a
+ * temporary P2P group similarly to the one that gets
+ * marked as such based on the pre-configured values
+ * used for the WPS network block.
+ */
+ ssid->p2p_group = wpa_s->current_ssid->p2p_group;
+ ssid->temporary = wpa_s->current_ssid->temporary;
+ }
wpas_notify_network_added(wpa_s, ssid);
}
wpa_config_set_network_defaults(ssid);
+ ssid->wps_run = wpa_s->wps_run;
os_free(ssid->ssid);
ssid->ssid = os_malloc(cred->ssid_len);
@@ -310,43 +472,16 @@ static int wpa_supplicant_wps_cred(void *ctx,
switch (cred->encr_type) {
case WPS_ENCR_NONE:
break;
- case WPS_ENCR_WEP:
- if (cred->key_len <= 0)
- break;
- if (cred->key_len != 5 && cred->key_len != 13 &&
- cred->key_len != 10 && cred->key_len != 26) {
- wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length "
- "%lu", (unsigned long) cred->key_len);
- return -1;
- }
- if (cred->key_idx > NUM_WEP_KEYS) {
- wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d",
- cred->key_idx);
- return -1;
- }
- if (cred->key_idx)
- key_idx = cred->key_idx - 1;
- if (cred->key_len == 10 || cred->key_len == 26) {
- if (hexstr2bin((char *) cred->key,
- ssid->wep_key[key_idx],
- cred->key_len / 2) < 0) {
- wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
- "%d", key_idx);
- return -1;
- }
- ssid->wep_key_len[key_idx] = cred->key_len / 2;
- } else {
- os_memcpy(ssid->wep_key[key_idx], cred->key,
- cred->key_len);
- ssid->wep_key_len[key_idx] = cred->key_len;
- }
- ssid->wep_tx_keyidx = key_idx;
- break;
case WPS_ENCR_TKIP:
ssid->pairwise_cipher = WPA_CIPHER_TKIP;
break;
case WPS_ENCR_AES:
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
+ ssid->group_cipher |= WPA_CIPHER_GCMP;
+ }
break;
}
@@ -366,11 +501,6 @@ static int wpa_supplicant_wps_cred(void *ctx,
}
#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
break;
- case WPS_AUTH_SHARED:
- ssid->auth_alg = WPA_AUTH_ALG_SHARED;
- ssid->key_mgmt = WPA_KEY_MGMT_NONE;
- ssid->proto = 0;
- break;
case WPS_AUTH_WPAPSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -412,8 +542,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
wpas_wps_security_workaround(wpa_s, ssid, cred);
- if (cred->ap_channel)
- wpa_s->wps_ap_channel = cred->ap_channel;
+ wpas_wps_remove_dup_network(wpa_s, ssid);
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->conf->update_config &&
@@ -434,15 +563,6 @@ static int wpa_supplicant_wps_cred(void *ctx,
}
-#ifdef CONFIG_P2P
-static void wpas_wps_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- wpas_p2p_notif_pbc_overlap(wpa_s);
-}
-#endif /* CONFIG_P2P */
-
-
static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
struct wps_event_m2d *m2d)
{
@@ -461,18 +581,20 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
* Notify P2P from eloop timeout to avoid issues with the
* interface getting removed while processing a message.
*/
- eloop_register_timeout(0, 0, wpas_wps_pbc_overlap_cb, wpa_s,
+ eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb, wpa_s,
NULL);
}
#endif /* CONFIG_P2P */
}
-static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
- "No Error", /* WPS_EI_NO_ERROR */
- "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
- "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
-};
+static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout");
+ wpas_clear_wps(wpa_s);
+}
+
static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail)
@@ -482,13 +604,13 @@ 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 reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
- wps_event_fail_reason[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
"msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error,
fail->error_indication,
- wps_event_fail_reason[fail->error_indication]);
+ wps_ei_str(fail->error_indication));
} else {
wpa_msg(wpa_s, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
@@ -498,11 +620,16 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
- wpas_clear_wps(wpa_s);
+
+ /*
+ * Need to allow WPS processing to complete, e.g., by sending WSC_NACK.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network");
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
+ eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
+
wpas_notify_wps_event_fail(wpa_s, fail);
-#ifdef CONFIG_P2P
wpas_p2p_wps_failed(wpa_s, fail);
-#endif /* CONFIG_P2P */
}
@@ -549,6 +676,9 @@ static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
wpa_s->wps_success = 1;
wpas_notify_wps_event_success(wpa_s);
+ if (wpa_s->current_ssid)
+ wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
+ wpa_s->extra_blacklist_count = 0;
/*
* Enable the networks disabled during wpas_wps_reassoc after 10
@@ -558,9 +688,7 @@ static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
NULL);
-#ifdef CONFIG_P2P
wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
-#endif /* CONFIG_P2P */
}
@@ -711,6 +839,12 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
break;
case WPS_EV_PBC_TIMEOUT:
break;
+ case WPS_EV_PBC_ACTIVE:
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE);
+ break;
+ case WPS_EV_PBC_DISABLE:
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE);
+ break;
case WPS_EV_ER_AP_ADD:
wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
break;
@@ -739,6 +873,17 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
}
+static int wpa_supplicant_wps_rf_band(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
+ return 0;
+
+ return (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
+}
+
+
enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
{
if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
@@ -754,21 +899,25 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
int id;
struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+
prev_current = wpa_s->current_ssid;
/* Enable the networks disabled during wpas_wps_reassoc */
wpas_wps_reenable_networks(wpa_s);
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
/* Remove any existing WPS network from configuration */
ssid = wpa_s->conf->ssid;
while (ssid) {
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
if (ssid == wpa_s->current_ssid) {
- wpa_s->current_ssid = NULL;
- if (ssid != NULL)
- wpas_notify_network_changed(wpa_s);
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
id = ssid->id;
remove_ssid = ssid;
@@ -800,7 +949,8 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
- int registrar, const u8 *bssid)
+ int registrar, const u8 *dev_addr,
+ const u8 *bssid)
{
struct wpa_ssid *ssid;
@@ -820,6 +970,11 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
return NULL;
}
+#ifdef CONFIG_P2P
+ if (dev_addr)
+ os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN);
+#endif /* CONFIG_P2P */
+
if (bssid) {
#ifndef CONFIG_P2P
struct wpa_bss *bss;
@@ -865,24 +1020,16 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
}
-static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *selected, const u8 *bssid)
+static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *selected)
{
struct wpa_ssid *ssid;
- struct wpa_bss *bss;
- wpa_s->known_wps_freq = 0;
- if (bssid) {
- bss = wpa_bss_get_bssid(wpa_s, bssid);
- if (bss && bss->freq > 0) {
- wpa_s->known_wps_freq = 1;
- wpa_s->wps_freq = bss->freq;
- }
- }
-
- if (wpa_s->current_ssid)
+ if (wpa_s->current_ssid) {
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
/* Mark all other networks disabled and trigger reassociation */
ssid = wpa_s->conf->ssid;
@@ -906,12 +1053,41 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
}
ssid = ssid->next;
}
+}
+
+
+static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *selected, const u8 *bssid,
+ int freq)
+{
+ struct wpa_bss *bss;
+
+ wpa_s->wps_run++;
+ if (wpa_s->wps_run == 0)
+ wpa_s->wps_run++;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+ if (freq) {
+ wpa_s->after_wps = 5;
+ wpa_s->wps_freq = freq;
+ } else if (bssid) {
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss && bss->freq > 0) {
+ wpa_s->known_wps_freq = 1;
+ wpa_s->wps_freq = bss->freq;
+ }
+ }
+
+ wpas_wps_temp_disable(wpa_s, selected);
+
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
wpa_s->normal_scans = 0;
wpa_s->wps_success = 0;
wpa_s->blacklist_cleared = 0;
+
+ wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -920,8 +1096,16 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
int p2p_group)
{
struct wpa_ssid *ssid;
+
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+ return -1;
+ }
+#endif /* CONFIG_AP */
wpas_clear_wps(wpa_s);
- ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+ ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
if (ssid == NULL)
return -1;
ssid->temporary = 1;
@@ -938,29 +1122,60 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
}
#endif /* CONFIG_P2P */
- wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
+ if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+ return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
- wpas_wps_reassoc(wpa_s, ssid, bssid);
+ wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
return 0;
}
-int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, int p2p_group, u16 dev_pw_id)
+static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, const u8 *bssid,
+ const char *pin, int p2p_group, u16 dev_pw_id,
+ const u8 *peer_pubkey_hash,
+ const u8 *ssid_val, size_t ssid_len, int freq)
{
struct wpa_ssid *ssid;
- char val[128];
+ char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN];
unsigned int rpin = 0;
+ char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+ return -1;
+ }
+#endif /* CONFIG_AP */
wpas_clear_wps(wpa_s);
- ssid = wpas_wps_add_network(wpa_s, 0, bssid);
- if (ssid == NULL)
+ if (bssid && is_zero_ether_addr(bssid))
+ bssid = NULL;
+ ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not add network");
return -1;
+ }
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ if (ssid_val) {
+ ssid->ssid = os_malloc(ssid_len);
+ if (ssid->ssid) {
+ os_memcpy(ssid->ssid, ssid_val, ssid_len);
+ ssid->ssid_len = ssid_len;
+ }
+ }
+ if (peer_pubkey_hash) {
+ os_memcpy(hash, " pkhash=", 8);
+ wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8,
+ peer_pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN);
+ } else {
+ hash[0] = '\0';
+ }
#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);
@@ -974,24 +1189,38 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
#endif /* CONFIG_P2P */
if (pin)
- os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"",
- pin, dev_pw_id);
- else {
+ os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"",
+ pin, dev_pw_id, hash);
+ else if (pin == NULL && dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
+ os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
+ dev_pw_id, hash);
+ } else {
rpin = wps_generate_pin();
- os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
- rpin, dev_pw_id);
+ os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
+ rpin, dev_pw_id, hash);
+ }
+ if (wpa_config_set(ssid, "phase1", val, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
+ return -1;
}
- wpa_config_set(ssid, "phase1", val, 0);
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
wpa_s->wps_ap_iter = 1;
- wpas_wps_reassoc(wpa_s, ssid, bssid);
+ wpas_wps_reassoc(wpa_s, ssid, bssid, freq);
return rpin;
}
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *pin, int p2p_group, u16 dev_pw_id)
+{
+ return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group,
+ dev_pw_id, NULL, NULL, 0, 0);
+}
+
+
/* Cancel the wps pbc/pin requests */
int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
{
@@ -1010,14 +1239,20 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
} else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
"deauthenticate");
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpas_clear_wps(wpa_s);
} else {
wpas_wps_reenable_networks(wpa_s);
wpas_wps_clear_ap_info(wpa_s);
+ if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) >
+ 0)
+ wpas_clear_wps(wpa_s);
}
+ wpa_s->after_wps = 0;
+
return 0;
}
@@ -1030,17 +1265,24 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
char *pos, *end;
int res;
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+ return -1;
+ }
+#endif /* CONFIG_AP */
if (!pin)
return -1;
wpas_clear_wps(wpa_s);
- ssid = wpas_wps_add_network(wpa_s, 1, bssid);
+ ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid);
if (ssid == NULL)
return -1;
ssid->temporary = 1;
pos = val;
end = pos + sizeof(val);
res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return -1;
pos += res;
if (settings) {
@@ -1048,28 +1290,38 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
"new_encr=%s new_key=%s",
settings->ssid_hex, settings->auth,
settings->encr, settings->key_hex);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return -1;
pos += res;
}
res = os_snprintf(pos, end - pos, "\"");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
+ return -1;
+ if (wpa_config_set(ssid, "phase1", val, 0) < 0)
return -1;
- wpa_config_set(ssid, "phase1", val, 0);
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
- wpas_wps_reassoc(wpa_s, ssid, bssid);
+ wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
return 0;
}
-static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
+ const u8 *p2p_dev_addr, const u8 *psk,
size_t psk_len)
{
- wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for "
- "STA " MACSTR, MAC2STR(mac_addr));
+ if (is_zero_ether_addr(p2p_dev_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
+ MAC2STR(mac_addr));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
+ " P2P Device Addr " MACSTR,
+ MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
+ }
wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
/* TODO */
@@ -1094,7 +1346,7 @@ static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
dev->model_number, dev->serial_number,
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
sizeof(devtype)));
- if (len > 0 && len < (int) sizeof(txt))
+ if (!os_snprintf_error(sizeof(txt), len))
wpa_printf(MSG_INFO, "%s", txt);
}
@@ -1118,7 +1370,6 @@ static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
static u16 wps_fix_config_methods(u16 config_methods)
{
-#ifdef CONFIG_WPS2
if ((config_methods &
(WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
@@ -1133,7 +1384,6 @@ static u16 wps_fix_config_methods(u16 config_methods)
"virtual_push_button for WPS 2.0 compliance");
config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
}
-#endif /* CONFIG_WPS2 */
return config_methods;
}
@@ -1142,7 +1392,9 @@ static u16 wps_fix_config_methods(u16 config_methods)
static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
struct wps_context *wps)
{
- wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname);
+ char buf[50];
+ const char *src;
+
if (is_nil_uuid(wpa_s->conf->uuid)) {
struct wpa_supplicant *first;
first = wpa_s->global->ifaces;
@@ -1153,18 +1405,18 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
os_memcpy(wps->uuid,
wpa_s->global->ifaces->wps->uuid,
WPS_UUID_LEN);
- wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first "
- "interface", wps->uuid, WPS_UUID_LEN);
+ src = "from the first interface";
} else {
uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
- wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
- "address", wps->uuid, WPS_UUID_LEN);
+ src = "based on MAC address";
}
} else {
os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
- wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration",
- wps->uuid, WPS_UUID_LEN);
+ src = "based on configuration";
}
+
+ uuid_bin2str(wps->uuid, buf, sizeof(buf));
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf);
}
@@ -1198,6 +1450,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
wps->cred_cb = wpa_supplicant_wps_cred;
wps->event_cb = wpa_supplicant_wps_event;
+ wps->rf_band_cb = wpa_supplicant_wps_rf_band;
wps->cb_ctx = wpa_s;
wps->dev.device_name = wpa_s->conf->device_name;
@@ -1268,18 +1521,39 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
}
+#ifdef CONFIG_WPS_ER
+static void wpas_wps_nfc_clear(struct wps_context *wps)
+{
+ wps->ap_nfc_dev_pw_id = 0;
+ wpabuf_free(wps->ap_nfc_dh_pubkey);
+ wps->ap_nfc_dh_pubkey = NULL;
+ wpabuf_free(wps->ap_nfc_dh_privkey);
+ wps->ap_nfc_dh_privkey = NULL;
+ wpabuf_free(wps->ap_nfc_dev_pw);
+ wps->ap_nfc_dev_pw = NULL;
+}
+#endif /* CONFIG_WPS_ER */
+
+
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
+ wpas_wps_assoc_with_cred_cancel(wpa_s);
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
wpas_wps_clear_ap_info(wpa_s);
+#ifdef CONFIG_P2P
+ eloop_cancel_timeout(wpas_p2p_pbc_overlap_cb, wpa_s, NULL);
+#endif /* CONFIG_P2P */
+
if (wpa_s->wps == NULL)
return;
#ifdef CONFIG_WPS_ER
wps_er_deinit(wpa_s->wps_er, NULL, NULL);
wpa_s->wps_er = NULL;
+ wpas_wps_nfc_clear(wpa_s->wps);
#endif /* CONFIG_WPS_ER */
wps_registrar_deinit(wpa_s->wps->registrar);
@@ -1460,6 +1734,10 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
uuid = wps_get_uuid_e(ie);
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
uuid, UUID_LEN);
+ if (os_memcmp(selected->bssid, bss->bssid, ETH_ALEN) == 0) {
+ wpabuf_free(ie);
+ continue;
+ }
if (sel_uuid == NULL || uuid == NULL ||
os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
ret = 1; /* PBC overlap */
@@ -1563,13 +1841,12 @@ int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter)
}
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
+void wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
{
#ifdef CONFIG_WPS_ER
wps_er_deinit(wpa_s->wps_er, NULL, NULL);
wpa_s->wps_er = NULL;
#endif /* CONFIG_WPS_ER */
- return 0;
}
@@ -1578,91 +1855,131 @@ int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
const char *uuid, const char *pin)
{
u8 u[UUID_LEN];
- int any = 0;
-
- if (os_strcmp(uuid, "any") == 0)
- any = 1;
- else if (uuid_str2bin(uuid, u))
+ const u8 *use_uuid = NULL;
+ u8 addr_buf[ETH_ALEN];
+
+ if (os_strcmp(uuid, "any") == 0) {
+ } else if (uuid_str2bin(uuid, u) == 0) {
+ use_uuid = u;
+ } else if (hwaddr_aton(uuid, addr_buf) == 0) {
+ use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
+ if (use_uuid == NULL)
+ return -1;
+ } else
return -1;
return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
- any ? NULL : u,
+ use_uuid,
(const u8 *) pin, os_strlen(pin), 300);
}
int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_pbc(wpa_s->wps_er, u);
+ return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
}
int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
+
+ return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
os_strlen(pin));
}
-int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
- int id)
+static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
+ struct wps_credential *cred)
{
- u8 u[UUID_LEN];
- struct wpa_ssid *ssid;
- struct wps_credential cred;
-
- if (uuid_str2bin(uuid, u))
- return -1;
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL || ssid->ssid == NULL)
- return -1;
-
- os_memset(&cred, 0, sizeof(cred));
+ os_memset(cred, 0, sizeof(*cred));
if (ssid->ssid_len > 32)
return -1;
- os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len);
- cred.ssid_len = ssid->ssid_len;
+ os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
+ cred->ssid_len = ssid->ssid_len;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
- cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ?
+ cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
- cred.encr_type = WPS_ENCR_AES;
+ cred->encr_type = WPS_ENCR_AES;
else
- cred.encr_type = WPS_ENCR_TKIP;
+ cred->encr_type = WPS_ENCR_TKIP;
if (ssid->passphrase) {
- cred.key_len = os_strlen(ssid->passphrase);
- if (cred.key_len >= 64)
+ cred->key_len = os_strlen(ssid->passphrase);
+ if (cred->key_len >= 64)
return -1;
- os_memcpy(cred.key, ssid->passphrase, cred.key_len);
+ os_memcpy(cred->key, ssid->passphrase, cred->key_len);
} else if (ssid->psk_set) {
- cred.key_len = 32;
- os_memcpy(cred.key, ssid->psk, 32);
+ cred->key_len = 32;
+ os_memcpy(cred->key, ssid->psk, 32);
} else
return -1;
} else {
- cred.auth_type = WPS_AUTH_OPEN;
- cred.encr_type = WPS_ENCR_NONE;
+ cred->auth_type = WPS_AUTH_OPEN;
+ cred->encr_type = WPS_ENCR_NONE;
}
- return wps_er_set_config(wpa_s->wps_er, u, &cred);
+
+ return 0;
+}
+
+
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+ int id)
+{
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+ struct wpa_ssid *ssid;
+ struct wps_credential cred;
+ int ret;
+
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return -1;
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL || ssid->ssid == NULL)
+ return -1;
+
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+ return -1;
+ ret = wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
+ os_memset(&cred, 0, sizeof(cred));
+ return ret;
}
int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin, struct wps_new_ap_settings *settings)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
struct wps_credential cred;
size_t len;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
if (settings->ssid_hex == NULL || settings->auth == NULL ||
settings->encr == NULL || settings->key_hex == NULL)
@@ -1692,8 +2009,10 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
if (os_strcmp(settings->encr, "NONE") == 0)
cred.encr_type = WPS_ENCR_NONE;
+#ifdef CONFIG_TESTING_OPTIONS
else if (os_strcmp(settings->encr, "WEP") == 0)
cred.encr_type = WPS_ENCR_WEP;
+#endif /* CONFIG_TESTING_OPTIONS */
else if (os_strcmp(settings->encr, "TKIP") == 0)
cred.encr_type = WPS_ENCR_TKIP;
else if (os_strcmp(settings->encr, "CCMP") == 0)
@@ -1701,8 +2020,8 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
else
return -1;
- return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
- os_strlen(pin), &cred);
+ return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
+ (const u8 *) pin, os_strlen(pin), &cred);
}
@@ -1711,15 +2030,20 @@ struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef, const char *uuid)
{
struct wpabuf *ret;
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
if (!wpa_s->wps_er)
return NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return NULL;
- ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+ ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
if (ndef && ret) {
struct wpabuf *tmp;
tmp = ndef_build_wifi(ret);
@@ -1759,19 +2083,6 @@ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
}
-int wpas_wps_in_progress(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ssid *ssid;
-
- for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
- if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS)
- return 1;
- }
-
- return 0;
-}
-
-
void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
{
struct wps_context *wps = wpa_s->wps;
@@ -1827,8 +2138,69 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_WPS_NFC
+#ifdef CONFIG_WPS_ER
+static struct wpabuf *
+wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
+ struct wpa_ssid *ssid)
+{
+ struct wpabuf *ret;
+ struct wps_credential cred;
+
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+ return NULL;
+
+ ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_ER */
+
+
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *id_str)
+{
+#ifdef CONFIG_WPS_ER
+ if (id_str) {
+ int id;
+ char *end = NULL;
+ struct wpa_ssid *ssid;
+
+ id = strtol(id_str, &end, 10);
+ if (end && *end)
+ return NULL;
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL)
+ return NULL;
+ return wpas_wps_network_config_token(wpa_s, ndef, ssid);
+ }
+#endif /* CONFIG_WPS_ER */
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface)
+ return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
+#endif /* CONFIG_AP */
+ return NULL;
+}
+
+
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
{
+ if (wpa_s->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ wpa_s->conf->wps_nfc_dev_pw_id,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ wpa_s->conf->wps_nfc_dev_pw);
+ }
+
return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
&wpa_s->conf->wps_nfc_dh_pubkey,
&wpa_s->conf->wps_nfc_dh_privkey,
@@ -1836,15 +2208,32 @@ struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
}
-int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr,
+ const u8 *bssid,
+ const struct wpabuf *dev_pw, u16 dev_pw_id,
+ int p2p_group, const u8 *peer_pubkey_hash,
+ const u8 *ssid, size_t ssid_len, int freq)
{
struct wps_context *wps = wpa_s->wps;
char pw[32 * 2 + 1];
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
+ dev_pw = wpa_s->conf->wps_nfc_dev_pw;
+ dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+ }
+
if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
- wpa_s->conf->wps_nfc_dh_privkey == NULL ||
- wpa_s->conf->wps_nfc_dev_pw == NULL)
+ wpa_s->conf->wps_nfc_dh_privkey == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Missing DH params - "
+ "cannot start NFC-triggered connection");
return -1;
+ }
+
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Missing Device Password (id=%u) - "
+ "cannot start NFC-triggered connection", dev_pw_id);
+ return -1;
+ }
dh5_free(wps->dh_ctx);
wpabuf_free(wps->dh_pubkey);
@@ -1857,24 +2246,42 @@ int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
wps->dh_pubkey = NULL;
wpabuf_free(wps->dh_privkey);
wps->dh_privkey = NULL;
+ wpa_printf(MSG_DEBUG, "WPS: Failed to get DH priv/pub key");
return -1;
}
wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
- if (wps->dh_ctx == NULL)
+ if (wps->dh_ctx == NULL) {
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
+ wpa_printf(MSG_DEBUG, "WPS: Failed to initialize DH context");
return -1;
+ }
- wpa_snprintf_hex_uppercase(pw, sizeof(pw),
- wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
- wpabuf_len(wpa_s->conf->wps_nfc_dev_pw));
- return wpas_wps_start_pin(wpa_s, bssid, pw, 0,
- wpa_s->conf->wps_nfc_dev_pw_id);
+ if (dev_pw) {
+ wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+ wpabuf_head(dev_pw),
+ wpabuf_len(dev_pw));
+ }
+ return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid,
+ dev_pw ? pw : NULL,
+ p2p_group, dev_pw_id, peer_pubkey_hash,
+ ssid, ssid_len, freq);
}
static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
struct wps_parse_attr *attr)
{
- wpa_s->wps_ap_channel = 0;
+ /*
+ * Disable existing networks temporarily to allow the newly learned
+ * credential to be preferred. Enable the temporarily disabled networks
+ * after 10 seconds.
+ */
+ wpas_wps_temp_disable(wpa_s, NULL);
+ eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+ NULL);
if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
return -1;
@@ -1882,12 +2289,8 @@ static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
return 0;
- wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
- "based on the received credential added");
- wpa_s->normal_scans = 0;
- wpa_supplicant_reinit_autoscan(wpa_s);
- if (wpa_s->wps_ap_channel) {
- u16 chan = wpa_s->wps_ap_channel;
+ if (attr->ap_channel) {
+ u16 chan = WPA_GET_BE16(attr->ap_channel);
int freq = 0;
if (chan >= 1 && chan <= 13)
@@ -1898,14 +2301,21 @@ static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
freq = 5000 + 5 * chan;
if (freq) {
- wpa_printf(MSG_DEBUG, "WPS: Credential indicated "
- "AP channel %u -> %u MHz", chan, freq);
+ wpa_printf(MSG_DEBUG, "WPS: Credential container indicated AP channel %u -> %u MHz",
+ chan, freq);
wpa_s->after_wps = 5;
wpa_s->wps_freq = freq;
}
}
+
+ wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
+ "based on the received credential added");
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+
+ wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
return 0;
@@ -1949,7 +2359,7 @@ static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
- const struct wpabuf *data)
+ const struct wpabuf *data, int forced_freq)
{
const struct wpabuf *wps = data;
struct wpabuf *tmp = NULL;
@@ -1962,6 +2372,15 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
/* Assume this contains full NDEF record */
tmp = ndef_parse_wifi(data);
if (tmp == NULL) {
+#ifdef CONFIG_P2P
+ tmp = ndef_parse_p2p(data);
+ if (tmp) {
+ ret = wpas_p2p_nfc_tag_process(wpa_s, tmp,
+ forced_freq);
+ wpabuf_free(tmp);
+ return ret;
+ }
+#endif /* CONFIG_P2P */
wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
return -1;
}
@@ -1974,53 +2393,337 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
}
-struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef)
{
- return ndef_build_wifi_hr();
+ struct wpabuf *ret;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+
+ ret = wps_build_nfc_handover_req(wpa_s->wps,
+ wpa_s->conf->wps_nfc_dh_pubkey);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
}
-struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf *
+wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef,
+ const char *uuid)
{
+#ifdef CONFIG_WPS_ER
+ struct wpabuf *ret;
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+ struct wps_context *wps = wpa_s->wps;
+
+ if (wps == NULL)
+ return NULL;
+
+ if (uuid == NULL)
+ return NULL;
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return NULL;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) {
+ if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+ }
+
+ wpas_wps_nfc_clear(wps);
+ wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ wps->ap_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+ wps->ap_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+ if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
+ wpas_wps_nfc_clear(wps);
+ return NULL;
+ }
+
+ ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid,
+ use_addr, wpa_s->conf->wps_nfc_dh_pubkey);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+#else /* CONFIG_WPS_ER */
return NULL;
+#endif /* CONFIG_WPS_ER */
}
+#endif /* CONFIG_WPS_NFC */
-int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
- const struct wpabuf *data)
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr, const char *uuid)
{
- /* TODO */
- return -1;
+ struct wpabuf *ret;
+ if (!cr)
+ return NULL;
+ ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
+ if (ret)
+ return ret;
+ return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
}
-int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
- const struct wpabuf *data)
+static int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
{
struct wpabuf *wps;
- int ret;
+ int ret = -1;
+ u16 wsc_len;
+ const u8 *pos;
+ struct wpabuf msg;
+ struct wps_parse_attr attr;
+ u16 dev_pw_id;
+ const u8 *bssid = NULL;
+ int freq = 0;
wps = ndef_parse_wifi(data);
if (wps == NULL)
return -1;
wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
"payload from NFC connection handover");
- wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
- ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+ if (wpabuf_len(wps) < 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Select "
+ "Message");
+ goto out;
+ }
+ pos = wpabuf_head(wps);
+ wsc_len = WPA_GET_BE16(pos);
+ if (wsc_len > wpabuf_len(wps) - 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+ "in Wi-Fi Handover Select Message", wsc_len);
+ goto out;
+ }
+ pos += 2;
+
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: WSC attributes in Wi-Fi Handover Select Message",
+ pos, wsc_len);
+ if (wsc_len < wpabuf_len(wps) - 2) {
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: Ignore extra data after WSC attributes",
+ pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+ }
+
+ wpabuf_set(&msg, pos, wsc_len);
+ ret = wps_parse_msg(&msg, &attr);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+ "Wi-Fi Handover Select Message");
+ goto out;
+ }
+
+ if (attr.oob_dev_password == NULL ||
+ attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+ "included in Wi-Fi Handover Select Message");
+ ret = -1;
+ goto out;
+ }
+
+ if (attr.ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No SSID included in Wi-Fi Handover "
+ "Select Message");
+ ret = -1;
+ goto out;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", attr.ssid, attr.ssid_len);
+
+ if (attr.mac_addr) {
+ bssid = attr.mac_addr;
+ wpa_printf(MSG_DEBUG, "WPS: MAC Address (BSSID): " MACSTR,
+ MAC2STR(bssid));
+ }
+
+ if (attr.rf_bands)
+ wpa_printf(MSG_DEBUG, "WPS: RF Bands: %d", *attr.rf_bands);
+
+ if (attr.ap_channel) {
+ u16 chan = WPA_GET_BE16(attr.ap_channel);
+
+ wpa_printf(MSG_DEBUG, "WPS: AP Channel: %d", chan);
+
+ if (chan >= 1 && chan <= 13 &&
+ (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ))
+ freq = 2407 + 5 * chan;
+ else if (chan == 14 &&
+ (attr.rf_bands == NULL ||
+ *attr.rf_bands & WPS_RF_24GHZ))
+ freq = 2484;
+ else if (chan >= 30 &&
+ (attr.rf_bands == NULL ||
+ *attr.rf_bands & WPS_RF_50GHZ))
+ freq = 5000 + 5 * chan;
+
+ if (freq) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: AP indicated channel %u -> %u MHz",
+ chan, freq);
+ }
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+ attr.oob_dev_password, attr.oob_dev_password_len);
+ dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+ WPS_OOB_PUBKEY_HASH_LEN);
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+ "%u in Wi-Fi Handover Select Message", dev_pw_id);
+ ret = -1;
+ goto out;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash",
+ attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+ ret = wpas_wps_start_nfc(wpa_s, NULL, bssid, NULL, dev_pw_id, 0,
+ attr.oob_dev_password,
+ attr.ssid, attr.ssid_len, freq);
+
+out:
wpabuf_free(wps);
+ return ret;
+}
+
+
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
+ return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
+}
+
+
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ struct wpabuf *wps;
+ int ret = -1;
+ u16 wsc_len;
+ const u8 *pos;
+ struct wpabuf msg;
+ struct wps_parse_attr attr;
+ u16 dev_pw_id;
+ /*
+ * Enrollee/station is always initiator of the NFC connection handover,
+ * so use the request message here to find Enrollee public key hash.
+ */
+ wps = ndef_parse_wifi(req);
+ if (wps == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+ "payload from NFC connection handover");
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+ if (wpabuf_len(wps) < 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+ "Message");
+ goto out;
+ }
+ pos = wpabuf_head(wps);
+ wsc_len = WPA_GET_BE16(pos);
+ if (wsc_len > wpabuf_len(wps) - 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+ "in rt Wi-Fi Handover Request Message", wsc_len);
+ goto out;
+ }
+ pos += 2;
+
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: WSC attributes in Wi-Fi Handover Request Message",
+ pos, wsc_len);
+ if (wsc_len < wpabuf_len(wps) - 2) {
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: Ignore extra data after WSC attributes",
+ pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+ }
+
+ wpabuf_set(&msg, pos, wsc_len);
+ ret = wps_parse_msg(&msg, &attr);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+ "Wi-Fi Handover Request Message");
+ goto out;
+ }
+
+ if (attr.oob_dev_password == NULL ||
+ attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+ "included in Wi-Fi Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ if (attr.uuid_e == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+ "Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+ attr.oob_dev_password, attr.oob_dev_password_len);
+ dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+ WPS_OOB_PUBKEY_HASH_LEN);
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+ "%u in Wi-Fi Handover Request Message", dev_pw_id);
+ ret = -1;
+ goto out;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+ attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+ ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar,
+ attr.oob_dev_password,
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ NULL, 0, 1);
+
+out:
+ wpabuf_free(wps);
return ret;
}
#endif /* CONFIG_WPS_NFC */
-extern int wpa_debug_level;
-
static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
{
size_t i;
- struct os_time now;
+ struct os_reltime now;
if (wpa_debug_level > MSG_DEBUG)
return;
@@ -2028,7 +2731,7 @@ static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
if (wpa_s->wps_ap == NULL)
return;
- os_get_time(&now);
+ os_get_reltime(&now);
for (i = 0; i < wpa_s->num_wps_ap; i++) {
struct wps_ap_info *ap = &wpa_s->wps_ap[i];
@@ -2132,11 +2835,14 @@ void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wps_ap_info *ap;
+
+ wpa_s->after_wps = 0;
+
if (!wpa_s->wps_ap_iter)
return;
ap = wpas_wps_get_ap_info(wpa_s, bssid);
if (ap == NULL)
return;
ap->tries++;
- os_get_time(&ap->last_attempt);
+ os_get_reltime(&ap->last_attempt);
}
diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.h b/contrib/wpa/wpa_supplicant/wps_supplicant.h
index dd0dc60..683bd50 100644
--- a/contrib/wpa/wpa_supplicant/wps_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/wps_supplicant.h
@@ -47,7 +47,7 @@ int wpas_wps_searching(struct wpa_supplicant *wpa_s);
int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
char *end);
int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter);
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
+void wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
const char *uuid, const char *pin);
int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);
@@ -60,18 +60,27 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef, const char *uuid);
int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
-int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *id_str);
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
-int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ const u8 *bssid,
+ const struct wpabuf *dev_pw, u16 dev_pw_id,
+ int p2p_group, const u8 *peer_pubkey_hash,
+ const u8 *ssid, size_t ssid_len, int freq);
int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
- const struct wpabuf *data);
-struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
-struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
-int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
- const struct wpabuf *data);
-int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
- const struct wpabuf *data);
+ const struct wpabuf *data, int forced_freq);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr, const char *uuid);
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
+int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
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);
diff --git a/contrib/xz/ChangeLog b/contrib/xz/ChangeLog
index b84727b..f2c90b0 100644
--- a/contrib/xz/ChangeLog
+++ b/contrib/xz/ChangeLog
@@ -1,3 +1,233 @@
+commit dec11497a71518423b5ff0e759100cf8aadf6c7b
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-26 16:53:44 +0200
+
+ Bump version and soname for 5.2.1.
+
+ src/liblzma/Makefile.am | 2 +-
+ src/liblzma/api/lzma/version.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit 29e39c79975ab89ee5dd671e97064534a9f3a649
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-26 13:01:09 +0200
+
+ Update NEWS for 5.2.1.
+
+ NEWS | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+commit 7a11c4a8e5e15f13d5fa59233b3172e65428efdd
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-22 19:38:48 +0200
+
+ xz: Use pipe2() if available.
+
+ configure.ac | 4 ++--
+ src/xz/file_io.c | 9 ++++++++-
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+commit 117d962685c72682c63edc9bb765367189800202
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-21 23:40:26 +0200
+
+ liblzma: Fix a compression-ratio regression in LZMA1/2 in fast mode.
+
+ The bug was added in the commit
+ f48fce093b07aeda95c18850f5e086d9f2383380 and thus
+ affected 5.1.4beta and 5.2.0. Luckily the bug cannot
+ cause data corruption or other nasty things.
+
+ src/liblzma/lzma/lzma_encoder_optimum_fast.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ae984e31c167d3bc52972ec422dd1ebd5f5d5719
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-21 23:00:19 +0200
+
+ xz: Fix the fcntl() usage when creating a pipe for the self-pipe trick.
+
+ Now it reads the old flags instead of blindly setting O_NONBLOCK.
+ The old code may have worked correctly, but this is better.
+
+ src/xz/file_io.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+commit 2205bb5853098aea36a56df6f5747037175f66b4
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-10 15:29:34 +0200
+
+ Update THANKS.
+
+ THANKS | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit d935b0cdf3db440269b9d952b2b281b18f8c7b08
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-10 15:28:30 +0200
+
+ tuklib_cpucores: Use cpuset_getaffinity() on FreeBSD if available.
+
+ In FreeBSD, cpuset_getaffinity() is the preferred way to get
+ the number of available cores.
+
+ Thanks to Rui Paulo for the patch. I edited it slightly, but
+ hopefully I didn't break anything.
+
+ m4/tuklib_cpucores.m4 | 23 ++++++++++++++++++++++-
+ src/common/tuklib_cpucores.c | 18 ++++++++++++++++++
+ 2 files changed, 40 insertions(+), 1 deletion(-)
+
+commit eb61bc58c20769cac4d05f363b9c0e8c9c71a560
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-09 22:08:37 +0200
+
+ xzdiff: Make the mktemp usage compatible with FreeBSD's mktemp.
+
+ Thanks to Rui Paulo for the fix.
+
+ src/scripts/xzdiff.in | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+commit b9a5b6b7a29029680af733082b6a46e0fc01623a
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-02-03 21:45:53 +0200
+
+ Add a few casts to tuklib_integer.h to silence possible warnings.
+
+ I heard that Visual Studio 2013 gave warnings without the casts.
+
+ Thanks to Gabi Davar.
+
+ src/common/tuklib_integer.h | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+commit c45757135f40e4a0de730ba5fff0100219493982
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-26 21:24:39 +0200
+
+ liblzma: Set LZMA_MEMCMPLEN_EXTRA depending on the compare method.
+
+ src/liblzma/common/memcmplen.h | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+commit 3c500174ed5485f550972a2a6109c361e875f069
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-26 20:40:16 +0200
+
+ Update THANKS.
+
+ THANKS | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit fec88d41e672d9e197c9442aecf02bd0dfa6d516
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-26 20:39:28 +0200
+
+ liblzma: Silence harmless Valgrind errors.
+
+ Thanks to Torsten Rupp for reporting this. I had
+ forgotten to run Valgrind before the 5.2.0 release.
+
+ src/liblzma/lz/lz_encoder.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit a9b45badfec0928d20a27c7176c005fa637f7d1e
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-09 21:50:19 +0200
+
+ xz: Fix comments.
+
+ src/xz/file_io.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+commit 541aee6dd4aa97a809aba281475a21b641bb89e2
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-09 21:35:06 +0200
+
+ Update THANKS.
+
+ THANKS | 1 +
+ 1 file changed, 1 insertion(+)
+
+commit 4170edc914655310d2363baccf5e615e09b04911
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-09 21:34:06 +0200
+
+ xz: Don't fail if stdout doesn't support O_NONBLOCK.
+
+ This is similar to the case with stdin.
+
+ Thanks to Brad Smith for the bug report and testing
+ on OpenBSD.
+
+ src/xz/file_io.c | 36 +++++++++++++++---------------------
+ 1 file changed, 15 insertions(+), 21 deletions(-)
+
+commit 04bbc0c2843c50c8ad1cba42b937118e38b0508d
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-07 19:18:20 +0200
+
+ xz: Fix a memory leak in DOS-specific code.
+
+ src/xz/file_io.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f0f1f6c7235ffa901cf76fe18e33749e200b3eea
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-07 19:08:06 +0200
+
+ xz: Don't fail if stdin doesn't support O_NONBLOCK.
+
+ It's a problem at least on OpenBSD which doesn't support
+ O_NONBLOCK on e.g. /dev/null. I'm not surprised if it's
+ a problem on other OSes too since this behavior is allowed
+ in POSIX-1.2008.
+
+ The code relying on this behavior was committed in June 2013
+ and included in 5.1.3alpha released on 2013-10-26. Clearly
+ the development releases only get limited testing.
+
+ src/xz/file_io.c | 18 +++++++-----------
+ 1 file changed, 7 insertions(+), 11 deletions(-)
+
+commit d2d484647d9d9d679f03c75abb0404f67069271c
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2015-01-06 20:30:15 +0200
+
+ Tests: Don't hide unexpected error messages in test_files.sh.
+
+ Hiding them makes no sense since normally there's no error
+ when testing the "good" files. With "bad" files errors are
+ expected and then it makes sense to keep the messages hidden.
+
+ tests/test_files.sh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit aae6a6aeda51cf94a47e39ad624728f9bee75e30
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2014-12-30 11:17:16 +0200
+
+ Update Solaris notes in INSTALL.
+
+ Mention the possible "make check" failure on Solaris in the
+ Solaris-specific section of INSTALL. It was already in
+ section 4.5 but it is better mention it in the OS-specific
+ section too.
+
+ INSTALL | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 7815112153178800a3521b9f31960e7cdc26cfba
+Author: Lasse Collin <lasse.collin@tukaani.org>
+Date: 2014-12-26 12:00:05 +0200
+
+ Build: POSIX shell isn't required if scripts are disabled.
+
+ INSTALL | 3 ++-
+ configure.ac | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
commit a0cd05ee71d330b79ead6eb9222e1b24e1559d3a
Author: Lasse Collin <lasse.collin@tukaani.org>
Date: 2014-12-21 20:48:37 +0200
diff --git a/contrib/xz/THANKS b/contrib/xz/THANKS
index f5f539c..05d20bd 100644
--- a/contrib/xz/THANKS
+++ b/contrib/xz/THANKS
@@ -67,6 +67,7 @@ has been important. :-) In alphabetical order:
- Andre Noll
- Peter O'Gorman
- Peter Pallinger
+ - Rui Paulo
- Igor Pavlov
- Diego Elio Pettenò
- Elbert Pol
@@ -78,12 +79,14 @@ has been important. :-) In alphabetical order:
- Eric S. Raymond
- Cristian Rodríguez
- Christian von Roques
+ - Torsten Rupp
- Jukka Salmi
- Alexandre Sauvé
- Benno Schulenberg
- Andreas Schwab
- Dan Shechter
- Stuart Shelton
+ - Brad Smith
- Jonathan Stott
- Dan Stromberg
- Vincent Torri
diff --git a/contrib/xz/src/common/tuklib_cpucores.c b/contrib/xz/src/common/tuklib_cpucores.c
index 7574bc9..e235fd1 100644
--- a/contrib/xz/src/common/tuklib_cpucores.c
+++ b/contrib/xz/src/common/tuklib_cpucores.c
@@ -18,6 +18,11 @@
# endif
# include <windows.h>
+// FreeBSD
+#elif defined(TUKLIB_CPUCORES_CPUSET)
+# include <sys/param.h>
+# include <sys/cpuset.h>
+
#elif defined(TUKLIB_CPUCORES_SYSCTL)
# ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
@@ -44,6 +49,19 @@ tuklib_cpucores(void)
GetSystemInfo(&sysinfo);
ret = sysinfo.dwNumberOfProcessors;
+#elif defined(TUKLIB_CPUCORES_CPUSET)
+ cpuset_t set;
+ if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
+ sizeof(set), &set) == 0) {
+# ifdef CPU_COUNT
+ ret = CPU_COUNT(&set);
+# else
+ for (unsigned i = 0; i < CPU_SETSIZE; ++i)
+ if (CPU_ISSET(i, &set))
+ ++ret;
+# endif
+ }
+
#elif defined(TUKLIB_CPUCORES_SYSCTL)
int name[2] = { CTL_HW, HW_NCPU };
int cpus;
diff --git a/contrib/xz/src/common/tuklib_integer.h b/contrib/xz/src/common/tuklib_integer.h
index e6daa77..a7fda67 100644
--- a/contrib/xz/src/common/tuklib_integer.h
+++ b/contrib/xz/src/common/tuklib_integer.h
@@ -321,8 +321,8 @@ unaligned_read32le(const uint8_t *buf)
static inline void
unaligned_write16be(uint8_t *buf, uint16_t num)
{
- buf[0] = num >> 8;
- buf[1] = num;
+ buf[0] = (uint8_t)(num >> 8);
+ buf[1] = (uint8_t)num;
return;
}
@@ -330,8 +330,8 @@ unaligned_write16be(uint8_t *buf, uint16_t num)
static inline void
unaligned_write16le(uint8_t *buf, uint16_t num)
{
- buf[0] = num;
- buf[1] = num >> 8;
+ buf[0] = (uint8_t)num;
+ buf[1] = (uint8_t)(num >> 8);
return;
}
@@ -339,10 +339,10 @@ unaligned_write16le(uint8_t *buf, uint16_t num)
static inline void
unaligned_write32be(uint8_t *buf, uint32_t num)
{
- buf[0] = num >> 24;
- buf[1] = num >> 16;
- buf[2] = num >> 8;
- buf[3] = num;
+ buf[0] = (uint8_t)(num >> 24);
+ buf[1] = (uint8_t)(num >> 16);
+ buf[2] = (uint8_t)(num >> 8);
+ buf[3] = (uint8_t)num;
return;
}
@@ -350,10 +350,10 @@ unaligned_write32be(uint8_t *buf, uint32_t num)
static inline void
unaligned_write32le(uint8_t *buf, uint32_t num)
{
- buf[0] = num;
- buf[1] = num >> 8;
- buf[2] = num >> 16;
- buf[3] = num >> 24;
+ buf[0] = (uint8_t)num;
+ buf[1] = (uint8_t)(num >> 8);
+ buf[2] = (uint8_t)(num >> 16);
+ buf[3] = (uint8_t)(num >> 24);
return;
}
diff --git a/contrib/xz/src/liblzma/api/lzma/version.h b/contrib/xz/src/liblzma/api/lzma/version.h
index d9614da..9682155 100644
--- a/contrib/xz/src/liblzma/api/lzma/version.h
+++ b/contrib/xz/src/liblzma/api/lzma/version.h
@@ -22,7 +22,7 @@
*/
#define LZMA_VERSION_MAJOR 5
#define LZMA_VERSION_MINOR 2
-#define LZMA_VERSION_PATCH 0
+#define LZMA_VERSION_PATCH 1
#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE
#ifndef LZMA_VERSION_COMMIT
diff --git a/contrib/xz/src/liblzma/common/memcmplen.h b/contrib/xz/src/liblzma/common/memcmplen.h
index f66e7cd..c1efc9e 100644
--- a/contrib/xz/src/liblzma/common/memcmplen.h
+++ b/contrib/xz/src/liblzma/common/memcmplen.h
@@ -19,11 +19,6 @@
# include <immintrin.h>
#endif
-/// How many extra bytes lzma_memcmplen() may read. This depends on
-/// the method but since it is just a few bytes the biggest possible
-/// value is used here.
-#define LZMA_MEMCMPLEN_EXTRA 16
-
/// Find out how many equal bytes the two buffers have.
///
@@ -39,6 +34,11 @@
///
/// \return Number of equal bytes in the buffers is returned.
/// This is always at least len and at most limit.
+///
+/// \note LZMA_MEMCMPLEN_EXTRA defines how many extra bytes may be read.
+/// It's rounded up to 2^n. This extra amount needs to be
+/// allocated in the buffers being used. It needs to be
+/// initialized too to keep Valgrind quiet.
static inline uint32_t lzma_attribute((__always_inline__))
lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
uint32_t len, uint32_t limit)
@@ -59,6 +59,7 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
// to be a good method. This may be fine on other 64-bit CPUs too.
// On big endian one should use xor instead of subtraction and switch
// to __builtin_clzll().
+#define LZMA_MEMCMPLEN_EXTRA 8
while (len < limit) {
const uint64_t x = *(const uint64_t *)(buf1 + len)
- *(const uint64_t *)(buf2 + len);
@@ -91,6 +92,7 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
// version is sometimes significantly faster and sometimes
// slightly slower than this SSE2 version, so this SSE2
// version isn't used on x86-64.
+# define LZMA_MEMCMPLEN_EXTRA 16
while (len < limit) {
const uint32_t x = 0xFFFF ^ _mm_movemask_epi8(_mm_cmpeq_epi8(
_mm_loadu_si128((const __m128i *)(buf1 + len)),
@@ -116,6 +118,7 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && !defined(WORDS_BIGENDIAN)
// Generic 32-bit little endian method
+# define LZMA_MEMCMPLEN_EXTRA 4
while (len < limit) {
uint32_t x = *(const uint32_t *)(buf1 + len)
- *(const uint32_t *)(buf2 + len);
@@ -138,6 +141,7 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && defined(WORDS_BIGENDIAN)
// Generic 32-bit big endian method
+# define LZMA_MEMCMPLEN_EXTRA 4
while (len < limit) {
uint32_t x = *(const uint32_t *)(buf1 + len)
^ *(const uint32_t *)(buf2 + len);
@@ -160,6 +164,7 @@ lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
#else
// Simple portable version that doesn't use unaligned access.
+# define LZMA_MEMCMPLEN_EXTRA 0
while (len < limit && buf1[len] == buf2[len])
++len;
diff --git a/contrib/xz/src/liblzma/lz/lz_encoder.c b/contrib/xz/src/liblzma/lz/lz_encoder.c
index 2033844..01dfc06 100644
--- a/contrib/xz/src/liblzma/lz/lz_encoder.c
+++ b/contrib/xz/src/liblzma/lz/lz_encoder.c
@@ -110,6 +110,12 @@ fill_window(lzma_coder *coder, const lzma_allocator *allocator,
coder->mf.write_pos = write_pos;
+ // Silence Valgrind. lzma_memcmplen() can read extra bytes
+ // and Valgrind will give warnings if those bytes are uninitialized
+ // because Valgrind cannot see that the values of the uninitialized
+ // bytes are eventually ignored.
+ memzero(coder->mf.buffer + write_pos, LZMA_MEMCMPLEN_EXTRA);
+
// If end of stream has been reached or flushing completed, we allow
// the encoder to process all the input (that is, read_pos is allowed
// to reach write_pos). Otherwise we keep keep_size_after bytes
diff --git a/contrib/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c b/contrib/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
index 8922cbd..9b30347 100644
--- a/contrib/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
+++ b/contrib/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
@@ -152,7 +152,7 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf,
// the old buf pointer instead of recalculating it with mf_ptr().
++buf;
- const uint32_t limit = len_main - 1;
+ const uint32_t limit = my_max(2, len_main - 1);
for (uint32_t i = 0; i < REPS; ++i) {
if (memcmp(buf, buf - coder->reps[i] - 1, limit) == 0) {
diff --git a/contrib/xz/src/xz/file_io.c b/contrib/xz/src/xz/file_io.c
index f135cf7..20f512a 100644
--- a/contrib/xz/src/xz/file_io.c
+++ b/contrib/xz/src/xz/file_io.c
@@ -82,13 +82,26 @@ io_init(void)
// we are root.
warn_fchown = geteuid() == 0;
- if (pipe(user_abort_pipe)
- || fcntl(user_abort_pipe[0], F_SETFL, O_NONBLOCK)
- == -1
- || fcntl(user_abort_pipe[1], F_SETFL, O_NONBLOCK)
- == -1)
+ // Create a pipe for the self-pipe trick. If pipe2() is available,
+ // we can avoid the fcntl() calls.
+# ifdef HAVE_PIPE2
+ if (pipe2(user_abort_pipe, O_NONBLOCK))
message_fatal(_("Error creating a pipe: %s"),
strerror(errno));
+# else
+ if (pipe(user_abort_pipe))
+ message_fatal(_("Error creating a pipe: %s"),
+ strerror(errno));
+
+ // Make both ends of the pipe non-blocking.
+ for (unsigned i = 0; i < 2; ++i) {
+ int flags = fcntl(user_abort_pipe[i], F_GETFL);
+ if (flags == -1 || fcntl(user_abort_pipe[i], F_SETFL,
+ flags | O_NONBLOCK) == -1)
+ message_fatal(_("Error creating a pipe: %s"),
+ strerror(errno));
+ }
+# endif
#endif
#ifdef __DJGPP__
@@ -393,7 +406,11 @@ io_open_src_real(file_pair *pair)
#ifdef TUKLIB_DOSLIKE
setmode(STDIN_FILENO, O_BINARY);
#else
- // Enable O_NONBLOCK for stdin.
+ // Try to set stdin to non-blocking mode. It won't work
+ // e.g. on OpenBSD if stdout is e.g. /dev/null. In such
+ // case we proceed as if stdin were non-blocking anyway
+ // (in case of /dev/null it will be in practice). The
+ // same applies to stdout in io_open_dest_real().
stdin_flags = fcntl(STDIN_FILENO, F_GETFL);
if (stdin_flags == -1) {
message_error(_("Error getting the file status flags "
@@ -402,17 +419,10 @@ io_open_src_real(file_pair *pair)
return true;
}
- if ((stdin_flags & O_NONBLOCK) == 0) {
- if (fcntl(STDIN_FILENO, F_SETFL,
- stdin_flags | O_NONBLOCK) == -1) {
- message_error(_("Error setting O_NONBLOCK "
- "on standard input: %s"),
- strerror(errno));
- return true;
- }
-
+ if ((stdin_flags & O_NONBLOCK) == 0
+ && fcntl(STDIN_FILENO, F_SETFL,
+ stdin_flags | O_NONBLOCK) != -1)
restore_stdin_flags = true;
- }
#endif
#ifdef HAVE_POSIX_FADVISE
// It will fail if stdin is a pipe and that's fine.
@@ -705,7 +715,10 @@ io_open_dest_real(file_pair *pair)
#ifdef TUKLIB_DOSLIKE
setmode(STDOUT_FILENO, O_BINARY);
#else
- // Set O_NONBLOCK if it isn't already set.
+ // Try to set O_NONBLOCK if it isn't already set.
+ // If it fails, we assume that stdout is non-blocking
+ // in practice. See the comments in io_open_src_real()
+ // for similar situation with stdin.
//
// NOTE: O_APPEND may be unset later in this function
// and it relies on stdout_flags being set here.
@@ -717,17 +730,10 @@ io_open_dest_real(file_pair *pair)
return true;
}
- if ((stdout_flags & O_NONBLOCK) == 0) {
- if (fcntl(STDOUT_FILENO, F_SETFL,
- stdout_flags | O_NONBLOCK) == -1) {
- message_error(_("Error setting O_NONBLOCK "
- "on standard output: %s"),
- strerror(errno));
- return true;
- }
-
- restore_stdout_flags = true;
- }
+ if ((stdout_flags & O_NONBLOCK) == 0
+ && fcntl(STDOUT_FILENO, F_SETFL,
+ stdout_flags | O_NONBLOCK) != -1)
+ restore_stdout_flags = true;
#endif
} else {
pair->dest_name = suffix_get_dest_name(pair->src_name);
@@ -742,6 +748,7 @@ io_open_dest_real(file_pair *pair)
message_error("%s: Refusing to write to "
"a DOS special file",
pair->dest_name);
+ free(pair->dest_name);
return true;
}
@@ -751,6 +758,7 @@ io_open_dest_real(file_pair *pair)
message_error("%s: Output file is the same "
"as the input file",
pair->dest_name);
+ free(pair->dest_name);
return true;
}
}
@@ -829,23 +837,24 @@ io_open_dest_real(file_pair *pair)
if (lseek(STDOUT_FILENO, 0, SEEK_END) == -1)
return false;
- // O_NONBLOCK was set earlier in this function
- // so it must be kept here too. If this
- // fcntl() call fails, we continue but won't
+ // Construct the new file status flags.
+ // If O_NONBLOCK was set earlier in this
+ // function, it must be kept here too.
+ int flags = stdout_flags & ~O_APPEND;
+ if (restore_stdout_flags)
+ flags |= O_NONBLOCK;
+
+ // If this fcntl() fails, we continue but won't
// try to create sparse output. The original
// flags will still be restored if needed (to
// unset O_NONBLOCK) when the file is finished.
- if (fcntl(STDOUT_FILENO, F_SETFL,
- (stdout_flags | O_NONBLOCK)
- & ~O_APPEND) == -1)
+ if (fcntl(STDOUT_FILENO, F_SETFL, flags) == -1)
return false;
// Disabling O_APPEND succeeded. Mark
// that the flags should be restored
- // in io_close_dest(). This quite likely was
- // already set when enabling O_NONBLOCK but
- // just in case O_NONBLOCK was already set,
- // set this again here.
+ // in io_close_dest(). (This may have already
+ // been set when enabling O_NONBLOCK.)
restore_stdout_flags = true;
} else if (lseek(STDOUT_FILENO, 0, SEEK_CUR)
diff --git a/etc/Makefile b/etc/Makefile
index 95f75f9..e5ade7f 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -215,12 +215,12 @@ distribution:
@false
.endif
cd ${.CURDIR}; \
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
${BIN1} ${DESTDIR}/etc; \
cap_mkdb ${CAP_MKDB_ENDIAN} ${DESTDIR}/etc/login.conf; \
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 755 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 755 \
${BIN2} ${DESTDIR}/etc; \
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 600 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 600 \
master.passwd nsmb.conf opieaccess ${DESTDIR}/etc;
.if ${MK_AT} == "no"
sed -i "" -e 's;.*/usr/libexec/atrun;#&;' ${DESTDIR}/etc/crontab
@@ -261,74 +261,74 @@ distribution:
${_+_}cd ${.CURDIR}/../share/termcap; ${MAKE} etc-termcap
${_+_}cd ${.CURDIR}/../usr.sbin/rmt; ${MAKE} etc-rmt
${_+_}cd ${.CURDIR}/pam.d; ${MAKE} install
- cd ${.CURDIR}; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 0444 \
+ cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 0444 \
${BSM_ETC_OPEN_FILES} ${BSM_ETC_DIR}
- cd ${.CURDIR}; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 0600 \
+ cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 0600 \
${BSM_ETC_RESTRICTED_FILES} ${BSM_ETC_DIR}
- cd ${.CURDIR}; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 0500 \
+ cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 0500 \
${BSM_ETC_EXEC_FILES} ${BSM_ETC_DIR}
.if ${MK_UNBOUND} != "no"
if [ ! -e ${DESTDIR}/etc/unbound ]; then \
- ${INSTALL_SYMLINK} -T package=unbound ../var/unbound ${DESTDIR}/etc/unbound; \
+ ${INSTALL_SYMLINK} ../var/unbound ${DESTDIR}/etc/unbound; \
fi
.endif
.if ${MK_SENDMAIL} != "no"
${_+_}cd ${.CURDIR}/sendmail; ${MAKE} distribution
.endif
.if ${MK_OPENSSH} != "no"
- cd ${.CURDIR}; ${INSTALL} -T package=ssh,config -o ${BINOWN} -g ${BINGRP} -m 644 \
+ cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
${SSH} ${DESTDIR}/etc/ssh
.endif
.if ${MK_OPENSSL} != "no"
- cd ${.CURDIR}; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 \
+ cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
${SSL} ${DESTDIR}/etc/ssl
.endif
.if ${MK_KERBEROS} != "no"
cd ${.CURDIR}/root; \
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
dot.k5login ${DESTDIR}/root/.k5login;
.endif
cd ${.CURDIR}/root; \
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
dot.profile ${DESTDIR}/root/.profile; \
rm -f ${DESTDIR}/.profile; \
ln ${DESTDIR}/root/.profile ${DESTDIR}/.profile
.if ${MK_TCSH} != "no"
cd ${.CURDIR}/root; \
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
dot.cshrc ${DESTDIR}/root/.cshrc; \
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
dot.login ${DESTDIR}/root/.login; \
rm -f ${DESTDIR}/.cshrc; \
ln ${DESTDIR}/root/.cshrc ${DESTDIR}/.cshrc
.endif
- cd ${.CURDIR}/mtree; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 \
+ cd ${.CURDIR}/mtree; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \
${MTREE} ${DESTDIR}/etc/mtree
.if ${MK_PPP} != "no"
- cd ${.CURDIR}/ppp; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 600 \
+ cd ${.CURDIR}/ppp; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 600 \
${PPPCNF} ${DESTDIR}/etc/ppp
.endif
.if ${MK_MAIL} != "no"
- cd ${.CURDIR}/mail; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 \
+ cd ${.CURDIR}/mail; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 \
${ETCMAIL} ${DESTDIR}/etc/mail
if [ -d ${DESTDIR}/etc/mail -a -f ${DESTDIR}/etc/mail/aliases -a \
! -f ${DESTDIR}/etc/aliases ]; then \
ln -s mail/aliases ${DESTDIR}/etc/aliases; \
fi
.endif
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g operator -m 664 /dev/null \
+ ${INSTALL} -o ${BINOWN} -g operator -m 664 /dev/null \
${DESTDIR}/etc/dumpdates
.if ${MK_LOCATE} != "no"
- ${INSTALL} ${TAG_ARGS} -o nobody -g ${BINGRP} -m 644 /dev/null \
+ ${INSTALL} -o nobody -g ${BINGRP} -m 644 /dev/null \
${DESTDIR}/var/db/locate.database
.endif
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 644 ${.CURDIR}/minfree \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 ${.CURDIR}/minfree \
${DESTDIR}/var/crash
- cd ${.CURDIR}/..; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 \
+ cd ${.CURDIR}/..; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \
${FREEBSD} ${DESTDIR}/
.if ${MK_BOOT} != "no"
.if exists(${.CURDIR}/../sys/${MACHINE}/conf/GENERIC.hints)
- ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 \
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \
${.CURDIR}/../sys/${MACHINE}/conf/GENERIC.hints \
${DESTDIR}/boot/device.hints
.endif
@@ -377,11 +377,12 @@ distrib-dirs: ${MTREES:N/*}
shift; \
d=$$1; \
test "$$d" == "/" && d=""; \
- d=$$d; \
+ d=${DISTBASE}$$d; \
shift; \
- ${ECHO} "${MTREE_CMD:N-W} -C -f $$m -K all | " \
+ test -d ${DESTDIR}/$$d || mkdir -p ${DESTDIR}/$$d; \
+ ${ECHO} "${MTREE_CMD:N-W} -C -f $$m -K uname,gname | " \
"sed s#^\.#.$$d# | ${METALOG.add}" ; \
- ${MTREE_CMD:N-W} -C -f $$m -K all | sed s#^\.#.$$d# | \
+ ${MTREE_CMD:N-W} -C -f $$m -K uname,gname | sed s#^\.#.$$d# | \
${METALOG.add} ; \
done; true
.endif
@@ -420,7 +421,7 @@ distrib-dirs: ${MTREES:N/*}
.endif
etc-examples:
- cd ${.CURDIR}; ${INSTALL} ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 \
+ cd ${.CURDIR}; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \
${BIN1} ${BIN2} nsmb.conf opieaccess \
${DESTDIR}/usr/share/examples/etc
${_+_}cd ${.CURDIR}/defaults; ${MAKE} install \
diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf
index 3499465..ef3b861 100644
--- a/etc/defaults/rc.conf
+++ b/etc/defaults/rc.conf
@@ -88,7 +88,7 @@ fsck_y_enable="NO" # Set to YES to do fsck -y if the initial preen fails.
fsck_y_flags="" # Additional flags for fsck -y
background_fsck="YES" # Attempt to run fsck in the background where possible.
background_fsck_delay="60" # Time to wait (seconds) before starting the fsck.
-netfs_types="nfs:NFS oldnfs:OLDNFS smbfs:SMB" # Net filesystems.
+netfs_types="nfs:NFS smbfs:SMB" # Net filesystems.
extra_netfs_types="NO" # List of network extra filesystem types for delayed
# mount at startup (or NO).
@@ -324,7 +324,6 @@ autounmountd_flags="" # Flags to autounmountd(8) (if autofs enabled).
nfs_client_enable="NO" # This host is an NFS client (or NO).
nfs_access_cache="60" # Client cache timeout in seconds
nfs_server_enable="NO" # This host is an NFS server (or NO).
-oldnfs_server_enable="NO" # Run the old NFS server (YES/NO).
nfs_server_flags="-u -t" # Flags to nfsd (if enabled).
mountd_enable="NO" # Run mountd (or NO).
mountd_flags="-r" # Flags to mountd (if NFS server enabled).
@@ -649,7 +648,7 @@ devfs_system_ruleset="" # The name (NOT number) of a ruleset to apply to /dev
devfs_set_rulesets="" # A list of /mount/dev=ruleset_name settings to
# apply (must be mounted already, i.e. fstab(5))
devfs_load_rulesets="YES" # Enable to always load the default rulesets
-performance_cx_lowest="Cmax" # Online CPU idle state
+performance_cx_lowest="C2" # Online CPU idle state
performance_cpu_freq="NONE" # Online CPU frequency
economy_cx_lowest="Cmax" # Offline CPU idle state
economy_cpu_freq="NONE" # Offline CPU frequency
diff --git a/etc/login.conf b/etc/login.conf
index 5481f46..ae6b8a0 100644
--- a/etc/login.conf
+++ b/etc/login.conf
@@ -26,7 +26,7 @@ default:\
:passwd_format=sha512:\
:copyright=/etc/COPYRIGHT:\
:welcome=/etc/motd:\
- :setenv=MAIL=/var/mail/$,BLOCKSIZE=K:\
+ :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,LC_COLLATE=C:\
:path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin ~/bin:\
:nologin=/var/run/nologin:\
:cputime=unlimited:\
@@ -81,8 +81,8 @@ root:\
# Russian Users Accounts. Setup proper environment variables.
#
russian|Russian Users Accounts:\
- :charset=KOI8-R:\
- :lang=ru_RU.KOI8-R:\
+ :charset=UTF-8:\
+ :lang=ru_RU.UTF-8:\
:tc=default:
diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist
index 55b20aa..48ec8b4 100644
--- a/etc/mtree/BSD.include.dist
+++ b/etc/mtree/BSD.include.dist
@@ -5,8 +5,6 @@
/set type=dir uname=root gname=wheel mode=0755
.
- altq
- ..
arpa
..
atf-c
@@ -254,6 +252,8 @@
..
..
net
+ altq
+ ..
..
net80211
..
diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
index 35e1c06..a863436 100644
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -354,7 +354,19 @@
..
..
sys
+ aio
+ ..
+ fifo
+ ..
+ file
+ ..
kern
+ execve
+ ..
+ ..
+ kqueue
+ ..
+ mqueue
..
netinet
..
@@ -392,6 +404,8 @@
unlink
..
..
+ vm
+ ..
..
usr.bin
apply
@@ -500,6 +514,8 @@
..
cmp
..
+ col
+ ..
comm
..
cut
@@ -532,6 +548,8 @@
regress.multitest.out
..
..
+ soelim
+ ..
timeout
..
tr
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index 9d46478..b182894 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -292,14 +292,6 @@
..
07.mail
..
- 10.exref
- ..
- 11.edit
- ..
- 12.vi
- ..
- 13.viref
- ..
18.msdiffs
..
19.memacros
diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile
index 10fe26b..d75bdc0 100644
--- a/etc/rc.d/Makefile
+++ b/etc/rc.d/Makefile
@@ -266,6 +266,10 @@ FILES+= routed
FILES+= sendmail
.endif
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.if ${MK_TIMED} != "no"
FILES+= timed
.endif
diff --git a/etc/rc.d/devd b/etc/rc.d/devd
index c7288e4..53532cc 100755
--- a/etc/rc.d/devd
+++ b/etc/rc.d/devd
@@ -4,7 +4,7 @@
#
# PROVIDE: devd
-# REQUIRE: netif
+# REQUIRE: netif ldconfig
# BEFORE: NETWORKING mountcritremote
# KEYWORD: nojail shutdown
diff --git a/etc/rc.d/hostid b/etc/rc.d/hostid
index c4545bd..281b241 100755
--- a/etc/rc.d/hostid
+++ b/etc/rc.d/hostid
@@ -1,6 +1,7 @@
#!/bin/sh
#
# Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+# Copyright (c) 2015 Xin LI <delphij@FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -55,23 +56,66 @@ hostid_set()
${SYSCTL} kern.hostid=${id} >/dev/null
}
-hostid_hardware()
+valid_hostid()
{
- uuid=`kenv -q smbios.system.uuid`
+ uuid=$1
+
x="[0-9a-f]"
y=$x$x$x$x
+
+ # Check against a blacklist before
+ # accepting the UUID.
case "${uuid}" in
+ 00000000-0000-0000-0000-000000000000)
+ ;;
+ 00020003-0004-0005-0006-000700080009)
+ ;;
+ 03000200-0400-0500-0006-000700080009)
+ ;;
+ 07090201-0103-0301-0807-060504030201)
+ ;;
+ 11111111-1111-1111-1111-111111111111)
+ ;;
+ 11111111-2222-3333-4444-555555555555)
+ ;;
+ 4c4c4544-0000-2010-8020-80c04f202020)
+ ;;
+ 58585858-5858-5858-5858-585858585858)
+ ;;
+ 890e2d14-cacd-45d1-ae66-bc80e8bfeb0f)
+ ;;
+ 8e275844-178f-44a8-aceb-a7d7e5178c63)
+ ;;
+ dc698397-fa54-4cf2-82c8-b1b5307a6a7f)
+ ;;
+ fefefefe-fefe-fefe-fefe-fefefefefefe)
+ ;;
+ *-ffff-ffff-ffff-ffffffffffff)
+ ;;
$y$y-$y-$y-$y-$y$y$y)
- echo "${uuid}"
+ return 0
;;
esac
+
+ return 1
+}
+
+hostid_hardware()
+{
+ uuid=`kenv -q smbios.system.uuid`
+
+ if valid_hostid $uuid; then
+ echo "${uuid}"
+ fi
}
hostid_generate()
{
# First look for UUID in hardware.
uuid=`hostid_hardware`
- if [ -z ${uuid} ]; then
+ if [ -z "${uuid}" ]; then
+ warn "hostid: unable to figure out a UUID from DMI data, generating a new one"
+ sleep 2
# If not found, fall back to software-generated UUID.
uuid=`uuidgen`
fi
@@ -92,11 +136,15 @@ hostid_start()
{
# If ${hostid_file} already exists, we take UUID from there.
if [ -r ${hostid_file} ]; then
- hostid_set `cat ${hostid_file}`
- else
- # No hostid file, generate UUID.
- hostid_generate
+ read saved_hostid < ${hostid_file}
+ if valid_hostid ${saved_hostid}; then
+ hostid_set `cat ${hostid_file}`
+ exit 0
+ fi
fi
+
+ # No hostid file, generate UUID.
+ hostid_generate
}
load_rc_config $name
diff --git a/etc/rc.d/hostid_save b/etc/rc.d/hostid_save
index fca0521..9741aec 100755
--- a/etc/rc.d/hostid_save
+++ b/etc/rc.d/hostid_save
@@ -16,12 +16,19 @@ rcvar="hostid_enable"
hostid_save()
{
- if [ ! -r ${hostid_file} ]; then
- $SYSCTL_N kern.hostuuid > ${hostid_file}
- if [ $? -ne 0 ]; then
- warn "could not store hostuuid in ${hostid_file}."
+ current_hostid=`$SYSCTL_N kern.hostuuid`
+
+ if [ -r ${hostid_file} ]; then
+ read saved_hostid < ${hostid_file}
+ if [ ${saved_hostid} = ${current_hostid} ]; then
+ exit 0
fi
fi
+
+ echo ${current_hostid} > ${hostid_file}
+ if [ $? -ne 0 ]; then
+ warn "could not store hostuuid in ${hostid_file}."
+ fi
}
load_rc_config $name
diff --git a/etc/rc.d/mountd b/etc/rc.d/mountd
index f3ebfdb..a7ad6c2 100755
--- a/etc/rc.d/mountd
+++ b/etc/rc.d/mountd
@@ -33,12 +33,6 @@ mountd_precmd()
fi
fi
- # If oldnfs_server_enable is yes, force use of the old NFS server
- #
- if checkyesno oldnfs_server_enable; then
- rc_flags="-o ${rc_flags}"
- fi
-
if checkyesno zfs_enable; then
rc_flags="${rc_flags} /etc/exports /etc/zfs/exports"
fi
diff --git a/etc/rc.d/nfsd b/etc/rc.d/nfsd
index e067ad1..8c67308 100755
--- a/etc/rc.d/nfsd
+++ b/etc/rc.d/nfsd
@@ -19,40 +19,25 @@ sig_stop="USR1"
nfsd_precmd()
{
- if checkyesno oldnfs_server_enable; then
- rc_flags="-o ${nfs_server_flags}"
-
- # Load the module now, so that the vfs.nfsrv sysctl
- # oids are available.
- load_kld nfsserver
-
- if checkyesno nfs_reserved_port_only; then
- echo 'NFS on reserved port only=YES'
- sysctl vfs.nfsrv.nfs_privport=1 > /dev/null
- else
- sysctl vfs.nfsrv.nfs_privport=0 > /dev/null
- fi
+ rc_flags="${nfs_server_flags}"
+
+ # Load the modules now, so that the vfs.nfsd sysctl
+ # oids are available.
+ load_kld nfsd
+
+ if checkyesno nfs_reserved_port_only; then
+ echo 'NFS on reserved port only=YES'
+ sysctl vfs.nfsd.nfs_privport=1 > /dev/null
+ else
+ sysctl vfs.nfsd.nfs_privport=0 > /dev/null
+ fi
+
+ if checkyesno nfsv4_server_enable; then
+ sysctl vfs.nfsd.server_max_nfsvers=4 > /dev/null
+ force_depend nfsuserd || err 1 "Cannot run nfsuserd"
else
- rc_flags="${nfs_server_flags}"
-
- # Load the modules now, so that the vfs.nfsd sysctl
- # oids are available.
- load_kld nfsd
-
- if checkyesno nfs_reserved_port_only; then
- echo 'NFS on reserved port only=YES'
- sysctl vfs.nfsd.nfs_privport=1 > /dev/null
- else
- sysctl vfs.nfsd.nfs_privport=0 > /dev/null
- fi
-
- if checkyesno nfsv4_server_enable; then
- sysctl vfs.nfsd.server_max_nfsvers=4 > /dev/null
- force_depend nfsuserd || err 1 "Cannot run nfsuserd"
- else
- echo 'NFSv4 is disabled'
- sysctl vfs.nfsd.server_max_nfsvers=3 > /dev/null
- fi
+ echo 'NFSv4 is disabled'
+ sysctl vfs.nfsd.server_max_nfsvers=3 > /dev/null
fi
force_depend rpcbind || return 1
diff --git a/etc/rc.d/pflog b/etc/rc.d/pflog
index 3deceab..8f6bcb4 100755
--- a/etc/rc.d/pflog
+++ b/etc/rc.d/pflog
@@ -24,30 +24,30 @@ pflog_prestart()
{
load_kld pflog || return 1
+ # create pflog_dev interface if needed
+ if ! ifconfig $pflog_dev > /dev/null 2>&1; then
+ if ! ifconfig $pflog_dev create; then
+ warn "could not create $pflog_dev."
+ return 1
+ fi
+ fi
+
# set pflog_dev interface to up state
if ! ifconfig $pflog_dev up; then
warn "could not bring up $pflog_dev."
return 1
fi
+ # -p flag requires stripping pidfile's leading /var/run and trailing .pid
+ pidfile=$(echo $pidfile | sed -e 's|/var/run/||' -e 's|.pid$||')
+
# prepare the command line for pflogd
- rc_flags="-f $pflog_logfile -i $pflog_dev $rc_flags"
+ rc_flags="-p $pidfile -f $pflog_logfile -i $pflog_dev $rc_flags"
# report we're ready to run pflogd
return 0
}
-pflog_poststart() {
- # Allow child pflogd to settle
- sleep 0.10
- # More elegant(?) method for getting a unique pid
- if [ -f /var/run/pflogd.pid ]; then
- mv /var/run/pflogd.pid $pidfile
- else
- warn "/var/run/pflogd.pid does not exist. Too fast."
- fi
-}
-
pflog_poststop()
{
if ! ifconfig $pflog_dev down; then
@@ -70,29 +70,33 @@ pflog_resync()
load_rc_config $name
-# Check if spawning multiple pflogd
-echo "Starting pflogd: $pflog_instances"
-if [ "$pflog_instances" ] && [ -n "$pflog_instances" ]; then
- start_postcmd="pflog_poststart"
+# Check if spawning multiple pflogd and told what to spawn
+if [ -n "$2" ]; then
+ # Set required variables
+ eval pflog_dev=\$pflog_${2}_dev
+ eval pflog_logfile=\$pflog_${2}_logfile
+ eval pflog_flags=\$pflog_${2}_flags
+ # Check that required vars have non-zero length, warn if not.
+ if [ -z $pflog_dev ]; then
+ warn "pflog_dev not set"
+ continue
+ fi
+ if [ -z $pflog_logfile ]; then
+ warn "pflog_logfile not set"
+ continue
+ fi
+
+ # Provide a unique pidfile name for pflogd -p <pidfile> flag
+ pidfile="/var/run/pflogd.$2.pid"
+
+ # Override service name and execute command
+ name=$pflog_dev
+ run_rc_command "$1"
+# Check if spawning multiple pflogd and not told what to spawn
+elif [ "$pflog_instances" ] && [ -n "$pflog_instances" ]; then
# Interate through requested instances.
for i in $pflog_instances; do
- # Set required variables
- eval pflog_dev=\$pflog_${i}_dev
- eval pflog_logfile=\$pflog_${i}_logfile
- eval pflog_flags=\$pflog_${i}_flags
- # Check that required vars have non-zero length, warn if not.
- if [ -z $pflog_dev ]; then
- warn "pflog_dev not set"
- continue
- fi
- if [ -z $pflog_logfile ]; then
- warn "pflog_logfile not set"
- continue
- fi
- # pflogd sets a pidfile, but the name is hardcoded. Concoct a
- # unique pidfile name.
- pidfile="/var/run/pflogd.$i.pid"
- run_rc_command "$1"
+ /etc/rc.d/pflog $1 $i
done
else
# Typical case, spawn single instance only.
diff --git a/etc/tests/rc.d/Makefile b/etc/rc.d/tests/Makefile
index 368e8f4..368e8f4 100644
--- a/etc/tests/rc.d/Makefile
+++ b/etc/rc.d/tests/Makefile
diff --git a/etc/tests/rc.d/routing_test.sh b/etc/rc.d/tests/routing_test.sh
index 693af23..693af23 100755
--- a/etc/tests/rc.d/routing_test.sh
+++ b/etc/rc.d/tests/routing_test.sh
diff --git a/etc/tests/Makefile b/etc/tests/Makefile
index fd9efda..5aacd5b 100644
--- a/etc/tests/Makefile
+++ b/etc/tests/Makefile
@@ -7,6 +7,4 @@ TESTSDIR= ${TESTSBASE}/etc
.PATH: ${.CURDIR:H:H}/tests
KYUAFILE= yes
-TESTS_SUBDIRS+= rc.d
-
.include <bsd.test.mk>
diff --git a/gnu/lib/libgomp/Makefile b/gnu/lib/libgomp/Makefile
index 237c14a..d428bd3 100644
--- a/gnu/lib/libgomp/Makefile
+++ b/gnu/lib/libgomp/Makefile
@@ -12,7 +12,7 @@ SHLIB_MAJOR= 1
SRCS= alloc.c barrier.c critical.c env.c \
error.c iter.c loop.c ordered.c parallel.c sections.c \
single.c team.c work.c lock.c mutex.c proc.c sem.c \
- bar.c time.c fortran.c
+ bar.c time.c fortran.c affinity.c
SRCS+= gstdint.h libgomp_f.h omp.h omp_lib.h
INCS+= omp.h
diff --git a/gnu/lib/libgomp/config.h b/gnu/lib/libgomp/config.h
index 6ef541b..547e692 100644
--- a/gnu/lib/libgomp/config.h
+++ b/gnu/lib/libgomp/config.h
@@ -26,6 +26,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
+/* Define if pthread_{,attr_}{g,s}etaffinity_np is supported. */
+#undef HAVE_PTHREAD_AFFINITY_NP
+
/* Define to 1 if you have the <semaphore.h> header file. */
#define HAVE_SEMAPHORE_H 1
@@ -52,6 +55,9 @@
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#define HAVE_SYS_SYSCTL_H 1
+
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
diff --git a/gnu/usr.bin/cc/Makefile b/gnu/usr.bin/cc/Makefile
index abc9876..65dc087 100644
--- a/gnu/usr.bin/cc/Makefile
+++ b/gnu/usr.bin/cc/Makefile
@@ -12,7 +12,10 @@ SUBDIR+= cpp
.endif
.if ${MK_CXX} != "no"
-SUBDIR+= cc1plus c++ c++filt
+SUBDIR+= cc1plus c++
+.if ${MK_ELFTOOLCHAIN_TOOLS} == "no"
+SUBDIR+= c++filt
+.endif
.endif
.if ${MK_GCOV} != "no"
diff --git a/gnu/usr.bin/groff/src/preproc/Makefile b/gnu/usr.bin/groff/src/preproc/Makefile
index f208bf2..38942fb 100644
--- a/gnu/usr.bin/groff/src/preproc/Makefile
+++ b/gnu/usr.bin/groff/src/preproc/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-SUBDIR= eqn grn html pic refer soelim tbl
+SUBDIR= eqn grn html pic refer tbl
SUBDIR_PARALLEL=
diff --git a/include/Makefile b/include/Makefile
index 46b24f5..d7badd7 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -50,6 +50,7 @@ LSUBDIRS= cam/ata cam/scsi \
geom/cache geom/concat geom/eli geom/gate geom/journal geom/label \
geom/mirror geom/mountver geom/multipath geom/nop \
geom/raid geom/raid3 geom/shsec geom/stripe geom/virstor \
+ net/altq \
netgraph/atm netgraph/netflow \
security/audit \
security/mac_biba security/mac_bsdextended security/mac_lomac \
@@ -144,7 +145,7 @@ compat:
-p ${DESTDIR}${INCLUDEDIR}
copies:
-.for i in ${LDIRS} ${LSUBDIRS} ${LSUBSUBDIRS} altq crypto machine machine/pc \
+.for i in ${LDIRS} ${LSUBDIRS} ${LSUBSUBDIRS} crypto machine machine/pc \
${_MARCHS}
.if exists(${DESTDIR}${INCLUDEDIR}/$i)
cd ${DESTDIR}${INCLUDEDIR}/$i; \
@@ -179,9 +180,6 @@ copies:
cd ${.CURDIR}/../sys/dev/pci; \
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 pcireg.h \
${DESTDIR}${INCLUDEDIR}/dev/pci
- cd ${.CURDIR}/../sys/contrib/altq/altq; \
- ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 *.h \
- ${DESTDIR}${INCLUDEDIR}/altq
cd ${.CURDIR}/../sys/fs/cd9660/; \
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 *.h \
${DESTDIR}${INCLUDEDIR}/isofs/cd9660
@@ -279,11 +277,6 @@ symlinks:
ln -fs ../../../../../sys/$i/$$h ${DESTDIR}${INCLUDEDIR}/$i; \
done
.endfor
- cd ${.CURDIR}/../sys/contrib/altq/altq; \
- for h in *.h; do \
- ln -fs ../../../sys/contrib/altq/altq/$$h \
- ${DESTDIR}${INCLUDEDIR}/altq; \
- done
.if ${MK_IPFILTER} != "no"
cd ${.CURDIR}/../sys/contrib/ipfilter/netinet; \
for h in *.h; do \
diff --git a/include/iconv.h b/include/iconv.h
index c07d02e..51f0603 100644
--- a/include/iconv.h
+++ b/include/iconv.h
@@ -53,7 +53,7 @@ typedef struct __tag_iconv_t *iconv_t;
__BEGIN_DECLS
iconv_t iconv_open(const char *, const char *);
-size_t iconv(iconv_t, const char ** __restrict,
+size_t iconv(iconv_t, char ** __restrict,
size_t * __restrict, char ** __restrict,
size_t * __restrict);
int iconv_close(iconv_t);
@@ -62,7 +62,7 @@ int iconv_close(iconv_t);
*/
int __iconv_get_list(char ***, size_t *, __iconv_bool);
void __iconv_free_list(char **, size_t);
-size_t __iconv(iconv_t, const char **, size_t *, char **,
+size_t __iconv(iconv_t, char **, size_t *, char **,
size_t *, __uint32_t, size_t *);
#define __ICONV_F_HIDE_INVALID 0x0001
diff --git a/include/pthread.h b/include/pthread.h
index ee66c65..8b59223 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -144,19 +144,25 @@ struct _pthread_cleanup_info {
*/
__BEGIN_DECLS
int pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
-int pthread_attr_destroy(pthread_attr_t *);
+int pthread_attr_destroy(pthread_attr_t *) __nonnull(1);
int pthread_attr_getstack(const pthread_attr_t * __restrict,
- void ** __restrict, size_t * __restrict);
-int pthread_attr_getstacksize(const pthread_attr_t *, size_t *);
+ void ** __restrict, size_t * __restrict)
+ __nonnull_all;
+int pthread_attr_getstacksize(const pthread_attr_t *, size_t *)
+ __nonnull_all;
int pthread_attr_getguardsize(const pthread_attr_t *, size_t *);
int pthread_attr_getstackaddr(const pthread_attr_t *, void **);
-int pthread_attr_getdetachstate(const pthread_attr_t *, int *);
-int pthread_attr_init(pthread_attr_t *);
-int pthread_attr_setstacksize(pthread_attr_t *, size_t);
-int pthread_attr_setguardsize(pthread_attr_t *, size_t);
-int pthread_attr_setstack(pthread_attr_t *, void *, size_t);
+int pthread_attr_getdetachstate(const pthread_attr_t *, int *)
+ __nonnull_all;
+int pthread_attr_init(pthread_attr_t *) __nonnull(1);
+int pthread_attr_setstacksize(pthread_attr_t *, size_t)
+ __nonnull(1);
+int pthread_attr_setguardsize(pthread_attr_t *, size_t)
+ __nonnull(1);
+int pthread_attr_setstack(pthread_attr_t *, void *, size_t)
+ __nonnull(1);
int pthread_attr_setstackaddr(pthread_attr_t *, void *);
-int pthread_attr_setdetachstate(pthread_attr_t *, int);
+int pthread_attr_setdetachstate(pthread_attr_t *, int) __nonnull(1);
int pthread_barrier_destroy(pthread_barrier_t *);
int pthread_barrier_init(pthread_barrier_t *,
const pthread_barrierattr_t *, unsigned);
@@ -164,7 +170,7 @@ int pthread_barrier_wait(pthread_barrier_t *);
int pthread_barrierattr_destroy(pthread_barrierattr_t *);
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *,
int *);
-int pthread_barrierattr_init(pthread_barrierattr_t *);
+int pthread_barrierattr_init(pthread_barrierattr_t *) __nonnull(1);
int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int);
#define pthread_cleanup_push(cleanup_routine, cleanup_arg) \
@@ -180,98 +186,109 @@ int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int);
__pthread_cleanup_pop_imp(execute); \
}
-int pthread_condattr_destroy(pthread_condattr_t *);
+int pthread_condattr_destroy(pthread_condattr_t *) __nonnull(1);
int pthread_condattr_getclock(const pthread_condattr_t *,
- clockid_t *);
-int pthread_condattr_getpshared(const pthread_condattr_t *, int *);
-int pthread_condattr_init(pthread_condattr_t *);
-int pthread_condattr_setclock(pthread_condattr_t *, clockid_t);
-int pthread_condattr_setpshared(pthread_condattr_t *, int);
-int pthread_cond_broadcast(pthread_cond_t *);
-int pthread_cond_destroy(pthread_cond_t *);
+ clockid_t *) __nonnull_all;
+int pthread_condattr_getpshared(const pthread_condattr_t *, int *)
+ __nonnull_all;
+int pthread_condattr_init(pthread_condattr_t *) __nonnull(1);
+int pthread_condattr_setclock(pthread_condattr_t *, clockid_t)
+ __nonnull(1);
+int pthread_condattr_setpshared(pthread_condattr_t *, int)
+ __nonnull(1);
+int pthread_cond_broadcast(pthread_cond_t *)
+ __nonnull(1);
+int pthread_cond_destroy(pthread_cond_t *)
+ __nonnull(1);
int pthread_cond_init(pthread_cond_t *,
- const pthread_condattr_t *);
-int pthread_cond_signal(pthread_cond_t *);
+ const pthread_condattr_t *) __nonnull(1);
+int pthread_cond_signal(pthread_cond_t *) __nonnull(1);
int pthread_cond_timedwait(pthread_cond_t *,
pthread_mutex_t *__mutex, const struct timespec *)
- __requires_exclusive(*__mutex);
+ __nonnull_all __requires_exclusive(*__mutex);
int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *__mutex)
- __requires_exclusive(*__mutex);
+ __nonnull_all __requires_exclusive(*__mutex);
int pthread_create(pthread_t *, const pthread_attr_t *,
- void *(*) (void *), void *);
+ void *(*) (void *), void *) __nonnull(1) __nonnull(3);
int pthread_detach(pthread_t);
int pthread_equal(pthread_t, pthread_t);
void pthread_exit(void *) __dead2;
void *pthread_getspecific(pthread_key_t);
-int pthread_getcpuclockid(pthread_t, clockid_t *);
+int pthread_getcpuclockid(pthread_t, clockid_t *) __nonnull(2);
int pthread_join(pthread_t, void **);
int pthread_key_create(pthread_key_t *,
- void (*) (void *));
+ void (*) (void *)) __nonnull(1);
int pthread_key_delete(pthread_key_t);
-int pthread_mutexattr_init(pthread_mutexattr_t *);
-int pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int pthread_mutexattr_init(pthread_mutexattr_t *) __nonnull(1);
+int pthread_mutexattr_destroy(pthread_mutexattr_t *) __nonnull(1);
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *,
- int *);
-int pthread_mutexattr_gettype(pthread_mutexattr_t *, int *);
-int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
-int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int);
+ int *) __nonnull_all;
+int pthread_mutexattr_gettype(pthread_mutexattr_t *, int *)
+ __nonnull_all;
+int pthread_mutexattr_settype(pthread_mutexattr_t *, int)
+ __nonnull(1);
+int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int)
+ __nonnull(1);
int pthread_mutex_destroy(pthread_mutex_t *__mutex)
- __requires_unlocked(*__mutex);
+ __nonnull(1) __requires_unlocked(*__mutex);
int pthread_mutex_init(pthread_mutex_t *__mutex,
const pthread_mutexattr_t *)
- __requires_unlocked(*__mutex);
+ __nonnull(1) __requires_unlocked(*__mutex);
int pthread_mutex_lock(pthread_mutex_t *__mutex)
- __locks_exclusive(*__mutex);
+ __nonnull(1) __locks_exclusive(*__mutex);
int pthread_mutex_trylock(pthread_mutex_t *__mutex)
- __trylocks_exclusive(0, *__mutex);
+ __nonnull(1) __trylocks_exclusive(0, *__mutex);
int pthread_mutex_timedlock(pthread_mutex_t *__mutex,
const struct timespec *)
- __trylocks_exclusive(0, *__mutex);
+ __nonnull_all __trylocks_exclusive(0, *__mutex);
int pthread_mutex_unlock(pthread_mutex_t *__mutex)
- __unlocks(*__mutex);
-int pthread_once(pthread_once_t *, void (*) (void));
+ __nonnull(1) __unlocks(*__mutex);
+int pthread_once(pthread_once_t *, void (*) (void)) __nonnull_all;
int pthread_rwlock_destroy(pthread_rwlock_t *__rwlock)
- __requires_unlocked(*__rwlock);
+ __nonnull(1) __requires_unlocked(*__rwlock);
int pthread_rwlock_init(pthread_rwlock_t *__rwlock,
const pthread_rwlockattr_t *)
- __requires_unlocked(*__rwlock);
+ __nonnull(1) __requires_unlocked(*__rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock)
- __locks_shared(*__rwlock);
+ __nonnull(1) __locks_shared(*__rwlock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *__rwlock,
const struct timespec *)
- __trylocks_shared(0, *__rwlock);
+ __nonnull_all __trylocks_shared(0, *__rwlock);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *__rwlock,
const struct timespec *)
- __trylocks_exclusive(0, *__rwlock);
+ __nonnull_all __trylocks_exclusive(0, *__rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *__rwlock)
- __trylocks_shared(0, *__rwlock);
+ __nonnull(1) __trylocks_shared(0, *__rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *__rwlock)
- __trylocks_exclusive(0, *__rwlock);
+ __nonnull(1) __trylocks_exclusive(0, *__rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *__rwlock)
- __unlocks(*__rwlock);
+ __nonnull(1) __unlocks(*__rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock)
- __locks_exclusive(*__rwlock);
-int pthread_rwlockattr_destroy(pthread_rwlockattr_t *);
+ __nonnull(1) __locks_exclusive(*__rwlock);
+int pthread_rwlockattr_destroy(pthread_rwlockattr_t *)
+ __nonnull(1);
int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *,
int *);
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *,
- int *);
-int pthread_rwlockattr_init(pthread_rwlockattr_t *);
+ int *) __nonnull_all;
+int pthread_rwlockattr_init(pthread_rwlockattr_t *)
+ __nonnull(1);
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *, int);
-int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int);
+int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int)
+ __nonnull(1);
pthread_t pthread_self(void);
int pthread_setspecific(pthread_key_t, const void *);
int pthread_spin_init(pthread_spinlock_t *__spin, int)
- __requires_unlocked(*__spin);
+ __requires_unlocked(*__spin);
int pthread_spin_destroy(pthread_spinlock_t *__spin)
- __requires_unlocked(*__spin);
+ __requires_unlocked(*__spin);
int pthread_spin_lock(pthread_spinlock_t *__spin)
- __locks_exclusive(*__spin);
+ __locks_exclusive(*__spin);
int pthread_spin_trylock(pthread_spinlock_t *__spin)
- __trylocks_exclusive(0, *__spin);
+ __trylocks_exclusive(0, *__spin);
int pthread_spin_unlock(pthread_spinlock_t *__spin)
- __unlocks(*__spin);
+ __unlocks(*__spin);
int pthread_cancel(pthread_t);
int pthread_setcancelstate(int, int *);
int pthread_setcanceltype(int, int *);
@@ -295,18 +312,20 @@ int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int);
int pthread_attr_getinheritsched(const pthread_attr_t *, int *);
int pthread_attr_getschedparam(const pthread_attr_t *,
- struct sched_param *);
-int pthread_attr_getschedpolicy(const pthread_attr_t *, int *);
-int pthread_attr_getscope(const pthread_attr_t *, int *);
+ struct sched_param *) __nonnull_all;
+int pthread_attr_getschedpolicy(const pthread_attr_t *, int *)
+ __nonnull_all;
+int pthread_attr_getscope(const pthread_attr_t *, int *)
+ __nonnull_all;
int pthread_attr_setinheritsched(pthread_attr_t *, int);
int pthread_attr_setschedparam(pthread_attr_t *,
- const struct sched_param *);
-int pthread_attr_setschedpolicy(pthread_attr_t *, int);
-int pthread_attr_setscope(pthread_attr_t *, int);
+ const struct sched_param *) __nonnull(1) __nonnull(2);
+int pthread_attr_setschedpolicy(pthread_attr_t *, int) __nonnull(1);
+int pthread_attr_setscope(pthread_attr_t *, int) __nonnull(1);
int pthread_getschedparam(pthread_t pthread, int *,
- struct sched_param *);
+ struct sched_param *) __nonnull(2) __nonnull(3);
int pthread_setschedparam(pthread_t, int,
- const struct sched_param *);
+ const struct sched_param *) __nonnull(3);
#if __XSI_VISIBLE
int pthread_getconcurrency(void);
int pthread_setconcurrency(int);
diff --git a/include/signal.h b/include/signal.h
index dca19aa..895ccc3 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -78,10 +78,10 @@ int sigdelset(sigset_t *, int);
int sigemptyset(sigset_t *);
int sigfillset(sigset_t *);
int sigismember(const sigset_t *, int);
-int sigpending(sigset_t *);
+int sigpending(sigset_t *) __nonnull(1);
int sigprocmask(int, const sigset_t * __restrict, sigset_t * __restrict);
-int sigsuspend(const sigset_t *);
-int sigwait(const sigset_t * __restrict, int * __restrict);
+int sigsuspend(const sigset_t *) __nonnull(1);
+int sigwait(const sigset_t * __restrict, int * __restrict) __nonnull_all;
#endif
#if __POSIX_VISIBLE >= 199506 || __XSI_VISIBLE >= 600
diff --git a/include/stdlib.h b/include/stdlib.h
index 6669495..a5ef0e7 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -87,21 +87,22 @@ int atoi(const char *);
long atol(const char *);
void *bsearch(const void *, const void *, size_t,
size_t, int (*)(const void *, const void *));
-void *calloc(size_t, size_t) __malloc_like;
+void *calloc(size_t, size_t) __malloc_like __result_use_check
+ __alloc_size(1) __alloc_size(2);
div_t div(int, int) __pure2;
_Noreturn void exit(int);
void free(void *);
char *getenv(const char *);
long labs(long) __pure2;
ldiv_t ldiv(long, long) __pure2;
-void *malloc(size_t) __malloc_like;
+void *malloc(size_t) __malloc_like __result_use_check __alloc_size(1);
int mblen(const char *, size_t);
size_t mbstowcs(wchar_t * __restrict , const char * __restrict, size_t);
int mbtowc(wchar_t * __restrict, const char * __restrict, size_t);
void qsort(void *, size_t, size_t,
int (*)(const void *, const void *));
int rand(void);
-void *realloc(void *, size_t);
+void *realloc(void *, size_t) __result_use_check __alloc_size(2);
void srand(unsigned);
double strtod(const char * __restrict, char ** __restrict);
float strtof(const char * __restrict, char ** __restrict);
@@ -155,7 +156,7 @@ _Noreturn void _Exit(int);
* If we're in a mode greater than C99, expose C11 functions.
*/
#if __ISO_C_VISIBLE >= 2011 || __cplusplus >= 201103L
-void * aligned_alloc(size_t, size_t) __malloc_like;
+void * aligned_alloc(size_t, size_t) __malloc_like __alloc_size(2);
int at_quick_exit(void (*)(void));
_Noreturn void
quick_exit(int);
@@ -170,7 +171,8 @@ char *realpath(const char * __restrict, char * __restrict);
int rand_r(unsigned *); /* (TSF) */
#endif
#if __POSIX_VISIBLE >= 200112
-int posix_memalign(void **, size_t, size_t); /* (ADV) */
+int posix_memalign(void **, size_t, size_t) __nonnull(1)
+ __alloc_size(3); /* (ADV) */
int setenv(const char *, const char *, int);
int unsetenv(const char *);
#endif
@@ -301,7 +303,9 @@ void qsort_r(void *, size_t, size_t, void *,
int (*)(void *, const void *, const void *));
int radixsort(const unsigned char **, int, const unsigned char *,
unsigned);
-void *reallocf(void *, size_t);
+void *reallocarray(void *, size_t, size_t) __result_use_check __alloc_size(2)
+ __alloc_size(3);
+void *reallocf(void *, size_t) __alloc_size(2);
int rpmatch(const char *);
void setprogname(const char *);
int sradixsort(const unsigned char **, int, const unsigned char *,
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index 2542a20..9dfad77 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -25,7 +25,7 @@ LIBADD+= md
.if ${MK_ICONV} != "no"
# TODO: This can be changed back to CFLAGS once iconv works correctly
# with statically linked binaries.
-SHARED_CFLAGS+= -DHAVE_ICONV=1 -DHAVE_ICONV_H=1 -DICONV_CONST=const
+SHARED_CFLAGS+= -DHAVE_ICONV=1 -DHAVE_ICONV_H=1 -DICONV_CONST=
.endif
.if ${MACHINE_ARCH:Marm*} != "" || ${MACHINE_ARCH:Mmips*} != "" || \
diff --git a/lib/libarchive/config_freebsd.h b/lib/libarchive/config_freebsd.h
index 0df3f91..fbf429f 100644
--- a/lib/libarchive/config_freebsd.h
+++ b/lib/libarchive/config_freebsd.h
@@ -25,6 +25,8 @@
* $FreeBSD$
*/
+#include <osreldate.h>
+
/* FreeBSD 5.0 and later have ACL and extattr support. */
#if __FreeBSD__ > 4
#define HAVE_ACL_CREATE_ENTRY 1
@@ -220,6 +222,11 @@
#define HAVE_ZLIB_H 1
#define TIME_WITH_SYS_TIME 1
+#if __FreeBSD_version >= 1100056
+#define HAVE_FUTIMENS 1
+#define HAVE_UTIMENSAT 1
+#endif
+
/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */
#if __FreeBSD__ < 5
#define intmax_t int64_t
diff --git a/lib/libbluetooth/bluetooth.c b/lib/libbluetooth/bluetooth.c
index 23b7df0..bbcf007 100644
--- a/lib/libbluetooth/bluetooth.c
+++ b/lib/libbluetooth/bluetooth.c
@@ -30,7 +30,7 @@
* $Id: bluetooth.c,v 1.3 2003/05/20 23:04:30 max Exp $
* $FreeBSD$
*/
-
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/lib/libbluetooth/dev.c b/lib/libbluetooth/dev.c
index 1f9e745..a6295dd 100644
--- a/lib/libbluetooth/dev.c
+++ b/lib/libbluetooth/dev.c
@@ -30,6 +30,7 @@
* $FreeBSD$
*/
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <stdio.h>
#include <string.h>
diff --git a/lib/libbluetooth/hci.c b/lib/libbluetooth/hci.c
index 1ae6ff9..651c0dd 100644
--- a/lib/libbluetooth/hci.c
+++ b/lib/libbluetooth/hci.c
@@ -31,6 +31,7 @@
*/
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <inttypes.h>
#include <stdio.h>
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
index eed9070..93ab138 100644
--- a/lib/libc/Makefile
+++ b/lib/libc/Makefile
@@ -79,7 +79,8 @@ NOASM=
.include "${LIBC_SRCTOP}/net/Makefile.inc"
.include "${LIBC_SRCTOP}/nls/Makefile.inc"
.include "${LIBC_SRCTOP}/posix1e/Makefile.inc"
-.if ${LIBC_ARCH} != "amd64" && \
+.if ${LIBC_ARCH} != "aarch64" && \
+ ${LIBC_ARCH} != "amd64" && \
${LIBC_ARCH} != "powerpc64" && \
${LIBC_ARCH} != "sparc64" && \
${MACHINE_ARCH:Mmipsn32*} == "" && \
@@ -156,12 +157,10 @@ libkern.${LIBC_ARCH}:: ${KMSRCS}
${CP} ${.ALLSRC} ${DESTDIR}/sys/libkern/${LIBC_ARCH}
.endif
-.if ${MK_SYSCALL_COMPAT} != "no"
-CFLAGS+=-DSYSCALL_COMPAT
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
.endif
-.include <bsd.arch.inc.mk>
-
.include <bsd.lib.mk>
# Disable warnings in contributed sources.
diff --git a/lib/libc/Makefile.amd64 b/lib/libc/Makefile.amd64
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/libc/Makefile.amd64
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/libc/Makefile.i386 b/lib/libc/Makefile.i386
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/libc/Makefile.i386
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/libc/aarch64/Makefile.inc b/lib/libc/aarch64/Makefile.inc
index 8cbf181..5f17200 100644
--- a/lib/libc/aarch64/Makefile.inc
+++ b/lib/libc/aarch64/Makefile.inc
@@ -3,3 +3,7 @@
# Machine dependent definitions for the arm 64-bit architecture.
#
+# Long double is quad precision
+GDTOASRCS+=strtorQ.c
+MDSRCS+=machdep_ldisQ.c
+SYM_MAPS+=${LIBC_SRCTOP}/aarch64/Symbol.map
diff --git a/lib/libc/aarch64/SYS.h b/lib/libc/aarch64/SYS.h
new file mode 100644
index 0000000..e0be59d
--- /dev/null
+++ b/lib/libc/aarch64/SYS.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define _SYSCALL(name) \
+ mov x8, SYS_ ## name; \
+ svc 0
+
+#define SYSCALL(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ ret; \
+END(__sys_##name)
+
+#define PSEUDO(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ b.cs cerror; \
+ ret; \
+END(__sys_##name)
+
+#define RSYSCALL(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ b.cs cerror; \
+ ret; \
+END(__sys_##name)
diff --git a/lib/libc/aarch64/Symbol.map b/lib/libc/aarch64/Symbol.map
new file mode 100644
index 0000000..5b21000
--- /dev/null
+++ b/lib/libc/aarch64/Symbol.map
@@ -0,0 +1,29 @@
+/*
+ * $FreeBSD$
+ */
+
+/*
+ * This only needs to contain symbols that are not listed in
+ * symbol maps from other parts of libc (i.e., not found in
+ * stdlib/Symbol.map, string/Symbol.map, sys/Symbol.map, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ _setjmp;
+ _longjmp;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ vfork;
+ brk;
+ sbrk;
+};
+
+FBSDprivate_1.0 {
+ _set_tp;
+ curbrk;
+ minbrk;
+};
diff --git a/lib/libc/aarch64/_fpmath.h b/lib/libc/aarch64/_fpmath.h
new file mode 100644
index 0000000..71d0a71
--- /dev/null
+++ b/lib/libc/aarch64/_fpmath.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * Copyright (2) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+ unsigned long manl :64;
+ unsigned long manh :48;
+ unsigned int exp :15;
+ unsigned int sign :1;
+ } bits;
+ /* TODO andrew: Check the packing here */
+ struct {
+ unsigned long manl :64;
+ unsigned long manh :48;
+ unsigned int expsign :16;
+ } xbits;
+};
+
+#define LDBL_NBIT 0
+#define LDBL_IMPLICIT_NBIT
+#define mask_nbit_l(u) ((void)0)
+
+#define LDBL_MANH_SIZE 48
+#define LDBL_MANL_SIZE 64
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)((u).bits.manl >> 32); \
+ (a)[2] = (uint32_t)(u).bits.manh; \
+ (a)[3] = (uint32_t)((u).bits.manh >> 32); \
+} while(0)
diff --git a/lib/libc/aarch64/arith.h b/lib/libc/aarch64/arith.h
new file mode 100644
index 0000000..ecb1a33
--- /dev/null
+++ b/lib/libc/aarch64/arith.h
@@ -0,0 +1,19 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
diff --git a/lib/libc/aarch64/gd_qnan.h b/lib/libc/aarch64/gd_qnan.h
new file mode 100644
index 0000000..27e8d58
--- /dev/null
+++ b/lib/libc/aarch64/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0x0
+#define ld_QNAN2 0x0
+#define ld_QNAN3 0x7fff8000
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0x0
+#define ldus_QNAN4 0x0
diff --git a/lib/libc/aarch64/gen/Makefile.inc b/lib/libc/aarch64/gen/Makefile.inc
new file mode 100644
index 0000000..32dea00
--- /dev/null
+++ b/lib/libc/aarch64/gen/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+SRCS+= flt_rounds.c \
+ ldexp.c \
+ _setjmp.S \
+ _set_tp.c \
+ setjmp.S \
+ sigsetjmp.S \
+ trivial-getcontextx.c
diff --git a/lib/libc/sys/lseek.c b/lib/libc/aarch64/gen/_set_tp.c
index a086be1..a587b2e 100644
--- a/lib/libc/sys/lseek.c
+++ b/lib/libc/aarch64/gen/_set_tp.c
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,14 +10,11 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -27,30 +24,19 @@
* SUCH DAMAGE.
*/
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)lseek.c 8.1 (Berkeley) 6/17/93";
-#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <string.h>
#include <sys/types.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include "libc_private.h"
-/*
- * This function provides 64-bit offset padding that
- * is not supplied by GCC 1.X but is supplied by GCC 2.X.
- */
-off_t
-lseek(fd, offset, whence)
- int fd;
- off_t offset;
- int whence;
+#include <machine/sysarch.h>
+
+#include <stdlib.h>
+
+void
+_set_tp(void *tp)
{
- if (__getosreldate() >= 700051)
- return(__sys_lseek(fd, offset, whence));
- else
- return(__sys_freebsd6_lseek(fd, 0, offset, whence));
+ asm volatile("msr tpidr_el0, %0" : : "r"(tp));
}
diff --git a/lib/libc/aarch64/gen/_setjmp.S b/lib/libc/aarch64/gen/_setjmp.S
new file mode 100644
index 0000000..504423b
--- /dev/null
+++ b/lib/libc/aarch64/gen/_setjmp.S
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+ENTRY(_setjmp)
+ /* Store the magic value and stack pointer */
+ ldr x8, .Lmagic
+ mov x9, sp
+ stp x8, x9, [x0], #16
+
+ /* Store the general purpose registers and lr */
+ stp x19, x20, [x0], #16
+ stp x21, x22, [x0], #16
+ stp x23, x24, [x0], #16
+ stp x25, x26, [x0], #16
+ stp x27, x28, [x0], #16
+ stp x29, lr, [x0], #16
+
+#ifndef _STANDALONE
+ /* Store the vfp registers */
+ stp d8, d9, [x0], #16
+ stp d10, d11, [x0], #16
+ stp d12, d13, [x0], #16
+ stp d14, d15, [x0]
+#endif
+
+ /* Return value */
+ mov x0, #0
+ ret
+.Lmagic:
+ .align 3
+ .quad _JB_MAGIC__SETJMP
+END(_setjmp)
+
+ENTRY(_longjmp)
+ /* Check the magic value */
+ ldr x8, [x0], #8
+ ldr x9, .Lmagic
+ cmp x8, x9
+ b.ne botch
+
+ /* Restore the stack pointer */
+ ldr x8, [x0], #8
+ mov sp, x8
+
+ /* Restore the general purpose registers and lr */
+ ldp x19, x20, [x0], #16
+ ldp x21, x22, [x0], #16
+ ldp x23, x24, [x0], #16
+ ldp x25, x26, [x0], #16
+ ldp x27, x28, [x0], #16
+ ldp x29, lr, [x0], #16
+
+#ifndef _STANDALONE
+ /* Restore the vfp registers */
+ ldp d8, d9, [x0], #16
+ ldp d10, d11, [x0], #16
+ ldp d12, d13, [x0], #16
+ ldp d14, d15, [x0]
+#endif
+
+ /* Load the return value */
+ mov x0, x1
+ ret
+
+botch:
+#ifdef _STANDALONE
+ b botch
+#else
+ bl _C_LABEL(longjmperror)
+ bl _C_LABEL(abort)
+#endif
+END(_longjmp)
diff --git a/lib/libc/sys/pread.c b/lib/libc/aarch64/gen/flt_rounds.c
index 7566566..6f8eeeb 100644
--- a/lib/libc/sys/pread.c
+++ b/lib/libc/aarch64/gen/flt_rounds.c
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
+/*-
+ * Copyright (c) 2012 Ian Lepore <freebsd@damnhippie.dyndns.org>
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,14 +10,11 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -27,31 +24,26 @@
* SUCH DAMAGE.
*/
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)mmap.c 8.1 (Berkeley) 6/17/93";
-#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include "libc_private.h"
-/*
- * This function provides 64-bit offset padding that
- * is not supplied by GCC 1.X but is supplied by GCC 2.X.
- */
-ssize_t
-pread(fd, buf, nbyte, offset)
- int fd;
- void *buf;
- size_t nbyte;
- off_t offset;
+#include <fenv.h>
+#include <float.h>
+
+static int map[] = {
+ 1, /* round to nearest */
+ 2, /* round to positive infinity */
+ 3, /* round to negative infinity */
+ 0 /* round to zero */
+};
+
+int
+__flt_rounds(void)
{
+ uint64_t fpcr;
- if (__getosreldate() >= 700051)
- return (__sys_pread(fd, buf, nbyte, offset));
- else
- return (__sys_freebsd6_pread(fd, buf, nbyte, 0, offset));
+ asm volatile("mrs %0, fpcr" : "=r" (fpcr));
+ return map[(fpcr >> 22) & 3];
}
diff --git a/lib/libc/aarch64/gen/setjmp.S b/lib/libc/aarch64/gen/setjmp.S
new file mode 100644
index 0000000..80a9484
--- /dev/null
+++ b/lib/libc/aarch64/gen/setjmp.S
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+ENTRY(setjmp)
+ sub sp, sp, #16
+ stp x0, lr, [sp]
+
+ /* Store the signal mask */
+ add x2, x0, #(_JB_SIGMASK * 8) /* oset */
+ mov x1, #0 /* set */
+ mov x0, #1 /* SIG_BLOCK */
+ bl sigprocmask
+
+ ldp x0, lr, [sp]
+ add sp, sp, #16
+
+ /* Store the magic value and stack pointer */
+ ldr x8, .Lmagic
+ mov x9, sp
+ stp x8, x9, [x0], #16
+
+ /* Store the general purpose registers and lr */
+ stp x19, x20, [x0], #16
+ stp x21, x22, [x0], #16
+ stp x23, x24, [x0], #16
+ stp x25, x26, [x0], #16
+ stp x27, x28, [x0], #16
+ stp x29, lr, [x0], #16
+
+ /* Store the vfp registers */
+ stp d8, d9, [x0], #16
+ stp d10, d11, [x0], #16
+ stp d12, d13, [x0], #16
+ stp d14, d15, [x0]
+
+ /* Return value */
+ mov x0, #0
+ ret
+.Lmagic:
+ .align 3
+ .quad _JB_MAGIC_SETJMP
+END(setjmp)
+
+ENTRY(longjmp)
+ sub sp, sp, #32
+ stp x0, lr, [sp]
+ str x1, [sp, #16]
+
+ /* Restore the signal mask */
+ mov x1, #0 /* oset */
+ add x1, x0, #(_JB_SIGMASK * 8) /* set */
+ mov x0, #3 /* SIG_BLOCK */
+ bl sigprocmask
+
+ ldr x1, [sp, #16]
+ ldp x0, lr, [sp]
+ add sp, sp, #32
+
+ /* Check the magic value */
+ ldr x8, [x0], #8
+ ldr x9, .Lmagic
+ cmp x8, x9
+ b.ne botch
+
+ /* Restore the stack pointer */
+ ldr x8, [x0], #8
+ mov sp, x8
+
+ /* Restore the general purpose registers and lr */
+ ldp x19, x20, [x0], #16
+ ldp x21, x22, [x0], #16
+ ldp x23, x24, [x0], #16
+ ldp x25, x26, [x0], #16
+ ldp x27, x28, [x0], #16
+ ldp x29, lr, [x0], #16
+
+ /* Restore the vfp registers */
+ ldp d8, d9, [x0], #16
+ ldp d10, d11, [x0], #16
+ ldp d12, d13, [x0], #16
+ ldp d14, d15, [x0]
+
+ /* Load the return value */
+ mov x0, x1
+ ret
+
+botch:
+ bl _C_LABEL(longjmperror)
+ bl _C_LABEL(abort)
+END(longjmp)
diff --git a/lib/libc/aarch64/gen/sigsetjmp.S b/lib/libc/aarch64/gen/sigsetjmp.S
new file mode 100644
index 0000000..8a13c9f
--- /dev/null
+++ b/lib/libc/aarch64/gen/sigsetjmp.S
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+ENTRY(sigsetjmp)
+ cmp x1, #0
+ b.eq _C_LABEL(_setjmp)
+ b _C_LABEL(setjmp)
+END(sigsetjmp)
+
+ENTRY(siglongjmp)
+ /* Load the _setjmp magic */
+ ldr x2, .Lmagic
+ ldr x3, [x0]
+
+ /* Check the magic */
+ cmp x2, x3
+ b.eq _C_LABEL(_longjmp)
+ b _C_LABEL(longjmp)
+.Lmagic:
+ .align 3
+ .quad _JB_MAGIC__SETJMP
+END(siglongjmp)
diff --git a/lib/libc/aarch64/sys/Makefile.inc b/lib/libc/aarch64/sys/Makefile.inc
new file mode 100644
index 0000000..cb56f73
--- /dev/null
+++ b/lib/libc/aarch64/sys/Makefile.inc
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+SRCS+= trivial-vdso_tc.c
+
+#MDASM= ptrace.S
+MDASM= brk.S \
+ cerror.S \
+ pipe.S \
+ sbrk.S \
+ shmat.S \
+ sigreturn.S \
+ syscall.S \
+ vfork.S
+
+# Don't generate default code for these syscalls:
+NOASM= break.o \
+ exit.o \
+ getlogin.o \
+ openbsd_poll.o \
+ sstk.o \
+ vfork.o \
+ yield.o
+
+PSEUDO= _exit.o \
+ _getlogin.o
diff --git a/lib/libc/aarch64/sys/brk.S b/lib/libc/aarch64/sys/brk.S
new file mode 100644
index 0000000..09167b6
--- /dev/null
+++ b/lib/libc/aarch64/sys/brk.S
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .data
+ .align 3
+ .globl _C_LABEL(minbrk)
+ .type _C_LABEL(minbrk),#object
+_C_LABEL(minbrk):
+ .quad _C_LABEL(_end)
+
+ .text
+/*
+ * int brk(const void *addr);
+ */
+ENTRY(_brk)
+ WEAK_REFERENCE(_brk, brk)
+
+ /* Load the address of minbrk */
+#ifdef __PIC__
+ adrp x2, :got:minbrk
+ ldr x3, [x2, #:got_lo12:minbrk]
+#else
+ ldr x3, .Lminbrk
+#endif
+
+ /* Get the minimum allowable brk address */
+ ldr x2, [x3]
+
+ /* Validate the address */
+ cmp x0, x2
+ b.ge 1f
+ /* Invalid, set it to the minimum */
+ mov x0, x2
+
+ /* Backup the new address */
+1: mov x4, x0
+
+ /* Update for this value, will overwrite x0 and x1 */
+ _SYSCALL(break)
+ b.cs cerror
+
+#ifdef __PIC__
+ adrp x2, :got:curbrk
+ ldr x3, [x2, #:got_lo12:curbrk]
+#else
+ ldr x3, .Lcurbrk
+#endif
+
+ /* Store the new curbrk value */
+ str x4, [x3]
+
+ /* Return success */
+ mov x0, #0
+ ret
+
+#ifndef __PIC__
+.Lcurbrk:
+ .quad _C_LABEL(curbrk)
+.Lminbrk:
+ .quad _C_LABEL(minbrk)
+#endif
+END(_brk)
diff --git a/lib/libc/aarch64/sys/cerror.S b/lib/libc/aarch64/sys/cerror.S
new file mode 100644
index 0000000..26c61bc
--- /dev/null
+++ b/lib/libc/aarch64/sys/cerror.S
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(cerror)
+ sub sp, sp, #16
+ stp x0, lr, [sp]
+ bl _C_LABEL(__error)
+ ldp x1, lr, [sp]
+ str x1, [x0]
+ movn x0, #0
+ movn x1, #0
+ add sp, sp, #16
+ ret
+END(cerror)
diff --git a/lib/libc/aarch64/sys/pipe.S b/lib/libc/aarch64/sys/pipe.S
new file mode 100644
index 0000000..6b1cf24
--- /dev/null
+++ b/lib/libc/aarch64/sys/pipe.S
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(__sys_pipe)
+ WEAK_REFERENCE(__sys_pipe, pipe)
+
+ /* Backup the pointer passed to us */
+ mov x2, x0
+
+ /* Make the syscall */
+ _SYSCALL(pipe)
+ b.cs cerror
+
+ /* Store the result */
+ str w0, [x2, #0]
+ str w1, [x2, #4]
+
+ /* Return */
+ mov x0, #0
+ ret
+END(__sys_pipe)
diff --git a/lib/libc/aarch64/sys/sbrk.S b/lib/libc/aarch64/sys/sbrk.S
new file mode 100644
index 0000000..db9d7e1
--- /dev/null
+++ b/lib/libc/aarch64/sys/sbrk.S
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .data
+ .align 3
+ .global _C_LABEL(curbrk)
+ .type _C_LABEL(curbrk),#object
+_C_LABEL(curbrk):
+ .quad _C_LABEL(_end)
+
+ .text
+/*
+ * void *sbrk(intptr_t incr);
+ */
+ENTRY(_sbrk)
+ WEAK_REFERENCE(_sbrk, sbrk)
+
+ /* Load the address of curbrk */
+#ifdef __PIC__
+ adrp x2, :got:curbrk
+ ldr x3, [x2, #:got_lo12:curbrk]
+#else
+ ldr x3, .Lcurbrk
+#endif
+
+ /* Get the current brk address */
+ ldr x2, [x3]
+
+ /* Calculate the new value */
+ add x0, x2, x0
+ mov x4, x0
+
+ /* Update for this value, will overwrite x0 and x1 */
+ _SYSCALL(break)
+ b.cs cerror
+
+ /* Load the old value to return */
+ ldr x0, [x3]
+
+ /* Store the new curbrk value */
+ str x4, [x3]
+
+ ret
+#ifndef __PIC__
+.Lcurbrk:
+ .quad _C_LABEL(curbrk)
+#endif
+END(_sbrk)
diff --git a/lib/libc/aarch64/sys/shmat.S b/lib/libc/aarch64/sys/shmat.S
new file mode 100644
index 0000000..c0fb34f
--- /dev/null
+++ b/lib/libc/aarch64/sys/shmat.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(shmat)
diff --git a/lib/libc/aarch64/sys/sigreturn.S b/lib/libc/aarch64/sys/sigreturn.S
new file mode 100644
index 0000000..21ec1e4
--- /dev/null
+++ b/lib/libc/aarch64/sys/sigreturn.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(sigreturn)
diff --git a/lib/libc/aarch64/sys/syscall.S b/lib/libc/aarch64/sys/syscall.S
new file mode 100644
index 0000000..6314835
--- /dev/null
+++ b/lib/libc/aarch64/sys/syscall.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(syscall)
diff --git a/lib/libc/aarch64/sys/vfork.S b/lib/libc/aarch64/sys/vfork.S
new file mode 100644
index 0000000..daecd1f
--- /dev/null
+++ b/lib/libc/aarch64/sys/vfork.S
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+ENTRY(__sys_vfork)
+ WEAK_REFERENCE(__sys_vfork, vfork)
+ WEAK_REFERENCE(__sys_vfork, _vfork)
+ mov x2, lr
+ _SYSCALL(vfork)
+ b.cs cerror
+ sub x1, x1, #1
+ and x0, x0, x1
+ mov lr, x2
+ ret
+END(__sys_vfork)
diff --git a/lib/libc/amd64/sys/Makefile.inc b/lib/libc/amd64/sys/Makefile.inc
index 8e0d614..46ea955 100644
--- a/lib/libc/amd64/sys/Makefile.inc
+++ b/lib/libc/amd64/sys/Makefile.inc
@@ -11,6 +11,3 @@ MDASM= vfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \
NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o vfork.o yield.o
PSEUDO= _getlogin.o _exit.o
-.if ${MK_SYSCALL_COMPAT} != "no"
-PSEUDO+= _pread.o _pwrite.o _lseek.o _mmap.o _ftruncate.o _truncate.o
-.endif
diff --git a/lib/libc/arm/sys/Makefile.inc b/lib/libc/arm/sys/Makefile.inc
index f36ab71..60c2dc3 100644
--- a/lib/libc/arm/sys/Makefile.inc
+++ b/lib/libc/arm/sys/Makefile.inc
@@ -8,6 +8,3 @@ MDASM= Ovfork.S brk.S cerror.S pipe.S ptrace.S sbrk.S shmat.S sigreturn.S syscal
NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o vfork.o yield.o
PSEUDO= _exit.o _getlogin.o
-.if ${MK_SYSCALL_COMPAT} != "no"
-PSEUDO+= _pread.o _pwrite.o _lseek.o _mmap.o _ftruncate.o _truncate.o
-.endif
diff --git a/lib/libc/gen/_once_stub.c b/lib/libc/gen/_once_stub.c
index d2acc29..c45565a 100644
--- a/lib/libc/gen/_once_stub.c
+++ b/lib/libc/gen/_once_stub.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
index 7635fbc..1ca8334 100644
--- a/lib/libc/gen/fts.c
+++ b/lib/libc/gen/fts.c
@@ -905,12 +905,13 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
if (ISSET(FTS_LOGICAL) || follow) {
if (fstatat(dfd, path, sbp, 0)) {
saved_errno = errno;
- if (!fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
- errno = 0;
- return (FTS_SLNONE);
+ if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
+ p->fts_errno = saved_errno;
+ goto err;
}
- p->fts_errno = saved_errno;
- goto err;
+ errno = 0;
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SLNONE);
}
} else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
p->fts_errno = errno;
diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3
index 120f4a0..85c37b1 100644
--- a/lib/libc/gen/getutxent.3
+++ b/lib/libc/gen/getutxent.3
@@ -475,4 +475,4 @@ They replaced the
.In utmp.h
interface.
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/nice.3 b/lib/libc/gen/nice.3
index 8ce13af..b04c8f4 100644
--- a/lib/libc/gen/nice.3
+++ b/lib/libc/gen/nice.3
@@ -87,7 +87,7 @@ The
function conforms to
.St -p1003.1-2008
except for the return value.
-This implementation returns 0 upon successful completion but
+This implementation returns 0 upon successful completion but
the standard requires returning the new nice value,
which could be \-1.
.Sh HISTORY
diff --git a/lib/libc/gen/posix_spawn.3 b/lib/libc/gen/posix_spawn.3
index 52e8171..2c9131b 100644
--- a/lib/libc/gen/posix_spawn.3
+++ b/lib/libc/gen/posix_spawn.3
@@ -457,4 +457,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawn_file_actions_addopen.3 b/lib/libc/gen/posix_spawn_file_actions_addopen.3
index b28f396..0b57999b 100644
--- a/lib/libc/gen/posix_spawn_file_actions_addopen.3
+++ b/lib/libc/gen/posix_spawn_file_actions_addopen.3
@@ -200,4 +200,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawn_file_actions_init.3 b/lib/libc/gen/posix_spawn_file_actions_init.3
index eda2a1d..380eed7 100644
--- a/lib/libc/gen/posix_spawn_file_actions_init.3
+++ b/lib/libc/gen/posix_spawn_file_actions_init.3
@@ -101,4 +101,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getflags.3 b/lib/libc/gen/posix_spawnattr_getflags.3
index b5995ce..2571f4a 100644
--- a/lib/libc/gen/posix_spawnattr_getflags.3
+++ b/lib/libc/gen/posix_spawnattr_getflags.3
@@ -108,4 +108,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getpgroup.3 b/lib/libc/gen/posix_spawnattr_getpgroup.3
index 91b3e5c..cfc1b54 100644
--- a/lib/libc/gen/posix_spawnattr_getpgroup.3
+++ b/lib/libc/gen/posix_spawnattr_getpgroup.3
@@ -93,4 +93,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getschedparam.3 b/lib/libc/gen/posix_spawnattr_getschedparam.3
index a137200..5eef96e 100644
--- a/lib/libc/gen/posix_spawnattr_getschedparam.3
+++ b/lib/libc/gen/posix_spawnattr_getschedparam.3
@@ -97,4 +97,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getschedpolicy.3 b/lib/libc/gen/posix_spawnattr_getschedpolicy.3
index 3e79d4b..5276de5 100644
--- a/lib/libc/gen/posix_spawnattr_getschedpolicy.3
+++ b/lib/libc/gen/posix_spawnattr_getschedpolicy.3
@@ -95,4 +95,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getsigdefault.3 b/lib/libc/gen/posix_spawnattr_getsigdefault.3
index 8878332..a81c714 100644
--- a/lib/libc/gen/posix_spawnattr_getsigdefault.3
+++ b/lib/libc/gen/posix_spawnattr_getsigdefault.3
@@ -95,4 +95,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getsigmask.3 b/lib/libc/gen/posix_spawnattr_getsigmask.3
index 4f9c014..be15d9d 100644
--- a/lib/libc/gen/posix_spawnattr_getsigmask.3
+++ b/lib/libc/gen/posix_spawnattr_getsigmask.3
@@ -95,4 +95,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_init.3 b/lib/libc/gen/posix_spawnattr_init.3
index 388fe5a..b4ec52c 100644
--- a/lib/libc/gen/posix_spawnattr_init.3
+++ b/lib/libc/gen/posix_spawnattr_init.3
@@ -120,4 +120,4 @@ and
functions first appeared in
.Fx 8.0 .
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/setproctitle.c b/lib/libc/gen/setproctitle.c
index cd705fb..9dff328 100644
--- a/lib/libc/gen/setproctitle.c
+++ b/lib/libc/gen/setproctitle.c
@@ -42,9 +42,10 @@ __FBSDID("$FreeBSD$");
* 1: old_ps_strings at the very top of the stack.
* 2: old_ps_strings at SPARE_USRSPACE below the top of the stack.
* 3: ps_strings at the very top of the stack.
- * This attempts to support a kernel built in the #2 and #3 era.
- */
-
+ * We only support a kernel providing #3 style ps_strings.
+ *
+ * For historical purposes, a definition of the old ps_strings structure
+ * and location is preserved below:
struct old_ps_strings {
char *old_ps_argvstr;
int old_ps_nargvstr;
@@ -53,6 +54,7 @@ struct old_ps_strings {
};
#define OLD_PS_STRINGS ((struct old_ps_strings *) \
(USRSTACK - SPARE_USRSPACE - sizeof(struct old_ps_strings)))
+ */
#include <stdarg.h>
@@ -136,41 +138,38 @@ setproctitle(const char *fmt, ...)
ps_strings = (struct ps_strings *)ul_ps_strings;
}
- /* PS_STRINGS points to zeroed memory on a style #2 kernel */
- if (ps_strings->ps_argvstr) {
- /* style #3 */
- if (oargc == -1) {
- /* Record our original args */
- oargc = ps_strings->ps_nargvstr;
- oargv = ps_strings->ps_argvstr;
- for (i = len = 0; i < oargc; i++) {
- /*
- * The program may have scribbled into its
- * argv array, e.g., to remove some arguments.
- * If that has happened, break out before
- * trying to call strlen on a NULL pointer.
- */
- if (oargv[i] == NULL) {
- oargc = i;
- break;
- }
- snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s",
- len ? " " : "", oargv[i]);
- if (len)
- len++;
- len += strlen(oargv[i]);
- if (len >= SPT_BUFSIZE)
- break;
+ /*
+ * PS_STRINGS points to zeroed memory on a style #2 kernel.
+ * Should not happen.
+ */
+ if (ps_strings->ps_argvstr == NULL)
+ return;
+
+ /* style #3 */
+ if (oargc == -1) {
+ /* Record our original args */
+ oargc = ps_strings->ps_nargvstr;
+ oargv = ps_strings->ps_argvstr;
+ for (i = len = 0; i < oargc; i++) {
+ /*
+ * The program may have scribbled into its
+ * argv array, e.g., to remove some arguments.
+ * If that has happened, break out before
+ * trying to call strlen on a NULL pointer.
+ */
+ if (oargv[i] == NULL) {
+ oargc = i;
+ break;
}
+ snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s",
+ len != 0 ? " " : "", oargv[i]);
+ if (len != 0)
+ len++;
+ len += strlen(oargv[i]);
+ if (len >= SPT_BUFSIZE)
+ break;
}
- ps_strings->ps_nargvstr = nargc;
- ps_strings->ps_argvstr = nargvp;
- } else {
- /* style #2 - we can only restore our first arg :-( */
- if (*obuf == '\0')
- strncpy(obuf, OLD_PS_STRINGS->old_ps_argvstr,
- SPT_BUFSIZE - 1);
- OLD_PS_STRINGS->old_ps_nargvstr = 1;
- OLD_PS_STRINGS->old_ps_argvstr = nargvp[0];
}
+ ps_strings->ps_nargvstr = nargc;
+ ps_strings->ps_argvstr = nargvp;
}
diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c
index 5219418..58ebb55 100644
--- a/lib/libc/gen/tls.c
+++ b/lib/libc/gen/tls.c
@@ -65,13 +65,14 @@ void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
#if defined(__amd64__)
#define TLS_TCB_ALIGN 16
#elif defined(__powerpc__) || defined(__i386__) || defined(__arm__) || \
- defined(__sparc64__) || defined(__mips__)
+ defined(__sparc64__) || defined(__mips__) || defined(__aarch64__)
#define TLS_TCB_ALIGN sizeof(void *)
#else
#error TLS_TCB_ALIGN undefined for target architecture
#endif
-#if defined(__arm__) || defined(__mips__) || defined(__powerpc__)
+#if defined(__arm__) || defined(__mips__) || defined(__powerpc__) || \
+ defined(__aarch64__)
#define TLS_VARIANT_I
#endif
#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__)
diff --git a/lib/libc/gen/waitid.c b/lib/libc/gen/waitid.c
index 795b208..17a2dd6 100644
--- a/lib/libc/gen/waitid.c
+++ b/lib/libc/gen/waitid.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <signal.h>
#include <errno.h>
#include "un-namespace.h"
+#include "libc_private.h"
int
__waitid(idtype_t idtype, id_t id, siginfo_t *info, int flags)
@@ -44,7 +45,9 @@ __waitid(idtype_t idtype, id_t id, siginfo_t *info, int flags)
int status;
pid_t ret;
- ret = _wait6(idtype, id, &status, flags, NULL, info);
+ ret = ((pid_t (*)(idtype_t, id_t, int *, int, struct __wrusage *,
+ siginfo_t *))__libc_interposing[INTERPOS_wait6])(idtype, id,
+ &status, flags, NULL, info);
/*
* According to SUSv4, waitid() shall not return a PID when a
diff --git a/lib/libc/i386/sys/Makefile.inc b/lib/libc/i386/sys/Makefile.inc
index b56183c..ebaa462 100644
--- a/lib/libc/i386/sys/Makefile.inc
+++ b/lib/libc/i386/sys/Makefile.inc
@@ -15,9 +15,6 @@ MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \
NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o vfork.o yield.o
PSEUDO= _getlogin.o _exit.o
-.if ${MK_SYSCALL_COMPAT} != "no"
-PSEUDO+= _pread.o _pwrite.o _lseek.o _mmap.o _ftruncate.o _truncate.o
-.endif
MAN+= i386_get_ioperm.2 i386_get_ldt.2 i386_vm86.2
MAN+= i386_set_watch.3
diff --git a/lib/libc/iconv/__iconv.c b/lib/libc/iconv/__iconv.c
index c9bee3f..85170b7 100644
--- a/lib/libc/iconv/__iconv.c
+++ b/lib/libc/iconv/__iconv.c
@@ -31,7 +31,7 @@
#include "iconv-internal.h"
size_t
-__iconv(iconv_t a, const char **b, size_t *c, char **d,
+__iconv(iconv_t a, char **b, size_t *c, char **d,
size_t *e, __uint32_t f, size_t *g)
{
return __bsd___iconv(a, b, c, d, e, f, g);
diff --git a/lib/libc/iconv/bsd_iconv.c b/lib/libc/iconv/bsd_iconv.c
index f764886..e032a5b 100644
--- a/lib/libc/iconv/bsd_iconv.c
+++ b/lib/libc/iconv/bsd_iconv.c
@@ -120,7 +120,7 @@ __bsd_iconv_close(iconv_t handle)
}
size_t
-__bsd_iconv(iconv_t handle, const char **in, size_t *szin, char **out, size_t *szout)
+__bsd_iconv(iconv_t handle, char **in, size_t *szin, char **out, size_t *szout)
{
size_t ret;
int err;
@@ -141,7 +141,7 @@ __bsd_iconv(iconv_t handle, const char **in, size_t *szin, char **out, size_t *s
}
size_t
-__bsd___iconv(iconv_t handle, const char **in, size_t *szin, char **out,
+__bsd___iconv(iconv_t handle, char **in, size_t *szin, char **out,
size_t *szout, uint32_t flags, size_t *invalids)
{
size_t ret;
diff --git a/lib/libc/iconv/citrus_iconv.h b/lib/libc/iconv/citrus_iconv.h
index ac14ac3..99604e9 100644
--- a/lib/libc/iconv/citrus_iconv.h
+++ b/lib/libc/iconv/citrus_iconv.h
@@ -52,7 +52,7 @@ __END_DECLS
*/
static __inline int
_citrus_iconv_convert(struct _citrus_iconv * __restrict cv,
- const char * __restrict * __restrict in, size_t * __restrict inbytes,
+ char * __restrict * __restrict in, size_t * __restrict inbytes,
char * __restrict * __restrict out, size_t * __restrict outbytes,
uint32_t flags, size_t * __restrict nresults)
{
diff --git a/lib/libc/iconv/citrus_iconv_local.h b/lib/libc/iconv/citrus_iconv_local.h
index 12d2fa3..5392da1 100644
--- a/lib/libc/iconv/citrus_iconv_local.h
+++ b/lib/libc/iconv/citrus_iconv_local.h
@@ -46,7 +46,7 @@ static void _citrus_##_m_##_iconv_uninit_shared \
(struct _citrus_iconv_shared *); \
static int _citrus_##_m_##_iconv_convert \
(struct _citrus_iconv * __restrict, \
- const char * __restrict * __restrict, \
+ char * __restrict * __restrict, \
size_t * __restrict, \
char * __restrict * __restrict, \
size_t * __restrict outbytes, \
@@ -75,7 +75,7 @@ typedef void (*_citrus_iconv_uninit_shared_t)
(struct _citrus_iconv_shared *);
typedef int (*_citrus_iconv_convert_t)
(struct _citrus_iconv * __restrict,
- const char *__restrict* __restrict, size_t * __restrict,
+ char *__restrict* __restrict, size_t * __restrict,
char * __restrict * __restrict, size_t * __restrict, uint32_t,
size_t * __restrict);
typedef int (*_citrus_iconv_init_context_t)(struct _citrus_iconv *);
diff --git a/lib/libc/iconv/citrus_none.c b/lib/libc/iconv/citrus_none.c
index 4f9b254..9ec4bd3 100644
--- a/lib/libc/iconv/citrus_none.c
+++ b/lib/libc/iconv/citrus_none.c
@@ -83,7 +83,7 @@ _citrus_NONE_stdenc_init_state(struct _citrus_stdenc * __restrict ce __unused,
static int
_citrus_NONE_stdenc_mbtocs(struct _citrus_stdenc * __restrict ce __unused,
- _csid_t *csid, _index_t *idx, const char **s, size_t n,
+ _csid_t *csid, _index_t *idx, char **s, size_t n,
void *ps __unused, size_t *nresult, struct iconv_hooks *hooks)
{
@@ -159,7 +159,7 @@ _citrus_NONE_stdenc_cstomb(struct _citrus_stdenc * __restrict ce __unused,
static int
_citrus_NONE_stdenc_mbtowc(struct _citrus_stdenc * __restrict ce __unused,
- _wc_t * __restrict pwc, const char ** __restrict s, size_t n,
+ _wc_t * __restrict pwc, char ** __restrict s, size_t n,
void * __restrict pspriv __unused, size_t * __restrict nresult,
struct iconv_hooks *hooks)
{
diff --git a/lib/libc/iconv/citrus_prop.c b/lib/libc/iconv/citrus_prop.c
index 28318de..642e423 100644
--- a/lib/libc/iconv/citrus_prop.c
+++ b/lib/libc/iconv/citrus_prop.c
@@ -293,8 +293,10 @@ done:
}
_memstream_ungetc(ms, ch);
errnum = _citrus_prop_read_character_common(ms, &ch);
- if (errnum != 0)
+ if (errnum != 0) {
+ free(s);
return (errnum);
+ }
s[n] = ch;
++n, --m;
}
diff --git a/lib/libc/iconv/citrus_stdenc.h b/lib/libc/iconv/citrus_stdenc.h
index 28fa29d..50f4dff 100644
--- a/lib/libc/iconv/citrus_stdenc.h
+++ b/lib/libc/iconv/citrus_stdenc.h
@@ -69,7 +69,7 @@ _citrus_stdenc_init_state(struct _citrus_stdenc * __restrict ce,
static __inline int
_citrus_stdenc_mbtocs(struct _citrus_stdenc * __restrict ce,
_citrus_csid_t * __restrict csid, _citrus_index_t * __restrict idx,
- const char ** __restrict s, size_t n, void * __restrict ps,
+ char ** __restrict s, size_t n, void * __restrict ps,
size_t * __restrict nresult, struct iconv_hooks *hooks)
{
diff --git a/lib/libc/iconv/citrus_stdenc_local.h b/lib/libc/iconv/citrus_stdenc_local.h
index 7b627a0..141abff 100644
--- a/lib/libc/iconv/citrus_stdenc_local.h
+++ b/lib/libc/iconv/citrus_stdenc_local.h
@@ -55,7 +55,7 @@ static int _citrus_##_e_##_stdenc_mbtocs \
(struct _citrus_stdenc * __restrict, \
_citrus_csid_t * __restrict, \
_citrus_index_t * __restrict, \
- const char ** __restrict, size_t, \
+ char ** __restrict, size_t, \
void * __restrict, size_t * __restrict, \
struct iconv_hooks *); \
static int _citrus_##_e_##_stdenc_cstomb \
@@ -66,7 +66,7 @@ static int _citrus_##_e_##_stdenc_cstomb \
static int _citrus_##_e_##_stdenc_mbtowc \
(struct _citrus_stdenc * __restrict, \
_citrus_wc_t * __restrict, \
- const char ** __restrict, size_t, \
+ char ** __restrict, size_t, \
void * __restrict, size_t * __restrict, \
struct iconv_hooks *); \
static int _citrus_##_e_##_stdenc_wctomb \
@@ -106,7 +106,7 @@ typedef int (*_citrus_stdenc_init_state_t)
typedef int (*_citrus_stdenc_mbtocs_t)
(struct _citrus_stdenc * __restrict,
_citrus_csid_t * __restrict, _citrus_index_t * __restrict,
- const char ** __restrict, size_t,
+ char ** __restrict, size_t,
void * __restrict, size_t * __restrict,
struct iconv_hooks *);
typedef int (*_citrus_stdenc_cstomb_t)
@@ -116,7 +116,7 @@ typedef int (*_citrus_stdenc_cstomb_t)
typedef int (*_citrus_stdenc_mbtowc_t)
(struct _citrus_stdenc * __restrict,
_citrus_wc_t * __restrict,
- const char ** __restrict, size_t,
+ char ** __restrict, size_t,
void * __restrict, size_t * __restrict,
struct iconv_hooks *);
typedef int (*_citrus_stdenc_wctomb_t)
diff --git a/lib/libc/iconv/citrus_stdenc_template.h b/lib/libc/iconv/citrus_stdenc_template.h
index 21bc5cc..9a05fa7 100644
--- a/lib/libc/iconv/citrus_stdenc_template.h
+++ b/lib/libc/iconv/citrus_stdenc_template.h
@@ -112,7 +112,7 @@ _FUNCNAME(stdenc_init_state)(struct _citrus_stdenc * __restrict ce,
static int
_FUNCNAME(stdenc_mbtocs)(struct _citrus_stdenc * __restrict ce,
_citrus_csid_t * __restrict csid, _citrus_index_t * __restrict idx,
- const char ** __restrict s, size_t n, void * __restrict ps,
+ char ** __restrict s, size_t n, void * __restrict ps,
size_t * __restrict nresult, struct iconv_hooks *hooks)
{
wchar_t wc;
@@ -151,7 +151,7 @@ _FUNCNAME(stdenc_cstomb)(struct _citrus_stdenc * __restrict ce,
static int
_FUNCNAME(stdenc_mbtowc)(struct _citrus_stdenc * __restrict ce,
- _citrus_wc_t * __restrict wc, const char ** __restrict s, size_t n,
+ _citrus_wc_t * __restrict wc, char ** __restrict s, size_t n,
void * __restrict ps, size_t * __restrict nresult,
struct iconv_hooks *hooks)
{
diff --git a/lib/libc/iconv/iconv-internal.h b/lib/libc/iconv/iconv-internal.h
index 9a6b3d9..9937f09 100644
--- a/lib/libc/iconv/iconv-internal.h
+++ b/lib/libc/iconv/iconv-internal.h
@@ -29,11 +29,11 @@
/*
* Interal prototypes for our back-end functions.
*/
-size_t __bsd___iconv(iconv_t, const char **, size_t *, char **,
+size_t __bsd___iconv(iconv_t, char **, size_t *, char **,
size_t *, __uint32_t, size_t *);
void __bsd___iconv_free_list(char **, size_t);
int __bsd___iconv_get_list(char ***, size_t *, __iconv_bool);
-size_t __bsd_iconv(iconv_t, const char ** __restrict,
+size_t __bsd_iconv(iconv_t, char ** __restrict,
size_t * __restrict, char ** __restrict,
size_t * __restrict);
const char *__bsd_iconv_canonicalize(const char *);
diff --git a/lib/libc/iconv/iconv.3 b/lib/libc/iconv/iconv.3
index 81b348b..1a4f8c3 100644
--- a/lib/libc/iconv/iconv.3
+++ b/lib/libc/iconv/iconv.3
@@ -48,7 +48,7 @@
.Ft size_t
.Fn iconv "iconv_t cd" "char ** restrict src" "size_t * restrict srcleft" "char ** restrict dst" "size_t * restrict dstleft"
.Ft size_t
-.Fn __iconv "iconv_t cd" "const char ** restrict src" "size_t * restrict srcleft" "char ** restrict dst" "size_t * restrict dstleft" "uint32_t flags" "size_t * invalids"
+.Fn __iconv "iconv_t cd" "char ** restrict src" "size_t * restrict srcleft" "char ** restrict dst" "size_t * restrict dstleft" "uint32_t flags" "size_t * invalids"
.Sh DESCRIPTION
The
.Fn iconv_open
diff --git a/lib/libc/iconv/iconv.c b/lib/libc/iconv/iconv.c
index d13c1df..4bd9620 100644
--- a/lib/libc/iconv/iconv.c
+++ b/lib/libc/iconv/iconv.c
@@ -31,7 +31,7 @@
#include "iconv-internal.h"
size_t
-iconv(iconv_t a, const char ** __restrict b,
+iconv(iconv_t a, char ** __restrict b,
size_t * __restrict c, char ** __restrict d,
size_t * __restrict e)
{
diff --git a/lib/libc/iconv/iconv_compat.c b/lib/libc/iconv/iconv_compat.c
index dea968f..ded2499 100644
--- a/lib/libc/iconv/iconv_compat.c
+++ b/lib/libc/iconv/iconv_compat.c
@@ -37,7 +37,7 @@
#include "iconv-internal.h"
size_t
-__iconv_compat(iconv_t a, const char ** b, size_t * c, char ** d,
+__iconv_compat(iconv_t a, char ** b, size_t * c, char ** d,
size_t * e, __uint32_t f, size_t *g)
{
return __bsd___iconv(a, b, c, d, e, f, g);
@@ -56,7 +56,7 @@ __iconv_get_list_compat(char ***a, size_t *b, __iconv_bool c)
}
size_t
-iconv_compat(iconv_t a, const char ** __restrict b,
+iconv_compat(iconv_t a, char ** __restrict b,
size_t * __restrict c, char ** __restrict d,
size_t * __restrict e)
{
diff --git a/lib/libc/include/compat.h b/lib/libc/include/compat.h
index 2b8f0de..b20fac5 100644
--- a/lib/libc/include/compat.h
+++ b/lib/libc/include/compat.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
@@ -47,9 +47,7 @@ __sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0);
#define __weak_reference(sym,alias) \
.weak alias;.equ alias,sym
-#ifndef SYSCALL_COMPAT
__weak_reference(__sys_fcntl,__fcntl_compat)
-#endif
#undef __weak_reference
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index ceaa2a3..a670d63 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -222,6 +222,8 @@ enum {
INTERPOS_spinlock,
INTERPOS_spinunlock,
INTERPOS_kevent,
+ INTERPOS_wait6,
+ INTERPOS_ppoll,
INTERPOS_MAX
};
@@ -276,21 +278,12 @@ extern void (*__cleanup)(void) __hidden;
/*
* Get kern.osreldate to detect ABI revisions. Explicitly
- * ignores value of $OSVERSION and caches result. Prototypes
- * for the wrapped "new" pad-less syscalls are here for now.
+ * ignores value of $OSVERSION and caches result.
*/
int __getosreldate(void);
#include <sys/_types.h>
#include <sys/_sigset.h>
-/* With pad */
-__off_t __sys_freebsd6_lseek(int, int, __off_t, int);
-int __sys_freebsd6_ftruncate(int, int, __off_t);
-int __sys_freebsd6_truncate(const char *, int, __off_t);
-__ssize_t __sys_freebsd6_pread(int, void *, __size_t, int, __off_t);
-__ssize_t __sys_freebsd6_pwrite(int, const void *, __size_t, int, __off_t);
-void * __sys_freebsd6_mmap(void *, __size_t, int, int, int, int, __off_t);
-
struct aiocb;
struct fd_set;
struct iovec;
@@ -305,6 +298,8 @@ struct timeval;
struct timezone;
struct __siginfo;
struct __ucontext;
+struct __wrusage;
+enum idtype;
int __sys_aio_suspend(const struct aiocb * const[], int,
const struct timespec *);
int __sys_accept(int, struct sockaddr *, __socklen_t *);
@@ -329,6 +324,8 @@ int __sys_pselect(int, struct fd_set *, struct fd_set *,
struct fd_set *, const struct timespec *,
const __sigset_t *);
int __sys_poll(struct pollfd *, unsigned, int);
+int __sys_ppoll(struct pollfd *, unsigned, const struct timespec *,
+ const __sigset_t *);
__ssize_t __sys_pread(int, void *, __size_t, __off_t);
__ssize_t __sys_pwrite(int, const void *, __size_t, __off_t);
__ssize_t __sys_read(int, void *, __size_t);
@@ -357,6 +354,8 @@ int __sys_thr_kill(long, int);
int __sys_thr_self(long *);
int __sys_truncate(const char *, __off_t);
__pid_t __sys_wait4(__pid_t, int *, int, struct rusage *);
+__pid_t __sys_wait6(enum idtype, __id_t, int *, int,
+ struct __wrusage *, struct __siginfo *);
__ssize_t __sys_write(int, const void *, __size_t);
__ssize_t __sys_writev(int, const struct iovec *, int);
diff --git a/lib/libc/locale/cXXrtomb_iconv.h b/lib/libc/locale/cXXrtomb_iconv.h
index 0ea553b..d6e7ce0 100644
--- a/lib/libc/locale/cXXrtomb_iconv.h
+++ b/lib/libc/locale/cXXrtomb_iconv.h
@@ -57,8 +57,7 @@ cXXrtomb_l(char * __restrict s, charXX_t c, mbstate_t * __restrict ps,
{
_ConversionState *cs;
struct _citrus_iconv *handle;
- const char *src;
- char *dst;
+ char *src, *dst;
size_t srcleft, dstleft, invlen;
int err;
diff --git a/lib/libc/locale/duplocale.3 b/lib/libc/locale/duplocale.3
index f2e8215..bc0c4bc 100644
--- a/lib/libc/locale/duplocale.3
+++ b/lib/libc/locale/duplocale.3
@@ -36,7 +36,7 @@
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
-.In xlocale.h
+.In locale.h
.Ft locale_t
.Fn duplocale "locale_t locale"
.Sh DESCRIPTION
diff --git a/lib/libc/locale/freelocale.3 b/lib/libc/locale/freelocale.3
index 86f4809..0df80e7 100644
--- a/lib/libc/locale/freelocale.3
+++ b/lib/libc/locale/freelocale.3
@@ -38,7 +38,7 @@ or
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
-.In xlocale.h
+.In locale.h
.Ft int
.Fn freelocale "locale_t locale"
.Sh DESCRIPTION
diff --git a/lib/libc/locale/mbrtocXX_iconv.h b/lib/libc/locale/mbrtocXX_iconv.h
index ac85a5a..9eb6f68 100644
--- a/lib/libc/locale/mbrtocXX_iconv.h
+++ b/lib/libc/locale/mbrtocXX_iconv.h
@@ -99,8 +99,7 @@ mbrtocXX_l(charXX_t * __restrict pc, const char * __restrict s, size_t n,
/* Convert as few characters to the dst buffer as possible. */
for (i = 0; ; i++) {
- const char *src;
- char *dst;
+ char *src, *dst;
size_t srcleft, dstleft, invlen;
int err;
diff --git a/lib/libc/locale/newlocale.3 b/lib/libc/locale/newlocale.3
index a639c37..c7414be 100644
--- a/lib/libc/locale/newlocale.3
+++ b/lib/libc/locale/newlocale.3
@@ -35,7 +35,7 @@
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
-.In xlocale
+.In locale.h
.Ft locale_t
.Fn newlocale "int mask" "const char * locale" "locale_t base"
.Sh DESCRIPTION
diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c
index 75adffa..cacfd73 100644
--- a/lib/libc/locale/none.c
+++ b/lib/libc/locale/none.c
@@ -209,7 +209,7 @@ struct xlocale_ctype __xlocale_global_ctype = {
256 /* __mb_sb_limit */
};
-const struct xlocale_ctype __xlocale_C_ctype = {
+struct xlocale_ctype __xlocale_C_ctype = {
{{0}, "C"},
(_RuneLocale*)&_DefaultRuneLocale,
_none_mbrtowc,
diff --git a/lib/libc/locale/querylocale.3 b/lib/libc/locale/querylocale.3
index f90d626..d1bb688 100644
--- a/lib/libc/locale/querylocale.3
+++ b/lib/libc/locale/querylocale.3
@@ -36,7 +36,7 @@
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
-.In xlocale.h
+.In locale.h
.Ft const char *
.Fn querylocale "int mask" "locale_t locale"
.Sh DESCRIPTION
diff --git a/lib/libc/locale/uselocale.3 b/lib/libc/locale/uselocale.3
index df29a62..96d0008 100644
--- a/lib/libc/locale/uselocale.3
+++ b/lib/libc/locale/uselocale.3
@@ -36,7 +36,7 @@
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
-.In xlocale.h
+.In locale.h
.Ft locale_t
.Fn uselocale "locale_t locale"
.Sh DESCRIPTION
diff --git a/lib/libc/mips/sys/Makefile.inc b/lib/libc/mips/sys/Makefile.inc
index a0452c6..460e69b 100644
--- a/lib/libc/mips/sys/Makefile.inc
+++ b/lib/libc/mips/sys/Makefile.inc
@@ -6,10 +6,6 @@ MDASM= Ovfork.S brk.S cerror.S exect.S \
fork.S pipe.S ptrace.S sbrk.S syscall.S
# Don't generate default code for these syscalls:
-NOASM= break.o exit.o ftruncate.o getlogin.o lseek.o mmap.o \
- openbsd_poll.o pread.o pwrite.o sstk.o truncate.o vfork.o yield.o
+NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o vfork.o yield.o
PSEUDO= _exit.o _getlogin.o
-.if ${MK_SYSCALL_COMPAT} != "no"
-PSEUDO+= _pread.o _pwrite.o _lseek.o _mmap.o _ftruncate.o _truncate.o
-.endif
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index c50374e..17c9b65 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -64,7 +64,6 @@ __FBSDID("$FreeBSD$");
#include <ifaddrs.h>
#include <sys/queue.h>
#ifdef INET6
-#include <net/if_var.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <netinet6/in6_var.h>
diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c
index 97880a2..89effe6 100644
--- a/lib/libc/net/name6.c
+++ b/lib/libc/net/name6.c
@@ -94,7 +94,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#ifdef INET6
#include <net/if.h>
-#include <net/if_var.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <netinet6/in6_var.h> /* XXX */
diff --git a/lib/libc/net/sctp_recvmsg.3 b/lib/libc/net/sctp_recvmsg.3
index bb1cf06..945797d 100644
--- a/lib/libc/net/sctp_recvmsg.3
+++ b/lib/libc/net/sctp_recvmsg.3
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 13, 2007
+.Dd April 23, 2015
.Dt SCTP_RECVMSG 3
.Os
.Sh NAME
@@ -98,13 +98,13 @@ receive buffer, then the
argument will
.Em not
have the
-.Dv MSG_EOF
+.Dv MSG_EOR
flag applied.
If the message is a complete message then
the
.Fa flags
argument will have
-.Dv MSG_EOF
+.Dv MSG_EOR
set.
Locally detected errors are
indicated by a return value of -1 with
diff --git a/lib/libc/nls/catopen.3 b/lib/libc/nls/catopen.3
index 7a16ee5..7744b0b 100644
--- a/lib/libc/nls/catopen.3
+++ b/lib/libc/nls/catopen.3
@@ -94,7 +94,7 @@ An empty string is substituted for undefined values.
Path names templates defined in
.Ev NLSPATH
are separated by colons
-.No ( Sq \&: ) .
+.Pq Sq \&: .
A leading or two adjacent colons
is equivalent to specifying %N.
.Pp
diff --git a/lib/libc/powerpc/gen/_setjmp.S b/lib/libc/powerpc/gen/_setjmp.S
index f7f3d64..663a8b6 100644
--- a/lib/libc/powerpc/gen/_setjmp.S
+++ b/lib/libc/powerpc/gen/_setjmp.S
@@ -58,24 +58,24 @@ ENTRY(_setjmp)
stmw %r9,20(%r3)
/* FPRs */
- stfd %f14,92+0*8(%r3)
- stfd %f15,92+1*8(%r3)
- stfd %f16,92+2*8(%r3)
- stfd %f17,92+3*8(%r3)
- stfd %f18,92+4*8(%r3)
- stfd %f19,92+5*8(%r3)
- stfd %f20,92+6*8(%r3)
- stfd %f21,92+7*8(%r3)
- stfd %f22,92+8*8(%r3)
- stfd %f23,92+9*8(%r3)
- stfd %f24,92+10*8(%r3)
- stfd %f25,92+11*8(%r3)
- stfd %f26,92+12*8(%r3)
- stfd %f27,92+13*8(%r3)
- stfd %f28,93+13*8(%r3)
- stfd %f29,93+14*8(%r3)
- stfd %f30,93+15*8(%r3)
- stfd %f31,93+16*8(%r3)
+ stfd %f14,112+0*8(%r3)
+ stfd %f15,112+1*8(%r3)
+ stfd %f16,112+2*8(%r3)
+ stfd %f17,112+3*8(%r3)
+ stfd %f18,112+4*8(%r3)
+ stfd %f19,112+5*8(%r3)
+ stfd %f20,112+6*8(%r3)
+ stfd %f21,112+7*8(%r3)
+ stfd %f22,112+8*8(%r3)
+ stfd %f23,112+9*8(%r3)
+ stfd %f24,112+10*8(%r3)
+ stfd %f25,112+11*8(%r3)
+ stfd %f26,112+12*8(%r3)
+ stfd %f27,112+13*8(%r3)
+ stfd %f28,112+14*8(%r3)
+ stfd %f29,112+15*8(%r3)
+ stfd %f30,112+16*8(%r3)
+ stfd %f31,112+17*8(%r3)
li %r3,0
blr
@@ -85,24 +85,24 @@ ENTRY(_longjmp)
lmw %r9,20(%r3)
/* FPRs */
- lfd %f14,92+0*8(%r3)
- lfd %f15,92+1*8(%r3)
- lfd %f16,92+2*8(%r3)
- lfd %f17,92+3*8(%r3)
- lfd %f18,92+4*8(%r3)
- lfd %f19,92+5*8(%r3)
- lfd %f20,92+6*8(%r3)
- lfd %f21,92+7*8(%r3)
- lfd %f22,92+8*8(%r3)
- lfd %f23,92+9*8(%r3)
- lfd %f24,92+10*8(%r3)
- lfd %f25,92+11*8(%r3)
- lfd %f26,92+12*8(%r3)
- lfd %f27,92+13*8(%r3)
- lfd %f28,93+13*8(%r3)
- lfd %f29,93+14*8(%r3)
- lfd %f30,93+15*8(%r3)
- lfd %f31,93+16*8(%r3)
+ lfd %f14,112+0*8(%r3)
+ lfd %f15,112+1*8(%r3)
+ lfd %f16,112+2*8(%r3)
+ lfd %f17,112+3*8(%r3)
+ lfd %f18,112+4*8(%r3)
+ lfd %f19,112+5*8(%r3)
+ lfd %f20,112+6*8(%r3)
+ lfd %f21,112+7*8(%r3)
+ lfd %f22,112+8*8(%r3)
+ lfd %f23,112+9*8(%r3)
+ lfd %f24,112+10*8(%r3)
+ lfd %f25,112+11*8(%r3)
+ lfd %f26,112+12*8(%r3)
+ lfd %f27,112+13*8(%r3)
+ lfd %f28,112+14*8(%r3)
+ lfd %f29,112+15*8(%r3)
+ lfd %f30,112+16*8(%r3)
+ lfd %f31,112+17*8(%r3)
mtlr %r11
mtcr %r12
diff --git a/lib/libc/powerpc/gen/setjmp.S b/lib/libc/powerpc/gen/setjmp.S
index 881c24e..ef7cb7e 100644
--- a/lib/libc/powerpc/gen/setjmp.S
+++ b/lib/libc/powerpc/gen/setjmp.S
@@ -68,24 +68,24 @@ ENTRY(setjmp)
stmw %r9,20(%r6)
/* FPRs */
- stfd %f14,92+0*8(%r6)
- stfd %f15,92+1*8(%r6)
- stfd %f16,92+2*8(%r6)
- stfd %f17,92+3*8(%r6)
- stfd %f18,92+4*8(%r6)
- stfd %f19,92+5*8(%r6)
- stfd %f20,92+6*8(%r6)
- stfd %f21,92+7*8(%r6)
- stfd %f22,92+8*8(%r6)
- stfd %f23,92+9*8(%r6)
- stfd %f24,92+10*8(%r6)
- stfd %f25,92+11*8(%r6)
- stfd %f26,92+12*8(%r6)
- stfd %f27,92+13*8(%r6)
- stfd %f28,93+13*8(%r6)
- stfd %f29,93+14*8(%r6)
- stfd %f30,93+15*8(%r6)
- stfd %f31,93+16*8(%r6)
+ stfd %f14,112+0*8(%r6)
+ stfd %f15,112+1*8(%r6)
+ stfd %f16,112+2*8(%r6)
+ stfd %f17,112+3*8(%r6)
+ stfd %f18,112+4*8(%r6)
+ stfd %f19,112+5*8(%r6)
+ stfd %f20,112+6*8(%r6)
+ stfd %f21,112+7*8(%r6)
+ stfd %f22,112+8*8(%r6)
+ stfd %f23,112+9*8(%r6)
+ stfd %f24,112+10*8(%r6)
+ stfd %f25,112+11*8(%r6)
+ stfd %f26,112+12*8(%r6)
+ stfd %f27,112+13*8(%r6)
+ stfd %f28,112+14*8(%r6)
+ stfd %f29,112+15*8(%r6)
+ stfd %f30,112+16*8(%r6)
+ stfd %f31,112+17*8(%r6)
li %r3,0 /* return (0) */
blr
@@ -96,24 +96,24 @@ ENTRY(__longjmp)
lmw %r9,20(%r3) /* restore regs */
/* FPRs */
- lfd %f14,92+0*8(%r3)
- lfd %f15,92+1*8(%r3)
- lfd %f16,92+2*8(%r3)
- lfd %f17,92+3*8(%r3)
- lfd %f18,92+4*8(%r3)
- lfd %f19,92+5*8(%r3)
- lfd %f20,92+6*8(%r3)
- lfd %f21,92+7*8(%r3)
- lfd %f22,92+8*8(%r3)
- lfd %f23,92+9*8(%r3)
- lfd %f24,92+10*8(%r3)
- lfd %f25,92+11*8(%r3)
- lfd %f26,92+12*8(%r3)
- lfd %f27,92+13*8(%r3)
- lfd %f28,93+13*8(%r3)
- lfd %f29,93+14*8(%r3)
- lfd %f30,93+15*8(%r3)
- lfd %f31,93+16*8(%r3)
+ lfd %f14,112+0*8(%r3)
+ lfd %f15,112+1*8(%r3)
+ lfd %f16,112+2*8(%r3)
+ lfd %f17,112+3*8(%r3)
+ lfd %f18,112+4*8(%r3)
+ lfd %f19,112+5*8(%r3)
+ lfd %f20,112+6*8(%r3)
+ lfd %f21,112+7*8(%r3)
+ lfd %f22,112+8*8(%r3)
+ lfd %f23,112+9*8(%r3)
+ lfd %f24,112+10*8(%r3)
+ lfd %f25,112+11*8(%r3)
+ lfd %f26,112+12*8(%r3)
+ lfd %f27,112+13*8(%r3)
+ lfd %f28,112+14*8(%r3)
+ lfd %f29,112+15*8(%r3)
+ lfd %f30,112+16*8(%r3)
+ lfd %f31,112+17*8(%r3)
mr %r6,%r4 /* save val param */
mtlr %r11 /* r11 -> link reg */
diff --git a/lib/libc/powerpc/gen/sigsetjmp.S b/lib/libc/powerpc/gen/sigsetjmp.S
index ec7460a..9c75f4f 100644
--- a/lib/libc/powerpc/gen/sigsetjmp.S
+++ b/lib/libc/powerpc/gen/sigsetjmp.S
@@ -73,24 +73,24 @@ ENTRY(sigsetjmp)
stmw %r9,20(%r6)
/* FPRs */
- stfd %f14,92+0*8(%r6)
- stfd %f15,92+1*8(%r6)
- stfd %f16,92+2*8(%r6)
- stfd %f17,92+3*8(%r6)
- stfd %f18,92+4*8(%r6)
- stfd %f19,92+5*8(%r6)
- stfd %f20,92+6*8(%r6)
- stfd %f21,92+7*8(%r6)
- stfd %f22,92+8*8(%r6)
- stfd %f23,92+9*8(%r6)
- stfd %f24,92+10*8(%r6)
- stfd %f25,92+11*8(%r6)
- stfd %f26,92+12*8(%r6)
- stfd %f27,92+13*8(%r6)
- stfd %f28,93+13*8(%r6)
- stfd %f29,93+14*8(%r6)
- stfd %f30,93+15*8(%r6)
- stfd %f31,93+16*8(%r6)
+ stfd %f14,112+0*8(%r6)
+ stfd %f15,112+1*8(%r6)
+ stfd %f16,112+2*8(%r6)
+ stfd %f17,112+3*8(%r6)
+ stfd %f18,112+4*8(%r6)
+ stfd %f19,112+5*8(%r6)
+ stfd %f20,112+6*8(%r6)
+ stfd %f21,112+7*8(%r6)
+ stfd %f22,112+8*8(%r6)
+ stfd %f23,112+9*8(%r6)
+ stfd %f24,112+10*8(%r6)
+ stfd %f25,112+11*8(%r6)
+ stfd %f26,112+12*8(%r6)
+ stfd %f27,112+13*8(%r6)
+ stfd %f28,112+14*8(%r6)
+ stfd %f29,112+15*8(%r6)
+ stfd %f30,112+16*8(%r6)
+ stfd %f31,112+17*8(%r6)
li %r3,0
blr
@@ -100,24 +100,24 @@ ENTRY(siglongjmp)
lmw %r9,20(%r3)
/* FPRs */
- lfd %f14,92+0*8(%r3)
- lfd %f15,92+1*8(%r3)
- lfd %f16,92+2*8(%r3)
- lfd %f17,92+3*8(%r3)
- lfd %f18,92+4*8(%r3)
- lfd %f19,92+5*8(%r3)
- lfd %f20,92+6*8(%r3)
- lfd %f21,92+7*8(%r3)
- lfd %f22,92+8*8(%r3)
- lfd %f23,92+9*8(%r3)
- lfd %f24,92+10*8(%r3)
- lfd %f25,92+11*8(%r3)
- lfd %f26,92+12*8(%r3)
- lfd %f27,92+13*8(%r3)
- lfd %f28,93+13*8(%r3)
- lfd %f29,93+14*8(%r3)
- lfd %f30,93+15*8(%r3)
- lfd %f31,93+16*8(%r3)
+ lfd %f14,112+0*8(%r3)
+ lfd %f15,112+1*8(%r3)
+ lfd %f16,112+2*8(%r3)
+ lfd %f17,112+3*8(%r3)
+ lfd %f18,112+4*8(%r3)
+ lfd %f19,112+5*8(%r3)
+ lfd %f20,112+6*8(%r3)
+ lfd %f21,112+7*8(%r3)
+ lfd %f22,112+8*8(%r3)
+ lfd %f23,112+9*8(%r3)
+ lfd %f24,112+10*8(%r3)
+ lfd %f25,112+11*8(%r3)
+ lfd %f26,112+12*8(%r3)
+ lfd %f27,112+13*8(%r3)
+ lfd %f28,112+14*8(%r3)
+ lfd %f29,112+15*8(%r3)
+ lfd %f30,112+16*8(%r3)
+ lfd %f31,112+17*8(%r3)
lwz %r7,0(%r3)
mr %r6,%r4
diff --git a/lib/libc/powerpc/sys/Makefile.inc b/lib/libc/powerpc/sys/Makefile.inc
index ad98ba1..98ec888 100644
--- a/lib/libc/powerpc/sys/Makefile.inc
+++ b/lib/libc/powerpc/sys/Makefile.inc
@@ -6,6 +6,3 @@ MDASM+= brk.S cerror.S exect.S pipe.S ptrace.S sbrk.S setlogin.S
NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o yield.o
PSEUDO= _getlogin.o _exit.o
-.if ${MK_SYSCALL_COMPAT} != "no"
-PSEUDO+= _pread.o _pwrite.o _lseek.o _mmap.o _ftruncate.o _truncate.o
-.endif
diff --git a/lib/libc/powerpc64/sys/Makefile.inc b/lib/libc/powerpc64/sys/Makefile.inc
index ad98ba1..98ec888 100644
--- a/lib/libc/powerpc64/sys/Makefile.inc
+++ b/lib/libc/powerpc64/sys/Makefile.inc
@@ -6,6 +6,3 @@ MDASM+= brk.S cerror.S exect.S pipe.S ptrace.S sbrk.S setlogin.S
NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o yield.o
PSEUDO= _getlogin.o _exit.o
-.if ${MK_SYSCALL_COMPAT} != "no"
-PSEUDO+= _pread.o _pwrite.o _lseek.o _mmap.o _ftruncate.o _truncate.o
-.endif
diff --git a/lib/libc/regex/re_format.7 b/lib/libc/regex/re_format.7
index 089316b..b3f9561 100644
--- a/lib/libc/regex/re_format.7
+++ b/lib/libc/regex/re_format.7
@@ -392,10 +392,12 @@ and
.Ql ?\&
are ordinary characters, and their functionality
can be expressed using bounds
-.No ( Ql {1,}
+.Po
+.Ql {1,}
or
.Ql {0,1}
-respectively).
+respectively
+.Pc .
Also note that
.Ql x+
in modern REs is equivalent to
diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c
index 2da5066..2f2d827 100644
--- a/lib/libc/regex/regcomp.c
+++ b/lib/libc/regex/regcomp.c
@@ -1726,13 +1726,13 @@ computematchjumps(struct parse *p, struct re_guts *g)
if (p->error != 0)
return;
- pmatches = (int*) malloc(g->mlen * sizeof(unsigned int));
+ pmatches = (int*) malloc(g->mlen * sizeof(int));
if (pmatches == NULL) {
g->matchjump = NULL;
return;
}
- g->matchjump = (int*) malloc(g->mlen * sizeof(unsigned int));
+ g->matchjump = (int*) malloc(g->mlen * sizeof(int));
if (g->matchjump == NULL) { /* Not a fatal error */
free(pmatches);
return;
diff --git a/lib/libc/regex/regex.3 b/lib/libc/regex/regex.3
index ea1ba25..6df2f09 100644
--- a/lib/libc/regex/regex.3
+++ b/lib/libc/regex/regex.3
@@ -420,10 +420,12 @@ it should have been the result from the most recent
using that
.Ft regex_t .
The
-.Fn ( regerror
+.Po
+.Fn regerror
may be able to supply a more detailed message using information
from the
-.Ft regex_t . )
+.Ft regex_t .
+.Pc
The
.Fn regerror
function
diff --git a/lib/libc/rpc/rpcbind.3 b/lib/libc/rpc/rpcbind.3
index 0b716ca..3bf8be9 100644
--- a/lib/libc/rpc/rpcbind.3
+++ b/lib/libc/rpc/rpcbind.3
@@ -25,7 +25,7 @@
.Ft bool_t
.Fn rpcb_gettime "const char *host" "time_t * timep"
.Ft "enum clnt_stat"
-.Fn rpcb_rmtcall "const struct netconfig *netconf" "const char *host" "const rpcprog_t prognum, const rpcvers_t versnum" "const rpcproc_t procnum, const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "const caddr_t out" "const struct timeval tout, const struct netbuf *svcaddr"
+.Fn rpcb_rmtcall "const struct netconfig *netconf" "const char *host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const rpcproc_t procnum" "const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "const caddr_t out" "const struct timeval tout" "const struct netbuf *svcaddr"
.Ft bool_t
.Fn rpcb_set "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct netbuf *svcaddr"
.Ft bool_t
diff --git a/lib/libc/sparc64/sys/Makefile.inc b/lib/libc/sparc64/sys/Makefile.inc
index 726c0c9..a62aac2 100644
--- a/lib/libc/sparc64/sys/Makefile.inc
+++ b/lib/libc/sparc64/sys/Makefile.inc
@@ -18,6 +18,3 @@ MDASM+= brk.S cerror.S exect.S pipe.S ptrace.S sbrk.S setlogin.S sigaction1.S
NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o yield.o
PSEUDO= _getlogin.o _exit.o
-.if ${MK_SYSCALL_COMPAT} != "no"
-PSEUDO+= _pread.o _pwrite.o _lseek.o _mmap.o _ftruncate.o _truncate.o
-.endif
diff --git a/lib/libc/stdio/flags.c b/lib/libc/stdio/flags.c
index b7552a4..9eed6d7 100644
--- a/lib/libc/stdio/flags.c
+++ b/lib/libc/stdio/flags.c
@@ -97,6 +97,10 @@ __sflags(const char *mode, int *optr)
/* set close-on-exec */
o |= O_CLOEXEC;
break;
+ case 'v':
+ /* verify */
+ o |= O_VERIFY;
+ break;
default:
known = 0;
break;
diff --git a/lib/libc/stdio/open_memstream.3 b/lib/libc/stdio/open_memstream.3
index 117dcb2..e01952b 100644
--- a/lib/libc/stdio/open_memstream.3
+++ b/lib/libc/stdio/open_memstream.3
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2013 Advanced Computing Technologies LLC
+.\" Copyright (c) 2013 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/lib/libc/stdio/open_memstream.c b/lib/libc/stdio/open_memstream.c
index aa50822..baa71e4 100644
--- a/lib/libc/stdio/open_memstream.c
+++ b/lib/libc/stdio/open_memstream.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/lib/libc/stdio/open_wmemstream.c b/lib/libc/stdio/open_wmemstream.c
index cf2968a..299e3d8 100644
--- a/lib/libc/stdio/open_wmemstream.c
+++ b/lib/libc/stdio/open_wmemstream.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index 57205a7..7cee03a 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -10,7 +10,8 @@ MISRCS+=_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \
merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c quick_exit.c \
radixsort.c rand.c \
- random.c reallocf.c realpath.c remque.c strfmon.c strtoimax.c \
+ random.c reallocarray.c reallocf.c realpath.c remque.c strfmon.c \
+ strtoimax.c \
strtol.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \
strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
@@ -25,7 +26,7 @@ MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 \
hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
lsearch.3 memory.3 ptsname.3 qsort.3 \
quick_exit.3 \
- radixsort.3 rand.3 random.3 reallocf.3 \
+ radixsort.3 rand.3 random.3 reallocarray.3 reallocf.3 \
realpath.3 strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \
tsearch.3
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index 39eab7d..782023e 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -113,6 +113,7 @@ FBSD_1.4 {
hcreate_r;
hdestroy_r;
hsearch_r;
+ reallocarray;
};
FBSDprivate_1.0 {
diff --git a/lib/libc/stdlib/reallocarray.3 b/lib/libc/stdlib/reallocarray.3
new file mode 100644
index 0000000..a85858c
--- /dev/null
+++ b/lib/libc/stdlib/reallocarray.3
@@ -0,0 +1,137 @@
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\">----The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2015
+.Dt REALLOCARRAY 3
+.Os
+.Sh NAME
+.Nm reallocarray
+.Nd memory reallocation function
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn reallocarray "void *ptr" "size_t nmemb" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn reallocarray
+except it operates on
+.Fa nmemb
+members of size
+.Fa size
+and checks for integer overflow in the calculation
+.Fa nmemb
+*
+.Fa size .
+.Sh RETURN VALUES
+.Fn reallocarray
+return a pointer to the allocated space; otherwise, a
+.Dv NULL
+pointer is returned and
+.Va errno
+is set to
+.Er ENOMEM .
+.Sh EXAMPLES
+Consider
+.Fn reallocarray
+when there is multiplication in the
+.Fa size
+argument of
+.Fn malloc
+or
+.Fn realloc .
+For example, avoid this common idiom as it may lead to integer overflow:
+.Bd -literal -offset indent
+if ((p = malloc(num * size)) == NULL)
+ err(1, "malloc");
+.Ed
+.Pp
+A drop-in replacement is the
+.Ox
+extension
+.Fn reallocarray :
+.Bd -literal -offset indent
+if ((p = reallocarray(NULL, num, size)) == NULL)
+ err(1, "reallocarray");
+.Ed
+.Pp
+When using
+.Fn realloc ,
+be careful to avoid the following idiom:
+.Bd -literal -offset indent
+size += 50;
+if ((p = realloc(p, size)) == NULL)
+ return (NULL);
+.Ed
+.Pp
+Do not adjust the variable describing how much memory has been allocated
+until the allocation has been successful.
+This can cause aberrant program behavior if the incorrect size value is used.
+In most cases, the above sample will also result in a leak of memory.
+As stated earlier, a return value of
+.Dv NULL
+indicates that the old object still remains allocated.
+Better code looks like this:
+.Bd -literal -offset indent
+newsize = size + 50;
+if ((newp = realloc(p, newsize)) == NULL) {
+ free(p);
+ p = NULL;
+ size = 0;
+ return (NULL);
+}
+p = newp;
+size = newsize;
+.Ed
+.Pp
+As with
+.Fn malloc ,
+it is important to ensure the new size value will not overflow;
+i.e. avoid allocations like the following:
+.Bd -literal -offset indent
+if ((newp = realloc(p, num * size)) == NULL) {
+ ...
+.Ed
+.Pp
+Instead, use
+.Fn reallocarray :
+.Bd -literal -offset indent
+if ((newp = reallocarray(p, num, size)) == NULL) {
+ ...
+.Ed
+.Sh SEE ALSO
+.Xr realloc 3
+.Sh HISTORY
+The
+.Fn reallocf
+function first appeared in
+.Ox 5.6 .
diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c
new file mode 100644
index 0000000..e1e9b7c
--- /dev/null
+++ b/lib/libc/stdlib/reallocarray.c
@@ -0,0 +1,42 @@
+/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ return (realloc(optr, size * nmemb));
+}
diff --git a/lib/libc/string/strlcat.c b/lib/libc/string/strlcat.c
index 2d13be7..f5ed6c6 100644
--- a/lib/libc/string/strlcat.c
+++ b/lib/libc/string/strlcat.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
+/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */
/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,36 +23,36 @@ __FBSDID("$FreeBSD$");
#include <string.h>
/*
- * Appends src to string dst of size siz (unlike strncat, siz is the
- * full size of dst, not space left). At most siz-1 characters
- * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
- * Returns strlen(src) + MIN(siz, strlen(initial dst)).
- * If retval >= siz, truncation occurred.
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
*/
size_t
-strlcat(char * __restrict dst, const char * __restrict src, size_t siz)
+strlcat(char * __restrict dst, const char * __restrict src, size_t dsize)
{
- char *d = dst;
- const char *s = src;
- size_t n = siz;
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
size_t dlen;
- /* Find the end of dst and adjust bytes left but don't go past end */
- while (n-- != 0 && *d != '\0')
- d++;
- dlen = d - dst;
- n = siz - dlen;
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0')
+ dst++;
+ dlen = dst - odst;
+ n = dsize - dlen;
- if (n == 0)
- return(dlen + strlen(s));
- while (*s != '\0') {
- if (n != 1) {
- *d++ = *s;
+ if (n-- == 0)
+ return(dlen + strlen(src));
+ while (*src != '\0') {
+ if (n != 0) {
+ *dst++ = *src;
n--;
}
- s++;
+ src++;
}
- *d = '\0';
+ *dst = '\0';
- return(dlen + (s - src)); /* count does not include NUL */
+ return(dlen + (src - osrc)); /* count does not include NUL */
}
diff --git a/lib/libc/string/strlcpy.c b/lib/libc/string/strlcpy.c
index 451b6df..019d231 100644
--- a/lib/libc/string/strlcpy.c
+++ b/lib/libc/string/strlcpy.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
+/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */
/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,32 +23,31 @@ __FBSDID("$FreeBSD$");
#include <string.h>
/*
- * Copy src to string dst of size siz. At most siz-1 characters
- * will be copied. Always NUL terminates (unless siz == 0).
- * Returns strlen(src); if retval >= siz, truncation occurred.
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
-strlcpy(char * __restrict dst, const char * __restrict src, size_t siz)
+strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize)
{
- char *d = dst;
- const char *s = src;
- size_t n = siz;
+ const char *osrc = src;
+ size_t nleft = dsize;
- /* Copy as many bytes as will fit */
- if (n != 0) {
- while (--n != 0) {
- if ((*d++ = *s++) == '\0')
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0) {
+ while (--nleft != 0) {
+ if ((*dst++ = *src++) == '\0')
break;
}
}
- /* Not enough room in dst, add NUL and traverse rest of src */
- if (n == 0) {
- if (siz != 0)
- *d = '\0'; /* NUL-terminate dst */
- while (*s++)
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0) {
+ if (dsize != 0)
+ *dst = '\0'; /* NUL-terminate dst */
+ while (*src++)
;
}
- return(s - src - 1); /* count does not include NUL */
+ return(src - osrc - 1); /* count does not include NUL */
}
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 7745b2a..5162563 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -26,18 +26,6 @@ SRCS+= \
__error.c \
interposing_table.c
-.if ${MK_SYSCALL_COMPAT} != "no"
-SYSCALL_COMPAT_SRCS= \
- ftruncate.c \
- lseek.c \
- mmap.c \
- pread.c \
- pwrite.c \
- truncate.c
-SRCS+= ${SYSCALL_COMPAT_SRCS}
-NOASM+= ${SYSCALL_COMPAT_SRCS:S/.c/.o/}
-.endif
-
SRCS+= futimens.c utimensat.c
NOASM+= futimens.o utimensat.o
PSEUDO+= _futimens.o _utimensat.o
@@ -57,6 +45,7 @@ INTERPOSED = \
open \
openat \
poll \
+ ppoll \
pselect \
read \
readv \
@@ -73,6 +62,7 @@ INTERPOSED = \
sigwaitinfo \
swapcontext \
wait4 \
+ wait6 \
write \
writev
diff --git a/lib/libc/sys/closefrom.2 b/lib/libc/sys/closefrom.2
index ffaa001..a0b5fc2 100644
--- a/lib/libc/sys/closefrom.2
+++ b/lib/libc/sys/closefrom.2
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/lib/libc/sys/fcntl.c b/lib/libc/sys/fcntl.c
index 7af617e..e85574a 100644
--- a/lib/libc/sys/fcntl.c
+++ b/lib/libc/sys/fcntl.c
@@ -3,6 +3,12 @@
* Authors: Doug Rabson <dfr@rabson.org>
* Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
*
+ * Copyright (c) 2014-2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * 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:
@@ -48,59 +54,3 @@ fcntl(int fd, int cmd, ...)
return (((int (*)(int, int, ...))
__libc_interposing[INTERPOS_fcntl])(fd, cmd, arg));
}
-
-#ifdef SYSCALL_COMPAT
-__weak_reference(__fcntl_compat, __fcntl);
-
-int
-__fcntl_compat(int fd, int cmd, ...)
-{
- va_list args;
- long arg;
- struct __oflock ofl;
- struct flock *flp;
- int res;
-
- va_start(args, cmd);
- arg = va_arg(args, long);
- va_end(args);
-
- if (__getosreldate() >= 800028) {
- return (__sys_fcntl(fd, cmd, arg));
- } else {
- if (cmd == F_GETLK || cmd == F_SETLK || cmd == F_SETLKW) {
- /*
- * Convert new-style struct flock (which
- * includes l_sysid) to old-style.
- */
- flp = (struct flock *) (uintptr_t) arg;
- ofl.l_start = flp->l_start;
- ofl.l_len = flp->l_len;
- ofl.l_pid = flp->l_pid;
- ofl.l_type = flp->l_type;
- ofl.l_whence = flp->l_whence;
-
- switch (cmd) {
- case F_GETLK:
- res = __sys_fcntl(fd, F_OGETLK, &ofl);
- if (res >= 0) {
- flp->l_start = ofl.l_start;
- flp->l_len = ofl.l_len;
- flp->l_pid = ofl.l_pid;
- flp->l_type = ofl.l_type;
- flp->l_whence = ofl.l_whence;
- flp->l_sysid = 0;
- }
- return (res);
-
- case F_SETLK:
- return (__sys_fcntl(fd, F_OSETLK, &ofl));
-
- case F_SETLKW:
- return (__sys_fcntl(fd, F_OSETLKW, &ofl));
- }
- }
- return (__sys_fcntl(fd, cmd, arg));
- }
-}
-#endif
diff --git a/lib/libc/sys/fork.2 b/lib/libc/sys/fork.2
index 1ad2052f..4fda74d 100644
--- a/lib/libc/sys/fork.2
+++ b/lib/libc/sys/fork.2
@@ -28,7 +28,7 @@
.\" @(#)fork.2 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd May 31, 2013
+.Dd May 1, 2015
.Dt FORK 2
.Os
.Sh NAME
@@ -53,7 +53,10 @@ The child process has a unique process ID.
The child process has a different parent
process ID (i.e., the process ID of the parent process).
.It
-The child process has its own copy of the parent's descriptors.
+The child process has its own copy of the parent's descriptors,
+except for descriptors returned by
+.Xr kqueue 2 ,
+which are not inherited from the parent process.
These descriptors reference the same underlying objects, so that,
for instance, file pointers in file objects are shared between
the child and the parent, so that an
diff --git a/lib/libc/sys/interposing_table.c b/lib/libc/sys/interposing_table.c
index 4290bc6..08dfbb1 100644
--- a/lib/libc/sys/interposing_table.c
+++ b/lib/libc/sys/interposing_table.c
@@ -44,7 +44,7 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(aio_suspend, __sys_aio_suspend),
SLOT(close, __sys_close),
SLOT(connect, __sys_connect),
- SLOT(fcntl, __fcntl_compat),
+ SLOT(fcntl, __sys_fcntl),
SLOT(fsync, __sys_fsync),
SLOT(fork, __sys_fork),
SLOT(msync, __sys_msync),
@@ -76,6 +76,8 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(spinlock, __libc_spinlock_stub),
SLOT(spinunlock, __libc_spinunlock_stub),
SLOT(kevent, __sys_kevent),
+ SLOT(wait6, __sys_wait6),
+ SLOT(ppoll, __sys_ppoll),
};
#undef SLOT
diff --git a/lib/libc/sys/mount.2 b/lib/libc/sys/mount.2
index 6fe62a6..881d830 100644
--- a/lib/libc/sys/mount.2
+++ b/lib/libc/sys/mount.2
@@ -28,7 +28,7 @@
.\" @(#)mount.2 8.3 (Berkeley) 5/24/95
.\" $FreeBSD$
.\"
-.Dd January 26, 2010
+.Dd April 13, 2015
.Dt MOUNT 2
.Os
.Sh NAME
@@ -351,11 +351,6 @@ The
argument
points outside the process's allocated address space.
.El
-.Pp
-A
-.Em ufs
-mount can also fail if the maximum number of file systems are currently
-mounted.
.Sh SEE ALSO
.Xr lsvfs 1 ,
.Xr mksnap_ffs 8 ,
diff --git a/lib/libc/sys/posix_openpt.2 b/lib/libc/sys/posix_openpt.2
index d34385f..b7e345c 100644
--- a/lib/libc/sys/posix_openpt.2
+++ b/lib/libc/sys/posix_openpt.2
@@ -137,4 +137,4 @@ is included for compatibility; in
opening a terminal does not cause it to become a process's controlling
terminal.
.Sh AUTHORS
-.An Ed Schouten Aq Mt ed@FreeBSD.org
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/sys/ppoll.c b/lib/libc/sys/ppoll.c
new file mode 100644
index 0000000..f62fd19
--- /dev/null
+++ b/lib/libc/sys/ppoll.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/poll.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_ppoll, __ppoll);
+
+#pragma weak ppoll
+int
+ppoll(struct pollfd pfd[], nfds_t nfds, const struct timespec *__restrict
+ timeout, const sigset_t *__restrict newsigmask)
+{
+
+ return (((int (*)(struct pollfd *, nfds_t, const struct timespec *,
+ const sigset_t *)) __libc_interposing[INTERPOS_ppoll])(pfd, nfds,
+ timeout, newsigmask));
+}
diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2
index 2c77901..76a3cef 100644
--- a/lib/libc/sys/procctl.2
+++ b/lib/libc/sys/procctl.2
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2013 Advanced Computing Technologies LLC
+.\" Copyright (c) 2013 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/lib/libc/sys/pwrite.c b/lib/libc/sys/pwrite.c
deleted file mode 100644
index d17ed29..0000000
--- a/lib/libc/sys/pwrite.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)mmap.c 8.1 (Berkeley) 6/17/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include "libc_private.h"
-
-/*
- * This function provides 64-bit offset padding that
- * is not supplied by GCC 1.X but is supplied by GCC 2.X.
- */
-ssize_t
-pwrite(fd, buf, nbyte, offset)
- int fd;
- const void *buf;
- size_t nbyte;
- off_t offset;
-{
- if (__getosreldate() >= 700051)
- return (__sys_pwrite(fd, buf, nbyte, offset));
- else
- return (__sys_freebsd6_pwrite(fd, buf, nbyte, 0, offset));
-}
diff --git a/lib/libc/sys/vfork.2 b/lib/libc/sys/vfork.2
index f93b429..0518262 100644
--- a/lib/libc/sys/vfork.2
+++ b/lib/libc/sys/vfork.2
@@ -28,7 +28,7 @@
.\" @(#)vfork.2 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd November 13, 2009
+.Dd April 6, 2015
.Dt VFORK 2
.Os
.Sh NAME
@@ -111,7 +111,7 @@ Same as for
The
.Fn vfork
system call appeared in
-.Bx 2.9 .
+.Bx 3 .
.Sh BUGS
To avoid a possible deadlock situation,
processes that are children in the middle
diff --git a/lib/libc/sys/wait6.c b/lib/libc/sys/wait6.c
new file mode 100644
index 0000000..d280a76
--- /dev/null
+++ b/lib/libc/sys/wait6.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_wait6, __wait6);
+
+#pragma weak wait6
+pid_t
+wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *ru,
+ siginfo_t *infop)
+{
+
+ return (((pid_t (*)(idtype_t, id_t, int *, int, struct __wrusage *,
+ siginfo_t *))__libc_interposing[INTERPOS_wait6])(idtype, id,
+ status, options, ru, infop));
+}
diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile
index 323a9f0..ed1d6ca 100644
--- a/lib/libc/tests/db/Makefile
+++ b/lib/libc/tests/db/Makefile
@@ -11,6 +11,7 @@ FILESDIR= ${TESTSDIR}
FILES= README
NETBSD_ATF_TESTS_SH+= db_test
+ATF_TESTS_SH_SED_db_test= -e 's,/bin/csh,/bin/cat,g'
.include "../Makefile.netbsd-tests"
diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile
index 89431bc..5e457fd 100644
--- a/lib/libc/tests/sys/Makefile
+++ b/lib/libc/tests/sys/Makefile
@@ -12,7 +12,9 @@ NETBSD_ATF_TESTS_C+= clock_gettime_test
NETBSD_ATF_TESTS_C+= connect_test
NETBSD_ATF_TESTS_C+= dup_test
NETBSD_ATF_TESTS_C+= fsync_test
+.if ${MACHINE} != "arm64" # ARM64TODO: Missing makecontext
NETBSD_ATF_TESTS_C+= getcontext_test
+.endif
NETBSD_ATF_TESTS_C+= getgroups_test
NETBSD_ATF_TESTS_C+= getitimer_test
NETBSD_ATF_TESTS_C+= getlogin_test
diff --git a/lib/libc/xdr/xdr_float.c b/lib/libc/xdr/xdr_float.c
index 1135806..1d3bb61 100644
--- a/lib/libc/xdr/xdr_float.c
+++ b/lib/libc/xdr/xdr_float.c
@@ -64,7 +64,8 @@ __FBSDID("$FreeBSD$");
#if defined(__m68k__) || defined(__sparc__) || defined(__i386__) || \
defined(__mips__) || defined(__ns32k__) || defined(__alpha__) || \
defined(__arm__) || defined(__ppc__) || \
- defined(__arm26__) || defined(__sparc64__) || defined(__amd64__)
+ defined(__arm26__) || defined(__sparc64__) || defined(__amd64__) || \
+ defined(__aarch64__)
#include <machine/endian.h>
#define IEEEFP
#endif
diff --git a/lib/libcapsicum/libcapsicum.3 b/lib/libcapsicum/libcapsicum.3
index 9df565a..cbfd214 100644
--- a/lib/libcapsicum/libcapsicum.3
+++ b/lib/libcapsicum/libcapsicum.3
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 14, 2014
+.Dd May 2, 2015
.Dt LIBCAPSICUM 3
.Os
.Sh NAME
@@ -68,9 +68,9 @@
.Ft "int"
.Fn cap_send_nvlist "const cap_channel_t *chan" "const nvlist_t *nvl"
.Ft "nvlist_t *"
-.Fn cap_recv_nvlist "const cap_channel_t *chan"
+.Fn cap_recv_nvlist "const cap_channel_t *chan" "int flags"
.Ft "nvlist_t *"
-.Fn cap_xfer_nvlist "const cap_channel_t *chan" "nvlist_t *nvl"
+.Fn cap_xfer_nvlist "const cap_channel_t *chan" "nvlist_t *nvl" "int flags"
.In libcapsicum_service.h
.Ft "cap_channel_t *"
.Fn cap_service_open "const cap_channel_t *chan" "const char *name"
@@ -171,11 +171,23 @@ Most services should provide higher level API.
The
.Fn cap_recv_nvlist
function receives the given nvlist over the given capability.
+The
+.Fa flags
+argument defines what type the top nvlist is expected to be.
+If the nvlist flags do not match the flags passed to
+.Fn cap_recv_nvlist ,
+the nvlist will not be returned.
.Pp
The
.Fn cap_xfer_nvlist
function sends the given nvlist, destroys it and receives new nvlist in
response over the given capability.
+The
+.Fa flags
+argument defines what type the top nvlist is expected to be.
+If the nvlist flags do not match the flags passed to
+.Fn cap_xfer_nvlist ,
+the nvlist will not be returned.
It does not matter if the function succeeds or fails, the nvlist given
for sending will always be destroyed once the function returns.
.Pp
diff --git a/lib/libcapsicum/libcapsicum.c b/lib/libcapsicum/libcapsicum.c
index 79ca871..79c570f 100644
--- a/lib/libcapsicum/libcapsicum.c
+++ b/lib/libcapsicum/libcapsicum.c
@@ -142,7 +142,7 @@ cap_clone(const cap_channel_t *chan)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "clone");
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (NULL);
if (nvlist_get_number(nvl, "error") != 0) {
@@ -195,7 +195,7 @@ cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
nvlmsg = nvlist_create(0);
nvlist_add_string(nvlmsg, "cmd", "limit_set");
nvlist_add_nvlist(nvlmsg, "limits", limits);
- nvlmsg = cap_xfer_nvlist(chan, nvlmsg);
+ nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
if (nvlmsg == NULL) {
nvlist_destroy(limits);
return (-1);
@@ -218,7 +218,7 @@ cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
nvlmsg = nvlist_create(0);
nvlist_add_string(nvlmsg, "cmd", "limit_get");
- nvlmsg = cap_xfer_nvlist(chan, nvlmsg);
+ nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
if (nvlmsg == NULL)
return (-1);
error = (int)nvlist_get_number(nvlmsg, "error");
@@ -246,21 +246,21 @@ cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
}
nvlist_t *
-cap_recv_nvlist(const cap_channel_t *chan)
+cap_recv_nvlist(const cap_channel_t *chan, int flags)
{
assert(chan != NULL);
assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
- return (nvlist_recv(chan->cch_sock));
+ return (nvlist_recv(chan->cch_sock, flags));
}
nvlist_t *
-cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl)
+cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags)
{
assert(chan != NULL);
assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
- return (nvlist_xfer(chan->cch_sock, nvl));
+ return (nvlist_xfer(chan->cch_sock, nvl, flags));
}
diff --git a/lib/libcapsicum/libcapsicum.h b/lib/libcapsicum/libcapsicum.h
index 4f8c597..c7110d8 100644
--- a/lib/libcapsicum/libcapsicum.h
+++ b/lib/libcapsicum/libcapsicum.h
@@ -105,11 +105,11 @@ int cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl);
/*
* Function receives nvlist over the given capability.
*/
-nvlist_t *cap_recv_nvlist(const cap_channel_t *chan);
+nvlist_t *cap_recv_nvlist(const cap_channel_t *chan, int flags);
/*
* Function sends the given nvlist, destroys it and receives new nvlist in
* response over the given capability.
*/
-nvlist_t *cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl);
+nvlist_t *cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags);
#endif /* !_LIBCAPSICUM_H_ */
diff --git a/lib/libcapsicum/libcapsicum_dns.c b/lib/libcapsicum/libcapsicum_dns.c
index 113f8dc..a180b6b 100644
--- a/lib/libcapsicum/libcapsicum_dns.c
+++ b/lib/libcapsicum/libcapsicum_dns.c
@@ -30,6 +30,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <assert.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
@@ -67,6 +68,8 @@ static struct hostent *
hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
{
unsigned int ii, nitems;
+ char nvlname[64];
+ int n;
hostent_free(hp);
@@ -81,8 +84,10 @@ hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
if (hp->h_aliases == NULL)
goto fail;
for (ii = 0; ii < nitems; ii++) {
+ n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
hp->h_aliases[ii] =
- strdup(nvlist_getf_string(nvl, "alias%u", ii));
+ strdup(nvlist_get_string(nvl, nvlname));
if (hp->h_aliases[ii] == NULL)
goto fail;
}
@@ -96,7 +101,9 @@ hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
hp->h_addr_list[ii] = malloc(hp->h_length);
if (hp->h_addr_list[ii] == NULL)
goto fail;
- bcopy(nvlist_getf_binary(nvl, NULL, "addr%u", ii),
+ n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ bcopy(nvlist_get_binary(nvl, nvlname, NULL),
hp->h_addr_list[ii], hp->h_length);
}
hp->h_addr_list[ii] = NULL;
@@ -125,7 +132,7 @@ cap_gethostbyname2(cap_channel_t *chan, const char *name, int type)
nvlist_add_string(nvl, "cmd", "gethostbyname");
nvlist_add_number(nvl, "family", (uint64_t)type);
nvlist_add_string(nvl, "name", name);
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
@@ -152,7 +159,7 @@ cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
nvlist_add_string(nvl, "cmd", "gethostbyaddr");
nvlist_add_binary(nvl, "addr", addr, (size_t)len);
nvlist_add_number(nvl, "family", (uint64_t)type);
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
@@ -208,8 +215,9 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
struct addrinfo *firstai, *prevai, *curai;
unsigned int ii;
const nvlist_t *nvlai;
+ char nvlname[64];
nvlist_t *nvl;
- int error;
+ int error, n;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getaddrinfo");
@@ -225,7 +233,7 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
nvlist_add_number(nvl, "hints.ai_protocol",
(uint64_t)hints->ai_protocol);
}
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
@@ -237,9 +245,11 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
nvlai = NULL;
firstai = prevai = curai = NULL;
for (ii = 0; ; ii++) {
- if (!nvlist_existsf_nvlist(nvl, "res%u", ii))
+ n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ if (!nvlist_exists_nvlist(nvl, nvlname))
break;
- nvlai = nvlist_getf_nvlist(nvl, "res%u", ii);
+ nvlai = nvlist_get_nvlist(nvl, nvlname);
curai = addrinfo_unpack(nvlai);
if (curai == NULL)
break;
@@ -273,7 +283,7 @@ cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
nvlist_add_number(nvl, "flags", (uint64_t)flags);
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
@@ -314,6 +324,8 @@ cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
{
nvlist_t *limits;
unsigned int i;
+ char nvlname[64];
+ int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
@@ -321,8 +333,11 @@ cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
limits = nvlist_create(0);
else
limit_remove(limits, "type");
- for (i = 0; i < ntypes; i++)
- nvlist_addf_string(limits, types[i], "type%u", i);
+ for (i = 0; i < ntypes; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "type%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(limits, nvlname, types[i]);
+ }
return (cap_limit_set(chan, limits));
}
@@ -332,6 +347,8 @@ cap_dns_family_limit(cap_channel_t *chan, const int *families,
{
nvlist_t *limits;
unsigned int i;
+ char nvlname[64];
+ int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
@@ -340,8 +357,9 @@ cap_dns_family_limit(cap_channel_t *chan, const int *families,
else
limit_remove(limits, "family");
for (i = 0; i < nfamilies; i++) {
- nvlist_addf_number(limits, (uint64_t)families[i],
- "family%u", i);
+ n = snprintf(nvlname, sizeof(nvlname), "family%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_number(limits, nvlname, (uint64_t)families[i]);
}
return (cap_limit_set(chan, limits));
}
diff --git a/lib/libcapsicum/libcapsicum_grp.c b/lib/libcapsicum/libcapsicum_grp.c
index c679ce9..267ac68 100644
--- a/lib/libcapsicum/libcapsicum_grp.c
+++ b/lib/libcapsicum/libcapsicum_grp.c
@@ -94,9 +94,10 @@ group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp,
size_t *bufsizep)
{
const char *mem;
- char **outstrs, *str;
+ char **outstrs, *str, nvlname[64];
size_t nmem, datasize, strsize;
unsigned int ii;
+ int n;
if (!nvlist_exists_number(nvl, "gr_nmem")) {
datasize = _ALIGNBYTES + sizeof(char *);
@@ -113,7 +114,9 @@ group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp,
nmem = (size_t)nvlist_get_number(nvl, "gr_nmem");
datasize = _ALIGNBYTES + sizeof(char *) * (nmem + 1);
for (ii = 0; ii < nmem; ii++) {
- mem = dnvlist_getf_string(nvl, NULL, "gr_mem[%u]", ii);
+ n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ mem = dnvlist_get_string(nvl, nvlname, NULL);
if (mem == NULL)
return (EINVAL);
datasize += strlen(mem) + 1;
@@ -125,7 +128,9 @@ group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp,
outstrs = (char **)_ALIGN(*bufferp);
str = (char *)outstrs + sizeof(char *) * (nmem + 1);
for (ii = 0; ii < nmem; ii++) {
- mem = nvlist_getf_string(nvl, "gr_mem[%u]", ii);
+ n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ mem = nvlist_get_string(nvl, nvlname);
strsize = strlen(mem) + 1;
memcpy(str, mem, strsize);
outstrs[ii] = str;
@@ -190,7 +195,7 @@ cap_getgrcommon_r(cap_channel_t *chan, const char *cmd, const char *name,
} else {
abort();
}
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
assert(errno != 0);
*result = NULL;
@@ -314,7 +319,7 @@ cap_setgroupent(cap_channel_t *chan, int stayopen)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setgroupent");
nvlist_add_bool(nvl, "stayopen", stayopen != 0);
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
@@ -334,7 +339,7 @@ cap_setgrent(cap_channel_t *chan)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setgrent");
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
@@ -355,7 +360,7 @@ cap_endgrent(cap_channel_t *chan)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "endgrent");
/* Ignore any errors, we have no way to report them. */
- nvlist_destroy(cap_xfer_nvlist(chan, nvl));
+ nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
}
int
@@ -407,6 +412,8 @@ cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
{
nvlist_t *limits, *groups;
unsigned int i;
+ char nvlname[64];
+ int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
@@ -417,10 +424,16 @@ cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
nvlist_free_nvlist(limits, "groups");
}
groups = nvlist_create(0);
- for (i = 0; i < ngids; i++)
- nvlist_addf_number(groups, (uint64_t)gids[i], "gid%u", i);
- for (i = 0; i < nnames; i++)
- nvlist_addf_string(groups, names[i], "name%u", i);
+ for (i = 0; i < ngids; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_number(groups, nvlname, (uint64_t)gids[i]);
+ }
+ for (i = 0; i < nnames; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(groups, nvlname, names[i]);
+ }
nvlist_move_nvlist(limits, "groups", groups);
return (cap_limit_set(chan, limits));
}
diff --git a/lib/libcapsicum/libcapsicum_pwd.c b/lib/libcapsicum/libcapsicum_pwd.c
index 792fb66..32eeeb0 100644
--- a/lib/libcapsicum/libcapsicum_pwd.c
+++ b/lib/libcapsicum/libcapsicum_pwd.c
@@ -154,7 +154,7 @@ cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
} else {
abort();
}
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
assert(errno != 0);
*result = NULL;
@@ -278,7 +278,7 @@ cap_setpassent(cap_channel_t *chan, int stayopen)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setpassent");
nvlist_add_bool(nvl, "stayopen", stayopen != 0);
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
@@ -299,7 +299,7 @@ cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", cmd);
/* Ignore any errors, we have no way to report them. */
- nvlist_destroy(cap_xfer_nvlist(chan, nvl));
+ nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
}
void
@@ -364,7 +364,9 @@ cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
size_t nnames, uid_t *uids, size_t nuids)
{
nvlist_t *limits, *users;
+ char nvlname[64];
unsigned int i;
+ int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
@@ -375,10 +377,16 @@ cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
nvlist_free_nvlist(limits, "users");
}
users = nvlist_create(0);
- for (i = 0; i < nuids; i++)
- nvlist_addf_number(users, (uint64_t)uids[i], "uid%u", i);
- for (i = 0; i < nnames; i++)
- nvlist_addf_string(users, names[i], "name%u", i);
+ for (i = 0; i < nuids; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "uid%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_number(users, nvlname, (uint64_t)uids[i]);
+ }
+ for (i = 0; i < nnames; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "name%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(users, nvlname, names[i]);
+ }
nvlist_move_nvlist(limits, "users", users);
return (cap_limit_set(chan, limits));
}
diff --git a/lib/libcapsicum/libcapsicum_random.c b/lib/libcapsicum/libcapsicum_random.c
index eed97e2..2c3eb36 100644
--- a/lib/libcapsicum/libcapsicum_random.c
+++ b/lib/libcapsicum/libcapsicum_random.c
@@ -57,7 +57,7 @@ cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes)
nvlist_add_string(nvl, "cmd", "generate");
nvlist_add_number(nvl, "size",
(uint64_t)(left > MAXSIZE ? MAXSIZE : left));
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_get_number(nvl, "error") != 0) {
diff --git a/lib/libcapsicum/libcapsicum_service.c b/lib/libcapsicum/libcapsicum_service.c
index 4127668..edfde8c 100644
--- a/lib/libcapsicum/libcapsicum_service.c
+++ b/lib/libcapsicum/libcapsicum_service.c
@@ -56,7 +56,7 @@ cap_service_open(const cap_channel_t *chan, const char *name)
nvlist_add_string(nvl, "service", name);
if (fd_is_valid(STDERR_FILENO))
nvlist_add_descriptor(nvl, "stderrfd", STDERR_FILENO);
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (NULL);
error = (int)nvlist_get_number(nvl, "error");
diff --git a/lib/libcapsicum/libcapsicum_sysctl.c b/lib/libcapsicum/libcapsicum_sysctl.c
index 6ea951b..fc69113 100644
--- a/lib/libcapsicum/libcapsicum_sysctl.c
+++ b/lib/libcapsicum/libcapsicum_sysctl.c
@@ -63,7 +63,7 @@ cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp);
if (newp != NULL)
nvlist_add_binary(nvl, "newp", newp, newlen);
- nvl = cap_xfer_nvlist(chan, nvl);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_get_number(nvl, "error") != 0) {
diff --git a/lib/libcasper/libcasper.c b/lib/libcasper/libcasper.c
index 7545baa..cb95346 100644
--- a/lib/libcasper/libcasper.c
+++ b/lib/libcasper/libcasper.c
@@ -279,7 +279,7 @@ casper_message(const cap_channel_t *capcas, struct service *service)
const char *cmd;
nvlist_t *nvl;
- nvl = cap_recv_nvlist(capcas);
+ nvl = cap_recv_nvlist(capcas, 0);
if (nvl == NULL)
pjdlog_exit(1, "Unable to receive message from Casper");
cmd = nvlist_get_string(nvl, "cmd");
@@ -297,7 +297,7 @@ service_message(struct service *service, struct service_connection *sconn)
const char *cmd;
int error;
- nvlin = cap_recv_nvlist(service_connection_get_chan(sconn));
+ nvlin = cap_recv_nvlist(service_connection_get_chan(sconn), 0);
if (nvlin == NULL) {
if (errno == ENOTCONN) {
pjdlog_debug(1, "Connection closed by the client.");
diff --git a/lib/libcompiler_rt/Makefile b/lib/libcompiler_rt/Makefile
index 5c5e110..5e21883 100644
--- a/lib/libcompiler_rt/Makefile
+++ b/lib/libcompiler_rt/Makefile
@@ -22,7 +22,6 @@ CRTSRC=${.CURDIR}/../../contrib/compiler-rt/lib/builtins
SRCF= absvdi2 \
absvsi2 \
absvti2 \
- addtf3 \
addvdi3 \
addvsi3 \
addvti3 \
@@ -37,7 +36,6 @@ SRCF= absvdi2 \
clzti2 \
cmpdi2 \
cmpti2 \
- comparetf2 \
ctzdi2 \
ctzsi2 \
ctzti2 \
@@ -46,31 +44,22 @@ SRCF= absvdi2 \
divmoddi4 \
divmodsi4 \
divsc3 \
- divtf3 \
divti3 \
divxc3 \
enable_execute_stack \
eprintf \
- extenddftf2 \
- extendsftf2 \
ffsdi2 \
ffsti2 \
fixdfdi \
fixdfti \
fixsfdi \
fixsfti \
- fixtfdi \
- fixtfsi \
- fixtfti \
fixunsdfdi \
fixunsdfsi \
fixunsdfti \
fixunssfdi \
fixunssfsi \
fixunssfti \
- fixunstfdi \
- fixunstfsi \
- fixunstfti \
fixunsxfdi \
fixunsxfsi \
fixunsxfti \
@@ -78,6 +67,7 @@ SRCF= absvdi2 \
fixxfti \
floatdidf \
floatdisf \
+ floatditf \
floatdixf \
floatsitf \
floattidf \
@@ -85,6 +75,7 @@ SRCF= absvdi2 \
floattixf \
floatundidf \
floatundisf \
+ floatunditf \
floatundixf \
floatunsidf \
floatunsisf \
@@ -103,11 +94,11 @@ SRCF= absvdi2 \
mulosi4 \
muloti4 \
mulsc3 \
- multf3 \
multi3 \
mulvdi3 \
mulvsi3 \
mulvti3 \
+ multc3 \
mulxc3 \
negdf2 \
negdi2 \
@@ -126,13 +117,10 @@ SRCF= absvdi2 \
powisf2 \
powitf2 \
powixf2 \
- subtf3 \
subvdi3 \
subvsi3 \
subvti3 \
trampoline_setup \
- trunctfdf2 \
- trunctfsf2 \
ucmpdi2 \
ucmpti2 \
udivdi3 \
@@ -143,6 +131,26 @@ SRCF= absvdi2 \
umoddi3 \
umodti3
+# 128-bit quad precision long double support, only used on arm64
+.if ${MACHINE_CPUARCH} == "aarch64"
+SRCF+= addtf3 \
+ comparetf2 \
+ divtf3 \
+ extenddftf2 \
+ extendsftf2 \
+ fixtfdi \
+ fixtfsi \
+ fixtfti \
+ fixunstfdi \
+ fixunstfsi \
+ fixunstfti \
+ floatunsitf \
+ multf3 \
+ subtf3 \
+ trunctfdf2 \
+ trunctfsf2
+.endif
+
# These are already shipped by libc.a on arm and mips
.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "mips"
SRCF+= adddf3 \
diff --git a/lib/libedit/el.c b/lib/libedit/el.c
index beb961e..a0d7015 100644
--- a/lib/libedit/el.c
+++ b/lib/libedit/el.c
@@ -96,7 +96,7 @@ el_init_fd(const char *prog, FILE *fin, FILE *fout, FILE *ferr,
*/
el->el_flags = 0;
#ifdef WIDECHAR
- if (setlocale(LC_CTYPE, "") != NULL) {
+ if (setlocale(LC_CTYPE, NULL) != NULL) {
if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
el->el_flags |= CHARSET_IS_UTF8;
}
diff --git a/lib/libelftc/elftc_version.c b/lib/libelftc/elftc_version.c
index 5df0587..7a8c96a 100644
--- a/lib/libelftc/elftc_version.c
+++ b/lib/libelftc/elftc_version.c
@@ -6,5 +6,5 @@
const char *
elftc_version(void)
{
- return "elftoolchain r3163M";
+ return "elftoolchain r3179M";
}
diff --git a/lib/libgeom/geom_xml2tree.c b/lib/libgeom/geom_xml2tree.c
index d5d4f31..2c23361 100644
--- a/lib/libgeom/geom_xml2tree.c
+++ b/lib/libgeom/geom_xml2tree.c
@@ -257,6 +257,7 @@ EndElement(void *userData, const char *name)
if (!strcmp(name, "config")) {
mt->config = NULL;
+ free(p);
return;
}
diff --git a/lib/libiconv_modules/BIG5/citrus_big5.c b/lib/libiconv_modules/BIG5/citrus_big5.c
index a8376eb..8dffc65 100644
--- a/lib/libiconv_modules/BIG5/citrus_big5.c
+++ b/lib/libiconv_modules/BIG5/citrus_big5.c
@@ -269,12 +269,12 @@ static int
/*ARGSUSED*/
_citrus_BIG5_mbrtowc_priv(_BIG5EncodingInfo * __restrict ei,
wchar_t * __restrict pwc,
- const char ** __restrict s, size_t n,
+ char ** __restrict s, size_t n,
_BIG5State * __restrict psenc,
size_t * __restrict nresult)
{
wchar_t wchar;
- const char *s0;
+ char *s0;
int c, chlenbak;
s0 = *s;
diff --git a/lib/libiconv_modules/DECHanyu/citrus_dechanyu.c b/lib/libiconv_modules/DECHanyu/citrus_dechanyu.c
index fc32018..ec2c597 100644
--- a/lib/libiconv_modules/DECHanyu/citrus_dechanyu.c
+++ b/lib/libiconv_modules/DECHanyu/citrus_dechanyu.c
@@ -165,10 +165,10 @@ is_94charset(int c)
static int
/*ARGSUSED*/
_citrus_DECHanyu_mbrtowc_priv(_DECHanyuEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_DECHanyuState * __restrict psenc, size_t * __restrict nresult)
{
- const char *s0;
+ char *s0;
wchar_t wc;
int ch;
diff --git a/lib/libiconv_modules/EUC/citrus_euc.c b/lib/libiconv_modules/EUC/citrus_euc.c
index 6483eb5..e0c2d23 100644
--- a/lib/libiconv_modules/EUC/citrus_euc.c
+++ b/lib/libiconv_modules/EUC/citrus_euc.c
@@ -190,12 +190,12 @@ _citrus_EUC_unpack_state(_EUCEncodingInfo *ei __unused, _EUCState *s,
#endif
static int
-_citrus_EUC_mbrtowc_priv(_EUCEncodingInfo *ei, wchar_t *pwc, const char **s,
+_citrus_EUC_mbrtowc_priv(_EUCEncodingInfo *ei, wchar_t *pwc, char **s,
size_t n, _EUCState *psenc, size_t *nresult)
{
wchar_t wchar;
int c, chlenbak, cs, len;
- const char *s0, *s1 = NULL;
+ char *s0, *s1 = NULL;
s0 = *s;
diff --git a/lib/libiconv_modules/EUCTW/citrus_euctw.c b/lib/libiconv_modules/EUCTW/citrus_euctw.c
index c35423e..6c3e9f6 100644
--- a/lib/libiconv_modules/EUCTW/citrus_euctw.c
+++ b/lib/libiconv_modules/EUCTW/citrus_euctw.c
@@ -176,10 +176,10 @@ _citrus_EUCTW_encoding_module_uninit(_EUCTWEncodingInfo *ei __unused)
static int
_citrus_EUCTW_mbrtowc_priv(_EUCTWEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s,
+ wchar_t * __restrict pwc, char ** __restrict s,
size_t n, _EUCTWState * __restrict psenc, size_t * __restrict nresult)
{
- const char *s0;
+ char *s0;
wchar_t wchar;
int c, chlenbak, cs;
diff --git a/lib/libiconv_modules/GBK2K/citrus_gbk2k.c b/lib/libiconv_modules/GBK2K/citrus_gbk2k.c
index 50ea2da..b64c7e0 100644
--- a/lib/libiconv_modules/GBK2K/citrus_gbk2k.c
+++ b/lib/libiconv_modules/GBK2K/citrus_gbk2k.c
@@ -149,10 +149,10 @@ _mb_count(wchar_t v)
static int
_citrus_GBK2K_mbrtowc_priv(_GBK2KEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_GBK2KState * __restrict psenc, size_t * __restrict nresult)
{
- const char *s0, *s1;
+ char *s0, *s1;
wchar_t wc;
int chlenbak, len;
diff --git a/lib/libiconv_modules/HZ/citrus_hz.c b/lib/libiconv_modules/HZ/citrus_hz.c
index d772b38..13d2f2c 100644
--- a/lib/libiconv_modules/HZ/citrus_hz.c
+++ b/lib/libiconv_modules/HZ/citrus_hz.c
@@ -175,13 +175,13 @@ _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei __unused,
static int
_citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_HZState * __restrict psenc, size_t * __restrict nresult)
{
escape_t *candidate, *init;
graphic_t *graphic;
const range_t *range;
- const char *s0;
+ char *s0;
wchar_t wc;
int bit, ch, head, len, tail;
diff --git a/lib/libiconv_modules/ISO2022/citrus_iso2022.c b/lib/libiconv_modules/ISO2022/citrus_iso2022.c
index 3402ba8..f3613d6 100644
--- a/lib/libiconv_modules/ISO2022/citrus_iso2022.c
+++ b/lib/libiconv_modules/ISO2022/citrus_iso2022.c
@@ -574,7 +574,7 @@ terminate:
static wchar_t
_ISO2022_sgetwchar(_ISO2022EncodingInfo * __restrict ei __unused,
- const char * __restrict string, size_t n, const char ** __restrict result,
+ char * __restrict string, size_t n, char ** __restrict result,
_ISO2022State * __restrict psenc)
{
const struct seqtable *sp;
@@ -842,10 +842,10 @@ asis:
static int
_citrus_ISO2022_mbrtowc_priv(_ISO2022EncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s,
+ wchar_t * __restrict pwc, char ** __restrict s,
size_t n, _ISO2022State * __restrict psenc, size_t * __restrict nresult)
{
- const char *p, *result, *s0;
+ char *p, *result, *s0;
wchar_t wchar;
int c, chlenbak;
diff --git a/lib/libiconv_modules/JOHAB/citrus_johab.c b/lib/libiconv_modules/JOHAB/citrus_johab.c
index a533a85..459f8c9 100644
--- a/lib/libiconv_modules/JOHAB/citrus_johab.c
+++ b/lib/libiconv_modules/JOHAB/citrus_johab.c
@@ -145,10 +145,10 @@ ishanja(int l, int t)
static int
/*ARGSUSED*/
_citrus_JOHAB_mbrtowc_priv(_JOHABEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_JOHABState * __restrict psenc, size_t * __restrict nresult)
{
- const char *s0;
+ char *s0;
int l, t;
if (*s == NULL) {
diff --git a/lib/libiconv_modules/MSKanji/citrus_mskanji.c b/lib/libiconv_modules/MSKanji/citrus_mskanji.c
index 8549699..4330cc8 100644
--- a/lib/libiconv_modules/MSKanji/citrus_mskanji.c
+++ b/lib/libiconv_modules/MSKanji/citrus_mskanji.c
@@ -153,10 +153,10 @@ _citrus_MSKanji_unpack_state(_MSKanjiEncodingInfo * __restrict ei __unused,
static int
/*ARGSUSED*/
_citrus_MSKanji_mbrtowc_priv(_MSKanjiEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_MSKanjiState * __restrict psenc, size_t * __restrict nresult)
{
- const char *s0;
+ char *s0;
wchar_t wchar;
int chlenbak, len;
diff --git a/lib/libiconv_modules/UES/citrus_ues.c b/lib/libiconv_modules/UES/citrus_ues.c
index 45f5416..8516c2a 100644
--- a/lib/libiconv_modules/UES/citrus_ues.c
+++ b/lib/libiconv_modules/UES/citrus_ues.c
@@ -185,10 +185,10 @@ is_basic(wchar_t wc)
static int
_citrus_UES_mbrtowc_priv(_UESEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_UESState * __restrict psenc, size_t * __restrict nresult)
{
- const char *s0;
+ char *s0;
int ch, head, num, tail;
wchar_t hi, wc;
diff --git a/lib/libiconv_modules/UTF1632/citrus_utf1632.c b/lib/libiconv_modules/UTF1632/citrus_utf1632.c
index 4ef4db1..6682ab2 100644
--- a/lib/libiconv_modules/UTF1632/citrus_utf1632.c
+++ b/lib/libiconv_modules/UTF1632/citrus_utf1632.c
@@ -97,9 +97,9 @@ _citrus_UTF1632_init_state(_UTF1632EncodingInfo *ei __unused,
static int
_citrus_UTF1632_mbrtowc_priv(_UTF1632EncodingInfo *ei, wchar_t *pwc,
- const char **s, size_t n, _UTF1632State *psenc, size_t *nresult)
+ char **s, size_t n, _UTF1632State *psenc, size_t *nresult)
{
- const char *s0;
+ char *s0;
size_t result;
wchar_t wc = L'\0';
int chlenbak, endian, needlen;
diff --git a/lib/libiconv_modules/UTF7/citrus_utf7.c b/lib/libiconv_modules/UTF7/citrus_utf7.c
index 53f4f77..ce74cfe 100644
--- a/lib/libiconv_modules/UTF7/citrus_utf7.c
+++ b/lib/libiconv_modules/UTF7/citrus_utf7.c
@@ -151,11 +151,11 @@ static const char spaces[] = " \t\r\n";
static int
_citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,
- uint16_t * __restrict u16, const char ** __restrict s, size_t n,
+ uint16_t * __restrict u16, char ** __restrict s, size_t n,
_UTF7State * __restrict psenc, size_t * __restrict nresult)
{
_UTF7State sv;
- const char *s0;
+ char *s0;
int done, i, len;
s0 = *s;
@@ -244,7 +244,7 @@ ilseq:
static int
_citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_UTF7State * __restrict psenc, size_t * __restrict nresult)
{
uint32_t u32;
diff --git a/lib/libiconv_modules/UTF8/citrus_utf8.c b/lib/libiconv_modules/UTF8/citrus_utf8.c
index d7c78d3..1bf433e 100644
--- a/lib/libiconv_modules/UTF8/citrus_utf8.c
+++ b/lib/libiconv_modules/UTF8/citrus_utf8.c
@@ -177,10 +177,10 @@ _citrus_UTF8_unpack_state(_UTF8EncodingInfo *ei __unused, _UTF8State *s,
#endif
static int
-_citrus_UTF8_mbrtowc_priv(_UTF8EncodingInfo *ei, wchar_t *pwc, const char **s,
+_citrus_UTF8_mbrtowc_priv(_UTF8EncodingInfo *ei, wchar_t *pwc, char **s,
size_t n, _UTF8State *psenc, size_t *nresult)
{
- const char *s0;
+ char *s0;
wchar_t wchar;
int i;
uint8_t c;
diff --git a/lib/libiconv_modules/VIQR/citrus_viqr.c b/lib/libiconv_modules/VIQR/citrus_viqr.c
index dddb0b0..ed91cf6 100644
--- a/lib/libiconv_modules/VIQR/citrus_viqr.c
+++ b/lib/libiconv_modules/VIQR/citrus_viqr.c
@@ -252,11 +252,11 @@ _citrus_VIQR_unpack_state(_VIQREncodingInfo * __restrict ei __unused,
static int
_citrus_VIQR_mbrtowc_priv(_VIQREncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
+ wchar_t * __restrict pwc, char ** __restrict s, size_t n,
_VIQRState * __restrict psenc, size_t * __restrict nresult)
{
mnemonic_t *m, *m0;
- const char *s0;
+ char *s0;
wchar_t wc;
ssize_t i;
int ch, escape;
diff --git a/lib/libiconv_modules/ZW/citrus_zw.c b/lib/libiconv_modules/ZW/citrus_zw.c
index 097fcfe..1728e3b 100644
--- a/lib/libiconv_modules/ZW/citrus_zw.c
+++ b/lib/libiconv_modules/ZW/citrus_zw.c
@@ -107,10 +107,10 @@ _citrus_ZW_unpack_state(_ZWEncodingInfo * __restrict ei __unused,
static int
_citrus_ZW_mbrtowc_priv(_ZWEncodingInfo * __restrict ei,
- wchar_t * __restrict pwc, const char **__restrict s, size_t n,
+ wchar_t * __restrict pwc, char **__restrict s, size_t n,
_ZWState * __restrict psenc, size_t * __restrict nresult)
{
- const char *s0;
+ char *s0;
wchar_t wc;
int ch, len;
diff --git a/lib/libiconv_modules/iconv_none/citrus_iconv_none.c b/lib/libiconv_modules/iconv_none/citrus_iconv_none.c
index 967ee13..9d6cd31 100644
--- a/lib/libiconv_modules/iconv_none/citrus_iconv_none.c
+++ b/lib/libiconv_modules/iconv_none/citrus_iconv_none.c
@@ -97,7 +97,7 @@ _citrus_iconv_none_iconv_uninit_context(struct _citrus_iconv *cv __unused)
static int
/*ARGSUSED*/
_citrus_iconv_none_iconv_convert(struct _citrus_iconv * __restrict ci __unused,
- const char * __restrict * __restrict in, size_t * __restrict inbytes,
+ char * __restrict * __restrict in, size_t * __restrict inbytes,
char * __restrict * __restrict out, size_t * __restrict outbytes,
uint32_t flags __unused, size_t * __restrict invalids)
{
diff --git a/lib/libiconv_modules/iconv_std/citrus_iconv_std.c b/lib/libiconv_modules/iconv_std/citrus_iconv_std.c
index 7c9b064..fd9a68c 100644
--- a/lib/libiconv_modules/iconv_std/citrus_iconv_std.c
+++ b/lib/libiconv_modules/iconv_std/citrus_iconv_std.c
@@ -104,7 +104,7 @@ init_encoding_state(struct _citrus_iconv_std_encoding *se)
static __inline int
mbtocsx(struct _citrus_iconv_std_encoding *se,
- _csid_t *csid, _index_t *idx, const char **s, size_t n, size_t *nresult,
+ _csid_t *csid, _index_t *idx, char **s, size_t n, size_t *nresult,
struct iconv_hooks *hooks)
{
@@ -461,7 +461,7 @@ _citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv *cv)
static int
_citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv,
- const char * __restrict * __restrict in, size_t * __restrict inbytes,
+ char * __restrict * __restrict in, size_t * __restrict inbytes,
char * __restrict * __restrict out, size_t * __restrict outbytes,
uint32_t flags, size_t * __restrict invalids)
{
@@ -469,7 +469,7 @@ _citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv,
struct _citrus_iconv_std_context *sc = cv->cv_closure;
_csid_t csid;
_index_t idx;
- const char *tmpin;
+ char *tmpin;
size_t inval, szrin, szrout;
int ret, state = 0;
diff --git a/lib/libkiconv/xlat16_iconv.c b/lib/libkiconv/xlat16_iconv.c
index fee3c77..3efb779 100644
--- a/lib/libkiconv/xlat16_iconv.c
+++ b/lib/libkiconv/xlat16_iconv.c
@@ -62,7 +62,7 @@ static int chklocale(int, const char *);
typedef void *iconv_t;
static int my_iconv_init(void);
static iconv_t (*my_iconv_open)(const char *, const char *);
-static size_t (*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
+static size_t (*my_iconv)(iconv_t, char **, size_t *, char **, size_t *);
static int (*my_iconv_close)(iconv_t);
#else
#include <iconv.h>
@@ -71,7 +71,7 @@ static int (*my_iconv_close)(iconv_t);
#define my_iconv iconv
#define my_iconv_close iconv_close
#endif
-static size_t my_iconv_char(iconv_t, const u_char **, size_t *, u_char **, size_t *);
+static size_t my_iconv_char(iconv_t, u_char **, size_t *, u_char **, size_t *);
int
kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag)
@@ -221,8 +221,8 @@ kiconv_xlat16_open(const char *tocode, const char *fromcode, int lcase)
src[0] = (u_char)(c >> 8);
src[1] = (u_char)c;
- ret = my_iconv_char(cd, (const u_char **)&srcp,
- &inbytesleft, &dstp, &outbytesleft);
+ ret = my_iconv_char(cd, &srcp, &inbytesleft,
+ &dstp, &outbytesleft);
if (ret == -1) {
table[us] = 0;
continue;
@@ -338,11 +338,10 @@ my_iconv_init(void)
#endif
static size_t
-my_iconv_char(iconv_t cd, const u_char **ibuf, size_t * ilen, u_char **obuf,
+my_iconv_char(iconv_t cd, u_char **ibuf, size_t * ilen, u_char **obuf,
size_t * olen)
{
- const u_char *sp;
- u_char *dp, ilocal[3], olocal[3];
+ u_char *sp, *dp, ilocal[3], olocal[3];
u_char c1, c2;
int ret;
size_t ir, or;
@@ -352,7 +351,7 @@ my_iconv_char(iconv_t cd, const u_char **ibuf, size_t * ilen, u_char **obuf,
ir = *ilen;
bzero(*obuf, *olen);
- ret = my_iconv(cd, (const char **)&sp, ilen, (char **)&dp, olen);
+ ret = my_iconv(cd, (char **)&sp, ilen, (char **)&dp, olen);
c1 = (*obuf)[0];
c2 = (*obuf)[1];
@@ -375,7 +374,7 @@ my_iconv_char(iconv_t cd, const u_char **ibuf, size_t * ilen, u_char **obuf,
sp = ilocal;
dp = olocal;
- if ((my_iconv(cd,(const char **)&sp, &ir, (char **)&dp, &or)) != -1) {
+ if ((my_iconv(cd,(char **)&sp, &ir, (char **)&dp, &or)) != -1) {
if (olocal[0] != c1)
return (ret);
@@ -429,7 +428,7 @@ my_iconv_char(iconv_t cd, const u_char **ibuf, size_t * ilen, u_char **obuf,
sp = ilocal + 1;
dp = olocal;
- if ((my_iconv(cd,(const char **)&sp, &ir, (char **)&dp, &or)) != -1) {
+ if ((my_iconv(cd,(char **)&sp, &ir, (char **)&dp, &or)) != -1) {
if (olocal[0] == c2)
/*
* inbuf is a single byte char
diff --git a/lib/liblzma/Symbol.map b/lib/liblzma/Symbol.map
index 565280d..c297625 100644
--- a/lib/liblzma/Symbol.map
+++ b/lib/liblzma/Symbol.map
@@ -108,7 +108,9 @@ XZ_5.2 {
XZprivate_1.0 {
lzma_alloc;
+ lzma_alloc_zero;
lzma_alone_decoder_init;
+ lzma_block_buffer_bound64;
lzma_block_decoder_init;
lzma_block_encoder_init;
lzma_bufcpy;
@@ -131,6 +133,7 @@ XZprivate_1.0 {
lzma_lz_decoder_uncompressed;
lzma_lz_encoder_init;
lzma_lz_encoder_memusage;
+ lzma_lzma2_block_size;
lzma_lzma2_decoder_init;
lzma_lzma2_decoder_memusage;
lzma_lzma2_encoder_init;
@@ -163,9 +166,16 @@ XZprivate_1.0 {
lzma_mf_hc3_skip;
lzma_mf_hc4_find;
lzma_mf_hc4_skip;
+ lzma_mt_block_size;
lzma_next_end;
lzma_next_filter_init;
lzma_next_filter_update;
+ lzma_outq_end;
+ lzma_outq_get_buf;
+ lzma_outq_init;
+ lzma_outq_is_readable;
+ lzma_outq_memusage;
+ lzma_outq_read;
lzma_raw_coder_init;
lzma_raw_coder_memusage;
lzma_raw_decoder_init;
@@ -190,7 +200,7 @@ XZprivate_1.0 {
lzma_simple_x86_decoder_init;
lzma_simple_x86_encoder_init;
lzma_stream_decoder_init;
- lzma_stream_encoder_init;
lzma_strm_init;
+ lzma_tuklib_cpucores;
lzma_tuklib_physmem;
};
diff --git a/lib/liblzma/config.h b/lib/liblzma/config.h
index 29b7fdb..1d0f0bc 100644
--- a/lib/liblzma/config.h
+++ b/lib/liblzma/config.h
@@ -1,95 +1,427 @@
/* $FreeBSD$ */
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* How many MiB of RAM to assume if the real amount cannot be determined. */
#define ASSUME_RAM 128
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+/* FreeBSD - disabled intentionally */
+/* #undef ENABLE_NLS */
+
+/* Define to 1 if bswap_16 is available. */
+/* #undef HAVE_BSWAP_16 */
+
+/* Define to 1 if bswap_32 is available. */
+/* #undef HAVE_BSWAP_32 */
+
+/* Define to 1 if bswap_64 is available. */
+/* #undef HAVE_BSWAP_64 */
+
+/* Define to 1 if you have the <byteswap.h> header file. */
+/* #undef HAVE_BYTESWAP_H */
+
+/* Define to 1 if the system has the type `CC_SHA256_CTX'. */
+/* #undef HAVE_CC_SHA256_CTX */
+
+/* Define to 1 if you have the `CC_SHA256_Init' function. */
+/* #undef HAVE_CC_SHA256_INIT */
+
+/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+/* #undef HAVE_CFLOCALECOPYCURRENT */
+
+/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
+
+/* Define to 1 if crc32 integrity check is enabled. */
#define HAVE_CHECK_CRC32 1
+
+/* Define to 1 if crc64 integrity check is enabled. */
#define HAVE_CHECK_CRC64 1
+
+/* Define to 1 if sha256 integrity check is enabled. */
#define HAVE_CHECK_SHA256 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the <CommonCrypto/CommonDigest.h> header file. */
+/* #undef HAVE_COMMONCRYPTO_COMMONDIGEST_H */
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+/* FreeBSD - disabled intentionally */
+/* #undef HAVE_DCGETTEXT */
+
+/* Define to 1 if you have the declaration of `CLOCK_MONOTONIC', and to 0 if
+ you don't. */
#define HAVE_DECL_CLOCK_MONOTONIC 1
+
+/* Define to 1 if you have the declaration of `program_invocation_name', and
+ to 0 if you don't. */
#define HAVE_DECL_PROGRAM_INVOCATION_NAME 0
+
+/* Define to 1 if arm decoder is enabled. */
#define HAVE_DECODER_ARM 1
+
+/* Define to 1 if armthumb decoder is enabled. */
#define HAVE_DECODER_ARMTHUMB 1
+
+/* Define to 1 if delta decoder is enabled. */
#define HAVE_DECODER_DELTA 1
+
+/* Define to 1 if ia64 decoder is enabled. */
#define HAVE_DECODER_IA64 1
+
+/* Define to 1 if lzma1 decoder is enabled. */
#define HAVE_DECODER_LZMA1 1
+
+/* Define to 1 if lzma2 decoder is enabled. */
#define HAVE_DECODER_LZMA2 1
+
+/* Define to 1 if powerpc decoder is enabled. */
#define HAVE_DECODER_POWERPC 1
+
+/* Define to 1 if sparc decoder is enabled. */
#define HAVE_DECODER_SPARC 1
+
+/* Define to 1 if x86 decoder is enabled. */
#define HAVE_DECODER_X86 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
+
+/* Define to 1 if arm encoder is enabled. */
#define HAVE_ENCODER_ARM 1
+
+/* Define to 1 if armthumb encoder is enabled. */
#define HAVE_ENCODER_ARMTHUMB 1
+
+/* Define to 1 if delta encoder is enabled. */
#define HAVE_ENCODER_DELTA 1
+
+/* Define to 1 if ia64 encoder is enabled. */
#define HAVE_ENCODER_IA64 1
+
+/* Define to 1 if lzma1 encoder is enabled. */
#define HAVE_ENCODER_LZMA1 1
+
+/* Define to 1 if lzma2 encoder is enabled. */
#define HAVE_ENCODER_LZMA2 1
+
+/* Define to 1 if powerpc encoder is enabled. */
#define HAVE_ENCODER_POWERPC 1
+
+/* Define to 1 if sparc encoder is enabled. */
#define HAVE_ENCODER_SPARC 1
+
+/* Define to 1 if x86 encoder is enabled. */
#define HAVE_ENCODER_X86 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `futimens' function. */
#define HAVE_FUTIMENS 1
-#define HAVE_FUTIMES 1
+
+/* Define to 1 if you have the `futimes' function. */
+/* #undef HAVE_FUTIMES */
+
+/* Define to 1 if you have the `futimesat' function. */
+/* #undef HAVE_FUTIMESAT */
+
+/* Define to 1 if you have the <getopt.h> header file. */
#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
#define HAVE_GETOPT_LONG 1
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+/* FreeBSD - disabled intentionally */
+/* #undef HAVE_GETTEXT */
+
+/* Define if you have the iconv() function and it works. */
+#define HAVE_ICONV 1
+
+/* Define to 1 if you have the <immintrin.h> header file. */
+#if defined(__FreeBSD__) && defined(__amd64__)
+#define HAVE_IMMINTRIN_H 1
+#endif
+
+/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
#define HAVE_MBRTOWC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
+
+/* Define to 1 to enable bt2 match finder. */
#define HAVE_MF_BT2 1
+
+/* Define to 1 to enable bt3 match finder. */
#define HAVE_MF_BT3 1
+
+/* Define to 1 to enable bt4 match finder. */
#define HAVE_MF_BT4 1
+
+/* Define to 1 to enable hc3 match finder. */
#define HAVE_MF_HC3 1
+
+/* Define to 1 to enable hc4 match finder. */
#define HAVE_MF_HC4 1
+
+/* Define to 1 if you have the <minix/sha2.h> header file. */
+/* #undef HAVE_MINIX_SHA2_H */
+
+/* Define to 1 if getopt.h declares extern int optreset. */
#define HAVE_OPTRESET 1
+
+/* Define to 1 if you have the `pipe2' function. */
+#define HAVE_PIPE2 1
+
+/* Define to 1 if you have the `posix_fadvise' function. */
#define HAVE_POSIX_FADVISE 1
+
+/* Define to 1 if you have the `pthread_condattr_setclock' function. */
#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1
+
+/* Have PTHREAD_PRIO_INHERIT. */
#define HAVE_PTHREAD_PRIO_INHERIT 1
+
+/* Define to 1 if you have the `SHA256Init' function. */
+/* #undef HAVE_SHA256INIT */
+
+/* Define to 1 if the system has the type `SHA256_CTX'. */
+/* FreeBSD - disabled libmd SHA256 for now */
+/* #undef HAVE_SHA256_CTX */
+
+/* Define to 1 if you have the <sha256.h> header file. */
+/* FreeBSD - disabled libmd SHA256 for now */
+/* #undef HAVE_SHA256_H */
+
+/* Define to 1 if you have the `SHA256_Init' function. */
+/* FreeBSD - disabled libmd SHA256 for now */
+/* #undef HAVE_SHA256_INIT */
+
+/* Define to 1 if the system has the type `SHA2_CTX'. */
+/* #undef HAVE_SHA2_CTX */
+
+/* Define to 1 if you have the <sha2.h> header file. */
+/* #undef HAVE_SHA2_H */
+
+/* Define to 1 if optimizing for size. */
+/* #undef HAVE_SMALL */
+
+/* Define to 1 if stdbool.h conforms to C99. */
#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
+
+/* Define to 1 if `st_atimensec' is a member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_ATIMENSEC */
+
+/* Define to 1 if `st_atimespec.tv_nsec' is a member of `struct stat'. */
#define HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC 1
+
+/* Define to 1 if `st_atim.st__tim.tv_nsec' is a member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC */
+
+/* Define to 1 if `st_atim.tv_nsec' is a member of `struct stat'. */
#define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1
+
+/* Define to 1 if `st_uatime' is a member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_UATIME */
+
+/* Define to 1 if you have the <sys/byteorder.h> header file. */
+/* #undef HAVE_SYS_BYTEORDER_H */
+
+/* Define to 1 if you have the <sys/endian.h> header file. */
#define HAVE_SYS_ENDIAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if the system has the type `uintptr_t'. */
#define HAVE_UINTPTR_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+/* #undef HAVE_UTIME */
+
+/* Define to 1 if you have the `utimes' function. */
+/* #undef HAVE_UTIMES */
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
#define HAVE_VISIBILITY 1
+
+/* Define to 1 if you have the `wcwidth' function. */
#define HAVE_WCWIDTH 1
+
+/* Define to 1 if the system has the type `_Bool'. */
#define HAVE__BOOL 1
+
+/* Define to 1 if _mm_movemask_epi8 is available. */
#if defined(__FreeBSD__) && defined(__amd64__)
#define HAVE__MM_MOVEMASK_EPI8 1
#endif
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 when using POSIX threads (pthreads). */
#define MYTHREAD_POSIX 1
+
+/* Define to 1 when using Windows Vista compatible threads. This uses features
+ that are not available on Windows XP. */
+/* #undef MYTHREAD_VISTA */
+
+/* Define to 1 when using Windows 95 (and thus XP) compatible threads. This
+ avoids use of features that were added in Windows Vista. */
+/* #undef MYTHREAD_WIN95 */
+
+/* Define to 1 to disable debugging code. */
#define NDEBUG 1
+
+/* Name of package */
#define PACKAGE "xz"
+
+/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "lasse.collin@tukaani.org"
+
+/* Define to the full name of this package. */
#define PACKAGE_NAME "XZ Utils"
-#define PACKAGE_STRING "XZ Utils 5.2.0"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "XZ Utils 5.2.1"
+
+/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "xz"
+
+/* Define to the home page for this package. */
#define PACKAGE_URL "http://tukaani.org/xz/"
-#define PACKAGE_VERSION "5.2.0"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "5.2.1"
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 8
+
+/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
-#define TUKLIB_CPUCORES_SYSCTL 1
+
+/* Define to 1 if the number of available CPU cores can be detected with
+ cpuset(2). */
+#define TUKLIB_CPUCORES_CPUSET 1
+
+/* Define to 1 if the number of available CPU cores can be detected with
+ pstat_getdynamic(). */
+/* #undef TUKLIB_CPUCORES_PSTAT_GETDYNAMIC */
+
+/* Define to 1 if the number of available CPU cores can be detected with
+ sysconf(_SC_NPROCESSORS_ONLN) or sysconf(_SC_NPROC_ONLN). */
+/* #undef TUKLIB_CPUCORES_SYSCONF */
+
+/* Define to 1 if the number of available CPU cores can be detected with
+ sysctl(). */
+/* #undef TUKLIB_CPUCORES_SYSCTL */
+
+/* Define to 1 if the system supports fast unaligned access to 16-bit and
+ 32-bit integers. */
+/* FreeBSD - derive from __NO_STRICT_ALIGNMENT */
+/* #undef TUKLIB_FAST_UNALIGNED_ACCESS */
+
+/* Define to 1 if the amount of physical memory can be detected with
+ _system_configuration.physmem. */
+/* #undef TUKLIB_PHYSMEM_AIX */
+
+/* Define to 1 if the amount of physical memory can be detected with
+ getinvent_r(). */
+/* #undef TUKLIB_PHYSMEM_GETINVENT_R */
+
+/* Define to 1 if the amount of physical memory can be detected with
+ getsysinfo(). */
+/* #undef TUKLIB_PHYSMEM_GETSYSINFO */
+
+/* Define to 1 if the amount of physical memory can be detected with
+ pstat_getstatic(). */
+/* #undef TUKLIB_PHYSMEM_PSTAT_GETSTATIC */
+
+/* Define to 1 if the amount of physical memory can be detected with
+ sysconf(_SC_PAGESIZE) and sysconf(_SC_PHYS_PAGES). */
+#define TUKLIB_PHYSMEM_SYSCONF 1
+
+/* Define to 1 if the amount of physical memory can be detected with sysctl().
+ */
+/* #undef TUKLIB_PHYSMEM_SYSCTL */
+
+/* Define to 1 if the amount of physical memory can be detected with Linux
+ sysinfo(). */
+/* #undef TUKLIB_PHYSMEM_SYSINFO */
+
+/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
+/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
+/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
+/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
+/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
+
+
+/* Version number of package */
+#define VERSION "5.2.1"
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined(__FreeBSD__)
#include <sys/_types.h>
#if defined(__NO_STRICT_ALIGNMENT)
@@ -100,5 +432,71 @@
# define WORDS_BIGENDIAN 1
#endif
#endif
-#define TUKLIB_PHYSMEM_SYSCONF 1
-#define VERSION "5.2.0"
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to rpl_ if the getopt replacement functions and variables should be
+ used. */
+/* #undef __GETOPT_PREFIX */
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef int32_t */
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef int64_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint16_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint64_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+ pointer, if such a type exists, and if the system does not define it. */
+/* #undef uintptr_t */
diff --git a/lib/libmandoc/Makefile b/lib/libmandoc/Makefile
index 276c463..6529ea4 100644
--- a/lib/libmandoc/Makefile
+++ b/lib/libmandoc/Makefile
@@ -28,11 +28,9 @@ LIBROFF_SRCS= eqn.c \
tbl_layout.c \
tbl_opts.c
-COMPAT_SRCS= compat_reallocarray.c
SRCS= ${LIBMAN_SRCS} \
${LIBMDOC_SRCS} \
${LIBROFF_SRCS} \
- ${COMPAT_SRCS} \
chars.c \
mandoc.c \
mandoc_aux.c \
diff --git a/lib/libmd/mdXhl.c b/lib/libmd/mdXhl.c
index e69e5e5..2954548 100644
--- a/lib/libmd/mdXhl.c
+++ b/lib/libmd/mdXhl.c
@@ -74,7 +74,7 @@ MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len)
i = read(f, buffer, sizeof(buffer));
else
i = read(f, buffer, n);
- if (i < 0)
+ if (i <= 0)
break;
MDXUpdate(&ctx, buffer, i);
n -= i;
diff --git a/lib/libmt/Makefile b/lib/libmt/Makefile
index fe54d2f..6fe5920 100644
--- a/lib/libmt/Makefile
+++ b/lib/libmt/Makefile
@@ -5,8 +5,7 @@ SHLIBDIR?= /lib
SRCS= mtlib.c
INCS= mtlib.h
-DPADD= ${LIBSBUF}
-LDADD= -lsbuf
+LIBADD= sbuf bsdxml
MAN= mt.3
diff --git a/lib/libmt/mt.3 b/lib/libmt/mt.3
index da63aa9..eaf0194 100644
--- a/lib/libmt/mt.3
+++ b/lib/libmt/mt.3
@@ -35,7 +35,6 @@
.Dt MT 3
.Os
.Sh NAME
-.Nm
.Nm mt_start_element ,
.Nm mt_end_element ,
.Nm mt_char_handler ,
diff --git a/lib/libnv/Makefile b/lib/libnv/Makefile
index f7853b0..8b2fc78 100644
--- a/lib/libnv/Makefile
+++ b/lib/libnv/Makefile
@@ -22,147 +22,66 @@ MAN+= nv.3
MLINKS+=nv.3 libnv.3 \
nv.3 nvlist.3
-MLINKS+=nv.3 nvlist_create.3 \
- nv.3 nvlist_destroy.3 \
- nv.3 nvlist_error.3 \
- nv.3 nvlist_set_error.3 \
- nv.3 nvlist_empty.3 \
+MLINKS+=nv.3 nvlist_add_binary.3 \
+ nv.3 nvlist_add_bool.3 \
+ nv.3 nvlist_add_descriptor.3 \
+ nv.3 nvlist_add_null.3 \
+ nv.3 nvlist_add_number.3 \
+ nv.3 nvlist_add_nvlist.3 \
+ nv.3 nvlist_add_string.3 \
+ nv.3 nvlist_add_stringf.3 \
+ nv.3 nvlist_add_stringv.3 \
nv.3 nvlist_clone.3 \
+ nv.3 nvlist_create.3 \
+ nv.3 nvlist_destroy.3 \
nv.3 nvlist_dump.3 \
- nv.3 nvlist_fdump.3 \
- nv.3 nvlist_size.3 \
- nv.3 nvlist_pack.3 \
- nv.3 nvlist_unpack.3 \
- nv.3 nvlist_send.3 \
- nv.3 nvlist_recv.3 \
- nv.3 nvlist_xfer.3 \
- nv.3 nvlist_next.3 \
+ nv.3 nvlist_empty.3 \
+ nv.3 nvlist_error.3 \
nv.3 nvlist_exists.3 \
- nv.3 nvlist_exists_type.3 \
- nv.3 nvlist_exists_null.3 \
+ nv.3 nvlist_exists_binary.3 \
nv.3 nvlist_exists_bool.3 \
+ nv.3 nvlist_exists_descriptor.3 \
+ nv.3 nvlist_exists_null.3 \
nv.3 nvlist_exists_number.3 \
- nv.3 nvlist_exists_string.3 \
nv.3 nvlist_exists_nvlist.3 \
- nv.3 nvlist_exists_descriptor.3 \
- nv.3 nvlist_exists_binary.3 \
- nv.3 nvlist_add_null.3 \
- nv.3 nvlist_add_bool.3 \
- nv.3 nvlist_add_number.3 \
- nv.3 nvlist_add_string.3 \
- nv.3 nvlist_add_stringf.3 \
- nv.3 nvlist_add_stringv.3 \
- nv.3 nvlist_add_nvlist.3 \
- nv.3 nvlist_add_descriptor.3 \
- nv.3 nvlist_add_binary.3 \
- nv.3 nvlist_move_string.3 \
- nv.3 nvlist_move_nvlist.3 \
- nv.3 nvlist_move_descriptor.3 \
- nv.3 nvlist_move_binary.3 \
+ nv.3 nvlist_exists_string.3 \
+ nv.3 nvlist_exists_type.3 \
+ nv.3 nvlist_fdump.3 \
+ nv.3 nvlist_flags.3 \
+ nv.3 nvlist_free.3 \
+ nv.3 nvlist_free_binary.3 \
+ nv.3 nvlist_free_bool.3 \
+ nv.3 nvlist_free_descriptor.3 \
+ nv.3 nvlist_free_null.3 \
+ nv.3 nvlist_free_number.3 \
+ nv.3 nvlist_free_nvlist.3 \
+ nv.3 nvlist_free_string.3 \
+ nv.3 nvlist_free_type.3 \
+ nv.3 nvlist_get_binary.3 \
nv.3 nvlist_get_bool.3 \
+ nv.3 nvlist_get_descriptor.3 \
nv.3 nvlist_get_number.3 \
- nv.3 nvlist_get_string.3 \
nv.3 nvlist_get_nvlist.3 \
- nv.3 nvlist_get_descriptor.3 \
- nv.3 nvlist_get_binary.3 \
nv.3 nvlist_get_parent.3 \
+ nv.3 nvlist_get_string.3 \
+ nv.3 nvlist_move_binary.3 \
+ nv.3 nvlist_move_descriptor.3 \
+ nv.3 nvlist_move_nvlist.3 \
+ nv.3 nvlist_move_string.3 \
+ nv.3 nvlist_next.3 \
+ nv.3 nvlist_pack.3 \
+ nv.3 nvlist_recv.3 \
+ nv.3 nvlist_send.3 \
+ nv.3 nvlist_set_error.3 \
+ nv.3 nvlist_size.3 \
+ nv.3 nvlist_take_binary.3 \
nv.3 nvlist_take_bool.3 \
+ nv.3 nvlist_take_descriptor.3 \
nv.3 nvlist_take_number.3 \
- nv.3 nvlist_take_string.3 \
nv.3 nvlist_take_nvlist.3 \
- nv.3 nvlist_take_descriptor.3 \
- nv.3 nvlist_take_binary.3 \
- nv.3 nvlist_free.3 \
- nv.3 nvlist_free_type.3 \
- nv.3 nvlist_free_null.3 \
- nv.3 nvlist_free_bool.3 \
- nv.3 nvlist_free_number.3 \
- nv.3 nvlist_free_string.3 \
- nv.3 nvlist_free_nvlist.3 \
- nv.3 nvlist_free_descriptor.3 \
- nv.3 nvlist_free_binary.3
-MLINKS+=nv.3 nvlist_existsf.3 \
- nv.3 nvlist_existsf_type.3 \
- nv.3 nvlist_existsf_null.3 \
- nv.3 nvlist_existsf_bool.3 \
- nv.3 nvlist_existsf_number.3 \
- nv.3 nvlist_existsf_string.3 \
- nv.3 nvlist_existsf_nvlist.3 \
- nv.3 nvlist_existsf_descriptor.3 \
- nv.3 nvlist_existsf_binary.3 \
- nv.3 nvlist_addf_null.3 \
- nv.3 nvlist_addf_bool.3 \
- nv.3 nvlist_addf_number.3 \
- nv.3 nvlist_addf_string.3 \
- nv.3 nvlist_addf_nvlist.3 \
- nv.3 nvlist_addf_descriptor.3 \
- nv.3 nvlist_addf_binary.3 \
- nv.3 nvlist_movef_string.3 \
- nv.3 nvlist_movef_nvlist.3 \
- nv.3 nvlist_movef_descriptor.3 \
- nv.3 nvlist_movef_binary.3 \
- nv.3 nvlist_getf_bool.3 \
- nv.3 nvlist_getf_number.3 \
- nv.3 nvlist_getf_string.3 \
- nv.3 nvlist_getf_nvlist.3 \
- nv.3 nvlist_getf_descriptor.3 \
- nv.3 nvlist_getf_binary.3 \
- nv.3 nvlist_takef_bool.3 \
- nv.3 nvlist_takef_number.3 \
- nv.3 nvlist_takef_string.3 \
- nv.3 nvlist_takef_nvlist.3 \
- nv.3 nvlist_takef_descriptor.3 \
- nv.3 nvlist_takef_binary.3 \
- nv.3 nvlist_freef.3 \
- nv.3 nvlist_freef_type.3 \
- nv.3 nvlist_freef_null.3 \
- nv.3 nvlist_freef_bool.3 \
- nv.3 nvlist_freef_number.3 \
- nv.3 nvlist_freef_string.3 \
- nv.3 nvlist_freef_nvlist.3 \
- nv.3 nvlist_freef_descriptor.3 \
- nv.3 nvlist_freef_binary.3
-MLINKS+=nv.3 nvlist_existsv.3 \
- nv.3 nvlist_existsv_type.3 \
- nv.3 nvlist_existsv_null.3 \
- nv.3 nvlist_existsv_bool.3 \
- nv.3 nvlist_existsv_number.3 \
- nv.3 nvlist_existsv_string.3 \
- nv.3 nvlist_existsv_nvlist.3 \
- nv.3 nvlist_existsv_descriptor.3 \
- nv.3 nvlist_existsv_binary.3 \
- nv.3 nvlist_addv_null.3 \
- nv.3 nvlist_addv_bool.3 \
- nv.3 nvlist_addv_number.3 \
- nv.3 nvlist_addv_string.3 \
- nv.3 nvlist_addv_nvlist.3 \
- nv.3 nvlist_addv_descriptor.3 \
- nv.3 nvlist_addv_binary.3 \
- nv.3 nvlist_movev_string.3 \
- nv.3 nvlist_movev_nvlist.3 \
- nv.3 nvlist_movev_descriptor.3 \
- nv.3 nvlist_movev_binary.3 \
- nv.3 nvlist_getv_bool.3 \
- nv.3 nvlist_getv_number.3 \
- nv.3 nvlist_getv_string.3 \
- nv.3 nvlist_getv_nvlist.3 \
- nv.3 nvlist_getv_descriptor.3 \
- nv.3 nvlist_getv_binary.3 \
- nv.3 nvlist_takev_bool.3 \
- nv.3 nvlist_takev_number.3 \
- nv.3 nvlist_takev_string.3 \
- nv.3 nvlist_takev_nvlist.3 \
- nv.3 nvlist_takev_descriptor.3 \
- nv.3 nvlist_takev_binary.3 \
- nv.3 nvlist_freev.3 \
- nv.3 nvlist_freev_type.3 \
- nv.3 nvlist_freev_null.3 \
- nv.3 nvlist_freev_bool.3 \
- nv.3 nvlist_freev_number.3 \
- nv.3 nvlist_freev_string.3 \
- nv.3 nvlist_freev_nvlist.3 \
- nv.3 nvlist_freev_descriptor.3 \
- nv.3 nvlist_freev_binary.3
+ nv.3 nvlist_take_string.3 \
+ nv.3 nvlist_unpack.3 \
+ nv.3 nvlist_xfer.3
WARNS?= 6
diff --git a/lib/libnv/nv.3 b/lib/libnv/nv.3
index be6e0fe..58033be 100644
--- a/lib/libnv/nv.3
+++ b/lib/libnv/nv.3
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 30, 2015
+.Dd May 2, 2015
.Dt NV 3
.Os
.Sh NAME
@@ -37,6 +37,7 @@
.Nm nvlist_error ,
.Nm nvlist_set_error ,
.Nm nvlist_empty ,
+.Nm nvlist_flags ,
.Nm nvlist_exists ,
.Nm nvlist_free ,
.Nm nvlist_clone ,
@@ -68,6 +69,8 @@
.Fn nvlist_set_error "nvlist_t *nvl, int error"
.Ft bool
.Fn nvlist_empty "const nvlist_t *nvl"
+.Ft int
+.Fn nvlist_flags "const nvlist_t *nvl"
.\"
.Ft "nvlist_t *"
.Fn nvlist_clone "const nvlist_t *nvl"
@@ -82,14 +85,14 @@
.Ft "void *"
.Fn nvlist_pack "const nvlist_t *nvl" "size_t *sizep"
.Ft "nvlist_t *"
-.Fn nvlist_unpack "const void *buf" "size_t size"
+.Fn nvlist_unpack "const void *buf" "size_t size" "int flags"
.\"
.Ft int
.Fn nvlist_send "int sock" "const nvlist_t *nvl"
.Ft "nvlist_t *"
-.Fn nvlist_recv "int sock"
+.Fn nvlist_recv "int sock" "int flags"
.Ft "nvlist_t *"
-.Fn nvlist_xfer "int sock" "nvlist_t *nvl"
+.Fn nvlist_xfer "int sock" "nvlist_t *nvl" "int flags"
.\"
.Ft "const char *"
.Fn nvlist_next "const nvlist_t *nvl" "int *typep" "void **cookiep"
@@ -229,6 +232,8 @@ The following flag can be provided:
.Bl -tag -width "NV_FLAG_IGNORE_CASE" -compact -offset indent
.It Dv NV_FLAG_IGNORE_CASE
Perform case-insensitive lookups of provided names.
+.It Dv NV_FLAG_NO_UNIQUE
+Names in the nvlist do not have to be unique.
.El
.Pp
The
@@ -269,6 +274,12 @@ otherwise.
The nvlist must not be in error state.
.Pp
The
+.Fn nvlist_flags
+function returns flags used to create the nvlist with the
+.Fn nvlist_create
+function.
+.Pp
+The
.Fn nvlist_clone
functions clones the given nvlist.
The clone shares no resources with its origin.
@@ -316,6 +327,18 @@ The nvlist must not be in error state.
The
.Fn nvlist_unpack
function converts the given buffer to the nvlist.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_unpack ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
The function returns
.Dv NULL
in case of an error.
@@ -334,12 +357,36 @@ The
function receives nvlist over the socket given by the
.Fa sock
argument.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_recv ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
.Pp
The
.Fn nvlist_xfer
function sends the given nvlist over the socket given by the
.Fa sock
argument and receives nvlist over the same socket.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_xfer ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
The given nvlist is always destroyed.
.Pp
The
@@ -550,7 +597,7 @@ const char *command;
char *filename;
int fd;
-nvl = nvlist_recv(sock);
+nvl = nvlist_recv(sock, 0);
if (nvl == NULL)
err(1, "nvlist_recv() failed");
@@ -579,7 +626,7 @@ const char *name;
void *cookie;
int type;
-nvl = nvlist_recv(sock);
+nvl = nvlist_recv(sock, 0);
if (nvl == NULL)
err(1, "nvlist_recv() failed");
@@ -608,7 +655,7 @@ const char *name;
void *cookie;
int type;
-nvl = nvlist_recv(sock);
+nvl = nvlist_recv(sock, 0);
if (nvl == NULL)
err(1, "nvlist_recv() failed");
diff --git a/lib/libnv/tests/dnv_tests.cc b/lib/libnv/tests/dnv_tests.cc
index ad26f38..2f92d9d 100644
--- a/lib/libnv/tests/dnv_tests.cc
+++ b/lib/libnv/tests/dnv_tests.cc
@@ -45,7 +45,7 @@ ATF_TEST_CASE_BODY(dnvlist_get_bool__present)
nvlist_add_bool(nvl, key, value);
ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, key, false), value);
- ATF_REQUIRE_EQ(dnvlist_getf_bool(nvl, false, "%c%s", 'n', "ame"), value);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "name", false), value);
nvlist_destroy(nvl);
}
@@ -60,12 +60,12 @@ ATF_TEST_CASE_BODY(dnvlist_get_bool__default_value)
nvl = nvlist_create(0);
ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, key, false), false);
- ATF_REQUIRE_EQ(dnvlist_getf_bool(nvl, true, "%d", 123), true);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "123", true), true);
nvlist_add_bool(nvl, key, true);
ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "otherkey", true), true);
- ATF_REQUIRE_EQ(dnvlist_getf_bool(nvl, false, "%d%c", 12, 'c'), false);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "12c", false), false);
nvlist_destroy(nvl);
}
@@ -84,7 +84,7 @@ ATF_TEST_CASE_BODY(dnvlist_get_number__present)
nvlist_add_number(nvl, key, value);
ATF_REQUIRE_EQ(dnvlist_get_number(nvl, key, 19), value);
- ATF_REQUIRE_EQ(dnvlist_getf_number(nvl, 65, "key"), value);
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "key", 65), value);
nvlist_destroy(nvl);
}
@@ -99,12 +99,11 @@ ATF_TEST_CASE_BODY(dnvlist_get_number__default_value)
nvl = nvlist_create(0);
ATF_REQUIRE_EQ(dnvlist_get_number(nvl, key, 5), 5);
- ATF_REQUIRE_EQ(dnvlist_getf_number(nvl, 12, "%s", key), 12);
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "1234", 5), 5);
nvlist_add_number(nvl, key, 24841);
- ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "hthth", 184), 184);
- ATF_REQUIRE_EQ(dnvlist_getf_number(nvl, 5641, "%d", 1234), 5641);
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "1234", 5641), 5641);
nvlist_destroy(nvl);
}
@@ -124,7 +123,7 @@ ATF_TEST_CASE_BODY(dnvlist_get_string__present)
ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, key, "g"), value), 0);
- actual_value = dnvlist_getf_string(nvl, "rs", "%s", key);
+ actual_value = dnvlist_get_string(nvl, key, "rs");
ATF_REQUIRE_EQ(strcmp(actual_value, value), 0);
nvlist_destroy(nvl);
@@ -142,13 +141,13 @@ ATF_TEST_CASE_BODY(dnvlist_get_string__default_value)
ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, key, "bar"), "bar"), 0);
- actual_value = dnvlist_getf_string(nvl, "d", "%s", key);
+ actual_value = dnvlist_get_string(nvl, key, "d");
ATF_REQUIRE_EQ(strcmp(actual_value, "d"), 0);
nvlist_add_string(nvl, key, "cxhweh");
ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, "hthth", "fd"), "fd"), 0);
- actual_value = dnvlist_getf_string(nvl, "5", "%s", "5");
+ actual_value = dnvlist_get_string(nvl, "5", "5");
ATF_REQUIRE_EQ(strcmp("5", "5"), 0);
nvlist_destroy(nvl);
@@ -172,10 +171,6 @@ ATF_TEST_CASE_BODY(dnvlist_get_nvlist__present)
ATF_REQUIRE(actual_value != NULL);
ATF_REQUIRE(nvlist_empty(actual_value));
- actual_value = dnvlist_getf_nvlist(nvl, NULL, "%s", key);
- ATF_REQUIRE(actual_value != NULL);
- ATF_REQUIRE(nvlist_empty(actual_value));
-
nvlist_destroy(nvl);
}
@@ -191,11 +186,10 @@ ATF_TEST_CASE_BODY(dnvlist_get_nvlist__default_value)
dummy = nvlist_create(0);
ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, key, dummy), dummy);
- ATF_REQUIRE_EQ(dnvlist_getf_nvlist(nvl, dummy, "%s", key), dummy);
nvlist_move_nvlist(nvl, key, nvlist_create(0));
ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, "456", dummy), dummy);
- ATF_REQUIRE_EQ(dnvlist_getf_nvlist(nvl, dummy, "%s", "gh"), dummy);
+ ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, "gh", dummy), dummy);
nvlist_destroy(nvl);
}
@@ -226,10 +220,6 @@ ATF_TEST_CASE_BODY(dnvlist_get_binary__present)
ATF_REQUIRE_EQ(value_size, actual_size);
ATF_REQUIRE_EQ(memcmp(actual_value, value, actual_size), 0);
- actual_value = dnvlist_getf_binary(nvl, &actual_size, "g", 1, "%s", k);
- ATF_REQUIRE_EQ(value_size, actual_size);
- ATF_REQUIRE_EQ(memcmp(actual_value, value, actual_size), 0);
-
nvlist_destroy(nvl);
}
@@ -251,8 +241,8 @@ ATF_TEST_CASE_BODY(dnvlist_get_binary__default_value)
ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
set_const_binary_value(default_value, default_size, "atf");
- actual_value = dnvlist_getf_binary(nvl, &actual_size, default_value,
- default_size, "%s", key);
+ actual_value = dnvlist_get_binary(nvl, key, &actual_size, default_value,
+ default_size);
ATF_REQUIRE_EQ(default_size, actual_size);
ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
@@ -266,8 +256,8 @@ ATF_TEST_CASE_BODY(dnvlist_get_binary__default_value)
set_const_binary_value(default_value, default_size,
"rrhgrythtyrtgbrhgrtdsvdfbtjlkul");
- actual_value = dnvlist_getf_binary(nvl, &actual_size, default_value,
- default_size, "s");
+ actual_value = dnvlist_get_binary(nvl, "s", &actual_size, default_value,
+ default_size);
ATF_REQUIRE_EQ(default_size, actual_size);
ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
diff --git a/lib/libnv/tests/nv_tests.cc b/lib/libnv/tests/nv_tests.cc
index bfdc972..d779190 100644
--- a/lib/libnv/tests/nv_tests.cc
+++ b/lib/libnv/tests/nv_tests.cc
@@ -77,9 +77,8 @@ ATF_TEST_CASE_BODY(nvlist_add_null__single_insert)
ATF_REQUIRE(!nvlist_empty(nvl));
ATF_REQUIRE(nvlist_exists(nvl, key));
- ATF_REQUIRE(nvlist_existsf(nvl, "%s", key));
ATF_REQUIRE(nvlist_exists_null(nvl, key));
- ATF_REQUIRE(nvlist_existsf_null(nvl, "key"));
+ ATF_REQUIRE(nvlist_exists_null(nvl, "key"));
/* Iterate over the nvlist; ensure that it has only our one key. */
it = NULL;
@@ -108,11 +107,10 @@ ATF_TEST_CASE_BODY(nvlist_add_bool__single_insert)
ATF_REQUIRE(!nvlist_empty(nvl));
ATF_REQUIRE(nvlist_exists(nvl, key));
- ATF_REQUIRE(nvlist_existsf(nvl, "%s%s", "na", "me"));
+ ATF_REQUIRE(nvlist_exists(nvl, "name"));
ATF_REQUIRE(nvlist_exists_bool(nvl, key));
- ATF_REQUIRE(nvlist_existsf_bool(nvl, "%s%c", "nam", 'e'));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, "name"));
ATF_REQUIRE_EQ(nvlist_get_bool(nvl, key), true);
- ATF_REQUIRE_EQ(nvlist_getf_bool(nvl, "%c%s", 'n', "ame"), true);
/* Iterate over the nvlist; ensure that it has only our one key. */
it = NULL;
@@ -143,11 +141,9 @@ ATF_TEST_CASE_BODY(nvlist_add_number__single_insert)
ATF_REQUIRE(!nvlist_empty(nvl));
ATF_REQUIRE(nvlist_exists(nvl, key));
- ATF_REQUIRE(nvlist_existsf(nvl, "%s%d", "foo", 123));
+ ATF_REQUIRE(nvlist_exists(nvl, "foo123"));
ATF_REQUIRE(nvlist_exists_number(nvl, key));
- ATF_REQUIRE(nvlist_existsf_number(nvl, "%s", key));
ATF_REQUIRE_EQ(nvlist_get_number(nvl, key), value);
- ATF_REQUIRE_EQ(nvlist_getf_number(nvl, "%s", key), value);
/* Iterate over the nvlist; ensure that it has only our one key. */
it = NULL;
@@ -178,11 +174,10 @@ ATF_TEST_CASE_BODY(nvlist_add_string__single_insert)
ATF_REQUIRE(!nvlist_empty(nvl));
ATF_REQUIRE(nvlist_exists(nvl, key));
- ATF_REQUIRE(nvlist_existsf(nvl, "%s", key));
+ ATF_REQUIRE(nvlist_exists(nvl, "test"));
ATF_REQUIRE(nvlist_exists_string(nvl, key));
- ATF_REQUIRE(nvlist_existsf_string(nvl, "%s", key));
+ ATF_REQUIRE(nvlist_exists_string(nvl, "test"));
ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, key), value), 0);
- ATF_REQUIRE_EQ(strcmp(nvlist_getf_string(nvl, "%s", key), value), 0);
/* nvlist_add_* is required to clone the value, so check for that. */
ATF_REQUIRE(nvlist_get_string(nvl, key) != value);
@@ -219,9 +214,9 @@ ATF_TEST_CASE_BODY(nvlist_add_nvlist__single_insert)
ATF_REQUIRE(!nvlist_empty(nvl));
ATF_REQUIRE(nvlist_exists(nvl, key));
- ATF_REQUIRE(nvlist_existsf(nvl, "%s", key));
+ ATF_REQUIRE(nvlist_exists(nvl, "test"));
ATF_REQUIRE(nvlist_exists_nvlist(nvl, key));
- ATF_REQUIRE(nvlist_existsf_nvlist(nvl, "%s", key));
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, "test"));
value = nvlist_get_nvlist(nvl, key);
ATF_REQUIRE(nvlist_exists_null(value, subkey));
@@ -229,10 +224,6 @@ ATF_TEST_CASE_BODY(nvlist_add_nvlist__single_insert)
/* nvlist_add_* is required to clone the value, so check for that. */
ATF_REQUIRE(sublist != value);
- value = nvlist_getf_nvlist(nvl, "%s", key);
- ATF_REQUIRE(nvlist_exists_null(value, subkey));
- ATF_REQUIRE(sublist != value);
-
/* Iterate over the nvlist; ensure that it has only our one key. */
it = NULL;
ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
@@ -283,9 +274,9 @@ ATF_TEST_CASE_BODY(nvlist_add_binary__single_insert)
ATF_REQUIRE(!nvlist_empty(nvl));
ATF_REQUIRE(nvlist_exists(nvl, key));
- ATF_REQUIRE(nvlist_existsf(nvl, "%s", key));
+ ATF_REQUIRE(nvlist_exists(nvl, "binary"));
ATF_REQUIRE(nvlist_exists_binary(nvl, key));
- ATF_REQUIRE(nvlist_existsf_binary(nvl, "%s", key));
+ ATF_REQUIRE(nvlist_exists_binary(nvl, "binary"));
ret_value = nvlist_get_binary(nvl, key, &ret_size);
ATF_REQUIRE_EQ(value_size, ret_size);
@@ -294,11 +285,6 @@ ATF_TEST_CASE_BODY(nvlist_add_binary__single_insert)
/* nvlist_add_* is required to clone the value, so check for that. */
ATF_REQUIRE(value != ret_value);
- ret_value = nvlist_getf_binary(nvl, &ret_size, "%s", key);
- ATF_REQUIRE_EQ(value_size, ret_size);
- ATF_REQUIRE_EQ(memcmp(value, ret_value, ret_size), 0);
- ATF_REQUIRE(value != ret_value);
-
/* Iterate over the nvlist; ensure that it has only our one key. */
it = NULL;
ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
@@ -454,7 +440,7 @@ ATF_TEST_CASE_BODY(nvlist_pack__empty_nvlist)
packed = nvlist_pack(nvl, &packed_size);
ATF_REQUIRE(packed != NULL);
- unpacked = nvlist_unpack(packed, packed_size);
+ unpacked = nvlist_unpack(packed, packed_size, 0);
ATF_REQUIRE(unpacked != NULL);
ATF_REQUIRE(unpacked != nvl);
ATF_REQUIRE(nvlist_empty(unpacked));
@@ -464,6 +450,40 @@ ATF_TEST_CASE_BODY(nvlist_pack__empty_nvlist)
free(packed);
}
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_unpack__flags_nvlist);
+ATF_TEST_CASE_BODY(nvlist_unpack__flags_nvlist)
+{
+ nvlist_t *nvl, *unpacked;
+ void *packed;
+ size_t packed_size;
+
+ nvl = nvlist_create(NV_FLAG_NO_UNIQUE);
+ ATF_REQUIRE(nvl != NULL);
+
+ nvlist_add_bool(nvl, "name", true);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, "name"));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked == NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, NV_FLAG_IGNORE_CASE);
+ ATF_REQUIRE(unpacked == NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, NV_FLAG_NO_UNIQUE);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE(unpacked != nvl);
+ ATF_REQUIRE(!nvlist_empty(unpacked));
+ ATF_REQUIRE(nvlist_exists_bool(unpacked, "name"));
+
+ nvlist_destroy(unpacked);
+ nvlist_destroy(nvl);
+ free(packed);
+}
+
static void
verify_null(const nvlist_t *nvl, int type)
{
@@ -548,7 +568,7 @@ ATF_TEST_CASE_BODY(nvlist_pack__multiple_values)
packed = nvlist_pack(nvl, &packed_size);
ATF_REQUIRE(packed != NULL);
- unpacked = nvlist_unpack(packed, packed_size);
+ unpacked = nvlist_unpack(packed, packed_size, 0);
ATF_REQUIRE(unpacked != 0);
it = NULL;
@@ -628,7 +648,7 @@ ATF_TEST_CASE_BODY(nvlist_unpack__duplicate_key)
ATF_REQUIRE(keypos != NULL);
memcpy(keypos, key2, keylen);
- unpacked = nvlist_unpack(packed, size);
+ unpacked = nvlist_unpack(packed, size, 0);
ATF_REQUIRE(nvlist_error(unpacked) != 0);
free(packed);
@@ -1220,6 +1240,7 @@ ATF_INIT_TEST_CASES(tp)
ATF_ADD_TEST_CASE(tp, nvlist_pack__multiple_values);
ATF_ADD_TEST_CASE(tp, nvlist_pack__error_nvlist);
ATF_ADD_TEST_CASE(tp, nvlist_unpack__duplicate_key);
+ ATF_ADD_TEST_CASE(tp, nvlist_unpack__flags_nvlist);
ATF_ADD_TEST_CASE(tp, nvlist_move_string__single_insert);
ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__single_insert);
diff --git a/lib/libnv/tests/nvlist_send_recv_test.c b/lib/libnv/tests/nvlist_send_recv_test.c
index 1b083c3..50222fb 100644
--- a/lib/libnv/tests/nvlist_send_recv_test.c
+++ b/lib/libnv/tests/nvlist_send_recv_test.c
@@ -95,7 +95,7 @@ parent(int sock)
int type, ctype;
size_t size;
- nvl = nvlist_recv(sock);
+ nvl = nvlist_recv(sock, 0);
CHECK(nvlist_error(nvl) == 0);
if (nvlist_error(nvl) != 0)
err(1, "nvlist_recv() failed");
diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c
index 17283d8..2ad2268 100644
--- a/lib/libpmc/libpmc.c
+++ b/lib/libpmc/libpmc.c
@@ -159,10 +159,12 @@ PMC_CLASSDEP_TABLE(p6, P6);
PMC_CLASSDEP_TABLE(xscale, XSCALE);
PMC_CLASSDEP_TABLE(armv7, ARMV7);
PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
+PMC_CLASSDEP_TABLE(mips74k, MIPS74K);
PMC_CLASSDEP_TABLE(octeon, OCTEON);
PMC_CLASSDEP_TABLE(ucf, UCF);
PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
PMC_CLASSDEP_TABLE(ppc970, PPC970);
+PMC_CLASSDEP_TABLE(e500, E500);
static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
@@ -293,9 +295,11 @@ PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
PMC_MDEP_TABLE(armv7, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
+PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K);
PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
-PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450);
-PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970);
+PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC);
PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
static const struct pmc_event_descr tsc_event_table[] =
@@ -360,11 +364,13 @@ PMC_CLASS_TABLE_DESC(armv7, ARMV7, armv7, armv7);
#endif
#if defined(__mips__)
PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
+PMC_CLASS_TABLE_DESC(mips74k, MIPS74K, mips74k, mips);
PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
#endif /* __mips__ */
#if defined(__powerpc__)
PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
+PMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc);
#endif
static struct pmc_class_descr soft_class_table_descr =
@@ -2432,6 +2438,13 @@ static struct pmc_event_alias mips24k_aliases[] = {
EV_ALIAS(NULL, NULL)
};
+static struct pmc_event_alias mips74k_aliases[] = {
+ EV_ALIAS("instructions", "INSTR_EXECUTED"),
+ EV_ALIAS("branches", "BRANCH_INSNS"),
+ EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCH_INSNS"),
+ EV_ALIAS(NULL, NULL)
+};
+
static struct pmc_event_alias octeon_aliases[] = {
EV_ALIAS("instructions", "RET"),
EV_ALIAS("branches", "BR"),
@@ -2484,6 +2497,12 @@ static struct pmc_event_alias ppc970_aliases[] = {
EV_ALIAS(NULL, NULL)
};
+static struct pmc_event_alias e500_aliases[] = {
+ EV_ALIAS("instructions", "INSTR_COMPLETED"),
+ EV_ALIAS("cycles", "CYCLES"),
+ EV_ALIAS(NULL, NULL)
+};
+
#define POWERPC_KW_OS "os"
#define POWERPC_KW_USR "usr"
#define POWERPC_KW_ANYTHREAD "anythread"
@@ -2923,6 +2942,10 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
ev = mips24k_event_table;
count = PMC_EVENT_TABLE_SIZE(mips24k);
break;
+ case PMC_CLASS_MIPS74K:
+ ev = mips74k_event_table;
+ count = PMC_EVENT_TABLE_SIZE(mips74k);
+ break;
case PMC_CLASS_OCTEON:
ev = octeon_event_table;
count = PMC_EVENT_TABLE_SIZE(octeon);
@@ -2935,6 +2958,10 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
ev = ppc970_event_table;
count = PMC_EVENT_TABLE_SIZE(ppc970);
break;
+ case PMC_CLASS_E500:
+ ev = e500_event_table;
+ count = PMC_EVENT_TABLE_SIZE(e500);
+ break;
case PMC_CLASS_SOFT:
ev = soft_event_table;
count = soft_event_info.pm_nevent;
@@ -3213,6 +3240,10 @@ pmc_init(void)
PMC_MDEP_INIT(mips24k);
pmc_class_table[n] = &mips24k_class_table_descr;
break;
+ case PMC_CPU_MIPS_74K:
+ PMC_MDEP_INIT(mips74k);
+ pmc_class_table[n] = &mips74k_class_table_descr;
+ break;
case PMC_CPU_MIPS_OCTEON:
PMC_MDEP_INIT(octeon);
pmc_class_table[n] = &octeon_class_table_descr;
@@ -3227,6 +3258,10 @@ pmc_init(void)
PMC_MDEP_INIT(ppc970);
pmc_class_table[n] = &ppc970_class_table_descr;
break;
+ case PMC_CPU_PPC_E500:
+ PMC_MDEP_INIT(e500);
+ pmc_class_table[n] = &e500_class_table_descr;
+ break;
#endif
default:
/*
@@ -3414,6 +3449,9 @@ _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
ev = mips24k_event_table;
evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
+ } else if (pe >= PMC_EV_MIPS74K_FIRST && pe <= PMC_EV_MIPS74K_LAST) {
+ ev = mips74k_event_table;
+ evfence = mips74k_event_table + PMC_EVENT_TABLE_SIZE(mips74k);
} else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) {
ev = octeon_event_table;
evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon);
@@ -3423,6 +3461,9 @@ _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
} else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) {
ev = ppc970_event_table;
evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970);
+ } else if (pe >= PMC_EV_E500_FIRST && pe <= PMC_EV_E500_LAST) {
+ ev = e500_event_table;
+ evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500);
} else if (pe == PMC_EV_TSC_TSC) {
ev = tsc_event_table;
evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
diff --git a/lib/libpmc/pmc.haswellxeon.3 b/lib/libpmc/pmc.haswellxeon.3
index 8eb5b7e..7519030 100644
--- a/lib/libpmc/pmc.haswellxeon.3
+++ b/lib/libpmc/pmc.haswellxeon.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd 21 November, 2014
+.Dd November 21, 2014
.Dt PMC.HASWELLXEON 3
.Os
.Sh NAME
diff --git a/lib/librt/Makefile b/lib/librt/Makefile
index 3629610..5696610 100644
--- a/lib/librt/Makefile
+++ b/lib/librt/Makefile
@@ -19,6 +19,8 @@ PRECIOUSLIB=
VERSION_MAP= ${.CURDIR}/Version.map
-.include <bsd.arch.inc.mk>
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
.include <bsd.lib.mk>
diff --git a/lib/librt/Makefile.amd64 b/lib/librt/Makefile.amd64
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/librt/Makefile.amd64
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/librt/Makefile.i386 b/lib/librt/Makefile.i386
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/librt/Makefile.i386
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c
index 868fbe5..fa2a92d 100644
--- a/lib/libsdp/search.c
+++ b/lib/libsdp/search.c
@@ -32,6 +32,7 @@
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <stdio.h>
diff --git a/lib/libsdp/service.c b/lib/libsdp/service.c
index 2667966..53c8909 100644
--- a/lib/libsdp/service.c
+++ b/lib/libsdp/service.c
@@ -32,6 +32,7 @@
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <string.h>
diff --git a/lib/libsdp/session.c b/lib/libsdp/session.c
index a31f327..a74ce5f 100644
--- a/lib/libsdp/session.c
+++ b/lib/libsdp/session.c
@@ -28,7 +28,7 @@
* $Id: session.c,v 1.2 2003/09/04 22:12:13 max Exp $
* $FreeBSD$
*/
-
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <stdlib.h>
@@ -62,6 +62,9 @@ sdp_open(bdaddr_t const *l, bdaddr_t const *r)
sa.l2cap_len = sizeof(sa);
sa.l2cap_family = AF_BLUETOOTH;
sa.l2cap_psm = 0;
+ sa.l2cap_cid = 0;
+ sa.l2cap_bdaddr_type = BDADDR_BREDR;
+
memcpy(&sa.l2cap_bdaddr, l, sizeof(sa.l2cap_bdaddr));
if (bind(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
ss->error = errno;
diff --git a/lib/libsdp/util.c b/lib/libsdp/util.c
index b996bd2..5ef4a1d 100644
--- a/lib/libsdp/util.c
+++ b/lib/libsdp/util.c
@@ -30,6 +30,7 @@
*/
#include <netinet/in.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <stdio.h>
#include <sdp.h>
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile
index a5a135f..2ee2921 100644
--- a/lib/libstand/Makefile
+++ b/lib/libstand/Makefile
@@ -11,6 +11,9 @@ MK_SSP= no
.include <src.opts.mk>
+LIBSTAND_SRC= ${.CURDIR}
+LIBC_SRC= ${LIBSTAND_SRC}/../libc
+
LIB= stand
NO_PIC=
INCS= stand.h
@@ -19,7 +22,7 @@ MAN= libstand.3
WARNS?= 0
CFLAGS+= -ffreestanding -Wformat
-CFLAGS+= -I${.CURDIR}
+CFLAGS+= -I${LIBSTAND_SRC}
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 -msoft-float
@@ -39,6 +42,9 @@ CFLAGS+= -msoft-float -D_STANDALONE -DNETIF_DEBUG
.if ${MACHINE_CPUARCH} == "arm"
CFLAGS+= -msoft-float -D_STANDALONE
.endif
+.if ${MACHINE_CPUARCH} == "aarch64"
+CFLAGS+= -D_STANDALONE -mgeneral-regs-only
+.endif
.if ${MACHINE_CPUARCH} == "mips"
CFLAGS+= -G0 -fno-pic -mno-abicalls
.endif
@@ -51,50 +57,54 @@ SRCS+= gzguts.h zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c g
# private (pruned) versions of libc string functions
SRCS+= strcasecmp.c
-.PATH: ${.CURDIR}/../libc/net
+.PATH: ${LIBC_SRC}/net
SRCS+= ntoh.c
# string functions from libc
-.PATH: ${.CURDIR}/../libc/string
+.PATH: ${LIBC_SRC}/string
SRCS+= bcmp.c bcopy.c bzero.c ffs.c memccpy.c memchr.c memcmp.c memcpy.c \
memmove.c memset.c qdivrem.c strcat.c strchr.c strcmp.c strcpy.c \
strcspn.c strlen.c strncat.c strncmp.c strncpy.c strpbrk.c \
strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c
.if ${MACHINE_CPUARCH} == "arm"
-.PATH: ${.CURDIR}/../libc/arm/gen
+.PATH: ${LIBC_SRC}/arm/gen
# Compiler support functions
-.PATH: ${.CURDIR}/../../contrib/compiler-rt/lib/builtins/
+.PATH: ${LIBSTAND_SRC}/../../contrib/compiler-rt/lib/builtins/
# __clzsi2 and ctzsi2 for various builtin functions
SRCS+= clzsi2.c ctzsi2.c
# Divide and modulus functions called by the compiler
SRCS+= divmoddi4.c divmodsi4.c divdi3.c divsi3.c moddi3.c modsi3.c
SRCS+= udivmoddi4.c udivmodsi4.c udivdi3.c udivsi3.c umoddi3.c umodsi3.c
-.PATH: ${.CURDIR}/../../contrib/compiler-rt/lib/builtins/arm/
+.PATH: ${LIBSTAND_SRC}/../../contrib/compiler-rt/lib/builtins/arm/
SRCS+= aeabi_idivmod.S aeabi_ldivmod.S aeabi_uidivmod.S aeabi_uldivmod.S
SRCS+= aeabi_memcmp.S aeabi_memcpy.S aeabi_memmove.S aeabi_memset.S
+.endif
+.if ${MACHINE_CPUARCH} == "aarch64"
+.PATH: ${LIBC_SRC}/aarch64/gen
.endif
+
.if ${MACHINE_CPUARCH} == "powerpc"
-.PATH: ${.CURDIR}/../libc/quad
+.PATH: ${LIBC_SRC}/quad
SRCS+= ashldi3.c ashrdi3.c
SRCS+= syncicache.c
.endif
# uuid functions from libc
-.PATH: ${.CURDIR}/../libc/uuid
+.PATH: ${LIBC_SRC}/uuid
SRCS+= uuid_equal.c uuid_is_nil.c
# _setjmp/_longjmp
-.PATH: ${.CURDIR}/${MACHINE_CPUARCH}
+.PATH: ${LIBSTAND_SRC}/${MACHINE_CPUARCH}
SRCS+= _setjmp.S
# decompression functionality from libbz2
# NOTE: to actually test this functionality after libbz2 upgrade compile
# loader(8) with LOADER_BZIP2_SUPPORT defined
-.PATH: ${.CURDIR}/../../contrib/bzip2
+.PATH: ${LIBSTAND_SRC}/../../contrib/bzip2
CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS
SRCS+= libstand_bzlib_private.h
@@ -103,7 +113,8 @@ SRCS+= _${file}
CLEANFILES+= _${file}
_${file}: ${file}
- sed "s|bzlib_private\.h|libstand_bzlib_private.h|" ${.ALLSRC} > ${.TARGET}
+ sed "s|bzlib_private\.h|libstand_bzlib_private.h|" \
+ ${.ALLSRC} > ${.TARGET}
.endfor
CLEANFILES+= libstand_bzlib_private.h
@@ -112,8 +123,8 @@ libstand_bzlib_private.h: bzlib_private.h
${.ALLSRC} > ${.TARGET}
# decompression functionality from libz
-.PATH: ${.CURDIR}/../libz
-CFLAGS+=-DHAVE_MEMCPY -I${.CURDIR}/../libz
+.PATH: ${LIBSTAND_SRC}/../libz
+CFLAGS+=-DHAVE_MEMCPY -I${LIBSTAND_SRC}/../libz
SRCS+= adler32.c crc32.c libstand_zutil.h libstand_gzguts.h
.for file in infback.c inffast.c inflate.c inftrees.c zutil.c
@@ -158,4 +169,3 @@ SRCS+= nandfs.c
.endif
.include <bsd.lib.mk>
-
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile
index 1acb17f..1717672 100644
--- a/lib/libthr/Makefile
+++ b/lib/libthr/Makefile
@@ -61,10 +61,8 @@ SYMLINKS+=lib${LIB}.so ${LIBDIR}/libpthread.so
SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a
.endif
-.if ${MK_SYSCALL_COMPAT} != "no"
-CFLAGS+=-DSYSCALL_COMPAT
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
.endif
-.include <bsd.arch.inc.mk>
-
.include <bsd.lib.mk>
diff --git a/lib/libthr/Makefile.amd64 b/lib/libthr/Makefile.amd64
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/libthr/Makefile.amd64
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/libthr/Makefile.i386 b/lib/libthr/Makefile.i386
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/libthr/Makefile.i386
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/libthr/tests/Makefile b/lib/libthr/tests/Makefile
index 50f07f0..11cf0e7 100644
--- a/lib/libthr/tests/Makefile
+++ b/lib/libthr/tests/Makefile
@@ -25,7 +25,9 @@ NETBSD_ATF_TESTS_C+= sigmask_test
NETBSD_ATF_TESTS_C+= sigsuspend_test
NETBSD_ATF_TESTS_C+= siglongjmp_test
NETBSD_ATF_TESTS_C+= sleep_test
+.if ${MACHINE} != "arm64" # ARM64TODO: Missing makecontext
NETBSD_ATF_TESTS_C+= swapcontext_test
+.endif
NETBSD_ATF_TESTS_SH= atexit_test
NETBSD_ATF_TESTS_SH+= cancel_test
diff --git a/lib/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c
index dc5b0c7..f200726 100644
--- a/lib/libthr/thread/thr_clean.c
+++ b/lib/libthr/thread/thr_clean.c
@@ -84,7 +84,7 @@ _pthread_cleanup_push(void (*routine) (void *), void *arg)
curthread->unwind_disabled = 1;
#endif
if ((newbuf = (struct pthread_cleanup *)
- malloc(sizeof(struct _pthread_cleanup_info))) != NULL) {
+ malloc(sizeof(struct pthread_cleanup))) != NULL) {
newbuf->routine = routine;
newbuf->routine_arg = arg;
newbuf->onheap = 1;
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
index e71bf4a..7c05697 100644
--- a/lib/libthr/thread/thr_syscalls.c
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -95,10 +95,6 @@ __FBSDID("$FreeBSD$");
#include "libc_private.h"
#include "thr_private.h"
-#ifdef SYSCALL_COMPAT
-extern int __fcntl_compat(int, int, ...);
-#endif
-
static int
__thr_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
@@ -203,18 +199,10 @@ __thr_fcntl(int fd, int cmd, ...)
va_start(ap, cmd);
if (cmd == F_OSETLKW || cmd == F_SETLKW) {
_thr_cancel_enter(curthread);
-#ifdef SYSCALL_COMPAT
- ret = __fcntl_compat(fd, cmd, va_arg(ap, void *));
-#else
ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
-#endif
_thr_cancel_leave(curthread, ret == -1);
} else {
-#ifdef SYSCALL_COMPAT
- ret = __fcntl_compat(fd, cmd, va_arg(ap, void *));
-#else
ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
-#endif
}
va_end(ap);
@@ -327,6 +315,26 @@ __thr_poll(struct pollfd *fds, unsigned int nfds, int timeout)
* the thread is not canceled.
*/
static int
+__thr_ppoll(struct pollfd pfd[], nfds_t nfds, const struct timespec *
+ timeout, const sigset_t *newsigmask)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ ret = __sys_ppoll(pfd, nfds, timeout, newsigmask);
+ _thr_cancel_leave(curthread, ret == -1);
+
+ return (ret);
+}
+
+/*
+ * Cancellation behavior:
+ * Thread may be canceled at start, but if the system call returns something,
+ * the thread is not canceled.
+ */
+static int
__thr_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
const struct timespec *timo, const sigset_t *mask)
{
@@ -545,6 +553,25 @@ __thr_wait4(pid_t pid, int *status, int options, struct rusage *rusage)
/*
* Cancellation behavior:
+ * Thread may be canceled at start, but if the system call returns
+ * a child pid, the thread is not canceled.
+ */
+static pid_t
+__thr_wait6(idtype_t idtype, id_t id, int *status, int options,
+ struct __wrusage *ru, siginfo_t *infop)
+{
+ struct pthread *curthread;
+ pid_t ret;
+
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ ret = __sys_wait6(idtype, id, status, options, ru, infop);
+ _thr_cancel_leave(curthread, ret <= 0);
+ return (ret);
+}
+
+/*
+ * Cancellation behavior:
* Thread may be canceled at start, but if the thread wrote some data,
* it is not canceled.
*/
@@ -623,6 +650,8 @@ __thr_interpose_libc(void)
SLOT(spinlock);
SLOT(spinunlock);
SLOT(kevent);
+ SLOT(wait6);
+ SLOT(ppoll);
#undef SLOT
*(__libc_interposing_slot(
INTERPOS__pthread_mutex_init_calloc_cb)) =
diff --git a/lib/libvmmapi/Makefile b/lib/libvmmapi/Makefile
index 93d3c85..26cf86f 100644
--- a/lib/libvmmapi/Makefile
+++ b/lib/libvmmapi/Makefile
@@ -6,6 +6,8 @@ INCS= vmmapi.h
WARNS?= 2
+LIBADD= util
+
CFLAGS+= -I${.CURDIR}
.include <bsd.lib.mk>
diff --git a/lib/libxo/Makefile b/lib/libxo/Makefile
index cc0e72a..62fface 100644
--- a/lib/libxo/Makefile
+++ b/lib/libxo/Makefile
@@ -26,6 +26,7 @@ MAN+= xo_attr.3 \
xo_flush.3 \
xo_no_setlocale.3 \
xo_open_container.3 \
+ xo_open_marker.3 \
xo_open_list.3 \
xo_parse_args.3 \
xo_set_allocator.3 \
@@ -33,6 +34,7 @@ MAN+= xo_attr.3 \
xo_set_info.3 \
xo_set_options.3 \
xo_set_style.3 \
+ xo_set_version.3 \
xo_set_writer.3
MAN+= xo_format.5
diff --git a/lib/msun/Makefile b/lib/msun/Makefile
index aee0f2d..5cb6292 100644
--- a/lib/msun/Makefile
+++ b/lib/msun/Makefile
@@ -221,6 +221,8 @@ MLINKS+=trunc.3 truncf.3 trunc.3 truncl.3
.include <src.opts.mk>
-.include <bsd.arch.inc.mk>
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
.include <bsd.lib.mk>
diff --git a/lib/msun/Makefile.amd64 b/lib/msun/Makefile.amd64
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/msun/Makefile.amd64
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/msun/Makefile.i386 b/lib/msun/Makefile.i386
deleted file mode 100644
index dd0f5b0..0000000
--- a/lib/msun/Makefile.i386
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
diff --git a/lib/msun/man/j0.3 b/lib/msun/man/j0.3
index 7e1b790..587b72e 100644
--- a/lib/msun/man/j0.3
+++ b/lib/msun/man/j0.3
@@ -98,7 +98,7 @@ The functions
.Fn y1 ,
and
.Fn y1f
-compute the linearly independent Bessel function of the second kind
+compute the linearly independent Bessel function of the second kind
of orders 0 and 1 for the positive
.Em real
value
@@ -135,12 +135,12 @@ is \*(Pm0, these routines
will generate a divide-by-zero exception and return -\*(If.
If
.Fa x
-is a sufficiently small positive number, then
+is a sufficiently small positive number, then
.Fn y1 ,
.Fn y1f ,
.Fn yn ,
and
-.Fn ynf
+.Fn ynf
will generate an overflow exception and return -\*(If.
.Sh SEE ALSO
.Xr math 3
diff --git a/lib/msun/man/lgamma.3 b/lib/msun/man/lgamma.3
index cb4b160..c8a22a2 100644
--- a/lib/msun/man/lgamma.3
+++ b/lib/msun/man/lgamma.3
@@ -124,7 +124,6 @@ are deprecated aliases for
and
.Fn lgammaf_r ,
respectively.
-
.Sh IDIOSYNCRASIES
Do not use the expression
.Dq Li signgam\(**exp(lgamma(x))
diff --git a/lib/msun/man/nextafter.3 b/lib/msun/man/nextafter.3
index c8c4aa3..01c472d 100644
--- a/lib/msun/man/nextafter.3
+++ b/lib/msun/man/nextafter.3
@@ -78,11 +78,11 @@ routines conform to
They implement the Nextafter function recommended by
.St -ieee754 ,
with the extension that
-.Fn nextafter +0.0, -0.0
+.Fn nextafter "+0.0" "-0.0"
returns
.Li -0.0 ,
and
-.Fn nextafter -0.0, +0.0
+.Fn nextafter "-0.0" "+0.0"
returns
.Li +0.0 .
.Sh HISTORY
diff --git a/lib/msun/tests/Makefile b/lib/msun/tests/Makefile
index cb06868..0479cfb 100644
--- a/lib/msun/tests/Makefile
+++ b/lib/msun/tests/Makefile
@@ -6,13 +6,12 @@ TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libm
TESTSDIR= ${TESTSBASE}/lib/msun
-.if ${MACHINE} == "sparc" || ${MACHINE} == "i386" \
- || ${MACHINE} == "amd64" || ${MACHINE_CPU} == "arm" \
- || ${MACHINE} == "sparc64"
+# All architectures on FreeBSD have fenv.h
CFLAGS+= -DHAVE_FENV_H
-.endif
-.if ${MACHINE} == "amd64" || ${MACHINE} == "i386"
+# Not sure why this isn't defined for all architectures, since most
+# have long double.
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
CFLAGS+= -D__HAVE_LONG_DOUBLE
.endif
diff --git a/libexec/casper/dns/dns.c b/libexec/casper/dns/dns.c
index 6be022a..f82801e 100644
--- a/libexec/casper/dns/dns.c
+++ b/libexec/casper/dns/dns.c
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
+#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
@@ -103,6 +104,8 @@ static void
hostent_pack(const struct hostent *hp, nvlist_t *nvl)
{
unsigned int ii;
+ char nvlname[64];
+ int n;
nvlist_add_string(nvl, "name", hp->h_name);
nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype);
@@ -112,8 +115,9 @@ hostent_pack(const struct hostent *hp, nvlist_t *nvl)
nvlist_add_number(nvl, "naliases", 0);
} else {
for (ii = 0; hp->h_aliases[ii] != NULL; ii++) {
- nvlist_addf_string(nvl, hp->h_aliases[ii], "alias%u",
- ii);
+ n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]);
}
nvlist_add_number(nvl, "naliases", (uint64_t)ii);
}
@@ -122,8 +126,10 @@ hostent_pack(const struct hostent *hp, nvlist_t *nvl)
nvlist_add_number(nvl, "naddrs", 0);
} else {
for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) {
- nvlist_addf_binary(nvl, hp->h_addr_list[ii],
- (size_t)hp->h_length, "addr%u", ii);
+ n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii],
+ (size_t)hp->h_length);
}
nvlist_add_number(nvl, "naddrs", (uint64_t)ii);
}
@@ -228,8 +234,10 @@ dns_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
goto out;
}
- if (!dns_allowed_family(limits, (int)sast.ss_family))
- return (NO_RECOVERY);
+ if (!dns_allowed_family(limits, (int)sast.ss_family)) {
+ error = NO_RECOVERY;
+ goto out;
+ }
flags = (int)nvlist_get_number(nvlin, "flags");
@@ -269,9 +277,10 @@ dns_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
{
struct addrinfo hints, *hintsp, *res, *cur;
const char *hostname, *servname;
+ char nvlname[64];
nvlist_t *elem;
unsigned int ii;
- int error, family;
+ int error, family, n;
if (!dns_allowed_type(limits, "ADDR"))
return (NO_RECOVERY);
@@ -308,7 +317,9 @@ dns_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) {
elem = addrinfo_pack(cur);
- nvlist_movef_nvlist(nvlout, elem, "res%u", ii);
+ n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_move_nvlist(nvlout, nvlname, elem);
}
freeaddrinfo(res);
diff --git a/libexec/casper/grp/grp.c b/libexec/casper/grp/grp.c
index ba22f62..ab28e1a 100644
--- a/libexec/casper/grp/grp.c
+++ b/libexec/casper/grp/grp.c
@@ -30,6 +30,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <stdlib.h>
@@ -184,6 +185,8 @@ grp_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
static bool
grp_pack(const nvlist_t *limits, const struct group *grp, nvlist_t *nvl)
{
+ char nvlname[64];
+ int n;
if (grp == NULL)
return (true);
@@ -210,8 +213,10 @@ grp_pack(const nvlist_t *limits, const struct group *grp, nvlist_t *nvl)
unsigned int ngroups;
for (ngroups = 0; grp->gr_mem[ngroups] != NULL; ngroups++) {
- nvlist_addf_string(nvl, grp->gr_mem[ngroups],
- "gr_mem[%u]", ngroups);
+ n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]",
+ ngroups);
+ assert(n > 0 && n < sizeof(nvlname));
+ nvlist_add_string(nvl, nvlname, grp->gr_mem[ngroups]);
}
nvlist_add_number(nvl, "gr_nmem", (uint64_t)ngroups);
}
diff --git a/libexec/getty/subr.c b/libexec/getty/subr.c
index 26d2173..992280a 100644
--- a/libexec/getty/subr.c
+++ b/libexec/getty/subr.c
@@ -38,9 +38,6 @@ static const char rcsid[] =
/*
* Melbourne getty.
*/
-#ifdef DEBUG
-#include <stdio.h>
-#endif
#include <stdlib.h>
#include <string.h>
#include <termios.h>
@@ -160,17 +157,6 @@ gettable(const char *name, char *buf)
fp->value = 1 ^ fp->invrt;
}
}
-
-#ifdef DEBUG
- printf("name=\"%s\", buf=\"%s\"\r\n", name, buf);
- for (sp = gettystrs; sp->field; sp++)
- printf("cgetstr: %s=%s\r\n", sp->field, sp->value);
- for (np = gettynums; np->field; np++)
- printf("cgetnum: %s=%d\r\n", np->field, np->value);
- for (fp = gettyflags; fp->field; fp++)
- printf("cgetflags: %s='%c' set='%c'\r\n", fp->field,
- fp->value + '0', fp->set + '0');
-#endif /* DEBUG */
}
void
diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c
index 8978110..b515a1e 100644
--- a/libexec/rtld-elf/aarch64/reloc.c
+++ b/libexec/rtld-elf/aarch64/reloc.c
@@ -161,7 +161,7 @@ rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, int flags,
if (def == NULL)
rtld_die();
- tlsdesc->index = defobj->tlsindex + def->st_value + rela->r_addend;
+ tlsdesc->index = defobj->tlsoffset + def->st_value + rela->r_addend;
return (tlsdesc->index);
}
@@ -206,7 +206,7 @@ reloc_plt(Obj_Entry *obj)
case R_AARCH64_TLSDESC:
if (ELF_R_SYM(rela->r_info) == 0) {
where[0] = (Elf_Addr)_rtld_tlsdesc;
- where[1] = obj->tlsindex + rela->r_addend;
+ where[1] = obj->tlsoffset + rela->r_addend;
} else {
where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
where[1] = (Elf_Addr)reloc_tlsdesc_alloc(obj,
diff --git a/libexec/rtld-elf/mips/reloc.c b/libexec/rtld-elf/mips/reloc.c
index 4e750d7..809adb8 100644
--- a/libexec/rtld-elf/mips/reloc.c
+++ b/libexec/rtld-elf/mips/reloc.c
@@ -245,7 +245,7 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL,
NULL);
if (def == NULL)
- _rtld_error("bind failed no symbol");
+ rtld_die();
target = (Elf_Addr)(defobj->relocbase + def->st_value);
dbg("bind now/fixup at %s sym # %jd in %s --> was=%p new=%p",
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 44b63a7..3ac4467 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -148,8 +148,10 @@ static void unlink_object(Obj_Entry *);
static void unload_object(Obj_Entry *);
static void unref_dag(Obj_Entry *);
static void ref_dag(Obj_Entry *);
-static char *origin_subst_one(char *, const char *, const char *, bool);
-static char *origin_subst(char *, const char *);
+static char *origin_subst_one(Obj_Entry *, char *, const char *,
+ const char *, bool);
+static char *origin_subst(Obj_Entry *, char *);
+static bool obj_resolve_origin(Obj_Entry *obj);
static void preinit_main(void);
static int rtld_verify_versions(const Objlist *);
static int rtld_verify_object_versions(Obj_Entry *);
@@ -788,8 +790,8 @@ basename(const char *name)
static struct utsname uts;
static char *
-origin_subst_one(char *real, const char *kw, const char *subst,
- bool may_free)
+origin_subst_one(Obj_Entry *obj, char *real, const char *kw,
+ const char *subst, bool may_free)
{
char *p, *p1, *res, *resp;
int subst_len, kw_len, subst_count, old_len, new_len;
@@ -808,9 +810,15 @@ origin_subst_one(char *real, const char *kw, const char *subst,
/*
* If the keyword is not found, just return.
+ *
+ * Return non-substituted string if resolution failed. We
+ * cannot do anything more reasonable, the failure mode of the
+ * caller is unresolved library anyway.
*/
- if (subst_count == 0)
+ if (subst_count == 0 || (obj != NULL && !obj_resolve_origin(obj)))
return (may_free ? real : xstrdup(real));
+ if (obj != NULL)
+ subst = obj->origin_path;
/*
* There is indeed something to substitute. Calculate the
@@ -847,20 +855,22 @@ origin_subst_one(char *real, const char *kw, const char *subst,
}
static char *
-origin_subst(char *real, const char *origin_path)
+origin_subst(Obj_Entry *obj, char *real)
{
char *res1, *res2, *res3, *res4;
+ if (obj == NULL || !trust)
+ return (xstrdup(real));
if (uts.sysname[0] == '\0') {
if (uname(&uts) != 0) {
_rtld_error("utsname failed: %d", errno);
return (NULL);
}
}
- res1 = origin_subst_one(real, "$ORIGIN", origin_path, false);
- res2 = origin_subst_one(res1, "$OSNAME", uts.sysname, true);
- res3 = origin_subst_one(res2, "$OSREL", uts.release, true);
- res4 = origin_subst_one(res3, "$PLATFORM", uts.machine, true);
+ res1 = origin_subst_one(obj, real, "$ORIGIN", NULL, false);
+ res2 = origin_subst_one(NULL, res1, "$OSNAME", uts.sysname, true);
+ res3 = origin_subst_one(NULL, res2, "$OSREL", uts.release, true);
+ res4 = origin_subst_one(NULL, res3, "$PLATFORM", uts.machine, true);
return (res4);
}
@@ -1124,7 +1134,7 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
#endif
case DT_FLAGS:
- if ((dynp->d_un.d_val & DF_ORIGIN) && trust)
+ if (dynp->d_un.d_val & DF_ORIGIN)
obj->z_origin = true;
if (dynp->d_un.d_val & DF_SYMBOLIC)
obj->symbolic = true;
@@ -1156,10 +1166,10 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
case DT_FLAGS_1:
if (dynp->d_un.d_val & DF_1_NOOPEN)
obj->z_noopen = true;
- if ((dynp->d_un.d_val & DF_1_ORIGIN) && trust)
+ if (dynp->d_un.d_val & DF_1_ORIGIN)
obj->z_origin = true;
- /*if (dynp->d_un.d_val & DF_1_GLOBAL)
- XXX ;*/
+ if (dynp->d_un.d_val & DF_1_GLOBAL)
+ obj->z_global = true;
if (dynp->d_un.d_val & DF_1_BIND_NOW)
obj->bind_now = true;
if (dynp->d_un.d_val & DF_1_NODELETE)
@@ -1207,30 +1217,33 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
}
}
+static bool
+obj_resolve_origin(Obj_Entry *obj)
+{
+
+ if (obj->origin_path != NULL)
+ return (true);
+ obj->origin_path = xmalloc(PATH_MAX);
+ return (rtld_dirname_abs(obj->path, obj->origin_path) != -1);
+}
+
static void
digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath,
const Elf_Dyn *dyn_soname, const Elf_Dyn *dyn_runpath)
{
- if (obj->z_origin && obj->origin_path == NULL) {
- obj->origin_path = xmalloc(PATH_MAX);
- if (rtld_dirname_abs(obj->path, obj->origin_path) == -1)
- rtld_die();
- }
-
- if (dyn_runpath != NULL) {
- obj->runpath = (char *)obj->strtab + dyn_runpath->d_un.d_val;
- if (obj->z_origin)
- obj->runpath = origin_subst(obj->runpath, obj->origin_path);
- }
- else if (dyn_rpath != NULL) {
- obj->rpath = (char *)obj->strtab + dyn_rpath->d_un.d_val;
- if (obj->z_origin)
- obj->rpath = origin_subst(obj->rpath, obj->origin_path);
- }
+ if (obj->z_origin && !obj_resolve_origin(obj))
+ rtld_die();
- if (dyn_soname != NULL)
- object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
+ if (dyn_runpath != NULL) {
+ obj->runpath = (char *)obj->strtab + dyn_runpath->d_un.d_val;
+ obj->runpath = origin_subst(obj, obj->runpath);
+ } else if (dyn_rpath != NULL) {
+ obj->rpath = (char *)obj->strtab + dyn_rpath->d_un.d_val;
+ obj->rpath = origin_subst(obj, obj->rpath);
+ }
+ if (dyn_soname != NULL)
+ object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
}
static void
@@ -1480,12 +1493,8 @@ find_library(const char *xname, const Obj_Entry *refobj, int *fdp)
xname);
return NULL;
}
- if (objgiven && refobj->z_origin) {
- return (origin_subst(__DECONST(char *, xname),
- refobj->origin_path));
- } else {
- return (xstrdup(xname));
- }
+ return (origin_subst(__DECONST(Obj_Entry *, refobj),
+ __DECONST(char *, xname)));
}
if (libmap_disable || !objgiven ||
@@ -1790,22 +1799,35 @@ init_dag(Obj_Entry *root)
}
static void
-process_nodelete(Obj_Entry *root)
+process_z(Obj_Entry *root)
{
const Objlist_Entry *elm;
+ Obj_Entry *obj;
/*
- * Walk over object DAG and process every dependent object that
- * is marked as DF_1_NODELETE. They need to grow their own DAG,
- * which then should have its reference upped separately.
+ * Walk over object DAG and process every dependent object
+ * that is marked as DF_1_NODELETE or DF_1_GLOBAL. They need
+ * to grow their own DAG.
+ *
+ * For DF_1_GLOBAL, DAG is required for symbol lookups in
+ * symlook_global() to work.
+ *
+ * For DF_1_NODELETE, the DAG should have its reference upped.
*/
STAILQ_FOREACH(elm, &root->dagmembers, link) {
- if (elm->obj != NULL && elm->obj->z_nodelete &&
- !elm->obj->ref_nodel) {
- dbg("obj %s nodelete", elm->obj->path);
- init_dag(elm->obj);
- ref_dag(elm->obj);
- elm->obj->ref_nodel = true;
+ obj = elm->obj;
+ if (obj == NULL)
+ continue;
+ if (obj->z_nodelete && !obj->ref_nodel) {
+ dbg("obj %s -z nodelete", obj->path);
+ init_dag(obj);
+ ref_dag(obj);
+ obj->ref_nodel = true;
+ }
+ if (obj->z_global && objlist_find(&list_global, obj) == NULL) {
+ dbg("obj %s -z global", obj->path);
+ objlist_push_tail(&list_global, obj);
+ init_dag(obj);
}
}
}
@@ -2152,7 +2174,7 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags)
* To avoid a race, we open the file and use fstat() rather than
* using stat().
*/
- if ((fd = open(path, O_RDONLY | O_CLOEXEC)) == -1) {
+ if ((fd = open(path, O_RDONLY | O_CLOEXEC | O_VERIFY)) == -1) {
_rtld_error("Cannot open \"%s\"", path);
free(path);
return (NULL);
@@ -2842,7 +2864,7 @@ search_library_pathfds(const char *name, const char *path, int *fdp)
dirfd = parse_libdir(fdstr);
if (dirfd < 0)
break;
- fd = __sys_openat(dirfd, name, O_RDONLY | O_CLOEXEC);
+ fd = __sys_openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_VERIFY);
if (fd >= 0) {
*fdp = fd;
len = strlen(fdstr) + strlen(name) + 3;
@@ -3044,13 +3066,13 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
initlist_add_objects(obj, &obj->next, &initlist);
}
/*
- * Process all no_delete objects here, given them own
- * DAGs to prevent their dependencies from being unloaded.
- * This has to be done after we have loaded all of the
- * dependencies, so that we do not miss any.
+ * Process all no_delete or global objects here, given
+ * them own DAGs to prevent their dependencies from being
+ * unloaded. This has to be done after we have loaded all
+ * of the dependencies, so that we do not miss any.
*/
if (obj != NULL)
- process_nodelete(obj);
+ process_z(obj);
} else {
/*
* Bump the reference counts for objects on this DAG. If
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index d207a92..d75d0ab 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -264,6 +264,7 @@ typedef struct Struct_Obj_Entry {
bool z_loadfltr : 1; /* Immediately load filtees */
bool z_interpose : 1; /* Interpose all objects but main */
bool z_nodeflib : 1; /* Don't search default library path */
+ bool z_global : 1; /* Make the object global */
bool ref_nodel : 1; /* Refcount increased to prevent dlclose */
bool init_scanned: 1; /* Object is already on init list. */
bool on_fini_list: 1; /* Object is already on fini list. */
diff --git a/release/Makefile.ec2 b/release/Makefile.ec2
index 869ebc1..f74d320 100644
--- a/release/Makefile.ec2
+++ b/release/Makefile.ec2
@@ -12,13 +12,17 @@ AMINAMESUFFIX!= date +-%Y-%m-%d
PUBLISH= --public
.endif
-ec2ami: cw-ec2
-.if !exists(/usr/local/bin/bsdec2-image-upload)
- @echo "--------------------------------------------------------------"
- @echo ">>> Creating EC2 AMIs requires bsdec2-image-upload"
- @echo "--------------------------------------------------------------"
- @false
+cw-ec2-portinstall:
+.if exists(${PORTSDIR}/net/bsdec2-image-upload/Makefile)
+ make -C ${PORTSDIR}/net/bsdec2-image-upload BATCH=1 all install clean
+.else
+. if !exists(/usr/local/sbin/pkg-static)
+ env ASSUME_ALWAYS_YES=yes pkg bootstrap -y
+. endif
+ env ASSUME_ALWAYS_YES=yes pkg install -y net/bsdec2-image-upload
.endif
+
+ec2ami: cw-ec2 cw-ec2-portinstall
.if !defined(AWSKEYFILE) || !exists(${AWSKEYFILE})
@echo "--------------------------------------------------------------"
@echo ">>> AWSKEYFILE must point at AWS keys for EC2 AMI creation"
diff --git a/release/arm/BEAGLEBONE.conf b/release/arm/BEAGLEBONE.conf
index 546af5c..4efb61d 100644
--- a/release/arm/BEAGLEBONE.conf
+++ b/release/arm/BEAGLEBONE.conf
@@ -33,5 +33,5 @@ load_target_env() {
export XDEV_FLAGS="${XDEV_FLAGS} MK_TESTS=no"
export KERNEL="BEAGLEBONE"
export CROCHETSRC="https://github.com/freebsd/crochet"
- export CROCHETBRANCH="trunk@r744"
+ export CROCHETBRANCH="trunk@rHEAD"
}
diff --git a/release/arm/PANDABOARD.conf b/release/arm/PANDABOARD.conf
index 9518914..dc8952d 100644
--- a/release/arm/PANDABOARD.conf
+++ b/release/arm/PANDABOARD.conf
@@ -33,5 +33,5 @@ load_target_env() {
export XDEV_FLAGS="${XDEV_FLAGS} MK_TESTS=no"
export KERNEL="PANDABOARD"
export CROCHETSRC="https://github.com/freebsd/crochet"
- export CROCHETBRANCH="trunk@r744"
+ export CROCHETBRANCH="trunk@rHEAD"
}
diff --git a/release/arm/RPI-B.conf b/release/arm/RPI-B.conf
index 19778f8..aae60c9 100644
--- a/release/arm/RPI-B.conf
+++ b/release/arm/RPI-B.conf
@@ -33,7 +33,7 @@ load_target_env() {
export XDEV_FLAGS="${XDEV_FLAGS} MK_TESTS=no"
export KERNEL="RPI-B"
export CROCHETSRC="https://github.com/freebsd/crochet"
- export CROCHETBRANCH="trunk@r744"
+ export CROCHETBRANCH="trunk@rHEAD"
export UBOOTSRC="https://github.com/gonzoua/u-boot-pi"
export UBOOTBRANCH="trunk"
export UBOOTDIR="/tmp/crochet/u-boot-rpi"
diff --git a/release/arm/WANDBOARD-QUAD.conf b/release/arm/WANDBOARD-QUAD.conf
index 48aa631..c3fff91 100644
--- a/release/arm/WANDBOARD-QUAD.conf
+++ b/release/arm/WANDBOARD-QUAD.conf
@@ -33,5 +33,5 @@ load_target_env() {
export XDEV_FLAGS="${XDEV_FLAGS} MK_TESTS=no"
export KERNEL="WANDBOARD-QUAD"
export CROCHETSRC="https://github.com/freebsd/crochet"
- export CROCHETBRANCH="trunk@r744"
+ export CROCHETBRANCH="trunk@rHEAD"
}
diff --git a/release/arm/ZEDBOARD.conf b/release/arm/ZEDBOARD.conf
index 07c35ba..4d0a461 100644
--- a/release/arm/ZEDBOARD.conf
+++ b/release/arm/ZEDBOARD.conf
@@ -32,5 +32,5 @@ load_target_env() {
export XDEV_FLAGS="${XDEV_FLAGS} MK_TESTS=no"
export KERNEL="ZEDBOARD"
export CROCHETSRC="https://github.com/freebsd/crochet"
- export CROCHETBRANCH="trunk@r744"
+ export CROCHETBRANCH="trunk@rHEAD"
}
diff --git a/release/arm64/make-memstick.sh b/release/arm64/make-memstick.sh
new file mode 100755
index 0000000..27ebf27
--- /dev/null
+++ b/release/arm64/make-memstick.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# This script generates a "memstick image" (image that can be copied to a
+# USB memory stick) from a directory tree. Note that the script does not
+# clean up after itself very well for error conditions on purpose so the
+# problem can be diagnosed (full filesystem most likely but ...).
+#
+# Usage: make-memstick.sh <directory tree> <image filename>
+#
+# $FreeBSD$
+#
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+export PATH
+
+if [ $# -ne 2 ]; then
+ echo "make-memstick.sh /path/to/directory /path/to/image/file"
+ exit 1
+fi
+
+if [ ! -d ${1} ]; then
+ echo "${1} must be a directory"
+ exit 1
+fi
+
+if [ -e ${2} ]; then
+ echo "won't overwrite ${2}"
+ exit 1
+fi
+
+echo '/dev/ufs/FreeBSD_Install / ufs ro,noatime 1 1' > ${1}/etc/fstab
+makefs -B little -o label=FreeBSD_Install ${2}.part ${1}
+if [ $? -ne 0 ]; then
+ echo "makefs failed"
+ exit 1
+fi
+rm ${1}/etc/fstab
+
+mkimg -s mbr -p efi:=${1}/boot/boot1.efifat -p freebsd:=${2}.part -o ${2}
+rm ${2}.part
+
diff --git a/release/doc/en_US.ISO8859-1/relnotes/article.xml b/release/doc/en_US.ISO8859-1/relnotes/article.xml
index d3f82d7..1528435 100644
--- a/release/doc/en_US.ISO8859-1/relnotes/article.xml
+++ b/release/doc/en_US.ISO8859-1/relnotes/article.xml
@@ -22,7 +22,7 @@
<pubdate>$FreeBSD$</pubdate>
- <!-- Last rev: 278934 -->
+ <!-- Last rev: 282146 -->
<copyright>
<year>2015</year>
@@ -316,7 +316,24 @@
<para revision="279571" contrib="sponsor"
sponsor="&scaleengine;">The &man.freebsd-update.8; utility has
been updated to prevent fetching updated binary patches when
- a previous upgrade has not been throughly completed.</para>
+ a previous upgrade has not been thoroughly completed.</para>
+
+ <para revision="279122" contrib="sponsor"
+ sponsor="&juniper;">The &man.netstat.1; utility has been
+ updated to link against the &man.libxo.3; shared
+ library.</para>
+
+ <para revision="280870">A regression in the &man.libarchive.3;
+ library that would prevent a directory from being included in
+ the archive when <literal>--one-file-system</literal> is used
+ has been fixed.</para>
+
+ <para revision="281311" contrib="sponsor" sponsor="&ff;">The
+ &man.ar.1; utility has been updated to set
+ <literal>ARCHIVE_EXTRACT_SECURE_SYMLINKS</literal> and
+ <literal>ARCHIVE_EXTRACT_SECURE_NODOTDOT</literal> to disallow
+ directory traversal when extracting an archive, similar to
+ &man.tar.1;.</para>
</sect2>
<sect2 xml:id="userland-contrib">
@@ -335,9 +352,6 @@
<para revision="261071">&man.jemalloc.3; has been updated to
version 3.5.0.</para>
- <para revision="261212"><application>bmake</application> has
- been updated to version 20140101.</para>
-
<para revision="261283"><application>libc++</application> has
been updated to version 3.4.</para>
@@ -379,6 +393,7 @@
<application>addr2line</application>,
<application>elfcopy (strip)</application>,
<application>nm</application>,
+ <application>readelf</application>,
<application>size</application>, and
<application>strings</application> were switched to the
versions from the ELF Tool Chain project.</para>
@@ -388,17 +403,34 @@
adding <acronym>UTF-8</acronym> support to the &man.sh.1;
shell.</para>
- <para revision="277270"><application>OpenSSL</application> has
- been updated to version 1.0.1l.</para>
-
- <para revision="278433">The &man.xz.1; utility has been udpated
- to version 5.2.0.</para>
-
<para revision="278433">The &man.xz.1; utility has been updated
to support multi-threaded compression.</para>
- <para revision="278970">The &man.acpi.4; subsystem has been
- updated to version 20150204.</para>
+ <para revision="280297"><application>OpenSSL</application> has
+ been updated to version 1.0.1m.</para>
+
+ <para revision="280932" contrib="sponsor" sponsor="&ff;">The
+ <application>elftoolchain</application> utilities have been
+ updated to version 3179.</para>
+
+ <para revision="281316">The &man.xz.1; utility has been updated
+ to version 5.2.1.</para>
+
+ <para revision="281373">The &man.nvi.1; utility has been updated
+ to version 2.1.3.</para>
+
+ <para revision="281396">The &man.acpi.4; subsystem has been
+ updated to version 20150410.</para>
+
+ <para revision="281806">The &man.wpa.supplicant.8; and
+ &man.hostapd.8; utilties have been updated to version
+ 2.4.</para>
+
+ <para revision="281812"><application>bmake</application> has
+ been updated to version 20150418.</para>
+
+ <para revision="282089">The &man.unbound.8; utility has been
+ updated to version 1.5.3.</para>
</sect2>
<sect2 xml:id="userland-installer">
@@ -481,6 +513,10 @@
<acronym>ELF</acronym> object in the
<literal>dlpi_name</literal> structure member.</para>
+ <para revision="273562" contrib="sponsor"
+ sponsor="&juniper;">The &man.libxo.3; library has been
+ imported to the base system.</para>
+
<para revision="273806" contrib="sponsor" sponsor="&chelsio;">A
userland library for Chelsio Terminator 5 based iWARP cards
has been added, allowing userland <acronym>RDMA</acronym>
@@ -509,6 +545,15 @@
updated to be able to handle 32-bit aligned data on 64-bit
platforms, also providing a significant improvement in 32-bit
workloads.</para>
+
+ <para revision="281130">Several standard include headers have
+ been updated to use of <application>gcc</application>
+ attributes, such as <literal>__result_use_check()</literal>,
+ <literal>__alloc_size()</literal>, and
+ <literal>__nonnull()</literal>.</para>
+
+ <para revision="281845">Support for file verification in
+ <acronym>MAC</acronym> has been added.</para>
</sect2>
<sect2 xml:id="userland-abi">
@@ -547,6 +592,30 @@
<para revision="272089">A bug in &man.ipfw.4; that could
potentially lead to a kernel panic when using &man.dummynet.4;
at layer 2 has been fixed.</para>
+
+ <para revision="280930" contrib="sponsor" sponsor="&mitail;">The
+ kernel <acronym>RPC</acronym> has been updated to include
+ several enhancements:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The 45 MiB limit on requests queued for
+ &man.nfsd.8; threads has been removed.</para>
+ </listitem>
+
+ <listitem>
+ <para>Avoids unnecessary throttling by not deferring
+ accounting for completed requests.</para>
+ </listitem>
+
+ <listitem>
+ <para>Fixes an integer overflow and signedness bugs.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para revision="281261" arch="powerpc">Support for
+ &man.dtrace.1; has been added for the
+ Book-E&nbsp;&trade;.</para>
</sect2>
<sect2 xml:id="kernel-config">
@@ -604,6 +673,14 @@
<para revision="279361">The <literal>kern.osrelease</literal>
and <literal>kern.osreldate</literal> are now configurable
&man.jail.8; parameters.</para>
+
+ <para revision="280308,280949" contrib="sponsor"
+ sponsor="&ix;, &ff;">The &man.devfs.5; device filesystem has
+ been changed to update timestamps for read/write operations
+ using seconds precision. A new &man.sysctl.8;,
+ <literal>vfs.devfs.dotimes</literal> has been added, which
+ when set to a non-zero value, enables default precision
+ timestamps for these operations.</para>
</sect2>
</sect1>
@@ -642,6 +719,9 @@
<filename>/dev/hpet<replaceable>N</replaceable></filename>
device, providing access to <acronym>HPET</acronym> from
userspace.</para>
+
+ <para revision="280183">The <literal>drm</literal> code has
+ been updated to match &linux; version 3.8.13.</para>
</sect2>
<sect2 xml:id="drivers-storage">
@@ -676,6 +756,9 @@
<para revision="276526">The <literal>asr(4)</literal> driver has
been removed, and is no longer supported.</para>
+
+ <para revision="281387">The &man.hptnr.4; driver has been
+ updated to version 1.1.1.</para>
</sect2>
<sect2 xml:id="drivers-network">
@@ -768,6 +851,10 @@
driver has been updated to correct performance counter
sampling on G4 (MPC74xxx) and G5 class processors.</para>
+ <para revision="281713" arch="powerpc">The &man.hwpmc.4;
+ driver has been updated to support the Freescale e500
+ core.</para>
+
<para revision="275732" contrib="sponsor"
sponsor="&ff;,&netgate;">The
<application>OpenCrypto</application> framework has been
@@ -819,6 +906,14 @@
<para revision="273515">The &man.virtio.console.4; driver has
been added, which provides an interface to VirtIO console
devices through a &man.tty.4; device.</para>
+
+ <para revision="279957">The &man.bhyve.8; hypervisor has been
+ updated to support <literal>DSM TRIM</literal> commands for
+ virtual <acronym>AHCI</acronym> disks.</para>
+
+ <para revision="281439" arch="arm">Support for the
+ <application>QEMU</application> <literal>virt</literal> system
+ has been added.</para>
</sect2>
<sect2 xml:id="hardware-arm">
@@ -835,6 +930,10 @@
driver has been added, which supports <acronym>CPU</acronym>
frequency and voltage control on the Raspberry Pi
<acronym>SOC</acronym>.</para>
+
+ <para revision="280259" contrib="sponsor" sponsor="&ff;">Initial
+ support for the ARM AArch64 architecture has been
+ added.</para>
</sect2>
</sect1>
@@ -846,6 +945,7 @@
<sect2 xml:id="storage-general">
<title>General Storage</title>
+
<para revision="278037" contrib="sponsor" sponsor="&ix;">The
&man.ctl.4; <acronym>LUN</acronym> mapping has been rewritten,
replacing <acronym>iSCSI</acronym>-specific mapping mechanisms
@@ -907,6 +1007,12 @@
Alternatively, &man.syscons.4; can be enabled at boot time by
entering <literal>set kern.vty=sc</literal> at the
&man.loader.8; prompt.</para>
+
+ <para revision="281616">The boot loader has been updated to
+ support entering the <acronym>GELI</acronym> passphrase before
+ loading the kernel. To enable this behavior, add
+ <literal>geom_eli_passphrase_prompt="YES"</literal> to
+ &man.loader.conf.5;.</para>
</sect2>
<sect2 xml:id="boot-menu">
@@ -1002,6 +1108,13 @@
</tbody>
</tgroup>
</informaltable>
+
+ <para revision="280971" contrib="sponsor"
+ sponsor="&netflix;, &nginx;">Support for <acronym>IP</acronym>
+ identification for atomic datagrams (<acronym>RFC</acronym>
+ 6864) has been added. Support for this feature can be toggled
+ with the <literal>net.inet.ip.rfc6864</literal>
+ &man.sysctl.8;, which is enabled by default.</para>
</sect2>
</sect1>
diff --git a/release/doc/share/xml/release.ent b/release/doc/share/xml/release.ent
index e02a5f6..f72b4d0 100644
--- a/release/doc/share/xml/release.ent
+++ b/release/doc/share/xml/release.ent
@@ -70,6 +70,7 @@
<!-- Architecture names -->
<!ENTITY arch.amd64 "amd64">
<!ENTITY arch.arm "arm">
+<!ENTITY arch.arm64 "aarch64">
<!ENTITY arch.i386 "i386">
<!ENTITY arch.mips "mips">
<!ENTITY arch.pc98 "pc98">
diff --git a/release/doc/share/xml/sponsor.ent b/release/doc/share/xml/sponsor.ent
index 6e77d0d..91cfe65 100644
--- a/release/doc/share/xml/sponsor.ent
+++ b/release/doc/share/xml/sponsor.ent
@@ -23,12 +23,18 @@
<!ENTITY google "Google">
+<!ENTITY juniper "Juniper Networks, Inc.">
+
<!ENTITY ix "iXsystems">
<!ENTITY limelight "Limelight Networks">
<!ENTITY lsi "LSI">
+<!ENTITY mitail "MIT Computer Science &amp; Artificial Intelligence Laboratory">
+
+<!ENTITY netflix "Netflix">
<!ENTITY netgate "Netgate">
+<!ENTITY nginx "Nginx, Inc.">
<!ENTITY sandvine "Sandvine, Inc.">
<!ENTITY scaleengine "ScaleEngine, Inc.">
diff --git a/release/release.conf.sample b/release/release.conf.sample
index aecfc34..9542df3 100644
--- a/release/release.conf.sample
+++ b/release/release.conf.sample
@@ -7,6 +7,7 @@
## defined in release.sh.
#load_chroot_env() { }
#load_target_env() { }
+#buildenv_setup() { }
## Set the directory within which the release will be built.
CHROOTDIR="/scratch"
diff --git a/release/release.sh b/release/release.sh
index 6511ec1..6b24b73 100755
--- a/release/release.sh
+++ b/release/release.sh
@@ -42,6 +42,7 @@ export PATH
# Prototypes that can be redefined per-chroot or per-target.
load_chroot_env() { }
load_target_env() { }
+buildenv_setup() { }
# The directory within which the release will be built.
CHROOTDIR="/scratch"
@@ -279,6 +280,7 @@ if [ -d ${CHROOTDIR}/usr/ports ]; then
fi
fi
+buildenv_setup
load_target_env
eval chroot ${CHROOTDIR} make -C /usr/src ${RELEASE_WMAKEFLAGS} buildworld
eval chroot ${CHROOTDIR} make -C /usr/src ${RELEASE_KMAKEFLAGS} buildkernel
diff --git a/release/scripts/mk-vmimage.sh b/release/scripts/mk-vmimage.sh
index d5985ce..fd84216 100755
--- a/release/scripts/mk-vmimage.sh
+++ b/release/scripts/mk-vmimage.sh
@@ -93,6 +93,16 @@ main() {
. "${VMCONFIG}"
fi
+ case ${TARGET}:${TARGET_ARCH} in
+ arm64:aarch64)
+ ROOTLABEL="ufs"
+ NOSWAP=1
+ ;;
+ *)
+ ROOTLABEL="gpt"
+ ;;
+ esac
+
vm_create_base
vm_install_base
vm_extra_install_base
diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr
index 8eafcee..d4cfc2d 100644
--- a/release/tools/vmimage.subr
+++ b/release/tools/vmimage.subr
@@ -14,17 +14,30 @@ write_partition_layout() {
SWAPOPT="-p freebsd-swap/swapfs::1G"
fi
+ _OBJDIR="$(make -C ${WORLDDIR} -V .OBJDIR)"
+ if [ -d "${_OBJDIR%%/usr/src}/${TARGET}.${TARGET_ARCH}" ]; then
+ BOOTFILES="/${_OBJDIR%%/usr/src}/${TARGET}.${TARGET_ARCH}/usr/src/sys/boot"
+ else
+ BOOTFILES="/${_OBJDIR}/sys/boot"
+ fi
+
case "${TARGET}:${TARGET_ARCH}" in
amd64:amd64 | i386:i386)
- mkimg -s gpt -b /boot/pmbr \
- -p freebsd-boot/bootfs:=/boot/gptboot \
+ mkimg -s gpt -b ${BOOTFILES}/i386/pmbr/pmbr \
+ -p freebsd-boot/bootfs:=${BOOTFILES}/i386/gptboot/gptboot \
${SWAPOPT} \
-p freebsd-ufs/rootfs:=${VMBASE} \
-o ${VMIMAGE}
;;
+ arm64:aarch64)
+ mkimg -s mbr \
+ -p efi:=${BOOTFILES}/efi/boot1/boot1.efifat \
+ -p freebsd:=${VMBASE} \
+ -o ${VMIMAGE}
+ ;;
powerpc:powerpc*)
mkimg -s apm \
- -p apple-boot/bootfs:=/boot/boot1.hfs \
+ -p apple-boot/bootfs:=${BOOTFILES}/powerpc/boot1.chrp/boot1.hfs \
${SWAPOPT} \
-p freebsd-ufs/rootfs:=${VMBASE} \
-o ${VMIMAGE}
@@ -63,7 +76,7 @@ vm_create_base() {
mkdir -p ${DESTDIR}
truncate -s ${VMSIZE} ${VMBASE}
mddev=$(mdconfig -f ${VMBASE})
- newfs -j /dev/${mddev}
+ newfs -L rootfs /dev/${mddev}
mount /dev/${mddev} ${DESTDIR}
return 0
@@ -83,10 +96,10 @@ vm_copy_base() {
truncate -s ${VMSIZE} ${VMBASE}.tmp
mkdir -p ${DESTDIR}/new
mdnew=$(mdconfig -f ${VMBASE}.tmp)
- newfs -j /dev/${mdnew}
+ newfs -L rootfs /dev/${mdnew}
mount /dev/${mdnew} ${DESTDIR}/new
- tar -cf- -C ${DESTDIR}/old . | tar -xf- -C ${DESTDIR}/new
+ tar -cf- -C ${DESTDIR}/old . | tar -xUf- -C ${DESTDIR}/new
umount_loop /dev/${mdold}
rmdir ${DESTDIR}/old
@@ -94,6 +107,7 @@ vm_copy_base() {
umount_loop /dev/${mdnew}
rmdir ${DESTDIR}/new
+ tunefs -j enable /dev/${mdnew}
mdconfig -d -u ${mdnew}
mv ${VMBASE}.tmp ${VMBASE}
}
@@ -108,7 +122,7 @@ vm_install_base() {
echo '# Custom /etc/fstab for FreeBSD VM images' \
> ${DESTDIR}/etc/fstab
- echo '/dev/gpt/rootfs / ufs rw 1 1' \
+ echo "/dev/${ROOTLABEL}/rootfs / ufs rw 1 1" \
>> ${DESTDIR}/etc/fstab
if [ -z "${NOSWAP}" ]; then
echo '/dev/gpt/swapfs none swap sw 0 0' \
@@ -167,8 +181,10 @@ vm_extra_install_ports() {
}
vm_extra_pre_umount() {
- # Prototype. When overridden, installs additional ports within the
- # virtual machine environment.
+ # Prototype. When overridden, performs additional tasks within the
+ # virtual machine environment prior to unmounting the filesystem.
+ # Note: When overriding this function, removing resolv.conf in the
+ # disk image must be included.
rm -f ${DESTDIR}/etc/resolv.conf
return 0
diff --git a/sbin/atm/atmconfig/atmconfig.8 b/sbin/atm/atmconfig/atmconfig.8
index c8a740c..dc765ca 100644
--- a/sbin/atm/atmconfig/atmconfig.8
+++ b/sbin/atm/atmconfig/atmconfig.8
@@ -90,7 +90,7 @@ To get a list of options and arguments for a command use:
.Pp
To get a list of common options use:
.D1 Nm Ic help Cm options
-.Ss The Ic diag Ss Command
+.Ss The Ic diag Command
The
.Ic diag
command allows the inspection of the ATM interfaces on the local host
@@ -201,7 +201,7 @@ Print traffic parameters: PCR, SCR, MBS, MCR.
.It Nm Ic diag Cm stats Ar device
Print driver specific statistics.
.El
-.Ss The Ic natm Ss Command
+.Ss The Ic natm Command
The
.Ic natm
command is used to change
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index 97b897b..15e1862 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -529,7 +529,7 @@ on the system.
.It Ic defects
Send the
.Tn SCSI
-READ DEFECT DATA (10) command (0x37) or the
+READ DEFECT DATA (10) command (0x37) or the
.Tn SCSI
READ DEFECT DATA (12) command (0xB7) to the given device, and
print out any combination of: the total number of defects, the primary
@@ -563,19 +563,18 @@ drives.
.It longblock
Print out the list as logical blocks.
This option uses a 64-bit block size.
-.It bfi
+.It bfi
Print out the list in bytes from index format.
.It extbfi
Print out the list in extended bytes from index format.
The extended format allows for ranges of blocks to be printed.
-.It phys
+.It phys
Print out the list in physical sector format.
Most drives support this format.
.It extphys
Print out the list in extended physical sector format.
The extended format allows for ranges of blocks to be printed.
.El
-.Pp
.It Fl G
Print out the grown defect list.
This is a list of bad blocks that have
diff --git a/sbin/casperd/casperd.c b/sbin/casperd/casperd.c
index 4b9037b..f838811 100644
--- a/sbin/casperd/casperd.c
+++ b/sbin/casperd/casperd.c
@@ -357,7 +357,7 @@ service_external_execute(int chanfd)
int stderrfd, execfd, procfd;
nvlist_t *nvl;
- nvl = nvlist_recv(chanfd);
+ nvl = nvlist_recv(chanfd, 0);
if (nvl == NULL)
pjdlog_exit(1, "Unable to receive nvlist");
service = nvlist_take_string(nvl, "service");
diff --git a/sbin/casperd/zygote.c b/sbin/casperd/zygote.c
index be3d9e5..c460bd3 100644
--- a/sbin/casperd/zygote.c
+++ b/sbin/casperd/zygote.c
@@ -91,7 +91,7 @@ zygote_clone(zygote_func_t *func, int flags, int *chanfdp, int *procfdp)
nvl = nvlist_create(0);
nvlist_add_number(nvl, "func", (uint64_t)(uintptr_t)func);
nvlist_add_number(nvl, "flags", (uint64_t)flags);
- nvl = nvlist_xfer(zygote_sock, nvl);
+ nvl = nvlist_xfer(zygote_sock, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_exists_number(nvl, "error")) {
@@ -134,7 +134,7 @@ zygote_main(int sock)
closefrom(sock + 1);
for (;;) {
- nvlin = nvlist_recv(sock);
+ nvlin = nvlist_recv(sock, 0);
if (nvlin == NULL) {
if (errno == ENOTCONN) {
/* Casperd exited. */
diff --git a/sbin/dmesg/dmesg.c b/sbin/dmesg/dmesg.c
index 9fee416..827ed8e 100644
--- a/sbin/dmesg/dmesg.c
+++ b/sbin/dmesg/dmesg.c
@@ -118,6 +118,9 @@ main(int argc, char *argv[])
*/
if (sysctlbyname("kern.msgbuf", NULL, &buflen, NULL, 0) == -1)
err(1, "sysctl kern.msgbuf");
+ /* Allocate extra room for growth between the sysctl calls. */
+ buflen += buflen/8;
+ /* Allocate more than sysctl sees, for room to append \n\0. */
if ((bp = malloc(buflen + 2)) == NULL)
errx(1, "malloc failed");
if (sysctlbyname("kern.msgbuf", bp, &buflen, NULL, 0) == -1)
diff --git a/sbin/ggate/ggatel/ggatel.8 b/sbin/ggate/ggatel/ggatel.8
index 1463426..37e11cd 100644
--- a/sbin/ggate/ggatel/ggatel.8
+++ b/sbin/ggate/ggatel/ggatel.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 2, 2011
+.Dd April 9, 2015
.Dt GGATEL 8
.Os
.Sh NAME
@@ -40,12 +40,6 @@
.Op Fl u Ar unit
.Ar path
.Nm
-.Cm attach
-.Op Fl v
-.Op Fl o Cm ro | wo | rw
-.Fl u Ar unit
-.Ar path
-.Nm
.Cm destroy
.Op Fl f
.Fl u Ar unit
@@ -53,6 +47,12 @@
.Cm list
.Op Fl v
.Op Fl u Ar unit
+.Nm
+.Cm rescue
+.Op Fl v
+.Op Fl o Cm ro | wo | rw
+.Fl u Ar unit
+.Ar path
.Sh DESCRIPTION
The
.Nm
@@ -70,10 +70,6 @@ Available commands:
Create a
.Nm ggate
provider related to the given regular file or device.
-.It Cm attach
-Attach a worker process to an existing
-.Nm ggate
-provider.
.It Cm destroy
Destroy the given
.Nm ggate
@@ -82,6 +78,12 @@ provider.
List
.Nm ggate
providers.
+.It Cm rescue
+Take over a previously created provider and handle pending and future
+requests. This is useful if the initial
+.Nm
+process died. To prevent data loss, the given path must lead to the
+regular file or device that was used to create the provider.
.El
.Pp
Available options:
@@ -111,7 +113,7 @@ Default is 30.
.It Fl u Ar unit
Unit number to use.
.It Fl v
-Do not fork, run in foreground and print debug informations on standard
+Do not fork, run in foreground and print debug information on standard
output.
.It Ar path
Path to a regular file or device.
diff --git a/sbin/growfs/Makefile b/sbin/growfs/Makefile
index 1f7422e..e7017a7 100644
--- a/sbin/growfs/Makefile
+++ b/sbin/growfs/Makefile
@@ -4,8 +4,6 @@
# $FreeBSD$
#
-#GFSDBG=
-
.include <src.opts.mk>
.PATH: ${.CURDIR}/../mount
@@ -16,7 +14,9 @@ MAN= growfs.8
CFLAGS+=-I${.CURDIR}/../mount
.if defined(GFSDBG)
-SRCS+= debug.c
+SRCS+= debug.c
+CFLAGS+= -DFS_DEBUG
+NO_WCAST_ALIGN= yes
.endif
LIBADD= util
diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c
index 96897e2..7b85b25 100644
--- a/sbin/growfs/growfs.c
+++ b/sbin/growfs/growfs.c
@@ -161,7 +161,7 @@ growfs(int fsi, int fso, unsigned int Nflag)
#ifdef FS_DEBUG
{
struct csum *dbg_csp;
- int dbg_csc;
+ u_int32_t dbg_csc;
char dbg_line[80];
dbg_csp = fscs;
@@ -242,7 +242,7 @@ growfs(int fsi, int fso, unsigned int Nflag)
#ifdef FS_DEBUG
{
struct csum *dbg_csp;
- int dbg_csc;
+ u_int32_t dbg_csc;
char dbg_line[80];
dbg_csp = fscs;
diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c
index c733373..3c3a757 100644
--- a/sbin/ifconfig/af_inet.c
+++ b/sbin/ifconfig/af_inet.c
@@ -46,7 +46,6 @@ static const char rcsid[] =
#include <ifaddrs.h>
#include <netinet/in.h>
-#include <net/if_var.h> /* for struct ifaddr */
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index bff66e0..8a18401 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -48,7 +48,6 @@ static const char rcsid[] =
#include <arpa/inet.h>
#include <netinet/in.h>
-#include <net/if_var.h> /* for struct ifaddr */
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c
index 3a510a5..9a1be79 100644
--- a/sbin/ifconfig/af_nd6.c
+++ b/sbin/ifconfig/af_nd6.c
@@ -46,7 +46,6 @@ static const char rcsid[] =
#include <arpa/inet.h>
#include <netinet/in.h>
-#include <net/if_var.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
diff --git a/sbin/ifconfig/carp.c b/sbin/ifconfig/carp.c
index 2c58fcb..adff153 100644
--- a/sbin/ifconfig/carp.c
+++ b/sbin/ifconfig/carp.c
@@ -36,7 +36,6 @@
#include <unistd.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/ip_carp.h>
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 9d38a27..4a79992 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -51,7 +51,6 @@ static const char rcsid[] =
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
diff --git a/sbin/ifconfig/ifmedia.c b/sbin/ifconfig/ifmedia.c
index 0b0daa3..eee3391 100644
--- a/sbin/ifconfig/ifmedia.c
+++ b/sbin/ifconfig/ifmedia.c
@@ -109,11 +109,17 @@ media_status(int s)
{
struct ifmediareq ifmr;
int *media_list, i;
+ int xmedia = 1;
(void) memset(&ifmr, 0, sizeof(ifmr));
(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ /*
+ * Check if interface supports extended media types.
+ */
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
+ xmedia = 0;
+ if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
/*
* Interface doesn't support SIOC{G,S}IFMEDIA.
*/
@@ -130,8 +136,13 @@ media_status(int s)
err(1, "malloc");
ifmr.ifm_ulist = media_list;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
- err(1, "SIOCGIFMEDIA");
+ if (xmedia) {
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+ } else {
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+ err(1, "SIOCGIFMEDIA");
+ }
printf("\tmedia: ");
print_media_word(ifmr.ifm_current, 1);
@@ -194,6 +205,7 @@ ifmedia_getstate(int s)
{
static struct ifmediareq *ifmr = NULL;
int *mwords;
+ int xmedia = 1;
if (ifmr == NULL) {
ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
@@ -213,7 +225,10 @@ ifmedia_getstate(int s)
* the current media type and the top-level type.
*/
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) {
+ xmedia = 0;
+ }
+ if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
err(1, "SIOCGIFMEDIA");
}
@@ -225,8 +240,13 @@ ifmedia_getstate(int s)
err(1, "malloc");
ifmr->ifm_ulist = mwords;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
- err(1, "SIOCGIFMEDIA");
+ if (xmedia) {
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+ } else {
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
+ err(1, "SIOCGIFMEDIA");
+ }
}
return ifmr;
diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c
index cefcbbc..1a3fbaa 100644
--- a/sbin/ifconfig/ifvlan.c
+++ b/sbin/ifconfig/ifvlan.c
@@ -40,7 +40,6 @@
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_vlan_var.h>
#include <net/route.h>
diff --git a/sbin/ifconfig/ifvxlan.c b/sbin/ifconfig/ifvxlan.c
index 9aa84a2..48f5331 100644
--- a/sbin/ifconfig/ifvxlan.c
+++ b/sbin/ifconfig/ifvxlan.c
@@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_vxlan.h>
#include <net/route.h>
#include <netinet/in.h>
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 9a0bd9e..687d707 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -375,6 +375,13 @@ static int ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
ipfw_cfg_lheader *cfg, size_t sz, int ac, char **av);
static void ipfw_list_tifaces(void);
+struct tidx;
+static uint16_t pack_object(struct tidx *tstate, char *name, int otype);
+static uint16_t pack_table(struct tidx *tstate, char *name);
+
+static char *table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx);
+static void object_sort_ctlv(ipfw_obj_ctlv *ctlv);
+
/*
* Simple string buffer API.
* Used to simplify buffer passing between function and for
@@ -2558,6 +2565,7 @@ ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
if (cfg->flags & IPFW_CFG_GET_STATIC) {
/* We've requested static rules */
if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
+ object_sort_ctlv(ctlv);
fo->tstate = ctlv;
readsz += ctlv->head.length;
ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
@@ -2724,19 +2732,18 @@ struct tidx {
};
static uint16_t
-pack_table(struct tidx *tstate, char *name)
+pack_object(struct tidx *tstate, char *name, int otype)
{
int i;
ipfw_obj_ntlv *ntlv;
- if (table_check_name(name) != 0)
- return (0);
-
for (i = 0; i < tstate->count; i++) {
if (strcmp(tstate->idx[i].name, name) != 0)
continue;
if (tstate->idx[i].set != tstate->set)
continue;
+ if (tstate->idx[i].head.type != otype)
+ continue;
return (tstate->idx[i].idx);
}
@@ -2752,7 +2759,7 @@ pack_table(struct tidx *tstate, char *name)
ntlv = &tstate->idx[i];
memset(ntlv, 0, sizeof(ipfw_obj_ntlv));
strlcpy(ntlv->name, name, sizeof(ntlv->name));
- ntlv->head.type = IPFW_TLV_TBL_NAME;
+ ntlv->head.type = otype;
ntlv->head.length = sizeof(ipfw_obj_ntlv);
ntlv->set = tstate->set;
ntlv->idx = ++tstate->counter;
@@ -2761,6 +2768,16 @@ pack_table(struct tidx *tstate, char *name)
return (ntlv->idx);
}
+static uint16_t
+pack_table(struct tidx *tstate, char *name)
+{
+
+ if (table_check_name(name) != 0)
+ return (0);
+
+ return (pack_object(tstate, name, IPFW_TLV_TBL_NAME));
+}
+
static void
fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate)
{
@@ -3611,7 +3628,6 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
break;
} else
goto chkarg;
-
case TOK_QUEUE:
action->opcode = O_QUEUE;
goto chkarg;
@@ -4656,6 +4672,101 @@ done:
*rbufsize = (char *)dst - (char *)rule;
}
+static int
+compare_ntlv(const void *_a, const void *_b)
+{
+ ipfw_obj_ntlv *a, *b;
+
+ a = (ipfw_obj_ntlv *)_a;
+ b = (ipfw_obj_ntlv *)_b;
+
+ if (a->set < b->set)
+ return (-1);
+ else if (a->set > b->set)
+ return (1);
+
+ if (a->idx < b->idx)
+ return (-1);
+ else if (a->idx > b->idx)
+ return (1);
+
+ if (a->head.type < b->head.type)
+ return (-1);
+ else if (a->head.type > b->head.type)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Provide kernel with sorted list of referenced objects
+ */
+static void
+object_sort_ctlv(ipfw_obj_ctlv *ctlv)
+{
+
+ qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
+}
+
+struct object_kt {
+ uint16_t uidx;
+ uint16_t type;
+};
+static int
+compare_object_kntlv(const void *k, const void *v)
+{
+ ipfw_obj_ntlv *ntlv;
+ struct object_kt key;
+
+ key = *((struct object_kt *)k);
+ ntlv = (ipfw_obj_ntlv *)v;
+
+ if (key.uidx < ntlv->idx)
+ return (-1);
+ else if (key.uidx > ntlv->idx)
+ return (1);
+
+ if (key.type < ntlv->head.type)
+ return (-1);
+ else if (key.type > ntlv->head.type)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Finds object name in @ctlv by @idx and @type.
+ * Uses the following facts:
+ * 1) All TLVs are the same size
+ * 2) Kernel implementation provides already sorted list.
+ *
+ * Returns table name or NULL.
+ */
+static char *
+object_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx, uint16_t type)
+{
+ ipfw_obj_ntlv *ntlv;
+ struct object_kt key;
+
+ key.uidx = idx;
+ key.type = type;
+
+ ntlv = bsearch(&key, (ctlv + 1), ctlv->count, ctlv->objsize,
+ compare_object_kntlv);
+
+ if (ntlv != 0)
+ return (ntlv->name);
+
+ return (NULL);
+}
+
+static char *
+table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
+{
+
+ return (object_search_ctlv(ctlv, idx, IPFW_TLV_TBL_NAME));
+}
+
/*
* Adds one or more rules to ipfw chain.
* Data layout:
@@ -4724,7 +4835,7 @@ ipfw_add(char *av[])
ctlv->count = ts.count;
ctlv->objsize = sizeof(ipfw_obj_ntlv);
memcpy(ctlv + 1, ts.idx, tlen);
- table_sort_ctlv(ctlv);
+ object_sort_ctlv(ctlv);
tstate = ctlv;
/* Rule next */
ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 80970ef..5a08321 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -344,8 +344,6 @@ int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
/* tables.c */
struct _ipfw_obj_ctlv;
-char *table_search_ctlv(struct _ipfw_obj_ctlv *ctlv, uint16_t idx);
-void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv);
int table_check_name(char *tablename);
void ipfw_list_ta(int ac, char *av[]);
void ipfw_list_values(int ac, char *av[]);
diff --git a/sbin/ipfw/nat.c b/sbin/ipfw/nat.c
index 4391778..184b172 100644
--- a/sbin/ipfw/nat.c
+++ b/sbin/ipfw/nat.c
@@ -1008,11 +1008,10 @@ nat_foreach(nat_cb_t *f, void *arg, int sort)
olh->size = sz;
if (do_get3(IP_FW_NAT44_LIST_NAT, &olh->opheader, &sz) != 0) {
+ sz = olh->size;
free(olh);
- if (errno == ENOMEM) {
- sz = olh->size;
+ if (errno == ENOMEM)
continue;
- }
return (errno);
}
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
index 4ea5b7b..08f4731 100644
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -1937,73 +1937,6 @@ ipfw_list_values(int ac, char *av[])
}
int
-compare_ntlv(const void *_a, const void *_b)
-{
- ipfw_obj_ntlv *a, *b;
-
- a = (ipfw_obj_ntlv *)_a;
- b = (ipfw_obj_ntlv *)_b;
-
- if (a->set < b->set)
- return (-1);
- else if (a->set > b->set)
- return (1);
-
- if (a->idx < b->idx)
- return (-1);
- else if (a->idx > b->idx)
- return (1);
-
- return (0);
-}
-
-int
-compare_kntlv(const void *k, const void *v)
-{
- ipfw_obj_ntlv *ntlv;
- uint16_t key;
-
- key = *((uint16_t *)k);
- ntlv = (ipfw_obj_ntlv *)v;
-
- if (key < ntlv->idx)
- return (-1);
- else if (key > ntlv->idx)
- return (1);
-
- return (0);
-}
-
-/*
- * Finds table name in @ctlv by @idx.
- * Uses the following facts:
- * 1) All TLVs are the same size
- * 2) Kernel implementation provides already sorted list.
- *
- * Returns table name or NULL.
- */
-char *
-table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
-{
- ipfw_obj_ntlv *ntlv;
-
- ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
- compare_kntlv);
-
- if (ntlv != 0)
- return (ntlv->name);
-
- return (NULL);
-}
-
-void
-table_sort_ctlv(ipfw_obj_ctlv *ctlv)
-{
-
- qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
-}
-
-int
table_check_name(char *tablename)
{
int c, i, l;
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index 55a45e7..2b1ac52 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -457,7 +457,6 @@ However, for the following file system types:
.Cm msdosfs ,
.Cm nfs ,
.Cm nullfs ,
-.Cm oldnfs ,
.Cm smbfs ,
.Cm udf ,
and
diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c
index 5ea45df..6427fc8 100644
--- a/sbin/mount/mount.c
+++ b/sbin/mount/mount.c
@@ -144,7 +144,7 @@ use_mountprog(const char *vfstype)
unsigned int i;
const char *fs[] = {
"cd9660", "mfs", "msdosfs", "nfs",
- "nullfs", "oldnfs", "smbfs", "udf", "unionfs",
+ "nullfs", "smbfs", "udf", "unionfs",
NULL
};
diff --git a/sbin/mount_nfs/Makefile b/sbin/mount_nfs/Makefile
index eceed2b..75f7817 100644
--- a/sbin/mount_nfs/Makefile
+++ b/sbin/mount_nfs/Makefile
@@ -5,14 +5,11 @@
PROG= mount_nfs
SRCS= mount_nfs.c getmntopts.c mounttab.c
MAN= mount_nfs.8
-MLINKS= mount_nfs.8 mount_oldnfs.8
MOUNT= ${.CURDIR}/../mount
UMNTALL= ${.CURDIR}/../../usr.sbin/rpc.umntall
CFLAGS+= -DNFS -I${MOUNT} -I${UMNTALL}
-LINKS= ${BINDIR}/mount_nfs ${BINDIR}/mount_oldnfs
-
.PATH: ${MOUNT} ${UMNTALL}
.include <bsd.prog.mk>
diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8
index f3d28b3..3a9cff5 100644
--- a/sbin/mount_nfs/mount_nfs.8
+++ b/sbin/mount_nfs/mount_nfs.8
@@ -63,12 +63,6 @@ It implements the mount protocol as described in RFC 1094, Appendix A and
.%T "NFS: Network File System Version 3 Protocol Specification" ,
Appendix I.
.Pp
-If the file system type is specified as ``oldnfs'', which implies this
-command is run as ``mount_oldnfs'', then it forces use of the old NFS
-client, which does not support the
-.Cm nfsv4
-option.
-.Pp
By default,
.Nm
keeps retrying until the mount succeeds.
diff --git a/sbin/newfs_msdos/newfs_msdos.8 b/sbin/newfs_msdos/newfs_msdos.8
index d61043a..0f1abb4 100644
--- a/sbin/newfs_msdos/newfs_msdos.8
+++ b/sbin/newfs_msdos/newfs_msdos.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 1, 2013
+.Dd April 9, 2015
.Dt NEWFS_MSDOS 8
.Os
.Sh NAME
@@ -112,7 +112,7 @@ only those characters permitted in regular DOS (8+3) filenames.
.It Fl O Ar OEM
OEM string (up to 8 characters).
The default is
-.Qq Li "BSD 4.4" .
+.Qq Li "BSD4.4 " .
.It Fl S Ar sector-size
Number of bytes per sector.
Acceptable values are powers of 2
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 99c26c0..aebf8a7 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -44,10 +44,10 @@ __FBSDID("$FreeBSD$");
#include <netinet/icmp6.h>
#include <net/pfvar.h>
#include <arpa/inet.h>
-#include <altq/altq.h>
-#include <altq/altq_cbq.h>
-#include <altq/altq_priq.h>
-#include <altq/altq_hfsc.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index f90fd70..c1ba12f 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <net/pfvar.h>
#include <arpa/inet.h>
-#include <altq/altq.h>
+#include <net/altq/altq.h>
#include <sys/sysctl.h>
#include <err.h>
diff --git a/sbin/pfctl/pfctl_altq.c b/sbin/pfctl/pfctl_altq.c
index ae566f8..64f474c 100644
--- a/sbin/pfctl/pfctl_altq.c
+++ b/sbin/pfctl/pfctl_altq.c
@@ -38,10 +38,10 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
-#include <altq/altq.h>
-#include <altq/altq_cbq.h>
-#include <altq/altq_priq.h>
-#include <altq/altq_hfsc.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
#include "pfctl_parser.h"
#include "pfctl.h"
diff --git a/sbin/pfctl/pfctl_qstats.c b/sbin/pfctl/pfctl_qstats.c
index 95371e4..0921d47 100644
--- a/sbin/pfctl/pfctl_qstats.c
+++ b/sbin/pfctl/pfctl_qstats.c
@@ -34,10 +34,10 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
-#include <altq/altq.h>
-#include <altq/altq_cbq.h>
-#include <altq/altq_priq.h>
-#include <altq/altq_hfsc.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
#include "pfctl.h"
#include "pfctl_parser.h"
diff --git a/share/doc/papers/Makefile b/share/doc/papers/Makefile
index 866fe20..eaf097f 100644
--- a/share/doc/papers/Makefile
+++ b/share/doc/papers/Makefile
@@ -6,7 +6,6 @@ SUBDIR= beyond4.3 \
devfs \
diskperf \
fsinterface \
- hwpmc \
jail \
kernmalloc \
kerntune \
diff --git a/share/doc/papers/bufbio/bio.ms b/share/doc/papers/bufbio/bio.ms
index 123f8e7..32e2917 100644
--- a/share/doc/papers/bufbio/bio.ms
+++ b/share/doc/papers/bufbio/bio.ms
@@ -40,7 +40,7 @@ This paper contains the road-map for a stackable "BIO" system in
FreeBSD, which will support these facilities.
.AE
.NH
-The miseducation of \fCstruct buf\fP.
+The miseducation of \f(CW.)struct buf\fP.
.PP
To fully appreciate the topic, I include a little historic overview
of struct buf, it is a most enlightening case of not exactly bit-rot
@@ -51,7 +51,7 @@ memory is was introduced into UNIX, all disk I/O were done from or
to a struct buf. In the 6th edition sources, as printed in Lions
Book, struct buf looks like this:
.DS
-.ft C
+.ft CW
.ps -1
struct buf
{
@@ -95,7 +95,7 @@ aspect and only a few fields relate exclusively to the cache aspect.
If we step forward to the BSD 4.4-Lite-2 release, struct buf has grown
a bit here or there:
.DS
-.ft C
+.ft CW
.ps -1
struct buf {
LIST_ENTRY(buf) b_hash; /* Hash chain. */
@@ -144,7 +144,7 @@ aspect, link buffers to the VM system, provide hacks for file-systems
.PP
By the time we get to FreeBSD 3.0 more stuff has grown on struct buf:
.DS
-.ft C
+.ft CW
.ps -1
struct buf {
LIST_ENTRY(buf) b_hash; /* Hash chain. */
@@ -215,7 +215,7 @@ and Vinum. They all basically do the same: they map I/O requests from
a logical space to a physical space, and the mappings they perform
can be 1:1 or 1:N. \**
.FS
-It is interesting to note that Lions in his comments to the \fCrkaddr\fP
+It is interesting to note that Lions in his comments to the \f(CW.)rkaddr\fP
routine (p. 16-2) writes \fIThe code in this procedure incorporates
a special feature for files which extend over more than one disk
drive. This feature is described in the UPM Section "RK(IV)". Its
@@ -258,7 +258,7 @@ limited extent diskslice/label, which
need only the I/O aspect, not the vnode, caching or VM linkage.
.IP
.I
-The I/O aspect of struct buf should be put in a separate \fCstruct bio\fP.
+The I/O aspect of struct buf should be put in a separate \f(CW.)struct bio\fP.
.R
.NH 1
Implications for future struct buf improvements
@@ -296,7 +296,7 @@ Anything that could be added to or done with
the I/O aspect of struct buf can also be added to or done
with the I/O aspect if it lives in a new "struct bio".
.NH 1
-Implementing a \fCstruct bio\fP
+Implementing a \f(CW.)struct bio\fP
.PP
The first decision to be made was who got to use the name "struct buf",
and considering the fact that it is the I/O aspect which gets separated
@@ -344,7 +344,7 @@ Definition of struct bio
.PP
With the cleanup of b_flags in place, the definition of struct bio looks like this:
.DS
-.ft C
+.ft CW
.ps -1
struct bio {
u_int bio_cmd; /* I/O operation. */
@@ -375,7 +375,7 @@ Definition of struct buf
After adding a struct bio to struct buf and the fields aliased into it
struct buf looks like this:
.DS
-.ft C
+.ft CW
.ps -1
struct buf {
/* XXX: b_io must be the first element of struct buf for now /phk */
@@ -424,7 +424,7 @@ And can be found at http://phk.freebsd.dk/misc
.FE
and consists mainly of systematic substitutions like these
.DS
-.ft C
+.ft CW
s/struct buf/struct bio/
s/b_flags/bio_flags/
s/b_bcount/bio_bcount/
diff --git a/share/doc/papers/hwpmc/Makefile b/share/doc/papers/hwpmc/Makefile
deleted file mode 100644
index d24fe06..0000000
--- a/share/doc/papers/hwpmc/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# $FreeBSD$
-
-VOLUME= papers
-DOC= hwpmc
-SRCS= hwpmc.ms
-MACROS= -ms
-
-.include <bsd.doc.mk>
diff --git a/share/doc/papers/hwpmc/hwpmc.ms b/share/doc/papers/hwpmc/hwpmc.ms
deleted file mode 100644
index 9061bb7..0000000
--- a/share/doc/papers/hwpmc/hwpmc.ms
+++ /dev/null
@@ -1,34 +0,0 @@
-.\" Copyright (c) 2004 Joseph Koshy.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY JOSEPH KOSHY AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL JOSEPH KOSHY OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" $FreeBSD$
-.\"
-.OH '''Using Hardware Performance Monitoring Counters'
-.EH 'HWPMC'''
-.TL
-Using Hardware Performance Monitoring Counters in FreeBSD
-.sp
-\s-2FreeBSD 5.2.1\s+2
-.sp
-\fRJuly, 2004\fR
-.PP
diff --git a/share/doc/usd/06.bc/bc b/share/doc/usd/06.bc/bc
index c4e68c6..4d87f2c 100644
--- a/share/doc/usd/06.bc/bc
+++ b/share/doc/usd/06.bc/bc
@@ -36,12 +36,13 @@
.\" @(#)bc 6.2 (Berkeley) 4/17/91
.\"
.if n \{\
-.po 5n
-.ll 70n
+.nr PO 5n
+.nr LL 70n
.\}
.EH 'USD:6-%''BC \- An Arbitrary Precision Desk-Calculator Language'
.OH 'BC \- An Arbitrary Precision Desk-Calculator Language''USD:6-%'
.\".RP
+.ND
.TL
BC \- An Arbitrary Precision Desk-Calculator Language
.AU
diff --git a/share/doc/usd/10.exref/Makefile.inc b/share/doc/usd/10.exref/Makefile.inc
index c5c2f55..9c637dc 100644
--- a/share/doc/usd/10.exref/Makefile.inc
+++ b/share/doc/usd/10.exref/Makefile.inc
@@ -2,4 +2,3 @@
VOLUME= usd/10.exref
MACROS= -ms
-SRCDIR= ${.CURDIR}/../../../../../contrib/nvi/docs/USD.doc/exref
diff --git a/contrib/nvi/docs/USD.doc/exref/ex.rm b/share/doc/usd/10.exref/exref/ex.rm
index 217bad4..9adde17 100644
--- a/contrib/nvi/docs/USD.doc/exref/ex.rm
+++ b/share/doc/usd/10.exref/exref/ex.rm
@@ -30,11 +30,13 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)ex.rm 8.5 (Berkeley) 8/18/96
+.\" $FreeBSD$
.\"
.nr LL 6.5i
.nr FL 6.5i
.EH 'USD:12-%''Ex Reference Manual'
.OH 'Ex Reference Manual''USD:12-%'
+.ND
.nr )P 0
.de ZP
.nr pd \\n()P
diff --git a/contrib/nvi/docs/USD.doc/exref/ex.summary b/share/doc/usd/10.exref/summary/ex.summary
index 83084a3..83084a3 100644
--- a/contrib/nvi/docs/USD.doc/exref/ex.summary
+++ b/share/doc/usd/10.exref/summary/ex.summary
diff --git a/share/doc/usd/11.vitut/Makefile b/share/doc/usd/11.vitut/Makefile
index f412b62..5fbe9db 100644
--- a/share/doc/usd/11.vitut/Makefile
+++ b/share/doc/usd/11.vitut/Makefile
@@ -5,7 +5,6 @@ VOLUME= usd/11.edit
SRCS= edittut.ms
MACROS= -ms
USE_TBL=
-SRCDIR= ${.CURDIR}/../../../../contrib/nvi/docs/USD.doc/edit
# index for versatec is different from the one in edit.tut
# because the fonts are different and entries reference page
diff --git a/contrib/nvi/docs/USD.doc/edit/edittut.ms b/share/doc/usd/11.vitut/edittut.ms
index 8a9d66e..8a9d66e 100644
--- a/contrib/nvi/docs/USD.doc/edit/edittut.ms
+++ b/share/doc/usd/11.vitut/edittut.ms
diff --git a/share/doc/usd/12.vi/Makefile.inc b/share/doc/usd/12.vi/Makefile.inc
index 42d417f..d96b811 100644
--- a/share/doc/usd/12.vi/Makefile.inc
+++ b/share/doc/usd/12.vi/Makefile.inc
@@ -2,4 +2,3 @@
VOLUME= usd/12.vi
MACROS= -ms
-SRCDIR= ${.CURDIR}/../../../../../contrib/nvi/docs/USD.doc/vitut
diff --git a/contrib/nvi/docs/USD.doc/vitut/vi.summary b/share/doc/usd/12.vi/summary/vi.summary
index 8a09ce9..8a09ce9 100644
--- a/contrib/nvi/docs/USD.doc/vitut/vi.summary
+++ b/share/doc/usd/12.vi/summary/vi.summary
diff --git a/contrib/nvi/docs/USD.doc/vitut/vi.chars b/share/doc/usd/12.vi/vi/vi.chars
index 7941065..7941065 100644
--- a/contrib/nvi/docs/USD.doc/vitut/vi.chars
+++ b/share/doc/usd/12.vi/vi/vi.chars
diff --git a/contrib/nvi/docs/USD.doc/vitut/vi.in b/share/doc/usd/12.vi/vi/vi.in
index c36ebe4..c36ebe4 100644
--- a/contrib/nvi/docs/USD.doc/vitut/vi.in
+++ b/share/doc/usd/12.vi/vi/vi.in
diff --git a/contrib/nvi/docs/USD.doc/vitut/vi.apwh.ms b/share/doc/usd/12.vi/viapwh/vi.apwh.ms
index 6b07630..6b07630 100644
--- a/contrib/nvi/docs/USD.doc/vitut/vi.apwh.ms
+++ b/share/doc/usd/12.vi/viapwh/vi.apwh.ms
diff --git a/share/doc/usd/13.viref/Makefile b/share/doc/usd/13.viref/Makefile
index d7bb392..49226ba 100644
--- a/share/doc/usd/13.viref/Makefile
+++ b/share/doc/usd/13.viref/Makefile
@@ -9,7 +9,6 @@ CLEANFILES= vi.ref-patched index
TRFLAGS= -U # this is to hide warnings only
USE_SOELIM=
USE_TBL=
-SRCDIR= ${.CURDIR}/../../../../contrib/nvi/docs/USD.doc/vi.ref
vi.ref-patched: vi.ref
sed -e 's:^\.so index.so$$:&.\\*[.T]:' ${.ALLSRC} > ${.TARGET}
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/ex.cmd.roff b/share/doc/usd/13.viref/ex.cmd.roff
index 382e635..382e635 100644
--- a/contrib/nvi/docs/USD.doc/vi.ref/ex.cmd.roff
+++ b/share/doc/usd/13.viref/ex.cmd.roff
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/ref.so b/share/doc/usd/13.viref/ref.so
index a82c792..a82c792 100644
--- a/contrib/nvi/docs/USD.doc/vi.ref/ref.so
+++ b/share/doc/usd/13.viref/ref.so
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/set.opt.roff b/share/doc/usd/13.viref/set.opt.roff
index 8384128..8384128 100644
--- a/contrib/nvi/docs/USD.doc/vi.ref/set.opt.roff
+++ b/share/doc/usd/13.viref/set.opt.roff
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/vi.cmd.roff b/share/doc/usd/13.viref/vi.cmd.roff
index 12030cd..12030cd 100644
--- a/contrib/nvi/docs/USD.doc/vi.ref/vi.cmd.roff
+++ b/share/doc/usd/13.viref/vi.cmd.roff
diff --git a/contrib/nvi/docs/USD.doc/vi.ref/vi.ref b/share/doc/usd/13.viref/vi.ref
index 12a483f..12a483f 100644
--- a/contrib/nvi/docs/USD.doc/vi.ref/vi.ref
+++ b/share/doc/usd/13.viref/vi.ref
diff --git a/share/doc/usd/18.msdiffs/ms.diffs b/share/doc/usd/18.msdiffs/ms.diffs
index 3bd8de6..de937af 100644
--- a/share/doc/usd/18.msdiffs/ms.diffs
+++ b/share/doc/usd/18.msdiffs/ms.diffs
@@ -37,6 +37,7 @@
.AM
.OH 'A Revised Version of \*ms''USD:18-%'
.EH 'USD:18-%''A Revised Version of \*ms'
+.ND
.TL
A Revised Version of \*ms
.AU
diff --git a/share/doc/usd/22.trofftut/tt00 b/share/doc/usd/22.trofftut/tt00
index f8c5ea7..cb893ff 100644
--- a/share/doc/usd/22.trofftut/tt00
+++ b/share/doc/usd/22.trofftut/tt00
@@ -46,6 +46,7 @@
.OH 'A TROFF Tutorial''USD:22-%'
.\".RP
.\" .....TM 76-1273-7 39199 39199-11
+.ND
.TL
A TROFF Tutorial
.AU "MH 2C-518" 6021
diff --git a/share/doc/usd/contents/contents.ms b/share/doc/usd/contents/contents.ms
index f18d046..03fde20 100644
--- a/share/doc/usd/contents/contents.ms
+++ b/share/doc/usd/contents/contents.ms
@@ -35,6 +35,7 @@
..
.OH '''USD Contents'
.EH 'USD Contents'''
+.ND
.TL
UNIX User's Supplementary Documents (USD)
.if !r.U .nr .U 0
diff --git a/share/dtrace/siftr b/share/dtrace/siftr
new file mode 100755
index 0000000..d12d35f
--- /dev/null
+++ b/share/dtrace/siftr
@@ -0,0 +1,68 @@
+#!/usr/sbin/dtrace -s
+/*-
+ * Copyright (c) 2015 George V. Neville-Neil
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * The siftr D script collects data from the SIFTR kernel module.
+ *
+ * Usage: siftr
+ */
+
+#pragma D option quiet
+tcp:kernel::siftr
+{
+ printf("direction %s state %s local %d remote %d\n",
+ siftr_dir_string[args[0]->direction],
+ tcp_state_string[args[0]->conn_state],
+ args[0]->tcp_localport,
+ args[0]->tcp_foreignport);
+ printf("snd_cwnd %d snd_wnd %d rcv_wnd %d snd_bwnd %d snd_ssthresh %d\n",
+ args[0]->snd_cwnd,
+ args[0]->snd_wnd,
+ args[0]->rcv_wnd,
+ args[0]->snd_bwnd,
+ args[0]->snd_ssthresh);
+ printf("\tmax_seg_size %u smoothed_rtt %d sack_enabled %d\n",
+ args[0]->max_seg_size,
+ args[0]->smoothed_rtt,
+ args[0]->sack_enabled);
+ printf("\tsnd_scale %d rcv_scale %d flags 0x%x rxt_length %d\n",
+ args[0]->snd_scale,
+ args[0]->rcv_scale,
+ args[0]->flags,
+ args[0]->rxt_length);
+ printf("\tsnd_buf_hiwater %u snd_buf_cc %u rcv_buf_hiwater %u\n",
+ args[0]->snd_buf_hiwater,
+ args[0]->snd_buf_cc,
+ args[0]->rcv_buf_hiwater);
+ printf("\trcv_buf_cc %u sent_inflight_bytes %u t_segqlen %d\n",
+ args[0]->rcv_buf_cc,
+ args[0]->sent_inflight_bytes,
+ args[0]->t_segqlen);
+ printf("\tflowid %u flowtype %u\n",
+ args[0]->flowid,
+ args[0]->flowtype);
+}
diff --git a/share/man/man3/pthread_testcancel.3 b/share/man/man3/pthread_testcancel.3
index 0b54290..fc412de 100644
--- a/share/man/man3/pthread_testcancel.3
+++ b/share/man/man3/pthread_testcancel.3
@@ -1,5 +1,5 @@
.\" $FreeBSD$
-.Dd March 29, 2015
+.Dd April 16, 2015
.Dt PTHREAD_TESTCANCEL 3
.Os
.Sh NAME
@@ -132,6 +132,7 @@ argument is non-zero.
.It Fn openat
.It Fn pause
.It Fn poll
+.It Fn ppoll
.It Fn pselect
.It Fn pthread_cond_timedwait
.It Fn pthread_cond_wait
@@ -159,6 +160,8 @@ argument is non-zero.
.It Fn wait
.It Fn wait3
.It Fn wait4
+.It Fn wait6
+.It Fn waitid
.It Fn waitpid
.It Fn write
.It Fn writev
diff --git a/share/man/man3/queue.3 b/share/man/man3/queue.3
index 6c6cee3..fbd1a06 100644
--- a/share/man/man3/queue.3
+++ b/share/man/man3/queue.3
@@ -28,7 +28,7 @@
.\" @(#)queue.3 8.2 (Berkeley) 1/24/94
.\" $FreeBSD$
.\"
-.Dd June 17, 2013
+.Dd April 16, 2015
.Dt QUEUE 3
.Os
.Sh NAME
@@ -147,7 +147,7 @@ lists and tail queues
.Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
-.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE" "STAILQ_ENTRY NAME"
+.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_NEXT "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE_AFTER "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index c68634d..4291e7a 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -121,6 +121,12 @@ MAN= aac.4 \
dpt.4 \
ds1307.4 \
ds3231.4 \
+ ${_dtrace_io.4} \
+ ${_dtrace_ip.4} \
+ ${_dtrace_proc.4} \
+ ${_dtrace_sched.4} \
+ ${_dtrace_tcp.4} \
+ ${_dtrace_udp.4} \
dummynet.4 \
ed.4 \
edsc.4 \
@@ -812,6 +818,15 @@ SUBDIR= man4.${MACHINE_CPUARCH}
_ccd.4= ccd.4
.endif
+.if ${MK_CDDL} != "no"
+_dtrace_io.4= dtrace-io.4
+_dtrace_ip.4= dtrace-ip.4
+_dtrace_proc.4= dtrace-proc.4
+_dtrace_sched.4= dtrace-sched.4
+_dtrace_tcp.4= dtrace-tcp.4
+_dtrace_udp.4= dtrace-udp.4
+.endif
+
.if ${MK_ISCSI} != "no"
MAN+= iscsi.4
MAN+= iscsi_initiator.4
diff --git a/share/man/man4/ada.4 b/share/man/man4/ada.4
index fd38b33..6f2964e 100644
--- a/share/man/man4/ada.4
+++ b/share/man/man4/ada.4
@@ -156,6 +156,7 @@ ATA device nodes
.Xr ahci 4 ,
.Xr cam 4 ,
.Xr da 4 ,
+.Xr mvs 4 ,
.Xr siis 4
.Sh HISTORY
The
diff --git a/share/man/man4/amdtemp.4 b/share/man/man4/amdtemp.4
index 9ce676e..2b9bcc3 100644
--- a/share/man/man4/amdtemp.4
+++ b/share/man/man4/amdtemp.4
@@ -64,7 +64,7 @@ The driver also creates
in the corresponding CPU device's sysctl tree, displaying the maximum
temperature of the two sensors located in each CPU core.
.Pp
-For Family 10h, 11h, 12h, 14h, 15h and 16h processors, the driver reports each
+For Family 10h, 11h, 12h, 14h, 15h, and 16h processors, the driver reports each
package's temperature through a sysctl node, named
.Va dev.amdtemp.%d.core0.sensor0 .
The driver also creates
diff --git a/share/man/man4/ata.4 b/share/man/man4/ata.4
index b65a647..c303a5a 100644
--- a/share/man/man4/ata.4
+++ b/share/man/man4/ata.4
@@ -99,6 +99,7 @@ Interface Power Management is disabled.
This is the default value.
.It 1
The device is allowed to initiate a PM state change; the host is passive.
+.El
.It Va hint.ata. Ns Ar X Ns Va .dev Ns Ar X Ns Va .sata_rev
limits the initial SATA revision (speed) for the specified device
on the specified channel.
diff --git a/share/man/man4/ctl.4 b/share/man/man4/ctl.4
index a226b62..a04f2fe 100644
--- a/share/man/man4/ctl.4
+++ b/share/man/man4/ctl.4
@@ -23,7 +23,7 @@
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
-.Dd October 23, 2014
+.Dd April 8, 2015
.Dt CTL 4
.Os
.Sh NAME
@@ -34,6 +34,7 @@ To compile this driver into the kernel,
place the following line in your
kernel configuration file:
.Bd -ragged -offset indent
+.Cd "device iscsi"
.Cd "device ctl"
.Ed
.Pp
diff --git a/share/man/man4/dtrace-io.4 b/share/man/man4/dtrace-io.4
new file mode 100644
index 0000000..4f81434
--- /dev/null
+++ b/share/man/man4/dtrace-io.4
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 18, 2015
+.Dt DTRACE-IO 4
+.Os
+.Sh NAME
+.Nm dtrace-io
+.Nd a DTrace provider for tracing events related to disk I/O
+.Sh SYNOPSIS
+.Fn io:::start "struct bio *" "struct devstat *"
+.Fn io:::done "struct bio *" "struct devstat *"
+.Sh DESCRIPTION
+The
+.Nm io
+provider allows the tracing of disk I/O events.
+The
+.Fn io:::start
+probe fires when a I/O request is about to be sent to the backing driver of a
+.Xr disk 9
+object.
+This occurs after all
+.Xr GEOM 4
+transformations have been performed on the request.
+The
+.Fn io:::done
+probe fires when a I/O request is completed.
+Both probes take a
+.Vt "struct bio *"
+representing the I/O request as their first argument.
+The second argument is a
+.Vt "struct devstat *"
+for the underlying
+.Xr disk 9
+object.
+.Sh ARGUMENTS
+The fields of
+.Vt "struct bio"
+are described in the
+.Xr g_bio 9
+manual page, and the fields of
+.Vt "struct devstat"
+are described in the
+.Xr devstat 9
+manual page.
+Translators for the
+.Vt bufinfo_t
+and
+.Vt devinfo_t
+D types are defined in
+.Pa /usr/lib/dtrace/io.d .
+.Sh FILES
+.Bl -tag -width "/usr/lib/dtrace/io.d" -compact
+.It Pa /usr/lib/dtrace/io.d
+DTrace type and translator definitions for the
+.Nm io
+provider.
+.El
+.Sh EXAMPLES
+The following script shows a per-process breakdown of total I/O by disk device:
+.Bd -literal -offset indent
+#pragma D option quiet
+
+io:::start
+{
+ @[args[1]->device_name, execname, pid] = sum(args[0]->bio_bcount);
+}
+
+END
+{
+ printf("%10s %20s %10s %15s\n", "DEVICE", "APP", "PID", "BYTES");
+ printa("%10s %20s %10d %15@d\n", @);
+}
+.Ed
+.Sh COMPATIBILITY
+This provider is not compatible with the
+.Nm io
+provider found in Solaris, as its probes use native
+.Fx
+argument types.
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr devstat 9 ,
+.Xr SDT 9
+.Sh HISTORY
+The
+.Nm io
+provider first appeared in
+.Fx
+9.2 and 10.0.
+.Sh AUTHORS
+This manual page was written by
+.An Mark Johnston Aq Mt markj@FreeBSD.org .
+.Sh BUGS
+The
+.Fn io:::wait-start
+and
+.Fn io:::wait-done
+probes are not currently implemented on
+.Fx .
diff --git a/share/man/man4/dtrace-ip.4 b/share/man/man4/dtrace-ip.4
new file mode 100644
index 0000000..f0a4ea9
--- /dev/null
+++ b/share/man/man4/dtrace-ip.4
@@ -0,0 +1,285 @@
+.\" Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 18, 2015
+.Dt DTRACE-IP 4
+.Os
+.Sh NAME
+.Nm dtrace-ip
+.Nd a DTrace provider for tracing events related to the IPv4 and IPv6 protocols
+.Sh SYNOPSIS
+.Fn ip:::receive "pktinfo_t *" "csinfo_t *" "ipinfo_t *" "ifinfo_t *" \
+ "ipv4info_t *" "ipv6info_t *"
+.Fn ip:::send "pktinfo_t *" "csinfo_t *" "ipinfo_t *" "ifinfo_t *" \
+ "ipv4info_t *" "ipv6info_t *"
+.Sh DESCRIPTION
+The DTrace
+.Nm ip
+provider allows users to trace events in the
+.Xr ip 4
+and
+.Xr ip6 4
+protocol implementations.
+The
+.Fn ip:::send
+probe fires whenever the kernel prepares to transmit an IP packet, and the
+.Fn ip:::receive
+probe fires whenever the kernel receives an IP packet.
+The arguments to these probes can be used to obtain detailed information about
+the IP headers of the corresponding packet, as well as the network interface on
+which the packet was sent or received.
+Unlike the
+.Xr dtrace-tcp 4
+and
+.Xr dtrace-udp 4
+providers,
+.Nm ip
+provider probes are triggered by forwarded packets.
+That is, the probes will fire on packets that are not destined to the local
+host.
+.Sh ARGUMENTS
+The
+.Vt pktinfo_t
+argument is currently unimplemented and is included for compatibility with other
+implementations of this provider.
+Its fields are:
+.Bl -tag -width "uintptr_t pkt_addr" -offset indent
+.It Vt uintptr_t pkt_addr
+Always set to 0.
+.El
+.Pp
+The
+.Vt csinfo_t
+argument is currently unimplemented and is included for compatibility with other
+implementations of this provider.
+Its fields are:
+.Bl -tag -width "uintptr_t cs_addr" -offset indent
+.It Vt uintptr_t cs_addr
+Always set to 0.
+.It Vt uint64_t cs_cid
+A pointer to the
+.Vt struct inpcb
+for this packet, or
+.Dv NULL .
+.It Vt pid_t cs_pid
+Always set to 0.
+.El
+.Pp
+The
+.Vt ipinfo_t
+argument contains IP fields common to both IPv4 and IPv6 packets.
+Its fields are:
+.Bl -tag -width "uint32_t ip_plength" -offset indent
+.It Vt uint8_t ip_ver
+IP version of the packet, 4 for IPv4 packets and 6 for IPv6 packets.
+.It Vt uint32_t ip_plength
+IP payload size.
+This does not include the size of the IP header or IPv6 option headers.
+.It Vt string ip_saddr
+IP source address.
+.It Vt string ip_daddr
+IP destination address.
+.El
+.Pp
+The
+.Vt ifinfo_t
+argument describes the outgoing and incoming interfaces for the packet in the
+.Fn ip:::send
+and
+.Fn ip:::receive
+probes respectively.
+Its fields are:
+.Bl -tag -width "uintptr_t if_addr" -offset indent
+.It Vt string if_name
+The interface name.
+.It Vt int8_t if_local
+A boolean value indicating whether or not the interface is a loopback interface.
+.It Vt uintptr_t if_addr
+A pointer to the
+.Vt struct ifnet
+which describes the interface.
+See the
+.Xr ifnet 9
+manual page.
+.El
+.Pp
+The
+.Vt ipv4info_t
+argument contains the fields of the IP header for IPv4 packets.
+This argument is
+.Dv NULL
+for IPv6 packets.
+DTrace scripts should use the
+.Fn ip_ver
+field in the
+.Vt ipinfo_t
+argument to determine whether to use this argument.
+Its fields are:
+.Bl -tag -width "uint16_t ipv4_checksum" -offset indent
+.It Vt uint8_t ipv4_ver
+IP version.
+This will always be 4 for IPv4 packets.
+.It Vt uint8_t ipv4_ihl
+The IP header length, including options, in 32-bit words.
+.It Vt uint8_t ipv4_tos
+IP type of service field.
+.It Vt uint16_t ipv4_length
+The total packet length, including the header, in bytes.
+.It Vt uint16_t ipv4_ident
+Identification field.
+.It Vt uint8_t ipv4_flags
+The IP flags.
+.It Vt uint16_t ipv4_offset
+The fragment offset of the packet.
+.It Vt uint8_t ipv4_ttl
+Time to live field.
+.It Vt uint8_t ipv4_protocol
+Next-level protocol ID.
+.It Vt string ipv4_protostr
+A string containing the name of the encapsulated protocol.
+The protocol strings are defined in the
+.Va protocol
+array in
+.Pa /usr/lib/dtrace/ip.d
+.It Vt uint16_t ipv4_checksum
+The IP checksum.
+.It Vt ipaddr_t ipv4_src
+IPv4 source address.
+.It Vt ipaddr_t ipv4_dst
+IPv4 destination address.
+.It Vt string ipv4_saddr
+A string representation of the source address.
+.It Vt string ipv4_daddr
+A string representation of the destination address.
+.It Vt ipha_t *ipv4_hdr
+A pointer to the raw IPv4 header.
+.El
+.Pp
+The
+.Vt ipv6info_t
+argument contains the fields of the IP header for IPv6 packets.
+Its fields are not set for IPv4 packets; as with the
+.Vt ipv4info_t
+argument, the
+.Fn ip_ver
+field should be used to determine whether this argument is valid.
+Its fields are:
+.Bl -tag -width "uint16_t ipv4_checksum" -offset indent
+.It Vt uint8_t ipv6_ver
+IP version.
+This will always be 6 for IPv6 packets.
+.It Vt uint8_t ipv6_tclass
+The traffic class, used to set the differentiated services codepoint and
+extended congestion notification flags.
+.It Vt uint32_t ipv6_flow
+The flow label of the packet.
+.It Vt uint16_t ipv6_plen
+The IP payload size, including extension headers, in bytes.
+.It Vt uint8_t ipv6_nexthdr
+An identifier for the type of the next header.
+.It Vt string ipv6_nextstr
+A string representation of the type of the next header.
+.It Vt uint8_t ipv6_hlim
+The hop limit.
+.It Vt ip6_addr_t *ipv6_src
+IPv6 source address.
+.It Vt ip6_addr_t *ipv6_dst
+IPv6 destination address.
+.It Vt string ipv6_saddr
+A string representation of the source address.
+.It Vt string ipv6_daddr
+A string representation of the destination address.
+.It Vt ip6_t *ipv6_hdr
+A pointer to the raw IPv6 header.
+.El
+.Sh FILES
+.Bl -tag -width "/usr/lib/dtrace/ip.d" -compact
+.It Pa /usr/lib/dtrace/ip.d
+DTrace type and translator definitions for the
+.Nm ip
+provider.
+.El
+.Sh EXAMPLES
+The following script counts received packets by remote host address.
+.Bd -literal -offset indent
+ip:::receive
+{
+ @num[args[2]->ip_saddr] = count();
+}
+.Ed
+.Pp
+This script will print some details of each IP packet as it is sent or received
+by the kernel:
+.Bd -literal -offset indent
+#pragma D option quiet
+#pramga D option switchrate=10Hz
+
+dtrace:::BEGIN
+{
+ printf(" %10s %30s %-30s %8s %6s\n", "DELTA(us)", "SOURCE",
+ "DEST", "INT", "BYTES");
+ last = timestamp;
+}
+
+ip:::send
+{
+ this->elapsed = (timestamp - last) / 1000;
+ printf(" %10d %30s -> %-30s %8s %6d\n", this->elapsed,
+ args[2]->ip_saddr, args[2]->ip_daddr, args[3]->if_name,
+ args[2]->ip_plength);
+ last = timestamp;
+}
+
+ip:::receive
+{
+ this->elapsed = (timestamp - last) / 1000;
+ printf(" %10d %30s <- %-30s %8s %6d\n", this->elapsed,
+ args[2]->ip_daddr, args[2]->ip_saddr, args[3]->if_name,
+ args[2]->ip_plength);
+ last = timestamp;
+}
+.Ed
+.Sh COMPATIBILITY
+This provider is compatible with the
+.Nm ip
+providers found in Solaris and Darwin.
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr dtrace-tcp 4 ,
+.Xr dtrace-udp 4 ,
+.Xr ip 4 ,
+.Xr ip6 4 ,
+.Xr ifnet 9 ,
+.Xr SDT 9
+.Sh HISTORY
+The
+.Nm ip
+provider first appeared in
+.Fx
+10.0.
+.Sh AUTHORS
+This manual page was written by
+.An Mark Johnston Aq Mt markj@FreeBSD.org .
diff --git a/share/man/man4/dtrace-proc.4 b/share/man/man4/dtrace-proc.4
new file mode 100644
index 0000000..9ba74fb
--- /dev/null
+++ b/share/man/man4/dtrace-proc.4
@@ -0,0 +1,264 @@
+.\" Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 18, 2015
+.Dt DTRACE-PROC 4
+.Os
+.Sh NAME
+.Nm dtrace-proc
+.Nd a DTrace provider for tracing events related to user processes
+.Sh SYNOPSIS
+.Fn proc:::create "struct proc *" "struct proc *" "int"
+.Fn proc:::exec "char *"
+.Fn proc:::exec-failure "int"
+.Fn proc:::exec-success "char *"
+.Fn proc:::exit "int"
+.Fn proc:::signal-clear "int" "ksiginfo_t *"
+.Fn proc:::signal-discard "struct thread *" "struct proc *" "int"
+.Fn proc:::signal-send "struct thread *" "struct proc *" "int"
+.Sh DESCRIPTION
+The DTrace
+.Nm proc
+provider provides insight into events related to user processes: process and
+thread creation and termination events, and process signalling.
+.Pp
+The
+.Fn proc:::create
+probe fires when a user process is created via the
+.Xr fork 2 ,
+.Xr vfork 2 ,
+.Xr pdfork 2 ,
+or
+.Xr rfork 2
+system calls.
+In particular, kernel processes created with the
+.Xr kproc 9
+KPI will not trigger this probe.
+The
+.Fn proc:::create
+probe's first two arguments are the parent process and new child process,
+respectively.
+The third argument is a mask of
+.Xr rfork 2
+flags indicating which process resources are to be shared between the parent and
+child processes.
+.Pp
+The
+.Fn proc:::exec
+probe fires when a process attempts to execute a file.
+Its argument is the specified filename for the file.
+If the attempt fails because of an error, the
+.Fn proc:::exec-failure
+probe will subsequently fire, providing the corresponding
+.Xr errno 2
+value in its first argument.
+Otherwise, the
+.Fn proc:::exec-success
+probe will fire.
+.Pp
+The
+.Fn proc:::exit
+probe fires when a process exits or is terminated.
+Its argument is the corresponding
+.Dv SIGCHLD
+signal code; valid values are documented in the
+.Xr siginfo 3
+manual page and defined in
+.Pa signal.h .
+For example, when a process exits normally, the value of
+.Dv args[0]
+will be
+.Dv CLD_EXITED .
+.Pp
+The
+.Fn proc:::signal-send
+probe fires when a signal is about to be sent to a process.
+The
+.Fn proc:::signal-discard
+probe fires when a signal is sent to a process that ignores it.
+This probe will fire after the
+.Fn proc:::signal-send
+probe for the signal in question.
+The arguments to these probes are the thread and process to which the signal
+will be sent, and the signal number of the signal.
+Valid signal numbers are defined in the
+.Xr signal 3
+manual page.
+The
+.Fn proc:::signal-clear
+probe fires when a pending signal has been cleared by one of the
+.Xr sigwait 2 ,
+.Xr sigtimedwait 2 ,
+or
+.Xr sigwaitinfo 2
+system calls.
+Its arguments are the signal number of the cleared signal, and a pointer to
+the corresponding signal information.
+The
+.Vt siginfo_t
+for the signal can be obtained from
+.Dv args[1]->ksi_info .
+.Sh ARGUMENTS
+Though the
+.Nm proc
+provider probes use native
+.Fx
+arguments types, standard D types for processes and threads are available.
+These are
+.Vt psinfo_t
+and
+.Vt lwpsinfo_t
+respectively, and are defined in
+.Pa /usr/lib/dtrace/psinfo.d .
+This file also defines two global variables,
+.Va curpsinfo
+and
+.Va curlwpsinfo ,
+which provide representations of the current process and thread using these
+types.
+.Pp
+The fields of
+.Vt psinfo_t
+are:
+.Bl -tag -width "uintptr_t pr_addr" -offset indent
+.It Vt int pr_nlwp
+Number of threads in the process.
+.It Vt pid_t pr_pid
+Process ID.
+.It Vt pid_t pr_ppid
+Process ID of the parent process, or 0 if the process does not have a parent.
+.It Vt pid_t pr_pgid
+Process ID of the process group leader.
+.It Vt pid_t pr_sid
+Session ID, or 0 if the process does not belong to a session.
+.It Vt pid_t pr_uid
+Real user ID.
+.It Vt pid_t pr_euid
+Effective user ID.
+.It Vt pid_t pr_gid
+Real group ID.
+.It Vt pid_t pr_egid
+Effective group ID.
+.It Vt uintptr_t pr_addr
+Pointer to the
+.Vt struct proc
+for the process.
+.It Vt string pr_psargs
+Process arguments.
+.It Vt u_int pr_arglen
+Length of the process argument string.
+.It Vt u_int pr_jailid
+Jail ID of the process.
+.El
+.Pp
+The fields of
+.Vt lwpsinfo_t
+are:
+.Bl -tag -width "uintptr_t pr_wchar" -offset indent
+.It Vt id_t pr_lwpid
+Thread ID.
+.It Vt int pr_flag
+Thread flags.
+.It Vt int pr_pri
+Real scheduling priority of the thread.
+.It Vt char pr_state
+Currently always 0.
+.It Vt char pr_sname
+Currently always
+.Ql ? .
+.It Vt short pr_syscall
+Currently always 0.
+.It Vt uintptr_t pr_addr
+Pointer to the
+.Vt struct thread
+for the thread.
+.It Vt uintptr_t pr_wchan
+Current wait address on which the thread is sleeping.
+.El
+.Sh FILES
+.Bl -tag -width "/usr/lib/dtrace/psinfo.d" -compact
+.It Pa /usr/lib/dtrace/psinfo.d
+DTrace type and translator definitions for the
+.Nm proc
+provider.
+.El
+.Sh EXAMPLES
+The following script logs process execution events as they occur:
+.Bd -literal -offset indent
+#pragma D option quiet
+
+proc:::exec-success
+{
+ printf("%s", curpsinfo->pr_psargs);
+}
+.Ed
+.Pp
+Note that the
+.Dv pr_psargs
+field is subject to the limit defined by the
+.Va kern.ps_arg_cache_limit
+sysctl.
+In particular, processes with an argument list longer than the value defined by
+this sysctl cannot be logged in this way.
+.Sh COMPATIBILITY
+The
+.Nm proc
+provider in
+.Fx
+is not compatible with the
+.Nm proc
+provider in Solaris.
+In particular,
+.Fx
+uses the native
+.Vt "struct proc"
+and
+.Vt "struct thread"
+types for probe arguments rather than translated types.
+Additionally, a number of
+.Nm proc
+provider probes found in Solaris are not currently available on
+.Fx .
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr errno 2 ,
+.Xr fork 2 ,
+.Xr pdfork 2 ,
+.Xr rfork 2 ,
+.Xr vfork 2 ,
+.Xr siginfo 3 ,
+.Xr signal 3 ,
+.Xr dtrace-sched 4 ,
+.Xr kproc 9
+.Sh HISTORY
+The
+.Nm proc
+provider first appeared in
+.Fx
+7.1.
+.Sh AUTHORS
+This manual page was written by
+.An Mark Johnston Aq Mt markj@FreeBSD.org .
diff --git a/share/man/man4/dtrace-sched.4 b/share/man/man4/dtrace-sched.4
new file mode 100644
index 0000000..0b26e5e
--- /dev/null
+++ b/share/man/man4/dtrace-sched.4
@@ -0,0 +1,227 @@
+.\" Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 18, 2015
+.Dt DTRACE-SCHED 4
+.Os
+.Sh NAME
+.Nm dtrace-sched
+.Nd a DTrace provider for tracing CPU scheduling events
+.Sh SYNOPSIS
+.Fn sched:::change-pri "struct thread *" "struct proc *" "uint8_t"
+.Fn sched:::dequeue "struct thread *" "struct proc *" "void *"
+.Fn sched:::enqueue "struct thread *" "struct proc *" "void *" "int"
+.Fn sched:::lend-pri "struct thread *" "struct proc *" "uint8_t" "struct thread *"
+.Fn sched:::load-change "int" "int"
+.Fn sched:::off-cpu "struct thread *" "struct proc *"
+.Fn sched:::on-cpu
+.Fn sched:::preempt
+.Fn sched:::remain-cpu
+.Fn sched:::surrender "struct thread *" "struct proc *"
+.Fn sched:::sleep
+.Fn sched:::tick "struct thread *" "struct proc *"
+.Fn sched:::wakeup "struct thread *" "struct proc *"
+.Sh DESCRIPTION
+The DTrace
+.Nm sched
+provider allows the tracing of events related to CPU scheduling in the 4BSD and
+ULE schedulers.
+.Pp
+The
+.Fn sched:::change-pri
+probe fires when a thread's active scheduling priority is about to be updated.
+The first two arguments are the thread whose priority is about to be changed,
+and the corresponding process.
+The third argument is the new absolute priority for the thread, while the
+current value is given by
+.Dv args[0]->td_priority .
+The
+.Fn sched:::lend-pri
+probe fires when the currently-running thread elevates the priority of another
+thread via priority lending.
+The first two arguments are the thread whose priority is about to be changed,
+and the corresponding process.
+The third argument is the new absolute priority for the thread.
+The fourth argument is the currently-running thread.
+.Pp
+The
+.Fn sched:::dequeue
+probe fires immediately before a runnable thread is removed from a scheduler
+run queue.
+This may occur when the thread is about to begin execution on a CPU, or because
+the thread is being migrated to a different run queue.
+The latter event may occur in several circumstances: the scheduler may be
+attempting to rebalance load between multiple CPUs, the thread's scheduling
+priority may have changed, or the thread's CPU affinity settings may have
+changed.
+The first two arguments to
+.Fn sched:::dequeue
+are the thread and corresponding process.
+The third argument is currently always
+.Dv NULL .
+The
+.Fn sched:::enqueue
+probe fires when a runnable thread is about to be added to a scheduler run
+queue.
+Its first two arguments are the thread and corresponding process.
+The third argument is currently always
+.Dv NULL .
+The fourth argument is a boolean value that is non-zero if the thread is
+enqueued at the beginning of its run queue slot, and zero if the thread is
+instead enqueued at the end.
+.Pp
+The
+.Fn sched:::load-change
+probe fires after the load of a thread queue is adjusted.
+The first argument is the cpuid for the CPU associated with the thread queue,
+and the second argument is the adjusted load of the thread queue, i.e., the
+number of elements in the queue.
+.Pp
+The
+.Fn sched:::off-cpu
+probe is triggered by the scheduler suspending execution of the
+currently-running thread, and the
+.Fn sched:::on-cpu
+probe fires when the current thread has been selected to run on a CPU and is
+about to begin or resume execution.
+The arguments to
+.Fn sched:::off-cpu
+are the thread and corresponding process selected to run following the
+currently-running thread.
+If these two threads are the same, the
+.Fn sched:::remain-cpu
+probe will fire instead.
+.Pp
+The
+.Fn sched:::surrender
+probe fires when the scheduler is called upon to make a scheduling decision by
+a thread running on a different CPU, via an interprocessor interrupt.
+The arguments to this probe are the interrupted thread and its corresponding
+process.
+This probe currently always fires in the context of the interrupted thread.
+.Pp
+The
+.Fn sched:::preempt
+probe will fire immediately before the currently-running thread is preempted.
+When this occurs, the scheduler will select a new thread to run, and one of the
+.Fn sched:::off-cpu
+or
+.Fn sched:::remain-cpu
+probes will subsequently fire, depending on whether or not the scheduler selects
+the preempted thread.
+.Pp
+The
+.Fn sched:::sleep
+probe fires immediately before the currently-running thread is about to suspend
+execution and begin waiting for a condition to be met.
+The
+.Fn sched:::wakeup
+probe fires when a thread is set up to resume execution after having gone to
+sleep.
+Its arguments are the thread being awoken, and the corresponding process.
+.Pp
+The
+.Fn sched:::tick
+fires before each scheduler clock tick.
+Its arguments are the currently-running thread and its corresponding process.
+.Sh ARGUMENTS
+The
+.Nm sched
+provider probes use the kernel types
+.Vt "struct proc"
+and
+.Vt "struct thread"
+to represent processes and threads, respectively.
+These structures have many fields and are defined in
+.Pa sys/proc.h .
+In a probe body, the currently-running thread can always be obtained with the
+.Va curthread
+global variable, which has type
+.Vt "struct thread *" .
+For example, when a running thread is about to sleep, the
+.Fn sched:::sleep
+probe fires in the context of that thread, which can be accessed using
+.Va curthread .
+The
+.Va curcpu
+global variable contains the cpuid of the CPU on which the currently-running
+thread is executing.
+.Sh EXAMPLES
+The following script gives a breakdown of CPU utilization by process name:
+.Bd -literal -offset indent
+sched:::on-cpu
+{
+ self->ts = timestamp;
+}
+
+sched:::off-cpu
+/self->ts != 0/
+{
+ @[execname] = sum((timestamp - self->ts) / 1000);
+ self->ts = 0;
+}
+.Ed
+.Pp
+Here, DTrace stores a timestamp each time a thread is scheduled to run, and
+computes the time elapsed in microseconds when it is descheduled.
+The results are summed by process name.
+.Sh COMPATIBILITY
+This provider is not compatible with the
+.Nm sched
+provider found in Solaris.
+In particular, the probe argument types are native
+.Fx
+types, and the
+.Fn sched:::cpucaps-sleep ,
+.Fn sched:::cpucaps-wakeup ,
+.Fn sched:::schedctl-nopreempt ,
+.Fn sched:::schedctl-preempt ,
+and
+.Fn sched:::schedctl-yield
+probes are not available in
+.Fx .
+.Pp
+The
+.Fn sched:::lend-pri
+and
+.Fn sched:::load-change
+probes are specific to
+.Fx .
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr sched_4bsd 4 ,
+.Xr sched_ule 4 ,
+.Xr SDT 9 ,
+.Xr sleepqueue 9
+.Sh HISTORY
+The
+.Nm sched
+provider first appeared in
+.Fx
+8.4 and 9.1.
+.Sh AUTHORS
+This manual page was written by
+.An Mark Johnston Aq Mt markj@FreeBSD.org .
diff --git a/share/man/man4/dtrace-tcp.4 b/share/man/man4/dtrace-tcp.4
new file mode 100644
index 0000000..3c1ffa2
--- /dev/null
+++ b/share/man/man4/dtrace-tcp.4
@@ -0,0 +1,400 @@
+.\" Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 18, 2015
+.Dt DTRACE-TCP 4
+.Os
+.Sh NAME
+.Nm dtrace-tcp
+.Nd a DTrace provider for tracing events related to the
+.Xr tcp 4
+protocol
+.Sh SYNOPSIS
+.Fn tcp:::accept-established "pktinfo_t *" "csinfo_t *" "ipinfo_t *" \
+ "tcpsinfo_t *" "tcpinfo_t *"
+.Fn tcp:::accept-refused "pktinfo_t *" "csinfo_t *" "ipinfo_t *" \
+ "tcpsinfo_t *" "tcpinfo_t *"
+.Fn tcp:::connect-established "pktinfo_t *" "csinfo_t *" "ipinfo_t *" \
+ "tcpsinfo_t *" "tcpinfo_t *"
+.Fn tcp:::connect-refused "pktinfo_t *" "csinfo_t *" "ipinfo_t *" \
+ "tcpsinfo_t *" "tcpinfo_t *"
+.Fn tcp:::connect-request "pktinfo_t *" "csinfo_t *" "ipinfo_t *" \
+ "tcpsinfo_t *" "tcpinfo_t *"
+.Fn tcp:::receive "pktinfo_t *" "csinfo_t *" "ipinfo_t *" "tcpsinfo_t *" \
+ "tcpinfo_t *"
+.Fn tcp:::send "pktinfo_t *" "csinfo_t *" "ipinfo_t *" "tcpsinfo_t *" \
+ "tcpinfo_t *"
+.Fn tcp:::state-change "void *" "csinfo_t *" "void *" "tcpsinfo_t *" "void *" \
+ "tcplsinfo_t *"
+.Sh DESCRIPTION
+The DTrace
+.Nm tcp
+provider allows users to trace events in the
+.Xr tcp 4
+protocol implementation.
+This provider is similar to the
+.Xr dtrace-ip 4
+and
+.Xr dtrace-udp 4
+providers, but additionally contains probes corresponding to protocol events at
+a level higher than packet reception and transmission.
+All
+.Nm tcp
+probes except for
+.Fn tcp:::state-change
+have the same number and type of arguments.
+The last three arguments are used to describe a TCP segment: the
+.Vt ipinfo_t
+argument exposes the version-agnostic fields of the IP header, while the
+.Vt tcpinfo_t
+argument exposes the TCP header, and the
+.Vt tcpsinfo_t
+argument describes details of the corresponding TCP connection state, if any.
+Their fields are described in the ARGUMENTS section.
+.Pp
+The
+.Fn tcp:::accept-established
+probe fires when a remotely-initiated active TCP open succeeds.
+At this point the new connection is in the ESTABLISHED state, and the probe
+arguments expose the headers associated with the final ACK of the three-way
+handshake.
+The
+.Fn tcp:::accept-refused
+probe fires when a SYN arrives on a port without a listening socket.
+The probe arguments expose the headers associated with the RST to be transmitted
+to the remote host in response to the SYN segment.
+.Pp
+The
+.Fn tcp:::connect-established ,
+.Fn tcp:::connect-refused ,
+and
+.Fn tcp:::connect-request
+probes are similar to the
+.Ql accept
+probes, except that they correspond to locally-initiated TCP connections.
+The
+.Fn tcp:::connect-established
+probe fires when the SYN-ACK segment of a three-way handshake is received from
+the remote host and a final ACK is prepared for transmission.
+This occurs immediately after the local connection state transitions from
+SYN-SENT to ESTABLISHED.
+The probe arguments describe the headers associated with the received SYN-ACK
+segment.
+The
+.Fn tcp:::connect-refused
+probe fires when the local host receives a RST segment in response to a SYN
+segment, indicating that the remote host refused to open a connection.
+The probe arguments describe the IP and TCP headers associated with the received
+RST segment.
+The
+.Fn tcp:::connect-request
+probe fires as the kernel prepares to transmit the initial SYN segment of a
+three-way handshake.
+.Pp
+The
+.Fn tcp:::send
+and
+.Fn tcp:::receive
+probes fire when the host sends or receives a TCP packet, respectively.
+As with the
+.Xr dtrace-udp 4
+provider,
+.Nm tcp
+probes fire only for packets sent by or to the local host; forwarded packets are
+handled in the IP layer and are only visible to the
+.Xr dtrace-ip 4
+provider.
+.Pp
+The
+.Fn tcp:::state-change
+probe fires upon local TCP connection state transitions.
+Its first, third and fifth arguments are currently always
+.Dv NULL .
+Its last argument describes the from-state in the transition, and the to-state
+can be obtained from
+.Dv args[2]->tcps_state .
+.Sh ARGUMENTS
+The
+.Vt pktinfo_t
+argument is currently unimplemented and is included for compatibility with other
+implementations of this provider.
+Its fields are:
+.Bl -tag -width "uinptr_t pkt_addr" -offset indent
+.It Vt uinptr_t pkt_addr
+Always set to 0.
+.El
+.Pp
+The
+.Vt csinfo_t
+argument is currently unimplemented and is included for compatibility with other
+implementations of this provider.
+Its fields are:
+.Bl -tag -width "uintptr_t cs_addr" -offset indent
+.It Vt uintptr_t cs_addr
+Always set to 0.
+.It Vt uint64_t cs_cid
+A pointer to the
+.Vt struct inpcb
+for this packet, or
+.Dv NULL .
+.It Vt pid_t cs_pid
+Always set to 0.
+.El
+.Pp
+The
+.Vt ipinfo_t
+type is a version-agnostic representation of fields from an IP header.
+Its fields are described in the
+.Xr dtrace-ip 4
+manual page.
+.Pp
+The
+.Vt tcpsinfo_t
+type is used to provide a stable representation of TCP connection state.
+Some
+.Nm tcp
+probes, such as
+.Fn tcp:::accept-refused ,
+fire in a context where there is no TCP connection; this argument is
+.Dv NULL
+in that case.
+Its fields are:
+.Bl -tag -width "uint16_t tcps_lport" -offset indent
+.It Vt uintptr_t tcps_addr
+The address of the corresponding TCP control block.
+This is currently a pointer to a
+.Vt struct tcpcb .
+.It Vt int tcps_local
+A boolean indicating whether the connection is local to the host.
+Currently unimplemented and always set to -1.
+.It Vt int tcps_active
+A boolean indicating whether the connection was initiated by the local host.
+Currently unimplemented and always set to -1.
+.It Vt uint16_t tcps_lport
+Local TCP port.
+.It Vt uint16_t tcps_rport
+Remote TCP port.
+.It Vt string tcps_laddr
+Local address.
+.It Vt string tcps_raddr
+Remote address.
+.It Vt int32_t tcps_state
+Current TCP state.
+The valid TCP state values are given by the constants prefixed with
+.Ql TCPS_
+in
+.Pa /usr/lib/dtrace/tcp.d .
+.It Vt uint32_t tcps_iss
+Initial send sequence number.
+.It Vt uint32_t tcps_suna
+Initial sequence number of sent but unacknowledged data.
+.It Vt uint32_t tcps_snxt
+Next sequence number for send.
+.It Vt uint32_t tcps_rack
+Sequence number of received and acknowledged data.
+.It Vt uint32_t tcps_rnxt
+Next expected sequence number for receive.
+.It Vt uint32_t tcps_swnd
+TCP send window size.
+.It Vt int32_t tcps_snd_ws
+Window scaling factor for the TCP send window.
+.It Vt uint32_t tcps_rwnd
+TCP receive window size.
+.It Vt int32_t tcps_rcv_ws
+Window scaling factor for the TCP receive window.
+.It Vt uint32_t tcps_cwnd
+TCP congestion window size.
+.It Vt uint32_t tcps_cwnd_ssthresh
+Congestion window threshold at which slow start ends and congestion avoidance
+begins.
+.It Vt uint32_t tcps_sack_fack
+Last sequence number selectively acknowledged by the receiver.
+.It Vt uint32_t tcps_sack_snxt
+Next selectively acknowledge sequence number at which to begin retransmitting.
+.It Vt uint32_t tcps_rto
+Round-trip timeout, in milliseconds.
+.It Vt uint32_t tcps_mss
+Maximum segment size.
+.It Vt int tcps_retransmit
+A boolean indicating that the local sender is retransmitting data.
+.It Vt int tcps_srtt
+Smoothed round-trip time.
+.El
+.Pp
+The
+.Vt tcpinfo_t
+type exposes the fields in a TCP segment header in host order.
+Its fields are:
+.Bl -tag -width "struct tcphdr *tcp_hdr" -offset indent
+.It Vt uint16_t tcp_sport
+Source TCP port.
+.It Vt uint16_t tcp_dport
+Destination TCP port.
+.It Vt uint32_t tcp_seq
+Sequence number.
+.It Vt uint32_t tcp_ack
+Acknowledgement number.
+.It Vt uint8_t tcp_offset
+Data offset, in bytes.
+.It Vt uint8_t tcp_flags
+TCP flags.
+.It Vt uint16_t tcp_window
+TCP window size.
+.It Vt uint16_t tcp_checksum
+Checksum.
+.It Vt uint16_t tcp_urgent
+Urgent data pointer.
+.It Vt struct tcphdr *tcp_hdr
+A pointer to the raw TCP header.
+.El
+.Pp
+The
+.Vt tcplsinfo_t
+type is used by the
+.Fn tcp:::state-change
+probe to provide the from-state of a transition.
+Its fields are:
+.Bl -tag -width "int32_t tcps_state" -offset indent
+.It Vt int32_t tcps_state
+A TCP state.
+The valid TCP state values are given by the constants prefixed with
+.Ql TCPS_
+in
+.Pa /usr/lib/dtrace/tcp.d .
+.El
+.Sh FILES
+.Bl -tag -width "/usr/lib/dtrace/tcp.d" -compact
+.It Pa /usr/lib/dtrace/tcp.d
+DTrace type and translator definitions for the
+.Nm tcp
+provider.
+.El
+.Sh EXAMPLES
+The following script logs TCP segments in real time:
+.Bd -literal -offset indent
+#pragma D option quiet
+#pragma D option switchrate=10hz
+
+dtrace:::BEGIN
+{
+ printf(" %3s %15s:%-5s %15s:%-5s %6s %s\n", "CPU",
+ "LADDR", "LPORT", "RADDR", "RPORT", "BYTES", "FLAGS");
+}
+
+tcp:::send
+{
+ this->length = args[2]->ip_plength - args[4]->tcp_offset;
+ printf(" %3d %16s:%-5d -> %16s:%-5d %6d (", cpu, args[2]->ip_saddr,
+ args[4]->tcp_sport, args[2]->ip_daddr, args[4]->tcp_dport,
+ this->length);
+ printf("%s", args[4]->tcp_flags & TH_FIN ? "FIN|" : "");
+ printf("%s", args[4]->tcp_flags & TH_SYN ? "SYN|" : "");
+ printf("%s", args[4]->tcp_flags & TH_RST ? "RST|" : "");
+ printf("%s", args[4]->tcp_flags & TH_PUSH ? "PUSH|" : "");
+ printf("%s", args[4]->tcp_flags & TH_ACK ? "ACK|" : "");
+ printf("%s", args[4]->tcp_flags & TH_URG ? "URG|" : "");
+ printf("%s", args[4]->tcp_flags == 0 ? "null " : "");
+ printf("\b)\n");
+}
+
+tcp:::receive
+{
+ this->length = args[2]->ip_plength - args[4]->tcp_offset;
+ printf(" %3d %16s:%-5d <- %16s:%-5d %6d (", cpu,
+ args[2]->ip_daddr, args[4]->tcp_dport, args[2]->ip_saddr,
+ args[4]->tcp_sport, this->length);
+ printf("%s", args[4]->tcp_flags & TH_FIN ? "FIN|" : "");
+ printf("%s", args[4]->tcp_flags & TH_SYN ? "SYN|" : "");
+ printf("%s", args[4]->tcp_flags & TH_RST ? "RST|" : "");
+ printf("%s", args[4]->tcp_flags & TH_PUSH ? "PUSH|" : "");
+ printf("%s", args[4]->tcp_flags & TH_ACK ? "ACK|" : "");
+ printf("%s", args[4]->tcp_flags & TH_URG ? "URG|" : "");
+ printf("%s", args[4]->tcp_flags == 0 ? "null " : "");
+ printf("\b)\n");
+}
+.Ed
+The following script logs TCP connection state changes as they occur:
+.Bd -literal -offset indent
+#pragma D option quiet
+#pragma D option switchrate=25hz
+
+int last[int];
+
+dtrace:::BEGIN
+{
+ printf(" %12s %-20s %-20s %s\n",
+ "DELTA(us)", "OLD", "NEW", "TIMESTAMP");
+}
+
+tcp:::state-change
+{
+ this->elapsed = (timestamp - last[args[1]->cs_cid]) / 1000;
+ printf(" %12d %-20s -> %-20s %d\n", this->elapsed,
+ tcp_state_string[args[5]->tcps_state],
+ tcp_state_string[args[3]->tcps_state], timestamp);
+ last[args[1]->cs_cid] = timestamp;
+}
+
+tcp:::state-change
+/last[args[1]->cs_cid] == 0/
+{
+ printf(" %12s %-20s -> %-20s %d\n", "-",
+ tcp_state_string[args[5]->tcps_state],
+ tcp_state_string[args[3]->tcps_state], timestamp);
+ last[args[1]->cs_cid] = timestamp;
+}
+.Ed
+.Sh COMPATIBILITY
+This provider is compatible with the
+.Nm tcp
+provider in Solaris.
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr dtrace-ip 4 ,
+.Xr dtrace-udp 4 ,
+.Xr tcp 4 ,
+.Xr SDT 9
+.Sh HISTORY
+The
+.Nm tcp
+provider first appeared in
+.Fx
+10.0.
+.Sh AUTHORS
+This manual page was written by
+.An Mark Johnston Aq Mt markj@FreeBSD.org .
+.Sh BUGS
+The
+.Fn tcp:::state-change
+probe does not fire upon transitions to the TIME-WAIT state.
+.Pp
+The
+.Vt tcps_local
+and
+.Vt tcps_active
+fields of
+.Vt tcpsinfo_t
+are not filled in by the translator.
diff --git a/share/man/man4/dtrace-udp.4 b/share/man/man4/dtrace-udp.4
new file mode 100644
index 0000000..7ebc906
--- /dev/null
+++ b/share/man/man4/dtrace-udp.4
@@ -0,0 +1,199 @@
+.\" Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 18, 2015
+.Dt DTRACE-UDP 4
+.Os
+.Sh NAME
+.Nm dtrace-udp
+.Nd a DTrace provider for tracing events related to the UDP protocol
+.Sh SYNOPSIS
+.Fn udp:::receive "pktinfo_t *" "csinfo_t *" "ipinfo_t *" "udpsinfo_t *" \
+ "udpinfo_t *"
+.Fn udp:::send "pktinfo_t *" "csinfo_t *" "ipinfo_t *" "udpsinfo_t *" \
+ "udpinfo_t *"
+.Sh DESCRIPTION
+The DTrace
+.Nm udp
+provider allows users to trace events in the
+.Xr udp 4
+protocol implementation.
+The
+.Fn udp:::send
+probe fires whenever the kernel prepares to transmit a UDP packet, and the
+.Fn udp:::receive
+probe fires whenever the kernel receives a UDP packet.
+The arguments to these probes can be used to obtain detailed information about
+the IP and UDP headers of the corresponding packet.
+.Sh ARGUMENTS
+The
+.Vt pktinfo_t
+argument is currently unimplemented and is included for compatibility with other
+implementations of this provider.
+Its fields are:
+.Bl -tag -width "uintptr_t pkt_addr" -offset indent
+.It Vt uintptr_t pkt_addr
+Always set to 0.
+.El
+.Pp
+The
+.Vt csinfo_t
+argument is currently unimplemented and is included for compatibility with other
+implementations of this provider.
+Its fields are:
+.Bl -tag -width "uintptr_t cs_addr" -offset indent
+.It Vt uintptr_t cs_addr
+Always set to 0.
+.It Vt uint64_t cs_cid
+A pointer to the
+.Vt struct inpcb
+for this packet, or
+.Dv NULL .
+.It Vt pid_t cs_pid
+Always set to 0.
+.El
+.Pp
+The
+.Vt ipinfo_t
+argument contains IP fields common to both IPv4 and IPv6 packets.
+Its fields are:
+.Bl -tag -width "uint32_t ip_plength" -offset indent
+.It Vt uint8_t ip_ver
+IP version of the packet, 4 for IPv4 packets and 6 for IPv6 packets.
+.It Vt uint32_t ip_plength
+IP payload size.
+This does not include the size of the IP header or IPv6 option headers.
+.It Vt string ip_saddr
+IP source address.
+.It Vt string ip_daddr
+IP destination address.
+.El
+.Pp
+The
+.Vt udpsinfo_t
+argument contains the state of the UDP connection associated with the packet.
+Its fields are:
+.Bl -tag -width "uintptr_t udps_addr" -offset indent
+.It Vt uintptr_t udps_addr
+Pointer to the
+.Vt struct inpcb
+containing the IP state for the associated socket.
+.It Vt uint16_t udps_lport
+Local UDP port.
+.It Vt uint16_t udps_rport
+Remote UDP port.
+.It Vt string udps_laddr
+Local IPv4 or IPv6 address.
+.It Vt string udps_raddr
+Remote IPv4 or IPv6 address.
+.El
+.Pp
+The
+.Vt udpinfo_t
+argument is the raw UDP header of the packet, with all fields in host order.
+Its fields are:
+.Bl -tag -width "struct udphdr *udp_hdr" -offset indent
+.It Vt uint16_t udp_sport
+Source UDP port.
+.It Vt uint16_t udp_dport
+Destination UDP port.
+.It Vt uint16_t udp_length
+Length of the UDP header and payload, in bytes.
+.It Vt uint16_t udp_checksum
+A checksum of the UDP header and payload, or 0 if no checksum was calculated.
+.It Vt struct udphdr *udp_hdr
+A pointer to the raw UDP header.
+.El
+.Sh FILES
+.Bl -tag -width "/usr/lib/dtrace/udp.d" -compact
+.It Pa /usr/lib/dtrace/udp.d
+DTrace type and translator definitions for the
+.Nm udp
+provider.
+.El
+.Sh EXAMPLES
+The following script counts transmitted packets by destination port.
+.Bd -literal -offset indent
+udp:::send
+{
+ @num[args[4]->udp_dport] = count();
+}
+.Ed
+.Pp
+This script will print some details of each UDP packet as it is sent or received
+by the kernel:
+.Bd -literal -offset indent
+#pragma D option quiet
+#pragma D option switchrate=10Hz
+
+dtrace:::BEGIN
+{
+ printf(" %10s %36s %-36s %6s\n", "DELTA(us)", "SOURCE",
+ "DEST", "BYTES");
+ last = timestamp;
+}
+
+udp:::send
+{
+ this->elapsed = (timestamp - last) / 1000;
+ self->dest = strjoin(strjoin(args[2]->ip_daddr, ":"),
+ lltostr(args[4]->udp_dport));
+ printf(" %10d %30s:%-5d -> %-36s %6d\n", this->elapsed,
+ args[2]->ip_saddr, args[4]->udp_sport,
+ self->dest, args[4]->udp_length);
+ last = timestamp;
+}
+
+udp:::receive
+{
+ this->elapsed = (timestamp - last) / 1000;
+ self->dest = strjoin(strjoin(args[2]->ip_saddr, ":"),
+ lltostr(args[4]->udp_sport));
+ printf(" %10d %30s:%-5d <- %-36s %6d\n", this->elapsed,
+ args[2]->ip_daddr, args[4]->udp_dport,
+ self->dest, args[4]->udp_length);
+ last = timestamp;
+}
+.Ed
+.Sh COMPATIBILITY
+This provider is compatible with the
+.Nm udp
+provider in Solaris.
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr dtrace-ip 4 ,
+.Xr dtrace-tcp 4 ,
+.Xr udp 4 ,
+.Xr SDT 9
+.Sh HISTORY
+The
+.Nm udp
+provider first appeared in
+.Fx
+10.0.
+.Sh AUTHORS
+This manual page was written by
+.An Mark Johnston Aq Mt markj@FreeBSD.org .
diff --git a/share/man/man4/inet.4 b/share/man/man4/inet.4
index 60a382c..a1d0a1c 100644
--- a/share/man/man4/inet.4
+++ b/share/man/man4/inet.4
@@ -28,7 +28,7 @@
.\" From: @(#)inet.4 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd April 3, 2015
+.Dd April 7, 2015
.Dt INET 4
.Os
.Sh NAME
@@ -244,19 +244,7 @@ IP datagrams (or all IP datagrams, if
.Va ip.rfc6864
is disabled) to be randomized instead of incremented by 1 with each packet
generated.
-This prevents information exchange between any combination of two or
-more inside and/or outside observers using packet frequency
-modulation, PFM.
-An outside observer can ping the outside facing port at a fixed rate
-sampling the returned counter.
-An inside observer can ping the inside facing port sampling the same
-counter.
-Even though packets don't flow directly between any of the observers
-any single observer can influence the data rate the other observer(s)
-is or are sampling.
-This is done by sending more or less ping packets towards the gateway
-per measured interval.
-Setting this sysctl also prevents the remote and internal observers to
+This closes a minor information leak which allows remote observers to
determine the rate of packet generation on the machine by watching the
counter.
At the same time, on high-speed links, it can decrease the ID reuse
diff --git a/share/man/man4/run.4 b/share/man/man4/run.4
index 8a2b6bc..7d97f1c 100644
--- a/share/man/man4/run.4
+++ b/share/man/man4/run.4
@@ -16,7 +16,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 3, 2014
+.Dd April 19, 2015
.Dt RUN 4
.Os
.Sh NAME
@@ -133,6 +133,7 @@ driver supports the following wireless adapters:
.It Belkin F6D4050 ver 1
.It Belkin F9L1103
.It Buffalo WLI-UC-AG300N
+.It Buffalo WLI-UC-G300HP
.It Buffalo WLI-UC-G300N
.It Buffalo WLI-UC-G301N
.It Buffalo WLI-UC-GN
diff --git a/share/man/man4/smb.4 b/share/man/man4/smb.4
index afe4605..de053f4 100644
--- a/share/man/man4/smb.4
+++ b/share/man/man4/smb.4
@@ -1,5 +1,6 @@
.\" Copyright (c) 1998, Nicolas Souchu
.\" Copyright (c) 2004, Joerg Wunsch
+.\" Copyright (c) 2015, Michael Gmelin <freebsd@grem.de>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -25,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 6, 2009
+.Dd April 25, 2015
.Dt SMB 4
.Os
.Sh NAME
@@ -36,10 +37,10 @@
.Sh DESCRIPTION
The
.Em smb
-character device driver provides generic i/o to any
+character device driver provides generic I/O to any
.Xr smbus 4
instance.
-In order to control SMB devices, use
+To control SMB devices, use
.Pa /dev/smb?
with the ioctls described below.
Any of these ioctl commands takes a pointer to
@@ -49,124 +50,145 @@ as its argument.
#include <sys/types.h>
struct smbcmd {
- char cmd;
- int count;
- u_char slave;
+ u_char cmd;
+ u_char reserved;
+ u_short op;
union {
- char byte;
- short word;
-
- char *byte_ptr;
- short *word_ptr;
-
- struct {
- short sdata;
- short *rdata;
- } process;
- } data;
+ char byte;
+ char buf[2];
+ short word;
+ } wdata;
+ union {
+ char byte;
+ char buf[2];
+ short word;
+ } rdata;
+ int slave;
+ char *wbuf; /* use wdata if NULL */
+ int wcount;
+ char *rbuf; /* use rdata if NULL */
+ int rcount;
};
.Ed
.Pp
The
.Fa slave
field is always used, and provides the address of the
-SMBus slave device to talk to.
+SMBus slave device.
The slave address is specified in the seven most significant bits
-.Pq i.e. Dq "left-justified" .
+.Pq i.e., Dq "left-justified" .
The least significant bit of the slave address must be zero.
.Pp
.Bl -column ".Dv SMB_QUICK_WRITE" -compact
.It Em Ioctl Ta Em Description
.Pp
.It Dv SMB_QUICK_WRITE Ta
-The
.Em QuickWrite
-command just issues the device address with write intent
-to the bus, without transferring any data.
+does not transfer any data.
+It just issues the device address with write intent to the bus.
.It Dv SMB_QUICK_READ Ta
-The
.Em QuickRead
-command just issues the device address with read intent
-to the bus, without transferring any data.
+does not transfer any data.
+It just issues the device address with read intent to the bus.
.It Dv SMB_SENDB Ta
-The
.Em SendByte
-command sends the byte provided in the
+sends the byte provided in
.Fa cmd
-field to the device.
+to the device.
.It Dv SMB_RECVB Ta
-The
.Em ReceiveByte
-command reads a single byte from the device which will
-be returned in the
-.Fa cmd
-field.
+reads a single byte from the device which is returned in
+.Fa cmd .
.It Dv SMB_WRITEB Ta
-The
.Em WriteByte
-command first sends the byte from the
+first sends the byte from
.Fa cmd
-field to the device, followed by the byte given in
-.Fa data.byte .
+to the device, followed by the byte given in
+.Fa wdata.byte .
.It Dv SMB_WRITEW Ta
-The
.Em WriteWord
-command first sends the byte from the
+first sends the byte from
.Fa cmd
-field to the device, followed by the word given in
-.Fa data.word .
+to the device, followed by the word given in
+.Fa wdata.word .
Note that the SMBus byte-order is little-endian by definition.
.It Dv SMB_READB Ta
-The
.Em ReadByte
-command first sends the byte from the
+first sends the byte from
.Fa cmd
-field to the device, and then reads one byte of data from
+to the device, then reads one byte of data from
the device.
-The returned data will be stored in the location pointed to by
-.Fa data.byte_ptr .
+Returned data is stored in
+.Fa rdata.byte .
.It Dv SMB_READW Ta
-The
.Em ReadWord
-command first sends the byte from the
+first sends the byte from
.Fa cmd
-field to the device, and then reads one word of data from
+to the device, then reads one word of data from
the device.
-The returned data will be stored in the location pointed to by
-.Fa data.word_ptr .
+Returned data is stored in
+.Fa rdata.word .
.It Dv SMB_PCALL Ta
-The
.Em ProcedureCall
-command first sends the byte from the
+first sends the byte from
.Fa cmd
-field to the device, followed by the word provided in
-.Fa data.process.sdata .
-It then reads one word of data from the device, and returns it
-in the location pointed to by
-.Fa data.process.rdata .
+to the device, followed by the word provided in
+.Fa wdata.word .
+It then reads one word of data from the device and returns it
+in
+.Fa rdata.word .
.It Dv SMB_BWRITE Ta
-The
.Em BlockWrite
-command first sends the byte from the
+first sends the byte from
.Fa cmd
-field to the device, followed by
-.Fa count
+to the device, followed by
+.Fa wcount
bytes of data that are taken from the buffer pointed to by
-.Fa data.byte_ptr .
+.Fa wbuf .
The SMBus specification mandates that no more than 32 bytes of
-data can be transferred in a single block read or write command.
-This value is available in the constant
+data can be transferred in a single block read or write command,
+but since
+.Xr smbus 4
+is also used to access I2C devices, the limit has been increased
+to 1024.
+This value can be read from the constant
.Dv SMB_MAXBLOCKSIZE .
.It Dv SMB_BREAD Ta
-The
.Em BlockRead
-command first sends the byte from the
+first sends the byte from
.Fa cmd
-field to the device, and then reads
-.Fa count
+to the device, then reads
+.Fa rcount
bytes of data that from the device.
-These data will be returned in the buffer pointed to by
-.Fa data.byte_ptr .
+This data is returned in the buffer pointed to by
+.Fa rbuf .
+.It Dv SMB_TRANS Ta
+.Em Trans
+sends an SMB roll-up transaction with flags that also allow it to
+be used for (mostly) I2C pass-through and with 10-bit addresses.
+This function can be utilized to roll up all of the above functions.
+It first sends the byte from
+.Fa cmd
+to the device, followed by
+.Fa wcount
+bytes of data that are taken from the buffer pointed to by
+.Fa wbuf ,
+then reads
+.Fa rcount
+bytes of data that from the device.
+This data is returned in the buffer pointed to by
+.Fa rbuf .
+.Pp
+The following flags are allowed in
+.Fa op :
+.Pp
+.Bd -literal -compact
+SMB_TRANS_NOSTOP Do not send STOP at end
+SMB_TRANS_NOCMD Ignore cmd field (do not tx)
+SMB_TRANS_NOCNT Do not tx or rx count field
+SMB_TRANS_7BIT Change address mode to 7-bit
+SMB_TRANS_10BIT Change address mode to 10-bit
+.Ed
.El
.Pp
The
@@ -201,4 +223,6 @@ manual page first appeared in
.Sh AUTHORS
This
manual page was written by
-.An Nicolas Souchu .
+.An Nicolas Souchu
+and extended by
+.An Michael Gmelin Aq freebsd@grem.de .
diff --git a/share/man/man4/tap.4 b/share/man/man4/tap.4
index 6e42996..a95627b 100644
--- a/share/man/man4/tap.4
+++ b/share/man/man4/tap.4
@@ -1,7 +1,7 @@
.\" $FreeBSD$
.\" Based on PR#2411
.\"
-.Dd November 30, 2014
+.Dd April 10, 2015
.Dt TAP 4
.Os
.Sh NAME
@@ -275,7 +275,9 @@ brought down
.Dq ifconfig tap Ns Sy N No down )
unless the device is a
.Em VMnet
-device.
+device, or has
+.Dv IFF_LINK0
+flag set.
All queued frames are thrown away.
If the interface is up when the data
device is not open, output frames are thrown away rather than
diff --git a/share/man/man4/urtwn.4 b/share/man/man4/urtwn.4
index 35463f4..5a58200 100644
--- a/share/man/man4/urtwn.4
+++ b/share/man/man4/urtwn.4
@@ -52,7 +52,7 @@ The
driver supports USB 2.0 wireless network devices based on Realtek
RTL8188CUS, RTL8188CE-VAU, RTL8188EUS, RTL8188RU and RTL8192CU chipsets.
.Pp
-The RTL8188CUS and RTL8188EUS are highly integrated 802.11n adapter that
+The RTL8188CUS and RTL8188EUS are highly integrated 802.11n adapters that
combine a MAC, a 1T1R capable baseband and an RF in a single chip.
They operate in the 2GHz spectrum only.
The RTL8188RU is a high-power variant of the RTL8188CUS.
diff --git a/share/man/man4/xen.4 b/share/man/man4/xen.4
index 83b3d12..c2b1f5b 100644
--- a/share/man/man4/xen.4
+++ b/share/man/man4/xen.4
@@ -28,24 +28,16 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 17, 2010
+.Dd April 30, 2015
.Dt XEN 4
.Os
.Sh NAME
.Nm xen
.Nd Xen Hypervisor Guest (DomU) Support
.Sh SYNOPSIS
-To compile para-virtualized (PV) Xen guest support into an i386 kernel, place
-the following lines in your kernel configuration file:
-.Bd -ragged -offset indent
-.Cd "options PAE"
-.Cd "options XEN"
-.Cd "nooptions NATIVE"
-.Ed
-.Pp
To compile hardware-assisted virtualization (HVM) Xen guest support with
-para-virtualized drivers into an amd64 kernel, place the following lines in
-your kernel configuration file:
+para-virtualized drivers into an amd64 or i386 kernel,
+place the following lines in your kernel configuration file:
.Bd -ragged -offset indent
.Cd "options XENHVM"
.Cd "device xenpci"
@@ -69,34 +61,14 @@ and hence able to optimize certain behaviors to improve performance or
semantics.
.Pp
.Fx
-supports a fully para-virtualized (PV) kernel on the i386 architecture using
-.Cd "options XEN"
-and
-.Cd "nooptions NATIVE" ;
-currently, this requires use of a PAE kernel, enabled via
-.Cd "options PAE" .
-.Pp
-.Fx
-supports hardware-assisted virtualization (HVM) on both the i386 and amd64
-kernels; however, PV device drivers with an HVM kernel are only supported on
-the amd64 architecture, and require
-.Cd "options XENHVM"
-and
-.Cd "device xenpci" .
+supports hardware-assisted virtualization (HVM) on both i386 and amd64
+kernels.
.Pp
Para-virtualized device drivers are required in order to support certain
functionality, such as processing management requests, returning idle
physical memory pages to the hypervisor, etc.
.Ss Xen DomU device drivers
-Xen para-virtualized drivers are automatically added to the kernel if a PV
-kernel is compiled using
-.Cd "options XEN" ;
-for HVM environments,
-.Cd "options XENHVM"
-and
-.Cd "device xenpci"
-are required.
-The follow drivers are supported:
+These para-virtualized drivers are supported:
.Bl -hang -offset indent -width blkfront
.It Nm balloon
Allow physical memory pages to be returned to the hypervisor as a result of
@@ -148,8 +120,6 @@ It is recommended that adaptive locking be disabled when using Xen:
.Cd "options NO_ADAPTIVE_RWLOCKS"
.Cd "options NO_ADAPTIVE_SX"
.Ed
-.Sh SEE ALSO
-.Xr pae 4
.Sh HISTORY
Support for
.Nm
@@ -173,12 +143,6 @@ This manual page was written by
.Fx
is only able to run as a Xen guest (DomU) and not as a Xen host (Dom0).
.Pp
-A fully para-virtualized (PV) kernel is only supported on i386, and not
-amd64.
-.Pp
-Para-virtualized drivers under hardware-assisted virtualization (HVM) kernel
-are only supported on amd64, not i386.
-.Pp
As of this release, Xen PV DomU support is not heavily tested; instability
has been reported during VM migration of PV kernels.
.Pp
diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5
index 2eccd7e..c263111 100644
--- a/share/man/man5/rc.conf.5
+++ b/share/man/man5/rc.conf.5
@@ -2294,14 +2294,6 @@ is set to
these are the flags to pass to the
.Xr nfscbd 8
daemon.
-.It Va oldnfs_server_enable
-.Pq Vt bool
-If
-.Va oldnfs_server_enable
-is set to
-.Dq Li YES ,
-force the NFS server daemons to run the old NFS server code
-that does not support NFSv4.
.It Va mountd_enable
.Pq Vt bool
If set to
diff --git a/share/man/man5/src.conf.5 b/share/man/man5/src.conf.5
index 0d1014c..13e8655 100644
--- a/share/man/man5/src.conf.5
+++ b/share/man/man5/src.conf.5
@@ -1,7 +1,7 @@
.\" DO NOT EDIT-- this file is automatically generated.
.\" from FreeBSD: head/tools/build/options/makeman 255964 2013-10-01 07:22:04Z des
.\" $FreeBSD$
-.Dd February 4, 2015
+.Dd April 19, 2015
.Dt SRC.CONF 5
.Os
.Sh NAME
@@ -359,9 +359,9 @@ and related utilities.
.\" from FreeBSD: head/tools/build/options/WITHOUT_CUSE 270171 2014-08-19 15:40:26Z hselasky
Set to not build CUSE-related programs and libraries.
.It Va WITHOUT_CXX
-.\" from FreeBSD: head/tools/build/options/WITHOUT_CXX 220402 2011-04-06 20:19:07Z uqs
+.\" from FreeBSD: head/tools/build/options/WITHOUT_CXX 281053 2015-04-03 23:55:04Z bdrewery
Set to not build
-.Xr g++ 1
+.Xr c++ 1
and related libraries.
It will also prevent building of
.Xr gperf 1
@@ -1100,9 +1100,6 @@ and related programs.
.It Va WITHOUT_SYMVER
.\" from FreeBSD: head/tools/build/options/WITHOUT_SYMVER 169649 2007-05-17 05:03:24Z deischen
Set to disable symbol versioning when building shared libraries.
-.It Va WITHOUT_SYSCALL_COMPAT
-.\" from FreeBSD: head/tools/build/options/WITHOUT_SYSCALL_COMPAT 265826 2014-05-10 16:37:28Z imp
-Do not include some compatible syscall wrappers in libc.
.It Va WITHOUT_SYSCONS
.\" from FreeBSD: head/tools/build/options/WITHOUT_SYSCONS 156932 2006-03-21 07:50:50Z ru
Set to not build
diff --git a/share/man/man9/BUS_BIND_INTR.9 b/share/man/man9/BUS_BIND_INTR.9
index 1c97897..162a8b5 100644
--- a/share/man/man9/BUS_BIND_INTR.9
+++ b/share/man/man9/BUS_BIND_INTR.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/BUS_CHILD_DELETED.9 b/share/man/man9/BUS_CHILD_DELETED.9
index 4caa856..4ab46be 100644
--- a/share/man/man9/BUS_CHILD_DELETED.9
+++ b/share/man/man9/BUS_CHILD_DELETED.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2012 Advanced Computing Technologies LLC
+.\" Copyright (c) 2012 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/BUS_CHILD_DETACHED.9 b/share/man/man9/BUS_CHILD_DETACHED.9
index 4e032d1..b79b9c4 100644
--- a/share/man/man9/BUS_CHILD_DETACHED.9
+++ b/share/man/man9/BUS_CHILD_DETACHED.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2012 Advanced Computing Technologies LLC
+.\" Copyright (c) 2012 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/BUS_DESCRIBE_INTR.9 b/share/man/man9/BUS_DESCRIBE_INTR.9
index 1000455..c340bb2 100644
--- a/share/man/man9/BUS_DESCRIBE_INTR.9
+++ b/share/man/man9/BUS_DESCRIBE_INTR.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/BUS_NEW_PASS.9 b/share/man/man9/BUS_NEW_PASS.9
index 4861ffd..1da2f67 100644
--- a/share/man/man9/BUS_NEW_PASS.9
+++ b/share/man/man9/BUS_NEW_PASS.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index d8fd585..7f79156 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1135,6 +1135,7 @@ MLINKS+=osd.9 osd_call.9 \
osd.9 osd_get.9 \
osd.9 osd_register.9 \
osd.9 osd_set.9
+MLINKS+=panic.9 vpanic.9
MLINKS+=pbuf.9 getpbuf.9 \
pbuf.9 relpbuf.9 \
pbuf.9 trypbuf.9
diff --git a/share/man/man9/SDT.9 b/share/man/man9/SDT.9
index 9016b42..2765c4c 100644
--- a/share/man/man9/SDT.9
+++ b/share/man/man9/SDT.9
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2013 Mark Johnston <markj@freebsd.org>
+.\" Copyright (c) 2013-2015 Mark Johnston <markj@freebsd.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 8, 2015
+.Dd April 18, 2015
.Dt SDT 9
.Os
.Sh NAME
@@ -194,7 +194,37 @@ macros are used to create
trace points.
They are meant to be added to executable code and can be used to instrument the
code in which they are called.
+.Sh PROVIDERS
+A number of kernel DTrace providers are available.
+In general, these providers define stable interfaces and should be treated as
+such: existing D scripts may be broken if a probe is renamed or its arguments
+are modified.
+However, it is often useful to define ad-hoc
+.Nm
+probes for debugging a subsystem or driver.
+Similarly, a developer may wish to provide a group of
+.Nm
+probes without committing to their future stability.
+Such probes should be added to the
+.Ql sdt
+provider instead of defining a new provider.
.Sh EXAMPLES
+The DTrace providers available on the current system can be listed with
+.Bd -literal -offset indent
+dtrace -l | sed 1d | awk '{print $2}' | sort -u
+.Ed
+.Pp
+A detailed list of the probes offered by a given provider can be obtained by
+specifying the provider using the
+.Fl P
+flag.
+For example, to view the probes and argument types for the
+.Ql sched
+provider, run
+.Bd -literal -offset indent
+dtrace -lv -P sched
+.Ed
+.Pp
The following probe definition will create a DTrace probe called
.Ql icmp:::receive-unreachable ,
which would hypothetically be triggered when the kernel receives an ICMP packet
@@ -274,7 +304,13 @@ SDT_PROBE_DEFINE1_XLATE(ip, , , receive, "struct icmp *",
"struct icmp_hdr_dt *");
.Ed
.Sh SEE ALSO
-.Xr dtrace 1
+.Xr dtrace 1 ,
+.Xr dtrace-io 4 ,
+.Xr dtrace-ip 4 ,
+.Xr dtrace-proc 4 ,
+.Xr dtrace-sched 4 ,
+.Xr dtrace-tcp 4 ,
+.Xr dtrace-udp 4
.Sh AUTHORS
.An -nosplit
DTrace and the
diff --git a/share/man/man9/VOP_ADVISE.9 b/share/man/man9/VOP_ADVISE.9
index 250be52..50cd860 100644
--- a/share/man/man9/VOP_ADVISE.9
+++ b/share/man/man9/VOP_ADVISE.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2013 Advanced Computing Technologies LLC
+.\" Copyright (c) 2013 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/VOP_ALLOCATE.9 b/share/man/man9/VOP_ALLOCATE.9
index 314410d..6f1f54c 100644
--- a/share/man/man9/VOP_ALLOCATE.9
+++ b/share/man/man9/VOP_ALLOCATE.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2013 Advanced Computing Technologies LLC
+.\" Copyright (c) 2013 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/bus_adjust_resource.9 b/share/man/man9/bus_adjust_resource.9
index be4adae..b7c477a 100644
--- a/share/man/man9/bus_adjust_resource.9
+++ b/share/man/man9/bus_adjust_resource.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2011 Advanced Computing Technologies LLC
+.\" Copyright (c) 2011 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/bus_generic_new_pass.9 b/share/man/man9/bus_generic_new_pass.9
index de64220..b0b79b6 100644
--- a/share/man/man9/bus_generic_new_pass.9
+++ b/share/man/man9/bus_generic_new_pass.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/bus_set_pass.9 b/share/man/man9/bus_set_pass.9
index a28d833..f59d03b 100644
--- a/share/man/man9/bus_set_pass.9
+++ b/share/man/man9/bus_set_pass.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/getenv.9 b/share/man/man9/getenv.9
index a20c5e8..a530ca4 100644
--- a/share/man/man9/getenv.9
+++ b/share/man/man9/getenv.9
@@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
-.\" Copyright (c) 2013 Advanced Computing Technologies LLC
+.\" Copyright (c) 2013 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/panic.9 b/share/man/man9/panic.9
index 44439dd..c467b86 100644
--- a/share/man/man9/panic.9
+++ b/share/man/man9/panic.9
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 11, 1995
+.Dd April 23, 2015
.Dt PANIC 9
.Os
.Sh NAME
@@ -42,10 +42,14 @@
.In sys/systm.h
.Ft void
.Fn panic "const char *fmt" ...
+.Ft void
+.Fn vpanic "const char *fmt" "va_list ap"
.Sh DESCRIPTION
The
.Fn panic
-function terminates the running system.
+and
+.Fn vpanic
+functions terminate the running system.
The message
.Fa fmt
is a
diff --git a/share/man/man9/printf.9 b/share/man/man9/printf.9
index 84ac822..505ea9b 100644
--- a/share/man/man9/printf.9
+++ b/share/man/man9/printf.9
@@ -67,7 +67,8 @@ The
.Fn log
function sends the message to the kernel logging facility, using
the log level as indicated by
-.Fa pri .
+.Fa pri ,
+and to the console if no process is yet reading the log.
.Pp
Each of these related functions use the
.Fa fmt
diff --git a/share/man/man9/refcount.9 b/share/man/man9/refcount.9
index b3c8d7f..b435bab 100644
--- a/share/man/man9/refcount.9
+++ b/share/man/man9/refcount.9
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/sglist.9 b/share/man/man9/sglist.9
index 280a993..a9b34de 100644
--- a/share/man/man9/sglist.9
+++ b/share/man/man9/sglist.9
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/man/man9/shm_map.9 b/share/man/man9/shm_map.9
index 4ba8222..e2b57d5 100644
--- a/share/man/man9/shm_map.9
+++ b/share/man/man9/shm_map.9
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 2011 Advanced Computing Technologies LLC
+.\" Copyright (c) 2011 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/share/misc/committers-src.dot b/share/misc/committers-src.dot
index 98ea817..9af30b7 100644
--- a/share/misc/committers-src.dot
+++ b/share/misc/committers-src.dot
@@ -240,6 +240,7 @@ np [label="Navdeep Parhar\nnp@FreeBSD.org\n2009/06/05"]
nwhitehorn [label="Nathan Whitehorn\nnwhitehorn@FreeBSD.org\n2008/07/03"]
obrien [label="David E. O'Brien\nobrien@FreeBSD.org\n1996/10/29"]
olli [label="Oliver Fromme\nolli@FreeBSD.org\n2008/02/14"]
+oshogbo [label="Mariusz Zaborski\noshogbo@FreeBSD.org\n2015/04/15"]
peadar [label="Peter Edwards\npeadar@FreeBSD.org\n2004/03/08"]
peter [label="Peter Wemm\npeter@FreeBSD.org\n1995/07/04"]
peterj [label="Peter Jeremy\npeterj@FreeBSD.org\n2012/09/14"]
@@ -633,6 +634,7 @@ phk -> mux
pjd -> kib
pjd -> lulf
+pjd -> oshogbo
pjd -> smh
pjd -> trociny
diff --git a/share/mk/bsd.dep.mk b/share/mk/bsd.dep.mk
index 407158c..233a945 100644
--- a/share/mk/bsd.dep.mk
+++ b/share/mk/bsd.dep.mk
@@ -128,18 +128,18 @@ CFLAGS+= -I${.OBJDIR}
.for _D in ${_DSRC:R}
DHDRS+= ${_D}.h
${_D}.h: ${_DSRC}
- ${DTRACE} -xnolibs -h -s ${.ALLSRC}
+ ${DTRACE} ${DTRACEFLAGS} -h -s ${.ALLSRC}
SRCS:= ${SRCS:S/^${_DSRC}$//}
OBJS+= ${_D}.o
CLEANFILES+= ${_D}.h ${_D}.o
${_D}.o: ${_DSRC} ${OBJS:S/^${_D}.o$//}
- ${DTRACE} -xnolibs -G -o ${.TARGET} -s ${.ALLSRC}
+ ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC}
.if defined(LIB)
CLEANFILES+= ${_D}.So ${_D}.po
${_D}.So: ${_DSRC} ${SOBJS:S/^${_D}.So$//}
- ${DTRACE} -xnolibs -G -o ${.TARGET} -s ${.ALLSRC}
+ ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC}
${_D}.po: ${_DSRC} ${POBJS:S/^${_D}.po$//}
- ${DTRACE} -xnolibs -G -o ${.TARGET} -s ${.ALLSRC}
+ ${DTRACE} ${DTRACEFLAGS} -G -o ${.TARGET} -s ${.ALLSRC}
.endif
.endfor
.endfor
diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk
index 75c90a0..512ad2f 100644
--- a/share/mk/src.libnames.mk
+++ b/share/mk/src.libnames.mk
@@ -111,6 +111,7 @@ _LIBRARIES= \
md \
memstat \
mp \
+ mt \
nandfs \
ncurses \
ncursesw \
@@ -199,6 +200,7 @@ _DP_proc+= ctf
_DP_mp= crypto
_DP_memstat= kvm
_DP_magic= z
+_DP_mt= bsdxml
_DP_ldns= crypto
.if ${MK_OPENSSL} != "no"
_DP_fetch= ssl crypto
@@ -227,6 +229,7 @@ _DP_krb5+= asn1 com_err crypt crypto hx509 roken wind heimbase heimipcc \
_DP_gssapi_krb5+= gssapi krb5 crypto roken asn1 com_err
_DP_lzma= pthread
_DP_ucl= m
+_DP_vmmapi= util
# Define spacial cases
LDADD_supcplusplus= -lsupc++
@@ -256,9 +259,15 @@ LDADD_sqlite3+= ${LDADD_pthread}
DPADD_atf_cxx+= ${DPADD_atf_c}
LDADD_atf_cxx+= ${LDADD_atf_c}
+DPADD_fifolog+= ${DPADD_z}
+LDADD_fifolog+= ${LDADD_z}
+
DPADD_ipf+= ${DPADD_kvm}
LDADD_ipf+= ${LDADD_kvm}
+DPADD_mt+= ${DPADD_sbuf}
+LDADD_mt+= ${LDADD_sbuf}
+
# The following depends on libraries which are using pthread
DPADD_hdb+= ${DPADD_pthread}
LDADD_hdb+= ${LDADD_pthread}
@@ -273,10 +282,14 @@ LDADD_gssapi_krb5+= ${LDADD_pthread}
.if ${_PRIVATELIBS:M${_l}}
USEPRIVATELIB+= ${_l}
.endif
-DPADD+= ${DPADD_${_l}}
+DPADD+= ${DPADD_${_l}:Umissing-dpadd_${_l}}
LDADD+= ${LDADD_${_l}}
.endfor
+.if defined(DPADD) && ${DPADD:Mmissing-dpadd_*}
+.error Missing ${DPADD:Mmissing-dpadd_*:S/missing-dpadd_//:S/^/DPADD_/} variable add "${DPADD:Mmissing-dpadd_*:S/missing-dpadd_//}" to _LIBRARIES, _INTERNALLIBS, or _PRIVATELIBS and define "${DPADD:Mmissing-dpadd_*:S/missing-dpadd_//:S/^/LIB/:tu}".
+.endif
+
.if defined(USEPRIVATELIB)
LDFLAGS+= -rpath ${LIBPRIVATEDIR}
.endif
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index b6ea715..6e18874 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -154,7 +154,6 @@ __DEFAULT_YES_OPTIONS = \
SOURCELESS_HOST \
SOURCELESS_UCODE \
SVNLITE \
- SYSCALL_COMPAT \
SYSCONS \
SYSINSTALL \
TALK \
@@ -234,7 +233,11 @@ __DEFAULT_YES_OPTIONS+=GCC GCC_BOOTSTRAP GNUCXX
__DEFAULT_NO_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC
.endif
.if ${__T} == "aarch64"
-BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GDB
+BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GCC GCC_BOOTSTRAP GDB
+.endif
+# LLVM lacks support for FreeBSD 64-bit atomic operations for ARMv4/ARMv5
+.if ${__T} == "arm" || ${__T} == "armeb"
+BROKEN_OPTIONS+=LLDB
.endif
.include <bsd.mkopt.mk>
diff --git a/share/mk/sys.mk b/share/mk/sys.mk
index 05f5b19..62ede89 100644
--- a/share/mk/sys.mk
+++ b/share/mk/sys.mk
@@ -62,17 +62,18 @@ CFLAGS += -fno-strict-aliasing
.endif
PO_CFLAGS ?= ${CFLAGS}
+# cp(1) is used to copy source files to ${.OBJDIR}, make sure it can handle
+# read-only files as non-root by passing -f.
+CP ?= cp -f
+
+CPP ?= cpp
+
# C Type Format data is required for DTrace
CTFFLAGS ?= -L VERSION
CTFCONVERT ?= ctfconvert
CTFMERGE ?= ctfmerge
-# cp(1) is used to copy source files to ${.OBJDIR}, make sure it can handle
-# read-only files as non-root by passing -f.
-CP ?= cp -f
-
-DTRACE ?= dtrace
.if defined(CFLAGS) && (${CFLAGS:M-g} != "")
CTFFLAGS += -g
.endif
@@ -81,7 +82,8 @@ CXX ?= c++
CXXFLAGS ?= ${CFLAGS:N-std=*:N-Wnested-externs:N-W*-prototypes:N-Wno-pointer-sign:N-Wold-style-definition}
PO_CXXFLAGS ?= ${CXXFLAGS}
-CPP ?= cpp
+DTRACE ?= dtrace
+DTRACEFLAGS ?= -C -x nolibs
.if empty(.MAKEFLAGS:M-s)
ECHO ?= echo
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index c3aac33..4455cab 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -174,6 +174,22 @@ IDTVEC(xen_intr_upcall)
jmp doreti
#endif
+#ifdef HYPERV
+/*
+ * This is the Hyper-V vmbus channel direct callback interrupt.
+ * Only used when it is running on Hyper-V.
+ */
+ .text
+ SUPERALIGN_TEXT
+IDTVEC(hv_vmbus_callback)
+ PUSH_FRAME
+ FAKE_MCOUNT(TF_RIP(%rsp))
+ movq %rsp, %rdi
+ call hv_vector_handler
+ MEXITCOUNT
+ jmp doreti
+#endif
+
#ifdef SMP
/*
* Global address space TLB shootdown.
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index e38482c..3230937 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -578,384 +578,6 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
}
#endif
-
-/*
- * Machine dependent boot() routine
- *
- * I haven't seen anything to put here yet
- * Possibly some stuff might be grafted back here from boot()
- */
-void
-cpu_boot(int howto)
-{
-}
-
-/*
- * Flush the D-cache for non-DMA I/O so that the I-cache can
- * be made coherent later.
- */
-void
-cpu_flush_dcache(void *ptr, size_t len)
-{
- /* Not applicable */
-}
-
-/* Get current clock frequency for the given cpu id. */
-int
-cpu_est_clockrate(int cpu_id, uint64_t *rate)
-{
- uint64_t tsc1, tsc2;
- uint64_t acnt, mcnt, perf;
- register_t reg;
-
- if (pcpu_find(cpu_id) == NULL || rate == NULL)
- return (EINVAL);
-
- /*
- * If TSC is P-state invariant and APERF/MPERF MSRs do not exist,
- * DELAY(9) based logic fails.
- */
- if (tsc_is_invariant && !tsc_perf_stat)
- return (EOPNOTSUPP);
-
-#ifdef SMP
- if (smp_cpus > 1) {
- /* Schedule ourselves on the indicated cpu. */
- thread_lock(curthread);
- sched_bind(curthread, cpu_id);
- thread_unlock(curthread);
- }
-#endif
-
- /* Calibrate by measuring a short delay. */
- reg = intr_disable();
- if (tsc_is_invariant) {
- wrmsr(MSR_MPERF, 0);
- wrmsr(MSR_APERF, 0);
- tsc1 = rdtsc();
- DELAY(1000);
- mcnt = rdmsr(MSR_MPERF);
- acnt = rdmsr(MSR_APERF);
- tsc2 = rdtsc();
- intr_restore(reg);
- perf = 1000 * acnt / mcnt;
- *rate = (tsc2 - tsc1) * perf;
- } else {
- tsc1 = rdtsc();
- DELAY(1000);
- tsc2 = rdtsc();
- intr_restore(reg);
- *rate = (tsc2 - tsc1) * 1000;
- }
-
-#ifdef SMP
- if (smp_cpus > 1) {
- thread_lock(curthread);
- sched_unbind(curthread);
- thread_unlock(curthread);
- }
-#endif
-
- return (0);
-}
-
-/*
- * Shutdown the CPU as much as possible
- */
-void
-cpu_halt(void)
-{
- for (;;)
- halt();
-}
-
-void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */
-static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */
-static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */
-SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RWTUN, &idle_mwait,
- 0, "Use MONITOR/MWAIT for short idle");
-
-#define STATE_RUNNING 0x0
-#define STATE_MWAIT 0x1
-#define STATE_SLEEPING 0x2
-
-static void
-cpu_idle_acpi(sbintime_t sbt)
-{
- int *state;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_SLEEPING;
-
- /* See comments in cpu_idle_hlt(). */
- disable_intr();
- if (sched_runnable())
- enable_intr();
- else if (cpu_idle_hook)
- cpu_idle_hook(sbt);
- else
- __asm __volatile("sti; hlt");
- *state = STATE_RUNNING;
-}
-
-static void
-cpu_idle_hlt(sbintime_t sbt)
-{
- int *state;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_SLEEPING;
-
- /*
- * Since we may be in a critical section from cpu_idle(), if
- * an interrupt fires during that critical section we may have
- * a pending preemption. If the CPU halts, then that thread
- * may not execute until a later interrupt awakens the CPU.
- * To handle this race, check for a runnable thread after
- * disabling interrupts and immediately return if one is
- * found. Also, we must absolutely guarentee that hlt is
- * the next instruction after sti. This ensures that any
- * interrupt that fires after the call to disable_intr() will
- * immediately awaken the CPU from hlt. Finally, please note
- * that on x86 this works fine because of interrupts enabled only
- * after the instruction following sti takes place, while IF is set
- * to 1 immediately, allowing hlt instruction to acknowledge the
- * interrupt.
- */
- disable_intr();
- if (sched_runnable())
- enable_intr();
- else
- __asm __volatile("sti; hlt");
- *state = STATE_RUNNING;
-}
-
-/*
- * MWAIT cpu power states. Lower 4 bits are sub-states.
- */
-#define MWAIT_C0 0xf0
-#define MWAIT_C1 0x00
-#define MWAIT_C2 0x10
-#define MWAIT_C3 0x20
-#define MWAIT_C4 0x30
-
-static void
-cpu_idle_mwait(sbintime_t sbt)
-{
- int *state;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_MWAIT;
-
- /* See comments in cpu_idle_hlt(). */
- disable_intr();
- if (sched_runnable()) {
- enable_intr();
- *state = STATE_RUNNING;
- return;
- }
- cpu_monitor(state, 0, 0);
- if (*state == STATE_MWAIT)
- __asm __volatile("sti; mwait" : : "a" (MWAIT_C1), "c" (0));
- else
- enable_intr();
- *state = STATE_RUNNING;
-}
-
-static void
-cpu_idle_spin(sbintime_t sbt)
-{
- int *state;
- int i;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_RUNNING;
-
- /*
- * The sched_runnable() call is racy but as long as there is
- * a loop missing it one time will have just a little impact if any
- * (and it is much better than missing the check at all).
- */
- for (i = 0; i < 1000; i++) {
- if (sched_runnable())
- return;
- cpu_spinwait();
- }
-}
-
-/*
- * C1E renders the local APIC timer dead, so we disable it by
- * reading the Interrupt Pending Message register and clearing
- * both C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
- *
- * Reference:
- * "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors"
- * #32559 revision 3.00+
- */
-#define MSR_AMDK8_IPM 0xc0010055
-#define AMDK8_SMIONCMPHALT (1ULL << 27)
-#define AMDK8_C1EONCMPHALT (1ULL << 28)
-#define AMDK8_CMPHALT (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT)
-
-static void
-cpu_probe_amdc1e(void)
-{
-
- /*
- * Detect the presence of C1E capability mostly on latest
- * dual-cores (or future) k8 family.
- */
- if (cpu_vendor_id == CPU_VENDOR_AMD &&
- (cpu_id & 0x00000f00) == 0x00000f00 &&
- (cpu_id & 0x0fff0000) >= 0x00040000) {
- cpu_ident_amdc1e = 1;
- }
-}
-
-void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi;
-
-void
-cpu_idle(int busy)
-{
- uint64_t msr;
- sbintime_t sbt = -1;
-
- CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
- busy, curcpu);
-#ifdef MP_WATCHDOG
- ap_watchdog(PCPU_GET(cpuid));
-#endif
- /* If we are busy - try to use fast methods. */
- if (busy) {
- if ((cpu_feature2 & CPUID2_MON) && idle_mwait) {
- cpu_idle_mwait(busy);
- goto out;
- }
- }
-
- /* If we have time - switch timers into idle mode. */
- if (!busy) {
- critical_enter();
- sbt = cpu_idleclock();
- }
-
- /* Apply AMD APIC timer C1E workaround. */
- if (cpu_ident_amdc1e && cpu_disable_c3_sleep) {
- msr = rdmsr(MSR_AMDK8_IPM);
- if (msr & AMDK8_CMPHALT)
- wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT);
- }
-
- /* Call main idle method. */
- cpu_idle_fn(sbt);
-
- /* Switch timers back into active mode. */
- if (!busy) {
- cpu_activeclock();
- critical_exit();
- }
-out:
- CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
- busy, curcpu);
-}
-
-int
-cpu_idle_wakeup(int cpu)
-{
- struct pcpu *pcpu;
- int *state;
-
- pcpu = pcpu_find(cpu);
- state = (int *)pcpu->pc_monitorbuf;
- /*
- * This doesn't need to be atomic since missing the race will
- * simply result in unnecessary IPIs.
- */
- if (*state == STATE_SLEEPING)
- return (0);
- if (*state == STATE_MWAIT)
- *state = STATE_RUNNING;
- return (1);
-}
-
-/*
- * Ordered by speed/power consumption.
- */
-struct {
- void *id_fn;
- char *id_name;
-} idle_tbl[] = {
- { cpu_idle_spin, "spin" },
- { cpu_idle_mwait, "mwait" },
- { cpu_idle_hlt, "hlt" },
- { cpu_idle_acpi, "acpi" },
- { NULL, NULL }
-};
-
-static int
-idle_sysctl_available(SYSCTL_HANDLER_ARGS)
-{
- char *avail, *p;
- int error;
- int i;
-
- avail = malloc(256, M_TEMP, M_WAITOK);
- p = avail;
- for (i = 0; idle_tbl[i].id_name != NULL; i++) {
- if (strstr(idle_tbl[i].id_name, "mwait") &&
- (cpu_feature2 & CPUID2_MON) == 0)
- continue;
- if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
- cpu_idle_hook == NULL)
- continue;
- p += sprintf(p, "%s%s", p != avail ? ", " : "",
- idle_tbl[i].id_name);
- }
- error = sysctl_handle_string(oidp, avail, 0, req);
- free(avail, M_TEMP);
- return (error);
-}
-
-SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD,
- 0, 0, idle_sysctl_available, "A", "list of available idle functions");
-
-static int
-idle_sysctl(SYSCTL_HANDLER_ARGS)
-{
- char buf[16];
- int error;
- char *p;
- int i;
-
- p = "unknown";
- for (i = 0; idle_tbl[i].id_name != NULL; i++) {
- if (idle_tbl[i].id_fn == cpu_idle_fn) {
- p = idle_tbl[i].id_name;
- break;
- }
- }
- strncpy(buf, p, sizeof(buf));
- error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
- if (error != 0 || req->newptr == NULL)
- return (error);
- for (i = 0; idle_tbl[i].id_name != NULL; i++) {
- if (strstr(idle_tbl[i].id_name, "mwait") &&
- (cpu_feature2 & CPUID2_MON) == 0)
- continue;
- if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
- cpu_idle_hook == NULL)
- continue;
- if (strcmp(idle_tbl[i].id_name, buf))
- continue;
- cpu_idle_fn = idle_tbl[i].id_fn;
- return (0);
- }
- return (EINVAL);
-}
-
-SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
- idle_sysctl, "A", "currently selected idle function");
-
/*
* Reset registers to default values on exec.
*/
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index c81495a..83ca548 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -81,28 +81,11 @@ __FBSDID("$FreeBSD$");
#define BIOS_RESET (0x0f)
#define BIOS_WARM (0x0a)
-/* lock region used by kernel profiling */
-int mcount_lock;
-
-int mp_naps; /* # of Applications processors */
-int boot_cpu_id = -1; /* designated BSP */
-
-extern struct pcpu __pcpu[];
-
-/* AP uses this during bootstrap. Do not staticize. */
-char *bootSTK;
-int bootAP;
-
-/* Free these after use */
-void *bootstacks[MAXCPU];
+extern struct pcpu __pcpu[];
/* Temporary variables for init_secondary() */
char *doublefault_stack;
char *nmi_stack;
-void *dpcpu;
-
-struct pcb stoppcbs[MAXCPU];
-struct susppcb **susppcbs;
/* Variables needed for SMP tlb shootdown. */
vm_offset_t smp_tlb_addr2;
@@ -112,309 +95,16 @@ uint64_t pcid_cr3;
pmap_t smp_tlb_pmap;
extern int invpcid_works;
-#ifdef COUNT_IPIS
-/* Interrupt counts. */
-static u_long *ipi_preempt_counts[MAXCPU];
-static u_long *ipi_ast_counts[MAXCPU];
-u_long *ipi_invltlb_counts[MAXCPU];
-u_long *ipi_invlrng_counts[MAXCPU];
-u_long *ipi_invlpg_counts[MAXCPU];
-u_long *ipi_invlcache_counts[MAXCPU];
-u_long *ipi_rendezvous_counts[MAXCPU];
-static u_long *ipi_hardclock_counts[MAXCPU];
-#endif
-
-/* Default cpu_ops implementation. */
-struct cpu_ops cpu_ops;
-
extern inthand_t IDTVEC(fast_syscall), IDTVEC(fast_syscall32);
-extern int pmap_pcid_enabled;
-
/*
* Local data and functions.
*/
-static volatile cpuset_t ipi_nmi_pending;
-
-/* used to hold the AP's until we are ready to release them */
-struct mtx ap_boot_mtx;
-
-/* Set to 1 once we're ready to let the APs out of the pen. */
-static volatile int aps_ready = 0;
-
-/*
- * Store data from cpu_add() until later in the boot when we actually setup
- * the APs.
- */
-struct cpu_info {
- int cpu_present:1;
- int cpu_bsp:1;
- int cpu_disabled:1;
- int cpu_hyperthread:1;
-} static cpu_info[MAX_APIC_ID + 1];
-int cpu_apic_ids[MAXCPU];
-int apic_cpuids[MAX_APIC_ID + 1];
-
-/* Holds pending bitmap based IPIs per CPU */
-volatile u_int cpu_ipi_pending[MAXCPU];
-
-static u_int boot_address;
-static int cpu_logical; /* logical cpus per core */
-static int cpu_cores; /* cores per package */
-
-static void assign_cpu_ids(void);
-static void set_interrupt_apic_ids(void);
static int start_ap(int apic_id);
-static void release_aps(void *dummy);
-static u_int hyperthreading_cpus; /* logical cpus sharing L1 cache */
-static int hyperthreading_allowed = 1;
static u_int bootMP_size;
-
-static void
-mem_range_AP_init(void)
-{
- if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
- mem_range_softc.mr_op->initAP(&mem_range_softc);
-}
-
-static void
-topo_probe_amd(void)
-{
- int core_id_bits;
- int id;
-
- /* AMD processors do not support HTT. */
- cpu_logical = 1;
-
- if ((amd_feature2 & AMDID2_CMP) == 0) {
- cpu_cores = 1;
- return;
- }
-
- core_id_bits = (cpu_procinfo2 & AMDID_COREID_SIZE) >>
- AMDID_COREID_SIZE_SHIFT;
- if (core_id_bits == 0) {
- cpu_cores = (cpu_procinfo2 & AMDID_CMP_CORES) + 1;
- return;
- }
-
- /* Fam 10h and newer should get here. */
- for (id = 0; id <= MAX_APIC_ID; id++) {
- /* Check logical CPU availability. */
- if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
- continue;
- /* Check if logical CPU has the same package ID. */
- if ((id >> core_id_bits) != (boot_cpu_id >> core_id_bits))
- continue;
- cpu_cores++;
- }
-}
-
-/*
- * Round up to the next power of two, if necessary, and then
- * take log2.
- * Returns -1 if argument is zero.
- */
-static __inline int
-mask_width(u_int x)
-{
-
- return (fls(x << (1 - powerof2(x))) - 1);
-}
-
-static void
-topo_probe_0x4(void)
-{
- u_int p[4];
- int pkg_id_bits;
- int core_id_bits;
- int max_cores;
- int max_logical;
- int id;
-
- /* Both zero and one here mean one logical processor per package. */
- max_logical = (cpu_feature & CPUID_HTT) != 0 ?
- (cpu_procinfo & CPUID_HTT_CORES) >> 16 : 1;
- if (max_logical <= 1)
- return;
-
- /*
- * Because of uniformity assumption we examine only
- * those logical processors that belong to the same
- * package as BSP. Further, we count number of
- * logical processors that belong to the same core
- * as BSP thus deducing number of threads per core.
- */
- if (cpu_high >= 0x4) {
- cpuid_count(0x04, 0, p);
- max_cores = ((p[0] >> 26) & 0x3f) + 1;
- } else
- max_cores = 1;
- core_id_bits = mask_width(max_logical/max_cores);
- if (core_id_bits < 0)
- return;
- pkg_id_bits = core_id_bits + mask_width(max_cores);
-
- for (id = 0; id <= MAX_APIC_ID; id++) {
- /* Check logical CPU availability. */
- if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
- continue;
- /* Check if logical CPU has the same package ID. */
- if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits))
- continue;
- cpu_cores++;
- /* Check if logical CPU has the same package and core IDs. */
- if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits))
- cpu_logical++;
- }
-
- KASSERT(cpu_cores >= 1 && cpu_logical >= 1,
- ("topo_probe_0x4 couldn't find BSP"));
-
- cpu_cores /= cpu_logical;
- hyperthreading_cpus = cpu_logical;
-}
-
-static void
-topo_probe_0xb(void)
-{
- u_int p[4];
- int bits;
- int cnt;
- int i;
- int logical;
- int type;
- int x;
-
- /* We only support three levels for now. */
- for (i = 0; i < 3; i++) {
- cpuid_count(0x0b, i, p);
-
- /* Fall back if CPU leaf 11 doesn't really exist. */
- if (i == 0 && p[1] == 0) {
- topo_probe_0x4();
- return;
- }
-
- bits = p[0] & 0x1f;
- logical = p[1] &= 0xffff;
- type = (p[2] >> 8) & 0xff;
- if (type == 0 || logical == 0)
- break;
- /*
- * Because of uniformity assumption we examine only
- * those logical processors that belong to the same
- * package as BSP.
- */
- for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) {
- if (!cpu_info[x].cpu_present ||
- cpu_info[x].cpu_disabled)
- continue;
- if (x >> bits == boot_cpu_id >> bits)
- cnt++;
- }
- if (type == CPUID_TYPE_SMT)
- cpu_logical = cnt;
- else if (type == CPUID_TYPE_CORE)
- cpu_cores = cnt;
- }
- if (cpu_logical == 0)
- cpu_logical = 1;
- cpu_cores /= cpu_logical;
-}
-
-/*
- * Both topology discovery code and code that consumes topology
- * information assume top-down uniformity of the topology.
- * That is, all physical packages must be identical and each
- * core in a package must have the same number of threads.
- * Topology information is queried only on BSP, on which this
- * code runs and for which it can query CPUID information.
- * Then topology is extrapolated on all packages using the
- * uniformity assumption.
- */
-static void
-topo_probe(void)
-{
- static int cpu_topo_probed = 0;
-
- if (cpu_topo_probed)
- return;
-
- CPU_ZERO(&logical_cpus_mask);
- if (mp_ncpus <= 1)
- cpu_cores = cpu_logical = 1;
- else if (cpu_vendor_id == CPU_VENDOR_AMD)
- topo_probe_amd();
- else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
- /*
- * See Intel(R) 64 Architecture Processor
- * Topology Enumeration article for details.
- *
- * Note that 0x1 <= cpu_high < 4 case should be
- * compatible with topo_probe_0x4() logic when
- * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
- * or it should trigger the fallback otherwise.
- */
- if (cpu_high >= 0xb)
- topo_probe_0xb();
- else if (cpu_high >= 0x1)
- topo_probe_0x4();
- }
-
- /*
- * Fallback: assume each logical CPU is in separate
- * physical package. That is, no multi-core, no SMT.
- */
- if (cpu_cores == 0 || cpu_logical == 0)
- cpu_cores = cpu_logical = 1;
- cpu_topo_probed = 1;
-}
-
-struct cpu_group *
-cpu_topo(void)
-{
- int cg_flags;
-
- /*
- * Determine whether any threading flags are
- * necessry.
- */
- topo_probe();
- if (cpu_logical > 1 && hyperthreading_cpus)
- cg_flags = CG_FLAG_HTT;
- else if (cpu_logical > 1)
- cg_flags = CG_FLAG_SMT;
- else
- cg_flags = 0;
- if (mp_ncpus % (cpu_cores * cpu_logical) != 0) {
- printf("WARNING: Non-uniform processors.\n");
- printf("WARNING: Using suboptimal topology.\n");
- return (smp_topo_none());
- }
- /*
- * No multi-core or hyper-threaded.
- */
- if (cpu_logical * cpu_cores == 1)
- return (smp_topo_none());
- /*
- * Only HTT no multi-core.
- */
- if (cpu_logical > 1 && cpu_cores == 1)
- return (smp_topo_1level(CG_SHARE_L1, cpu_logical, cg_flags));
- /*
- * Only multi-core no HTT.
- */
- if (cpu_cores > 1 && cpu_logical == 1)
- return (smp_topo_1level(CG_SHARE_L2, cpu_cores, cg_flags));
- /*
- * Both HTT and multi-core.
- */
- return (smp_topo_2level(CG_SHARE_L2, cpu_cores,
- CG_SHARE_L1, cpu_logical, cg_flags));
-}
+static u_int boot_address;
/*
* Calculate usable address in base memory for AP trampoline code.
@@ -433,85 +123,6 @@ mp_bootaddress(u_int basemem)
return mptramp_pagetables;
}
-void
-cpu_add(u_int apic_id, char boot_cpu)
-{
-
- if (apic_id > MAX_APIC_ID) {
- panic("SMP: APIC ID %d too high", apic_id);
- return;
- }
- KASSERT(cpu_info[apic_id].cpu_present == 0, ("CPU %d added twice",
- apic_id));
- cpu_info[apic_id].cpu_present = 1;
- if (boot_cpu) {
- KASSERT(boot_cpu_id == -1,
- ("CPU %d claims to be BSP, but CPU %d already is", apic_id,
- boot_cpu_id));
- boot_cpu_id = apic_id;
- cpu_info[apic_id].cpu_bsp = 1;
- }
- if (mp_ncpus < MAXCPU) {
- mp_ncpus++;
- mp_maxid = mp_ncpus - 1;
- }
- if (bootverbose)
- printf("SMP: Added CPU %d (%s)\n", apic_id, boot_cpu ? "BSP" :
- "AP");
-}
-
-void
-cpu_mp_setmaxid(void)
-{
-
- /*
- * mp_maxid should be already set by calls to cpu_add().
- * Just sanity check its value here.
- */
- if (mp_ncpus == 0)
- KASSERT(mp_maxid == 0,
- ("%s: mp_ncpus is zero, but mp_maxid is not", __func__));
- else if (mp_ncpus == 1)
- mp_maxid = 0;
- else
- KASSERT(mp_maxid >= mp_ncpus - 1,
- ("%s: counters out of sync: max %d, count %d", __func__,
- mp_maxid, mp_ncpus));
-}
-
-int
-cpu_mp_probe(void)
-{
-
- /*
- * Always record BSP in CPU map so that the mbuf init code works
- * correctly.
- */
- CPU_SETOF(0, &all_cpus);
- if (mp_ncpus == 0) {
- /*
- * No CPUs were found, so this must be a UP system. Setup
- * the variables to represent a system with a single CPU
- * with an id of 0.
- */
- mp_ncpus = 1;
- return (0);
- }
-
- /* At least one CPU was found. */
- if (mp_ncpus == 1) {
- /*
- * One CPU was found, so this must be a UP system with
- * an I/O APIC.
- */
- mp_maxid = 0;
- return (0);
- }
-
- /* At least two CPUs were found. */
- return (1);
-}
-
/*
* Initialize the IPI handlers and start up the AP's.
*/
@@ -575,47 +186,6 @@ cpu_mp_start(void)
/*
- * Print various information about the SMP system hardware and setup.
- */
-void
-cpu_mp_announce(void)
-{
- const char *hyperthread;
- int i;
-
- printf("FreeBSD/SMP: %d package(s) x %d core(s)",
- mp_ncpus / (cpu_cores * cpu_logical), cpu_cores);
- if (hyperthreading_cpus > 1)
- printf(" x %d HTT threads", cpu_logical);
- else if (cpu_logical > 1)
- printf(" x %d SMT threads", cpu_logical);
- printf("\n");
-
- /* List active CPUs first. */
- printf(" cpu0 (BSP): APIC ID: %2d\n", boot_cpu_id);
- for (i = 1; i < mp_ncpus; i++) {
- if (cpu_info[cpu_apic_ids[i]].cpu_hyperthread)
- hyperthread = "/HT";
- else
- hyperthread = "";
- printf(" cpu%d (AP%s): APIC ID: %2d\n", i, hyperthread,
- cpu_apic_ids[i]);
- }
-
- /* List disabled CPUs last. */
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || !cpu_info[i].cpu_disabled)
- continue;
- if (cpu_info[i].cpu_hyperthread)
- hyperthread = "/HT";
- else
- hyperthread = "";
- printf(" cpu (AP%s): APIC ID: %2d (disabled)\n", hyperthread,
- i);
- }
-}
-
-/*
* AP CPU's call this to initialize themselves.
*/
void
@@ -624,7 +194,6 @@ init_secondary(void)
struct pcpu *pc;
struct nmi_pcpu *np;
u_int64_t msr, cr0;
- u_int cpuid;
int cpu, gsel_tss, x;
struct region_descriptor ap_gdt;
@@ -712,94 +281,7 @@ init_secondary(void)
while (!aps_ready)
ia32_pause();
- /*
- * On real hardware, switch to x2apic mode if possible. Do it
- * after aps_ready was signalled, to avoid manipulating the
- * mode while BSP might still want to send some IPI to us
- * (second startup IPI is ignored on modern hardware etc).
- */
- lapic_xapic_mode();
-
- /* Initialize the PAT MSR. */
- pmap_init_pat();
-
- /* set up CPU registers and state */
- cpu_setregs();
-
- /* set up SSE/NX */
- initializecpu();
-
- /* set up FPU state on the AP */
- fpuinit();
-
- if (cpu_ops.cpu_init)
- cpu_ops.cpu_init();
-
- /* A quick check from sanity claus */
- cpuid = PCPU_GET(cpuid);
- if (PCPU_GET(apic_id) != lapic_id()) {
- printf("SMP: cpuid = %d\n", cpuid);
- printf("SMP: actual apic_id = %d\n", lapic_id());
- printf("SMP: correct apic_id = %d\n", PCPU_GET(apic_id));
- panic("cpuid mismatch! boom!!");
- }
-
- /* Initialize curthread. */
- KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
- PCPU_SET(curthread, PCPU_GET(idlethread));
-
- mca_init();
-
- mtx_lock_spin(&ap_boot_mtx);
-
- /* Init local apic for irq's */
- lapic_setup(1);
-
- /* Set memory range attributes for this CPU to match the BSP */
- mem_range_AP_init();
-
- smp_cpus++;
-
- CTR1(KTR_SMP, "SMP: AP CPU #%d Launched", cpuid);
- printf("SMP: AP CPU #%d Launched!\n", cpuid);
-
- /* Determine if we are a logical CPU. */
- /* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */
- if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0)
- CPU_SET(cpuid, &logical_cpus_mask);
-
- if (bootverbose)
- lapic_dump("AP");
-
- if (smp_cpus == mp_ncpus) {
- /* enable IPI's, tlb shootdown, freezes etc */
- atomic_store_rel_int(&smp_started, 1);
- }
-
- /*
- * Enable global pages TLB extension
- * This also implicitly flushes the TLB
- */
-
- load_cr4(rcr4() | CR4_PGE);
- if (pmap_pcid_enabled)
- load_cr4(rcr4() | CR4_PCIDE);
- load_ds(_udatasel);
- load_es(_udatasel);
- load_fs(_ufssel);
- mtx_unlock_spin(&ap_boot_mtx);
-
- /* Wait until all the AP's are up. */
- while (smp_started == 0)
- ia32_pause();
-
- /* Start per-CPU event timers. */
- cpu_initclocks_ap();
-
- sched_throw(NULL);
-
- panic("scheduler returned us to %s", __func__);
- /* NOTREACHED */
+ init_secondary_tail();
}
/*******************************************************************
@@ -807,108 +289,6 @@ init_secondary(void)
*/
/*
- * We tell the I/O APIC code about all the CPUs we want to receive
- * interrupts. If we don't want certain CPUs to receive IRQs we
- * can simply not tell the I/O APIC code about them in this function.
- * We also do not tell it about the BSP since it tells itself about
- * the BSP internally to work with UP kernels and on UP machines.
- */
-static void
-set_interrupt_apic_ids(void)
-{
- u_int i, apic_id;
-
- for (i = 0; i < MAXCPU; i++) {
- apic_id = cpu_apic_ids[i];
- if (apic_id == -1)
- continue;
- if (cpu_info[apic_id].cpu_bsp)
- continue;
- if (cpu_info[apic_id].cpu_disabled)
- continue;
-
- /* Don't let hyperthreads service interrupts. */
- if (cpu_logical > 1 &&
- apic_id % cpu_logical != 0)
- continue;
-
- intr_add_cpu(i);
- }
-}
-
-/*
- * Assign logical CPU IDs to local APICs.
- */
-static void
-assign_cpu_ids(void)
-{
- u_int i;
-
- TUNABLE_INT_FETCH("machdep.hyperthreading_allowed",
- &hyperthreading_allowed);
-
- /* Check for explicitly disabled CPUs. */
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp)
- continue;
-
- if (hyperthreading_cpus > 1 && i % hyperthreading_cpus != 0) {
- cpu_info[i].cpu_hyperthread = 1;
-
- /*
- * Don't use HT CPU if it has been disabled by a
- * tunable.
- */
- if (hyperthreading_allowed == 0) {
- cpu_info[i].cpu_disabled = 1;
- continue;
- }
- }
-
- /* Don't use this CPU if it has been disabled by a tunable. */
- if (resource_disabled("lapic", i)) {
- cpu_info[i].cpu_disabled = 1;
- continue;
- }
- }
-
- if (hyperthreading_allowed == 0 && hyperthreading_cpus > 1) {
- hyperthreading_cpus = 0;
- cpu_logical = 1;
- }
-
- /*
- * Assign CPU IDs to local APIC IDs and disable any CPUs
- * beyond MAXCPU. CPU 0 is always assigned to the BSP.
- *
- * To minimize confusion for userland, we attempt to number
- * CPUs such that all threads and cores in a package are
- * grouped together. For now we assume that the BSP is always
- * the first thread in a package and just start adding APs
- * starting with the BSP's APIC ID.
- */
- mp_ncpus = 1;
- cpu_apic_ids[0] = boot_cpu_id;
- apic_cpuids[boot_cpu_id] = 0;
- for (i = boot_cpu_id + 1; i != boot_cpu_id;
- i == MAX_APIC_ID ? i = 0 : i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp ||
- cpu_info[i].cpu_disabled)
- continue;
-
- if (mp_ncpus < MAXCPU) {
- cpu_apic_ids[mp_ncpus] = i;
- apic_cpuids[i] = mp_ncpus;
- mp_ncpus++;
- } else
- cpu_info[i].cpu_disabled = 1;
- }
- KASSERT(mp_maxid >= mp_ncpus - 1,
- ("%s: counters out of sync: max %d, count %d", __func__, mp_maxid,
- mp_ncpus));
-}
-
-/*
* start each AP in our list
*/
int
@@ -1026,129 +406,6 @@ start_ap(int apic_id)
return 0; /* return FAILURE */
}
-#ifdef COUNT_XINVLTLB_HITS
-u_int xhits_gbl[MAXCPU];
-u_int xhits_pg[MAXCPU];
-u_int xhits_rng[MAXCPU];
-static SYSCTL_NODE(_debug, OID_AUTO, xhits, CTLFLAG_RW, 0, "");
-SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, global, CTLFLAG_RW, &xhits_gbl,
- sizeof(xhits_gbl), "IU", "");
-SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, page, CTLFLAG_RW, &xhits_pg,
- sizeof(xhits_pg), "IU", "");
-SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, range, CTLFLAG_RW, &xhits_rng,
- sizeof(xhits_rng), "IU", "");
-
-u_int ipi_global;
-u_int ipi_page;
-u_int ipi_range;
-u_int ipi_range_size;
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_global, CTLFLAG_RW, &ipi_global, 0, "");
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_page, CTLFLAG_RW, &ipi_page, 0, "");
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_range, CTLFLAG_RW, &ipi_range, 0, "");
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_range_size, CTLFLAG_RW,
- &ipi_range_size, 0, "");
-
-u_int ipi_masked_global;
-u_int ipi_masked_page;
-u_int ipi_masked_range;
-u_int ipi_masked_range_size;
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_masked_global, CTLFLAG_RW,
- &ipi_masked_global, 0, "");
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_masked_page, CTLFLAG_RW,
- &ipi_masked_page, 0, "");
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_masked_range, CTLFLAG_RW,
- &ipi_masked_range, 0, "");
-SYSCTL_UINT(_debug_xhits, OID_AUTO, ipi_masked_range_size, CTLFLAG_RW,
- &ipi_masked_range_size, 0, "");
-#endif /* COUNT_XINVLTLB_HITS */
-
-/*
- * Init and startup IPI.
- */
-void
-ipi_startup(int apic_id, int vector)
-{
-
- /*
- * This attempts to follow the algorithm described in the
- * Intel Multiprocessor Specification v1.4 in section B.4.
- * For each IPI, we allow the local APIC ~20us to deliver the
- * IPI. If that times out, we panic.
- */
-
- /*
- * first we do an INIT IPI: this INIT IPI might be run, resetting
- * and running the target CPU. OR this INIT IPI might be latched (P5
- * bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be
- * ignored.
- */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
- APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
- lapic_ipi_wait(100);
-
- /* Explicitly deassert the INIT IPI. */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT,
- apic_id);
-
- DELAY(10000); /* wait ~10mS */
-
- /*
- * next we do a STARTUP IPI: the previous INIT IPI might still be
- * latched, (P5 bug) this 1st STARTUP would then terminate
- * immediately, and the previously started INIT IPI would continue. OR
- * the previous INIT IPI has already run. and this STARTUP IPI will
- * run. OR the previous INIT IPI was ignored. and this STARTUP IPI
- * will run.
- */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
- vector, apic_id);
- if (!lapic_ipi_wait(100))
- panic("Failed to deliver first STARTUP IPI to APIC %d",
- apic_id);
- DELAY(200); /* wait ~200uS */
-
- /*
- * finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF
- * the previous STARTUP IPI was cancelled by a latched INIT IPI. OR
- * this STARTUP IPI will be ignored, as only ONE STARTUP IPI is
- * recognized after hardware RESET or INIT IPI.
- */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
- vector, apic_id);
- if (!lapic_ipi_wait(100))
- panic("Failed to deliver second STARTUP IPI to APIC %d",
- apic_id);
-
- DELAY(200); /* wait ~200uS */
-}
-
-/*
- * Send an IPI to specified CPU handling the bitmap logic.
- */
-static void
-ipi_send_cpu(int cpu, u_int ipi)
-{
- u_int bitmap, old_pending, new_pending;
-
- KASSERT(cpu_apic_ids[cpu] != -1, ("IPI to non-existent CPU %d", cpu));
-
- if (IPI_IS_BITMAPED(ipi)) {
- bitmap = 1 << ipi;
- ipi = IPI_BITMAP_VECTOR;
- do {
- old_pending = cpu_ipi_pending[cpu];
- new_pending = old_pending | bitmap;
- } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu],
- old_pending, new_pending));
- if (old_pending)
- return;
- }
- lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
-}
-
/*
* Flush the TLB on all other CPU's
*/
@@ -1228,26 +485,6 @@ smp_targeted_tlb_shootdown(cpuset_t mask, u_int vector, pmap_t pmap,
}
void
-smp_cache_flush(void)
-{
-
- if (smp_started)
- smp_tlb_shootdown(IPI_INVLCACHE, NULL, 0, 0);
-}
-
-void
-smp_invltlb(pmap_t pmap)
-{
-
- if (smp_started) {
- smp_tlb_shootdown(IPI_INVLTLB, pmap, 0, 0);
-#ifdef COUNT_XINVLTLB_HITS
- ipi_global++;
-#endif
- }
-}
-
-void
smp_invlpg(pmap_t pmap, vm_offset_t addr)
{
@@ -1312,210 +549,23 @@ smp_masked_invlpg_range(cpuset_t mask, pmap_t pmap, vm_offset_t addr1,
}
void
-ipi_bitmap_handler(struct trapframe frame)
-{
- struct trapframe *oldframe;
- struct thread *td;
- int cpu = PCPU_GET(cpuid);
- u_int ipi_bitmap;
-
- critical_enter();
- td = curthread;
- td->td_intr_nesting_level++;
- oldframe = td->td_intr_frame;
- td->td_intr_frame = &frame;
- ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]);
- if (ipi_bitmap & (1 << IPI_PREEMPT)) {
-#ifdef COUNT_IPIS
- (*ipi_preempt_counts[cpu])++;
-#endif
- sched_preempt(td);
- }
- if (ipi_bitmap & (1 << IPI_AST)) {
-#ifdef COUNT_IPIS
- (*ipi_ast_counts[cpu])++;
-#endif
- /* Nothing to do for AST */
- }
- if (ipi_bitmap & (1 << IPI_HARDCLOCK)) {
-#ifdef COUNT_IPIS
- (*ipi_hardclock_counts[cpu])++;
-#endif
- hardclockintr();
- }
- td->td_intr_frame = oldframe;
- td->td_intr_nesting_level--;
- critical_exit();
-}
-
-/*
- * send an IPI to a set of cpus.
- */
-void
-ipi_selected(cpuset_t cpus, u_int ipi)
-{
- int cpu;
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_OR_ATOMIC(&ipi_nmi_pending, &cpus);
-
- while ((cpu = CPU_FFS(&cpus)) != 0) {
- cpu--;
- CPU_CLR(cpu, &cpus);
- CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
- ipi_send_cpu(cpu, ipi);
- }
-}
-
-/*
- * send an IPI to a specific CPU.
- */
-void
-ipi_cpu(int cpu, u_int ipi)
-{
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_SET_ATOMIC(cpu, &ipi_nmi_pending);
-
- CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
- ipi_send_cpu(cpu, ipi);
-}
-
-/*
- * send an IPI to all CPUs EXCEPT myself
- */
-void
-ipi_all_but_self(u_int ipi)
+smp_cache_flush(void)
{
- cpuset_t other_cpus;
-
- other_cpus = all_cpus;
- CPU_CLR(PCPU_GET(cpuid), &other_cpus);
- if (IPI_IS_BITMAPED(ipi)) {
- ipi_selected(other_cpus, ipi);
- return;
- }
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
-
- CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
- lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
+ if (smp_started)
+ smp_tlb_shootdown(IPI_INVLCACHE, NULL, 0, 0);
}
-int
-ipi_nmi_handler()
-{
- u_int cpuid;
-
- /*
- * As long as there is not a simple way to know about a NMI's
- * source, if the bitmask for the current CPU is present in
- * the global pending bitword an IPI_STOP_HARD has been issued
- * and should be handled.
- */
- cpuid = PCPU_GET(cpuid);
- if (!CPU_ISSET(cpuid, &ipi_nmi_pending))
- return (1);
-
- CPU_CLR_ATOMIC(cpuid, &ipi_nmi_pending);
- cpustop_handler();
- return (0);
-}
-
-/*
- * Handle an IPI_STOP by saving our current context and spinning until we
- * are resumed.
- */
void
-cpustop_handler(void)
-{
- u_int cpu;
-
- cpu = PCPU_GET(cpuid);
-
- savectx(&stoppcbs[cpu]);
-
- /* Indicate that we are stopped */
- CPU_SET_ATOMIC(cpu, &stopped_cpus);
-
- /* Wait for restart */
- while (!CPU_ISSET(cpu, &started_cpus))
- ia32_pause();
-
- CPU_CLR_ATOMIC(cpu, &started_cpus);
- CPU_CLR_ATOMIC(cpu, &stopped_cpus);
+smp_invltlb(pmap_t pmap)
+{
-#ifdef DDB
- amd64_db_resume_dbreg();
+ if (smp_started) {
+ smp_tlb_shootdown(IPI_INVLTLB, pmap, 0, 0);
+#ifdef COUNT_XINVLTLB_HITS
+ ipi_global++;
#endif
-
- if (cpu == 0 && cpustop_restartfunc != NULL) {
- cpustop_restartfunc();
- cpustop_restartfunc = NULL;
- }
-}
-
-/*
- * Handle an IPI_SUSPEND by saving our current context and spinning until we
- * are resumed.
- */
-void
-cpususpend_handler(void)
-{
- u_int cpu;
-
- mtx_assert(&smp_ipi_mtx, MA_NOTOWNED);
-
- cpu = PCPU_GET(cpuid);
- if (savectx(&susppcbs[cpu]->sp_pcb)) {
- fpususpend(susppcbs[cpu]->sp_fpususpend);
- wbinvd();
- CPU_SET_ATOMIC(cpu, &suspended_cpus);
- } else {
- fpuresume(susppcbs[cpu]->sp_fpususpend);
- pmap_init_pat();
- initializecpu();
- PCPU_SET(switchtime, 0);
- PCPU_SET(switchticks, ticks);
-
- /* Indicate that we are resumed */
- CPU_CLR_ATOMIC(cpu, &suspended_cpus);
}
-
- /* Wait for resume */
- while (!CPU_ISSET(cpu, &started_cpus))
- ia32_pause();
-
- if (cpu_ops.cpu_resume)
- cpu_ops.cpu_resume();
- if (vmm_resume_p)
- vmm_resume_p();
-
- /* Resume MCA and local APIC */
- lapic_xapic_mode();
- mca_resume();
- lapic_setup(0);
-
- CPU_CLR_ATOMIC(cpu, &started_cpus);
- /* Indicate that we are resumed */
- CPU_CLR_ATOMIC(cpu, &suspended_cpus);
}
/*
@@ -1678,63 +728,3 @@ invlrng_handler(void)
atomic_add_int(&smp_tlb_wait, 1);
}
-
-void
-invlcache_handler(void)
-{
-#ifdef COUNT_IPIS
- (*ipi_invlcache_counts[PCPU_GET(cpuid)])++;
-#endif /* COUNT_IPIS */
-
- wbinvd();
- atomic_add_int(&smp_tlb_wait, 1);
-}
-
-/*
- * This is called once the rest of the system is up and running and we're
- * ready to let the AP's out of the pen.
- */
-static void
-release_aps(void *dummy __unused)
-{
-
- if (mp_ncpus == 1)
- return;
- atomic_store_rel_int(&aps_ready, 1);
- while (smp_started == 0)
- ia32_pause();
-}
-SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
-
-#ifdef COUNT_IPIS
-/*
- * Setup interrupt counters for IPI handlers.
- */
-static void
-mp_ipi_intrcnt(void *dummy)
-{
- char buf[64];
- int i;
-
- CPU_FOREACH(i) {
- snprintf(buf, sizeof(buf), "cpu%d:invltlb", i);
- intrcnt_add(buf, &ipi_invltlb_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:invlrng", i);
- intrcnt_add(buf, &ipi_invlrng_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:invlpg", i);
- intrcnt_add(buf, &ipi_invlpg_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:invlcache", i);
- intrcnt_add(buf, &ipi_invlcache_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:preempt", i);
- intrcnt_add(buf, &ipi_preempt_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:ast", i);
- intrcnt_add(buf, &ipi_ast_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:rendezvous", i);
- intrcnt_add(buf, &ipi_rendezvous_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:hardclock", i);
- intrcnt_add(buf, &ipi_hardclock_counts[i]);
- }
-}
-SYSINIT(mp_ipi_intrcnt, SI_SUB_INTR, SI_ORDER_MIDDLE, mp_ipi_intrcnt, NULL);
-#endif
-
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 29158e8..dc823fa 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -2532,6 +2532,8 @@ pmap_release(pmap_t pmap)
pmap->pm_stats.resident_count));
KASSERT(vm_radix_is_empty(&pmap->pm_root),
("pmap_release: pmap has reserved page table page(s)"));
+ KASSERT(CPU_EMPTY(&pmap->pm_active),
+ ("releasing active pmap %p", pmap));
if (pmap_pcid_enabled) {
/*
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index bdaca33..c24dd5a 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -340,7 +340,9 @@ device virtio_blk # VirtIO Block device
device virtio_scsi # VirtIO SCSI device
device virtio_balloon # VirtIO Memory Balloon device
-# HyperV drivers
+# HyperV drivers and enchancement support
+# NOTE: HYPERV depends on hyperv. They must be added or removed together.
+options HYPERV # Hyper-V kernel infrastructure
device hyperv # HyperV drivers
# Xen HVM Guest Optimizations
diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES
index 9b697f0..e0fe465 100644
--- a/sys/amd64/conf/NOTES
+++ b/sys/amd64/conf/NOTES
@@ -494,6 +494,8 @@ device virtio_balloon # VirtIO Memory Balloon device
device virtio_random # VirtIO Entropy device
device virtio_console # VirtIO Console device
+# Microsoft Hyper-V enchancement support
+options HYPERV # Hyper-V kernel infrastructure
device hyperv # HyperV drivers
# Xen HVM Guest Optimizations
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index ccde0e3..9083421 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -91,6 +91,7 @@ struct dumperinfo;
void *alloc_fpusave(int flags);
void amd64_syscall(struct thread *td, int traced);
void busdma_swi(void);
+void cpu_probe_amdc1e(void);
void cpu_setregs(void);
void doreti_iret(void) __asm(__STRING(doreti_iret));
void doreti_iret_fault(void) __asm(__STRING(doreti_iret_fault));
diff --git a/sys/amd64/include/metadata.h b/sys/amd64/include/metadata.h
index cf244e4..e13eba0 100644
--- a/sys/amd64/include/metadata.h
+++ b/sys/amd64/include/metadata.h
@@ -37,17 +37,17 @@
#define MODINFOMD_MODULEP 0x1006
struct efi_map_header {
- size_t memory_size;
- size_t descriptor_size;
+ uint64_t memory_size;
+ uint64_t descriptor_size;
uint32_t descriptor_version;
};
struct efi_fb {
uint64_t fb_addr;
uint64_t fb_size;
- int fb_height;
- int fb_width;
- int fb_stride;
+ uint32_t fb_height;
+ uint32_t fb_width;
+ uint32_t fb_stride;
uint32_t fb_mask_red;
uint32_t fb_mask_green;
uint32_t fb_mask_blue;
diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h
index 3a4b6b3..034a693 100644
--- a/sys/amd64/include/smp.h
+++ b/sys/amd64/include/smp.h
@@ -35,6 +35,39 @@ extern int mp_naps;
extern int boot_cpu_id;
extern struct pcb stoppcbs[];
extern int cpu_apic_ids[];
+extern int bootAP;
+extern void *dpcpu;
+extern char *bootSTK;
+extern int bootAP;
+extern void *bootstacks[];
+extern volatile u_int cpu_ipi_pending[];
+extern volatile int aps_ready;
+extern struct mtx ap_boot_mtx;
+extern int cpu_logical;
+extern int cpu_cores;
+extern int pmap_pcid_enabled;
+extern u_int xhits_gbl[];
+extern u_int xhits_pg[];
+extern u_int xhits_rng[];
+extern u_int ipi_global;
+extern u_int ipi_page;
+extern u_int ipi_range;
+extern u_int ipi_range_size;
+extern u_int ipi_masked_global;
+extern u_int ipi_masked_page;
+extern u_int ipi_masked_range;
+extern u_int ipi_masked_range_size;
+
+extern volatile int smp_tlb_wait;
+
+struct cpu_info {
+ int cpu_present:1;
+ int cpu_bsp:1;
+ int cpu_disabled:1;
+ int cpu_hyperthread:1;
+};
+extern struct cpu_info cpu_info[];
+
#ifdef COUNT_IPIS
extern u_long *ipi_invltlb_counts[MAXCPU];
extern u_long *ipi_invlrng_counts[MAXCPU];
@@ -60,9 +93,11 @@ inthand_t
struct pmap;
/* functions in mp_machdep.c */
+void assign_cpu_ids(void);
void cpu_add(u_int apic_id, char boot_cpu);
void cpustop_handler(void);
void cpususpend_handler(void);
+void init_secondary_tail(void);
void invltlb_handler(void);
void invltlb_pcid_handler(void);
void invlpg_handler(void);
@@ -77,6 +112,7 @@ void ipi_cpu(int cpu, u_int ipi);
int ipi_nmi_handler(void);
void ipi_selected(cpuset_t cpus, u_int ipi);
u_int mp_bootaddress(u_int);
+void set_interrupt_apic_ids(void);
void smp_cache_flush(void);
void smp_invlpg(struct pmap *pmap, vm_offset_t addr);
void smp_masked_invlpg(cpuset_t mask, struct pmap *pmap, vm_offset_t addr);
@@ -87,6 +123,9 @@ void smp_masked_invlpg_range(cpuset_t mask, struct pmap *pmap,
void smp_invltlb(struct pmap *pmap);
void smp_masked_invltlb(cpuset_t mask, struct pmap *pmap);
int native_start_all_aps(void);
+void mem_range_AP_init(void);
+void topo_probe(void);
+void ipi_send_cpu(int cpu, u_int ipi);
#endif /* !LOCORE */
#endif /* SMP */
diff --git a/sys/amd64/include/vm.h b/sys/amd64/include/vm.h
index 6573e37..22d2eca 100644
--- a/sys/amd64/include/vm.h
+++ b/sys/amd64/include/vm.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h
index 52294bd..7c617be 100644
--- a/sys/amd64/include/vmm.h
+++ b/sys/amd64/include/vmm.h
@@ -204,13 +204,12 @@ int vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state);
int vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state);
int vm_apicid2vcpuid(struct vm *vm, int apicid);
int vm_activate_cpu(struct vm *vm, int vcpu);
-cpuset_t vm_active_cpus(struct vm *vm);
-cpuset_t vm_suspended_cpus(struct vm *vm);
struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid);
void vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip);
void vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip);
void vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip);
+#ifdef _SYS__CPUSET_H_
/*
* Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'.
* The rendezvous 'func(arg)' is not allowed to do anything that will
@@ -228,6 +227,9 @@ void vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip);
typedef void (*vm_rendezvous_func_t)(struct vm *vm, int vcpuid, void *arg);
void vm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest,
vm_rendezvous_func_t func, void *arg);
+cpuset_t vm_active_cpus(struct vm *vm);
+cpuset_t vm_suspended_cpus(struct vm *vm);
+#endif /* _SYS__CPUSET_H_ */
static __inline int
vcpu_rendezvous_pending(void *rendezvous_cookie)
diff --git a/sys/amd64/include/xen/xenfunc.h b/sys/amd64/include/xen/xenfunc.h
index d03d4f6..d8a6b5c 100644
--- a/sys/amd64/include/xen/xenfunc.h
+++ b/sys/amd64/include/xen/xenfunc.h
@@ -29,12 +29,7 @@
#ifndef _XEN_XENFUNC_H_
#define _XEN_XENFUNC_H_
-#ifdef XENHVM
#include <machine/xen/xenvar.h>
-#else
-#include <machine/xen/xenpmap.h>
-#include <machine/segments.h>
-#endif
#define BKPT __asm__("int3");
#define XPQ_CALL_DEPTH 5
@@ -64,10 +59,6 @@ void _xen_machphys_update(vm_paddr_t, vm_paddr_t, char *file, int line);
#define xen_machphys_update(a, b) _xen_machphys_update((a), (b), NULL, 0)
#endif
-#ifndef XENHVM
-void xen_update_descriptor(union descriptor *, union descriptor *);
-#endif
-
extern struct mtx balloon_lock;
#if 0
#define balloon_lock(__flags) mtx_lock_irqsave(&balloon_lock, __flags)
diff --git a/sys/amd64/include/xen/xenpmap.h b/sys/amd64/include/xen/xenpmap.h
deleted file mode 100644
index d768dad..0000000
--- a/sys/amd64/include/xen/xenpmap.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- *
- * Copyright (c) 2004 Christian Limpach.
- * Copyright (c) 2004,2005 Kip Macy
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Christian Limpach.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-#ifndef _XEN_XENPMAP_H_
-#define _XEN_XENPMAP_H_
-
-#include <machine/xen/features.h>
-
-void _xen_queue_pt_update(vm_paddr_t, vm_paddr_t, char *, int);
-void xen_pt_switch(vm_paddr_t);
-void xen_set_ldt(vm_paddr_t, unsigned long);
-void xen_pgdpt_pin(vm_paddr_t);
-void xen_pgd_pin(vm_paddr_t);
-void xen_pgd_unpin(vm_paddr_t);
-void xen_pt_pin(vm_paddr_t);
-void xen_pt_unpin(vm_paddr_t);
-void xen_flush_queue(void);
-void xen_check_queue(void);
-#if 0
-void pmap_ref(pt_entry_t *pte, vm_paddr_t ma);
-#endif
-
-#ifdef INVARIANTS
-#define xen_queue_pt_update(a, b) _xen_queue_pt_update((a), (b), __FILE__, __LINE__)
-#else
-#define xen_queue_pt_update(a, b) _xen_queue_pt_update((a), (b), NULL, 0)
-#endif
-
-#ifdef PMAP_DEBUG
-#define PMAP_REF pmap_ref
-#define PMAP_DEC_REF_PAGE pmap_dec_ref_page
-#define PMAP_MARK_PRIV pmap_mark_privileged
-#define PMAP_MARK_UNPRIV pmap_mark_unprivileged
-#else
-#define PMAP_MARK_PRIV(a)
-#define PMAP_MARK_UNPRIV(a)
-#define PMAP_REF(a, b)
-#define PMAP_DEC_REF_PAGE(a)
-#endif
-
-#define ALWAYS_SYNC 0
-
-#ifdef PT_DEBUG
-#define PT_LOG() printk("WP PT_SET %s:%d\n", __FILE__, __LINE__)
-#else
-#define PT_LOG()
-#endif
-
-#define INVALID_P2M_ENTRY (~0UL)
-
-#define pmap_valid_entry(E) ((E) & PG_V) /* is PDE or PTE valid? */
-
-#define SH_PD_SET_VA 1
-#define SH_PD_SET_VA_MA 2
-#define SH_PD_SET_VA_CLEAR 3
-
-struct pmap;
-void pd_set(struct pmap *pmap, int ptepindex, vm_paddr_t val, int type);
-#ifdef notyet
-static vm_paddr_t
-vptetomachpte(vm_paddr_t *pte)
-{
- vm_offset_t offset, ppte;
- vm_paddr_t pgoffset, retval, *pdir_shadow_ptr;
- int pgindex;
-
- ppte = (vm_offset_t)pte;
- pgoffset = (ppte & PAGE_MASK);
- offset = ppte - (vm_offset_t)PTmap;
- pgindex = ppte >> PDRSHIFT;
-
- pdir_shadow_ptr = (vm_paddr_t *)PCPU_GET(pdir_shadow);
- retval = (pdir_shadow_ptr[pgindex] & ~PAGE_MASK) + pgoffset;
- return (retval);
-}
-#endif
-#define PT_GET(_ptp) \
- (pmap_valid_entry(*(_ptp)) ? xpmap_mtop(*(_ptp)) : (0))
-
-#ifdef WRITABLE_PAGETABLES
-
-#define PT_SET_VA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- PT_LOG(); \
- *(_ptp) = xpmap_ptom((_npte)); \
-} while (/*CONSTCOND*/0)
-#define PT_SET_VA_MA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- PT_LOG(); \
- *(_ptp) = (_npte); \
-} while (/*CONSTCOND*/0)
-#define PT_CLEAR_VA(_ptp, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- PT_LOG(); \
- *(_ptp) = 0; \
-} while (/*CONSTCOND*/0)
-
-#define PD_SET_VA(_pmap, _ptp, _npte, sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- pd_set((_pmap),(_ptp),(_npte), SH_PD_SET_VA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_SET_VA_MA(_pmap, _ptp, _npte, sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- pd_set((_pmap),(_ptp),(_npte), SH_PD_SET_VA_MA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_CLEAR_VA(_pmap, _ptp, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- pd_set((_pmap),(_ptp), 0, SH_PD_SET_VA_CLEAR); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-#else /* !WRITABLE_PAGETABLES */
-
-#define PT_SET_VA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- xen_queue_pt_update(vtomach(_ptp), \
- xpmap_ptom(_npte)); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PT_SET_VA_MA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- xen_queue_pt_update(vtomach(_ptp), _npte); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PT_CLEAR_VA(_ptp, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- xen_queue_pt_update(vtomach(_ptp), 0); \
- if (sync || ALWAYS_SYNC) \
- xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-#define PD_SET_VA(_pmap, _ptepindex,_npte,sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- pd_set((_pmap),(_ptepindex),(_npte), SH_PD_SET_VA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_SET_VA_MA(_pmap, _ptepindex,_npte,sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- pd_set((_pmap),(_ptepindex),(_npte), SH_PD_SET_VA_MA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_CLEAR_VA(_pmap, _ptepindex, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- pd_set((_pmap),(_ptepindex), 0, SH_PD_SET_VA_CLEAR); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-#endif
-
-#define PT_SET_MA(_va, _ma) \
-do { \
- PANIC_IF(HYPERVISOR_update_va_mapping(((unsigned long)(_va)),\
- (_ma), \
- UVMF_INVLPG| UVMF_ALL) < 0); \
-} while (/*CONSTCOND*/0)
-
-#define PT_UPDATES_FLUSH() do { \
- xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-static __inline vm_paddr_t
-xpmap_mtop(vm_paddr_t mpa)
-{
- vm_paddr_t tmp = (mpa & PG_FRAME);
-
- return machtophys(tmp) | (mpa & ~PG_FRAME);
-}
-
-static __inline vm_paddr_t
-xpmap_ptom(vm_paddr_t ppa)
-{
- vm_paddr_t tmp = (ppa & PG_FRAME);
-
- return phystomach(tmp) | (ppa & ~PG_FRAME);
-}
-
-static __inline void
-set_phys_to_machine(unsigned long pfn, unsigned long mfn)
-{
-#ifdef notyet
- PANIC_IF(max_mapnr && pfn >= max_mapnr);
-#endif
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
-#ifdef notyet
- PANIC_IF((pfn != mfn && mfn != INVALID_P2M_ENTRY));
-#endif
- return;
- }
- xen_phys_machine[pfn] = mfn;
-}
-
-
-
-
-#endif /* _XEN_XENPMAP_H_ */
diff --git a/sys/amd64/include/xen/xenvar.h b/sys/amd64/include/xen/xenvar.h
index d9dbc5d..110a351 100644
--- a/sys/amd64/include/xen/xenvar.h
+++ b/sys/amd64/include/xen/xenvar.h
@@ -48,68 +48,7 @@ if (xendebug_flags & argflags) XENPRINTF("(file=%s, line=%d) " _f "\n", __FILE__
#define TRACE_DEBUG(argflags, _f, _a...)
#endif
-#ifdef XENHVM
-
-static inline vm_paddr_t
-phystomach(vm_paddr_t pa)
-{
-
- return (pa);
-}
-
-static inline vm_paddr_t
-machtophys(vm_paddr_t ma)
-{
-
- return (ma);
-}
-
#define vtomach(va) pmap_kextract((vm_offset_t) (va))
-#define PFNTOMFN(pa) (pa)
-#define MFNTOPFN(ma) (ma)
-
-#define set_phys_to_machine(pfn, mfn) ((void)0)
-#define phys_to_machine_mapping_valid(pfn) (TRUE)
-#define PT_UPDATES_FLUSH() ((void)0)
-
-#else
-
-extern xen_pfn_t *xen_phys_machine;
-
-
-extern xen_pfn_t *xen_machine_phys;
-/* Xen starts physical pages after the 4MB ISA hole -
- * FreeBSD doesn't
- */
-
-
-#undef ADD_ISA_HOLE /* XXX */
-
-#ifdef ADD_ISA_HOLE
-#define ISA_INDEX_OFFSET 1024
-#define ISA_PDR_OFFSET 1
-#else
-#define ISA_INDEX_OFFSET 0
-#define ISA_PDR_OFFSET 0
-#endif
-
-
-#define PFNTOMFN(i) (xen_phys_machine[(i)])
-#define MFNTOPFN(i) ((vm_paddr_t)xen_machine_phys[(i)])
-
-#define VTOP(x) ((((uintptr_t)(x))) - KERNBASE)
-#define PTOV(x) (((uintptr_t)(x)) + KERNBASE)
-
-#define VTOPFN(x) (VTOP(x) >> PAGE_SHIFT)
-#define PFNTOV(x) PTOV((vm_paddr_t)(x) << PAGE_SHIFT)
-
-#define VTOMFN(va) (vtomach(va) >> PAGE_SHIFT)
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-
-#define phystomach(pa) (((vm_paddr_t)(PFNTOMFN((pa) >> PAGE_SHIFT))) << PAGE_SHIFT)
-#define machtophys(ma) (((vm_paddr_t)(MFNTOPFN((ma) >> PAGE_SHIFT))) << PAGE_SHIFT)
-
-#endif
void xpq_init(void);
diff --git a/sys/amd64/vmm/amd/amdv.c b/sys/amd64/vmm/amd/amdv.c
index acb3a3d..3157e21 100644
--- a/sys/amd64/vmm/amd/amdv.c
+++ b/sys/amd64/vmm/amd/amdv.c
@@ -32,7 +32,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
-#include <sys/smp.h>
#include <machine/vmm.h>
#include "io/iommu.h"
diff --git a/sys/amd64/vmm/amd/svm.c b/sys/amd64/vmm/amd/svm.c
index 18871d0..7cc13ca 100644
--- a/sys/amd64/vmm/amd/svm.c
+++ b/sys/amd64/vmm/amd/svm.c
@@ -802,6 +802,7 @@ svm_handle_inst_emul(struct vmcb *vmcb, uint64_t gpa, struct vm_exit *vmexit)
case CPU_MODE_REAL:
vmexit->u.inst_emul.cs_base = seg.base;
vmexit->u.inst_emul.cs_d = 0;
+ break;
case CPU_MODE_PROTECTED:
case CPU_MODE_COMPATIBILITY:
vmexit->u.inst_emul.cs_base = seg.base;
@@ -1917,7 +1918,7 @@ svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
}
/* We are asked to give the cpu by scheduler. */
- if (curthread->td_flags & (TDF_ASTPENDING | TDF_NEEDRESCHED)) {
+ if (vcpu_should_yield(vm, vcpu)) {
enable_gintr();
vm_exit_astpending(vm, vcpu, state->rip);
break;
diff --git a/sys/amd64/vmm/amd/svm_msr.c b/sys/amd64/vmm/amd/svm_msr.c
index 100af4b..088751a 100644
--- a/sys/amd64/vmm/amd/svm_msr.c
+++ b/sys/amd64/vmm/amd/svm_msr.c
@@ -27,12 +27,17 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/errno.h>
+#include <sys/systm.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
+#include <machine/vmm.h>
+#include "svm.h"
+#include "vmcb.h"
+#include "svm_softc.h"
#include "svm_msr.h"
#ifndef MSR_AMDK8_IPM
@@ -105,6 +110,18 @@ svm_rdmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t *result,
int error = 0;
switch (num) {
+ case MSR_MCG_CAP:
+ case MSR_MCG_STATUS:
+ *result = 0;
+ break;
+ case MSR_MTRRcap:
+ case MSR_MTRRdefType:
+ case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
+ case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
+ case MSR_MTRR64kBase:
+ case MSR_SYSCFG:
+ *result = 0;
+ break;
case MSR_AMDK8_IPM:
*result = 0;
break;
@@ -122,6 +139,18 @@ svm_wrmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t val, bool *retu)
int error = 0;
switch (num) {
+ case MSR_MCG_CAP:
+ case MSR_MCG_STATUS:
+ break; /* ignore writes */
+ case MSR_MTRRcap:
+ vm_inject_gp(sc->vm, vcpu);
+ break;
+ case MSR_MTRRdefType:
+ case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
+ case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
+ case MSR_MTRR64kBase:
+ case MSR_SYSCFG:
+ break; /* Ignore writes */
case MSR_AMDK8_IPM:
/*
* Ignore writes to the "Interrupt Pending Message" MSR.
diff --git a/sys/amd64/vmm/amd/vmcb.c b/sys/amd64/vmm/amd/vmcb.c
index fb4b2c8..d860169 100644
--- a/sys/amd64/vmm/amd/vmcb.c
+++ b/sys/amd64/vmm/amd/vmcb.c
@@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/cpuset.h>
#include <machine/segments.h>
#include <machine/specialreg.h>
diff --git a/sys/amd64/vmm/intel/vmx_msr.c b/sys/amd64/vmm/intel/vmx_msr.c
index e517778..3091f68 100644
--- a/sys/amd64/vmm/intel/vmx_msr.c
+++ b/sys/amd64/vmm/intel/vmx_msr.c
@@ -31,7 +31,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/cpuset.h>
#include <machine/clock.h>
#include <machine/cpufunc.h>
@@ -396,6 +395,17 @@ vmx_rdmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t *val, bool *retu)
error = 0;
switch (num) {
+ case MSR_MCG_CAP:
+ case MSR_MCG_STATUS:
+ *val = 0;
+ break;
+ case MSR_MTRRcap:
+ case MSR_MTRRdefType:
+ case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
+ case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
+ case MSR_MTRR64kBase:
+ *val = 0;
+ break;
case MSR_IA32_MISC_ENABLE:
*val = misc_enable;
break;
@@ -427,6 +437,17 @@ vmx_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val, bool *retu)
error = 0;
switch (num) {
+ case MSR_MCG_CAP:
+ case MSR_MCG_STATUS:
+ break; /* ignore writes */
+ case MSR_MTRRcap:
+ vm_inject_gp(vmx->vm, vcpuid);
+ break;
+ case MSR_MTRRdefType:
+ case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
+ case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
+ case MSR_MTRR64kBase:
+ break; /* Ignore writes */
case MSR_IA32_MISC_ENABLE:
changed = val ^ misc_enable;
/*
diff --git a/sys/amd64/vmm/io/vatpic.c b/sys/amd64/vmm/io/vatpic.c
index 0df6e7c..6e94f5b 100644
--- a/sys/amd64/vmm/io/vatpic.c
+++ b/sys/amd64/vmm/io/vatpic.c
@@ -30,7 +30,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/queue.h>
-#include <sys/cpuset.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
diff --git a/sys/amd64/vmm/io/vatpit.c b/sys/amd64/vmm/io/vatpit.c
index 842253d..173ef1f 100644
--- a/sys/amd64/vmm/io/vatpit.c
+++ b/sys/amd64/vmm/io/vatpit.c
@@ -31,7 +31,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/queue.h>
-#include <sys/cpuset.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
diff --git a/sys/amd64/vmm/io/vhpet.c b/sys/amd64/vmm/io/vhpet.c
index a4c96cd..1db1c51 100644
--- a/sys/amd64/vmm/io/vhpet.c
+++ b/sys/amd64/vmm/io/vhpet.c
@@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
-#include <sys/cpuset.h>
#include <dev/acpica/acpi_hpet.h>
diff --git a/sys/amd64/vmm/io/vioapic.c b/sys/amd64/vmm/io/vioapic.c
index 411887d..e6b8b5a 100644
--- a/sys/amd64/vmm/io/vioapic.c
+++ b/sys/amd64/vmm/io/vioapic.c
@@ -32,7 +32,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/queue.h>
-#include <sys/cpuset.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c
index 7097248..3451e1e 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -547,6 +547,8 @@ vlapic_update_ppr(struct vlapic *vlapic)
VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr);
}
+static VMM_STAT(VLAPIC_GRATUITOUS_EOI, "EOI without any in-service interrupt");
+
static void
vlapic_process_eoi(struct vlapic *vlapic)
{
@@ -557,11 +559,7 @@ vlapic_process_eoi(struct vlapic *vlapic)
isrptr = &lapic->isr0;
tmrptr = &lapic->tmr0;
- /*
- * The x86 architecture reserves the the first 32 vectors for use
- * by the processor.
- */
- for (i = 7; i > 0; i--) {
+ for (i = 7; i >= 0; i--) {
idx = i * 4;
bitpos = fls(isrptr[idx]);
if (bitpos-- != 0) {
@@ -570,17 +568,21 @@ vlapic_process_eoi(struct vlapic *vlapic)
vlapic->isrvec_stk_top);
}
isrptr[idx] &= ~(1 << bitpos);
+ vector = i * 32 + bitpos;
+ VCPU_CTR1(vlapic->vm, vlapic->vcpuid, "EOI vector %d",
+ vector);
VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi");
vlapic->isrvec_stk_top--;
vlapic_update_ppr(vlapic);
if ((tmrptr[idx] & (1 << bitpos)) != 0) {
- vector = i * 32 + bitpos;
vioapic_process_eoi(vlapic->vm, vlapic->vcpuid,
vector);
}
return;
}
}
+ VCPU_CTR0(vlapic->vm, vlapic->vcpuid, "Gratuitous EOI");
+ vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_GRATUITOUS_EOI, 1);
}
static __inline int
@@ -1092,11 +1094,7 @@ vlapic_pending_intr(struct vlapic *vlapic, int *vecptr)
irrptr = &lapic->irr0;
- /*
- * The x86 architecture reserves the the first 32 vectors for use
- * by the processor.
- */
- for (i = 7; i > 0; i--) {
+ for (i = 7; i >= 0; i--) {
idx = i * 4;
val = atomic_load_acq_int(&irrptr[idx]);
bitpos = fls(val);
diff --git a/sys/amd64/vmm/io/vpmtmr.c b/sys/amd64/vmm/io/vpmtmr.c
index 09f763f..1e7bb93 100644
--- a/sys/amd64/vmm/io/vpmtmr.c
+++ b/sys/amd64/vmm/io/vpmtmr.c
@@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/queue.h>
-#include <sys/cpuset.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
diff --git a/sys/amd64/vmm/io/vrtc.c b/sys/amd64/vmm/io/vrtc.c
index ab9cabb..18ebc4b 100644
--- a/sys/amd64/vmm/io/vrtc.c
+++ b/sys/amd64/vmm/io/vrtc.c
@@ -30,7 +30,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
-#include <sys/cpuset.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/lock.h>
@@ -63,9 +62,12 @@ struct rtcdev {
uint8_t reg_b;
uint8_t reg_c;
uint8_t reg_d;
- uint8_t nvram[128 - 14];
+ uint8_t nvram[36];
+ uint8_t century;
+ uint8_t nvram2[128 - 51];
} __packed;
CTASSERT(sizeof(struct rtcdev) == 128);
+CTASSERT(offsetof(struct rtcdev, century) == RTC_CENTURY);
struct vrtc {
struct vm *vm;
@@ -139,20 +141,23 @@ update_enabled(struct vrtc *vrtc)
}
static time_t
-vrtc_curtime(struct vrtc *vrtc)
+vrtc_curtime(struct vrtc *vrtc, sbintime_t *basetime)
{
sbintime_t now, delta;
- time_t t;
+ time_t t, secs;
KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__));
t = vrtc->base_rtctime;
+ *basetime = vrtc->base_uptime;
if (update_enabled(vrtc)) {
now = sbinuptime();
delta = now - vrtc->base_uptime;
KASSERT(delta >= 0, ("vrtc_curtime: uptime went backwards: "
"%#lx to %#lx", vrtc->base_uptime, now));
- t += delta / SBT_1S;
+ secs = delta / SBT_1S;
+ t += secs;
+ *basetime += secs * SBT_1S;
}
return (t);
}
@@ -245,6 +250,7 @@ secs_to_rtc(time_t rtctime, struct vrtc *vrtc, int force_update)
rtc->day_of_month = rtcset(rtc, ct.day);
rtc->month = rtcset(rtc, ct.mon);
rtc->year = rtcset(rtc, ct.year % 100);
+ rtc->century = rtcset(rtc, ct.year / 100);
}
static int
@@ -274,7 +280,7 @@ rtc_to_secs(struct vrtc *vrtc)
struct timespec ts;
struct rtcdev *rtc;
struct vm *vm;
- int error, hour, pm, year;
+ int century, error, hour, pm, year;
KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__));
@@ -358,10 +364,14 @@ rtc_to_secs(struct vrtc *vrtc)
VM_CTR2(vm, "Invalid RTC year %#x/%d", rtc->year, year);
goto fail;
}
- if (year >= 70)
- ct.year = 1900 + year;
- else
- ct.year = 2000 + year;
+
+ error = rtcget(rtc, rtc->century, &century);
+ ct.year = century * 100 + year;
+ if (error || ct.year < POSIX_BASE_YEAR) {
+ VM_CTR2(vm, "Invalid RTC century %#x/%d", rtc->century,
+ ct.year);
+ goto fail;
+ }
error = clock_ct_to_ts(&ct, &ts);
if (error || ts.tv_sec < 0) {
@@ -373,13 +383,19 @@ rtc_to_secs(struct vrtc *vrtc)
}
return (ts.tv_sec); /* success */
fail:
- return (VRTC_BROKEN_TIME); /* failure */
+ /*
+ * Stop updating the RTC if the date/time fields programmed by
+ * the guest are invalid.
+ */
+ VM_CTR0(vrtc->vm, "Invalid RTC date/time programming detected");
+ return (VRTC_BROKEN_TIME);
}
static int
-vrtc_time_update(struct vrtc *vrtc, time_t newtime)
+vrtc_time_update(struct vrtc *vrtc, time_t newtime, sbintime_t newbase)
{
struct rtcdev *rtc;
+ sbintime_t oldbase;
time_t oldtime;
uint8_t alarm_sec, alarm_min, alarm_hour;
@@ -391,16 +407,21 @@ vrtc_time_update(struct vrtc *vrtc, time_t newtime)
alarm_hour = rtc->alarm_hour;
oldtime = vrtc->base_rtctime;
- VM_CTR2(vrtc->vm, "Updating RTC time from %#lx to %#lx",
+ VM_CTR2(vrtc->vm, "Updating RTC secs from %#lx to %#lx",
oldtime, newtime);
+ oldbase = vrtc->base_uptime;
+ VM_CTR2(vrtc->vm, "Updating RTC base uptime from %#lx to %#lx",
+ oldbase, newbase);
+ vrtc->base_uptime = newbase;
+
if (newtime == oldtime)
return (0);
/*
* If 'newtime' indicates that RTC updates are disabled then just
* record that and return. There is no need to do alarm interrupt
- * processing or update 'base_uptime' in this case.
+ * processing in this case.
*/
if (newtime == VRTC_BROKEN_TIME) {
vrtc->base_rtctime = VRTC_BROKEN_TIME;
@@ -446,8 +467,6 @@ vrtc_time_update(struct vrtc *vrtc, time_t newtime)
if (uintr_enabled(vrtc))
vrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_UPDATE);
- vrtc->base_uptime = sbinuptime();
-
return (0);
}
@@ -518,7 +537,7 @@ static void
vrtc_callout_handler(void *arg)
{
struct vrtc *vrtc = arg;
- sbintime_t freqsbt;
+ sbintime_t freqsbt, basetime;
time_t rtctime;
int error;
@@ -540,8 +559,8 @@ vrtc_callout_handler(void *arg)
vrtc_set_reg_c(vrtc, vrtc->rtcdev.reg_c | RTCIR_PERIOD);
if (aintr_enabled(vrtc) || uintr_enabled(vrtc)) {
- rtctime = vrtc_curtime(vrtc);
- error = vrtc_time_update(vrtc, rtctime);
+ rtctime = vrtc_curtime(vrtc, &basetime);
+ error = vrtc_time_update(vrtc, rtctime, basetime);
KASSERT(error == 0, ("%s: vrtc_time_update error %d",
__func__, error));
}
@@ -606,7 +625,7 @@ static int
vrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval)
{
struct rtcdev *rtc;
- sbintime_t oldfreq, newfreq;
+ sbintime_t oldfreq, newfreq, basetime;
time_t curtime, rtctime;
int error;
uint8_t oldval, changed;
@@ -627,19 +646,13 @@ vrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval)
if (changed & RTCSB_HALT) {
if ((newval & RTCSB_HALT) == 0) {
rtctime = rtc_to_secs(vrtc);
+ basetime = sbinuptime();
if (rtctime == VRTC_BROKEN_TIME) {
- /*
- * Stop updating the RTC if the date/time
- * programmed by the guest is not correct.
- */
- VM_CTR0(vrtc->vm, "Invalid RTC date/time "
- "programming detected");
-
if (rtc_flag_broken_time)
return (-1);
}
} else {
- curtime = vrtc_curtime(vrtc);
+ curtime = vrtc_curtime(vrtc, &basetime);
KASSERT(curtime == vrtc->base_rtctime, ("%s: mismatch "
"between vrtc basetime (%#lx) and curtime (%#lx)",
__func__, vrtc->base_rtctime, curtime));
@@ -658,7 +671,7 @@ vrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval)
rtctime = VRTC_BROKEN_TIME;
rtc->reg_b &= ~RTCSB_UINTR;
}
- error = vrtc_time_update(vrtc, rtctime);
+ error = vrtc_time_update(vrtc, rtctime, basetime);
KASSERT(error == 0, ("vrtc_time_update error %d", error));
}
@@ -738,7 +751,7 @@ vrtc_set_time(struct vm *vm, time_t secs)
vrtc = vm_rtc(vm);
VRTC_LOCK(vrtc);
- error = vrtc_time_update(vrtc, secs);
+ error = vrtc_time_update(vrtc, secs, sbinuptime());
VRTC_UNLOCK(vrtc);
if (error) {
@@ -755,11 +768,12 @@ time_t
vrtc_get_time(struct vm *vm)
{
struct vrtc *vrtc;
+ sbintime_t basetime;
time_t t;
vrtc = vm_rtc(vm);
VRTC_LOCK(vrtc);
- t = vrtc_curtime(vrtc);
+ t = vrtc_curtime(vrtc, &basetime);
VRTC_UNLOCK(vrtc);
return (t);
@@ -777,7 +791,7 @@ vrtc_nvram_write(struct vm *vm, int offset, uint8_t value)
* Don't allow writes to RTC control registers or the date/time fields.
*/
if (offset < offsetof(struct rtcdev, nvram[0]) ||
- offset >= sizeof(struct rtcdev)) {
+ offset == RTC_CENTURY || offset >= sizeof(struct rtcdev)) {
VM_CTR1(vrtc->vm, "RTC nvram write to invalid offset %d",
offset);
return (EINVAL);
@@ -796,6 +810,7 @@ int
vrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval)
{
struct vrtc *vrtc;
+ sbintime_t basetime;
time_t curtime;
uint8_t *ptr;
@@ -811,8 +826,8 @@ vrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval)
/*
* Update RTC date/time fields if necessary.
*/
- if (offset < 10) {
- curtime = vrtc_curtime(vrtc);
+ if (offset < 10 || offset == RTC_CENTURY) {
+ curtime = vrtc_curtime(vrtc, &basetime);
secs_to_rtc(curtime, vrtc, 0);
}
@@ -852,6 +867,7 @@ vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
{
struct vrtc *vrtc;
struct rtcdev *rtc;
+ sbintime_t basetime;
time_t curtime;
int error, offset;
@@ -869,16 +885,20 @@ vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
}
error = 0;
- curtime = vrtc_curtime(vrtc);
- vrtc_time_update(vrtc, curtime);
+ curtime = vrtc_curtime(vrtc, &basetime);
+ vrtc_time_update(vrtc, curtime, basetime);
- if (in) {
- /*
- * Update RTC date/time fields if necessary.
- */
- if (offset < 10)
- secs_to_rtc(curtime, vrtc, 0);
+ /*
+ * Update RTC date/time fields if necessary.
+ *
+ * This is not just for reads of the RTC. The side-effect of writing
+ * the century byte requires other RTC date/time fields (e.g. sec)
+ * to be updated here.
+ */
+ if (offset < 10 || offset == RTC_CENTURY)
+ secs_to_rtc(curtime, vrtc, 0);
+ if (in) {
if (offset == 12) {
/*
* XXX
@@ -922,6 +942,18 @@ vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
*((uint8_t *)rtc + offset) = *val;
break;
}
+
+ /*
+ * XXX some guests (e.g. OpenBSD) write the century byte
+ * outside of RTCSB_HALT so re-calculate the RTC date/time.
+ */
+ if (offset == RTC_CENTURY && !rtc_halted(vrtc)) {
+ curtime = rtc_to_secs(vrtc);
+ error = vrtc_time_update(vrtc, curtime, sbinuptime());
+ KASSERT(!error, ("vrtc_time_update error %d", error));
+ if (curtime == VRTC_BROKEN_TIME && rtc_flag_broken_time)
+ error = -1;
+ }
}
VRTC_UNLOCK(vrtc);
return (error);
@@ -971,7 +1003,7 @@ vrtc_init(struct vm *vm)
VRTC_LOCK(vrtc);
vrtc->base_rtctime = VRTC_BROKEN_TIME;
- vrtc_time_update(vrtc, curtime);
+ vrtc_time_update(vrtc, curtime, sbinuptime());
secs_to_rtc(curtime, vrtc, 0);
VRTC_UNLOCK(vrtc);
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 6bd5bce..bca9b98 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -1293,8 +1293,12 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)
else if (error != 0)
panic("%s: vmm_fetch_instruction error %d", __func__, error);
- if (vmm_decode_instruction(vm, vcpuid, gla, cpu_mode, cs_d, vie) != 0)
- return (EFAULT);
+ if (vmm_decode_instruction(vm, vcpuid, gla, cpu_mode, cs_d, vie) != 0) {
+ VCPU_CTR1(vm, vcpuid, "Error decoding instruction at %#lx",
+ vme->rip + cs_base);
+ *retu = true; /* dump instruction bytes in userspace */
+ return (0);
+ }
/*
* If the instruction length was not specified then update it now
diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c
index ca0b144..7172365 100644
--- a/sys/amd64/vmm/vmm_instruction_emul.c
+++ b/sys/amd64/vmm/vmm_instruction_emul.c
@@ -71,6 +71,9 @@ enum {
VIE_OP_TYPE_CMP,
VIE_OP_TYPE_POP,
VIE_OP_TYPE_MOVS,
+ VIE_OP_TYPE_GROUP1,
+ VIE_OP_TYPE_STOS,
+ VIE_OP_TYPE_BITTEST,
VIE_OP_TYPE_LAST
};
@@ -90,6 +93,11 @@ static const struct vie_op two_byte_opcodes[256] = {
.op_byte = 0xB7,
.op_type = VIE_OP_TYPE_MOVZX,
},
+ [0xBA] = {
+ .op_byte = 0xBA,
+ .op_type = VIE_OP_TYPE_BITTEST,
+ .op_flags = VIE_OP_F_IMM8,
+ },
[0xBE] = {
.op_byte = 0xBE,
.op_type = VIE_OP_TYPE_MOVSX,
@@ -145,6 +153,16 @@ static const struct vie_op one_byte_opcodes[256] = {
.op_type = VIE_OP_TYPE_MOVS,
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION
},
+ [0xAA] = {
+ .op_byte = 0xAA,
+ .op_type = VIE_OP_TYPE_STOS,
+ .op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION
+ },
+ [0xAB] = {
+ .op_byte = 0xAB,
+ .op_type = VIE_OP_TYPE_STOS,
+ .op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION
+ },
[0xC6] = {
/* XXX Group 11 extended opcode - not just MOV */
.op_byte = 0xC6,
@@ -161,15 +179,15 @@ static const struct vie_op one_byte_opcodes[256] = {
.op_type = VIE_OP_TYPE_AND,
},
[0x81] = {
- /* XXX Group 1 extended opcode - not just AND */
+ /* XXX Group 1 extended opcode */
.op_byte = 0x81,
- .op_type = VIE_OP_TYPE_AND,
+ .op_type = VIE_OP_TYPE_GROUP1,
.op_flags = VIE_OP_F_IMM,
},
[0x83] = {
- /* XXX Group 1 extended opcode - not just OR */
+ /* XXX Group 1 extended opcode */
.op_byte = 0x83,
- .op_type = VIE_OP_TYPE_OR,
+ .op_type = VIE_OP_TYPE_GROUP1,
.op_flags = VIE_OP_F_IMM8,
},
[0x8F] = {
@@ -802,6 +820,68 @@ done:
}
static int
+emulate_stos(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
+ struct vm_guest_paging *paging, mem_region_read_t memread,
+ mem_region_write_t memwrite, void *arg)
+{
+ int error, opsize, repeat;
+ uint64_t val;
+ uint64_t rcx, rdi, rflags;
+
+ opsize = (vie->op.op_byte == 0xAA) ? 1 : vie->opsize;
+ repeat = vie->repz_present | vie->repnz_present;
+
+ if (repeat) {
+ error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RCX, &rcx);
+ KASSERT(!error, ("%s: error %d getting rcx", __func__, error));
+
+ /*
+ * The count register is %rcx, %ecx or %cx depending on the
+ * address size of the instruction.
+ */
+ if ((rcx & vie_size2mask(vie->addrsize)) == 0)
+ return (0);
+ }
+
+ error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RAX, &val);
+ KASSERT(!error, ("%s: error %d getting rax", __func__, error));
+
+ error = memwrite(vm, vcpuid, gpa, val, opsize, arg);
+ if (error)
+ return (error);
+
+ error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RDI, &rdi);
+ KASSERT(error == 0, ("%s: error %d getting rdi", __func__, error));
+
+ error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);
+ KASSERT(error == 0, ("%s: error %d getting rflags", __func__, error));
+
+ if (rflags & PSL_D)
+ rdi -= opsize;
+ else
+ rdi += opsize;
+
+ error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RDI, rdi,
+ vie->addrsize);
+ KASSERT(error == 0, ("%s: error %d updating rdi", __func__, error));
+
+ if (repeat) {
+ rcx = rcx - 1;
+ error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RCX,
+ rcx, vie->addrsize);
+ KASSERT(!error, ("%s: error %d updating rcx", __func__, error));
+
+ /*
+ * Repeat the instruction if the count register is not zero.
+ */
+ if ((rcx & vie_size2mask(vie->addrsize)) != 0)
+ vm_restart_instruction(vm, vcpuid);
+ }
+
+ return (0);
+}
+
+static int
emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
mem_region_read_t memread, mem_region_write_t memwrite, void *arg)
{
@@ -839,16 +919,18 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
error = vie_update_register(vm, vcpuid, reg, result, size);
break;
case 0x81:
+ case 0x83:
/*
- * AND/OR mem (ModRM:r/m) with immediate and store the
+ * AND mem (ModRM:r/m) with immediate and store the
* result in mem.
*
- * AND: i = 4
- * OR: i = 1
- * 81 /i op r/m16, imm16
- * 81 /i op r/m32, imm32
- * REX.W + 81 /i op r/m64, imm32 sign-extended to 64
+ * 81 /4 and r/m16, imm16
+ * 81 /4 and r/m32, imm32
+ * REX.W + 81 /4 and r/m64, imm32 sign-extended to 64
*
+ * 83 /4 and r/m16, imm8 sign-extended to 16
+ * 83 /4 and r/m32, imm8 sign-extended to 32
+ * REX.W + 83/4 and r/m64, imm8 sign-extended to 64
*/
/* get the first operand */
@@ -857,26 +939,11 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
break;
/*
- * perform the operation with the pre-fetched immediate
- * operand and write the result
- */
- switch (vie->reg & 7) {
- case 0x4:
- /* modrm:reg == b100, AND */
- result = val1 & vie->immediate;
- break;
- case 0x1:
- /* modrm:reg == b001, OR */
- result = val1 | vie->immediate;
- break;
- default:
- error = EINVAL;
- break;
- }
- if (error)
- break;
-
- error = memwrite(vm, vcpuid, gpa, result, size, arg);
+ * perform the operation with the pre-fetched immediate
+ * operand and write the result
+ */
+ result = val1 & vie->immediate;
+ error = memwrite(vm, vcpuid, gpa, result, size, arg);
break;
default:
break;
@@ -913,20 +980,20 @@ emulate_or(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
error = EINVAL;
switch (vie->op.op_byte) {
+ case 0x81:
case 0x83:
/*
* OR mem (ModRM:r/m) with immediate and store the
* result in mem.
*
- * 83 /1 OR r/m16, imm8 sign-extended to 16
- * 83 /1 OR r/m32, imm8 sign-extended to 32
- * REX.W + 83/1 OR r/m64, imm8 sign-extended to 64
+ * 81 /1 or r/m16, imm16
+ * 81 /1 or r/m32, imm32
+ * REX.W + 81 /1 or r/m64, imm32 sign-extended to 64
*
- * Currently, only the OR operation of the 0x83 opcode
- * is implemented (ModRM:reg = b001).
+ * 83 /1 or r/m16, imm8 sign-extended to 16
+ * 83 /1 or r/m32, imm8 sign-extended to 32
+ * REX.W + 83/1 or r/m64, imm8 sign-extended to 64
*/
- if ((vie->reg & 7) != 1)
- break;
/* get the first operand */
error = memread(vm, vcpuid, gpa, &val1, size, arg);
@@ -997,11 +1064,37 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
if (error)
return (error);
+ rflags2 = getcc(size, op1, op2);
+ break;
+ case 0x81:
+ case 0x83:
+ /*
+ * 81 /7 cmp r/m16, imm16
+ * 81 /7 cmp r/m32, imm32
+ * REX.W + 81 /7 cmp r/m64, imm32 sign-extended to 64
+ *
+ * 83 /7 cmp r/m16, imm8 sign-extended to 16
+ * 83 /7 cmp r/m32, imm8 sign-extended to 32
+ * REX.W + 83 /7 cmp r/m64, imm8 sign-extended to 64
+ *
+ * Compare mem (ModRM:r/m) with immediate and set
+ * status flags according to the results. The
+ * comparison is performed by subtracting the
+ * immediate from the first operand and then setting
+ * the status flags.
+ *
+ */
+
+ /* get the first operand */
+ error = memread(vm, vcpuid, gpa, &op1, size, arg);
+ if (error)
+ return (error);
+
+ rflags2 = getcc(size, op1, vie->immediate);
break;
default:
return (EINVAL);
}
- rflags2 = getcc(size, op1, op2);
error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);
if (error)
return (error);
@@ -1220,6 +1313,76 @@ emulate_pop(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
return (error);
}
+static int
+emulate_group1(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
+ struct vm_guest_paging *paging, mem_region_read_t memread,
+ mem_region_write_t memwrite, void *memarg)
+{
+ int error;
+
+ switch (vie->reg & 7) {
+ case 0x1: /* OR */
+ error = emulate_or(vm, vcpuid, gpa, vie,
+ memread, memwrite, memarg);
+ break;
+ case 0x4: /* AND */
+ error = emulate_and(vm, vcpuid, gpa, vie,
+ memread, memwrite, memarg);
+ break;
+ case 0x7: /* CMP */
+ error = emulate_cmp(vm, vcpuid, gpa, vie,
+ memread, memwrite, memarg);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
+
+static int
+emulate_bittest(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
+ mem_region_read_t memread, mem_region_write_t memwrite, void *memarg)
+{
+ uint64_t val, rflags;
+ int error, bitmask, bitoff;
+
+ /*
+ * 0F BA is a Group 8 extended opcode.
+ *
+ * Currently we only emulate the 'Bit Test' instruction which is
+ * identified by a ModR/M:reg encoding of 100b.
+ */
+ if ((vie->reg & 7) != 4)
+ return (EINVAL);
+
+ error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);
+ KASSERT(error == 0, ("%s: error %d getting rflags", __func__, error));
+
+ error = memread(vm, vcpuid, gpa, &val, vie->opsize, memarg);
+ if (error)
+ return (error);
+
+ /*
+ * Intel SDM, Vol 2, Table 3-2:
+ * "Range of Bit Positions Specified by Bit Offset Operands"
+ */
+ bitmask = vie->opsize * 8 - 1;
+ bitoff = vie->immediate & bitmask;
+
+ /* Copy the bit into the Carry flag in %rflags */
+ if (val & (1UL << bitoff))
+ rflags |= PSL_C;
+ else
+ rflags &= ~PSL_C;
+
+ error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);
+ KASSERT(error == 0, ("%s: error %d updating rflags", __func__, error));
+
+ return (0);
+}
+
int
vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
struct vm_guest_paging *paging, mem_region_read_t memread,
@@ -1231,6 +1394,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
return (EINVAL);
switch (vie->op.op_type) {
+ case VIE_OP_TYPE_GROUP1:
+ error = emulate_group1(vm, vcpuid, gpa, vie, paging, memread,
+ memwrite, memarg);
+ break;
case VIE_OP_TYPE_POP:
error = emulate_pop(vm, vcpuid, gpa, vie, paging, memread,
memwrite, memarg);
@@ -1256,6 +1423,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
error = emulate_movs(vm, vcpuid, gpa, vie, paging, memread,
memwrite, memarg);
break;
+ case VIE_OP_TYPE_STOS:
+ error = emulate_stos(vm, vcpuid, gpa, vie, paging, memread,
+ memwrite, memarg);
+ break;
case VIE_OP_TYPE_AND:
error = emulate_and(vm, vcpuid, gpa, vie,
memread, memwrite, memarg);
@@ -1268,6 +1439,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
error = emulate_sub(vm, vcpuid, gpa, vie,
memread, memwrite, memarg);
break;
+ case VIE_OP_TYPE_BITTEST:
+ error = emulate_bittest(vm, vcpuid, gpa, vie,
+ memread, memwrite, memarg);
+ break;
default:
error = EINVAL;
break;
diff --git a/sys/amd64/vmm/vmm_ioport.c b/sys/amd64/vmm/vmm_ioport.c
index fc68a61..63044e8 100644
--- a/sys/amd64/vmm/vmm_ioport.c
+++ b/sys/amd64/vmm/vmm_ioport.c
@@ -28,16 +28,10 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/cpuset.h>
#include <sys/systm.h>
-#include <vm/vm.h>
-
#include <machine/vmm.h>
#include <machine/vmm_instruction_emul.h>
-#include <x86/psl.h>
#include "vatpic.h"
#include "vatpit.h"
diff --git a/sys/amd64/vmm/vmm_lapic.c b/sys/amd64/vmm/vmm_lapic.c
index 15a995e..6bccd32 100644
--- a/sys/amd64/vmm/vmm_lapic.c
+++ b/sys/amd64/vmm/vmm_lapic.c
@@ -57,7 +57,11 @@ lapic_set_intr(struct vm *vm, int cpu, int vector, bool level)
if (cpu < 0 || cpu >= VM_MAXCPU)
return (EINVAL);
- if (vector < 32 || vector > 255)
+ /*
+ * According to section "Maskable Hardware Interrupts" in Intel SDM
+ * vectors 16 through 255 can be delivered through the local APIC.
+ */
+ if (vector < 16 || vector > 255)
return (EINVAL);
vlapic = vm_lapic(vm, cpu);
diff --git a/sys/amd64/vmm/vmm_stat.c b/sys/amd64/vmm/vmm_stat.c
index 9ecf9af..4ae5fb9 100644
--- a/sys/amd64/vmm/vmm_stat.c
+++ b/sys/amd64/vmm/vmm_stat.c
@@ -33,7 +33,6 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>
-#include <sys/smp.h>
#include <machine/vmm.h>
#include "vmm_util.h"
diff --git a/sys/amd64/vmm/x86.c b/sys/amd64/vmm/x86.c
index c37d21c..137c7ee 100644
--- a/sys/amd64/vmm/x86.c
+++ b/sys/amd64/vmm/x86.c
@@ -32,7 +32,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/pcpu.h>
#include <sys/systm.h>
-#include <sys/cpuset.h>
#include <sys/sysctl.h>
#include <machine/clock.h>
@@ -231,10 +230,11 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id,
regs[1] |= (vcpu_id << CPUID_0000_0001_APICID_SHIFT);
/*
- * Don't expose VMX, SpeedStep or TME capability.
+ * Don't expose VMX, SpeedStep, TME or SMX capability.
* Advertise x2APIC capability and Hypervisor guest.
*/
regs[2] &= ~(CPUID2_VMX | CPUID2_EST | CPUID2_TM2);
+ regs[2] &= ~(CPUID2_SMX);
regs[2] |= CPUID2_HV;
@@ -286,18 +286,20 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id,
* Hide thermal monitoring
*/
regs[3] &= ~(CPUID_ACPI | CPUID_TM);
-
+
/*
- * Machine check handling is done in the host.
- * Hide MTRR capability.
+ * Hide the debug store capability.
*/
- regs[3] &= ~(CPUID_MCA | CPUID_MCE | CPUID_MTRR);
-
- /*
- * Hide the debug store capability.
- */
regs[3] &= ~CPUID_DS;
+ /*
+ * Advertise the Machine Check and MTRR capability.
+ *
+ * Some guest OSes (e.g. Windows) will not boot if
+ * these features are absent.
+ */
+ regs[3] |= (CPUID_MCA | CPUID_MCE | CPUID_MTRR);
+
logical_cpus = threads_per_core * cores_per_package;
regs[1] &= ~CPUID_HTT_CORES;
regs[1] |= (logical_cpus & 0xff) << 16;
diff --git a/sys/arm/allwinner/a10_clk.c b/sys/arm/allwinner/a10_clk.c
index af7e875..ddec359 100644
--- a/sys/arm/allwinner/a10_clk.c
+++ b/sys/arm/allwinner/a10_clk.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include "a10_clk.h"
diff --git a/sys/arm/allwinner/a10_clk.h b/sys/arm/allwinner/a10_clk.h
index 3794196..2bba1a4 100644
--- a/sys/arm/allwinner/a10_clk.h
+++ b/sys/arm/allwinner/a10_clk.h
@@ -17,98 +17,98 @@
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
-#ifndef _A10_CLK_H_
-#define _A10_CLK_H_
+#ifndef _A10_CLK_H_
+#define _A10_CLK_H_
-#define CCMU_BASE 0xe1c20000
+#define CCMU_BASE 0xe1c20000
-#define CCM_PLL1_CFG 0x0000
-#define CCM_PLL1_TUN 0x0004
-#define CCM_PLL2_CFG 0x0008
-#define CCM_PLL2_TUN 0x000c
-#define CCM_PLL3_CFG 0x0010
-#define CCM_PLL3_TUN 0x0014
-#define CCM_PLL4_CFG 0x0018
-#define CCM_PLL4_TUN 0x001c
-#define CCM_PLL5_CFG 0x0020
-#define CCM_PLL5_TUN 0x0024
-#define CCM_PLL6_CFG 0x0028
-#define CCM_PLL6_TUN 0x002c
-#define CCM_PLL7_CFG 0x0030
-#define CCM_PLL7_TUN 0x0034
-#define CCM_PLL1_TUN2 0x0038
-#define CCM_PLL5_TUN2 0x003c
-#define CCM_PLL_LOCK_DBG 0x004c
-#define CCM_OSC24M_CFG 0x0050
-#define CCM_CPU_AHB_APB0_CFG 0x0054
-#define CCM_APB1_CLK_DIV 0x0058
-#define CCM_AXI_GATING 0x005c
-#define CCM_AHB_GATING0 0x0060
-#define CCM_AHB_GATING1 0x0064
-#define CCM_APB0_GATING 0x0068
-#define CCM_APB1_GATING 0x006c
-#define CCM_NAND_SCLK_CFG 0x0080
-#define CCM_MS_SCLK_CFG 0x0084
-#define CCM_MMC0_SCLK_CFG 0x0088
-#define CCM_MMC1_SCLK_CFG 0x008c
-#define CCM_MMC2_SCLK_CFG 0x0090
-#define CCM_MMC3_SCLK_CFG 0x0094
-#define CCM_TS_CLK 0x0098
-#define CCM_SS_CLK 0x009c
-#define CCM_SPI0_CLK 0x00a0
-#define CCM_SPI1_CLK 0x00a4
-#define CCM_SPI2_CLK 0x00a8
-#define CCM_PATA_CLK 0x00ac
-#define CCM_IR0_CLK 0x00b0
-#define CCM_IR1_CLK 0x00b4
-#define CCM_IIS_CLK 0x00b8
-#define CCM_AC97_CLK 0x00bc
-#define CCM_SPDIF_CLK 0x00c0
-#define CCM_KEYPAD_CLK 0x00c4
-#define CCM_SATA_CLK 0x00c8
-#define CCM_USB_CLK 0x00cc
-#define CCM_GPS_CLK 0x00d0
-#define CCM_SPI3_CLK 0x00d4
-#define CCM_DRAM_CLK 0x0100
-#define CCM_BE0_SCLK 0x0104
-#define CCM_BE1_SCLK 0x0108
-#define CCM_FE0_CLK 0x010c
-#define CCM_FE1_CLK 0x0110
-#define CCM_MP_CLK 0x0114
-#define CCM_LCD0_CH0_CLK 0x0118
-#define CCM_LCD1_CH0_CLK 0x011c
-#define CCM_CSI_ISP_CLK 0x0120
-#define CCM_TVD_CLK 0x0128
-#define CCM_LCD0_CH1_CLK 0x012c
-#define CCM_LCD1_CH1_CLK 0x0130
-#define CCM_CS0_CLK 0x0134
-#define CCM_CS1_CLK 0x0138
-#define CCM_VE_CLK 0x013c
-#define CCM_AUDIO_CODEC_CLK 0x0140
-#define CCM_AVS_CLK 0x0144
-#define CCM_ACE_CLK 0x0148
-#define CCM_LVDS_CLK 0x014c
-#define CCM_HDMI_CLK 0x0150
-#define CCM_MALI400_CLK 0x0154
+#define CCM_PLL1_CFG 0x0000
+#define CCM_PLL1_TUN 0x0004
+#define CCM_PLL2_CFG 0x0008
+#define CCM_PLL2_TUN 0x000c
+#define CCM_PLL3_CFG 0x0010
+#define CCM_PLL3_TUN 0x0014
+#define CCM_PLL4_CFG 0x0018
+#define CCM_PLL4_TUN 0x001c
+#define CCM_PLL5_CFG 0x0020
+#define CCM_PLL5_TUN 0x0024
+#define CCM_PLL6_CFG 0x0028
+#define CCM_PLL6_TUN 0x002c
+#define CCM_PLL7_CFG 0x0030
+#define CCM_PLL7_TUN 0x0034
+#define CCM_PLL1_TUN2 0x0038
+#define CCM_PLL5_TUN2 0x003c
+#define CCM_PLL_LOCK_DBG 0x004c
+#define CCM_OSC24M_CFG 0x0050
+#define CCM_CPU_AHB_APB0_CFG 0x0054
+#define CCM_APB1_CLK_DIV 0x0058
+#define CCM_AXI_GATING 0x005c
+#define CCM_AHB_GATING0 0x0060
+#define CCM_AHB_GATING1 0x0064
+#define CCM_APB0_GATING 0x0068
+#define CCM_APB1_GATING 0x006c
+#define CCM_NAND_SCLK_CFG 0x0080
+#define CCM_MS_SCLK_CFG 0x0084
+#define CCM_MMC0_SCLK_CFG 0x0088
+#define CCM_MMC1_SCLK_CFG 0x008c
+#define CCM_MMC2_SCLK_CFG 0x0090
+#define CCM_MMC3_SCLK_CFG 0x0094
+#define CCM_TS_CLK 0x0098
+#define CCM_SS_CLK 0x009c
+#define CCM_SPI0_CLK 0x00a0
+#define CCM_SPI1_CLK 0x00a4
+#define CCM_SPI2_CLK 0x00a8
+#define CCM_PATA_CLK 0x00ac
+#define CCM_IR0_CLK 0x00b0
+#define CCM_IR1_CLK 0x00b4
+#define CCM_IIS_CLK 0x00b8
+#define CCM_AC97_CLK 0x00bc
+#define CCM_SPDIF_CLK 0x00c0
+#define CCM_KEYPAD_CLK 0x00c4
+#define CCM_SATA_CLK 0x00c8
+#define CCM_USB_CLK 0x00cc
+#define CCM_GPS_CLK 0x00d0
+#define CCM_SPI3_CLK 0x00d4
+#define CCM_DRAM_CLK 0x0100
+#define CCM_BE0_SCLK 0x0104
+#define CCM_BE1_SCLK 0x0108
+#define CCM_FE0_CLK 0x010c
+#define CCM_FE1_CLK 0x0110
+#define CCM_MP_CLK 0x0114
+#define CCM_LCD0_CH0_CLK 0x0118
+#define CCM_LCD1_CH0_CLK 0x011c
+#define CCM_CSI_ISP_CLK 0x0120
+#define CCM_TVD_CLK 0x0128
+#define CCM_LCD0_CH1_CLK 0x012c
+#define CCM_LCD1_CH1_CLK 0x0130
+#define CCM_CS0_CLK 0x0134
+#define CCM_CS1_CLK 0x0138
+#define CCM_VE_CLK 0x013c
+#define CCM_AUDIO_CODEC_CLK 0x0140
+#define CCM_AVS_CLK 0x0144
+#define CCM_ACE_CLK 0x0148
+#define CCM_LVDS_CLK 0x014c
+#define CCM_HDMI_CLK 0x0150
+#define CCM_MALI400_CLK 0x0154
-#define CCM_AHB_GATING_USB0 (1 << 0)
-#define CCM_AHB_GATING_EHCI0 (1 << 1)
-#define CCM_AHB_GATING_EHCI1 (1 << 3)
-#define CCM_AHB_GATING_EMAC (1 << 17)
+#define CCM_AHB_GATING_USB0 (1 << 0)
+#define CCM_AHB_GATING_EHCI0 (1 << 1)
+#define CCM_AHB_GATING_EHCI1 (1 << 3)
+#define CCM_AHB_GATING_EMAC (1 << 17)
-#define CCM_USB_PHY (1 << 8)
-#define CCM_USB0_RESET (1 << 0)
-#define CCM_USB1_RESET (1 << 1)
-#define CCM_USB2_RESET (1 << 2)
+#define CCM_USB_PHY (1 << 8)
+#define CCM_USB0_RESET (1 << 0)
+#define CCM_USB1_RESET (1 << 1)
+#define CCM_USB2_RESET (1 << 2)
int a10_clk_usb_activate(void);
int a10_clk_usb_deactivate(void);
diff --git a/sys/arm/allwinner/a10_common.c b/sys/arm/allwinner/a10_common.c
index 9bc726e..3b5bf0e 100644
--- a/sys/arm/allwinner/a10_common.c
+++ b/sys/arm/allwinner/a10_common.c
@@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/vmparam.h>
struct fdt_fixup_entry fdt_fixup_table[] = {
diff --git a/sys/arm/allwinner/a10_gpio.c b/sys/arm/allwinner/a10_gpio.c
index 906b2c4..b2dca00 100644
--- a/sys/arm/allwinner/a10_gpio.c
+++ b/sys/arm/allwinner/a10_gpio.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/resource.h>
-#include <machine/fdt.h>
#include <machine/intr.h>
#include <dev/fdt/fdt_common.h>
diff --git a/sys/arm/allwinner/a10_sramc.c b/sys/arm/allwinner/a10_sramc.c
index fc71c7d..a26afbb 100644
--- a/sys/arm/allwinner/a10_sramc.c
+++ b/sys/arm/allwinner/a10_sramc.c
@@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/frame.h>
#include <machine/intr.h>
-#include <machine/fdt.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
diff --git a/sys/arm/allwinner/a10_wdog.c b/sys/arm/allwinner/a10_wdog.c
index af7365b..40609b0 100644
--- a/sys/arm/allwinner/a10_wdog.c
+++ b/sys/arm/allwinner/a10_wdog.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpufunc.h>
#include <machine/machdep.h>
-#include <machine/fdt.h>
#include <arm/allwinner/a10_wdog.h>
diff --git a/sys/arm/allwinner/a20/a20_cpu_cfg.c b/sys/arm/allwinner/a20/a20_cpu_cfg.c
index 81f6a50..ed0345a 100644
--- a/sys/arm/allwinner/a20/a20_cpu_cfg.c
+++ b/sys/arm/allwinner/a20/a20_cpu_cfg.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include "a20_cpu_cfg.h"
diff --git a/sys/arm/allwinner/a20/a20_mp.c b/sys/arm/allwinner/a20/a20_mp.c
index aa450a7..9429aaf 100644
--- a/sys/arm/allwinner/a20/a20_mp.c
+++ b/sys/arm/allwinner/a20/a20_mp.c
@@ -25,6 +25,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -33,6 +34,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
@@ -68,7 +72,7 @@ platform_mp_setmaxid(void)
if (mp_ncpus != 0)
return;
- /* Read current CP15 Cache Size ID Register */
+ /* Read the number of cores from the CP15 L2 Control Register. */
__asm __volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (ncpu));
ncpu = ((ncpu >> 24) & 0x3) + 1;
diff --git a/sys/arm/allwinner/a20/files.a20 b/sys/arm/allwinner/a20/files.a20
index 0edd6e8..f8d8f6f 100644
--- a/sys/arm/allwinner/a20/files.a20
+++ b/sys/arm/allwinner/a20/files.a20
@@ -1,19 +1,5 @@
# $FreeBSD$
-kern/kern_clocksource.c standard
-arm/arm/bus_space_asm_generic.S standard
-arm/arm/bus_space_generic.c standard
arm/arm/gic.c standard
-arm/allwinner/a20/a20_cpu_cfg.c standard
-arm/allwinner/a10_clk.c standard
-arm/allwinner/a10_sramc.c standard
-arm/allwinner/a10_gpio.c optional gpio
-arm/allwinner/a10_ehci.c optional ehci
-arm/allwinner/if_emac.c optional emac
-arm/allwinner/a10_wdog.c standard
-arm/allwinner/timer.c standard
-arm/arm/bus_space_base.c standard
-arm/allwinner/a10_common.c standard
-arm/allwinner/a10_machdep.c standard
arm/allwinner/a20/a20_mp.c optional smp
diff --git a/sys/arm/allwinner/a20/std.a20 b/sys/arm/allwinner/a20/std.a20
index 7d5342b..eb4fa3f 100644
--- a/sys/arm/allwinner/a20/std.a20
+++ b/sys/arm/allwinner/a20/std.a20
@@ -22,4 +22,5 @@ options ARM_L2_PIPT
options IPI_IRQ_START=0
options IPI_IRQ_END=15
+files "../allwinner/files.allwinner"
files "../allwinner/a20/files.a20"
diff --git a/sys/arm/allwinner/files.a10 b/sys/arm/allwinner/files.a10
index 8dda7cf..9f28fc4 100644
--- a/sys/arm/allwinner/files.a10
+++ b/sys/arm/allwinner/files.a10
@@ -1,19 +1,3 @@
# $FreeBSD$
-kern/kern_clocksource.c standard
-arm/arm/bus_space_asm_generic.S standard
-arm/arm/bus_space_generic.c standard
-
-arm/allwinner/a10_clk.c standard
-arm/allwinner/a10_common.c standard
-arm/allwinner/a10_gpio.c optional gpio
-arm/allwinner/a10_ehci.c optional ehci
-arm/allwinner/a10_machdep.c standard
-arm/allwinner/a10_sramc.c standard
-arm/allwinner/a10_wdog.c standard
-arm/allwinner/a20/a20_cpu_cfg.c standard
arm/allwinner/aintc.c standard
-arm/allwinner/if_emac.c optional emac
-arm/allwinner/timer.c standard
-arm/arm/bus_space_base.c standard
-#arm/allwinner/console.c standard
diff --git a/sys/arm/allwinner/files.allwinner b/sys/arm/allwinner/files.allwinner
new file mode 100644
index 0000000..9b65e7c
--- /dev/null
+++ b/sys/arm/allwinner/files.allwinner
@@ -0,0 +1,18 @@
+# $FreeBSD$
+kern/kern_clocksource.c standard
+
+arm/arm/bus_space_base.c standard
+arm/arm/bus_space_asm_generic.S standard
+arm/arm/bus_space_generic.c standard
+
+arm/allwinner/a10_clk.c standard
+arm/allwinner/a10_common.c standard
+arm/allwinner/a10_ehci.c optional ehci
+arm/allwinner/a10_gpio.c optional gpio
+arm/allwinner/a10_machdep.c standard
+arm/allwinner/a10_sramc.c standard
+arm/allwinner/a10_wdog.c standard
+arm/allwinner/a20/a20_cpu_cfg.c standard
+arm/allwinner/if_emac.c optional emac
+arm/allwinner/timer.c standard
+#arm/allwinner/console.c standard
diff --git a/sys/arm/allwinner/if_emac.c b/sys/arm/allwinner/if_emac.c
index 7828661..e311049 100644
--- a/sys/arm/allwinner/if_emac.c
+++ b/sys/arm/allwinner/if_emac.c
@@ -101,6 +101,7 @@ struct emac_softc {
int emac_watchdog_timer;
int emac_rx_process_limit;
int emac_link;
+ uint32_t emac_fifo_mask;
};
static int emac_probe(device_t);
@@ -121,7 +122,7 @@ static void emac_intr(void *);
static int emac_ioctl(struct ifnet *, u_long, caddr_t);
static void emac_rxeof(struct emac_softc *, int);
-static void emac_txeof(struct emac_softc *);
+static void emac_txeof(struct emac_softc *, uint32_t);
static int emac_miibus_readreg(device_t, int, int);
static int emac_miibus_writereg(device_t, int, int, int);
@@ -253,14 +254,28 @@ emac_reset(struct emac_softc *sc)
}
static void
-emac_txeof(struct emac_softc *sc)
+emac_drain_rxfifo(struct emac_softc *sc)
+{
+ uint32_t data;
+
+ while (EMAC_READ_REG(sc, EMAC_RX_FBC) > 0)
+ data = EMAC_READ_REG(sc, EMAC_RX_IO_DATA);
+}
+
+static void
+emac_txeof(struct emac_softc *sc, uint32_t status)
{
struct ifnet *ifp;
EMAC_ASSERT_LOCKED(sc);
ifp = sc->emac_ifp;
- if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+ status &= (EMAC_TX_FIFO0 | EMAC_TX_FIFO1);
+ sc->emac_fifo_mask &= ~status;
+ if (status == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 2);
+ else
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
/* Unarm watchdog timer if no TX */
@@ -275,7 +290,7 @@ emac_rxeof(struct emac_softc *sc, int count)
uint32_t reg_val, rxcount;
int16_t len;
uint16_t status;
- int good_packet, i;
+ int i;
ifp = sc->emac_ifp;
for (; count > 0 &&
@@ -327,20 +342,19 @@ emac_rxeof(struct emac_softc *sc, int count)
return;
}
- good_packet = 1;
-
/* Get packet size and status */
reg_val = EMAC_READ_REG(sc, EMAC_RX_IO_DATA);
len = reg_val & 0xffff;
status = (reg_val >> 16) & 0xffff;
- if (len < 64) {
- good_packet = 0;
+ if (len < 64 || (status & EMAC_PKT_OK) == 0) {
if (bootverbose)
if_printf(ifp,
"bad packet: len = %i status = %i\n",
len, status);
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ emac_drain_rxfifo(sc);
+ continue;
}
#if 0
if (status & (EMAC_CRCERR | EMAC_LENERR)) {
@@ -352,63 +366,58 @@ emac_rxeof(struct emac_softc *sc, int count)
if_printf(ifp, "length error\n");
}
#endif
- if (good_packet) {
- m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
- if (m == NULL)
- return;
- m->m_len = m->m_pkthdr.len = MCLBYTES;
-
- len -= ETHER_CRC_LEN;
-
- /* Copy entire frame to mbuf first. */
- bus_space_read_multi_4(sc->emac_tag, sc->emac_handle,
- EMAC_RX_IO_DATA, mtod(m, uint32_t *),
- roundup2(len, 4) / 4);
-
- m->m_pkthdr.rcvif = ifp;
- m->m_len = m->m_pkthdr.len = len;
-
- /*
- * Emac controller needs strict aligment, so to avoid
- * copying over an entire frame to align, we allocate
- * a new mbuf and copy ethernet header + IP header to
- * the new mbuf. The new mbuf is prepended into the
- * existing mbuf chain.
- */
- if (m->m_len <= (MHLEN - ETHER_HDR_LEN)) {
- bcopy(m->m_data, m->m_data + ETHER_HDR_LEN,
- m->m_len);
- m->m_data += ETHER_HDR_LEN;
- } else if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN) &&
- m->m_len > (MHLEN - ETHER_HDR_LEN)) {
- MGETHDR(m0, M_NOWAIT, MT_DATA);
- if (m0 != NULL) {
- len = ETHER_HDR_LEN +
- m->m_pkthdr.l2hlen;
- bcopy(m->m_data, m0->m_data, len);
- m->m_data += len;
- m->m_len -= len;
- m0->m_len = len;
- M_MOVE_PKTHDR(m0, m);
- m0->m_next = m;
- m = m0;
- } else {
- if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
- m_freem(m);
- m = NULL;
- continue;
- }
- } else if (m->m_len > EMAC_MAC_MAXF) {
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL) {
+ emac_drain_rxfifo(sc);
+ return;
+ }
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+ /* Copy entire frame to mbuf first. */
+ bus_space_read_multi_4(sc->emac_tag, sc->emac_handle,
+ EMAC_RX_IO_DATA, mtod(m, uint32_t *), roundup2(len, 4) / 4);
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_len = m->m_pkthdr.len = len - ETHER_CRC_LEN;
+
+ /*
+ * Emac controller needs strict aligment, so to avoid
+ * copying over an entire frame to align, we allocate
+ * a new mbuf and copy ethernet header + IP header to
+ * the new mbuf. The new mbuf is prepended into the
+ * existing mbuf chain.
+ */
+ if (m->m_len <= (MHLEN - ETHER_HDR_LEN)) {
+ bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, m->m_len);
+ m->m_data += ETHER_HDR_LEN;
+ } else if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN) &&
+ m->m_len > (MHLEN - ETHER_HDR_LEN)) {
+ MGETHDR(m0, M_NOWAIT, MT_DATA);
+ if (m0 != NULL) {
+ len = ETHER_HDR_LEN + m->m_pkthdr.l2hlen;
+ bcopy(m->m_data, m0->m_data, len);
+ m->m_data += len;
+ m->m_len -= len;
+ m0->m_len = len;
+ M_MOVE_PKTHDR(m0, m);
+ m0->m_next = m;
+ m = m0;
+ } else {
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
m_freem(m);
m = NULL;
continue;
}
- if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
- EMAC_UNLOCK(sc);
- (*ifp->if_input)(ifp, m);
- EMAC_LOCK(sc);
+ } else if (m->m_len > EMAC_MAC_MAXF) {
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ m_freem(m);
+ m = NULL;
+ continue;
}
+ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+ EMAC_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ EMAC_LOCK(sc);
}
}
@@ -582,11 +591,13 @@ emac_start_locked(struct ifnet *ifp)
{
struct emac_softc *sc;
struct mbuf *m, *m0;
- uint32_t reg_val;
+ uint32_t fifo, reg;
sc = ifp->if_softc;
if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
return;
+ if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+ return;
if (sc->emac_link == 0)
return;
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
@@ -594,7 +605,14 @@ emac_start_locked(struct ifnet *ifp)
return;
/* Select channel */
- EMAC_WRITE_REG(sc, EMAC_TX_INS, 0);
+ if (sc->emac_fifo_mask & EMAC_TX_FIFO0)
+ fifo = 1;
+ else
+ fifo = 0;
+ sc->emac_fifo_mask |= (1 << fifo);
+ if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ EMAC_WRITE_REG(sc, EMAC_TX_INS, fifo);
/*
* Emac controller wants 4 byte aligned TX buffers.
@@ -615,17 +633,17 @@ emac_start_locked(struct ifnet *ifp)
roundup2(m->m_len, 4) / 4);
/* Send the data lengh. */
- EMAC_WRITE_REG(sc, EMAC_TX_PL0, m->m_len);
+ reg = (fifo == 0) ? EMAC_TX_PL0 : EMAC_TX_PL1;
+ EMAC_WRITE_REG(sc, reg, m->m_len);
/* Start translate from fifo to phy. */
- reg_val = EMAC_READ_REG(sc, EMAC_TX_CTL0);
- reg_val |= 1;
- EMAC_WRITE_REG(sc, EMAC_TX_CTL0, reg_val);
+ reg = (fifo == 0) ? EMAC_TX_CTL0 : EMAC_TX_CTL1;
+ EMAC_WRITE_REG(sc, reg, EMAC_READ_REG(sc, reg) | 1);
/* Set timeout */
sc->emac_watchdog_timer = 5;
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ /* Data have been sent to hardware, it is okay to free the mbuf now. */
BPF_MTAP(ifp, m);
m_freem(m);
}
@@ -664,9 +682,6 @@ emac_intr(void *arg)
sc = (struct emac_softc *)arg;
EMAC_LOCK(sc);
- ifp = sc->emac_ifp;
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
- return;
/* Disable all interrupts */
EMAC_WRITE_REG(sc, EMAC_INT_CTL, 0);
@@ -680,18 +695,17 @@ emac_intr(void *arg)
emac_rxeof(sc, sc->emac_rx_process_limit);
/* Transmit Interrupt check */
- if (reg_val & EMAC_INT_STA_TX){
- emac_txeof(sc);
+ if (reg_val & EMAC_INT_STA_TX) {
+ emac_txeof(sc, reg_val);
+ ifp = sc->emac_ifp;
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
emac_start_locked(ifp);
}
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
- /* Re-enable interrupt mask */
- reg_val = EMAC_READ_REG(sc, EMAC_INT_CTL);
- reg_val |= EMAC_INT_EN;
- EMAC_WRITE_REG(sc, EMAC_INT_CTL, reg_val);
- }
+ /* Re-enable interrupt mask */
+ reg_val = EMAC_READ_REG(sc, EMAC_INT_CTL);
+ reg_val |= EMAC_INT_EN;
+ EMAC_WRITE_REG(sc, EMAC_INT_CTL, reg_val);
EMAC_UNLOCK(sc);
}
diff --git a/sys/arm/allwinner/if_emacreg.h b/sys/arm/allwinner/if_emacreg.h
index ee79c30..4776302 100644
--- a/sys/arm/allwinner/if_emacreg.h
+++ b/sys/arm/allwinner/if_emacreg.h
@@ -51,6 +51,8 @@
#define EMAC_TX_TSVH0 0x30
#define EMAC_TX_TSVL1 0x34
#define EMAC_TX_TSVH1 0x38
+#define EMAC_TX_FIFO0 (1 << 0)
+#define EMAC_TX_FIFO1 (1 << 1)
#define EMAC_RX_CTL 0x3C
#define EMAC_RX_HASH0 0x40
@@ -61,7 +63,7 @@
#define EMAC_INT_CTL 0x54
#define EMAC_INT_STA 0x58
-#define EMAC_INT_STA_TX (0x01 | 0x02)
+#define EMAC_INT_STA_TX (EMAC_TX_FIFO0 | EMAC_TX_FIFO1)
#define EMAC_INT_STA_RX 0x100
#define EMAC_INT_EN (0xf << 0) | (1 << 8)
@@ -223,6 +225,7 @@
/* Receive status */
#define EMAC_CRCERR (1 << 4)
#define EMAC_LENERR (3 << 5)
+#define EMAC_PKT_OK (1 << 7)
#define EMAC_RX_FLUSH_FIFO (1 << 3)
#define EMAC_PHY_RESET (1 << 15)
diff --git a/sys/arm/allwinner/std.a10 b/sys/arm/allwinner/std.a10
index fa24d5c..da5d895 100644
--- a/sys/arm/allwinner/std.a10
+++ b/sys/arm/allwinner/std.a10
@@ -17,4 +17,7 @@ options KERNPHYSADDR=0x40200000
makeoptions KERNVIRTADDR=0xc0200000
options KERNVIRTADDR=0xc0200000
+options ARM_L2_PIPT
+
+files "../allwinner/files.allwinner"
files "../allwinner/files.a10"
diff --git a/sys/arm/allwinner/timer.c b/sys/arm/allwinner/timer.c
index a04fafa..7c2a340 100644
--- a/sys/arm/allwinner/timer.c
+++ b/sys/arm/allwinner/timer.c
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <sys/kdb.h>
diff --git a/sys/arm/altera/socfpga/socfpga_gpio.c b/sys/arm/altera/socfpga/socfpga_gpio.c
index 7cec0c1..0e71d18 100644
--- a/sys/arm/altera/socfpga/socfpga_gpio.c
+++ b/sys/arm/altera/socfpga/socfpga_gpio.c
@@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/altera/socfpga/socfpga_manager.c b/sys/arm/altera/socfpga/socfpga_manager.c
index 47fd23f..3b63f79 100644
--- a/sys/arm/altera/socfpga/socfpga_manager.c
+++ b/sys/arm/altera/socfpga/socfpga_manager.c
@@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/altera/socfpga/socfpga_mp.c b/sys/arm/altera/socfpga/socfpga_mp.c
index 0942ea7..24784e9 100644
--- a/sys/arm/altera/socfpga/socfpga_mp.c
+++ b/sys/arm/altera/socfpga/socfpga_mp.c
@@ -38,6 +38,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
diff --git a/sys/arm/amlogic/aml8726/aml8726_clkmsr.c b/sys/arm/amlogic/aml8726/aml8726_clkmsr.c
index 51c9d85..da75618 100644
--- a/sys/arm/amlogic/aml8726/aml8726_clkmsr.c
+++ b/sys/arm/amlogic/aml8726/aml8726_clkmsr.c
@@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <arm/amlogic/aml8726/aml8726_soc.h>
#include <arm/amlogic/aml8726/aml8726_clkmsr.h>
@@ -147,6 +148,30 @@ aml8726_clkmsr_clock_frequency(struct aml8726_clkmsr_softc *sc, unsigned clock)
return value;
}
+static void
+aml8726_clkmsr_fixup_clk81(struct aml8726_clkmsr_softc *sc, int freq)
+{
+ pcell_t prop;
+ ssize_t len;
+ phandle_t clk_node;
+ phandle_t node;
+
+ node = ofw_bus_get_node(sc->dev);
+
+ len = OF_getencprop(node, "clocks", &prop, sizeof(prop));
+ if ((len / sizeof(prop)) != 1 || prop == 0 ||
+ (clk_node = OF_node_from_xref(prop)) == 0)
+ return;
+
+ len = OF_getencprop(clk_node, "clock-frequency", &prop, sizeof(prop));
+ if ((len / sizeof(prop)) != 1 || prop != 0)
+ return;
+
+ freq = cpu_to_fdt32(freq);
+
+ OF_setprop(clk_node, "clock-frequency", (void *)&freq, sizeof(freq));
+}
+
static int
aml8726_clkmsr_probe(device_t dev)
{
@@ -178,6 +203,8 @@ aml8726_clkmsr_attach(device_t dev)
freq = aml8726_clkmsr_clock_frequency(sc, AML_CLKMSR_CLK81);
device_printf(sc->dev, "bus clock %u MHz\n", freq);
+ aml8726_clkmsr_fixup_clk81(sc, freq * 1000000);
+
return (0);
}
@@ -209,8 +236,8 @@ static driver_t aml8726_clkmsr_driver = {
static devclass_t aml8726_clkmsr_devclass;
-DRIVER_MODULE(clkmsr, simplebus, aml8726_clkmsr_driver,
- aml8726_clkmsr_devclass, 0, 0);
+EARLY_DRIVER_MODULE(clkmsr, simplebus, aml8726_clkmsr_driver,
+ aml8726_clkmsr_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_EARLY);
int
aml8726_clkmsr_bus_frequency()
@@ -222,6 +249,9 @@ aml8726_clkmsr_bus_frequency()
u_long start, size;
int freq;
+ KASSERT(aml8726_soc_hw_rev != AML_SOC_HW_REV_UNKNOWN,
+ ("aml8726_soc_hw_rev isn't initialized"));
+
/*
* Try to access the clkmsr node directly i.e. through /aliases/.
*/
diff --git a/sys/arm/amlogic/aml8726/aml8726_fb.c b/sys/arm/amlogic/aml8726/aml8726_fb.c
index f0c9395..94d3906 100644
--- a/sys/arm/amlogic/aml8726/aml8726_fb.c
+++ b/sys/arm/amlogic/aml8726/aml8726_fb.c
@@ -49,6 +49,9 @@ __FBSDID("$FreeBSD$");
#include <sys/fbio.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/fdt.h>
diff --git a/sys/arm/amlogic/aml8726/aml8726_i2c.c b/sys/arm/amlogic/aml8726/aml8726_i2c.c
index 5e81204..c47bb6e 100644
--- a/sys/arm/amlogic/aml8726/aml8726_i2c.c
+++ b/sys/arm/amlogic/aml8726/aml8726_i2c.c
@@ -93,7 +93,7 @@ aml8726_iic_probe(device_t dev)
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_is_compatible(dev, "amlogic,aml8726-i2c"))
+ if (!ofw_bus_is_compatible(dev, "amlogic,meson6-i2c"))
return (ENXIO);
device_set_desc(dev, "Amlogic aml8726 I2C");
diff --git a/sys/arm/amlogic/aml8726/aml8726_identsoc.c b/sys/arm/amlogic/aml8726/aml8726_identsoc.c
index 2349367..b10ad16 100644
--- a/sys/arm/amlogic/aml8726/aml8726_identsoc.c
+++ b/sys/arm/amlogic/aml8726/aml8726_identsoc.c
@@ -59,8 +59,8 @@ __FBSDID("$FreeBSD$");
#include <arm/amlogic/aml8726/aml8726_soc.h>
-uint32_t aml8726_soc_hw_rev = 0xffffffff;
-uint32_t aml8726_soc_metal_rev = 0xffffffff;
+uint32_t aml8726_soc_hw_rev = AML_SOC_HW_REV_UNKNOWN;
+uint32_t aml8726_soc_metal_rev = AML_SOC_METAL_REV_UNKNOWN;
static const struct {
uint32_t hw_rev;
@@ -86,11 +86,10 @@ static const struct {
{ 0xff, NULL }
};
-static void
-aml8726_identify_soc(void *dummy)
+void
+aml8726_identify_soc()
{
int err;
- int i;
struct resource res;
memset(&res, 0, sizeof(res));
@@ -108,6 +107,12 @@ aml8726_identify_soc(void *dummy)
aml8726_soc_metal_rev = bus_read_4(&res, AML_SOC_METAL_REV_REG);
bus_space_unmap(res.r_bustag, res.r_bushandle, 0x100000);
+}
+
+static void
+aml8726_identify_announce_soc(void *dummy)
+{
+ int i;
for (i = 0; aml8726_soc_desc[i].desc; i++)
if (aml8726_soc_desc[i].hw_rev == aml8726_soc_hw_rev)
@@ -133,5 +138,5 @@ aml8726_identify_soc(void *dummy)
printf("\n");
}
-SYSINIT(aml8726_identify_soc, SI_SUB_CPU, SI_ORDER_SECOND,
- aml8726_identify_soc, NULL);
+SYSINIT(aml8726_identify_announce_soc, SI_SUB_CPU, SI_ORDER_SECOND,
+ aml8726_identify_announce_soc, NULL);
diff --git a/sys/arm/amlogic/aml8726/aml8726_machdep.c b/sys/arm/amlogic/aml8726/aml8726_machdep.c
index 0cfb31a..4476c90 100644
--- a/sys/arm/amlogic/aml8726/aml8726_machdep.c
+++ b/sys/arm/amlogic/aml8726/aml8726_machdep.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <dev/fdt/fdt_common.h>
+#include <arm/amlogic/aml8726/aml8726_soc.h>
#include <arm/amlogic/aml8726/aml8726_clkmsr.h>
#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
@@ -55,12 +56,12 @@ vm_offset_t aml8726_aobus_kva_base;
static void
aml8726_fixup_busfreq()
{
- phandle_t node, child;
+ phandle_t node;
pcell_t freq, prop;
ssize_t len;
/*
- * Set the bus-frequency for any top level SoC simple-bus which
+ * Set the bus-frequency for the SoC simple-bus if it
* needs updating (meaning the current frequency is zero).
*/
@@ -74,16 +75,6 @@ aml8726_fixup_busfreq()
len = OF_getencprop(node, "bus-frequency", &prop, sizeof(prop));
if ((len / sizeof(prop)) == 1 && prop == 0)
OF_setprop(node, "bus-frequency", (void *)&freq, sizeof(freq));
-
- for (child = OF_child(node); child != 0; child = OF_peer(child)) {
- if (fdt_is_compatible_strict(child, "simple-bus")) {
- len = OF_getencprop(child, "bus-frequency",
- &prop, sizeof(prop));
- if ((len / sizeof(prop)) == 1 && prop == 0)
- OF_setprop(child, "bus-frequency",
- (void *)&freq, sizeof(freq));
- }
- }
}
vm_offset_t
@@ -116,6 +107,13 @@ platform_gpio_init(void)
(vm_offset_t)arm_devmap_ptov(0xc8100000, 0x100000);
/*
+ * The hardware mux used by clkmsr is unique to the SoC (though
+ * currently clk81 is at a fixed location, however that might
+ * change in the future).
+ */
+ aml8726_identify_soc();
+
+ /*
* This FDT fixup should arguably be called through fdt_fixup_table,
* however currently there's no mechanism to specify a fixup which
* should always be invoked.
@@ -179,13 +177,13 @@ fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
* multi core chips also have a GIC.
*/
#ifdef SMP
- if (!fdt_is_compatible_strict(node, "arm,gic"))
+ if (!fdt_is_compatible_strict(node, "arm,cortex-a9-gic"))
#else
if (!fdt_is_compatible_strict(node, "amlogic,aml8726-pic"))
#endif
return (ENXIO);
- *interrupt = fdt32_to_cpu(intr[0]);
+ *interrupt = fdt32_to_cpu(intr[1]);
*trig = INTR_TRIGGER_EDGE;
*pol = INTR_POLARITY_HIGH;
diff --git a/sys/arm/amlogic/aml8726/aml8726_mmc.c b/sys/arm/amlogic/aml8726/aml8726_mmc.c
index b1d4935..7d1ef4e 100644
--- a/sys/arm/amlogic/aml8726/aml8726_mmc.c
+++ b/sys/arm/amlogic/aml8726/aml8726_mmc.c
@@ -70,6 +70,7 @@ struct aml8726_mmc_softc {
device_t dev;
struct resource *res[2];
struct mtx mtx;
+ struct callout ch;
uint32_t port;
unsigned int ref_freq;
struct aml8726_mmc_gpio pwr_en;
@@ -81,7 +82,7 @@ struct aml8726_mmc_softc {
struct mmc_host host;
int bus_busy;
struct mmc_command *cmd;
- unsigned int timeout_remaining;
+ uint32_t stop_timeout;
};
static struct resource_spec aml8726_mmc_spec[] = {
@@ -92,6 +93,7 @@ static struct resource_spec aml8726_mmc_spec[] = {
#define AML_MMC_LOCK(sc) mtx_lock(&(sc)->mtx)
#define AML_MMC_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
+#define AML_MMC_LOCK_ASSERT(sc) mtx_assert(&(sc)->mtx, MA_OWNED)
#define AML_MMC_LOCK_INIT(sc) \
mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
"mmc", MTX_DEF)
@@ -107,6 +109,60 @@ static struct resource_spec aml8726_mmc_spec[] = {
#define PWR_OFF_FLAG(pol) ((pol) == 0 ? GPIO_PIN_HIGH : \
GPIO_PIN_LOW)
+#define MSECS_TO_TICKS(ms) (((ms)*hz)/1000 + 1)
+
+static void aml8726_mmc_timeout(void *arg);
+
+static unsigned int
+aml8726_mmc_clk(phandle_t node)
+{
+ pcell_t prop;
+ ssize_t len;
+ phandle_t clk_node;
+
+ len = OF_getencprop(node, "clocks", &prop, sizeof(prop));
+ if ((len / sizeof(prop)) != 1 || prop == 0 ||
+ (clk_node = OF_node_from_xref(prop)) == 0)
+ return (0);
+
+ len = OF_getencprop(clk_node, "clock-frequency", &prop, sizeof(prop));
+ if ((len / sizeof(prop)) != 1 || prop == 0)
+ return (0);
+
+ return ((unsigned int)prop);
+}
+
+static uint32_t
+aml8726_mmc_freq(struct aml8726_mmc_softc *sc, uint32_t divisor)
+{
+
+ return (sc->ref_freq / ((divisor + 1) * 2));
+}
+
+static uint32_t
+aml8726_mmc_div(struct aml8726_mmc_softc *sc, uint32_t desired_freq)
+{
+ uint32_t divisor;
+
+ divisor = sc->ref_freq / (desired_freq * 2);
+
+ if (divisor == 0)
+ divisor = 1;
+
+ divisor -= 1;
+
+ if (aml8726_mmc_freq(sc, divisor) > desired_freq)
+ divisor += 1;
+
+ if (divisor > (AML_MMC_CONFIG_CMD_CLK_DIV_MASK >>
+ AML_MMC_CONFIG_CMD_CLK_DIV_SHIFT)) {
+ divisor = AML_MMC_CONFIG_CMD_CLK_DIV_MASK >>
+ AML_MMC_CONFIG_CMD_CLK_DIV_SHIFT;
+ }
+
+ return (divisor);
+}
+
static void
aml8726_mmc_mapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
@@ -143,25 +199,18 @@ aml8726_mmc_power_on(struct aml8726_mmc_softc *sc)
PWR_ON_FLAG(sc->pwr_en.pol)));
}
-static int
-aml8726_mmc_restart_timer(struct aml8726_mmc_softc *sc)
+static void
+aml8726_mmc_soft_reset(struct aml8726_mmc_softc *sc, boolean_t enable_irq)
{
- uint32_t count;
- uint32_t isr;
-
- if (sc->cmd == NULL || sc->timeout_remaining == 0)
- return (0);
-
- count = (sc->timeout_remaining > 0x1fff) ? 0x1fff :
- sc->timeout_remaining;
- sc->timeout_remaining -= count;
+ uint32_t icr;
- isr = (count << AML_MMC_IRQ_STATUS_TIMER_CNT_SHIFT) |
- AML_MMC_IRQ_STATUS_TIMER_EN | AML_MMC_IRQ_STATUS_TIMEOUT_IRQ;
+ icr = AML_MMC_IRQ_CONFIG_SOFT_RESET;
- CSR_WRITE_4(sc, AML_MMC_IRQ_STATUS_REG, isr);
+ if (enable_irq == true)
+ icr |= AML_MMC_IRQ_CONFIG_CMD_DONE_EN;
- return (1);
+ CSR_WRITE_4(sc, AML_MMC_IRQ_CONFIG_REG, icr);
+ CSR_BARRIER(sc, AML_MMC_IRQ_CONFIG_REG);
}
static int
@@ -172,7 +221,6 @@ aml8726_mmc_start_command(struct aml8726_mmc_softc *sc, struct mmc_command *cmd)
uint32_t block_size;
uint32_t bus_width;
uint32_t cmdr;
- uint32_t cycles_per_msec;
uint32_t extr;
uint32_t mcfgr;
uint32_t nbits_per_pkg;
@@ -184,14 +232,9 @@ aml8726_mmc_start_command(struct aml8726_mmc_softc *sc, struct mmc_command *cmd)
return (MMC_ERR_INVALID);
/*
- * Ensure the hardware state machine is in a known state,
- * the command done interrupt is enabled, and previous
- * IRQ status bits have been cleared.
+ * Ensure the hardware state machine is in a known state.
*/
- CSR_WRITE_4(sc, AML_MMC_IRQ_CONFIG_REG,
- (AML_MMC_IRQ_CONFIG_SOFT_RESET | AML_MMC_IRQ_CONFIG_CMD_DONE_EN));
- CSR_BARRIER(sc, AML_MMC_IRQ_CONFIG_REG);
- CSR_WRITE_4(sc, AML_MMC_IRQ_STATUS_REG, AML_MMC_IRQ_STATUS_CLEAR_IRQ);
+ aml8726_mmc_soft_reset(sc, true);
/*
* Start and transmission bits are per section 4.7.2 of the:
@@ -206,6 +249,13 @@ aml8726_mmc_start_command(struct aml8726_mmc_softc *sc, struct mmc_command *cmd)
mcfgr = sc->port;
timeout = AML_MMC_CMD_TIMEOUT;
+ /*
+ * If this is a linked command, then use the previous timeout.
+ */
+ if (cmd == cmd->mrq->stop && sc->stop_timeout)
+ timeout = sc->stop_timeout;
+ sc->stop_timeout = 0;
+
if ((cmd->flags & MMC_RSP_136) != 0) {
cmdr |= AML_MMC_CMD_RESP_CRC7_FROM_8;
cmdr |= (133 << AML_MMC_CMD_RESP_BITS_SHIFT);
@@ -272,32 +322,24 @@ aml8726_mmc_start_command(struct aml8726_mmc_softc *sc, struct mmc_command *cmd)
timeout = AML_MMC_WRITE_TIMEOUT *
(data->len / block_size);
}
+
+ /*
+ * Stop terminates a multiblock read / write and thus
+ * can take as long to execute as an actual read / write.
+ */
+ if (cmd->mrq->stop != NULL)
+ sc->stop_timeout = timeout;
}
sc->cmd = cmd;
cmd->error = MMC_ERR_NONE;
- /*
- * Round up while calculating the number of cycles which
- * correspond to a millisecond. Use that to determine
- * the count from the desired timeout in milliseconds.
- *
- * The counter has a limited range which is not sufficient
- * for directly implementing worst case timeouts at high clock
- * rates so a 32 bit counter is implemented in software.
- *
- * The documentation isn't clear on when the timer starts
- * so add 48 cycles for the command and 136 cycles for the
- * response (the values are from the previously mentioned
- * standard).
- */
if (timeout > AML_MMC_MAX_TIMEOUT)
timeout = AML_MMC_MAX_TIMEOUT;
- cycles_per_msec = (ios->clock + 1000 - 1) / 1000;
- sc->timeout_remaining = 48 + 136 + timeout * cycles_per_msec;
- aml8726_mmc_restart_timer(sc);
+ callout_reset(&sc->ch, MSECS_TO_TICKS(timeout),
+ aml8726_mmc_timeout, sc);
CSR_WRITE_4(sc, AML_MMC_CMD_ARGUMENT_REG, cmd->arg);
CSR_WRITE_4(sc, AML_MMC_MULT_CONFIG_REG, mcfgr);
@@ -311,20 +353,96 @@ aml8726_mmc_start_command(struct aml8726_mmc_softc *sc, struct mmc_command *cmd)
}
static void
-aml8726_mmc_intr(void *arg)
+aml8726_mmc_finish_command(struct aml8726_mmc_softc *sc, int mmc_error)
{
- struct aml8726_mmc_softc *sc = (struct aml8726_mmc_softc *)arg;
+ int mmc_stop_error;
struct mmc_command *cmd;
struct mmc_command *stop_cmd;
struct mmc_data *data;
+
+ AML_MMC_LOCK_ASSERT(sc);
+
+ /* Clear all interrupts since the request is no longer in flight. */
+ CSR_WRITE_4(sc, AML_MMC_IRQ_STATUS_REG, AML_MMC_IRQ_STATUS_CLEAR_IRQ);
+ CSR_BARRIER(sc, AML_MMC_IRQ_STATUS_REG);
+
+ /* In some cases (e.g. finish called via timeout) this is a NOP. */
+ callout_stop(&sc->ch);
+
+ cmd = sc->cmd;
+ sc->cmd = NULL;
+
+ cmd->error = mmc_error;
+
+ data = cmd->data;
+
+ if (data && data->len &&
+ (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) != 0) {
+ if ((data->flags & MMC_DATA_READ) != 0)
+ bus_dmamap_sync(sc->dmatag, sc->dmamap,
+ BUS_DMASYNC_POSTREAD);
+ else
+ bus_dmamap_sync(sc->dmatag, sc->dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->dmatag, sc->dmamap);
+ }
+
+ /*
+ * If there's a linked stop command, then start the stop command.
+ * In order to establish a known state attempt the stop command
+ * even if the original request encountered an error.
+ */
+
+ stop_cmd = (cmd->mrq->stop != cmd) ? cmd->mrq->stop : NULL;
+
+ if (stop_cmd != NULL) {
+ mmc_stop_error = aml8726_mmc_start_command(sc, stop_cmd);
+ if (mmc_stop_error == MMC_ERR_NONE) {
+ AML_MMC_UNLOCK(sc);
+ return;
+ }
+ stop_cmd->error = mmc_stop_error;
+ }
+
+ AML_MMC_UNLOCK(sc);
+
+ /* Execute the callback after dropping the lock. */
+ if (cmd->mrq)
+ cmd->mrq->done(cmd->mrq);
+}
+
+static void
+aml8726_mmc_timeout(void *arg)
+{
+ struct aml8726_mmc_softc *sc = (struct aml8726_mmc_softc *)arg;
+
+ /*
+ * The command failed to complete in time so forcefully
+ * terminate it.
+ */
+ aml8726_mmc_soft_reset(sc, false);
+
+ /*
+ * Ensure the command has terminated before continuing on
+ * to things such as bus_dmamap_sync / bus_dmamap_unload.
+ */
+ while ((CSR_READ_4(sc, AML_MMC_IRQ_STATUS_REG) &
+ AML_MMC_IRQ_STATUS_CMD_BUSY) != 0)
+ cpu_spinwait();
+
+ aml8726_mmc_finish_command(sc, MMC_ERR_TIMEOUT);
+}
+
+static void
+aml8726_mmc_intr(void *arg)
+{
+ struct aml8726_mmc_softc *sc = (struct aml8726_mmc_softc *)arg;
uint32_t cmdr;
- uint32_t icr;
uint32_t isr;
uint32_t mcfgr;
uint32_t previous_byte;
uint32_t resp;
int mmc_error;
- int mmc_stop_error;
unsigned int i;
AML_MMC_LOCK(sc);
@@ -348,12 +466,6 @@ aml8726_mmc_intr(void *arg)
if ((cmdr & AML_MMC_CMD_CMD_HAS_DATA) != 0 &&
(isr & AML_MMC_IRQ_STATUS_WR_CRC16_OK) == 0)
mmc_error = MMC_ERR_BADCRC;
- } else if ((isr & AML_MMC_IRQ_STATUS_TIMEOUT_IRQ) != 0) {
- if (aml8726_mmc_restart_timer(sc) != 0) {
- AML_MMC_UNLOCK(sc);
- return;
- }
- mmc_error = MMC_ERR_TIMEOUT;
} else {
spurious:
@@ -370,49 +482,12 @@ spurious:
return;
}
- if ((isr & AML_MMC_IRQ_STATUS_CMD_BUSY) != 0 &&
- /*
- * A multiblock operation may keep the hardware
- * busy until stop transmission is executed.
- */
- (isr & AML_MMC_IRQ_STATUS_CMD_DONE_IRQ) == 0) {
- if (mmc_error == MMC_ERR_NONE)
- mmc_error = MMC_ERR_FAILED;
-
- /*
- * Issue a soft reset (while leaving the command complete
- * interrupt enabled) to terminate the command.
- *
- * Ensure the command has terminated before continuing on
- * to things such as bus_dmamap_sync / bus_dmamap_unload.
- */
-
- icr = AML_MMC_IRQ_CONFIG_SOFT_RESET |
- AML_MMC_IRQ_CONFIG_CMD_DONE_EN;
-
- CSR_WRITE_4(sc, AML_MMC_IRQ_CONFIG_REG, icr);
-
- while ((CSR_READ_4(sc, AML_MMC_IRQ_STATUS_REG) &
- AML_MMC_IRQ_STATUS_CMD_BUSY) != 0)
- cpu_spinwait();
- }
-
- /* Clear all interrupts since the request is no longer in flight. */
- CSR_WRITE_4(sc, AML_MMC_IRQ_STATUS_REG, AML_MMC_IRQ_STATUS_CLEAR_IRQ);
- CSR_BARRIER(sc, AML_MMC_IRQ_STATUS_REG);
-
- cmd = sc->cmd;
- sc->cmd = NULL;
-
- cmd->error = mmc_error;
-
- if ((cmd->flags & MMC_RSP_PRESENT) != 0 &&
- mmc_error == MMC_ERR_NONE) {
+ if ((cmdr & AML_MMC_CMD_RESP_BITS_MASK) != 0) {
mcfgr = sc->port;
mcfgr |= AML_MMC_MULT_CONFIG_RESP_READOUT_EN;
CSR_WRITE_4(sc, AML_MMC_MULT_CONFIG_REG, mcfgr);
- if ((cmd->flags & MMC_RSP_136) != 0) {
+ if ((cmdr & AML_MMC_CMD_RESP_CRC7_FROM_8) != 0) {
/*
* Controller supplies 135:8 instead of
@@ -425,48 +500,39 @@ spurious:
for (i = 0; i < 4; i++) {
resp = CSR_READ_4(sc, AML_MMC_CMD_ARGUMENT_REG);
- cmd->resp[3 - i] = (resp << 8) | previous_byte;
+ sc->cmd->resp[3 - i] = (resp << 8) |
+ previous_byte;
previous_byte = (resp >> 24) & 0xff;
}
} else
- cmd->resp[0] = CSR_READ_4(sc, AML_MMC_CMD_ARGUMENT_REG);
+ sc->cmd->resp[0] = CSR_READ_4(sc,
+ AML_MMC_CMD_ARGUMENT_REG);
}
- data = cmd->data;
-
- if (data && data->len &&
- (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) != 0) {
- if ((data->flags & MMC_DATA_READ) != 0)
- bus_dmamap_sync(sc->dmatag, sc->dmamap,
- BUS_DMASYNC_POSTREAD);
- else
- bus_dmamap_sync(sc->dmatag, sc->dmamap,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->dmatag, sc->dmamap);
- }
+ if ((isr & AML_MMC_IRQ_STATUS_CMD_BUSY) != 0 &&
+ /*
+ * A multiblock operation may keep the hardware
+ * busy until stop transmission is executed.
+ */
+ (isr & AML_MMC_IRQ_STATUS_CMD_DONE_IRQ) == 0) {
+ if (mmc_error == MMC_ERR_NONE)
+ mmc_error = MMC_ERR_FAILED;
- /*
- * If there's a linked stop command, then start the stop command.
- * In order to establish a known state attempt the stop command
- * even if the original request encountered an error.
- */
+ /*
+ * Issue a soft reset to terminate the command.
+ *
+ * Ensure the command has terminated before continuing on
+ * to things such as bus_dmamap_sync / bus_dmamap_unload.
+ */
- stop_cmd = (cmd->mrq->stop != cmd) ? cmd->mrq->stop : NULL;
+ aml8726_mmc_soft_reset(sc, false);
- if (stop_cmd != NULL) {
- mmc_stop_error = aml8726_mmc_start_command(sc, stop_cmd);
- if (mmc_stop_error == MMC_ERR_NONE) {
- AML_MMC_UNLOCK(sc);
- return;
- }
- stop_cmd->error = mmc_stop_error;
+ while ((CSR_READ_4(sc, AML_MMC_IRQ_STATUS_REG) &
+ AML_MMC_IRQ_STATUS_CMD_BUSY) != 0)
+ cpu_spinwait();
}
- AML_MMC_UNLOCK(sc);
-
- /* Execute the callback after dropping the lock. */
- if (cmd->mrq)
- cmd->mrq->done(cmd->mrq);
+ aml8726_mmc_finish_command(sc, mmc_error);
}
static int
@@ -502,15 +568,13 @@ aml8726_mmc_attach(device_t dev)
node = ofw_bus_get_node(dev);
- len = OF_getencprop(OF_parent(node), "bus-frequency",
- prop, sizeof(prop));
- if ((len / sizeof(prop[0])) != 1 || prop[0] == 0) {
- device_printf(dev, "missing bus-frequency attribute in FDT\n");
+ sc->ref_freq = aml8726_mmc_clk(node);
+
+ if (sc->ref_freq == 0) {
+ device_printf(dev, "missing clocks attribute in FDT\n");
return (ENXIO);
}
- sc->ref_freq = prop[0];
-
/*
* The pins must be specified as part of the device in order
* to know which port to used.
@@ -681,8 +745,10 @@ aml8726_mmc_attach(device_t dev)
goto fail;
}
- sc->host.f_min = 200000;
- sc->host.f_max = 50000000;
+ callout_init_mtx(&sc->ch, &sc->mtx, CALLOUT_RETURNUNLOCKED);
+
+ sc->host.f_min = aml8726_mmc_freq(sc, aml8726_mmc_div(sc, 200000));
+ sc->host.f_max = aml8726_mmc_freq(sc, aml8726_mmc_div(sc, 50000000));
sc->host.host_ocr = sc->voltages[0] | sc->voltages[1];
sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED;
@@ -739,10 +805,12 @@ aml8726_mmc_detach(device_t dev)
* disable the interrupts, and clear the interrupts.
*/
(void)aml8726_mmc_power_off(sc);
- CSR_WRITE_4(sc, AML_MMC_IRQ_CONFIG_REG, AML_MMC_IRQ_CONFIG_SOFT_RESET);
- CSR_BARRIER(sc, AML_MMC_IRQ_CONFIG_REG);
+ aml8726_mmc_soft_reset(sc, false);
CSR_WRITE_4(sc, AML_MMC_IRQ_STATUS_REG, AML_MMC_IRQ_STATUS_CLEAR_IRQ);
+ /* This should be a NOP since no command was in flight. */
+ callout_stop(&sc->ch);
+
AML_MMC_UNLOCK(sc);
bus_generic_detach(dev);
@@ -770,8 +838,7 @@ aml8726_mmc_shutdown(device_t dev)
* disable the interrupts, and clear the interrupts.
*/
(void)aml8726_mmc_power_off(sc);
- CSR_WRITE_4(sc, AML_MMC_IRQ_CONFIG_REG, AML_MMC_IRQ_CONFIG_SOFT_RESET);
- CSR_BARRIER(sc, AML_MMC_IRQ_CONFIG_REG);
+ aml8726_mmc_soft_reset(sc, false);
CSR_WRITE_4(sc, AML_MMC_IRQ_STATUS_REG, AML_MMC_IRQ_STATUS_CLEAR_IRQ);
return (0);
@@ -782,7 +849,6 @@ aml8726_mmc_update_ios(device_t bus, device_t child)
{
struct aml8726_mmc_softc *sc = device_get_softc(bus);
struct mmc_ios *ios = &sc->host.ios;
- unsigned int divisor;
int error;
int i;
uint32_t cfgr;
@@ -803,15 +869,8 @@ aml8726_mmc_update_ios(device_t bus, device_t child)
return (EINVAL);
}
- divisor = sc->ref_freq / (ios->clock * 2) - 1;
- if (divisor == 0 || divisor == -1)
- divisor = 1;
- if ((sc->ref_freq / ((divisor + 1) * 2)) > ios->clock)
- divisor += 1;
- if (divisor > 0x3ff)
- divisor = 0x3ff;
-
- cfgr |= divisor;
+ cfgr |= aml8726_mmc_div(sc, ios->clock) <<
+ AML_MMC_CONFIG_CMD_CLK_DIV_SHIFT;
CSR_WRITE_4(sc, AML_MMC_CONFIG_REG, cfgr);
diff --git a/sys/arm/amlogic/aml8726/aml8726_mmc.h b/sys/arm/amlogic/aml8726/aml8726_mmc.h
index 0370943..64e3bae 100644
--- a/sys/arm/amlogic/aml8726/aml8726_mmc.h
+++ b/sys/arm/amlogic/aml8726/aml8726_mmc.h
@@ -47,20 +47,6 @@
#define AML_MMC_WRITE_TIMEOUT 500
#define AML_MMC_MAX_TIMEOUT 5000
-/*
- * Internally the timeout is implemented by counting clock cycles.
- *
- * Since the hardware implements timeouts by counting cycles
- * the minimum read / write timeout (assuming the minimum
- * conversion factor of 1 cycle per usec) is:
- *
- * (8 bits * 512 bytes per block + 16 bits CRC) = 4112 usec
- */
-#if ((AML_MMC_READ_TIMEOUT * 1000) < 4112 || \
- (AML_MMC_WRITE_TIMEOUT * 1000) < 4112)
-#error "Single block timeout is smaller than supported"
-#endif
-
#define AML_MMC_CMD_ARGUMENT_REG 0
#define AML_MMC_CMD_SEND_REG 4
diff --git a/sys/arm/amlogic/aml8726/aml8726_mp.c b/sys/arm/amlogic/aml8726/aml8726_mp.c
index c4aa43a..4f0bce0 100644
--- a/sys/arm/amlogic/aml8726/aml8726_mp.c
+++ b/sys/arm/amlogic/aml8726/aml8726_mp.c
@@ -50,6 +50,9 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/bus.h>
#include <machine/smp.h>
#include <machine/fdt.h>
diff --git a/sys/arm/amlogic/aml8726/aml8726_soc.h b/sys/arm/amlogic/aml8726/aml8726_soc.h
index e45a5df..45e3bc4 100644
--- a/sys/arm/amlogic/aml8726/aml8726_soc.h
+++ b/sys/arm/amlogic/aml8726/aml8726_soc.h
@@ -32,8 +32,11 @@
#define AML_SOC_AOBUS_BASE_ADDR 0xc8100000
#define AML_SOC_CBUS_BASE_ADDR 0xc1100000
+void aml8726_identify_soc(void);
+
/* cbus */
#define AML_SOC_HW_REV_REG 0x7d4c
+#define AML_SOC_HW_REV_UNKNOWN 0xffffffff
#define AML_SOC_HW_REV_M3 0x15
#define AML_SOC_HW_REV_M6 0x16
#define AML_SOC_HW_REV_M6TV 0x17
@@ -42,6 +45,7 @@
#define AML_SOC_HW_REV_M8B 0x1b
#define AML_SOC_METAL_REV_REG 0x81a8
+#define AML_SOC_METAL_REV_UNKNOWN 0xffffffff
#define AML_SOC_M8_METAL_REV_A 0x11111111
#define AML_SOC_M8_METAL_REV_M2_A 0x11111112
#define AML_SOC_M8_METAL_REV_B 0x11111113
diff --git a/sys/arm/amlogic/aml8726/aml8726_timer.c b/sys/arm/amlogic/aml8726/aml8726_timer.c
index 074d51d..6061703 100644
--- a/sys/arm/amlogic/aml8726/aml8726_timer.c
+++ b/sys/arm/amlogic/aml8726/aml8726_timer.c
@@ -226,7 +226,7 @@ aml8726_timer_probe(device_t dev)
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_is_compatible(dev, "amlogic,aml8726-timer"))
+ if (!ofw_bus_is_compatible(dev, "amlogic,meson6-timer"))
return (ENXIO);
device_set_desc(dev, "Amlogic aml8726 timer");
diff --git a/sys/arm/amlogic/aml8726/aml8726_wdt.c b/sys/arm/amlogic/aml8726/aml8726_wdt.c
index ca9b755..1e89f81 100644
--- a/sys/arm/amlogic/aml8726/aml8726_wdt.c
+++ b/sys/arm/amlogic/aml8726/aml8726_wdt.c
@@ -167,7 +167,7 @@ aml8726_wdt_probe(device_t dev)
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_is_compatible(dev, "amlogic,aml8726-wdt"))
+ if (!ofw_bus_is_compatible(dev, "amlogic,meson6-wdt"))
return (ENXIO);
device_set_desc(dev, "Amlogic aml8726 WDT");
diff --git a/sys/arm/amlogic/aml8726/files.aml8726 b/sys/arm/amlogic/aml8726/files.aml8726
index b32ebcd..ca058a5 100644
--- a/sys/arm/amlogic/aml8726/files.aml8726
+++ b/sys/arm/amlogic/aml8726/files.aml8726
@@ -4,12 +4,13 @@ kern/kern_clocksource.c standard
arm/arm/bus_space_base.c standard
arm/arm/bus_space_generic.c standard
-arm/arm/bus_space_asm_generic.S standard
+arm/arm/gic.c standard
arm/arm/pl310.c standard
arm/amlogic/aml8726/aml8726_l2cache.c standard
arm/amlogic/aml8726/aml8726_machdep.c standard
+arm/amlogic/aml8726/aml8726_mp.c optional smp
arm/amlogic/aml8726/aml8726_identsoc.c standard
arm/amlogic/aml8726/aml8726_ccm.c standard
arm/amlogic/aml8726/aml8726_clkmsr.c standard
diff --git a/sys/arm/amlogic/aml8726/files.smp b/sys/arm/amlogic/aml8726/files.smp
deleted file mode 100644
index 9b6c6ab..0000000
--- a/sys/arm/amlogic/aml8726/files.smp
+++ /dev/null
@@ -1,4 +0,0 @@
-#$FreeBSD$
-
-arm/arm/gic.c standard
-arm/amlogic/aml8726/aml8726_mp.c standard
diff --git a/sys/arm/amlogic/aml8726/std.aml8726 b/sys/arm/amlogic/aml8726/std.aml8726
index 073f02c..61b515f 100644
--- a/sys/arm/amlogic/aml8726/std.aml8726
+++ b/sys/arm/amlogic/aml8726/std.aml8726
@@ -4,6 +4,15 @@ cpu CPU_CORTEXA
machine arm armv6
makeoptions CONF_CFLAGS="-march=armv7a"
+# Physical memory starts at 0x80000000. We assume the kernel is loaded
+# at 0x80100000 by u-boot (which doesn't support ubldr since it's missing
+# CONFIG_API). The kernel must be supplied as a binary since u-boot is
+# also missing CONFIG_CMD_ELF.
+#
+#
+options KERNVIRTADDR=0xc0100000 # Used in ldscript.arm
+makeoptions KERNVIRTADDR=0xc0100000
+
device fdt_pinctrl
files "../amlogic/aml8726/files.aml8726"
diff --git a/sys/arm/amlogic/aml8726/std.odroidc1 b/sys/arm/amlogic/aml8726/std.odroidc1
deleted file mode 100644
index 441c135..0000000
--- a/sys/arm/amlogic/aml8726/std.odroidc1
+++ /dev/null
@@ -1,17 +0,0 @@
-# $FreeBSD$
-
-include "../amlogic/aml8726/std.aml8726"
-
-makeoptions FDT_DTS_FILE=odroidc1.dts
-
-options SMP # Enable multiple cores
-files "../amlogic/aml8726/files.smp"
-
-# Physical memory starts at 0x00000000. We assume the kernel is loaded
-# at 0x00100000 by u-boot (which doesn't support ubldr since it's missing
-# CONFIG_API). The kernel must be supplied as a binary since u-boot is
-# also missing CONFIG_CMD_ELF.
-#
-#
-options KERNVIRTADDR=0xc0100000 # Used in ldscript.arm
-makeoptions KERNVIRTADDR=0xc0100000
diff --git a/sys/arm/amlogic/aml8726/std.vsatv102-m6 b/sys/arm/amlogic/aml8726/std.vsatv102-m6
deleted file mode 100644
index e0014a4..0000000
--- a/sys/arm/amlogic/aml8726/std.vsatv102-m6
+++ /dev/null
@@ -1,17 +0,0 @@
-# $FreeBSD$
-
-include "../amlogic/aml8726/std.aml8726"
-
-makeoptions FDT_DTS_FILE=vsatv102-m6.dts
-
-options SMP # Enable multiple cores
-files "../amlogic/aml8726/files.smp"
-
-# Physical memory starts at 0x80000000. We assume the kernel is loaded
-# at 0x80100000 by u-boot (which doesn't support ubldr since it's missing
-# CONFIG_API). The kernel must be supplied as a binary since u-boot is
-# also missing CONFIG_CMD_ELF.
-#
-#
-options KERNVIRTADDR=0xc0100000 # Used in ldscript.arm
-makeoptions KERNVIRTADDR=0xc0100000
diff --git a/sys/arm/amlogic/aml8726/uart_dev_aml8726.c b/sys/arm/amlogic/aml8726/uart_dev_aml8726.c
index 6c1e85e..1dda52f 100644
--- a/sys/arm/amlogic/aml8726/uart_dev_aml8726.c
+++ b/sys/arm/amlogic/aml8726/uart_dev_aml8726.c
@@ -48,6 +48,10 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpu.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
#include <dev/uart/uart.h>
#include <dev/uart/uart_cpu.h>
#include <dev/uart/uart_cpu_fdt.h>
@@ -262,6 +266,25 @@ struct uart_ops aml8726_uart_ops = {
.getc = aml8726_uart_getc,
};
+static unsigned int
+aml8726_uart_bus_clk(phandle_t node)
+{
+ pcell_t prop;
+ ssize_t len;
+ phandle_t clk_node;
+
+ len = OF_getencprop(node, "clocks", &prop, sizeof(prop));
+ if ((len / sizeof(prop)) != 1 || prop == 0 ||
+ (clk_node = OF_node_from_xref(prop)) == 0)
+ return (0);
+
+ len = OF_getencprop(clk_node, "clock-frequency", &prop, sizeof(prop));
+ if ((len / sizeof(prop)) != 1 || prop == 0)
+ return (0);
+
+ return ((unsigned int)prop);
+}
+
static int
aml8726_uart_bus_probe(struct uart_softc *sc)
{
@@ -330,8 +353,10 @@ aml8726_uart_bus_attach(struct uart_softc *sc)
bas = &sc->sc_bas;
+ bas->rclk = aml8726_uart_bus_clk(ofw_bus_get_node(sc->sc_dev));
+
if (bas->rclk == 0) {
- device_printf(sc->sc_dev, "missing clock attribute in FDT\n");
+ device_printf(sc->sc_dev, "missing clocks attribute in FDT\n");
return (ENXIO);
}
@@ -699,11 +724,12 @@ struct uart_class uart_aml8726_class = {
sizeof(struct uart_softc),
.uc_ops = &aml8726_uart_ops,
.uc_range = 24,
- .uc_rclk = 0
+ .uc_rclk = 0,
+ .uc_rshift = 0
};
static struct ofw_compat_data compat_data[] = {
- { "amlogic,aml8726-uart", (uintptr_t)&uart_aml8726_class },
+ { "amlogic,meson-uart", (uintptr_t)&uart_aml8726_class },
{ NULL, (uintptr_t)NULL }
};
UART_FDT_CLASS_AND_DEVICE(compat_data);
diff --git a/sys/arm/arm/busdma_machdep-v6.c b/sys/arm/arm/busdma_machdep-v6.c
index ed501c5..7236c5a 100644
--- a/sys/arm/arm/busdma_machdep-v6.c
+++ b/sys/arm/arm/busdma_machdep-v6.c
@@ -1685,8 +1685,8 @@ add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
/* Page offset needs to be preserved. */
- bpage->vaddr |= vaddr & PAGE_MASK;
- bpage->busaddr |= vaddr & PAGE_MASK;
+ bpage->vaddr |= addr & PAGE_MASK;
+ bpage->busaddr |= addr & PAGE_MASK;
}
bpage->datavaddr = vaddr;
bpage->dataaddr = addr;
diff --git a/sys/arm/arm/busdma_machdep.c b/sys/arm/arm/busdma_machdep.c
index 265292d..acd8f81 100644
--- a/sys/arm/arm/busdma_machdep.c
+++ b/sys/arm/arm/busdma_machdep.c
@@ -1441,8 +1441,8 @@ add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
/* Page offset needs to be preserved. */
- bpage->vaddr |= vaddr & PAGE_MASK;
- bpage->busaddr |= vaddr & PAGE_MASK;
+ bpage->vaddr |= addr & PAGE_MASK;
+ bpage->busaddr |= addr & PAGE_MASK;
}
bpage->datavaddr = vaddr;
bpage->dataaddr = addr;
diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c
index f98e91a..a3c8239 100644
--- a/sys/arm/arm/cpufunc.c
+++ b/sys/arm/arm/cpufunc.c
@@ -1186,7 +1186,8 @@ arm11x6_setup(void)
CPU_CONTROL_32BD_ENABLE |
CPU_CONTROL_LABT_ENABLE |
CPU_CONTROL_SYST_ENABLE |
- CPU_CONTROL_IC_ENABLE;
+ CPU_CONTROL_IC_ENABLE |
+ CPU_CONTROL_UNAL_ENABLE;
/*
* "write as existing" bits
diff --git a/sys/arm/arm/devmap.c b/sys/arm/arm/devmap.c
index 1c60a15..823210f 100644
--- a/sys/arm/arm/devmap.c
+++ b/sys/arm/arm/devmap.c
@@ -29,6 +29,8 @@ __FBSDID("$FreeBSD$");
/*
* Routines for mapping device memory.
+ *
+ * This is used on both arm and arm64.
*/
#include "opt_ddb.h"
@@ -40,10 +42,18 @@ __FBSDID("$FreeBSD$");
#include <vm/pmap.h>
#include <machine/armreg.h>
#include <machine/devmap.h>
+#include <machine/vmparam.h>
static const struct arm_devmap_entry *devmap_table;
static boolean_t devmap_bootstrap_done = false;
+#if defined(__aarch64__)
+#define MAX_VADDR VM_MAX_KERNEL_ADDRESS
+#define PTE_DEVICE VM_MEMATTR_DEVICE
+#elif defined(__arm__)
+#define MAX_VADDR ARM_VECTORS_HIGH
+#endif
+
/*
* The allocated-kva (akva) devmap table and metadata. Platforms can call
* arm_devmap_add_entry() to add static device mappings to this table using
@@ -53,7 +63,11 @@ static boolean_t devmap_bootstrap_done = false;
#define AKVA_DEVMAP_MAX_ENTRIES 32
static struct arm_devmap_entry akva_devmap_entries[AKVA_DEVMAP_MAX_ENTRIES];
static u_int akva_devmap_idx;
-static vm_offset_t akva_devmap_vaddr = ARM_VECTORS_HIGH;
+static vm_offset_t akva_devmap_vaddr = MAX_VADDR;
+
+#ifdef __aarch64__
+extern int early_boot;
+#endif
/*
* Print the contents of the static mapping table using the provided printf-like
@@ -99,7 +113,7 @@ arm_devmap_lastaddr()
if (akva_devmap_idx > 0)
return (akva_devmap_vaddr);
- lowaddr = ARM_VECTORS_HIGH;
+ lowaddr = MAX_VADDR;
for (pd = devmap_table; pd != NULL && pd->pd_size != 0; ++pd) {
if (lowaddr > pd->pd_va)
lowaddr = pd->pd_va;
@@ -136,9 +150,12 @@ arm_devmap_add_entry(vm_paddr_t pa, vm_size_t sz)
* align the virtual address to the next-lower 1MB boundary so that we
* end up with a nice efficient section mapping.
*/
+#ifdef __arm__
if ((pa & 0x000fffff) == 0 && (sz & 0x000fffff) == 0) {
akva_devmap_vaddr = trunc_1mpage(akva_devmap_vaddr - sz);
- } else {
+ } else
+#endif
+ {
akva_devmap_vaddr = trunc_page(akva_devmap_vaddr - sz);
}
m = &akva_devmap_entries[akva_devmap_idx++];
@@ -186,8 +203,12 @@ arm_devmap_bootstrap(vm_offset_t l1pt, const struct arm_devmap_entry *table)
return;
for (pd = devmap_table; pd->pd_size != 0; ++pd) {
+#if defined(__arm__)
pmap_map_chunk(l1pt, pd->pd_va, pd->pd_pa, pd->pd_size,
pd->pd_prot,pd->pd_cache);
+#elif defined(__aarch64__)
+ pmap_kenter_device(pd->pd_va, pd->pd_size, pd->pd_pa);
+#endif
}
}
@@ -246,28 +267,31 @@ arm_devmap_vtop(void * vpva, vm_size_t size)
void *
pmap_mapdev(vm_offset_t pa, vm_size_t size)
{
- vm_offset_t va, tmpva, offset;
+ vm_offset_t va, offset;
void * rva;
/* First look in the static mapping table. */
if ((rva = arm_devmap_ptov(pa, size)) != NULL)
return (rva);
-
+
offset = pa & PAGE_MASK;
pa = trunc_page(pa);
size = round_page(size + offset);
-
- va = kva_alloc(size);
+
+#ifdef __aarch64__
+ if (early_boot) {
+ akva_devmap_vaddr = trunc_page(akva_devmap_vaddr - size);
+ va = akva_devmap_vaddr;
+ KASSERT(va >= VM_MAX_KERNEL_ADDRESS - L2_SIZE,
+ ("Too many early devmap mappings"));
+ } else
+#endif
+ va = kva_alloc(size);
if (!va)
panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
- for (tmpva = va; size > 0;) {
- pmap_kenter_device(tmpva, pa);
- size -= PAGE_SIZE;
- tmpva += PAGE_SIZE;
- pa += PAGE_SIZE;
- }
-
+ pmap_kenter_device(va, size, pa);
+
return ((void *)(va + offset));
}
@@ -277,25 +301,18 @@ pmap_mapdev(vm_offset_t pa, vm_size_t size)
void
pmap_unmapdev(vm_offset_t va, vm_size_t size)
{
- vm_offset_t tmpva, offset;
- vm_size_t origsize;
+ vm_offset_t offset;
/* Nothing to do if we find the mapping in the static table. */
if (arm_devmap_vtop((void*)va, size) != DEVMAP_PADDR_NOTFOUND)
return;
- origsize = size;
offset = va & PAGE_MASK;
va = trunc_page(va);
size = round_page(size + offset);
- for (tmpva = va; size > 0;) {
- pmap_kremove(tmpva);
- size -= PAGE_SIZE;
- tmpva += PAGE_SIZE;
- }
-
- kva_free(va, origsize);
+ pmap_kremove_device(va, size);
+ kva_free(va, size);
}
#ifdef DDB
diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c
index 9085d67..598decc 100644
--- a/sys/arm/arm/elf_machdep.c
+++ b/sys/arm/arm/elf_machdep.c
@@ -105,7 +105,6 @@ elf32_arm_abi_supported(struct image_params *imgp)
{
const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
-#ifdef __ARM_EABI__
/*
* When configured for EABI, FreeBSD supports EABI vesions 4 and 5.
*/
@@ -115,17 +114,6 @@ elf32_arm_abi_supported(struct image_params *imgp)
EF_ARM_EABI_VERSION(hdr->e_flags), imgp->args->fname);
return (FALSE);
}
-#else
- /*
- * When configured for OABI, that's all we do, so reject EABI binaries.
- */
- if (EF_ARM_EABI_VERSION(hdr->e_flags) != EF_ARM_EABI_VERSION_UNKNOWN) {
- if (bootverbose)
- uprintf("Attempting to execute EABI binary (rev %d) image %s",
- EF_ARM_EABI_VERSION(hdr->e_flags), imgp->args->fname);
- return (FALSE);
- }
-#endif
return (TRUE);
}
diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
index 8be4b25..d246a87 100644
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -101,10 +101,22 @@ static struct timecounter arm_tmr_timecount = {
.tc_quality = 1000,
};
+#ifdef __arm__
+#define get_el0(x) cp15_## x ##_get()
+#define get_el1(x) cp15_## x ##_get()
+#define set_el0(x, val) cp15_## x ##_set(val)
+#define set_el1(x, val) cp15_## x ##_set(val)
+#else /* __aarch64__ */
+#define get_el0(x) READ_SPECIALREG(x ##_el0)
+#define get_el1(x) READ_SPECIALREG(x ##_el1)
+#define set_el0(x, val) WRITE_SPECIALREG(x ##_el0, val)
+#define set_el1(x, val) WRITE_SPECIALREG(x ##_el1, val)
+#endif
+
static int
get_freq(void)
{
- return (cp15_cntfrq_get());
+ return (get_el0(cntfrq));
}
static long
@@ -114,9 +126,9 @@ get_cntxct(bool physical)
isb();
if (physical)
- val = cp15_cntpct_get();
+ val = get_el0(cntpct);
else
- val = cp15_cntvct_get();
+ val = get_el0(cntvct);
return (val);
}
@@ -126,9 +138,9 @@ set_ctrl(uint32_t val, bool physical)
{
if (physical)
- cp15_cntp_ctl_set(val);
+ set_el0(cntp_ctl, val);
else
- cp15_cntv_ctl_set(val);
+ set_el0(cntv_ctl, val);
isb();
return (0);
@@ -139,9 +151,9 @@ set_tval(uint32_t val, bool physical)
{
if (physical)
- cp15_cntp_tval_set(val);
+ set_el0(cntp_tval, val);
else
- cp15_cntv_tval_set(val);
+ set_el0(cntv_tval, val);
isb();
return (0);
@@ -153,9 +165,9 @@ get_ctrl(bool physical)
uint32_t val;
if (physical)
- val = cp15_cntp_ctl_get();
+ val = get_el0(cntp_ctl);
else
- val = cp15_cntv_ctl_get();
+ val = get_el0(cntv_ctl);
return (val);
}
@@ -165,10 +177,10 @@ disable_user_access(void)
{
uint32_t cntkctl;
- cntkctl = cp15_cntkctl_get();
+ cntkctl = get_el1(cntkctl);
cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN |
GT_CNTKCTL_EVNTEN | GT_CNTKCTL_PL0VCTEN | GT_CNTKCTL_PL0PCTEN);
- cp15_cntkctl_set(cntkctl);
+ set_el1(cntkctl, cntkctl);
isb();
}
@@ -242,11 +254,15 @@ arm_tmr_probe(device_t dev)
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_is_compatible(dev, "arm,armv7-timer"))
- return (ENXIO);
+ if (ofw_bus_is_compatible(dev, "arm,armv7-timer")) {
+ device_set_desc(dev, "ARMv7 Generic Timer");
+ return (BUS_PROBE_DEFAULT);
+ } else if (ofw_bus_is_compatible(dev, "arm,armv8-timer")) {
+ device_set_desc(dev, "ARMv8 Generic Timer");
+ return (BUS_PROBE_DEFAULT);
+ }
- device_set_desc(dev, "ARMv7 Generic Timer");
- return (BUS_PROBE_DEFAULT);
+ return (ENXIO);
}
@@ -285,7 +301,11 @@ arm_tmr_attach(device_t dev)
return (ENXIO);
}
+#ifdef __arm__
sc->physical = true;
+#else /* __aarch64__ */
+ sc->physical = false;
+#endif
arm_tmr_sc = sc;
diff --git a/sys/arm/arm/intr.c b/sys/arm/arm/intr.c
index e83bca9..be8e87c 100644
--- a/sys/arm/arm/intr.c
+++ b/sys/arm/arm/intr.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/pmckern.h>
#include <machine/atomic.h>
+#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/cpu.h>
diff --git a/sys/arm/arm/locore-v4.S b/sys/arm/arm/locore-v4.S
index 8ef53e9..d798e97 100644
--- a/sys/arm/arm/locore-v4.S
+++ b/sys/arm/arm/locore-v4.S
@@ -116,7 +116,7 @@ ASENTRY_NP(_start)
* If we're running with MMU disabled, test against the
* physical address instead.
*/
- mrc p15, 0, r2, c1, c0, 0
+ mrc p15, 0, r2, c1, c0, 0
ands r2, r2, #CPU_CONTROL_MMU_ENABLE
ldreq r6, =PHYSADDR
ldrne r6, =LOADERRAMADDR
@@ -125,7 +125,7 @@ ASENTRY_NP(_start)
cmp r7, pc
bhi from_ram
b do_copy
-
+
flash_lower:
cmp r6, pc
bls from_ram
@@ -148,12 +148,12 @@ from_ram:
disable_mmu:
/* Disable MMU for a while */
- mrc p15, 0, r2, c1, c0, 0
+ mrc p15, 0, r2, c1, c0, 0
bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
CPU_CONTROL_WBUF_ENABLE)
bic r2, r2, #(CPU_CONTROL_IC_ENABLE)
bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
- mcr p15, 0, r2, c1, c0, 0
+ mcr p15, 0, r2, c1, c0, 0
nop
nop
@@ -169,36 +169,16 @@ Lunmapped:
adr r0, Lpagetable
bl translate_va_to_pa
-#ifndef _ARM_ARCH_6
/*
* Some of the older ports (the various XScale, mostly) assume
* that the memory before the kernel is mapped, and use it for
- * the various stacks, page tables, etc. For those CPUs, map the
- * 64 first MB of RAM, as it used to be.
+ * the various stacks, page tables, etc. For those CPUs, map the
+ * 64 first MB of RAM, as it used to be.
*/
/*
* Map PA == VA
- */
- ldr r5, =PHYSADDR
- mov r1, r5
- mov r2, r5
- /* Map 64MiB, preserved over calls to build_pagetables */
- mov r3, #64
- bl build_pagetables
-
- /* Create the kernel map to jump to */
- mov r1, r5
- ldr r2, =(KERNBASE)
- bl build_pagetables
- ldr r5, =(KERNPHYSADDR)
-#else
- /*
- * Map PA == VA
- */
- /* Find the start kernels load address */
- adr r5, _start
- ldr r2, =(L1_S_OFFSET)
- bic r5, r2
+ */
+ ldr r5, =PHYSADDR
mov r1, r5
mov r2, r5
/* Map 64MiB, preserved over calls to build_pagetables */
@@ -207,10 +187,10 @@ Lunmapped:
/* Create the kernel map to jump to */
mov r1, r5
- ldr r2, =(KERNVIRTADDR)
+ ldr r2, =(KERNBASE)
bl build_pagetables
-#endif
-
+ ldr r5, =(KERNPHYSADDR)
+
#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
/* Create the custom map */
ldr r1, =SOCDEV_PA
@@ -221,26 +201,16 @@ Lunmapped:
mcr p15, 0, r0, c2, c0, 0 /* Set TTB */
mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */
-#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
- mov r0, #0
- mcr p15, 0, r0, c13, c0, 1 /* Set ASID to 0 */
-#endif
-
/* Set the Domain Access register. Very important! */
- mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
+ mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
mcr p15, 0, r0, c3, c0, 0
- /*
+ /*
* Enable MMU.
* On armv6 enable extended page tables, and set alignment checking
* to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
* instructions emitted by clang.
*/
mrc p15, 0, r0, c1, c0, 0
-#ifdef _ARM_ARCH_6
- orr r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
- orr r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
- orr r0, r0, #(CPU_CONTROL_AF_ENABLE)
-#endif
orr r0, r0, #(CPU_CONTROL_MMU_ENABLE)
mcr p15, 0, r0, c1, c0, 0
nop
@@ -280,7 +250,7 @@ virt_done:
/* init arm will return the new stack pointer. */
mov sp, r0
- bl _C_LABEL(mi_startup) /* call mi_startup()! */
+ bl _C_LABEL(mi_startup) /* call mi_startup()! */
adr r0, .Lmainreturned
b _C_LABEL(panic)
@@ -389,11 +359,11 @@ pagetable:
.word _C_LABEL(cpufuncs)
ENTRY_NP(cpu_halt)
- mrs r2, cpsr
+ mrs r2, cpsr
bic r2, r2, #(PSR_MODE)
- orr r2, r2, #(PSR_SVC32_MODE)
+ orr r2, r2, #(PSR_SVC32_MODE)
orr r2, r2, #(PSR_I | PSR_F)
- msr cpsr_fsxc, r2
+ msr cpsr_fsxc, r2
ldr r4, .Lcpu_reset_address
ldr r4, [r4]
@@ -419,9 +389,9 @@ ENTRY_NP(cpu_halt)
* Hurl ourselves into the ROM
*/
mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
- mcr p15, 0, r0, c1, c0, 0
- mcrne p15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */
- mov pc, r4
+ mcr p15, 0, r0, c1, c0, 0
+ mcrne p15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */
+ mov pc, r4
/*
* _cpu_reset_address contains the address to branch to, to complete
@@ -458,7 +428,7 @@ ENTRY(longjmp)
END(longjmp)
.data
- .global _C_LABEL(esym)
+ .global _C_LABEL(esym)
_C_LABEL(esym): .word _C_LABEL(end)
ENTRY_NP(abort)
@@ -471,7 +441,7 @@ ENTRY_NP(sigcode)
/*
* Call the sigreturn system call.
- *
+ *
* We have to load r7 manually rather than using
* "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
* correct. Using the alternative places esigcode at the address
diff --git a/sys/arm/arm/locore-v6.S b/sys/arm/arm/locore-v6.S
index 55b4311..7d5ba97 100644
--- a/sys/arm/arm/locore-v6.S
+++ b/sys/arm/arm/locore-v6.S
@@ -39,7 +39,7 @@
__FBSDID("$FreeBSD$");
-#ifndef ARM_NEW_PMAP
+#ifndef ARM_NEW_PMAP
#define PTE1_OFFSET L1_S_OFFSET
#define PTE1_SHIFT L1_S_SHIFT
#define PTE1_SIZE L1_S_SIZE
@@ -52,13 +52,13 @@ __FBSDID("$FreeBSD$");
.align 2
/*
- * On entry for FreeBSD boot ABI:
- * r0 - metadata pointer or 0 (boothowto on AT91's boot2)
- * r1 - if (r0 == 0) then metadata pointer
- * On entry for Linux boot ABI:
+ * On entry for FreeBSD boot ABI:
+ * r0 - metadata pointer or 0 (boothowto on AT91's boot2)
+ * r1 - if (r0 == 0) then metadata pointer
+ * On entry for Linux boot ABI:
* r0 - 0
* r1 - machine type (passed as arg2 to initarm)
- * r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
+ * r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
*
* For both types of boot we gather up the args, put them in a struct arm_boot_params
* structure and pass that to initarm.
@@ -66,17 +66,17 @@ __FBSDID("$FreeBSD$");
.globl btext
btext:
ASENTRY_NP(_start)
- STOP_UNWINDING /* Can't unwind into the bootloader! */
+ STOP_UNWINDING /* Can't unwind into the bootloader! */
- /* Make sure interrupts are disabled. */
+ /* Make sure interrupts are disabled. */
cpsid ifa
- mov r8, r0 /* 0 or boot mode from boot2 */
- mov r9, r1 /* Save Machine type */
- mov r10, r2 /* Save meta data */
+ mov r8, r0 /* 0 or boot mode from boot2 */
+ mov r9, r1 /* Save Machine type */
+ mov r10, r2 /* Save meta data */
mov r11, r3 /* Future expansion */
- /*
+ /*
* Check whether data cache is enabled. If it is, then we know
* current tags are valid (not power-on garbage values) and there
* might be dirty lines that need cleaning. Disable cache to prevent
@@ -93,7 +93,7 @@ ASENTRY_NP(_start)
* valid. Disable all caches and the MMU, and invalidate everything
* before setting up new page tables and re-enabling the mmu.
*/
-1:
+1:
bic r7, #CPU_CONTROL_DC_ENABLE
bic r7, #CPU_CONTROL_MMU_ENABLE
bic r7, #CPU_CONTROL_IC_ENABLE
@@ -119,13 +119,13 @@ ASENTRY_NP(_start)
/*
* Map PA == VA
*/
- /* Find the start kernels load address */
+ /* Find the start kernels load address */
adr r5, _start
ldr r2, =(PTE1_OFFSET)
bic r5, r2
mov r1, r5
mov r2, r5
- /* Map 64MiB, preserved over calls to build_pagetables */
+ /* Map 64MiB, preserved over calls to build_pagetables */
mov r3, #64
bl build_pagetables
@@ -142,41 +142,41 @@ ASENTRY_NP(_start)
#endif
bl init_mmu
- /* Switch to virtual addresses. */
+ /* Switch to virtual addresses. */
ldr pc, =1f
1:
- /* Setup stack, clear BSS */
+ /* Setup stack, clear BSS */
ldr r1, =.Lstart
ldmia r1, {r1, r2, sp} /* Set initial stack and */
add sp, sp, #INIT_ARM_STACK_SIZE
- sub r2, r2, r1 /* get zero init data */
+ sub r2, r2, r1 /* get zero init data */
mov r3, #0
2:
str r3, [r1], #0x0004 /* get zero init data */
- subs r2, r2, #4
+ subs r2, r2, #4
bgt 2b
- mov r1, #28 /* loader info size is 28 bytes also second arg */
- subs sp, sp, r1 /* allocate arm_boot_params struct on stack */
- mov r0, sp /* loader info pointer is first arg */
- bic sp, sp, #7 /* align stack to 8 bytes */
- str r1, [r0] /* Store length of loader info */
+ mov r1, #28 /* loader info size is 28 bytes also second arg */
+ subs sp, sp, r1 /* allocate arm_boot_params struct on stack */
+ mov r0, sp /* loader info pointer is first arg */
+ bic sp, sp, #7 /* align stack to 8 bytes */
+ str r1, [r0] /* Store length of loader info */
str r8, [r0, #4] /* Store r0 from boot loader */
str r9, [r0, #8] /* Store r1 from boot loader */
str r10, [r0, #12] /* store r2 from boot loader */
str r11, [r0, #16] /* store r3 from boot loader */
str r5, [r0, #20] /* store the physical address */
- adr r4, Lpagetable /* load the pagetable address */
+ adr r4, Lpagetable /* load the pagetable address */
ldr r5, [r4, #4]
str r5, [r0, #24] /* store the pagetable address */
mov fp, #0 /* trace back starts here */
bl _C_LABEL(initarm) /* Off we go */
- /* init arm will return the new stack pointer. */
+ /* init arm will return the new stack pointer. */
mov sp, r0
- bl _C_LABEL(mi_startup) /* call mi_startup()! */
+ bl _C_LABEL(mi_startup) /* call mi_startup()! */
ldr r0, =.Lmainreturned
b _C_LABEL(panic)
@@ -219,8 +219,8 @@ translate_va_to_pa:
mov pc, lr
/*
- * Init MMU
- * r0 - The table base address
+ * Init MMU
+ * r0 - the table base address
*/
ASENTRY_NP(init_mmu)
@@ -267,11 +267,11 @@ END(init_mmu)
/*
- * Init SMP coherent mode, enable caching and switch to final MMU table.
- * Called with disabled caches
- * r0 - The table base address
- * r1 - clear bits for aux register
- * r2 - set bits for aux register
+ * Init SMP coherent mode, enable caching and switch to final MMU table.
+ * Called with disabled caches
+ * r0 - The table base address
+ * r1 - clear bits for aux register
+ * r2 - set bits for aux register
*/
ASENTRY_NP(reinit_mmu)
push {r4-r11, lr}
@@ -331,11 +331,11 @@ END(reinit_mmu)
/*
* Builds the page table
- * r0 - The table base address
- * r1 - The physical address (trashed)
- * r2 - The virtual address (trashed)
- * r3 - The number of 1MiB sections
- * r4 - Trashed
+ * r0 - The table base address
+ * r1 - The physical address (trashed)
+ * r2 - The virtual address (trashed)
+ * r3 - The number of 1MiB sections
+ * r4 - Trashed
*
* Addresses must be 1MiB aligned
*/
@@ -350,15 +350,15 @@ build_pagetables:
#endif
orr r1, r4
- /* Move the virtual address to the correct bit location */
+ /* Move the virtual address to the correct bit location */
lsr r2, #(PTE1_SHIFT - 2)
mov r4, r3
1:
str r1, [r0, r2]
- add r2, r2, #4
- add r1, r1, #(PTE1_SIZE)
- adds r4, r4, #-1
+ add r2, r2, #4
+ add r1, r1, #(PTE1_SIZE)
+ adds r4, r4, #-1
bhi 1b
mov pc, lr
@@ -372,7 +372,7 @@ VA_TO_PA_POINTER(Lpagetable, boot_pt1)
.word svcstk /* must remain in order together. */
.Lmainreturned:
- .asciz "main() returned"
+ .asciz "main() returned"
.align 2
.bss
@@ -380,8 +380,8 @@ svcstk:
.space INIT_ARM_STACK_SIZE * MAXCPU
/*
- * Memory for the initial pagetable. We are unable to place this in
- * the bss as this will be cleared after the table is loaded.
+ * Memory for the initial pagetable. We are unable to place this in
+ * the bss as this will be cleared after the table is loaded.
*/
.section ".init_pagetable"
.align 14 /* 16KiB aligned */
@@ -398,7 +398,7 @@ boot_pt1:
#if defined(SMP)
ASENTRY_NP(mpentry)
- /* Make sure interrupts are disabled. */
+ /* Make sure interrupts are disabled. */
cpsid ifa
/* Setup core, disable all caches. */
@@ -419,10 +419,10 @@ ASENTRY_NP(mpentry)
mcr CP15_ICIALLU
ISB
- /* Find the delta between VA and PA */
+ /* Find the delta between VA and PA */
adr r0, Lpagetable
bl translate_va_to_pa
-
+
bl init_mmu
adr r1, .Lstart+8 /* Get initstack pointer from */
@@ -433,7 +433,7 @@ ASENTRY_NP(mpentry)
mul r2, r1, r0 /* Point sp to initstack */
add sp, sp, r2 /* area for this processor. */
- /* Switch to virtual addresses. */
+ /* Switch to virtual addresses. */
ldr pc, =1f
1:
mov fp, #0 /* trace back starts here */
@@ -459,14 +459,14 @@ ENTRY_NP(cpu_halt)
ldr r4, [r4]
teq r4, #0
movne pc, r4
-1:
+1:
WFI
b 1b
/*
* _cpu_reset_address contains the address to branch to, to complete
* the cpu reset after turning the MMU off
- * This variable is provided by the hardware specific code
+ * This variable is provided by the hardware specific code
*/
.Lcpu_reset_address:
.word _C_LABEL(cpu_reset_address)
@@ -498,38 +498,37 @@ END(abort)
ENTRY_NP(sigcode)
mov r0, sp
- add r0, r0, #SIGF_UC
+ add r0, r0, #SIGF_UC
/*
- * Call the sigreturn system call.
+ * Call the sigreturn system call.
*
* We have to load r7 manually rather than using
- * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
+ * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
* correct. Using the alternative places esigcode at the address
- * of the data rather than the address one past the data.
+ * of the data rather than the address one past the data.
*/
- ldr r7, [pc, #12] /* Load SYS_sigreturn */
+ ldr r7, [pc, #12] /* Load SYS_sigreturn */
swi SYS_sigreturn
- /* Well if that failed we better exit quick ! */
+ /* Well if that failed we better exit quick ! */
- ldr r7, [pc, #8] /* Load SYS_exit */
+ ldr r7, [pc, #8] /* Load SYS_exit */
swi SYS_exit
- /* Branch back to retry SYS_sigreturn */
+ /* Branch back to retry SYS_sigreturn */
b . - 16
END(sigcode)
-
.word SYS_sigreturn
.word SYS_exit
.align 2
- .global _C_LABEL(esigcode)
+ .global _C_LABEL(esigcode)
_C_LABEL(esigcode):
.data
- .global szsigcode
+ .global szsigcode
szsigcode:
.long esigcode-sigcode
diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c
index 68d31a9..a76e18a4 100644
--- a/sys/arm/arm/machdep.c
+++ b/sys/arm/arm/machdep.c
@@ -1055,7 +1055,6 @@ kenv_next(char *cp)
static void
print_kenv(void)
{
- int len;
char *cp;
debugf("loader passed (static) kenv:\n");
@@ -1065,7 +1064,6 @@ print_kenv(void)
}
debugf(" kern_envp = 0x%08x\n", (uint32_t)kern_envp);
- len = 0;
for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
debugf(" %x %s\n", (uint32_t)cp, cp);
}
diff --git a/sys/arm/arm/mpcore_timer.c b/sys/arm/arm/mpcore_timer.c
index 62c5344..88060cf 100644
--- a/sys/arm/arm/mpcore_timer.c
+++ b/sys/arm/arm/mpcore_timer.c
@@ -65,7 +65,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <arm/arm/mpcore_timervar.h>
diff --git a/sys/arm/arm/pmap-v6-new.c b/sys/arm/arm/pmap-v6-new.c
index 8c15918..f404214 100644
--- a/sys/arm/arm/pmap-v6-new.c
+++ b/sys/arm/arm/pmap-v6-new.c
@@ -6051,11 +6051,38 @@ retry:
}
void
-pmap_kenter_device(vm_offset_t va, vm_paddr_t pa)
+pmap_kenter_device(vm_offset_t va, vm_size_t size, vm_paddr_t pa)
{
+ vm_offset_t sva;
- pmap_kenter_prot_attr(va, pa, PTE2_AP_KRW, PTE2_ATTR_DEVICE);
- tlb_flush(va);
+ KASSERT((size & PAGE_MASK) == 0,
+ ("%s: device mapping not page-sized", __func__));
+
+ sva = va;
+ while (size != 0) {
+ pmap_kenter_prot_attr(va, pa, PTE2_AP_KRW, PTE2_ATTR_DEVICE);
+ va += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ tlb_flush_range(sva, va - sva);
+}
+
+void
+pmap_kremove_device(vm_offset_t va, vm_size_t size)
+{
+ vm_offset_t sva;
+
+ KASSERT((size & PAGE_MASK) == 0,
+ ("%s: device mapping not page-sized", __func__));
+
+ sva = va;
+ while (size != 0) {
+ pmap_kremove(va);
+ va += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ tlb_flush_range(sva, va - sva);
}
void
@@ -6067,13 +6094,13 @@ pmap_set_pcb_pagedir(pmap_t pmap, struct pcb *pcb)
/*
- * Clean L1 data cache range on a single page, which is not mapped yet.
+ * Clean L1 data cache range by physical address.
+ * The range must be within a single page.
*/
static void
pmap_dcache_wb_pou(vm_paddr_t pa, vm_size_t size, vm_memattr_t ma)
{
struct sysmaps *sysmaps;
- vm_offset_t va;
KASSERT(((pa & PAGE_MASK) + size) <= PAGE_SIZE,
("%s: not on single page", __func__));
@@ -6084,9 +6111,8 @@ pmap_dcache_wb_pou(vm_paddr_t pa, vm_size_t size, vm_memattr_t ma)
if (*sysmaps->CMAP3)
panic("%s: CMAP3 busy", __func__);
pte2_store(sysmaps->CMAP3, PTE2_KERN_NG(pa, PTE2_AP_KRW, ma));
- va = (vm_offset_t)sysmaps->CADDR3;
- tlb_flush_local(va);
- dcache_wb_pou(va, size);
+ tlb_flush_local((vm_offset_t)sysmaps->CADDR3);
+ dcache_wb_pou((vm_offset_t)sysmaps->CADDR3 + (pa & PAGE_MASK), size);
pte2_clear(sysmaps->CMAP3);
sched_unpin();
mtx_unlock(&sysmaps->lock);
diff --git a/sys/arm/arm/pmap-v6.c b/sys/arm/arm/pmap-v6.c
index 317d776..0e0d884 100644
--- a/sys/arm/arm/pmap-v6.c
+++ b/sys/arm/arm/pmap-v6.c
@@ -2451,10 +2451,36 @@ pmap_kenter_nocache(vm_offset_t va, vm_paddr_t pa)
}
void
-pmap_kenter_device(vm_offset_t va, vm_paddr_t pa)
+pmap_kenter_device(vm_offset_t va, vm_size_t size, vm_paddr_t pa)
{
+ vm_offset_t sva;
- pmap_kenter_internal(va, pa, KENTER_DEVICE);
+ KASSERT((size & PAGE_MASK) == 0,
+ ("%s: device mapping not page-sized", __func__));
+
+ sva = va;
+ while (size != 0) {
+ pmap_kenter_internal(va, pa, KENTER_DEVICE);
+ va += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+}
+
+void
+pmap_kremove_device(vm_offset_t va, vm_size_t size)
+{
+ vm_offset_t sva;
+
+ KASSERT((size & PAGE_MASK) == 0,
+ ("%s: device mapping not page-sized", __func__));
+
+ sva = va;
+ while (size != 0) {
+ pmap_kremove(va);
+ va += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
}
void
diff --git a/sys/arm/arm/pmap.c b/sys/arm/arm/pmap.c
index 1619236..e1429a1 100644
--- a/sys/arm/arm/pmap.c
+++ b/sys/arm/arm/pmap.c
@@ -2712,14 +2712,36 @@ pmap_kenter_nocache(vm_offset_t va, vm_paddr_t pa)
}
void
-pmap_kenter_device(vm_offset_t va, vm_paddr_t pa)
+pmap_kenter_device(vm_offset_t va, vm_size_t size, vm_paddr_t pa)
{
+ vm_offset_t sva;
- /*
- * XXX - Need a way for kenter_internal to handle PTE_DEVICE mapping as
- * a potentially different thing than PTE_NOCACHE.
- */
- pmap_kenter_internal(va, pa, 0);
+ KASSERT((size & PAGE_MASK) == 0,
+ ("%s: device mapping not page-sized", __func__));
+
+ sva = va;
+ while (size != 0) {
+ pmap_kenter_internal(va, pa, 0);
+ va += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+}
+
+void
+pmap_kremove_device(vm_offset_t va, vm_size_t size)
+{
+ vm_offset_t sva;
+
+ KASSERT((size & PAGE_MASK) == 0,
+ ("%s: device mapping not page-sized", __func__));
+
+ sva = va;
+ while (size != 0) {
+ pmap_kremove(va);
+ va += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
}
void
diff --git a/sys/arm/arm/pmu.c b/sys/arm/arm/pmu.c
index 168c8b4..c224525 100644
--- a/sys/arm/arm/pmu.c
+++ b/sys/arm/arm/pmu.c
@@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/arm/trap-v6.c b/sys/arm/arm/trap-v6.c
index b9cad50..abafa86 100644
--- a/sys/arm/arm/trap-v6.c
+++ b/sys/arm/arm/trap-v6.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_extern.h>
#include <vm/vm_param.h>
+#include <machine/acle-compat.h>
#include <machine/cpu.h>
#include <machine/cpu-v6.h>
#include <machine/frame.h>
@@ -287,7 +288,11 @@ abort_handler(struct trapframe *tf, int prefetch)
#endif
td = curthread;
fsr = (prefetch) ? cp15_ifsr_get(): cp15_dfsr_get();
+#if __ARM_ARCH >= 7
+ far = (prefetch) ? cp15_ifar_get() : cp15_dfar_get();
+#else
far = (prefetch) ? TRAPF_PC(tf) : cp15_dfar_get();
+#endif
idx = FSR_TO_FAULT(fsr);
usermode = TRAPF_USERMODE(tf); /* Abort came from user mode? */
diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c
index 383a74a..2ab58ea 100644
--- a/sys/arm/arm/vm_machdep.c
+++ b/sys/arm/arm/vm_machdep.c
@@ -178,11 +178,7 @@ cpu_set_syscall_retval(struct thread *td, int error)
* place the returned data into r1. As the lseek and frerebsd6_lseek
* syscalls also return an off_t they do not need this fixup.
*/
-#ifdef __ARM_EABI__
call = frame->tf_r7;
-#else
- call = *(u_int32_t *)(frame->tf_pc - INSN_SIZE) & 0x000fffff;
-#endif
if (call == SYS___syscall) {
register_t *ap = &frame->tf_r0;
register_t code = ap[_QUAD_LOWWORD];
diff --git a/sys/arm/at91/at91_common.c b/sys/arm/at91/at91_common.c
index 8282aa1..4153366 100644
--- a/sys/arm/at91/at91_common.c
+++ b/sys/arm/at91/at91_common.c
@@ -29,15 +29,22 @@ __FBSDID("$FreeBSD$");
#define _ARM32_BUS_DMA_PRIVATE
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/bus.h>
+
#include <vm/vm.h>
+
#include <machine/devmap.h>
+#include <machine/intr.h>
#include <machine/machdep.h>
#include <machine/platform.h>
+
#include <arm/at91/at91var.h>
#include <arm/at91/at91soc.h>
#include <arm/at91/at91_aicreg.h>
+
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
+
#include <machine/fdt.h>
extern const struct arm_devmap_entry at91_devmap[];
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_common.c b/sys/arm/broadcom/bcm2835/bcm2835_common.c
index a534957..a558ac8 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_common.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_common.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/vmparam.h>
struct fdt_fixup_entry fdt_fixup_table[] = {
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_fb.c b/sys/arm/broadcom/bcm2835/bcm2835_fb.c
index 3270da1..6e6cfda 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_fb.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_fb.c
@@ -29,46 +29,27 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/bio.h>
#include <sys/bus.h>
-#include <sys/conf.h>
-#include <sys/endian.h>
+#include <sys/consio.h>
+#include <sys/fbio.h>
+#include <sys/kdb.h>
#include <sys/kernel.h>
-#include <sys/kthread.h>
-#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/queue.h>
-#include <sys/resource.h>
-#include <sys/rman.h>
-#include <sys/time.h>
-#include <sys/timetc.h>
-#include <sys/fbio.h>
-#include <sys/consio.h>
-
-#include <sys/kdb.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-#include <machine/cpufunc.h>
-#include <machine/resource.h>
-#include <machine/intr.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <dev/fb/fbreg.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-
-#include <dev/fb/fbreg.h>
#include <dev/syscons/syscons.h>
-#include <arm/broadcom/bcm2835/bcm2835_mbox.h>
-#include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
+#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
#include "mbox_if.h"
-#define BCMFB_FONT_HEIGHT 16
-
struct argb {
uint8_t a;
uint8_t r;
@@ -101,40 +82,15 @@ static u_char mouse_pointer[16] = {
0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
};
-#define FB_WIDTH 640
-#define FB_HEIGHT 480
-#define FB_DEPTH 24
-
-struct bcm_fb_config {
- uint32_t xres;
- uint32_t yres;
- uint32_t vxres;
- uint32_t vyres;
- uint32_t pitch;
- uint32_t bpp;
- uint32_t xoffset;
- uint32_t yoffset;
- /* Filled by videocore */
- uint32_t base;
- uint32_t screen_size;
-};
+#define BCMFB_FONT_HEIGHT 16
+#define BCMFB_FONT_WIDTH 8
+#define FB_WIDTH 640
+#define FB_HEIGHT 480
+#define FB_DEPTH 24
struct bcmsc_softc {
- device_t dev;
- struct cdev * cdev;
- struct mtx mtx;
- bus_dma_tag_t dma_tag;
- bus_dmamap_t dma_map;
- struct bcm_fb_config* fb_config;
- bus_addr_t fb_config_phys;
- struct intr_config_hook init_hook;
-
-};
-
-struct video_adapter_softc {
/* Videoadpater part */
video_adapter_t va;
- int console;
intptr_t fb_addr;
intptr_t fb_paddr;
@@ -149,199 +105,75 @@ struct video_adapter_softc {
unsigned int ymargin;
unsigned char *font;
+ int fbswap;
int initialized;
};
-static struct bcmsc_softc *bcmsc_softc;
-static struct video_adapter_softc va_softc;
-
-#define bcm_fb_lock(_sc) mtx_lock(&(_sc)->mtx)
-#define bcm_fb_unlock(_sc) mtx_unlock(&(_sc)->mtx)
-#define bcm_fb_lock_assert(sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
+static struct bcmsc_softc bcmsc;
static int bcm_fb_probe(device_t);
static int bcm_fb_attach(device_t);
-static void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err);
static void bcmfb_update_margins(video_adapter_t *adp);
static int bcmfb_configure(int);
-static void
-bcm_fb_init(void *arg)
-{
- struct bcmsc_softc *sc = arg;
- struct video_adapter_softc *va_sc = &va_softc;
- int err;
- volatile struct bcm_fb_config* fb_config = sc->fb_config;
- phandle_t node;
- pcell_t cell;
- device_t mbox;
-
- node = ofw_bus_get_node(sc->dev);
-
- fb_config->xres = 0;
- fb_config->yres = 0;
- fb_config->bpp = 0;
-
- if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0)
- fb_config->xres = (int)fdt32_to_cpu(cell);
- if (fb_config->xres == 0)
- fb_config->xres = FB_WIDTH;
-
- if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0)
- fb_config->yres = (uint32_t)fdt32_to_cpu(cell);
- if (fb_config->yres == 0)
- fb_config->yres = FB_HEIGHT;
-
- if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0)
- fb_config->bpp = (uint32_t)fdt32_to_cpu(cell);
- if (fb_config->bpp == 0)
- fb_config->bpp = FB_DEPTH;
-
- fb_config->vxres = 0;
- fb_config->vyres = 0;
- fb_config->xoffset = 0;
- fb_config->yoffset = 0;
- fb_config->base = 0;
- fb_config->pitch = 0;
- fb_config->screen_size = 0;
-
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
- mbox = devclass_get_device(devclass_find("mbox"), 0);
- if (mbox) {
- MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_FB, sc->fb_config_phys);
- MBOX_READ(mbox, BCM2835_MBOX_CHAN_FB, &err);
- }
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_POSTREAD);
-
- if (fb_config->base != 0) {
- device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n",
- fb_config->xres, fb_config->yres,
- fb_config->vxres, fb_config->vyres,
- fb_config->xoffset, fb_config->yoffset,
- fb_config->bpp);
-
-
- device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n",
- fb_config->pitch, fb_config->base,
- fb_config->screen_size);
-
- va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size);
- va_sc->fb_paddr = fb_config->base;
- va_sc->fb_size = fb_config->screen_size;
- va_sc->depth = fb_config->bpp;
- va_sc->stride = fb_config->pitch;
-
- va_sc->width = fb_config->xres;
- va_sc->height = fb_config->yres;
- bcmfb_update_margins(&va_sc->va);
- }
- else {
- device_printf(sc->dev, "Failed to set framebuffer info\n");
- }
-
- config_intrhook_disestablish(&sc->init_hook);
-}
-
static int
bcm_fb_probe(device_t dev)
{
- int error = 0;
+ int error;
if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb"))
return (ENXIO);
-
device_set_desc(dev, "BCM2835 framebuffer device");
-
error = sc_probe_unit(device_get_unit(dev),
device_get_flags(dev) | SC_AUTODETECT_KBD);
if (error != 0)
return (error);
-
return (BUS_PROBE_DEFAULT);
}
static int
bcm_fb_attach(device_t dev)
{
- struct bcmsc_softc *sc = device_get_softc(dev);
- int dma_size = sizeof(struct bcm_fb_config);
- int err;
-
- if (bcmsc_softc)
- return (ENXIO);
+ struct bcm2835_fb_config fb;
+ struct bcmsc_softc *sc;
- bcmsc_softc = sc;
-
- sc->dev = dev;
- mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF);
-
- err = bus_dma_tag_create(
- bus_get_dma_tag(sc->dev),
- PAGE_SIZE, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- dma_size, 1, /* maxsize, nsegments */
- dma_size, 0, /* maxsegsize, flags */
- NULL, NULL, /* lockfunc, lockarg */
- &sc->dma_tag);
-
- err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config,
- 0, &sc->dma_map);
- if (err) {
- device_printf(dev, "cannot allocate framebuffer\n");
- goto fail;
- }
-
- err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config,
- dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT);
-
- if (err) {
- device_printf(dev, "cannot load DMA map\n");
- goto fail;
- }
+ sc = (struct bcmsc_softc *)vid_get_adapter(vid_find_adapter(
+ "bcmfb", 0));
+ if (sc != NULL)
+ device_set_softc(dev, sc);
+ else
+ sc = device_get_softc(dev);
- err = (sc_attach_unit(device_get_unit(dev),
- device_get_flags(dev) | SC_AUTODETECT_KBD));
+ memset(&fb, 0, sizeof(fb));
+ if (bcm2835_mbox_fb_get_w_h(dev, &fb) != 0)
+ return (ENXIO);
+ fb.bpp = FB_DEPTH;
+ if (bcm2835_mbox_fb_init(dev, &fb) != 0)
+ return (ENXIO);
- if (err) {
+ sc->fb_addr = (intptr_t)pmap_mapdev(fb.base, fb.size);
+ sc->fb_paddr = fb.base;
+ sc->fb_size = fb.size;
+ sc->depth = fb.bpp;
+ sc->stride = fb.pitch;
+ sc->width = fb.xres;
+ sc->height = fb.yres;
+ bcmfb_update_margins(&sc->va);
+
+ if (sc_attach_unit(device_get_unit(dev),
+ device_get_flags(dev) | SC_AUTODETECT_KBD) != 0) {
device_printf(dev, "failed to attach syscons\n");
- goto fail;
+ return (ENXIO);
}
- /*
- * We have to wait until interrupts are enabled.
- * Mailbox relies on it to get data from VideoCore
- */
- sc->init_hook.ich_func = bcm_fb_init;
- sc->init_hook.ich_arg = sc;
-
- if (config_intrhook_establish(&sc->init_hook) != 0) {
- device_printf(dev, "failed to establish intrhook\n");
- return (ENOMEM);
- }
+ device_printf(dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres,
+ fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp);
+ device_printf(dev,
+ "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n",
+ sc->fbswap, fb.pitch, fb.base, fb.size);
return (0);
-
-fail:
- return (ENXIO);
-}
-
-
-static void
-bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
-{
- bus_addr_t *addr;
-
- if (err)
- return;
-
- addr = (bus_addr_t*)arg;
- *addr = PHYS_TO_VCBUS(segs[0].ds_addr);
}
static device_method_t bcm_fb_methods[] = {
@@ -504,13 +336,13 @@ bcmrend_set_cursor(scr_stat* scp, int base, int height, int blink)
static void
bcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
{
- video_adapter_t* adp = scp->sc->adp;
- struct video_adapter_softc *sc;
- int row, col;
+ int bytes, col, i, j, row;
+ struct bcmsc_softc *sc;
uint8_t *addr;
- int i, j, bytes;
+ video_adapter_t *adp;
- sc = (struct video_adapter_softc *)adp;
+ adp = scp->sc->adp;
+ sc = (struct bcmsc_softc *)adp;
if (scp->curs_attr.height <= 0)
return;
@@ -529,8 +361,7 @@ bcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
+ (row + sc->ymargin)*(sc->stride)
+ (sc->depth/8) * (col + sc->xmargin);
- bytes = sc->depth/8;
-
+ bytes = sc->depth / 8;
/* our cursor consists of simply inverting the char under it */
for (i = 0; i < adp->va_info.vi_cheight; i++) {
for (j = 0; j < adp->va_info.vi_cwidth; j++) {
@@ -577,56 +408,80 @@ extern u_char dflt_font_16[];
static void
bcmfb_update_margins(video_adapter_t *adp)
{
- struct video_adapter_softc *sc;
+ struct bcmsc_softc *sc;
video_info_t *vi;
- sc = (struct video_adapter_softc *)adp;
+ sc = (struct bcmsc_softc *)adp;
vi = &adp->va_info;
sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
- sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
+ sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2;
}
static int
bcmfb_configure(int flags)
{
- struct video_adapter_softc *va_sc;
-
- va_sc = &va_softc;
- phandle_t display, root;
+ char bootargs[2048], *n, *p, *v;
pcell_t cell;
+ phandle_t chosen, display, root;
+ struct bcmsc_softc *sc;
- if (va_sc->initialized)
+ sc = &bcmsc;
+ if (sc->initialized)
return (0);
- va_sc->width = 0;
- va_sc->height = 0;
+ sc->width = 0;
+ sc->height = 0;
/*
* It seems there is no way to let syscons framework know
* that framebuffer resolution has changed. So just try
- * to fetch data from FDT and go with defaults if failed
+ * to fetch data from FDT bootargs, FDT display data and
+ * finally go with defaults if everything else has failed.
*/
+ chosen = OF_finddevice("/chosen");
+ if (chosen != 0 &&
+ OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) {
+ p = bootargs;
+ while ((v = strsep(&p, " ")) != NULL) {
+ if (*v == '\0')
+ continue;
+ n = strsep(&v, "=");
+ if (strcmp(n, "bcm2708_fb.fbwidth") == 0 && v != NULL)
+ sc->width = (unsigned int)strtol(v, NULL, 0);
+ else if (strcmp(n, "bcm2708_fb.fbheight") == 0 &&
+ v != NULL)
+ sc->height = (unsigned int)strtol(v, NULL, 0);
+ else if (strcmp(n, "bcm2708_fb.fbswap") == 0 &&
+ v != NULL)
+ if (*v == '1')
+ sc->fbswap = 1;
+ }
+ }
+
root = OF_finddevice("/");
if ((root != 0) &&
(display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) {
- if ((OF_getprop(display, "broadcom,width",
- &cell, sizeof(cell))) > 0)
- va_sc->width = (int)fdt32_to_cpu(cell);
+ if (sc->width == 0) {
+ if ((OF_getprop(display, "broadcom,width",
+ &cell, sizeof(cell))) > 0)
+ sc->width = (int)fdt32_to_cpu(cell);
+ }
- if ((OF_getprop(display, "broadcom,height",
- &cell, sizeof(cell))) > 0)
- va_sc->height = (int)fdt32_to_cpu(cell);
+ if (sc->height == 0) {
+ if ((OF_getprop(display, "broadcom,height",
+ &cell, sizeof(cell))) > 0)
+ sc->height = (int)fdt32_to_cpu(cell);
+ }
}
- if (va_sc->width == 0)
- va_sc->width = FB_WIDTH;
- if (va_sc->height == 0)
- va_sc->height = FB_HEIGHT;
-
- bcmfb_init(0, &va_sc->va, 0);
+ if (sc->width == 0)
+ sc->width = FB_WIDTH;
+ if (sc->height == 0)
+ sc->height = FB_HEIGHT;
- va_sc->initialized = 1;
+ bcmfb_init(0, &sc->va, 0);
+ sc->initialized = 1;
return (0);
}
@@ -641,20 +496,19 @@ bcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
static int
bcmfb_init(int unit, video_adapter_t *adp, int flags)
{
- struct video_adapter_softc *sc;
+ struct bcmsc_softc *sc;
video_info_t *vi;
- sc = (struct video_adapter_softc *)adp;
+ sc = (struct bcmsc_softc *)adp;
vi = &adp->va_info;
vid_init_struct(adp, "bcmfb", -1, unit);
sc->font = dflt_font_16;
vi->vi_cheight = BCMFB_FONT_HEIGHT;
- vi->vi_cwidth = 8;
-
- vi->vi_width = sc->width/8;
- vi->vi_height = sc->height/vi->vi_cheight;
+ vi->vi_cwidth = BCMFB_FONT_WIDTH;
+ vi->vi_width = sc->width / vi->vi_cwidth;
+ vi->vi_height = sc->height / vi->vi_cheight;
/*
* Clamp width/height to syscons maximums
@@ -665,8 +519,7 @@ bcmfb_init(int unit, video_adapter_t *adp, int flags)
vi->vi_height = ROW;
sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
- sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
-
+ sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight)) / 2;
adp->va_window = (vm_offset_t) bcmfb_static_window;
adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
@@ -706,8 +559,9 @@ static int
bcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
u_char *data, int c, int count)
{
- struct video_adapter_softc *sc = (struct video_adapter_softc *)adp;
+ struct bcmsc_softc *sc;
+ sc = (struct bcmsc_softc *)adp;
sc->font = data;
return (0);
@@ -780,9 +634,9 @@ static int
bcmfb_blank_display(video_adapter_t *adp, int mode)
{
- struct video_adapter_softc *sc;
+ struct bcmsc_softc *sc;
- sc = (struct video_adapter_softc *)adp;
+ sc = (struct bcmsc_softc *)adp;
if (sc && sc->fb_addr)
memset((void*)sc->fb_addr, 0, sc->fb_size);
@@ -793,9 +647,9 @@ static int
bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
int prot, vm_memattr_t *memattr)
{
- struct video_adapter_softc *sc;
+ struct bcmsc_softc *sc;
- sc = (struct video_adapter_softc *)adp;
+ sc = (struct bcmsc_softc *)adp;
/*
* This might be a legacy VGA mem request: if so, just point it at the
@@ -812,10 +666,10 @@ bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
static int
bcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
{
- struct video_adapter_softc *sc;
+ struct bcmsc_softc *sc;
struct fbtype *fb;
- sc = (struct video_adapter_softc *)adp;
+ sc = (struct bcmsc_softc *)adp;
switch (cmd) {
case FBIOGTYPE:
@@ -897,16 +751,13 @@ bcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
static int
bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
{
- struct video_adapter_softc *sc;
- int row;
- int col;
- int i, j, k;
- uint8_t *addr;
+ int bytes, col, i, j, k, row;
+ struct bcmsc_softc *sc;
u_char *p;
- uint8_t fg, bg, color;
+ uint8_t *addr, fg, bg, color;
uint16_t rgb;
- sc = (struct video_adapter_softc *)adp;
+ sc = (struct bcmsc_softc *)adp;
if (sc->fb_addr == 0)
return (0);
@@ -921,6 +772,7 @@ bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
fg = a & 0xf ;
bg = (a >> 4) & 0xf;
+ bytes = sc->depth / 8;
for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
for (j = 0, k = 7; j < 8; j++, k--) {
if ((p[i] & (1 << k)) == 0)
@@ -930,22 +782,32 @@ bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
switch (sc->depth) {
case 32:
- addr[4*j+0] = bcmfb_palette[color].r;
- addr[4*j+1] = bcmfb_palette[color].g;
- addr[4*j+2] = bcmfb_palette[color].b;
- addr[4*j+3] = bcmfb_palette[color].a;
- break;
case 24:
- addr[3*j] = bcmfb_palette[color].r;
- addr[3*j+1] = bcmfb_palette[color].g;
- addr[3*j+2] = bcmfb_palette[color].b;
+ if (sc->fbswap) {
+ addr[bytes * j + 0] =
+ bcmfb_palette[color].b;
+ addr[bytes * j + 1] =
+ bcmfb_palette[color].g;
+ addr[bytes * j + 2] =
+ bcmfb_palette[color].r;
+ } else {
+ addr[bytes * j + 0] =
+ bcmfb_palette[color].r;
+ addr[bytes * j + 1] =
+ bcmfb_palette[color].g;
+ addr[bytes * j + 2] =
+ bcmfb_palette[color].b;
+ }
+ if (sc->depth == 32)
+ addr[bytes * j + 3] =
+ bcmfb_palette[color].a;
break;
case 16:
rgb = (bcmfb_palette[color].r >> 3) << 11;
rgb |= (bcmfb_palette[color].g >> 2) << 5;
rgb |= (bcmfb_palette[color].b >> 3);
- addr[2*j] = rgb & 0xff;
- addr[2*j + 1] = (rgb >> 8) & 0xff;
+ addr[bytes * j] = rgb & 0xff;
+ addr[bytes * j + 1] = (rgb >> 8) & 0xff;
default:
/* Not supported yet */
break;
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_fbd.c b/sys/arm/broadcom/bcm2835/bcm2835_fbd.c
index b3b0dd3..34a7af8 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_fbd.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_fbd.c
@@ -35,30 +35,13 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/bus.h>
-#include <sys/conf.h>
-#include <sys/endian.h>
+#include <sys/fbio.h>
#include <sys/kernel.h>
-#include <sys/kthread.h>
-#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/queue.h>
-#include <sys/resource.h>
-#include <sys/rman.h>
-#include <sys/time.h>
-#include <sys/timetc.h>
-#include <sys/fbio.h>
-#include <sys/consio.h>
-
-#include <sys/kdb.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-#include <machine/cpufunc.h>
-#include <machine/fdt.h>
-#include <machine/resource.h>
-#include <machine/intr.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
@@ -66,136 +49,21 @@ __FBSDID("$FreeBSD$");
#include <dev/fb/fbreg.h>
#include <dev/vt/vt.h>
+#include <dev/vt/colors/vt_termcolors.h>
-#include <arm/broadcom/bcm2835/bcm2835_mbox.h>
-#include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
+#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
#include "fb_if.h"
#include "mbox_if.h"
-#define FB_WIDTH 640
-#define FB_HEIGHT 480
-#define FB_DEPTH 24
-
-struct bcm_fb_config {
- uint32_t xres;
- uint32_t yres;
- uint32_t vxres;
- uint32_t vyres;
- uint32_t pitch;
- uint32_t bpp;
- uint32_t xoffset;
- uint32_t yoffset;
- /* Filled by videocore */
- uint32_t base;
- uint32_t screen_size;
-};
+#define FB_DEPTH 24
struct bcmsc_softc {
- device_t dev;
struct fb_info *info;
- bus_dma_tag_t dma_tag;
- bus_dmamap_t dma_map;
- struct bcm_fb_config* fb_config;
- bus_addr_t fb_config_phys;
- struct intr_config_hook init_hook;
};
static int bcm_fb_probe(device_t);
static int bcm_fb_attach(device_t);
-static void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg,
- int err);
-
-static void
-bcm_fb_init(void *arg)
-{
- volatile struct bcm_fb_config *fb_config;
- struct bcmsc_softc *sc;
- struct fb_info *info;
- phandle_t node;
- pcell_t cell;
- device_t mbox;
- device_t fbd;
- int err = 0;
-
- sc = arg;
- fb_config = sc->fb_config;
- node = ofw_bus_get_node(sc->dev);
-
- fb_config->xres = 0;
- fb_config->yres = 0;
- fb_config->bpp = 0;
- fb_config->vxres = 0;
- fb_config->vyres = 0;
- fb_config->xoffset = 0;
- fb_config->yoffset = 0;
- fb_config->base = 0;
- fb_config->pitch = 0;
- fb_config->screen_size = 0;
-
- if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0)
- fb_config->xres = (int)fdt32_to_cpu(cell);
- if (fb_config->xres == 0)
- fb_config->xres = FB_WIDTH;
-
- if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0)
- fb_config->yres = (uint32_t)fdt32_to_cpu(cell);
- if (fb_config->yres == 0)
- fb_config->yres = FB_HEIGHT;
-
- if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0)
- fb_config->bpp = (uint32_t)fdt32_to_cpu(cell);
- if (fb_config->bpp == 0)
- fb_config->bpp = FB_DEPTH;
-
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
- mbox = devclass_get_device(devclass_find("mbox"), 0);
- if (mbox) {
- MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_FB, sc->fb_config_phys);
- MBOX_READ(mbox, BCM2835_MBOX_CHAN_FB, &err);
- }
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_POSTREAD);
-
- if (fb_config->base != 0) {
- device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n",
- fb_config->xres, fb_config->yres,
- fb_config->vxres, fb_config->vyres,
- fb_config->xoffset, fb_config->yoffset,
- fb_config->bpp);
-
- device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n",
- fb_config->pitch, fb_config->base,
- fb_config->screen_size);
-
- info = malloc(sizeof(struct fb_info), M_DEVBUF,
- M_WAITOK | M_ZERO);
- info->fb_name = device_get_nameunit(sc->dev);
- info->fb_vbase = (intptr_t)pmap_mapdev(fb_config->base,
- fb_config->screen_size);
- info->fb_pbase = fb_config->base;
- info->fb_size = fb_config->screen_size;
- info->fb_bpp = info->fb_depth = fb_config->bpp;
- info->fb_stride = fb_config->pitch;
- info->fb_width = fb_config->xres;
- info->fb_height = fb_config->yres;
-
- sc->info = info;
-
- fbd = device_add_child(sc->dev, "fbd",
- device_get_unit(sc->dev));
- if (fbd == NULL)
- device_printf(sc->dev, "Failed to add fbd child\n");
- else if (device_probe_and_attach(fbd) != 0)
- device_printf(sc->dev, "Failed to attach fbd device\n");
- } else {
- device_printf(sc->dev, "Failed to set framebuffer info\n");
- }
-
- config_intrhook_disestablish(&sc->init_hook);
-}
static int
bcm_fb_probe(device_t dev)
@@ -211,66 +79,82 @@ bcm_fb_probe(device_t dev)
static int
bcm_fb_attach(device_t dev)
{
- struct bcmsc_softc *sc = device_get_softc(dev);
- int dma_size = sizeof(struct bcm_fb_config);
- int err;
-
- sc->dev = dev;
+ char bootargs[2048], *n, *p, *v;
+ device_t fbd;
+ int fbswap;
+ phandle_t chosen;
+ struct bcm2835_fb_config fb;
+ struct bcmsc_softc *sc;
+ struct fb_info *info;
- err = bus_dma_tag_create(
- bus_get_dma_tag(sc->dev),
- PAGE_SIZE, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- dma_size, 1, /* maxsize, nsegments */
- dma_size, 0, /* maxsegsize, flags */
- NULL, NULL, /* lockfunc, lockarg */
- &sc->dma_tag);
+ sc = device_get_softc(dev);
+ memset(&fb, 0, sizeof(fb));
+ if (bcm2835_mbox_fb_get_w_h(dev, &fb) != 0)
+ return (ENXIO);
+ fb.bpp = FB_DEPTH;
+ if (bcm2835_mbox_fb_init(dev, &fb) != 0)
+ return (ENXIO);
- err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config, 0,
- &sc->dma_map);
- if (err) {
- device_printf(dev, "cannot allocate framebuffer\n");
- goto fail;
+ info = malloc(sizeof(struct fb_info), M_DEVBUF, M_WAITOK | M_ZERO);
+ info->fb_name = device_get_nameunit(dev);
+ info->fb_vbase = (intptr_t)pmap_mapdev(fb.base, fb.size);
+ info->fb_pbase = fb.base;
+ info->fb_size = fb.size;
+ info->fb_bpp = info->fb_depth = fb.bpp;
+ info->fb_stride = fb.pitch;
+ info->fb_width = fb.xres;
+ info->fb_height = fb.yres;
+ sc->info = info;
+
+ /* Newer firmware versions needs an inverted color palette. */
+ fbswap = 0;
+ chosen = OF_finddevice("/chosen");
+ if (chosen != 0 &&
+ OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) {
+ p = bootargs;
+ while ((v = strsep(&p, " ")) != NULL) {
+ if (*v == '\0')
+ continue;
+ n = strsep(&v, "=");
+ if (strcmp(n, "bcm2708_fb.fbswap") == 0 && v != NULL)
+ if (*v == '1')
+ fbswap = 1;
+ }
+ }
+ if (fbswap) {
+ switch (info->fb_bpp) {
+ case 24:
+ vt_generate_cons_palette(info->fb_cmap,
+ COLOR_FORMAT_RGB, 0xff, 0, 0xff, 8, 0xff, 16);
+ info->fb_cmsize = 16;
+ break;
+ case 32:
+ vt_generate_cons_palette(info->fb_cmap,
+ COLOR_FORMAT_RGB, 0xff, 16, 0xff, 8, 0xff, 0);
+ info->fb_cmsize = 16;
+ break;
+ }
}
- err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config,
- dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT);
-
- if (err) {
- device_printf(dev, "cannot load DMA map\n");
- goto fail;
+ fbd = device_add_child(dev, "fbd", device_get_unit(dev));
+ if (fbd == NULL) {
+ device_printf(dev, "Failed to add fbd child\n");
+ free(info, M_DEVBUF);
+ return (ENXIO);
+ } else if (device_probe_and_attach(fbd) != 0) {
+ device_printf(dev, "Failed to attach fbd device\n");
+ device_delete_child(dev, fbd);
+ free(info, M_DEVBUF);
+ return (ENXIO);
}
- /*
- * We have to wait until interrupts are enabled.
- * Mailbox relies on it to get data from VideoCore
- */
- sc->init_hook.ich_func = bcm_fb_init;
- sc->init_hook.ich_arg = sc;
-
- if (config_intrhook_establish(&sc->init_hook) != 0) {
- device_printf(dev, "failed to establish intrhook\n");
- return (ENOMEM);
- }
+ device_printf(dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres,
+ fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp);
+ device_printf(dev,
+ "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n",
+ fbswap, fb.pitch, fb.base, fb.size);
return (0);
-
-fail:
- return (ENXIO);
-}
-
-static void
-bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
-{
- bus_addr_t *addr;
-
- if (err)
- return;
-
- addr = (bus_addr_t*)arg;
- *addr = PHYS_TO_VCBUS(segs[0].ds_addr);
}
static struct fb_info *
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
index 2ab7ebf..5940ad6 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
@@ -306,8 +306,7 @@ bcm2835_mbox_init_dma(device_t dev, size_t len, bus_dma_tag_t *tag,
return (NULL);
}
- err = bus_dmamap_load(*tag, *map, buf,
- sizeof(struct msg_set_power_state), bcm2835_mbox_dma_cb,
+ err = bus_dmamap_load(*tag, *map, buf, len, bcm2835_mbox_dma_cb,
phys, 0);
if (err != 0) {
bus_dmamem_free(*tag, buf, *map);
@@ -319,6 +318,47 @@ bcm2835_mbox_init_dma(device_t dev, size_t len, bus_dma_tag_t *tag,
return (buf);
}
+static int
+bcm2835_mbox_err(device_t dev, bus_addr_t msg_phys, uint32_t resp_phys,
+ struct bcm2835_mbox_hdr *msg, size_t len)
+{
+ int idx;
+ struct bcm2835_mbox_tag_hdr *tag;
+ uint8_t *last;
+
+ if ((uint32_t)msg_phys != resp_phys) {
+ device_printf(dev, "response channel mismatch\n");
+ return (EIO);
+ }
+ if (msg->code != BCM2835_MBOX_CODE_RESP_SUCCESS) {
+ device_printf(dev, "mbox response error\n");
+ return (EIO);
+ }
+
+ /* Loop until the end tag. */
+ tag = (struct bcm2835_mbox_tag_hdr *)(msg + 1);
+ last = (uint8_t *)msg + len;
+ for (idx = 0; tag->tag != 0; idx++) {
+ if ((tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE) == 0) {
+ device_printf(dev, "tag %d response error\n", idx);
+ return (EIO);
+ }
+ /* Clear the response bit. */
+ tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
+
+ /* Next tag. */
+ tag = (struct bcm2835_mbox_tag_hdr *)((uint8_t *)tag +
+ sizeof(*tag) + tag->val_buf_size);
+
+ if ((uint8_t *)tag > last) {
+ device_printf(dev, "mbox buffer size error\n");
+ return (EIO);
+ }
+ }
+
+ return (0);
+}
+
int
bcm2835_mbox_set_power_state(device_t dev, uint32_t device_id, boolean_t on)
{
@@ -414,3 +454,136 @@ bcm2835_mbox_get_clock_rate(device_t dev, uint32_t clock_id, uint32_t *hz)
return (0);
}
+
+int
+bcm2835_mbox_fb_get_w_h(device_t dev, struct bcm2835_fb_config *fb)
+{
+ device_t mbox;
+ int err;
+ bus_dma_tag_t msg_tag;
+ bus_dmamap_t msg_map;
+ bus_addr_t msg_phys;
+ struct msg_fb_get_w_h *msg;
+ uint32_t reg;
+
+ /* get mbox device */
+ mbox = devclass_get_device(devclass_find("mbox"), 0);
+ if (mbox == NULL) {
+ device_printf(dev, "can't find mbox\n");
+ return (ENXIO);
+ }
+
+ /* Allocate memory for the message */
+ msg = bcm2835_mbox_init_dma(dev, sizeof(*msg), &msg_tag, &msg_map,
+ &msg_phys);
+ if (msg == NULL)
+ return (ENOMEM);
+
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ BCM2835_MBOX_INIT_TAG(&msg->physical_w_h, GET_PHYSICAL_W_H);
+ msg->physical_w_h.tag_hdr.val_len = 0;
+ BCM2835_MBOX_INIT_TAG(&msg->virtual_w_h, GET_VIRTUAL_W_H);
+ msg->virtual_w_h.tag_hdr.val_len = 0;
+ BCM2835_MBOX_INIT_TAG(&msg->offset, GET_VIRTUAL_OFFSET);
+ msg->offset.tag_hdr.val_len = 0;
+ msg->end_tag = 0;
+
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREWRITE);
+ MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)msg_phys);
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREREAD);
+ MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &reg);
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTREAD);
+
+ err = bcm2835_mbox_err(dev, msg_phys, reg, &msg->hdr, sizeof(*msg));
+ if (err == 0) {
+ fb->xres = msg->physical_w_h.body.resp.width;
+ fb->yres = msg->physical_w_h.body.resp.height;
+ fb->vxres = msg->virtual_w_h.body.resp.width;
+ fb->vyres = msg->virtual_w_h.body.resp.height;
+ fb->xoffset = msg->offset.body.resp.x;
+ fb->yoffset = msg->offset.body.resp.y;
+ }
+
+ bus_dmamap_unload(msg_tag, msg_map);
+ bus_dmamem_free(msg_tag, msg, msg_map);
+ bus_dma_tag_destroy(msg_tag);
+
+ return (err);
+}
+
+int
+bcm2835_mbox_fb_init(device_t dev, struct bcm2835_fb_config *fb)
+{
+ device_t mbox;
+ int err;
+ bus_dma_tag_t msg_tag;
+ bus_dmamap_t msg_map;
+ bus_addr_t msg_phys;
+ struct msg_fb_setup *msg;
+ uint32_t reg;
+
+ /* get mbox device */
+ mbox = devclass_get_device(devclass_find("mbox"), 0);
+ if (mbox == NULL) {
+ device_printf(dev, "can't find mbox\n");
+ return (ENXIO);
+ }
+
+ /* Allocate memory for the message */
+ msg = bcm2835_mbox_init_dma(dev, sizeof(*msg), &msg_tag, &msg_map,
+ &msg_phys);
+ if (msg == NULL)
+ return (ENOMEM);
+
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ BCM2835_MBOX_INIT_TAG(&msg->physical_w_h, SET_PHYSICAL_W_H);
+ msg->physical_w_h.body.req.width = fb->xres;
+ msg->physical_w_h.body.req.height = fb->yres;
+ BCM2835_MBOX_INIT_TAG(&msg->virtual_w_h, SET_VIRTUAL_W_H);
+ msg->virtual_w_h.body.req.width = fb->vxres;
+ msg->virtual_w_h.body.req.height = fb->vyres;
+ BCM2835_MBOX_INIT_TAG(&msg->offset, GET_VIRTUAL_OFFSET);
+ msg->offset.body.req.x = fb->xoffset;
+ msg->offset.body.req.y = fb->yoffset;
+ BCM2835_MBOX_INIT_TAG(&msg->depth, SET_DEPTH);
+ msg->depth.body.req.bpp = fb->bpp;
+ BCM2835_MBOX_INIT_TAG(&msg->alpha, SET_ALPHA_MODE);
+ msg->alpha.body.req.alpha = BCM2835_MBOX_ALPHA_MODE_IGNORED;
+ BCM2835_MBOX_INIT_TAG(&msg->buffer, ALLOCATE_BUFFER);
+ msg->buffer.body.req.alignment = PAGE_SIZE;
+ BCM2835_MBOX_INIT_TAG(&msg->pitch, GET_PITCH);
+ msg->end_tag = 0;
+
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREWRITE);
+ MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)msg_phys);
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREREAD);
+ MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &reg);
+ bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTREAD);
+
+ err = bcm2835_mbox_err(dev, msg_phys, reg, &msg->hdr, sizeof(*msg));
+ if (err == 0) {
+ fb->xres = msg->physical_w_h.body.resp.width;
+ fb->yres = msg->physical_w_h.body.resp.height;
+ fb->vxres = msg->virtual_w_h.body.resp.width;
+ fb->vyres = msg->virtual_w_h.body.resp.height;
+ fb->xoffset = msg->offset.body.resp.x;
+ fb->yoffset = msg->offset.body.resp.y;
+ fb->pitch = msg->pitch.body.resp.pitch;
+ fb->base = msg->buffer.body.resp.fb_address;
+ fb->size = msg->buffer.body.resp.fb_size;
+ }
+
+ bus_dmamap_unload(msg_tag, msg_map);
+ bus_dmamem_free(msg_tag, msg, msg_map);
+ bus_dma_tag_destroy(msg_tag);
+
+ return (err);
+}
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h b/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
index 76f2a16..a425f2a 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
+++ b/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
@@ -52,6 +52,12 @@ struct bcm2835_mbox_tag_hdr {
uint32_t val_len;
};
+#define BCM2835_MBOX_INIT_TAG(tag_, tagid_) do { \
+ (tag_)->tag_hdr.tag = BCM2835_MBOX_TAG_##tagid_; \
+ (tag_)->tag_hdr.val_buf_size = sizeof((tag_)->body); \
+ (tag_)->tag_hdr.val_len = sizeof((tag_)->body.req); \
+} while (0)
+
#define BCM2835_MBOX_POWER_ID_EMMC 0x00000000
#define BCM2835_MBOX_POWER_ID_UART0 0x00000001
#define BCM2835_MBOX_POWER_ID_UART1 0x00000002
@@ -322,4 +328,151 @@ struct msg_get_max_temperature {
uint32_t end_tag;
};
+#define BCM2835_MBOX_TAG_GET_PHYSICAL_W_H 0x00040003
+#define BCM2835_MBOX_TAG_SET_PHYSICAL_W_H 0x00048003
+#define BCM2835_MBOX_TAG_GET_VIRTUAL_W_H 0x00040004
+#define BCM2835_MBOX_TAG_SET_VIRTUAL_W_H 0x00048004
+
+struct bcm2835_mbox_tag_fb_w_h {
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ uint32_t width;
+ uint32_t height;
+ } req;
+ struct {
+ uint32_t width;
+ uint32_t height;
+ } resp;
+ } body;
+};
+
+#define BCM2835_MBOX_TAG_GET_DEPTH 0x00040005
+#define BCM2835_MBOX_TAG_SET_DEPTH 0x00048005
+
+struct bcm2835_mbox_tag_depth {
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ uint32_t bpp;
+ } req;
+ struct {
+ uint32_t bpp;
+ } resp;
+ } body;
+};
+
+#define BCM2835_MBOX_TAG_GET_ALPHA_MODE 0x00040007
+#define BCM2835_MBOX_TAG_SET_ALPHA_MODE 0x00048007
+
+#define BCM2835_MBOX_ALPHA_MODE_0_OPAQUE 0
+#define BCM2835_MBOX_ALPHA_MODE_0_TRANSPARENT 1
+#define BCM2835_MBOX_ALPHA_MODE_IGNORED 2
+
+struct bcm2835_mbox_tag_alpha_mode {
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ uint32_t alpha;
+ } req;
+ struct {
+ uint32_t alpha;
+ } resp;
+ } body;
+};
+
+#define BCM2835_MBOX_TAG_GET_VIRTUAL_OFFSET 0x00040009
+#define BCM2835_MBOX_TAG_SET_VIRTUAL_OFFSET 0x00048009
+
+struct bcm2835_mbox_tag_virtual_offset {
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ uint32_t x;
+ uint32_t y;
+ } req;
+ struct {
+ uint32_t x;
+ uint32_t y;
+ } resp;
+ } body;
+};
+
+#define BCM2835_MBOX_TAG_GET_PITCH 0x00040008
+
+struct bcm2835_mbox_tag_pitch {
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ } req;
+ struct {
+ uint32_t pitch;
+ } resp;
+ } body;
+};
+
+#define BCM2835_MBOX_TAG_ALLOCATE_BUFFER 0x00040001
+
+struct bcm2835_mbox_tag_allocate_buffer {
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ uint32_t alignment;
+ } req;
+ struct {
+ uint32_t fb_address;
+ uint32_t fb_size;
+ } resp;
+ } body;
+};
+
+#define BCM2835_MBOX_TAG_RELEASE_BUFFER 0x00048001
+
+struct bcm2835_mbox_tag_release_buffer {
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ } req;
+ struct {
+ } resp;
+ } body;
+};
+
+struct bcm2835_fb_config {
+ uint32_t xres;
+ uint32_t yres;
+ uint32_t vxres;
+ uint32_t vyres;
+ uint32_t xoffset;
+ uint32_t yoffset;
+ uint32_t bpp;
+ uint32_t pitch;
+ uint32_t base;
+ uint32_t size;
+};
+
+struct msg_fb_get_w_h {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_fb_w_h physical_w_h;
+ struct bcm2835_mbox_tag_fb_w_h virtual_w_h;
+ struct bcm2835_mbox_tag_virtual_offset offset;
+ uint32_t end_tag;
+};
+
+int bcm2835_mbox_fb_get_w_h(device_t, struct bcm2835_fb_config *);
+
+struct msg_fb_setup {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_fb_w_h physical_w_h;
+ struct bcm2835_mbox_tag_fb_w_h virtual_w_h;
+ struct bcm2835_mbox_tag_virtual_offset offset;
+ struct bcm2835_mbox_tag_depth depth;
+ struct bcm2835_mbox_tag_alpha_mode alpha;
+ struct bcm2835_mbox_tag_allocate_buffer buffer;
+ struct bcm2835_mbox_tag_pitch pitch;
+ uint32_t end_tag;
+};
+
+int bcm2835_mbox_fb_init(device_t, struct bcm2835_fb_config *);
+
#endif /* _BCM2835_MBOX_PROP_H_ */
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c
index 19eeb71..1024a48 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c
@@ -181,17 +181,16 @@ bcm_sdhci_attach(device_t dev)
if (err == 0) {
/* Convert to MHz */
default_freq /= 1000000;
- if (bootverbose)
- device_printf(dev, "default frequency: %dMHz\n",
- default_freq);
+ }
+ if (default_freq == 0) {
+ node = ofw_bus_get_node(sc->sc_dev);
+ if ((OF_getencprop(node, "clock-frequency", &cell,
+ sizeof(cell))) > 0)
+ default_freq = cell / 1000000;
}
if (default_freq == 0)
default_freq = BCM2835_DEFAULT_SDHCI_FREQ;
- node = ofw_bus_get_node(sc->sc_dev);
- if ((OF_getprop(node, "clock-frequency", &cell, sizeof(cell))) > 0)
- default_freq = fdt32_to_cpu(cell)/1000000;
-
if (bootverbose)
device_printf(dev, "SDHCI frequency: %dMHz\n", default_freq);
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_spi.c b/sys/arm/broadcom/bcm2835/bcm2835_spi.c
index c9f6d33..3692c67 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_spi.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_spi.c
@@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/resource.h>
-#include <machine/fdt.h>
#include <machine/intr.h>
#include <dev/fdt/fdt_common.h>
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_systimer.c b/sys/arm/broadcom/bcm2835/bcm2835_systimer.c
index 5e73747..93bf676 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_systimer.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_systimer.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#define BCM2835_NUM_TIMERS 4
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_wdog.c b/sys/arm/broadcom/bcm2835/bcm2835_wdog.c
index 58cb2c3..ca823f1 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_wdog.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_wdog.c
@@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpufunc.h>
#include <machine/machdep.h>
-#include <machine/fdt.h>
#include <arm/broadcom/bcm2835/bcm2835_wdog.h>
diff --git a/sys/arm/broadcom/bcm2835/std.bcm2836 b/sys/arm/broadcom/bcm2835/std.bcm2836
index 874083f..bb112be 100644
--- a/sys/arm/broadcom/bcm2835/std.bcm2836
+++ b/sys/arm/broadcom/bcm2835/std.bcm2836
@@ -5,6 +5,8 @@ cpu CPU_CORTEXA
makeoptions CONF_CFLAGS="-march=armv7a"
options SOC_BCM2836
+options ARM_L2_PIPT
+
files "../broadcom/bcm2835/files.bcm2836"
files "../broadcom/bcm2835/files.bcm283x"
diff --git a/sys/arm/conf/AML8726 b/sys/arm/conf/AML8726
new file mode 100644
index 0000000..7272db4
--- /dev/null
+++ b/sys/arm/conf/AML8726
@@ -0,0 +1,143 @@
+#
+# Kernel configuration for Amlogic aml8726 boards.
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+ident AML8726
+include "../amlogic/aml8726/std.aml8726"
+
+options HZ=100
+options SCHED_ULE # ULE scheduler
+options PREEMPTION # Enable kernel thread preemption
+options INET # InterNETworking
+options INET6 # IPv6 communications protocols
+options SCTP # Stream Control Transmission Protocol
+options FFS # Berkeley Fast Filesystem
+options SOFTUPDATES # Enable FFS soft updates support
+options UFS_ACL # Support for access control lists
+options UFS_DIRHASH # Improve performance on big directories
+options UFS_GJOURNAL # Enable gjournal-based UFS journaling
+options QUOTA # Enable disk quotas for UFS
+options NFSCL # Network Filesystem Client
+options NFSLOCKD # Network Lock Manager
+options NFS_ROOT # NFS usable as /, requires NFSCL
+options MSDOSFS # MSDOS Filesystem
+options CD9660 # ISO 9660 Filesystem
+options PROCFS # Process filesystem (requires PSEUDOFS)
+options PSEUDOFS # Pseudo-filesystem framework
+options TMPFS # Efficient memory filesystem
+options GEOM_PART_GPT # GUID Partition Tables
+options GEOM_PART_BSD # BSD partition scheme
+options GEOM_PART_MBR # MBR partition scheme
+options COMPAT_43 # Compatible with BSD 4.3 [KEEP THIS!]
+options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
+options KTRACE # ktrace(1) support
+options SYSVSHM # SYSV-style shared memory
+options SYSVMSG # SYSV-style message queues
+options SYSVSEM # SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
+options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed.
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+options FREEBSD_BOOT_LOADER # Process metadata passed from loader(8)
+options LINUX_BOOT_ABI
+options VFP # Enable floating point hardware support
+options SMP # Enable multiple cores
+
+# Debugging
+makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
+options ALT_BREAK_TO_DEBUGGER
+#options VERBOSE_SYSINIT # Enable verbose sysinit messages
+options BOOTVERBOSE=1
+options KDB # Enable kernel debugger support
+# For minimum debugger support (stable branch) use:
+#options KDB_TRACE # Print a stack trace for a panic
+# For full debugger support use this instead:
+options DDB # Enable the kernel debugger
+options INVARIANTS # Enable calls of extra sanity checking
+options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
+options WITNESS # Enable checks to detect deadlocks and cycles
+options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
+#options DIAGNOSTIC
+
+# NFS root from boopt/dhcp
+#options BOOTP
+#options BOOTP_NFSROOT
+#options BOOTP_COMPAT
+#options BOOTP_NFSV3
+#options BOOTP_WIRED_TO=axe0
+
+# MMC/SD/SDIO Card slot support
+device mmc # mmc/sd bus
+device mmcsd # mmc/sd flash cards
+
+# Boot device is 2nd slice on MMC/SD card
+options ROOTDEVNAME=\"ufs:mmcsd0s2\"
+
+# GPIO
+device gpio
+device gpioled
+
+# I2C support
+device iicbus
+device iicbb
+device iic
+
+# vt is the default console driver, resembling an SCO console
+device vt
+#device kbdmux
+
+# Serial (COM) ports
+device uart # Generic UART driver
+
+# Pseudo devices.
+device loop # Network loopback
+device random # Entropy device
+device ether # Ethernet support
+device pty # BSD-style compatibility pseudo ttys
+
+# The `bpf' device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+# Note that 'bpf' is required for DHCP.
+device bpf # Berkeley packet filter
+
+# USB support
+device usb # General USB code (mandatory for USB)
+device dwcotg # DWC OTG controller
+options USB_HOST_ALIGN=64 # Align usb buffers to cache line size.
+options USB_DEBUG
+#options USB_REQ_DEBUG
+#options USB_VERBOSE
+
+#device ukbd # USB keyboard
+#device ums # USB mouse
+
+device scbus # SCSI bus (required for ATA/SCSI)
+device da # Direct Access (disks)
+device umass # Disks/Mass storage - Requires scbus and da
+
+# Ethernet support
+device miibus # MII bus support
+
+# SoC Ethernet, requires miibus
+device dwc
+
+# USB Ethernet support, requires miibus
+device axe # ASIX Electronics USB Ethernet
+
+# Flattened Device Tree
+options FDT # Configure using FDT/DTB data
diff --git a/sys/arm/conf/CUBIEBOARD b/sys/arm/conf/CUBIEBOARD
index f137b5a..945f0ae 100644
--- a/sys/arm/conf/CUBIEBOARD
+++ b/sys/arm/conf/CUBIEBOARD
@@ -139,4 +139,4 @@ device miibus
options FDT # Configure using FDT/DTB data
options FDT_DTB_STATIC
makeoptions FDT_DTS_FILE=cubieboard.dts
-
+makeoptions MODULES_EXTRA=dtb/allwinner
diff --git a/sys/arm/conf/CUBIEBOARD2 b/sys/arm/conf/CUBIEBOARD2
index 0aefc5f..d370dda 100644
--- a/sys/arm/conf/CUBIEBOARD2
+++ b/sys/arm/conf/CUBIEBOARD2
@@ -140,4 +140,4 @@ device miibus
options FDT # Configure using FDT/DTB data
options FDT_DTB_STATIC
makeoptions FDT_DTS_FILE=cubieboard2.dts
-
+makeoptions MODULES_EXTRA=dtb/allwinner
diff --git a/sys/arm/conf/EFIKA_MX b/sys/arm/conf/EFIKA_MX
index 6ea9d8a..a4690f6 100644
--- a/sys/arm/conf/EFIKA_MX
+++ b/sys/arm/conf/EFIKA_MX
@@ -24,6 +24,8 @@ include "../freescale/imx/std.imx51"
makeoptions WITHOUT_MODULES="ahc"
+options SOC_IMX51
+
options SCHED_4BSD # 4BSD scheduler
options PREEMPTION # Enable kernel thread preemption
options INET # InterNETworking
diff --git a/sys/arm/conf/IMX53 b/sys/arm/conf/IMX53
index d627c25..9f78f30 100644
--- a/sys/arm/conf/IMX53
+++ b/sys/arm/conf/IMX53
@@ -22,6 +22,8 @@ ident IMX53
include "../freescale/imx/std.imx53"
+options SOC_IMX53
+
options SCHED_4BSD # 4BSD scheduler
options PREEMPTION # Enable kernel thread preemption
options INET # InterNETworking
diff --git a/sys/arm/conf/IMX6 b/sys/arm/conf/IMX6
index ada4eea..f1baf29 100644
--- a/sys/arm/conf/IMX6
+++ b/sys/arm/conf/IMX6
@@ -21,6 +21,8 @@
ident IMX6
include "../freescale/imx/std.imx6"
+options SOC_IMX6
+
options HZ=500 # Scheduling quantum is 2 milliseconds.
options SCHED_ULE # ULE scheduler
options PREEMPTION # Enable kernel thread preemption
diff --git a/sys/arm/conf/ODROIDC1 b/sys/arm/conf/ODROIDC1
index 7d70fa4..7bb7b56 100644
--- a/sys/arm/conf/ODROIDC1
+++ b/sys/arm/conf/ODROIDC1
@@ -1,7 +1,7 @@
# ODROIDC1 -- Custom configuration for the HardKernel ODROID-C1 SBC
#
-# For more information on this file, please read the handbook section on
-# Kernel Configuration Files:
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
#
# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
#
@@ -17,117 +17,10 @@
#
# $FreeBSD$
-ident ODROIDC1
-
-include "../amlogic/aml8726/std.odroidc1"
-
-options HZ=100
-options SCHED_ULE # ULE scheduler
-options PREEMPTION # Enable kernel thread preemption
-options INET # InterNETworking
-options INET6 # IPv6 communications protocols
-options FFS # Berkeley Fast Filesystem
-options SOFTUPDATES # Enable FFS soft updates support
-options UFS_ACL # Support for access control lists
-options UFS_DIRHASH # Improve performance on big directories
-options PROCFS # Process filesystem (requires PSEUDOFS)
-options PSEUDOFS # Pseudo-filesystem framework
-options GEOM_PART_BSD # BSD partition scheme
-options GEOM_PART_MBR # MBR partition scheme
-options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
-options KTRACE # ktrace(1) support
-options SYSVSHM # SYSV-style shared memory
-options SYSVMSG # SYSV-style message queues
-options SYSVSEM # SYSV-style semaphores
-options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions
-options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed.
-options KBD_INSTALL_CDEV # install a CDEV entry in /dev
-options LINUX_BOOT_ABI
-options VFP # vfp/neon
-
-# Debugging
-makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
-options ALT_BREAK_TO_DEBUGGER
-#options VERBOSE_SYSINIT # Enable verbose sysinit messages
-options BOOTVERBOSE=1
-options KDB
-options DDB # Enable the kernel debugger
-options INVARIANTS # Enable calls of extra sanity checking
-options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
-options WITNESS # Enable checks to detect deadlocks and cycles
-options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
-#options DIAGNOSTIC
-
-# NFS support
-#options NFSCL # New Network Filesystem Client
-#options NFSLOCKD # Network Lock Manager
-#options NFS_ROOT # NFS usable as /, requires NFSCL
-
-# NFS root from boopt/dhcp
-#options BOOTP
-#options BOOTP_NFSROOT
-#options BOOTP_COMPAT
-#options BOOTP_NFSV3
-#options BOOTP_WIRED_TO=axe0
-
-# MMC/SD/SDIO card slot support
-device mmc # mmc/sd bus
-device mmcsd # mmc/sd flash cards
-
-# Boot device is 2nd slice on MMC/SD card
-options ROOTDEVNAME=\"ufs:mmcsd0s2\"
-
-# GPIO
-device gpio
-device gpioled
-
-# I2C support
-device iicbus
-device iicbb
-device iic
+#NO_UNIVERSE
-# vt is the default console driver, resembling an SCO console
-device vt
-#device kbdmux
-
-# Serial (COM) ports
-device uart # Generic UART driver
-
-# Pseudo devices.
-device loop # Network loopback
-device random # Entropy device
-device ether # Ethernet support
-device pty # BSD-style compatibility pseudo ttys
-
-# The `bpf' device enables the Berkeley Packet Filter.
-# Be aware of the administrative consequences of enabling this!
-# Note that 'bpf' is required for DHCP.
-device bpf # Berkeley packet filter
-
-# USB support
-device usb # General USB code (mandatory for USB)
-device dwcotg # DWC OTG controller
-options USB_HOST_ALIGN=64 # Cacheline size is 64
-options USB_DEBUG
-#options USB_REQ_DEBUG
-#options USB_VERBOSE
-
-#device ukbd # USB keyboard
-#device ums # USB mouse
-
-device scbus # SCSI bus (required for ATA/SCSI)
-device da # Direct Access (disks)
-device umass # Disks/Mass storage - Requires scbus and da
-
-# Ethernet support
-device miibus # MII bus support
-
-# SoC Ethernet, requires miibus
-device dwc
-
-# USB Ethernet, requires miibus
-device axe # ASIX Electronics USB Ethernet
+include "AML8726"
+ident ODROIDC1
-# Flattened Device Tree
-options FDT
-options FDT_DTB_STATIC
+options FDT_DTB_STATIC
+makeoptions FDT_DTS_FILE=odroidc1.dts
diff --git a/sys/arm/conf/RK3188 b/sys/arm/conf/RK3188
index 2aba68e..64065d3 100644
--- a/sys/arm/conf/RK3188
+++ b/sys/arm/conf/RK3188
@@ -72,8 +72,8 @@ options WITNESS # Enable checks to detect deadlocks and cycles
options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
options DIAGNOSTIC
-# Boot device is 2nd slice on USB
-options ROOTDEVNAME=\"ufs:/dev/da0s2\"
+# Root mount from MMC/SD card
+options ROOTDEVNAME=\"ufs:/dev/mmcsd0\"
# MMC/SD/SDIO Card slot support
device mmc # mmc/sd bus
diff --git a/sys/arm/conf/RPI2 b/sys/arm/conf/RPI2
index 02f3869..5383601 100644
--- a/sys/arm/conf/RPI2
+++ b/sys/arm/conf/RPI2
@@ -1,5 +1,5 @@
#
-# RPI-B -- Custom configuration for the Raspberry Pi
+# RPI2 -- Custom configuration for the Raspberry Pi 2
#
# For more information on this file, please read the config(5) manual page,
# and/or the handbook section on Kernel Configuration Files:
@@ -18,7 +18,7 @@
#
# $FreeBSD$
-ident RPI-B
+ident RPI2
include "../broadcom/bcm2835/std.rpi"
include "../broadcom/bcm2835/std.bcm2836"
@@ -137,6 +137,6 @@ device bcm2835_spi
options FDT # Configure using FDT/DTB data
# Note: DTB is normally loaded and modified by RPi boot loader, then
# handed to kernel via U-Boot and ubldr.
-options FDT_DTB_STATIC
-makeoptions FDT_DTS_FILE=rpi2.dts
+#options FDT_DTB_STATIC
+#makeoptions FDT_DTS_FILE=rpi2.dts
makeoptions MODULES_EXTRA=dtb/rpi
diff --git a/sys/arm/conf/VIRT b/sys/arm/conf/VIRT
new file mode 100644
index 0000000..c4f9405
--- /dev/null
+++ b/sys/arm/conf/VIRT
@@ -0,0 +1,97 @@
+#
+# VIRT -- Custom configuration for the qemu virt platform
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+ident VIRT
+
+include "../qemu/std.virt"
+
+options HZ=100
+options SCHED_4BSD # 4BSD scheduler
+options PREEMPTION # Enable kernel thread preemption
+options INET # InterNETworking
+options INET6 # IPv6 communications protocols
+options SCTP # Stream Control Transmission Protocol
+options FFS # Berkeley Fast Filesystem
+options SOFTUPDATES # Enable FFS soft updates support
+options UFS_ACL # Support for access control lists
+options UFS_DIRHASH # Improve performance on big directories
+options UFS_GJOURNAL # Enable gjournal-based UFS journaling
+options QUOTA # Enable disk quotas for UFS
+options NFSCL # Network Filesystem Client
+options NFSLOCKD # Network Lock Manager
+options NFS_ROOT # NFS usable as /, requires NFSCL
+options MSDOSFS # MSDOS Filesystem
+options CD9660 # ISO 9660 Filesystem
+options PROCFS # Process filesystem (requires PSEUDOFS)
+options PSEUDOFS # Pseudo-filesystem framework
+options TMPFS # Efficient memory filesystem
+options GEOM_PART_GPT # GUID Partition Tables
+options GEOM_PART_BSD # BSD partition scheme
+options GEOM_PART_MBR # MBR partition scheme
+options GEOM_LABEL # Provides labelization
+options COMPAT_43 # Compatible with BSD 4.3 [KEEP THIS!]
+options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
+options KTRACE # ktrace(1) support
+options SYSVSHM # SYSV-style shared memory
+options SYSVMSG # SYSV-style message queues
+options SYSVSEM # SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+options PLATFORM
+options FREEBSD_BOOT_LOADER # Process metadata passed from loader(8)
+options VFP # Enable floating point hardware support
+options ARM_NEW_PMAP # Enable the new v6 pmap
+
+# Debugging for use in -current
+makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
+options BREAK_TO_DEBUGGER
+options ALT_BREAK_TO_DEBUGGER
+#options VERBOSE_SYSINIT # Enable verbose sysinit messages
+options KDB # Enable kernel debugger support
+# For minimum debugger support (stable branch) use:
+#options KDB_TRACE # Print a stack trace for a panic
+# For full debugger support use this instead:
+options DDB # Enable the kernel debugger
+options INVARIANTS # Enable calls of extra sanity checking
+options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
+#options WITNESS # Enable checks to detect deadlocks and cycles
+#options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
+#options DIAGNOSTIC
+
+device bpf
+device loop
+device ether
+device uart
+device pty
+device snp
+device pl011
+device psci
+
+device virtio
+device virtio_mmio
+device virtio_blk
+device vtnet
+
+device md
+device random # Entropy device
+
+# Flattened Device Tree
+options FDT # Configure using FDT/DTB data
+
diff --git a/sys/arm/conf/VSATV102 b/sys/arm/conf/VSATV102
index a3df9fa..b5de5f9 100644
--- a/sys/arm/conf/VSATV102
+++ b/sys/arm/conf/VSATV102
@@ -1,7 +1,7 @@
# VSATV102 -- Custom configuration for the Visson ATV-102 media player
#
-# For more information on this file, please read the handbook section on
-# Kernel Configuration Files:
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
#
# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
#
@@ -17,117 +17,10 @@
#
# $FreeBSD$
-ident VSATV102
-
-include "../amlogic/aml8726/std.vsatv102-m6"
-
-options HZ=100
-options SCHED_ULE # ULE scheduler
-options PREEMPTION # Enable kernel thread preemption
-options INET # InterNETworking
-options INET6 # IPv6 communications protocols
-options FFS # Berkeley Fast Filesystem
-options SOFTUPDATES # Enable FFS soft updates support
-options UFS_ACL # Support for access control lists
-options UFS_DIRHASH # Improve performance on big directories
-options PROCFS # Process filesystem (requires PSEUDOFS)
-options PSEUDOFS # Pseudo-filesystem framework
-options GEOM_PART_BSD # BSD partition scheme
-options GEOM_PART_MBR # MBR partition scheme
-options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
-options KTRACE # ktrace(1) support
-options SYSVSHM # SYSV-style shared memory
-options SYSVMSG # SYSV-style message queues
-options SYSVSEM # SYSV-style semaphores
-options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions
-options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed.
-options KBD_INSTALL_CDEV # install a CDEV entry in /dev
-options LINUX_BOOT_ABI
-options VFP # vfp/neon
-
-# Debugging
-makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
-options ALT_BREAK_TO_DEBUGGER
-#options VERBOSE_SYSINIT # Enable verbose sysinit messages
-options BOOTVERBOSE=1
-options KDB
-options DDB # Enable the kernel debugger
-options INVARIANTS # Enable calls of extra sanity checking
-options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
-options WITNESS # Enable checks to detect deadlocks and cycles
-options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
-#options DIAGNOSTIC
-
-# NFS support
-#options NFSCL # New Network Filesystem Client
-#options NFSLOCKD # Network Lock Manager
-#options NFS_ROOT # NFS usable as /, requires NFSCL
-
-# NFS root from boopt/dhcp
-#options BOOTP
-#options BOOTP_NFSROOT
-#options BOOTP_COMPAT
-#options BOOTP_NFSV3
-#options BOOTP_WIRED_TO=axe0
-
-# MMC/SD/SDIO card slot support
-device mmc # mmc/sd bus
-device mmcsd # mmc/sd flash cards
-
-# Boot device is 2nd slice on MMC/SD card
-options ROOTDEVNAME=\"ufs:mmcsd0s2\"
-
-# GPIO
-device gpio
-device gpioled
-
-# I2C support
-device iicbus
-device iicbb
-device iic
+#NO_UNIVERSE
-# vt is the default console driver, resembling an SCO console
-device vt
-#device kbdmux
-
-# Serial (COM) ports
-device uart # Generic UART driver
-
-# Pseudo devices.
-device loop # Network loopback
-device random # Entropy device
-device ether # Ethernet support
-device pty # BSD-style compatibility pseudo ttys
-
-# The `bpf' device enables the Berkeley Packet Filter.
-# Be aware of the administrative consequences of enabling this!
-# Note that 'bpf' is required for DHCP.
-device bpf # Berkeley packet filter
-
-# USB support
-device usb # General USB code (mandatory for USB)
-device dwcotg # DWC OTG controller
-options USB_HOST_ALIGN=64 # Cacheline size is 64
-options USB_DEBUG
-#options USB_REQ_DEBUG
-#options USB_VERBOSE
-
-#device ukbd # USB keyboard
-#device ums # USB mouse
-
-device scbus # SCSI bus (required for ATA/SCSI)
-device da # Direct Access (disks)
-device umass # Disks/Mass storage - Requires scbus and da
-
-# Ethernet support
-device miibus # MII bus support
-
-# SoC Ethernet, requires miibus
-device dwc
-
-# USB Ethernet, requires miibus
-device axe # ASIX Electronics USB Ethernet
+include "AML8726"
+ident VSATV102
-# Flattened Device Tree
-options FDT
-options FDT_DTB_STATIC
+options FDT_DTB_STATIC
+makeoptions FDT_DTS_FILE=vsatv102-m6.dts
diff --git a/sys/arm/freescale/imx/files.imx53 b/sys/arm/freescale/imx/files.imx5
index 6ca4ffd..58e925b 100644
--- a/sys/arm/freescale/imx/files.imx53
+++ b/sys/arm/freescale/imx/files.imx5
@@ -6,14 +6,15 @@ kern/kern_clocksource.c standard
# Init
arm/freescale/imx/imx_common.c standard
arm/freescale/imx/imx_machdep.c standard
-arm/freescale/imx/imx53_machdep.c standard
+arm/freescale/imx/imx51_machdep.c optional soc_imx51
+arm/freescale/imx/imx53_machdep.c optional soc_imx53
arm/arm/bus_space_base.c standard
# Special serial console for debuging early boot code
#arm/freescale/imx/console.c standard
# UART driver (includes serial console support)
-dev/uart/uart_dev_imx.c optional uart
+dev/uart/uart_dev_imx.c optional uart
# TrustZone Interrupt Controller
arm/freescale/imx/tzic.c standard
diff --git a/sys/arm/freescale/imx/files.imx51 b/sys/arm/freescale/imx/files.imx51
deleted file mode 100644
index b779ee2..0000000
--- a/sys/arm/freescale/imx/files.imx51
+++ /dev/null
@@ -1,49 +0,0 @@
-# $FreeBSD$
-arm/arm/bus_space_asm_generic.S standard
-arm/arm/bus_space_generic.c standard
-kern/kern_clocksource.c standard
-
-# Init
-arm/freescale/imx/imx_common.c standard
-arm/freescale/imx/imx_machdep.c standard
-arm/freescale/imx/imx51_machdep.c standard
-arm/arm/bus_space_base.c standard
-
-# Dummy serial console
-#arm/freescale/imx/console.c standard
-
-# TrustZone Interrupt Controller
-arm/freescale/imx/tzic.c standard
-
-# IOMUX - external pins multiplexor
-arm/freescale/imx/imx_iomux.c standard
-
-# GPIO
-arm/freescale/imx/imx_gpio.c optional gpio
-
-# Generic Periodic Timer
-arm/freescale/imx/imx_gpt.c standard
-
-# Clock Configuration Manager
-arm/freescale/imx/imx51_ccm.c standard
-
-# i.MX5xx PATA controller
-dev/ata/chipsets/ata-fsl.c optional imxata
-
-# UART driver
-dev/uart/uart_dev_imx.c optional uart
-
-# USB OH3 controller (1 OTG, 3 EHCI)
-arm/freescale/imx/imx_nop_usbphy.c optional ehci
-dev/usb/controller/ehci_imx.c optional ehci
-
-# Watchdog
-arm/freescale/imx/imx_wdog.c optional imxwdt
-
-# i2c
-arm/freescale/imx/imx_i2c.c optional fsliic
-
-# IPU - Image Processing Unit (frame buffer also)
-arm/freescale/imx/imx51_ipuv3.c optional sc
-arm/freescale/imx/imx51_ipuv3_fbd.c optional vt
-dev/vt/hw/fb/vt_early_fb.c optional vt
diff --git a/sys/arm/freescale/imx/imx51_ccm.c b/sys/arm/freescale/imx/imx51_ccm.c
index 8e099ce5..7a05d1e 100644
--- a/sys/arm/freescale/imx/imx51_ccm.c
+++ b/sys/arm/freescale/imx/imx51_ccm.c
@@ -78,7 +78,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <arm/freescale/imx/imx51_ccmvar.h>
#include <arm/freescale/imx/imx51_ccmreg.h>
diff --git a/sys/arm/freescale/imx/imx51_ipuv3.c b/sys/arm/freescale/imx/imx51_ipuv3.c
index 6c0a9eb..3da87a9 100644
--- a/sys/arm/freescale/imx/imx51_ipuv3.c
+++ b/sys/arm/freescale/imx/imx51_ipuv3.c
@@ -53,6 +53,9 @@ __FBSDID("$FreeBSD$");
#include <sys/kdb.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
diff --git a/sys/arm/freescale/imx/imx51_ipuv3_fbd.c b/sys/arm/freescale/imx/imx51_ipuv3_fbd.c
index 4828240..3852754 100644
--- a/sys/arm/freescale/imx/imx51_ipuv3_fbd.c
+++ b/sys/arm/freescale/imx/imx51_ipuv3_fbd.c
@@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
-#include <machine/fdt.h>
#include <machine/resource.h>
#include <machine/frame.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/imx/imx6_anatop.c b/sys/arm/freescale/imx/imx6_anatop.c
index 644ac7f..a384501 100644
--- a/sys/arm/freescale/imx/imx6_anatop.c
+++ b/sys/arm/freescale/imx/imx6_anatop.c
@@ -67,7 +67,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <arm/arm/mpcore_timervar.h>
#include <arm/freescale/fsl_ocotpreg.h>
diff --git a/sys/arm/freescale/imx/imx6_audmux.c b/sys/arm/freescale/imx/imx6_audmux.c
index 4ea2109..3b08a14 100644
--- a/sys/arm/freescale/imx/imx6_audmux.c
+++ b/sys/arm/freescale/imx/imx6_audmux.c
@@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/imx/imx6_mp.c b/sys/arm/freescale/imx/imx6_mp.c
index afadee0..b02588c 100644
--- a/sys/arm/freescale/imx/imx6_mp.c
+++ b/sys/arm/freescale/imx/imx6_mp.c
@@ -34,6 +34,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/imx/imx6_sdma.c b/sys/arm/freescale/imx/imx6_sdma.c
index 4a4c287..91d66af 100644
--- a/sys/arm/freescale/imx/imx6_sdma.c
+++ b/sys/arm/freescale/imx/imx6_sdma.c
@@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/imx/imx6_ssi.c b/sys/arm/freescale/imx/imx6_ssi.c
index af8a9e8..184de2a 100644
--- a/sys/arm/freescale/imx/imx6_ssi.c
+++ b/sys/arm/freescale/imx/imx6_ssi.c
@@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/imx/imx_common.c b/sys/arm/freescale/imx/imx_common.c
index 3b7139c..0fe7082 100644
--- a/sys/arm/freescale/imx/imx_common.c
+++ b/sys/arm/freescale/imx/imx_common.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/vmparam.h>
struct fdt_fixup_entry fdt_fixup_table[] = {
diff --git a/sys/arm/freescale/imx/imx_gpt.c b/sys/arm/freescale/imx/imx_gpt.c
index 6f77963..8da0b2e 100644
--- a/sys/arm/freescale/imx/imx_gpt.c
+++ b/sys/arm/freescale/imx/imx_gpt.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/intr.h>
-#include <machine/fdt.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
diff --git a/sys/arm/freescale/imx/imx_iomux.c b/sys/arm/freescale/imx/imx_iomux.c
index d1ac6cb..c130b78 100644
--- a/sys/arm/freescale/imx/imx_iomux.c
+++ b/sys/arm/freescale/imx/imx_iomux.c
@@ -58,7 +58,6 @@
#include <sys/rman.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <dev/fdt/fdt_common.h>
#include <dev/fdt/fdt_pinctrl.h>
diff --git a/sys/arm/freescale/imx/imx_wdog.c b/sys/arm/freescale/imx/imx_wdog.c
index cadd1d7..9ac5826 100644
--- a/sys/arm/freescale/imx/imx_wdog.c
+++ b/sys/arm/freescale/imx/imx_wdog.c
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include <machine/fdt.h>
#include <arm/freescale/imx/imx_wdogreg.h>
diff --git a/sys/arm/freescale/imx/std.imx51 b/sys/arm/freescale/imx/std.imx51
index fbc1349..eca33c2 100644
--- a/sys/arm/freescale/imx/std.imx51
+++ b/sys/arm/freescale/imx/std.imx51
@@ -13,5 +13,4 @@ options PHYSADDR=0x90000000
device fdt_pinctrl
-files "../freescale/imx/files.imx51"
-
+files "../freescale/imx/files.imx5"
diff --git a/sys/arm/freescale/imx/std.imx53 b/sys/arm/freescale/imx/std.imx53
index cbef21a..1da484c 100644
--- a/sys/arm/freescale/imx/std.imx53
+++ b/sys/arm/freescale/imx/std.imx53
@@ -13,5 +13,4 @@ options PHYSADDR=0x70000000
device fdt_pinctrl
-files "../freescale/imx/files.imx53"
-
+files "../freescale/imx/files.imx5"
diff --git a/sys/arm/freescale/vybrid/vf_adc.c b/sys/arm/freescale/vybrid/vf_adc.c
index f497ec0..0a806fb 100644
--- a/sys/arm/freescale/vybrid/vf_adc.c
+++ b/sys/arm/freescale/vybrid/vf_adc.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_anadig.c b/sys/arm/freescale/vybrid/vf_anadig.c
index 77946d3..3a2cbc4 100644
--- a/sys/arm/freescale/vybrid/vf_anadig.c
+++ b/sys/arm/freescale/vybrid/vf_anadig.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_ccm.c b/sys/arm/freescale/vybrid/vf_ccm.c
index 30df67a..8f8a3f0 100644
--- a/sys/arm/freescale/vybrid/vf_ccm.c
+++ b/sys/arm/freescale/vybrid/vf_ccm.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_dcu4.c b/sys/arm/freescale/vybrid/vf_dcu4.c
index d2ddddc..34dea46 100644
--- a/sys/arm/freescale/vybrid/vf_dcu4.c
+++ b/sys/arm/freescale/vybrid/vf_dcu4.c
@@ -47,6 +47,9 @@ __FBSDID("$FreeBSD$");
#include <sys/eventhandler.h>
#include <sys/gpio.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
diff --git a/sys/arm/freescale/vybrid/vf_dmamux.c b/sys/arm/freescale/vybrid/vf_dmamux.c
index 1909621..a887ffa 100644
--- a/sys/arm/freescale/vybrid/vf_dmamux.c
+++ b/sys/arm/freescale/vybrid/vf_dmamux.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_edma.c b/sys/arm/freescale/vybrid/vf_edma.c
index c5df919..ed12072 100644
--- a/sys/arm/freescale/vybrid/vf_edma.c
+++ b/sys/arm/freescale/vybrid/vf_edma.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_gpio.c b/sys/arm/freescale/vybrid/vf_gpio.c
index 4f458a1..0c1cf82 100644
--- a/sys/arm/freescale/vybrid/vf_gpio.c
+++ b/sys/arm/freescale/vybrid/vf_gpio.c
@@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_i2c.c b/sys/arm/freescale/vybrid/vf_i2c.c
index 2eb6726..c554ce2 100644
--- a/sys/arm/freescale/vybrid/vf_i2c.c
+++ b/sys/arm/freescale/vybrid/vf_i2c.c
@@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_iomuxc.c b/sys/arm/freescale/vybrid/vf_iomuxc.c
index 8d8f7fd..95711d6 100644
--- a/sys/arm/freescale/vybrid/vf_iomuxc.c
+++ b/sys/arm/freescale/vybrid/vf_iomuxc.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_mscm.c b/sys/arm/freescale/vybrid/vf_mscm.c
index b07181e..02850e5 100644
--- a/sys/arm/freescale/vybrid/vf_mscm.c
+++ b/sys/arm/freescale/vybrid/vf_mscm.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_nfc.c b/sys/arm/freescale/vybrid/vf_nfc.c
index 28db4c6..62b7782 100644
--- a/sys/arm/freescale/vybrid/vf_nfc.c
+++ b/sys/arm/freescale/vybrid/vf_nfc.c
@@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$");
#include <dev/nand/nandbus.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include "nfc_if.h"
diff --git a/sys/arm/freescale/vybrid/vf_port.c b/sys/arm/freescale/vybrid/vf_port.c
index 1cc83ed..943ca88 100644
--- a/sys/arm/freescale/vybrid/vf_port.c
+++ b/sys/arm/freescale/vybrid/vf_port.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_sai.c b/sys/arm/freescale/vybrid/vf_sai.c
index 586055d..309d95e 100644
--- a/sys/arm/freescale/vybrid/vf_sai.c
+++ b/sys/arm/freescale/vybrid/vf_sai.c
@@ -53,7 +53,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_spi.c b/sys/arm/freescale/vybrid/vf_spi.c
index 222b96f..8fa466b 100644
--- a/sys/arm/freescale/vybrid/vf_spi.c
+++ b/sys/arm/freescale/vybrid/vf_spi.c
@@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_src.c b/sys/arm/freescale/vybrid/vf_src.c
index ac9b23b..83d7e96 100644
--- a/sys/arm/freescale/vybrid/vf_src.c
+++ b/sys/arm/freescale/vybrid/vf_src.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_tcon.c b/sys/arm/freescale/vybrid/vf_tcon.c
index 2cc4a6a..31f85b5 100644
--- a/sys/arm/freescale/vybrid/vf_tcon.c
+++ b/sys/arm/freescale/vybrid/vf_tcon.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/freescale/vybrid/vf_uart.c b/sys/arm/freescale/vybrid/vf_uart.c
index da11871..312f18c 100644
--- a/sys/arm/freescale/vybrid/vf_uart.c
+++ b/sys/arm/freescale/vybrid/vf_uart.c
@@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$");
#include <sys/conf.h>
#include <sys/kdb.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_cpu.h>
@@ -277,7 +276,8 @@ static struct uart_class uart_vybrid_class = {
sizeof(struct vf_uart_softc),
.uc_ops = &uart_vybrid_ops,
.uc_range = 0x100,
- .uc_rclk = 24000000 /* TODO: get value from CCM */
+ .uc_rclk = 24000000, /* TODO: get value from CCM */
+ .uc_rshift = 0
};
static struct ofw_compat_data compat_data[] = {
diff --git a/sys/arm/include/fdt.h b/sys/arm/include/fdt.h
index 9bd9332..c1b785e 100644
--- a/sys/arm/include/fdt.h
+++ b/sys/arm/include/fdt.h
@@ -32,13 +32,7 @@
#ifndef _MACHINE_FDT_H_
#define _MACHINE_FDT_H_
-#include <dev/ofw/openfirm.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
#include <machine/bus.h>
-#include <machine/intr.h>
/* Max interrupt number */
#define FDT_INTR_MAX NIRQ
@@ -51,8 +45,4 @@
*/
extern bus_space_tag_t fdtbus_bs_tag;
-struct arm_devmap_entry;
-
-int fdt_localbus_devmap(phandle_t, struct arm_devmap_entry *, int, int *);
-
#endif /* _MACHINE_FDT_H_ */
diff --git a/sys/arm/include/metadata.h b/sys/arm/include/metadata.h
index 0ef3f41..cf4c9bb 100644
--- a/sys/arm/include/metadata.h
+++ b/sys/arm/include/metadata.h
@@ -31,5 +31,12 @@
#define MODINFOMD_BOOTINFO 0x1001
#define MODINFOMD_DTBP 0x1002
+#define MODINFOMD_EFI_MAP 0x1003
+
+struct efi_map_header {
+ uint64_t memory_size;
+ uint64_t descriptor_size;
+ uint32_t descriptor_version;
+};
#endif /* !_MACHINE_METADATA_H_ */
diff --git a/sys/arm/include/pmap-v6.h b/sys/arm/include/pmap-v6.h
index 54c0f85..bb58682 100644
--- a/sys/arm/include/pmap-v6.h
+++ b/sys/arm/include/pmap-v6.h
@@ -190,7 +190,8 @@ void *pmap_mapdev_attr(vm_paddr_t, vm_size_t, int);
boolean_t pmap_page_is_mapped(vm_page_t );
void pmap_page_set_memattr(vm_page_t , vm_memattr_t );
void pmap_unmapdev(vm_offset_t, vm_size_t);
-void pmap_kenter_device(vm_offset_t , vm_paddr_t );
+void pmap_kenter_device(vm_offset_t, vm_size_t, vm_paddr_t);
+void pmap_kremove_device(vm_offset_t, vm_size_t);
void pmap_set_pcb_pagedir(pmap_t , struct pcb *);
void pmap_lazyfix_action(void);
diff --git a/sys/arm/include/pmap.h b/sys/arm/include/pmap.h
index b88ca32..c42a36f 100644
--- a/sys/arm/include/pmap.h
+++ b/sys/arm/include/pmap.h
@@ -258,7 +258,8 @@ void pmap_bootstrap(vm_offset_t firstaddr, struct pv_addr *l1pt);
int pmap_change_attr(vm_offset_t, vm_size_t, int);
void pmap_kenter(vm_offset_t va, vm_paddr_t pa);
void pmap_kenter_nocache(vm_offset_t va, vm_paddr_t pa);
-void pmap_kenter_device(vm_offset_t va, vm_paddr_t pa);
+void pmap_kenter_device(vm_offset_t, vm_size_t, vm_paddr_t);
+void pmap_kremove_device(vm_offset_t, vm_size_t);
void *pmap_kenter_temporary(vm_paddr_t pa, int i);
void pmap_kenter_user(vm_offset_t va, vm_paddr_t pa);
vm_paddr_t pmap_kextract(vm_offset_t va);
diff --git a/sys/arm/mv/armadaxp/armadaxp_mp.c b/sys/arm/mv/armadaxp/armadaxp_mp.c
index 775fc09..1fa4d53 100644
--- a/sys/arm/mv/armadaxp/armadaxp_mp.c
+++ b/sys/arm/mv/armadaxp/armadaxp_mp.c
@@ -36,6 +36,7 @@
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <vm/vm_extern.h>
+#include <vm/pmap.h>
#include <dev/fdt/fdt_common.h>
diff --git a/sys/arm/mv/gpio.c b/sys/arm/mv/gpio.c
index 2e255aa..79b7cc6 100644
--- a/sys/arm/mv/gpio.c
+++ b/sys/arm/mv/gpio.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <sys/queue.h>
#include <sys/timetc.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/intr.h>
#include <dev/fdt/fdt_common.h>
diff --git a/sys/arm/mv/mv_localbus.c b/sys/arm/mv/mv_localbus.c
index 8d91c41..59cccc4 100644
--- a/sys/arm/mv/mv_localbus.c
+++ b/sys/arm/mv/mv_localbus.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include "dev/fdt/fdt_common.h"
#include "ofw_bus_if.h"
+#include <arm/mv/mvvar.h>
#include <arm/mv/mvwin.h>
#ifdef DEBUG
diff --git a/sys/arm/mv/mv_ts.c b/sys/arm/mv/mv_ts.c
index 7c2a113..7606859 100644
--- a/sys/arm/mv/mv_ts.c
+++ b/sys/arm/mv/mv_ts.c
@@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/sysctl.h>
-#include <machine/fdt.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
diff --git a/sys/arm/mv/mvvar.h b/sys/arm/mv/mvvar.h
index a9b2bb0..7166fab 100644
--- a/sys/arm/mv/mvvar.h
+++ b/sys/arm/mv/mvvar.h
@@ -140,5 +140,6 @@ struct arm_devmap_entry;
int mv_pci_devmap(phandle_t, struct arm_devmap_entry *, vm_offset_t,
vm_offset_t);
+int fdt_localbus_devmap(phandle_t, struct arm_devmap_entry *, int, int *);
#endif /* _MVVAR_H_ */
diff --git a/sys/arm/qemu/files.qemu b/sys/arm/qemu/files.qemu
new file mode 100644
index 0000000..d23524e
--- /dev/null
+++ b/sys/arm/qemu/files.qemu
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+#
+# Standard ARM support.
+#
+arm/arm/bus_space_base.c standard
+arm/arm/bus_space_generic.c standard
+kern/kern_clocksource.c standard
+
+#
+# Standard qemu virt devices and support.
+#
+arm/arm/gic.c standard
+arm/arm/generic_timer.c standard
+arm/qemu/virt_common.c standard
+arm/qemu/virt_machdep.c standard
diff --git a/sys/arm/qemu/std.virt b/sys/arm/qemu/std.virt
new file mode 100644
index 0000000..ca6a06f
--- /dev/null
+++ b/sys/arm/qemu/std.virt
@@ -0,0 +1,15 @@
+# $FreeBSD$
+machine arm armv6
+cpu CPU_CORTEXA
+makeoptions CONF_CFLAGS="-march=armv7a"
+makeoptions ARM_LITTLE_ENDIAN
+options ARM_L2_PIPT
+
+options KERNVIRTADDR = 0xc1000000
+makeoptions KERNVIRTADDR = 0xc1000000
+
+options IPI_IRQ_START=0
+options IPI_IRQ_END=15
+
+files "../qemu/files.qemu"
+
diff --git a/sys/arm/qemu/virt_common.c b/sys/arm/qemu/virt_common.c
new file mode 100644
index 0000000..fc02247
--- /dev/null
+++ b/sys/arm/qemu/virt_common.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2015 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#include <machine/intr.h>
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
+fdt_pic_decode_t fdt_pic_table[] = {
+ &gic_decode_fdt,
+ NULL
+};
diff --git a/lib/libc/sys/mmap.c b/sys/arm/qemu/virt_machdep.c
index 0fa03ba..6b0cba2 100644
--- a/lib/libc/sys/mmap.c
+++ b/sys/arm/qemu/virt_machdep.c
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
+/*-
+ * Copyright (c) 2015 Andrew Turner
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,14 +10,11 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -25,32 +22,71 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
*/
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)mmap.c 8.1 (Berkeley) 6/17/93";
-#endif /* LIBC_SCCS and not lint */
+#include "opt_platform.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include "libc_private.h"
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+
+#include <machine/bus.h>
+#include <machine/devmap.h>
+#include <machine/platform.h>
+#include <machine/platformvar.h>
+
+#include "platform_if.h"
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+ return (0);
+}
+
+void
+cpu_reset(void)
+{
+
+ while (1);
+}
+
+static vm_offset_t
+virt_lastaddr(platform_t plat)
+{
+
+ return (arm_devmap_lastaddr());
+}
/*
- * This function provides 64-bit offset padding that
- * is not supplied by GCC 1.X but is supplied by GCC 2.X.
+ * Set up static device mappings.
*/
-void *
-mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+static int
+virt_devmap_init(platform_t plat)
{
- if (__getosreldate() >= 700051) {
- return (__sys_mmap(addr, len, prot, flags, fd, offset));
- } else {
- return (__sys_freebsd6_mmap(addr, len, prot, flags, fd, 0,
- offset));
- }
+ arm_devmap_add_entry(0x09000000, 0x100000); /* Uart */
+ return (0);
}
+
+static platform_method_t virt_methods[] = {
+ PLATFORMMETHOD(platform_devmap_init, virt_devmap_init),
+ PLATFORMMETHOD(platform_lastaddr, virt_lastaddr),
+
+ PLATFORMMETHOD_END,
+};
+
+FDT_PLATFORM_DEF(virt, "virt", 0, "linux,dummy-virt");
diff --git a/sys/arm/rockchip/rk30xx_common.c b/sys/arm/rockchip/rk30xx_common.c
index 6eb892c..eff1824 100644
--- a/sys/arm/rockchip/rk30xx_common.c
+++ b/sys/arm/rockchip/rk30xx_common.c
@@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/vmparam.h>
struct fdt_fixup_entry fdt_fixup_table[] = {
diff --git a/sys/arm/rockchip/rk30xx_gpio.c b/sys/arm/rockchip/rk30xx_gpio.c
index ce20c1c..2c95fb9 100644
--- a/sys/arm/rockchip/rk30xx_gpio.c
+++ b/sys/arm/rockchip/rk30xx_gpio.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/resource.h>
-#include <machine/fdt.h>
#include <machine/intr.h>
#include <dev/fdt/fdt_common.h>
diff --git a/sys/arm/rockchip/rk30xx_grf.c b/sys/arm/rockchip/rk30xx_grf.c
index 29da576..ce61e8c 100644
--- a/sys/arm/rockchip/rk30xx_grf.c
+++ b/sys/arm/rockchip/rk30xx_grf.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include "rk30xx_grf.h"
diff --git a/sys/arm/rockchip/rk30xx_mp.c b/sys/arm/rockchip/rk30xx_mp.c
index 1232611..74c8b55 100644
--- a/sys/arm/rockchip/rk30xx_mp.c
+++ b/sys/arm/rockchip/rk30xx_mp.c
@@ -33,6 +33,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
diff --git a/sys/arm/rockchip/rk30xx_pmu.c b/sys/arm/rockchip/rk30xx_pmu.c
index 517aef3..514e961 100644
--- a/sys/arm/rockchip/rk30xx_pmu.c
+++ b/sys/arm/rockchip/rk30xx_pmu.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include "rk30xx_pmu.h"
diff --git a/sys/arm/samsung/exynos/exynos5_mp.c b/sys/arm/samsung/exynos/exynos5_mp.c
index fa0fa07..1b3afbb 100644
--- a/sys/arm/samsung/exynos/exynos5_mp.c
+++ b/sys/arm/samsung/exynos/exynos5_mp.c
@@ -33,6 +33,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
diff --git a/sys/arm/samsung/exynos/exynos_uart.c b/sys/arm/samsung/exynos/exynos_uart.c
index 9e33bcb..7b372de 100644
--- a/sys/arm/samsung/exynos/exynos_uart.c
+++ b/sys/arm/samsung/exynos/exynos_uart.c
@@ -380,6 +380,7 @@ static struct uart_class uart_exynos4210_class = {
.uc_ops = &uart_exynos4210_ops,
.uc_range = 8,
.uc_rclk = 0,
+ .uc_rshift = 0
};
static struct ofw_compat_data compat_data[] = {
diff --git a/sys/arm/samsung/s3c2xx0/uart_dev_s3c2410.c b/sys/arm/samsung/s3c2xx0/uart_dev_s3c2410.c
index 2ee1217..cc0d59a 100644
--- a/sys/arm/samsung/s3c2xx0/uart_dev_s3c2410.c
+++ b/sys/arm/samsung/s3c2xx0/uart_dev_s3c2410.c
@@ -402,4 +402,5 @@ struct uart_class uart_s3c2410_class = {
.uc_ops = &uart_s3c2410_ops,
.uc_range = 8,
.uc_rclk = 0,
+ .uc_rshift = 0
};
diff --git a/sys/arm/ti/am335x/am335x_dmtimer.c b/sys/arm/ti/am335x/am335x_dmtimer.c
index 09acb3d..7ba171e 100644
--- a/sys/arm/ti/am335x/am335x_dmtimer.c
+++ b/sys/arm/ti/am335x/am335x_dmtimer.c
@@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <arm/ti/ti_prcm.h>
#include <arm/ti/ti_scm.h>
diff --git a/sys/arm/ti/am335x/am335x_prcm.c b/sys/arm/ti/am335x/am335x_prcm.c
index 4b3a245..d9f4db1 100644
--- a/sys/arm/ti/am335x/am335x_prcm.c
+++ b/sys/arm/ti/am335x/am335x_prcm.c
@@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#define CM_PER 0
#define CM_PER_L4LS_CLKSTCTRL (CM_PER + 0x000)
diff --git a/sys/arm/ti/omap4/omap4_mp.c b/sys/arm/ti/omap4/omap4_mp.c
index e298cd1..6423e56 100644
--- a/sys/arm/ti/omap4/omap4_mp.c
+++ b/sys/arm/ti/omap4/omap4_mp.c
@@ -31,6 +31,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
diff --git a/sys/arm/ti/ti_common.c b/sys/arm/ti/ti_common.c
index 5fb72b7..4d12c71 100644
--- a/sys/arm/ti/ti_common.c
+++ b/sys/arm/ti/ti_common.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/vmparam.h>
struct fdt_fixup_entry fdt_fixup_table[] = {
diff --git a/sys/arm/ti/ti_mbox.c b/sys/arm/ti/ti_mbox.c
index 3fb5c33..1f8cde1 100644
--- a/sys/arm/ti/ti_mbox.c
+++ b/sys/arm/ti/ti_mbox.c
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <arm/ti/ti_mbox.h>
#include <arm/ti/ti_prcm.h>
diff --git a/sys/arm/ti/ti_pruss.c b/sys/arm/ti/ti_pruss.c
index 9a981d8..805476b 100644
--- a/sys/arm/ti/ti_pruss.c
+++ b/sys/arm/ti/ti_pruss.c
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <arm/ti/ti_prcm.h>
#include <arm/ti/ti_pruss.h>
diff --git a/sys/arm/ti/ti_wdt.c b/sys/arm/ti/ti_wdt.c
index 7e8e5ae..2b51cc2 100644
--- a/sys/arm/ti/ti_wdt.c
+++ b/sys/arm/ti/ti_wdt.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <arm/ti/ti_prcm.h>
#include <arm/ti/ti_wdt.h>
diff --git a/sys/arm/versatile/pl050.c b/sys/arm/versatile/pl050.c
index ec26f2a..c5d8a61 100644
--- a/sys/arm/versatile/pl050.c
+++ b/sys/arm/versatile/pl050.c
@@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$");
#include <dev/kbd/kbdreg.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <dev/kbd/kbdtables.h>
diff --git a/sys/arm/versatile/sp804.c b/sys/arm/versatile/sp804.c
index 5f986b1..a69c018 100644
--- a/sys/arm/versatile/sp804.c
+++ b/sys/arm/versatile/sp804.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#define SP804_TIMER1_LOAD 0x00
#define SP804_TIMER1_VALUE 0x04
diff --git a/sys/arm/versatile/versatile_clcd.c b/sys/arm/versatile/versatile_clcd.c
index 804c24f..76c6c63 100644
--- a/sys/arm/versatile/versatile_clcd.c
+++ b/sys/arm/versatile/versatile_clcd.c
@@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$");
#include <dev/syscons/syscons.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#define PL110_VENDOR_ARM926PXP 1
diff --git a/sys/arm/versatile/versatile_common.c b/sys/arm/versatile/versatile_common.c
index 7a9e42f..bcb504a 100644
--- a/sys/arm/versatile/versatile_common.c
+++ b/sys/arm/versatile/versatile_common.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/vmparam.h>
struct fdt_fixup_entry fdt_fixup_table[] = {
diff --git a/sys/arm/versatile/versatile_pci.c b/sys/arm/versatile/versatile_pci.c
index 7b198ca..10f3119 100644
--- a/sys/arm/versatile/versatile_pci.c
+++ b/sys/arm/versatile/versatile_pci.c
@@ -35,6 +35,10 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/watchdog.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr.h>
diff --git a/sys/arm/versatile/versatile_timer.c b/sys/arm/versatile/versatile_timer.c
index 5231ef1c..c5f6def 100644
--- a/sys/arm/versatile/versatile_timer.c
+++ b/sys/arm/versatile/versatile_timer.c
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
void
cpu_initclocks(void)
diff --git a/sys/arm/xilinx/zy7_mp.c b/sys/arm/xilinx/zy7_mp.c
index b6a540f..305290e 100644
--- a/sys/arm/xilinx/zy7_mp.c
+++ b/sys/arm/xilinx/zy7_mp.c
@@ -31,6 +31,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
diff --git a/sys/arm64/arm64/autoconf.c b/sys/arm64/arm64/autoconf.c
new file mode 100644
index 0000000..c29b335
--- /dev/null
+++ b/sys/arm64/arm64/autoconf.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Setup the system to run on the current machine.
+ *
+ * Configure() is called at boot time and initializes the vba
+ * device tables and the memory controller monitoring. Available
+ * devices are determined (from possibilities mentioned in ioconf.c),
+ * and the drivers are initialized.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/kernel.h>
+
+#include <machine/intr.h>
+
+static void configure_first(void *);
+static void configure(void *);
+static void configure_final(void *);
+
+SYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL);
+/* SI_ORDER_SECOND is hookable */
+SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL);
+/* SI_ORDER_MIDDLE is hookable */
+SYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL);
+
+/*
+ * Determine i/o configuration for a machine.
+ */
+static void
+configure_first(void *dummy)
+{
+
+ /* nexus0 is the top of the device tree */
+ device_add_child(root_bus, "nexus", 0);
+}
+
+static void
+configure(void *dummy)
+{
+
+ /* initialize new bus architecture */
+ root_bus_configure();
+}
+
+static void
+configure_final(void *dummy)
+{
+ arm_enable_intr();
+ cninit_finish();
+
+ if (bootverbose)
+ printf("Device configuration finished.\n");
+
+ cold = 0;
+}
diff --git a/sys/arm64/arm64/bcopy.c b/sys/arm64/arm64/bcopy.c
new file mode 100644
index 0000000..613ca97
--- /dev/null
+++ b/sys/arm64/arm64/bcopy.c
@@ -0,0 +1,139 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: sys/powerpc/powerpc/bcopy.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef long word; /* "word" used for optimal copy speed */
+
+#define wsize sizeof(word)
+#define wmask (wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+void *
+memcpy(void *dst0, const void *src0, size_t length)
+{
+ char *dst;
+ const char *src;
+ size_t t;
+
+ dst = dst0;
+ src = src0;
+
+ if (length == 0 || dst == src) { /* nothing to do */
+ goto done;
+ }
+
+ /*
+ * Macros: loop-t-times; and loop-t-times, t>0
+ */
+#define TLOOP(s) if (t) TLOOP1(s)
+#define TLOOP1(s) do { s; } while (--t)
+
+ if ((unsigned long)dst < (unsigned long)src) {
+ /*
+ * Copy forward.
+ */
+ t = (size_t)src; /* only need low bits */
+
+ if ((t | (uintptr_t)dst) & wmask) {
+ /*
+ * Try to align operands. This cannot be done
+ * unless the low bits match.
+ */
+ if ((t ^ (uintptr_t)dst) & wmask || length < wsize) {
+ t = length;
+ } else {
+ t = wsize - (t & wmask);
+ }
+
+ length -= t;
+ TLOOP1(*dst++ = *src++);
+ }
+ /*
+ * Copy whole words, then mop up any trailing bytes.
+ */
+ t = length / wsize;
+ TLOOP(*(word *)dst = *(const word *)src; src += wsize;
+ dst += wsize);
+ t = length & wmask;
+ TLOOP(*dst++ = *src++);
+ } else {
+ /*
+ * Copy backwards. Otherwise essentially the same.
+ * Alignment works as before, except that it takes
+ * (t&wmask) bytes to align, not wsize-(t&wmask).
+ */
+ src += length;
+ dst += length;
+ t = (uintptr_t)src;
+
+ if ((t | (uintptr_t)dst) & wmask) {
+ if ((t ^ (uintptr_t)dst) & wmask || length <= wsize) {
+ t = length;
+ } else {
+ t &= wmask;
+ }
+
+ length -= t;
+ TLOOP1(*--dst = *--src);
+ }
+ t = length / wsize;
+ TLOOP(src -= wsize; dst -= wsize;
+ *(word *)dst = *(const word *)src);
+ t = length & wmask;
+ TLOOP(*--dst = *--src);
+ }
+done:
+ return (dst0);
+}
+
+void
+bcopy(const void *src0, void *dst0, size_t length)
+{
+
+ memcpy(dst0, src0, length);
+}
+
diff --git a/sys/arm64/arm64/bus_machdep.c b/sys/arm64/arm64/bus_machdep.c
new file mode 100644
index 0000000..25a675e
--- /dev/null
+++ b/sys/arm64/arm64/bus_machdep.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "opt_platform.h"
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+
+uint8_t generic_bs_r_1(void *, bus_space_handle_t, bus_size_t);
+uint16_t generic_bs_r_2(void *, bus_space_handle_t, bus_size_t);
+uint32_t generic_bs_r_4(void *, bus_space_handle_t, bus_size_t);
+uint64_t generic_bs_r_8(void *, bus_space_handle_t, bus_size_t);
+
+void generic_bs_rm_1(void *, bus_space_handle_t, bus_size_t, uint8_t *,
+ bus_size_t);
+void generic_bs_rm_2(void *, bus_space_handle_t, bus_size_t, uint16_t *,
+ bus_size_t);
+void generic_bs_rm_4(void *, bus_space_handle_t, bus_size_t, uint32_t *,
+ bus_size_t);
+void generic_bs_rm_8(void *, bus_space_handle_t, bus_size_t, uint64_t *,
+ bus_size_t);
+
+void generic_bs_w_1(void *, bus_space_handle_t, bus_size_t, uint8_t);
+void generic_bs_w_2(void *, bus_space_handle_t, bus_size_t, uint16_t);
+void generic_bs_w_4(void *, bus_space_handle_t, bus_size_t, uint32_t);
+void generic_bs_w_8(void *, bus_space_handle_t, bus_size_t, uint64_t);
+
+void generic_bs_wm_1(void *, bus_space_handle_t, bus_size_t, const uint8_t *,
+ bus_size_t);
+void generic_bs_wm_2(void *, bus_space_handle_t, bus_size_t, const uint16_t *,
+ bus_size_t);
+void generic_bs_wm_4(void *, bus_space_handle_t, bus_size_t, const uint32_t *,
+ bus_size_t);
+void generic_bs_wm_8(void *, bus_space_handle_t, bus_size_t, const uint64_t *,
+ bus_size_t);
+
+static int
+generic_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags,
+ bus_space_handle_t *bshp)
+{
+ void *va;
+
+ va = pmap_mapdev(bpa, size);
+ if (va == NULL)
+ return (ENOMEM);
+ *bshp = (bus_space_handle_t)va;
+ return (0);
+}
+
+static void
+generic_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size)
+{
+
+ pmap_unmapdev(bsh, size);
+}
+
+static void
+generic_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, int flags)
+{
+}
+
+static int
+generic_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, bus_space_handle_t *nbshp)
+{
+
+ *nbshp = bsh + offset;
+ return (0);
+}
+
+struct bus_space memmap_bus = {
+ /* cookie */
+ .bs_cookie = NULL,
+
+ /* mapping/unmapping */
+ .bs_map = generic_bs_map,
+ .bs_unmap = generic_bs_unmap,
+ .bs_subregion = generic_bs_subregion,
+
+ /* allocation/deallocation */
+ .bs_alloc = NULL,
+ .bs_free = NULL,
+
+ /* barrier */
+ .bs_barrier = generic_bs_barrier,
+
+ /* read single */
+ .bs_r_1 = generic_bs_r_1,
+ .bs_r_2 = generic_bs_r_2,
+ .bs_r_4 = generic_bs_r_4,
+ .bs_r_8 = generic_bs_r_8,
+
+ /* read multiple */
+ .bs_rm_1 = generic_bs_rm_1,
+ .bs_rm_2 = generic_bs_rm_2,
+ .bs_rm_4 = generic_bs_rm_4,
+ .bs_rm_8 = generic_bs_rm_8,
+
+ /* write single */
+ .bs_w_1 = generic_bs_w_1,
+ .bs_w_2 = generic_bs_w_2,
+ .bs_w_4 = generic_bs_w_4,
+ .bs_w_8 = generic_bs_w_8,
+
+ /* write multiple */
+ .bs_wm_1 = generic_bs_wm_1,
+ .bs_wm_2 = generic_bs_wm_2,
+ .bs_wm_4 = generic_bs_wm_4,
+ .bs_wm_8 = generic_bs_wm_8,
+
+ /* write region */
+ .bs_wr_1 = NULL,
+ .bs_wr_2 = NULL,
+ .bs_wr_4 = NULL,
+ .bs_wr_8 = NULL,
+
+ /* set multiple */
+ .bs_sm_1 = NULL,
+ .bs_sm_2 = NULL,
+ .bs_sm_4 = NULL,
+ .bs_sm_8 = NULL,
+
+ /* set region */
+ .bs_sr_1 = NULL,
+ .bs_sr_2 = NULL,
+ .bs_sr_4 = NULL,
+ .bs_sr_8 = NULL,
+
+ /* copy */
+ .bs_c_1 = NULL,
+ .bs_c_2 = NULL,
+ .bs_c_4 = NULL,
+ .bs_c_8 = NULL,
+
+ /* read single stream */
+ .bs_r_1_s = NULL,
+ .bs_r_2_s = NULL,
+ .bs_r_4_s = NULL,
+ .bs_r_8_s = NULL,
+
+ /* read multiple stream */
+ .bs_rm_1_s = generic_bs_rm_1,
+ .bs_rm_2_s = generic_bs_rm_2,
+ .bs_rm_4_s = generic_bs_rm_4,
+ .bs_rm_8_s = generic_bs_rm_8,
+
+ /* read region stream */
+ .bs_rr_1_s = NULL,
+ .bs_rr_2_s = NULL,
+ .bs_rr_4_s = NULL,
+ .bs_rr_8_s = NULL,
+
+ /* write single stream */
+ .bs_w_1_s = NULL,
+ .bs_w_2_s = NULL,
+ .bs_w_4_s = NULL,
+ .bs_w_8_s = NULL,
+
+ /* write multiple stream */
+ .bs_wm_1_s = generic_bs_wm_1,
+ .bs_wm_2_s = generic_bs_wm_2,
+ .bs_wm_4_s = generic_bs_wm_4,
+ .bs_wm_8_s = generic_bs_wm_8,
+
+ /* write region stream */
+ .bs_wr_1_s = NULL,
+ .bs_wr_2_s = NULL,
+ .bs_wr_4_s = NULL,
+ .bs_wr_8_s = NULL,
+};
+
+#ifdef FDT
+bus_space_tag_t fdtbus_bs_tag = &memmap_bus;
+#endif
diff --git a/sys/arm64/arm64/bus_space_asm.S b/sys/arm64/arm64/bus_space_asm.S
new file mode 100644
index 0000000..20d4128
--- /dev/null
+++ b/sys/arm64/arm64/bus_space_asm.S
@@ -0,0 +1,235 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+
+ENTRY(generic_bs_r_1)
+ ldrb w0, [x1, x2]
+ ret
+END(generic_bs_r_1)
+
+ENTRY(generic_bs_r_2)
+ ldrh w0, [x1, x2]
+ ret
+END(generic_bs_r_2)
+
+ENTRY(generic_bs_r_4)
+ ldr w0, [x1, x2]
+ ret
+END(generic_bs_r_4)
+
+ENTRY(generic_bs_r_8)
+ ldr x0, [x1, x2]
+ ret
+END(generic_bs_r_8)
+
+ENTRY(generic_bs_rm_1)
+ /* If there is anything to read. */
+ cbz x4, 2f
+
+ /* Calculate the device address. */
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Read the data. */
+1: ldrb w1, [x0]
+ strb w1, [x3], #1
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_rm_1)
+
+ENTRY(generic_bs_rm_2)
+ /* If there is anything to read. */
+ cbz x4, 2f
+
+ /* Calculate the device address. */
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Read the data. */
+1: ldrh w1, [x0]
+ strh w1, [x3], #2
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_rm_2)
+
+ENTRY(generic_bs_rm_4)
+ /* If there is anything to read. */
+ cbz x4, 2f
+
+ /* Calculate the device address. */
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Read the data. */
+1: ldr w1, [x0]
+ str w1, [x3], #4
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_rm_4)
+
+ENTRY(generic_bs_rm_8)
+ /* If there is anything to read. */
+ cbz x4, 2f
+
+ /* Calculate the device address. */
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Read the data. */
+1: ldr x1, [x0]
+ str x1, [x3], #8
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_rm_8)
+
+
+ENTRY(generic_bs_w_1)
+ strb w3, [x1, x2]
+ ret
+END(generic_bs_w_1)
+
+ENTRY(generic_bs_w_2)
+ strh w3, [x1, x2]
+ ret
+END(generic_bs_w_2)
+
+ENTRY(generic_bs_w_4)
+ str w3, [x1, x2]
+ ret
+END(generic_bs_w_4)
+
+ENTRY(generic_bs_w_8)
+ str x3, [x1, x2]
+ ret
+END(generic_bs_w_8)
+
+ENTRY(generic_bs_wm_1)
+ /* If there is anything to write. */
+ cbz x4, 2f
+
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Write the data */
+1: ldrb w1, [x3], #1
+ strb w1, [x0]
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_wm_1)
+
+ENTRY(generic_bs_wm_2)
+ /* If there is anything to write. */
+ cbz x4, 2f
+
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Write the data */
+1: ldrh w1, [x3], #2
+ strh w1, [x0]
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_wm_2)
+
+ENTRY(generic_bs_wm_4)
+ /* If there is anything to write. */
+ cbz x4, 2f
+
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Write the data */
+1: ldr w1, [x3], #4
+ str w1, [x0]
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_wm_4)
+
+ENTRY(generic_bs_wm_8)
+ /* If there is anything to write. */
+ cbz x4, 2f
+
+ add x0, x1, x2
+ /*
+ * x0 = The device address.
+ * x3 = The kernel address.
+ * x4 = Count
+ */
+
+ /* Write the data */
+1: ldr x1, [x3], #8
+ str x1, [x0]
+ subs x4, x4, #1
+ b.ne 1b
+
+2: ret
+END(generic_bs_wm_8)
diff --git a/sys/arm64/arm64/busdma_machdep.c b/sys/arm64/arm64/busdma_machdep.c
new file mode 100644
index 0000000..4a89b1f
--- /dev/null
+++ b/sys/arm64/arm64/busdma_machdep.c
@@ -0,0 +1,68 @@
+/* $FreeBSD$ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+
+int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
+ bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp)
+{
+
+ panic("_bus_dmamap_load_phys");
+}
+
+int
+_bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map, struct vm_page **ma,
+ bus_size_t tlen, int ma_offs, int flags, bus_dma_segment_t *segs,
+ int *segp)
+{
+
+ panic("_bus_dmamap_load_ma");
+}
+
+int
+_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
+ bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
+ int *segp)
+{
+
+ panic("_bus_dmamap_load_buffer");
+}
+
+void
+__bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map,
+ struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg)
+{
+
+ panic("__bus_dmamap_waitok");
+}
+
+bus_dma_segment_t *
+_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map,
+ bus_dma_segment_t *segs, int nsegs, int error)
+{
+
+ panic("_bus_dmamap_complete");
+}
+
+void
+_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+
+ panic("_bus_dmamap_unload");
+}
+
+void
+_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
+{
+
+ panic("_bus_dmamap_sync");
+}
diff --git a/sys/arm64/arm64/clock.c b/sys/arm64/arm64/clock.c
new file mode 100644
index 0000000..ef68ea4
--- /dev/null
+++ b/sys/arm64/arm64/clock.c
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/systm.h>
+
+void
+cpu_initclocks(void)
+{
+
+ cpu_initclocks_bsp();
+}
diff --git a/sys/arm64/arm64/copyinout.S b/sys/arm64/arm64/copyinout.S
new file mode 100644
index 0000000..56512ec
--- /dev/null
+++ b/sys/arm64/arm64/copyinout.S
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/errno.h>
+
+#include "assym.s"
+
+/*
+ * Fault handler for the copy{in,out} functions below.
+ */
+ENTRY(copyio_fault)
+ SET_FAULT_HANDLER(xzr, x1) /* Clear the handler */
+ mov x0, #EFAULT
+ ret
+END(copyio_fault)
+
+/*
+ * Copies from a kernel to user address
+ *
+ * int copyout(const void *kaddr, void *udaddr, size_t len)
+ */
+ENTRY(copyout)
+ cbz x2, 2f /* If len == 0 then skip loop */
+
+ adr x6, copyio_fault /* Get the handler address */
+ SET_FAULT_HANDLER(x6, x7) /* Set the handler */
+
+1: ldrb w4, [x0], #1 /* Load from kaddr */
+ strb w4, [x1], #1 /* Store in uaddr */
+ sub x2, x2, #1 /* len-- */
+ cbnz x2, 1b
+
+ SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
+
+2: mov x0, xzr /* return 0 */
+ ret
+END(copyout)
+
+/*
+ * Copies from a user to kernel address
+ *
+ * int copyin(const void *uaddr, void *kdaddr, size_t len)
+ */
+ENTRY(copyin)
+ cbz x2, 2f /* If len == 0 then skip loop */
+
+ adr x6, copyio_fault /* Get the handler address */
+ SET_FAULT_HANDLER(x6, x7) /* Set the handler */
+
+1: ldrb w4, [x0], #1 /* Load from uaddr */
+ strb w4, [x1], #1 /* Store in kaddr */
+ sub x2, x2, #1 /* len-- */
+ cbnz x2, 1b
+
+ SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
+
+2: mov x0, xzr /* return 0 */
+ ret
+END(copyin)
+
+/*
+ * Copies a string from a user to kernel address
+ *
+ * int copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
+ */
+ENTRY(copyinstr)
+ mov x5, xzr /* count = 0 */
+ cbz x2, 3f /* If len == 0 then skip loop */
+
+ adr x6, copyio_fault /* Get the handler address */
+ SET_FAULT_HANDLER(x6, x7) /* Set the handler */
+
+1: ldrb w4, [x0], #1 /* Load from uaddr */
+ strb w4, [x1], #1 /* Store in kaddr */
+ cbz w4, 2f /* If == 0 then break */
+ sub x2, x2, #1 /* len-- */
+ add x5, x5, #1 /* count++ */
+ cbnz x2, 1b
+
+2: SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
+
+3: cbz x3, 4f /* Check if done != NULL */
+ add x5, x5, #1 /* count++ */
+ str x5, [x3] /* done = count */
+
+4: mov x0, xzr /* return 0 */
+ ret
+END(copyinstr)
diff --git a/sys/arm64/arm64/copystr.c b/sys/arm64/arm64/copystr.c
new file mode 100644
index 0000000..008fdd1
--- /dev/null
+++ b/sys/arm64/arm64/copystr.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+int
+copystr(const void * __restrict kfaddr, void * __restrict kdaddr, size_t len,
+ size_t * __restrict lencopied)
+{
+ const char *src;
+ size_t pos;
+ char *dst;
+ int error;
+
+ error = ENAMETOOLONG;
+ src = kfaddr;
+ dst = kdaddr;
+ for (pos = 0; pos < len; pos++) {
+ dst[pos] = src[pos];
+ if (src[pos] == '\0') {
+ /* Increment pos to hold the number of bytes copied */
+ pos++;
+ error = 0;
+ break;
+ }
+ }
+
+ if (lencopied != NULL)
+ *lencopied = pos;
+
+ return (0);
+}
+
diff --git a/sys/arm64/arm64/cpufunc_asm.S b/sys/arm64/arm64/cpufunc_asm.S
new file mode 100644
index 0000000..9b17c21
--- /dev/null
+++ b/sys/arm64/arm64/cpufunc_asm.S
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2014 Robin Randhawa
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+#include <machine/param.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * FIXME:
+ * Need big.LITTLE awareness at some point.
+ * Using arm64_p[id]cache_line_size may not be the best option.
+ * Need better SMP awareness.
+ */
+ .text
+ .align 2
+
+.Lpage_mask:
+ .word PAGE_MASK
+
+/*
+ * Macro to handle the cache. This takes the start address in x0, length
+ * in x1. It will corrupt x0, x1, x2, and x3.
+ */
+.macro cache_handle_range dcop = 0, ic = 0, icop = 0
+.if \ic == 0
+ ldr x3, =dcache_line_size /* Load the D cache line size */
+.else
+ ldr x3, =idcache_line_size /* Load the I & D cache line size */
+.endif
+ ldr x3, [x3]
+ sub x4, x3, #1 /* Get the address mask */
+ and x2, x0, x4 /* Get the low bits of the address */
+ add x1, x1, x2 /* Add these to the size */
+ bic x0, x0, x4 /* Clear the low bit of the address */
+1:
+.if \ic != 0
+ ic \icop, x0
+.endif
+ dc \dcop, x0
+ add x0, x0, x3 /* Move to the next line */
+ subs x1, x1, x3 /* Reduce the size */
+ b.hi 1b /* Check if we are done */
+.if \ic != 0
+ isb
+.endif
+ dsb ish
+ ret
+.endm
+
+ENTRY(arm64_nullop)
+ ret
+END(arm64_nullop)
+
+/*
+ * Generic functions to read/modify/write the internal coprocessor registers
+ */
+
+ENTRY(arm64_setttb)
+ dsb ish
+ msr ttbr0_el1, x0
+ dsb ish
+ isb
+ ret
+END(arm64_setttb)
+
+ENTRY(arm64_tlb_flushID)
+#ifdef SMP
+ tlbi vmalle1is
+#else
+ tlbi vmalle1
+#endif
+ dsb ish
+ isb
+ ret
+END(arm64_tlb_flushID)
+
+ENTRY(arm64_tlb_flushID_SE)
+ ldr x1, .Lpage_mask
+ bic x0, x0, x1
+#ifdef SMP
+ tlbi vae1is, x0
+#else
+ tlbi vae1, x0
+#endif
+ dsb ish
+ isb
+ ret
+END(arm64_tlb_flushID_SE)
+
+/*
+ * void arm64_dcache_wb_range(vm_offset_t, vm_size_t)
+ */
+ENTRY(arm64_dcache_wb_range)
+ cache_handle_range dcop = cvac
+END(arm64_dcache_wb_range)
+
+/*
+ * void arm64_dcache_wbinv_range(vm_offset_t, vm_size_t)
+ */
+ENTRY(arm64_dcache_wbinv_range)
+ cache_handle_range dcop = civac
+END(arm64_dcache_wbinv_range)
+
+/*
+ * void arm64_dcache_inv_range(vm_offset_t, vm_size_t)
+ *
+ * Note, we must not invalidate everything. If the range is too big we
+ * must use wb-inv of the entire cache.
+ */
+ENTRY(arm64_dcache_inv_range)
+ cache_handle_range dcop = ivac
+END(arm64_dcache_inv_range)
+
+/*
+ * void arm64_idcache_wbinv_range(vm_offset_t, vm_size_t)
+ */
+ENTRY(arm64_idcache_wbinv_range)
+ cache_handle_range dcop = civac, ic = 1, icop = ivau
+END(arm64_idcache_wbinv_range)
+
+/*
+ * void arm64_icache_sync_range(vm_offset_t, vm_size_t)
+ */
+ENTRY(arm64_icache_sync_range)
+ cache_handle_range dcop = cvac, ic = 1, icop = ivau
+END(arm64_icache_sync_range)
diff --git a/sys/arm64/arm64/db_disasm.c b/sys/arm64/arm64/db_disasm.c
new file mode 100644
index 0000000..ec943a4
--- /dev/null
+++ b/sys/arm64/arm64/db_disasm.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <ddb/ddb.h>
+
+vm_offset_t
+db_disasm(vm_offset_t loc, boolean_t altfmt)
+{
+ return 0;
+}
+
+/* End of db_disasm.c */
diff --git a/sys/arm64/arm64/db_interface.c b/sys/arm64/arm64/db_interface.c
new file mode 100644
index 0000000..38834af
--- /dev/null
+++ b/sys/arm64/arm64/db_interface.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+
+#ifdef KDB
+#include <sys/kdb.h>
+#endif
+
+#include <ddb/ddb.h>
+#include <ddb/db_variables.h>
+
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/vmparam.h>
+
+static int
+db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
+{
+ long *reg;
+
+ if (kdb_frame == NULL)
+ return (0);
+
+ reg = (long *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep);
+ if (op == DB_VAR_GET)
+ *valuep = *reg;
+ else
+ *reg = *valuep;
+ return (1);
+}
+
+#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x)
+struct db_variable db_regs[] = {
+ { "spsr", DB_OFFSET(tf_spsr), db_frame },
+ { "x0", DB_OFFSET(tf_x[0]), db_frame },
+ { "x1", DB_OFFSET(tf_x[1]), db_frame },
+ { "x2", DB_OFFSET(tf_x[2]), db_frame },
+ { "x3", DB_OFFSET(tf_x[3]), db_frame },
+ { "x4", DB_OFFSET(tf_x[4]), db_frame },
+ { "x5", DB_OFFSET(tf_x[5]), db_frame },
+ { "x6", DB_OFFSET(tf_x[6]), db_frame },
+ { "x7", DB_OFFSET(tf_x[7]), db_frame },
+ { "x8", DB_OFFSET(tf_x[8]), db_frame },
+ { "x9", DB_OFFSET(tf_x[9]), db_frame },
+ { "x10", DB_OFFSET(tf_x[10]), db_frame },
+ { "x11", DB_OFFSET(tf_x[11]), db_frame },
+ { "x12", DB_OFFSET(tf_x[12]), db_frame },
+ { "x13", DB_OFFSET(tf_x[13]), db_frame },
+ { "x14", DB_OFFSET(tf_x[14]), db_frame },
+ { "x15", DB_OFFSET(tf_x[15]), db_frame },
+ { "x16", DB_OFFSET(tf_x[16]), db_frame },
+ { "x17", DB_OFFSET(tf_x[17]), db_frame },
+ { "x18", DB_OFFSET(tf_x[18]), db_frame },
+ { "x19", DB_OFFSET(tf_x[19]), db_frame },
+ { "x20", DB_OFFSET(tf_x[20]), db_frame },
+ { "x21", DB_OFFSET(tf_x[21]), db_frame },
+ { "x22", DB_OFFSET(tf_x[22]), db_frame },
+ { "x23", DB_OFFSET(tf_x[23]), db_frame },
+ { "x24", DB_OFFSET(tf_x[24]), db_frame },
+ { "x25", DB_OFFSET(tf_x[25]), db_frame },
+ { "x26", DB_OFFSET(tf_x[26]), db_frame },
+ { "x27", DB_OFFSET(tf_x[27]), db_frame },
+ { "x28", DB_OFFSET(tf_x[28]), db_frame },
+ { "x29", DB_OFFSET(tf_x[29]), db_frame },
+ { "lr", DB_OFFSET(tf_lr), db_frame },
+ { "elr", DB_OFFSET(tf_elr), db_frame },
+ { "sp", DB_OFFSET(tf_sp), db_frame },
+};
+
+struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+void
+db_show_mdpcpu(struct pcpu *pc)
+{
+}
+
+static int
+db_validate_address(vm_offset_t addr)
+{
+ struct proc *p = curproc;
+ struct pmap *pmap;
+
+ if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap ||
+ addr >= VM_MAXUSER_ADDRESS)
+ pmap = pmap_kernel();
+ else
+ pmap = p->p_vmspace->vm_map.pmap;
+
+ return (pmap_extract(pmap, addr) == FALSE);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+int
+db_read_bytes(vm_offset_t addr, size_t size, char *data)
+{
+ const char *src = (const char *)addr;
+
+ while (size-- > 0) {
+ if (db_validate_address((vm_offset_t)src)) {
+ db_printf("address %p is invalid\n", src);
+ return (-1);
+ }
+ *data++ = *src++;
+ }
+ return (0);
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+int
+db_write_bytes(vm_offset_t addr, size_t size, char *data)
+{
+ char *dst;
+
+ dst = (char *)addr;
+ while (size-- > 0) {
+ if (db_validate_address((vm_offset_t)dst)) {
+ db_printf("address %p is invalid\n", dst);
+ return (-1);
+ }
+ *dst++ = *data++;
+ }
+
+ dsb();
+ /* Clean D-cache and invalidate I-cache */
+ cpu_dcache_wb_range(addr, (vm_size_t)size);
+ cpu_icache_sync_range(addr, (vm_size_t)size);
+ dsb();
+ isb();
+
+ return (0);
+}
diff --git a/sys/arm64/arm64/db_trace.c b/sys/arm64/arm64/db_trace.c
new file mode 100644
index 0000000..1e89bac
--- /dev/null
+++ b/sys/arm64/arm64/db_trace.c
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <machine/pcb.h>
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+
+#include <machine/armreg.h>
+#include <machine/debug_monitor.h>
+
+struct unwind_state {
+ uint64_t fp;
+ uint64_t sp;
+ uint64_t pc;
+};
+
+void
+db_md_list_watchpoints()
+{
+
+ dbg_show_watchpoint();
+}
+
+int
+db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
+{
+
+ return (dbg_remove_watchpoint(addr, size, DBG_FROM_EL1));
+}
+
+int
+db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
+{
+
+ return (dbg_setup_watchpoint(addr, size, DBG_FROM_EL1,
+ HW_BREAKPOINT_RW));
+}
+
+static int
+db_unwind_frame(struct unwind_state *frame)
+{
+ uint64_t fp = frame->fp;
+
+ if (fp == 0)
+ return -1;
+
+ frame->sp = fp + 0x10;
+ /* FP to previous frame (X29) */
+ frame->fp = *(uint64_t *)(fp);
+ /* LR (X30) */
+ frame->pc = *(uint64_t *)(fp + 8) - 4;
+ return (0);
+}
+
+static void
+db_stack_trace_cmd(struct unwind_state *frame)
+{
+ c_db_sym_t sym;
+ const char *name;
+ db_expr_t value;
+ db_expr_t offset;
+
+ while (1) {
+ uint64_t pc = frame->pc;
+ int ret;
+
+ ret = db_unwind_frame(frame);
+ if (ret < 0)
+ break;
+
+ sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
+ if (sym == C_DB_SYM_NULL) {
+ value = 0;
+ name = "(null)";
+ } else
+ db_symbol_values(sym, &name, &value);
+
+ db_printf("%s() at ", name);
+ db_printsym(frame->pc, DB_STGY_PROC);
+ db_printf("\n");
+
+ db_printf("\t pc = 0x%016lx lr = 0x%016lx\n", pc,
+ frame->pc);
+ db_printf("\t sp = 0x%016lx fp = 0x%016lx\n", frame->sp,
+ frame->fp);
+ /* TODO: Show some more registers */
+ db_printf("\n");
+ }
+}
+
+int
+db_trace_thread(struct thread *thr, int count)
+{
+ struct unwind_state frame;
+ struct pcb *ctx;
+
+ if (thr != curthread) {
+ ctx = kdb_thr_ctx(thr);
+
+ frame.sp = (uint64_t)ctx->pcb_sp;
+ frame.fp = (uint64_t)ctx->pcb_x[29];
+ frame.pc = (uint64_t)ctx->pcb_x[30];
+ db_stack_trace_cmd(&frame);
+ } else
+ db_trace_self();
+ return (0);
+}
+
+void
+db_trace_self(void)
+{
+ struct unwind_state frame;
+ uint64_t sp;
+
+ __asm __volatile("mov %0, sp" : "=&r" (sp));
+
+ frame.sp = sp;
+ frame.fp = (uint64_t)__builtin_frame_address(0);
+ frame.pc = (uint64_t)db_trace_self;
+ db_stack_trace_cmd(&frame);
+}
diff --git a/sys/arm64/arm64/debug_monitor.c b/sys/arm64/arm64/debug_monitor.c
new file mode 100644
index 0000000..50d663d
--- /dev/null
+++ b/sys/arm64/arm64/debug_monitor.c
@@ -0,0 +1,487 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kdb.h>
+#include <sys/pcpu.h>
+#include <sys/systm.h>
+
+#include <machine/armreg.h>
+#include <machine/cpu.h>
+#include <machine/debug_monitor.h>
+#include <machine/kdb.h>
+#include <machine/param.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+
+enum dbg_t {
+ DBG_TYPE_BREAKPOINT = 0,
+ DBG_TYPE_WATCHPOINT = 1,
+};
+
+static int dbg_watchpoint_num;
+static int dbg_breakpoint_num;
+static int dbg_ref_count_mde[MAXCPU];
+static int dbg_ref_count_kde[MAXCPU];
+
+/* Watchpoints/breakpoints control register bitfields */
+#define DBG_WATCH_CTRL_LEN_1 (0x1 << 5)
+#define DBG_WATCH_CTRL_LEN_2 (0x3 << 5)
+#define DBG_WATCH_CTRL_LEN_4 (0xf << 5)
+#define DBG_WATCH_CTRL_LEN_8 (0xff << 5)
+#define DBG_WATCH_CTRL_LEN_MASK(x) ((x) & (0xff << 5))
+#define DBG_WATCH_CTRL_EXEC (0x0 << 3)
+#define DBG_WATCH_CTRL_LOAD (0x1 << 3)
+#define DBG_WATCH_CTRL_STORE (0x2 << 3)
+#define DBG_WATCH_CTRL_ACCESS_MASK(x) ((x) & (0x3 << 3))
+
+/* Common for breakpoint and watchpoint */
+#define DBG_WB_CTRL_EL1 (0x1 << 1)
+#define DBG_WB_CTRL_EL0 (0x2 << 1)
+#define DBG_WB_CTRL_ELX_MASK(x) ((x) & (0x3 << 1))
+#define DBG_WB_CTRL_E (0x1 << 0)
+
+#define DBG_REG_BASE_BVR 0
+#define DBG_REG_BASE_BCR (DBG_REG_BASE_BVR + 16)
+#define DBG_REG_BASE_WVR (DBG_REG_BASE_BCR + 16)
+#define DBG_REG_BASE_WCR (DBG_REG_BASE_WVR + 16)
+
+/* Watchpoint/breakpoint helpers */
+#define DBG_WB_WVR "wvr"
+#define DBG_WB_WCR "wcr"
+#define DBG_WB_BVR "bvr"
+#define DBG_WB_BCR "bcr"
+
+#define DBG_WB_READ(reg, num, val) do { \
+ __asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val)); \
+} while (0)
+
+#define DBG_WB_WRITE(reg, num, val) do { \
+ __asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val)); \
+} while (0)
+
+#define READ_WB_REG_CASE(reg, num, offset, val) \
+ case (num + offset): \
+ DBG_WB_READ(reg, num, val); \
+ break
+
+#define WRITE_WB_REG_CASE(reg, num, offset, val) \
+ case (num + offset): \
+ DBG_WB_WRITE(reg, num, val); \
+ break
+
+#define SWITCH_CASES_READ_WB_REG(reg, offset, val) \
+ READ_WB_REG_CASE(reg, 0, offset, val); \
+ READ_WB_REG_CASE(reg, 1, offset, val); \
+ READ_WB_REG_CASE(reg, 2, offset, val); \
+ READ_WB_REG_CASE(reg, 3, offset, val); \
+ READ_WB_REG_CASE(reg, 4, offset, val); \
+ READ_WB_REG_CASE(reg, 5, offset, val); \
+ READ_WB_REG_CASE(reg, 6, offset, val); \
+ READ_WB_REG_CASE(reg, 7, offset, val); \
+ READ_WB_REG_CASE(reg, 8, offset, val); \
+ READ_WB_REG_CASE(reg, 9, offset, val); \
+ READ_WB_REG_CASE(reg, 10, offset, val); \
+ READ_WB_REG_CASE(reg, 11, offset, val); \
+ READ_WB_REG_CASE(reg, 12, offset, val); \
+ READ_WB_REG_CASE(reg, 13, offset, val); \
+ READ_WB_REG_CASE(reg, 14, offset, val); \
+ READ_WB_REG_CASE(reg, 15, offset, val)
+
+#define SWITCH_CASES_WRITE_WB_REG(reg, offset, val) \
+ WRITE_WB_REG_CASE(reg, 0, offset, val); \
+ WRITE_WB_REG_CASE(reg, 1, offset, val); \
+ WRITE_WB_REG_CASE(reg, 2, offset, val); \
+ WRITE_WB_REG_CASE(reg, 3, offset, val); \
+ WRITE_WB_REG_CASE(reg, 4, offset, val); \
+ WRITE_WB_REG_CASE(reg, 5, offset, val); \
+ WRITE_WB_REG_CASE(reg, 6, offset, val); \
+ WRITE_WB_REG_CASE(reg, 7, offset, val); \
+ WRITE_WB_REG_CASE(reg, 8, offset, val); \
+ WRITE_WB_REG_CASE(reg, 9, offset, val); \
+ WRITE_WB_REG_CASE(reg, 10, offset, val); \
+ WRITE_WB_REG_CASE(reg, 11, offset, val); \
+ WRITE_WB_REG_CASE(reg, 12, offset, val); \
+ WRITE_WB_REG_CASE(reg, 13, offset, val); \
+ WRITE_WB_REG_CASE(reg, 14, offset, val); \
+ WRITE_WB_REG_CASE(reg, 15, offset, val)
+
+static uint64_t
+dbg_wb_read_reg(int reg, int n)
+{
+ uint64_t val = 0;
+
+ switch (reg + n) {
+ SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
+ SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
+ SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
+ SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
+ default:
+ db_printf("trying to read from wrong debug register %d\n", n);
+ }
+
+ return val;
+}
+
+static void
+dbg_wb_write_reg(int reg, int n, uint64_t val)
+{
+ switch (reg + n) {
+ SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
+ SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
+ SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
+ SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
+ default:
+ db_printf("trying to write to wrong debug register %d\n", n);
+ }
+ isb();
+}
+
+void
+kdb_cpu_set_singlestep(void)
+{
+
+ kdb_frame->tf_spsr |= DBG_SPSR_SS;
+ WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) |
+ DBG_MDSCR_SS | DBG_MDSCR_KDE);
+
+ /*
+ * Disable breakpoints and watchpoints, e.g. stepping
+ * over watched instruction will trigger break exception instead of
+ * single-step exception and locks CPU on that instruction for ever.
+ */
+ if (dbg_ref_count_mde[PCPU_GET(cpuid)] > 0) {
+ WRITE_SPECIALREG(MDSCR_EL1,
+ READ_SPECIALREG(MDSCR_EL1) & ~DBG_MDSCR_MDE);
+ }
+}
+
+void
+kdb_cpu_clear_singlestep(void)
+{
+
+ WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) &
+ ~(DBG_MDSCR_SS | DBG_MDSCR_KDE));
+
+ /* Restore breakpoints and watchpoints */
+ if (dbg_ref_count_mde[PCPU_GET(cpuid)] > 0) {
+ WRITE_SPECIALREG(MDSCR_EL1,
+ READ_SPECIALREG(MDSCR_EL1) | DBG_MDSCR_MDE);
+ }
+
+ if (dbg_ref_count_kde[PCPU_GET(cpuid)] > 0) {
+ WRITE_SPECIALREG(MDSCR_EL1,
+ READ_SPECIALREG(MDSCR_EL1) | DBG_MDSCR_KDE);
+ }
+}
+
+static const char *
+dbg_watchtype_str(uint32_t type)
+{
+ switch (type) {
+ case DBG_WATCH_CTRL_EXEC:
+ return ("execute");
+ case DBG_WATCH_CTRL_STORE:
+ return ("write");
+ case DBG_WATCH_CTRL_LOAD:
+ return ("read");
+ case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE:
+ return ("read/write");
+ default:
+ return ("invalid");
+ }
+}
+
+static int
+dbg_watchtype_len(uint32_t len)
+{
+ switch (len) {
+ case DBG_WATCH_CTRL_LEN_1:
+ return (1);
+ case DBG_WATCH_CTRL_LEN_2:
+ return (2);
+ case DBG_WATCH_CTRL_LEN_4:
+ return (4);
+ case DBG_WATCH_CTRL_LEN_8:
+ return (8);
+ default:
+ return (0);
+ }
+}
+
+void
+dbg_show_watchpoint(void)
+{
+ uint32_t wcr, len, type;
+ uint64_t addr;
+ int i;
+
+ db_printf("\nhardware watchpoints:\n");
+ db_printf(" watch status type len address symbol\n");
+ db_printf(" ----- -------- ---------- --- ------------------ ------------------\n");
+ for (i = 0; i < dbg_watchpoint_num; i++) {
+ wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
+ if ((wcr & DBG_WB_CTRL_E) != 0) {
+ type = DBG_WATCH_CTRL_ACCESS_MASK(wcr);
+ len = DBG_WATCH_CTRL_LEN_MASK(wcr);
+ addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i);
+ db_printf(" %-5d %-8s %10s %3d 0x%16lx ",
+ i, "enabled", dbg_watchtype_str(type),
+ dbg_watchtype_len(len), addr);
+ db_printsym((db_addr_t)addr, DB_STGY_ANY);
+ db_printf("\n");
+ } else {
+ db_printf(" %-5d disabled\n", i);
+ }
+ }
+}
+
+
+static int
+dbg_find_free_slot(enum dbg_t type)
+{
+ u_int max, reg, i;
+
+ switch(type) {
+ case DBG_TYPE_BREAKPOINT:
+ max = dbg_breakpoint_num;
+ reg = DBG_REG_BASE_BCR;
+
+ break;
+ case DBG_TYPE_WATCHPOINT:
+ max = dbg_watchpoint_num;
+ reg = DBG_REG_BASE_WCR;
+ break;
+ default:
+ db_printf("Unsupported debug type\n");
+ return (i);
+ }
+
+ for (i = 0; i < max; i++) {
+ if ((dbg_wb_read_reg(reg, i) & DBG_WB_CTRL_E) == 0)
+ return (i);
+ }
+
+ return (-1);
+}
+
+static int
+dbg_find_slot(enum dbg_t type, db_expr_t addr)
+{
+ u_int max, reg_addr, reg_ctrl, i;
+
+ switch(type) {
+ case DBG_TYPE_BREAKPOINT:
+ max = dbg_breakpoint_num;
+ reg_addr = DBG_REG_BASE_BVR;
+ reg_ctrl = DBG_REG_BASE_BCR;
+ break;
+ case DBG_TYPE_WATCHPOINT:
+ max = dbg_watchpoint_num;
+ reg_addr = DBG_REG_BASE_WVR;
+ reg_ctrl = DBG_REG_BASE_WCR;
+ break;
+ default:
+ db_printf("Unsupported debug type\n");
+ return (i);
+ }
+
+ for (i = 0; i < max; i++) {
+ if ((dbg_wb_read_reg(reg_addr, i) == addr) &&
+ ((dbg_wb_read_reg(reg_ctrl, i) & DBG_WB_CTRL_E) != 0))
+ return (i);
+ }
+
+ return (-1);
+}
+
+static void
+dbg_enable_monitor(enum dbg_el_t el)
+{
+ uint64_t reg_mdcr = 0;
+
+ /*
+ * There is no need to have debug monitor on permanently, thus we are
+ * refcounting and turn it on only if any of CPU is going to use that.
+ */
+ if (atomic_fetchadd_int(&dbg_ref_count_mde[PCPU_GET(cpuid)], 1) == 0)
+ reg_mdcr = DBG_MDSCR_MDE;
+
+ if ((el == DBG_FROM_EL1) &&
+ atomic_fetchadd_int(&dbg_ref_count_kde[PCPU_GET(cpuid)], 1) == 0)
+ reg_mdcr |= DBG_MDSCR_KDE;
+
+ if (reg_mdcr)
+ WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) | reg_mdcr);
+}
+
+static void
+dbg_disable_monitor(enum dbg_el_t el)
+{
+ uint64_t reg_mdcr = 0;
+
+ if (atomic_fetchadd_int(&dbg_ref_count_mde[PCPU_GET(cpuid)], -1) == 1)
+ reg_mdcr = DBG_MDSCR_MDE;
+
+ if ((el == DBG_FROM_EL1) &&
+ atomic_fetchadd_int(&dbg_ref_count_kde[PCPU_GET(cpuid)], -1) == 1)
+ reg_mdcr |= DBG_MDSCR_KDE;
+
+ if (reg_mdcr)
+ WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) & ~reg_mdcr);
+}
+
+int
+dbg_setup_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_el_t el,
+ enum dbg_access_t access)
+{
+ uint64_t wcr_size, wcr_priv, wcr_access;
+ u_int i;
+
+ i = dbg_find_free_slot(DBG_TYPE_WATCHPOINT);
+ if (i == -1) {
+ db_printf("Can not find slot for watchpoint, max %d"
+ " watchpoints supported\n", dbg_watchpoint_num);
+ return (i);
+ }
+
+ switch(size) {
+ case 1:
+ wcr_size = DBG_WATCH_CTRL_LEN_1;
+ break;
+ case 2:
+ wcr_size = DBG_WATCH_CTRL_LEN_2;
+ break;
+ case 4:
+ wcr_size = DBG_WATCH_CTRL_LEN_4;
+ break;
+ case 8:
+ wcr_size = DBG_WATCH_CTRL_LEN_8;
+ break;
+ default:
+ db_printf("Unsupported address size for watchpoint\n");
+ return (-1);
+ }
+
+ switch(el) {
+ case DBG_FROM_EL0:
+ wcr_priv = DBG_WB_CTRL_EL0;
+ break;
+ case DBG_FROM_EL1:
+ wcr_priv = DBG_WB_CTRL_EL1;
+ break;
+ default:
+ db_printf("Unsupported exception level for watchpoint\n");
+ return (-1);
+ }
+
+ switch(access) {
+ case HW_BREAKPOINT_X:
+ wcr_access = DBG_WATCH_CTRL_EXEC;
+ break;
+ case HW_BREAKPOINT_R:
+ wcr_access = DBG_WATCH_CTRL_LOAD;
+ break;
+ case HW_BREAKPOINT_W:
+ wcr_access = DBG_WATCH_CTRL_STORE;
+ break;
+ case HW_BREAKPOINT_RW:
+ wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE;
+ break;
+ default:
+ db_printf("Unsupported exception level for watchpoint\n");
+ return (-1);
+ }
+
+ dbg_wb_write_reg(DBG_REG_BASE_WVR, i, addr);
+ dbg_wb_write_reg(DBG_REG_BASE_WCR, i, wcr_size | wcr_access | wcr_priv |
+ DBG_WB_CTRL_E);
+ dbg_enable_monitor(el);
+ return (0);
+}
+
+int
+dbg_remove_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_el_t el)
+{
+ u_int i;
+
+ i = dbg_find_slot(DBG_TYPE_WATCHPOINT, addr);
+ if (i == -1) {
+ db_printf("Can not find watchpoint for address 0%lx\n", addr);
+ return (i);
+ }
+
+ dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
+ dbg_disable_monitor(el);
+ return (0);
+}
+
+void
+dbg_monitor_init(void)
+{
+ u_int i;
+
+ /* Clear OS lock */
+ WRITE_SPECIALREG(OSLAR_EL1, 0);
+
+ /* Find out many breakpoints and watchpoints we can use */
+ dbg_watchpoint_num = ((READ_SPECIALREG(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1;
+ dbg_breakpoint_num = ((READ_SPECIALREG(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1;
+
+ if (bootverbose && PCPU_GET(cpuid) == 0) {
+ db_printf("%d watchpoints and %d breakpoints supported\n",
+ dbg_watchpoint_num, dbg_breakpoint_num);
+ }
+
+ /*
+ * We have limited number of {watch,break}points, each consists of
+ * two registers:
+ * - wcr/bcr regsiter configurates corresponding {watch,break}point
+ * behaviour
+ * - wvr/bvr register keeps address we are hunting for
+ *
+ * Reset all breakpoints and watchpoints.
+ */
+ for (i = 0; i < dbg_watchpoint_num; ++i) {
+ dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
+ dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
+ }
+
+ for (i = 0; i < dbg_breakpoint_num; ++i) {
+ dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
+ dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
+ }
+
+ dbg_enable();
+}
diff --git a/sys/arm64/arm64/dump_machdep.c b/sys/arm64/arm64/dump_machdep.c
new file mode 100644
index 0000000..d92777f
--- /dev/null
+++ b/sys/arm64/arm64/dump_machdep.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/kerneldump.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+
+#include <machine/dump.h>
+
+int do_minidump = 1;
+TUNABLE_INT("debug.minidump", &do_minidump);
+SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RW, &do_minidump, 0,
+ "Enable mini crash dumps");
+
+void
+dumpsys_wbinv_all(void)
+{
+
+ printf("dumpsys_wbinv_all\n");
+}
+
+void
+dumpsys_map_chunk(vm_paddr_t pa, size_t chunk __unused, void **va)
+{
+
+ printf("dumpsys_map_chunk\n");
+ while(1);
+}
+
+/*
+ * Add a header to be used by libkvm to get the va to pa delta
+ */
+int
+dumpsys_write_aux_headers(struct dumperinfo *di)
+{
+
+ printf("dumpsys_map_chunk\n");
+ return (0);
+}
diff --git a/sys/arm64/arm64/elf_machdep.c b/sys/arm64/arm64/elf_machdep.c
new file mode 100644
index 0000000..5702e7f
--- /dev/null
+++ b/sys/arm64/arm64/elf_machdep.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * Copyright (c) 2014 Andrew Turner.
+ * Copyright (c) 2001 Jake Burkholder.
+ * Copyright (c) 2000 Eduardo Horvath.
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from: NetBSD: mdreloc.c,v 1.42 2008/04/28 20:23:04 martin Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/linker.h>
+#include <sys/proc.h>
+#include <sys/sysent.h>
+#include <sys/imgact_elf.h>
+#include <sys/syscall.h>
+#include <sys/signalvar.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+
+#include <machine/elf.h>
+#include <machine/md_var.h>
+
+#include "linker_if.h"
+
+static struct sysentvec elf64_freebsd_sysvec = {
+ .sv_size = SYS_MAXSYSCALL,
+ .sv_table = sysent,
+ .sv_mask = 0,
+ .sv_sigsize = 0,
+ .sv_sigtbl = NULL,
+ .sv_errsize = 0,
+ .sv_errtbl = NULL,
+ .sv_transtrap = NULL,
+ .sv_fixup = __elfN(freebsd_fixup),
+ .sv_sendsig = sendsig,
+ .sv_sigcode = sigcode,
+ .sv_szsigcode = &szsigcode,
+ .sv_prepsyscall = NULL,
+ .sv_name = "FreeBSD ELF64",
+ .sv_coredump = __elfN(coredump),
+ .sv_imgact_try = NULL,
+ .sv_minsigstksz = MINSIGSTKSZ,
+ .sv_pagesize = PAGE_SIZE,
+ .sv_minuser = VM_MIN_ADDRESS,
+ .sv_maxuser = VM_MAXUSER_ADDRESS,
+ .sv_usrstack = USRSTACK,
+ .sv_psstrings = PS_STRINGS,
+ .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE,
+ .sv_copyout_strings = exec_copyout_strings,
+ .sv_setregs = exec_setregs,
+ .sv_fixlimit = NULL,
+ .sv_maxssiz = NULL,
+ .sv_flags = SV_ABI_FREEBSD | SV_LP64,
+ .sv_set_syscall_retval = cpu_set_syscall_retval,
+ .sv_fetch_syscall_args = cpu_fetch_syscall_args,
+ .sv_syscallnames = syscallnames,
+ .sv_schedtail = NULL,
+};
+
+static Elf64_Brandinfo freebsd_brand_info = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_AARCH64,
+ .compat_3_brand = "FreeBSD",
+ .emul_path = NULL,
+ .interp_path = "/libexec/ld-elf.so.1",
+ .sysvec = &elf64_freebsd_sysvec,
+ .interp_newpath = NULL,
+ .brand_note = &elf64_freebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
+};
+
+SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST,
+ (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_info);
+
+static Elf64_Brandinfo freebsd_brand_oinfo = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_AARCH64,
+ .compat_3_brand = "FreeBSD",
+ .emul_path = NULL,
+ .interp_path = "/usr/libexec/ld-elf.so.1",
+ .sysvec = &elf64_freebsd_sysvec,
+ .interp_newpath = NULL,
+ .brand_note = &elf64_freebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
+};
+
+SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
+ (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo);
+
+void
+elf64_dump_thread(struct thread *td __unused, void *dst __unused,
+ size_t *off __unused)
+{
+
+}
+
+int
+elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
+ int type, elf_lookup_fn lookup __unused)
+{
+
+ panic("elf_reloc_local");
+}
+
+/* Process one elf relocation with addend. */
+int
+elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
+ elf_lookup_fn lookup)
+{
+
+ panic("elf_reloc");
+}
+
+int
+elf_cpu_load_file(linker_file_t lf __unused)
+{
+
+ return (0);
+}
+
+int
+elf_cpu_unload_file(linker_file_t lf __unused)
+{
+
+ return (0);
+}
diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S
new file mode 100644
index 0000000..efb1364
--- /dev/null
+++ b/sys/arm64/arm64/exception.S
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "assym.s"
+
+ .text
+
+.macro save_registers el
+ stp x28, x29, [sp, #-16]!
+ stp x26, x27, [sp, #-16]!
+ stp x24, x25, [sp, #-16]!
+ stp x22, x23, [sp, #-16]!
+ stp x20, x21, [sp, #-16]!
+ stp x18, x19, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x4, x5, [sp, #-16]!
+ stp x2, x3, [sp, #-16]!
+ stp x0, x1, [sp, #-16]!
+ mrs x10, elr_el1
+ mrs x11, spsr_el1
+.if \el == 0
+ mrs x12, sp_el0
+.else
+ mov x12, sp
+.endif
+ stp x10, x11, [sp, #-16]!
+ stp x12, lr, [sp, #-16]!
+ mrs x18, tpidr_el1
+.endm
+
+.macro restore_registers el
+ ldp x12, lr, [sp], #16
+ ldp x10, x11, [sp], #16
+.if \el == 0
+ msr sp_el0, x12
+.else
+ mov sp, x12
+.endif
+ msr spsr_el1, x11
+ msr elr_el1, x10
+ ldp x0, x1, [sp], #16
+ ldp x2, x3, [sp], #16
+ ldp x4, x5, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x16, x17, [sp], #16
+.if \el == 0
+ ldp x18, x19, [sp], #16
+.else
+ ldp xzr, x19, [sp], #16
+.endif
+ ldp x20, x21, [sp], #16
+ ldp x22, x23, [sp], #16
+ ldp x24, x25, [sp], #16
+ ldp x26, x27, [sp], #16
+ ldp x28, x29, [sp], #16
+.endm
+
+.macro do_ast
+ /* Disable interrupts */
+ mrs x19, daif
+ msr daifset, #2
+
+ /* Read the current thread flags */
+1: ldr x1, [x18, #PC_CURTHREAD] /* Load curthread */
+ ldr x2, [x1, #TD_FLAGS]! /* TODO: No need for the ! but clang fails without it */
+
+ /* Check if we have either bits set */
+ mov x3, #((TDF_ASTPENDING|TDF_NEEDRESCHED) >> 8)
+ lsl x3, x3, #8
+ and x2, x2, x3
+ cmp x2, #0
+ b.eq 2f
+
+ /* Restore interrupts */
+ msr daif, x19
+
+ /* handle the ast */
+ mov x0, sp
+ bl _C_LABEL(ast)
+
+ /* Disable interrupts */
+ mrs x19, daif
+ msr daifset, #2
+
+2:
+ /* Restore interrupts */
+ msr daif, x19
+.endm
+
+handle_el1h_sync:
+ save_registers 1
+ mov x0, sp
+ bl do_el1h_sync
+ restore_registers 1
+ eret
+
+handle_el1h_irq:
+ save_registers 1
+ mov x0, sp
+ bl arm_cpu_intr
+ restore_registers 1
+ eret
+
+handle_el1h_error:
+ brk 0xf13
+
+handle_el0_sync:
+ save_registers 0
+ mov x0, sp
+ bl do_el0_sync
+ do_ast
+ restore_registers 0
+ eret
+
+handle_el0_irq:
+ save_registers 0
+ mov x0, sp
+ bl arm_cpu_intr
+ restore_registers 0
+ eret
+
+handle_el0_error:
+ save_registers 0
+ mov x0, sp
+ bl do_el0_error
+ brk 0xf23
+ 1: b 1b
+
+.macro vempty
+ .align 7
+ brk 0xfff
+ 1: b 1b
+.endm
+
+.macro vector name
+ .align 7
+ b handle_\name
+.endm
+
+ .align 11
+ .globl exception_vectors
+exception_vectors:
+ vempty /* Synchronous EL1t */
+ vempty /* IRQ EL1t */
+ vempty /* FIQ EL1t */
+ vempty /* Error EL1t */
+
+ vector el1h_sync /* Synchronous EL1h */
+ vector el1h_irq /* IRQ EL1h */
+ vempty /* FIQ EL1h */
+ vector el1h_error /* Error EL1h */
+
+ vector el0_sync /* Synchronous 64-bit EL0 */
+ vector el0_irq /* IRQ 64-bit EL0 */
+ vempty /* FIQ 64-bit EL0 */
+ vector el0_error /* Error 64-bit EL0 */
+
+ vempty /* Synchronous 32-bit EL0 */
+ vempty /* IRQ 32-bit EL0 */
+ vempty /* FIQ 32-bit EL0 */
+ vempty /* Error 32-bit EL0 */
+
diff --git a/sys/arm64/arm64/genassym.c b/sys/arm64/arm64/genassym.c
new file mode 100644
index 0000000..33b2042
--- /dev/null
+++ b/sys/arm64/arm64/genassym.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2004 Olivier Houchard
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/assym.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <machine/vmparam.h>
+
+ASSYM(KERNBASE, KERNBASE);
+ASSYM(TDF_ASTPENDING, TDF_ASTPENDING);
+ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED);
+
+ASSYM(PCPU_SIZE, sizeof(struct pcpu));
+ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb));
+ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread));
+
+/* Size of pcb, rounded to keep stack alignment */
+ASSYM(PCB_SIZE, roundup2(sizeof(struct pcb), STACKALIGNBYTES + 1));
+ASSYM(PCB_REGS, offsetof(struct pcb, pcb_x));
+ASSYM(PCB_SP, offsetof(struct pcb, pcb_sp));
+ASSYM(PCB_L1ADDR, offsetof(struct pcb, pcb_l1addr));
+ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
+
+ASSYM(SF_UC, offsetof(struct sigframe, sf_uc));
+
+ASSYM(TD_PCB, offsetof(struct thread, td_pcb));
+ASSYM(TD_FLAGS, offsetof(struct thread, td_flags));
+ASSYM(TD_LOCK, offsetof(struct thread, td_lock));
+
+ASSYM(TF_X, offsetof(struct trapframe, tf_x));
diff --git a/sys/arm64/arm64/gic.c b/sys/arm64/arm64/gic.c
new file mode 100644
index 0000000..59fac99
--- /dev/null
+++ b/sys/arm64/arm64/gic.c
@@ -0,0 +1,398 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Developed by Damjan Marion <damjan.marion@gmail.com>
+ *
+ * Based on OMAP4 GIC code by Ben Gray
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/cpuset.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/smp.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+
+#include "pic_if.h"
+
+/* We are using GICv2 register naming */
+
+/* Distributor Registers */
+#define GICD_CTLR 0x000 /* v1 ICDDCR */
+#define GICD_TYPER 0x004 /* v1 ICDICTR */
+#define GICD_IIDR 0x008 /* v1 ICDIIDR */
+#define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */
+#define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */
+#define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */
+#define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */
+#define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */
+#define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */
+#define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */
+#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */
+#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */
+#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */
+
+/* CPU Registers */
+#define GICC_CTLR 0x0000 /* v1 ICCICR */
+#define GICC_PMR 0x0004 /* v1 ICCPMR */
+#define GICC_BPR 0x0008 /* v1 ICCBPR */
+#define GICC_IAR 0x000C /* v1 ICCIAR */
+#define GICC_EOIR 0x0010 /* v1 ICCEOIR */
+#define GICC_RPR 0x0014 /* v1 ICCRPR */
+#define GICC_HPPIR 0x0018 /* v1 ICCHPIR */
+#define GICC_ABPR 0x001C /* v1 ICCABPR */
+#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/
+
+#define GIC_FIRST_IPI 0 /* Irqs 0-15 are SGIs/IPIs. */
+#define GIC_LAST_IPI 15
+#define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */
+#define GIC_LAST_PPI 31 /* core) peripheral interrupts. */
+#define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */
+
+/* First bit is a polarity bit (0 - low, 1 - high) */
+#define GICD_ICFGR_POL_LOW (0 << 0)
+#define GICD_ICFGR_POL_HIGH (1 << 0)
+#define GICD_ICFGR_POL_MASK 0x1
+/* Second bit is a trigger bit (0 - level, 1 - edge) */
+#define GICD_ICFGR_TRIG_LVL (0 << 1)
+#define GICD_ICFGR_TRIG_EDGE (1 << 1)
+#define GICD_ICFGR_TRIG_MASK 0x2
+
+struct arm_gic_softc {
+ device_t gic_dev;
+ struct resource * gic_res[3];
+ bus_space_tag_t gic_c_bst;
+ bus_space_tag_t gic_d_bst;
+ bus_space_handle_t gic_c_bsh;
+ bus_space_handle_t gic_d_bsh;
+ uint8_t ver;
+ struct mtx mutex;
+ uint32_t nirqs;
+};
+
+static struct resource_spec arm_gic_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */
+ { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */
+ { -1, 0 }
+};
+
+static struct arm_gic_softc *arm_gic_sc = NULL;
+
+#define gic_c_read_4(_sc, _reg) \
+ bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
+#define gic_c_write_4(_sc, _reg, _val) \
+ bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
+#define gic_d_read_4(_sc, _reg) \
+ bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
+#define gic_d_write_4(_sc, _reg, _val) \
+ bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
+
+static pic_dispatch_t gic_dispatch;
+static pic_eoi_t gic_eoi;
+static pic_mask_t gic_mask_irq;
+static pic_unmask_t gic_unmask_irq;
+
+static struct ofw_compat_data compat_data[] = {
+ {"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */
+ {"arm,gic-400", true},
+ {"arm,cortex-a15-gic", true},
+ {"arm,cortex-a9-gic", true},
+ {"arm,cortex-a7-gic", true},
+ {"arm,arm11mp-gic", true},
+ {"brcm,brahma-b15-gic", true},
+ {NULL, false}
+};
+
+static int
+arm_gic_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "ARM Generic Interrupt Controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+#ifdef SMP
+static void
+gic_init_secondary(device_t dev)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ int i;
+
+ for (i = 0; i < sc->nirqs; i += 4)
+ gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
+
+ /* Set all the interrupts to be in Group 0 (secure) */
+ for (i = 0; i < sc->nirqs; i += 32) {
+ gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
+ }
+
+ /* Enable CPU interface */
+ gic_c_write_4(sc, GICC_CTLR, 1);
+
+ /* Set priority mask register. */
+ gic_c_write_4(sc, GICC_PMR, 0xff);
+
+ /* Enable interrupt distribution */
+ gic_d_write_4(sc, GICD_CTLR, 0x01);
+
+ /*
+ * Activate the timer interrupts: virtual, secure, and non-secure.
+ */
+ gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F)));
+ gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
+ gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
+}
+#endif
+
+static int
+arm_gic_attach(device_t dev)
+{
+ struct arm_gic_softc *sc;
+ int i;
+ uint32_t icciidr;
+
+ if (arm_gic_sc)
+ return (ENXIO);
+
+ sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ sc->gic_dev = dev;
+ arm_gic_sc = sc;
+
+ /* Initialize mutex */
+ mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
+
+ /* Distributor Interface */
+ sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
+ sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]);
+
+ /* CPU Interface */
+ sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
+ sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
+
+ /* Disable interrupt forwarding to the CPU interface */
+ gic_d_write_4(sc, GICD_CTLR, 0x00);
+
+ /* Get the number of interrupts */
+ sc->nirqs = gic_d_read_4(sc, GICD_TYPER);
+ sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1);
+
+ arm_register_root_pic(dev, sc->nirqs);
+
+ icciidr = gic_c_read_4(sc, GICC_IIDR);
+ device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
+ icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
+ (icciidr & 0xfff), sc->nirqs);
+
+ /* Set all global interrupts to be level triggered, active low. */
+ for (i = 32; i < sc->nirqs; i += 16) {
+ gic_d_write_4(sc, GICD_ICFGR(i >> 4), 0x00000000);
+ }
+
+ /* Disable all interrupts. */
+ for (i = 32; i < sc->nirqs; i += 32) {
+ gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
+ }
+
+ for (i = 0; i < sc->nirqs; i += 4) {
+ gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
+ gic_d_write_4(sc, GICD_ITARGETSR(i >> 2),
+ 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24);
+ }
+
+ /* Set all the interrupts to be in Group 0 (secure) */
+ for (i = 0; i < sc->nirqs; i += 32) {
+ gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
+ }
+
+ /* Enable CPU interface */
+ gic_c_write_4(sc, GICC_CTLR, 1);
+
+ /* Set priority mask register. */
+ gic_c_write_4(sc, GICC_PMR, 0xff);
+
+ /* Enable interrupt distribution */
+ gic_d_write_4(sc, GICD_CTLR, 0x01);
+
+ return (0);
+}
+
+static void gic_dispatch(device_t dev, struct trapframe *frame)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ uint32_t active_irq;
+ int first = 1;
+
+ while (1) {
+ active_irq = gic_c_read_4(sc, GICC_IAR);
+
+ /*
+ * Immediatly EOIR the SGIs, because doing so requires the other
+ * bits (ie CPU number), not just the IRQ number, and we do not
+ * have this information later.
+ */
+
+ if ((active_irq & 0x3ff) <= GIC_LAST_IPI)
+ gic_c_write_4(sc, GICC_EOIR, active_irq);
+ active_irq &= 0x3FF;
+
+ if (active_irq == 0x3FF) {
+ if (first)
+ printf("Spurious interrupt detected\n");
+ return;
+ }
+
+ arm_dispatch_intr(active_irq, frame);
+ first = 0;
+ }
+}
+
+static void
+gic_eoi(device_t dev, u_int irq)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+
+ gic_c_write_4(sc, GICC_EOIR, irq);
+}
+
+void
+gic_mask_irq(device_t dev, u_int irq)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+
+ gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
+ gic_c_write_4(sc, GICC_EOIR, irq);
+}
+
+void
+gic_unmask_irq(device_t dev, u_int irq)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+
+ gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
+}
+
+#ifdef SMP
+static void
+gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ uint32_t val = 0, i;
+
+ for (i = 0; i < MAXCPU; i++)
+ if (CPU_ISSET(i, &cpus))
+ val |= 1 << (16 + i);
+
+ gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
+}
+
+static int
+arm_gic_ipi_read(device_t dev, int i)
+{
+
+ if (i != -1) {
+ /*
+ * The intr code will automagically give the frame pointer
+ * if the interrupt argument is 0.
+ */
+ if ((unsigned int)i > 16)
+ return (0);
+ return (i);
+ }
+
+ return (0x3ff);
+}
+
+static void
+arm_gic_ipi_clear(device_t dev, int ipi)
+{
+ /* no-op */
+}
+#endif
+
+static device_method_t arm_gic_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, arm_gic_probe),
+ DEVMETHOD(device_attach, arm_gic_attach),
+
+ /* pic_if */
+ DEVMETHOD(pic_dispatch, gic_dispatch),
+ DEVMETHOD(pic_eoi, gic_eoi),
+ DEVMETHOD(pic_mask, gic_mask_irq),
+ DEVMETHOD(pic_unmask, gic_unmask_irq),
+
+#ifdef SMP
+ DEVMETHOD(pic_init_secondary, gic_init_secondary),
+ DEVMETHOD(pic_ipi_send, gic_ipi_send),
+#endif
+
+ { 0, 0 }
+};
+
+static driver_t arm_gic_driver = {
+ "gic",
+ arm_gic_methods,
+ sizeof(struct arm_gic_softc),
+};
+
+static devclass_t arm_gic_devclass;
+
+EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
new file mode 100644
index 0000000..b961ed3
--- /dev/null
+++ b/sys/arm64/arm64/identcpu.c
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Semihalf
+ * under sponsorship of the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/pcpu.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+
+char machine[] = "arm64";
+
+SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0,
+ "Machine class");
+
+/*
+ * Per-CPU affinity as provided in MPIDR_EL1
+ * Indexed by CPU number in logical order selected by the system.
+ * Relevant fields can be extracetd using CPU_AFFn macros,
+ * Aff3.Aff2.Aff1.Aff0 construct a unique CPU address in the system.
+ *
+ * Fields used by us:
+ * Aff1 - Cluster number
+ * Aff0 - CPU number in Aff1 cluster
+ */
+uint64_t __cpu_affinity[MAXCPU];
+
+#define CPU_IMPL_ARM 0x41
+#define CPU_IMPL_BROADCOM 0x42
+#define CPU_IMPL_CAVIUM 0x43
+#define CPU_IMPL_DEC 0x44
+#define CPU_IMPL_INFINEON 0x49
+#define CPU_IMPL_FREESCALE 0x4D
+#define CPU_IMPL_NVIDIA 0x4E
+#define CPU_IMPL_APM 0x50
+#define CPU_IMPL_QUALCOMM 0x51
+#define CPU_IMPL_MARVELL 0x56
+#define CPU_IMPL_INTEL 0x69
+
+#define CPU_PART_THUNDER 0x0A1
+#define CPU_PART_FOUNDATION 0xD00
+#define CPU_PART_CORTEX_A53 0xD03
+#define CPU_PART_CORTEX_A57 0xD07
+
+#define CPU_IMPL(midr) (((midr) >> 24) & 0xff)
+#define CPU_PART(midr) (((midr) >> 4) & 0xfff)
+#define CPU_VAR(midr) (((midr) >> 20) & 0xf)
+#define CPU_REV(midr) (((midr) >> 0) & 0xf)
+
+struct cpu_desc {
+ u_int cpu_impl;
+ u_int cpu_part_num;
+ u_int cpu_variant;
+ u_int cpu_revision;
+ const char *cpu_impl_name;
+ const char *cpu_part_name;
+};
+
+struct cpu_desc cpu_desc[MAXCPU];
+
+struct cpu_parts {
+ u_int part_id;
+ const char *part_name;
+};
+#define CPU_PART_NONE { 0, "Unknown Processor" }
+
+struct cpu_implementers {
+ u_int impl_id;
+ const char *impl_name;
+ /*
+ * Part number is implementation defined
+ * so each vendor will have its own set of values and names.
+ */
+ const struct cpu_parts *cpu_parts;
+};
+#define CPU_IMPLEMENTER_NONE { 0, "Unknown Implementer", cpu_parts_none }
+
+/*
+ * Per-implementer table of (PartNum, CPU Name) pairs.
+ */
+/* ARM Ltd. */
+static const struct cpu_parts cpu_parts_arm[] = {
+ { 0xD00, "Foundation-Model" },
+ { 0xD03, "Cortex-A53" },
+ { 0xD07, "Cortex-A57" },
+ CPU_PART_NONE,
+};
+/* Cavium */
+static const struct cpu_parts cpu_parts_cavium[] = {
+ { 0x0A1, "Thunder" },
+ CPU_PART_NONE,
+};
+
+/* Unknown */
+static const struct cpu_parts cpu_parts_none[] = {
+ CPU_PART_NONE,
+};
+
+/*
+ * Implementers table.
+ */
+const struct cpu_implementers cpu_implementers[] = {
+ { CPU_IMPL_ARM, "ARM", cpu_parts_arm },
+ { CPU_IMPL_BROADCOM, "Broadcom", cpu_parts_none },
+ { CPU_IMPL_CAVIUM, "Cavium", cpu_parts_cavium },
+ { CPU_IMPL_DEC, "DEC", cpu_parts_none },
+ { CPU_IMPL_INFINEON, "IFX", cpu_parts_none },
+ { CPU_IMPL_FREESCALE, "Freescale", cpu_parts_none },
+ { CPU_IMPL_NVIDIA, "NVIDIA", cpu_parts_none },
+ { CPU_IMPL_APM, "APM", cpu_parts_none },
+ { CPU_IMPL_QUALCOMM, "Qualcomm", cpu_parts_none },
+ { CPU_IMPL_MARVELL, "Marvell", cpu_parts_none },
+ { CPU_IMPL_INTEL, "Intel", cpu_parts_none },
+ CPU_IMPLEMENTER_NONE,
+};
+
+void identify_cpu(void);
+
+void
+identify_cpu(void)
+{
+ u_int midr;
+ u_int impl_id;
+ u_int part_id;
+ u_int cpu;
+ uint64_t mpidr;
+ size_t i;
+ const struct cpu_parts *cpu_partsp = NULL;
+
+ cpu = PCPU_GET(cpuid);
+ midr = get_midr();
+
+ impl_id = CPU_IMPL(midr);
+ for (i = 0; i < nitems(cpu_implementers); i++) {
+ if (impl_id == cpu_implementers[i].impl_id ||
+ cpu_implementers[i].impl_id == 0) {
+ cpu_desc[cpu].cpu_impl = impl_id;
+ cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name;
+ cpu_partsp = cpu_implementers[i].cpu_parts;
+ break;
+ }
+ }
+
+ part_id = CPU_PART(midr);
+ for (i = 0; &cpu_partsp[i] != NULL; i++) {
+ if (part_id == cpu_partsp[i].part_id ||
+ cpu_partsp[i].part_id == 0) {
+ cpu_desc[cpu].cpu_part_num = part_id;
+ cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name;
+ break;
+ }
+ }
+
+ printf("CPU: %s %s r%dp%d\n", cpu_desc[cpu].cpu_impl_name,
+ cpu_desc[cpu].cpu_part_name, CPU_VAR(midr), CPU_REV(midr));
+
+ /*
+ * Save affinity for the boot CPU.
+ * (CPU0 in the internal system enumeration.
+ */
+ mpidr = get_mpidr();
+ CPU_AFFINITY(0) = mpidr & CPU_AFF_MASK;
+
+ if (bootverbose)
+ printf("CPU%u affinity: %u.%u.%u.%u\n", 0, CPU_AFF0(mpidr),
+ CPU_AFF1(mpidr), CPU_AFF2(mpidr), CPU_AFF3(mpidr));
+}
diff --git a/sys/arm64/arm64/in_cksum.c b/sys/arm64/arm64/in_cksum.c
new file mode 100644
index 0000000..ae02e91
--- /dev/null
+++ b/sys/arm64/arm64/in_cksum.c
@@ -0,0 +1,241 @@
+/* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1988, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1996
+ * Matt Thomas <matt@3am-software.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
+ */
+
+#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <machine/in_cksum.h>
+
+/*
+ * Checksum routine for Internet Protocol family headers
+ * (Portable Alpha version).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ */
+
+#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
+#define REDUCE32 \
+ { \
+ q_util.q = sum; \
+ sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
+ }
+#define REDUCE16 \
+ { \
+ q_util.q = sum; \
+ l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
+ sum = l_util.s[0] + l_util.s[1]; \
+ ADDCARRY(sum); \
+ }
+
+static const u_int32_t in_masks[] = {
+ /*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/
+ 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */
+ 0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */
+ 0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */
+ 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */
+};
+
+union l_util {
+ u_int16_t s[2];
+ u_int32_t l;
+};
+union q_util {
+ u_int16_t s[4];
+ u_int32_t l[2];
+ u_int64_t q;
+};
+
+static u_int64_t
+in_cksumdata(const void *buf, int len)
+{
+ const u_int32_t *lw = (const u_int32_t *) buf;
+ u_int64_t sum = 0;
+ u_int64_t prefilled;
+ int offset;
+ union q_util q_util;
+
+ if ((3 & (long) lw) == 0 && len == 20) {
+ sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
+ REDUCE32;
+ return sum;
+ }
+
+ if ((offset = 3 & (long) lw) != 0) {
+ const u_int32_t *masks = in_masks + (offset << 2);
+ lw = (u_int32_t *) (((long) lw) - offset);
+ sum = *lw++ & masks[len >= 3 ? 3 : len];
+ len -= 4 - offset;
+ if (len <= 0) {
+ REDUCE32;
+ return sum;
+ }
+ }
+#if 0
+ /*
+ * Force to cache line boundary.
+ */
+ offset = 32 - (0x1f & (long) lw);
+ if (offset < 32 && len > offset) {
+ len -= offset;
+ if (4 & offset) {
+ sum += (u_int64_t) lw[0];
+ lw += 1;
+ }
+ if (8 & offset) {
+ sum += (u_int64_t) lw[0] + lw[1];
+ lw += 2;
+ }
+ if (16 & offset) {
+ sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
+ lw += 4;
+ }
+ }
+#endif
+ /*
+ * access prefilling to start load of next cache line.
+ * then add current cache line
+ * save result of prefilling for loop iteration.
+ */
+ prefilled = lw[0];
+ while ((len -= 32) >= 4) {
+ u_int64_t prefilling = lw[8];
+ sum += prefilled + lw[1] + lw[2] + lw[3]
+ + lw[4] + lw[5] + lw[6] + lw[7];
+ lw += 8;
+ prefilled = prefilling;
+ }
+ if (len >= 0) {
+ sum += prefilled + lw[1] + lw[2] + lw[3]
+ + lw[4] + lw[5] + lw[6] + lw[7];
+ lw += 8;
+ } else {
+ len += 32;
+ }
+ while ((len -= 16) >= 0) {
+ sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
+ lw += 4;
+ }
+ len += 16;
+ while ((len -= 4) >= 0) {
+ sum += (u_int64_t) *lw++;
+ }
+ len += 4;
+ if (len > 0)
+ sum += (u_int64_t) (in_masks[len] & *lw);
+ REDUCE32;
+ return sum;
+}
+
+u_short
+in_addword(u_short a, u_short b)
+{
+ u_int64_t sum = a + b;
+
+ ADDCARRY(sum);
+ return (sum);
+}
+
+u_short
+in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
+{
+ u_int64_t sum;
+ union q_util q_util;
+ union l_util l_util;
+
+ sum = (u_int64_t) a + b + c;
+ REDUCE16;
+ return (sum);
+}
+
+u_short
+in_cksum_skip(struct mbuf *m, int len, int skip)
+{
+ u_int64_t sum = 0;
+ int mlen = 0;
+ int clen = 0;
+ caddr_t addr;
+ union q_util q_util;
+ union l_util l_util;
+
+ len -= skip;
+ for (; skip && m; m = m->m_next) {
+ if (m->m_len > skip) {
+ mlen = m->m_len - skip;
+ addr = mtod(m, caddr_t) + skip;
+ goto skip_start;
+ } else {
+ skip -= m->m_len;
+ }
+ }
+
+ for (; m && len; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ mlen = m->m_len;
+ addr = mtod(m, caddr_t);
+skip_start:
+ if (len < mlen)
+ mlen = len;
+ if ((clen ^ (long) addr) & 1)
+ sum += in_cksumdata(addr, mlen) << 8;
+ else
+ sum += in_cksumdata(addr, mlen);
+
+ clen += mlen;
+ len -= mlen;
+ }
+ REDUCE16;
+ return (~sum & 0xffff);
+}
+
+u_int in_cksum_hdr(const struct ip *ip)
+{
+ u_int64_t sum = in_cksumdata(ip, sizeof(struct ip));
+ union q_util q_util;
+ union l_util l_util;
+ REDUCE16;
+ return (~sum & 0xffff);
+}
diff --git a/sys/arm64/arm64/intr_machdep.c b/sys/arm64/arm64/intr_machdep.c
new file mode 100644
index 0000000..6f1c7bb
--- /dev/null
+++ b/sys/arm64/arm64/intr_machdep.c
@@ -0,0 +1,503 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * Copyright (c) 2002 Benno Rice.
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ *
+ * This code is derived from software contributed by
+ * William Jolitz (Berkeley) and Benno Rice.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * form: src/sys/powerpc/powerpc/intr_machdep.c, r271712 2014/09/17
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/cpuset.h>
+#include <sys/interrupt.h>
+#include <sys/queue.h>
+
+#include <machine/cpufunc.h>
+#include <machine/intr.h>
+
+#ifdef SMP
+#include <machine/smp.h>
+#endif
+
+#include "pic_if.h"
+
+#define MAX_STRAY_LOG 5
+#define INTRNAME_LEN (MAXCOMLEN + 1)
+
+#define NIRQS 1024 /* Maximum number of interrupts in the system */
+
+static MALLOC_DEFINE(M_INTR, "intr", "Interrupt Services");
+
+/*
+ * Linked list of interrupts that have been set-up.
+ * Each element holds the interrupt description
+ * and has to be allocated and freed dynamically.
+ */
+static SLIST_HEAD(, arm64_intr_entry) irq_slist_head =
+ SLIST_HEAD_INITIALIZER(irq_slist_head);
+
+struct arm64_intr_entry {
+ SLIST_ENTRY(arm64_intr_entry) entries;
+ struct intr_event *i_event;
+
+ enum intr_trigger i_trig;
+ enum intr_polarity i_pol;
+
+ u_int i_hw_irq; /* Physical interrupt number */
+ u_int i_cntidx; /* Index in intrcnt table */
+ u_int i_handlers; /* Allocated handlers */
+ u_long *i_cntp; /* Interrupt hit counter */
+};
+
+/* Counts and names for statistics - see sys/sys/interrupt.h */
+/* Tables are indexed by i_cntidx */
+u_long intrcnt[NIRQS];
+char intrnames[NIRQS * INTRNAME_LEN];
+size_t sintrcnt = sizeof(intrcnt);
+size_t sintrnames = sizeof(intrnames);
+
+static u_int intrcntidx; /* Current index into intrcnt table */
+static u_int arm64_nintrs; /* Max interrupts number of the root PIC */
+static u_int arm64_nstray; /* Number of received stray interrupts */
+static device_t root_pic; /* PIC device for all incoming interrupts */
+static device_t msi_pic; /* Device which handles MSI/MSI-X interrupts */
+static struct mtx intr_list_lock;
+
+static void
+intr_init(void *dummy __unused)
+{
+
+ mtx_init(&intr_list_lock, "intr sources lock", NULL, MTX_DEF);
+}
+SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
+
+/*
+ * Helper routines.
+ */
+
+/* Set interrupt name for statistics */
+static void
+intrcnt_setname(const char *name, u_int idx)
+{
+
+ snprintf(&intrnames[idx * INTRNAME_LEN], INTRNAME_LEN, "%-*s",
+ INTRNAME_LEN - 1, name);
+}
+
+/*
+ * Get intr structure for the given interrupt number.
+ * Allocate one if this is the first time.
+ * (Similar to ppc's intr_lookup() but without actual
+ * lookup since irq number is an index in arm64_intrs[]).
+ */
+static struct arm64_intr_entry *
+intr_acquire(u_int hw_irq)
+{
+ struct arm64_intr_entry *intr;
+
+ mtx_lock(&intr_list_lock);
+
+ SLIST_FOREACH(intr, &irq_slist_head, entries) {
+ if (intr->i_hw_irq == hw_irq) {
+ break;
+ }
+ }
+ if (intr != NULL)
+ goto out;
+
+ /* Do not alloc another intr when max number of IRQs has been reached */
+ if (intrcntidx >= NIRQS)
+ goto out;
+
+ intr = malloc(sizeof(*intr), M_INTR, M_NOWAIT);
+ if (intr == NULL)
+ goto out;
+
+ intr->i_event = NULL;
+ intr->i_handlers = 0;
+ intr->i_trig = INTR_TRIGGER_CONFORM;
+ intr->i_pol = INTR_POLARITY_CONFORM;
+ intr->i_cntidx = atomic_fetchadd_int(&intrcntidx, 1);
+ intr->i_cntp = &intrcnt[intr->i_cntidx];
+ intr->i_hw_irq = hw_irq;
+ SLIST_INSERT_HEAD(&irq_slist_head, intr, entries);
+out:
+ mtx_unlock(&intr_list_lock);
+ return intr;
+}
+
+static void
+intr_pre_ithread(void *arg)
+{
+ struct arm64_intr_entry *intr = arg;
+
+ PIC_PRE_ITHREAD(root_pic, intr->i_hw_irq);
+}
+
+static void
+intr_post_ithread(void *arg)
+{
+ struct arm64_intr_entry *intr = arg;
+
+ PIC_POST_ITHREAD(root_pic, intr->i_hw_irq);
+}
+
+static void
+intr_post_filter(void *arg)
+{
+ struct arm64_intr_entry *intr = arg;
+
+ PIC_POST_FILTER(root_pic, intr->i_hw_irq);
+}
+
+/*
+ * Register PIC driver.
+ * This is intended to be called by the very first PIC driver
+ * at the end of the successful attach.
+ * Note that during boot this can be called after first references
+ * to bus_setup_intr() so it is required to not use root_pic if it
+ * is not 100% safe.
+ */
+void
+arm_register_root_pic(device_t dev, u_int nirq)
+{
+
+ KASSERT(root_pic == NULL, ("Unable to set the pic twice"));
+ KASSERT(nirq <= NIRQS, ("PIC is trying to handle too many IRQs"));
+
+ arm64_nintrs = NIRQS; /* Number of IRQs limited only by array size */
+ root_pic = dev;
+}
+
+/* Register device which allocates MSI interrupts */
+void
+arm_register_msi_pic(device_t dev)
+{
+
+ KASSERT(msi_pic == NULL, ("Unable to set msi_pic twice"));
+ msi_pic = dev;
+}
+
+int
+arm_alloc_msi(device_t pci_dev, int count, int *irqs)
+{
+
+ return PIC_ALLOC_MSI(msi_pic, pci_dev, count, irqs);
+}
+
+int
+arm_release_msi(device_t pci_dev, int count, int *irqs)
+{
+
+ return PIC_RELEASE_MSI(msi_pic, pci_dev, count, irqs);
+}
+
+int
+arm_map_msi(device_t pci_dev, int irq, uint64_t *addr, uint32_t *data)
+{
+
+ return PIC_MAP_MSI(msi_pic, pci_dev, irq, addr, data);
+}
+
+int
+arm_alloc_msix(device_t pci_dev, int *irq)
+{
+
+ return PIC_ALLOC_MSIX(msi_pic, pci_dev, irq);
+}
+
+int
+arm_release_msix(device_t pci_dev, int irq)
+{
+
+ return PIC_RELEASE_MSIX(msi_pic, pci_dev, irq);
+}
+
+
+int
+arm_map_msix(device_t pci_dev, int irq, uint64_t *addr, uint32_t *data)
+{
+
+ return PIC_MAP_MSIX(msi_pic, pci_dev, irq, addr, data);
+}
+
+/*
+ * Finalize interrupts bring-up (should be called from configure_final()).
+ * Enables all interrupts registered by bus_setup_intr() during boot
+ * as well as unlocks interrups reception on primary CPU.
+ */
+int
+arm_enable_intr(void)
+{
+ struct arm64_intr_entry *intr;
+
+ if (root_pic == NULL)
+ panic("Cannot enable interrupts. No PIC configured");
+
+ /*
+ * Iterate through all possible interrupts and perform
+ * configuration if the interrupt is registered.
+ */
+ SLIST_FOREACH(intr, &irq_slist_head, entries) {
+ /*
+ * XXX: In case we allowed to set up interrupt whose number
+ * exceeds maximum number of interrupts for the root PIC
+ * disable it and print proper error message.
+ *
+ * This can happen only when calling bus_setup_intr()
+ * before the interrupt controller is attached.
+ */
+ if (intr->i_cntidx >= arm64_nintrs) {
+ /* Better fail when IVARIANTS enabled */
+ KASSERT(0, ("%s: Interrupt %u cannot be handled by the "
+ "registered PIC. Max interrupt number: %u", __func__,
+ intr->i_cntidx, arm64_nintrs - 1));
+ /* Print message and disable otherwise */
+ printf("ERROR: Cannot enable irq %u. Disabling.\n",
+ intr->i_cntidx);
+ PIC_MASK(root_pic, intr->i_hw_irq);
+ }
+
+ if (intr->i_trig != INTR_TRIGGER_CONFORM ||
+ intr->i_pol != INTR_POLARITY_CONFORM) {
+ PIC_CONFIG(root_pic, intr->i_hw_irq,
+ intr->i_trig, intr->i_pol);
+ }
+
+ if (intr->i_handlers > 0)
+ PIC_UNMASK(root_pic, intr->i_hw_irq);
+
+ }
+ /* Enable interrupt reception on this CPU */
+ intr_enable();
+
+ return (0);
+}
+
+int
+arm_setup_intr(const char *name, driver_filter_t *filt, driver_intr_t handler,
+ void *arg, u_int hw_irq, enum intr_type flags, void **cookiep)
+{
+ struct arm64_intr_entry *intr;
+ int error;
+
+ intr = intr_acquire(hw_irq);
+ if (intr == NULL)
+ return (ENOMEM);
+
+ /*
+ * Watch out for interrupts' numbers.
+ * If this is a system boot then don't allow to overfill interrupts
+ * table (the interrupts will be deconfigured in arm_enable_intr()).
+ */
+ if (intr->i_cntidx >= NIRQS)
+ return (EINVAL);
+
+ if (intr->i_event == NULL) {
+ error = intr_event_create(&intr->i_event, (void *)intr, 0,
+ hw_irq, intr_pre_ithread, intr_post_ithread,
+ intr_post_filter, NULL, "irq%u", hw_irq);
+ if (error)
+ return (error);
+ }
+
+ error = intr_event_add_handler(intr->i_event, name, filt, handler, arg,
+ intr_priority(flags), flags, cookiep);
+
+ if (!error) {
+ mtx_lock(&intr_list_lock);
+ intrcnt_setname(intr->i_event->ie_fullname, intr->i_cntidx);
+ intr->i_handlers++;
+
+ if (!cold && intr->i_handlers == 1) {
+ if (intr->i_trig != INTR_TRIGGER_CONFORM ||
+ intr->i_pol != INTR_POLARITY_CONFORM) {
+ PIC_CONFIG(root_pic, intr->i_hw_irq, intr->i_trig,
+ intr->i_pol);
+ }
+
+ PIC_UNMASK(root_pic, intr->i_hw_irq);
+ }
+ mtx_unlock(&intr_list_lock);
+ }
+
+ return (error);
+}
+
+int
+arm_teardown_intr(void *cookie)
+{
+ struct arm64_intr_entry *intr;
+ int error;
+
+ intr = intr_handler_source(cookie);
+ error = intr_event_remove_handler(cookie);
+ if (!error) {
+ mtx_lock(&intr_list_lock);
+ intr->i_handlers--;
+ if (intr->i_handlers == 0)
+ PIC_MASK(root_pic, intr->i_hw_irq);
+ intrcnt_setname(intr->i_event->ie_fullname, intr->i_cntidx);
+ mtx_unlock(&intr_list_lock);
+ }
+
+ return (error);
+}
+
+int
+arm_config_intr(u_int hw_irq, enum intr_trigger trig, enum intr_polarity pol)
+{
+ struct arm64_intr_entry *intr;
+
+ intr = intr_acquire(hw_irq);
+ if (intr == NULL)
+ return (ENOMEM);
+
+ intr->i_trig = trig;
+ intr->i_pol = pol;
+
+ if (!cold && root_pic != NULL)
+ PIC_CONFIG(root_pic, intr->i_hw_irq, trig, pol);
+
+ return (0);
+}
+
+void
+arm_dispatch_intr(u_int hw_irq, struct trapframe *tf)
+{
+ struct arm64_intr_entry *intr;
+
+ SLIST_FOREACH(intr, &irq_slist_head, entries) {
+ if (intr->i_hw_irq == hw_irq) {
+ break;
+ }
+ }
+
+ if (intr == NULL)
+ goto stray;
+
+ (*intr->i_cntp)++;
+
+ if (!intr_event_handle(intr->i_event, tf))
+ return;
+
+stray:
+ if (arm64_nstray < MAX_STRAY_LOG) {
+ arm64_nstray++;
+ printf("Stray IRQ %u\n", hw_irq);
+ if (arm64_nstray >= MAX_STRAY_LOG) {
+ printf("Got %d stray IRQs. Not logging anymore.\n",
+ MAX_STRAY_LOG);
+ }
+ }
+
+ if (intr != NULL)
+ PIC_MASK(root_pic, intr->i_hw_irq);
+}
+
+void
+arm_cpu_intr(struct trapframe *tf)
+{
+
+ critical_enter();
+ PIC_DISPATCH(root_pic, tf);
+ critical_exit();
+}
+
+#ifdef SMP
+void
+arm_setup_ipihandler(driver_filter_t *filt, u_int ipi)
+{
+
+ /* ARM64TODO: The hard coded 16 will be fixed with am_intrng */
+ arm_setup_intr("ipi", filt, NULL, (void *)((uintptr_t)ipi | 1<<16), ipi + 16,
+ INTR_TYPE_MISC | INTR_EXCL, NULL);
+ arm_unmask_ipi(ipi);
+}
+
+void
+arm_unmask_ipi(u_int ipi)
+{
+ PIC_UNMASK(root_pic, ipi + 16);
+}
+
+void
+arm_init_secondary(void)
+{
+
+ PIC_INIT_SECONDARY(root_pic);
+}
+
+/* Sending IPI */
+void
+ipi_all_but_self(u_int ipi)
+{
+
+ /* ARM64TODO: We should support this */
+ panic("ipi_all_but_self");
+}
+
+void
+ipi_cpu(int cpu, u_int ipi)
+{
+ cpuset_t cpus;
+
+ CPU_ZERO(&cpus);
+ CPU_SET(cpu, &cpus);
+
+ /* ARM64TODO: This will be fixed with arm_intrng */
+ ipi += 16;
+
+ CTR2(KTR_SMP, "ipi_cpu: cpu: %d, ipi: %x", cpu, ipi);
+ PIC_IPI_SEND(root_pic, cpus, ipi);
+}
+
+void
+ipi_selected(cpuset_t cpus, u_int ipi)
+{
+
+ /* ARM64TODO: This will be fixed with arm_intrng */
+ ipi += 16;
+
+ CTR1(KTR_SMP, "ipi_selected: ipi: %x", ipi);
+ PIC_IPI_SEND(root_pic, cpus, ipi);
+}
+
+#endif
diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
new file mode 100644
index 0000000..bf702fa
--- /dev/null
+++ b/sys/arm64/arm64/locore.S
@@ -0,0 +1,544 @@
+/*-
+ * Copyright (c) 2012-2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "assym.s"
+#include <sys/syscall.h>
+#include <machine/asm.h>
+#include <machine/armreg.h>
+#include <machine/hypervisor.h>
+#include <machine/param.h>
+#include <machine/pte.h>
+
+#define VIRT_BITS 39
+
+ .globl kernbase
+ .set kernbase, KERNBASE
+
+#define DEVICE_MEM 0
+#define NORMAL_UNCACHED 1
+#define NORMAL_MEM 2
+
+/*
+ * We assume:
+ * MMU on with an identity map, or off
+ * D-Cache: off
+ * I-Cache: on or off
+ * We are loaded at a 2MiB aligned address
+ */
+
+#define INIT_STACK_SIZE (PAGE_SIZE * 4)
+
+ .text
+ .globl _start
+_start:
+ /* Drop to EL1 */
+ bl drop_to_el1
+
+ /*
+ * Disable the MMU. We may have entered the kernel with it on and
+ * will need to update the tables later. If this has been set up
+ * with anything other than a VA == PA map then this will fail,
+ * but in this case the code to find where we are running from
+ * would have also failed.
+ */
+ dsb sy
+ mrs x2, sctlr_el1
+ bic x2, x2, SCTLR_M
+ msr sctlr_el1, x2
+ isb
+
+
+ /* Get the virt -> phys offset */
+ bl get_virt_delta
+
+ /*
+ * At this point:
+ * x29 = PA - VA
+ * x28 = Our physical load address
+ */
+
+ /* Create the page tables */
+ bl create_pagetables
+
+ /*
+ * At this point:
+ * x27 = TTBR0 table
+ * x26 = TTBR1 table
+ */
+
+ /* Enable the mmu */
+ bl start_mmu
+
+ /* Jump to the virtual address space */
+ ldr x15, .Lvirtdone
+ br x15
+
+virtdone:
+ /* Set up the stack */
+ adr x25, initstack_end
+ mov sp, x25
+ sub sp, sp, #PCB_SIZE
+
+ /* Zero the BSS */
+ ldr x15, .Lbss
+ ldr x14, .Lend
+1:
+ str xzr, [x15], #8
+ cmp x15, x14
+ b.lo 1b
+
+ /* Backup the module pointer */
+ mov x1, x0
+
+ /* Make the page table base a virtual address */
+ sub x26, x26, x29
+
+ sub sp, sp, #(64 * 4)
+ mov x0, sp
+
+ /* Degate the delda so it is VA -> PA */
+ neg x29, x29
+
+ str x1, [x0] /* modulep */
+ str x26, [x0, 8] /* kern_l1pt */
+ str x29, [x0, 16] /* kern_delta */
+ str x25, [x0, 24] /* kern_stack */
+
+ /* trace back starts here */
+ mov fp, #0
+ /* Branch to C code */
+ bl initarm
+ bl mi_startup
+
+ /* We should not get here */
+ brk 0
+
+ .align 3
+.Lvirtdone:
+ .quad virtdone
+.Lbss:
+ .quad __bss_start
+.Lend:
+ .quad _end
+
+/*
+ * If we are started in EL2, configure the required hypervisor
+ * registers and drop to EL1.
+ */
+drop_to_el1:
+ mrs x1, CurrentEL
+ lsr x1, x1, #2
+ cmp x1, #0x2
+ b.eq 1f
+ ret
+1:
+ /* Configure the Hypervisor */
+ mov x2, #(HCR_RW)
+ msr hcr_el2, x2
+
+ /* Load the Virtualization Process ID Register */
+ mrs x2, midr_el1
+ msr vpidr_el2, x2
+
+ /* Load the Virtualization Multiprocess ID Register */
+ mrs x2, mpidr_el1
+ msr vmpidr_el2, x2
+
+ /* Set the bits that need to be 1 in sctlr_el1 */
+ ldr x2, .Lsctlr_res1
+ msr sctlr_el1, x2
+
+ /* Don't trap to EL2 for exceptions */
+ mov x2, #CPTR_RES1
+ msr cptr_el2, x2
+
+ /* Don't trap to EL2 for CP15 traps */
+ msr hstr_el2, xzr
+
+ /* Hypervisor trap functions */
+ adr x2, hyp_vectors
+ msr vbar_el2, x2
+
+ mov x2, #(PSR_F | PSR_I | PSR_A | PSR_D | PSR_M_EL1h)
+ msr spsr_el2, x2
+
+ /* Set the address to return to our return address */
+ msr elr_el2, x30
+
+ eret
+
+ .align 3
+.Lsctlr_res1:
+ .quad SCTLR_RES1
+
+#define VECT_EMPTY \
+ .align 7; \
+ 1: b 1b
+
+ .align 11
+hyp_vectors:
+ VECT_EMPTY /* Synchronous EL2t */
+ VECT_EMPTY /* IRQ EL2t */
+ VECT_EMPTY /* FIQ EL2t */
+ VECT_EMPTY /* Error EL2t */
+
+ VECT_EMPTY /* Synchronous EL2h */
+ VECT_EMPTY /* IRQ EL2h */
+ VECT_EMPTY /* FIQ EL2h */
+ VECT_EMPTY /* Error EL2h */
+
+ VECT_EMPTY /* Synchronous 64-bit EL1 */
+ VECT_EMPTY /* IRQ 64-bit EL1 */
+ VECT_EMPTY /* FIQ 64-bit EL1 */
+ VECT_EMPTY /* Error 64-bit EL1 */
+
+ VECT_EMPTY /* Synchronous 32-bit EL1 */
+ VECT_EMPTY /* IRQ 32-bit EL1 */
+ VECT_EMPTY /* FIQ 32-bit EL1 */
+ VECT_EMPTY /* Error 32-bit EL1 */
+
+/*
+ * Get the delta between the physical address we were loaded to and the
+ * virtual address we expect to run from. This is used when building the
+ * initial page table.
+ */
+get_virt_delta:
+ /* Load the physical address of virt_map */
+ adr x29, virt_map
+ /* Load the virtual address of virt_map stored in virt_map */
+ ldr x28, [x29]
+ /* Find PA - VA as PA' = VA' - VA + PA = VA' + (PA - VA) = VA' + x29 */
+ sub x29, x29, x28
+ /* Find the load address for the kernel */
+ mov x28, #(KERNBASE)
+ add x28, x28, x29
+ ret
+
+ .align 3
+virt_map:
+ .quad virt_map
+
+/*
+ * This builds the page tables containing the identity map, and the kernel
+ * virtual map.
+ *
+ * It relys on:
+ * We were loaded to an address that is on a 2MiB boundary
+ * All the memory must not cross a 1GiB boundaty
+ * x28 contains the physical address we were loaded from
+ *
+ * TODO: This is out of date.
+ * There are at least 5 pages before that address for the page tables
+ * The pages used are:
+ * - The identity (PA = VA) table (TTBR0)
+ * - The Kernel L1 table (TTBR1)(not yet)
+ * - The PA != VA L2 table to jump into (not yet)
+ * - The FDT L2 table (not yet)
+ */
+create_pagetables:
+ /* Save the Link register */
+ mov x5, x30
+
+ /* Clean the page table */
+ adr x6, pagetable
+ mov x26, x6
+ adr x27, pagetable_end
+1:
+ stp xzr, xzr, [x6], #16
+ stp xzr, xzr, [x6], #16
+ stp xzr, xzr, [x6], #16
+ stp xzr, xzr, [x6], #16
+ cmp x6, x27
+ b.lo 1b
+
+ /*
+ * Build the TTBR1 maps.
+ */
+
+ /* Find the size of the kernel */
+ mov x6, #(KERNBASE)
+ ldr x7, .Lend
+ /* Find the end - begin */
+ sub x8, x7, x6
+ /* Get the number of l2 pages to allocate, rounded down */
+ lsr x10, x8, #(L2_SHIFT)
+ /* Add 4 MiB for any rounding above and the module data */
+ add x10, x10, #2
+
+ /* Create the kernel space L2 table */
+ mov x6, x26
+ mov x7, #NORMAL_MEM
+ mov x8, #(KERNBASE & L2_BLOCK_MASK)
+ mov x9, x28
+ bl build_block_pagetable
+
+ /* Move to the l1 table */
+ add x26, x26, #PAGE_SIZE
+
+ /* Link the l1 -> l2 table */
+ mov x9, x6
+ mov x6, x26
+ bl link_l1_pagetable
+
+
+ /*
+ * Build the TTBR0 maps.
+ */
+ add x27, x26, #PAGE_SIZE
+
+#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
+ /* Create a table for the UART */
+ mov x6, x27 /* The initial page table */
+ mov x7, #DEVICE_MEM
+ mov x8, #(SOCDEV_VA) /* VA start */
+ mov x9, #(SOCDEV_PA) /* PA start */
+ bl build_section_pagetable
+#endif
+
+ /* Create the VA = PA map */
+ mov x6, x27 /* The initial page table */
+ mov x7, #NORMAL_UNCACHED /* Uncached as it's only needed early on */
+ mov x9, x27
+ mov x8, x9 /* VA start (== PA start) */
+ bl build_section_pagetable
+
+ /* Restore the Link register */
+ mov x30, x5
+ ret
+
+/*
+ * Builds a 1 GiB page table entry
+ * x6 = L1 table
+ * x7 = Type (0 = Device, 1 = Normal)
+ * x8 = VA start
+ * x9 = PA start (trashed)
+ * x11, x12 and x13 are trashed
+ */
+build_section_pagetable:
+ /*
+ * Build the L1 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L1_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L1 block entry */
+ lsl x12, x7, #2
+ orr x12, x12, #L1_BLOCK
+ orr x12, x12, #(ATTR_AF)
+
+ /* Only use the output address bits */
+ lsr x9, x9, #L1_SHIFT
+ orr x12, x12, x9, lsl #L1_SHIFT
+
+ /* Store the entry */
+ str x12, [x6, x11, lsl #3]
+
+ ret
+
+/*
+ * Builds an L1 -> L2 table descriptor
+ *
+ * This is a link for a 1GiB block of memory with up to 2MiB regions mapped
+ * within it by build_block_pagetable.
+ *
+ * x6 = L1 table
+ * x8 = Virtual Address
+ * x9 = L2 PA (trashed)
+ * x11, x12 and x13 are trashed
+ */
+link_l1_pagetable:
+ /*
+ * Link an L1 -> L2 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L1_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L1 block entry */
+ mov x12, #L1_TABLE
+
+ /* Only use the output address bits */
+ lsr x9, x9, #12
+ orr x12, x12, x9, lsl #12
+
+ /* Store the entry */
+ str x12, [x6, x11, lsl #3]
+
+ ret
+
+/*
+ * Builds count 2 MiB page table entry
+ * x6 = L2 table
+ * x7 = Type (0 = Device, 1 = Normal)
+ * x8 = VA start
+ * x9 = PA start (trashed)
+ * x10 = Entry count (TODO)
+ * x11, x12 and x13 are trashed
+ */
+build_block_pagetable:
+ /*
+ * Build the L2 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L2_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L2 block entry */
+ lsl x12, x7, #2
+ orr x12, x12, #L2_BLOCK
+ orr x12, x12, #(ATTR_AF)
+
+ /* Only use the output address bits */
+ lsr x9, x9, #L2_SHIFT
+
+ /* Set the physical address for this virtual address */
+1: orr x12, x12, x9, lsl #L2_SHIFT
+
+ /* Store the entry */
+ str x12, [x6, x11, lsl #3]
+
+ /* Clear the address bits */
+ and x12, x12, #ATTR_MASK_L
+
+ sub x10, x10, #1
+ add x11, x11, #1
+ add x9, x9, #1
+ cbnz x10, 1b
+
+2: ret
+
+start_mmu:
+ dsb sy
+
+ /* Load the exception vectors */
+ ldr x2, =exception_vectors
+ msr vbar_el1, x2
+
+ /* Load ttbr0 and ttbr1 */
+ msr ttbr0_el1, x27
+ msr ttbr1_el1, x26
+ isb
+
+ /* Clear the Monitor Debug System control register */
+ msr mdscr_el1, xzr
+
+ /* Invalidate the TLB */
+ tlbi vmalle1is
+
+ ldr x2, mair
+ msr mair_el1, x2
+
+ /* Setup TCR according to PARange bits from ID_AA64MMFR0_EL1 */
+ ldr x2, tcr
+ mrs x3, id_aa64mmfr0_el1
+ bfi x2, x3, #32, #3
+ msr tcr_el1, x2
+
+ /* Setup SCTLR */
+ ldr x2, sctlr_set
+ ldr x3, sctlr_clear
+ mrs x1, sctlr_el1
+ bic x1, x1, x3 /* Clear the required bits */
+ orr x1, x1, x2 /* Set the required bits */
+ msr sctlr_el1, x1
+ isb
+
+ ret
+
+ .align 3
+mair:
+ /* Device Normal, no cache Normal, write-back */
+ .quad MAIR_ATTR(0x00, 0) | MAIR_ATTR(0x44, 1) | MAIR_ATTR(0xff, 2)
+tcr:
+ .quad (TCR_TxSZ(64 - VIRT_BITS) | TCR_ASID_16 | TCR_TG1_4K)
+sctlr_set:
+ /* Bits to set */
+ .quad (SCTLR_UCI | SCTLR_nTWE | SCTLR_nTWI | SCTLR_UCT | SCTLR_DZE | \
+ SCTLR_I | SCTLR_SED | SCTLR_C | SCTLR_M)
+sctlr_clear:
+ /* Bits to clear */
+ .quad (SCTLR_EE | SCTLR_EOE | SCTLR_WXN | SCTLR_UMA | SCTLR_ITD | \
+ SCTLR_THEE | SCTLR_CP15BEN | SCTLR_SA0 | SCTLR_SA | SCTLR_A)
+
+ .globl abort
+abort:
+ b abort
+
+ //.section .init_pagetable
+ .align 12 /* 4KiB aligned */
+ /*
+ * 3 initial tables (in the following order):
+ * L2 for kernel (High addresses)
+ * L1 for kernel
+ * L1 for user (Low addresses)
+ */
+pagetable:
+ .space PAGE_SIZE
+pagetable_l1_ttbr1:
+ .space PAGE_SIZE
+pagetable_l1_ttbr0:
+ .space PAGE_SIZE
+pagetable_end:
+
+el2_pagetable:
+ .space PAGE_SIZE
+
+ .globl init_pt_va
+init_pt_va:
+ .quad pagetable /* XXX: Keep page tables VA */
+
+ .align 4
+initstack:
+ .space (PAGE_SIZE * KSTACK_PAGES)
+initstack_end:
+
+
+ENTRY(sigcode)
+ mov x0, sp
+ add x0, x0, #SF_UC
+
+1:
+ mov x8, #SYS_sigreturn
+ svc 0
+
+ /* sigreturn failed, exit */
+ mov x8, #SYS_exit
+ svc 0
+
+ b 1b
+END(sigcode)
+ /* This may be copied to the stack, keep it 16-byte aligned */
+ .align 3
+esigcode:
+
+ .data
+ .align 3
+ .global szsigcode
+szsigcode:
+ .quad esigcode - sigcode
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
new file mode 100644
index 0000000..221b138
--- /dev/null
+++ b/sys/arm64/arm64/machdep.c
@@ -0,0 +1,854 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/cpu.h>
+#include <sys/efi.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/linker.h>
+#include <sys/msgbuf.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/rwlock.h>
+#include <sys/sched.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_pager.h>
+
+#include <machine/armreg.h>
+#include <machine/cpu.h>
+#include <machine/debug_monitor.h>
+#include <machine/kdb.h>
+#include <machine/devmap.h>
+#include <machine/machdep.h>
+#include <machine/metadata.h>
+#include <machine/pcb.h>
+#include <machine/reg.h>
+#include <machine/vmparam.h>
+
+#ifdef VFP
+#include <machine/vfp.h>
+#endif
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
+struct pcpu __pcpu[MAXCPU];
+
+static struct trapframe proc0_tf;
+
+vm_paddr_t phys_avail[PHYS_AVAIL_SIZE + 2];
+vm_paddr_t dump_avail[PHYS_AVAIL_SIZE + 2];
+
+int early_boot = 1;
+int cold = 1;
+long realmem = 0;
+long Maxmem = 0;
+
+#define PHYSMAP_SIZE (2 * (VM_PHYSSEG_MAX - 1))
+vm_paddr_t physmap[PHYSMAP_SIZE];
+u_int physmap_idx;
+
+struct kva_md_info kmi;
+
+int64_t dcache_line_size; /* The minimum D cache line size */
+int64_t icache_line_size; /* The minimum I cache line size */
+int64_t idcache_line_size; /* The minimum cache line size */
+
+static void
+cpu_startup(void *dummy)
+{
+
+ identify_cpu();
+
+ vm_ksubmap_init(&kmi);
+ bufinit();
+ vm_pager_bufferinit();
+}
+
+SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
+
+void
+bzero(void *buf, size_t len)
+{
+ uint8_t *p;
+
+ p = buf;
+ while(len-- > 0)
+ *p++ = 0;
+}
+
+int
+fill_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *frame;
+
+ frame = td->td_frame;
+ regs->sp = frame->tf_sp;
+ regs->lr = frame->tf_lr;
+ regs->elr = frame->tf_elr;
+ regs->spsr = frame->tf_spsr;
+
+ memcpy(regs->x, frame->tf_x, sizeof(regs->x));
+
+ return (0);
+}
+
+int
+set_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *frame;
+
+ frame = td->td_frame;
+ frame->tf_sp = regs->sp;
+ frame->tf_lr = regs->lr;
+ frame->tf_elr = regs->elr;
+ frame->tf_spsr = regs->spsr;
+
+ memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x));
+
+ return (0);
+}
+
+int
+fill_fpregs(struct thread *td, struct fpreg *regs)
+{
+#ifdef VFP
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+ if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running VFP instructions we will
+ * need to save the state to memcpy it below.
+ */
+ vfp_save_state(td);
+
+ memcpy(regs->fp_q, pcb->pcb_vfp, sizeof(regs->fp_q));
+ regs->fp_cr = pcb->pcb_fpcr;
+ regs->fp_sr = pcb->pcb_fpsr;
+ } else
+#endif
+ memset(regs->fp_q, 0, sizeof(regs->fp_q));
+ return (0);
+}
+
+int
+set_fpregs(struct thread *td, struct fpreg *regs)
+{
+#ifdef VFP
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+ memcpy(pcb->pcb_vfp, regs->fp_q, sizeof(regs->fp_q));
+ pcb->pcb_fpcr = regs->fp_cr;
+ pcb->pcb_fpsr = regs->fp_sr;
+#endif
+ return (0);
+}
+
+int
+fill_dbregs(struct thread *td, struct dbreg *regs)
+{
+
+ panic("fill_dbregs");
+}
+
+int
+set_dbregs(struct thread *td, struct dbreg *regs)
+{
+
+ panic("set_dbregs");
+}
+
+int
+ptrace_set_pc(struct thread *td, u_long addr)
+{
+
+ panic("ptrace_set_pc");
+ return (0);
+}
+
+int
+ptrace_single_step(struct thread *td)
+{
+
+ /* TODO; */
+ return (0);
+}
+
+int
+ptrace_clear_single_step(struct thread *td)
+{
+
+ /* TODO; */
+ return (0);
+}
+
+void
+exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
+{
+ struct trapframe *tf = td->td_frame;
+
+ memset(tf, 0, sizeof(struct trapframe));
+
+ tf->tf_sp = stack;
+ tf->tf_lr = imgp->entry_addr;
+ tf->tf_elr = imgp->entry_addr;
+}
+
+/* Sanity check these are the same size, they will be memcpy'd to and fro */
+CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
+ sizeof((struct gpregs *)0)->gp_x);
+CTASSERT(sizeof(((struct trapframe *)0)->tf_x) ==
+ sizeof((struct reg *)0)->x);
+
+int
+get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
+{
+ struct trapframe *tf = td->td_frame;
+
+ if (clear_ret & GET_MC_CLEAR_RET)
+ mcp->mc_gpregs.gp_x[0] = 0;
+ else
+ mcp->mc_gpregs.gp_x[0] = tf->tf_x[0];
+
+ memcpy(&mcp->mc_gpregs.gp_x[1], &tf->tf_x[1],
+ sizeof(mcp->mc_gpregs.gp_x[1]) * (nitems(mcp->mc_gpregs.gp_x) - 1));
+
+ mcp->mc_gpregs.gp_sp = tf->tf_sp;
+ mcp->mc_gpregs.gp_lr = tf->tf_lr;
+ mcp->mc_gpregs.gp_elr = tf->tf_elr;
+ mcp->mc_gpregs.gp_spsr = tf->tf_spsr;
+
+ return (0);
+}
+
+int
+set_mcontext(struct thread *td, mcontext_t *mcp)
+{
+ struct trapframe *tf = td->td_frame;
+
+ memcpy(tf->tf_x, mcp->mc_gpregs.gp_x, sizeof(tf->tf_x));
+
+ tf->tf_sp = mcp->mc_gpregs.gp_sp;
+ tf->tf_lr = mcp->mc_gpregs.gp_lr;
+ tf->tf_elr = mcp->mc_gpregs.gp_elr;
+ tf->tf_spsr = mcp->mc_gpregs.gp_spsr;
+
+ return (0);
+}
+
+static void
+get_fpcontext(struct thread *td, mcontext_t *mcp)
+{
+#ifdef VFP
+ struct pcb *curpcb;
+
+ critical_enter();
+
+ curpcb = curthread->td_pcb;
+
+ if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running VFP instructions we will
+ * need to save the state to memcpy it below.
+ */
+ vfp_save_state(td);
+
+ memcpy(mcp->mc_fpregs.fp_q, curpcb->pcb_vfp,
+ sizeof(mcp->mc_fpregs));
+ mcp->mc_fpregs.fp_cr = curpcb->pcb_fpcr;
+ mcp->mc_fpregs.fp_sr = curpcb->pcb_fpsr;
+ mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
+ mcp->mc_flags |= _MC_FP_VALID;
+ }
+
+ critical_exit();
+#endif
+}
+
+static void
+set_fpcontext(struct thread *td, mcontext_t *mcp)
+{
+#ifdef VFP
+ struct pcb *curpcb;
+
+ critical_enter();
+
+ if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
+ curpcb = curthread->td_pcb;
+
+ /*
+ * Discard any vfp state for the current thread, we
+ * are about to override it.
+ */
+ vfp_discard(td);
+
+ memcpy(curpcb->pcb_vfp, mcp->mc_fpregs.fp_q,
+ sizeof(mcp->mc_fpregs));
+ curpcb->pcb_fpcr = mcp->mc_fpregs.fp_cr;
+ curpcb->pcb_fpsr = mcp->mc_fpregs.fp_sr;
+ curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags;
+ }
+
+ critical_exit();
+#endif
+}
+
+void
+cpu_idle(int busy)
+{
+
+ spinlock_enter();
+ if (!busy)
+ cpu_idleclock();
+ if (!sched_runnable())
+ __asm __volatile(
+ "dsb sy \n"
+ "wfi \n");
+ if (!busy)
+ cpu_activeclock();
+ spinlock_exit();
+}
+
+void
+cpu_halt(void)
+{
+
+ panic("cpu_halt");
+}
+
+/*
+ * Flush the D-cache for non-DMA I/O so that the I-cache can
+ * be made coherent later.
+ */
+void
+cpu_flush_dcache(void *ptr, size_t len)
+{
+
+ /* TBD */
+}
+
+/* Get current clock frequency for the given CPU ID. */
+int
+cpu_est_clockrate(int cpu_id, uint64_t *rate)
+{
+
+ panic("cpu_est_clockrate");
+}
+
+void
+cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
+{
+}
+
+void
+spinlock_enter(void)
+{
+ struct thread *td;
+ register_t daif;
+
+ td = curthread;
+ if (td->td_md.md_spinlock_count == 0) {
+ daif = intr_disable();
+ td->td_md.md_spinlock_count = 1;
+ td->td_md.md_saved_daif = daif;
+ } else
+ td->td_md.md_spinlock_count++;
+ critical_enter();
+}
+
+void
+spinlock_exit(void)
+{
+ struct thread *td;
+ register_t daif;
+
+ td = curthread;
+ critical_exit();
+ daif = td->td_md.md_saved_daif;
+ td->td_md.md_spinlock_count--;
+ if (td->td_md.md_spinlock_count == 0)
+ intr_restore(daif);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct sigreturn_args {
+ ucontext_t *ucp;
+};
+#endif
+
+int
+sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
+{
+ ucontext_t uc;
+ uint32_t spsr;
+
+ if (uap == NULL)
+ return (EFAULT);
+ if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
+ return (EFAULT);
+
+ spsr = uc.uc_mcontext.mc_gpregs.gp_spsr;
+ if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
+ (spsr & (PSR_F | PSR_I | PSR_A | PSR_D)) != 0)
+ return (EINVAL);
+
+ set_mcontext(td, &uc.uc_mcontext);
+ set_fpcontext(td, &uc.uc_mcontext);
+
+ /* Restore signal mask. */
+ kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
+
+ return (EJUSTRETURN);
+}
+
+/*
+ * Construct a PCB from a trapframe. This is called from kdb_trap() where
+ * we want to start a backtrace from the function that caused us to enter
+ * the debugger. We have the context in the trapframe, but base the trace
+ * on the PCB. The PCB doesn't have to be perfect, as long as it contains
+ * enough for a backtrace.
+ */
+void
+makectx(struct trapframe *tf, struct pcb *pcb)
+{
+ int i;
+
+ for (i = 0; i < PCB_LR; i++)
+ pcb->pcb_x[i] = tf->tf_x[i];
+
+ pcb->pcb_x[PCB_LR] = tf->tf_lr;
+ pcb->pcb_pc = tf->tf_elr;
+ pcb->pcb_sp = tf->tf_sp;
+}
+
+void
+sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct thread *td;
+ struct proc *p;
+ struct trapframe *tf;
+ struct sigframe *fp, frame;
+ struct sigacts *psp;
+ int code, onstack, sig;
+
+ td = curthread;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ sig = ksi->ksi_signo;
+ code = ksi->ksi_code;
+ psp = p->p_sigacts;
+ mtx_assert(&psp->ps_mtx, MA_OWNED);
+
+ tf = td->td_frame;
+ onstack = sigonstack(tf->tf_sp);
+
+ CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
+ catcher, sig);
+
+ /* Allocate and validate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ fp = (struct sigframe *)(td->td_sigstk.ss_sp +
+ td->td_sigstk.ss_size);
+#if defined(COMPAT_43)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else {
+ fp = (struct sigframe *)td->td_frame->tf_sp;
+ }
+
+ /* Make room, keeping the stack aligned */
+ fp--;
+ fp = (struct sigframe *)STACKALIGN(fp);
+
+ /* Fill in the frame to copy out */
+ get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+ get_fpcontext(td, &frame.sf_uc.uc_mcontext);
+ frame.sf_si = ksi->ksi_info;
+ frame.sf_uc.uc_sigmask = *mask;
+ frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ?
+ ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+ frame.sf_uc.uc_stack = td->td_sigstk;
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(td->td_proc);
+
+ /* Copy the sigframe out to the user's stack. */
+ if (copyout(&frame, fp, sizeof(*fp)) != 0) {
+ /* Process has trashed its stack. Kill it. */
+ CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ /* Translate the signal if appropriate. */
+ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
+ sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
+
+ tf->tf_x[0]= sig;
+ tf->tf_x[1] = (register_t)&fp->sf_si;
+ tf->tf_x[2] = (register_t)&fp->sf_uc;
+
+ tf->tf_elr = (register_t)catcher;
+ tf->tf_sp = (register_t)fp;
+ tf->tf_lr = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode));
+
+ CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
+ tf->tf_sp);
+
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+
+static void
+init_proc0(vm_offset_t kstack)
+{
+ struct pcpu *pcpup = &__pcpu[0];
+
+ proc_linkup0(&proc0, &thread0);
+ thread0.td_kstack = kstack;
+ thread0.td_pcb = (struct pcb *)(thread0.td_kstack) - 1;
+ thread0.td_pcb->pcb_fpflags = 0;
+ thread0.td_pcb->pcb_vfpcpu = UINT_MAX;
+ thread0.td_frame = &proc0_tf;
+ pcpup->pc_curpcb = thread0.td_pcb;
+}
+
+typedef struct {
+ uint32_t type;
+ uint64_t phys_start;
+ uint64_t virt_start;
+ uint64_t num_pages;
+ uint64_t attr;
+} EFI_MEMORY_DESCRIPTOR;
+
+static int
+add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
+ u_int *physmap_idxp)
+{
+ u_int i, insert_idx, _physmap_idx;
+
+ _physmap_idx = *physmap_idxp;
+
+ if (length == 0)
+ return (1);
+
+ /*
+ * Find insertion point while checking for overlap. Start off by
+ * assuming the new entry will be added to the end.
+ */
+ insert_idx = _physmap_idx;
+ for (i = 0; i <= _physmap_idx; i += 2) {
+ if (base < physmap[i + 1]) {
+ if (base + length <= physmap[i]) {
+ insert_idx = i;
+ break;
+ }
+ if (boothowto & RB_VERBOSE)
+ printf(
+ "Overlapping memory regions, ignoring second region\n");
+ return (1);
+ }
+ }
+
+ /* See if we can prepend to the next entry. */
+ if (insert_idx <= _physmap_idx &&
+ base + length == physmap[insert_idx]) {
+ physmap[insert_idx] = base;
+ return (1);
+ }
+
+ /* See if we can append to the previous entry. */
+ if (insert_idx > 0 && base == physmap[insert_idx - 1]) {
+ physmap[insert_idx - 1] += length;
+ return (1);
+ }
+
+ _physmap_idx += 2;
+ *physmap_idxp = _physmap_idx;
+ if (_physmap_idx == PHYSMAP_SIZE) {
+ printf(
+ "Too many segments in the physical address map, giving up\n");
+ return (0);
+ }
+
+ /*
+ * Move the last 'N' entries down to make room for the new
+ * entry if needed.
+ */
+ for (i = _physmap_idx; i > insert_idx; i -= 2) {
+ physmap[i] = physmap[i - 2];
+ physmap[i + 1] = physmap[i - 1];
+ }
+
+ /* Insert the new entry. */
+ physmap[insert_idx] = base;
+ physmap[insert_idx + 1] = base + length;
+ return (1);
+}
+
+#define efi_next_descriptor(ptr, size) \
+ ((struct efi_md *)(((uint8_t *) ptr) + size))
+
+static void
+add_efi_map_entries(struct efi_map_header *efihdr, vm_paddr_t *physmap,
+ u_int *physmap_idxp)
+{
+ struct efi_md *map, *p;
+ const char *type;
+ size_t efisz;
+ int ndesc, i;
+
+ static const char *types[] = {
+ "Reserved",
+ "LoaderCode",
+ "LoaderData",
+ "BootServicesCode",
+ "BootServicesData",
+ "RuntimeServicesCode",
+ "RuntimeServicesData",
+ "ConventionalMemory",
+ "UnusableMemory",
+ "ACPIReclaimMemory",
+ "ACPIMemoryNVS",
+ "MemoryMappedIO",
+ "MemoryMappedIOPortSpace",
+ "PalCode"
+ };
+
+ /*
+ * Memory map data provided by UEFI via the GetMemoryMap
+ * Boot Services API.
+ */
+ efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
+ map = (struct efi_md *)((uint8_t *)efihdr + efisz);
+
+ if (efihdr->descriptor_size == 0)
+ return;
+ ndesc = efihdr->memory_size / efihdr->descriptor_size;
+
+ if (boothowto & RB_VERBOSE)
+ printf("%23s %12s %12s %8s %4s\n",
+ "Type", "Physical", "Virtual", "#Pages", "Attr");
+
+ for (i = 0, p = map; i < ndesc; i++,
+ p = efi_next_descriptor(p, efihdr->descriptor_size)) {
+ if (boothowto & RB_VERBOSE) {
+ if (p->md_type <= EFI_MD_TYPE_PALCODE)
+ type = types[p->md_type];
+ else
+ type = "<INVALID>";
+ printf("%23s %012lx %12p %08lx ", type, p->md_phys,
+ p->md_virt, p->md_pages);
+ if (p->md_attr & EFI_MD_ATTR_UC)
+ printf("UC ");
+ if (p->md_attr & EFI_MD_ATTR_WC)
+ printf("WC ");
+ if (p->md_attr & EFI_MD_ATTR_WT)
+ printf("WT ");
+ if (p->md_attr & EFI_MD_ATTR_WB)
+ printf("WB ");
+ if (p->md_attr & EFI_MD_ATTR_UCE)
+ printf("UCE ");
+ if (p->md_attr & EFI_MD_ATTR_WP)
+ printf("WP ");
+ if (p->md_attr & EFI_MD_ATTR_RP)
+ printf("RP ");
+ if (p->md_attr & EFI_MD_ATTR_XP)
+ printf("XP ");
+ if (p->md_attr & EFI_MD_ATTR_RT)
+ printf("RUNTIME");
+ printf("\n");
+ }
+
+ switch (p->md_type) {
+ case EFI_MD_TYPE_CODE:
+ case EFI_MD_TYPE_DATA:
+ case EFI_MD_TYPE_BS_CODE:
+ case EFI_MD_TYPE_BS_DATA:
+ case EFI_MD_TYPE_FREE:
+ /*
+ * We're allowed to use any entry with these types.
+ */
+ break;
+ default:
+ continue;
+ }
+
+ if (!add_physmap_entry(p->md_phys, (p->md_pages * PAGE_SIZE),
+ physmap, physmap_idxp))
+ break;
+ }
+}
+
+#ifdef FDT
+static void
+try_load_dtb(caddr_t kmdp)
+{
+ vm_offset_t dtbp;
+
+ dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
+ if (dtbp == (vm_offset_t)NULL) {
+ printf("ERROR loading DTB\n");
+ return;
+ }
+
+ if (OF_install(OFW_FDT, 0) == FALSE)
+ panic("Cannot install FDT");
+
+ if (OF_init((void *)dtbp) != 0)
+ panic("OF_init failed with the found device tree");
+}
+#endif
+
+static void
+cache_setup(void)
+{
+ int dcache_line_shift, icache_line_shift;
+ uint32_t ctr_el0;
+
+ ctr_el0 = READ_SPECIALREG(ctr_el0);
+
+ /* Read the log2 words in each D cache line */
+ dcache_line_shift = CTR_DLINE_SIZE(ctr_el0);
+ /* Get the D cache line size */
+ dcache_line_size = sizeof(int) << dcache_line_shift;
+
+ /* And the same for the I cache */
+ icache_line_shift = CTR_ILINE_SIZE(ctr_el0);
+ icache_line_size = sizeof(int) << icache_line_shift;
+
+ idcache_line_size = MIN(dcache_line_size, icache_line_size);
+}
+
+void
+initarm(struct arm64_bootparams *abp)
+{
+ struct efi_map_header *efihdr;
+ struct pcpu *pcpup;
+ vm_offset_t lastaddr;
+ caddr_t kmdp;
+ vm_paddr_t mem_len;
+ int i;
+
+ /* Set the module data location */
+ preload_metadata = (caddr_t)(uintptr_t)(abp->modulep);
+
+ /* Find the kernel address */
+ kmdp = preload_search_by_type("elf kernel");
+ if (kmdp == NULL)
+ kmdp = preload_search_by_type("elf64 kernel");
+
+ boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
+ kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
+
+#ifdef FDT
+ try_load_dtb(kmdp);
+#endif
+
+ /* Find the address to start allocating from */
+ lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
+
+ /* Load the physical memory ranges */
+ physmap_idx = 0;
+ efihdr = (struct efi_map_header *)preload_search_info(kmdp,
+ MODINFO_METADATA | MODINFOMD_EFI_MAP);
+ add_efi_map_entries(efihdr, physmap, &physmap_idx);
+
+ /* Print the memory map */
+ mem_len = 0;
+ for (i = 0; i < physmap_idx; i += 2)
+ mem_len += physmap[i + 1] - physmap[i];
+
+ /* Set the pcpu data, this is needed by pmap_bootstrap */
+ pcpup = &__pcpu[0];
+ pcpu_init(pcpup, 0, sizeof(struct pcpu));
+
+ /*
+ * Set the pcpu pointer with a backup in tpidr_el1 to be
+ * loaded when entering the kernel from userland.
+ */
+ __asm __volatile(
+ "mov x18, %0 \n"
+ "msr tpidr_el1, %0" :: "r"(pcpup));
+
+ PCPU_SET(curthread, &thread0);
+
+ /* Do basic tuning, hz etc */
+ init_param1();
+
+ cache_setup();
+
+ /* Bootstrap enough of pmap to enter the kernel proper */
+ pmap_bootstrap(abp->kern_l1pt, KERNBASE - abp->kern_delta,
+ lastaddr - KERNBASE);
+
+ arm_devmap_bootstrap(0, NULL);
+
+ cninit();
+
+ init_proc0(abp->kern_stack);
+ msgbufinit(msgbufp, msgbufsize);
+ mutex_init();
+ init_param2(physmem);
+
+ dbg_monitor_init();
+ kdb_init();
+
+ early_boot = 0;
+}
+
diff --git a/sys/arm64/arm64/mem.c b/sys/arm64/arm64/mem.c
new file mode 100644
index 0000000..70c0f57
--- /dev/null
+++ b/sys/arm64/arm64/mem.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/memrange.h>
+
+#include <machine/memdev.h>
+
+struct mem_range_softc mem_range_softc;
+
+int
+memrw(struct cdev *dev, struct uio *uio, int flags)
+{
+
+ panic("memrw");
+}
+
diff --git a/sys/arm64/arm64/minidump_machdep.c b/sys/arm64/arm64/minidump_machdep.c
new file mode 100644
index 0000000..c53be2c
--- /dev/null
+++ b/sys/arm64/arm64/minidump_machdep.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_watchdog.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/kerneldump.h>
+
+#include <machine/md_var.h>
+
+int
+minidumpsys(struct dumperinfo *di)
+{
+
+ printf("minidumpsys\n");
+ while (1);
+}
+
diff --git a/sys/arm64/arm64/nexus.c b/sys/arm64/arm64/nexus.c
new file mode 100644
index 0000000..bc38330
--- /dev/null
+++ b/sys/arm64/arm64/nexus.c
@@ -0,0 +1,334 @@
+/*-
+ * Copyright 1998 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * This code implements a `root nexus' for Arm Architecture
+ * machines. The function of the root nexus is to serve as an
+ * attachment point for both processors and buses, and to manage
+ * resources which are common to all of them. In particular,
+ * this code implements the core resource managers for interrupt
+ * requests, DMA requests (which rightfully should be a part of the
+ * ISA code but it's easier to do it here for now), I/O port addresses,
+ * and I/O memory address space.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/interrupt.h>
+
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include "opt_platform.h"
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include "ofw_bus_if.h"
+#endif
+
+extern struct bus_space memmap_bus;
+
+static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
+
+struct nexus_device {
+ struct resource_list nx_resources;
+};
+
+#define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev))
+
+static struct rman mem_rman;
+
+static int nexus_probe(device_t);
+static int nexus_attach(device_t);
+static int nexus_print_child(device_t, device_t);
+static device_t nexus_add_child(device_t, u_int, const char *, int);
+static struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
+ u_long, u_long, u_long, u_int);
+static int nexus_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+ enum intr_polarity pol);
+static int nexus_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+
+static int nexus_setup_intr(device_t dev, device_t child, struct resource *res,
+ int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep);
+static int nexus_teardown_intr(device_t, device_t, struct resource *, void *);
+
+#ifdef FDT
+static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent,
+ int icells, pcell_t *intr);
+#endif
+
+static device_method_t nexus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, nexus_probe),
+ DEVMETHOD(device_attach, nexus_attach),
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, nexus_print_child),
+ DEVMETHOD(bus_add_child, nexus_add_child),
+ DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
+ DEVMETHOD(bus_activate_resource, nexus_activate_resource),
+ DEVMETHOD(bus_config_intr, nexus_config_intr),
+ DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, nexus_setup_intr),
+ DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
+#ifdef FDT
+ DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr),
+#endif
+ { 0, 0 }
+};
+
+static devclass_t nexus_devclass;
+static driver_t nexus_driver = {
+ "nexus",
+ nexus_methods,
+ 1 /* no softc */
+};
+DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
+
+static int
+nexus_probe(device_t dev)
+{
+
+ device_quiet(dev); /* suppress attach message for neatness */
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+nexus_attach(device_t dev)
+{
+
+ mem_rman.rm_start = 0;
+ mem_rman.rm_end = ~0ul;
+ mem_rman.rm_type = RMAN_ARRAY;
+ mem_rman.rm_descr = "I/O memory addresses";
+ if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0, ~0))
+ panic("nexus_probe mem_rman");
+
+ /*
+ * First, deal with the children we know about already
+ */
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static int
+nexus_print_child(device_t bus, device_t child)
+{
+ int retval = 0;
+
+ retval += bus_print_child_header(bus, child);
+ retval += printf("\n");
+
+ return (retval);
+}
+
+static device_t
+nexus_add_child(device_t bus, u_int order, const char *name, int unit)
+{
+ device_t child;
+ struct nexus_device *ndev;
+
+ ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT|M_ZERO);
+ if (!ndev)
+ return (0);
+ resource_list_init(&ndev->nx_resources);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+
+ /* should we free this in nexus_child_detached? */
+ device_set_ivars(child, ndev);
+
+ return (child);
+}
+
+
+/*
+ * Allocate a resource on behalf of child. NB: child is usually going to be a
+ * child of one of our descendants, not a direct child of nexus0.
+ * (Exceptions include footbridge.)
+ */
+static struct resource *
+nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource *rv;
+ struct rman *rm;
+ int needactivate = flags & RF_ACTIVE;
+
+ switch (type) {
+ case SYS_RES_MEMORY:
+ case SYS_RES_IOPORT:
+ rm = &mem_rman;
+ break;
+
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == 0)
+ return (NULL);
+
+ rman_set_rid(rv, *rid);
+ rman_set_bushandle(rv, rman_get_start(rv));
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
+ enum intr_polarity pol)
+{
+
+ return (arm_config_intr(irq, trig, pol));
+}
+
+static int
+nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
+ driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
+{
+ int error;
+
+ if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
+ flags |= INTR_EXCL;
+
+ /* We depend here on rman_activate_resource() being idempotent. */
+ error = rman_activate_resource(res);
+ if (error)
+ return (error);
+
+ error = arm_setup_intr(device_get_nameunit(child), filt, intr,
+ arg, rman_get_start(res), flags, cookiep);
+
+ return (error);
+}
+
+static int
+nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
+{
+
+ return (arm_teardown_intr(ih));
+}
+
+static int
+nexus_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ int err;
+ bus_addr_t paddr;
+ bus_size_t psize;
+ bus_space_handle_t vaddr;
+
+ if ((err = rman_activate_resource(r)) != 0)
+ return (err);
+
+ /*
+ * If this is a memory resource, map it into the kernel.
+ */
+ if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
+ paddr = (bus_addr_t)rman_get_start(r);
+ psize = (bus_size_t)rman_get_size(r);
+ err = bus_space_map(&memmap_bus, paddr, psize, 0, &vaddr);
+ if (err != 0) {
+ rman_deactivate_resource(r);
+ return (err);
+ }
+ rman_set_bustag(r, &memmap_bus);
+ rman_set_virtual(r, (void *)vaddr);
+ rman_set_bushandle(r, vaddr);
+ }
+ return (0);
+}
+
+static int
+nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ bus_size_t psize;
+ bus_space_handle_t vaddr;
+
+ psize = (bus_size_t)rman_get_size(r);
+ vaddr = rman_get_bushandle(r);
+
+ if (vaddr != 0) {
+ bus_space_unmap(&memmap_bus, vaddr, psize);
+ rman_set_virtual(r, NULL);
+ rman_set_bushandle(r, 0);
+ }
+
+ return (rman_deactivate_resource(r));
+}
+
+#ifdef FDT
+static int
+nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
+ pcell_t *intr)
+{
+ int irq;
+
+ if (icells == 3) {
+ irq = intr[1];
+ if (intr[0] == 0)
+ irq += 32; /* SPI */
+ else
+ irq += 16; /* PPI */
+ } else
+ irq = intr[0];
+
+ return (irq);
+}
+#endif
+
diff --git a/sys/arm64/arm64/pic_if.m b/sys/arm64/arm64/pic_if.m
new file mode 100644
index 0000000..f05c31b
--- /dev/null
+++ b/sys/arm64/arm64/pic_if.m
@@ -0,0 +1,180 @@
+#-
+# Copyright (c) 1998 Doug Rabson
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# from: src/sys/kern/bus_if.m,v 1.21 2002/04/21 11:16:10 markm Exp
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <sys/cpuset.h>
+#include <machine/frame.h>
+
+INTERFACE pic;
+
+CODE {
+ static pic_translate_code_t pic_translate_code_default;
+
+ static void pic_translate_code_default(device_t dev, u_int irq,
+ int code, enum intr_trigger *trig, enum intr_polarity *pol)
+ {
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+ }
+
+ static void pic_pre_ithread(device_t dev, u_int irq)
+ {
+ PIC_MASK(dev, irq);
+ PIC_EOI(dev, irq);
+ }
+
+ static void pic_post_ithread(device_t dev, u_int irq)
+ {
+ PIC_UNMASK(dev, irq);
+ }
+
+ static void pic_post_filter(device_t dev, u_int irq)
+ {
+ PIC_EOI(dev, irq);
+ }
+};
+
+METHOD void bind {
+ device_t dev;
+ u_int irq;
+ cpuset_t cpumask;
+};
+
+METHOD void translate_code {
+ device_t dev;
+ u_int irq;
+ int code;
+ enum intr_trigger *trig;
+ enum intr_polarity *pol;
+} DEFAULT pic_translate_code_default;
+
+METHOD void config {
+ device_t dev;
+ u_int irq;
+ enum intr_trigger trig;
+ enum intr_polarity pol;
+};
+
+METHOD void dispatch {
+ device_t dev;
+ struct trapframe *tf;
+};
+
+METHOD void enable {
+ device_t dev;
+ u_int irq;
+ u_int vector;
+};
+
+METHOD void pre_ithread {
+ device_t dev;
+ u_int irq;
+} DEFAULT pic_pre_ithread;
+
+METHOD void post_ithread {
+ device_t dev;
+ u_int irq;
+} DEFAULT pic_post_ithread;
+
+METHOD void post_filter {
+ device_t dev;
+ u_int irq;
+} DEFAULT pic_post_filter;
+
+METHOD void eoi {
+ device_t dev;
+ u_int irq;
+};
+
+METHOD void ipi {
+ device_t dev;
+ u_int cpu;
+};
+
+METHOD void mask {
+ device_t dev;
+ u_int irq;
+};
+
+METHOD void unmask {
+ device_t dev;
+ u_int irq;
+};
+
+METHOD void init_secondary {
+ device_t dev;
+};
+
+METHOD void ipi_send {
+ device_t dev;
+ cpuset_t cpus;
+ u_int ipi;
+};
+
+METHOD int alloc_msi {
+ device_t dev;
+ device_t pci_dev;
+ int count;
+ int *irqs;
+};
+
+METHOD int alloc_msix {
+ device_t dev;
+ device_t pci_dev;
+ int *irq;
+};
+
+METHOD int map_msi {
+ device_t dev;
+ device_t pci_dev;
+ int irq;
+ uint64_t *addr;
+ uint32_t *data;
+};
+
+METHOD int map_msix {
+ device_t dev;
+ device_t pci_dev;
+ int irq;
+ uint64_t *addr;
+ uint32_t *data;
+};
+
+METHOD int release_msi {
+ device_t dev;
+ device_t pci_dev;
+ int count;
+ int *irqs;
+};
+
+METHOD int release_msix {
+ device_t dev;
+ device_t pci_dev;
+ int irq;
+};
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
new file mode 100644
index 0000000..c192fa6
--- /dev/null
+++ b/sys/arm64/arm64/pmap.c
@@ -0,0 +1,3082 @@
+/*-
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ * Copyright (c) 1994 John S. Dyson
+ * All rights reserved.
+ * Copyright (c) 1994 David Greenman
+ * All rights reserved.
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ * Copyright (c) 2005-2010 Alan L. Cox <alc@cs.rice.edu>
+ * All rights reserved.
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
+ */
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Jake Burkholder,
+ * Safeport Network Services, and Network Associates Laboratories, the
+ * Security Research Division of Network Associates, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define AMD64_NPT_AWARE
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Manages physical address maps.
+ *
+ * Since the information managed by this module is
+ * also stored by the logical address mapping module,
+ * this module may throw away valid virtual-to-physical
+ * mappings at almost any time. However, invalidations
+ * of virtual-to-physical mappings must be done as
+ * requested.
+ *
+ * In order to cope with hardware architectures which
+ * make virtual-to-physical map invalidates expensive,
+ * this module may delay invalidate or reduced protection
+ * operations until such time as they are actually
+ * necessary. This module is given full information as
+ * to which processors are currently using which maps,
+ * and to when physical maps must be made correct.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/msgbuf.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/sx.h>
+#include <sys/vmem.h>
+#include <sys/vmmeter.h>
+#include <sys/sched.h>
+#include <sys/sysctl.h>
+#include <sys/_unrhdr.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_radix.h>
+#include <vm/vm_reserv.h>
+#include <vm/uma.h>
+
+#include <machine/machdep.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+
+#define NPDEPG (PAGE_SIZE/(sizeof (pd_entry_t)))
+#define NUPDE (NPDEPG * NPDEPG)
+#define NUSERPGTBLS (NUPDE + NPDEPG)
+
+#if !defined(DIAGNOSTIC)
+#ifdef __GNUC_GNU_INLINE__
+#define PMAP_INLINE __attribute__((__gnu_inline__)) inline
+#else
+#define PMAP_INLINE extern inline
+#endif
+#else
+#define PMAP_INLINE
+#endif
+
+/*
+ * These are configured by the mair_el1 register. This is set up in locore.S
+ */
+#define DEVICE_MEMORY 0
+#define UNCACHED_MEMORY 1
+#define CACHED_MEMORY 2
+
+
+#ifdef PV_STATS
+#define PV_STAT(x) do { x ; } while (0)
+#else
+#define PV_STAT(x) do { } while (0)
+#endif
+
+#define pmap_l2_pindex(v) ((v) >> L2_SHIFT)
+
+#define NPV_LIST_LOCKS MAXCPU
+
+#define PHYS_TO_PV_LIST_LOCK(pa) \
+ (&pv_list_locks[pa_index(pa) % NPV_LIST_LOCKS])
+
+#define CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa) do { \
+ struct rwlock **_lockp = (lockp); \
+ struct rwlock *_new_lock; \
+ \
+ _new_lock = PHYS_TO_PV_LIST_LOCK(pa); \
+ if (_new_lock != *_lockp) { \
+ if (*_lockp != NULL) \
+ rw_wunlock(*_lockp); \
+ *_lockp = _new_lock; \
+ rw_wlock(*_lockp); \
+ } \
+} while (0)
+
+#define CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m) \
+ CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, VM_PAGE_TO_PHYS(m))
+
+#define RELEASE_PV_LIST_LOCK(lockp) do { \
+ struct rwlock **_lockp = (lockp); \
+ \
+ if (*_lockp != NULL) { \
+ rw_wunlock(*_lockp); \
+ *_lockp = NULL; \
+ } \
+} while (0)
+
+#define VM_PAGE_TO_PV_LIST_LOCK(m) \
+ PHYS_TO_PV_LIST_LOCK(VM_PAGE_TO_PHYS(m))
+
+struct pmap kernel_pmap_store;
+
+vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss) */
+vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
+vm_offset_t kernel_vm_end = 0;
+
+struct msgbuf *msgbufp = NULL;
+
+static struct rwlock_padalign pvh_global_lock;
+
+/*
+ * Data for the pv entry allocation mechanism
+ */
+static TAILQ_HEAD(pch, pv_chunk) pv_chunks = TAILQ_HEAD_INITIALIZER(pv_chunks);
+static struct mtx pv_chunks_mutex;
+static struct rwlock pv_list_locks[NPV_LIST_LOCKS];
+
+static void free_pv_chunk(struct pv_chunk *pc);
+static void free_pv_entry(pmap_t pmap, pv_entry_t pv);
+static pv_entry_t get_pv_entry(pmap_t pmap, struct rwlock **lockp);
+static vm_page_t reclaim_pv_chunk(pmap_t locked_pmap, struct rwlock **lockp);
+static void pmap_pvh_free(struct md_page *pvh, pmap_t pmap, vm_offset_t va);
+static pv_entry_t pmap_pvh_remove(struct md_page *pvh, pmap_t pmap,
+ vm_offset_t va);
+static vm_page_t pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va,
+ vm_page_t m, vm_prot_t prot, vm_page_t mpte, struct rwlock **lockp);
+static int pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t sva,
+ pd_entry_t ptepde, struct spglist *free, struct rwlock **lockp);
+static boolean_t pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va,
+ vm_page_t m, struct rwlock **lockp);
+
+static vm_page_t _pmap_alloc_l3(pmap_t pmap, vm_pindex_t ptepindex,
+ struct rwlock **lockp);
+
+static void _pmap_unwire_l3(pmap_t pmap, vm_offset_t va, vm_page_t m,
+ struct spglist *free);
+static int pmap_unuse_l3(pmap_t, vm_offset_t, pd_entry_t, struct spglist *);
+
+/********************/
+/* Inline functions */
+/********************/
+
+static __inline void
+pagecopy(void *s, void *d)
+{
+
+ memcpy(d, s, PAGE_SIZE);
+}
+
+static __inline void
+pagezero(void *p)
+{
+
+ bzero(p, PAGE_SIZE);
+}
+
+#define pmap_l1_index(va) (((va) >> L1_SHIFT) & Ln_ADDR_MASK)
+#define pmap_l2_index(va) (((va) >> L2_SHIFT) & Ln_ADDR_MASK)
+#define pmap_l3_index(va) (((va) >> L3_SHIFT) & Ln_ADDR_MASK)
+
+static __inline pd_entry_t *
+pmap_l1(pmap_t pmap, vm_offset_t va)
+{
+
+ return (&pmap->pm_l1[pmap_l1_index(va)]);
+}
+
+static __inline pd_entry_t *
+pmap_l1_to_l2(pd_entry_t *l1, vm_offset_t va)
+{
+ pd_entry_t *l2;
+
+ l2 = (pd_entry_t *)PHYS_TO_DMAP(*l1 & ~ATTR_MASK);
+ return (&l2[pmap_l2_index(va)]);
+}
+
+static __inline pd_entry_t *
+pmap_l2(pmap_t pmap, vm_offset_t va)
+{
+ pd_entry_t *l1;
+
+ l1 = pmap_l1(pmap, va);
+ if ((*l1 & ATTR_DESCR_MASK) != L1_TABLE)
+ return (NULL);
+
+ return (pmap_l1_to_l2(l1, va));
+}
+
+static __inline pt_entry_t *
+pmap_l2_to_l3(pd_entry_t *l2, vm_offset_t va)
+{
+ pt_entry_t *l3;
+
+ l3 = (pd_entry_t *)PHYS_TO_DMAP(*l2 & ~ATTR_MASK);
+ return (&l3[pmap_l3_index(va)]);
+}
+
+static __inline pt_entry_t *
+pmap_l3(pmap_t pmap, vm_offset_t va)
+{
+ pd_entry_t *l2;
+
+ l2 = pmap_l2(pmap, va);
+ if (l2 == NULL || (*l2 & ATTR_DESCR_MASK) != L2_TABLE)
+ return (NULL);
+
+ return (pmap_l2_to_l3(l2, va));
+}
+
+/*
+ * These load the old table data and store the new value.
+ * They need to be atomic as the System MMU may write to the table at
+ * the same time as the CPU.
+ */
+#define pmap_load_store(table, entry) atomic_swap_64(table, entry)
+#define pmap_set(table, mask) atomic_set_64(table, mask)
+#define pmap_load_clear(table) atomic_swap_64(table, 0)
+#define pmap_load(table) (*table)
+
+static __inline int
+pmap_is_current(pmap_t pmap)
+{
+
+ return ((pmap == pmap_kernel()) ||
+ (pmap == curthread->td_proc->p_vmspace->vm_map.pmap));
+}
+
+static __inline int
+pmap_l3_valid(pt_entry_t l3)
+{
+
+ return ((l3 & ATTR_DESCR_MASK) == L3_PAGE);
+}
+
+static __inline int
+pmap_l3_valid_cacheable(pt_entry_t l3)
+{
+
+ return (((l3 & ATTR_DESCR_MASK) == L3_PAGE) &&
+ ((l3 & ATTR_IDX_MASK) == ATTR_IDX(CACHED_MEMORY)));
+}
+
+#define PTE_SYNC(pte) cpu_dcache_wb_range((vm_offset_t)pte, sizeof(*pte))
+
+/*
+ * Checks if the page is dirty. We currently lack proper tracking of this on
+ * arm64 so for now assume is a page mapped as rw was accessed it is.
+ */
+static inline int
+pmap_page_dirty(pt_entry_t pte)
+{
+
+ return ((pte & (ATTR_AF | ATTR_AP_RW_BIT)) ==
+ (ATTR_AF | ATTR_AP(ATTR_AP_RW)));
+}
+
+static __inline void
+pmap_resident_count_inc(pmap_t pmap, int count)
+{
+
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ pmap->pm_stats.resident_count += count;
+}
+
+static __inline void
+pmap_resident_count_dec(pmap_t pmap, int count)
+{
+
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ KASSERT(pmap->pm_stats.resident_count >= count,
+ ("pmap %p resident count underflow %ld %d", pmap,
+ pmap->pm_stats.resident_count, count));
+ pmap->pm_stats.resident_count -= count;
+}
+
+static pt_entry_t *
+pmap_early_page_idx(vm_offset_t l1pt, vm_offset_t va, u_int *l1_slot,
+ u_int *l2_slot)
+{
+ pt_entry_t *l2;
+ pd_entry_t *l1;
+
+ l1 = (pd_entry_t *)l1pt;
+ *l1_slot = (va >> L1_SHIFT) & Ln_ADDR_MASK;
+
+ /* Check locore has used a table L1 map */
+ KASSERT((l1[*l1_slot] & ATTR_DESCR_MASK) == L1_TABLE,
+ ("Invalid bootstrap L1 table"));
+ /* Find the address of the L2 table */
+ l2 = (pt_entry_t *)init_pt_va;
+ *l2_slot = pmap_l2_index(va);
+
+ return (l2);
+}
+
+static vm_paddr_t
+pmap_early_vtophys(vm_offset_t l1pt, vm_offset_t va)
+{
+ u_int l1_slot, l2_slot;
+ pt_entry_t *l2;
+
+ l2 = pmap_early_page_idx(l1pt, va, &l1_slot, &l2_slot);
+
+ return ((l2[l2_slot] & ~ATTR_MASK) + (va & L2_OFFSET));
+}
+
+static void
+pmap_bootstrap_dmap(vm_offset_t l1pt)
+{
+ vm_offset_t va;
+ vm_paddr_t pa;
+ pd_entry_t *l1;
+ u_int l1_slot;
+
+ va = DMAP_MIN_ADDRESS;
+ l1 = (pd_entry_t *)l1pt;
+ l1_slot = pmap_l1_index(DMAP_MIN_ADDRESS);
+
+ for (pa = 0; va < DMAP_MAX_ADDRESS;
+ pa += L1_SIZE, va += L1_SIZE, l1_slot++) {
+ KASSERT(l1_slot < Ln_ENTRIES, ("Invalid L1 index"));
+
+ /*
+ * TODO: Turn the cache on here when we have cache
+ * flushing code.
+ */
+ pmap_load_store(&l1[l1_slot],
+ (pa & ~L1_OFFSET) | ATTR_AF | L1_BLOCK |
+ ATTR_IDX(CACHED_MEMORY));
+ }
+
+ cpu_dcache_wb_range((vm_offset_t)l1, PAGE_SIZE);
+ cpu_tlb_flushID();
+}
+
+static vm_offset_t
+pmap_bootstrap_l2(vm_offset_t l1pt, vm_offset_t va, vm_offset_t l2_start)
+{
+ vm_offset_t l2pt;
+ vm_paddr_t pa;
+ pd_entry_t *l1;
+ u_int l1_slot;
+
+ KASSERT((va & L1_OFFSET) == 0, ("Invalid virtual address"));
+
+ l1 = (pd_entry_t *)l1pt;
+ l1_slot = pmap_l1_index(va);
+ l2pt = l2_start;
+
+ for (; va < VM_MAX_KERNEL_ADDRESS; l1_slot++, va += L1_SIZE) {
+ KASSERT(l1_slot < Ln_ENTRIES, ("Invalid L1 index"));
+
+ pa = pmap_early_vtophys(l1pt, l2pt);
+ pmap_load_store(&l1[l1_slot],
+ (pa & ~Ln_TABLE_MASK) | L1_TABLE);
+ l2pt += PAGE_SIZE;
+ }
+
+ /* Clean the L2 page table */
+ memset((void *)l2_start, 0, l2pt - l2_start);
+ cpu_dcache_wb_range(l2_start, l2pt - l2_start);
+
+ /* Flush the l1 table to ram */
+ cpu_dcache_wb_range((vm_offset_t)l1, PAGE_SIZE);
+
+ return l2pt;
+}
+
+static vm_offset_t
+pmap_bootstrap_l3(vm_offset_t l1pt, vm_offset_t va, vm_offset_t l3_start)
+{
+ vm_offset_t l2pt, l3pt;
+ vm_paddr_t pa;
+ pd_entry_t *l2;
+ u_int l2_slot;
+
+ KASSERT((va & L2_OFFSET) == 0, ("Invalid virtual address"));
+
+ l2 = pmap_l2(kernel_pmap, va);
+ l2 = (pd_entry_t *)((uintptr_t)l2 & ~(PAGE_SIZE - 1));
+ l2pt = (vm_offset_t)l2;
+ l2_slot = pmap_l2_index(va);
+ l3pt = l3_start;
+
+ for (; va < VM_MAX_KERNEL_ADDRESS; l2_slot++, va += L2_SIZE) {
+ KASSERT(l2_slot < Ln_ENTRIES, ("Invalid L2 index"));
+
+ pa = pmap_early_vtophys(l1pt, l3pt);
+ pmap_load_store(&l2[l2_slot],
+ (pa & ~Ln_TABLE_MASK) | L2_TABLE);
+ l3pt += PAGE_SIZE;
+ }
+
+ /* Clean the L2 page table */
+ memset((void *)l3_start, 0, l3pt - l3_start);
+ cpu_dcache_wb_range(l3_start, l3pt - l3_start);
+
+ cpu_dcache_wb_range((vm_offset_t)l2, PAGE_SIZE);
+
+ return l3pt;
+}
+
+/*
+ * Bootstrap the system enough to run with virtual memory.
+ */
+void
+pmap_bootstrap(vm_offset_t l1pt, vm_paddr_t kernstart, vm_size_t kernlen)
+{
+ u_int l1_slot, l2_slot, avail_slot, map_slot, used_map_slot;
+ uint64_t kern_delta;
+ pt_entry_t *l2;
+ vm_offset_t va, freemempos;
+ vm_offset_t dpcpu, msgbufpv;
+ vm_paddr_t pa;
+
+ kern_delta = KERNBASE - kernstart;
+ physmem = 0;
+
+ printf("pmap_bootstrap %lx %lx %lx\n", l1pt, kernstart, kernlen);
+ printf("%lx\n", l1pt);
+ printf("%lx\n", (KERNBASE >> L1_SHIFT) & Ln_ADDR_MASK);
+
+ /* Set this early so we can use the pagetable walking functions */
+ kernel_pmap_store.pm_l1 = (pd_entry_t *)l1pt;
+ PMAP_LOCK_INIT(kernel_pmap);
+
+ /*
+ * Initialize the global pv list lock.
+ */
+ rw_init(&pvh_global_lock, "pmap pv global");
+
+ /* Create a direct map region early so we can use it for pa -> va */
+ pmap_bootstrap_dmap(l1pt);
+
+ va = KERNBASE;
+ pa = KERNBASE - kern_delta;
+
+ /*
+ * Start to initialise phys_avail by copying from physmap
+ * up to the physical address KERNBASE points at.
+ */
+ map_slot = avail_slot = 0;
+ for (; map_slot < (physmap_idx * 2); map_slot += 2) {
+ if (physmap[map_slot] == physmap[map_slot + 1])
+ continue;
+
+ if (physmap[map_slot] <= pa &&
+ physmap[map_slot + 1] > pa)
+ break;
+
+ phys_avail[avail_slot] = physmap[map_slot];
+ phys_avail[avail_slot + 1] = physmap[map_slot + 1];
+ physmem += (phys_avail[avail_slot + 1] -
+ phys_avail[avail_slot]) >> PAGE_SHIFT;
+ avail_slot += 2;
+ }
+
+ /* Add the memory before the kernel */
+ if (physmap[avail_slot] < pa) {
+ phys_avail[avail_slot] = physmap[map_slot];
+ phys_avail[avail_slot + 1] = pa;
+ physmem += (phys_avail[avail_slot + 1] -
+ phys_avail[avail_slot]) >> PAGE_SHIFT;
+ avail_slot += 2;
+ }
+ used_map_slot = map_slot;
+
+ /*
+ * Read the page table to find out what is already mapped.
+ * This assumes we have mapped a block of memory from KERNBASE
+ * using a single L1 entry.
+ */
+ l2 = pmap_early_page_idx(l1pt, KERNBASE, &l1_slot, &l2_slot);
+
+ /* Sanity check the index, KERNBASE should be the first VA */
+ KASSERT(l2_slot == 0, ("The L2 index is non-zero"));
+
+ /* Find how many pages we have mapped */
+ for (; l2_slot < Ln_ENTRIES; l2_slot++) {
+ if ((l2[l2_slot] & ATTR_DESCR_MASK) == 0)
+ break;
+
+ /* Check locore used L2 blocks */
+ KASSERT((l2[l2_slot] & ATTR_DESCR_MASK) == L2_BLOCK,
+ ("Invalid bootstrap L2 table"));
+ KASSERT((l2[l2_slot] & ~ATTR_MASK) == pa,
+ ("Incorrect PA in L2 table"));
+
+ va += L2_SIZE;
+ pa += L2_SIZE;
+ }
+
+ va = roundup2(va, L1_SIZE);
+
+ freemempos = KERNBASE + kernlen;
+ freemempos = roundup2(freemempos, PAGE_SIZE);
+ /* Create the l2 tables up to VM_MAX_KERNEL_ADDRESS */
+ freemempos = pmap_bootstrap_l2(l1pt, va, freemempos);
+ /* And the l3 tables for the early devmap */
+ freemempos = pmap_bootstrap_l3(l1pt,
+ VM_MAX_KERNEL_ADDRESS - L2_SIZE, freemempos);
+
+ cpu_tlb_flushID();
+
+#define alloc_pages(var, np) \
+ (var) = freemempos; \
+ freemempos += (np * PAGE_SIZE); \
+ memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+ /* Allocate dynamic per-cpu area. */
+ alloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE);
+ dpcpu_init((void *)dpcpu, 0);
+
+ /* Allocate memory for the msgbuf, e.g. for /sbin/dmesg */
+ alloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE);
+ msgbufp = (void *)msgbufpv;
+
+ virtual_avail = roundup2(freemempos, L1_SIZE);
+ virtual_end = VM_MAX_KERNEL_ADDRESS - L2_SIZE;
+ kernel_vm_end = virtual_avail;
+
+ pa = pmap_early_vtophys(l1pt, freemempos);
+
+ /* Finish initialising physmap */
+ map_slot = used_map_slot;
+ for (; avail_slot < (PHYS_AVAIL_SIZE - 2) &&
+ map_slot < (physmap_idx * 2); map_slot += 2) {
+ if (physmap[map_slot] == physmap[map_slot + 1])
+ continue;
+
+ /* Have we used the current range? */
+ if (physmap[map_slot + 1] <= pa)
+ continue;
+
+ /* Do we need to split the entry? */
+ if (physmap[map_slot] < pa) {
+ phys_avail[avail_slot] = pa;
+ phys_avail[avail_slot + 1] = physmap[map_slot + 1];
+ } else {
+ phys_avail[avail_slot] = physmap[map_slot];
+ phys_avail[avail_slot + 1] = physmap[map_slot + 1];
+ }
+ physmem += (phys_avail[avail_slot + 1] -
+ phys_avail[avail_slot]) >> PAGE_SHIFT;
+
+ avail_slot += 2;
+ }
+ phys_avail[avail_slot] = 0;
+ phys_avail[avail_slot + 1] = 0;
+
+ /*
+ * Maxmem isn't the "maximum memory", it's one larger than the
+ * highest page of the physical address space. It should be
+ * called something like "Maxphyspage".
+ */
+ Maxmem = atop(phys_avail[avail_slot - 1]);
+
+ cpu_tlb_flushID();
+}
+
+/*
+ * Initialize a vm_page's machine-dependent fields.
+ */
+void
+pmap_page_init(vm_page_t m)
+{
+
+ TAILQ_INIT(&m->md.pv_list);
+ m->md.pv_memattr = VM_MEMATTR_WRITE_BACK;
+}
+
+/*
+ * Initialize the pmap module.
+ * Called by vm_init, to initialize any structures that the pmap
+ * system needs to map virtual memory.
+ */
+void
+pmap_init(void)
+{
+ int i;
+
+ /*
+ * Initialize the pv chunk list mutex.
+ */
+ mtx_init(&pv_chunks_mutex, "pmap pv chunk list", NULL, MTX_DEF);
+
+ /*
+ * Initialize the pool of pv list locks.
+ */
+ for (i = 0; i < NPV_LIST_LOCKS; i++)
+ rw_init(&pv_list_locks[i], "pmap pv list");
+}
+
+/*
+ * Normal, non-SMP, invalidation functions.
+ * We inline these within pmap.c for speed.
+ */
+PMAP_INLINE void
+pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
+{
+
+ sched_pin();
+ __asm __volatile(
+ "dsb sy \n"
+ "tlbi vaae1is, %0 \n"
+ "dsb sy \n"
+ "isb \n"
+ : : "r"(va >> PAGE_SHIFT));
+ sched_unpin();
+}
+
+PMAP_INLINE void
+pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
+{
+ vm_offset_t addr;
+
+ sched_pin();
+ sva >>= PAGE_SHIFT;
+ eva >>= PAGE_SHIFT;
+ __asm __volatile("dsb sy");
+ for (addr = sva; addr < eva; addr++) {
+ __asm __volatile(
+ "tlbi vaae1is, %0" : : "r"(addr));
+ }
+ __asm __volatile(
+ "dsb sy \n"
+ "isb \n");
+ sched_unpin();
+}
+
+PMAP_INLINE void
+pmap_invalidate_all(pmap_t pmap)
+{
+
+ sched_pin();
+ __asm __volatile(
+ "dsb sy \n"
+ "tlbi vmalle1is \n"
+ "dsb sy \n"
+ "isb \n");
+ sched_unpin();
+}
+
+/*
+ * Routine: pmap_extract
+ * Function:
+ * Extract the physical page address associated
+ * with the given map/virtual_address pair.
+ */
+vm_paddr_t
+pmap_extract(pmap_t pmap, vm_offset_t va)
+{
+ pd_entry_t *l2p, l2;
+ pt_entry_t *l3p, l3;
+ vm_paddr_t pa;
+
+ pa = 0;
+ PMAP_LOCK(pmap);
+ /*
+ * Start with the l2 tabel. We are unable to allocate
+ * pages in the l1 table.
+ */
+ l2p = pmap_l2(pmap, va);
+ if (l2p != NULL) {
+ l2 = *l2p;
+ if ((l2 & ATTR_DESCR_MASK) == L2_TABLE) {
+ l3p = pmap_l2_to_l3(l2p, va);
+ if (l3p != NULL) {
+ l3 = *l3p;
+
+ if ((l3 & ATTR_DESCR_MASK) == L3_PAGE)
+ pa = (l3 & ~ATTR_MASK) |
+ (va & L3_OFFSET);
+ }
+ } else if ((l2 & ATTR_DESCR_MASK) == L2_BLOCK)
+ pa = (l2 & ~ATTR_MASK) | (va & L2_OFFSET);
+ }
+ PMAP_UNLOCK(pmap);
+ return (pa);
+}
+
+/*
+ * Routine: pmap_extract_and_hold
+ * Function:
+ * Atomically extract and hold the physical page
+ * with the given pmap and virtual address pair
+ * if that mapping permits the given protection.
+ */
+vm_page_t
+pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot)
+{
+ pt_entry_t *l3p, l3;
+ vm_paddr_t pa;
+ vm_page_t m;
+
+ pa = 0;
+ m = NULL;
+ PMAP_LOCK(pmap);
+retry:
+ l3p = pmap_l3(pmap, va);
+ if (l3p != NULL && (l3 = *l3p) != 0) {
+ if (((l3 & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW)) ||
+ ((prot & VM_PROT_WRITE) == 0)) {
+ if (vm_page_pa_tryrelock(pmap, l3 & ~ATTR_MASK, &pa))
+ goto retry;
+ m = PHYS_TO_VM_PAGE(l3 & ~ATTR_MASK);
+ vm_page_hold(m);
+ }
+ }
+ PA_UNLOCK_COND(pa);
+ PMAP_UNLOCK(pmap);
+ return (m);
+}
+
+vm_paddr_t
+pmap_kextract(vm_offset_t va)
+{
+ pd_entry_t *l2;
+ pt_entry_t *l3;
+ vm_paddr_t pa;
+
+ if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) {
+ pa = DMAP_TO_PHYS(va);
+ } else {
+ l2 = pmap_l2(kernel_pmap, va);
+ if (l2 == NULL)
+ panic("pmap_kextract: No l2");
+ if ((*l2 & ATTR_DESCR_MASK) == L2_BLOCK)
+ return ((*l2 & ~ATTR_MASK) | (va & L2_OFFSET));
+
+ l3 = pmap_l2_to_l3(l2, va);
+ if (l3 == NULL)
+ panic("pmap_kextract: No l3...");
+ pa = (*l3 & ~ATTR_MASK) | (va & PAGE_MASK);
+ }
+ return (pa);
+}
+
+/***************************************************
+ * Low level mapping routines.....
+ ***************************************************/
+
+void
+pmap_kenter_device(vm_offset_t va, vm_size_t size, vm_paddr_t pa)
+{
+ pt_entry_t *l3;
+
+ KASSERT((pa & L3_OFFSET) == 0,
+ ("pmap_kenter_device: Invalid physical address"));
+ KASSERT((va & L3_OFFSET) == 0,
+ ("pmap_kenter_device: Invalid virtual address"));
+ KASSERT((size & PAGE_MASK) == 0,
+ ("pmap_kenter_device: Mapping is not page-sized"));
+
+ while (size != 0) {
+ l3 = pmap_l3(kernel_pmap, va);
+ KASSERT(l3 != NULL, ("Invalid page table, va: 0x%lx", va));
+ pmap_load_store(l3, (pa & ~L3_OFFSET) | ATTR_AF | L3_PAGE |
+ ATTR_IDX(DEVICE_MEMORY));
+ PTE_SYNC(l3);
+
+ va += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+}
+
+/*
+ * Remove a page from the kernel pagetables.
+ * Note: not SMP coherent.
+ */
+PMAP_INLINE void
+pmap_kremove(vm_offset_t va)
+{
+ pt_entry_t *l3;
+
+ l3 = pmap_l3(kernel_pmap, va);
+ KASSERT(l3 != NULL, ("pmap_kremove: Invalid address"));
+
+ if (pmap_l3_valid_cacheable(pmap_load(l3)))
+ cpu_dcache_wb_range(va, L3_SIZE);
+ pmap_load_clear(l3);
+ PTE_SYNC(l3);
+}
+
+void
+pmap_kremove_device(vm_offset_t va, vm_size_t size)
+{
+ pt_entry_t *l3;
+
+ KASSERT((va & L3_OFFSET) == 0,
+ ("pmap_kremove_device: Invalid virtual address"));
+ KASSERT((size & PAGE_MASK) == 0,
+ ("pmap_kremove_device: Mapping is not page-sized"));
+
+ while (size != 0) {
+ l3 = pmap_l3(kernel_pmap, va);
+ KASSERT(l3 != NULL, ("Invalid page table, va: 0x%lx", va));
+ pmap_load_clear(l3);
+ PTE_SYNC(l3);
+
+ va += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+}
+
+/*
+ * Used to map a range of physical addresses into kernel
+ * virtual address space.
+ *
+ * The value passed in '*virt' is a suggested virtual address for
+ * the mapping. Architectures which can support a direct-mapped
+ * physical to virtual region can return the appropriate address
+ * within that region, leaving '*virt' unchanged. Other
+ * architectures should map the pages starting at '*virt' and
+ * update '*virt' with the first usable address after the mapped
+ * region.
+ */
+vm_offset_t
+pmap_map(vm_offset_t *virt, vm_paddr_t start, vm_paddr_t end, int prot)
+{
+ return PHYS_TO_DMAP(start);
+}
+
+
+/*
+ * Add a list of wired pages to the kva
+ * this routine is only used for temporary
+ * kernel mappings that do not need to have
+ * page modification or references recorded.
+ * Note that old mappings are simply written
+ * over. The page *must* be wired.
+ * Note: SMP coherent. Uses a ranged shootdown IPI.
+ */
+void
+pmap_qenter(vm_offset_t sva, vm_page_t *ma, int count)
+{
+ pt_entry_t *l3, pa;
+ vm_offset_t va;
+ vm_page_t m;
+ int i;
+
+ va = sva;
+ for (i = 0; i < count; i++) {
+ m = ma[i];
+ pa = VM_PAGE_TO_PHYS(m) | ATTR_AF |
+ ATTR_IDX(m->md.pv_memattr) | ATTR_AP(ATTR_AP_RW) | L3_PAGE;
+ l3 = pmap_l3(kernel_pmap, va);
+ pmap_load_store(l3, pa);
+ PTE_SYNC(l3);
+
+ va += L3_SIZE;
+ }
+}
+
+/*
+ * This routine tears out page mappings from the
+ * kernel -- it is meant only for temporary mappings.
+ * Note: SMP coherent. Uses a ranged shootdown IPI.
+ */
+void
+pmap_qremove(vm_offset_t sva, int count)
+{
+ vm_offset_t va;
+
+ va = sva;
+ while (count-- > 0) {
+ KASSERT(va >= VM_MIN_KERNEL_ADDRESS, ("usermode va %lx", va));
+ pmap_kremove(va);
+ va += PAGE_SIZE;
+ }
+ pmap_invalidate_range(kernel_pmap, sva, va);
+}
+
+/***************************************************
+ * Page table page management routines.....
+ ***************************************************/
+static __inline void
+pmap_free_zero_pages(struct spglist *free)
+{
+ vm_page_t m;
+
+ while ((m = SLIST_FIRST(free)) != NULL) {
+ SLIST_REMOVE_HEAD(free, plinks.s.ss);
+ /* Preserve the page's PG_ZERO setting. */
+ vm_page_free_toq(m);
+ }
+}
+
+/*
+ * Schedule the specified unused page table page to be freed. Specifically,
+ * add the page to the specified list of pages that will be released to the
+ * physical memory manager after the TLB has been updated.
+ */
+static __inline void
+pmap_add_delayed_free_list(vm_page_t m, struct spglist *free,
+ boolean_t set_PG_ZERO)
+{
+
+ if (set_PG_ZERO)
+ m->flags |= PG_ZERO;
+ else
+ m->flags &= ~PG_ZERO;
+ SLIST_INSERT_HEAD(free, m, plinks.s.ss);
+}
+
+/*
+ * Decrements a page table page's wire count, which is used to record the
+ * number of valid page table entries within the page. If the wire count
+ * drops to zero, then the page table page is unmapped. Returns TRUE if the
+ * page table page was unmapped and FALSE otherwise.
+ */
+static inline boolean_t
+pmap_unwire_l3(pmap_t pmap, vm_offset_t va, vm_page_t m, struct spglist *free)
+{
+
+ --m->wire_count;
+ if (m->wire_count == 0) {
+ _pmap_unwire_l3(pmap, va, m, free);
+ return (TRUE);
+ } else
+ return (FALSE);
+}
+
+static void
+_pmap_unwire_l3(pmap_t pmap, vm_offset_t va, vm_page_t m, struct spglist *free)
+{
+
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ /*
+ * unmap the page table page
+ */
+ if (m->pindex >= NUPDE) {
+ /* PD page */
+ pd_entry_t *l1;
+ l1 = pmap_l1(pmap, va);
+ pmap_load_clear(l1);
+ PTE_SYNC(l1);
+ } else {
+ /* PTE page */
+ pd_entry_t *l2;
+ l2 = pmap_l2(pmap, va);
+ pmap_load_clear(l2);
+ PTE_SYNC(l2);
+ }
+ pmap_resident_count_dec(pmap, 1);
+ if (m->pindex < NUPDE) {
+ /* We just released a PT, unhold the matching PD */
+ vm_page_t pdpg;
+
+ pdpg = PHYS_TO_VM_PAGE(*pmap_l1(pmap, va) & ~ATTR_MASK);
+ pmap_unwire_l3(pmap, va, pdpg, free);
+ }
+
+ /*
+ * This is a release store so that the ordinary store unmapping
+ * the page table page is globally performed before TLB shoot-
+ * down is begun.
+ */
+ atomic_subtract_rel_int(&vm_cnt.v_wire_count, 1);
+
+ /*
+ * Put page on a list so that it is released after
+ * *ALL* TLB shootdown is done
+ */
+ pmap_add_delayed_free_list(m, free, TRUE);
+}
+
+/*
+ * After removing an l3 entry, this routine is used to
+ * conditionally free the page, and manage the hold/wire counts.
+ */
+static int
+pmap_unuse_l3(pmap_t pmap, vm_offset_t va, pd_entry_t ptepde,
+ struct spglist *free)
+{
+ vm_page_t mpte;
+
+ if (va >= VM_MAXUSER_ADDRESS)
+ return (0);
+ KASSERT(ptepde != 0, ("pmap_unuse_pt: ptepde != 0"));
+ mpte = PHYS_TO_VM_PAGE(ptepde & ~ATTR_MASK);
+ return (pmap_unwire_l3(pmap, va, mpte, free));
+}
+
+void
+pmap_pinit0(pmap_t pmap)
+{
+
+ PMAP_LOCK_INIT(pmap);
+ bzero(&pmap->pm_stats, sizeof(pmap->pm_stats));
+ pmap->pm_l1 = kernel_pmap->pm_l1;
+}
+
+int
+pmap_pinit(pmap_t pmap)
+{
+ vm_paddr_t l1phys;
+ vm_page_t l1pt;
+
+ /*
+ * allocate the l1 page
+ */
+ while ((l1pt = vm_page_alloc(NULL, 0xdeadbeef, VM_ALLOC_NORMAL |
+ VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL)
+ VM_WAIT;
+
+ l1phys = VM_PAGE_TO_PHYS(l1pt);
+ pmap->pm_l1 = (pd_entry_t *)PHYS_TO_DMAP(l1phys);
+
+ if ((l1pt->flags & PG_ZERO) == 0)
+ pagezero(pmap->pm_l1);
+
+ bzero(&pmap->pm_stats, sizeof(pmap->pm_stats));
+
+ return (1);
+}
+
+/*
+ * This routine is called if the desired page table page does not exist.
+ *
+ * If page table page allocation fails, this routine may sleep before
+ * returning NULL. It sleeps only if a lock pointer was given.
+ *
+ * Note: If a page allocation fails at page table level two or three,
+ * one or two pages may be held during the wait, only to be released
+ * afterwards. This conservative approach is easily argued to avoid
+ * race conditions.
+ */
+static vm_page_t
+_pmap_alloc_l3(pmap_t pmap, vm_pindex_t ptepindex, struct rwlock **lockp)
+{
+ vm_page_t m, /*pdppg, */pdpg;
+
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+
+ /*
+ * Allocate a page table page.
+ */
+ if ((m = vm_page_alloc(NULL, ptepindex, VM_ALLOC_NOOBJ |
+ VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) {
+ if (lockp != NULL) {
+ RELEASE_PV_LIST_LOCK(lockp);
+ PMAP_UNLOCK(pmap);
+ rw_runlock(&pvh_global_lock);
+ VM_WAIT;
+ rw_rlock(&pvh_global_lock);
+ PMAP_LOCK(pmap);
+ }
+
+ /*
+ * Indicate the need to retry. While waiting, the page table
+ * page may have been allocated.
+ */
+ return (NULL);
+ }
+ if ((m->flags & PG_ZERO) == 0)
+ pmap_zero_page(m);
+
+ /*
+ * Map the pagetable page into the process address space, if
+ * it isn't already there.
+ */
+
+ if (ptepindex >= NUPDE) {
+ pd_entry_t *l1;
+ vm_pindex_t l1index;
+
+ l1index = ptepindex - NUPDE;
+ l1 = &pmap->pm_l1[l1index];
+ pmap_load_store(l1, VM_PAGE_TO_PHYS(m) | L1_TABLE);
+ PTE_SYNC(l1);
+
+ } else {
+ vm_pindex_t l1index;
+ pd_entry_t *l1, *l2;
+
+ l1index = ptepindex >> (L1_SHIFT - L2_SHIFT);
+ l1 = &pmap->pm_l1[l1index];
+ if (*l1 == 0) {
+ /* recurse for allocating page dir */
+ if (_pmap_alloc_l3(pmap, NUPDE + l1index,
+ lockp) == NULL) {
+ --m->wire_count;
+ atomic_subtract_int(&vm_cnt.v_wire_count, 1);
+ vm_page_free_zero(m);
+ return (NULL);
+ }
+ } else {
+ pdpg = PHYS_TO_VM_PAGE(*l1 & ~ATTR_MASK);
+ pdpg->wire_count++;
+ }
+
+ l2 = (pd_entry_t *)PHYS_TO_DMAP(*l1 & ~ATTR_MASK);
+ l2 = &l2[ptepindex & Ln_ADDR_MASK];
+ pmap_load_store(l2, VM_PAGE_TO_PHYS(m) | ATTR_AF |
+ ATTR_IDX(CACHED_MEMORY) | L2_TABLE);
+ PTE_SYNC(l2);
+ }
+
+ pmap_resident_count_inc(pmap, 1);
+
+ return (m);
+}
+
+static vm_page_t
+pmap_alloc_l3(pmap_t pmap, vm_offset_t va, struct rwlock **lockp)
+{
+ vm_pindex_t ptepindex;
+ pd_entry_t *l2;
+ vm_page_t m;
+
+ /*
+ * Calculate pagetable page index
+ */
+ ptepindex = pmap_l2_pindex(va);
+retry:
+ /*
+ * Get the page directory entry
+ */
+ l2 = pmap_l2(pmap, va);
+
+ /*
+ * If the page table page is mapped, we just increment the
+ * hold count, and activate it.
+ */
+ if (l2 != NULL && *l2 != 0) {
+ m = PHYS_TO_VM_PAGE(*l2 & ~ATTR_MASK);
+ m->wire_count++;
+ } else {
+ /*
+ * Here if the pte page isn't mapped, or if it has been
+ * deallocated.
+ */
+ m = _pmap_alloc_l3(pmap, ptepindex, lockp);
+ if (m == NULL && lockp != NULL)
+ goto retry;
+ }
+ /*
+ * XXXARM64: I'm not sure why we need this but it fixes a crash
+ * when running things from a shell script.
+ */
+ pmap_invalidate_all(pmap);
+ return (m);
+}
+
+
+/***************************************************
+ * Pmap allocation/deallocation routines.
+ ***************************************************/
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_release(pmap_t pmap)
+{
+ vm_page_t m;
+
+ KASSERT(pmap->pm_stats.resident_count == 0,
+ ("pmap_release: pmap resident count %ld != 0",
+ pmap->pm_stats.resident_count));
+
+ m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pmap->pm_l1));
+
+ m->wire_count--;
+ atomic_subtract_int(&vm_cnt.v_wire_count, 1);
+ vm_page_free_zero(m);
+}
+
+#if 0
+static int
+kvm_size(SYSCTL_HANDLER_ARGS)
+{
+ unsigned long ksize = VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS;
+
+ return sysctl_handle_long(oidp, &ksize, 0, req);
+}
+SYSCTL_PROC(_vm, OID_AUTO, kvm_size, CTLTYPE_LONG|CTLFLAG_RD,
+ 0, 0, kvm_size, "LU", "Size of KVM");
+
+static int
+kvm_free(SYSCTL_HANDLER_ARGS)
+{
+ unsigned long kfree = VM_MAX_KERNEL_ADDRESS - kernel_vm_end;
+
+ return sysctl_handle_long(oidp, &kfree, 0, req);
+}
+SYSCTL_PROC(_vm, OID_AUTO, kvm_free, CTLTYPE_LONG|CTLFLAG_RD,
+ 0, 0, kvm_free, "LU", "Amount of KVM free");
+#endif /* 0 */
+
+/*
+ * grow the number of kernel page table entries, if needed
+ */
+void
+pmap_growkernel(vm_offset_t addr)
+{
+ vm_paddr_t paddr;
+ vm_page_t nkpg;
+ pd_entry_t *l1, *l2;
+
+ mtx_assert(&kernel_map->system_mtx, MA_OWNED);
+
+ addr = roundup2(addr, L2_SIZE);
+ if (addr - 1 >= kernel_map->max_offset)
+ addr = kernel_map->max_offset;
+ while (kernel_vm_end < addr) {
+ l1 = pmap_l1(kernel_pmap, kernel_vm_end);
+ if (*l1 == 0) {
+ /* We need a new PDP entry */
+ nkpg = vm_page_alloc(NULL, kernel_vm_end >> L1_SHIFT,
+ VM_ALLOC_INTERRUPT | VM_ALLOC_NOOBJ |
+ VM_ALLOC_WIRED | VM_ALLOC_ZERO);
+ if (nkpg == NULL)
+ panic("pmap_growkernel: no memory to grow kernel");
+ if ((nkpg->flags & PG_ZERO) == 0)
+ pmap_zero_page(nkpg);
+ paddr = VM_PAGE_TO_PHYS(nkpg);
+ pmap_load_store(l1, paddr | L1_TABLE);
+ PTE_SYNC(l1);
+ continue; /* try again */
+ }
+ l2 = pmap_l1_to_l2(l1, kernel_vm_end);
+ if ((*l2 & ATTR_AF) != 0) {
+ kernel_vm_end = (kernel_vm_end + L2_SIZE) & ~L2_OFFSET;
+ if (kernel_vm_end - 1 >= kernel_map->max_offset) {
+ kernel_vm_end = kernel_map->max_offset;
+ break;
+ }
+ continue;
+ }
+
+ nkpg = vm_page_alloc(NULL, kernel_vm_end >> L2_SHIFT,
+ VM_ALLOC_INTERRUPT | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
+ VM_ALLOC_ZERO);
+ if (nkpg == NULL)
+ panic("pmap_growkernel: no memory to grow kernel");
+ if ((nkpg->flags & PG_ZERO) == 0)
+ pmap_zero_page(nkpg);
+ paddr = VM_PAGE_TO_PHYS(nkpg);
+ pmap_load_store(l2, paddr | L2_TABLE);
+ PTE_SYNC(l2);
+
+ kernel_vm_end = (kernel_vm_end + L2_SIZE) & ~L2_OFFSET;
+ if (kernel_vm_end - 1 >= kernel_map->max_offset) {
+ kernel_vm_end = kernel_map->max_offset;
+ break;
+ }
+ }
+}
+
+
+/***************************************************
+ * page management routines.
+ ***************************************************/
+
+CTASSERT(sizeof(struct pv_chunk) == PAGE_SIZE);
+CTASSERT(_NPCM == 3);
+CTASSERT(_NPCPV == 168);
+
+static __inline struct pv_chunk *
+pv_to_chunk(pv_entry_t pv)
+{
+
+ return ((struct pv_chunk *)((uintptr_t)pv & ~(uintptr_t)PAGE_MASK));
+}
+
+#define PV_PMAP(pv) (pv_to_chunk(pv)->pc_pmap)
+
+#define PC_FREE0 0xfffffffffffffffful
+#define PC_FREE1 0xfffffffffffffffful
+#define PC_FREE2 0x000000fffffffffful
+
+static const uint64_t pc_freemask[_NPCM] = { PC_FREE0, PC_FREE1, PC_FREE2 };
+
+#if 0
+#ifdef PV_STATS
+static int pc_chunk_count, pc_chunk_allocs, pc_chunk_frees, pc_chunk_tryfail;
+
+SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_count, CTLFLAG_RD, &pc_chunk_count, 0,
+ "Current number of pv entry chunks");
+SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_allocs, CTLFLAG_RD, &pc_chunk_allocs, 0,
+ "Current number of pv entry chunks allocated");
+SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_frees, CTLFLAG_RD, &pc_chunk_frees, 0,
+ "Current number of pv entry chunks frees");
+SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_tryfail, CTLFLAG_RD, &pc_chunk_tryfail, 0,
+ "Number of times tried to get a chunk page but failed.");
+
+static long pv_entry_frees, pv_entry_allocs, pv_entry_count;
+static int pv_entry_spare;
+
+SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_frees, CTLFLAG_RD, &pv_entry_frees, 0,
+ "Current number of pv entry frees");
+SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_allocs, CTLFLAG_RD, &pv_entry_allocs, 0,
+ "Current number of pv entry allocs");
+SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_count, CTLFLAG_RD, &pv_entry_count, 0,
+ "Current number of pv entries");
+SYSCTL_INT(_vm_pmap, OID_AUTO, pv_entry_spare, CTLFLAG_RD, &pv_entry_spare, 0,
+ "Current number of spare pv entries");
+#endif
+#endif /* 0 */
+
+/*
+ * We are in a serious low memory condition. Resort to
+ * drastic measures to free some pages so we can allocate
+ * another pv entry chunk.
+ *
+ * Returns NULL if PV entries were reclaimed from the specified pmap.
+ *
+ * We do not, however, unmap 2mpages because subsequent accesses will
+ * allocate per-page pv entries until repromotion occurs, thereby
+ * exacerbating the shortage of free pv entries.
+ */
+static vm_page_t
+reclaim_pv_chunk(pmap_t locked_pmap, struct rwlock **lockp)
+{
+
+ panic("reclaim_pv_chunk");
+}
+
+/*
+ * free the pv_entry back to the free list
+ */
+static void
+free_pv_entry(pmap_t pmap, pv_entry_t pv)
+{
+ struct pv_chunk *pc;
+ int idx, field, bit;
+
+ rw_assert(&pvh_global_lock, RA_LOCKED);
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ PV_STAT(atomic_add_long(&pv_entry_frees, 1));
+ PV_STAT(atomic_add_int(&pv_entry_spare, 1));
+ PV_STAT(atomic_subtract_long(&pv_entry_count, 1));
+ pc = pv_to_chunk(pv);
+ idx = pv - &pc->pc_pventry[0];
+ field = idx / 64;
+ bit = idx % 64;
+ pc->pc_map[field] |= 1ul << bit;
+ if (pc->pc_map[0] != PC_FREE0 || pc->pc_map[1] != PC_FREE1 ||
+ pc->pc_map[2] != PC_FREE2) {
+ /* 98% of the time, pc is already at the head of the list. */
+ if (__predict_false(pc != TAILQ_FIRST(&pmap->pm_pvchunk))) {
+ TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
+ TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list);
+ }
+ return;
+ }
+ TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
+ free_pv_chunk(pc);
+}
+
+static void
+free_pv_chunk(struct pv_chunk *pc)
+{
+ vm_page_t m;
+
+ mtx_lock(&pv_chunks_mutex);
+ TAILQ_REMOVE(&pv_chunks, pc, pc_lru);
+ mtx_unlock(&pv_chunks_mutex);
+ PV_STAT(atomic_subtract_int(&pv_entry_spare, _NPCPV));
+ PV_STAT(atomic_subtract_int(&pc_chunk_count, 1));
+ PV_STAT(atomic_add_int(&pc_chunk_frees, 1));
+ /* entire chunk is free, return it */
+ m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pc));
+#if 0 /* TODO: For minidump */
+ dump_drop_page(m->phys_addr);
+#endif
+ vm_page_unwire(m, PQ_INACTIVE);
+ vm_page_free(m);
+}
+
+/*
+ * Returns a new PV entry, allocating a new PV chunk from the system when
+ * needed. If this PV chunk allocation fails and a PV list lock pointer was
+ * given, a PV chunk is reclaimed from an arbitrary pmap. Otherwise, NULL is
+ * returned.
+ *
+ * The given PV list lock may be released.
+ */
+static pv_entry_t
+get_pv_entry(pmap_t pmap, struct rwlock **lockp)
+{
+ int bit, field;
+ pv_entry_t pv;
+ struct pv_chunk *pc;
+ vm_page_t m;
+
+ rw_assert(&pvh_global_lock, RA_LOCKED);
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ PV_STAT(atomic_add_long(&pv_entry_allocs, 1));
+retry:
+ pc = TAILQ_FIRST(&pmap->pm_pvchunk);
+ if (pc != NULL) {
+ for (field = 0; field < _NPCM; field++) {
+ if (pc->pc_map[field]) {
+ bit = ffsl(pc->pc_map[field]) - 1;
+ break;
+ }
+ }
+ if (field < _NPCM) {
+ pv = &pc->pc_pventry[field * 64 + bit];
+ pc->pc_map[field] &= ~(1ul << bit);
+ /* If this was the last item, move it to tail */
+ if (pc->pc_map[0] == 0 && pc->pc_map[1] == 0 &&
+ pc->pc_map[2] == 0) {
+ TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
+ TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc,
+ pc_list);
+ }
+ PV_STAT(atomic_add_long(&pv_entry_count, 1));
+ PV_STAT(atomic_subtract_int(&pv_entry_spare, 1));
+ return (pv);
+ }
+ }
+ /* No free items, allocate another chunk */
+ m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ |
+ VM_ALLOC_WIRED);
+ if (m == NULL) {
+ if (lockp == NULL) {
+ PV_STAT(pc_chunk_tryfail++);
+ return (NULL);
+ }
+ m = reclaim_pv_chunk(pmap, lockp);
+ if (m == NULL)
+ goto retry;
+ }
+ PV_STAT(atomic_add_int(&pc_chunk_count, 1));
+ PV_STAT(atomic_add_int(&pc_chunk_allocs, 1));
+#if 0 /* TODO: This is for minidump */
+ dump_add_page(m->phys_addr);
+#endif
+ pc = (void *)PHYS_TO_DMAP(m->phys_addr);
+ pc->pc_pmap = pmap;
+ pc->pc_map[0] = PC_FREE0 & ~1ul; /* preallocated bit 0 */
+ pc->pc_map[1] = PC_FREE1;
+ pc->pc_map[2] = PC_FREE2;
+ mtx_lock(&pv_chunks_mutex);
+ TAILQ_INSERT_TAIL(&pv_chunks, pc, pc_lru);
+ mtx_unlock(&pv_chunks_mutex);
+ pv = &pc->pc_pventry[0];
+ TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list);
+ PV_STAT(atomic_add_long(&pv_entry_count, 1));
+ PV_STAT(atomic_add_int(&pv_entry_spare, _NPCPV - 1));
+ return (pv);
+}
+
+/*
+ * First find and then remove the pv entry for the specified pmap and virtual
+ * address from the specified pv list. Returns the pv entry if found and NULL
+ * otherwise. This operation can be performed on pv lists for either 4KB or
+ * 2MB page mappings.
+ */
+static __inline pv_entry_t
+pmap_pvh_remove(struct md_page *pvh, pmap_t pmap, vm_offset_t va)
+{
+ pv_entry_t pv;
+
+ rw_assert(&pvh_global_lock, RA_LOCKED);
+ TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) {
+ if (pmap == PV_PMAP(pv) && va == pv->pv_va) {
+ TAILQ_REMOVE(&pvh->pv_list, pv, pv_next);
+ pvh->pv_gen++;
+ break;
+ }
+ }
+ return (pv);
+}
+
+/*
+ * First find and then destroy the pv entry for the specified pmap and virtual
+ * address. This operation can be performed on pv lists for either 4KB or 2MB
+ * page mappings.
+ */
+static void
+pmap_pvh_free(struct md_page *pvh, pmap_t pmap, vm_offset_t va)
+{
+ pv_entry_t pv;
+
+ pv = pmap_pvh_remove(pvh, pmap, va);
+ KASSERT(pv != NULL, ("pmap_pvh_free: pv not found"));
+ free_pv_entry(pmap, pv);
+}
+
+/*
+ * Conditionally create the PV entry for a 4KB page mapping if the required
+ * memory can be allocated without resorting to reclamation.
+ */
+static boolean_t
+pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m,
+ struct rwlock **lockp)
+{
+ pv_entry_t pv;
+
+ rw_assert(&pvh_global_lock, RA_LOCKED);
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ /* Pass NULL instead of the lock pointer to disable reclamation. */
+ if ((pv = get_pv_entry(pmap, NULL)) != NULL) {
+ pv->pv_va = va;
+ CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m);
+ TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next);
+ m->md.pv_gen++;
+ return (TRUE);
+ } else
+ return (FALSE);
+}
+
+/*
+ * pmap_remove_l3: do the things to unmap a page in a process
+ */
+static int
+pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va,
+ pd_entry_t l2e, struct spglist *free, struct rwlock **lockp)
+{
+ pt_entry_t old_l3;
+ vm_page_t m;
+
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ if (pmap_is_current(pmap) && pmap_l3_valid_cacheable(pmap_load(l3)))
+ cpu_dcache_wb_range(va, L3_SIZE);
+ old_l3 = pmap_load_clear(l3);
+ PTE_SYNC(l3);
+ if (old_l3 & ATTR_SW_WIRED)
+ pmap->pm_stats.wired_count -= 1;
+ pmap_resident_count_dec(pmap, 1);
+ if (old_l3 & ATTR_SW_MANAGED) {
+ m = PHYS_TO_VM_PAGE(old_l3 & ~ATTR_MASK);
+ if (pmap_page_dirty(old_l3))
+ vm_page_dirty(m);
+ if (old_l3 & ATTR_AF)
+ vm_page_aflag_set(m, PGA_REFERENCED);
+ CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m);
+ pmap_pvh_free(&m->md, pmap, va);
+ }
+ return (pmap_unuse_l3(pmap, va, l2e, free));
+}
+
+/*
+ * Remove the given range of addresses from the specified map.
+ *
+ * It is assumed that the start and end are properly
+ * rounded to the page size.
+ */
+void
+pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
+{
+ struct rwlock *lock;
+ vm_offset_t va, va_next;
+ pd_entry_t *l1, *l2;
+ pt_entry_t l3_paddr, *l3;
+ struct spglist free;
+ int anyvalid;
+
+ /*
+ * Perform an unsynchronized read. This is, however, safe.
+ */
+ if (pmap->pm_stats.resident_count == 0)
+ return;
+
+ anyvalid = 0;
+ SLIST_INIT(&free);
+
+ rw_rlock(&pvh_global_lock);
+ PMAP_LOCK(pmap);
+
+ lock = NULL;
+ for (; sva < eva; sva = va_next) {
+
+ if (pmap->pm_stats.resident_count == 0)
+ break;
+
+ l1 = pmap_l1(pmap, sva);
+ if (*l1 == 0) {
+ va_next = (sva + L1_SIZE) & ~L1_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+ continue;
+ }
+
+ /*
+ * Calculate index for next page table.
+ */
+ va_next = (sva + L2_SIZE) & ~L2_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+
+ l2 = pmap_l1_to_l2(l1, sva);
+ if (l2 == NULL)
+ continue;
+
+ l3_paddr = *l2;
+
+ /*
+ * Weed out invalid mappings.
+ */
+ if ((l3_paddr & ATTR_DESCR_MASK) != L2_TABLE)
+ continue;
+
+ /*
+ * Limit our scan to either the end of the va represented
+ * by the current page table page, or to the end of the
+ * range being removed.
+ */
+ if (va_next > eva)
+ va_next = eva;
+
+ va = va_next;
+ for (l3 = pmap_l2_to_l3(l2, sva); sva != va_next; l3++,
+ sva += L3_SIZE) {
+ if (l3 == NULL)
+ panic("l3 == NULL");
+ if (*l3 == 0) {
+ if (va != va_next) {
+ pmap_invalidate_range(pmap, va, sva);
+ va = va_next;
+ }
+ continue;
+ }
+ if (va == va_next)
+ va = sva;
+ if (pmap_remove_l3(pmap, l3, sva, l3_paddr, &free,
+ &lock)) {
+ sva += L3_SIZE;
+ break;
+ }
+ }
+ if (va != va_next)
+ pmap_invalidate_range(pmap, va, sva);
+ }
+ if (lock != NULL)
+ rw_wunlock(lock);
+ if (anyvalid)
+ pmap_invalidate_all(pmap);
+ rw_runlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
+ pmap_free_zero_pages(&free);
+}
+
+/*
+ * Routine: pmap_remove_all
+ * Function:
+ * Removes this physical page from
+ * all physical maps in which it resides.
+ * Reflects back modify bits to the pager.
+ *
+ * Notes:
+ * Original versions of this routine were very
+ * inefficient because they iteratively called
+ * pmap_remove (slow...)
+ */
+
+void
+pmap_remove_all(vm_page_t m)
+{
+ pv_entry_t pv;
+ pmap_t pmap;
+ pt_entry_t *l3, tl3;
+ pd_entry_t *l2;
+ struct spglist free;
+
+ KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+ ("pmap_remove_all: page %p is not managed", m));
+ SLIST_INIT(&free);
+ rw_wlock(&pvh_global_lock);
+ while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) {
+ pmap = PV_PMAP(pv);
+ PMAP_LOCK(pmap);
+ pmap_resident_count_dec(pmap, 1);
+ l2 = pmap_l2(pmap, pv->pv_va);
+ KASSERT((*l2 & ATTR_DESCR_MASK) == L2_TABLE,
+ ("pmap_remove_all: found a table when expecting "
+ "a block in %p's pv list", m));
+ l3 = pmap_l2_to_l3(l2, pv->pv_va);
+ if (pmap_is_current(pmap) &&
+ pmap_l3_valid_cacheable(pmap_load(l3)))
+ cpu_dcache_wb_range(pv->pv_va, L3_SIZE);
+ tl3 = pmap_load_clear(l3);
+ PTE_SYNC(l3);
+ if (tl3 & ATTR_SW_WIRED)
+ pmap->pm_stats.wired_count--;
+ if ((tl3 & ATTR_AF) != 0)
+ vm_page_aflag_set(m, PGA_REFERENCED);
+
+ /*
+ * Update the vm_page_t clean and reference bits.
+ */
+ if (pmap_page_dirty(tl3))
+ vm_page_dirty(m);
+ pmap_unuse_l3(pmap, pv->pv_va, *l2, &free);
+ pmap_invalidate_page(pmap, pv->pv_va);
+ TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
+ m->md.pv_gen++;
+ free_pv_entry(pmap, pv);
+ PMAP_UNLOCK(pmap);
+ }
+ vm_page_aflag_clear(m, PGA_WRITEABLE);
+ rw_wunlock(&pvh_global_lock);
+ pmap_free_zero_pages(&free);
+}
+
+/*
+ * Set the physical protection on the
+ * specified range of this map as requested.
+ */
+void
+pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
+{
+ vm_offset_t va, va_next;
+ pd_entry_t *l1, *l2;
+ pt_entry_t *l3p, l3;
+
+ if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
+ pmap_remove(pmap, sva, eva);
+ return;
+ }
+
+ if ((prot & VM_PROT_WRITE) == VM_PROT_WRITE)
+ return;
+
+ PMAP_LOCK(pmap);
+ for (; sva < eva; sva = va_next) {
+
+ l1 = pmap_l1(pmap, sva);
+ if (*l1 == 0) {
+ va_next = (sva + L1_SIZE) & ~L1_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+ continue;
+ }
+
+ va_next = (sva + L2_SIZE) & ~L2_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+
+ l2 = pmap_l1_to_l2(l1, sva);
+ if (l2 == NULL || (*l2 & ATTR_DESCR_MASK) != L2_TABLE)
+ continue;
+
+ if (va_next > eva)
+ va_next = eva;
+
+ va = va_next;
+ for (l3p = pmap_l2_to_l3(l2, sva); sva != va_next; l3p++,
+ sva += L3_SIZE) {
+ l3 = pmap_load(l3p);
+ if (pmap_l3_valid(l3)) {
+ pmap_set(l3p, ATTR_AP(ATTR_AP_RO));
+ PTE_SYNC(l3p);
+ }
+ }
+ }
+ PMAP_UNLOCK(pmap);
+
+ /* TODO: Only invalidate entries we are touching */
+ pmap_invalidate_all(pmap);
+}
+
+/*
+ * Insert the given physical page (p) at
+ * the specified virtual address (v) in the
+ * target physical map with the protection requested.
+ *
+ * If specified, the page will be wired down, meaning
+ * that the related pte can not be reclaimed.
+ *
+ * NB: This is the only routine which MAY NOT lazy-evaluate
+ * or lose information. That is, this routine must actually
+ * insert this page into the given map NOW.
+ */
+int
+pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
+ u_int flags, int8_t psind __unused)
+{
+ struct rwlock *lock;
+ pd_entry_t *l1, *l2;
+ pt_entry_t new_l3, orig_l3;
+ pt_entry_t *l3;
+ pv_entry_t pv;
+ vm_paddr_t opa, pa, l2_pa, l3_pa;
+ vm_page_t mpte, om, l2_m, l3_m;
+ boolean_t nosleep;
+
+ va = trunc_page(va);
+ if ((m->oflags & VPO_UNMANAGED) == 0 && !vm_page_xbusied(m))
+ VM_OBJECT_ASSERT_LOCKED(m->object);
+ pa = VM_PAGE_TO_PHYS(m);
+ new_l3 = (pt_entry_t)(pa | ATTR_AF | L3_PAGE);
+ if ((prot & VM_PROT_WRITE) == 0)
+ new_l3 |= ATTR_AP(ATTR_AP_RO);
+ if ((flags & PMAP_ENTER_WIRED) != 0)
+ new_l3 |= ATTR_SW_WIRED;
+ if ((va >> 63) == 0)
+ new_l3 |= ATTR_AP(ATTR_AP_USER);
+ new_l3 |= ATTR_IDX(m->md.pv_memattr);
+
+ mpte = NULL;
+
+ lock = NULL;
+ rw_rlock(&pvh_global_lock);
+ PMAP_LOCK(pmap);
+
+ if (va < VM_MAXUSER_ADDRESS) {
+ nosleep = (flags & PMAP_ENTER_NOSLEEP) != 0;
+ mpte = pmap_alloc_l3(pmap, va, nosleep ? NULL : &lock);
+ if (mpte == NULL && nosleep) {
+ if (lock != NULL)
+ rw_wunlock(lock);
+ rw_runlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
+ return (KERN_RESOURCE_SHORTAGE);
+ }
+ l3 = pmap_l3(pmap, va);
+ } else {
+ l3 = pmap_l3(pmap, va);
+ /* TODO: This is not optimal, but should mostly work */
+ if (l3 == NULL) {
+ l2 = pmap_l2(pmap, va);
+
+ if (l2 == NULL) {
+ l2_m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
+ VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
+ VM_ALLOC_ZERO);
+ if (l2_m == NULL)
+ panic("pmap_enter: l2 pte_m == NULL");
+ if ((l2_m->flags & PG_ZERO) == 0)
+ pmap_zero_page(l2_m);
+
+ l2_pa = VM_PAGE_TO_PHYS(l2_m);
+ l1 = pmap_l1(pmap, va);
+ pmap_load_store(l1, l2_pa | L1_TABLE);
+ PTE_SYNC(l1);
+ l2 = pmap_l1_to_l2(l1, va);
+ }
+
+ KASSERT(l2 != NULL,
+ ("No l2 table after allocating one"));
+
+ l3_m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
+ VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO);
+ if (l3_m == NULL)
+ panic("pmap_enter: l3 pte_m == NULL");
+ if ((l3_m->flags & PG_ZERO) == 0)
+ pmap_zero_page(l3_m);
+
+ l3_pa = VM_PAGE_TO_PHYS(l3_m);
+ pmap_load_store(l2, l3_pa | L2_TABLE);
+ PTE_SYNC(l2);
+ l3 = pmap_l2_to_l3(l2, va);
+ }
+ }
+
+ om = NULL;
+ orig_l3 = pmap_load(l3);
+ opa = orig_l3 & ~ATTR_MASK;
+
+ /*
+ * Is the specified virtual address already mapped?
+ */
+ if (pmap_l3_valid(orig_l3)) {
+ /*
+ * Wiring change, just update stats. We don't worry about
+ * wiring PT pages as they remain resident as long as there
+ * are valid mappings in them. Hence, if a user page is wired,
+ * the PT page will be also.
+ */
+ if ((flags & PMAP_ENTER_WIRED) != 0 &&
+ (orig_l3 & ATTR_SW_WIRED) == 0)
+ pmap->pm_stats.wired_count++;
+ else if ((flags & PMAP_ENTER_WIRED) == 0 &&
+ (orig_l3 & ATTR_SW_WIRED) != 0)
+ pmap->pm_stats.wired_count--;
+
+ /*
+ * Remove the extra PT page reference.
+ */
+ if (mpte != NULL) {
+ mpte->wire_count--;
+ KASSERT(mpte->wire_count > 0,
+ ("pmap_enter: missing reference to page table page,"
+ " va: 0x%lx", va));
+ }
+
+ /*
+ * Has the physical page changed?
+ */
+ if (opa == pa) {
+ /*
+ * No, might be a protection or wiring change.
+ */
+ if ((orig_l3 & ATTR_SW_MANAGED) != 0) {
+ new_l3 |= ATTR_SW_MANAGED;
+ if ((new_l3 & ATTR_AP(ATTR_AP_RW)) ==
+ ATTR_AP(ATTR_AP_RW)) {
+ vm_page_aflag_set(m, PGA_WRITEABLE);
+ }
+ }
+ goto validate;
+ }
+
+ /* Flush the cache, there might be uncommitted data in it */
+ if (pmap_is_current(pmap) && pmap_l3_valid_cacheable(orig_l3))
+ cpu_dcache_wb_range(va, L3_SIZE);
+ } else {
+ /*
+ * Increment the counters.
+ */
+ if ((new_l3 & ATTR_SW_WIRED) != 0)
+ pmap->pm_stats.wired_count++;
+ pmap_resident_count_inc(pmap, 1);
+ }
+ /*
+ * Enter on the PV list if part of our managed memory.
+ */
+ if ((m->oflags & VPO_UNMANAGED) == 0) {
+ new_l3 |= ATTR_SW_MANAGED;
+ pv = get_pv_entry(pmap, &lock);
+ pv->pv_va = va;
+ CHANGE_PV_LIST_LOCK_TO_PHYS(&lock, pa);
+ TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next);
+ m->md.pv_gen++;
+ if ((new_l3 & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW))
+ vm_page_aflag_set(m, PGA_WRITEABLE);
+ }
+
+ /*
+ * Update the L3 entry.
+ */
+ if (orig_l3 != 0) {
+validate:
+ orig_l3 = pmap_load_store(l3, new_l3);
+ PTE_SYNC(l3);
+ opa = orig_l3 & ~ATTR_MASK;
+
+ if (opa != pa) {
+ if ((orig_l3 & ATTR_SW_MANAGED) != 0) {
+ om = PHYS_TO_VM_PAGE(opa);
+ if (pmap_page_dirty(orig_l3))
+ vm_page_dirty(om);
+ if ((orig_l3 & ATTR_AF) != 0)
+ vm_page_aflag_set(om, PGA_REFERENCED);
+ CHANGE_PV_LIST_LOCK_TO_PHYS(&lock, opa);
+ pmap_pvh_free(&om->md, pmap, va);
+ }
+ } else if (pmap_page_dirty(orig_l3)) {
+ if ((orig_l3 & ATTR_SW_MANAGED) != 0)
+ vm_page_dirty(m);
+ }
+ if ((orig_l3 & ATTR_AF) != 0)
+ pmap_invalidate_page(pmap, va);
+ } else {
+ pmap_load_store(l3, new_l3);
+ PTE_SYNC(l3);
+ }
+ if ((pmap != pmap_kernel()) && (pmap == &curproc->p_vmspace->vm_pmap))
+ cpu_icache_sync_range(va, PAGE_SIZE);
+
+ if (lock != NULL)
+ rw_wunlock(lock);
+ rw_runlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
+ return (KERN_SUCCESS);
+}
+
+/*
+ * Maps a sequence of resident pages belonging to the same object.
+ * The sequence begins with the given page m_start. This page is
+ * mapped at the given virtual address start. Each subsequent page is
+ * mapped at a virtual address that is offset from start by the same
+ * amount as the page is offset from m_start within the object. The
+ * last page in the sequence is the page with the largest offset from
+ * m_start that can be mapped at a virtual address less than the given
+ * virtual address end. Not every virtual page between start and end
+ * is mapped; only those for which a resident page exists with the
+ * corresponding offset from m_start are mapped.
+ */
+void
+pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end,
+ vm_page_t m_start, vm_prot_t prot)
+{
+ struct rwlock *lock;
+ vm_offset_t va;
+ vm_page_t m, mpte;
+ vm_pindex_t diff, psize;
+
+ VM_OBJECT_ASSERT_LOCKED(m_start->object);
+
+ psize = atop(end - start);
+ mpte = NULL;
+ m = m_start;
+ lock = NULL;
+ rw_rlock(&pvh_global_lock);
+ PMAP_LOCK(pmap);
+ while (m != NULL && (diff = m->pindex - m_start->pindex) < psize) {
+ va = start + ptoa(diff);
+ mpte = pmap_enter_quick_locked(pmap, va, m, prot, mpte, &lock);
+ m = TAILQ_NEXT(m, listq);
+ }
+ if (lock != NULL)
+ rw_wunlock(lock);
+ rw_runlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
+}
+
+/*
+ * this code makes some *MAJOR* assumptions:
+ * 1. Current pmap & pmap exists.
+ * 2. Not wired.
+ * 3. Read access.
+ * 4. No page table pages.
+ * but is *MUCH* faster than pmap_enter...
+ */
+
+void
+pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot)
+{
+ struct rwlock *lock;
+
+ lock = NULL;
+ rw_rlock(&pvh_global_lock);
+ PMAP_LOCK(pmap);
+ (void)pmap_enter_quick_locked(pmap, va, m, prot, NULL, &lock);
+ if (lock != NULL)
+ rw_wunlock(lock);
+ rw_runlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
+}
+
+static vm_page_t
+pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
+ vm_prot_t prot, vm_page_t mpte, struct rwlock **lockp)
+{
+ struct spglist free;
+ pd_entry_t *l2;
+ pt_entry_t *l3;
+ vm_paddr_t pa;
+
+ KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva ||
+ (m->oflags & VPO_UNMANAGED) != 0,
+ ("pmap_enter_quick_locked: managed mapping within the clean submap"));
+ rw_assert(&pvh_global_lock, RA_LOCKED);
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+
+ /*
+ * In the case that a page table page is not
+ * resident, we are creating it here.
+ */
+ if (va < VM_MAXUSER_ADDRESS) {
+ vm_pindex_t l2pindex;
+
+ /*
+ * Calculate pagetable page index
+ */
+ l2pindex = pmap_l2_pindex(va);
+ if (mpte && (mpte->pindex == l2pindex)) {
+ mpte->wire_count++;
+ } else {
+ /*
+ * Get the l2 entry
+ */
+ l2 = pmap_l2(pmap, va);
+
+ /*
+ * If the page table page is mapped, we just increment
+ * the hold count, and activate it. Otherwise, we
+ * attempt to allocate a page table page. If this
+ * attempt fails, we don't retry. Instead, we give up.
+ */
+ if (l2 != NULL && *l2 != 0) {
+ mpte = PHYS_TO_VM_PAGE(*l2 & ~ATTR_MASK);
+ mpte->wire_count++;
+ } else {
+ /*
+ * Pass NULL instead of the PV list lock
+ * pointer, because we don't intend to sleep.
+ */
+ mpte = _pmap_alloc_l3(pmap, l2pindex, NULL);
+ if (mpte == NULL)
+ return (mpte);
+ }
+ }
+ l3 = (pt_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(mpte));
+ l3 = &l3[pmap_l3_index(va)];
+ } else {
+ mpte = NULL;
+ l3 = pmap_l3(kernel_pmap, va);
+ }
+ if (l3 == NULL)
+ panic("pmap_enter_quick_locked: No l3");
+ if (*l3) {
+ if (mpte != NULL) {
+ mpte->wire_count--;
+ mpte = NULL;
+ }
+ return (mpte);
+ }
+
+ /*
+ * Enter on the PV list if part of our managed memory.
+ */
+ if ((m->oflags & VPO_UNMANAGED) == 0 &&
+ !pmap_try_insert_pv_entry(pmap, va, m, lockp)) {
+ if (mpte != NULL) {
+ SLIST_INIT(&free);
+ if (pmap_unwire_l3(pmap, va, mpte, &free)) {
+ pmap_invalidate_page(pmap, va);
+ pmap_free_zero_pages(&free);
+ }
+ mpte = NULL;
+ }
+ return (mpte);
+ }
+
+ /*
+ * Increment counters
+ */
+ pmap_resident_count_inc(pmap, 1);
+
+ pa = VM_PAGE_TO_PHYS(m) | ATTR_AF | ATTR_IDX(m->md.pv_memattr) |
+ ATTR_AP(ATTR_AP_RW) | L3_PAGE;
+
+ /*
+ * Now validate mapping with RO protection
+ */
+ if ((m->oflags & VPO_UNMANAGED) == 0)
+ pa |= ATTR_SW_MANAGED;
+ pmap_load_store(l3, pa);
+ PTE_SYNC(l3);
+ pmap_invalidate_page(pmap, va);
+ return (mpte);
+}
+
+/*
+ * This code maps large physical mmap regions into the
+ * processor address space. Note that some shortcuts
+ * are taken, but the code works.
+ */
+void
+pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_object_t object,
+ vm_pindex_t pindex, vm_size_t size)
+{
+
+ VM_OBJECT_ASSERT_WLOCKED(object);
+ KASSERT(object->type == OBJT_DEVICE || object->type == OBJT_SG,
+ ("pmap_object_init_pt: non-device object"));
+}
+
+/*
+ * Clear the wired attribute from the mappings for the specified range of
+ * addresses in the given pmap. Every valid mapping within that range
+ * must have the wired attribute set. In contrast, invalid mappings
+ * cannot have the wired attribute set, so they are ignored.
+ *
+ * The wired attribute of the page table entry is not a hardware feature,
+ * so there is no need to invalidate any TLB entries.
+ */
+void
+pmap_unwire(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
+{
+ vm_offset_t va_next;
+ pd_entry_t *l1, *l2;
+ pt_entry_t *l3;
+ boolean_t pv_lists_locked;
+
+ pv_lists_locked = FALSE;
+ PMAP_LOCK(pmap);
+ for (; sva < eva; sva = va_next) {
+ l1 = pmap_l1(pmap, sva);
+ if (*l1 == 0) {
+ va_next = (sva + L1_SIZE) & ~L1_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+ continue;
+ }
+
+ va_next = (sva + L2_SIZE) & ~L2_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+
+ l2 = pmap_l1_to_l2(l1, sva);
+ if (*l2 == 0)
+ continue;
+
+ if (va_next > eva)
+ va_next = eva;
+ for (l3 = pmap_l2_to_l3(l2, sva); sva != va_next; l3++,
+ sva += L3_SIZE) {
+ if (*l3 == 0)
+ continue;
+ if ((*l3 & ATTR_SW_WIRED) == 0)
+ panic("pmap_unwire: l3 %#jx is missing "
+ "ATTR_SW_WIRED", (uintmax_t)*l3);
+
+ /*
+ * PG_W must be cleared atomically. Although the pmap
+ * lock synchronizes access to PG_W, another processor
+ * could be setting PG_M and/or PG_A concurrently.
+ */
+ atomic_clear_long(l3, ATTR_SW_WIRED);
+ pmap->pm_stats.wired_count--;
+ }
+ }
+ if (pv_lists_locked)
+ rw_runlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
+}
+
+/*
+ * Copy the range specified by src_addr/len
+ * from the source map to the range dst_addr/len
+ * in the destination map.
+ *
+ * This routine is only advisory and need not do anything.
+ */
+
+void
+pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
+ vm_offset_t src_addr)
+{
+}
+
+/*
+ * pmap_zero_page zeros the specified hardware page by mapping
+ * the page into KVM and using bzero to clear its contents.
+ */
+void
+pmap_zero_page(vm_page_t m)
+{
+ vm_offset_t va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
+
+ pagezero((void *)va);
+}
+
+/*
+ * pmap_zero_page_area zeros the specified hardware page by mapping
+ * the page into KVM and using bzero to clear its contents.
+ *
+ * off and size may not cover an area beyond a single hardware page.
+ */
+void
+pmap_zero_page_area(vm_page_t m, int off, int size)
+{
+ vm_offset_t va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
+
+ if (off == 0 && size == PAGE_SIZE)
+ pagezero((void *)va);
+ else
+ bzero((char *)va + off, size);
+}
+
+/*
+ * pmap_zero_page_idle zeros the specified hardware page by mapping
+ * the page into KVM and using bzero to clear its contents. This
+ * is intended to be called from the vm_pagezero process only and
+ * outside of Giant.
+ */
+void
+pmap_zero_page_idle(vm_page_t m)
+{
+ vm_offset_t va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
+
+ pagezero((void *)va);
+}
+
+/*
+ * pmap_copy_page copies the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bcopy to copy the page, one machine dependent page at a
+ * time.
+ */
+void
+pmap_copy_page(vm_page_t msrc, vm_page_t mdst)
+{
+ vm_offset_t src = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(msrc));
+ vm_offset_t dst = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(mdst));
+
+ pagecopy((void *)src, (void *)dst);
+}
+
+int unmapped_buf_allowed = 1;
+
+void
+pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[],
+ vm_offset_t b_offset, int xfersize)
+{
+ void *a_cp, *b_cp;
+ vm_page_t m_a, m_b;
+ vm_paddr_t p_a, p_b;
+ vm_offset_t a_pg_offset, b_pg_offset;
+ int cnt;
+
+ while (xfersize > 0) {
+ a_pg_offset = a_offset & PAGE_MASK;
+ m_a = ma[a_offset >> PAGE_SHIFT];
+ p_a = m_a->phys_addr;
+ b_pg_offset = b_offset & PAGE_MASK;
+ m_b = mb[b_offset >> PAGE_SHIFT];
+ p_b = m_b->phys_addr;
+ cnt = min(xfersize, PAGE_SIZE - a_pg_offset);
+ cnt = min(cnt, PAGE_SIZE - b_pg_offset);
+ if (__predict_false(!PHYS_IN_DMAP(p_a))) {
+ panic("!DMAP a %lx", p_a);
+ } else {
+ a_cp = (char *)PHYS_TO_DMAP(p_a) + a_pg_offset;
+ }
+ if (__predict_false(!PHYS_IN_DMAP(p_b))) {
+ panic("!DMAP b %lx", p_b);
+ } else {
+ b_cp = (char *)PHYS_TO_DMAP(p_b) + b_pg_offset;
+ }
+ bcopy(a_cp, b_cp, cnt);
+ a_offset += cnt;
+ b_offset += cnt;
+ xfersize -= cnt;
+ }
+}
+
+/*
+ * Returns true if the pmap's pv is one of the first
+ * 16 pvs linked to from this page. This count may
+ * be changed upwards or downwards in the future; it
+ * is only necessary that true be returned for a small
+ * subset of pmaps for proper page aging.
+ */
+boolean_t
+pmap_page_exists_quick(pmap_t pmap, vm_page_t m)
+{
+ struct rwlock *lock;
+ pv_entry_t pv;
+ int loops = 0;
+ boolean_t rv;
+
+ KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+ ("pmap_page_exists_quick: page %p is not managed", m));
+ rv = FALSE;
+ rw_rlock(&pvh_global_lock);
+ lock = VM_PAGE_TO_PV_LIST_LOCK(m);
+ rw_rlock(lock);
+ TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
+ if (PV_PMAP(pv) == pmap) {
+ rv = TRUE;
+ break;
+ }
+ loops++;
+ if (loops >= 16)
+ break;
+ }
+ rw_runlock(lock);
+ rw_runlock(&pvh_global_lock);
+ return (rv);
+}
+
+/*
+ * pmap_page_wired_mappings:
+ *
+ * Return the number of managed mappings to the given physical page
+ * that are wired.
+ */
+int
+pmap_page_wired_mappings(vm_page_t m)
+{
+ struct rwlock *lock;
+ pmap_t pmap;
+ pt_entry_t *l3;
+ pv_entry_t pv;
+ int count, md_gen;
+
+ if ((m->oflags & VPO_UNMANAGED) != 0)
+ return (0);
+ rw_rlock(&pvh_global_lock);
+ lock = VM_PAGE_TO_PV_LIST_LOCK(m);
+ rw_rlock(lock);
+restart:
+ count = 0;
+ TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
+ pmap = PV_PMAP(pv);
+ if (!PMAP_TRYLOCK(pmap)) {
+ md_gen = m->md.pv_gen;
+ rw_runlock(lock);
+ PMAP_LOCK(pmap);
+ rw_rlock(lock);
+ if (md_gen != m->md.pv_gen) {
+ PMAP_UNLOCK(pmap);
+ goto restart;
+ }
+ }
+ l3 = pmap_l3(pmap, pv->pv_va);
+ if (l3 != NULL && (*l3 & ATTR_SW_WIRED) != 0)
+ count++;
+ PMAP_UNLOCK(pmap);
+ }
+ rw_runlock(lock);
+ rw_runlock(&pvh_global_lock);
+ return (count);
+}
+
+/*
+ * Destroy all managed, non-wired mappings in the given user-space
+ * pmap. This pmap cannot be active on any processor besides the
+ * caller.
+ *
+ * This function cannot be applied to the kernel pmap. Moreover, it
+ * is not intended for general use. It is only to be used during
+ * process termination. Consequently, it can be implemented in ways
+ * that make it faster than pmap_remove(). First, it can more quickly
+ * destroy mappings by iterating over the pmap's collection of PV
+ * entries, rather than searching the page table. Second, it doesn't
+ * have to test and clear the page table entries atomically, because
+ * no processor is currently accessing the user address space. In
+ * particular, a page table entry's dirty bit won't change state once
+ * this function starts.
+ */
+void
+pmap_remove_pages(pmap_t pmap)
+{
+ pd_entry_t ptepde, *l2;
+ pt_entry_t *l3, tl3;
+ struct spglist free;
+ vm_page_t m;
+ pv_entry_t pv;
+ struct pv_chunk *pc, *npc;
+ struct rwlock *lock;
+ int64_t bit;
+ uint64_t inuse, bitmask;
+ int allfree, field, freed, idx;
+ vm_paddr_t pa;
+
+ lock = NULL;
+
+ SLIST_INIT(&free);
+ rw_rlock(&pvh_global_lock);
+ PMAP_LOCK(pmap);
+ TAILQ_FOREACH_SAFE(pc, &pmap->pm_pvchunk, pc_list, npc) {
+ allfree = 1;
+ freed = 0;
+ for (field = 0; field < _NPCM; field++) {
+ inuse = ~pc->pc_map[field] & pc_freemask[field];
+ while (inuse != 0) {
+ bit = ffsl(inuse) - 1;
+ bitmask = 1UL << bit;
+ idx = field * 64 + bit;
+ pv = &pc->pc_pventry[idx];
+ inuse &= ~bitmask;
+
+ l2 = pmap_l2(pmap, pv->pv_va);
+ ptepde = pmap_load(l2);
+ l3 = pmap_l2_to_l3(l2, pv->pv_va);
+ tl3 = pmap_load(l3);
+
+/*
+ * We cannot remove wired pages from a process' mapping at this time
+ */
+ if (tl3 & ATTR_SW_WIRED) {
+ allfree = 0;
+ continue;
+ }
+
+ pa = tl3 & ~ATTR_MASK;
+
+ m = PHYS_TO_VM_PAGE(pa);
+ KASSERT(m->phys_addr == pa,
+ ("vm_page_t %p phys_addr mismatch %016jx %016jx",
+ m, (uintmax_t)m->phys_addr,
+ (uintmax_t)tl3));
+
+ KASSERT((m->flags & PG_FICTITIOUS) != 0 ||
+ m < &vm_page_array[vm_page_array_size],
+ ("pmap_remove_pages: bad l3 %#jx",
+ (uintmax_t)tl3));
+
+ if (pmap_is_current(pmap) &&
+ pmap_l3_valid_cacheable(pmap_load(l3)))
+ cpu_dcache_wb_range(pv->pv_va, L3_SIZE);
+ pmap_load_clear(l3);
+ PTE_SYNC(l3);
+
+ /*
+ * Update the vm_page_t clean/reference bits.
+ */
+ if ((tl3 & ATTR_AP_RW_BIT) ==
+ ATTR_AP(ATTR_AP_RW))
+ vm_page_dirty(m);
+
+ CHANGE_PV_LIST_LOCK_TO_VM_PAGE(&lock, m);
+
+ /* Mark free */
+ pc->pc_map[field] |= bitmask;
+
+ pmap_resident_count_dec(pmap, 1);
+ TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
+ m->md.pv_gen++;
+
+ pmap_unuse_l3(pmap, pv->pv_va, ptepde, &free);
+ freed++;
+ }
+ }
+ PV_STAT(atomic_add_long(&pv_entry_frees, freed));
+ PV_STAT(atomic_add_int(&pv_entry_spare, freed));
+ PV_STAT(atomic_subtract_long(&pv_entry_count, freed));
+ if (allfree) {
+ TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
+ free_pv_chunk(pc);
+ }
+ }
+ pmap_invalidate_all(pmap);
+ if (lock != NULL)
+ rw_wunlock(lock);
+ rw_runlock(&pvh_global_lock);
+ PMAP_UNLOCK(pmap);
+ pmap_free_zero_pages(&free);
+}
+
+/*
+ * This is used to check if a page has been accessed or modified. As we
+ * don't have a bit to see if it has been modified we have to assume it
+ * has been if the page is read/write.
+ */
+static boolean_t
+pmap_page_test_mappings(vm_page_t m, boolean_t accessed, boolean_t modified)
+{
+ struct rwlock *lock;
+ pv_entry_t pv;
+ pt_entry_t *l3, mask, value;
+ pmap_t pmap;
+ int md_gen;
+ boolean_t rv;
+
+ rv = FALSE;
+ rw_rlock(&pvh_global_lock);
+ lock = VM_PAGE_TO_PV_LIST_LOCK(m);
+ rw_rlock(lock);
+restart:
+ TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
+ pmap = PV_PMAP(pv);
+ if (!PMAP_TRYLOCK(pmap)) {
+ md_gen = m->md.pv_gen;
+ rw_runlock(lock);
+ PMAP_LOCK(pmap);
+ rw_rlock(lock);
+ if (md_gen != m->md.pv_gen) {
+ PMAP_UNLOCK(pmap);
+ goto restart;
+ }
+ }
+ l3 = pmap_l3(pmap, pv->pv_va);
+ mask = 0;
+ value = 0;
+ if (modified) {
+ mask |= ATTR_AP_RW_BIT;
+ value |= ATTR_AP(ATTR_AP_RW);
+ }
+ if (accessed) {
+ mask |= ATTR_AF | ATTR_DESCR_MASK;
+ value |= ATTR_AF | L3_PAGE;
+ }
+ rv = (pmap_load(l3) & mask) == value;
+ PMAP_UNLOCK(pmap);
+ if (rv)
+ goto out;
+ }
+out:
+ rw_runlock(lock);
+ rw_runlock(&pvh_global_lock);
+ return (rv);
+}
+
+/*
+ * pmap_is_modified:
+ *
+ * Return whether or not the specified physical page was modified
+ * in any physical maps.
+ */
+boolean_t
+pmap_is_modified(vm_page_t m)
+{
+
+ KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+ ("pmap_is_modified: page %p is not managed", m));
+
+ /*
+ * If the page is not exclusive busied, then PGA_WRITEABLE cannot be
+ * concurrently set while the object is locked. Thus, if PGA_WRITEABLE
+ * is clear, no PTEs can have PG_M set.
+ */
+ VM_OBJECT_ASSERT_WLOCKED(m->object);
+ if (!vm_page_xbusied(m) && (m->aflags & PGA_WRITEABLE) == 0)
+ return (FALSE);
+ return (pmap_page_test_mappings(m, FALSE, TRUE));
+}
+
+/*
+ * pmap_is_prefaultable:
+ *
+ * Return whether or not the specified virtual address is eligible
+ * for prefault.
+ */
+boolean_t
+pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr)
+{
+ pt_entry_t *l3;
+ boolean_t rv;
+
+ rv = FALSE;
+ PMAP_LOCK(pmap);
+ l3 = pmap_l3(pmap, addr);
+ if (l3 != NULL && *l3 != 0) {
+ rv = TRUE;
+ }
+ PMAP_UNLOCK(pmap);
+ return (rv);
+}
+
+/*
+ * pmap_is_referenced:
+ *
+ * Return whether or not the specified physical page was referenced
+ * in any physical maps.
+ */
+boolean_t
+pmap_is_referenced(vm_page_t m)
+{
+
+ KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+ ("pmap_is_referenced: page %p is not managed", m));
+ return (pmap_page_test_mappings(m, TRUE, FALSE));
+}
+
+/*
+ * Clear the write and modified bits in each of the given page's mappings.
+ */
+void
+pmap_remove_write(vm_page_t m)
+{
+ pmap_t pmap;
+ struct rwlock *lock;
+ pv_entry_t pv;
+ pt_entry_t *l3, oldl3;
+ int md_gen;
+
+ KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+ ("pmap_remove_write: page %p is not managed", m));
+
+ /*
+ * If the page is not exclusive busied, then PGA_WRITEABLE cannot be
+ * set by another thread while the object is locked. Thus,
+ * if PGA_WRITEABLE is clear, no page table entries need updating.
+ */
+ VM_OBJECT_ASSERT_WLOCKED(m->object);
+ if (!vm_page_xbusied(m) && (m->aflags & PGA_WRITEABLE) == 0)
+ return;
+ rw_rlock(&pvh_global_lock);
+ lock = VM_PAGE_TO_PV_LIST_LOCK(m);
+retry_pv_loop:
+ rw_wlock(lock);
+ TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
+ pmap = PV_PMAP(pv);
+ if (!PMAP_TRYLOCK(pmap)) {
+ md_gen = m->md.pv_gen;
+ rw_wunlock(lock);
+ PMAP_LOCK(pmap);
+ rw_wlock(lock);
+ if (md_gen != m->md.pv_gen) {
+ PMAP_UNLOCK(pmap);
+ rw_wunlock(lock);
+ goto retry_pv_loop;
+ }
+ }
+ l3 = pmap_l3(pmap, pv->pv_va);
+retry:
+ oldl3 = *l3;
+ if ((oldl3 & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW)) {
+ if (!atomic_cmpset_long(l3, oldl3,
+ oldl3 | ATTR_AP(ATTR_AP_RO)))
+ goto retry;
+ if ((oldl3 & ATTR_AF) != 0)
+ vm_page_dirty(m);
+ pmap_invalidate_page(pmap, pv->pv_va);
+ }
+ PMAP_UNLOCK(pmap);
+ }
+ rw_wunlock(lock);
+ vm_page_aflag_clear(m, PGA_WRITEABLE);
+ rw_runlock(&pvh_global_lock);
+}
+
+static __inline boolean_t
+safe_to_clear_referenced(pmap_t pmap, pt_entry_t pte)
+{
+
+ return (FALSE);
+}
+
+#define PMAP_TS_REFERENCED_MAX 5
+
+/*
+ * pmap_ts_referenced:
+ *
+ * Return a count of reference bits for a page, clearing those bits.
+ * It is not necessary for every reference bit to be cleared, but it
+ * is necessary that 0 only be returned when there are truly no
+ * reference bits set.
+ *
+ * XXX: The exact number of bits to check and clear is a matter that
+ * should be tested and standardized at some point in the future for
+ * optimal aging of shared pages.
+ */
+int
+pmap_ts_referenced(vm_page_t m)
+{
+ pv_entry_t pv, pvf;
+ pmap_t pmap;
+ struct rwlock *lock;
+ pd_entry_t *l2;
+ pt_entry_t *l3;
+ vm_paddr_t pa;
+ int cleared, md_gen, not_cleared;
+ struct spglist free;
+
+ KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+ ("pmap_ts_referenced: page %p is not managed", m));
+ SLIST_INIT(&free);
+ cleared = 0;
+ pa = VM_PAGE_TO_PHYS(m);
+ lock = PHYS_TO_PV_LIST_LOCK(pa);
+ rw_rlock(&pvh_global_lock);
+ rw_wlock(lock);
+retry:
+ not_cleared = 0;
+ if ((pvf = TAILQ_FIRST(&m->md.pv_list)) == NULL)
+ goto out;
+ pv = pvf;
+ do {
+ if (pvf == NULL)
+ pvf = pv;
+ pmap = PV_PMAP(pv);
+ if (!PMAP_TRYLOCK(pmap)) {
+ md_gen = m->md.pv_gen;
+ rw_wunlock(lock);
+ PMAP_LOCK(pmap);
+ rw_wlock(lock);
+ if (md_gen != m->md.pv_gen) {
+ PMAP_UNLOCK(pmap);
+ goto retry;
+ }
+ }
+ l2 = pmap_l2(pmap, pv->pv_va);
+ KASSERT((*l2 & ATTR_DESCR_MASK) == L2_TABLE,
+ ("pmap_ts_referenced: found an invalid l2 table"));
+ l3 = pmap_l2_to_l3(l2, pv->pv_va);
+ if ((*l3 & ATTR_AF) != 0) {
+ if (safe_to_clear_referenced(pmap, *l3)) {
+ /*
+ * TODO: We don't handle the access flag
+ * at all. We need to be able to set it in
+ * the exception handler.
+ */
+ panic("TODO: safe_to_clear_referenced\n");
+ } else if ((*l3 & ATTR_SW_WIRED) == 0) {
+ /*
+ * Wired pages cannot be paged out so
+ * doing accessed bit emulation for
+ * them is wasted effort. We do the
+ * hard work for unwired pages only.
+ */
+ pmap_remove_l3(pmap, l3, pv->pv_va,
+ *l2, &free, &lock);
+ pmap_invalidate_page(pmap, pv->pv_va);
+ cleared++;
+ if (pvf == pv)
+ pvf = NULL;
+ pv = NULL;
+ KASSERT(lock == VM_PAGE_TO_PV_LIST_LOCK(m),
+ ("inconsistent pv lock %p %p for page %p",
+ lock, VM_PAGE_TO_PV_LIST_LOCK(m), m));
+ } else
+ not_cleared++;
+ }
+ PMAP_UNLOCK(pmap);
+ /* Rotate the PV list if it has more than one entry. */
+ if (pv != NULL && TAILQ_NEXT(pv, pv_next) != NULL) {
+ TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
+ TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next);
+ m->md.pv_gen++;
+ }
+ } while ((pv = TAILQ_FIRST(&m->md.pv_list)) != pvf && cleared +
+ not_cleared < PMAP_TS_REFERENCED_MAX);
+out:
+ rw_wunlock(lock);
+ rw_runlock(&pvh_global_lock);
+ pmap_free_zero_pages(&free);
+ return (cleared + not_cleared);
+}
+
+/*
+ * Apply the given advice to the specified range of addresses within the
+ * given pmap. Depending on the advice, clear the referenced and/or
+ * modified flags in each mapping and set the mapped page's dirty field.
+ */
+void
+pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, int advice)
+{
+}
+
+/*
+ * Clear the modify bits on the specified physical page.
+ */
+void
+pmap_clear_modify(vm_page_t m)
+{
+
+ KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+ ("pmap_clear_modify: page %p is not managed", m));
+ VM_OBJECT_ASSERT_WLOCKED(m->object);
+ KASSERT(!vm_page_xbusied(m),
+ ("pmap_clear_modify: page %p is exclusive busied", m));
+
+ /*
+ * If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set.
+ * If the object containing the page is locked and the page is not
+ * exclusive busied, then PGA_WRITEABLE cannot be concurrently set.
+ */
+ if ((m->aflags & PGA_WRITEABLE) == 0)
+ return;
+
+ /* TODO: We lack support for tracking if a page is modified */
+}
+
+void *
+pmap_mapbios(vm_paddr_t pa, vm_size_t size)
+{
+
+ return ((void *)PHYS_TO_DMAP(pa));
+}
+
+void
+pmap_unmapbios(vm_paddr_t pa, vm_size_t size)
+{
+}
+
+/*
+ * Sets the memory attribute for the specified page.
+ */
+void
+pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
+{
+
+ panic("pmap_page_set_memattr");
+}
+
+/*
+ * perform the pmap work for mincore
+ */
+int
+pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa)
+{
+
+ panic("pmap_mincore");
+}
+
+void
+pmap_activate(struct thread *td)
+{
+ pmap_t pmap;
+
+ critical_enter();
+ pmap = vmspace_pmap(td->td_proc->p_vmspace);
+ td->td_pcb->pcb_l1addr = vtophys(pmap->pm_l1);
+ __asm __volatile("msr ttbr0_el1, %0" : : "r"(td->td_pcb->pcb_l1addr));
+ critical_exit();
+}
+
+void
+pmap_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz)
+{
+
+ panic("pmap_sync_icache");
+}
+
+/*
+ * Increase the starting virtual address of the given mapping if a
+ * different alignment might result in more superpage mappings.
+ */
+void
+pmap_align_superpage(vm_object_t object, vm_ooffset_t offset,
+ vm_offset_t *addr, vm_size_t size)
+{
+}
+
+/**
+ * Get the kernel virtual address of a set of physical pages. If there are
+ * physical addresses not covered by the DMAP perform a transient mapping
+ * that will be removed when calling pmap_unmap_io_transient.
+ *
+ * \param page The pages the caller wishes to obtain the virtual
+ * address on the kernel memory map.
+ * \param vaddr On return contains the kernel virtual memory address
+ * of the pages passed in the page parameter.
+ * \param count Number of pages passed in.
+ * \param can_fault TRUE if the thread using the mapped pages can take
+ * page faults, FALSE otherwise.
+ *
+ * \returns TRUE if the caller must call pmap_unmap_io_transient when
+ * finished or FALSE otherwise.
+ *
+ */
+boolean_t
+pmap_map_io_transient(vm_page_t page[], vm_offset_t vaddr[], int count,
+ boolean_t can_fault)
+{
+ vm_paddr_t paddr;
+ boolean_t needs_mapping;
+ int error, i;
+
+ /*
+ * Allocate any KVA space that we need, this is done in a separate
+ * loop to prevent calling vmem_alloc while pinned.
+ */
+ needs_mapping = FALSE;
+ for (i = 0; i < count; i++) {
+ paddr = VM_PAGE_TO_PHYS(page[i]);
+ if (__predict_false(paddr >= DMAP_MAX_PHYSADDR)) {
+ error = vmem_alloc(kernel_arena, PAGE_SIZE,
+ M_BESTFIT | M_WAITOK, &vaddr[i]);
+ KASSERT(error == 0, ("vmem_alloc failed: %d", error));
+ needs_mapping = TRUE;
+ } else {
+ vaddr[i] = PHYS_TO_DMAP(paddr);
+ }
+ }
+
+ /* Exit early if everything is covered by the DMAP */
+ if (!needs_mapping)
+ return (FALSE);
+
+ /*
+ * NB: The sequence of updating a page table followed by accesses
+ * to the corresponding pages used in the !DMAP case is subject to
+ * the situation described in the "AMD64 Architecture Programmer's
+ * Manual Volume 2: System Programming" rev. 3.23, "7.3.1 Special
+ * Coherency Considerations". Therefore, issuing the INVLPG right
+ * after modifying the PTE bits is crucial.
+ */
+ if (!can_fault)
+ sched_pin();
+ for (i = 0; i < count; i++) {
+ paddr = VM_PAGE_TO_PHYS(page[i]);
+ if (paddr >= DMAP_MAX_PHYSADDR) {
+ panic(
+ "pmap_map_io_transient: TODO: Map out of DMAP data");
+ }
+ }
+
+ return (needs_mapping);
+}
+
+void
+pmap_unmap_io_transient(vm_page_t page[], vm_offset_t vaddr[], int count,
+ boolean_t can_fault)
+{
+ vm_paddr_t paddr;
+ int i;
+
+ if (!can_fault)
+ sched_unpin();
+ for (i = 0; i < count; i++) {
+ paddr = VM_PAGE_TO_PHYS(page[i]);
+ if (paddr >= DMAP_MAX_PHYSADDR) {
+ panic("pmap_unmap_io_transient: TODO: Unmap data");
+ }
+ }
+}
diff --git a/sys/arm64/arm64/stack_machdep.c b/sys/arm64/arm64/stack_machdep.c
new file mode 100644
index 0000000..a640077
--- /dev/null
+++ b/sys/arm64/arm64/stack_machdep.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/stack.h>
+
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <machine/stack.h>
+
+void
+stack_save_td(struct stack *st, struct thread *td)
+{
+
+ if (TD_IS_SWAPPED(td))
+ panic("stack_save_td: swapped");
+ if (TD_IS_RUNNING(td))
+ panic("stack_save_td: running");
+
+ stack_zero(st);
+}
+
+void
+stack_save(struct stack *st)
+{
+
+ stack_zero(st);
+}
diff --git a/sys/arm64/arm64/support.S b/sys/arm64/arm64/support.S
new file mode 100644
index 0000000..9f30b58
--- /dev/null
+++ b/sys/arm64/arm64/support.S
@@ -0,0 +1,255 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014-2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+#include "assym.s"
+
+/*
+ * One of the fu* or su* functions failed, return -1.
+ */
+ENTRY(fsu_fault)
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the handler function */
+ mov x0, #-1
+ ret
+END(fsu_fault)
+
+/*
+ * int casueword32(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
+ */
+ENTRY(casueword32)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x4) /* And set it */
+1: ldxr w4, [x0] /* Load-exclusive the data */
+ cmp w4, w1 /* Compare */
+ b.ne 2f /* Not equal, exit */
+ stxr w5, w3, [x0] /* Store the new data */
+ cbnz w5, 1b /* Retry on failure */
+ ldrb w0, [x0] /* Try loading the data */
+2: SET_FAULT_HANDLER(xzr, x5) /* Reset the fault handler */
+ str w4, [x2] /* Store the read data */
+ ret /* Return */
+END(casueword32)
+
+/*
+ * int casueword(volatile u_long *, u_long, u_long *, u_long)
+ */
+ENTRY(casueword)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x4) /* And set it */
+1: ldxr x4, [x0] /* Load-exclusive the data */
+ cmp x4, x1 /* Compare */
+ b.ne 2f /* Not equal, exit */
+ stxr w5, x3, [x0] /* Store the new data */
+ cbnz w5, 1b /* Retry on failure */
+ ldrb w0, [x0] /* Try loading the data */
+2: SET_FAULT_HANDLER(xzr, x5) /* Reset the fault handler */
+ str x4, [x2] /* Store the read data */
+ ret /* Return */
+END(casueword)
+
+/*
+ * int fubyte(volatile const void *)
+ */
+ENTRY(fubyte)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x1) /* And set it */
+ ldrb w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */
+ ret /* Return */
+END(fubyte)
+
+/*
+ * int fuword(volatile const void *)
+ */
+ENTRY(fuword16)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x1) /* And set it */
+ ldrh w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */
+ ret /* Return */
+END(fuword16)
+
+/*
+ * int32_t fueword32(volatile const void *, int32_t *)
+ */
+ENTRY(fueword32)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ ldr w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ str w0, [x1] /* Save the data in kernel space */
+ mov w0, #0 /* Success */
+ ret /* Return */
+END(fueword32)
+
+/*
+ * long fueword(volatile const void *, int64_t *)
+ * int64_t fueword64(volatile const void *, int64_t *)
+ */
+ENTRY(fueword)
+EENTRY(fueword64)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ ldr x0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ str x0, [x1] /* Save the data in kernel space */
+ mov x0, #0 /* Success */
+ ret /* Return */
+EEND(fueword64)
+END(fueword)
+
+/*
+ * int subyte(volatile void *, int)
+ */
+ENTRY(subyte)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ strb w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(subyte)
+
+/*
+ * int suword16(volatile void *, int)
+ */
+ENTRY(suword16)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ strh w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(suword16)
+
+/*
+ * int suword32(volatile void *, int)
+ */
+ENTRY(suword32)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ str w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(suword32)
+
+/*
+ * int suword(volatile void *, long)
+ */
+ENTRY(suword)
+EENTRY(suword64)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ str x1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+EEND(suword64)
+END(suword)
+
+/*
+ * fuswintr and suswintr are just like fusword and susword except that if
+ * the page is not in memory or would cause a trap, then we return an error.
+ * The important thing is to prevent sleep() and switch().
+ */
+
+/*
+ * Special handler so the trap code knows not to sleep.
+ */
+ENTRY(fsu_intr_fault)
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the handler function */
+ mov x0, #-1
+ ret
+END(fsu_fault)
+
+/*
+ * int fuswintr(void *)
+ */
+ENTRY(fuswintr)
+ adr x6, fsu_intr_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x1) /* And set it */
+ ldr w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */
+ ret /* Return */
+END(fuswintr)
+
+/*
+ * int suswintr(void *base, int word)
+ */
+ENTRY(suswintr)
+ adr x6, fsu_intr_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ str w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(suswintr)
+
+ENTRY(setjmp)
+ /* Store the stack pointer */
+ mov x8, sp
+ str x8, [x0]
+
+ /* Store the general purpose registers and lr */
+ stp x19, x20, [x0], #16
+ stp x21, x22, [x0], #16
+ stp x23, x24, [x0], #16
+ stp x25, x26, [x0], #16
+ stp x27, x28, [x0], #16
+ stp x29, lr, [x0], #16
+
+ /* Return value */
+ mov x0, #0
+ ret
+END(setjmp)
+
+ENTRY(longjmp)
+ /* Restore the stack pointer */
+ ldr x8, [x0], #8
+ mov sp, x8
+
+ /* Restore the general purpose registers and lr */
+ ldp x19, x20, [x0], #16
+ ldp x21, x22, [x0], #16
+ ldp x23, x24, [x0], #16
+ ldp x25, x26, [x0], #16
+ ldp x27, x28, [x0], #16
+ ldp x29, lr, [x0], #16
+
+ /* Load the return value */
+ mov x0, x1
+ ret
+END(longjmp)
diff --git a/sys/arm64/arm64/swtch.S b/sys/arm64/arm64/swtch.S
new file mode 100644
index 0000000..2d547fd
--- /dev/null
+++ b/sys/arm64/arm64/swtch.S
@@ -0,0 +1,255 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "assym.s"
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+
+/*
+ * void cpu_throw(struct thread *old, struct thread *new)
+ */
+ENTRY(cpu_throw)
+#ifdef SMP
+#error cpu_throw needs to be ported to support SMP
+#endif
+
+#ifdef VFP
+ /* Backup the new thread pointer around a call to C code */
+ mov x19, x1
+ bl vfp_discard
+ mov x1, x19
+#endif
+
+ /* Store the new curthread */
+ str x1, [x18, #PC_CURTHREAD]
+ /* And the new pcb */
+ ldr x4, [x1, #TD_PCB]
+ str x4, [x18, #PC_CURPCB]
+
+ /*
+ * TODO: We may need to flush the cache here.
+ */
+
+ /* Switch to the new pmap */
+ ldr x5, [x4, #PCB_L1ADDR]
+ msr ttbr0_el1, x5
+ isb
+
+ /* Invalidate the TLB */
+ dsb sy
+ tlbi vmalle1is
+ dsb sy
+ isb
+
+ /* Restore the registers */
+ ldp x5, x6, [x4, #PCB_SP]
+ mov sp, x5
+ msr tpidr_el0, x6
+ ldp x8, x9, [x4, #PCB_REGS + 8 * 8]
+ ldp x10, x11, [x4, #PCB_REGS + 10 * 8]
+ ldp x12, x13, [x4, #PCB_REGS + 12 * 8]
+ ldp x14, x15, [x4, #PCB_REGS + 14 * 8]
+ ldp x16, x17, [x4, #PCB_REGS + 16 * 8]
+ ldr x19, [x4, #PCB_REGS + 19 * 8]
+ ldp x20, x21, [x4, #PCB_REGS + 20 * 8]
+ ldp x22, x23, [x4, #PCB_REGS + 22 * 8]
+ ldp x24, x25, [x4, #PCB_REGS + 24 * 8]
+ ldp x26, x27, [x4, #PCB_REGS + 26 * 8]
+ ldp x28, x29, [x4, #PCB_REGS + 28 * 8]
+ ldr x30, [x4, #PCB_REGS + 30 * 8]
+
+ ret
+END(cpu_throw)
+
+/*
+ * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
+ *
+ * x0 = old
+ * x1 = new
+ * x2 = mtx
+ * x3 to x7, x16 and x17 are caller saved
+ */
+ENTRY(cpu_switch)
+#ifdef SMP
+#error cpu_switch needs to be ported to support SMP
+#endif
+
+ /* Store the new curthread */
+ str x1, [x18, #PC_CURTHREAD]
+ /* And the new pcb */
+ ldr x4, [x1, #TD_PCB]
+ str x4, [x18, #PC_CURPCB]
+
+ /*
+ * Save the old context.
+ */
+ ldr x4, [x0, #TD_PCB]
+
+ /* Store the callee-saved registers */
+ stp x8, x9, [x4, #PCB_REGS + 8 * 8]
+ stp x10, x11, [x4, #PCB_REGS + 10 * 8]
+ stp x12, x13, [x4, #PCB_REGS + 12 * 8]
+ stp x14, x15, [x4, #PCB_REGS + 14 * 8]
+ stp x16, x17, [x4, #PCB_REGS + 16 * 8]
+ stp x18, x19, [x4, #PCB_REGS + 18 * 8]
+ stp x20, x21, [x4, #PCB_REGS + 20 * 8]
+ stp x22, x23, [x4, #PCB_REGS + 22 * 8]
+ stp x24, x25, [x4, #PCB_REGS + 24 * 8]
+ stp x26, x27, [x4, #PCB_REGS + 26 * 8]
+ stp x28, x29, [x4, #PCB_REGS + 28 * 8]
+ str x30, [x4, #PCB_REGS + 30 * 8]
+ /* And the old stack pointer */
+ mov x5, sp
+ mrs x6, tpidr_el0
+ stp x5, x6, [x4, #PCB_SP]
+
+#ifdef VFP
+ mov x19, x0
+ mov x20, x1
+ mov x21, x2
+ bl vfp_save_state
+ mov x2, x21
+ mov x1, x20
+ mov x0, x19
+#endif
+
+ /*
+ * Restore the saved context.
+ */
+ ldr x4, [x1, #TD_PCB]
+
+ /*
+ * TODO: We may need to flush the cache here if switching
+ * to a user process.
+ */
+
+ /* Switch to the new pmap */
+ ldr x5, [x4, #PCB_L1ADDR]
+ msr ttbr0_el1, x5
+ isb
+
+ /* Invalidate the TLB */
+ dsb sy
+ tlbi vmalle1is
+ dsb sy
+ isb
+
+ /* Release the old thread */
+ str x2, [x0, #TD_LOCK]
+#if defined(SCHED_ULE) && defined(SMP)
+#error We may need to wait for the lock here
+#endif
+
+ /* Restore the registers */
+ ldp x5, x6, [x4, #PCB_SP]
+ mov sp, x5
+ msr tpidr_el0, x6
+ ldp x8, x9, [x4, #PCB_REGS + 8 * 8]
+ ldp x10, x11, [x4, #PCB_REGS + 10 * 8]
+ ldp x12, x13, [x4, #PCB_REGS + 12 * 8]
+ ldp x14, x15, [x4, #PCB_REGS + 14 * 8]
+ ldp x16, x17, [x4, #PCB_REGS + 16 * 8]
+ ldr x19, [x4, #PCB_REGS + 19 * 8]
+ ldp x20, x21, [x4, #PCB_REGS + 20 * 8]
+ ldp x22, x23, [x4, #PCB_REGS + 22 * 8]
+ ldp x24, x25, [x4, #PCB_REGS + 24 * 8]
+ ldp x26, x27, [x4, #PCB_REGS + 26 * 8]
+ ldp x28, x29, [x4, #PCB_REGS + 28 * 8]
+ ldr x30, [x4, #PCB_REGS + 30 * 8]
+
+ str xzr, [x4, #PCB_REGS + 18 * 8]
+ ret
+.Lcpu_switch_panic_str:
+ .asciz "cpu_switch: %p\0"
+END(cpu_switch)
+
+ENTRY(fork_trampoline)
+ mov x0, x8
+ mov x1, x9
+ mov x2, sp
+ mov fp, #0 /* Stack traceback stops here. */
+ bl _C_LABEL(fork_exit)
+
+ /* Restore sp and lr */
+ ldp x0, x1, [sp]
+ msr sp_el0, x0
+ mov lr, x1
+
+ /* Restore the registers other than x0 and x1 */
+ ldp x2, x3, [sp, #TF_X + 2 * 8]
+ ldp x4, x5, [sp, #TF_X + 4 * 8]
+ ldp x6, x7, [sp, #TF_X + 6 * 8]
+ ldp x8, x9, [sp, #TF_X + 8 * 8]
+ ldp x10, x11, [sp, #TF_X + 10 * 8]
+ ldp x12, x13, [sp, #TF_X + 12 * 8]
+ ldp x14, x15, [sp, #TF_X + 14 * 8]
+ ldp x16, x17, [sp, #TF_X + 16 * 8]
+ ldr x19, [sp, #TF_X + 19 * 8]
+ ldp x20, x21, [sp, #TF_X + 20 * 8]
+ ldp x22, x23, [sp, #TF_X + 22 * 8]
+ ldp x24, x25, [sp, #TF_X + 24 * 8]
+ ldp x26, x27, [sp, #TF_X + 26 * 8]
+ ldp x28, x29, [sp, #TF_X + 28 * 8]
+ /* Skip x30 as it was restored above as lr */
+
+ /*
+ * Disable interrupts to avoid
+ * overwriting spsr_el1 by an IRQ exception.
+ */
+ msr daifset, #2
+
+ /* Restore elr and spsr */
+ ldp x0, x1, [sp, #16]
+ msr elr_el1, x0
+ msr spsr_el1, x1
+
+ /* Finally x0 and x1 */
+ ldp x0, x1, [sp, #TF_X + 0 * 8]
+ ldr x18, [sp, #TF_X + 18 * 8]
+
+ /*
+ * No need for interrupts reenabling since PSR
+ * will be set to the desired value anyway.
+ */
+ eret
+
+END(fork_trampoline)
+
+ENTRY(savectx)
+ adr x0, .Lsavectx_panic_str
+ bl panic
+ ret
+.Lsavectx_panic_str:
+ .asciz "savectx"
+END(savectx)
+
diff --git a/sys/arm64/arm64/sys_machdep.c b/sys/arm64/arm64/sys_machdep.c
new file mode 100644
index 0000000..c9ee6c5
--- /dev/null
+++ b/sys/arm64/arm64/sys_machdep.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+
+#include <machine/sysarch.h>
+
+
+int
+sysarch(struct thread *td, struct sysarch_args *uap)
+{
+
+ return (ENOTSUP);
+}
+
diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
new file mode 100644
index 0000000..a5c9d61
--- /dev/null
+++ b/sys/arm64/arm64/trap.c
@@ -0,0 +1,311 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/pioctl.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+#ifdef KDB
+#include <sys/kdb.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_extern.h>
+
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <machine/pcpu.h>
+#include <machine/vmparam.h>
+
+#ifdef VFP
+#include <machine/vfp.h>
+#endif
+
+#ifdef KDB
+#include <machine/db_machdep.h>
+#endif
+
+#ifdef DDB
+#include <ddb/db_output.h>
+#endif
+
+extern register_t fsu_intr_fault;
+
+/* Called from exception.S */
+void do_el1h_sync(struct trapframe *);
+void do_el0_sync(struct trapframe *);
+void do_el0_error(struct trapframe *);
+
+static __inline void
+call_trapsignal(struct thread *td, int sig, u_long code)
+{
+ ksiginfo_t ksi;
+
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = sig;
+ ksi.ksi_code = (int)code;
+ trapsignal(td, &ksi);
+}
+
+int
+cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
+{
+ struct proc *p;
+ register_t *ap;
+ int nap;
+
+ nap = 8;
+ p = td->td_proc;
+ ap = td->td_frame->tf_x;
+
+ sa->code = td->td_frame->tf_x[8];
+
+ if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
+ sa->code = *ap++;
+ nap--;
+ }
+
+ if (p->p_sysent->sv_mask)
+ sa->code &= p->p_sysent->sv_mask;
+ if (sa->code >= p->p_sysent->sv_size)
+ sa->callp = &p->p_sysent->sv_table[0];
+ else
+ sa->callp = &p->p_sysent->sv_table[sa->code];
+
+ sa->narg = sa->callp->sy_narg;
+ memcpy(sa->args, ap, nap * sizeof(register_t));
+ if (sa->narg > nap)
+ panic("TODO: Could we have more then 8 args?");
+
+ td->td_retval[0] = 0;
+ td->td_retval[1] = 0;
+
+ return (0);
+}
+
+#include "../../kern/subr_syscall.c"
+
+static void
+svc_handler(struct trapframe *frame)
+{
+ struct syscall_args sa;
+ struct thread *td;
+ int error;
+
+ td = curthread;
+ td->td_frame = frame;
+
+ error = syscallenter(td, &sa);
+ syscallret(td, error, &sa);
+}
+
+static void
+data_abort(struct trapframe *frame, uint64_t esr, int lower)
+{
+ struct vm_map *map;
+ struct thread *td;
+ struct proc *p;
+ struct pcb *pcb;
+ vm_prot_t ftype;
+ vm_offset_t va;
+ uint64_t far;
+ int error, sig;
+
+ td = curthread;
+ pcb = td->td_pcb;
+
+ /*
+ * Special case for fuswintr and suswintr. These can't sleep so
+ * handle them early on in the trap handler.
+ */
+ if (__predict_false(pcb->pcb_onfault == (vm_offset_t)&fsu_intr_fault)) {
+ frame->tf_elr = pcb->pcb_onfault;
+ return;
+ }
+
+ far = READ_SPECIALREG(far_el1);
+ p = td->td_proc;
+
+ if (lower)
+ map = &td->td_proc->p_vmspace->vm_map;
+ else {
+ /* The top bit tells us which range to use */
+ if ((far >> 63) == 1)
+ map = kernel_map;
+ else
+ map = &td->td_proc->p_vmspace->vm_map;
+ }
+
+ va = trunc_page(far);
+ ftype = ((esr >> 6) & 1) ? VM_PROT_READ | VM_PROT_WRITE : VM_PROT_READ;
+
+ if (map != kernel_map) {
+ /*
+ * Keep swapout from messing with us during this
+ * critical time.
+ */
+ PROC_LOCK(p);
+ ++p->p_lock;
+ PROC_UNLOCK(p);
+
+ /* Fault in the user page: */
+ error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
+
+ PROC_LOCK(p);
+ --p->p_lock;
+ PROC_UNLOCK(p);
+ } else {
+ /*
+ * Don't have to worry about process locking or stacks in the
+ * kernel.
+ */
+ error = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
+ }
+
+ if (error != 0) {
+ if (lower) {
+ if (error == ENOMEM)
+ sig = SIGKILL;
+ else
+ sig = SIGSEGV;
+ call_trapsignal(td, sig, 0);
+ } else {
+ if (td->td_intr_nesting_level == 0 &&
+ pcb->pcb_onfault != 0) {
+ frame->tf_x[0] = error;
+ frame->tf_elr = pcb->pcb_onfault;
+ return;
+ }
+ panic("vm_fault failed: %lx", frame->tf_elr);
+ }
+ }
+
+ if (lower)
+ userret(td, frame);
+}
+
+void
+do_el1h_sync(struct trapframe *frame)
+{
+ uint32_t exception;
+ uint64_t esr;
+
+ /* Read the esr register to get the exception details */
+ esr = READ_SPECIALREG(esr_el1);
+ exception = ESR_ELx_EXCEPTION(esr);
+
+ /*
+ * Sanity check we are in an exception er can handle. The IL bit
+ * is used to indicate the instruction length, except in a few
+ * exceptions described in the ARMv8 ARM.
+ *
+ * It is unclear in some cases if the bit is implementation defined.
+ * The Foundation Model and QEMU disagree on if the IL bit should
+ * be set when we are in a data fault from the same EL and the ISV
+ * bit (bit 24) is also set.
+ */
+ KASSERT((esr & ESR_ELx_IL) == ESR_ELx_IL ||
+ (exception == EXCP_DATA_ABORT && ((esr & ISS_DATA_ISV) == 0)),
+ ("Invalid instruction length in exception"));
+
+ switch(exception) {
+ case EXCP_FP_SIMD:
+ case EXCP_TRAP_FP:
+ panic("VFP exception in the kernel");
+ case EXCP_DATA_ABORT:
+ data_abort(frame, esr, 0);
+ break;
+ case EXCP_BRK:
+ case EXCP_WATCHPT_EL1:
+ case EXCP_SOFTSTP_EL1:
+#ifdef KDB
+ kdb_trap(exception, 0, frame);
+#else
+ panic("No debugger in kernel.\n");
+#endif
+ break;
+ default:
+ panic("Unknown kernel exception %x esr_el1 %lx\n", exception,
+ esr);
+ }
+}
+
+void
+do_el0_sync(struct trapframe *frame)
+{
+ uint32_t exception;
+ uint64_t esr;
+
+ /* Check we have a sane environment when entering from userland */
+ KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
+ ("Invalid pcpu address from userland: %p (tpidr %lx)",
+ get_pcpu(), READ_SPECIALREG(tpidr_el1)));
+
+ esr = READ_SPECIALREG(esr_el1);
+ exception = ESR_ELx_EXCEPTION(esr);
+
+ switch(exception) {
+ case EXCP_FP_SIMD:
+ case EXCP_TRAP_FP:
+#ifdef VFP
+ vfp_restore_state();
+#else
+ panic("VFP exception in userland");
+#endif
+ break;
+ case EXCP_SVC:
+ svc_handler(frame);
+ break;
+ case EXCP_INSN_ABORT_L:
+ case EXCP_DATA_ABORT_L:
+ data_abort(frame, esr, 1);
+ break;
+ default:
+ panic("Unknown userland exception %x esr_el1 %lx\n", exception,
+ esr);
+ }
+}
+
+void
+do_el0_error(struct trapframe *frame)
+{
+
+ panic("do_el0_error");
+}
+
diff --git a/sys/arm64/arm64/uio_machdep.c b/sys/arm64/arm64/uio_machdep.c
new file mode 100644
index 0000000..e6f6d39
--- /dev/null
+++ b/sys/arm64/arm64/uio_machdep.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2004 Alan L. Cox <alc@cs.rice.edu>
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <machine/vmparam.h>
+
+/*
+ * Implement uiomove(9) from physical memory using the direct map to
+ * avoid the creation and destruction of ephemeral mappings.
+ */
+int
+uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio)
+{
+ struct thread *td = curthread;
+ struct iovec *iov;
+ void *cp;
+ vm_offset_t page_offset, vaddr;
+ size_t cnt;
+ int error = 0;
+ int save = 0;
+ boolean_t mapped;
+
+ KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
+ ("uiomove_fromphys: mode"));
+ KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
+ ("uiomove_fromphys proc"));
+ save = td->td_pflags & TDP_DEADLKTREAT;
+ td->td_pflags |= TDP_DEADLKTREAT;
+ mapped = FALSE;
+ while (n > 0 && uio->uio_resid) {
+ iov = uio->uio_iov;
+ cnt = iov->iov_len;
+ if (cnt == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ continue;
+ }
+ if (cnt > n)
+ cnt = n;
+ page_offset = offset & PAGE_MASK;
+ cnt = min(cnt, PAGE_SIZE - page_offset);
+ if (uio->uio_segflg != UIO_NOCOPY) {
+ mapped = pmap_map_io_transient(
+ &ma[offset >> PAGE_SHIFT], &vaddr, 1, TRUE);
+ cp = (char *)vaddr + page_offset;
+ }
+ switch (uio->uio_segflg) {
+ case UIO_USERSPACE:
+ maybe_yield();
+ if (uio->uio_rw == UIO_READ)
+ error = copyout(cp, iov->iov_base, cnt);
+ else
+ error = copyin(iov->iov_base, cp, cnt);
+ if (error)
+ goto out;
+ break;
+ case UIO_SYSSPACE:
+ if (uio->uio_rw == UIO_READ)
+ bcopy(cp, iov->iov_base, cnt);
+ else
+ bcopy(iov->iov_base, cp, cnt);
+ break;
+ case UIO_NOCOPY:
+ break;
+ }
+ if (__predict_false(mapped)) {
+ pmap_unmap_io_transient(&ma[offset >> PAGE_SHIFT],
+ &vaddr, 1, TRUE);
+ mapped = FALSE;
+ }
+ iov->iov_base = (char *)iov->iov_base + cnt;
+ iov->iov_len -= cnt;
+ uio->uio_resid -= cnt;
+ uio->uio_offset += cnt;
+ offset += cnt;
+ n -= cnt;
+ }
+out:
+ if (__predict_false(mapped)) {
+ panic("TODO 3");
+ pmap_unmap_io_transient(&ma[offset >> PAGE_SHIFT], &vaddr, 1,
+ TRUE);
+ }
+ if (save == 0)
+ td->td_pflags &= ~TDP_DEADLKTREAT;
+ return (error);
+}
diff --git a/sys/arm64/arm64/vfp.c b/sys/arm64/arm64/vfp.c
new file mode 100644
index 0000000..7ce59b8
--- /dev/null
+++ b/sys/arm64/arm64/vfp.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef VFP
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+
+#include <machine/armreg.h>
+#include <machine/pcb.h>
+#include <machine/vfp.h>
+
+/* Sanity check we can store all the VFP registers */
+CTASSERT(sizeof(((struct pcb *)0)->pcb_vfp) == 16 * 32);
+
+static void
+vfp_enable(void)
+{
+ uint32_t cpacr;
+
+ cpacr = READ_SPECIALREG(cpacr_el1);
+ cpacr = (cpacr & ~CPACR_FPEN_MASK) | CPACR_FPEN_TRAP_NONE;
+ WRITE_SPECIALREG(cpacr_el1, cpacr);
+ isb();
+}
+
+static void
+vfp_disable(void)
+{
+ uint32_t cpacr;
+
+ cpacr = READ_SPECIALREG(cpacr_el1);
+ cpacr = (cpacr & ~CPACR_FPEN_MASK) | CPACR_FPEN_TRAP_ALL1;
+ WRITE_SPECIALREG(cpacr_el1, cpacr);
+ isb();
+}
+
+/*
+ * Called when the thread is dying. If the thread was the last to use the
+ * VFP unit mark it as unused to tell the kernel the fp state is unowned.
+ * Ensure the VFP unit is off so we get an exception on the next access.
+ */
+void
+vfp_discard(struct thread *td)
+{
+
+ if (PCPU_GET(fpcurthread) == td)
+ PCPU_SET(fpcurthread, NULL);
+
+ vfp_disable();
+}
+
+void
+vfp_save_state(struct thread *td)
+{
+ __int128_t *vfp_state;
+ uint64_t fpcr, fpsr;
+ uint32_t cpacr;
+
+ critical_enter();
+ /*
+ * Only store the registers if the VFP is enabled,
+ * i.e. return if we are trapping on FP access.
+ */
+ cpacr = READ_SPECIALREG(cpacr_el1);
+ if ((cpacr & CPACR_FPEN_MASK) == CPACR_FPEN_TRAP_NONE) {
+ vfp_state = td->td_pcb->pcb_vfp;
+ __asm __volatile(
+ "mrs %0, fpcr \n"
+ "mrs %1, fpsr \n"
+ "stp q0, q1, [%2, #16 * 0]\n"
+ "stp q2, q3, [%2, #16 * 2]\n"
+ "stp q4, q5, [%2, #16 * 4]\n"
+ "stp q6, q7, [%2, #16 * 6]\n"
+ "stp q8, q9, [%2, #16 * 8]\n"
+ "stp q10, q11, [%2, #16 * 10]\n"
+ "stp q12, q13, [%2, #16 * 12]\n"
+ "stp q14, q15, [%2, #16 * 14]\n"
+ "stp q16, q17, [%2, #16 * 16]\n"
+ "stp q18, q19, [%2, #16 * 18]\n"
+ "stp q20, q21, [%2, #16 * 20]\n"
+ "stp q22, q23, [%2, #16 * 22]\n"
+ "stp q24, q25, [%2, #16 * 24]\n"
+ "stp q26, q27, [%2, #16 * 26]\n"
+ "stp q28, q29, [%2, #16 * 28]\n"
+ "stp q30, q31, [%2, #16 * 30]\n"
+ : "=&r"(fpcr), "=&r"(fpsr) : "r"(vfp_state));
+
+ td->td_pcb->pcb_fpcr = fpcr;
+ td->td_pcb->pcb_fpsr = fpsr;
+
+ dsb();
+ vfp_disable();
+ }
+ critical_exit();
+}
+
+void
+vfp_restore_state(void)
+{
+ __int128_t *vfp_state;
+ uint64_t fpcr, fpsr;
+ struct pcb *curpcb;
+ u_int cpu;
+
+ critical_enter();
+
+ cpu = PCPU_GET(cpuid);
+ curpcb = curthread->td_pcb;
+ curpcb->pcb_fpflags |= PCB_FP_STARTED;
+
+ vfp_enable();
+
+ if (PCPU_GET(fpcurthread) != curthread && cpu != curpcb->pcb_vfpcpu) {
+
+ vfp_state = curthread->td_pcb->pcb_vfp;
+ fpcr = curthread->td_pcb->pcb_fpcr;
+ fpsr = curthread->td_pcb->pcb_fpsr;
+
+ __asm __volatile(
+ "ldp q0, q1, [%2, #16 * 0]\n"
+ "ldp q2, q3, [%2, #16 * 2]\n"
+ "ldp q4, q5, [%2, #16 * 4]\n"
+ "ldp q6, q7, [%2, #16 * 6]\n"
+ "ldp q8, q9, [%2, #16 * 8]\n"
+ "ldp q10, q11, [%2, #16 * 10]\n"
+ "ldp q12, q13, [%2, #16 * 12]\n"
+ "ldp q14, q15, [%2, #16 * 14]\n"
+ "ldp q16, q17, [%2, #16 * 16]\n"
+ "ldp q18, q19, [%2, #16 * 18]\n"
+ "ldp q20, q21, [%2, #16 * 20]\n"
+ "ldp q22, q23, [%2, #16 * 22]\n"
+ "ldp q24, q25, [%2, #16 * 24]\n"
+ "ldp q26, q27, [%2, #16 * 26]\n"
+ "ldp q28, q29, [%2, #16 * 28]\n"
+ "ldp q30, q31, [%2, #16 * 30]\n"
+ "msr fpcr, %0 \n"
+ "msr fpsr, %1 \n"
+ : : "r"(fpcr), "r"(fpsr), "r"(vfp_state));
+
+ PCPU_SET(fpcurthread, curthread);
+ curpcb->pcb_vfpcpu = cpu;
+ }
+
+ critical_exit();
+}
+
+void
+vfp_init(void)
+{
+ uint64_t pfr;
+
+ /* Check if there is a vfp unit present */
+ pfr = READ_SPECIALREG(id_aa64pfr0_el1);
+ if ((pfr & ID_AA64PFR0_FP_MASK) == ID_AA64PFR0_FP_NONE)
+ return;
+
+ /* Disable to be enabled when it's used */
+ vfp_disable();
+}
+
+SYSINIT(vfp, SI_SUB_CPU, SI_ORDER_ANY, vfp_init, NULL);
+
+#endif
diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c
new file mode 100644
index 0000000..11591f0
--- /dev/null
+++ b/sys/arm64/arm64/vm_machdep.c
@@ -0,0 +1,265 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/limits.h>
+#include <sys/proc.h>
+#include <sys/sf_buf.h>
+#include <sys/signal.h>
+#include <sys/unistd.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/uma.h>
+#include <vm/uma_int.h>
+
+#include <machine/armreg.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/frame.h>
+
+#ifdef VFP
+#include <machine/vfp.h>
+#endif
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the pcb, set up the stack so that the child
+ * ready to run and return to user mode.
+ */
+void
+cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
+{
+ struct pcb *pcb2;
+ struct trapframe *tf;
+
+ if ((flags & RFPROC) == 0)
+ return;
+
+ if (td1 == curthread) {
+ /*
+ * Save the tpidr_el0 and the vfp state, these normally happen
+ * in cpu_switch, but if userland changes these then forks
+ * this may not have happened.
+ */
+ td1->td_pcb->pcb_tpidr_el0 = READ_SPECIALREG(tpidr_el0);
+#ifdef VFP
+ if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0)
+ vfp_save_state(td1);
+#endif
+ }
+
+ pcb2 = (struct pcb *)(td2->td_kstack +
+ td2->td_kstack_pages * PAGE_SIZE) - 1;
+
+ td2->td_pcb = pcb2;
+ bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
+
+ td2->td_pcb->pcb_l1addr =
+ vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l1);
+
+ tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1);
+ bcopy(td1->td_frame, tf, sizeof(*tf));
+ tf->tf_x[0] = 0;
+ tf->tf_x[1] = 0;
+ tf->tf_spsr = 0;
+
+ td2->td_frame = tf;
+
+ /* Set the return value registers for fork() */
+ td2->td_pcb->pcb_x[8] = (uintptr_t)fork_return;
+ td2->td_pcb->pcb_x[9] = (uintptr_t)td2;
+ td2->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline;
+ td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame;
+ td2->td_pcb->pcb_vfpcpu = UINT_MAX;
+
+ /* Setup to release spin count in fork_exit(). */
+ td2->td_md.md_spinlock_count = 1;
+ td2->td_md.md_saved_daif = 0;
+}
+
+void
+cpu_reset(void)
+{
+
+ printf("cpu_reset");
+ while(1)
+ __asm volatile("wfi" ::: "memory");
+}
+
+void
+cpu_thread_swapin(struct thread *td)
+{
+}
+
+void
+cpu_thread_swapout(struct thread *td)
+{
+}
+
+void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+ struct trapframe *frame;
+
+ frame = td->td_frame;
+
+ switch (error) {
+ case 0:
+ frame->tf_x[0] = td->td_retval[0];
+ frame->tf_x[1] = td->td_retval[1];
+ frame->tf_spsr &= ~PSR_C; /* carry bit */
+ break;
+ case ERESTART:
+ frame->tf_elr -= 4;
+ break;
+ case EJUSTRETURN:
+ break;
+ default:
+ frame->tf_spsr |= PSR_C; /* carry bit */
+ frame->tf_x[0] = error;
+ break;
+ }
+}
+
+/*
+ * Initialize machine state (pcb and trap frame) for a new thread about to
+ * upcall. Put enough state in the new thread's PCB to get it to go back
+ * userret(), where we can intercept it again to set the return (upcall)
+ * Address and stack, along with those from upcals that are from other sources
+ * such as those generated in thread_userret() itself.
+ */
+void
+cpu_set_upcall(struct thread *td, struct thread *td0)
+{
+ bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe));
+ bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb));
+
+ td->td_pcb->pcb_x[8] = (uintptr_t)fork_return;
+ td->td_pcb->pcb_x[9] = (uintptr_t)td;
+ td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline;
+ td->td_pcb->pcb_sp = (uintptr_t)td->td_frame;
+ td->td_pcb->pcb_vfpcpu = UINT_MAX;
+
+ /* Setup to release spin count in fork_exit(). */
+ td->td_md.md_spinlock_count = 1;
+ td->td_md.md_saved_daif = 0;
+}
+
+/*
+ * Set that machine state for performing an upcall that has to
+ * be done in thread_userret() so that those upcalls generated
+ * in thread_userret() itself can be done as well.
+ */
+void
+cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
+ stack_t *stack)
+{
+
+ panic("cpu_set_upcall_kse");
+}
+
+int
+cpu_set_user_tls(struct thread *td, void *tls_base)
+{
+
+ panic("cpu_set_user_tls");
+}
+
+void
+cpu_thread_exit(struct thread *td)
+{
+}
+
+void
+cpu_thread_alloc(struct thread *td)
+{
+
+ td->td_pcb = (struct pcb *)(td->td_kstack +
+ td->td_kstack_pages * PAGE_SIZE) - 1;
+ td->td_frame = (struct trapframe *)STACKALIGN(
+ td->td_pcb - 1);
+}
+
+void
+cpu_thread_free(struct thread *td)
+{
+}
+
+void
+cpu_thread_clean(struct thread *td)
+{
+}
+
+/*
+ * Intercept the return address from a freshly forked process that has NOT
+ * been scheduled yet.
+ *
+ * This is needed to make kernel threads stay in kernel mode.
+ */
+void
+cpu_set_fork_handler(struct thread *td, void (*func)(void *), void *arg)
+{
+
+ td->td_pcb->pcb_x[8] = (uintptr_t)func;
+ td->td_pcb->pcb_x[9] = (uintptr_t)arg;
+ td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline;
+ td->td_pcb->pcb_sp = (uintptr_t)td->td_frame;
+ td->td_pcb->pcb_vfpcpu = UINT_MAX;
+}
+
+void
+cpu_exit(struct thread *td)
+{
+}
+
+void
+swi_vm(void *v)
+{
+
+ /* Nothing to do here - busdma bounce buffers are not implemented. */
+}
+
+void *
+uma_small_alloc(uma_zone_t zone, vm_size_t bytes, u_int8_t *flags, int wait)
+{
+
+ panic("uma_small_alloc");
+}
+
+void
+uma_small_free(void *mem, vm_size_t size, u_int8_t flags)
+{
+
+ panic("uma_small_free");
+}
+
diff --git a/sys/arm64/conf/DEFAULTS b/sys/arm64/conf/DEFAULTS
new file mode 100644
index 0000000..8f6d58f
--- /dev/null
+++ b/sys/arm64/conf/DEFAULTS
@@ -0,0 +1,14 @@
+#
+# DEFAULTS -- Default kernel configuration file for FreeBSD/arm64
+#
+# $FreeBSD$
+
+machine arm64 aarch64
+
+# Pseudo devices.
+device mem # Memory and kernel memory devices
+
+# Default partitioning schemes
+options GEOM_PART_BSD
+options GEOM_PART_MBR
+
diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC
new file mode 100644
index 0000000..8aca411
--- /dev/null
+++ b/sys/arm64/conf/GENERIC
@@ -0,0 +1,94 @@
+#
+# GENERIC -- Generic kernel configuration file for FreeBSD/arm64
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+cpu ARM64
+ident GENERIC
+
+makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
+makeoptions NO_MODULES=1 # We don't yet support modules on arm64
+
+options SCHED_ULE # ULE scheduler
+options PREEMPTION # Enable kernel thread preemption
+options INET # InterNETworking
+options INET6 # IPv6 communications protocols
+options TCP_OFFLOAD # TCP offload
+options SCTP # Stream Control Transmission Protocol
+options FFS # Berkeley Fast Filesystem
+options SOFTUPDATES # Enable FFS soft updates support
+options UFS_ACL # Support for access control lists
+options UFS_DIRHASH # Improve performance on big directories
+options UFS_GJOURNAL # Enable gjournal-based UFS journaling
+options QUOTA # Enable disk quotas for UFS
+options MD_ROOT # MD is a potential root device
+options NFSCL # New Network Filesystem Client
+options NFSD # New Network Filesystem Server
+options NFSLOCKD # Network Lock Manager
+options NFS_ROOT # NFS usable as /, requires NFSCL
+options MSDOSFS # MSDOS Filesystem
+options CD9660 # ISO 9660 Filesystem
+options PROCFS # Process filesystem (requires PSEUDOFS)
+options PSEUDOFS # Pseudo-filesystem framework
+options GEOM_PART_GPT # GUID Partition Tables.
+options GEOM_RAID # Soft RAID functionality.
+options GEOM_LABEL # Provides labelization
+options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
+options KTRACE # ktrace(1) support
+options STACK # stack(9) support
+options SYSVSHM # SYSV-style shared memory
+options SYSVMSG # SYSV-style message queues
+options SYSVSEM # SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
+options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed.
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4)
+options AUDIT # Security event auditing
+options CAPABILITY_MODE # Capsicum capability mode
+options CAPABILITIES # Capsicum capabilities
+options MAC # TrustedBSD MAC Framework
+options KDTRACE_FRAME # Ensure frames are compiled in
+options KDTRACE_HOOKS # Kernel DTrace hooks
+options VFP # Floating-point support
+
+device virtio
+device virtio_mmio
+device virtio_blk
+device vtnet
+
+# Serial (COM) ports
+device uart # Generic UART driver
+device pl011
+
+# Pseudo devices.
+device loop # Network loopback
+device random # Entropy device
+device ether # Ethernet support
+device vlan # 802.1Q VLAN support
+device tun # Packet tunnel.
+device md # Memory "disks"
+device gif # IPv6 and IPv4 tunneling
+device firmware # firmware assist module
+device psci # Support for ARM PSCI
+
+# The `bpf' device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+# Note that 'bpf' is required for DHCP.
+device bpf # Berkeley packet filter
+
+options FDT
diff --git a/sys/arm64/include/_bus.h b/sys/arm64/include/_bus.h
new file mode 100644
index 0000000..f11991f
--- /dev/null
+++ b/sys/arm64/include/_bus.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2005 M. Warner Losh.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE__BUS_H_
+#define _MACHINE__BUS_H_
+
+/*
+ * Addresses (in bus space).
+ */
+typedef u_long bus_addr_t;
+typedef u_long bus_size_t;
+
+/*
+ * Access methods for bus space.
+ */
+typedef u_long bus_space_handle_t;
+typedef struct bus_space *bus_space_tag_t;
+
+#endif /* !_MACHINE__BUS_H_ */
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
new file mode 100644
index 0000000..51063bb
--- /dev/null
+++ b/sys/arm64/include/armreg.h
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 2013, 2014 Andrew Turner
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_ARMREG_H_
+#define _MACHINE_ARMREG_H_
+
+#define READ_SPECIALREG(reg) \
+({ uint64_t val; \
+ __asm __volatile("mrs %0, " __STRING(reg) : "=&r" (val)); \
+ val; \
+})
+#define WRITE_SPECIALREG(reg, val) \
+ __asm __volatile("msr " __STRING(reg) ", %0" : : "r"((uint64_t)val))
+
+/* CPACR_EL1 */
+#define CPACR_FPEN_MASK (0x3 << 20)
+#define CPACR_FPEN_TRAP_ALL1 (0x0 << 20) /* Traps from EL0 and EL1 */
+#define CPACR_FPEN_TRAP_EL0 (0x1 << 20) /* Traps from EL0 */
+#define CPACR_FPEN_TRAP_ALL2 (0x2 << 20) /* Traps from EL0 and EL1 */
+#define CPACR_FPEN_TRAP_NONE (0x3 << 20) /* No traps */
+#define CPACR_TTA (0x1 << 28)
+
+/* CTR_EL0 - Cache Type Register */
+#define CTR_DLINE_SHIFT 16
+#define CTR_DLINE_MASK (0xf << CTR_DLINE_SHIFT)
+#define CTR_DLINE_SIZE(reg) (((reg) & CTR_DLINE_MASK) >> CTR_DLINE_SHIFT)
+#define CTR_ILINE_SHIFT 0
+#define CTR_ILINE_MASK (0xf << CTR_ILINE_SHIFT)
+#define CTR_ILINE_SIZE(reg) (((reg) & CTR_ILINE_MASK) >> CTR_ILINE_SHIFT)
+
+/* ESR_ELx */
+#define ESR_ELx_ISS_MASK 0x00ffffff
+#define ISS_INSN_FnV (0x01 << 10)
+#define ISS_INSN_EA (0x01 << 9)
+#define ISS_INSN_S1PTW (0x01 << 7)
+#define ISS_INSN_IFSC_MASK (0x1f << 0)
+#define ISS_DATA_ISV (0x01 << 24)
+#define ISS_DATA_SAS_MASK (0x03 << 22)
+#define ISS_DATA_SSE (0x01 << 21)
+#define ISS_DATA_SRT_MASK (0x1f << 16)
+#define ISS_DATA_SF (0x01 << 15)
+#define ISS_DATA_AR (0x01 << 14)
+#define ISS_DATA_FnV (0x01 << 10)
+#define ISS_DATa_EA (0x01 << 9)
+#define ISS_DATa_CM (0x01 << 8)
+#define ISS_INSN_S1PTW (0x01 << 7)
+#define ISS_DATa_WnR (0x01 << 6)
+#define ISS_DATA_DFSC_MASK (0x1f << 0)
+#define ESR_ELx_IL (0x01 << 25)
+#define ESR_ELx_EC_SHIFT 26
+#define ESR_ELx_EC_MASK (0x3f << 26)
+#define ESR_ELx_EXCEPTION(esr) (((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT)
+#define EXCP_UNKNOWN 0x00 /* Unkwn exception */
+#define EXCP_FP_SIMD 0x07 /* VFP/SIMD trap */
+#define EXCP_ILL_STATE 0x0e /* Illegal execution state */
+#define EXCP_SVC 0x15 /* SVC trap */
+#define EXCP_MSR 0x18 /* MSR/MRS trap */
+#define EXCP_INSN_ABORT_L 0x20 /* Instruction abort, from lower EL */
+#define EXCP_INSN_ABORT 0x21 /* Instruction abort, from same EL */
+#define EXCP_PC_ALIGN 0x22 /* PC alignment fault */
+#define EXCP_DATA_ABORT_L 0x24 /* Data abort, from lower EL */
+#define EXCP_DATA_ABORT 0x25 /* Data abort, from same EL */
+#define EXCP_SP_ALIGN 0x26 /* SP slignment fault */
+#define EXCP_TRAP_FP 0x2c /* Trapped FP exception */
+#define EXCP_SERROR 0x2f /* SError interrupt */
+#define EXCP_SOFTSTP_EL1 0x33 /* Software Step, from same EL */
+#define EXCP_WATCHPT_EL1 0x35 /* Watchpoint, from same EL */
+#define EXCP_BRK 0x3c /* Breakpoint */
+
+/* ID_AA64PFR0_EL1 */
+#define ID_AA64PFR0_EL0_MASK (0xf << 0)
+#define ID_AA64PFR0_EL1_MASK (0xf << 4)
+#define ID_AA64PFR0_EL2_MASK (0xf << 8)
+#define ID_AA64PFR0_EL3_MASK (0xf << 12)
+#define ID_AA64PFR0_FP_MASK (0xf << 16)
+#define ID_AA64PFR0_FP_IMPL (0x0 << 16) /* Floating-point implemented */
+#define ID_AA64PFR0_FP_NONE (0xf << 16) /* Floating-point not implemented */
+#define ID_AA64PFR0_ADV_SIMD_MASK (0xf << 20)
+#define ID_AA64PFR0_GIC_MASK (0xf << 24)
+
+/* MAIR_EL1 - Memory Attribute Indirection Register */
+#define MAIR_ATTR_MASK(idx) (0xff << ((n)* 8))
+#define MAIR_ATTR(attr, idx) ((attr) << ((idx) * 8))
+
+/* SCTLR_EL1 - System Control Register */
+#define SCTLR_RES0 0xc8222400 /* Reserved, write 0 */
+#define SCTLR_RES1 0x30d00800 /* Reserved, write 1 */
+
+#define SCTLR_M 0x00000001
+#define SCTLR_A 0x00000002
+#define SCTLR_C 0x00000004
+#define SCTLR_SA 0x00000008
+#define SCTLR_SA0 0x00000010
+#define SCTLR_CP15BEN 0x00000020
+#define SCTLR_THEE 0x00000040
+#define SCTLR_ITD 0x00000080
+#define SCTLR_SED 0x00000100
+#define SCTLR_UMA 0x00000200
+#define SCTLR_I 0x00001000
+#define SCTLR_DZE 0x00004000
+#define SCTLR_UCT 0x00008000
+#define SCTLR_nTWI 0x00010000
+#define SCTLR_nTWE 0x00040000
+#define SCTLR_WXN 0x00080000
+#define SCTLR_EOE 0x01000000
+#define SCTLR_EE 0x02000000
+#define SCTLR_UCI 0x04000000
+
+/* SPSR_EL1 */
+/*
+ * When the exception is taken in AArch64:
+ * M[4] is 0 for AArch64 mode
+ * M[3:2] is the exception level
+ * M[1] is unused
+ * M[0] is the SP select:
+ * 0: always SP0
+ * 1: current ELs SP
+ */
+#define PSR_M_EL0t 0x00000000
+#define PSR_M_EL1t 0x00000004
+#define PSR_M_EL1h 0x00000005
+#define PSR_M_EL2t 0x00000008
+#define PSR_M_EL2h 0x00000009
+#define PSR_M_MASK 0x0000001f
+
+#define PSR_F 0x00000040
+#define PSR_I 0x00000080
+#define PSR_A 0x00000100
+#define PSR_D 0x00000200
+#define PSR_IL 0x00100000
+#define PSR_SS 0x00200000
+#define PSR_V 0x10000000
+#define PSR_C 0x20000000
+#define PSR_Z 0x40000000
+#define PSR_N 0x80000000
+
+/* TCR_EL1 - Translation Control Register */
+#define TCR_ASID_16 (1 << 36)
+
+#define TCR_IPS_SHIFT 32
+#define TCR_IPS_32BIT (0 << TCR_IPS_SHIFT)
+#define TCR_IPS_36BIT (1 << TCR_IPS_SHIFT)
+#define TCR_IPS_40BIT (2 << TCR_IPS_SHIFT)
+#define TCR_IPS_42BIT (3 << TCR_IPS_SHIFT)
+#define TCR_IPS_44BIT (4 << TCR_IPS_SHIFT)
+#define TCR_IPS_48BIT (5 << TCR_IPS_SHIFT)
+
+#define TCR_TG1_SHIFT 30
+#define TCR_TG1_16K (1 << TCR_TG1_SHIFT)
+#define TCR_TG1_4K (2 << TCR_TG1_SHIFT)
+#define TCR_TG1_64K (3 << TCR_TG1_SHIFT)
+
+#define TCR_T1SZ_SHIFT 16
+#define TCR_T0SZ_SHIFT 0
+#define TCR_TxSZ(x) (((x) << TCR_T1SZ_SHIFT) | ((x) << TCR_T0SZ_SHIFT))
+
+/* Saved Program Status Register */
+#define DBG_SPSR_SS (0x1 << 21)
+
+/* Monitor Debug System Control Register */
+#define DBG_MDSCR_SS (0x1 << 0)
+#define DBG_MDSCR_KDE (0x1 << 13)
+#define DBG_MDSCR_MDE (0x1 << 15)
+
+#endif /* !_MACHINE_ARMREG_H_ */
diff --git a/sys/arm64/include/atomic.h b/sys/arm64/include/atomic.h
index 366ae02..f0f6c17 100644
--- a/sys/arm64/include/atomic.h
+++ b/sys/arm64/include/atomic.h
@@ -160,7 +160,6 @@ atomic_subtract_32(volatile uint32_t *p, uint32_t val)
#define atomic_set_int atomic_set_32
#define atomic_subtract_int atomic_subtract_32
-
static __inline void
atomic_add_acq_32(volatile uint32_t *p, uint32_t val)
{
@@ -170,7 +169,7 @@ atomic_add_acq_32(volatile uint32_t *p, uint32_t val)
__asm __volatile(
"1: ldaxr %w0, [%2] \n"
" add %w0, %w0, %w3 \n"
- " stlxr %w1, %w0, [%2] \n"
+ " stxr %w1, %w0, [%2] \n"
" cbnz %w1, 1b \n"
"2:"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
@@ -186,7 +185,7 @@ atomic_clear_acq_32(volatile uint32_t *p, uint32_t val)
__asm __volatile(
"1: ldaxr %w0, [%2] \n"
" bic %w0, %w0, %w3 \n"
- " stlxr %w1, %w0, [%2] \n"
+ " stxr %w1, %w0, [%2] \n"
" cbnz %w1, 1b \n"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
);
@@ -203,7 +202,7 @@ atomic_cmpset_acq_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
" ldaxr %w0, [%2] \n"
" cmp %w0, %w3 \n"
" b.ne 2f \n"
- " stlxr %w1, %w4, [%2] \n"
+ " stxr %w1, %w4, [%2] \n"
" cbnz %w1, 1b \n"
"2:"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
@@ -218,8 +217,9 @@ atomic_load_acq_32(volatile uint32_t *p)
{
uint32_t ret;
- ret = *p;
- dmb();
+ __asm __volatile(
+ "ldar %w0, [%1] \n"
+ : "=&r" (ret) : "r" (p) : "memory");
return (ret);
}
@@ -233,7 +233,7 @@ atomic_set_acq_32(volatile uint32_t *p, uint32_t val)
__asm __volatile(
"1: ldaxr %w0, [%2] \n"
" orr %w0, %w0, %w3 \n"
- " stlxr %w1, %w0, [%2] \n"
+ " stxr %w1, %w0, [%2] \n"
" cbnz %w1, 1b \n"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
);
@@ -248,6 +248,82 @@ atomic_subtract_acq_32(volatile uint32_t *p, uint32_t val)
__asm __volatile(
"1: ldaxr %w0, [%2] \n"
" sub %w0, %w0, %w3 \n"
+ " stxr %w1, %w0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
+
+#define atomic_add_acq_int atomic_add_acq_32
+#define atomic_clear_acq_int atomic_clear_acq_32
+#define atomic_cmpset_acq_int atomic_cmpset_acq_32
+#define atomic_load_acq_int atomic_load_acq_32
+#define atomic_set_acq_int atomic_set_acq_32
+#define atomic_subtract_acq_int atomic_subtract_acq_32
+
+/* The atomic functions currently are both acq and rel, we should fix this. */
+
+static __inline void
+atomic_add_rel_32(volatile uint32_t *p, uint32_t val)
+{
+ uint32_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: ldxr %w0, [%2] \n"
+ " add %w0, %w0, %w3 \n"
+ " stlxr %w1, %w0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ "2:"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
+
+static __inline void
+atomic_clear_rel_32(volatile uint32_t *p, uint32_t val)
+{
+ uint32_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: ldxr %w0, [%2] \n"
+ " bic %w0, %w0, %w3 \n"
+ " stlxr %w1, %w0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
+
+static __inline int
+atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
+{
+ uint32_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: mov %w1, #1 \n"
+ " ldxr %w0, [%2] \n"
+ " cmp %w0, %w3 \n"
+ " b.ne 2f \n"
+ " stlxr %w1, %w4, [%2] \n"
+ " cbnz %w1, 1b \n"
+ "2:"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
+ : : "cc", "memory"
+ );
+
+ return (!res);
+}
+
+static __inline void
+atomic_set_rel_32(volatile uint32_t *p, uint32_t val)
+{
+ uint32_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: ldxr %w0, [%2] \n"
+ " orr %w0, %w0, %w3 \n"
" stlxr %w1, %w0, [%2] \n"
" cbnz %w1, 1b \n"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
@@ -258,23 +334,25 @@ static __inline void
atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
{
- dmb();
- *p = val;
+ __asm __volatile(
+ "stlr %w0, [%1] \n"
+ : : "r" (val), "r" (p) : "memory");
}
-#define atomic_add_acq_int atomic_add_acq_32
-#define atomic_clear_acq_int atomic_add_acq_32
-#define atomic_cmpset_acq_int atomic_cmpset_acq_32
-#define atomic_load_acq_int atomic_load_acq_32
-#define atomic_set_acq_int atomic_set_acq_32
-#define atomic_subtract_acq_int atomic_subtract_acq_32
+static __inline void
+atomic_subtract_rel_32(volatile uint32_t *p, uint32_t val)
+{
+ uint32_t tmp;
+ int res;
-/* The atomic functions currently are both acq and rel, we should fix this. */
-#define atomic_add_rel_32 atomic_add_acq_32
-#define atomic_clear_rel_32 atomic_add_acq_32
-#define atomic_cmpset_rel_32 atomic_cmpset_acq_32
-#define atomic_set_rel_32 atomic_set_acq_32
-#define atomic_subtract_rel_32 atomic_subtract_acq_32
+ __asm __volatile(
+ "1: ldxr %w0, [%2] \n"
+ " sub %w0, %w0, %w3 \n"
+ " stlxr %w1, %w0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
#define atomic_add_rel_int atomic_add_rel_32
#define atomic_clear_rel_int atomic_add_rel_32
@@ -440,7 +518,7 @@ atomic_add_acq_64(volatile uint64_t *p, uint64_t val)
__asm __volatile(
"1: ldaxr %0, [%2] \n"
" add %0, %0, %3 \n"
- " stlxr %w1, %0, [%2] \n"
+ " stxr %w1, %0, [%2] \n"
" cbnz %w1, 1b \n"
"2:"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
@@ -456,7 +534,7 @@ atomic_clear_acq_64(volatile uint64_t *p, uint64_t val)
__asm __volatile(
"1: ldaxr %0, [%2] \n"
" bic %0, %0, %3 \n"
- " stlxr %w1, %0, [%2] \n"
+ " stxr %w1, %0, [%2] \n"
" cbnz %w1, 1b \n"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
);
@@ -473,7 +551,7 @@ atomic_cmpset_acq_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
" ldaxr %0, [%2] \n"
" cmp %0, %3 \n"
" b.ne 2f \n"
- " stlxr %w1, %4, [%2] \n"
+ " stxr %w1, %4, [%2] \n"
" cbnz %w1, 1b \n"
"2:"
: "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
@@ -488,8 +566,9 @@ atomic_load_acq_64(volatile uint64_t *p)
{
uint64_t ret;
- ret = *p;
- dmb();
+ __asm __volatile(
+ "ldar %0, [%1] \n"
+ : "=&r" (ret) : "r" (p) : "memory");
return (ret);
}
@@ -503,7 +582,7 @@ atomic_set_acq_64(volatile uint64_t *p, uint64_t val)
__asm __volatile(
"1: ldaxr %0, [%2] \n"
" orr %0, %0, %3 \n"
- " stlxr %w1, %0, [%2] \n"
+ " stxr %w1, %0, [%2] \n"
" cbnz %w1, 1b \n"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
);
@@ -518,20 +597,12 @@ atomic_subtract_acq_64(volatile uint64_t *p, uint64_t val)
__asm __volatile(
"1: ldaxr %0, [%2] \n"
" sub %0, %0, %3 \n"
- " stlxr %w1, %0, [%2] \n"
+ " stxr %w1, %0, [%2] \n"
" cbnz %w1, 1b \n"
: "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
);
}
-static __inline void
-atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
-{
-
- dmb();
- *p = val;
-}
-
#define atomic_add_acq_long atomic_add_acq_64
#define atomic_clear_acq_long atomic_add_acq_64
#define atomic_cmpset_acq_long atomic_cmpset_acq_64
@@ -550,21 +621,106 @@ atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
* TODO: The atomic functions currently are both acq and rel, we should fix
* this.
*/
-#define atomic_add_rel_64 atomic_add_acq_64
-#define atomic_clear_rel_64 atomic_add_acq_64
-#define atomic_cmpset_rel_64 atomic_cmpset_acq_64
-#define atomic_set_rel_64 atomic_set_acq_64
-#define atomic_subtract_rel_64 atomic_subtract_acq_64
+static __inline void
+atomic_add_rel_64(volatile uint64_t *p, uint64_t val)
+{
+ uint64_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: ldxr %0, [%2] \n"
+ " add %0, %0, %3 \n"
+ " stlxr %w1, %0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ "2:"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
+
+static __inline void
+atomic_clear_rel_64(volatile uint64_t *p, uint64_t val)
+{
+ uint64_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: ldxr %0, [%2] \n"
+ " bic %0, %0, %3 \n"
+ " stlxr %w1, %0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
+
+static __inline int
+atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
+{
+ uint64_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: mov %w1, #1 \n"
+ " ldxr %0, [%2] \n"
+ " cmp %0, %3 \n"
+ " b.ne 2f \n"
+ " stlxr %w1, %4, [%2] \n"
+ " cbnz %w1, 1b \n"
+ "2:"
+ : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
+ : : "cc", "memory"
+ );
+
+ return (!res);
+}
+
+static __inline void
+atomic_set_rel_64(volatile uint64_t *p, uint64_t val)
+{
+ uint64_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: ldxr %0, [%2] \n"
+ " orr %0, %0, %3 \n"
+ " stlxr %w1, %0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
+
+static __inline void
+atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
+{
+
+ __asm __volatile(
+ "stlr %0, [%1] \n"
+ : : "r" (val), "r" (p) : "memory");
+}
+
+static __inline void
+atomic_subtract_rel_64(volatile uint64_t *p, uint64_t val)
+{
+ uint64_t tmp;
+ int res;
+
+ __asm __volatile(
+ "1: ldxr %0, [%2] \n"
+ " sub %0, %0, %3 \n"
+ " stlxr %w1, %0, [%2] \n"
+ " cbnz %w1, 1b \n"
+ : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
+ );
+}
#define atomic_add_rel_long atomic_add_rel_64
-#define atomic_clear_rel_long atomic_add_rel_64
+#define atomic_clear_rel_long atomic_clear_rel_64
#define atomic_cmpset_rel_long atomic_cmpset_rel_64
#define atomic_set_rel_long atomic_set_rel_64
#define atomic_subtract_rel_long atomic_subtract_rel_64
#define atomic_store_rel_long atomic_store_rel_64
#define atomic_add_rel_ptr atomic_add_rel_64
-#define atomic_clear_rel_ptr atomic_add_rel_64
+#define atomic_clear_rel_ptr atomic_clear_rel_64
#define atomic_cmpset_rel_ptr atomic_cmpset_rel_64
#define atomic_set_rel_ptr atomic_set_rel_64
#define atomic_subtract_rel_ptr atomic_subtract_rel_64
diff --git a/sys/arm64/include/bus.h b/sys/arm64/include/bus.h
new file mode 100644
index 0000000..8aaf1d3
--- /dev/null
+++ b/sys/arm64/include/bus.h
@@ -0,0 +1,469 @@
+/* $NetBSD: bus.h,v 1.11 2003/07/28 17:35:54 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1996 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * From: sys/arm/include/bus.h
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_BUS_H_
+#define _MACHINE_BUS_H_
+
+#include <machine/_bus.h>
+
+#define BUS_SPACE_ALIGNED_POINTER(p, t) ALIGNED_POINTER(p, t)
+
+#define BUS_SPACE_MAXADDR_24BIT 0xFFFFFFUL
+#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFFUL
+#define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFFUL
+#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFFUL
+
+#define BUS_SPACE_MAXADDR 0xFFFFFFFFFFFFFFFFUL
+#define BUS_SPACE_MAXSIZE 0xFFFFFFFFFFFFFFFFUL
+
+#define BUS_SPACE_MAP_CACHEABLE 0x01
+#define BUS_SPACE_MAP_LINEAR 0x02
+#define BUS_SPACE_MAP_PREFETCHABLE 0x04
+
+#define BUS_SPACE_UNRESTRICTED (~0)
+
+#define BUS_SPACE_BARRIER_READ 0x01
+#define BUS_SPACE_BARRIER_WRITE 0x02
+
+
+struct bus_space {
+ /* cookie */
+ void *bs_cookie;
+
+ /* mapping/unmapping */
+ int (*bs_map) (void *, bus_addr_t, bus_size_t,
+ int, bus_space_handle_t *);
+ void (*bs_unmap) (void *, bus_space_handle_t, bus_size_t);
+ int (*bs_subregion) (void *, bus_space_handle_t,
+ bus_size_t, bus_size_t, bus_space_handle_t *);
+
+ /* allocation/deallocation */
+ int (*bs_alloc) (void *, bus_addr_t, bus_addr_t,
+ bus_size_t, bus_size_t, bus_size_t, int,
+ bus_addr_t *, bus_space_handle_t *);
+ void (*bs_free) (void *, bus_space_handle_t,
+ bus_size_t);
+
+ /* get kernel virtual address */
+ /* barrier */
+ void (*bs_barrier) (void *, bus_space_handle_t,
+ bus_size_t, bus_size_t, int);
+
+ /* read single */
+ u_int8_t (*bs_r_1) (void *, bus_space_handle_t, bus_size_t);
+ u_int16_t (*bs_r_2) (void *, bus_space_handle_t, bus_size_t);
+ u_int32_t (*bs_r_4) (void *, bus_space_handle_t, bus_size_t);
+ u_int64_t (*bs_r_8) (void *, bus_space_handle_t, bus_size_t);
+
+ /* read multiple */
+ void (*bs_rm_1) (void *, bus_space_handle_t, bus_size_t,
+ u_int8_t *, bus_size_t);
+ void (*bs_rm_2) (void *, bus_space_handle_t, bus_size_t,
+ u_int16_t *, bus_size_t);
+ void (*bs_rm_4) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t);
+ void (*bs_rm_8) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t);
+
+ /* read region */
+ void (*bs_rr_1) (void *, bus_space_handle_t,
+ bus_size_t, u_int8_t *, bus_size_t);
+ void (*bs_rr_2) (void *, bus_space_handle_t,
+ bus_size_t, u_int16_t *, bus_size_t);
+ void (*bs_rr_4) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t);
+ void (*bs_rr_8) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t);
+
+ /* write single */
+ void (*bs_w_1) (void *, bus_space_handle_t,
+ bus_size_t, u_int8_t);
+ void (*bs_w_2) (void *, bus_space_handle_t,
+ bus_size_t, u_int16_t);
+ void (*bs_w_4) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t);
+ void (*bs_w_8) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t);
+
+ /* write multiple */
+ void (*bs_wm_1) (void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t);
+ void (*bs_wm_2) (void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t);
+ void (*bs_wm_4) (void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t);
+ void (*bs_wm_8) (void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t);
+
+ /* write region */
+ void (*bs_wr_1) (void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t);
+ void (*bs_wr_2) (void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t);
+ void (*bs_wr_4) (void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t);
+ void (*bs_wr_8) (void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t);
+
+ /* set multiple */
+ void (*bs_sm_1) (void *, bus_space_handle_t,
+ bus_size_t, u_int8_t, bus_size_t);
+ void (*bs_sm_2) (void *, bus_space_handle_t,
+ bus_size_t, u_int16_t, bus_size_t);
+ void (*bs_sm_4) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t, bus_size_t);
+ void (*bs_sm_8) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t, bus_size_t);
+
+ /* set region */
+ void (*bs_sr_1) (void *, bus_space_handle_t,
+ bus_size_t, u_int8_t, bus_size_t);
+ void (*bs_sr_2) (void *, bus_space_handle_t,
+ bus_size_t, u_int16_t, bus_size_t);
+ void (*bs_sr_4) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t, bus_size_t);
+ void (*bs_sr_8) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t, bus_size_t);
+
+ /* copy */
+ void (*bs_c_1) (void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t);
+ void (*bs_c_2) (void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t);
+ void (*bs_c_4) (void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t);
+ void (*bs_c_8) (void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t);
+
+ /* read single stream */
+ u_int8_t (*bs_r_1_s) (void *, bus_space_handle_t, bus_size_t);
+ u_int16_t (*bs_r_2_s) (void *, bus_space_handle_t, bus_size_t);
+ u_int32_t (*bs_r_4_s) (void *, bus_space_handle_t, bus_size_t);
+ u_int64_t (*bs_r_8_s) (void *, bus_space_handle_t, bus_size_t);
+
+ /* read multiple stream */
+ void (*bs_rm_1_s) (void *, bus_space_handle_t, bus_size_t,
+ u_int8_t *, bus_size_t);
+ void (*bs_rm_2_s) (void *, bus_space_handle_t, bus_size_t,
+ u_int16_t *, bus_size_t);
+ void (*bs_rm_4_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t);
+ void (*bs_rm_8_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t);
+
+ /* read region stream */
+ void (*bs_rr_1_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int8_t *, bus_size_t);
+ void (*bs_rr_2_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int16_t *, bus_size_t);
+ void (*bs_rr_4_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t);
+ void (*bs_rr_8_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t);
+
+ /* write single stream */
+ void (*bs_w_1_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int8_t);
+ void (*bs_w_2_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int16_t);
+ void (*bs_w_4_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int32_t);
+ void (*bs_w_8_s) (void *, bus_space_handle_t,
+ bus_size_t, u_int64_t);
+
+ /* write multiple stream */
+ void (*bs_wm_1_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t);
+ void (*bs_wm_2_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t);
+ void (*bs_wm_4_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t);
+ void (*bs_wm_8_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t);
+
+ /* write region stream */
+ void (*bs_wr_1_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t);
+ void (*bs_wr_2_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t);
+ void (*bs_wr_4_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t);
+ void (*bs_wr_8_s) (void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t);
+};
+
+
+/*
+ * Utility macros; INTERNAL USE ONLY.
+ */
+#define __bs_c(a,b) __CONCAT(a,b)
+#define __bs_opname(op,size) __bs_c(__bs_c(__bs_c(bs_,op),_),size)
+
+#define __bs_rs(sz, t, h, o) \
+ (*(t)->__bs_opname(r,sz))((t)->bs_cookie, h, o)
+#define __bs_ws(sz, t, h, o, v) \
+ (*(t)->__bs_opname(w,sz))((t)->bs_cookie, h, o, v)
+#define __bs_nonsingle(type, sz, t, h, o, a, c) \
+ (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, a, c)
+#define __bs_set(type, sz, t, h, o, v, c) \
+ (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, v, c)
+#define __bs_copy(sz, t, h1, o1, h2, o2, cnt) \
+ (*(t)->__bs_opname(c,sz))((t)->bs_cookie, h1, o1, h2, o2, cnt)
+
+#define __bs_opname_s(op,size) __bs_c(__bs_c(__bs_c(__bs_c(bs_,op),_),size),_s)
+#define __bs_rs_s(sz, t, h, o) \
+ (*(t)->__bs_opname_s(r,sz))((t)->bs_cookie, h, o)
+#define __bs_ws_s(sz, t, h, o, v) \
+ (*(t)->__bs_opname_s(w,sz))((t)->bs_cookie, h, o, v)
+#define __bs_nonsingle_s(type, sz, t, h, o, a, c) \
+ (*(t)->__bs_opname_s(type,sz))((t)->bs_cookie, h, o, a, c)
+
+
+/*
+ * Mapping and unmapping operations.
+ */
+#define bus_space_map(t, a, s, c, hp) \
+ (*(t)->bs_map)((t)->bs_cookie, (a), (s), (c), (hp))
+#define bus_space_unmap(t, h, s) \
+ (*(t)->bs_unmap)((t)->bs_cookie, (h), (s))
+#define bus_space_subregion(t, h, o, s, hp) \
+ (*(t)->bs_subregion)((t)->bs_cookie, (h), (o), (s), (hp))
+
+
+/*
+ * Allocation and deallocation operations.
+ */
+#define bus_space_alloc(t, rs, re, s, a, b, c, ap, hp) \
+ (*(t)->bs_alloc)((t)->bs_cookie, (rs), (re), (s), (a), (b), \
+ (c), (ap), (hp))
+#define bus_space_free(t, h, s) \
+ (*(t)->bs_free)((t)->bs_cookie, (h), (s))
+
+/*
+ * Bus barrier operations.
+ */
+#define bus_space_barrier(t, h, o, l, f) \
+ (*(t)->bs_barrier)((t)->bs_cookie, (h), (o), (l), (f))
+
+
+
+/*
+ * Bus read (single) operations.
+ */
+#define bus_space_read_1(t, h, o) __bs_rs(1,(t),(h),(o))
+#define bus_space_read_2(t, h, o) __bs_rs(2,(t),(h),(o))
+#define bus_space_read_4(t, h, o) __bs_rs(4,(t),(h),(o))
+#define bus_space_read_8(t, h, o) __bs_rs(8,(t),(h),(o))
+
+#define bus_space_read_stream_1(t, h, o) __bs_rs_s(1,(t), (h), (o))
+#define bus_space_read_stream_2(t, h, o) __bs_rs_s(2,(t), (h), (o))
+#define bus_space_read_stream_4(t, h, o) __bs_rs_s(4,(t), (h), (o))
+#define bus_space_read_stream_8(t, h, o) __bs_rs_s(8,8,(t),(h),(o))
+
+/*
+ * Bus read multiple operations.
+ */
+#define bus_space_read_multi_1(t, h, o, a, c) \
+ __bs_nonsingle(rm,1,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_2(t, h, o, a, c) \
+ __bs_nonsingle(rm,2,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_4(t, h, o, a, c) \
+ __bs_nonsingle(rm,4,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_8(t, h, o, a, c) \
+ __bs_nonsingle(rm,8,(t),(h),(o),(a),(c))
+
+#define bus_space_read_multi_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,1,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,2,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,4,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,8,(t),(h),(o),(a),(c))
+
+
+/*
+ * Bus read region operations.
+ */
+#define bus_space_read_region_1(t, h, o, a, c) \
+ __bs_nonsingle(rr,1,(t),(h),(o),(a),(c))
+#define bus_space_read_region_2(t, h, o, a, c) \
+ __bs_nonsingle(rr,2,(t),(h),(o),(a),(c))
+#define bus_space_read_region_4(t, h, o, a, c) \
+ __bs_nonsingle(rr,4,(t),(h),(o),(a),(c))
+#define bus_space_read_region_8(t, h, o, a, c) \
+ __bs_nonsingle(rr,8,(t),(h),(o),(a),(c))
+
+#define bus_space_read_region_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,1,(t),(h),(o),(a),(c))
+#define bus_space_read_region_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,2,(t),(h),(o),(a),(c))
+#define bus_space_read_region_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,4,(t),(h),(o),(a),(c))
+#define bus_space_read_region_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,8,(t),(h),(o),(a),(c))
+
+
+/*
+ * Bus write (single) operations.
+ */
+#define bus_space_write_1(t, h, o, v) __bs_ws(1,(t),(h),(o),(v))
+#define bus_space_write_2(t, h, o, v) __bs_ws(2,(t),(h),(o),(v))
+#define bus_space_write_4(t, h, o, v) __bs_ws(4,(t),(h),(o),(v))
+#define bus_space_write_8(t, h, o, v) __bs_ws(8,(t),(h),(o),(v))
+
+#define bus_space_write_stream_1(t, h, o, v) __bs_ws_s(1,(t),(h),(o),(v))
+#define bus_space_write_stream_2(t, h, o, v) __bs_ws_s(2,(t),(h),(o),(v))
+#define bus_space_write_stream_4(t, h, o, v) __bs_ws_s(4,(t),(h),(o),(v))
+#define bus_space_write_stream_8(t, h, o, v) __bs_ws_s(8,(t),(h),(o),(v))
+
+
+/*
+ * Bus write multiple operations.
+ */
+#define bus_space_write_multi_1(t, h, o, a, c) \
+ __bs_nonsingle(wm,1,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_2(t, h, o, a, c) \
+ __bs_nonsingle(wm,2,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_4(t, h, o, a, c) \
+ __bs_nonsingle(wm,4,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_8(t, h, o, a, c) \
+ __bs_nonsingle(wm,8,(t),(h),(o),(a),(c))
+
+#define bus_space_write_multi_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,1,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,2,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,4,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,8,(t),(h),(o),(a),(c))
+
+
+/*
+ * Bus write region operations.
+ */
+#define bus_space_write_region_1(t, h, o, a, c) \
+ __bs_nonsingle(wr,1,(t),(h),(o),(a),(c))
+#define bus_space_write_region_2(t, h, o, a, c) \
+ __bs_nonsingle(wr,2,(t),(h),(o),(a),(c))
+#define bus_space_write_region_4(t, h, o, a, c) \
+ __bs_nonsingle(wr,4,(t),(h),(o),(a),(c))
+#define bus_space_write_region_8(t, h, o, a, c) \
+ __bs_nonsingle(wr,8,(t),(h),(o),(a),(c))
+
+#define bus_space_write_region_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,1,(t),(h),(o),(a),(c))
+#define bus_space_write_region_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,2,(t),(h),(o),(a),(c))
+#define bus_space_write_region_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,4,(t),(h),(o),(a),(c))
+#define bus_space_write_region_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,8,(t),(h),(o),(a),(c))
+
+
+/*
+ * Set multiple operations.
+ */
+#define bus_space_set_multi_1(t, h, o, v, c) \
+ __bs_set(sm,1,(t),(h),(o),(v),(c))
+#define bus_space_set_multi_2(t, h, o, v, c) \
+ __bs_set(sm,2,(t),(h),(o),(v),(c))
+#define bus_space_set_multi_4(t, h, o, v, c) \
+ __bs_set(sm,4,(t),(h),(o),(v),(c))
+#define bus_space_set_multi_8(t, h, o, v, c) \
+ __bs_set(sm,8,(t),(h),(o),(v),(c))
+
+
+/*
+ * Set region operations.
+ */
+#define bus_space_set_region_1(t, h, o, v, c) \
+ __bs_set(sr,1,(t),(h),(o),(v),(c))
+#define bus_space_set_region_2(t, h, o, v, c) \
+ __bs_set(sr,2,(t),(h),(o),(v),(c))
+#define bus_space_set_region_4(t, h, o, v, c) \
+ __bs_set(sr,4,(t),(h),(o),(v),(c))
+#define bus_space_set_region_8(t, h, o, v, c) \
+ __bs_set(sr,8,(t),(h),(o),(v),(c))
+
+
+/*
+ * Copy operations.
+ */
+#define bus_space_copy_region_1(t, h1, o1, h2, o2, c) \
+ __bs_copy(1, t, h1, o1, h2, o2, c)
+#define bus_space_copy_region_2(t, h1, o1, h2, o2, c) \
+ __bs_copy(2, t, h1, o1, h2, o2, c)
+#define bus_space_copy_region_4(t, h1, o1, h2, o2, c) \
+ __bs_copy(4, t, h1, o1, h2, o2, c)
+#define bus_space_copy_region_8(t, h1, o1, h2, o2, c) \
+ __bs_copy(8, t, h1, o1, h2, o2, c)
+
+#include <machine/bus_dma.h>
+
+#endif /* _MACHINE_BUS_H_ */
diff --git a/sys/arm64/include/bus_dma.h b/sys/arm64/include/bus_dma.h
new file mode 100644
index 0000000..b07d0f7
--- /dev/null
+++ b/sys/arm64/include/bus_dma.h
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+
+#ifndef _MACHINE_BUS_DMA_H_
+#define _MACHINE_BUS_DMA_H_
+
+#include <sys/bus_dma.h>
+
+#endif /* !_MACHINE_BUS_DMA_H_ */
diff --git a/sys/arm64/include/clock.h b/sys/arm64/include/clock.h
new file mode 100644
index 0000000..da23dbe
--- /dev/null
+++ b/sys/arm64/include/clock.h
@@ -0,0 +1 @@
+/* $FreeBSD$ */
diff --git a/sys/arm64/include/counter.h b/sys/arm64/include/counter.h
new file mode 100644
index 0000000..9d56cce
--- /dev/null
+++ b/sys/arm64/include/counter.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_COUNTER_H_
+#define _MACHINE_COUNTER_H_
+
+#include <sys/pcpu.h>
+#ifdef INVARIANTS
+#include <sys/proc.h>
+#endif
+
+#define counter_enter() critical_enter()
+#define counter_exit() critical_exit()
+
+#ifdef IN_SUBR_COUNTER_C
+static inline uint64_t
+counter_u64_read_one(uint64_t *p, int cpu)
+{
+
+ return (*(uint64_t *)((char *)p + sizeof(struct pcpu) * cpu));
+}
+
+static inline uint64_t
+counter_u64_fetch_inline(uint64_t *p)
+{
+ uint64_t r;
+ int i;
+
+ r = 0;
+ for (i = 0; i < mp_ncpus; i++)
+ r += counter_u64_read_one((uint64_t *)p, i);
+
+ return (r);
+}
+
+/* XXXKIB might interrupt increment */
+static void
+counter_u64_zero_one_cpu(void *arg)
+{
+
+ *((uint64_t *)((char *)arg + sizeof(struct pcpu) *
+ PCPU_GET(cpuid))) = 0;
+}
+
+static inline void
+counter_u64_zero_inline(counter_u64_t c)
+{
+
+ smp_rendezvous(smp_no_rendevous_barrier, counter_u64_zero_one_cpu,
+ smp_no_rendevous_barrier, c);
+}
+#endif
+
+#define counter_u64_add_protected(c, inc) do { \
+ CRITICAL_ASSERT(curthread); \
+ *(uint64_t *)zpcpu_get(c) += (inc); \
+} while (0)
+
+static inline void
+counter_u64_add(counter_u64_t c, int64_t inc)
+{
+
+ counter_enter();
+ counter_u64_add_protected(c, inc);
+ counter_exit();
+}
+
+#endif /* ! _MACHINE_COUNTER_H_ */
diff --git a/sys/arm64/include/cpufunc.h b/sys/arm64/include/cpufunc.h
index 08d5355..5a7f08b 100644
--- a/sys/arm64/include/cpufunc.h
+++ b/sys/arm64/include/cpufunc.h
@@ -109,6 +109,7 @@ get_mpidr(void)
}
#define cpu_nullop() arm64_nullop()
+#define cpufunc_nullop() arm64_nullop()
#define cpu_setttb(a) arm64_setttb(a)
#define cpu_tlb_flushID() arm64_tlb_flushID()
diff --git a/sys/arm64/include/db_machdep.h b/sys/arm64/include/db_machdep.h
new file mode 100644
index 0000000..b249256
--- /dev/null
+++ b/sys/arm64/include/db_machdep.h
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014-2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_DB_MACHDEP_H_
+#define _MACHINE_DB_MACHDEP_H_
+
+#include <machine/armreg.h>
+#include <machine/frame.h>
+#include <machine/trap.h>
+
+#define T_BREAKPOINT (EXCP_BRK)
+#define T_WATCHPOINT (EXCP_WATCHPT_EL1)
+
+typedef vm_offset_t db_addr_t;
+typedef long db_expr_t;
+
+#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_pc)
+
+#define BKPT_INST (0xd4200000)
+#define BKPT_SIZE (4)
+#define BKPT_SET(inst) (BKPT_INST)
+
+#define BKPT_SKIP do { \
+ kdb_frame->tf_elr += BKPT_SIZE; \
+} while (0)
+
+#define db_clear_single_step kdb_cpu_clear_singlestep
+#define db_set_single_step kdb_cpu_set_singlestep
+
+#define IS_BREAKPOINT_TRAP(type, code) (type == T_BREAKPOINT)
+#define IS_WATCHPOINT_TRAP(type, code) (type == T_WATCHPOINT)
+
+#define inst_trap_return(ins) (0)
+/* ret */
+#define inst_return(ins) (((ins) & 0xfffffc1fu) == 0xd65f0000)
+#define inst_call(ins) (((ins) & 0xfc000000u) == 0x94000000u || /* BL */ \
+ ((ins) & 0xfffffc1fu) == 0xd63f0000u) /* BLR */
+
+#define inst_load(ins) ({ \
+ uint32_t tmp_instr = db_get_value(PC_REGS(), sizeof(uint32_t), FALSE); \
+ is_load_instr(tmp_instr); \
+})
+
+#define inst_store(ins) ({ \
+ uint32_t tmp_instr = db_get_value(PC_REGS(), sizeof(uint32_t), FALSE); \
+ is_store_instr(tmp_instr); \
+})
+
+#define is_load_instr(ins) ((((ins) & 0x3b000000u) == 0x18000000u) || /* literal */ \
+ (((ins) & 0x3f400000u) == 0x08400000u) || /* exclusive */ \
+ (((ins) & 0x3bc00000u) == 0x28400000u) || /* no-allocate pair */ \
+ ((((ins) & 0x3b200c00u) == 0x38000400u) && \
+ (((ins) & 0x3be00c00u) != 0x38000400u) && \
+ (((ins) & 0xffe00c00u) != 0x3c800400u)) || /* immediate post-indexed */ \
+ ((((ins) & 0x3b200c00u) == 0x38000c00u) && \
+ (((ins) & 0x3be00c00u) != 0x38000c00u) && \
+ (((ins) & 0xffe00c00u) != 0x3c800c00u)) || /* immediate pre-indexed */ \
+ ((((ins) & 0x3b200c00u) == 0x38200800u) && \
+ (((ins) & 0x3be00c00u) != 0x38200800u) && \
+ (((ins) & 0xffe00c00u) != 0x3ca00c80u)) || /* register offset */ \
+ ((((ins) & 0x3b200c00u) == 0x38000800u) && \
+ (((ins) & 0x3be00c00u) != 0x38000800u)) || /* unprivileged */ \
+ ((((ins) & 0x3b200c00u) == 0x38000000u) && \
+ (((ins) & 0x3be00c00u) != 0x38000000u) && \
+ (((ins) & 0xffe00c00u) != 0x3c800000u)) || /* unscaled immediate */ \
+ ((((ins) & 0x3b000000u) == 0x39000000u) && \
+ (((ins) & 0x3bc00000u) != 0x39000000u) && \
+ (((ins) & 0xffc00000u) != 0x3d800000u)) && /* unsigned immediate */ \
+ (((ins) & 0x3bc00000u) == 0x28400000u) || /* pair (offset) */ \
+ (((ins) & 0x3bc00000u) == 0x28c00000u) || /* pair (post-indexed) */ \
+ (((ins) & 0x3bc00000u) == 0x29800000u)) /* pair (pre-indexed) */
+
+#define is_store_instr(ins) ((((ins) & 0x3f400000u) == 0x08000000u) || /* exclusive */ \
+ (((ins) & 0x3bc00000u) == 0x28000000u) || /* no-allocate pair */ \
+ ((((ins) & 0x3be00c00u) == 0x38000400u) || \
+ (((ins) & 0xffe00c00u) == 0x3c800400u)) || /* immediate post-indexed */ \
+ ((((ins) & 0x3be00c00u) == 0x38000c00u) || \
+ (((ins) & 0xffe00c00u) == 0x3c800c00u)) || /* immediate pre-indexed */ \
+ ((((ins) & 0x3be00c00u) == 0x38200800u) || \
+ (((ins) & 0xffe00c00u) == 0x3ca00800u)) || /* register offset */ \
+ (((ins) & 0x3be00c00u) == 0x38000800u) || /* unprivileged */ \
+ ((((ins) & 0x3be00c00u) == 0x38000000u) || \
+ (((ins) & 0xffe00c00u) == 0x3c800000u)) || /* unscaled immediate */ \
+ ((((ins) & 0x3bc00000u) == 0x39000000u) || \
+ (((ins) & 0xffc00000u) == 0x3d800000u)) || /* unsigned immediate */ \
+ (((ins) & 0x3bc00000u) == 0x28000000u) || /* pair (offset) */ \
+ (((ins) & 0x3bc00000u) == 0x28800000u) || /* pair (post-indexed) */ \
+ (((ins) & 0x3bc00000u) == 0x29800000u)) /* pair (pre-indexed) */
+
+#define next_instr_address(pc, bd) ((bd) ? (pc) : ((pc) + 4))
+
+#define DB_SMALL_VALUE_MAX (0x7fffffff)
+#define DB_SMALL_VALUE_MIN (-0x40001)
+
+#define DB_ELFSIZE 64
+
+#endif /* !_MACHINE_DB_MACHDEP_H_ */
diff --git a/sys/arm64/include/debug_monitor.h b/sys/arm64/include/debug_monitor.h
new file mode 100644
index 0000000..59a0cb8
--- /dev/null
+++ b/sys/arm64/include/debug_monitor.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_DEBUG_MONITOR_H_
+#define _MACHINE_DEBUG_MONITOR_H_
+
+#ifdef KDB
+
+#include <machine/db_machdep.h>
+
+enum dbg_el_t {
+ DBG_FROM_EL0 = 0,
+ DBG_FROM_EL1 = 1,
+};
+
+enum dbg_access_t {
+ HW_BREAKPOINT_X = 0,
+ HW_BREAKPOINT_R = 1,
+ HW_BREAKPOINT_W = 2,
+ HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W,
+};
+
+void dbg_monitor_init(void);
+void dbg_show_watchpoint(void);
+int dbg_setup_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_el_t el,
+ enum dbg_access_t access);
+int dbg_remove_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_el_t el);
+#else
+static __inline void
+dbg_monitor_init(void)
+{
+}
+#endif
+
+#endif /* _MACHINE_DEBUG_MONITOR_H_ */
diff --git a/sys/arm64/include/devmap.h b/sys/arm64/include/devmap.h
new file mode 100644
index 0000000..e205d9b
--- /dev/null
+++ b/sys/arm64/include/devmap.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_DEVMAP_H_
+#define _MACHINE_DEVMAP_H_
+
+/*
+ * This structure is used by MD code to describe static mappings of devices
+ * which are established as part of bringing up the MMU early in the boot.
+ */
+struct arm_devmap_entry {
+ vm_offset_t pd_va; /* virtual address */
+ vm_paddr_t pd_pa; /* physical address */
+ vm_size_t pd_size; /* size of region */
+ vm_prot_t pd_prot; /* protection code */
+ int pd_cache; /* cache attributes */
+};
+
+/*
+ * Return the lowest KVA address used in any entry in the registered devmap
+ * table. This works with whatever table is registered, including the internal
+ * table used by arm_devmap_add_entry() if that routine was used. Platforms can
+ * implement initarm_lastaddr() by calling this if static device mappings are
+ * their only use of high KVA space.
+ */
+vm_offset_t arm_devmap_lastaddr(void);
+
+/*
+ * Automatically allocate KVA (from the top of the address space downwards) and
+ * make static device mapping entries in an internal table. The internal table
+ * is automatically registered on the first call to this.
+ */
+void arm_devmap_add_entry(vm_paddr_t pa, vm_size_t sz);
+
+/*
+ * Register a platform-local table to be bootstrapped by the generic
+ * initarm() in arm/machdep.c. This is used by newer code that allocates and
+ * fills in its own local table but does not have its own initarm() routine.
+ */
+void arm_devmap_register_table(const struct arm_devmap_entry * _table);
+
+/*
+ * Establish mappings for all the entries in the table. This is called
+ * automatically from the common initarm() in arm/machdep.c, and also from the
+ * custom initarm() routines in older code. If the table pointer is NULL, this
+ * will use the table installed previously by arm_devmap_register_table().
+ */
+void arm_devmap_bootstrap(vm_offset_t _l1pt,
+ const struct arm_devmap_entry *_table);
+
+/*
+ * Translate between virtual and physical addresses within a region that is
+ * static-mapped by the devmap code. If the given address range isn't
+ * static-mapped, then ptov returns NULL and vtop returns DEVMAP_PADDR_NOTFOUND.
+ * The latter implies that you can't vtop just the last byte of physical address
+ * space. This is not as limiting as it might sound, because even if a device
+ * occupies the end of the physical address space, you're only prevented from
+ * doing vtop for that single byte. If you vtop a size bigger than 1 it works.
+ */
+#define DEVMAP_PADDR_NOTFOUND ((vm_paddr_t)(-1))
+
+void * arm_devmap_ptov(vm_paddr_t _pa, vm_size_t _sz);
+vm_paddr_t arm_devmap_vtop(void * _va, vm_size_t _sz);
+
+/* Print the static mapping table; used for bootverbose output. */
+void arm_devmap_print_table(void);
+
+#endif
diff --git a/sys/arm64/include/dump.h b/sys/arm64/include/dump.h
new file mode 100644
index 0000000..6f25375
--- /dev/null
+++ b/sys/arm64/include/dump.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2014 EMC Corp.
+ * Author: Conrad Meyer <conrad.meyer@isilon.com>
+ * Copyright (c) 2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_DUMP_H_
+#define _MACHINE_DUMP_H_
+
+#define KERNELDUMP_ARCH_VERSION KERNELDUMP_AARCH64_VERSION
+#define EM_VALUE EM_AARCH64
+/* XXX: I suppose 20 should be enough. */
+#define DUMPSYS_MD_PA_NPAIRS 20
+#define DUMPSYS_NUM_AUX_HDRS 1
+
+void dumpsys_wbinv_all(void);
+int dumpsys_write_aux_headers(struct dumperinfo *di);
+
+static inline void
+dumpsys_pa_init(void)
+{
+
+ dumpsys_gen_pa_init();
+}
+
+static inline struct dump_pa *
+dumpsys_pa_next(struct dump_pa *p)
+{
+
+ return (dumpsys_gen_pa_next(p));
+}
+
+static inline void
+dumpsys_unmap_chunk(vm_paddr_t pa, size_t s, void *va)
+{
+
+ dumpsys_gen_unmap_chunk(pa, s, va);
+}
+
+static inline int
+dumpsys(struct dumperinfo *di)
+{
+
+ return (dumpsys_generic(di));
+}
+
+#endif /* !_MACHINE_DUMP_H_ */
diff --git a/sys/arm64/include/hypervisor.h b/sys/arm64/include/hypervisor.h
new file mode 100644
index 0000000..4e9980f
--- /dev/null
+++ b/sys/arm64/include/hypervisor.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2013, 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_HYPERVISOR_H_
+#define _MACHINE_HYPERVISOR_H_
+
+/*
+ * These registers are only useful when in hypervisor context,
+ * e.g. specific to EL2, or controlling the hypervisor.
+ */
+
+/*
+ * Architecture feature trap register
+ */
+#define CPTR_RES0 0x7fefc800
+#define CPTR_RES1 0x000033ff
+#define CPTR_TFP 0x00000400
+#define CPTR_TTA 0x00100000
+#define CPTR_TCPAC 0x80000000
+
+/*
+ * Hypervisor Config Register
+ */
+
+#define HCR_VM 0x0000000000000001
+#define HCR_SWIO 0x0000000000000002
+#define HCR_PTW 0x0000000000000004
+#define HCR_FMO 0x0000000000000008
+#define HCR_IMO 0x0000000000000010
+#define HCR_AMO 0x0000000000000020
+#define HCR_VF 0x0000000000000040
+#define HCR_VI 0x0000000000000080
+#define HCR_VSE 0x0000000000000100
+#define HCR_FB 0x0000000000000200
+#define HCR_BSU_MASK 0x0000000000000c00
+#define HCR_DC 0x0000000000001000
+#define HCR_TWI 0x0000000000002000
+#define HCR_TWE 0x0000000000004000
+#define HCR_TID0 0x0000000000008000
+#define HCR_TID1 0x0000000000010000
+#define HCR_TID2 0x0000000000020000
+#define HCR_TID3 0x0000000000040000
+#define HCR_TSC 0x0000000000080000
+#define HCR_TIDCP 0x0000000000100000
+#define HCR_TACR 0x0000000000200000
+#define HCR_TSW 0x0000000000400000
+#define HCR_TPC 0x0000000000800000
+#define HCR_TPU 0x0000000001000000
+#define HCR_TTLB 0x0000000002000000
+#define HCR_TVM 0x0000000004000000
+#define HCR_TGE 0x0000000008000000
+#define HCR_TDZ 0x0000000010000000
+#define HCR_HCD 0x0000000020000000
+#define HCR_TRVM 0x0000000040000000
+#define HCR_RW 0x0000000080000000
+#define HCR_CD 0x0000000100000000
+#define HCR_ID 0x0000000200000000
+
+#endif
+
diff --git a/lib/libc/sys/ftruncate.c b/sys/arm64/include/in_cksum.h
index 78b5a36..40524e4 100644
--- a/lib/libc/sys/ftruncate.c
+++ b/sys/arm64/include/in_cksum.h
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,6 +10,10 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -25,31 +29,28 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * from tahoe: in_cksum.c 1.2 86/01/05
+ * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91
+ * from: Id: in_cksum.c,v 1.8 1995/12/03 18:35:19 bde Exp
+ * $FreeBSD$
*/
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)ftruncate.c 8.1 (Berkeley) 6/17/93";
-#endif /* LIBC_SCCS and not lint */
+#ifndef _MACHINE_IN_CKSUM_H_
+#define _MACHINE_IN_CKSUM_H_ 1
+
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-#include <sys/types.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include "libc_private.h"
+#ifdef _KERNEL
+#define in_cksum(m, len) in_cksum_skip(m, len, 0)
+u_short in_addword(u_short sum, u_short b);
+u_short in_cksum_skip(struct mbuf *m, int len, int skip);
+u_int do_cksum(const void *, int);
+#if defined(IPVERSION) && (IPVERSION == 4)
+u_int in_cksum_hdr(const struct ip *);
+#endif
-/*
- * This function provides 64-bit offset padding that
- * is not supplied by GCC 1.X but is supplied by GCC 2.X.
- */
-int
-ftruncate(fd, length)
- int fd;
- off_t length;
-{
+u_short in_pseudo(u_int sum, u_int b, u_int c);
- if (__getosreldate() >= 700051)
- return(__sys_ftruncate(fd, length));
- else
- return(__sys_freebsd6_ftruncate(fd, 0, length));
-}
+#endif /* _KERNEL */
+#endif /* _MACHINE_IN_CKSUM_H_ */
diff --git a/sys/arm64/include/intr.h b/sys/arm64/include/intr.h
new file mode 100644
index 0000000..1031c64
--- /dev/null
+++ b/sys/arm64/include/intr.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner <andrew@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_INTR_H_
+#define _MACHINE_INTR_H_
+
+int arm_config_intr(u_int, enum intr_trigger, enum intr_polarity);
+void arm_cpu_intr(struct trapframe *);
+void arm_dispatch_intr(u_int, struct trapframe *);
+int arm_enable_intr(void);
+void arm_mask_irq(u_int);
+void arm_register_root_pic(device_t, u_int);
+void arm_register_msi_pic(device_t);
+int arm_alloc_msi(device_t, int, int *);
+int arm_release_msi(device_t, int, int *);
+int arm_alloc_msix(device_t, int *);
+int arm_release_msix(device_t, int);
+int arm_map_msi(device_t, int, uint64_t *, uint32_t *);
+int arm_map_msix(device_t, int, uint64_t *, uint32_t *);
+int arm_setup_intr(const char *, driver_filter_t *, driver_intr_t,
+ void *, u_int, enum intr_type, void **);
+int arm_teardown_intr(void *);
+void arm_unmask_irq(u_int);
+
+#ifdef SMP
+void arm_init_secondary(void);
+void arm_setup_ipihandler(driver_filter_t *, u_int);
+void arm_unmask_ipi(u_int);
+#endif
+
+#endif /* _MACHINE_INTR_H */
diff --git a/sys/arm64/include/kdb.h b/sys/arm64/include/kdb.h
new file mode 100644
index 0000000..e4f4f70
--- /dev/null
+++ b/sys/arm64/include/kdb.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_KDB_H_
+#define _MACHINE_KDB_H_
+
+#include <machine/cpufunc.h>
+
+#define KDB_STOPPEDPCB(pc) &stoppcbs[pc->pc_cpuid]
+
+void kdb_cpu_clear_singlestep(void);
+void kdb_cpu_set_singlestep(void);
+
+static __inline void
+kdb_cpu_sync_icache(unsigned char *addr, size_t size)
+{
+}
+
+static __inline void
+kdb_cpu_trap(int type, int code)
+{
+}
+
+#endif /* _MACHINE_KDB_H_ */
diff --git a/sys/arm64/include/machdep.h b/sys/arm64/include/machdep.h
new file mode 100644
index 0000000..92c735b
--- /dev/null
+++ b/sys/arm64/include/machdep.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2013 Andrew Turner <andrew@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_MACHDEP_H_
+#define _MACHINE_MACHDEP_H_
+
+struct arm64_bootparams {
+ vm_offset_t modulep;
+ vm_offset_t kern_l1pt; /* L1 page table for the kernel */
+ uint64_t kern_delta;
+ vm_offset_t kern_stack;
+};
+
+extern vm_paddr_t physmap[];
+extern u_int physmap_idx;
+
+void initarm(struct arm64_bootparams *);
+
+#endif /* _MACHINE_MACHDEP_H_ */
diff --git a/lib/libc/sys/truncate.c b/sys/arm64/include/md_var.h
index 375c9d9..3bdb5e5 100644
--- a/lib/libc/sys/truncate.c
+++ b/sys/arm64/include/md_var.h
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
+/*-
+ * Copyright (c) 1995 Bruce D. Evans.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,14 +10,14 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the author nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -25,31 +25,20 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * from: FreeBSD: src/sys/i386/include/md_var.h,v 1.40 2001/07/12
+ * $FreeBSD$
*/
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)truncate.c 8.1 (Berkeley) 6/17/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#ifndef _MACHINE_MD_VAR_H_
+#define _MACHINE_MD_VAR_H_
-#include <sys/types.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include "libc_private.h"
+extern long Maxmem;
+extern char sigcode[];
+extern int szsigcode;
-/*
- * This function provides 64-bit offset padding that
- * is not supplied by GCC 1.X but is supplied by GCC 2.X.
- */
-int
-truncate(path, length)
- const char *path;
- off_t length;
-{
+struct dumperinfo;
+int minidumpsys(struct dumperinfo *);
+void busdma_swi(void);
- if (__getosreldate() >= 700051)
- return(__sys_truncate(path, length));
- else
- return(__sys_freebsd6_truncate(path, 0, length));
-}
+#endif /* !_MACHINE_MD_VAR_H_ */
diff --git a/sys/arm64/include/memdev.h b/sys/arm64/include/memdev.h
new file mode 100644
index 0000000..f16ba16
--- /dev/null
+++ b/sys/arm64/include/memdev.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2004 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_MEMDEV_H_
+#define _MACHINE_MEMDEV_H_
+
+#define CDEV_MINOR_MEM 0
+#define CDEV_MINOR_KMEM 1
+
+d_open_t memopen;
+d_read_t memrw;
+#define memioctl (d_ioctl_t *)NULL
+#define memmmap (d_mmap_t *)NULL
+
+#endif /* _MACHINE_MEMDEV_H_ */
diff --git a/sys/arm64/include/metadata.h b/sys/arm64/include/metadata.h
new file mode 100644
index 0000000..090e908
--- /dev/null
+++ b/sys/arm64/include/metadata.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner <andrew@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_METADATA_H_
+#define _MACHINE_METADATA_H_
+
+#define MODINFOMD_EFI_MAP 0x1001
+#define MODINFOMD_DTBP 0x1002
+
+struct efi_map_header {
+ size_t memory_size;
+ size_t descriptor_size;
+ uint32_t descriptor_version;
+};
+
+#endif /* !_MACHINE_METADATA_H_ */
diff --git a/sys/arm64/include/ofw_machdep.h b/sys/arm64/include/ofw_machdep.h
new file mode 100644
index 0000000..511fc8d
--- /dev/null
+++ b/sys/arm64/include/ofw_machdep.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2009 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_OFW_MACHDEP_H_
+#define _MACHINE_OFW_MACHDEP_H_
+
+#include <vm/vm.h>
+
+typedef uint32_t cell_t;
+
+struct mem_region {
+ vm_offset_t mr_start;
+ vm_size_t mr_size;
+};
+
+#endif /* _MACHINE_OFW_MACHDEP_H_ */
diff --git a/sys/arm64/include/param.h b/sys/arm64/include/param.h
index 3dac7a1..412e619 100644
--- a/sys/arm64/include/param.h
+++ b/sys/arm64/include/param.h
@@ -118,8 +118,4 @@
#define pgtok(x) ((unsigned long)(x) * (PAGE_SIZE / 1024))
-#ifdef _KERNEL
-#define NO_FUEWORD 1
-#endif
-
#endif /* !_MACHINE_PARAM_H_ */
diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h
index 338601b..63ae34c 100644
--- a/sys/arm64/include/pmap.h
+++ b/sys/arm64/include/pmap.h
@@ -136,12 +136,15 @@ extern vm_offset_t virtual_end;
void pmap_bootstrap(vm_offset_t, vm_paddr_t, vm_size_t);
void pmap_kenter(vm_offset_t, vm_paddr_t);
-void pmap_kenter_device(vm_offset_t, vm_paddr_t);
+void pmap_kenter_device(vm_offset_t, vm_size_t, vm_paddr_t);
vm_paddr_t pmap_kextract(vm_offset_t va);
void pmap_kremove(vm_offset_t);
+void pmap_kremove_device(vm_offset_t, vm_size_t);
void *pmap_mapdev(vm_offset_t, vm_size_t);
+void *pmap_mapbios(vm_paddr_t, vm_size_t);
void pmap_unmapdev(vm_offset_t, vm_size_t);
+void pmap_unmapbios(vm_offset_t, vm_size_t);
boolean_t pmap_map_io_transient(vm_page_t *, vm_offset_t *, int, boolean_t);
void pmap_unmap_io_transient(vm_page_t *, vm_offset_t *, int, boolean_t);
diff --git a/sys/arm64/include/psl.h b/sys/arm64/include/psl.h
new file mode 100644
index 0000000..da23dbe
--- /dev/null
+++ b/sys/arm64/include/psl.h
@@ -0,0 +1 @@
+/* $FreeBSD$ */
diff --git a/sys/arm64/include/resource.h b/sys/arm64/include/resource.h
new file mode 100644
index 0000000..723d145
--- /dev/null
+++ b/sys/arm64/include/resource.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright 1998 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_RESOURCE_H_
+#define _MACHINE_RESOURCE_H_ 1
+
+/*
+ * Definitions of resource types for Intel Architecture machines
+ * with support for legacy ISA devices and drivers.
+ */
+
+#define SYS_RES_IRQ 1 /* interrupt lines */
+#define SYS_RES_DRQ 2 /* isa dma lines */
+#define SYS_RES_MEMORY 3 /* i/o memory */
+#define SYS_RES_IOPORT 4 /* i/o ports */
+#define SYS_RES_GPIO 5 /* general purpose i/o */
+
+#endif /* !_MACHINE_RESOURCE_H_ */
diff --git a/sys/arm64/include/sf_buf.h b/sys/arm64/include/sf_buf.h
new file mode 100644
index 0000000..59f9009
--- /dev/null
+++ b/sys/arm64/include/sf_buf.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2003, 2005 Alan L. Cox <alc@cs.rice.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_SF_BUF_H_
+#define _MACHINE_SF_BUF_H_
+
+/*
+ * On this machine, the only purpose for which sf_buf is used is to implement
+ * an opaque pointer required by the machine-independent parts of the kernel.
+ * That pointer references the vm_page that is "mapped" by the sf_buf. The
+ * actual mapping is provided by the direct virtual-to-physical mapping.
+ */
+static inline vm_offset_t
+sf_buf_kva(struct sf_buf *sf)
+{
+
+ return (PHYS_TO_DMAP(VM_PAGE_TO_PHYS((vm_page_t)sf)));
+}
+
+static inline vm_page_t
+sf_buf_page(struct sf_buf *sf)
+{
+
+ return ((vm_page_t)sf);
+}
+#endif /* !_MACHINE_SF_BUF_H_ */
diff --git a/sys/arm64/include/smp.h b/sys/arm64/include/smp.h
new file mode 100644
index 0000000..da23dbe
--- /dev/null
+++ b/sys/arm64/include/smp.h
@@ -0,0 +1 @@
+/* $FreeBSD$ */
diff --git a/sys/arm64/include/stack.h b/sys/arm64/include/stack.h
new file mode 100644
index 0000000..8131ce5
--- /dev/null
+++ b/sys/arm64/include/stack.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_STACK_H_
+#define _MACHINE_STACK_H_
+
+#define INKERNEL(va) \
+ ((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
+
+#endif /* !_MACHINE_STACK_H_ */
diff --git a/sys/arm64/include/trap.h b/sys/arm64/include/trap.h
new file mode 100644
index 0000000..da23dbe
--- /dev/null
+++ b/sys/arm64/include/trap.h
@@ -0,0 +1 @@
+/* $FreeBSD$ */
diff --git a/sys/arm64/include/vfp.h b/sys/arm64/include/vfp.h
new file mode 100644
index 0000000..ccb853c
--- /dev/null
+++ b/sys/arm64/include/vfp.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_VFP_H_
+#define _MACHINE_VFP_H_
+
+#ifdef _KERNEL
+
+#ifndef LOCORE
+void vfp_init(void);
+void vfp_discard(struct thread *);
+void vfp_restore_state(void);
+void vfp_save_state(struct thread *);
+#endif
+
+#endif
+
+#endif /* !_MACHINE_VFP_H_ */
diff --git a/sys/boot/Makefile b/sys/boot/Makefile
index 172255e..2aa76b7 100644
--- a/sys/boot/Makefile
+++ b/sys/boot/Makefile
@@ -5,6 +5,7 @@
.if ${MK_FORTH} != "no"
# Build the add-in FORTH interpreter.
SUBDIR+= ficl
+SUBDIR+= forth
.endif
.include <bsd.arch.inc.mk>
diff --git a/sys/boot/Makefile.arm b/sys/boot/Makefile.arm
index 46fc574..bb0e01c 100644
--- a/sys/boot/Makefile.arm
+++ b/sys/boot/Makefile.arm
@@ -4,4 +4,4 @@
SUBDIR+= fdt
.endif
-SUBDIR+= uboot
+SUBDIR+= efi uboot
diff --git a/sys/boot/Makefile.arm64 b/sys/boot/Makefile.arm64
new file mode 100644
index 0000000..116e903
--- /dev/null
+++ b/sys/boot/Makefile.arm64
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.if ${MK_FDT} != "no"
+SUBDIR+= fdt
+.endif
+
+SUBDIR+= efi
diff --git a/sys/boot/arm64/Makefile b/sys/boot/arm64/Makefile
new file mode 100644
index 0000000..3ecb582
--- /dev/null
+++ b/sys/boot/arm64/Makefile
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include <bsd.subdir.mk>
diff --git a/sys/boot/arm64/libarm64/cache.c b/sys/boot/arm64/libarm64/cache.c
new file mode 100644
index 0000000..2b3c0b1
--- /dev/null
+++ b/sys/boot/arm64/libarm64/cache.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <machine/armreg.h>
+
+#include <stand.h>
+#include <efi.h>
+
+#include "cache.h"
+
+static unsigned int
+get_dcache_line_size(void)
+{
+ uint64_t ctr;
+ unsigned int dcl_size;
+
+ /* Accessible from all security levels */
+ ctr = READ_SPECIALREG(ctr_el0);
+
+ /*
+ * Relevant field [19:16] is LOG2
+ * of the number of words in DCache line
+ */
+ dcl_size = CTR_DLINE_SIZE(ctr);
+
+ /* Size of word shifted by cache line size */
+ return (sizeof(int) << dcl_size);
+}
+
+void
+cpu_flush_dcache(const void *ptr, size_t len)
+{
+
+ uint64_t cl_size;
+ vm_offset_t addr, end;
+
+ cl_size = get_dcache_line_size();
+
+ /* Calculate end address to clean */
+ end = (vm_offset_t)(ptr + len);
+ /* Align start address to cache line */
+ addr = (vm_offset_t)ptr;
+ addr = rounddown2(addr, cl_size);
+
+ for (; addr < end; addr += cl_size)
+ __asm __volatile("dc civac, %0" : : "r" (addr) : "memory");
+ /* Full system DSB */
+ __asm __volatile("dsb sy" : : : "memory");
+}
+
+void
+cpu_inval_icache(const void *ptr, size_t len)
+{
+
+ /* NULL ptr or 0 len means all */
+ if (ptr == NULL || len == 0) {
+ __asm __volatile(
+ "ic ialluis \n"
+ "dsb ish \n"
+ : : : "memory");
+ return;
+ }
+
+ /* TODO: Other cache ranges if necessary */
+}
diff --git a/sys/boot/arm64/libarm64/cache.h b/sys/boot/arm64/libarm64/cache.h
new file mode 100644
index 0000000..89b094b
--- /dev/null
+++ b/sys/boot/arm64/libarm64/cache.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of the FreeBSD Foundation.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CACHE_H_
+#define _CACHE_H_
+
+/* cache.c */
+void cpu_flush_dcache(const void *, size_t);
+void cpu_inval_icache(const void *, size_t);
+
+#endif /* _CACHE_H_ */
diff --git a/sys/boot/common/Makefile.inc b/sys/boot/common/Makefile.inc
index dde6879..54e8617 100644
--- a/sys/boot/common/Makefile.inc
+++ b/sys/boot/common/Makefile.inc
@@ -9,6 +9,8 @@ SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c
SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c
.elif ${MACHINE} == "pc98"
SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c
+.elif ${MACHINE_CPUARCH} == "aarch64"
+SRCS+= load_elf64.c reloc_elf64.c
.elif ${MACHINE_CPUARCH} == "arm"
SRCS+= load_elf32.c reloc_elf32.c
.elif ${MACHINE_CPUARCH} == "powerpc"
@@ -56,16 +58,6 @@ SRCS+= pnp.c
# Forth interpreter
.if defined(BOOT_FORTH)
SRCS+= interp_forth.c
-MAN+= ../forth/beastie.4th.8
-MAN+= ../forth/brand.4th.8
-MAN+= ../forth/check-password.4th.8
-MAN+= ../forth/color.4th.8
-MAN+= ../forth/delay.4th.8
-MAN+= ../forth/loader.conf.5
-MAN+= ../forth/loader.4th.8
-MAN+= ../forth/menu.4th.8
-MAN+= ../forth/menusets.4th.8
-MAN+= ../forth/version.4th.8
.endif
.if defined(BOOT_PROMPT_123)
diff --git a/sys/boot/common/md.c b/sys/boot/common/md.c
index 6d2d2b4..a8f092b9 100644
--- a/sys/boot/common/md.c
+++ b/sys/boot/common/md.c
@@ -27,11 +27,11 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <stand.h>
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/queue.h>
#include <machine/stdarg.h>
-#include <stand.h>
#include "bootstrap.h"
diff --git a/sys/boot/efi/Makefile b/sys/boot/efi/Makefile
index 5dfb648..57d4e81 100644
--- a/sys/boot/efi/Makefile
+++ b/sys/boot/efi/Makefile
@@ -1,8 +1,18 @@
# $FreeBSD$
+.include <src.opts.mk>
+
SUBDIR= libefi
-.if ${MACHINE_CPUARCH} == "amd64"
+.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm"
+.if ${MK_FDT} != "no"
+SUBDIR+= fdt
+.endif
+.endif
+
+.if ${MACHINE_CPUARCH} == "aarch64" || \
+ ${MACHINE_CPUARCH} == "amd64" || \
+ ${MACHINE_CPUARCH} == "arm"
SUBDIR+= loader boot1
.endif
diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile
index 2bcdc31..e611063 100644
--- a/sys/boot/efi/boot1/Makefile
+++ b/sys/boot/efi/boot1/Makefile
@@ -15,27 +15,38 @@ INTERNALPROG=
# architecture-specific loader code
SRCS= boot1.c reloc.c start.S
-CFLAGS+= -fPIC
CFLAGS+= -I.
CFLAGS+= -I${.CURDIR}/../include
-CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH}
+CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include
CFLAGS+= -I${.CURDIR}/../../..
# Always add MI sources and REGULAR efi loader bits
-.PATH: ${.CURDIR}/../loader/arch/${MACHINE_CPUARCH} ${.CURDIR}/../../common
+.PATH: ${.CURDIR}/../loader/arch/${MACHINE}
+.PATH: ${.CURDIR}/../loader
+.PATH: ${.CURDIR}/../../common
CFLAGS+= -I${.CURDIR}/../../common
FILES= boot1.efi boot1.efifat
FILESMODE_boot1.efi= ${BINMODE}
-LDSCRIPT= ${.CURDIR}/../loader/arch/${MACHINE_CPUARCH}/ldscript.${MACHINE_CPUARCH}
+LDSCRIPT= ${.CURDIR}/../loader/arch/${MACHINE}/ldscript.${MACHINE}
LDFLAGS= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
+CFLAGS+= -fPIC
LDFLAGS+= -Wl,-znocombreloc
.endif
+.if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "i386"
+#
+# Add libstand for the runtime functions used by the compiler - for example
+# __aeabi_* (arm) or __divdi3 (i386).
+#
+DPADD+= ${LIBSTAND}
+LDADD+= -lstand
+.endif
+
${PROG}: ${LDSCRIPT}
OBJCOPY?= objcopy
@@ -45,6 +56,8 @@ OBJDUMP?= objdump
EFI_TARGET= efi-app-x86_64
.elif ${MACHINE_CPUARCH} == "i386"
EFI_TARGET= efi-app-ia32
+.else
+EFI_TARGET= binary
.endif
boot1.efi: loader.sym
@@ -52,7 +65,7 @@ boot1.efi: loader.sym
${OBJDUMP} -t ${.ALLSRC} | fgrep '*UND*'; \
exit 1; \
fi
- ${OBJCOPY} -j .text -j .sdata -j .data \
+ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \
-j .dynamic -j .dynsym -j .rel.dyn \
-j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \
--output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET}
@@ -66,24 +79,27 @@ boot1.o: ${.CURDIR}/../../common/ufsread.c
boot1.efifat: boot1.efi
echo ${.OBJDIR}
- uudecode ${.CURDIR}/fat.tmpl.bz2.uu
- mv fat.tmpl.bz2 ${.TARGET}.bz2
+ uudecode ${.CURDIR}/fat-${MACHINE}.tmpl.bz2.uu
+ mv fat-${MACHINE}.tmpl.bz2 ${.TARGET}.bz2
bzip2 -f -d ${.TARGET}.bz2
dd if=boot1.efi of=${.TARGET} seek=${BOOT1_OFFSET} conv=notrunc
-CLEANFILES= boot1.efifat
+CLEANFILES= boot1.efi boot1.efifat
.endif # ${COMPILER_TYPE} != "gcc"
.include <bsd.prog.mk>
-.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
-beforedepend ${OBJS}: machine x86
+beforedepend ${OBJS}: machine
-CLEANFILES+= machine x86 boot1.efi
+CLEANFILES+= machine
machine:
- ln -sf ${.CURDIR}/../../../amd64/include machine
+ ln -sf ${.CURDIR}/../../../${MACHINE}/include machine
+
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
+beforedepend ${OBJS}: x86
+CLEANFILES+= x86
x86:
ln -sf ${.CURDIR}/../../../x86/include x86
diff --git a/sys/boot/efi/boot1/boot1.c b/sys/boot/efi/boot1/boot1.c
index e5719ff..eff191b 100644
--- a/sys/boot/efi/boot1/boot1.c
+++ b/sys/boot/efi/boot1/boot1.c
@@ -30,7 +30,7 @@ __FBSDID("$FreeBSD$");
#define _PATH_LOADER "/boot/loader.efi"
#define _PATH_KERNEL "/boot/kernel/kernel"
-
+
#define BSIZEMAX 16384
typedef int putc_func_t(char c, void *arg);
@@ -40,7 +40,7 @@ struct sp_data {
u_int sp_len;
u_int sp_size;
};
-
+
static const char digits[] = "0123456789abcdef";
static void panic(const char *fmt, ...) __dead2;
@@ -59,10 +59,10 @@ static char *__ultoa(char *buf, u_long val, int base);
static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
static void load(const char *fname);
-EFI_SYSTEM_TABLE *systab;
-EFI_HANDLE *image;
+static EFI_SYSTEM_TABLE *systab;
+static EFI_HANDLE *image;
-static void
+static void
bcopy(const void *src, void *dst, size_t len)
{
const char *s = src;
@@ -71,12 +71,12 @@ bcopy(const void *src, void *dst, size_t len)
while (len-- != 0)
*d++ = *s++;
}
-
+
static void
memcpy(void *dst, const void *src, size_t len)
{
bcopy(src, dst, len);
-}
+}
static void
bzero(void *b, size_t len)
@@ -86,7 +86,7 @@ bzero(void *b, size_t len)
while (len-- != 0)
*p++ = 0;
}
-
+
static int
strcmp(const char *s1, const char *s2)
{
@@ -108,11 +108,12 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
{
EFI_HANDLE handles[128];
EFI_BLOCK_IO *blkio;
- UINTN i, nparts = sizeof(handles);
+ UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
EFI_STATUS status;
EFI_DEVICE_PATH *devpath;
EFI_BOOT_SERVICES *BS;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
+ SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
char *path = _PATH_LOADER;
systab = Xsystab;
@@ -124,8 +125,29 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
if (status == EFI_SUCCESS)
(void)ConsoleControl->SetMode(ConsoleControl,
EfiConsoleControlScreenText);
+ /*
+ * Reset the console and find the best text mode.
+ */
+ conout = systab->ConOut;
+ conout->Reset(conout, TRUE);
+ max_dim = best_mode = 0;
+ for (i = 0; ; i++) {
+ status = conout->QueryMode(conout, i,
+ &cols, &rows);
+ if (EFI_ERROR(status))
+ break;
+ if (cols * rows > max_dim) {
+ max_dim = cols * rows;
+ best_mode = i;
+ }
+ }
+ if (max_dim > 0)
+ conout->SetMode(conout, best_mode);
+ conout->EnableCursor(conout, TRUE);
+ conout->ClearScreen(conout);
- printf(" \n>> FreeBSD EFI boot block\n");
+ printf("\n"
+ ">> FreeBSD EFI boot block\n");
printf(" Loader path: %s\n", path);
status = systab->BootServices->LocateHandle(ByProtocol,
@@ -134,7 +156,7 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
for (i = 0; i < nparts; i++) {
status = systab->BootServices->HandleProtocol(handles[i],
- &DevicePathGUID, (void **)&devpath);
+ &DevicePathGUID, (void **)&devpath);
if (EFI_ERROR(status))
continue;
@@ -142,7 +164,7 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
devpath = NextDevicePathNode(devpath);
status = systab->BootServices->HandleProtocol(handles[i],
- &BlockIoProtocolGUID, (void **)&blkio);
+ &BlockIoProtocolGUID, (void **)&blkio);
if (EFI_ERROR(status))
continue;
@@ -158,7 +180,7 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
bootdevhandle = handles[i];
load(path);
-
+
panic("Load failed");
return EFI_SUCCESS;
@@ -266,7 +288,7 @@ fsstat(ufs_ino_t inode)
}
static struct dmadat __dmadat;
-
+
static int
domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
{
@@ -278,7 +300,7 @@ domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
if (!quiet)
printf("domount: can't read superblock\n");
return (-1);
- }
+ }
if (!quiet)
printf("Succesfully mounted UFS filesystem\n");
return (0);
@@ -303,23 +325,23 @@ load(const char *fname)
status = systab->BootServices->AllocatePool(EfiLoaderData,
bufsize, &buffer);
fsread(ino, buffer, bufsize);
-
+
/* XXX: For secure boot, we need our own loader here */
status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
buffer, bufsize, &loaderhandle);
if (EFI_ERROR(status))
- printf("LoadImage failed with error %d\n", status);
+ printf("LoadImage failed with error %lx\n", status);
status = systab->BootServices->HandleProtocol(loaderhandle,
&LoadedImageGUID, (VOID**)&loaded_image);
if (EFI_ERROR(status))
- printf("HandleProtocol failed with error %d\n", status);
+ printf("HandleProtocol failed with error %lx\n", status);
loaded_image->DeviceHandle = bootdevhandle;
status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
if (EFI_ERROR(status))
- printf("StartImage failed with error %d\n", status);
+ printf("StartImage failed with error %lx\n", status);
}
static void
@@ -549,4 +571,3 @@ __ultoa(char *buf, u_long ul, int base)
while ((ul /= base) != 0);
return (p);
}
-
diff --git a/sys/boot/efi/boot1/fat.tmpl.bz2.uu b/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu
index c9044ee..d8a44b7 100644
--- a/sys/boot/efi/boot1/fat.tmpl.bz2.uu
+++ b/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu
@@ -1,7 +1,7 @@
FAT template boot filesystem created by generate-fat.sh
DO NOT EDIT
$FreeBSD$
-begin 644 fat.tmpl.bz2
+begin 644 fat-amd64.tmpl.bz2
M0EIH.3%!629362AK*D(`&I+____[ZZKJZ_^N_ZO^Z_Z_OJ[L`4`!7I0$#&$"
M0$!$3&(<P`(;J*C:0E0E#30&AH`T````9#0```9````#)ZF0:,-3U/409,`)
M@`"8`C3",````$R:8F@P`C`````"24U,D>I-DTU,)ZAZ0VA-!M0T'J`>H#"9
diff --git a/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu b/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu
new file mode 100644
index 0000000..15b59d8
--- /dev/null
+++ b/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu
@@ -0,0 +1,26 @@
+FAT template boot filesystem created by generate-fat.sh
+DO NOT EDIT
+$FreeBSD$
+begin 644 fat-arm.tmpl.bz2
+M0EIH.3%!629365NH-?4`&T!_____ZZ[J[_ZN_ZO^J_Z[OJ_^J^J[^KZNKNNJ
+MZNKNZOJ^P`+\#$``0`&AD:,@TTTT-&C30#$R&FF1H:!B&)D&F@```-&AB::#
+M1HP0-,AD`T8F(TTP2JII&?^I5/]4`@TTT-&(T8FAB:&@T:8F(Q!@!`9,1DR9
+M`-,$:,FC)B&FC"8"#3"#(-,0`&AD:,@TTTT-&C30#$R&FF1H:!B&)D&F@```
+M-&AB::#1HP0-,AD`T8F(TTP*HI)D\DFDVC0AIIH]3(:-``80>HTTR!IH::#$
+M-`Q`:`/2:::&)IDP"/0$T:>IFD]$R8---3HUK2<PNK%<6\J]BA",-*(A%:0B
+M(B#G5%F8B$$(68C_:!`A#OL<HAB+JZ6UHRRU>*K9].C:!IWS-2UK9M<WC]W[
+M+]QW,9%V2,?<"ZEO9B("$,I.0ZFE66K/,<N6+8ITS$J3))F2I4HJ5*E2I74J
+M:$J5*E2I4JE5*I*I-2I4J5.;84I4J5*E2I6ZU4Q*E2I4J5+X<SOK,65E965D
+MT:($(0A"$(0A"$(0C>.3@8,&#!@P8(0A"$(0@0A"$(0[;_L-&C1HT:-&B+YP
+M,&#!@P8,$"$(0A"-?NW$*YY:V9IQ,:B93+AX^A7B),5HN_4JV=2\Y,:-+W'Q
+MKQKVU7KA+YR'.:*V#48N-"7<`%:TT4D`/;N;SZM9X,V(@!D'=P==+O)9*\H8
+MI8W<L9:.AU[N;G"QEHLZBWB/2B.SKCGRM):%ZK3-2U3ZV1;%MUZX:^?X_Y@N
+MM=0SN1R7Z\&PN,I8VVWKMS$1-X41%"V)-;+V9:MI5;.+M*TMZ]K7HQ-ALY1\
+M4LG)\#5/I7#7-D_1<KUPE\OW)<YEW=.GMJ%$MUF)TE9N)8[M[6LIEXF@H6?S
+MW%U89M5M+:LW6(\?7Z6I:U4F>IM*Q<2E)KFG;%M&U;INV]<)Q%^P'*<]T6R;
+M^7`P.+I+N(HA%=#(^Q0WVV0]=$2=5)>-XWKW7!95E7$<5QW)<IS6"PF@7&+H
+M&<ETI.`9F48V7/E&??ROG%<9FU^Y#E.8W+GL%]#L7+U=^CY91Q\+`K'-WPF4
+M.2S[EM@S38.8YKG.@P6_83I,-<G1DPY84N-)VMWK,/!;AIJ&3E%&7B`0A,`&
+3'65I7J6`B^?^+N2*<*$@MU!KZ@``
+`
+end
diff --git a/sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu b/sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu
new file mode 100644
index 0000000..031815c
--- /dev/null
+++ b/sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu
@@ -0,0 +1,26 @@
+FAT template boot filesystem created by generate-fat.sh
+DO NOT EDIT
+$FreeBSD$
+begin 644 fat-arm64.tmpl.bz2
+M0EIH.3%!62936:2BH:(`&T#_____ZZKJ[_^N_ZO_J_Z[OJ_NJ^JK^KZNKNNJ
+MZNKNZOJ^P`+\```"``:`9,@T&F3$,@!B`,AIHP$#0-`T``,09--&31IH9#)D
+M,(#$T&)B!A``-`,F0:#3)B&0`Q`&0TT8"!H&@:``&(,FFC)HTT,ADR&$!B:#
+M$Q`P@`&@&3(-!IDQ#(`8@#(::,!`T#0-``#$&331DT::&0R9#"`Q-!B8@8"J
+M*0GY$I&GH"-&AZ@T```T`:`!HT```&@&@-,C0`-`#U,(-`&)ZF(PGIJ>IO;U
+M^=&QL3`-\E@Q+$(RTHB$7I"(B(-W:73$0@A#;S##$3$`A#FL\LAF,;&8;[CE
+M&D=@ON\:9IWHO):QK7LL=LFN;1M6Y:%F>-1G^&O-A*(@0AQ,\#H*KRCJF>9Q
+MFF_,RWU4X-,R6K5EJU:M6L"JMB5555555JVJU*U-JU:M6MUB*I555555;XHJ
+ME555555YM='L;(N7+ERY<N4****************.2B55555555%%%%%%%%"B
+MBBBBBC#S/DW+ERY<N7+E&NE55555550HHHHHHHS_(SQEG'X7.OTSKFY=#*]*
+M9?C*,7MM&JO=0EIDQW:7C-0U;WGRM>_!^S^F[=KA#3YJ.S-)`!>O]K)`#-ZO
+MU=9T,X(@!H',-+,1Q'-6'#ZNQORGURS=]_O%.6SF5G,PC`G#X_@7W$RC>2Q)
+M9MW3P&G:AJFA?`^AKWXOV?R_QDL9F^`=5H>$UWWT9K&Q/HS.!KXB)U)9$6,)
+M*/!EJ7>+W2L65_C\&LP69G$?'M$18.(LL.G:AZ;%>TUKYF.V+9/W9AMF[<VT
+MS/X;%DL?1SW5Y]4L]R=+RLNCTMB[6_5C8C2+?DPWF/F.G]WN[5+:G4UOWC%E
+M*3V7BO??&^=COL?:V3]&T9#<-XWKX3\,BQ#[KW01%D(X'O<#8?*B.`D]1J&O
+M>&^]HFB?J_AM6V;ANF2RG7,61I)?])L35<Y8C.RWDHV3\GZOW;-TC:MLW#<O
+MG;QDO2<6_S5;,T$1["/3W^^]&4;3*_F\:?7"90R&E;=N']O@;ENF[?ZR6Q93
+M_F6SAO9,N65+9R:#69>2^EX5C12BSAX@$(3`!EWEZ6P2R$9#_Q=R13A0D*2B
+"H:(`
+`
+end
diff --git a/sys/boot/efi/boot1/fat-i386.tmpl.bz2.uu b/sys/boot/efi/boot1/fat-i386.tmpl.bz2.uu
new file mode 100644
index 0000000..2bdebf0
--- /dev/null
+++ b/sys/boot/efi/boot1/fat-i386.tmpl.bz2.uu
@@ -0,0 +1,26 @@
+FAT template boot filesystem created by generate-fat.sh
+DO NOT EDIT
+$FreeBSD$
+begin 644 fat-i386.tmpl.bz2
+M0EIH.3%!629368LPC"P`&T#_____[ZKJ[_ZN_ZO^J_Z[OJ_OJ^JK_KZNKNNJ
+MZNKNZOJ^P`+\``4`15/%`]3U!H:-`:,C0```&@:9!H`T`!D````&@&@:9HF1
+MA``R:``:"``T,C1D&FFFAHT::`8F0TTR-#0,0Q,@TT```!HT,330:-&"!ID,
+M@&C$Q&FF(`#0R-&0::::&C1IH!B9#33(T-`Q#$R#30```&C0Q--!HT8(&F0R
+M`:,3$::8%4DDT_(HDQDFC$TR8F31H#0R,@T-!IH`#0R-`:9`TT--&C0-,C(R
+M--/0C"---/28$P:::G.M7$NU9*YMC#26[FI",))$0BU((B(@Y=99)$((0LB)
+M<:0@0AFL6JA=Y+)+JX9A-W:UXB7H/&:9\#3OG;)]#;MZOE^X3DL>PXZ:3<R.
+MJ1C*H@$(=/+'8VBTMO`8MBEXQ##KM0R"4I%:M56K5JU:VHI4DHHHHHHK5T5I
+M*TJU:M6K<JY4244444489-2)******/<SFZLBQ8L6+%BQ,FFFFFFFFFFFFFF
+MFFZV)*******)IIIIIIIIDTTTTTTUUFM/8L6+%BQ8L37TE%%%%%%$R::::::
+M;HNLR]568NF=;_H3.25=S.TN8C:-Q*3(SMM])&*T6=89:T"3R4HTB33/?:UL
+M&T;EO'`<1RVBN@U%Y'F&?@`M7&BD0`O=;\FNSTK<0`QK-P9;M*C)ZVIAUSMY
+M+RX<WJ797N#>Z7)W*[T]0YDF(D\UI%&H:I\KI&Q?FW+,N`_U_S`9%EL9H,?D
+M+[=S7F7N=K>6VVB(EK"J(J71=U(].36-&M9]E)+CJ[>NMXBU<ME(921[;4OB
+M8E]+[GX-LW+>.`OW%#X"4"I`L0*`H@*982S&"L)%`M'-HP#B!/4PH$;I)EK"
+M?`??(&!3=]_K])6G70T%+BT8F221>O8;!LVT?HV[=-ZWZ_<-QW,<YL3*[OAV
+MEUANWB*H1:7J(DC':.IN-FB,9(U;4KYX3]V595OW!<)Q7'<I@,%H6)DE$D=U
+M)SY&X7$29N2,5)S+BI&\;YOW`<%GE^XCCN2VCF,!JF6<C5_VCU)(X.#PK1RK
+MX2DAPVA<9QW(:]R7*<MS6`W#!<]A,4<Z3`DPI,&2_D==K<+`;5I:F4DBK,Q`
+8(0E`!A6EJ2^2<1'$?^+N2*<*$A%F$86`
+`
+end
diff --git a/sys/boot/efi/boot1/generate-fat.sh b/sys/boot/efi/boot1/generate-fat.sh
index 2688da3..7992b55 100755
--- a/sys/boot/efi/boot1/generate-fat.sh
+++ b/sys/boot/efi/boot1/generate-fat.sh
@@ -17,18 +17,21 @@ BOOT1_SIZE=128k
#
# Known filenames
-# amd64: BOOTx64.efi
-# arm64: BOOTaa64.efi
+# amd64: BOOTx64.efi
+# arm64: BOOTaa64.efi
+# arm: BOOTarm.efi
+# i386: BOOTia32.efi
#
-if [ -z "$1" ]; then
- echo "Usage: $0 filename"
+if [ -z "$2" ]; then
+ echo "Usage: $0 arch boot-filename"
exit 1
fi
-FILENAME=$1
+ARCH=$1
+FILENAME=$2
# Generate 800K FAT image
-OUTPUT_FILE=fat.tmpl
+OUTPUT_FILE=fat-${ARCH}.tmpl
dd if=/dev/zero of=$OUTPUT_FILE bs=512 count=$FAT_SIZE
DEVICE=`mdconfig -a -f $OUTPUT_FILE`
diff --git a/sys/boot/efi/fdt/Makefile b/sys/boot/efi/fdt/Makefile
index 05fbee8..19a4c49 100644
--- a/sys/boot/efi/fdt/Makefile
+++ b/sys/boot/efi/fdt/Makefile
@@ -10,7 +10,7 @@ INTERNALLIB=
SRCS= efi_fdt.c
CFLAGS+= -ffreestanding -msoft-float
-.if ${MACHINE_CPUARCH} == "arm64"
+.if ${MACHINE_CPUARCH} == "aarch64"
CFLAGS+= -mgeneral-regs-only
.endif
@@ -18,7 +18,7 @@ CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/
# EFI library headers
CFLAGS+= -I${.CURDIR}/../include
-CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH}
+CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
# libfdt headers
CFLAGS+= -I${.CURDIR}/../../fdt
@@ -27,7 +27,7 @@ CFLAGS+= -I${.CURDIR}/../../fdt
CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. -I.
machine:
- ln -sf ${.CURDIR}/../../../${MACHINE_CPUARCH}/include machine
+ ln -sf ${.CURDIR}/../../../${MACHINE}/include machine
CLEANFILES+= machine
diff --git a/sys/boot/efi/include/arm/efibind.h b/sys/boot/efi/include/arm/efibind.h
new file mode 100644
index 0000000..85537ad
--- /dev/null
+++ b/sys/boot/efi/include/arm/efibind.h
@@ -0,0 +1,165 @@
+/* $FreeBSD$ */
+/*++
+
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ EfiBind.h
+
+Abstract:
+
+ Processor or Compiler specific defines and types for IA-32.
+ We are using the ANSI C 2000 _t type definitions for basic types.
+ This it technically a violation of the coding standard, but they
+ are used to make EfiTypes.h portable. Code other than EfiTypes.h
+ should never use any ANSI C 2000 _t integer types.
+
+--*/
+
+#ifndef _EFI_BIND_H_
+#define _EFI_BIND_H_
+
+
+#define EFI_DRIVER_ENTRY_POINT(InitFunction)
+#define EFI_APPLICATION_ENTRY_POINT EFI_DRIVER_ENTRY_POINT
+
+
+//
+// Make sure we are useing the correct packing rules per EFI specification
+//
+#ifndef __GNUC__
+#pragma pack()
+#endif
+
+
+#ifdef __FreeBSD__
+#include <sys/stdint.h>
+#else
+//
+// Assume standard IA-32 alignment.
+// BugBug: Need to check portability of long long
+//
+typedef unsigned long long uint64_t;
+typedef long long int64_t;
+typedef unsigned int uint32_t;
+typedef int int32_t;
+typedef unsigned short uint16_t;
+typedef short int16_t;
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+#endif
+
+typedef uint64_t UINT64;
+typedef int64_t INT64;
+typedef uint32_t UINT32;
+typedef int32_t INT32;
+typedef uint16_t UINT16;
+typedef int16_t INT16;
+typedef uint8_t UINT8;
+typedef int8_t INT8;
+
+#undef VOID
+#define VOID void
+
+//
+// Native integer size in stdint.h
+//
+typedef uint32_t UINTN;
+typedef int32_t INTN;
+
+#define EFIERR(a) (0x80000000 | a)
+#define EFI_ERROR_MASK 0x80000000
+#define EFIERR_OEM(a) (0xc0000000 | a)
+
+//
+// Processor specific defines
+//
+#define EFI_MAX_BIT 0x80000000
+#define MAX_2_BITS 0xC0000000
+
+//
+// Maximum legal IA-32 address
+//
+#define EFI_MAX_ADDRESS 0xFFFFFFFF
+
+//
+// Bad pointer value to use in check builds.
+// if you see this value you are using uninitialized or free'ed data
+//
+#define EFI_BAD_POINTER 0xAFAFAFAF
+#define EFI_BAD_POINTER_AS_BYTE 0xAF
+
+#define EFI_DEADLOOP() { volatile UINTN __iii; __iii = 1; while (__iii); }
+
+//
+// Inject a break point in the code to assist debugging for NT Emulation Environment
+// For real hardware, just put in a halt loop. Don't do a while(1) because the
+// compiler will optimize away the rest of the function following, so that you run out in
+// the weeds if you skip over it with a debugger.
+//
+#define EFI_BREAKPOINT EFI_DEADLOOP()
+
+
+//
+// Memory Fence forces serialization, and is needed to support out of order
+// memory transactions. The Memory Fence is mainly used to make sure IO
+// transactions complete in a deterministic sequence, and to syncronize locks
+// an other MP code. Currently no memory fencing is required.
+//
+#define MEMORY_FENCE()
+
+//
+// Some compilers don't support the forward reference construct:
+// typedef struct XXXXX. The forward reference is required for
+// ANSI compatibility.
+//
+// The following macro provide a workaround for such cases.
+//
+
+
+#ifdef EFI_NO_INTERFACE_DECL
+ #define EFI_FORWARD_DECLARATION(x)
+#else
+ #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x
+#endif
+
+
+//
+// Some C compilers optimize the calling conventions to increase performance.
+// EFIAPI is used to make all public APIs follow the standard C calling
+// convention.
+//
+#define EFIAPI
+
+
+
+//
+// For symbol name in GNU assembly code, an extra "_" is necessary
+//
+#if defined(__GNUC__)
+ ///
+ /// Private worker functions for ASM_PFX()
+ ///
+ #define _CONCATENATE(a, b) __CONCATENATE(a, b)
+ #define __CONCATENATE(a, b) a ## b
+
+ ///
+ /// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix
+ /// on symbols in assembly language.
+ ///
+ #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name)
+
+#endif
+
+#define INTERFACE_DECL(x) struct x
+
+#endif
diff --git a/sys/boot/efi/include/arm64/efibind.h b/sys/boot/efi/include/arm64/efibind.h
new file mode 100644
index 0000000..21f0d25
--- /dev/null
+++ b/sys/boot/efi/include/arm64/efibind.h
@@ -0,0 +1,219 @@
+/* $FreeBSD$ */
+/*++
+
+Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved
+This software and associated documentation (if any) is furnished
+under a license and may only be used or copied in accordance
+with the terms of the license. Except as permitted by such
+license, no part of this software or documentation may be
+reproduced, stored in a retrieval system, or transmitted in any
+form or by any means without the express written consent of
+Intel Corporation.
+
+Module Name:
+
+ efefind.h
+
+Abstract:
+
+ EFI to compile bindings
+
+
+
+
+Revision History
+
+--*/
+
+#pragma pack()
+
+
+#ifdef __FreeBSD__
+#include <sys/stdint.h>
+#else
+//
+// Basic int types of various widths
+//
+
+#if (__STDC_VERSION__ < 199901L )
+
+ // No ANSI C 1999/2000 stdint.h integer width declarations
+
+ #if _MSC_EXTENSIONS
+
+ // Use Microsoft C compiler integer width declarations
+
+ typedef unsigned __int64 uint64_t;
+ typedef __int64 int64_t;
+ typedef unsigned __int32 uint32_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int16 uint16_t;
+ typedef __int16 int16_t;
+ typedef unsigned __int8 uint8_t;
+ typedef __int8 int8_t;
+ #else
+ #ifdef UNIX_LP64
+
+ // Use LP64 programming model from C_FLAGS for integer width declarations
+
+ typedef unsigned long uint64_t;
+ typedef long int64_t;
+ typedef unsigned int uint32_t;
+ typedef int int32_t;
+ typedef unsigned short uint16_t;
+ typedef short int16_t;
+ typedef unsigned char uint8_t;
+ typedef char int8_t;
+ #else
+
+ // Assume P64 programming model from C_FLAGS for integer width declarations
+
+ typedef unsigned long long uint64_t;
+ typedef long long int64_t;
+ typedef unsigned int uint32_t;
+ typedef int int32_t;
+ typedef unsigned short uint16_t;
+ typedef short int16_t;
+ typedef unsigned char uint8_t;
+ typedef char int8_t;
+ #endif
+ #endif
+#endif
+#endif /* __FreeBSD__ */
+
+//
+// Basic EFI types of various widths
+//
+
+
+typedef uint64_t UINT64;
+typedef int64_t INT64;
+typedef uint32_t UINT32;
+typedef int32_t INT32;
+typedef uint16_t UINT16;
+typedef int16_t INT16;
+typedef uint8_t UINT8;
+typedef int8_t INT8;
+
+
+#undef VOID
+#define VOID void
+
+
+typedef int64_t INTN;
+typedef uint64_t UINTN;
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// BugBug: Code to debug
+//
+#define BIT63 0x8000000000000000
+
+#define PLATFORM_IOBASE_ADDRESS (0xffffc000000 | BIT63)
+#define PORT_TO_MEMD(_Port) (PLATFORM_IOBASE_ADDRESS | ( ( ( (_Port) & 0xfffc) << 10 ) | ( (_Port) & 0x0fff) ) )
+
+//
+// Macro's with casts make this much easier to use and read.
+//
+#define PORT_TO_MEM8D(_Port) (*(UINT8 *)(PORT_TO_MEMD(_Port)))
+#define POST_CODE(_Data) (PORT_TO_MEM8D(0x80) = (_Data))
+//
+// BugBug: End Debug Code!!!
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+#define EFIERR(a) (0x8000000000000000 | a)
+#define EFI_ERROR_MASK 0x8000000000000000
+#define EFIERR_OEM(a) (0xc000000000000000 | a)
+
+#define BAD_POINTER 0xFBFBFBFBFBFBFBFB
+#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF
+
+#pragma intrinsic (__break)
+#define BREAKPOINT() __break(0)
+
+//
+// Pointers must be aligned to these address to function
+// you will get an alignment fault if this value is less than 8
+//
+#define MIN_ALIGNMENT_SIZE 8
+
+#define ALIGN_VARIABLE(Value , Adjustment) \
+ (UINTN) Adjustment = 0; \
+ if((UINTN)Value % MIN_ALIGNMENT_SIZE) \
+ (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \
+ Value = (UINTN)Value + (UINTN)Adjustment
+
+//
+// Define macros to create data structure signatures.
+//
+
+#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8))
+#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16))
+#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32))
+
+//
+// EFIAPI - prototype calling convention for EFI function pointers
+// BOOTSERVICE - prototype for implementation of a boot service interface
+// RUNTIMESERVICE - prototype for implementation of a runtime service interface
+// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service
+// RUNTIME_CODE - pragma macro for declaring runtime code
+//
+
+#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options
+ #if _MSC_EXTENSIONS
+ #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler
+ #else
+ #define EFIAPI // Substitute expresion to force C calling convention
+ #endif
+#endif
+
+#define BOOTSERVICE
+#define RUNTIMESERVICE
+#define RUNTIMEFUNCTION
+
+#define RUNTIME_CODE(a) alloc_text("rtcode", a)
+#define BEGIN_RUNTIME_DATA() data_seg("rtdata")
+#define END_RUNTIME_DATA() data_seg()
+
+#define VOLATILE volatile
+
+//
+// BugBug: Need to find out if this is portable accross compliers.
+//
+void __mfa (void);
+#pragma intrinsic (__mfa)
+#define MEMORY_FENCE() __mfa()
+
+#ifdef EFI_NO_INTERFACE_DECL
+ #define EFI_FORWARD_DECLARATION(x)
+ #define EFI_INTERFACE_DECL(x)
+#else
+ #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x
+ #define EFI_INTERFACE_DECL(x) typedef struct x
+#endif
+
+//
+// When build similiar to FW, then link everything together as
+// one big module.
+//
+
+#define EFI_DRIVER_ENTRY_POINT(InitFunction)
+
+#define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \
+ (_if)->LoadInternal(type, name, entry)
+// entry(NULL, ST)
+
+#ifdef __FreeBSD__
+#define INTERFACE_DECL(x) struct x
+#else
+//
+// Some compilers don't support the forward reference construct:
+// typedef struct XXXXX
+//
+// The following macro provide a workaround for such cases.
+//
+#ifdef NO_INTERFACE_DECL
+#define INTERFACE_DECL(x)
+#else
+#define INTERFACE_DECL(x) typedef struct x
+#endif
+#endif
diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile
index 2a3a251..88ca242 100644
--- a/sys/boot/efi/libefi/Makefile
+++ b/sys/boot/efi/libefi/Makefile
@@ -10,7 +10,7 @@ SRCS= delay.c efi_console.c efinet.c efipart.c errno.c handles.c \
CFLAGS+= -fPIC -mno-red-zone
.endif
CFLAGS+= -I${.CURDIR}/../include
-CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH}
+CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
# Pick up the bootstrap header for some interface items
diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile
index e109b72..5585f78 100644
--- a/sys/boot/efi/loader/Makefile
+++ b/sys/boot/efi/loader/Makefile
@@ -20,19 +20,23 @@ SRCS= autoload.c \
copy.c \
devicename.c \
main.c \
+ reloc.c \
+ smbios.c \
vers.c
-.PATH: ${.CURDIR}/arch/${MACHINE_CPUARCH}
-.include "${.CURDIR}/arch/${MACHINE_CPUARCH}/Makefile.inc"
+.PATH: ${.CURDIR}/arch/${MACHINE}
+# For smbios.c
+.PATH: ${.CURDIR}/../../i386/libi386
+.include "${.CURDIR}/arch/${MACHINE}/Makefile.inc"
-CFLAGS+= -fPIC
CFLAGS+= -I${.CURDIR}
-CFLAGS+= -I${.CURDIR}/arch/${MACHINE_CPUARCH}
+CFLAGS+= -I${.CURDIR}/arch/${MACHINE}
CFLAGS+= -I${.CURDIR}/../include
-CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH}
+CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include
CFLAGS+= -I${.CURDIR}/../../..
-CFLAGS+= -DNO_PCI
+CFLAGS+= -I${.CURDIR}/../../i386/libi386
+CFLAGS+= -DNO_PCI -DEFI
.if ${MK_FORTH} != "no"
BOOT_FORTH= yes
@@ -42,6 +46,15 @@ CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_CPUARCH}
LIBFICL= ${.OBJDIR}/../../ficl/libficl.a
.endif
+LOADER_FDT_SUPPORT?= no
+.if ${MK_FDT} != "no" && ${LOADER_FDT_SUPPORT} != "no"
+CFLAGS+= -I${.CURDIR}/../../fdt
+CFLAGS+= -I${.OBJDIR}/../../fdt
+CFLAGS+= -DLOADER_FDT_SUPPORT
+LIBEFI_FDT= ${.OBJDIR}/../../efi/fdt/libefi_fdt.a
+LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a
+.endif
+
# Include bcache code.
HAVE_BCACHE= yes
@@ -57,12 +70,12 @@ CFLAGS+= -I${.CURDIR}/../../common
FILES= loader.efi
FILESMODE_loader.efi= ${BINMODE}
-LDSCRIPT= ${.CURDIR}/arch/${MACHINE_CPUARCH}/ldscript.${MACHINE_CPUARCH}
-LDFLAGS= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared -Wl,-znocombreloc
+LDSCRIPT= ${.CURDIR}/arch/${MACHINE}/ldscript.${MACHINE}
+LDFLAGS+= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared
CLEANFILES= vers.c loader.efi
-NEWVERSWHAT= "EFI loader" ${MACHINE_CPUARCH}
+NEWVERSWHAT= "EFI loader" ${MACHINE}
vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../../efi/loader/version
sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
@@ -74,6 +87,8 @@ OBJDUMP?= objdump
EFI_TARGET= efi-app-x86_64
.elif ${MACHINE_CPUARCH} == "i386"
EFI_TARGET= efi-app-ia32
+.else
+EFI_TARGET= binary
.endif
loader.efi: loader.sym
@@ -81,26 +96,32 @@ loader.efi: loader.sym
${OBJDUMP} -t ${.ALLSRC} | fgrep '*UND*'; \
exit 1; \
fi
- ${OBJCOPY} -j .text -j .sdata -j .data \
+ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \
-j .dynamic -j .dynsym -j .rel.dyn \
-j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \
--output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET}
LIBEFI= ${.OBJDIR}/../libefi/libefi.a
-DPADD= ${LIBFICL} ${LIBEFI} ${LIBSTAND} ${LDSCRIPT}
-LDADD= ${LIBFICL} ${LIBEFI} ${LIBSTAND}
+DPADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} \
+ ${LDSCRIPT}
+LDADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND}
.endif # ${COMPILER_TYPE} != "gcc"
.include <bsd.prog.mk>
-beforedepend ${OBJS}: machine x86
+beforedepend ${OBJS}: machine
-CLEANFILES+= machine x86
+CLEANFILES+= machine
machine:
- ln -sf ${.CURDIR}/../../../amd64/include machine
+ ln -sf ${.CURDIR}/../../../${MACHINE}/include machine
+
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
+beforedepend ${OBJS}: x86
+CLEANFILES+= x86
x86:
ln -sf ${.CURDIR}/../../../x86/include x86
+.endif
diff --git a/sys/boot/efi/loader/arch/amd64/Makefile.inc b/sys/boot/efi/loader/arch/amd64/Makefile.inc
index 3f2b68e..fee959b 100644
--- a/sys/boot/efi/loader/arch/amd64/Makefile.inc
+++ b/sys/boot/efi/loader/arch/amd64/Makefile.inc
@@ -3,9 +3,11 @@
SRCS+= amd64_tramp.S \
start.S \
framebuffer.c \
- elf64_freebsd.c \
- reloc.c
+ elf64_freebsd.c
.PATH: ${.CURDIR}/../../i386/libi386
SRCS+= nullconsole.c \
comconsole.c
+
+CFLAGS+= -fPIC
+LDFLAGS+= -Wl,-znocombreloc
diff --git a/sys/boot/efi/loader/arch/arm/Makefile.inc b/sys/boot/efi/loader/arch/arm/Makefile.inc
new file mode 100644
index 0000000..b2876ca
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+SRCS+= exec.c \
+ start.S
+
+LOADER_FDT_SUPPORT=yes
diff --git a/sys/boot/efi/loader/arch/arm/exec.c b/sys/boot/efi/loader/arch/arm/exec.c
new file mode 100644
index 0000000..1cbbce5
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm/exec.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2001 Benno Rice <benno@FreeBSD.org>
+ * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/linker.h>
+
+#include <machine/md_var.h>
+#include <machine/metadata.h>
+#include <machine/elf.h>
+
+#include <stand.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "bootstrap.h"
+#include "loader_efi.h"
+
+extern vm_offset_t md_load(char *, vm_offset_t *);
+
+int
+__elfN(arm_load)(char *filename, u_int64_t dest,
+ struct preloaded_file **result)
+{
+ int r;
+
+ r = __elfN(loadfile)(filename, dest, result);
+ if (r != 0)
+ return (r);
+
+ return (0);
+}
+
+int
+__elfN(arm_exec)(struct preloaded_file *fp)
+{
+ struct file_metadata *fmp;
+ vm_offset_t modulep, kernend;
+ Elf_Ehdr *e;
+ int error;
+ void (*entry)(void *);
+ EFI_STATUS status;
+
+ if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
+ return (EFTYPE);
+
+ e = (Elf_Ehdr *)&fmp->md_data;
+
+ if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0)
+ return (error);
+
+ entry = efi_translate(e->e_entry);
+ printf("Kernel entry at 0x%x...\n", (unsigned)entry);
+ printf("Kernel args: %s\n", fp->f_args);
+ printf("modulep: %#x\n", modulep);
+ printf("relocation_offset %llx\n", __elfN(relocation_offset));
+
+ status = BS->ExitBootServices(IH, efi_mapkey);
+ if (EFI_ERROR(status)) {
+ printf("%s: ExitBootServices() returned 0x%lx\n", __func__,
+ (long)status);
+ return (EINVAL);
+ }
+
+ dev_cleanup();
+
+ (*entry)((void *)modulep);
+ panic("exec returned");
+}
+
+static struct file_format arm_elf = {
+ __elfN(arm_load),
+ __elfN(arm_exec)
+};
+
+struct file_format *file_formats[] = {
+ &arm_elf,
+ NULL
+};
+
diff --git a/sys/boot/efi/loader/arch/arm/ldscript.arm b/sys/boot/efi/loader/arch/arm/ldscript.arm
new file mode 100644
index 0000000..6404c0c
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm/ldscript.arm
@@ -0,0 +1,62 @@
+/* $FreeBSD$ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+ "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0;
+ ImageBase = .;
+ .text : {
+ *(.peheader)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.gnu.linkonce.t*)
+ } =0
+ _etext = .;
+ PROVIDE (etext = .);
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.data *.data.*)
+ *(.gnu.linkonce.d*)
+ *(.rodata)
+ *(.rodata.*)
+ CONSTRUCTORS
+
+ PROVIDE (__bss_start = .);
+ *(.sbss)
+ *(.scommon)
+ *(.dynsbss)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ PROVIDE (__bss_end = .);
+ }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata : {
+ *(.got.plt .got)
+ *(.sdata*.sdata.* .gnu.linkonce.s.*)
+ }
+ set_Xcommand_set : {
+ __start_set_Xcommand_set = .;
+ *(set_Xcommand_set)
+ __stop_set_Xcommand_set = .;
+ }
+ __gp = .;
+ .plt : { *(.plt) }
+ .dynamic : { *(.dynamic) }
+ .reloc : { *(.reloc) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.dyn : {
+ *(.rel.*)
+ *(.relset_*)
+ }
+ _edata = .;
+ .hash : { *(.hash) }
+}
diff --git a/sys/boot/efi/loader/arch/arm/start.S b/sys/boot/efi/loader/arch/arm/start.S
new file mode 100644
index 0000000..4160655
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm/start.S
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 2014, 2015 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asm.h>
+
+/*
+ * We need to be a PE32 file for EFI. On some architectures we can use
+ * objcopy to create the correct file, however on arm we need to do
+ * it ourselves.
+ */
+
+#define IMAGE_FILE_MACHINE_ARM 0x01c2
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+
+ .section .peheader
+efi_start:
+ /* The MS-DOS Stub, only used to get the offset of the COFF header */
+ .ascii "MZ"
+ .short 0
+ .space 0x38
+ .long pe_sig - efi_start
+
+ /* The PE32 Signature. Needs to be 8-byte aligned */
+ .align 3
+pe_sig:
+ .ascii "PE"
+ .short 0
+coff_head:
+ .short IMAGE_FILE_MACHINE_ARM /* ARM file */
+ .short 2 /* 2 Sections */
+ .long 0 /* Timestamp */
+ .long 0 /* No symbol table */
+ .long 0 /* No symbols */
+ .short section_table - optional_header /* Optional header size */
+ .short 0 /* Characteristics TODO: Fill in */
+
+optional_header:
+ .short 0x010b /* PE32 (32-bit addressing) */
+ .byte 0 /* Major linker version */
+ .byte 0 /* Minor linker version */
+ .long _edata - _end_header /* Code size */
+ .long 0 /* No initialized data */
+ .long 0 /* No uninitialized data */
+ .long _start - efi_start /* Entry point */
+ .long _end_header - efi_start /* Start of code */
+ .long 0 /* Start of data */
+
+optional_windows_header:
+ .long 0 /* Image base */
+ .long 32 /* Section Alignment */
+ .long 8 /* File alignment */
+ .short 0 /* Major OS version */
+ .short 0 /* Minor OS version */
+ .short 0 /* Major image version */
+ .short 0 /* Minor image version */
+ .short 0 /* Major subsystem version */
+ .short 0 /* Minor subsystem version */
+ .long 0 /* Win32 version */
+ .long _edata - efi_start /* Image size */
+ .long _end_header - efi_start /* Header size */
+ .long 0 /* Checksum */
+ .short 0xa /* Subsystem (EFI app) */
+ .short 0 /* DLL Characteristics */
+ .long 0 /* Stack reserve */
+ .long 0 /* Stack commit */
+ .long 0 /* Heap reserve */
+ .long 0 /* Heap commit */
+ .long 0 /* Loader flags */
+ .long 6 /* Number of RVAs */
+
+ /* RVAs: */
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+section_table:
+ /* We need a .reloc section for EFI */
+ .ascii ".reloc"
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long 0 /* Virtual size */
+ .long 0 /* Virtual address */
+ .long 0 /* Size of raw data */
+ .long 0 /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */
+
+ /* The contents of the loader */
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long _edata - _end_header /* Virtual size */
+ .long _end_header - efi_start /* Virtual address */
+ .long _edata - _end_header /* Size of raw data */
+ .long _end_header - efi_start /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \
+ IMAGE_SCN_MEM_READ) /* Characteristics */
+_end_header:
+
+ .text
+_start:
+ /* Save the boot params to the stack */
+ push {r0, r1}
+
+ adr r0, .Lbase
+ ldr r1, [r0]
+ sub r5, r0, r1
+
+ ldr r0, .Limagebase
+ add r0, r0, r5
+ ldr r1, .Ldynamic
+ add r1, r1, r5
+
+ bl _C_LABEL(_reloc)
+
+ /* Zero the BSS, _reloc fixed the values for us */
+ ldr r0, .Lbss
+ ldr r1, .Lbssend
+ mov r2, #0
+
+1: cmp r0, r1
+ bgt 2f
+ str r2, [r0], #4
+ b 1b
+2:
+
+ pop {r0, r1}
+ bl _C_LABEL(efi_main)
+
+1: b 1b
+
+.Lbase:
+ .word .
+.Limagebase:
+ .word ImageBase
+.Ldynamic:
+ .word _DYNAMIC
+.Lbss:
+ .word __bss_start
+.Lbssend:
+ .word __bss_end
+
+.align 3
+stack:
+ .space 512
+stack_end:
+
diff --git a/sys/boot/efi/loader/arch/arm64/Makefile.inc b/sys/boot/efi/loader/arch/arm64/Makefile.inc
new file mode 100644
index 0000000..e5064cc
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm64/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+LOADER_FDT_SUPPORT=yes
+SRCS+= exec.c \
+ start.S
+
+.PATH: ${.CURDIR}/../../arm64/libarm64
+CFLAGS+=-I${.CURDIR}/../../arm64/libarm64
+SRCS+= cache.c
diff --git a/sys/boot/efi/loader/arch/arm64/exec.c b/sys/boot/efi/loader/arch/arm64/exec.c
new file mode 100644
index 0000000..1f72269
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm64/exec.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2006 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <machine/elf.h>
+
+#include <bootstrap.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "loader_efi.h"
+#include "cache.h"
+
+static int elf64_exec(struct preloaded_file *amp);
+static int elf64_obj_exec(struct preloaded_file *amp);
+
+int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp);
+
+static struct file_format arm64_elf = {
+ elf64_loadfile,
+ elf64_exec
+};
+
+struct file_format *file_formats[] = {
+ &arm64_elf,
+ NULL
+};
+
+static int
+elf64_exec(struct preloaded_file *fp)
+{
+ vm_offset_t modulep, kernendp;
+ vm_offset_t clean_addr;
+ size_t clean_size;
+ struct file_metadata *md;
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS addr;
+ Elf_Ehdr *ehdr;
+ int err;
+ void (*entry)(vm_offset_t);
+
+ if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
+ return(EFTYPE);
+
+ ehdr = (Elf_Ehdr *)&(md->md_data);
+ entry = efi_translate(ehdr->e_entry);
+
+ err = bi_load(fp->f_args, &modulep, &kernendp);
+ if (err != 0)
+ return (err);
+
+ status = BS->ExitBootServices(IH, efi_mapkey);
+ if (EFI_ERROR(status)) {
+ printf("%s: ExitBootServices() returned 0x%lx\n", __func__,
+ (long)status);
+ return (EINVAL);
+ }
+
+ /* Clean D-cache under kernel area and invalidate whole I-cache */
+ clean_addr = efi_translate(fp->f_addr);
+ clean_size = efi_translate(kernendp) - clean_addr;
+
+ cpu_flush_dcache((void *)clean_addr, clean_size);
+ cpu_inval_icache(NULL, 0);
+
+ (*entry)(modulep);
+ panic("exec returned");
+}
+
+static int
+elf64_obj_exec(struct preloaded_file *fp)
+{
+
+ printf("%s called for preloaded file %p (=%s):\n", __func__, fp,
+ fp->f_name);
+ return (ENOSYS);
+}
+
diff --git a/sys/boot/efi/loader/arch/arm64/ldscript.arm64 b/sys/boot/efi/loader/arch/arm64/ldscript.arm64
new file mode 100644
index 0000000..7b62eaa
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm64/ldscript.arm64
@@ -0,0 +1,80 @@
+/* $FreeBSD$ */
+/*
+OUTPUT_FORMAT("elf64-aarch64-freebsd", "elf64-aarch64-freebsd", "elf64-aarch64-freebsd")
+*/
+OUTPUT_ARCH(aarch64)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0;
+ ImageBase = .;
+ .text : {
+ *(.peheader)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.plt)
+ } =0x00300000010070000002000001000400
+ . = ALIGN(16);
+ .data : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ *(.rodata1)
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
+ *(.opd)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.data1)
+ *(.plabel)
+
+ . = ALIGN(16);
+ __bss_start = .;
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss *.bss.*)
+ *(COMMON)
+ . = ALIGN(16);
+ __bss_end = .;
+ }
+ . = ALIGN(16);
+ set_Xcommand_set : {
+ __start_set_Xcommand_set = .;
+ *(set_Xcommand_set)
+ __stop_set_Xcommand_set = .;
+ }
+ . = ALIGN(16);
+ __gp = .;
+ .sdata : {
+ *(.got.plt .got)
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ *(dynsbss)
+ *(.scommon)
+ }
+ . = ALIGN(16);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(16);
+ .rela.dyn : {
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ *(.rela.plt)
+ *(.relset_*)
+ *(.rela.dyn .rela.dyn.*)
+ }
+ . = ALIGN(16);
+ .reloc : { *(.reloc) }
+ . = ALIGN(16);
+ .dynsym : { *(.dynsym) }
+ _edata = .;
+
+ /* Unused sections */
+ .dynstr : { *(.dynstr) }
+ .hash : { *(.hash) }
+}
diff --git a/sys/boot/efi/loader/arch/arm64/start.S b/sys/boot/efi/loader/arch/arm64/start.S
new file mode 100644
index 0000000..a8002fa
--- /dev/null
+++ b/sys/boot/efi/loader/arch/arm64/start.S
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * We need to be a PE32+ file for EFI. On some architectures we can use
+ * objcopy to create the correct file, however on arm64 we need to do
+ * it ourselves.
+ */
+
+#define IMAGE_FILE_MACHINE_ARM64 0xaa64
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+
+ .section .peheader
+efi_start:
+ /* The MS-DOS Stub, only used to get the offset of the COFF header */
+ .ascii "MZ"
+ .short 0
+ .space 0x38
+ .long pe_sig - efi_start
+
+ /* The PE32 Signature. Needs to be 8-byte aligned */
+ .align 3
+pe_sig:
+ .ascii "PE"
+ .short 0
+coff_head:
+ .short IMAGE_FILE_MACHINE_ARM64 /* AArch64 file */
+ .short 2 /* 2 Sections */
+ .long 0 /* Timestamp */
+ .long 0 /* No symbol table */
+ .long 0 /* No symbols */
+ .short section_table - optional_header /* Optional header size */
+ .short 0 /* Characteristics TODO: Fill in */
+
+optional_header:
+ .short 0x020b /* PE32+ (64-bit addressing) */
+ .byte 0 /* Major linker version */
+ .byte 0 /* Minor linker version */
+ .long _edata - _end_header /* Code size */
+ .long 0 /* No initialized data */
+ .long 0 /* No uninitialized data */
+ .long _start - efi_start /* Entry point */
+ .long _end_header - efi_start /* Start of code */
+
+optional_windows_header:
+ .quad 0 /* Image base */
+ .long 32 /* Section Alignment */
+ .long 8 /* File alignment */
+ .short 0 /* Major OS version */
+ .short 0 /* Minor OS version */
+ .short 0 /* Major image version */
+ .short 0 /* Minor image version */
+ .short 0 /* Major subsystem version */
+ .short 0 /* Minor subsystem version */
+ .long 0 /* Win32 version */
+ .long _edata - efi_start /* Image size */
+ .long _end_header - efi_start /* Header size */
+ .long 0 /* Checksum */
+ .short 0xa /* Subsystem (EFI app) */
+ .short 0 /* DLL Characteristics */
+ .quad 0 /* Stack reserve */
+ .quad 0 /* Stack commit */
+ .quad 0 /* Heap reserve */
+ .quad 0 /* Heap commit */
+ .long 0 /* Loader flags */
+ .long 6 /* Number of RVAs */
+
+ /* RVAs: */
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+section_table:
+ /* We need a .reloc section for EFI */
+ .ascii ".reloc"
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long 0 /* Virtual size */
+ .long 0 /* Virtual address */
+ .long 0 /* Size of raw data */
+ .long 0 /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */
+
+ /* The contents of the loader */
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long _edata - _end_header /* Virtual size */
+ .long _end_header - efi_start /* Virtual address */
+ .long _edata - _end_header /* Size of raw data */
+ .long _end_header - efi_start /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \
+ IMAGE_SCN_MEM_READ) /* Characteristics */
+_end_header:
+
+ .text
+ .globl _start
+_start:
+ /* Save the boot params to the stack */
+ stp x0, x1, [sp, #-16]!
+
+ adr x0, __bss_start
+ adr x1, __bss_end
+
+ b 2f
+
+1:
+ stp xzr, xzr, [x0], #16
+2:
+ cmp x0, x1
+ b.lo 1b
+
+ adr x0, ImageBase
+ adr x1, _DYNAMIC
+
+ bl _reloc
+
+ ldp x0, x1, [sp], #16
+
+ bl efi_main
+
+1: b 1b
diff --git a/sys/boot/efi/loader/arch/i386/Makefile.inc b/sys/boot/efi/loader/arch/i386/Makefile.inc
new file mode 100644
index 0000000..4e08c53
--- /dev/null
+++ b/sys/boot/efi/loader/arch/i386/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+SRCS+= start.S \
+ efimd.c \
+ elf32_freebsd.c \
+ exec.c
+
+.PATH: ${.CURDIR}/../../i386/libi386
+SRCS+= nullconsole.c \
+ comconsole.c
+
+CFLAGS+= -fPIC
+LDFLAGS+= -Wl,-znocombreloc
diff --git a/sys/boot/efi/loader/arch/i386/bootinfo.c b/sys/boot/efi/loader/arch/i386/bootinfo.c
index 853d044..cbd6e4e 100644
--- a/sys/boot/efi/loader/arch/i386/bootinfo.c
+++ b/sys/boot/efi/loader/arch/i386/bootinfo.c
@@ -219,7 +219,7 @@ bi_load(struct preloaded_file *fp, uint64_t *bi_addr)
bi.bi_version = 1;
// bi.bi_boothowto = bi_getboothowto(fp->f_args);
- /*
+ /*
* Allow the environment variable 'rootdev' to override the supplied
* device. This should perhaps go to MI code and/or have $rootdev
* tested/set by MI code before launching the kernel.
diff --git a/sys/boot/efi/loader/arch/i386/elf32_freebsd.c b/sys/boot/efi/loader/arch/i386/elf32_freebsd.c
index f193735..bae8f7b 100644
--- a/sys/boot/efi/loader/arch/i386/elf32_freebsd.c
+++ b/sys/boot/efi/loader/arch/i386/elf32_freebsd.c
@@ -48,9 +48,15 @@ static int elf32_obj_exec(struct preloaded_file *amp);
struct file_format i386_elf = { elf32_loadfile, elf32_exec };
struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec };
+struct file_format *file_formats[] = {
+ &i386_elf,
+ &i386_elf_obj,
+ NULL
+};
+
/*
- * There is an ELF kernel and one or more ELF modules loaded.
- * We wish to start executing the kernel image, so make such
+ * There is an ELF kernel and one or more ELF modules loaded.
+ * We wish to start executing the kernel image, so make such
* preparations as are required, and do so.
*/
static int
diff --git a/sys/boot/efi/loader/arch/i386/i386_copy.c b/sys/boot/efi/loader/arch/i386/i386_copy.c
index 43c26ce..522913f 100644
--- a/sys/boot/efi/loader/arch/i386/i386_copy.c
+++ b/sys/boot/efi/loader/arch/i386/i386_copy.c
@@ -28,7 +28,7 @@
__FBSDID("$FreeBSD$");
/*
- * MD primitives supporting placement of module data
+ * MD primitives supporting placement of module data
*
* XXX should check load address/size against memory top.
*/
diff --git a/sys/boot/efi/loader/arch/i386/start.S b/sys/boot/efi/loader/arch/i386/start.S
index ea4597f..2be2478 100644
--- a/sys/boot/efi/loader/arch/i386/start.S
+++ b/sys/boot/efi/loader/arch/i386/start.S
@@ -33,7 +33,7 @@
#define EFI_SUCCESS 0
/*
- * EFI entry point.
+ * EFI entry point.
* _start(EFI_IMAGE image_handle, EFI_SYSTEM_TABLE *system_table);
*
* We calculate the base address along with _DYNAMIC, relocate us and finally
diff --git a/sys/boot/efi/loader/bootinfo.c b/sys/boot/efi/loader/bootinfo.c
index 28ec620..6ef83a8 100644
--- a/sys/boot/efi/loader/bootinfo.c
+++ b/sys/boot/efi/loader/bootinfo.c
@@ -46,11 +46,15 @@ __FBSDID("$FreeBSD$");
#include "bootstrap.h"
#include "loader_efi.h"
-#if defined(__amd64__) || defined(__i386__)
+#if defined(__amd64__)
#include <machine/specialreg.h>
#include "framebuffer.h"
#endif
+#if defined(LOADER_FDT_SUPPORT)
+#include <fdt_platform.h>
+#endif
+
UINTN efi_mapkey;
static const char howto_switches[] = "aCdrgDmphsv";
@@ -215,6 +219,9 @@ bi_copymodules(vm_offset_t addr)
if (fp->f_args)
MOD_ARGS(addr, fp->f_args, c);
v = fp->f_addr;
+#if defined(__arm__)
+ v -= __elfN(relocation_offset);
+#endif
MOD_ADDR(addr, v, c);
v = fp->f_size;
MOD_SIZE(addr, v, c);
@@ -237,7 +244,7 @@ bi_load_efi_data(struct preloaded_file *kfp)
UINT32 mmver;
struct efi_map_header *efihdr;
-#if defined(__amd64__) || defined(__i386__)
+#if defined(__amd64__)
struct efi_fb efifb;
if (efi_find_framebuffer(&efifb) == 0) {
@@ -324,6 +331,25 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
vm_offset_t size;
char *rootdevname;
int howto;
+#if defined(LOADER_FDT_SUPPORT)
+ vm_offset_t dtbp;
+ int dtb_size;
+#endif
+#if defined(__arm__)
+ vm_offset_t vaddr;
+ int i;
+ /*
+ * These metadata addreses must be converted for kernel after
+ * relocation.
+ */
+ uint32_t mdt[] = {
+ MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND,
+ MODINFOMD_ENVP,
+#if defined(LOADER_FDT_SUPPORT)
+ MODINFOMD_DTBP
+#endif
+ };
+#endif
howto = bi_getboothowto(args);
@@ -358,6 +384,16 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
/* Pad to a page boundary. */
addr = roundup(addr, PAGE_SIZE);
+#if defined(LOADER_FDT_SUPPORT)
+ /* Handle device tree blob */
+ dtbp = addr;
+ dtb_size = fdt_copy(addr);
+
+ /* Pad to a page boundary */
+ if (dtb_size)
+ addr += roundup(dtb_size, PAGE_SIZE);
+#endif
+
kfp = file_findfile(NULL, "elf kernel");
if (kfp == NULL)
kfp = file_findfile(NULL, "elf64 kernel");
@@ -366,6 +402,13 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
kernend = 0; /* fill it in later */
file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
+#if defined(LOADER_FDT_SUPPORT)
+ if (dtb_size)
+ file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp);
+ else
+ pager_output("WARNING! Trying to fire up the kernel, but no "
+ "device tree blob found!\n");
+#endif
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
bi_load_efi_data(kfp);
@@ -380,6 +423,22 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
md = file_findmetadata(kfp, MODINFOMD_KERNEND);
bcopy(&kernend, md->md_data, sizeof kernend);
+#if defined(__arm__)
+ *modulep -= __elfN(relocation_offset);
+
+ /* Do relocation fixup on metadata of each module. */
+ for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
+ for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) {
+ md = file_findmetadata(xp, mdt[i]);
+ if (md) {
+ bcopy(md->md_data, &vaddr, sizeof vaddr);
+ vaddr -= __elfN(relocation_offset);
+ bcopy(&vaddr, md->md_data, sizeof vaddr);
+ }
+ }
+ }
+#endif
+
/* Copy module list and metadata. */
(void)bi_copymodules(addr);
diff --git a/sys/boot/efi/loader/copy.c b/sys/boot/efi/loader/copy.c
index 1da3f43..10f4cb2 100644
--- a/sys/boot/efi/loader/copy.c
+++ b/sys/boot/efi/loader/copy.c
@@ -61,9 +61,27 @@ efi_copy_init(void)
}
staging_end = staging + STAGE_PAGES * 4096;
+#if defined(__aarch64__) || defined(__arm__)
+ /*
+ * Round the kernel load address to a 2MiB value. This is needed
+ * because the kernel builds a page table based on where it has
+ * been loaded in physical address space. As the kernel will use
+ * either a 1MiB or 2MiB page for this we need to make sure it
+ * is correctly aligned for both cases.
+ */
+ staging = roundup2(staging, 2 * 1024 * 1024);
+#endif
+
return (0);
}
+void *
+efi_translate(vm_offset_t ptr)
+{
+
+ return ((void *)(ptr + stage_offset));
+}
+
ssize_t
efi_copyin(const void *src, vm_offset_t dest, const size_t len)
{
diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c
index d6b2b53..93c6059 100644
--- a/sys/boot/efi/loader/main.c
+++ b/sys/boot/efi/loader/main.c
@@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$");
#include <efilib.h>
#include <bootstrap.h>
+#include <smbios.h>
+
#include "loader_efi.h"
extern char bootprog_name[];
@@ -63,6 +65,7 @@ main(int argc, CHAR16 *argv[])
{
char vendor[128];
EFI_LOADED_IMAGE *img;
+ EFI_GUID *guid;
int i;
/*
@@ -128,6 +131,14 @@ main(int argc, CHAR16 *argv[])
archsw.arch_copyout = efi_copyout;
archsw.arch_readin = efi_readin;
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ guid = &ST->ConfigurationTable[i].VendorGuid;
+ if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
+ smbios_detect(ST->ConfigurationTable[i].VendorTable);
+ break;
+ }
+ }
+
interact(NULL); /* doesn't return */
return (EFI_SUCCESS); /* keep compiler happy */
@@ -285,7 +296,7 @@ command_configuration(int argc, char *argv[])
}
-COMMAND_SET(mode, "mode", "change or display text modes", command_mode);
+COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
static int
command_mode(int argc, char *argv[])
@@ -331,7 +342,7 @@ command_mode(int argc, char *argv[])
}
if (i != 0)
- printf("Choose the mode with \"col <mode number>\"\n");
+ printf("Select a mode with the command \"mode <number>\"\n");
return (CMD_OK);
}
@@ -387,3 +398,22 @@ command_nvram(int argc, char *argv[])
return (CMD_OK);
}
+
+#ifdef LOADER_FDT_SUPPORT
+extern int command_fdt_internal(int argc, char *argv[]);
+
+/*
+ * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
+ * and declaring it as extern is in contradiction with COMMAND_SET() macro
+ * (which uses static pointer), we're defining wrapper function, which
+ * calls the proper fdt handling routine.
+ */
+static int
+command_fdt(int argc, char *argv[])
+{
+
+ return (command_fdt_internal(argc, argv));
+}
+
+COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
+#endif
diff --git a/sys/boot/efi/loader/arch/amd64/reloc.c b/sys/boot/efi/loader/reloc.c
index 98bcf8e..fbe2043 100644
--- a/sys/boot/efi/loader/arch/amd64/reloc.c
+++ b/sys/boot/efi/loader/reloc.c
@@ -32,18 +32,38 @@ __FBSDID("$FreeBSD$");
#include <efi.h>
#include <bootstrap.h>
-#ifdef __i386__
+#if defined(__aarch64__)
+#define ElfW_Rel Elf64_Rela
+#define ElfW_Dyn Elf64_Dyn
+#define ELFW_R_TYPE ELF64_R_TYPE
+#define ELF_RELA
+#elif defined(__arm__) || defined(__i386__)
#define ElfW_Rel Elf32_Rel
#define ElfW_Dyn Elf32_Dyn
#define ELFW_R_TYPE ELF32_R_TYPE
-#elif __amd64__
+#elif defined(__amd64__)
#define ElfW_Rel Elf64_Rel
#define ElfW_Dyn Elf64_Dyn
#define ELFW_R_TYPE ELF64_R_TYPE
+#else
+#error architecture not supported
+#endif
+#if defined(__aarch64__)
+#define RELOC_TYPE_NONE R_AARCH64_NONE
+#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE
+#elif defined(__amd64__)
+#define RELOC_TYPE_NONE R_X86_64_NONE
+#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE
+#elif defined(__arm__)
+#define RELOC_TYPE_NONE R_ARM_NONE
+#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE
+#elif defined(__i386__)
+#define RELOC_TYPE_NONE R_386_NONE
+#define RELOC_TYPE_RELATIVE R_386_RELATIVE
#endif
/*
- * A simple relocator for IA32/AMD64 EFI binaries.
+ * A simple relocator for EFI binaries.
*/
EFI_STATUS
_reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle,
@@ -81,20 +101,21 @@ _reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle,
/*
* Perform the actual relocation.
- * XXX: We are reusing code for the amd64 version of this, but
- * we must make sure the relocation types are the same.
*/
- CTASSERT(R_386_NONE == R_X86_64_NONE);
- CTASSERT(R_386_RELATIVE == R_X86_64_RELATIVE);
for (; relsz > 0; relsz -= relent) {
switch (ELFW_R_TYPE(rel->r_info)) {
- case R_386_NONE:
+ case RELOC_TYPE_NONE:
/* No relocation needs be performed. */
break;
- case R_386_RELATIVE:
+
+ case RELOC_TYPE_RELATIVE:
/* Address relative to the base address. */
newaddr = (unsigned long *)(ImageBase + rel->r_offset);
*newaddr += ImageBase;
+ /* Add the addend when the ABI uses them */
+#ifdef ELF_RELA
+ *newaddr += rel->r_addend;
+#endif
break;
default:
/* XXX: do we need other relocations ? */
diff --git a/sys/boot/fdt/dts/arm/bcm2836.dtsi b/sys/boot/fdt/dts/arm/bcm2836.dtsi
index 7fdaecf..bd75c84 100644
--- a/sys/boot/fdt/dts/arm/bcm2836.dtsi
+++ b/sys/boot/fdt/dts/arm/bcm2836.dtsi
@@ -101,6 +101,12 @@
*/
};
+ watchdog0 {
+ compatible = "broadcom,bcm2835-wdt",
+ "broadcom,bcm2708-wdt";
+ reg = <0x10001c 0x0c>; /* 0x1c, 0x20, 0x24 */
+ };
+
gpio: gpio {
compatible = "broadcom,bcm2835-gpio",
"broadcom,bcm2708-gpio";
@@ -125,11 +131,11 @@
pinctrl-names = "default";
pinctrl-0 = <&pins_reserved>;
- /* Pins that can short 3.3V to GND in output mode: 46-47
+ /* Pins that can short 3.3V to GND in output mode: 46
* Pins used by VideoCore: 48-53
*/
- broadcom,read-only = <46>, <47>, <48>, <49>, <50>,
- <51>, <52>, <53>;
+ broadcom,read-only = <46>, <48>, <49>, <50>,
+ <51>, <52>, <53>;
/* BSC0 */
pins_bsc0_a: bsc0_a {
@@ -431,7 +437,7 @@
interrupts = <70>;
interrupt-parent = <&intc>;
- clock-frequency = <2500000000>; /* Set by VideoCore */
+ clock-frequency = <250000000>; /* Set by VideoCore */
};
uart0: uart0 {
diff --git a/sys/boot/fdt/dts/arm/meson8b.dtsi b/sys/boot/fdt/dts/arm/meson8b.dtsi
new file mode 100644
index 0000000..c76a01a
--- /dev/null
+++ b/sys/boot/fdt/dts/arm/meson8b.dtsi
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2015 John Wehle <john@feith.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/include/ "meson.dtsi"
+
+/ {
+ model = "Amlogic Meson8b SoC";
+ compatible = "amlogic,meson8b";
+
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x200>;
+ };
+
+ cpu@201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x201>;
+ };
+
+ cpu@202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x202>;
+ };
+
+ cpu@203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x203>;
+ };
+ };
+
+ clk81: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+};
+
+&L2 {
+ interrupts = <0 143 1>;
+};
diff --git a/sys/boot/fdt/dts/arm/odroidc1.dts b/sys/boot/fdt/dts/arm/odroidc1.dts
index 6a90ed4..c65344b 100644
--- a/sys/boot/fdt/dts/arm/odroidc1.dts
+++ b/sys/boot/fdt/dts/arm/odroidc1.dts
@@ -39,6 +39,8 @@
/memreserve/ 0x7900000 0x00600000; /* 6MB frame buffer */
+#include "meson8b.dtsi"
+
/ {
model = "hardkernel,odroid-c1";
compatible = "hardkernel,odroid-c1", "amlogic,s805";
@@ -46,41 +48,10 @@
#address-cells = <1>;
#size-cells = <1>;
- interrupt-parent = <&gic>;
-
aliases {
soc = &soc;
screen = &screen;
- uart0 = &uart0;
- };
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- cpu@0 {
- device_type = "cpu";
- compatible = "arm,cortex-a5";
- reg = <0x0>;
- };
-
- cpu@1 {
- device_type = "cpu";
- compatible = "arm,cortex-a5";
- reg = <0x1>;
- };
-
- cpu@2 {
- device_type = "cpu";
- compatible = "arm,cortex-a5";
- reg = <0x2>;
- };
-
- cpu@3 {
- device_type = "cpu";
- compatible = "arm,cortex-a5";
- reg = <0x3>;
- };
+ uart0 = &uart_AO;
};
memory {
@@ -88,60 +59,37 @@
reg = <0x0 0x40000000>; /* 1GB RAM */
};
- soc: soc@c0000000 {
+ soc: soc {
device_type = "soc";
- compatible = "simple-bus";
bus-frequency = <0>;
- #address-cells = <1>;
- #size-cells = <1>;
-
- ranges = <0x0 0xc0000000 0x1a100000>;
-
- gic: gic@4301000 {
- device_type = "interrupt-controller";
- compatible = "arm,gic";
- reg = <0x4301000 0x1000>, // distributer registers
- <0x4300100 0x0100>; // CPU if registers
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
-
- scu: scu@4300000 {
+ scu: scu@c4300000 {
compatible = "arm,cortex-a5-scu";
- reg = <0x4300000 0x1000>;
+ reg = <0xc4300000 0x1000>;
};
- cpuconfig: cpuconfig@1901ff80 {
+ cpuconfig: cpuconfig@d901ff80 {
compatible = "amlogic,aml8726-cpuconfig";
- reg = <0x1901ff80 16>;
+ reg = <0xd901ff80 16>;
};
- pl310@4200000 {
- compatible = "arm,pl310";
- reg = <0x4200000 0x1000>;
- interrupts = <61>;
- interrupt-parent = <&gic>;
- };
-
- ccm@1104140 {
+ ccm@c1104140 {
compatible = "amlogic,aml8726-ccm";
- reg = <0x1104140 20>; /* cbus 0x1050 */
+ reg = <0xc1104140 20>; /* cbus 0x1050 */
functions = "ethernet", "i2c", "rng", "sdio", "sdxc",
"uart-a", "uart-b", "uart-c",
"usb-a", "usb-b";
};
- pinctrl@11080b0 {
+ pinctrl@c11080b0 {
compatible = "amlogic,aml8726-pinctrl";
- reg = <0x11080b0 40>, /* mux */
- <0x11080e8 24>, /* pu/pd */
- <0x1108120 24>, /* pull enable */
- <0x8100014 4>, /* ao mux */
- <0x810002c 4>, /* ao pu/pd */
- <0x810002c 4>; /* ao pull enable */
+ reg = <0xc11080b0 40>, /* mux */
+ <0xc11080e8 24>, /* pu/pd */
+ <0xc1108120 24>, /* pull enable */
+ <0xc8100014 4>, /* ao mux */
+ <0xc810002c 4>, /* ao pu/pd */
+ <0xc810002c 4>; /* ao pull enable */
/*
* Currently only pin muxing that deviates
@@ -242,24 +190,10 @@
};
};
- watchdog@1109900 {
- compatible = "amlogic,aml8726-wdt";
- reg = <0x1109900 8>; /* cbus 0x2640 */
- interrupts = <0>;
- interrupt-parent = <&gic>;
- };
-
- timer@1109940 {
- compatible = "amlogic,aml8726-timer";
- reg = <0x1109940 24>; /* cbus 0x2650 */
- interrupts = <10 11 6 29>;
- interrupt-parent = <&gic>;
- };
-
- rtc@8100740 {
+ rtc@c8100740 {
compatible = "amlogic,aml8726-rtc";
- reg = <0x8100740 20>; /* aobus 0x1d0 */
- interrupts = <72>;
+ reg = <0xc8100740 20>; /* aobus 0x1d0 */
+ interrupts = <0 72 1>;
interrupt-parent = <&gic>;
init-always = "false";
@@ -267,62 +201,55 @@
gpo-init = <0x500000>;
};
- clkmsr: clkmsr@1108758 {
+ clkmsr: clkmsr@c1108758 {
compatible = "amlogic,aml8726-clkmsr";
- reg = <0x1108758 16>; /* cbus 0x21d6 */
- };
+ reg = <0xc1108758 16>; /* cbus 0x21d6 */
- uart0: uart@81004c0 {
- /* uart-ao */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x81004c0 20>; /* aobus 0x130 */
- interrupts = <90>;
- interrupt-parent = <&gic>;
+ clocks = <&clk81>;
};
- gpioao: gpio@8100024 {
+ gpioao: gpio@c8100024 {
/* gpio unit 7 */
compatible = "amlogic,aml8726-gpio";
- reg = <0x8100024 4>, /* oen aobus 0x9 */
- <0x8100024 4>, /* out */
- <0x8100028 4>; /* in */
+ reg = <0xc8100024 4>, /* oen aobus 0x9 */
+ <0xc8100024 4>, /* out */
+ <0xc8100028 4>; /* in */
gpio-controller;
#gpio-cells = <1>;
pin-count = <14>;
};
- gpio3: gpio@1108054 {
+ gpio3: gpio@c1108054 {
compatible = "amlogic,aml8726-gpio";
- reg = <0x1108054 4>, /* oen cbus 0x2015 */
- <0x1108058 4>, /* out */
- <0x110805c 4>; /* in */
+ reg = <0xc1108054 4>, /* oen cbus 0x2015 */
+ <0xc1108058 4>, /* out */
+ <0xc110805c 4>; /* in */
gpio-controller;
#gpio-cells = <1>;
pin-count = <32>;
};
- gpio5: gpio@110806c {
+ gpio5: gpio@c110806c {
compatible = "amlogic,aml8726-gpio";
- reg = <0x110806c 4>, /* oen cbus 0x201b */
- <0x1108070 4>, /* out */
- <0x1108074 4>; /* in */
+ reg = <0xc110806c 4>, /* oen cbus 0x201b */
+ <0xc1108070 4>, /* out */
+ <0xc1108074 4>; /* in */
gpio-controller;
#gpio-cells = <1>;
pin-count = <32>;
};
- mmc@1108c20 {
+ mmc@c1108c20 {
compatible = "amlogic,aml8726-mmc";
- reg = <0x1108c20 32>; /* cbus 0x2308 */
- interrupts = <28>;
+ reg = <0xc1108c20 32>; /* cbus 0x2308 */
+ interrupts = <0 28 1>;
interrupt-parent = <&gic>;
+ clocks = <&clk81>;
+
pinctrl-names = "default";
pinctrl-0 = <&pins_sdio_b>;
@@ -342,11 +269,11 @@
ins-detect = <&gpio5 29 0>; /* card_6 */
};
- sdxc@1108e00 {
+ sdxc@c1108e00 {
compatible = "amlogic,aml8726-sdxc-m8";
clock-frequency = <1275000000>;
- reg = <0x1108e00 60>; /* cbus 0x2380 */
- interrupts = <78>;
+ reg = <0xc1108e00 60>; /* cbus 0x2380 */
+ interrupts = <0 78 1>;
interrupt-parent = <&gic>;
pinctrl-names = "default";
@@ -357,82 +284,33 @@
mmc-rst = <&gpio3 9 0>; /* boot_9 emmc-rst */
};
- rng@1108100 {
+ rng@c1108100 {
compatible = "amlogic,aml8726-rng";
- reg = <0x1108100 8>; /* cbus 0x2040 */
+ reg = <0xc1108100 8>; /* cbus 0x2040 */
};
- i2c@1108500 {
- /* i2c-a */
- compatible = "amlogic,aml8726-i2c";
- reg = <0x1108500 32>; /* cbus 0x2140 */
- interrupts = <21>;
- interrupt-parent = <&gic>;
- };
-
- i2c@11087c0 {
- /* i2c-b */
- compatible = "amlogic,aml8726-i2c";
- reg = <0x11087c0 32>; /* cbus 0x21f0 */
- interrupts = <128>;
- interrupt-parent = <&gic>;
- };
-
- uart@11084c0 {
- /* uart-a */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x11084c0 20>; /* cbus 0x2130 */
- interrupts = <26>;
- interrupt-parent = <&gic>;
- };
-
- uart@11084dc {
- /* uart-b */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x11084dc 20>; /* cbus 0x2137 */
- interrupts = <75>;
- interrupt-parent = <&gic>;
- };
-
- uart@1108700 {
- /* uart-c */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x1108700 20>; /* cbus 0x21c0 */
- interrupts = <93>;
- interrupt-parent = <&gic>;
- };
-
- usb-phy@1108800 {
+ usb-phy@c1108800 {
/* usb-a phy */
compatible = "amlogic,aml8726-m8-usb-phy";
- reg = <0x1108800 32>; /* cbus 0x2200 */
+ reg = <0xc1108800 32>; /* cbus 0x2200 */
usb-pwr-en = <&gpioao 5 1>; /* gpioao_5 vbus */
};
- usb-phy@1108820 {
+ usb-phy@c1108820 {
/* usb-b phy */
compatible = "amlogic,aml8726-m8-usb-phy";
- reg = <0x1108820 32>; /* cbus 0x2208 */
+ reg = <0xc1108820 32>; /* cbus 0x2208 */
force-aca = "true";
usb-hub-rst = <&gpioao 4 0>; /* gpioao_4 hub-rst */
};
- usb@9040000 {
+ usb@c9040000 {
/* usb-a */
compatible = "synopsys,designware-hs-otg2";
- reg = <0x9040000 0x40000>; /* ahbbus 0x40000*/
- interrupts = <30>;
+ reg = <0xc9040000 0x40000>; /* ahbbus 0x40000*/
+ interrupts = <0 30 4>;
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;
@@ -440,11 +318,11 @@
dr_mode = "host";
};
- usb@90c0000 {
+ usb@c90c0000 {
/* usb-b */
compatible = "synopsys,designware-hs-otg2";
- reg = <0x90c0000 0x40000>; /* ahbbus 0xc0000 */
- interrupts = <31>;
+ reg = <0xc90c0000 0x40000>; /* ahbbus 0xc0000 */
+ interrupts = <0 31 4>;
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;
@@ -452,11 +330,11 @@
dr_mode = "host";
};
- eth@9410000 {
+ eth@c9410000 {
/* ethernet */
compatible = "snps,dwmac";
- reg = <0x9410000 0x2000>; /* ahbbus 0x410000 */
- interrupts = <8>;
+ reg = <0xc9410000 0x2000>; /* ahbbus 0x410000 */
+ interrupts = <0 8 1>;
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;
@@ -464,13 +342,16 @@
eth-phy-rst = <&gpio3 23 0>; /* gpioh_4 phy-rst */
};
- screen: fb@8006020 {
+ screen: fb@c8006020 {
device_type = "display";
compatible = "amlogic,aml8726-fb";
- reg = <0x8006048 12>, /* CANVAS */
- <0x1106800 1024>, /* VIU */
- <0x1107400 1024>; /* VPP */
- interrupts = <2 3 12 13>;
+ reg = <0xc8006048 12>, /* CANVAS */
+ <0xc1106800 1024>, /* VIU */
+ <0xc1107400 1024>; /* VPP */
+ interrupts = <0 2 1>,
+ <0 3 1>,
+ <0 12 1>,
+ <0 13 1>;
interrupt-parent = <&gic>;
address = <0x7900000>; /* match memreserve */
@@ -495,3 +376,32 @@
stdout = "uart0";
};
};
+
+&clk81 {
+ clock-frequency = <0>;
+};
+
+&uart_AO {
+ status = "okay";
+ current-speed = <115200>;
+};
+
+&uart_A {
+ status = "okay";
+};
+
+&uart_B {
+ status = "okay";
+};
+
+&uart_C {
+ status = "okay";
+};
+
+&i2c_A {
+ status = "okay";
+};
+
+&i2c_B {
+ status = "okay";
+};
diff --git a/sys/boot/fdt/dts/arm/rpi2.dts b/sys/boot/fdt/dts/arm/rpi2.dts
index 59974f1..1c8c559 100644
--- a/sys/boot/fdt/dts/arm/rpi2.dts
+++ b/sys/boot/fdt/dts/arm/rpi2.dts
@@ -322,18 +322,14 @@
leds {
compatible = "gpio-leds";
- ok {
- label = "ok";
- gpios = <&gpio 16 1>;
-
- /* Don't change this - it configures
- * how the led driver determines if
- * the led is on or off when it loads.
- */
- default-state = "keep";
-
- /* This is the real default state. */
- linux,default-trigger = "default-on";
+ pwr {
+ label = "pwr";
+ gpios = <&gpio 35 0>;
+ };
+
+ act {
+ label = "act";
+ gpios = <&gpio 47 0>;
};
};
diff --git a/sys/boot/fdt/dts/arm/vsatv102-m6.dts b/sys/boot/fdt/dts/arm/vsatv102-m6.dts
index 639e010..ad3b5a1 100644
--- a/sys/boot/fdt/dts/arm/vsatv102-m6.dts
+++ b/sys/boot/fdt/dts/arm/vsatv102-m6.dts
@@ -39,6 +39,8 @@
/memreserve/ 0x84900000 0x00600000; /* 6MB frame buffer */
+#include "meson6.dtsi"
+
/ {
/*
* My development unit visually appears to be a Visson ATV-102
@@ -50,34 +52,15 @@
*/
model = "visson,atv-102";
- compatible = "visson,atv-102", "amlogic,aml8726-m6";
+ compatible = "visson,atv-102", "amlogic,meson6";
#address-cells = <1>;
#size-cells = <1>;
- interrupt-parent = <&gic>;
-
aliases {
soc = &soc;
screen = &screen;
- uart0 = &uart0;
- };
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- cpu@0 {
- device_type = "cpu";
- compatible = "arm,cortex-a9";
- reg = <0x0>;
- };
-
- cpu@1 {
- device_type = "cpu";
- compatible = "arm,cortex-a9";
- reg = <0x1>;
- };
+ uart0 = &uart_AO;
};
memory {
@@ -85,69 +68,46 @@
reg = <0x80000000 0x40000000>; /* 1GB RAM */
};
- soc: soc@c0000000 {
+ soc: soc {
device_type = "soc";
- compatible = "simple-bus";
bus-frequency = <0>;
- #address-cells = <1>;
- #size-cells = <1>;
-
- ranges = <0x0 0xc0000000 0x1a100000>;
-
- pic: pic@1109a40 {
+ pic: pic@c1109a40 {
device_type = "interrupt-controller";
compatible = "amlogic,aml8726-pic";
- reg = <0x1109a40 128>; /* cbus 0x2690 */
+ reg = <0xc1109a40 128>; /* cbus 0x2690 */
interrupt-controller;
- #interrupt-cells = <1>;
+ #interrupt-cells = <3>;
};
- gic: gic@4301000 {
- device_type = "interrupt-controller";
- compatible = "arm,gic";
- reg = <0x4301000 0x1000>, /* distributer registers */
- <0x4300100 0x0100>; /* CPU if registers */
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
-
- scu: scu@4300000 {
+ scu: scu@c4300000 {
compatible = "arm,cortex-a9-scu";
- reg = <0x4300000 0x1000>;
+ reg = <0xc4300000 0x1000>;
};
- cpuconfig: cpuconfig@1901ff80 {
+ cpuconfig: cpuconfig@d901ff80 {
compatible = "amlogic,aml8726-cpuconfig";
- reg = <0x1901ff80 8>;
- };
-
- pl310@4200000 {
- compatible = "arm,pl310";
- reg = <0x4200000 0x1000>;
- interrupts = <61>; /* AM_IRQ1(29) */
- interrupt-parent = <&gic>;
+ reg = <0xd901ff80 8>;
};
- ccm@1104140 {
+ ccm@c1104140 {
compatible = "amlogic,aml8726-ccm";
- reg = <0x1104140 20>; /* cbus 0x1050 */
+ reg = <0xc1104140 20>; /* cbus 0x1050 */
functions = "ethernet", "i2c", "rng", "sdio",
"uart-a", "uart-b", "uart-c",
"usb-a", "usb-b";
};
- pinctrl: pinctrl@11080b0 {
+ pinctrl: pinctrl@c11080b0 {
compatible = "amlogic,aml8726-pinctrl";
- reg = <0x11080b0 40>, /* mux */
- <0x11080e8 24>, /* pu/pd */
- <0x11080e8 24>, /* pull enable */
- <0x8100014 4>, /* ao mux */
- <0x810002c 4>, /* ao pu/pd */
- <0x810002c 4>; /* ao pull enable */
+ reg = <0xc11080b0 40>, /* mux */
+ <0xc11080e8 24>, /* pu/pd */
+ <0xc11080e8 24>, /* pull enable */
+ <0xc8100014 4>, /* ao mux */
+ <0xc810002c 4>, /* ao pu/pd */
+ <0xc810002c 4>; /* ao pull enable */
/*
* Currently only pin muxing that deviates
@@ -189,27 +149,10 @@
};
};
- watchdog@1109900 {
- compatible = "amlogic,aml8726-wdt";
- reg = <0x1109900 8>; /* cbus 0x2640 */
- interrupts = <0>; /* AM_IRQ0(0) */
- interrupt-parent = <&gic>;
- };
-
- timer@1109940 {
- compatible = "amlogic,aml8726-timer";
- reg = <0x1109940 24>; /* cbus 0x2650 */
- interrupts = <10 /* AM_IRQ0(10) */
- 11 /* AM_IRQ0(11) */
- 6 /* AM_IRQ0(6) */
- 29>; /* AM_IRQ0(29) */
- interrupt-parent = <&gic>;
- };
-
- rtc@1a004340 {
+ rtc@da004340 {
compatible = "amlogic,aml8726-rtc";
- reg = <0x1a004340 20>; /* secbus2 0xd0 */
- interrupts = <72>; /* AM_IRQ2(8) */
+ reg = <0xda004340 20>; /* secbus2 0xd0 */
+ interrupts = <0 72 1>; /* AM_IRQ2(8) */
interrupt-parent = <&gic>;
init-always = "false";
@@ -217,62 +160,55 @@
gpo-init = <0x500000>;
};
- clkmsr: clkmsr@1108758 {
+ clkmsr: clkmsr@c1108758 {
compatible = "amlogic,aml8726-clkmsr";
- reg = <0x1108758 16>; /* cbus 0x21d6 */
- };
+ reg = <0xc1108758 16>; /* cbus 0x21d6 */
- uart0: uart@81004c0 {
- /* uart-ao */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x81004c0 20>; /* aobus 0x130 */
- interrupts = <90>; /* AM_IRQ2(26) */
- interrupt-parent = <&gic>;
+ clocks = <&clk81>;
};
- gpioao: gpio@8100024 {
+ gpioao: gpio@c8100024 {
/* gpio unit 7 */
compatible = "amlogic,aml8726-gpio";
- reg = <0x8100024 4>, /* oen aobus 0x9 */
- <0x8100024 4>, /* out */
- <0x8100028 4>; /* in */
+ reg = <0xc8100024 4>, /* oen aobus 0x9 */
+ <0xc8100024 4>, /* out */
+ <0xc8100028 4>; /* in */
gpio-controller;
#gpio-cells = <1>;
pin-count = <12>;
};
- gpio5: gpio@110806c {
+ gpio5: gpio@c110806c {
compatible = "amlogic,aml8726-gpio";
- reg = <0x110806c 4>, /* oen cbus 0x201b */
- <0x1108070 4>, /* out */
- <0x1108074 4>; /* in */
+ reg = <0xc110806c 4>, /* oen cbus 0x201b */
+ <0xc1108070 4>, /* out */
+ <0xc1108074 4>; /* in */
gpio-controller;
#gpio-cells = <1>;
pin-count = <32>;
};
- gpio6: gpio@1108020 {
+ gpio6: gpio@c1108020 {
compatible = "amlogic,aml8726-gpio";
- reg = <0x1108020 4>, /* oen cbus 0x2008 */
- <0x1108024 4>, /* out */
- <0x1108028 4>; /* in */
+ reg = <0xc1108020 4>, /* oen cbus 0x2008 */
+ <0xc1108024 4>, /* out */
+ <0xc1108028 4>; /* in */
gpio-controller;
#gpio-cells = <1>;
pin-count = <29>;
};
- mmc@1108c20 {
+ mmc@c1108c20 {
compatible = "amlogic,aml8726-mmc";
- reg = <0x1108c20 32>; /* cbus 0x2308 */
- interrupts = <28>; /* AM_IRQ0(28) */
+ reg = <0xc1108c20 32>; /* cbus 0x2308 */
+ interrupts = <0 28 1>; /* AM_IRQ0(28) */
interrupt-parent = <&gic>;
+ clocks = <&clk81>;
+
pinctrl-names = "default";
pinctrl-0 = <&pins_sdio_b>;
@@ -282,90 +218,41 @@
ins-detect = <&gpio5 29 0>; /* card_6 */
};
- rng@1108100 {
+ rng@c1108100 {
compatible = "amlogic,aml8726-rng";
- reg = <0x1108100 8>; /* cbus 0x2040 */
- };
-
- i2c@1108500 {
- /* i2c-a */
- compatible = "amlogic,aml8726-i2c";
- reg = <0x1108500 32>; /* cbus 0x2140 */
- interrupts = <21>;
- interrupt-parent = <&gic>;
- };
-
- i2c@11087c0 {
- /* i2c-b */
- compatible = "amlogic,aml8726-i2c";
- reg = <0x11087c0 32>; /* cbus 0x21f0 */
- interrupts = <128>;
- interrupt-parent = <&gic>;
+ reg = <0xc1108100 8>; /* cbus 0x2040 */
};
- uart@11084c0 {
- /* uart-a */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x11084c0 20>; /* cbus 0x2130 */
- interrupts = <26>;
- interrupt-parent = <&gic>;
- };
-
- uart@11084dc {
- /* uart-b */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x11084dc 20>; /* cbus 0x2137 */
- interrupts = <75>;
- interrupt-parent = <&gic>;
- };
-
- uart@1108700 {
- /* uart-c */
- device_type = "serial";
- compatible = "amlogic,aml8726-uart";
- clock-frequency = <0>;
- current-speed = <115200>;
- reg = <0x1108700 20>; /* cbus 0x21c0 */
- interrupts = <93>;
- interrupt-parent = <&gic>;
- };
-
- usb-phy@1108400 {
+ usb-phy@c1108400 {
/* usb-a phy */
compatible = "amlogic,aml8726-m6-usb-phy";
- reg = <0x1108400 32>; /* cbus 0x2100 */
+ reg = <0xc1108400 32>; /* cbus 0x2100 */
};
- usb-phy@1108420 {
+ usb-phy@c1108420 {
/* usb-b phy */
compatible = "amlogic,aml8726-m6-usb-phy";
- reg = <0x1108420 32>; /* cbus 0x2108 */
+ reg = <0xc1108420 32>; /* cbus 0x2108 */
usb-pwr-en = <&gpioao 3 1>, /* gpioao_3 vbus */
<&gpio6 11 0>; /* gpioe_11 wifi */
};
- usb@9040000 {
+ usb@c9040000 {
/* usb-a */
compatible = "synopsys,designware-hs-otg2";
- reg = <0x9040000 0x40000>; /* ahbbus 0x40000*/
- interrupts = <30>; /* AM_IRQ0(30) */
+ reg = <0xc9040000 0x40000>; /* ahbbus 0x40000*/
+ interrupts = <0 30 4>; /* AM_IRQ0(30) */
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;
};
- usb@90c0000 {
+ usb@c90c0000 {
/* usb-b */
compatible = "synopsys,designware-hs-otg2";
- reg = <0x90c0000 0x40000>; /* ahbbus 0xc0000 */
- interrupts = <31>; /* AM_IRQ0(31) */
+ reg = <0xc90c0000 0x40000>; /* ahbbus 0xc0000 */
+ interrupts = <0 31 4>; /* AM_IRQ0(31) */
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;
@@ -373,11 +260,11 @@
dr_mode = "host";
};
- eth@9410000 {
+ eth@c9410000 {
/* ethernet */
compatible = "snps,dwmac";
- reg = <0x9410000 0x2000>; /* ahbbus 0x410000 */
- interrupts = <8>; /* AM_IRQ0(8) */
+ reg = <0xc9410000 0x2000>; /* ahbbus 0x410000 */
+ interrupts = <0 8 1>; /* AM_IRQ0(8) */
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;
@@ -385,16 +272,16 @@
eth-phy-rst = <&gpio5 15 0>; /* gpioy_15 phy-rst */
};
- screen: fb@8006324 {
+ screen: fb@c8006324 {
device_type = "display";
compatible = "amlogic,aml8726-fb";
- reg = <0x8006324 12>, /* CANVAS */
- <0x1106800 1024>, /* VIU */
- <0x1107400 1024>; /* VPP */
- interrupts = <2 /* AM_IRQ0(2) */
- 3 /* AM_IRQ0(3) */
- 12 /* AM_IRQ0(12) */
- 13>; /* AM_IRQ0(13) */
+ reg = <0xc8006324 12>, /* CANVAS */
+ <0xc1106800 1024>, /* VIU */
+ <0xc1107400 1024>; /* VPP */
+ interrupts = <0 2 1>, /* AM_IRQ0(2) */
+ <0 3 1>, /* AM_IRQ0(3) */
+ <0 12 1>, /* AM_IRQ0(12) */
+ <0 13 1>; /* AM_IRQ0(13) */
interrupt-parent = <&gic>;
address = <0x84900000>; /* match memreserve */
@@ -410,3 +297,12 @@
stdout = "uart0";
};
};
+
+&clk81 {
+ clock-frequency = <0>;
+};
+
+&uart_AO {
+ status = "okay";
+ current-speed = <115200>;
+};
diff --git a/sys/boot/ficl/aarch64/sysdep.c b/sys/boot/ficl/aarch64/sysdep.c
new file mode 100644
index 0000000..ad38660
--- /dev/null
+++ b/sys/boot/ficl/aarch64/sysdep.c
@@ -0,0 +1,99 @@
+/*******************************************************************
+** s y s d e p . c
+** Forth Inspired Command Language
+** Author: John Sadler (john_sadler@alum.mit.edu)
+** Created: 16 Oct 1997
+** Implementations of FICL external interface functions...
+**
+*******************************************************************/
+
+/* $FreeBSD$ */
+
+#ifdef TESTMAIN
+#include <stdio.h>
+#include <stdlib.h>
+#else
+#include <stand.h>
+#endif
+#include "ficl.h"
+
+/*
+******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith
+*/
+
+#if PORTABLE_LONGMULDIV == 0
+DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y)
+{
+ DPUNS q;
+ u_int64_t qx;
+
+ qx = (u_int64_t)x * (u_int64_t) y;
+
+ q.hi = (u_int32_t)( qx >> 32 );
+ q.lo = (u_int32_t)( qx & 0xFFFFFFFFL);
+
+ return q;
+}
+
+UNSQR ficlLongDiv(DPUNS q, FICL_UNS y)
+{
+ UNSQR result;
+ u_int64_t qx, qh;
+
+ qh = q.hi;
+ qx = (qh << 32) | q.lo;
+
+ result.quot = qx / y;
+ result.rem = qx % y;
+
+ return result;
+}
+#endif
+
+void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline)
+{
+ IGNORE(pVM);
+
+ while(*msg != 0)
+ putchar(*(msg++));
+ if (fNewline)
+ putchar('\n');
+
+ return;
+}
+
+void *ficlMalloc (size_t size)
+{
+ return malloc(size);
+}
+
+void *ficlRealloc (void *p, size_t size)
+{
+ return realloc(p, size);
+}
+
+void ficlFree (void *p)
+{
+ free(p);
+}
+
+
+/*
+** Stub function for dictionary access control - does nothing
+** by default, user can redefine to guarantee exclusive dict
+** access to a single thread for updates. All dict update code
+** is guaranteed to be bracketed as follows:
+** ficlLockDictionary(TRUE);
+** <code that updates dictionary>
+** ficlLockDictionary(FALSE);
+**
+** Returns zero if successful, nonzero if unable to acquire lock
+** befor timeout (optional - could also block forever)
+*/
+#if FICL_MULTITHREAD
+int ficlLockDictionary(short fLock)
+{
+ IGNORE(fLock);
+ return 0;
+}
+#endif /* FICL_MULTITHREAD */
diff --git a/sys/boot/ficl/aarch64/sysdep.h b/sys/boot/ficl/aarch64/sysdep.h
new file mode 100644
index 0000000..3726b9e
--- /dev/null
+++ b/sys/boot/ficl/aarch64/sysdep.h
@@ -0,0 +1,411 @@
+/*******************************************************************
+ s y s d e p . h
+** Forth Inspired Command Language
+** Author: John Sadler (john_sadler@alum.mit.edu)
+** Created: 16 Oct 1997
+** Ficl system dependent types and prototypes...
+**
+** Note: Ficl also depends on the use of "assert" when
+** FICL_ROBUST is enabled. This may require some consideration
+** in firmware systems since assert often
+** assumes stderr/stdout.
+** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $
+*******************************************************************/
+/*
+** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
+** All rights reserved.
+**
+** Get the latest Ficl release at http://ficl.sourceforge.net
+**
+** L I C E N S E and D I S C L A I M E R
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+**
+** I am interested in hearing from anyone who uses ficl. If you have
+** a problem, a success story, a defect, an enhancement request, or
+** if you would like to contribute to the ficl release, please send
+** contact me by email at the address above.
+**
+** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $
+** $FreeBSD$
+*/
+
+#if !defined (__SYSDEP_H__)
+#define __SYSDEP_H__
+
+#include <sys/types.h>
+
+#include <stddef.h> /* size_t, NULL */
+#include <setjmp.h>
+#include <assert.h>
+
+#if !defined IGNORE /* Macro to silence unused param warnings */
+#define IGNORE(x) (void)(x)
+#endif
+
+/*
+** TRUE and FALSE for C boolean operations, and
+** portable 32 bit types for CELLs
+**
+*/
+#if !defined TRUE
+#define TRUE 1
+#endif
+#if !defined FALSE
+#define FALSE 0
+#endif
+
+
+/*
+** System dependent data type declarations...
+*/
+#if !defined INT32
+#define INT32 int
+#endif
+
+#if !defined UNS32
+#define UNS32 unsigned int
+#endif
+
+#if !defined UNS16
+#define UNS16 unsigned short
+#endif
+
+#if !defined UNS8
+#define UNS8 unsigned char
+#endif
+
+#if !defined NULL
+#define NULL ((void *)0)
+#endif
+
+/*
+** FICL_UNS and FICL_INT must have the same size as a void* on
+** the target system. A CELL is a union of void*, FICL_UNS, and
+** FICL_INT.
+** (11/2000: same for FICL_FLOAT)
+*/
+#if !defined FICL_INT
+#define FICL_INT long
+#endif
+
+#if !defined FICL_UNS
+#define FICL_UNS unsigned long
+#endif
+
+#if !defined FICL_FLOAT
+#define FICL_FLOAT float
+#endif
+
+/*
+** Ficl presently supports values of 32 and 64 for BITS_PER_CELL
+*/
+#if !defined BITS_PER_CELL
+#define BITS_PER_CELL 64
+#endif
+
+#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64))
+ Error!
+#endif
+
+typedef struct
+{
+ FICL_UNS hi;
+ FICL_UNS lo;
+} DPUNS;
+
+typedef struct
+{
+ FICL_UNS quot;
+ FICL_UNS rem;
+} UNSQR;
+
+typedef struct
+{
+ FICL_INT hi;
+ FICL_INT lo;
+} DPINT;
+
+typedef struct
+{
+ FICL_INT quot;
+ FICL_INT rem;
+} INTQR;
+
+
+/*
+** B U I L D C O N T R O L S
+*/
+
+#if !defined (FICL_MINIMAL)
+#define FICL_MINIMAL 0
+#endif
+#if (FICL_MINIMAL)
+#define FICL_WANT_SOFTWORDS 0
+#define FICL_WANT_FLOAT 0
+#define FICL_WANT_USER 0
+#define FICL_WANT_LOCALS 0
+#define FICL_WANT_DEBUGGER 0
+#define FICL_WANT_OOP 0
+#define FICL_PLATFORM_EXTEND 0
+#define FICL_MULTITHREAD 0
+#define FICL_ROBUST 0
+#define FICL_EXTENDED_PREFIX 0
+#endif
+
+/*
+** FICL_PLATFORM_EXTEND
+** Includes words defined in ficlCompilePlatform
+*/
+#if !defined (FICL_PLATFORM_EXTEND)
+#define FICL_PLATFORM_EXTEND 1
+#endif
+
+/*
+** FICL_WANT_FLOAT
+** Includes a floating point stack for the VM, and words to do float operations.
+** Contributed by Guy Carver
+*/
+#if !defined (FICL_WANT_FLOAT)
+#define FICL_WANT_FLOAT 0
+#endif
+
+/*
+** FICL_WANT_DEBUGGER
+** Inludes a simple source level debugger
+*/
+#if !defined (FICL_WANT_DEBUGGER)
+#define FICL_WANT_DEBUGGER 1
+#endif
+
+/*
+** User variables: per-instance variables bound to the VM.
+** Kinda like thread-local storage. Could be implemented in a
+** VM private dictionary, but I've chosen the lower overhead
+** approach of an array of CELLs instead.
+*/
+#if !defined FICL_WANT_USER
+#define FICL_WANT_USER 1
+#endif
+
+#if !defined FICL_USER_CELLS
+#define FICL_USER_CELLS 16
+#endif
+
+/*
+** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and
+** a private dictionary for local variable compilation.
+*/
+#if !defined FICL_WANT_LOCALS
+#define FICL_WANT_LOCALS 1
+#endif
+
+/* Max number of local variables per definition */
+#if !defined FICL_MAX_LOCALS
+#define FICL_MAX_LOCALS 16
+#endif
+
+/*
+** FICL_WANT_OOP
+** Inludes object oriented programming support (in softwords)
+** OOP support requires locals and user variables!
+*/
+#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER)
+#if !defined (FICL_WANT_OOP)
+#define FICL_WANT_OOP 0
+#endif
+#endif
+
+#if !defined (FICL_WANT_OOP)
+#define FICL_WANT_OOP 1
+#endif
+
+/*
+** FICL_WANT_SOFTWORDS
+** Controls inclusion of all softwords in softcore.c
+*/
+#if !defined (FICL_WANT_SOFTWORDS)
+#define FICL_WANT_SOFTWORDS 1
+#endif
+
+/*
+** FICL_MULTITHREAD enables dictionary mutual exclusion
+** wia the ficlLockDictionary system dependent function.
+** Note: this implementation is experimental and poorly
+** tested. Further, it's unnecessary unless you really
+** intend to have multiple SESSIONS (poor choice of name
+** on my part) - that is, threads that modify the dictionary
+** at the same time.
+*/
+#if !defined FICL_MULTITHREAD
+#define FICL_MULTITHREAD 0
+#endif
+
+/*
+** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be
+** defined in C in sysdep.c. Use this if you cannot easily
+** generate an inline asm definition
+*/
+#if !defined (PORTABLE_LONGMULDIV)
+#define PORTABLE_LONGMULDIV 0
+#endif
+
+/*
+** INLINE_INNER_LOOP causes the inner interpreter to be inline code
+** instead of a function call. This is mainly because MS VC++ 5
+** chokes with an internal compiler error on the function version.
+** in release mode. Sheesh.
+*/
+#if !defined INLINE_INNER_LOOP
+#if defined _DEBUG
+#define INLINE_INNER_LOOP 0
+#else
+#define INLINE_INNER_LOOP 1
+#endif
+#endif
+
+/*
+** FICL_ROBUST enables bounds checking of stacks and the dictionary.
+** This will detect stack over and underflows and dictionary overflows.
+** Any exceptional condition will result in an assertion failure.
+** (As generated by the ANSI assert macro)
+** FICL_ROBUST == 1 --> stack checking in the outer interpreter
+** FICL_ROBUST == 2 also enables checking in many primitives
+*/
+
+#if !defined FICL_ROBUST
+#define FICL_ROBUST 2
+#endif
+
+/*
+** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of
+** a new virtual machine's stacks, unless overridden at
+** create time.
+*/
+#if !defined FICL_DEFAULT_STACK
+#define FICL_DEFAULT_STACK 128
+#endif
+
+/*
+** FICL_DEFAULT_DICT specifies the number of CELLs to allocate
+** for the system dictionary by default. The value
+** can be overridden at startup time as well.
+** FICL_DEFAULT_ENV specifies the number of cells to allot
+** for the environment-query dictionary.
+*/
+#if !defined FICL_DEFAULT_DICT
+#define FICL_DEFAULT_DICT 12288
+#endif
+
+#if !defined FICL_DEFAULT_ENV
+#define FICL_DEFAULT_ENV 260
+#endif
+
+/*
+** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in
+** the dictionary search order. See Forth DPANS sec 16.3.3
+** (file://dpans16.htm#16.3.3)
+*/
+#if !defined FICL_DEFAULT_VOCS
+#define FICL_DEFAULT_VOCS 16
+#endif
+
+/*
+** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure
+** that stores pointers to parser extension functions. I would never expect to have
+** more than 8 of these, so that's the default limit. Too many of these functions
+** will probably exact a nasty performance penalty.
+*/
+#if !defined FICL_MAX_PARSE_STEPS
+#define FICL_MAX_PARSE_STEPS 8
+#endif
+
+/*
+** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if
+** included as part of softcore.c)
+*/
+#if !defined FICL_EXTENDED_PREFIX
+#define FICL_EXTENDED_PREFIX 0
+#endif
+
+/*
+** FICL_ALIGN is the power of two to which the dictionary
+** pointer address must be aligned. This value is usually
+** either 1 or 2, depending on the memory architecture
+** of the target system; 2 is safe on any 16 or 32 bit
+** machine. 3 would be appropriate for a 64 bit machine.
+*/
+#if !defined FICL_ALIGN
+#define FICL_ALIGN 3
+#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1)
+#endif
+
+/*
+** System dependent routines --
+** edit the implementations in sysdep.c to be compatible
+** with your runtime environment...
+** ficlTextOut sends a NULL terminated string to the
+** default output device - used for system error messages
+** ficlMalloc and ficlFree have the same semantics as malloc and free
+** in standard C
+** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned
+** product
+** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient
+** and remainder
+*/
+struct vm;
+void ficlTextOut(struct vm *pVM, char *msg, int fNewline);
+void *ficlMalloc (size_t size);
+void ficlFree (void *p);
+void *ficlRealloc(void *p, size_t size);
+/*
+** Stub function for dictionary access control - does nothing
+** by default, user can redefine to guarantee exclusive dict
+** access to a single thread for updates. All dict update code
+** must be bracketed as follows:
+** ficlLockDictionary(TRUE);
+** <code that updates dictionary>
+** ficlLockDictionary(FALSE);
+**
+** Returns zero if successful, nonzero if unable to acquire lock
+** before timeout (optional - could also block forever)
+**
+** NOTE: this function must be implemented with lock counting
+** semantics: nested calls must behave properly.
+*/
+#if FICL_MULTITHREAD
+int ficlLockDictionary(short fLock);
+#else
+#define ficlLockDictionary(x) 0 /* ignore */
+#endif
+
+/*
+** 64 bit integer math support routines: multiply two UNS32s
+** to get a 64 bit product, & divide the product by an UNS32
+** to get an UNS32 quotient and remainder. Much easier in asm
+** on a 32 bit CPU than in C, which usually doesn't support
+** the double length result (but it should).
+*/
+DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y);
+UNSQR ficlLongDiv(DPUNS q, FICL_UNS y);
+
+#endif /*__SYSDEP_H__*/
diff --git a/sys/boot/forth/check-password.4th b/sys/boot/forth/check-password.4th
index 04114aa..d41777c 100644
--- a/sys/boot/forth/check-password.4th
+++ b/sys/boot/forth/check-password.4th
@@ -146,6 +146,15 @@ only forth definitions also password-processing
2drop read-reset
else drop then
+ \ Prompt for GEOM ELI (geli(8)) passphrase if enabled
+ s" geom_eli_passphrase_prompt" getenv dup -1 <> if
+ s" YES" compare-insensitive 0= if
+ s" GELI Passphrase: " read ( prompt -- )
+ readval readlen @ s" kern.geom.eli.passphrase" setenv
+ read-reset
+ then
+ else drop then
+
\ Exit if a password was not set
s" password" getenv -1 = if exit else drop then
diff --git a/sys/boot/forth/check-password.4th.8 b/sys/boot/forth/check-password.4th.8
index e1f52b7..db0aa4b 100644
--- a/sys/boot/forth/check-password.4th.8
+++ b/sys/boot/forth/check-password.4th.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2011-2012 Devin Teske
+.\" Copyright (c) 2011-2015 Devin Teske
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 10, 2012
+.Dd March 20, 2015
.Dt CHECK-PASSWORD.4TH 8
.Os
.Sh NAME
@@ -33,8 +33,12 @@
.Sh DESCRIPTION
The file that goes by the name of
.Nm
-is a set of commands designed to either prevent booting or prevent modification
-of boot options without an appropriately configured password.
+is a set of commands designed to do one or more of the following:
+.Pp
+.Dl o Prevent booting without password
+.Dl o Prevent modification of boot options without password
+.Dl o Provide a password to mount geli(8) encrypted root disk(s)
+.Pp
The commands of
.Nm
by themselves are not enough for most uses.
@@ -58,14 +62,23 @@ The commands provided by it are:
.Pp
.Bl -tag -width disable-module_module -compact -offset indent
.It Ic check-password
-Dual-purpose function that can either protect the interactive boot menu or
-prevent boot without password (separately).
+Multi-purpose function that can protect the interactive boot menu,
+prevent boot without password, or prompt for geli(8) passphrase
+.Pq depending on Xr loader.conf 5 settings .
.Pp
First checks
.Va bootlock_password
and if-set, the user cannot continue until the correct password is entered.
.Pp
-Next checks
+Next, checks
+.Va geom_eli_passphrase_prompt
+and if set to
+.Li YES
+.Pq case-insensitive
+prompts the user to enter their GELI password for later mounting of the root
+device(s) during boot.
+.Pp
+Last, checks
.Va password
and if-set, tries to
.Ic autoboot
@@ -81,6 +94,11 @@ The environment variables that effect its behavior are:
Sets the bootlock password (up to 16 characters long) that is required by
.Ic check-password
to be entered before the system is allowed to boot.
+.It Va geom_eli_passphrase_prompt
+Selects whether loader(8) will prompt for GELI credentials, handing-off to the
+kernel for later mounting of
+.Xr geli 8
+encrypted root device(s).
.It Va password
Sets the password (up to 16 characters long) that is required by
.Ic check-password
@@ -122,6 +140,16 @@ to prevent booting without password:
.Bd -literal -offset indent -compact
bootlock_password="boot"
.Ed
+.Pp
+Add the following to
+.Xr loader.conf 5
+to generate a prompt at boot to collect GELI credentials for mounting
+.Xr geli 8
+encrypted root device(s):
+.Pp
+.Bd -literal -offset indent -compact
+geom_eli_passphrase_prompt="YES"
+.Ed
.Sh SEE ALSO
.Xr loader.conf 5 ,
.Xr loader 8 ,
diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf
index 573a06a..240e403 100644
--- a/sys/boot/forth/loader.conf
+++ b/sys/boot/forth/loader.conf
@@ -48,6 +48,16 @@ entropy_cache_type="/boot/entropy"
#kern.random.sys.seeded="0" # Set this to 1 to start /dev/random
# without waiting for a (re)seed.
+##############################################################
+### RAM Blacklist configuration #############################
+##############################################################
+
+ram_blacklist_load="NO" # Set this to YES to load a file
+ # containing a list of addresses to
+ # exclude from the running system.
+ram_blacklist_name="/boot/blacklist.txt" # Set this to the name of the file
+ram_blacklist_type="ram_blacklist" # Required for the kernel to find
+ # the blacklist module
##############################################################
### Loader settings ########################################
@@ -62,6 +72,7 @@ entropy_cache_type="/boot/entropy"
# "NO" to disable autobooting
#password="" # Prevent changes to boot options
#bootlock_password="" # Prevent booting (see check-password.4th(8))
+#geom_eli_passphrase_prompt="NO" # Prompt for geli(8) passphrase to mount root
#beastie_disable="NO" # Turn the beastie boot menu on and off
#kernels="kernel kernel.old" # Kernels to display in the boot menu
#loader_logo="orbbw" # Desired logo: orbbw, orb, fbsdbw, beastiebw, beastie, none
diff --git a/sys/boot/forth/menu.4th b/sys/boot/forth/menu.4th
index 4d8aaee..9127565 100644
--- a/sys/boot/forth/menu.4th
+++ b/sys/boot/forth/menu.4th
@@ -206,6 +206,8 @@ also menu-infrastructure definitions
\
: printmenuitem ( menu_item_str -- ascii_keycode )
+ loader_color? if [char] ^ escc! then
+
menurow dup @ 1+ swap ! ( increment menurow )
menuidx dup @ 1+ swap ! ( increment menuidx )
diff --git a/sys/boot/forth/menu.rc b/sys/boot/forth/menu.rc
index 70f0b68..e650848 100644
--- a/sys/boot/forth/menu.rc
+++ b/sys/boot/forth/menu.rc
@@ -17,6 +17,7 @@ menu-init \ initialize the menu area (see `menu.4th')
\ Initialize main menu constructs (see `menu.4th')
\ NOTE: To use `non-ansi' variants, add `loader_color=0' to loader.conf(5)
+\ NOTE: ANSI variants can use `^' in place of literal `Esc' (ASCII 27)
\
\ MAIN MENU
@@ -28,22 +29,22 @@ set mainmenu_init[1]="init_boot"
set mainmenu_caption[1]="Boot Multi User [Enter]"
set maintoggled_text[1]="Boot [S]ingle User [Enter]"
set mainmenu_command[1]="boot"
-set mainansi_caption[1]="Boot Multi User [Enter]"
-set maintoggled_ansi[1]="Boot Single User [Enter]"
+set mainansi_caption[1]="^[1mB^[moot Multi User ^[1m[Enter]^[m"
+set maintoggled_ansi[1]="Boot ^[1mS^[mingle User ^[1m[Enter]^[m"
\ keycode set by init_boot
set mainmenu_init[2]="init_altboot"
set mainmenu_caption[2]="Boot [S]ingle User"
set maintoggled_text[2]="Boot [M]ulti User"
set mainmenu_command[2]="altboot"
-set mainansi_caption[2]="Boot Single User"
-set maintoggled_ansi[2]="Boot Multi User"
+set mainansi_caption[2]="Boot ^[1mS^[mingle User"
+set maintoggled_ansi[2]="Boot ^[1mM^[multi User"
\ keycode set by init_altboot
set mainmenu_caption[3]="[Esc]ape to loader prompt"
set mainmenu_command[3]="goto_prompt"
set mainmenu_keycode[3]=27
-set mainansi_caption[3]="Escape to loader prompt"
+set mainansi_caption[3]="^[1mEsc^[mape to loader prompt"
\ Enable built-in "Reboot" trailing menuitem
\ NOTE: appears before menu_options if configured
@@ -62,7 +63,7 @@ set mainmenu_keycode[5]=107
set mainmenu_caption[6]="Configure Boot [O]ptions..."
set mainmenu_command[6]="2 goto_menu"
set mainmenu_keycode[6]=111
-set mainansi_caption[6]="Configure Boot Options..."
+set mainansi_caption[6]="Configure Boot ^[1mO^[mptions..."
\
\ BOOT OPTIONS MENU
@@ -73,12 +74,12 @@ set menuset_name2="options"
set optionsmenu_caption[1]="Back to Main Menu [Backspace]"
set optionsmenu_command[1]="1 goto_menu"
set optionsmenu_keycode[1]=8
-set optionsansi_caption[1]="Back to Main Menu [Backspace]"
+set optionsansi_caption[1]="Back to Main Menu ^[1m[Backspace]^[m"
set optionsmenu_caption[2]="Load System [D]efaults"
set optionsmenu_command[2]="set_default_boot_options"
set optionsmenu_keycode[2]=100
-set optionsansi_caption[2]="Load System Defaults"
+set optionsansi_caption[2]="Load System ^[1mD^[mefaults"
set optionsmenu_options=3
set optionsmenu_optionstext="Boot Options:"
@@ -88,32 +89,32 @@ set optionsmenu_caption[3]="[A]CPI Support off"
set optionstoggled_text[3]="[A]CPI Support On"
set optionsmenu_command[3]="toggle_acpi"
set optionsmenu_keycode[3]=97
-set optionsansi_caption[3]="ACPI Support Off"
-set optionstoggled_ansi[3]="ACPI Support On"
+set optionsansi_caption[3]="^[1mA^[mCPI Support ^[34;1mOff^[m"
+set optionstoggled_ansi[3]="^[1mA^[mCPI Support ^[32;7mOn^[m"
set optionsmenu_init[4]="init_safemode"
set optionsmenu_caption[4]="Safe [M]ode... off"
set optionstoggled_text[4]="Safe [M]ode... On"
set optionsmenu_command[4]="toggle_safemode"
set optionsmenu_keycode[4]=109
-set optionsansi_caption[4]="Safe Mode... Off"
-set optionstoggled_ansi[4]="Safe Mode... On"
+set optionsansi_caption[4]="Safe ^[1mM^[mode... ^[34;1mOff^[m"
+set optionstoggled_ansi[4]="Safe ^[1mM^[mode... ^[32;7mOn^[m"
set optionsmenu_init[5]="init_singleuser"
set optionsmenu_caption[5]="[S]ingle User. off"
set optionstoggled_text[5]="[S]ingle User. On"
set optionsmenu_command[5]="toggle_singleuser"
set optionsmenu_keycode[5]=115
-set optionsansi_caption[5]="Single User. Off"
-set optionstoggled_ansi[5]="Single User. On"
+set optionsansi_caption[5]="^[1mS^[mingle User. ^[34;1mOff^[m"
+set optionstoggled_ansi[5]="^[1mS^[mingle User. ^[32;7mOn^[m"
set optionsmenu_init[6]="init_verbose"
set optionsmenu_caption[6]="[V]erbose..... off"
set optionstoggled_text[6]="[V]erbose..... On"
set optionsmenu_command[6]="toggle_verbose"
set optionsmenu_keycode[6]=118
-set optionsansi_caption[6]="Verbose..... Off"
-set optionstoggled_ansi[6]="Verbose..... On"
+set optionsansi_caption[6]="^[1mV^[merbose..... ^[34;1mOff^[m"
+set optionstoggled_ansi[6]="^[1mV^[merbose..... ^[32;7mOn^[m"
\ Enable automatic booting (add ``autoboot_delay=N'' to loader.conf(5) to
\ customize the timeout; default is 10-seconds)
diff --git a/sys/boot/forth/version.4th b/sys/boot/forth/version.4th
index 2b672b6..a5311b4 100644
--- a/sys/boot/forth/version.4th
+++ b/sys/boot/forth/version.4th
@@ -85,10 +85,12 @@ only forth definitions also version-processing
dup versionX @ swap - versionY @ at-xy
\ Print the version (optionally in cyan)
- loader_color? dup ( -- bool bool )
+ loader_color? dup ( c-addr/u -- c-addr/u bool bool )
if 6 fg then
- type
+ -rot type
if me then
+
+ 0 25 at-xy
;
only forth definitions
diff --git a/sys/boot/i386/common/edd.h b/sys/boot/i386/common/edd.h
index 4a204f7..7d1f450 100644
--- a/sys/boot/i386/common/edd.h
+++ b/sys/boot/i386/common/edd.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2011 Advanced Computing Technologies LLC
+ * Copyright (c) 2011 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h
index 2322c2b..ce650dd 100644
--- a/sys/boot/i386/libi386/libi386.h
+++ b/sys/boot/i386/libi386/libi386.h
@@ -113,10 +113,6 @@ uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function);
void biosacpi_detect(void);
-void smbios_detect(void);
-int smbios_match(const char* bios_vendor, const char* maker,
- const char* product);
-
int i386_autoload(void);
int bi_getboothowto(char *kargs);
diff --git a/sys/boot/i386/libi386/smbios.c b/sys/boot/i386/libi386/smbios.c
index 570111c..6e4fb84 100644
--- a/sys/boot/i386/libi386/smbios.c
+++ b/sys/boot/i386/libi386/smbios.c
@@ -31,8 +31,13 @@ __FBSDID("$FreeBSD$");
#include <bootstrap.h>
#include <sys/endian.h>
+#ifdef EFI
+/* In EFI, we don't need PTOV(). */
+#define PTOV(x) (caddr_t)(x)
+#else
#include "btxv86.h"
-#include "libi386.h"
+#endif
+#include "smbios.h"
/*
* Detect SMBIOS and export information about the SMBIOS into the
@@ -347,17 +352,18 @@ smbios_find_struct(int type)
}
static void
-smbios_probe(void)
+smbios_probe(const caddr_t addr)
{
caddr_t saddr, info;
- u_int32_t paddr;
+ uintptr_t paddr;
if (smbios.probed)
return;
smbios.probed = 1;
/* Search signatures and validate checksums. */
- saddr = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH);
+ saddr = smbios_sigsearch(addr ? addr : PTOV(SMBIOS_START),
+ SMBIOS_LENGTH);
if (saddr == NULL)
return;
@@ -392,13 +398,13 @@ smbios_probe(void)
}
void
-smbios_detect(void)
+smbios_detect(const caddr_t addr)
{
char buf[16];
caddr_t dmi;
int i;
- smbios_probe();
+ smbios_probe(addr);
if (smbios.addr == NULL)
return;
@@ -433,7 +439,8 @@ int
smbios_match(const char* bios_vendor, const char* maker,
const char* product)
{
- smbios_probe();
+ /* XXXRP currently, only called from non-EFI. */
+ smbios_probe(NULL);
return (smbios_match_str(bios_vendor, smbios.bios_vendor) &&
smbios_match_str(maker, smbios.maker) &&
smbios_match_str(product, smbios.product));
diff --git a/sys/boot/i386/libi386/smbios.h b/sys/boot/i386/libi386/smbios.h
new file mode 100644
index 0000000..03fc07e
--- /dev/null
+++ b/sys/boot/i386/libi386/smbios.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2015 Rui Paulo <rpaulo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SMBIOS_H_
+#define _SMBIOS_H_
+
+void smbios_detect(const caddr_t);
+int smbios_match(const char *, const char *, const char *);
+
+#endif /* _SMBIOS_H_ */
diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c
index 3479169..82465a3 100644
--- a/sys/boot/i386/loader/main.c
+++ b/sys/boot/i386/loader/main.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include "bootstrap.h"
#include "common/bootargs.h"
#include "libi386/libi386.h"
+#include "libi386/smbios.h"
#include "btxv86.h"
#ifdef LOADER_ZFS_SUPPORT
@@ -115,7 +116,7 @@ main(void)
}
setheap(heap_bottom, heap_top);
- /*
+ /*
* XXX Chicken-and-egg problem; we want to have console output early, but some
* console attributes may depend on reading from eg. the boot device, which we
* can't do yet.
@@ -181,7 +182,7 @@ main(void)
biosacpi_detect();
/* detect SMBIOS for future reference */
- smbios_detect();
+ smbios_detect(NULL);
/* detect PCI BIOS for future reference */
biospci_detect();
diff --git a/sys/boot/libstand32/Makefile b/sys/boot/libstand32/Makefile
index a08a8e9..c41dc21 100644
--- a/sys/boot/libstand32/Makefile
+++ b/sys/boot/libstand32/Makefile
@@ -11,9 +11,10 @@ MAN=
.include <src.opts.mk>
MK_SSP= no
-S= ${.CURDIR}/../../../lib/libstand
+LIBSTAND_SRC= ${.CURDIR}/../../../lib/libstand
+LIBC_SRC= ${LIBSTAND_SRC}/../libc
-.PATH: ${S}
+.PATH: ${LIBSTAND_SRC}
LIB= stand
INTERNALLIB=
MK_PROFILE= no
@@ -22,7 +23,7 @@ NO_PIC=
WARNS?= 0
CFLAGS+= -ffreestanding -Wformat
-CFLAGS+= -I${S}
+CFLAGS+= -I${LIBSTAND_SRC}
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
CFLAGS.gcc+= -mpreferred-stack-boundary=2
@@ -52,56 +53,54 @@ SRCS+= gzguts.h zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c g
# private (pruned) versions of libc string functions
SRCS+= strcasecmp.c
-LIBC= ${S}/../libc
-
-.PATH: ${LIBC}/net
+.PATH: ${LIBC_SRC}/net
SRCS+= ntoh.c
# string functions from libc
-.PATH: ${LIBC}/string
+.PATH: ${LIBC_SRC}/string
SRCS+= bcmp.c bcopy.c bzero.c ffs.c memccpy.c memchr.c memcmp.c memcpy.c \
memmove.c memset.c qdivrem.c strcat.c strchr.c strcmp.c strcpy.c \
strcspn.c strlen.c strncat.c strncmp.c strncpy.c strpbrk.c \
strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c
.if ${MACHINE_CPUARCH} == "arm"
-.PATH: ${LIBC}/arm/gen
+.PATH: ${LIBC_SRC}/arm/gen
# Compiler support functions
-.PATH: ${.CURDIR}/../../../contrib/compiler-rt/lib/builtins/
+.PATH: ${LIBSTAND_SRC}/../../contrib/compiler-rt/lib/builtins/
# __clzsi2 and ctzsi2 for various builtin functions
SRCS+= clzsi2.c ctzsi2.c
# Divide and modulus functions called by the compiler
SRCS+= divmoddi4.c divmodsi4.c divdi3.c divsi3.c moddi3.c modsi3.c
SRCS+= udivmoddi4.c udivmodsi4.c udivdi3.c udivsi3.c umoddi3.c umodsi3.c
-.PATH: ${.CURDIR}/../../../contrib/compiler-rt/lib/builtins/arm/
+.PATH: ${LIBSTAND_SRC}/../../contrib/compiler-rt/lib/builtins/arm/
SRCS+= aeabi_idivmod.S aeabi_ldivmod.S aeabi_uidivmod.S aeabi_uldivmod.S
SRCS+= aeabi_memcmp.S aeabi_memcpy.S aeabi_memmove.S aeabi_memset.S
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
-.PATH: ${LIBC}/quad
+.PATH: ${LIBC_SRC}/quad
SRCS+= ashldi3.c ashrdi3.c
SRCS+= syncicache.c
.endif
# uuid functions from libc
-.PATH: ${LIBC}/uuid
+.PATH: ${LIBC_SRC}/uuid
SRCS+= uuid_equal.c uuid_is_nil.c
# _setjmp/_longjmp
.if ${MACHINE_CPUARCH} == "amd64"
-.PATH: ${S}/i386
+.PATH: ${LIBSTAND_SRC}/i386
.else
-.PATH: ${S}/${MACHINE_CPUARCH}
+.PATH: ${LIBSTAND_SRC}/${MACHINE_CPUARCH}
.endif
SRCS+= _setjmp.S
# decompression functionality from libbz2
# NOTE: to actually test this functionality after libbz2 upgrade compile
# loader(8) with LOADER_BZIP2_SUPPORT defined
-.PATH: ${.CURDIR}/../../../contrib/bzip2
+.PATH: ${LIBSTAND_SRC}/../../contrib/bzip2
CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS
SRCS+= libstand_bzlib_private.h
@@ -110,7 +109,8 @@ SRCS+= _${file}
CLEANFILES+= _${file}
_${file}: ${file}
- sed "s|bzlib_private\.h|libstand_bzlib_private.h|" ${.ALLSRC} > ${.TARGET}
+ sed "s|bzlib_private\.h|libstand_bzlib_private.h|" \
+ ${.ALLSRC} > ${.TARGET}
.endfor
CLEANFILES+= libstand_bzlib_private.h
@@ -119,8 +119,8 @@ libstand_bzlib_private.h: bzlib_private.h
${.ALLSRC} > ${.TARGET}
# decompression functionality from libz
-.PATH: ${S}/../libz
-CFLAGS+=-DHAVE_MEMCPY -I${S}/../libz
+.PATH: ${LIBSTAND_SRC}/../libz
+CFLAGS+=-DHAVE_MEMCPY -I${LIBSTAND_SRC}/../libz
SRCS+= adler32.c crc32.c libstand_zutil.h libstand_gzguts.h
.for file in infback.c inffast.c inflate.c inftrees.c zutil.c
diff --git a/sys/boot/sparc64/loader/main.c b/sys/boot/sparc64/loader/main.c
index 44c4d21..ae1e559 100644
--- a/sys/boot/sparc64/loader/main.c
+++ b/sys/boot/sparc64/loader/main.c
@@ -101,7 +101,7 @@ static inline u_long itlb_get_data_sun4u(u_int, u_int);
static int itlb_enter_sun4u(u_int, u_long data, vm_offset_t);
static vm_offset_t itlb_va_to_pa_sun4u(vm_offset_t);
static void itlb_relocate_locked0_sun4u(void);
-extern vm_offset_t md_load(char *, vm_offset_t *);
+extern vm_offset_t md_load(char *, vm_offset_t *, vm_offset_t *);
static int sparc64_autoload(void);
static ssize_t sparc64_readin(const int, vm_offset_t, const size_t);
static ssize_t sparc64_copyin(const void *, vm_offset_t, size_t);
@@ -340,7 +340,7 @@ static int
__elfN(exec)(struct preloaded_file *fp)
{
struct file_metadata *fmp;
- vm_offset_t mdp;
+ vm_offset_t mdp, dtbp;
Elf_Addr entry;
Elf_Ehdr *e;
int error;
@@ -349,7 +349,7 @@ __elfN(exec)(struct preloaded_file *fp)
return (EFTYPE);
e = (Elf_Ehdr *)&fmp->md_data;
- if ((error = md_load(fp->f_args, &mdp)) != 0)
+ if ((error = md_load(fp->f_args, &mdp, &dtbp)) != 0)
return (error);
printf("jumping to kernel entry at %#lx.\n", e->e_entry);
diff --git a/sys/boot/userboot/libstand/Makefile b/sys/boot/userboot/libstand/Makefile
index 35903fc..88eb98f 100644
--- a/sys/boot/userboot/libstand/Makefile
+++ b/sys/boot/userboot/libstand/Makefile
@@ -11,9 +11,10 @@ MAN=
.include <bsd.own.mk>
MK_SSP= no
-S= ${.CURDIR}/../../../../lib/libstand
+LIBSTAND_SRC= ${.CURDIR}/../../../../lib/libstand
+LIBC_SRC= ${LIBSTAND_SRC}/../libc
-.PATH: ${S}
+.PATH: ${LIBSTAND_SRC}
LIB= stand
INTERNALLIB=
MK_PROFILE= no
@@ -22,7 +23,7 @@ NO_PIC=
WARNS?= 0
CFLAGS+= -ffreestanding -Wformat -fPIC
-CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
+CFLAGS+= -I${LIBSTAND_SRC}
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2
@@ -49,14 +50,12 @@ SRCS+= gzguts.h zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c g
# private (pruned) versions of libc string functions
SRCS+= strcasecmp.c
-LIBC= ${.CURDIR}/../../../../lib/libc
-
-.PATH: ${LIBC}/net
+.PATH: ${LIBC_SRC}/net
SRCS+= ntoh.c
# string functions from libc
-.PATH: ${LIBC}/string
+.PATH: ${LIBC_SRC}/string
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "powerpc" || \
${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "amd64" || \
${MACHINE_CPUARCH} == "arm"
@@ -66,34 +65,34 @@ SRCS+= bcmp.c bcopy.c bzero.c ffs.c memccpy.c memchr.c memcmp.c memcpy.c \
strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c
.endif
.if ${MACHINE_CPUARCH} == "arm"
-.PATH: ${LIBC}/arm/gen
+.PATH: ${LIBC_SRC}/arm/gen
SRCS+= divsi3.S
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
-.PATH: ${LIBC}/libc/quad
+.PATH: ${LIBC_SRC}/quad
SRCS+= ashldi3.c ashrdi3.c
-.PATH: ${LIBC}/powerpc/gen
+.PATH: ${LIBC_SRC}/powerpc/gen
SRCS+= syncicache.c
.endif
# uuid functions from libc
-.PATH: ${LIBC}/uuid
+.PATH: ${LIBC_SRC}/uuid
SRCS+= uuid_equal.c uuid_is_nil.c
# _setjmp/_longjmp
.if ${MACHINE_CPUARCH} == "amd64"
-.PATH: ${S}/amd64
+.PATH: ${LIBSTAND_SRC}/amd64
.elif ${MACHINE_ARCH} == "powerpc64"
-.PATH: ${S}/powerpc
+.PATH: ${LIBSTAND_SRC}/powerpc
.else
-.PATH: ${S}/${MACHINE_CPUARCH}
+.PATH: ${LIBSTAND_SRC}/${MACHINE_CPUARCH}
.endif
SRCS+= _setjmp.S
# decompression functionality from libbz2
# NOTE: to actually test this functionality after libbz2 upgrade compile
# loader(8) with LOADER_BZIP2_SUPPORT defined
-.PATH: ${.CURDIR}/../../../../contrib/bzip2
+.PATH: ${LIBSTAND_SRC}/../../contrib/bzip2
CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS
SRCS+= libstand_bzlib_private.h
@@ -102,7 +101,8 @@ SRCS+= _${file}
CLEANFILES+= _${file}
_${file}: ${file}
- sed "s|bzlib_private\.h|libstand_bzlib_private.h|" ${.ALLSRC} > ${.TARGET}
+ sed "s|bzlib_private\.h|libstand_bzlib_private.h|" \
+ ${.ALLSRC} > ${.TARGET}
.endfor
CLEANFILES+= libstand_bzlib_private.h
@@ -111,8 +111,8 @@ libstand_bzlib_private.h: bzlib_private.h
${.ALLSRC} > ${.TARGET}
# decompression functionality from libz
-.PATH: ${.CURDIR}/../../../../lib/libz
-CFLAGS+=-DHAVE_MEMCPY -I${.CURDIR}/../../../../lib/libz
+.PATH: ${LIBSTAND_SRC}/../libz
+CFLAGS+=-DHAVE_MEMCPY -I${LIBSTAND_SRC}/../libz
SRCS+= adler32.c crc32.c libstand_zutil.h libstand_gzguts.h
.for file in infback.c inffast.c inflate.c inftrees.c zutil.c
@@ -121,7 +121,8 @@ CLEANFILES+= _${file}
_${file}: ${file}
sed -e "s|zutil\.h|libstand_zutil.h|" \
- -e "s|gzguts\.h|libstand_gzguts.h|" ${.ALLSRC} > ${.TARGET}
+ -e "s|gzguts\.h|libstand_gzguts.h|" \
+ ${.ALLSRC} > ${.TARGET}
.endfor
# depend on stand.h being able to be included multiple times
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 06e01fc..ad55373 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -4264,8 +4264,10 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg)
}
memcpy(ccb->casync.async_arg_ptr, async_arg, size);
ccb->casync.async_arg_size = size;
- } else if (size < 0)
+ } else if (size < 0) {
+ ccb->casync.async_arg_ptr = async_arg;
ccb->casync.async_arg_size = size;
+ }
if (path->device != NULL && path->device->lun_id != CAM_LUN_WILDCARD)
xpt_freeze_devq(path, 1);
else
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index 3266d5b3f..a429259 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -6039,7 +6039,7 @@ scsi_parse_transportid_rdma(char *id_str, struct scsi_transportid_header **hdr,
goto bailout;
}
*alloc_len = sizeof(*rdma);
- bzero(rdma, sizeof(rdma));
+ bzero(rdma, *alloc_len);
rdma->format_protocol = SCSI_PROTO_RDMA | SCSI_TRN_RDMA_FORMAT_DEFAULT;
bcopy(rdma_id, rdma->initiator_port_id, SCSI_TRN_RDMA_PORT_LEN);
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 911aece..74dd3b9 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -1186,7 +1186,7 @@ static struct da_quirk_entry da_quirk_table[] =
/*
* MX-ES USB Drive by Mach Xtreme
*/
- { T_DIRECT, SIP_MEDIA_REMOVABLE, "MX", "MXUB3SES*", "*"},
+ { T_DIRECT, SIP_MEDIA_REMOVABLE, "MX", "MXUB3*", "*"},
/*quirks*/DA_Q_NO_RC16
},
};
diff --git a/sys/cddl/contrib/opensolaris/common/nvpair/nvpair.c b/sys/cddl/contrib/opensolaris/common/nvpair/nvpair.c
index 53ed5f2..cd6af4e 100644
--- a/sys/cddl/contrib/opensolaris/common/nvpair/nvpair.c
+++ b/sys/cddl/contrib/opensolaris/common/nvpair/nvpair.c
@@ -1227,6 +1227,7 @@ nvpair_type_is_array(nvpair_t *nvp)
data_type_t type = NVP_TYPE(nvp);
if ((type == DATA_TYPE_BYTE_ARRAY) ||
+ (type == DATA_TYPE_INT8_ARRAY) ||
(type == DATA_TYPE_UINT8_ARRAY) ||
(type == DATA_TYPE_INT16_ARRAY) ||
(type == DATA_TYPE_UINT16_ARRAY) ||
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
index 818f180..b31e8bb 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -611,7 +611,11 @@ dtrace_panic(const char *format, ...)
va_list alist;
va_start(alist, format);
+#ifdef __FreeBSD__
+ vpanic(format, alist);
+#else
dtrace_vpanic(format, alist);
+#endif
va_end(alist);
}
@@ -15374,13 +15378,15 @@ dtrace_helper_action_destroy(dtrace_helper_action_t *helper,
}
static int
-dtrace_helper_destroygen(int gen)
+dtrace_helper_destroygen(dtrace_helpers_t *help, int gen)
{
proc_t *p = curproc;
- dtrace_helpers_t *help = p->p_dtrace_helpers;
dtrace_vstate_t *vstate;
int i;
+ if (help == NULL)
+ help = p->p_dtrace_helpers;
+
ASSERT(MUTEX_HELD(&dtrace_lock));
if (help == NULL || gen > help->dthps_generation)
@@ -15478,9 +15484,9 @@ dtrace_helper_validate(dtrace_helper_action_t *helper)
}
static int
-dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep)
+dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep,
+ dtrace_helpers_t *help)
{
- dtrace_helpers_t *help;
dtrace_helper_action_t *helper, *last;
dtrace_actdesc_t *act;
dtrace_vstate_t *vstate;
@@ -15490,7 +15496,6 @@ dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep)
if (which < 0 || which >= DTRACE_NHELPER_ACTIONS)
return (EINVAL);
- help = curproc->p_dtrace_helpers;
last = help->dthps_actions[which];
vstate = &help->dthps_vstate;
@@ -15614,15 +15619,12 @@ dtrace_helper_provider_register(proc_t *p, dtrace_helpers_t *help,
}
static int
-dtrace_helper_provider_add(dof_helper_t *dofhp, int gen)
+dtrace_helper_provider_add(dof_helper_t *dofhp, dtrace_helpers_t *help, int gen)
{
- dtrace_helpers_t *help;
dtrace_helper_provider_t *hprov, **tmp_provs;
uint_t tmp_maxprovs, i;
ASSERT(MUTEX_HELD(&dtrace_lock));
-
- help = curproc->p_dtrace_helpers;
ASSERT(help != NULL);
/*
@@ -15914,13 +15916,28 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
dtrace_helpers_t *help;
dtrace_vstate_t *vstate;
dtrace_enabling_t *enab = NULL;
+ proc_t *p = curproc;
int i, gen, rv, nhelpers = 0, nprovs = 0, destroy = 1;
uintptr_t daddr = (uintptr_t)dof;
ASSERT(MUTEX_HELD(&dtrace_lock));
- if ((help = curproc->p_dtrace_helpers) == NULL)
- help = dtrace_helpers_create(curproc);
+#ifdef __FreeBSD__
+ if (dhp->dofhp_pid != p->p_pid) {
+ if ((p = pfind(dhp->dofhp_pid)) == NULL)
+ return (-1);
+ if (!P_SHOULDSTOP(p) ||
+ (p->p_flag & P_TRACED) == 0 ||
+ p->p_pptr->p_pid != curproc->p_pid) {
+ PROC_UNLOCK(p);
+ return (-1);
+ }
+ PROC_UNLOCK(p);
+ }
+#endif
+
+ if ((help = p->p_dtrace_helpers) == NULL)
+ help = dtrace_helpers_create(p);
vstate = &help->dthps_vstate;
@@ -15968,12 +15985,13 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
continue;
if ((rv = dtrace_helper_action_add(DTRACE_HELPER_ACTION_USTACK,
- ep)) != 0) {
+ ep, help)) != 0) {
/*
* Adding this helper action failed -- we are now going
* to rip out the entire generation and return failure.
*/
- (void) dtrace_helper_destroygen(help->dthps_generation);
+ (void) dtrace_helper_destroygen(help,
+ help->dthps_generation);
dtrace_enabling_destroy(enab);
dtrace_dof_destroy(dof);
return (-1);
@@ -15990,9 +16008,9 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
if (dhp != NULL && nprovs > 0) {
dhp->dofhp_dof = (uint64_t)(uintptr_t)dof;
- if (dtrace_helper_provider_add(dhp, gen) == 0) {
+ if (dtrace_helper_provider_add(dhp, help, gen) == 0) {
mutex_exit(&dtrace_lock);
- dtrace_helper_provider_register(curproc, help, dhp);
+ dtrace_helper_provider_register(p, help, dhp);
mutex_enter(&dtrace_lock);
destroy = 0;
@@ -16956,7 +16974,7 @@ dtrace_ioctl_helper(int cmd, intptr_t arg, int *rv)
case DTRACEHIOC_REMOVE: {
mutex_enter(&dtrace_lock);
- rval = dtrace_helper_destroygen(arg);
+ rval = dtrace_helper_destroygen(NULL, arg);
mutex_exit(&dtrace_lock);
return (rval);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
index 4176dce..30ca7b9 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
@@ -2671,8 +2671,12 @@ arc_reclaim_needed(void)
* Above limits know nothing about real level of KVA fragmentation.
* Start aggressive reclamation if too little sequential KVA left.
*/
- if (vmem_size(heap_arena, VMEM_MAXFREE) < zfs_max_recordsize)
+ if (vmem_size(heap_arena, VMEM_MAXFREE) < zfs_max_recordsize) {
+ DTRACE_PROBE2(arc__reclaim_maxfree, uint64_t,
+ vmem_size(heap_arena, VMEM_MAXFREE),
+ uint64_t, zfs_max_recordsize);
return (1);
+ }
#else /* _KERNEL */
if (spa_get_random(100) == 0)
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
index 36ac27a..fb9c8a1 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
@@ -23,6 +23,7 @@
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/* Portions Copyright 2010 Robert Milkowski */
@@ -879,11 +880,7 @@ dmu_objset_clone_check(void *arg, dmu_tx_t *tx)
dsl_dir_rele(pdd, FTAG);
return (SET_ERROR(EEXIST));
}
- /* You can't clone across pools. */
- if (pdd->dd_pool != dp) {
- dsl_dir_rele(pdd, FTAG);
- return (SET_ERROR(EXDEV));
- }
+
error = dsl_fs_ss_limit_check(pdd, 1, ZFS_PROP_FILESYSTEM_LIMIT, NULL,
doca->doca_cred);
if (error != 0) {
@@ -896,12 +893,6 @@ dmu_objset_clone_check(void *arg, dmu_tx_t *tx)
if (error != 0)
return (error);
- /* You can't clone across pools. */
- if (origin->ds_dir->dd_pool != dp) {
- dsl_dataset_rele(origin, FTAG);
- return (SET_ERROR(EXDEV));
- }
-
/* You can only clone snapshots, not the head datasets. */
if (!dsl_dataset_is_snapshot(origin)) {
dsl_dataset_rele(origin, FTAG);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c
index 7b1d6be..faa6d0c 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c
@@ -306,21 +306,22 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
arc_flags_t flags = ARC_FLAG_WAIT;
int i;
int epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT;
+ dnode_phys_t *cdnp;
err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
if (err != 0)
goto post;
- dnp = buf->b_data;
+ cdnp = buf->b_data;
for (i = 0; i < epb; i++) {
- prefetch_dnode_metadata(td, &dnp[i], zb->zb_objset,
+ prefetch_dnode_metadata(td, &cdnp[i], zb->zb_objset,
zb->zb_blkid * epb + i);
}
/* recursively visitbp() blocks below this */
for (i = 0; i < epb; i++) {
- err = traverse_dnode(td, &dnp[i], zb->zb_objset,
+ err = traverse_dnode(td, &cdnp[i], zb->zb_objset,
zb->zb_blkid * epb + i);
if (err != 0)
break;
@@ -328,7 +329,7 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
} else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) {
arc_flags_t flags = ARC_FLAG_WAIT;
objset_phys_t *osp;
- dnode_phys_t *dnp;
+ dnode_phys_t *mdnp, *gdnp, *udnp;
err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
@@ -336,26 +337,27 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
goto post;
osp = buf->b_data;
- dnp = &osp->os_meta_dnode;
- prefetch_dnode_metadata(td, dnp, zb->zb_objset,
+ mdnp = &osp->os_meta_dnode;
+ gdnp = &osp->os_groupused_dnode;
+ udnp = &osp->os_userused_dnode;
+
+ prefetch_dnode_metadata(td, mdnp, zb->zb_objset,
DMU_META_DNODE_OBJECT);
if (arc_buf_size(buf) >= sizeof (objset_phys_t)) {
- prefetch_dnode_metadata(td, &osp->os_groupused_dnode,
- zb->zb_objset, DMU_GROUPUSED_OBJECT);
- prefetch_dnode_metadata(td, &osp->os_userused_dnode,
- zb->zb_objset, DMU_USERUSED_OBJECT);
+ prefetch_dnode_metadata(td, gdnp, zb->zb_objset,
+ DMU_GROUPUSED_OBJECT);
+ prefetch_dnode_metadata(td, udnp, zb->zb_objset,
+ DMU_USERUSED_OBJECT);
}
- err = traverse_dnode(td, dnp, zb->zb_objset,
+ err = traverse_dnode(td, mdnp, zb->zb_objset,
DMU_META_DNODE_OBJECT);
if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
- dnp = &osp->os_groupused_dnode;
- err = traverse_dnode(td, dnp, zb->zb_objset,
+ err = traverse_dnode(td, gdnp, zb->zb_objset,
DMU_GROUPUSED_OBJECT);
}
if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
- dnp = &osp->os_userused_dnode;
- err = traverse_dnode(td, dnp, zb->zb_objset,
+ err = traverse_dnode(td, udnp, zb->zb_objset,
DMU_USERUSED_OBJECT);
}
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
index ce22f4e..58db4dd 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
@@ -413,7 +413,8 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
offsetof(dmu_sendarg_t, dsa_link));
if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
- int zaperr = zap_contains(mos, dsobj, DS_FIELD_LARGE_BLOCKS);
+ int zaperr = zap_contains(mos, dsobj,
+ DS_FIELD_LARGE_BLOCKS);
if (zaperr != ENOENT) {
VERIFY0(zaperr);
ds->ds_large_blocks = B_TRUE;
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
index 1862f8c..26f5c2d 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
@@ -24,6 +24,7 @@
* All rights reserved.
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/dmu.h>
@@ -408,7 +409,7 @@ dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
/* Make sure the name is in the specified pool. */
spaname = spa_name(dp->dp_spa);
if (strcmp(buf, spaname) != 0)
- return (SET_ERROR(EINVAL));
+ return (SET_ERROR(EXDEV));
ASSERT(dsl_pool_config_held(dp));
@@ -1706,7 +1707,7 @@ dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
if (dd->dd_pool != newparent->dd_pool) {
dsl_dir_rele(newparent, FTAG);
dsl_dir_rele(dd, FTAG);
- return (SET_ERROR(ENXIO));
+ return (SET_ERROR(EXDEV));
}
/* new name should not already exist */
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
index a829b06..55e3c45 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
@@ -195,11 +195,6 @@
CTASSERT(sizeof(zfs_cmd_t) < IOCPARM_MAX);
-static int snapshot_list_prefetch;
-SYSCTL_DECL(_vfs_zfs);
-SYSCTL_INT(_vfs_zfs, OID_AUTO, snapshot_list_prefetch, CTLFLAG_RWTUN,
- &snapshot_list_prefetch, 0, "Prefetch data when listing snapshots");
-
static struct cdev *zfsdev;
extern void zfs_init(void);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c
index 6a90b9c..fe02399 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c
@@ -137,7 +137,7 @@ zfs_onexit_fd_hold(int fd, minor_t *minorp)
*minorp = (minor_t)(uintptr_t)data;
curthread->td_fpop = tmpfp;
if (error != 0)
- return (error);
+ return (SET_ERROR(EBADF));
return (zfs_onexit_minor_to_state(*minorp, &zo));
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
index d925712..e3b314f 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
@@ -1320,15 +1320,25 @@ zfs_rezget(znode_t *zp)
}
/*
- * XXXPJD: Not sure how is that possible, but under heavy
- * zfs recv -F load it happens that z_gen is the same, but
- * vnode type is different than znode type. This would mean
- * that for example regular file was replaced with directory
- * which has the same object number.
+ * It is highly improbable but still quite possible that two
+ * objects in different datasets are created with the same
+ * object numbers and in transaction groups with the same
+ * numbers. znodes corresponding to those objects would
+ * have the same z_id and z_gen, but their other attributes
+ * may be different.
+ * zfs recv -F may replace one of such objects with the other.
+ * As a result file properties recorded in the replaced
+ * object's vnode may no longer match the received object's
+ * properties. At present the only cached property is the
+ * files type recorded in v_type.
+ * So, handle this case by leaving the old vnode and znode
+ * disassociated from the actual object. A new vnode and a
+ * znode will be created if the object is accessed
+ * (e.g. via a look-up). The old vnode and znode will be
+ * recycled when the last vnode reference is dropped.
*/
vp = ZTOV(zp);
- if (vp != NULL &&
- vp->v_type != IFTOVT((mode_t)zp->z_mode)) {
+ if (vp != NULL && vp->v_type != IFTOVT((mode_t)zp->z_mode)) {
zfs_znode_dmu_fini(zp);
ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
return (EIO);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
index 4605ee5..dfcdbbf 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
@@ -1423,8 +1423,9 @@ typedef struct dof_helper {
char dofhp_mod[DTRACE_MODNAMELEN]; /* executable or library name */
uint64_t dofhp_addr; /* base address of object */
uint64_t dofhp_dof; /* address of helper DOF */
-#ifndef illumos
- int gen;
+#ifdef __FreeBSD__
+ pid_t dofhp_pid; /* target process ID */
+ int dofhp_gen;
#endif
} dof_helper_t;
diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_asm.S b/sys/cddl/dev/dtrace/amd64/dtrace_asm.S
index cf8314c..a6c079e 100644
--- a/sys/cddl/dev/dtrace/amd64/dtrace_asm.S
+++ b/sys/cddl/dev/dtrace/amd64/dtrace_asm.S
@@ -363,211 +363,3 @@ dtrace_interrupt_enable(dtrace_icookie_t cookie)
popfq
ret
END(dtrace_interrupt_enable)
-
-/*
- * The panic() and cmn_err() functions invoke vpanic() as a common entry point
- * into the panic code implemented in panicsys(). vpanic() is responsible
- * for passing through the format string and arguments, and constructing a
- * regs structure on the stack into which it saves the current register
- * values. If we are not dying due to a fatal trap, these registers will
- * then be preserved in panicbuf as the current processor state. Before
- * invoking panicsys(), vpanic() activates the first panic trigger (see
- * common/os/panic.c) and switches to the panic_stack if successful. Note that
- * DTrace takes a slightly different panic path if it must panic from probe
- * context. Instead of calling panic, it calls into dtrace_vpanic(), which
- * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
- * branches back into vpanic().
- */
-
-/*
-void
-vpanic(const char *format, va_list alist)
-*/
- ENTRY(vpanic) /* Initial stack layout: */
-
- pushq %rbp /* | %rip | 0x60 */
- movq %rsp, %rbp /* | %rbp | 0x58 */
- pushfq /* | rfl | 0x50 */
- pushq %r11 /* | %r11 | 0x48 */
- pushq %r10 /* | %r10 | 0x40 */
- pushq %rbx /* | %rbx | 0x38 */
- pushq %rax /* | %rax | 0x30 */
- pushq %r9 /* | %r9 | 0x28 */
- pushq %r8 /* | %r8 | 0x20 */
- pushq %rcx /* | %rcx | 0x18 */
- pushq %rdx /* | %rdx | 0x10 */
- pushq %rsi /* | %rsi | 0x8 alist */
- pushq %rdi /* | %rdi | 0x0 format */
-
- movq %rsp, %rbx /* %rbx = current %rsp */
-
- leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */
- call panic_trigger /* %eax = panic_trigger() */
-
-vpanic_common:
- /*
- * The panic_trigger result is in %eax from the call above, and
- * dtrace_panic places it in %eax before branching here.
- * The rdmsr instructions that follow below will clobber %eax so
- * we stash the panic_trigger result in %r11d.
- */
- movl %eax, %r11d
- cmpl $0, %r11d
- je 0f
-
- /*
- * If panic_trigger() was successful, we are the first to initiate a
- * panic: we now switch to the reserved panic_stack before continuing.
- */
- leaq panic_stack(%rip), %rsp
- addq $PANICSTKSIZE, %rsp
-0: subq $REGSIZE, %rsp
- /*
- * Now that we've got everything set up, store the register values as
- * they were when we entered vpanic() to the designated location in
- * the regs structure we allocated on the stack.
- */
-#ifdef notyet
- movq 0x0(%rbx), %rcx
- movq %rcx, REGOFF_RDI(%rsp)
- movq 0x8(%rbx), %rcx
- movq %rcx, REGOFF_RSI(%rsp)
- movq 0x10(%rbx), %rcx
- movq %rcx, REGOFF_RDX(%rsp)
- movq 0x18(%rbx), %rcx
- movq %rcx, REGOFF_RCX(%rsp)
- movq 0x20(%rbx), %rcx
-
- movq %rcx, REGOFF_R8(%rsp)
- movq 0x28(%rbx), %rcx
- movq %rcx, REGOFF_R9(%rsp)
- movq 0x30(%rbx), %rcx
- movq %rcx, REGOFF_RAX(%rsp)
- movq 0x38(%rbx), %rcx
- movq %rcx, REGOFF_RBX(%rsp)
- movq 0x58(%rbx), %rcx
-
- movq %rcx, REGOFF_RBP(%rsp)
- movq 0x40(%rbx), %rcx
- movq %rcx, REGOFF_R10(%rsp)
- movq 0x48(%rbx), %rcx
- movq %rcx, REGOFF_R11(%rsp)
- movq %r12, REGOFF_R12(%rsp)
-
- movq %r13, REGOFF_R13(%rsp)
- movq %r14, REGOFF_R14(%rsp)
- movq %r15, REGOFF_R15(%rsp)
-
- xorl %ecx, %ecx
- movw %ds, %cx
- movq %rcx, REGOFF_DS(%rsp)
- movw %es, %cx
- movq %rcx, REGOFF_ES(%rsp)
- movw %fs, %cx
- movq %rcx, REGOFF_FS(%rsp)
- movw %gs, %cx
- movq %rcx, REGOFF_GS(%rsp)
-
- movq $0, REGOFF_TRAPNO(%rsp)
-
- movq $0, REGOFF_ERR(%rsp)
- leaq vpanic(%rip), %rcx
- movq %rcx, REGOFF_RIP(%rsp)
- movw %cs, %cx
- movzwq %cx, %rcx
- movq %rcx, REGOFF_CS(%rsp)
- movq 0x50(%rbx), %rcx
- movq %rcx, REGOFF_RFL(%rsp)
- movq %rbx, %rcx
- addq $0x60, %rcx
- movq %rcx, REGOFF_RSP(%rsp)
- movw %ss, %cx
- movzwq %cx, %rcx
- movq %rcx, REGOFF_SS(%rsp)
-
- /*
- * panicsys(format, alist, rp, on_panic_stack)
- */
- movq REGOFF_RDI(%rsp), %rdi /* format */
- movq REGOFF_RSI(%rsp), %rsi /* alist */
- movq %rsp, %rdx /* struct regs */
- movl %r11d, %ecx /* on_panic_stack */
- call panicsys
- addq $REGSIZE, %rsp
-#endif
- popq %rdi
- popq %rsi
- popq %rdx
- popq %rcx
- popq %r8
- popq %r9
- popq %rax
- popq %rbx
- popq %r10
- popq %r11
- popfq
- leave
- ret
- END(vpanic)
-
-/*
-void
-dtrace_vpanic(const char *format, va_list alist)
-*/
- ENTRY(dtrace_vpanic) /* Initial stack layout: */
-
- pushq %rbp /* | %rip | 0x60 */
- movq %rsp, %rbp /* | %rbp | 0x58 */
- pushfq /* | rfl | 0x50 */
- pushq %r11 /* | %r11 | 0x48 */
- pushq %r10 /* | %r10 | 0x40 */
- pushq %rbx /* | %rbx | 0x38 */
- pushq %rax /* | %rax | 0x30 */
- pushq %r9 /* | %r9 | 0x28 */
- pushq %r8 /* | %r8 | 0x20 */
- pushq %rcx /* | %rcx | 0x18 */
- pushq %rdx /* | %rdx | 0x10 */
- pushq %rsi /* | %rsi | 0x8 alist */
- pushq %rdi /* | %rdi | 0x0 format */
-
- movq %rsp, %rbx /* %rbx = current %rsp */
-
- leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */
- call dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
- jmp vpanic_common
-
- END(dtrace_vpanic)
-
-/*
-int
-panic_trigger(int *tp)
-*/
- ENTRY(panic_trigger)
- xorl %eax, %eax
- movl $0xdefacedd, %edx
- lock
- xchgl %edx, (%rdi)
- cmpl $0, %edx
- je 0f
- movl $0, %eax
- ret
-0: movl $1, %eax
- ret
- END(panic_trigger)
-
-/*
-int
-dtrace_panic_trigger(int *tp)
-*/
- ENTRY(dtrace_panic_trigger)
- xorl %eax, %eax
- movl $0xdefacedd, %edx
- lock
- xchgl %edx, (%rdi)
- cmpl $0, %edx
- je 0f
- movl $0, %eax
- ret
-0: movl $1, %eax
- ret
- END(dtrace_panic_trigger)
diff --git a/sys/cddl/dev/dtrace/arm/dtrace_asm.S b/sys/cddl/dev/dtrace/arm/dtrace_asm.S
index ce27b14..06e91d2 100644
--- a/sys/cddl/dev/dtrace/arm/dtrace_asm.S
+++ b/sys/cddl/dev/dtrace/arm/dtrace_asm.S
@@ -170,24 +170,6 @@ ENTRY(dtrace_copystr)
END(dtrace_copystr)
/*
-void
-vpanic(const char *format, va_list alist)
-*/
-ENTRY(vpanic) /* Initial stack layout: */
-vpanic_common:
- RET
-END(vpanic)
-
-/*
-void
-dtrace_vpanic(const char *format, va_list alist)
-*/
-ENTRY(dtrace_vpanic) /* Initial stack layout: */
- b vpanic
- RET
-END(dtrace_vpanic) /* Initial stack layout: */
-
-/*
uintptr_t
dtrace_caller(int aframes)
*/
diff --git a/sys/cddl/dev/dtrace/dtrace_hacks.c b/sys/cddl/dev/dtrace/dtrace_hacks.c
index 21da9f8..3f89973 100644
--- a/sys/cddl/dev/dtrace/dtrace_hacks.c
+++ b/sys/cddl/dev/dtrace/dtrace_hacks.c
@@ -3,9 +3,6 @@
dtrace_cacheid_t dtrace_predcache_id;
-int panic_quiesce;
-char panic_stack[PANICSTKSIZE];
-
boolean_t
priv_policy_only(const cred_t *a, int b, boolean_t c)
{
diff --git a/sys/cddl/dev/dtrace/dtrace_ioctl.c b/sys/cddl/dev/dtrace/dtrace_ioctl.c
index ef9bed5..524e937 100644
--- a/sys/cddl/dev/dtrace/dtrace_ioctl.c
+++ b/sys/cddl/dev/dtrace/dtrace_ioctl.c
@@ -32,9 +32,9 @@ static int
dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
struct thread *td)
{
- int rval;
dof_helper_t *dhp = NULL;
dof_hdr_t *dof = NULL;
+ int rval;
switch (cmd) {
case DTRACEHIOC_ADDDOF:
@@ -51,7 +51,7 @@ dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
mutex_enter(&dtrace_lock);
if ((rval = dtrace_helper_slurp((dof_hdr_t *)dof, dhp)) != -1) {
if (dhp) {
- dhp->gen = rval;
+ dhp->dofhp_gen = rval;
copyout(dhp, addr, sizeof(*dhp));
}
rval = 0;
@@ -59,10 +59,11 @@ dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
rval = EINVAL;
}
mutex_exit(&dtrace_lock);
+
return (rval);
case DTRACEHIOC_REMOVE:
mutex_enter(&dtrace_lock);
- rval = dtrace_helper_destroygen((int)*addr);
+ rval = dtrace_helper_destroygen(NULL, (int)*addr);
mutex_exit(&dtrace_lock);
return (rval);
diff --git a/sys/cddl/dev/dtrace/i386/dtrace_asm.S b/sys/cddl/dev/dtrace/i386/dtrace_asm.S
index 6338719..d44f6c3 100644
--- a/sys/cddl/dev/dtrace/i386/dtrace_asm.S
+++ b/sys/cddl/dev/dtrace/i386/dtrace_asm.S
@@ -355,167 +355,3 @@ void dtrace_interrupt_enable(dtrace_icookie_t cookie)
popfl
ret
END(dtrace_interrupt_enable)
-
-/*
- * The panic() and cmn_err() functions invoke vpanic() as a common entry point
- * into the panic code implemented in panicsys(). vpanic() is responsible
- * for passing through the format string and arguments, and constructing a
- * regs structure on the stack into which it saves the current register
- * values. If we are not dying due to a fatal trap, these registers will
- * then be preserved in panicbuf as the current processor state. Before
- * invoking panicsys(), vpanic() activates the first panic trigger (see
- * common/os/panic.c) and switches to the panic_stack if successful. Note that
- * DTrace takes a slightly different panic path if it must panic from probe
- * context. Instead of calling panic, it calls into dtrace_vpanic(), which
- * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
- * branches back into vpanic().
- */
-/*
-void vpanic(const char *format, va_list alist)
-*/
- ENTRY(vpanic) /* Initial stack layout: */
-
- pushl %ebp /* | %eip | 20 */
- movl %esp, %ebp /* | %ebp | 16 */
- pushl %eax /* | %eax | 12 */
- pushl %ebx /* | %ebx | 8 */
- pushl %ecx /* | %ecx | 4 */
- pushl %edx /* | %edx | 0 */
-
- movl %esp, %ebx /* %ebx = current stack pointer */
-
- lea panic_quiesce, %eax /* %eax = &panic_quiesce */
- pushl %eax /* push &panic_quiesce */
- call panic_trigger /* %eax = panic_trigger() */
- addl $4, %esp /* reset stack pointer */
-
-vpanic_common:
- cmpl $0, %eax /* if (%eax == 0) */
- je 0f /* goto 0f; */
-
- /*
- * If panic_trigger() was successful, we are the first to initiate a
- * panic: we now switch to the reserved panic_stack before continuing.
- */
- lea panic_stack, %esp /* %esp = panic_stack */
- addl $PANICSTKSIZE, %esp /* %esp += PANICSTKSIZE */
-
-0: subl $REGSIZE, %esp /* allocate struct regs */
-
- /*
- * Now that we've got everything set up, store the register values as
- * they were when we entered vpanic() to the designated location in
- * the regs structure we allocated on the stack.
- */
-#ifdef notyet
- mov %gs, %edx
- mov %edx, REGOFF_GS(%esp)
- mov %fs, %edx
- mov %edx, REGOFF_FS(%esp)
- mov %es, %edx
- mov %edx, REGOFF_ES(%esp)
- mov %ds, %edx
- mov %edx, REGOFF_DS(%esp)
- movl %edi, REGOFF_EDI(%esp)
- movl %esi, REGOFF_ESI(%esp)
- movl 16(%ebx), %ecx
- movl %ecx, REGOFF_EBP(%esp)
- movl %ebx, %ecx
- addl $20, %ecx
- movl %ecx, REGOFF_ESP(%esp)
- movl 8(%ebx), %ecx
- movl %ecx, REGOFF_EBX(%esp)
- movl 0(%ebx), %ecx
- movl %ecx, REGOFF_EDX(%esp)
- movl 4(%ebx), %ecx
- movl %ecx, REGOFF_ECX(%esp)
- movl 12(%ebx), %ecx
- movl %ecx, REGOFF_EAX(%esp)
- movl $0, REGOFF_TRAPNO(%esp)
- movl $0, REGOFF_ERR(%esp)
- lea vpanic, %ecx
- movl %ecx, REGOFF_EIP(%esp)
- mov %cs, %edx
- movl %edx, REGOFF_CS(%esp)
- pushfl
- popl %ecx
- movl %ecx, REGOFF_EFL(%esp)
- movl $0, REGOFF_UESP(%esp)
- mov %ss, %edx
- movl %edx, REGOFF_SS(%esp)
-
- movl %esp, %ecx /* %ecx = &regs */
- pushl %eax /* push on_panic_stack */
- pushl %ecx /* push &regs */
- movl 12(%ebp), %ecx /* %ecx = alist */
- pushl %ecx /* push alist */
- movl 8(%ebp), %ecx /* %ecx = format */
- pushl %ecx /* push format */
- call panicsys /* panicsys(); */
- addl $16, %esp /* pop arguments */
-
- addl $REGSIZE, %esp
-#endif
- popl %edx
- popl %ecx
- popl %ebx
- popl %eax
- leave
- ret
- END(vpanic)
-
-/*
-void dtrace_vpanic(const char *format, va_list alist)
-*/
- ENTRY(dtrace_vpanic) /* Initial stack layout: */
-
- pushl %ebp /* | %eip | 20 */
- movl %esp, %ebp /* | %ebp | 16 */
- pushl %eax /* | %eax | 12 */
- pushl %ebx /* | %ebx | 8 */
- pushl %ecx /* | %ecx | 4 */
- pushl %edx /* | %edx | 0 */
-
- movl %esp, %ebx /* %ebx = current stack pointer */
-
- lea panic_quiesce, %eax /* %eax = &panic_quiesce */
- pushl %eax /* push &panic_quiesce */
- call dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
- addl $4, %esp /* reset stack pointer */
- jmp vpanic_common /* jump back to common code */
-
- END(dtrace_vpanic)
-
-/*
-int
-panic_trigger(int *tp)
-*/
- ENTRY(panic_trigger)
- xorl %eax, %eax
- movl $0xdefacedd, %edx
- lock
- xchgl %edx, (%edi)
- cmpl $0, %edx
- je 0f
- movl $0, %eax
- ret
-0: movl $1, %eax
- ret
- END(panic_trigger)
-
-/*
-int
-dtrace_panic_trigger(int *tp)
-*/
- ENTRY(dtrace_panic_trigger)
- xorl %eax, %eax
- movl $0xdefacedd, %edx
- lock
- xchgl %edx, (%edi)
- cmpl $0, %edx
- je 0f
- movl $0, %eax
- ret
-0: movl $1, %eax
- ret
- END(dtrace_panic_trigger)
diff --git a/sys/cddl/dev/dtrace/mips/dtrace_asm.S b/sys/cddl/dev/dtrace/mips/dtrace_asm.S
index 50f6c54..199d16be 100644
--- a/sys/cddl/dev/dtrace/mips/dtrace_asm.S
+++ b/sys/cddl/dev/dtrace/mips/dtrace_asm.S
@@ -249,49 +249,6 @@ LEAF(dtrace_invop_uninit)
END(dtrace_invop_uninit)
/*
- * The panic() and cmn_err() functions invoke vpanic() as a common entry point
- * into the panic code implemented in panicsys(). vpanic() is responsible
- * for passing through the format string and arguments, and constructing a
- * regs structure on the stack into which it saves the current register
- * values. If we are not dying due to a fatal trap, these registers will
- * then be preserved in panicbuf as the current processor state. Before
- * invoking panicsys(), vpanic() activates the first panic trigger (see
- * common/os/panic.c) and switches to the panic_stack if successful. Note that
- * DTrace takes a slightly different panic path if it must panic from probe
- * context. Instead of calling panic, it calls into dtrace_vpanic(), which
- * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
- * branches back into vpanic().
- */
-
-/*
-void
-vpanic(const char *format, va_list alist)
-*/
-LEAF(vpanic) /* Initial stack layout: */
-
-vpanic_common:
- j ra
- nop
-END(vpanic)
-
-
-
-/*
-void
-dtrace_vpanic(const char *format, va_list alist)
-*/
-LEAF(dtrace_vpanic) /* Initial stack layout: */
-
-#if 0
- jal dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
- nop
-#endif
- j vpanic_common
- nop
-
-END(dtrace_vpanic)
-
-/*
uintptr_t
dtrace_caller(int aframes)
*/
@@ -300,4 +257,3 @@ LEAF(dtrace_caller)
j ra
nop
END(dtrace_caller)
-
diff --git a/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S b/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
index 5676360..3adfbe3 100644
--- a/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
+++ b/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
@@ -161,45 +161,6 @@ ASENTRY_NOPROF(dtrace_copystr)
END(dtrace_copystr)
/*
- * The panic() and cmn_err() functions invoke vpanic() as a common entry point
- * into the panic code implemented in panicsys(). vpanic() is responsible
- * for passing through the format string and arguments, and constructing a
- * regs structure on the stack into which it saves the current register
- * values. If we are not dying due to a fatal trap, these registers will
- * then be preserved in panicbuf as the current processor state. Before
- * invoking panicsys(), vpanic() activates the first panic trigger (see
- * common/os/panic.c) and switches to the panic_stack if successful. Note that
- * DTrace takes a slightly different panic path if it must panic from probe
- * context. Instead of calling panic, it calls into dtrace_vpanic(), which
- * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
- * branches back into vpanic().
- */
-
-/*
-void
-vpanic(const char *format, va_list alist)
-*/
-ASENTRY_NOPROF(vpanic) /* Initial stack layout: */
-
-vpanic_common:
- blr
-END(vpanic)
-
-
-
-/*
-void
-dtrace_vpanic(const char *format, va_list alist)
-*/
-ASENTRY_NOPROF(dtrace_vpanic) /* Initial stack layout: */
-
-#if 0
- bl dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
-#endif
- b vpanic_common
-END(dtrace_vpanic)
-
-/*
uintptr_t
dtrace_caller(int aframes)
*/
@@ -207,4 +168,3 @@ ASENTRY_NOPROF(dtrace_caller)
li %r3, -1
blr
END(dtrace_caller)
-
diff --git a/sys/cddl/dev/profile/profile.c b/sys/cddl/dev/profile/profile.c
index 338a958..d31d5c8 100644
--- a/sys/cddl/dev/profile/profile.c
+++ b/sys/cddl/dev/profile/profile.c
@@ -134,8 +134,10 @@ struct profile_probe_percpu;
#endif
#ifdef __arm__
-/* bogus */
-#define PROF_ARTIFICIAL_FRAMES 9
+/*
+ * At least on ARMv7, this appears to work quite well.
+ */
+#define PROF_ARTIFICIAL_FRAMES 10
#endif
typedef struct profile_probe {
diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
index ed3df7a..982b44e 100644
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -243,32 +243,6 @@ struct i386_ldt_args32 {
uint32_t num;
};
-/*
- * Alternative layouts for <sys/procfs.h>
- */
-struct prstatus32 {
- int pr_version;
- u_int pr_statussz;
- u_int pr_gregsetsz;
- u_int pr_fpregsetsz;
- int pr_osreldate;
- int pr_cursig;
- pid_t pr_pid;
- struct reg32 pr_reg;
-};
-
-struct prpsinfo32 {
- int pr_version;
- u_int pr_psinfosz;
- char pr_fname[PRFNAMESZ+1];
- char pr_psargs[PRARGSZ+1];
-};
-
-struct thrmisc32 {
- char pr_tname[MAXCOMLEN+1];
- u_int _pad;
-};
-
struct mq_attr32 {
int mq_flags;
int mq_maxmsg;
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index a72612b..8696b36 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -253,9 +253,8 @@ freebsd4_freebsd32_getfsstat(struct thread *td, struct freebsd4_freebsd32_getfss
count = uap->bufsize / sizeof(struct statfs32);
size = count * sizeof(struct statfs);
- error = kern_getfsstat(td, &buf, size, UIO_SYSSPACE, uap->flags);
+ error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, uap->flags);
if (size > 0) {
- count = td->td_retval[0];
sp = buf;
while (count > 0 && error == 0) {
copy_statfs(sp, &stat32);
@@ -266,6 +265,8 @@ freebsd4_freebsd32_getfsstat(struct thread *td, struct freebsd4_freebsd32_getfss
}
free(buf, M_TEMP);
}
+ if (error == 0)
+ td->td_retval[0] = count;
return (error);
}
#endif
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index b2fe3ed..b2444c1 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -53,10 +53,10 @@ __FBSDID("$FreeBSD$");
#include <sys/filedesc.h>
#include <sys/jail.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/mount.h>
#include <sys/msg.h>
#include <sys/mutex.h>
#include <sys/namei.h>
@@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sem.h>
#include <sys/smp.h>
#include <sys/socket.h>
+#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/time.h>
@@ -326,11 +327,12 @@ static int
linprocfs_domtab(PFS_FILL_ARGS)
{
struct nameidata nd;
- struct mount *mp;
const char *lep;
char *dlep, *flep, *mntto, *mntfrom, *fstype;
size_t lep_len;
int error;
+ struct statfs *buf, *sp;
+ size_t count;
/* resolve symlinks etc. in the emulation tree prefix */
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
@@ -344,20 +346,26 @@ linprocfs_domtab(PFS_FILL_ARGS)
}
lep_len = strlen(lep);
- mtx_lock(&mountlist_mtx);
- error = 0;
- TAILQ_FOREACH(mp, &mountlist, mnt_list) {
+ buf = NULL;
+ error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
+ UIO_SYSSPACE, MNT_WAIT);
+ if (error != 0) {
+ free(buf, M_TEMP);
+ free(flep, M_TEMP);
+ return (error);
+ }
+
+ for (sp = buf; count > 0; sp++, count--) {
/* determine device name */
- mntfrom = mp->mnt_stat.f_mntfromname;
+ mntfrom = sp->f_mntfromname;
/* determine mount point */
- mntto = mp->mnt_stat.f_mntonname;
- if (strncmp(mntto, lep, lep_len) == 0 &&
- mntto[lep_len] == '/')
+ mntto = sp->f_mntonname;
+ if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
mntto += lep_len;
/* determine fs type */
- fstype = mp->mnt_stat.f_fstypename;
+ fstype = sp->f_fstypename;
if (strcmp(fstype, pn->pn_info->pi_name) == 0)
mntfrom = fstype = "proc";
else if (strcmp(fstype, "procfs") == 0)
@@ -365,16 +373,16 @@ linprocfs_domtab(PFS_FILL_ARGS)
if (strcmp(fstype, "linsysfs") == 0) {
sbuf_printf(sb, "/sys %s sysfs %s", mntto,
- mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
+ sp->f_flags & MNT_RDONLY ? "ro" : "rw");
} else {
/* For Linux msdosfs is called vfat */
if (strcmp(fstype, "msdosfs") == 0)
fstype = "vfat";
sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
- mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
+ sp->f_flags & MNT_RDONLY ? "ro" : "rw");
}
#define ADD_OPTION(opt, name) \
- if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
+ if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
ADD_OPTION(MNT_SYNCHRONOUS, "sync");
ADD_OPTION(MNT_NOEXEC, "noexec");
ADD_OPTION(MNT_NOSUID, "nosuid");
@@ -387,7 +395,8 @@ linprocfs_domtab(PFS_FILL_ARGS)
/* a real Linux mtab will also show NFS options */
sbuf_printf(sb, " 0 0\n");
}
- mtx_unlock(&mountlist_mtx);
+
+ free(buf, M_TEMP);
free(flep, M_TEMP);
return (error);
}
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 88303b9..78a65d0 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -55,10 +55,6 @@ __FBSDID("$FreeBSD$");
#include <security/mac/mac_framework.h>
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/ufsmount.h>
-
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
#include <machine/../linux32/linux32_proto.h>
@@ -136,39 +132,39 @@ linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mod
/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
-
- if (!error) {
- fd = td->td_retval[0];
- /*
- * XXX In between kern_open() and fget(), another process
- * having the same filedesc could use that fd without
- * checking below.
- */
- error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
- if (!error) {
- sx_slock(&proctree_lock);
- PROC_LOCK(p);
- if (!(bsd_flags & O_NOCTTY) &&
- SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
- PROC_UNLOCK(p);
- sx_unlock(&proctree_lock);
- /* XXXPJD: Verify if TIOCSCTTY is allowed. */
- if (fp->f_type == DTYPE_VNODE)
- (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
- td->td_ucred, td);
- } else {
- PROC_UNLOCK(p);
- sx_sunlock(&proctree_lock);
- }
+ if (error != 0)
+ goto done;
+
+ if (bsd_flags & O_NOCTTY)
+ goto done;
+
+ /*
+ * XXX In between kern_open() and fget(), another process
+ * having the same filedesc could use that fd without
+ * checking below.
+ */
+ fd = td->td_retval[0];
+ if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) {
+ if (fp->f_type != DTYPE_VNODE) {
fdrop(fp, td);
- /*
- * XXX as above, fdrop()/kern_close() pair is racy.
- */
- if (error)
- kern_close(td, fd);
+ goto done;
+ }
+ sx_slock(&proctree_lock);
+ PROC_LOCK(p);
+ if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
+ PROC_UNLOCK(p);
+ sx_sunlock(&proctree_lock);
+ /* XXXPJD: Verify if TIOCSCTTY is allowed. */
+ (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
+ td->td_ucred, td);
+ } else {
+ PROC_UNLOCK(p);
+ sx_sunlock(&proctree_lock);
}
+ fdrop(fp, td);
}
+done:
#ifdef DEBUG
if (ldebug(open))
printf(LMSG("open returns error %d"), error);
@@ -1078,12 +1074,10 @@ linux_pwrite(td, uap)
int
linux_mount(struct thread *td, struct linux_mount_args *args)
{
- struct ufs_args ufs;
char fstypename[MFSNAMELEN];
char mntonname[MNAMELEN], mntfromname[MNAMELEN];
int error;
int fsflags;
- void *fsdata;
error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
NULL);
@@ -1104,20 +1098,10 @@ linux_mount(struct thread *td, struct linux_mount_args *args)
if (strcmp(fstypename, "ext2") == 0) {
strcpy(fstypename, "ext2fs");
- fsdata = &ufs;
- ufs.fspec = mntfromname;
-#define DEFAULT_ROOTID -2
- ufs.export.ex_root = DEFAULT_ROOTID;
- ufs.export.ex_flags =
- args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
} else if (strcmp(fstypename, "proc") == 0) {
strcpy(fstypename, "linprocfs");
- fsdata = NULL;
} else if (strcmp(fstypename, "vfat") == 0) {
strcpy(fstypename, "msdosfs");
- fsdata = NULL;
- } else {
- return (ENODEV);
}
fsflags = 0;
@@ -1137,19 +1121,11 @@ linux_mount(struct thread *td, struct linux_mount_args *args)
fsflags |= MNT_UPDATE;
}
- if (strcmp(fstypename, "linprocfs") == 0) {
- error = kernel_vmount(fsflags,
- "fstype", fstypename,
- "fspath", mntonname,
- NULL);
- } else if (strcmp(fstypename, "msdosfs") == 0) {
- error = kernel_vmount(fsflags,
- "fstype", fstypename,
- "fspath", mntonname,
- "from", mntfromname,
- NULL);
- } else
- error = EOPNOTSUPP;
+ error = kernel_vmount(fsflags,
+ "fstype", fstypename,
+ "fspath", mntonname,
+ "from", mntfromname,
+ NULL);
return (error);
}
diff --git a/sys/compat/linux/linux_getcwd.c b/sys/compat/linux/linux_getcwd.c
index 1c7080d..ebcf970 100644
--- a/sys/compat/linux/linux_getcwd.c
+++ b/sys/compat/linux/linux_getcwd.c
@@ -2,11 +2,15 @@
/* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 2015 The FreeBSD Foundation
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Bill Sommerfeld.
*
+ * Portions of this software were developed by Edward Tomasz Napierala
+ * 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:
@@ -36,19 +40,9 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/namei.h>
-#include <sys/filedesc.h>
-#include <sys/kernel.h>
-#include <sys/file.h>
-#include <sys/stat.h>
#include <sys/syscallsubr.h>
-#include <sys/vnode.h>
-#include <sys/mount.h>
#include <sys/proc.h>
-#include <sys/uio.h>
#include <sys/malloc.h>
-#include <sys/dirent.h>
-#include <ufs/ufs/dir.h> /* XXX only for DIRBLKSIZ */
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -57,410 +51,40 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux.h>
#include <machine/../linux/linux_proto.h>
#endif
+#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_util.h>
-#include <security/mac/mac_framework.h>
-
-static int
-linux_getcwd_scandir(struct vnode **, struct vnode **,
- char **, char *, struct thread *);
-static int
-linux_getcwd_common(struct vnode *, struct vnode *,
- char **, char *, int, int, struct thread *);
-
-#define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4)
-
-/*
- * Vnode variable naming conventions in this file:
- *
- * rvp: the current root we're aiming towards.
- * lvp, *lvpp: the "lower" vnode
- * uvp, *uvpp: the "upper" vnode.
- *
- * Since all the vnodes we're dealing with are directories, and the
- * lookups are going *up* in the filesystem rather than *down*, the
- * usual "pvp" (parent) or "dvp" (directory) naming conventions are
- * too confusing.
- */
-
-/*
- * XXX Will infinite loop in certain cases if a directory read reliably
- * returns EINVAL on last block.
- * XXX is EINVAL the right thing to return if a directory is malformed?
- */
-
-/*
- * XXX Untested vs. mount -o union; probably does the wrong thing.
- */
-
-/*
- * Find parent vnode of *lvpp, return in *uvpp
- *
- * If we care about the name, scan it looking for name of directory
- * entry pointing at lvp.
- *
- * Place the name in the buffer which starts at bufp, immediately
- * before *bpp, and move bpp backwards to point at the start of it.
- *
- * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed
- * On exit, *uvpp is either NULL or is a locked vnode reference.
- */
-static int
-linux_getcwd_scandir(lvpp, uvpp, bpp, bufp, td)
- struct vnode **lvpp;
- struct vnode **uvpp;
- char **bpp;
- char *bufp;
- struct thread *td;
-{
- int error = 0;
- int eofflag;
- off_t off;
- int tries;
- struct uio uio;
- struct iovec iov;
- char *dirbuf = NULL;
- int dirbuflen;
- ino_t fileno;
- struct vattr va;
- struct vnode *uvp = NULL;
- struct vnode *lvp = *lvpp;
- struct componentname cn;
- int len, reclen;
- tries = 0;
-
- /*
- * If we want the filename, get some info we need while the
- * current directory is still locked.
- */
- if (bufp != NULL) {
- error = VOP_GETATTR(lvp, &va, td->td_ucred);
- if (error) {
- vput(lvp);
- *lvpp = NULL;
- *uvpp = NULL;
- return error;
- }
- }
-
- /*
- * Ok, we have to do it the hard way..
- * Next, get parent vnode using lookup of ..
- */
- cn.cn_nameiop = LOOKUP;
- cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY;
- cn.cn_thread = td;
- cn.cn_cred = td->td_ucred;
- cn.cn_pnbuf = NULL;
- cn.cn_nameptr = "..";
- cn.cn_namelen = 2;
- cn.cn_consume = 0;
- cn.cn_lkflags = LK_SHARED;
-
- /*
- * At this point, lvp is locked and will be unlocked by the lookup.
- * On successful return, *uvpp will be locked
- */
-#ifdef MAC
- error = mac_vnode_check_lookup(td->td_ucred, lvp, &cn);
- if (error == 0)
-#endif
- error = VOP_LOOKUP(lvp, uvpp, &cn);
- if (error) {
- vput(lvp);
- *lvpp = NULL;
- *uvpp = NULL;
- return error;
- }
- uvp = *uvpp;
-
- /* If we don't care about the pathname, we're done */
- if (bufp == NULL) {
- vput(lvp);
- *lvpp = NULL;
- return 0;
- }
-
- fileno = va.va_fileid;
-
- dirbuflen = DIRBLKSIZ;
- if (dirbuflen < va.va_blocksize)
- dirbuflen = va.va_blocksize;
- dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK);
-
-#if 0
-unionread:
-#endif
- off = 0;
- do {
- /* call VOP_READDIR of parent */
- iov.iov_base = dirbuf;
- iov.iov_len = dirbuflen;
-
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_offset = off;
- uio.uio_resid = dirbuflen;
- uio.uio_segflg = UIO_SYSSPACE;
- uio.uio_rw = UIO_READ;
- uio.uio_td = td;
-
- eofflag = 0;
-
-#ifdef MAC
- error = mac_vnode_check_readdir(td->td_ucred, uvp);
- if (error == 0)
-#endif /* MAC */
- error = VOP_READDIR(uvp, &uio, td->td_ucred, &eofflag,
- 0, 0);
-
- off = uio.uio_offset;
-
- /*
- * Try again if NFS tosses its cookies.
- * XXX this can still loop forever if the directory is busted
- * such that the second or subsequent page of it always
- * returns EINVAL
- */
- if ((error == EINVAL) && (tries < 3)) {
- off = 0;
- tries++;
- continue; /* once more, with feeling */
- }
-
- if (!error) {
- char *cpos;
- struct dirent *dp;
-
- cpos = dirbuf;
- tries = 0;
-
- /* scan directory page looking for matching vnode */
- for (len = (dirbuflen - uio.uio_resid); len > 0; len -= reclen) {
- dp = (struct dirent *) cpos;
- reclen = dp->d_reclen;
-
- /* check for malformed directory.. */
- if (reclen < DIRENT_MINSIZE) {
- error = EINVAL;
- goto out;
- }
- /*
- * XXX should perhaps do VOP_LOOKUP to
- * check that we got back to the right place,
- * but getting the locking games for that
- * right would be heinous.
- */
- if ((dp->d_type != DT_WHT) &&
- (dp->d_fileno == fileno)) {
- char *bp = *bpp;
- bp -= dp->d_namlen;
-
- if (bp <= bufp) {
- error = ERANGE;
- goto out;
- }
- bcopy(dp->d_name, bp, dp->d_namlen);
- error = 0;
- *bpp = bp;
- goto out;
- }
- cpos += reclen;
- }
- }
- } while (!eofflag);
- error = ENOENT;
-
-out:
- vput(lvp);
- *lvpp = NULL;
- free(dirbuf, M_TEMP);
- return error;
-}
-
-
-/*
- * common routine shared by sys___getcwd() and linux_vn_isunder()
- */
-
-#define GETCWD_CHECK_ACCESS 0x0001
-
-static int
-linux_getcwd_common (lvp, rvp, bpp, bufp, limit, flags, td)
- struct vnode *lvp;
- struct vnode *rvp;
- char **bpp;
- char *bufp;
- int limit;
- int flags;
- struct thread *td;
-{
- struct filedesc *fdp = td->td_proc->p_fd;
- struct vnode *uvp = NULL;
- char *bp = NULL;
- int error;
- accmode_t accmode = VEXEC;
-
- if (rvp == NULL) {
- rvp = fdp->fd_rdir;
- if (rvp == NULL)
- rvp = rootvnode;
- }
-
- VREF(rvp);
- VREF(lvp);
-
- /*
- * Error handling invariant:
- * Before a `goto out':
- * lvp is either NULL, or locked and held.
- * uvp is either NULL, or locked and held.
- */
-
- error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY);
- if (error != 0)
- panic("vn_lock LK_RETRY returned error %d", error);
- if (bufp)
- bp = *bpp;
- /*
- * this loop will terminate when one of the following happens:
- * - we hit the root
- * - getdirentries or lookup fails
- * - we run out of space in the buffer.
- */
- if (lvp == rvp) {
- if (bp)
- *(--bp) = '/';
- goto out;
- }
- do {
- if (lvp->v_type != VDIR) {
- error = ENOTDIR;
- goto out;
- }
-
- /*
- * access check here is optional, depending on
- * whether or not caller cares.
- */
- if (flags & GETCWD_CHECK_ACCESS) {
- error = VOP_ACCESS(lvp, accmode, td->td_ucred, td);
- if (error)
- goto out;
- accmode = VEXEC|VREAD;
- }
-
- /*
- * step up if we're a covered vnode..
- */
- while (lvp->v_vflag & VV_ROOT) {
- struct vnode *tvp;
-
- if (lvp == rvp)
- goto out;
-
- tvp = lvp;
- lvp = lvp->v_mount->mnt_vnodecovered;
- vput(tvp);
- /*
- * hodie natus est radici frater
- */
- if (lvp == NULL) {
- error = ENOENT;
- goto out;
- }
- VREF(lvp);
- error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY);
- if (error != 0)
- panic("vn_lock LK_RETRY returned %d", error);
- }
- error = linux_getcwd_scandir(&lvp, &uvp, &bp, bufp, td);
- if (error)
- goto out;
-#ifdef DIAGNOSTIC
- if (lvp != NULL)
- panic("getcwd: oops, forgot to null lvp");
- if (bufp && (bp <= bufp)) {
- panic("getcwd: oops, went back too far");
- }
-#endif
- if (bp)
- *(--bp) = '/';
- lvp = uvp;
- uvp = NULL;
- limit--;
- } while ((lvp != rvp) && (limit > 0));
-
-out:
- if (bpp)
- *bpp = bp;
- if (uvp)
- vput(uvp);
- if (lvp)
- vput(lvp);
- vrele(rvp);
- return error;
-}
-
-
/*
* Find pathname of process's current directory.
- *
- * Use vfs vnode-to-name reverse cache; if that fails, fall back
- * to reading directory contents.
*/
-
int
linux_getcwd(struct thread *td, struct linux_getcwd_args *args)
{
- char *bp, *bend, *path;
- int error, len, lenused;
+ char *path;
+ int error, lenused;
#ifdef DEBUG
if (ldebug(getcwd))
printf(ARGS(getcwd, "%p, %ld"), args->buf, (long)args->bufsize);
#endif
- len = args->bufsize;
-
- if (len > MAXPATHLEN*4)
- len = MAXPATHLEN*4;
- else if (len < 2)
- return ERANGE;
+ /*
+ * Linux returns ERANGE instead of EINVAL.
+ */
+ if (args->bufsize < 2)
+ return (ERANGE);
- path = malloc(len, M_TEMP, M_WAITOK);
+ path = malloc(LINUX_PATH_MAX, M_TEMP, M_WAITOK);
- error = kern___getcwd(td, path, UIO_SYSSPACE, len);
- if (!error) {
+ error = kern___getcwd(td, path, UIO_SYSSPACE, args->bufsize,
+ LINUX_PATH_MAX);
+ if (error == 0) {
lenused = strlen(path) + 1;
- if (lenused <= args->bufsize) {
+ error = copyout(path, args->buf, lenused);
+ if (error == 0)
td->td_retval[0] = lenused;
- error = copyout(path, args->buf, lenused);
- }
- else
- error = ERANGE;
- } else {
- bp = &path[len];
- bend = bp;
- *(--bp) = '\0';
-
- /*
- * 5th argument here is "max number of vnodes to traverse".
- * Since each entry takes up at least 2 bytes in the output buffer,
- * limit it to N/2 vnodes for an N byte buffer.
- */
-
- error = linux_getcwd_common (td->td_proc->p_fd->fd_cdir, NULL,
- &bp, path, len/2, GETCWD_CHECK_ACCESS, td);
- if (error)
- goto out;
- lenused = bend - bp;
- td->td_retval[0] = lenused;
- /* put the result into user buffer */
- error = copyout(bp, args->buf, lenused);
}
-out:
+
free(path, M_TEMP);
return (error);
}
-
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index 154d78f..51135d8 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -55,6 +55,8 @@
#define LINUX_MREMAP_MAYMOVE 1
#define LINUX_MREMAP_FIXED 2
+#define LINUX_PATH_MAX 4096
+
extern const char *linux_platform;
/*
diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c
index d287d5d..cbb536b 100644
--- a/sys/compat/svr4/svr4_stream.c
+++ b/sys/compat/svr4/svr4_stream.c
@@ -1829,7 +1829,7 @@ svr4_do_getmsg(td, uap, fp)
break;
default:
- fdclose(td->td_proc->p_fd, afp, st->s_afd, td);
+ fdclose(td, afp, st->s_afd);
fdrop(afp, td);
st->s_afd = -1;
mtx_unlock(&Giant);
@@ -1967,7 +1967,7 @@ svr4_do_getmsg(td, uap, fp)
if (error) {
if (afp) {
- fdclose(td->td_proc->p_fd, afp, st->s_afd, td);
+ fdclose(td, afp, st->s_afd);
fdrop(afp, td);
st->s_afd = -1;
}
diff --git a/sys/conf/Makefile.arm64 b/sys/conf/Makefile.arm64
new file mode 100644
index 0000000..46c191c
--- /dev/null
+++ b/sys/conf/Makefile.arm64
@@ -0,0 +1,54 @@
+# Makefile.arm64 -- with config changes.
+# Copyright 1990 W. Jolitz
+# from: @(#)Makefile.i386 7.1 5/10/91
+# from FreeBSD: src/sys/conf/Makefile.i386,v 1.255 2002/02/20 23:35:49
+# $FreeBSD$
+#
+# Makefile for FreeBSD
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/arm64/conf/``machineid''
+# after which you should do
+# config machineid
+# Generic makefile changes should be made in
+# /sys/conf/Makefile.arm64
+# after which config should be rerun for all machines.
+#
+
+# Which version of config(8) is required.
+%VERSREQ= 600012
+
+.if !defined(S)
+S= ../../..
+.endif
+.include "$S/conf/kern.pre.mk"
+
+INCLUDES+= -I$S/contrib/libfdt
+
+# We generally don't want fpu instructions in the kernel.
+CFLAGS += -mgeneral-regs-only
+
+# Reserve x18 for pcpu data
+CFLAGS += -ffixed-x18
+
+.if !empty(DDB_ENABLED)
+CFLAGS += -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer
+.endif
+
+%BEFORE_DEPEND
+
+%OBJS
+
+%FILES.c
+
+%FILES.s
+
+%FILES.m
+
+%CLEAN
+
+%RULES
+
+.include "$S/conf/kern.post.mk"
diff --git a/sys/conf/Makefile.pc98 b/sys/conf/Makefile.pc98
index 9d0f25b..1bd5bae 100644
--- a/sys/conf/Makefile.pc98
+++ b/sys/conf/Makefile.pc98
@@ -28,6 +28,9 @@ S= ./@
S= ../../..
.endif
.endif
+
+LDSCRIPT_NAME?= ldscript.${MACHINE_ARCH}
+
.include "$S/conf/kern.pre.mk"
ASM_CFLAGS.mpboot.s= ${CLANG_NO_IAS34}
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index e728ee2..06c8549 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2836,6 +2836,7 @@ options INIT_PATH=/sbin/init:/rescue/init
options BUS_DEBUG # enable newbus debugging
options DEBUG_VFS_LOCKS # enable VFS lock debugging
options SOCKBUF_DEBUG # enable sockbuf last record/mb tail checking
+options IFMEDIA_DEBUG # enable debugging in net/if_media.c
#
# Verbose SYSINIT
diff --git a/sys/conf/files b/sys/conf/files
index 9e63ffe..caaed94 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -247,14 +247,6 @@ compat/freebsd32/freebsd32_ioctl.c optional compat_freebsd32
compat/freebsd32/freebsd32_misc.c optional compat_freebsd32
compat/freebsd32/freebsd32_syscalls.c optional compat_freebsd32
compat/freebsd32/freebsd32_sysent.c optional compat_freebsd32
-contrib/altq/altq/altq_cbq.c optional altq
-contrib/altq/altq/altq_cdnr.c optional altq
-contrib/altq/altq/altq_hfsc.c optional altq
-contrib/altq/altq/altq_priq.c optional altq
-contrib/altq/altq/altq_red.c optional altq
-contrib/altq/altq/altq_rio.c optional altq
-contrib/altq/altq/altq_rmclass.c optional altq
-contrib/altq/altq/altq_subr.c optional altq
contrib/dev/acpica/common/ahids.c optional acpi acpi_debug
contrib/dev/acpica/common/ahuuids.c optional acpi acpi_debug
contrib/dev/acpica/components/debugger/dbcmds.c optional acpi acpi_debug
@@ -592,7 +584,6 @@ dev/acpica/acpi_button.c optional acpi
dev/acpica/acpi_cmbat.c optional acpi
dev/acpica/acpi_cpu.c optional acpi
dev/acpica/acpi_ec.c optional acpi
-dev/acpica/acpi_hpet.c optional acpi
dev/acpica/acpi_isab.c optional acpi isa
dev/acpica/acpi_lid.c optional acpi
dev/acpica/acpi_package.c optional acpi
@@ -1788,6 +1779,8 @@ dev/ixgbe/ixgbe_82599.c optional ix ixv inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/ixgbe_x540.c optional ix ixv inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
+dev/ixgbe/ixgbe_x550.c optional ix ixv inet \
+ compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/ixgbe_dcb.c optional ix ixv inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/ixgbe_dcb_82598.c optional ix ixv inet \
@@ -2685,24 +2678,24 @@ wpi.fw optional wpifw \
clean "wpi.fw"
dev/xe/if_xe.c optional xe
dev/xe/if_xe_pccard.c optional xe pccard
-dev/xen/balloon/balloon.c optional xen | xenhvm
-dev/xen/blkfront/blkfront.c optional xen | xenhvm
-dev/xen/blkback/blkback.c optional xen | xenhvm
-dev/xen/console/console.c optional xen | xenhvm
-dev/xen/console/xencons_ring.c optional xen | xenhvm
-dev/xen/control/control.c optional xen | xenhvm
-dev/xen/grant_table/grant_table.c optional xen | xenhvm
-dev/xen/netback/netback.c optional xen | xenhvm
-dev/xen/netfront/netfront.c optional xen | xenhvm
+dev/xen/balloon/balloon.c optional xenhvm
+dev/xen/blkfront/blkfront.c optional xenhvm
+dev/xen/blkback/blkback.c optional xenhvm
+dev/xen/console/console.c optional xenhvm
+dev/xen/console/xencons_ring.c optional xenhvm
+dev/xen/control/control.c optional xenhvm
+dev/xen/grant_table/grant_table.c optional xenhvm
+dev/xen/netback/netback.c optional xenhvm
+dev/xen/netfront/netfront.c optional xenhvm
dev/xen/xenpci/xenpci.c optional xenpci
-dev/xen/timer/timer.c optional xen | xenhvm
-dev/xen/pvcpu/pvcpu.c optional xen | xenhvm
-dev/xen/xenstore/xenstore.c optional xen | xenhvm
-dev/xen/xenstore/xenstore_dev.c optional xen | xenhvm
-dev/xen/xenstore/xenstored_dev.c optional xen | xenhvm
-dev/xen/evtchn/evtchn_dev.c optional xen | xenhvm
-dev/xen/privcmd/privcmd.c optional xen | xenhvm
-dev/xen/debug/debug.c optional xen | xenhvm
+dev/xen/timer/timer.c optional xenhvm
+dev/xen/pvcpu/pvcpu.c optional xenhvm
+dev/xen/xenstore/xenstore.c optional xenhvm
+dev/xen/xenstore/xenstore_dev.c optional xenhvm
+dev/xen/xenstore/xenstored_dev.c optional xenhvm
+dev/xen/evtchn/evtchn_dev.c optional xenhvm
+dev/xen/privcmd/privcmd.c optional xenhvm
+dev/xen/debug/debug.c optional xenhvm
dev/xl/if_xl.c optional xl pci
dev/xl/xlphy.c optional xl pci
fs/autofs/autofs.c optional autofs
@@ -2941,8 +2934,6 @@ fs/ext2fs/ext2_bmap.c optional ext2fs
fs/ext2fs/ext2_extents.c optional ext2fs
fs/ext2fs/ext2_inode.c optional ext2fs
fs/ext2fs/ext2_inode_cnv.c optional ext2fs
-fs/ext2fs/ext2_hash.c optional ext2fs
-fs/ext2fs/ext2_htree.c optional ext2fs
fs/ext2fs/ext2_lookup.c optional ext2fs
fs/ext2fs/ext2_subr.c optional ext2fs
fs/ext2fs/ext2_vfsops.c optional ext2fs
@@ -3272,6 +3263,17 @@ libkern/strtoul.c standard
libkern/strtouq.c standard
libkern/strvalid.c standard
libkern/timingsafe_bcmp.c standard
+libkern/zlib.c optional crypto | geom_uzip | ipsec | \
+ mxge | netgraph_deflate | \
+ ddb_ctf | gzio | geom_uncompress
+net/altq/altq_cbq.c optional altq
+net/altq/altq_cdnr.c optional altq
+net/altq/altq_hfsc.c optional altq
+net/altq/altq_priq.c optional altq
+net/altq/altq_red.c optional altq
+net/altq/altq_rio.c optional altq
+net/altq/altq_rmclass.c optional altq
+net/altq/altq_subr.c optional altq
net/bpf.c standard
net/bpf_buffer.c optional bpf
net/bpf_jitter.c optional bpf_jitter
@@ -3326,9 +3328,6 @@ net/slcompress.c optional netgraph_vjc | sppp | \
netgraph_sppp
net/toeplitz.c optional inet rss | inet6 rss
net/vnet.c optional vimage
-net/zlib.c optional crypto | geom_uzip | ipsec | \
- mxge | netgraph_deflate | \
- ddb_ctf | gzio | geom_uncompress
net80211/ieee80211.c optional wlan
net80211/ieee80211_acl.c optional wlan wlan_acl
net80211/ieee80211_action.c optional wlan
@@ -3485,6 +3484,7 @@ netinet/ip_ipsec.c optional inet ipsec
netinet/ip_mroute.c optional mrouting inet
netinet/ip_options.c optional inet
netinet/ip_output.c optional inet
+netinet/ip_reass.c optional inet
netinet/raw_ip.c optional inet | inet6
netinet/cc/cc.c optional inet | inet6
netinet/cc/cc_newreno.c optional inet | inet6
@@ -3504,6 +3504,7 @@ netinet/sctp_sysctl.c optional inet sctp | inet6 sctp
netinet/sctp_timer.c optional inet sctp | inet6 sctp
netinet/sctp_usrreq.c optional inet sctp | inet6 sctp
netinet/sctputil.c optional inet sctp | inet6 sctp
+netinet/siftr.c optional inet siftr alq | inet6 siftr alq
netinet/tcp_debug.c optional tcpdebug
netinet/tcp_hostcache.c optional inet | inet6
netinet/tcp_input.c optional inet | inet6
@@ -3564,7 +3565,6 @@ netipsec/keysock.c optional ipsec inet | ipsec inet6
netipsec/xform_ah.c optional ipsec inet | ipsec inet6
netipsec/xform_esp.c optional ipsec inet | ipsec inet6
netipsec/xform_ipcomp.c optional ipsec inet | ipsec inet6
-netipsec/xform_ipip.c optional ipsec inet | ipsec inet6
netipsec/xform_tcp.c optional ipsec inet tcp_signature | \
ipsec inet6 tcp_signature
netnatm/natm.c optional natm
@@ -4045,13 +4045,13 @@ vm/vm_reserv.c standard
vm/vm_unix.c standard
vm/vm_zeroidle.c standard
vm/vnode_pager.c standard
-xen/features.c optional xen | xenhvm
-xen/xenbus/xenbus_if.m optional xen | xenhvm
-xen/xenbus/xenbus.c optional xen | xenhvm
-xen/xenbus/xenbusb_if.m optional xen | xenhvm
-xen/xenbus/xenbusb.c optional xen | xenhvm
-xen/xenbus/xenbusb_front.c optional xen | xenhvm
-xen/xenbus/xenbusb_back.c optional xen | xenhvm
+xen/features.c optional xenhvm
+xen/xenbus/xenbus_if.m optional xenhvm
+xen/xenbus/xenbus.c optional xenhvm
+xen/xenbus/xenbusb_if.m optional xenhvm
+xen/xenbus/xenbusb.c optional xenhvm
+xen/xenbus/xenbusb_front.c optional xenhvm
+xen/xenbus/xenbusb_back.c optional xenhvm
xdr/xdr.c optional krpc | nfslockd | nfscl | nfsd
xdr/xdr_array.c optional krpc | nfslockd | nfscl | nfsd
xdr/xdr_mbuf.c optional krpc | nfslockd | nfscl | nfsd
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 4910903..8aadcf5 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -145,6 +145,7 @@ crypto/via/padlock.c optional padlock
crypto/via/padlock_cipher.c optional padlock
crypto/via/padlock_hash.c optional padlock
dev/acpica/acpi_if.m standard
+dev/acpica/acpi_hpet.c optional acpi
dev/acpi_support/acpi_wmi_if.m standard
dev/agp/agp_amd64.c optional agp
dev/agp/agp_i810.c optional agp
@@ -513,10 +514,10 @@ compat/ndis/winx64_wrap.S optional ndisapi pci
libkern/memmove.c standard
libkern/memset.c standard
#
-# x86 real mode BIOS emulator, required by atkbdc/dpms/pci/vesa
+# x86 real mode BIOS emulator, required by dpms/pci/vesa
#
-compat/x86bios/x86bios.c optional x86bios | atkbd | dpms | pci | vesa
-contrib/x86emu/x86emu.c optional x86bios | atkbd | dpms | pci | vesa
+compat/x86bios/x86bios.c optional x86bios | dpms | pci | vesa
+contrib/x86emu/x86emu.c optional x86bios | dpms | pci | vesa
#
# bvm console
#
@@ -558,6 +559,7 @@ x86/pci/pci_bus.c optional pci
x86/pci/qpi.c optional pci
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
+x86/x86/cpu_machdep.c standard
x86/x86/dump_machdep.c standard
x86/x86/fdt_machdep.c optional fdt
x86/x86/identcpu.c standard
@@ -568,13 +570,14 @@ x86/x86/local_apic.c standard
x86/x86/mca.c standard
x86/x86/mptable.c optional mptable
x86/x86/mptable_pci.c optional mptable pci
+x86/x86/mp_x86.c optional smp
x86/x86/msi.c optional pci
x86/x86/nexus.c standard
x86/x86/pvclock.c standard
x86/x86/tsc.c standard
x86/x86/delay.c standard
x86/xen/hvm.c optional xenhvm
-x86/xen/xen_intr.c optional xen | xenhvm
+x86/xen/xen_intr.c optional xenhvm
x86/xen/pv.c optional xenhvm
x86/xen/pvcpu_enum.c optional xenhvm
x86/xen/xen_apic.c optional xenhvm
diff --git a/sys/conf/files.arm b/sys/conf/files.arm
index 741b907..b40f7c9 100644
--- a/sys/conf/files.arm
+++ b/sys/conf/files.arm
@@ -85,6 +85,8 @@ dev/fdt/fdt_arm_platform.c optional platform fdt
dev/hwpmc/hwpmc_arm.c optional hwpmc
dev/hwpmc/hwpmc_armv7.c optional hwpmc armv6
dev/kbd/kbd.c optional sc | vt
+dev/psci/psci.c optional psci
+dev/psci/psci_arm.S optional psci
dev/syscons/scgfbrndr.c optional sc
dev/syscons/scterm-teken.c optional sc
dev/syscons/scvtb.c optional sc
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
new file mode 100644
index 0000000..f80fecd
--- /dev/null
+++ b/sys/conf/files.arm64
@@ -0,0 +1,54 @@
+# $FreeBSD$
+arm/arm/devmap.c standard
+arm/arm/generic_timer.c standard
+arm64/arm64/autoconf.c standard
+arm64/arm64/bcopy.c standard
+arm64/arm64/bus_machdep.c standard
+arm64/arm64/bus_space_asm.S standard
+arm64/arm64/busdma_machdep.c standard
+arm64/arm64/clock.c standard
+arm64/arm64/copyinout.S standard
+arm64/arm64/copystr.c standard
+arm64/arm64/cpufunc_asm.S standard
+arm64/arm64/db_disasm.c optional ddb
+arm64/arm64/db_interface.c optional ddb
+arm64/arm64/db_trace.c optional ddb
+arm64/arm64/debug_monitor.c optional kdb
+arm64/arm64/dump_machdep.c standard
+arm64/arm64/elf_machdep.c standard
+arm64/arm64/exception.S standard
+arm64/arm64/gic.c standard
+arm64/arm64/identcpu.c standard
+arm64/arm64/intr_machdep.c standard
+arm64/arm64/in_cksum.c optional inet | inet6
+arm64/arm64/locore.S standard no-obj
+arm64/arm64/machdep.c standard
+arm64/arm64/mem.c standard
+arm64/arm64/minidump_machdep.c standard
+arm64/arm64/nexus.c standard
+arm64/arm64/pic_if.m standard
+arm64/arm64/pmap.c standard
+arm64/arm64/stack_machdep.c standard
+arm64/arm64/support.S standard
+arm64/arm64/swtch.S standard
+arm64/arm64/sys_machdep.c standard
+arm64/arm64/trap.c standard
+arm64/arm64/uio_machdep.c standard
+arm64/arm64/vfp.c standard
+arm64/arm64/vm_machdep.c standard
+dev/fdt/fdt_arm64.c optional fdt
+dev/ofw/ofw_cpu.c optional fdt
+dev/psci/psci.c optional psci
+dev/psci/psci_arm64.S optional psci
+dev/uart/uart_cpu_fdt.c optional uart fdt
+dev/uart/uart_dev_pl011.c optional uart pl011
+kern/kern_clocksource.c standard
+kern/subr_dummy_vdso_tc.c standard
+libkern/bcmp.c standard
+libkern/ffs.c standard
+libkern/ffsl.c standard
+libkern/fls.c standard
+libkern/flsl.c standard
+libkern/flsll.c standard
+libkern/memmove.c standard
+libkern/memset.c standard
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 1873514..68dd6a9 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -285,6 +285,7 @@ dev/uart/uart_cpu_x86.c optional uart
dev/viawd/viawd.c optional viawd
dev/vmware/vmxnet3/if_vmx.c optional vmx
dev/acpica/acpi_if.m standard
+dev/acpica/acpi_hpet.c optional acpi
dev/acpi_support/acpi_wmi_if.m standard
dev/wbwd/wbwd.c optional wbwd
dev/wpi/if_wpi.c optional wpi
@@ -427,16 +428,15 @@ i386/bios/smapi_bios.S optional smapi
i386/i386/atomic.c standard \
compile-with "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}"
i386/i386/autoconf.c standard
-i386/i386/bios.c optional native
-i386/i386/bioscall.s optional native
+i386/i386/bios.c standard
+i386/i386/bioscall.s standard
i386/i386/bpf_jit_machdep.c optional bpf_jitter
i386/i386/db_disasm.c optional ddb
i386/i386/db_interface.c optional ddb
i386/i386/db_trace.c optional ddb
i386/i386/elan-mmcr.c optional cpu_elan | cpu_soekris
i386/i386/elf_machdep.c standard
-i386/i386/exception.s optional native
-i386/xen/exception.s optional xen
+i386/i386/exception.s standard
i386/i386/gdb_machdep.c optional gdb
i386/i386/geode.c optional cpu_geode
i386/i386/i686_mem.c optional mem
@@ -444,22 +444,17 @@ i386/i386/in_cksum.c optional inet | inet6
i386/i386/initcpu.c standard
i386/i386/io.c optional io
i386/i386/k6_mem.c optional mem
-i386/i386/locore.s optional native no-obj
-i386/xen/locore.s optional xen no-obj
+i386/i386/locore.s standard no-obj
i386/i386/longrun.c optional cpu_enable_longrun
i386/i386/machdep.c standard
-i386/xen/xen_machdep.c optional xen
i386/i386/mem.c optional mem
i386/i386/minidump_machdep.c standard
i386/i386/mp_clock.c optional smp
-i386/i386/mp_machdep.c optional native smp
-i386/xen/mp_machdep.c optional xen smp
+i386/i386/mp_machdep.c optional smp
i386/i386/mp_watchdog.c optional mp_watchdog smp
-i386/i386/mpboot.s optional smp native
-i386/xen/mptable.c optional apic xen
+i386/i386/mpboot.s optional smp
i386/i386/perfmon.c optional perfmon
-i386/i386/pmap.c optional native
-i386/xen/pmap.c optional xen
+i386/i386/pmap.c standard
i386/i386/ptrace_machdep.c standard
i386/i386/stack_machdep.c optional ddb | stack
i386/i386/support.s standard
@@ -488,7 +483,6 @@ i386/ibcs2/ibcs2_util.c optional ibcs2
i386/ibcs2/ibcs2_xenix.c optional ibcs2
i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2
i386/ibcs2/imgact_coff.c optional ibcs2
-i386/xen/clock.c optional xen
i386/isa/elink.c optional ep | ie
i386/isa/npx.c optional npx
i386/isa/pmtimer.c optional pmtimer
@@ -531,9 +525,9 @@ i386/xbox/xboxfb.c optional xboxfb
dev/fb/boot_font.c optional xboxfb
i386/xbox/pic16l.s optional xbox
#
-# x86 real mode BIOS support, required by atkbdc/dpms/pci/vesa
+# x86 real mode BIOS support, required by dpms/pci/vesa
#
-compat/x86bios/x86bios.c optional x86bios | atkbd | dpms | pci | vesa
+compat/x86bios/x86bios.c optional x86bios | dpms | pci | vesa
#
# bvm console
#
@@ -565,9 +559,9 @@ x86/iommu/intel_qi.c optional acpi acpi_dmar pci
x86/iommu/intel_quirks.c optional acpi acpi_dmar pci
x86/iommu/intel_utils.c optional acpi acpi_dmar pci
x86/isa/atpic.c optional atpic
-x86/isa/atrtc.c optional native
-x86/isa/clock.c optional native
-x86/isa/elcr.c optional atpic | apic native
+x86/isa/atrtc.c standard
+x86/isa/clock.c standard
+x86/isa/elcr.c optional atpic | apic
x86/isa/isa.c optional isa
x86/isa/isa_dma.c optional isa
x86/isa/nmi.c standard
@@ -576,24 +570,26 @@ x86/pci/pci_bus.c optional pci
x86/pci/qpi.c optional pci
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
+x86/x86/cpu_machdep.c standard
x86/x86/dump_machdep.c standard
x86/x86/fdt_machdep.c optional fdt
x86/x86/identcpu.c standard
x86/x86/intr_machdep.c standard
x86/x86/io_apic.c optional apic
-x86/x86/legacy.c optional native
+x86/x86/legacy.c standard
x86/x86/local_apic.c optional apic
x86/x86/mca.c standard
-x86/x86/mptable.c optional apic native
-x86/x86/mptable_pci.c optional apic native pci
+x86/x86/mptable.c optional apic
+x86/x86/mptable_pci.c optional apic pci
+x86/x86/mp_x86.c optional smp
x86/x86/msi.c optional apic pci
x86/x86/nexus.c standard
x86/x86/tsc.c standard
x86/x86/pvclock.c standard
x86/x86/delay.c standard
x86/xen/hvm.c optional xenhvm
-x86/xen/xen_intr.c optional xen | xenhvm
+x86/xen/xen_intr.c optional xenhvm
x86/xen/xen_apic.c optional xenhvm
-x86/xen/xenpv.c optional xen | xenhvm
-x86/xen/xen_nexus.c optional xen | xenhvm
-x86/xen/xen_msi.c optional xen | xenhvm
+x86/xen/xenpv.c optional xenhvm
+x86/xen/xen_nexus.c optional xenhvm
+x86/xen/xen_msi.c optional xenhvm
diff --git a/sys/conf/files.mips b/sys/conf/files.mips
index 3677de4..4bc6775a1 100644
--- a/sys/conf/files.mips
+++ b/sys/conf/files.mips
@@ -89,3 +89,4 @@ dev/nvram2env/nvram2env.c optional nvram2env
# hwpmc support
dev/hwpmc/hwpmc_mips.c optional hwpmc
dev/hwpmc/hwpmc_mips24k.c optional hwpmc_mips24k
+dev/hwpmc/hwpmc_mips74k.c optional hwpmc_mips74k
diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98
index be67ce4..ae165fc 100644
--- a/sys/conf/files.pc98
+++ b/sys/conf/files.pc98
@@ -248,6 +248,7 @@ x86/isa/isa.c optional isa
x86/pci/pci_bus.c optional pci
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
+x86/x86/cpu_machdep.c standard
x86/x86/dump_machdep.c standard
x86/x86/identcpu.c standard
x86/x86/intr_machdep.c standard
@@ -255,6 +256,7 @@ x86/x86/io_apic.c optional apic
x86/x86/legacy.c standard
x86/x86/local_apic.c optional apic
x86/x86/mca.c standard
+x86/x86/mp_x86.c optional smp
x86/x86/mptable.c optional apic
x86/x86/mptable_pci.c optional apic pci
x86/x86/msi.c optional apic pci
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index 9d34751..92f4101 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -31,11 +31,12 @@ dev/fb/fb.c optional sc
dev/fdt/fdt_powerpc.c optional fdt
# ofwbus depends on simplebus.
dev/fdt/simplebus.c optional aim | fdt
-dev/hwpmc/hwpmc_powerpc.c optional hwpmc
+dev/hwpmc/hwpmc_e500.c optional hwpmc
dev/hwpmc/hwpmc_mpc7xxx.c optional hwpmc
+dev/hwpmc/hwpmc_powerpc.c optional hwpmc
dev/hwpmc/hwpmc_ppc970.c optional hwpmc
dev/iicbus/ad7417.c optional ad7417 powermac
-dev/iicbus/adm1030.c optional powermac windtunnel | adm1030 powermac
+dev/iicbus/adm1030.c optional powermac windtunnel | adm1030 powermac
dev/iicbus/adt746x.c optional adt746x powermac
dev/iicbus/ds1631.c optional ds1631 powermac
dev/iicbus/ds1775.c optional ds1775 powermac
@@ -96,23 +97,20 @@ libkern/udivdi3.c optional powerpc
libkern/umoddi3.c optional powerpc
powerpc/aim/interrupt.c optional aim
powerpc/aim/locore.S optional aim no-obj
-powerpc/aim/machdep.c optional aim
+powerpc/aim/aim_machdep.c optional aim
powerpc/aim/mmu_oea.c optional aim powerpc
powerpc/aim/mmu_oea64.c optional aim
powerpc/aim/moea64_if.m optional aim
powerpc/aim/moea64_native.c optional aim
powerpc/aim/mp_cpudep.c optional aim
powerpc/aim/slb.c optional aim powerpc64
-powerpc/aim/trap.c optional aim
-powerpc/aim/uma_machdep.c optional aim
powerpc/booke/interrupt.c optional booke
powerpc/booke/locore.S optional booke no-obj
-powerpc/booke/machdep.c optional booke
+powerpc/booke/booke_machdep.c optional booke
powerpc/booke/machdep_e500.c optional booke_e500
powerpc/booke/mp_cpudep.c optional booke smp
powerpc/booke/platform_bare.c optional booke
powerpc/booke/pmap.c optional booke
-powerpc/booke/trap.c optional booke
powerpc/cpufreq/dfs.c optional cpufreq
powerpc/cpufreq/pcr.c optional cpufreq aim
powerpc/cpufreq/pmufreq.c optional cpufreq aim pmu
@@ -136,6 +134,7 @@ powerpc/mpc85xx/i2c.c optional iicbus fdt
powerpc/mpc85xx/isa.c optional mpc85xx isa
powerpc/mpc85xx/lbc.c optional mpc85xx
powerpc/mpc85xx/mpc85xx.c optional mpc85xx
+powerpc/mpc85xx/mpc85xx_gpio.c optional mpc85xx gpio
powerpc/mpc85xx/platform_mpc85xx.c optional mpc85xx
powerpc/mpc85xx/pci_mpc85xx.c optional pci mpc85xx
powerpc/ofw/ofw_machdep.c standard
@@ -195,6 +194,7 @@ powerpc/powerpc/gdb_machdep.c optional gdb
powerpc/powerpc/in_cksum.c optional inet | inet6
powerpc/powerpc/intr_machdep.c standard
powerpc/powerpc/iommu_if.m standard
+powerpc/powerpc/machdep.c standard
powerpc/powerpc/mem.c optional mem
powerpc/powerpc/mmu_if.m standard
powerpc/powerpc/mp_machdep.c optional smp
@@ -215,7 +215,9 @@ powerpc/powerpc/stack_machdep.c optional ddb | stack
powerpc/powerpc/suswintr.c standard
powerpc/powerpc/syncicache.c standard
powerpc/powerpc/sys_machdep.c standard
+powerpc/powerpc/trap.c standard
powerpc/powerpc/uio_machdep.c standard
+powerpc/powerpc/uma_machdep.c standard
powerpc/powerpc/vm_machdep.c standard
powerpc/ps3/ehci_ps3.c optional ps3 ehci
powerpc/ps3/ohci_ps3.c optional ps3 ohci
diff --git a/sys/conf/kern.mk b/sys/conf/kern.mk
index 9a7ad61..8e76268 100644
--- a/sys/conf/kern.mk
+++ b/sys/conf/kern.mk
@@ -187,7 +187,7 @@ CFLAGS+= -fstack-protector
CFLAGS+= -gdwarf-2
.endif
-CFLAGS+= ${CWARNEXTRA} ${CWARNFLAGS} ${CWARNFLAGS.${.IMPSRC:T}}
+CFLAGS+= ${CWARNFLAGS} ${CWARNFLAGS.${.IMPSRC:T}}
CFLAGS+= ${CFLAGS.${COMPILER_TYPE}} ${CFLAGS.${.IMPSRC:T}}
# Tell bmake not to mistake standard targets for things to be searched for
diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk
index ede4ae8..8c3b9c6 100644
--- a/sys/conf/kern.pre.mk
+++ b/sys/conf/kern.pre.mk
@@ -26,7 +26,7 @@ KODIR?= /boot/${KERNEL}
LDSCRIPT_NAME?= ldscript.$M
LDSCRIPT?= $S/conf/${LDSCRIPT_NAME}
-M= ${MACHINE_CPUARCH}
+M= ${MACHINE}
AWK?= awk
CP?= cp
@@ -64,13 +64,10 @@ NOSTDINC= -nostdinc
INCLUDES= ${NOSTDINC} ${INCLMAGIC} -I. -I$S
-# This hack lets us use the OpenBSD altq code without spamming a new
-# include path into contrib'ed source files.
-INCLUDES+= -I$S/contrib/altq
-
.if make(depend) || make(kernel-depend)
-# ... and the same for ipfilter
+# This hack lets us use the ipfilter code without spamming a new
+# include path into contrib'ed source files.
INCLUDES+= -I$S/contrib/ipfilter
# ... and the same for ath
@@ -90,7 +87,7 @@ INCLUDES+= -I$S/dev/cxgb -I$S/dev/cxgbe
.endif
-CFLAGS= ${COPTFLAGS} ${DEBUG} ${CWARNFLAGS}
+CFLAGS= ${COPTFLAGS} ${DEBUG}
CFLAGS+= ${INCLUDES} -D_KERNEL -DHAVE_KERNEL_OPTION_HEADERS -include opt_global.h
CFLAGS_PARAM_INLINE_UNIT_GROWTH?=100
CFLAGS_PARAM_LARGE_FUNCTION_GROWTH?=1000
diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk
index dff8610..e6fd846 100644
--- a/sys/conf/kmod.mk
+++ b/sys/conf/kmod.mk
@@ -101,10 +101,6 @@ CFLAGS+= -DHAVE_KERNEL_OPTION_HEADERS -include ${KERNBUILDDIR}/opt_global.h
# set because there are no standard paths for non-headers.
CFLAGS+= -I. -I${SYSDIR}
-# Add -I path for altq headers as they are included via net/if_var.h
-# for example.
-CFLAGS+= -I${SYSDIR}/contrib/altq
-
CFLAGS.gcc+= -finline-limit=${INLINE_LIMIT}
CFLAGS.gcc+= -fms-extensions
CFLAGS.gcc+= --param inline-unit-growth=100
@@ -429,10 +425,10 @@ genassym.o: opt_global.h
.endif
assym.s: ${SYSDIR}/kern/genassym.sh
sh ${SYSDIR}/kern/genassym.sh genassym.o > ${.TARGET}
-genassym.o: ${SYSDIR}/${MACHINE_CPUARCH}/${MACHINE_CPUARCH}/genassym.c
+genassym.o: ${SYSDIR}/${MACHINE}/${MACHINE}/genassym.c
genassym.o: ${SRCS:Mopt_*.h}
${CC} -c ${CFLAGS:N-fno-common} \
- ${SYSDIR}/${MACHINE_CPUARCH}/${MACHINE_CPUARCH}/genassym.c
+ ${SYSDIR}/${MACHINE}/${MACHINE}/genassym.c
.endif
lint: ${SRCS}
diff --git a/sys/conf/ldscript.arm64 b/sys/conf/ldscript.arm64
new file mode 100644
index 0000000..4b38654
--- /dev/null
+++ b/sys/conf/ldscript.arm64
@@ -0,0 +1,149 @@
+/* $FreeBSD$ */
+OUTPUT_ARCH(aarch64)
+ENTRY(_start)
+
+SEARCH_DIR(/usr/lib);
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = kernbase + SIZEOF_HEADERS;
+ .text :
+ {
+ *(.text)
+ *(.stub)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.gnu.linkonce.t*)
+ } =0x9090
+ _etext = .;
+ PROVIDE (etext = .);
+ .fini : { *(.fini) } =0x9090
+ .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
+ .rodata1 : { *(.rodata1) }
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.text :
+ { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+ .rela.text :
+ { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+ .rel.data :
+ { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+ .rela.data :
+ { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+ .rel.rodata :
+ { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+ .rela.rodata :
+ { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0x9090
+ .plt : { *(.plt) }
+
+ . = ALIGN(4);
+ _extab_start = .;
+ PROVIDE(extab_start = .);
+ .ARM.extab : { *(.ARM.extab) }
+ _extab.end = .;
+ PROVIDE(extab_end = .);
+
+ _exidx_start = .;
+ PROVIDE(exidx_start = .);
+ .ARM.exidx : { *(.ARM.exidx) }
+ _exidx_end = .;
+ PROVIDE(exidx_end = .);
+
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(0x1000) + (. & (0x1000 - 1)) ;
+ .data :
+ {
+ *(.data)
+ *(.gnu.linkonce.d*)
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ . = ALIGN(32 / 8);
+ _start_ctors = .;
+ PROVIDE (start_ctors = .);
+ .ctors :
+ {
+ *(.ctors)
+ }
+ _stop_ctors = .;
+ PROVIDE (stop_ctors = .);
+ .dtors :
+ {
+ *(.dtors)
+ }
+ .got : { *(.got.plt) *(.got) }
+ .dynamic : { *(.dynamic) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ . = ALIGN(8);
+ .sdata : { *(.sdata) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ . = ALIGN(8);
+ _end = . ;
+ PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* These must appear regardless of . */
+}
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index c06eeaf..3ca5bcd 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -33,17 +33,17 @@
TYPE="FreeBSD"
REVISION="11.0"
BRANCH="CURRENT"
-if [ "X${BRANCH_OVERRIDE}" != "X" ]; then
+if [ -n "${BRANCH_OVERRIDE}" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
RELEASE="${REVISION}-${BRANCH}"
VERSION="${TYPE} ${RELEASE}"
-if [ "X${SYSDIR}" = "X" ]; then
+if [ -z "${SYSDIR}" ]; then
SYSDIR=$(dirname $0)/..
fi
-if [ "X${PARAMFILE}" != "X" ]; then
+if [ -n "${PARAMFILE}" ]; then
RELDATE=$(awk '/__FreeBSD_version.*propagated to newvers/ {print $3}' \
${PARAMFILE})
else
@@ -72,7 +72,7 @@ do
done
# no copyright found, use a dummy
-if [ X"$COPYRIGHT" = X ]; then
+if [ -z "$COPYRIGHT" ]; then
COPYRIGHT="/*-
* Copyright (c) 1992-$year The FreeBSD Project.
* All rights reserved.
diff --git a/sys/conf/options b/sys/conf/options
index 28d7950..b698717 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -432,6 +432,7 @@ ROUTETABLES opt_route.h
RSS opt_rss.h
SLIP_IFF_OPTS opt_slip.h
TCPDEBUG
+SIFTR
TCP_OFFLOAD opt_inet.h # Enable code to dispatch TCP offloading
TCP_SIGNATURE opt_inet.h
VLAN_ARRAY opt_vlan.h
@@ -553,6 +554,7 @@ LPT_DEBUG opt_lpt.h
PLIP_DEBUG opt_plip.h
LOCKF_DEBUG opt_debug_lockf.h
SI_DEBUG opt_debug_si.h
+IFMEDIA_DEBUG opt_ifmedia.h
# Fb options
FB_DEBUG opt_fb.h
@@ -927,6 +929,7 @@ IPOIB_CM opt_ofed.h
# Resource Accounting
RACCT opt_global.h
+RACCT_DISABLED opt_global.h
# Resource Limits
RCTL opt_global.h
diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64
index f1d4b4a..0e59187 100644
--- a/sys/conf/options.amd64
+++ b/sys/conf/options.amd64
@@ -63,5 +63,7 @@ BPF_JITTER opt_bpf.h
XENHVM opt_global.h
+HYPERV opt_global.h
+
# options for the Intel C600 SAS driver (isci)
ISCI_LOGGING opt_isci.h
diff --git a/sys/conf/options.arm b/sys/conf/options.arm
index 239be2a..b712b02 100644
--- a/sys/conf/options.arm
+++ b/sys/conf/options.arm
@@ -40,6 +40,9 @@ PV_STATS opt_pmap.h
QEMU_WORKAROUNDS opt_global.h
SOC_BCM2835 opt_global.h
SOC_BCM2836 opt_global.h
+SOC_IMX51 opt_global.h
+SOC_IMX53 opt_global.h
+SOC_IMX6 opt_global.h
SOC_MV_ARMADAXP opt_global.h
SOC_MV_DISCOVERY opt_global.h
SOC_MV_DOVE opt_global.h
diff --git a/sys/conf/options.arm64 b/sys/conf/options.arm64
new file mode 100644
index 0000000..1dfcbec
--- /dev/null
+++ b/sys/conf/options.arm64
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+ARM64 opt_global.h
+SOCDEV_PA opt_global.h
+SOCDEV_VA opt_global.h
+VFP opt_global.h
diff --git a/sys/conf/options.i386 b/sys/conf/options.i386
index 96b6d4d..69eb7e3 100644
--- a/sys/conf/options.i386
+++ b/sys/conf/options.i386
@@ -36,6 +36,11 @@ KVA_PAGES opt_global.h
# Physical address extensions and support for >4G ram. As above.
PAE opt_global.h
+# Use PAE page tables, but limit memory support to 4GB.
+# This keeps the i386 non-PAE KBI, in particular, drivers see
+# 32bit vm_paddr_t.
+PAE_TABLES opt_global.h
+
TIMER_FREQ opt_clock.h
CPU_ATHLON_SSE_HACK opt_cpu.h
@@ -116,9 +121,9 @@ NPX_DEBUG opt_npx.h
# BPF just-in-time compiler
BPF_JITTER opt_bpf.h
-NATIVE opt_global.h
-XEN opt_global.h
XENHVM opt_global.h
+HYPERV opt_global.h
+
# options for the Intel C600 SAS driver (isci)
ISCI_LOGGING opt_isci.h
diff --git a/sys/contrib/altq/altq/altqconf.h b/sys/contrib/altq/altq/altqconf.h
deleted file mode 100644
index 4d3921c..0000000
--- a/sys/contrib/altq/altq/altqconf.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* $OpenBSD: altqconf.h,v 1.1 2001/06/27 05:28:36 kjc Exp $ */
-/* $NetBSD: altqconf.h,v 1.2 2001/05/30 11:57:16 mrg Exp $ */
-
-#if defined(_KERNEL_OPT) || defined(__OpenBSD__)
-
-#if defined(_KERNEL_OPT)
-#include "opt_altq_enabled.h"
-#endif
-
-#include <sys/conf.h>
-
-#ifdef ALTQ
-#define NALTQ 1
-#else
-#define NALTQ 0
-#endif
-
-cdev_decl(altq);
-
-#ifdef __OpenBSD__
-#define cdev_altq_init(c,n) { \
- dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
- (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
- (dev_type_stop((*))) enodev, 0, (dev_type_select((*))) enodev, \
- (dev_type_mmap((*))) enodev }
-#else
-#define cdev_altq_init(x,y) cdev__oci_init(x,y)
-#endif
-#endif /* defined(_KERNEL_OPT) || defined(__OpenBSD__) */
diff --git a/sys/contrib/dev/acpica/acpica_prep.sh b/sys/contrib/dev/acpica/acpica_prep.sh
index 00c5fa4..faf850e 100755
--- a/sys/contrib/dev/acpica/acpica_prep.sh
+++ b/sys/contrib/dev/acpica/acpica_prep.sh
@@ -18,11 +18,12 @@ fulldirs="common compiler components include os_specific"
# files to remove
stripdirs="generate libraries tests tools"
-stripfiles="Makefile README accygwin.h acefi.h achaiku.h acintel.h \
- aclinux.h aclinuxex.h acmacosx.h acmsvc.h acnetbsd.h acos2.h \
- acwin.h acwin64.h new_table.txt osefitbl.c osefixf.c \
- osfreebsdtbl.c oslinuxtbl.c osunixdir.c osunixmap.c oswindir.c \
- oswintbl.c oswinxf.c readme.txt utclib.c"
+stripfiles="Makefile README accygwin.h acdragonfly.h acdragonflyex.h \
+ acefi.h achaiku.h acintel.h aclinux.h aclinuxex.h acmacosx.h \
+ acmsvc.h acnetbsd.h acos2.h acwin.h acwin64.h new_table.txt \
+ osbsdtbl.c osefitbl.c osefixf.c osfreebsdtbl.c oslinuxtbl.c \
+ osunixdir.c osunixmap.c oswindir.c oswintbl.c oswinxf.c \
+ readme.txt utclib.c"
# include files to canonify
src_headers="acapps.h acbuffer.h accommon.h acconfig.h acdebug.h \
diff --git a/sys/contrib/dev/acpica/changes.txt b/sys/contrib/dev/acpica/changes.txt
index 0469af0..ad9d23c 100644
--- a/sys/contrib/dev/acpica/changes.txt
+++ b/sys/contrib/dev/acpica/changes.txt
@@ -1,7 +1,84 @@
----------------------------------------
-04 February 2015. Summary of changes for version 20150204:
+10 April 2015. Summary of changes for version 20150410:
-This release is available at https://acpica.org/downloads
+Reverted a change introduced in version 20150408 that caused
+a regression in the disassembler where incorrect operator
+symbols could be emitted.
+
+----------------------------------------
+08 April 2015. Summary of changes for version 20150408:
+
+
+1) ACPICA kernel-resident subsystem:
+
+Permanently set the return value for the _REV predefined name. It now
+returns 2 (was 5). This matches other ACPI implementations. _REV will be
+deprecated in the future, and is now defined to be 1 for ACPI 1.0, and 2
+for ACPI 2.0 and later. It should never be used to differentiate or
+identify operating systems.
+
+Added the "Windows 2015" string to the _OSI support. ACPICA will now
+return TRUE to a query with this string.
+
+Fixed several issues with the local version of the printf function.
+
+Added the C99 compiler option (-std=c99) to the Unix makefiles.
+
+ Current Release:
+ Non-Debug Version: 99.9K Code, 27.4K Data, 127.3K Total
+ Debug Version: 195.2K Code, 80.7K Data, 275.9K Total
+ Previous Release:
+ Non-Debug Version: 98.8K Code, 27.3K Data, 126.1K Total
+ Debug Version: 192.1K Code, 79.8K Data, 271.9K Total
+
+
+2) iASL Compiler/Disassembler and Tools:
+
+iASL: Implemented an enhancement to the constant folding feature to
+transform the parse tree to a simple Store operation whenever possible:
+ Add (2, 3, X) ==> is converted to: Store (5, X)
+ X = 2 + 3 ==> is converted to: Store (5, X)
+
+Updated support for the SLIC table (Software Licensing Description Table)
+in both the Data Table compiler and the disassembler. The SLIC table
+support now conforms to "Microsoft Software Licensing Tables (SLIC and
+MSDM). November 29, 2011. Copyright 2011 Microsoft". Note: Any SLIC data
+following the ACPI header is now defined to be "Proprietary Data", and as
+such, can only be entered or displayed as a hex data block.
+
+Implemented full support for the MSDM table as described in the document
+above. Note: The format of MSDM is similar to SLIC. Any MSDM data
+following the ACPI header is defined to be "Proprietary Data", and can
+only be entered or displayed as a hex data block.
+
+Implemented the -Pn option for the iASL Table Compiler (was only
+implemented for the ASL compiler). This option disables the iASL
+preprocessor.
+
+Disassembler: For disassembly of Data Tables, added a comment field
+around the Ascii equivalent data that is emitted as part of the "Raw
+Table Data" block. This prevents the iASL Preprocessor from possible
+confusion if/when the table is compiled.
+
+Disassembler: Added an option (-df) to force the disassembler to assume
+that the table being disassembled contains valid AML. This feature is
+useful for disassembling AML files that contain ACPI signatures other
+than DSDT or SSDT (such as OEMx or other signatures).
+
+Changes for the EFI version of the tools:
+1) Fixed a build error/issue
+2) Fixed a cast warning
+
+iASL: Fixed a path issue with the __FILE__ operator by making the
+directory prefix optional within the internal SplitInputFilename
+function.
+
+Debugger: Removed some unused global variables.
+
+Tests: Updated the makefile for proper generation of the AAPITS suite.
+
+----------------------------------------
+04 February 2015. Summary of changes for version 20150204:
ACPICA kernel-resident subsystem:
@@ -14,24 +91,26 @@ Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix GPE storm issues.
A raw gpe handling mechanism was created to allow better handling of GPE
storms that aren't easily managed by the normal handler. The raw handler
allows disabling/renabling of the the GPE so that interrupt storms can be
-avoided in cases where events cannot be timely serviced. In this scenario,
-handlers should use the AcpiSetGpe() API to disable/enable the GPE. This API
-will leave the reference counts undisturbed, thereby preventing unintentional
-clearing of the GPE when the intent in only to temporarily disable it. Raw
-handlers allow enabling and disabling of a GPE by removing GPE register
-locking. As such, raw handlers much provide their own locks while using
-GPE API's to protect access to GPE data structures.
+avoided in cases where events cannot be timely serviced. In this
+scenario, handlers should use the AcpiSetGpe() API to disable/enable the
+GPE. This API will leave the reference counts undisturbed, thereby
+preventing unintentional clearing of the GPE when the intent in only to
+temporarily disable it. Raw handlers allow enabling and disabling of a
+GPE by removing GPE register locking. As such, raw handlers much provide
+their own locks while using GPE API's to protect access to GPE data
+structures.
Lv Zheng
Events: Always modify GPE registers under the GPE lock.
Applies GPE lock around AcpiFinishGpe() to protect access to GPE register
values. Reported as bug by joe.liu@apple.com.
-Unix makefiles: Separate option to disable optimizations and _FORTIFY_SOURCE.
-This change removes the _FORTIFY_SOURCE flag from the NOOPT disable option and
-creates a separate flag (NOFORTIFY) for this purpose. Some toolchains may
-define _FORTIFY_SOURCE which leads redefined errors when building ACPICA. This
-allows disabling the option without also having to disable optimazations.
+Unix makefiles: Separate option to disable optimizations and
+_FORTIFY_SOURCE. This change removes the _FORTIFY_SOURCE flag from the
+NOOPT disable option and creates a separate flag (NOFORTIFY) for this
+purpose. Some toolchains may define _FORTIFY_SOURCE which leads redefined
+errors when building ACPICA. This allows disabling the option without
+also having to disable optimazations.
David Box
Current Release:
diff --git a/sys/contrib/dev/acpica/common/adfile.c b/sys/contrib/dev/acpica/common/adfile.c
index edf4513..2bfe7ed 100644
--- a/sys/contrib/dev/acpica/common/adfile.c
+++ b/sys/contrib/dev/acpica/common/adfile.c
@@ -295,7 +295,10 @@ FlSplitInputPathname (
char *Filename;
- *OutDirectoryPath = NULL;
+ if (OutDirectoryPath)
+ {
+ *OutDirectoryPath = NULL;
+ }
if (!InputPath)
{
@@ -340,7 +343,10 @@ FlSplitInputPathname (
return (AE_NO_MEMORY);
}
- *OutDirectoryPath = DirectoryPath;
+ if (OutDirectoryPath)
+ {
+ *OutDirectoryPath = DirectoryPath;
+ }
if (OutFilename)
{
diff --git a/sys/contrib/dev/acpica/common/adisasm.c b/sys/contrib/dev/acpica/common/adisasm.c
index 2212450..658b5be 100644
--- a/sys/contrib/dev/acpica/common/adisasm.c
+++ b/sys/contrib/dev/acpica/common/adisasm.c
@@ -64,6 +64,11 @@ AdCreateTableHeader (
char *Filename,
ACPI_TABLE_HEADER *Table);
+static ACPI_STATUS
+AdStoreTable (
+ ACPI_TABLE_HEADER *Table,
+ UINT32 *TableIndex);
+
/* Stubs for ASL compiler */
#ifndef ACPI_ASL_COMPILER
@@ -298,7 +303,7 @@ AdAmlDisassemble (
return (Status);
}
- if (!AcpiGbl_DbOpt_disasm)
+ if (!AcpiGbl_DbOpt_Disasm)
{
return (AE_OK);
}
@@ -337,7 +342,6 @@ AdAmlDisassemble (
{
fprintf (stderr, "Could not open output file %s\n", DisasmFilename);
Status = AE_ERROR;
- ACPI_FREE (DisasmFilename);
goto Cleanup;
}
@@ -346,9 +350,11 @@ AdAmlDisassemble (
*OutFilename = DisasmFilename;
- if (!AcpiUtIsAmlTable (Table))
+ /* ForceAmlDisassembly means to assume the table contains valid AML */
+
+ if (!AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table))
{
- AdDisassemblerHeader (Filename);
+ AdDisassemblerHeader (Filename, ACPI_IS_DATA_TABLE);
AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n",
Table->Signature);
AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength] "
@@ -486,7 +492,7 @@ AdAmlDisassemble (
/* Optional displays */
- if (AcpiGbl_DbOpt_disasm)
+ if (AcpiGbl_DbOpt_Disasm)
{
/* This is the real disassembly */
@@ -515,7 +521,7 @@ AdAmlDisassemble (
Cleanup:
- if (Table && !AcpiUtIsAmlTable (Table))
+ if (Table && !AcpiGbl_ForceAmlDisassembly &&!AcpiUtIsAmlTable (Table))
{
ACPI_FREE (Table);
}
@@ -543,6 +549,7 @@ Cleanup:
* FUNCTION: AdDisassemblerHeader
*
* PARAMETERS: Filename - Input file for the table
+ * TableType - Either AML or DataTable
*
* RETURN: None
*
@@ -553,7 +560,8 @@ Cleanup:
void
AdDisassemblerHeader (
- char *Filename)
+ char *Filename,
+ UINT8 TableType)
{
time_t Timer;
@@ -565,17 +573,20 @@ AdDisassemblerHeader (
AcpiOsPrintf ("/*\n");
AcpiOsPrintf (ACPI_COMMON_HEADER (AML_DISASSEMBLER_NAME, " * "));
- if (AcpiGbl_CstyleDisassembly)
+ if (TableType == ACPI_IS_AML_TABLE)
{
- AcpiOsPrintf (
- " * Disassembling to symbolic ASL+ operators\n"
- " *\n");
- }
- else
- {
- AcpiOsPrintf (
- " * Disassembling to non-symbolic legacy ASL operators\n"
- " *\n");
+ if (AcpiGbl_CstyleDisassembly)
+ {
+ AcpiOsPrintf (
+ " * Disassembling to symbolic ASL+ operators\n"
+ " *\n");
+ }
+ else
+ {
+ AcpiOsPrintf (
+ " * Disassembling to non-symbolic legacy ASL operators\n"
+ " *\n");
+ }
}
AcpiOsPrintf (" * Disassembly of %s, %s", Filename, ctime (&Timer));
@@ -609,7 +620,7 @@ AdCreateTableHeader (
/*
* Print file header and dump original table header
*/
- AdDisassemblerHeader (Filename);
+ AdDisassemblerHeader (Filename, ACPI_IS_AML_TABLE);
AcpiOsPrintf (" * Original Table Header:\n");
AcpiOsPrintf (" * Signature \"%4.4s\"\n", Table->Signature);
@@ -717,7 +728,7 @@ AdDisplayTables (
return (AE_NOT_EXIST);
}
- if (!AcpiGbl_DbOpt_verbose)
+ if (!AcpiGbl_DbOpt_Verbose)
{
AdCreateTableHeader (Filename, Table);
}
@@ -725,7 +736,7 @@ AdDisplayTables (
AcpiDmDisassemble (NULL, AcpiGbl_ParseOpRoot, ACPI_UINT32_MAX);
MpEmitMappingInfo ();
- if (AcpiGbl_DbOpt_verbose)
+ if (AcpiGbl_DbOpt_Verbose)
{
AcpiOsPrintf ("\n\nTable Header:\n");
AcpiUtDebugDumpBuffer ((UINT8 *) Table, sizeof (ACPI_TABLE_HEADER),
@@ -740,6 +751,43 @@ AdDisplayTables (
}
+/*******************************************************************************
+ *
+ * FUNCTION: AdStoreTable
+ *
+ * PARAMETERS: Table - Table header
+ * TableIndex - Where the table index is returned
+ *
+ * RETURN: Status and table index.
+ *
+ * DESCRIPTION: Add an ACPI table to the global table list
+ *
+ ******************************************************************************/
+
+static ACPI_STATUS
+AdStoreTable (
+ ACPI_TABLE_HEADER *Table,
+ UINT32 *TableIndex)
+{
+ ACPI_STATUS Status;
+ ACPI_TABLE_DESC *TableDesc;
+
+
+ Status = AcpiTbGetNextTableDescriptor (TableIndex, &TableDesc);
+ if (ACPI_FAILURE (Status))
+ {
+ return (Status);
+ }
+
+ /* Initialize added table */
+
+ AcpiTbInitTableDescriptor (TableDesc, ACPI_PTR_TO_PHYSADDR (Table),
+ ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, Table);
+ AcpiTbValidateTable (TableDesc);
+ return (AE_OK);
+}
+
+
/******************************************************************************
*
* FUNCTION: AdGetLocalTables
@@ -777,8 +825,7 @@ AdGetLocalTables (
/* Store DSDT in the Table Manager */
- Status = AcpiTbStoreTable (0, NewTable, NewTable->Length,
- 0, &TableIndex);
+ Status = AdStoreTable (NewTable, &TableIndex);
if (ACPI_FAILURE (Status))
{
fprintf (stderr, "Could not store DSDT\n");
@@ -871,9 +918,7 @@ AdParseTable (
if (LoadTable)
{
- Status = AcpiTbStoreTable ((ACPI_PHYSICAL_ADDRESS) Table, Table,
- Table->Length, ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
- &TableIndex);
+ Status = AdStoreTable (Table, &TableIndex);
if (ACPI_FAILURE (Status))
{
return (Status);
diff --git a/sys/contrib/dev/acpica/common/dmtable.c b/sys/contrib/dev/acpica/common/dmtable.c
index d33d86f..b1875f8 100644
--- a/sys/contrib/dev/acpica/common/dmtable.c
+++ b/sys/contrib/dev/acpica/common/dmtable.c
@@ -241,13 +241,6 @@ static const char *AcpiDmPmttSubnames[] =
"Unknown SubTable Type" /* Reserved */
};
-static const char *AcpiDmSlicSubnames[] =
-{
- "Public Key Structure",
- "Windows Marker Structure",
- "Unknown SubTable Type" /* Reserved */
-};
-
static const char *AcpiDmSratSubnames[] =
{
"Processor Local APIC/SAPIC Affinity",
@@ -339,6 +332,7 @@ ACPI_DMTABLE_DATA AcpiDmTableData[] =
{ACPI_SIG_MCHI, AcpiDmTableInfoMchi, NULL, NULL, TemplateMchi, "Management Controller Host Interface table"},
{ACPI_SIG_MPST, AcpiDmTableInfoMpst, AcpiDmDumpMpst, DtCompileMpst, TemplateMpst, "Memory Power State Table"},
{ACPI_SIG_MSCT, NULL, AcpiDmDumpMsct, DtCompileMsct, TemplateMsct, "Maximum System Characteristics Table"},
+ {ACPI_SIG_MSDM, NULL, AcpiDmDumpSlic, DtCompileSlic, TemplateMsdm, "Microsoft Data Management table"},
{ACPI_SIG_MTMR, NULL, AcpiDmDumpMtmr, DtCompileMtmr, TemplateMtmr, "MID Timer Table"},
{ACPI_SIG_PCCT, AcpiDmTableInfoPcct, AcpiDmDumpPcct, DtCompilePcct, TemplatePcct, "Platform Communications Channel Table"},
{ACPI_SIG_PMTT, NULL, AcpiDmDumpPmtt, DtCompilePmtt, TemplatePmtt, "Platform Memory Topology Table"},
@@ -515,10 +509,20 @@ AcpiDmDumpDataTable (
}
else
{
- AcpiOsPrintf ("\n**** Unknown ACPI table type [%4.4s]\n\n",
+ AcpiOsPrintf ("\n**** Unknown ACPI table signature [%4.4s]\n\n",
Table->Signature);
- fprintf (stderr, "Unknown ACPI table signature [%4.4s], decoding header only\n",
+
+ fprintf (stderr, "Unknown ACPI table signature [%4.4s], ",
Table->Signature);
+
+ if (!AcpiGbl_ForceAmlDisassembly)
+ {
+ fprintf (stderr, "decoding ACPI table header only\n");
+ }
+ else
+ {
+ fprintf (stderr, "assuming table contains valid AML code\n");
+ }
}
}
else if (TableData->TableHandler)
@@ -686,6 +690,7 @@ AcpiDmDumpTable (
UINT32 ByteLength;
UINT8 Temp8;
UINT16 Temp16;
+ UINT32 Temp32;
UINT64 Value;
ACPI_DMTABLE_DATA *TableData;
const char *Name;
@@ -715,7 +720,8 @@ AcpiDmDumpTable (
if ((CurrentOffset >= TableLength) ||
(SubtableLength && (Info->Offset >= SubtableLength)))
{
- AcpiOsPrintf ("**** ACPI table terminates in the middle of a data structure!\n");
+ AcpiOsPrintf (
+ "**** ACPI table terminates in the middle of a data structure! (dump table)\n");
return (AE_BAD_DATA);
}
@@ -760,7 +766,6 @@ AcpiDmDumpTable (
case ACPI_DMT_UINT32:
case ACPI_DMT_NAME4:
case ACPI_DMT_SIG:
- case ACPI_DMT_SLIC:
case ACPI_DMT_LPIT:
ByteLength = 4;
@@ -805,6 +810,12 @@ AcpiDmDumpTable (
ByteLength = 128;
break;
+ case ACPI_DMT_BUFFER:
+ case ACPI_DMT_RAW_BUFFER:
+
+ ByteLength = SubtableLength;
+ break;
+
case ACPI_DMT_STRING:
ByteLength = ACPI_STRLEN (ACPI_CAST_PTR (char, Target)) + 1;
@@ -838,7 +849,8 @@ AcpiDmDumpTable (
if (CurrentOffset + ByteLength > TableLength)
{
- AcpiOsPrintf ("**** ACPI table terminates in the middle of a data structure!\n");
+ AcpiOsPrintf (
+ "**** ACPI table terminates in the middle of a data structure!\n");
return (AE_BAD_DATA);
}
@@ -1005,8 +1017,9 @@ AcpiDmDumpTable (
AcpiOsPrintf ("%2.2X", *Target);
Temp8 = AcpiDmGenerateChecksum (Table,
- ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Length,
- ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Checksum);
+ ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Length,
+ ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Checksum);
+
if (Temp8 != ACPI_CAST_PTR (ACPI_TABLE_HEADER, Table)->Checksum)
{
AcpiOsPrintf (
@@ -1032,7 +1045,7 @@ AcpiDmDumpTable (
Temp8 = ACPI_GAS_WIDTH_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, Temp8, AcpiDmGasAccessWidth[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmGasAccessWidth[Temp8]);
break;
case ACPI_DMT_GAS:
@@ -1069,7 +1082,8 @@ AcpiDmDumpTable (
Temp16 = ACPI_DMAR_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT16_FORMAT, ACPI_GET16 (Target), AcpiDmDmarSubnames[Temp16]);
+ AcpiOsPrintf (UINT16_FORMAT, ACPI_GET16 (Target),
+ AcpiDmDmarSubnames[Temp16]);
break;
case ACPI_DMT_DMAR_SCOPE:
@@ -1082,7 +1096,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_DMAR_SCOPE_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmDmarScope[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmDmarScope[Temp8]);
break;
case ACPI_DMT_EINJACT:
@@ -1095,7 +1110,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_EINJ_ACTION_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmEinjActions[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmEinjActions[Temp8]);
break;
case ACPI_DMT_EINJINST:
@@ -1108,7 +1124,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_EINJ_INSTRUCTION_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmEinjInstructions[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmEinjInstructions[Temp8]);
break;
case ACPI_DMT_ERSTACT:
@@ -1121,7 +1138,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_ERST_ACTION_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmErstActions[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmErstActions[Temp8]);
break;
case ACPI_DMT_ERSTINST:
@@ -1134,7 +1152,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_ERST_INSTRUCTION_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmErstInstructions[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmErstInstructions[Temp8]);
break;
case ACPI_DMT_GTDT:
@@ -1147,7 +1166,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_GTDT_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmGtdtSubnames[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmGtdtSubnames[Temp8]);
break;
case ACPI_DMT_HEST:
@@ -1160,12 +1180,15 @@ AcpiDmDumpTable (
Temp16 = ACPI_HEST_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT16_FORMAT, ACPI_GET16 (Target), AcpiDmHestSubnames[Temp16]);
+ AcpiOsPrintf (UINT16_FORMAT, ACPI_GET16 (Target),
+ AcpiDmHestSubnames[Temp16]);
break;
case ACPI_DMT_HESTNTFY:
- AcpiOsPrintf (STRING_FORMAT, "Hardware Error Notification Structure");
+ AcpiOsPrintf (STRING_FORMAT,
+ "Hardware Error Notification Structure");
+
AcpiDmDumpTable (TableLength, CurrentOffset, Target,
sizeof (ACPI_HEST_NOTIFY), AcpiDmTableInfoHestNotify);
AcpiOsPrintf ("\n");
@@ -1182,7 +1205,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_HEST_NOTIFY_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmHestNotifySubnames[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmHestNotifySubnames[Temp8]);
break;
case ACPI_DMT_MADT:
@@ -1195,7 +1219,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_MADT_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmMadtSubnames[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmMadtSubnames[Temp8]);
break;
case ACPI_DMT_PCCT:
@@ -1208,7 +1233,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_PCCT_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmPcctSubnames[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmPcctSubnames[Temp8]);
break;
case ACPI_DMT_PMTT:
@@ -1221,20 +1247,20 @@ AcpiDmDumpTable (
Temp8 = ACPI_PMTT_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmPmttSubnames[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmPmttSubnames[Temp8]);
break;
- case ACPI_DMT_SLIC:
-
- /* SLIC subtable types */
-
- Temp8 = *Target;
- if (Temp8 > ACPI_SLIC_TYPE_RESERVED)
- {
- Temp8 = ACPI_SLIC_TYPE_RESERVED;
- }
+ case ACPI_DMT_RAW_BUFFER:
+ /*
+ * Currently only used for SLIC table
+ */
+ AcpiOsPrintf ("/* Proprietary data structure */ ");
- AcpiOsPrintf (UINT32_FORMAT, *Target, AcpiDmSlicSubnames[Temp8]);
+ AcpiDmDumpBuffer (Table, sizeof (ACPI_TABLE_HEADER),
+ ByteLength, sizeof (ACPI_TABLE_HEADER),
+ "Licensing Data", TRUE);
+ AcpiOsPrintf ("\n");
break;
case ACPI_DMT_SRAT:
@@ -1247,7 +1273,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_SRAT_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmSratSubnames[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmSratSubnames[Temp8]);
break;
case ACPI_DMT_FADTPM:
@@ -1260,7 +1287,8 @@ AcpiDmDumpTable (
Temp8 = ACPI_FADT_PM_RESERVED;
}
- AcpiOsPrintf (UINT8_FORMAT, *Target, AcpiDmFadtProfiles[Temp8]);
+ AcpiOsPrintf (UINT8_FORMAT, *Target,
+ AcpiDmFadtProfiles[Temp8]);
break;
case ACPI_DMT_IVRS:
@@ -1295,26 +1323,14 @@ AcpiDmDumpTable (
/* LPIT subtable types */
- Temp8 = *Target;
- switch (Temp8)
+ Temp32 = ACPI_GET32 (Target);
+ if (Temp32 > ACPI_LPIT_TYPE_RESERVED)
{
- case ACPI_LPIT_TYPE_NATIVE_CSTATE:
-
- Name = AcpiDmLpitSubnames[0];
- break;
-
- case ACPI_LPIT_TYPE_SIMPLE_IO:
-
- Name = AcpiDmLpitSubnames[1];
- break;
-
- default:
-
- Name = AcpiDmLpitSubnames[2];
- break;
+ Temp32 = ACPI_LPIT_TYPE_RESERVED;
}
- AcpiOsPrintf (UINT32_FORMAT, *Target, Name);
+ AcpiOsPrintf (UINT32_FORMAT, ACPI_GET32 (Target),
+ AcpiDmLpitSubnames[Temp32]);
break;
case ACPI_DMT_EXIT:
@@ -1331,8 +1347,10 @@ AcpiDmDumpTable (
if (TableOffset && !SubtableLength)
{
- /* If this table is not the main table, subtable must have valid length */
-
+ /*
+ * If this table is not the main table, the subtable must have a
+ * valid length
+ */
AcpiOsPrintf ("Invalid zero length subtable\n");
return (AE_BAD_DATA);
}
diff --git a/sys/contrib/dev/acpica/common/dmtbdump.c b/sys/contrib/dev/acpica/common/dmtbdump.c
index 399afa5..8a44328 100644
--- a/sys/contrib/dev/acpica/common/dmtbdump.c
+++ b/sys/contrib/dev/acpica/common/dmtbdump.c
@@ -59,14 +59,6 @@ AcpiDmValidateFadtLength (
UINT32 Revision,
UINT32 Length);
-static void
-AcpiDmDumpBuffer (
- void *Table,
- UINT32 BufferOffset,
- UINT32 Length,
- UINT32 AbsoluteOffset,
- char *Header);
-
/*******************************************************************************
*
@@ -78,6 +70,7 @@ AcpiDmDumpBuffer (
* AbsoluteOffset - Offset of buffer in the main ACPI table
* Header - Name of the buffer field (printed on the
* first line only.)
+ * MultiLine - TRUE if a large, multi-line buffer
*
* RETURN: None
*
@@ -86,13 +79,14 @@ AcpiDmDumpBuffer (
*
******************************************************************************/
-static void
+void
AcpiDmDumpBuffer (
void *Table,
UINT32 BufferOffset,
UINT32 Length,
UINT32 AbsoluteOffset,
- char *Header)
+ char *Header,
+ BOOLEAN MultiLine)
{
UINT8 *Buffer;
UINT32 i;
@@ -110,10 +104,19 @@ AcpiDmDumpBuffer (
{
if (!(i % 16))
{
- AcpiOsPrintf ("\n");
- AcpiDmLineHeader (AbsoluteOffset,
- ((Length - i) > 16) ? 16 : (Length - i), Header);
- Header = NULL;
+ if (MultiLine)
+ {
+ /* Insert a backslash - line continuation character */
+
+ AcpiOsPrintf ("\\\n ");
+ }
+ else
+ {
+ AcpiOsPrintf ("\n");
+ AcpiDmLineHeader (AbsoluteOffset,
+ ((Length - i) > 16) ? 16 : (Length - i), Header);
+ Header = NULL;
+ }
}
AcpiOsPrintf ("%.02X ", *Buffer);
@@ -526,7 +529,7 @@ AcpiDmDumpAsf (
DataOffset++;
if (DataOffset > Table->Length)
{
- AcpiOsPrintf ("**** ACPI table terminates in the middle of a data structure!\n");
+ AcpiOsPrintf ("**** ACPI table terminates in the middle of a data structure! (ASF! table)\n");
return;
}
}
@@ -692,7 +695,7 @@ AcpiDmDumpCsrt (
InfoLength = SubSubTable->Length - SubSubOffset;
AcpiDmDumpBuffer (SubSubTable, SubSubOffset, InfoLength,
- Offset + SubOffset + SubSubOffset, "ResourceInfo");
+ Offset + SubOffset + SubSubOffset, "ResourceInfo", FALSE);
SubSubOffset += InfoLength;
/* Point to next sub-subtable */
@@ -812,7 +815,7 @@ AcpiDmDumpDbg2 (
if (SubTable->OemDataOffset)
{
AcpiDmDumpBuffer (SubTable, SubTable->OemDataOffset, SubTable->OemDataLength,
- Offset + SubTable->OemDataOffset, "OEM Data");
+ Offset + SubTable->OemDataOffset, "OEM Data", FALSE);
}
/* Point to next subtable */
@@ -2535,67 +2538,8 @@ void
AcpiDmDumpSlic (
ACPI_TABLE_HEADER *Table)
{
- ACPI_STATUS Status;
- UINT32 Offset = sizeof (ACPI_TABLE_SLIC);
- ACPI_SLIC_HEADER *SubTable;
- ACPI_DMTABLE_INFO *InfoTable;
-
-
- /* There is no main SLIC table, only subtables */
-
- SubTable = ACPI_ADD_PTR (ACPI_SLIC_HEADER, Table, Offset);
- while (Offset < Table->Length)
- {
- /* Common subtable header */
-
- AcpiOsPrintf ("\n");
- Status = AcpiDmDumpTable (Table->Length, Offset, SubTable,
- SubTable->Length, AcpiDmTableInfoSlicHdr);
- if (ACPI_FAILURE (Status))
- {
- return;
- }
-
- switch (SubTable->Type)
- {
- case ACPI_SLIC_TYPE_PUBLIC_KEY:
-
- InfoTable = AcpiDmTableInfoSlic0;
- break;
-
- case ACPI_SLIC_TYPE_WINDOWS_MARKER:
-
- InfoTable = AcpiDmTableInfoSlic1;
- break;
-
- default:
-
- AcpiOsPrintf ("\n**** Unknown SLIC subtable type 0x%X\n", SubTable->Type);
-
- /* Attempt to continue */
-
- if (!SubTable->Length)
- {
- AcpiOsPrintf ("Invalid zero length subtable\n");
- return;
- }
- goto NextSubTable;
- }
-
- AcpiOsPrintf ("\n");
- Status = AcpiDmDumpTable (Table->Length, Offset, SubTable,
- SubTable->Length, InfoTable);
- if (ACPI_FAILURE (Status))
- {
- return;
- }
-
-NextSubTable:
- /* Point to next subtable */
-
- Offset += SubTable->Length;
- SubTable = ACPI_ADD_PTR (ACPI_SLIC_HEADER, SubTable, SubTable->Length);
- }
+ AcpiDmDumpTable (Table->Length, sizeof (ACPI_TABLE_HEADER), Table,
+ Table->Length - sizeof (*Table), AcpiDmTableInfoSlic);
}
diff --git a/sys/contrib/dev/acpica/common/dmtbinfo.c b/sys/contrib/dev/acpica/common/dmtbinfo.c
index 6a71c8a..4ce802b 100644
--- a/sys/contrib/dev/acpica/common/dmtbinfo.c
+++ b/sys/contrib/dev/acpica/common/dmtbinfo.c
@@ -200,9 +200,7 @@
#define ACPI_S3PTH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_HEADER,f)
#define ACPI_S3PT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_RESUME,f)
#define ACPI_S3PT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_S3PT_SUSPEND,f)
-#define ACPI_SLICH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SLIC_HEADER,f)
-#define ACPI_SLIC0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SLIC_KEY,f)
-#define ACPI_SLIC1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SLIC_MARKER,f)
+#define ACPI_SLIC_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_TABLE_SLIC,f)
#define ACPI_SRATH_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SUBTABLE_HEADER,f)
#define ACPI_SRAT0_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_CPU_AFFINITY,f)
#define ACPI_SRAT1_OFFSET(f) (UINT16) ACPI_OFFSET (ACPI_SRAT_MEM_AFFINITY,f)
@@ -2043,42 +2041,16 @@ ACPI_DMTABLE_INFO AcpiDmTableInfoSbst[] =
/*******************************************************************************
*
- * SLIC - Software Licensing Description Table. There is no common table, just
- * the standard ACPI header and then subtables.
+ * SLIC - Software Licensing Description Table. This table contains the standard
+ * ACPI header followed by proprietary data structures
*
******************************************************************************/
-/* Common Subtable header (one per Subtable) */
-
-ACPI_DMTABLE_INFO AcpiDmTableInfoSlicHdr[] =
-{
- {ACPI_DMT_SLIC, ACPI_SLICH_OFFSET (Type), "Subtable Type", 0},
- {ACPI_DMT_UINT32, ACPI_SLICH_OFFSET (Length), "Length", DT_LENGTH},
- ACPI_DMT_TERMINATOR
-};
-
-ACPI_DMTABLE_INFO AcpiDmTableInfoSlic0[] =
-{
- {ACPI_DMT_UINT8, ACPI_SLIC0_OFFSET (KeyType), "Key Type", 0},
- {ACPI_DMT_UINT8, ACPI_SLIC0_OFFSET (Version), "Version", 0},
- {ACPI_DMT_UINT16, ACPI_SLIC0_OFFSET (Reserved), "Reserved", 0},
- {ACPI_DMT_UINT32, ACPI_SLIC0_OFFSET (Algorithm), "Algorithm", 0},
- {ACPI_DMT_NAME4, ACPI_SLIC0_OFFSET (Magic), "Magic", 0},
- {ACPI_DMT_UINT32, ACPI_SLIC0_OFFSET (BitLength), "BitLength", 0},
- {ACPI_DMT_UINT32, ACPI_SLIC0_OFFSET (Exponent), "Exponent", 0},
- {ACPI_DMT_BUF128, ACPI_SLIC0_OFFSET (Modulus[0]), "Modulus", 0},
- ACPI_DMT_TERMINATOR
-};
+/* Single subtable, a proprietary format, so treat it as a buffer */
-ACPI_DMTABLE_INFO AcpiDmTableInfoSlic1[] =
+ACPI_DMTABLE_INFO AcpiDmTableInfoSlic[] =
{
- {ACPI_DMT_UINT32, ACPI_SLIC1_OFFSET (Version), "Version", 0},
- {ACPI_DMT_NAME6, ACPI_SLIC1_OFFSET (OemId[0]), "Oem ID", 0},
- {ACPI_DMT_NAME8, ACPI_SLIC1_OFFSET (OemTableId[0]), "Oem Table ID", 0},
- {ACPI_DMT_NAME8, ACPI_SLIC1_OFFSET (WindowsFlag[0]), "Windows Flag", 0},
- {ACPI_DMT_UINT32, ACPI_SLIC1_OFFSET (SlicVersion), "SLIC Version", 0},
- {ACPI_DMT_BUF16, ACPI_SLIC1_OFFSET (Reserved[0]), "Reserved", 0},
- {ACPI_DMT_BUF128, ACPI_SLIC1_OFFSET (Signature[0]), "Signature", 0},
+ {ACPI_DMT_RAW_BUFFER, 0, "Software Licensing Structure", 0},
ACPI_DMT_TERMINATOR
};
@@ -2091,7 +2063,7 @@ ACPI_DMTABLE_INFO AcpiDmTableInfoSlic1[] =
ACPI_DMTABLE_INFO AcpiDmTableInfoSlit[] =
{
- {ACPI_DMT_UINT64, ACPI_SLIT_OFFSET (LocalityCount), "Localities", 0},
+ {ACPI_DMT_UINT64, ACPI_SLIT_OFFSET (LocalityCount), "Localities", 0},
ACPI_DMT_TERMINATOR
};
diff --git a/sys/contrib/dev/acpica/compiler/aslcodegen.c b/sys/contrib/dev/acpica/compiler/aslcodegen.c
index 541236a..8dd30f3 100644
--- a/sys/contrib/dev/acpica/compiler/aslcodegen.c
+++ b/sys/contrib/dev/acpica/compiler/aslcodegen.c
@@ -460,7 +460,7 @@ CgWriteTableHeader (
/* Compiler version */
- TableHeader.AslCompilerRevision = ASL_REVISION;
+ TableHeader.AslCompilerRevision = ACPI_CA_VERSION;
/* Table length. Checksum zero for now, will rewrite later */
diff --git a/sys/contrib/dev/acpica/compiler/aslcompile.c b/sys/contrib/dev/acpica/compiler/aslcompile.c
index cf37c6a..0b0ca7a 100644
--- a/sys/contrib/dev/acpica/compiler/aslcompile.c
+++ b/sys/contrib/dev/acpica/compiler/aslcompile.c
@@ -195,8 +195,16 @@ CmDoCompile (
Event = UtBeginEvent ("Constant folding via AML interpreter");
DbgPrint (ASL_DEBUG_OUTPUT,
"\nInterpreting compile-time constant expressions\n\n");
- TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD,
- OpcAmlConstantWalk, NULL, NULL);
+
+ if (Gbl_FoldConstants)
+ {
+ TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD,
+ OpcAmlConstantWalk, NULL, NULL);
+ }
+ else
+ {
+ DbgPrint (ASL_PARSE_OUTPUT, " Optional folding disabled\n");
+ }
UtEndEvent (Event);
/* Update AML opcodes if necessary, after constant folding */
diff --git a/sys/contrib/dev/acpica/compiler/aslcompiler.h b/sys/contrib/dev/acpica/compiler/aslcompiler.h
index 7fb2088..7b07295 100644
--- a/sys/contrib/dev/acpica/compiler/aslcompiler.h
+++ b/sys/contrib/dev/acpica/compiler/aslcompiler.h
@@ -686,6 +686,10 @@ TrAllocateNode (
UINT32 ParseOpcode);
void
+TrPrintNodeCompileFlags (
+ UINT32 Flags);
+
+void
TrReleaseNode (
ACPI_PARSE_OBJECT *Op);
@@ -705,6 +709,10 @@ TrCreateLeafNode (
UINT32 ParseOpcode);
ACPI_PARSE_OBJECT *
+TrCreateNullTarget (
+ void);
+
+ACPI_PARSE_OBJECT *
TrCreateAssignmentNode (
ACPI_PARSE_OBJECT *Target,
ACPI_PARSE_OBJECT *Source);
diff --git a/sys/contrib/dev/acpica/compiler/asldefine.h b/sys/contrib/dev/acpica/compiler/asldefine.h
index f639ecc..14307c1 100644
--- a/sys/contrib/dev/acpica/compiler/asldefine.h
+++ b/sys/contrib/dev/acpica/compiler/asldefine.h
@@ -48,7 +48,6 @@
/*
* Compiler versions and names
*/
-#define ASL_REVISION ACPI_CA_VERSION
#define ASL_COMPILER_NAME "ASL+ Optimizing Compiler"
#define AML_DISASSEMBLER_NAME "AML/ASL+ Disassembler"
#define ASL_INVOCATION_NAME "iasl"
diff --git a/sys/contrib/dev/acpica/compiler/aslfold.c b/sys/contrib/dev/acpica/compiler/aslfold.c
index b8038ec..26b786d 100644
--- a/sys/contrib/dev/acpica/compiler/aslfold.c
+++ b/sys/contrib/dev/acpica/compiler/aslfold.c
@@ -76,97 +76,125 @@ OpcUpdateIntegerNode (
ACPI_PARSE_OBJECT *Op,
UINT64 Value);
+static ACPI_STATUS
+TrTransformToStoreOp (
+ ACPI_PARSE_OBJECT *Op,
+ ACPI_WALK_STATE *WalkState);
+
+static ACPI_STATUS
+TrSimpleConstantReduction (
+ ACPI_PARSE_OBJECT *Op,
+ ACPI_WALK_STATE *WalkState);
+
+static void
+TrInstallReducedConstant (
+ ACPI_PARSE_OBJECT *Op,
+ ACPI_OPERAND_OBJECT *ObjDesc);
+
/*******************************************************************************
*
- * FUNCTION: OpcAmlEvaluationWalk1
+ * FUNCTION: OpcAmlConstantWalk
*
* PARAMETERS: ASL_WALK_CALLBACK
*
* RETURN: Status
*
- * DESCRIPTION: Descending callback for AML execution of constant subtrees
+ * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
*
******************************************************************************/
-static ACPI_STATUS
-OpcAmlEvaluationWalk1 (
+ACPI_STATUS
+OpcAmlConstantWalk (
ACPI_PARSE_OBJECT *Op,
UINT32 Level,
void *Context)
{
- ACPI_WALK_STATE *WalkState = Context;
- ACPI_STATUS Status;
- ACPI_PARSE_OBJECT *OutOp;
+ ACPI_WALK_STATE *WalkState;
+ ACPI_STATUS Status = AE_OK;
- WalkState->Op = Op;
- WalkState->Opcode = Op->Common.AmlOpcode;
- WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
-
- /* Copy child pointer to Arg for compatibility with Interpreter */
+ if (Op->Asl.CompileFlags == 0)
+ {
+ return (AE_OK);
+ }
- if (Op->Asl.Child)
+ /*
+ * Only interested in subtrees that could possibly contain
+ * expressions that can be evaluated at this time
+ */
+ if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
+ (Op->Asl.CompileFlags & NODE_IS_TARGET))
{
- Op->Common.Value.Arg = Op->Asl.Child;
+ return (AE_OK);
}
- /* Call AML dispatcher */
+ /* Create a new walk state */
- Status = AcpiDsExecBeginOp (WalkState, &OutOp);
- if (ACPI_FAILURE (Status))
+ WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
+ if (!WalkState)
{
- AcpiOsPrintf ("Constant interpretation failed - %s\n",
- AcpiFormatException (Status));
+ return (AE_NO_MEMORY);
}
- return (Status);
-}
+ WalkState->NextOp = NULL;
+ WalkState->Params = NULL;
+ /*
+ * Examine the entire subtree -- all nodes must be constants
+ * or type 3/4/5 opcodes
+ */
+ Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
+ OpcAmlCheckForConstant, NULL, WalkState);
-/*******************************************************************************
- *
- * FUNCTION: OpcAmlEvaluationWalk2
- *
- * PARAMETERS: ASL_WALK_CALLBACK
- *
- * RETURN: Status
- *
- * DESCRIPTION: Ascending callback for AML execution of constant subtrees
- *
- ******************************************************************************/
+ /*
+ * Did we find an entire subtree that contains all constants
+ * and type 3/4/5 opcodes?
+ */
+ switch (Status)
+ {
+ case AE_OK:
-static ACPI_STATUS
-OpcAmlEvaluationWalk2 (
- ACPI_PARSE_OBJECT *Op,
- UINT32 Level,
- void *Context)
-{
- ACPI_WALK_STATE *WalkState = Context;
- ACPI_STATUS Status;
+ /* Simple case, like Add(3,4) -> 7 */
+ Status = TrSimpleConstantReduction (Op, WalkState);
+ break;
- WalkState->Op = Op;
- WalkState->Opcode = Op->Common.AmlOpcode;
- WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
+ case AE_CTRL_RETURN_VALUE:
- /* Copy child pointer to Arg for compatibility with Interpreter */
+ /* More complex case, like Add(3,4,Local0) -> Store(7,Local0) */
- if (Op->Asl.Child)
- {
- Op->Common.Value.Arg = Op->Asl.Child;
- }
+ Status = TrTransformToStoreOp (Op, WalkState);
+ break;
- /* Call AML dispatcher */
+ case AE_TYPE:
+
+ AcpiDsDeleteWalkState (WalkState);
+ return (AE_OK);
+
+ default:
+ AcpiDsDeleteWalkState (WalkState);
+ break;
+ }
- Status = AcpiDsExecEndOp (WalkState);
if (ACPI_FAILURE (Status))
{
- AcpiOsPrintf ("Constant interpretation failed - %s\n",
- AcpiFormatException (Status));
+ DbgPrint (ASL_PARSE_OUTPUT, "Cannot resolve, %s\n",
+ AcpiFormatException (Status));
+
+ /* We could not resolve the subtree for some reason */
+
+ AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
+ (char *) AcpiFormatException (Status));
+
+ /* Set the subtree value to ZERO anyway. Eliminates further errors */
+
+ OpcUpdateIntegerNode (Op, 0);
}
- return (Status);
+ /* Abort the walk of this subtree, we are done with it */
+
+ return (AE_CTRL_DEPTH);
}
@@ -189,6 +217,7 @@ OpcAmlCheckForConstant (
void *Context)
{
ACPI_WALK_STATE *WalkState = Context;
+ ACPI_STATUS Status = AE_OK;
WalkState->Op = Op;
@@ -196,7 +225,20 @@ OpcAmlCheckForConstant (
WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
- Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
+ Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
+
+ /*
+ * TBD: Ignore buffer constants for now. The problem is that these
+ * constants have been transformed into RAW_DATA at this point, from
+ * the parse tree transform process which currently happens before
+ * the constant folding process. We may need to defer this transform
+ * for buffer until after the constant folding.
+ */
+ if (WalkState->Opcode == AML_BUFFER_OP)
+ {
+ Status = AE_TYPE;
+ goto CleanupAndExit;
+ }
/*
* These opcodes do not appear in the OpcodeInfo table, but
@@ -207,50 +249,32 @@ OpcAmlCheckForConstant (
(WalkState->Opcode == AML_RAW_DATA_DWORD) ||
(WalkState->Opcode == AML_RAW_DATA_QWORD))
{
- WalkState->WalkType = ACPI_WALK_CONST_OPTIONAL;
- return (AE_TYPE);
+ DbgPrint (ASL_PARSE_OUTPUT, "RAW DATA");
+ Status = AE_TYPE;
+ goto CleanupAndExit;
}
+ /* Type 3/4/5 opcodes have the AML_CONSTANT flag set */
+
if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
{
- /* The opcode is not a Type 3/4/5 opcode */
+ /* Not 3/4/5 opcode, but maybe can convert to STORE */
if (Op->Asl.CompileFlags & NODE_IS_TARGET)
{
DbgPrint (ASL_PARSE_OUTPUT,
- "**** Valid Target, cannot reduce ****\n");
- }
- else
- {
- DbgPrint (ASL_PARSE_OUTPUT,
- "**** Not a Type 3/4/5 opcode ****\n");
+ "**** Valid Target, transform to Store ****\n");
+ return (AE_CTRL_RETURN_VALUE);
}
- if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
- {
- /*
- * We are looking at at normal expression to see if it can be
- * reduced. It can't. No error
- */
- return (AE_TYPE);
- }
+ /* Expression cannot be reduced */
- /*
- * This is an expression that MUST reduce to a constant, and it
- * can't be reduced. This is an error
- */
- if (Op->Asl.CompileFlags & NODE_IS_TARGET)
- {
- AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op,
- Op->Asl.ParseOpName);
- }
- else
- {
- AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op,
- Op->Asl.ParseOpName);
- }
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "**** Not a Type 3/4/5 opcode (%s) ****",
+ Op->Asl.ParseOpName);
- return (AE_TYPE);
+ Status = AE_TYPE;
+ goto CleanupAndExit;
}
/* Debug output */
@@ -259,250 +283,346 @@ OpcAmlCheckForConstant (
if (Op->Asl.CompileFlags & NODE_IS_TARGET)
{
- DbgPrint (ASL_PARSE_OUTPUT, " TARGET");
+ if (Op->Asl.ParseOpcode == PARSEOP_ZERO)
+ {
+ DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " NULL TARGET");
+ }
+ else
+ {
+ DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " VALID TARGET");
+ }
}
if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
{
- DbgPrint (ASL_PARSE_OUTPUT, " TERMARG");
+ DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " TERMARG");
}
+CleanupAndExit:
+
+ /* Dump the node compile flags also */
+
+ TrPrintNodeCompileFlags (Op->Asl.CompileFlags);
DbgPrint (ASL_PARSE_OUTPUT, "\n");
- return (AE_OK);
+ return (Status);
}
/*******************************************************************************
*
- * FUNCTION: OpcAmlConstantWalk
+ * FUNCTION: TrSimpleConstantReduction
*
- * PARAMETERS: ASL_WALK_CALLBACK
+ * PARAMETERS: Op - Parent operator to be transformed
+ * WalkState - Current walk state
*
* RETURN: Status
*
- * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
+ * DESCRIPTION: Reduce an entire AML operation to a single constant. The
+ * operation must not have a target operand.
+ *
+ * Add (32,64) --> 96
*
******************************************************************************/
-ACPI_STATUS
-OpcAmlConstantWalk (
+static ACPI_STATUS
+TrSimpleConstantReduction (
ACPI_PARSE_OBJECT *Op,
- UINT32 Level,
- void *Context)
+ ACPI_WALK_STATE *WalkState)
{
- ACPI_WALK_STATE *WalkState;
- ACPI_STATUS Status = AE_OK;
- ACPI_OPERAND_OBJECT *ObjDesc;
ACPI_PARSE_OBJECT *RootOp;
ACPI_PARSE_OBJECT *OriginalParentOp;
- UINT8 WalkType;
+ ACPI_OPERAND_OBJECT *ObjDesc;
+ ACPI_STATUS Status;
- /*
- * Only interested in subtrees that could possibly contain
- * expressions that can be evaluated at this time
- */
- if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
- (Op->Asl.CompileFlags & NODE_IS_TARGET))
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Simple subtree constant reduction, operator to constant\n");
+
+ /* Allocate a new temporary root for this subtree */
+
+ RootOp = TrAllocateNode (PARSEOP_INTEGER);
+ if (!RootOp)
{
- return (AE_OK);
+ return (AE_NO_MEMORY);
}
- /* Set the walk type based on the reduction used for this op */
+ RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
- if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
- {
- /* Op is a TermArg, constant folding is merely optional */
+ OriginalParentOp = Op->Common.Parent;
+ Op->Common.Parent = RootOp;
- if (!Gbl_FoldConstants)
- {
- return (AE_CTRL_DEPTH);
- }
+ /* Hand off the subtree to the AML interpreter */
- WalkType = ACPI_WALK_CONST_OPTIONAL;
- }
- else
- {
- /* Op is a DataObject, the expression MUST reduced to a constant */
+ WalkState->CallerReturnDesc = &ObjDesc;
+
+ Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
+ OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
+
+ /* Restore original parse tree */
+
+ Op->Common.Parent = OriginalParentOp;
- WalkType = ACPI_WALK_CONST_REQUIRED;
+ if (ACPI_FAILURE (Status))
+ {
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Constant Subtree evaluation(1), %s\n",
+ AcpiFormatException (Status));
+ return (Status);
}
- /* Create a new walk state */
+ /* Get the final result */
- WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
- if (!WalkState)
+ Status = AcpiDsResultPop (&ObjDesc, WalkState);
+ if (ACPI_FAILURE (Status))
{
- return (AE_NO_MEMORY);
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Constant Subtree evaluation(2), %s\n",
+ AcpiFormatException (Status));
+ return (Status);
}
- WalkState->NextOp = NULL;
- WalkState->Params = NULL;
- WalkState->WalkType = WalkType;
- WalkState->CallerReturnDesc = &ObjDesc;
+ TrInstallReducedConstant (Op, ObjDesc);
- /*
- * Examine the entire subtree -- all nodes must be constants
- * or type 3/4/5 opcodes
- */
- Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
- OpcAmlCheckForConstant, NULL, WalkState);
+ UtSetParseOpName (Op);
+ Op->Asl.Child = NULL;
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: TrTransformToStoreOp
+ *
+ * PARAMETERS: Op - Parent operator to be transformed
+ * WalkState - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transforms a single AML operation with a constant and target
+ * to a simple store operation:
+ *
+ * Add (32,64,DATA) --> Store (96,DATA)
+ *
+ ******************************************************************************/
+
+static ACPI_STATUS
+TrTransformToStoreOp (
+ ACPI_PARSE_OBJECT *Op,
+ ACPI_WALK_STATE *WalkState)
+{
+ ACPI_PARSE_OBJECT *OriginalTarget;
+ ACPI_PARSE_OBJECT *NewTarget;
+ ACPI_PARSE_OBJECT *Child1;
+ ACPI_PARSE_OBJECT *Child2;
+ ACPI_OPERAND_OBJECT *ObjDesc;
+ ACPI_PARSE_OBJECT *NewParent;
+ ACPI_PARSE_OBJECT *OriginalParent;
+ ACPI_STATUS Status;
+
+
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Reduction/Transform to StoreOp: Store(Constant, Target)\n");
+
+ /* Extract the operands */
+
+ Child1 = Op->Asl.Child;
+ Child2 = Child1->Asl.Next;
/*
- * Did we find an entire subtree that contains all constants and type 3/4/5
- * opcodes? (Only AE_OK or AE_TYPE returned from above)
+ * Special case for DIVIDE -- it has two targets. The first
+ * is for the remainder and if present, we will not attempt
+ * to reduce the expression.
*/
- if (Status == AE_TYPE)
+ if (Op->Asl.ParseOpcode == PARSEOP_DIVIDE)
{
- /* Subtree cannot be reduced to a constant */
-
- if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
+ Child2 = Child2->Asl.Next;
+ if (Child2->Asl.ParseOpcode != PARSEOP_ZERO)
{
- AcpiDsDeleteWalkState (WalkState);
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Cannot reduce DIVIDE - has two targets\n\n");
return (AE_OK);
}
+ }
+
+ /*
+ * Create a NULL (zero) target so that we can use the
+ * interpreter to evaluate the expression.
+ */
+ NewTarget = TrCreateNullTarget ();
+ NewTarget->Common.AmlOpcode = AML_INT_NAMEPATH_OP;
- /* Don't descend any further, and use a default "constant" value */
+ /* Handle one-operand cases (NOT, TOBCD, etc.) */
- Status = AE_CTRL_DEPTH;
+ if (!Child2->Asl.Next)
+ {
+ Child2 = Child1;
}
- else
+
+ /* Link in new NULL target as the last operand */
+
+ OriginalTarget = Child2->Asl.Next;
+ Child2->Asl.Next = NewTarget;
+ NewTarget->Asl.Parent = OriginalTarget->Asl.Parent;
+
+ NewParent = TrAllocateNode (PARSEOP_INTEGER);
+ NewParent->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
+
+ OriginalParent = Op->Common.Parent;
+ Op->Common.Parent = NewParent;
+
+ /* Hand off the subtree to the AML interpreter */
+
+ WalkState->CallerReturnDesc = &ObjDesc;
+
+ Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
+ OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
+ if (ACPI_FAILURE (Status))
{
- /* Subtree can be reduced */
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Constant Subtree evaluation(3), %s\n",
+ AcpiFormatException (Status));
+ goto EvalError;
+ }
- /* Allocate a new temporary root for this subtree */
+ /* Get the final result */
- RootOp = TrAllocateNode (PARSEOP_INTEGER);
- if (!RootOp)
- {
- return (AE_NO_MEMORY);
- }
+ Status = AcpiDsResultPop (&ObjDesc, WalkState);
+ if (ACPI_FAILURE (Status))
+ {
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Constant Subtree evaluation(4), %s\n",
+ AcpiFormatException (Status));
+ goto EvalError;
+ }
- RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
+ /* Folded constant is in ObjDesc, store into Child1 */
- OriginalParentOp = Op->Common.Parent;
- Op->Common.Parent = RootOp;
+ TrInstallReducedConstant (Child1, ObjDesc);
- /* Hand off the subtree to the AML interpreter */
+ /* Convert operator to STORE */
- Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
- OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
- Op->Common.Parent = OriginalParentOp;
+ Op->Asl.ParseOpcode = PARSEOP_STORE;
+ Op->Asl.AmlOpcode = AML_STORE_OP;
+ UtSetParseOpName (Op);
+ Op->Common.Parent = OriginalParent;
- /* TBD: we really *should* release the RootOp node */
+ /* Truncate any subtree expressions, they have been evaluated */
- if (ACPI_SUCCESS (Status))
- {
- TotalFolds++;
+ Child1->Asl.Child = NULL;
+ Child2->Asl.Child = NULL;
- /* Get the final result */
+ /* First child is the folded constant */
- Status = AcpiDsResultPop (&ObjDesc, WalkState);
- }
+ /* Second child will be the target */
- /* Check for error from the ACPICA core */
+ Child1->Asl.Next = OriginalTarget;
+ return (AE_OK);
- if (ACPI_FAILURE (Status))
- {
- AslCoreSubsystemError (Op, Status,
- "Failure during constant evaluation", FALSE);
- }
- }
- if (ACPI_FAILURE (Status))
- {
- /* We could not resolve the subtree for some reason */
+EvalError:
- AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
- Op->Asl.ParseOpName);
+ /* Restore original links */
- /* Set the subtree value to ZERO anyway. Eliminates further errors */
+ Op->Common.Parent = OriginalParent;
+ Child2->Asl.Next = OriginalTarget;
+ return (Status);
+}
- OpcUpdateIntegerNode (Op, 0);
- }
- else
- {
- AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
- Op->Asl.ParseOpName);
-
- /*
- * Because we know we executed type 3/4/5 opcodes above, we know that
- * the result must be either an Integer, String, or Buffer.
- */
- switch (ObjDesc->Common.Type)
- {
- case ACPI_TYPE_INTEGER:
- OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
+/*******************************************************************************
+ *
+ * FUNCTION: TrInstallReducedConstant
+ *
+ * PARAMETERS: Op - Parent operator to be transformed
+ * ObjDesc - Reduced constant to be installed
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Transform the original operator to a simple constant.
+ * Handles Integers, Strings, and Buffers.
+ *
+ ******************************************************************************/
+
+static void
+TrInstallReducedConstant (
+ ACPI_PARSE_OBJECT *Op,
+ ACPI_OPERAND_OBJECT *ObjDesc)
+{
+ ACPI_PARSE_OBJECT *RootOp;
- DbgPrint (ASL_PARSE_OUTPUT,
- "Constant expression reduced to (%s) %8.8X%8.8X\n",
- Op->Asl.ParseOpName,
- ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
- break;
- case ACPI_TYPE_STRING:
+ TotalFolds++;
+ AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
+ Op->Asl.ParseOpName);
- Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
- Op->Common.AmlOpcode = AML_STRING_OP;
- Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
- Op->Common.Value.String = ObjDesc->String.Pointer;
+ /*
+ * Because we know we executed type 3/4/5 opcodes above, we know that
+ * the result must be either an Integer, String, or Buffer.
+ */
+ switch (ObjDesc->Common.Type)
+ {
+ case ACPI_TYPE_INTEGER:
- DbgPrint (ASL_PARSE_OUTPUT,
- "Constant expression reduced to (STRING) %s\n",
- Op->Common.Value.String);
+ OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
- break;
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Constant expression reduced to (%s) %8.8X%8.8X\n\n",
+ Op->Asl.ParseOpName,
+ ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
+ break;
- case ACPI_TYPE_BUFFER:
+ case ACPI_TYPE_STRING:
- Op->Asl.ParseOpcode = PARSEOP_BUFFER;
- Op->Common.AmlOpcode = AML_BUFFER_OP;
- Op->Asl.CompileFlags = NODE_AML_PACKAGE;
- UtSetParseOpName (Op);
+ Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
+ Op->Common.AmlOpcode = AML_STRING_OP;
+ Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
+ Op->Common.Value.String = ObjDesc->String.Pointer;
- /* Child node is the buffer length */
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Constant expression reduced to (STRING) %s\n\n",
+ Op->Common.Value.String);
- RootOp = TrAllocateNode (PARSEOP_INTEGER);
+ break;
- RootOp->Asl.AmlOpcode = AML_DWORD_OP;
- RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
- RootOp->Asl.Parent = Op;
+ case ACPI_TYPE_BUFFER:
- (void) OpcSetOptimalIntegerSize (RootOp);
+ Op->Asl.ParseOpcode = PARSEOP_BUFFER;
+ Op->Common.AmlOpcode = AML_BUFFER_OP;
+ Op->Asl.CompileFlags = NODE_AML_PACKAGE;
+ UtSetParseOpName (Op);
- Op->Asl.Child = RootOp;
- Op = RootOp;
- UtSetParseOpName (Op);
+ /* Child node is the buffer length */
- /* Peer to the child is the raw buffer data */
+ RootOp = TrAllocateNode (PARSEOP_INTEGER);
- RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
- RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
- RootOp->Asl.AmlLength = ObjDesc->Buffer.Length;
- RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
- RootOp->Asl.Parent = Op->Asl.Parent;
+ RootOp->Asl.AmlOpcode = AML_DWORD_OP;
+ RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
+ RootOp->Asl.Parent = Op;
- Op->Asl.Next = RootOp;
- Op = RootOp;
+ (void) OpcSetOptimalIntegerSize (RootOp);
- DbgPrint (ASL_PARSE_OUTPUT,
- "Constant expression reduced to (BUFFER) length %X\n",
- ObjDesc->Buffer.Length);
- break;
+ Op->Asl.Child = RootOp;
+ Op = RootOp;
+ UtSetParseOpName (Op);
- default:
+ /* Peer to the child is the raw buffer data */
- printf ("Unsupported return type: %s\n",
- AcpiUtGetObjectTypeName (ObjDesc));
- break;
- }
- }
+ RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
+ RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
+ RootOp->Asl.AmlLength = ObjDesc->Buffer.Length;
+ RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
+ RootOp->Asl.Parent = Op->Asl.Parent;
- UtSetParseOpName (Op);
- Op->Asl.Child = NULL;
+ Op->Asl.Next = RootOp;
+ Op = RootOp;
- AcpiDsDeleteWalkState (WalkState);
- return (AE_CTRL_DEPTH);
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "Constant expression reduced to (BUFFER) length %X\n\n",
+ ObjDesc->Buffer.Length);
+ break;
+
+ default:
+ break;
+ }
}
@@ -511,10 +631,11 @@ OpcAmlConstantWalk (
* FUNCTION: OpcUpdateIntegerNode
*
* PARAMETERS: Op - Current parse object
+ * Value - Value for the integer op
*
* RETURN: None
*
- * DESCRIPTION: Update node to the correct integer type.
+ * DESCRIPTION: Update node to the correct Integer type and value
*
******************************************************************************/
@@ -566,3 +687,98 @@ OpcUpdateIntegerNode (
Op->Asl.AmlLength = 0;
}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: OpcAmlEvaluationWalk1
+ *
+ * PARAMETERS: ASL_WALK_CALLBACK
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback for AML execution of constant subtrees
+ *
+ ******************************************************************************/
+
+static ACPI_STATUS
+OpcAmlEvaluationWalk1 (
+ ACPI_PARSE_OBJECT *Op,
+ UINT32 Level,
+ void *Context)
+{
+ ACPI_WALK_STATE *WalkState = Context;
+ ACPI_STATUS Status;
+ ACPI_PARSE_OBJECT *OutOp;
+
+
+ WalkState->Op = Op;
+ WalkState->Opcode = Op->Common.AmlOpcode;
+ WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
+
+ /* Copy child pointer to Arg for compatibility with Interpreter */
+
+ if (Op->Asl.Child)
+ {
+ Op->Common.Value.Arg = Op->Asl.Child;
+ }
+
+ /* Call AML dispatcher */
+
+ Status = AcpiDsExecBeginOp (WalkState, &OutOp);
+ if (ACPI_FAILURE (Status))
+ {
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "%s Constant interpretation failed (1) - %s\n",
+ Op->Asl.ParseOpName, AcpiFormatException (Status));
+ }
+
+ return (Status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: OpcAmlEvaluationWalk2
+ *
+ * PARAMETERS: ASL_WALK_CALLBACK
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback for AML execution of constant subtrees
+ *
+ ******************************************************************************/
+
+static ACPI_STATUS
+OpcAmlEvaluationWalk2 (
+ ACPI_PARSE_OBJECT *Op,
+ UINT32 Level,
+ void *Context)
+{
+ ACPI_WALK_STATE *WalkState = Context;
+ ACPI_STATUS Status;
+
+
+ WalkState->Op = Op;
+ WalkState->Opcode = Op->Common.AmlOpcode;
+ WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
+
+ /* Copy child pointer to Arg for compatibility with Interpreter */
+
+ if (Op->Asl.Child)
+ {
+ Op->Common.Value.Arg = Op->Asl.Child;
+ }
+
+ /* Call AML dispatcher */
+
+ Status = AcpiDsExecEndOp (WalkState);
+ if (ACPI_FAILURE (Status))
+ {
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "%s: Constant interpretation failed (2) - %s\n",
+ Op->Asl.ParseOpName, AcpiFormatException (Status));
+ }
+
+ return (Status);
+}
diff --git a/sys/contrib/dev/acpica/compiler/asllisting.c b/sys/contrib/dev/acpica/compiler/asllisting.c
index 9c51a93..a8fe2de 100644
--- a/sys/contrib/dev/acpica/compiler/asllisting.c
+++ b/sys/contrib/dev/acpica/compiler/asllisting.c
@@ -270,7 +270,10 @@ LsTreeWriteWalk (
UtPrintFormattedName (Op->Asl.ParseOpcode, Level);
- DbgPrint (ASL_TREE_OUTPUT, " (%.4X)\n", Op->Asl.ParseOpcode);
+ DbgPrint (ASL_TREE_OUTPUT, " (%.4X) Flags %8.8X",
+ Op->Asl.ParseOpcode, Op->Asl.CompileFlags);
+ TrPrintNodeCompileFlags (Op->Asl.CompileFlags);
+ DbgPrint (ASL_TREE_OUTPUT, "\n");
return (AE_OK);
}
diff --git a/sys/contrib/dev/acpica/compiler/aslmain.c b/sys/contrib/dev/acpica/compiler/aslmain.c
index d7ba1ae..99745ad 100644
--- a/sys/contrib/dev/acpica/compiler/aslmain.c
+++ b/sys/contrib/dev/acpica/compiler/aslmain.c
@@ -187,6 +187,7 @@ Usage (
ACPI_OPTION ("-db", "Do not translate Buffers to Resource Templates");
ACPI_OPTION ("-dc <f1 f2 ...>", "Disassemble AML and immediately compile it");
ACPI_OPTION ("", " (Obtain DSDT from current system if no input file)");
+ ACPI_OPTION ("-df", "Force disassembler to assume table contains valid AML");
ACPI_OPTION ("-dl", "Emit legacy ASL code only (no C-style operators)");
ACPI_OPTION ("-e <f1 f2 ...>", "Include ACPI table(s) for external symbol resolution");
ACPI_OPTION ("-fe <file>", "Specify external symbol declaration file");
diff --git a/sys/contrib/dev/acpica/compiler/aslmap.c b/sys/contrib/dev/acpica/compiler/aslmap.c
index 3d0e327..90252cb 100644
--- a/sys/contrib/dev/acpica/compiler/aslmap.c
+++ b/sys/contrib/dev/acpica/compiler/aslmap.c
@@ -222,7 +222,7 @@ const ASL_MAPPING_ENTRY AslKeywordMapping [] =
/* EXTENDEDIO */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0),
/* EXTENDEDMEMORY */ OP_TABLE_ENTRY (AML_BYTE_OP, 0, 0, 0),
/* EXTENDEDSPACE */ OP_TABLE_ENTRY (AML_RAW_DATA_QWORD, 0, 0, ACPI_BTYPE_INTEGER),
-/* EXTERNAL */ OP_TABLE_ENTRY (AML_DEFAULT_ARG_OP, 0, 0, 0),
+/* EXTERNAL */ OP_TABLE_ENTRY (AML_EXTERNAL_OP, 0, 0, 0),
/* FATAL */ OP_TABLE_ENTRY (AML_FATAL_OP, 0, 0, 0),
/* FIELD */ OP_TABLE_ENTRY (AML_FIELD_OP, 0, NODE_AML_PACKAGE, 0),
/* FINDSETLEFTBIT */ OP_TABLE_ENTRY (AML_FIND_SET_LEFT_BIT_OP, 0, 0, ACPI_BTYPE_INTEGER),
diff --git a/sys/contrib/dev/acpica/compiler/aslmapenter.c b/sys/contrib/dev/acpica/compiler/aslmapenter.c
index a75ff33..87ad28a 100644
--- a/sys/contrib/dev/acpica/compiler/aslmapenter.c
+++ b/sys/contrib/dev/acpica/compiler/aslmapenter.c
@@ -216,6 +216,7 @@ MpCreateGpioInfo (
ACPI_GPIO_INFO *Info;
ACPI_GPIO_INFO *NextGpio;
ACPI_GPIO_INFO *PrevGpio;
+ char *Buffer;
/*
@@ -223,8 +224,8 @@ MpCreateGpioInfo (
* sorted by both source device name and then the pin number. There is
* one block per pin.
*/
- Info = ACPI_CAST_PTR (ACPI_GPIO_INFO,
- UtStringCacheCalloc (sizeof (ACPI_GPIO_INFO)));
+ Buffer = UtStringCacheCalloc (sizeof (ACPI_GPIO_INFO));
+ Info = ACPI_CAST_PTR (ACPI_GPIO_INFO, Buffer);
NextGpio = Gbl_GpioList;
PrevGpio = NULL;
@@ -293,14 +294,15 @@ MpCreateSerialInfo (
ACPI_SERIAL_INFO *Info;
ACPI_SERIAL_INFO *NextSerial;
ACPI_SERIAL_INFO *PrevSerial;
+ char *Buffer;
/*
* Allocate a new info block and insert it into the global Serial list
* sorted by both source device name and then the address.
*/
- Info = ACPI_CAST_PTR (ACPI_SERIAL_INFO,
- UtStringCacheCalloc (sizeof (ACPI_SERIAL_INFO)));
+ Buffer = UtStringCacheCalloc (sizeof (ACPI_SERIAL_INFO));
+ Info = ACPI_CAST_PTR (ACPI_SERIAL_INFO, Buffer);
NextSerial = Gbl_SerialList;
PrevSerial = NULL;
diff --git a/sys/contrib/dev/acpica/compiler/asloptions.c b/sys/contrib/dev/acpica/compiler/asloptions.c
index 5868d98..cc20bcd 100644
--- a/sys/contrib/dev/acpica/compiler/asloptions.c
+++ b/sys/contrib/dev/acpica/compiler/asloptions.c
@@ -274,6 +274,11 @@ AslDoOptions (
break;
+ case 'f':
+
+ AcpiGbl_ForceAmlDisassembly = TRUE;
+ break;
+
case 'l': /* Use legacy ASL code (not ASL+) for disassembly */
Gbl_DoCompile = FALSE;
diff --git a/sys/contrib/dev/acpica/compiler/aslrules.y b/sys/contrib/dev/acpica/compiler/aslrules.y
index 67f0413..dbe0882 100644
--- a/sys/contrib/dev/acpica/compiler/aslrules.y
+++ b/sys/contrib/dev/acpica/compiler/aslrules.y
@@ -130,7 +130,7 @@ Expression
: PARSEOP_EXP_LOGICAL_NOT {$<n>$ = TrCreateLeafNode (PARSEOP_LNOT);}
TermArg {$$ = TrLinkChildren ($<n>2,1,$3);}
| PARSEOP_EXP_NOT {$<n>$ = TrCreateLeafNode (PARSEOP_NOT);}
- TermArg {$$ = TrLinkChildren ($<n>2,2,$3,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>2,2,$3,TrCreateNullTarget ());}
| SuperName PARSEOP_EXP_INCREMENT {$<n>$ = TrCreateLeafNode (PARSEOP_INCREMENT);}
{$$ = TrLinkChildren ($<n>3,1,$1);}
@@ -140,27 +140,27 @@ Expression
/* Binary operators: math and logical */
| TermArg PARSEOP_EXP_ADD {$<n>$ = TrCreateLeafNode (PARSEOP_ADD);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_DIVIDE {$<n>$ = TrCreateLeafNode (PARSEOP_DIVIDE);}
- TermArg {$$ = TrLinkChildren ($<n>3,4,$1,$4,TrCreateLeafNode (PARSEOP_ZERO),
- TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,4,$1,$4,TrCreateNullTarget (),
+ TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_MODULO {$<n>$ = TrCreateLeafNode (PARSEOP_MOD);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_MULTIPLY {$<n>$ = TrCreateLeafNode (PARSEOP_MULTIPLY);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_SHIFT_LEFT {$<n>$ = TrCreateLeafNode (PARSEOP_SHIFTLEFT);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_SHIFT_RIGHT {$<n>$ = TrCreateLeafNode (PARSEOP_SHIFTRIGHT);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_SUBTRACT {$<n>$ = TrCreateLeafNode (PARSEOP_SUBTRACT);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_AND {$<n>$ = TrCreateLeafNode (PARSEOP_AND);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_OR {$<n>$ = TrCreateLeafNode (PARSEOP_OR);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_XOR {$<n>$ = TrCreateLeafNode (PARSEOP_XOR);}
- TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateLeafNode (PARSEOP_ZERO));}
+ TermArg {$$ = TrLinkChildren ($<n>3,3,$1,$4,TrCreateNullTarget ());}
| TermArg PARSEOP_EXP_GREATER {$<n>$ = TrCreateLeafNode (PARSEOP_LGREATER);}
TermArg {$$ = TrLinkChildren ($<n>3,2,$1,$4);}
@@ -198,7 +198,7 @@ EqualsTerm
TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));}
| TermArg PARSEOP_EXP_DIV_EQ {$<n>$ = TrCreateLeafNode (PARSEOP_DIVIDE);}
- TermArg {$$ = TrLinkChildren ($<n>3,4,$1,$4,TrCreateLeafNode (PARSEOP_ZERO),
+ TermArg {$$ = TrLinkChildren ($<n>3,4,$1,$4,TrCreateNullTarget (),
TrSetNodeFlags (TrCreateTargetOperand ($1, NULL), NODE_IS_TARGET));}
| TermArg PARSEOP_EXP_MOD_EQ {$<n>$ = TrCreateLeafNode (PARSEOP_MOD);}
@@ -247,11 +247,10 @@ TermList
Term
: Object {}
- | Expression {}
| Type1Opcode {}
| Type2Opcode {}
- | Type2IntegerOpcode {}
- | Type2StringOpcode {}
+ | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);}
+ | Type2StringOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);}
| Type2BufferOpcode {}
| Type2BufferOrStringOpcode {}
| error {$$ = AslDoError(); yyclearin;}
@@ -332,7 +331,7 @@ NameSpaceModifier
| ScopeTerm {}
;
-UserTerm
+MethodInvocationTerm
: NameString '(' {TrUpdateNode (PARSEOP_METHODCALL, $1);}
ArgList ')' {$$ = TrLinkChildNode ($1,$4);}
;
@@ -355,8 +354,7 @@ Removed from TermArg due to reduce/reduce conflicts
*/
TermArg
- : Expression {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);}
- | Type2Opcode {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);}
+ : Type2Opcode {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);}
| DataObject {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);}
| NameString {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);}
| ArgTerm {$$ = TrSetNodeFlags ($1, NODE_IS_TERM_ARG);}
@@ -364,8 +362,8 @@ TermArg
;
Target
- : {$$ = TrSetNodeFlags (TrCreateLeafNode (PARSEOP_ZERO), NODE_IS_TARGET | NODE_COMPILE_TIME_CONST);} /* Placeholder is a ZeroOp object */
- | ',' {$$ = TrSetNodeFlags (TrCreateLeafNode (PARSEOP_ZERO), NODE_IS_TARGET | NODE_COMPILE_TIME_CONST);} /* Placeholder is a ZeroOp object */
+ : {$$ = TrCreateNullTarget ();} /* Placeholder is a ZeroOp object */
+ | ',' {$$ = TrCreateNullTarget ();} /* Placeholder is a ZeroOp object */
| ',' SuperName {$$ = TrSetNodeFlags ($2, NODE_IS_TARGET);}
;
@@ -453,7 +451,7 @@ Type2Opcode
| EqualsTerm {}
| TimerTerm {}
| WaitTerm {}
- | UserTerm {}
+ | MethodInvocationTerm {}
;
/*
@@ -461,7 +459,8 @@ Type2Opcode
*/
Type2IntegerOpcode /* "Type3" opcodes */
- : AddTerm {}
+ : Expression {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);}
+ | AddTerm {}
| AndTerm {}
| DecTerm {}
| DivideTerm {}
@@ -507,7 +506,7 @@ Type2BufferOpcode /* "Type5" Opcodes */
;
Type2BufferOrStringOpcode
- : ConcatTerm {}
+ : ConcatTerm {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST);}
| PrintfTerm {}
| FprintfTerm {}
| MidTerm {}
@@ -543,7 +542,7 @@ Type6Opcode
: RefOfTerm {}
| DerefOfTerm {}
| IndexTerm {}
- | UserTerm {}
+ | MethodInvocationTerm {}
;
IncludeTerm
@@ -1920,7 +1919,7 @@ SuperName
| DebugTerm {}
| Type6Opcode {}
-/* For ObjectType: SuperName except for UserTerm (method invocation) */
+/* For ObjectType: SuperName except for MethodInvocationTerm */
ObjectTypeName
: NameString {}
@@ -1931,7 +1930,7 @@ ObjectTypeName
| DerefOfTerm {}
| IndexTerm {}
-/* | UserTerm {} */ /* Caused reduce/reduce with Type6Opcode->UserTerm */
+/* | MethodInvocationTerm {} */ /* Caused reduce/reduce with Type6Opcode->MethodInvocationTerm */
;
ArgTerm
diff --git a/sys/contrib/dev/acpica/compiler/aslstartup.c b/sys/contrib/dev/acpica/compiler/aslstartup.c
index c8840b2..cbebd0d 100644
--- a/sys/contrib/dev/acpica/compiler/aslstartup.c
+++ b/sys/contrib/dev/acpica/compiler/aslstartup.c
@@ -248,7 +248,7 @@ AslDoDisassembly (
/* This is where the disassembly happens */
- AcpiGbl_DbOpt_disasm = TRUE;
+ AcpiGbl_DbOpt_Disasm = TRUE;
Status = AdAmlDisassemble (AslToFile,
Gbl_Files[ASL_FILE_INPUT].Filename, Gbl_OutputFilenamePrefix,
&Gbl_Files[ASL_FILE_INPUT].Filename);
diff --git a/sys/contrib/dev/acpica/compiler/asltree.c b/sys/contrib/dev/acpica/compiler/asltree.c
index 071231e..68d8072 100644
--- a/sys/contrib/dev/acpica/compiler/asltree.c
+++ b/sys/contrib/dev/acpica/compiler/asltree.c
@@ -55,10 +55,6 @@ static ACPI_PARSE_OBJECT *
TrGetNextNode (
void);
-static char *
-TrGetNodeFlagName (
- UINT32 Flags);
-
/*******************************************************************************
*
@@ -187,7 +183,7 @@ TrUpdateNode (
}
DbgPrint (ASL_PARSE_OUTPUT,
- "\nUpdateNode: Old - %s, New - %s\n\n",
+ "\nUpdateNode: Old - %s, New - %s\n",
UtGetOpName (Op->Asl.ParseOpcode),
UtGetOpName (ParseOpcode));
@@ -261,90 +257,140 @@ TrUpdateNode (
/*******************************************************************************
*
- * FUNCTION: TrGetNodeFlagName
+ * FUNCTION: TrPrintNodeCompileFlags
*
* PARAMETERS: Flags - Flags word to be decoded
*
- * RETURN: Name string. Always returns a valid string pointer.
+ * RETURN: None
*
- * DESCRIPTION: Decode a flags word
+ * DESCRIPTION: Decode a flags word to text. Displays all flags that are set.
*
******************************************************************************/
-static char *
-TrGetNodeFlagName (
+void
+TrPrintNodeCompileFlags (
UINT32 Flags)
{
+ UINT32 i;
+ UINT32 FlagBit = 1;
+ char *FlagName = NULL;
+
- switch (Flags)
+ for (i = 0; i < 32; i++)
{
- case NODE_VISITED:
+ switch (Flags & FlagBit)
+ {
+ case NODE_VISITED:
+
+ FlagName = "NODE_VISITED";
+ break;
+
+ case NODE_AML_PACKAGE:
- return ("NODE_VISITED");
+ FlagName = "NODE_AML_PACKAGE";
+ break;
+
+ case NODE_IS_TARGET:
+
+ FlagName = "NODE_IS_TARGET";
+ break;
+
+ case NODE_IS_RESOURCE_DESC:
- case NODE_AML_PACKAGE:
+ FlagName = "NODE_IS_RESOURCE_DESC";
+ break;
+
+ case NODE_IS_RESOURCE_FIELD:
+
+ FlagName = "NODE_IS_RESOURCE_FIELD";
+ break;
- return ("NODE_AML_PACKAGE");
+ case NODE_HAS_NO_EXIT:
- case NODE_IS_TARGET:
+ FlagName = "NODE_HAS_NO_EXIT";
+ break;
- return ("NODE_IS_TARGET");
+ case NODE_IF_HAS_NO_EXIT:
- case NODE_IS_RESOURCE_DESC:
+ FlagName = "NODE_IF_HAS_NO_EXIT";
+ break;
- return ("NODE_IS_RESOURCE_DESC");
+ case NODE_NAME_INTERNALIZED:
- case NODE_IS_RESOURCE_FIELD:
+ FlagName = "NODE_NAME_INTERNALIZED";
+ break;
- return ("NODE_IS_RESOURCE_FIELD");
+ case NODE_METHOD_NO_RETVAL:
- case NODE_HAS_NO_EXIT:
+ FlagName = "NODE_METHOD_NO_RETVAL";
+ break;
- return ("NODE_HAS_NO_EXIT");
+ case NODE_METHOD_SOME_NO_RETVAL:
- case NODE_IF_HAS_NO_EXIT:
+ FlagName = "NODE_METHOD_SOME_NO_RETVAL";
+ break;
- return ("NODE_IF_HAS_NO_EXIT");
+ case NODE_RESULT_NOT_USED:
- case NODE_NAME_INTERNALIZED:
+ FlagName = "NODE_RESULT_NOT_USED";
+ break;
- return ("NODE_NAME_INTERNALIZED");
+ case NODE_METHOD_TYPED:
- case NODE_METHOD_NO_RETVAL:
+ FlagName = "NODE_METHOD_TYPED";
+ break;
- return ("NODE_METHOD_NO_RETVAL");
+ case NODE_COMPILE_TIME_CONST:
- case NODE_METHOD_SOME_NO_RETVAL:
+ FlagName = "NODE_COMPILE_TIME_CONST";
+ break;
- return ("NODE_METHOD_SOME_NO_RETVAL");
+ case NODE_IS_TERM_ARG:
- case NODE_RESULT_NOT_USED:
+ FlagName = "NODE_IS_TERM_ARG";
+ break;
- return ("NODE_RESULT_NOT_USED");
+ case NODE_WAS_ONES_OP:
- case NODE_METHOD_TYPED:
+ FlagName = "NODE_WAS_ONES_OP";
+ break;
- return ("NODE_METHOD_TYPED");
+ case NODE_IS_NAME_DECLARATION:
- case NODE_COMPILE_TIME_CONST:
+ FlagName = "NODE_IS_NAME_DECLARATION";
+ break;
- return ("NODE_COMPILE_TIME_CONST");
+ case NODE_COMPILER_EMITTED:
- case NODE_IS_TERM_ARG:
+ FlagName = "NODE_COMPILER_EMITTED";
+ break;
- return ("NODE_IS_TERM_ARG");
+ case NODE_IS_DUPLICATE:
- case NODE_WAS_ONES_OP:
+ FlagName = "NODE_IS_DUPLICATE";
+ break;
- return ("NODE_WAS_ONES_OP");
+ case NODE_IS_RESOURCE_DATA:
- case NODE_IS_NAME_DECLARATION:
+ FlagName = "NODE_IS_RESOURCE_DATA";
+ break;
- return ("NODE_IS_NAME_DECLARATION");
+ case NODE_IS_NULL_RETURN:
- default:
+ FlagName = "NODE_IS_NULL_RETURN";
+ break;
- return ("Multiple Flags (or unknown flag) set");
+ default:
+ break;
+ }
+
+ if (FlagName)
+ {
+ DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName);
+ FlagName = NULL;
+ }
+
+ FlagBit <<= 1;
}
}
@@ -368,15 +414,17 @@ TrSetNodeFlags (
UINT32 Flags)
{
- DbgPrint (ASL_PARSE_OUTPUT,
- "\nSetNodeFlags: Op %p, %8.8X %s\n\n", Op, Flags,
- TrGetNodeFlagName (Flags));
-
if (!Op)
{
return (NULL);
}
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags);
+
+ TrPrintNodeCompileFlags (Flags);
+ DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
+
Op->Asl.CompileFlags |= Flags;
return (Op);
}
@@ -588,7 +636,40 @@ TrCreateLeafNode (
DbgPrint (ASL_PARSE_OUTPUT,
"\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n",
- Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode));
+ Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode));
+
+ return (Op);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: TrCreateNullTarget
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Pointer to the new node. Aborts on allocation failure
+ *
+ * DESCRIPTION: Create a "null" target node. This is defined by the ACPI
+ * specification to be a zero AML opcode, and indicates that
+ * no target has been specified for the parent operation
+ *
+ ******************************************************************************/
+
+ACPI_PARSE_OBJECT *
+TrCreateNullTarget (
+ void)
+{
+ ACPI_PARSE_OBJECT *Op;
+
+
+ Op = TrAllocateNode (PARSEOP_ZERO);
+ Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST);
+
+ DbgPrint (ASL_PARSE_OUTPUT,
+ "\nCreateNullTarget Ln/Col %u/%u NewNode %p Op %s\n",
+ Op->Asl.LineNumber, Op->Asl.Column, Op,
+ UtGetOpName (Op->Asl.ParseOpcode));
return (Op);
}
@@ -620,7 +701,6 @@ TrCreateConstantLeafNode (
time_t CurrentTime;
char *StaticTimeString;
char *TimeString;
- char *Path;
char *Filename;
@@ -647,7 +727,7 @@ TrCreateConstantLeafNode (
/* Get the simple filename from the full path */
- FlSplitInputPathname (Op->Asl.Filename, &Path, &Filename);
+ FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename);
Op->Asl.Value.String = Filename;
break;
@@ -672,7 +752,7 @@ TrCreateConstantLeafNode (
}
DbgPrint (ASL_PARSE_OUTPUT,
- "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p Op %s Value %8.8X%8.8X ",
+ "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p Op %s Value %8.8X%8.8X \n",
Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode),
ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
return (Op);
@@ -813,7 +893,8 @@ TrCreateValuedLeafNode (
case PARSEOP_INTEGER:
- DbgPrint (ASL_PARSE_OUTPUT, "INTEGER");
+ DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X",
+ ACPI_FORMAT_UINT64 (Value));
break;
default:
@@ -948,7 +1029,7 @@ TrCreateNode (
}
va_end(ap);
- DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
+ DbgPrint (ASL_PARSE_OUTPUT, "\n");
return (Op);
}
@@ -1104,7 +1185,7 @@ TrLinkPeerNode (
DbgPrint (ASL_PARSE_OUTPUT,
- "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n\n",
+ "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n",
Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
@@ -1130,7 +1211,7 @@ TrLinkPeerNode (
if (Op1 == Op2)
{
DbgPrint (ASL_DEBUG_OUTPUT,
- "\n\n************* Internal error, linking node to itself %p\n\n\n",
+ "\n************* Internal error, linking node to itself %p\n",
Op1);
AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
"Linking node to itself");
@@ -1214,7 +1295,7 @@ TrLinkPeerNodes (
}
va_end (ap);
- DbgPrint (ASL_PARSE_OUTPUT,"\n\n");
+ DbgPrint (ASL_PARSE_OUTPUT,"\n");
return (Start);
}
@@ -1241,7 +1322,7 @@ TrLinkChildNode (
DbgPrint (ASL_PARSE_OUTPUT,
- "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n\n",
+ "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n",
Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
diff --git a/sys/contrib/dev/acpica/compiler/asltypes.y b/sys/contrib/dev/acpica/compiler/asltypes.y
index 3177d1d..650b856 100644
--- a/sys/contrib/dev/acpica/compiler/asltypes.y
+++ b/sys/contrib/dev/acpica/compiler/asltypes.y
@@ -74,7 +74,7 @@ NoEcho('
%type <n> Term
%type <n> TermArg
%type <n> TermList
-%type <n> UserTerm
+%type <n> MethodInvocationTerm
/* Type4Opcode is obsolete */
diff --git a/sys/contrib/dev/acpica/compiler/aslutils.c b/sys/contrib/dev/acpica/compiler/aslutils.c
index 7258daa..37d394b 100644
--- a/sys/contrib/dev/acpica/compiler/aslutils.c
+++ b/sys/contrib/dev/acpica/compiler/aslutils.c
@@ -503,8 +503,13 @@ UtDisplaySummary (
if (Gbl_FileType != ASL_INPUT_TYPE_ASCII_DATA)
{
- FlPrintFile (FileId,
- ", %u Optimizations", Gbl_ExceptionCount[ASL_OPTIMIZATION]);
+ FlPrintFile (FileId, ", %u Optimizations",
+ Gbl_ExceptionCount[ASL_OPTIMIZATION]);
+
+ if (TotalFolds)
+ {
+ FlPrintFile (FileId, ", %u Constants Folded", TotalFolds);
+ }
}
FlPrintFile (FileId, "\n");
diff --git a/sys/contrib/dev/acpica/compiler/aslwalks.c b/sys/contrib/dev/acpica/compiler/aslwalks.c
index c378f2d..c59895d 100644
--- a/sys/contrib/dev/acpica/compiler/aslwalks.c
+++ b/sys/contrib/dev/acpica/compiler/aslwalks.c
@@ -252,6 +252,13 @@ AnOperandTypecheckWalkEnd (
}
return (AE_OK);
+ case AML_EXTERNAL_OP:
+ /*
+ * Not really a "runtime" opcode since it used by disassembler only.
+ * The parser will find any issues with the operands.
+ */
+ return (AE_OK);
+
default:
break;
@@ -388,9 +395,6 @@ AnOperandTypecheckWalkEnd (
break;
case PARSEOP_DEBUG:
-
- break;
-
case PARSEOP_REFOF:
case PARSEOP_INDEX:
default:
diff --git a/sys/contrib/dev/acpica/compiler/dtcompile.c b/sys/contrib/dev/acpica/compiler/dtcompile.c
index e94a222..74bfc33 100644
--- a/sys/contrib/dev/acpica/compiler/dtcompile.c
+++ b/sys/contrib/dev/acpica/compiler/dtcompile.c
@@ -102,13 +102,18 @@ DtDoCompile (
/* Preprocessor */
- Event = UtBeginEvent ("Preprocess input file");
- PrDoPreprocess ();
- UtEndEvent (Event);
-
- if (Gbl_PreprocessOnly)
+ if (Gbl_PreprocessFlag)
{
- return (AE_OK);
+ /* Preprocessor */
+
+ Event = UtBeginEvent ("Preprocess input file");
+ PrDoPreprocess ();
+ UtEndEvent (Event);
+
+ if (Gbl_PreprocessOnly)
+ {
+ return (AE_OK);
+ }
}
/*
diff --git a/sys/contrib/dev/acpica/compiler/dtcompiler.h b/sys/contrib/dev/acpica/compiler/dtcompiler.h
index 307df3f..3a0b763 100644
--- a/sys/contrib/dev/acpica/compiler/dtcompiler.h
+++ b/sys/contrib/dev/acpica/compiler/dtcompiler.h
@@ -85,15 +85,16 @@
*/
typedef struct dt_field
{
- char *Name; /* Field name (from name : value) */
- char *Value; /* Field value (from name : value) */
- struct dt_field *Next; /* Next field */
- struct dt_field *NextLabel; /* If field is a label, next label */
- UINT32 Line; /* Line number for this field */
- UINT32 ByteOffset; /* Offset in source file for field */
- UINT32 NameColumn; /* Start column for field name */
- UINT32 Column; /* Start column for field value */
- UINT32 TableOffset;/* Binary offset within ACPI table */
+ char *Name; /* Field name (from name : value) */
+ char *Value; /* Field value (from name : value) */
+ UINT32 StringLength;/* Length of Value */
+ struct dt_field *Next; /* Next field */
+ struct dt_field *NextLabel; /* If field is a label, next label */
+ UINT32 Line; /* Line number for this field */
+ UINT32 ByteOffset; /* Offset in source file for field */
+ UINT32 NameColumn; /* Start column for field name */
+ UINT32 Column; /* Start column for field value */
+ UINT32 TableOffset; /* Binary offset within ACPI table */
UINT8 Flags;
} DT_FIELD;
@@ -557,6 +558,7 @@ extern const unsigned char TemplateMcfg[];
extern const unsigned char TemplateMchi[];
extern const unsigned char TemplateMpst[];
extern const unsigned char TemplateMsct[];
+extern const unsigned char TemplateMsdm[];
extern const unsigned char TemplateMtmr[];
extern const unsigned char TemplatePcct[];
extern const unsigned char TemplatePmtt[];
diff --git a/sys/contrib/dev/acpica/compiler/dtio.c b/sys/contrib/dev/acpica/compiler/dtio.c
index e840fc9..bebd927 100644
--- a/sys/contrib/dev/acpica/compiler/dtio.c
+++ b/sys/contrib/dev/acpica/compiler/dtio.c
@@ -375,6 +375,7 @@ DtParseLine (
Field->ByteOffset = Offset;
Field->NameColumn = NameColumn;
Field->Column = Column;
+ Field->StringLength = Length;
DtLinkField (Field);
}
@@ -414,6 +415,7 @@ DtGetNextLine (
int c;
+ ACPI_MEMSET (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize);
for (i = 0; ;)
{
/*
@@ -939,11 +941,11 @@ DtDumpFieldList (
DbgPrint (ASL_DEBUG_OUTPUT, "\nField List:\n"
"LineNo ByteOff NameCol Column TableOff "
- "Flags %32s : %s\n\n", "Name", "Value");
+ "Flags %32s : %s\n\n", "Name", "Value");
while (Field)
{
DbgPrint (ASL_DEBUG_OUTPUT,
- "%.08X %.08X %.08X %.08X %.08X %.08X %32s : %s\n",
+ "%.08X %.08X %.08X %.08X %.08X %2.2X %32s : %s\n",
Field->Line, Field->ByteOffset, Field->NameColumn,
Field->Column, Field->TableOffset, Field->Flags,
Field->Name, Field->Value);
diff --git a/sys/contrib/dev/acpica/compiler/dttable.c b/sys/contrib/dev/acpica/compiler/dttable.c
index bc0cbd2..3fe02e8 100644
--- a/sys/contrib/dev/acpica/compiler/dttable.c
+++ b/sys/contrib/dev/acpica/compiler/dttable.c
@@ -2240,15 +2240,11 @@ DtCompileSlic (
DT_SUBTABLE *Subtable;
DT_SUBTABLE *ParentTable;
DT_FIELD **PFieldList = (DT_FIELD **) List;
- DT_FIELD *SubtableStart;
- ACPI_SLIC_HEADER *SlicHeader;
- ACPI_DMTABLE_INFO *InfoTable;
while (*PFieldList)
{
- SubtableStart = *PFieldList;
- Status = DtCompileTable (PFieldList, AcpiDmTableInfoSlicHdr,
+ Status = DtCompileTable (PFieldList, AcpiDmTableInfoSlic,
&Subtable, TRUE);
if (ACPI_FAILURE (Status))
{
@@ -2258,35 +2254,6 @@ DtCompileSlic (
ParentTable = DtPeekSubtable ();
DtInsertSubtable (ParentTable, Subtable);
DtPushSubtable (Subtable);
-
- SlicHeader = ACPI_CAST_PTR (ACPI_SLIC_HEADER, Subtable->Buffer);
-
- switch (SlicHeader->Type)
- {
- case ACPI_SLIC_TYPE_PUBLIC_KEY:
-
- InfoTable = AcpiDmTableInfoSlic0;
- break;
-
- case ACPI_SLIC_TYPE_WINDOWS_MARKER:
-
- InfoTable = AcpiDmTableInfoSlic1;
- break;
-
- default:
-
- DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "SLIC");
- return (AE_ERROR);
- }
-
- Status = DtCompileTable (PFieldList, InfoTable, &Subtable, TRUE);
- if (ACPI_FAILURE (Status))
- {
- return (Status);
- }
-
- ParentTable = DtPeekSubtable ();
- DtInsertSubtable (ParentTable, Subtable);
DtPopSubtable ();
}
diff --git a/sys/contrib/dev/acpica/compiler/dttemplate.h b/sys/contrib/dev/acpica/compiler/dttemplate.h
index 0398d69..39be761 100644
--- a/sys/contrib/dev/acpica/compiler/dttemplate.h
+++ b/sys/contrib/dev/acpica/compiler/dttemplate.h
@@ -662,6 +662,23 @@ const unsigned char TemplateMchi[] =
0x00,0x00,0x00,0x00,0x00 /* 00000040 "....." */
};
+const unsigned char TemplateMsdm[] =
+{
+ 0x4D,0x53,0x44,0x4D,0x64,0x00,0x00,0x00, /* 00000000 "MSDMd..." */
+ 0x01,0x34,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 ".4Intel." */
+ 0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65, /* 00000010 "Template" */
+ 0x03,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
+ 0x04,0x02,0x15,0x20,0x00,0x00,0x00,0x00, /* 00000020 "... ...." */
+ 0x0A,0x10,0x16,0x17,0x18,0x19,0x1A,0x1B, /* 00000028 "........" */
+ 0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23, /* 00000030 ".... !"#" */
+ 0x24,0x25,0x26,0x27,0x10,0x0A,0x15,0x16, /* 00000038 "$%&'...." */
+ 0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E, /* 00000040 "........" */
+ 0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26, /* 00000048 ". !"#$%&" */
+ 0x16,0x15,0x0A,0x10,0x16,0x17,0x18,0x19, /* 00000050 "........" */
+ 0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21, /* 00000058 "...... !" */
+ 0x22,0x23,0x24,0x25 /* 00000060 ""#$%" */
+};
+
const unsigned char TemplateMpst[] =
{
0x4D,0x50,0x53,0x54,0xB6,0x00,0x00,0x00, /* 00000000 "MPST...." */
diff --git a/sys/contrib/dev/acpica/compiler/dtutils.c b/sys/contrib/dev/acpica/compiler/dtutils.c
index 3635f13..7d3c2c8 100644
--- a/sys/contrib/dev/acpica/compiler/dtutils.c
+++ b/sys/contrib/dev/acpica/compiler/dtutils.c
@@ -364,6 +364,7 @@ DtGetFieldType (
break;
case ACPI_DMT_BUFFER:
+ case ACPI_DMT_RAW_BUFFER:
case ACPI_DMT_BUF7:
case ACPI_DMT_BUF10:
case ACPI_DMT_BUF16:
@@ -531,7 +532,6 @@ DtGetFieldLength (
case ACPI_DMT_UINT32:
case ACPI_DMT_NAME4:
- case ACPI_DMT_SLIC:
case ACPI_DMT_SIG:
case ACPI_DMT_LPIT:
@@ -588,6 +588,7 @@ DtGetFieldLength (
break;
case ACPI_DMT_BUFFER:
+ case ACPI_DMT_RAW_BUFFER:
Value = DtGetFieldValue (Field);
if (Value)
diff --git a/sys/contrib/dev/acpica/components/debugger/dbmethod.c b/sys/contrib/dev/acpica/components/debugger/dbmethod.c
index 8f2e4db..5224854 100644
--- a/sys/contrib/dev/acpica/components/debugger/dbmethod.c
+++ b/sys/contrib/dev/acpica/components/debugger/dbmethod.c
@@ -396,11 +396,11 @@ AcpiDbDisassembleMethod (
/* Now we can disassemble the method */
- AcpiGbl_DbOpt_verbose = FALSE;
+ AcpiGbl_DbOpt_Verbose = FALSE;
#ifdef ACPI_DISASSEMBLER
AcpiDmDisassemble (NULL, Op, 0);
#endif
- AcpiGbl_DbOpt_verbose = TRUE;
+ AcpiGbl_DbOpt_Verbose = TRUE;
AcpiPsDeleteParseTree (Op);
diff --git a/sys/contrib/dev/acpica/components/debugger/dbxface.c b/sys/contrib/dev/acpica/components/debugger/dbxface.c
index 8d2e0a8..d72ee5e 100644
--- a/sys/contrib/dev/acpica/components/debugger/dbxface.c
+++ b/sys/contrib/dev/acpica/components/debugger/dbxface.c
@@ -424,13 +424,11 @@ AcpiDbInitialize (
AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
AcpiGbl_DbOutputFlags = ACPI_DB_CONSOLE_OUTPUT;
- AcpiGbl_DbOpt_tables = FALSE;
- AcpiGbl_DbOpt_disasm = FALSE;
- AcpiGbl_DbOpt_stats = FALSE;
+ AcpiGbl_DbOpt_Disasm = FALSE;
#ifdef ACPI_DISASSEMBLER
- AcpiGbl_DbOpt_verbose = TRUE;
+ AcpiGbl_DbOpt_Verbose = TRUE;
#endif
- AcpiGbl_DbOpt_ini_methods = TRUE;
+ AcpiGbl_DbOpt_NoIniMethods = FALSE;
AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE);
if (!AcpiGbl_DbBuffer)
@@ -479,10 +477,9 @@ AcpiDbInitialize (
}
#ifdef ACPI_DISASSEMBLER
- if (!AcpiGbl_DbOpt_verbose)
+ if (!AcpiGbl_DbOpt_Verbose)
{
- AcpiGbl_DbOpt_disasm = TRUE;
- AcpiGbl_DbOpt_stats = FALSE;
+ AcpiGbl_DbOpt_Disasm = TRUE;
}
#endif
diff --git a/sys/contrib/dev/acpica/components/disassembler/dmopcode.c b/sys/contrib/dev/acpica/components/disassembler/dmopcode.c
index f2ef535..b10d433 100644
--- a/sys/contrib/dev/acpica/components/disassembler/dmopcode.c
+++ b/sys/contrib/dev/acpica/components/disassembler/dmopcode.c
@@ -852,18 +852,6 @@ AcpiDmDisassembleOneOp (
}
break;
- case AML_INT_STATICSTRING_OP:
-
- if (Op->Common.Value.String)
- {
- AcpiOsPrintf ("%s", Op->Common.Value.String);
- }
- else
- {
- AcpiOsPrintf ("\"<NULL STATIC STRING PTR>\"");
- }
- break;
-
case AML_INT_NAMEPATH_OP:
AcpiDmNamestring (Op->Common.Value.Name);
diff --git a/sys/contrib/dev/acpica/components/disassembler/dmwalk.c b/sys/contrib/dev/acpica/components/disassembler/dmwalk.c
index 43a1139..2dbaa84 100644
--- a/sys/contrib/dev/acpica/components/disassembler/dmwalk.c
+++ b/sys/contrib/dev/acpica/components/disassembler/dmwalk.c
@@ -562,7 +562,7 @@ AcpiDmDescendingOp (
if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
{
- if (AcpiGbl_DbOpt_verbose)
+ if (AcpiGbl_DbOpt_Verbose)
{
(void) AcpiPsDisplayObjectPathname (NULL, Op);
}
diff --git a/sys/contrib/dev/acpica/components/dispatcher/dsopcode.c b/sys/contrib/dev/acpica/components/dispatcher/dsopcode.c
index 86fe26c..157e4ce 100644
--- a/sys/contrib/dev/acpica/components/dispatcher/dsopcode.c
+++ b/sys/contrib/dev/acpica/components/dispatcher/dsopcode.c
@@ -477,7 +477,7 @@ AcpiDsEvalRegionOperands (
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
ObjDesc,
- ACPI_FORMAT_NATIVE_UINT (ObjDesc->Region.Address),
+ ACPI_FORMAT_UINT64 (ObjDesc->Region.Address),
ObjDesc->Region.Length));
/* Now the address and length are valid for this opregion */
@@ -579,12 +579,12 @@ AcpiDsEvalTableRegionOperands (
return_ACPI_STATUS (AE_NOT_EXIST);
}
- ObjDesc->Region.Address = (ACPI_PHYSICAL_ADDRESS) ACPI_TO_INTEGER (Table);
+ ObjDesc->Region.Address = ACPI_PTR_TO_PHYSADDR (Table);
ObjDesc->Region.Length = Table->Length;
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
ObjDesc,
- ACPI_FORMAT_NATIVE_UINT (ObjDesc->Region.Address),
+ ACPI_FORMAT_UINT64 (ObjDesc->Region.Address),
ObjDesc->Region.Length));
/* Now the address and length are valid for this opregion */
diff --git a/sys/contrib/dev/acpica/components/dispatcher/dsutils.c b/sys/contrib/dev/acpica/components/dispatcher/dsutils.c
index f4f0f33..a115b2e 100644
--- a/sys/contrib/dev/acpica/components/dispatcher/dsutils.c
+++ b/sys/contrib/dev/acpica/components/dispatcher/dsutils.c
@@ -599,6 +599,15 @@ AcpiDsCreateOperand (
ACPI_OPERAND_OBJECT, AcpiGbl_RootNode);
Status = AE_OK;
}
+ else if (ParentOp->Common.AmlOpcode == AML_EXTERNAL_OP)
+ {
+ /* TBD: May only be temporary */
+
+ ObjDesc = AcpiUtCreateStringObject ((ACPI_SIZE) NameLength);
+
+ ACPI_STRNCPY (ObjDesc->String.Pointer, NameString, NameLength);
+ Status = AE_OK;
+ }
else
{
/*
diff --git a/sys/contrib/dev/acpica/components/events/evregion.c b/sys/contrib/dev/acpica/components/events/evregion.c
index 19ceb26..54171b6 100644
--- a/sys/contrib/dev/acpica/components/events/evregion.c
+++ b/sys/contrib/dev/acpica/components/events/evregion.c
@@ -288,7 +288,7 @@ AcpiEvAddressSpaceDispatch (
ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&RegionObj->Region.Handler->AddressSpace, Handler,
- ACPI_FORMAT_NATIVE_UINT (Address),
+ ACPI_FORMAT_UINT64 (Address),
AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
if (!(HandlerDesc->AddressSpace.HandlerFlags &
diff --git a/sys/contrib/dev/acpica/components/events/evxfevnt.c b/sys/contrib/dev/acpica/components/events/evxfevnt.c
index 08507b3..5515922 100644
--- a/sys/contrib/dev/acpica/components/events/evxfevnt.c
+++ b/sys/contrib/dev/acpica/components/events/evxfevnt.c
@@ -401,7 +401,8 @@ AcpiGetEventStatus (
if (InByte)
{
- LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;
+ LocalEventStatus |=
+ (ACPI_EVENT_FLAG_ENABLED | ACPI_EVENT_FLAG_ENABLE_SET);
}
/* Fixed event currently active? */
@@ -415,7 +416,7 @@ AcpiGetEventStatus (
if (InByte)
{
- LocalEventStatus |= ACPI_EVENT_FLAG_SET;
+ LocalEventStatus |= ACPI_EVENT_FLAG_STATUS_SET;
}
(*EventStatus) = LocalEventStatus;
diff --git a/sys/contrib/dev/acpica/components/executer/exdump.c b/sys/contrib/dev/acpica/components/executer/exdump.c
index 9986022..622dc14 100644
--- a/sys/contrib/dev/acpica/components/executer/exdump.c
+++ b/sys/contrib/dev/acpica/components/executer/exdump.c
@@ -784,7 +784,7 @@ AcpiExDumpOperand (
else
{
AcpiOsPrintf (" base %8.8X%8.8X Length %X\n",
- ACPI_FORMAT_NATIVE_UINT (ObjDesc->Region.Address),
+ ACPI_FORMAT_UINT64 (ObjDesc->Region.Address),
ObjDesc->Region.Length);
}
break;
diff --git a/sys/contrib/dev/acpica/components/executer/exfldio.c b/sys/contrib/dev/acpica/components/executer/exfldio.c
index c4d4019..2908da4 100644
--- a/sys/contrib/dev/acpica/components/executer/exfldio.c
+++ b/sys/contrib/dev/acpica/components/executer/exfldio.c
@@ -289,13 +289,13 @@ AcpiExAccessRegion (
}
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
- " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
+ " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
RgnDesc->Region.SpaceId,
ObjDesc->CommonField.AccessByteWidth,
ObjDesc->CommonField.BaseByteOffset,
FieldDatumByteOffset,
- ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset))));
+ ACPI_FORMAT_UINT64 (RgnDesc->Region.Address + RegionOffset)));
/* Invoke the appropriate AddressSpace/OpRegion handler */
diff --git a/sys/contrib/dev/acpica/components/executer/exoparg3.c b/sys/contrib/dev/acpica/components/executer/exoparg3.c
index 6d0fdd1..da873c3 100644
--- a/sys/contrib/dev/acpica/components/executer/exoparg3.c
+++ b/sys/contrib/dev/acpica/components/executer/exoparg3.c
@@ -125,7 +125,18 @@ AcpiExOpcode_3A_0T_0R (
/* Might return while OS is shutting down, just continue */
ACPI_FREE (Fatal);
- break;
+ goto Cleanup;
+
+ case AML_EXTERNAL_OP:
+ /*
+ * If the interpreter sees this opcode, just ignore it. The External
+ * op is intended for use by disassemblers in order to properly
+ * disassemble control method invocations. The opcode or group of
+ * opcodes should be surrounded by an "if (0)" clause to ensure that
+ * AML interpreters never see the opcode.
+ */
+ Status = AE_OK;
+ goto Cleanup;
default:
diff --git a/sys/contrib/dev/acpica/components/executer/exregion.c b/sys/contrib/dev/acpica/components/executer/exregion.c
index 9deef50..59b4612 100644
--- a/sys/contrib/dev/acpica/components/executer/exregion.c
+++ b/sys/contrib/dev/acpica/components/executer/exregion.c
@@ -175,8 +175,8 @@ AcpiExSystemMemorySpaceHandler (
* one page, which is similar to the original code that used a 4k
* maximum window.
*/
- PageBoundaryMapLength =
- ACPI_ROUND_UP (Address, ACPI_DEFAULT_PAGE_SIZE) - Address;
+ PageBoundaryMapLength = (ACPI_SIZE)
+ (ACPI_ROUND_UP (Address, ACPI_DEFAULT_PAGE_SIZE) - Address);
if (PageBoundaryMapLength == 0)
{
PageBoundaryMapLength = ACPI_DEFAULT_PAGE_SIZE;
@@ -189,13 +189,12 @@ AcpiExSystemMemorySpaceHandler (
/* Create a new mapping starting at the address given */
- MemInfo->MappedLogicalAddress = AcpiOsMapMemory (
- (ACPI_PHYSICAL_ADDRESS) Address, MapLength);
+ MemInfo->MappedLogicalAddress = AcpiOsMapMemory (Address, MapLength);
if (!MemInfo->MappedLogicalAddress)
{
ACPI_ERROR ((AE_INFO,
"Could not map memory at 0x%8.8X%8.8X, size %u",
- ACPI_FORMAT_NATIVE_UINT (Address), (UINT32) MapLength));
+ ACPI_FORMAT_UINT64 (Address), (UINT32) MapLength));
MemInfo->MappedLength = 0;
return_ACPI_STATUS (AE_NO_MEMORY);
}
@@ -215,7 +214,7 @@ AcpiExSystemMemorySpaceHandler (
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
- BitWidth, Function, ACPI_FORMAT_NATIVE_UINT (Address)));
+ BitWidth, Function, ACPI_FORMAT_UINT64 (Address)));
/*
* Perform the memory read or write
@@ -338,7 +337,7 @@ AcpiExSystemIoSpaceHandler (
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
- BitWidth, Function, ACPI_FORMAT_NATIVE_UINT (Address)));
+ BitWidth, Function, ACPI_FORMAT_UINT64 (Address)));
/* Decode the function parameter */
diff --git a/sys/contrib/dev/acpica/components/hardware/hwgpe.c b/sys/contrib/dev/acpica/components/hardware/hwgpe.c
index 9cc511e..093ba80 100644
--- a/sys/contrib/dev/acpica/components/hardware/hwgpe.c
+++ b/sys/contrib/dev/acpica/components/hardware/hwgpe.c
@@ -280,6 +280,19 @@ AcpiHwGetGpeStatus (
LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED;
}
+ /* GPE currently enabled (enable bit == 1)? */
+
+ Status = AcpiHwRead (&InByte, &GpeRegisterInfo->EnableAddress);
+ if (ACPI_FAILURE (Status))
+ {
+ return (Status);
+ }
+
+ if (RegisterBit & InByte)
+ {
+ LocalEventStatus |= ACPI_EVENT_FLAG_ENABLE_SET;
+ }
+
/* GPE currently active (status bit == 1)? */
Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress);
@@ -290,7 +303,7 @@ AcpiHwGetGpeStatus (
if (RegisterBit & InByte)
{
- LocalEventStatus |= ACPI_EVENT_FLAG_SET;
+ LocalEventStatus |= ACPI_EVENT_FLAG_STATUS_SET;
}
/* Set return value */
diff --git a/sys/contrib/dev/acpica/components/hardware/hwvalid.c b/sys/contrib/dev/acpica/components/hardware/hwvalid.c
index ade53ad..3b6b567 100644
--- a/sys/contrib/dev/acpica/components/hardware/hwvalid.c
+++ b/sys/contrib/dev/acpica/components/hardware/hwvalid.c
@@ -155,8 +155,8 @@ AcpiHwValidateIoRequest (
ByteWidth = ACPI_DIV_8 (BitWidth);
LastAddress = Address + ByteWidth - 1;
- ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Address %p LastAddress %p Length %X",
- ACPI_CAST_PTR (void, Address), ACPI_CAST_PTR (void, LastAddress),
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Address %8.8X%8.8X LastAddress %8.8X%8.8X Length %X",
+ ACPI_FORMAT_UINT64 (Address), ACPI_FORMAT_UINT64 (LastAddress),
ByteWidth));
/* Maximum 16-bit address in I/O space */
@@ -164,8 +164,8 @@ AcpiHwValidateIoRequest (
if (LastAddress > ACPI_UINT16_MAX)
{
ACPI_ERROR ((AE_INFO,
- "Illegal I/O port address/length above 64K: %p/0x%X",
- ACPI_CAST_PTR (void, Address), ByteWidth));
+ "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X",
+ ACPI_FORMAT_UINT64 (Address), ByteWidth));
return_ACPI_STATUS (AE_LIMIT);
}
@@ -196,8 +196,8 @@ AcpiHwValidateIoRequest (
if (AcpiGbl_OsiData >= PortInfo->OsiDependency)
{
ACPI_DEBUG_PRINT ((ACPI_DB_IO,
- "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)",
- ACPI_CAST_PTR (void, Address), ByteWidth, PortInfo->Name,
+ "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)",
+ ACPI_FORMAT_UINT64 (Address), ByteWidth, PortInfo->Name,
PortInfo->Start, PortInfo->End));
return_ACPI_STATUS (AE_AML_ILLEGAL_ADDRESS);
diff --git a/sys/contrib/dev/acpica/components/namespace/nsdump.c b/sys/contrib/dev/acpica/components/namespace/nsdump.c
index 6140397..77fb279 100644
--- a/sys/contrib/dev/acpica/components/namespace/nsdump.c
+++ b/sys/contrib/dev/acpica/components/namespace/nsdump.c
@@ -313,9 +313,9 @@ AcpiNsDumpOneObject (
{
case ACPI_TYPE_PROCESSOR:
- AcpiOsPrintf ("ID %02X Len %02X Addr %p\n",
+ AcpiOsPrintf ("ID %02X Len %02X Addr %8.8X%8.8X\n",
ObjDesc->Processor.ProcId, ObjDesc->Processor.Length,
- ACPI_CAST_PTR (void, ObjDesc->Processor.Address));
+ ACPI_FORMAT_UINT64 (ObjDesc->Processor.Address));
break;
case ACPI_TYPE_DEVICE:
@@ -388,7 +388,7 @@ AcpiNsDumpOneObject (
if (ObjDesc->Region.Flags & AOPOBJ_DATA_VALID)
{
AcpiOsPrintf (" Addr %8.8X%8.8X Len %.4X\n",
- ACPI_FORMAT_NATIVE_UINT (ObjDesc->Region.Address),
+ ACPI_FORMAT_UINT64 (ObjDesc->Region.Address),
ObjDesc->Region.Length);
}
else
diff --git a/sys/contrib/dev/acpica/components/parser/psopcode.c b/sys/contrib/dev/acpica/components/parser/psopcode.c
index c219778..e351e4c 100644
--- a/sys/contrib/dev/acpica/components/parser/psopcode.c
+++ b/sys/contrib/dev/acpica/components/parser/psopcode.c
@@ -333,7 +333,11 @@ const ACPI_OPCODE_INFO AcpiGbl_AmlOpInfo[AML_NUM_OPCODES] =
/* ACPI 5.0 opcodes */
/* 7F */ ACPI_OP ("-ConnectField-", ARGP_CONNECTFIELD_OP, ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS),
-/* 80 */ ACPI_OP ("-ExtAccessField-", ARGP_CONNECTFIELD_OP, ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0)
+/* 80 */ ACPI_OP ("-ExtAccessField-", ARGP_CONNECTFIELD_OP, ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+
+/* ACPI 6.0 opcodes */
+
+/* 81 */ ACPI_OP ("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE,/* ? */ AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R)
/*! [End] no source code translation !*/
};
diff --git a/sys/contrib/dev/acpica/components/parser/psopinfo.c b/sys/contrib/dev/acpica/components/parser/psopinfo.c
index e44bf7b..872f58a 100644
--- a/sys/contrib/dev/acpica/components/parser/psopinfo.c
+++ b/sys/contrib/dev/acpica/components/parser/psopinfo.c
@@ -226,7 +226,7 @@ const UINT8 AcpiGbl_ShortOpIndex[256] =
/* 8 9 A B C D E F */
/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK,
/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK,
-/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK,
+/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, 0x81, _UNK, _UNK,
/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
diff --git a/sys/contrib/dev/acpica/components/resources/rsaddr.c b/sys/contrib/dev/acpica/components/resources/rsaddr.c
index f05c4fc..decd9a6 100644
--- a/sys/contrib/dev/acpica/components/resources/rsaddr.c
+++ b/sys/contrib/dev/acpica/components/resources/rsaddr.c
@@ -77,7 +77,7 @@ ACPI_RSCONVERT_INFO AcpiRsConvertAddress16[5] =
* Address Translation Offset
* Address Length
*/
- {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.Address16.Granularity),
+ {ACPI_RSC_MOVE16, ACPI_RS_OFFSET (Data.Address16.Address.Granularity),
AML_OFFSET (Address16.Granularity),
5},
@@ -117,7 +117,7 @@ ACPI_RSCONVERT_INFO AcpiRsConvertAddress32[5] =
* Address Translation Offset
* Address Length
*/
- {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.Address32.Granularity),
+ {ACPI_RSC_MOVE32, ACPI_RS_OFFSET (Data.Address32.Address.Granularity),
AML_OFFSET (Address32.Granularity),
5},
@@ -157,7 +157,7 @@ ACPI_RSCONVERT_INFO AcpiRsConvertAddress64[5] =
* Address Translation Offset
* Address Length
*/
- {ACPI_RSC_MOVE64, ACPI_RS_OFFSET (Data.Address64.Granularity),
+ {ACPI_RSC_MOVE64, ACPI_RS_OFFSET (Data.Address64.Address.Granularity),
AML_OFFSET (Address64.Granularity),
5},
@@ -203,7 +203,7 @@ ACPI_RSCONVERT_INFO AcpiRsConvertExtAddress64[5] =
* Address Length
* Type-Specific Attribute
*/
- {ACPI_RSC_MOVE64, ACPI_RS_OFFSET (Data.ExtAddress64.Granularity),
+ {ACPI_RSC_MOVE64, ACPI_RS_OFFSET (Data.ExtAddress64.Address.Granularity),
AML_OFFSET (ExtAddress64.Granularity),
6}
};
diff --git a/sys/contrib/dev/acpica/components/resources/rsdump.c b/sys/contrib/dev/acpica/components/resources/rsdump.c
index ddae6e0..9c1a7ec 100644
--- a/sys/contrib/dev/acpica/components/resources/rsdump.c
+++ b/sys/contrib/dev/acpica/components/resources/rsdump.c
@@ -1,6 +1,6 @@
/*******************************************************************************
*
- * Module Name: rsdump - Functions to display the resource structures.
+ * Module Name: rsdump - AML debugger support for resource structures.
*
******************************************************************************/
@@ -48,8 +48,10 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME ("rsdump")
-
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
+/*
+ * All functions in this module are used by the AML Debugger only
+ */
+#if defined(ACPI_DEBUGGER)
/* Local prototypes */
@@ -89,8 +91,8 @@ AcpiRsDumpByteList (
static void
AcpiRsDumpWordList (
- UINT16 Length,
- UINT16 *Data);
+ UINT16 Length,
+ UINT16 *Data);
static void
AcpiRsDumpDwordList (
@@ -99,8 +101,8 @@ AcpiRsDumpDwordList (
static void
AcpiRsDumpShortByteList (
- UINT8 Length,
- UINT8 *Data);
+ UINT8 Length,
+ UINT8 *Data);
static void
AcpiRsDumpResourceSource (
@@ -113,7 +115,133 @@ AcpiRsDumpAddressCommon (
static void
AcpiRsDumpDescriptor (
void *Resource,
- ACPI_RSDUMP_INFO *Table);
+ ACPI_RSDUMP_INFO *Table);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: AcpiRsDumpResourceList
+ *
+ * PARAMETERS: ResourceList - Pointer to a resource descriptor list
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Dispatches the structure to the correct dump routine.
+ *
+ ******************************************************************************/
+
+void
+AcpiRsDumpResourceList (
+ ACPI_RESOURCE *ResourceList)
+{
+ UINT32 Count = 0;
+ UINT32 Type;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_RESOURCES, _COMPONENT))
+ {
+ return;
+ }
+
+ /* Walk list and dump all resource descriptors (END_TAG terminates) */
+
+ do
+ {
+ AcpiOsPrintf ("\n[%02X] ", Count);
+ Count++;
+
+ /* Validate Type before dispatch */
+
+ Type = ResourceList->Type;
+ if (Type > ACPI_RESOURCE_TYPE_MAX)
+ {
+ AcpiOsPrintf (
+ "Invalid descriptor type (%X) in resource list\n",
+ ResourceList->Type);
+ return;
+ }
+
+ /* Sanity check the length. It must not be zero, or we loop forever */
+
+ if (!ResourceList->Length)
+ {
+ AcpiOsPrintf (
+ "Invalid zero length descriptor in resource list\n");
+ return;
+ }
+
+ /* Dump the resource descriptor */
+
+ if (Type == ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ {
+ AcpiRsDumpDescriptor (&ResourceList->Data,
+ AcpiGbl_DumpSerialBusDispatch[
+ ResourceList->Data.CommonSerialBus.Type]);
+ }
+ else
+ {
+ AcpiRsDumpDescriptor (&ResourceList->Data,
+ AcpiGbl_DumpResourceDispatch[Type]);
+ }
+
+ /* Point to the next resource structure */
+
+ ResourceList = ACPI_NEXT_RESOURCE (ResourceList);
+
+ /* Exit when END_TAG descriptor is reached */
+
+ } while (Type != ACPI_RESOURCE_TYPE_END_TAG);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: AcpiRsDumpIrqList
+ *
+ * PARAMETERS: RouteTable - Pointer to the routing table to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print IRQ routing table
+ *
+ ******************************************************************************/
+
+void
+AcpiRsDumpIrqList (
+ UINT8 *RouteTable)
+{
+ ACPI_PCI_ROUTING_TABLE *PrtElement;
+ UINT8 Count;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_RESOURCES, _COMPONENT))
+ {
+ return;
+ }
+
+ PrtElement = ACPI_CAST_PTR (ACPI_PCI_ROUTING_TABLE, RouteTable);
+
+ /* Dump all table elements, Exit on zero length element */
+
+ for (Count = 0; PrtElement->Length; Count++)
+ {
+ AcpiOsPrintf ("\n[%02X] PCI IRQ Routing Table Package\n", Count);
+ AcpiRsDumpDescriptor (PrtElement, AcpiRsDumpPrt);
+
+ PrtElement = ACPI_ADD_PTR (ACPI_PCI_ROUTING_TABLE,
+ PrtElement, PrtElement->Length);
+ }
+}
/*******************************************************************************
@@ -288,14 +416,16 @@ AcpiRsDumpDescriptor (
/*
* Common flags for all Address resources
*/
- AcpiRsDumpAddressCommon (ACPI_CAST_PTR (ACPI_RESOURCE_DATA, Target));
+ AcpiRsDumpAddressCommon (ACPI_CAST_PTR (
+ ACPI_RESOURCE_DATA, Target));
break;
case ACPI_RSD_SOURCE:
/*
* Optional ResourceSource for Address resources
*/
- AcpiRsDumpResourceSource (ACPI_CAST_PTR (ACPI_RESOURCE_SOURCE, Target));
+ AcpiRsDumpResourceSource (ACPI_CAST_PTR (
+ ACPI_RESOURCE_SOURCE, Target));
break;
default:
@@ -399,131 +529,6 @@ AcpiRsDumpAddressCommon (
/*******************************************************************************
*
- * FUNCTION: AcpiRsDumpResourceList
- *
- * PARAMETERS: ResourceList - Pointer to a resource descriptor list
- *
- * RETURN: None
- *
- * DESCRIPTION: Dispatches the structure to the correct dump routine.
- *
- ******************************************************************************/
-
-void
-AcpiRsDumpResourceList (
- ACPI_RESOURCE *ResourceList)
-{
- UINT32 Count = 0;
- UINT32 Type;
-
-
- ACPI_FUNCTION_ENTRY ();
-
-
- /* Check if debug output enabled */
-
- if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_RESOURCES, _COMPONENT))
- {
- return;
- }
-
- /* Walk list and dump all resource descriptors (END_TAG terminates) */
-
- do
- {
- AcpiOsPrintf ("\n[%02X] ", Count);
- Count++;
-
- /* Validate Type before dispatch */
-
- Type = ResourceList->Type;
- if (Type > ACPI_RESOURCE_TYPE_MAX)
- {
- AcpiOsPrintf (
- "Invalid descriptor type (%X) in resource list\n",
- ResourceList->Type);
- return;
- }
-
- /* Sanity check the length. It must not be zero, or we loop forever */
-
- if (!ResourceList->Length)
- {
- AcpiOsPrintf (
- "Invalid zero length descriptor in resource list\n");
- return;
- }
-
- /* Dump the resource descriptor */
-
- if (Type == ACPI_RESOURCE_TYPE_SERIAL_BUS)
- {
- AcpiRsDumpDescriptor (&ResourceList->Data,
- AcpiGbl_DumpSerialBusDispatch[ResourceList->Data.CommonSerialBus.Type]);
- }
- else
- {
- AcpiRsDumpDescriptor (&ResourceList->Data,
- AcpiGbl_DumpResourceDispatch[Type]);
- }
-
- /* Point to the next resource structure */
-
- ResourceList = ACPI_NEXT_RESOURCE (ResourceList);
-
- /* Exit when END_TAG descriptor is reached */
-
- } while (Type != ACPI_RESOURCE_TYPE_END_TAG);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION: AcpiRsDumpIrqList
- *
- * PARAMETERS: RouteTable - Pointer to the routing table to dump.
- *
- * RETURN: None
- *
- * DESCRIPTION: Print IRQ routing table
- *
- ******************************************************************************/
-
-void
-AcpiRsDumpIrqList (
- UINT8 *RouteTable)
-{
- ACPI_PCI_ROUTING_TABLE *PrtElement;
- UINT8 Count;
-
-
- ACPI_FUNCTION_ENTRY ();
-
-
- /* Check if debug output enabled */
-
- if (!ACPI_IS_DEBUG_ENABLED (ACPI_LV_RESOURCES, _COMPONENT))
- {
- return;
- }
-
- PrtElement = ACPI_CAST_PTR (ACPI_PCI_ROUTING_TABLE, RouteTable);
-
- /* Dump all table elements, Exit on zero length element */
-
- for (Count = 0; PrtElement->Length; Count++)
- {
- AcpiOsPrintf ("\n[%02X] PCI IRQ Routing Table Package\n", Count);
- AcpiRsDumpDescriptor (PrtElement, AcpiRsDumpPrt);
-
- PrtElement = ACPI_ADD_PTR (ACPI_PCI_ROUTING_TABLE,
- PrtElement, PrtElement->Length);
- }
-}
-
-
-/*******************************************************************************
- *
* FUNCTION: AcpiRsOut*
*
* PARAMETERS: Title - Name of the resource field
@@ -620,8 +625,8 @@ AcpiRsDumpByteList (
static void
AcpiRsDumpShortByteList (
- UINT8 Length,
- UINT8 *Data)
+ UINT8 Length,
+ UINT8 *Data)
{
UINT8 i;
diff --git a/sys/contrib/dev/acpica/components/resources/rsdumpinfo.c b/sys/contrib/dev/acpica/components/resources/rsdumpinfo.c
index aab597a..dfa1a84 100644
--- a/sys/contrib/dev/acpica/components/resources/rsdumpinfo.c
+++ b/sys/contrib/dev/acpica/components/resources/rsdumpinfo.c
@@ -161,11 +161,12 @@ ACPI_RSDUMP_INFO AcpiRsDumpAddress16[8] =
{
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpAddress16), "16-Bit WORD Address Space",NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Granularity), "Granularity", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Minimum), "Address Minimum", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Maximum), "Address Maximum", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.TranslationOffset), "Translation Offset", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.AddressLength), "Address Length", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.Granularity), "Granularity", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.Minimum), "Address Minimum", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.Maximum), "Address Maximum", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.TranslationOffset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (Address16.Address.AddressLength), "Address Length", NULL},
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (Address16.ResourceSource), NULL, NULL}
};
@@ -173,11 +174,12 @@ ACPI_RSDUMP_INFO AcpiRsDumpAddress32[8] =
{
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpAddress32), "32-Bit DWORD Address Space", NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Granularity), "Granularity", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Minimum), "Address Minimum", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Maximum), "Address Maximum", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.TranslationOffset), "Translation Offset", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.AddressLength), "Address Length", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.Granularity), "Granularity", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.Minimum), "Address Minimum", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.Maximum), "Address Maximum", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.TranslationOffset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET (Address32.Address.AddressLength), "Address Length", NULL},
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (Address32.ResourceSource), NULL, NULL}
};
@@ -185,11 +187,12 @@ ACPI_RSDUMP_INFO AcpiRsDumpAddress64[8] =
{
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpAddress64), "64-Bit QWORD Address Space", NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Granularity), "Granularity", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Minimum), "Address Minimum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Maximum), "Address Maximum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.TranslationOffset), "Translation Offset", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.AddressLength), "Address Length", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.Granularity), "Granularity", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.Minimum), "Address Minimum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.Maximum), "Address Maximum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.TranslationOffset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (Address64.Address.AddressLength), "Address Length", NULL},
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (Address64.ResourceSource), NULL, NULL}
};
@@ -197,11 +200,13 @@ ACPI_RSDUMP_INFO AcpiRsDumpExtAddress64[8] =
{
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE (AcpiRsDumpExtAddress64), "64-Bit Extended Address Space", NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Granularity), "Granularity", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Minimum), "Address Minimum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Maximum), "Address Maximum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.TranslationOffset), "Translation Offset", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.AddressLength), "Address Length", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.Granularity), "Granularity", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.Minimum), "Address Minimum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.Maximum), "Address Maximum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.TranslationOffset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.Address.AddressLength),
+ "Address Length", NULL},
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET (ExtAddress64.TypeSpecific), "Type-Specific Attribute", NULL}
};
diff --git a/sys/contrib/dev/acpica/components/resources/rsxface.c b/sys/contrib/dev/acpica/components/resources/rsxface.c
index 2fe3e6f..a477f20 100644
--- a/sys/contrib/dev/acpica/components/resources/rsxface.c
+++ b/sys/contrib/dev/acpica/components/resources/rsxface.c
@@ -61,11 +61,11 @@
ACPI_COPY_FIELD(Out, In, MinAddressFixed); \
ACPI_COPY_FIELD(Out, In, MaxAddressFixed); \
ACPI_COPY_FIELD(Out, In, Info); \
- ACPI_COPY_FIELD(Out, In, Granularity); \
- ACPI_COPY_FIELD(Out, In, Minimum); \
- ACPI_COPY_FIELD(Out, In, Maximum); \
- ACPI_COPY_FIELD(Out, In, TranslationOffset); \
- ACPI_COPY_FIELD(Out, In, AddressLength); \
+ ACPI_COPY_FIELD(Out, In, Address.Granularity); \
+ ACPI_COPY_FIELD(Out, In, Address.Minimum); \
+ ACPI_COPY_FIELD(Out, In, Address.Maximum); \
+ ACPI_COPY_FIELD(Out, In, Address.TranslationOffset); \
+ ACPI_COPY_FIELD(Out, In, Address.AddressLength); \
ACPI_COPY_FIELD(Out, In, ResourceSource);
diff --git a/sys/contrib/dev/acpica/components/tables/tbdata.c b/sys/contrib/dev/acpica/components/tables/tbdata.c
index 4ff62dd..70bac2c 100644
--- a/sys/contrib/dev/acpica/components/tables/tbdata.c
+++ b/sys/contrib/dev/acpica/components/tables/tbdata.c
@@ -121,7 +121,8 @@ AcpiTbAcquireTable (
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
- Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, TableDesc->Address);
+ Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER,
+ ACPI_PHYSADDR_TO_PTR (TableDesc->Address));
break;
default:
@@ -227,7 +228,8 @@ AcpiTbAcquireTempTable (
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
- TableHeader = ACPI_CAST_PTR (ACPI_TABLE_HEADER, Address);
+ TableHeader = ACPI_CAST_PTR (ACPI_TABLE_HEADER,
+ ACPI_PHYSADDR_TO_PTR (Address));
if (!TableHeader)
{
return (AE_NO_MEMORY);
@@ -437,11 +439,11 @@ AcpiTbVerifyTempTable (
if (ACPI_FAILURE (Status))
{
ACPI_EXCEPTION ((AE_INFO, AE_NO_MEMORY,
- "%4.4s " ACPI_PRINTF_UINT
+ "%4.4s 0x%8.8X%8.8X"
" Attempted table install failed",
AcpiUtValidAcpiName (TableDesc->Signature.Ascii) ?
TableDesc->Signature.Ascii : "????",
- ACPI_FORMAT_TO_UINT (TableDesc->Address)));
+ ACPI_FORMAT_UINT64 (TableDesc->Address)));
goto InvalidateAndExit;
}
}
@@ -529,21 +531,24 @@ AcpiTbResizeRootTableList (
/*******************************************************************************
*
- * FUNCTION: AcpiTbGetNextRootIndex
+ * FUNCTION: AcpiTbGetNextTableDescriptor
*
* PARAMETERS: TableIndex - Where table index is returned
+ * TableDesc - Where table descriptor is returned
*
- * RETURN: Status and table index.
+ * RETURN: Status and table index/descriptor.
*
* DESCRIPTION: Allocate a new ACPI table entry to the global table list
*
******************************************************************************/
ACPI_STATUS
-AcpiTbGetNextRootIndex (
- UINT32 *TableIndex)
+AcpiTbGetNextTableDescriptor (
+ UINT32 *TableIndex,
+ ACPI_TABLE_DESC **TableDesc)
{
ACPI_STATUS Status;
+ UINT32 i;
/* Ensure that there is room for the table in the Root Table List */
@@ -558,8 +563,18 @@ AcpiTbGetNextRootIndex (
}
}
- *TableIndex = AcpiGbl_RootTableList.CurrentTableCount;
+ i = AcpiGbl_RootTableList.CurrentTableCount;
AcpiGbl_RootTableList.CurrentTableCount++;
+
+ if (TableIndex)
+ {
+ *TableIndex = i;
+ }
+ if (TableDesc)
+ {
+ *TableDesc = &AcpiGbl_RootTableList.Tables[i];
+ }
+
return (AE_OK);
}
diff --git a/sys/contrib/dev/acpica/components/tables/tbinstal.c b/sys/contrib/dev/acpica/components/tables/tbinstal.c
index 2fe219d..d77d2c8 100644
--- a/sys/contrib/dev/acpica/components/tables/tbinstal.c
+++ b/sys/contrib/dev/acpica/components/tables/tbinstal.c
@@ -201,8 +201,8 @@ AcpiTbInstallFixedTable (
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL);
if (ACPI_FAILURE (Status))
{
- ACPI_ERROR ((AE_INFO, "Could not acquire table length at %p",
- ACPI_CAST_PTR (void, Address)));
+ ACPI_ERROR ((AE_INFO, "Could not acquire table length at %8.8X%8.8X",
+ ACPI_FORMAT_UINT64 (Address)));
return_ACPI_STATUS (Status);
}
@@ -268,8 +268,8 @@ AcpiTbInstallStandardTable (
Status = AcpiTbAcquireTempTable (&NewTableDesc, Address, Flags);
if (ACPI_FAILURE (Status))
{
- ACPI_ERROR ((AE_INFO, "Could not acquire table length at %p",
- ACPI_CAST_PTR (void, Address)));
+ ACPI_ERROR ((AE_INFO, "Could not acquire table length at %8.8X%8.8X",
+ ACPI_FORMAT_UINT64 (Address)));
return_ACPI_STATUS (Status);
}
@@ -281,8 +281,8 @@ AcpiTbInstallStandardTable (
AcpiGbl_DisableSsdtTableInstall &&
ACPI_COMPARE_NAME (&NewTableDesc.Signature, ACPI_SIG_SSDT))
{
- ACPI_INFO ((AE_INFO, "Ignoring installation of %4.4s at %p",
- NewTableDesc.Signature.Ascii, ACPI_CAST_PTR (void, Address)));
+ ACPI_INFO ((AE_INFO, "Ignoring installation of %4.4s at %8.8X%8.8X",
+ NewTableDesc.Signature.Ascii, ACPI_FORMAT_UINT64 (Address)));
goto ReleaseAndExit;
}
@@ -368,7 +368,6 @@ AcpiTbInstallStandardTable (
*/
AcpiTbUninstallTable (&NewTableDesc);
*TableIndex = i;
- (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
return_ACPI_STATUS (AE_OK);
}
}
@@ -376,7 +375,7 @@ AcpiTbInstallStandardTable (
/* Add the table to the global root table list */
- Status = AcpiTbGetNextRootIndex (&i);
+ Status = AcpiTbGetNextTableDescriptor (&i, NULL);
if (ACPI_FAILURE (Status))
{
goto ReleaseAndExit;
@@ -459,11 +458,11 @@ FinishOverride:
return;
}
- ACPI_INFO ((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
- " %s table override, new table: " ACPI_PRINTF_UINT,
+ ACPI_INFO ((AE_INFO, "%4.4s 0x%8.8X%8.8X"
+ " %s table override, new table: 0x%8.8X%8.8X",
OldTableDesc->Signature.Ascii,
- ACPI_FORMAT_TO_UINT (OldTableDesc->Address),
- OverrideType, ACPI_FORMAT_TO_UINT (NewTableDesc.Address)));
+ ACPI_FORMAT_UINT64 (OldTableDesc->Address),
+ OverrideType, ACPI_FORMAT_UINT64 (NewTableDesc.Address)));
/* We can now uninstall the original table */
@@ -485,49 +484,6 @@ FinishOverride:
/*******************************************************************************
*
- * FUNCTION: AcpiTbStoreTable
- *
- * PARAMETERS: Address - Table address
- * Table - Table header
- * Length - Table length
- * Flags - Install flags
- * TableIndex - Where the table index is returned
- *
- * RETURN: Status and table index.
- *
- * DESCRIPTION: Add an ACPI table to the global table list
- *
- ******************************************************************************/
-
-ACPI_STATUS
-AcpiTbStoreTable (
- ACPI_PHYSICAL_ADDRESS Address,
- ACPI_TABLE_HEADER *Table,
- UINT32 Length,
- UINT8 Flags,
- UINT32 *TableIndex)
-{
- ACPI_STATUS Status;
- ACPI_TABLE_DESC *TableDesc;
-
-
- Status = AcpiTbGetNextRootIndex (TableIndex);
- if (ACPI_FAILURE (Status))
- {
- return (Status);
- }
-
- /* Initialize added table */
-
- TableDesc = &AcpiGbl_RootTableList.Tables[*TableIndex];
- AcpiTbInitTableDescriptor (TableDesc, Address, Flags, Table);
- TableDesc->Pointer = Table;
- return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
* FUNCTION: AcpiTbUninstallTable
*
* PARAMETERS: TableDesc - Table descriptor
@@ -558,7 +514,7 @@ AcpiTbUninstallTable (
if ((TableDesc->Flags & ACPI_TABLE_ORIGIN_MASK) ==
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL)
{
- ACPI_FREE (ACPI_CAST_PTR (void, TableDesc->Address));
+ ACPI_FREE (ACPI_PHYSADDR_TO_PTR (TableDesc->Address));
}
TableDesc->Address = ACPI_PTR_TO_PHYSADDR (NULL);
diff --git a/sys/contrib/dev/acpica/components/tables/tbprint.c b/sys/contrib/dev/acpica/components/tables/tbprint.c
index 8be1a9f..f0ea090 100644
--- a/sys/contrib/dev/acpica/components/tables/tbprint.c
+++ b/sys/contrib/dev/acpica/components/tables/tbprint.c
@@ -144,18 +144,12 @@ AcpiTbPrintTableHeader (
ACPI_TABLE_HEADER LocalHeader;
- /*
- * The reason that we use ACPI_PRINTF_UINT and ACPI_FORMAT_TO_UINT is to
- * support both 32-bit and 64-bit hosts/addresses in a consistent manner.
- * The %p specifier does not emit uniform output on all hosts. On some,
- * leading zeros are not supported.
- */
if (ACPI_COMPARE_NAME (Header->Signature, ACPI_SIG_FACS))
{
/* FACS only has signature and length fields */
- ACPI_INFO ((AE_INFO, "%-4.4s " ACPI_PRINTF_UINT " %06X",
- Header->Signature, ACPI_FORMAT_TO_UINT (Address),
+ ACPI_INFO ((AE_INFO, "%-4.4s 0x%8.8X%8.8X %06X",
+ Header->Signature, ACPI_FORMAT_UINT64 (Address),
Header->Length));
}
else if (ACPI_VALIDATE_RSDP_SIG (Header->Signature))
@@ -166,8 +160,8 @@ AcpiTbPrintTableHeader (
ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->OemId, ACPI_OEM_ID_SIZE);
AcpiTbFixString (LocalHeader.OemId, ACPI_OEM_ID_SIZE);
- ACPI_INFO ((AE_INFO, "RSDP " ACPI_PRINTF_UINT " %06X (v%.2d %-6.6s)",
- ACPI_FORMAT_TO_UINT (Address),
+ ACPI_INFO ((AE_INFO, "RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)",
+ ACPI_FORMAT_UINT64 (Address),
(ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision > 0) ?
ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Length : 20,
ACPI_CAST_PTR (ACPI_TABLE_RSDP, Header)->Revision,
@@ -180,9 +174,9 @@ AcpiTbPrintTableHeader (
AcpiTbCleanupTableHeader (&LocalHeader, Header);
ACPI_INFO ((AE_INFO,
- "%-4.4s " ACPI_PRINTF_UINT
+ "%-4.4s 0x%8.8X%8.8X"
" %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)",
- LocalHeader.Signature, ACPI_FORMAT_TO_UINT (Address),
+ LocalHeader.Signature, ACPI_FORMAT_UINT64 (Address),
LocalHeader.Length, LocalHeader.Revision, LocalHeader.OemId,
LocalHeader.OemTableId, LocalHeader.OemRevision,
LocalHeader.AslCompilerId, LocalHeader.AslCompilerRevision));
diff --git a/sys/contrib/dev/acpica/components/tables/tbxfroot.c b/sys/contrib/dev/acpica/components/tables/tbxfroot.c
index 26babdb..e3b93d3 100644
--- a/sys/contrib/dev/acpica/components/tables/tbxfroot.c
+++ b/sys/contrib/dev/acpica/components/tables/tbxfroot.c
@@ -158,7 +158,7 @@ AcpiTbValidateRsdp (
ACPI_STATUS
AcpiFindRootPointer (
- ACPI_SIZE *TableAddress)
+ ACPI_PHYSICAL_ADDRESS *TableAddress)
{
UINT8 *TablePtr;
UINT8 *MemRover;
@@ -218,7 +218,7 @@ AcpiFindRootPointer (
PhysicalAddress += (UINT32) ACPI_PTR_DIFF (MemRover, TablePtr);
- *TableAddress = PhysicalAddress;
+ *TableAddress = (ACPI_PHYSICAL_ADDRESS) PhysicalAddress;
return_ACPI_STATUS (AE_OK);
}
}
@@ -249,7 +249,7 @@ AcpiFindRootPointer (
PhysicalAddress = (UINT32)
(ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (MemRover, TablePtr));
- *TableAddress = PhysicalAddress;
+ *TableAddress = (ACPI_PHYSICAL_ADDRESS) PhysicalAddress;
return_ACPI_STATUS (AE_OK);
}
diff --git a/sys/contrib/dev/acpica/components/utilities/utaddress.c b/sys/contrib/dev/acpica/components/utilities/utaddress.c
index 02d6110..5ed2b4d 100644
--- a/sys/contrib/dev/acpica/components/utilities/utaddress.c
+++ b/sys/contrib/dev/acpica/components/utilities/utaddress.c
@@ -117,10 +117,10 @@ AcpiUtAddAddressRange (
AcpiGbl_AddressRangeList[SpaceId] = RangeInfo;
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
- "\nAdded [%4.4s] address range: 0x%p-0x%p\n",
+ "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
AcpiUtGetNodeName (RangeInfo->RegionNode),
- ACPI_CAST_PTR (void, Address),
- ACPI_CAST_PTR (void, RangeInfo->EndAddress)));
+ ACPI_FORMAT_UINT64 (Address),
+ ACPI_FORMAT_UINT64 (RangeInfo->EndAddress)));
(void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
return_ACPI_STATUS (AE_OK);
@@ -179,10 +179,10 @@ AcpiUtRemoveAddressRange (
}
ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
- "\nRemoved [%4.4s] address range: 0x%p-0x%p\n",
+ "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
AcpiUtGetNodeName (RangeInfo->RegionNode),
- ACPI_CAST_PTR (void, RangeInfo->StartAddress),
- ACPI_CAST_PTR (void, RangeInfo->EndAddress)));
+ ACPI_FORMAT_UINT64 (RangeInfo->StartAddress),
+ ACPI_FORMAT_UINT64 (RangeInfo->EndAddress)));
ACPI_FREE (RangeInfo);
return_VOID;
@@ -266,12 +266,12 @@ AcpiUtCheckAddressRange (
Pathname = AcpiNsGetExternalPathname (RangeInfo->RegionNode);
ACPI_WARNING ((AE_INFO,
- "%s range 0x%p-0x%p conflicts with OpRegion 0x%p-0x%p (%s)",
+ "%s range 0x%8.8X%8.8X-0x%8.8X%8.8X conflicts with OpRegion 0x%8.8X%8.8X-0x%8.8X%8.8X (%s)",
AcpiUtGetRegionName (SpaceId),
- ACPI_CAST_PTR (void, Address),
- ACPI_CAST_PTR (void, EndAddress),
- ACPI_CAST_PTR (void, RangeInfo->StartAddress),
- ACPI_CAST_PTR (void, RangeInfo->EndAddress),
+ ACPI_FORMAT_UINT64 (Address),
+ ACPI_FORMAT_UINT64 (EndAddress),
+ ACPI_FORMAT_UINT64 (RangeInfo->StartAddress),
+ ACPI_FORMAT_UINT64 (RangeInfo->EndAddress),
Pathname));
ACPI_FREE (Pathname);
}
diff --git a/sys/contrib/dev/acpica/components/utilities/utbuffer.c b/sys/contrib/dev/acpica/components/utilities/utbuffer.c
index 862ac6b..cc41419 100644
--- a/sys/contrib/dev/acpica/components/utilities/utbuffer.c
+++ b/sys/contrib/dev/acpica/components/utilities/utbuffer.c
@@ -158,6 +158,15 @@ AcpiUtDumpBuffer (
return;
}
+ /*
+ * Add comment characters so rest of line is ignored when
+ * compiled
+ */
+ if (j == 0)
+ {
+ AcpiOsPrintf ("// ");
+ }
+
BufChar = Buffer[(ACPI_SIZE) i + j];
if (ACPI_IS_PRINT (BufChar))
{
diff --git a/sys/contrib/dev/acpica/components/utilities/utglobal.c b/sys/contrib/dev/acpica/components/utilities/utglobal.c
index 1dfd3e1..e027aa1 100644
--- a/sys/contrib/dev/acpica/components/utilities/utglobal.c
+++ b/sys/contrib/dev/acpica/components/utilities/utglobal.c
@@ -111,12 +111,19 @@ const ACPI_PREDEFINED_NAMES AcpiGbl_PreDefinedNames[] =
{"_SB_", ACPI_TYPE_DEVICE, NULL},
{"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL},
{"_TZ_", ACPI_TYPE_DEVICE, NULL},
- {"_REV", ACPI_TYPE_INTEGER, (char *) ACPI_CA_SUPPORT_LEVEL},
+ /*
+ * March, 2015:
+ * The _REV object is in the process of being deprecated, because
+ * other ACPI implementations permanently return 2. Thus, it
+ * has little or no value. Return 2 for compatibility with
+ * other ACPI implementations.
+ */
+ {"_REV", ACPI_TYPE_INTEGER, ACPI_CAST_PTR (char, 2)},
{"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
- {"_GL_", ACPI_TYPE_MUTEX, (char *) 1},
+ {"_GL_", ACPI_TYPE_MUTEX, ACPI_CAST_PTR (char, 1)},
#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
- {"_OSI", ACPI_TYPE_METHOD, (char *) 1},
+ {"_OSI", ACPI_TYPE_METHOD, ACPI_CAST_PTR (char, 1)},
#endif
/* Table terminator */
diff --git a/sys/contrib/dev/acpica/components/utilities/utmisc.c b/sys/contrib/dev/acpica/components/utilities/utmisc.c
index d5d81ca..f3d2222 100644
--- a/sys/contrib/dev/acpica/components/utilities/utmisc.c
+++ b/sys/contrib/dev/acpica/components/utilities/utmisc.c
@@ -84,6 +84,7 @@ AcpiUtIsPciRootBridge (
}
+#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP)
/*******************************************************************************
*
* FUNCTION: AcpiUtIsAmlTable
@@ -114,6 +115,7 @@ AcpiUtIsAmlTable (
return (FALSE);
}
+#endif
/*******************************************************************************
diff --git a/sys/contrib/dev/acpica/components/utilities/utosi.c b/sys/contrib/dev/acpica/components/utilities/utosi.c
index 6b225ca..bf6ba86 100644
--- a/sys/contrib/dev/acpica/components/utilities/utosi.c
+++ b/sys/contrib/dev/acpica/components/utilities/utosi.c
@@ -105,6 +105,7 @@ static ACPI_INTERFACE_INFO AcpiDefaultSupportedInterfaces[] =
{"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */
{"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */
{"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
+ {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */
/* Feature Group Strings */
diff --git a/sys/contrib/dev/acpica/components/utilities/utprint.c b/sys/contrib/dev/acpica/components/utilities/utprint.c
index d870ad4..62aecf0 100644
--- a/sys/contrib/dev/acpica/components/utilities/utprint.c
+++ b/sys/contrib/dev/acpica/components/utilities/utprint.c
@@ -442,11 +442,11 @@ AcpiUtVsnprintf (
const char *Format,
va_list Args)
{
- UINT8 Base = 10;
- UINT8 Type = 0;
- INT32 Width = -1;
- INT32 Precision = -1;
- char Qualifier = 0;
+ UINT8 Base;
+ UINT8 Type;
+ INT32 Width;
+ INT32 Precision;
+ char Qualifier;
UINT64 Number;
char *Pos;
char *End;
@@ -468,6 +468,9 @@ AcpiUtVsnprintf (
continue;
}
+ Type = 0;
+ Base = 10;
+
/* Process sign */
do
diff --git a/sys/contrib/dev/acpica/components/utilities/utstate.c b/sys/contrib/dev/acpica/components/utilities/utstate.c
index d90d694..3396319 100644
--- a/sys/contrib/dev/acpica/components/utilities/utstate.c
+++ b/sys/contrib/dev/acpica/components/utilities/utstate.c
@@ -50,44 +50,6 @@
/*******************************************************************************
*
- * FUNCTION: AcpiUtCreatePkgStateAndPush
- *
- * PARAMETERS: Object - Object to be added to the new state
- * Action - Increment/Decrement
- * StateList - List the state will be added to
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create a new state and push it
- *
- ******************************************************************************/
-
-ACPI_STATUS
-AcpiUtCreatePkgStateAndPush (
- void *InternalObject,
- void *ExternalObject,
- UINT16 Index,
- ACPI_GENERIC_STATE **StateList)
-{
- ACPI_GENERIC_STATE *State;
-
-
- ACPI_FUNCTION_ENTRY ();
-
-
- State = AcpiUtCreatePkgState (InternalObject, ExternalObject, Index);
- if (!State)
- {
- return (AE_NO_MEMORY);
- }
-
- AcpiUtPushGenericState (StateList, State);
- return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
* FUNCTION: AcpiUtPushGenericState
*
* PARAMETERS: ListHead - Head of the state stack
diff --git a/sys/contrib/dev/acpica/components/utilities/utuuid.c b/sys/contrib/dev/acpica/components/utilities/utuuid.c
index 8b3cb99..435c6c3 100644
--- a/sys/contrib/dev/acpica/components/utilities/utuuid.c
+++ b/sys/contrib/dev/acpica/components/utilities/utuuid.c
@@ -48,6 +48,7 @@
ACPI_MODULE_NAME ("utuuid")
+#if (defined ACPI_ASL_COMPILER || defined ACPI_DISASSEMBLER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP)
/*
* UUID support functions.
*
@@ -99,3 +100,4 @@ AcpiUtConvertStringToUuid (
AcpiUtAsciiCharToHex (InString[AcpiGbl_MapToUuidOffset[i] + 1]);
}
}
+#endif
diff --git a/sys/contrib/dev/acpica/include/acdebug.h b/sys/contrib/dev/acpica/include/acdebug.h
index f630575..23464d6 100644
--- a/sys/contrib/dev/acpica/include/acdebug.h
+++ b/sys/contrib/dev/acpica/include/acdebug.h
@@ -77,7 +77,7 @@ typedef struct acpi_db_execute_walk
#define PARAM_LIST(pl) pl
-#define DBTEST_OUTPUT_LEVEL(lvl) if (AcpiGbl_DbOpt_verbose)
+#define DBTEST_OUTPUT_LEVEL(lvl) if (AcpiGbl_DbOpt_Verbose)
#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\
AcpiOsPrintf PARAM_LIST(fp);}
diff --git a/sys/contrib/dev/acpica/include/acdisasm.h b/sys/contrib/dev/acpica/include/acdisasm.h
index 34cf1f7..f4487e5 100644
--- a/sys/contrib/dev/acpica/include/acdisasm.h
+++ b/sys/contrib/dev/acpica/include/acdisasm.h
@@ -129,6 +129,7 @@ typedef enum
/* Types used only for the Data Table Compiler */
ACPI_DMT_BUFFER,
+ ACPI_DMT_RAW_BUFFER, /* Large, multiple line buffer */
ACPI_DMT_DEVICE_PATH,
ACPI_DMT_LABEL,
ACPI_DMT_PCI_PATH,
@@ -351,9 +352,7 @@ extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3ptHdr[];
extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt0[];
extern ACPI_DMTABLE_INFO AcpiDmTableInfoS3pt1[];
extern ACPI_DMTABLE_INFO AcpiDmTableInfoSbst[];
-extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlicHdr[];
-extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlic0[];
-extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlic1[];
+extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlic[];
extern ACPI_DMTABLE_INFO AcpiDmTableInfoSlit[];
extern ACPI_DMTABLE_INFO AcpiDmTableInfoSpcr[];
extern ACPI_DMTABLE_INFO AcpiDmTableInfoSpmi[];
@@ -422,6 +421,15 @@ AcpiDmLineHeader2 (
* dmtbdump
*/
void
+AcpiDmDumpBuffer (
+ void *Table,
+ UINT32 BufferOffset,
+ UINT32 Length,
+ UINT32 AbsoluteOffset,
+ char *Header,
+ BOOLEAN MultiLine);
+
+void
AcpiDmDumpAsf (
ACPI_TABLE_HEADER *Table);
@@ -996,6 +1004,10 @@ AcpiDmCloseOperator (
*/
void
AdDisassemblerHeader (
- char *Filename);
+ char *Filename,
+ UINT8 TableType);
+
+#define ACPI_IS_AML_TABLE 0
+#define ACPI_IS_DATA_TABLE 1
#endif /* __ACDISASM_H__ */
diff --git a/sys/contrib/dev/acpica/include/acglobal.h b/sys/contrib/dev/acpica/include/acglobal.h
index 9b6e936..ab2fc26 100644
--- a/sys/contrib/dev/acpica/include/acglobal.h
+++ b/sys/contrib/dev/acpica/include/acglobal.h
@@ -310,9 +310,10 @@ ACPI_INIT_GLOBAL (UINT8, AcpiGbl_DbOutputFlags, ACPI_DB_CONSOLE_O
ACPI_INIT_GLOBAL (UINT8, AcpiGbl_NoResourceDisassembly, FALSE);
ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_IgnoreNoopOperator, FALSE);
ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_CstyleDisassembly, TRUE);
+ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_ForceAmlDisassembly, FALSE);
-ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_disasm);
-ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_verbose);
+ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_Disasm);
+ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_Verbose);
ACPI_GLOBAL (BOOLEAN, AcpiGbl_NumExternalMethods);
ACPI_GLOBAL (UINT32, AcpiGbl_ResolvedExternalMethods);
ACPI_GLOBAL (ACPI_EXTERNAL_LIST *, AcpiGbl_ExternalList);
@@ -325,9 +326,7 @@ ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_DbTerminateThreads, FALSE);
ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_AbortMethod, FALSE);
ACPI_INIT_GLOBAL (BOOLEAN, AcpiGbl_MethodExecuting, FALSE);
-ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_tables);
-ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_stats);
-ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_ini_methods);
+ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_NoIniMethods);
ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOpt_NoRegionSupport);
ACPI_GLOBAL (BOOLEAN, AcpiGbl_DbOutputToFile);
ACPI_GLOBAL (char *, AcpiGbl_DbBuffer);
diff --git a/sys/contrib/dev/acpica/include/aclocal.h b/sys/contrib/dev/acpica/include/aclocal.h
index 5f9b0f3..9729930 100644
--- a/sys/contrib/dev/acpica/include/aclocal.h
+++ b/sys/contrib/dev/acpica/include/aclocal.h
@@ -54,7 +54,7 @@ typedef UINT32 ACPI_MUTEX_HANDLE;
/* Total number of aml opcodes defined */
-#define AML_NUM_OPCODES 0x81
+#define AML_NUM_OPCODES 0x82
/* Forward declarations */
diff --git a/sys/contrib/dev/acpica/include/acmacros.h b/sys/contrib/dev/acpica/include/acmacros.h
index b23d175..35d53f6 100644
--- a/sys/contrib/dev/acpica/include/acmacros.h
+++ b/sys/contrib/dev/acpica/include/acmacros.h
@@ -64,23 +64,12 @@
#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (UINT64) (val))
/*
- * printf() format helpers. These macros are workarounds for the difficulties
+ * printf() format helper. This macros is a workaround for the difficulties
* with emitting 64-bit integers and 64-bit pointers with the same code
* for both 32-bit and 64-bit hosts.
*/
#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i)
-#if ACPI_MACHINE_WIDTH == 64
-#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i)
-#define ACPI_FORMAT_TO_UINT(i) ACPI_FORMAT_UINT64(i)
-#define ACPI_PRINTF_UINT "0x%8.8X%8.8X"
-
-#else
-#define ACPI_FORMAT_NATIVE_UINT(i) 0, (UINT32) (i)
-#define ACPI_FORMAT_TO_UINT(i) (UINT32) (i)
-#define ACPI_PRINTF_UINT "0x%8.8X"
-#endif
-
/*
* Macros for moving data around to/from buffers that are possibly unaligned.
diff --git a/sys/contrib/dev/acpica/include/acopcode.h b/sys/contrib/dev/acpica/include/acopcode.h
index f4ba55d..9432d61 100644
--- a/sys/contrib/dev/acpica/include/acopcode.h
+++ b/sys/contrib/dev/acpica/include/acopcode.h
@@ -112,6 +112,7 @@
#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA)
#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST)
#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME)
+#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_BYTEDATA)
#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG)
#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST)
#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
@@ -245,6 +246,7 @@
#define ARGI_DWORD_OP ARGI_INVALID_OPCODE
#define ARGI_ELSE_OP ARGI_INVALID_OPCODE
#define ARGI_EVENT_OP ARGI_INVALID_OPCODE
+#define ARGI_EXTERNAL_OP ARGI_LIST3 (ARGI_STRING, ARGI_INTEGER, ARGI_INTEGER)
#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER)
#define ARGI_FIELD_OP ARGI_INVALID_OPCODE
#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
diff --git a/sys/contrib/dev/acpica/include/acpixf.h b/sys/contrib/dev/acpica/include/acpixf.h
index 26988ab..8f6e089 100644
--- a/sys/contrib/dev/acpica/include/acpixf.h
+++ b/sys/contrib/dev/acpica/include/acpixf.h
@@ -46,7 +46,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20150204
+#define ACPI_CA_VERSION 0x20150410
#include <contrib/dev/acpica/include/acconfig.h>
#include <contrib/dev/acpica/include/actypes.h>
@@ -503,7 +503,7 @@ AcpiReallocateRootTable (
ACPI_EXTERNAL_RETURN_STATUS (
ACPI_STATUS
AcpiFindRootPointer (
- ACPI_SIZE *RsdpAddress))
+ ACPI_PHYSICAL_ADDRESS *RsdpAddress))
ACPI_EXTERNAL_RETURN_STATUS (
ACPI_STATUS
diff --git a/sys/contrib/dev/acpica/include/acresrc.h b/sys/contrib/dev/acpica/include/acresrc.h
index 3b62275..ef3265876 100644
--- a/sys/contrib/dev/acpica/include/acresrc.h
+++ b/sys/contrib/dev/acpica/include/acresrc.h
@@ -352,8 +352,9 @@ AcpiRsSetResourceLength (
/*
- * rsdump
+ * rsdump - Debugger support
*/
+#ifdef ACPI_DEBUGGER
void
AcpiRsDumpResourceList (
ACPI_RESOURCE *Resource);
@@ -361,6 +362,7 @@ AcpiRsDumpResourceList (
void
AcpiRsDumpIrqList (
UINT8 *RouteTable);
+#endif
/*
diff --git a/sys/contrib/dev/acpica/include/acrestyp.h b/sys/contrib/dev/acpica/include/acrestyp.h
index 971dd72..d695451 100644
--- a/sys/contrib/dev/acpica/include/acrestyp.h
+++ b/sys/contrib/dev/acpica/include/acrestyp.h
@@ -345,6 +345,36 @@ typedef struct acpi_resource_source
UINT8 MaxAddressFixed; \
ACPI_RESOURCE_ATTRIBUTE Info;
+typedef struct acpi_address16_attribute
+{
+ UINT16 Granularity;
+ UINT16 Minimum;
+ UINT16 Maximum;
+ UINT16 TranslationOffset;
+ UINT16 AddressLength;
+
+} ACPI_ADDRESS16_ATTRIBUTE;
+
+typedef struct acpi_address32_attribute
+{
+ UINT32 Granularity;
+ UINT32 Minimum;
+ UINT32 Maximum;
+ UINT32 TranslationOffset;
+ UINT32 AddressLength;
+
+} ACPI_ADDRESS32_ATTRIBUTE;
+
+typedef struct acpi_address64_attribute
+{
+ UINT64 Granularity;
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 TranslationOffset;
+ UINT64 AddressLength;
+
+} ACPI_ADDRESS64_ATTRIBUTE;
+
typedef struct acpi_resource_address
{
ACPI_RESOURCE_ADDRESS_COMMON
@@ -354,11 +384,7 @@ typedef struct acpi_resource_address
typedef struct acpi_resource_address16
{
ACPI_RESOURCE_ADDRESS_COMMON
- UINT16 Granularity;
- UINT16 Minimum;
- UINT16 Maximum;
- UINT16 TranslationOffset;
- UINT16 AddressLength;
+ ACPI_ADDRESS16_ATTRIBUTE Address;
ACPI_RESOURCE_SOURCE ResourceSource;
} ACPI_RESOURCE_ADDRESS16;
@@ -366,11 +392,7 @@ typedef struct acpi_resource_address16
typedef struct acpi_resource_address32
{
ACPI_RESOURCE_ADDRESS_COMMON
- UINT32 Granularity;
- UINT32 Minimum;
- UINT32 Maximum;
- UINT32 TranslationOffset;
- UINT32 AddressLength;
+ ACPI_ADDRESS32_ATTRIBUTE Address;
ACPI_RESOURCE_SOURCE ResourceSource;
} ACPI_RESOURCE_ADDRESS32;
@@ -378,11 +400,7 @@ typedef struct acpi_resource_address32
typedef struct acpi_resource_address64
{
ACPI_RESOURCE_ADDRESS_COMMON
- UINT64 Granularity;
- UINT64 Minimum;
- UINT64 Maximum;
- UINT64 TranslationOffset;
- UINT64 AddressLength;
+ ACPI_ADDRESS64_ATTRIBUTE Address;
ACPI_RESOURCE_SOURCE ResourceSource;
} ACPI_RESOURCE_ADDRESS64;
@@ -391,11 +409,7 @@ typedef struct acpi_resource_extended_address64
{
ACPI_RESOURCE_ADDRESS_COMMON
UINT8 RevisionID;
- UINT64 Granularity;
- UINT64 Minimum;
- UINT64 Maximum;
- UINT64 TranslationOffset;
- UINT64 AddressLength;
+ ACPI_ADDRESS64_ATTRIBUTE Address;
UINT64 TypeSpecific;
} ACPI_RESOURCE_EXTENDED_ADDRESS64;
diff --git a/sys/contrib/dev/acpica/include/acstruct.h b/sys/contrib/dev/acpica/include/acstruct.h
index 1de614f..547921b 100644
--- a/sys/contrib/dev/acpica/include/acstruct.h
+++ b/sys/contrib/dev/acpica/include/acstruct.h
@@ -69,11 +69,6 @@
#define ACPI_WALK_METHOD 0x01
#define ACPI_WALK_METHOD_RESTART 0x02
-/* Flags for iASL compiler only */
-
-#define ACPI_WALK_CONST_REQUIRED 0x10
-#define ACPI_WALK_CONST_OPTIONAL 0x20
-
typedef struct acpi_walk_state
{
diff --git a/sys/contrib/dev/acpica/include/actables.h b/sys/contrib/dev/acpica/include/actables.h
index bc1574d..3eb02d3 100644
--- a/sys/contrib/dev/acpica/include/actables.h
+++ b/sys/contrib/dev/acpica/include/actables.h
@@ -70,8 +70,9 @@ AcpiTbScanMemoryForRsdp (
* tbdata - table data structure management
*/
ACPI_STATUS
-AcpiTbGetNextRootIndex (
- UINT32 *TableIndex);
+AcpiTbGetNextTableDescriptor (
+ UINT32 *TableIndex,
+ ACPI_TABLE_DESC **TableDesc);
void
AcpiTbInitTableDescriptor (
@@ -173,14 +174,6 @@ AcpiTbInstallStandardTable (
BOOLEAN Override,
UINT32 *TableIndex);
-ACPI_STATUS
-AcpiTbStoreTable (
- ACPI_PHYSICAL_ADDRESS Address,
- ACPI_TABLE_HEADER *Table,
- UINT32 Length,
- UINT8 Flags,
- UINT32 *TableIndex);
-
void
AcpiTbUninstallTable (
ACPI_TABLE_DESC *TableDesc);
diff --git a/sys/contrib/dev/acpica/include/actbl2.h b/sys/contrib/dev/acpica/include/actbl2.h
index f8a0278..5cdf904 100644
--- a/sys/contrib/dev/acpica/include/actbl2.h
+++ b/sys/contrib/dev/acpica/include/actbl2.h
@@ -75,6 +75,7 @@
#define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */
#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */
#define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */
+#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */
#define ACPI_SIG_MTMR "MTMR" /* MID Timer table */
#define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */
#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */
@@ -980,7 +981,8 @@ typedef struct acpi_lpit_header
enum AcpiLpitType
{
ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00,
- ACPI_LPIT_TYPE_SIMPLE_IO = 0x01
+ ACPI_LPIT_TYPE_SIMPLE_IO = 0x01,
+ ACPI_LPIT_TYPE_RESERVED = 0x02 /* 2 and above are reserved */
};
/* Masks for Flags field above */
@@ -1085,6 +1087,24 @@ typedef struct acpi_table_mchi
/*******************************************************************************
*
+ * MSDM - Microsoft Data Management table
+ *
+ * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)",
+ * November 29, 2011. Copyright 2011 Microsoft
+ *
+ ******************************************************************************/
+
+/* Basic MSDM table is only the common ACPI header */
+
+typedef struct acpi_table_msdm
+{
+ ACPI_TABLE_HEADER Header; /* Common ACPI table header */
+
+} ACPI_TABLE_MSDM;
+
+
+/*******************************************************************************
+ *
* MTMR - MID Timer Table
* Version 1
*
@@ -1114,10 +1134,9 @@ typedef struct acpi_mtmr_entry
/*******************************************************************************
*
* SLIC - Software Licensing Description Table
- * Version 1
*
- * Conforms to "OEM Activation 2.0 for Windows Vista Operating Systems",
- * Copyright 2006
+ * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)",
+ * November 29, 2011. Copyright 2011 Microsoft
*
******************************************************************************/
@@ -1130,62 +1149,6 @@ typedef struct acpi_table_slic
} ACPI_TABLE_SLIC;
-/* Common SLIC subtable header */
-
-typedef struct acpi_slic_header
-{
- UINT32 Type;
- UINT32 Length;
-
-} ACPI_SLIC_HEADER;
-
-/* Values for Type field above */
-
-enum AcpiSlicType
-{
- ACPI_SLIC_TYPE_PUBLIC_KEY = 0,
- ACPI_SLIC_TYPE_WINDOWS_MARKER = 1,
- ACPI_SLIC_TYPE_RESERVED = 2 /* 2 and greater are reserved */
-};
-
-
-/*
- * SLIC Subtables, correspond to Type in ACPI_SLIC_HEADER
- */
-
-/* 0: Public Key Structure */
-
-typedef struct acpi_slic_key
-{
- ACPI_SLIC_HEADER Header;
- UINT8 KeyType;
- UINT8 Version;
- UINT16 Reserved;
- UINT32 Algorithm;
- char Magic[4];
- UINT32 BitLength;
- UINT32 Exponent;
- UINT8 Modulus[128];
-
-} ACPI_SLIC_KEY;
-
-
-/* 1: Windows Marker Structure */
-
-typedef struct acpi_slic_marker
-{
- ACPI_SLIC_HEADER Header;
- UINT32 Version;
- char OemId[ACPI_OEM_ID_SIZE]; /* ASCII OEM identification */
- char OemTableId[ACPI_OEM_TABLE_ID_SIZE]; /* ASCII OEM table identification */
- char WindowsFlag[8];
- UINT32 SlicVersion;
- UINT8 Reserved[16];
- UINT8 Signature[128];
-
-} ACPI_SLIC_MARKER;
-
-
/*******************************************************************************
*
* SPCR - Serial Port Console Redirection table
diff --git a/sys/contrib/dev/acpica/include/actypes.h b/sys/contrib/dev/acpica/include/actypes.h
index c6f2170..79ae310 100644
--- a/sys/contrib/dev/acpica/include/actypes.h
+++ b/sys/contrib/dev/acpica/include/actypes.h
@@ -201,9 +201,29 @@ typedef int INT32;
typedef INT32 ACPI_NATIVE_INT;
typedef UINT32 ACPI_SIZE;
+
+#ifdef ACPI_32BIT_PHYSICAL_ADDRESS
+
+/*
+ * OSPMs can define this to shrink the size of the structures for 32-bit
+ * none PAE environment. ASL compiler may always define this to generate
+ * 32-bit OSPM compliant tables.
+ */
typedef UINT32 ACPI_IO_ADDRESS;
typedef UINT32 ACPI_PHYSICAL_ADDRESS;
+#else /* ACPI_32BIT_PHYSICAL_ADDRESS */
+
+/*
+ * It is reported that, after some calculations, the physical addresses can
+ * wrap over the 32-bit boundary on 32-bit PAE environment.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=87971
+ */
+typedef UINT64 ACPI_IO_ADDRESS;
+typedef UINT64 ACPI_PHYSICAL_ADDRESS;
+
+#endif /* ACPI_32BIT_PHYSICAL_ADDRESS */
+
#define ACPI_MAX_PTR ACPI_UINT32_MAX
#define ACPI_SIZE_MAX ACPI_UINT32_MAX
@@ -720,23 +740,26 @@ typedef UINT32 ACPI_EVENT_TYPE;
* The encoding of ACPI_EVENT_STATUS is illustrated below.
* Note that a set bit (1) indicates the property is TRUE
* (e.g. if bit 0 is set then the event is enabled).
- * +-------------+-+-+-+-+
- * | Bits 31:4 |3|2|1|0|
- * +-------------+-+-+-+-+
- * | | | | |
- * | | | | +- Enabled?
- * | | | +--- Enabled for wake?
- * | | +----- Set?
- * | +------- Has a handler?
- * +------------- <Reserved>
+ * +-------------+-+-+-+-+-+
+ * | Bits 31:5 |4|3|2|1|0|
+ * +-------------+-+-+-+-+-+
+ * | | | | | |
+ * | | | | | +- Enabled?
+ * | | | | +--- Enabled for wake?
+ * | | | +----- Status bit set?
+ * | | +------- Enable bit set?
+ * | +--------- Has a handler?
+ * +--------------- <Reserved>
*/
typedef UINT32 ACPI_EVENT_STATUS;
#define ACPI_EVENT_FLAG_DISABLED (ACPI_EVENT_STATUS) 0x00
#define ACPI_EVENT_FLAG_ENABLED (ACPI_EVENT_STATUS) 0x01
#define ACPI_EVENT_FLAG_WAKE_ENABLED (ACPI_EVENT_STATUS) 0x02
-#define ACPI_EVENT_FLAG_SET (ACPI_EVENT_STATUS) 0x04
-#define ACPI_EVENT_FLAG_HAS_HANDLER (ACPI_EVENT_STATUS) 0x08
+#define ACPI_EVENT_FLAG_STATUS_SET (ACPI_EVENT_STATUS) 0x04
+#define ACPI_EVENT_FLAG_ENABLE_SET (ACPI_EVENT_STATUS) 0x08
+#define ACPI_EVENT_FLAG_HAS_HANDLER (ACPI_EVENT_STATUS) 0x10
+#define ACPI_EVENT_FLAG_SET ACPI_EVENT_FLAG_STATUS_SET
/* Actions for AcpiSetGpe, AcpiGpeWakeup, AcpiHwLowSetGpe */
@@ -1344,6 +1367,7 @@ typedef struct acpi_memory_list
#define ACPI_OSI_WIN_VISTA_SP2 0x0A
#define ACPI_OSI_WIN_7 0x0B
#define ACPI_OSI_WIN_8 0x0C
+#define ACPI_OSI_WIN_10 0x0D
/* Definitions of file IO */
diff --git a/sys/contrib/dev/acpica/include/acutils.h b/sys/contrib/dev/acpica/include/acutils.h
index a651863..85426bf 100644
--- a/sys/contrib/dev/acpica/include/acutils.h
+++ b/sys/contrib/dev/acpica/include/acutils.h
@@ -723,6 +723,12 @@ const ACPI_PREDEFINED_INFO *
AcpiUtMatchPredefinedMethod (
char *Name);
+void
+AcpiUtGetExpectedReturnTypes (
+ char *Buffer,
+ UINT32 ExpectedBtypes);
+
+#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP)
const ACPI_PREDEFINED_INFO *
AcpiUtMatchResourceName (
char *Name);
@@ -733,15 +739,11 @@ AcpiUtDisplayPredefinedMethod (
const ACPI_PREDEFINED_INFO *ThisName,
BOOLEAN MultiLine);
-void
-AcpiUtGetExpectedReturnTypes (
- char *Buffer,
- UINT32 ExpectedBtypes);
-
UINT32
AcpiUtGetResourceBitWidth (
char *Buffer,
UINT16 Types);
+#endif
/*
@@ -782,13 +784,6 @@ AcpiUtCreateUpdateStateAndPush (
UINT16 Action,
ACPI_GENERIC_STATE **StateList);
-ACPI_STATUS
-AcpiUtCreatePkgStateAndPush (
- void *InternalObject,
- void *ExternalObject,
- UINT16 Index,
- ACPI_GENERIC_STATE **StateList);
-
ACPI_GENERIC_STATE *
AcpiUtCreateControlState (
void);
@@ -827,9 +822,11 @@ BOOLEAN
AcpiUtIsPciRootBridge (
char *Id);
+#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP)
BOOLEAN
AcpiUtIsAmlTable (
ACPI_TABLE_HEADER *Table);
+#endif
ACPI_STATUS
AcpiUtWalkPackageTree (
@@ -918,6 +915,7 @@ void
AcpiUtStrupr (
char *SrcString);
+#ifdef ACPI_ASL_COMPILER
void
AcpiUtStrlwr (
char *SrcString);
@@ -926,6 +924,7 @@ int
AcpiUtStricmp (
char *String1,
char *String2);
+#endif
ACPI_STATUS
AcpiUtStrtoul64 (
@@ -938,9 +937,11 @@ AcpiUtPrintString (
char *String,
UINT16 MaxLength);
+#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP
void
UtConvertBackslashes (
char *Pathname);
+#endif
BOOLEAN
AcpiUtValidAcpiName (
@@ -1189,9 +1190,11 @@ AcpiUtFilePrintf (
/*
* utuuid -- UUID support functions
*/
+#if (defined ACPI_ASL_COMPILER || defined ACPI_DISASSEMBLER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP)
void
AcpiUtConvertStringToUuid (
char *InString,
UINT8 *UuidBuffer);
+#endif
#endif /* _ACUTILS_H */
diff --git a/sys/contrib/dev/acpica/include/amlcode.h b/sys/contrib/dev/acpica/include/amlcode.h
index 03530b9..d56f6d9 100644
--- a/sys/contrib/dev/acpica/include/amlcode.h
+++ b/sys/contrib/dev/acpica/include/amlcode.h
@@ -65,6 +65,7 @@
#define AML_PACKAGE_OP (UINT16) 0x12
#define AML_VAR_PACKAGE_OP (UINT16) 0x13 /* ACPI 2.0 */
#define AML_METHOD_OP (UINT16) 0x14
+#define AML_EXTERNAL_OP (UINT16) 0x15 /* ACPI 6.0 */
#define AML_DUAL_NAME_PREFIX (UINT16) 0x2e
#define AML_MULTI_NAME_PREFIX_OP (UINT16) 0x2f
#define AML_NAME_CHAR_SUBSEQ (UINT16) 0x30
@@ -209,7 +210,6 @@
#define AML_INT_RESERVEDFIELD_OP (UINT16) 0x0031
#define AML_INT_ACCESSFIELD_OP (UINT16) 0x0032
#define AML_INT_BYTELIST_OP (UINT16) 0x0033
-#define AML_INT_STATICSTRING_OP (UINT16) 0x0034
#define AML_INT_METHODCALL_OP (UINT16) 0x0035
#define AML_INT_RETURN_VALUE_OP (UINT16) 0x0036
#define AML_INT_EVAL_SUBTREE_OP (UINT16) 0x0037
diff --git a/sys/contrib/dev/acpica/include/platform/acenv.h b/sys/contrib/dev/acpica/include/platform/acenv.h
index 759a68e..f5f3b1a 100644
--- a/sys/contrib/dev/acpica/include/platform/acenv.h
+++ b/sys/contrib/dev/acpica/include/platform/acenv.h
@@ -77,6 +77,7 @@
#define ACPI_LARGE_NAMESPACE_NODE
#define ACPI_DATA_TABLE_DISASSEMBLY
#define ACPI_SINGLE_THREADED
+#define ACPI_32BIT_PHYSICAL_ADDRESS
#endif
/* AcpiExec configuration. Multithreaded with full AML debugger */
diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h
index 6d74468..8aece74 100644
--- a/sys/contrib/ipfilter/netinet/ip_compat.h
+++ b/sys/contrib/ipfilter/netinet/ip_compat.h
@@ -153,7 +153,8 @@ struct ether_addr {
# include <sys/rwlock.h>
# define KMUTEX_T struct mtx
# define KRWLOCK_T struct rwlock
-# ifdef _KERNEL
+
+#ifdef _KERNEL
# define READ_ENTER(x) rw_rlock(&(x)->ipf_lk)
# define WRITE_ENTER(x) rw_wlock(&(x)->ipf_lk)
# define MUTEX_DOWNGRADE(x) rw_downgrade(&(x)->ipf_lk)
@@ -165,16 +166,7 @@ struct ether_addr {
else \
rw_runlock(&(x)->ipf_lk); \
} while (0)
-# endif
-
# include <net/if_var.h>
-# define IFNAME(x) ((struct ifnet *)x)->if_xname
-# define COPYIFNAME(v, x, b) \
- (void) strncpy(b, \
- ((struct ifnet *)x)->if_xname, \
- LIFNAMSIZ)
-
-# ifdef _KERNEL
# define GETKTIME(x) microtime((struct timeval *)x)
# include <netinet/in_systm.h>
@@ -216,8 +208,28 @@ struct ether_addr {
# define M_DUP(m) m_dup(m, M_NOWAIT)
# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
typedef struct mbuf mb_t;
-# endif /* _KERNEL */
+#else /* !_KERNEL */
+#ifndef _NET_IF_VAR_H_
+/*
+ * Userland emulation of struct ifnet.
+ */
+struct route;
+struct mbuf;
+struct ifnet {
+ char if_xname[IFNAMSIZ];
+ TAILQ_HEAD(, ifaddr) if_addrlist;
+ int (*if_output)(struct ifnet *, struct mbuf *,
+ const struct sockaddr *, struct route *);
+};
+#endif /* _NET_IF_VAR_H_ */
+#endif /* _KERNEL */
+
+# define IFNAME(x) ((struct ifnet *)x)->if_xname
+# define COPYIFNAME(v, x, b) \
+ (void) strncpy(b, \
+ ((struct ifnet *)x)->if_xname, \
+ LIFNAMSIZ)
typedef u_long ioctlcmd_t;
typedef struct uio uio_t;
diff --git a/sys/contrib/x86emu/x86emu.c b/sys/contrib/x86emu/x86emu.c
index 87cd777..41e7c4a 100644
--- a/sys/contrib/x86emu/x86emu.c
+++ b/sys/contrib/x86emu/x86emu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: x86emu.c,v 1.5 2010/02/17 15:09:47 pirofti Exp $ */
+/* $OpenBSD: x86emu.c,v 1.9 2014/06/15 11:04:49 pirofti Exp $ */
/* $NetBSD: x86emu.c,v 1.7 2009/02/03 19:26:29 joerg Exp $ */
/*
@@ -5250,7 +5250,7 @@ x86emuOp2_pop_FS(struct x86emu *emu)
static void
hw_cpuid(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
{
- __asm__ __volatile__("cpuid"
+ __asm__ volatile("cpuid"
: "=a" (*a), "=b" (*b),
"=c" (*c), "=d" (*d)
: "a" (*a), "c" (*c)
diff --git a/sys/crypto/aesni/aesencdec.h b/sys/crypto/aesni/aesencdec.h
index 5e4f128..76e6403 100644
--- a/sys/crypto/aesni/aesencdec.h
+++ b/sys/crypto/aesni/aesencdec.h
@@ -27,6 +27,8 @@
*
*/
+#include <crypto/aesni/aesni_os.h>
+
#include <wmmintrin.h>
static inline void
diff --git a/sys/crypto/aesni/aesni_ghash.c b/sys/crypto/aesni/aesni_ghash.c
index 005ba81..f7be6c0 100644
--- a/sys/crypto/aesni/aesni_ghash.c
+++ b/sys/crypto/aesni/aesni_ghash.c
@@ -67,6 +67,7 @@
#ifdef _KERNEL
#include <crypto/aesni/aesni.h>
+#include <crypto/aesni/aesni_os.h>
#else
#include <stdint.h>
#endif
diff --git a/sys/crypto/aesni/aesni_os.h b/sys/crypto/aesni/aesni_os.h
new file mode 100644
index 0000000..273c3f9
--- /dev/null
+++ b/sys/crypto/aesni/aesni_os.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright 2015 Craig Rodrigues <rodrigc@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#if defined(__GNUC__) && defined(_KERNEL)
+/* Suppress inclusion of gcc's mm_malloc.h header */
+#define _MM_MALLOC_H_INCLUDED 1
+#endif
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index b331fb8..7796fbe 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -606,7 +606,7 @@ acpi_attach(device_t dev)
sc->acpi_handle_reboot = 1;
/* Only enable S4BIOS by default if the FACS says it is available. */
- if (AcpiGbl_FACS->Flags & ACPI_FACS_S4_BIOS_PRESENT)
+ if (AcpiGbl_FACS != NULL && AcpiGbl_FACS->Flags & ACPI_FACS_S4_BIOS_PRESENT)
sc->acpi_s4bios = 1;
/* Probe all supported sleep states. */
@@ -1071,30 +1071,53 @@ acpi_hint_device_unit(device_t acdev, device_t child, const char *name,
}
/*
- * Fetch the NUMA domain for the given device.
- *
- * If a device has a _PXM method, map that to a NUMA domain.
+ * Fetch the VM domain for the given device 'dev'.
*
- * If none is found, then it'll call the parent method.
- * If there's no domain, return ENOENT.
+ * Return 1 + domain if there's a domain, 0 if not found;
+ * -1 upon an error.
*/
int
-acpi_get_domain(device_t dev, device_t child, int *domain)
+acpi_parse_pxm(device_t dev, int *domain)
{
#if MAXMEMDOM > 1
ACPI_HANDLE h;
int d, pxm;
- h = acpi_get_handle(child);
+ h = acpi_get_handle(dev);
if ((h != NULL) &&
ACPI_SUCCESS(acpi_GetInteger(h, "_PXM", &pxm))) {
d = acpi_map_pxm_to_vm_domainid(pxm);
if (d < 0)
- return (ENOENT);
+ return (-1);
*domain = d;
- return (0);
+ return (1);
}
#endif
+
+ return (0);
+}
+
+/*
+ * Fetch the NUMA domain for the given device.
+ *
+ * If a device has a _PXM method, map that to a NUMA domain.
+ *
+ * If none is found, then it'll call the parent method.
+ * If there's no domain, return ENOENT.
+ */
+int
+acpi_get_domain(device_t dev, device_t child, int *domain)
+{
+ int ret;
+
+ ret = acpi_parse_pxm(child, domain);
+ /* Error */
+ if (ret == -1)
+ return (ENOENT);
+ /* Found */
+ if (ret == 1)
+ return (0);
+
/* No _PXM node; go up a level */
return (bus_generic_get_domain(dev, child, domain));
}
@@ -1151,7 +1174,7 @@ acpi_sysres_alloc(device_t dev)
if (res != NULL) {
rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
rle->res = res;
- } else
+ } else if (bootverbose)
device_printf(dev, "reservation of %lx, %lx (%d) failed\n",
rle->start, rle->count, rle->type);
}
diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c
index 545f641..490f277 100644
--- a/sys/dev/acpica/acpi_pcib_acpi.c
+++ b/sys/dev/acpica/acpi_pcib_acpi.c
@@ -194,27 +194,27 @@ acpi_pcib_producer_handler(ACPI_RESOURCE *res, void *context)
break;
switch (res->Type) {
case ACPI_RESOURCE_TYPE_ADDRESS16:
- min = res->Data.Address16.Minimum;
- max = res->Data.Address16.Maximum;
- length = res->Data.Address16.AddressLength;
+ min = res->Data.Address16.Address.Minimum;
+ max = res->Data.Address16.Address.Maximum;
+ length = res->Data.Address16.Address.AddressLength;
break;
case ACPI_RESOURCE_TYPE_ADDRESS32:
- min = res->Data.Address32.Minimum;
- max = res->Data.Address32.Maximum;
- length = res->Data.Address32.AddressLength;
+ min = res->Data.Address32.Address.Minimum;
+ max = res->Data.Address32.Address.Maximum;
+ length = res->Data.Address32.Address.AddressLength;
break;
case ACPI_RESOURCE_TYPE_ADDRESS64:
- min = res->Data.Address64.Minimum;
- max = res->Data.Address64.Maximum;
- length = res->Data.Address64.AddressLength;
+ min = res->Data.Address64.Address.Minimum;
+ max = res->Data.Address64.Address.Maximum;
+ length = res->Data.Address64.Address.AddressLength;
break;
default:
KASSERT(res->Type ==
ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
("should never happen"));
- min = res->Data.ExtAddress64.Minimum;
- max = res->Data.ExtAddress64.Maximum;
- length = res->Data.ExtAddress64.AddressLength;
+ min = res->Data.ExtAddress64.Address.Minimum;
+ max = res->Data.ExtAddress64.Address.Maximum;
+ length = res->Data.ExtAddress64.Address.AddressLength;
break;
}
if (length == 0)
diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c
index 07ebace..f8936a5 100644
--- a/sys/dev/acpica/acpi_resource.c
+++ b/sys/dev/acpica/acpi_resource.c
@@ -298,28 +298,28 @@ acpi_parse_resource(ACPI_RESOURCE *res, void *context)
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
switch (res->Type) {
case ACPI_RESOURCE_TYPE_ADDRESS16:
- gran = res->Data.Address16.Granularity;
- min = res->Data.Address16.Minimum;
- max = res->Data.Address16.Maximum;
- length = res->Data.Address16.AddressLength;
+ gran = res->Data.Address16.Address.Granularity;
+ min = res->Data.Address16.Address.Minimum;
+ max = res->Data.Address16.Address.Maximum;
+ length = res->Data.Address16.Address.AddressLength;
#ifdef ACPI_DEBUG
name = "Address16";
#endif
break;
case ACPI_RESOURCE_TYPE_ADDRESS32:
- gran = res->Data.Address32.Granularity;
- min = res->Data.Address32.Minimum;
- max = res->Data.Address32.Maximum;
- length = res->Data.Address32.AddressLength;
+ gran = res->Data.Address32.Address.Granularity;
+ min = res->Data.Address32.Address.Minimum;
+ max = res->Data.Address32.Address.Maximum;
+ length = res->Data.Address32.Address.AddressLength;
#ifdef ACPI_DEBUG
name = "Address32";
#endif
break;
case ACPI_RESOURCE_TYPE_ADDRESS64:
- gran = res->Data.Address64.Granularity;
- min = res->Data.Address64.Minimum;
- max = res->Data.Address64.Maximum;
- length = res->Data.Address64.AddressLength;
+ gran = res->Data.Address64.Address.Granularity;
+ min = res->Data.Address64.Address.Minimum;
+ max = res->Data.Address64.Address.Maximum;
+ length = res->Data.Address64.Address.AddressLength;
#ifdef ACPI_DEBUG
name = "Address64";
#endif
@@ -327,10 +327,10 @@ acpi_parse_resource(ACPI_RESOURCE *res, void *context)
default:
KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64,
("should never happen"));
- gran = res->Data.ExtAddress64.Granularity;
- min = res->Data.ExtAddress64.Minimum;
- max = res->Data.ExtAddress64.Maximum;
- length = res->Data.ExtAddress64.AddressLength;
+ gran = res->Data.ExtAddress64.Address.Granularity;
+ min = res->Data.ExtAddress64.Address.Minimum;
+ max = res->Data.ExtAddress64.Address.Maximum;
+ length = res->Data.ExtAddress64.Address.AddressLength;
#ifdef ACPI_DEBUG
name = "ExtAddress64";
#endif
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index a314098..2e2b96d 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -185,7 +185,7 @@ extern struct mtx acpi_mutex;
* Various features and capabilities for the acpi_get_features() method.
* In particular, these are used for the ACPI 3.0 _PDC and _OSC methods.
* See the Intel document titled "Intel Processor Vendor-Specific ACPI",
- * number 302223-005.
+ * number 302223-007.
*/
#define ACPI_CAP_PERF_MSRS (1 << 0) /* Intel SpeedStep PERF_CTL MSRs */
#define ACPI_CAP_C1_IO_HALT (1 << 1) /* Intel C1 "IO then halt" sequence */
@@ -198,6 +198,9 @@ extern struct mtx acpi_mutex;
#define ACPI_CAP_SMP_C1_NATIVE (1 << 8) /* MP C1 support other than halt */
#define ACPI_CAP_SMP_C3_NATIVE (1 << 9) /* MP C2 and C3 support */
#define ACPI_CAP_PX_HW_COORD (1 << 11) /* Intel P-state HW coordination */
+#define ACPI_CAP_INTR_CPPC (1 << 12) /* Native Interrupt Handling for
+ Collaborative Processor Performance Control notifications */
+#define ACPI_CAP_HW_DUTY_C (1 << 13) /* Hardware Duty Cycling */
/*
* Quirk flags.
@@ -497,8 +500,8 @@ SYSCTL_DECL(_debug_acpi);
#if MAXMEMDOM > 1
extern int acpi_map_pxm_to_vm_domainid(int pxm);
#endif
-
extern int acpi_get_domain(device_t dev, device_t child, int *domain);
+extern int acpi_parse_pxm(device_t dev, int *domain);
#endif /* _KERNEL */
#endif /* !_ACPIVAR_H_ */
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h
index 2622efd..938a68c 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212.h
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h
@@ -345,7 +345,9 @@ struct ath_hal_5212 {
uint32_t ah_txBusy;
uint32_t ah_rx_chainmask;
uint32_t ah_tx_chainmask;
- HAL_ANI_STATE ext_ani_state;
+
+ /* Used to return ANI statistics to the diagnostic API */
+ HAL_ANI_STATS ext_ani_stats;
};
#define AH5212(_ah) ((struct ath_hal_5212 *)(_ah))
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
index 098a14c..e2f1eb7 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
@@ -1052,7 +1052,7 @@ ar5212GetDiagState(struct ath_hal *ah, int request,
void **result, uint32_t *resultsize)
{
struct ath_hal_5212 *ahp = AH5212(ah);
- struct ar5212AniState *astate;
+ HAL_ANI_STATS *astats;
(void) ahp;
if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
@@ -1084,27 +1084,15 @@ ar5212GetDiagState(struct ath_hal *ah, int request,
0 : sizeof(struct ar5212AniState);
return AH_TRUE;
case HAL_DIAG_ANI_STATS:
- OS_MEMZERO(&ahp->ext_ani_state, sizeof(ahp->ext_ani_state));
- astate = ar5212AniGetCurrentState(ah);
- if (astate == NULL) {
+ OS_MEMZERO(&ahp->ext_ani_stats, sizeof(ahp->ext_ani_stats));
+ astats = ar5212AniGetCurrentStats(ah);
+ if (astats == NULL) {
*result = NULL;
*resultsize = 0;
} else {
- ahp->ext_ani_state.noiseImmunityLevel =
- astate->noiseImmunityLevel;
- ahp->ext_ani_state.spurImmunityLevel =
- astate->spurImmunityLevel;
- ahp->ext_ani_state.firstepLevel =
- astate->firstepLevel;
- ahp->ext_ani_state.ofdmWeakSigDetectOff =
- astate->ofdmWeakSigDetectOff;
- ahp->ext_ani_state.cckWeakSigThreshold =
- astate->cckWeakSigThreshold;
- ahp->ext_ani_state.listenTime =
- astate->listenTime;
-
- *result = &ahp->ext_ani_state;
- *resultsize = sizeof(ahp->ext_ani_state);
+ OS_MEMCPY(&ahp->ext_ani_stats, astats, sizeof(HAL_ANI_STATS));
+ *result = &ahp->ext_ani_stats;
+ *resultsize = sizeof(ahp->ext_ani_stats);
}
return AH_TRUE;
case HAL_DIAG_ANI_CMD:
diff --git a/sys/dev/atkbdc/atkbd.c b/sys/dev/atkbdc/atkbd.c
index d93c1c6..a90f5d2 100644
--- a/sys/dev/atkbdc/atkbd.c
+++ b/sys/dev/atkbdc/atkbd.c
@@ -44,19 +44,6 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/resource.h>
-#if defined(__i386__) || defined(__amd64__)
-#include <machine/md_var.h>
-#include <machine/psl.h>
-#include <compat/x86bios/x86bios.h>
-#include <machine/pc/bios.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <vm/vm_param.h>
-
-#include <isa/isareg.h>
-#endif /* __i386__ || __amd64__ */
-
#include <sys/kbio.h>
#include <dev/kbd/kbdreg.h>
#include <dev/atkbdc/atkbdreg.h>
@@ -82,6 +69,9 @@ static int atkbd_reset(KBDC kbdc, int flags, int c);
#define HAS_QUIRK(p, q) (((atkbdc_softc_t *)(p))->quirks & q)
#define ALLOW_DISABLE_KBD(kbdc) !HAS_QUIRK(kbdc, KBDC_QUIRK_KEEP_ACTIVATED)
+#define DEFAULT_DELAY 0x1 /* 500ms */
+#define DEFAULT_RATE 0x10 /* 14Hz */
+
int
atkbd_probe_unit(device_t dev, int irq, int flags)
{
@@ -249,7 +239,7 @@ static keyboard_switch_t atkbdsw = {
KEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure);
/* local functions */
-static int get_typematic(keyboard_t *kbd);
+static int set_typematic(keyboard_t *kbd);
static int setup_kbd_port(KBDC kbdc, int port, int intr);
static int get_kbd_echo(KBDC kbdc);
static int probe_keyboard(KBDC kbdc, int flags);
@@ -443,7 +433,7 @@ atkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
goto bad;
}
atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
- get_typematic(kbd);
+ set_typematic(kbd);
delay[0] = kbd->kb_delay1;
delay[1] = kbd->kb_delay2;
atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
@@ -503,7 +493,7 @@ atkbd_intr(keyboard_t *kbd, void *arg)
init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config);
KBD_FOUND_DEVICE(kbd);
atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
- get_typematic(kbd);
+ set_typematic(kbd);
delay[0] = kbd->kb_delay1;
delay[1] = kbd->kb_delay2;
atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
@@ -1135,57 +1125,19 @@ atkbd_reset(KBDC kbdc, int flags, int c)
/* local functions */
static int
-get_typematic(keyboard_t *kbd)
+set_typematic(keyboard_t *kbd)
{
-#if defined(__i386__) || defined(__amd64__)
- /*
- * Only some systems allow us to retrieve the keyboard repeat
- * rate previously set via the BIOS...
- */
- x86regs_t regs;
- uint8_t *p;
+ int val, error;
+ atkbd_state_t *state = kbd->kb_data;
- /*
- * Traditional entry points of int 0x15 and 0x16 are fixed
- * and later BIOSes follow them. (U)EFI CSM specification
- * also mandates these fixed entry points.
- *
- * Validate the entry points here before we proceed further.
- * It's known that some recent laptops does not have the
- * same entry point and hang on boot if we call it.
- */
- if (x86bios_get_intr(0x15) != 0xf000f859 ||
- x86bios_get_intr(0x16) != 0xf000e82e)
- return (ENODEV);
-
- /* Is BIOS system configuration table supported? */
- x86bios_init_regs(&regs);
- regs.R_AH = 0xc0;
- x86bios_intr(&regs, 0x15);
- if ((regs.R_FLG & PSL_C) != 0 || regs.R_AH != 0)
- return (ENODEV);
-
- /* Is int 0x16, function 0x09 supported? */
- p = x86bios_offset((regs.R_ES << 4) + regs.R_BX);
- if (readw(p) < 5 || (readb(p + 6) & 0x40) == 0)
- return (ENODEV);
-
- /* Is int 0x16, function 0x0306 supported? */
- x86bios_init_regs(&regs);
- regs.R_AH = 0x09;
- x86bios_intr(&regs, 0x16);
- if ((regs.R_AL & 0x08) == 0)
- return (ENODEV);
-
- x86bios_init_regs(&regs);
- regs.R_AX = 0x0306;
- x86bios_intr(&regs, 0x16);
- kbd->kb_delay1 = typematic_delay(regs.R_BH << 5);
- kbd->kb_delay2 = typematic_rate(regs.R_BL);
- return (0);
-#else
- return (ENODEV);
-#endif /* __i386__ || __amd64__ */
+ val = typematic(DEFAULT_DELAY, DEFAULT_RATE);
+ error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, val);
+ if (error == 0) {
+ kbd->kb_delay1 = typematic_delay(val);
+ kbd->kb_delay2 = typematic_rate(val);
+ }
+
+ return (error);
}
static int
diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c
index 94cf880..6c7f47a 100644
--- a/sys/dev/atkbdc/psm.c
+++ b/sys/dev/atkbdc/psm.c
@@ -191,13 +191,15 @@ enum {
SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
- SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX
+ SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
+ SYNAPTICS_SYSCTL_TOUCHPAD_OFF
};
typedef struct synapticsinfo {
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
int directional_scrolls;
+ int two_finger_scroll;
int min_pressure;
int max_pressure;
int max_width;
@@ -228,6 +230,7 @@ typedef struct synapticsinfo {
int vscroll_min_delta;
int vscroll_div_min;
int vscroll_div_max;
+ int touchpad_off;
} synapticsinfo_t;
typedef struct synapticspacket {
@@ -336,6 +339,7 @@ struct psm_softc { /* Driver status information */
int lasterr;
int cmdcount;
struct sigio *async; /* Processes waiting for SIGIO */
+ int extended_buttons;
};
static devclass_t psm_devclass;
@@ -476,6 +480,10 @@ static probefunc_t enable_synaptics;
static probefunc_t enable_trackpoint;
static probefunc_t enable_versapad;
+static void set_trackpoint_parameters(struct psm_softc *sc);
+static void synaptics_passthrough_on(struct psm_softc *sc);
+static void synaptics_passthrough_off(struct psm_softc *sc);
+
static struct {
int model;
u_char syncmask;
@@ -883,6 +891,13 @@ doinitialize(struct psm_softc *sc, mousemode_t *mode)
set_mouse_resolution(kbdc, mode->resolution);
set_mouse_scaling(kbdc, 1);
set_mouse_mode(kbdc);
+
+ /*
+ * Trackpoint settings are lost on resume.
+ * Restore them here.
+ */
+ if (sc->tphw > 0)
+ set_trackpoint_parameters(sc);
}
/* Record sync on the next data packet we see. */
@@ -2723,6 +2738,12 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
goto SYNAPTICS_END;
}
+ if (sc->syninfo.touchpad_off) {
+ *x = *y = *z = 0;
+ ms->button = ms->obutton;
+ goto SYNAPTICS_END;
+ }
+
/* Button presses */
touchpad_buttons = 0;
if (pb->ipacket[0] & 0x01)
@@ -2735,7 +2756,8 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
touchpad_buttons |= MOUSE_BUTTON4DOWN;
if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02)
touchpad_buttons |= MOUSE_BUTTON5DOWN;
- } else if (sc->synhw.capExtended && sc->synhw.capMiddle) {
+ } else if (sc->synhw.capExtended && sc->synhw.capMiddle &&
+ !sc->synhw.capClickPad) {
/* Middle Button */
if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
touchpad_buttons |= MOUSE_BUTTON2DOWN;
@@ -2752,7 +2774,13 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
if (pb->ipacket[5] & 0x02)
touchpad_buttons |= MOUSE_BUTTON7DOWN;
} else {
- touchpad_buttons |= MOUSE_BUTTON2DOWN;
+ if (pb->ipacket[4] & 0x01)
+ touchpad_buttons |= MOUSE_BUTTON1DOWN;
+ if (pb->ipacket[5] & 0x01)
+ touchpad_buttons |= MOUSE_BUTTON3DOWN;
+ if (pb->ipacket[4] & 0x02)
+ touchpad_buttons |= MOUSE_BUTTON2DOWN;
+ sc->extended_buttons = touchpad_buttons;
}
/*
@@ -2774,13 +2802,26 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
mask = (1 << maskedbits) - 1;
pb->ipacket[4] &= ~(mask);
pb->ipacket[5] &= ~(mask);
+ } else if (!sc->syninfo.directional_scrolls &&
+ !sc->synaction.in_vscroll) {
+ /*
+ * Keep reporting MOUSE DOWN until we get a new packet
+ * indicating otherwise.
+ */
+ touchpad_buttons |= sc->extended_buttons;
}
}
+ /* Handle ClickPad. */
+ if (sc->synhw.capClickPad &&
+ ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
+ touchpad_buttons |= MOUSE_BUTTON1DOWN;
ms->button = touchpad_buttons | guest_buttons;
- /* Check pressure to detect a real wanted action on the
- * touchpad. */
+ /*
+ * Check pressure to detect a real wanted action on the
+ * touchpad.
+ */
if (*z >= sc->syninfo.min_pressure) {
synapticsaction_t *synaction;
int cursor, peer, window;
@@ -2793,7 +2834,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
int weight_current, weight_previous, weight_len_squared;
int div_min, div_max, div_len;
int vscroll_hor_area, vscroll_ver_area;
-
+ int two_finger_scroll;
int len, weight_prev_x, weight_prev_y;
int div_max_x, div_max_y, div_x, div_y;
@@ -2820,6 +2861,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
div_len = sc->syninfo.div_len;
vscroll_hor_area = sc->syninfo.vscroll_hor_area;
vscroll_ver_area = sc->syninfo.vscroll_ver_area;
+ two_finger_scroll = sc->syninfo.two_finger_scroll;
/* Palm detection. */
if (!(
@@ -2979,33 +3021,57 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
dxp >= sc->syninfo.vscroll_min_delta ||
dyp >= sc->syninfo.vscroll_min_delta) {
- /* Check for horizontal scrolling. */
- if ((vscroll_hor_area > 0 &&
- synaction->start_y <= vscroll_hor_area) ||
- (vscroll_hor_area < 0 &&
- synaction->start_y >=
- 6143 + vscroll_hor_area))
- synaction->in_vscroll += 2;
-
- /* Check for vertical scrolling. */
- if ((vscroll_ver_area > 0 &&
- synaction->start_x <= vscroll_ver_area) ||
- (vscroll_ver_area < 0 &&
- synaction->start_x >=
- 6143 + vscroll_ver_area))
- synaction->in_vscroll += 1;
+ /*
+ * Handle two finger scrolling.
+ * Note that we don't rely on fingers_nb
+ * as that keeps the maximum number of fingers.
+ */
+ if (two_finger_scroll) {
+ if (w == 0) {
+ synaction->in_vscroll +=
+ dyp ? 2 : 0;
+ synaction->in_vscroll +=
+ dxp ? 1 : 0;
+ }
+ } else {
+ /* Check for horizontal scrolling. */
+ if ((vscroll_hor_area > 0 &&
+ synaction->start_y <=
+ vscroll_hor_area) ||
+ (vscroll_hor_area < 0 &&
+ synaction->start_y >=
+ 6143 + vscroll_hor_area))
+ synaction->in_vscroll += 2;
+
+ /* Check for vertical scrolling. */
+ if ((vscroll_ver_area > 0 &&
+ synaction->start_x <=
+ vscroll_ver_area) ||
+ (vscroll_ver_area < 0 &&
+ synaction->start_x >=
+ 6143 + vscroll_ver_area))
+ synaction->in_vscroll += 1;
+ }
/* Avoid conflicts if area overlaps. */
- if (synaction->in_vscroll == 3)
+ if (synaction->in_vscroll >= 3)
synaction->in_vscroll =
(dxp > dyp) ? 2 : 1;
}
- VLOG(5, (LOG_DEBUG,
- "synaptics: virtual scrolling: %s "
- "(direction=%d, dxp=%d, dyp=%d)\n",
- synaction->in_vscroll ? "YES" : "NO",
- synaction->in_vscroll, dxp, dyp));
}
+ /*
+ * Reset two finger scrolling when the number of fingers
+ * is different from two.
+ */
+ if (two_finger_scroll && w != 0)
+ synaction->in_vscroll = 0;
+
+ VLOG(5, (LOG_DEBUG,
+ "synaptics: virtual scrolling: %s "
+ "(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
+ synaction->in_vscroll ? "YES" : "NO",
+ synaction->in_vscroll, dxp, dyp,
+ synaction->fingers_nb));
weight_prev_x = weight_prev_y = weight_previous;
div_max_x = div_max_y = div_max;
@@ -3247,6 +3313,7 @@ SYNAPTICS_END:
* That's why the horizontal wheel is disabled by
* default for now.
*/
+
if (ms->button & MOUSE_BUTTON4DOWN) {
*z = -1;
ms->button &= ~MOUSE_BUTTON4DOWN;
@@ -3460,7 +3527,7 @@ psmsoftintr(void *arg)
c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
((y < 0) ? MOUSE_PS2_YNEG : 0);
break;
-
+
case MOUSE_MODEL_4D:
/*
* b7 b6 b5 b4 b3 b2 b1 b0
@@ -4084,6 +4151,10 @@ synaptics_sysctl(SYSCTL_HANDLER_ARGS)
if (arg < -6143 || arg > 6143)
return (EINVAL);
break;
+ case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
+ if (arg < 0 || arg > 1)
+ return (EINVAL);
+ break;
default:
return (EINVAL);
}
@@ -4108,13 +4179,29 @@ synaptics_sysctl_create_tree(struct psm_softc *sc)
0, "Synaptics TouchPad");
/* hw.psm.synaptics.directional_scrolls. */
- sc->syninfo.directional_scrolls = 1;
+ sc->syninfo.directional_scrolls = 0;
SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
"directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
&sc->syninfo.directional_scrolls, 0,
"Enable hardware scrolling pad (if non-zero) or register it as "
- "a middle-click (if 0)");
+ "extended buttons (if 0)");
+
+ /*
+ * Turn off two finger scroll if we have a
+ * physical area reserved for scrolling or when
+ * there's no multi finger support.
+ */
+ if (sc->synhw.verticalScroll || sc->synhw.capMultiFinger == 0)
+ sc->syninfo.two_finger_scroll = 0;
+ else
+ sc->syninfo.two_finger_scroll = 1;
+ /* hw.psm.synaptics.two_finger_scroll. */
+ SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
+ SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+ "two_finger_scroll", CTLFLAG_RW|CTLFLAG_ANYBODY,
+ &sc->syninfo.two_finger_scroll, 0,
+ "Enable two finger scrolling");
/* hw.psm.synaptics.min_pressure. */
sc->syninfo.min_pressure = 16;
@@ -4395,6 +4482,15 @@ synaptics_sysctl_create_tree(struct psm_softc *sc)
&sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
synaptics_sysctl, "I",
"Divisor for slow scrolling");
+
+ /* hw.psm.synaptics.touchpad_off. */
+ sc->syninfo.touchpad_off = 0;
+ SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+ SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+ "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+ &sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
+ synaptics_sysctl, "I",
+ "Turn off touchpad");
}
static int
@@ -4483,8 +4579,12 @@ enable_synaptics(KBDC kbdc, struct psm_softc *sc)
synhw.nExtendedQueries = (status[0] & 0x70) != 0;
synhw.capMiddle = (status[0] & 0x04) != 0;
synhw.capPassthrough = (status[2] & 0x80) != 0;
+ synhw.capLowPower = (status[2] & 0x40) != 0;
+ synhw.capMultiFingerReport =
+ (status[2] & 0x20) != 0;
synhw.capSleep = (status[2] & 0x10) != 0;
synhw.capFourButtons = (status[2] & 0x08) != 0;
+ synhw.capBallistics = (status[2] & 0x04) != 0;
synhw.capMultiFinger = (status[2] & 0x02) != 0;
synhw.capPalmDetect = (status[2] & 0x01) != 0;
@@ -4495,8 +4595,12 @@ enable_synaptics(KBDC kbdc, struct psm_softc *sc)
printf(" nExtendedQueries: %d\n",
synhw.nExtendedQueries);
printf(" capPassthrough: %d\n", synhw.capPassthrough);
+ printf(" capLowPower: %d\n", synhw.capLowPower);
+ printf(" capMultiFingerReport: %d\n",
+ synhw.capMultiFingerReport);
printf(" capSleep: %d\n", synhw.capSleep);
printf(" capFourButtons: %d\n", synhw.capFourButtons);
+ printf(" capBallistics: %d\n", synhw.capBallistics);
printf(" capMultiFinger: %d\n", synhw.capMultiFinger);
printf(" capPalmDetect: %d\n", synhw.capPalmDetect);
}
@@ -4511,7 +4615,21 @@ enable_synaptics(KBDC kbdc, struct psm_softc *sc)
return (FALSE);
if (get_mouse_status(kbdc, status, 0, 3) != 3)
return (FALSE);
+ synhw.verticalScroll = (status[0] & 0x01) != 0;
+ synhw.horizontalScroll = (status[0] & 0x02) != 0;
+ synhw.verticalWheel = (status[0] & 0x08) != 0;
synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
+ if (verbose >= 2) {
+ printf(" Extended model ID:\n");
+ printf(" verticalScroll: %d\n",
+ synhw.verticalScroll);
+ printf(" horizontalScroll: %d\n",
+ synhw.horizontalScroll);
+ printf(" verticalWheel: %d\n",
+ synhw.verticalWheel);
+ printf(" nExtendedButtons: %d\n",
+ synhw.nExtendedButtons);
+ }
/*
* Add the number of extended buttons to the total
* button support count, including the middle button
@@ -4532,6 +4650,42 @@ enable_synaptics(KBDC kbdc, struct psm_softc *sc)
printf(" No extended capabilities\n");
}
+ /* Read the continued capabilities bits. */
+ if (mouse_ext_command(kbdc, 0xc) != 0 &&
+ get_mouse_status(kbdc, status, 0, 3) == 3) {
+ synhw.capClickPad = (status[1] & 0x01) << 1;
+ synhw.capClickPad |= (status[0] & 0x10) != 0;
+ synhw.capDeluxeLEDs = (status[1] & 0x02) != 0;
+ synhw.noAbsoluteFilter = (status[1] & 0x04) != 0;
+ synhw.capReportsV = (status[1] & 0x08) != 0;
+ synhw.capUniformClickPad = (status[1] & 0x10) != 0;
+ synhw.capReportsMin = (status[1] & 0x20) != 0;
+ synhw.capInterTouch = (status[1] & 0x40) != 0;
+ synhw.capReportsMax = (status[2] & 0x02) != 0;
+ synhw.capClearPad = (status[2] & 0x04) != 0;
+ synhw.capAdvancedGestures = (status[2] & 0x08) != 0;
+ synhw.capCoveredPad = (status[2] & 0x80) != 0;
+
+ if (verbose >= 2) {
+ printf(" Continued capabilities:\n");
+ printf(" capClickPad: %d\n", synhw.capClickPad);
+ printf(" capDeluxeLEDs: %d\n", synhw.capDeluxeLEDs);
+ printf(" noAbsoluteFilter: %d\n",
+ synhw.noAbsoluteFilter);
+ printf(" capReportsV: %d\n", synhw.capReportsV);
+ printf(" capUniformClickPad: %d\n",
+ synhw.capUniformClickPad);
+ printf(" capReportsMin: %d\n", synhw.capReportsMin);
+ printf(" capInterTouch: %d\n", synhw.capInterTouch);
+ printf(" capReportsMax: %d\n", synhw.capReportsMax);
+ printf(" capClearPad: %d\n", synhw.capClearPad);
+ printf(" capAdvancedGestures: %d\n",
+ synhw.capAdvancedGestures);
+ printf(" capCoveredPad: %d\n", synhw.capCoveredPad);
+ }
+ buttons += synhw.capClickPad;
+ }
+
/*
* Add the default number of 3 buttons to the total
* count of supported buttons reported above.
@@ -4568,25 +4722,75 @@ enable_synaptics(KBDC kbdc, struct psm_softc *sc)
VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons));
if (sc != NULL) {
+ if (trackpoint_support && synhw.capPassthrough) {
+ synaptics_passthrough_on(sc);
+ enable_trackpoint(kbdc, sc);
+ synaptics_passthrough_off(sc);
+ }
/* Create sysctl tree. */
synaptics_sysctl_create_tree(sc);
-
sc->hw.buttons = buttons;
}
return (TRUE);
}
+static void
+synaptics_passthrough_on(struct psm_softc *sc)
+{
+ int mode_byte;
+
+ mode_byte = 0xc1 | (1 << 5);
+ VLOG(2, (LOG_NOTICE, "psm: setting pass-through mode. %d\n",
+ mode_byte));
+ mouse_ext_command(sc->kbdc, mode_byte);
+
+ /* "Commit" the Set Mode Byte command sent above. */
+ set_mouse_sampling_rate(sc->kbdc, 20);
+}
+
+static void
+synaptics_passthrough_off(struct psm_softc *sc)
+{
+ int mode_byte;
+
+ mode_byte = 0xc1;
+ VLOG(2, (LOG_NOTICE, "psm: turning pass-through mode off.\n"));
+ set_mouse_scaling(sc->kbdc, 2);
+ set_mouse_scaling(sc->kbdc, 1);
+ mouse_ext_command(sc->kbdc, mode_byte);
+
+ /* "Commit" the Set Mode Byte command sent above. */
+ set_mouse_sampling_rate(sc->kbdc, 20);
+}
+
/* IBM/Lenovo TrackPoint */
static int
-trackpoint_command(KBDC kbdc, int cmd, int loc, int val)
+trackpoint_command(struct psm_softc *sc, int cmd, int loc, int val)
{
const int seq[] = { 0xe2, cmd, loc, val };
int i;
- for (i = 0; i < nitems(seq); i++)
- if (send_aux_command(kbdc, seq[i]) != PSM_ACK)
+ if (sc->synhw.capPassthrough)
+ synaptics_passthrough_on(sc);
+
+ for (i = 0; i < nitems(seq); i++) {
+ if (sc->synhw.capPassthrough &&
+ (seq[i] == 0xff || seq[i] == 0xe7))
+ if (send_aux_command(sc->kbdc, 0xe7) != PSM_ACK) {
+ synaptics_passthrough_off(sc);
+ return (EIO);
+ }
+ if (send_aux_command(sc->kbdc, seq[i]) != PSM_ACK) {
+ if (sc->synhw.capPassthrough)
+ synaptics_passthrough_off(sc);
return (EIO);
+ }
+ }
+
+ if (sc->synhw.capPassthrough)
+ synaptics_passthrough_off(sc);
+
return (0);
}
@@ -4629,7 +4833,7 @@ trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
return (0);
if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1))
return (EINVAL);
- error = trackpoint_command(sc->kbdc, tp[TPMASK] == 0 ? 0x81 : 0x47,
+ error = trackpoint_command(sc, tp[TPMASK] == 0 ? 0x81 : 0x47,
tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]);
if (error != 0)
return (error);
@@ -4652,7 +4856,7 @@ trackpoint_sysctl_create_tree(struct psm_softc *sc)
0, "IBM/Lenovo TrackPoint");
/* hw.psm.trackpoint.sensitivity */
- sc->tpinfo.sensitivity = 0x64;
+ sc->tpinfo.sensitivity = 0x80;
SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
"sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
@@ -4760,6 +4964,25 @@ trackpoint_sysctl_create_tree(struct psm_softc *sc)
"Skip backups from drags");
}
+static void
+set_trackpoint_parameters(struct psm_softc *sc)
+{
+ trackpoint_command(sc, 0x81, 0x4a, sc->tpinfo.sensitivity);
+ trackpoint_command(sc, 0x81, 0x60, sc->tpinfo.uplateau);
+ trackpoint_command(sc, 0x81, 0x4d, sc->tpinfo.inertia);
+ trackpoint_command(sc, 0x81, 0x57, sc->tpinfo.reach);
+ trackpoint_command(sc, 0x81, 0x58, sc->tpinfo.draghys);
+ trackpoint_command(sc, 0x81, 0x59, sc->tpinfo.mindrag);
+ trackpoint_command(sc, 0x81, 0x5a, sc->tpinfo.upthresh);
+ trackpoint_command(sc, 0x81, 0x5c, sc->tpinfo.threshold);
+ trackpoint_command(sc, 0x81, 0x5d, sc->tpinfo.jenks);
+ trackpoint_command(sc, 0x81, 0x5e, sc->tpinfo.ztime);
+ if (sc->tpinfo.pts == 0x01)
+ trackpoint_command(sc, 0x47, 0x2c, 0x01);
+ if (sc->tpinfo.skipback == 0x01)
+ trackpoint_command(sc, 0x47, 0x2d, 0x08);
+}
+
static int
enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
{
@@ -4780,23 +5003,14 @@ enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
/* Create sysctl tree. */
trackpoint_sysctl_create_tree(sc);
- trackpoint_command(kbdc, 0x81, 0x4a, sc->tpinfo.sensitivity);
- trackpoint_command(kbdc, 0x81, 0x4d, sc->tpinfo.inertia);
- trackpoint_command(kbdc, 0x81, 0x60, sc->tpinfo.uplateau);
- trackpoint_command(kbdc, 0x81, 0x57, sc->tpinfo.reach);
- trackpoint_command(kbdc, 0x81, 0x58, sc->tpinfo.draghys);
- trackpoint_command(kbdc, 0x81, 0x59, sc->tpinfo.mindrag);
- trackpoint_command(kbdc, 0x81, 0x5a, sc->tpinfo.upthresh);
- trackpoint_command(kbdc, 0x81, 0x5c, sc->tpinfo.threshold);
- trackpoint_command(kbdc, 0x81, 0x5d, sc->tpinfo.jenks);
- trackpoint_command(kbdc, 0x81, 0x5e, sc->tpinfo.ztime);
- if (sc->tpinfo.pts == 0x01)
- trackpoint_command(kbdc, 0x47, 0x2c, 0x01);
- if (sc->tpinfo.skipback == 0x01)
- trackpoint_command(kbdc, 0x47, 0x2d, 0x08);
-
- sc->hw.hwid = id;
- sc->hw.buttons = 3;
+ /*
+ * Don't overwrite hwid and buttons when we are
+ * a guest device.
+ */
+ if (!sc->synhw.capPassthrough) {
+ sc->hw.hwid = id;
+ sc->hw.buttons = 3;
+ }
}
return (TRUE);
diff --git a/sys/dev/bxe/bxe.h b/sys/dev/bxe/bxe.h
index f37b93f..eb695d0 100644
--- a/sys/dev/bxe/bxe.h
+++ b/sys/dev/bxe/bxe.h
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <sys/limits.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
+#include <sys/zlib.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -60,7 +61,6 @@ __FBSDID("$FreeBSD$");
#include <net/if_var.h>
#include <net/if_media.h>
#include <net/if_vlan_var.h>
-#include <net/zlib.h>
#include <net/bpf.h>
#include <netinet/in.h>
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 40098b8..4bbb55e 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -1571,9 +1571,6 @@ cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
struct ifmedia *media = NULL;
struct ifmedia_entry *cur;
int speed = pi->link_cfg.speed;
-#ifdef INVARIANTS
- int data = (pi->port_type << 8) | pi->mod_type;
-#endif
if (ifp == pi->ifp)
media = &pi->media;
@@ -1584,7 +1581,6 @@ cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
MPASS(media != NULL);
cur = media->ifm_cur;
- MPASS(cur->ifm_data == data);
ifmr->ifm_status = IFM_AVALID;
if (!pi->link_cfg.link_ok)
@@ -2884,30 +2880,29 @@ t4_set_desc(struct adapter *sc)
static void
build_medialist(struct port_info *pi, struct ifmedia *media)
{
- int data, m;
+ int m;
PORT_LOCK(pi);
ifmedia_removeall(media);
m = IFM_ETHER | IFM_FDX;
- data = (pi->port_type << 8) | pi->mod_type;
switch(pi->port_type) {
case FW_PORT_TYPE_BT_XFI:
case FW_PORT_TYPE_BT_XAUI:
- ifmedia_add(media, m | IFM_10G_T, data, NULL);
+ ifmedia_add(media, m | IFM_10G_T, 0, NULL);
/* fall through */
case FW_PORT_TYPE_BT_SGMII:
- ifmedia_add(media, m | IFM_1000_T, data, NULL);
- ifmedia_add(media, m | IFM_100_TX, data, NULL);
- ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL);
+ ifmedia_add(media, m | IFM_1000_T, 0, NULL);
+ ifmedia_add(media, m | IFM_100_TX, 0, NULL);
+ ifmedia_add(media, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(media, IFM_ETHER | IFM_AUTO);
break;
case FW_PORT_TYPE_CX4:
- ifmedia_add(media, m | IFM_10G_CX4, data, NULL);
+ ifmedia_add(media, m | IFM_10G_CX4, 0, NULL);
ifmedia_set(media, m | IFM_10G_CX4);
break;
@@ -2918,29 +2913,29 @@ build_medialist(struct port_info *pi, struct ifmedia *media)
switch (pi->mod_type) {
case FW_PORT_MOD_TYPE_LR:
- ifmedia_add(media, m | IFM_10G_LR, data, NULL);
+ ifmedia_add(media, m | IFM_10G_LR, 0, NULL);
ifmedia_set(media, m | IFM_10G_LR);
break;
case FW_PORT_MOD_TYPE_SR:
- ifmedia_add(media, m | IFM_10G_SR, data, NULL);
+ ifmedia_add(media, m | IFM_10G_SR, 0, NULL);
ifmedia_set(media, m | IFM_10G_SR);
break;
case FW_PORT_MOD_TYPE_LRM:
- ifmedia_add(media, m | IFM_10G_LRM, data, NULL);
+ ifmedia_add(media, m | IFM_10G_LRM, 0, NULL);
ifmedia_set(media, m | IFM_10G_LRM);
break;
case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
- ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL);
+ ifmedia_add(media, m | IFM_10G_TWINAX, 0, NULL);
ifmedia_set(media, m | IFM_10G_TWINAX);
break;
case FW_PORT_MOD_TYPE_NONE:
m &= ~IFM_FDX;
- ifmedia_add(media, m | IFM_NONE, data, NULL);
+ ifmedia_add(media, m | IFM_NONE, 0, NULL);
ifmedia_set(media, m | IFM_NONE);
break;
@@ -2950,7 +2945,7 @@ build_medialist(struct port_info *pi, struct ifmedia *media)
device_printf(pi->dev,
"unknown port_type (%d), mod_type (%d)\n",
pi->port_type, pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
+ ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
ifmedia_set(media, m | IFM_UNKNOWN);
break;
}
@@ -2960,24 +2955,24 @@ build_medialist(struct port_info *pi, struct ifmedia *media)
switch (pi->mod_type) {
case FW_PORT_MOD_TYPE_LR:
- ifmedia_add(media, m | IFM_40G_LR4, data, NULL);
+ ifmedia_add(media, m | IFM_40G_LR4, 0, NULL);
ifmedia_set(media, m | IFM_40G_LR4);
break;
case FW_PORT_MOD_TYPE_SR:
- ifmedia_add(media, m | IFM_40G_SR4, data, NULL);
+ ifmedia_add(media, m | IFM_40G_SR4, 0, NULL);
ifmedia_set(media, m | IFM_40G_SR4);
break;
case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
- ifmedia_add(media, m | IFM_40G_CR4, data, NULL);
+ ifmedia_add(media, m | IFM_40G_CR4, 0, NULL);
ifmedia_set(media, m | IFM_40G_CR4);
break;
case FW_PORT_MOD_TYPE_NONE:
m &= ~IFM_FDX;
- ifmedia_add(media, m | IFM_NONE, data, NULL);
+ ifmedia_add(media, m | IFM_NONE, 0, NULL);
ifmedia_set(media, m | IFM_NONE);
break;
@@ -2985,7 +2980,7 @@ build_medialist(struct port_info *pi, struct ifmedia *media)
device_printf(pi->dev,
"unknown port_type (%d), mod_type (%d)\n",
pi->port_type, pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
+ ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
ifmedia_set(media, m | IFM_UNKNOWN);
break;
}
@@ -2995,7 +2990,7 @@ build_medialist(struct port_info *pi, struct ifmedia *media)
device_printf(pi->dev,
"unknown port_type (%d), mod_type (%d)\n", pi->port_type,
pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
+ ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
ifmedia_set(media, m | IFM_UNKNOWN);
break;
}
diff --git a/sys/dev/cxgbe/tom/t4_listen.c b/sys/dev/cxgbe/tom/t4_listen.c
index e6cbfe4..fc5f935 100644
--- a/sys/dev/cxgbe/tom/t4_listen.c
+++ b/sys/dev/cxgbe/tom/t4_listen.c
@@ -1090,35 +1090,6 @@ pass_accept_req_to_protohdrs(const struct mbuf *m, struct in_conninfo *inc,
}
}
-static int
-ifnet_has_ip6(struct ifnet *ifp, struct in6_addr *ip6)
-{
- struct ifaddr *ifa;
- struct sockaddr_in6 *sin6;
- int found = 0;
- struct in6_addr in6 = *ip6;
-
- /* Just as in ip6_input */
- if (in6_clearscope(&in6) || in6_clearscope(&in6))
- return (0);
- in6_setscope(&in6, ifp, NULL);
-
- if_addr_rlock(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- sin6 = (void *)ifa->ifa_addr;
- if (sin6->sin6_family != AF_INET6)
- continue;
-
- if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6)) {
- found = 1;
- break;
- }
- }
- if_addr_runlock(ifp);
-
- return (found);
-}
-
static struct l2t_entry *
get_l2te_for_nexthop(struct port_info *pi, struct ifnet *ifp,
struct in_conninfo *inc)
@@ -1166,29 +1137,6 @@ get_l2te_for_nexthop(struct port_info *pi, struct ifnet *ifp,
return (e);
}
-static int
-ifnet_has_ip(struct ifnet *ifp, struct in_addr in)
-{
- struct ifaddr *ifa;
- struct sockaddr_in *sin;
- int found = 0;
-
- if_addr_rlock(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- sin = (void *)ifa->ifa_addr;
- if (sin->sin_family != AF_INET)
- continue;
-
- if (sin->sin_addr.s_addr == in.s_addr) {
- found = 1;
- break;
- }
- }
- if_addr_runlock(ifp);
-
- return (found);
-}
-
#define REJECT_PASS_ACCEPT() do { \
reject_reason = __LINE__; \
goto reject; \
@@ -1281,7 +1229,7 @@ do_pass_accept_req(struct sge_iq *iq, const struct rss_header *rss,
* SYN must be directed to an IP6 address on this ifnet. This
* is more restrictive than in6_localip.
*/
- if (!ifnet_has_ip6(ifp, &inc.inc6_laddr))
+ if (!in6_ifhasaddr(ifp, &inc.inc6_laddr))
REJECT_PASS_ACCEPT();
} else {
@@ -1293,7 +1241,7 @@ do_pass_accept_req(struct sge_iq *iq, const struct rss_header *rss,
* SYN must be directed to an IP address on this ifnet. This
* is more restrictive than in_localip.
*/
- if (!ifnet_has_ip(ifp, inc.inc_laddr))
+ if (!in_ifhasaddr(ifp, inc.inc_laddr))
REJECT_PASS_ACCEPT();
}
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index 4e2f9ed..6ac6eb6 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -1046,8 +1046,7 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr)
}
drbr_advance(ifp, txr->br);
enq++;
- if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len);
- if (next->m_flags & M_MCAST)
+ if (next->m_flags & M_MCAST && adapter->vf_ifp)
if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
ETHER_BPF_MTAP(ifp, next);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
@@ -4055,7 +4054,9 @@ static bool
igb_txeof(struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
+#ifdef DEV_NETMAP
struct ifnet *ifp = adapter->ifp;
+#endif /* DEV_NETMAP */
u32 work, processed = 0;
u16 limit = txr->process_limit;
struct igb_tx_buf *buf;
@@ -4130,7 +4131,6 @@ igb_txeof(struct tx_ring *txr)
}
++txr->packets;
++processed;
- if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
txr->watchdog_time = ticks;
/* Try the next packet */
@@ -4630,8 +4630,11 @@ igb_initialise_rss_mapping(struct adapter *adapter)
/* Now fill in hash table */
- /* XXX This means RSS enable + 8 queues for my igb (82580.) */
- mrqc = E1000_MRQC_ENABLE_RSS_4Q;
+ /*
+ * MRQC: Multiple Receive Queues Command
+ * Set queuing to RSS control, number depends on the device.
+ */
+ mrqc = E1000_MRQC_ENABLE_RSS_8Q;
#ifdef RSS
/* XXX ew typecasting */
@@ -5124,7 +5127,6 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
if (eop) {
rxr->fmp->m_pkthdr.rcvif = ifp;
- if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
rxr->rx_packets++;
/* capture data for AIM */
rxr->packets++;
@@ -5139,45 +5141,51 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
rxr->fmp->m_pkthdr.ether_vtag = vtag;
rxr->fmp->m_flags |= M_VLANTAG;
}
-#ifdef RSS
- /* XXX set flowtype once this works right */
- rxr->fmp->m_pkthdr.flowid =
- le32toh(cur->wb.lower.hi_dword.rss);
- switch (pkt_info & E1000_RXDADV_RSSTYPE_MASK) {
- case E1000_RXDADV_RSSTYPE_IPV4_TCP:
- M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_RSS_TCP_IPV4);
- break;
- case E1000_RXDADV_RSSTYPE_IPV4:
- M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_RSS_IPV4);
- break;
- case E1000_RXDADV_RSSTYPE_IPV6_TCP:
- M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_RSS_TCP_IPV6);
- break;
- case E1000_RXDADV_RSSTYPE_IPV6_EX:
- M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_RSS_IPV6_EX);
- break;
- case E1000_RXDADV_RSSTYPE_IPV6:
- M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_RSS_IPV6);
- break;
- case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX:
- M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_RSS_TCP_IPV6_EX);
- break;
- /* XXX no UDP support in RSS just yet */
-#ifdef notyet
- case E1000_RXDADV_RSSTYPE_IPV4_UDP:
- case E1000_RXDADV_RSSTYPE_IPV6_UDP:
- case E1000_RXDADV_RSSTYPE_IPV6_UDP_EX:
-#endif
-
- default:
- /* XXX fallthrough */
+ /*
+ * In case of multiqueue, we have RXCSUM.PCSD bit set
+ * and never cleared. This means we have RSS hash
+ * available to be used.
+ */
+ if (adapter->num_queues > 1) {
+ rxr->fmp->m_pkthdr.flowid =
+ le32toh(cur->wb.lower.hi_dword.rss);
+ switch (pkt_info & E1000_RXDADV_RSSTYPE_MASK) {
+ case E1000_RXDADV_RSSTYPE_IPV4_TCP:
+ M_HASHTYPE_SET(rxr->fmp,
+ M_HASHTYPE_RSS_TCP_IPV4);
+ break;
+ case E1000_RXDADV_RSSTYPE_IPV4:
+ M_HASHTYPE_SET(rxr->fmp,
+ M_HASHTYPE_RSS_IPV4);
+ break;
+ case E1000_RXDADV_RSSTYPE_IPV6_TCP:
+ M_HASHTYPE_SET(rxr->fmp,
+ M_HASHTYPE_RSS_TCP_IPV6);
+ break;
+ case E1000_RXDADV_RSSTYPE_IPV6_EX:
+ M_HASHTYPE_SET(rxr->fmp,
+ M_HASHTYPE_RSS_IPV6_EX);
+ break;
+ case E1000_RXDADV_RSSTYPE_IPV6:
+ M_HASHTYPE_SET(rxr->fmp,
+ M_HASHTYPE_RSS_IPV6);
+ break;
+ case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX:
+ M_HASHTYPE_SET(rxr->fmp,
+ M_HASHTYPE_RSS_TCP_IPV6_EX);
+ break;
+ default:
+ /* XXX fallthrough */
+ M_HASHTYPE_SET(rxr->fmp,
+ M_HASHTYPE_OPAQUE);
+ }
+ } else {
+#ifndef IGB_LEGACY_TX
+ rxr->fmp->m_pkthdr.flowid = que->msix;
M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_OPAQUE);
- }
-#elif !defined(IGB_LEGACY_TX)
- rxr->fmp->m_pkthdr.flowid = que->msix;
- M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_OPAQUE);
#endif
+ }
sendmp = rxr->fmp;
/* Make sure to set M_PKTHDR. */
sendmp->m_flags |= M_PKTHDR;
@@ -5551,24 +5559,94 @@ igb_led_func(void *arg, int onoff)
}
static uint64_t
+igb_get_vf_counter(if_t ifp, ift_counter cnt)
+{
+ struct adapter *adapter;
+ struct e1000_vf_stats *stats;
+#ifndef IGB_LEGACY_TX
+ struct tx_ring *txr;
+ uint64_t rv;
+#endif
+
+ adapter = if_getsoftc(ifp);
+ stats = (struct e1000_vf_stats *)adapter->stats;
+
+ switch (cnt) {
+ case IFCOUNTER_IPACKETS:
+ return (stats->gprc);
+ case IFCOUNTER_OPACKETS:
+ return (stats->gptc);
+ case IFCOUNTER_IBYTES:
+ return (stats->gorc);
+ case IFCOUNTER_OBYTES:
+ return (stats->gotc);
+ case IFCOUNTER_IMCASTS:
+ return (stats->mprc);
+ case IFCOUNTER_IERRORS:
+ return (adapter->dropped_pkts);
+ case IFCOUNTER_OERRORS:
+ return (adapter->watchdog_events);
+#ifndef IGB_LEGACY_TX
+ case IFCOUNTER_OQDROPS:
+ rv = 0;
+ txr = adapter->tx_rings;
+ for (int i = 0; i < adapter->num_queues; i++, txr++)
+ rv += txr->br->br_drops;
+ return (rv);
+#endif
+ default:
+ return (if_get_counter_default(ifp, cnt));
+ }
+}
+
+static uint64_t
igb_get_counter(if_t ifp, ift_counter cnt)
{
struct adapter *adapter;
struct e1000_hw_stats *stats;
+#ifndef IGB_LEGACY_TX
+ struct tx_ring *txr;
+ uint64_t rv;
+#endif
adapter = if_getsoftc(ifp);
+ if (adapter->vf_ifp)
+ return (igb_get_vf_counter(ifp, cnt));
+
stats = (struct e1000_hw_stats *)adapter->stats;
switch (cnt) {
+ case IFCOUNTER_IPACKETS:
+ return (stats->gprc);
+ case IFCOUNTER_OPACKETS:
+ return (stats->gptc);
+ case IFCOUNTER_IBYTES:
+ return (stats->gorc);
+ case IFCOUNTER_OBYTES:
+ return (stats->gotc);
+ case IFCOUNTER_IMCASTS:
+ return (stats->mprc);
+ case IFCOUNTER_OMCASTS:
+ return (stats->mptc);
case IFCOUNTER_IERRORS:
return (adapter->dropped_pkts + stats->rxerrc +
stats->crcerrs + stats->algnerrc +
- stats->ruc + stats->roc + stats->mpc + stats->cexterr);
+ stats->ruc + stats->roc + stats->cexterr);
case IFCOUNTER_OERRORS:
return (stats->ecol + stats->latecol +
adapter->watchdog_events);
case IFCOUNTER_COLLISIONS:
return (stats->colc);
+ case IFCOUNTER_IQDROPS:
+ return (stats->mpc);
+#ifndef IGB_LEGACY_TX
+ case IFCOUNTER_OQDROPS:
+ rv = 0;
+ txr = adapter->tx_rings;
+ for (int i = 0; i < adapter->num_queues; i++, txr++)
+ rv += txr->br->br_drops;
+ return (rv);
+#endif
default:
return (if_get_counter_default(ifp, cnt));
}
diff --git a/sys/dev/etherswitch/miiproxy.c b/sys/dev/etherswitch/miiproxy.c
index f05b121..b0f2398 100644
--- a/sys/dev/etherswitch/miiproxy.c
+++ b/sys/dev/etherswitch/miiproxy.c
@@ -62,35 +62,35 @@ struct mdioproxy_softc {
};
/*
- * The rendevous data structures and functions allow two device endpoints to
+ * The rendezvous data structures and functions allow two device endpoints to
* match up, so that the proxy endpoint can be associated with a target
* endpoint. The proxy has to know the device name of the target that it
- * wants to associate with, for example through a hint. The rendevous code
+ * wants to associate with, for example through a hint. The rendezvous code
* makes no assumptions about the devices that want to meet.
*/
-struct rendevous_entry;
+struct rendezvous_entry;
-enum rendevous_op {
- RENDEVOUS_ATTACH,
- RENDEVOUS_DETACH
+enum rendezvous_op {
+ RENDEZVOUS_ATTACH,
+ RENDEZVOUS_DETACH
};
-typedef int (*rendevous_callback_t)(enum rendevous_op,
- struct rendevous_entry *);
+typedef int (*rendezvous_callback_t)(enum rendezvous_op,
+ struct rendezvous_entry *);
-static SLIST_HEAD(rendevoushead, rendevous_entry) rendevoushead =
- SLIST_HEAD_INITIALIZER(rendevoushead);
+static SLIST_HEAD(rendezvoushead, rendezvous_entry) rendezvoushead =
+ SLIST_HEAD_INITIALIZER(rendezvoushead);
-struct rendevous_endpoint {
+struct rendezvous_endpoint {
device_t device;
const char *name;
- rendevous_callback_t callback;
+ rendezvous_callback_t callback;
};
-struct rendevous_entry {
- SLIST_ENTRY(rendevous_entry) entries;
- struct rendevous_endpoint proxy;
- struct rendevous_endpoint target;
+struct rendezvous_entry {
+ SLIST_ENTRY(rendezvous_entry) entries;
+ struct rendezvous_endpoint proxy;
+ struct rendezvous_endpoint target;
};
/*
@@ -98,15 +98,15 @@ struct rendevous_entry {
* returns an error, undo the attachment.
*/
static int
-rendevous_attach(struct rendevous_entry *e, struct rendevous_endpoint *ep)
+rendezvous_attach(struct rendezvous_entry *e, struct rendezvous_endpoint *ep)
{
int error;
- error = e->proxy.callback(RENDEVOUS_ATTACH, e);
+ error = e->proxy.callback(RENDEZVOUS_ATTACH, e);
if (error == 0) {
- error = e->target.callback(RENDEVOUS_ATTACH, e);
+ error = e->target.callback(RENDEZVOUS_ATTACH, e);
if (error != 0) {
- e->proxy.callback(RENDEVOUS_DETACH, e);
+ e->proxy.callback(RENDEZVOUS_DETACH, e);
ep->device = NULL;
ep->callback = NULL;
}
@@ -115,27 +115,27 @@ rendevous_attach(struct rendevous_entry *e, struct rendevous_endpoint *ep)
}
/*
- * Create an entry for the proxy in the rendevous list. The name parameter
+ * Create an entry for the proxy in the rendezvous list. The name parameter
* indicates the name of the device that is the target endpoint for this
- * rendevous. The callback will be invoked as soon as the target is
+ * rendezvous. The callback will be invoked as soon as the target is
* registered: either immediately if the target registered itself earlier,
* or once the target registers. Returns ENXIO if the target has not yet
* registered.
*/
static int
-rendevous_register_proxy(device_t dev, const char *name,
- rendevous_callback_t callback)
+rendezvous_register_proxy(device_t dev, const char *name,
+ rendezvous_callback_t callback)
{
- struct rendevous_entry *e;
+ struct rendezvous_entry *e;
KASSERT(callback != NULL, ("callback must be set"));
- SLIST_FOREACH(e, &rendevoushead, entries) {
+ SLIST_FOREACH(e, &rendezvoushead, entries) {
if (strcmp(name, e->target.name) == 0) {
/* the target is already attached */
e->proxy.name = device_get_nameunit(dev);
e->proxy.device = dev;
e->proxy.callback = callback;
- return (rendevous_attach(e, &e->proxy));
+ return (rendezvous_attach(e, &e->proxy));
}
}
e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
@@ -143,34 +143,34 @@ rendevous_register_proxy(device_t dev, const char *name,
e->proxy.device = dev;
e->proxy.callback = callback;
e->target.name = name;
- SLIST_INSERT_HEAD(&rendevoushead, e, entries);
+ SLIST_INSERT_HEAD(&rendezvoushead, e, entries);
return (ENXIO);
}
/*
- * Create an entry in the rendevous list for the target.
+ * Create an entry in the rendezvous list for the target.
* Returns ENXIO if the proxy has not yet registered.
*/
static int
-rendevous_register_target(device_t dev, rendevous_callback_t callback)
+rendezvous_register_target(device_t dev, rendezvous_callback_t callback)
{
- struct rendevous_entry *e;
+ struct rendezvous_entry *e;
const char *name;
-
+
KASSERT(callback != NULL, ("callback must be set"));
name = device_get_nameunit(dev);
- SLIST_FOREACH(e, &rendevoushead, entries) {
+ SLIST_FOREACH(e, &rendezvoushead, entries) {
if (strcmp(name, e->target.name) == 0) {
e->target.device = dev;
e->target.callback = callback;
- return (rendevous_attach(e, &e->target));
+ return (rendezvous_attach(e, &e->target));
}
}
e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
e->target.name = name;
e->target.device = dev;
e->target.callback = callback;
- SLIST_INSERT_HEAD(&rendevoushead, e, entries);
+ SLIST_INSERT_HEAD(&rendezvoushead, e, entries);
return (ENXIO);
}
@@ -178,20 +178,20 @@ rendevous_register_target(device_t dev, rendevous_callback_t callback)
* Remove the registration for the proxy.
*/
static int
-rendevous_unregister_proxy(device_t dev)
+rendezvous_unregister_proxy(device_t dev)
{
- struct rendevous_entry *e;
+ struct rendezvous_entry *e;
int error = 0;
-
- SLIST_FOREACH(e, &rendevoushead, entries) {
+
+ SLIST_FOREACH(e, &rendezvoushead, entries) {
if (e->proxy.device == dev) {
if (e->target.device == NULL) {
- SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries);
+ SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
free(e, M_MIIPROXY);
return (0);
} else {
- e->proxy.callback(RENDEVOUS_DETACH, e);
- e->target.callback(RENDEVOUS_DETACH, e);
+ e->proxy.callback(RENDEZVOUS_DETACH, e);
+ e->target.callback(RENDEZVOUS_DETACH, e);
}
e->proxy.device = NULL;
e->proxy.callback = NULL;
@@ -205,20 +205,20 @@ rendevous_unregister_proxy(device_t dev)
* Remove the registration for the target.
*/
static int
-rendevous_unregister_target(device_t dev)
+rendezvous_unregister_target(device_t dev)
{
- struct rendevous_entry *e;
+ struct rendezvous_entry *e;
int error = 0;
-
- SLIST_FOREACH(e, &rendevoushead, entries) {
+
+ SLIST_FOREACH(e, &rendezvoushead, entries) {
if (e->target.device == dev) {
if (e->proxy.device == NULL) {
- SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries);
+ SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
free(e, M_MIIPROXY);
return (0);
} else {
- e->proxy.callback(RENDEVOUS_DETACH, e);
- e->target.callback(RENDEVOUS_DETACH, e);
+ e->proxy.callback(RENDEZVOUS_DETACH, e);
+ e->target.callback(RENDEZVOUS_DETACH, e);
}
e->target.device = NULL;
e->target.callback = NULL;
@@ -234,15 +234,15 @@ rendevous_unregister_target(device_t dev)
*/
static int
-miiproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous)
+miiproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
{
- struct miiproxy_softc *sc = device_get_softc(rendevous->proxy.device);
+ struct miiproxy_softc *sc = device_get_softc(rendezvous->proxy.device);
switch (op) {
- case RENDEVOUS_ATTACH:
- sc->mdio = device_get_parent(rendevous->target.device);
+ case RENDEZVOUS_ATTACH:
+ sc->mdio = device_get_parent(rendezvous->target.device);
break;
- case RENDEVOUS_DETACH:
+ case RENDEZVOUS_DETACH:
sc->mdio = NULL;
break;
}
@@ -263,7 +263,7 @@ miiproxy_attach(device_t dev)
/*
* The ethernet interface needs to call mii_attach_proxy() to pass
- * the relevant parameters for rendevous with the MDIO target.
+ * the relevant parameters for rendezvous with the MDIO target.
*/
return (bus_generic_attach(dev));
}
@@ -272,7 +272,7 @@ static int
miiproxy_detach(device_t dev)
{
- rendevous_unregister_proxy(dev);
+ rendezvous_unregister_proxy(dev);
bus_generic_detach(dev);
return (0);
}
@@ -322,7 +322,7 @@ miiproxy_mediainit(device_t dev)
* Functions for the MDIO target device driver.
*/
static int
-mdioproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous)
+mdioproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
{
return (0);
}
@@ -349,7 +349,7 @@ static int
mdioproxy_attach(device_t dev)
{
- rendevous_register_target(dev, mdioproxy_rendevous_callback);
+ rendezvous_register_target(dev, mdioproxy_rendezvous_callback);
return (bus_generic_attach(dev));
}
@@ -357,7 +357,7 @@ static int
mdioproxy_detach(device_t dev)
{
- rendevous_unregister_target(dev);
+ rendezvous_unregister_target(dev);
bus_generic_detach(dev);
return (0);
}
@@ -373,7 +373,7 @@ mii_attach_proxy(device_t dev)
int error;
const char *name;
device_t miiproxy;
-
+
if (resource_string_value(device_get_name(dev),
device_get_unit(dev), "mdio", &name) != 0) {
if (bootverbose)
@@ -391,7 +391,7 @@ mii_attach_proxy(device_t dev)
sc = device_get_softc(miiproxy);
sc->parent = dev;
sc->proxy = miiproxy;
- if (rendevous_register_proxy(miiproxy, name, miiproxy_rendevous_callback) != 0) {
+ if (rendezvous_register_proxy(miiproxy, name, miiproxy_rendezvous_callback) != 0) {
device_printf(dev, "can't attach proxy\n");
return (NULL);
}
diff --git a/sys/dev/fdt/fdt_arm64.c b/sys/dev/fdt/fdt_arm64.c
new file mode 100644
index 0000000..fc98f51
--- /dev/null
+++ b/sys/dev/fdt/fdt_arm64.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include "ofw_bus_if.h"
+#include "fdt_common.h"
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
diff --git a/sys/dev/fdt/fdt_pinctrl.c b/sys/dev/fdt/fdt_pinctrl.c
index 0a0dd84..b4d33c9 100644
--- a/sys/dev/fdt/fdt_pinctrl.c
+++ b/sys/dev/fdt/fdt_pinctrl.c
@@ -46,7 +46,7 @@ fdt_pinctrl_configure(device_t client, u_int index)
char name[16];
snprintf(name, sizeof(name), "pinctrl-%u", index);
- nconfigs = OF_getprop_alloc(ofw_bus_get_node(client), name,
+ nconfigs = OF_getencprop_alloc(ofw_bus_get_node(client), name,
sizeof(*configs), (void **)&configs);
if (nconfigs < 0)
return (ENOENT);
@@ -122,12 +122,12 @@ pinctrl_configure_children(device_t pinctrl, phandle_t parent)
if (!fdt_is_enabled(node))
continue;
pinctrl_configure_children(pinctrl, node);
- nconfigs = OF_getencprop_alloc(node, "pinctrl-0",
+ nconfigs = OF_getencprop_alloc(node, "pinctrl-0",
sizeof(*configs), (void **)&configs);
if (nconfigs <= 0)
continue;
if (bootverbose) {
- char name[32];
+ char name[32];
OF_getprop(node, "name", &name, sizeof(name));
printf("Processing %d pin-config node(s) in pinctrl-0 for %s\n",
nconfigs, name);
diff --git a/sys/dev/hptnr/README b/sys/dev/hptnr/README
index 150994a..a490026 100644
--- a/sys/dev/hptnr/README
+++ b/sys/dev/hptnr/README
@@ -1,8 +1,16 @@
Rocket Controller Driver for FreeBSD
-Copyright (C) 2014 HighPoint Technologies, Inc. All rights reserved.
+Copyright (C) 2015 HighPoint Technologies, Inc. All rights reserved.
#############################################################################
Revision History:
+ v1.1.1 2015-03-26
+ * Support 4Kn drive.
+ * Change the SCSI target ID of the disk to be the index of physical connetion to the HBA.
+ * Support staggered drive spin up.
+ * Fix a bug that command would be timeout because of improper interrupt service routine.
+ * Error handling to avoid scsi command lost which caused system hang up.
+ * Fix a bug that fail to get the devcie's serial number via FreeNAS WebGUI.
+
v1.0.1 2014-8-19
* Do not retry the command and reset the disk when failed to enable or
disable spin up feature.
@@ -13,7 +21,7 @@ Revision History:
* Support smartmontool for R750.
v1.0 2013-7-3
- *First source code release
+ First source code release
#############################################################################
@@ -49,7 +57,7 @@ Revision History:
2) Extract the driver files under the kernel source tree:
# cd /usr/src/sys/
- # tar xvzf /your/path/to/hptnr_freebsd_src_v1.0.1_14_08_19.tgz
+ # tar xvzf /your/path/to/hptnr-freebsd-src-v1.0-130701.tgz
3) Update the kernel configuration file to include the HighPoint source.
Assume the configure file is GENERIC, and new kernel configure file is
diff --git a/sys/dev/hptnr/amd64-elf.hptnr_lib.o.uu b/sys/dev/hptnr/amd64-elf.hptnr_lib.o.uu
index 4f01b04..00334cf 100644
--- a/sys/dev/hptnr/amd64-elf.hptnr_lib.o.uu
+++ b/sys/dev/hptnr/amd64-elf.hptnr_lib.o.uu
@@ -1,6297 +1,4969 @@
begin 644 hptnr_lib.o
-M?T5,1@(!`0D```````````$`/@`!`````````````````````````+`#!@``
-M`````````$```````$``$``-`(G0Q@<(QD<!$D"$]G0&@$\"!.L$@&<"^X3`
-M=`:`9PS?ZP2`3PP@N!0```##9F9FD//#9F9FD&9F9I!F9I!F9I!!5T%6055!
-M5%532(/L&$F)_4F)]DB)U8A,)`=%B<=(BT8P2(E$)!!(QT8P`````$B%P`^%
-M=`$``.@`````28G$N`````!-A>0/A!$"``!,B>_H`````$B)1"002(7`=15,
-MB>9,B>_H`````+@`````Z>H!``!!QD0D.!I!QD0D.0A!QD0D.@A!QD0D.P!!
-MQD0D//]!QD0D/0!!QD0D):M!#[=&.&9!B40D($V);"0H0<=$)#3_````0<>$
-M))0````(````2(M$)!!(BT`028E$)$A(!?\```!)B40D4$'&1"0P)$B+1"00
-M28E$)'A)QX0DH`````````!!QD0D)(!)C5PD6+X`````2(G?Z`````!(BT0D
-M$$B+<!BZ_P```$B)W^@`````3(GF3(GOZ`````"[R/___^L@9F9FD&9FD+_H
-M`P``Z`````"#ZP%,B>_H`````(3;=`Y!#[9$)"0\@'3=A,!T,4B-="003(GO
-MZ`````!!#[=T)#))BWY0Z`````!,B>9,B>_H`````+@`````Z<<```!)QT0D
-M>`````!,B>9,B>_H`````$B+1"002(M8$$$/MM</MG0D!TB->P3H`````$&)
-MQ,8#`,9#`0#&0P(`QD,#`$B)[DR)[^@`````2(U5.+@`````9F:0Q@00`$B#
-MP`%(@_@0=?)!C40D!,9%.!7&13D1B$4\QD4]`$B-75A$#[;@1(EE-,>%E```
-M``````!(BU0D$$B+0A!(B45(2(E5>+X`````2(G?Z`````!(BT0D$$B+<!A$
-MB>)(B=_H`````+@!````2(/$&%M=05Q!74%>05_#D)")\&:)=PC&1PX`9L='
-M#```9H7V=!^-4/^Y`````&9FD$B+!V:)%`A(@\$"@^H!9H/Z_W7L\\-F9F:0
-M9F:09F:008GP9HEW",9'#@%FQT<,``!FA?9T'KH`````N0````!(BP=FB10(
-M@\(!2(/!`F9$.<)U[//#9F9FD&9FD&9FD(!_#@%U*@^W1PP/M\A(BQ</MQ1*
-M@\`!9HE'#&8[1PIR!F;'1PP``&:#;P@!#[?"PTB+%P^W1PB#Z`%FB4<(#[?`
-M#[<$0L-F9F:09F:09F:0@'\.`74J#[=7"`^W1PP!P@^W1PJ)P8G0P?H?]_E(
-M8])(BP=FB3109H-'"`'#9F:0#[='"`^WR$B+%V:)-$J#P`%FB4<(PV9F9I!F
-M9I!F9I!F@W\(``^4P`^VP,.0D)"02(L/2#G/=0BY`````.L/D$B+$4B+00A(
-MB4((2(D02(G(PV9F9I!F9F:09F:09F:008G0A-)T.@^V!SH&=2A(B?&^````
-M`.L4#[97`0^V00%(@\<!2(/!`3C"=0J#Q@%$.,9UY.L+N`````!F9I!FD,.X
-M`0```,-F9I!F9I!F9I#&1P$`0(AW`L='!`````##08G0#[97`0^VPDB-!$!(
-MP>`"2(G!2`-/"(/"`8A7`40!1P2X`````,8$"`!(@\`!2(/X#'7R2(DQ1(A!
-M"$R)P@^VQHA!"42)PL'J$(/B/P^V00J#X,`)T(A!"L-F9F:0#[9'`3H'#Y+`
-M#[;`PV9FD$B)^;@`````@'D"_W4(9HDQB%$"ZPV#P`%(@\$$9CV``'7E#[?`
-MPV9FD&9FD&9FD$&)T`^WQDB-!(>`>`+_=1!F1(D`B$@"#[?&PV9FD&:0#[;1
-M00^W\.@`````#[?`PTB)^;@`````.%$"=1-F.3%U#L9!`O]FQP'__^L09F:0
-M@\`!2(/!!&8]@`!UVP^WP,-F9F:09F9FD&9F9I!F9I"X`````(G!.%2'`G4&
-M9CDTAW0/@\$!2(/``4@]@````'7C9H'Y@`"X@`$```]$R`^WP<-F9F:09F:0
-M9F:09F:0#[9'.#P(=#X\*'0Z/*@/A/\````\B`^$.0$``#P*9I!T)#PJ="`\
-MJ@^$Y0```#R*#X0?`0``/"]T##R/9F9FD`^%E`$``#PO#X22````/"]W(CP*
-M=%\\"G<*/`AF9F:0=43K43PH='@\*F9FD&9FD'4TZVP\CP^$V0```#R/9I!W
-M%3R(#X3+````/(IF9F:0=13IO@```#RH9F9FD&9FD'1Q/*IT;;D`````N```
-M``#I$P$```^V1SK!X`@/ME<["=`/ME<Y@^(?P>(0"=")P0^V1SSI[P```&9F
-M9I!F9I`/ME<ZP>(8#[9'.\'@$`G"#[9'/0G"#[9'/,'@"(G1"<$/MD<_P>`(
-M#[970`G0Z;4````/ME<ZP>(8#[9'.\'@$`G"#[9'/0G"#[9'/,'@"(G1"<$/
-MME<^P>(8#[9'/\'@$`G"#[9'00G"#[9'0,'@"`G0ZW,/ME<Z2,'B.`^V1SM(
-MP>`P2`G"#[9'04@)P@^V1SQ(P>`H2`G"#[9'/4C!X"!("<(/MD<^2,'@&$@)
-MP@^V1S](P>`02`G"#[9'0$C!X`A(B=%("<$/ME="P>(8#[9'0\'@$`G"#[9'
-M10G"#[9'1,'@"`G02(F/B````(F'D````&:#3R(!\\-F9F:0NO____]FA?9T
-M,4B)^;\`````NO____])Q\``````9I`/M@$QT`^VP,'J"$$S%("#QP%(@\$!
-M9CGW=>6)T,-FD$B#[&A$#[9/.T0/MD<Z#[9/.0^V5S@/MD='B40D6`^V1T:)
-M1"10#[9'18E$)$@/MD=$B40D0`^V1T.)1"0X#[9'0HE$)#`/MD=!B40D*`^V
-M1T")1"0@#[9'/XE$)!@/MD<^B40D$`^V1SV)1"0(#[9'/(D$)$B)_DC'QP``
-M``"X`````.@`````2(/$:,-FD$B#[`@/MD8!B$<!#[9&`HA'`HM&!(E'!$B+
-M1P@/ME<!2(T44DC!X@)(BW8(2(G'Z`````!(@\0(PV9F9I!F9I!(BT]@#[97
-M6+@`````9F:0Q@0X`$B#P`%(/:@```!U\$B)3V"(5UC#9F9FD&9F9I"X````
-M`+K_____9F:09F:0B!0X2(/``4@]``(``'7Q\\-F9F:09F9FD&9F9I!F9I"Y
-M`````$@[/W022(M/"$B+$4B+00A(B4((2(D02(G(PTB+#XN!!`$``(G"@>)^
-M__[_B9$$`0``)7[_\O](BU<(B0)(BU<(B4(,2(M7"(E"$$B+5PB)0A1(BU<(
-MB4(82(M7"(E"!$B+!XN`5`$``(D%`````"7^`/__2(L7B8)4`0``PV9F9I!F
-M9I!F9I!F9I")\4B+!XN0!`$``(D5``````^W1SQF/8!D=`QF/8"1=`9F/8"4
-M=1$/MLF#P0BX`0```-/@"<+K$$`/MLZ#P0RX`0```-/@"<)(BP>)D`0!``##
-M9F9FD&9F9I!F9I!F9I")\4B+!XN0!`$``(D5``````^W1SQF/8!D=`QF/8"1
-M=`9F/8"4=1$/MLF#P0BX_O___]/`(<+K$$`/MLZ#P0RX_O___]/`(<)(BP>)
-MD`0!``##9F9FD&9F9I!F9I!F9I")\4"`_O]T;T"`_A]W,HNW&`$``+H!````
-MT^*)T/?0(?")AQ@!``"+AU@!``")!0`````AT'1`B8=8`0``PV:0B[<<`0``
-M#[;!@^@@N@$```")P=/BB=#WT"'PB8<<`0``BX=@`0``B04`````(=!T!HF'
-M8`$``//#9F9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)U8GP3(LO
-M0(#^`P^&B0```$B-',4`````@>/X!P``38VD'0`"``!!QP0D#`$``+\0)P``
-MZ`````!)C9P=!`(```^V50/!XA@/MD4"P>`0"<(/MD4`"<(/MD4!P>`("<*)
-M$T''!"00`0``OQ`G``#H``````^V50?!XA@/MD4&P>`0"<(/MD4$"<(/MD4%
-MP>`("<*)$^F$````2(T<Q0````"!X_@'``!.C:0K``(``$''!"0,`0``OQ`G
-M``#H`````$J-G"L$`@``#[95`\'B&`^V10+!X!`)P@^V10`)P@^V10'!X`@)
-MPHD30<<$)!`!``"_$"<``.@`````#[95!\'B&`^V10;!X!`)P@^V100)P@^V
-M107!X`@)PHD32(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPTB#[!A(B5PD"$R)
-M9"0028G\0`^VWHG>Z`````"_$"<``.@`````B=Y,B>?H`````$B+7"0(3(MD
-M)!!(@\08PY!!5T%6055!5%532(/L6$F)_XA4)%=(BQ>`?SX`#X0\`@``0;P`
-M````0;W@____0;[P____0`^VQDB)1"1(2(V"@`$``$B)1"1`2(V*A`$``$B)
-M3"0X2(V"H`$``$B)1"0P2(V*I`$``$B)3"0H2(V"4`(``$B)1"0@2(V*5`(`
-M`$B)3"082(V"X`$``$B)1"002('"T`$``$B)5"0(9F:02(M$)$A$B>%(T_BH
-M`0^$C0$``$2)Y8/]`W871(GJ2`-4)"B+`HD%`````(/@_HD"ZQN-%.T`````
-MB=)(`U0D.(L"B04`````@^#^B0*_$"<``.@`````@'PD5P!T<H/]`W871(GR
-M2`-4)!"+`HD%`````(/(`HD"ZQN-%*T`````B=)(`U0D"(L"B04`````@\@"
-MB0)$B?!(BTPD$$@!P8T$K0````")P$B+5"0(2`'"@_T#=@J+`8D%`````.L(
-MBP*)!0````"H`G1TZ^-FD(/]`W8O1(GK2(M$)"!(`=C'``````"_$"<``.@`
-M````2`-<)!B+`XD%`````(/(`8D#ZT&-'.T`````B=M(BT0D($@!V,<`````
-M`+\0)P``Z`````!(`UPD&(L#B04`````@\@!B0/K-V9F9I!F9I"#_0-V*T2)
-MZDB+1"0P2`'0QP`!````2`-4)"B+`HD%`````(/(`8D"ZS9F9I!F9I"-!.T`
-M````B<!(BU0D0$@!PL<"`0```$@#1"0XBQ")%0````"#R@&)$&9F9I!F9I!!
-MC50D`4F#Q`%!@\4(08/&!$$/MD<^.=`/AT+^__](@\186UU!7$%=05Y!7\-F
-M9I!54TB#[`B)T4B++X/^`W8@C03UX/___XG`2(V4!:`!``"+`HD%`````(/@
-M_HD"ZQZ-!/4`````B<!(C90%@`$``(L"B04`````@^#^B0*$R71^@_X#=B"-
-M!+7P____B<!(C90%X`$``(L"B04`````@\@"B0+K'HT$M0````")P$B-E`70
-M`0``BP*)!0````"#R`*)`HT4M0````"-0O")P$B-C`7@`0``B=)(C905T`$`
-M`(/^`W8*BP&)!0````#K"(L"B04`````J`)T=>OC@_X#=CB-'/7@____B=M(
-MC80K4`(``,<``````+\0)P``Z`````!(C9PK5`(``(L#B04`````@\@!B0/K
-M-HT<]0````")VTB-A"M0`@``QP``````OQ`G``#H`````$B-G"M4`@``BP.)
-M!0````"#R`&)`TB#Q`A;7<.0D)"0D)!(B?E(BS\/MX&P$@``@\`!9HF!L!(`
-M`&8[@;02``!R"6;'@;`2``````^W@;`2``!(P>`"2`.!:!$``(L6B1`/MX&P
-M$@``B8<L`0``PV9FD$&)T+@`````Q@0(`$B#P`%(@_@$=?*)\F:!XO\/#[<!
-M9B4`\`G09HD!#[97#<'B#(L!)?\/\/\)T(D!#[9'"H/@`DB#^`$9TH/B`H/"
-M`<'B!0^V00.#X!\)T(/($(/@]XA!`_9'"@%T%T2)PH/B?\'B!`^W00)F)0_X
-M"=!FB4$"\\-F9F:09F9FD&9FD&9FD+@`````Q@0P`$B#P`%(@_@-=?(/MD<Y
-MB`8/MD<ZB$8!#[9'.XA&`@^V1SR(1@,/MD<]B$8$#[9'/HA&!0^V1S^(1@;V
-MAY8````$=",/MD=`B$8(#[9'08A&"0^V1T*(1@H/MD=#B$8+#[9'1(A&#+@!
-M````PV9F9I!F9F:09F:0N@````!!N@````!!N?_____K4@'21(G`T_BH`702
-M]\(````!=1J!\G<GVP#K$F:0B=`U=R?;`/?"`````0]%T(/I`40YR77+28/"
-M`4F#^@AU$XG0P>@0B`>)T,'H"(A'`8A7`L-%#[8$,KD'````ZZ)F9F:09F9F
-MD&9F9I!F9I!(BX<($0``BQ"+4`2+4`B+0`R)!0````##9F9FD&9FD$B#[`A(
-MBX:(````1`^V1T-%A,!T(@^V4`VY`````/;"`70,ZQ)(B=!(T_BH`74(@\$!
-M1#C!=>[&1D(,Z`````!(@\0(PV9F9I!F9F:09F:02(/L"$B)^$B+/V;'0$X!
-M`,9`0AU(B<;H`````$B#Q`C#9F9FD&9F9I!F9F:09F:02(/L"$B+/P^W]DC!
-MY@-(`[>P"0``2(LV2(7V=#U(BQ</MT8R9L'H!0^WP(T$A0`#``")@G`!``!(
-MBQ</MTXR@^$?N`$```!(T^")@G0!``"Z`````.@`````2(/$",.005=!5D%5
-M05154TB#[`A(B?M)B?:`?T,`="6Y`````/9&#0%T#NL800^V1@U(T_BH`74,
-M@\$!#[9#0V8YR'?H28M&0$B%P'0<2(VPD````$B+>RCH`````$F+=D!(B=_H
-M`````$F-1F!).49@#X1S`0``28G'3(G_Z`````!(B<5(@WA```^$0`$``("X
-M@P`````/A*````!F@WMH``^$E0```$&]`````$&\`````)!(BX.P"0``3`'@
-M2(LP2(7V=&$/MT8@9CM%.'579CV%`'=1#[?`@+P#8`@``/]T1$B+$P^W1C)F
-MP>@%#[?`C02%``,``(F"<`$``$B+$P^W3C*#X1^X`0```$C3X(F"=`$``,9&
-M)"&Z`````$B)W^@`````08/%`4F#Q`@/MT-H1#GH#X]X____2(M%0$C'0&``
-M````]D5,!'492(G?Z`````!(BW5`N@$```!(B=_H`````$B+54`/MH+,````
-MC02`#[92`@'02)@/MH@`````#[93.@^V<SE(Q\<`````N`````#H`````$B+
-M54!(B[/P"```OP$```#H`````$B+54!(B[/P"```OP8```#H`````$C'14``
-M````08!N#@%(B>Y(B=_H`````$TY?F`/A9#^__])QT9``````$B+`XN(6`$`
-M`(D-`````(7)=`E(BP.)B%@!``!(@\0(6UU!7$%=05Y!7\-F9F:09F9FD$B#
-M[`A,BP=!#[9P0T"$]G0U28V`N!(``+D`````2#GX=1KK(@^VP4B-%$!(C120
-M28V4T+@2``!(.?IT#X/!`4`X\77@ZP6Y``````^VP4B-%$!(C1202(T$U0``
-M``!)B[0`R!(``$B%]G1]]D8*`G1W28V$`+@2``!(.48@=6D/MD98A,!T"(/`
-M`8A&6.M92(M62$B#ZCA(C4Y(2(U".$@YR'1$2(-Z$`!U+.L*9F:02(-Z$`!U
-M(,9&6`$/MHJ[````28NXL!```$G'P`````#H`````.L12(M2.$B#ZCA(C4(X
-M2#G(=<A(@\0(PV9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)^TB)]4B+
-M1G!,BV@H#[=.(&:!^84`=W\/M\$/MH0'8`@``#S_='!F@_E_=R$/MM!(BX\X
-M"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZTYF@?F!`'<<#[;`2(N7B`D``$AI
-MP,@/``!(BT00"`^V0`CK*P^VP$B+EV`)``!(C03`2,'@!4B+A!"(````#[9`
-M".L+9F:09F:0N/\```!(F$0/MJ0#Y@@``$B+=7A(A?9T"$B)W^@`````2(GN
-M2(G?Z`````!!#[;$2(T\@$B-/+A(C;S[P`$``$R)[D'_E:````!(BUPD"$B+
-M;"003(MD)!A,BVPD($B#Q"C#9F9FD&9FD&9FD&9FD$%455-(B?5(B=-F@7XX
-MX0%U$0^V1CJ#Z!%!O``````\`78T2(LW2(N^.`D```^W12"Z8)X!`&8]A0!W
-M%P^WP`^VA`9@"```2(T40$B-%)!(P>(%3(TD%\9#!`6`8P7^@"/?N`````!F
-M@7TXX0%U$0^V13J#Z`$\`0^6P`^VP&:0P>`'#[83@^)_"<*($P^VA98```"#
-MX`'!X`:#XK\)PH@3]H66`````70.3(GGZ`````!FB4,(ZP1FB4L(#[=#"(A%
-M)6:!?3CA`74E#[95.HU"_SP!=PH/ME4[@^(/ZRJ0C4+ON@\````\`78=9F9F
-MD+H`````28-\)&``=`Q!#[:4)($```"#X@\/M@.#X/`)T(@#6UU!7,-F9F:0
-M9F9FD$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!)B?Q(B?-)
-MB=</MD8X/`AT#SPH=`L\J'0'/(AF9I!U#H.+E`````KK)69FD&:0/`IT#CPJ
-M=`H\JG0&/(IFD'4.@XN4`````F9F9I!F9I`/MWLX9H'_X0%U'`^V0SJ#Z!$\
-M`7<1@XN4````"+@`````Z4D%``!$BT,X08'@____`$&!^.$!$``/A>8````/
-MMTL@9H'YA0`/A_($```/M\%!#[:\!&`(``")^$"`__]T;F:#^7]W(T`/MM=)
-MBXPD.`D``$B-!%)(C02"2,'@!4B+1`A0#[9`".M%9H'Y@0!W'D`/ML=)BY0D
-MB`D``$AIP,@/``!(BT00"`^V0`CK($`/ML=)BY0D8`D``$B-!,!(P>`%2(N$
-M$(@````/MD`(#[;`00^VA`3F"```2(T4@$B-%)!)C;34P`$``$F+E"2("0``
-M0`^VQTAIP,@/``!!O0````#V1`)=$`^%8`(``,9#)`1!QP<`````N`$```#I
-M2P0```^W4R"Y_P```+C_____9H'ZA0`/AXL````/M\)!#[:T!&`(``")\$"`
-M_O]T<V:#^G]W*$`/MM9)BXPD.`D``$B-!%)(C02"2,'@!4B+1`A0#[9`".M*
-M9F:09I!F@?J!`'<>0`^VQDF+E"2("0``2&G`R`\``$B+1!`(#[9`".L@0`^V
-MQDF+E"1@"0``2(T$P$C!X`5(BX00B`````^V0`A`#[;.1`^V\$ECQD$/MJP$
-MY@@``$B-1*T`2(U$A0!)C;3$P`$```^WP4B-%$!(C1202,'B!4F)U4T#K"0X
-M"0``9H'_X0%U"P^V0SJ#Z`$\`78I9H'Y_P!T!T'V14L$=1O&0R0&0<<'````
-M`+@!````Z38#``!F9I!F9I!!#[952(G1@^$!="3VP@1T'T$/MD0D1$$Z1"1.
-M<A)!QP<!````N`$```#I`0,``)!-A>T/A/<```"%R0^$[P```/;"!`^$Y@``
-M`$B)WDR)[^@`````A,!U%<9#)`1!QP<`````N`$```#IP@(``$&`O8,````?
-M=A%!QP<!````N`$```#IIP(``/:#E@````%T%TB-1*T`2(U$A0!!]H3$S`$`
-M``%T&^M?2(U$K0!(C42%`$'VA,3,`0```0^$OP$``$2)]DR)Y^@`````A,!T
-M$4''!P$```"X`0```.E.`@``]H.6`````0^$D@$``$B-1*T`2(U$A0!!]H3$
-MS`$```$/A'D!``!,B>_H`````&:#^!\/AF<!``!!QP<!````N`$```#I!0(`
-M`&9FD&:0]D8*`G0R08'XX0$0`&9FD`^$.P$``$$/MH6#````03J%@@```'(>
-M0<<'`0```+@!````Z<@!``!!@?CA`1``#X0,`0``00^W16J`>SCA#X7]````
-M@'LY`0^%\P```$C1Z$B)PH/B`0^V0SJ#Z`8\"0^'Q@````^VP/\DQ0````!!
-MN`$```"Y`0```$B)VDR)[DR)Y^@`````A,`/A;````!!QP<"````N`$```#I
-M3@$``$&X`0```+D`````2(G:3(GN3(GGZ`````"$P`^%?@```$''!P(```"X
-M`0```.D<`0``#[;*0;@!````2(G:3(GN3(GGZ`````"$P'520<<'`@```+@!
-M````Z?`````/MLI!N`````!(B=I,B>Y,B>?H`````(3`=29!QP<"````N`$`
-M``#IQ````,9#)`1!QP<`````N`$```#IKP```$F-O"2@#P``Z`````"$P'01
-M0<<'`0```+@!````Z8T```"`>SCA=4Z`>SD!9F:0=46`>SH/=3^`>ST!9F9F
-MD'4U#[9S/,'F"`^V0SL!Q@^W]DR)Y^@`````2#M#:'4%2(7`=1+&0R0$0<<'
-M`````+@!````ZSFX`````.LR9I!!#[:$).4)``!(C12`2(T4D$F-M-3``0``
-M28N4)(@)``"X.+@/`.F4^___9F:09I!(BUPD"$B+;"003(MD)!A,BVPD($R+
-M="0H3(M\)#!(@\0XPV9F9I!F9I!F9I!F9I!(@^P(2(L_Z`````!(@\0(PV9F
-M9I!F9F:09F9FD&9FD$%7059!54%455-(@^Q828G]2(GU2(N?.!$``&;'1C+_
-M#TB-5"0LZ`````"$P'0)BT0D+.D."P``BT4X)?___P`]X0$0``^%Y0```+^(
-M$P``Z``````/MTT@9H'YA0`/A[D*```/M\%!#[:T!6`(``")\$"`_O]T:V:#
-M^7]W(D`/MM9)BXTX"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZT-F@?F!`'<=
-M0`^VQDF+E8@)``!(:<#(#P``2(M$$`@/MD`(ZQ]`#[;&28N58`D``$B-!,!(
-MP>`%2(N$$(@````/MD`(#[;`00^VA`7F"```2(T4@$B-%)!-C;35P`$``$F+
-ME8@)``!`#[;&2&G`R`\``$@!PDB)5"002,=$)`@`````2,=$)!@`````Z7(!
-M```/MU4@OO\```!F@?J%`'<,#[?"00^VM`5@"```#[=].&:!_^$!=0\/MD4Z
-M@^@1/`$/AL8```!F@?J%`'=Z#[?"00^VA`5@"```//]T:F:#^G]W(0^VT$F+
-MC3@)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK2&:!^H$`=QP/ML!)BY6("0``
-M2&G`R`\``$B+1!`(#[9`".LE#[;`28N58`D``$B-!,!(P>`%2(N$$(@````/
-MMD`(ZP6X_____P^VP$$/MH0%Y@@``$B-%(!(C12038VTU<`!```/M\9(C11`
-M2(T4D$C!X@5)`Y4X"0``2(E4)`AF@?_A`75&ZS(/M\9(C03`2,'@!4D#A6`)
-M``!(B40D&$R+L(@```!(QT0D"`````!(QT0D$`````#K1`^V53J-0N\\`78G
-MC4+_/`%V(&:!_O\`=`M(BT0D"/9`2P1U#L9%)`:X`````.FV"```2,=$)!``
-M````2,=$)!@`````2(UT)$A,B>_H`````$&)QV:)13),B>_H`````$F)Q+@"
-M````387D#X1W"```3(FE@````$$/M]=(B10D2&G"L`0``$B-'!A(C4,@22N%
-M.!$``$D#A4`1``!(BU0D2(E"($C!Z"!(BU0D2(E")$F+1"082(M4)$B)0BA(
-MP>@@2(M4)$B)0BQ(BT0D2&9$B7@(N`````#&!!@`2(/``4@]L`0``'7P9H%]
-M..$!=50/MD4Z@^@1/`%W24B-3"0P2(M$)$@/ME`(2(GN2(M\)`CH`````$B-
-M@R`$``!)*X4X$0``20.%0!$``$B+5"1(B4(02,'H($B+5"1(B4(4Z14!``!!
-M#[96"O;"`74LBT4X)?___P`]X0$0``^$G````$B+3"0(#[9!2*@!#X2+````
-MJ`0/A(,```#VA98````@=`](C70D,$B)[^@`````ZQM(C4PD,$B+1"1(#[90
-M"$B)[DB+?"0(Z`````!(C8,@!```22N%.!$``$D#A4`1``!(BU0D2(E"$$C!
-MZ"!(BU0D2(E"%$B)V$DKA3@1``!)`X5`$0``2(M4)$B)0AA(P>@@2(M4)$B)
-M0ASK7/;"`G172(G822N%.!$``$D#A4`1``!(BU0D2(E"&$C!Z"!(BU0D2(E"
-M'$B-@R`$``!)*X4X$0``20.%0!$``$B+5"1(B4(02,'H($B+5"1(B4(42(M$
-M)$B`2`$"#[9564B+1"1(9HE0`H!]60!T,[\`````B?A(C01`2,'@`DF+="00
-M2(M-8$B+%`A(B10&BU0("(E4!@B#QP$/MD59.?AWTHM5-$B+1"1(B5`,9H%]
-M..$!=3\/MD4Z@^@1/`%W-$$/M\](BU0D2$B)[DR)]^@`````2(U,)#!(B=I(
-MB>Y,B??H`````$&`9@S^Z8L$``!F9I!!#[9&"J@"#X0B!```2(M$)$C&0`;^
-M2(M$)$B`8`?^2(-\)`@`#X2X````2(M$)`@/ME!(2(G0@^`&2(/X!@^%GP``
-M`/;"`0^$E@```$$/M\](BU0D2$B)[DR)]^@`````]H66`````7002(M$)$@/
-MMT`(P>`#B$0D,4B-3"0P2(G:2(GN3(GWZ`````#VA98````!=`=!@$X,`>L%
-M08!F#/[&`Z%(BU0D"`^V@NH```"#X`\/ME,!@^+P"<*(4P%(BTPD"`^W03B#
-MP`%FP<`(9HE#`DF)S$F!Q-0```#I/0,``&:!?3CA`0^%)`(```^V13H\#W03
-M0;P`````/!`/A1L#``#IK@````^V53S!X@@/MD4[`<)(BT0D2,9`!`U(BT0D
-M2(!@!?Z`3"1#"$B+="1(#[9%)4$/MHWN````T^!F"48(2(M,)$@/MD$!@^`?
-M@\@@B$$!2(M%/DB)@S@$``!FP<((9HF31`0```^V13V(@T($``#&`Y%(BU0D
-M"`^W0CB#P`%FP<`(9HE#`DB+3"0(#[:1Z@```(/B#P^V0P&#X/`)T(A#`4F)
-MS$F!Q-0```#I:`(``$B+5"1(#[9%)4$/MHWN````T^!F"4((Q@.!9L=#`O__
-M2(M$)!`/MI"[````@^(/#[9#`8/@\`G0B$,!2(-]2`!U#L9%)"&X`````.GN
-M`P``]D4[`70I3(ME4$V%Y'0@28N]L!```$R)YN@`````@^`/#[93`8/B\`G"
-MB%,!ZP5,BV0D$$B+54@/MD(!OA`````\@`^$A@```#R`=Q\\%7<2/!!F9I!F
-MD'-G@^@"/`%W1.M7/!=F9I!W.^M>/(5T+CR%9F:09F:0=Q`\@71#/()U(V9F
-MD&9FD.LB/)!R%[XH````/))F9I!V-3R3=0>^C````.LJO@0```#K(P^V0@2-
-M-(4(````D.L5O@@```#K#KX,````9I#K!;X<````B?+!Z@)(BT0D2(A0!$B+
-M3"1(9L'J"(/B`0^V006#X/X)T(A!!4B-NR`$``")\DB+=4CH`````.D-`0``
-M#[9%.(/H!#RK=T`/ML#_),4`````#[9%0,'@"`^V54&-#!"#^0UW&+@!````
-M2-/@J=@^``!T"4B+1"1(@$@!!$B+1"1(@$@!`>L)2(M$)$B`8`'[2(M$)$C&
-M0`0-2(M$)$B`8`7^2(M4)$@/MD4E00^VC>X```#3X&8)0@A(BT0D2(!@`1_&
-M@R`$```&3(MD)`A)@<34````2(V[(00``$R)YN@`````2(V[)00``$R)YN@`
-M````2(M%.$B)@T0$``!(BT5`2(F#3`0``$B+5"0(2(N"W````$B)@S@$``#&
-M`Y%(BTPD"`^VD>H```"#X@\/MD,!@^#P"="(0P$/MT$X@\`!9L'`"&:)0P)-
-MA>1T8TF+!"1(B4,$ZUFH`71500^WSTB+5"1(2(GN3(GWZ`````#VA98````!
-M=!!(BT0D2`^W0`C!X`.(1"0Q2(U,)#!(B=I(B>Y,B??H`````/:%E@````%T
-M!T&`3@P!ZP5!@&8,_DF+A;`)``!(BQ0D2(DLT$2)^F;!Z@5%#[?G@>+_!P``
-M1(GA@^$?N`$```!(T^!!"825N`D``(M%."7___\`/>$!$`!U*4B-3"1`N@``
-M``!$B>9,B??H``````^V1"1#@^`?@\A`B$0D0^FD````9H%]..$!=3,/MD4Z
-M@^@1/`%W*$B+="083(GOZ`````!(C4PD0$B+1"08#[904$2)YDR)]^@`````
-MZVE(BW0D"$R)[^@`````2(U,)$!(BT0D"`^V4')$B>9,B??H`````$B+3"0(
-M#[912$B)T(/@!DB#^`9U+O;"`70I#[9$)$.#X!^#R&"(1"1##[91<H/B?\'B
-M!`^W1"1"9B4/^`G09HE$)$)(C70D0$R)[^@`````2(MS(+@#````2(7V=$%(
-MQ\<`````N`````#H`````+@#````ZRE!#[:%Y0D``$B-%(!(C12038VTU<`!
-M``!)BY6("0``N#BX#P#IR_7__TB#Q%A;74%<05U!7D%?PV9F9I!F9F:09F:0
-M055!5%532(/L"$B)_4&]`````$R-I_@```#IN0$``)!,B>?H`````$B)PTB#
-M>'``=39(B>_H`````$B)0W!(A<!U)4B-E?@```!(BX7X````2(E8"$B)`TB)
-M4PA(B9WX````Z9T!``"+0S@E____`#WA`1``#X3=````#[=#(&8]@``/A,\`
-M```/MLAFB4L@9H/Y?W8:9H%[..$!=2D/MD,Z@^@1/`%W'F9F9I!F9I!F@?F%
-M`'<0#[?!#[:4!6`(``"`^O]U&<9#)`9(B=Y(B>_H`````.G]````9F:09I`/
-MMW,X9H'^X0%U%0^V>SJ-1^\\`0^'[0```.L?9F9FD`^VPDB-%$!(C1202,'B
-M!4F)U4P#K3@)``#K!XU'_SP!=C9F@?F``'0O9H'^X0%FD'4+#[9#.H/H$3P!
-M=AM!]D5+!'44QD,D!DB)WDB)[^@`````Z8````!(B=Y(B>_H`````(/X`G<*
-M@_@!<R5F9I#K$(/X`W5A9F:09F:09F:0ZTM(B=Y(B>_H`````&9FD.M&2(.[
-M@`````!T#TB-LX````!(B>_H`````$B-E?@```!(BX7X````2(E8"$B)`TB)
-M4PA(B9WX````ZSA(B=Y(B>_H`````$PYI?@````/A3O^___K'@^VPDB-%$!(
-MC1202,'B!4F)U4P#K3@)``#I%O___TB#Q`A;74%<05W#2(/L2$B)7"082(EL
-M)"!,B60D*$R);"0P3(ET)#A,B7PD0$B)]4F)_4R+9U!-BS0D00^V1"0,J!!T
-M#,:'Z`````;IC`(```^VE^@```"`^@$/A((```"`^@%R&H#Z!`^$HP```(#Z
-M!@^%S0(``&9FD.E=`@``QH?H`````4B)_DR)]^@`````QD4D@4&`3"0,"$B#
-MO8``````=`](C;6`````3(GWZ`````!)BX;X````2(EH"$B)10!)C8;X````
-M2(E%"$F)KO@```!,B??H`````.EB`@``@^#W08A$)`R`A^L````!QH?H````
-M`,9&)`),B??H`````$R)]^@`````Z3,"``#&A^L`````2(.^@`````!T#TB-
-MMH````!,B??H`````$F+34!(A<D/A)X!``"+402-0@&)002#^B@/AXP!``!)
-MBX;X````2(EH"$B)10!)C8;X````2(E%"$F)KO@```!!@'U*_W0D28M%8$B%
-MP'0&@'A"`'053(GJO@(```!,B>?H`````.FH`0``00^V1"0,@^#W@\@008A$
-M)`Q)BW582(7V=11!@'PD#@!U+.GE````9F9FD&9FD$$/MI6!````0;@`````
-MN0(```!,B>?H`````.E:`0``0;\`````QD0D%P!)C40D8$B)1"0(2(M\)`CH
-M`````$B)Q4F+1"1H28EL)&A(BU0D"$B)50!(B44(2(DH2(M50$B%TG0528NV
-M\`@``+\%````Z`````"`34P"2(GJO@8```!,B>?H`````("]@P````!T-D&-
-M7P%!@?]_EI@`=R9,B??H`````+\!````Z`````"`O8,`````=`N#PP&!^X&6
-MF`!UVD&)WX!$)!<!#[9$)!=!.$0D#@^'5____TF+?6!(A?]U'$'&14H#9D''
-MA<@``````$R)[DR)]^@`````ZW?H`````&9F9I!F9F:0ZVA!#[9=2DC'QP``
-M``"X`````.@`````08!D)`SO28N&^````$B):`A(B44`28V&^````$B)10A)
-MB:[X````3(GJO@8```!,B>?H`````(#[_W4.3(GJ3(GF3(GWZ`````!,B??H
-M`````$B+7"082(ML)"!,BV0D*$R+;"0P3(MT)#A,BWPD0$B#Q$C#9F:005=!
-M5D%505154TB#["A(B?U)B?5(BX\X"0``N&">`0!F@7X@A0!W&P^W1B`/MH0'
-M8`@``$B-%$!(C1202(G02,'@!4R-)`%(BY4($0``2('"0`@``$$/MD0D<L'@
-M"$B82`'"BS*)-0````!!B?=!P>\02(N5"!$``$B!PD`(``!!#[9$)'+!X`A(
-MF$@!PHM"!(D%`````(A$)!")PL'J"(A4)!'!Z!"(1"022(N5"!$``$B!PD`(
-M``!!#[9$)'+!X`A(F$@!PHM""(D%`````(A$)!.)PL'J"(A4)!3!Z!"(1"05
-MQD0D%@#&1"07`(M,)!!!B?9!P>X800^VWT2+1"041(GRB=Y(Q\<`````N```
-M``#H`````(G8@_`!B<*#X@%T%$6$_W0/0<9%)`"X`````.FH`@``08!])(%F
-M9I!U(4B-3"001(GRB=Y,B>_H`````$'&120"N`````#I?0(``$&+13@E____
-M`#WA`0X`=0]!QD4D(;@`````Z5X"``!!]H66`````74HA-)U)$&`?"1*_W0<
-M2(U,)!!$B?*)WDR)[^@`````N`````#I+`(``$R)YDB)[^@`````3(GF2(GO
-MZ`````!(BU4`00^W13)FP>@%#[?`C02%``,``(F"<`$``$B+10!!#[=-,H/A
-M'[H!````2(G32-/CB9AT`0``00^W13)(P>`#2`.%L`D``$C'``````!!#[=-
-M,HG(9L'H!27_!P``@^$?2(G62-/F2(GQ]]$AC(6X"0``00^W33*)R&;!Z`4E
-M_P<``(/A'TC3XO?2(52%;$F+50!)BT4(2(E""$B)$$$/MW4R2(V]H`\``.@`
-M````08"L)(,````!0<9%)(%)@[V``````'0/28VU@````$B)[^@`````28U$
-M)"!).40D(`^$"0$``$F)QDB-A:`/``!(B40D"$R-O?@```!F9F:09F:03(GW
-MZ`````!(B<-(BU4`#[=`,F;!Z`4/M\"-!(4``P``B8)P`0``2(M%``^W2S*#
-MX1^Z`0```$B)UDC3YHFP=`$```^W0S)(P>`#2`.%L`D``$C'```````/MTLR
-MB<AFP>@%)?\'``"#X1](B=9(T^9(B?'WT2&,A;@)```/MTLRB<AFP>@%)?\'
-M``"#X1](T^+WTB%4A6P/MW,R2(M\)`CH`````$&`K"2#`````4B#NX``````
-M=`](C;.`````2(GOZ`````!(BX7X````2(E8"$B)`TR)>PA(B9WX````33ET
-M)"`/A13___]!@:64````___^_T'&A"3H````!$R)[DR)Y^@`````N`$```!(
-M@\0H6UU!7$%=05Y!7\.02(/L6$B)7"0H2(EL)#!,B60D.$R);"1`3(ET)$A,
-MB7PD4$B)5"002(LO3(N%.!$``$B%T@^$Q@(```^WUDAIPK`$``!*C0P`]D$A
-M`G082(T$U0````!(`X6P"0``2(L`QD`D`NL62(T$U0````!(`X6P"0``2(L`
-MQD`D(4R-%-4`````2(N%L`D``$P!T$B+$(M"."7___\`/>$!$``/A+`!```/
-MMT(@9CV%`'<2#[?`#[:$!6`(```\_W499F:03(G02`.%L`D``$B+`,9`)`;I
-MR@@```^VP$B-%$!(C1202,'B!4R+G3@)``!)`=.`?"03`'EN00^V4TA(B="#
-MX`9(@_@&=2/VP@%T'DB+10"+D%@!``")%0````"%TG0*2(M%`(F06`$``$B+
-M10"+@%`!``")!0````"#R`)(BU4`B8)0`0``2(M%`(N`!`$``(D%`````(#,
-M_TB+50")@@0!``!F]T$@`@@/A.H```"`?4,`#X3@````NP````!!N0````!%
-MB<A!#[;)#[9'#4C3^*@!=&!!@/D#=B=(BT4`2`70`0``C12-`````$ACTD@!
-MT(L`B04`````P>@4@^`!ZR5(BT4`2`70`0``C12-`````$ACTD@!T(L`B04`
-M````P>@4@^`!A,!T"K@!````2-/@"<-!@\$!08U``3A%0W>!A-MT4CA?#75-
-MB?!FP>@%)?\'``"+1(5LB?&#X1](T_BH`74R08"[Z`````)W"$'&@^@````#
-M3(G02`.%L`D``$B+,$R)W^@`````Z4P'``!!NP````#V1"03`0^$.P<``$R)
-MT$@#A;`)``!(BS#&1B0ABT8X)?___P`]X0$.``^$%P<``$B+E0@1``!(@<)`
-M"```00^V0W+!X`A(F$@!PHL"B04`````2(N5"!$``$B!PD0(``!!#[9#<L'@
-M"$B82`'"BP*)!0````!(BY4($0``2('"2`@``$$/MD-RP>`(2)A(`<*+`HD%
-M`````$B)[^@`````Z:$&``"0#[?V2(T<]0````!(BX6P"0``2`'82(L09H%Z
-M..$!#X4,`0``#[9Z.D"`_Q`/AVX&``"X`0```(GY2-/@J<`P```/A<P```"I
-M```!`'54]L2`#X1)!@``2&G&L`0``$J-#``/MD$SB$(D2(G82`.%L`D``$B+
-M`/9`(P0/A"`&``"`>"0`#X06!@``2(M04$B%T@^$"08```^V03.(`NG^!0``
-M2&G&L`0``$J-#`!,C6$H2(G82`.%L`D``$B+$$$/MD0D`HA")$B)V$@#A;`)
-M``!(BP!(@WA(``^$P04```^VN2$$``#H`````$B)VD@#E;`)``!(BPJ+430Y
-MT`]'PHG"2(MY2$R)YN@`````Z8T%``!(B=A(`X6P"0``2(L`QD`D`.EW!0``
-M9F9FD&9FD$B)V$@#A;`)``!,BRA-BWUHN/____]F08%]((4`=QE(B=A(`X6P
-M"0``2(L`#[=`(`^VA`5@"```#[;`2(T40$B-%)!(P>(%3(NE.`D``$D!U$'&
-MA"3H`````$$/ME0D2$B)T(/@!DB#^`8/A9<!``#VP@$/A(X!``!!QD4D`$'V
-MA98````@#X3D!```387_#X3;!```0?:'L0````(/A*$```!!BT4TA<`/A)4`
-M``!)B[^@````2(7_=`V)PDF+=4CH`````.M\28-]2`!T=4F#O[@`````=0I)
-M@[_``````'1A38MM2$F+A[@```!(A<!T#4B)PT'VA[$````!="9(B[5`"@``
-MN@$```!,B?]!_Y?`````NP````"%P'0'2(N=0`H``$B+>PB+$TR)[N@`````
-MBP-)`<6+0P1(@\,0A<!TXDB+E0@1``!(@<)`"```00^V1"1RP>`(2)A(`<*+
-M`HD%`````(G"P>H008B7FP```,'H&&9!B8>0````2(N5"!$``$B!PD0(``!!
-M#[9$)'+!X`A(F$@!PHL2B14`````#[;"9D&)AY0````/ML9F08F'E@```(G0
-MP>@0#[;`9D&)AY@```#!ZAA!B)>:````2(N5"!$``$B!PDP(``!!#[9$)'+!
-MX`A(F$@!PHL"B04`````#[;`9D&)AY(```#I:0,``$AIQK`$``!.C30`00^V
-M1C.$P`^%T0```$B)V$@#A;`)``!(BP#&0"0`0?:%E@```!`/A#(#``!-A?\/
-MA"D#``!!#[9&,T&(AY(```!!]H>Q`````@^$#P,``$&#?30`#X0$`P``28._
-MN`````!U#DF#O\``````#X3L`@``38ME2$F+A[@```!(A<!T#4B)PT'VA[$`
-M```!="9(B[5`"@``N@$```!,B?]!_Y?`````NP````"%P'0'2(N=0`H``$B+
-M>PB+$TR)YN@`````BP-)`<2+0P1(@\,0A<`/A8<"``#KW&9FD&:0/`(/A2@"
-M``!!#[9.0$&+1CB)1"0D#[94)"</MD0D),'@&`G"#[9$)"7!X!`)P@^V1"0F
-MP>`(08G400G$@^%_@/EQ=CS&1"0-`$&#_`%V#$$/MD9!@^`/B$0D#<9$)`X`
-M08/\`G8)00^V3D*(3"0.08/\`W9F00^V1D.(1"0/ZV#&1"0-`$&#_`)V#$$/
-MMDY"@^$/B$PD#<9$)`X`QD0D#P!!@_P'=CE!#[9&1X/`"$$YQ$0/1^#&1"0.
-M`$&#_`QV"4$/MD9,B$0D#D&#_`UV"T$/MDY-B$PD#^L%QD0D#P!(B=A(`X6P
-M"0``2(L`@'@P`'1(187D=$/&0"0@2(G82`.%L`D``$B+``^V0#`/MM!$..!$
-M#T+B2(G82`.%L`D``$B+`$B+>%!(A?]T'T2)XDF-=D#H`````.L12(G82`.%
-ML`D``$B+`,9`)"*`?"0-!'412(G82`.%L`D``$B+`,9`)`)).6TH#X02`0``
-M387_#X0)`0``0?:%E@```!!T0$$/MD8S08B'D@```$'VA[$````"="I!#[9%
-M,$2)XD$XQ`]'T(32=!A)B[^H````2(7_=`P/MM))C79`Z`````"`?"0-"W=<
-M#[9$)`W_),4`````0<:'L@````'IGP```(!\)`X$=12`?"0/`G4-0<:'L@``
-M`!'IA````$'&A[(````"ZWI!QH>R````$.MP0<:'L@````OK9D'&A[(````&
-MZUQ!QH>R````#>M29I`\*'4G00^VA"2#````@^@!08B$)((```!(B=A(`X6P
-M"0``2(L`QD`D@>LE/`AU"K\0)P``Z`````!(B=A(`X6P"0``2(L`QD`D(69F
-MD&9FD$B+7"0H2(ML)#!,BV0D.$R+;"1`3(MT)$A,BWPD4$B#Q%C#9F9FD&9F
-MD&9FD&9FD$%7059!54%455-(@>RH````2(G]2(E\)'`/MX>R$@``9HF$)(``
-M``!(BP>+@$`!``")!0````!F)?\/9HF'LA(``&8[A"2`````=7%(BP>+L%`!
-M``")-0````!(BP>)L%`!``"X`````/?&`/__``^$!`D``$C'QP````"X````
-M`.@`````2(M\)'#H`````+@!````Z=\(``!F9I!F9I!(BT4`BX!``0``B04`
-M````9B7_#V:)A;(2``#K)$B-EP@!``!(B50D:$B-CZ`/``!(B4PD8$B-M_@`
-M``!(B70D6$B+A9@1``"+`(D%``````^WC;(2```E_P\```^WT3G0=9UF@?G_
-M#P^%P@<``.G2!P``3(N%.!$``&:#A"2``````0^WA"2`````9CN%MA(``+@`
-M````#[>4)(`````/0]!FB90D@````$B+E9@1``!(@\($#[>$)(````"+#()!
-MB<E!P>D00?;!"`^$KP```$B+10"+D%`!``")%0````!(BT4`B9!0`0``]\(`
-M__\`=&F`?4,`=&.)UO?&``$``'4NOP````#WQ@```0!T0.L?#[?7C4H(2(GP
-M2-/XJ`%U%(U*$$B)\$C3^*@!=0?K'[\`````#[?'2(T4@$B-%)!(C9S5P`$`
-M`$B%VW4=ZPR#QP$/MD5#9CGX=[9(BWPD<.@`````Z<4&``!(BWPD<.@`````
-MB$,/Z;,&``!F9I")SF:!YO\/#[?&2&G0L`0``$V+1!`@2(T\Q0````!(BX6P
-M"0``2`'X2(L82(7;#X5L`0``#[?VB?)(Q\<`````N`````#H`````&:#?6@`
-M#X1;!@``QH0DGP````!F9I!$#[:T))\```!.C3SU`````$B+A;`)``!,`?A(
-MBS!(A?8/A/D```!-:>:P!```3`.E.!$``$B+G=@0```/MDXE1`^VK"2?````
-M1(GJ2,?'`````+@`````Z`````!,B?A(`X6P"0``2(LXZ`````!!BXPD)`0`
-M`$&+E"0@!```18N,)"P$``!%BX0D*`0``$2)[DC'QP````"X`````.@`````
-M3(GP2,'@!D@!PXM#-(M[,$2+4RQ$BULH1(MC)$2+:R!$BW,<1(M[&(M+%(E,
-M)'Q$BTL01(M##(M+"(M3!(LSB40D0(E\)#A$B50D,$2)7"0H1(ED)"!$B6PD
-M&$2)="001(E\)`B+1"1\B00D2,?'`````+@`````Z`````"`A"2?`````0^V
-MA"2?````9CM%:`^#%@4``.G!_O__D$'VP2`/A(@!``"`>R2!9I`/A5L!``#&
-M0R0A#[=#,DC!X`-(`X6P"0``2,<```````^W2S*)R&;!Z`4E_P<``(/A'[H!
-M````2(G62-/F2(GQ]]$AC(6X"0``#[=+,HG(9L'H!27_!P``@^$?2-/B]](A
-M5(5L#[=S,DB+?"1@Z`````!(@[N``````'0/2(VS@````$B)[^@`````#[=3
-M(&:!^H4`#X?'````#[?"#[:$!6`(```\_P^$M````&:#^G]W(P^VP$B-%$!(
-MC1202,'B!4@#E3@)``!(BT)0@'@(_P^5P.M9#[=#(&8]@0!W)@^WP`^VA`5@
-M"```2&G`R`\``$@#A8@)``!(BT`(@'@(_P^5P.LI#[=#(`^VA`5@"```2(T$
-MP$C!X`5(`X5@"0``2(N`B````(!X"/\/E<"$P'0N2(G>2(GOZ`````!(BX7X
-M````2(E8"$B)`TB+1"182(E#"$B)G?@```#IGP,``$B+3"1H2(M1"$B-0Q!(
-MB4$(2(E+$$B)4`A(B0+I?@,``(GP9L'H!40/M_!)8\8/M_9!B?=!@^<?BT2%
-M;$2)^4C3^*@!#X55`P``2(GX2`.%L`D``$B+``^W4"!F@?J%``^'N@````^W
-MP@^VA`5@"```//\/A*<```!F@_I_=R`/ML!(C11`2(T4D$C!X@5(`Y4X"0``
-M2(M"4`^V0`CK;4B)^$@#A;`)``!(BP`/MT`@9CV!`'<C#[?`#[:$!6`(``!(
-M:<#(#P``2`.%B`D``$B+0`@/MD`(ZS-(B?A(`X6P"0``2(L`#[=`(`^VA`5@
-M"```2(T$P$C!X`5(`X5@"0``2(N`B`````^V0`@\_W00#[;02&/"@+P%Y@@`
-M`/]U-DECQHM$A6Q$B?E(T_BH`0^%:@(``,9#)`9(B=_H`````+H`````2(G>
-M2(GOZ`````#I20(``$ACP@^VA`7F"```2(T4@$B-%)!(C;S5P`$``$V%P'0-
-M0?;!`K@`````3`]$P/9'"@(/A%X!``!,B<+H`````$ECQHM$A6Q$B?E(T_BH
-M`0^%]0$``(![)($/A8\````/MT,R2,'@`T@#A;`)``!(QP``````#[=+,HG*
-M9L'J!8'B_P<``(/A'[@!````2-/@]]`AA)6X"0``#[=S,DB+?"1@Z`````!(
-MB=Y(B>_H`````$B#NX``````=`](C;.`````2(GOZ`````!(BX7X````2(E8
-M"$B)`TB+="182(ES"$B)G?@```#I7`$``$B+A0@!``!(.T0D:'1?0;P`````
-M08/$`4B+`$@Y1"1H=?)%A.1T1D&]`````$B+?"1HZ`````!(C4CP2(MT)&A(
-MBU8(2(E&"$B),$B)4`A(B0)(.=FX`0```$0/1.A!@.P!=<E%A.T/A>\```!(
-MBT0D:$B+4`A(C4,02(M,)&A(B4$(2(E+$$B)4`A(B0))8]:X`0```$2)^4C3
-MX`F$E:P```#IM````$R)PN@`````2(N%"`$``$@[1"1H=%M!O`````!!@\0!
-M2(L`2#E$)&AU\D6$Y'1"0;T`````2(M\)&CH`````$B-2/!(BW0D:$B+5@A(
-MB48(2(DP2(E0"$B)`D@YV;@!````1`]$Z$&`[`%UR46$[75#@'LD@70]2(M$
-M)&A(BU`(2(U#$$B+3"1H2(E!"$B)2Q!(B5`(2(D"26/6N`$```!$B?E(T^`)
-MA)6L````9F9FD&9FD`^WM"2`````9CFULA(```^%+OC__V:!O;(2``#_#W0C
-M2(N%F!$``(L`B04`````)?\/```/MY6R$@``.=`/A<[W__](C84(`0``2#F%
-M"`$``'1)2(G#2(G?Z`````!(C7#P#[=.,HG*9L'J!8'B_P<``(/A'[@!````
-M2-/@]]`AA)6L````N@````!(B>_H`````$@YG0@!``!UNDB)[^@`````N`$`
-M``!(@<2H````6UU!7$%=05Y!7\-F9I!FD$B#["A(B5PD"$B);"003(ED)!A,
-MB6PD($B+G_`(``!(BT,(1(LH1(DM`````$'WQ0```)!T>DB+0PA$B2CK<9!(
-M@<.(%```2(L#BY!0`0``B14`````2(L#B9!0`0``A=)T//?"````$'0<2(L#
-MQX!0`0``````$$B+`XN`4`$``(D%`````$B+`\>`4`$```$```!(B=_H````
-M`$$!Q(/%`8/]`G69ZQ=F9F:09F:00;P`````O0````#KBF9FD$6$Y`^5P$6%
-M[0^5P@G0#[;`2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9FD&9FD$%7059!
-M54%455-(@^PH28G\2(L'BY!0`0``B14`````2(L'B9!0`0``9F9FD&9FD/?"
-M`/__``^$*`D``$&`?"1#``^$'`D``,9$)!``B=)(B50D"$0/MFPD$$&-30A(
-MBT0D"$C3^*@!=11!C4T02(M$)`A(T_BH`0^$T0@``(!\)!`#=BM)BP0D2`6`
-M`0``0HT4[0````!(8])(`="+`(D%`````,'H$X/@`>LI9F:028L$)$@%@`$`
-M`$*-%.T`````2&/22`'0BP")!0````#!Z!.#X`&$P'0F3(GGZ`````!)8]5(
-MC0122(T$@D&!C,3L$@`````(`&9F9I!F9I!)BQ0D@'PD$`-V)4*-!.T`````
-M2)A(C80"@`$``(L`B04`````)0```0#K(V9F9I!"C03M`````$B82(V$`H`!
-M``"+`(D%`````"4```$`A<!T08!\)!`#=AU"C03M`````$B82(V$`H`!``#'
-M`````0#I&0@``$*-!.T`````2)A(C80"@`$``,<````!`.G\!P``08!\)%$!
-M#X6H!@``@'PD$`-V*4F+!"1(!8`!``!"C13M`````$ACTD@!T(L`B04`````
-M@^`!ZR=F9F:028L$)$@%@`$``$*-%.T`````2&/22`'0BP")!0````"#X`&$
-MP`^$50$``$ECQ4B-'$!(C1R82,'C`TF-M!SP$@``28M\)"CH`````$F+O!S(
-M$@``2(7_=!U(BT=`2(7`=!3V0$X"=0[H`````(3`D`^%"@$``$ECQ4B-%$!(
-MC12028N$U,@2``!(A<!T=4F)QH!X#@`/A(L```!!OP````!(C6A@2(GOZ```
-M``!(B<-(BT4(2(E="$B)*TB)0PA(B1CV0TP"=2](BU-`2(72=!9)B[0D\`@`
-M`+\%````Z`````"`2TP"2(G:O@8```!,B??H`````$&#QP%%.'X.=B7KH@^V
-M="00N@$```!,B>?H`````+^@A@$`Z`````"Z`"TQ`>L%ND!+3`!)8\5(C0Q`
-M2(T,B$C!X0-*C30AB9;P$@``2,>&`!,````````/MD0D$$B-%$!(C12028V4
-MU+@2``!(B98($P``28VT#/`2``!)BWPD*.@`````9F:0@'PD$`-V/4*-%.T`
-M````2&/228L$)$@%@`$``$@!T(L`B04`````28L$)$@%@`$``$@!PHL"B04`
-M````P>@'@^`!ZSM"C13M`````$ACTDF+!"1(!8`!``!(`="+`(D%`````$F+
-M!"1(!8`!``!(`<*+`HD%`````,'H!X/@`83`='6`?"00`W8W0HT,[0````!(
-M8\E)BP0D2`6$`0``2`'(BP")!0````!)BQ0D2('"A`$``$@!T0T```$`B0'K
-M/D*-#.T`````2&/)28L$)$@%A`$``$@!R(L`B04`````28L4)$B!PH0!``!(
-M`=$-```!`(D!ZR^`?"00`W8H28L$)$@%@`$``$*-%.T`````2&/22`'0BP")
-M!0````#!Z!*#X`'K)DF+!"1(!8`!``!"C13M`````$ACTD@!T(L`B04`````
-MP>@2@^`!A,`/A"("``"`?"00`W8W0HT,[0````!(8\E)BP0D2`6``0``2`'(
-MBP")!0`````-```$`$F+%"1(@<*``0``2`'1B0'K-4*-#.T`````2&/)28L$
-M)$@%@`$``$@!R(L`B04`````#0``!`!)BQ0D2('"@`$``$@!T8D!26/%2(T4
-M0$B-%)!)BX34R!(``$B%P'0328G%2(-X0``/A:(```#IA`$``(!\)!`#=DI"
-MC13M`````$ACTDF+!"1(!8`!``!(`="+"(D-`````$F+!"1(!8`!``!(C00"
-MB0A)BP0D2`6``0``2`'"BP*)!0````#IT`,``$*-%.T`````2&/228L$)$@%
-M@`$``$@!T(L(B0T`````28L$)$@%@`$``$B-!`*)"$F+!"1(!8`!``!(`<*+
-M`HD%`````.F&`P``9I!(BTA`#[=!3@^WT/;&`0^%TP```$B)S?;"`@^$QP``
-M`(/@_6:)04Y(C;'`````28M\)"CH`````,9$)!``@'T[`'1WQD0D$``/MD0D
-M$$B+7,582(7;=%1(BU-`2(72=!9)B[0D\`@``+\%````Z`````"`2TP"2(G:
-MO@8```!,B>_H`````("[@P````!T')!,B>?H`````+\!````Z`````"`NX,`
-M````=>6`1"00`0^V1"00.$4[=X['A<````!`2TP`2,>%T`````````!(B:W8
-M````2(VUP````$F+?"0HZ`````"`?"00`W8R28L$)$@%@`$```^V5"002,'B
-M`X'B^`<``$@!T(L`B04`````P>@(@^`!ZS!F9I!F9I!)BP0D2`6``0``#[94
-M)!!(P>(#@>+X!P``2`'0BP")!0````#!Z`B#X`&$P`^$%@$``(!\)!`#=BQ)
-MBP0D2`6``0``#[94)!!(P>(#@>+X!P``2`'0BP")!0````"#\`&#X`'K*DF+
-M!"1(!8`!```/ME0D$$C!X@.!XO@'``!(`="+`(D%`````(/P`8/@`83`#X2Q
-M````#[9$)!!(C11`2(T4D$F-E-2P$@``3(UZ"$F+1Q!(A<`/A(L```!)B<9(
-MC7)`28M\)"CH`````$&`?@X`=%%!O0````!)C6Y@D$B)[^@`````2(G#2(M%
-M"$B)70A(B2M(B4,(2(D82(M30$B%TG0628NT)/`(``"_!0```.@`````@$M,
-M`D&#Q0%%.&X.=[I!QT<X@(0>`$G'1T@`````38E_4$F-=SA)BWPD*.@`````
-M@'PD$`,/AG\````/MEPD$$C!XP.!X_@'``!)BP0D2`6``0``2`'8BQ")%0``
-M``!)BP0D2`6``0``2(T$`XD028L$)$@%@`$``$B-!`.+`(D%`````$F+!"1(
-M!3`"``!(C00#QP``````OQ`G``#H`````$F+!"1(!30"``!(`<.+`XD%````
-M`.M]#[9<)!!(P>,#@>/X!P``28L$)$@%@`$``$@!V(L0B14`````28L$)$@%
-M@`$``$B-!`.)$$F+!"1(!8`!``!(C00#BP")!0````!)BP0D2`50`@``2(T$
-M`\<``````+\0)P``Z`````!)BP0D2`54`@``2`'#BP.)!0````"`1"00`0^V
-M1"0003A$)$,/A_#V__])BP0DBY!0`0``B14`````28L$)(F04`$``/?"`/__
-M`'0FZ:7V__]F9I!FD$ECU4B-!%)(C02"08&,Q.P2``````$`Z>CW__^X````
-M`$B#Q"A;74%<05U!7D%?PT%7059!54%455-(@^QH28G]0(AT)$M`#[;&B40D
-M3$B82(T40$B-%)!(C1373(NZR!(```^VJL(2``!(BP=`@/X#=@S'@'`!``#$
-M`0``ZPK'@'`!``"H`0``2(E$)&!(!70!``!(B40D4$B+5"1@BX)T`0``B04`
-M````BTPD3(/A`[L'````T^-!B=Q!"<1$B:)T`0``O^@#``#H`````/?31"'C
-M2(M,)&")F70!``"`?"1+`W95BT0D3,'@`DB82(V4`=`!``"+`HD%`````(/(
-M"(D"BUPD3,'C`TACVTB-A!D``@``QP`X````OQ`G``#H`````$B+5"1@2(V$
-M&@0"``#'``````#K6(M$)$S!X`)(F$B+3"1@2(V4`=`!``"+`HD%`````(/(
-M"(D"BUPD3,'C`TACVTB-A!D``@``QP`X````OQ`G``#H`````$B+5"1@2(V$
-M&@0"``#'``````!-A?\/A%<(``!!@'U#`'0LNP`````/MLM!#[9'#4C3^*@!
-M=`^Z`0```(G.3(GOZ`````"#PP%!.%U#=]E!]D<*`71G3(G^3(GOZ`````"+
-M="1,3(GOZ`````!(8T0D3$B-%$!(C12028V4U>`2``"+0@BI```0`'0()?__
-M[_^)0@A,B?Y,B>_H`````$AC1"1,2(T40$B-%)!)QX35R!(```````#IM@<`
-M`$&`?U@`=!1)B[VP$```3(G^Z`````!!@&]8`4C'P/[___\/MDPD3$C3P$`@
-MZ(A$)%L/A+T"``"+="1,3(GOZ`````!(8T0D3$B-%$!(C12028V4U>`2``"+
-M0@BI```0`'0()?__[_^)0@@/MD0D6T&(1PU!@'U#``^$[P$``,=$)%P`````
-M#[;02(E4)#!(BTPD8$B!P0`"``!(B4PD*$B+1"1@2`4$`@``2(E$)"`/ME0D
-M6XE4)!Q(BTPD8$B!P=`!``!(B4PD$$0/MG0D7$$/MNY(BT0D,(GI2-/XJ`$/
-MA$T!``!(8\5(C11`2(T4D`^V1"1;08B$U<(2``!!@/X##X:5````C1SM````
-M`$ACVTB+1"0H2`'8QP`X````OQ`G``#H`````$@#7"0@BU0D'(D32(M,)&#'
-M@7`!``#$`0``2(M4)%"+`HD%`````(GI@^$#NP<```#3XT&)W$$)Q$2)(K_H
-M`P``Z`````#WTT0AXTB+3"10B1F-%*T`````2&/22`-4)!"+`HD%`````(/(
-M"(D"Z98```"-'.T`````2&/;2(M$)"A(`=C'`#@```"_$"<``.@`````2`-<
-M)""+1"0<B0-(BU0D8,>"<`$``*@!``!(BTPD4(L!B04`````B>F#X0.[!P``
-M`-/C08G<00G$2(M$)%!$B2"_Z`,``.@`````]]-!(=Q(BU0D4$2)(HT4K0``
-M``!(8])(`U0D$(L"B04`````@\@(B0*#1"1<`4&-1@%!.$5#=BSI@_[__TB)
-MW^@`````2(UPR$B+4PA(B4,(2(D82(E0"$B)`DB#>-@`=!'K";X`````28U?
-M2$DY7TAURDB%]G0XQD9:`$&`?4,`="VY`````+H`````00^V1PU(T_BH`70.
-M#[;"B$P&<(!&6@&#P@&#P0%!.$U#=]VZ`````+Z!````3(G_Z`````!(8T0D
-M3$B-%$!(C1202<>$U<@2````````08!]0P`/A9\#``#IP@0``+H`````O@8`
-M``!,B?_H`````(MT)$Q,B>_H`````$AC1"1,2(T40$B-%)!)C935X!(``(M"
-M"*D``!``=`@E___O_XE""$F-1TA).4=(#X0``@``2(D$)$B+/"3H`````$R-
-M<,A(C5`02#E0$`^$PP$``$F-1DA(B40D"$B+?"0(Z`````!(C5CP@'M)#747
-M2(VP4`$``$B+0U!(BP!(BW@HZ`````!(BQ-(BT,(2(E""$B)$("[@P````!T
-M'6:03(GOZ`````"_`0```.@`````@+N#`````'7E2(M#0$B%P`^$*@$``$C'
-M0&``````@+N#``````^$IP```&9!@WUH``^$FP```+T`````0;P`````3(G@
-M20.%L`D``$B+,$B%]G1J#[=&(&8[0SAU8&8]A0!W6@^WP$&`O`5@"```_W1,
-M28M5``^W1C)FP>@%#[?`C02%``,``(F"<`$``$F+50`/MTXR@^$?N`$```!(
-MT^")@G0!``#&1B0AN@````!,B>_H`````&9FD&9FD(/%`4F#Q`A!#[=%:#GH
-M#X]P____]D-,!'493(GOZ`````!(BW-`N@$```!,B>_H`````$B+0T`/ME`"
-M#[9P`4C'QP````"X`````.@`````2(M30$F+M?`(``"_`0```.@`````2(M3
-M0$F+M?`(``"_!@```.@`````2,=#0`````!!@&\.`4&`;E@!2(G>3(GOZ```
-M``!(BU0D"$DY5D@/A4;^__]!@&\H`4R)]DR)[^@`````2(L,)$DY3T@/A03^
-M__])C4=@23E'8`^$$`$``+T`````28G$2<?&`````$R)Y^@`````2(G#@+B#
-M`````'0WC44!@?U_EI@`=@2)Q>LHB<5,B>_H`````+\!````Z`````"`NX,`
-M````=`N#Q0&!_8&6F`!UVDB+0T!(A<`/A(\```!(QT!@`````/9#3`1U&4R)
-M[^@`````2(MS0+H!````3(GOZ`````!(BU-`#[:"S````(T$@`^V4@(!T$B8
-M00^V#`9!#[95.D$/MG4Y2,?'`````+@`````Z`````!(BU-`28NU\`@``+\!
-M````Z`````!(BU-`28NU\`@``+\&````Z`````!(QT-``````$&`;PX!2(G>
-M3(GOZ`````!-.6=@#X7__O__3(G^3(GOZ`````!(8T0D3$B-%$!(C1202<>$
-MU<@2````````Z5;\__]!OP`````/MD0D6TB)1"1`2(M4)&!(@<+0`0``2(E4
-M)#A%B?Y!#[;O2(M$)$")Z4C3^*@!=0M$.'PD2P^%U0```$&`_@-V:$B+1"1@
-MQX!P`0``Q`$``$B+5"10BP*)!0````")Z8/A`XT,2;L'````T^-!B=Q!"<1$
-MB2*_Z`,``.@`````]]-$(>-(BTPD4(D9C12M`````$ACTD@#5"0XBP*)!0``
-M``"#R`B)`NMG2(M$)&#'@'`!``"H`0``2(M4)%"+`HD%`````(GI@^$#C0Q)
-MNP<```#3XT&)W$$)Q$2)(K_H`P``Z`````#WTT$AW$B+3"101(DAC12M````
-M`$ACTD@#5"0XBP*)!0````"#R`B)`D&#QP%!C48!03A%0P^'^?[__TB#Q&A;
-M74%<05U!7D%?PV9F9I!F9F:09F:09F:005154TF)_$B)]0^V=T-`A/9T)@^V
-M50V[`````/;"`70.ZQ9(B=")V4C3^*@!=0^#PP%`./-U[.L%NP````#V10P"
-M=0I(C45@2#E%8'5H2(GOZ`````"$P'113(GGZ`````!(B<9(A<!T3$B+56A(
-MB45H2(U%8$B)!DB)5@A(B3*`10X!2(EN4,9&2`7&1DD`QH:!````#[D!````
-MN@$```!(B>_H`````.L+#[;S3(GGZ`````!;74%<PV9FD&:0059!54%455-(
-MB?U!B?5$#[;V0HT$M0````!,8^"[`````+\0)P``Z`````!!@/T#=AY(BT4`
-M2`70`0``3`'@BP")!0````#!Z!2#X`'K'9!(BT4`2`70`0``28T$!(L`B04`
-M````P>@4@^`!A,!U"H/#`6:!^RP!=:A$B?9(B>_H`````$B)[^@`````26/&
-M2(T40$B-%)!(C435`/:`P1(```%T#TB+L,@2``!(B>_H`````%M=05Q!74%>
-MPV:0059!54%455-!B?5)B?Q$#[;V26/&2(T40$B-%)!(BZS7R!(``$B%[0^$
-ME@$``$C'P/[___]$B?%(T\"$10T/A8`!``!(C45(2#E%2'450;T`````2(U=
-M8(!]#@!U(^GS`@``0`^VQDB-/$!(C3RX28V\_+@2``#H`````.G5`@``2(G?
-MZ`````!(B<%(BT,(2(E+"$B)&4B)00A(B0B`>4D`#X4)`0``#[=!.$F#O,1@
-M!````'4+2(-Y0``/A-D````/MT$X28N$Q&`$``!(@[B```````^$IP```,:!
-MZ``````/ME%(2(G0@^`&2(/X!G4M]L(!="C&04H%QD%+!`^VD8$```!(BW%8
-M2(MY4.@`````Z9@```!F9F:09F:0#[912$B)T(/@!DB#^`1U(/;"`70;QD%*
-M`\9!2P1(B<Y,B>?H`````.MG9F:09F:0#[912$B)T(/@!DB#^`9U4?;"`75,
-MQD%+!L9!2@5FQX'(``````!(B<Y,B>?H`````.LN2(M10$F+M"3P"```OP0`
-M``#H`````.L6#[=1.$F+M"3P"```OP(```#H`````$&#Q0%$.&T.#X:7`0``
-MZ;W^__]"C02U`````$ACZ+L`````OQ`G``#H`````$&`_0-V'4F+!"1(!=`!
-M``!(`>B+`(D%`````,'H%(/@`>L;28L$)$@%T`$``$@!Z(L`B04`````P>@4
-M@^`!A,!U"H/#`6:!^RP!=:I$B?9,B>?H`````$R)Y^@`````26/&2(T40$B-
-M%)!)BZS4R!(``$B%[0^$_0```$&`?"1#`'0LNP`````/MLL/MD4-2-/XJ`%T
-M#[H`````B<Y,B>?H`````(/#`4$X7"1#=]E!#[;%2(T40$B-%)!)C934N!(`
-M`$B)52!(C45(2#E%2'4X2(U%8$@Y16!U+NM[9F:09I!(B=_H`````$B-<,A(
-MBU,(2(E#"$B)&$B)4`A(B0)(@WC8`'01ZPF^`````$B-74A(.5U(=<I(A?9T
-M6\9&6@!!@'PD0P!T3[D`````N@`````/MD4-2-/XJ`%T#@^VPHA,!G"`1EH!
-M@\(!@\$!03A,)$-V(NO;]D4*`70-2(GN3(GGZ`````#K#;X`````2(GOZ```
-M``!;74%<05U!7L.02(/L"$R+!T2+3S1!#[9P0T"$]G1B28V`N!(``+D`````
-M2#GX=1KK3P^VP4B-%$!(C12028V4T+@2``!(.?IT"(/!`4`X\77@@/D#=B])
-MBP!(!=`!``!(C12-`````('B_`,``$@!T(L`B04`````P>@4@^`!ZRVY````
-M`$F+`$@%T`$``$B-%(T`````@>+\`P``2`'0BP")!0````#!Z!2#X`&$P'00
-M#[;Q1(G*3(G'Z`````#K"P^V\4R)Q^@`````2(/$",-F9F:09F9FD$%7059!
-M54%455-(@^P(2(GS28G^3(NGB````$F++"1!]D0D#!!T!,9'409!#[9&43P!
-M='D\`7(5/`0/A)D````\!@^%2`,``.FZ`0``0<9&40%,B?9(B>_H`````,9#
-M)(%!@$PD#`A(@[N``````'0/2(VS@````$B)[^@`````2(V5^````$B+A?@`
-M``!(B5@(2(D#2(E3"$B)G?@```!(B>_H`````.GC`@``08!D)`SW08!&4@%!
-MQD91`,9#)`)(B=Y(B>_H`````$B)[^@`````Z;<"``!!#[9$)`R#X/>#R!!!
-MB$0D#$&+E@@!``"-0@%!B88(`0``@_H"#X<#`0``2(.[@`````!T#TB-LX``
-M``!(B>_H`````$B-E?@```!(BX7X````2(E8"$B)`TB)4PA(B9WX````08!^
-M0@!U&$&_`````$V-;"1@08!\)`X`=1[IG@```+H`````O@(```!,B>?H````
-M`&:0Z1L"``!,B>_H`````$B)PTF+10A)B5T(3(DK2(E#"$B)&$B+4T!(A=)T
-M%4B+M?`(``"_!0```.@`````@$M,`DB)VKX&````3(GGZ`````"`NX,`````
-M=")F9F:09F:02(GOZ`````"_`0```.@`````@+N#`````'7E08/'`44X?"0.
-M#X=[____3(GWZ`````#IB0$``$&`9"0,]T''A@@!````````2(.[@`````!T
-M#TB-LX````!(B>_H`````$B-E?@```!(BX7X````2(E8"$B)`TB)4PA(B9WX
-M````N@````"^!@```$R)Y^@`````28U$)&!).40D8'1\28G%3(GOZ`````!(
-MB<-(BT!`2(7`=%-(QT!@`````$B)[^@`````2(MS0+H!````2(GOZ`````!(
-MBU-`2(NU\`@``+\!````Z`````!(BU-`2(NU\`@``+\&````Z`````!(QT-`
-M`````$B)WDB)[^@`````33EL)&!UATR)]DB)[^@`````2<=$)$``````2(M%
-M`(N06`$``(D5`````(72=`I(BT4`B9!8`0``0?9$)`H!=&N`?4,`="RY````
-M`$'V1"0-`705ZQUF9I!F9I!!#[9$)`U(T_BH`74/@\$!.$U#=^OK!;D`````
-M#[;9B=Y(B>_H`````$R)YDB)[^@`````2&/;2(T$6TB-!(-(QX3%R!(`````
-M``!F9I!FD$B#Q`A;74%<05U!7D%?PY!(@^PH2(E<)`A(B6PD$$R)9"083(EL
-M)"!(B?-(B?U,BV]038ME``^W3C*)R&;!Z`4/M_!(8\9!BT2$;(/A'TC3^*@!
-M#X5G`P``28L4)(T$M0`#``")@G`!``!)BP0DBY!T`0``B14`````QD,D(8M#
-M."7___\`/>$!#P!U(TB)W^@`````N@````!(B=Y,B>?H`````.D6`P``9F:0
-M9F:0B=`/MTLR@^$?2-/XJ`%T$$B)W^@`````3(GGZ``````/MH7H````/`0/
-MA^$"```/ML#_),4`````QH7H`````;H!````2(G>3(GOZ`````#INP(``,:%
-MZ`````*Z"````$B)WDR)[^@`````Z9\"``#&A>@````#2(GJOB$```!,B>_H
-M`````$B+=5A(A?9T'P^VE8$```!!N`````"Y`0```$R)[^@`````Z6`"``!!
-M#[9U#;H`````3(GGZ`````#I20(``,:%Z`````1(@WU8`'0S2(GJOB$```!,
-MB>_H``````^VE8$```!(BW580;@`````N0(```!,B>_H`````.D(`@``N@``
-M``"^(0```$R)[^@`````00^V=0VZ`0```$R)Y^@`````Z=\!``"`?4K_=!5(
-MB>J^!@```$R)[^@`````Z<0!``!(B>J^!@```$R)[^@`````2(M-0$B%R702
-MBU$$C4(!B4$$@_H%#X:9`0``QD5+`<9%2@"`O8,`````=!M,B>?H`````+\!
-M````Z`````"`O8,`````=>5(@WU8`'092(M5$$B+11A(B4((2(D02(M%6(!H
-M6`'K&4B+56!(A=)T$`^VA8$```!(QT3"6`````!(BU4`2(M%"$B)0@A(B1!!
-M@&T.`4B+O2`!``!(A?]T$0^VM0T!``"Z`0```.@`````2(M]6$B%_W01#[:U
-M@0```+H!````Z`````!(BT5`2(7`=')(QT!@`````$R)Y^@`````2(MU0+H!
-M````3(GGZ`````!(BT5`#[90`@^V<`%(Q\<`````N`````#H`````$B+54!)
-MB[0D\`@``+\!````Z`````!(BU5`28NT)/`(``"_!@```.@`````2,=%0```
-M``!(B>Y,B>?H`````$&`?0G_=%R]`````$&`?0X`=#F]`````$F-76!F9F:0
-M9F:02(G?Z`````!(BU,(2(E#"$B)&$B)4`A(B0*`>$K_=0F#Q0%!.&T.=]=!
-M.&T.=Q%!QD4)_TR)[DR)Y^@`````D$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$
-M*,-F9F:09F:005=!5D%505154TB#[&A)B?](BX>(````2(E$)&!(BRA(BX68
-M$0``1(LP2(G^2(GOZ`````!!@']2`78%0<9'401)C5\H23E?*`^$4P$``$B)
-MW^@`````2(E$)%A)BT<H2(M4)%A(B5`(2(D"2(E:"$F)5RA(A=(/A#L#``!(
-MBTPD8$B+02`/MDU!#[95.@^V=3E(BUPD6$0/MTLR1`^V0`A(Q\<`````N```
-M``#H`````$0/MVLR36GEL`0``$P#I3@1``!(BYW8$```2(M\)%CH`````$&+
-MC"0D!```08N4)"`$``!(BWPD6`^W=S)%BXPD+`0``$6+A"0H!```2,?'````
-M`+@`````Z`````!)P>4&3`'KBT,TBWLP1(M3+$2+6RA$BV,D1(MK((M3'(E4
-M)$R+2QB)3"10BU,4B50D5$2+2Q!$BT,,BTL(BU,$BS.)1"1`B7PD.$2)5"0P
-M1(E<)"A$B60D($2);"08BUPD3(E<)!"+?"10B7PD"(M$)%2)!"1(Q\<`````
-MN`````#H`````&:#?6@`=3OIZP$``$B+5"1@2(M"(`^V34$/ME4Z#[9U.4&Y
-M____`$0/MD`(2,?'`````+@`````Z`````#I$0(``+L`````3(VEH`\``$R-
-MK?@```!F9I!FD`^WPTC!X`-(`X6P"0``2(LP2(7V#X1V`0``#[=&(&9!.4=`
-M#X5G`0``#[>5LA(``$$YUG10@\(!#[>%MA(``#G"N``````/0]"-0@%(P>`"
-M2`.%F!$``(L`J0``"`!U(&8E_P]F.=AU%T@Y="18=15(B>_H`````.E\`0``
-M9F:01#GR=;`/MT8@9CV%`&9FD`^'^@````^WP("\!6`(``#_#X3I````2(M,
-M)&"`>5@`#X7:````]D$*`0^$T````$B+50`/MT8R9L'H!0^WP(T$A0`#``")
-M@G`!``!(BT4`#[=.,H/A'[H!````2(G72-/GB;AT`0``#[=&,DC!X`-(`X6P
-M"0``2,<```````^W3C*)R&;!Z`4E_P<``(/A'TB)UTC3YTB)^??1(8R%N`D`
-M``^W3C*)R&;!Z`4E_P<``(/A'TC3XO?2(52%;$@Y="18="=(BP9(BU8(2(E0
-M"$B)`DB+A?@```!(B7`(2(D&3(EN"$B)M?@````/MW8R3(GGZ`````!!@&]%
-M`69F9I"#PP%F.5UH#X=C_O__2(M$)&#V0`H!=%%(BTPD6$B+$4B+00A(B4((
-M2(D02(G.3(G_Z`````#K,4B+7"1@2(M#(`^V34$/ME4Z#[9U.4&Y____`$0/
-MMD`(2,?'`````+@`````Z`````!(@\1H6UU!7$%=05Y!7\-F9F:09F9FD$%7
-M059!54%455-(@^PH28GX2(E4)"!,BR\/M_9(P>8#20.UL`D``$B++F:!?3CA
-M`74N#[9%.H/H$3P!=R-,BW]`2,=$)!@`````2(72=6E!QD=1`$C'1"08````
-M`.M9D$F+C3@)``"X8)X!`&:!?2"%`'<<#[=%($$/MH0%8`@``$B-%$!(C120
-M2(G02,'@!4@!P4B)3"080;\`````2(-\)"``=1)(BT0D&,:`Z`````!!OP``
-M``"`?22!=05!@&`,]TB#?"0@``^%`@$``,9%)`#VA98````@#X2"!0``2(M%
-M:$B%P`^$=04``$B)P_:`L0````)T'4B+N*````!(A?]T$4B+=4A(A?9T"(M5
-M-.@`````28N5"!$``$B!PD`(``!(BTPD&`^V07+!X`A(F$@!PHL"B04`````
-MB<+!ZA"(DYL```#!Z!AFB8.0````28N5"!$``$B!PD0(```/MD%RP>`(2)A(
-M`<*+$HD5``````^VPF:)@Y0````/ML9FB8.6````B=#!Z!`/ML!FB8.8````
-MP>H8B).:````28N5"!$``$B!PDP(```/MD%RP>`(2)A(`<*+`HD%``````^V
-MP&:)@Y(```#ID00```^W13)(:<"P!```38NE.!$``$D!Q$F-G"0@!```@'TD
-M@'4$QD4D(4B#?"08``^$F````$B+1"082(M00$B%TG1"#[:"S````(T$@`^V
-M4@(!T$B8#[:(`````$$/ME4Z00^V=3E,BTPD($2+131(Q\<`````N`````#H
-M`````.F#````BWTT2(M,)!A$#[:)@0```$F+0"!$#[9`"$$/MDU!00^V53I!
-M#[9U.4B+1"0@2(E$)`B)/"1(Q\<`````N`````#H`````.L[387_=#9$BTTT
-M28M`($0/MD`(00^V34%!#[95.D$/MG4Y2(M$)"!(B00D2,?'`````+@`````
-MZ`````"+2P2+$P^W=3)$BTL,1(M#"$C'QP````"X`````.@`````0?9$)"(!
-M='],C6583(NU@````$&+5"0$00^V="0!2,?'`````+@`````Z`````"`?5@`
-M#X3R````NP`````/ML-(C01`2,'@`DF+5"0(2`'"20-&$(M*"$B+$@^V\T2+
-M2`A,BP!(Q\<`````N`````#H`````(/#`4$X'"0/AJ@```#KN6:008!\)"<`
-M#XF8````#[=U,HGR9L'J!0^WT@^W]DC'QP````"X`````.@`````08N-P`D`
-M`$&+E;P)``!!B[6X"0``18N%Q`D``$C'QP````"X`````.@`````#[=U,DC'
-MQP````"X`````.@`````28M5``^W13)FP>@%#[?`C02%``,``(F"<`$``$F+
-M50`/MTTR@^$?N`$```!(T^")@G0!``!F@7TXX0%U&`^V13J#Z!$\`7<-3(G_
-MZ`````#I'@(```^V5"0C]L(!#X3N`0``BT4X)?___P`]X0$.``^$VP$``$F+
-ME0@1``!(@<)`"```2(M,)!@/MD%RP>`(2)A(`<)$BR)$B24`````28N5"!$`
-M`$B!PD0(```/MD%RP>`(2)A(`<)$BS)$B34`````28N5"!$``$B!PD@(```/
-MMD%RP>`(2)A(`<*+&HD=`````$F+E0@1``!(@<),"```#[9!<L'@"$B82`'"
-M1(L"1(D%`````(G91(GR1(GF2,?'`````+@`````Z`````#VA98````@#X3J
-M````2(M]:,:'L@```!#&120@1(G@P>@0B(>;````1(G@P>@89HF'D````(G8
-MP>`(00^VU@'09HF'E````(G8L`!,B?$/MM4!T&:)AY8```")VL'J$,'B"$2)
-M\,'H$`^VP`'"9HF7F````$F+E0@1``!(@<),"```2(M,)!@/MD%RP>`(2)A(
-M`<*+,HDU`````$`/MO9FB;>2````#[>/E@````^WEY@````/M_9$#[>'E```
-M`$C'QP````"X`````.@`````28N5"!$``$B!PD`(``!(BTPD&`^V07+!X`A(
-MF$@!PL<"`````.M:9H%]..$!=2(/MD4Z@^@:/`%W%TC'QP````"X`````.@`
-M````QD4D(>LP2(GN3(GOZ`````#K(Y"$TGD>28M%`(N(6`$``(D-`````(7)
-M=`I)BT4`B8A8`0``2(/$*%M=05Q!74%>05_#9F9FD&9F9I!F9F:09F:02(/L
-M"`^V1CA(.7XH=4H\"'1E/"AT83RH=%T\B&9F9I!T53P*=%$\*G1-/*IF9F:0
-M=$4\BG1!2(N'^````$B)<`A(B09(C8?X````2(E&"$B)M_@```#K'TB+EP`!
-M``!(B;<``0``2(V'^````$B)!DB)5@A(B3+H`````$B#Q`C#9F9FD&9F9I!F
-M9F:09F:02(/L".@`````2(/$",-FD%-(@^Q@2(G[2(U,)%U(C50D7DB-="1?
-M#[=_/$B-1"122(E$)#A(C40D5$B)1"0P2(U$)$Q(B40D*$B-1"1.2(E$)"!(
-MC40D6$B)1"082(U$)%I(B40D$$B-1"1;2(E$)`A(C40D5DB)!"1,C4PD7$R-
-M1"10Z``````/ME0D7P^V="1>2(U\)$CH``````^V1"1?2(T40$B-%)!(P>(%
-M2(MS($B-NQ@)``"Y`0```.@`````#[94)%U(C1322,'B!4B+<R!(C;M`"0``
-MN0$```#H``````^V5"1>2&G2R`\``$B+<R!(C;MH"0``N0$```#H``````^W
-M5"182,'B`TB+<R!(C;N0"0``N0$```#H``````^W1"102(T4@$B-%)!(P>(#
-M2(MS($B-NV@*``"Y`0```.@`````#[94)%P/MT0D4$@/K]!(C1122,'B`DB+
-M<R!(C;OX"0``N0$```#H`````$B+<R!(C;L@"@``N0$```"Z``(``.@`````
-M#[9,)%](BW,@2(V[6`L``+H`"```Z``````/ME0D6TC!X@5(BW,@2(V[N`H`
-M`+D!````Z`````!(BW,@2(V[X`H``+D!````N@`!``#H``````^V5"1:2(T4
-MDDC!X@5(BW,@2(V["`L``+D!````Z``````/MU0D5DB-%))(P>(#2(MS($B-
-MNS`+``"Y`0```.@`````#[=4)%A(`=)(BW,@2(V[>`\``+D!````Z``````/
-MME0D7T@!TDB+<R!(C;NP#P``N0$```#H``````^V5"1=2`'22(MS($B-N^@/
-M``"Y`0```.@`````#[94)%Y(`=)(BW,@2(V[(!```+D!````Z``````/ME,^
-M2`'22(MS($B-NU@0``"Y`0```.@`````#[=4)$Y(C1122,'B!$B+<R!(C;N0
-M"@``N0$```#H`````(M4)$A(BW,@2(V[D!```+D!````Z``````/MU0D6$C!
-MX@9(BW,@2(V[N!```$&X`0```+E`````Z`````!(BW,@2(V[Z!```$&X`0``
-M`+D``0``N@`9``#H``````^W5"182&G2L`0``$B+<R!(C;L8$0``0;@!````
-MN8````#H``````^W5"142,'B`DB+<R!(C;M($0``0;@!````N00```#H````
-M``^W5"122,'B`DB+<R!(C;MX$0``0;@!````N00```#H``````^V5"1;P>(+
-M2(MS($B-NZ@1``!!N`$```"Y"````.@`````2(MS($B-N]@1``!!N`$```"Y
-M"````+H```@`Z``````/MU0D5DAITHP!``!(BW,@2('#"!(``$&X`0```+D(
-M````2(G?Z`````"X`````$B#Q&!;PV9FD&:02(/L.$B)7"0(2(EL)!!,B60D
-M&$R);"0@3(ET)"A,B7PD,$F)]TF)_4B+!TB)!"1,C6=(3(GGZ`````!(B<-,
-MC7#(2(L\).@`````2(G%28M%4$F)75!-B68X28E&0$B)&+@!````2(7M='C&
-M13CAQD4Y`<9%.A"`33L!28N'H````$B)16A(BT5P3(EX*$F-AY````!(B450
-MQD4ES$$/MD9;9HE%($F+10!(B44HQT4TD````$R)?4A(QX6@`````````$B-
-M?5B^`````.@`````2(GN2(L\).@`````N`````!(BUPD"$B+;"003(MD)!A,
-MBVPD($R+="0H3(M\)#!(@\0XPV9F9I!F9I!F9I!!5T%6055!5%532(/L&$B)
-M_4C'1"00`````$B+1"00#[:4*.8(``"`^O\/A.H````/MLI(C02)2(T$@4B-
-MA,7``0``2(E$)`@/MO)(8\9(C12`2(T4D("\U<X!````#X2V````0;P`````
-M2(T$B4B-!(%(P>`#3(VT!2`"``!,C2PH2&/&2(T4@$B-%)!,C;S5P`$``$R)
-M]^@`````2(G#28N%*`(``$F)G2@"``!,B3-(B4,(2(D82(M30$B%TG052(NU
-M\`@``+\%````Z`````"`2TP"2(G:O@(```!(BWPD".@`````@+N#`````'0;
-M2(GOZ`````"_`0```.@`````@+N#`````'7E08/$`44X9PX/AWO___](@T0D
-M$`%(@WPD$`0/A>[^__](B>_H`````$B#Q!A;74%<05U!7D%?PV9F9I!F9I!F
-M9I!F9I!!5T%6055!5%532(/L>$B)^\9'40#&1U``QD=/`,:':10```!(C9>X
-M$@``N`````#&!!``2(/``4@]H`$``'7P2(V#^````$B)@_@```!(B8,``0``
-M2(V#"`$``$B)@P@!``!(B8,0`0``3(VC&`$``$R)HQ@!``!,B:,@`0``3(VK
-M*`$``$R)JR@!``!,B:LP`0``2(V#.`$``$B)1"1(2(F#.`$``$B)@T`!``!(
-MC8M(`0``2(E,)%!(B8M(`0``2(F+4`$``$R-LV@!``!,B;-H`0``3(FS<`$`
-M`$B-LW@!``!(B70D0$B)LW@!``!(B;.``0``3(V[6`$``$R)NU@!``!,B;M@
-M`0``2(U,)&Y(C50D<$B-="1Q#[=[/$B-1"1R2(E$)#A(C40D=$B)1"0P2(U$
-M)&1(B40D*$B-1"1J2(E$)"!(C40D=DB)1"082(U$)&Q(B40D$$B-1"1M2(E$
-M)`A(C40D:$B)!"1,C4PD;TR-1"1FZ``````/MD0D<8A#1@^V1"1PB$-'#[9$
-M)&Z(@_$````/MT0D=F:)0V@/MT0D=&:)@[02```/MT0D<H/H`6:)@[82```/
-MMT0D9F:)0U(/MT,\9CV`D70*9CV`E`^%I`D``,9#303&0T,$QD-.0,9#3`#&
-M@^X````)QD-$`$B-NQ@)``#H`````$B)P4B)@S@)```/MD0D<4B-%$!(C120
-M2,'B!4B%TG002(G(Q@``2(/``4B#Z@%U\TB-NT`)``#H`````$B)P4B)@V`)
-M```/MD0D;DB-!,!(B<)(P>(%2(72=!!(B<C&``!(@\`!2(/J`77S2(V[:`D`
-M`.@`````2(G!2(F#B`D```^V1"1P2&G0R`\``$B%TG002(G(Q@``2(/``4B#
-MZ@%U\TB-NY`)``#H`````$B)P4B)@[`)```/MT0D=DB-%,4`````2(72=!!(
-MB<C&``!(@\`!2(/J`77S2(V[(`H``.@`````2(F#0`H``$B-N_@)``#H````
-M`$B)Q4B)@Q@*``!(C;MH"@``Z`````!(B<)(B8.("@``9H-\)&8`=$BY````
-M`$B):F`/MD0D;XA"6$B+@R`!``!(B9,@`0``3(DB2(E""$B)$`^V1"1O2(T$
-M0$B-;(4`2('"J````(/!`68Y3"1F=[U(C;N0"@``Z`````!(B<)(B8.P"@``
-M9H-\)&H`="^Y`````,9"$`!(BX,P`0``2(F3,`$``$R)*DB)0@A(B1!(@\(P
-M@\$!9CE,)&IWUDB-N[@*``#H`````$B)PDB)@]@*``"`?"1M`'0SN0````!(
-MBX-``0``2(F30`$``$B+="1(2(DR2(E""$B)$$B#PB"#P0$/MD0D;68YR'?2
-M2(V[X`H``.@`````2(G"2(F#``L``$B-B``!``!(BX-0`0``2(F34`$``$B+
-M="102(DR2(E""$B)$$B#PB!(.<IUVDB-NP@+``#H`````$B)PDB)@R@+``"`
-M?"1L`'0QN0````!(BX-P`0``2(F3<`$``$R),DB)0@A(B1!(@<*@````@\$!
-M#[9$)&QF.<AWU$B-NS`+``#H`````$B)PDB)@U`+``!F@WPD:`!T*[D`````
-M2(N#8`$``$B)DV`!``!,B3I(B4((2(D02(/"*(/!`68Y3"1H=]J`?"1Q`'1)
-MO0````!,C:-8"P``3(GGZ``````/M]5(B833>`L``$B+DX`!``!(B8.``0``
-M2(M,)$!(B0A(B5`(2(D"@\4!#[9$)'%F.>AWPTB-NW@/``#H`````$B)@Y@/
-M``!(B8.@#P``#[=T)'9FB;.J#P``#[?V2(V[H`\``.@`````2(V[L`\``.@`
-M````2(F#T`\``$B)@]@/```/MG0D<6:)L^(/```/M_9(C;O8#P``Z`````!(
-MC;OH#P``Z`````!(B8,($```2(F#$!````^V="1N9HFS&A````^W]DB-NQ`0
-M``#H`````$B-NR`0``#H`````$B)@T`0``!(B8-($```#[9T)'!FB;-2$```
-M#[?V2(V[2!```.@`````2(V[6!```.@`````2(F#>!```$B)@X`0```/MD,^
-M9HF#BA````^V<SY(C;N`$```Z`````!(C;N0$```Z`````!(B<%(B8.P$```
-M#[9$)'!(C03`2,'@!XG&@<9@5P``=!*)\DB)R,8``$B#P`%(@^H!=?-(BX.P
-M$```B3!(BY.P$```#[9$)'"(0@0/ME0D<$B+N[`0``#H`````$&X`````(![
-M/@`/A*0```"_``````^WQTB-%(!(C1202,'B`TR-A!/``0``2(T$&D&(>`A!
-MQD`)`$B)F,`!``!!QD`.`,:`&`(```#&@.@!````QX!@`@```````$B-C!/P
-M`0``2(F(\`$``$B)B/@!``!(C8P3"`(``$B)B`@"``!(B8@0`@``2(V4$R`"
-M``!(B9`@`@``2(F0*`(``$'&0`H"@\<!#[9#/F8Y^`^'8?___\9#3`#&@^8(
-M``#_QH/G"```_\:#Z`@``/_&@^D(``#_@'PD<0`/A)8```"^``````^WSDB-
-M!$E(C02!2,'@!4B+DS@)``#&1`)+`4B+DS@)``#&1!!*`$B+DS@)``#&A!"`
-M````_TB+DS@)``#&1!!R_TB+DS@)``!FQX00R```````2,>$RV`$````````
-M2(G!2`.+.`D``$B-42!(B5$@2`.#.`D``$B-4"!(B5`H@\8!#[9$)'%F.?`/
-MAV____]FQX/L``````"X`````,:$&&`(``#_2(/``4@]A@```'7L@'PD<``/
-MA+T```"^``````^WQDAIP,@/``!(BY.("0``QD0"6`!(BY.("0``QD0060!(
-MBY.("0``2,=$$!``````2(G!2`.+B`D``$B-41A(B5$82(G!2`.+B`D``$B-
-M41A(B5$@2(G!2`.+B`D``$B-42A(B5$H2(G!2`.+B`D``$B-42A(B5$P2(N3
-MB`D``$R)1!`(2(G!2`.+B`D``$B-44A(B5%(2`.#B`D``$B-4$A(B5!0@\8!
-M#[9$)'!F.?`/ATC____&@^\```"`@'PD;@`/A((```"^``````^WQDB-!,!(
-MP>`%2(N38`D``&;'1`).!`!(BY-@"0``QD000@!(BY-@"0``QD001/](BY-@
-M"0``QD004/](B<%(`XM@"0``2(U1*$B)42A(B<%(`XM@"0``2(U1*$B)43!(
-MBY-@"0``3(F$$(@```"#Q@$/MD0D;F8Y\'>#QH/P````@DB-L^`0``!(C;NX
-M$```Z`````!(B8/8$```2(VS$!$``$B-N^@0``#H`````$B)@P@1``!(C;-`
-M$0``2(V[&!$``.@`````2(F#.!$``$B-LW`1``!(C;M($0``Z`````!(B8-H
-M$0``2(VSH!$``$B-NW@1``#H`````$B)@Y@1``!(C;/0$0``2(V[J!$``.@`
-M````28G$2(F#R!$``$B+J]`1``"`?"1M`'120;T`````2(M\)$CH`````$R)
-M8!!(B6@82(N30`$``$B)@T`!``!(BW0D2$B),$B)4`A(B0))@<0`"```2('%
-M``@``$&#Q0$/MD0D;69$.>AWM$B-LP`2``!(C;O8$0``Z`````!)B<1(B8/X
-M$0``2(NK`!(``$&]`````$B+?"10Z`````!,B6`02(EH&$B+DU`!``!(B8-0
-M`0``2(M,)%!(B0A(B5`(2(D"28'$```!`$B!Q0```0!!@\4!9D&#_0AUN$B-
-MLS`2``!(C;L($@``Z`````!(B8,H$@``3(NC,!(``&:#?"1H`'1(2(G%0;4`
-M3(G_Z`````!(B6@03(E@&$B+DV`!``!(B8-@`0``3(DX2(E0"$B)`DB!Q8P!
-M``!)@<2,`0``08/%`69$.6PD:'>^2(/$>%M=05Q!74%>05_#9F9FD$%50515
-M4TB#[`A)B?U)B?1(BYZ(````#[961TB)_DB)W^@`````2(G%9D&#3"1.$$&`
-M?4,`=%FY`````/9##0%T#>M,#[9##4C3^*@!=0V#P0%!#[9%0V8YR'?H9H/Y
-M`W8S28M%`$@%T`$``$B-%(T`````@>+\_P,`2`'0BP")!0````#!Z!2#\`&#
-MX`'K,;D`````28M%`$@%T`$``$B-%(T`````@>+\_P,`2`'0BP")!0````#!
-MZ!2#\`&#X`&$P'00#[;Q3(GOZ`````#IEP$``$B-0V!(.4-@#X09`0``2(7M
-M#X00`0``#[:%@0```$G'1,18`````$B+50!(BT4(2(E""$B)$$B)ZKX&````
-M2(G?Z`````"`O8,`````=!M,B>_H`````+\!````Z`````"`O8,`````=>5(
-MBT5`2(7`=$A(QT!@`````/9%3`1U"$R)[^@`````2(M50$F+M?`(``"_`0``
-M`.@`````2(M50$F+M?`(``"_!@```.@`````2,=%0`````"`:PX!2(GN3(GO
-MZ`````!)BT4`BY!8`0``B14`````A=)T"DF+10")D%@!``!!QD0D0@!F08-D
-M)$[O08!\)#L`="JZ``````^WPDF+1,182(7`=`J`>$K_#X5^````@\(!00^V
-M1"0[9CG0=]M!@'PD3@!X#[T`````08!\)#L`=1'K2TR)YDR)[^@`````9I#K
-M2@^WQ4F+7,182(7;="'V0TP"=!M(BU-`28NU\`@``+\&````Z`````"`8TS]
-M9I"#Q0%!#[9$)#MF.>AWQ&9!QT0D3@(`08!D)$G]2(/$"%M=05Q!7<-F9I!F
-M9I!F9I!!5T%6055!5%532(/L>$F)_TB)?"102(M'4$B)1"1P2(LH2(N%F!$`
-M`$2+,$B)_DB)[^@`````08"_ZP````%V"$'&A^@````$28U'($C'1"1H````
-M`$DY1R!T*4F-7R!(B=_H`````$B)1"1H28M'($B+5"1H2(E0"$B)`DB)6@A)
-MB5<@28-_0`!T4$&X____`$B#?"1H`'0*2(M,)&A$#[=!,DF+5T`/MH+,````
-MC02`#[92`@'02)@/MH@`````#[95.@^V=3E(Q\<`````N`````#H`````.M,
-MO____P!(@WPD:`!T"4B+="1H#[=^,D4/MH^!````2(M4)'!(BT(@1`^V0`@/
-MMDU!#[95.@^V=3F)/"1(Q\<`````N`````#H`````$B#?"1H``^$S@,``$B+
-M3"1H1`^W:3)-:>6P!```3`.E.!$``$B+G=@0``!(B<_H`````$&+C"0D!```
-M08N4)"`$``!(BT0D:`^W<#)%BXPD+`0``$6+A"0H!```2,?'`````+@`````
-MZ`````!)P>4&3`'KBT,TBWLP1(M3+$2+6RA$BV,D1(MK((M3'(E4)%R+2QB)
-M3"1@BW,4B70D9$2+2Q!$BT,,BTL(BU,$BS.)1"1`B7PD.$2)5"0P1(E<)"A$
-MB60D($2);"08BT0D7(E$)!"+1"1@B40D"(M$)&2)!"1(Q\<`````N`````#H
-M`````$R+9"1H28/$6$B+5"1H3(NJ@````$&+5"0$00^V="0!2,?'`````+@`
-M````Z`````!!@'PD`0!T3KL`````9F9FD&9FD`^VPTB-!$!(P>`"28M4)`A(
-M`<))`T40BTH(2(L2#[;S1(M("$R+`$C'QP````"X`````.@`````@\,!03A<
-M)`%WOF:#?6@`#X0B`@``0;P`````3(VMH`\``$B-C?@```!(B4PD2$$/M\1(
-MP>`#2`.%L`D``$B+&$B%VP^$WP$```^W0R!F03E'.`^%T`$```^WE;(2``!!
-M.=9T;&9F9I"#P@$/MX6V$@``.<*X``````]#T(U"`4C!X`)(`X68$0``BP"I
-M```(`'4X9B7_#V9$.>!U+D@Y7"1H=2Q(BT0D:`^W<#)(Q\<`````N`````#H
-M`````$B)[^@`````Z9\!``!$.?)UF$B+5"1P@'I8``^%20$```^W0R!F/84`
-M#X<[`0``#[?`@+P%8`@``/\/A"H!``!(@WPD4``/A`0!``!!#[9'2*@!#X3W
-M````J`0/A.\```!(BU4`#[=#,F;!Z`4/M\"-!(4``P``B8)P`0``2(M%``^W
-M2S*#X1^Z`0```$B)UDC3YHFP=`$```^W0S)(P>`#2`.%L`D``$C'```````/
-MMTLRB<AFP>@%)?\'``"#X1](B=9(T^9(B?'WT2&,A;@)```/MTLRB<AFP>@%
-M)?\'``"#X1](T^+WTB%4A6Q(.UPD:'1%2(L32(M#"$B)0@A(B1!(@[N`````
-M`'0/2(VS@````$B)[^@`````2(N%^````$B)6`A(B0-(BT0D2$B)0PA(B9WX
-M````#[=S,DR)[^@`````08"O@P````'K&DB+5"1P]D(*`G0/2(G>3(G_Z```
-M``!F9F:008/$`69$.65H#X?W_?__2(-\)%``="M!#[9'2*@!="*H!'0>2(M,
-M)&A(BQ%(BT$(2(E""$B)$$B)SDR)_^@`````2(/$>%M=05Q!74%>05_#D)"0
-MD)"0D)"0D)"0D)"02(M'4$R+"$&X`````$2-%!9##[:$"&`(```\_W1"#[;`
-M2(T40$B-%)!(P>(%2(G020.!.`D``$`XL`X!``!U($@YN"`!``!U%T2(D`T!
-M``!)BX$X"0``B(P"#`$``&:028/``4F!^(````!UI//#D$B+?U@/MH?`````
-M/$]W,0^VP$B-!$!(P>`$`?*(E`?)````#[:'P````$B-!$!(P>`$B(P'R```
-M`("'P`````'SPV9F9I!F9F:09F:09F:00;C_____9H7V=$Q(B?I!N/____^_
-M`````&9F9I!F9I`/M@J-0=`\"7<;08#X_[@`````1`]$P$$/ML"-!(!$C41!
-MT.L&08#X_W4,@\<!2(/"`68Y]W7)00^VP,-F9F:008G12(M'4$R+`+D`````
-MD$(/MH0!8`@``#S_=#,/ML!(C11`2(T4D$C!X@5(B=!)`X`X"0``2#FX(`$`
-M`'410#BP#0$``'4(1(B(#P$``,-(@\$!2('Y@````'6S\\.028G32(M'4$R+
-M"$R+5UA!N`````!##[:$"&`(```\_W1$#[;`2(T40$B-%)!(P>(%20.1.`D`
-M`$@YNB`!``!U)4`XL@T!``!U'(3)=`Q(BX(8`0``28D#ZQE)BP-(B8(8`0``
-MZPU)@\`!28'X@````'6B3(G7N`````!F9I!F9I`/MI?(````@/H!=D2`^A=T
-M/T`XM\D```!U-H3)=!9(F$B-!$!(P>`$28N$`M````!)B0/#2)A(C01`2,'@
-M!$F+$TF)E`+0````PV9FD&9FD(/``4B#QS"#^%!UI//#9I!!5D%505154TB#
-M[!!)B?Y!B?%(B[\H`0``#[9'`L'@"`^V5P-$C00000^WP(/`!#T`"```#X_L
-M````0(3V=$Q!#[:6$`$``+[@____(=8/MD<!@^`/B=&#X1`)\`G(O@@````A
-MUH/@\XG1@^$$"?`)R(/B`H/@_$$/MHX0`0``@^$!"=`)R(A'`>M*#[97`;[@
-M____(=9!#[:&$`$``(/@#XG1@^$0"?`)R+X(````(=:#X/.)T8/A!`GP"<B#
-MX@*#X/P/MD\!@^$!"=`)R$&(AA`!``!(C5<(00^WP$R-9`<$23G4=C](B50D
-M"+L`````00^VZ4R-;"0(9F:09F:0#[;SB>E,B>I,B??H`````$B+1"0(2(/`
-M!$B)1"0(@\,!3#G@<MI(@\006UU!7$%=05[#9F9FD&9FD&9FD&9FD%-(B?M(
-MBTY(#[9!`L'@"`^V40,!T`^WP(U0!`^W1C0YPG\?2(N_*`$``$ACTDB)SN@`
-M````O@````!(B=_H`````%O#9F9FD&9F9I!F9F:005=!5D%505154TB#[`A)
-MB?=!B=1(BU]828G>O0````!,C6X$#[:#R````#P!=D$\%W0]1#BCR0```'4T
-M00^V5P-(8\5(C01`2,'@!$F-O`;8````@/H@N"`````/1]`/MM),B>[H````
-M`&9FD&9FD(/%`4B#PS"#_5!UJ$B#Q`A;74%<05U!7D%?PV9FD&:02(/L2$B)
-M7"082(EL)"!,B60D*$R);"0P3(ET)#A,B7PD0$F)_$&)UXG+3(D$)$"(="0/
-M2(M'4$R+,$R)]^@`````2(G%2(7`#X3V````3(GWZ`````!)B<5(A<!U$DB)
-M[DR)]^@`````Z=8```!FD$B-15A(B40D$$F+?1")VDF+M"0H`0``Z`````#&
-MA9@````*QD4EK$$/MT0D.&:)12!(BQ0D2(E5:$R)=2B)732#C90````228M%
-M$$B)14A,B6UX28V$).P```!(B450QD4P($C'A:``````````QD4X.\9%.0(/
-MMD0D#XA%.D2)^,'H$(A%.TR)^@^VQHA%/$2(?3T/MD4VB$4^#[9%-8A%/XA=
-M0,9%00"^`````$B+?"00Z`````"+531)BW482(M\)!#H`````$B)[DR)]^@`
-M````2(M<)!A(BVPD($R+9"0H3(ML)#!,BW0D.$R+?"1`2(/$2,-F9I!F9I!F
-M9I!(@^Q(2(E<)!A(B6PD($R)9"0H3(EL)#!,B70D.$R)?"1`28G\08G7B4PD
-M"$R)PT"(="0/2(M'4$R+,$R)]^@`````2(G%2(7`#X3J````3(GWZ`````!)
-MB<5(A<!U$4B)[DR)]^@`````Z<H```"02(U%6$B)1"00QH68````"L9%):Q!
-M#[=$)#AFB44@2(E=:$R)=2C'A90````(````3(EM>$F+11!(B45(BU0D"(E5
-M-$F-A"3L````2(E%4,9%,"!(QX6@`````````,9%.#S&13D"#[9$)`^(13I$
-MB?C!Z!"(13M,B?H/ML:(13Q$B'T]#[9%-HA%/@^V136(13\/MD0D"(A%0,9%
-M00"^`````$B+?"00Z`````"+531)BW482(M\)!#H`````$B)[DR)]^@`````
-M2(M<)!A(BVPD($R+9"0H3(ML)#!,BW0D.$R+?"1`2(/$2,-F9F:02(/L.$B)
-M7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_$B+1U!,BSA(BY<H`0``
-M#[9"`L'@"`^V4@,!T`^WP$2-:`1!@?T`"```#X_.````3(G_Z`````!(B<5(
-MA<`/A+H```!,B?_H`````$F)QDB%P'402(GN3(G_Z`````#IF@```$B-75A(
-MBW@026/528NT)"@!``#H`````,9%):Q!#[=$)#AFB44@3(E]*$2);32#C90`
-M```228M&$$B)14A,B75X28V$).P```!(B450QD4P($C'A:``````````QD4X
-M'<9%.1#&13H"#[9%-8A%.T2(;3R^`````$B)W^@`````BU4T28MV&$B)W^@`
-M````2(GN3(G_Z`````!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(
-M@\0XPV9F9I!F9F:09F:02(/L*$B)7"082(EL)"!(B?N)U4C'1"00`````(!_
-M2P%T04B-5"000`^V]KD!````Z`````!(BT0D$$B%P'0D@`B`0(3M=`M(BT0D
-M$(!(`R#K"4B+1"00@&`#WTB)W^@`````2(M<)!A(BVPD($B#Q"C#9F9FD&9F
-M9I!F9I!F9I!(@^PX2(E<)`A(B6PD$$R)9"083(EL)"!,B70D*$R)?"0P28G]
-M08GW2(M'4$R+,$R)]^@`````2(G%2(7`#X2I````3(GWZ`````!)B<1(A<!U
-M$$B)[DR)]^@`````Z8D```!(C5U8QD4EK$$/MT4X9HE%($R)=2C'A90````(
-M````3(EE>$F+1"002(E%2,=%-``(``!)C87L````2(E%4,9%,"!(QX6@````
-M`````,9%.!S&13D!1(A].L9%.PC&13P`O@````!(B=_H`````(M5-$F+="08
-M2(G?Z`````!(B>Y,B??H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,
-MBWPD,$B#Q#C#D$%7059!54%455-(@^P82(D\)$B+3D@/MD$"P>`(#[91`XT\
-M$`^WQX/`!`^W5C0YT`^/6@$``$R-:0@/M\=,C70!!$R);"0(0;P`````QT0D
-M%`````!-.?4/@]D```!FD`^V1"04B$0D$T$/MD4"P>`(00^V50-$C3P000^W
-M]TB+?"0(2(/'!.@`````B<$\_W5>00^WQTB+7"0(2(U4`P1(B=-).=8/AL\`
-M``!!B<R0#[9"`L'@"`^V4@.-+!`/M_5(C7L$Z``````\_W4(08#\_W5YZW%!
-M.,1$#T?@#[?%2(U4`P1(B=-).=9V8.O!D(G"1"CB#[;2#[9<)!.)WDB+/"3H
-M`````(G:3(GN2(L\).@`````00^WQTB+5"0(3(UL`@1,B6PD"(-$)!0!33GN
-M#X<I____O@(```!(BSPDZ`````#K24&\``````^V5"033(GN2(L\).@`````
-M00^WQTB+7"0(3(UL`P1,B6PD"(-$)!0!Z>7^__\/ME0D$TR)[DB+/"3H````
-M`.NI9I!(@\086UU!7$%=05Y!7\.005=!5D%505154TB#[`A)B?Y(BTY(#[9!
-M`L'@"`^V40,!T`^WP(/`!`^W5C0YT`^/#`$``$B-40@/MG$!QD0D`P"Y````
-M``^V0@(`1"0##[9"`TB-5`($@\$!0#C.<^>`?"0#``^$O@```$B-:@1!OP``
-M``!!O0````#'1"0$``````^V5?U!`=4/MD7\/`%T!#P7=3M$B>LHTT$XW79Q
-M#[9$)`2#P`%$#[;@9F:09I`/MDW\#[;S1(GB3(GWZ`````"#PP%$..MT1NOD
-M9F9FD$F+1EB`N,$````!=#-$B>LHTT$XW78I#[9$)`2#P`%$#[;@#[9-_`^V
-M\T2)XDR)]^@`````@\,!1#CK=>9F9I!!@\<!@T0D!`%(@\4$1#I\)`,/A5K_
-M__])BT98QH#!`````;X'````3(GWZ`````!(@\0(6UU!7$%=05Y!7\.02(/L
-M*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($F)_$B%_P^$Q````$B+1U!,BS!,
-MB??H`````$B)Q4B%P`^$J0```$R)]^@`````28G%2(7`=1!(B>Y,B??H````
-M`.F)````2(U=6,9%):Q!#[=$)#AFB44@3(EU*,>%E`````@```!,B6UX28M%
-M$$B)14C'130`"```28V$).P```!(B450QD4P($C'A:``````````QD4X',9%
-M.0'&13H"QD4[",9%/`"^`````$B)W^@`````BU4T28MU&$B)W^@`````2(GN
-M3(GWZ`````!(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9I!(
-M@^P82(D<)$B);"0(3(ED)!!(B?-)B?Q(BVYH#[=.(&:!^84`#X>E````#[?!
-M#[:T!V`(``!`@/[_#X20````9H/Y?W<B0`^VUDB+CS@)``!(C0122(T$@DC!
-MX`5(BT0(4`^V0`CK2&:!^8$`=QU`#[;&2(N7B`D``$AIP,@/``!(BT00"`^V
-M0`CK)$`/ML9(BY=@"0``2(T$P$C!X`5(BX00B`````^V0`AF9I!FD#S_=!P/
-MML!!@+P$Y@@``/]T#D"`_O]T"`^V0R0\!G4P2(-[>`!T#$B-<WA,B>?H````
-M`$B)WDR)Y^@`````QT50_____TB)[_]52.MS9F:0A,!U.?:#E`````AT$TB+
-M?3"+4S1(BW-(Z`````!F9I#'15``````2(M5.$B%TG0%BT4@B0)(B>__54CK
-M$\=%4/____](B>__54AF9I!F9I!(@WMX`'0,2(US>$R)Y^@`````2(G>3(GG
-MZ`````!FD$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F:09F:09F:02(/L*$B)
-M7"0(2(EL)!!,B60D&$R);"0@2(GS28G\1`^V;B0/MT8@9CV%`'<C2(N/.`D`
-M``^WP`^VA`=@"```2(T40$B-%)!(B=!(P>`%ZPQ(BX\X"0``N&">`0!(C2P!
-M183M=2!FQX7(``````"`>S@<=1&`>SH"=0M(B=Y(B>_H`````$B#>W@`=`Q(
-MC7-X3(GGZ`````!(B=Y,B>?H`````$&`_09T/4B-G6`!``!)BWPD*$B)WN@`
-M````QX5@`0``@(0>`$C'A7`!````````2(FM>`$``$F+?"0H2(G>Z`````!(
-MBUPD"$B+;"003(MD)!A,BVPD($B#Q"C#D$%7059!54%455-(@^P(28G_08G6
-M2(M'4$B+*$&\`````$R-;@Q!#[:$+&`(```\_W12#[;`2(T40$B-%)!(B=-(
-MP>,%2(G?2`.].`D``$B!Q]0```"Z"````$R)[N@`````A,!T'DB+A3@)``!$
-MB+0##@$``$B+A3@)``!,B;P#(`$``$F#Q`%)@?R`````=91(@\0(6UU!7$%=
-M05Y!7\-!5T%6055!5%532(/L&$B)?"0(2(M.2`^V00+!X`@/ME$#C3P0#[?'
-M@\`$#[=6-#G0#X_F````2(U9"`^WQTB-3`$$2(E,)!!)B=U(.=D/AKH```!!
-MO@````!F9I!F9I!$B?(/M@N$R0^(A0```(G(@^`//`9U?/9#`\!T!O9#!<!U
-M</;!$'0Y@'L$`&9F9I!T84F-;0A!O`````!F9F:0#[93`TB)[DB+?"0(Z```
-M``!(@\4<08/$`40X8P1V-.O?@'L"`'0L28UM!$&\`````$0/MOI$B?I(B>Y(
-MBWPD".@`````2(/%'$&#Q`%$.&,"=^(/MD,!28U<!0))B=U!@\8!2#M<)!`/
-M@E+___^^`0```$B+?"0(Z`````!(@\086UU!7$%=05Y!7\-F9F:005=!5D%5
-M05154TB#["A(B70D"$B)?"00#[9&)(A$)"</MTX@9H'YA0`/A_@#```/M\$/
-MMK0'8`@``+C_````0(#^_W1Z9H/Y?W<G0`^VUDB+1"002(N(.`D``$B-!%)(
-MC02"2,'@!4B+1`A0#[9`".M-9H'Y@0!W(D`/ML9(BTPD$$B+D8@)``!(:<#(
-M#P``2(M$$`@/MD`(ZR1`#[;&2(M,)!!(BY%@"0``2(T$P$C!X`5(BX00B```
-M``^V0`A(F$B+5"001`^VO`+F"```2XT$OTF-!(=(C83"P`$``$B)1"082(N*
-M.`D``$`/ML9(C11`2(T4D$B)T$C!X`5(C2P!@'PD)P`/A;,"``!FQX7(````
-M``!(BTPD"(!Y.!P/A9L"```/MD$Z/`)T6CP"=Q$\`0^%AP(``&9F9I!F9I#K
-M'CP'="\\"@^%<@(``$B+="0(2(GOZ`````#I8`(``$B+="0(2(GOZ`````!F
-M9I#I2P(``$B+="0(2(GOZ`````#I.0(``$B+="0(2(GOZ`````!(C9U@`0``
-M2(M%4$B+`$B+>"A(B=[H`````,>%8`$``("$'@!(QX5P`0```````$B)K7@!
-M``!(BT502(L`2(MX*$B)WN@`````QD5*_TN-!+])C02'2(M4)!"`O,+.`0``
-M``^$DP$``$&\`````$N-!+])C02'2,'@`TR-M`(@`@``2(T<$$R-J\`!``!,
-MB??H`````$B)Q4B+@R@"``!(B:LH`@``3(EU`$B)10A(B2B`?4K_#X26````
-M@'U)``^%EP```$B)[H"]Z0`````/A%<!```/ME5(2(G0@^`&2(/X!G4G]L(!
-M="(/MI6!````2(MU6$B)Z4B+?"08Z`````#I)0$``&9FD&:02(/X!'4;]L(!
-M9F9FD&9FD'0/2(M\)!#H`````.G_````2(/X!@^%]0```/;"`6:0#X7J````
-M2(M\)!#H`````.G;````QH7I`````&9F9I!!@\0!00^V10Y$..`/AQ____]!
-M.,0/A80```"$P`^$?````$&\`````$N-!+])C02'2,'@`TB+3"003(VL`2`"
-M``!(C1P(3(VSP`$``&9FD$R)[^@`````2(G%2(N#*`(``$B)JR@"``!,B6T`
-M2(E%"$B)*(!]2O]T&P^V14D\(G0$/`UU#[X*````2(GOZ`````#K.T&#Q`%%
-M.&8.=[%+C02_28T$ATB+5"00QH3"R0$``/](BW0D&$B)U^@`````@'PD)P`/
-MA:0```!F9F:02(M,)`A(@WEX`'012(G.2(/&>$B+?"00Z`````!(BW0D"$B+
-M?"00Z`````"`?"0G`'1M#[>%R````(/``6:)A<@```!F@_@*=@YFQX7(````
-M``#IQ?W__[X*````2(GOZ`````#K.4B+1"001`^VN.4)``!+C02_28T$ATB+
-M5"002(V$PL`!``!(B40D&$B+BC@)``"X8)X!`.F?_/__D$B#Q"A;74%<05U!
-M7D%?PY!(A?]T2TB%]G1&2(72=$%(A<ET/&9!@?B%`'<T00^WP("\!V`(``#_
-M=";&0CCAQD(Y`<9".A-F1(E"($B)<BA(B8J@````N`$```##9F9FD+@`````
-MPV9F9I!F9I!F9I!(BT<(BT`$B04`````B<*!R@``#``E___S_T"$]@]%PDB+
-M5PB)`DB+5PB)0@Q(BU<(B4(02(M7"(E"%$B+5PB)0AA(BU<(B4($PY"0D)"0
-MD$R+5"0@3(M<)#")^&:!_R(G=U]F@?\@)P^#E````&:!_T`A#X2)````9H'_
-M0"%FD'<@9H'_("%T>6:!_R(A9I!T<&:!_U`'=6]F9F:09F:0ZV!F@?]$(719
-M9H'_1"%FD')69BT0)V:#^`%W3&9F9I#K0&:!_X(G=#EF@?^")V:0=Q)F@?\D
-M)W0I9H'_@"=FD'4FZQYF@?^`D69F9I!F9I!T$&:!_X"4=`EF@?^`<F:0=0;&
-M!A3&`@+&`00/MA9(BT0D&(@09D''`H``9D''`P``0<8!($B+1"0(9L<```$/
-MMA9(BT0D$(@0#[8&9D$#`F9!`P-(BU0D*&:)`F9!B0!!#[<22(M$)#AFB1!!
-M#[<2@\(+2(M$)$!FB1##9F9FD%53B?,/MW=H9H7V#X0$`0``3(N7L`D``$&[
-M`````+W_____28L"2(7`#X34````#[=((+C_````08GH9H'YA0`/AXX````/
-MM\%$#[:,!V`(``!%B<A!@/G_='5F@_E_=R-!#[;12(N/.`D``$B-!%)(C02"
-M2,'@!4B+1`A01`^V0`CK3&:!^8$`=QY!#[;!2(N7B`D``$AIP,@/``!(BT00
-M"$0/MD`(ZR=!#[;!2(N78`D``$B-!,!(P>`%2(N$$(@```!$#[9`"&9F9I!F
-M9I!!#[;!2(N/.`D``$$XV'4C#[?`2(T40$B-%)!(P>(%#[9$"DBH`70+J`1T
-M![@!````ZQ=!@\,!28/""&9!.?,/A0[___^X`````%M=PV9FD$B+1U!,BQ!-
-MBYK8$```10^W2FBY`````$&X`````.M##[?Q28N"L`D``$B+%/!(A=)T+8M"
-M."7___\`/>$!$`!T'@^W1SAF.T(@=11(B?!(P>`&9D8Y1!@(=`YF9I!FD(/!
-M`69$.<ERMV9$.<ET$T&#P`%F08/X'W<(N0````"0Z^%!#[?`PV9FD&9FD&9F
-MD$B+1U!(A<!T&L8`<$B+1U!`B'`"2(M'4,9`!P!(BT=0B%`,\\-F9F:09F9F
-MD&9FD//#9F9FD&9F9I!F9I!F9I!!B?%,B<J!XO\!``!(BX>P"0``3(L$T$V%
-MP'0K#[:W[@```$$/MD`EB?'3X`^W^$$/M]&X__\``-/@(<(YU[@`````3`]%
-MP$R)P,-F9I!FD+@`````Q@0X`$B#P`%(/2`!``!U\,9'1/_&1U#_2(U'*$B)
-M1RA(B4<PPV9FD&9FD+@`````Q@0X`$B#P`%(/:`!``!U\,:'@````/_&1W+_
-MQH>"````'TB-1R!(B4<@2(E'*,-F9F:09F9FD&9F9I!(BP9(BY<P`0``2(F'
-M,`$``$B!QR@!``!(B3A(B5`(2(D"2,<&`````,-F9I!F9I!(BY<@`0``2(FW
-M(`$``$B-AQ@!``!(B09(B58(2(DR2(-^<`!T"4B#QG#H`````//#9F9FD&9F
-M9I!F9F:09F:02(L&2(N74`$``$B)AU`!``!(@<=(`0``2(DX2(E0"$B)`DC'
-M!@````##9F:09F:02(L&2(N70`$``$B)AT`!``!(@<<X`0``2(DX2(E0"$B)
-M`DC'!@````##9F:09F:02(N'<`$``$B)MW`!``!(@<=H`0``2(D^2(E&"$B)
-M,,-(BP9(BY>``0``2(F'@`$``$B!QW@!``!(B3A(B5`(2(D"2,<&`````,-F
-M9I!F9I!(BP9(BY=@`0``2(F'8`$``$B!QU@!``!(B3A(B5`(2(D"2,<&````
-M`,-F9I!F9I!`@/\7=Q%`#[;'_R3%`````+@T````P[@$````9F9FD,.X/```
-M`,.X%````&9F9I##N$````##N!P```!F9F:0P[@8````P[@H````9F9FD,.X
-M(````,.X3````&9F9I##9F9FD&9F9I!F9F:09F:0#[962$B)T(/@!DB#^`9U
-M$/;"`0^$VP```&9F9I!F9I"`?G+_#X7*````2(L'1(N(&`$``$2)#0````"Y
-M`````+@!````08G`0=/@187!=3.(3G)(BQ=$B<!$"<B)@A@!``!(BP>+@%@!
-M``")!0````!$B<(APG1X2(L'B9!8`0``ZVV#P0&#^2!UM4B+!T2+B!P!``!$
-MB0T`````L0!FD(G*N`$```!!B<!!T^!%A<%U-HU"((A&<DB+%T2)P$0)R(F"
-M'`$``$B+!XN`8`$``(D%`````$2)PB'"=!-(BP>)D&`!``#K"(/!`8/Y('6P
-M@$=$`?/#9F9FD&9FD&9FD(!^4/\/A<4```!(BP=$BX@8`0``1(D-`````+D`
-M````N`$```!!B<!!T^!%A<%U,XA.4$B+%T2)P$0)R(F"&`$``$B+!XN`6`$`
-M`(D%`````$2)PB'"='-(BP>)D%@!``#K:(/!`8/Y('6U2(L'1(N('`$``$2)
-M#0````"Q`&:0N`$```!!B<!!T^!%A<%U,XA.4$B+%T2)P$0)R(F"'`$``$B+
-M!XN`8`$``(D%`````$2)PB'"=!-(BP>)D&`!``#K"(/!`8/Y('6U@$=$`?/#
-M9F9FD&9F9I!F9F:09F:02(MW0$B%]G0YN0````!FD$B+1,Y82(7`=`@XD($`
-M``!T#$B#P0%(@_D%=!;KXF:!?D"%`'<,2(7`9F9FD&9FD'4%N`````#SPV9F
-M9I!F9I!!54%455-(B?U)B<W!Y@@/MM(!UH!_,``/A-4```!(@W]0``^$R@``
-M`(N'E````*@)00^4P+D`````2,?'`````$&)S`^W%,^)\"'09CG"#X60````
-M#[8$S0`````\`W0$/`=U"T0X!,T`````=7:0QD4D($UCY$C'PP````!"#[94
-MXP8/MO!(B>_H`````$B+55!"#[9$XP>(0@U-A>UT-$F+30!(B<I(P>H@2(M%
-M4(E0`TB+15"`"(#VA98````$=!*%TG0.2(M%4(E("$B+15"`('](BU50#[9%
-M,(/H!XA"!^L.2(/!`4B#^1`/A4[___];74%<05W#9F:09F:02(/L"$B-EU@!
-M``"X`````$@YEU@!``!T$$B)U^@`````2,=`(`````!(@\0(PV:02(/L"$B-
-MEW@!``"X`````$@YEW@!``!T"$B)U^@`````2(/$",-F9F:09F:09F:02(/L
-M"$B-EV@!``"X`````$@YEV@!``!T*$B)U^@`````2(G!N@````!F9F:09F:0
-MQ@0*`$B#P@%(@?J@````=>](@\0(PV9F9I!F9I!F9I!(@^P(2(V7.`$``+@`
-M````2#F7.`$``'0(2(G7Z`````!(@\0(PV9F9I!F9I!F9I!(@^P(2(V7*`$`
-M`+@`````2#F7*`$``'0,2(G7Z`````#&0!``2(/$",-F9I!F9I!!5T%6055!
-M5%532(/L"$F)_T&)]<=$)`0`````0;X`````0P^VA#[@"```//\/A!T!```/
-MMM!!C8:`````9CV!`'=]#[?"2&G`R`\``$B)PTD#GX@)``"`>U@`=%.]````
-M`$R-8TA,B>?H`````$B-2/!(BU-02(E#4$R)81!(B5$82(D"BT%()0#__P`]
-M``#_`'43]D%+!'0-2(M!0$B%P'0$1(AH`8/%`4`X:UAWMD2(J\(```!!@\4!
-MZ9`````/M\)(C03`2,'@!4B)QDD#MV`)``"`?CL`=#VY``````^VP4B+5,98
-M2(72=".+0D@E`/__`#T``/\`=13V0DL$=`Y(BT)`2(7`=`5$B&@!D(/!`3A.
-M.W?(1(BN%`$``("^%0$```-U'X-$)`0!BT0D!(/``X/X!G8708/%`<=$)`0`
-M````ZPE!@\4!9F:09I!)@\8!28/^!@^%Q/[__TF+A_`(``!,.?AU#TB-N(@4
-M``!$B>[HA_[__TB#Q`A;74%<05U!7D%?PV9F9I!F9F:02(/L"`^V1@@/MK0'
-MY@@``,:$!^8(``#_#[?V2(''@!```.@`````2(/$",-F9F:02(M6<$B%TG08
-M2(M"&$B)1CA(BT(@2(E&0$B+0BA(B49(\\-F9F:09F:09F:09F:02(M6<$B%
-MTG0<2(M&.$B)0AA(BT9`2(E"($B+1DA(B4(HQD(0`?/#9F:09F:09F:00515
-M4TF)_$B+'V:#>V@`#X3,````O0````!F9I!F9I`/M]5(BX.P"0``2(L\T$B%
-M_P^$G0````^W3R!F@?F%`'=^#[?!#[:$`V`(```\_W1O9H/Y?W<A#[;02(N+
-M.`D``$B-!%)(C02"2,'@!4B+1`A0#[90".M-9H'Y@0!W'`^VP$B+DX@)``!(
-M:<#(#P``2(M$$`@/ME`(ZRH/ML!(BY-@"0``2(T$P$C!X`5(BX00B`````^V
-M4`CK"F9FD&:0NO\```!!#[9$)`@YPG4%Z`````"#Q0%F.6MH#X<_____6UU!
-M7,-F9F:09F:09F:02(/L&$B)7"0(2(EL)!!(B?M(B?4/MD90//]T$P^V\$B+
-M/^@`````QD50_X!K1`%(BUPD"$B+;"002(/$&,-FD$B#[!A(B5PD"$B);"00
-M2(G[2(GU#[9&<CS_=!,/MO!(BS_H`````,9%<O^`:T0!2(M<)`A(BVPD$$B#
-MQ!C#9I!54TB#[`A(B?U(B?-(.7XH#X3;````@'XD``^%IP````^V1C@\%70(
-M/%4/A9<```!(BT-P2(7`#X2*````2(G!@'@0`0^%?0```&:!>!CA`75U2(NU
-M.`D```^W0R"Z8)X!`&8]A0!W%P^WP`^VA`5@"```2(T40$B-%)!(P>(%2(T$
-M%@^V21J`^0=T'8#Y!W<'@/D&=3'K&H#Y#&9FD&:0=""`^0UU(.L09H-@:OUF
-MD.L59H-(:@+K#F:#8&KW9I#K!6:#2&H(2(-[>`!T(X%[-``(``!W#DB-<WA(
-MB>_H`````.L,2(US>$B)[^@`````9H%[..$!#X4G`0``#[=#(&8]A0`/AXL`
-M```/M\`/MH0%8`@``#S_#X1X````2(N-.`D``(![)`!U:P^VP$B-%$!(C120
-M2,'B!4B-!!$/ME,Z@/H'=!V`^@=W!X#Z!G4VZQ^`^@QT*H#Z#69FD&:0=27K
-M%6:#8&K]9F9FD&9FD.L59H-(:@+K#F:#8&KW9I#K!6:#2&H(9H%[..$!9F:0
-M#X6.````@'LZ"P^%A`````^W<R`/MD5&C7C_B?+K&Y"#P@%F@?J%`'<0#[?*
-M2&/!@+P%8`@``/]U"0^WPCGX?-_K36:!^?\`=2)F9I!F9I#K/H/&`6:!_H4`
-M=Q`/M]9(8\*`O`5@"```_W4,#[?&.<=_W[K_````9HE3(,9#)(!(B=Y(B>_H
-M`````.DB`0``QD,D`$@Y:RAT)DB+0W!(A<!T'8!X$`%U"TB)WDB)[^@`````
-M2(US<$B)[^@`````2(.[@`````!T#TB-LX````!(B>_H`````$B+>RA(B=[_
-MDZ`````/MU,X9H'ZX0%U5P^V0SJ#Z!$\`7=,#[=#(&8]A0`/AZ@````/M\`/
-MMH0%8`@``#S_#X25````#[;`2(T$P$C!X`5(B<9(`[5@"0``@'Y%`'5Z@'Y0
-M_W1T2(GOZ`````#K:@^W0R!F/84`=V`/M\`/MHP%8`@``$B+M3@)``"+0S@E
-M____`#WA`1``=#^!^?\```!T-V:!^N$!=0X/MD,Z@^@1/`%V)69FD(G(2(T4
-M0$B-%)!(P>(%2`'6@+Z#`````'4(2(GOZ`````!(@\0(6UW#9F9FD&9FD%53
-M2(/L"$B)_4B)\P^W3B!F@?F%``^'I@````^WP0^VM`=@"```0(#^_P^$D0``
-M`&:#^7]W(D`/MM9(BX\X"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZTAF@?F!
-M`'<=0`^VQDB+EX@)``!(:<#(#P``2(M$$`@/MD`(ZR1`#[;&2(N78`D``$B-
-M!,!(P>`%2(N$$(@````/MD`(9F:09I!F/?\`=!L/M\`/MKP%Y@@``$"`__]T
-M"D`/ML9F/?\`=1!(B=Y(B>_H`````.F!````#[93.P^V0SP/MDL]@/D!=`6`
-M^0AU8$B+2VC!X`@/MM(!T"7_`0``2(N5L`D``$@Y#,)U0@^W23*)RF;!Z@6!
-MXO\'``"#X1^X`0```$C3X/?0(425;$B+0V@/MW`R0`^VQTB-/(!(C3RX2(V\
-M_<`!``#H`````$B)WDB)[^@`````2(/$"%M=PV9F9I!F9I!(@^P82(E<)`A(
-MB6PD$$B)^TB-OQ@!``"]`````$@YNQ@!``!T'.@`````2(G%2(G'Z`````!(
-MB=_H`````$B)17!(B>A(BUPD"$B+;"002(/$&,-F9F:09F9FD&9F9I!(@^P8
-M2(D<)$B);"0(3(ED)!!(B?U(BT=03(L@3(GGZ`````!(B<-(A<!T<$R)Y^@`
-M````2(G"2(7`=13&A>D````!2(G>3(GGZ`````#K3,9#.``/MT4X9HE#(,:#
-MF`````],B6,HQT,T`````$C'0T@`````2(M"$$B)0U#&0S`D2(E3>$C'@Z``
-M````````2(G>3(GGZ`````!(BQPD2(ML)`A,BV0D$$B#Q!C#D$B#[!A(B1PD
-M2(EL)`A,B60D$$B)_4&)]$B+1U!(BQA(B=_H`````$B)PDB%P'1$QD`X&\9`
-M.0%$B&`\#[=%.&:)0B#&@I@````/2(E:*,="-`````!(QT)(`````$C'@J``
-M````````2(G62(G?Z`````!(BQPD2(ML)`A,BV0D$$B#Q!C#9F9FD&9FD&9F
-MD$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!)B?])B?5,BS=,
-MB??H`````$B)Q4B%P`^$C@```$R)]^@`````28G$2(7`=1%(B>Y,B??H````
-M`.MQ9F9FD$B-75C&13CAQD4Y`<9%.@Y!#[=%.&:)12!F08-E:/=)BP=(B44H
-MQT4T``@``$F+1"002(E%2$R)97A(QX6@`````````+X`````2(G?Z`````"+
-M531)BW0D&$B)W^@`````2(GN3(GWZ`````!(BUPD"$B+;"003(MD)!A,BVPD
-M($R+="0H3(M\)#!(@\0XPTB#["A(B5PD"$B);"003(ED)!A,B6PD($F)](G5
-M2(L?2(G?Z`````!(B<)(A<!T7\9`..'&0#D!0(AH.L9`.P]!#[=$)#AFB4(@
-M2(E:*,="-`````!(QT)(`````$C'@J``````````2(G62(G?Z`````!`@/T!
-M=0R_!0```.@`````ZPJ_4,,``.@`````2(M<)`A(BVPD$$R+9"083(ML)"!(
-M@\0HPV9F9I!F9F:055-(@^P(2(G]2(GS#[=.(&:!^84`#X>G````#[?!#[:T
-M!V`(``!`@/[_#X22````9H/Y?W<B0`^VUDB+CS@)``!(C0122(T$@DC!X`5(
-MBT0(4`^V0`CK2&:!^8$`=QU`#[;&2(N7B`D``$AIP,@/``!(BT00"`^V0`CK
-M)$`/ML9(BY=@"0``2(T$P$C!X`5(BX00B`````^V0`AF9I!FD#S_=!X/ML`/
-MMHP%Y@@``(#Y_W0.0(#^_W0(#[9#)#P&=3Y(@WMX`'0E@7LT``@``'<02(US
-M>$B)[^@`````9I#K#$B-<WA(B>_H`````$B)WDB)[^@`````ZWQF9I!FD$B+
-ME3@)``"$P'0U0`^VQDB--$!(C32P2,'F!4B--#(/ML%(C3R`2(T\N$B-O/W`
-M`0``N@$```#H`````&9F9I!(@WMX`'0E@7LT``@``'<02(US>$B)[^@`````
-MZPYFD$B-<WA(B>_H`````$B)WDB)[^@`````2(/$"%M=PV:02(/L*$B)'"1(
-MB6PD"$R)9"003(EL)!A,B70D($B)^TB)]0^W3B!F@?F%``^''P$```^WP0^V
-MM`=@"```0(#^_P^$"@$``&:#^7]W)$`/MM9(BX\X"0``2(T$4DB-!()(P>`%
-M2(M$"%`/MD`(ZT5FD&:!^8$`=QU`#[;&2(N7B`D``$AIP,@/``!(BT00"`^V
-M0`CK'T`/ML9(BY=@"0``2(T$P$C!X`5(BX00B`````^V0`@\_P^$E0```$0/
-MMN8/ML!$#[:L`^8(``!!@/W_=']F08'\_P!T=X!])`9T<4R+LS@)``"`?3H!
-M=4F_"@```.@`````2(GN2(G?Z`````!!#[?$2(TT0$B--+!(P>8%28TT-D$/
-MML5(C3R`2(T\N$B-O/O``0``N@(```#H`````.L;O_0!``#H`````$B)[DB)
-MW^@`````9F:09F:02(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9I!(
-M@^P82(D<)$B);"0(3(ED)!!)B?Q(BT=02(LH2(GOZ`````!(B<-(A<!U"T'&
-MA"3I`````>M?QD`X%<9`):M!#[=$)#AFB4,@2(EK*$&X`0```+D!````2(G:
-M3(GF2(GOZ`````"$P'462(G>2(GOZ`````!!QH0DZ0````'K%DC'@Z``````
-M````2(G>2(GOZ`````!(BQPD2(ML)`A,BV0D$$B#Q!C#9F9FD&9FD$B#["A(
-MB5PD"$B);"003(ED)!A,B6PD($B)^TB+1U!,BRA,B>_H`````$B)Q4B%P'4.
-MQH/I`````>FV````9I!,B>_H`````$F)Q$B%P'47QH/I`````4B)[DR)[^@`
-M````Z8T```#&13@:QD4Y",9%.@C&13L`QD4\_\9%/0#&126K#[=#.&:)12!,
-MB6THQT4T_P```,>%E`````@```!)BT0D$$B)14A(!?\```!(B450QD4P)$R)
-M97A(QX6@`````````$B-75B^`````$B)W^@`````28MT)!BZ_P```$B)W^@`
-M````2(GN3(GOZ`````!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F:02(/L
-M.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_$&)]DB+1U!,BRA,
-MB>_H`````$B)PTB%P'410<:$).D````!Z;H```!F9I!,B>_H`````$B)Q4B%
-MP'4@0<:$).D````!2(G>3(GOZ`````#IC@```&9F9I!F9I!,C7M8QD,X$D6$
-M]G03QD,Y`<9#.H#&0SQ`ZPEF9I!FD,9#/"3&0R6K00^W1"0X9HE#($R):RC'
-M0S1@````QX.4````"````$B+11!(B4-(2(EK>$C'@Z``````````O@````!,
-MB?_H`````$B+=1BZ8````$R)_^@`````2(G>3(GOZ`````!(BUPD"$B+;"00
-M3(MD)!A,BVPD($R+="0H3(M\)#!(@\0XPV9FD&9FD$B#["A(B1PD2(EL)`A,
-MB60D$$R);"083(ET)"!)B?Q(BT=03(LP3(GWZ`````!(B<5(A<!U#D'&A"3I
-M`````>FR````3(GWZ`````!)B<5(A<!U'$'&A"3I`````4B)[DR)]^@`````
-MZ8D```!F9I!(C5U8QD4XGL9%.1#&144@QD4EJT$/MT0D.&:)12!,B74HQT4T
-M(````,>%E`````@```!)BT402(E%2$R);7A(@\`@2(E%4,9%,"1(QX6@````
-M`````,:%F`````^^`````$B)W^@`````28MU&+H@````2(G?Z`````!(B>Y,
-MB??H`````$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9FD&9FD&9F
-MD&9FD$B#["A(B1PD2(EL)`A,B60D$$R);"083(ET)"!)B?Q(BT=03(LP3(GW
-MZ`````!(B<5(A<!U#D'&A"3I`````>FC````3(GWZ`````!)B<5(A<!U'$'&
-MA"3I`````4B)[DR)]^@`````ZWUF9I!F9I!(C5U8QD4X)<9%):M!#[=$)#AF
-MB44@3(EU*,=%-`@```#'A90````(````28M%$$B)14A(@\`(2(E%4,9%,"1,
-MB6UX2,>%H`````````"^`````$B)W^@`````28MU&+H(````2(G?Z`````!(
-MB>Y,B??H`````$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9FD&9F
-M9I!F9F:02(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_TF)
-M](E4)`1(BR],B[4X"0``#[=&($0/MJP%8`@``$B)[^@`````2(G#00^W="0R
-MB?!FP>@%#[?`BT2%;(GQ@^$?2-/XJ`$/A<(```!(A=L/A+D```!!#[;%2(T4
-M0$B-%)!(P>(%28T4%D$/MD0D)0^VC>X```#3X`GPQD,XX<9#.0'&0SH/B$,[
-M9L'H"(A#/`^V1"0$B$,]2(N"W````$B)0SY,B6-HQD,EJ@^W0CAFB4,@28L'
-M2(E#*,=#-`````!(QT-(`````$C'@Z``````````2(U[6+X`````Z`````!(
-MB=Y(B>_H`````$$/MTPD,HG*9L'J!8'B_P<``(/A'[@!````2-/@"425;$B+
-M7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD&9FD&9FD$%7
-M059!54%455-(@^P(28G^28G508GW2(L?9H-[:``/A`X"``"]`````$&\____
-M_P^WU4B+@[`)``!(BS302(7V#X3?`0``1(M&.$&!X/___P!!@?CA`1``#X6A
-M````387M#X6^`0``#[=.(&:!^84`=WD/M\$/MH0#8`@``#S_=&IF@_E_=R$/
-MMM!(BXLX"0``2(T$4DB-!()(P>`%2(M$"%`/MD@(ZT9F@?F!`'<<#[;`2(N3
-MB`D``$AIP,@/``!(BT00"`^V2`CK(P^VP$B+DV`)``!(C03`2,'@!4B+A!"(
-M````#[9(".L#1(GAN@````#IOP```&9F9I!F9I`/MTX@9H'YA0`/AZ$````/
-MM\$/MKP#8`@``$"`__\/A(P```!F@_E_=R)`#[;72(N+.`D``$B-!%)(C02"
-M2,'@!4B+1`A0#[9(".M$9H'Y@0!W'4`/ML=(BY.("0``2&G`R`\``$B+1!`(
-M#[9(".L@0`^VQTB+DV`)``!(C03`2,'@!4B+A!"(````#[9(")!`#[;'2(T4
-M0$B-%)!(P>(%2`.3.`D``.L/9F9FD&9FD$2)X;H`````03A."'5H387M=`M!
-M#[=%.&8[1B!U6$&`_P9T0T&!^.$!$`!T.@^V2DA(B<B#X`9(@_@&=2KVP0%U
-M)8"ZZ`````!U'$&!^.$!#P!T(D2(?B2Z`0```$R)]^@`````ZP]$B'XD#[?U
-M3(GWZ`````"#Q0%F.6MH#X?]_?__08#_@0^$5P$``$B+@_@```!(C:OX````
-M2#G%#X1``0``N@````!F9F:09F:0@\(!2(L`2#G%=?5FA=(/A"`!``!$C6+_
-M2(GOZ`````!(B<9-A>UT*$$/MT4X9CM&('0=2(N#``$``$B)LP`!``!(B2Y(
-MB48(2(DPZ<@````/MTX@9H'YA0!W>0^WP0^VA`-@"```//]T:F:#^7]W(0^V
-MT$B+BS@)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK2&:!^8$`=QP/ML!(BY.(
-M"0``2&G`R`\``$B+1!`(#[9`".LE#[;`2(N38`D``$B-!,!(P>`%2(N$$(@`
-M```/MD`(ZP6X_____T$Z1@AU(8M&."7___\`/>$!#P!T$D2(?B1(B=_H````
-M`.L<9F9FD$B+@P`!``!(B;,``0``2(DN2(E&"$B),$&-1"3_9D6%Y'012#NK
-M^````'0(08G$Z>3^__](@\0(6UU!7$%=05Y!7\-F9F:09F:09F:09F:02(/L
-M.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_$F)]DF)S4&)UTB+
-M+TB)[^@`````2(G#2(7`=0]!QH7I`````>F+````9I!(B>_H`````$B)PDB%
-MP'452(G>2(GOZ`````!!QH7I`````>MDQD,XX<9#.0'&0SH01(A[)4$/MD9;
-M9HE#($F+!"1(B4,HQT,TD````$B-0A!(B4-(2(E3>,9``1+&0A!`1(AX"4C'
-M@Z``````````2(U[6+X`````Z`````!(B=Y(B>_H`````$B+7"0(2(ML)!!,
-MBV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD$B#[#A(B5PD"$B);"003(ED
-M)!A,B6PD($R)="0H3(E\)#!)B?Q)B?5!B=9!B<](BR](B>_H`````$B)PTB%
-MP`^$@@```$B)[^@`````2(G"2(7`='+&0SCAQD,Y`<9#.A!$B',E00^V15MF
-MB4,@28L$)$B)0RC'0S20````2(U"$$B)0TA(B5-XQD`!D<9"$$!$B'`)1(AX
-M"DC'@Z``````````2(U[6+X`````Z`````!(B=Y(B>_H`````+^@A@$`Z```
-M``!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(@\0XPV9FD&9FD$B#
-M["A(B1PD2(EL)`A,B60D$$R);"083(ET)"!)B?Q)B?5!B=9(BR](B>_H````
-M`$B)PTB%P'1T2(GOZ`````!(B<)(A<!T9,9#..'&0SD!QD,Z$,9#);M!#[9%
-M6V:)0R!)BP0D2(E#*,=#-)````!(C4(02(E#2$B)4WC&0`$0QD(00$2(<`E(
-MQX.@`````````$B->UB^`````.@`````2(G>2(GOZ`````!(BQPD2(ML)`A,
-MBV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"08
-M3(EL)"!)B?Q)B?5(BR](B>_H`````$B)PTB%P'1P2(GOZ`````!(B<)(A<!T
-M8,9#..'&0SD!QD,Z$,9#);M!#[9%6V:)0R!)BP0D2(E#*,=#-)````!(C4(0
-M2(E#2$B)4WC&0`$`QD(00$C'@Z``````````2(U[6+X`````Z`````!(B=Y(
-MB>_H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9I!F9I!54TB#[`A(
-MB?U(C9^`$```2(G?Z`````"$P`^%X````$B)W^@`````B<&X`````(G&@+PH
-MY@@``/]U"CA%3',2B$5,ZPV#Q@%(@\`!2(/X!'7=0(#^!`^$I````$`/ML:(
-MC`7F"```#[?Y2(T$OTB-!(=(C93%P`$``+@`````D,8$$`!(@\`!2#VH````
-M=?`/M\%(C12`2(T4D$C!X@-(C8P5\`$``$B-!"I(B8CP`0``2(F(^`$``$B-
-MC!4(`@``2(F("`(``$B)B!`"``!(C905(`(``$B)D"`"``!(B9`H`@``0(BP
-MR`$``$B-!+](C02'2(V$Q<`!``#K!V:0N`````!(@\0(6UW#9F9FD$B#[!A(
-MB1PD2(EL)`A,B60D$$B)_4B-G]@/``!(B=_H`````(3`#X4Y`0``2(G?Z```
-M``")PK@`````9F:09I")PX"\*&`(``#_=14/ML!F.87L````<QAFB87L````
-MZP^#PP%(@\`!2#V`````=="`^X`/A.P````/ML.(E`5@"```#[?"2(T40$B-
-M%)!)B=1)P>0%3(GG2`.].`D``.@`````2(N5.`D```^VPV9!B404.$B+A3@)
-M``!!QD0$2@!(BX4X"0``0<9$!&W_2(N%.`D``$'&1`1L_TB+A3@)``!!QD0$
-M;O](BX4X"0``0<9$!'#_2(N%.`D``$'&1`1O_TB+A3@)``!!QD0$<?](BX4X
-M"0``0<:$!.H`````2(N%.`D``$'&A`0/`0``_TB)[^@`````2(N5.`D``$F)
-MA!0H`0``@'U1`74-2(N%.`D``$&`3`1,`4R)X$@#A3@)``#K!;@`````2(L<
-M)$B+;"0(3(MD)!!(@\08PV9FD%-(B?OH1^'__TB+N_`(``#H`````%O#9F:0
-M9F:09F:02(/L&$B)'"1(B6PD"$R)9"002(G]2(V?$!```$B)W^@`````A,`/
-MA>8```!(B=_H`````(G"2(GHNX+___]FD("XX@@``/]U%SB=\````',AB)WP
-M````ZQEF9F:09F:0@\,!2(/``8#[A@^$H@```.O.@/N&#X27````#[;#B)0%
-M8`@```^WPDB-!,!)B<1)P>0%3(GG2`.]8`D``.@`````2(N58`D```^VPV9!
-MB4040(!]40%U#TB+A6`)``!F0<=$!$S__TB+A6`)``!!QD0$0@!(BX5@"0``
-M9D''1`1.``!(BX5@"0``9D''A`0``0````!(B[WP"```O@````#H`````$R)
-MX$@#A6`)``#K!;@`````2(L<)$B+;"0(3(MD)!!(@\08PV9FD&9FD%532(/L
-M"$B)_0^W1D`/MIP'8`@``,:$!V`(``#_#[?S2(V_$!```.@`````#[?;2(T<
-MVTC!XP5(B=Y(`[5@"0``@'Y0_W0(2(GOZ`````!(B[WP"```O@````#H````
-M`$B#Q`A;7<-F9I!F9I!F9I!32(G[#[9&6P^VM`=@"```QH0'8`@``/\/M_9(
-MC;]($```Z`````!(B[OP"```O@````#H`````%O#9F:09F:04TB)\X!^1/]T
-M%$B-MI````!(BW\HZ`````#&0T3_6\-32(GS@+Z`````_W072(VV,`$``$B+
-M?RCH`````,:#@````/];PV9F9I!F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"08
-M3(EL)"!(B?M)B?0/MT8X1`^VK`=@"```00^WQ4B-%$!(C1202(G52,'E!4B)
-M[D@#MS@)``!(@<8H`0``Z`````!!#[=4)#A(BX338`0``$B%P'092(.X@```
-M``!U#TC'A--@!````````&9FD$$/MT0D.,:$`V`(``#_00^W]4B-N]@/``#H
-M`````$B)[D@#LS@)``"`?G+_=`A(B=_H`````$R)YDB)W^@`````2(N#.`D`
-M`,9$!4H`2(N#.`D``,9$!4L!2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9F
-M9I!F9F:09F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@28G]2(GS9H%^
-M..$!#X7.````#[9&.H/H$3P!#X>_````#[=&(&8]A0`/AXH!```/M\`/MH0'
-M8`@``$B+EV`)```\_P^$<`$```^VP$B-!,!(P>`%2(TL`H!M10%,C64H3(GG
-MZ`````!(B<)(.=AU2DB)[DR)[^@`````3#ME*`^$-`$``,>%D``````2>@!(
-MQX6@`````````$B)K:@```!(C;60````28M]*.@`````QD5$`.G_````2(M%
-M*$B)4`A(B0),B6((2(E5*$B+$TB+0PA(B4((2(D0Z=D````/MT,@9CV%``^'
-MRP````^WP$$/MI0%8`@``$F+C3@)``"+0S@E____`#WA`1``#X2E````@?K_
-M````#X29````B=!(C11`2(T4D$C!X@5(C2P1@*V#`````4R-92!,B>?H````
-M`$B)PD@YV'5+2(GN3(GOZ`````!,.V4@=%O'A3`!````$GH`2,>%0`$`````
-M``!(B:U(`0``2(VU,`$``$F+?2CH`````,:%@`````#K)F9FD&:02(M%($B)
-M4`A(B0),B6((2(E5($B+$TB+0PA(B4((2(D02(M<)`A(BVPD$$R+9"083(ML
-M)"!(@\0HPV9FD&9FD%532(/L"$B)^TB)]0^W?C*)^F;!Z@4/M_>)\8/A'[@!
-M````2-/@B<'WT8'B_P<``"%,DVQF@?__#W1$#[?'2,'@`T@#@[`)``!(@S@`
-M=#!(QP``````(8R3N`D``$B-NZ`/``#H`````$B)[DB)W^@`````2(GN2(G?
-MZ`````!(@\0(6UW#9F9FD&9FD&9FD%532(/L"$B)]6:!?CCA`0^%K`````^V
-M1CJ#Z!$\`0^'G0````^W1B"Z_P```&8]A0!W"P^WP`^VE`=@"```B=!(C03`
-M2,'@!4B)PT@#GV`)``"`>T3_=4D/MI68````C002A-*Z"`````]$P@^VP&G`
-M0$(/`(F#D````$C'@Z``````````2(F;J````$B-LY````!(BW\HZ`````#&
-M0T0`2(M3,$B):S!(C4,H2(E%`$B)50A(B2J`0T4!Z;T````/MT4@NO\```!F
-M/84`=PL/M\`/MI0'8`@``$B+CS@)``"+13@E____`#WA`1``#X2)````B=!(
-MC11`2(T4D$C!X@5(C1P1@+N`````_W50#[:5F````(T$$H32N@@````/1,(/
-MML!IP$!"#P")@S`!``!(QX-``0```````$B)FT@!``!(C;,P`0``2(M_*.@`
-M````QH.``````&9F9I!(BU,H2(EK*$B-0R!(B44`2(E5"$B)*H"#@P````%(
-M@\0(6UW#9F9FD&9F9I!F9I!!5T%6055!5%532(/L*$F)_DB)="0(#[=.(&:!
-M^84`#X<%`P``#[?!#[:T!V`(``")\$"`_O]T:V:#^7]W(D`/MM9(BX\X"0``
-M2(T$4DB-!()(P>`%2(M$"%`/MD`(ZT-F@?F!`'<=0`^VQDB+EX@)``!(:<#(
-M#P``2(M$$`@/MD`(ZQ]`#[;&2(N78`D``$B-!,!(P>`%2(N$$(@````/MD`(
-M#[;`10^VA`;F"```2XT$@$F-!(!)C83&P`$``$B)1"0028N6B`D``$`/ML9(
-M:<#(#P``3(T\`DB+1"0(2(M02`^V0@$\$G0I/)$/A1("``!+C02`28T$@+D`
-M````08"\QLX!````#X3*`0``Z5L!``!+C02`28T$@$F-!,9(BXC``0``2(E,
-M)"`/MDH)B$PD'@^V4AJ(5"0?NP````"`N,X!````='!!O`````!+C02`28T$
-M@$C!X`--C:P&(`(``$J-+#!,C;7``0``D$R)[^@`````2(G#2(N%*`(``$B)
-MG2@"``!,B2M(B4,(2(D83#E[6'47#[:#@0```$B+5"0(.D(E=!!F9I!F9I!!
-M@\0!13AF#G>V2(M,)`A(BW%X2(7V=`I(BWPD(.@`````2(MT)`A(BWPD(.@`
-M````#[:#R@```(U0`8B3R@```#P#=RN`?"0?`'4D2(M$)`@/ME`E2(MS6$&X
-M`````+D"````2(M\)!#H`````.LSC4(!B(/*````@/H"=B6`?"0?`'4>QD-+
-M`L9#2O^`8TS^2(G>2(M\)"#H`````.D%`0``#[9,)!\/ME0D'DR)_DB+?"00
-MZ`````#IZ0```+T`````2XT$@$F-!(!(P>`#38VD!B`"``!*C1PP3(VKP`$`
-M`$R)Y^@`````2(G!2(N#*`(``$B)BR@"``!,B2%(B4$(2(D(3#EY6'44#[:!
-M@0```$B+5"0(.D(E=`QF9I"#Q0%!.&T.=[H/ME%(2(G0@^`&2(/X!G4<]L(!
-M=!=(BT0D"`^V4"5(BW%82(M\)!#H`````$B+5"0(2(MR>$B%]G0(3(GWZ```
-M``!(BW0D"$R)]^@`````ZRY$#[:'Y0D``$N-!(!)C02`2(V$Q\`!``!(B40D
-M$$B+EX@)``"X.+@/`.E^_?__2(/$*%M=05Q!74%>05_#9F:09F:09F:0055!
-M5%532(/L"$F)_4F)]$B)T\9"2P'&0DH`O@8```!,B>?H`````$B#>U@`=!=(
-MBU,02(M#&$B)0@A(B1!(BT-8@&A8`8"[@P````!T')!,B>_H`````+\!````
-MZ`````"`NX,`````=>5(B[L@`0``2(7_=!$/MK,-`0``N@$```#H`````$B+
-M>UA(A?]T$0^VLX$```"Z`0```.@`````2(MK0$B%[0^$B@```$B#O8``````
-M=7!(@[V(`````'5F]D-,!'493(GOZ`````!(BW-`N@$```!,B>_H`````$B+
-M0T`/ME`"#[9P`4C'QP````"X`````.@`````2(M30$F+M?`(``"_`0```.@`
-M````2(M30$F+M?`(``"_!@```.@`````2,=#0`````!(QT5@`````$B+4V!(
-MA=)T$`^V@X$```!(QT3"6`````!(BQ-(BT,(2(E""$B)$$&`;"0.`4B)WDR)
-M[^@`````08!\)`G_=%U!@'PD#@!T1+L`````28UL)&!F9I!FD$B)[^@`````
-M28M4)&A)B40D:$B)*$B)4`A(B0*`>$K_=0R#PP%!.%PD#G8)Z])!.%PD#G<1
-M0<9$)`G_3(GF3(GOZ`````!(@\0(6UU!7$%=PV9F9I!F9F:09F9FD&9FD$%7
-M059!54%455-(@^P(28G_28GV2(G5QD)+`<9"2@"^!@```$R)]^@`````2(-]
-M6`!T%TB+51!(BT482(E""$B)$$B+15B`:%@!@+V#`````'0;3(G_Z`````"_
-M`0```.@`````@+V#`````'7E2(N](`$``$B%_W01#[:U#0$``+H!````Z```
-M``!(BWU82(7_=!$/MK6!````N@$```#H`````$B+74!(A=L/A`0!``#V14P$
-M=1E,B?_H`````$B+=4"Z`0```$R)_^@`````2(M50`^V@LP```"-!(`/ME("
-M`=!(F`^VB`````!!#[97.D$/MG<Y1`^VA8,```!(Q\<`````N`````#H````
-M`$B+54!)B[?P"```OP$```#H`````$B+BX````!(A<D/A#X!```/MT4X2<>$
-MQV`$````````2,>#@`````````!(B[N0````NO____](B=[_T>D-`0``#[=%
-M.$G'A,=@!````````$C'@X@`````````2(N[D````/_2]D5,`G052(M50$F+
-MM_`(``"_!@```.@`````2,=%0`````!(QT-@`````$B+56!(A=)T$`^VA8$`
-M``!(QT3"6`````!(BU4`2(M%"$B)0@A(B1!!#[96#H/J`4&(5@Y(BT5@2(7`
-M=`=F@WA.`G5@A-)T7$&\`````$V-;F!,B>_H`````$B)PTF+1FA)B5YH3(DK
-M2(E#"$B)&$B%VW0F]D-,`G0@2(M30$F+M_`(``"_!@```.@`````@&-,_69F
-M9I!F9I!!@\0!13AF#G>N2(GN3(G_Z`````!(@\0(6UU!7$%=05Y!7\-(BY.(
-M````2(72#X7C_O__Z0+___]F9F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R)
-M;"0@2(G[2(M'4$R+*$R)[^@`````2(G%2(7`#X35````3(GOZ`````!)B<1(
-MA<!U&L:#Z0````%(B>Y,B>_H`````.FN````9F:0QD4XH$B-53FX`````&9F
-MD,8$$`!(@\`!2(/X!77RQD4^`,9%/P#&14``QD5!B,9%0@#&14,`QD4EJP^W
-M0SAFB44@3(EM*,>%E`````@```#'132(````28M$)!!(B45(2`6(````2(E%
-M4,9%,"1,B65X2,>%H`````````!(C5U8O@````!(B=_H`````$F+="08NH@`
-M``!(B=_H`````$B)[DR)[^@`````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0H
-MPV9F9I!F9F:09F9FD%532(/L"$B)_4B-GT@0``!(B=_H`````(3`#X4(`0``
-M2(G?Z`````")PKF`____@+W@"```_W02@+WA"```_P^%XP```+F!____.(WO
-M````<P:(C>\```"`^8(/A,<````/ML&(E`5@"```#[?"2&G8R`\``$B)VD@#
-ME8@)``"X`````,8$$`!(@\`!2#W(#P``=?!(B=I(`Y6("0``2(U"&$B)0AA(
-MB=I(`Y6("0``2(U"&$B)0B!(B=I(`Y6("0``2(U"*$B)0BA(B=I(`Y6("0``
-M2(U"*$B)0C!(B=I(`Y6("0``2(U"2$B)0DA(B=I(`Y6("0``2(U"2$B)0E!(
-MBX6("0``B$P#6TB+O?`(``"^`````.@`````2(G82`.%B`D``.L%N`````!(
-M@\0(6UW#9F9FD&9F9I!F9F:005132(/L"$F)]$B+G]@0``!(@<>@#P``Z```
-M``")P0^WP$C!X`9(`=A)B00DN@````#&!`(`2(/"`4B#^D!U\@^WP4B#Q`A;
-M05S#9F:09I!(@^P(2(V72`$``+@`````2#F72`$``'0(2(G7Z`````!(@\0(
-MPY"0D)"0D)"0D)!`#[;V2(TT]DC!Y@>!QF!7``")-\-F9F:09F9FD&9FD`^V
-MT@^W1%9X@\`!9HE$5G@/ME8"`=`/M\##9F:09F:0N`$```"`O[M"```!=!.#
-MP`%(@<>P````@_@@=>AFN/__\\-F9F:09F:09F:09F:02(GYN`$```!`.+&X
-M0@``=1\XD;E"``!U%XG`2(T4@$B-%%!(P>($QH07"T(```'#@\`!2('!L```
-M`(/X('7)\\-F9F:09F9FD&9F9I!F9I#&`?Y$#[97!$6$TG1.28GX0;D`````
-M0;L`````N`````!).;#860``=1Y!.--U%4B82(T$P$C!X`</MH0'Q%<``(@!
-MPT&#PP%!@\$!@\`!28'`@`0``$4XT77&\\-F9I!)B?J`^@%T&$0/MD<$OP``
-M``!%A,`/A'`!``#I00$``$&[`````$V%P`^$'`$```^V5P1!NP````"$TG0T
-M2(GX0;L`````0;D`````9F9FD$@YL-A9``!U"4$XR70308/!`4&#PP%(!8`$
-M``!!.--UWT$/MOM(8\](C0S)2,'A!TF-E`I@5P``2(L"28D`2(M""$F)0`A(
-MBT(028E`$$B+0AA)B4`82(M"($F)0"!(BT(H28E`*$B+0C!)B4`P2(M".$F)
-M0#A(BT)`28E`0$B+0DA)B4!(2(M"4$F)0%!(BT)828E`6(M"8$&)0&!!@+P*
-M8%<```!T4[X`````2&/'2(T$P$B-/,4`````3HT,$4`/ML9(B<)(P>($28U,
-M$&!(C00'2,'@!$F-E`+@60``2(L"2(E!!$B+0@A(B4$,@\8!03BQ8%<``'?%
-M00^VPTB-!,!(P>`'00^VA`)@5P``PTR)TKD`````OP````!FD$@YLMA9```/
-ME,`!QX/!`4B!PH`$``!$.,%UY4`/ML?#055!5%532(GS28G538G,08G)1(G%
-M28GXO@````!F9I")\4@Y7R`/A84```!(8\9(:<!0$```38U4`"!!NP````!$
-MB=I!#[9"+(3`=`0\\'5/2&/22&/)2(G02,'@!4AIR5`0``!(`<A,`<!(B5@P
-M3(EH.$C!X@5(C50*($J-!`)(C4@@9HEI`D2(2"!)BP0D28E$$"3&00S_ZQ9F
-M9I!FD$&#PP%)@\(@08'[@@```'60@\8!2(''4!```(/^!`^%7/___UM=05Q!
-M7<-F9I!FD$%505154TB#[`A)B?5(B?V`?P0`=$9!O`````!F9F:000^VW$AC
-MPTB-!,!(P>`'@+P%Q%<``/UT&4B-O`6\5P``N@@```!,B>[H`````(3`=0]!
-M@\0!1#AE!'?$N_\```")V$B#Q`A;74%<05W#9I!32(G[Z`````"Z"0```#S_
-M=!,/ML!(C03`2,'@!P^VE`-F5P``B=!;PV9F9I!F9I!(@^P(28GR28G11(G"
-M2(G^3(V'8$$``+@`````9F9FD$+&!```2(/``4@]D````'7OQH9A00``$\:&
-M8$$``$`/ML:(AF9!``"(EF=!``"(CFE!``!(QX8`0@```````$B)OOA!``!)
-MBT%<2(F&\$$``$B!QF!!``!,B=?H`````$B#Q`C#9F9FD&9F9I!F9I!!54%4
-M55-(@^P(28GU28G43(G-08G)1(G#2(GX28GZN@$```!!B=-!B="`N+M"```!
-M#X7N````2&/22(T$DDB-!$)(P>`$3`'02(V0`$(``,9""P!,B9#X00``#[9*
-M"DACP4B-%(!(C1102,'B!$F-E!)@00``N`````!F9I!FD,8$$`!(@\`!2#V0
-M````=?!(8\%(C32`2(TT<$C!Y@1*C1062(V*8$$``,9!`9#&@F!!``!`#[;'
-MB$$&B)IG00``1(A)"4B+10!)B80R<$$``$ECP$B-%(!(C1102,'B!$J-!!)(
-MQX``0@```````$B)N/A!``!)BT0D7$F)A!+P00``00^VPTB-%(!(C1102,'B
-M!$F-M!)@00``3(GOZ`````#K%X/"`4@%L````(/Z(`^%[?[__[@!````2(/$
-M"%M=05Q!7<-F9I!F9I!F9I!(@^P(28GS08G22(GZ28GXN`$```")QH"ZNT(`
-M``$/A>$```!(F$B-%(!(C1102,'B!$F-A!``0@``1(A0"(A("<9`"P!$#[9(
-M"DECP4B-%(!(C1102,'B!$F-E!!@00``N`````#&!!``2(/``4@]D````'7P
-M26/12(T$DDB-!$)(P>`$3`'`2(V08$$``,9"`1#&@&!!``!`B$H)2&/&2(T,
-M@$B-#$A(P>$$00^VA`@*0@``2(T4@$B-%%!(P>($2HT$`DC'@`!"````````
-M2(FX^$$``$$/ML)(C03`2,'@!TF+A`"\5P``28F$"/!!``!)C;008$$``$R)
-MW^@`````ZQ6#P`%(@<*P````@_@@#X7]_O__L`%(@\0(PY!(@^P(28GQB=!(
-MB?[&APM"````3(V'8$$``+D`````D$+&!`$`2(/!`4B!^9````!U[L:&84$`
-M``'&AF!!``!`2,>&`$(```````!(B;[X00``#[;`2(T$P$C!X`=(BX0&O%<`
-M`$B)AO!!``!(@<9@00``3(G/Z`````!(@\0(PTB#[`A)B?&)T$B)_L:'"T(`
-M``!,C8=@00``N0````"00L8$`0!(@\$!2('YD````'7NQH9A00```,:&8$$`
-M`$!(QX8`0@```````$B)OOA!```/ML!(C03`2,'@!TB+A`:\5P``2(F&\$$`
-M`$B!QF!!``!,B<_H`````$B#Q`C#05=!5D%505154TB#[#A(B7PD&$B)="00
-M08G51(A$)`])B?Q%#[;U26/&2(T$P$C!X`>`O`?$5P``_0^$Q@@``(#Y$`^$
-MA0(``(#Y$'<7A,D/A)T```"`^0$/A:<(``"0Z08!``"`^>)T&X#Y_V9FD'0I
-M@/F0#X6+"```9F:09I#IR`8``+D`````@'\$`&:0#X7<!P``Z00(``!)8\9(
-MC03`2,'@!\:$!\17``#_@+\+0@```74E1(GR2(MT)!!(BWPD&.@`````A<`/
-MA34(``!!@$0D!@'I*@@``$ECQL9$!P<!2(M4)!!(B53'$.D3"```@+\+0@``
-M`7582(V/8$$``$ECQDB-!,!(P>`'2`'X#[91"8B08E<``$@%P%<```^V40J#
-MX@&(4`7&0`0`1(GR2(MT)!!(BWPD&.@`````A<`/A;T'``!!@$0D!@'IL@<`
-M`$ECQL9$!P<!2(M,)!!(B4S'$.F;!P``26/&2(T$P$C!X`=(C30X#[:7DD$`
-M`(B6LE<```^WEY!!``!FB90'L%<``$B+EXA!``!(B90'H%<``$B+EVQ!``!(
-MB90'<%<``$B-C`>`5P``2(N7=$$``$B)$4B+EWQ!``!(B5$(BY>$00``B90'
-MF%<``,:&Q%<```&`?P8?#X07!P``NP````!(C:Y@5P``3(VNL%<``.M)#[;+
-M1(GR2(MT)!!(BWPD&.@`````A<!T%4ECQDB-!,!(P>`'08B<!+-7``#K((/#
-M`4&`1"0&`3A=`@]%PT&(10-!@'PD!A]T!3I=`G*R0<:$)`M"```!00^V="0$
-M0(3V#X2<!@``N@````!!@'PD!P%T%^M#9F9FD&9FD`^VT4ACPD&`?`0'`74S
-M2&/"0<9$!`?_28MTQ!!!N0````!!N`````"Y_P```$B+?"08Z`````#I2@8`
-M`+D`````@\$!0#CQ=;?I.`8``$V)STF-01A(B40D($B-="0P28M!&$B)1"0P
-M26/&2(T$P$C!X`=(C2PX2(V%P%<``,9`!!!!]D$,<`^$0@,``$B+E<A7``!(
-MA=)T<0^V6`9(C7I<N@@```#H`````(3`=5M!]D</#W142(N%R%<``$B%P'1(
-M2(G%@'UE`'0_#[;;B=I(B>Y,B>?H`````$R+3"0@1`^WP(G92(GJ2(MT)!!(
-MBWPD&.@`````#[9=9DB+16A(A<!T!4B)Q>N[00^V3P_VP0T/A.L```!)8\9(
-MC13`2(G02,'@!T$/MK0$8%<``$"`_A\/A\H```#VP0AT%T`/ML9(C0302,'@
-M!$'&A`3@60``!NL<0`^VUDECQDB-!,!(C03"2,'@!$'&A`3@60``!T`/ML9)
-M8_9(C33V2(T4\$C!X@1)C;P4X%D``,9'`0!!#[9'#XA'`TB+1"0P28F$%.A9
-M``!!#[9'"8A'`D$/ME<-@^(/2,'F!TP!YDB-CF!7```/MD$&.,(/1]"#X@\/
-MMD<$@^#P"="(1P1!#[97*8/B#P^V208XR@]'T<'B!(/@#PG0B$<$@(9@5P``
-M`>G,`0``]L$"#X3#`0``2(UT)#!,B>?H`````(G!//\/A6(!``!!#[9,)`2$
-MR70]00^VA"3$5P``//]T,+H`````//UU'NLE#[;"2(T$P$C!X`=!#[:$!,17
-M```\_W02//UT#H/"`3C*==WK!;H`````#[;"2(T$P$C!X`=)C8P$8%<``+@`
-M````Q@0(`$B#P`%(@_AD=?)$#[;226/22(T4TDC!X@=*C3PB00^VQ4B-!,!(
-MP>`'28V$!&!7``!(B8?(5P``38V$%+!7``!)8]9(C1322,'B!TF+A!2\5P``
-M28E`!$B+3"002(F/V%D``$P!XDB+@M!7``!(B8?05P``3(V/P%<``$'&003_
-M2(VW8%<```^V3@=!#[9'"8B$#VA7``"`1@<!00^V1PV#X`\/MI)F5P``.-`/
-M1\*(1@9(BT0D,$F)0`Q!#[9'#XA&`P^V1"0/08A!!D$/MD0D!4$Z1"0$=09!
-MQD0D!0!!@$0D!0%)8\)!QD0$!P%(BU0D$$F)5,00ZTI)8\9(C03`2,'@!P^V
-MT4B-%-)(P>('28V4%&!7``!).90$R%<``'0B#[;!2(T$P$C!X`=,`>`/MG('
-M00^V3PF(C#!H5P``@$('`4$/ME<)1(GV3(GGZ`````!)8\9(C03`2,'@!T&`
-MO`2S5P````^$H````$&`?"0&'W5CZ8`"``!!QD<$$`^V2P-$B?)(BW0D$$B+
-M?"08Z`````"%P`^%70(``$&`1"0&`0^V2P,/ML&#P`$/ME4".=!U#\9#`P#I
-M/`(``&9FD&9FD(U!`8A#`T&`?"0&'P^$)`(``.LC26/&2(T$P$C!X`=,`>!(
-MC9BP5P``2(VH8%<``$R-N,!7```/MD,#.D4"#X)R____Z>T!``!!@'PD!@`/
-MA>$!``!!N0````!!N`````"YD````$2)\DB+="002(M\)!CH`````.FY`0``
-M28G]0;\`````2(M,)!!).4T@#X6#````1(GX2&G`4!```$F-7`0@O0````!$
-MB?A(:<!0$```2(D$)(![+/]U2D&`?"0&'P^$;0$``(GH2,'@!4B+%"1(C400
-M0`^V2R!(BU,838U,!`1$#[=#(DB+="002(M\)!CH`````(7`=0I!@$0D!@'&
-M0RSP2(/%`4B#PR!(@?V"````=9])@\<!28'%4!```$F#_P0/A5G___]!@'PD
-M!@`/A?T```!!#[9T)`1`A/8/A,L```"Z`````$&`?"0'`700ZSP/MM%(8\)!
-M@'P$!P%U,TACPD'&1`0'_TF+=,000;D`````0;@`````N?\```!(BWPD&.@`
-M````Z:,```"Y`````(/!`4`X\76WZW$/ML%(C03`2,'@!TF-E`3`5P``#[9"
-M!#S]=`@\_W0$QD($_H/!`4$X3"0$=]-)8\9(C03`2,'@!TF+K`305P``NP``
-M``!"@'PC*`%U$D+&1",H`$J+=",@2(M\)!C_U4B!PU`0``!(@?M`00``="7K
-MU$&Y`````$&X`````+GB````1(GR2(MT)!!(BWPD&.@`````2(/$.%M=05Q!
-M74%>05_#9F9FD&9F9I!F9I!(@^P82(D<)$B);"0(3(ED)!!)B?Q(B?5(BYZ8
-M````@'L&``^$1P$``$B-MI````!(B=_H`````(G!//\/A"X!``!(B>X/MD4!
-M/`%T6CP!<AH\$`^$B@```#R09F:09I`/A0H!``#IQ@```("["T(````/A?@`
-M``#&@PM"```!@&L&`0^VT4&Y`````$&X`````+D`````3(GF2(G?Z`````#I
-MR0```("["T(````/A;P```#&@PM"```!@&L&`0^VT4&Y`````$&X`````+D!
-M````3(GF2(G?Z`````#IC0```+H`````.HP:N$(``'4/#[:$&KE"```Z1@ET
-M$F:02('"L````$B!^E`5``!UV(!K!@$/MM%)B?%$#[9&";D0````3(GF2(G?
-MZ`````#K/P^VA:H```!(C12`2(T44$C!X@3&A!,+0@```8!K!@$/MM%!N0``
-M``!!N`````"YD````$R)YDB)W^@`````D$B+'"1(BVPD"$R+9"002(/$&,-F
-M9F:09F:09F:09F:008G0B?*%]G042(GY2(G0D,8!`$B#P0%(@^@!=?.)-TB!
-MZF!7``!(N(_C.([C.([C2/?B2,'J"D$XT$$/0M"(5P2$TG0KN@````!F9I!F
-M9I`/ML+&1`<'_TB-!,!(P>`'QH0'Q%<``/V#P@$X5P1WX,9'!@#&1P4`2(GX
-MN@````#&@`M"```!B)`*0@``@\(!2`6P````@_H@=>7SPV9FD$B)^8!_!``/
-MA)D```"_`````$0/ML=)8\!(C03`2,'@!T@YM`'860``=6ZX`````$`XO`BX
-M0@``=0C&A`B[0@```4@%L````$@]4!4``'7@26/`2(T$P$C!X`=(QX0!V%D`
-M``````!(C90!8%<``+@`````Q@00`$B#P`%(@_AD=?))8\!(C03`2,'@!\:$
-M`<17``#]@&D%`8/'`4`X>00/AVS___](B<]!N`````!(.7<@=3!(QT<@````
-M`,9'*`!)8\!(:<!0$```2(U$`2"Z`````,9`+`"#P@%(@\`@@/J"=?!!@\`!
-M2(''4!```$&#^`1UN?/#9F9FD&9F9I!!54%455-(@^P(2(G]2(GW28G438G%
-M08G(2(GK#[9%!3I%!'4$QD4%`$0/MEL%2(G>28G9N`````!!B<*)PDF+22!(
-M.?EU2TB82&G`4!```,9$`R@!#[9+!$&[`````(3)=&1!NP````!(.;[860``
-M=0X/MH;$5P``@\`#/`%V1T&#PP%(@<:`!```03C+=#?KUTB%R7492&/"2&G`
-M4!```$@!V$B)>"#&0"@!ZQEFD$&#P@&#P`%)@<%0$```@_@$#X5R____00^V
-MPDAIP%`0``!(C40#,+D`````9F9FD,8$`0!(@\$!2('Y`A```'7O10^VTTEC
-MPDB)?,,000^VPTB-!,!(P>`'2(V$`V!7``!FN0``Q@0!`$B#P0%(@_ED=?))
-M8\)(C03`2,'@!TB-C`/85P``N`````!F9I!FD,8$"`!(@\`!2#T``@``=?!)
-M8\)(C03`2,'@!TB-#!A(B;G860``3(FIT%<``,:!Q%<``/](QX'(5P``````
-M`$F+%"1(B90#O%<``$2(@697``!!N0````!!N`````"Y_P```$2)TDB)_DB)
-M[^@`````@$,%`4B#Q`A;74%<05W#2(L'3(L`#[9P0T"$]G1'#[97#;D`````
-M]L(!=`WK-Y!(B=!(T_BH`74(@\$!0#CQ=>Z`^0-V)$B-!(T`````)?P#``!)
-MC80`T`$``(L`B04`````ZR*Y`````$B-!(T`````)?P#``!)C80`T`$``(L`
-MB04`````P>@4@^`!PY!(BP=$#[9`0T&Y"@```$6$P'1*#[9_#4B)PKX`````
-M0;D*````N0````!F9I!F9I!(B?A(T_BH`704#[:"ZA(``(/@`X/`"$$XP40/
-M1\B#Q@&#P0%(@\)H1#C&==-!#[;!PV9F9I!F9F:09F:09F:02(L'1`^V0$-!
-MN0@```!%A,!T2@^V?PU(B<*^`````$&Y"````+D`````9F:09F:02(GX2-/X
-MJ`%T%`^V@NH2``"#X`.#P`A!.,%$#T+(@\8!@\$!2(/":$0XQG7300^VP<-F
-M9F:09F9FD&9FD&9FD`^V!\#H!(/@!P^V=P*)PH#.`D#VQ@0/1<(/MD\#B<*!
-MR@```@#VP00/1<*)PH#."$#VQ@@/1<*)PH'*```(`/;!"`]%PHG"@,X$0/;&
-M`@]%PHG"@<H```0`]L$"#T7"#[97%,'B&`G0PV9F9I!F9I#H`````//#9F:0
-M9F:09F:0BX<0"0``)?___P"Z`````#U0`9,`=1D/MH<3"0``P.@$/`P/E,`/
-MMM!F9F:09F:0B=##9F9FD&9FD&9FD&9FD(7V?D(/M@>$P'0$/"!U,4B)^KD`
-M````ZQ=F9F:09F:0#[9"`4B#P@&$P'0$/"!U$(/!`3GQ=>GK#69F9I!F9I"X
-M`````,.X`0```&9FD&:0PV9F9I!F9F:09F9FD&9FD`^V1P,/ME<"P>(("=#!
-MX!`/MD\!#[87P>(("=$)R,.008G0A=)T);D`````9F9FD`^V%P^V1P&(!HA6
-M`4B#Q@)(@\<"@\$!1#G!=>3SPV:02(/L"$F)\`^W1B"Z_P```&8]A0!W"P^W
-MP`^VE`=@"```#[?22(T4TDC!X@5(`Y=@"0``2(NW"!$```^V0E#!X`A(F$B-
-MA`9,"```BPB)#0````"!X?\````/MD)0P>`(2)A(C;0&1`@``(L&B04`````
-MP>`("<B)@A`!``!FQX(,`0````!,B<;H`````$B#Q`C#9F9FD&9FD&9FD&9F
-MD$B#["A(B5PD"$B);"003(ED)!A,B6PD($F)_4&)]$B++T"`_@-V.4J-'.4`
-M````@>/X!P``2(V$'3`"``#'``P```"_$"<``.@`````2(V$'30"``"+.(D]
-M`````.LWD$J-'.4`````@>/X!P``2(V$*U`"``#'``P```"_$"<``.@`````
-M2(V<*U0"``"+.XD]`````$$/MO1(8\9(C11`2(T4D$F-E-6P$@``#[9*$8/A
-M_(A*$8GX)0``/P`]```0`'4+B<B#R`*(0A'K&9!(8\9(C11`2(T4D(G(@\@!
-M08B$U<$2``!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9F9I!F9F:0
-M9F:005=!5D%505154TB#[!A)B?Y,BS])BP?&1DD`QD9(!<9&2P9(B7Y0N0``
-M``"]`````$B-D``"``!(B50D$$@%!`(``$B)1"0(ZQ9F9I!F9I!!#[9&#4C3
-M^*@!=0J#P0&003I/0W+J@/D#=GI(C1S-`````('C^`<``$R+;"0020'=0<=%
-M`"P```"_$"<``.@`````2`-<)`A$BR-$B24`````0<=%`"0```"_$"<``.@`
-M````BP.)!0````#!X`A!@>3_````00G$0<=%`"````"_$"<``.@`````BQN)
-M'0````#K>$B-',T`````@>/X!P``3(ML)!!)`=U!QT4`+````+\0)P``Z```
-M``!(`UPD"$2+(T2))0````!!QT4`)````+\0)P``Z`````"+`XD%`````,'@
-M"$&!Y/\```!!"<1!QT4`(````+\0)P``Z`````"+&XD=`````$&!_`$!:99U
-M&D&`3@P&B=C!Z!`\4`^4P`^VP.M(9F:09F:008'\`0$``'4/B=C!Z!`\4`^4
-MP`^VP.LJOX@3``#H`````(/%`4"`_01W"KD`````Z:O^__^)V,'H$#Q0#Y3`
-M#[;`2(/$&%M=05Q!74%>05_#9F9FD&9F9I!F9F:09F:0055!5%532(/L"$B)
-M_4&)]$B+AX@```!,BRAF@[\,`0```'0PB?._Z`,``.@`````187D=`6#^P%V
-M&DR)[V9FD.@`````9H.]#`$```!T!8/K`NO22(/$"%M=05Q!7<.02(/L.$B)
-M7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_(G+08GV08G518G'2(N'
-MB````$B+*$B)[^@`````2(G&QD`XX<9`.0'&0#H2N`\```!%A/9U!D$/MD0D
-M1XA&.T2(;CQ,B>H/ML:(1CT/ML>(1CZ)V,'H$(A&/XG8P>@8B$9`B%Y!00^W
-M1"1`9HE&($B);BC'1C0`````2,=&2`````!%A/](Q\``````2,?"`````$@/
-M1<)(B8:@````2(GOZ`````!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\
-M)#!(@\0XPV:02(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($F)_(G+08GV
-M08G52(N'B````$B+*$B)[^@`````2(G&QD`XX<9`.0'&0#H2N`\```!%A/9U
-M!D$/MD0D1XA&.T2(;CQ,B>H/ML:(1CT/ML>(1CZ)V,'H$(A&/XG8P>@8B$9`
-MB%Y!00^W1"1`9HE&($B);BC'1C0`````2,=&2`````!(QX:@`````````$B)
-M[^@`````2(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-FD%-(B?M!B<I!
-MB=%(A?\/A`$!``!,BP=-A<`/A/4```!!#[9X0X7_?E=(BX.(````#[90#;D`
-M````]L(!=`WK0)!(B=!(T_BH`74'@\$!.?EU[X/Y`WXN28L`2`70`0``C12-
-M`````$ACTD@!T(L`B04`````P>@4@_`!@^`!ZRRY`````$F+`$@%T`$``(T4
-MC0````!(8])(`="+`(D%`````,'H%(/P`8/@`83`=66`NQP!````=0:`>T(`
-M=58/MT-`08"\`&`(``#_=$?&0T(E9L>##`$```$`00^WT4`/MO9!N`$```!$
-MB=%(B=_H`````+X%````2(G?Z`````#&0T(`9H.[#`$````/E,`/ML#K!;@`
-M````6\-F9I!FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)_4&)]4&)U$B+
-MAX@```!(BQA(B=_H`````$B)QL9`..'&0#D!QD`Z$;@/````183M=00/MD5'
-MB$8[1(AF/$R)X@^VQHA&/0^W14!FB48@2(E>*,=&-`````!(QT9(`````$C'
-MAJ``````````2(G?Z`````!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F:0
-M9F:09F:055-(@^P(2(G[2(G-08G12(7_#X0&`0``3(L'387`#X3Z````00^V
-M>$.%_WY62(N#B`````^V4`VY`````/;"`70,ZS](B=!(T_BH`74'@\$!.<]U
-M[X/Y`WXN28L`2`70`0``C12-`````$ACTD@!T(L`B04`````P>@4@_`!@^`!
-MZRRY`````$F+`$@%T`$``(T4C0````!(8])(`="+`(D%`````,'H%(/P`8/@
-M`83`=6N`NQP!````=0:`>T(`=5P/MT-`08"\`&`(``#_=$W&0T(E9L>##`$`
-M``$`00^WT4`/MO:Y`0```$B)W^@`````O@4```!(B=_H`````,9#0@!F@[L,
-M`0```'40BX,0`0``B44`N`$```#K!;@`````2(/$"%M=PV9FD&9FD$B#["A(
-MB1PD2(EL)`A,B60D$$R);"083(ET)"!(B?U!B?5!B=1!B<Y(BX>(````2(L8
-M2(G?Z`````!(B<;&0#CAQD`Y`<9`.A&X#P```$6$[74$#[9%1XA&.T2(9CQ,
-MB>(/ML:(1CT/MT5`9HE&($B)7BC'1C0`````2,=&2`````!%A/9(Q\``````
-M2,?"`````$@/1<)(B8:@````2(G?Z`````!(BQPD2(ML)`A,BV0D$$R+;"08
-M3(MT)"!(@\0HPV9F9I!F9I!F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL
-M)"!(B?5!B=1!B<U(BQ](B=_H`````$B)PDB%P'40QH7I`````<9%2@/IE```
-M`,9`..'&0#D!08#\`1G`]]"#P`*(0CI%A.UU4;@`````2(-]8`!T!P^VA8$`
-M``"(0CL/MT4X9HE"($B)6BC'0C0`````2,="2`````!(Q\``````2(F"H```
-M`$B)UDB)W^@`````ZRUF9I!FD,9".P\/MT4X9HE"($B)6BC'0C0`````2,="
-M2`````!(Q\``````Z[](BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9F
-M9I!F9F:09F:005=!5D%505154TB#[#B)]4F)U$B+#XT4[0````"-0N")P$B-
-MG`@@`@``2(D<)$B-A`@D`@``2(E$)`B)TDR-O`H``@``3(VL"@0"``"[````
-M`$R-="00@_T#=B6-@QP!``!(BQ0DB0*_$"<``.@`````2(M4)`B+`HD%````
-M`.L=C8,<`0``08D'OQ`G``#H`````$&+10")!0````!"B00S2(/#!$B#^QQU
-MJTB+1"0028D$)$B+1"0828E$)`A(BT0D($F)1"00BT0D*$&)1"082(/$.%M=
-M05Q!74%>05_#9F9FD&9F9I!F9F:09F:005=!5D%505154TB#[#B)]4F)U$B+
-M#XT4[0````"-0N")P$B-G`@@`@``2(D<)$B-A`@D`@``2(E$)`B)TDR-O`H`
-M`@``3(VL"@0"``"[`````$R-="00@_T#=B6-@P`!``!(BQ0DB0*_$"<``.@`
-M````2(M4)`B+`HD%`````.L=C8,``0``08D'OQ`G``#H`````$&+10")!0``
-M``!"B00S2(/#!$B#^QQUJTB+1"0028D$)$B+1"0828E$)`A(BT0D($F)1"00
-MBT0D*$&)1"082(/$.%M=05Q!74%>05_#9F9FD&9F9I!F9F:09F:005=!5D%5
-M05154TB#[#A)B?Y`B'0D"TR+/T0/MNY)8\5(C11`2(T4D$B-%-=(C8*P$@``
-M0(AP$$B)NK@2``#&0!(`1(GNZ`````!(C6PD$$B)Z$B)ZL8``$B#P`%(B=-,
-MC60D,$PYX'7L#[9$)`N)1"0,B<9,B??H`````$B)W^@`````26/52(T,4DB-
-M#(I(P>$#2HT4,8F"T!(``$B+0PQ)B80.U!(``(!\)`L#=CQ"C02M`````$B8
-M28V$!]`!``"+`(D%`````(F"Z!(``$*-!.T`````2)A)C80'@`$``(L(B0T`
-M````ZT="C02M`````$B828V$!]`!``"+"(D-`````$ECQ4B-%$!(C12008F,
-MUN@2``!"C03M`````$B828V$!X`!``"+"(D-`````$ECQ4B-%$!(C12028T4
-MUDB-@N`2``")2`SV0`H0#X0Z`0``]H+!$@```G1/D,9%``!(@\4!3#GE=?-(
-MC5PD$$B)VHMT)`Q,B??H`````$B)W^@`````26/52(T,4DB-#(I(P>$#08F$
-M#MP2``!(BT,,28F$#N`2``#K%TECQ4B-%$!(C1200<>$UMP2```!``(`@'PD
-M"P-V-4*-'.T`````2&/;2HV$.S`"``#'`!@```"_$"<``.@`````2HV<.S0"
-M``"+,XDU`````.LS0HT<[0````!(8]M*C80[4`(``,<`&````+\0)P``Z```
-M``!*C9P[5`(``(LSB34`````26/%2(T40$B-%)")\8'A____WXGP#0```"!!
-M]X36Z!(``````P")R@]%T(!\)`L#=A9"C03M`````$B828V$!S0"``")$.L4
-M0HT$[0````!(F$F-A`=4`@``B1!(@\0X6UU!7$%=05Y!7\.0059!54%455-(
-MB?U)B?9)B?4/MP9FA<!Y"R4`'P``P?@(B$=)2(V]A````$F-511)BT442(F%
-MA````$B+0@A(B4<(BT(0B4<03(VEP````$F+12Y(B87`````2(V=F````$F-
-M539)BT4V2(F%F````$B+0@A(B4,(2(M"$$B)0Q!(BT(82(E#&$B+0B!(B4,@
-MN@H```!(B?[H,_#__[H$````3(GF3(GGZ"/P__^Z%````$B)WDB)W^@3\/__
-M9L=%:```9L=%:@``9D&#OK(!```!#Y3"P>(##[9%3(/@]PG0B$5,0?:%IP``
-M``1T!F;'16@!`$'VA:0````!="1F@TUH`D'VA:H````!=`5F@TUJ`4'VA:@`
-M```!=`9F@4UH``%!]H6D````('049H--:`1!]H6J````('0%9H--:@)!]H6D
-M````0'069H%-:(``0?:%J@```$!T!F:#36H(D,:%@@````)!]H69`````70R
-M#[=%:*@!=`R#R`AFB45H9H--:A!!#[:%E@```(/@'X/``3P@NA\````/1,*(
-MA8(```!!]H68````"'0&9H%-:``"0?:%F`````1T!6:#36@@0?:%F`````)T
-M!6:#36@00?:%J````"!T%4'VA:X````@=`MF@TUH0&9FD&9FD/9%:`%T#4F+
-MA<@```!(B45XZPA!BT5X2(E%>$B#;7@!0?9%:@)T&D$/MX6`````J`]T#F:#
-M^`(9P(/`!(A%;.L$QD5L`L9%;?]!#[=5?@^WPJ@$=`O&16T"ZQMF9I!FD*@"
-M=`;&16T!ZPSVP@%F9I!T!,9%;0#&16[_0?9%:@1T'[D`````00^WA;````!(
-MT_BH`70#B$UN@\$!@_D'=>:^``(``$R)[^@`````B87,````0?:&I@```"!T
-M&T$/MX:L````@^`@@_@!&<"#P`*(A9@!``#K!\:%F`$```"X`0```%M=05Q!
-M74%>PV9FD$B#["A(B1PD2(EL)`A,B60D$$R);"083(ET)"!)B?U)B?9,BR>[
-M@/___^L)9F9FD(#[A7=##[;#00^VK`1@"```0(#]_W0Q0`^VQ4AIP,@/``!(
-MB<=)`[PDB`D``$PY;PAU%;H(````3(GVZ`````"$P'0$B>CK#X/#`8#[@6:0
-M=JZX_____P^VP$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F:09F:0
-M9F:005=!5D%505154TB#[#A)B?Y(BP>`?T,`#X01`P``QT0D-`````!(C9``
-M`@``2(E4)`A(!00"``!(B00D9F9FD`^V3"0TB$PD,T0/MOE)8\=(C11`2(T4
-MD$F---;VANH2```0#X2O`@``2(V6L!(``+@!````1(GY2-/@"$(22(NVR!(`
-M`$B)="0H]D(1`@^$'@$```^V1"0SC6@!03AN0P^&#`$``$ECQTB-%$!(C120
-M2,'B`TB)5"0@3`'R2(E4)!A(BU0D($F-E!;@$@``2(E4)!!$#[;M26/%2(T4
-M0$B-%)!(C1S5`````$Z-)#-!]H0DZA(``!`/A*<```!(BTPD&/>!W!(`````
-M#@`/A)(```!)C;0>X!(``+H(````2(M\)!#H`````(3`='=)C;0>U!(``$B+
-M1"0@28V\!M02``"Z"````.@`````A,!T5+@!````1(GI2-/@2(M4)!A(@<*P
-M$@``"D(2B$(208B$),(2``!(@WPD*`!U#TV+I"3($@``3(ED)"CK&$ECQ4B-
-M%$!(C1202(M$)"A)B836R!(``(/%`4$X;D,/AR+___](@WPD*``/A<0```!,
-MB??H`````$B)1"0H2(7`#X1;`0``26/'2(T,0$B-#(A)C0S.2(M4)"A(B9'(
-M$@``#[9$)#-(C11`2(T4D$F-E-:X$@``2(M$)"A(B5`@#[:!P1(``$B+5"0H
-MB$(*QD()`$R),L9"#@#&0E@`QD(H``^V3"0SC7$!03AV0W9=26/'2(T40$B-
-M%)!)C;S6L!(``$`/MLX/MD<22-/XJ`%T&$ACP4B-%$!(C1202(M$)"A)B836
-MR!(``(/&`4$X=D-V&NO.26/'2(T40$B-%)!(BTPD*$F)C-;($@``26/'2(T4
-M0$B-%)!)C936L!(```^V0A)(BTPD*(A!#0^V:A*`?"0S`W8K0HT<_0````!(
-M8]M(BT0D"$@!V,<`.````+\0)P``Z`````!(`QPDB2OK*4*-'/T`````2&/;
-M2(M$)`A(`=C'`#@```"_$"<``.@`````2`,<)(DK@T0D-`$/MD0D,X/``4$X
-M1D,/AQ']__](@\0X6UU!7$%=05Y!7\-FD$%7059!54%455-(@^QH2(G]3(LG
-MQD0D4%#&1"11!<9$)%($QD0D4S#&1"14$<9$)%6KQD0D5@#&1"17`$''A"0`
-M0`$`$R```$B+!\>`!$`!`/__``!(BP?'@`1``0``````2#N_\`@```^%U```
-M`$B-GX@4``!(C9<0"0``0;@!````N0@```"^```"`.@`````BX4("0``#[:5
-M$PD``(/J!(T$@HB%$PD``$B)[^@`````A,!U#$B+1"102(F%$`D``(L%````
-M``"%$PD``(/``8D%``````^VA1`)``"(@Q`)```/MH41"0``B(,1"0``#[:%
-M$@D``(B#$@D```^VA1,)``"#P`*(@Q,)```/MH44"0``B(,4"0``#[:%%0D`
-M`(B#%0D```^VA18)``"(@Q8)```/MH47"0``B(,7"0``38GG28V$)``!``!(
-MB40D0$&+A"0``0``B04`````#[?0B50D7*@@=`LEW_\``(E$)%SK&(G0@\@@
-MB40D7$B+5"1`B0*+`HD%`````$B+10#'@`0!````````2(M%`,>`&`$`````
-M``!(BT4`QX`<`0```````+^0T`,`Z`````!!QX=P`0``&`$``$&+AW0!``")
-M!0````"`Y/V`S`2)1"1<0<>'<`$``!@!``"+1"1<08F'=`$``$''AW`!```H
-M`0``0<>'=`$``']_``!!QX=P`0``)`$``$&+AW0!``")!0````!FN```#?\_
-M``")1"1<0<>'<`$``"0!``"+1"1<08F'=`$``$''AW`!```\`0``0<>'=`$`
-M````>@!!QX=P`0``I`$``$''AW0!``!]O^__0<>'<`$``+@!``!!BX=T`0``
-MB04`````)?__```-``#Z`(E$)%Q!QX=P`0``N`$``(M$)%Q!B8=T`0``0<>'
-MG````/\```!!QX>0`@``1`$``$''AY0"```&$``(0<>'D`(``+0!``!!QX>4
-M`@``7W```$''AY`"```P````08N'E`(``(D%`````##D@,PSB40D7$&)AY0"
-M``"`?4,`#X25`@``QT0D2`````!)C8=0`@``2(E$)#A)C9=4`@``2(E4)#!(
-MC840"0``2(E$)"A)C9>``0``2(E4)"!)C8>$`0``2(E$)!A)C9<P`@``2(E4
-M)!!)C8<T`@``2(E$)`AF9F:09F:0#[94)$B(5"1/@/H##X;^````1`^V\D*-
-M'/4`````2&/;3(ML)!!)`=U!QT4`"````+\0)P``Z`````!(BT0D"$R-)`-!
-MBP0DB04`````B40D7`T``(``08D$)$B+5"0H1(GV2(GOZ`````!$B?9(B>_H
-M`````$''10!$`0``OQ`G``#H`````$''!"0&$``(0<=%`+0!``"_$"<``.@`
-M````0<<$)%]P``!!QT4`"````+\0)P``Z`````#'1"1<_U2``$''!"3_5```
-MN@$```!$B?9(B>_H`````$B+1"0@2(T4`XL"B04`````)?___O^)`L=$)%P%
-M`<@`2`-<)!C'`P4!R`#I^P```&9F9I!$#[9T)$]"C1SU`````$ACVTR+;"0X
-M20'=0<=%``@```"_$"<``.@`````2(M4)#!,C20308L$)(D%`````(E$)%P-
-M``"``$&)!"1(BU0D*$2)]DB)[^@`````1(GV2(GOZ`````!!QT4`1`$``+\0
-M)P``Z`````!!QP0D!A``"$''10"T`0``OQ`G``#H`````$''!"1?<```0<=%
-M``@```"_$"<``.@`````QT0D7/]4@`!!QP0D_U0``+H!````1(GV2(GOZ```
+M?T5,1@(!`0D```````````$`/@`!`````````````````````````$#S!```
+M`````````$```````$``$``-`(GP9HEW",9'#@!FQT<,``!FA?9T'XU0_[D`
+M````9F:02(L'9HD4"$B#P0*#Z@%F@_K_=>SSPV9F9I!F9I!F9I!!B?!FB7<(
+MQD<.`6;'1PP``&:%]G0>N@````"Y`````$B+!V:)%`B#P@%(@\$"9D0YPG7L
+M\\-F9F:09F:09F:0@'\.`74J#[='#`^WR$B+%P^W%$J#P`%FB4<,9CM'"G(&
+M9L='#```9H-O"`$/M\+#2(L7#[='"(/H`6:)1P@/M\`/MP1"PV9F9I!F9I!F
+M9I"`?PX!=2H/MU<(#[='#`'"#[='"HG!B=#!^A_W^4ACTDB+!V:)-%!F@T<(
+M`<-F9I`/MT<(#[?(2(L79HDT2H/``6:)1PC#9F9FD&9FD&9FD&:#?P@`#Y3`
+M#[;`PY"0D)!(BP](.<]U"+D`````ZP^02(L12(M!"$B)0@A(B1!(B<C#9F9F
+MD&9F9I!F9I!F9I!!B="$TG0Z#[8'.@9U*$B)\;X`````ZQ0/ME<!#[9!`4B#
+MQP%(@\$!.,)U"H/&`40XQG7DZPNX`````&9FD&:0P[@!````PV9FD&9FD&9F
+MD,9'`0!`B'<"QT<$`````,-!B=`/ME<!#[;"2(T$0$C!X`)(B<%(`T\(@\(!
+MB%<!1`%'!+@`````Q@0(`$B#P`%(@_@,=?)(B3%$B$$(3(G"#[;&B$$)1(G"
+MP>H0@^(_#[9!"H/@P`G0B$$*PV9F9I`/MD<!.@</DL`/ML##9F:02(GYN```
+M``"`>0+_=0AFB3&(40+K#8/``4B#P01F/8``=>4/M\##9F:09F:09F:008G0
+M#[?&2(T$AX!X`O]U$&9$B0"(2`(/M\;#9F:09I`/MM%!#[?PZ``````/M\##
+M2(GYN``````X40)U$V8Y,74.QD$"_V;'`?__ZQ!F9I"#P`%(@\$$9CV``'7;
+M#[?`PV9F9I!F9F:09F9FD&9FD+D`````B<@X5(\"=09F.32/=!"#P`%(@\$!
+M2('Y@````'7B#[?`PV9FD&9FD&9FD`^V1S@\"'0^/"AT.CRH#X3_````/(@/
+MA#D!```\"F:0="0\*G0@/*H/A.4````\B@^$'P$``#PO=`P\CV9F9I`/A90!
+M```\+P^$D@```#PO=R(\"G1?/`IW"CP(9F9FD'5$ZU$\*'1X/"IF9I!F9I!U
+M-.ML/(\/A-D````\CV:0=Q4\B`^$RP```#R*9F9FD'44Z;X````\J&9F9I!F
+M9I!T<3RJ=&VY`````+@`````Z1,!```/MD<ZP>`(#[97.PG0#[97.8/B'\'B
+M$`G0B<$/MD<\Z>\```!F9F:09F:0#[97.L'B&`^V1SO!X!`)P@^V1ST)P@^V
+M1SS!X`B)T0G!#[9'/\'@"`^V5T`)T.FU````#[97.L'B&`^V1SO!X!`)P@^V
+M1ST)P@^V1SS!X`B)T0G!#[97/L'B&`^V1S_!X!`)P@^V1T$)P@^V1T#!X`@)
+MT.MS#[97.DC!XC@/MD<[2,'@,$@)P@^V1T%("<(/MD<\2,'@*$@)P@^V1SU(
+MP>`@2`G"#[9'/DC!X!A("<(/MD<_2,'@$$@)P@^V1T!(P>`(2(G12`G!#[97
+M0L'B&`^V1T/!X!`)P@^V1T4)P@^V1T3!X`@)T$B)CX@```")AY````!F@T\B
+M`?/#9F9FD$B#[%A$#[9//$0/MD<[#[9/.@^V5SD/MG<X#[9'1XE$)%`/MD=&
+MB40D2`^V1T6)1"1`#[9'1(E$)#@/MD=#B40D,`^V1T*)1"0H#[9'08E$)"`/
+MMD=`B40D&`^V1S^)1"00#[9'/HE$)`@/MD<]B00D2,?'`````+@`````Z```
+M``!(@\18PV9FD&9FD&9FD$B#[`@/MD8!B$<!#[9&`HA'`HM&!(E'!$B+1P@/
+MME<!2(T44DC!X@)(BW8(2(G'Z`````!(@\0(PV9F9I!F9I!(BT]@#[976+@`
+M````9F:0Q@0X`$B#P`%(/;````!U\$B)3V"(5UC#9F9FD&9F9I"X`````+K_
+M____9F:09F:0B!0X2(/``4@]``(``'7Q\\-F9F:09F9FD&9F9I!F9I"Y````
+M`$@[/W022(M/"$B+$4B+00A(B4((2(D02(G(PTB+#XN1!`$``(G0)7[__O^)
+M@00!``"!XG[_\O](BT<(B1!(BT<(B5`,2(L'BX!4`0``B04`````)?X`__](
+MBQ>)@E0!``##9F:09F:09F:0B?%(BP>+D`0!``")%0`````/MT<\9CV`9'0,
+M9CV`D70&9CV`E'41#[;)@\$(N`$```#3X`G"ZQ!`#[;.@\$,N`$```#3X`G"
+M2(L'B9`$`0``PV9F9I!F9F:09F:09F:0B?%(BP>+D`0!``")%0`````/MT<\
+M9CV`9'0,9CV`D70&9CV`E'41#[;)@\$(N/[____3P"'"ZQ!`#[;.@\$,N/[_
+M___3P"'"2(L'B9`$`0``PV9F9I!F9F:09F:09F:0B?%`@/[_=&]`@/X?=S*+
+MMQ@!``"Z`0```-/BB=#WT"'PB8<8`0``BX=8`0``B04`````(=!T0(F'6`$`
+M`,-FD(NW'`$```^VP8/H(+H!````B<'3XHG0]]`A\(F''`$``(N'8`$``(D%
+M`````"'0=`:)AV`!``#SPV9F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL
+M)"!(B=6)\$R++T"`_@,/AHD```!(C1S%`````('C^`<``$V-I!T``@``0<<$
+M)`P!``"_$"<``.@`````28V<'00"```/ME4#P>(8#[9%`L'@$`G"#[9%``G"
+M#[9%`<'@"`G"B1-!QP0D$`$``+\0)P``Z``````/ME4'P>(8#[9%!L'@$`G"
+M#[9%!`G"#[9%!<'@"`G"B1/IA````$B-',4`````@>/X!P``3HVD*P`"``!!
+MQP0D#`$``+\0)P``Z`````!*C9PK!`(```^V50/!XA@/MD4"P>`0"<(/MD4`
+M"<(/MD4!P>`("<*)$T''!"00`0``OQ`G``#H``````^V50?!XA@/MD4&P>`0
+M"<(/MD4$"<(/MD4%P>`("<*)$TB+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-(
+M@^P82(E<)`A,B60D$$F)_$`/MMZ)WN@`````OQ`G``#H`````(G>3(GGZ```
+M``!(BUPD"$R+9"002(/$&,.005=!5D%505154TB#[%A)B?^(5"172(L7@'\^
+M``^$/`(``$&\`````$&]X/___T&^\/___T`/ML9(B40D2$B-@H`!``!(B40D
+M0$B-BH0!``!(B4PD.$B-@J`!``!(B40D,$B-BJ0!``!(B4PD*$B-@E`"``!(
+MB40D($B-BE0"``!(B4PD&$B-@N`!``!(B40D$$B!PM`!``!(B50D"&9FD$B+
+M1"1(1(GA2-/XJ`$/A(T!``!$B>6#_0-V%T2)ZD@#5"0HBP*)!0````"#X/Z)
+M`NL;C13M`````(G22`-4)#B+`HD%`````(/@_HD"OQ`G``#H`````(!\)%<`
+M='*#_0-V%T2)\D@#5"00BP*)!0````"#R`*)`NL;C12M`````(G22`-4)`B+
+M`HD%`````(/(`HD"1(GP2(M,)!!(`<&-!*T`````B<!(BU0D"$@!PH/]`W8*
+MBP&)!0````#K"(L"B04`````J`)T=.OC9I"#_0-V+T2)ZTB+1"0@2`'8QP``
+M````OQ`G``#H`````$@#7"08BP.)!0````"#R`&)`^M!C1SM`````(G;2(M$
+M)"!(`=C'``````"_$"<``.@`````2`-<)!B+`XD%`````(/(`8D#ZS=F9F:0
+M9F:0@_T#=BM$B>I(BT0D,$@!T,<``0```$@#5"0HBP*)!0````"#R`&)`NLV
+M9F:09F:0C03M`````(G`2(M4)$!(`<+'`@$```!(`T0D.(L0B14`````@\H!
+MB1!F9F:09F:008U4)`%)@\0!08/%"$&#Q@1!#[9'/CG0#X="_O__2(/$6%M=
+M05Q!74%>05_#9F:055-(@^P(B=%(BR^#_@-V((T$]>#___^)P$B-E`6@`0``
+MBP*)!0````"#X/Z)`NL>C03U`````(G`2(V4!8`!``"+`HD%`````(/@_HD"
+MA,ET?H/^`W8@C02U\/___XG`2(V4!>`!``"+`HD%`````(/(`HD"ZQZ-!+4`
+M````B<!(C90%T`$``(L"B04`````@\@"B0*-%+4`````C4+PB<!(C8P%X`$`
+M`(G22(V4%=`!``"#_@-V"HL!B04`````ZPB+`HD%`````*@"='7KXX/^`W8X
+MC1SUX/___XG;2(V$*U`"``#'``````"_$"<``.@`````2(V<*U0"``"+`XD%
+M`````(/(`8D#ZS:-'/4`````B=M(C80K4`(``,<``````+\0)P``Z`````!(
+MC9PK5`(``(L#B04`````@\@!B0-(@\0(6UW#D)"0D)"028G09H%^..$!=14/
+MMD8Z@^@10;D`````/`%V-V9F9I!(BS],BX]("```#[=&(+K8)@$`9CV#`'<7
+M#[?`#[:$!W@'``!(C13`2(T4D$C!X@-)`=%!QD`$!4&`8`7^08`@W[@`````
+M9H%^..$!=1(/MD8Z@^@!/`$/EL`/ML!F9I")PL'B!T$/M@"#X#\)T$&(`/:&
+ME@````%U!69!B4@(00^W0`B(1B5F@7XXX0%U(0^V5CJ-0O\\`7<)#[96.X/B
+M#^LAC4+ON@\````\`785D+H`````28-Y6`!T"$$/ME%Q@^(/00^V`(/@\`G0
+M08@`PV9F9I!F9F:09F9FD&9FD$B)^4B+/P^W@<@,``"#P`%FB8'(#```9CN!
+MS`P``'()9L>!R`P`````#[>!R`P``$C!X`)(`X&`"P``BQ:)$`^W@<@,``")
+MARP!``##9F:008G0N`````#&!`@`2(/``4B#^`1U\HGR9H'B_P\/MP%F)0#P
+M"=!FB0$/ME<,P>(,BP$E_P_P_PG0B0$/MD<*@^`"2(/X`1G2@^("@\(!P>(%
+M#[9!`X/@'PG0@\@0@^#WB$$#]D<*`7071(G"@^)_P>($#[=!`F8E#_@)T&:)
+M00+SPV9F9I!F9F:09F:09F:0N`````#&!#``2(/``4B#^`UU\@^V1SF(!@^V
+M1SJ(1@$/MD<[B$8"#[9'/(A&`P^V1SV(1@0/MD<^B$8%#[9'/XA&!O:'E@``
+M``1T(P^V1T"(1@@/MD=!B$8)#[9'0HA&"@^V1T.(1@L/MD=$B$8,N`$```##
+M9F9FD&9F9I!F9I"Z`````$&Z`````$&Y_____^M2`=)$B<#3^*@!=!+WP@``
+M``%U&H'R=R?;`.L29I")T#5W)]L`]\(````!#T70@^D!1#G)=<M)@\(!28/Z
+M"'43B=#!Z!"(!XG0P>@(B$<!B%<"PT4/M@0RN0<```#KHF9F9I!F9F:09F9F
+MD&9FD`^W]DC!Y@-(`[>8"```2(L.2(7)=#-(BQ</MT$R9L'H!0^WP(T$A0`#
+M``")@G`!``!(BQ</MTDR@^$?N`$```!(T^")@G0!``#SPV9FD&:0\\-F9F:0
+M9F9FD&9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($F)_(GU1`^V[DR)
+MZ4C!X01,B>A(P>`'2"G(2(V$!P`-``#'0`@`````A-(/A"H"``!`@/X#=D%(
+MC1SM`````('C^`<``$B+!T@%``(``$@!V,<`(````+\0)P``Z`````!)BP0D
+M2`4$`@``2`'#BP.)!0````#K/TB-'.T`````@>/X!P``2(L'2`4``@``2`'8
+MQP`@````OQ`G``#H`````$F+!"1(!00"``!(`<.+`XD%`````,'H$(3`>2I`
+M#[;%00^V="1!C32P2,?'`````+@`````Z`````"X`````.G^`0``9I!`@/T#
+M#X:F````2(T<[0````"!X_@'``!)BP0D2`4``@``2`'8QP`L````OQ`G``#H
+M`````$F+!"1(!00"``!(C00#BQ")%0````!,B>E(P>$$3(GH2,'@!T@IR('B
+M_P```$&)E`0(#0``28L$)$@%``(``$B-!`/'`"0```"_$"<``.@`````28L$
+M)$@%!`(``$@!PXL#B04`````B<&!X?___P#IH0```&9FD&9FD$B-'.T`````
+M@>/X!P``28L$)$@%``(``$@!V,<`+````+\0)P``Z`````!)BP0D2`4$`@``
+M2(T$`XL0B14`````3(GI2,'A!$R)Z$C!X`=(*<B!XO\```!!B90$"`T``$F+
+M!"1(!0`"``!(C00#QP`D````OQ`G``#H`````$F+!"1(!00"``!(`<.+`XD%
+M`````(G!@>'___\`3(GH2,'@!$R)ZDC!X@=(*<*)R,'@"$$)A!0(#0``N`$`
+M``#IB0```$`/MLZ)R,'@"$AC\$B)\D@#ER`+``"+`HD%`````,'H$(3`>1\/
+MMG=!C32Q2,?'`````+@`````Z`````"X`````.M%BTH,B0T`````3(GJ2,'B
+M!$R)Z$C!X`=(*=!(C90'``T``(E*"$B)\$@#AR`+``"+0`2)!0````#!X`@)
+MR(E""+@!````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9F9I!F9F:09F:0
+M05=!5D%505154TB#[`A(B?U)B?>`?T,`="6Y`````/9&#`%T#NL800^V1PQ(
+MT_BH`74,@\$!#[9%0V8YR'?H28M'*$B%P'0<2(VPN````$B+?2CH`````$F+
+M=RA(B>_H`````$F-1T!).4=`#X1*`0``2(D$)$B+/"3H`````$F)Q$B#>$``
+M#X01`0``@'AS`'1P9H-]9`!T:4&^`````$&]`````$B+A9@(``!,`>A(BQA(
+MA=MT.@^W0R!F03M$)#AU+F8]@P!W*`^WP("\!7@'``#_=!O&0R0A#[=S,DB)
+M[^@`````2(G>2(GOZ`````!!@\8!28/%"`^W161$.?!_HTF+1"1`2,=`:```
+M``!!]D0D3`1U&DB)[^@`````28MT)$"Z`0```$B)[^@`````28M4)$`/MH++
+M````C02`#[92`@'02)@/MH@`````#[95.@^V=3E(Q\<`````N`````#H````
+M`$F+5"1`2(NU``@``+\!````Z`````!)BU0D0$B+M0`(``"_!@```.@`````
+M2<=$)$``````08!O#0%,B>9(B>_H`````$B+!"1).4=`#X6Z_O__2<='*```
+M``!(BT4`BY!8`0``B14`````A=)T"DB+10")D%@!``!(@\0(6UU!7$%=05Y!
+M7\-F9F:09F9FD&9F9I!F9I!!5T%6055!5%532(/L*$B)_4B+!XN(4`$``(D-
+M`````$B+%XG()?#__P")@E`!``#WP0#__P`/A.4'``"`?4,`#X3;!P``QD0D
+M$`")R4B)3"0(1`^V;"0008U-"$B+1"0(2-/XJ`%U%$&-31!(BT0D"$C3^*@!
+M#X22!P``@'PD$`-V+4B+10!(!8`!``!"C13M`````$ACTD@!T(L`B04`````
+MP>@3@^`!ZRMF9I!FD$B+10!(!8`!``!"C13M`````$ACTD@!T(L`B04`````
+MP>@3@^`!A,!T-KH`````1(GN2(GOZ`````"$P'0B26/%2(G"2,'B!$C!X`=(
+M*="!C`4$#0`````(`&9FD&9FD$B+50"`?"00`W8E0HT$[0````!(F$B-A`*`
+M`0``BP")!0`````E```!`.LC9F9FD$*-!.T`````2)A(C80"@`$``(L`B04`
+M````)0```0"%P'1=@'PD$`-V'4*-!.T`````2)A(C80"@`$``,<````!`.G)
+M!@``0HT$[0````!(F$B-A`*``0``QP````$`Z:P&``!)8\5(B<)(P>($2,'@
+M!T@IT(&,!00-``````$`@'U+`0^%.@4``(!\)!`#=B5(BT4`2`6``0``0HT4
+M[0````!(8])(`="+`(D%`````(/@`>LC2(M%`$@%@`$``$*-%.T`````2&/2
+M2`'0BP")!0````"#X`&$P`^$80$``$ECW4B)V$C!X`1(P>,'2"G#2(VT'1`-
+M``!(BWTHZ`````!(B[P=X`P``$B%_W0=2(M'*$B%P'04]D!*`G4.D.@`````
+MA,`/A14!``!)8\5(B<)(P>($2,'@!T@IT$B+A`7@#```2(7`='9)B<:`>`T`
+M#X2,````0;\`````3(U@0$R)Y^@`````2(G#28M$)`A)B5PD"$R)(TB)0PA(
+MB1CV0TP"=2Y(BU-`2(72=!5(B[4`"```OP4```#H`````(!+3`)(B=J^!@``
+M`$R)]^@`````08/'`44X?@UV)>NA#[9T)!"Z`0```$B)[^@`````OZ"&`0#H
+M`````+X`+3$!ZP6^0$M,`$ECU4B)T$C!X`1(P>('2"G"2(T,*HFQ$`T``$C'
+M@2`-````````#[9$)!!(B<9(P>8$2,'@!T@I\$B-A`70#```2(F!*`T``$B-
+MM!40#0``2(M]*.@`````@'PD$`-V/4*-%.T`````2&/22(M%`$@%@`$``$@!
+MT(L`B04`````2(M%`$@%@`$``$@!PHL"B04`````P>@'@^`!ZSM"C13M````
+M`$ACTDB+10!(!8`!``!(`="+`(D%`````$B+10!(!8`!``!(`<*+`HD%````
+M`,'H!X/@`83`='N`?"00`W8W0HT,[0````!(8\E(BT4`2`6$`0``2`'(BP")
+M!0````!(BU4`2('"A`$``$@!T0T```$`B0'K1$*-#.T`````2&/)2(M%`$@%
+MA`$``$@!R(L`B04`````2(M5`$B!PH0!``!(`=$-```!`(D!ZS9F9I!F9I"`
+M?"00`W8I2(M%`$@%@`$``$*-%.T`````2&/22`'0BP")!0````#!Z!*#X`'K
+M)Y!(BT4`2`6``0``0HT4[0````!(8])(`="+`(D%`````,'H$H/@`83`#X0F
+M`@``#[9-04&-3(T`#[95.@^V=3E(Q\<`````N`````#H`````(!\)!`#=C="
+MC0SM`````$ACR4B+10!(!8`!``!(`<B+`(D%``````T```0`2(M5`$B!PH`!
+M``!(`=&)`>LU0HT,[0````!(8\E(BT4`2`6``0``2`'(BP")!0`````-```$
+M`$B+50!(@<*``0``2`'1B0%)8\5(B<)(P>($2,'@!T@IT$B+A`7@#```2(7`
+M=!!(@W@H``^%I````.EC`0``@'PD$`-V2D*-%.T`````2&/22(M%`$@%@`$`
+M`$@!T(L(B0T`````2(M%`$@%@`$``$B-!`*)"$B+10!(!8`!``!(`<*+`HD%
+M`````.DO`@``0HT4[0````!(8])(BT4`2`6``0``2`'0BPB)#0````!(BT4`
+M2`6``0``2(T$`HD(2(M%`$@%@`$``$@!PHL"B04`````Z>4!``!F9F:03(M@
+M*$'V1"1*`@^$D@```,9$)!``08!\)#H`=$/&1"00``^V1"0028M<Q%A(A=MT
+M'DB+4T!(A=)T%4B+M0`(``"_!0```.@`````@$M,`H!$)!`!#[9$)!!!.$0D
+M.G?"28V<)+@```!(BWTH2(G>Z`````!!QX0DN````$!+3`!)QX0DR```````
+M``!-B:0DT````$B+?2A(B=[H`````.LB#[9-04&-3(T`#[95.@^V=3E(Q\<`
+M````N`````#H`````(!\)!`##X:"````#[9<)!!(P>,#@>/X!P``2(M%`$@%
+M@`$``$@!V(L0B14`````2(M%`$@%@`$``$B-!`.)$$B+10!(!8`!``!(C00#
+MBP")!0````!(BT4`2`4P`@``2(T$`\<``````+\0)P``Z`````!(BT4`2`4T
+M`@``2`'#BP.)!0````#I?0````^V7"002,'C`X'C^`<``$B+10!(!8`!``!(
+M`=B+$(D5`````$B+10!(!8`!``!(C00#B1!(BT4`2`6``0``2(T$`XL`B04`
+M````2(M%`$@%4`(``$B-!`/'``````"_$"<``.@`````2(M%`$@%5`(``$@!
+MPXL#B04`````@$0D$`$/MD0D$#A%0P^',?C__TB+10"+B%`!``")#0````!(
+MBU4`B<@E\/__`(F"4`$``/?!`/__`'0CZ>'W__^0N@$```!$B>Y(B>_H````
+M`(3`#X4\^?__Z5/Y__^X`````$B#Q"A;74%<05U!7D%?PV9F9I!F9F:09F9F
+MD&9FD$%455-(B?M,BR>`?SH`="V]`````$`/ML5(BU3#6$B%TG012(N[@```
+M`+XA````Z`````"#Q0%`.&LZ=]A(B[N`````N@````"^(0```.@`````9L=#
+M2B$`QD-"$4B)WDR)Y^@`````6UU!7,-F9I!!5T%6055!5%532(/L"$B)_4R+
+MIX````!-BRPD00^V1"0+J!!T"<9'30;I)P$```^V5TV`^@1T#H#Z!@^%A`$`
+M`.D0`0``@^#W@\@008A$)`N+E^P```"-0@&)A^P```"#^@(/A^T```!)BX6P
+M````2(EP"$B)!DF-A;````!(B48(28FUL````(!_0@!T#;L`````@'\Z`'4;
+MZSM!O@````!-C7PD0$&`?"0-`'4_D.F1````#[;#2(M4Q5A(A=)T#;XA````
+M3(GGZ`````"#PP$X73IWWKH`````OB$```!,B>?H`````.G7````3(G_Z```
+M``!(B<-)BT0D2$F)7"1(3(D[2(E#"$B)&$B+4T!(A=)T%4F+M0`(``"_!0``
+M`.@`````@$M,`DB)VKX&````3(GGZ`````!!@\8!13AT)`UWJ/9%2@)T>4B)
+M[^@`````ZV]!@&0D"_?'A>P`````````28N%L````$B)<`A(B09)C86P````
+M2(E&"$F)M;````"`?3H`=">[``````^VPTB+5,582(72=`V^!@```$R)Y^@`
+M````@\,!.%TZ=]ZZ`````+X&````3(GGZ`````!(@\0(6UU!7$%=05Y!7\-F
+M9F:09F9FD&9F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL)"!)B?Q(B?-)B=4/
+MMW8X9H'^X0%U%`^V0SJ#Z!$\`0^&%0$``&9FD&:0#[=#(+G_````9CV#`'<,
+M#[?`00^VC`1X!P``#[?!2(T4P$B-%)!(P>(#2(G520.L)$@(``!F@?[A`74+
+M#[9#.H/H`3P!=BEF@?G_`'0&]D5+!'4<QD,D!D''10``````N`$```#IJP``
+M`&9FD&9FD`^V14BH`71XJ`1T=$$/MDPD1$$/MD0D23C!<B8/MM`/MO%(Q\<`
+M````N`````#H`````$''10`!````N`$```#K8TB)WDB)[^@`````A,!U$\9#
+M)"%!QT4``````+@!````ZT&`?7,?=A9!QT4``0```+@!````ZRQF9F:09F:0
+M28V\)!@*``#H`````(3`=`]!QT4``0```+@!````ZP6X`````$B+7"0(2(ML
+M)!!,BV0D&$R+;"0@2(/$*,-FD$%7059!54%455-(@^Q828G\2(GU2(N?4`L`
+M`&;'1C+_#TB-5"0LZ`````"$P'0)BT0D+.D%!```#[=-(+__````9H'Y@P!W
+M#`^WP4$/MKP$>`<```^W=3AF@?[A`74/#[9%.H/H$3P!#X:E````9H'Y@P!W
+M40^WP4$/MH0$>`<``#S_=$%F@_E_=QX/MM!)BXPD2`@``$B-!-)(C02"2(M$
+MP5`/MD`(ZR(/ML!)BY0D<`@``$C!X`A(BX00@`````^V0`CK!;C_____#[;`
+M00^VA`3\!P``2(G"2,'B!TB-A,)0`0``28U$!`A(B40D$`^WQTB-%,!(C120
+M2,'B`TF)UTT#O"1("```9H'^X0%U/.LH#[?'2,'@"$D#A"1P"```2(E$)!A(
+MBX"`````2(E$)!!!OP````#K-P^V53J-0N\\`78CC4+_/`%V'&:!__\`=`=!
+M]D=+!'4.QD4D!K@`````Z=0"``!(QT0D&`````!(C70D2$R)Y^@`````08G&
+M9HE%,DR+;7@/M]!(B50D"$AIPK`$``!(C1P82(U#($DKA"10"P``20.$)%@+
+M``!(BU0D2(E"($C!Z"!(BU0D2(E")$F+11A(BU0D2(E"*$C!Z"!(BU0D2(E"
+M+$B+1"1(9D2)<`BX`````&9F9I#&!!@`2(/``4@]L`0``'7P9H%]..$!=5@/
+MMD4Z@^@1/`%W34B-3"0P2(M$)$@/ME`(2(GN3(G_Z`````!(C8,@!```22N$
+M)%`+``!)`X0D6`L``$B+5"1(B4(02,'H($B+5"1(B4(4Z98```!F9F:02(M$
+M)!#V0`H!#X2#````]H66````('0/2(UT)#!(B>_H`````.L92(U,)#!(BT0D
+M2`^V4`A(B>Y,B?_H`````$B-@R`$``!)*X0D4`L``$D#A"18"P``2(M4)$B)
+M0A!(P>@@2(M4)$B)0A1(B=A)*X0D4`L``$D#A"18"P``2(M4)$B)0AA(P>@@
+M2(M4)$B)0AP/ME592(M$)$AFB5`"@'U9`'0ROP````")^$B-!$!(P>`"28MU
+M$$B+36!(BQ0(2(D4!HM4"`B)5`8(@\<!#[9%63GX=].+531(BT0D2(E0#$4/
+MM^Y(BU0D2$2)Z4B)[DB+?"00Z`````!(C4PD,$B)VDB)[DR)Y^@`````28N$
+M))@(``!(BU0D"$B)+-!$B?)FP>H%@>+_!P``1(GI@^$?N`$```!(T^!!"824
+MH`@``&:!?3CA`74^#[9%.H/H$3P!=S-(BW0D&$R)Y^@`````2(U,)$!(BT0D
+M&`^V4$Q$B>Y(BWPD$.@`````@ST``````G4DZU!,B?Y,B>?H`````$B-3"1`
+M00^V5V9$B>Y(BWPD$.@`````2(UT)$!,B>?H`````$B+<R!(A?9T&$C'QP``
+M``"X`````.@`````N`,```#K!;@#````2(/$6%M=05Q!74%>05_#9F9FD$%4
+M55-(B?U,C:>P````Z0T!``!,B>?H`````$B)PP^V4"!FB5`@9H/Z?W849H%X
+M..$!=2,/MD`Z@^@1/`%W&)!F@?J#`'<0#[?"#[:4!7@'``"`^O]U&<9#)`9(
+MB=Y(B>_H`````.FU````9F:09I!F@7LXX0%U&`^V2SJ-0>\\`0^'J````.LW
+M9F9FD&9FD`^VPDB-%,!(C1202,'B`TB)T$@#A4@(``#V0$L$=1'&0R0&2(G>
+M2(GOZ`````#K8$B)WDB)[^@`````@_@"9I!W!X/X`7,;ZPN#^`-F9F:0=3[K
+M,$B)WDB)[^@`````D.LN2(V5L````$B+A;````!(B5@(2(D#2(E3"$B)G;``
+M``#K/4B)WDB)[^@`````D$PYI;`````/A>;^___K(DB+M4@(``"-0?\\`7:#
+M#[;"2(T4P$B-%)!(C036Z5C___];74%<PV9F9I!F9I!F9I!(@^PX2(E<)`A(
+MB6PD$$R)9"083(EL)"!,B70D*$R)?"0P2(G]3(MG4$V++"2[`````&:!?CCA
+M`746#[9&.H/H`3P!#Y;`#[;89F9FD&9FD`^VA<`````\!'0-/`8/A24"``#I
+MR`$``,:%P@````!(BTU`2(7)=1L/MI4A`0``C4(!B(4A`0``@/H"#X>?`0``
+MZQ*+402-0@&)002#^B@/AXL!``!)BX6P````2(EP"$B)!DF-A;````!(B48(
+M28FUL````,9&)(!(B>J^(0```$R)Y^@`````A=L/A:<!``"`?4K_=#9(BU58
+M2(729I`/A)(!``"`>D(`="'V0DH"#X2"`0``#[9-<;@!````T^`)0E"`34P0
+MZ6L!``!!#[9$)`N#X/>#R!!!B$0D"T&`?"0-`'130;X`````38U\)$!,B?_H
+M`````$B)PTF+1"1(28E<)$A,B3M(B4,(2(D82(M30$B%TG0528NU``@``+\%
+M````Z`````"`2TP"08/&`44X="0-=[A(BU582(72=2W&14H#9L>%N```````
+M2(GJOB$```!,B>?H`````$B)[DR)[^@`````Z<D```#V0DH"#X2_````#[9-
+M<;@!````T^`)0E"`34P02(MU6$B!QK@```!)BWTHZ`````!(BT58QX"X````
+M@(0>`$B+15A(QX#(`````````$B+15A(B8#0````2(MU6$B!QK@```!)BWTH
+MZ`````#K6V9FD`^V74I!@&0D"^])BX6P````2(EP"$B)!DF-A;````!(B48(
+M28FUL````$B)ZKX&````3(GGZ`````"`^_]U$4B)ZDR)YDR)[^@`````9F:0
+M3(GOZ`````!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(@\0XPV9F
+MD&:005=!5D%505154TB#[`A(B?U)B?=(BX]("```#[=&(+K8)@$`9CV#`'<7
+M#[?`#[:$!W@'``!(C13`2(T4D$C!X@-,C2013(GF2(GOZ`````!,B>9(B>_H
+M`````$$/MW<R2(GOZ`````!!#[=W,DB)[^@`````9D''1S+_#TF+%TF+1PA(
+MB4((2(D008!L)',!38UL)"!-.6PD('163(VUL````$R)[^@`````2(G##[=P
+M,DB)[^@`````#[=S,DB)[^@`````9L=#,O\/08!L)',!2(N%L````$B)6`A(
+MB0-,B7,(2(F=L````$TY;"0@=;%!QH0DP`````1,B?Y,B>?H`````+@!````
+M2(/$"%M=05Q!74%>05_#9F:09F:02(/L:$B)7"0X2(EL)$!,B60D2$R);"10
+M3(ET)%A,B7PD8$B)5"0H3(LG#[?V2,'F`TD#M"28"```2(LN9H%]..$!=2X/
+MMD4Z@^@1/`%W(TB+5RA$#[9Z3$&^`````$B#?"0H`'5AQD)-`$&^`````.M5
+M28N,)$@(``"XV"8!`&:!?2"#`'<=#[=%($$/MH0$>`<``$B-%,!(C1202(T$
+MU0````!,C30!10^V?F:Z`````$B#?"0H`'4-0<:&P`````"Z`````(!])(%U
+M!(!G"_=(@WPD*``/A7,!``#&120`@ST``````7479H%]..$!=0\/MD4Z@^@1
+M/`%W!,9%)"'VA98````@#X1"!```2(M%:$B%P`^$-00``$B)P_:`L0````)T
+M'4B+N*````!(A?]T$4B+=4A(A?9T"(M5-.@`````28N4)"`+``!(@<)`"```
+M00^V1F;!X`A(F$@!PHL"B04`````B<+!ZA"(DYL```#!Z!AFB8.0````28N4
+M)"`+``!(@<)$"```00^V1F;!X`A(F$@!PHL2B14`````#[;"9HF#E`````^V
+MQF:)@Y8```")T,'H$`^VP&:)@Y@```#!ZAB(DYH```!)BY0D(`L``$B!PDP(
+M``!!#[9&9L'@"$B82`'"BP*)!0`````/ML!FB8.2````28N4)"`+``!(@<)(
+M"```00^V1F;!X`A(F$@!PHL"B04`````B<+!X@AF"9.4````B<*!X@#_``!F
+M"9.6````P>@()0#_``!F"8.8````Z0(#``!FD`^W13)(:<"P!```38NL)%`+
+M``!)`<5)C9T@!```@'TD@'4$QD4D(4V%]@^$D0```$F+5D!(A=)T0`^V@LL`
+M``"-!(`/ME("`=!(F`^VB`````!!#[94)#I!#[9T)#E,BT0D*$C'QP````"X
+M`````.@`````Z8<```!(BU<@00^V1"1!#[92"(T$@HT$@$$/ME9Q`=!(F`^V
+MB`````!!#[94)#I!#[9T)#E,BT0D*$C'QP````"X`````.@`````ZS](A=)T
+M.DB+1R!!#[9,)$$/MD`(C0R(00^V5"0Z00^V="0Y3(M$)"A(Q\<`````N```
+M``#H`````&9F9I!F9I"+2PB+4P2+,T2+0PQ(Q\<`````N`````#H`````$'V
+M12(!=1-!@'TG`'D,#[=U,DR)Y^@`````#[9$)"NH`0^$7`$``$R)^DC!X@B!
+MX@#_``!)BX0D(`L``$@%0`@``$@!T(LPB34`````08GW0<'O$(GPP>@8B$0D
+M$$F+A"0@"P``2`5$"```2(T$`D2+*$2)+0````!)BX0D(`L``$@%2`@``$B-
+M!`*+&(D=`````$F+A"0@"P``2`5,"```2`'"1(LR1(DU``````^V1"00B00D
+M10^VST6)\(G91(GJ2,?'`````+@`````Z`````!F@7TXX0%U#P^V13J#Z!$\
+M`0^&^0```,9%)`+VA98````@=&E(BTUH1(BYFP````^V1"009HF!D````(G8
+MP>`(00^VU0'09HF!E````(G>0(#F`$R)Z`^VU(T$%F:)@98```")VL'J$,'B
+M"$2)Z,'H$`^VP`'"9HF1F````$$/ML9FB8&2````Z8,```!F@7TXX0%U"P^V
+M13J#Z!H\`79P2(GN3(GGZ`````#K8V9FD(3`>5Q!@/\?=RI)BP0DBY!8`0``
+MB14`````N`$```!$B?G3X"'"=#A)BP0DB9!8`0``ZRQ)BP0DBY!@`0``B14`
+M````00^VSX/I(+@!````T^`APG0*28L$)(F08`$``$B+7"0X2(ML)$!,BV0D
+M2$R+;"103(MT)%A,BWPD8$B#Q&C#9F9FD&9FD&9FD&9FD$%7059!54%455-(
+M@^P82(G]2(E\)`A$#[>OR@P``$B+A[`+``"+`(D%`````&8E_P]FB8?*#```
+M9D0YZ'4^2(L'BX!0`0``B04`````2(L7)?#__P")@E`!``"Z`````(7`#X1$
+M!```2(M\)`CH`````+H!````Z3`$``!F@;_*#```_P\/A:4#``#IO@,``$R+
+MA5`+``!!@\4!9D0[K<X,``"X`````$0/0^A(BY6P"P``2(/"!$$/M\6+#()!
+MB<E!P>D00?;!"`^$M@```$B+10"+B%`!``")#0````!(BU4`B<@E\/__`(F"
+M4`$``(7`=&V`?4,`=&>)SO?&``$``'4NOP````#WQ@```0!T1.L?#[?7C4H(
+M2(GP2-/XJ`%U%(U*$$B)\$C3^*@!=0?K([\`````#[?'2(G"2,'B!TB-A,)0
+M`0``2(U<!0A(A=MU'>L,@\<!#[9%0V8Y^'>R2(M\)`CH`````.G0`@``2(M\
+M)`CH`````(A##F9FD.F[`@``08G/9D&!Y_\/00^WQTAIT+`$``!-BT00($B-
+M-,4`````2(N%F`@``$@!\$B+&$B%VP^%QP```$$/M_>)\DC'QP````"X````
+M`.@`````9H-]9``/A&("``!!OP````!!#[;73(TTU0````!(BX68"```3`'P
+M2(LP2(7V=&I(:=JP!```2`.=4`L```^V3B5%#[;G1(GB2,?'`````+@`````
+MZ`````!,B?!(`X68"```2(LXZ`````"+BR0$``"+DR`$``!$BXLL!```1(N#
+M*`0``$2)YDC'QP````"X`````.@`````08/'`4$/ML=F.T5D#X/"`0``Z6'_
+M__](B?!(`X68"```2(L`#[=0(&:!^H,`=W@/M\(/MH0%>`<``#S_=&EF@_I_
+M=R`/ML!(C13`2(T4D$C!X@-(`Y5("```2(M"4`^V0`CK+TB)\$@#A9@(``!(
+MBP`/MT`@#[:$!7@'``!(P>`(2`.%<`@``$B+@(`````/MD`(//]T$`^VT$AC
+MPH"\!?P'``#_=1S&0R0&2(G?Z`````!(B=Y(B>_H`````.D1`0``2&/"#[:$
+M!?P'``!(B<)(P>('2(V$PE`!``!(C7P%"$V%P'0-0?;!`K@`````3`]$P/9'
+M"@(/A=8```!!#[?'B40D%$R)PHG&Z`````!(BX7`````2#D$)'180;P`````
+M08/$`4B+`$@Y!"1U\T6$Y'1`0;X`````2(L\).@`````2(U(\$B+-"1(BU8(
+M2(E&"$B),$B)4`A(B0)(.=FX`0```$0/1/!!@.P!=<M%A/9U7X![)(%T66:!
+M>S+_#V9FD'1.2(L$)$B+4`A(C4,02(L,)$B)00A(B4L02(E0"$B)`D2)^F;!
+MZ@6#XG^+3"04@^$?N`$```!(T^`)1)5HZQ!(C;?`````2(DT)&9FD&:09D0Y
+MK<H,```/A4+\__](C87`````2#F%P````'1!2(G#2(G?Z`````!(C7#P#[=.
+M,HG*9L'J!8'B_P<``(/A'[@!````2-/@]]`A1)5H2(GOZ`````!(.9W`````
+M=<)(B>_H`````+H!````B=!(@\086UU!7$%=05Y!7\-F9I!54TB#[`A(BY<`
+M"```2(M""(LHB2T`````]\4```"0=`9(BT((B2A(BY\`"```]\4```0`="M(
+MBP.+D%`!``")%0````"%TG082(L#B9!0`0``2(L#BX!0`0``B04`````]\4`
+M``@`=#=(@</`#@``2(L#BY!0`0``B14`````A=)T'4B+`XF04`$``$B+`XN`
+M4`$``(D%`````&9FD&:02(N[``@``+X`````Z`````!(BYL`"```2(G?Z```
+M``!(C;O`#@``Z`````!(B[L`"```O@$```#H`````(7M#Y7`#[;`2(/$"%M=
+MPV9F9I!!5T%6055!5%532(/L.$F)_D"(="0?1`^V[DECQ4B)PDC!X@1(P>`'
+M2"G02`'X2(NHX`P``$0/MKC:#```2(L'0(#^`W8,QX!P`0``Q`$``.L*QX!P
+M`0``J`$``$B)1"0P2`5T`0``2(E$)"!(BU0D,(N"=`$``(D%`````$2)Z8/A
+M`[L'````T^-!B=Q!"<1$B:)T`0``O^@#``#H`````/?31"'C2(M,)#")F70!
+M``"`?"0?`W970HT$K0````!(F$B-E`'0`0``BP*)!0````"#R`B)`D*-'.T`
+M````2&/;2(V$&0`"``#'`#@```"_$"<``.@`````2(M4)#!(C80:!`(``,<`
+M`````.M:0HT$K0````!(F$B+3"0P2(V4`=`!``"+`HD%`````(/("(D"0HT<
+M[0````!(8]M(C809``(``,<`.````+\0)P``Z`````!(BU0D,$B-A!H$`@``
+MQP``````2(7M#X27`P``08!^0P!T,+L`````9I`/MLL/MD4,2-/XJ`%T$KH!
+M````B<Y,B??H`````&9FD(/#`4$X7D-WU_9%"@%T<$B)[DR)]^@`````1(GN
+M3(GWZ`````!)8\5(B<)(P>($2,'@!T@IT$J-%#"+@@`-``"I```0`'0+)?__
+M[_^)@@`-``!(B>Y,B??H`````$ECQ4B)PDC!X@1(P>`'2"G02<>$!N`,````
+M````Z>H"``!(Q\#^____1(GI2-/`1"#XB$0D+P^%G@$``+H`````O@8```!(
+MB>_H`````$2)[DR)]^@`````26/%2(G"2,'B!$C!X`=(*=!*C10PBX(`#0``
+MJ0``$`!T"R7__^__B8(`#0``2(U%,$@Y13!U^DB-14!(.45`#X04`0``0;\`
+M````2(D$)$B+/"3H`````$F)Q(!X<P!T-4&-7P%!@?]_EI@`=R5,B??H````
+M`+\!````Z`````!!@'PD<P!T"X/#`8'[@9:8`'7;08G?28M$)$!(A<`/A)@`
+M``!(QT!H`````$'V1"1,!'4:3(GWZ`````!)BW0D0+H!````3(GWZ`````!)
+MBU0D0`^V@LL```"-!(`/ME("`=!(F`^VB`````!!#[96.D$/MG8Y2,?'````
+M`+@`````Z`````!)BU0D0$F+M@`(``"_`0```.@`````28M4)$!)B[8`"```
+MOP8```#H`````$G'1"1``````(!M#0%,B>9,B??H`````$B+%"1(.55`#X7V
+M_O__2(GN3(GWZ`````!)8\5(B<)(P>($2,'@!T@IT$G'A`;@#````````$&`
+M?D,`#X0G`0``0;\`````#[9,)"](B4PD$$B+1"0P2`70`0``2(E$)`A%B?U!
+M#[;O2(M$)!")Z4C3^*@!=0M$.'PD'P^%U0```$&`_0-V:$B+1"0PQX!P`0``
+MQ`$``$B+5"0@BP*)!0````")Z8/A`XT,2;L'````T^-!B=Q!"<1$B2*_Z`,`
+M`.@`````]]-$(>-(BTPD((D9C12M`````$ACTD@#5"0(BP*)!0````"#R`B)
+M`NMG2(M$)##'@'`!``"H`0``2(M4)""+`HD%`````(GI@^$#C0Q)NP<```#3
+MXT&)W$$)Q$2)(K_H`P``Z`````#WTT$AW$B+3"0@1(DAC12M`````$ACTD@#
+M5"0(BP*)!0````"#R`B)`D&#QP%!C44!03A&0P^'^?[__TB#Q#A;74%<05U!
+M7D%?PV9F9I!F9F:005154TF)_$B)]0^V=T-`A/9T)@^V50R[`````/;"`70.
+MZQ9(B=")V4C3^*@!=0^#PP%`./-U[.L%NP````#V10L"=0I(C45`2#E%0'5E
+M2(GOZ`````"$P'1.3(GGZ`````!(B<9(A<!T24B+54A(B45(2(U%0$B)!DB)
+M5@A(B3*`10T!2(EN4,9&2`7&1DD`QD9Q#[D!````N@$```!(B>_H`````.L+
+M#[;S3(GGZ`````!;74%<PV9F9I!F9F:0059!54%455-(B?U!B?5$#[;V0HT$
+MM0````!,8^"[`````+\0)P``Z`````!!@/T#=AY(BT4`2`70`0``3`'@BP")
+M!0````#!Z!2#X`'K'9!(BT4`2`70`0``28T$!(L`B04`````P>@4@^`!A,!U
+M"H/#`6:!^RP!=:A$B?9(B>_H`````$B)[^@`````26/&2(G"2,'B!$C!X`=(
+M*=!(`>CV@-D,```!=`](B[#@#```2(GOZ`````!;74%<05U!7L-F9F:09F9F
+MD&9FD&9FD$%6055!5%5308GU2(G]1`^V]DECQDB)PDC!X@1(P>`'2"G03(ND
+M!^`,``!-A>0/A`@!``!(Q\#^____1(GQ2-/`081$)`P/A?````!!@'PD#0`/
+MA.@!``!!O0````!)C5PD0$B)W^@`````2(G"2(M#"$B)4PA(B1I(B4((2(D0
+M@'I)``^%G@````^W0CA(@[S%>`,```!U!TB#>D``=',/MT(X2(N$Q7@#``!(
+M@[B``````'1&QH+```````^V2DA(B<B#X`9(@_@&=07VP0%U5@^V2DA(B<B#
+MX`9(@_@$=4;VP0%T0<9"2@/&0DL$2(G62(GOZ`````#K+$B+4D!(B[4`"```
+MOP0```#H`````.L5#[=2.$B+M0`(``"_`@```.@`````08/%`44X;"0-#X8)
+M`0``Z2?___]"C02U`````$QCX+L`````9F9FD+\0)P``Z`````!!@/T#=B!(
+MBT4`2`70`0``3`'@BP")!0````#!Z!2#X`'K'F9FD$B+10!(!=`!``!,`>"+
+M`(D%`````,'H%(/@`83`=0J#PP%F@?LL`76G1(GV2(GOZ`````!(B>_H````
+M`$ECQDB)PDC!X@1(P>`'2"G03(ND!>`,``!-A>1T9H!]0P!T++L`````#[;+
+M00^V1"0,2-/XJ`%T#[H`````B<Y(B>_H`````(/#`3A=0W?900^VQ4B)PDC!
+MX@1(P>`'2"G02(V$!=`,``!)B40D($'V1"0*`70-3(GF2(GOZ`````!FD%M=
+M05Q!74%>PV9F9I!F9I!(@^P(3(L'1(M/-$$/MG!#0(3V=&A)C8#0#```N0``
+M``!(.?AU(.M5#[;!2(G"2,'B!$C!X`=(*=!)C80`T`P``$@Y^'0(@\$!0#CQ
+M==J`^0-V+TF+`$@%T`$``$B-%(T`````@>+\`P``2`'0BP")!0````#!Z!2#
+MX`'K+;D`````28L`2`70`0``2(T4C0````"!XOP#``!(`="+`(D%`````,'H
+M%(/@`83`=!`/MO%$B<I,B<?H`````.L+#[;Q3(G'Z`````!(@\0(PV:04TB#
+M[&!(B?M(C4PD74B-5"1>2(UT)%\/MW\\2(U$)%)(B40D.$B-1"142(E$)#!(
+MC40D3$B)1"0H2(U$)$Y(B40D($B-1"182(E$)!A(C40D6DB)1"002(U$)%M(
+MB40D"$B-1"162(D$)$R-3"1<3(U$)%#H``````^V1"1?2(T4P$B-%)!(P>(#
+M2(MS($B-NR@(``"Y`0```.@`````#[94)%U(P>((2(MS($B-NU`(``"Y`0``
+M`.@`````#[=4)%A(P>(#2(MS($B-NW@(``"Y`0```.@`````#[=$)%!(C12`
+M2(T44$C!X@1(BW,@2(V[4`D``+D!````Z``````/ME0D7`^W1"102`^OT$B-
+M%%)(P>("2(MS($B-N^`(``"Y`0```.@`````2(MS($B-NP@)``"Y`0```+H`
+M`@``Z``````/ME0D6TC!X@5(BW,@2(V[>`D``+D!````Z`````!(BW,@2(V[
+MH`D``+D!````N@`!``#H``````^W5"162(T4DDC!X@-(BW,@2(V[R`D``+D!
+M````Z``````/MU0D6$@!TDB+<R!(C;OP"0``N0$```#H``````^V5"1?2`'2
+M2(MS($B-NR@*``"Y`0```.@`````#[94)%U(`=)(BW,@2(V[8`H``+D!````
+MZ``````/ME,^2`'22(MS($B-NY@*``"Y`0```.@`````#[=4)%A(P>(&2(MS
+M($B-N]`*``!!N`$```"Y0````.@`````2(MS($B-NP`+``!!N`$```"Y``$`
+M`+H`20``Z``````/MU0D6$AITK`$``!(BW,@2(V[,`L``$&X`0```+F`````
+MZ``````/MU0D5$C!X@)(BW,@2(V[8`L``$&X`0```+D$````Z``````/MU0D
+M4DC!X@)(BW,@2(V[D`L``$&X`0```+D$````Z``````/ME0D6\'B#$B+<R!(
+MC;O`"P``0;@!````N0@```#H`````$B+<R!(C;OP"P``0;@!````N0@```"Z
+M```(`.@`````#[=4)%9(:=*,`0``2(MS($B!PR`,``!!N`$```"Y"````$B)
+MW^@`````N`````!(@\1@6\-FD$B#[`A(BY>X````2(FWN````$B-A[````!(
+MB09(B58(2(DRZ`````!(@\0(PV9FD$%7059!54%455-(@^P82(G]2,=$)!``
+M````2(M$)!`/MI0H_`<``(#Z_P^$Z0````^VRDB)R$C!X`=(C83(4`$``$B-
+M1`4(2(E$)`@/MO)(8\9(B<)(P>('2(T$PH"\!64!````#X2N````0;P`````
+M2(G(2,'@!TB-!,A,C;0%F`$``$R-+"A(8\9(B<)(P>('2(T$PDR-O`50`0``
+M3(GWZ`````!(B<-)BX6@`0``28F=H`$``$R),TB)0PA(B1A(BU-`2(72=!5(
+MB[4`"```OP4```#H`````(!+3`)(B=J^(0```$B+?"0(Z`````"`>W,`=!A(
+MB>_H`````+\!````Z`````"`>W,`=>A!@\0!13AG%7>%2(-$)!`!2(-\)!`$
+M#X7O_O__2(GOZ`````!(@\086UU!7$%=05Y!7\-F9F:09F9FD&9FD&9FD$%7
+M059!54%455-(@^P828G]2(E\)!!,BV=028LL)$B+A;`+``!$BS!(B?Y(B>_H
+M`````$F-72!!OP````!).5T@=!Y(B=_H`````$F)QTF+12!,B7@(28D'28E?
+M"$V)?2!)BU5`2(72=$1!N/__``!-A?]T!44/MT<R#[:"RP```(T$@`^V4@(!
+MT$B8#[:(``````^V53H/MG4Y2,?'`````+@`````Z`````#K3$&X__\``$V%
+M_W0%10^W1S(/MD5!28M4)"`/ME((C02"C02`00^V57$!T$B8#[:(``````^V
+M53H/MG4Y2,?'`````+@`````Z`````!-A?\/A,H!``!%#[=G,DUIY+`$``!,
+M`Z50"P``28V<)"`$``!,B?_H`````(M+!$$/MW<R1(M+#$2+0PA!BY0D(`0`
+M`$C'QP````"X`````.@`````9H-]9``/A#T!``!!O`````!(C86P````2(E$
+M)`AF9F:000^WU$B+A9@(``!(BQS02(7;#X0``0``00^W?3AF.WL@#X7Q````
+M#[>5R@P``$$YUG1B#[>US@P``$B+C;`+``"#P@$Y\K@`````#T/0C4(!BP2!
+MJ0``"`!U-68E_P]F1#G@=2M).=]U*TB)[^@`````00^W=S)(Q\<`````N```
+M``#H`````.G0````9F:01#GR=:QF@?^#`&9FD&9FD'=V#[?'@+P%>`<``/]T
+M:4B#?"00`'1A00^V14BH`718J`1T5$PY^W0L2(L#2(M3"$B)4`A(B0)(BX6P
+M````2(E8"$B)`TB+1"0(2(E#"$B)G;`````/MW,R2(GOZ``````/MW,R2(GO
+MZ`````!FQT,R_P]!@&US`4&#Q`%F1#EE9`^'V?[__TB#?"00`'0N00^V14BH
+M`70EJ`1T(4'&A<`````$28L728M'"$B)0@A(B1!,B?Y,B>_H`````$B#Q!A;
+M74%<05U!7D%?PV9F9I!!5T%6055!5%532(/L:$B)^\9'2P#&1TH`QH>A#@``
+M`$B-E]`,``"X`````&9F9I#&!!``2(/``4@]P`$``'7P2(V#L````$B)@[``
+M``!(B8.X````2(V#P````$B)@\````!(B8/(````3(VCT````$R)H]````!,
+MB:/8````2(V#X````$B)@^````!(B8/H````3(V[\````$R)N_````!,B;OX
+M````2(V#``$``$B)1"1`2(F#``$``$B)@P@!``!,C;,0`0``3(FS$`$``$R)
+MLQ@!``!(C4PD7DB-5"1@2(UT)&$/MWL\2(U$)&)(B40D.$B-1"1D2(E$)#!(
+MC40D5$B)1"0H2(U$)%I(B40D($B-1"1F2(E$)!A(C40D7$B)1"002(U$)%U(
+MB40D"$B-1"182(D$)$R-3"1?3(U$)%;H``````^V1"1AB$-&#[9$)%Z(@ZL`
+M```/MT0D9F:)0V0/MT0D9&:)@\P,```/MT0D8H/H`6:)@\X,```/MT0D5F:)
+M0TP/MT,\9CV`D70*9CV`E`^%RP8``,9#2`3&0T,$QD-)0,9#1P#&@ZH````)
+MQD-$`$B-NR@(``#H`````$B)P4B)@T@(```/MD0D84B-%,!(C1202,'B`TB%
+MTG002(G(Q@``2(/``4B#Z@%U\TB-NU`(``#H`````$B)P4B)@W`(```/MD0D
+M7DB)PDC!X@A(A=)T$$B)R,8``$B#P`%(@^H!=?-(C;MX"```Z`````!(B<%(
+MB8.8"```#[=$)&9(C13%`````$B%TG002(G(Q@``2(/``4B#Z@%U\TB-NP@)
+M``#H`````$B)@R@)``!(C;O@"```Z`````!(B<5(B8,`"0``2(V[4`D``.@`
+M````2(G"2(F#<`D``&:#?"16`'1(N0````!(B6I@#[9$)%^(0EA(BX/8````
+M2(F3V````$R)(DB)0@A(B1`/MD0D7TB-!$!(C6R%`$B!PK````"#P0%F.4PD
+M5G>]2(V[>`D``.@`````2(G"2(F#F`D``(!\)%T`="ZY`````$B+@_@```!(
+MB9/X````3(DZ2(E""$B)$$B#PB"#P0$/MD0D768YR'?72(V[H`D``.@`````
+M2(G"2(F#P`D``$B-B``!``!(BX,(`0``2(F3"`$``$B+="1`2(DR2(E""$B)
+M$$B#PB!(.<IUVDB-N\@)``#H`````$B)PDB)@^@)``!F@WPD6`!T*[D`````
+M2(N#&`$``$B)DQ@!``!,B3)(B4((2(D02(/"*(/!`68Y3"18=]I(C;OP"0``
+MZ`````!(B8,0"@``2(F#&`H```^W="1F9HFS(@H```^W]DB-NQ@*``#H````
+M`$B-NR@*``#H`````$B)@T@*``!(B8-0"@``#[9T)&%FB;-:"@``#[?V2(V[
+M4`H``.@`````2(V[8`H``.@`````2(F#@`H``$B)@X@*```/MG0D7F:)LY(*
+M```/M_9(C;N("@``Z`````!(C;N8"@``Z`````!(B8.X"@``2(F#P`H```^V
+M0SYFB8/*"@``#[9S/DB-N\`*``#H`````$&X`````(![/@!T?[\`````#[?7
+M2(G02,'@!TB-%-!,C8036`$``$B-!!I(C;!0`0``0(A^$,9&$0!(B9A8`0``
+MQD85`,>`V`$```````!(C8P3B`$``$B)B(@!``!(B8B0`0``2(V4$Y@!``!(
+MB9"8`0``2(F0H`$``,9&$@*#QP$/MD,^9CGX=X;&0T<`QH/\!P``_\:#_0<`
+M`/_&@_X'``#_QH/_!P``_X!\)&$`#X23````O@`````/M\Y(C03)2(T$@4C!
+MX`-(BY-("```QD0"2P%(BY-("```QD002@!(BY-("```QD00</](BY-("```
+MQD009O](BY-("```9L>$$+@``````$C'A,MX`P```````$B)P4@#BT@(``!(
+MC5$@2(E1($@#@T@(``!(C5`@2(E0*(/&`0^V1"1A9CGP#X=R____9L>#J```
+M````N`````#&A!AX!P``_TB#P`%(/80```!U[(!\)%X`='Z^``````^WUDC!
+MX@A(BX-P"```9L=$$$H$`$B+@W`(``#&1`)"`$B+@W`(``#&1`)#_TB+@W`(
+M``#&1`),_TB)T4@#BW`(``!(C4$H2(E!*$B)T4@#BW`(``!(C4$H2(E!,$B+
+M@W`(``!,B80"@````(/&`0^V1"1>9CGP=X=(C;/X"@``2(V[T`H``.@`````
+M2(F#\`H``$B-LR@+``!(C;L`"P``Z`````!(B8,@"P``2(VS6`L``$B-NS`+
+M``#H`````$B)@U`+``!(C;.("P``2(V[8`L``.@`````2(F#@`L``$B-L[@+
+M``!(C;N0"P``Z`````!(B8.P"P``2(VSZ`L``$B-N\`+``#H`````$F)Q$B)
+M@^`+``!(BZOH"P``@'PD70!T2T&]`````$R)_^@`````3(E@$$B):!A(BY/X
+M````2(F#^````$R).$B)4`A(B0))@<0`$```2('%`!```$&#Q0$/MD0D769$
+M.>AWNTB-LQ@,``!(C;OP"P``Z`````!)B<1(B8,0#```2(NK&`P``$&]````
+M`$B+?"1`Z`````!,B6`02(EH&$B+DP@!``!(B8,(`0``2(M,)$!(B0A(B5`(
+M2(D"28'$```!`$B!Q0```0!!@\4!9D&#_0AUN$B-LT@,``!(C;L@#```Z```
+M``!(B8-`#```3(NC2`P``&:#?"18`'1(2(G%0;4`3(GWZ`````!(B6@03(E@
+M&$B+DQ@!``!(B8,8`0``3(DP2(E0"$B)`DB!Q8P!``!)@<2,`0``08/%`69$
+M.6PD6'>^2(/$:%M=05Q!74%>05_#9F:09F:09F:005=!5D%505154TB#[`A)
+MB?U,BZ>`````28LL)$B+A;`+``!$BSA(B?Y(B>_H`````$F-72A).5TH#X2Q
+M````2(G?Z`````!)B<9)BT4H3(EP"$F)!DF)7@A-B74H387V#X3[`0``#[9-
+M04F+1"0@#[9`"(T,B`^V53H/MG4Y10^W1C)(Q\<`````N`````#H`````$4/
+MMV8R36GDL`0``$P#I5`+``!)C9PD(`0``$R)]^@`````BTL$00^W=C)$BTL,
+M1(M#"$&+E"0@!```2,?'`````+@`````Z`````!F@WUD`'4]Z54!``!F9F:0
+M#[9-04F+1"0@#[9`"(T,B`^V53H/MG4Y0;C__P``2,?'`````+@`````Z```
+M``#I;`$``$&\`````$B-A;````!(B00D00^WU$B+A9@(``!(BQS02(7;#X3E
+M````00^W?4!F.WL@#X76````#[>5R@P``$$YUW1?#[>US@P``$B+C;`+``"#
+MP@$Y\K@`````#T/0C4(!BP2!J0``"`!U,F8E_P]F1#G@=2A).=YU*$B)[^@`
+M````00^W=C)(Q\<`````N`````#H`````.G.````1#GZ=:]F@?^#`&9F9I!W
+M8`^WQX"\!7@'``#_=%-).=YT*TB+`TB+4PA(B5`(2(D"2(N%L````$B)6`A(
+MB0-(BP0D2(E#"$B)G;`````/MW,R2(GOZ``````/MW,R2(GOZ`````!FQT,R
+M_P]!@&U$`4&#Q`%F1#EE9`^']/[__TF+%DF+1@A(B4((2(D00<9%301,B?9,
+MB>_H`````.LO#[9-04F+1"0@#[9`"(T,B`^V53H/MG4Y0;C__P``2,?'````
+M`+@`````Z`````!(@\0(6UU!7$%=05Y!7\.00(#^`1G`]]`E```,@$B+5PB)
+M0@S#D)"0D)"0D)"0D)!32(M<)"!,BU0D*$R+7"0X9H'_(B=W6V:!_R`G#X.0
+M````9H'_0"$/A(4```!F@?]`(7<>9H'_("%T=V:!_R(A='!F@?]0!W5O9F9F
+MD&9FD.M@9H'_1"%T66:!_T0A9I!R5HV'\-C__V:#^`%W2F:0ZT!F@?^")W0Y
+M9H'_@B=FD'<29H'_)"=T*6:!_X`G9I!U)NL>9H'_@)%F9F:09F:0=!!F@?^`
+ME'0)9H'_@')FD'4&Q@84Q@(`Q@$$9H'_4`=T!<8#`.L)#[8&B`-F9F:09D''
+M`H``9D''`P``0<8!($B+1"009L<```$/MA9(BT0D&(@0#[8&9D$#`F9!`P-(
+MBU0D,&:)`F9!B0!!#[<22(M$)$!FB1!!#[<2@\(+2(M$)$AFB1!;PV9F9I!F
+M9F:0\\-F9F:09F9FD&9FD&9FD$&Y`````$$/MH0Y^`<``#S_=&`/ML!(P>`(
+M28G`3`.'<`@``$&`>#H`=#ZY``````^VP4F+5,!82(72=".+0D@E`/__`#T`
+M`/\`=13V0DL$=`Y(BT)`2(7`=`5`B'`!D(/!`4$X2#IWQT&(L/@```"#Q@%)
+M@\$!28/Y!'6)2(N'``@``$@Y^'4,2(VXP`X``.AK____\\-F9I!F9I!F9I"X
+M`````,8$.`!(@\`!2#T``0``=?#&1T/_QD=,_TB-1RA(B4<H2(E',,-F9I!F
+M9I"X`````,8$.`!(@\`!2#TH`0``=?#&1W#_QD=F_\9'<A](C4<@2(E'($B)
+M1RC#9I!(BP9(BY<(`0``2(F'"`$``$B!QP`!``!(B3A(B5`(2(D"2,<&````
+M`,-F9I!F9I!(BP9(BY?X````2(F'^````$B!Q_````!(B3A(B5`(2(D"2,<&
+M`````,-F9I!F9I!(BP9(BY<8`0``2(F'&`$``$B!QQ`!``!(B3A(B5`(2(D"
+M2,<&`````,-F9I!F9I!32(G[@'Y,_P^%_@```$B+!T2+@!@!``!$B04`````
+MN0````"X`0```(G'T^=!A?AU/HA.3$B+$XGX1`G`B8(8`0``2(L#BX!8`0``
+MB04`````B?HAP@^$K````$B+`XF06`$``.F>````9F:09F:0@\$!@_D@=:Q(
+MBP-$BX`<`0``1(D%`````+$`9F:09I"X`0```(G'T^=!A?AU,HA.3$B+$XGX
+M1`G`B8(<`0``2(L#BX!@`0``B04`````B?HAPG1$2(L#B9!@`0``ZSF0@\$!
+M@_D@=;A(BT,(BP!(BP.+D!P!``"+L!@!``")-0````")\8GR2,?'`````+@`
+M````Z`````"`0T0!6\-FD%-(B?L/ME9(2(G0@^`&2(/X!G4,]L(!#X0$`0``
+M9F:0@'YF_P^%]P```$B+`T2+@!@!``!$B04`````N0````"X`0```(G'T^=!
+MA?AU.(A.9DB+$XGX1`G`B8(8`0``2(L#BX!8`0``B04`````B?HAP@^$I0``
+M`$B+`XF06`$``.F7````@\$!@_D@=;)(BP-$BX`<`0``1(D%`````+$`B<JX
+M`0```(G'T^=!A?AU-(U"((A&9DB+$XGX1`G`B8(<`0``2(L#BX!@`0``B04`
+M````B?HAPG1#2(L#B9!@`0``ZSB#P0&#^2!UM$B+0PB+`$B+`XN0'`$``(NP
+M&`$``(DU`````(GQB?)(Q\<`````N`````#H`````(!#1`%;PV9F9I!F9I!F
+M9I!F9I!(@^P(2(V7$`$``+@`````2#F7$`$``'002(G7Z`````!(QT`@````
+M`$B#Q`C#9I!(@^P(#[?62(N'F`@``$C'!-``````B?)FP>H%#[?V@>+_!P``
+MB?&#X1^X`0```$C3X/?0(827H`@``$B!QQ@*``#H`````$B#Q`C#9F9FD$B#
+M[`@/MD8(#[:T!_P'``#&A`?\!P``_P^W]DB!Q\`*``#H`````$B#Q`C#9F9F
+MD$B#[!A(B5PD"$B);"002(G[2(GU#[9&3#S_=!,/MO!(BS_H`````,9%3/^`
+M:T0!2(M<)`A(BVPD$$B#Q!C#9I!(@^P82(E<)`A(B6PD$$B)^TB)]0^V1F8\
+M_W03#[;P2(L_Z`````#&16;_@&M$`4B+7"0(2(ML)!!(@\08PV:055-(@^P(
+M2(G]2(GS2#E^*'0N2(-^<`!T)X"^@`````!U'H%^-``0``!W"TB-=G#H````
+M`.L*2(UV<.@`````D&:!>SCA`0^%E`````^W0R!F/8,`#X=X````#[?`#[:$
+M!7@'```\_W1I2(N-2`@``(![)`!U7`^VP$B-%,!(C1202(T$T0^V4SJ`^@=T
+M&X#Z!W<'@/H&=2_K&(#Z#&9FD'0@@/H-=2#K$&:#8&+]9I#K%6:#2&("ZPYF
+M@V!B]V:0ZP5F@TAB"&:!>SCA`69FD'4.@'LZ"W4(QD,D`&9F9I!(BWLH2(G>
+M_Y.@````9H%[..$!=4L/MD,Z@^@1/`%W0`^W0R!F/8,`=W8/M\`/MH0%>`<`
+M`#S_=&</ML!(P>`(2(G&2`.U<`@``(!^1`!U4$B)[^@`````ZT9F9I!F9I`/
+MMT,@9CV#`'<V#[?`#[:$!7@'``!(BXU("```//]T(`^VP$B-%,!(C1202(TT
+MT8!^<P!U"TB)[^@`````9F:02(/$"%M=PV9FD&9FD&9FD$B#[!A(B5PD"$B)
+M;"002(G[2(V_T````+T`````2#F[T````'0GZ`````!(B<5(B<?H`````,9%
+M)(!(B=_H`````$B)17C&A:@````!2(GH2(M<)`A(BVPD$$B#Q!C#D%532(/L
+M"$B)_4B-G\`*``!(B=_H`````(3`#X70````2(G?Z`````")P;@`````B<:`
+MO"C\!P``_W4*.$5'<Q*(14?K#8/&`4B#P`%(@_@$==U`@/X$#X24````0`^V
+MQHB,!?P'```/M_E(B?A(P>`'2(V$^%`!``!(C50%"+@`````Q@00`$B#P`%(
+M/8@```!U\`^WP4B)PDC!X@=(C03"2(V,!8@!``!(C10H2(F*B`$``$B)BI`!
+M``!(C80%F`$``$B)@I@!``!(B8*@`0``0(BR8`$``$B)^$C!X`=(C83X4`$`
+M`$B-1`4(ZP=FD+@`````2(/$"%M=PV9F9I!(@^P82(D<)$B);"0(3(ED)!!(
+MB?U(C9]0"@``2(G?Z`````"$P`^%U````$B)W^@`````B<*X`````&9FD&:0
+MB<.`O"AX!P``_W45#[;`9CF%J````',89HF%J````.L/@\,!2(/``4@]@```
+M`'70@/N`#X2'````#[;#B)0%>`<```^WPDB-%,!(C1203(TDU0````!,B>=(
+M`[U("```Z`````!(BY5("```#[;#9D&)1!0X2(N%2`@``$'&1`1*`$B+A4@(
+M``!!QD0$9/](BX5("```0<9$!&7_@'U+`74-2(N%2`@``$&`3`1,`4R)X$@#
+MA4@(``#K"F9FD&:0N`````!(BQPD2(ML)`A,BV0D$$B#Q!C#9F9FD&9F9I!3
+M2(G[Z.?V__](B[L`"```Z`````!;PV9FD&9FD&9FD$B#[!A(B1PD2(EL)`A,
+MB60D$$B)_4B-GX@*``!(B=_H`````(3`#X6T````2(G?Z`````")PDB)Z$&\
+M@/___Y"`N/@'``#_=!1!@\0!2(/``4&`_(0/A(4```#KXT&`_(1T?4$/ML2(
+ME`5X!P``#[?:2,'C"$B)WT@#O7`(``#H`````$B+E7`(``!!#[;$9HE$$T!(
+MBX5P"```QD0#0@!(BX5P"```9L=$`TH``$B+A7`(``!FQX0#Z```````2(N]
+M``@``+X`````Z`````!(B=A(`X5P"```ZPEF9F:0N`````!(BQPD2(ML)`A,
+MBV0D$$B#Q!C#9F9FD&9F9I!54TB#[`A(B?T/MT9`#[:<!W@'``#&A`=X!P``
+M_P^W\TB-OX@*``#H``````^WVTC!XPA(B=Y(`[5P"```@'Y,_W0(2(GOZ```
+M``!(B[T`"```O@````#H`````$B#Q`A;7<-F9F:09F:09F:09F:04TB)\X!^
+M0_]T%$B-MH@```!(BW\HZ`````#&0T/_6\-32(GS@'YP_W042(VVZ````$B+
+M?RCH`````,9#</];PTB#[!A(B1PD2(EL)`A,B60D$$B)^TF)]`^W1C@/MJP'
+M>`<``$B+E,=X`P``2(72=!9(@[J``````'4,2,>$QW@#````````00^W1"0X
+MQH0#>`<``/\/M_5(C;M0"@``Z``````/M\5(C13`2(T4D$B-+-4`````2(GN
+M2`.S2`@``(!^9O]T"$B)W^@`````3(GF2(G?Z`````!(BX-("```QD0%2@!(
+MBX-("```QD0%2P%(BQPD2(ML)`A,BV0D$$B#Q!C#9F9FD&9F9I!F9I!(@^PH
+M2(E<)`A(B6PD$$R)9"083(EL)"!)B?U(B?-F@7XXX0$/A<P````/MD8Z@^@1
+M/`$/A[T````/MT8@9CV#``^':@$```^WP`^VA`=X!P``2(N7<`@``#S_#X10
+M`0``#[;`2,'@"$B-+`*`;40!3(UE*$R)Y^@`````2(G"2#G8=4Q(B>Y,B>_H
+M`````$P[92@/A!@!``#'A8@`````$GH`2,>%F`````````!(B:V@````2(VU
+MB````$F+?2CH`````,9%0P#IXP```&:02(M%*$B)4`A(B0),B6((2(E5*$B+
+M$TB+0PA(B4((2(D0Z;L````/MT,@9CV#``^'K0````^WP$$/MH0%>`<``$F+
+MC4@(```\_P^$D@````^VP$B-%,!(C1202(TLT8!M<P%,C64@3(GGZ`````!(
+MB<)(.=AU2DB)[DR)[^@`````3#ME('1:QX7H`````!)Z`$C'A?@`````````
+M2(FM``$``$B-M>@```!)BWTHZ`````#&17``ZRAF9F:09F:02(M%($B)4`A(
+MB0),B6((2(E5($B+$TB+0PA(B4((2(D02(M<)`A(BVPD$$R+9"083(ML)"!(
+M@\0HPV9FD&9FD$B#[!A(B5PD"$B);"002(G]2(GS#[=.,F:!^?\/=!$/M]%(
+MBX>8"```2(,\T`!U(`^WR4B)VDC'Q@````!(Q\<`````N`````#H`````.LD
+M#[?QZ`````!FQT,R_P](B=Y(B>_H`````$B)WDB)[^@`````2(M<)`A(BVPD
+M$$B#Q!C#9F9FD&9FD&9FD&9FD$%7059!54%455-(@^P(28G^28G50(AT)`=(
+MBQ]F@WMD``^$P````$&\`````$&______T$/M]1(BX.8"```2(LLT$B%[0^$
+MC0````^W=2!F@?Z#`'=.#[?&#[:$`W@'```\_W0_9H/^?W<=#[;02(N+2`@`
+M`$B-!-)(C02"2(M$P5`/MD`(ZQ\/ML!(BY-P"```2,'@"$B+A!"`````#[9`
+M".L#1(GX03I&"'4K387M=`=F03MU.'4?#[9$)`>(121!#[?T2(G?Z`````!(
+MB>Y(B=_H`````$&#Q`%F1#EC9`^'3/___X!\)`>!#X0:`0``2(N#L````$B-
+MJ[````!(.>@/A`,!``!!O`````"008/$`4B+`$@YZ'7T9D6%Y`^$Y@```$&_
+M_____V9F9I!(B>_H`````$B)Q@^W>"!F@?^#`'=.#[?'#[:$`W@'```\_W0_
+M9H/_?W<=#[;02(N+2`@``$B-!-)(C02"2(M$P5`/MD`(ZQ\/ML!(BY-P"```
+M2,'@"$B+A!"`````#[9`".L#1(GX387M="1F03M].'0=2(N#N````$B)L[@`
+M``!(B2Y(B48(2(DPZSMF9I!!.D8(=1J`?B2`=0@/MD0D!XA&)$B)W^@`````
+MZQIFD$B+@[@```!(B;.X````2(DN2(E&"$B),&9!@^P!=`U(.:NP````#X4D
+M____2(/$"%M=05Q!74%>05_#9F:09I!54TB#[`A(B?5F@7XXX0$/A:L````/
+MMD8Z@^@1/`$/AYP````/MT8@NO\```!F/8,`=PL/M\`/MI0'>`<``(G02,'@
+M"$B)PT@#GW`(``"`>T/_=4D/MI68````C002A-*Z"`````]$P@^VP&G`0$(/
+M`(F#B````$C'@Y@`````````2(F;H````$B-LX@```!(BW\HZ`````#&0T,`
+M2(M3,$B):S!(C4,H2(E%`$B)50A(B2J`0T0!Z9\```!F9I`/MT4@NO\```!F
+M/8,`=PL/M\`/MI0'>`<``(G02(T4P$B-%)!(P>(#2(G32`.?2`@``(![</]U
+M20^VE9@```"-!!*$TKH(````#T3"#[;`:<!`0@\`B8/H````2,>#^```````
+M``!(B9L``0``2(VSZ````$B+?RCH`````,9#<`!(BU,H2(EK*$B-0R!(B44`
+M2(E5"$B)*H!#<P%(@\0(6UW#9F9FD&9FD&9FD&9FD$%7059!54%455-(@^P(
+M28G_28GV2(G5QD)+`<9"2@"^!@```$R)]^@`````@'US`'083(G_Z`````"_
+M`0```.@`````@'US`'7H2(M=0$B%VP^$`P$``/9%3`1U&4R)_^@`````2(MU
+M0+H!````3(G_Z`````!(BU5`#[:"RP```(T$@`^V4@(!T$B8#[:(`````$$/
+MME<Z00^V=SE$#[9%<TC'QP````"X`````.@`````2(M50$F+MP`(``"_`0``
+M`.@`````2(N+@````$B%R0^$<P$```^W13A)QX3'>`,```````!(QX.`````
+M`````$B+NY````"Z_____TB)WO_1Z4(!```/MT4X2<>$QW@#````````2,>#
+MB`````````!(B[N0````_]+V14P"=!5(BU5`28NW``@``+\&````Z`````!(
+MQT5``````$C'0V@`````ZSU!#[9'04F+5B`/ME((C02"C02`#[95<0'02)@/
+MMH@`````00^V5SI!#[9W.4C'QP````"X`````.@`````2(M56$B%TG0-#[9%
+M<4C'1,)8`````$B+50!(BT4(2(E""$B)$$$/ME8-@^H!08A6#4B+15A(A<!T
+M!V:#>$H"=5F$TG150;P`````38UN0$R)[^@`````2(G#28M&2$F)7DA,B2M(
+MB4,(2(D82(7;=!_V0TP"=!E(BU-`28NW``@``+\&````Z`````"`8TS]08/$
+M`44X9@UWM4B)[DR)_^@`````2(/$"%M=05Q!74%>05_#2(N3B````$B%T@^%
+MKO[__^G-_O__4TB)\TB+E]@```!(B;?8````2(V'T````$B)!DB)5@A(B3)(
+M@WYX`'0)2(UV>.@`````QH.H`````%O#9F9FD$B#[`A(C9?P````N`````!(
+M.9?P````=`A(B=?H`````$B#Q`C#9F9FD&9FD&9FD$B#[`A(C9<``0``N```
+M``!(.9<``0``=`A(B=?H`````$B#Q`C#9F9FD&9FD&9FD$%44TB#[`A)B?1(
+MBY_P"@``2(''&`H``.@`````B<$/M\!(P>`&2`'828D$)+H`````Q@0"`$B#
+MP@%(@_I`=?(/M\%(@\0(6T%<PY"0D)"02(L'3(L`#[9P0T"$]G1'#[97#+D`
+M````]L(!=`WK-Y!(B=!(T_BH`74(@\$!0#CQ=>Z`^0-V)$B-!(T`````)?P#
+M``!)C80`T`$``(L`B04`````ZR*Y`````$B-!(T`````)?P#``!)C80`T`$`
+M`(L`B04`````P>@4@^`!PY`/M@?`Z`2#X`</MG<"B<*`S@)`]L8$#T7"#[9/
+M`XG"@<H```(`]L$$#T7"B<*`S@A`]L8(#T7"B<*!R@``"`#VP0@/1<*)PH#.
+M!$#VQ@(/1<*)PH'*```$`/;!`@]%P@^V5Q3!XA@)T,-F9F:09F:0A?9^0@^V
+M!X3`=`0\('4Q2(GZN0````#K%V9F9I!F9I`/MD(!2(/"`83`=`0\('40@\$!
+M.?%UZ>L-9F9FD&9FD+@`````P[@!````9F:09I##9F9FD&9F9I!F9F:09F:0
+M08G0A=)T);D`````9F9FD`^V%P^V1P&(!HA6`4B#Q@)(@\<"@\$!1#G!=>3S
+MPV:02(/L&$B)'"1,B60D"$R);"0028G]B?-(BX>`````3(L@3(GGZ`````!(
+MB<;&0#CAQD`Y`<9`.A+&0#L/QD`\H,9`/0,/ML>(1CZ)V,'H$(A&/XG8P>@8
+MB$9`B%Y!00^W14!FB48@3(EF*,=&-`````!(QT9(`````$C'AJ``````````
+M3(GGZ`````!(BQPD3(MD)`A,BVPD$$B#Q!C#D$B#["A(B5PD"$B);"003(ED
+M)!A,B6PD($B)]4&)U$&)S4B+'TB)W^@`````2(G"2(7`=1#&A<$````!QD5*
+M`^F,````QD`XX<9`.0%!@/P!&<#WT(/``HA".D6$[75)N`````!(@WU8`'0$
+M#[9%<8A".P^W13AFB4(@2(E:*,="-`````!(QT)(`````$C'P`````!(B8*@
+M````2(G62(G?Z`````#K*,9".P\/MT4X9HE"($B)6BC'0C0`````2,="2```
+M``!(Q\``````Z\1(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9FD$B#
+M[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!(B?U%B<5,B0PD08GV
+M08G708G,2(N'@````$B+&$B)W^@`````2(G"2(7`='K&0#CAQD`Y`4&`_@$/
+ME,"#P!&(0CJX#P```$6$_W4$#[9%18A".T2(8CQ,B>$/ML6(0CU!@/X!=1],
+MB>D/ML6(0CY$B>C!Z!"(0C]$B>C!Z!B(0D!$B&I!#[=%0&:)0B!(B5HH2(L$
+M)$B)@J````!(B=9(B=_H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,
+MBWPD,$B#Q#C#9F9FD$B#["A(B1PD2(EL)`A,B60D$$R);"083(ET)"!(B?5-
+MB<9!B=1!B<U(BQ](B=_H`````$B)PDB%P'4-QH7!`````<9%2@/K5,9`..'&
+M0#D!08#\`1G`]]"#P`*(0CJX#P```$6$[74$#[9%<8A".P^W13AFB4(@2(E:
+M*,="-`````!(QT)(`````$R)LJ````!(B=9(B=_H`````$B+'"1(BVPD"$R+
+M9"003(ML)!A,BW0D($B#Q"C#9F9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,
+MB6PD($F)_4&)]$B++T"`_@-V.DJ-'.4`````@>/X!P``2(V$'3`"``#'``P`
+M``"_$"<``.@`````2(V$'30"``!$BP!$B04`````ZSA*C1SE`````('C^`<`
+M`$B-A"M0`@``QP`,````OQ`G``#H`````$B-G"M4`@``1(L#1(D%`````$$/
+MMO1(8\9(B<)(P>($2,'@!T@IT$F-C`70#```O_S___]`(GD)0(AY"42)P"4`
+M`#\`/0``$`!U#HGX@\@"B$$)ZR)F9F:02&/&2(G"2,'B!$C!X`=(*=")^H/*
+M`4&(E`79#```2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9FD&9FD&9FD$%5
+M05154TB#[`A(B?U!B?1(BX>`````3(LH9H._\`````!T,(GSO^@#``#H````
+M`$6%Y'0%@_L!=AI,B>]F9I#H`````&:#O?``````=`6#ZP+KTDB#Q`A;74%<
+M05W#D$B#[`A)B?`/MT8@NO\```!F/8,`=PL/M\`/MI0'>`<```^WTDC!X@A(
+M`Y=P"```2(NW(`L```^V0DS!X`A(F$B-A`9,"```BPB)#0````"!X?\````/
+MMD),P>`(2)A(C;0&1`@``(L&B04`````P>`("<B)@O0```!FQX+P``````!,
+MB<;H`````$B#Q`C#D$%6055!5%532(G]28GV28GU#[<&9H7`>0LE`!\``,'X
+M"(A'24B-?71)C54428M%%$B)171(BT((2(E'"(M"$(E'$$R-I;````!)BT4N
+M2(F%L````$B-G8@```!)C54V28M%-DB)A8@```!(BT((2(E#"$B+0A!(B4,0
+M2(M"&$B)0QA(BT(@2(E#(+H*````2(G^Z.GY__^Z!````$R)YDR)Y^C9^?__
+MNA0```!(B=Y(B=_HR?G__V;'16```&;'16(``&9!@[ZR`0```0^4PL'B`P^V
+M14R#X/<)T(A%3$'VA:<````$=`9FQT5@`0!!]H6D`````70H9H--8`)!]H6J
+M`````70%9H--8@%!]H6H`````70*9H%-8``!9F9FD$'VA:0````@=!9F@TU@
+M!$'VA:H````@=`=F@TUB`F:00?:%I````$!T%F:!36"``$'VA:H```!`=`9F
+M@TUB")#&17(!]D5@`70-28N%R````$B)16CK"$&+17A(B45H00^WA=0````E
+M`-```+H``@``/0!0``!U&$$/MX7L````P>`000^WE>H````!T(T4`(F5O```
+M`$B#;6@!QD5D`D'V16H"=!I!#[>%@````*@/=`YF@_@"&<"#P`2(161FD,9%
+M9?]!]D5J!'0?N0````!!#[>%L````$C3^*@!=`.(366#P0&#^0=UYL:%(`$`
+M``!!]H:F````('0900^WAJP```"#X""#^`$9P(/``HB%(`$``+@!````6UU!
+M7$%=05[#9F9FD&9F9I!F9I!F9I!!5T%6055!5%532(/L.(GU28G42(L/C13M
+M`````(U"X(G`2(V<""`"``!(B1PD2(V$""0"``!(B40D"(G23(V\"@`"``!,
+MC:P*!`(``+L`````3(UT)!"#_0-V)8V#'`$``$B+%"2)`K\0)P``Z`````!(
+MBU0D"(L"B04`````ZQV-@QP!``!!B0>_$"<``.@`````08M%`(D%`````$*)
+M!#-(@\,$2(/[''6K2(M$)!!)B00D2(M$)!A)B40D"$B+1"0@28E$)!"+1"0H
+M08E$)!A(@\0X6UU!7$%=05Y!7\-F9F:09F9FD&9F9I!F9I!!5T%6055!5%53
+M2(/L.(GU28G42(L/C13M`````(U"X(G`2(V<""`"``!(B1PD2(V$""0"``!(
+MB40D"(G23(V\"@`"``!,C:P*!`(``+L`````3(UT)!"#_0-V)8V#``$``$B+
+M%"2)`K\0)P``Z`````!(BU0D"(L"B04`````ZQV-@P`!``!!B0>_$"<``.@`
+M````08M%`(D%`````$*)!#-(@\,$2(/[''6K2(M$)!!)B00D2(M$)!A)B40D
+M"$B+1"0@28E$)!"+1"0H08E$)!A(@\0X6UU!7$%=05Y!7\-F9F:09F9FD&9F
+M9I!F9I!!5D%505154TB#["!(B?U!B?9,BR]$#[;F26/$2(G"2,'B!$C!X`=(
+M*=!(`?A(C9#0#```0(AR"$B)N-`,``#&0@H`1(GFZ`````!(B>!(B>+&``!(
+M@\`!2(G32(U,)"!(.<AU[$$/MO9(B>)(B>_H`````$B)Y^@`````26/42(G1
+M2,'A!$C!X@=(*<I(C0PJB8'H#```2(M##$B)A!7L#```08#^`W8\0HT$I0``
+M``!(F$F-A`70`0``BP")!0````")@0`-``!"C03E`````$B828V$!8`!``"+
+M"(D-`````.M,0HT$I0````!(F$F-A`70`0``BPB)#0````!)8\1(B<)(P>($
+M2,'@!T@IT(F,!0`-``!"C03E`````$B828V$!8`!``"+"(D-`````$ECQ$B)
+MPDC!X@1(P>`'2"G02`'HB8@$#0``]H`"#0``$`^$X````/:`V0P```)U"L>`
+M]`P```$``@!!@/X#=C5"C1SE`````$ACVTJ-A"LP`@``QP`8````OQ`G``#H
+M`````$J-G"LT`@``BS.)-0````#K,T*-'.4`````2&/;2HV$*U`"``#'`!@`
+M``"_$"<``.@`````2HV<*U0"``"+,XDU`````$ECQ$B)PDC!X@1(P>`'2"G0
+MB?&!X?___]^)\H'*````(/>$!0`-``````,`#T3108#^`W860HT$Y0````!(
+MF$F-A`4T`@``B1#K%$*-!.4`````2)A)C80%5`(``(D02(/$(%M=05Q!74%>
+MPV9F9I!F9F:09F:005=!5D%505154TB#[!A)B?Y,BS])BP?&1DD`QD9(!<9&
+M2P9(B7Y0N0````"]`````$B-D``"``!(B50D$$@%!`(``$B)1"0(ZQ9F9I!F
+M9I!!#[9&#$C3^*@!=0J#P0&003I/0W+J@/D#=GI(C1S-`````('C^`<``$R+
+M;"0020'=0<=%`"P```"_$"<``.@`````2`-<)`A$BR-$B24`````0<=%`"0`
+M``"_$"<``.@`````BP.)!0````#!X`A!@>3_````00G$0<=%`"````"_$"<`
+M`.@`````BQN)'0````#K>$B-',T`````@>/X!P``3(ML)!!)`=U!QT4`+```
+M`+\0)P``Z`````!(`UPD"$2+(T2))0````!!QT4`)````+\0)P``Z`````"+
+M`XD%`````,'@"$&!Y/\```!!"<1!QT4`(````+\0)P``Z`````"+&XD=````
+M`$&!_`$!:99U&D&`3@L&B=C!Z!`\4`^4P`^VV.M>9F:09F:008'\`0$``'4/
+MB=C!Z!`\4`^4P`^VV.M`OX@3``#H`````(/%`4"`_01W"KD`````Z:O^__^)
+MV,'H$#Q0#Y3`#[;8B=I$B>9(Q\<`````N`````#H`````(G82(/$&%M=05Q!
+M74%>05_#9F9FD&9FD$%7059!54%455-(@^Q(28G]2(L'@']#``^$/P,``,=$
+M)$0`````2(V0``(``$B)5"002`4$`@``2(E$)`AF9I`/MDPD1(A,)$,/ML&)
+M1"0T2)A(B<)(P>($2,'@!T@IT$J--"CVA@(-```0#X35`@``2(V6T`P``+@!
+M````#[9,)#1(T^`(0@I(B[;@#```2(ET)#CV0@D"#X0@`0``#[9$)$.-:`%!
+M.&U##X8.`0``2&-$)#1(B<)(P>($2,'@!T@IT$B)1"0H28V4!?@,``!(B50D
+M($F-C`7L#```2(E,)!A$#[;U26/&2(G"2,'B!$C!X`=(B<-(*=-.C20K0?:$
+M)`(-```0#X2D````3(M\)"A-`>]!]X?T#``````.``^$BP```$F-M!WX#```
+MN@@```!(BWPD(.@`````A,!T<$F-M!WL#```N@@```!(BWPD&.@`````A,!T
+M5;@!````1(GQ2-/@28V7T`P```I""HA""D&(A"3:#```2(-\)#@`=0]-BZ0D
+MX`P``$R)9"0XZQY)8\9(B<)(P>($2,'@!T@IT$B+5"0X28F4!>`,``"#Q0%!
+M.&U##X<D____2(-\)#@`#X76````3(GOZ`````!(B40D.$B%P`^$?0$``$AC
+M5"0T2(G02,'@!$C!X@=(*<),`>I(BTPD.$B)BN`,```/MD0D0TB)P4C!X01(
+MP>`'2"G(28V$!=`,``!(BTPD.$B)02`/MH+9#```B$$*QD$)`$R)*<9!#0`/
+MMD0D0XUP`4$X=4-V=TAC1"0T2(G"2,'B!$C!X`=(*=!)C;P%T`P``$`/MLX/
+MMD<*2-/XJ`%T'DACP4B)PDC!X@1(P>`'2"G02(M4)#A)B90%X`P``(/&`4$X
+M=4-V)NO(9F9FD$AC1"0T2(G"2,'B!$C!X`=(*=!(BTPD.$F)C`7@#```2&-$
+M)#1(B<)(P>($2,'@!T@IT$F-E`70#```#[9""DB+3"0XB$$,#[9J"H!\)$,#
+M=BN+7"0TP>,#2&/;2(M$)!!(`=C'`#@```"_$"<``.@`````2`-<)`B)*^LI
+MBUPD-,'C`TACVTB+1"002`'8QP`X````OQ`G``#H`````$@#7"0(B2N#1"1$
+M`0^V1"1#@\`!03A%0P^'X_S__TB#Q$A;74%<05U!7D%?PV9F9I!!5T%6055!
+M5%532(/L:$F)_DB+#\9$)%!0QD0D40'&1"12D\9$)%/`QD0D5!'&1"15`\9$
+M)%8`QD0D5P!(.[\`"```#X63````2(V7P`X``$B+1"102(F'(`@``(L%````
+M``"'(P@``(/``8D%``````^VAR`(``"(@B`(```/MH<A"```B((A"```#[:'
+M(@@``(B"(@@```^VAR,(``"#P`*(@B,(```/MH<D"```B((D"```#[:')0@`
+M`(B")0@```^VAR8(``"(@B8(```/MH<G"```B((G"```28G/2(V!``$``$B)
+M1"1`BX$``0``B04`````#[?0B50D7*@@=`LEW_\``(E$)%SK&(G0@\@@B40D
+M7$B+5"1`B0*+`HD%`````$F+!L>`!`$```````!)BP;'@!@!````````28L&
+MQX`<`0```````+^0T`,`Z`````!!QX=P`0``&`$``$&+AW0!``")!0````"`
+MY/V`S`2)1"1<0<>'<`$``!@!``"+1"1<08F'=`$``$''AW`!```H`0``0<>'
+M=`$``']_``!!QX=P`0``)`$``$&+AW0!``")!0````!FN```#?\_``")1"1<
+M0<>'<`$``"0!``"+1"1<08F'=`$``$''AW`!```\`0``0<>'=`$`````>@!!
+MQX=P`0``I`$``$''AW0!``!]O^__0<>'<`$``+@!``!!BX=T`0``B04`````
+M)?__```-``#Z`(E$)%Q!QX=P`0``N`$``(M$)%Q!B8=T`0``0<>'G````/\`
+M``!!QX>0`@``1`$``$''AY0"```&$``(0<>'D`(``+0!``!!QX>4`@``7W``
+M`$''AY`"```P````08N'E`(``(D%`````##D@,PSB40D7$&)AY0"``!!@'Y#
+M``^$@P(``,=$)$@`````28V'4`(``$B)1"0X28V75`(``$B)5"0P28V&(`@`
+M`$B)1"0H28V7@`$``$B)5"0@28V'A`$``$B)1"0828V7,`(``$B)5"0028V'
+M-`(``$B)1"0(9F:0#[94)$B(5"1/@/H##X;U````#[;JC1SM`````$ACVTR+
+M;"0020'=0<=%``@```"_$"<``.@`````2(M$)`A,C20#08L$)(D%`````(E$
+M)%P-``"``$&)!"1(BU0D*(GN3(GWZ`````")[DR)]^@`````0<=%`$0!``"_
+M$"<``.@`````0<<$)`80``A!QT4`M`$``+\0)P``Z`````!!QP0D7W```$''
+M10`(````OQ`G``#H`````,=$)%S_5(``0<<$)/]4``"Z`0```(GN3(GWZ```
M``!(BT0D($B-%`.+`HD%`````"7___[_B0+'1"1<!0'(`$@#7"08QP,%`<@`
-MOZ"&`0#H`````$2)]DB)[^@`````@T0D2`$/MD0D3X/``3A%0P^'SOW__TB)
-M[^@`````08N'!`$``(D%`````(/(`HE$)%Q!B8<$`0``2(M4)$"+`HD%````
-M`"7P___]#0T```*)1"1<B0*+`HD%`````$B+A>`0``!!B8<(`0``BX7D$```
-M08F'#`$``$B+A1`1``!!B8<0`0``BX44$0``08F'%`$``$''AR`!````````
-M#[>%M!(``"7_#P``#0```0!!B8<@`0``2(N%<!$``$&)AR0!``"+A701``!!
-MB8<H`0``2(N%F!$``,<`_P\``$''AS0!````````#[>%MA(``"7_#P``#0``
-M`0!!B8<T`0``2(N%H!$``$&)AS@!``"+A:01``!!B8<\`0``0<>'2`$`````
-M``#'1"1<``$``$''ATP!`````0``08N'!`$``(D%`````(/(64&)AP0!``#'
-M1"1<^_\`#$''AU0!``#[_P`,0<>'7`$``/__``"Z`````$ACPL>$A;@)````
-M````QT2%;`````"#P@&#^A!UXF;'A;`2``#_#V;'A;(2``#_#\9%4`&X`0``
-M`$B#Q&A;74%<05U!7D%?PV9F9I!F9I!!5T%6055!5%532(/L"$F)_DF)]$R+
-M+TR)[^@`````2(G#2(7`=0Y!QH0DZ0````'IL0```$R)[^@`````2(G%2(7`
-M=1E!QH0DZ0````%(B=Y,B>_H`````.F(````3(U[6,9#..'&0SD!QD,Z`T$/
-MMT0D.&:)0R#&@Y@````/28L&2(E#*,=#-``"``!(BU402(E32+@`````9F:0
-M9F:0Q@00`$B#P`%(/0`"``!U\$B):WA(QX.@`````````+X`````3(G_Z```
-M``"+4S1(BW483(G_Z`````!(B=Y,B>_H`````$B#Q`A;74%<05U!7D%?PV9F
-M9I!F9F:09F:0059!54%455-(@^PP28G]3(LG#[9'#83`#X3"`P``#[;PO0``
-M``!`]L8!=16Z`````(/"`0^VZHGPB>G3^*@!=/!(8\5(C11`2(T4D$F-E-30
-M$@``BT(,J0```@!T#0T```0`)?___?^)0@Q(8\5(C11`2(T4D$&+A-3<$@``
-MJ0``!``/A*$"``!)BYPD\`@``$F-A"2(%```3#GC2`]$V$F---1$#[:.XA(`
-M`$0/MH;A$@``#[:.X!(``$$/ME0D00^VAN<2``")1"0@#[:&YA(``(E$)!@/
-MMH;E$@``B40D$`^VAN02``")1"0(#[:&XQ(``(D$)(GN2,?'`````+@`````
-MZ`````!!N`````!(8\5(C11`2(T4D$V-C-3@$@``00^VA!C@"```//\/A(0`
-M```/ML!(:<#(#P``28G"3`.3B`D``$R)UDR)S[D(````_/.F#Y?"#Y+`.,)U
-M6$4/MDH$10^V0@-!#[9*`D$/ME(!00^V,D$/MD('B40D$$$/MD(&B40D"$$/
-MMD(%B00D2,?'`````+@`````Z`````!!QD4)_TR)[DR)Y^@`````Z2@"``!)
-M@\`!28/X`@^%7?___TR)Y^@`````2(G#2(7`#X0&`@``2&/%2(T40$B-%)!!
-M]H34W1(```1T!(!+70)(8\5(C11`2(T4D$'VA-3>$@``!'0$@$M=$$ACQ4B-
-M%$!(C1200?:$U-T2```(=`2`2UT$2&/%2(T40$B-%)!!]H34WA(```AT!(!+
-M72!(8\5(C11`2(T4D$'VA-3=$@```G0$@$M=`4ACQ4B-%$!(C1200?:$U-X2
-M```"=`2`2UT(QD-8`$F)WDACQ4B-%$!(C12028N$U.`2``!(B0-,B6L(3(GO
-MZ`````"(@[L```!!@$4H`4&`?"1#`'0RN0````"Z`````&9F9I!!#[9%#4C3
-M^*@!=`X/ML*(3`-P@$-:`8/"`8/!`4$X3"1#=]Q)BTU02(U3.$F)55!)C45(
-M2(E#.$B)2T!(B1%!@$58`0^VB[L```!)B[PDL!```$G'P`````!,B?),B>[H
-M`````.FV````J0``"``/A*L```!,B>?H`````$B)PTB%P`^$EP```,9`2P;&
-M0$H%9L>`R```````QD!(!L9`20!(QT!X```%`$ACQ4B-%$!(C12028N$U.`2
-M``!(B8/4````2(F#S````$R):U!,B>_H`````(B#Z@```&:#2V@03(GOZ```
-M```\"78&9H%+:``"0<9%#@%)BU5H28E=:$F-16!(B0-(B5,(2(D:2(G>3(GG
-MZ`````!F9I!F9I!(@\0P6UU!7$%=05[#9F:005=!5D%505154TB#["A)B?Q(
-MB?-(A?9T%P^V1@F$P'0///\/A>T'``#I1P$``&:0N0````!"#[:$(>8(```\
-M_W03#[;`2(T4@$B-%)!)C9S4P`$``$B#P0%(@_D$==:]`````$(/MH0EY@@`
-M`#S_=#D/ML!(C12`2(T4D$C!X@-)C9P4P`$``$'VA!3*`0```G0/O@````!(
-MB=_H`````.L(2(G?Z`````!(@\4!2(/]!'6P00^V1"0^9D$YA"2($```#X5-
-M!P``2(7;#X6.````08!\)%$`#X4X!P``0<9$)%$!28NTW&`$``!(A?9T7TB+
-MAH````!(A<!T)TC'AH``````````2<>$W&`$````````2(N^D````+K_____
-M_]#K+$B+AH@```!(A<!T($C'AH@`````````2<>$W&`$````````2(N^D```
-M`/_02(/#`4B#^Q0/A+@&``#KA,9#"?](B=Y,B>?H`````)#IH08``+D`````
-M9F:09F:00@^VA"'F"```//\/A/<````/MM!(C0222(T$@DC!X`--C;P$P`$`
-M`$&`?PG_#X35````08!_#@`/A%@&``"]`````$B-!))(C02"2,'@`TV-K`0@
-M`@``2HT<($V)_DR)[^@`````2(G!2(N#*`(``$B)BR@"``!,B2E(B4$(2(D(
-M@'E*_W1O@+GI``````^$`@8```^V44A(B="#X`9(@_@&=1WVP@%T/0^VD8$`
-M``!(BW%83(G_Z`````#IU04``$B#^`0/A<L%``#VP@%FD`^$P`4``$B)SDR)
-MY^@`````Z;`%``!(B<Y,B>?H`````.F@!0``@\4!03AN#@^&DP4``.E6____
-M2(/!`4B#^00/A>K^__](QT0D$`````!!@'PD40`/A:8```"[`````$F+M-Q@
-M!```0@^VA"-@"```2(7V=')(BXZ`````2(7)=&9(@WY@`'5?//]T-@^V^`^W
-MQTB-%$!(C1202,'B!4B)T$D#A"0X"0``]D!+!'03@'A)`'4-#[?73(GGZ```
-M``#K)4G'A-Q@!````````$C'AH``````````2(N^D````+K______]%(@\,!
-M2(/[%`^%:O___T'&1"11`>G%!```2(M4)!!"#[:$(N8(```\_P^$G00```^V
-MT$B-!))(C02"2,'@`TF-C`3``0``2(E,)"!!@+P$S@$````/A'($``#&1"0?
-M`$B-!))(C02"2,'@`TF-E`0@`@``2(D4)$Z--"!)B<](BSPDZ`````!(B<-)
-MBX8H`@``28F>*`(``$B+#"1(B0M(B4,(2(D8@'M*_P^%"`0``$0/MVLX26/%
-M00^VE`1@"```9HE4)`Y)BZS$8`0``/9#3`1T;$B%[71G2(.]@`````!T74B#
-M?6``=5:`8TS[]D-+!'02#[=4)`Y(B>Y,B>?H`````.LZ2(N%@````$ECU4G'
-MA-1@!````````$C'A8``````````2,=#0`````!(B[V0````NO____](B>[_
-MT/9#2P0/A&X!``#&@^@`````08!G#.?V0TP!#X3X````@&-,_DB+4T!(A=)T
-M2X![20!U+O9#2P1T*$$/ME0D08T4DD&-5)4`2&/228NT)/`(``"_!P```.@`
-M````Z><```!)B[0D\`@``+\!````Z`````#IT````$B%[71C2(N-@````$B%
-MR9!T5H![20!U&_9#2P1T%0^W5"0.2(GN3(GGZ`````#IG0```$ECQ4G'A,1@
-M!````````$C'A8``````````2,=#0`````!(B[V0````NO____](B>[_T>MH
-M@'M)`'5B]D-+!'1<00^V5"1!C12208U4E0!(8]))B[0D\`@``+\"````Z```
-M``#K-V9F9I!F9I!(BT-`2(7`="=(BY"(````2(72=!M(QX"(`````````$B+
-M0T!(B[B0````_])F9I#V0TP"#X0F`@``2(M30$F+M"3P"```OP8```#H````
-M`(!C3/WIX`$``&9F9I!F9I!(BT-`2(7`#X3,`0``2(.XB``````/A+X!``#&
-M0TL!QD-*`$B)VKX&````2(M\)"#H`````$B#>U@`=!=(BU,02(M#&$B)0@A(
-MB1!(BT-8@&A8`8"[@P````!T'V9F9I!,B>?H`````+\!````Z`````"`NX,`
-M````=>5(B[L@`0``2(7_=!$/MK,-`0``N@$```#H`````$B+>UA(A?]T$0^V
-MLX$```"Z`0```.@`````2(MK0$B%[0^$XP```/9#3`1U3DR)Y^@`````2(MS
-M0+H!````3(GGZ`````!(BT-`#[90`@^V<`%(Q\<`````N`````#H`````$B+
-M4T!)B[0D\`@``+\!````Z`````#K+P^V50(/MG4!2,?'`````+@`````Z```
-M``!(BU-`28NT)/`(``"_`0```.@`````2(N5B````$B%TG0D#[=#.$G'A,1@
-M!````````$C'A8@`````````2(N]D````/_2]D-,`G0:2(M30$F+M"3P"```
-MOP8```#H`````(!C3/U(QT-``````$C'16``````2(M38$B%TG00#[:#@0``
-M`$C'1,)8`````$B+$TB+0PA(B4((2(D008!O#@%(B=Y,B>?H`````/9#3`)T
-M(4B+4T!)B[0D\`@``+\&````Z`````"`8TS]9F9FD&9FD(!$)!\!#[9,)!]!
-M.$\.#X>R^___2(-$)!`!2(-\)!`$#X4[^___N`$```!(@\0H6UU!7$%=05Y!
-M7\-F9I!F9I!54TB#[`A(B?M(BR_H`````(3`=!D/MG5#0(3V=#0/ME,-N0``
-M``#VP@%T'NLDQD,)_TB)WDB)[^@`````ZV*02(G02-/XJ`%U"(/!`4`X\77N
-M2(GOZ`````!(B<9(A<!T/TB+4VA(B4-H2(U#8$B)!DB)5@A(B3*`0PX!2(E>
-M4,9&2`7&1DD`QH:!````#[D!````N@$```!(B=_H`````$B#Q`A;7<-F9F:0
-M9F9FD$B#["A(B1PD2(EL)`A,B60D$$R);"083(ET)"!)B?Q(B?5(BYZ(````
-M#[9&0CPD#X<2!@``#[;`_R3%``````^W1DX/M]#VP@1T#&;'1DX!`,9&0@'K
-M0V:#^"!U#&;'1DX(`,9&0A'K,832>17V1DD#=`\D?X/("&:)1D[&1D(-ZQCV
-MP@AT!L9%0@?K#?;&`G0(QD5'`,9%0AY(B>Y,B>?H`````.F=!0``N0$```"Z
-M`@```+X!````2(GOZ`````#I@04``+D!````N@````"^`0```$B)[^@`````
-MZ64%``"Y`0```+H!````O@$```!(B>_H`````.E)!0``N0$```"Z8````+X!
-M````2(GOZ`````#I+04```^V3DA!N`$```"Z8````+X!````2(GOZ`````#I
-M#`4``$&X`0```+D```$$NB$```"^`0```$B)[^@`````Z>H$``!(BT,@@6`T
-M___W_T&X`0```+D!````N@(```"^`````$B)[^@`````Z;T$``!!N`$```"Y
-M`````+H"````O@````!(B>_H`````+\0)P``Z`````#ID00``$B+0R"!8#3_
-M__?_0;@!````N0$```"Z`@```+X`````2(GOZ`````#I9`0``$&X`0```+D`
-M````N@(```"^`````$B)[^@`````OQ`G``#H`````.DX!```N0$```"Z`@``
-M`+X`````2(GOZ`````#I'`0``+D!````N@````"^`````$B)[^@`````Z0`$
-M``"Y`0```+H!````O@````!(B>_H`````.GD`P``0;@!````N?____^Z`0``
-M`+X`````2(GOZ`````#IP@,``+D!````N@````"^`````$B)[^@`````Z:8#
-M```/MD9'3(MLQEA)B5U028EU8`^V1D=!B(6!````0<9%2@-!QD5)`$&`34@%
-M@$,.`4B+4VA(C4-@3(EK:$F)10!)B54(3(DJOX`:!@#H`````$&`?"1#`'0F
-MO0````#V0PT!=`_K&0^V0PV)Z4C3^*@!=1&#Q0%!.&PD0W?IZP6]`````$B+
-M4R"+0C2I```(`'0*)?__]_^)0C3K:4B-!.T`````28G&08'F^`<``+NX"P``
-M0(#]`W8=28L$)$@%@`$``$P!\(L`B04`````P>@3@^`!ZQQ)BP0D2`6``0``
-M28T$!HL`B04`````P>@3@^`!A,!U#[_H`P``Z`````"#ZP%UKF9!QX7(````
-M``!,B>Y,B>?H`````.F(`@``OT`-`P#H`````+D`````NB````"^`0```$B)
-M[^@`````OQ`G``#H`````.E8`@``N0````"Z`0```+X`````2(GOZ`````"_
-M$"<``.@`````Z3("``!(BT,@@6`T___W_T&X`````+G_____N@$```"^````
-M`$B)[^@`````OQ`G``#H`````.G[`0``N0````"Z`````+X`````2(GOZ```
-M``"_$"<``.@`````Z=4!``#H`````.G+`0``9F9FD.@`````Z;T!``!!N`$`
-M``"Y\````+J;````O@$```!(B>_H`````.F;`0``0;@!````N:#66BNZX`,`
-M`+X!````2(GOZ`````#I>0$``$&X`0```+D`X`,`NJ0#``"^`0```$B)[^@`
-M````Z5<!``!!N`$```"YY*@&`;K$`P``O@$```!(B>_H`````.DU`0``N0$`
-M``"Z2`,``+X!````2(GOZ`````#I&0$``+]`#0,`Z`````"Y`0```+H@````
-MO@$```!(B>_H`````+\0)P``Z`````#IZ0```$&X`0```+D`````NB$```"^
-M`0```$B)[^@`````Z<<```"Y`0```+I@````O@$```!(B>_H`````.FK````
-M#[9.2$&X`0```+I@````O@$```!(B>_H`````.F*````QD,)`$B+OH@```#H
-M`````.MXN0$```"Z`0```+X`````2(GOZ`````"_$"<``.@`````ZU5(BT,@
-M@6`T___W_T&X`0```+G_____N@$```"^`````$B)[^@`````OQ`G``#H````
-M`.LAN0$```"Z`0```+X`````2(GOZ`````"_$"<``.@`````N`$```!(BQPD
-M2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9I!(@^P82(D<)$B);"0(
-M3(ED)!!(B?M(B?4/MU8@9H'ZA0`/AXX````/M\(/MH0'8`@``#S_=']F@_I_
-M=R0/ML!(C11`2(T4D$C!X@5(`Y<X"0``2(M"4`^V4`CK7F9F9I`/MT8@9CV!
-M`'<C#[?`#[:$!V`(``!(:<#(#P``2`.'B`D``$B+0`@/ME`(ZRT/MT8@#[:$
-M!V`(``!(C03`2,'@!4@#AV`)``!(BX"(````#[90".L%NO____^Y_____V:!
-M?2"%`'<,#[=%(`^VC`-@"```2(NS8`D```^VPH#Z_W0>2)B`O`/F"```_W02
-M@/G_=`V`?20&=2IF9F:09F:02(-]>`!T#$B-=7A(B=_H`````$B)[DB)W^@`
-M````Z0T!```/ML%(C03`2,'@!4R-)`9!#[9$)$(\&@^$A0```#P:=PX\$0^%
-MNP```&9F9I#K$SP;='<\'`^%J0```&:0Z9P```!(BY,($0``2('"3`@``$$/
-MMD0D4,'@"$B82`'"BPJ)#0`````/MLE(BY,($0``2('"1`@``$$/MD0D4,'@
-M"$B82`'"BP*)!0````#!X`@)P4&)C"0$`0``0<9$)$(:ZT)!QD0D0AOK.DB+
-M@P@1``!(!4P(``!!#[94)%#!X@A(8])(`="+`(D%`````(/@]T&(1"1(0<9$
-M)$(<ZP9!QD0D0AU(@WUX`'0,2(UU>$B)W^@`````2(GN2(G?Z`````!,B>9(
-MB=_H`````$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F:09F:09F:02(/L"$B)
-M_DB+/^@`````2(/$",-F9F:09F9FD&9F9I!(@^PX2(E<)`A(B6PD$$R)9"08
-M3(EL)"!,B70D*$R)?"0P28G_2(GS2(MN4`^W=CA(8\:Z`````("\!V`(``#_
-M#X0Z"0``#[9#2CP)#X1.!0``/`EW2CP%#X27````/`5W'CP##X2M````/`1F
-M9F:0#X7L"```Z=$```!F9I!FD#P'#X2A!```/`=F9I!F9I`/AQP$``#I@0(`
-M`&9FD&:0/!8/A'X#```\%F9FD&9FD'<C/!0/A-$%```\%&9F9I`/A]L"```\
-M"@^%E`@``&:0Z3L%```\&@^$'P(``#S_D`^$J04``#P7#X5T"```9I#I1@,`
-M``^V=T-`A/9F9F:0#X2'````#[95#4&\`````/;"`71MZW9(BT4@@6`T___^
-M_TB+>U"Y`````+H!````2(G>Z`````"_!0```.@`````N@$```#I-`@``+D`
-M````N@````!(B=Y(B>_H`````+]0PP``Z`````"Z`0```.D+"```2(G01(GA
-M2-/XJ`%U$4&#Q`%!./1UZNL&0;P`````#[932$B)T(/@!DB#^`9U"?;"`0^%
-MQ@```$B+52"+0C2I```!`'0-)?___O^)0C3IJP```$J-!.4`````28G&08'F
-M^`<``$&]$"<``)!)BQ=!@/P#=A=)C806@`$``(L`B04`````)0```0#K%4F-
-MA!:``0``BP")!0`````E```!`(7`="Q!@/P#=A-)C806@`$``,<````!`.DW
-M!P``28V$%H`!``#'`````0#I)`<``+_H`P``Z`````!!@^T!=8O&0TL"QD-*
-M_TB)WDR)_^@`````N@$```#I#@<``/9%"@%T-$B)WDB)[^@`````A,!U)4&]
-M^@```$B)WDB)[^@`````A,!U$+_H`P``Z`````!!@^T!=>%!@/P#=B9)BP=(
-M!8`!``!*C13E`````('B^`<``$@!T(L0B14`````B1#K)$F+!T@%@`$``$J-
-M%.4`````@>+X!P``2`'0BQ")%0````")$$B+>U!(B=[H2.;__[\@3@``Z```
-M``"Z`0```.ED!@``2,?'`````+@`````Z`````!(BVM03(ME`$R)Y^@`````
-M2(G!2(7`=1'&@^D````!N@$```#I*@8``,9`..'&0#D!QD`Z%P^W0SAFB4$@
+MZ?(````/MFPD3XT<[0````!(8]M,BVPD.$D!W4''10`(````OQ`G``#H````
+M`$B+5"0P3(TD$T&+!"2)!0````")1"1<#0``@`!!B00D2(M4)"B)[DR)]^@`
+M````B>Y,B??H`````$''10!$`0``OQ`G``#H`````$''!"0&$``(0<=%`+0!
+M``"_$"<``.@`````0<<$)%]P``!!QT4`"````+\0)P``Z`````#'1"1<_U2`
+M`$''!"3_5```N@$```")[DR)]^@`````2(M$)"!(C10#BP*)!0`````E___^
+M_XD"QT0D7`4!R`!(`UPD&,<#!0'(`+^@A@$`Z`````")[DR)]^@`````@T0D
+M2`$/MD0D3X/``4$X1D,/A]S]__],B??H`````$&+AP0!``")!0````"#R`*)
+M1"1<08F'!`$``$B+5"1`BP*)!0`````E\/___0T-```"B40D7(D"BP*)!0``
+M``!)BX;X"@``08F'"`$``$&+AOP*``!!B8<,`0``28N&*`L``$&)AQ`!``!!
+MBX8L"P``08F'%`$``$''AR`!````````00^WALP,```E_P\```T```$`08F'
+M(`$``$F+AH@+``!!B8<D`0``08N&C`L``$&)AR@!``!)BX:P"P``QP#_#P``
+M0<>'-`$```````!!#[>&S@P``"7_#P``#0```0!!B8<T`0``28N&N`L``$&)
+MAS@!``!!BX:\"P``08F'/`$``$''AT@!````````QT0D7``!``!!QX=,`0``
+M``$``$&+AP0!``")!0````"#R%E!B8<$`0``QT0D7/O_``Q!QX=4`0``^_\`
+M#$''AUP!``#__P``N@````!F9F:09F:02&/"0<>$AJ`(````````@\(!@_H0
+M=>EF0<>&R`P``/\/9D''ALH,``#_#[@!````2(/$:%M=05Q!74%>05_#D$%7
+M059!54%455-(@^P(28G^28GT3(LO3(GOZ`````!(B<-(A<!U#D'&A"3!````
+M`>FQ````3(GOZ`````!(B<5(A<!U&4'&A"3!`````4B)WDR)[^@`````Z8@`
+M``!,C7M8QD,XX<9#.0'&0SH#00^W1"0X9HE#(,:#F`````])BP9(B4,HQT,T
+M``(``$B+51!(B5-(N`````!F9I!F9I#&!!``2(/``4@]``(``'7P2(EK<$C'
+M@Z``````````O@````!,B?_H`````(M3-$B+=1A,B?_H`````$B)WDR)[^@`
+M````2(/$"%M=05Q!74%>05_#9F9FD&9F9I!F9I!!5T%6055!5%532(/L*$F)
+M_$B)\TB%]G07#[9&"83`=`\\_P^%'0<``.E'`0``9I"Y`````$(/MH0A_`<`
+M`#S_=!</ML!(B<)(P>('2(V$PE`!``!)C5P$"$B#P0%(@_D$==*]`````$(/
+MMH0E_`<``#S_="L/ML!(B<)(P>('2(T$PDF-G`18`0``0?:$!&(!```"=0I(
+MB=_H`````&:02(/%`4B#_01UOD$/MD0D/F9!.80DR`H```^%AP8``$B%VP^%
+MF````$&`?"1+``^%<@8``$'&1"1+`69FD&9FD$F+M-QX`P``2(7V=&-(BX:`
+M````2(7`="=(QX:``````````$G'A-QX`P```````$B+OI````"Z_______0
+MZS!(BX:(````2(7`="1(QX:(`````````$G'A-QX`P```````$B+OI````#_
+MT&9F9I!(@\,!2(/[%`^$Z`4``.N`QD,)_TB)WDR)Y^@`````D.G1!0``N0``
+M``!F9I!F9I!"#[:$(?P'```\_P^$@P````^VT$B)T$C!X`=(C03028V$!%`!
+M``"`>!'_=&>`>!4`#X2/!0``O0````!(B=!(P>`'2(T$T$V-K`28`0``2HT<
+M($R-HU`!``!,B>_H`````$B+DZ`!``!(B8.@`0``3(DH2(E0"$B)`H!X2O\/
+MA4(%``"#Q0%!.&PD%0^&-`4``.O&2(/!`4B#^00/A5[___](QT0D$`````!!
+M@'PD2P`/A:H```"[`````&9F9I!)B[3<>`,``$(/MH0C>`<``$B%]G1R2(N.
+M@````$B%R71F2(-^:`!U7SS_=#8/MO@/M\=(C13`2(T4D$C!X@-(B=!)`X0D
+M2`@``/9`2P1T$X!X20!U#0^WUTR)Y^@`````ZR5)QX3<>`,```````!(QX:`
+M`````````$B+OI````"Z_______12(/#`4B#^Q0/A6K___]!QD0D2P'I900`
+M`$B+5"000@^VA"+\!P``//\/A#T$```/MM!(B=!(P>`'2(T$T$F-C`18`0``
+M2(E,)"!!@+P$90$````/A!,$``#&1"0?`$B)T$C!X`=(C03028V4!)@!``!(
+MB10D3HTT($V-OE`!``!(BSPDZ`````!(B<-)BX:@`0``28F>H`$``$B+#"1(
+MB0M(B4,(2(D8@'M*_P^%I@,``$0/MVLX26/%00^VE`1X!P``9HE4)`Y)BZS$
+M>`,``/9#3`1T<DB%[71M2(.]@`````!T8TB#?6@`=5R`8TS[]D-+!'02#[=4
+M)`Y(B>Y,B>?H`````.M`2(N%@````$ECU4G'A-1X`P```````$C'A8``````
+M````2,=#0`````!(B[V0````NO____](B>[_T&9FD&9FD/9#2P0/A&8!``#&
+M@\``````08!G$^?V0TP!#X3W````@&-,_DB+4T!(A=)T2X![20!U+O9#2P1T
+M*$$/ME0D08T4DD&-5)4`2&/228NT)``(``"_!P```.@`````Z>,```!)B[0D
+M``@``+\!````Z`````#IS````$B%[71B2(N-@````$B%R716@'M)`'4;]D-+
+M!'05#[=4)`Y(B>Y,B>?H`````.F:````26/%2<>$Q'@#````````2,>%@```
+M``````!(QT-``````$B+O9````"Z_____TB)[O_1ZV6`>TD`=5_V0TL$9F9F
+MD&9FD'1200^V5"1!C12208U4E0!(8]))B[0D``@``+\"````Z`````#K+4B+
+M0T!(A<!T)$B+D(@```!(A=)T&$C'@(@`````````2(M#0$B+N)````#_TO9#
+M3`(/A,(!``!(BU-`28NT)``(``"_!@```.@`````@&-,_>E_`0``9F:02(M#
+M0$B%P`^$;P$``$B#N(@`````#X1A`0``QD-+`<9#2@!(B=J^!@```$B+?"0@
+MZ`````"`>W,`=!UF9I!FD$R)Y^@`````OP$```#H`````(![<P!UZ$B+:T!(
+MA>T/A.,```#V0TP$=4Y,B>?H`````$B+<T"Z`0```$R)Y^@`````2(M#0`^V
+M4`(/MG`!2,?'`````+@`````Z`````!(BU-`28NT)``(``"_`0```.@`````
+MZR\/ME4"#[9U`4C'QP````"X`````.@`````2(M30$F+M"0`"```OP$```#H
+M`````$B+E8@```!(A=)T)`^W0SA)QX3$>`,```````!(QX6(`````````$B+
+MO9````#_TO9#3`)T&DB+4T!)B[0D``@``+\&````Z`````"`8TS]2,=#0```
+M``!(QT5H`````$B+4UA(A=)T#0^V0W%(QT3"6`````!(BQ-(BT,(2(E""$B)
+M$$&`;Q4!2(G>3(GGZ`````#V0TP"=!Y(BU-`28NT)``(``"_!@```.@`````
+M@&-,_69F9I"`1"0?`0^V3"0?03A/%0^'%/S__TB#1"00`4B#?"00!`^%F_O_
+M_[@!````2(/$*%M=05Q!74%>05_#9F:09F:02(/L.$B)7"0(2(EL)!!,B60D
+M&$R);"0@3(ET)"A,B7PD,$F)_4B)\TR+9E`/MT8XN@````"`O`=X!P``_P^$
+MH@<```^V1DH\"0^$H04``#P)=TT\!0^$F@```#P%9F:0=QX\`P^$K@```#P$
+M9F9FD`^%6@<``.G0````9F:09I`\!P^$]`0``#P'9F:09F:0#X=O!```Z7P"
+M``!F9I!FD#P6#X34`P``/!9F9I!F9I!W(SP4#X0A!@``/!1F9F:0#X<'`P``
+M/`H/A0('``!FD.F+!0``/!H/A"0"```\_Y`/A/D%```\%P^%X@8``&:0Z9D#
+M```/MG=#0(3V9F9FD`^$@0```$$/ME0D#+T`````]L(!=&?K;TF+1"0@@6`T
+M___^_TB+?E"Y`````+H!````Z`````"_!0```.@`````N@$```#IF@8``+D`
+M````N@````!,B>?H`````+]0PP``Z`````"Z`0```.ET!@``2(G0B>E(T_BH
+M`74/@\4!0#CU=>SK!;T`````#[932$B)T(/@!DB#^`9U"?;"`0^%S@```$F+
+M5"0@BT(TJ0```0!T#27___[_B4(TZ;(```!(C03M`````$F)QT&!Y_@'``!!
+MOA`G``!F9F:09F:028M5`$"`_0-V%TF-A!>``0``BP")!0`````E```!`.L5
+M28V$%X`!``"+`(D%`````"4```$`A<!T+$"`_0-V$TF-A!>``0``QP````$`
+MZ:0%``!)C807@`$``,<````!`.F1!0``O^@#``#H`````$&#[@%UBL9#2P+&
+M0TK_2(G>3(GOZ`````"Z`0```.ER!0``0?9$)`H!=#1(B=Y,B>?H`````(3`
+M=25!OOH```!(B=Y,B>?H`````(3`=1"_Z`,``.@`````08/N`77A0(#]`W8G
+M28M%`$@%@`$``$B-%.T`````@>+X!P``2`'0BQ")%0````")$.LE28M%`$@%
+M@`$``$B-%.T`````@>+X!P``2`'0BQ")%0````")$$B+>U!(B=[HD_3__[H!
+M````Z<X$```/MD=!28M4)"`/ME((C02"C02`#[96<0'02)@/MH@`````#[97
+M.@^V=SE(Q\<`````N`````#H`````$B+:U!,BV4`3(GGZ`````!(B<%(A<!U
+M$<:#P0````&Z`0```.EJ!```QD`XX<9`.0'&0#H7#[=#.&:)02#&@9@````/
M2(M%`$B)02C'030`````2,=!2`````!(QX&@`````````$B)SDR)Y^@`````
-MN@$```#IWP4``$C'QP````"X`````.@`````2(MK4$R+90!,B>?H`````$B)
-MP4B%P'41QH/I`````;H!````Z:4%``#&0#CAQD`Y`<9`.A@/MT,X9HE!($B+
-M10!(B4$HQT$T`````$C'04@`````2,>!H`````````!(B<Y,B>?H`````+H!
-M````Z5H%``!(B=Y(B>_H'^7__[H!````Z44%``!,BV4`3(GGZ`````!(B<(/
-MMDML2(7`=0[&@^D````!L@'I'P4``,9`..'&0#D!QD`Z!8A(.P^W0SAFB4(@
-M2(M%`$B)0BC'0C0`````2,="2`````!(QX*@`````````(A+;TB)UDR)Y^@`
-M````N@$```#IS@0``$R+90!,B>?H`````$B)P@^V2VY(A<!U#L:#Z0````&R
-M`>FH!```QD`XX<9`.0'&0#H$B$@[#[=#.&:)0B!(BT4`2(E"*,="-`````!(
-MQT)(`````$C'@J``````````B$MQ2(G63(GGZ`````"Z`0```.E7!```3(ME
-M`$R)Y^@`````2(G!2(7`=1'&@^D````!N@$```#I,@0``,9`..'&0#D!QD`Z
-M!@^W0SAFB4$@2(M%`$B)02C'030`````2,=!2`````!(QX&@`````````$B)
-MSDR)Y^@`````N@$```#IYP,``&9F9I!F9I!,BV4`3(GGZ`````!(B<%(A<!U
-M$<:#Z0````&Z`0```.F[`P``QD`XX<9`.0'&0#H,#[=#.&:)02!(BT4`2(E!
-M*,=!-`````!(QT%(`````$C'@:``````````2(G.3(GGZ`````"Z`0```.EP
-M`P``3(ME`$R)Y^@`````2(G!2(7`=1'&@^D````!N@$```#I2P,``,9`..'&
-M0#D!QD`Z%L9`/`$/MT,X9HE!(,:!F`````](BT4`2(E!*,=!-`````!(QT%(
-M`````$C'@:``````````2(G.3(GGZ`````"Z`0```.GU`@``QD-*_V;'@\@`
-M``````^V4TA(B="#X`9(@_@&=07VP@%U%4B#>V``=0Y(B>_H`````(B#Z@``
-M`(![2P)U#TB+<U!(B=I,B?_H`````/9%#`)U&+L`````3(UE8(!]#@`/A4`!
-M``#I5P(``$B+=4`/MDY&#[;1#[9&.X/H`3G"?2Z-00&(1D:`1D<!QD9"``^W
-M1DZ#X/Z#R`AFB49.3(G_Z`````"Z`0```.E'`@``.<)T%+L`````3(UE8(!]
-M#@!U*>D1`@``QD9"``^W1DZ#X/:`S`)FB49.3(G_Z`````"Z`0```.D+`@``
-M3(GGZ`````!(B<%(BT5H2(E-:$R)(4B)00A(B0B`>4K_='R`N>D`````#X2]
-M`0``#[912$B)T(/@!DB#^`9U(O;"`71%#[:1@0```$B+<5A(B>_H`````+H!
-M````Z:D!``!(@_@$#X6!`0``]L(!#X1X`0``2(G.3(G_Z`````"Z`0```.F!
-M`0``2(G.3(G_Z`````"Z`0```.EL`0``QH'I`````(/#`3A=#@^&.P$``.E)
-M____9F9FD$R)Y^@`````2(G!2(M%:$B)36A,B2%(B4$(2(D(@'E*_P^$D```
-M`(!Y20`/A7\```"`N>D`````#X3T````#[912$B)T(/@!DB#^`9U(O;"`71(
-M#[:1@0```$B+<5A(B>_H`````+H!````Z>````!(@_@$#X6X````]L(!9F:0
-M#X2L````2(G.3(G_Z`````"Z`0```.FU````2(G.3(G_Z`````"Z`0```.F@
-M````QH'I`````(/#`0^V10XXV`^'.O___SC#=5*$P'1.NP````!,C65@3(GG
-MZ`````!(B<)(BT5H2(E5:$R)(DB)0@A(B1`/MD))/")T!#P-=12^"@```$B)
-MU^@`````N@$```#K/(/#`3A=#G>[QD4)_TB)[DR)_^@`````N@$```#K'KH!
-M````ZQ=%A>UF9F:0#X3?^/__Z??X__]F9I!FD(G02(M<)`A(BVPD$$R+9"08
-M3(ML)"!,BW0D*$R+?"0P2(/$.,-F9F:09F9FD&9FD$B#["A(B5PD"$B);"00
-M3(ED)!A,B6PD($B)^TF)]`^W3B!F@?F%``^'Z`````^WP0^VM`=@"```0(#^
-M_P^$TP```&:#^7]W*$`/MM9(BX\X"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(
-MZTEF9I!F9I!F@?F!`'<=0`^VQDB+EX@)``!(:<#(#P``2(M$$`@/MD`(ZQ]`
-M#[;&2(N78`D``$B-!,!(P>`%2(N$$(@````/MD`(//]T7@^VP`^VK`/F"```
-M0(#]_W080(#^_W0200^V3"0D@/D&=6=F9F:09F:00(#]_W0O0(#^_W0I0`^V
-MQDB-%$!(C1202,'B!4F)U4P#JS@)``!!QD5+`D'&14K_Z9\"``!)@WPD>`!T
-M#4F-="1X2(G?Z`````!,B>9(B=_H`````.FE`@``9F:09F:00`^VQDB-%$!(
-MC1202,'B!4F)U4P#JS@)``!)BU0D2(3)#X2Y````00^V1"0Z/`8/A-`````\
-M#`^$R````$$/MY7(````C4(!9D&)A<@```!F@_H)=AM!@'U*!G040<9%2P)!
-MQD5*_T&`94S^Z0,"``"_Z`,``.@`````00^V54A(B="#X`9(@_@&=3KVP@%T
-M-4$/MI6!````28MU6$`/ML5(C3R`2(T\N$B-O/O``0``0;@`````N0(```#H
-M`````.G9`0``0<9%2@-,B>Y(B=_H`````.G$`0``9F:09I!!#[9$)#H\`74+
-M0<9%2@20Z7\!```\`G4,0<9%2@5FD.EO`0``/`,/A<\```!(B=9!@'U*!74K
-M9H%Z!,@W9F:0=2!!#[=U.$C'QP````"X`````.@`````0<9%2@;I,@$``$R)
-M[^@`````28V]F````+XH````Z"6___^$P'5!28V]A````+X4````Z!"___^$
-MP'4L28V]P````+X(````Z/N^__^$P'4728-]>`!T$$'&14H7Z=H```!F9I!F
-M9I!F08.]R````!UV%$'&14L"0<9%2O]!@&5,_NFU````O^@#``#H`````$'&
-M14H:9D&#A<@````!Z9@````\%W4*0<9%2A7IB@```#P89F9FD'4'0<9%2A;K
-M>SP$9F:09I!U!T'&14H'ZVL\!69FD&:0=0=!QD5*".M;/`9F9I!FD'4'0<9%
-M2@GK2SP,9F:09I!U!T'&14H*ZSL\%F9FD&:0=0=!QD5*%.LK/`YF9I!FD'4B
-M28-\)'@`=`U)C70D>$B)W^@`````3(GF2(G?Z`````#K*TF#?"1X`'0-28UT
-M)'A(B=_H`````$R)YDB)W^@`````3(GN2(G?Z`````!(BUPD"$B+;"003(MD
-M)!A,BVPD($B#Q"C#9F9FD&9F9I!(@^PH2(D<)$B);"0(3(ED)!!,B6PD&$R)
-M="0@28G^28GT2(MN4`^W1CBZ`````("\!V`(``#_#X3+`@``#[9&2CP4#X3'
-M````/!1W.#P-D`^$^P```#P-=PX\!69F9I`/A9T"``#K33P.9F:09F:0#X3O
-M````/`\/A84"``!FD.GR````/!L/A)4````\&Y!W$#P8=#D\&0^%90(``&:0
-MZT0\''17//\/A54"``!FD.G&````O@````!,B>=F9I#H`````+H!````Z3D"
-M``"^`0```$R)Y^@`````N@$```#I(@(``+X!````3(GGZ`````"Z`0```.D+
-M`@``2(GWZ`````"Z`0```.GY`0``D$B)]^@`````N@$```#IY@$``/9&:01T
-M%TB)]V9FD&:0Z`````"Z`0```.G)`0``2(GWZ`````"Z`0```.FW`0``2(GW
-MZ`````"Z`0```&:0Z:,!``!(B??H`````+H!````Z9$!``#&1DK_@'T.``^$
-MV0```+L`````3(UM8&:03(GOZ`````!(B<%(BT5H2(E-:$R)*4B)00A(B0B`
-M>4K_#X2)````@'E)``^%A@```("YZ0`````/A#4!```/ME%(2(G0@^`&2(/X
-M!G4B]L(!=$@/MI&!````2(MQ6$B)[^@`````N@$```#I"`$``$B#^`0/A?D`
-M``#VP@%F9I`/A.T```!(B<Y,B??H`````+H!````Z=T```!(B<Y,B??H````
-M`+H!````Z<@```#&@>D`````@\,!#[9%#CC8#X<Z____.,,/A8\```!!#[9$
-M)$D\(G06/`UT$D&\`````$R-;6"`?0X`=1;K;[X*````3(GGZ`````"Z`0``
-M`.MV3(GOZ`````!(B<-(BT5H2(E=:$R)*TB)0PA(B1@/MD-)/")T!#P-=2A(
-MB=Y(Q\<`````N`````#H`````+X*````2(G?Z`````"Z`0```.LE08/$`40X
-M90YWI<9%"?](B>Y,B??H`````+H!````ZP6Z`0```(G02(L<)$B+;"0(3(MD
-M)!!,BVPD&$R+="0@2(/$*,-F9I!F9I!F9I!!5T%6055!5%532(/L*$F)_0^W
-M5B!!N/____]$B<!F@?J%``^'@`````^WPD0/MH0'8`@``$2)P$&`^/]T:V:#
-M^G]W(D$/MM!(BX\X"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZT-F@?J!`'<=
-M00^VP$B+EX@)``!(:<#(#P``2(M$$`@/MD`(ZQ]!#[;`2(N78`D``$B-!,!(
-MP>`%2(N$$(@````/MD`(#[;`00^VO`7F"```2(T$OTB-!(=)C83%P`$``$B)
-M1"0800^VP$B-%$!(C1202,'B!4D#E3@)``!(B50D($B+3D@/M@'!X!@/ME$!
-MP>(0"=`/ME$#"=`/ME$"P>(("=#!Z`-(C6D(@_@0NA`````/1\*)P$R--,%,
-M.?4/AX0!``#'1"04`````$B-!+](C02'2,'@`TZ-/"A)C9?``0``2(E4)`A)
-MC80%(`(``$B)!"1F9F:09F:02(GOZ`````!!B<1(C74$N00```#\2,?'````
-M`/.F#Y?"#Y+`.,(/A10!``!!@_P0#X<*`0``@T0D%`&#?"04`74K2(M$)"#'
-M@)`!```!````1(F@E`$``$B+10!(BU0D($B)@MP```#ITP```$R)[^@`````
-M2(G#2(7`#X3,````QD!+!L9`2@5FQX#(``````#&0$@&QD!)`$C'0'@```4`
-MQX"0`0```0```$2)H)0!``!(BU0D($B+@M0```!(B8/4````2(N"U````$B)
-M@\P```!(BT4`2(F#W````$B+1"082(E#4$B)Q^@`````B(/J````9H-+:!!(
-MBWPD&.@`````/`EV!F:!2V@``DB+5"0(@$(.`4F+AR@"``!)B9\H`@``2(L4
-M)$B)$TB)0PA(B1A(B=Y,B>_H`````)!(@\4(3#GU#X:S_O__2(/$*%M=05Q!
-M74%>05_#9F9FD$%7059!54%455-(@>Q(`@``2(E\)!A(B70D$(G02(M7"$B)
-M5"0@2(L*2(E,)"@/ME=8B%0D-TB)^4B#P4A(B4PD.$@Y3T@/A)$"``"`?"0W
-M``^$A@(```^VP(E$)`Q(BWPD..@`````3(U@\$R-1"1`BTPD#+H!````2(MT
-M)"!(BWPD$.@`````3(U\)$"`?"1```^$!0$``$&]`````$V-M"34````00^V
-M[4ACQ4B)PTC!XP1)C7P?;+H(````3(GVZ`````"$P`^$L0```$F-5!]@#[9"
-M"(/@#T&(A"3J````00^W3"1H9H'AW_V)R(/($&9!B40D:`^V0@C`Z`0\"74+
-MB<B#R#!F08E$)&A(8\5(P>`$00^V1`=HP.@$/`IU"&9!@4PD:``"2(M,)#A(
-MBU$(28U$)!!(B4$(28E,)!!)B50D&$B)`D'V1"1,`G1#08!D)$S]28M4)$!(
-MA=)T,TB+1"0H2(NP\`@``+\&````Z`````#K&V9FD&9FD$&#Q0%%."]V%69F
-M9I!F9I#I$O___T4X+P^')`$``$R)XKX&````2(M\)"#H`````$&`O"2#````
-M`'0D9F:09I!(BWPD*.@`````OP$```#H`````$&`O"2#`````'7A28N\)"`!
-M``!(A?]T$T$/MK0D#0$``+H!````Z`````!)BWPD6$B%_W0300^VM"2!````
-MN@$```#H`````$F+1"1`2(7`=&U(QT!@`````$'V1"1,!'4>2(M\)"CH````
-M`$F+="1`N@$```!(BWPD*.@`````28M4)$!(BTPD*$B+L?`(``"_!@```.@`
-M````28M4)$!(BT0D*$B+L/`(``"_`0```.@`````2<=$)$``````28L4)$F+
-M1"0(2(E""$B)$$B+5"0@@&H.`4B+3"08@&E8`4R)YDB+?"0HZ`````!(BU0D
-M.$B+1"082#E02'0+@&PD-P$/A8']__](@<1(`@``6UU!7$%=05Y!7\.005=!
-M5D%505154TB!["@"``!)B?])B?5(B=5(BP=(B40D$$0/MN%(C5PD($F)V$2)
-MX;H!````2(G^3(GOZ`````!$B>),B>Y(B>_H`````$R+=4A)@^X02(U=2$F-
-M1A!(.=AT+T$/MD9)/`UT%3PB=3/K#T$/MD9)/`UT!CPB9I!U(D'&1DH%0<9&
-M2P3&1"0>`>L%QD0D'@"`?"0@`'48Z=T!``!-BW8028/N$$F-1A!(.=AUONO<
-MQD0D'P!)C5=@2(E4)`A,BV5(28/L$$F-1"002#G##X2\`0``#[9$)!](P>`$
-M3(VL!(P```!F9F:028V\)-0```"Z"````$R)[N@`````A,`/A6`!``!-BV0D
-M$$F#[!!)C40D$$@YV`^$<P$``.O*08!'#@'&04H%QH'H`````,9!2P1FQX'(
-M``````#&@<H`````2,=!>```!0`/MGPD'TACQTC!X`1(C90$@`````^V0@2(
-M04@/MD(%B$%)3(EY4`^V0@B#X`^(@>H````/MW%H9H'FW_V)\(/($&:)06@/
-MMD((P.@$/`EU"8GP@\@P9HE!:$ACQTC!X`0/MH0$B````,#H!#P*=09F@4EH
-M``)(B6E82&/'2,'@!`^VE`2&````B)&!````2(N$!(P```!(B8'4````2(F!
-MS````(!%6`%)BT=H28E/:$B+5"0(2(D12(E!"$B)"$B+55!(C4$02(E%4$B)
-M61!(B5$82(D"#[912$B)T(/@!L9$)!X`2(/X!G4P]L(!=!D/MI&!````2(GN
-M3(G_Z`````#&1"0>`.L22(G.2(M\)!#H`````,9$)!X`@$0D'P$/MD0D'SA$
-M)"`/AT3^__^`?"0>`'0EO@H```!,B??H`````.L62(M\)!#H`````$B)P4B%
-MP`^%>?[__TB!Q"@"``!;74%<05U!7D%?PY!!5T%6055!5%532('L2`(``$F)
-M_4B)="0H2(LO#[9'*(A$)#=(C5=(2(E4)#A(.5=(#X2A`P``A,`/A)D#``!(
-MC4PD0$B#P5Q(B4PD($B-1"1`2(/`5$B)1"082(U4)$!(@\)`2(E4)!!(C4PD
-M0$B#P1!(B4PD"$B-1"1`2(/`($B)!"1(BWPD..@`````3(U@R$&X`````+D`
-M````N@````!,B>Y(BWPD*.@`````08G'A,`/A`L#``!!O@````"[`````(E<
-M)#!!N`````")V;H!````3(GN2(M\)"CH``````^VP$C!X`1(@\!D2#T``@``
-M#X>Y`0``3(U$)$")V;H!````3(GN2(M\)"CH`````+H(````3(GF2(M\)"#H
-M`````(3`#X2&`0``2(M,)#A(BU$(28U$)#A(B4$(28E,)#A)B50D0$B)`@^V
-M1"1"08A$)%E(BW0D&$R)[^@`````//]T%@^VP$AIP,@/``!(`X6("0``28E$
-M)!!%A/9T7P^V1"1#T>B#X`'!X`1!#[94)%V#XN\)PD&(5"1=#[9$)$/!Z`.#
-MX`'!X`6#XM\)PD&(5"1=#[9$)$/!Z`*#X`'!X`.#XO<)PD&(5"1=#[9$)$9!
-MB(0DNP```.FY````#[9$)$)!B$0D64V);"0(#[9$)$9!B(0DNP````^W1"1$
-M08E$)&`/MX0DD````&9!B80DN`````^VA"22````08B$)+H```!(BX0D@```
-M`$F)A"2H````2(M4)!!(BT((28F$)+````!(BT0D4$F)1"1X2(M,)`A(BT$(
-M28F$)(````!)C90DB````$B+1"1@28F$)(@```!(BPPD2(M!"$B)0@A(BT$0
-M2(E"$$B+1"1X28F$)*````"+3"0P3(GB2(MT)"A,B>_H`````.GY````08/&
-M`8/#`44X_@^$`@$``.G]_?__3(GWZ`````!(C5CP2(G:O@8```!,B>_H````
-M`("[@P````!T'F9FD$B)[^@`````OP$```#H`````("[@P````!UY4B+0T!(
-MA<!T64C'0&``````]D-,!'492(GOZ`````!(BW-`N@$```!(B>_H`````$B+
-M4T!(B[7P"```OP$```#H`````$B+4T!(B[7P"```OP8```#H`````$C'0T``
-M````2(L32(M#"$B)0@A(B1!!@&T.`4&`;"18`4B)WDB)[^@`````33ET)$@/
-MA2S___]!@&TH`4R)YDB)[^@`````2(M$)#A).45(="&`;"0W`70:9I#IO_S_
-M_TV-="1(33ET)$B0#X7R_O__Z\1(@<1(`@``6UU!7$%=05Y!7\-F9I!F9I!!
-M5T%6055!5%532('L.`(``$B)?"082(GU2(L&2(E$)"!(B?Y(B>_H`````$&X
-M`````+D`````N@````!(B>Y(BWPD&.@`````B$0D+X3`#X1N`P``0;\`````
-M0;X`````2(U52$B)5"0(2(U-8$B)#"1!N`````!$B?&Z`0```$B)[DB+?"08
-MZ``````/ML!(P>`$2(/`9$@]``(```^'#`,``$R-1"0P1(GQN@$```!(B>Y(
-MBWPD&.@`````3(UD)#!)C70D7$B)[^@`````//\/A=@"``!(BWPD(.@`````
-M2(G#2(7`#X3L`@``@$4H`<9`6`!)BT0D7$B)`TF-="142(GOZ``````\_W0:
-M#[;`2&G`R`\``$B+="0@2`.&B`D``$B)0Q!!#[9$)`*(0UE!#[9$)`/1Z(/@
-M`<'@!`^V4UV#XN\)PHA374$/MD0D`\'H`X/@`<'@!8/BWPG"B%-=00^V1"0#
-MP>@"@^`!P>`#@^+W"<*(4UU(B6L(00^V1"0&B(.[````28M$)`A(B4-P00^V
-M1"0'B$-:00^W1"0$B4-@00^W1"109HF#N````$$/MD0D4HB#N@```$F+1"1`
-M2(F#J````$F+1"1(2(F#L````$F+1"002(E#>$F+1"082(F#@````$B-BX@`
-M``!)C50D($F+1"0@2(F#B````$B+0@A(B4$(2(M"$$B)01!)BT0D.$B)@Z``
-M``!(BU502(U#.$B)15!(BTPD"$B)2SA(B5-`2(D"08`\)``/A&H!``!!O0``
-M``!(C7-(2(ET)!!(BWPD(.@`````2(G!2(7`#X1O`0``@$4.`<9`2@7&@.@`
-M````QD!+!$C'0'@```4`9L>`R```````00^W_4ACQTC!X`1)C50$8`^V0@2(
-M04@/MD(%B$%)2(EI4$B)65@/MD(&B(&!````#[9""(/@#XB!Z@````^W<6AF
-M@>;?_8GP@\@09HE!:`^V0@C`Z`0\"74)B?"#R#!FB4%H2&/'2,'@!$$/MD0$
-M:,#H!#P*=0IF@4EH``)F9F:02&/'2,'@!$F+1`1L2(F!U````$B)@<P```"`
-M0U@!2(M%:$B)36A(BQ0D2(D12(E!"$B)"$B+4U!(C4$02(E#4$B+="002(EQ
-M$$B)41A(B0(/ME%(2(G0@^`&2(/X!G4F]L(!=!0/MI&!````2(G>2(GOZ```
-M``#K#4B)SDB+?"0@Z`````!!@\4!00^V!"1F1#GH#X>L_O__9F9FD&9FD$&#
-MQP%!@\8!1#I\)"\/A:_\__^`?0X`=1'&10G_2(GN2(M\)"#H`````$B!Q#@"
-M``!;74%<05U!7D%?PV9F9I!!5T%6055!5%532(/L&$F)_DF)]$&X`````+D`
-M````N@````#H`````$&)Q83`=#:]`````+L`````3(U\)!>03(GYB=I,B>9,
-MB??H`````(!\)!?^#X6N````@\4!@\,!1#CM==I!#[9$)%B#Z`%!B$0D6(3`
-M='M)BRPD0<9$)%@`28M<)$A(@^LX28U4)$A(C4,X2#G0='!(@WL0`'5`ZP=(
-M@WL0`'4W0<9$)%@!3(GF3(GWZ``````/MHN[````2(N]L!```$G'P`````!(
-MB=I,B>;H`````.LM9F9FD$B+6SA(@^LX2(U#.$@YT'6QZQ9,B>9,B??H````
-M`$R)YDR)]^@`````2(/$&%M=05Q!74%>05_#9F9FD&9F9I!!54%455-(@^P(
-M2(G]28GT3(LONPH```!,B>9(B>_H`````(3`=0^_Z`,``.@`````@^L!=>)!
-M#[9U0T"$]G0B#[95#;D`````]L(!=`SK$DB)T$C3^*@!=0B#P0%`./%U[DF+
-M%"1)BT0D"$B)0@A(B1"`;0X!3(GF3(GOZ`````#V10P"=$E(BW5`2(7V=1A,
-MB>_H`````$B)QDB%P`^$4@$``$B)14!,B2Y(B:Z(````QD9&`,9&1P#&1D(`
-M9H-.3@1,B>_H`````.DF`0``2(M%0$B%P`^$N````$B-L)````!)BWTHZ```
-M``!(BW5`3(GOZ`````!,C65@3#EE8`^$A@```$R)Y^@`````2(G#2(M`0$B%
-MP'192,=`8`````#V0TP$=1E,B>_H`````$B+<T"Z`0```$R)[^@`````2(M3
-M0$F+M?`(``"_`0```.@`````2(M30$F+M?`(``"_!@```.@`````2,=#0```
-M``"`;0X!2(G>3(GOZ`````!,.65@#X5Z____2,=%0`````"`?0X`=!)(C7U@
-MZ`````!(B<&`;0X!ZPM,B>_H`````$B)P4B%R70Y2(M5:$B)36A(C45@2(D!
-M2(E1"$B)"H!%#@%(B6E0QD%(!<9!20#&04L&QD%*`TB)SDR)[^@`````2(/$
-M"%M=05Q!7<-F9F:09F9FD&9F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL
-M)"!(B?M(B?4/MTX@9H'YA0`/AY4````/M\$/MK0'8`@``$"`_O\/A(````!F
-M@_E_=RA`#[;62(N/.`D``$B-!%)(C02"2,'@!4B+1`A0#[9`".M)9F:09F:0
-M9H'Y@0!W'4`/ML9(BY>("0``2&G`R`\``$B+1!`(#[9`".L?0`^VQDB+EV`)
-M``!(C03`2,'@!4B+A!"(````#[9`"$`/MM8\_W0'9H'Z_P!U(TB#?7@`=`Q(
-MC75X2(G?Z`````!(B>Y(B=_H`````.D]`0``#[;`#[:,`^8(```/M\)(C11`
-M2(T4D$C!X@5)B=5,`ZLX"0``@'TD``^$K0```$B-!(E(C02!3(VDP\`!``!!
-M#[9,)`T/ME4[#[9U.D4/MD0D#DC'QP````"X`````.@`````28M5`$F+10A(
-MB4((2(D008!L)`X!3(GN2(G?Z`````!(B>Y(B=_H``````^V>T-`A/\/A*(`
-M``!!#[9T)`VY`````$#VQ@%U#^L9#[;*2(GP2-/XJ`%T$8G.2(G?Z`````#K
-M=KH`````@\(!0#CZ==KK9V9FD&:02(T$B4B-!(%,C:3#P`$``(!].@%U++\0
-M)P``Z`````!(B>Y(B=_H`````+D!````N@````!,B>Y,B>?H`````.L@OU##
-M``#H`````$B)[DB)W^@`````3(GN3(GGZ`````!(BUPD"$B+;"003(MD)!A,
-MBVPD($B#Q"C#9F:09I!!5T%6055!5%532(/L"$B)^TF)]4&)UD&)STB+!TB)
-M!"2`?PX`='F]`````$R-9V!,B>?H`````$B)PDB+0VA(B5-H3(DB2(E""$B)
-M$$PY:EAU#40XLH$```!T#69F9I"#Q0%`.&L.=\=`.&L.=#%!@/]0=2O&0DL&
-MQD)*!<9"2`?&0DD`3(EJ6$B)6E#&@LH`````2(G62(L\).@`````2(/$"%M=
-M05Q!74%>05_#D$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!(
-MB?U)B?0/MU8@9H'ZA0`/AXX````/M\(/MH0'8`@``#S_=']F@_I_=R0/ML!(
-MC11`2(T4D$C!X@5(`Y<X"0``2(M"4`^V4`CK7F9F9I`/MT8@9CV!`'<C#[?`
-M#[:$!V`(``!(:<#(#P``2`.'B`D``$B+0`@/ME`(ZRT/MT8@#[:$!V`(``!(
-MC03`2,'@!4@#AV`)``!(BX"(````#[90".L%NO____^Y_____V9!@7PD((4`
-M=PY!#[=$)"`/MHP%8`@```^VP@^VA`7F"```2(T4@$B-%)!,C;35P`$```^V
-MP4B-!,!(P>`%3(NM8`D``$D!Q4&`?"0\`@^%@````$$/MD0D0"7P````@_@@
-M=`6#^!!U:T$/ME0D0(G0@^`/@_@!=2B)T8'A\````$&X`0```+H"````O@``
-M``!,B>_H`````.GS"@``9F:000^V14=)BU3%6$$/MD0D0"7P````@_@@#Y3`
-M@\`(B(+J````2(M"8&:!8$[__NF]"@``00^V1"0DA,!T.XG#28-\)'@`=`U)
-MC70D>$B)[^@`````3(GF2(GOZ`````"`^P(/A8@*``!,B>Y(B>_H`````.EX
-M"@``0<>%"`$```````!!#[9%0CPD#X<#"@``#[;`_R3%`````$F+1B#V0#8(
-M#X0B"@``Z4<&``!F9I!(BY4($0``2('"3`@``$$/MD50P>`(2)A(`<*+`HD%
-M`````(/X!;H%````#T?"08A%.T&`?@\`=`]!QD5"`$'&1@\`Z9L)``!!QD5"
-M`NF1"0``2(N5"!$``$B!PDP(``!!#[9%4,'@"$B82`'"BP*)!0`````/ML!F
-M08E%/$B+E0@1``!(@<)$"```00^V15#!X`A(F$@!PHL"B04`````B<+!Z@AF
-M08E5/L'@"&9!"44\9H'Z0$&X`P```+H9````#T3"08A%0ND6"0``2(N5"!$`
-M`$B!PD0(``!!#[9%4,'@"$B82`'"BP*)!0````!!B$4Y2(N5"!$``$B!PDP(
-M``!!#[9%4,'@"$B82`'"BP*)!0````")P*@(=`=!QD4Z#.L@J`1T"D'&13H+
-M9F:0ZQ*#X`)(@_@!&<#WT(/@"D&(13I!#[9%1SP!&<"#X`*#P!1!B$5"Z8<(
-M``!(BX4($0``2`5,"```00^V55#!X@A(8])(`="+`(D%`````(/("$&(14A!
-MQD5"!>E3"```0<9%0@!!#[=%3F8E]_V#R`)F08E%3DF#?"1X`'0-28UT)'A(
-MB>_H`````$R)YDB)[^@`````0<9&"?],B?9(B>_H`````.EE"```0<9%0@3I
-M_@<``$$/MD5'@\`!08A%1T$Z13MS5T'&14(628-\)'@`=`U)C70D>$B)[^@`
-M````3(GF2(GOZ`````!!QX60````@(0>`$G'A:``````````38FMJ````$F-
-MM9````!(BWTHZ`````#I\@<``$'&14<`0<9%0A>_(*$'`.@`````Z7P'``!!
-MQD5"%.ER!P``0<9%0@CI:`<``$'&14(4Z5X'``!!QD5*`.@`````28F%\```
-M`$'&14(5Z4,'``!(BY4($0``2('"3`@``$$/MD50P>`(2)A(`<*+&HD=````
-M``^VVTB+E0@1``!(@<)$"```00^V15#!X`A(F$@!PHL"B04`````Z`````!)
-MB87X````@^,/@_L#=0I!QD5""NG<!@``08N%\`````5`#0,`03F%^````'D:
-M00^V14H\"G<10<9%0A6#P`%!B$5*Z:T&``!!#[9%1TF#?,58``^$U`$``$C'
-M!"0`````08!^#@!T0D&_`````$F-7F!(B=_H`````$B)!"1!#[9%1TB+%"1)
-M.53%6'0<2(M#"$B)4PA(B1I(B4((2(D008/'`44X?@YWR$&`;@X!2(L,)$B+
-M04!(A<`/A%,!``!(QT!@`````/9!3`1U-TB)[^@`````2(L4)$B+0F#&@!P!
-M```!2(MR0+H!````2(GOZ`````!(BPPD2(M!8,:`'`$```!(BP0D2(M00$B+
-MM?`(``"_`0```.@`````2(L4)$B+0D!(BXB`````2(7)=#$/MT(X2,>$Q6`$
-M````````2(M"0$C'@(``````````2(MR0$B+OI````"Z_______12(L,)$B+
-M04!(A<!T.$B+D(@```!(A=)T+`^W03A(QX3%8`0```````!(BT%`2,>`B```
-M``````!(BT%`2(NXD````/_22(L$)$B+4$`/MH+,````C02`#[92`@'02)@/
-MMH@`````#[95.@^V=3E(BP0D1`^V@(,```!(Q\<`````N`````#H`````$B+
-M#"1(BU%`2(NU\`@``+\&````Z`````!(BP0D2,=`0`````!!#[9%1TG'1,58
-M`````$B+-"1(B>_H`````$'&14()Z;X$``!(BY4($0``2('"3`@``$$/MD50
-MP>`(2)A(`<*+"HD-``````^VR4B+E0@1``!(@<)$"```00^V15#!X`A(F$@!
-MPHL"B04`````P>`("<A!B45408!]0@IT!ZD```$`=`I!QD5""^E4!```0<9%
-M0@Q!#[9%1TF#?,58`'1108!^#@`/A)0$``!!OP````!)C5Y@2(G?Z`````!(
-MB<)!#[9%1TDY5,58=0=!@&X.`>LI2(M#"$B)4PA(B1I(B4((2(D008/'`44X
-M?@YV#>O$2(GOZ`````!(B<)(A=(/A#H$``!!#[9%1TF)5,5800^V14N(@NH`
-M``#IPP,``$B)[^@`````OP$```#H`````(/K`8/[_W0*28M&(/9`-@ATW$'&
-M14()Z94#``!(BY4($0``2('"3`@``$$/MD50P>`(2)A(`<*+"HD-``````^V
-MR4B+E0@1``!(@<)$"```00^V15#!X`A(F$@!PHL"B04`````#[;`P>`("<@E
-M_P\``#T3`0``#Y3"/2,!```/E,&$TG40A,EU##TS`0``=4+I2`,``$'&14(8
-MA-*0=`I!QD5+".D'`P``A,EFD'0*0<9%2PGI]P(``#TS`0``#X7L`@``0<9%
-M2PIF9F:0Z=X"``!!#[9-1@^VT4$/MD4[@^@!.<)]%HU!`4&(149!@$5'`4'&
-M14('Z;0"``!!QD5'`$'&14(>Z:4"``!!QD5"`^F;`@``0<9%0B)F9I#IC@(`
-M`$'&14(CZ80"``!!QD5"`^EZ`@``2(N5"!$``$B!PDP(``!!#[9%4,'@"$B8
-M2`'"BPJ)#0````!(BY4($0``2('"1`@``$$/MD50P>`(2)A(`<*+$HD5````
-M`(G0P>`(#[;)"<AF/0,1#X6C````B=#!Z`AF/453=`IF/4`##X6.````9D''
-M13P#$69!B44^9CU%4W4?08"]%0$```)T%4'&A14!```"0<>%&`$``!\```#K
-M)F9!@7T^0`-U'4&`O14!```#=!-!QH45`0```T''A1@!```/^`,`0<:%'`$`
-M``%,B>_H`````$'&A1P!````28M%`$B+N/`(``"^`````.@`````0<9%0@/I
-M?0$``$'&14(A0<:%%0$```#I:P$``$B+E0@1``!(@<),"```00^V15#!X`A(
-MF$@!PHL"B04`````2(N5"!$``$B!PD0(``!!#[9%4,'@"$B82`'"BP*)!0``
-M``!!QD5"'^D;`0``0<9%0B#I$0$``$B+E0@1``!(@<),"```00^V15#!X`A(
-MF$@!PHL"B04`````2(N5"!$``$B!PD0(``!!#[9%4,'@"$B82`'"BP*)!0``
-M``!!#[9-1T$/MD4[C5$!08A51P^VR0^VP(/H`3G!N`8```"Z'P````],PD&(
-M14+IF0```$B+E0@1``!(@<),"```00^V15#!X`A(F$@!PHL*B0T`````#[;)
-M2(N5"!$``$B!PD0(``!!#[9%4,'@"$B82`'"BP*)!0````#!X`@)P4&)C00!
-M``!!QD5"&NL]0<9%0AOK-DB+A0@1``!(!4P(``!!#[954,'B"$ACTD@!T(L`
-MB04`````@^#W08A%2$'&14(<ZP5!QD5"'4F#?"1X`'0-28UT)'A(B>_H````
-M`$R)YDB)[^@`````3(GN2(GOZ`````#K,$'&14(8Z<+\__](B>]F9I#H````
-M`+\!````Z`````"[/D(/`.D!_/__9F9FD&9FD$B+7"0(2(ML)!!,BV0D&$R+
-M;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD&9FD&9FD&9FD$B#[#A(B5PD"$B);"00
-M3(ED)!A,B6PD($R)="0H3(E\)#!(B?U(B?,/MTX@9H'YA0`/A]\````/M\$/
-MMK0'8`@``$"`_O\/A,H```!F@_E_=R)`#[;62(N/.`D``$B-!%)(C02"2,'@
-M!4B+1`A0#[9`".M#9H'Y@0!W'4`/ML9(BY>("0``2&G`R`\``$B+1!`(#[9`
-M".L?0`^VQDB+EV`)``!(C03`2,'@!4B+A!"(````#[9`"#S_=%L/ML`/MHP%
-MY@@``(#Y_W050(#^_W0/#[9[)$"`_P9U969FD&:0@/G_=#%`@/[_="M`#[;&
-M2(T40$B-%)!(P>(%28G43`.E.`D``$'&1"1+`D'&1"1*_^FZ!P``2(-[>`!T
-M#$B-<WA(B>_H`````$B)WDB)[^@`````Z<<'``!F9F:09F:00`^VQDB-%$!(
-MC1202,'B!4F)U$P#I3@)``!!#[>T),@```!F@?ZK#7<&0(#_`G4Z2(-[>`!T
-M#$B-<WA(B>_H`````$B)WDB)[^@`````0<9$)$K_0<9$)$L"3(GF2(GOZ```
-M``#I5@<``+H`````0(#_('4>2(M34`^V`H/@?SQQ=@D/ME(!@^(/ZP</ME("
-M@^(/1`^VZ4N-1*T`28U$A0!,C;3%P`$```^V0S@\&@^$Y@4``#P:=QP\$G1.
-M/!60#X2)!@``A,`/A(X%``!FD.F[!@``/"4/A"<#```\)9!W$SP;#X6F!@``
-M9F:09F:0Z5P%```\G@^$%`0``#R@D`^%B@8``.E8!@``0(3_9I`/A<T"``!(
-MBTM(@'LY`&:0=&9(A<ET2X!Y`8!U18!Y`@!U/P^V00,\/'<W#[;028VT)(0`
-M``"X`````,8$,"!(@\`!2(/X%'7R@_H4#T/028V\)(0```")TDB-<03H````
-M`&9!QX0DR```````0<9$)$H9Z0@&``!!QD0D2ACV009`=1$/M@&#X!^#^`T/
-MA9$!``#K"P^V`8/@'X/X#74(0<9$)$D-ZP9!QD0D22)!#[9T)$E(Q\<`````
-MN`````#H`````$B#>W@`=`Q(C7-X2(GOZ`````!(B=Y(B>_H`````$N-1*T`
-M28U$A0"`O,7.`0````^$M04``$&^`````$N-1*T`28U$A0!(P>`#3(VD!2`"
-M``!(C1PH3(V[P`$``$R)Y^@`````2(N3*`(``$B)@R@"``!,B2!(B5`(2(D"
-M#[9`23PB=`0\#74*08/&`44X=PYWRDN-1*T`28U$A0`/MH3%S@$``$0X\`^%
-M/04``(3`#X0U!0``0;P`````9L=$)`8``$&_`````$N-1*T`28U$A0!(P>`#
-M3(VL!2`"``!(C1PH3(VSP`$``$R)[^@`````2(G"2(N#*`(``$B)DR@"``!,
-MB2I(B4((2(D0#[9"23PB=`0\#743#[=".&8[1"0&<@AFB40D!DF)UT&#Q`%%
-M.&8.=[1-A?\/A*P$``!!@']*_P^$H00``$'&1TK_3(G^2(GOZ`````#IC`0`
-M`(/X`7410<9$)$D!0<9$)$K_Z48$``#V004!9I!T"&9!@4PD:``$2(MS2$B%
-M]G1F28V4))@```"X`````,8$$`!(@\`!2(/X*'7R28V4),````"P`,8$$`!(
-M@\`!2(/X"'7R28V,))@```!(C58(2(M&"$F)A"28````2(M""$B)00A(BT(0
-M2(E!$(M&($&)A"3`````08.\))`!````#X6X`P``0<9$)$H<Z:T#``"-1@%F
-M08F$),@```"_$"<``.@`````0<9$)$H%Z8P#``!(BTM(0(3_#X69````#[91
-M!L'B"`^V007!X!`)P@^V00<)P@^V003!X!@)PD&)E"3D````#[81P>(8#[9!
-M`PG"#[9!`L'@"`G"#[9!`<'@$`G0B<))B50D>$&#O"3D`````'4?9D&#A"3(
-M`````;\0)P``Z`````!!QD0D2AOI"0,``(/X_W439D&!3"1H``1!QD0D2AOI
-M\0(``$'&1"1*#>GF`@``0(#_(&:0=2Z`^@9T!8#Z`G4DC48!9D&)A"3(````
-MOQ`G``#H`````$'&1"1*!>FS`@``9F:02(-[>`!T#$B-<WA(B>_H`````$B)
-MWDB)[^@`````3(GB3(GV2(GOZ`````#IKP(``$R+0TA`A/\/A<P```!!#[90
-M"L'B"$$/MD`)P>`0"<)!#[9`"PG"00^V0`C!X!@)PD&)E"3D````00^V2`-(
-MP>$@00^V0`)(P>`H2`G!00^V`$C!X#A("<%!#[9``4C!X#!("<%!#[90!L'B
-M"$$/MD`%P>`0"<)!#[9`!PG"00^V0`3!X!@)PD@)T4F)3"1X0?9`#`%T!V9!
-M@TPD:@1!@[PDY`````!U'V9!@X0DR`````&_$"<``.@`````0<9$)$H;Z;@!
-M``!F08-,)&@!0<9$)$H-Z:8!``!`@/\@9I!U+H#Z!G0%@/H"=22-1@%F08F$
-M),@```"_$"<``.@`````0<9$)$H;Z7,!``!F9I!(@WMX`'0,2(US>$B)[^@`
-M````2(G>2(GOZ`````!,B>),B?9(B>_H`````.EO`0``0<9$)$H4Z30!``!`
-M@/\@=2Z`^@9T!8#Z`G4DC48!9D&)A"3(````OQ`G``#H`````$'&1"1*%.D#
-M`0``9F:00<9$)$H;Z?4```!`A/]FD'5M2(M#2&9!@TPD:`)F08-,)&H!9D&!
-M3"1HA`"`>`,`=06`.!9W'V9!@X0DR`````&_$"<``.@`````0<9$)$H-Z:H`
-M``#V0`8$=`EF08-,)&H"ZP=F08-D)&K]2(M#>$F)1"0P2,=#>`````#K.$"`
-M_R!U*X#Z!G0(@/H"9F:0=26-1@%F08F$),@```"_$"<``.@`````0<9$)$H%
-MZU!F08-D)&CY0<9$)$H.ZT%`A/]U!V9!@TPD:@-!QD0D2@_K+4"$_W4+2(G>
-M2(GOZ`````!!@[PDD`$```$9P(/@$X/`!4&(1"1*9F9FD&9FD$B#>W@`=`Q(
-MC7-X2(GOZ`````!(B=Y(B>_H`````$R)YDB)[^@`````9F9FD&9FD$B+7"0(
-M2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#D)"0D)"0D)"0D)"0D(/B
-M!\'B"(#.($B+1PA(+>0\``!(P>8(@>8`_P``2`'PB1`/MP!FB04`````#[;`
-MPX/B!\'B"(C*@,X02(M'"$@MY#P``$C!Y@B!Y@#_``!(`?")$,-F9F:09F9F
-MD&9FD%53O0````"[`````$&Y_____T&[`````$6)VD&#PP&X`0```$&)P$2)
-MV4'3X$2)P;X`````N,#AY`"Z`````/?Q.?AW$8GZ*<)$.<IS"$2)U8GS08G1
-M@\8!1`'!@_X0==1!@_L(=;&-!-T`````">@/ML!;7<-F9F:09F:09F:02(/L
-M$$B)'"1,B60D"$F)_$`/MMZY`````+H'````B=[H*____T$/MHPD.1(``+H#
-M````B=Y,B>?H$____TB+'"1,BV0D"$B#Q!##9F:09I!3B?,/MO*Z`P```.C`
-M_O__.-@/E,`/ML!;PV9FD&9FD$B%_W0WN@````!F9I!F9I`/MH0ZX@@```^V
-MR#S_=!,/M\%(C03`2,'@!4@#AV`)``##2(/"`4B#^@1UU+@`````PV9F9I!F
-M9F:09F:09F:055-(BY_X"```2(7;2`]$W[T`````N0````"Z!P```(GN2(G?
-MZ&?^__^Y1````+H"````B>Y(B=_H4_[__[G0````N@````")[DB)W^@__O__
-MN0````"Z!````(GN2(G?Z"O^__^#Q0&#_0)UJ+^@A@$`Z$G^__^(@SD2```/
-MMLBZ`P```+X`````2(G?Z/[]__];7<-F9F:09F9FD&9FD$%455-(B?L/MH<5
-M`0``/`(/A;(```!$BY<8`0``0;P`````O0```"I!N0````"^`````+\`````
-M0;@$````9I"Z`0```(G0B?'3X$&%PG48C4X&T^)!"=1!"=&X%0```(GYT^`)
-MQ>L)1(G`B?G3X`G%@\8!@\<%08/``X/^!77`1(G)NJ@#``!`M@%(B=_H````
-M`(GINL0#``"^`0```$B)W^@`````00^WS`N+&`$``+J@`P``O@$```!(B=_H
-M`````.FX````/`,/A;````!$BY<8`0``0;P`````O0```"I!N0````"^````
-M`+\`````0;@$````N@$```")T(GQT^!!A<)U&(U.!M/B00G400G1N!4```")
-M^=/@"<7K"42)P(GYT^`)Q8/&`8/'!4&#P`.#_@1UP$2)R;JH`P``0+8!2(G?
-MZ`````")Z;K$`P``O@$```!(B=_H`````$$/M\P+BQ@!``#WT;J@`P``O@$`
-M``!(B=_H`````&9FD%M=05S#9F9FD&9F9I!F9I!(@^P(B?&$TG06N/[____3
-MP"&'&`$``.L49F9FD&9FD+@!````T^`)AQ@!``#H`````$B#Q`C#9F:09F:0
-M9F:04TB)^V;'APP!```!``^W]HGQP>$-0;@!````NJ`#``"^`0```.@`````
-MOA0```!(B=_H`````%O#9F9FD&9FD$B#[`B)\832=1:X_O___]/`9B&'``$`
-M`.L49F:09F:0N`$```#3X&8)AP`!```/M[<``0``Z`````!(@\0(PY!(@^PH
-M2(E<)`A(B6PD$$R)9"083(EL)"!)B?U!B=0/MJ[,````#[9>`DB+?G!(A?]T
-M"P^VT@^V\^@`````@/L#=Q"-%*N-1*L$0(#]`P]&PNL-C540C44@0(#]`P]&
-MPD$/MM0/MO!,B>_H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9I!F
-M9I!F9I!!5%5328G\NP````!`#[;NN@(```")[DR)Y^C!^O__J`AT#;@`````
-MZR!F9I!F9I"_`0```.@`````@\,!@?L0)P``=<NX_P```%M=05S#D$B#["A(
-MB5PD"$B);"003(ED)!A,B6PD($B)_4F)S4&)U$`/MMZ)WNB$____A<!U,$$/
-MMO2)VDB)[^B"^___A<!T'KH!````B=Y(B>_H/_K__T&(10"X`````.L)9F9F
-MD+C_____2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV:02(/L*$B)7"0(2(EL
-M)!!,B60D&$R);"0@2(G]08G-1`^VXD`/MMY$B>&Z`0```(G>Z`OZ__^Y0```
-M`+H"````B=Y(B>_H]_G__XG>2(GOZ-W^__^%P'5,187M=#1!]L0!=!6)VKY`
-M````2(GOZ,_Z__^%P'0NZS.)VKX8````2(GOZ+KZ__^%P'09ZQYF9F:0B=J^
-M*````$B)[^BA^O__A<!U![C_````ZP:X`````)!(BUPD"$B+;"003(MD)!A,
-MBVPD($B#Q"C#9F9FD&9FD$%7059!54%455-(@^P(28G]2(D,)$6)QHGSB=6$
-MT@^$\0```$0/MOZY9````+H"````1(G^Z#;Y__]$B?Y,B>_H&_[__X7`=1"Z
-M`P```$2)_DR)[^CG^/__0`^VU;D!````1(G^3(GOZ,/^__]!O/____^$P`^%
-M@P$``$&\`````$6%]@^.=`$``$B+'"1!O`````!!C6[_1#GE=36Y0````+H"
-M````1(G^3(GOZ+[X__])8\Q(`PPDNE@```!$B?Y,B>_HY_W__X7`=#7I+`$`
-M`+E$````N@(```!$B?Y,B>_HB?C__TB)V;I0````1(G^3(GOZ+;]__^%P`^%
-M_````$&#Q`%(@\,!13GT#X3K````ZX._H(8!`.B!^/__#[;K#[;(N@,```")
-M[DR)[^@\^/__B>Y,B>_H(OW__X7`=")!#[:-.1(``+H#````B>Y,B>_H%_C_
-M_T&\_____^F:````B>J^8````$R)[^C]^/__A<!T#4&\`````$6%]GYEZQ]!
-M#[:-.1(``+H#````B>Y,B>_HU??__T&\_____^M;2(L<)$&\`````&9FD+E$
-M````N@(```")[DR)[^BL]___2(G9NH````")[DR)[^C:_/__A<!U#4&#Q`%(
-M@\,!13GT=<E!#[:-.1(``+H#````B>Y,B>_H<O?__T2)X$B#Q`A;74%<05U!
-M7D%?PTB#[!A(B5PD"$R)9"0028G\2(G00`^VUD&)R$B)P;X!````Z,C]__^)
-MP[E4````N@(```"^`0```$R)Y^@?]___B=A(BUPD"$R+9"002(/$&,-F9F:0
-M9F9FD&9FD&9FD$B#[!A(B5PD"$R)9"0028G\2(G00`^VUD&)R$B)P;X`````
-MZ&C]__^)P[E4````N@(```"^`````$R)Y^B_]O__B=A(BUPD"$R+9"002(/$
-M&,-F9F:09F9FD&9FD&9FD$%6055!5%5328G]2(G-18G&B=-$#[;FN60```"Z
-M`@```$2)YNAW]O__1(GF3(GOZ%S[__^%P'40N@,```!$B>9,B>_H*/;__P^V
-MT[D!````1(GF3(GOZ`7\__^$P'4V187V?CA(B>N]`````&9F9I`/MA.Y````
-M`$2)YDR)[^C=^___A,!U#H/%`4B#PP%$.?5T">O;N/_____K!;@`````6UU!
-M7$%=05[#9F:09F:02(/L&$B)7"0(3(ED)!!)B?Q(B=!`#[;608G(2(G!O@``
-M``#H*/___XG#N50```"Z`@```+X`````3(GGZ*_U__^)V$B+7"0(3(MD)!!(
-M@\08PV9F9I!F9F:09F:09F:02(/L"$B+A_@(``!(A<!(#T3'0(@U`````+D@
-M````2,?"`````+X.````2(G'Z`````!(@\0(PV9FD&9FD&9FD$B#[`B)\832
-M=!:X`0```-/@9@F'9!0``.L49F:09F:0N/[____3P&8AAV04```/MK=D%```
-MZ`````!(@\0(PY!!5T%6055!5%532(/L2$B)^TF)]DB+3BA(@\$!BW8<@^X!
-MQT0D1`````!)BT8P2(E$)"`/ME$!@/H!=11!QT90`````.F'!```9F9FD&9F
-MD(#Z`G5)@'D"`74V2(N'^`@``$B%P$@/1,=(BY#P"```#[9!`XB"9A0```^V
-M00.(@NXH``!!QT90`````.D_!```0<=&4/[____I,@0``(#Z!`^%_@$```^V
-M00.#Z#L\`0^'[P$``$V+?BA)@\<!00^V;P)(BY_P"```0`^V]4B)W^@`````
-MB<*$P'0-#[;`@+P#8`@``/]U4$B+F_`(``!(@<.(%```2(N[\`@``.@`````
-MB>HHP@^V\DB)W^@`````B<*$P'0-#[;`@+P#8`@``/]U%$''1E#_____3(GW
-M0?]62.FM`P``#[;"#[:$`V`(``"`^H%W9`^VR$AIR<@/``!!#[9W!$$/ME<%
-MP>(000^V1P;!X`@)PD$/MD<'"<*)5"0L00^V5PC!XA!!#[9'"<'@"`G"00^V
-M1PH)PHE4)#!(B<U(`ZN("0``#X3M````@'U8`'4=Z>(```!!QT90_____TR)
-M]T'_5DAF9F:0Z2$#``!!O`````#&1"0W`$R-;4B+1"0L2(E$)!!)C5<+2(E4
-M)`A`#[;VB70D!$R)[^@`````2(U8\$B+55!(B4503(EK$$B)4QA(B0(/MD-)
-M/`UT!#PB=5U!#[9'`SP[="(\/'5038GPBTPD+(M4)#"+="0$2(G?Z`````#&
-M1"0W`>LR2(N[*`$``$B+5"002(MT)`CH`````$V)\(M,)"R+5"0PBW0D!$B)
-MW^@`````QD0D-P%!@\0!1#AE6`^':O___X!\)#<`#X57`@``0<=&4/____],
-MB?=!_U9(9I#I00(``(#Z`P^%F0```(!Y`@$/A8(````/MD,^C30`#[9Y`XGZ
-MB?C!^A_W_HG5.=9^6TR-:01$#[;B#[91!$2)YDB)W^@`````C47\@_@#=AB-
-M1?2#^`-V$(U%[(/X`W8(C47D@_@#=P=(@<.(%```00^V50!$B>9(B=_H````
-M`$''1E``````Z:,!``!!QT90_O___^F6`0``0<=&4/[____IB0$``(`Y!78W
-M@'D$_G4Q2(U4)$1(B[OP"```3(GVZ`````"$P`^%8@$``,=$)$0`````0<=&
-M4/_____I30$``$R+J_@(``!-A>U,#T3K2(G+N`(```!(*<A(B40D&$QC_NF<
-M````9F9FD&9FD`^V*TR-8@$/MM#VP@%T08M,)$2-1`T`03M&(`^'V@```(G)
-M2`-,)"!!B>B^`````$R)[^BX]___.>@/A;L````!;"1$3(GCZTQF9F:09F:0
-M2&/%2HT<($B+1"082`'83#GX#X^3````08GH3(GAO@````!,B>_H1?K__X7`
-M=7R`.P!U!H![`0!T"[\0)P``D.@`````2(U3`0^V0P&$P`^%6____P^V`X3`
-M=%</MMBY5````+H"````O@````!,B>_HFO#__XM,)$1!BT8@*<@YPP]'V(G)
-M2`-,)"!!B=BZ`````+X`````3(GOZ/_V__^%P'@&`40D1.L(0<=&4/____^Y
-M5````+H"````O@````!,B>_H1O#__V9FD&9FD$F+5CA(A=)T!HM$)$2)`DR)
-M]T'_5DA(@\1(6UU!7$%=05Y!7\-F9F:09F9FD&9FD$B#[`A(BX?X"```2(7`
-M2`]$QTB+N/`(```/MH=G%```A,!T#8/H`8B'9Q0``(3`=1W&!0``````N2``
-M``!(Q\(`````O@X```#H`````$B#Q`C#9F9FD&9FD&9FD&9FD$B#[`A(BX?X
-M"```2(7`2`]$QTB+N/`(``"`OV84````=22`AV<4```!Q@4``````;D@````
-M2,?"`````+X.````Z`````!(@\0(PV9FD&:02(/L&$B)7"0(3(ED)!!)B?Q(
-MB=!`#[;608G(2(G!O@````#HF/C__XG#N50```"Z`@```+X`````3(GGZ!_O
-M__^)V$B+7"0(3(MD)!!(@\08PY"0D)"0D)"0D)"0D)"0B?9(BT<(2"T``@$`
-M2`'&BP:)!0````##9F9FD&9F9I")]DB+1PA(+0`"`0!(`<:)%L-F9F:09F9F
-MD&9FD&9FD%-(B?M(BU<(2('J``(!`,>"@``!``````"+@@0!`0")!0````"`
-MS`&)@@0!`0"Z"````+X,P@``Z`````"ZN`L``+X(P@``2(G?Z`````"Z`0``
-M/+X`P@``2(G?Z`````"Z"````+X,PP``2(G?Z`````"ZN`L``+X(PP``2(G?
-MZ`````"Z`0``/+X`PP``2(G?Z`````"Z@("`@+XXP@``2(G?Z`````"Z"!@H
-M.+X@P@``2(G?Z`````"Z@("`@+X\P@``2(G?Z`````"Z"1DI.;XDP@``2(G?
-MZ`````"Z@("`@+Y`P@``2(G?Z`````"Z"AHJ.KXHP@``2(G?Z`````"Z@("`
-M@+Y$P@``2(G?Z`````"Z"QLK.[XLP@``2(G?Z`````"Z@("`@+Y(P@``2(G?
-MZ`````"Z2$E*2[XPP@``2(G?Z`````"Z@("`@+XXPP``2(G?Z`````"Z#!PL
-M/+X@PP``2(G?Z`````"Z@("`@+X\PP``2(G?Z`````"Z#1TM/;XDPP``2(G?
-MZ`````"Z@("`@+Y`PP``2(G?Z`````"Z#AXN/KXHPP``2(G?Z`````"Z@("`
-M@+Y$PP``2(G?Z`````"Z#Q\O/[XLPP``2(G?Z`````"Z@("`@+Y(PP``2(G?
-MZ`````"Z3$U.3[XPPP``2(G?Z`````#'0U2`@("`QT-8@("`@,=#7("`@(#'
-M0V"`@("`QT-D@("`@$B-@X@4``#'0%2`@("`QT!8@("`@,=`7("`@(#'0&"`
-M@("`QT!D@("`@%O#9I!(BU<(2('J``(!`(N";``!`(D%`````(F";``!`,-F
-MD$B+5PA(@>H``@$`BX)H``$`B04`````"?")@F@``0##55-(B?N)\4@YO_`(
-M```/A;P```")\,#H`D&X`````)`/MO")R/?0@^`#C3S%`````+@'````B?G3
-MX/?01(M,LU1!(<%$B4RS5(32=`ZX`0```-/@1`G(B42S5$$/ML")Q<'E"(M3
-M5(VU.,(``$B+N_`(``#H`````(M36(VU/,(``$B+N_`(``#H`````(M37(VU
-M0,(``$B+N_`(``#H`````(M38(VU1,(``$B+N_`(``#H`````(M39(VU2,(`
-M`$B+N_`(``#H`````%M=PXGPP.@"@^@%0;@!````Z3W___]F9F:09F:09F:0
-M9F:005=!5D%505154TB#[`A(B?U!B?9!B==!B<U(BT<(3(L@3(GGZ`````!(
-MB<-(A<`/A.L```!,B>?H`````$B)PDB%P`^$UP```,9%7`'&0SCAQD,Y`<9#
-M.A#&0R6[#[9%6V:)0R!,B6,HQT,TD````$B-0A!(B4-(2(E3>$B)P4B)PK@`
-M````Q@00`$B#P`%(/9````!U\,9!`8+&`4!$B'$"1(AY`T2(:01!@/T"=R%(
-MC7D(2HT4K0````"!XOP#``!)C;0DH!(``.@`````ZRM)BX0DH!(``$B)00A(
-MC7D000^VU8T4E?C___](8]))C;0DJ!(``.@`````2,>#H`````````!(C7M8
-MO@````#H`````$B)WDR)Y^@`````2(/$"%M=05Q!74%>05_#D$B#[#A(B5PD
-M"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!(B?U!B?5!B=9!B<](BT<(3(L@
-M3(GGZ`````!(B<-(A<!T>TR)Y^@`````2(G"2(7`=&O&15P!QD,XX<9#.0'&
-M0SH0QD,ENP^V15MFB4,@3(EC*,=#-)````!(C4(02(E#2$B)4WC&0`$"QD(0
-M0$2(:`)$B'`#1(AX!$C'@Z``````````2(U[6+X`````Z`````!(B=Y,B>?H
+MN@$```#I&`0```^V1T%)BU0D(`^V4@B-!(*-!(`/ME9Q`=!(F`^VB``````/
+MME<Z#[9W.4C'QP````"X`````.@`````2(MK4$R+90!,B>?H`````$B)P4B%
+MP'41QH/!`````;H!````Z;0#``#&0#CAQD`Y`<9`.A@/MT,X9HE!($B+10!(
+MB4$HQT$T`````$C'04@`````2,>!H`````````!(B<Y,B>?H`````+H!````
+MZ6D#``!,B>?H'//__[H!````Z5<#``!)BRPD2(GOZ`````!(B<$/MD-D2(7)
+M=1'&@\$````!N@$```#I+@,``,9!..'&03D!QD$Z!8A!.P^W0SAFB4$@28L$
+M)$B)02C'030`````2,=!2`````!(QX&@`````````$B)SDB)[^@`````N@$`
+M``#IX`(``$F++"1(B>_H`````$B)P0^V0V5(A<EU$<:#P0````&Z`0```.FW
+M`@``QD$XX<9!.0'&03H$B$$[#[=#.&:)02!)BP0D2(E!*,=!-`````!(QT%(
+M`````$C'@:``````````2(G.2(GOZ`````"Z`0```.EI`@``28LL)$B)[^@`
+M````2(G!2(7`=1'&@\$````!N@$```#I1`(``,9`..'&0#D!QD`Z!@^W0SAF
+MB4$@28L$)$B)02C'030`````2,=!2`````!(QX&@`````````$B)SDB)[^@`
+M````N@$```#I^0$``&9F9I!)BRPD2(GOZ`````!(B<%(A<!U$<:#P0````&Z
+M`0```.G0`0``QD`XX<9`.0'&0#H,#[=#.&:)02!)BP0D2(E!*,=!-`````!(
+MQT%(`````$C'@:``````````2(G.2(GOZ`````"Z`0```.F%`0``28LL)$B)
+M[^@`````2(G!2(7`=1'&@\$````!N@$```#I8`$``,9`..'&0#D!QD`Z%L9`
+M/`$/MT,X9HE!(,:!F`````])BP0D2(E!*,=!-`````!(QT%(`````$C'@:``
+M````````2(G.2(GOZ`````"Z`0```.D*`0``QD9*_V;'@[@``````(![2P)U
+M$DB+<U!(B=I,B>_H`````&9FD$'V1"0+`G47NP````!)C6PD0$&`?"0-`'4F
+MZ9,```!)BW0D*(!&10%,B>_H`````+H!````Z:L```!F9I!F9I!(B>_H````
+M`$B)PDF+1"1(28E4)$A(B2I(B4((2(D0@'I*_W1#@'I)`'4V@+K!`````'1<
+M#[9*2$B)R(/@!DB#^`9T3$B#^`1U1O;!`71!2(G63(GOZ`````"Z`0```.M$
+MQH+!`````(/#`4$X7"0-=XY!QD0D"?],B>9,B>_H`````+H!````ZQMF9I!F
+M9I"Z`0```.L.187V#X1V^O__Z8[Z__^)T$B+7"0(2(ML)!!,BV0D&$R+;"0@
+M3(MT)"A,BWPD,$B#Q#C#9F:09F:02(/L*$B)7"002(EL)!A,B60D($B)^TB)
+M]4B+=DA$#[9%.@^W32!F@?F#``^'B@,```^WP0^VO`=X!P``0(#__P^$=0,`
+M`&:#^7]W)$`/MM=(BXM("```2(T$TDB-!()(BT3!4`^V0`CK(69FD&9FD$`/
+MML=(BY-P"```2,'@"$B+A!"`````#[9`"#S_#X0H`P``#[;`#[:$`_P'```\
+M_W010(#__W0+1`^V321!@/D&=3X\_P^$``,``$"`__^0#X3U`@``0`^VQTB-
+M%,!(C1202,'B`TF)U$P#HT@(``!!QD0D2P)!QD0D2O_IOP(``$`/ML=(C13`
+M2(T4D$C!X@-)B=1,`Z-("```183)#X2N````08#X!@^$I````$&`^`P/A-@!
+M``!%#[9$)$H/MD-!28M4)%!(BU(@#[92"(T$@HT$@$$/ME0D<0'02)@/MH@`
+M````#[93.@^V<SE!#[>$)+@```")!"1%#[;)2,?'`````+@`````Z`````!!
+M#[>4)+@```"-0@%F08F$)+@```!F@_H!=AE!@'PD2@9T$4'&1"1+`D'&1"1*
+M_^G]`0``O^@#``#H`````.GN`0``08#X`74-0<9$)$H$9I#IVP$``$&`^`)U
+M"T'&1"1*!>G*`0``08#X`P^%$`$``$&`?"1*&G4@9H%^!,@W9I!U%F9!QX0D
+MN```````0<9$)$H&Z9@!``!,B>?H`````$F-O"2(````OB@```#HOM3__X3`
+M=4I)C7PD=+X4````Z*O4__^$P'4W28V\)+````"^"````.B5U/__A,!U(4F#
+M?"1H`'099D''A"2X``````!!QD0D2A?I,P$``&9FD`^V0T%)BU0D4$B+4B`/
+MME((C02"C02`00^V5"1Q`=!(F`^VB``````/ME,Z#[9S.44/MX0DN````$C'
+MQP````"X`````.@`````9D&#O"2X````'7810<9$)$L"0<9$)$K_Z<D```"_
+MZ`,``.@`````9D&#A"2X`````>FP````08#X%W469D''A"2X``````!!QD0D
+M2A7IE````$&`^!AU$V9!QX0DN```````0<9$)$H6ZWM!@/@$=1-F0<>$)+@`
+M`````$'&1"1*!^MB08#X!7439D''A"2X``````!!QD0D2@CK24&`^`9U$V9!
+MQX0DN```````0<9$)$H)ZS!!@/@,=1-F0<>$)+@``````$'&1"1*"NL708#X
+M%G419D''A"2X``````!!QD0D2A1,B>9(B=_H`````$B#?7``=`Q(C75P2(G?
+MZ`````!(B>Y(B=_H`````$B+7"002(ML)!A,BV0D($B#Q"C#9F:02(/L&$B)
+M'"1(B6PD"$R)9"0028G\2(GU2(N^@`````^W3DKVP2!(Q\(`````2,?`````
+M`$@/1="`?D(:#X>^!```#[9&0O\DQ0`````/ME9%#[9&.CC"#X-5!```#[;"
+M2(MTQEA(A?8/A#8$``#I&@0``,9&0@'&144`2<?!`````$&X`````+D"````
+MN@$```"^`````$B)[^@`````N`````#I7`0``$G'P0````!!N`````"Y````
+M`+H!````O@````!(B>_H`````+@`````Z2X$``!)Q\$`````0;@`````N0$`
+M``"Z`0```+X`````2(GOZ`````"X`````.D`!```2<?!`````$&X`````+E@
+M````N@$```"^`````$B)[^@`````N`````#IT@,``$G'P0````!$#[9&1KE@
+M````N@$```"^`0```$B)[^@`````N`````#II0,``$G'P0````!!N````02Y
+M(0```+H!````O@$```!(B>_H`````+@`````Z7<#``!)Q\$`````0;@!````
+MN0(```"Z`````+X!````2(GOZ`````"X`````.E)`P``2<?!`````$&X````
+M`+D"````N@````"^`0```$B)[^@`````N`````#I&P,``$F)T4&X`````+D`
+M````N@````"^`````$B)[^@`````N`````#I\0(``$B+1R"!8#3___;_2<?!
+M`````$&X_____[D!````N@````"^`0```$B)[^@`````N`````#IN`(``$0/
+MMDY%2(M'($0/MD`(00^V1"1!08T$@(T$@$0!R$B8#[:(`````$$/ME0D.D$/
+MMG0D.4C'QP````"X`````.@`````#[9%14B+=,582(N]@````$G'P`````"Y
+M`````+H!````Z`````"X`````.E$`@``#[9&14B+=,982<?``````+D`````
+MN@````#H`````+@`````Z1L"``!(BT<@]T`T```)`'0&QD9"$.M.QH;Z````
+M`$B-GK@```!)BWPD*$B)WN@`````QX6X````0$(/`$C'A<@`````````2(FM
+MT````$F+?"0H2(G>Z`````"X`0```.FZ`0``]D5*('1L@WU0`'17QD5"$@^V
+M?3I`A/]T=HMU4+H`````N0````!`]L8!=1;K)F9F9I!F9I`/MLI(B?!(T_BH
+M`707B%5%2,?`_O___TC3P"%%4.L[N@````"#P@%`./IUU.LLQD5%`,9%0AEF
+M@V5*W^L=#[9%18/``8A%13I%.G(*QD5%`,9%0AGK!,9%0@M(B>Y,B>?H````
+M`+@!````Z18!``!)Q\$`````0;@`````N2````"Z`0```+X`````2(GOZ```
+M``"X`````.GH````2<?!`````$&X`````+D!````N@````"^`````$B)[^@`
+M````N`````#IN@```$G'P0````!!N/____^Y`0```+H`````O@$```!(B>_H
+M`````+@`````Z8P```!F9F:09F:0#[;"2(MTQ5A(A?9T%\9&2AK&1DL&3(GG
+MZ`````"X`0```.MA@\(!B%5%#[9%.CC0=\XXPG5*QD5%`,9%0A%(B>Y,B>?H
+M`````+@!````ZS6)R(/(`F:)1DK&1D(`2(N&@````,9`"?](B[:`````3(GG
+MZ`````"X`0```.L'9I"X`0```$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F9F
+MD$B#[!A(B1PD2(EL)`A,B60D$$B)_4R+)TB+AX````!(BU`@]T(T```)`'5+
+M#[:'^@```#P*=EE$#[9/140/MD((00^V1"1!08T$@(T$@$0!R$B8#[:(````
+M`$$/ME0D.D$/MG0D.4C'QP````"X`````.@`````QD5"$$B)[DB+?0#H````
+M`.M-9F9FD&9FD(/``8B'^@```$B-G[@```!)BWPD*$B)WN@`````QX6X````
+M0$(/`$C'A<@`````````2(FMT````$F+?"0H2(G>Z`````!(BQPD2(ML)`A,
+MBV0D$$B#Q!C#9F9FD&9FD$%6055!5%532(/L$$F)_$F)]0^W5B!F@?J#`'=9
+M#[?"#[:$!W@'```\_W1*9H/Z?W<@#[;`2(T4P$B-%)!(P>(#2`.72`@``$B+
+M0E`/ME`(ZRD/MT8@#[:$!W@'``!(P>`(2`.'<`@``$B+@(`````/ME`(ZP6Z
+M_____[G_____9D&!?2"#`'<.00^W12!!#[:,!'@'```/ML)!#[:$!/P'``!(
+MB<)(P>('2(V$PE`!``!-C70$"`^VP4C!X`A)BZPD<`@``$@!Q4&`?20`#X2R
+M````#[9]140/MD5"28M&($0/MD@(00^V3"1!08T,B4$/ME0D.D$/MG0D.8D\
+M)$C'QP````"X`````.@`````@'TZ`'0JNP````!F9I!FD`^VPTB+5,582(72
+M=`M,B?9,B>?H`````(/#`3A=.G?@28-]<`!T#$F-=7!,B>?H`````$R)[DR)
+MY^@`````9H--2@+&14(`2(N%@````,9`"?](B[6`````3(GGZ`````#IM0$`
+M`$F+E"0@"P``2('"0`@```^V14S!X`A(F$@!PHL"B04`````28N4)"`+``!(
+M@<)$"```#[9%3,'@"$B82`'"BPJ)#0````!)BY0D(`L``$B!PD@(```/MD5,
+MP>`(2)A(`<*+`HD%`````$F+E"0@"P``2('"3`@```^V14S!X`A(F$@!PHL2
+MB14`````#[9%0CP1="L\$7<-/`L/A?\```#IIP```#P29F:0='X\$P^%ZP``
+M`&9FD&9FD.F#````B<C!X`@+15`/MM()T(E%4+H`````@'TZ`'0^N@````"Y
+M`````/9%4`%U#^L?#[;*BT502-/XJ`%T%XA514C'P/[___](T\`A15#K#;H`
+M````@\(!.%4Z=]0X53H/E,"-!,42````B$5"ZW6)R,'@"*D```$$=`;&14(3
+MZV/&14(+ZUW&14(+9F9FD.M32(N%@````$B+0""!8#3___?_QD5"$(G0@^`/
+M@_@#=1H/MD5%2(M$Q5A(A<!T!O9`3!!T'\9%0@SK&0^V145(BU3%6$B%TG0+
+M3(GV3(GGZ`````!,B>Y,B>?H`````$B)[DR)Y^@`````2(/$$%M=05Q!74%>
+MPV9F9I!F9F:02(/L"$B)_DB+/^@`````2(/$",-F9F:09F9FD&9F9I!(@^P(
+MQD=""$B)_DB+/^@`````2(/$",-F9F:09F9FD$B#[`C&1T(.2(G^2(L_Z```
+M``!(@\0(PV9F9I!F9F:055-(@^P(2(G[2(LOZ`````"$P'09#[9U0T"$]G0T
+M#[93#+D`````]L(!=![K),9#"?](B=Y(B>_H`````.M?D$B)T$C3^*@!=0B#
+MP0%`./%U[DB)[^@`````2(G&2(7`=#Q(BU-(2(E#2$B-0T!(B09(B58(2(DR
+M@$,-`4B)7E#&1D@%QD9)`,9&<0^Y`0```+H!````2(G?Z`````!(@\0(6UW#
+M9F9FD&9F9I!F9I!!54%455-(@^P(2(G]28GT3(LONPH```!,B>9(B>_H````
+M`(3`=0^_Z`,``.@`````@^L!=>)!#[9U0T"$]G0B#[95#+D`````]L(!=`SK
+M$DB)T$C3^*@!=0B#P0%`./%U[DF+%"1)BT0D"$B)0@A(B1"`;0T!3(GF3(GO
+MZ`````#V10L"=$9(BW4H2(7V=1A,B>_H`````$B)QDB%P`^$4`$``$B)12A,
+MB2Y(B:Z`````QD9%`,9&0@!FQT9*`0!,B>_H`````.DG`0``2(M%*$B%P`^$
+MN0```$B-L+@```!)BWTHZ`````!(BW4H3(GOZ`````!,C65`3#EE0`^$AP``
+M`$R)Y^@`````2(G#2(M`0$B%P'1:2,=`:`````#V0TP$=1I,B>_H`````$B+
+M<T"Z`0```$R)[^@`````D$B+4T!)B[4`"```OP$```#H`````$B+4T!)B[4`
+M"```OP8```#H`````$C'0T``````@&T-`4B)WDR)[^@`````3#EE0`^%>?__
+M_TC'12@`````@'T-`'022(U]0.@`````2(G!@&T-`>L+3(GOZ`````!(B<%(
+MA<ET.4B+54A(B4U(2(U%0$B)`4B)40A(B0J`10T!2(EI4,9!2`7&04D`QD%+
+M!L9!2@-(B<Y,B>_H`````$B#Q`A;74%<05W#D$B#["A(B5PD"$B);"003(ED
+M)!A,B6PD($B)_4B)\P^W3B!F@?F#`'=?#[?!#[:T!W@'``!`@/[_=$YF@_E_
+M=QY`#[;62(N/2`@``$B-!-)(C02"2(M$P5`/MD`(ZQM`#[;&2(N7<`@``$C!
+MX`A(BX00@`````^V0`A`#[;6//]T!V:!^O\`=1!(B=Y(B>_H`````.E.`0``
+M#[;`#[:,!?P'```/M\)(C13`2(T4D$C!X@-)B=5,`ZU("```@'LD``^$N@``
+M`$B)R$C!X`=(C03(3(VD!5`!``!!#[9,)!0/ME,[#[9S.D4/MD0D%4C'QP``
+M``"X`````.@`````28M5`$F+10A(B4((2(D008!L)!4!3(GN2(GOZ`````!(
+MB=Y(B>_H``````^V?4-`A/\/A+````!!#[9T)!2Y`````$#VQ@%U%NL@9F9F
+MD&9FD`^VRDB)\$C3^*@!=!.)SDB)[^@`````ZWVZ`````&:0@\(!0#CZ==CK
+M;&9FD&9FD$B)R$C!X`=(C83(4`$``$R-9`4(@'LZ`74LOQ`G``#H`````$B)
+MWDB)[^@`````N0$```"Z`````$R)[DR)Y^@`````ZR"_4,,``.@`````2(G>
+M2(GOZ`````!,B>Y,B>?H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,.0
+M059!54%455-(@^P028G\28GU#[=6(&:!^H,`=UD/M\(/MH0'>`<``#S_=$IF
+M@_I_=R`/ML!(C13`2(T4D$C!X@-(`Y=("```2(M"4`^V4`CK*0^W1B`/MH0'
+M>`<``$C!X`A(`X=P"```2(N`@`````^V4`CK!;K_____N?____]F08%]((,`
+M=PY!#[=%($$/MHP$>`<```^VPD$/MH0$_`<``$B)PDC!X@=(C83"4`$``$V-
+M=`0(00^V13J#Z`&[`````#P!=QH/ML%(C13`2(T4D$C!X@-)BYPD2`@``$@!
+MTTF+;BA!@'TD``^$+P$``$F#?7``=`Q)C75P3(GGZ`````!,B>Y,B>?H````
+M`$$/ME4ZC4+_/`%W=(#Z`4`/E,=`#[;_28M&($0/MD`(1`^V345!#[9$)$%!
+MC02`C02`1`'(2)@/MH@`````00^V5"0Z00^V="0YB3PD2,?'`````+@`````
+MZ`````!(B=I,B?9,B>?H`````,9%0A!(B>Y,B>?H`````.E1!```#[9]140/
+MMD5"28M&($0/MD@(00^V3"1!08T,B4$/ME0D.D$/MG0D.8D\)$C'QP````"X
+M`````.@`````@'TZ`'0ENP`````/ML-(BU3%6$B%TG0+3(GV3(GGZ`````"#
+MPP$X73IWX&:#34H"QD5"`$B+A8````#&0`G_2(NU@````$R)Y^@`````Z<(#
+M``!FD`^V14*#Z`VZ`````+D`````/`$/AHP```!)BY0D(`L``$B!PD`(```/
+MMD5,P>`(2)A(`<*+`HD%`````$F+E"0@"P``2('"1`@```^V14S!X`A(F$@!
+MPHL*B0T`````28N4)"`+``!(@<)("```#[9%3,'@"$B82`'"BP*)!0````!)
+MBY0D(`L``$B!PDP(```/MD5,P>`(2)A(`<*+$HD5``````^V14(\#@^'#P,`
+M``^VP/\DQ0````"#^@6X!0````]&PHA%.L9%0@+IP`(``(G(P>`(#[;2"=!F
+MB44\B<C!Z`AFB44^QD5"`^F@`@``B$TXB="H"'0&QD4Y#.L;J`1T!L9%.0OK
+M$8/@`DB#^`$9P/?0@^`*B$4YQD5"!.EM`@``B="#R`B(14;&14(%Z5P"``#&
+M14(&Z5,"``#&14('Z4H"```/MD5%@\`!B$5%.D4Z<U!)@WUP`'0,28UU<$R)
+MY^@`````3(GN3(GGZ`````#'A;@```"`A!X`2,>%R`````````!(B:W0````
+M2(VUN````$F+?"0HZ`````#I&0(``,9%10!(C9VX````28M\)"A(B=[H````
+M`$R)[DR)Y^@`````QX6X````0$(/`$C'A<@`````````2(FMT````$F+?"0H
+M2(G>Z`````#IR`$```^V146#P`&(144Z13H/A8<!``#&144`QD5'9,9%0@OI
+M=@$``,9%0@KI;0$``,9%0@OI9`$``$B+A8````!(BT`@@6`T___W_XG0@^`/
+M@_@#=0G&14(,Z3\!```/MD5'A,!T%8/H`8A%1[_H`P``Z`````#I(@$```^V
+M146#P`&(144Z13H/@@\!``#&144`QD5"&>D"`0``#[9%14B+1,582(7`=!Q(
+MB<&`8$SO2(L02(M`"$B)0@A(B1!!@&X-`>LV3(GGZ`````!(B<%(A<!U)DF#
+M?7``=`Q)C75P3(GGZ`````!,B>Y,B>?H`````.G3````9F:0QD5"#0^V145(
+MB4S%6$R)<5!(B6E8#[9%18A!<<9!20"`24@%08!&#0%)C49`2(M0"$B)2`A(
+MB0%(B5$(2(D*ZV%(C9VX````28M\)"A(B=[H`````,>%N````%##``!(QX7(
+M`````````$B)K=````!)BWPD*$B)WN@`````28-]<`!T#$F-=7!,B>?H````
+M`$R)[DR)Y^@`````ZS+&14(/28-]<`!T#$F-=7!,B>?H`````$R)[DR)Y^@`
+M````2(GN3(GGZ`````!F9I!FD$B#Q!!;74%<05U!7L.0D)"#X@?!X@B`SB!(
+MBT<(2"WD/```2,'F"('F`/\``$@!\(D0#[<`9HD%``````^VP,.#X@?!X@B(
+MRH#.$$B+1PA(+>0\``!(P>8(@>8`_P``2`'PB1##9F9FD&9F9I!F9I!54[T`
+M````NP````!!N?____]!NP````!%B=I!@\,!N`$```!!B<!$B=E!T^!$B<&^
+M`````+C`X>0`N@````#W\3GX=Q&)^BG"1#G*<PA$B=6)\T&)T8/&`40!P8/^
+M$'7408/["'6QC03=``````GH#[;`6UW#9F9FD&9FD&9FD$B#[!!(B1PD3(ED
+M)`A)B?Q`#[;>N0````"Z!P```(G>Z"O___]!#[:,)%$,``"Z`P```(G>3(GG
+MZ!/___](BQPD3(MD)`A(@\00PV9FD&:04XGS#[;RN@,```#HP/[__SC8#Y3`
+M#[;`6\-F9I!F9I!(A?]T-;H`````9F:09F:0#[:$.O@'```/ML@\_W01#[?!
+M2,'@"$@#AW`(``##9I!(@\(!2(/Z!'76N`````##55-(BY\("```2(7;2`]$
+MW[T`````N0````"Z!P```(GN2(G?Z'?^__^Y1````+H"````B>Y(B=_H8_[_
+M_[G0````N@````")[DB)W^A/_O__N0````"Z!````(GN2(G?Z#O^__^#Q0&#
+M_0)UJ+^@A@$`Z%G^__^(@U$,```/MLBZ`P```+X`````2(G?Z`[^__];7<-F
+M9F:09F9FD&9FD%-(B?MFQX?P`````0`/M_;!Y@WH`````+X4````2(G?Z```
+M``!;PV9FD&9FD&9FD$B#[`B)\832=1:X_O___]/`9B&'Z````.L49F:09F:0
+MN`$```#3X&8)A^@````/M[?H````Z`````!(@\0(PY!(@^PH2(E<)`A(B6PD
+M$$R)9"083(EL)"!)B?U!B=0/MJ[+````#[9>`DB+?G!(A?]T"P^VT@^V\^@`
+M````@/L#=Q"-%*N-1*L$0(#]`P]&PNL-C540C44@0(#]`P]&PD$/MM0/MO!,
+MB>_H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9I!F9I!F9I!!5%53
+M28G\NP````!`#[;NN@(```")[DR)Y^BQ_/__J`AT#;@`````ZR!F9I!F9I"_
+M`0```.@`````@\,!@?L0)P``=<NX_P```%M=05S#D$B#["A(B5PD"$B);"00
+M3(ED)!A,B6PD($B)_4F)S4&)U$`/MMZ)WNB$____A<!U,$$/MO2)VDB)[^AR
+M_?__A<!T'KH!````B=Y(B>_H+_S__T&(10"X`````.L)9F9FD+C_____2(M<
+M)`A(BVPD$$R+9"083(ML)"!(@\0HPV:02(/L*$B)7"0(2(EL)!!,B60D&$R)
+M;"0@2(G]08G-1`^VXD`/MMY$B>&Z`0```(G>Z/O[__^Y0````+H"````B=Y(
+MB>_HY_O__XG>2(GOZ-W^__^%P'5,187M=#1!]L0!=!6)VKY`````2(GOZ+_\
+M__^%P'0NZS.)VKX8````2(GOZ*K\__^%P'09ZQYF9F:0B=J^*````$B)[^B1
+M_/__A<!U![C_````ZP:X`````)!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#
+M9F9FD&9FD$%7059!54%455-(@^P(28G]2(D,)$6)QHGSB=6$T@^$\0```$0/
+MMOZY9````+H"````1(G^Z";[__]$B?Y,B>_H&_[__X7`=1"Z`P```$2)_DR)
+M[^C7^O__0`^VU;D!````1(G^3(GOZ,/^__]!O/____^$P`^%@P$``$&\````
+M`$6%]@^.=`$``$B+'"1!O`````!!C6[_1#GE=36Y0````+H"````1(G^3(GO
+MZ*[Z__])8\Q(`PPDNE@```!$B?Y,B>_HY_W__X7`=#7I+`$``+E$````N@(`
+M``!$B?Y,B>_H>?K__TB)V;I0````1(G^3(GOZ+;]__^%P`^%_````$&#Q`%(
+M@\,!13GT#X3K````ZX._H(8!`.AQ^O__#[;K#[;(N@,```")[DR)[^@L^O__
+MB>Y,B>_H(OW__X7`=")!#[:-40P``+H#````B>Y,B>_H!_K__T&\_____^F:
+M````B>J^8````$R)[^CM^O__A<!T#4&\`````$6%]GYEZQ]!#[:-40P``+H#
+M````B>Y,B>_HQ?G__T&\_____^M;2(L<)$&\`````&9FD+E$````N@(```")
+M[DR)[^B<^?__2(G9NH````")[DR)[^C:_/__A<!U#4&#Q`%(@\,!13GT=<E!
+M#[:-40P``+H#````B>Y,B>_H8OG__T2)X$B#Q`A;74%<05U!7D%?PTB#[!A(
+MB5PD"$R)9"0028G\2(G00`^VUD&)R$B)P;X!````Z,C]__^)P[E4````N@(`
+M``"^`0```$R)Y^@/^?__B=A(BUPD"$R+9"002(/$&,-F9F:09F9FD&9FD&9F
+MD$B#[!A(B5PD"$R)9"0028G\2(G00`^VUD&)R$B)P;X`````Z&C]__^)P[E4
+M````N@(```"^`````$R)Y^BO^/__B=A(BUPD"$R+9"002(/$&,-F9F:09F9F
+MD&9FD&9FD$%6055!5%5328G]2(G-18G&B=-$#[;FN60```"Z`@```$2)YNAG
+M^/__1(GF3(GOZ%S[__^%P'40N@,```!$B>9,B>_H&/C__P^VT[D!````1(GF
+M3(GOZ`7\__^$P'4V187V?CA(B>N]`````&9F9I`/MA.Y`````$2)YDR)[^C=
+M^___A,!U#H/%`4B#PP%$.?5T">O;N/_____K!;@`````6UU!7$%=05[#9F:0
+M9F:02(/L&$B)7"0(3(ED)!!)B?Q(B=!`#[;608G(2(G!O@````#H*/___XG#
+MN50```"Z`@```+X`````3(GGZ)_W__^)V$B+7"0(3(MD)!!(@\08PV9F9I!F
+M9F:09F:09F:02(/L"$B+AP@(``!(A<!(#T3'0(@U`````+D@````2,?"````
+M`+X.````2(G'Z`````!(@\0(PV9FD&9FD&9FD$B#[`B)\832=!:X`0```-/@
+M9@F'G`X``.L49F:09F:0N/[____3P&8AAYP.```/MK><#@``Z`````!(@\0(
+MPY!!5T%6055!5%532(/L&$B)^TF)]DB+3BA(@\$!BU8<@^H!2(M&,$B)1"00
+M#[9!`3P!=13'1E``````QT0D#`````#I<@(``#P"=5B`>0(!D'4]2(N'"`@`
+M`$B%P$@/1,=(BY``"```#[9!`XB"G@X```^V00.(@EX=``#'1E``````QT0D
+M#`````#I*@(``,=&4/[____'1"0,`````.D6`@``/`,/A;$```"`>0(!D`^%
+MD@````^V1SZ--``/MGD#B?J)^,'Z'_?^B=4YUGYC3(UI!$0/MN(/ME$$1(GF
+M2(G?Z`````"-1?R#^`-V&(U%](/X`W80C47L@_@#=@B-1>2#^`-W!TB!P\`.
+M``!!#[95`$2)YDB)W^@`````0<=&4`````#'1"0,`````.F&`0``0<=&4/[_
+M___'1"0,`````.EQ`0``QT90_O___\=$)`P`````Z5T!``!,BZ\("```387M
+M3`]$[TB)R\=$)`P`````N`(```!(*<A(B00D3&/ZZ:<```!F9F:09F:0#[8K
+M3(UB`0^VT/;"`71!BT0D#(U<!0!!.UX@#X?I````B<%(`TPD$$&)Z+X`````
+M3(GOZ-CY__\YZ`^%R@```(E<)`Q,B>/K5V9F9I!F9I!(8\5*C1P@2(L$)$@!
+MV$PY^`^/HP```$&)Z$R)X;X`````3(GOZ&;\__^%P`^%B````(`[`'4+@'L!
+M`&9FD&:0=`Z_$"<``.@`````9F9FD$B-4P$/MD,!A,`/A5#___^+;"0,#[8#
+MA,!T5P^VV+E4````N@(```"^`````$R)[^B;]/__08M&("M$)`PYPP]'V(GI
+M2`-,)!!!B=BZ`````+X`````3(GOZ!+Y__^%P'@(`>B)1"0,ZPA!QT90____
+M_[E4````N@(```"^`````$R)[^A']/__28M&.$B%P'0&BU0D#(D03(GW0?]6
+M2$B#Q!A;74%<05U!7D%?PV:02(/L"$B+AP@(``!(A<!(#T3'2(NX``@```^V
+MAY\.``"$P'0-@^@!B(>?#@``A,!U'<8%``````"Y(````$C'P@````"^#@``
+M`.@`````2(/$",-F9F:09F:09F:09F:02(/L"$B+AP@(``!(A<!(#T3'2(NX
+M``@``("_G@X```!U)("'GPX```'&!0`````!N2````!(Q\(`````O@X```#H
+M`````$B#Q`C#9F:09I!(@^P82(E<)`A,B60D$$F)_$B)T$`/MM9!B<A(B<&^
+M`````.BX^O__B<.Y5````+H"````O@````!,B>?H+_/__XG82(M<)`A,BV0D
+M$$B#Q!C#D)"0D)"0D)"0D)"0D)")]DB+1PA(+0`"`0!(`<:+!HD%`````,-F
+M9F:09F9FD(GV2(M'"$@M``(!`$@!QHD6PV9F9I!F9F:09F:09F:04TB)^TB+
+M5PA(@>H``@$`QX*```$``````(N"!`$!`(D%`````(#,`8F"!`$!`+H(````
+MO@S"``#H`````+JX"P``O@C"``!(B=_H`````+H!```\O@#"``!(B=_H````
+M`+H(````O@S#``!(B=_H`````+JX"P``O@C#``!(B=_H`````+H!```\O@##
+M``!(B=_H`````+J`@("`OCC"``!(B=_H`````+H(&"@XOB#"``!(B=_H````
+M`+J`@("`OCS"``!(B=_H`````+H)&2DYOB3"``!(B=_H`````+J`@("`OD#"
+M``!(B=_H`````+H*&BHZOBC"``!(B=_H`````+J`@("`OD3"``!(B=_H````
+M`+H+&RL[OBS"``!(B=_H`````+J`@("`ODC"``!(B=_H`````+I(24I+OC#"
+M``!(B=_H`````+J`@("`OCC#``!(B=_H`````+H,'"P\OB##``!(B=_H````
+M`+J`@("`OCS#``!(B=_H`````+H-'2T]OB3#``!(B=_H`````+J`@("`OD##
+M``!(B=_H`````+H.'BX^OBC#``!(B=_H`````+J`@("`OD3#``!(B=_H````
+M`+H/'R\_OBS#``!(B=_H`````+J`@("`ODC#``!(B=_H`````+I,34Y/OC##
+M``!(B=_H`````,=#4("`@(#'0U2`@("`QT-8@("`@,=#7("`@(#'0V"`@("`
+M2(V#P`X``,=`4("`@(#'0%2`@("`QT!8@("`@,=`7("`@(#'0&"`@("`6\-F
+MD$B+5PA(@>H``@$`BX)L``$`B04`````B8)L``$`PV:02(M7"$B!Z@`"`0"+
+M@F@``0")!0`````)\(F":``!`,-54TB)^XGQ2#F_``@```^%O````(GPP.@"
+M0;@`````D`^V\(G(]]"#X`.-/,4`````N`<```")^=/@]]!$BTRS4$$AP42)
+M3+-0A-)T#K@!````T^!$"<B)1+-000^VP(G%P>4(BU-0C;4XP@``2(N[``@`
+M`.@`````BU-4C;4\P@``2(N[``@``.@`````BU-8C;5`P@``2(N[``@``.@`
+M````BU-<C;5$P@``2(N[``@``.@`````BU-@C;5(P@``2(N[``@``.@`````
+M6UW#B?#`Z`*#Z`5!N`$```#I/?___Y"0D)"0D)"0D)"0D)!)B=%,BY=("```
+M#[=&(+K8)@$`9CV#`'<7#[?`#[:$!W@'``!(C13`2(T4D$C!X@--C8$@!```
+M0<:!(`0``"=F@7XXX0%U*40/MDXZ08U!_SP!=PQ!N0\```!$(DX[ZRM!C4'O
+M0;D/````/`%V'6:028T$$D&Y`````$B#>%@`=`I!N0\```!$(DAQ00^V0`&#
+MX/!$"<A!B$`!N`$```!F@7XXX0%U#P^V1CJ#Z`$\`0^7P`^VP(G"P>('00^V
+M0`&#X'\)T$&(0`$/MD$&08A``@^V`4&(0`,/MD$%08A`!P^V00=!B$`/#[9!
+M`D&(0`0/MD$#08A`!0^V001!B$`&#[9!`4&(0`P/MD$*08A`"`^V00M!B$`)
+M#[9!#$&(0`H/MD$(08A`"P^V00E!B$`-PV9F9I!F9F:09F9FD&9FD,9')`)(
+MBT=00(AP`DB+1U#&0`<`2(M'4(A0#,-F9F:0#[9'/8A&`@^V1SR(1@,/MD<[
+MB$8$#[9'.HA&"L-F9I`/MD=!B$8"#[9'0(A&`P^V1S^(1@0/MD<^B$8*#[9'
+M/8A&"P^V1SR(1@S#9F:09I"%TGXAN0````!F9F:09F:0B=`IR(/X`@^=P`^V
+MP(U,`0$YRG_K\\-F9I!F9I!F9I!(@^P@2(D<)$B);"0(3(ED)!!,B6PD&$B)
+M^TB)U0^V1S@\*G0C/"IW"CPH#X6E````ZQ4\B'0I/(IF9F:09F:0#X60````
+MZQA$#[9C0$0/MFL_2(GN2(G?Z`````#K%I!$#[9C140/MFM$2(GN2(G?Z```
+M``#&105`BX.4````J0```0!U4*D```0`="5$B&4!1(AM"0^V0S@\*'0$/(AU
+M!L9%!B7K+\9%!C5F9I!FD.LD1(AE`0^V0SJ#X`\(104/MD,X/"AT!#R(=0;&
+M10;(ZP3&10;*2(L<)$B+;"0(3(MD)!!,BVPD&$B#Q"##9I`/MD<Z"D<["D<\
+M"D<]#[;`#[970(/B`0G0=!6Z)````+X%````Z`````#SPV9F9I#&1@;L2,>'
+MH`````````##2(/L($B)'"1(B6PD"$R)9"003(EL)!A(B?M(B?4/MD<X/"]T
+M"SR/=5GK%V9FD&:01`^V9T!$#[9O/^@`````D.L/1`^V9T5$#[9O1.@`````
+MQD4%0/:#E@````1T$D2(90%$B&T)QD4&0NL69F9FD$2(90$/MD,Z@^`/"$4%
+MQD4&0$B+'"1(BVPD"$R+9"003(ML)!A(@\0@PV9FD&9FD$B)\<9"!4`/MD8X
+M/#5T!CR1=2/K&P^W1V"#X`&#^`$9P(/@_8/H%HA"!NLD9F9FD,9"!NKK&KHD
+M````O@4```!(B<_H`````//#9F:09F:0]D$Y`G0$QD$D`//#9F9FD/9'//!T
+M#[HD````O@4```#H`````//#9F:09F:09F:02(/L"$F)\+@`````9F9FD,8$
+M"`!(@\`!2(/X#77R00^V0#@\-0^$G0```#PU=RD\*'1B/"AW#CP;#X6"`P``
+MD.F;````/"IT3#PO9F:09I`/A6L#``#K6#R/9F:09F:0=$X\CW<2/(AT*SR*
+M9F9FD`^%2P,``.L=/)%F9I!F9I!T1CSA#X4W`P``9F:09F:0Z80````/MO)(
+MB<I,B<?H`````,=$)`0!````Z1D#``!(B<Y,B<?H`````,=$)`0!````Z0$#
+M``!(B<I,B<;H`````,=$)`0!````Z>D"``!!]D`\`70AQD$&<,9!!`#&00,`
+MQD$"`,9!!4#'1"0$`0```.G!`@``QD$&X,=$)`0!````Z;`"``!!@'@Y`0^%
+MG0(``$&`>#H<#X>2`@``00^V0#K_),4`````QD$'!,=$)`0!````Z7T"``#&
+M00<`QT0D!`$```#I;`(``,9!!NS'1"0$`0```.E;`@``QD$&[\8!`T$/MD`[
+M@\A`B$$!QT0D!`$```#I/`(``,9!!N_&`0?'1"0$`0```.DH`@``QD$&0,9!
+M`0'&005`QT0D!`$```#I#P(``,9!!N_&`0-!#[9`.X/("(A!`<=$)`0!````
+MZ?`!``#&00;OQ@$"QT0D!`$```#IW`$``,9!!N_&`8+'1"0$`0```.G(`0``
+MQD$&[\8!!L=$)`0!````Z;0!``#&00;OQ@&&QT0D!`$```#IH`$``,9!!N-!
+M#[9`.XA!`<=$)`0!````Z8<!``#&00:PQ@'8QD$#3\9!!,+'1"0$`0```.EK
+M`0``QD$&L,8!V<9!`T_&003"QT0D!`$```#I3P$``,9!!K#&`=K&00-/QD$$
+MPL=$)`0!````Z3,!``#V1V`!=!'&00;JQT0D!`$```#I'`$``,9!!N?'1"0$
+M`0```.D+`0``QD$&[\8!JL=$)`0!````Z?<```#&00;OQ@%5QT0D!`$```#I
+MXP```,9!!N1!#[9`/(@!00^V0#V(00A!#[9`.XA!!<=$)`0!````Z;L```!!
+M#[9`.XA!!D$/MD`\B`%!#[9`/8A!`D$/MD`^B$$#00^V0#^(001!#[9`08A!
+M"D$/MD!`B$$!QT0D!`$```#K>L9!!NA!#[9`/(@!00^V0#V(00A!#[9`.XA!
+M!4$/MD`^B$$"00^V0#^(00-!#[9`0(A!!$$/MD!!B$$!QT0D!`$```#K-<=$
+M)`0!````0?9`/`%T)L9!!G#&000`QD$#`,9!`@#&005`QT0D!`$```#K",=$
+M)`0`````BT0D!$B#Q`C#9F9FD&9F9I!F9I!F9I!32(/L($B)\TB+3DA(QP0D
+M`````$C'1"0(`````$C'1"00`````$C'1"08`````/:!IP````1T#4B+D<@`
+M``!(@^H!ZP:+47B#Z@&`>S@E=6%(B=!(P>@8B`0D2(G02,'H$(A$)`%(B=!(
+MP>@(B$0D`HA4)`/V@=4````0=13&1"0&`L9$)`<`N`@```#IK@```$B-?"0$
+M2(VQZ@```+H$````Z`````"X"````.F.````2(G02,'H.(@$)$B)T$C!Z#"(
+M1"0!2(G02,'H*(A$)`)(B=!(P>@@B$0D`TB)T$C!Z!B(1"0$2(G02,'H$(A$
+M)`5(B=!(P>@(B$0D!HA4)`?V@=4````0=17&1"0*`L9$)`L`N"````#K)&9F
+M9I!(C7PD"$B-L>H```"Z!````.@`````N"````!F9I!FD$B+>TA(8]!(B>;H
+M`````$B#Q"!;PV9F9I!F9F:09F:02(/L"`^V1C@\-0^$E0```#PU=RX\*'10
+M/"AW%CP29I!T1CP;#X66````9F:09F:0ZW,\*G0R/"\/A8(```!FD.LF/(]T
+M(CR/=PX\B&9F9I!T%CR*=6KK$#RP9F:09F:0='4\X75:ZQOV1V`!9F9FD'1E
+M@8Z4```````$`+@!````ZUF`?CD!=4>`?CH<=T%(#[Y..K@!````2-/@J?X_
+MQAUU-.LK]D=@`70L@8Z4```````$`+@!````ZR!F9F:02(GWZ`````"X````
+M`.L-D+@`````ZP6X`0```$B#Q`C#D)"0D)"0D)"0D)"0D)"02(M_"$4/ML!!
+MP>`$#[;2P>((00G01(G`@\@$A,E$#T7`08/Y_W092(V7`/[^_T2)R"7__P,`
+MB8($R```08/(`D2)!L-F9F:09F9FD&9F9I!(BT<(2"T``@$`@\X!B;``R```
+MPV9F9I!F9F:09F9FD$%455-!B?1(BT<(A?9T3$@M``(!`$B-J`#(``"+@`#(
+M``")!0````"[`````*@!=0_K(8M%`(D%`````*@!=!2_"@```.@`````@\,!
+M1#GC=>'K![@`````ZP6X_____UM=05S#9F9FD&9F9I!F9I!54TB#[!A(B?O'
+M1"04`````$B+;PC&AZ`.````#[85`````$B-="040;D`````0;@"````N0$`
+M``#HXO[__XMT)!1(B=_H)O___[Z@A@$`2(G?Z#G___^%P'552(V%`/[^_XN`
+M#,@``(D%`````(E$)!0]'V,``'4WQX.0#@``'V,``,>#E`X`````!`#'@Y@.
+M``````$`2,>#J`X```````!FN```Z5<"``!F9I!FD,=$)!0`````2(MK",:#
+MH`X```$/MA4`````2(UT)!1!N?____]!N`(```"Y`0```$B)W^@X_O__BW0D
+M%$B)W^A\_O__OA`G``!(B=_HC_[__X7`=6Y(C84`_O[_BX`,R```B04`````
+MB40D%#T?0P``="T]'T0``'5)QX.0#@``'T0``,>#E`X`````!P#'@Y@.````
+M``$`Z9,!``!F9I#'@Y`.```?0P``QX.4#@`````$`,>#F`X``````0#I;0$`
+M`,=$)!0`````2(MK",:#H`X````/MA4`````2(UT)!1!N0````!!N`(```"Y
+M`0```$B)W^AU_?__BW0D%$B)W^BY_?__OA`G``!(B=_HS/W__X7`=5!(C84`
+M_O[_BX`,R```B04`````B40D%#V_0P``=3+'@Y`.``"_0P``QX.4#@`````@
+M`,>#F`X````0``!(QX.H#@```````&:X``#IZ@```,=$)!0`````2(MK",:#
+MH`X````/MA4`````2(UT)!1!N0````!!N`(```"Y`0```$B)W^C0_/__BW0D
+M%$B)W^@4_?__OA`G``!(B=_H)_W__X7`=6=(C84`_O[_BX`,R```B04`````
+MB40D%#WO$0``=`D][Q(``'5"ZR#'@Y`.``#O$0``QX.4#@`````$`,>#F`X`
+M`````0#K/L>#D`X``.\2``#'@Y0.``````@`QX.8#@`````!`.L>N/_____K
+M)V9FD&:02,>#J`X```````"X`````.L02,>#J`X```````"X`````$B#Q!A;
+M7<-F9F:09F:02(/L*$B)7"002(EL)!A,B60D($B)^XGW28G42(MK"(#Y!+@$
+M````#T?(2(N#J`X```^V4`1(C70D#$&)^40/ML&Y`0```$B)W^C"^___BW0D
+M#$B)W^@&_/__OA`G``!(B=_H&?S__[K_____A<!U($B-A0#^_O^+@`S(``")
+M!0````")1"0,08D$)+H`````B=!(BUPD$$B+;"083(MD)"!(@\0HPV9F9I!F
+M9I!F9I!54TB#[!A(B?M(B=5(BX>H#@``#[90"TB-1"0408GQ0;@!````N0$`
+M``!(B<;H+OO__XMT)!1(B=_H<OO__[X0)P``2(G?Z(7[__^Z_____X7`=1I(
+MBT,(2"WT.0``BP")!0````"(10"Z`````(G02(/$&%M=PV9FD&9FD&9FD$%7
+M059!54%455-(@^P82(G[08G-08GW08G6A<D/A(X```"]`````$R+8PA(BX.H
+M#@``#[90`D&Y_____T&X`0```+D!````2(UT)!1(B=_HC/K__XMT)!1(B=_H
+MT/K__[X0)P``2(G?Z./Z__^%P'4I28V$)`#^_O^+D`S(``")%0````!$B?@A
+MT$0X\'4'N`````#K'XE4)!2_"@```.@`````@\4!1#GM#X5W____N/____](
+M@\086UU!7$%=05Y!7\-F9F:09F9FD&9F9I!32(/L$$B)^TB+AZ@.```/MA!(
+MC70D#$&Y_____T&X`````+D`````Z./Y__^+="0,2(G?Z"?Z__^^$"<``$B)
+MW^@Z^O__A<!U)KG@DP0`N@(```"^`P```$B)W^C/_O__N@````"%P'0+9F:0
+M9F:0NO____^)T$B#Q!!;PV9FD$B#["A(B5PD&$B);"0@2(G[B?7&1"07_TB-
+M5"07Z`````"%P'5R@'PD%P!T<TB)W^A+____@_C_=%Y(BX.H#@``#[90"DB-
+M="0008GI0;@`````N0````!(B=_H,/G__XMT)!!(B=_H=/G__[X0)P``2(G?
+MZ(?Y__^%P'4;N>"3!`"Z`````+X#````2(G?Z!S^__^%P'0(N/_____K!I"X
+M`````$B+7"082(ML)"!(@\0HPV9F9I!F9F:09F9FD$B#[%A(B5PD*$B);"0P
+M3(ED)#A,B6PD0$R)="1(3(E\)%!(B?U!B?:)RTB#OZ@.````#X3X`@``28G7
+M183`#X1<`0``@_[_=1</MX>0#@``9HD"N`$```#I^0(``&9FD(/^_G42BX>4
+M#@``B0*X`0```.G?`@``@_[]=12+AY@.``")`K@!````Z<@"``!FD`'SB5PD
+M##N?E`X```^'C@(``(GS@^/\08GT08/D`W1B3(UL)"2Y!````$R)ZHG>Z/S[
+M__^#PP2Z!````#E<)`QS#42)X$0I\(M,)`R-%`A$.>)V+D2)X4R)_V9FD&9F
+MD(G(00^V1`4`B`=(@\<!@\$!.=%UZXG01"G@@^@!38U\!P%$BV0D#$&#Y/Q$
+M.>-S*DR-;"0DN00```!,B>J)WDB)[^B)^___BT0D)$&)!TF#QP2#PP1!.=QW
+MVSE<)`P/AN,!``!,C60D)+D$````3(GBB=Y(B>_H5?O__XMT)`PIW@^$P`$`
+M`+D`````N@````!!#[8$%$*(!#J#P0%(@\(!.?$/A)X!``#KYF9FD&:0@_[_
+M=2N`.@]U$<:'H0X```&X`0```.F;`0``QH>A#@```+@!````Z8H!``!F9F:0
+MB4PD%(G(`?`[AY0.```/ATP!``"`OZ$.````#X0_`0``B?"Z`````/>WF`X`
+M`(72#X6-````@+^@#@```'0-Z`````"%P`^%%`$``$B)[^B<_/__@_C_#X0#
+M`0``2(N%J`X```^V4`9(C70D)$6)\4&X`````+D`````2(GOZ'WV__^+="0D
+M2(GOZ,'V__^^$"<``$B)[^C4]O__A<`/A;P```"YX),$`+H`````O@,```!(
+MB>_H9?O__X7`#X6=````A=L/A)P```#'1"00`````(M$)!!%BR0'1(ML)!!%
+M`?5(BUT(2('K``(!`$B)[^CZ^___1(FC",@``$B+A:@.```/ME`%18GI0;@$
+M````N0````!(C70D)$B)[^C=]?__BW0D)$B)[^@A]O__OA`G``!(B>_H-/;_
+M_X7`=2"YB!,``+H`````O@$```!(B>_HR?K__X7`=!=F9I!FD+@`````ZQ^X
+M`0```&9F9I#K%(-$)!`$BT0D$#E$)!1VYNE-____2(M<)"A(BVPD,$R+9"0X
+M3(ML)$!,BW0D2$R+?"102(/$6,.0D)"0D)"0N`````##9F9FD&9FD&9FD+@`
+M````.3T`````?C=(8\=(Q\$`````2(T$0$C!X`,/MQ0(9HD6#[=4"`)FB58"
+M#[94"`B(5@@/MD0("8A&";@!````\\-F9F:09F:09F:0N(`?``##9F9FD&9F
+MD&9FD+C0````PV9F9I!F9I!F9I"X"````,-F9F:09F:09F:0\\-F9F:09F9F
+MD&9FD&9FD,:'R@````#&AJ@`````PY!(A?]T$TB+1W!(A<!T"@^V@/@```"(
+M1P'SPV9FD&9FD%532(G[2(7_='N]`````)`/MH0=>`<``#S_=$0/MM!(C032
+M2(T$@DC!X`-(B<)(`Y-("```="F+0D@E`/__`#T``/\`=1KV0DL$=!1(BWI`
+M2(7_=`OH`````&9FD&9FD$B#Q0%(@?V`````=:-(BX,`"```2#G8=0Q(C;C`
+M#@``Z`````!;7<-F9F:09F9FD+@`````PV9F9I!F9I!F9I"X`````,-F9F:0
+M9F:09F:0N/_____#9F9FD&9FD&9FD+C_____PV9F9I!F9I!F9I"X_____\-F
+M9F:09F:09F:0N/_____#9F9FD&9FD&9FD,="!`````#'`@````"X`````,-F
+M9F:09F:09F:09F:02(M':$B%P'1)2,=`0`````"`2$P$2,=':`````!(QT=P
+M`````(M'"(/X/W\32(M7>$B82,>$PG@#````````PTB+5WA(F$C'A,)X`0``
+M`````//#9F9FD&9F9I!F9F:02(M':$B%P'1)2,=`0`````"`8$S[2,=':```
+M``!(QT=P`````(M'"(/X/W\32(M7>$B82,>$PG@#````````PTB+5WA(F$C'
+MA,)X`0```````//#9F9FD&9F9I!F9F:02(/L"$C'QP````#H`````+@`````
+M2(/$",-F9I!F9I!54TB#[#C&!"1MQD0D`?_&1"0"(\9$)`,4QD0D!#K&1"0%
+M[\9$)`86QD0D!Y)(BZ\("```2(7M2`]$[TB-1"002(G"Q@``2(/``4B)TTB-
+M3"0P2#G(=>S&1"04`;D@````O@X```!(B>_H`````(7`=4*_@!H&`.@`````
+MN2````!(B=J^#P```$B)[^@`````@_@@=1Y(C7,02(GGN0@```#\\Z8/E\(/
+MDL"Y`0```#C"=!9(Q\<`````N`````#H`````+D`````#[;!2(/$.%M=PV9F
+M9I!F9F:09F9FD%532(/L:$B)^TB+KP`(``!(@<7`#@``2(L'2(7`=!-(C;``
+M`/[_2(DW2(M_(.@`````2(MS$$B%]G0)2(M[(.@`````2(MS&$B%]G0)2(M[
+M(.@`````2(U,)&5(C50D9DB-="1G#[=[/$B-1"1:2(E$)#A(C40D7$B)1"0P
+M2(U$)%9(B40D*$B-1"182(E$)"!(C40D8$B)1"082(U$)&)(B40D$$B-1"1C
+M2(E$)`A(C40D7DB)!"1,C4PD9$R-1"14Z`````!(B[-("```2(7V=!](C;LH
+M"```Z`````!(B[5("```2(V]*`@``.@`````2(NS<`@``$B%]G0?2(V[4`@`
+M`.@`````2(NU<`@``$B-O5`(``#H`````$B+LX`*``!(A?9T'TB-NV`*``#H
+M`````$B+M8`*``!(C;U@"@``Z`````!(B[.8"```2(7V=!](C;MX"```Z```
+M``!(B[68"```2(V]>`@``.@`````2(NS<`D``$B%]G0?2(V[4`D``.@`````
+M2(NU<`D``$B-O5`)``#H`````$B+LP`)``!(A?9T'TB-N^`(``#H`````$B+
+MM0`)``!(C;W@"```Z`````!(B[,H"0``2(7V=!](C;L("0``Z`````!(B[4H
+M"0``2(V]"`D``.@`````2(NSF`D``$B%]G0?2(V[>`D``.@`````2(NUF`D`
+M`$B-O7@)``#H`````$B+L\`)``!(A?9T'TB-NZ`)``#H`````$B+M<`)``!(
+MC;V@"0``Z`````!(B[/H"0``2(7V=!](C;O("0``Z`````!(B[7H"0``2(V]
+MR`D``.@`````2(NS$`H``$B%]G0?2(V[\`D``.@`````2(NU$`H``$B-O?`)
+M``#H`````$B+LT@*``!(A?9T'TB-NR@*``#H`````$B+M4@*``!(C;TH"@``
+MZ`````!(B[.X"@``2(7V=!](C;N8"@``Z`````!(B[6X"@``2(V]F`H``.@`
+M````2(NS\`H``$B%]G0M2(N3^`H``$B-N]`*``#H`````$B+E?@*``!(B[7P
+M"@``2(V]T`H``.@`````2(NS(`L``$B%]G0M2(N3*`L``$B-NP`+``#H````
+M`$B+E2@+``!(B[4@"P``2(V]``L``.@`````2(NS4`L``$B%]G0M2(N36`L`
+M`$B-NS`+``#H`````$B+E5@+``!(B[50"P``2(V],`L``.@`````2(NSL`L`
+M`$B%]G0M2(N3N`L``$B-NY`+``#H`````$B+E;@+``!(B[6P"P``2(V]D`L`
+M`.@`````2(NS@`L``$B%]G0M2(N3B`L``$B-NV`+``#H`````$B+E8@+``!(
+MB[6`"P``2(V]8`L``.@`````2(NSX`L``$B%]G0M2(N3Z`L``$B-N\`+``#H
+M`````$B+E>@+``!(B[7@"P``2(V]P`L``.@`````2(NS$`P``$B%]G0M2(N3
+M&`P``$B-N_`+``#H`````$B+E1@,``!(B[40#```2(V]\`L``.@`````2(NS
+M0`P``$B%]G0M2(N32`P``$B-NR`,``#H`````$B+E4@,``!(B[5`#```2(V]
+M(`P``.@`````2(/$:%M=PV9F9I!F9F:09F:02(/L&$B)7"0(3(ED)!!(B?OH
+M`````$B)W^@`````3(VCP`X``$R)Y^@`````2(G?Z`````"_T`<``.@`````
+M2(G?Z`````"^`0```$B)W^@`````O@$```!,B>?H`````$B+7"0(3(MD)!!(
+M@\08PTB#[`A`B'=*0`^V]N@`````N`$```!(@\0(PV9FD&:04TB)^^@`````
+M2(N[``@``$B!Q\`.``#H`````%O#9I!32(G[Z`````!(B[L`"```2(''P`X`
+M`.@`````6\-FD$B#[`CH``````^VP(,]``````"Z`0````]%PDB#Q`C#2(/L
+M.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$B)^T&)]$&)U4B+;VA,
+MBW=X2(7M#X06`0``@+_*``````^%"0$``$R)]^@`````28G'2(7`#X3U````
+MQD`XX<9`.0%%A.1T#4&`_0$9P/?0@\`'ZPM!@/T!&<#WT(/`#4&(1SH/MT4X
+M9D&)1R!)B5\H0<='-`````!)QT=(`````$G'AZ``````````3(G^3(GWZ```
+M``#&@\H````!9L>#R````/0!2(7;=$Y(BU-H2(72=$]F@;O(````E@!U#DB+
+M>E"^(0```.@`````9H.KR`````&_T`<``.@`````3(GWZ`````!(BU-H2(72
+M=`F`N\H`````=;MF@[O(`````'0:08!_)`!U$TB+0V@/MT!B9HE#7KL`````
+MZP6[_____TR)_DR)]^@`````ZP6[_____XG82(M<)`A(BVPD$$R+9"083(ML
+M)"!,BW0D*$R+?"0P2(/$.,-F9F:02(/L*$B)'"1(B6PD"$R)9"003(EL)!A,
+MB70D($B)^XGU3(MG:$R+;WA-A>0/A"8!``"`O\H`````#X49`0``3(GOZ```
+M``!)B<9(A<`/A`4!``#V`P(/A>H```!`@/T4=PQ`#[;%C01`P>`"ZQ>XB?__
+M_T#VY6;!Z`C`Z`0/ML`%\````$'&1CCA0<9&.0%!QD8Z'$&(1CM!#[=$)#AF
+M08E&($F)7BA!QT8T`````$G'1D@`````2<>&H`````````!,B?9,B>_H````
+M`,:#R@````%FQX/(````Q`E(A=MT3DB+4VA(A=)T3V:!N\@```"6`'4.2(MZ
+M4+XA````Z`````!F@ZO(`````;_0!P``Z`````!,B>_H`````$B+4VA(A=)T
+M"8"[R@````!UNV:#N\@`````=`R[`````$&`?B0`=`6[_____TR)]DR)[^@`
+M````ZP6[_____XG82(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9F:0
+M2(/L&$B)'"1(B6PD"$R)9"002(GS2(M'4$R+($B+;F@/MD8D/`9T2#P&=PJ$
+MP'0@/`)U#NLN/"%T-CR`9F9FD'0NN`````#K<69F9I!F9I!(BT=`QT`$````
+M`,:%L@````'K$\:%L@```!#K"F9FD,:%L@````U(@WMP`'0C@7LT`!```'<.
+M2(US<$R)Y^@`````ZPQ(C7-P3(GGZ`````!(B=Y,B>?H`````$B)[_^5R```
+M`+@!````2(L<)$B+;"0(3(MD)!!(@\08PV9FD$%6055!5%532(G[2(GU08G,
+M3(MV>$R-;UA!@/@!&<"#X`B#P`J)AY0```!(BT9H]D!@`71\08#X`1G`@^`"
+M@^AXB$<XQD<Y`$B)T$C!Z#B(1SI(B=!(P>@PB$<[2(G02,'H*(A'/$B)T$C!
+MZ""(1SU(B=!(P>@8B$<^2(G02,'H$(A'/TB)T$C!Z`B(1T"(5T'&1T(`QD=#
+M`$2)X&;!Z`B(1T1$B&=%QD=&`,9'1P#K2D&`^`$9P(/@`H/`*(A'.,9'.0!(
+MB=!(P>@8B$<Z2(G02,'H$(A'.TB)T$C!Z`B(1SR(5SW&1SX`1(G@9L'H"(A'
+M/T2(9T#&1T$`2(G?Z`````!(BT5H#[=`.&:)0R#&0R2`2(EK*$B+0W!(BT`0
+M2(E#2$$/M\0/KT58B4,TQD,P($B+16A(!<,```!(B4-02,>#H`````````"^
+M`````$R)[^@`````BU,T2(M#<$B+<!A,B>_H`````,:%R@````%(B=Y,B??H
+M`````$B%[71N2(M5:$B%TG1E@+W*`````'1C9H&]R````)8`=1%(BWI0OB$`
+M``#H`````&9FD&:#K<@````!O]`'``#H`````$R)]^@`````2(M5:$B%TG0=
+M@+W*`````'0;Z[:X`````(![)`!T&F9F9I!F9I"X_____^L,9H.]R`````!T
+M[^O;6UU!7$%=05[#9F9FD$B#['A(B5PD2$B);"103(ED)%A,B6PD8$R)="1H
+M3(E\)'!(B?M)B?5)B<]!B=1%B<9(BV]H2(7M#X1R`@``@+_*``````^%90(`
+M`$B+15!(B40D&$B+5WA(B10D9L>'R````!`G2(G7Z`````!(B40D$$B%P`^$
+M-0(``&9!@_P$=AY!#[?T2,?'`````+@`````Z`````#K&F9F9I!F9I!(BSPD
+MZ`````!(B40D"$B%P'492(MT)!!(BSPDZ`````!!O/_____IZ@$``$B+5"0(
+M2(M$)!!(B5!PQH"``````4B+!"1(B[``"```QD8_`4B)VK\%````Z`````"`
+M34P"2(M3:+XA````2(M\)!CH`````$B#>V@`#X01`0``@+O*``````^%!`$`
+M`$$/M]2)T,'@"8E$)#R+2UC&1"0@`('Y`!```'4<1(GH@^`'B$0D($G![0,/
+MML"-1`('08G$0<'L`T6$]G5M@?D`$```=3Y!#[?,0;@!````3(GJ2(G>2(M\
+M)!#H9/S__X7`="!(Q\<`````N`````#H`````$&\_____^F*````9F9FD`^V
+M5"0@2,'B"4B)UX'G``X``$B+1"0(2`-X$(M4)#Q,B?[H`````$$/M\Q%#[;&
+M3(GJ2(G>2(M\)!#H`?S__X7`=3U!O`````!%A/9T.(M4)#P/MD0D($C!X`E(
+MB<:!Y@`.``!(BT0D"$@#<!!,B?_H`````$&\`````.L)9F:00;S_____2(M4
+M)!!(@WIP`'0Y@7HT`!```'<22(G62(/&<$B+/"3H`````.L22(MT)!!(@\9P
+M2(L\).@`````2(M$)!#&@(``````2(MT)!!(BSPDZ`````!(BQ0D2(NR``@`
+M`,9&/P!(B=J_!@```.@`````@&5,_>L+9F:09I!!O/____]$B>!(BUPD2$B+
+M;"103(MD)%A,BVPD8$R+="1H3(M\)'!(@\1XPV9F9I!(@^PH2(D<)$B);"0(
+M3(ED)!!,B6PD&$R)="0@2(G[28GU28G42(MO:$B%[74*2(G7_];I^````$B#
+MOX@`````=0Y(@[^``````'0/9F9FD$R)YT'_U>G5````@+W```````^%O0``
+M`(!]2O]F9F:0#X6O````2(M%6$B%P'07@'A-``^%G````/9`2@)F9I`/A(\`
+M``!(BWU0]D<+$&:0#X5_````3(LW@'US`'0-2(GJO@8```#H`````$R)JX@`
+M``!,B:.0````#[952$B)T(/@!DB#^`9T5DB#^`1U4/;"`71+2(M%6$B%P'0B
+M]D!*`G0\9L=`2@$`2(M%6,9`0@%(BW583(GWZ`````#K(,9%2@/&14L$2(GN
+M3(GWZ`````#K"TR)YT'_U69FD&:02(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@
+M2(/$*,-F9I!54TB#[`A(B?M(C:_`#@``Z`````!(B4,H2(E%*$B)FP`(``!(
+MB9T`"```BX,8"```B848"```QH.>#@```<:%G@X```%(B=_H`````$B)W^@`
+M````2(GOZ`````"^`````$B)W^@`````2(G?Z`````"$P'1J2(GOZ`````"$
+MP'1>2(G?Z`````"_T`<``.@`````2(G?Z`````#'@R@!``#H`P``2,>#.`$`
+M``````!(B9M``0``2(VS*`$``$B+>RCH`````+X`````2(G?Z`````"X`0``
+M`.L)9F9FD+@`````2(/$"%M=PV9F9I!32(G[Z`````!(@</`#@``2(G?Z```
+M``"X`0```%O#D$%7059!54%455-(@^P82(ET)`A(B10D@ST```````^%;P$`
+M`,<%``````$```!$BST`````QT0D%`````!)Q\4`````2,?#`````$G'Q@``
+M``#I=@(```^WA@````#!X!!"#[<4+@G0.<4/A?$```!!N`````"_`````&9F
+MD&:09H,\'P!U7TECT$B)T4C!X05*BP0N2(D$&4*+1"X(B409"`^V@0````!(
+MP>(#2(T\`@^V1"03B$2[#0^V@0````!(C3P"#[9$)!*(1+L.#[:!`````$@!
+MPL9$DP\`@($``````>MT#[:/``````^VP;H`````0O<T-H72=$L/ML%)8]!(
+MC0S5`````$B-/`$/MD0D$XA$NPU(P>(%#[:"`````$B-/`$/MD0D$HA$NPX/
+MMH(`````2`'!QD2+#P"`@@`````!ZQ)!@\`!2(/'($&#^`0/A2;___^#A@``
+M```!08/"`4B#QAA%.?H/A>7^__]!@\0!08/\(`^%%P$``(-$)!0!@7PD%/\`
+M```/A3H!``!(@WPD"`!T"$B+5"0(Q@(`BS4`````O0````"%]GXUN0````"]
+M`````+H``````ZH`````2(-\)`@`=`V+@@````!(BUPD"``#@\$!2(/"&#GQ
+M==I(@SPD``^$[````$&Y`````$&Z`````$G'Q`````!F0X,\(@`/A,T```!!
+M#[:2`````(32=&=!N`````!)8\%,C1S%``````^VPH/H`4B-6`%+C00#2(TT
+MA0````!(BSPDN00```#\\Z8/E\(/DL`XPG4A2(-\)`@`=`]!#[:"`````$B+
+M5"0(B`)!#[:J`````.L)28/``4DYV'6T08/!`4F#PB!!@_D$=$SI;O___T2(
+M9"02N0````"Z`````$2)YHM\)!3H`````(G%0;H`````O@````!%A?\/CX_]
+M___II?[__P^V1"04B$0D$T&\`````.NY0`^VQ4B#Q!A;74%<05U!7D%?PV9F
+M9I!F9F:09F9FD&9FD$B#[!A(B1PD2(EL)`A,B60D$$&)]$B+7WA(BV]H]@<!
+M="Y(B=_H`````$B%P'0Q@+CY`````'0H00^VU$B+=4!(B=_H`````.L69F:0
+M9F:00`^VUDB+=4!(B=_H`````$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F:0
+M9F:09F:02(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$B)_4&)
+M]$B+7VA,BV]X2(7;#X0N`P``@+_*``````^%(0,``/8'`@^%&`,```^V@R`!
+M``"$P'0+0#CP=4R0Z0(#``!(BU-`#[:"RP```(T$@`^V4@(!T$B8#[:(````
+M`$$/ME4Z00^V=3E%#[;$2,?'`````+@`````Z`````"X_____^G!`@``3(GO
+MZ`````!)B<9(A<`/A*@"``!(BU-`#[:"RP```(T$@`^V4@(!T$B8#[:(````
+M`$$/ME4Z00^V=3E%#[;$2,?'`````+@`````Z`````!!QD8XX4'&1CD!08#\
+M`@^5P(/`&D&(1CH/MT,X9D&)1B!)B6XH0<=&-`````!)QT9(`````$G'AJ``
+M````````3(GV3(GOZ`````#&A<H````!9L>%R````/0!2(7M=$Y(BU5H2(72
+M=$5F@;W(````E@!U#DB+>E"^(0```.@`````9H.MR`````&_T`<``.@`````
+M3(GOZ`````!(BU5H2(72=`F`O<H`````=;M,B?9,B>_H`````&:#O<@`````
+M#X2>`0``08!^)``/A9,!``!,BW5H28M&4$R+*$R)[^@`````2(G#2(7`=1)!
+MQH;!`````;@`````Z7(!``!,B>_H`````$F)Q$B%P'4=0<:&P0````%(B=Y,
+MB>_H`````+@`````Z44!``!,C7M8QD,XX<9#.0'&0SH#00^W1CAFB4,@QH.8
+M````#TB):RC'0S0``@``28M4)!!(B5-(N`````#&!!``2(/``4@]``(``'7P
+M3(EC<$C'@Z``````````O@````!,B?_H`````(M3-$F+="083(G_Z`````!(
+MB=Y,B>_H`````,:%R@````%FQX7(````^@!(A>UT3DB+56A(A=)T3V:!O<@`
+M``"6`'4.2(MZ4+XA````Z`````!F@ZW(`````;_0!P``Z`````!,B>_H````
+M`$B+56A(A=)T"8"]R@````!UNV:#O<@`````=""`>R0`=1I(BW-(3(GWZ```
+M``!!#[:&(`$``(B%S@```$B#>W``=`Q(C7-P3(GOZ`````!(B=Y,B>_H````
+M`+@`````ZQ-F9F:09F:0N/_____K!;C_____2(M<)`A(BVPD$$R+9"083(ML
+M)"!,BW0D*$R+?"0P2(/$.,.02(/L"(`^"7<*#[8&_R3%`````+C_____ZW9(
+MBT8(2(N0"`@``$B%TD@/1-!(B[H`"```QH>?#@```>@`````N`````#K2@^V
+M5@B^`````.A\[?__ZSH/ME8(O@$```#H;.W__^LJ#[9V".@`````D.L>#[9V
+M".@`````9F:09I#K#@^V=@CH`````+@`````2(/$",-F9F:09F9FD&9FD$B#
+M[!A(B1PD2(EL)`A,B60D$$B)_4R+9WA)BX0D``@``(!X/P!U84B+GX`````/
+MMH?+````C02`#[97`@'02)@/MH@`````00^V5"0Z00^V="0Y1`^VA\X```!(
+MQ\<`````N`````#H`````$C'A8``````````BU4(2(N]D````$B)[O_3ZSU(
+MC9^8````28M\)"A(B=[H`````,>%F````/0!``!(QX6H`````````$B)K;``
+M``!)BWPD*$B)WN@`````2(L<)$B+;"0(3(MD)!!(@\08PV9F9I!F9F:00515
+M4TF)_$B)\P^WTDB-!-)(C02"2,'@`TB)Q4@#KT@(``!,BX<`"```28'`P`X`
+M`$B);FA(B75`QH4A`0```$B#?5@`=2D/MG]#0(3_#X19`0``2(MU4+D`````
+M23NT).`,```/A!8!``#I,`$``(`.`4B+15A(B49P#[9_0T"$_W152(MU4+D`
+M````23NT).`,``!T).LS9F9FD&9FD`^VP4B)PDC!X@1(P>`'2"G023FT!.`,
+M``!U%D$/MD0D08T$@8B#RP```.L-N0````"#P0%`./EUQTF+C"0`"```O@``
+M``"Z`````&9FD&:0#[:$"O@'```\_W0=#[;`2,'@"$@#@7`(``!(.T58=09`
+MB',!ZT>#Q@%(@\(!2(/Z!'7-L@!"#[:$`O@'```\_W0A#[;`2,'@"$D#@'`(
+M``!(.T58=0I`B',!ZQ%F9F:0@\8!2(/"`4B#^@1UR`^V17&(0P+K80^VP4B)
+MPDC!X@1(P>`'2"G023FT!.`,``!U)$$/MD0D08T$@8A#`8B#RP```$$X3"1#
+M=1?K$69F9I"Y`````(/!`4`X^76YQD,!_\9#`@"#O1@!````=`F+A1P!``"(
+M0P)(C4L@2(V5B````$B+A8@```!(B4,@2(M""$B)00A(BT(02(E!$$B+0AA(
+MB4$82(M"($B)02!(C4L,2(U5=$B+171(B4,,2(M""$B)00B+0A")01!(BX6P
+M````2(E#2`^W16!FB4-<#[=%8F:)0UY(BT5H2(E#4(N%O````(E#6`^V17*(
+M0V`/MH4@`0``B(/.````]D5,!'4/3(GGZ`````!F9F:09F:0#[952$B)T(/@
+M!DB#^`9U!?;"`70#@"/]#[953-#J@^($#[8#@^#["="(`P^V0P&(@\T````/
+MMD,"B(/,````2(G?Z`````!(BW5`N@````!,B>?H`````$B)W^A0_/__6UU!
+M7,-F9F:09F9FD&9FD$B#[!A(B5PD"$B);"002(G]2(N?``@``.@`````@'U+
+M`74M2(V[P`X``(!_2P%T6X"]L`X```!U%[X`````Z`````"`A;`.```!9F:0
+M9F:02(V=*`$``$B+?2A(B=[H`````,>%*`$``.@#``!(QX4X`0```````$B)
+MK4`!``!(BWTH2(G>Z`````!(BUPD"$B+;"002(/$&,-F9I!F9I!!5T%6055!
+M5%532(/L.$F)_(GP2(G328G-08GV0<'N&$&)]T'![Q`/MM2(5"000(AT)`](
+MC:O`#@``N`````"0Q@08`$B#P`%(/8`?``!U\$R):R"+!0````"(0T"#P`&)
+M!0````!$B',[1(A[.@^V1"00B$,Y#[94)`^(4SC&0T$`00^W!"1FB4,P00^W
+M1"0"9HE#,D&+1"0$B4,T2(V3@!T``$B)D[@.``!,B6T@#[9#0(A%0$2(=3M$
+MB'TZ#[9$)!"(13D/MD0D#XA%.,9%00%!#[<$)&:)13!!#[=$)`)FB44R08M$
+M)`2)131(B96X#@``#[=#,F8])"</A!0!``!F/20G#X>$````9CU$(0^$``$`
+M`&8]1"%W1&8]("$/A/````!F/2`A=P]F/5`'#X7T````Z=L```!F/2(AD`^$
+MT````&8]0"%F9I!F9I`/A=0```#INP```&9FD&:09CT0)P^"P````&8]$2=F
+MD`^&H````&8M("=F@_@"9I`/AZ0```#IBP```&9FD&:09CV`)P^$?````&8]
+M@"=FD'<N9CU`)W1N9CU`)V9F9I!W"&8],"=U<NM<9CU$)V:0=%1F/6`G=6+K
+M3&9FD&9FD&8]@')T0&8]@')F9I!F9I!W"&8]@B=U0NLL9CV`D6:0=`YF/8"4
+M=3+K'&9FD&9FD&;'0SR`D<9#/@1FQT4\@)'&13X$ZQ1FQT,\@)3&0SX$9L=%
+M/("4QD4^!$$/MD0D"(A#0D$/MD0D"(A%0KD```0`N@````"^`@```$R)[^@`
+M````2(D#N0`@``"Z`````+X`````3(GOZ`````!(B<%(B4,02(L#2(7`#X3E
+M`0``2(7)#X3<`0``2(V0``(!`$B)4PA(C8````(`2(D#2`4`0```2(E%`$B)
+M50A(B4T01(L%`````$6%P'YGO@````"Y`````$C'QP`````/MP0Y9D$[!"1U
+M/P^W@0````!F03M$)`)U,(N1`````(/"`8F1`````$2+B0````!%A<ET%40Y
+MRG80B="Z`````$'W\8F1`````(/&`4B#P1A$.<9UJDB+0PA(+>!]``#'``'P
+M`P!(BT,(2"W8?0``QP`!``#H2(M[(+YX````Z`````")PB4`<```/0`@``!V
+M%(#FCX#.($B+>R"^>````.@`````1(AT)"-$B'PD(@^V5"00B%0D(0^V1"0/
+MB$0D(+T`````0;D`````2<?$`````$R-;"0@9D.#/"$`#X2B````08"Y````
+M```/A(0```!!N`````!(8\5,C13%`````$V)ZTN-!`)(C32%`````+D$````
+M_$R)W_.F#Y?"#Y+`.,)U.T$/MH$`````@\`!08B!`````$$/MI$`````A-)T
+M'3C0=AD/ML`/MLJZ`````&;W\4&(D0````!F9F:008U0`4F#P`%!#[:!````
+M`#G0?Y"#Q0%)@\$@@_T$#X52____QX,8"````0```+@!````ZP6X`````$B#
+MQ#A;74%<05U!7D%?PV9F9I!F9I!)B?!,BT]X#[8'@^`!1`^VT+@`````0L8$
+M``!(@\`!2(/X,'7Q28NQN`X``$B)\K``Q@00`$B#P`%(/0`"``!U\$B-3C:Z
+M`````&9FD&9FD`^V1%<AB`11#[9$5R"(1%$!2(/"`4B#^A1UY4B-3A2R``^V
+M1%<-B`11#[9$5PR(1%$!2(/"`4B#^@IUY4B-3BZR``^V1%=)B`11#[9$5TB(
+M1%$!2(/"`4B#^@1UY4F)<"!(BT=02(/``4F)`(M'6$&)0`@]`!```'4$2<$@
+M`TB#?V@`=2+V!P%T'4B+1W!(A<!T-TV%R70R#[=`0$&`O`%X!P``_W0C#[:'
+MRP```(T$@`^V5P(!T$B8#[:``````$&(0!!!N@````!!QD`1`$'&0!(!0<9`
+M%A!!QD`5$$2)T(T4`+[]____02)P#@G608AP#L'@!4$/ME`,@^+?"<)!B%`,
+M#[='7$C!Z`>#X`'!X`:#XK\)PD&(4`P/MT=<2,'H`H/@`4$/MD@-@^'^"<%!
+MB$@-#[='7DC!Z`/!X`>#XG\)PD&(4`P/MT=>2-'H@^`!`<"#X3T)P4&(2`V#
+MRA!!B%`,#[8'T.B#X`&#YOX)QD&(<`X/M@>#X`2#YOL)QD&(<`YF0<=`&``0
+M#[:'S@```$&(0!,/MH?+````08A`*,-F9F:09F9FD&9FD&9FD$B#["A(B1PD
+M2(EL)`A,B60D$$R);"083(ET)"!(B?M(B?5,BW=X2(M&2$B).$B+1VA(A<!U
+M&L:&L@````)(B??_EL@```#I%08``&9FD&:0]D!,`G0:QH:R`````DB)]_^6
+MR````.GU!0``9F:09I!,B??H`````$F)Q$B%P&:0=17&A;(````"2(GO_Y7(
+M````Z<D%``#'@)0`````````2(EH:$B+0VA)B40D*$B+0V@/MT`X9D&)1"0@
+M#[:%L````#P"#X2;`0``/`)W"83`="+I'P,``#P#9F:09F:0#X36`0``/`0/
+MA0D#``!FD.F7`0``2(N5D`````^WC9@```"!>U@`$```=0A(P>H#9L'I`TB+
+M0VCV0&`!#X2N````#[:%L0```*@"=`A!QD0D.(CK$H/@!#P!&<"#X`6#Z'9!
+MB$0D.$'&1"0Y`$B)T$C!Z#A!B$0D.DB)T$C!Z#!!B$0D.TB)T$C!Z"A!B$0D
+M/$B)T$C!Z"!!B$0D/4B)T$C!Z!A!B$0D/DB)T$C!Z!!!B$0D/TB)T$C!Z`A!
+MB$0D0$&(5"1!0<9$)$(`0<9$)$,`B<AFP>@(08A$)$1!B$PD14'&1"1&`$'&
+M1"1'`.MP#[:%L0```*@"=`A!QD0D."CK$H/@!#P!&<"#X`6#P"I!B$0D.$'&
+M1"0Y`$B)T$C!Z!A!B$0D.DB)T$C!Z!!!B$0D.TB)T$C!Z`A!B$0D/$&(5"0]
+M0<9$)#X`B<AFP>@(08A$)#]!B$PD0$'&1"1!`$B+0VA(!<,```!)B40D4$'&
+M1"0P(`^WP0^O0UA!B40D-.F=`0``@+V0````$'<%]@,"=0S&A;(````&Z;`#
+M``#&A;(````&Z:0#```/MH6Q````@^`P/"!U%T'&1"0X&T'&1"0Y`4'&1"0\
+M`.E2`0``0<9$)#@UZ4<!``!(BT-H#[9`2*@!="BH!'0D08&,))0``````"``
+M#[>5G````&8[E9(```!U%.M=9F:09F:0QH6R````!NDT`P``#[:%FP```#SC
+M=$`\XW<./$)T.#RP=!\\0'4DZRX\[&9FD&:0=!`\[W0A/.5U$69FD&9FD.L5
+M9HF5D@```.L,QH6R````!NGI`@``0<9$)#BP#[>%D````$&(1"0Y#[>%D@``
+M`$&(1"0Z#[>%E````$&(1"0[#[>%E@```$&(1"0\#[>%F````$&(1"0]#[:%
+MF@```$&(1"0^#[:%FP```$&(1"0_#[:%D0```$&(1"1`#[:%DP```$&(1"1!
+M#[:%E0```$&(1"1"#[:%EP```$&(1"1##[:%F0```$&(1"1$]H6Q````!G0=
+M#[>%G````,'@"4&)1"0TZPS&A;(````&Z2T"``!)QX0DH``````````/MH6Q
+M````J`8/A`("``!-C6PD6$B+G;@```!(A=MT!*@!=35(BX7`````2(7`#X0#
+M`@``28NV*`D``+H`````2(GO_]"%P`^$Z@$``$F+GB@)``!(A=MT.4R)Y^@`
+M````O@````!,B>_H`````$B#PQ"+4_!(BW/X3(GOZ`````"+0_1(@\,0A<`/
+MA8$!``#KX+X`````3(GOZ`````!!BT0D-#T`$```=SU,B??H`````$B)P4B%
+MP'4,QH6R````"^E:`0``2(M`$$F)1"1(28E,)'!!BU0D-$B+<1A,B>_H````
+M`.M0/0```0!W/4R)]^@`````2(G!2(7`=0S&A;(````+Z18!``!(BT`028E$
+M)$A)B4PD<$&+5"0T2(MQ&$R)[^@`````ZPS&A;(````&Z>D````/MH6Q````
+MJ`0/A,H```"`O;`````#=2!(B[6@````2(7V=!1)BWPD2$&+5"0TZ`````#I
+MH0```$B+E;@```!(A=)U%4B+A<````!(A<`/A;4```#K8V9FD$V+;"1(J`%U
+M"4B)TV9F9I#K*$B+A<````!(A<!T'$F+MB@)``"Z`0```$B)[__0A<!T!TF+
+MGB@)``!(@\,0BU/P2(MS^$R)[^@`````BT/P20'%BT/T2(/#$(7`=2+KWD&+
+M1"0T28M,)$B%P'02B<)(B<C&``!(@\`!2(/J`77S3(GF3(GWZ`````#K,V9F
+MD$R)YDR)]^@`````2(GO_Y7(````ZQJ[`````.E1_O__38ML)$CI9/___V9F
+MD&9FD$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F:055-(@^P(2(G]
+M2(GSN`````#&!!@`2(/``4@]@````'7P@[T8"````0^40Q,/ME4Z#[9-.0^V
+M=3@/MD4[B$,#B%,"B$L!0(@S@$L1$`^W13!FB4,$#[=%,F:)0P:+A1@(``"(
+M0W#&0Q(@#[=5,F:!^B`A=`=F@?HB(75(QD,7`DB-0SS'0SQ2;V-KQT-`9712
+M0<=`"$E$(%/'0`Q31"`RQT`0,3)X(,=`%$-O;G3'0!AR;VQL9L=`'&5RQD`>
+M`.D!`0``C8+PV/__9H/X`7829H'Z0"%T"V:!^D0A#X6G````QD,7!`^W53*-
+M@O#8__]F@_@!=T1(C4,\QT,\4F]C:\=#0&5T4D''0`A)1"`RQT`,-S%X(,=`
+M$%-!4R#'0!1#;VYTQT`8<F]L;&;'0!QE<L9`'@#IBP```&:!^D`A=`=F@?I$
+M(75]2(U#/,=#/%)O8VO'0T!E=%)!QT`(240@4\=`#%-$(#+'0!`Q-'@@QT`4
+M0V]N=,=`&')O;&QFQT`<97+&0!X`ZSS&0Q<(2(U#/,=#/%)O8VO'0T!E="`W
+MQT`(-3`@4\=`#$%402#'0!!#;VYTQT`4<F]L;&;'0!AE<L9`&@#&0Q<HQD,2
+M`<9#$"A(C4,8QT,82&EG:,=#'%!O:6['0`AT(%1EQT`,8VAN;\=`$&QO9VG'
+M0!1E<RP@QT`826YC+L9`'`!(BX40"```2(7`=`I(BT`02(E#:.L(2(M%$$B)
+M0VC'0V``(```2(M](+Y\````Z`````")PH'B\`,``,'J!(A3<8/@#XA#<TB+
+M?2"^@````.@`````B<*!X@``\`/!ZA2(4W(E```/`,'H$(A#=$B#Q`A;7<-F
+MD$%7059!54%455-(@^P(28G]B?5(B=.X`````&9FD&:0Q@08`$B#P`%(/=``
+M``!U\(EK"(/]$WX*28'%P`X``(/M%$ACQ;H`````28.\Q7@#````#X4D`@``
+M2&/%28F<Q7@#``!,B6MX2(F+@````$R)@Y````!!@'U+`0^%]P$``(']@P``
+M``^/U0$``$$/MH0%>`<``#S_#X3$`0``#[;`9HE$)`8/M\!(C13`2(T4D$C!
+MX@-)B=1-`Z5("```0?9$)$L$#X27`0``08M$)$@E`/__`#T``/\`#X6"`0``
+M0?9$)$P$#X3Q````0<:$),``````00^V5"1(2(G0@^`&2(/X!@^$;0$``$B#
+M^`0/A6,!``#VP@$/A%H!``!)BUPD4$F+1"182(7`#X6%````0<9$)$H#0<9$
+M)$L$@'L-`'1/O0````!,C7-`3(GWZ`````!(B<)(BT-(2(E32$R),DB)0@A(
+MB1"`>DK_=!A).=1T$T'&A"3!`````;H!````Z?8```"#Q0$/MD,-.>A_ND&`
+MO"3!`````0^$UP```$R)YDR)[^@`````N@$```#IQP```(!X0@`/A;@```!F
+MQT!*`0!)BW0D6$R)[^@`````N@$```#IH````$V+9"1008!\)`T`=&%!O@``
+M``!-C7PD0$R)_^@`````2(G"28M$)$A)B50D2$R).DB)0@A(B1"`>DK_="8/
+MMD))/")T!#P-=1I(8\5)QX3%>`,```````"Z`````.M!9F9FD$&#Q@%%.'0D
+M#7>J#[=4)`9(B=Y,B>_H`````+H!````ZQM(8\5)QX3%>`,```````"Z````
+M`.L%N@$```")T$B#Q`A;74%<05U!7D%?PY"0B=#&!PC&1P$20(3V=`:`3P($
+MZP2`9P+[A,!T!H!G#-_K!(!/#""X%````,-F9F:0\\-F9F:09F9FD&9FD&9F
+MD$%7059!54%455-(@^P828G]28GV2(G5B$PD!T6)QTB+1C!(B40D$$C'1C``
+M````2(7`#X5T`0``Z`````!)B<2X`````$V%Y`^$$0(``$R)[^@`````2(E$
+M)!!(A<!U%4R)YDR)[^@`````N`````#IZ@$``$'&1"0X&D'&1"0Y"$'&1"0Z
+M"$'&1"0[`$'&1"0\_T'&1"0]`$'&1"0EJT$/MT8X9D&)1"0@38EL)"A!QT0D
+M-/\```!!QX0DE`````@```!(BT0D$$B+0!!)B40D2$@%_P```$F)1"100<9$
+M)#`D2(M$)!!)B40D>$G'A"2@`````````$'&1"0D@$F-7"18O@````!(B=_H
+M`````$B+1"002(MP&+K_````2(G?Z`````!,B>9,B>_H`````+O(____ZR!F
+M9F:09F:0O^@#``#H`````(/K`4R)[^@`````A-MT#D$/MD0D)#R`=-V$P'0Q
+M2(UT)!!,B>_H`````$$/MW0D,DF+?E#H`````$R)YDR)[^@`````N`````#I
+MQP```$G'1"1X`````$R)YDR)[^@`````2(M$)!!(BU@000^VUP^V="0'2(U[
+M!.@`````08G$Q@,`QD,!`,9#`@#&0P,`2(GN3(GOZ`````!(C54XN`````!F
+M9I#&!!``2(/``4B#^!!U\D&-1"0$QD4X%<9%.1&(13S&13T`2(U=6$0/MN!$
+MB64TQX64`````````$B+5"002(M"$$B)14A(B55XO@````!(B=_H`````$B+
+M1"002(MP&$2)XDB)W^@`````N`$```!(@\086UU!7$%=05Y!7\.0D(GP9HEW
+M",9'#@!FQT<,``!FA?9T'XU0_[D`````9F:02(L'9HD4"$B#P0*#Z@%F@_K_
+M=>SSPV9F9I!F9I!F9I!!B?!FB7<(QD<.`6;'1PP``&:%]G0>N@````"Y````
+M`$B+!V:)%`B#P@%(@\$"9D0YPG7L\\-F9F:09F:09F:0@'\.`74J#[='#`^W
+MR$B+%P^W%$J#P`%FB4<,9CM'"G(&9L='#```9H-O"`$/M\+#2(L7#[='"(/H
+M`6:)1P@/M\`/MP1"PV9F9I!F9I!F9I"`?PX!=2H/MU<(#[='#`'"#[='"HG!
+MB=#!^A_W^4ACTDB+!V:)-%!F@T<(`<-F9I`/MT<(#[?(2(L79HDT2H/``6:)
+M1PC#9F9FD&9FD&9FD&:#?P@`#Y3`#[;`PY"0D)!(BP](.<]U"+D`````ZP^0
+M2(L12(M!"$B)0@A(B1!(B<C#9F9FD&9F9I!F9I!F9I!!B="$TG0Z#[8'2(GY
+MOP`````Z!G06ZQX/ME$!#[9&`4B#Q@%(@\$!.,)U"H/'`40XQW7DZPNX````
+M`&9FD&:0P[@!````PV9FD&9FD&9FD,9'`0!`B'<"QT<$`````,-!B=`/ME<!
+M#[;"2(T$0$C!X`)(B<%(`T\(@\(!B%<!1`%'!+@`````Q@0(`$B#P`%(@_@,
+M=?)(B3%$B$$(3(G"#[;&B$$)1(G"P>H0@^(_#[9!"H/@P`G0B$$*PV9F9I`/
+MMD<!.@</DL`/ML##9F:02(GYN`````"`>0+_=0AFB3&(40+K#8/``4B#P01F
+M/8``=>4/M\##9F:09F:09F:008G0#[?&2(T$AX!X`O]U$&9$B0"(2`(/M\;#
+M9F:09I`/MM%!#[?PZ``````/M\##2(GYN``````X40)U$V8Y,74.QD$"_V;'
+M`?__ZQ!F9I"#P`%(@\$$9CV``'7;#[?`PV9F9I!F9F:09F9FD&9FD+@`````
+MB<$X5(<"=09F.32'=`^#P0%(@\`!2#V`````=>-F@?F``+B``0``#T3(#[?!
+MPV9F9I!F9I!F9I!F9I`/MD<X/`AT/CPH=#H\J`^$_P```#R(#X0Y`0``/`IF
+MD'0D/"IT(#RJ#X3E````/(H/A!\!```\+W0,/(]F9F:0#X64`0``/"\/A)(`
+M```\+W<B/`IT7SP*=PH\"&9F9I!U1.M1/"AT>#PJ9F:09F:0=33K;#R/#X39
+M````/(]FD'<5/(@/A,L````\BF9F9I!U%.F^````/*AF9F:09F:0='$\JG1M
+MN0````"X`````.D3`0``#[9'.L'@"`^V5SL)T`^V5SF#XA_!XA`)T(G!#[9'
+M/.GO````9F9FD&9FD`^V5SK!XA@/MD<[P>`0"<(/MD<]"<(/MD<\P>`(B=$)
+MP0^V1S_!X`@/ME=`"=#IM0````^V5SK!XA@/MD<[P>`0"<(/MD<]"<(/MD<\
+MP>`(B=$)P0^V5S[!XA@/MD<_P>`0"<(/MD=!"<(/MD=`P>`("=#K<P^V5SI(
+MP>(X#[9'.TC!X#!("<(/MD=!2`G"#[9'/$C!X"A("<(/MD<]2,'@($@)P@^V
+M1SY(P>`82`G"#[9'/TC!X!!("<(/MD=`2,'@"$B)T4@)P0^V5T+!XA@/MD=#
+MP>`0"<(/MD=%"<(/MD=$P>`("=!(B8^(````B8>0````9H-/(@'SPV9F9I"Z
+M_____V:%]G0Q2(GYOP````"Z_____TG'P`````!FD`^V`3'0#[;`P>H(03,4
+M@(/'`4B#P0%F.?=UY8G0PV:02(/L:$0/MD\[1`^V1SH/MD\Y#[97.`^V1T>)
+M1"18#[9'1HE$)%`/MD=%B40D2`^V1T2)1"1`#[9'0XE$)#@/MD="B40D,`^V
+M1T&)1"0H#[9'0(E$)"`/MD<_B40D&`^V1SZ)1"00#[9'/8E$)`@/MD<\B00D
+M2(G^2,?'`````+@`````Z`````!(@\1HPV:02(/L"`^V1@&(1P$/MD8"B$<"
+MBT8$B4<$2(M'"`^V5P%(C1122,'B`DB+=@A(B<?H`````$B#Q`C#9F9FD&9F
+MD$B+3V`/ME=8N`````!F9I#&!#@`2(/``4@]J````'7P2(E/8(A76,-F9F:0
+M9F9FD+@`````NO____]F9I!F9I"(%#A(@\`!2#T``@``=?'SPV9F9I!F9F:0
+M9F9FD&9FD+D`````2#L_=!)(BT\(2(L12(M!"$B)0@A(B1!(B<C#2(L/BY$$
+M`0``B=`E?O_^_XF!!`$``('B?O_R_TB+1PB)$$B+1PB)4`Q(BP>+@%0!``")
+M!0`````E_@#__TB+%XF"5`$``,-F9I!F9I!F9I")\4B+!XN0!`$``(D5````
+M``^W1SQF/8!D=`QF/8"1=`9F/8"4=1$/MLF#P0BX`0```-/@"<+K$$`/MLZ#
+MP0RX`0```-/@"<)(BP>)D`0!``##9F9FD&9F9I!F9I!F9I")\4B+!XN0!`$`
+M`(D5``````^W1SQF/8!D=`QF/8"1=`9F/8"4=1$/MLF#P0BX_O___]/`(<+K
+M$$`/MLZ#P0RX_O___]/`(<)(BP>)D`0!``##9F9FD&9F9I!F9I!F9I")\4"`
+M_O]T;T"`_A]W,HNW&`$``+H!````T^*)T/?0(?")AQ@!``"+AU@!``")!0``
+M```AT'1`B8=8`0``PV:0B[<<`0``#[;!@^@@N@$```")P=/BB=#WT"'PB8<<
+M`0``BX=@`0``B04`````(=!T!HF'8`$``//#9F9FD&9FD$B#["A(B5PD"$B)
+M;"003(ED)!A,B6PD($B)U8GP3(LO0(#^`P^&B0```$B-',4`````@>/X!P``
+M38VD'0`"``!!QP0D#`$``+\0)P``Z`````!)C9P=!`(```^V50/!XA@/MD4"
+MP>`0"<(/MD4`"<(/MD4!P>`("<*)$T''!"00`0``OQ`G``#H``````^V50?!
+MXA@/MD4&P>`0"<(/MD4$"<(/MD4%P>`("<*)$^F$````2(T<Q0````"!X_@'
+M``!.C:0K``(``$''!"0,`0``OQ`G``#H`````$J-G"L$`@``#[95`\'B&`^V
+M10+!X!`)P@^V10`)P@^V10'!X`@)PHD30<<$)!`!``"_$"<``.@`````#[95
+M!\'B&`^V10;!X!`)P@^V100)P@^V107!X`@)PHD32(M<)`A(BVPD$$R+9"08
+M3(ML)"!(@\0HPTB#[!A(B5PD"$R)9"0028G\0`^VWHG>Z`````"_$"<``.@`
+M````B=Y,B>?H`````$B+7"0(3(MD)!!(@\08PY!!5T%6055!5%532(/L6$F)
+M_XA4)%=(BQ>`?SX`#X0\`@``0;P`````0;W@____0;[P____0`^VQDB)1"1(
+M2(V"@`$``$B)1"1`2(V*A`$``$B)3"0X2(V"H`$``$B)1"0P2(V*I`$``$B)
+M3"0H2(V"4`(``$B)1"0@2(V*5`(``$B)3"082(V"X`$``$B)1"002('"T`$`
+M`$B)5"0(9F:02(M$)$A$B>%(T_BH`0^$C0$``$2)Y8/]`W871(GJ2`-4)"B+
+M`HD%`````(/@_HD"ZQN-%.T`````B=)(`U0D.(L"B04`````@^#^B0*_$"<`
+M`.@`````@'PD5P!T<H/]`W871(GR2`-4)!"+`HD%`````(/(`HD"ZQN-%*T`
+M````B=)(`U0D"(L"B04`````@\@"B0)$B?!(BTPD$$@!P8T$K0````")P$B+
+M5"0(2`'"@_T#=@J+`8D%`````.L(BP*)!0````"H`G1TZ^-FD(/]`W8O1(GK
+M2(M$)"!(`=C'``````"_$"<``.@`````2`-<)!B+`XD%`````(/(`8D#ZT&-
+M'.T`````B=M(BT0D($@!V,<``````+\0)P``Z`````!(`UPD&(L#B04`````
+M@\@!B0/K-V9F9I!F9I"#_0-V*T2)ZDB+1"0P2`'0QP`!````2`-4)"B+`HD%
+M`````(/(`8D"ZS9F9I!F9I"-!.T`````B<!(BU0D0$@!PL<"`0```$@#1"0X
+MBQ")%0````"#R@&)$&9F9I!F9I!!C50D`4F#Q`%!@\4(08/&!$$/MD<^.=`/
+MAT+^__](@\186UU!7$%=05Y!7\-F9I!54TB#[`B)T4B++X/^`W8@C03UX/__
+M_XG`2(V4!:`!``"+`HD%`````(/@_HD"ZQZ-!/4`````B<!(C90%@`$``(L"
+MB04`````@^#^B0*$R71^@_X#=B"-!+7P____B<!(C90%X`$``(L"B04`````
+M@\@"B0+K'HT$M0````")P$B-E`70`0``BP*)!0````"#R`*)`HT4M0````"-
+M0O")P$B-C`7@`0``B=)(C905T`$``(/^`W8*BP&)!0````#K"(L"B04`````
+MJ`)T=>OC@_X#=CB-'/7@____B=M(C80K4`(``,<``````+\0)P``Z`````!(
+MC9PK5`(``(L#B04`````@\@!B0/K-HT<]0````")VTB-A"M0`@``QP``````
+MOQ`G``#H`````$B-G"M4`@``BP.)!0````"#R`&)`TB#Q`A;7<.0D)"0D)!(
+MB?E(BS\/MX&X$@``@\`!9HF!N!(``&8[@;P2``!R"6;'@;@2``````^W@;@2
+M``!(P>`"2`.!<!$``(L6B1`/MX&X$@``B8<L`0``PV9FD$&)T+@`````Q@0(
+M`$B#P`%(@_@$=?*)\F:!XO\/#[<!9B4`\`G09HD!#[97#<'B#(L!)?\/\/\)
+MT(D!#[9'"H/@`DB#^`$9TH/B`H/"`<'B!0^V00.#X!\)T(/($(/@]XA!`_9'
+M"@%T%T2)PH/B?\'B!`^W00)F)0_X"=!FB4$"\\-F9F:09F9FD&9FD&9FD+@`
+M````Q@0P`$B#P`%(@_@-=?(/MD<YB`8/MD<ZB$8!#[9'.XA&`@^V1SR(1@,/
+MMD<]B$8$#[9'/HA&!0^V1S^(1@;VAY8````$=",/MD=`B$8(#[9'08A&"0^V
+M1T*(1@H/MD=#B$8+#[9'1(A&#+@!````PV9F9I!F9F:09F:0N@````!!N@``
+M``!!N?_____K4@'21(G`T_BH`702]\(````!=1J!\G<GVP#K$F:0B=`U=R?;
+M`/?"`````0]%T(/I`40YR77+28/"`4F#^@AU$XG0P>@0B`>)T,'H"(A'`8A7
+M`L-%#[8$,KD'````ZZ)F9F:09F9FD&9F9I!F9I!(BX<0$0``BQ"+4`2+4`B+
+M0`R)!0````##9F9FD&9FD$B#[`A(BX:(````1`^V1T-%A,!T(@^V4`VY````
+M`/;"`70,ZQ)(B=!(T_BH`74(@\$!1#C!=>[&1D(,Z`````!(@\0(PV9F9I!F
+M9F:09F:02(/L"$B)^$B+/V;'0$X!`,9`0AU(B<;H`````$B#Q`C#9F9FD&9F
+M9I!F9F:09F:02(/L"$B+/P^W]DC!Y@-(`[>X"0``2(LV2(7V=#U(BQ</MT8R
+M9L'H!0^WP(T$A0`#``")@G`!``!(BQ</MTXR@^$?N`$```!(T^")@G0!``"Z
+M`````.@`````2(/$",.005=!5D%505154TB#[`A(B?U)B?:`?T,`="6Y````
+M`/9&#0%T#NL800^V1@U(T_BH`74,@\$!#[9%0V8YR'?H28M&0$B%P'0<2(VP
+MD````$B+?2CH`````$F+=D!(B>_H`````$F-1F!).49@#X1<`0``28G'3(G_
+MZ`````!(B<-(@WA```^$*0$``("X@P`````/A*(```!F@WUP``^$EP```$&]
+M`````$&\`````)!(BX6X"0``3`'@2(LP2(7V=&,/MT8@9CM#.'599CV%`'=3
+M#[?`@+P%:`@``/]T1DB+50`/MT8R9L'H!0^WP(T$A0`#``")@G`!``!(BU4`
+M#[=.,H/A'[@!````2-/@B8)T`0``QD8D(;H`````2(GOZ`````!!@\4!28/$
+M"`^W17!$.>@/CW;___](BT-`2,=`8`````#V0TP$=1E(B>_H`````$B+<T"Z
+M`0```$B)[^@`````2(M#0`^V4`(/MG`!2,?'`````+@`````Z`````!(BU-`
+M2(NU^`@``+\!````Z`````!(BU-`2(NU^`@``+\&````Z`````!(QT-`````
+M`$&`;@X!2(G>2(GOZ`````!-.7Y@#X6G_O__2<=&0`````!(BT4`BXA8`0``
+MB0T`````A<ET"DB+10")B%@!``!(@\0(6UU!7$%=05Y!7\-F9F:09F:09F:0
+M9F:02(/L"$R+!T$/MG!#0(3V=#5)C8#`$@``N0````!(.?AU&NLB#[;!2(T4
+M0$B-%)!)C930P!(``$@Y^G0/@\$!0#CQ=>#K!;D`````#[;!2(T40$B-%)!(
+MC035`````$F+M`#0$@``2(7V='WV1@H"='=)C80`P!(``$@Y1B!U:0^V1EB$
+MP'0(@\`!B$98ZUE(BU9(2(/J.$B-3DA(C4(X2#G(=$1(@WH0`'4LZPIF9I!(
+M@WH0`'4@QD98`0^VBKL```!)B[BX$```2<?``````.@`````ZQ%(BU(X2(/J
+M.$B-0CA(.<AUR$B#Q`C#9F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@2(G[
+M2(GU2(M&<$R+:"@/MTX@9H'YA0!W?P^WP0^VA`=H"```//]T<&:#^7]W(0^V
+MT$B+CT`)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK3F:!^8$`=QP/ML!(BY>0
+M"0``2&G`R`\``$B+1!`(#[9`".LK#[;`2(N7:`D``$B-!,!(P>`%2(N$$(@`
+M```/MD`(ZPMF9I!F9I"X_P```$B81`^VI`/N"```2(MU>$B%]G0(2(G?Z```
+M``!(B>Y(B=_H`````$$/ML1(C3R`2(T\N$B-O/O(`0``3(GN0?^5H````$B+
+M7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:09F:09F:09F:005154TB)]4B)
+MTV:!?CCA`741#[9&.H/H$4&\`````#P!=C1(BS=(B[Y`"0``#[=%(+I@G@$`
+M9CV%`'<7#[?`#[:$!F@(``!(C11`2(T4D$C!X@5,C207QD,$!8!C!?Z`(]^X
+M`````&:!?3CA`741#[9%.H/H`3P!#Y;`#[;`9I#!X`</MA.#XG\)PH@3#[:%
+ME@```(/@`<'@!H/BOPG"B!/VA98````!=`Y,B>?H`````&:)0PCK!&:)2P@/
+MMT,(B$4E9H%]..$!=24/ME4ZC4+_/`%W"@^V53N#X@_K*I"-0N^Z#P```#P!
+M=AUF9F:0N@````!)@WPD8`!T#$$/MI0D@0```(/B#P^V`X/@\`G0B`-;74%<
+MPV9F9I!F9F:02(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)
+M_$B)\TF)UP^V1C@\"'0//"AT"SRH=`<\B&9FD'4.@XN4````"NLE9F:09I`\
+M"G0./"IT"CRJ=`8\BF:0=0Z#BY0````"9F9FD&9FD`^W>SAF@?_A`74<#[9#
+M.H/H$3P!=Q&#BY0````(N`````#I204``$2+0SA!@>#___\`08'XX0$0``^%
+MY@````^W2R!F@?F%``^'\@0```^WP4$/MKP$:`@``(GX0(#__W1N9H/Y?W<C
+M0`^VUTF+C"1`"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZT5F@?F!`'<>0`^V
+MQTF+E"20"0``2&G`R`\``$B+1!`(#[9`".L@0`^VQTF+E"1H"0``2(T$P$C!
+MX`5(BX00B`````^V0`@/ML!!#[:$!.X(``!(C12`2(T4D$F-M-3(`0``28N4
+M))`)``!`#[;'2&G`R`\``$&]`````/9$`ET0#X5@`@``QD,D!$''!P````"X
+M`0```.E+!```#[=3(+G_````N/____]F@?J%``^'BP````^WPD$/MK0$:`@`
+M`(GP0(#^_W1S9H/Z?W<H0`^VUDF+C"1`"0``2(T$4DB-!()(P>`%2(M$"%`/
+MMD`(ZTIF9I!FD&:!^H$`=QY`#[;&28N4))`)``!(:<#(#P``2(M$$`@/MD`(
+MZR!`#[;&28N4)&@)``!(C03`2,'@!4B+A!"(````#[9`"$`/MLY$#[;P26/&
+M00^VK`3N"```2(U$K0!(C42%`$F-M,3(`0``#[?!2(T40$B-%)!(P>(%28G5
+M30.L)$`)``!F@?_A`74+#[9#.H/H`3P!=BEF@?G_`'0'0?9%2P1U&\9#)`9!
+MQP<`````N`$```#I-@,``&9FD&9FD$$/ME5(B=&#X0%T)/;"!'0?00^V1"1$
+M03I$)$IR$D''!P$```"X`0```.D!`P``D$V%[0^$]P```(7)#X3O````]L($
+M#X3F````2(G>3(GOZ`````"$P'45QD,D!$''!P````"X`0```.G"`@``08"]
+M@P```!]V$4''!P$```"X`0```.FG`@``]H.6`````7072(U$K0!(C42%`$'V
+MA,34`0```70;ZU](C42M`$B-1(4`0?:$Q-0!```!#X2_`0``1(GV3(GGZ```
+M``"$P'010<<'`0```+@!````Z4X"``#V@Y8````!#X22`0``2(U$K0!(C42%
+M`$'VA,34`0```0^$>0$``$R)[^@`````9H/X'P^&9P$``$''!P$```"X`0``
+M`.D%`@``9F:09I#V1@H"=#)!@?CA`1``9F:0#X0[`0``00^VA8,```!!.H6"
+M````<AY!QP<!````N`$```#IR`$``$&!^.$!$``/A`P!``!!#[=%:H![..$/
+MA?T```"`>SD!#X7S````2-'H2(G"@^(!#[9#.H/H!CP)#X?&````#[;`_R3%
+M`````$&X`0```+D!````2(G:3(GN3(GGZ`````"$P`^%L````$''!P(```"X
+M`0```.E.`0``0;@!````N0````!(B=I,B>Y,B>?H`````(3`#X5^````0<<'
+M`@```+@!````Z1P!```/MLI!N`$```!(B=I,B>Y,B>?H`````(3`=5)!QP<"
+M````N`$```#I\`````^VRD&X`````$B)VDR)[DR)Y^@`````A,!U)D''!P(`
+M``"X`0```.G$````QD,D!$''!P````"X`0```.FO````28V\)*@/``#H````
+M`(3`=!%!QP<!````N`$```#IC0```(![..%U3H![.0%F9I!U18![.@]U/X![
+M/0%F9F:0=34/MG,\P>8(#[9#.P'&#[?V3(GGZ`````!(.T-H=05(A<!U$L9#
+M)`1!QP<`````N`$```#K.;@`````ZS)FD$$/MH0D[0D``$B-%(!(C12028VT
+MU,@!``!)BY0DD`D``+@XN`\`Z93[__]F9I!FD$B+7"0(2(ML)!!,BV0D&$R+
+M;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD&9FD&9FD&9FD$B#[`A(BS_H`````$B#
+MQ`C#9F9FD&9F9I!F9F:09F:005=!5D%505154TB#[%A)B?U(B?5(BY]`$0``
+M9L=&,O\/2(U4)"SH`````(3`=`F+1"0LZ0X+``"+13@E____`#WA`1``#X7E
+M````OX@3``#H``````^W32!F@?F%``^'N0H```^WP4$/MK0%:`@``(GP0(#^
+M_W1K9H/Y?W<B0`^VUDF+C4`)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK0V:!
+M^8$`=QU`#[;&28N5D`D``$AIP,@/``!(BT00"`^V0`CK'T`/ML9)BY5H"0``
+M2(T$P$C!X`5(BX00B`````^V0`@/ML!!#[:$!>X(``!(C12`2(T4D$V-M-7(
+M`0``28N5D`D``$`/ML9(:<#(#P``2`'"2(E4)!!(QT0D"`````!(QT0D&```
+M``#I<@$```^W52"^_P```&:!^H4`=PP/M\)!#[:T!6@(```/MWTX9H'_X0%U
+M#P^V13J#Z!$\`0^&Q@```&:!^H4`=WH/M\)!#[:$!6@(```\_W1J9H/Z?W<A
+M#[;028N-0`D``$B-!%)(C02"2,'@!4B+1`A0#[9`".M(9H'Z@0!W'`^VP$F+
+ME9`)``!(:<#(#P``2(M$$`@/MD`(ZR4/ML!)BY5H"0``2(T$P$C!X`5(BX00
+MB`````^V0`CK!;C_____#[;`00^VA`7N"```2(T4@$B-%)!-C;35R`$```^W
+MQDB-%$!(C1202,'B!4D#E4`)``!(B50D"&:!_^$!=4;K,@^WQDB-!,!(P>`%
+M20.%:`D``$B)1"083(NPB````$C'1"0(`````$C'1"00`````.M$#[95.HU"
+M[SP!=B>-0O\\`78@9H'^_P!T"TB+1"0(]D!+!'4.QD4D!K@`````Z;8(``!(
+MQT0D$`````!(QT0D&`````!(C70D2$R)[^@`````08G'9HE%,DR)[^@`````
+M28G$N`(```!-A>0/A'<(``!,B:6`````00^WUTB)%"1(:<*P!```2(T<&$B-
+M0R!)*X5`$0``20.%2!$``$B+5"1(B4(@2,'H($B+5"1(B4(D28M$)!A(BU0D
+M2(E"*$C!Z"!(BU0D2(E"+$B+1"1(9D2)>`BX`````,8$&`!(@\`!2#VP!```
+M=?!F@7TXX0%U5`^V13J#Z!$\`7=)2(U,)#!(BT0D2`^V4`A(B>Y(BWPD".@`
+M````2(V#(`0``$DKA4`1``!)`X5($0``2(M4)$B)0A!(P>@@2(M4)$B)0A3I
+M%0$``$$/ME8*]L(!=2R+13@E____`#WA`1``#X2<````2(M,)`@/MD%(J`$/
+MA(L```"H!`^$@P```/:%E@```"!T#TB-="0P2(GOZ`````#K&TB-3"0P2(M$
+M)$@/ME`(2(GN2(M\)`CH`````$B-@R`$``!)*X5`$0``20.%2!$``$B+5"1(
+MB4(02,'H($B+5"1(B4(42(G822N%0!$``$D#A4@1``!(BU0D2(E"&$C!Z"!(
+MBU0D2(E"'.M<]L("=%=(B=A)*X5`$0``20.%2!$``$B+5"1(B4(82,'H($B+
+M5"1(B4(<2(V#(`0``$DKA4`1``!)`X5($0``2(M4)$B)0A!(P>@@2(M4)$B)
+M0A1(BT0D2(!(`0(/ME592(M$)$AFB5`"@'U9`'0SOP````")^$B-!$!(P>`"
+M28MT)!!(BTU@2(L4"$B)%`:+5`@(B50&"(/'`0^V15DY^'?2BU4T2(M$)$B)
+M4`QF@7TXX0%U/P^V13J#Z!$\`7<T00^WSTB+5"1(2(GN3(GWZ`````!(C4PD
+M,$B)VDB)[DR)]^@`````08!F#/[IBP0``&9FD$$/MD8*J`(/A"($``!(BT0D
+M2,9`!OY(BT0D2(!@!_Y(@WPD"``/A+@```!(BT0D"`^V4$A(B="#X`9(@_@&
+M#X6?````]L(!#X26````00^WSTB+5"1(2(GN3(GWZ`````#VA98````!=!!(
+MBT0D2`^W0`C!X`.(1"0Q2(U,)#!(B=I(B>Y,B??H`````/:%E@````%T!T&`
+M3@P!ZP5!@&8,_L8#H4B+5"0(#[:"Z@```(/@#P^V4P&#XO`)PHA3`4B+3"0(
+M#[=!.(/``6;!P`AFB4,"28G,28'$U````.D]`P``9H%]..$!#X4D`@``#[9%
+M.CP/=!-!O``````\$`^%&P,``.FN````#[95/,'B"`^V13L!PDB+1"1(QD`$
+M#4B+1"1(@&`%_H!,)$,(2(MT)$@/MD4E00^VC?8```#3X&8)1@A(BTPD2`^V
+M00&#X!^#R""(00%(BT4^2(F#.`0``&;!P@AFB9-$!```#[9%/8B#0@0``,8#
+MD4B+5"0(#[=".(/``6;!P`AFB4,"2(M,)`@/MI'J````@^(/#[9#`8/@\`G0
+MB$,!28G,28'$U````.EH`@``2(M4)$@/MD4E00^VC?8```#3X&8)0@C&`X%F
+MQT,"__](BT0D$`^VD+L```"#X@\/MD,!@^#P"="(0P%(@WU(`'4.QD4D(;@`
+M````Z>X#``#V13L!="E,BV50387D="!)B[VX$```3(GFZ`````"#X`\/ME,!
+M@^+P"<*(4P'K!4R+9"002(M52`^V0@&^$````#R`#X2&````/(!W'SP5=Q(\
+M$&9FD&:0<V>#Z`(\`7=$ZU<\%V9FD'<[ZUX\A70N/(5F9I!F9I!W$#R!=$,\
+M@G4C9F:09F:0ZR(\D'(7OB@````\DF9FD'8U/)-U![Z,````ZRJ^!````.LC
+M#[9"!(TTA0@```"0ZQ6^"````.L.O@P```!FD.L%OAP```")\L'J`DB+1"1(
+MB%`$2(M,)$AFP>H(@^(!#[9!!8/@_@G0B$$%2(V[(`0``(GR2(MU2.@`````
+MZ0T!```/MD4X@^@$/*MW0`^VP/\DQ0`````/MD5`P>`(#[9508T,$(/Y#7<8
+MN`$```!(T^"IV#X``'0)2(M$)$B`2`$$2(M$)$B`2`$!ZPE(BT0D2(!@`?M(
+MBT0D2,9`!`U(BT0D2(!@!?Y(BU0D2`^V125!#[:-]@```-/@9@E""$B+1"1(
+M@&`!'\:#(`0```9,BV0D"$F!Q-0```!(C;LA!```3(GFZ`````!(C;LE!```
+M3(GFZ`````!(BT4X2(F#1`0``$B+14!(B8-,!```2(M4)`A(BX+<````2(F#
+M.`0``,8#D4B+3"0(#[:1Z@```(/B#P^V0P&#X/`)T(A#`0^W03B#P`%FP<`(
+M9HE#`DV%Y'1C28L$)$B)0P3K6:@!=%5!#[?/2(M4)$A(B>Y,B??H`````/:%
+ME@````%T$$B+1"1(#[=`",'@`XA$)#%(C4PD,$B)VDB)[DR)]^@`````]H66
+M`````70'08!.#`'K!4&`9@S^28N%N`D``$B+%"1(B2S01(GZ9L'J!44/M^>!
+MXO\'``!$B>&#X1^X`0```$C3X$$)A)7`"0``BT4X)?___P`]X0$0`'4I2(U,
+M)$"Z`````$2)YDR)]^@`````#[9$)$.#X!^#R$"(1"1#Z:0```!F@7TXX0%U
+M,P^V13J#Z!$\`7<H2(MT)!A,B>_H`````$B-3"1`2(M$)!@/ME!01(GF3(GW
+MZ`````#K:4B+="0(3(GOZ`````!(C4PD0$B+1"0(#[90<D2)YDR)]^@`````
+M2(M,)`@/ME%(2(G0@^`&2(/X!G4N]L(!="D/MD0D0X/@'X/(8(A$)$,/ME%R
+M@^)_P>($#[=$)$)F)0_X"=!FB40D0DB-="1`3(GOZ`````!(BW,@N`,```!(
+MA?9T04C'QP````"X`````.@`````N`,```#K*4$/MH7M"0``2(T4@$B-%)!-
+MC;35R`$``$F+E9`)``"X.+@/`.G+]?__2(/$6%M=05Q!74%>05_#9F9FD&9F
+M9I!F9I!!54%455-(@^P(2(G]0;T`````3(VG``$``.FY`0``D$R)Y^@`````
+M2(G#2(-X<`!U-DB)[^@`````2(E#<$B%P'4E2(V5``$``$B+A0`!``!(B5@(
+M2(D#2(E3"$B)G0`!``#IG0$``(M#."7___\`/>$!$``/A-T````/MT,@9CV`
+M``^$SP````^VR&:)2R!F@_E_=AIF@7LXX0%U*0^V0SJ#Z!$\`7<>9F9FD&9F
+MD&:!^84`=Q`/M\$/MI0%:`@``(#Z_W49QD,D!DB)WDB)[^@`````Z?T```!F
+M9I!FD`^W<SAF@?[A`745#[9[.HU'[SP!#X?M````ZQ]F9F:0#[;"2(T40$B-
+M%)!(P>(%28G53`.M0`D``.L'C4?_/`%V-F:!^8``="]F@?[A`6:0=0L/MD,Z
+M@^@1/`%V&T'V14L$=13&0R0&2(G>2(GOZ`````#I@````$B)WDB)[^@`````
+M@_@"=PJ#^`%S)69FD.L0@_@#=6%F9I!F9I!F9I#K2TB)WDB)[^@`````9F:0
+MZT9(@[N``````'0/2(VS@````$B)[^@`````2(V5``$``$B+A0`!``!(B5@(
+M2(D#2(E3"$B)G0`!``#K.$B)WDB)[^@`````3#FE``$```^%._[__^L>#[;"
+M2(T40$B-%)!(P>(%28G53`.M0`D``.D6____2(/$"%M=05Q!7<-(@^Q(2(E<
+M)!A(B6PD($R)9"0H3(EL)#!,B70D.$R)?"1`2(GU28G]3(MG4$V+-"1!#[9$
+M)`RH$'0,QH?H````!NF,`@``#[:7Z````(#Z`0^$@@```(#Z`7(:@/H$#X2C
+M````@/H&#X7-`@``9F:0Z5T"``#&A^@````!2(G^3(GWZ`````#&122!08!,
+M)`P(2(.]@`````!T#TB-M8````!,B??H`````$F+A@`!``!(B6@(2(E%`$F-
+MA@`!``!(B44(28FN``$``$R)]^@`````Z6("``"#X/=!B$0D#("'ZP````'&
+MA^@`````QD8D`DR)]^@`````3(GWZ`````#I,P(``,:'ZP````!(@[Z`````
+M`'0/2(VV@````$R)]^@`````28M-0$B%R0^$G@$``(M1!(U"`8E!!(/Z*`^'
+MC`$``$F+A@`!``!(B6@(2(E%`$F-A@`!``!(B44(28FN``$``$&`?4K_="1)
+MBT5@2(7`=`:`>$(`=!5,B>J^`@```$R)Y^@`````Z:@!``!!#[9$)`R#X/>#
+MR!!!B$0D#$F+=5A(A?9U%$&`?"0.`'4LZ>4```!F9F:09F:000^VE8$```!!
+MN`````"Y`@```$R)Y^@`````Z5H!``!!OP````#&1"07`$F-1"1@2(E$)`A(
+MBWPD".@`````2(G%28M$)&A)B6PD:$B+5"0(2(E5`$B)10A(B2A(BU5`2(72
+M=!5)B[;X"```OP4```#H`````(!-3`)(B>J^!@```$R)Y^@`````@+V#````
+M`'0V08U?`4&!_W^6F`!W)DR)]^@`````OP$```#H`````("]@P````!T"X/#
+M`8'[@9:8`'7:08G?@$0D%P$/MD0D%T$X1"0.#X=7____28M]8$B%_W4<0<9%
+M2@-F0<>%R```````3(GN3(GWZ`````#K=^@`````9F9FD&9F9I#K:$$/MEU*
+M2,?'`````+@`````Z`````!!@&0D#.])BX8``0``2(EH"$B)10!)C88``0``
+M2(E%"$F)K@`!``!,B>J^!@```$R)Y^@`````@/O_=0Y,B>I,B>9,B??H````
+M`$R)]^@`````2(M<)!A(BVPD($R+9"0H3(ML)#!,BW0D.$R+?"1`2(/$2,-F
+M9I!!5T%6055!5%532(/L*$B)_4F)]4B+CT`)``"X8)X!`&:!?B"%`'<;#[=&
+M(`^VA`=H"```2(T40$B-%)!(B=!(P>`%3(TD`4B+E1`1``!(@<)`"```00^V
+M1"1RP>`(2)A(`<*+,HDU`````$&)]T'![Q!(BY40$0``2('"0`@``$$/MD0D
+M<L'@"$B82`'"BT($B04`````B$0D$(G"P>H(B%0D$<'H$(A$)!)(BY40$0``
+M2('"0`@``$$/MD0D<L'@"$B82`'"BT((B04`````B$0D$XG"P>H(B%0D%,'H
+M$(A$)!7&1"06`,9$)!<`BTPD$$&)]D'![AA!#[;?1(M$)!1$B?*)WDC'QP``
+M``"X`````.@`````B=B#\`&)PH/B`704183_=`]!QD4D`+@`````Z:@"``!!
+M@'TD@69FD'4A2(U,)!!$B?*)WDR)[^@`````0<9%)`*X`````.E]`@``08M%
+M."7___\`/>$!#@!U#T'&120AN`````#I7@(``$'VA98````!=2B$TG4D08!\
+M)$K_=!Q(C4PD$$2)\HG>3(GOZ`````"X`````.DL`@``3(GF2(GOZ`````!,
+MB>9(B>_H`````$B+50!!#[=%,F;!Z`4/M\"-!(4``P``B8)P`0``2(M%`$$/
+MMTTR@^$?N@$```!(B=-(T^.)F'0!``!!#[=%,DC!X`-(`X6X"0``2,<`````
+M`$$/MTTRB<AFP>@%)?\'``"#X1](B=9(T^9(B?'WT2&,A<`)``!!#[=-,HG(
+M9L'H!27_!P``@^$?2-/B]](A5(5T28M5`$F+10A(B4((2(D000^W=3)(C;VH
+M#P``Z`````!!@*PD@P````%!QD4D@4F#O8``````=`])C;6`````2(GOZ```
+M``!)C40D($DY1"0@#X0)`0``28G&2(V%J`\``$B)1"0(3(V]``$``&9F9I!F
+M9I!,B??H`````$B)PTB+50`/MT`R9L'H!0^WP(T$A0`#``")@G`!``!(BT4`
+M#[=+,H/A'[H!````2(G62-/FB;!T`0``#[=#,DC!X`-(`X6X"0``2,<`````
+M``^W2S*)R&;!Z`4E_P<``(/A'TB)UDC3YDB)\??1(8R%P`D```^W2S*)R&;!
+MZ`4E_P<``(/A'TC3XO?2(52%=`^W<S)(BWPD".@`````08"L)(,````!2(.[
+M@`````!T#TB-LX````!(B>_H`````$B+A0`!``!(B5@(2(D#3(E["$B)G0`!
+M``!-.70D(`^%%/___T&!I90```#___[_0<:$).@````$3(GN3(GGZ`````"X
+M`0```$B#Q"A;74%<05U!7D%?PY!(@^Q82(E<)"A(B6PD,$R)9"0X3(EL)$!,
+MB70D2$R)?"102(E4)!!(BR],BX5`$0``2(72#X3&`@``#[?62&G"L`0``$J-
+M#`#V02$"=!A(C035`````$@#A;@)``!(BP#&0"0"ZQ9(C035`````$@#A;@)
+M``!(BP#&0"0A3(T4U0````!(BX6X"0``3`'02(L0BT(X)?___P`]X0$0``^$
+ML`$```^W0B!F/84`=Q(/M\`/MH0%:`@``#S_=1EF9I!,B=!(`X6X"0``2(L`
+MQD`D!NG*"```#[;`2(T40$B-%)!(P>(%3(N=0`D``$D!TX!\)!,`>6Y!#[93
+M2$B)T(/@!DB#^`9U(_;"`70>2(M%`(N06`$``(D5`````(72=`I(BT4`B9!8
+M`0``2(M%`(N`4`$``(D%`````(/(`DB+50")@E`!``!(BT4`BX`$`0``B04`
+M````@,S_2(M5`(F"!`$``&;W02`""`^$Z@```(!]0P`/A.````"[`````$&Y
+M`````$6)R$$/MLD/MD<-2-/XJ`%T8$&`^0-V)TB+10!(!=`!``"-%(T`````
+M2&/22`'0BP")!0````#!Z!2#X`'K)4B+10!(!=`!``"-%(T`````2&/22`'0
+MBP")!0````#!Z!2#X`&$P'0*N`$```!(T^`)PT&#P0%!C4`!.$5#=X&$VW12
+M.%\-=4V)\&;!Z`4E_P<``(M$A72)\8/A'TC3^*@!=3)!@+OH`````G<(0<:#
+MZ`````-,B=!(`X6X"0``2(LP3(G?Z`````#I3`<``$&[`````/9$)!,!#X0[
+M!P``3(G02`.%N`D``$B+,,9&)"&+1C@E____`#WA`0X`#X07!P``2(N5$!$`
+M`$B!PD`(``!!#[9#<L'@"$B82`'"BP*)!0````!(BY40$0``2('"1`@``$$/
+MMD-RP>`(2)A(`<*+`HD%`````$B+E1`1``!(@<)("```00^V0W+!X`A(F$@!
+MPHL"B04`````2(GOZ`````#IH08``)`/M_9(C1SU`````$B+A;@)``!(`=A(
+MBQ!F@7HXX0$/A0P!```/MGHZ0(#_$`^';@8``+@!````B?E(T^"IP#````^%
+MS````*D```$`=53VQ(`/A$D&``!(:<:P!```2HT,``^V03.(0B1(B=A(`X6X
+M"0``2(L`]D`C!`^$(`8``(!X)``/A!8&``!(BU!02(72#X0)!@``#[9!,X@"
+MZ?X%``!(:<:P!```2HT,`$R-82A(B=A(`X6X"0``2(L000^V1"0"B$(D2(G8
+M2`.%N`D``$B+`$B#>$@`#X3!!0``#[:Y(00``.@`````2(G:2`.5N`D``$B+
+M"HM1-#G0#T?"B<)(BWE(3(GFZ`````#IC04``$B)V$@#A;@)``!(BP#&0"0`
+MZ7<%``!F9F:09F:02(G82`.%N`D``$R+*$V+?6BX_____V9!@7T@A0!W&4B)
+MV$@#A;@)``!(BP`/MT`@#[:$!6@(```/ML!(C11`2(T4D$C!X@5,BZ5`"0``
+M20'40<:$).@`````00^V5"1(2(G0@^`&2(/X!@^%EP$``/;"`0^$C@$``$'&
+M120`0?:%E@```"`/A.0$``!-A?\/A-L$``!!]H>Q`````@^$H0```$&+132%
+MP`^$E0```$F+OZ````!(A?]T#8G"28MU2.@`````ZWQ)@WU(`'1U28._N```
+M``!U"DF#O\``````=&%-BVU(28N'N````$B%P'0-2(G#0?:'L0````%T)DB+
+MM4@*``"Z`0```$R)_T'_E\````"[`````(7`=`=(BYU("@``2(M["(L33(GN
+MZ`````"+`TD!Q8M#!$B#PQ"%P'3B2(N5$!$``$B!PD`(``!!#[9$)'+!X`A(
+MF$@!PHL"B04`````B<+!ZA!!B)>;````P>@89D&)AY````!(BY40$0``2('"
+M1`@``$$/MD0D<L'@"$B82`'"BQ*)%0`````/ML)F08F'E`````^VQF9!B8>6
+M````B=#!Z!`/ML!F08F'F````,'J&$&(EYH```!(BY40$0``2('"3`@``$$/
+MMD0D<L'@"$B82`'"BP*)!0`````/ML!F08F'D@```.EI`P``2&G&L`0``$Z-
+M-`!!#[9&,X3`#X71````2(G82`.%N`D``$B+`,9`)`!!]H66````$`^$,@,`
+M`$V%_P^$*0,``$$/MD8S08B'D@```$'VA[$````"#X0/`P``08-]-``/A`0#
+M``!)@[^X`````'4.28._P``````/A.P"``!-BV5(28N'N````$B%P'0-2(G#
+M0?:'L0````%T)DB+M4@*``"Z`0```$R)_T'_E\````"[`````(7`=`=(BYU(
+M"@``2(M["(L33(GFZ`````"+`TD!Q(M#!$B#PQ"%P`^%AP(``.O<9F:09I`\
+M`@^%*`(``$$/MDY`08M&.(E$)"0/ME0D)P^V1"0DP>`8"<(/MD0D)<'@$`G"
+M#[9$)";!X`A!B=1!"<2#X7^`^7%V/,9$)`T`08/\`78,00^V1D&#X`^(1"0-
+MQD0D#@!!@_P"=@E!#[9.0HA,)`Y!@_P#=F9!#[9&0XA$)`_K8,9$)`T`08/\
+M`G8,00^V3D*#X0^(3"0-QD0D#@#&1"0/`$&#_`=V.4$/MD9'@\`(03G$1`]'
+MX,9$)`X`08/\#'8)00^V1DR(1"0.08/\#78+00^V3DV(3"0/ZP7&1"0/`$B)
+MV$@#A;@)``!(BP"`>#``=$A%A>1T0\9`)"!(B=A(`X6X"0``2(L`#[9`,`^V
+MT$0XX$0/0N)(B=A(`X6X"0``2(L`2(MX4$B%_W0?1(GB28UV0.@`````ZQ%(
+MB=A(`X6X"0``2(L`QD`D(H!\)`T$=1%(B=A(`X6X"0``2(L`QD`D`DDY;2@/
+MA!(!``!-A?\/A`D!``!!]H66````$'1`00^V1C-!B(>2````0?:'L0````)T
+M*D$/MD4P1(GB03C$#T?0A-)T&$F+OZ@```!(A?]T#`^VTDF-=D#H`````(!\
+M)`T+=UP/MD0D#?\DQ0````!!QH>R`````>F?````@'PD#@1U%(!\)`\"=0U!
+MQH>R````$>F$````0<:'L@````+K>D'&A[(````0ZW!!QH>R````"^MF0<:'
+ML@````;K7$'&A[(````-ZU)FD#PH=2=!#[:$)(,```"#Z`%!B(0D@@```$B)
+MV$@#A;@)``!(BP#&0"2!ZR4\"'4*OQ`G``#H`````$B)V$@#A;@)``!(BP#&
+M0"0A9F:09F:02(M<)"A(BVPD,$R+9"0X3(ML)$!,BW0D2$R+?"102(/$6,-F
+M9F:09F:09F:09F:005=!5D%505154TB![*@```!(B?U(B7PD<`^WA[H2``!F
+MB80D@````$B+AZ`1``"+`(D%`````&8E_P]FB8>Z$@``9CN$)(````!U4DB+
+M!XNP4`$``(DU`````$B+!XGR@>+P__\`B9!0`0``N`````"%T@^$F@@``$C'
+MQP````"X`````.@`````2(M\)'#H`````+@!````Z74(``!F@;^Z$@``_P\/
+MA<,'``!F9I#I]`<``$R+A4`1``!F@X0D@`````$/MY0D@````&8[E;X2``"X
+M``````]#T&:)E"2`````2(N5H!$``$B#P@0/MX0D@````(L,@D&)R4'!Z1!!
+M]L$(#X2U````2(M%`(N(4`$``(D-`````$B+50")R"7P__\`B8)0`0``A<!T
+M;(!]0P!T9HG.]\8``0``=3&_`````/?&```!`'1#9F:0ZQ\/M]>-2@A(B?!(
+MT_BH`744C4H02(GP2-/XJ`%U!^L?OP`````/M\=(C12`2(T4D$B-G-7(`0``
+M2(7;=1WK#(/'`0^V14-F.?AWMDB+?"1PZ`````#IZ08``$B+?"1PZ`````"(
+M0P_IUP8``&9FD(G.9H'F_P\/M\9(:="P!```38M$$"!(C3S%`````$B+A;@)
+M``!(`?A(BQA(A=L/A6P!```/M_:)\DC'QP````"X`````.@`````9H-]<``/
+MA'\&``#&A"2?`````&9FD$0/MK0DGP```$Z-//4`````2(N%N`D``$P!^$B+
+M,$B%]@^$^0```$UIYK`$``!,`Z5`$0``2(N=X!````^V3B5$#[:L))\```!$
+MB>I(Q\<`````N`````#H`````$R)^$@#A;@)``!(BSCH`````$&+C"0D!```
+M08N4)"`$``!%BXPD+`0``$6+A"0H!```1(GN2,?'`````+@`````Z`````!,
+MB?!(P>`&2`'#BT,TBWLP1(M3+$2+6RA$BV,D1(MK($2+<QQ$BWL8BTL4B4PD
+M?$2+2Q!$BT,,BTL(BU,$BS.)1"1`B7PD.$2)5"0P1(E<)"A$B60D($2);"08
+M1(ET)!!$B7PD"(M$)'R)!"1(Q\<`````N`````#H`````("$))\````!#[:$
+M))\```!F.T5P#X,Z!0``Z<'^__^00?;!(`^$B`$``(![)(%FD`^%6P$``,9#
+M)"$/MT,R2,'@`T@#A;@)``!(QP``````#[=+,HG(9L'H!27_!P``@^$?N@$`
+M``!(B=9(T^9(B?'WT2&,A<`)```/MTLRB<AFP>@%)?\'``"#X1](T^+WTB%4
+MA70/MW,R2(M\)&#H`````$B#NX``````=`](C;.`````2(GOZ``````/MU,@
+M9H'ZA0`/A\<````/M\(/MH0%:`@``#S_#X2T````9H/Z?W<C#[;`2(T40$B-
+M%)!(P>(%2`.50`D``$B+0E"`>`C_#Y7`ZUD/MT,@9CV!`'<F#[?`#[:$!6@(
+M``!(:<#(#P``2`.%D`D``$B+0`B`>`C_#Y7`ZRD/MT,@#[:$!6@(``!(C03`
+M2,'@!4@#A6@)``!(BX"(````@'@(_P^5P(3`="Y(B=Y(B>_H`````$B+A0`!
+M``!(B5@(2(D#2(M$)%A(B4,(2(F=``$``.G#`P``2(M,)&A(BU$(2(U#$$B)
+M00A(B4L02(E0"$B)`NFB`P``B?!FP>@%1`^W\$ECQ@^W]D&)]T&#YQ^+1(5T
+M1(GY2-/XJ`$/A7D#``!(B?A(`X6X"0``2(L`#[=0(&:!^H4`#X>Z````#[?"
+M#[:$!6@(```\_P^$IP```&:#^G]W(`^VP$B-%$!(C1202,'B!4@#E4`)``!(
+MBT)0#[9`".MM2(GX2`.%N`D``$B+``^W0"!F/8$`=R,/M\`/MH0%:`@``$AI
+MP,@/``!(`X60"0``2(M`"`^V0`CK,TB)^$@#A;@)``!(BP`/MT`@#[:$!6@(
+M``!(C03`2,'@!4@#A6@)``!(BX"(````#[9`"#S_=!`/MM!(8\*`O`7N"```
+M_W4V26/&BT2%=$2)^4C3^*@!#X6.`@``QD,D!DB)W^@`````N@````!(B=Y(
+MB>_H`````.EM`@``2&/"#[:$!>X(``!(C12`2(T4D$B-O-7(`0``387`=`U!
+M]L$"N`````!,#T3`]D<*`@^$7@$``$R)PN@`````26/&BT2%=$2)^4C3^*@!
+M#X49`@``@'LD@0^%CP````^W0S)(P>`#2`.%N`D``$C'```````/MTLRB<IF
+MP>H%@>+_!P``@^$?N`$```!(T^#WT"&$E<`)```/MW,R2(M\)&#H`````$B)
+MWDB)[^@`````2(.[@`````!T#TB-LX````!(B>_H`````$B+A0`!``!(B5@(
+M2(D#2(MT)%A(B7,(2(F=``$``.F``0``2(N%$`$``$@[1"1H=%]!O`````!!
+M@\0!2(L`2#E$)&AU\D6$Y'1&0;T`````2(M\)&CH`````$B-2/!(BW0D:$B+
+M5@A(B48(2(DP2(E0"$B)`D@YV;@!````1`]$Z$&`[`%UR46$[0^%$P$``$B+
+M1"1H2(M0"$B-0Q!(BTPD:$B)00A(B4L02(E0"$B)`DECUK@!````1(GY2-/@
+M"825M````.G8````3(G"Z`````!(BX40`0``2#M$)&AT6T&\`````$&#Q`%(
+MBP!(.40D:'7R183D=$)!O0````!(BWPD:.@`````2(U(\$B+="1H2(M6"$B)
+M1@A(B3!(B5`(2(D"2#G9N`$```!$#T3H08#L`77)183M=6>`>R2!=&%(BT0D
+M:$B+4`A(C4,02(M,)&A(B4$(2(E+$$B)4`A(B0))8]:X`0```$2)^4C3X`F$
+ME;0```#K*69FD&:02(VW$`$``$B)="1H2(V'J`\``$B)1"1@2(V7``$``$B)
+M5"18#[>,)(````!F.8VZ$@``#X4,^/__2(V%$`$``$@YA1`!``!T34B)PV9F
+M9I!(B=_H`````$B-</`/MTXRB<IFP>H%@>+_!P``@^$?N`$```!(T^#WT"&$
+ME;0```"Z`````$B)[^@`````2#F=$`$``'6Z2(GOZ`````"X`0```$B!Q*@`
+M``!;74%<05U!7D%?PV9F9I!F9F:09F:055-(@^P(2(N7^`@``$B+0@B+*(DM
+M`````/?%````D'0&2(M""(DH2(N?^`@``/?%```$`'0K2(L#BY!0`0``B14`
+M````A=)T&$B+`XF04`$``$B+`XN`4`$``(D%`````/?%```(`'0W2('#D!0`
+M`$B+`XN04`$``(D5`````(72=!U(BP.)D%`!``!(BP.+@%`!``")!0````!F
+M9I!FD$B+N_@(``"^`````.@`````2(N;^`@``$B)W^@`````2(V[D!0``.@`
+M````2(N[^`@``+X!````Z`````"X`0```(7M=0NX`````(![2P!U`$B#Q`A;
+M7<-F9F:09F9FD$%7059!54%455-(@^PH28G\2(L'BXA0`0``B0T`````2(L7
+MB<@E\/__`(F"4`$``/?!`/__``^$*`D``$&`?"1#``^$'`D``,9$)!``B<E(
+MB4PD"$0/MFPD$$&-30A(BT0D"$C3^*@!=11!C4T02(M$)`A(T_BH`0^$T0@`
+M`(!\)!`#=BM)BP0D2`6``0``0HT4[0````!(8])(`="+`(D%`````,'H$X/@
+M`>LI9F:028L$)$@%@`$``$*-%.T`````2&/22`'0BP")!0````#!Z!.#X`&$
+MP'0F3(GGZ`````!)8]5(C0122(T$@D&!C,3T$@`````(`&9F9I!F9I!)BQ0D
+M@'PD$`-V)4*-!.T`````2)A(C80"@`$``(L`B04`````)0```0#K(V9F9I!"
+MC03M`````$B82(V$`H`!``"+`(D%`````"4```$`A<!T08!\)!`#=AU"C03M
+M`````$B82(V$`H`!``#'`````0#I&P@``$*-!.T`````2)A(C80"@`$``,<`
+M```!`.G^!P``08!\)$T!#X6H!@``@'PD$`-V*4F+!"1(!8`!``!"C13M````
+M`$ACTD@!T(L`B04`````@^`!ZR=F9F:028L$)$@%@`$``$*-%.T`````2&/2
+M2`'0BP")!0````"#X`&$P`^$50$``$ECQ4B-'$!(C1R82,'C`TF-M!SX$@``
+M28M\)"CH`````$F+O!S0$@``2(7_=!U(BT=`2(7`=!3V0$X"=0[H`````(3`
+MD`^%"@$``$ECQ4B-%$!(C12028N$U-`2``!(A<!T=4F)QH!X#@`/A(L```!!
+MOP````!(C6A@2(GOZ`````!(B<-(BT4(2(E="$B)*TB)0PA(B1CV0TP"=2](
+MBU-`2(72=!9)B[0D^`@``+\%````Z`````"`2TP"2(G:O@8```!,B??H````
+M`$&#QP%%.'X.=B7KH@^V="00N@$```!,B>?H`````+^@A@$`Z`````"Z`"TQ
+M`>L%ND!+3`!)8\5(C0Q`2(T,B$C!X0-*C30AB9;X$@``2,>&"!,````````/
+MMD0D$$B-%$!(C12028V4U,`2``!(B980$P``28VT#/@2``!)BWPD*.@`````
+M9F:0@'PD$`-V/4*-%.T`````2&/228L$)$@%@`$``$@!T(L`B04`````28L$
+M)$@%@`$``$@!PHL"B04`````P>@'@^`!ZSM"C13M`````$ACTDF+!"1(!8`!
+M``!(`="+`(D%`````$F+!"1(!8`!``!(`<*+`HD%`````,'H!X/@`83`='6`
+M?"00`W8W0HT,[0````!(8\E)BP0D2`6$`0``2`'(BP")!0````!)BQ0D2('"
+MA`$``$@!T0T```$`B0'K/D*-#.T`````2&/)28L$)$@%A`$``$@!R(L`B04`
+M````28L4)$B!PH0!``!(`=$-```!`(D!ZR^`?"00`W8H28L$)$@%@`$``$*-
+M%.T`````2&/22`'0BP")!0````#!Z!*#X`'K)DF+!"1(!8`!``!"C13M````
+M`$ACTD@!T(L`B04`````P>@2@^`!A,`/A"("``"`?"00`W8W0HT,[0````!(
+M8\E)BP0D2`6``0``2`'(BP")!0`````-```$`$F+%"1(@<*``0``2`'1B0'K
+M-4*-#.T`````2&/)28L$)$@%@`$``$@!R(L`B04`````#0``!`!)BQ0D2('"
+M@`$``$@!T8D!26/%2(T40$B-%)!)BX34T!(``$B%P'0328G%2(-X0``/A:(`
+M``#IA`$``(!\)!`#=DI"C13M`````$ACTDF+!"1(!8`!``!(`="+"(D-````
+M`$F+!"1(!8`!``!(C00"B0A)BP0D2`6``0``2`'"BP*)!0````#IT`,``$*-
+M%.T`````2&/228L$)$@%@`$``$@!T(L(B0T`````28L$)$@%@`$``$B-!`*)
+M"$F+!"1(!8`!``!(`<*+`HD%`````.F&`P``9I!(BTA`#[=!3@^WT/;&`0^%
+MTP```$B)S?;"`@^$QP```(/@_6:)04Y(C;'`````28M\)"CH`````,9$)!``
+M@'T[`'1WQD0D$``/MD0D$$B+7,582(7;=%1(BU-`2(72=!9)B[0D^`@``+\%
+M````Z`````"`2TP"2(G:O@8```!,B>_H`````("[@P````!T')!,B>?H````
+M`+\!````Z`````"`NX,`````=>6`1"00`0^V1"00.$4[=X['A<````!`2TP`
+M2,>%T`````````!(B:W8````2(VUP````$F+?"0HZ`````"`?"00`W8R28L$
+M)$@%@`$```^V5"002,'B`X'B^`<``$@!T(L`B04`````P>@(@^`!ZS!F9I!F
+M9I!)BP0D2`6``0``#[94)!!(P>(#@>+X!P``2`'0BP")!0````#!Z`B#X`&$
+MP`^$%@$``(!\)!`#=BQ)BP0D2`6``0``#[94)!!(P>(#@>+X!P``2`'0BP")
+M!0````"#\`&#X`'K*DF+!"1(!8`!```/ME0D$$C!X@.!XO@'``!(`="+`(D%
+M`````(/P`8/@`83`#X2Q````#[9$)!!(C11`2(T4D$V-O-3`$@``28M'$$B%
+MP`^$CP```$F)QDF-=SA)BWPD*.@`````08!^#@!T54&]`````$F-;F!F9I!F
+MD$B)[^@`````2(G#2(M%"$B)70A(B2M(B4,(2(D82(M30$B%TG0628NT)/@(
+M``"_!0```.@`````@$M,`D&#Q0%%.&X.=[I!QT<X@(0>`$G'1T@`````38E_
+M4$F-=SA)BWPD*.@`````@'PD$`,/AG\````/MEPD$$C!XP.!X_@'``!)BP0D
+M2`6``0``2`'8BQ")%0````!)BP0D2`6``0``2(T$`XD028L$)$@%@`$``$B-
+M!`.+`(D%`````$F+!"1(!3`"``!(C00#QP``````OQ`G``#H`````$F+!"1(
+M!30"``!(`<.+`XD%`````.M]#[9<)!!(P>,#@>/X!P``28L$)$@%@`$``$@!
+MV(L0B14`````28L$)$@%@`$``$B-!`.)$$F+!"1(!8`!``!(C00#BP")!0``
+M``!)BP0D2`50`@``2(T$`\<``````+\0)P``Z`````!)BP0D2`54`@``2`'#
+MBP.)!0````"`1"00`0^V1"0003A$)$,/A_#V__])BP0DBXA0`0``B0T`````
+M28L4)(G()?#__P")@E`!``#WP0#__P!T(>F>]O__26/52(T$4DB-!()!@8S$
+M]!(``````0#IYO?__[@`````2(/$*%M=05Q!74%>05_#9F9FD&9F9I!F9I!F
+M9I!!5T%6055!5%532(/L:$F)_4"(="1+0`^VQHE$)$Q(F$B-%$!(C1202(T4
+MUTR+NM`2```/MJK*$@``2(L'0(#^`W8,QX!P`0``Q`$``.L*QX!P`0``J`$`
+M`$B)1"1@2`5T`0``2(E$)%!(BU0D8(N"=`$``(D%`````(M,)$R#X0.[!P``
+M`-/C08G<00G$1(FB=`$``+_H`P``Z`````#WTT0AXTB+3"1@B9ET`0``@'PD
+M2P-V58M$)$S!X`)(F$B-E`'0`0``BP*)!0````"#R`B)`HM<)$S!XP-(8]M(
+MC809``(``,<`.````+\0)P``Z`````!(BU0D8$B-A!H$`@``QP``````ZUB+
+M1"1,P>`"2)A(BTPD8$B-E`'0`0``BP*)!0````"#R`B)`HM<)$S!XP-(8]M(
+MC809``(``,<`.````+\0)P``Z`````!(BU0D8$B-A!H$`@``QP``````387_
+M#X0Y"```08!]0P!T++L`````#[;+00^V1PU(T_BH`70/N@$```")SDR)[^@`
+M````@\,!03A=0W?90?9'"@%T:DR)_DR)[^@`````BW0D3$R)[^@`````2&-$
+M)$Q(C11`2(T4D$F-5-4`BX+P$@``J0``$`!T"R7__^__B8+P$@``3(G^3(GO
+MZ`````!(8T0D3$B-%$!(C1202<>$U=`2````````Z94'``!!@']8`'0428N]
+MN!```$R)_N@`````08!O6`%(Q\#^____#[9,)$Q(T\!`(.B(1"1;#X3``@``
+MBW0D3$R)[^@`````2&-$)$Q(C11`2(T4D$F-5-4`BX+P$@``J0``$`!T"R7_
+M_^__B8+P$@``#[9$)%M!B$<-08!]0P`/A.\!``#'1"1<``````^VT$B)5"0P
+M2(M,)&!(@<$``@``2(E,)"A(BT0D8$@%!`(``$B)1"0@#[94)%N)5"0<2(M,
+M)&!(@<'0`0``2(E,)!!$#[9T)%Q!#[;N2(M$)#")Z4C3^*@!#X1-`0``2&/%
+M2(T40$B-%)`/MD0D6T&(A-7*$@``08#^`P^&E0```(T<[0````!(8]M(BT0D
+M*$@!V,<`.````+\0)P``Z`````!(`UPD((M4)!R)$TB+3"1@QX%P`0``Q`$`
+M`$B+5"10BP*)!0````")Z8/A`[L'````T^-!B=Q!"<1$B2*_Z`,``.@`````
+M]]-$(>-(BTPD4(D9C12M`````$ACTD@#5"00BP*)!0````"#R`B)`NF6````
+MC1SM`````$ACVTB+1"0H2`'8QP`X````OQ`G``#H`````$@#7"0@BT0D'(D#
+M2(M4)&#'@G`!``"H`0``2(M,)%"+`8D%`````(GI@^$#NP<```#3XT&)W$$)
+MQ$B+1"101(D@O^@#``#H`````/?302'<2(M4)%!$B2*-%*T`````2&/22`-4
+M)!"+`HD%`````(/("(D"@T0D7`%!C48!03A%0W8LZ8/^__](B=_H`````$B-
+M<,A(BU,(2(E#"$B)&$B)4`A(B0)(@WC8`'01ZPF^`````$F-7TA).5](=<I(
+MA?9T.,9&6@!!@'U#`'0MN0````"Z`````$$/MD<-2-/XJ`%T#@^VPHA,!G"`
+M1EH!@\(!@\$!03A-0W?=N@````"^@0```$R)_^@`````2&-$)$Q(C11`2(T4
+MD$G'A-70$@```````$&`?4,`#X5[`P``Z9X$``"Z`````+X&````3(G_Z```
+M``"+="1,3(GOZ`````!(8T0D3$B-%$!(C12028U4U0"+@O`2``"I```0`'0+
+M)?__[_^)@O`2``!)C4=(23E'2`^$_0$``$B)!"1(BSPDZ`````!,C7#(2(U0
+M$$@Y4!`/A,`!``!)C49(2(E$)`A(BWPD".@`````2(U8\(![20UU%TB-L%`!
+M``!(BT-02(L`2(MX*.@`````2(L32(M#"$B)0@A(B1"`NX,`````=!M,B>_H
+M`````+\!````Z`````"`NX,`````=>5(BT-`2(7`#X0I`0``2,=`8`````"`
+MNX,`````#X2F````9D&#?7``#X2:````O0````!!O`````!F9I!FD$R)X$D#
+MA;@)``!(BS!(A?9T9`^W1B!F.T,X=5IF/84`=U0/M\!!@+P%:`@``/]T1DF+
+M50`/MT8R9L'H!0^WP(T$A0`#``")@G`!``!)BU4`#[=.,H/A'[@!````2-/@
+MB8)T`0``QD8D(;H`````3(GOZ`````"#Q0%)@\0(00^W17`YZ`^/=O____9#
+M3`1U&4R)[^@`````2(MS0+H!````3(GOZ`````!(BT-`#[90`@^V<`%(Q\<`
+M````N`````#H`````$B+4T!)B[7X"```OP$```#H`````$B+4T!)B[7X"```
+MOP8```#H`````$C'0T``````08!O#@%!@&Y8`4B)WDR)[^@`````2(M4)`A)
+M.59(#X5)_O__08!O*`%,B?9,B>_H`````$B+#"1).4](#X4'_O__28U'8$DY
+M1V`/A.P```"]`````$F)Q$R)Y^@`````2(G#@+B#`````'0WC44!@?U_EI@`
+M=@2)Q>LHB<5,B>_H`````+\!````Z`````"`NX,`````=`N#Q0&!_8&6F`!U
+MVDB+0T!(A<!T=DC'0&``````]D-,!'493(GOZ`````!(BW-`N@$```!,B>_H
+M`````$B+0T`/ME`"#[9P`4C'QP````"X`````.@`````2(M30$F+M?@(``"_
+M`0```.@`````2(M30$F+M?@(``"_!@```.@`````2,=#0`````!!@&\.`4B)
+MWDR)[^@`````33EG8`^%'/___TR)_DR)[^@`````2&-$)$Q(C11`2(T4D$G'
+MA-70$@```````.EZ_/__0;\`````#[9$)%M(B40D0$B+5"1@2('"T`$``$B)
+M5"0X18G^00^V[TB+1"1`B>E(T_BH`74+1#A\)$L/A=4```!!@/X#=FA(BT0D
+M8,>`<`$``,0!``!(BU0D4(L"B04`````B>F#X0.-#$F[!P```-/C08G<00G$
+M1(DBO^@#``#H`````/?31"'C2(M,)%")&8T4K0````!(8])(`U0D.(L"B04`
+M````@\@(B0+K9TB+1"1@QX!P`0``J`$``$B+5"10BP*)!0````")Z8/A`XT,
+M2;L'````T^-!B=Q!"<1$B2*_Z`,``.@`````]]-!(=Q(BTPD4$2)(8T4K0``
+M``!(8])(`U0D.(L"B04`````@\@(B0)!@\<!08U&`4$X14,/A_G^__](@\1H
+M6UU!7$%=05Y!7\-F9F:09F9FD&9F9I!!5%5328G\2(GU#[9W0T"$]G0F#[95
+M#;L`````]L(!=`[K%DB)T(G92-/XJ`%U#X/#`4`X\W7LZP6[`````/9%#`)U
+M"DB-16!(.45@=6A(B>_H`````(3`=%%,B>?H`````$B)QDB%P'1,2(M5:$B)
+M16A(C45@2(D&2(E6"$B),H!%#@%(B6Y0QD9(!<9&20#&AH$````/N0$```"Z
+M`0```$B)[^@`````ZPL/MO-,B>?H`````%M=05S#9F:09I!!5D%505154TB)
+M_4&)]40/MO9"C02U`````$QCX+L`````OQ`G``#H`````$&`_0-V'DB+10!(
+M!=`!``!,`>"+`(D%`````,'H%(/@`>L=D$B+10!(!=`!``!)C00$BP")!0``
+M``#!Z!2#X`&$P'4*@\,!9H'[+`%UJ$2)]DB)[^@`````2(GOZ`````!)8\9(
+MC11`2(T4D$B-1-4`]H#)$@```70/2(NPT!(``$B)[^@`````6UU!7$%=05[#
+M9I!!5D%505154T&)]4F)_$0/MO9)8\9(C11`2(T4D$B+K-?0$@``2(7M#X26
+M`0``2,?`_O___T2)\4C3P(1%#0^%@`$``$B-14A(.45(=15!O0````!(C5U@
+M@'T.`'4CZ?,"``!`#[;&2(T\0$B-/+A)C;S\P!(``.@`````Z=4"``!(B=_H
+M`````$B)P4B+0PA(B4L(2(D92(E!"$B)"(!Y20`/A0D!```/MT$X28.\Q&@$
+M````=0M(@WE```^$V0````^W03A)BX3$:`0``$B#N(``````#X2G````QH'H
+M``````^V44A(B="#X`9(@_@&=2WVP@%T*,9!2@7&04L$#[:1@0```$B+<5A(
+MBWE0Z`````#IF````&9F9I!F9I`/ME%(2(G0@^`&2(/X!'4@]L(!=!O&04H#
+MQD%+!$B)SDR)Y^@`````ZV=F9I!F9I`/ME%(2(G0@^`&2(/X!G51]L(!=4S&
+M04L&QD%*!6;'@<@``````$B)SDR)Y^@`````ZRY(BU%`28NT)/@(``"_!```
+M`.@`````ZQ8/MU$X28NT)/@(``"_`@```.@`````08/%`40X;0X/AI<!``#I
+MO?[__T*-!+4`````2&/HNP````"_$"<``.@`````08#]`W8=28L$)$@%T`$`
+M`$@!Z(L`B04`````P>@4@^`!ZQM)BP0D2`70`0``2`'HBP")!0````#!Z!2#
+MX`&$P'4*@\,!9H'[+`%UJD2)]DR)Y^@`````3(GGZ`````!)8\9(C11`2(T4
+MD$F+K-30$@``2(7M#X3]````08!\)$,`="R[``````^VRP^V10U(T_BH`70/
+MN@````")SDR)Y^@`````@\,!03A<)$-WV4$/ML5(C11`2(T4D$F-E-3`$@``
+M2(E5($B-14A(.45(=3A(C45@2#E%8'4NZWMF9I!FD$B)W^@`````2(UPR$B+
+M4PA(B4,(2(D82(E0"$B)`DB#>-@`=!'K";X`````2(U=2$@Y74AURDB%]G1;
+MQD9:`$&`?"1#`'1/N0````"Z``````^V10U(T_BH`70.#[;"B$P&<(!&6@&#
+MP@&#P0%!.$PD0W8BZ]OV10H!=`U(B>Y,B>?H`````.L-O@````!(B>_H````
+M`%M=05Q!74%>PY!(@^P(3(L'1(M/-$$/MG!#0(3V=&))C8#`$@``N0````!(
+M.?AU&NM/#[;!2(T40$B-%)!)C930P!(``$@Y^G0(@\$!0#CQ=>"`^0-V+TF+
+M`$@%T`$``$B-%(T`````@>+\`P``2`'0BP")!0````#!Z!2#X`'K+;D`````
+M28L`2`70`0``2(T4C0````"!XOP#``!(`="+`(D%`````,'H%(/@`83`=!`/
+MMO%$B<I,B<?H`````.L+#[;Q3(G'Z`````!(@\0(PV9F9I!F9F:005=!5D%5
+M05154TB#[`A(B?-)B?Y,BZ>(````28LL)$'V1"0,$'0$QD=1!D$/MD91/`%T
+M>3P!<A4\!`^$F0```#P&#X5(`P``Z;H!``!!QD91`4R)]DB)[^@`````QD,D
+M@4&`3"0,"$B#NX``````=`](C;.`````2(GOZ`````!(C94``0``2(N%``$`
+M`$B)6`A(B0-(B5,(2(F=``$``$B)[^@`````Z>,"``!!@&0D#/=!@$92`4'&
+M1E$`QD,D`DB)WDB)[^@`````2(GOZ`````#IMP(``$$/MD0D#(/@]X/($$&(
+M1"0,08N6"`$``(U"`4&)A@@!``"#^@(/AP,!``!(@[N``````'0/2(VS@```
+M`$B)[^@`````2(V5``$``$B+A0`!``!(B5@(2(D#2(E3"$B)G0`!``!!@'Y"
+M`'480;\`````38UL)&!!@'PD#@!U'NF>````N@````"^`@```$R)Y^@`````
+M9I#I&P(``$R)[^@`````2(G#28M%"$F)70A,B2M(B4,(2(D82(M30$B%TG05
+M2(NU^`@``+\%````Z`````"`2TP"2(G:O@8```!,B>?H`````("[@P````!T
+M(F9F9I!F9I!(B>_H`````+\!````Z`````"`NX,`````=>5!@\<!13A\)`X/
+MAWO___],B??H`````.F)`0``08!D)`SW0<>&"`$```````!(@[N``````'0/
+M2(VS@````$B)[^@`````2(V5``$``$B+A0`!``!(B5@(2(D#2(E3"$B)G0`!
+M``"Z`````+X&````3(GGZ`````!)C40D8$DY1"1@='Q)B<5,B>_H`````$B)
+MPTB+0$!(A<!T4TC'0&``````2(GOZ`````!(BW-`N@$```!(B>_H`````$B+
+M4T!(B[7X"```OP$```#H`````$B+4T!(B[7X"```OP8```#H`````$C'0T``
+M````2(G>2(GOZ`````!-.6PD8'6'3(GV2(GOZ`````!)QT0D0`````!(BT4`
+MBY!8`0``B14`````A=)T"DB+10")D%@!``!!]D0D"@%T:X!]0P!T++D`````
+M0?9$)`T!=!7K'69FD&9FD$$/MD0D#4C3^*@!=0^#P0$X34-WZ^L%N0`````/
+MMMF)WDB)[^@`````3(GF2(GOZ`````!(8]M(C01;2(T$@TC'A,70$@``````
+M`&9FD&:02(/$"%M=05Q!74%>05_#D$B#["A(B5PD"$B);"003(ED)!A,B6PD
+M($B)\TB)_4R+;U!-BV4`#[=.,HG(9L'H!0^W\$ACQD&+1(1T@^$?2-/XJ`$/
+MA6<#``!)BQ0DC02U``,``(F"<`$``$F+!"2+D'0!``")%0````#&0R0ABT,X
+M)?___P`]X0$/`'4C2(G?Z`````"Z`````$B)WDR)Y^@`````Z18#``!F9I!F
+M9I")T`^W2S*#X1](T_BH`7002(G?Z`````!,B>?H``````^VA>@````\!`^'
+MX0(```^VP/\DQ0````#&A>@````!N@$```!(B=Y,B>_H`````.F[`@``QH7H
+M`````KH(````2(G>3(GOZ`````#IGP(``,:%Z`````-(B>J^(0```$R)[^@`
+M````2(MU6$B%]G0?#[:5@0```$&X`````+D!````3(GOZ`````#I8`(``$$/
+MMG4-N@````!,B>?H`````.E)`@``QH7H````!$B#?5@`=#-(B>J^(0```$R)
+M[^@`````#[:5@0```$B+=5A!N`````"Y`@```$R)[^@`````Z0@"``"Z````
+M`+XA````3(GOZ`````!!#[9U#;H!````3(GGZ`````#IWP$``(!]2O]T%4B)
+MZKX&````3(GOZ`````#IQ`$``$B)ZKX&````3(GOZ`````!(BTU`2(7)=!*+
+M402-0@&)002#^@4/AID!``#&14L!QD5*`("]@P````!T&TR)Y^@`````OP$`
+M``#H`````("]@P````!UY4B#?5@`=!E(BU402(M%&$B)0@A(B1!(BT58@&A8
+M`>L92(M58$B%TG00#[:%@0```$C'1,)8`````$B+50!(BT4(2(E""$B)$$&`
+M;0X!2(N](`$``$B%_W01#[:U#0$``+H!````Z`````!(BWU82(7_=!$/MK6!
+M````N@$```#H`````$B+14!(A<!T<DC'0&``````3(GGZ`````!(BW5`N@$`
+M``!,B>?H`````$B+14`/ME`"#[9P`4C'QP````"X`````.@`````2(M50$F+
+MM"3X"```OP$```#H`````$B+54!)B[0D^`@``+\&````Z`````!(QT5`````
+M`$B)[DR)Y^@`````08!]"?]T7+T`````08!]#@!T.;T`````28U=8&9F9I!F
+M9I!(B=_H`````$B+4PA(B4,(2(D82(E0"$B)`H!X2O]U"8/%`4$X;0YWUT$X
+M;0YW$4'&10G_3(GN3(GGZ`````"02(M<)`A(BVPD$$R+9"083(ML)"!(@\0H
+MPV9F9I!F9I!!5T%6055!5%532(/L:$F)_TB+AX@```!(B40D8$B+*$B+A:`1
+M``!$BS!(B?Y(B>_H`````$&`?U(!=@5!QD=1!$F-7RA).5\H#X13`0``2(G?
+MZ`````!(B40D6$F+1RA(BU0D6$B)4`A(B0)(B5H(28E7*$B%T@^$.P,``$B+
+M3"1@2(M!(`^V34$/ME4Z#[9U.4B+7"181`^W2S)$#[9`"$C'QP````"X````
+M`.@`````1`^W:S)-:>6P!```3`.E0!$``$B+G>`0``!(BWPD6.@`````08N,
+M)"0$``!!BY0D(`0``$B+?"18#[=W,D6+C"0L!```18N$)"@$``!(Q\<`````
+MN`````#H`````$G!Y09,`>N+0S2+>S!$BU,L1(M;*$2+8R1$BVL@BU,<B50D
+M3(M+&(E,)%"+4Q2)5"141(M+$$2+0PR+2PB+4P2+,XE$)$")?"0X1(E4)#!$
+MB5PD*$2)9"0@1(EL)!B+7"1,B5PD$(M\)%")?"0(BT0D5(D$)$C'QP````"X
+M`````.@`````9H-]<`!U.^GK`0``2(M4)&!(BT(@#[9-00^V53H/MG4Y0;G_
+M__\`1`^V0`A(Q\<`````N`````#H`````.D1`@``NP````!,C:6H#P``3(VM
+M``$``&9FD&:0#[?#2,'@`T@#A;@)``!(BS!(A?8/A'8!```/MT8@9D$Y1T`/
+MA6<!```/MY6Z$@``03G6=%"#P@$/MX6^$@``.<*X``````]#T(U"`4C!X`)(
+M`X6@$0``BP"I```(`'4@9B7_#V8YV'472#ET)%AU%4B)[^@`````Z7P!``!F
+M9I!$.?)UL`^W1B!F/84`9F:0#X?Z````#[?`@+P%:`@``/\/A.D```!(BTPD
+M8(!Y6``/A=H```#V00H!#X30````2(M5``^W1C)FP>@%#[?`C02%``,``(F"
+M<`$``$B+10`/MTXR@^$?N@$```!(B==(T^>)N'0!```/MT8R2,'@`T@#A;@)
+M``!(QP``````#[=.,HG(9L'H!27_!P``@^$?2(G72-/G2(GY]]$AC(7`"0``
+M#[=.,HG(9L'H!27_!P``@^$?2-/B]](A5(5T2#ET)%AT)TB+!DB+5@A(B5`(
+M2(D"2(N%``$``$B)<`A(B09,B6X(2(FU``$```^W=C),B>?H`````$&`;T4!
+M9F9FD(/#`68Y77`/AV/^__](BT0D8/9`"@%T44B+3"182(L12(M!"$B)0@A(
+MB1!(B<Y,B?_H`````.LQ2(M<)&!(BT,@#[9-00^V53H/MG4Y0;G___\`1`^V
+M0`A(Q\<`````N`````#H`````$B#Q&A;74%<05U!7D%?PV9F9I!F9F:005=!
+M5D%505154TB#["A)B?A(B50D($R++P^W]DC!Y@-)`[6X"0``2(LN9H%]..$!
+M=2X/MD4Z@^@1/`%W(TR+?T!(QT0D&`````!(A=)U:4'&1U$`2,=$)!@`````
+MZUF028N-0`D``+A@G@$`9H%]((4`=QP/MT4@00^VA`5H"```2(T40$B-%)!(
+MB=!(P>`%2`'!2(E,)!A!OP````!(@WPD(`!U$DB+1"08QH#H`````$&_````
+M`(!])(%U!4&`8`SW2(-\)"``#X4"`0``QD4D`/:%E@```"`/A$(%``!(BT5H
+M2(7`#X0U!0``2(G#]H"Q`````G0=2(NXH````$B%_W012(MU2$B%]G0(BU4T
+MZ`````!)BY40$0``2('"0`@``$B+3"08#[9!<L'@"$B82`'"BP*)!0````")
+MPL'J$(B3FP```,'H&&:)@Y````!)BY40$0``2('"1`@```^V07+!X`A(F$@!
+MPHL2B14`````#[;"9HF#E`````^VQF:)@Y8```")T,'H$`^VP&:)@Y@```#!
+MZAB(DYH```!)BY40$0``2('"3`@```^V07+!X`A(F$@!PHL"B04`````#[;`
+M9HF#D@```.E1!```#[=%,DAIP+`$``!-BZ5`$0``20'$28V<)"`$``"`?22`
+M=03&120A2(-\)!@`=%-(BT0D&$B#>$``#X6`````BWTT1`^VB($```!)BT`@
+M1`^V0`A!#[9-04$/ME4Z00^V=3E(BT0D($B)1"0(B3PD2,?'`````+@`````
+MZ`````#K/4V%_W0X1(M--$F+0"!$#[9`"$$/MDU!00^V53I!#[9U.4B+1"0@
+M2(D$)$C'QP````"X`````.@`````9I"+2P2+$P^W=3)$BTL,1(M#"$C'QP``
+M``"X`````.@`````0?9$)"(!='U,C6583(NU@````$&+5"0$00^V="0!2,?'
+M`````+@`````Z`````"`?5@`#X3U````NP`````/ML-(C01`2,'@`DF+5"0(
+M2`'"20-&$(M*"$B+$@^V\T2+2`A,BP!(Q\<`````N`````#H`````(/#`4$X
+M'"0/AJL```#KN4&`?"0G`&9FD`^)F@````^W=3*)\F;!Z@4/M](/M_9(Q\<`
+M````N`````#H`````$&+C<@)``!!BY7$"0``08NUP`D``$6+A<P)``!(Q\<`
+M````N`````#H``````^W=3)(Q\<`````N`````#H`````$F+50`/MT4R9L'H
+M!0^WP(T$A0`#``")@G`!``!)BU4`#[=-,H/A'[@!````2-/@B8)T`0``9I!F
+M@7TXX0%U&`^V13J#Z!$\`7<-3(G_Z`````#I(@(```^V5"0C]L(!#X3R`0``
+MBT4X)?___P`]X0$.``^$WP$``$F+E1`1``!(@<)`"```2(M,)!@/MD%RP>`(
+M2)A(`<)$BR)$B24`````28N5$!$``$B!PD0(```/MD%RP>`(2)A(`<)$BS)$
+MB34`````28N5$!$``$B!PD@(```/MD%RP>`(2)A(`<*+&HD=`````$F+E1`1
+M``!(@<),"```#[9!<L'@"$B82`'"1(L"1(D%`````(G91(GR1(GF2,?'````
+M`+@`````Z`````#VA98````@#X3J````2(M]:,:'L@```!#&120@1(G@P>@0
+MB(>;````1(G@P>@89HF'D````(G8P>`(00^VU@'09HF'E````(G8L`!,B?$/
+MMM4!T&:)AY8```")VL'J$,'B"$2)\,'H$`^VP`'"9HF7F````$F+E1`1``!(
+M@<),"```2(M,)!@/MD%RP>`(2)A(`<*+,HDU`````$`/MO9FB;>2````#[>/
+ME@````^WEY@````/M_9$#[>'E````$C'QP````"X`````.@`````28N5$!$`
+M`$B!PD`(``!(BTPD&`^V07+!X`A(F$@!PL<"`````.M>9H%]..$!=20/MD4Z
+M@^@:/`%W&4C'QP````"X`````.@`````QD4D(>LT9I!(B>Y,B>_H`````.LE
+M9F:0A-)Y'DF+10"+B%@!``")#0````"%R70*28M%`(F(6`$``$B#Q"A;74%<
+M05U!7D%?PV9F9I!F9F:09F9FD&9FD$B#[`@/MD8X2#E^*'5*/`AT93PH=&$\
+MJ'1=/(AF9F:0=%4\"G11/"IT33RJ9F9FD'1%/(IT04B+AP`!``!(B7`(2(D&
+M2(V'``$``$B)1@A(B;<``0``ZQ](BY<(`0``2(FW"`$``$B-AP`!``!(B09(
+MB58(2(DRZ`````!(@\0(PV9F9I!F9F:09F9FD&9FD$B#[`CH`````$B#Q`C#
+M9I!32(/L8$B)^TB-3"1=2(U4)%Y(C70D7P^W?SQ(C40D4DB)1"0X2(U$)%1(
+MB40D,$B-1"1,2(E$)"A(C40D3DB)1"0@2(U$)%A(B40D&$B-1"1:2(E$)!!(
+MC40D6TB)1"0(2(U$)%9(B00D3(U,)%Q,C40D4.@`````#[94)%\/MG0D7DB-
+M?"1(Z``````/MD0D7TB-%$!(C1202,'B!4B+<R!(C;L@"0``N0$```#H````
+M``^V5"1=2(T4TDC!X@5(BW,@2(V[2`D``+D!````Z``````/ME0D7DAITL@/
+M``!(BW,@2(V[<`D``+D!````Z``````/MU0D6$C!X@-(BW,@2(V[F`D``+D!
+M````Z``````/MT0D4$B-%(!(C1202,'B`TB+<R!(C;MP"@``N0$```#H````
+M``^V5"1<#[=$)%!(#Z_02(T44DC!X@)(BW,@2(V[``H``+D!````Z`````!(
+MBW,@2(V[*`H``+D!````N@`"``#H``````^V3"1?2(MS($B-NV`+``"Z``@`
+M`.@`````#[94)%M(P>(%2(MS($B-N\`*``"Y`0```.@`````2(MS($B-N^@*
+M``"Y`0```+H``0``Z``````/ME0D6DB-%))(P>(%2(MS($B-NQ`+``"Y`0``
+M`.@`````#[=4)%9(C1222,'B`TB+<R!(C;LX"P``N0$```#H``````^W5"18
+M2`'22(MS($B-NX`/``"Y`0```.@`````#[94)%](`=)(BW,@2(V[N`\``+D!
+M````Z``````/ME0D74@!TDB+<R!(C;OP#P``N0$```#H``````^V5"1>2`'2
+M2(MS($B-NR@0``"Y`0```.@`````#[93/D@!TDB+<R!(C;M@$```N0$```#H
+M``````^W5"1.2(T44DC!X@1(BW,@2(V[F`H``+D!````Z`````"+5"1(2(MS
+M($B-NY@0``"Y`0```.@`````#[=4)%A(P>(&2(MS($B-N\`0``!!N`$```"Y
+M0````.@`````2(MS($B-N_`0``!!N`$```"Y``$``+H`&0``Z``````/MU0D
+M6$AITK`$``!(BW,@2(V[(!$``$&X`0```+F`````Z``````/MU0D5$C!X@)(
+MBW,@2(V[4!$``$&X`0```+D$````Z``````/MU0D4DC!X@)(BW,@2(V[@!$`
+M`$&X`0```+D$````Z``````/ME0D6\'B"TB+<R!(C;NP$0``0;@!````N0@`
+M``#H`````$B+<R!(C;O@$0``0;@!````N0@```"Z```(`.@`````#[=4)%9(
+M:=*,`0``2(MS($B!PQ`2``!!N`$```"Y"````$B)W^@`````N`````!(@\1@
+M6\-F9I!FD$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!)B?=)
+MB?U(BP=(B00D3(UG2$R)Y^@`````2(G#3(UPR$B+/"3H`````$B)Q4F+15!)
+MB5U038EF.$F)1D!(B1BX`0```$B%[71XQD4XX<9%.0'&13H0@$T[`4F+AZ``
+M``!(B45H2(M%<$R)>"A)C8>0````2(E%4,9%)<Q!#[9&6V:)12!)BT4`2(E%
+M*,=%-)````!,B7U(2,>%H`````````!(C7U8O@````#H`````$B)[DB+/"3H
+M`````+@`````2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$.,-F
+M9F:09F:09F:005=!5D%505154TB#[!A(B?U(QT0D$`````!(BT0D$`^VE"CN
+M"```@/K_#X3J````#[;*2(T$B4B-!(%(C83%R`$``$B)1"0(#[;R2&/&2(T4
+M@$B-%)"`O-76`0````^$M@```$&\`````$B-!(E(C02!2,'@`TR-M`4H`@``
+M3(TL*$ACQDB-%(!(C1203(V\U<`!``!,B??H`````$B)PTF+A3`"``!)B9TP
+M`@``3(DS2(E#"$B)&$B+4T!(A=)T%4B+M?@(``"_!0```.@`````@$M,`DB)
+MVKX"````2(M\)`CH`````("[@P````!T&TB)[^@`````OP$```#H`````("[
+M@P````!UY4&#Q`%%.&<6#X=[____2(-$)!`!2(-\)!`$#X7N_O__2(GOZ```
+M``!(@\086UU!7$%=05Y!7\-F9F:09F:09F:09F:005=!5D%505154TB#['A(
+MB?O&1TT`QD=,`,9'2P#&AW$4````2(V7P!(``+@`````Q@00`$B#P`%(/:`!
+M``!U\$B-@P`!``!(B8,``0``2(F#"`$``$B-@Q`!``!(B8,0`0``2(F#&`$`
+M`$R-HR`!``!,B:,@`0``3(FC*`$``$R-JS`!``!,B:LP`0``3(FK.`$``$B-
+M@T`!``!(B40D2$B)@T`!``!(B8-(`0``2(V+4`$``$B)3"102(F+4`$``$B)
+MBU@!``!,C;-P`0``3(FS<`$``$R)LW@!``!(C;.``0``2(ET)$!(B;.``0``
+M2(FSB`$``$R-NV`!``!,B;M@`0``3(F[:`$``$B-3"1N2(U4)'!(C70D<0^W
+M>SQ(C40D<DB)1"0X2(U$)'1(B40D,$B-1"1D2(E$)"A(C40D:DB)1"0@2(U$
+M)'9(B40D&$B-1"1L2(E$)!!(C40D;4B)1"0(2(U$)&A(B00D3(U,)&],C40D
+M9N@`````#[9$)'&(0T8/MD0D<(A#1P^V1"1NB(/Y````#[=$)'9FB4-P#[=$
+M)'1FB8.\$@``#[=$)'*#Z`%FB8.^$@``#[=$)&9FB4-.#[=#/&8]@)%T"F8]
+M@)0/A:@)``#&0TD$QD-#!,9#2D#&0T@`QH/V````"<9#1`!(C;L@"0``Z```
+M``!(B<%(B8-`"0``#[9$)'%(C11`2(T4D$C!X@5(A=)T$$B)R,8``$B#P`%(
+M@^H!=?-(C;M("0``Z`````!(B<%(B8-H"0``#[9$)&Y(C03`2(G"2,'B!4B%
+MTG002(G(Q@``2(/``4B#Z@%U\TB-NW`)``#H`````$B)P4B)@Y`)```/MD0D
+M<$AIT,@/``!(A=)T$$B)R,8``$B#P`%(@^H!=?-(C;N8"0``Z`````!(B<%(
+MB8.X"0``#[=$)'9(C13%`````$B%TG002(G(Q@``2(/``4B#Z@%U\TB-NR@*
+M``#H`````$B)@T@*``!(C;L`"@``Z`````!(B<5(B8,@"@``2(V[<`H``.@`
+M````2(G"2(F#D`H``&:#?"1F`'1(N0````!(B6I@#[9$)&^(0EA(BX,H`0``
+M2(F3*`$``$R)(DB)0@A(B1`/MD0D;TB-!$!(C6R%`$B!PJ@```"#P0%F.4PD
+M9G>]2(V[F`H``.@`````2(G"2(F#N`H``&:#?"1J`'0ON0````#&0A``2(N#
+M.`$``$B)DS@!``!,B2I(B4((2(D02(/",(/!`68Y3"1J=]9(C;O`"@``Z```
+M``!(B<)(B8/@"@``@'PD;0!T,[D`````2(N#2`$``$B)DT@!``!(BW0D2$B)
+M,DB)0@A(B1!(@\(@@\$!#[9$)&UF.<AWTDB-N^@*``#H`````$B)PDB)@P@+
+M``!(C8@``0``2(N#6`$``$B)DU@!``!(BW0D4$B),DB)0@A(B1!(@\(@2#G*
+M==I(C;L0"P``Z`````!(B<)(B8,P"P``@'PD;`!T,;D`````2(N#>`$``$B)
+MDW@!``!,B3)(B4((2(D02('"H````(/!`0^V1"1L9CG(=]1(C;LX"P``Z```
+M``!(B<)(B8-8"P``9H-\)&@`="NY`````$B+@V@!``!(B9-H`0``3(DZ2(E"
+M"$B)$$B#PBB#P0%F.4PD:'?:@'PD<0!T2;T`````3(VC8`L``$R)Y^@`````
+M#[?52(F$TX`+``!(BY.(`0``2(F#B`$``$B+3"1`2(D(2(E0"$B)`H/%`0^V
+M1"1Q9CGH=\-(C;N`#P``Z`````!(B8.@#P``2(F#J`\```^W="1V9HFSL@\`
+M``^W]DB-NZ@/``#H`````$B-N[@/``#H`````$B)@]@/``!(B8/@#P``#[9T
+M)'%FB;/J#P``#[?V2(V[X`\``.@`````2(V[\`\``.@`````2(F#$!```$B)
+M@Q@0```/MG0D;F:)LR(0```/M_9(C;L8$```Z`````!(C;LH$```Z`````!(
+MB8-($```2(F#4!````^V="1P9HFS6A````^W]DB-NU`0``#H`````$B-NV`0
+M``#H`````$B)@X`0``!(B8.($```#[9#/F:)@Y(0```/MG,^2(V[B!```.@`
+M````2(V[F!```.@`````2(G!2(F#N!````^V1"1P2(T$P$C!X`>)QH'&8%<`
+M`'02B?)(B<C&``!(@\`!2(/J`77S2(N#N!```(DP2(N3N!````^V1"1PB$($
+M#[94)'!(B[NX$```Z`````!!N`````"`>SX`#X2H````OP`````/M\=(C12`
+M2(T4D$C!X@-,C803R`$``$B-!!I(C;#``0``0(A^$,9&$0!(B9C(`0``QD86
+M`,:`(`(```#&@/`!````QX!H`@```````$B-C!/X`0``2(F(^`$``$B)B``"
+M``!(C8P3$`(``$B)B!`"``!(B8@8`@``2(V4$R@"``!(B9`H`@``2(F0,`(`
+M`,9&$@*#QP$/MD,^9CGX#X==____QD-(`,:#[@@``/_&@^\(``#_QH/P"```
+M_\:#\0@``/^`?"1Q``^$E@```+X`````#[?.2(T$24B-!(%(P>`%2(N30`D`
+M`,9$`DL!2(N30`D``,9$$$H`2(N30`D``,:$$(````#_2(N30`D``,9$$'+_
+M2(N30`D``&;'A!#(``````!(QX3+:`0```````!(B<%(`XM`"0``2(U1($B)
+M42!(`X-`"0``2(U0($B)4"B#Q@$/MD0D<68Y\`^';____V;'@_0``````+@`
+M````QH08:`@``/](@\`!2#V&````=>R`?"1P``^$O0```+X`````#[?&2&G`
+MR`\``$B+DY`)``#&1`)8`$B+DY`)``#&1!!9`$B+DY`)``!(QT00$`````!(
+MB<%(`XN0"0``2(U1&$B)41A(B<%(`XN0"0``2(U1&$B)42!(B<%(`XN0"0``
+M2(U1*$B)42A(B<%(`XN0"0``2(U1*$B)43!(BY.0"0``3(E$$`A(B<%(`XN0
+M"0``2(U12$B)44A(`X.0"0``2(U02$B)4%"#Q@$/MD0D<&8Y\`^'2/___\:#
+M]P```("`?"1N``^$@@```+X`````#[?&2(T$P$C!X`5(BY-H"0``9L=$`DX$
+M`$B+DV@)``#&1!!"`$B+DV@)``#&1!!$_TB+DV@)``#&1!!0_TB)P4@#BV@)
+M``!(C5$H2(E1*$B)P4@#BV@)``!(C5$H2(E1,$B+DV@)``!,B800B````(/&
+M`0^V1"1N9CGP=X/&@_@```""2(VSZ!```$B-N\`0``#H`````$B)@^`0``!(
+MC;,8$0``2(V[\!```.@`````2(F#$!$``$B-LT@1``!(C;L@$0``Z`````!(
+MB8-`$0``2(VS>!$``$B-NU`1``#H`````$B)@W`1``!(C;.H$0``2(V[@!$`
+M`.@`````2(F#H!$``$B-L]@1``!(C;NP$0``Z`````!)B<1(B8/0$0``2(NK
+MV!$``(!\)&T`=%)!O0````!(BWPD2.@`````3(E@$$B):!A(BY-(`0``2(F#
+M2`$``$B+="1(2(DP2(E0"$B)`DF!Q``(``!(@<4`"```08/%`0^V1"1M9D0Y
+MZ'>T2(VS"!(``$B-N^`1``#H`````$F)Q$B)@P`2``!(BZL($@``0;T`````
+M2(M\)%#H`````$R)8!!(B6@82(N36`$``$B)@U@!``!(BTPD4$B)"$B)4`A(
+MB0))@<0```$`2('%```!`$&#Q0%F08/]"'6X2(VS.!(``$B-NQ`2``#H````
+M`$B)@S`2``!,BZ,X$@``9H-\)&@`=$A(B<5!M0!,B?_H`````$B):!!,B6`8
+M2(N3:`$``$B)@V@!``!,B3A(B5`(2(D"2('%C`$``$F!Q(P!``!!@\4!9D0Y
+M;"1H=[Y(@\1X6UU!7$%=05Y!7\-!54%455-(@^P(28G]28GT2(N>B`````^V
+M5D=(B?Y(B=_H`````$B)Q69!@TPD3A!!@'U#`'19N0````#V0PT!=`WK3`^V
+M0PU(T_BH`74-@\$!00^V14-F.<AWZ&:#^0-V,TF+10!(!=`!``!(C12-````
+M`('B_/\#`$@!T(L`B04`````P>@4@_`!@^`!ZS&Y`````$F+10!(!=`!``!(
+MC12-`````('B_/\#`$@!T(L`B04`````P>@4@_`!@^`!A,!T$`^V\4R)[^@`
+M````Z9<!``!(C4-@2#E#8`^$&0$``$B%[0^$$`$```^VA8$```!)QT3$6```
+M``!(BU4`2(M%"$B)0@A(B1!(B>J^!@```$B)W^@`````@+V#`````'0;3(GO
+MZ`````"_`0```.@`````@+V#`````'7E2(M%0$B%P'1(2,=`8`````#V14P$
+M=0A,B>_H`````$B+54!)B[7X"```OP$```#H`````$B+54!)B[7X"```OP8`
+M``#H`````$C'14``````@&L.`4B)[DR)[^@`````28M%`(N06`$``(D5````
+M`(72=`I)BT4`B9!8`0``0<9$)$(`9D&#9"1.[T&`?"0[`'0JN@`````/M\))
+MBT3$6$B%P'0*@'A*_P^%?@```(/"`4$/MD0D.V8YT'?;08!\)$X`>`^]````
+M`$&`?"0[`'41ZTM,B>9,B>_H`````&:0ZTH/M\5)BUS$6$B%VW0A]D-,`G0;
+M2(M30$F+M?@(``"_!@```.@`````@&-,_6:0@\4!00^V1"0[9CGH=\1F0<=$
+M)$X"`$&`9"1)_4B#Q`A;74%<05W#9F:09F:09F:005=!5D%505154TB#['A)
+MB?](B7PD4$B+1U!(B40D<$B+*$B+A:`1``!$BS!(B?Y(B>_H`````$&`O^L`
+M```!=@A!QH?H````!$F-1R!(QT0D:`````!).4<@="E)C5\@2(G?Z`````!(
+MB40D:$F+1R!(BU0D:$B)4`A(B0)(B5H(28E7($F#?T``=4R_____`$B#?"1H
+M`'0)2(M,)&@/MWDR10^VCX$```!(BW0D<$B+1B!$#[9`"`^V34$/ME4Z#[9U
+M.8D\)$C'QP````"X`````.@`````2(-\)&@`#X3.`P``2(M$)&A$#[=H,DUI
+MY;`$``!,`Z5`$0``2(N=X!```$B)Q^@`````08N,)"0$``!!BY0D(`0``$B+
+M1"1H#[=P,D6+C"0L!```18N$)"@$``!(Q\<`````N`````#H`````$G!Y09,
+M`>N+0S2+>S!$BU,L1(M;*$2+8R1$BVL@BU,<B50D7(M+&(E,)&"+<Q2)="1D
+M1(M+$$2+0PR+2PB+4P2+,XE$)$")?"0X1(E4)#!$B5PD*$2)9"0@1(EL)!B+
+M1"1<B40D$(M$)&")1"0(BT0D9(D$)$C'QP````"X`````.@`````3(MD)&A)
+M@\182(M4)&A,BZJ`````08M4)`1!#[9T)`%(Q\<`````N`````#H`````$&`
+M?"0!`'1.NP````!F9F:09F:0#[;#2(T$0$C!X`))BU0D"$@!PDD#11"+2@A(
+MBQ(/MO-$BT@(3(L`2,?'`````+@`````Z`````"#PP%!.%PD`7>^9H-]<``/
+MA"("``!!O`````!,C:VH#P``2(V-``$``$B)3"1(00^WQ$C!X`-(`X6X"0``
+M2(L82(7;#X3?`0``#[=#(&9!.4<X#X70`0``#[>5NA(``$$YUG1L9F9FD(/"
+M`0^WA;X2```YPK@`````#T/0C4(!2,'@`D@#A:`1``"+`*D```@`=3AF)?\/
+M9D0YX'4N2#E<)&AU+$B)[^@`````2(M$)&@/MW`R2,?'`````+@`````Z```
+M``#IGP$``$0Y\G682(M4)'"`>E@`#X5)`0``#[=#(&8]A0`/ASL!```/M\"`
+MO`5H"```_P^$*@$``$B#?"10``^$!`$``$$/MD=(J`$/A/<```"H!`^$[P``
+M`$B+50`/MT,R9L'H!0^WP(T$A0`#``")@G`!``!(BT4`#[=+,H/A'[H!````
+M2(G62-/FB;!T`0``#[=#,DC!X`-(`X6X"0``2,<```````^W2S*)R&;!Z`4E
+M_P<``(/A'TB)UDC3YDB)\??1(8R%P`D```^W2S*)R&;!Z`4E_P<``(/A'TC3
+MXO?2(52%=$@[7"1H=$5(BQ-(BT,(2(E""$B)$$B#NX``````=`](C;.`````
+M2(GOZ`````!(BX4``0``2(E8"$B)`TB+1"1(2(E#"$B)G0`!```/MW,R3(GO
+MZ`````!!@*^#`````>L:2(M4)'#V0@H"=`](B=Y,B?_H`````&9F9I!!@\0!
+M9D0Y97`/A_?]__](@WPD4`!T*T$/MD=(J`%T(J@$=!Y(BTPD:$B+$4B+00A(
+MB4((2(D02(G.3(G_Z`````!(@\1X6UU!7$%=05Y!7\.0D)"0D)"0D)"0D)"0
+MD)!(BT=03(L(0;@`````1(T4%D,/MH0(:`@``#S_=$(/ML!(C11`2(T4D$C!
+MX@5(B=!)`X%`"0``0#BP#@$``'4@2#FX(`$``'471(B0#0$``$F+@4`)``"(
+MC`(,`0``9I!)@\`!28'X@````'6D\\.02(M_6`^VA\`````\3W<Q#[;`2(T$
+M0$C!X`0!\HB4!\D````/MH?`````2(T$0$C!X`2(C`?(````@(?``````?/#
+M9F9FD&9F9I!F9I!F9I!!N/____]FA?9T3$B)^D&X_____[\`````9F9FD&9F
+MD`^V"HU!T#P)=QM!@/C_N`````!$#T3`00^VP(T$@$2-1$'0ZP9!@/C_=0R#
+MQP%(@\(!9CGW=<E!#[;`PV9F9I!!B=%(BT=03(L`N0````"00@^VA`%H"```
+M//]T,P^VP$B-%$!(C1202,'B!4B)T$D#@$`)``!(.;@@`0``=1%`.+`-`0``
+M=0A$B(@/`0``PTB#P0%(@?F`````=;/SPY!)B=-(BT=03(L(3(M76$&X````
+M`$,/MH0(:`@``#S_=$0/ML!(C11`2(T4D$C!X@5)`Y%`"0``2#FZ(`$``'4E
+M0#BR#0$``'4<A,ET#$B+@A@!``!)B0/K&4F+`TB)@A@!``#K#4F#P`%)@?B`
+M````=:),B=>X`````&9FD&9FD`^VE\@```"`^@%V1(#Z%W0_0#BWR0```'4V
+MA,ET%DB82(T$0$C!X`1)BX0"T````$F)`\-(F$B-!$!(P>`$28L328F4`M``
+M``##9F:09F:0@\`!2(/',(/X4'6D\\-FD$%6055!5%532(/L$$F)_D&)\4B+
+MOR@!```/MD<"P>`(#[97`T2-!!!!#[?`@\`$/0`(```/C^P```!`A/9T3$$/
+MMI80`0``ON#___\AU@^V1P&#X`^)T8/A$`GP"<B^"````"'6@^#SB=&#X00)
+M\`G(@^("@^#\00^VCA`!``"#X0$)T`G(B$<!ZTH/ME<!ON#___\AUD$/MH80
+M`0``@^`/B=&#X1`)\`G(O@@````AUH/@\XG1@^$$"?`)R(/B`H/@_`^V3P&#
+MX0$)T`G(08B&$`$``$B-5PA!#[?`3(UD!P1).=1V/TB)5"0(NP````!!#[;I
+M3(UL)`AF9I!F9I`/MO.)Z4R)ZDR)]^@`````2(M$)`A(@\`$2(E$)`B#PP%,
+M.>!RVDB#Q!!;74%<05U!7L-F9F:09F:09F:09F:04TB)^TB+3D@/MD$"P>`(
+M#[91`P'0#[?`C5`$#[=&-#G"?Q](B[\H`0``2&/22(G.Z`````"^`````$B)
+MW^@`````6\-F9F:09F9FD&9F9I!!5T%6055!5%532(/L"$F)]T&)U$B+7UA)
+MB=Z]`````$R-;@0/MH/(````/`%V03P7=#U$.*/)````=31!#[97`TACQ4B-
+M!$!(P>`$28V\!M@```"`^B"X(`````]'T`^VTDR)[N@`````9F:09F:0@\4!
+M2(/#,(/]4'6H2(/$"%M=05Q!74%>05_#9F:09I!(@^Q(2(E<)!A(B6PD($R)
+M9"0H3(EL)#!,B70D.$R)?"1`28G\08G7B<M,B00D0(AT)`](BT=03(LP3(GW
+MZ`````!(B<5(A<`/A/8```!,B??H`````$F)Q4B%P'422(GN3(GWZ`````#I
+MU@```&:02(U%6$B)1"0028M]$(G:28NT)"@!``#H`````,:%F`````K&126L
+M00^W1"0X9HE%($B+%"1(B55H3(EU*(E=-(.-E````!))BT402(E%2$R);7A)
+MC80D[````$B)15#&13`@2,>%H`````````#&13@[QD4Y`@^V1"0/B$4Z1(GX
+MP>@0B$4[3(GZ#[;&B$4\1(A]/0^V13:(13X/MD4UB$4_B%U`QD5!`+X`````
+M2(M\)!#H`````(M5-$F+=1A(BWPD$.@`````2(GN3(GWZ`````!(BUPD&$B+
+M;"0@3(MD)"A,BVPD,$R+="0X3(M\)$!(@\1(PV9FD&9FD&9FD$B#[$A(B5PD
+M&$B);"0@3(ED)"A,B6PD,$R)="0X3(E\)$!)B?Q!B=>)3"0(3(G#0(AT)`](
+MBT=03(LP3(GWZ`````!(B<5(A<`/A.H```!,B??H`````$F)Q4B%P'412(GN
+M3(GWZ`````#IR@```)!(C4582(E$)!#&A9@````*QD4EK$$/MT0D.&:)12!(
+MB5UH3(EU*,>%E`````@```!,B6UX28M%$$B)14B+5"0(B54T28V$).P```!(
+MB450QD4P($C'A:``````````QD4X/,9%.0(/MD0D#XA%.D2)^,'H$(A%.TR)
+M^@^VQHA%/$2(?3T/MD4VB$4^#[9%-8A%/P^V1"0(B$5`QD5!`+X`````2(M\
+M)!#H`````(M5-$F+=1A(BWPD$.@`````2(GN3(GWZ`````!(BUPD&$B+;"0@
+M3(MD)"A,BVPD,$R+="0X3(M\)$!(@\1(PV9F9I!(@^PX2(E<)`A(B6PD$$R)
+M9"083(EL)"!,B70D*$R)?"0P28G\2(M'4$R+.$B+ER@!```/MD("P>`(#[92
+M`P'0#[?`1(UH!$&!_0`(```/C\X```!,B?_H`````$B)Q4B%P`^$N@```$R)
+M_^@`````28G&2(7`=1!(B>Y,B?_H`````.F:````2(U=6$B+>!!)8]5)B[0D
+M*`$``.@`````QD4EK$$/MT0D.&:)12!,B7TH1(EM-(.-E````!))BT802(E%
+M2$R)=7A)C80D[````$B)15#&13`@2,>%H`````````#&13@=QD4Y$,9%.@(/
+MMD4UB$4[1(AM/+X`````2(G?Z`````"+531)BW882(G?Z`````!(B>Y,B?_H
M`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD&9F
-MD&9FD&9FD$%6055!5%532(G[08GU08G62(M'"$B+*+D"````N@````"^````
-M`.@`````@'M<`'082(GOZ`````"_`0```.@`````@'M<`'7H2(M#"$B+`$@%
-MH!(``(!X`@!X.X!(`H"Y`0```+H`````O@````!(B=_H`````(![7`!T&F:0
-M2(GOZ`````"_`0```.@`````@'M<`'7H1(GHP.@"1`^VX+D!````1(GBO@,`
-M``!(B=_H`````(![7`!T&V9FD$B)[^@`````OP$```#H`````(![7`!UZ$B+
-M0PA(BS!$B>GWT8/A`T6$]@^5PL'B`P^VA`Z@$@``@^#G"="(A`Z@$@``N0$`
-M``!$B>*^`P```$B)W^@`````6UU!7$%=05[#9F9FD&9F9I!F9I!F9I!(@^PH
-M2(E<)`A(B6PD$$R)9"083(EL)"!(B?M(B?4/MT8@9CV%`'<;3(NOB`D```^W
-MP`^VA`=@"```3&G@R`\``.L-3(NOB`D``$&\.+@/`$B+54B`>@$"=19(BT($
-M2(F#H!(``$B+0@Q(B8.H$@``2(MU>$B%]G0(2(G?Z`````!(B>Y(B=_H````
-M`$/&1"5<`$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,.0D)"0D$F)T4R+ES@)
-M```/MT8@NF">`0!F/84`=Q</M\`/MH0'8`@``$B-%$!(C1202,'B!4V-@2`$
-M``!!QH$@!```)V:!?CCA`74I1`^V3CI!C4'_/`%W#$&Y#P```$0B3COK+D&-
-M0>]!N0\````\`78@9I!)C0020;D`````2(-X8`!T#4&Y#P```$0BB($```!!
-M#[9``8/@\$0)R$&(0`&X`0```&:!?CCA`746#[9&.H/H`3P!#Y?`#[;`9F9F
-MD&9FD(G"P>('00^V0`&#X'\)T$&(0`$/MD$&08A``@^V`4&(0`,/MD$%08A`
-M!P^V00=!B$`/#[9!`D&(0`0/MD$#08A`!0^V001!B$`&#[9!`4&(0`P/MD$*
-M08A`"`^V00M!B$`)#[9!#$&(0`H/MD$(08A`"P^V00E!B$`-PV9FD&:00`^V
-MQ\-F9F:09F9FD&9FD(GX#[;$PV9F9I!F9I!F9I#&1R0"2(M'4$"(<`)(BT=0
-MQD`'`$B+1U"(4`S#9F9FD`^V1SV(1@(/MD<\B$8##[9'.XA&!`^V1SJ(1@K#
-M9F:0#[9'08A&`@^V1T"(1@,/MD<_B$8$#[9'/HA&"@^V1SV(1@L/MD<\B$8,
-MPV9FD&:0A=)^(;D`````9F9FD&9FD(G0*<B#^`(/G<`/ML"-3`$!.<I_Z_/#
-M9F:09F:09F:02(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($B)^TB)U4&)
-M]@^V1S@\*G0E/"IW$3PH#X7=````9F9FD&9FD.L0/(AT*CR*#X7(````9I#K
-M'D0/MF-`1`^V:S](B>Y(B=_H`````.L<9F9FD&9FD$0/MF-%1`^V:T1(B>Y(
-MB=_H`````,9%!4"+@Y0```"I```!`'0P1(AE`$2(;0A"C03U`````(A%`0^V
-M0S@\*'0$/(AU"\9%!F#K6V9FD&:0QD4&8>M0J0``!`!F9I!FD'0@1(AE`42(
-M;0D/MD,X/"AT!#R(=0;&108EZRK&108UZR1$B&4!#[9#.H/@#PA%!0^V0S@\
-M*'0$/(AU!L9%!LCK!,9%!LI(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0H
-MPV9F9I!F9I!F9I!F9I`/MD<Z"D<["D<\"D<]#[;`#[970(/B`0G0=!6Z)```
-M`+X%````Z`````#SPV9F9I#&1@;L2,>'H`````````##2(/L($B)'"1(B6PD
-M"$R)9"003(EL)!A(B?M(B?4/MD<X/"]T"SR/=5GK%V9FD&:01`^V9T!$#[9O
-M/^@`````D.L/1`^V9T5$#[9O1.@`````QD4%0/:#E@````1T$D2(90%$B&T)
-MQD4&0NL69F9FD$2(90$/MD,Z@^`/"$4%QD4&0$B+'"1(BVPD"$R+9"003(ML
-M)!A(@\0@PV9FD&9FD$B)\<9"!4`/MD8X/#5T!CR1=2/K&P^W1VB#X`&#^`$9
-MP(/@_8/H%HA"!NLD9F9FD,9"!NKK&KHD````O@4```!(B<_H`````//#9F:0
-M9F:0]D$Y`G0$QD$D`//#9F9FD/9'//!T#[HD````O@4```#H`````//#9F:0
-M9F:09F:02(/L"$F)\+@`````9F9FD,8$"`!(@\`!2(/X#77R00^V0#@\-0^$
-MG0```#PU=RD\*'1B/"AW#CP;#X6A`P``D.F;````/"IT3#PO9F:09I`/A8H#
-M``#K6#R/9F:09F:0=$X\CW<2/(AT*SR*9F9FD`^%:@,``.L=/)%F9I!F9I!T
-M1CSA#X56`P``9F:09F:0Z80````/MO)(B<I,B<?H`````,=$)`0!````Z3@#
-M``!(B<Y,B<?H`````,=$)`0!````Z2`#``!(B<I,B<;H`````,=$)`0!````
-MZ0@#``!!]D`\`70AQD$&<,9!!`#&00,`QD$"`,9!!4#'1"0$`0```.G@`@``
-MQD$&X,=$)`0!````Z<\"``!!@'@Y`0^%O`(``$&`>#H<#X>Q`@``00^V0#K_
-M),4`````QD$'!,=$)`0!````Z9P"``#&00<`QT0D!`$```#IBP(``,9!!NS'
-M1"0$`0```.EZ`@``QD$&[\8!`T$/MD`[@\A`B$$!QT0D!`$```#I6P(``,9!
-M!N_&`0?'1"0$`0```.E'`@``QD$&0,9!`0'&005`QT0D!`$```#I+@(``,9!
-M!N_&`0-!#[9`.X/("(A!`<=$)`0!````Z0\"``#&00;OQ@$"QT0D!`$```#I
-M^P$``,9!!N_&`8+'1"0$`0```.GG`0``QD$&[\8!!L=$)`0!````Z=,!``#&
-M00;OQ@&&QT0D!`$```#IOP$``,9!!N-!#[9`.XA!`<=$)`0!````Z:8!``#&
-M00:PQ@'8QD$#3\9!!,+'1"0$`0```.F*`0``QD$&L,8!V<9!`T_&003"QT0D
-M!`$```#I;@$``,9!!K#&`=K&00-/QD$$PL=$)`0!````Z5(!``#V1V@!=!'&
-M00;JQT0D!`$```#I.P$``,9!!N?'1"0$`0```.DJ`0``QD$&[\8!JL=$)`0!
-M````Z18!``#&00;OQ@%5QT0D!`$```#I`@$``,9!!B_&00$!QD$"$,=$)`0!
-M````Z>D```#&00;D00^V0#R(`4$/MD`]B$$(00^V0#N(007'1"0$`0```.G!
-M````00^V0#N(009!#[9`/(@!00^V0#V(00)!#[9`/HA!`T$/MD`_B$$$00^V
-M0$&(00I!#[9`0(A!`<=$)`0!````Z7T```#&00;H00^V0#R(`4$/MD`]B$$(
-M00^V0#N(005!#[9`/HA!`D$/MD`_B$$#00^V0$"(001!#[9`08A!`<=$)`0!
-M````ZSC'1"0$`0```$'V0#P!="G&009PQD$$`,9!`P#&00(`QD$%0,=$)`0!
-M````ZPMF9I#'1"0$`````(M$)`1(@\0(PV9F9I!F9F:09F9FD&9FD%-(@^P@
-M2(GS2(M.2$C'!"0`````2,=$)`@`````2,=$)!``````2,=$)!@`````]H&G
-M````!'0-2(N1R````$B#Z@'K!HM1>(/J`8![."5U84B)T$C!Z!B(!"1(B=!(
-MP>@0B$0D`4B)T$C!Z`B(1"0"B%0D`_:!U0```!!U%,9$)`8"QD0D!P"X"```
-M`.FN````2(U\)`1(C;'J````N@0```#H`````+@(````Z8X```!(B=!(P>@X
-MB`0D2(G02,'H,(A$)`%(B=!(P>@HB$0D`DB)T$C!Z""(1"0#2(G02,'H&(A$
-M)`1(B=!(P>@0B$0D!4B)T$C!Z`B(1"0&B%0D!_:!U0```!!U%<9$)`H"QD0D
-M"P"X(````.LD9F9FD$B-?"0(2(VQZ@```+H$````Z`````"X(````&9FD&:0
-M2(M[2$ACT$B)YN@`````2(/$(%O#9F9FD&9F9I!F9I!32(GS2(M74$B+"@^V
-M1C@\+W1?/"]W*SP;#X0Q`0``/!MW#SP2#X5%`0``9F:09I#K0#PH=#P\*@^%
-M,@$``&:0ZS`\BG0L/(IW&#PU9F9FD`^$^@```#R(#X42`0``9I#K$#R/=`P\
-MX0^%`@$``&:0ZW7V1V@!=`J!BY0```````0`]D=J$`^$%`$``$B#?V``#X4)
-M`0``#[9#.#PH=!`\*G0,/(AT"#R*#X7Q````]D(,`744#[9R"$B)S^@`````
-MA,`/A-<```"`>R2!#X3-````@8N4```````!`+@!````Z;X```"`?CD!#X6D
-M````@'XZ'`^'F@```$@/ODXZN`$```!(T^"I]C_`'74CJ0A`!@!U#*D``"``
-M=2-F9I#K<X..E`````BX`0```&:0ZW.#CI0````!N`$```#K98..E````""X
-M`0```.M79I#V1V@!=`J!BY0```````0`@XN4`````;@!````ZS=FD(N#E```
-M`*D``"``=!CV1V@!=!T-```$`(F#E````+@!````ZQ"X`````.L)9F9FD+@!
-M````6\.0D)"0D)"0D)!(BW\(10^VP$'!X`0/MM+!X@A!"=!$B<"#R`2$R40/
-M1<!!@_G_=!E(C9<`_O[_1(G()?__`P")@@3(``!!@\@"1(D&PV9F9I!F9F:0
-M9F9FD$B+1PA(+0`"`0"#S@&)L`#(``##9F9FD&9F9I!F9F:005154T&)]$B+
-M1PB%]G1,2"T``@$`2(VH`,@``(N``,@``(D%`````+L`````J`%U#^LABT4`
-MB04`````J`%T%+\*````Z`````"#PP%$.>-UX>L'N`````#K!;C_____6UU!
-M7,-F9F:09F9FD&9FD%532(/L&$B)^\=$)!0`````2(MO",:':!0````/MA4`
-M````2(UT)!1!N0````!!N`(```"Y`0```.CB_O__BW0D%$B)W^@F____OJ"&
-M`0!(B=_H.?___X7`=55(C84`_O[_BX`,R```B04`````B40D%#T?8P``=3?'
-M@U@4```?8P``QX-<%``````$`,>#8!0``````0!(QX-P%````````&:X``#I
-M5P(``&9FD&:0QT0D%`````!(BVL(QH-H%````0^V%0````!(C70D%$&Y____
-M_T&X`@```+D!````2(G?Z#C^__^+="042(G?Z'S^__^^$"<``$B)W^B/_O__
-MA<!U;DB-A0#^_O^+@`S(``")!0````")1"04/1]#``!T+3T?1```=4G'@U@4
-M```?1```QX-<%``````'`,>#8!0``````0#IDP$``&9FD,>#6!0``!]#``#'
-M@UP4``````0`QX-@%``````!`.EM`0``QT0D%`````!(BVL(QH-H%`````^V
-M%0````!(C70D%$&Y`````$&X`@```+D!````2(G?Z'7]__^+="042(G?Z+G]
-M__^^$"<``$B)W^C,_?__A<!U4$B-A0#^_O^+@`S(``")!0````")1"04/;]#
-M``!U,L>#6!0``+]#``#'@UP4`````"``QX-@%````!```$C'@W`4````````
-M9K@``.GJ````QT0D%`````!(BVL(QH-H%`````^V%0````!(C70D%$&Y````
-M`$&X`@```+D!````2(G?Z-#\__^+="042(G?Z!3]__^^$"<``$B)W^@G_?__
-MA<!U9TB-A0#^_O^+@`S(``")!0````")1"04/>\1``!T"3WO$@``=4+K(,>#
-M6!0``.\1``#'@UP4``````0`QX-@%``````!`.L^QX-8%```[Q(``,>#7!0`
-M````"`#'@V`4``````$`ZQZX_____^LG9F:09I!(QX-P%````````+@`````
-MZQ!(QX-P%````````+@`````2(/$&%M=PV9F9I!F9I!(@^PH2(E<)!!(B6PD
-M&$R)9"0@2(G[B?=)B=1(BVL(@/D$N`0````/1\A(BX-P%```#[90!$B-="0,
-M08GY1`^VP;D!````2(G?Z,+[__^+="0,2(G?Z`;\__^^$"<``$B)W^@9_/__
-MNO____^%P'4@2(V%`/[^_XN`#,@``(D%`````(E$)`Q!B00DN@````")T$B+
-M7"002(ML)!A,BV0D($B#Q"C#9F9FD&9FD&9FD%532(/L&$B)^TB)U4B+AW`4
-M```/ME`+2(U$)!1!B?%!N`$```"Y`0```$B)QN@N^___BW0D%$B)W^AR^___
-MOA`G``!(B=_HA?O__[K_____A<!U&DB+0PA(+?0Y``"+`(D%`````(A%`+H`
-M````B=!(@\086UW#9F:09F:09F:005=!5D%505154TB#[!A(B?M!B<U!B?=!
-MB=:%R0^$C@```+T`````3(MC"$B+@W`4```/ME`"0;G_____0;@!````N0$`
-M``!(C70D%$B)W^B,^O__BW0D%$B)W^C0^O__OA`G``!(B=_HX_K__X7`=2E)
-MC80D`/[^_XN0#,@``(D5`````$2)^"'01#CP=0>X`````.L?B50D%+\*````
-MZ`````"#Q0%$.>T/A7?___^X_____TB#Q!A;74%<05U!7D%?PV9F9I!F9F:0
-M9F9FD%-(@^P02(G[2(N'<!0```^V$$B-="0,0;G_____0;@`````N0````#H
-MX_G__XMT)`Q(B=_H)_K__[X0)P``2(G?Z#KZ__^%P'4FN>"3!`"Z`@```+X#
-M````2(G?Z,_^__^Z`````(7`=`MF9I!F9I"Z_____XG02(/$$%O#9F:02(/L
-M*$B)7"082(EL)"!(B?N)]<9$)!?_2(U4)!?H`````(7`=7*`?"07`'1S2(G?
-MZ$O___^#^/]T7DB+@W`4```/ME`*2(UT)!!!B>E!N`````"Y`````$B)W^@P
-M^?__BW0D$$B)W^AT^?__OA`G``!(B=_HA_G__X7`=1NYX),$`+H`````O@,`
-M``!(B=_H'/[__X7`=`BX_____^L&D+@`````2(M<)!A(BVPD($B#Q"C#9F9F
-MD&9F9I!F9F:02(/L6$B)7"0H2(EL)#!,B60D.$R);"1`3(ET)$A,B7PD4$B)
-M_4&)]HG+2(._<!0````/A/@"``!)B==%A,`/A%P!``"#_O]U%P^WAU@4``!F
-MB0*X`0```.GY`@``9F:0@_[^=1*+AUP4``")`K@!````Z=\"``"#_OUU%(N'
-M8!0``(D"N`$```#IR`(``&:0`?.)7"0,.Y]<%```#X>.`@``B?.#X_Q!B?1!
-M@^0#=&),C6PD)+D$````3(GJB=[H_/O__X/#!+H$````.5PD#',-1(G@1"GP
-MBTPD#(T4"$0YXG8N1(GA3(G_9F:09F:0B<A!#[9$!0"(!TB#QP&#P0$YT77K
-MB=!$*>"#Z`%-C7P'`42+9"0,08/D_$0YXW,J3(UL)"2Y!````$R)ZHG>2(GO
-MZ(G[__^+1"0D08D'28/'!(/#!$$YW'?;.5PD#`^&XP$``$R-9"0DN00```!,
-MB>*)WDB)[^A5^___BW0D#"G>#X3``0``N0````"Z`````$$/M@040H@$.H/!
-M`4B#P@$Y\0^$G@$``.OF9F:09I"#_O]U*X`Z#W41QH=I%````;@!````Z9L!
-M``#&AVD4````N`$```#IB@$``&9F9I")3"04B<@!\#N'7!0```^'3`$``("_
-M:10````/A#\!``")\+H`````][=@%```A=(/A8T```"`OV@4````=`WH````
-M`(7`#X44`0``2(GOZ)S\__^#^/\/A`,!``!(BX5P%```#[90!DB-="0D18GQ
-M0;@`````N0````!(B>_H??;__XMT)"1(B>_HP?;__[X0)P``2(GOZ-3V__^%
-MP`^%O````+G@DP0`N@````"^`P```$B)[^AE^___A<`/A9T```"%VP^$G```
-M`,=$)!``````BT0D$$6+)`=$BVPD$$4!]4B+70A(@>L``@$`2(GOZ/K[__]$
-MB:,(R```2(N%<!0```^V4`5%B>E!N`0```"Y`````$B-="0D2(GOZ-WU__^+
-M="0D2(GOZ"'V__^^$"<``$B)[^@T]O__A<!U(+F($P``N@````"^`0```$B)
-M[^C)^O__A<!T%V9FD&:0N`````#K'[@!````9F9FD.L4@T0D$`2+1"00.40D
-M%';FZ4W___](BUPD*$B+;"0P3(MD)#A,BVPD0$R+="1(3(M\)%!(@\18PY"0
-MD)"0D)"X`````,-F9F:09F:09F:0N``````Y/0````!^-TACQTC'P0````!(
-MC01`2,'@`P^W%`AFB18/MU0(`F:)5@(/ME0("(A6"`^V1`@)B$8)N`$```#S
-MPV9F9I!F9I!F9I"X$"L``,-F9F:09F:09F:0N-````##9F9FD&9FD&9FD+@(
-M````PV9F9I!F9I!F9I"^`````$&X`````+D`````#[:4.>`(``"`^O]T2HV!
-M@````&8]@0!W!X/&`>LY9I`/ML)(BY=@"0``2(T$P$C!X`6`O!`5`0```W48
-M08/``4&-0`.#^`9V#H/&`4&X`````.L#@\8!2(/!`4B#^09UGXGPPV9F9I!F
-M9F:09F9FD$B)^4&Z`````$&[`````$&Y@````$`/MO:#Q@%F9F:018G(#[:!
-MX`@``#S_=%!F08'Y@0!W"D&#P@'K/69F9I`/ML!(BY=@"0``2(T$P$C!X`6`
-MO!`5`0```W4908/#`4&-0P.#^`9V$$&#P@%!NP````#K!$&#P@%$.=9T%TB#
-MP0%!@\$!08'YA@```'610;@`````1(G`PV9F9I!F9I#SPV9F9I!F9F:09F:0
-M9F:0QH?+`````,-F9F:09F9FD+C_````2(7_=$2^_____[D`````#[:$.>((
-M```\_W0@#[;`2(N78`D``$B-!,!(P>`%#[:$$!0!``!`.,8/1_!(@\$!2(/Y
-M!'7*0`^VQO/#N`````##9F9FD&9FD&9FD+@`````PV9F9I!F9I!F9I")\,#H
-M!(U(5XU0,#P*#T/1B!>)\(/@#X/X"7X*B?"#X`^#P%?K"(GP@^`/@\`PB$<!
-MPV9F9I!F9F:09F:09F:02(/L$$B)'"1,B60D"$B)^T&)]$R)X`^V].BB____
-M00^V]$B#PP)(B=_HDO___TB+'"1,BV0D"$B#Q!##9F9FD,="!`````#'`@``
-M``"X`````,-F9F:09F:09F:09F:02(M'8$B%P'112,=`0`````"`2$P$2,='
-M8`````!(QT=P`````$C'1V@`````BT<(@_@_?Q-(BU=X2)A(QX3"8`0`````
-M``##2(M7>$B82,>$PF`"````````\\-F9F:02(M'8$B%P'112,=`0`````"`
-M8$S[2,='8`````!(QT=P`````$C'1V@`````BT<(@_@_?Q-(BU=X2)A(QX3"
-M8`0```````##2(M7>$B82,>$PF`"````````\\-F9F:02(/L"$C'QP````#H
-M`````+@`````2(/$",-F9I!F9I!54TB#[#C&!"1MQD0D`?_&1"0"(\9$)`,4
-MQD0D!#K&1"0%[\9$)`86QD0D!Y)(BZ_X"```2(7M2`]$[TB-1"002(G"Q@``
-M2(/``4B)TTB-3"0P2#G(=>S&1"04`;D@````O@X```!(B>_H`````(7`=4*_
-M@!H&`.@`````N2````!(B=J^#P```$B)[^@`````@_@@=1Y(C7,02(GGN0@`
-M``#\\Z8/E\(/DL"Y`0```#C"=!9(Q\<`````N`````#H`````+D`````#[;!
-M2(/$.%M=PV9F9I!F9F:09F9FD$%7059!54%455-(@^QH28G\3(N_\`@``$F!
-MQX@4``!(BP=(A<!T$TB-L```_O](B3=(BW\@Z`````!)BW0D$$B%]G0*28M\
-M)"#H`````$F+="082(7V=`I)BWPD(.@`````2(U,)&5(C50D9DB-="1G00^W
-M?"0\2(U$)%I(B40D.$B-1"1<2(E$)#!(C40D5DB)1"0H2(U$)%A(B40D($B-
-M1"1@2(E$)!A(C40D8DB)1"002(U$)&-(B40D"$B-1"1>2(D$)$R-3"1D3(U$
-M)%3H`````$F+M"0X"0``2(7V="!)C;PD&`D``.@`````28NW.`D``$F-OQ@)
-M``#H`````$F+M"1@"0``2(7V="!)C;PD0`D``.@`````28NW8`D``$F-OT`)
-M``#H`````$F+M"2("0``2(7V="!)C;PD:`D``.@`````28NWB`D``$F-OV@)
-M``#H`````$F+M"0H"P``2(7V="!)C;PD"`L``.@`````28NW*`L``$F-OP@+
-M``#H`````(!\)&<`=$2]`````$V-M"18"P``38VO6`L```^WW4F+M-QX"P``
-M3(GWZ`````!)B[3?>`L``$R)[^@`````@\4!#[9$)&=F.>AWT$F+M"0($```
-M2(7V="!)C;PDZ`\``.@`````28NW"!```$F-O^@/``#H`````$F+M"1`$```
-M2(7V="!)C;PD(!```.@`````28NW0!```$F-OR`0``#H`````$F+M"2P$```
-M2(7V="!)C;PDD!```.@`````28NWL!```$F-OY`0``#H`````$F+M"2P"0``
-M2(7V="!)C;PDD`D``.@`````28NWL`D``$F-OY`)``#H`````$F+M"2("@``
-M2(7V="!)C;PD:`H``.@`````28NWB`H``$F-OV@*``#H`````$F+M"08"@``
-M2(7V="!)C;PD^`D``.@`````28NW&`H``$F-O_@)``#H`````$F+M"1`"@``
-M2(7V="!)C;PD(`H``.@`````28NW0`H``$F-OR`*``#H`````$F+M"38"@``
-M2(7V="!)C;PDN`H``.@`````28NWV`H``$F-O[@*``#H`````$F+M"0`"P``
-M2(7V="!)C;PDX`H``.@`````28NW``L``$F-O^`*``#H`````$F+M"10"P``
-M2(7V="!)C;PD,`L``.@`````28NW4`L``$F-OS`+``#H`````$F+M"28#P``
-M2(7V="!)C;PD>`\``.@`````28NWF`\``$F-OW@/``#H`````$F+M"30#P``
-M2(7V="!)C;PDL`\``.@`````28NWT`\``$F-O[`/``#H`````$F+M"1X$```
-M2(7V="!)C;PD6!```.@`````28NW>!```$F-OU@0``#H`````$F+M"2P"@``
-M2(7V="!)C;PDD`H``.@`````28NWL`H``$F-OY`*``#H`````$F+M"38$```
-M2(7V="])BY0DX!```$F-O"2X$```Z`````!)BY?@$```28NWV!```$F-O[@0
-M``#H`````$F+M"0($0``2(7V="])BY0D$!$``$F-O"3H$```Z`````!)BY<0
-M$0``28NW"!$``$F-O^@0``#H`````$F+M"0X$0``2(7V="])BY0D0!$``$F-
-MO"08$0``Z`````!)BY=`$0``28NW.!$``$F-OQ@1``#H`````$F+M"28$0``
-M2(7V="])BY0DH!$``$F-O"1X$0``Z`````!)BY>@$0``28NWF!$``$F-OW@1
-M``#H`````$F+M"1H$0``2(7V="])BY0D<!$``$F-O"1($0``Z`````!)BY=P
-M$0``28NW:!$``$F-OT@1``#H`````$F+M"3($0``2(7V="])BY0DT!$``$F-
-MO"2H$0``Z`````!)BY?0$0``28NWR!$``$F-OZ@1``#H`````$F+M"3X$0``
-M2(7V="])BY0D`!(``$F-O"38$0``Z`````!)BY<`$@``28NW^!$``$F-O]@1
-M``#H`````$F+M"0H$@``2(7V="])BY0D,!(``$F-O"0($@``Z`````!)BY<P
-M$@``28NW*!(``$F-OP@2``#H`````$B#Q&A;74%<05U!7D%?PV9F9I!F9I!(
-M@^P82(E<)`A,B60D$$F)_$&(="1/0`^VWHG>Z`````!)@<2(%```B=Y,B>?H
-M`````+@!````2(M<)`A,BV0D$$B#Q!C#9F9FD&9FD&9FD%532(/L"$B)_>@`
-M````2(GOZ`````!(C9V(%```2(G?Z`````!(B>_H`````+_0!P``Z`````!(
-MB>_H`````+X!````2(GOZ`````"^`0```$B)W^@`````NX````!FD$B+E?`(
-M``!(8\,/MH0"8`@``#S_="T/ML!(C03`2,'@!4B)QD@#LF`)``#V1DX"=!)F
-MQT9.`0#&1D(=2(GOZ`````"#PP&!^X8```!ULDB+G?`(``!(@<.(%```O0``
-M```/MH0=X`@``#S_=#,/ML!(C03`2,'@!4B)QD@#LV`)``#V1DX"=!AFQT9.
-M`0#&1D(=2(G?Z`````!F9I!F9I!(@\4!2(/]!G6W2(/$"%M=PV9F9I!F9F:0
-M9F9FD&9FD%-(B?OH`````$B+N_`(``!(@<>(%```Z`````!;PV:04TB)^^@`
-M````2(N[\`@``$B!QX@4``#H`````%O#9I!(@^P(Z``````/ML!(@\0(PV9F
-M9I!F9F:09F9FD&9FD$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\
-M)#!(B?M!B?1!B=5(BV]@3(MW>$B%[0^$&P$``("_RP`````/A0X!``!,B??H
-M`````$F)QTB%P`^$^@```,9`..'&0#D!183D=`U!@/T!&<#WT(/`!^L+08#]
-M`1G`]]"#P`U!B$<Z0<9')(`/MT4X9D&)1R!)B5\H0<='-`````!)QT=(````
-M`$G'AZ``````````3(G^3(GWZ`````#&@\L````!9L>#R````/0!2(7;=$Y(
-MBU-@2(72=$]F@;O(````E@!U#DB+>E"^(0```.@`````9H.KR`````&_T`<`
-M`.@`````3(GWZ`````!(BU-@2(72=`F`N\L`````=;MF@[O(`````'0:08!_
-M)`!U$TB+0V`/MT!J9HE#6KL`````ZP6[_____TR)_DR)]^@`````ZP6[____
-M_XG82(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$.,-F9F:09F9F
-MD&9F9I!F9I!(@^Q(2(E<)!A(B6PD($R)9"0H3(EL)#!,B70D.$R)?"1`2(G]
-M08GU3(MG8$R+=WA-A>0/A'D$``"`O\L`````#X5L!```3(GWZ`````!)B<=(
-MA<`/A%@$``#V10`"#X7\````08#]%'<,00^VQ8T$0,'@`NL7N(G___]!]N5F
-MP>@(P.@$#[;`!?````!!QD<XX4'&1SD!0<9'.AQ!B$<[0<9')(!!#[=$)#AF
-M08E'($F);RA!QT<T`````$G'1T@`````2<>'H`````````!,B?Y,B??H````
-M`,:%RP````%FQX7(````Q`E(A>UT3DB+56!(A=)T4V:!O<@```"6`'4.2(MZ
-M4+XA````Z`````!F@ZW(`````;_0!P``Z`````!,B??H`````$B+56!(A=)T
-M"8"]RP````!UNV:#O<@`````#X15`P``NP````!!@'\D``^$2@,``.E``P``
-M3(GWZ`````!(B40D$$B%P`^$*@,``$F-7UA(BT`02(D$)$'&1S@:0<9'.0A!
-MQD<Z&D'&1SL`0<9'/!!!QD<]`$B+1"0028E'>$'&1R2`00^W1"0X9D&)1R!)
-MB6\H2(M$)!!(BT`028E'2$''1S00````2(M%8$@%[````$F)1U!!QD<P($G'
-MAZ``````````O@````!(B=_H`````$&+5S1(BT0D$$B+<!A(B=_H`````$R)
-M_DR)]^@`````QH7+`````6;'A<@```#Z`$B%[71.2(M58$B%TG1/9H&]R```
-M`)8`=0Y(BWI0OB$```#H`````&:#K<@````!O]`'``#H`````$R)]^@`````
-M2(M58$B%TG0)@+W+`````'6[9H.]R`````!T!T&`?R0`=!=(C70D$$R)]^@`
-M````N______I_0$``$R)_DR)]^@`````3(GWZ`````!)B<=(A<!U'4B-="00
-M3(GWZ`````"[_____^G=`0``9F:09F:02(U86$B+/"1(@\<$2(L4)`^V0@,/
-MM@0'B$($QD<!"L9'`@"X`````$B+%"3&!!``2(/``4B#^`1U[D6$[74&@&<#
-M_.M!00^VU6G28.H``+@?A>M1]^K!^@6`3P,#B='!Z1B(3P2)UL'N$$"(=P6)
-MT,'H"(A'!HA7!XA/"$"(=PF(1PJ(5PM(BT0D$$F)1WA!QD<X%0^V!\#X!_?0
-M@\`108A'.4'&1SH`0<9'.P!!QD<\$$'&1ST`@"<_0<9')(!!#[=$)#AF08E'
-M($F);RA(BT0D$$B+0!!)B4=(0<='-!````!(BT5@2`7L````28E'4$'&1S`@
-M2<>'H`````````"^`````$B)W^@`````08M7-$B+1"002(MP&$B)W^@`````
-M3(G^3(GWZ`````#&A<L````!9L>%R````/H`2(7M=$Y(BU5@2(72=$]F@;W(
-M````E@!U#DB+>E"^(0```.@`````9H.MR`````&_T`<``.@`````3(GWZ```
-M``!(BU5@2(72=`F`O<L`````=;MF@[W(`````'0,NP````!!@'\D`'0%N___
-M__](C70D$$R)]^@`````ZPIF9I!FD+O_____3(G^3(GWZ`````#K!;O_____
-MB=A(BUPD&$B+;"0@3(MD)"A,BVPD,$R+="0X3(M\)$!(@\1(PV9F9I!(@^QH
-M2(E<)#A(B6PD0$R)9"1(3(EL)%!,B70D6$R)?"1@2(G]2(GS28G/08G518G&
-M3(MG8$V%Y`^$M@,``("_RP`````/A:D#``!)BT0D4$B)1"0P2(M7>$B)5"0(
-M9L>'R````!`G2(G7Z`````!(B40D*$B%P`^$=P,``$$/M\6)1"0$9D&#_01V
-M%8G&2,?'`````+@`````Z`````#K%$B+?"0(Z`````!(B40D$$B%P'492(MT
-M)"A(BWPD".@`````N______I0@,``(M4)`3!X@F)5"0D2(M$)`A(B[#P"```
-MQD8_`4B)ZK\%````Z`````!!@$PD3`)(BU5@OB$```!(BWPD,.@`````2(M4
-M)"A(@\)82(E4)!A%A/9T%4B+1"0HQX"4````"@```,9`."CK*$B+5"0HQX*4
-M````$@```,9"."I(BT0D$$B+>!"+5"0D3(G^Z`````!(BT5@]D!H`0^$@0``
-M`$&`_@$9P(/@`H/H>$B+5"0HB$(XQD(Y`$B)V$C!Z#B(0CI(B=A(P>@PB$([
-M2(G82,'H*(A"/$B)V$C!Z""(0CU(B=A(P>@8B$(^2(G82,'H$(A"/TB)V$C!
-MZ`B(0D"(6D'&0D(`QD)#`$2)Z&;!Z`B(0D1$B&I%QD)&`,9"1P#K3T&`_@$9
-MP(/@`H/`*$B+5"0HB$(XQD(Y`$B)V$C!Z!B(0CI(B=A(P>@0B$([2(G82,'H
-M"(A"/(A:/<9"/@!$B>AFP>@(B$(_1(AJ0,9"00!(BWPD*.@`````2(M%8`^W
-M0#A(BU0D*&:)0B#&0B2`2(EJ*$B+5"002(M"$$B+5"0H2(E"2(M$)"2)0C1(
-MBT0D$$B)0GC&0C`@2(M%8$@%[````$B)0E!(QX*@`````````+X`````2(M\
-M)!CH`````$B+1"0HBU`T2(M$)!!(BW`82(M\)!CH`````,:%RP````%(BW0D
-M*$B+?"0(Z`````!(A>T/A)@```!(BU5@2(72#X2+````@+W+``````^$^0``
-M`&:!O<@```"6`'4.2(MZ4+XA````Z`````!F@ZW(`````;_0!P``Z`````!(
-MBWPD".@`````2(M58$B%TG1`@+W+``````^$K@```.NS2(M4)"B`>B0`=2:[
-M`````$6$]G0ABU0D)$B+1"002(MP$$R)_^@`````NP````#K!;O_____2(M4
-M)"A(@WIX`'0O@7HT``@``'<32(G62(/&>$B+?"0(Z`````#K$TB+="0H2(/&
-M>$B+?"0(Z`````!(BW0D*$B+?"0(Z`````!(BT0D"$B+L/`(``#&1C\`2(GJ
-MOP8```#H`````$&`9"1,_>L<N______K%6:#O<@`````#X5&____Z7+___]F
-MD(G82(M<)#A(BVPD0$R+9"1(3(ML)%!,BW0D6$R+?"1@2(/$:,-F9F:09F9F
-MD&9FD$B#[!A(B1PD2(EL)`A,B60D$$B)\TB+1U!,BR!(BVYH#[9&)#P@=$@\
-M('<*A,!T(CP&=Q7K,#PB=#8\(F9F9I!R)(/`@#P!=AVX`````&:0ZV-(BT=`
-MQT`$`````,:%L@````'K"L:%L@````UF9I!(@WMX`'0E@7LT``@``'<02(US
-M>$R)Y^@`````ZPYFD$B-<WA,B>?H`````$B)WDR)Y^@`````2(GO_Y7(````
-MN`$```!(BQPD2(ML)`A,BV0D$$B#Q!C#9F9FD&9F9I!(@^PH2(D<)$B);"0(
-M3(ED)!!,B6PD&$R)="0@2(G[28GU28G42(MO8$B%[74*2(G7_];I/@$``$B#
-MOX@`````=0Y(@[^``````'0/9F9FD$R)YT'_U>D;`0``@+WH``````^%"`$`
-M`(!]2O]F9F:0#X7Z````2(M%8$B%P'0*@'A1``^%YP```$B+?5#V1PP0#X79
-M````3(LW@+V#`````'0-2(GJO@8```#H`````$R)JX@```!,B:.0````#[95
-M2$B)T(/@!DB#^`9U*?;"`71]QD5*!<9%2P0/MI6!````2(MU6$B+?5!(B>GH
-M`````.E_````2(/X!'5Y]L(!='1(BU5@2(72="\/MT).J`)T8X/@_6:)0DY(
-MBT5@9L=`3@$`2(M%8,9`0AU(BW5@3(GWZ`````#K/,9%2@/&14L$2(GN3(GW
-MZ`````#K)Y#&14H%QD5+!F;'A<@``````$B)[DR)]^@`````ZPAFD$R)YT'_
-MU4B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9FD&9FD&9FD&9FD%-(
-MB?M(A?\/A,,```!(BW]XZ`````!(B<)(A<`/A'X```"`N!4!````='6`"P$/
-MMH`5`0``/`)U.DB#>W``=1D/MH/,````@^`#B$,"#[:"%`$``(A#`>MW#[:#
-MS0```(A#`DB+0W`/MH`4`0``B$,!ZUT\`W59#[:#S````(/@`\'@`@*#S0``
-M`(A#`DB+0W`/MH`4`0``B$,!ZS-F9I!(BT-P2(7`=0M(BT-H2(7`=0[K'`^V
-M@!0!``"(0P'K$`^V@,(```"(0P%F9I!F9I!;PV9F9I!F9F:09F:09F:055-(
-M@^P(2(G[2(7_='>]``````^VA!U@"```//]T00^VT$B-!%)(C02"2,'@!4B)
-MPD@#DS@)``!T)HM"2"4`__\`/0``_P!U%_9"2P1T$4B+>D!(A?]T".@`````
-M9F:02(/%`4B!_8````!UIDB+@_`(``!(.=AU#$B-N(@4``#H`````$B#Q`A;
-M7<-F9F:055-(@^P(2(G[2(VOB!0``.@`````2(E#*$B)12A(B9OP"```2(F=
-M\`@``(N#"`D``(F%"`D``,:#9A0```'&A684```!2(G?Z`````!(B=_H````
-M`$B)[^@`````2(G?Z`````"$P'1G2(GOZ`````"$P'1;2(G?Z`````"_T`<`
-M`.@`````2(G?Z`````#'@Y`!``#H`P``2,>#H`$```````!(B9NH`0``2(VS
-MD`$``$B+>RCH`````+X`````2(G?Z`````"X`0```.L&D+@`````2(/$"%M=
-MPV9F9I!32(G[Z`````!(@<.(%```2(G?Z`````"X`0```%O#D$%7059!54%4
-M55-(@^P82(ET)`A(B10D@ST```````^%;P$``,<%``````$```!$BST`````
-MQT0D%`````!)Q\4`````2,?#`````$G'Q@````#I=@(```^WA@````#!X!!"
-M#[<4+@G0.<4/A?$```!!N`````"_`````&9FD&:09H,\'P!U7TECT$B)T4C!
-MX05*BP0N2(D$&4*+1"X(B409"`^V@0````!(P>(#2(T\`@^V1"03B$2[#0^V
-M@0````!(C3P"#[9$)!*(1+L.#[:!`````$@!PL9$DP\`@($``````>MT#[:/
-M``````^VP;H`````0O<T-H72=$L/ML%)8]!(C0S5`````$B-/`$/MD0D$XA$
-MNPU(P>(%#[:"`````$B-/`$/MD0D$HA$NPX/MH(`````2`'!QD2+#P"`@@``
-M```!ZQ)!@\`!2(/'($&#^`0/A2;___^#A@`````!08/"`4B#QAA%.?H/A>7^
-M__]!@\0!08/\(`^%%P$``(-$)!0!@7PD%/\````/A3H!``!(@WPD"`!T"$B+
-M5"0(Q@(`BS4`````O0````"%]GXUN0````"]`````+H``````ZH`````2(-\
-M)`@`=`V+@@````!(BUPD"``#@\$!2(/"&#GQ==I(@SPD``^$[````$&Y````
-M`$&Z`````$G'Q`````!F0X,\(@`/A,T```!!#[:2`````(32=&=!N`````!)
-M8\%,C1S%``````^VPH/H`4B-6`%+C00#2(TTA0````!(BSPDN00```#\\Z8/
-ME\(/DL`XPG4A2(-\)`@`=`]!#[:"`````$B+5"0(B`)!#[:J`````.L)28/`
-M`4DYV'6T08/!`4F#PB!!@_D$=$SI;O___T2(9"02N0````"Z`````$2)YHM\
-M)!3H`````(G%0;H`````O@````!%A?\/CX_]___II?[__P^V1"04B$0D$T&\
-M`````.NY0`^VQ4B#Q!A;74%<05U!7D%?PV9F9I!F9F:09F9FD&9FD$B#[!A(
-MB1PD2(EL)`A,B60D$(GU3(MG>$B+7V#V!P%T7TB+>UA(A?]T$$`/MM8/MK.!
-M````Z`````!(B[L@`0``2(7_=!!`#[;5#[:S#0$``.@`````3(GGZ`````!(
-MA<!T+8"X%0$```!T)$`/MM5(BW-`3(GGZ`````#K$F:00`^VUDB+<T!,B>?H
-M`````$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F:09F:09F:02(/L2$B)7"08
-M2(EL)"!,B60D*$R);"0P3(ET)#A,B7PD0$B)^T&)]$B+;V!,BV]X2(7M#X0^
-M`P``@+_+``````^%,0,``/8'`@^%*`,```^VA9@!``"$P'0+0#CP=3J0Z1(#
-M```/M@^#X0$/MLD/ME<"#[9W`40/MH4/`0``2,?'`````+@`````Z`````"[
-M_____^GC`@``3(GOZ`````!)B<=(A<`/A,H"``!(BU5`#[:"S````(T$@`^V
-M4@(!T$B8#[:(`````$$/ME4Z00^V=3E%#[;$2,?'`````+@`````Z`````!!
-MQD<XX4'&1SD!08#\`@^5P(/`&D&(1SI!QD<D@`^W13AF08E'($F)7RA!QT<T
-M`````$G'1T@`````2<>'H`````````!,B?Y,B>_H`````,:#RP````%FQX/(
-M````]`%(A=MT3DB+4V!(A=)T4V:!N\@```"6`'4.2(MZ4+XA````Z`````!F
-M@ZO(`````;_0!P``Z`````!,B>_H`````$B+4V!(A=)T"8"[RP````!UNV:#
-MN\@`````#X2[`0``08!_)``/A;`!``!(BT-@2(E$)!!(BT!03(LP3(GWZ```
-M``!(B<5(A<!U%DB+1"00QH#I`````;L`````Z7\!``!,B??H`````$F)Q$B%
-MP'4E2(M4)!#&@ND````!2(GN3(GWZ`````"[`````.E.`0``9F9FD$B-15A(
-MB40D",9%..'&13D!QD4Z`TB+5"00#[=".&:)12#&A9@````/2(E=*,=%-``"
-M``!)BU0D$$B)54BX`````,8$$`!(@\`!2#T``@``=?!,B65X2,>%H```````
-M``"^`````$B+?"0(Z`````"+531)BW0D&$B+?"0(Z`````!(B>Y,B??H````
-M`,:#RP````%FQX/(````^@!(A=MT3DB+4V!(A=)T3V:!N\@```"6`'4.2(MZ
-M4+XA````Z`````!F@ZO(`````;_0!P``Z`````!,B??H`````$B+4V!(A=)T
-M"8"[RP````!UNV:#N\@`````=":`?20`=2!(BW5(2(M\)!#H`````$B+5"00
-M#[:"F`$``(B#SP```$B#?7@`=`Q(C75X3(GWZ`````!(B>Y,B??H`````+L`
-M````ZP6[_____TR)_DR)[^@`````ZP6[_____XG82(M<)!A(BVPD($R+9"0H
-M3(ML)#!,BW0D.$R+?"1`2(/$2,-F9F:09F9FD&9F9I!F9I!(@^PH2(E<)`A(
-MB6PD$$R)9"083(EL)"!(B?N`/@EW$`^V!O\DQ0````!F9I!F9I"X_____^DF
-M`0``2(M&"$B+D/@(``!(A=)(#T302(NZ\`@``,:'9Q0```'H`````+@`````
-MZ?<````/ME8(O@````#HF>C__^GD````#[96"+X!````Z(;H___IT0````^V
-M=@CH`````.G#````1`^V;@A,BV=X2(MO8+C_____]D=8"`^$IP```$F+M"3P
-M"```2(GZOP4```#H`````(!-3`)(BWU02(GJOB$```#H`````("]@P````!T
-M'V9F9I"_T`<``.@`````3(GGZ`````"`O8,`````=>5%A.UT#&:#2UH09H--
-M:A#K"F:#8UKO9H-E:N])B[0D\`@``$B)VK\&````Z`````"`94S]N`````#K
-M&@^V=@CH`````)#K#@^V=@CH`````+@`````2(M<)`A(BVPD$$R+9"083(ML
-M)"!(@\0HPV9F9I!F9I!(@^P82(D<)$B);"0(3(ED)!!(B?U,BV=X28N$)/`(
-M``"`>#\`=6%(BY^`````#[:'S````(T$@`^V5P(!T$B8#[:(`````$$/ME0D
-M.D$/MG0D.40/MH?/````2,?'`````+@`````Z`````!(QX6``````````(M5
-M"$B+O9````!(B>[_T^L]2(V?F````$F+?"0H2(G>Z`````#'A9@```#T`0``
-M2,>%J`````````!(B:VP````28M\)"A(B=[H`````$B+'"1(BVPD"$R+9"00
-M2(/$&,-F9F:09F9FD$%7059!54%455-(@^P(2(D\)$F)]@^WTDB-!%)(C02"
-M2,'@!4F)Q4P#KS@)``!,BX?P"```28'`B!0``$R);F!)B75`28-]6`!U-4F#
-M?6``=2Y(BP0D#[9X0T"$_P^$/`0``$F+=5"Y`````$@[L,@2```/A/P#``#I
-M%`0``&:008`.`4F+16!)B49P28M%6$F)1FA(BQ0D#[9Z0T"$_W1.28MU4+D`
-M````2#NRR!(``'0;ZRT/ML%(C11`2(T4D$B+!"1(.;30R!(``'492(L4)`^V
-M0D&-!(%!B(;,````ZPVY`````(/!`4`X^77&2(L$)$B+B/`(```/MH'@"```
-MO@`````\_W0I28M56$B%TG0;#[;`2&G`R`\``$@#@8@)``"^`````$@YPG0O
-MO@$````/MH'A"```//]T*TF+55A(A=)T'P^VP$AIP,@/``!(`X&("0``2#G"
-M=0E!B'8!Z?<```"#Q@&Z`````&:0#[:$"N((```\_W0G#[;`2(T$P$C!X`5(
-M`X%@"0``23M%8'4,08AV`>G`````9F:0@\8!2(/"`4B#^@1UPXGQ00^V@.`(
-M```\_W0F28M56$B%TG4%C7$!ZQ@/ML!(:<#(#P``20.`B`D``$@YPG7EZRM!
-M#[:`X0@``#S_="A)BU582(72=!P/ML!(:<#(#P``20.`B`D``$@YPG4&08AV
-M`>M+@\8!N@````!F9I!F9I!"#[:$`N((```\_W0F#[;`2(T$P$C!X`5)`X!@
-M"0``23M%8'4+08AV`>L29F:09I"#Q@%(@\(!2(/Z!'7#2(L4)(!Z40%U/4F+
-M?5A(A?]T$D$/MK6!````N@````#H`````$F+O2`!``!(A?\/A+P!``!!#[:U
-M#0$``+H`````Z`````!)@[T@`0````^$G`$``$F+;5B`?5@`=%E!O`````!(
-MC5U(28G?2(G?Z`````!(C4CP2(M54$B)15!(B5D02(E1&$B)`H"Y#P$``/]U
-M$(!Y20!U"DB#N2`!````=0I!@\0!1#AE6'>[1#AE6`^%D0```$$/MH4/`0``
-M08A&`H!]6``/A),!``"[`````$R-94A,B>?H`````$B-2/!(BU502(E%4$R)
-M81!(B5$82(D"2(M!0$B%P'0\#[:1#P$``#A0`G0P2(.X@`````!U)DB#N(@`
-M````=1R(4`(/MU$X2(L$)$B+L/`(``"_!P```.@`````@\,!.%U8#X8:`0``
-MZXY!#[:%@0```$&(1@)!QH4/`0``_X!]6``/A/H```"[`````&9F9I!F9I!,
-MB?_H`````$B-2/!(BU502(E%4$R)>1!(B5$82(D"@+D/`0``_W1,QH$/`0``
-M_TB+04!(A<!T/`^VD8$````X4`)T,$B#N(``````=29(@[B(`````'4<B%`"
-M#[=1.$B+!"1(B[#P"```OP<```#H`````(/#`3A=6'9RZX)!#[:%@0```$&(
-M1@+K8@^VP4B-%$!(C1202(L$)$@YM-#($@``=2)(BQ0D#[9"08T$@4&(1@%!
-MB(;,````.$I#=13K#;D`````@\$!0#CY=;U!QD8!_T'&1@(`08.]D`$```!T
-M"T&+A90!``!!B$8"28U.($F-E9@```!)BX68````28E&($B+0@A(B4$(2(M"
-M$$B)01!(BT(82(E!&$B+0B!(B4$@28U.#$F-E80```!)BX6$````28E&#$B+
-M0@A(B4$(BT(0B4$028N%P````$F)1DA!#[=%:&9!B49800^W16IF08E&6DF+
-M17A)B49000^VA8(```!!B$9<00^VA9@!``!!B(;/````0?9%3`1U"4B+/"3H
-M`````$$/ME5(2(G0@^`&2(/X!G4+]L(!=09!@`X"ZP1!@";]00^V54S0ZH/B
-M!$$/M@:#X/L)T$&(!D$/MD8!08B&S@```$$/MD8"08B&S0```$R)]^@`````
-M28MU0+H`````2(L\).@`````3(GWZ$;Y__](@\0(6UU!7$%=05Y!7\-F9F:0
-M9F:02(/L&$B)7"0(2(EL)!!(B?U(BY_P"```Z`````"`?5$!=2U(C;N(%```
-M@']1`71;@+UX%````'47O@````#H`````("%>!0```%F9I!F9I!(C9V0`0``
-M2(M]*$B)WN@`````QX60`0``Z`,``$C'A:`!````````2(FMJ`$``$B+?2A(
-MB=[H`````$B+7"0(2(ML)!!(@\08PV9FD&9FD$%455-(@^PP28G[2(G32(MN
-M*$R+9C!$#[95"TB+A_`(``!(B[#P"```OP````!!N`````"Y`````&9F9I!F
-M9I`/MI0QX`@``(#Z_W1*C8&`````9CV!`'<'@\<!ZSEFD`^VPDB+EF`)``!(
-MC03`2,'@!8"\$!4!```#=1A!@\`!08U``X/X!G8.@\<!0;@`````ZP.#QP%(
-M@\$!2(/Y!G6?08GY2(NV\`@``$B!QH@4``"Q``^VE#'@"```@/K_=$^-@8``
-M``!F/8$`=P6#QP'K/@^VPDB+EF`)``!(C03`2,'@!8"\$!4!```#=1A!@\`!
-M08U``X/X!G85@\<!0;@`````ZPJ#QP%F9F:09F:02(/!`4B#^09UFD$Y^@^-
-M[P<``$4YT0^>P,<#`````#S_#X34!P``#[;X2&G_B!0``$D#N_`(``#H````
-M`$B)QTB%P`^$L@<```^V@!4!```\`@^%Q0$``,<#!`````^V=0=(BQ</MT=`
-MN0````"`O`)@"```_P^$F0$``$"`_B,/AX`!``!`#[;&_R3%`````$''!"1%
-M4P,1N`$```!FD.EM`0``2(U,)"RZ$`,``+X!````Z`````"$P`^$10$``(M$
-M)"R%P`^$0`$``"7_`P``:<`0)P``C8@0EJ__NG.(JTR)R/?BB<@IT-'H`<+!
-MZ@=!B10DN`$```#I$@$``$B-3"0LN@@#``"^`0```.@`````A,`/A.H```"+
-M1"0LA<`/A.4````E_P,``&G`Z`,``(V(R.7W_[K+:RBOB<CWXHG(*=#1Z`'"
-MP>H$08D4)+@!````Z;<```!(C4PD++H(`P``O@$```#H`````(3`#X2/````
-MBT0D+(7`#X2*````P>@0)?\#``!IP.@#``"-B,CE]_^ZRVLHKXG(]^*)R"G0
-MT>@!PL'J!$&)%"2X`0```.M<2(U,)"RZ#`,``+X!````Z`````"$P'0XBT0D
-M+(7`=#<E_P,``&G`Z`,``(V(R.7W_[K+:RBOB<CWXHG(*=#1Z`'"P>H$08D4
-M)+@!````ZPRX`````.L%N`$````/ML@/ML'I\`4``#P##X76!0``QP,$````
-M1`^V30=(QP0D`````$C'1"0(`````$C'1"00`````$C'1"08`````$B+%P^V
-M@O$```"$P`^$H0```$&X`````$F)XP^VP(/H`4R-4`&^`````+@!````B<=$
-MB<'3YP^VA!;B"```//]T*`^VP$B-!,!(P>`%2(G!2`.*8`D``$B+@8@```!(
-MBT`@#[9`"CGX=!!(@\8!2(/^!`^$)@4``.N\2(7)#X0;!0``#[=!0("\`F`(
-M``#_#X0)!0``@+D5`0```P^%_`0``$N)#,-)@\`!33G0#X5R____08#Y50^'
-MUP0``$$/ML'_),4`````0<<$)$`#`Q&X`0```.F_!```2(U,)"Q!C4$!@^`#
-M2(L\Q+HT`P``O@$```#H`````(3`#X23!```#[=4)"R)5"0L@?K__P``=1)!
-MQP0D_____[@!````Z74$``"XP.'D`(G1N@````#W\4&)!"2X`0```.E9!```
-M2(U,)"Q(BWPD"+H0`P``O@$```#H`````(3`#X0S!```BT0D+"7_`P``:<`0
-M)P``C8@0EJ__NG.(JTR)R/?BB<@IT-'H`<+!Z@=!B10DN`$```#I`00``$B-
-M3"0L2(M\)`BZ"`,``+X!````Z`````"$P`^$VP,``(M$)"PE_P,``&G`Z`,`
-M`(V(R.7W_[K+:RBOB<CWXHG(*=#1Z`'"P>H$08D4)+@!````Z:D#``!(C4PD
-M+$B+?"0(N@@#``"^`0```.@`````A,`/A(,#```/MT0D+B7_`P``:<#H`P``
-MC8C(Y??_NLMK**^)R/?BB<@IT-'H`<+!Z@1!B10DN`$```#I4`,``$B-3"0L
-M2(M\)`BZ#`,``+X!````Z`````"$P`^$*@,``(M$)"PE_P,``&G`Z`,``(V(
-MR.7W_[K+:RBOB<CWXHG(*=#1Z`'"P>H$08D4)+@!````Z?@"``!(C4PD+$B+
-M/"2Z%`,``+X!````Z`````"$P`^$TP(``(M4)"R!XO\#``!(:=(ZN`$`2('"
-MXTH#`$C!Z@5(N$-XM''$6GP*2/?B2,'J!T&)%"2X`0```.F=`@``2(U,)"Q(
-MBWPD"+H4`P``O@$```#H`````(3`#X1W`@``BU0D+('B_P,``$AITCJX`0!(
-M@<+C2@,`2,'J!$BXA?!HXXBU^!1(]^)(P>H(08D4)+@!````Z4$"``!(C4PD
-M+$B+?"00NA0#``"^`0```.@`````A,`/A!L"``"+5"0L@>+_`P``2&G2YA-`
-M`DB!P@W_3@1(N+U">N75E+_62/?B2,'J%T&)%"2X`0```.GI`0``2(U,)"Q(
-MBWPD&+H4`P``O@$```#H`````(3`#X3#`0``BU0D+('B_P,``$AITJY%X0!(
-M@<(I4J\!2+C;-+;7@MX;0TCWXDC!ZA)!B10DN`$```#ID0$``$B-3"0L2(M\
-M)`BZL`,``+X!````Z`````"$P`^$:P$``(M$)"S!Z`^#X`%!B00DN`$```#I
-M6`$``(!]"`!T$4B+1"0(@:`8`0``__?__^L/2(M$)`B!B!@!````"```2(M\
-M)`CH`````+@!````Z1X!``"`?0@`=!%(BT0D"(&@&`$``/_O___K#TB+1"0(
-M@8@8`0```!```$B+?"0(Z`````"X`0```.GD````@'T(`'012(M$)`B!H!@!
-M``#_W___ZP](BT0D"(&(&`$````@``!(BWPD".@`````N`$```#IJ@```(!]
-M"`!T$4B+1"0(@:`8`0``_[___^L/2(M$)`B!B!@!````0```2(M\)`CH````
-M`+@!````ZW.`?0@`=!%(BT0D"(&@&`$``/___O_K#TB+1"0(@8@8`0`````!
-M`$B+?"0(Z`````"X`0```.L\@'T(`'012(M$)`B!H!@!``#___W_ZP](BT0D
-M"(&(&`$``````@!(BWPD".@`````N`$```#K!;@`````#[;`ZP6X``````^V
-MP.L2N`````#K"\<#`````+@`````2(/$,%M=05S#9F9FD&9FD&9FD$%7059!
-M54%455-(@^PX28G\B?!(B=-)B<U!B?9!P>X808GW0<'O$`^VU(A4)!!`B'0D
-M#TB-JX@4``"X`````)#&!!@`2(/``4@]$"L``'7P3(EK((L%`````(A#0(/`
-M`8D%`````$2(<SM$B'LZ#[9$)!"(0SD/ME0D#XA3.,9#00!!#[<$)&:)0S!!
-M#[=$)`)FB4,R08M$)`2)0S1(C9,0*0``2(F3@!0``$R);2`/MD-`B$5`1(AU
-M.T2(?3H/MD0D$(A%.0^V1"0/B$4XQD5!`4$/MP0D9HE%,$$/MT0D`F:)13)!
-MBT0D!(E%-$B)E8`4```/MT,R9CTD)P^$%`$``&8])"</AX0```!F/40A#X0`
-M`0``9CU$(7=$9CT@(0^$\````&8]("%W#V8]4`</A?0```#IVP```&8](B&0
-M#X30````9CU`(69FD&9FD`^%U````.F[````9F:09I!F/1`G#X+`````9CT1
-M)V:0#X:@````9BT@)V:#^`)FD`^'I````.F+````9F:09I!F/8`G#X1\````
-M9CV`)V:0=RYF/4`G=&YF/4`G9F9FD'<(9CTP)W5RZUQF/40G9I!T5&8]8"=U
-M8NM,9F:09F:09CV`<G1`9CV`<F9FD&9FD'<(9CV")W5"ZRQF/8"19I!T#F8]
-M@)1U,NL<9F:09F:09L=#/("1QD,^!&;'13R`D<9%/@3K%&;'0SR`E,9#/@1F
-MQT4\@)3&13X$00^V1"0(B$-"00^V1"0(B$5"N0``!`"Z`````+X"````3(GO
-MZ`````!(B0.Y`"```+H`````O@````!,B>_H`````$B)P4B)0Q!(BP-(A<`/
-MA.4!``!(A<D/A-P!``!(C9```@$`2(E3"$B-@````@!(B0-(!0!```!(B44`
-M2(E5"$B)31!$BP4`````187`?F>^`````+D`````2,?'``````^W!#EF03L$
-M)'4_#[>!`````&9!.T0D`G4PBY$`````@\(!B9$`````1(N)`````$6%R705
-M1#G*=A")T+H`````0??QB9$`````@\8!2(/!&$0YQG6J2(M#"$@MX'T``,<`
-M`?`#`$B+0PA(+=A]``#'``$``.A(BWL@OG@```#H`````(G")0!P```]`"``
-M`'84@.:/@,X@2(M[(+YX````Z`````!$B'0D(T2(?"0B#[94)!"(5"0A#[9$
-M)`^(1"0@O0````!!N0````!)Q\0`````3(UL)"!F0X,\(0`/A*(```!!@+D`
-M``````^$A````$&X`````$ACQ4R-%,4`````38GK2XT$`DB--(4`````N00`
-M``#\3(G?\Z8/E\(/DL`XPG4[00^V@0````"#P`%!B($`````00^VD0````"$
-MTG0=.-!V&0^VP`^VRKH`````9O?Q08B1`````&9F9I!!C5`!28/``4$/MH$`
-M````.=!_D(/%`4F#P2"#_00/A5+____'@P@)```!````N`$```#K!;@`````
-M2(/$.%M=05Q!74%>05_#9F9FD&9FD$%455-(B?M(B?5(BW]X#[8#@^`!1`^V
-MX+@`````9F:0Q@0H`$B#P`%(@_@H=?)(B[>`%```2(GRL`!F9I!F9I#&!!``
-M2(/``4@]``(``'7P2(U.-KH`````9F9FD&9FD`^V1%,AB`11#[9$4R"(1%$!
-M2(/"`4B#^A1UY4B-3A2R``^V1%,-B`11#[9$4PR(1%$!2(/"`4B#^@IUY4B-
-M3BZR``^V1%-)B`11#[9$4TB(1%$!2(/"`4B#^@1UY4B)=1A(BT-02(/``4B)
-M10!(@WM@`'5!]@,!=#Q(BT-H2(7_#Y7"2(7`=!*$TG0.#[9`6X"\!V`(``#_
-M=1M(BT-PA-)T-TB%P'0R#[=`0("\!V`(``#_="0/MH/,````C02`#[93`@'0
-M2)@/MH``````B$4,0;P`````ZR#H`````$B%P'02@+@5`0```G4)#[9#`8A%
-M#.L$QD4,_\9%#0#&10X!QD42$,9%$1!$B>"-%`"^_?___T`B=0H)UD"(=0K!
-MX`4/MDT(@^'?"<&(30@/MT-82,'H!X/@`<'@!H/AOPG!B$T(#[=#6$C!Z`*#
-MX`$/ME4)@^+^"<*(50D/MT-:2,'H`\'@!X/A?PG!B$T(#[=#6DC1Z(/@`0'`
-M@^+]"<*(50D/MT-82,'H`X/@`<'@!H/BOPG"B%4)#[=#6DC!Z`3!X`>#XG\)
-MPHA5"8/)$(A-"`^V`]#H@^`!@^;^"<9`B'4*#[8#@^`$@^;["<9`B'4*9L=%
-M%``0#[:#SP```(A%#P^V@\P```"(12!;74%<PY!!5D%505154T&)]4&)UDB)
-MRTR)Q4B%R707N`````!FD,8$&`!(@\`!2#VL````=?!(A>UT&;@`````9F:0
-M9F:0Q@0H`$B#P`%(@_@H=?),BZ?P"```00^V]4R)Y^@`````B<)FA<!T#@^W
-MP$&`O`1@"```_W5(38ND)/`(``!)@<2(%```28N\)/`(``#H`````$$IQ4$/
-MMO5,B>?H`````(G"9H7`#X1/`P``#[?`08"\!&`(``#_#X0]`P``#[?"00^V
-MA`1@"```9H'Z@0`/AU("``!)BXPDB`D```^WP$AIP,@/``!(C30!2(7;#X36
-M````2(M6$$B%TG1U00^VA"3@"```//]T&`^VP$AIP,@/``!(C00!OX````!(
-M.<)T)4$/MH0DX0@``#S_=!P/ML!(:<#(#P``2(T$`4@YPG4)OX$```!`B'L"
-M@'Y:`'0PN@`````/ML(/MDP&<+@!````T^`)0R"#P@$X5EIV$>ODQD,"_TB+
-M1@@/MD`-B4,@Q@,!#[9&68A#`4B+1GA(B4,$2(N&B````$B)0PQ(BX:0````
-M2(E#%(N&H````(E#'$2):R0/MH;`````B4,HN`````#I-@(``$B%[0^$*`(`
-M`$6%]@^('P(```^VAL````!!.<8/C0\"``!)8\9(C01`2,'@!$@!\$B-D,``
-M```/MDH(B$T`#[92"8A5`4B+@-`````/M@"#X`^(10*`^0-T+H#Y`W<.@/D"
-M#X6I````Z:L```"`^01F9I!F9I!T0(#Y$@^%D````&9FD&:0ZU])8\9(C01`
-M2,'@!$B+E`;0````#[9"`8/@!P^VP,'@"`^V4@(!T(T$@`'`B44$ZV!)8\9(
-MC01`2,'@!$B+A`;0````#[9``H3`=0G'100`````ZSP/ML"#Z!2)103K,4EC
-MQDB-!$!(P>`$2(N4!M`````/MD("P>`(#[92`P'0C02``<")103K!\=%!```
-M``!(C4T(26/&2(T$0$C!X`1(C80&T````$B-4`A(BT`(2(E%"$B+0@A(B4$(
-M2(M"$$B)01!(BT(82(E!&+@`````Z=D````/M\!(C03`2,'@!4B)Q4D#K"1@
-M"0``QD,"_\8#`DF+E"1@"0``#[9$$#N(0P%(BX6(````#[9`#8E#(`^VA14!
-M```\`G4KQT,$2%!4`,=##%)O8VO'0Q!E=%-TQT,4;W(@``^W=3Y(C7L7Z%K"
-M___K1SP#=2'&0P$0QT,@`0```,=#!$A05`#'0PQ%2C,T9L=#$#``ZR+&0P1V
-M#[=U/$B->P7H(L+__\9##&0/MW4^2(U[#>@1PO__QD,<<@^V=3E(C7L=Z,#!
-M__]$B6LDN`````#K!;C_____6UU!7$%=05[#9F9FD&9FD$%505154T&)]4B)
-MT[@`````Q@08`$B#P`%(/2@-``!U\$B+K_`(``!!#[;U2(GOZ`````")PF:%
-MP'0-#[?`@+P%8`@``/]U14B+K?`(``!(@<6(%```2(N]\`@``.@`````02G%
-M00^V]4B)[^@`````B<)FA<`/A)$#```/M\"`O`5@"```_P^$@`,```^WP@^V
-MA`5@"```9H'Z@0`/AXT"``!(BXV("0``#[?`2&G`R`\``$R-!`%)BU`02(72
-M='0/MH7@"```//]T&`^VP$AIP,@/``!(C00!OH````!(.<)T(P^VA>$(```\
-M_W0<#[;`2&G`R`\``$B-!`%(.<)U";Z!````0(AS`D&`>%H`=#*Z``````^V
-MPD$/MDP`<+@!````T^`)0R"#P@%!.%!:=A'KXL9#`O])BT`(#[9`#8E#(,8#
-M`4$/MD!9B$,!28M`>$B)0P1)BX"(````2(E##$F+@)````!(B4,408N`H```
-M`(E#'$2):R1!@+C```````^$BP(``$&Y`````$$/MOE(8\=(C0R`2(T,RTB-
-M!$!(P>`$3`'`2(V0P`````^V<@A`B+&H````#[92"8B1J0```$B+@-`````/
-MM@"#X`^(@:H```!`@/X#=#1`@/X#=Q%`@/X"#X73````9I#IW@```$"`_@1F
-M9F:09F:0=$M`@/X2#X6U````9F9FD.M]2&//2(T$24C!X`1)BY0`T````$B-
-M#(D/MD(!@^`'#[;`P>`(#[92`@'0C02``<")A,NL````Z88```!(8]=(C012
-M2,'@!$F+A`#0````#[9``H3`=1%(C022QX3#K`````````#K6DACUTB-%)(/
-MML"#Z!2)A-.L````ZT1(8\](C01)2,'@!$F+E`#0````2(T,B0^V0@+!X`@/
-MME(#`="-!(`!P(F$RZP```#K$DACQTB-!(#'A,.L`````````$ACQTB-%(!(
-MC933H````$B-<A!(C01`2,'@!$F-A`#0````2(U("$B+0`A(B4(02(M!"$B)
-M1@A(BT$02(E&$$B+01A(B48808/!`44XB,`````/AND```#I7_[__P^WP$B-
-M!,!(P>`%28G$3`.E8`D``,9#`O_&`P)(BY5@"0``#[9$$#N(0P%)BX0DB```
-M``^V0`V)0R!!#[:$)!4!```\`G4MQT,$2%!4`,=##%)O8VO'0Q!E=%-TQT,4
-M;W(@`$$/MW0D/DB->Q?H/K[__^M+/`-U(<9#`1#'0R`!````QT,$2%!4`,=#
-M#$5*,S1FQT,0,`#K)L9#!'9!#[=T)#Q(C7L%Z`2^___&0PQD00^W="0^2(U[
-M#>CQO?__QD,<<D$/MG0D.4B->QWHGKW__T2):R2X`````.L,N/_____K!;@`
-M````6UU!7$%=PT%455-!B?1(B=.X`````)#&!!@`2(/``4@]I`P``'7P2(NO
-M\`@``$$/MO1(B>_H`````(G"9H7`=`T/M\"`O`5@"```_W5'2(NM\`@``$B!
-MQ8@4``!(B[WP"```Z`````!$B>8IQD`/MO9(B>_H`````(G"9H7`#X1G`P``
-M#[?`@+P%8`@``/\/A%8#```/M\(/MH0%8`@``&:!^H$`#X=G`@``2(N-B`D`
-M``^WP$AIP,@/``!,C00!28M0$$B%TG1T#[:%X`@``#S_=!@/ML!(:<#(#P``
-M2(T$`;Z`````2#G"=",/MH7A"```//]T'`^VP$AIP,@/``!(C00!2#G"=0F^
-M@0```$"(<P)!@'A:`'0RN@`````/ML)!#[9,`'"X`0```-/@"4,@@\(!03A0
-M6G81Z^+&0P+_28M`"`^V0`V)0R#&`P%!#[9`68A#`4F+0'A(B4,$28N`B```
-M`$B)0PQ)BX"0````2(E#%$&+@*````")0QQ!@+C```````^$90(``$&Y````
-M`$$/MOE(8\=(C0R`2(T,RTB-!$!(P>`$3`'`2(V0P`````^V<@A`B'$D#[92
-M"8A1)4B+@-`````/M@"#X`^(029`@/X#=#!`@/X#=P]`@/X"#X7`````Z<H`
-M``!`@/X$9F:09I!T14"`_A(/A:8```!F9F:0ZW%(8\](C01)2,'@!$F+E`#0
-M````2(T,B0^V0@&#X`</ML#!X`@/ME("`="-!(`!P(E$RRCK>DACUTB-!%)(
-MP>`$28N$`-`````/MD`"A,!U#DB-!)+'1,,H`````.M12&/72(T4D@^VP(/H
-M%(E$TRCK/DACSTB-!$E(P>`$28N4`-````!(C0R)#[9"`L'@"`^V4@,!T(T$
-M@`'`B43+*.L/2&/'2(T$@,=$PR@`````2&/'2(T4@$B-5-,@2(UR#$B-!$!(
-MP>`$28V$`-````!(C4@(2(M`"$B)0@Q(BT$(2(E&"$B+01!(B4802(M!&$B)
-M1AA!@\$!13B(P`````^&Y0```.F!_O__#[?`2(T$P$C!X`5)B<1,`Z5@"0``
-MQD,"_\8#`DB+E6`)```/MD00.XA#`4F+A"2(````#[9`#8E#($$/MH0D%0$`
-M`#P"=2W'0P1(4%0`QT,,4F]C:\=#$&5T4W3'0Q1O<B``00^W="0^2(U[%^A#
-MNO__ZTL\`W4AQD,!$,=#(`$```#'0P1(4%0`QT,,14HS-&;'0Q`P`.LFQD,$
-M=D$/MW0D/$B->P7H";K__\9##&1!#[=T)#Y(C7L-Z/:Y___&0QQR00^V="0Y
-M2(U['>BCN?__N`````#K#+C_____ZP6X`````%M=05S#9F9FD&9F9I!F9I!!
-M5%5308GT2(G3N`````"0Q@08`$B#P`%(/0`!``!U\$B+K_`(``!!#[;T2(GO
-MZ`````")PF:%P'0-#[?`@+P%8`@``/]U1TB+K?`(``!(@<6(%```2(N]\`@`
-M`.@`````1(GF*<9`#[;V2(GOZ`````")PF:%P`^$V0$```^WP("\!6`(``#_
-M#X3(`0``#[?"#[:$!6`(``!F@?J!``^'V0```$B+C8@)```/M\!(:<#(#P``
-M2(TT`4B+5A!(A=)T<0^VA>`(```\_W08#[;`2&G`R`\``$B-!`&_@````$@Y
-MPG0C#[:%X0@``#S_=!P/ML!(:<#(#P``2(T$`4@YPG4)OX$```!`B'L"@'Y:
-M`'0PN@`````/ML(/MDP&<+@!````T^`)0R"#P@$X5EIV$>ODQD,"_TB+1@@/
-MMD`-B4,@Q@,!#[9&68A#`4B+1GA(B4,$2(N&B````$B)0PQ(BX:0````2(E#
-M%(N&H````(E#'+@`````Z=X````/M\!(C03`2,'@!4F)Q$P#I6`)``#&0P+_
-MQ@,"2(N58`D```^V1!`[B$,!28N$)(@````/MD`-B4,@00^VA"05`0``/`)U
-M+<=#!$A05`#'0PQ2;V-KQT,09713=,=#%&]R(`!!#[=T)#Y(C7L7Z-&W___K
-M2SP#=2'&0P$0QT,@`0```,=#!$A05`#'0PQ%2C,T9L=#$#``ZR;&0P1V00^W
-M="0\2(U[!>B7M___QD,,9$$/MW0D/DB->PWHA+?__\9#'')!#[9T)#E(C7L=
-MZ#&W__^X`````.L%N/____];74%<PTB#["A(B1PD2(EL)`A,B60D$$R);"08
-M3(ET)"!(B?M)B?1,BW=X2(M&2$B).$B+1V!(A<!U&L:&L@````)(B??_EL@`
-M``#I:@8``&9FD&:0]D!,`G0:QH:R`````DB)]_^6R````.E*!@``9F:09I!,
-MB??H`````$B)Q4B%P&:0=1Y!QH0DL@````),B>=!_Y0DR````.D:!@``9F:0
-M9I#'@)0`````````3(E@:$B+0V!(B44H2(M#8`^W0#AFB44@QD4D@$$/MH0D
-ML````#P"#X1I`0``/`)W"H3`=!R0Z4(#```\`P^$\`$``#P$D`^%,0,``.FX
-M`0``2(M#8/9`:`$/A)\```!!#[:$)+$```"H`G0&QD4XB.L0@^`$/`$9P(/@
-M!8/H=HA%.$F+E"20````00^WC"28````QD4Y`$B)T$C!Z#B(13I(B=!(P>@P
-MB$4[2(G02,'H*(A%/$B)T$C!Z""(13U(B=!(P>@8B$4^2(G02,'H$(A%/TB)
-MT$C!Z`B(14"(54'&14(`QD5#`(G(9L'H"(A%1(A-1<9%1@#&14<`ZVU!#[:$
-M)+$```"H`G0&QD4X*.L0@^`$/`$9P(/@!8/`*HA%.$F+E"20````00^WC"28
-M````QD4Y`$B)T$C!Z!B(13I(B=!(P>@0B$4[2(G02,'H"(A%/(A5/<9%/@")
-MR&;!Z`B(13^(34#&14$`2(M#8$@%[````$B)15#&13`@#[?!P>`)B44T@XV4
-M`````NGY`0``9F9FD$$/MH0DD````#P0=P7V`P)U#D'&A"2R````!NDD!```
-M2(U].`^VT$F-M"28````Z`````!(BT-@2`7L````2(E%4,9%,""!C90`````
-M`!``QD4EJT'VA"2Q````!@^$D@$``$&+A"24````B44TZ8(!``!!#[:$)+$`
-M``"#X#`\('41QD4X&\9%.0'&13P`Z6$!``#&13@UZ5@!``!(BT-@#[9`2*@!
-M=">H!'0C@8V4```````@`$$/MY0DG````&9!.Y0DD@```'43ZV-F9I!!QH0D
-ML@````;I9@,``$$/MH0DFP```#SC=$4\XW<3/$)T/3RP=!T\0'4G9F:09I#K
-M+CSL=`X\[W0F/.5F9F:0=1#K'&9!B90DD@```&9FD.L.0<:$)+(````&Z10#
-M``#&13BP00^WA"20````B$4Y00^WA"22````B$4Z00^WA"24````B$4[00^W
-MA"26````B$4\00^WA"28````B$4]00^VA"2:````B$4^00^VA"2;````B$4_
-M00^VA"21````B$5`00^VA"23````B$5!00^VA"25````B$5"00^VA"27````
-MB$5#00^VA"29````B$5$0?:$)+$````&="9!#[>$))P```#!X`F)132#C90`
-M```$ZPY!QH0DL@````;I3P(``$C'A:``````````00^VA"2Q````J`8/A!\"
-M``"H`G0)@XV4````".L'@XV4````$$R-;5A)BYPDN````$B%VW0+0?:$)+$`
-M```!=39)BX0DP````$B%P`^$"@(``$F+MD`*``"Z`````$R)Y__0A<`/A/$!
-M``!)BYY`"@``2(7;=#E(B>_H`````+X`````3(GOZ`````!(@\,0BU/P2(MS
-M^$R)[^@`````BT/T2(/#$(7`#X6)`0``Z^"^`````$R)[^@`````BT4T/0`(
-M``!W.TR)]^@`````2(G!2(7`=0Y!QH0DL@````OI7P$``$B+0!!(B45(2(E-
-M>(M5-$B+<1A,B>_H`````.M4/0```0!W/TR)]V9F9I#H`````$B)P4B%P'4.
-M0<:$)+(````+Z1D!``!(BT`02(E%2$B)37B+531(BW$83(GOZ`````#K#D'&
-MA"2R````!NGN````00^VA"2Q````J`0/A-````!!@+PDL`````-U'DF+M"2@
-M````2(7V=!%(BWU(BU4TZ`````#IIP```$F+E"2X````2(72=1-)BX0DP```
-M`$B%P`^%N````.MA3(MM2*@!=0I(B=-F9I!FD.LI28N$),````!(A<!T'$F+
-MMD`*``"Z`0```$R)Y__0A<!T!TF+GD`*``!(@\,0BU/P2(MS^$R)[^@`````
-MBT/P20'%BT/T2(/#$(7`=2CKWHM%-$B+34B%P'0;B<)(B<C&``!(@\`!2(/J
-M`70)Z_&#C90````!2(GN3(GWZ`````#K,4B)[DR)]^@`````3(GG0?^4),@`
-M``#K&;L`````Z4K^__],BVU(9F:09F:0Z5K___](BQPD2(ML)`A,BV0D$$R+
-M;"083(MT)"!(@\0HPV9F9I!F9F:09F:09F:055-(@^P(2(G]2(GSN`````#&
-M!!@`2(/``4@]@````'7P@[T("0```0^40Q,/ME4Z#[9-.0^V=3@/MD4[B$,#
-MB%,"B$L!0(@S@$L1$`^W13!FB4,$#[=%,F:)0P:+A0@)``"(0W#&0Q(@#[=5
-M,F:!^B`A=`=F@?HB(75(QD,7`DB-0SS'0SQ2;V-KQT-`97120<=`"$E$(%/'
-M0`Q31"`RQT`0,3)X(,=`%$-O;G3'0!AR;VQL9L=`'&5RQD`>`.D!`0``C8+P
-MV/__9H/X`7829H'Z0"%T"V:!^D0A#X6G````QD,7!`^W53*-@O#8__]F@_@!
-M=T1(C4,\QT,\4F]C:\=#0&5T4D''0`A)1"`RQT`,-S%X(,=`$%-!4R#'0!1#
-M;VYTQT`8<F]L;&;'0!QE<L9`'@#IBP```&:!^D`A=`=F@?I$(75]2(U#/,=#
-M/%)O8VO'0T!E=%)!QT`(240@4\=`#%-$(#+'0!`Q-'@@QT`40V]N=,=`&')O
-M;&QFQT`<97+&0!X`ZSS&0Q<(2(U#/,=#/%)O8VO'0T!E="`WQT`(-3`@4\=`
-M#$%402#'0!!#;VYTQT`4<F]L;&;'0!AE<L9`&@#&0Q<HQD,2`<9#$"A(C4,8
-MQT,82&EG:,=#'%!O:6['0`AT(%1EQT`,8VAN;\=`$&QO9VG'0!1E<RP@QT`8
-M26YC+L9`'`!(BX4`"0``2(7`=`I(BT`02(E#:.L(2(M%$$B)0VC'0V``(```
-M2(M](+Y\````Z`````")PH'B\`,``,'J!(A3<8/@#XA#<TB+?2"^@````.@`
-M````B<*!X@``\`/!ZA2(4W(E```/`,'H$(A#=$B#Q`A;7<-FD$%7059!54%4
-M55-(@^P(28G]B?5(B=.X`````&9FD&:0Q@08`$B#P`%(/=````!U\(EK"(/]
-M$WX*28'%B!0``(/M%$ACQ;H`````28.\Q6`$````#X72`@``2&/%28F<Q6`$
-M``!,B6MX2(F+@````$R)@Y````!!@'U1`0^%I0(``(']A0````^/@P(``$$/
-MMH0%8`@``#S_#X1R`@``#[;`9HE$)`8/M\!(C11`2(T4D$C!X@5)B=1-`Z4X
-M"0``0?9$)$L$#X1%`@``08M$)$@E`/__`#T``/\`#X4P`@``0?9$)$P$#X2<
-M`0``0<:$).@`````00^V1"1(2(G"@^(&2(/Z!G4YJ`$/A!`!``!!QD0D2@5!
-MQD0D2P1!#[:4)($```!)BW0D6$F+?"103(GAZ`````"Z`0```.GK`0``2(/Z
-M!`^%W`$``*@!9F9FD`^$T`$``$F+7"1028M$)&!(A<`/A84```!!QD0D2@-!
-MQD0D2P2`>PX`=$^]`````$R-<V!,B??H`````$B)PDB+0VA(B5-H3(DR2(E"
-M"$B)$(!Z2O]T&$DYU'030<:$).D````!N@$```#I;`$``(/%`0^V0PXYZ'^Z
-M08"\).D````!#X1-`0``3(GF3(GOZ`````"Z`0```.D]`0``@'A"``^%+@$`
-M`&:#8$[]28M$)&!FQT!.(`!)BW0D8$R)[^@`````N@$```#I#`$``$F+1"10
-M#[9`#4&`?3X`="V[``````^VZ`^VRTB)Z$C3^*@!=`^Z`````(G.3(GOZ```
-M``"#PP%!.%T^=]M!QD0D2P9!QD0D2@5F0<>$),@``````$R)YDR)[^@`````
-MN@$```#IHP```$V+9"1008!\)`X`=%U!O@````!-C7PD8$R)_^@`````2(G"
-M28M$)&A)B50D:$R).DB)0@A(B1"`>DK_="(/MD))/")T!#P-=19(8\5)QX3%
-M8`0```````"Z`````.M$08/&`44X="0.=ZX/MU0D!DB)WDR)[^@`````N@$`
-M``#K(F9F9I!F9I!(8\5)QX3%8`0```````"Z`````.L%N@$```")T$B#Q`A;
-M74%<05U!7D%?PY"0D)")T,8'",9'`1)`A/9T!H!/`@3K!(!G`ON$P'0&@&<,
-MW^L$@$\,(+@4````PV9F9I#SPV9F9I!F9F:09F:09F:005=!5D%505154TB#
-M[!A)B?U)B?9(B=6(3"0'18G'2(M&,$B)1"002,=&,`````!(A<`/A70!``#H
-M`````$F)Q+@`````387D#X01`@``3(GOZ`````!(B40D$$B%P'453(GF3(GO
-MZ`````"X`````.GJ`0``0<9$)#@:0<9$)#D(0<9$)#H(0<9$)#L`0<9$)#S_
-M0<9$)#T`0<9$)"6K00^W1CAF08E$)"!-B6PD*$''1"0T_P```$''A"24````
-M"````$B+1"002(M`$$F)1"1(2`7_````28E$)%!!QD0D,"1(BT0D$$F)1"1X
-M2<>$)*``````````0<9$)"2`28U<)%B^`````$B)W^@`````2(M$)!!(BW`8
-MNO\```!(B=_H`````$R)YDR)[^@`````N\C____K(&9F9I!F9I"_Z`,``.@`
-M````@^L!3(GOZ`````"$VW0.00^V1"0D/(!TW83`=#%(C70D$$R)[^@`````
-M00^W="0R28M^4.@`````3(GF3(GOZ`````"X`````.G'````2<=$)'@`````
-M3(GF3(GOZ`````!(BT0D$$B+6!!!#[;7#[9T)`=(C7L$Z`````!!B<3&`P#&
-M0P$`QD,"`,9#`P!(B>Y,B>_H`````$B-53BX`````&9FD,8$$`!(@\`!2(/X
-M$'7R08U$)`3&13@5QD4Y$8A%/,9%/0!(C5U81`^VX$2)933'A90`````````
-M2(M4)!!(BT(02(E%2$B)57B^`````$B)W^@`````2(M$)!!(BW`81(GB2(G?
-MZ`````"X`0```$B#Q!A;74%<05U!7D%?PY"0B?!FB7<(QD<.`&;'1PP``&:%
-M]G0?C5#_N0````!F9I!(BP=FB10(2(/!`H/J`6:#^O]U[//#9F9FD&9FD&9F
-MD$&)\&:)=PC&1PX!9L='#```9H7V=!ZZ`````+D`````2(L'9HD4"(/"`4B#
-MP0)F1#G"=>SSPV9F9I!F9I!F9I"`?PX!=2H/MT<,#[?(2(L7#[<42H/``6:)
-M1PQF.T<*<@9FQT<,``!F@V\(`0^WPL-(BQ</MT<(@^@!9HE'"`^WP`^W!$+#
-M9F9FD&9FD&9FD(!_#@%U*@^W5P@/MT<,`<(/MT<*B<&)T,'Z'_?Y2&/22(L'
-M9HDT4&:#1P@!PV9FD`^W1P@/M\A(BQ=FB31*@\`!9HE'",-F9F:09F:09F:0
-M9H-_"``/E,`/ML##D)"0D$B+#T@YSW4(N0````#K#Y!(BQ%(BT$(2(E""$B)
-M$$B)R,-F9F:09F9FD&9FD&9FD$&)T(32=#H/M@<Z!G4H2(GQO@````#K%`^V
-M5P$/MD$!2(/'`4B#P0$XPG4*@\8!1#C&=>3K"[@`````9F:09I##N`$```##
-M9F:09F:09F:0QD<!`$"(=P+'1P0`````PT&)T`^V5P$/ML)(C01`2,'@`DB)
-MP4@#3PB#P@&(5P%$`4<$N`````#&!`@`2(/``4B#^`QU\DB),42(00A,B<(/
-MML:(00E$B<+!ZA"#XC\/MD$*@^#`"="(00K#9F9FD`^V1P$Z!P^2P`^VP,-F
-M9I!(B?FX`````(!Y`O]U"&:),8A1`NL-@\`!2(/!!&8]@`!UY0^WP,-F9I!F
-M9I!F9I!!B=`/M\9(C02'@'@"_W409D2)`(A(`@^WQL-F9I!FD`^VT4$/M_#H
-M``````^WP,-(B?FX`````#A1`G439CDQ=0[&00+_9L<!___K$&9FD(/``4B#
-MP01F/8``==L/M\##9F9FD&9F9I!F9F:09F:0N`````")P3A4AP)U!F8Y-(=T
-M#X/!`4B#P`%(/8````!UXV:!^8``N(`!```/1,@/M\'#9F9FD&9FD&9FD&9F
-MD`^V1S@\"'0^/"AT.CRH#X3_````/(@/A#D!```\"F:0="0\*G0@/*H/A.4`
-M```\B@^$'P$``#PO=`P\CV9F9I`/A90!```\+P^$D@```#PO=R(\"G1?/`IW
-M"CP(9F9FD'5$ZU$\*'1X/"IF9I!F9I!U-.ML/(\/A-D````\CV:0=Q4\B`^$
-MRP```#R*9F9FD'44Z;X````\J&9F9I!F9I!T<3RJ=&VY`````+@`````Z1,!
-M```/MD<ZP>`(#[97.PG0#[97.8/B'\'B$`G0B<$/MD<\Z>\```!F9F:09F:0
-M#[97.L'B&`^V1SO!X!`)P@^V1ST)P@^V1SS!X`B)T0G!#[9'/\'@"`^V5T`)
-MT.FU````#[97.L'B&`^V1SO!X!`)P@^V1ST)P@^V1SS!X`B)T0G!#[97/L'B
-M&`^V1S_!X!`)P@^V1T$)P@^V1T#!X`@)T.MS#[97.DC!XC@/MD<[2,'@,$@)
-MP@^V1T%("<(/MD<\2,'@*$@)P@^V1SU(P>`@2`G"#[9'/DC!X!A("<(/MD<_
-M2,'@$$@)P@^V1T!(P>`(2(G12`G!#[970L'B&`^V1T/!X!`)P@^V1T4)P@^V
-M1T3!X`@)T$B)CX@```")AY````!F@T\B`?/#9F9FD+K_____9H7V=#%(B?F_
-M`````+K_____2<?``````&:0#[8!,=`/ML#!Z@A!,Q2`@\<!2(/!`68Y]W7E
-MB=##9I!(@^QH1`^V3SM$#[9'.@^V3SD/ME<X#[9'1XE$)%@/MD=&B40D4`^V
-M1T6)1"1(#[9'1(E$)$`/MD=#B40D.`^V1T*)1"0P#[9'08E$)"@/MD=`B40D
-M(`^V1S^)1"08#[9'/HE$)!`/MD<]B40D"`^V1SR)!"1(B?Y(Q\<`````N```
-M``#H`````$B#Q&C#9I!(@^P(#[9&`8A'`0^V1@*(1P*+1@2)1P1(BT<(#[97
-M`4B-%%)(P>("2(MV"$B)Q^@`````2(/$",-F9F:09F:02(M/8`^V5UBX````
-M`&9FD,8$.`!(@\`!2#VH````=?!(B4]@B%=8PV9F9I!F9F:0N`````"Z____
-M_V9FD&9FD(@4.$B#P`%(/0`"``!U\?/#9F9FD&9F9I!F9F:09F:0N0````!(
-M.S]T$DB+3PA(BQ%(BT$(2(E""$B)$$B)R,-(BP^+@00!``")PH'B?O_^_XF1
-M!`$``"5^__+_2(M7"(D"2(M7"(E"#$B+5PB)0A!(BU<(B4(42(M7"(E"&$B+
-M5PB)0@1(BP>+@%0!``")!0`````E_@#__TB+%XF"5`$``,-F9F:09F:09F:0
-M9F:0B?%(BP>+D`0!``")%0`````/MT<\9CV`9'0,9CV`D70&9CV`E'41#[;)
-M@\$(N`$```#3X`G"ZQ!`#[;.@\$,N`$```#3X`G"2(L'B9`$`0``PV9F9I!F
-M9F:09F:09F:0B?%(BP>+D`0!``")%0`````/MT<\9CV`9'0,9CV`D70&9CV`
-ME'41#[;)@\$(N/[____3P"'"ZQ!`#[;.@\$,N/[____3P"'"2(L'B9`$`0``
-MPV9F9I!F9F:09F:09F:0B?%`@/[_=&]`@/X?=S*+MQ@!``"Z`0```-/BB=#W
-MT"'PB8<8`0``BX=8`0``B04`````(=!T0(F'6`$``,-FD(NW'`$```^VP8/H
-M(+H!````B<'3XHG0]]`A\(F''`$``(N'8`$``(D%`````"'0=`:)AV`!``#S
-MPV9F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL)"!(B=6)\$R++T"`_@,/
-MAHD```!(C1S%`````('C^`<``$V-I!T``@``0<<$)`P!``"_$"<``.@`````
-M28V<'00"```/ME4#P>(8#[9%`L'@$`G"#[9%``G"#[9%`<'@"`G"B1-!QP0D
-M$`$``+\0)P``Z``````/ME4'P>(8#[9%!L'@$`G"#[9%!`G"#[9%!<'@"`G"
-MB1/IA````$B-',4`````@>/X!P``3HVD*P`"``!!QP0D#`$``+\0)P``Z```
-M``!*C9PK!`(```^V50/!XA@/MD4"P>`0"<(/MD4`"<(/MD4!P>`("<*)$T''
-M!"00`0``OQ`G``#H``````^V50?!XA@/MD4&P>`0"<(/MD4$"<(/MD4%P>`(
-M"<*)$TB+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-(@^P82(E<)`A,B60D$$F)
-M_$`/MMZ)WN@`````OQ`G``#H`````(G>3(GGZ`````!(BUPD"$R+9"002(/$
-M&,.005=!5D%505154TB#[%A)B?^(5"172(L7@'\^``^$/`(``$&\`````$&]
-MX/___T&^\/___T`/ML9(B40D2$B-@H`!``!(B40D0$B-BH0!``!(B4PD.$B-
-M@J`!``!(B40D,$B-BJ0!``!(B4PD*$B-@E`"``!(B40D($B-BE0"``!(B4PD
-M&$B-@N`!``!(B40D$$B!PM`!``!(B50D"&9FD$B+1"1(1(GA2-/XJ`$/A(T!
-M``!$B>6#_0-V%T2)ZD@#5"0HBP*)!0````"#X/Z)`NL;C13M`````(G22`-4
-M)#B+`HD%`````(/@_HD"OQ`G``#H`````(!\)%<`='*#_0-V%T2)\D@#5"00
-MBP*)!0````"#R`*)`NL;C12M`````(G22`-4)`B+`HD%`````(/(`HD"1(GP
-M2(M,)!!(`<&-!*T`````B<!(BU0D"$@!PH/]`W8*BP&)!0````#K"(L"B04`
-M````J`)T=.OC9I"#_0-V+T2)ZTB+1"0@2`'8QP``````OQ`G``#H`````$@#
-M7"08BP.)!0````"#R`&)`^M!C1SM`````(G;2(M$)"!(`=C'``````"_$"<`
-M`.@`````2`-<)!B+`XD%`````(/(`8D#ZS=F9F:09F:0@_T#=BM$B>I(BT0D
-M,$@!T,<``0```$@#5"0HBP*)!0````"#R`&)`NLV9F:09F:0C03M`````(G`
-M2(M4)$!(`<+'`@$```!(`T0D.(L0B14`````@\H!B1!F9F:09F:008U4)`%)
-M@\0!08/%"$&#Q@1!#[9'/CG0#X="_O__2(/$6%M=05Q!74%>05_#9F:055-(
-M@^P(B=%(BR^#_@-V((T$]>#___^)P$B-E`6@`0``BP*)!0````"#X/Z)`NL>
-MC03U`````(G`2(V4!8`!``"+`HD%`````(/@_HD"A,ET?H/^`W8@C02U\/__
-M_XG`2(V4!>`!``"+`HD%`````(/(`HD"ZQZ-!+4`````B<!(C90%T`$``(L"
-MB04`````@\@"B0*-%+4`````C4+PB<!(C8P%X`$``(G22(V4%=`!``"#_@-V
-M"HL!B04`````ZPB+`HD%`````*@"='7KXX/^`W8XC1SUX/___XG;2(V$*U`"
-M``#'``````"_$"<``.@`````2(V<*U0"``"+`XD%`````(/(`8D#ZS:-'/4`
-M````B=M(C80K4`(``,<``````+\0)P``Z`````!(C9PK5`(``(L#B04`````
-M@\@!B0-(@\0(6UW#D)"0D)"02(GY2(L_#[>!N!(``(/``6:)@;@2``!F.X&\
-M$@``<@EFQX&X$@`````/MX&X$@``2,'@`D@#@7`1``"+%HD0#[>!N!(``(F'
-M+`$``,-F9I!!B="X`````,8$"`!(@\`!2(/X!'7RB?)F@>+_#P^W`68E`/`)
-MT&:)`0^V5PW!X@R+`27_#_#_"=")`0^V1PJ#X`)(@_@!&=*#X@*#P@'!X@4/
-MMD$#@^`?"="#R!"#X/>(00/V1PH!=!=$B<*#XG_!X@0/MT$"9B4/^`G09HE!
-M`O/#9F9FD&9F9I!F9I!F9I"X`````,8$,`!(@\`!2(/X#77R#[9'.8@&#[9'
-M.HA&`0^V1SN(1@(/MD<\B$8##[9'/8A&!`^V1SZ(1@4/MD<_B$8&]H>6````
-M!'0C#[9'0(A&"`^V1T&(1@D/MD="B$8*#[9'0XA&"P^V1T2(1@RX`0```,-F
-M9F:09F9FD&9FD+H`````0;H`````0;G_____ZU(!TD2)P-/XJ`%T$O?"````
-M`74:@?)W)]L`ZQ)FD(G0-7<GVP#WP@````$/1="#Z0%$.<EURTF#P@%)@_H(
-M=1.)T,'H$(@'B=#!Z`B(1P&(5P+#10^V!#*Y!P```.NB9F9FD&9F9I!F9F:0
-M9F:02(N'$!$``(L0BU`$BU`(BT`,B04`````PV9F9I!F9I!(@^P(2(N&B```
-M`$0/MD=#183`="(/ME`-N0````#VP@%T#.L22(G02-/XJ`%U"(/!`40XP77N
-MQD9"#.@`````2(/$",-F9F:09F9FD&9FD$B#[`A(B?A(BS]FQT!.`0#&0$(=
-M2(G&Z`````!(@\0(PV9F9I!F9F:09F9FD&9FD$B#[`A(BS\/M_9(P>8#2`.W
-MN`D``$B+-DB%]G0]2(L7#[=&,F;!Z`4/M\"-!(4``P``B8)P`0``2(L7#[=.
-M,H/A'[@!````2-/@B8)T`0``N@````#H`````$B#Q`C#D$%7059!54%455-(
-M@^P(2(G]28GV@']#`'0EN0````#V1@T!=`[K&$$/MD8-2-/XJ`%U#(/!`0^V
-M14-F.<AWZ$F+1D!(A<!T'$B-L)````!(BWTHZ`````!)BW9`2(GOZ`````!)
-MC49@23E&8`^$7`$``$F)QTR)_^@`````2(G#2(-X0``/A"D!``"`N(,`````
-M#X2B````9H-]=``/A)<```!!O0````!!O`````"02(N%N`D``$P!X$B+,$B%
-M]G1C#[=&(&8[0SAU668]A0!W4P^WP("\!6@(``#_=$9(BU4`#[=&,F;!Z`4/
-MM\"-!(4``P``B8)P`0``2(M5``^W3C*#X1^X`0```$C3X(F"=`$``,9&)"&Z
-M`````$B)[^@`````08/%`4F#Q`@/MT5T1#GH#X]V____2(M#0$C'0&``````
-M]D-,!'492(GOZ`````!(BW-`N@$```!(B>_H`````$B+0T`/ME`"#[9P`4C'
-MQP````"X`````.@`````2(M30$B+M?@(``"_`0```.@`````2(M30$B+M?@(
-M``"_!@```.@`````2,=#0`````!!@&X.`4B)WDB)[^@`````33E^8`^%I_[_
-M_TG'1D``````2(M%`(N(6`$``(D-`````(7)=`I(BT4`B8A8`0``2(/$"%M=
-M05Q!74%>05_#9F9FD&9FD&9FD&9FD$B#[`A,BP=!#[9P0T"$]G0U28V`P!(`
-M`+D`````2#GX=1KK(@^VP4B-%$!(C12028V4T,`2``!(.?IT#X/!`4`X\77@
-MZP6Y``````^VP4B-%$!(C1202(T$U0````!)B[0`T!(``$B%]G1]]D8*`G1W
-M28V$`,`2``!(.48@=6D/MD98A,!T"(/``8A&6.M92(M62$B#ZCA(C4Y(2(U"
-M.$@YR'1$2(-Z$`!U+.L*9F:02(-Z$`!U(,9&6`$/MHJ[````28NXN!```$G'
-MP`````#H`````.L12(M2.$B#ZCA(C4(X2#G(=<A(@\0(PV9FD$B#["A(B5PD
-M"$B);"003(ED)!A,B6PD($B)^TB)]4B+1G!,BV@H#[=.(&:!^84`=W\/M\$/
-MMH0':`@``#S_='!F@_E_=R$/MM!(BX]`"0``2(T$4DB-!()(P>`%2(M$"%`/
-MMD`(ZTYF@?F!`'<<#[;`2(N7D`D``$AIP,@/``!(BT00"`^V0`CK*P^VP$B+
-MEV@)``!(C03`2,'@!4B+A!"(````#[9`".L+9F:09F:0N/\```!(F$0/MJ0#
-M[@@``$B+=7A(A?9T"$B)W^@`````2(GN2(G?Z`````!!#[;$2(T\@$B-/+A(
-MC;S[R`$``$R)[D'_E:````!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9F
-MD&9FD&9FD&9FD$%455-(B?5(B=-F@7XXX0%U$0^V1CJ#Z!%!O``````\`78T
-M2(LW2(N^0`D```^W12"Z8)X!`&8]A0!W%P^WP`^VA`9H"```2(T40$B-%)!(
-MP>(%3(TD%\9#!`6`8P7^@"/?N`````!F@7TXX0%U$0^V13J#Z`$\`0^6P`^V
-MP&:0P>`'#[83@^)_"<*($P^VA98```"#X`'!X`:#XK\)PH@3]H66`````70.
-M3(GGZ`````!FB4,(ZP1FB4L(#[=#"(A%)6:!?3CA`74E#[95.HU"_SP!=PH/
-MME4[@^(/ZRJ0C4+ON@\````\`78=9F9FD+H`````28-\)&``=`Q!#[:4)($`
-M``"#X@\/M@.#X/`)T(@#6UU!7,-F9F:09F9FD$B#[#A(B5PD"$B);"003(ED
-M)!A,B6PD($R)="0H3(E\)#!)B?Q(B?-)B=</MD8X/`AT#SPH=`L\J'0'/(AF
-M9I!U#H.+E`````KK)69FD&:0/`IT#CPJ=`H\JG0&/(IFD'4.@XN4`````F9F
-M9I!F9I`/MWLX9H'_X0%U'`^V0SJ#Z!$\`7<1@XN4````"+@`````Z4D%``!$
-MBT,X08'@____`$&!^.$!$``/A>8````/MTL@9H'YA0`/A_($```/M\%!#[:\
-M!&@(``")^$"`__]T;F:#^7]W(T`/MM=)BXPD0`D``$B-!%)(C02"2,'@!4B+
-M1`A0#[9`".M%9H'Y@0!W'D`/ML=)BY0DD`D``$AIP,@/``!(BT00"`^V0`CK
-M($`/ML=)BY0D:`D``$B-!,!(P>`%2(N$$(@````/MD`(#[;`00^VA`3N"```
-M2(T4@$B-%)!)C;34R`$``$F+E"20"0``0`^VQTAIP,@/``!!O0````#V1`)=
-M$`^%8`(``,9#)`1!QP<`````N`$```#I2P0```^W4R"Y_P```+C_____9H'Z
-MA0`/AXL````/M\)!#[:T!&@(``")\$"`_O]T<V:#^G]W*$`/MM9)BXPD0`D`
-M`$B-!%)(C02"2,'@!4B+1`A0#[9`".M*9F:09I!F@?J!`'<>0`^VQDF+E"20
-M"0``2&G`R`\``$B+1!`(#[9`".L@0`^VQDF+E"1H"0``2(T$P$C!X`5(BX00
-MB`````^V0`A`#[;.1`^V\$ECQD$/MJP$[@@``$B-1*T`2(U$A0!)C;3$R`$`
-M``^WP4B-%$!(C1202,'B!4F)U4T#K"1`"0``9H'_X0%U"P^V0SJ#Z`$\`78I
-M9H'Y_P!T!T'V14L$=1O&0R0&0<<'`````+@!````Z38#``!F9I!F9I!!#[95
-M2(G1@^$!="3VP@1T'T$/MD0D1$$Z1"1.<A)!QP<!````N`$```#I`0,``)!-
-MA>T/A/<```"%R0^$[P```/;"!`^$Y@```$B)WDR)[^@`````A,!U%<9#)`1!
-MQP<`````N`$```#IP@(``$&`O8,````?=A%!QP<!````N`$```#IIP(``/:#
-ME@````%T%TB-1*T`2(U$A0!!]H3$U`$```%T&^M?2(U$K0!(C42%`$'VA,34
-M`0```0^$OP$``$2)]DR)Y^@`````A,!T$4''!P$```"X`0```.E.`@``]H.6
-M`````0^$D@$``$B-1*T`2(U$A0!!]H3$U`$```$/A'D!``!,B>_H`````&:#
-M^!\/AF<!``!!QP<!````N`$```#I!0(``&9FD&:0]D8*`G0R08'XX0$0`&9F
-MD`^$.P$``$$/MH6#````03J%@@```'(>0<<'`0```+@!````Z<@!``!!@?CA
-M`1``#X0,`0``00^W16J`>SCA#X7]````@'LY`0^%\P```$C1Z$B)PH/B`0^V
-M0SJ#Z`8\"0^'Q@````^VP/\DQ0````!!N`$```"Y`0```$B)VDR)[DR)Y^@`
-M````A,`/A;````!!QP<"````N`$```#I3@$``$&X`0```+D`````2(G:3(GN
-M3(GGZ`````"$P`^%?@```$''!P(```"X`0```.D<`0``#[;*0;@!````2(G:
-M3(GN3(GGZ`````"$P'520<<'`@```+@!````Z?`````/MLI!N`````!(B=I,
-MB>Y,B>?H`````(3`=29!QP<"````N`$```#IQ````,9#)`1!QP<`````N`$`
-M``#IKP```$F-O"2H#P``Z`````"$P'010<<'`0```+@!````Z8T```"`>SCA
-M=4Z`>SD!9F:0=46`>SH/=3^`>ST!9F9FD'4U#[9S/,'F"`^V0SL!Q@^W]DR)
-MY^@`````2#M#:'4%2(7`=1+&0R0$0<<'`````+@!````ZSFX`````.LR9I!!
-M#[:$).T)``!(C12`2(T4D$F-M-3(`0``28N4))`)``"X.+@/`.F4^___9F:0
-M9I!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(@\0XPV9F9I!F9I!F
-M9I!F9I!(@^P(2(L_Z`````!(@\0(PV9F9I!F9F:09F9FD&9FD$%7059!54%4
-M55-(@^Q828G]2(GU2(N?0!$``&;'1C+_#TB-5"0LZ`````"$P'0)BT0D+.D.
-M"P``BT4X)?___P`]X0$0``^%Y0```+^($P``Z``````/MTT@9H'YA0`/A[D*
-M```/M\%!#[:T!6@(``")\$"`_O]T:V:#^7]W(D`/MM9)BXU`"0``2(T$4DB-
-M!()(P>`%2(M$"%`/MD`(ZT-F@?F!`'<=0`^VQDF+E9`)``!(:<#(#P``2(M$
-M$`@/MD`(ZQ]`#[;&28N5:`D``$B-!,!(P>`%2(N$$(@````/MD`(#[;`00^V
-MA`7N"```2(T4@$B-%)!-C;35R`$``$F+E9`)``!`#[;&2&G`R`\``$@!PDB)
-M5"002,=$)`@`````2,=$)!@`````Z7(!```/MU4@OO\```!F@?J%`'<,#[?"
-M00^VM`5H"```#[=].&:!_^$!=0\/MD4Z@^@1/`$/AL8```!F@?J%`'=Z#[?"
-M00^VA`5H"```//]T:F:#^G]W(0^VT$F+C4`)``!(C0122(T$@DC!X`5(BT0(
-M4`^V0`CK2&:!^H$`=QP/ML!)BY60"0``2&G`R`\``$B+1!`(#[9`".LE#[;`
-M28N5:`D``$B-!,!(P>`%2(N$$(@````/MD`(ZP6X_____P^VP$$/MH0%[@@`
-M`$B-%(!(C12038VTU<@!```/M\9(C11`2(T4D$C!X@5)`Y5`"0``2(E4)`AF
-M@?_A`75&ZS(/M\9(C03`2,'@!4D#A6@)``!(B40D&$R+L(@```!(QT0D"```
-M``!(QT0D$`````#K1`^V53J-0N\\`78GC4+_/`%V(&:!_O\`=`M(BT0D"/9`
-M2P1U#L9%)`:X`````.FV"```2,=$)!``````2,=$)!@`````2(UT)$A,B>_H
-M`````$&)QV:)13),B>_H`````$F)Q+@"````387D#X1W"```3(FE@````$$/
-MM]=(B10D2&G"L`0``$B-'!A(C4,@22N%0!$``$D#A4@1``!(BU0D2(E"($C!
-MZ"!(BU0D2(E")$F+1"082(M4)$B)0BA(P>@@2(M4)$B)0BQ(BT0D2&9$B7@(
-MN`````#&!!@`2(/``4@]L`0``'7P9H%]..$!=50/MD4Z@^@1/`%W24B-3"0P
-M2(M$)$@/ME`(2(GN2(M\)`CH`````$B-@R`$``!)*X5`$0``20.%2!$``$B+
-M5"1(B4(02,'H($B+5"1(B4(4Z14!``!!#[96"O;"`74LBT4X)?___P`]X0$0
-M``^$G````$B+3"0(#[9!2*@!#X2+````J`0/A(,```#VA98````@=`](C70D
-M,$B)[^@`````ZQM(C4PD,$B+1"1(#[90"$B)[DB+?"0(Z`````!(C8,@!```
-M22N%0!$``$D#A4@1``!(BU0D2(E"$$C!Z"!(BU0D2(E"%$B)V$DKA4`1``!)
-M`X5($0``2(M4)$B)0AA(P>@@2(M4)$B)0ASK7/;"`G172(G822N%0!$``$D#
-MA4@1``!(BU0D2(E"&$C!Z"!(BU0D2(E"'$B-@R`$``!)*X5`$0``20.%2!$`
-M`$B+5"1(B4(02,'H($B+5"1(B4(42(M$)$B`2`$"#[9564B+1"1(9HE0`H!]
-M60!T,[\`````B?A(C01`2,'@`DF+="002(M-8$B+%`A(B10&BU0("(E4!@B#
-MQP$/MD59.?AWTHM5-$B+1"1(B5`,9H%]..$!=3\/MD4Z@^@1/`%W-$$/M\](
-MBU0D2$B)[DR)]^@`````2(U,)#!(B=I(B>Y,B??H`````$&`9@S^Z8L$``!F
-M9I!!#[9&"J@"#X0B!```2(M$)$C&0`;^2(M$)$B`8`?^2(-\)`@`#X2X````
-M2(M$)`@/ME!(2(G0@^`&2(/X!@^%GP```/;"`0^$E@```$$/M\](BU0D2$B)
-M[DR)]^@`````]H66`````7002(M$)$@/MT`(P>`#B$0D,4B-3"0P2(G:2(GN
-M3(GWZ`````#VA98````!=`=!@$X,`>L%08!F#/[&`Z%(BU0D"`^V@NH```"#
-MX`\/ME,!@^+P"<*(4P%(BTPD"`^W03B#P`%FP<`(9HE#`DF)S$F!Q-0```#I
-M/0,``&:!?3CA`0^%)`(```^V13H\#W030;P`````/!`/A1L#``#IK@````^V
-M53S!X@@/MD4[`<)(BT0D2,9`!`U(BT0D2(!@!?Z`3"1#"$B+="1(#[9%)4$/
-MMHWZ````T^!F"48(2(M,)$@/MD$!@^`?@\@@B$$!2(M%/DB)@S@$``!FP<((
-M9HF31`0```^V13V(@T($``#&`Y%(BU0D"`^W0CB#P`%FP<`(9HE#`DB+3"0(
-M#[:1Z@```(/B#P^V0P&#X/`)T(A#`4F)S$F!Q-0```#I:`(``$B+5"1(#[9%
-M)4$/MHWZ````T^!F"4((Q@.!9L=#`O__2(M$)!`/MI"[````@^(/#[9#`8/@
-M\`G0B$,!2(-]2`!U#L9%)"&X`````.GN`P``]D4[`70I3(ME4$V%Y'0@28N]
-MN!```$R)YN@`````@^`/#[93`8/B\`G"B%,!ZP5,BV0D$$B+54@/MD(!OA``
-M```\@`^$A@```#R`=Q\\%7<2/!!F9I!FD'-G@^@"/`%W1.M7/!=F9I!W.^M>
-M/(5T+CR%9F:09F:0=Q`\@71#/()U(V9FD&9FD.LB/)!R%[XH````/))F9I!V
-M-3R3=0>^C````.LJO@0```#K(P^V0@2--(4(````D.L5O@@```#K#KX,````
-M9I#K!;X<````B?+!Z@)(BT0D2(A0!$B+3"1(9L'J"(/B`0^V006#X/X)T(A!
-M!4B-NR`$``")\DB+=4CH`````.D-`0``#[9%.(/H!#RK=T`/ML#_),4`````
-M#[9%0,'@"`^V54&-#!"#^0UW&+@!````2-/@J=@^``!T"4B+1"1(@$@!!$B+
-M1"1(@$@!`>L)2(M$)$B`8`'[2(M$)$C&0`0-2(M$)$B`8`7^2(M4)$@/MD4E
-M00^VC?H```#3X&8)0@A(BT0D2(!@`1_&@R`$```&3(MD)`A)@<34````2(V[
-M(00``$R)YN@`````2(V[)00``$R)YN@`````2(M%.$B)@T0$``!(BT5`2(F#
-M3`0``$B+5"0(2(N"W````$B)@S@$``#&`Y%(BTPD"`^VD>H```"#X@\/MD,!
-M@^#P"="(0P$/MT$X@\`!9L'`"&:)0P)-A>1T8TF+!"1(B4,$ZUFH`71500^W
-MSTB+5"1(2(GN3(GWZ`````#VA98````!=!!(BT0D2`^W0`C!X`.(1"0Q2(U,
-M)#!(B=I(B>Y,B??H`````/:%E@````%T!T&`3@P!ZP5!@&8,_DF+A;@)``!(
-MBQ0D2(DLT$2)^F;!Z@5%#[?G@>+_!P``1(GA@^$?N`$```!(T^!!"825P`D`
-M`(M%."7___\`/>$!$`!U*4B-3"1`N@````!$B>9,B??H``````^V1"1#@^`?
-M@\A`B$0D0^FD````9H%]..$!=3,/MD4Z@^@1/`%W*$B+="083(GOZ`````!(
-MC4PD0$B+1"08#[904$2)YDR)]^@`````ZVE(BW0D"$R)[^@`````2(U,)$!(
-MBT0D"`^V4')$B>9,B??H`````$B+3"0(#[912$B)T(/@!DB#^`9U+O;"`70I
-M#[9$)$.#X!^#R&"(1"1##[91<H/B?\'B!`^W1"1"9B4/^`G09HE$)$)(C70D
-M0$R)[^@`````2(MS(+@#````2(7V=$%(Q\<`````N`````#H`````+@#````
-MZRE!#[:%[0D``$B-%(!(C12038VTU<@!``!)BY60"0``N#BX#P#IR_7__TB#
-MQ%A;74%<05U!7D%?PV9F9I!F9F:09F:0055!5%532(/L"$B)_4&]`````$R-
-MIP`!``#IN0$``)!,B>?H`````$B)PTB#>'``=39(B>_H`````$B)0W!(A<!U
-M)4B-E0`!``!(BX4``0``2(E8"$B)`TB)4PA(B9T``0``Z9T!``"+0S@E____
-M`#WA`1``#X3=````#[=#(&8]@``/A,\````/MLAFB4L@9H/Y?W8:9H%[..$!
-M=2D/MD,Z@^@1/`%W'F9F9I!F9I!F@?F%`'<0#[?!#[:4!6@(``"`^O]U&<9#
-M)`9(B=Y(B>_H`````.G]````9F:09I`/MW,X9H'^X0%U%0^V>SJ-1^\\`0^'
-M[0```.L?9F9FD`^VPDB-%$!(C1202,'B!4F)U4P#K4`)``#K!XU'_SP!=C9F
-M@?F``'0O9H'^X0%FD'4+#[9#.H/H$3P!=AM!]D5+!'44QD,D!DB)WDB)[^@`
-M````Z8````!(B=Y(B>_H`````(/X`G<*@_@!<R5F9I#K$(/X`W5A9F:09F:0
-M9F:0ZTM(B=Y(B>_H`````&9FD.M&2(.[@`````!T#TB-LX````!(B>_H````
-M`$B-E0`!``!(BX4``0``2(E8"$B)`TB)4PA(B9T``0``ZSA(B=Y(B>_H````
-M`$PYI0`!```/A3O^___K'@^VPDB-%$!(C1202,'B!4F)U4P#K4`)``#I%O__
-M_TB#Q`A;74%<05W#2(/L2$B)7"082(EL)"!,B60D*$R);"0P3(ET)#A,B7PD
-M0$B)]4F)_4R+9U!-BS0D00^V1"0,J!!T#,:'Z`````;IC`(```^VE^@```"`
-M^@$/A((```"`^@%R&H#Z!`^$HP```(#Z!@^%S0(``&9FD.E=`@``QH?H````
-M`4B)_DR)]^@`````QD4D@4&`3"0,"$B#O8``````=`](C;6`````3(GWZ```
-M``!)BX8``0``2(EH"$B)10!)C88``0``2(E%"$F)K@`!``!,B??H`````.EB
-M`@``@^#W08A$)`R`A^L````!QH?H`````,9&)`),B??H`````$R)]^@`````
-MZ3,"``#&A^L`````2(.^@`````!T#TB-MH````!,B??H`````$F+34!(A<D/
-MA)X!``"+402-0@&)002#^B@/AXP!``!)BX8``0``2(EH"$B)10!)C88``0``
-M2(E%"$F)K@`!``!!@'U*_W0D28M%8$B%P'0&@'A"`'053(GJO@(```!,B>?H
-M`````.FH`0``00^V1"0,@^#W@\@008A$)`Q)BW582(7V=11!@'PD#@!U+.GE
-M````9F9FD&9FD$$/MI6!````0;@`````N0(```!,B>?H`````.E:`0``0;\`
-M````QD0D%P!)C40D8$B)1"0(2(M\)`CH`````$B)Q4F+1"1H28EL)&A(BU0D
-M"$B)50!(B44(2(DH2(M50$B%TG0528NV^`@``+\%````Z`````"`34P"2(GJ
-MO@8```!,B>?H`````("]@P````!T-D&-7P%!@?]_EI@`=R9,B??H`````+\!
-M````Z`````"`O8,`````=`N#PP&!^X&6F`!UVD&)WX!$)!<!#[9$)!=!.$0D
-M#@^'5____TF+?6!(A?]U'$'&14H#9D''A<@``````$R)[DR)]^@`````ZW?H
-M`````&9F9I!F9F:0ZVA!#[9=2DC'QP````"X`````.@`````08!D)`SO28N&
-M``$``$B):`A(B44`28V&``$``$B)10A)B:X``0``3(GJO@8```!,B>?H````
-M`(#[_W4.3(GJ3(GF3(GWZ`````!,B??H`````$B+7"082(ML)"!,BV0D*$R+
-M;"0P3(MT)#A,BWPD0$B#Q$C#9F:005=!5D%505154TB#["A(B?U)B?5(BX]`
-M"0``N&">`0!F@7X@A0!W&P^W1B`/MH0':`@``$B-%$!(C1202(G02,'@!4R-
-M)`%(BY40$0``2('"0`@``$$/MD0D<L'@"$B82`'"BS*)-0````!!B?=!P>\0
-M2(N5$!$``$B!PD`(``!!#[9$)'+!X`A(F$@!PHM"!(D%`````(A$)!")PL'J
-M"(A4)!'!Z!"(1"022(N5$!$``$B!PD`(``!!#[9$)'+!X`A(F$@!PHM""(D%
-M`````(A$)!.)PL'J"(A4)!3!Z!"(1"05QD0D%@#&1"07`(M,)!!!B?9!P>X8
-M00^VWT2+1"041(GRB=Y(Q\<`````N`````#H`````(G8@_`!B<*#X@%T%$6$
-M_W0/0<9%)`"X`````.FH`@``08!])(%F9I!U(4B-3"001(GRB=Y,B>_H````
-M`$'&120"N`````#I?0(``$&+13@E____`#WA`0X`=0]!QD4D(;@`````Z5X"
-M``!!]H66`````74HA-)U)$&`?"1*_W0<2(U,)!!$B?*)WDR)[^@`````N```
-M``#I+`(``$R)YDB)[^@`````3(GF2(GOZ`````!(BU4`00^W13)FP>@%#[?`
-MC02%``,``(F"<`$``$B+10!!#[=-,H/A'[H!````2(G32-/CB9AT`0``00^W
-M13)(P>`#2`.%N`D``$C'``````!!#[=-,HG(9L'H!27_!P``@^$?2(G62-/F
-M2(GQ]]$AC(7`"0``00^W33*)R&;!Z`4E_P<``(/A'TC3XO?2(52%>$F+50!)
-MBT4(2(E""$B)$$$/MW4R2(V]J`\``.@`````08"L)(,````!0<9%)(%)@[V`
-M`````'0/28VU@````$B)[^@`````28U$)"!).40D(`^$"0$``$F)QDB-A:@/
-M``!(B40D"$R-O0`!``!F9F:09F:03(GWZ`````!(B<-(BU4`#[=`,F;!Z`4/
-MM\"-!(4``P``B8)P`0``2(M%``^W2S*#X1^Z`0```$B)UDC3YHFP=`$```^W
-M0S)(P>`#2`.%N`D``$C'```````/MTLRB<AFP>@%)?\'``"#X1](B=9(T^9(
-MB?'WT2&,A<`)```/MTLRB<AFP>@%)?\'``"#X1](T^+WTB%4A7@/MW,R2(M\
-M)`CH`````$&`K"2#`````4B#NX``````=`](C;.`````2(GOZ`````!(BX4`
-M`0``2(E8"$B)`TR)>PA(B9T``0``33ET)"`/A13___]!@:64````___^_T'&
-MA"3H````!$R)[DR)Y^@`````N`$```!(@\0H6UU!7$%=05Y!7\.02(/L6$B)
-M7"0H2(EL)#!,B60D.$R);"1`3(ET)$A,B7PD4$B)5"002(LO3(N%0!$``$B%
-MT@^$Q@(```^WUDAIPK`$``!*C0P`]D$A`G082(T$U0````!(`X6X"0``2(L`
-MQD`D`NL62(T$U0````!(`X6X"0``2(L`QD`D(4R-%-4`````2(N%N`D``$P!
-MT$B+$(M"."7___\`/>$!$``/A+`!```/MT(@9CV%`'<2#[?`#[:$!6@(```\
-M_W499F:03(G02`.%N`D``$B+`,9`)`;IR@@```^VP$B-%$!(C1202,'B!4R+
-MG4`)``!)`=.`?"03`'EN00^V4TA(B="#X`9(@_@&=2/VP@%T'DB+10"+D%@!
-M``")%0````"%TG0*2(M%`(F06`$``$B+10"+@%`!``")!0````"#R`)(BU4`
-MB8)0`0``2(M%`(N`!`$``(D%`````(#,_TB+50")@@0!``!F]T$@`@@/A.H`
-M``"`?4,`#X3@````NP````!!N0````!%B<A!#[;)#[9'#4C3^*@!=&!!@/D#
-M=B=(BT4`2`70`0``C12-`````$ACTD@!T(L`B04`````P>@4@^`!ZR5(BT4`
-M2`70`0``C12-`````$ACTD@!T(L`B04`````P>@4@^`!A,!T"K@!````2-/@
-M"<-!@\$!08U``3A%0W>!A-MT4CA?#75-B?!FP>@%)?\'``"+1(5XB?&#X1](
-MT_BH`74R08"[Z`````)W"$'&@^@````#3(G02`.%N`D``$B+,$R)W^@`````
-MZ4P'``!!NP````#V1"03`0^$.P<``$R)T$@#A;@)``!(BS#&1B0ABT8X)?__
-M_P`]X0$.``^$%P<``$B+E1`1``!(@<)`"```00^V0W+!X`A(F$@!PHL"B04`
-M````2(N5$!$``$B!PD0(``!!#[9#<L'@"$B82`'"BP*)!0````!(BY40$0``
-M2('"2`@``$$/MD-RP>`(2)A(`<*+`HD%`````$B)[^@`````Z:$&``"0#[?V
-M2(T<]0````!(BX6X"0``2`'82(L09H%Z..$!#X4,`0``#[9Z.D"`_Q`/AVX&
-M``"X`0```(GY2-/@J<`P```/A<P```"I```!`'54]L2`#X1)!@``2&G&L`0`
-M`$J-#``/MD$SB$(D2(G82`.%N`D``$B+`/9`(P0/A"`&``"`>"0`#X06!@``
-M2(M04$B%T@^$"08```^V03.(`NG^!0``2&G&L`0``$J-#`!,C6$H2(G82`.%
-MN`D``$B+$$$/MD0D`HA")$B)V$@#A;@)``!(BP!(@WA(``^$P04```^VN2$$
-M``#H`````$B)VD@#E;@)``!(BPJ+430YT`]'PHG"2(MY2$R)YN@`````Z8T%
-M``!(B=A(`X6X"0``2(L`QD`D`.EW!0``9F9FD&9FD$B)V$@#A;@)``!,BRA-
-MBWUHN/____]F08%]((4`=QE(B=A(`X6X"0``2(L`#[=`(`^VA`5H"```#[;`
-M2(T40$B-%)!(P>(%3(NE0`D``$D!U$'&A"3H`````$$/ME0D2$B)T(/@!DB#
-M^`8/A9<!``#VP@$/A(X!``!!QD4D`$'VA98````@#X3D!```387_#X3;!```
-M0?:'L0````(/A*$```!!BT4TA<`/A)4```!)B[^@````2(7_=`V)PDF+=4CH
-M`````.M\28-]2`!T=4F#O[@`````=0I)@[_``````'1A38MM2$F+A[@```!(
-MA<!T#4B)PT'VA[$````!="9(B[5("@``N@$```!,B?]!_Y?`````NP````"%
-MP'0'2(N=2`H``$B+>PB+$TR)[N@`````BP-)`<6+0P1(@\,0A<!TXDB+E1`1
-M``!(@<)`"```00^V1"1RP>`(2)A(`<*+`HD%`````(G"P>H008B7FP```,'H
-M&&9!B8>0````2(N5$!$``$B!PD0(``!!#[9$)'+!X`A(F$@!PHL2B14`````
-M#[;"9D&)AY0````/ML9F08F'E@```(G0P>@0#[;`9D&)AY@```#!ZAA!B)>:
-M````2(N5$!$``$B!PDP(``!!#[9$)'+!X`A(F$@!PHL"B04`````#[;`9D&)
-MAY(```#I:0,``$AIQK`$``!.C30`00^V1C.$P`^%T0```$B)V$@#A;@)``!(
-MBP#&0"0`0?:%E@```!`/A#(#``!-A?\/A"D#``!!#[9&,T&(AY(```!!]H>Q
-M`````@^$#P,``$&#?30`#X0$`P``28._N`````!U#DF#O\``````#X3L`@``
-M38ME2$F+A[@```!(A<!T#4B)PT'VA[$````!="9(B[5("@``N@$```!,B?]!
-M_Y?`````NP````"%P'0'2(N=2`H``$B+>PB+$TR)YN@`````BP-)`<2+0P1(
-M@\,0A<`/A8<"``#KW&9FD&:0/`(/A2@"``!!#[9.0$&+1CB)1"0D#[94)"</
-MMD0D),'@&`G"#[9$)"7!X!`)P@^V1"0FP>`(08G400G$@^%_@/EQ=CS&1"0-
-M`$&#_`%V#$$/MD9!@^`/B$0D#<9$)`X`08/\`G8)00^V3D*(3"0.08/\`W9F
-M00^V1D.(1"0/ZV#&1"0-`$&#_`)V#$$/MDY"@^$/B$PD#<9$)`X`QD0D#P!!
-M@_P'=CE!#[9&1X/`"$$YQ$0/1^#&1"0.`$&#_`QV"4$/MD9,B$0D#D&#_`UV
-M"T$/MDY-B$PD#^L%QD0D#P!(B=A(`X6X"0``2(L`@'@P`'1(187D=$/&0"0@
-M2(G82`.%N`D``$B+``^V0#`/MM!$..!$#T+B2(G82`.%N`D``$B+`$B+>%!(
-MA?]T'T2)XDF-=D#H`````.L12(G82`.%N`D``$B+`,9`)"*`?"0-!'412(G8
-M2`.%N`D``$B+`,9`)`)).6TH#X02`0``387_#X0)`0``0?:%E@```!!T0$$/
-MMD8S08B'D@```$'VA[$````"="I!#[9%,$2)XD$XQ`]'T(32=!A)B[^H````
-M2(7_=`P/MM))C79`Z`````"`?"0-"W=<#[9$)`W_),4`````0<:'L@````'I
-MGP```(!\)`X$=12`?"0/`G4-0<:'L@```!'IA````$'&A[(````"ZWI!QH>R
-M````$.MP0<:'L@````OK9D'&A[(````&ZUQ!QH>R````#>M29I`\*'4G00^V
-MA"2#````@^@!08B$)((```!(B=A(`X6X"0``2(L`QD`D@>LE/`AU"K\0)P``
-MZ`````!(B=A(`X6X"0``2(L`QD`D(69FD&9FD$B+7"0H2(ML)#!,BV0D.$R+
-M;"1`3(MT)$A,BWPD4$B#Q%C#9F9FD&9FD&9FD&9FD$%7059!54%455-(@>RH
-M````2(G]2(E\)'`/MX>Z$@``9HF$)(````!(BP>+@$`!``")!0````!F)?\/
-M9HF'NA(``&8[A"2`````=7%(BP>+L%`!``")-0````!(BP>)L%`!``"X````
-M`/?&`/__``^$!`D``$C'QP````"X`````.@`````2(M\)'#H`````+@!````
-MZ=\(``!F9I!F9I!(BT4`BX!``0``B04`````9B7_#V:)A;H2``#K)$B-EQ`!
-M``!(B50D:$B-CZ@/``!(B4PD8$B-MP`!``!(B70D6$B+A:`1``"+`(D%````
-M``^WC;H2```E_P\```^WT3G0=9UF@?G_#P^%P@<``.G2!P``3(N%0!$``&:#
-MA"2``````0^WA"2`````9CN%OA(``+@`````#[>4)(`````/0]!FB90D@```
-M`$B+E:`1``!(@\($#[>$)(````"+#()!B<E!P>D00?;!"`^$KP```$B+10"+
-MD%`!``")%0````!(BT4`B9!0`0``]\(`__\`=&F`?4,`=&.)UO?&``$``'4N
-MOP````#WQ@```0!T0.L?#[?7C4H(2(GP2-/XJ`%U%(U*$$B)\$C3^*@!=0?K
-M'[\`````#[?'2(T4@$B-%)!(C9S5R`$``$B%VW4=ZPR#QP$/MD5#9CGX=[9(
-MBWPD<.@`````Z<4&``!(BWPD<.@`````B$,/Z;,&``!F9I")SF:!YO\/#[?&
-M2&G0L`0``$V+1!`@2(T\Q0````!(BX6X"0``2`'X2(L82(7;#X5L`0``#[?V
-MB?)(Q\<`````N`````#H`````&:#?70`#X1;!@``QH0DGP````!F9I!$#[:T
-M))\```!.C3SU`````$B+A;@)``!,`?A(BS!(A?8/A/D```!-:>:P!```3`.E
-M0!$``$B+G>`0```/MDXE1`^VK"2?````1(GJ2,?'`````+@`````Z`````!,
-MB?A(`X6X"0``2(LXZ`````!!BXPD)`0``$&+E"0@!```18N,)"P$``!%BX0D
-M*`0``$2)[DC'QP````"X`````.@`````3(GP2,'@!D@!PXM#-(M[,$2+4RQ$
-MBULH1(MC)$2+:R!$BW,<1(M[&(M+%(E,)'Q$BTL01(M##(M+"(M3!(LSB40D
-M0(E\)#A$B50D,$2)7"0H1(ED)"!$B6PD&$2)="001(E\)`B+1"1\B00D2,?'
-M`````+@`````Z`````"`A"2?`````0^VA"2?````9CM%=`^#%@4``.G!_O__
-MD$'VP2`/A(@!``"`>R2!9I`/A5L!``#&0R0A#[=#,DC!X`-(`X6X"0``2,<`
-M``````^W2S*)R&;!Z`4E_P<``(/A'[H!````2(G62-/F2(GQ]]$AC(7`"0``
-M#[=+,HG(9L'H!27_!P``@^$?2-/B]](A5(5X#[=S,DB+?"1@Z`````!(@[N`
-M`````'0/2(VS@````$B)[^@`````#[=3(&:!^H4`#X?'````#[?"#[:$!6@(
-M```\_P^$M````&:#^G]W(P^VP$B-%$!(C1202,'B!4@#E4`)``!(BT)0@'@(
-M_P^5P.M9#[=#(&8]@0!W)@^WP`^VA`5H"```2&G`R`\``$@#A9`)``!(BT`(
-M@'@(_P^5P.LI#[=#(`^VA`5H"```2(T$P$C!X`5(`X5H"0``2(N`B````(!X
-M"/\/E<"$P'0N2(G>2(GOZ`````!(BX4``0``2(E8"$B)`TB+1"182(E#"$B)
-MG0`!``#IGP,``$B+3"1H2(M1"$B-0Q!(B4$(2(E+$$B)4`A(B0+I?@,``(GP
-M9L'H!40/M_!)8\8/M_9!B?=!@^<?BT2%>$2)^4C3^*@!#X55`P``2(GX2`.%
-MN`D``$B+``^W4"!F@?J%``^'N@````^WP@^VA`5H"```//\/A*<```!F@_I_
-M=R`/ML!(C11`2(T4D$C!X@5(`Y5`"0``2(M"4`^V0`CK;4B)^$@#A;@)``!(
-MBP`/MT`@9CV!`'<C#[?`#[:$!6@(``!(:<#(#P``2`.%D`D``$B+0`@/MD`(
-MZS-(B?A(`X6X"0``2(L`#[=`(`^VA`5H"```2(T$P$C!X`5(`X5H"0``2(N`
-MB`````^V0`@\_W00#[;02&/"@+P%[@@``/]U-DECQHM$A7A$B?E(T_BH`0^%
-M:@(``,9#)`9(B=_H`````+H`````2(G>2(GOZ`````#I20(``$ACP@^VA`7N
-M"```2(T4@$B-%)!(C;S5R`$``$V%P'0-0?;!`K@`````3`]$P/9'"@(/A%X!
-M``!,B<+H`````$ECQHM$A7A$B?E(T_BH`0^%]0$``(![)($/A8\````/MT,R
-M2,'@`T@#A;@)``!(QP``````#[=+,HG*9L'J!8'B_P<``(/A'[@!````2-/@
-M]]`AA)7`"0``#[=S,DB+?"1@Z`````!(B=Y(B>_H`````$B#NX``````=`](
-MC;.`````2(GOZ`````!(BX4``0``2(E8"$B)`TB+="182(ES"$B)G0`!``#I
-M7`$``$B+A1`!``!(.T0D:'1?0;P`````08/$`4B+`$@Y1"1H=?)%A.1T1D&]
-M`````$B+?"1HZ`````!(C4CP2(MT)&A(BU8(2(E&"$B),$B)4`A(B0)(.=FX
-M`0```$0/1.A!@.P!=<E%A.T/A>\```!(BT0D:$B+4`A(C4,02(M,)&A(B4$(
-M2(E+$$B)4`A(B0))8]:X`0```$2)^4C3X`F$E;@```#IM````$R)PN@`````
-M2(N%$`$``$@[1"1H=%M!O`````!!@\0!2(L`2#E$)&AU\D6$Y'1"0;T`````
-M2(M\)&CH`````$B-2/!(BW0D:$B+5@A(B48(2(DP2(E0"$B)`D@YV;@!````
-M1`]$Z$&`[`%UR46$[75#@'LD@70]2(M$)&A(BU`(2(U#$$B+3"1H2(E!"$B)
-M2Q!(B5`(2(D"26/6N`$```!$B?E(T^`)A)6X````9F9FD&9FD`^WM"2`````
-M9CFUNA(```^%+OC__V:!O;H2``#_#W0C2(N%H!$``(L`B04`````)?\/```/
-MMY6Z$@``.=`/A<[W__](C840`0``2#F%$`$``'1)2(G#2(G?Z`````!(C7#P
-M#[=.,HG*9L'J!8'B_P<``(/A'[@!````2-/@]]`AA)6X````N@````!(B>_H
-M`````$@YG1`!``!UNDB)[^@`````N`$```!(@<2H````6UU!7$%=05Y!7\-F
-M9I!FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B+G_@(``!(BT,(1(LH1(DM
-M`````$'WQ0```)!T>DB+0PA$B2CK<9!(@<.0%```2(L#BY!0`0``B14`````
-M2(L#B9!0`0``A=)T//?"````$'0<2(L#QX!0`0``````$$B+`XN`4`$``(D%
-M`````$B+`\>`4`$```$```!(B=_H`````$$!Q(/%`8/]`G69ZQ=F9F:09F:0
-M0;P`````O0````#KBF9FD$6$Y`^5P$6%[0^5P@G0#[;`2(M<)`A(BVPD$$R+
-M9"083(ML)"!(@\0HPV9FD&9FD$%7059!54%455-(@^PH28G\2(L'BY!0`0``
-MB14`````2(L'B9!0`0``9F9FD&9FD/?"`/__``^$*`D``$&`?"1#``^$'`D`
-M`,9$)!``B=)(B50D"$0/MFPD$$&-30A(BT0D"$C3^*@!=11!C4T02(M$)`A(
-MT_BH`0^$T0@``(!\)!`#=BM)BP0D2`6``0``0HT4[0````!(8])(`="+`(D%
-M`````,'H$X/@`>LI9F:028L$)$@%@`$``$*-%.T`````2&/22`'0BP")!0``
-M``#!Z!.#X`&$P'0F3(GGZ`````!)8]5(C0122(T$@D&!C,3T$@`````(`&9F
-M9I!F9I!)BQ0D@'PD$`-V)4*-!.T`````2)A(C80"@`$``(L`B04`````)0``
-M`0#K(V9F9I!"C03M`````$B82(V$`H`!``"+`(D%`````"4```$`A<!T08!\
-M)!`#=AU"C03M`````$B82(V$`H`!``#'`````0#I&0@``$*-!.T`````2)A(
-MC80"@`$``,<````!`.G\!P``08!\)%$!#X6H!@``@'PD$`-V*4F+!"1(!8`!
-M``!"C13M`````$ACTD@!T(L`B04`````@^`!ZR=F9F:028L$)$@%@`$``$*-
-M%.T`````2&/22`'0BP")!0````"#X`&$P`^$50$``$ECQ4B-'$!(C1R82,'C
-M`TF-M!SX$@``28M\)"CH`````$F+O!S0$@``2(7_=!U(BT=`2(7`=!3V0$X"
-M=0[H`````(3`D`^%"@$``$ECQ4B-%$!(C12028N$U-`2``!(A<!T=4F)QH!X
-M#@`/A(L```!!OP````!(C6A@2(GOZ`````!(B<-(BT4(2(E="$B)*TB)0PA(
-MB1CV0TP"=2](BU-`2(72=!9)B[0D^`@``+\%````Z`````"`2TP"2(G:O@8`
-M``!,B??H`````$&#QP%%.'X.=B7KH@^V="00N@$```!,B>?H`````+^@A@$`
-MZ`````"Z`"TQ`>L%ND!+3`!)8\5(C0Q`2(T,B$C!X0-*C30AB9;X$@``2,>&
-M"!,````````/MD0D$$B-%$!(C12028V4U,`2``!(B980$P``28VT#/@2``!)
-MBWPD*.@`````9F:0@'PD$`-V/4*-%.T`````2&/228L$)$@%@`$``$@!T(L`
-MB04`````28L$)$@%@`$``$@!PHL"B04`````P>@'@^`!ZSM"C13M`````$AC
-MTDF+!"1(!8`!``!(`="+`(D%`````$F+!"1(!8`!``!(`<*+`HD%`````,'H
-M!X/@`83`='6`?"00`W8W0HT,[0````!(8\E)BP0D2`6$`0``2`'(BP")!0``
-M``!)BQ0D2('"A`$``$@!T0T```$`B0'K/D*-#.T`````2&/)28L$)$@%A`$`
-M`$@!R(L`B04`````28L4)$B!PH0!``!(`=$-```!`(D!ZR^`?"00`W8H28L$
-M)$@%@`$``$*-%.T`````2&/22`'0BP")!0````#!Z!*#X`'K)DF+!"1(!8`!
-M``!"C13M`````$ACTD@!T(L`B04`````P>@2@^`!A,`/A"("``"`?"00`W8W
-M0HT,[0````!(8\E)BP0D2`6``0``2`'(BP")!0`````-```$`$F+%"1(@<*`
-M`0``2`'1B0'K-4*-#.T`````2&/)28L$)$@%@`$``$@!R(L`B04`````#0``
-M!`!)BQ0D2('"@`$``$@!T8D!26/%2(T40$B-%)!)BX34T!(``$B%P'0328G%
-M2(-X0``/A:(```#IA`$``(!\)!`#=DI"C13M`````$ACTDF+!"1(!8`!``!(
-M`="+"(D-`````$F+!"1(!8`!``!(C00"B0A)BP0D2`6``0``2`'"BP*)!0``
-M``#IT`,``$*-%.T`````2&/228L$)$@%@`$``$@!T(L(B0T`````28L$)$@%
-M@`$``$B-!`*)"$F+!"1(!8`!``!(`<*+`HD%`````.F&`P``9I!(BTA`#[=!
-M3@^WT/;&`0^%TP```$B)S?;"`@^$QP```(/@_6:)04Y(C;'`````28M\)"CH
-M`````,9$)!``@'T[`'1WQD0D$``/MD0D$$B+7,582(7;=%1(BU-`2(72=!9)
-MB[0D^`@``+\%````Z`````"`2TP"2(G:O@8```!,B>_H`````("[@P````!T
-M')!,B>?H`````+\!````Z`````"`NX,`````=>6`1"00`0^V1"00.$4[=X['
-MA<````!`2TP`2,>%T`````````!(B:W8````2(VUP````$F+?"0HZ`````"`
-M?"00`W8R28L$)$@%@`$```^V5"002,'B`X'B^`<``$@!T(L`B04`````P>@(
-M@^`!ZS!F9I!F9I!)BP0D2`6``0``#[94)!!(P>(#@>+X!P``2`'0BP")!0``
-M``#!Z`B#X`&$P`^$%@$``(!\)!`#=BQ)BP0D2`6``0``#[94)!!(P>(#@>+X
-M!P``2`'0BP")!0````"#\`&#X`'K*DF+!"1(!8`!```/ME0D$$C!X@.!XO@'
-M``!(`="+`(D%`````(/P`8/@`83`#X2Q````#[9$)!!(C11`2(T4D$V-O-3`
-M$@``28M'$$B%P`^$CP```$F)QDF-=SA)BWPD*.@`````08!^#@!T54&]````
-M`$F-;F!F9I!FD$B)[^@`````2(G#2(M%"$B)70A(B2M(B4,(2(D82(M30$B%
-MTG0628NT)/@(``"_!0```.@`````@$M,`D&#Q0%%.&X.=[I!QT<X@(0>`$G'
-M1T@`````38E_4$F-=SA)BWPD*.@`````@'PD$`,/AG\````/MEPD$$C!XP.!
-MX_@'``!)BP0D2`6``0``2`'8BQ")%0````!)BP0D2`6``0``2(T$`XD028L$
-M)$@%@`$``$B-!`.+`(D%`````$F+!"1(!3`"``!(C00#QP``````OQ`G``#H
-M`````$F+!"1(!30"``!(`<.+`XD%`````.M]#[9<)!!(P>,#@>/X!P``28L$
-M)$@%@`$``$@!V(L0B14`````28L$)$@%@`$``$B-!`.)$$F+!"1(!8`!``!(
-MC00#BP")!0````!)BP0D2`50`@``2(T$`\<``````+\0)P``Z`````!)BP0D
-M2`54`@``2`'#BP.)!0````"`1"00`0^V1"0003A$)$,/A_#V__])BP0DBY!0
-M`0``B14`````28L$)(F04`$``/?"`/__`'0FZ:7V__]F9I!FD$ECU4B-!%)(
-MC02"08&,Q/02``````$`Z>CW__^X`````$B#Q"A;74%<05U!7D%?PT%7059!
-M54%455-(@^QH28G]0(AT)$M`#[;&B40D3$B82(T40$B-%)!(C1373(NZT!(`
-M``^VJLH2``!(BP=`@/X#=@S'@'`!``#$`0``ZPK'@'`!``"H`0``2(E$)&!(
-M!70!``!(B40D4$B+5"1@BX)T`0``B04`````BTPD3(/A`[L'````T^-!B=Q!
-M"<1$B:)T`0``O^@#``#H`````/?31"'C2(M,)&")F70!``"`?"1+`W95BT0D
-M3,'@`DB82(V4`=`!``"+`HD%`````(/("(D"BUPD3,'C`TACVTB-A!D``@``
-MQP`X````OQ`G``#H`````$B+5"1@2(V$&@0"``#'``````#K6(M$)$S!X`)(
-MF$B+3"1@2(V4`=`!``"+`HD%`````(/("(D"BUPD3,'C`TACVTB-A!D``@``
-MQP`X````OQ`G``#H`````$B+5"1@2(V$&@0"``#'``````!-A?\/A#D(``!!
-M@'U#`'0LNP`````/MLM!#[9'#4C3^*@!=`^Z`0```(G.3(GOZ`````"#PP%!
-M.%U#=]E!]D<*`71J3(G^3(GOZ`````"+="1,3(GOZ`````!(8T0D3$B-%$!(
-MC12028U4U0"+@O`2``"I```0`'0+)?__[_^)@O`2``!,B?Y,B>_H`````$AC
-M1"1,2(T40$B-%)!)QX35T!(```````#IE0<``$&`?U@`=!1)B[VX$```3(G^
-MZ`````!!@&]8`4C'P/[___\/MDPD3$C3P$`@Z(A$)%L/A,`"``"+="1,3(GO
-MZ`````!(8T0D3$B-%$!(C12028U4U0"+@O`2``"I```0`'0+)?__[_^)@O`2
-M```/MD0D6T&(1PU!@'U#``^$[P$``,=$)%P`````#[;02(E4)#!(BTPD8$B!
-MP0`"``!(B4PD*$B+1"1@2`4$`@``2(E$)"`/ME0D6XE4)!Q(BTPD8$B!P=`!
-M``!(B4PD$$0/MG0D7$$/MNY(BT0D,(GI2-/XJ`$/A$T!``!(8\5(C11`2(T4
-MD`^V1"1;08B$U<H2``!!@/X##X:5````C1SM`````$ACVTB+1"0H2`'8QP`X
-M````OQ`G``#H`````$@#7"0@BU0D'(D32(M,)&#'@7`!``#$`0``2(M4)%"+
-M`HD%`````(GI@^$#NP<```#3XT&)W$$)Q$2)(K_H`P``Z`````#WTT0AXTB+
-M3"10B1F-%*T`````2&/22`-4)!"+`HD%`````(/("(D"Z98```"-'.T`````
-M2&/;2(M$)"A(`=C'`#@```"_$"<``.@`````2`-<)""+1"0<B0-(BU0D8,>"
-M<`$``*@!``!(BTPD4(L!B04`````B>F#X0.[!P```-/C08G<00G$2(M$)%!$
-MB2"_Z`,``.@`````]]-!(=Q(BU0D4$2)(HT4K0````!(8])(`U0D$(L"B04`
-M````@\@(B0*#1"1<`4&-1@%!.$5#=BSI@_[__TB)W^@`````2(UPR$B+4PA(
-MB4,(2(D82(E0"$B)`DB#>-@`=!'K";X`````28U?2$DY7TAURDB%]G0XQD9:
-M`$&`?4,`="VY`````+H`````00^V1PU(T_BH`70.#[;"B$P&<(!&6@&#P@&#
-MP0%!.$U#=]VZ`````+Z!````3(G_Z`````!(8T0D3$B-%$!(C1202<>$U=`2
-M````````08!]0P`/A7L#``#IG@0``+H`````O@8```!,B?_H`````(MT)$Q,
-MB>_H`````$AC1"1,2(T40$B-%)!)C535`(N"\!(``*D``!``=`LE___O_XF"
-M\!(``$F-1TA).4=(#X3]`0``2(D$)$B+/"3H`````$R-<,A(C5`02#E0$`^$
-MP`$``$F-1DA(B40D"$B+?"0(Z`````!(C5CP@'M)#7472(VP4`$``$B+0U!(
-MBP!(BW@HZ`````!(BQ-(BT,(2(E""$B)$("[@P````!T&TR)[^@`````OP$`
-M``#H`````("[@P````!UY4B+0T!(A<`/A"D!``!(QT!@`````("[@P`````/
-MA*8```!F08-]=``/A)H```"]`````$&\`````&9FD&:03(G@20.%N`D``$B+
-M,$B%]G1D#[=&(&8[0SAU6F8]A0!W5`^WP$&`O`5H"```_W1&28M5``^W1C)F
-MP>@%#[?`C02%``,``(F"<`$``$F+50`/MTXR@^$?N`$```!(T^")@G0!``#&
-M1B0AN@````!,B>_H`````(/%`4F#Q`A!#[=%=#GH#X]V____]D-,!'493(GO
-MZ`````!(BW-`N@$```!,B>_H`````$B+0T`/ME`"#[9P`4C'QP````"X````
-M`.@`````2(M30$F+M?@(``"_`0```.@`````2(M30$F+M?@(``"_!@```.@`
-M````2,=#0`````!!@&\.`4&`;E@!2(G>3(GOZ`````!(BU0D"$DY5D@/A4G^
-M__]!@&\H`4R)]DR)[^@`````2(L,)$DY3T@/A0?^__])C4=@23E'8`^$[```
-M`+T`````28G$3(GGZ`````!(B<.`N(,`````=#>-10&!_7^6F`!V!(G%ZRB)
-MQ4R)[^@`````OP$```#H`````("[@P````!T"X/%`8']@9:8`'7:2(M#0$B%
-MP'1V2,=`8`````#V0TP$=1E,B>_H`````$B+<T"Z`0```$R)[^@`````2(M#
-M0`^V4`(/MG`!2,?'`````+@`````Z`````!(BU-`28NU^`@``+\!````Z```
-M``!(BU-`28NU^`@``+\&````Z`````!(QT-``````$&`;PX!2(G>3(GOZ```
-M``!-.6=@#X4<____3(G^3(GOZ`````!(8T0D3$B-%$!(C1202<>$U=`2````
-M````Z7K\__]!OP`````/MD0D6TB)1"1`2(M4)&!(@<+0`0``2(E4)#A%B?Y!
-M#[;O2(M$)$")Z4C3^*@!=0M$.'PD2P^%U0```$&`_@-V:$B+1"1@QX!P`0``
-MQ`$``$B+5"10BP*)!0````")Z8/A`XT,2;L'````T^-!B=Q!"<1$B2*_Z`,`
-M`.@`````]]-$(>-(BTPD4(D9C12M`````$ACTD@#5"0XBP*)!0````"#R`B)
-M`NMG2(M$)&#'@'`!``"H`0``2(M4)%"+`HD%`````(GI@^$#C0Q)NP<```#3
-MXT&)W$$)Q$2)(K_H`P``Z`````#WTT$AW$B+3"101(DAC12M`````$ACTD@#
-M5"0XBP*)!0````"#R`B)`D&#QP%!C48!03A%0P^'^?[__TB#Q&A;74%<05U!
-M7D%?PV9F9I!F9F:09F9FD$%455-)B?Q(B?4/MG=#0(3V="8/ME4-NP````#V
-MP@%T#NL62(G0B=E(T_BH`74/@\,!0#CS=>SK!;L`````]D4,`G4*2(U%8$@Y
-M16!U:$B)[^@`````A,!T44R)Y^@`````2(G&2(7`=$Q(BU5H2(E%:$B-16!(
-MB09(B58(2(DR@$4.`4B);E#&1D@%QD9)`,:&@0````^Y`0```+H!````2(GO
-MZ`````#K"P^V\TR)Y^@`````6UU!7,-F9I!FD$%6055!5%532(G]08GU1`^V
-M]D*-!+4`````3&/@NP````"_$"<``.@`````08#]`W8>2(M%`$@%T`$``$P!
-MX(L`B04`````P>@4@^`!ZQV02(M%`$@%T`$``$F-!`2+`(D%`````,'H%(/@
-M`83`=0J#PP%F@?LL`76H1(GV2(GOZ`````!(B>_H`````$ECQDB-%$!(C120
-M2(U$U0#V@,D2```!=`](B[#0$@``2(GOZ`````!;74%<05U!7L-FD$%6055!
-M5%5308GU28G\1`^V]DECQDB-%$!(C1202(NLU]`2``!(A>T/A)8!``!(Q\#^
-M____1(GQ2-/`A$4-#X6``0``2(U%2$@Y14AU%4&]`````$B-76"`?0X`=2/I
-M\P(``$`/ML9(C3Q`2(T\N$F-O/S`$@``Z`````#IU0(``$B)W^@`````2(G!
-M2(M#"$B)2PA(B1E(B4$(2(D(@'E)``^%"0$```^W03A)@[S$:`0```!U"TB#
-M>4``#X39````#[=!.$F+A,1H!```2(.X@``````/A*<```#&@>@`````#[91
-M2$B)T(/@!DB#^`9U+?;"`70HQD%*!<9!2P0/MI&!````2(MQ6$B+>5#H````
-M`.F8````9F9FD&9FD`^V44A(B="#X`9(@_@$=2#VP@%T&\9!2@/&04L$2(G.
-M3(GGZ`````#K9V9FD&9FD`^V44A(B="#X`9(@_@&=5'VP@%U3,9!2P;&04H%
-M9L>!R```````2(G.3(GGZ`````#K+DB+44!)B[0D^`@``+\$````Z`````#K
-M%@^W43A)B[0D^`@``+\"````Z`````!!@\4!1#AM#@^&EP$``.F]_O__0HT$
-MM0````!(8^B[`````+\0)P``Z`````!!@/T#=AU)BP0D2`70`0``2`'HBP")
-M!0````#!Z!2#X`'K&TF+!"1(!=`!``!(`>B+`(D%`````,'H%(/@`83`=0J#
-MPP%F@?LL`76J1(GV3(GGZ`````!,B>?H`````$ECQDB-%$!(C12028NLU-`2
-M``!(A>T/A/T```!!@'PD0P!T++L`````#[;+#[9%#4C3^*@!=`^Z`````(G.
-M3(GGZ`````"#PP%!.%PD0W?900^VQ4B-%$!(C12028V4U,`2``!(B54@2(U%
-M2$@Y14AU.$B-16!(.45@=2[K>V9FD&:02(G?Z`````!(C7#(2(M3"$B)0PA(
-MB1A(B5`(2(D"2(-XV`!T$>L)O@````!(C5U(2#E=2'7*2(7V=%O&1EH`08!\
-M)$,`=$^Y`````+H`````#[9%#4C3^*@!=`X/ML*(3`9P@$9:`8/"`8/!`4$X
-M3"1#=B+KV_9%"@%T#4B)[DR)Y^@`````ZPV^`````$B)[^@`````6UU!7$%=
-M05[#D$B#[`A,BP=$BT\T00^V<$-`A/9T8DF-@,`2``"Y`````$@Y^'4:ZT\/
-MML%(C11`2(T4D$F-E-#`$@``2#GZ=`B#P0%`./%UX(#Y`W8O28L`2`70`0``
-M2(T4C0````"!XOP#``!(`="+`(D%`````,'H%(/@`>LMN0````!)BP!(!=`!
-M``!(C12-`````('B_`,``$@!T(L`B04`````P>@4@^`!A,!T$`^V\42)RDR)
-MQ^@`````ZPL/MO%,B<?H`````$B#Q`C#9F9FD&9F9I!!5T%6055!5%532(/L
-M"$B)\TF)_DR+IX@```!)BRPD0?9$)`P0=`3&1U$&00^V1E$\`71Y/`%R%3P$
-M#X29````/`8/A4@#``#IN@$``$'&1E$!3(GV2(GOZ`````#&0R2!08!,)`P(
-M2(.[@`````!T#TB-LX````!(B>_H`````$B-E0`!``!(BX4``0``2(E8"$B)
-M`TB)4PA(B9T``0``2(GOZ`````#IXP(``$&`9"0,]T&`1E(!0<9&40#&0R0"
-M2(G>2(GOZ`````!(B>_H`````.FW`@``00^V1"0,@^#W@\@008A$)`Q!BY8(
-M`0``C4(!08F&"`$``(/Z`@^'`P$``$B#NX``````=`](C;.`````2(GOZ```
-M``!(C94``0``2(N%``$``$B)6`A(B0-(B5,(2(F=``$``$&`?D(`=1A!OP``
-M``!-C6PD8$&`?"0.`'4>Z9X```"Z`````+X"````3(GGZ`````!FD.D;`@``
-M3(GOZ`````!(B<-)BT4(28E="$R)*TB)0PA(B1A(BU-`2(72=!5(B[7X"```
-MOP4```#H`````(!+3`)(B=J^!@```$R)Y^@`````@+N#`````'0B9F9FD&9F
-MD$B)[^@`````OP$```#H`````("[@P````!UY4&#QP%%.'PD#@^'>____TR)
-M]^@`````Z8D!``!!@&0D#/=!QX8(`0```````$B#NX``````=`](C;.`````
-M2(GOZ`````!(C94``0``2(N%``$``$B)6`A(B0-(B5,(2(F=``$``+H`````
-MO@8```!,B>?H`````$F-1"1@23E$)&!T?$F)Q4R)[^@`````2(G#2(M`0$B%
-MP'132,=`8`````!(B>_H`````$B+<T"Z`0```$B)[^@`````2(M30$B+M?@(
-M``"_`0```.@`````2(M30$B+M?@(``"_!@```.@`````2,=#0`````!(B=Y(
-MB>_H`````$TY;"1@=8=,B?9(B>_H`````$G'1"1``````$B+10"+D%@!``")
-M%0````"%TG0*2(M%`(F06`$``$'V1"0*`71K@'U#`'0LN0````!!]D0D#0%T
-M%>L=9F:09F:000^V1"0-2-/XJ`%U#X/!`3A-0W?KZP6Y``````^VV8G>2(GO
-MZ`````!,B>9(B>_H`````$ACVTB-!%M(C02#2,>$Q=`2````````9F:09I!(
-M@\0(6UU!7$%=05Y!7\.02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@2(GS2(G]
-M3(MO4$V+90`/MTXRB<AFP>@%#[?P2&/&08M$A'B#X1](T_BH`0^%9P,``$F+
-M%"2-!+4``P``B8)P`0``28L$)(N0=`$``(D5`````,9#)"&+0S@E____`#WA
-M`0\`=2-(B=_H`````+H`````2(G>3(GGZ`````#I%@,``&9FD&9FD(G0#[=+
-M,H/A'TC3^*@!=!!(B=_H`````$R)Y^@`````#[:%Z````#P$#X?A`@``#[;`
-M_R3%`````,:%Z`````&Z`0```$B)WDR)[^@`````Z;L"``#&A>@````"N@@`
-M``!(B=Y,B>_H`````.F?`@``QH7H`````TB)ZKXA````3(GOZ`````!(BW58
-M2(7V=!\/MI6!````0;@`````N0$```!,B>_H`````.E@`@``00^V=0VZ````
-M`$R)Y^@`````Z4D"``#&A>@````$2(-]6`!T,TB)ZKXA````3(GOZ``````/
-MMI6!````2(MU6$&X`````+D"````3(GOZ`````#I"`(``+H`````OB$```!,
-MB>_H`````$$/MG4-N@$```!,B>?H`````.G?`0``@'U*_W052(GJO@8```!,
-MB>_H`````.G$`0``2(GJO@8```!,B>_H`````$B+34!(A<ET$HM1!(U"`8E!
-M!(/Z!0^&F0$``,9%2P'&14H`@+V#`````'0;3(GGZ`````"_`0```.@`````
-M@+V#`````'7E2(-]6`!T&4B+51!(BT482(E""$B)$$B+15B`:%@!ZQE(BU5@
-M2(72=!`/MH6!````2,=$PE@`````2(M5`$B+10A(B4((2(D008!M#@%(B[T@
-M`0``2(7_=!$/MK4-`0``N@$```#H`````$B+?5A(A?]T$0^VM8$```"Z`0``
-M`.@`````2(M%0$B%P'1R2,=`8`````!,B>?H`````$B+=4"Z`0```$R)Y^@`
-M````2(M%0`^V4`(/MG`!2,?'`````+@`````Z`````!(BU5`28NT)/@(``"_
-M`0```.@`````2(M50$F+M"3X"```OP8```#H`````$C'14``````2(GN3(GG
-MZ`````!!@'T)_W1<O0````!!@'T.`'0YO0````!)C5U@9F9FD&9FD$B)W^@`
-M````2(M3"$B)0PA(B1A(B5`(2(D"@'A*_W4)@\4!03AM#G?703AM#G<10<9%
-M"?],B>Y,B>?H`````)!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9F
-MD$%7059!54%455-(@^QH28G_2(N'B````$B)1"1@2(LH2(N%H!$``$2+,$B)
-M_DB)[^@`````08!_4@%V!4'&1U$$28U?*$DY7R@/A%,!``!(B=_H`````$B)
-M1"1828M'*$B+5"182(E0"$B)`DB)6@A)B5<H2(72#X0[`P``2(M,)&!(BT$@
-M#[9-00^V53H/MG4Y2(M<)%A$#[=+,D0/MD`(2,?'`````+@`````Z`````!$
-M#[=K,DUIY;`$``!,`Z5`$0``2(N=X!```$B+?"18Z`````!!BXPD)`0``$&+
-ME"0@!```2(M\)%@/MW<R18N,)"P$``!%BX0D*`0``$C'QP````"X`````.@`
-M````2<'E!DP!ZXM#-(M[,$2+4RQ$BULH1(MC)$2+:R"+4QR)5"1,BTL8B4PD
-M4(M3%(E4)%1$BTL01(M##(M+"(M3!(LSB40D0(E\)#A$B50D,$2)7"0H1(ED
-M)"!$B6PD&(M<)$R)7"00BWPD4(E\)`B+1"14B00D2,?'`````+@`````Z```
-M``!F@WUT`'4[Z>L!``!(BU0D8$B+0B`/MDU!#[95.@^V=3E!N?___P!$#[9`
-M"$C'QP````"X`````.@`````Z1$"``"[`````$R-I:@/``!,C:T``0``9F:0
-M9I`/M\-(P>`#2`.%N`D``$B+,$B%]@^$=@$```^W1B!F03E'0`^%9P$```^W
-ME;H2``!!.=9T4(/"`0^WA;X2```YPK@`````#T/0C4(!2,'@`D@#A:`1``"+
-M`*D```@`=2!F)?\/9CG8=1=(.70D6'452(GOZ`````#I?`$``&9FD$0Y\G6P
-M#[=&(&8]A0!F9I`/A_H````/M\"`O`5H"```_P^$Z0```$B+3"1@@'E8``^%
-MV@```/9!"@$/A-````!(BU4`#[=&,F;!Z`4/M\"-!(4``P``B8)P`0``2(M%
-M``^W3C*#X1^Z`0```$B)UTC3YXFX=`$```^W1C)(P>`#2`.%N`D``$C'````
-M```/MTXRB<AFP>@%)?\'``"#X1](B==(T^=(B?GWT2&,A<`)```/MTXRB<AF
-MP>@%)?\'``"#X1](T^+WTB%4A7A(.70D6'0G2(L&2(M6"$B)4`A(B0)(BX4`
-M`0``2(EP"$B)!DR);@A(B;4``0``#[=V,DR)Y^@`````08!O10%F9F:0@\,!
-M9CE==`^'8_[__TB+1"1@]D`*`7112(M,)%A(BQ%(BT$(2(E""$B)$$B)SDR)
-M_^@`````ZS%(BUPD8$B+0R`/MDU!#[95.@^V=3E!N?___P!$#[9`"$C'QP``
-M``"X`````.@`````2(/$:%M=05Q!74%>05_#9F9FD&9F9I!!5T%6055!5%53
-M2(/L*$F)^$B)5"0@3(LO#[?V2,'F`TD#M;@)``!(BRYF@7TXX0%U+@^V13J#
-MZ!$\`7<C3(M_0$C'1"08`````$B%TG5I0<9'40!(QT0D&`````#K69!)BXU`
-M"0``N&">`0!F@7T@A0!W'`^W12!!#[:$!6@(``!(C11`2(T4D$B)T$C!X`5(
-M`<%(B4PD&$&_`````$B#?"0@`'422(M$)!C&@.@`````0;\`````@'TD@74%
-M08!@#/=(@WPD(``/A0(!``#&120`]H66````(`^$0@4``$B+16A(A<`/A#4%
-M``!(B</V@+$````"=!U(B[B@````2(7_=!%(BW5(2(7V=`B+533H`````$F+
-ME1`1``!(@<)`"```2(M,)!@/MD%RP>`(2)A(`<*+`HD%`````(G"P>H0B).;
-M````P>@89HF#D````$F+E1`1``!(@<)$"```#[9!<L'@"$B82`'"BQ*)%0``
-M```/ML)FB8.4````#[;&9HF#E@```(G0P>@0#[;`9HF#F````,'J&(B3F@``
-M`$F+E1`1``!(@<),"```#[9!<L'@"$B82`'"BP*)!0`````/ML!FB8.2````
-MZ5$$```/MT4R2&G`L`0``$V+I4`1``!)`<1)C9PD(`0``(!])(!U!,9%)"%(
-M@WPD&`!T4TB+1"082(-X0``/A8````"+?31$#[:(@0```$F+0"!$#[9`"$$/
-MMDU!00^V53I!#[9U.4B+1"0@2(E$)`B)/"1(Q\<`````N`````#H`````.L]
-M387_=#A$BTTT28M`($0/MD`(00^V34%!#[95.D$/MG4Y2(M$)"!(B00D2,?'
-M`````+@`````Z`````!FD(M+!(L3#[=U,D2+2PQ$BT,(2,?'`````+@`````
-MZ`````!!]D0D(@%T?4R-95A,B[6`````08M4)`1!#[9T)`%(Q\<`````N```
-M``#H`````(!]6``/A/4```"[``````^VPTB-!$!(P>`"28M4)`A(`<))`T80
-MBTH(2(L2#[;S1(M("$R+`$C'QP````"X`````.@`````@\,!03@<)`^&JP``
-M`.NY08!\)"<`9F:0#XF:````#[=U,HGR9L'J!0^WT@^W]DC'QP````"X````
-M`.@`````08N-R`D``$&+E<0)``!!B[7`"0``18N%S`D``$C'QP````"X````
-M`.@`````#[=U,DC'QP````"X`````.@`````28M5``^W13)FP>@%#[?`C02%
-M``,``(F"<`$``$F+50`/MTTR@^$?N`$```!(T^")@G0!``!FD&:!?3CA`748
-M#[9%.H/H$3P!=PU,B?_H`````.DB`@``#[94)"/VP@$/A/(!``"+13@E____
-M`#WA`0X`#X3?`0``28N5$!$``$B!PD`(``!(BTPD&`^V07+!X`A(F$@!PD2+
-M(D2))0````!)BY40$0``2('"1`@```^V07+!X`A(F$@!PD2+,D2)-0````!)
-MBY40$0``2('"2`@```^V07+!X`A(F$@!PHL:B1T`````28N5$!$``$B!PDP(
-M```/MD%RP>`(2)A(`<)$BP)$B04`````B=E$B?)$B>9(Q\<`````N`````#H
-M`````/:%E@```"`/A.H```!(BWUHQH>R````$,9%)"!$B>#!Z!"(AYL```!$
-MB>#!Z!AFB8>0````B=C!X`A!#[;6`=!FB8>4````B=BP`$R)\0^VU0'09HF'
-ME@```(G:P>H0P>((1(GPP>@0#[;``<)FB9>8````28N5$!$``$B!PDP(``!(
-MBTPD&`^V07+!X`A(F$@!PHLRB34`````0`^V]F:)MY(````/MX^6````#[>7
-MF`````^W]D0/MX>4````2,?'`````+@`````Z`````!)BY40$0``2('"0`@`
-M`$B+3"08#[9!<L'@"$B82`'"QP(`````ZUYF@7TXX0%U)`^V13J#Z!H\`7<9
-M2,?'`````+@`````Z`````#&120AZS1FD$B)[DR)[^@`````ZR5F9I"$TGD>
-M28M%`(N(6`$``(D-`````(7)=`I)BT4`B8A8`0``2(/$*%M=05Q!74%>05_#
-M9F9FD&9F9I!F9F:09F:02(/L"`^V1CA(.7XH=4H\"'1E/"AT83RH=%T\B&9F
-M9I!T53P*=%$\*G1-/*IF9F:0=$4\BG1!2(N'``$``$B)<`A(B09(C8<``0``
-M2(E&"$B)MP`!``#K'TB+EP@!``!(B;<(`0``2(V'``$``$B)!DB)5@A(B3+H
-M`````$B#Q`C#9F9FD&9F9I!F9F:09F:02(/L".@`````2(/$",-FD%-(@^Q@
-M2(G[2(U,)%U(C50D7DB-="1?#[=_/$B-1"122(E$)#A(C40D5$B)1"0P2(U$
-M)$Q(B40D*$B-1"1.2(E$)"!(C40D6$B)1"082(U$)%I(B40D$$B-1"1;2(E$
-M)`A(C40D5DB)!"1,C4PD7$R-1"10Z``````/ME0D7P^V="1>2(U\)$CH````
-M``^V1"1?2(T40$B-%)!(P>(%2(MS($B-NR`)``"Y`0```.@`````#[94)%U(
-MC1322,'B!4B+<R!(C;M("0``N0$```#H``````^V5"1>2&G2R`\``$B+<R!(
-MC;MP"0``N0$```#H``````^W5"182,'B`TB+<R!(C;N8"0``N0$```#H````
-M``^W1"102(T4@$B-%)!(P>(#2(MS($B-NW`*``"Y`0```.@`````#[94)%P/
-MMT0D4$@/K]!(C1122,'B`DB+<R!(C;L`"@``N0$```#H`````$B+<R!(C;LH
-M"@``N0$```"Z``(``.@`````#[9,)%](BW,@2(V[8`L``+H`"```Z``````/
-MME0D6TC!X@5(BW,@2(V[P`H``+D!````Z`````!(BW,@2(V[Z`H``+D!````
-MN@`!``#H``````^V5"1:2(T4DDC!X@5(BW,@2(V[$`L``+D!````Z``````/
-MMU0D5DB-%))(P>(#2(MS($B-NS@+``"Y`0```.@`````#[=4)%A(`=)(BW,@
-M2(V[@`\``+D!````Z``````/ME0D7T@!TDB+<R!(C;NX#P``N0$```#H````
-M``^V5"1=2`'22(MS($B-N_`/``"Y`0```.@`````#[94)%Y(`=)(BW,@2(V[
-M*!```+D!````Z``````/ME,^2`'22(MS($B-NV`0``"Y`0```.@`````#[=4
-M)$Y(C1122,'B!$B+<R!(C;N8"@``N0$```#H`````(M4)$A(BW,@2(V[F!``
-M`+D!````Z``````/MU0D6$C!X@9(BW,@2(V[P!```$&X`0```+E`````Z```
-M``!(BW,@2(V[\!```$&X`0```+D``0``N@`9``#H``````^W5"182&G2L`0`
-M`$B+<R!(C;L@$0``0;@!````N8````#H``````^W5"142,'B`DB+<R!(C;M0
-M$0``0;@!````N00```#H``````^W5"122,'B`DB+<R!(C;N`$0``0;@!````
-MN00```#H``````^V5"1;P>(+2(MS($B-N[`1``!!N`$```"Y"````.@`````
-M2(MS($B-N^`1``!!N`$```"Y"````+H```@`Z``````/MU0D5DAITHP!``!(
-MBW,@2('#$!(``$&X`0```+D(````2(G?Z`````"X`````$B#Q&!;PV9FD&:0
-M2(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)]TF)_4B+!TB)
-M!"1,C6=(3(GGZ`````!(B<-,C7#(2(L\).@`````2(G%28M%4$F)75!-B68X
-M28E&0$B)&+@!````2(7M='C&13CAQD4Y`<9%.A"`33L!28N'H````$B)16A(
-MBT5P3(EX*$F-AY````!(B450QD4ES$$/MD9;9HE%($F+10!(B44HQT4TD```
-M`$R)?4A(QX6@`````````$B-?5B^`````.@`````2(GN2(L\).@`````N```
-M``!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(@\0XPV9F9I!F9I!F
-M9I!!5T%6055!5%532(/L&$B)_4C'1"00`````$B+1"00#[:4*.X(``"`^O\/
-MA.H````/MLI(C02)2(T$@4B-A,7(`0``2(E$)`@/MO)(8\9(C12`2(T4D("\
-MU=8!````#X2V````0;P`````2(T$B4B-!(%(P>`#3(VT!2@"``!,C2PH2&/&
-M2(T4@$B-%)!,C;S5P`$``$R)]^@`````2(G#28N%,`(``$F)G3`"``!,B3-(
-MB4,(2(D82(M30$B%TG052(NU^`@``+\%````Z`````"`2TP"2(G:O@(```!(
-MBWPD".@`````@+N#`````'0;2(GOZ`````"_`0```.@`````@+N#`````'7E
-M08/$`44X9Q8/AWO___](@T0D$`%(@WPD$`0/A>[^__](B>_H`````$B#Q!A;
-M74%<05U!7D%?PV9F9I!F9I!F9I!F9I!!5T%6055!5%532(/L>$B)^\9'40#&
-M1U``QD=/`,:'<10```!(C9?`$@``N`````#&!!``2(/``4@]H`$``'7P2(V#
-M``$``$B)@P`!``!(B8,(`0``2(V#$`$``$B)@Q`!``!(B8,8`0``3(VC(`$`
-M`$R)HR`!``!,B:,H`0``3(VK,`$``$R)JS`!``!,B:LX`0``2(V#0`$``$B)
-M1"1(2(F#0`$``$B)@T@!``!(C8M0`0``2(E,)%!(B8M0`0``2(F+6`$``$R-
-MLW`!``!,B;-P`0``3(FS>`$``$B-LX`!``!(B70D0$B)LX`!``!(B;.(`0``
-M3(V[8`$``$R)NV`!``!,B;MH`0``2(U,)&Y(C50D<$B-="1Q#[=[/$B-1"1R
-M2(E$)#A(C40D=$B)1"0P2(U$)&1(B40D*$B-1"1J2(E$)"!(C40D=DB)1"08
-M2(U$)&Q(B40D$$B-1"1M2(E$)`A(C40D:$B)!"1,C4PD;TR-1"1FZ``````/
-MMD0D<8A#1@^V1"1PB$-'#[9$)&Z(@_T````/MT0D=F:)0W0/MT0D=&:)@[P2
-M```/MT0D<H/H`6:)@[X2```/MT0D9F:)0U(/MT,\9CV`D70*9CV`E`^%J`D`
-M`,9#303&0T,$QD-.0,9#3`#&@_H````)QD-$`$B-NR`)``#H`````$B)P4B)
-M@T`)```/MD0D<4B-%$!(C1202,'B!4B%TG002(G(Q@``2(/``4B#Z@%U\TB-
-MNT@)``#H`````$B)P4B)@V@)```/MD0D;DB-!,!(B<)(P>(%2(72=!!(B<C&
-M``!(@\`!2(/J`77S2(V[<`D``.@`````2(G!2(F#D`D```^V1"1P2&G0R`\`
-M`$B%TG002(G(Q@``2(/``4B#Z@%U\TB-NY@)``#H`````$B)P4B)@[@)```/
-MMT0D=DB-%,4`````2(72=!!(B<C&``!(@\`!2(/J`77S2(V[*`H``.@`````
-M2(F#2`H``$B-NP`*``#H`````$B)Q4B)@R`*``!(C;MP"@``Z`````!(B<)(
-MB8.0"@``9H-\)&8`=$BY`````$B):F`/MD0D;XA"6$B+@R@!``!(B9,H`0``
-M3(DB2(E""$B)$`^V1"1O2(T$0$B-;(4`2('"J````(/!`68Y3"1F=[U(C;N8
-M"@``Z`````!(B<)(B8.X"@``9H-\)&H`="^Y`````,9"$`!(BX,X`0``2(F3
-M.`$``$R)*DB)0@A(B1!(@\(P@\$!9CE,)&IWUDB-N\`*``#H`````$B)PDB)
-M@^`*``"`?"1M`'0SN0````!(BX-(`0``2(F32`$``$B+="1(2(DR2(E""$B)
-M$$B#PB"#P0$/MD0D;68YR'?22(V[Z`H``.@`````2(G"2(F#"`L``$B-B``!
-M``!(BX-8`0``2(F36`$``$B+="102(DR2(E""$B)$$B#PB!(.<IUVDB-NQ`+
-M``#H`````$B)PDB)@S`+``"`?"1L`'0QN0````!(BX-X`0``2(F3>`$``$R)
-M,DB)0@A(B1!(@<*@````@\$!#[9$)&QF.<AWU$B-NS@+``#H`````$B)PDB)
-M@U@+``!F@WPD:`!T*[D`````2(N#:`$``$B)DV@!``!,B3I(B4((2(D02(/"
-M*(/!`68Y3"1H=]J`?"1Q`'1)O0````!,C:-@"P``3(GGZ``````/M]5(B833
-M@`L``$B+DX@!``!(B8.(`0``2(M,)$!(B0A(B5`(2(D"@\4!#[9$)'%F.>AW
-MPTB-NX`/``#H`````$B)@Z`/``!(B8.H#P``#[=T)'9FB;.R#P``#[?V2(V[
-MJ`\``.@`````2(V[N`\``.@`````2(F#V`\``$B)@^`/```/MG0D<6:)L^H/
-M```/M_9(C;O@#P``Z`````!(C;OP#P``Z`````!(B8,0$```2(F#&!````^V
-M="1N9HFS(A````^W]DB-NQ@0``#H`````$B-NR@0``#H`````$B)@T@0``!(
-MB8-0$```#[9T)'!FB;-:$```#[?V2(V[4!```.@`````2(V[8!```.@`````
-M2(F#@!```$B)@X@0```/MD,^9HF#DA````^V<SY(C;N($```Z`````!(C;N8
-M$```Z`````!(B<%(B8.X$```#[9$)'!(C03`2,'@!XG&@<9@5P``=!*)\DB)
-MR,8``$B#P`%(@^H!=?-(BX.X$```B3!(BY.X$```#[9$)'"(0@0/ME0D<$B+
-MN[@0``#H`````$&X`````(![/@`/A*@```"_``````^WQTB-%(!(C1202,'B
-M`TR-A!/(`0``2(T$&DB-L,`!``!`B'X0QD81`$B)F,@!``#&1A8`QH`@`@``
-M`,:`\`$```#'@&@"````````2(V,$_@!``!(B8CX`0``2(F(``(``$B-C!,0
-M`@``2(F($`(``$B)B!@"``!(C903*`(``$B)D"@"``!(B9`P`@``QD82`H/'
-M`0^V0SYF.?@/AUW____&0TP`QH/N"```_\:#[P@``/_&@_`(``#_QH/Q"```
-M_X!\)'$`#X26````O@`````/M\Y(C01)2(T$@4C!X`5(BY-`"0``QD0"2P%(
-MBY-`"0``QD002@!(BY-`"0``QH00@````/](BY-`"0``QD00<O](BY-`"0``
-M9L>$$,@``````$C'A,MH!````````$B)P4@#BT`)``!(C5$@2(E1($@#@T`)
-M``!(C5`@2(E0*(/&`0^V1"1Q9CGP#X=O____9L>#^```````N`````#&A!AH
-M"```_TB#P`%(/88```!U[(!\)'``#X2]````O@`````/M\9(:<#(#P``2(N3
-MD`D``,9$`E@`2(N3D`D``,9$$%D`2(N3D`D``$C'1!`0`````$B)P4@#BY`)
-M``!(C5$82(E1&$B)P4@#BY`)``!(C5$82(E1($B)P4@#BY`)``!(C5$H2(E1
-M*$B)P4@#BY`)``!(C5$H2(E1,$B+DY`)``!,B400"$B)P4@#BY`)``!(C5%(
-M2(E12$@#@Y`)``!(C5!(2(E04(/&`0^V1"1P9CGP#X=(____QH/[````@(!\
-M)&X`#X2"````O@`````/M\9(C03`2,'@!4B+DV@)``!FQT0"3@0`2(N3:`D`
-M`,9$$$(`2(N3:`D``,9$$$3_2(N3:`D``,9$$%#_2(G!2`.+:`D``$B-42A(
-MB5$H2(G!2`.+:`D``$B-42A(B5$P2(N3:`D``$R)A!"(````@\8!#[9$)&YF
-M.?!W@\:#_````()(C;/H$```2(V[P!```.@`````2(F#X!```$B-LQ@1``!(
-MC;OP$```Z`````!(B8,0$0``2(VS2!$``$B-NR`1``#H`````$B)@T`1``!(
-MC;-X$0``2(V[4!$``.@`````2(F#<!$``$B-LZ@1``!(C;N`$0``Z`````!(
-MB8.@$0``2(VSV!$``$B-N[`1``#H`````$F)Q$B)@]`1``!(BZO8$0``@'PD
-M;0!T4D&]`````$B+?"1(Z`````!,B6`02(EH&$B+DT@!``!(B8-(`0``2(MT
-M)$A(B3!(B5`(2(D"28'$``@``$B!Q0`(``!!@\4!#[9$)&UF1#GH=[1(C;,(
-M$@``2(V[X!$``.@`````28G$2(F#`!(``$B+JP@2``!!O0````!(BWPD4.@`
-M````3(E@$$B):!A(BY-8`0``2(F#6`$``$B+3"102(D(2(E0"$B)`DF!Q```
-M`0!(@<4```$`08/%`69!@_T(=;A(C;,X$@``2(V[$!(``.@`````2(F#,!(`
-M`$R+HS@2``!F@WPD:`!T2$B)Q4&U`$R)_^@`````2(EH$$R)8!A(BY-H`0``
-M2(F#:`$``$R).$B)4`A(B0)(@<6,`0``28'$C`$``$&#Q0%F1#EL)&AWODB#
-MQ'A;74%<05U!7D%?PT%505154TB#[`A)B?U)B?1(BYZ(````#[961TB)_DB)
-MW^@`````2(G%9D&#3"1.$$&`?4,`=%FY`````/9##0%T#>M,#[9##4C3^*@!
-M=0V#P0%!#[9%0V8YR'?H9H/Y`W8S28M%`$@%T`$``$B-%(T`````@>+\_P,`
-M2`'0BP")!0````#!Z!2#\`&#X`'K,;D`````28M%`$@%T`$``$B-%(T`````
-M@>+\_P,`2`'0BP")!0````#!Z!2#\`&#X`&$P'00#[;Q3(GOZ`````#IEP$`
-M`$B-0V!(.4-@#X09`0``2(7M#X00`0``#[:%@0```$G'1,18`````$B+50!(
-MBT4(2(E""$B)$$B)ZKX&````2(G?Z`````"`O8,`````=!M,B>_H`````+\!
-M````Z`````"`O8,`````=>5(BT5`2(7`=$A(QT!@`````/9%3`1U"$R)[^@`
-M````2(M50$F+M?@(``"_`0```.@`````2(M50$F+M?@(``"_!@```.@`````
-M2,=%0`````"`:PX!2(GN3(GOZ`````!)BT4`BY!8`0``B14`````A=)T"DF+
-M10")D%@!``!!QD0D0@!F08-D)$[O08!\)#L`="JZ``````^WPDF+1,182(7`
-M=`J`>$K_#X5^````@\(!00^V1"0[9CG0=]M!@'PD3@!X#[T`````08!\)#L`
-M=1'K2TR)YDR)[^@`````9I#K2@^WQ4F+7,182(7;="'V0TP"=!M(BU-`28NU
-M^`@``+\&````Z`````"`8TS]9I"#Q0%!#[9$)#MF.>AWQ&9!QT0D3@(`08!D
-M)$G]2(/$"%M=05Q!7<-F9I!F9I!F9I!!5T%6055!5%532(/L>$F)_TB)?"10
-M2(M'4$B)1"1P2(LH2(N%H!$``$2+,$B)_DB)[^@`````08"_ZP````%V"$'&
-MA^@````$28U'($C'1"1H`````$DY1R!T*4F-7R!(B=_H`````$B)1"1H28M'
-M($B+5"1H2(E0"$B)`DB)6@A)B5<@28-_0`!U3+____\`2(-\)&@`=`E(BTPD
-M:`^W>3)%#[:/@0```$B+="1P2(M&($0/MD`(#[9-00^V53H/MG4YB3PD2,?'
-M`````+@`````Z`````!(@WPD:``/A,X#``!(BT0D:$0/MV@R36GEL`0``$P#
-MI4`1``!(BYW@$```2(G'Z`````!!BXPD)`0``$&+E"0@!```2(M$)&@/MW`R
-M18N,)"P$``!%BX0D*`0``$C'QP````"X`````.@`````2<'E!DP!ZXM#-(M[
-M,$2+4RQ$BULH1(MC)$2+:R"+4QR)5"1<BTL8B4PD8(MS%(ET)&1$BTL01(M#
-M#(M+"(M3!(LSB40D0(E\)#A$B50D,$2)7"0H1(ED)"!$B6PD&(M$)%R)1"00
-MBT0D8(E$)`B+1"1DB00D2,?'`````+@`````Z`````!,BV0D:$F#Q%A(BU0D
-M:$R+JH````!!BU0D!$$/MG0D`4C'QP````"X`````.@`````08!\)`$`=$Z[
-M`````&9F9I!F9I`/ML-(C01`2,'@`DF+5"0(2`'"20-%$(M*"$B+$@^V\T2+
-M2`A,BP!(Q\<`````N`````#H`````(/#`4$X7"0!=[YF@WUT``^$(@(``$&\
-M`````$R-K:@/``!(C8T``0``2(E,)$A!#[?$2,'@`T@#A;@)``!(BQA(A=L/
-MA-\!```/MT,@9D$Y1S@/A=`!```/MY6Z$@``03G6=&QF9F:0@\(!#[>%OA(`
-M`#G"N``````/0]"-0@%(P>`"2`.%H!$``(L`J0``"`!U.&8E_P]F1#G@=2Y(
-M.5PD:'4L2(M$)&@/MW`R2,?'`````+@`````Z`````!(B>_H`````.F?`0``
-M1#GR=9A(BU0D<(!Z6``/A4D!```/MT,@9CV%``^'.P$```^WP("\!6@(``#_
-M#X0J`0``2(-\)%``#X0$`0``00^V1TBH`0^$]P```*@$#X3O````2(M5``^W
-M0S)FP>@%#[?`C02%``,``(F"<`$``$B+10`/MTLR@^$?N@$```!(B=9(T^:)
-ML'0!```/MT,R2,'@`T@#A;@)``!(QP``````#[=+,HG(9L'H!27_!P``@^$?
-M2(G62-/F2(GQ]]$AC(7`"0``#[=+,HG(9L'H!27_!P``@^$?2-/B]](A5(5X
-M2#M<)&AT14B+$TB+0PA(B4((2(D02(.[@`````!T#TB-LX````!(B>_H````
-M`$B+A0`!``!(B5@(2(D#2(M$)$A(B4,(2(F=``$```^W<S),B>_H`````$&`
-MKX,````!ZQI(BU0D</9""@)T#TB)WDR)_^@`````9F9FD$&#Q`%F1#EE=`^'
-M]_W__TB#?"10`'0K00^V1TBH`70BJ`1T'DB+3"1H2(L12(M!"$B)0@A(B1!(
-MB<Y,B?_H`````$B#Q'A;74%<05U!7D%?PY"0D)"0D)"0D)"0D)"0D$B+1U!,
-MBPA!N`````!$C1060P^VA`AH"```//]T0@^VP$B-%$!(C1202,'B!4B)T$D#
-M@4`)``!`.+`.`0``=2!(.;@@`0``=1=$B)`-`0``28N!0`D``(B,`@P!``!F
-MD$F#P`%)@?B`````=:3SPY!(BW]8#[:'P````#Q/=S$/ML!(C01`2,'@!`'R
-MB)0'R0````^VA\````!(C01`2,'@!(B,!\@```"`A\`````!\\-F9F:09F9F
-MD&9FD&9FD$&X_____V:%]G1,2(GZ0;C_____OP````!F9F:09F:0#[8*C4'0
-M/`EW&T&`^/^X`````$0/1,!!#[;`C02`1(U$0=#K!D&`^/]U#(/'`4B#P@%F
-M.?=UR4$/ML##9F9FD$&)T4B+1U!,BP"Y`````)!"#[:$`6@(```\_W0S#[;`
-M2(T40$B-%)!(P>(%2(G020.`0`D``$@YN"`!``!U$4`XL`T!``!U"$2(B`\!
-M``##2(/!`4B!^8````!UL_/#D$F)TTB+1U!,BPA,BU=80;@`````0P^VA`AH
-M"```//]T1`^VP$B-%$!(C1202,'B!4D#D4`)``!(.;H@`0``=25`.+(-`0``
-M=1R$R70,2(N"&`$``$F)`^L928L#2(F"&`$``.L-28/``4F!^(````!UHDR)
-MU[@`````9F:09F:0#[:7R````(#Z`79$@/H7=#]`.+?)````=3:$R7062)A(
-MC01`2,'@!$F+A`+0````28D#PTB82(T$0$C!X`1)BQ-)B90"T````,-F9I!F
-M9I"#P`%(@\<P@_A0=:3SPV:0059!54%455-(@^P028G^08GQ2(N_*`$```^V
-M1P+!X`@/ME<#1(T$$$$/M\"#P`0]``@```^/[````$"$]G1,00^VEA`!``"^
-MX/___R'6#[9'`8/@#XG1@^$0"?`)R+X(````(=:#X/.)T8/A!`GP"<B#X@*#
-MX/Q!#[:.$`$``(/A`0G0"<B(1P'K2@^V5P&^X/___R'600^VAA`!``"#X`^)
-MT8/A$`GP"<B^"````"'6@^#SB=&#X00)\`G(@^("@^#\#[9/`8/A`0G0"<A!
-MB(80`0``2(U7"$$/M\!,C60'!$DYU'8_2(E4)`B[`````$$/MNE,C6PD"&9F
-MD&9FD`^V\XGI3(GJ3(GWZ`````!(BT0D"$B#P`1(B40D"(/#`4PYX'+:2(/$
-M$%M=05Q!74%>PV9F9I!F9I!F9I!F9I!32(G[2(M.2`^V00+!X`@/ME$#`=`/
-MM\"-4`0/MT8T.<)_'TB+OR@!``!(8])(B<[H`````+X`````2(G?Z`````!;
-MPV9F9I!F9F:09F9FD$%7059!54%455-(@^P(28GW08G42(M?6$F)WKT`````
-M3(UN!`^V@\@````\`79!/!=T/40XH\D```!U-$$/ME<#2&/%2(T$0$C!X`1)
-MC;P&V````(#Z(+@@````#T?0#[;23(GNZ`````!F9I!F9I"#Q0%(@\,P@_U0
-M=:A(@\0(6UU!7$%=05Y!7\-F9I!FD$B#[$A(B5PD&$B);"0@3(ED)"A,B6PD
-M,$R)="0X3(E\)$!)B?Q!B=>)RTR)!"1`B'0D#TB+1U!,BS!,B??H`````$B)
-MQ4B%P`^$]@```$R)]^@`````28G%2(7`=1)(B>Y,B??H`````.G6````9I!(
-MC4582(E$)!!)BWT0B=I)B[0D*`$``.@`````QH68````"L9%):Q!#[=$)#AF
-MB44@2(L4)$B)56A,B74HB5TT@XV4````$DF+11!(B45(3(EM>$F-A"3L````
-M2(E%4,9%,"!(QX6@`````````,9%.#O&13D"#[9$)`^(13I$B?C!Z!"(13M,
-MB?H/ML:(13Q$B'T]#[9%-HA%/@^V136(13^(74#&14$`O@````!(BWPD$.@`
-M````BU4T28MU&$B+?"00Z`````!(B>Y,B??H`````$B+7"082(ML)"!,BV0D
-M*$R+;"0P3(MT)#A,BWPD0$B#Q$C#9F:09F:09F:02(/L2$B)7"082(EL)"!,
-MB60D*$R);"0P3(ET)#A,B7PD0$F)_$&)UXE,)`A,B<-`B'0D#TB+1U!,BS!,
-MB??H`````$B)Q4B%P`^$Z@```$R)]^@`````28G%2(7`=1%(B>Y,B??H````
-M`.G*````D$B-15A(B40D$,:%F`````K&126L00^W1"0X9HE%($B)76A,B74H
-MQX64````"````$R);7A)BT402(E%2(M4)`B)531)C80D[````$B)15#&13`@
-M2,>%H`````````#&13@\QD4Y`@^V1"0/B$4Z1(GXP>@0B$4[3(GZ#[;&B$4\
-M1(A]/0^V13:(13X/MD4UB$4_#[9$)`B(14#&14$`O@````!(BWPD$.@`````
-MBU4T28MU&$B+?"00Z`````!(B>Y,B??H`````$B+7"082(ML)"!,BV0D*$R+
-M;"0P3(MT)#A,BWPD0$B#Q$C#9F9FD$B#[#A(B5PD"$B);"003(ED)!A,B6PD
-M($R)="0H3(E\)#!)B?Q(BT=03(LX2(N7*`$```^V0@+!X`@/ME(#`=`/M\!$
-MC6@$08']``@```^/S@```$R)_^@`````2(G%2(7`#X2Z````3(G_Z`````!)
-MB<9(A<!U$$B)[DR)_^@`````Z9H```!(C5U82(MX$$ECU4F+M"0H`0``Z```
-M``#&126L00^W1"0X9HE%($R)?2A$B6TT@XV4````$DF+1A!(B45(3(EU>$F-
-MA"3L````2(E%4,9%,"!(QX6@`````````,9%.!W&13D0QD4Z`@^V136(13M$
-MB&T\O@````!(B=_H`````(M5-$F+=AA(B=_H`````$B)[DR)_^@`````2(M<
-M)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$.,-F9F:09F9FD&9FD$B#
-M["A(B5PD&$B);"0@2(G[B=5(QT0D$`````"`?TL!=$%(C50D$$`/MO:Y`0``
-M`.@`````2(M$)!!(A<!T)(`(@$"$[70+2(M$)!"`2`,@ZPE(BT0D$(!@`]](
-MB=_H`````$B+7"082(ML)"!(@\0HPV9F9I!F9F:09F:09F:02(/L.$B)7"0(
-M2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_4&)]TB+1U!,BS!,B??H````
-M`$B)Q4B%P`^$J0```$R)]^@`````28G$2(7`=1!(B>Y,B??H`````.F)````
-M2(U=6,9%):Q!#[=%.&:)12!,B74HQX64````"````$R)97A)BT0D$$B)14C'
-M130`"```28V%[````$B)15#&13`@2,>%H`````````#&13@<QD4Y`42(?3K&
-M13L(QD4\`+X`````2(G?Z`````"+531)BW0D&$B)W^@`````2(GN3(GWZ```
-M``!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(@\0XPY!!5T%6055!
-M5%532(/L&$B)/"1(BTY(#[9!`L'@"`^V40.-/!`/M\>#P`0/MU8T.=`/CUH!
-M``!,C6D(#[?'3(UT`01,B6PD"$&\`````,=$)!0`````33GU#X/9````9I`/
-MMD0D%(A$)!-!#[9%`L'@"$$/ME4#1(T\$$$/M_=(BWPD"$B#QP3H`````(G!
-M//]U7D$/M\=(BUPD"$B-5`,$2(G323G6#X;/````08G,D`^V0@+!X`@/ME(#
-MC2P0#[?U2(U[!.@`````//]U"$&`_/]U>>MQ03C$1`]'X`^WQ4B-5`,$2(G3
-M23G6=F#KP9")PD0HX@^VT@^V7"03B=Y(BSPDZ`````")VDR)[DB+/"3H````
-M`$$/M\=(BU0D"$R-;`($3(EL)`B#1"04`4TY[@^'*?___[X"````2(L\).@`
-M````ZTE!O``````/ME0D$TR)[DB+/"3H`````$$/M\=(BUPD"$R-;`,$3(EL
-M)`B#1"04`>GE_O__#[94)!-,B>Y(BSPDZ`````#KJ6:02(/$&%M=05Q!74%>
-M05_#D$%7059!54%455-(@^P(28G^2(M.2`^V00+!X`@/ME$#`=`/M\"#P`0/
-MMU8T.=`/CPP!``!(C5$(#[9Q`<9$)`,`N0`````/MD("`$0D`P^V0@-(C50"
-M!(/!`4`XSG/G@'PD`P`/A+X```!(C6H$0;\`````0;T`````QT0D!``````/
-MME7]00'5#[9%_#P!=`0\%W4[1(GK*--!.-UV<0^V1"0$@\`!1`^VX&9FD&:0
-M#[9-_`^V\T2)XDR)]^@`````@\,!1#CK=$;KY&9F9I!)BT98@+C!`````70S
-M1(GK*--!.-UV*0^V1"0$@\`!1`^VX`^V3?P/MO-$B>),B??H`````(/#`40X
-MZW7F9F:008/'`8-$)`0!2(/%!$0Z?"0##X5:____28M&6,:`P0````&^!P``
-M`$R)]^@`````2(/$"%M=05Q!74%>05_#D$B#["A(B1PD2(EL)`A,B60D$$R)
-M;"083(ET)"!)B?Q(A?\/A,0```!(BT=03(LP3(GWZ`````!(B<5(A<`/A*D`
-M``!,B??H`````$F)Q4B%P'402(GN3(GWZ`````#IB0```$B-75C&126L00^W
-M1"0X9HE%($R)=2C'A90````(````3(EM>$F+11!(B45(QT4T``@``$F-A"3L
-M````2(E%4,9%,"!(QX6@`````````,9%.!S&13D!QD4Z`L9%.PC&13P`O@``
-M``!(B=_H`````(M5-$F+=1A(B=_H`````$B)[DR)]^@`````2(L<)$B+;"0(
-M3(MD)!!,BVPD&$R+="0@2(/$*,-F9F:09F:02(/L&$B)'"1(B6PD"$R)9"00
-M2(GS28G\2(MN:`^W3B!F@?F%``^'I0````^WP0^VM`=H"```0(#^_P^$D```
-M`&:#^7]W(D`/MM9(BX]`"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZTAF@?F!
-M`'<=0`^VQDB+EY`)``!(:<#(#P``2(M$$`@/MD`(ZR1`#[;&2(N7:`D``$B-
-M!,!(P>`%2(N$$(@````/MD`(9F:09I`\_W0<#[;`08"\!.X(``#_=`Y`@/[_
-M=`@/MD,D/`9U,$B#>W@`=`Q(C7-X3(GGZ`````!(B=Y,B>?H`````,=%4/__
-M__](B>__54CK<V9FD(3`=3GV@Y0````(=!-(BWTPBU,T2(MS2.@`````9F:0
-MQT50`````$B+53A(A=)T!8M%((D"2(GO_U5(ZQ/'15#_____2(GO_U5(9F:0
-M9F:02(-[>`!T#$B-<WA,B>?H`````$B)WDR)Y^@`````9I!(BQPD2(ML)`A,
-MBV0D$$B#Q!C#9F9FD&9FD&9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD
-M($B)\TF)_$0/MFXD#[=&(&8]A0!W(TB+CT`)```/M\`/MH0':`@``$B-%$!(
-MC1202(G02,'@!>L,2(N/0`D``+A@G@$`2(TL`46$[74@9L>%R```````@'LX
-M''41@'LZ`G4+2(G>2(GOZ`````!(@WMX`'0,2(US>$R)Y^@`````2(G>3(GG
-MZ`````!!@/T&=#U(C9U@`0``28M\)"A(B=[H`````,>%8`$``("$'@!(QX5P
-M`0```````$B)K7@!``!)BWPD*$B)WN@`````2(M<)`A(BVPD$$R+9"083(ML
-M)"!(@\0HPY!!5T%6055!5%532(/L"$F)_T&)UDB+1U!(BRA!O`````!,C6X,
-M00^VA"QH"```//]T4@^VP$B-%$!(C1202(G32,'C!4B)WT@#O4`)``!(@<?4
-M````N@@```!,B>[H`````(3`=!Y(BX5`"0``1(BT`PX!``!(BX5`"0``3(F\
-M`R`!``!)@\0!28'\@````'642(/$"%M=05Q!74%>05_#05=!5D%505154TB#
-M[!A(B7PD"$B+3D@/MD$"P>`(#[91`XT\$`^WQX/`!`^W5C0YT`^/Y@```$B-
-M60@/M\=(C4P!!$B)3"0028G=2#G9#X:Z````0;X`````9F:09F:01(GR#[8+
-MA,D/B(4```")R(/@#SP&=7SV0P/`=`;V0P7`=7#VP1!T.8![!`!F9F:0=&%)
-MC6T(0;P`````9F9FD`^V4P-(B>Y(BWPD".@`````2(/%'$&#Q`%$.&,$=C3K
-MWX![`@!T+$F-;01!O`````!$#[;Z1(GZ2(GN2(M\)`CH`````$B#Q1Q!@\0!
-M1#AC`G?B#[9#`4F-7`4"28G=08/&`4@[7"00#X)2____O@$```!(BWPD".@`
-M````2(/$&%M=05Q!74%>05_#9F9FD$%7059!54%455-(@^PH2(ET)`A(B7PD
-M$`^V1B2(1"0G#[=.(&:!^84`#X?X`P``#[?!#[:T!V@(``"X_P```$"`_O]T
-M>F:#^7]W)T`/MM9(BT0D$$B+B$`)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK
-M36:!^8$`=R)`#[;&2(M,)!!(BY&0"0``2&G`R`\``$B+1!`(#[9`".LD0`^V
-MQDB+3"002(N1:`D``$B-!,!(P>`%2(N$$(@````/MD`(2)A(BU0D$$0/MKP"
-M[@@``$N-!+])C02'2(V$PL@!``!(B40D&$B+BD`)``!`#[;&2(T40$B-%)!(
-MB=!(P>`%2(TL`8!\)"<`#X6S`@``9L>%R```````2(M,)`B`>3@<#X6;`@``
-M#[9!.CP"=%H\`G<1/`$/A8<"``!F9F:09F:0ZQX\!W0O/`H/A7("``!(BW0D
-M"$B)[^@`````Z6`"``!(BW0D"$B)[^@`````9F:0Z4L"``!(BW0D"$B)[^@`
-M````Z3D"``!(BW0D"$B)[^@`````2(V=8`$``$B+15!(BP!(BW@H2(G>Z```
-M``#'A6`!``"`A!X`2,>%<`$```````!(B:UX`0``2(M%4$B+`$B+>"A(B=[H
-M`````,9%2O]+C02_28T$ATB+5"00@+S"U@$````/A),!``!!O`````!+C02_
-M28T$ATC!X`-,C;0"*`(``$B-'!!,C:O``0``3(GWZ`````!(B<5(BX,P`@``
-M2(FK,`(``$R)=0!(B44(2(DH@'U*_P^$E@```(!]20`/A9<```!(B>Z`O>D`
-M````#X17`0``#[952$B)T(/@!DB#^`9U)_;"`70B#[:5@0```$B+=5A(B>E(
-MBWPD&.@`````Z24!``!F9I!FD$B#^`1U&_;"`69F9I!F9I!T#TB+?"00Z```
-M``#I_P```$B#^`8/A?4```#VP@%FD`^%Z@```$B+?"00Z`````#IVP```,:%
-MZ0````!F9F:008/$`4$/MD461#C@#X<?____03C$#X6$````A,`/A'P```!!
-MO`````!+C02_28T$ATC!X`-(BTPD$$R-K`$H`@``2(T<"$R-L\`!``!F9I!,
-MB>_H`````$B)Q4B+@S`"``!(B:LP`@``3(EM`$B)10A(B2B`?4K_=!L/MD5)
-M/")T!#P-=0^^"@```$B)[^@`````ZSM!@\0!13AF%G>Q2XT$OTF-!(=(BU0D
-M$,:$PM$!``#_2(MT)!A(B=?H`````(!\)"<`#X6D````9F9FD$B+3"0(2(-Y
-M>`!T$4B)SDB#QGA(BWPD$.@`````2(MT)`A(BWPD$.@`````@'PD)P!T;0^W
-MA<@```"#P`%FB87(````9H/X"G8.9L>%R```````Z<7]__^^"@```$B)[^@`
-M````ZSE(BT0D$$0/MKCM"0``2XT$OTF-!(=(BU0D$$B-A,+(`0``2(E$)!A(
-MBXI`"0``N&">`0#IG_S__Y!(@\0H6UU!7$%=05Y!7\.02(7_=$M(A?9T1DB%
-MTG1!2(7)=#QF08'XA0!W-$$/M\"`O`=H"```_W0FQD(XX<9".0'&0CH39D2)
-M0B!(B7(H2(F*H````+@!````PV9F9I"X`````,-F9F:09F:09F:02(M'"(M`
-M!(D%`````(G"@<H```P`)?__\_]`A/8/1<)(BU<(B0)(BU<(B4(,2(M7"(E"
-M$$B+5PB)0A1(BU<(B4(82(M7"(E"!,.0D)"0D)!,BU0D($R+7"0PB?AF@?\B
-M)W=?9H'_("</@Y0```!F@?]`(0^$B0```&:!_T`A9I!W(&:!_R`A='EF@?\B
-M(6:0='!F@?]0!W5O9F9FD&9FD.M@9H'_1"%T66:!_T0A9I!R5F8M$"=F@_@!
-M=TQF9F:0ZT!F@?^")W0Y9H'_@B=FD'<29H'_)"=T*6:!_X`G9I!U)NL>9H'_
-M@)%F9F:09F:0=!!F@?^`E'0)9H'_@')FD'4&Q@9`Q@("Q@$$#[862(M$)!B(
-M$&9!QP*``&9!QP,``$'&`2!(BT0D"&;'```!#[862(M$)!"($`^V!F9!`P)F
-M00,#2(M4)"AFB0)F08D`00^W$DB+1"0X9HD000^W$H/""TB+1"1`9HD0PV9F
-M9I!54XGS#[=W=&:%]@^$!`$``$R+E[@)``!!NP````"]_____TF+`DB%P`^$
-MU`````^W2""X_P```$&)Z&:!^84`#X>.````#[?!1`^VC`=H"```18G(08#Y
-M_W1U9H/Y?W<C00^VT4B+CT`)``!(C0122(T$@DC!X`5(BT0(4$0/MD`(ZTQF
-M@?F!`'<>00^VP4B+EY`)``!(:<#(#P``2(M$$`A$#[9`".LG00^VP4B+EV@)
-M``!(C03`2,'@!4B+A!"(````1`^V0`AF9F:09F:000^VP4B+CT`)``!!.-AU
-M(P^WP$B-%$!(C1202,'B!0^V1`I(J`%T"Z@$=`>X`0```.L708/#`4F#P@AF
-M03GS#X4.____N`````!;7<-F9I!(BT=03(L038N:X!```$4/MTITN0````!!
-MN`````#K0P^W\4F+@K@)``!(BQ3P2(72="V+0C@E____`#WA`1``=!X/MT<X
-M9CM"('442(GP2,'@!F9&.408"'0.9F:09I"#P0%F1#G)<K=F1#G)=!-!@\`!
-M9D&#^!]W"+D`````D.OA00^WP,-F9I!F9I!F9I!(BT=02(7`=!K&`'!(BT=0
-M0(AP`DB+1U#&0`<`2(M'4(A0#//#9F9FD&9F9I!F9I#SPV9F9I!F9F:09F:0
-M9F:008GQ3(G*@>+_`0``2(N'N`D``$R+!-!-A<!T*P^VM_H```!!#[9`)8GQ
-MT^`/M_A!#[?1N/__``#3X"'".=>X`````$P/1<!,B<##9F:09I"X`````,8$
-M.`!(@\`!2#T@`0``=?#&1T3_QD=0_TB-1RA(B4<H2(E',,-F9I!F9I"X````
-M`,8$.`!(@\`!2#V@`0``=?#&AX````#_QD=R_\:'@@```!](C4<@2(E'($B)
-M1RC#9F9FD&9F9I!F9F:02(L&2(N7.`$``$B)AS@!``!(@<<P`0``2(DX2(E0
-M"$B)`DC'!@````##9F:09F:02(N7*`$``$B)MR@!``!(C8<@`0``2(D&2(E6
-M"$B),DB#?G``=`E(@\9PZ`````#SPV9F9I!F9F:09F9FD&9FD$B+!DB+EU@!
-M``!(B8=8`0``2(''4`$``$B).$B)4`A(B0)(QP8`````PV9FD&9FD$B+!DB+
-MET@!``!(B8=(`0``2(''0`$``$B).$B)4`A(B0)(QP8`````PV9FD&9FD$B+
-MAW@!``!(B;=X`0``2(''<`$``$B)/DB)1@A(B3##2(L&2(N7B`$``$B)AX@!
-M``!(@<>``0``2(DX2(E0"$B)`DC'!@````##9F:09F:02(L&2(N7:`$``$B)
-MAV@!``!(@<=@`0``2(DX2(E0"$B)`DC'!@````##9F:09F:00(#_%W<10`^V
-MQ_\DQ0````"X-````,.X!````&9F9I##N#P```##N!0```!F9F:0P[A`````
-MP[@<````9F9FD,.X&````,.X*````&9F9I##N"````##N$P```!F9F:0PV9F
-M9I!F9F:09F9FD&9FD`^V5DA(B="#X`9(@_@&=1#VP@$/A-L```!F9F:09F:0
-M@'YR_P^%R@```$B+!T2+B!@!``!$B0T`````N0````"X`0```$&)P$'3X$6%
-MP74SB$YR2(L71(G`1`G(B8(8`0``2(L'BX!8`0``B04`````1(G"(<)T>$B+
-M!XF06`$``.MM@\$!@_D@=;5(BP=$BX@<`0``1(D-`````+$`9I")RK@!````
-M08G`0=/@187!=3:-0B"(1G)(BQ=$B<!$"<B)@AP!``!(BP>+@&`!``")!0``
-M``!$B<(APG032(L'B9!@`0``ZPB#P0&#^2!UL(!'1`'SPV9F9I!F9I!F9I"`
-M?E#_#X7%````2(L'1(N(&`$``$2)#0````"Y`````+@!````08G`0=/@187!
-M=3.(3E!(BQ=$B<!$"<B)@A@!``!(BP>+@%@!``")!0````!$B<(APG1S2(L'
-MB9!8`0``ZVB#P0&#^2!UM4B+!T2+B!P!``!$B0T`````L0!FD+@!````08G`
-M0=/@187!=3.(3E!(BQ=$B<!$"<B)@AP!``!(BP>+@&`!``")!0````!$B<(A
-MPG032(L'B9!@`0``ZPB#P0&#^2!UM8!'1`'SPV9F9I!F9F:09F9FD&9FD$B+
-M=T!(A?9T.;D`````9I!(BT3.6$B%P'0(.)"!````=`Q(@\$!2(/Y!706Z^)F
-M@7Y`A0!W#$B%P&9F9I!F9I!U!;@`````\\-F9F:09F:0055!5%532(G]28G-
-MP>8(#[;2`=:`?S``#X35````2(-_4``/A,H```"+AY0```"H"4$/E,"Y````
-M`$C'QP````!!B<P/MQ3/B?`AT&8YP@^%D`````^V!,T`````/`-T!#P'=0M$
-M.`3-`````'5VD,9%)"!-8^1(Q\,`````0@^V5.,&#[;P2(GOZ`````!(BU50
-M0@^V1.,'B$(-387M=#1)BTT`2(G*2,'J($B+15")4`-(BT50@`B`]H66````
-M!'02A=)T#DB+15")2`A(BT50@"!_2(M54`^V13"#Z`>(0@?K#DB#P0%(@_D0
-M#X5.____6UU!7$%=PV9FD&9FD$B#[`A(C9=@`0``N`````!(.9=@`0``=!!(
-MB=?H`````$C'0"``````2(/$",-FD$B#[`A(C9>``0``N`````!(.9>``0``
-M=`A(B=?H`````$B#Q`C#9F9FD&9FD&9FD$B#[`A(C9=P`0``N`````!(.9=P
-M`0``="A(B=?H`````$B)P;H`````9F9FD&9FD,8$"@!(@\(!2('ZH````'7O
-M2(/$",-F9F:09F:09F:02(/L"$B-ET`!``"X`````$@YET`!``!T"$B)U^@`
-M````2(/$",-F9F:09F:09F:02(/L"$B-ES`!``"X`````$@YES`!``!T#$B)
-MU^@`````QD`0`$B#Q`C#9F:09F:005=!5D%505154TB#[`A)B?]!B?7'1"0$
-M`````$&^`````$,/MH0^Z`@``#S_#X0=`0``#[;008V&@````&8]@0!W?0^W
-MPDAIP,@/``!(B<-)`Y^0"0``@'M8`'13O0````!,C6-(3(GGZ`````!(C4CP
-M2(M34$B)0U!,B6$02(E1&$B)`HM!2"4`__\`/0``_P!U$_9!2P1T#4B+04!(
-MA<!T!$2(:`&#Q0%`.&M8=[9$B*O"````08/%`>F0````#[?"2(T$P$C!X`5(
-MB<9)`[=H"0``@'X[`'0]N0`````/ML%(BU3&6$B%TG0CBT)()0#__P`]``#_
-M`'44]D)+!'0.2(M"0$B%P'0%1(AH`9"#P0$X3CMWR$2(KA0!``"`OA4!```#
-M=1^#1"0$`8M$)`2#P`.#^`9V%T&#Q0''1"0$`````.L)08/%`69FD&:028/&
-M`4F#_@8/A<3^__])BX?X"```3#GX=0](C;B0%```1(GNZ(?^__](@\0(6UU!
-M7$%=05Y!7\-F9F:09F9FD$B#[`@/MD8(#[:T!^X(``#&A`?N"```_P^W]DB!
-MQX@0``#H`````$B#Q`C#9F9FD$B+5G!(A=)T&$B+0AA(B48X2(M"($B)1D!(
-MBT(H2(E&2//#9F9FD&9FD&9FD&9FD$B+5G!(A=)T'$B+1CA(B4(82(M&0$B)
-M0B!(BT9(2(E"*,9"$`'SPV9FD&9FD&9FD$%455-)B?Q(BQ]F@WMT``^$S```
-M`+T`````9F:09F:0#[?52(N#N`D``$B+/-!(A?\/A)T````/MT\@9H'YA0!W
-M?@^WP0^VA`-H"```//]T;V:#^7]W(0^VT$B+BT`)``!(C0122(T$@DC!X`5(
-MBT0(4`^V4`CK36:!^8$`=QP/ML!(BY.0"0``2&G`R`\``$B+1!`(#[90".LJ
-M#[;`2(N3:`D``$B-!,!(P>`%2(N$$(@````/ME`(ZPIF9I!FD+K_````00^V
-M1"0(.<)U!>@`````@\4!9CEK=`^'/____UM=05S#9F9FD&9FD&9FD$B#[!A(
-MB5PD"$B);"002(G[2(GU#[9&4#S_=!,/MO!(BS_H`````,9%4/^`:T0!2(M<
-M)`A(BVPD$$B#Q!C#9I!(@^P82(E<)`A(B6PD$$B)^TB)]0^V1G(\_W03#[;P
-M2(L_Z`````#&17+_@&M$`4B+7"0(2(ML)!!(@\08PV:055-(@^P(2(G]2(GS
-M2#E^*`^$VP```(!^)``/A:<````/MD8X/!5T"#Q5#X67````2(M#<$B%P`^$
-MB@```$B)P8!X$`$/A7T```!F@7@8X0%U=4B+M4`)```/MT,@NF">`0!F/84`
-M=Q</M\`/MH0%:`@``$B-%$!(C1202,'B!4B-!!8/MDD:@/D'=!V`^0=W!X#Y
-M!G4QZQJ`^0QF9I!FD'0@@/D-=2#K$&:#8&K]9I#K%6:#2&H"ZPYF@V!J]V:0
-MZP5F@TAJ"$B#>W@`=".!>S0`"```=PY(C7-X2(GOZ`````#K#$B-<WA(B>_H
-M`````&:!>SCA`0^%)P$```^W0R!F/84`#X>+````#[?`#[:$!6@(```\_P^$
-M>````$B+C4`)``"`>R0`=6L/ML!(C11`2(T4D$C!X@5(C001#[93.H#Z!W0=
-M@/H'=P>`^@9U-NL?@/H,="J`^@UF9I!FD'4EZQ5F@V!J_69F9I!F9I#K%6:#
-M2&H"ZPYF@V!J]V:0ZP5F@TAJ"&:!>SCA`69FD`^%C@```(![.@L/A80````/
-MMW,@#[9%1HUX_XGRZQN0@\(!9H'ZA0!W$`^WRDACP8"\!6@(``#_=0D/M\(Y
-M^'S?ZTUF@?G_`'4B9F:09F:0ZSZ#Q@%F@?Z%`'<0#[?62&/"@+P%:`@``/]U
-M#`^WQCG'?]^Z_P```&:)4R#&0R2`2(G>2(GOZ`````#I(@$``,9#)`!(.6LH
-M="9(BT-P2(7`=!V`>!`!=0M(B=Y(B>_H`````$B-<W!(B>_H`````$B#NX``
-M````=`](C;.`````2(GOZ`````!(BWLH2(G>_Y.@````#[=3.&:!^N$!=5</
-MMD,Z@^@1/`%W3`^W0R!F/84`#X>H````#[?`#[:$!6@(```\_P^$E0````^V
-MP$B-!,!(P>`%2(G&2`.U:`D``(!^10!U>H!^4/]T=$B)[^@`````ZVH/MT,@
-M9CV%`'=@#[?`#[:,!6@(``!(B[5`"0``BT,X)?___P`]X0$0`'0_@?G_````
-M=#=F@?KA`74.#[9#.H/H$3P!=B5F9I")R$B-%$!(C1202,'B!4@!UH"^@P``
-M``!U"$B)[^@`````2(/$"%M=PV9F9I!F9I!54TB#[`A(B?U(B?,/MTX@9H'Y
-MA0`/AZ8````/M\$/MK0':`@``$"`_O\/A)$```!F@_E_=R)`#[;62(N/0`D`
-M`$B-!%)(C02"2,'@!4B+1`A0#[9`".M(9H'Y@0!W'4`/ML9(BY>0"0``2&G`
-MR`\``$B+1!`(#[9`".LD0`^VQDB+EV@)``!(C03`2,'@!4B+A!"(````#[9`
-M"&9FD&:09CW_`'0;#[?`#[:\!>X(``!`@/__=`I`#[;&9CW_`'402(G>2(GO
-MZ`````#I@0````^V4SL/MD,\#[9+/8#Y`70%@/D(=6!(BTMHP>`(#[;2`=`E
-M_P$``$B+E;@)``!(.0S"=4(/MTDRB<IFP>H%@>+_!P``@^$?N`$```!(T^#W
-MT"%$E7A(BT-H#[=P,D`/ML=(C3R`2(T\N$B-O/W(`0``Z`````!(B=Y(B>_H
-M`````$B#Q`A;7<-F9F:09F:02(/L&$B)7"0(2(EL)!!(B?M(C;\@`0``O0``
-M``!(.;L@`0``=!SH`````$B)Q4B)Q^@`````2(G?Z`````!(B45P2(GH2(M<
-M)`A(BVPD$$B#Q!C#9F9FD&9F9I!F9F:02(/L&$B)'"1(B6PD"$R)9"002(G]
-M2(M'4$R+($R)Y^@`````2(G#2(7`='!,B>?H`````$B)PDB%P'44QH7I````
-M`4B)WDR)Y^@`````ZTS&0S@`#[=%.&:)0R#&@Y@````/3(EC*,=#-`````!(
-MQT-(`````$B+0A!(B4-0QD,P)$B)4WA(QX.@`````````$B)WDR)Y^@`````
-M2(L<)$B+;"0(3(MD)!!(@\08PY!(@^P82(D<)$B);"0(3(ED)!!(B?U!B?1(
-MBT=02(L82(G?Z`````!(B<)(A<!T1,9`.!O&0#D!1(A@/`^W13AFB4(@QH*8
-M````#TB)6BC'0C0`````2,="2`````!(QX*@`````````$B)UDB)W^@`````
-M2(L<)$B+;"0(3(MD)!!(@\08PV9F9I!F9I!F9I!(@^PX2(E<)`A(B6PD$$R)
-M9"083(EL)"!,B70D*$R)?"0P28G_28GU3(LW3(GWZ`````!(B<5(A<`/A(X`
-M``!,B??H`````$F)Q$B%P'412(GN3(GWZ`````#K<69F9I!(C5U8QD4XX<9%
-M.0'&13H.00^W13AFB44@9D&#96CW28L'2(E%*,=%-``(``!)BT0D$$B)14A,
-MB65X2,>%H`````````"^`````$B)W^@`````BU4T28MT)!A(B=_H`````$B)
-M[DR)]^@`````2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$.,-(
-M@^PH2(E<)`A(B6PD$$R)9"083(EL)"!)B?2)U4B+'TB)W^@`````2(G"2(7`
-M=%_&0#CAQD`Y`4"(:#K&0#L/00^W1"0X9HE"($B)6BC'0C0`````2,="2```
-M``!(QX*@`````````$B)UDB)W^@`````0(#]`74,OP4```#H`````.L*OU##
-M``#H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:09F9FD%532(/L
-M"$B)_4B)\P^W3B!F@?F%``^'IP````^WP0^VM`=H"```0(#^_P^$D@```&:#
-M^7]W(D`/MM9(BX]`"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZTAF@?F!`'<=
-M0`^VQDB+EY`)``!(:<#(#P``2(M$$`@/MD`(ZR1`#[;&2(N7:`D``$B-!,!(
-MP>`%2(N$$(@````/MD`(9F:09I`\_W0>#[;`#[:,!>X(``"`^?]T#D"`_O]T
-M"`^V0R0\!G4^2(-[>`!T)8%[-``(``!W$$B-<WA(B>_H`````&:0ZPQ(C7-X
-M2(GOZ`````!(B=Y(B>_H`````.M\9F:09I!(BY5`"0``A,!T-4`/ML9(C31`
-M2(TTL$C!Y@5(C30R#[;!2(T\@$B-/+A(C;S]R`$``+H!````Z`````!F9F:0
-M2(-[>`!T)8%[-``(``!W$$B-<WA(B>_H`````.L.9I!(C7-X2(GOZ`````!(
-MB=Y(B>_H`````$B#Q`A;7<-FD$B#["A(B1PD2(EL)`A,B60D$$R);"083(ET
-M)"!(B?M(B?4/MTX@9H'YA0`/AQ\!```/M\$/MK0':`@``$"`_O\/A`H!``!F
-M@_E_=R1`#[;62(N/0`D``$B-!%)(C02"2,'@!4B+1`A0#[9`".M%9I!F@?F!
-M`'<=0`^VQDB+EY`)``!(:<#(#P``2(M$$`@/MD`(ZQ]`#[;&2(N7:`D``$B-
-M!,!(P>`%2(N$$(@````/MD`(//\/A)4```!$#[;F#[;`1`^VK`/N"```08#]
-M_W1_9D&!_/\`='>`?20&='%,B[-`"0``@'TZ`75)OPH```#H`````$B)[DB)
-MW^@`````00^WQ$B--$!(C32P2,'F!4F--#9!#[;%2(T\@$B-/+A(C;S[R`$`
-M`+H"````Z`````#K&[_T`0``Z`````!(B>Y(B=_H`````&9FD&9FD$B+'"1(
-MBVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F:02(/L&$B)'"1(B6PD"$R)9"00
-M28G\2(M'4$B+*$B)[^@`````2(G#2(7`=0M!QH0DZ0````'K7\9`.!7&0"6K
-M00^W1"0X9HE#($B):RA!N`$```"Y`0```$B)VDR)YDB)[^@`````A,!U%DB)
-MWDB)[^@`````0<:$).D````!ZQ9(QX.@`````````$B)WDB)[^@`````2(L<
-M)$B+;"0(3(MD)!!(@\08PV9F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL
-M)"!(B?M(BT=03(LH3(GOZ`````!(B<5(A<!U#L:#Z0````'IM@```&:03(GO
-MZ`````!)B<1(A<!U%\:#Z0````%(B>Y,B>_H`````.F-````QD4X&L9%.0C&
-M13H(QD4[`,9%//_&13T`QD4EJP^W0SAFB44@3(EM*,=%-/\```#'A90````(
-M````28M$)!!(B45(2`7_````2(E%4,9%,"1,B65X2,>%H`````````!(C5U8
-MO@````!(B=_H`````$F+="08NO\```!(B=_H`````$B)[DR)[^@`````2(M<
-M)`A(BVPD$$R+9"083(ML)"!(@\0HPV9FD$B#[#A(B5PD"$B);"003(ED)!A,
-MB6PD($R)="0H3(E\)#!)B?Q!B?9(BT=03(LH3(GOZ`````!(B<-(A<!U$4'&
-MA"3I`````>FZ````9F:03(GOZ`````!(B<5(A<!U($'&A"3I`````4B)WDR)
-M[^@`````Z8X```!F9F:09F:03(U[6,9#.!)%A/9T$\9#.0'&0SJ`QD,\0.L)
-M9F:09I#&0SPDQD,EJT$/MT0D.&:)0R!,B6LHQT,T8````,>#E`````@```!(
-MBT402(E#2$B):WA(QX.@`````````+X`````3(G_Z`````!(BW48NF````!,
-MB?_H`````$B)WDR)[^@`````2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+
-M?"0P2(/$.,-F9I!F9I!(@^PH2(D<)$B);"0(3(ED)!!,B6PD&$R)="0@28G\
-M2(M'4$R+,$R)]^@`````2(G%2(7`=0Y!QH0DZ0````'IL@```$R)]^@`````
-M28G%2(7`=1Q!QH0DZ0````%(B>Y,B??H`````.F)````9F:02(U=6,9%.)[&
-M13D0QD5%(,9%):M!#[=$)#AFB44@3(EU*,=%-"````#'A90````(````28M%
-M$$B)14A,B6UX2(/`($B)15#&13`D2,>%H`````````#&A9@````/O@````!(
-MB=_H`````$F+=1BZ(````$B)W^@`````2(GN3(GWZ`````!(BQPD2(ML)`A,
-MBV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9I!F9I!F9I!(@^PH2(D<)$B);"0(
-M3(ED)!!,B6PD&$R)="0@28G\2(M'4$R+,$R)]^@`````2(G%2(7`=0Y!QH0D
-MZ0````'IHP```$R)]^@`````28G%2(7`=1Q!QH0DZ0````%(B>Y,B??H````
-M`.M]9F:09F:02(U=6,9%."7&126K00^W1"0X9HE%($R)=2C'130(````QX64
-M````"````$F+11!(B45(2(/`"$B)15#&13`D3(EM>$C'A:``````````O@``
-M``!(B=_H`````$F+=1BZ"````$B)W^@`````2(GN3(GWZ`````!(BQPD2(ML
-M)`A,BV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9F:09F9FD$B#[#A(B5PD"$B)
-M;"003(ED)!A,B6PD($R)="0H3(E\)#!)B?])B?2)5"0$2(LO3(NU0`D```^W
-M1B!$#[:L!6@(``!(B>_H`````$B)PT$/MW0D,HGP9L'H!0^WP(M$A7B)\8/A
-M'TC3^*@!#X7"````2(7;#X2Y````00^VQ4B-%$!(C1202,'B!4F-%!9!#[9$
-M)"4/MHWZ````T^`)\,9#..'&0SD!QD,Z#XA#.V;!Z`B(0SP/MD0D!(A#/4B+
-M@MP```!(B4,^3(EC:,9#):H/MT(X9HE#($F+!TB)0RC'0S0`````2,=#2```
-M``!(QX.@`````````$B->UB^`````.@`````2(G>2(GOZ`````!!#[=,)#*)
-MRF;!Z@6!XO\'``"#X1^X`0```$C3X`E$E7A(BUPD"$B+;"003(MD)!A,BVPD
-M($R+="0H3(M\)#!(@\0XPV9F9I!F9I!F9I!!5T%6055!5%532(/L"$F)_DF)
-MU4&)]TB+'V:#>W0`#X0.`@``O0````!!O/____\/M]5(BX.X"0``2(LTT$B%
-M]@^$WP$``$2+1CA!@>#___\`08'XX0$0``^%H0```$V%[0^%O@$```^W3B!F
-M@?F%`'=Y#[?!#[:$`V@(```\_W1J9H/Y?W<A#[;02(N+0`D``$B-!%)(C02"
-M2,'@!4B+1`A0#[9(".M&9H'Y@0!W'`^VP$B+DY`)``!(:<#(#P``2(M$$`@/
-MMD@(ZR,/ML!(BY-H"0``2(T$P$C!X`5(BX00B`````^V2`CK`T2)X;H`````
-MZ;\```!F9F:09F:0#[=.(&:!^84`#X>A````#[?!#[:\`V@(``!`@/__#X2,
-M````9H/Y?W<B0`^VUTB+BT`)``!(C0122(T$@DC!X`5(BT0(4`^V2`CK1&:!
-M^8$`=QU`#[;'2(N3D`D``$AIP,@/``!(BT00"`^V2`CK($`/ML=(BY-H"0``
-M2(T$P$C!X`5(BX00B`````^V2`B00`^VQTB-%$!(C1202,'B!4@#DT`)``#K
-M#V9F9I!F9I!$B>&Z`````$$X3@AU:$V%[70+00^W13AF.T8@=5A!@/\&=$-!
-M@?CA`1``=#H/MDI(2(G(@^`&2(/X!G4J]L$!=26`NN@`````=1Q!@?CA`0\`
-M=")$B'XDN@$```!,B??H`````.L/1(A^)`^W]4R)]^@`````@\4!9CEK=`^'
-M_?W__T&`_X$/A%<!``!(BX,``0``2(VK``$``$@YQ0^$0`$``+H`````9F9F
-MD&9FD(/"`4B+`$@YQ77U9H72#X0@`0``1(UB_TB)[^@`````2(G&387M="A!
-M#[=%.&8[1B!T'4B+@P@!``!(B;,(`0``2(DN2(E&"$B),.G(````#[=.(&:!
-M^84`=WD/M\$/MH0#:`@``#S_=&IF@_E_=R$/MM!(BXM`"0``2(T$4DB-!()(
-MP>`%2(M$"%`/MD`(ZTAF@?F!`'<<#[;`2(N3D`D``$AIP,@/``!(BT00"`^V
-M0`CK)0^VP$B+DV@)``!(C03`2,'@!4B+A!"(````#[9`".L%N/____]!.D8(
-M=2&+1C@E____`#WA`0\`=!)$B'XD2(G?Z`````#K'&9F9I!(BX,(`0``2(FS
-M"`$``$B)+DB)1@A(B3!!C40D_V9%A>1T$4@[JP`!``!T"$&)Q.GD_O__2(/$
-M"%M=05Q!74%>05_#9F9FD&9FD&9FD&9FD$B#[#A(B5PD"$B);"003(ED)!A,
-MB6PD($R)="0H3(E\)#!)B?Q)B?9)B<U!B==(BR](B>_H`````$B)PTB%P'4/
-M0<:%Z0````'IBP```&:02(GOZ`````!(B<)(A<!U%4B)WDB)[^@`````0<:%
-MZ0````'K9,9#..'&0SD!QD,Z$$2(>R5!#[9&6V:)0R!)BP0D2(E#*,=#-)``
-M``!(C4(02(E#2$B)4WC&0`$2QD(00$2(>`E(QX.@`````````$B->UB^````
-M`.@`````2(G>2(GOZ`````!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\
-M)#!(@\0XPV9F9I!(@^PX2(E<)`A(B6PD$$R)9"083(EL)"!,B70D*$R)?"0P
-M28G\28GU08G608G/2(LO2(GOZ`````!(B<-(A<`/A((```!(B>_H`````$B)
-MPDB%P'1RQD,XX<9#.0'&0SH01(AS)4$/MD5;9HE#($F+!"1(B4,HQT,TD```
-M`$B-0A!(B4-(2(E3>,9``9'&0A!`1(AP"42(>`I(QX.@`````````$B->UB^
-M`````.@`````2(G>2(GOZ`````"_H(8!`.@`````2(M<)`A(BVPD$$R+9"08
-M3(ML)"!,BW0D*$R+?"0P2(/$.,-F9I!F9I!(@^PH2(D<)$B);"0(3(ED)!!,
-MB6PD&$R)="0@28G\28GU08G62(LO2(GOZ`````!(B<-(A<!T=$B)[^@`````
-M2(G"2(7`=&3&0SCAQD,Y`<9#.A#&0R6[00^V15MFB4,@28L$)$B)0RC'0S20
-M````2(U"$$B)0TA(B5-XQD`!$,9"$$!$B'`)2,>#H`````````!(C7M8O@``
-M``#H`````$B)WDB)[^@`````2(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$
-M*,-F9F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@28G\28GU2(LO2(GO
-MZ`````!(B<-(A<!T<$B)[^@`````2(G"2(7`=&#&0SCAQD,Y`<9#.A#&0R6[
-M00^V15MFB4,@28L$)$B)0RC'0S20````2(U"$$B)0TA(B5-XQD`!`,9"$$!(
-MQX.@`````````$B->UB^`````.@`````2(G>2(GOZ`````!(BUPD"$B+;"00
-M3(MD)!A,BVPD($B#Q"C#9F:09F:055-(@^P(2(G]2(V?B!```$B)W^@`````
-MA,`/A>````!(B=_H`````(G!N`````")QH"\*.X(``#_=0HX14QS$HA%3.L-
-M@\8!2(/``4B#^`1UW4"`_@0/A*0```!`#[;&B(P%[@@```^W^4B-!+](C02'
-M2(V4Q<@!``"X`````)#&!!``2(/``4@]J````'7P#[?!2(T4@$B-%)!(P>(#
-M2(V,%?@!``!(C00J2(F(^`$``$B)B``"``!(C8P5$`(``$B)B!`"``!(B8@8
-M`@``2(V4%2@"``!(B9`H`@``2(F0,`(``$"(L-`!``!(C02_2(T$ATB-A,7(
-M`0``ZP=FD+@`````2(/$"%M=PV9F9I!(@^P82(D<)$B);"0(3(ED)!!(B?U(
-MC9_@#P``2(G?Z`````"$P`^%.0$``$B)W^@`````B<*X`````&9FD&:0B<.`
-MO"AH"```_W45#[;`9CF%^````',89HF%^````.L/@\,!2(/``4@]@````'70
-M@/N`#X3L````#[;#B)0%:`@```^WPDB-%$!(C12028G42<'D!4R)YT@#O4`)
-M``#H`````$B+E4`)```/ML-F08E$%#A(BX5`"0``0<9$!$H`2(N%0`D``$'&
-M1`1M_TB+A4`)``!!QD0$;/](BX5`"0``0<9$!&[_2(N%0`D``$'&1`1P_TB+
-MA4`)``!!QD0$;_](BX5`"0``0<9$!''_2(N%0`D``$'&A`3J`````$B+A4`)
-M``!!QH0$#P$``/](B>_H`````$B+E4`)``!)B804*`$``(!]40%U#4B+A4`)
-M``!!@$P$3`%,B>!(`X5`"0``ZP6X`````$B+'"1(BVPD"$R+9"002(/$&,-F
-M9I!32(G[Z$?A__](B[OX"```Z`````!;PV9FD&9FD&9FD$B#[!A(B1PD2(EL
-M)`A,B60D$$B)_4B-GQ@0``!(B=_H`````(3`#X7F````2(G?Z`````")PDB)
-MZ+N"____9I"`N.H(``#_=1<XG?P```!S(8B=_````.L99F9FD&9FD(/#`4B#
-MP`&`^X8/A*(```#KSH#[A@^$EP````^VPXB4!6@(```/M\)(C03`28G$2<'D
-M!4R)YT@#O6@)``#H`````$B+E6@)```/ML-F08E$%$"`?5$!=0](BX5H"0``
-M9D''1`1,__](BX5H"0``0<9$!$(`2(N%:`D``&9!QT0$3@``2(N%:`D``&9!
-MQX0$``$``/__2(N]^`@``+X`````Z`````!,B>!(`X5H"0``ZP6X`````$B+
-M'"1(BVPD"$R+9"002(/$&,-F9I!F9I!54TB#[`A(B?T/MT9`#[:<!V@(``#&
-MA`=H"```_P^W\TB-OQ@0``#H``````^WVTB-'-M(P>,%2(G>2`.U:`D``(!^
-M4/]T"$B)[^@`````2(N]^`@``+X`````Z`````!(@\0(6UW#9F:09F:09F:0
-M4TB)^P^V1EL/MK0':`@``,:$!V@(``#_#[?V2(V_4!```.@`````2(N[^`@`
-M`+X`````Z`````!;PV9FD&9FD%-(B?.`?D3_=!1(C;:0````2(M_*.@`````
-MQD-$_UO#4TB)\X"^@````/]T%TB-MC`!``!(BW\HZ`````#&@X````#_6\-F
-M9F:09F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@2(G[28GT#[=&.$0/
-MMJP':`@``$$/M\5(C11`2(T4D$B)U4C!Y05(B>Y(`[=`"0``2('&*`$``.@`
-M````00^W5"0X2(N$TV@$``!(A<!T&4B#N(``````=0](QX33:`0```````!F
-M9I!!#[=$)#C&A`-H"```_T$/M_5(C;O@#P``Z`````!(B>Y(`[-`"0``@'YR
-M_W0(2(G?Z`````!,B>9(B=_H`````$B+@T`)``#&1`5*`$B+@T`)``#&1`5+
-M`4B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:09F9FD&9FD&9FD$B#["A(
-MB5PD"$B);"003(ED)!A,B6PD($F)_4B)\V:!?CCA`0^%S@````^V1CJ#Z!$\
-M`0^'OP````^W1B!F/84`#X>*`0``#[?`#[:$!V@(``!(BY=H"0``//\/A'`!
-M```/ML!(C03`2,'@!4B-+`*`;44!3(UE*$R)Y^@`````2(G"2#G8=4I(B>Y,
-MB>_H`````$P[92@/A#0!``#'A9``````$GH`2,>%H`````````!(B:VH````
-M2(VUD````$F+?2CH`````,9%1`#I_P```$B+12A(B5`(2(D"3(EB"$B)52A(
-MBQ-(BT,(2(E""$B)$.G9````#[=#(&8]A0`/A\L````/M\!!#[:4!6@(``!)
-MBXU`"0``BT,X)?___P`]X0$0``^$I0```('Z_P````^$F0```(G02(T40$B-
-M%)!(P>(%2(TL$8"M@P````%,C64@3(GGZ`````!(B<)(.=AU2TB)[DR)[^@`
-M````3#ME('1;QX4P`0```!)Z`$C'A4`!````````2(FM2`$``$B-M3`!``!)
-MBWTHZ`````#&A8``````ZR9F9I!FD$B+12!(B5`(2(D"3(EB"$B)52!(BQ-(
-MBT,(2(E""$B)$$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9I!F9I!54TB#
-M[`A(B?M(B?4/MWXRB?IFP>H%#[?WB?&#X1^X`0```$C3X(G!]]&!XO\'```A
-M3)-X9H'__P]T1`^WQTC!X`-(`X.X"0``2(,X`'0P2,<``````"&,D\`)``!(
-MC;NH#P``Z`````!(B>Y(B=_H`````$B)[DB)W^@`````2(/$"%M=PV9F9I!F
-M9I!F9I!54TB#[`A(B?5F@7XXX0$/A:P````/MD8Z@^@1/`$/AYT````/MT8@
-MNO\```!F/84`=PL/M\`/MI0':`@``(G02(T$P$C!X`5(B<-(`Y]H"0``@'M$
-M_W5)#[:5F````(T$$H32N@@````/1,(/ML!IP$!"#P")@Y````!(QX.@````
-M`````$B)FZ@```!(C;.0````2(M_*.@`````QD-$`$B+4S!(B6LP2(U#*$B)
-M10!(B54(2(DJ@$-%`>F]````#[=%(+K_````9CV%`'<+#[?`#[:4!V@(``!(
-MBX]`"0``BT4X)?___P`]X0$0``^$B0```(G02(T40$B-%)!(P>(%2(T<$8"[
-M@````/]U4`^VE9@```"-!!*$TKH(````#T3"#[;`:<!`0@\`B8,P`0``2,>#
-M0`$```````!(B9M(`0``2(VS,`$``$B+?RCH`````,:#@`````!F9F:02(M3
-M*$B):RA(C4,@2(E%`$B)50A(B2J`@X,````!2(/$"%M=PV9F9I!F9F:09F:0
-M05=!5D%505154TB#["A)B?Y(B70D"`^W3B!F@?F%``^'!0,```^WP0^VM`=H
-M"```B?!`@/[_=&MF@_E_=R)`#[;62(N/0`D``$B-!%)(C02"2,'@!4B+1`A0
-M#[9`".M#9H'Y@0!W'4`/ML9(BY>0"0``2&G`R`\``$B+1!`(#[9`".L?0`^V
-MQDB+EV@)``!(C03`2,'@!4B+A!"(````#[9`"`^VP$4/MH0&[@@``$N-!(!)
-MC02`28V$QL@!``!(B40D$$F+EI`)``!`#[;&2&G`R`\``$R-/`)(BT0D"$B+
-M4$@/MD(!/!)T*3R1#X42`@``2XT$@$F-!("Y`````$&`O,;6`0````^$R@$`
-M`.E;`0``2XT$@$F-!(!)C03&2(N(R`$``$B)3"0@#[9*"8A,)!X/ME(:B%0D
-M'[L`````@+C6`0```'1P0;P`````2XT$@$F-!(!(P>`#38VL!B@"``!*C2PP
-M3(VUP`$``)!,B>_H`````$B)PTB+A3`"``!(B9TP`@``3(DK2(E#"$B)&$PY
-M>UAU%P^V@X$```!(BU0D"#I")7009F:09F:008/$`44X9A9WMDB+3"0(2(MQ
-M>$B%]G0*2(M\)"#H`````$B+="0(2(M\)"#H``````^V@\H```"-4`&(D\H`
-M```\`W<K@'PD'P!U)$B+1"0(#[90)4B+<UA!N`````"Y`@```$B+?"00Z```
-M``#K,XU"`8B#R@```(#Z`G8E@'PD'P!U'L9#2P+&0TK_@&-,_DB)WDB+?"0@
-MZ`````#I!0$```^V3"0?#[94)!Y,B?Y(BWPD$.@`````Z>D```"]`````$N-
-M!(!)C02`2,'@`TV-I`8H`@``2HT<,$R-J\`!``!,B>?H`````$B)P4B+@S`"
-M``!(B8LP`@``3(DA2(E!"$B)"$PY>5AU%`^V@8$```!(BU0D"#I")70,9F:0
-M@\4!03AM%G>Z#[912$B)T(/@!DB#^`9U'/;"`7072(M$)`@/ME`E2(MQ6$B+
-M?"00Z`````!(BU0D"$B+<GA(A?9T"$R)]^@`````2(MT)`A,B??H`````.LN
-M1`^VA^T)``!+C02`28T$@$B-A,?(`0``2(E$)!!(BY>0"0``N#BX#P#I?OW_
-M_TB#Q"A;74%<05U!7D%?PV9FD&9FD&9FD$%505154TB#[`A)B?U)B?1(B=/&
-M0DL!QD)*`+X&````3(GGZ`````!(@WM8`'072(M3$$B+0QA(B4((2(D02(M#
-M6(!H6`&`NX,`````=!R03(GOZ`````"_`0```.@`````@+N#`````'7E2(N[
-M(`$``$B%_W01#[:S#0$``+H!````Z`````!(BWM82(7_=!$/MK.!````N@$`
-M``#H`````$B+:T!(A>T/A(H```!(@[V``````'5P2(.]B`````!U9O9#3`1U
-M&4R)[^@`````2(MS0+H!````3(GOZ`````!(BT-`#[90`@^V<`%(Q\<`````
-MN`````#H`````$B+4T!)B[7X"```OP$```#H`````$B+4T!)B[7X"```OP8`
-M``#H`````$C'0T``````2,=%8`````!(BU-@2(72=!`/MH.!````2,=$PE@`
-M````2(L32(M#"$B)0@A(B1!!@&PD#@%(B=Y,B>_H`````$&`?"0)_W1=08!\
-M)`X`=$2[`````$F-;"1@9F:09I!(B>_H`````$F+5"1H28E$)&A(B2A(B5`(
-M2(D"@'A*_W4,@\,!03A<)`YV">O203A<)`YW$4'&1"0)_TR)YDR)[^@`````
-M2(/$"%M=05Q!7<-F9F:09F9FD&9F9I!F9I!!5T%6055!5%532(/L"$F)_TF)
-M]DB)U<9"2P'&0DH`O@8```!,B??H`````$B#?5@`=!=(BU402(M%&$B)0@A(
-MB1!(BT58@&A8`8"]@P````!T&TR)_^@`````OP$```#H`````("]@P````!U
-MY4B+O2`!``!(A?]T$0^VM0T!``"Z`0```.@`````2(M]6$B%_W01#[:U@0``
-M`+H!````Z`````!(BUU`2(7;#X01`0``]D5,!'5-3(G_Z`````!(BW5`N@$`
-M``!,B?_H`````$B+14`/ME`"#[9P`4C'QP````"X`````.@`````2(M50$F+
-MM_@(``"_`0```.@`````ZRX/ME,"#[9S`4C'QP````"X`````.@`````2(M5
-M0$F+M_@(``"_`0```.@`````2(N+@````$B%R0^$-P$```^W13A)QX3':`0`
-M``````!(QX.``````````$B+NY````"Z_____TB)WO_1Z08!```/MT4X2<>$
-MQV@$````````2,>#B`````````!(B[N0````_]+V14P"=!5(BU5`28NW^`@`
-M`+\&````Z`````!(QT5``````$C'0V``````2(M58$B%TG00#[:%@0```$C'
-M1,)8`````$B+50!(BT4(2(E""$B)$$$/ME8.@^H!08A6#DB+16!(A<!T!V:#
-M>$X"=5F$TG150;P`````38UN8$R)[^@`````2(G#28M&:$F)7FA,B2M(B4,(
-M2(D82(7;=!_V0TP"=!E(BU-`28NW^`@``+\&````Z`````"`8TS]08/$`44X
-M9@YWM4B)[DR)_^@`````2(/$"%M=05Q!74%>05_#2(N3B````$B%T@^%ZO[_
-M_^D)____D$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)^TB+1U!,BRA,B>_H
-M`````$B)Q4B%P`^$U0```$R)[^@`````28G$2(7`=1K&@^D````!2(GN3(GO
-MZ`````#IK@```&9FD,9%.*!(C54YN`````!F9I#&!!``2(/``4B#^`5U\L9%
-M/@#&13\`QD5``,9%08C&14(`QD5#`,9%):L/MT,X9HE%($R);2C'A90````(
-M````QT4TB````$F+1"002(E%2$@%B````$B)15#&13`D3(EE>$C'A:``````
-M````2(U=6+X`````2(G?Z`````!)BW0D&+J(````2(G?Z`````!(B>Y,B>_H
-M`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:09F9FD&9F9I!54TB#
-M[`A(B?U(C9]0$```2(G?Z`````"$P`^%"`$``$B)W^@`````B<*Y@/___X"]
-MZ`@``/]T$H"]Z0@``/\/A>,```"Y@?___SB-^P```',&B(W[````@/F"#X3'
-M````#[;!B)0%:`@```^WPDAIV,@/``!(B=I(`Y60"0``N`````#&!!``2(/`
-M`4@]R`\``'7P2(G:2`.5D`D``$B-0AA(B4(82(G:2`.5D`D``$B-0AA(B4(@
-M2(G:2`.5D`D``$B-0BA(B4(H2(G:2`.5D`D``$B-0BA(B4(P2(G:2`.5D`D`
-M`$B-0DA(B4)(2(G:2`.5D`D``$B-0DA(B4)02(N%D`D``(A,`UM(B[WX"```
-MO@````#H`````$B)V$@#A9`)``#K!;@`````2(/$"%M=PV9F9I!F9F:09F9F
-MD$%44TB#[`A)B?1(BY_@$```2(''J`\``.@`````B<$/M\!(P>`&2`'828D$
-M)+H`````Q@0"`$B#P@%(@_I`=?(/M\%(@\0(6T%<PV9FD&:02(/L"$B-EU`!
-M``"X`````$@YEU`!``!T"$B)U^@`````2(/$",.0D)"0D)"0D)"00`^V]DB-
-M-/9(P>8'@<9@5P``B3?#9F9FD&9F9I!F9I`/MM(/MT16>(/``6:)1%9X#[96
-M`@'0#[?`PV9FD&9FD+@!````@+^[0@```703@\`!2(''L````(/X('7H9KC_
-M__/#9F9FD&9FD&9FD&9FD$B)^;@!````0#BQN$(``'4?.)&Y0@``=1>)P$B-
-M%(!(C1102,'B!,:$%PM"```!PX/``4B!P;````"#^"!UR?/#9F9FD&9F9I!F
-M9F:09F:0Q@'^1`^V5P1%A-)T3DF)^$&Y`````$&[`````+@`````23FPV%D`
-M`'4>03C3=15(F$B-!,!(P>`'#[:$!\17``"(`<-!@\,!08/!`8/``4F!P(`$
-M``!%.-%UQO/#9F:028GZ@/H!=!A$#[9'!+\`````183`#X1P`0``Z4$!``!!
-MNP````!-A<`/A!P!```/ME<$0;L`````A-)T-$B)^$&[`````$&Y`````&9F
-M9I!(.;#860``=0E!.,ET$T&#P0%!@\,!2`6`!```03C3==]!#[;[2&//2(T,
-MR4C!X0=)C90*8%<``$B+`DF)`$B+0@A)B4`(2(M"$$F)0!!(BT(828E`&$B+
-M0B!)B4`@2(M"*$F)0"A(BT(P28E`,$B+0CA)B4`X2(M"0$F)0$!(BT)(28E`
-M2$B+0E!)B4!02(M"6$F)0%B+0F!!B4!@08"\"F!7````=%.^`````$ACQTB-
-M!,!(C3S%`````$Z-#!%`#[;&2(G"2,'B!$F-3!!@2(T$!TC!X`1)C90"X%D`
-M`$B+`DB)001(BT((2(E!#(/&`4$XL6!7``!WQ4$/ML-(C03`2,'@!T$/MH0"
-M8%<``,-,B=*Y`````+\`````9I!(.;+860``#Y3``<>#P0%(@<*`!```1#C!
-M=>5`#[;'PT%505154TB)\TF)U4V)S$&)R42)Q4F)^+X`````9F:0B?%(.5\@
-M#X6%````2&/&2&G`4!```$V-5``@0;L`````1(G:00^V0BR$P'0$//!U3TAC
-MTDACR4B)T$C!X`5(:<E0$```2`'(3`'`2(E8,$R):#A(P>(%2(U4"B!*C00"
-M2(U((&:):0)$B$@@28L$)$F)1!`DQD$,_^L69F:09I!!@\,!28/"($&!^X(`
-M``!UD(/&`4B!QU`0``"#_@0/A5S___];74%<05W#9F:09I!!54%455-(@^P(
-M28GU2(G]@'\$`'1&0;P`````9F9FD$$/MMQ(8\-(C03`2,'@!X"\!<17``#]
-M=!E(C;P%O%<``+H(````3(GNZ`````"$P'4/08/$`40X901WQ+O_````B=A(
-M@\0(6UU!7$%=PV:04TB)^^@`````N@D````\_W03#[;`2(T$P$C!X`</MI0#
-M9E<``(G06\-F9F:09F:02(/L"$F)\DF)T42)PDB)_DR-AV!!``"X`````&9F
-M9I!"Q@0``$B#P`%(/9````!U[\:&84$``!/&AF!!``!`#[;&B(9F00``B)9G
-M00``B(YI00``2,>&`$(```````!(B;[X00``28M!7$B)AO!!``!(@<9@00``
-M3(G7Z`````!(@\0(PV9F9I!F9F:09F:0055!5%532(/L"$F)]4F)U$R)S4&)
-MR42)PTB)^$F)^KH!````08G308G0@+B[0@```0^%[@```$ACTDB-!))(C01"
-M2,'@!$P!T$B-D`!"``#&0@L`3(F0^$$```^V2@I(8\%(C12`2(T44$C!X@1)
-MC9028$$``+@`````9F:09I#&!!``2(/``4@]D````'7P2&/!2(TT@$B--'!(
-MP>8$2HT4%DB-BF!!``#&00&0QH)@00``0`^VQXA!!HB:9T$``$2(20E(BT4`
-M28F$,G!!``!)8\!(C12`2(T44$C!X@1*C0022,>``$(```````!(B;CX00``
-M28M$)%Q)B802\$$``$$/ML-(C12`2(T44$C!X@1)C;028$$``$R)[^@`````
-MZQ>#P@%(!;````"#^B`/A>W^__^X`0```$B#Q`A;74%<05W#9F:09F:09F:0
-M2(/L"$F)\T&)TDB)^DF)^+@!````B<:`NKM"```!#X7A````2)A(C12`2(T4
-M4$C!X@1)C800`$(``$2(4`B(2`G&0`L`1`^V2`I)8\%(C12`2(T44$C!X@1)
-MC9008$$``+@`````Q@00`$B#P`%(/9````!U\$ECT4B-!))(C01"2,'@!$P!
-MP$B-D&!!``#&0@$0QH!@00``0(A*"4ACQDB-#(!(C0Q(2,'A!$$/MH0("D(`
-M`$B-%(!(C1102,'B!$J-!`)(QX``0@```````$B)N/A!``!!#[;"2(T$P$C!
-MX`=)BX0`O%<``$F)A`CP00``28VT$&!!``!,B=_H`````.L5@\`!2('"L```
-M`(/X(`^%_?[__[`!2(/$",.02(/L"$F)\8G02(G^QH<+0@```$R-AV!!``"Y
-M`````)!"Q@0!`$B#P0%(@?F0````=>[&AF%!```!QH9@00``0$C'A@!"````
-M````2(F^^$$```^VP$B-!,!(P>`'2(N$!KQ7``!(B8;P00``2('&8$$``$R)
-MS^@`````2(/$",-(@^P(28GQB=!(B?[&APM"````3(V'8$$``+D`````D$+&
-M!`$`2(/!`4B!^9````!U[L:&84$```#&AF!!``!`2,>&`$(```````!(B;[X
-M00``#[;`2(T$P$C!X`=(BX0&O%<``$B)AO!!``!(@<9@00``3(G/Z`````!(
-M@\0(PT%7059!54%455-(@^PX2(E\)!A(B70D$$&)U42(1"0/28G\10^V]4EC
-MQDB-!,!(P>`'@+P'Q%<``/T/A,8(``"`^1`/A(4"``"`^1!W%X3)#X2=````
-M@/D!#X6G"```D.D&`0``@/GB=!N`^?]F9I!T*8#YD`^%BP@``&9FD&:0Z<@&
-M``"Y`````(!_!`!FD`^%W`<``.D$"```26/&2(T$P$C!X`?&A`?$5P``_X"_
-M"T(```%U)42)\DB+="002(M\)!CH`````(7`#X4U"```08!$)`8!Z2H(``!)
-M8\;&1`<'`4B+5"002(E4QQ#I$P@``("_"T(```%U6$B-CV!!``!)8\9(C03`
-M2,'@!T@!^`^V40F(D&)7``!(!<!7```/ME$*@^(!B%`%QD`$`$2)\DB+="00
-M2(M\)!CH`````(7`#X6]!P``08!$)`8!Z;('``!)8\;&1`<'`4B+3"002(E,
-MQQ#IFP<``$ECQDB-!,!(P>`'2(TT.`^VEY)!``"(EK)7```/MY>000``9HF4
-M![!7``!(BY>(00``2(F4!Z!7``!(BY=L00``2(F4!W!7``!(C8P'@%<``$B+
-MEW1!``!(B1%(BY=\00``2(E1"(N7A$$``(F4!YA7``#&AL17```!@'\&'P^$
-M%P<``+L`````2(VN8%<``$R-KK!7``#K20^VRT2)\DB+="002(M\)!CH````
-M`(7`=!5)8\9(C03`2,'@!T&(G`2S5P``ZR"#PP%!@$0D!@$X70(/1<-!B$4#
-M08!\)`8?=`4Z70)RLD'&A"0+0@```4$/MG0D!$"$]@^$G`8``+H`````08!\
-M)`<!=!?K0V9F9I!F9I`/MM%(8\)!@'P$!P%U,TACPD'&1`0'_TF+=,000;D`
-M````0;@`````N?\```!(BWPD&.@`````Z4H&``"Y`````(/!`4`X\76WZ3@&
-M``!-B<])C4$82(E$)"!(C70D,$F+01A(B40D,$ECQDB-!,!(P>`'2(TL.$B-
-MA<!7``#&0`000?9!#'`/A$(#``!(BY7(5P``2(72='$/ME@&2(UZ7+H(````
-MZ`````"$P'5;0?9'#P]T5$B+A<A7``!(A<!T2$B)Q8!]90!T/P^VVXG:2(GN
-M3(GGZ`````!,BTPD($0/M\")V4B)ZDB+="002(M\)!CH``````^V769(BT5H
-M2(7`=`5(B<7KNT$/MD\/]L$-#X3K````26/&2(T4P$B)T$C!X`=!#[:T!&!7
-M``!`@/X?#X?*````]L$(=!=`#[;&2(T$T$C!X`1!QH0$X%D```;K'$`/MM9)
-M8\9(C03`2(T$PDC!X`1!QH0$X%D```=`#[;&26/V2(TT]DB-%/!(P>($28V\
-M%.!9``#&1P$`00^V1P^(1P-(BT0D,$F)A!3H60``00^V1PF(1P)!#[97#8/B
-M#TC!Y@=,`>9(C8Y@5P``#[9!!CC"#T?0@^(/#[9'!(/@\`G0B$<$00^V5RF#
-MX@\/MDD&.,H/1]'!X@2#X`\)T(A'!("&8%<```'IS`$``/;!`@^$PP$``$B-
-M="0P3(GGZ`````")P3S_#X5B`0``00^V3"0$A,ET/4$/MH0DQ%<``#S_=#"Z
-M`````#S]=1[K)0^VPDB-!,!(P>`'00^VA`3$5P``//]T$CS]=`Z#P@$XRG7=
-MZP6Z``````^VPDB-!,!(P>`'28V,!&!7``"X`````,8$"`!(@\`!2(/X9'7R
-M1`^VTDECTDB-%-)(P>('2HT\(D$/ML5(C03`2,'@!TF-A`1@5P``2(F'R%<`
-M`$V-A!2P5P``26/62(T4TDC!X@=)BX04O%<``$F)0`1(BTPD$$B)C]A9``!,
-M`>)(BX+05P``2(F'T%<``$R-C\!7``!!QD$$_TB-MV!7```/MDX'00^V1PF(
-MA`]H5P``@$8'`4$/MD<-@^`/#[:29E<``#C0#T?"B$8&2(M$)#!)B4`,00^V
-M1P^(1@,/MD0D#T&(009!#[9$)`5!.D0D!'4&0<9$)`4`08!$)`4!26/"0<9$
-M!`<!2(M4)!!)B53$$.M*26/&2(T$P$C!X`</MM%(C1322,'B!TF-E!1@5P``
-M23F4!,A7``!T(@^VP4B-!,!(P>`'3`'@#[9R!T$/MD\)B(PP:%<``(!"!P%!
-M#[97"42)]DR)Y^@`````26/&2(T$P$C!X`=!@+P$LU<````/A*````!!@'PD
-M!A]U8^F``@``0<9'!!`/MDL#1(GR2(MT)!!(BWPD&.@`````A<`/A5T"``!!
-M@$0D!@$/MDL##[;!@\`!#[95`CG0=0_&0P,`Z3P"``!F9I!F9I"-00&(0P-!
-M@'PD!A\/A"0"``#K(TECQDB-!,!(P>`'3`'@2(V8L%<``$B-J&!7``!,C;C`
-M5P``#[9#`SI%`@^"<O___^GM`0``08!\)`8`#X7A`0``0;D`````0;@`````
-MN9````!$B?)(BW0D$$B+?"08Z`````#IN0$``$F)_4&_`````$B+3"0023E-
-M(`^%@P```$2)^$AIP%`0``!)C5P$(+T`````1(GX2&G`4!```$B)!"2`>RS_
-M=4I!@'PD!A\/A&T!``")Z$C!X`5(BQ0D2(U$$$`/MDL@2(M3&$V-3`0$1`^W
-M0R)(BW0D$$B+?"08Z`````"%P'4*08!$)`8!QD,L\$B#Q0%(@\,@2(']@@``
-M`'6?28/'`4F!Q5`0``!)@_\$#X59____08!\)`8`#X7]````00^V="0$0(3V
-M#X3+````N@````!!@'PD!P%T$.L\#[;12&/"08!\!`<!=3-(8\)!QD0$!_])
-MBW3$$$&Y`````$&X`````+G_````2(M\)!CH`````.FC````N0````"#P0%`
-M./%UM^MQ#[;!2(T$P$C!X`=)C90$P%<```^V0@0\_70(//]T!,9"!/Z#P0%!
-M.$PD!'?326/&2(T$P$C!X`=)BZP$T%<``+L`````0H!\(R@!=1)"QD0C*`!*
-MBW0C($B+?"08_]5(@<-0$```2('[0$$``'0EZ]1!N0````!!N`````"YX@``
-M`$2)\DB+="002(M\)!CH`````$B#Q#A;74%<05U!7D%?PV9F9I!F9F:09F:0
-M2(/L&$B)'"1(B6PD"$R)9"0028G\2(GU2(N>F````(![!@`/A$<!``!(C;:0
-M````2(G?Z`````")P3S_#X0N`0``2(GN#[9%`3P!=%H\`7(:/!`/A(H````\
-MD&9FD&:0#X4*`0``Z<8```"`NPM"````#X7X````QH,+0@```8!K!@$/MM%!
-MN0````!!N`````"Y`````$R)YDB)W^@`````Z<D```"`NPM"````#X6\````
-MQH,+0@```8!K!@$/MM%!N0````!!N`````"Y`0```$R)YDB)W^@`````Z8T`
-M``"Z`````#J,&KA"``!U#P^VA!JY0@``.D8)=!)FD$B!PK````!(@?I0%0``
-M==B`:P8!#[;128GQ1`^V1@FY$````$R)YDB)W^@`````ZS\/MH6J````2(T4
-M@$B-%%!(P>($QH03"T(```&`:P8!#[;10;D`````0;@`````N9````!,B>9(
-MB=_H`````)!(BQPD2(ML)`A,BV0D$$B#Q!C#9F9FD&9FD&9FD&9FD$&)T(GR
-MA?9T%$B)^4B)T)#&`0!(@\$!2(/H`77SB3=(@>I@5P``2+B/XSB.XSB.XTCW
-MXDC!Z@I!.-!!#T+0B%<$A-)T*[H`````9F:09F:0#[;"QD0'!_](C03`2,'@
-M!\:$!\17``#]@\(!.%<$=^#&1P8`QD<%`$B)^+H`````QH`+0@```8B0"D(`
-M`(/"`4@%L````(/Z('7E\\-F9I!(B?F`?P0`#X29````OP````!$#[;'26/`
-M2(T$P$C!X`=(.;0!V%D``'5NN`````!`.+P(N$(``'4(QH0(NT(```%(!;``
-M``!(/5`5``!UX$ECP$B-!,!(P>`'2,>$`=A9````````2(V4`6!7``"X````
-M`,8$$`!(@\`!2(/X9'7R26/`2(T$P$C!X`?&A`'$5P``_8!I!0&#QP%`.'D$
-M#X=L____2(G/0;@`````2#EW('4P2,='(`````#&1R@`26/`2&G`4!```$B-
-M1`$@N@````#&0"P`@\(!2(/`((#Z@G7P08/``4B!QU`0``!!@_@$=;GSPV9F
-M9I!F9F:0055!5%532(/L"$B)_4B)]TF)U$V)Q4&)R$B)ZP^V104Z101U!,9%
-M!0!$#[9;!4B)WDF)V;@`````08G"B<))BTD@2#GY=4M(F$AIP%`0``#&1`,H
-M`0^V2P1!NP````"$R71D0;L`````2#F^V%D``'4.#[:&Q%<``(/``SP!=D=!
-M@\,!2('&@`0``$$XRW0WZ]=(A<EU&4ACPDAIP%`0``!(`=A(B7@@QD`H`>L9
-M9I!!@\(!@\`!28'!4!```(/X!`^%<O___T$/ML)(:<!0$```2(U$`S"Y````
-M`&9F9I#&!`$`2(/!`4B!^0(0``!U[T4/MM-)8\)(B7S#$$$/ML-(C03`2,'@
-M!TB-A`-@5P``9KD``,8$`0!(@\$!2(/Y9'7R26/"2(T$P$C!X`=(C8P#V%<`
-M`+@`````9F:09I#&!`@`2(/``4@]``(``'7P26/"2(T$P$C!X`=(C0P82(FY
-MV%D``$R)J=!7``#&@<17``#_2,>!R%<```````!)BQ0D2(F4`[Q7``!$B(%F
-M5P``0;D`````0;@`````N?\```!$B=)(B?Y(B>_H`````(!#!0%(@\0(6UU!
-M7$%=PTB+!TR+``^V<$-`A/9T1P^V5PVY`````/;"`70-ZS>02(G02-/XJ`%U
-M"(/!`4`X\77N@/D#=B1(C02-`````"7\`P``28V$`-`!``"+`(D%`````.LB
-MN0````!(C02-`````"7\`P``28V$`-`!``"+`(D%`````,'H%(/@`<.02(L'
-M1`^V0$-!N0H```!%A,!T2@^V?PU(B<*^`````$&Y"@```+D`````9F:09F:0
-M2(GX2-/XJ`%T%`^V@O(2``"#X`.#P`A!.,%$#T?(@\8!@\$!2(/":$0XQG73
-M00^VP<-F9F:09F9FD&9FD&9FD$B+!T0/MD!#0;D(````183`=$H/MG\-2(G"
-MO@````!!N0@```"Y`````&9FD&9FD$B)^$C3^*@!=!0/MH+R$@``@^`#@\`(
-M03C!1`]"R(/&`8/!`4B#PFA$.,9UTT$/ML'#9F9FD&9F9I!F9I!F9I`/M@?`
-MZ`2#X`</MG<"B<*`S@)`]L8$#T7"#[9/`XG"@<H```(`]L$$#T7"B<*`S@A`
-M]L8(#T7"B<*!R@``"`#VP0@/1<*)PH#.!$#VQ@(/1<*)PH'*```$`/;!`@]%
-MP@^V5Q3!XA@)T,-F9F:09F:0Z`````#SPV9FD&9FD&9FD(N'&`D``"7___\`
-MN@`````]4`&3`'49#[:'&PD``,#H!#P,#Y3`#[;09F9FD&9FD(G0PV9F9I!F
-M9I!F9I!F9I"%]GY"#[8'A,!T!#P@=3%(B?JY`````.L79F9FD&9FD`^V0@%(
-M@\(!A,!T!#P@=1"#P0$Y\77IZPUF9F:09F:0N`````##N`$```!F9I!FD,-F
-M9F:09F9FD&9F9I!F9I`/MD<##[97`L'B"`G0P>`0#[9/`0^V%\'B"`G1"<C#
-MD$&)T(72="6Y`````&9F9I`/MA</MD<!B`:(5@%(@\8"2(/'`H/!`40YP77D
-M\\-FD$B#[`A)B?`/MT8@NO\```!F/84`=PL/M\`/MI0':`@```^WTDB-%-)(
-MP>(%2`.7:`D``$B+MQ`1```/MD)0P>`(2)A(C80&3`@``(L(B0T`````@>'_
-M````#[9"4,'@"$B82(VT!D0(``"+!HD%`````,'@"`G(B8(0`0``9L>"#`$`
-M````3(G&Z`````!(@\0(PV9F9I!F9I!F9I!F9I!(@^PH2(E<)`A(B6PD$$R)
-M9"083(EL)"!)B?U!B?1(BR]`@/X#=CE*C1SE`````('C^`<``$B-A!TP`@``
-MQP`,````OQ`G``#H`````$B-A!TT`@``BSB)/0````#K-Y!*C1SE`````('C
-M^`<``$B-A"M0`@``QP`,````OQ`G``#H`````$B-G"M4`@``BSN)/0````!!
-M#[;T2&/&2(T40$B-%)!)C935P!(```^V2@F#X?R(2@F)^"4``#\`/0``$`!U
-M"XG(@\@"B$()ZQF02&/&2(T40$B-%)")R(/(`4&(A-7)$@``2(M<)`A(BVPD
-M$$R+9"083(ML)"!(@\0HPV9F9I!F9F:09F9FD&9FD$%7059!54%455-(@^P8
-M28G^3(L_28L'QD9)`,9&2`7&1DL&2(E^4+D`````O0````!(C9```@``2(E4
-M)!!(!00"``!(B40D".L69F:09F:000^V1@U(T_BH`74*@\$!D$$Z3T-RZH#Y
-M`W9Z2(T<S0````"!X_@'``!,BVPD$$D!W4''10`L````OQ`G``#H`````$@#
-M7"0(1(LC1(DE`````$''10`D````OQ`G``#H`````(L#B04`````P>`(08'D
-M_P```$$)Q$''10`@````OQ`G``#H`````(L;B1T`````ZWA(C1S-`````('C
-M^`<``$R+;"0020'=0<=%`"P```"_$"<``.@`````2`-<)`A$BR-$B24`````
-M0<=%`"0```"_$"<``.@`````BP.)!0````#!X`A!@>3_````00G$0<=%`"``
-M``"_$"<``.@`````BQN)'0````!!@?P!`6F6=1I!@$X,!HG8P>@0/%`/E,`/
-MML#K2&9FD&9FD$&!_`$!``!U#XG8P>@0/%`/E,`/ML#K*K^($P``Z`````"#
-MQ0%`@/T$=PJY`````.FK_O__B=C!Z!`\4`^4P`^VP$B#Q!A;74%<05U!7D%?
-MPV9F9I!F9F:09F9FD&9FD$%505154TB#[`A(B?U!B?1(BX>(````3(LH9H._
-M#`$```!T,(GSO^@#``#H`````$6%Y'0%@_L!=AI,B>]F9I#H`````&:#O0P!
-M````=`6#ZP+KTDB#Q`A;74%<05W#D$B#[#A(B5PD"$B);"003(ED)!A,B6PD
-M($R)="0H3(E\)#!)B?R)RT&)]D&)U46)QTB+AX@```!(BRA(B>_H`````$B)
-MQL9`..'&0#D!QD`Z$K@/````183V=09!#[9$)$>(1CM$B&X\3(GJ#[;&B$8]
-M#[;'B$8^B=C!Z!"(1C^)V,'H&(A&0(A>04$/MT0D0&:)1B!(B6XHQT8T````
-M`$C'1D@`````183_2,?``````$C'P@````!(#T7"2(F&H````$B)[^@`````
-M2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$.,-FD$B#["A(B1PD
-M2(EL)`A,B60D$$R);"083(ET)"!)B?R)RT&)]D&)U4B+AX@```!(BRA(B>_H
-M`````$B)QL9`..'&0#D!QD`Z$K@/````183V=09!#[9$)$>(1CM$B&X\3(GJ
-M#[;&B$8]#[;'B$8^B=C!Z!"(1C^)V,'H&(A&0(A>04$/MT0D0&:)1B!(B6XH
-MQT8T`````$C'1D@`````2,>&H`````````!(B>_H`````$B+'"1(BVPD"$R+
-M9"003(ML)!A,BW0D($B#Q"C#9I!32(G[08G*08G12(7_#X0!`0``3(L'387`
-M#X3U````00^V>$.%_WY72(N#B`````^V4`VY`````/;"`70-ZT"02(G02-/X
-MJ`%U!X/!`3GY=>^#^0-^+DF+`$@%T`$``(T4C0````!(8])(`="+`(D%````
-M`,'H%(/P`8/@`>LLN0````!)BP!(!=`!``"-%(T`````2&/22`'0BP")!0``
-M``#!Z!2#\`&#X`&$P'5E@+L<`0```'4&@'M"`'56#[=#0$&`O`!H"```_W1'
-MQD-")6;'@PP!```!`$$/M]%`#[;V0;@!````1(G12(G?Z`````"^!0```$B)
-MW^@`````QD-"`&:#NPP!````#Y3`#[;`ZP6X`````%O#9F:09I!(@^PH2(E<
-M)`A(B6PD$$R)9"083(EL)"!(B?U!B?5!B=1(BX>(````2(L82(G?Z`````!(
-MB<;&0#CAQD`Y`<9`.A&X#P```$6$[74$#[9%1XA&.T2(9CQ,B>(/ML:(1CT/
-MMT5`9HE&($B)7BC'1C0`````2,=&2`````!(QX:@`````````$B)W^@`````
-M2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9FD&9FD&9FD%532(/L"$B)^TB)
-MS4&)T4B%_P^$!@$``$R+!TV%P`^$^@```$$/MGA#A?]^5DB+@X@````/ME`-
-MN0````#VP@%T#.L_2(G02-/XJ`%U!X/!`3G/=>^#^0-^+DF+`$@%T`$``(T4
-MC0````!(8])(`="+`(D%`````,'H%(/P`8/@`>LLN0````!)BP!(!=`!``"-
-M%(T`````2&/22`'0BP")!0````#!Z!2#\`&#X`&$P'5K@+L<`0```'4&@'M"
-M`'5<#[=#0$&`O`!H"```_W1-QD-")6;'@PP!```!`$$/M]%`#[;VN0$```!(
-MB=_H`````+X%````2(G?Z`````#&0T(`9H.[#`$```!U$(N#$`$``(E%`+@!
-M````ZP6X`````$B#Q`A;7<-F9I!F9I!(@^PH2(D<)$B);"0(3(ED)!!,B6PD
-M&$R)="0@2(G]08GU08G408G.2(N'B````$B+&$B)W^@`````2(G&QD`XX<9`
-M.0'&0#H1N`\```!%A.UU!`^V14>(1CM$B&8\3(GB#[;&B$8]#[=%0&:)1B!(
-MB5XHQT8T`````$C'1D@`````183V2,?``````$C'P@````!(#T7"2(F&H```
-M`$B)W^@`````2(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9F:09F:0
-M9F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@2(GU08G408G-2(L?2(G?
-MZ`````!(B<)(A<!U$,:%Z0````'&14H#Z90```#&0#CAQD`Y`4&`_`$9P/?0
-M@\`"B$(Z183M=5&X`````$B#?6``=`</MH6!````B$([#[=%.&:)0B!(B5HH
-MQT(T`````$C'0D@`````2,?``````$B)@J````!(B=9(B=_H`````.LM9F:0
-M9I#&0CL/#[=%.&:)0B!(B5HHQT(T`````$C'0D@`````2,?``````.N_2(M<
-M)`A(BVPD$$R+9"083(ML)"!(@\0HPV9F9I!F9F:09F9FD&9FD$%7059!54%4
-M55-(@^PXB?5)B=1(BP^-%.T`````C4+@B<!(C9P((`(``$B)'"1(C80()`(`
-M`$B)1"0(B=),C;P*``(``$R-K`H$`@``NP````!,C70D$(/]`W8EC8,<`0``
-M2(L4)(D"OQ`G``#H`````$B+5"0(BP*)!0````#K'8V#'`$``$&)![\0)P``
-MZ`````!!BT4`B04`````0HD$,TB#PP1(@_L<=:M(BT0D$$F)!"1(BT0D&$F)
-M1"0(2(M$)"!)B40D$(M$)"A!B40D&$B#Q#A;74%<05U!7D%?PV9F9I!F9F:0
-M9F9FD&9FD$%7059!54%455-(@^PXB?5)B=1(BP^-%.T`````C4+@B<!(C9P(
-M(`(``$B)'"1(C80()`(``$B)1"0(B=),C;P*``(``$R-K`H$`@``NP````!,
-MC70D$(/]`W8EC8,``0``2(L4)(D"OQ`G``#H`````$B+5"0(BP*)!0````#K
-M'8V#``$``$&)![\0)P``Z`````!!BT4`B04`````0HD$,TB#PP1(@_L<=:M(
-MBT0D$$F)!"1(BT0D&$F)1"0(2(M$)"!)B40D$(M$)"A!B40D&$B#Q#A;74%<
-M05U!7D%?PV9F9I!F9F:09F9FD&9FD$%7059!54%455-(@^PX28G^0(AT)`M,
-MBS]$#[;N26/%2(T40$B-%)!(C1372(V"P!(``$"(<`A(B;K`$@``QD`*`$2)
-M[N@`````2(UL)!!(B>A(B>K&``!(@\`!2(G33(UD)#!,.>!U[`^V1"0+B40D
-M#(G&3(GWZ`````!(B=_H`````$ECU4B-#%)(C0R*2,'A`TJ-%#&)@M@2``!(
-MBT,,28F$#MP2``"`?"0+`W8\0HT$K0````!(F$F-A`?0`0``BP")!0````")
-M@O`2``!"C03M`````$B828V$!X`!``"+"(D-`````.M'0HT$K0````!(F$F-
-MA`?0`0``BPB)#0````!)8\5(C11`2(T4D$&)C-;P$@``0HT$[0````!(F$F-
-MA`>``0``BPB)#0````!)8\5(C11`2(T4D$F-!-:)B/02``#V@/(2```0#X0[
-M`0``]H#)$@```G109I#&10``2(/%`4PYY77S2(U<)!!(B=J+="0,3(GWZ```
-M``!(B=_H`````$ECU4B-#%)(C0R*2,'A`T&)A`[D$@``2(M##$F)A`[H$@``
-MZQ=)8\5(C11`2(T4D$''A-;D$@```0`"`(!\)`L#=C5"C1SM`````$ACVTJ-
-MA#LP`@``QP`8````OQ`G``#H`````$J-G#LT`@``BS.)-0````#K,T*-'.T`
-M````2&/;2HV$.U`"``#'`!@```"_$"<``.@`````2HV<.U0"``"+,XDU````
-M`$ECQ4B-%$!(C120B?&!X?___]^)\`T````@0?>$UO`2``````,`B<H/1="`
-M?"0+`W860HT$[0````!(F$F-A`<T`@``B1#K%$*-!.T`````2)A)C80'5`(`
-M`(D02(/$.%M=05Q!74%>05_#D$%6055!5%532(G]28GV28GU#[<&9H7`>0LE
-M`!\``,'X"(A'24B-O80```!)C54428M%%$B)A80```!(BT((2(E'"(M"$(E'
-M$$R-I<````!)BT4N2(F%P````$B-G9@```!)C54V28M%-DB)A9@```!(BT((
-M2(E#"$B+0A!(B4,02(M"&$B)0QA(BT(@2(E#(+H*````2(G^Z#/P__^Z!```
-M`$R)YDR)Y^@C\/__NA0```!(B=Y(B=_H$_#__V;'16@``&;'16H``&9!@[ZR
-M`0```0^4PL'B`P^V14R#X/<)T(A%3$'VA:<````$=`9FQT5H`0!!]H6D````
-M`70D9H--:`)!]H6J`````70%9H--:@%!]H6H`````70&9H%-:``!0?:%I```
-M`"!T%&:#36@$0?:%J@```"!T!6:#36H"0?:%I````$!T%F:!36B``$'VA:H`
-M``!`=`9F@TUJ")#&A8(````"0?:%F0````%T,@^W16BH`70,@\@(9HE%:&:#
-M36H000^VA98```"#X!^#P`$\(+H?````#T3"B(6"````0?:%F`````AT!F:!
-M36@``D'VA9@````$=`5F@TUH($'VA9@````"=`5F@TUH$$'VA:@````@=!5!
-M]H6N````('0+9H--:$!F9I!F9I#V16@!=`U)BX7(````2(E%>.L(08M%>$B)
-M17A(@VUX`4'V16H"=!I!#[>%@````*@/=`YF@_@"&<"#P`2(16SK!,9%;`+&
-M16W_00^W57X/M\*H!'0+QD5M`NL;9F:09I"H`G0&QD5M`>L,]L(!9F:0=`3&
-M16T`QD5N_T'V16H$=!^Y`````$$/MX6P````2-/XJ`%T`XA-;H/!`8/Y!W7F
-MO@`"``!,B>_H`````(F%S````$'VAJ8````@=!M!#[>&K````(/@((/X`1G`
-M@\`"B(68`0``ZP?&A9@!````N`$```!;74%<05U!7L-F9I!(@^PH2(D<)$B)
-M;"0(3(ED)!!,B6PD&$R)="0@28G]28GV3(LGNX#____K"69F9I"`^X5W0P^V
-MPT$/MJP$:`@``$"`_?]T,4`/ML5(:<#(#P``2(G'20.\))`)``!,.6\(=16Z
-M"````$R)]N@`````A,!T!(GHZP^#PP&`^X%FD':NN/____\/ML!(BQPD2(ML
-M)`A,BV0D$$R+;"083(MT)"!(@\0HPV9FD&9FD&9FD$%7059!54%455-(@^PX
-M28G^2(L'@']#``^$$0,``,=$)#0`````2(V0``(``$B)5"0(2`4$`@``2(D$
-M)&9F9I`/MDPD-(A,)#-$#[;Y26/'2(T40$B-%)!)C336]H;R$@``$`^$KP(`
-M`$B-EL`2``"X`0```$2)^4C3X`A""DB+MM`2``!(B70D*/9""0(/A!X!```/
-MMD0D,XUH`4$X;D,/A@P!``!)8\=(C11`2(T4D$C!X@-(B50D($P!\DB)5"08
-M2(M4)"!)C906Z!(``$B)5"001`^V[4ECQ4B-%$!(C1202(T<U0````!.C20S
-M0?:$)/(2```0#X2G````2(M,)!CW@>02``````X`#X22````28VT'N@2``"Z
-M"````$B+?"00Z`````"$P'1W28VT'MP2``!(BT0D($F-O`;<$@``N@@```#H
-M`````(3`=%2X`0```$2)Z4C3X$B+5"082('"P!(```I""HA""D&(A"3*$@``
-M2(-\)"@`=0]-BZ0DT!(``$R)9"0HZQA)8\5(C11`2(T4D$B+1"0H28F$UM`2
-M``"#Q0%!.&Y##X<B____2(-\)"@`#X7$````3(GWZ`````!(B40D*$B%P`^$
-M6P$``$ECQTB-#$!(C0R(28T,SDB+5"0H2(F1T!(```^V1"0S2(T40$B-%)!)
-MC936P!(``$B+1"0H2(E0(`^V@<D2``!(BU0D*(A""L9""0!,B3+&0@X`QD)8
-M`,9"*``/MDPD,XUQ`4$X=D-V74ECQTB-%$!(C12028V\UL`2``!`#[;.#[9'
-M"DC3^*@!=!A(8\%(C11`2(T4D$B+1"0H28F$UM`2``"#Q@%!.'9#=AKKSDEC
-MQTB-%$!(C1202(M,)"A)B8S6T!(``$ECQTB-%$!(C12028V4UL`2```/MD(*
-M2(M,)"B(00T/MFH*@'PD,P-V*T*-'/T`````2&/;2(M$)`A(`=C'`#@```"_
-M$"<``.@`````2`,<)(DKZRE"C1S]`````$ACVTB+1"0(2`'8QP`X````OQ`G
-M``#H`````$@#'"2)*X-$)#0!#[9$)#.#P`%!.$9##X<1_?__2(/$.%M=05Q!
-M74%>05_#9I!!5T%6055!5%532(/L:$B)_4R+)\9$)%!0QD0D407&1"12!,9$
-M)%,PQD0D5!'&1"15J\9$)%8`QD0D5P!!QX0D`$`!`!,@``!(BP?'@`1``0#_
-M_P``2(L'QX`$0`$``````$@[O_@(```/A=0```!(C9^0%```2(V7&`D``$&X
-M`0```+D(````O@```@#H`````(N%$`D```^VE1L)``"#Z@2-!(*(A1L)``!(
-MB>_H`````(3`=0Q(BT0D4$B)A1@)``"+!0``````A1L)``"#P`&)!0`````/
-MMH48"0``B(,8"0``#[:%&0D``(B#&0D```^VA1H)``"(@QH)```/MH4;"0``
-M@\`"B(,;"0``#[:%'`D``(B#'`D```^VA1T)``"(@QT)```/MH4>"0``B(,>
-M"0``#[:%'PD``(B#'PD``$V)YTF-A"0``0``2(E$)$!!BX0D``$``(D%````
-M``^WT(E4)%RH('0+)=__``")1"1<ZQB)T(/(((E$)%Q(BU0D0(D"BP*)!0``
-M``!(BT4`QX`$`0```````$B+10#'@!@!````````2(M%`,>`'`$```````"_
-MD-`#`.@`````0<>'<`$``!@!``!!BX=T`0``B04`````@.3]@,P$B40D7$''
-MAW`!```8`0``BT0D7$&)AW0!``!!QX=P`0``*`$``$''AW0!``!_?P``0<>'
-M<`$``"0!``!!BX=T`0``B04`````9K@```W_/P``B40D7$''AW`!```D`0``
-MBT0D7$&)AW0!``!!QX=P`0``/`$``$''AW0!`````'H`0<>'<`$``*0!``!!
-MQX=T`0``?;_O_T''AW`!``"X`0``08N'=`$``(D%`````"7__P``#0``^@")
-M1"1<0<>'<`$``+@!``"+1"1<08F'=`$``$''AYP```#_````0<>'D`(``$0!
-M``!!QX>4`@``!A``"$''AY`"``"T`0``0<>'E`(``%]P``!!QX>0`@``,```
-M`$&+AY0"``")!0`````PY(#,,XE$)%Q!B8>4`@``@'U#``^$E0(``,=$)$@`
-M````28V'4`(``$B)1"0X28V75`(``$B)5"0P2(V%&`D``$B)1"0H28V7@`$`
-M`$B)5"0@28V'A`$``$B)1"0828V7,`(``$B)5"0028V'-`(``$B)1"0(9F9F
-MD&9FD`^V5"1(B%0D3X#Z`P^&_@```$0/MO)"C1SU`````$ACVTR+;"0020'=
-M0<=%``@```"_$"<``.@`````2(M$)`A,C20#08L$)(D%`````(E$)%P-``"`
-M`$&)!"1(BU0D*$2)]DB)[^@`````1(GV2(GOZ`````!!QT4`1`$``+\0)P``
-MZ`````!!QP0D!A``"$''10"T`0``OQ`G``#H`````$''!"1?<```0<=%``@`
-M``"_$"<``.@`````QT0D7/]4@`!!QP0D_U0``+H!````1(GV2(GOZ`````!(
-MBT0D($B-%`.+`HD%`````"7___[_B0+'1"1<!0'(`$@#7"08QP,%`<@`Z?L`
-M``!F9F:01`^V="1/0HT<]0````!(8]M,BVPD.$D!W4''10`(````OQ`G``#H
-M`````$B+5"0P3(TD$T&+!"2)!0````")1"1<#0``@`!!B00D2(M4)"A$B?9(
-MB>_H`````$2)]DB)[^@`````0<=%`$0!``"_$"<``.@`````0<<$)`80``A!
-MQT4`M`$``+\0)P``Z`````!!QP0D7W```$''10`(````OQ`G``#H`````,=$
-M)%S_5(``0<<$)/]4``"Z`0```$2)]DB)[^@`````2(M$)"!(C10#BP*)!0``
-M```E___^_XD"QT0D7`4!R`!(`UPD&,<#!0'(`+^@A@$`Z`````!$B?9(B>_H
-M`````(-$)$@!#[9$)$^#P`$X14,/A\[]__](B>_H`````$&+AP0!``")!0``
-M``"#R`*)1"1<08F'!`$``$B+5"1`BP*)!0`````E\/___0T-```"B40D7(D"
-MBP*)!0````!(BX7H$```08F'"`$``(N%[!```$&)APP!``!(BX48$0``08F'
-M$`$``(N%'!$``$&)AQ0!``!!QX<@`0````````^WA;P2```E_P\```T```$`
-M08F'(`$``$B+A7@1``!!B8<D`0``BX5\$0``08F'*`$``$B+A:`1``#'`/\/
-M``!!QX<T`0````````^WA;X2```E_P\```T```$`08F'-`$``$B+A:@1``!!
-MB8<X`0``BX6L$0``08F'/`$``$''AT@!````````QT0D7``!``!!QX=,`0``
-M``$``$&+AP0!``")!0````"#R%E!B8<$`0``QT0D7/O_``Q!QX=4`0``^_\`
-M#$''AUP!``#__P``N@````!(8\+'A(7`"0```````,=$A7@`````@\(!@_H0
-M=>)FQX6X$@``_P]FQX6Z$@``_P_&15`!N`$```!(@\1H6UU!7$%=05Y!7\-F
-M9F:09F:005=!5D%505154TB#[`A)B?Y)B?1,BR],B>_H`````$B)PTB%P'4.
-M0<:$).D````!Z;$```!,B>_H`````$B)Q4B%P'490<:$).D````!2(G>3(GO
-MZ`````#IB````$R->UC&0SCAQD,Y`<9#.@-!#[=$)#AFB4,@QH.8````#TF+
-M!DB)0RC'0S0``@``2(M5$$B)4TBX`````&9FD&9FD,8$$`!(@\`!2#T``@``
-M=?!(B6MX2,>#H`````````"^`````$R)_^@`````BU,T2(MU&$R)_^@`````
-M2(G>3(GOZ`````!(@\0(6UU!7$%=05Y!7\-F9F:09F9FD&9FD$%6055!5%53
-M2(/L,$F)_4R+)P^V1PV$P`^$P@,```^V\+T`````0/;&`745N@````"#P@$/
-MMNJ)\(GIT_BH`73P2&/%2(T40$B-%)!)C934X!(``(M"!*D```(`=`T-```$
-M`"7___W_B4($2&/%2(T40$B-%)!!BX34Y!(``*D```0`#X2A`@``28N<)/@(
-M``!)C80DD!0``$PYXT@/1-A)C3341`^VCNH2``!$#[:&Z1(```^VCN@2``!!
-M#[94)$$/MH;O$@``B40D(`^VANX2``")1"08#[:&[1(``(E$)!`/MH;L$@``
-MB40D"`^VANL2``")!"2)[DC'QP````"X`````.@`````0;@`````2&/%2(T4
-M0$B-%)!-C8S4Z!(``$$/MH08Z`@``#S_#X2$````#[;`2&G`R`\``$F)PDP#
-MDY`)``!,B=9,B<^Y"````/SSI@^7P@^2P#C"=5A%#[9*!$4/MD(#00^V2@)!
-M#[92`4$/MC)!#[9"!XE$)!!!#[9"!HE$)`A!#[9"!8D$)$C'QP````"X````
-M`.@`````0<9%"?],B>Y,B>?H`````.DH`@``28/``4F#^`(/A5W___],B>?H
-M`````$B)PTB%P`^$!@(``$ACQ4B-%$!(C1200?:$U.42```$=`2`2UT"2&/%
-M2(T40$B-%)!!]H34YA(```1T!(!+71!(8\5(C11`2(T4D$'VA-3E$@``"'0$
-M@$M=!$ACQ4B-%$!(C1200?:$U.82```(=`2`2UT@2&/%2(T40$B-%)!!]H34
-MY1(```)T!(!+70%(8\5(C11`2(T4D$'VA-3F$@```G0$@$M=",9#6`!)B=Y(
-M8\5(C11`2(T4D$F+A-3H$@``2(D#3(EK"$R)[^@`````B(.[````08!%*`%!
-M@'PD0P!T,KD`````N@````!F9F:000^V10U(T_BH`70.#[;"B$P#<(!#6@&#
-MP@&#P0%!.$PD0W?<28M-4$B-4SA)B55028U%2$B)0SA(B4M`2(D108!%6`$/
-MMHN[````28N\)+@0``!)Q\``````3(GR3(GNZ`````#IM@```*D```@`#X2K
-M````3(GGZ`````!(B<-(A<`/A)<```#&0$L&QD!*!6;'@,@``````,9`2`;&
-M0$D`2,=`>```!0!(8\5(C11`2(T4D$F+A-3H$@``2(F#U````$B)@\P```!,
-MB6M03(GOZ`````"(@^H```!F@TMH$$R)[^@`````/`EV!F:!2V@``D'&10X!
-M28M5:$F)76A)C45@2(D#2(E3"$B)&DB)WDR)Y^@`````9F:09F:02(/$,%M=
-M05Q!74%>PV9FD$%7059!54%455-(@^PH2(G]2(GS2(7V=!4/MD8)A,!T#3S_
-M#X7M!P``Z4<!``"Y``````^VA"GN"```//]T$P^VP$B-%(!(C1202(V<U<@!
-M``!(@\$!2(/Y!'770;P`````00^VA"SN"```//]T.`^VP$B-%(!(C1202,'B
-M`TB-G!7(`0``]H05T@$```)T#[X`````2(G?Z`````#K"$B)W^@`````28/$
-M`4F#_`20=;`/MD4^9CF%D!````^%4P<``$B%VP^%E````(!]40`/A4`'``#&
-M15$!9F:09F:02(NTW6@$``!(A?9T8TB+AH````!(A<!T)TC'AH``````````
-M2,>$W6@$````````2(N^D````+K______]#K,$B+AH@```!(A<!T)$C'AH@`
-M````````2,>$W6@$````````2(N^D````/_09F9FD$B#PP%(@_M`#X2X!@``
-MZX#&0PG_2(G>2(GOZ`````"0Z:$&``"Y`````&9FD&9FD`^VA"GN"```//\/
-MA`4!```/MM!(C0222(T$@DC!X`-,C;P%R`$``$B-A`7``0``@'@1_P^$W```
-M`(!X%@`/A%,&``!!O`````!(C0222(T$@DC!X`-,C:P%*`(``$B-'"A,C;/`
-M`0``3(GOZ`````!(B<%(BX,P`@``2(F+,`(``$R)*4B)00A(B0B`>4K_=&^`
-MN>D`````#X3X!0``#[9!2$B)PH/B!DB#^@9U'*@!=#H/MI&!````2(MQ6$R)
-M_^@`````Z<P%``!(@_H$#X7"!0``J`$/A+H%``!(B<Y(B>_H`````.FJ!0``
-M2(G.2(GOZ`````#IF@4``&9F9I!!@\0!13AF%@^&B`4``&:0Z5/___](@\$!
-M2(/Y!&9FD`^%VO[__TC'1"00`````(!]40`/A:4```"[`````&:02(NTW6@$
-M```/MH0K:`@``$B%]G1R2(N.@````$B%R71F2(-^8`!U7SS_=#8/MO@/M\=(
-MC11`2(T4D$C!X@5(B=!(`X5`"0``]D!+!'04@'A)`'4.#[?72(GOZ`````"0
-MZR5(QX3=:`0```````!(QX:``````````$B+OI````"Z_______12(/#`4B#
-M^T`/A6O____&15$!Z;@$``!(BU0D$`^VA"KN"```//\/A)$$```/MM!(C022
-M2(T$@DC!X`-(C8P%R`$``$B)3"0@@+P%U@$````/A&<$``#&1"0?`$B-!))(
-MC02"2,'@`TB-E`4H`@``2(D4)$R--"A-C;[``0``2(L\).@`````2(G#28N&
-M,`(``$F)GC`"``!(BPPD2(D+2(E#"$B)&(![2O\/A?D#``!$#[=K.$ECQ0^V
-ME`5H"```9HE4)`Y,BZ3%:`0``/9#3`1T=DV%Y'1Q28.\)(``````=&9)@WPD
-M8`!U7H!C3/OV0TL$=!(/MU0D#DR)YDB)[^@`````ZT))BX0D@````$ECU4C'
-MA-5H!````````$G'A"2``````````$C'0T``````28N\))````"Z_____TR)
-MYO_09F:09I#V0TL$#X13`0``QH/H`````$&`9Q3G]D-,`0^$Z````(!C3/Y(
-MBU-`2(72=$6`>TD`=2GV0TL$=",/ME5!P>(&1`'J2&/22(NU^`@``+\'````
-MZ`````#IV0```$B+M?@(``"_`0```.@`````Z<,```!-A>1T94F+C"2`````
-M2(7)=%B`>TD`=1OV0TL$=!4/MU0D#DR)YDB)[^@`````Z9````!)8\5(QX3%
-M:`0```````!)QX0D@`````````!(QT-``````$F+O"20````NO____],B>;_
-MT>M9@'M)`'53]D-+!'1-#[950<'B!D0!ZDACTDB+M?@(``"_`@```.@`````
-MZRU(BT-`2(7`="1(BY"(````2(72=!A(QX"(`````````$B+0T!(B[B0````
-M_]+V0TP"#X0A`@``2(M30$B+M?@(``"_!@```.@`````@&-,_>GA`0``2(M#
-M0$B%P`^$U`$``$B#N(@`````#X3&`0``QD-+`<9#2@!(B=J^!@```$B+?"0@
-MZ`````!(@WM8`'072(M3$$B+0QA(B4((2(D02(M#6(!H6`&`NX,`````=")F
-M9F:09F:02(GOZ`````"_`0```.@`````@+N#`````'7E2(N[(`$``$B%_W01
-M#[:S#0$``+H!````Z`````!(BWM82(7_=!$/MK.!````N@$```#H`````$R+
-M8T!-A>0/A.@```#V0TP$=4U(B>_H`````$B+<T"Z`0```$B)[^@`````2(M#
-M0`^V4`(/MG`!2,?'`````+@`````Z`````!(BU-`2(NU^`@``+\!````Z```
-M``#K,D$/ME0D`D$/MG0D`4C'QP````"X`````.@`````2(M30$B+M?@(``"_
-M`0```.@`````28N4)(@```!(A=)T)@^W0SA(QX3%:`0```````!)QX0DB```
-M``````!)B[PDD````/_2]D-,`G092(M30$B+M?@(``"_!@```.@`````@&-,
-M_4C'0T``````2<=$)&``````2(M38$B%TG00#[:#@0```$C'1,)8`````$B+
-M$TB+0PA(B4((2(D008!O%@%(B=Y(B>_H`````/9#3`)T'$B+4T!(B[7X"```
-MOP8```#H`````(!C3/UF9I"`1"0?`0^V3"0?03A/%@^'P?O__TB#1"00`4B#
-M?"00!`^%2/O__[@!````2(/$*%M=05Q!74%>05_#9F:09F:055-(@^P(2(G[
-M2(LOZ`````"$P'09#[9U0T"$]G0T#[93#;D`````]L(!=![K),9#"?](B=Y(
-MB>_H`````.MBD$B)T$C3^*@!=0B#P0%`./%U[DB)[^@`````2(G&2(7`=#](
-MBU-H2(E#:$B-0V!(B09(B58(2(DR@$,.`4B)7E#&1D@%QD9)`,:&@0````^Y
-M`0```+H!````2(G?Z`````!(@\0(6UW#9F9FD&9F9I!(@^PH2(D<)$B);"0(
-M3(ED)!!,B6PD&$R)="0@28G\2(GU2(N>B`````^V1D(\)`^'$@8```^VP/\D
-MQ0`````/MT9.#[?0]L($=`QFQT9.`0#&1D(!ZT-F@_@@=0QFQT9."`#&1D(1
-MZS&$TGD5]D9)`W0/)'^#R`AFB49.QD9"#>L8]L((=`;&14('ZPWVQ@)T",9%
-M1P#&14(>2(GN3(GGZ`````#IG04``+D!````N@(```"^`0```$B)[^@`````
-MZ8$%``"Y`0```+H`````O@$```!(B>_H`````.EE!0``N0$```"Z`0```+X!
-M````2(GOZ`````#I204``+D!````NF````"^`0```$B)[^@`````Z2T%```/
-MMDY(0;@!````NF````"^`0```$B)[^@`````Z0P%``!!N`$```"Y```!!+HA
-M````O@$```!(B>_H`````.GJ!```2(M#((%@-/__]_]!N`$```"Y`0```+H"
-M````O@````!(B>_H`````.F]!```0;@!````N0````"Z`@```+X`````2(GO
-MZ`````"_$"<``.@`````Z9$$``!(BT,@@6`T___W_T&X`0```+D!````N@(`
-M``"^`````$B)[^@`````Z60$``!!N`$```"Y`````+H"````O@````!(B>_H
-M`````+\0)P``Z`````#I.`0``+D!````N@(```"^`````$B)[^@`````Z1P$
-M``"Y`0```+H`````O@````!(B>_H`````.D`!```N0$```"Z`0```+X`````
-M2(GOZ`````#IY`,``$&X`0```+G_____N@$```"^`````$B)[^@`````Z<(#
-M``"Y`0```+H`````O@````!(B>_H`````.FF`P``#[9&1TR+;,9828E=4$F)
-M=6`/MD9'08B%@0```$'&14H#0<9%20!!@$U(!8!##@%(BU-H2(U#8$R):VA)
-MB44`28E5"$R)*K^`&@8`Z`````!!@'PD0P!T)KT`````]D,-`70/ZQD/MD,-
-MB>E(T_BH`741@\4!03AL)$-WZ>L%O0````!(BU,@BT(TJ0``"`!T"B7___?_
-MB4(TZVE(C03M`````$F)QD&!YO@'``"[N`L``$"`_0-V'4F+!"1(!8`!``!,
-M`?"+`(D%`````,'H$X/@`>L<28L$)$@%@`$``$F-!`:+`(D%`````,'H$X/@
-M`83`=0^_Z`,``.@`````@^L!=:YF0<>%R```````3(GN3(GGZ`````#IB`(`
-M`+]`#0,`Z`````"Y`````+H@````O@$```!(B>_H`````+\0)P``Z`````#I
-M6`(``+D`````N@$```"^`````$B)[^@`````OQ`G``#H`````.DR`@``2(M#
-M((%@-/__]_]!N`````"Y_____[H!````O@````!(B>_H`````+\0)P``Z```
-M``#I^P$``+D`````N@````"^`````$B)[^@`````OQ`G``#H`````.G5`0``
-MZ`````#IRP$``&9F9I#H`````.F]`0``0;@!````N?````"ZFP```+X!````
-M2(GOZ`````#IFP$``$&X`0```+F@UEHKNN`#``"^`0```$B)[^@`````Z7D!
-M``!!N`$```"Y`.`#`+JD`P``O@$```!(B>_H`````.E7`0``0;@!````N>2H
-M!@&ZQ`,``+X!````2(GOZ`````#I-0$``+D!````ND@#``"^`0```$B)[^@`
-M````Z1D!``"_0`T#`.@`````N0$```"Z(````+X!````2(GOZ`````"_$"<`
-M`.@`````Z>D```!!N`$```"Y`````+HA````O@$```!(B>_H`````.G'````
-MN0$```"Z8````+X!````2(GOZ`````#IJP````^V3DA!N`$```"Z8````+X!
-M````2(GOZ`````#IB@```,9#"0!(B[Z(````Z`````#K>+D!````N@$```"^
-M`````$B)[^@`````OQ`G``#H`````.M52(M#((%@-/__]_]!N`$```"Y____
-M_[H!````O@````!(B>_H`````+\0)P``Z`````#K(;D!````N@$```"^````
-M`$B)[^@`````OQ`G``#H`````+@!````2(L<)$B+;"0(3(MD)!!,BVPD&$R+
-M="0@2(/$*,-F9F:09F:02(/L&$B)'"1(B6PD"$R)9"002(G[2(GU#[=6(&:!
-M^H4`#X>.````#[?"#[:$!V@(```\_W1_9H/Z?W<D#[;`2(T40$B-%)!(P>(%
-M2`.70`D``$B+0E`/ME`(ZUYF9F:0#[=&(&8]@0!W(P^WP`^VA`=H"```2&G`
-MR`\``$@#AY`)``!(BT`(#[90".LM#[=&(`^VA`=H"```2(T$P$C!X`5(`X=H
-M"0``2(N`B`````^V4`CK!;K_____N?____]F@7T@A0!W#`^W12`/MHP#:`@`
-M`$B+LV@)```/ML*`^O]T'DB8@+P#[@@``/]T$H#Y_W0-@'TD!G4J9F9FD&9F
-MD$B#?7@`=`Q(C75X2(G?Z`````!(B>Y(B=_H`````.D-`0``#[;!2(T$P$C!
-MX`5,C20&00^V1"1"/!H/A(4````\&G<./!$/A;L```!F9F:0ZQ,\&W1W/!P/
-MA:D```!FD.F<````2(N3$!$``$B!PDP(``!!#[9$)%#!X`A(F$@!PHL*B0T`
-M````#[;)2(N3$!$``$B!PD0(``!!#[9$)%#!X`A(F$@!PHL"B04`````P>`(
-M"<%!B8PD!`$``$'&1"1"&NM"0<9$)$(;ZSI(BX,0$0``2`5,"```00^V5"10
-MP>((2&/22`'0BP")!0````"#X/=!B$0D2$'&1"1"'.L&0<9$)$(=2(-]>`!T
-M#$B-=7A(B=_H`````$B)[DB)W^@`````3(GF2(G?Z`````!(BQPD2(ML)`A,
-MBV0D$$B#Q!C#9F9FD&9FD&9FD&9FD$B#[`A(B?Y(BS_H`````$B#Q`C#9F9F
-MD&9F9I!F9F:02(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)
-M_TB)\TB+;E`/MW8X2&/&N@````"`O`=H"```_P^$.@D```^V0TH\"0^$3@4`
-M`#P)=TH\!0^$EP```#P%=QX\`P^$K0```#P$9F9FD`^%[`@``.G1````9F:0
-M9I`\!P^$H00``#P'9F:09F:0#X<<!```Z8$"``!F9I!FD#P6#X1^`P``/!9F
-M9I!F9I!W(SP4#X31!0``/!1F9F:0#X?;`@``/`H/A90(``!FD.D[!0``/!H/
-MA!\"```\_Y`/A*D%```\%P^%=`@``&:0Z48#```/MG=#0(3V9F9FD`^$AP``
-M``^V50U!O`````#VP@%T;>MV2(M%((%@-/___O](BWM0N0````"Z`0```$B)
-MWN@`````OP4```#H`````+H!````Z30(``"Y`````+H`````2(G>2(GOZ```
-M``"_4,,``.@`````N@$```#I"P@``$B)T$2)X4C3^*@!=1%!@\0!03CT=>KK
-M!D&\``````^V4TA(B="#X`9(@_@&=0GVP@$/A<8```!(BU4@BT(TJ0```0!T
-M#27___[_B4(TZ:L```!*C03E`````$F)QD&!YO@'``!!O1`G``"028L708#\
-M`W8728V$%H`!``"+`(D%`````"4```$`ZQ5)C806@`$``(L`B04`````)0``
-M`0"%P'0L08#\`W8328V$%H`!``#'`````0#I-P<``$F-A!:``0``QP````$`
-MZ20'``"_Z`,``.@`````08/M`76+QD-+`L9#2O](B=Y,B?_H`````+H!````
-MZ0X'``#V10H!=#1(B=Y(B>_H`````(3`=25!O?H```!(B=Y(B>_H`````(3`
-M=1"_Z`,``.@`````08/M`77A08#\`W8F28L'2`6``0``2HT4Y0````"!XO@'
-M``!(`="+$(D5`````(D0ZR1)BP=(!8`!``!*C13E`````('B^`<``$@!T(L0
-MB14`````B1!(BWM02(G>Z$CF__^_($X``.@`````N@$```#I9`8``$C'QP``
-M``"X`````.@`````2(MK4$R+90!,B>?H`````$B)P4B%P'41QH/I`````;H!
-M````Z2H&``#&0#CAQD`Y`<9`.A</MT,X9HE!($B+10!(B4$HQT$T`````$C'
-M04@`````2,>!H`````````!(B<Y,B>?H`````+H!````Z=\%``!(Q\<`````
-MN`````#H`````$B+:U!,BV4`3(GGZ`````!(B<%(A<!U$<:#Z0````&Z`0``
-M`.FE!0``QD`XX<9`.0'&0#H8#[=#.&:)02!(BT4`2(E!*,=!-`````!(QT%(
-M`````$C'@:``````````2(G.3(GGZ`````"Z`0```.E:!0``2(G>2(GOZ!_E
-M__^Z`0```.E%!0``3(ME`$R)Y^@`````2(G"#[9+;$B%P'4.QH/I`````;(!
-MZ1\%``#&0#CAQD`Y`<9`.@6(2#L/MT,X9HE"($B+10!(B4(HQT(T`````$C'
-M0D@`````2,>"H`````````"(2V](B=9,B>?H`````+H!````Z<X$``!,BV4`
-M3(GGZ`````!(B<(/MDMN2(7`=0[&@^D````!L@'IJ`0``,9`..'&0#D!QD`Z
-M!(A(.P^W0SAFB4(@2(M%`$B)0BC'0C0`````2,="2`````!(QX*@````````
-M`(A+<4B)UDR)Y^@`````N@$```#I5P0``$R+90!,B>?H`````$B)P4B%P'41
-MQH/I`````;H!````Z3($``#&0#CAQD`Y`<9`.@8/MT,X9HE!($B+10!(B4$H
-MQT$T`````$C'04@`````2,>!H`````````!(B<Y,B>?H`````+H!````Z><#
-M``!F9F:09F:03(ME`$R)Y^@`````2(G!2(7`=1'&@^D````!N@$```#INP,`
-M`,9`..'&0#D!QD`Z#`^W0SAFB4$@2(M%`$B)02C'030`````2,=!2`````!(
-MQX&@`````````$B)SDR)Y^@`````N@$```#I<`,``$R+90!,B>?H`````$B)
-MP4B%P'41QH/I`````;H!````Z4L#``#&0#CAQD`Y`<9`.A;&0#P!#[=#.&:)
-M02#&@9@````/2(M%`$B)02C'030`````2,=!2`````!(QX&@`````````$B)
-MSDR)Y^@`````N@$```#I]0(``,9#2O]FQX/(```````/ME-(2(G0@^`&2(/X
-M!G4%]L(!=15(@WM@`'4.2(GOZ`````"(@^H```"`>TL"=0](BW-02(G:3(G_
-MZ`````#V10P"=1B[`````$R-96"`?0X`#X5``0``Z5<"``!(BW5`#[9.1@^V
-MT0^V1CN#Z`$YPGTNC4$!B$9&@$9'`<9&0@`/MT9.@^#^@\@(9HE&3DR)_^@`
-M````N@$```#I1P(``#G"=!2[`````$R-96"`?0X`=2GI$0(``,9&0@`/MT9.
-M@^#V@,P"9HE&3DR)_^@`````N@$```#I"P(``$R)Y^@`````2(G!2(M%:$B)
-M36A,B2%(B4$(2(D(@'E*_W1\@+GI``````^$O0$```^V44A(B="#X`9(@_@&
-M=2+VP@%T10^VD8$```!(BW%82(GOZ`````"Z`0```.FI`0``2(/X!`^%@0$`
-M`/;"`0^$>`$``$B)SDR)_^@`````N@$```#I@0$``$B)SDR)_^@`````N@$`
-M``#I;`$``,:!Z0````"#PP$X70X/ACL!``#I2?___V9F9I!,B>?H`````$B)
-MP4B+16A(B4UH3(DA2(E!"$B)"(!Y2O\/A)````"`>4D`#X5_````@+GI````
-M``^$]`````^V44A(B="#X`9(@_@&=2+VP@%T2`^VD8$```!(BW%82(GOZ```
-M``"Z`0```.G@````2(/X!`^%N````/;"`69FD`^$K````$B)SDR)_^@`````
-MN@$```#IM0```$B)SDR)_^@`````N@$```#IH````,:!Z0````"#PP$/MD4.
-M.-@/ASK___\XPW52A,!T3KL`````3(UE8$R)Y^@`````2(G"2(M%:$B)56A,
-MB2)(B4((2(D0#[9"23PB=`0\#744O@H```!(B=?H`````+H!````ZSR#PP$X
-M70YWN\9%"?](B>Y,B?_H`````+H!````ZQZZ`0```.L7187M9F9FD`^$W_C_
-M_^GW^/__9F:09I")T$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#
-MQ#C#9F9FD&9F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL)"!(B?M)B?0/
-MMTX@9H'YA0`/A^@````/M\$/MK0':`@``$"`_O\/A-,```!F@_E_=RA`#[;6
-M2(N/0`D``$B-!%)(C02"2,'@!4B+1`A0#[9`".M)9F:09F:09H'Y@0!W'4`/
-MML9(BY>0"0``2&G`R`\``$B+1!`(#[9`".L?0`^VQDB+EV@)``!(C03`2,'@
-M!4B+A!"(````#[9`"#S_=%X/ML`/MJP#[@@``$"`_?]T&$"`_O]T$D$/MDPD
-M)(#Y!G5G9F9FD&9FD$"`_?]T+T"`_O]T*4`/ML9(C11`2(T4D$C!X@5)B=5,
-M`ZM`"0``0<9%2P)!QD5*_^F?`@``28-\)'@`=`U)C70D>$B)W^@`````3(GF
-M2(G?Z`````#II0(``&9FD&9FD$`/ML9(C11`2(T4D$C!X@5)B=5,`ZM`"0``
-M28M4)$B$R0^$N0```$$/MD0D.CP&#X30````/`P/A,@```!!#[>5R````(U"
-M`69!B87(````9H/Z"78;08!]2@9T%$'&14L"0<9%2O]!@&5,_ND#`@``O^@#
-M``#H`````$$/ME5(2(G0@^`&2(/X!G4Z]L(!=#5!#[:5@0```$F+=5A`#[;%
-M2(T\@$B-/+A(C;S[R`$``$&X`````+D"````Z`````#IV0$``$'&14H#3(GN
-M2(G?Z`````#IQ`$``&9FD&:000^V1"0Z/`%U"T'&14H$D.E_`0``/`)U#$'&
-M14H%9I#I;P$``#P##X7/````2(G608!]2@5U*V:!>@3(-V9FD'4@00^W=3A(
-MQ\<`````N`````#H`````$'&14H&Z3(!``!,B>_H`````$F-O9@```"^*```
-M`.@EO___A,!U04F-O80```"^%````.@0O___A,!U+$F-O<````"^"````.C[
-MOO__A,!U%TF#?7@`=!!!QD5*%^G:````9F:09F:09D&#O<@````==A1!QD5+
-M`D'&14K_08!E3/[IM0```+_H`P``Z`````!!QD5*&F9!@X7(`````>F8````
-M/!=U"D'&14H5Z8H````\&&9F9I!U!T'&14H6ZWL\!&9FD&:0=0=!QD5*!^MK
-M/`5F9I!FD'4'0<9%2@CK6SP&9F:09I!U!T'&14H)ZTL\#&9FD&:0=0=!QD5*
-M"NL[/!9F9I!FD'4'0<9%2A3K*SP.9F:09I!U(DF#?"1X`'0-28UT)'A(B=_H
-M`````$R)YDB)W^@`````ZRM)@WPD>`!T#4F-="1X2(G?Z`````!,B>9(B=_H
-M`````$R)[DB)W^@`````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9F9I!F
-M9F:02(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($F)_DF)]$B+;E`/MT8X
-MN@````"`O`=H"```_P^$RP(```^V1DH\%`^$QP```#P4=S@\#9`/A/L````\
-M#7<./`5F9F:0#X6=`@``ZTT\#F9FD&9FD`^$[P```#P/#X6%`@``9I#I\@``
-M`#P;#X25````/!N0=Q`\&'0Y/!D/A64"``!FD.M$/!QT5SS_#X55`@``9I#I
-MQ@```+X`````3(GG9F:0Z`````"Z`0```.DY`@``O@$```!,B>?H`````+H!
-M````Z2("``"^`0```$R)Y^@`````N@$```#I"P(``$B)]^@`````N@$```#I
-M^0$``)!(B??H`````+H!````Z>8!``#V1FD$=!=(B?=F9I!FD.@`````N@$`
-M``#IR0$``$B)]^@`````N@$```#IMP$``$B)]^@`````N@$```!FD.FC`0``
-M2(GWZ`````"Z`0```.F1`0``QD9*_X!]#@`/A-D```"[`````$R-;6!FD$R)
-M[^@`````2(G!2(M%:$B)36A,B2E(B4$(2(D(@'E*_P^$B0```(!Y20`/A88`
-M``"`N>D`````#X0U`0``#[912$B)T(/@!DB#^`9U(O;"`71(#[:1@0```$B+
-M<5A(B>_H`````+H!````Z0@!``!(@_@$#X7Y````]L(!9F:0#X3M````2(G.
-M3(GWZ`````"Z`0```.G=````2(G.3(GWZ`````"Z`0```.G(````QH'I````
-M`(/#`0^V10XXV`^'.O___SC##X6/````00^V1"1)/")T%CP-=!)!O`````!,
-MC6U@@'T.`'46ZV^^"@```$R)Y^@`````N@$```#K=DR)[^@`````2(G#2(M%
-M:$B)76A,B2M(B4,(2(D8#[9#23PB=`0\#74H2(G>2,?'`````+@`````Z```
-M``"^"@```$B)W^@`````N@$```#K)4&#Q`%$.&4.=Z7&10G_2(GN3(GWZ```
-M``"Z`0```.L%N@$```")T$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#
-M9F:09F:09F:005=!5D%505154TB#["A)B?T/MU8@0;C_____1(G`9H'ZA0`/
-MAX`````/M\)$#[:$!V@(``!$B<!!@/C_=&MF@_I_=R)!#[;02(N/0`D``$B-
-M!%)(C02"2,'@!4B+1`A0#[9`".M#9H'Z@0!W'4$/ML!(BY>0"0``2&G`R`\`
-M`$B+1!`(#[9`".L?00^VP$B+EV@)``!(C03`2,'@!4B+A!"(````#[9`"`^V
-MP$$/MKP%[@@``$B-!+](C02'28V$Q<@!``!(B40D($$/ML!(C11`2(T4D$C!
-MX@5)B==-`[U`"0``2(M.2`^V`<'@&`^V40'!XA`)T`^V40,)T`^V40+!X@@)
-MT,'H`TB-:0B#^!"Z$`````]'PHG`3(TTP4PY]0^'?`$``,=$)!P`````2(T$
-MOTB-!(=(P>`#2HT4*$B)5"002('"P`$``$B)5"0(28V$!2@"``!(B00D9F9F
-MD$B)[^@`````08G$2(UU!$C'QP````"Y!````/SSI@^7P@^2P#C"#X4*`0``
-M08/\$`^'``$``(-$)!P!@WPD'`%U(D''AY`!```!````18FGE`$``$B+10!)
-MB8?<````Z=(```!,B>_H`````$B)PTB%P`^$RP```,9`2P;&0$H%9L>`R```
-M````QD!(!L9`20!(QT!X```%`,>`D`$```$```!$B:"4`0``28N'U````$B)
-M@]0```!)BX?4````2(F#S````$B+10!(B8/<````2(M$)"!(B4-02(G'Z```
-M``"(@^H```!F@TMH$$B+?"0@Z``````\"78&9H%+:``"2(M4)`B`0A8!2(M4
-M)!!(BX(P`@``2(F:,`(``$B+%"1(B1-(B4,(2(D82(G>3(GOZ`````!(@\4(
-M3#GU#X:]_O__2(/$*%M=05Q!74%>05_#9F9FD&9F9I!F9I!F9I!!5T%6055!
-M5%532('L2`(``$B)?"082(ET)!")T$B+5PA(B50D($B+"DB)3"0H#[976(A4
-M)#=(B?E(@\%(2(E,)#A(.4](#X21`@``@'PD-P`/A(8"```/ML")1"0,2(M\
-M)#CH`````$R-8/!,C40D0(M,)`RZ`0```$B+="0@2(M\)!#H`````$R-?"1`
-M@'PD0``/A`4!``!!O0````!-C;0DU````$$/MNU(8\5(B<-(P>,$28U\'VRZ
-M"````$R)]N@`````A,`/A+$```!)C50?8`^V0@B#X`]!B(0DZ@```$$/MTPD
-M:&:!X=_]B<B#R!!F08E$)&@/MD((P.@$/`EU"XG(@\@P9D&)1"1H2&/%2,'@
-M!$$/MD0':,#H!#P*=0AF08%,)&@``DB+3"0X2(M1"$F-1"002(E!"$F)3"00
-M28E4)!A(B0)!]D0D3`)T0T&`9"1,_4F+5"1`2(72=#-(BT0D*$B+L/@(``"_
-M!@```.@`````ZQMF9I!F9I!!@\4!13@O=A5F9F:09F:0Z1+___]%."\/AR0!
-M``!,B>*^!@```$B+?"0@Z`````!!@+PD@P````!T)&9FD&:02(M\)"CH````
-M`+\!````Z`````!!@+PD@P````!UX4F+O"0@`0``2(7_=!-!#[:T)`T!``"Z
-M`0```.@`````28M\)%A(A?]T$T$/MK0D@0```+H!````Z`````!)BT0D0$B%
-MP'1M2,=`8`````!!]D0D3`1U'DB+?"0HZ`````!)BW0D0+H!````2(M\)"CH
-M`````$F+5"1`2(M,)"A(B['X"```OP8```#H`````$F+5"1`2(M$)"A(B[#X
-M"```OP$```#H`````$G'1"1``````$F+%"1)BT0D"$B)0@A(B1!(BU0D((!J
-M#@%(BTPD&(!I6`%,B>9(BWPD*.@`````2(M4)#A(BT0D&$@Y4$AT"X!L)#<!
-M#X6!_?__2('$2`(``%M=05Q!74%>05_#D$%7059!54%455-(@>PH`@``28G_
-M28GU2(G52(L'2(E$)!!$#[;A2(U<)"!)B=A$B>&Z`0```$B)_DR)[^@`````
-M1(GB3(GN2(GOZ`````!,BW5(28/N$$B-74A)C4802#G8="]!#[9&23P-=!4\
-M(G4SZP]!#[9&23P-=`8\(F:0=2)!QD9*!4'&1DL$QD0D'@'K!<9$)!X`@'PD
-M(`!U&.G=`0``38MV$$F#[A!)C4802#G8=;[KW,9$)!\`28U78$B)5"0(3(ME
-M2$F#[!!)C40D$$@YPP^$O`$```^V1"0?2,'@!$R-K`2,````9F9FD$F-O"34
-M````N@@```!,B>[H`````(3`#X5@`0``38MD)!!)@^P028U$)!!(.=@/A',!
-M``#KRD&`1PX!QD%*!<:!Z`````#&04L$9L>!R```````QH'*`````$C'07@`
-M``4`#[9\)!](8\=(P>`$2(V4!(`````/MD($B$%(#[9"!8A!24R)>5`/MD((
-M@^`/B('J````#[=Q:&:!YM_]B?"#R!!FB4%H#[9"",#H!#P)=0F)\(/(,&:)
-M06A(8\=(P>`$#[:$!(@```#`Z`0\"G4&9H%):``"2(EI6$ACQTC!X`0/MI0$
-MA@```(B1@0```$B+A`2,````2(F!U````$B)@<P```"`15@!28M':$F)3VA(
-MBU0D"$B)$4B)00A(B0A(BU502(U!$$B)15!(B5D02(E1&$B)`@^V44A(B="#
-MX`;&1"0>`$B#^`9U,/;"`709#[:1@0```$B)[DR)_^@`````QD0D'@#K$DB)
-MSDB+?"00Z`````#&1"0>`(!$)!\!#[9$)!\X1"0@#X=$_O__@'PD'@!T);X*
-M````3(GWZ`````#K%DB+?"00Z`````!(B<%(A<`/A7G^__](@<0H`@``6UU!
-M7$%=05Y!7\.005=!5D%505154TB![$@"``!)B?U(B70D*$B++P^V1RB(1"0W
-M2(U72$B)5"0X2#E72`^$H0,``(3`#X29`P``2(U,)$!(@\%<2(E,)"!(C40D
-M0$B#P%1(B40D&$B-5"1`2(/"0$B)5"002(U,)$!(@\$02(E,)`A(C40D0$B#
-MP"!(B00D2(M\)#CH`````$R-8,A!N`````"Y`````+H`````3(GN2(M\)"CH
-M`````$&)QX3`#X0+`P``0;X`````NP````")7"0P0;@`````B=FZ`0```$R)
-M[DB+?"0HZ``````/ML!(P>`$2(/`9$@]``(```^'N0$``$R-1"1`B=FZ`0``
-M`$R)[DB+?"0HZ`````"Z"````$R)YDB+?"0@Z`````"$P`^$A@$``$B+3"0X
-M2(M1"$F-1"0X2(E!"$F)3"0X28E4)$!(B0(/MD0D0D&(1"192(MT)!A,B>_H
-M`````#S_=!8/ML!(:<#(#P``2`.%D`D``$F)1"00183V=%\/MD0D0]'H@^`!
-MP>`$00^V5"1=@^+O"<)!B%0D70^V1"1#P>@#@^`!P>`%@^+?"<)!B%0D70^V
-M1"1#P>@"@^`!P>`#@^+W"<)!B%0D70^V1"1&08B$)+L```#IN0````^V1"1"
-M08A$)%E-B6PD"`^V1"1&08B$)+L````/MT0D1$&)1"1@#[>$))````!F08F$
-M)+@````/MH0DD@```$&(A"2Z````2(N$)(````!)B80DJ````$B+5"002(M"
-M"$F)A"2P````2(M$)%!)B40D>$B+3"0(2(M!"$F)A"2`````28V4)(@```!(
-MBT0D8$F)A"2(````2(L,)$B+00A(B4((2(M!$$B)0A!(BT0D>$F)A"2@````
-MBTPD,$R)XDB+="0H3(GOZ`````#I^0```$&#Q@&#PP%%./X/A`(!``#I_?W_
-M_TR)]^@`````2(U8\$B)VKX&````3(GOZ`````"`NX,`````=!YF9I!(B>_H
-M`````+\!````Z`````"`NX,`````=>5(BT-`2(7`=%E(QT!@`````/9#3`1U
-M&4B)[^@`````2(MS0+H!````2(GOZ`````!(BU-`2(NU^`@``+\!````Z```
-M``!(BU-`2(NU^`@``+\&````Z`````!(QT-``````$B+$TB+0PA(B4((2(D0
-M08!M#@%!@&PD6`%(B=Y(B>_H`````$TY="1(#X4L____08!M*`%,B>9(B>_H
-M`````$B+1"0X23E%2'0A@&PD-P%T&F:0Z;_\__]-C70D2$TY="1(D`^%\O[_
-M_^O$2('$2`(``%M=05Q!74%>05_#9F:09F:005=!5D%505154TB![#@"``!(
-MB7PD&$B)]4B+!DB)1"0@2(G^2(GOZ`````!!N`````"Y`````+H`````2(GN
-M2(M\)!CH`````(A$)"^$P`^$;@,``$&_`````$&^`````$B-54A(B50D"$B-
-M36!(B0PD0;@`````1(GQN@$```!(B>Y(BWPD&.@`````#[;`2,'@!$B#P&1(
-M/0`"```/APP#``!,C40D,$2)\;H!````2(GN2(M\)!CH`````$R-9"0P28UT
-M)%Q(B>_H`````#S_#X78`@``2(M\)"#H`````$B)PTB%P`^$[`(``(!%*`'&
-M0%@`28M$)%Q(B0-)C70D5$B)[^@`````//]T&@^VP$AIP,@/``!(BW0D($@#
-MAI`)``!(B4,000^V1"0"B$-900^V1"0#T>B#X`'!X`0/ME-=@^+O"<*(4UU!
-M#[9$)`/!Z`.#X`'!X`6#XM\)PHA374$/MD0D`\'H`H/@`<'@`X/B]PG"B%-=
-M2(EK"$$/MD0D!HB#NP```$F+1"0(2(E#<$$/MD0D!XA#6D$/MT0D!(E#8$$/
-MMT0D4&:)@[@```!!#[9$)%*(@[H```!)BT0D0$B)@Z@```!)BT0D2$B)@[``
-M``!)BT0D$$B)0WA)BT0D&$B)@X````!(C8N(````28U4)"!)BT0D($B)@X@`
-M``!(BT((2(E!"$B+0A!(B4$028M$)#A(B8.@````2(M54$B-0SA(B4502(M,
-M)`A(B4LX2(E30$B)`D&`/"0`#X1J`0``0;T`````2(US2$B)="002(M\)"#H
-M`````$B)P4B%P`^$;P$``(!%#@'&0$H%QH#H`````,9`2P1(QT!X```%`&;'
-M@,@``````$$/M_U(8\=(P>`$28U4!&`/MD($B$%(#[9"!8A!24B):5!(B5E8
-M#[9"!HB!@0````^V0@B#X`^(@>H````/MW%H9H'FW_V)\(/($&:)06@/MD((
-MP.@$/`EU"8GP@\@P9HE!:$ACQTC!X`1!#[9$!&C`Z`0\"G4*9H%):``"9F9F
-MD$ACQTC!X`1)BT0$;$B)@=0```!(B8',````@$-8`4B+16A(B4UH2(L4)$B)
-M$4B)00A(B0A(BU-02(U!$$B)0U!(BW0D$$B)<1!(B5$82(D"#[912$B)T(/@
-M!DB#^`9U)O;"`704#[:1@0```$B)WDB)[^@`````ZPU(B<Y(BWPD(.@`````
-M08/%`4$/M@0D9D0YZ`^'K/[__V9F9I!F9I!!@\<!08/&`40Z?"0O#X6O_/__
-M@'T.`'41QD4)_TB)[DB+?"0@Z`````!(@<0X`@``6UU!7$%=05Y!7\-F9F:0
-M05=!5D%505154TB#[!A)B?Y)B?1!N`````"Y`````+H`````Z`````!!B<6$
-MP'0VO0````"[`````$R-?"07D$R)^8G:3(GF3(GWZ`````"`?"07_@^%K@``
-M`(/%`8/#`40X[77:00^V1"18@^@!08A$)%B$P'1[28LL)$'&1"18`$F+7"1(
-M2(/K.$F-5"1(2(U#.$@YT'1P2(-[$`!U0.L'2(-[$`!U-T'&1"18`4R)YDR)
-M]^@`````#[:+NP```$B+O;@0``!)Q\``````2(G:3(GFZ`````#K+69F9I!(
-MBULX2(/K.$B-0SA(.=!UL>L63(GF3(GWZ`````!,B>9,B??H`````$B#Q!A;
-M74%<05U!7D%?PV9F9I!F9F:0055!5%532(/L"$B)_4F)]$R++[L*````3(GF
-M2(GOZ`````"$P'4/O^@#``#H`````(/K`77B00^V=4-`A/9T(@^V50VY````
-M`/;"`70,ZQ)(B=!(T_BH`74(@\$!0#CQ=>Y)BQ0D28M$)`A(B4((2(D0@&T.
-M`4R)YDR)[^@`````]D4,`G1)2(MU0$B%]G483(GOZ`````!(B<9(A<`/A%(!
-M``!(B45`3(DN2(FNB````,9&1@#&1D<`QD9"`&:#3DX$3(GOZ`````#I)@$`
-M`$B+14!(A<`/A+@```!(C;"0````28M]*.@`````2(MU0$R)[^@`````3(UE
-M8$PY96`/A(8```!,B>?H`````$B)PTB+0$!(A<!T64C'0&``````]D-,!'49
-M3(GOZ`````!(BW-`N@$```!,B>_H`````$B+4T!)B[7X"```OP$```#H````
-M`$B+4T!)B[7X"```OP8```#H`````$C'0T``````@&T.`4B)WDR)[^@`````
-M3#EE8`^%>O___TC'14``````@'T.`'022(U]8.@`````2(G!@&T.`>L+3(GO
-MZ`````!(B<%(A<ET.4B+56A(B4UH2(U%8$B)`4B)40A(B0J`10X!2(EI4,9!
-M2`7&04D`QD%+!L9!2@-(B<Y,B>_H`````$B#Q`A;74%<05W#9F9FD&9F9I!F
-M9F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@2(G[2(GU#[=.(&:!^84`
-M#X>5````#[?!#[:T!V@(``!`@/[_#X2`````9H/Y?W<H0`^VUDB+CT`)``!(
-MC0122(T$@DC!X`5(BT0(4`^V0`CK269FD&9FD&:!^8$`=QU`#[;&2(N7D`D`
+M9I!F9I!(@^PH2(E<)!A(B6PD($B)^XG52,=$)!``````@']+`71!2(U4)!!`
+M#[;VN0$```#H`````$B+1"002(7`="2`"(!`A.UT"TB+1"00@$@#(.L)2(M$
+M)!"`8`/?2(G?Z`````!(BUPD&$B+;"0@2(/$*,-F9F:09F9FD&9FD&9FD$B#
+M[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!)B?U!B?=(BT=03(LP
+M3(GWZ`````!(B<5(A<`/A*D```!,B??H`````$F)Q$B%P'402(GN3(GWZ```
+M``#IB0```$B-75C&126L00^W13AFB44@3(EU*,>%E`````@```!,B65X28M$
+M)!!(B45(QT4T``@``$F-A>P```!(B450QD4P($C'A:``````````QD4X',9%
+M.0%$B'TZQD4[",9%/`"^`````$B)W^@`````BU4T28MT)!A(B=_H`````$B)
+M[DR)]^@`````2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$.,.0
+M05=!5D%505154TB#[!A(B3PD2(M.2`^V00+!X`@/ME$#C3P0#[?'@\`$#[=6
+M-#G0#X]:`0``3(UI"`^WQTR-=`$$3(EL)`A!O`````#'1"04`````$TY]0^#
+MV0```&:0#[9$)!2(1"0300^V10+!X`A!#[95`T2-/!!!#[?W2(M\)`A(@\<$
+MZ`````")P3S_=5Y!#[?'2(M<)`A(C50#!$B)TTDYU@^&SP```$&)S)`/MD("
+MP>`(#[92`XTL$`^W]4B->P3H`````#S_=0A!@/S_=7GK<4$XQ$0/1^`/M\5(
+MC50#!$B)TTDYUG9@Z\&0B<)$*.(/MM(/MEPD$XG>2(L\).@`````B=I,B>Y(
+MBSPDZ`````!!#[?'2(M4)`A,C6P"!$R);"0(@T0D%`%-.>X/ARG___^^`@``
+M`$B+/"3H`````.M)0;P`````#[94)!-,B>Y(BSPDZ`````!!#[?'2(M<)`A,
+MC6P#!$R);"0(@T0D%`'IY?[__P^V5"033(GN2(L\).@`````ZZEFD$B#Q!A;
+M74%<05U!7D%?PY!!5T%6055!5%532(/L"$F)_DB+3D@/MD$"P>`(#[91`P'0
+M#[?`@\`$#[=6-#G0#X\,`0``2(U1"`^V<0'&1"0#`+D`````#[9"`@!$)`,/
+MMD(#2(U4`@2#P0%`.,YSYX!\)`,`#X2^````2(UJ!$&_`````$&]`````,=$
+M)`0`````#[95_4$!U0^V1?P\`70$/!=U.T2)ZRC303C==G$/MD0D!(/``40/
+MMN!F9I!FD`^V3?P/MO-$B>),B??H`````(/#`40XZW1&Z^1F9F:028M&6("X
+MP0````%T,T2)ZRC303C==BD/MD0D!(/``40/MN`/MDW\#[;S1(GB3(GWZ```
+M``"#PP%$..MUYF9FD$&#QP&#1"0$`4B#Q01$.GPD`P^%6O___TF+1EC&@,$`
+M```!O@<```!,B??H`````$B#Q`A;74%<05U!7D%?PY!(@^PH2(D<)$B);"0(
+M3(ED)!!,B6PD&$R)="0@28G\2(7_#X3$````2(M'4$R+,$R)]^@`````2(G%
+M2(7`#X2I````3(GWZ`````!)B<5(A<!U$$B)[DR)]^@`````Z8D```!(C5U8
+MQD4EK$$/MT0D.&:)12!,B74HQX64````"````$R);7A)BT402(E%2,=%-``(
+M``!)C80D[````$B)15#&13`@2,>%H`````````#&13@<QD4Y`<9%.@+&13L(
+MQD4\`+X`````2(G?Z`````"+531)BW482(G?Z`````!(B>Y,B??H`````$B+
+M'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9FD&9FD$B#[!A(B1PD2(EL
+M)`A,B60D$$B)\TF)_$B+;F@/MTX@9H'YA0`/AZ4````/M\$/MK0':`@``$"`
+M_O\/A)````!F@_E_=R)`#[;62(N/0`D``$B-!%)(C02"2,'@!4B+1`A0#[9`
+M".M(9H'Y@0!W'4`/ML9(BY>0"0``2&G`R`\``$B+1!`(#[9`".LD0`^VQDB+
+MEV@)``!(C03`2,'@!4B+A!"(````#[9`"&9FD&:0//]T'`^VP$&`O`3N"```
+M_W0.0(#^_W0(#[9#)#P&=3!(@WMX`'0,2(US>$R)Y^@`````2(G>3(GGZ```
+M``#'15#_____2(GO_U5(ZW-F9I"$P'4Y]H.4````"'032(M],(M3-$B+<TCH
+M`````&9FD,=%4`````!(BU4X2(72=`6+12")`DB)[_]52.L3QT50_____TB)
+M[_]52&9FD&9FD$B#>W@`=`Q(C7-X3(GGZ`````!(B=Y,B>?H`````&:02(L<
+M)$B+;"0(3(MD)!!(@\08PV9F9I!F9I!F9I!F9I!(@^PH2(E<)`A(B6PD$$R)
+M9"083(EL)"!(B?-)B?Q$#[9N)`^W1B!F/84`=R-(BX]`"0``#[?`#[:$!V@(
+M``!(C11`2(T4D$B)T$C!X`7K#$B+CT`)``"X8)X!`$B-+`%%A.UU(&;'A<@`
+M`````(![.!QU$8![.@)U"TB)WDB)[^@`````2(-[>`!T#$B-<WA,B>?H````
+M`$B)WDR)Y^@`````08#]!G0]2(V=8`$``$F+?"0H2(G>Z`````#'A6`!``"`
+MA!X`2,>%<`$```````!(B:UX`0``28M\)"A(B=[H`````$B+7"0(2(ML)!!,
+MBV0D&$R+;"0@2(/$*,.005=!5D%505154TB#[`A)B?]!B=9(BT=02(LH0;P`
+M````3(UN#$$/MH0L:`@``#S_=%(/ML!(C11`2(T4D$B)TTC!XP5(B=](`[U`
+M"0``2(''U````+H(````3(GNZ`````"$P'0>2(N%0`D``$2(M`,.`0``2(N%
+M0`D``$R)O`,@`0``28/$`4F!_(````!UE$B#Q`A;74%<05U!7D%?PT%7059!
+M54%455-(@^P82(E\)`A(BTY(#[9!`L'@"`^V40.-/!`/M\>#P`0/MU8T.=`/
+MC^8```!(C5D(#[?'2(U,`01(B4PD$$F)W4@YV0^&N@```$&^`````&9FD&9F
+MD$2)\@^V"X3)#XB%````B<B#X`\\!G5\]D,#P'0&]D,%P'5P]L$0=#F`>P0`
+M9F9FD'1A28UM"$&\`````&9F9I`/ME,#2(GN2(M\)`CH`````$B#Q1Q!@\0!
+M1#AC!'8TZ]^`>P(`="Q)C6T$0;P`````1`^V^D2)^DB)[DB+?"0(Z`````!(
+M@\4<08/$`40X8P)WX@^V0P%)C5P%`DF)W4&#Q@%(.UPD$`^"4O___[X!````
+M2(M\)`CH`````$B#Q!A;74%<05U!7D%?PV9F9I!!5T%6055!5%532(/L*$B)
+M="0(2(E\)!`/MD8DB$0D)P^W3B!F@?F%``^'^`,```^WP0^VM`=H"```N/\`
+M``!`@/[_='IF@_E_=R=`#[;62(M$)!!(BXA`"0``2(T$4DB-!()(P>`%2(M$
+M"%`/MD`(ZTUF@?F!`'<B0`^VQDB+3"002(N1D`D``$AIP,@/``!(BT00"`^V
+M0`CK)$`/ML9(BTPD$$B+D6@)``!(C03`2,'@!4B+A!"(````#[9`"$B82(M4
+M)!!$#[:\`NX(``!+C02_28T$ATB-A,+(`0``2(E$)!A(BXI`"0``0`^VQDB-
+M%$!(C1202(G02,'@!4B-+`&`?"0G``^%LP(``&;'A<@``````$B+3"0(@'DX
+M'`^%FP(```^V03H\`G1:/`)W$3P!#X6'`@``9F9FD&9FD.L>/`=T+SP*#X5R
+M`@``2(MT)`A(B>_H`````.E@`@``2(MT)`A(B>_H`````&9FD.E+`@``2(MT
+M)`A(B>_H`````.DY`@``2(MT)`A(B>_H`````$B-G6`!``!(BT502(L`2(MX
+M*$B)WN@`````QX5@`0``@(0>`$C'A7`!````````2(FM>`$``$B+15!(BP!(
+MBW@H2(G>Z`````#&14K_2XT$OTF-!(=(BU0D$("\PM8!````#X23`0``0;P`
+M````2XT$OTF-!(=(P>`#3(VT`B@"``!(C1P03(VKP`$``$R)]^@`````2(G%
+M2(N#,`(``$B)JS`"``!,B74`2(E%"$B)*(!]2O\/A)8```"`?4D`#X67````
+M2(GN@+WI``````^$5P$```^V54A(B="#X`9(@_@&=2?VP@%T(@^VE8$```!(
+MBW582(GI2(M\)!CH`````.DE`0``9F:09I!(@_@$=1OVP@%F9F:09F:0=`](
+MBWPD$.@`````Z?\```!(@_@&#X7U````]L(!9I`/A>H```!(BWPD$.@`````
+MZ=L```#&A>D`````9F9FD$&#Q`%!#[9%%D0XX`^''____T$XQ`^%A````(3`
+M#X1\````0;P`````2XT$OTF-!(=(P>`#2(M,)!!,C:P!*`(``$B-'`A,C;/`
+M`0``9F:03(GOZ`````!(B<5(BX,P`@``2(FK,`(``$R);0!(B44(2(DH@'U*
+M_W0;#[9%23PB=`0\#74/O@H```!(B>_H`````.L[08/$`44X9A9WL4N-!+])
+MC02'2(M4)!#&A,+1`0``_TB+="082(G7Z`````"`?"0G``^%I````&9F9I!(
+MBTPD"$B#>7@`=!%(B<Y(@\9X2(M\)!#H`````$B+="0(2(M\)!#H`````(!\
+M)"<`=&T/MX7(````@\`!9HF%R````&:#^`IV#F;'A<@``````.G%_?__O@H`
+M``!(B>_H`````.LY2(M$)!!$#[:X[0D``$N-!+])C02'2(M4)!!(C83"R`$`
+M`$B)1"082(N*0`D``+A@G@$`Z9_\__^02(/$*%M=05Q!74%>05_#D$B%_W1+
+M2(7V=$9(A=)T04B%R70\9D&!^(4`=S1!#[?`@+P':`@``/]T)L9"..'&0CD!
+MQD(Z$V9$B4(@2(ER*$B)BJ````"X`0```,-F9F:0N`````##9F9FD&9FD&9F
+MD$"`_@$9P/?0)0``#(!(BU<(B4(,PY"0D)"0D)"0D)"03(M4)"!,BUPD,(GX
+M9H'_(B=W7V:!_R`G#X.4````9H'_0"$/A(D```!F@?]`(6:0=R!F@?\@(71Y
+M9H'_(B%FD'1P9H'_4`=U;V9F9I!F9I#K8&:!_T0A=%EF@?]$(6:0<E9F+1`G
+M9H/X`7=,9F9FD.M`9H'_@B=T.6:!_X(G9I!W$F:!_R0G="EF@?^`)V:0=2;K
+M'F:!_X"19F9FD&9FD'009H'_@)1T"6:!_X!R9I!U!L8&0,8"`L8!!`^V%DB+
+M1"08B!!F0<<"@`!F0<<#``!!Q@$@2(M$)`AFQP```0^V%DB+1"00B!`/M@9F
+M00,"9D$#`TB+5"0H9HD"9D&)`$$/MQ)(BT0D.&:)$$$/MQ*#P@M(BT0D0&:)
+M$,-F9F:055.)\P^W=W!FA?8/A`0!``!,BY>X"0``0;L`````O?____])BP)(
+MA<`/A-0````/MT@@N/\```!!B>AF@?F%``^'C@````^WP40/MHP':`@``$6)
+MR$&`^?]T=6:#^7]W(T$/MM%(BX]`"0``2(T$4DB-!()(P>`%2(M$"%!$#[9`
+M".M,9H'Y@0!W'D$/ML%(BY>0"0``2&G`R`\``$B+1!`(1`^V0`CK)T$/ML%(
+MBY=H"0``2(T$P$C!X`5(BX00B````$0/MD`(9F9FD&9FD$$/ML%(BX]`"0``
+M03C8=2,/M\!(C11`2(T4D$C!X@4/MD0*2*@!=`NH!'0'N`$```#K%T&#PP%)
+M@\((9D$Y\P^%#O___[@`````6UW#9F:02(M'4$R+$$V+FN`0``!%#[=*<+D`
+M````0;@`````ZT,/M_%)BX*X"0``2(L4\$B%TG0MBT(X)?___P`]X0$0`'0>
+M#[='.&8[0B!U%$B)\$C!X`9F1CE$&`AT#F9FD&:0@\$!9D0YR7*W9D0YR703
+M08/``69!@_@?=PBY`````)#KX4$/M\##9F:09F:09F:02(M'4$B%P'0:Q@!P
+M2(M'4$"(<`)(BT=0QD`'`$B+1U"(4`SSPV9F9I!F9F:09F:0\\-F9F:09F9F
+MD&9FD&9FD$&)\4R)RH'B_P$``$B+A[@)``!,BP30387`="L/MK?V````00^V
+M0"6)\=/@#[?X00^WT;C__P``T^`APCG7N`````!,#T7`3(G`PV9FD&:0N```
+M``#&!#@`2(/``4@](`$``'7PQD=$_\9'4/](C4<H2(E'*$B)1S##9F:09F:0
+MN`````#&!#@`2(/``4@]H`$``'7PQH>`````_\9'<O_&AX(````?2(U'($B)
+M1R!(B4<HPV9F9I!F9F:09F9FD$B+!DB+ES@!``!(B8<X`0``2('',`$``$B)
+M.$B)4`A(B0)(QP8`````PV9FD&9FD$B+ER@!``!(B;<H`0``2(V'(`$``$B)
+M!DB)5@A(B3)(@WYP`'0)2(/&<.@`````\\-F9F:09F9FD&9F9I!F9I!(BP9(
+MBY=8`0``2(F'6`$``$B!QU`!``!(B3A(B5`(2(D"2,<&`````,-F9I!F9I!(
+MBP9(BY=(`0``2(F'2`$``$B!QT`!``!(B3A(B5`(2(D"2,<&`````,-F9I!F
+M9I!(BX=X`0``2(FW>`$``$B!QW`!``!(B3Y(B48(2(DPPTB+!DB+EX@!``!(
+MB8>(`0``2(''@`$``$B).$B)4`A(B0)(QP8`````PV9FD&9FD$B+!DB+EV@!
+M``!(B8=H`0``2(''8`$``$B).$B)4`A(B0)(QP8`````PV9FD&9FD$"`_Q=W
+M$4`/ML?_),4`````N#0```##N`0```!F9F:0P[@\````P[@4````9F9FD,.X
+M0````,.X'````&9F9I##N!@```##N"@```!F9F:0P[@@````P[A,````9F9F
+MD,-F9F:09F9FD&9F9I!F9I`/ME9(2(G0@^`&2(/X!G40]L(!#X3;````9F9F
+MD&9FD(!^<O\/A<H```!(BP=$BX@8`0``1(D-`````+D`````N`$```!!B<!!
+MT^!%A<%U,XA.<DB+%T2)P$0)R(F"&`$``$B+!XN`6`$``(D%`````$2)PB'"
+M='A(BP>)D%@!``#K;8/!`8/Y('6U2(L'1(N('`$``$2)#0````"Q`&:0B<JX
+M`0```$&)P$'3X$6%P74VC4(@B$9R2(L71(G`1`G(B8(<`0``2(L'BX!@`0``
+MB04`````1(G"(<)T$TB+!XF08`$``.L(@\$!@_D@=;"`1T0!\\-F9F:09F:0
+M9F:0@'Y0_P^%Q0```$B+!T2+B!@!``!$B0T`````N0````"X`0```$&)P$'3
+MX$6%P74SB$Y02(L71(G`1`G(B8(8`0``2(L'BX!8`0``B04`````1(G"(<)T
+M<TB+!XF06`$``.MH@\$!@_D@=;5(BP=$BX@<`0``1(D-`````+$`9I"X`0``
+M`$&)P$'3X$6%P74SB$Y02(L71(G`1`G(B8(<`0``2(L'BX!@`0``B04`````
+M1(G"(<)T$TB+!XF08`$``.L(@\$!@_D@=;6`1T0!\\-F9F:09F9FD&9F9I!F
+M9I!(BW=`2(7V=#FY`````&:02(M$SEA(A<!T"#B0@0```'0,2(/!`4B#^05T
+M%NOB9H%^0(4`=PQ(A<!F9F:09F:0=06X`````//#9F9FD&9FD$%505154TB)
+M_4F)S<'F"`^VT@'6@'\P``^$U0```$B#?U``#X3*````BX>4````J`E!#Y3`
+MN0````!(Q\<`````08G,#[<4SXGP(=!F.<(/A9`````/M@3-`````#P#=`0\
+M!W4+1#@$S0````!U=I#&120@36/D2,?#`````$(/ME3C!@^V\$B)[^@`````
+M2(M54$(/MD3C!XA"#4V%[70T28M-`$B)RDC!ZB!(BT50B5`#2(M%4(`(@/:%
+ME@````1T$H72=`Y(BT50B4@(2(M%4(`@?TB+55`/MD4P@^@'B$('ZPY(@\$!
+M2(/Y$`^%3O___UM=05Q!7<-F9I!F9I!(@^P(2(V78`$``+@`````2#F78`$`
+M`'002(G7Z`````!(QT`@`````$B#Q`C#9I!(@^P(2(V7@`$``+@`````2#F7
+M@`$``'0(2(G7Z`````!(@\0(PV9F9I!F9I!F9I!(@^P(2(V7<`$``+@`````
+M2#F7<`$``'0H2(G7Z`````!(B<&Z`````&9F9I!F9I#&!`H`2(/"`4B!^J``
+M``!U[TB#Q`C#9F9FD&9FD&9FD$B#[`A(C9=``0``N`````!(.9=``0``=`A(
+MB=?H`````$B#Q`C#9F9FD&9FD&9FD$B#[`A(C9<P`0``N`````!(.9<P`0``
+M=`Q(B=?H`````,9`$`!(@\0(PV9FD&9FD$%7059!54%455-(@^P(28G_08GU
+MQT0D!`````!!O@````!##[:$/N@(```\_P^$'0$```^VT$&-AH````!F/8$`
+M=WT/M\)(:<#(#P``2(G#20.?D`D``(![6`!T4[T`````3(UC2$R)Y^@`````
+M2(U(\$B+4U!(B4-03(EA$$B)41A(B0*+04@E`/__`#T``/\`=1/V04L$=`U(
+MBT%`2(7`=`1$B&@!@\4!0#AK6'>V1(BKP@```$&#Q0'ID`````^WPDB-!,!(
+MP>`%2(G&20.W:`D``(!^.P!T/;D`````#[;!2(M4QEA(A=)T(XM"2"4`__\`
+M/0``_P!U%/9"2P1T#DB+0D!(A<!T!42(:`&0@\$!.$X[=\A$B*X4`0``@+X5
+M`0```W4?@T0D!`&+1"0$@\`#@_@&=A=!@\4!QT0D!`````#K"4&#Q0%F9I!F
+MD$F#Q@%)@_X&#X7$_O__28N'^`@``$PY^'4/2(VXD!0``$2)[NB'_O__2(/$
+M"%M=05Q!74%>05_#9F9FD&9F9I!(@^P(#[9&"`^VM`?N"```QH0'[@@``/\/
+MM_9(@<>($```Z`````!(@\0(PV9F9I!(BU9P2(72=!A(BT(82(E&.$B+0B!(
+MB49`2(M"*$B)1DCSPV9F9I!F9I!F9I!F9I!(BU9P2(72=!Q(BT8X2(E"&$B+
+M1D!(B4(@2(M&2$B)0BC&0A`!\\-F9I!F9I!F9I!!5%5328G\2(L?9H-[<``/
+MA,P```"]`````&9FD&9FD`^WU4B+@[@)``!(BSS02(7_#X2=````#[=/(&:!
+M^84`=WX/M\$/MH0#:`@``#S_=&]F@_E_=R$/MM!(BXM`"0``2(T$4DB-!()(
+MP>`%2(M$"%`/ME`(ZTUF@?F!`'<<#[;`2(N3D`D``$AIP,@/``!(BT00"`^V
+M4`CK*@^VP$B+DV@)``!(C03`2,'@!4B+A!"(````#[90".L*9F:09I"Z_P``
+M`$$/MD0D"#G"=07H`````(/%`68Y:W`/AS____];74%<PV9F9I!F9I!F9I!(
+M@^P82(E<)`A(B6PD$$B)^TB)]0^V1E`\_W03#[;P2(L_Z`````#&15#_@&M$
+M`4B+7"0(2(ML)!!(@\08PV:02(/L&$B)7"0(2(EL)!!(B?M(B?4/MD9R//]T
+M$P^V\$B+/^@`````QD5R_X!K1`%(BUPD"$B+;"002(/$&,-FD%532(/L"$B)
+M_4B)\T@Y?B@/A-L```"`?B0`#X6G````#[9&.#P5=`@\50^%EP```$B+0W!(
+MA<`/A(H```!(B<&`>!`!#X5]````9H%X&.$!=75(B[5`"0``#[=#(+I@G@$`
+M9CV%`'<7#[?`#[:$!6@(``!(C11`2(T4D$C!X@5(C006#[9)&H#Y!W0=@/D'
+M=P>`^09U,>L:@/D,9F:09I!T((#Y#74@ZQ!F@V!J_6:0ZQ5F@TAJ`NL.9H-@
+M:O=FD.L%9H-(:@A(@WMX`'0C@7LT``@``'<.2(US>$B)[^@`````ZPQ(C7-X
+M2(GOZ`````!F@7LXX0$/A2<!```/MT,@9CV%``^'BP````^WP`^VA`5H"```
+M//\/A'@```!(BXU`"0``@'LD`'5K#[;`2(T40$B-%)!(P>(%2(T$$0^V4SJ`
+M^@=T'8#Z!W<'@/H&=3;K'X#Z#'0J@/H-9F:09I!U)>L59H-@:OUF9F:09F:0
+MZQ5F@TAJ`NL.9H-@:O=FD.L%9H-(:@AF@7LXX0%F9I`/A8X```"`>SH+#X6$
+M````#[=S(`^V14:->/^)\NL;D(/"`6:!^H4`=Q`/M\I(8\&`O`5H"```_W4)
+M#[?".?A\W^M-9H'Y_P!U(F9FD&9FD.L^@\8!9H'^A0!W$`^WUDACPH"\!6@(
+M``#_=0P/M\8YQW_?NO\```!FB5,@QD,D@$B)WDB)[^@`````Z2(!``#&0R0`
+M2#EK*'0F2(M#<$B%P'0=@'@0`74+2(G>2(GOZ`````!(C7-P2(GOZ`````!(
+M@[N``````'0/2(VS@````$B)[^@`````2(M[*$B)WO^3H`````^W4SAF@?KA
+M`757#[9#.H/H$3P!=TP/MT,@9CV%``^'J`````^WP`^VA`5H"```//\/A)4`
+M```/ML!(C03`2,'@!4B)QD@#M6@)``"`?D4`=7J`?E#_='1(B>_H`````.MJ
+M#[=#(&8]A0!W8`^WP`^VC`5H"```2(NU0`D``(M#."7___\`/>$!$`!T/X'Y
+M_P```'0W9H'ZX0%U#@^V0SJ#Z!$\`78E9F:0B<A(C11`2(T4D$C!X@5(`=:`
+MOH,`````=0A(B>_H`````$B#Q`A;7<-F9F:09F:055-(@^P(2(G]2(GS#[=.
+M(&:!^84`#X>F````#[?!#[:T!V@(``!`@/[_#X21````9H/Y?W<B0`^VUDB+
+MCT`)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK2&:!^8$`=QU`#[;&2(N7D`D`
+M`$AIP,@/``!(BT00"`^V0`CK)$`/ML9(BY=H"0``2(T$P$C!X`5(BX00B```
+M``^V0`AF9I!FD&8]_P!T&P^WP`^VO`7N"```0(#__W0*0`^VQF8]_P!U$$B)
+MWDB)[^@`````Z8$````/ME,[#[9#/`^V2SV`^0%T!8#Y"'5@2(M+:,'@"`^V
+MT@'0)?\!``!(BY6X"0``2#D,PG5"#[=),HG*9L'J!8'B_P<``(/A'[@!````
+M2-/@]]`A1)5T2(M#:`^W<#)`#[;'2(T\@$B-/+A(C;S]R`$``.@`````2(G>
+M2(GOZ`````!(@\0(6UW#9F9FD&9FD$B#[!A(B5PD"$B);"002(G[2(V_(`$`
+M`+T`````2#F[(`$``'0<Z`````!(B<5(B<?H`````$B)W^@`````2(E%<$B)
+MZ$B+7"0(2(ML)!!(@\08PV9F9I!F9F:09F9FD$B#[!A(B1PD2(EL)`A,B60D
+M$$B)_4B+1U!,BR!,B>?H`````$B)PTB%P'1P3(GGZ`````!(B<)(A<!U%,:%
+MZ0````%(B=Y,B>?H`````.M,QD,X``^W13AFB4,@QH.8````#TR)8RC'0S0`
+M````2,=#2`````!(BT(02(E#4,9#,"1(B5-X2,>#H`````````!(B=Y,B>?H
+M`````$B+'"1(BVPD"$R+9"002(/$&,.02(/L&$B)'"1(B6PD"$R)9"002(G]
+M08GT2(M'4$B+&$B)W^@`````2(G"2(7`=$3&0#@;QD`Y`42(8#P/MT4X9HE"
+M(,:"F`````](B5HHQT(T`````$C'0D@`````2,>"H`````````!(B=9(B=_H
+M`````$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F:09F:02(/L.$B)7"0(2(EL
+M)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_TF)]4R+-TR)]^@`````2(G%2(7`
+M#X2.````3(GWZ`````!)B<1(A<!U$4B)[DR)]^@`````ZW%F9F:02(U=6,9%
+M..'&13D!QD4Z#D$/MT4X9HE%(&9!@V5H]TF+!TB)12C'130`"```28M$)!!(
+MB45(3(EE>$C'A:``````````O@````!(B=_H`````(M5-$F+="082(G?Z```
+M``!(B>Y,B??H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#
+MQ#C#2(/L*$B)7"0(2(EL)!!,B60D&$R);"0@28GTB=5(BQ](B=_H`````$B)
+MPDB%P'1?QD`XX<9`.0%`B&@ZQD`[#T$/MT0D.&:)0B!(B5HHQT(T`````$C'
+M0D@`````2,>"H`````````!(B=9(B=_H`````$"`_0%U#+\%````Z`````#K
+M"K]0PP``Z`````!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9F9I!5
+M4TB#[`A(B?U(B?,/MTX@9H'YA0`/AZ<````/M\$/MK0':`@``$"`_O\/A)(`
+M``!F@_E_=R)`#[;62(N/0`D``$B-!%)(C02"2,'@!4B+1`A0#[9`".M(9H'Y
+M@0!W'4`/ML9(BY>0"0``2&G`R`\``$B+1!`(#[9`".LD0`^VQDB+EV@)``!(
+MC03`2,'@!4B+A!"(````#[9`"&9FD&:0//]T'@^VP`^VC`7N"```@/G_=`Y`
+M@/[_=`@/MD,D/`9U/DB#>W@`="6!>S0`"```=Q!(C7-X2(GOZ`````!FD.L,
+M2(US>$B)[^@`````2(G>2(GOZ`````#K?&9FD&:02(N50`D``(3`=#5`#[;&
+M2(TT0$B--+!(P>8%2(TT,@^VP4B-/(!(C3RX2(V\_<@!``"Z`0```.@`````
+M9F9FD$B#>W@`="6!>S0`"```=Q!(C7-X2(GOZ`````#K#F:02(US>$B)[^@`
+M````2(G>2(GOZ`````!(@\0(6UW#9I!(@^PH2(D<)$B);"0(3(ED)!!,B6PD
+M&$R)="0@2(G[2(GU#[=.(&:!^84`#X<?`0``#[?!#[:T!V@(``!`@/[_#X0*
+M`0``9H/Y?W<D0`^VUDB+CT`)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK16:0
+M9H'Y@0!W'4`/ML9(BY>0"0``2&G`R`\``$B+1!`(#[9`".L?0`^VQDB+EV@)
+M``!(C03`2,'@!4B+A!"(````#[9`"#S_#X25````1`^VY@^VP$0/MJP#[@@`
+M`$&`_?]T?V9!@?S_`'1W@'TD!G1Q3(NS0`D``(!].@%U2;\*````Z`````!(
+MB>Y(B=_H`````$$/M\1(C31`2(TTL$C!Y@5)C30V00^VQ4B-/(!(C3RX2(V\
+M^\@!``"Z`@```.@`````ZQN_]`$``.@`````2(GN2(G?Z`````!F9I!F9I!(
+MBQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HPV9FD$B#[!A(B1PD2(EL)`A,
+MB60D$$F)_$B+1U!(BRA(B>_H`````$B)PTB%P'4+0<:$).D````!ZU_&0#@5
+MQD`EJT$/MT0D.&:)0R!(B6LH0;@!````N0$```!(B=I,B>9(B>_H`````(3`
+M=19(B=Y(B>_H`````$'&A"3I`````>L62,>#H`````````!(B=Y(B>_H````
+M`$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F:02(/L*$B)7"0(2(EL)!!,B60D
+M&$R);"0@2(G[2(M'4$R+*$R)[^@`````2(G%2(7`=0[&@^D````!Z;8```!F
+MD$R)[^@`````28G$2(7`=1?&@^D````!2(GN3(GOZ`````#IC0```,9%.!K&
+M13D(QD4Z",9%.P#&13S_QD4]`,9%):L/MT,X9HE%($R);2C'133_````QX64
+M````"````$F+1"002(E%2$@%_P```$B)15#&13`D3(EE>$C'A:``````````
+M2(U=6+X`````2(G?Z`````!)BW0D&+K_````2(G?Z`````!(B>Y,B>_H````
+M`$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9I!(@^PX2(E<)`A(B6PD$$R)
+M9"083(EL)"!,B70D*$R)?"0P28G\08GV2(M'4$R+*$R)[^@`````2(G#2(7`
+M=1%!QH0DZ0````'IN@```&9FD$R)[^@`````2(G%2(7`=2!!QH0DZ0````%(
+MB=Y,B>_H`````.F.````9F9FD&9FD$R->UC&0S@2183V=!/&0SD!QD,Z@,9#
+M/$#K"69FD&:0QD,\),9#):M!#[=$)#AFB4,@3(EK*,=#-&````#'@Y0````(
+M````2(M%$$B)0TA(B6MX2,>#H`````````"^`````$R)_^@`````2(MU&+I@
+M````3(G_Z`````!(B=Y,B>_H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT
+M)"A,BWPD,$B#Q#C#9F:09F:02(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D
+M($F)_$B+1U!,BS!,B??H`````$B)Q4B%P'4.0<:$).D````!Z;(```!,B??H
+M`````$F)Q4B%P'4<0<:$).D````!2(GN3(GWZ`````#IB0```&9FD$B-75C&
+M13B>QD4Y$,9%12#&126K00^W1"0X9HE%($R)=2C'130@````QX64````"```
+M`$F+11!(B45(3(EM>$B#P"!(B450QD4P)$C'A:``````````QH68````#[X`
+M````2(G?Z`````!)BW48NB````!(B=_H`````$B)[DR)]^@`````2(L<)$B+
+M;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9F:09F:09F:09F:02(/L*$B)'"1(
+MB6PD"$R)9"003(EL)!A,B70D($F)_$B+1U!,BS!,B??H`````$B)Q4B%P'4.
+M0<:$).D````!Z:,```!,B??H`````$F)Q4B%P'4<0<:$).D````!2(GN3(GW
+MZ`````#K?69FD&9FD$B-75C&13@EQD4EJT$/MT0D.&:)12!,B74HQT4T"```
+M`,>%E`````@```!)BT402(E%2$B#P`A(B450QD4P)$R);7A(QX6@````````
+M`+X`````2(G?Z`````!)BW48N@@```!(B=_H`````$B)[DR)]^@`````2(L<
+M)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9F:09F9FD&9F9I!(@^PX2(E<
+M)`A(B6PD$$R)9"083(EL)"!,B70D*$R)?"0P28G_28GTB50D!$B++TR+M4`)
+M```/MT8@1`^VK`5H"```2(GOZ`````!(B<-!#[=T)#*)\&;!Z`4/M\"+1(5T
+MB?&#X1](T_BH`0^%P@```$B%VP^$N0```$$/ML5(C11`2(T4D$C!X@5)C106
+M00^V1"0E#[:-]@```-/@"?#&0SCAQD,Y`<9#.@^(0SMFP>@(B$,\#[9$)`2(
+M0SU(BX+<````2(E#/DR)8VC&0R6J#[=".&:)0R!)BP=(B4,HQT,T`````$C'
+M0T@`````2,>#H`````````!(C7M8O@````#H`````$B)WDB)[^@`````00^W
+M3"0RB<IFP>H%@>+_!P``@^$?N`$```!(T^`)1)5T2(M<)`A(BVPD$$R+9"08
+M3(ML)"!,BW0D*$R+?"0P2(/$.,-F9F:09F:09F:005=!5D%505154TB#[`A)
+MB?Y)B=5!B?=(BQ]F@WMP``^$#@(``+T`````0;S_____#[?52(N#N`D``$B+
+M--!(A?8/A-\!``!$BT8X08'@____`$&!^.$!$``/A:$```!-A>T/A;X!```/
+MMTX@9H'YA0!W>0^WP0^VA`-H"```//]T:F:#^7]W(0^VT$B+BT`)``!(C012
+M2(T$@DC!X`5(BT0(4`^V2`CK1F:!^8$`=QP/ML!(BY.0"0``2&G`R`\``$B+
+M1!`(#[9(".LC#[;`2(N3:`D``$B-!,!(P>`%2(N$$(@````/MD@(ZP-$B>&Z
+M`````.F_````9F9FD&9FD`^W3B!F@?F%``^'H0````^WP0^VO`-H"```0(#_
+M_P^$C````&:#^7]W(D`/MM=(BXM`"0``2(T$4DB-!()(P>`%2(M$"%`/MD@(
+MZT1F@?F!`'<=0`^VQTB+DY`)``!(:<#(#P``2(M$$`@/MD@(ZR!`#[;'2(N3
+M:`D``$B-!,!(P>`%2(N$$(@````/MD@(D$`/ML=(C11`2(T4D$C!X@5(`Y-`
+M"0``ZP]F9F:09F:01(GAN@````!!.$X(=6A-A>UT"T$/MT4X9CM&('5808#_
+M!G1#08'XX0$0`'0Z#[9*2$B)R(/@!DB#^`9U*O;!`74E@+KH`````'4<08'X
+MX0$/`'0B1(A^)+H!````3(GWZ`````#K#T2(?B0/M_5,B??H`````(/%`68Y
+M:W`/A_W]__]!@/^!#X17`0``2(N#``$``$B-JP`!``!(.<4/A$`!``"Z````
+M`&9F9I!F9I"#P@%(BP!(.<5U]6:%T@^$(`$``$2-8O](B>_H`````$B)QDV%
+M[70H00^W13AF.T8@=!U(BX,(`0``2(FS"`$``$B)+DB)1@A(B3#IR`````^W
+M3B!F@?F%`'=Y#[?!#[:$`V@(```\_W1J9H/Y?W<A#[;02(N+0`D``$B-!%)(
+MC02"2,'@!4B+1`A0#[9`".M(9H'Y@0!W'`^VP$B+DY`)``!(:<#(#P``2(M$
+M$`@/MD`(ZR4/ML!(BY-H"0``2(T$P$C!X`5(BX00B`````^V0`CK!;C_____
+M03I&"'4ABT8X)?___P`]X0$/`'021(A^)$B)W^@`````ZQQF9F:02(N#"`$`
+M`$B)LP@!``!(B2Y(B48(2(DP08U$)/]F187D=!%(.ZL``0``=`A!B<3IY/[_
+M_TB#Q`A;74%<05U!7D%?PV9F9I!F9I!F9I!F9I!(@^PX2(E<)`A(B6PD$$R)
+M9"083(EL)"!,B70D*$R)?"0P28G\28GV28G-08G72(LO2(GOZ`````!(B<-(
+MA<!U#T'&A>D````!Z8L```!FD$B)[^@`````2(G"2(7`=15(B=Y(B>_H````
+M`$'&A>D````!ZV3&0SCAQD,Y`<9#.A!$B'LE00^V1EMFB4,@28L$)$B)0RC'
+M0S20````2(U"$$B)0TA(B5-XQD`!$L9"$$!$B'@)2,>#H`````````!(C7M8
+MO@````#H`````$B)WDB)[^@`````2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D
+M*$R+?"0P2(/$.,-F9F:02(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,
+MB7PD,$F)_$F)]4&)UD&)STB++TB)[^@`````2(G#2(7`#X2"````2(GOZ```
+M``!(B<)(A<!T<L9#..'&0SD!QD,Z$$2(<R5!#[9%6V:)0R!)BP0D2(E#*,=#
+M-)````!(C4(02(E#2$B)4WC&0`&1QD(00$2(<`E$B'@*2,>#H`````````!(
+MC7M8O@````#H`````$B)WDB)[^@`````OZ"&`0#H`````$B+7"0(2(ML)!!,
+MBV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F:09F:02(/L*$B)'"1(B6PD"$R)
+M9"003(EL)!A,B70D($F)_$F)]4&)UDB++TB)[^@`````2(G#2(7`='1(B>_H
+M`````$B)PDB%P'1DQD,XX<9#.0'&0SH0QD,ENT$/MD5;9HE#($F+!"1(B4,H
+MQT,TD````$B-0A!(B4-(2(E3>,9``1#&0A!`1(AP"4C'@Z``````````2(U[
+M6+X`````Z`````!(B=Y(B>_H`````$B+'"1(BVPD"$R+9"003(ML)!A,BW0D
+M($B#Q"C#9F9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($F)_$F)]4B+
+M+TB)[^@`````2(G#2(7`='!(B>_H`````$B)PDB%P'1@QD,XX<9#.0'&0SH0
+MQD,ENT$/MD5;9HE#($F+!"1(B4,HQT,TD````$B-0A!(B4-(2(E3>,9``0#&
+M0A!`2,>#H`````````!(C7M8O@````#H`````$B)WDB)[^@`````2(M<)`A(
+MBVPD$$R+9"083(ML)"!(@\0HPV9FD&9FD%532(/L"$B)_4B-GX@0``!(B=_H
+M`````(3`#X7@````2(G?Z`````")P;@`````B<:`O"CN"```_W4*.$5(<Q*(
+M14CK#8/&`4B#P`%(@_@$==U`@/X$#X2D````0`^VQHB,!>X(```/M_E(C02_
+M2(T$ATB-E,7(`0``N`````"0Q@00`$B#P`%(/:@```!U\`^WP4B-%(!(C120
+M2,'B`TB-C!7X`0``2(T$*DB)B/@!``!(B8@``@``2(V,%1`"``!(B8@0`@``
+M2(F(&`(``$B-E!4H`@``2(F0*`(``$B)D#`"``!`B+#0`0``2(T$OTB-!(=(
+MC83%R`$``.L'9I"X`````$B#Q`A;7<-F9F:02(/L&$B)'"1(B6PD"$R)9"00
+M2(G]2(V?X`\``$B)W^@`````A,`/A3D!``!(B=_H`````(G"N`````!F9I!F
+MD(G#@+PH:`@``/]U%0^VP&8YA?0```!S&&:)A?0```#K#X/#`4B#P`%(/8``
+M``!UT(#[@`^$[`````^VPXB4!6@(```/M\)(C11`2(T4D$F)U$G!Y`5,B>=(
+M`[U`"0``Z`````!(BY5`"0``#[;#9D&)1!0X2(N%0`D``$'&1`1*`$B+A4`)
+M``!!QD0$;?](BX5`"0``0<9$!&S_2(N%0`D``$'&1`1N_TB+A4`)``!!QD0$
+M</](BX5`"0``0<9$!&__2(N%0`D``$'&1`1Q_TB+A4`)``!!QH0$Z@````!(
+MBX5`"0``0<:$!`\!``#_2(GOZ`````!(BY5`"0``28F$%"@!``"`?4T!=0U(
+MBX5`"0``08!,!$P!3(G@2`.%0`D``.L%N`````!(BQPD2(ML)`A,BV0D$$B#
+MQ!C#9F:04TB)^^A'X?__2(N[^`@``.@`````6\-F9I!F9I!F9I!(@^P82(D<
+M)$B);"0(3(ED)!!(B?U(C9\8$```2(G?Z`````"$P`^%Y@```$B)W^@`````
+MB<)(B>B[@O___V:0@+CJ"```_W47.)WX````<R&(G?@```#K&69F9I!F9I"#
+MPP%(@\`!@/N&#X2B````Z\Z`^X8/A)<````/ML.(E`5H"```#[?"2(T$P$F)
+MQ$G!Y`5,B>=(`[UH"0``Z`````!(BY5H"0``#[;#9D&)1!1`@'U-`74/2(N%
+M:`D``&9!QT0$3/__2(N%:`D``$'&1`1"`$B+A6@)``!F0<=$!$X``$B+A6@)
+M``!F0<>$!``!``#__TB+O?@(``"^`````.@`````3(G@2`.%:`D``.L%N```
+M``!(BQPD2(ML)`A,BV0D$$B#Q!C#9F:09F:055-(@^P(2(G]#[=&0`^VG`=H
+M"```QH0':`@``/\/M_-(C;\8$```Z``````/M]M(C1S;2,'C!4B)WD@#M6@)
+M``"`?E#_=`A(B>_H`````$B+O?@(``"^`````.@`````2(/$"%M=PV9FD&9F
+MD&9FD%-(B?L/MD9;#[:T!V@(``#&A`=H"```_P^W]DB-OU`0``#H`````$B+
+MN_@(``"^`````.@`````6\-F9I!F9I!32(GS@'Y$_W042(VVD````$B+?RCH
+M`````,9#1/];PU-(B?.`OH````#_=!=(C;8P`0``2(M_*.@`````QH.`````
+M_UO#9F9FD&9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)^TF)]`^W
+M1CA$#[:L!V@(``!!#[?%2(T40$B-%)!(B=5(P>4%2(GN2`.W0`D``$B!QB@!
+M``#H`````$$/MU0D.$B+A--H!```2(7`=!E(@[B``````'4/2,>$TV@$````
+M````9F:000^W1"0XQH0#:`@``/]!#[?U2(V[X`\``.@`````2(GN2`.S0`D`
+M`(!^<O]T"$B)W^@`````3(GF2(G?Z`````!(BX-`"0``QD0%2@!(BX-`"0``
+MQD0%2P%(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9F9I!F9I!F9I!(
+M@^PH2(E<)`A(B6PD$$R)9"083(EL)"!)B?U(B?-F@7XXX0$/A<X````/MD8Z
+M@^@1/`$/A[\````/MT8@9CV%``^'B@$```^WP`^VA`=H"```2(N7:`D``#S_
+M#X1P`0``#[;`2(T$P$C!X`5(C2P"@&U%`4R-92A,B>?H`````$B)PD@YV'5*
+M2(GN3(GOZ`````!,.V4H#X0T`0``QX60`````!)Z`$C'A:``````````2(FM
+MJ````$B-M9````!)BWTHZ`````#&140`Z?\```!(BT4H2(E0"$B)`DR)8@A(
+MB54H2(L32(M#"$B)0@A(B1#IV0````^W0R!F/84`#X?+````#[?`00^VE`5H
+M"```28N-0`D``(M#."7___\`/>$!$``/A*4```"!^O\````/A)D```")T$B-
+M%$!(C1202,'B!4B-+!&`K8,````!3(UE($R)Y^@`````2(G"2#G8=4M(B>Y,
+MB>_H`````$P[92!T6\>%,`$````2>@!(QX5``0```````$B)K4@!``!(C;4P
+M`0``28M]*.@`````QH6``````.LF9F:09I!(BT4@2(E0"$B)`DR)8@A(B54@
+M2(L32(M#"$B)0@A(B1!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F:09F:0
+M55-(@^P(2(G[2(GU#[=^,HGZ9L'J!0^W]XGQ@^$?N`$```!(T^")P??1@>+_
+M!P``(4R3=&:!__\/=$0/M\=(P>`#2`.#N`D``$B#.`!T,$C'```````AC)/`
+M"0``2(V[J`\``.@`````2(GN2(G?Z`````!(B>Y(B=_H`````$B#Q`A;7<-F
+M9F:09F:09F:055-(@^P(2(GU9H%^..$!#X6L````#[9&.H/H$3P!#X>=````
+M#[=&(+K_````9CV%`'<+#[?`#[:4!V@(``")T$B-!,!(P>`%2(G#2`.?:`D`
+M`(![1/]U20^VE9@```"-!!*$TKH(````#T3"#[;`:<!`0@\`B8.0````2,>#
+MH`````````!(B9NH````2(VSD````$B+?RCH`````,9#1`!(BU,P2(EK,$B-
+M0RA(B44`2(E5"$B)*H!#10'IO0````^W12"Z_P```&8]A0!W"P^WP`^VE`=H
+M"```2(N/0`D``(M%."7___\`/>$!$``/A(D```")T$B-%$!(C1202,'B!4B-
+M'!&`NX````#_=5`/MI68````C002A-*Z"`````]$P@^VP&G`0$(/`(F#,`$`
+M`$C'@T`!````````2(F;2`$``$B-LS`!``!(BW\HZ`````#&@X``````9F9F
+MD$B+4RA(B6LH2(U#($B)10!(B54(2(DJ@(.#`````4B#Q`A;7<-F9F:09F9F
+MD&9FD$%7059!54%455-(@^PH28G^2(ET)`@/MTX@9H'YA0`/AP4#```/M\$/
+MMK0':`@``(GP0(#^_W1K9H/Y?W<B0`^VUDB+CT`)``!(C0122(T$@DC!X`5(
+MBT0(4`^V0`CK0V:!^8$`=QU`#[;&2(N7D`D``$AIP,@/``!(BT00"`^V0`CK
+M'T`/ML9(BY=H"0``2(T$P$C!X`5(BX00B`````^V0`@/ML!%#[:$!NX(``!+
+MC02`28T$@$F-A,;(`0``2(E$)!!)BY:0"0``0`^VQDAIP,@/``!,C3P"2(M$
+M)`A(BU!(#[9"`3P2="D\D0^%$@(``$N-!(!)C02`N0````!!@+S&U@$````/
+MA,H!``#I6P$``$N-!(!)C02`28T$QDB+B,@!``!(B4PD(`^V2@F(3"0>#[92
+M&HA4)!^[`````("XU@$```!T<$&\`````$N-!(!)C02`2,'@`TV-K`8H`@``
+M2HTL,$R-M<`!``"03(GOZ`````!(B<-(BX4P`@``2(F=,`(``$R)*TB)0PA(
+MB1A,.7M8=1</MH.!````2(M4)`@Z0B5T$&9FD&9FD$&#Q`%%.&86=[9(BTPD
+M"$B+<7A(A?9T"DB+?"0@Z`````!(BW0D"$B+?"0@Z``````/MH/*````C5`!
+MB)/*````/`-W*X!\)!\`=21(BT0D"`^V4"5(BW-80;@`````N0(```!(BWPD
+M$.@`````ZS.-0@&(@\H```"`^@)V)8!\)!\`=1[&0TL"QD-*_X!C3/Y(B=Y(
+MBWPD(.@`````Z04!```/MDPD'P^V5"0>3(G^2(M\)!#H`````.GI````O0``
+M``!+C02`28T$@$C!X`--C:0&*`(``$J-'#!,C:O``0``3(GGZ`````!(B<%(
+MBX,P`@``2(F+,`(``$R)(4B)00A(B0A,.7E8=10/MH&!````2(M4)`@Z0B5T
+M#&9FD(/%`4$X;19WN@^V44A(B="#X`9(@_@&=1SVP@%T%TB+1"0(#[90)4B+
+M<5A(BWPD$.@`````2(M4)`A(BW)X2(7V=`A,B??H`````$B+="0(3(GWZ```
+M``#K+D0/MH?M"0``2XT$@$F-!(!(C83'R`$``$B)1"002(N7D`D``+@XN`\`
+MZ7[]__](@\0H6UU!7$%=05Y!7\-F9I!F9I!F9I!!54%455-(@^P(28G]28GT
+M2(G3QD)+`<9"2@"^!@```$R)Y^@`````2(-[6`!T%TB+4Q!(BT,82(E""$B)
+M$$B+0UB`:%@!@+N#`````'0<D$R)[^@`````OP$```#H`````("[@P````!U
+MY4B+NR`!``!(A?]T$0^VLPT!``"Z`0```.@`````2(M[6$B%_W01#[:S@0``
+M`+H!````Z`````!(BVM`2(7M#X2*````2(.]@`````!U<$B#O8@`````=6;V
+M0TP$=1E,B>_H`````$B+<T"Z`0```$R)[^@`````2(M#0`^V4`(/MG`!2,?'
+M`````+@`````Z`````!(BU-`28NU^`@``+\!````Z`````!(BU-`28NU^`@`
+M`+\&````Z`````!(QT-``````$C'16``````2(M38$B%TG00#[:#@0```$C'
+M1,)8`````$B+$TB+0PA(B4((2(D008!L)`X!2(G>3(GOZ`````!!@'PD"?]T
+M74&`?"0.`'1$NP````!)C6PD8&9FD&:02(GOZ`````!)BU0D:$F)1"1H2(DH
+M2(E0"$B)`H!X2O]U#(/#`4$X7"0.=@GKTD$X7"0.=Q%!QD0D"?],B>9,B>_H
+M`````$B#Q`A;74%<05W#9F9FD&9F9I!F9F:09F:005=!5D%505154TB#[`A)
+MB?])B?9(B=7&0DL!QD)*`+X&````3(GWZ`````!(@WU8`'072(M5$$B+11A(
+MB4((2(D02(M%6(!H6`&`O8,`````=!M,B?_H`````+\!````Z`````"`O8,`
+M````=>5(B[T@`0``2(7_=!$/MK4-`0``N@$```#H`````$B+?5A(A?]T$0^V
+MM8$```"Z`0```.@`````2(M=0$B%VP^$$0$``/9%3`1U34R)_^@`````2(MU
+M0+H!````3(G_Z`````!(BT5`#[90`@^V<`%(Q\<`````N`````#H`````$B+
+M54!)B[?X"```OP$```#H`````.LN#[93`@^V<P%(Q\<`````N`````#H````
+M`$B+54!)B[?X"```OP$```#H`````$B+BX````!(A<D/A#<!```/MT4X2<>$
+MQV@$````````2,>#@`````````!(B[N0````NO____](B=[_T>D&`0``#[=%
+M.$G'A,=H!````````$C'@X@`````````2(N[D````/_2]D5,`G052(M50$F+
+MM_@(``"_!@```.@`````2,=%0`````!(QT-@`````$B+56!(A=)T$`^VA8$`
+M``!(QT3"6`````!(BU4`2(M%"$B)0@A(B1!!#[96#H/J`4&(5@Y(BT5@2(7`
+M=`=F@WA.`G59A-)T54&\`````$V-;F!,B>_H`````$B)PTF+1FA)B5YH3(DK
+M2(E#"$B)&$B%VW0?]D-,`G092(M30$F+M_@(``"_!@```.@`````@&-,_4&#
+MQ`%%.&8.=[5(B>Y,B?_H`````$B#Q`A;74%<05U!7D%?PTB+DX@```!(A=(/
+MA>K^___I"?___Y!(@^PH2(E<)`A(B6PD$$R)9"083(EL)"!(B?M(BT=03(LH
+M3(GOZ`````!(B<5(A<`/A-4```!,B>_H`````$F)Q$B%P'4:QH/I`````4B)
+M[DR)[^@`````Z:X```!F9I#&13B@2(U5.;@`````9F:0Q@00`$B#P`%(@_@%
+M=?+&13X`QD4_`,9%0`#&14&(QD5"`,9%0P#&126K#[=#.&:)12!,B6THQX64
+M````"````,=%-(@```!)BT0D$$B)14A(!8@```!(B450QD4P)$R)97A(QX6@
+M`````````$B-75B^`````$B)W^@`````28MT)!BZB````$B)W^@`````2(GN
+M3(GOZ`````!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9F9I!F9F:0
+M55-(@^P(2(G]2(V?4!```$B)W^@`````A,`/A0@!``!(B=_H`````(G"N8#_
+M__^`O>@(``#_=!*`O>D(``#_#X7C````N8'___\XC?<```!S!HB-]P```(#Y
+M@@^$QP````^VP8B4!6@(```/M\)(:=C(#P``2(G:2`.5D`D``+@`````Q@00
+M`$B#P`%(/<@/``!U\$B)VD@#E9`)``!(C4(82(E"&$B)VD@#E9`)``!(C4(8
+M2(E"($B)VD@#E9`)``!(C4(H2(E"*$B)VD@#E9`)``!(C4(H2(E",$B)VD@#
+ME9`)``!(C4)(2(E"2$B)VD@#E9`)``!(C4)(2(E"4$B+A9`)``"(3`-;2(N]
+M^`@``+X`````Z`````!(B=A(`X60"0``ZP6X`````$B#Q`A;7<-F9F:09F9F
+MD&9F9I!!5%-(@^P(28GT2(N?X!```$B!QZ@/``#H`````(G!#[?`2,'@!D@!
+MV$F)!"2Z`````,8$`@!(@\(!2(/Z0'7R#[?!2(/$"%M!7,-F9I!FD$B#[`A(
+MC9=0`0``N`````!(.9=0`0``=`A(B=?H`````$B#Q`C#D)"0D)"0D)"0D$`/
+MMO9(C33V2,'F!X'&8%<``(DWPV9F9I!F9F:09F:0#[;2#[=$5GB#P`%FB416
+M>`^V5@(!T`^WP,-F9I!F9I"X`0```("_NT(```%T$X/``4B!Q[````"#^"!U
+MZ&:X___SPV9F9I!F9I!F9I!F9I!(B?FX`0```$`XL;A"``!U'SB1N4(``'47
+MB<!(C12`2(T44$C!X@3&A!<+0@```<.#P`%(@<&P````@_@@=<GSPV9F9I!F
+M9F:09F9FD&9FD,8!_D0/ME<$1832=$Y)B?A!N0````!!NP````"X`````$DY
+ML-A9``!U'D$XTW452)A(C03`2,'@!P^VA`?$5P``B`'#08/#`4&#P0&#P`%)
+M@<"`!```13C1=<;SPV9FD$F)^H#Z`7081`^V1P2_`````$6$P`^$<`$``.E!
+M`0``0;L`````387`#X0<`0``#[97!$&[`````(32=#1(B?A!NP````!!N0``
+M``!F9F:02#FPV%D``'4)03C)=!-!@\$!08/#`4@%@`0``$$XTW7?00^V^TAC
+MSTB-#,E(P>$'28V4"F!7``!(BP))B0!(BT((28E`"$B+0A!)B4`02(M"&$F)
+M0!A(BT(@28E`($B+0BA)B4`H2(M",$F)0#!(BT(X28E`.$B+0D!)B4!`2(M"
+M2$F)0$A(BT)028E`4$B+0EA)B4!8BT)@08E`8$&`O`I@5P```'13O@````!(
+M8\=(C03`2(T\Q0````!.C0P10`^VQDB)PDC!X@1)C4P08$B-!`=(P>`$28V4
+M`N!9``!(BP)(B4$$2(M""$B)00R#Q@%!.+%@5P``=\5!#[;#2(T$P$C!X`=!
+M#[:$`F!7``##3(G2N0````"_`````&:02#FRV%D```^4P`''@\$!2('"@`0`
+M`$0XP77E0`^VQ\-!54%455-(B?-)B=5-B<Q!B<E$B<5)B?B^`````&9FD(GQ
+M2#E?(`^%A0```$ACQDAIP%`0``!-C50`($&[`````$2)VD$/MD(LA,!T!#SP
+M=4](8])(8\E(B=!(P>`%2&G)4!```$@!R$P!P$B)6#!,B6@X2,'B!4B-5`H@
+M2HT$`DB-2"!FB6D"1(A(($F+!"1)B400),9!#/_K%F9FD&:008/#`4F#PB!!
+M@?N"````=9"#Q@%(@<=0$```@_X$#X5<____6UU!7$%=PV9FD&:0055!5%53
+M2(/L"$F)]4B)_8!_!`!T1D&\`````&9F9I!!#[;<2&/#2(T$P$C!X`>`O`7$
+M5P``_7092(V\!;Q7``"Z"````$R)[N@`````A,!U#T&#Q`%$.&4$=\2[_P``
+M`(G82(/$"%M=05Q!7<-FD%-(B?OH`````+H)````//]T$P^VP$B-!,!(P>`'
+M#[:4`V97``")T%O#9F9FD&9FD$B#[`A)B?))B=%$B<)(B?Y,C8=@00``N```
+M``!F9F:00L8$``!(@\`!2#V0````=>_&AF%!```3QH9@00``0`^VQHB&9D$`
+M`(B69T$``(B.:4$``$C'A@!"````````2(F^^$$``$F+05Q(B8;P00``2('&
+M8$$``$R)U^@`````2(/$",-F9F:09F9FD&9FD$%505154TB#[`A)B?5)B=1,
+MB<U!B<E$B<-(B?A)B?JZ`0```$&)TT&)T("XNT(```$/A>X```!(8])(C022
+M2(T$0DC!X`1,`=!(C9``0@``QD(+`$R)D/A!```/MDH*2&/!2(T4@$B-%%!(
+MP>($28V4$F!!``"X`````&9FD&:0Q@00`$B#P`%(/9````!U\$ACP4B--(!(
+MC31P2,'F!$J-%!9(C8I@00``QD$!D,:"8$$``$`/ML>(00:(FF=!``!$B$D)
+M2(M%`$F)A#)P00``26/`2(T4@$B-%%!(P>($2HT$$DC'@`!"````````2(FX
+M^$$``$F+1"1<28F$$O!!``!!#[;#2(T4@$B-%%!(P>($28VT$F!!``!,B>_H
+M`````.L7@\(!2`6P````@_H@#X7M_O__N`$```!(@\0(6UU!7$%=PV9FD&9F
+MD&9FD$B#[`A)B?-!B=)(B?I)B?BX`0```(G&@+J[0@```0^%X0```$B82(T4
+M@$B-%%!(P>($28V$$`!"``!$B%`(B$@)QD`+`$0/MD@*26/!2(T4@$B-%%!(
+MP>($28V4$&!!``"X`````,8$$`!(@\`!2#V0````=?!)8]%(C0222(T$0DC!
+MX`1,`<!(C9!@00``QD(!$,:`8$$``$"(2@E(8\9(C0R`2(T,2$C!X01!#[:$
+M"`I"``!(C12`2(T44$C!X@1*C00"2,>``$(```````!(B;CX00``00^VPDB-
+M!,!(P>`'28N$`+Q7``!)B80(\$$``$F-M!!@00``3(G?Z`````#K%8/``4B!
+MPK````"#^"`/A?W^__^P`4B#Q`C#D$B#[`A)B?&)T$B)_L:'"T(```!,C8=@
+M00``N0````"00L8$`0!(@\$!2('YD````'7NQH9A00```<:&8$$``$!(QX8`
+M0@```````$B)OOA!```/ML!(C03`2,'@!TB+A`:\5P``2(F&\$$``$B!QF!!
+M``!,B<_H`````$B#Q`C#2(/L"$F)\8G02(G^QH<+0@```$R-AV!!``"Y````
+M`)!"Q@0!`$B#P0%(@?F0````=>[&AF%!````QH9@00``0$C'A@!"````````
+M2(F^^$$```^VP$B-!,!(P>`'2(N$!KQ7``!(B8;P00``2('&8$$``$R)S^@`
+M````2(/$",-!5T%6055!5%532(/L.$B)?"082(ET)!!!B=5$B$0D#TF)_$4/
+MMO5)8\9(C03`2,'@!X"\!\17``#]#X3&"```@/D0#X2%`@``@/D0=Q>$R0^$
+MG0```(#Y`0^%IP@``)#I!@$``(#YXG0;@/G_9F:0="F`^9`/A8L(``!F9I!F
+MD.G(!@``N0````"`?P0`9I`/A=P'``#I!`@``$ECQDB-!,!(P>`'QH0'Q%<`
+M`/^`OPM"```!=25$B?)(BW0D$$B+?"08Z`````"%P`^%-0@``$&`1"0&`>DJ
+M"```26/&QD0'!P%(BU0D$$B)5,<0Z1,(``"`OPM"```!=5A(C8]@00``26/&
+M2(T$P$C!X`=(`?@/ME$)B)!B5P``2`7`5P``#[91"H/B`8A0!<9`!`!$B?)(
+MBW0D$$B+?"08Z`````"%P`^%O0<``$&`1"0&`>FR!P``26/&QD0'!P%(BTPD
+M$$B)3,<0Z9L'``!)8\9(C03`2,'@!TB--#@/MI>200``B):R5P``#[>7D$$`
+M`&:)E`>P5P``2(N7B$$``$B)E`>@5P``2(N7;$$``$B)E`=P5P``2(V,!X!7
+M``!(BY=T00``2(D12(N7?$$``$B)40B+EX1!``")E`>85P``QH;$5P```8!_
+M!A\/A!<'``"[`````$B-KF!7``!,C:ZP5P``ZTD/MLM$B?)(BW0D$$B+?"08
+MZ`````"%P'0526/&2(T$P$C!X`=!B)P$LU<``.L@@\,!08!$)`8!.%T"#T7#
+M08A%`T&`?"0&'W0%.ET"<K)!QH0D"T(```%!#[9T)`1`A/8/A)P&``"Z````
+M`$&`?"0'`707ZT-F9F:09F:0#[;12&/"08!\!`<!=3-(8\)!QD0$!_])BW3$
+M$$&Y`````$&X`````+G_````2(M\)!CH`````.E*!@``N0````"#P0%`./%U
+MM^DX!@``38G/28U!&$B)1"0@2(UT)#!)BT$82(E$)#!)8\9(C03`2,'@!TB-
+M+#A(C87`5P``QD`$$$'V00QP#X1"`P``2(N5R%<``$B%TG1Q#[98!DB->ERZ
+M"````.@`````A,!U6T'V1P\/=%1(BX7(5P``2(7`=$A(B<6`?64`=#\/MMN)
+MVDB)[DR)Y^@`````3(M,)"!$#[?`B=E(B>I(BW0D$$B+?"08Z``````/MEUF
+M2(M%:$B%P'0%2(G%Z[M!#[9/#_;!#0^$ZP```$ECQDB-%,!(B=!(P>`'00^V
+MM`1@5P``0(#^'P^'R@```/;!"'070`^VQDB-!-!(P>`$0<:$!.!9```&ZQQ`
+M#[;626/&2(T$P$B-!,)(P>`$0<:$!.!9```'0`^VQDEC]DB--/9(C13P2,'B
+M!$F-O!3@60``QD<!`$$/MD</B$<#2(M$)#!)B804Z%D``$$/MD<)B$<"00^V
+M5PV#X@](P>8'3`'F2(V.8%<```^V008XP@]'T(/B#P^V1P2#X/`)T(A'!$$/
+MME<I@^(/#[9)!CC*#T?1P>($@^`/"="(1P2`AF!7```!Z<P!``#VP0(/A,,!
+M``!(C70D,$R)Y^@`````B<$\_P^%8@$``$$/MDPD!(3)=#U!#[:$),17```\
+M_W0PN@`````\_74>ZR4/ML)(C03`2,'@!T$/MH0$Q%<``#S_=!(\_70.@\(!
+M.,IUW>L%N@`````/ML)(C03`2,'@!TF-C`1@5P``N`````#&!`@`2(/``4B#
+M^&1U\D0/MM))8])(C1322,'B!TJ-/")!#[;%2(T$P$C!X`=)C80$8%<``$B)
+MA\A7``!-C804L%<``$ECUDB-%-)(P>('28N$%+Q7``!)B4`$2(M,)!!(B8_8
+M60``3`'B2(N"T%<``$B)A]!7``!,C8_`5P``0<9!!/](C;=@5P``#[9.!T$/
+MMD<)B(0/:%<``(!&!P%!#[9'#8/@#P^VDF97```XT`]'PHA&!DB+1"0P28E`
+M#$$/MD</B$8##[9$)`]!B$$&00^V1"0%03I$)`1U!D'&1"0%`$&`1"0%`4EC
+MPD'&1`0'`4B+5"0028E4Q!#K2DECQDB-!,!(P>`'#[;12(T4TDC!X@=)C904
+M8%<``$DYE`3(5P``="(/ML%(C03`2,'@!TP!X`^V<@=!#[9/"8B,,&A7``"`
+M0@<!00^V5PE$B?9,B>?H`````$ECQDB-!,!(P>`'08"\!+-7````#X2@````
+M08!\)`8?=6/I@`(``$'&1P00#[9+`T2)\DB+="002(M\)!CH`````(7`#X5=
+M`@``08!$)`8!#[9+`P^VP8/``0^V50(YT'4/QD,#`.D\`@``9F:09F:0C4$!
+MB$,#08!\)`8?#X0D`@``ZR-)8\9(C03`2,'@!TP!X$B-F+!7``!(C:A@5P``
+M3(VXP%<```^V0P,Z10(/@G+____I[0$``$&`?"0&``^%X0$``$&Y`````$&X
+M`````+F0````1(GR2(MT)!!(BWPD&.@`````Z;D!``!)B?U!OP````!(BTPD
+M$$DY32`/A8,```!$B?A(:<!0$```28U<!""]`````$2)^$AIP%`0``!(B00D
+M@'LL_W5*08!\)`8?#X1M`0``B>A(P>`%2(L4)$B-1!!`#[9+($B+4QA-C4P$
+M!$0/MT,B2(MT)!!(BWPD&.@`````A<!U"D&`1"0&`<9#+/!(@\4!2(/#($B!
+M_8(```!UGTF#QP%)@<50$```28/_!`^%6?___T&`?"0&``^%_0```$$/MG0D
+M!$"$]@^$RP```+H`````08!\)`<!=!#K/`^VT4ACPD&`?`0'`74S2&/"0<9$
+M!`?_28MTQ!!!N0````!!N`````"Y_P```$B+?"08Z`````#IHP```+D`````
+M@\$!0#CQ=;?K<0^VP4B-!,!(P>`'28V4!,!7```/MD($//UT"#S_=`3&0@3^
+M@\$!03A,)`1WTTECQDB-!,!(P>`'28NL!-!7``"[`````$*`?",H`7420L9$
+M(R@`2HMT(R!(BWPD&/_52('#4!```$B!^T!!``!T)>O40;D`````0;@`````
+MN>(```!$B?)(BW0D$$B+?"08Z`````!(@\0X6UU!7$%=05Y!7\-F9F:09F9F
+MD&9FD$B#[!A(B1PD2(EL)`A,B60D$$F)_$B)]4B+GI@```"`>P8`#X1'`0``
+M2(VVD````$B)W^@`````B<$\_P^$+@$``$B)[@^V10$\`71:/`%R&CP0#X2*
+M````/)!F9I!FD`^%"@$``.G&````@+L+0@````^%^````,:#"T(```&`:P8!
+M#[;10;D`````0;@`````N0````!,B>9(B=_H`````.G)````@+L+0@````^%
+MO````,:#"T(```&`:P8!#[;10;D`````0;@`````N0$```!,B>9(B=_H````
+M`.F-````N@`````ZC!JX0@``=0\/MH0:N4(``#I&"7029I!(@<*P````2('Z
+M4!4``'78@&L&`0^VT4F)\40/MD8)N1````!,B>9(B=_H`````.L_#[:%J@``
+M`$B-%(!(C1102,'B!,:$$PM"```!@&L&`0^VT4&Y`````$&X`````+F0````
+M3(GF2(G?Z`````"02(L<)$B+;"0(3(MD)!!(@\08PV9F9I!F9I!F9I!F9I!!
+MB=")\H7V=!1(B?E(B="0Q@$`2(/!`4B#Z`%U\XDW2('J8%<``$BXC^,XCN,X
+MCN-(]^)(P>H*03C000]"T(A7!(32="NZ`````&9FD&9FD`^VPL9$!P?_2(T$
+MP$C!X`?&A`?$5P``_8/"`3A7!'?@QD<&`,9'!0!(B?BZ`````,:`"T(```&(
+MD`I"``"#P@%(!;````"#^B!UY?/#9F:02(GY@'\$``^$F0```+\`````1`^V
+MQTECP$B-!,!(P>`'2#FT`=A9``!U;K@`````0#B\"+A"``!U",:$"+M"```!
+M2`6P````2#U0%0``=>!)8\!(C03`2,'@!TC'A`'860```````$B-E`%@5P``
+MN`````#&!!``2(/``4B#^&1U\DECP$B-!,!(P>`'QH0!Q%<``/V`:04!@\<!
+M0#AY!`^';/___TB)ST&X`````$@Y=R!U,$C'1R``````QD<H`$ECP$AIP%`0
+M``!(C40!(+H`````QD`L`(/"`4B#P""`^H)U\$&#P`%(@<=0$```08/X!'6Y
+M\\-F9F:09F9FD$%505154TB#[`A(B?U(B?=)B=1-B<5!B<A(B>L/MD4%.D4$
+M=03&104`1`^V6P5(B=Y)B=FX`````$&)PHG"28M)($@Y^75+2)A(:<!0$```
+MQD0#*`$/MDL$0;L`````A,ET9$&[`````$@YOMA9``!U#@^VAL17``"#P`,\
+M`79'08/#`4B!QH`$``!!.,MT-^O72(7)=1E(8\)(:<!0$```2`'82(EX(,9`
+M*`'K&6:008/"`8/``4F!P5`0``"#^`0/A7+___]!#[;"2&G`4!```$B-1`,P
+MN0````!F9F:0Q@0!`$B#P0%(@?D"$```=>]%#[;326/"2(E\PQ!!#[;#2(T$
+MP$C!X`=(C80#8%<``&:Y``#&!`$`2(/!`4B#^61U\DECPDB-!,!(P>`'2(V,
+M`]A7``"X`````&9FD&:0Q@0(`$B#P`%(/0`"``!U\$ECPDB-!,!(P>`'2(T,
+M&$B)N=A9``!,B:G05P``QH'$5P``_TC'@<A7````````28L4)$B)E`.\5P``
+M1(B!9E<``$&Y`````$&X`````+G_````1(G22(G^2(GOZ`````"`0P4!2(/$
+M"%M=05Q!7<-(BP=,BP`/MG!#0(3V=$</ME<-N0````#VP@%T#>LWD$B)T$C3
+M^*@!=0B#P0%`./%U[H#Y`W8D2(T$C0`````E_`,``$F-A`#0`0``BP")!0``
+M``#K(KD`````2(T$C0`````E_`,``$F-A`#0`0``BP")!0````#!Z!2#X`'#
+MD$B+!T0/MD!#0;D*````183`=$H/MG\-2(G"0;D*````O@````"Y`````&9F
+MD&9FD$B)^$C3^*@!=!0/MH+R$@``@^`#@\`(03C!1`]'R(/&`8/!`4B#PFA$
+M.,9UTT$/ML'#9F9FD&9F9I!F9I!F9I!(BP=$#[9`0T&Y"````$6$P'1*#[9_
+M#4B)PKX`````0;D(````N0````!F9I!F9I!(B?A(T_BH`704#[:"\A(``(/@
+M`X/`"$$XP40/0LB#Q@&#P0%(@\)H1#C&==-!#[;!PV9F9I!F9F:09F:09F:0
+M#[8'P.@$@^`'#[9W`HG"@,X"0/;&!`]%P@^V3P.)PH'*```"`/;!!`]%PHG"
+M@,X(0/;&"`]%PHG"@<H```@`]L$(#T7"B<*`S@1`]L8"#T7"B<*!R@``!`#V
+MP0(/1<(/ME<4P>(8"=##9F9FD&9FD.@`````\\-F9I!F9I!F9I"+AQ@)```E
+M____`+H`````/5`!DP!U&0^VAQL)``#`Z`0\#`^4P`^VT&9F9I!F9I")T,-F
+M9F:09F:09F:09F:0A?9^0@^V!X3`=`0\('4Q2(GZN0````#K%V9F9I!F9I`/
+MMD(!2(/"`83`=`0\('40@\$!.?%UZ>L-9F9FD&9FD+@`````P[@!````9F:0
+M9I##9F9FD&9F9I!F9F:09F:0#[9'`P^V5P+!X@@)T,'@$`^V3P$/MA?!X@@)
+MT0G(PY!!B="%TG0EN0````!F9F:0#[87#[9'`8@&B%8!2(/&`DB#QP*#P0%$
+M.<%UY//#9I!(@^P(28GP#[=&(+K_````9CV%`'<+#[?`#[:4!V@(```/M])(
+MC1322,'B!4@#EV@)``!(B[<0$0``#[9"4,'@"$B82(V$!DP(``"+"(D-````
+M`('A_P````^V0E#!X`A(F$B-M`9$"```BP:)!0````#!X`@)R(F"$`$``&;'
+M@@P!`````$R)QN@`````2(/$",-F9F:09F:09F:09F:02(/L*$B)7"0(2(EL
+M)!!,B60D&$R);"0@28G]08GT2(LO0(#^`W8Y2HT<Y0````"!X_@'``!(C80=
+M,`(``,<`#````+\0)P``Z`````!(C80=-`(``(LXB3T`````ZS>02HT<Y0``
+M``"!X_@'``!(C80K4`(``,<`#````+\0)P``Z`````!(C9PK5`(``(L[B3T`
+M````00^V]$ACQDB-%$!(C12028V4U<`2```/MDH)@^'\B$H)B?@E```_`#T`
+M`!``=0N)R(/(`HA"">L9D$ACQDB-%$!(C120B<B#R`%!B(35R1(``$B+7"0(
+M2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:09F9FD&9F9I!F9I!!5T%6055!5%53
+M2(/L&$F)_DR+/TF+!\9&20#&1D@%QD9+!DB)?E"Y`````+T`````2(V0``(`
+M`$B)5"002`4$`@``2(E$)`CK%F9FD&9FD$$/MD8-2-/XJ`%U"H/!`9!!.D]#
+M<NJ`^0-V>DB-',T`````@>/X!P``3(ML)!!)`=U!QT4`+````+\0)P``Z```
+M``!(`UPD"$2+(T2))0````!!QT4`)````+\0)P``Z`````"+`XD%`````,'@
+M"$&!Y/\```!!"<1!QT4`(````+\0)P``Z`````"+&XD=`````.MX2(T<S0``
+M``"!X_@'``!,BVPD$$D!W4''10`L````OQ`G``#H`````$@#7"0(1(LC1(DE
+M`````$''10`D````OQ`G``#H`````(L#B04`````P>`(08'D_P```$$)Q$''
+M10`@````OQ`G``#H`````(L;B1T`````08'\`0%IEG4:08!.#`:)V,'H$#Q0
+M#Y3`#[;`ZTAF9I!F9I!!@?P!`0``=0^)V,'H$#Q0#Y3`#[;`ZRJ_B!,``.@`
+M````@\4!0(#]!'<*N0````#IJ_[__XG8P>@0/%`/E,`/ML!(@\086UU!7$%=
+M05Y!7\-F9F:09F9FD&9F9I!F9I!!54%455-(@^P(2(G]08GT2(N'B````$R+
+M*&:#OPP!````=#")\[_H`P``Z`````!%A>1T!8/[`78:3(GO9F:0Z`````!F
+M@[T,`0```'0%@^L"Z])(@\0(6UU!7$%=PY!(@^PX2(E<)`A(B6PD$$R)9"08
+M3(EL)"!,B70D*$R)?"0P28G\B<M!B?9!B=5%B<=(BX>(````2(LH2(GOZ```
+M``!(B<;&0#CAQD`Y`<9`.A*X#P```$6$]G4&00^V1"1'B$8[1(AN/$R)Z@^V
+MQHA&/0^VQXA&/HG8P>@0B$8_B=C!Z!B(1D"(7D%!#[=$)$!FB48@2(EN*,=&
+M-`````!(QT9(`````$6$_TC'P`````!(Q\(`````2`]%PDB)AJ````!(B>_H
+M`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9I!(@^PH
+M2(D<)$B);"0(3(ED)!!,B6PD&$R)="0@28G\B<M!B?9!B=5(BX>(````2(LH
+M2(GOZ`````!(B<;&0#CAQD`Y`<9`.A*X#P```$6$]G4&00^V1"1'B$8[1(AN
+M/$R)Z@^VQHA&/0^VQXA&/HG8P>@0B$8_B=C!Z!B(1D"(7D%!#[=$)$!FB48@
+M2(EN*,=&-`````!(QT9(`````$C'AJ``````````2(GOZ`````!(BQPD2(ML
+M)`A,BV0D$$R+;"083(MT)"!(@\0HPV:04TB)^T&)RD&)T4B%_P^$`0$``$R+
+M!TV%P`^$]0```$$/MGA#A?]^5TB+@X@````/ME`-N0````#VP@%T#>M`D$B)
+MT$C3^*@!=0>#P0$Y^77O@_D#?BY)BP!(!=`!``"-%(T`````2&/22`'0BP")
+M!0````#!Z!2#\`&#X`'K++D`````28L`2`70`0``C12-`````$ACTD@!T(L`
+MB04`````P>@4@_`!@^`!A,!U98"['`$```!U!H![0@!U5@^W0T!!@+P`:`@`
+M`/]T1\9#0B5FQX,,`0```0!!#[?10`^V]D&X`0```$2)T4B)W^@`````O@4`
+M``!(B=_H`````,9#0@!F@[L,`0````^4P`^VP.L%N`````!;PV9FD&:02(/L
+M*$B)7"0(2(EL)!!,B60D&$R);"0@2(G]08GU08G42(N'B````$B+&$B)W^@`
+M````2(G&QD`XX<9`.0'&0#H1N`\```!%A.UU!`^V14>(1CM$B&8\3(GB#[;&
+MB$8]#[=%0&:)1B!(B5XHQT8T`````$C'1D@`````2,>&H`````````!(B=_H
+M`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9I!F9I!F9I!54TB#[`A(
+MB?M(B<U!B=%(A?\/A`8!``!,BP=-A<`/A/H```!!#[9X0X7_?E9(BX.(````
+M#[90#;D`````]L(!=`SK/TB)T$C3^*@!=0>#P0$YSW7O@_D#?BY)BP!(!=`!
+M``"-%(T`````2&/22`'0BP")!0````#!Z!2#\`&#X`'K++D`````28L`2`70
+M`0``C12-`````$ACTD@!T(L`B04`````P>@4@_`!@^`!A,!U:X"['`$```!U
+M!H![0@!U7`^W0T!!@+P`:`@``/]T3<9#0B5FQX,,`0```0!!#[?10`^V]KD!
+M````2(G?Z`````"^!0```$B)W^@`````QD-"`&:#NPP!````=1"+@Q`!``")
+M10"X`0```.L%N`````!(@\0(6UW#9F:09F:02(/L*$B)'"1(B6PD"$R)9"00
+M3(EL)!A,B70D($B)_4&)]4&)U$&)SDB+AX@```!(BQA(B=_H`````$B)QL9`
+M..'&0#D!QD`Z$;@/````183M=00/MD5'B$8[1(AF/$R)X@^VQHA&/0^W14!F
+MB48@2(E>*,=&-`````!(QT9(`````$6$]DC'P`````!(Q\(`````2`]%PDB)
+MAJ````!(B=_H`````$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9F
+MD&9FD&9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)]4&)U$&)S4B+
+M'TB)W^@`````2(G"2(7`=1#&A>D````!QD5*`^F4````QD`XX<9`.0%!@/P!
+M&<#WT(/``HA".D6$[751N`````!(@WU@`'0'#[:%@0```(A".P^W13AFB4(@
+M2(E:*,="-`````!(QT)(`````$C'P`````!(B8*@````2(G62(G?Z`````#K
+M+69FD&:0QD([#P^W13AFB4(@2(E:*,="-`````!(QT)(`````$C'P`````#K
+MOTB+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:09F9FD&9F9I!F9I!!5T%6
+M055!5%532(/L.(GU28G42(L/C13M`````(U"X(G`2(V<""`"``!(B1PD2(V$
+M""0"``!(B40D"(G23(V\"@`"``!,C:P*!`(``+L`````3(UT)!"#_0-V)8V#
+M'`$``$B+%"2)`K\0)P``Z`````!(BU0D"(L"B04`````ZQV-@QP!``!!B0>_
+M$"<``.@`````08M%`(D%`````$*)!#-(@\,$2(/[''6K2(M$)!!)B00D2(M$
+M)!A)B40D"$B+1"0@28E$)!"+1"0H08E$)!A(@\0X6UU!7$%=05Y!7\-F9F:0
+M9F9FD&9F9I!F9I!!5T%6055!5%532(/L.(GU28G42(L/C13M`````(U"X(G`
+M2(V<""`"``!(B1PD2(V$""0"``!(B40D"(G23(V\"@`"``!,C:P*!`(``+L`
+M````3(UT)!"#_0-V)8V#``$``$B+%"2)`K\0)P``Z`````!(BU0D"(L"B04`
+M````ZQV-@P`!``!!B0>_$"<``.@`````08M%`(D%`````$*)!#-(@\,$2(/[
+M''6K2(M$)!!)B00D2(M$)!A)B40D"$B+1"0@28E$)!"+1"0H08E$)!A(@\0X
+M6UU!7$%=05Y!7\-F9F:09F9FD&9F9I!F9I!!5T%6055!5%532(/L.$F)_D"(
+M="0+3(L_1`^V[DECQ4B-%$!(C1202(T4UTB-@L`2``!`B'`(2(FZP!(``,9`
+M"@!$B>[H`````$B-;"002(GH2(GJQ@``2(/``4B)TTR-9"0P3#G@=>P/MD0D
+M"XE$)`R)QDR)]^@`````2(G?Z`````!)8]5(C0Q22(T,BDC!X0-*C10QB8+8
+M$@``2(M##$F)A`[<$@``@'PD"P-V/$*-!*T`````2)A)C80'T`$``(L`B04`
+M````B8+P$@``0HT$[0````!(F$F-A`>``0``BPB)#0````#K1T*-!*T`````
+M2)A)C80'T`$``(L(B0T`````26/%2(T40$B-%)!!B8S6\!(``$*-!.T`````
+M2)A)C80'@`$``(L(B0T`````26/%2(T40$B-%)!)C036B8CT$@``]H#R$@``
+M$`^$.P$``/:`R1(```)T4&:0QD4``$B#Q0%,.>5U\TB-7"002(G:BW0D#$R)
+M]^@`````2(G?Z`````!)8]5(C0Q22(T,BDC!X0-!B80.Y!(``$B+0PQ)B80.
+MZ!(``.L726/%2(T40$B-%)!!QX36Y!(```$``@"`?"0+`W8U0HT<[0````!(
+M8]M*C80[,`(``,<`&````+\0)P``Z`````!*C9P[-`(``(LSB34`````ZS-"
+MC1SM`````$ACVTJ-A#M0`@``QP`8````OQ`G``#H`````$J-G#M4`@``BS.)
+M-0````!)8\5(C11`2(T4D(GQ@>'____?B?`-````($'WA-;P$@`````#`(G*
+M#T70@'PD"P-V%D*-!.T`````2)A)C80'-`(``(D0ZQ1"C03M`````$B828V$
+M!U0"``")$$B#Q#A;74%<05U!7D%?PY!!5D%505154TB)_4F)]DF)]0^W!F:%
+MP'D+)0`?``#!^`B(1TE(C;V$````28U5%$F+111(B86$````2(M""$B)1PB+
+M0A")1Q!,C:7`````28M%+DB)A<````!(C9V8````28U5-DF+139(B868````
+M2(M""$B)0PA(BT(02(E#$$B+0AA(B4,82(M"($B)0R"Z"@```$B)_N@S\/__
+MN@0```!,B>9,B>?H(_#__[H4````2(G>2(G?Z!/P__]FQT5H``!FQT5J``!F
+M08.^L@$```$/E,+!X@,/MD5,@^#W"="(14Q!]H6G````!'0&9L=%:`$`0?:%
+MI`````%T)&:#36@"0?:%J@````%T!6:#36H!0?:%J`````%T!F:!36@``4'V
+MA:0````@=!1F@TUH!$'VA:H````@=`5F@TUJ`D'VA:0```!`=!9F@4UH@`!!
+M]H6J````0'0&9H--:@B0QH6"`````D'VA9D````!=#(/MT5HJ`%T#(/("&:)
+M16AF@TUJ$$$/MH66````@^`?@\`!/""Z'P````]$PHB%@@```$'VA9@````(
+M=`9F@4UH``)!]H68````!'0%9H--:"!!]H68`````G0%9H--:!!!]H6H````
+M('050?:%K@```"!T"V:#36A`9F:09F:0]D5H`70-28N%R````$B)17CK"$&+
+M17A(B45X2(-M>`%!]D5J`G0:00^WA8````"H#W0.9H/X`AG`@\`$B$5LZP3&
+M16P"QD5M_T$/MU5^#[?"J`1T"\9%;0+K&V9FD&:0J`)T!L9%;0'K#/;"`69F
+MD'0$QD5M`,9%;O]!]D5J!'0?N0````!!#[>%L````$C3^*@!=`.(36Z#P0&#
+M^0=UYKX``@``3(GOZ`````")A<P```!!]H:F````('0;00^WAJP```"#X""#
+M^`$9P(/``HB%F`$``.L'QH68`0```+@!````6UU!7$%=05[#9F:02(/L*$B)
+M'"1(B6PD"$R)9"003(EL)!A,B70D($F)_4F)]DR+)[N`____ZPEF9F:0@/N%
+M=T,/ML-!#[:L!&@(``!`@/W_=#%`#[;%2&G`R`\``$B)QTD#O"20"0``3#EO
+M"'45N@@```!,B?;H`````(3`=`2)Z.L/@\,!@/N!9I!VKKC_____#[;`2(L<
+M)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9I!F9I!F9I!!5T%6055!5%53
+M2(/L.$F)_DB+!X!_0P`/A!$#``#'1"0T`````$B-D``"``!(B50D"$@%!`(`
+M`$B)!"1F9F:0#[9,)#2(3"0S1`^V^4ECQTB-%$!(C12028TTUO:&\A(``!`/
+MA*\"``!(C9;`$@``N`$```!$B?E(T^`(0@I(B[;0$@``2(ET)"CV0@D"#X0>
+M`0``#[9$)#.-:`%!.&Y##X8,`0``26/'2(T40$B-%)!(P>(#2(E4)"!,`?)(
+MB50D&$B+5"0@28V4%N@2``!(B50D$$0/MNU)8\5(C11`2(T4D$B-'-4`````
+M3HTD,T'VA"3R$@``$`^$IP```$B+3"08]X'D$@`````.``^$D@```$F-M![H
+M$@``N@@```!(BWPD$.@`````A,!T=TF-M![<$@``2(M$)"!)C;P&W!(``+H(
+M````Z`````"$P'14N`$```!$B>E(T^!(BU0D&$B!PL`2```*0@J(0@I!B(0D
+MRA(``$B#?"0H`'4/38ND)-`2``!,B60D*.L826/%2(T40$B-%)!(BT0D*$F)
+MA-;0$@``@\4!03AN0P^'(O___TB#?"0H``^%Q````$R)]^@`````2(E$)"A(
+MA<`/A%L!``!)8\=(C0Q`2(T,B$F-#,Y(BU0D*$B)D=`2```/MD0D,TB-%$!(
+MC12028V4UL`2``!(BT0D*$B)4"`/MH')$@``2(M4)"B(0@K&0@D`3(DRQD(.
+M`,9"6`#&0B@`#[9,)#.-<0%!.'9#=EU)8\=(C11`2(T4D$F-O-;`$@``0`^V
+MS@^V1PI(T_BH`7082&/!2(T40$B-%)!(BT0D*$F)A-;0$@``@\8!03AV0W8:
+MZ\Y)8\=(C11`2(T4D$B+3"0H28F,UM`2``!)8\=(C11`2(T4D$F-E-;`$@``
+M#[9""DB+3"0HB$$-#[9J"H!\)#,#=BM"C1S]`````$ACVTB+1"0(2`'8QP`X
+M````OQ`G``#H`````$@#'"2)*^LI0HT<_0````!(8]M(BT0D"$@!V,<`.```
+M`+\0)P``Z`````!(`QPDB2N#1"0T`0^V1"0S@\`!03A&0P^'$?W__TB#Q#A;
+M74%<05U!7D%?PV:005=!5D%505154TB#[&A(B?U,BR?&1"104,9$)%$%QD0D
+M4@3&1"13,,9$)%01QD0D5:O&1"16`,9$)%<`0<>$)`!``0`3(```2(L'QX`$
+M0`$`__\``$B+!\>`!$`!``````!(.[_X"```#X74````2(V?D!0``$B-EQ@)
+M``!!N`$```"Y"````+X```(`Z`````"+A1`)```/MI4;"0``@^H$C02"B(4;
+M"0``2(GOZ`````"$P'4,2(M$)%!(B848"0``BP4``````(4;"0``@\`!B04`
+M````#[:%&`D``(B#&`D```^VA1D)``"(@QD)```/MH4:"0``B(,:"0``#[:%
+M&PD``(/``HB#&PD```^VA1P)``"(@QP)```/MH4="0``B(,="0``#[:%'@D`
+M`(B#'@D```^VA1\)``"(@Q\)``!-B>=)C80D``$``$B)1"1`08N$)``!``")
+M!0`````/M]")5"1<J"!T"R7?_P``B40D7.L8B="#R"")1"1<2(M4)$")`HL"
+MB04`````2(M%`,>`!`$```````!(BT4`QX`8`0```````$B+10#'@!P!````
+M````OY#0`P#H`````$''AW`!```8`0``08N'=`$``(D%`````(#D_8#,!(E$
+M)%Q!QX=P`0``&`$``(M$)%Q!B8=T`0``0<>'<`$``"@!``!!QX=T`0``?W\`
+M`$''AW`!```D`0``08N'=`$``(D%`````&:X```-_S\``(E$)%Q!QX=P`0``
+M)`$``(M$)%Q!B8=T`0``0<>'<`$``#P!``!!QX=T`0````!Z`$''AW`!``"D
+M`0``0<>'=`$``'V_[_]!QX=P`0``N`$``$&+AW0!``")!0`````E__\```T`
+M`/H`B40D7$''AW`!``"X`0``BT0D7$&)AW0!``!!QX><````_P```$''AY`"
+M``!$`0``0<>'E`(```80``A!QX>0`@``M`$``$''AY0"``!?<```0<>'D`(`
+M`#````!!BX>4`@``B04`````,.2`S#.)1"1<08F'E`(``(!]0P`/A)4"``#'
+M1"1(`````$F-AU`"``!(B40D.$F-EU0"``!(B50D,$B-A1@)``!(B40D*$F-
+MEX`!``!(B50D($F-AX0!``!(B40D&$F-ES`"``!(B50D$$F-AS0"``!(B40D
+M"&9F9I!F9I`/ME0D2(A4)$^`^@,/AOX```!$#[;R0HT<]0````!(8]M,BVPD
+M$$D!W4''10`(````OQ`G``#H`````$B+1"0(3(TD`T&+!"2)!0````")1"1<
+M#0``@`!!B00D2(M4)"A$B?9(B>_H`````$2)]DB)[^@`````0<=%`$0!``"_
+M$"<``.@`````0<<$)`80``A!QT4`M`$``+\0)P``Z`````!!QP0D7W```$''
+M10`(````OQ`G``#H`````,=$)%S_5(``0<<$)/]4``"Z`0```$2)]DB)[^@`
+M````2(M$)"!(C10#BP*)!0`````E___^_XD"QT0D7`4!R`!(`UPD&,<#!0'(
+M`.G[````9F9FD$0/MG0D3T*-'/4`````2&/;3(ML)#A)`=U!QT4`"````+\0
+M)P``Z`````!(BU0D,$R-)!-!BP0DB04`````B40D7`T``(``08D$)$B+5"0H
+M1(GV2(GOZ`````!$B?9(B>_H`````$''10!$`0``OQ`G``#H`````$''!"0&
+M$``(0<=%`+0!``"_$"<``.@`````0<<$)%]P``!!QT4`"````+\0)P``Z```
+M``#'1"1<_U2``$''!"3_5```N@$```!$B?9(B>_H`````$B+1"0@2(T4`XL"
+MB04`````)?___O^)`L=$)%P%`<@`2`-<)!C'`P4!R`"_H(8!`.@`````1(GV
+M2(GOZ`````"#1"1(`0^V1"1/@\`!.$5##X?._?__2(GOZ`````!!BX<$`0``
+MB04`````@\@"B40D7$&)AP0!``!(BU0D0(L"B04`````)?#___T-#0```HE$
+M)%R)`HL"B04`````2(N%Z!```$&)AP@!``"+A>P0``!!B8<,`0``2(N%&!$`
+M`$&)AQ`!``"+A1P1``!!B8<4`0``0<>'(`$````````/MX6\$@``)?\/```-
+M```!`$&)AR`!``!(BX5X$0``08F')`$``(N%?!$``$&)AR@!``!(BX6@$0``
+MQP#_#P``0<>'-`$````````/MX6^$@``)?\/```-```!`$&)AS0!``!(BX6H
+M$0``08F'.`$``(N%K!$``$&)ASP!``!!QX=(`0```````,=$)%P``0``0<>'
+M3`$````!``!!BX<$`0``B04`````@\A908F'!`$``,=$)%S[_P`,0<>'5`$`
+M`/O_``Q!QX=<`0``__\``+H`````2&/"QX2%P`D```````#'1(5T`````(/"
+M`8/Z$'7B9L>%N!(``/\/9L>%NA(``/\/QD5,`;@!````2(/$:%M=05Q!74%>
+M05_#9F9FD&9FD$%7059!54%455-(@^P(28G^28GT3(LO3(GOZ`````!(B<-(
+MA<!U#D'&A"3I`````>FQ````3(GOZ`````!(B<5(A<!U&4'&A"3I`````4B)
+MWDR)[^@`````Z8@```!,C7M8QD,XX<9#.0'&0SH#00^W1"0X9HE#(,:#F```
+M``])BP9(B4,HQT,T``(``$B+51!(B5-(N`````!F9I!F9I#&!!``2(/``4@]
+M``(``'7P2(EK>$C'@Z``````````O@````!,B?_H`````(M3-$B+=1A,B?_H
+M`````$B)WDR)[^@`````2(/$"%M=05Q!74%>05_#9F9FD&9F9I!F9I!!5D%5
+M05154TB#[#!)B?U,BR</MD<-A,`/A,(#```/MO"]`````$#VQ@%U%;H`````
+M@\(!#[;JB?")Z=/XJ`%T\$ACQ4B-%$!(C12028V4U.`2``"+0@2I```"`'0-
+M#0``!``E___]_XE"!$ACQ4B-%$!(C12008N$U.02``"I```$``^$H0(``$F+
+MG"3X"```28V$))`4``!,.>-(#T3828TTU$0/MH[J$@``1`^VAND2```/MH[H
+M$@``00^V5"1!#[:&[Q(``(E$)"`/MH;N$@``B40D&`^VANT2``")1"00#[:&
+M[!(``(E$)`@/MH;K$@``B00DB>Y(Q\<`````N`````#H`````$&X`````$AC
+MQ4B-%$!(C12038V,U.@2``!!#[:$&.@(```\_P^$A`````^VP$AIP,@/``!)
+MB<),`Y.0"0``3(G63(G/N0@```#\\Z8/E\(/DL`XPG5810^V2@1%#[9"`T$/
+MMDH"00^V4@%!#[8R00^V0@>)1"0000^V0@:)1"0(00^V0@6)!"1(Q\<`````
+MN`````#H`````$'&10G_3(GN3(GGZ`````#I*`(``$F#P`%)@_@"#X5=____
+M3(GGZ`````!(B<-(A<`/A`8"``!(8\5(C11`2(T4D$'VA-3E$@``!'0$@$M=
+M`DACQ4B-%$!(C1200?:$U.82```$=`2`2UT02&/%2(T40$B-%)!!]H34Y1(`
+M``AT!(!+701(8\5(C11`2(T4D$'VA-3F$@``"'0$@$M=($ACQ4B-%$!(C120
+M0?:$U.42```"=`2`2UT!2&/%2(T40$B-%)!!]H34YA(```)T!(!+70C&0U@`
+M28G>2&/%2(T40$B-%)!)BX34Z!(``$B)`TR):PA,B>_H`````(B#NP```$&`
+M12@!08!\)$,`=#*Y`````+H`````9F9FD$$/MD4-2-/XJ`%T#@^VPHA,`W"`
+M0UH!@\(!@\$!03A,)$-WW$F+35!(C5,X28E54$F-14A(B4,X2(E+0$B)$4&`
+M15@!#[:+NP```$F+O"2X$```2<?``````$R)\DR)[N@`````Z;8```"I```(
+M``^$JP```$R)Y^@`````2(G#2(7`#X27````QD!+!L9`2@5FQX#(``````#&
+M0$@&QD!)`$C'0'@```4`2&/%2(T40$B-%)!)BX34Z!(``$B)@]0```!(B8/,
+M````3(EK4$R)[^@`````B(/J````9H-+:!!,B>_H`````#P)=@9F@4MH``)!
+MQD4.`4F+56A)B5UH28U%8$B)`TB)4PA(B1I(B=Y,B>?H`````&9FD&9FD$B#
+MQ#!;74%<05U!7L-F9I!!5T%6055!5%532(/L*$B)_4B)\TB%]G05#[9&"83`
+M=`T\_P^%[0<``.E'`0``N0`````/MH0I[@@``#S_=!,/ML!(C12`2(T4D$B-
+MG-7(`0``2(/!`4B#^01UUT&\`````$$/MH0L[@@``#S_=#@/ML!(C12`2(T4
+MD$C!X@-(C9P5R`$``/:$%=(!```"=`^^`````$B)W^@`````ZPA(B=_H````
+M`$F#Q`%)@_P$D'6P#[9%/F8YA9`0```/A5,'``!(A=L/A90```"`?4T`#X5`
+M!P``QD5-`69FD&9FD$B+M-UH!```2(7V=&-(BX:`````2(7`="=(QX:`````
+M`````$C'A-UH!````````$B+OI````"Z_______0ZS!(BX:(````2(7`="1(
+MQX:(`````````$C'A-UH!````````$B+OI````#_T&9F9I!(@\,!2(/[0`^$
+MN`8``.N`QD,)_TB)WDB)[^@`````D.FA!@``N0````!F9I!F9I`/MH0I[@@`
+M`#S_#X0%`0``#[;02(T$DDB-!()(P>`#3(V\!<@!``!(C80%P`$``(!X$?\/
+MA-P```"`>!8`#X13!@``0;P`````2(T$DDB-!()(P>`#3(VL!2@"``!(C1PH
+M3(VSP`$``$R)[^@`````2(G!2(N#,`(``$B)BS`"``!,B2E(B4$(2(D(@'E*
+M_W1O@+GI``````^$^`4```^V04A(B<*#X@9(@_H&=1RH`70Z#[:1@0```$B+
+M<5A,B?_H`````.G,!0``2(/Z!`^%P@4``*@!#X2Z!0``2(G.2(GOZ`````#I
+MJ@4``$B)SDB)[^@`````Z9H%``!F9F:008/$`44X9A8/AH@%``!FD.E3____
+M2(/!`4B#^01F9I`/A=K^__](QT0D$`````"`?4T`#X6E````NP````!FD$B+
+MM-UH!```#[:$*V@(``!(A?9T<DB+CH````!(A<ET9DB#?F``=5\\_W0V#[;X
+M#[?'2(T40$B-%)!(P>(%2(G02`.%0`D``/9`2P1T%(!X20!U#@^WUTB)[^@`
+M````D.LE2,>$W6@$````````2,>&@`````````!(B[Z0````NO______T4B#
+MPP%(@_M`#X5K____QD5-`>FX!```2(M4)!`/MH0J[@@``#S_#X21!```#[;0
+M2(T$DDB-!()(P>`#2(V,!<@!``!(B4PD(("\!=8!````#X1G!```QD0D'P!(
+MC0222(T$@DC!X`-(C90%*`(``$B)%"1,C30H38V^P`$``$B+/"3H`````$B)
+MPTF+AC`"``!)B9XP`@``2(L,)$B)"TB)0PA(B1B`>TK_#X7Y`P``1`^W:SA)
+M8\4/MI0%:`@``&:)5"0.3(NDQ6@$``#V0TP$='9-A>1T<4F#O"2``````'1F
+M28-\)&``=5Z`8TS[]D-+!'02#[=4)`Y,B>9(B>_H`````.M"28N$)(````!)
+M8]5(QX35:`0```````!)QX0D@`````````!(QT-``````$F+O"20````NO__
+M__],B>;_T&9FD&:0]D-+!`^$4P$``,:#Z`````!!@&<4Y_9#3`$/A.@```"`
+M8TS^2(M30$B%TG1%@'M)`'4I]D-+!'0C#[950<'B!D0!ZDACTDB+M?@(``"_
+M!P```.@`````Z=D```!(B[7X"```OP$```#H`````.G#````387D=&5)BXPD
+M@````$B%R718@'M)`'4;]D-+!'05#[=4)`Y,B>9(B>_H`````.F0````26/%
+M2,>$Q6@$````````2<>$)(``````````2,=#0`````!)B[PDD````+K_____
+M3(GF_]'K68![20!U4_9#2P1T30^V54'!X@9$`>I(8])(B[7X"```OP(```#H
+M`````.LM2(M#0$B%P'0D2(N0B````$B%TG082,>`B`````````!(BT-`2(NX
+MD````/_2]D-,`@^$(0(``$B+4T!(B[7X"```OP8```#H`````(!C3/WIX0$`
+M`$B+0T!(A<`/A-0!``!(@[B(``````^$Q@$``,9#2P'&0TH`2(G:O@8```!(
+MBWPD(.@`````2(-[6`!T%TB+4Q!(BT,82(E""$B)$$B+0UB`:%@!@+N#````
+M`'0B9F9FD&9FD$B)[^@`````OP$```#H`````("[@P````!UY4B+NR`!``!(
+MA?]T$0^VLPT!``"Z`0```.@`````2(M[6$B%_W01#[:S@0```+H!````Z```
+M``!,BV-`387D#X3H````]D-,!'5-2(GOZ`````!(BW-`N@$```!(B>_H````
+M`$B+0T`/ME`"#[9P`4C'QP````"X`````.@`````2(M30$B+M?@(``"_`0``
+M`.@`````ZS)!#[94)`)!#[9T)`%(Q\<`````N`````#H`````$B+4T!(B[7X
+M"```OP$```#H`````$F+E"2(````2(72="8/MT,X2,>$Q6@$````````2<>$
+M)(@`````````28N\))````#_TO9#3`)T&4B+4T!(B[7X"```OP8```#H````
+M`(!C3/U(QT-``````$G'1"1@`````$B+4V!(A=)T$`^V@X$```!(QT3"6```
+M``!(BQ-(BT,(2(E""$B)$$&`;Q8!2(G>2(GOZ`````#V0TP"=!Q(BU-`2(NU
+M^`@``+\&````Z`````"`8TS]9F:0@$0D'P$/MDPD'T$X3Q8/A\'[__](@T0D
+M$`%(@WPD$`0/A4C[__^X`0```$B#Q"A;74%<05U!7D%?PV9FD&9FD%532(/L
+M"$B)^TB++^@`````A,!T&0^V=4-`A/9T-`^V4PVY`````/;"`70>ZR3&0PG_
+M2(G>2(GOZ`````#K8I!(B=!(T_BH`74(@\$!0#CQ=>Y(B>_H`````$B)QDB%
+MP'0_2(M3:$B)0VA(C4-@2(D&2(E6"$B),H!##@%(B5Y0QD9(!<9&20#&AH$`
+M```/N0$```"Z`0```$B)W^@`````2(/$"%M=PV9F9I!F9F:02(/L*$B)'"1(
+MB6PD"$R)9"003(EL)!A,B70D($F)_$B)]4B+GH@````/MD9"/"0/AQ(&```/
+MML#_),4`````#[=&3@^WT/;"!'0,9L=&3@$`QD9"`>M#9H/X('4,9L=&3@@`
+MQD9"$>LQA-)Y%?9&20-T#R1_@\@(9HE&3L9&0@WK&/;""'0&QD5"!^L-]L8"
+M=`C&14<`QD5"'DB)[DR)Y^@`````Z9T%``"Y`0```+H"````O@$```!(B>_H
+M`````.F!!0``N0$```"Z`````+X!````2(GOZ`````#I904``+D!````N@$`
+M``"^`0```$B)[^@`````Z4D%``"Y`0```+I@````O@$```!(B>_H`````.DM
+M!0``#[9.2$&X`0```+I@````O@$```!(B>_H`````.D,!0``0;@!````N0``
+M`02Z(0```+X!````2(GOZ`````#IZ@0``$B+0R"!8#3___?_0;@!````N0$`
+M``"Z`@```+X`````2(GOZ`````#IO00``$&X`0```+D`````N@(```"^````
+M`$B)[^@`````OQ`G``#H`````.F1!```2(M#((%@-/__]_]!N`$```"Y`0``
+M`+H"````O@````!(B>_H`````.ED!```0;@!````N0````"Z`@```+X`````
+M2(GOZ`````"_$"<``.@`````Z3@$``"Y`0```+H"````O@````!(B>_H````
+M`.D<!```N0$```"Z`````+X`````2(GOZ`````#I``0``+D!````N@$```"^
+M`````$B)[^@`````Z>0#``!!N`$```"Y_____[H!````O@````!(B>_H````
+M`.G"`P``N0$```"Z`````+X`````2(GOZ`````#II@,```^V1D=,BVS&6$F)
+M75!)B75@#[9&1T&(A8$```!!QD5*`T'&14D`08!-2`6`0PX!2(M3:$B-0V!,
+MB6MH28E%`$F)50A,B2J_@!H&`.@`````08!\)$,`=":]`````/9##0%T#^L9
+M#[9##8GI2-/XJ`%U$8/%`4$X;"1#=^GK!;T`````2(M3((M"-*D```@`=`HE
+M___W_XE"-.MI2(T$[0````!)B<9!@>;X!P``N[@+``!`@/T#=AU)BP0D2`6`
+M`0``3`'PBP")!0````#!Z!.#X`'K'$F+!"1(!8`!``!)C00&BP")!0````#!
+MZ!.#X`&$P'4/O^@#``#H`````(/K`76N9D''A<@``````$R)[DR)Y^@`````
+MZ8@"``"_0`T#`.@`````N0````"Z(````+X!````2(GOZ`````"_$"<``.@`
+M````Z5@"``"Y`````+H!````O@````!(B>_H`````+\0)P``Z`````#I,@(`
+M`$B+0R"!8#3___?_0;@`````N?____^Z`0```+X`````2(GOZ`````"_$"<`
+M`.@`````Z?L!``"Y`````+H`````O@````!(B>_H`````+\0)P``Z`````#I
+MU0$``.@`````Z<L!``!F9F:0Z`````#IO0$``$&X`0```+GP````NIL```"^
+M`0```$B)[^@`````Z9L!``!!N`$```"YH-9:*[K@`P``O@$```!(B>_H````
+M`.EY`0``0;@!````N0#@`P"ZI`,``+X!````2(GOZ`````#I5P$``$&X`0``
+M`+GDJ`8!NL0#``"^`0```$B)[^@`````Z34!``"Y`0```+I(`P``O@$```!(
+MB>_H`````.D9`0``OT`-`P#H`````+D!````NB````"^`0```$B)[^@`````
+MOQ`G``#H`````.GI````0;@!````N0````"Z(0```+X!````2(GOZ`````#I
+MQP```+D!````NF````"^`0```$B)[^@`````Z:L````/MDY(0;@!````NF``
+M``"^`0```$B)[^@`````Z8H```#&0PD`2(N^B````.@`````ZWBY`0```+H!
+M````O@````!(B>_H`````+\0)P``Z`````#K54B+0R"!8#3___?_0;@!````
+MN?____^Z`0```+X`````2(GOZ`````"_$"<``.@`````ZR&Y`0```+H!````
+MO@````!(B>_H`````+\0)P``Z`````"X`0```$B+'"1(BVPD"$R+9"003(ML
+M)!A,BW0D($B#Q"C#9F9FD&9FD$B#[!A(B1PD2(EL)`A,B60D$$B)^TB)]0^W
+M5B!F@?J%``^'C@````^WP@^VA`=H"```//]T?V:#^G]W)`^VP$B-%$!(C120
+M2,'B!4@#ET`)``!(BT)0#[90".M>9F9FD`^W1B!F/8$`=R,/M\`/MH0':`@`
+M`$AIP,@/``!(`X>0"0``2(M`"`^V4`CK+0^W1B`/MH0':`@``$B-!,!(P>`%
+M2`.':`D``$B+@(@````/ME`(ZP6Z_____[G_____9H%]((4`=PP/MT4@#[:,
+M`V@(``!(B[-H"0``#[;"@/K_=!Y(F("\`^X(``#_=!*`^?]T#8!])`9U*F9F
+M9I!F9I!(@WUX`'0,2(UU>$B)W^@`````2(GN2(G?Z`````#I#0$```^VP4B-
+M!,!(P>`%3(TD!D$/MD0D0CP:#X2%````/!IW#CP1#X6[````9F9FD.L3/!MT
+M=SP<#X6I````9I#IG````$B+DQ`1``!(@<),"```00^V1"10P>`(2)A(`<*+
+M"HD-``````^VR4B+DQ`1``!(@<)$"```00^V1"10P>`(2)A(`<*+`HD%````
+M`,'@"`G!08F,)`0!``!!QD0D0AKK0D'&1"1"&^LZ2(N#$!$``$@%3`@``$$/
+MME0D4,'B"$ACTD@!T(L`B04`````@^#W08A$)$A!QD0D0ASK!D'&1"1"'4B#
+M?7@`=`Q(C75X2(G?Z`````!(B>Y(B=_H`````$R)YDB)W^@`````2(L<)$B+
+M;"0(3(MD)!!(@\08PV9F9I!F9I!F9I!F9I!(@^P(2(G^2(L_Z`````!(@\0(
+MPV9F9I!F9F:09F9FD$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\
+M)#!)B?](B?-(BVY0#[=V.$ACQKH`````@+P':`@``/\/A#H)```/MD-*/`D/
+MA$X%```\"7=*/`4/A)<````\!7<>/`,/A*T````\!&9F9I`/A>P(``#IT0``
+M`&9FD&:0/`</A*@$```\!V9FD&9FD`^'(P0``.F!`@``9F:09I`\%@^$A0,`
+M`#P69F:09F:0=R,\%`^$T04``#P49F9FD`^'X@(``#P*#X64"```9I#I.P4`
+M`#P:#X0?`@``//^0#X2I!0``/!</A70(``!FD.E-`P``#[9W0T"$]F9F9I`/
+MA(<````/ME4-0;P`````]L(!=&WK=DB+12"!8#3___[_2(M[4+D`````N@$`
+M``!(B=[H`````+\%````Z`````"Z`0```.DT"```N0````"Z`````$B)WDB)
+M[^@`````OU##``#H`````+H!````Z0L(``!(B=!$B>%(T_BH`74108/$`4$X
+M]'7JZP9!O``````/ME-(2(G0@^`&2(/X!G4)]L(!#X7&````2(M5((M"-*D`
+M``$`=`TE___^_XE"-.FK````2HT$Y0````!)B<9!@>;X!P``0;T0)P``D$F+
+M%T&`_`-V%TF-A!:``0``BP")!0`````E```!`.L528V$%H`!``"+`(D%````
+M`"4```$`A<!T+$&`_`-V$TF-A!:``0``QP````$`Z3<'``!)C806@`$``,<`
+M```!`.DD!P``O^@#``#H`````$&#[0%UB\9#2P+&0TK_2(G>3(G_Z`````"Z
+M`0```.D.!P``]D4*`70T2(G>2(GOZ`````"$P'4E0;WZ````2(G>2(GOZ```
+M``"$P'40O^@#``#H`````$&#[0%UX4&`_`-V)DF+!T@%@`$``$J-%.4`````
+M@>+X!P``2`'0BQ")%0````")$.LD28L'2`6``0``2HT4Y0````"!XO@'``!(
+M`="+$(D5`````(D02(M[4$B)WNA(YO__OR!.``#H`````+H!````Z60&``!(
+MQ\<`````N`````#H`````$B+:U!,BV4`3(GGZ`````!(B<%(A<!U$<:#Z0``
+M``&Z`0```.DJ!@``QD`XX<9`.0'&0#H7#[=#.&:)02#&@9@````/2(M%`$B)
+M02C'030`````2,=!2`````!(QX&@`````````$B)SDR)Y^@`````N@$```#I
+MV`4``$C'QP````"X`````.@`````2(MK4$R+90!,B>?H`````$B)P4B%P'41
+MQH/I`````;H!````Z9X%``#&0#CAQD`Y`<9`.A@/MT,X9HE!($B+10!(B4$H
+MQT$T`````$C'04@`````2,>!H`````````!(B<Y,B>?H`````+H!````Z5,%
+M``!(B=Y(B>_H&.7__[H!````Z3X%``!,BV4`3(GGZ`````!(B<(/MDML2(7`
+M=0[&@^D````!L@'I&`4``,9`..'&0#D!QD`Z!8A(.P^W0SAFB4(@2(M%`$B)
+M0BC'0C0`````2,="2`````!(QX*@`````````(A+;TB)UDR)Y^@`````N@$`
+M``#IQP0``$R+90!,B>?H`````$B)P@^V2VY(A<!U#L:#Z0````&R`>FA!```
+MQD`XX<9`.0'&0#H$B$@[#[=#.&:)0B!(BT4`2(E"*,="-`````!(QT)(````
+M`$C'@J``````````B$MQ2(G63(GGZ`````"Z`0```.E0!```3(ME`$R)Y^@`
+M````2(G!2(7`=1'&@^D````!N@$```#I*P0``,9`..'&0#D!QD`Z!@^W0SAF
+MB4$@2(M%`$B)02C'030`````2,=!2`````!(QX&@`````````$B)SDR)Y^@`
+M````N@$```#IX`,``$R+90!,B>?H`````$B)P4B%P'41QH/I`````;H!````
+MZ;L#``#&0#CAQD`Y`<9`.@P/MT,X9HE!($B+10!(B4$HQT$T`````$C'04@`
+M````2,>!H`````````!(B<Y,B>?H`````+H!````Z7`#``!,BV4`3(GGZ```
+M``!(B<%(A<!U$<:#Z0````&Z`0```.E+`P``QD`XX<9`.0'&0#H6QD`\`0^W
+M0SAFB4$@QH&8````#TB+10!(B4$HQT$T`````$C'04@`````2,>!H```````
+M``!(B<Y,B>?H`````+H!````Z?4"``#&0TK_9L>#R```````#[932$B)T(/@
+M!DB#^`9U!?;"`7452(-[8`!U#DB)[^@`````B(/J````@'M+`G4/2(MS4$B)
+MVDR)_^@`````]D4,`G48NP````!,C65@@'T.``^%0`$``.E7`@``2(MU0`^V
+M3D8/MM$/MD8[@^@!.<)]+HU!`8A&1H!&1P'&1D(`#[=&3H/@_H/("&:)1DY,
+MB?_H`````+H!````Z4<"```YPG04NP````!,C65@@'T.`'4IZ1$"``#&1D(`
+M#[=&3H/@]H#,`F:)1DY,B?_H`````+H!````Z0L"``!,B>?H`````$B)P4B+
+M16A(B4UH3(DA2(E!"$B)"(!Y2O]T?("YZ0`````/A+T!```/ME%(2(G0@^`&
+M2(/X!G4B]L(!=$4/MI&!````2(MQ6$B)[^@`````N@$```#IJ0$``$B#^`0/
+MA8$!``#VP@$/A'@!``!(B<Y,B?_H`````+H!````Z8$!``!(B<Y,B?_H````
+M`+H!````Z6P!``#&@>D`````@\,!.%T.#X8[`0``Z4G___]F9F:03(GGZ```
+M``!(B<%(BT5H2(E-:$R)(4B)00A(B0B`>4K_#X20````@'E)``^%?P```("Y
+MZ0`````/A/0````/ME%(2(G0@^`&2(/X!G4B]L(!=$@/MI&!````2(MQ6$B)
+M[^@`````N@$```#IX````$B#^`0/A;@```#VP@%F9I`/A*P```!(B<Y,B?_H
+M`````+H!````Z;4```!(B<Y,B?_H`````+H!````Z:````#&@>D`````@\,!
+M#[9%#CC8#X<Z____.,-U4H3`=$Z[`````$R-96!,B>?H`````$B)PDB+16A(
+MB55H3(DB2(E""$B)$`^V0DD\(G0$/`UU%+X*````2(G7Z`````"Z`0```.L\
+M@\,!.%T.=[O&10G_2(GN3(G_Z`````"Z`0```.L>N@$```#K%T6%[69F9I`/
+MA-_X___I]_C__V9FD&:0B=!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\
+M)#!(@\0XPV9F9I!F9F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@2(G[
+M28GT#[=.(&:!^84`#X?H````#[?!#[:T!V@(``!`@/[_#X33````9H/Y?W<H
+M0`^VUDB+CT`)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK269FD&9FD&:!^8$`
+M=QU`#[;&2(N7D`D``$AIP,@/``!(BT00"`^V0`CK'T`/ML9(BY=H"0``2(T$
+MP$C!X`5(BX00B`````^V0`@\_W1>#[;`#[:L`^X(``!`@/W_=!A`@/[_=!)!
+M#[9,)"2`^09U9V9F9I!F9I!`@/W_="]`@/[_="E`#[;&2(T40$B-%)!(P>(%
+M28G53`.K0`D``$'&14L"0<9%2O_IGP(``$F#?"1X`'0-28UT)'A(B=_H````
+M`$R)YDB)W^@`````Z:4"``!F9I!F9I!`#[;&2(T40$B-%)!(P>(%28G53`.K
+M0`D``$F+5"1(A,D/A+D```!!#[9$)#H\!@^$T````#P,#X3(````00^WE<@`
+M``"-0@%F08F%R````&:#^@EV&T&`?4H&=!1!QD5+`D'&14K_08!E3/[I`P(`
+M`+_H`P``Z`````!!#[952$B)T(/@!DB#^`9U.O;"`70U00^VE8$```!)BW58
+M0`^VQ4B-/(!(C3RX2(V\^\@!``!!N`````"Y`@```.@`````Z=D!``!!QD5*
+M`TR)[DB)W^@`````Z<0!``!F9I!FD$$/MD0D.CP!=0M!QD5*!)#I?P$``#P"
+M=0Q!QD5*!6:0Z6\!```\`P^%SP```$B)UD&`?4H%=2MF@7H$R#=F9I!U($$/
+MMW4X2,?'`````+@`````Z`````!!QD5*!NDR`0``3(GOZ`````!)C;V8````
+MOB@```#H);___X3`=4%)C;V$````OA0```#H$+___X3`=2Q)C;W`````O@@`
+M``#H^[[__X3`=1=)@WUX`'000<9%2A?IV@```&9FD&9FD&9!@[W(````'784
+M0<9%2P)!QD5*_T&`94S^Z;4```"_Z`,``.@`````0<9%2AIF08.%R`````'I
+MF````#P7=0I!QD5*%>F*````/!AF9F:0=0=!QD5*%NM[/`1F9I!FD'4'0<9%
+M2@?K:SP%9F:09I!U!T'&14H(ZUL\!F9FD&:0=0=!QD5*">M+/`QF9I!FD'4'
+M0<9%2@KK.SP69F:09I!U!T'&14H4ZRL\#F9FD&:0=2))@WPD>`!T#4F-="1X
+M2(G?Z`````!,B>9(B=_H`````.LK28-\)'@`=`U)C70D>$B)W^@`````3(GF
+M2(G?Z`````!,B>Y(B=_H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F
+M9F:09F9FD$B#["A(B1PD2(EL)`A,B60D$$R);"083(ET)"!)B?Y)B?1(BVY0
+M#[=&.+H`````@+P':`@``/\/A,L"```/MD9*/!0/A,<````\%'<X/`V0#X3[
+M````/`UW#CP%9F9FD`^%G0(``.M-/`YF9I!F9I`/A.\````\#P^%A0(``&:0
+MZ?(````\&P^$E0```#P;D'<0/!AT.3P9#X5E`@``9I#K1#P<=%<\_P^%50(`
+M`&:0Z<8```"^`````$R)YV9FD.@`````N@$```#I.0(``+X!````3(GGZ```
+M``"Z`0```.DB`@``O@$```!,B>?H`````+H!````Z0L"``!(B??H`````+H!
+M````Z?D!``"02(GWZ`````"Z`0```.GF`0``]D9I!'072(GW9F:09I#H````
+M`+H!````Z<D!``!(B??H`````+H!````Z;<!``!(B??H`````+H!````9I#I
+MHP$``$B)]^@`````N@$```#ID0$``,9&2O^`?0X`#X39````NP````!,C6U@
+M9I!,B>_H`````$B)P4B+16A(B4UH3(DI2(E!"$B)"(!Y2O\/A(D```"`>4D`
+M#X6&````@+GI``````^$-0$```^V44A(B="#X`9(@_@&=2+VP@%T2`^VD8$`
+M``!(BW%82(GOZ`````"Z`0```.D(`0``2(/X!`^%^0```/;"`69FD`^$[0``
+M`$B)SDR)]^@`````N@$```#IW0```$B)SDR)]^@`````N@$```#IR````,:!
+MZ0````"#PP$/MD4..-@/ASK___\XPP^%CP```$$/MD0D23PB=!8\#7020;P`
+M````3(UM8(!]#@!U%NMOO@H```!,B>?H`````+H!````ZW9,B>_H`````$B)
+MPTB+16A(B5UH3(DK2(E#"$B)&`^V0TD\(G0$/`UU*$B)WDC'QP````"X````
+M`.@`````O@H```!(B=_H`````+H!````ZR5!@\0!1#AE#G>EQD4)_TB)[DR)
+M]^@`````N@$```#K!;H!````B=!(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(
+M@\0HPV9FD&9FD&9FD$%7059!54%455-(@^PH28G]#[=6($&X_____T2)P&:!
+M^H4`#X>`````#[?"1`^VA`=H"```1(G`08#X_W1K9H/Z?W<B00^VT$B+CT`)
+M``!(C0122(T$@DC!X`5(BT0(4`^V0`CK0V:!^H$`=QU!#[;`2(N7D`D``$AI
+MP,@/``!(BT00"`^V0`CK'T$/ML!(BY=H"0``2(T$P$C!X`5(BX00B`````^V
+M0`@/ML!!#[:\!>X(``!(C02_2(T$ATF-A,7(`0``2(E$)"!!#[;`2(T40$B-
+M%)!(P>(%28G730.]0`D``$B+3D@/M@'!X!@/ME$!P>(0"=`/ME$#"=`/ME$"
+MP>(("=#!Z`-(C6D(@_@0NA`````/1\*)P$R--,%,.?4/AWP!``#'1"0<````
+M`$B-!+](C02'2,'@`TJ-%"A(B50D$$B!PL`!``!(B50D"$F-A`4H`@``2(D$
+M)&9F9I!(B>_H`````$&)Q$B-=01(Q\<`````N00```#\\Z8/E\(/DL`XP@^%
+M"@$``$&#_!`/AP`!``"#1"0<`8-\)!P!=2)!QX>0`0```0```$6)IY0!``!(
+MBT4`28F'W````.G2````3(GOZ`````!(B<-(A<`/A,L```#&0$L&QD!*!6;'
+M@,@``````,9`2`;&0$D`2,=`>```!0#'@)`!```!````1(F@E`$``$F+A]0`
+M``!(B8/4````28N'U````$B)@\P```!(BT4`2(F#W````$B+1"0@2(E#4$B)
+MQ^@`````B(/J````9H-+:!!(BWPD(.@`````/`EV!F:!2V@``DB+5"0(@$(6
+M`4B+5"002(N",`(``$B)FC`"``!(BQ0D2(D32(E#"$B)&$B)WDR)[^@`````
+M2(/%"$PY]0^&O?[__TB#Q"A;74%<05U!7D%?PV9F9I!F9F:09F:09F:005=!
+M5D%505154TB![$@"``!(B7PD&$B)="00B=!(BU<(2(E4)"!(BPI(B4PD*`^V
+M5UB(5"0W2(GY2(/!2$B)3"0X2#E/2`^$D0(``(!\)#<`#X2&`@``#[;`B40D
+M#$B+?"0XZ`````!,C6#P3(U$)$"+3"0,N@$```!(BW0D($B+?"00Z`````!,
+MC7PD0(!\)$``#X0%`0``0;T`````38VT)-0```!!#[;M2&/%2(G#2,'C!$F-
+M?!]LN@@```!,B?;H`````(3`#X2Q````28U4'V`/MD((@^`/08B$).H```!!
+M#[=,)&AF@>'?_8G(@\@09D&)1"1H#[9"",#H!#P)=0N)R(/(,&9!B40D:$AC
+MQ4C!X`1!#[9$!VC`Z`0\"G4(9D&!3"1H``)(BTPD.$B+40A)C40D$$B)00A)
+MB4PD$$F)5"082(D"0?9$)$P"=$-!@&0D3/U)BU0D0$B%TG0S2(M$)"A(B[#X
+M"```OP8```#H`````.L;9F:09F:008/%`44X+W859F9FD&9FD.D2____13@O
+M#X<D`0``3(GBO@8```!(BWPD(.@`````08"\)(,`````="1F9I!FD$B+?"0H
+MZ`````"_`0```.@`````08"\)(,`````=>%)B[PD(`$``$B%_W0300^VM"0-
+M`0``N@$```#H`````$F+?"182(7_=!-!#[:T)($```"Z`0```.@`````28M$
+M)$!(A<!T;4C'0&``````0?9$)$P$=1Y(BWPD*.@`````28MT)$"Z`0```$B+
+M?"0HZ`````!)BU0D0$B+3"0H2(NQ^`@``+\&````Z`````!)BU0D0$B+1"0H
+M2(NP^`@``+\!````Z`````!)QT0D0`````!)BQ0D28M$)`A(B4((2(D02(M4
+M)""`:@X!2(M,)!B`:5@!3(GF2(M\)"CH`````$B+5"0X2(M$)!A(.5!(=`N`
+M;"0W`0^%@?W__TB!Q$@"``!;74%<05U!7D%?PY!!5T%6055!5%532('L*`(`
+M`$F)_TF)]4B)U4B+!TB)1"001`^VX4B-7"0@28G81(GAN@$```!(B?Y,B>_H
+M`````$2)XDR)[DB)[^@`````3(MU2$F#[A!(C5U(28U&$$@YV'0O00^V1DD\
+M#705/")U,^L/00^V1DD\#70&/")FD'4B0<9&2@5!QD9+!,9$)!X!ZP7&1"0>
+M`(!\)"``=1CIW0$``$V+=A!)@^X028U&$$@YV'6^Z]S&1"0?`$F-5V!(B50D
+M"$R+94A)@^P028U$)!!(.<,/A+P!```/MD0D'TC!X`1,C:P$C````&9F9I!)
+MC;PDU````+H(````3(GNZ`````"$P`^%8`$``$V+9"0028/L$$F-1"002#G8
+M#X1S`0``Z\I!@$<.`<9!2@7&@>@`````QD%+!&;'@<@``````,:!R@````!(
+MQT%X```%``^V?"0?2&/'2,'@!$B-E`2`````#[9"!(A!2`^V0@6(04E,B7E0
+M#[9""(/@#XB!Z@````^W<6AF@>;?_8GP@\@09HE!:`^V0@C`Z`0\"74)B?"#
+MR#!FB4%H2&/'2,'@!`^VA`2(````P.@$/`IU!F:!26@``DB):5A(8\=(P>`$
+M#[:4!(8```"(D8$```!(BX0$C````$B)@=0```!(B8',````@$58`4F+1VA)
+MB4]H2(M4)`A(B1%(B4$(2(D(2(M54$B-01!(B4502(E9$$B)41A(B0(/ME%(
+M2(G0@^`&QD0D'@!(@_@&=3#VP@%T&0^VD8$```!(B>Y,B?_H`````,9$)!X`
+MZQ)(B<Y(BWPD$.@`````QD0D'@"`1"0?`0^V1"0?.$0D(`^'1/[__X!\)!X`
+M="6^"@```$R)]^@`````ZQ9(BWPD$.@`````2(G!2(7`#X5Y_O__2('$*`(`
+M`%M=05Q!74%>05_#D$%7059!54%455-(@>Q(`@``28G]2(ET)"A(BR\/MD<H
+MB$0D-TB-5TA(B50D.$@Y5T@/A*$#``"$P`^$F0,``$B-3"1`2(/!7$B)3"0@
+M2(U$)$!(@\!42(E$)!A(C50D0$B#PD!(B50D$$B-3"1`2(/!$$B)3"0(2(U$
+M)$!(@\`@2(D$)$B+?"0XZ`````!,C6#(0;@`````N0````"Z`````$R)[DB+
+M?"0HZ`````!!B<>$P`^$"P,``$&^`````+L`````B5PD,$&X`````(G9N@$`
+M``!,B>Y(BWPD*.@`````#[;`2,'@!$B#P&1(/0`"```/A[D!``!,C40D0(G9
+MN@$```!,B>Y(BWPD*.@`````N@@```!,B>9(BWPD(.@`````A,`/A(8!``!(
+MBTPD.$B+40A)C40D.$B)00A)B4PD.$F)5"1`2(D"#[9$)$)!B$0D64B+="08
+M3(GOZ``````\_W06#[;`2&G`R`\``$@#A9`)``!)B40D$$6$]G1?#[9$)$/1
+MZ(/@`<'@!$$/ME0D78/B[PG"08A4)%T/MD0D0\'H`X/@`<'@!8/BWPG"08A4
+M)%T/MD0D0\'H`H/@`<'@`X/B]PG"08A4)%T/MD0D1D&(A"2[````Z;D````/
+MMD0D0D&(1"1938EL)`@/MD0D1D&(A"2[````#[=$)$1!B40D8`^WA"20````
+M9D&)A"2X````#[:$))(```!!B(0DN@```$B+A"2`````28F$)*@```!(BU0D
+M$$B+0@A)B80DL````$B+1"1028E$)'A(BTPD"$B+00A)B80D@````$F-E"2(
+M````2(M$)&!)B80DB````$B+#"1(BT$(2(E""$B+01!(B4(02(M$)'A)B80D
+MH````(M,)#!,B>)(BW0D*$R)[^@`````Z?D```!!@\8!@\,!13C^#X0"`0``
+MZ?W]__],B??H`````$B-6/!(B=J^!@```$R)[^@`````@+N#`````'0>9F:0
+M2(GOZ`````"_`0```.@`````@+N#`````'7E2(M#0$B%P'192,=`8`````#V
+M0TP$=1E(B>_H`````$B+<T"Z`0```$B)[^@`````2(M30$B+M?@(``"_`0``
+M`.@`````2(M30$B+M?@(``"_!@```.@`````2,=#0`````!(BQ-(BT,(2(E"
+M"$B)$$&`;0X!08!L)%@!2(G>2(GOZ`````!-.70D2`^%+/___T&`;2@!3(GF
+M2(GOZ`````!(BT0D.$DY14AT(8!L)#<!=!IFD.F__/__38UT)$A-.70D2)`/
+MA?+^___KQ$B!Q$@"``!;74%<05U!7D%?PV9FD&9FD$%7059!54%455-(@>PX
+M`@``2(E\)!A(B?5(BP9(B40D($B)_DB)[^@`````0;@`````N0````"Z````
+M`$B)[DB+?"08Z`````"(1"0OA,`/A&X#``!!OP````!!O@````!(C55(2(E4
+M)`A(C4U@2(D,)$&X`````$2)\;H!````2(GN2(M\)!CH``````^VP$C!X`1(
+M@\!D2#T``@``#X<,`P``3(U$)#!$B?&Z`0```$B)[DB+?"08Z`````!,C60D
+M,$F-="1<2(GOZ``````\_P^%V`(``$B+?"0@Z`````!(B<-(A<`/A.P"``"`
+M12@!QD!8`$F+1"1<2(D#28UT)%1(B>_H`````#S_=!H/ML!(:<#(#P``2(MT
+M)"!(`X:0"0``2(E#$$$/MD0D`HA#64$/MD0D`]'H@^`!P>`$#[9378/B[PG"
+MB%-=00^V1"0#P>@#@^`!P>`%@^+?"<*(4UU!#[9$)`/!Z`*#X`'!X`.#XO<)
+MPHA374B):PA!#[9$)`:(@[L```!)BT0D"$B)0W!!#[9$)`>(0UI!#[=$)`2)
+M0V!!#[=$)%!FB8.X````00^V1"12B(.Z````28M$)$!(B8.H````28M$)$A(
+MB8.P````28M$)!!(B4-X28M$)!A(B8.`````2(V+B````$F-5"0@28M$)"!(
+MB8.(````2(M""$B)00A(BT(02(E!$$F+1"0X2(F#H````$B+55!(C4,X2(E%
+M4$B+3"0(2(E+.$B)4T!(B0)!@#PD``^$:@$``$&]`````$B-<TA(B70D$$B+
+M?"0@Z`````!(B<%(A<`/A&\!``"`10X!QD!*!<:`Z`````#&0$L$2,=`>```
+M!0!FQX#(``````!!#[?]2&/'2,'@!$F-5`1@#[9"!(A!2`^V0@6(04E(B6E0
+M2(E96`^V0@:(@8$````/MD((@^`/B('J````#[=Q:&:!YM_]B?"#R!!FB4%H
+M#[9"",#H!#P)=0F)\(/(,&:)06A(8\=(P>`$00^V1`1HP.@$/`IU"F:!26@`
+M`F9F9I!(8\=(P>`$28M$!&Q(B8'4````2(F!S````(!#6`%(BT5H2(E-:$B+
+M%"1(B1%(B4$(2(D(2(M34$B-01!(B4-02(MT)!!(B7$02(E1&$B)`@^V44A(
+MB="#X`9(@_@&=2;VP@%T%`^VD8$```!(B=Y(B>_H`````.L-2(G.2(M\)"#H
+M`````$&#Q0%!#[8$)&9$.>@/AZS^__]F9F:09F:008/'`4&#Q@%$.GPD+P^%
+MK_S__X!]#@!U$<9%"?](B>Y(BWPD(.@`````2('$.`(``%M=05Q!74%>05_#
+M9F9FD$%7059!54%455-(@^P828G^28GT0;@`````N0````"Z`````.@`````
+M08G%A,!T-KT`````NP````!,C7PD%Y!,B?F)VDR)YDR)]^@`````@'PD%_X/
+MA:X```"#Q0&#PP%$..UUVD$/MD0D6(/H`4&(1"18A,!T>TF++"1!QD0D6`!)
+MBUPD2$B#ZSA)C50D2$B-0SA(.=!T<$B#>Q``=4#K!TB#>Q``=3=!QD0D6`%,
+MB>9,B??H``````^VB[L```!(B[VX$```2<?``````$B)VDR)YN@`````ZRUF
+M9F:02(M;.$B#ZSA(C4,X2#G0=;'K%DR)YDR)]^@`````3(GF3(GWZ`````!(
+M@\086UU!7$%=05Y!7\-F9F:09F9FD$%505154TB#[`A(B?U)B?1,BR^["@``
+M`$R)YDB)[^@`````A,!U#[_H`P``Z`````"#ZP%UXD$/MG5#0(3V="(/ME4-
+MN0````#VP@%T#.L22(G02-/XJ`%U"(/!`4`X\77N28L4)$F+1"0(2(E""$B)
+M$(!M#@%,B>9,B>_H`````/9%#`)T24B+=4!(A?9U&$R)[^@`````2(G&2(7`
+M#X12`0``2(E%0$R)+DB)KH@```#&1D8`QD9'`,9&0@!F@TY.!$R)[^@`````
+MZ28!``!(BT5`2(7`#X2X````2(VPD````$F+?2CH`````$B+=4!,B>_H````
+M`$R-96!,.65@#X2&````3(GGZ`````!(B<-(BT!`2(7`=%E(QT!@`````/9#
+M3`1U&4R)[^@`````2(MS0+H!````3(GOZ`````!(BU-`28NU^`@``+\!````
+MZ`````!(BU-`28NU^`@``+\&````Z`````!(QT-``````(!M#@%(B=Y,B>_H
+M`````$PY96`/A7K___](QT5``````(!]#@!T$DB-?6#H`````$B)P8!M#@'K
+M"TR)[^@`````2(G!2(7)=#E(BU5H2(E-:$B-16!(B0%(B5$(2(D*@$4.`4B)
+M:5#&04@%QD%)`,9!2P;&04H#2(G.3(GOZ`````!(@\0(6UU!7$%=PV9F9I!F
+M9F:09F9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)^TB)]0^W3B!F
+M@?F%``^'E0````^WP0^VM`=H"```0(#^_P^$@````&:#^7]W*$`/MM9(BX]`
+M"0``2(T$4DB-!()(P>`%2(M$"%`/MD`(ZTEF9I!F9I!F@?F!`'<=0`^VQDB+
+MEY`)``!(:<#(#P``2(M$$`@/MD`(ZQ]`#[;&2(N7:`D``$B-!,!(P>`%2(N$
+M$(@````/MD`(0`^VUCS_=`=F@?K_`'4C2(-]>`!T#$B-=7A(B=_H`````$B)
+M[DB)W^@`````Z3T!```/ML`/MHP#[@@```^WPDB-%$!(C1202,'B!4F)U4P#
+MJT`)``"`?20`#X2M````2(T$B4B-!(%,C:3#P`$``$$/MDPD%0^V53L/MG4Z
+M10^V1"062,?'`````+@`````Z`````!)BU4`28M%"$B)0@A(B1!!@&PD%@%,
+MB>Y(B=_H`````$B)[DB)W^@`````#[9[0T"$_P^$H@```$$/MG0D%;D`````
+M0/;&`74/ZQD/MLI(B?!(T_BH`701B<Y(B=_H`````.MVN@````"#P@%`./IU
+MVNMG9F:09I!(C02)2(T$@4R-I,/(`0``@'TZ`74LOQ`G``#H`````$B)[DB)
+MW^@`````N0$```"Z`````$R)[DR)Y^@`````ZR"_4,,``.@`````2(GN2(G?
+MZ`````!,B>Y,B>?H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9I!F
+MD$%7059!54%455-(@^P(2(G[28GU08G608G/2(L'2(D$)(!_#@!T>;T`````
+M3(UG8$R)Y^@`````2(G"2(M#:$B)4VA,B2)(B4((2(D03#EJ6'4-1#BR@0``
+M`'0-9F9FD(/%`4`X:PYWQT`X:PYT,4&`_U!U*\9"2P;&0DH%QD)(!\9"20!,
+MB6I82(E:4,:"R@````!(B=9(BSPDZ`````!(@\0(6UU!7$%=05Y!7\.02(/L
+M.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$B)_4F)]`^W5B!F@?J%
+M``^'C@````^WP@^VA`=H"```//]T?V:#^G]W)`^VP$B-%$!(C1202,'B!4@#
+MET`)``!(BT)0#[90".M>9F9FD`^W1B!F/8$`=R,/M\`/MH0':`@``$AIP,@/
+M``!(`X>0"0``2(M`"`^V4`CK+0^W1B`/MH0':`@``$B-!,!(P>`%2`.':`D`
+M`$B+@(@````/ME`(ZP6Z_____[G_____9D&!?"0@A0!W#D$/MT0D(`^VC`5H
+M"```#[;"#[:$!>X(``!(C12`2(T4D$R-M-7(`0``#[;!2(T$P$C!X`5,BZUH
+M"0``20'%08!\)#P"#X6`````00^V1"1`)?````"#^"!T!8/X$'5K00^V5"1`
+MB="#X`^#^`%U*(G1@>'P````0;@!````N@(```"^`````$R)[^@`````Z>,*
+M``!F9I!!#[9%1TF+5,5800^V1"1`)?````"#^"`/E,"#P`B(@NH```!(BT)@
+M9H%@3O_^Z:T*``!!#[9$)"2$P'0[B<-)@WPD>`!T#4F-="1X2(GOZ`````!,
+MB>9(B>_H`````(#[`@^%>`H``$R)[DB)[^@`````Z6@*``!!QX4(`0``````
+M`$$/MD5"/"0/A_,)```/ML#_),4`````28M&(/9`-@@/A!(*``#I-P8``&9F
+MD$B+E1`1``!(@<),"```00^V15#!X`A(F$@!PHL"B04`````@_@%N@4````/
+M1\)!B$4[08!^#P!T#T'&14(`0<9&#P#IBPD``$'&14("Z8$)``!(BY40$0``
+M2('"3`@``$$/MD50P>`(2)A(`<*+`HD%``````^VP&9!B44\2(N5$!$``$B!
+MPD0(``!!#[9%4,'@"$B82`'"BP*)!0````")PL'J"&9!B54^P>`(9D$)13QF
+M@?I`074*0<9%0AGI$`D``&9!@7T^%9>X`P```+HD````#T3"08A%0NGS"```
+M2(N5$!$``$B!PD0(``!!#[9%4,'@"$B82`'"BP*)!0````!!B$4Y2(N5$!$`
+M`$B!PDP(``!!#[9%4,'@"$B82`'"BP*)!0````")P*@(=`=!QD4Z#.L=J`1T
+M!T'&13H+ZQ*#X`)(@_@!&<#WT(/@"D&(13I!#[9%1SP!&<"#X`*#P!1!B$5"
+MZ6<(``!(BX40$0``2`5,"```00^V55#!X@A(8])(`="+`(D%`````(/("$&(
+M14A!QD5"!>DS"```0<9%0@!!#[=%3F8E]_V#R`)F08E%3DF#?"1X`'0-28UT
+M)'A(B>_H`````$R)YDB)[^@`````0<9&"?],B?9(B>_H`````.E%"```0<9%
+M0@3IW@<``$$/MD5'@\`!08A%1T$Z13MS5T'&14(628-\)'@`=`U)C70D>$B)
+M[^@`````3(GF2(GOZ`````!!QX60````@(0>`$G'A:``````````38FMJ```
+M`$F-M9````!(BWTHZ`````#IT@<``$'&14<`0<9%0A>_(*$'`.@`````Z5P'
+M``!!QD5"%.E2!P``0<9%0@CI2`<``$'&14(4Z3X'``!!QD5*`.@`````28F%
+M\````$'&14(5Z2,'``!(BY40$0``2('"3`@``$$/MD50P>`(2)A(`<*+&HD=
+M``````^VVTB+E1`1``!(@<)$"```00^V15#!X`A(F$@!PHL"B04`````Z```
+M``!)B87X````@^,/@_L#=0I!QD5""NF\!@``08N%\`````5`#0,`03F%^```
+M`'D:00^V14H\"G<10<9%0A6#P`%!B$5*Z8T&``!!#[9%1TF#?,58``^$KP$`
+M`$C'!"0`````08!^#@!T0D&_`````$F-7F!(B=_H`````$B)!"1!#[9%1TB+
+M%"1).53%6'0<2(M#"$B)4PA(B1I(B4((2(D008/'`44X?@YWR$&`;@X!2(L,
+M)$B+04!(A<`/A"X!``!(QT!@`````/9!3`1U-TB)[^@`````2(L4)$B+0F#&
+M@!P!```!2(MR0+H!````2(GOZ`````!(BPPD2(M!8,:`'`$```!(BP0D2(M0
+M0$B+M?@(``"_`0```.@`````2(L4)$B+0D!(BXB`````2(7)=#$/MT(X2,>$
+MQ6@$````````2(M"0$C'@(``````````2(MR0$B+OI````"Z_______12(L,
+M)$B+04!(A<!T.$B+D(@```!(A=)T+`^W03A(QX3%:`0```````!(BT%`2,>`
+MB`````````!(BT%`2(NXD````/_22(L4)$B+0D`/ME`"#[9P`4C'QP````"X
+M`````.@`````2(L,)$B+44!(B[7X"```OP8```#H`````$B+!"1(QT!`````
+M`$$/MD5'2<=$Q5@`````2(LT)$B)[^@`````0<9%0@GIPP0``$B+E1`1``!(
+M@<),"```00^V15#!X`A(F$@!PHL*B0T`````#[;)2(N5$!$``$B!PD0(``!!
+M#[9%4,'@"$B82`'"BP*)!0````#!X`@)R$&)151!@'U""G0'J0```0!T"D'&
+M14(+Z5D$``!!QD5"#$$/MD5'28-\Q5@`=%)!@'X.``^$F00``$&_`````$F-
+M7F!(B=_H`````$B)PD$/MD5'23E4Q5AU"$&`;@X!ZRJ02(M#"$B)4PA(B1I(
+MB4((2(D008/'`44X?@YV#>O#2(GOZ`````!(B<)(A=(/A#X$``!!#[9%1TF)
+M5,5800^V14N(@NH```#IQP,``&9F9I!(B>_H`````+\!````Z`````"#ZP&#
+M^_]T"DF+1B#V0#8(=-Q!QD5"">F5`P``2(N5$!$``$B!PDP(``!!#[9%4,'@
+M"$B82`'"BPJ)#0`````/MLE(BY40$0``2('"1`@``$$/MD50P>`(2)A(`<*+
+M`HD%``````^VP,'@"`G()?\/```]$P$```^4PCTC`0``#Y3!A-)U$(3)=0P]
+M,P$``'5"Z4@#``!!QD5"&(32D'0*0<9%2PCI!P,``(3)9I!T"D'&14L)Z?<"
+M```],P$```^%[`(``$'&14L*9F9FD.G>`@``00^V348/MM%!#[9%.X/H`3G"
+M?1:-00%!B$5&08!%1P%!QD5"!^FT`@``0<9%1P!!QD5"'NFE`@``0<9%0@/I
+MFP(``$'&14(B9F:0Z8X"``!!QD5"(^F$`@``0<9%0@/I>@(``$B+E1`1``!(
+M@<),"```00^V15#!X`A(F$@!PHL*B0T`````2(N5$!$``$B!PD0(``!!#[9%
+M4,'@"$B82`'"BQ*)%0````")T,'@"`^VR0G(9CT#$0^%HP```(G0P>@(9CU%
+M4W0*9CU``P^%C@```&9!QT4\`Q%F08E%/F8]15-U'T&`O14!```"=!5!QH45
+M`0```D''A1@!```?````ZR9F08%]/D`#=1U!@+T5`0```W030<:%%0$```-!
+MQX48`0``#_@#`$'&A1P!```!3(GOZ`````!!QH4<`0```$F+10!(B[CX"```
+MO@````#H`````$'&14(#Z7T!``!!QD5"(4'&A14!````Z6L!``!(BY40$0``
+M2('"3`@``$$/MD50P>`(2)A(`<*+`HD%`````$B+E1`1``!(@<)$"```00^V
+M15#!X`A(F$@!PHL"B04`````0<9%0A_I&P$``$'&14(@Z1$!``!(BY40$0``
+M2('"3`@``$$/MD50P>`(2)A(`<*+`HD%`````$B+E1`1``!(@<)$"```00^V
+M15#!X`A(F$@!PHL"B04`````00^V34=!#[9%.XU1`4&(54</MLD/ML"#Z`$Y
+MP;@&````NA\````/3,)!B$5"Z9D```!(BY40$0``2('"3`@``$$/MD50P>`(
+M2)A(`<*+"HD-``````^VR4B+E1`1``!(@<)$"```00^V15#!X`A(F$@!PHL"
+MB04`````P>`("<%!B8T$`0``0<9%0AKK/4'&14(;ZS9(BX40$0``2`5,"```
+M00^V55#!X@A(8])(`="+`(D%`````(/@]T&(14A!QD5"'.L%0<9%0AU)@WPD
+M>`!T#4F-="1X2(GOZ`````!,B>9(B>_H`````$R)[DB)[^@`````ZS!!QD5"
+M&.G"_/__2(GO9F:0Z`````"_`0```.@`````NSY"#P#I`?S__V9F9I!F9I!(
+MBUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(@\0XPV9F9I!F9I!F9I!F
+M9I!(@^PX2(E<)`A(B6PD$$R)9"083(EL)"!,B70D*$R)?"0P2(G]2(GS#[=.
+M(&:!^84`#X??````#[?!#[:T!V@(``!`@/[_#X3*````9H/Y?W<B0`^VUDB+
+MCT`)``!(C0122(T$@DC!X`5(BT0(4`^V0`CK0V:!^8$`=QU`#[;&2(N7D`D`
M`$AIP,@/``!(BT00"`^V0`CK'T`/ML9(BY=H"0``2(T$P$C!X`5(BX00B```
-M``^V0`A`#[;6//]T!V:!^O\`=2-(@WUX`'0,2(UU>$B)W^@`````2(GN2(G?
-MZ`````#I/0$```^VP`^VC`/N"```#[?"2(T40$B-%)!(P>(%28G53`.K0`D`
-M`(!])``/A*T```!(C02)2(T$@4R-I,/``0``00^V3"05#[95.P^V=3I%#[9$
-M)!9(Q\<`````N`````#H`````$F+50!)BT4(2(E""$B)$$&`;"06`4R)[DB)
-MW^@`````2(GN2(G?Z``````/MGM#0(3_#X2B````00^V="05N0````!`]L8!
-M=0_K&0^VRDB)\$C3^*@!=!&)SDB)W^@`````ZW:Z`````(/"`4`X^G7:ZV=F
-M9I!FD$B-!(E(C02!3(VDP\@!``"`?3H!=2R_$"<``.@`````2(GN2(G?Z```
-M``"Y`0```+H`````3(GN3(GGZ`````#K(+]0PP``Z`````!(B>Y(B=_H````
-M`$R)[DR)Y^@`````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9FD&:005=!
-M5D%505154TB#[`A(B?M)B?5!B=9!B<](BP=(B00D@'\.`'1YO0````!,C6=@
-M3(GGZ`````!(B<)(BT-H2(E3:$R)(DB)0@A(B1!,.6I8=0U$.+*!````=`UF
-M9F:0@\4!0#AK#G?'0#AK#G0Q08#_4'4KQD)+!L9"2@7&0D@'QD))`$R):EA(
-MB5I0QH+*`````$B)UDB+/"3H`````$B#Q`A;74%<05U!7D%?PY!(@^PX2(E<
-M)`A(B6PD$$R)9"083(EL)"!,B70D*$R)?"0P2(G]28GT#[=6(&:!^H4`#X>.
-M````#[?"#[:$!V@(```\_W1_9H/Z?W<D#[;`2(T40$B-%)!(P>(%2`.70`D`
-M`$B+0E`/ME`(ZUYF9F:0#[=&(&8]@0!W(P^WP`^VA`=H"```2&G`R`\``$@#
-MAY`)``!(BT`(#[90".LM#[=&(`^VA`=H"```2(T$P$C!X`5(`X=H"0``2(N`
-MB`````^V4`CK!;K_____N?____]F08%\)""%`'<.00^W1"0@#[:,!6@(```/
-MML(/MH0%[@@``$B-%(!(C1203(VTU<@!```/ML%(C03`2,'@!4R+K6@)``!)
-M`<5!@'PD/`(/A8````!!#[9$)$`E\````(/X('0%@_@0=6M!#[94)$")T(/@
-M#X/X`74HB=&!X?````!!N`$```"Z`@```+X`````3(GOZ`````#IXPH``&9F
-MD$$/MD5'28M4Q5A!#[9$)$`E\````(/X(`^4P(/`"(B"Z@```$B+0F!F@6!.
-M__[IK0H``$$/MD0D)(3`=#N)PTF#?"1X`'0-28UT)'A(B>_H`````$R)YDB)
-M[^@`````@/L"#X5X"@``3(GN2(GOZ`````#I:`H``$''A0@!````````00^V
-M14(\)`^'\PD```^VP/\DQ0````!)BT8@]D`V"`^$$@H``.DW!@``9F:02(N5
-M$!$``$B!PDP(``!!#[9%4,'@"$B82`'"BP*)!0````"#^`6Z!0````]'PD&(
-M13M!@'X/`'0/0<9%0@!!QD8/`.F+"0``0<9%0@+I@0D``$B+E1`1``!(@<),
-M"```00^V15#!X`A(F$@!PHL"B04`````#[;`9D&)13Q(BY40$0``2('"1`@`
-M`$$/MD50P>`(2)A(`<*+`HD%`````(G"P>H(9D&)53[!X`AF00E%/&:!^D!!
-M=0I!QD5"&>D0"0``9D&!?3X5E[@#````NB0````/1,)!B$5"Z?,(``!(BY40
-M$0``2('"1`@``$$/MD50P>`(2)A(`<*+`HD%`````$&(13E(BY40$0``2('"
-M3`@``$$/MD50P>`(2)A(`<*+`HD%`````(G`J`AT!T'&13H,ZQVH!'0'0<9%
-M.@OK$H/@`DB#^`$9P/?0@^`*08A%.D$/MD5'/`$9P(/@`H/`%$&(14+I9P@`
-M`$B+A1`1``!(!4P(``!!#[954,'B"$ACTD@!T(L`B04`````@\@(08A%2$'&
-M14(%Z3,(``!!QD5"`$$/MT5.9B7W_8/(`F9!B45.28-\)'@`=`U)C70D>$B)
-M[^@`````3(GF2(GOZ`````!!QD8)_TR)]DB)[^@`````Z44(``!!QD5"!.G>
-M!P``00^V14>#P`%!B$5'03I%.W-70<9%0A9)@WPD>`!T#4F-="1X2(GOZ```
-M``!,B>9(B>_H`````$''A9````"`A!X`2<>%H`````````!-B:VH````28VU
-MD````$B+?2CH`````.G2!P``0<9%1P!!QD5"%[\@H0<`Z`````#I7`<``$'&
-M14(4Z5('``!!QD5"".E(!P``0<9%0A3I/@<``$'&14H`Z`````!)B87P````
-M0<9%0A7I(P<``$B+E1`1``!(@<),"```00^V15#!X`A(F$@!PHL:B1T`````
-M#[;;2(N5$!$``$B!PD0(``!!#[9%4,'@"$B82`'"BP*)!0````#H`````$F)
-MA?@```"#XP^#^P-U"D'&14(*Z;P&``!!BX7P````!4`-`P!!.87X````>1I!
-M#[9%2CP*=Q%!QD5"%8/``4&(14KIC08``$$/MD5'28-\Q5@`#X2O`0``2,<$
-M)`````!!@'X.`'1"0;\`````28U>8$B)W^@`````2(D$)$$/MD5'2(L4)$DY
-M5,58=!Q(BT,(2(E3"$B)&DB)0@A(B1!!@\<!13A^#G?(08!N#@%(BPPD2(M!
-M0$B%P`^$+@$``$C'0&``````]D%,!'4W2(GOZ`````!(BQ0D2(M"8,:`'`$`
-M``%(BW)`N@$```!(B>_H`````$B+#"1(BT%@QH`<`0```$B+!"1(BU!`2(NU
-M^`@``+\!````Z`````!(BQ0D2(M"0$B+B(````!(A<ET,0^W0CA(QX3%:`0`
-M``````!(BT)`2,>`@`````````!(BW)`2(N^D````+K______]%(BPPD2(M!
-M0$B%P'0X2(N0B````$B%TG0L#[=!.$C'A,5H!````````$B+04!(QX"(````
-M`````$B+04!(B[B0````_])(BQ0D2(M"0`^V4`(/MG`!2,?'`````+@`````
-MZ`````!(BPPD2(M10$B+M?@(``"_!@```.@`````2(L$)$C'0$``````00^V
-M14=)QT3%6`````!(BS0D2(GOZ`````!!QD5"">G#!```2(N5$!$``$B!PDP(
-M``!!#[9%4,'@"$B82`'"BPJ)#0`````/MLE(BY40$0``2('"1`@``$$/MD50
-MP>`(2)A(`<*+`HD%`````,'@"`G(08E%5$&`?4(*=`>I```!`'0*0<9%0@OI
-M600``$'&14(,00^V14=)@WS%6`!T4D&`?@X`#X29!```0;\`````28U>8$B)
-MW^@`````2(G"00^V14=).53%6'4(08!N#@'K*I!(BT,(2(E3"$B)&DB)0@A(
-MB1!!@\<!13A^#G8-Z\-(B>_H`````$B)PDB%T@^$/@0``$$/MD5'28E4Q5A!
-M#[9%2XB"Z@```.G'`P``9F9FD$B)[^@`````OP$```#H`````(/K`8/[_W0*
-M28M&(/9`-@ATW$'&14()Z94#``!(BY40$0``2('"3`@``$$/MD50P>`(2)A(
-M`<*+"HD-``````^VR4B+E1`1``!(@<)$"```00^V15#!X`A(F$@!PHL"B04`
-M````#[;`P>`("<@E_P\``#T3`0``#Y3"/2,!```/E,&$TG40A,EU##TS`0``
-M=4+I2`,``$'&14(8A-*0=`I!QD5+".D'`P``A,EFD'0*0<9%2PGI]P(``#TS
-M`0``#X7L`@``0<9%2PIF9F:0Z=X"``!!#[9-1@^VT4$/MD4[@^@!.<)]%HU!
-M`4&(149!@$5'`4'&14('Z;0"``!!QD5'`$'&14(>Z:4"``!!QD5"`^F;`@``
-M0<9%0B)F9I#IC@(``$'&14(CZ80"``!!QD5"`^EZ`@``2(N5$!$``$B!PDP(
-M``!!#[9%4,'@"$B82`'"BPJ)#0````!(BY40$0``2('"1`@``$$/MD50P>`(
-M2)A(`<*+$HD5`````(G0P>`(#[;)"<AF/0,1#X6C````B=#!Z`AF/453=`IF
-M/4`##X6.````9D''13P#$69!B44^9CU%4W4?08"]%0$```)T%4'&A14!```"
-M0<>%&`$``!\```#K)F9!@7T^0`-U'4&`O14!```#=!-!QH45`0```T''A1@!
-M```/^`,`0<:%'`$```%,B>_H`````$'&A1P!````28M%`$B+N/@(``"^````
-M`.@`````0<9%0@/I?0$``$'&14(A0<:%%0$```#I:P$``$B+E1`1``!(@<),
-M"```00^V15#!X`A(F$@!PHL"B04`````2(N5$!$``$B!PD0(``!!#[9%4,'@
-M"$B82`'"BP*)!0````!!QD5"'^D;`0``0<9%0B#I$0$``$B+E1`1``!(@<),
-M"```00^V15#!X`A(F$@!PHL"B04`````2(N5$!$``$B!PD0(``!!#[9%4,'@
-M"$B82`'"BP*)!0````!!#[9-1T$/MD4[C5$!08A51P^VR0^VP(/H`3G!N`8`
-M``"Z'P````],PD&(14+IF0```$B+E1`1``!(@<),"```00^V15#!X`A(F$@!
-MPHL*B0T`````#[;)2(N5$!$``$B!PD0(``!!#[9%4,'@"$B82`'"BP*)!0``
-M``#!X`@)P4&)C00!``!!QD5"&NL]0<9%0AOK-DB+A1`1``!(!4P(``!!#[95
-M4,'B"$ACTD@!T(L`B04`````@^#W08A%2$'&14(<ZP5!QD5"'4F#?"1X`'0-
-M28UT)'A(B>_H`````$R)YDB)[^@`````3(GN2(GOZ`````#K,$'&14(8Z<+\
-M__](B>]F9I#H`````+\!````Z`````"[/D(/`.D!_/__9F9FD&9FD$B+7"0(
-M2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD&9FD&9FD&9FD$B#
-M[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!(B?U(B?,/MTX@9H'Y
-MA0`/A]\````/M\$/MK0':`@``$"`_O\/A,H```!F@_E_=R)`#[;62(N/0`D`
-M`$B-!%)(C02"2,'@!4B+1`A0#[9`".M#9H'Y@0!W'4`/ML9(BY>0"0``2&G`
-MR`\``$B+1!`(#[9`".L?0`^VQDB+EV@)``!(C03`2,'@!4B+A!"(````#[9`
-M"#S_=%L/ML`/MHP%[@@``(#Y_W050(#^_W0/#[9[)$"`_P9U969FD&:0@/G_
-M=#%`@/[_="M`#[;&2(T40$B-%)!(P>(%28G43`.E0`D``$'&1"1+`D'&1"1*
-M_^FZ!P``2(-[>`!T#$B-<WA(B>_H`````$B)WDB)[^@`````Z<<'``!F9F:0
-M9F:00`^VQDB-%$!(C1202,'B!4F)U$P#I4`)``!!#[>T),@```!F@?ZK#7<&
-M0(#_`G4Z2(-[>`!T#$B-<WA(B>_H`````$B)WDB)[^@`````0<9$)$K_0<9$
-M)$L"3(GF2(GOZ`````#I5@<``+H`````0(#_('4>2(M34`^V`H/@?SQQ=@D/
-MME(!@^(/ZP</ME("@^(/1`^VZ4N-1*T`28U$A0!,C;3%R`$```^V0S@\&@^$
-MY@4``#P:=QP\$G1./!60#X2)!@``A,`/A(X%``!FD.F[!@``/"4/A"<#```\
-M)9!W$SP;#X6F!@``9F:09F:0Z5P%```\G@^$%`0``#R@D`^%B@8``.E8!@``
-M0(3_9I`/A<T"``!(BTM(@'LY`&:0=&9(A<ET2X!Y`8!U18!Y`@!U/P^V00,\
-M/'<W#[;028VT)(0```"X`````,8$,"!(@\`!2(/X%'7R@_H4#T/028V\)(0`
-M``")TDB-<03H`````&9!QX0DR```````0<9$)$H9Z0@&``!!QD0D2ACV009`
-M=1$/M@&#X!^#^`T/A9$!``#K"P^V`8/@'X/X#74(0<9$)$D-ZP9!QD0D22)!
-M#[9T)$E(Q\<`````N`````#H`````$B#>W@`=`Q(C7-X2(GOZ`````!(B=Y(
-MB>_H`````$N-1*T`28U$A0"`O,76`0````^$M04``$&^`````$N-1*T`28U$
-MA0!(P>`#3(VD!2@"``!(C1PH3(V[P`$``$R)Y^@`````2(N3,`(``$B)@S`"
-M``!,B2!(B5`(2(D"#[9`23PB=`0\#74*08/&`44X=Q9WRDN-1*T`28U$A0`/
-MMH3%U@$``$0X\`^%/04``(3`#X0U!0``0;P`````9L=$)`8``$&_`````$N-
-M1*T`28U$A0!(P>`#3(VL!2@"``!(C1PH3(VSP`$``$R)[^@`````2(G"2(N#
-M,`(``$B)DS`"``!,B2I(B4((2(D0#[9"23PB=`0\#743#[=".&8[1"0&<@AF
-MB40D!DF)UT&#Q`%%.&86=[1-A?\/A*P$``!!@']*_P^$H00``$'&1TK_3(G^
-M2(GOZ`````#IC`0``(/X`7410<9$)$D!0<9$)$K_Z48$``#V004!9I!T"&9!
-M@4PD:``$2(MS2$B%]G1F28V4))@```"X`````,8$$`!(@\`!2(/X*'7R28V4
-M),````"P`,8$$`!(@\`!2(/X"'7R28V,))@```!(C58(2(M&"$F)A"28````
-M2(M""$B)00A(BT(02(E!$(M&($&)A"3`````08.\))`!````#X6X`P``0<9$
-M)$H<Z:T#``"-1@%F08F$),@```"_$"<``.@`````0<9$)$H%Z8P#``!(BTM(
-M0(3_#X69````#[91!L'B"`^V007!X!`)P@^V00<)P@^V003!X!@)PD&)E"3D
-M````#[81P>(8#[9!`PG"#[9!`L'@"`G"#[9!`<'@$`G0B<))B50D>$&#O"3D
-M`````'4?9D&#A"3(`````;\0)P``Z`````!!QD0D2AOI"0,``(/X_W439D&!
-M3"1H``1!QD0D2AOI\0(``$'&1"1*#>GF`@``0(#_(&:0=2Z`^@9T!8#Z`G4D
-MC48!9D&)A"3(````OQ`G``#H`````$'&1"1*!>FS`@``9F:02(-[>`!T#$B-
-M<WA(B>_H`````$B)WDB)[^@`````3(GB3(GV2(GOZ`````#IKP(``$R+0TA`
-MA/\/A<P```!!#[90"L'B"$$/MD`)P>`0"<)!#[9`"PG"00^V0`C!X!@)PD&)
-ME"3D````00^V2`-(P>$@00^V0`)(P>`H2`G!00^V`$C!X#A("<%!#[9``4C!
-MX#!("<%!#[90!L'B"$$/MD`%P>`0"<)!#[9`!PG"00^V0`3!X!@)PD@)T4F)
-M3"1X0?9`#`%T!V9!@TPD:@1!@[PDY`````!U'V9!@X0DR`````&_$"<``.@`
-M````0<9$)$H;Z;@!``!F08-,)&@!0<9$)$H-Z:8!``!`@/\@9I!U+H#Z!G0%
-M@/H"=22-1@%F08F$),@```"_$"<``.@`````0<9$)$H;Z7,!``!F9I!(@WMX
-M`'0,2(US>$B)[^@`````2(G>2(GOZ`````!,B>),B?9(B>_H`````.EO`0``
-M0<9$)$H4Z30!``!`@/\@=2Z`^@9T!8#Z`G4DC48!9D&)A"3(````OQ`G``#H
-M`````$'&1"1*%.D#`0``9F:00<9$)$H;Z?4```!`A/]FD'5M2(M#2&9!@TPD
-M:`)F08-,)&H!9D&!3"1HA`"`>`,`=06`.!9W'V9!@X0DR`````&_$"<``.@`
-M````0<9$)$H-Z:H```#V0`8$=`EF08-,)&H"ZP=F08-D)&K]2(M#>$F)1"0P
-M2,=#>`````#K.$"`_R!U*X#Z!G0(@/H"9F:0=26-1@%F08F$),@```"_$"<`
-M`.@`````0<9$)$H%ZU!F08-D)&CY0<9$)$H.ZT%`A/]U!V9!@TPD:@-!QD0D
-M2@_K+4"$_W4+2(G>2(GOZ`````!!@[PDD`$```$9P(/@$X/`!4&(1"1*9F9F
-MD&9FD$B#>W@`=`Q(C7-X2(GOZ`````!(B=Y(B>_H`````$R)YDB)[^@`````
-M9F9FD&9FD$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#D)"0
-MD)"0D)"0D)"0D(/B!\'B"(#.($B+1PA(+>0\``!(P>8(@>8`_P``2`'PB1`/
-MMP!FB04`````#[;`PX/B!\'B"(C*@,X02(M'"$@MY#P``$C!Y@B!Y@#_``!(
-M`?")$,-F9F:09F9FD&9FD%53O0````!!N?____^[`````$&[`````$6)VD&#
-MPP&X`0```$&)P$2)V4'3X$2)P;X`````N,#AY`"Z`````/?Q.?AW$8GZ*<)$
-M.<IS"(GU08G11(G3@\8!1`'!@_X0==1!@_L(=;&-!.T`````"=@/ML!;7<-F
-M9F:09F:09F:02(/L$$B)'"1,B60D"$F)_$`/MMZY`````+H'````B=[H*___
-M_T$/MHPD01(``+H#````B=Y,B>?H$____TB+'"1,BV0D"$B#Q!##9F:09I!3
-MB?,/MO*Z`P```.C`_O__.-@/E,`/ML!;PV9FD&9FD$B%_W0WN@````!F9I!F
-M9I`/MH0ZZ@@```^VR#S_=!,/M\%(C03`2,'@!4@#AV@)``##2(/"`4B#^@1U
-MU+@`````PV9F9I!F9F:09F:09F:055-(BY\`"0``2(7;2`]$W[T`````N0``
-M``"Z!P```(GN2(G?Z&?^__^Y1````+H"````B>Y(B=_H4_[__[G0````N@``
-M``")[DB)W^@__O__N0````"Z!````(GN2(G?Z"O^__^#Q0&#_0)UJ+^@A@$`
-MZ$G^__^(@T$2```/MLBZ`P```+X`````2(G?Z/[]__];7<-F9F:09F9FD&9F
-MD$%455-(B?L/MH<5`0``/`(/A;(```!$BY<8`0``0;P`````O0```"I!N0``
-M``"^`````+\`````0;@$````9I"Z`0```(G0B?'3X$&%PG48C4X&T^)!"=1!
-M"=&X%0```(GYT^`)Q>L)1(G`B?G3X`G%@\8!@\<%08/``X/^!77`1(G)NJ@#
-M``!`M@%(B=_H`````(GINL0#``"^`0```$B)W^@`````00^WS`N+&`$``+J@
-M`P``O@$```!(B=_H`````.FX````/`,/A;````!$BY<8`0``0;P`````O0``
-M`"I!N0````"^`````+\`````0;@$````N@$```")T(GQT^!!A<)U&(U.!M/B
-M00G400G1N!4```")^=/@"<7K"42)P(GYT^`)Q8/&`8/'!4&#P`.#_@1UP$2)
+M``^V0`@\_W1;#[;`#[:,!>X(``"`^?]T%4"`_O]T#P^V>R1`@/\&=65F9I!F
+MD(#Y_W0Q0(#^_W0K0`^VQDB-%$!(C1202,'B!4F)U$P#I4`)``!!QD0D2P)!
+MQD0D2O_IN@<``$B#>W@`=`Q(C7-X2(GOZ`````!(B=Y(B>_H`````.G'!P``
+M9F9FD&9FD$`/ML9(C11`2(T4D$C!X@5)B=1,`Z5`"0``00^WM"3(````9H'^
+MJPUW!D"`_P)U.DB#>W@`=`Q(C7-X2(GOZ`````!(B=Y(B>_H`````$'&1"1*
+M_T'&1"1+`DR)YDB)[^@`````Z58'``"Z`````$"`_R!U'DB+4U`/M@*#X'\\
+M<78)#[92`8/B#^L'#[92`H/B#T0/MNE+C42M`$F-1(4`3(VTQ<@!```/MD,X
+M/!H/A.8%```\&G<</!)T3CP5D`^$B08``(3`#X2.!0``9I#INP8``#PE#X0G
+M`P``/"60=Q,\&P^%I@8``&9FD&9FD.E<!0``/)X/A!0$```\H)`/A8H&``#I
+M6`8``$"$_V:0#X7-`@``2(M+2(![.0!FD'1F2(7)=$N`>0&`=46`>0(`=3\/
+MMD$#/#QW-P^VT$F-M"2$````N`````#&!#`@2(/``4B#^!1U\H/Z%`]#T$F-
+MO"2$````B=)(C7$$Z`````!F0<>$),@``````$'&1"1*&>D(!@``0<9$)$H8
+M]D$&0'41#[8!@^`?@_@-#X61`0``ZPL/M@&#X!^#^`UU"$'&1"1)#>L&0<9$
+M)$DB00^V="1)2,?'`````+@`````Z`````!(@WMX`'0,2(US>$B)[^@`````
+M2(G>2(GOZ`````!+C42M`$F-1(4`@+S%U@$````/A+4%``!!O@````!+C42M
+M`$F-1(4`2,'@`TR-I`4H`@``2(T<*$R-N\`!``!,B>?H`````$B+DS`"``!(
+MB8,P`@``3(D@2(E0"$B)`@^V0$D\(G0$/`UU"D&#Q@%%.'<6=\I+C42M`$F-
+M1(4`#[:$Q=8!``!$./`/A3T%``"$P`^$-04``$&\`````&;'1"0&``!!OP``
+M``!+C42M`$F-1(4`2,'@`TR-K`4H`@``2(T<*$R-L\`!``!,B>_H`````$B)
+MPDB+@S`"``!(B9,P`@``3(DJ2(E""$B)$`^V0DD\(G0$/`UU$P^W0CAF.T0D
+M!G((9HE$)`9)B==!@\0!13AF%G>T387_#X2L!```08!_2O\/A*$$``!!QD=*
+M_TR)_DB)[^@`````Z8P$``"#^`%U$4'&1"1)`4'&1"1*_^E&!```]D$%`6:0
+M=`AF08%,)&@`!$B+<TA(A?9T9DF-E"28````N`````#&!!``2(/``4B#^"AU
+M\DF-E"3`````L`#&!!``2(/``4B#^`AU\DF-C"28````2(U6"$B+1@A)B80D
+MF````$B+0@A(B4$(2(M"$$B)01"+1B!!B80DP````$&#O"20`0````^%N`,`
+M`$'&1"1*'.FM`P``C48!9D&)A"3(````OQ`G``#H`````$'&1"1*!>F,`P``
+M2(M+2$"$_P^%F0````^V40;!X@@/MD$%P>`0"<(/MD$'"<(/MD$$P>`8"<)!
+MB90DY`````^V$<'B&`^V00,)P@^V00+!X`@)P@^V00'!X!`)T(G"28E4)'A!
+M@[PDY`````!U'V9!@X0DR`````&_$"<``.@`````0<9$)$H;Z0D#``"#^/]U
+M$V9!@4PD:``$0<9$)$H;Z?$"``!!QD0D2@WIY@(``$"`_R!FD'4N@/H&=`6`
+M^@)U)(U&`69!B80DR````+\0)P``Z`````!!QD0D2@7ILP(``&9FD$B#>W@`
+M=`Q(C7-X2(GOZ`````!(B=Y(B>_H`````$R)XDR)]DB)[^@`````Z:\"``!,
+MBT-(0(3_#X7,````00^V4`K!X@A!#[9`"<'@$`G"00^V0`L)PD$/MD`(P>`8
+M"<)!B90DY````$$/MD@#2,'A($$/MD`"2,'@*$@)P4$/M@!(P>`X2`G!00^V
+M0`%(P>`P2`G!00^V4`;!X@A!#[9`!<'@$`G"00^V0`<)PD$/MD`$P>`8"<)(
+M"=%)B4PD>$'V0`P!=`=F08-,)&H$08.\).0`````=1]F08.$),@````!OQ`G
+M``#H`````$'&1"1*&^FX`0``9D&#3"1H`4'&1"1*#>FF`0``0(#_(&:0=2Z`
+M^@9T!8#Z`G4DC48!9D&)A"3(````OQ`G``#H`````$'&1"1*&^ES`0``9F:0
+M2(-[>`!T#$B-<WA(B>_H`````$B)WDB)[^@`````3(GB3(GV2(GOZ`````#I
+M;P$``$'&1"1*%.DT`0``0(#_('4N@/H&=`6`^@)U)(U&`69!B80DR````+\0
+M)P``Z`````!!QD0D2A3I`P$``&9FD$'&1"1*&^GU````0(3_9I!U;4B+0TAF
+M08-,)&@"9D&#3"1J`69!@4PD:(0`@'@#`'4%@#@6=Q]F08.$),@````!OQ`G
+M``#H`````$'&1"1*#>FJ````]D`&!'0)9D&#3"1J`NL'9D&#9"1J_4B+0WA)
+MB40D,$C'0W@`````ZSA`@/\@=2N`^@9T"(#Z`F9FD'4EC48!9D&)A"3(````
+MOQ`G``#H`````$'&1"1*!>M09D&#9"1H^4'&1"1*#NM!0(3_=0=F08-,)&H#
+M0<9$)$H/ZRU`A/]U"TB)WDB)[^@`````08.\))`!```!&<"#X!.#P`5!B$0D
+M2F9F9I!F9I!(@WMX`'0,2(US>$B)[^@`````2(G>2(GOZ`````!,B>9(B>_H
+M`````&9F9I!F9I!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H3(M\)#!(@\0X
+MPY"0D)"0D)"0D)"0D)"#X@?!X@B`SB!(BT<(2"WD/```2,'F"('F`/\``$@!
+M\(D0#[<`9HD%``````^VP,.#X@?!X@B(RH#.$$B+1PA(+>0\``!(P>8(@>8`
+M_P``2`'PB1##9F9FD&9F9I!F9I!54[T`````NP````!!N?____]!NP````!%
+MB=I!@\,!N`$```!!B<!$B=E!T^!$B<&^`````+C`X>0`N@````#W\3GX=Q&)
+M^BG"1#G*<PA$B=6)\T&)T8/&`40!P8/^$'7408/["'6QC03=``````GH#[;`
+M6UW#9F9FD&9FD&9FD$B#[!!(B1PD3(ED)`A)B?Q`#[;>N0````"Z!P```(G>
+MZ"O___]!#[:,)$$2``"Z`P```(G>3(GGZ!/___](BQPD3(MD)`A(@\00PV9F
+MD&:04XGS#[;RN@,```#HP/[__SC8#Y3`#[;`6\-F9I!F9I!(A?]T-[H`````
+M9F:09F:0#[:$.NH(```/ML@\_W03#[?!2(T$P$C!X`5(`X=H"0``PTB#P@%(
+M@_H$==2X`````,-F9F:09F9FD&9FD&9FD%532(N?``D``$B%VT@/1-^]````
+M`+D`````N@<```")[DB)W^AG_O__N40```"Z`@```(GN2(G?Z%/^__^YT```
+M`+H`````B>Y(B=_H/_[__[D`````N@0```")[DB)W^@K_O__@\4!@_T"=:B_
+MH(8!`.A)_O__B(-!$@``#[;(N@,```"^`````$B)W^C^_?__6UW#9F9FD&9F
+M9I!F9I!!5%532(G[#[:'%0$``#P"#X6R````1(N7&`$``$&\`````+T````J
+M0;D`````O@````"_`````$&X!````&:0N@$```")T(GQT^!!A<)U&(U.!M/B
+M00G400G1N!4```")^=/@"<7K"42)P(GYT^`)Q8/&`8/'!4&#P`.#_@5UP$2)
MR;JH`P``0+8!2(G?Z`````")Z;K$`P``O@$```!(B=_H`````$$/M\P+BQ@!
-M``#WT;J@`P``O@$```!(B=_H`````&9FD%M=05S#9F9FD&9F9I!F9I!(@^P(
-MB?&$TG06N/[____3P"&'&`$``.L49F9FD&9FD+@!````T^`)AQ@!``#H````
-M`$B#Q`C#9F:09F:09F:02(/L"`^W]L'F"(U.#T&X`0```+J:````O@$```#H
-M`````$B#Q`C#9F:09F:09F:02(/L"(GQA-)T%KC^____T\!F(8<``0``ZQ1F
-M9I!F9I"X`0```-/@9@F'``$```^WMP`!``#H`````$B#Q`C#D$B#["A(B1PD
-M2(EL)`A,B60D$$R);"083(ET)"!(B?U!B=8/MI[,````1`^V;@)(BWYP2(7_
-M=`P/MM)!#[;UZ`````!(B>_H`````(#[!W=(#[;#_R3%`````$&\^P```.LV
-M0;PS````ZRY!O#L```#K)D&\<P```.L>0;Q[````ZQ9!O+,```#K#D&\NP``
-M`.L&0;SS````1(GF2(GOZ`````!!#[;608UTG0!`#[;V2(GOZ`````!(BQPD
-M2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9F:09F:005154TF)_+L`
-M````0`^V[KH"````B>Y,B>?H@?K__Z@(=`VX`````.L@9F:09F:0OP$```#H
-M`````(/#`8'[$"<``'7+N/\```!;74%<PY!(@^PH2(E<)`A(B6PD$$R)9"08
-M3(EL)"!(B?U)B<U!B=1`#[;>B=[HA/___X7`=3!!#[;TB=I(B>_H0OO__X7`
-M=!ZZ`0```(G>2(GOZ/_Y__]!B$4`N`````#K"69F9I"X_____TB+7"0(2(ML
-M)!!,BV0D&$R+;"0@2(/$*,-FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)
-M_4&)S40/MN)`#[;>1(GAN@$```")WNC+^?__N4````"Z`@```(G>2(GOZ+?Y
-M__^)WDB)[^C=_O__A<!U3$6%[70T0?;$`705B=J^0````$B)[^B/^O__A<!T
-M+NLSB=J^&````$B)[^AZ^O__A<!T&>L>9F9FD(G:OB@```!(B>_H8?K__X7`
-M=0>X_P```.L&N`````"02(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9F9I!F
-M9I!!5T%6055!5%532(/L"$F)_4B)#"1%B<:)\XG5A-(/A/$```!$#[;^N60`
-M``"Z`@```$2)_NCV^/__1(G^3(GOZ!O^__^%P'40N@,```!$B?Y,B>_HI_C_
-M_T`/MM6Y`0```$2)_DR)[^C#_O__0;S_____A,`/A8,!``!!O`````!%A?8/
-MCG0!``!(BQPD0;P`````08UN_T0YY74UN4````"Z`@```$2)_DR)[^A^^/__
-M26/,2`,,)+I8````1(G^3(GOZ.?]__^%P'0UZ2P!``"Y1````+H"````1(G^
-M3(GOZ$GX__](B=FZ4````$2)_DR)[^BV_?__A<`/A?P```!!@\0!2(/#`44Y
-M]`^$ZP```.N#OZ"&`0#H0?C__P^VZP^VR+H#````B>Y,B>_H_/?__XGN3(GO
-MZ"+]__^%P'0B00^VC4$2``"Z`P```(GN3(GOZ-?W__]!O/_____IF@```(GJ
-MOF````!,B>_HO?C__X7`=`U!O`````!%A?9^9>L?00^VC4$2``"Z`P```(GN
-M3(GOZ)7W__]!O/_____K6TB+'"1!O`````!F9I"Y1````+H"````B>Y,B>_H
-M;/?__TB)V;J`````B>Y,B>_HVOS__X7`=0U!@\0!2(/#`44Y]'7)00^VC4$2
-M``"Z`P```(GN3(GOZ#+W__]$B>!(@\0(6UU!7$%=05Y!7\-(@^P82(E<)`A,
-MB60D$$F)_$B)T$`/MM9!B<A(B<&^`````.C(_?__B<.Y5````+H"````O@``
-M``!,B>?HW_;__XG82(M<)`A,BV0D$$B#Q!C#9F9FD&9F9I!F9I!F9I!(@^P8
-M2(E<)`A,B60D$$F)_$B)T$`/MM9!B<A(B<&^`0```.AH_?__B<.Y5````+H"
-M````O@$```!,B>?H?_;__XG82(M<)`A,BV0D$$B#Q!C#9F9FD&9F9I!F9I!F
-M9I!!5D%505154TF)_4B)S46)QHG31`^VYKED````N@(```!$B>;H-_;__T2)
-MYDR)[^A<^___A<!U$+H#````1(GF3(GOZ.CU__\/MM.Y`0```$2)YDR)[^@%
-M_/__A,!U-D6%]GXX2(GKO0````!F9F:0#[83N0````!$B>9,B>_HW?O__X3`
-M=0Z#Q0%(@\,!1#GU=`GKV[C_____ZP6X`````%M=05Q!74%>PV9FD&9FD$B#
-M[!A(B5PD"$R)9"0028G\2(G00`^VUD&)R$B)P;X!````Z"C___^)P[E4````
-MN@(```"^`0```$R)Y^AO]?__B=A(BUPD"$R+9"002(/$&,-F9F:09F9FD&9F
-MD&9FD$B#[`A(BX<`"0``2(7`2`]$QT"(-0````"Y(````$C'P@````"^#@``
-M`$B)Q^@`````2(/$",-F9I!F9I!F9I!(@^P(B?&$TG06N`$```#3X&8)AVP4
-M``#K%&9FD&9FD+C^____T\!F(8=L%```#[:W;!0``.@`````2(/$",.005=!
-M5D%505154TB#[%A(B?M)B?9(BTXH2(/!`HMV'(/N`<=$)%0`````28M&,$B)
-M1"0P28M&*`^V40&`^@%U$$''1E``````Z?,$``!F9I"`^@)U28!Y`@%U-DB+
-MAP`)``!(A<!(#T3'2(N0^`@```^V00.(@FX4```/MD$#B(+^*```0<=&4```
-M``#IKP0``$''1E#^____Z:($``!,C7@!@/H$#X7U`0``#[9!`X/H.SP!#X?F
-M`0``00^V;P)(BY_X"```0`^V]4B)W^@`````B<*$P'0-#[;`@+P#:`@``/]U
-M4$B+F_@(``!(@<.0%```2(N[^`@``.@`````B>HHP@^V\DB)W^@`````B<*$
-MP'0-#[;`@+P#:`@``/]U%$''1E#_____3(GW0?]62.DA!```#[;"#[:$`V@(
-M``"`^H%W9`^VR$AIR<@/``!!#[9W!$$/ME<%P>(000^V1P;!X`@)PD$/MD<'
-M"<*)5"0\00^V5PC!XA!!#[9'"<'@"`G"00^V1PH)PHE4)$!(B<U(`ZN0"0``
-M#X3I````@'U8`'49Z=X```!!QT90_____TR)]T'_5DCIF0,``$&\`````,9$
-M)$<`3(UM2(M$)#Q(B40D&$F-5PM(B50D$$`/MO:)="0,3(GOZ`````!(C5CP
-M2(M54$B)15!,B6L02(E3&$B)`@^V0TD\#70$/")U74$/MD<#/#MT(CP\=5!-
-MB?"+3"0\BU0D0(MT)`Q(B=_H`````,9$)$<!ZS)(B[LH`0``2(M4)!A(BW0D
-M$.@`````38GPBTPD/(M4)$"+="0,2(G?Z`````#&1"1'`4&#Q`%$.&58#X=J
-M____@'PD1P`/A<\"``!!QT90_____TR)]T'_5DCINP(``&9FD&:0@/H##X6<
-M````@'D"`69FD`^%@@````^V0SZ--``/MGD#B?J)^,'Z'_?^B=4YUGY;3(UI
-M!$0/MN(/ME$$1(GF2(G?Z`````"-1?R#^`-V&(U%](/X`W80C47L@_@#=@B-
-M1>2#^`-W!TB!PY`4``!!#[95`$2)YDB)W^@`````0<=&4`````#I%0(``$''
-M1E#^____Z0@"``!!QT90_O___^G[`0``@#D%=CF`>03^9I!U,4B-5"142(N[
-M^`@``$R)]N@`````A,`/A=(!``#'1"14`````$''1E#_____Z;T!``!,BZL`
-M"0``387M3`]$ZTB)R[@"````2"G(2(E$)"A(8_9(B70D(.GG````9I`/MBM,
-MC6(!#[;0]L(!=&F+3"14B>N-1`T`03M&(`^'3`$``$&`/P%U)XG)2`-,)#!!
-MB>B^`0```$R)[^BP]___.>AT*^DF`0``9F9FD&9FD(G)2`-,)#!!B>B^````
-M`$R)[^B)]___.>@/A0`!```!7"143(GCZVU(8\5*C1P@2(M$)"A(`=A(.T0D
-M(`^/W0```$&`/P%U'$&)Z$R)X;X!````3(GOZ!7Z__^%P'0@Z;L```!!B>A,
-MB>&^`````$R)[^CY^?__A<`/A:````"`.P!U!H![`0!T"[\0)P``D.@`````
-M2(U3`0^V0P&$P`^%"____P^V`X3`='L/MMBY5````+H"````O@````!,B>_H
-M"O#__XM4)%1!BT8@*=`YPP]'V$&`/P%U'HG12`-,)#!!B=BZ`````+X!````
-M3(GOZ*GV___K'(G12`-,)#!!B=BZ`````+X`````3(GOZ(OV__^%P'@&`40D
-M5.L(0<=&4/____^Y5````+H"````O@````!,B>_HDN___V:028M6.$B%TG0&
-MBT0D5(D"3(GW0?]62$B#Q%A;74%<05U!7D%?PV9F9I!F9F:09F:02(/L"$B+
-MAP`)``!(A<!(#T3'2(NX^`@```^VAV\4``"$P'0-@^@!B(=O%```A,!U'<8%
-M``````"Y(````$C'P@````"^#@```.@`````2(/$",-F9F:09F:09F:09F:0
-M2(/L"$B+AP`)``!(A<!(#T3'2(NX^`@``("_;A0```!U)("';Q0```'&!0``
-M```!N2````!(Q\(`````O@X```#H`````$B#Q`C#9F:09I!(@^P82(E<)`A,
-MB60D$$F)_$B)T$`/MM9!B<A(B<&^`````.@H^/__B<.Y5````+H"````O@``
-M``!,B>?H;^[__XG82(M<)`A,BV0D$$B#Q!C#D)"0D)"0D)"0D)"0D)")]DB+
-M1PA(+0`"`0!(`<:+!HD%`````,-F9F:09F9FD(GV2(M'"$@M``(!`$@!QHD6
-MPV9F9I!F9F:09F:09F:04TB)^TB+5PA(@>H``@$`QX*```$``````(N"!`$!
-M`(D%`````(#,`8F"!`$!`+H$````O@S"``#H`````+JX"P``O@C"``!(B=_H
-M`````+H!``P`O@#"``!(B=_H`````+H$````O@S#``!(B=_H`````+JX"P``
-MO@C#``!(B=_H`````+H!``P`O@##``!(B=_H`````$B+0PA(+;0!``!FQP``
-M`$B+0PA(+90!```/MP!FB04`````#[?`2(M3"$B!ZI0!``"#R`1FB0)(BT,(
-M2"V8`0``9L<`!`!FQX-L%```__];PV9F9I!F9F:02(M7"$B!Z@`"`0"+@FP`
-M`0")!0`````,R(F";``!`,-(BU<(2('J``(!`(N":``!`(D%`````"0W"?")
-M@F@``0##9F9FD&9F9I!F9I!F9I!32#F_^`@``'5HB?#`Z`)!NP````!$#[;0
-M26/:B?"#X`-$C0Q`N`<```!$B<G3X/?01(M$GU1!(<!$B42?5(32=`ZX!```
-M`-/@1`G`B42?5$ECPHM4AU1!#[;SP>8(@<90P@``2(N_^`@``.@`````6\.)
-M\,#H`H/H!$&[`0```.N39F9FD&9F9I!F9I!F9I!!5T%6055!5%532(/L"$B)
-M_4&)]D&)UT&)S4B+1PA,BR!,B>?H`````$B)PTB%P`^$ZP```$R)Y^@`````
-M2(G"2(7`#X37````QD5<`<9#..'&0SD!QD,Z$,9#);L/MD5;9HE#($R)8RC'
-M0S20````2(U"$$B)0TA(B5-X2(G!2(G"N`````#&!!``2(/``4@]D````'7P
-MQD$!@L8!0$2(<0)$B'D#1(AI!$&`_0)W(4B->0A*C12M`````('B_`,``$F-
-MM"2H$@``Z`````#K*TF+A"2H$@``2(E!"$B->1!!#[;5C125^/___TACTDF-
-MM"2P$@``Z`````!(QX.@`````````$B->UB^`````.@`````2(G>3(GGZ```
-M``!(@\0(6UU!7$%=05Y!7\.02(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET
-M)"A,B7PD,$B)_4&)]4&)UD&)STB+1PA,BR!,B>?H`````$B)PTB%P'1[3(GG
-MZ`````!(B<)(A<!T:\9%7`'&0SCAQD,Y`<9#.A#&0R6[#[9%6V:)0R!,B6,H
-MQT,TD````$B-0A!(B4-(2(E3>,9``0+&0A!`1(AH`D2(<`-$B'@$2,>#H```
-M``````!(C7M8O@````#H`````$B)WDR)Y^@`````2(M<)`A(BVPD$$R+9"08
-M3(ML)"!,BW0D*$R+?"0P2(/$.,-F9F:09F:09F:09F:0059!54%455-(B?M!
-MB?5!B=9(BT<(2(LHN0(```"Z`````+X`````Z`````"`>UP`=!A(B>_H````
-M`+\!````Z`````"`>UP`=>A(BT,(2(L`2`6H$@``@'@"`'@[@$@"@+D!````
-MN@````"^`````$B)W^@`````@'M<`'0:9I!(B>_H`````+\!````Z`````"`
-M>UP`=>A$B>C`Z`)$#[;@N0$```!$B>*^`P```$B)W^@`````@'M<`'0;9F:0
-M2(GOZ`````"_`0```.@`````@'M<`'7H2(M#"$B+,$2)Z??1@^$#183V#Y7"
-MP>(##[:$#J@2``"#X.<)T(B$#J@2``"Y`0```$2)XKX#````2(G?Z`````!;
-M74%<05U!7L-F9F:09F9FD&9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD
-M($B)^TB)]0^W1B!F/84`=QM,BZ^0"0``#[?`#[:$!V@(``!,:>#(#P``ZPU,
-MBZ^0"0``0;PXN`\`2(M52(!Z`0)U%DB+0@1(B8.H$@``2(M"#$B)@[`2``!(
-MBW5X2(7V=`A(B=_H`````$B)[DB)W^@`````0\9$)5P`2(M<)`A(BVPD$$R+
-M9"083(ML)"!(@\0HPY"0D)"028G13(N70`D```^W1B"Z8)X!`&8]A0!W%P^W
-MP`^VA`=H"```2(T40$B-%)!(P>(%38V!(`0``$'&@2`$```G9H%^..$!=2E$
-M#[9..D&-0?\\`7<,0;D/````1")..^LN08U![T&Y#P```#P!=B!FD$F-!!)!
-MN0````!(@WA@`'0-0;D/````1"*(@0```$$/MD`!@^#P1`G(08A``;@!````
-M9H%^..$!=18/MD8Z@^@!/`$/E\`/ML!F9F:09F:0B<+!X@=!#[9``8/@?PG0
-M08A``0^V009!B$`"#[8!08A``P^V005!B$`'#[9!!T&(0`\/MD$"08A`!`^V
-M00-!B$`%#[9!!$&(0`8/MD$!08A`#`^V00I!B$`(#[9!"T&(0`D/MD$,08A`
-M"@^V00A!B$`+#[9!"4&(0`W#9F:09I!`#[;'PV9F9I!F9F:09F:0B?@/ML3#
-M9F9FD&9FD&9FD,9')`)(BT=00(AP`DB+1U#&0`<`2(M'4(A0#,-F9F:0#[9'
-M/8A&`@^V1SR(1@,/MD<[B$8$#[9'.HA&"L-F9I`/MD=!B$8"#[9'0(A&`P^V
-M1S^(1@0/MD<^B$8*#[9'/8A&"P^V1SR(1@S#9F:09I"%TGXAN0````!F9F:0
-M9F:0B=`IR(/X`@^=P`^VP(U,`0$YRG_K\\-F9I!F9I!F9I!(@^PH2(D<)$B)
-M;"0(3(ED)!!,B6PD&$R)="0@2(G[2(G508GV#[9'.#PJ="4\*G<1/"@/A=T`
-M``!F9F:09F:0ZQ`\B'0J/(H/A<@```!FD.L>1`^V8T!$#[9K/TB)[DB)W^@`
-M````ZQQF9F:09F:01`^V8T5$#[9K1$B)[DB)W^@`````QD4%0(N#E````*D`
-M``$`=#!$B&4`1(AM"$*-!/4`````B$4!#[9#.#PH=`0\B'4+QD4&8.M;9F:0
-M9I#&109AZU"I```$`&9FD&:0="!$B&4!1(AM"0^V0S@\*'0$/(AU!L9%!B7K
-M*L9%!C7K)$2(90$/MD,Z@^`/"$4%#[9#.#PH=`0\B'4&QD4&R.L$QD4&RDB+
-M'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9FD&9FD&9FD&9FD`^V1SH*
-M1SL*1SP*1ST/ML`/ME=`@^(!"=!T%;HD````O@4```#H`````//#9F9FD,9&
-M!NQ(QX>@`````````,-(@^P@2(D<)$B);"0(3(ED)!!,B6PD&$B)^TB)]0^V
-M1S@\+W0+/(]U6>L79F:09I!$#[9G0$0/MF\_Z`````"0ZP]$#[9G140/MF]$
-MZ`````#&105`]H.6````!'021(AE`42(;0G&109"ZQ9F9F:01(AE`0^V0SJ#
-MX`\(107&109`2(L<)$B+;"0(3(MD)!!,BVPD&$B#Q"##9F:09F:02(GQQD(%
-M0`^V1C@\-70&/)%U(^L;#[=':(/@`8/X`1G`@^#]@^@6B$(&ZR1F9F:0QD(&
-MZNL:NB0```"^!0```$B)S^@`````\\-F9I!F9I#V03D"=`3&020`\\-F9F:0
-M]D<\\'0/NB0```"^!0```.@`````\\-F9I!F9I!F9I!(@^P(28GPN`````!F
-M9F:0Q@0(`$B#P`%(@_@-=?)!#[9`.#PU#X2=````/#5W*3PH=&(\*'<./!L/
-MA:$#``"0Z9L````\*G1,/"]F9I!FD`^%B@,``.M8/(]F9I!F9I!T3CR/=Q(\
-MB'0K/(IF9F:0#X5J`P``ZQT\D69FD&9FD'1&/.$/A58#``!F9I!F9I#IA```
-M``^V\DB)RDR)Q^@`````QT0D!`$```#I.`,``$B)SDR)Q^@`````QT0D!`$`
-M``#I(`,``$B)RDR)QN@`````QT0D!`$```#I"`,``$'V0#P!="'&009PQD$$
-M`,9!`P#&00(`QD$%0,=$)`0!````Z>`"``#&00;@QT0D!`$```#ISP(``$&`
-M>#D!#X6\`@``08!X.AP/A[$"``!!#[9`.O\DQ0````#&00<$QT0D!`$```#I
-MG`(``,9!!P#'1"0$`0```.F+`@``QD$&[,=$)`0!````Z7H"``#&00;OQ@$#
-M00^V0#N#R$"(00''1"0$`0```.E;`@``QD$&[\8!!\=$)`0!````Z4<"``#&
-M009`QD$!`<9!!4#'1"0$`0```.DN`@``QD$&[\8!`T$/MD`[@\@(B$$!QT0D
-M!`$```#I#P(``,9!!N_&`0+'1"0$`0```.G[`0``QD$&[\8!@L=$)`0!````
-MZ><!``#&00;OQ@$&QT0D!`$```#ITP$``,9!!N_&`8;'1"0$`0```.F_`0``
-MQD$&XT$/MD`[B$$!QT0D!`$```#II@$``,9!!K#&`=C&00-/QD$$PL=$)`0!
-M````Z8H!``#&00:PQ@'9QD$#3\9!!,+'1"0$`0```.EN`0``QD$&L,8!VL9!
-M`T_&003"QT0D!`$```#I4@$``/9':`%T$<9!!NK'1"0$`0```.D[`0``QD$&
-MY\=$)`0!````Z2H!``#&00;OQ@&JQT0D!`$```#I%@$``,9!!N_&`57'1"0$
-M`0```.D"`0``QD$&+\9!`0'&00(0QT0D!`$```#IZ0```,9!!N1!#[9`/(@!
-M00^V0#V(00A!#[9`.XA!!<=$)`0!````Z<$```!!#[9`.XA!!D$/MD`\B`%!
-M#[9`/8A!`D$/MD`^B$$#00^V0#^(001!#[9`08A!"D$/MD!`B$$!QT0D!`$`
-M``#I?0```,9!!NA!#[9`/(@!00^V0#V(00A!#[9`.XA!!4$/MD`^B$$"00^V
-M0#^(00-!#[9`0(A!!$$/MD!!B$$!QT0D!`$```#K.,=$)`0!````0?9`/`%T
-M*<9!!G#&000`QD$#`,9!`@#&005`QT0D!`$```#K"V9FD,=$)`0`````BT0D
-M!$B#Q`C#9F9FD&9F9I!F9F:09F:04TB#["!(B?-(BTY(2,<$)`````!(QT0D
-M"`````!(QT0D$`````!(QT0D&`````#V@:<````$=`U(BY'(````2(/J`>L&
-MBU%X@^H!@'LX)75A2(G02,'H&(@$)$B)T$C!Z!"(1"0!2(G02,'H"(A$)`*(
-M5"0#]H'5````$'44QD0D!@+&1"0'`+@(````Z:X```!(C7PD!$B-L>H```"Z
-M!````.@`````N`@```#IC@```$B)T$C!Z#B(!"1(B=!(P>@PB$0D`4B)T$C!
-MZ"B(1"0"2(G02,'H((A$)`-(B=!(P>@8B$0D!$B)T$C!Z!"(1"0%2(G02,'H
-M"(A$)`:(5"0']H'5````$'45QD0D"@+&1"0+`+@@````ZR1F9F:02(U\)`A(
-MC;'J````N@0```#H`````+@@````9F:09I!(BWM(2&/02(GFZ`````!(@\0@
-M6\-F9F:09F9FD&9FD%-(B?-(BU=02(L*#[9&.#PO=%\\+W<K/!L/A#$!```\
-M&W<//!(/A44!``!F9I!FD.M`/"AT/#PJ#X4R`0``9I#K,#R*="P\BG<8/#5F
-M9F:0#X3Z````/(@/A1(!``!FD.L0/(]T##SA#X4"`0``9I#K=?9':`%T"H&+
-ME```````!`#V1VH0#X04`0``2(-_8``/A0D!```/MD,X/"AT$#PJ=`P\B'0(
-M/(H/A?$```#V0@P!=10/MG((2(G/Z`````"$P`^$UP```(![)($/A,T```"!
-MBY0```````$`N`$```#IO@```(!^.0$/A:0```"`?CH<#X>:````2`^^3CJX
-M`0```$C3X*GV/\`==2.I"$`&`'4,J0``(`!U(V9FD.MS@XZ4````"+@!````
-M9I#K<X..E`````&X`0```.ME@XZ4````(+@!````ZU=FD/9':`%T"H&+E```
-M````!`"#BY0````!N`$```#K-V:0BX.4````J0``(`!T&/9':`%T'0T```0`
-MB8.4````N`$```#K$+@`````ZPEF9F:0N`$```!;PY"0D)"0D)"0D$B+?PA%
-M#[;`0<'@!`^VTL'B"$$)T$2)P(/(!(3)1`]%P$&#^?]T&4B-EP#^_O]$B<@E
-M__\#`(F"!,@``$&#R`)$B0;#9F9FD&9F9I!F9F:02(M'"$@M``(!`(/.`8FP
-M`,@``,-F9F:09F9FD&9F9I!!5%5308GT2(M'"(7V=$Q(+0`"`0!(C:@`R```
-MBX``R```B04`````NP````"H`74/ZR&+10")!0````"H`704OPH```#H````
-M`(/#`40YXW7AZP>X`````.L%N/____];74%<PV9F9I!F9F:09F:055-(@^P8
-M2(G[QT0D%`````!(BV\(QH=P%`````^V%0````!(C70D%$&Y`````$&X`@``
-M`+D!````Z.+^__^+="042(G?Z";___^^H(8!`$B)W^@Y____A<!U54B-A0#^
-M_O^+@`S(``")!0````")1"04/1]C``!U-\>#8!0``!]C``#'@V04``````0`
-MQX-H%``````!`$C'@W@4````````9K@``.E7`@``9F:09I#'1"04`````$B+
-M:PC&@W`4```!#[85`````$B-="040;G_____0;@"````N0$```!(B=_H./[_
-M_XMT)!1(B=_H?/[__[X0)P``2(G?Z(_^__^%P'5N2(V%`/[^_XN`#,@``(D%
-M`````(E$)!0]'T,``'0M/1]$``!U2<>#8!0``!]$``#'@V04``````<`QX-H
-M%``````!`.F3`0``9F:0QX-@%```'T,``,>#9!0`````!`#'@V@4``````$`
-MZ6T!``#'1"04`````$B+:PC&@W`4````#[85`````$B-="040;D`````0;@"
-M````N0$```!(B=_H=?W__XMT)!1(B=_HN?W__[X0)P``2(G?Z,S]__^%P'50
-M2(V%`/[^_XN`#,@``(D%`````(E$)!0]OT,``'4RQX-@%```OT,``,>#9!0`
-M````(`#'@V@4````$```2,>#>!0```````!FN```Z>H```#'1"04`````$B+
-M:PC&@W`4````#[85`````$B-="040;D`````0;@"````N0$```!(B=_HT/S_
-M_XMT)!1(B=_H%/W__[X0)P``2(G?Z"?]__^%P'5G2(V%`/[^_XN`#,@``(D%
-M`````(E$)!0][Q$``'0)/>\2``!U0NL@QX-@%```[Q$``,>#9!0`````!`#'
-M@V@4``````$`ZS['@V`4``#O$@``QX-D%``````(`,>#:!0``````0#K'KC_
-M____ZR=F9I!FD$C'@W@4````````N`````#K$$C'@W@4````````N`````!(
-M@\086UW#9F9FD&9FD$B#["A(B5PD$$B);"083(ED)"!(B?N)]TF)U$B+:PB`
-M^02X!`````]'R$B+@W@4```/ME`$2(UT)`Q!B?E$#[;!N0$```!(B=_HPOO_
-M_XMT)`Q(B=_H!OS__[X0)P``2(G?Z!G\__^Z_____X7`=2!(C84`_O[_BX`,
-MR```B04`````B40D#$&)!"2Z`````(G02(M<)!!(BVPD&$R+9"0@2(/$*,-F
-M9F:09F:09F:055-(@^P82(G[2(G52(N'>!0```^V4`M(C40D%$&)\4&X`0``
-M`+D!````2(G&Z"[[__^+="042(G?Z'+[__^^$"<``$B)W^B%^___NO____^%
-MP'4:2(M#"$@M]#D``(L`B04`````B$4`N@````")T$B#Q!A;7<-F9I!F9I!F
-M9I!!5T%6055!5%532(/L&$B)^T&)S4&)]T&)UH7)#X2.````O0````!,BV,(
-M2(N#>!0```^V4`)!N?____]!N`$```"Y`0```$B-="042(G?Z(SZ__^+="04
-M2(G?Z-#Z__^^$"<``$B)W^CC^O__A<!U*4F-A"0`_O[_BY`,R```B14`````
-M1(GX(=!$./!U![@`````ZQ^)5"04OPH```#H`````(/%`40Y[0^%=____[C_
-M____2(/$&%M=05Q!74%>05_#9F9FD&9F9I!F9F:04TB#[!!(B?M(BX=X%```
-M#[802(UT)`Q!N?____]!N`````"Y`````.CC^?__BW0D#$B)W^@G^O__OA`G
-M``!(B=_H.OK__X7`=2:YX),$`+H"````O@,```!(B=_HS_[__[H`````A<!T
-M"V9FD&9FD+K_____B=!(@\006\-F9I!(@^PH2(E<)!A(B6PD($B)^XGUQD0D
-M%_](C50D%^@`````A<!U<H!\)!<`='-(B=_H2____X/X_W1>2(N#>!0```^V
-M4`I(C70D$$&)Z4&X`````+D`````2(G?Z##Y__^+="002(G?Z'3Y__^^$"<`
-M`$B)W^B'^?__A<!U&[G@DP0`N@````"^`P```$B)W^@<_O__A<!T"+C_____
-MZP:0N`````!(BUPD&$B+;"0@2(/$*,-F9F:09F9FD&9F9I!(@^Q82(E<)"A(
-MB6PD,$R)9"0X3(EL)$!,B70D2$R)?"102(G]08GVB<M(@[]X%`````^$^`(`
-M`$F)UT6$P`^$7`$``(/^_W47#[>'8!0``&:)`K@!````Z?D"``!F9I"#_OYU
-M$HN'9!0``(D"N`$```#IWP(``(/^_744BX=H%```B0*X`0```.G(`@``9I`!
-M\XE<)`P[GV04```/AXX"``")\X/C_$&)]$&#Y`-T8DR-;"0DN00```!,B>J)
-MWNC\^___@\,$N@0````Y7"0,<PU$B>!$*?"+3"0,C10(1#GB=BY$B>%,B?]F
-M9I!F9I")R$$/MD0%`(@'2(/'`8/!`3G1=>N)T$0IX(/H`4V-?`<!1(MD)`Q!
-M@^3\1#GC<RI,C6PD)+D$````3(GJB=Y(B>_HB?O__XM$)"1!B0=)@\<$@\,$
-M03G<=]LY7"0,#X;C`0``3(UD)"2Y!````$R)XHG>2(GOZ%7[__^+="0,*=X/
-MA,`!``"Y`````+H`````00^V!!1"B`0Z@\$!2(/"`3GQ#X2>`0``Z^9F9I!F
-MD(/^_W4K@#H/=1'&AW$4```!N`$```#IFP$``,:'<10```"X`0```.F*`0``
-M9F9FD(E,)!2)R`'P.X=D%```#X=,`0``@+]Q%`````^$/P$``(GPN@````#W
-MMV@4``"%T@^%C0```("_<!0```!T#>@`````A<`/A10!``!(B>_HG/S__X/X
-M_P^$`P$``$B+A7@4```/ME`&2(UT)"1%B?%!N`````"Y`````$B)[^A]]O__
-MBW0D)$B)[^C!]O__OA`G``!(B>_HU/;__X7`#X6\````N>"3!`"Z`````+X#
-M````2(GOZ&7[__^%P`^%G0```(7;#X2<````QT0D$`````"+1"0018LD!T2+
-M;"0010'U2(M="$B!ZP`"`0!(B>_H^OO__T2)HPC(``!(BX5X%```#[90!46)
-MZ4&X!````+D`````2(UT)"1(B>_HW?7__XMT)"1(B>_H(?;__[X0)P``2(GO
-MZ#3V__^%P'4@N8@3``"Z`````+X!````2(GOZ,GZ__^%P'079F:09I"X````
-M`.L?N`$```!F9F:0ZQ2#1"00!(M$)!`Y1"04=N;I3?___TB+7"0H2(ML)#!,
-MBV0D.$R+;"1`3(MT)$A,BWPD4$B#Q%C#D)"0D)"0D+@`````PV9F9I!F9I!F
-M9I"X`````#D]`````'XW2&/'2,?!`````$B-!$!(P>`##[<4"&:)%@^W5`@"
-M9HE6`@^V5`@(B%8(#[9$"`F(1@FX`0```//#9F9FD&9FD&9FD+@@*P``PV9F
-M9I!F9I!F9I"XT````,-F9F:09F:09F:0N`@```##9F9FD&9FD&9FD+X`````
-M0;@`````N0`````/MI0YZ`@``(#Z_W1*C8&`````9CV!`'<'@\8!ZSEFD`^V
-MPDB+EV@)``!(C03`2,'@!8"\$!4!```#=1A!@\`!08U``X/X!G8.@\8!0;@`
-M````ZP.#Q@%(@\$!2(/Y!G6?B?##9F9FD&9F9I!F9F:02(GY0;H`````0;L`
-M````0;F`````0`^V]H/&`69F9I!%B<@/MH'H"```//]T4&9!@?F!`'<*08/"
-M`>L]9F9FD`^VP$B+EV@)``!(C03`2,'@!8"\$!4!```#=1E!@\,!08U#`X/X
-M!G8008/"`4&[`````.L$08/"`40YUG072(/!`4&#P0%!@?F&````=9%!N```
-M``!$B<##9F9FD&9FD//#9F9FD&9F9I!F9I!F9I#&A\L`````PV9F9I!F9F:0
-MN/\```!(A?]T1+[_____N0`````/MH0YZ@@``#S_="`/ML!(BY=H"0``2(T$
-MP$C!X`4/MH00%`$``$`XQ@]'\$B#P0%(@_D$=<I`#[;&\\.X`````,-F9F:0
-M9F:09F:02(NW^`@``+\`````0;@`````N0`````/MI0QZ`@``(#Z_W1/C8&`
-M````9CV!`'<%@\<!ZSX/ML)(BY9H"0``2(T$P$C!X`6`O!`5`0```W4?08/`
-M`4&-0`.#^`9V%8/'`4&X`````.L*9F9FD&9FD(/'`4B#P0%(@_D&=9I(B[;X
-M"```2('&D!0``+$`9F:0#[:4,>@(``"`^O]T2HV!@````&8]@0!W!X/'`>LY
-M9I`/ML)(BY9H"0``2(T$P$C!X`6`O!`5`0```W4808/``4&-0`.#^`9V#H/'
-M`4&X`````.L#@\<!2(/!`4B#^09UGXGXPV9F9I!F9F:09F9FD(GPP.@$C4A7
-MC5`P/`H/0]&(%XGP@^`/@_@)?@J)\(/@#X/`5^L(B?"#X`^#P#"(1P'#9F9F
-MD&9F9I!F9I!F9I!(@^P02(D<)$R)9"0(2(G[08GT3(G@#[;TZ*+___]!#[;T
-M2(/#`DB)W^B2____2(L<)$R+9"0(2(/$$,-F9F:0QT($`````,<"`````+@`
-M````PV9F9I!F9I!F9I!F9I!(BT=@2(7`=%%(QT!``````(!(3`1(QT=@````
-M`$C'1W``````2,=':`````"+1PB#^#]_$TB+5WA(F$C'A,)H!````````,-(
-MBU=X2)A(QX3":`(```````#SPV9F9I!(BT=@2(7`=%%(QT!``````(!@3/M(
-MQT=@`````$C'1W``````2,=':`````"+1PB#^#]_$TB+5WA(F$C'A,)H!```
-M`````,-(BU=X2)A(QX3":`(```````#SPV9F9I!(@^P(2,?'`````.@`````
-MN`````!(@\0(PV9FD&9FD%532(/L.,8$)&W&1"0!_\9$)`(CQD0D`Q3&1"0$
-M.L9$)`7OQD0D!A;&1"0'DDB+KP`)``!(A>U(#T3O2(U$)!!(B<+&``!(@\`!
-M2(G32(U,)#!(.<AU[,9$)!0!N2````"^#@```$B)[^@`````A<!U0K^`&@8`
-MZ`````"Y(````$B)VKX/````2(GOZ`````"#^"!U'DB-<Q!(B>>Y"````/SS
-MI@^7P@^2P+D!````.,)T%DC'QP````"X`````.@`````N0`````/ML%(@\0X
-M6UW#9F9FD&9F9I!F9F:005=!5D%505154TB#[&A)B?Q,B[_X"```28''D!0`
-M`$B+!TB%P'032(VP``#^_TB)-TB+?R#H`````$F+="002(7V=`I)BWPD(.@`
-M````28MT)!A(A?9T"DF+?"0@Z`````!(C4PD94B-5"1F2(UT)&=!#[=\)#Q(
-MC40D6DB)1"0X2(U$)%Q(B40D,$B-1"162(E$)"A(C40D6$B)1"0@2(U$)&!(
-MB40D&$B-1"1B2(E$)!!(C40D8TB)1"0(2(U$)%Y(B00D3(U,)&1,C40D5.@`
-M````28NT)$`)``!(A?9T($F-O"0@"0``Z`````!)B[=`"0``28V_(`D``.@`
-M````28NT)&@)``!(A?9T($F-O"1("0``Z`````!)B[=H"0``28V_2`D``.@`
-M````28NT))`)``!(A?9T($F-O"1P"0``Z`````!)B[>0"0``28V_<`D``.@`
-M````28NT)#`+``!(A?9T($F-O"00"P``Z`````!)B[<P"P``28V_$`L``.@`
-M````@'PD9P!T1+T`````38VT)&`+``!-C:]@"P``#[?=28NTW(`+``!,B??H
-M`````$F+M-^`"P``3(GOZ`````"#Q0$/MD0D9V8YZ'?028NT)!`0``!(A?9T
-M($F-O"3P#P``Z`````!)B[<0$```28V_\`\``.@`````28NT)$@0``!(A?9T
-M($F-O"0H$```Z`````!)B[=($```28V_*!```.@`````28NT)+@0``!(A?9T
-M($F-O"28$```Z`````!)B[>X$```28V_F!```.@`````28NT)+@)``!(A?9T
-M($F-O"28"0``Z`````!)B[>X"0``28V_F`D``.@`````28NT))`*``!(A?9T
-M($F-O"1P"@``Z`````!)B[>0"@``28V_<`H``.@`````28NT)"`*``!(A?9T
-M($F-O"0`"@``Z`````!)B[<@"@``28V_``H``.@`````28NT)$@*``!(A?9T
-M($F-O"0H"@``Z`````!)B[=("@``28V_*`H``.@`````28NT).`*``!(A?9T
-M($F-O"3`"@``Z`````!)B[?@"@``28V_P`H``.@`````28NT)`@+``!(A?9T
-M($F-O"3H"@``Z`````!)B[<("P``28V_Z`H``.@`````28NT)%@+``!(A?9T
-M($F-O"0X"P``Z`````!)B[=8"P``28V_.`L``.@`````28NT)*`/``!(A?9T
-M($F-O"2`#P``Z`````!)B[>@#P``28V_@`\``.@`````28NT)-@/``!(A?9T
-M($F-O"2X#P``Z`````!)B[?8#P``28V_N`\``.@`````28NT)(`0``!(A?9T
-M($F-O"1@$```Z`````!)B[>`$```28V_8!```.@`````28NT)+@*``!(A?9T
-M($F-O"28"@``Z`````!)B[>X"@``28V_F`H``.@`````28NT).`0``!(A?9T
-M+TF+E"3H$```28V\),`0``#H`````$F+E^@0``!)B[?@$```28V_P!```.@`
-M````28NT)!`1``!(A?9T+TF+E"08$0``28V\)/`0``#H`````$F+EQ@1``!)
-MB[<0$0``28V_\!```.@`````28NT)$`1``!(A?9T+TF+E"1($0``28V\)"`1
-M``#H`````$F+ET@1``!)B[=`$0``28V_(!$``.@`````28NT)*`1``!(A?9T
-M+TF+E"2H$0``28V\)(`1``#H`````$F+EZ@1``!)B[>@$0``28V_@!$``.@`
-M````28NT)'`1``!(A?9T+TF+E"1X$0``28V\)%`1``#H`````$F+EW@1``!)
-MB[=P$0``28V_4!$``.@`````28NT)-`1``!(A?9T+TF+E"38$0``28V\)+`1
-M``#H`````$F+E]@1``!)B[?0$0``28V_L!$``.@`````28NT)``2``!(A?9T
-M+TF+E"0($@``28V\).`1``#H`````$F+EP@2``!)B[<`$@``28V_X!$``.@`
-M````28NT)#`2``!(A?9T+TF+E"0X$@``28V\)!`2``#H`````$F+ES@2``!)
-MB[<P$@``28V_$!(``.@`````2(/$:%M=05Q!74%>05_#9F9FD&9FD$B#[!A(
-MB5PD"$R)9"002(G[Z`````!(B=_H`````$R-HY`4``!,B>?H`````$B)W^@`
-M````O]`'``#H`````$B)W^@`````O@$```!(B=_H`````+X!````3(GGZ```
-M``!(BUPD"$R+9"002(/$&,-(@^P82(E<)`A,B60D$$F)_$&(="1/0`^VWHG>
-MZ`````!)@<20%```B=Y,B>?H`````+@!````2(M<)`A,BV0D$$B#Q!C#9F9F
-MD&9FD&9FD%-(B?OH`````$B+N_@(``!(@<>0%```Z`````!;PV:04TB)^^@`
-M````2(N[^`@``$B!QY`4``#H`````%O#9I!(@^P(Z``````/ML!(@\0(PV9F
-M9I!F9F:09F9FD&9FD$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\
-M)#!(B?M!B?1!B=5(BV]@3(MW>$B%[0^$&P$``("_RP`````/A0X!``!,B??H
-M`````$F)QTB%P`^$^@```,9`..'&0#D!183D=`U!@/T!&<#WT(/`!^L+08#]
-M`1G`]]"#P`U!B$<Z0<9')(`/MT4X9D&)1R!)B5\H0<='-`````!)QT=(````
-M`$G'AZ``````````3(G^3(GWZ`````#&@\L````!9L>#R````/0!2(7;=$Y(
-MBU-@2(72=$]F@;O(````E@!U#DB+>E"^(0```.@`````9H.KR`````&_T`<`
-M`.@`````3(GWZ`````!(BU-@2(72=`F`N\L`````=;MF@[O(`````'0:08!_
-M)`!U$TB+0V`/MT!J9HE#6KL`````ZP6[_____TR)_DR)]^@`````ZP6[____
-M_XG82(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$.,-F9F:09F9F
-MD&9F9I!F9I!(@^Q(2(E<)!A(B6PD($R)9"0H3(EL)#!,B70D.$R)?"1`2(G]
-M08GU3(MG8$R+=WA-A>0/A'D$``"`O\L`````#X5L!```3(GWZ`````!)B<=(
-MA<`/A%@$``#V10`"#X7\````08#]%'<,00^VQ8T$0,'@`NL7N(G___]!]N5F
-MP>@(P.@$#[;`!?````!!QD<XX4'&1SD!0<9'.AQ!B$<[0<9')(!!#[=$)#AF
-M08E'($F);RA!QT<T`````$G'1T@`````2<>'H`````````!,B?Y,B??H````
-M`,:%RP````%FQX7(````Q`E(A>UT3DB+56!(A=)T4V:!O<@```"6`'4.2(MZ
-M4+XA````Z`````!F@ZW(`````;_0!P``Z`````!,B??H`````$B+56!(A=)T
-M"8"]RP````!UNV:#O<@`````#X15`P``NP````!!@'\D``^$2@,``.E``P``
-M3(GWZ`````!(B40D$$B%P`^$*@,``$F-7UA(BT`02(D$)$'&1S@:0<9'.0A!
-MQD<Z&D'&1SL`0<9'/!!!QD<]`$B+1"0028E'>$'&1R2`00^W1"0X9D&)1R!)
-MB6\H2(M$)!!(BT`028E'2$''1S00````2(M%8$@%[````$F)1U!!QD<P($G'
-MAZ``````````O@````!(B=_H`````$&+5S1(BT0D$$B+<!A(B=_H`````$R)
-M_DR)]^@`````QH7+`````6;'A<@```#Z`$B%[71.2(M58$B%TG1/9H&]R```
-M`)8`=0Y(BWI0OB$```#H`````&:#K<@````!O]`'``#H`````$R)]^@`````
-M2(M58$B%TG0)@+W+`````'6[9H.]R`````!T!T&`?R0`=!=(C70D$$R)]^@`
-M````N______I_0$``$R)_DR)]^@`````3(GWZ`````!)B<=(A<!U'4B-="00
-M3(GWZ`````"[_____^G=`0``9F:09F:02(U86$B+/"1(@\<$2(L4)`^V0@,/
-MM@0'B$($QD<!"L9'`@"X`````$B+%"3&!!``2(/``4B#^`1U[D6$[74&@&<#
-M_.M!00^VU6G28.H``+@?A>M1]^K!^@6`3P,#B='!Z1B(3P2)UL'N$$"(=P6)
-MT,'H"(A'!HA7!XA/"$"(=PF(1PJ(5PM(BT0D$$F)1WA!QD<X%0^V!\#X!_?0
-M@\`108A'.4'&1SH`0<9'.P!!QD<\$$'&1ST`@"<_0<9')(!!#[=$)#AF08E'
-M($F);RA(BT0D$$B+0!!)B4=(0<='-!````!(BT5@2`7L````28E'4$'&1S`@
-M2<>'H`````````"^`````$B)W^@`````08M7-$B+1"002(MP&$B)W^@`````
-M3(G^3(GWZ`````#&A<L````!9L>%R````/H`2(7M=$Y(BU5@2(72=$]F@;W(
-M````E@!U#DB+>E"^(0```.@`````9H.MR`````&_T`<``.@`````3(GWZ```
-M``!(BU5@2(72=`F`O<L`````=;MF@[W(`````'0,NP````!!@'\D`'0%N___
-M__](C70D$$R)]^@`````ZPIF9I!FD+O_____3(G^3(GWZ`````#K!;O_____
-MB=A(BUPD&$B+;"0@3(MD)"A,BVPD,$R+="0X3(M\)$!(@\1(PV9F9I!(@^QH
-M2(E<)#A(B6PD0$R)9"1(3(EL)%!,B70D6$R)?"1@2(G]2(GS28G/08G518G&
-M3(MG8$V%Y`^$M@,``("_RP`````/A:D#``!)BT0D4$B)1"0P2(M7>$B)5"0(
-M9L>'R````!`G2(G7Z`````!(B40D*$B%P`^$=P,``$$/M\6)1"0$9D&#_01V
-M%8G&2,?'`````+@`````Z`````#K%$B+?"0(Z`````!(B40D$$B%P'492(MT
-M)"A(BWPD".@`````N______I0@,``(M4)`3!X@F)5"0D2(M$)`A(B[#X"```
-MQD8_`4B)ZK\%````Z`````!!@$PD3`)(BU5@OB$```!(BWPD,.@`````2(M4
-M)"A(@\)82(E4)!A%A/9T%4B+1"0HQX"4````"@```,9`."CK*$B+5"0HQX*4
-M````$@```,9"."I(BT0D$$B+>!"+5"0D3(G^Z`````!(BT5@]D!H`0^$@0``
-M`$&`_@$9P(/@`H/H>$B+5"0HB$(XQD(Y`$B)V$C!Z#B(0CI(B=A(P>@PB$([
-M2(G82,'H*(A"/$B)V$C!Z""(0CU(B=A(P>@8B$(^2(G82,'H$(A"/TB)V$C!
-MZ`B(0D"(6D'&0D(`QD)#`$2)Z&;!Z`B(0D1$B&I%QD)&`,9"1P#K3T&`_@$9
-MP(/@`H/`*$B+5"0HB$(XQD(Y`$B)V$C!Z!B(0CI(B=A(P>@0B$([2(G82,'H
-M"(A"/(A:/<9"/@!$B>AFP>@(B$(_1(AJ0,9"00!(BWPD*.@`````2(M%8`^W
-M0#A(BU0D*&:)0B#&0B2`2(EJ*$B+5"002(M"$$B+5"0H2(E"2(M$)"2)0C1(
-MBT0D$$B)0GC&0C`@2(M%8$@%[````$B)0E!(QX*@`````````+X`````2(M\
-M)!CH`````$B+1"0HBU`T2(M$)!!(BW`82(M\)!CH`````,:%RP````%(BW0D
-M*$B+?"0(Z`````!(A>T/A)@```!(BU5@2(72#X2+````@+W+``````^$^0``
-M`&:!O<@```"6`'4.2(MZ4+XA````Z`````!F@ZW(`````;_0!P``Z`````!(
-MBWPD".@`````2(M58$B%TG1`@+W+``````^$K@```.NS2(M4)"B`>B0`=2:[
-M`````$6$]G0ABU0D)$B+1"002(MP$$R)_^@`````NP````#K!;O_____2(M4
-M)"A(@WIX`'0O@7HT``@``'<32(G62(/&>$B+?"0(Z`````#K$TB+="0H2(/&
-M>$B+?"0(Z`````!(BW0D*$B+?"0(Z`````!(BT0D"$B+L/@(``#&1C\`2(GJ
-MOP8```#H`````$&`9"1,_>L<N______K%6:#O<@`````#X5&____Z7+___]F
-MD(G82(M<)#A(BVPD0$R+9"1(3(ML)%!,BW0D6$R+?"1@2(/$:,-F9F:09F9F
-MD&9FD$B#[!A(B1PD2(EL)`A,B60D$$B)\TB+1U!,BR!(BVYH#[9&)#P@=$@\
-M('<*A,!T(CP&=Q7K,#PB=#8\(F9F9I!R)(/`@#P!=AVX`````&:0ZV-(BT=`
-MQT`$`````,:%L@````'K"L:%L@````UF9I!(@WMX`'0E@7LT``@``'<02(US
-M>$R)Y^@`````ZPYFD$B-<WA,B>?H`````$B)WDR)Y^@`````2(GO_Y7(````
-MN`$```!(BQPD2(ML)`A,BV0D$$B#Q!C#9F9FD&9F9I!(@^PH2(D<)$B);"0(
-M3(ED)!!,B6PD&$R)="0@2(G[28GU28G42(MO8$B%[74*2(G7_];I/@$``$B#
-MOX@`````=0Y(@[^``````'0/9F9FD$R)YT'_U>D;`0``@+WH``````^%"`$`
-M`(!]2O]F9F:0#X7Z````2(M%8$B%P'0*@'A1``^%YP```$B+?5#V1PP0#X79
-M````3(LW@+V#`````'0-2(GJO@8```#H`````$R)JX@```!,B:.0````#[95
-M2$B)T(/@!DB#^`9U*?;"`71]QD5*!<9%2P0/MI6!````2(MU6$B+?5!(B>GH
-M`````.E_````2(/X!'5Y]L(!='1(BU5@2(72="\/MT).J`)T8X/@_6:)0DY(
-MBT5@9L=`3@$`2(M%8,9`0AU(BW5@3(GWZ`````#K/,9%2@/&14L$2(GN3(GW
-MZ`````#K)Y#&14H%QD5+!F;'A<@``````$B)[DR)]^@`````ZPAFD$R)YT'_
-MU4B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9FD&9FD&9FD&9FD%-(
-MB?M(A?\/A,,```!(BW]XZ`````!(B<)(A<`/A'X```"`N!4!````='6`"P$/
-MMH`5`0``/`)U.DB#>W``=1D/MH/,````@^`#B$,"#[:"%`$``(A#`>MW#[:#
-MS0```(A#`DB+0W`/MH`4`0``B$,!ZUT\`W59#[:#S````(/@`\'@`@*#S0``
-M`(A#`DB+0W`/MH`4`0``B$,!ZS-F9I!(BT-P2(7`=0M(BT-H2(7`=0[K'`^V
-M@!0!``"(0P'K$`^V@,(```"(0P%F9I!F9I!;PV9F9I!F9F:09F:09F:055-(
-M@^P(2(G[2(7_='>]``````^VA!UH"```//]T00^VT$B-!%)(C02"2,'@!4B)
-MPD@#DT`)``!T)HM"2"4`__\`/0``_P!U%_9"2P1T$4B+>D!(A?]T".@`````
-M9F:02(/%`4B!_8````!UIDB+@_@(``!(.=AU#$B-N)`4``#H`````$B#Q`A;
-M7<-F9F:055-(@^P(2(G[2(VOD!0``.@`````2(E#*$B)12A(B9OX"```2(F=
-M^`@``(N#$`D``(F%$`D``,:#;A0```'&A6X4```!2(G?Z`````!(B=_H````
-M`$B)[^@`````2(G?Z`````"$P'1G2(GOZ`````"$P'1;2(G?Z`````"_T`<`
-M`.@`````2(G?Z`````#'@Y@!``#H`P``2,>#J`$```````!(B9NP`0``2(VS
-MF`$``$B+>RCH`````+X`````2(G?Z`````"X`0```.L&D+@`````2(/$"%M=
-MPV9F9I!32(G[Z`````!(@<.0%```2(G?Z`````"X`0```%O#D$%7059!54%4
-M55-(@^P82(ET)`A(B10D@ST```````^%;P$``,<%``````$```!$BST`````
-MQT0D%`````!)Q\4`````2,?#`````$G'Q@````#I=@(```^WA@````#!X!!"
-M#[<4+@G0.<4/A?$```!!N`````"_`````&9FD&:09H,\'P!U7TECT$B)T4C!
-MX05*BP0N2(D$&4*+1"X(B409"`^V@0````!(P>(#2(T\`@^V1"03B$2[#0^V
-M@0````!(C3P"#[9$)!*(1+L.#[:!`````$@!PL9$DP\`@($``````>MT#[:/
-M``````^VP;H`````0O<T-H72=$L/ML%)8]!(C0S5`````$B-/`$/MD0D$XA$
-MNPU(P>(%#[:"`````$B-/`$/MD0D$HA$NPX/MH(`````2`'!QD2+#P"`@@``
-M```!ZQ)!@\`!2(/'($&#^`0/A2;___^#A@`````!08/"`4B#QAA%.?H/A>7^
-M__]!@\0!08/\(`^%%P$``(-$)!0!@7PD%/\````/A3H!``!(@WPD"`!T"$B+
-M5"0(Q@(`BS4`````O0````"%]GXUN0````"]`````+H``````ZH`````2(-\
-M)`@`=`V+@@````!(BUPD"``#@\$!2(/"&#GQ==I(@SPD``^$[````$&Y````
-M`$&Z`````$G'Q`````!F0X,\(@`/A,T```!!#[:2`````(32=&=!N`````!)
-M8\%,C1S%``````^VPH/H`4B-6`%+C00#2(TTA0````!(BSPDN00```#\\Z8/
-ME\(/DL`XPG4A2(-\)`@`=`]!#[:"`````$B+5"0(B`)!#[:J`````.L)28/`
-M`4DYV'6T08/!`4F#PB!!@_D$=$SI;O___T2(9"02N0````"Z`````$2)YHM\
-M)!3H`````(G%0;H`````O@````!%A?\/CX_]___II?[__P^V1"04B$0D$T&\
-M`````.NY0`^VQ4B#Q!A;74%<05U!7D%?PV9F9I!F9F:09F9FD&9FD$B#[!A(
-MB1PD2(EL)`A,B60D$(GU3(MG>$B+7V#V!P%T7TB+>UA(A?]T$$`/MM8/MK.!
-M````Z`````!(B[L@`0``2(7_=!!`#[;5#[:S#0$``.@`````3(GGZ`````!(
-MA<!T+8"X%0$```!T)$`/MM5(BW-`3(GGZ`````#K$F:00`^VUDB+<T!,B>?H
-M`````$B+'"1(BVPD"$R+9"002(/$&,-F9F:09F:09F:09F:02(/L2$B)7"08
-M2(EL)"!,B60D*$R);"0P3(ET)#A,B7PD0$B)^T&)]$B+;V!,BV]X2(7M#X0W
-M`P``@+_+``````^%*@,``/8'`@^%(0,```^VA9@!``"$P'0+0#CP=3J0Z0L#
-M```/M@^#X0$/MLD/ME<"#[9W`40/MH4/`0``2,?'`````+@`````Z`````"[
-M_____^G<`@``3(GOZ`````!)B<9(A<`/A,,"``!(BT-@#[8+@^$!#[;)#[93
-M`@^V<P%%#[;,1`^V@`\!``!(Q\<`````N`````#H`````$'&1CCA0<9&.0%!
-M@/P"#Y7`@\`:08A&.D'&1B2`#[=%.&9!B48@28E>*$''1C0`````2<=&2```
-M``!)QX:@`````````$R)]DR)[^@`````QH/+`````6;'@\@```#T`4B%VW1.
-M2(M38$B%TG139H&[R````)8`=0Y(BWI0OB$```#H`````&:#J\@````!O]`'
-M``#H`````$R)[^@`````2(M38$B%TG0)@+O+`````'6[9H.[R``````/A+<!
-M``!!@'XD``^%K`$``$B+0V!(B40D$$B+0%!,BSA,B?_H`````$B)Q4B%P'46
-M2(M$)!#&@.D````!NP````#I>P$``$R)_^@`````28G$2(7`=2%(BU0D$,:"
-MZ0````%(B>Y,B?_H`````+L`````Z4H!``!(C4582(E$)`C&13CAQD4Y`<9%
-M.@-(BU0D$`^W0CAFB44@QH68````#TB)72C'130``@``28M4)!!(B55(N```
-M``#&!!``2(/``4@]``(``'7P3(EE>$C'A:``````````O@````!(BWPD".@`
-M````BU4T28MT)!A(BWPD".@`````2(GN3(G_Z`````#&@\L````!9L>#R```
-M`/H`2(7;=$Y(BU-@2(72=$]F@;O(````E@!U#DB+>E"^(0```.@`````9H.K
-MR`````&_T`<``.@`````3(G_Z`````!(BU-@2(72=`F`N\L`````=;MF@[O(
-M`````'0F@'TD`'4@2(MU2$B+?"00Z`````!(BU0D$`^V@I@!``"(@\\```!(
-M@WUX`'0,2(UU>$R)_^@`````2(GN3(G_Z`````"[`````.L%N_____],B?9,
-MB>_H`````.L,9F9FD&9FD+O_____B=A(BUPD&$B+;"0@3(MD)"A,BVPD,$R+
-M="0X3(M\)$!(@\1(PV9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD($B)
-M^X`^"7<0#[8&_R3%`````&9FD&9FD+C_____Z28!``!(BT8(2(N0``D``$B%
-MTD@/1-!(B[KX"```QH=O%````>@`````N`````#I]P````^V5@B^`````.BI
-MZ/__Z>0````/ME8(O@$```#HENC__^G1````#[9V".@`````Z<,```!$#[9N
-M"$R+9WA(BV]@N/_____V1U@(#X2G````28NT)/@(``!(B?J_!0```.@`````
-M@$U,`DB+?5!(B>J^(0```.@`````@+V#`````'0?9F9FD+_0!P``Z`````!,
-MB>?H`````("]@P````!UY46$[70,9H-+6A!F@TUJ$.L*9H-C6N]F@V5J[TF+
-MM"3X"```2(G:OP8```#H`````(!E3/VX`````.L:#[9V".@`````D.L.#[9V
-M".@`````N`````!(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F9FD&9FD$B#
-M[%A(B5PD0$B);"1(3(ED)%!(B?U,BV=X28N$)/@(``"`>#\`#X6T````2(N?
-M@````$B+?V!$#[:/#P$``$&X`0```$0B10`/MDT"#[95`8MU"`^VA]L```")
-M1"0X#[:'V@```(E$)#`/MH?9````B40D*`^VA]@```")1"0@#[:'UP```(E$
-M)!@/MH?6````B40D$`^VA]4```")1"0(#[:'U````(D$)$&#X`%(Q\<`````
-MN`````#H`````$C'A8``````````BU4(2(N]D````$B)[O_3ZT%F9F:02(V?
-MF````$F+?"0H2(G>Z`````#'A9@```#T`0``2,>%J`````````!(B:VP````
-M28M\)"A(B=[H`````$B+7"1`2(ML)$A,BV0D4$B#Q%C#9F9FD&9F9I!F9F:0
-M9F:005=!5D%505154TB#[`A(B3PD28GV#[?22(T$4DB-!()(P>`%28G%3`.O
-M0`D``$R+A_@(``!)@<"0%```3(EN8$F)=4!)@WU8`'4U28-]8`!U+DB+!"0/
-MMGA#0(3_#X0\!```28MU4+D`````2#NPT!(```^$_`,``.D4!```9I!!@`X!
-M28M%8$F)1G!)BT5828E&:$B+%"0/MGI#0(3_=$Y)BW50N0````!(.[+0$@``
-M=!OK+0^VP4B-%$!(C1202(L$)$@YM-#0$@``=1E(BQ0D#[9"08T$@4&(ALP`
-M``#K#;D`````@\$!0#CY=<9(BP0D2(N(^`@```^V@>@(``"^`````#S_="E)
-MBU582(72=!L/ML!(:<#(#P``2`.!D`D``+X`````2#G"="^^`0````^V@>D(
-M```\_W0K28M56$B%TG0?#[;`2&G`R`\``$@#@9`)``!(.<)U"4&(=@'I]P``
-M`(/&`;H`````9I`/MH0*Z@@``#S_="</ML!(C03`2,'@!4@#@6@)``!).T5@
-M=0Q!B'8!Z<````!F9I"#Q@%(@\(!2(/Z!'7#B?%!#[:`Z`@``#S_="9)BU58
-M2(72=06-<0'K&`^VP$AIP,@/``!)`X"0"0``2#G"=>7K*T$/MH#I"```//]T
-M*$F+55A(A=)T'`^VP$AIP,@/``!)`X"0"0``2#G"=09!B'8!ZTN#Q@&Z````
-M`&9FD&9FD$(/MH0"Z@@``#S_="8/ML!(C03`2,'@!4D#@&@)``!).T5@=0M!
-MB'8!ZQ)F9I!FD(/&`4B#P@%(@_H$=<-(BQ0D@'I1`74]28M]6$B%_W0200^V
-MM8$```"Z`````.@`````28N](`$``$B%_P^$O`$``$$/MK4-`0``N@````#H
-M`````$F#O2`!````#X2<`0``28MM6(!]6`!T64&\`````$B-74A)B=](B=_H
-M`````$B-2/!(BU502(E%4$B)61!(B5$82(D"@+D/`0``_W40@'E)`'4*2(.Y
-M(`$```!U"D&#Q`%$.&58=[M$.&58#X61````00^VA0\!``!!B$8"@'U8``^$
-MDP$``+L`````3(UE2$R)Y^@`````2(U(\$B+55!(B4503(EA$$B)41A(B0)(
-MBT%`2(7`=#P/MI$/`0``.%`"=#!(@[B``````'4F2(.XB`````!U'(A0`@^W
-M43A(BP0D2(NP^`@``+\'````Z`````"#PP$X75@/AAH!``#KCD$/MH6!````
-M08A&`D'&A0\!``#_@'U8``^$^@```+L`````9F9FD&9FD$R)_^@`````2(U(
-M\$B+55!(B4503(EY$$B)41A(B0*`N0\!``#_=$S&@0\!``#_2(M!0$B%P'0\
-M#[:1@0```#A0`G0P2(.X@`````!U)DB#N(@`````=1R(4`(/MU$X2(L$)$B+
-ML/@(``"_!P```.@`````@\,!.%U8=G+K@D$/MH6!````08A&`NMB#[;!2(T4
-M0$B-%)!(BP0D2#FTT-`2``!U(DB+%"0/MD)!C02!08A&`4&(ALP````X2D-U
-M%.L-N0````"#P0%`./EUO4'&1@'_0<9&`@!!@[V0`0```'0+08N%E`$``$&(
-M1@))C4X@28V5F````$F+A9@```!)B48@2(M""$B)00A(BT(02(E!$$B+0AA(
-MB4$82(M"($B)02!)C4X,28V5A````$F+A80```!)B48,2(M""$B)00B+0A")
-M01!)BX7`````28E&2$$/MT5H9D&)1EA!#[=%:F9!B49:28M%>$F)1E!!#[:%
-M@@```$&(1EQ!#[:%F`$``$&(AL\```!!]D5,!'4)2(L\).@`````00^V54A(
-MB="#X`9(@_@&=0OVP@%U!D&`#@+K!$&`)OU!#[953-#J@^($00^V!H/@^PG0
-M08@&00^V1@%!B(;.````00^V1@)!B(;-````3(GWZ`````!)BW5`N@````!(
-MBSPDZ`````!,B??HYOC__TB#Q`A;74%<05U!7D%?PV9F9I!F9I!(@^P82(E<
-M)`A(B6PD$$B)_4B+G_@(``#H`````(!]40%U+4B-NY`4``"`?U$!=%N`O8`4
-M````=1>^`````.@`````@(6`%````69FD&9FD$B-G9@!``!(BWTH2(G>Z```
-M``#'A9@!``#H`P``2,>%J`$```````!(B:VP`0``2(M]*$B)WN@`````2(M<
-M)`A(BVPD$$B#Q!C#9F:09F:005154TB#[#!)B?M(B=-(BVXH3(MF,$0/ME4+
-M2(N'^`@``$B+L/@(``!!N`````"_`````+D`````9F9FD&9FD`^VE#'H"```
-M@/K_=$J-@8````!F/8$`=P>#QP'K.6:0#[;"2(N6:`D``$B-!,!(P>`%@+P0
-M%0$```-U&$&#P`%!C4`#@_@&=@Z#QP%!N`````#K`X/'`4B#P0%(@_D&=9]!
-MB?E(B[;X"```2('&D!0``+$`#[:4,>@(``"`^O]T3XV!@````&8]@0!W!8/'
-M`>L^#[;"2(N6:`D``$B-!,!(P>`%@+P0%0$```-U&$&#P`%!C4`#@_@&=A6#
-MQP%!N`````#K"H/'`69F9I!F9I!(@\$!2(/Y!G6:03GZ#XWO!P``13G1#Y[`
-MQP,`````//\/A-0'```/MOA(:?^0%```20.[^`@``.@`````2(G'2(7`#X2R
-M!P``#[:`%0$``#P"#X7%`0``QP,$````#[9U!TB+%P^W1T"Y`````("\`F@(
-M``#_#X29`0``0(#^(P^'@`$``$`/ML;_),4`````0<<$)$53`Q&X`0```&:0
-MZ6T!``!(C4PD++H0`P``O@$```#H`````(3`#X1%`0``BT0D+(7`#X1``0``
-M)?\#``!IP!`G``"-B!"6K_^Z<XBK3(G(]^*)R"G0T>@!PL'J!T&)%"2X`0``
-M`.D2`0``2(U,)"RZ"`,``+X!````Z`````"$P`^$Z@```(M$)"R%P`^$Y0``
-M`"7_`P``:<#H`P``C8C(Y??_NLMK**^)R/?BB<@IT-'H`<+!Z@1!B10DN`$`
-M``#IMP```$B-3"0LN@@#``"^`0```.@`````A,`/A(\```"+1"0LA<`/A(H`
-M``#!Z!`E_P,``&G`Z`,``(V(R.7W_[K+:RBOB<CWXHG(*=#1Z`'"P>H$08D4
-M)+@!````ZUQ(C4PD++H,`P``O@$```#H`````(3`=#B+1"0LA<!T-R7_`P``
-M:<#H`P``C8C(Y??_NLMK**^)R/?BB<@IT-'H`<+!Z@1!B10DN`$```#K#+@`
-M````ZP6X`0````^VR`^VP>GP!0``/`,/A=8%``#'`P0```!$#[9-!TC'!"0`
-M````2,=$)`@`````2,=$)!``````2,=$)!@`````2(L7#[:"_0```(3`#X2A
-M````0;@`````28GC#[;`@^@!3(U0`;X`````N`$```")QT2)P=/G#[:$%NH(
-M```\_W0H#[;`2(T$P$C!X`5(B<%(`XIH"0``2(N!B````$B+0"`/MD`*.?AT
-M$$B#Q@%(@_X$#X0F!0``Z[Q(A<D/A!L%```/MT%`@+P":`@``/\/A`D%``"`
-MN14!```##X7\!```2XD,PTF#P`%-.=`/A7+___]!@/E5#X?7!```00^VP?\D
-MQ0````!!QP0D0`,#$;@!````Z;\$``!(C4PD+$&-00&#X`-(BSS$NC0#``"^
-M`0```.@`````A,`/A),$```/MU0D+(E4)"R!^O__``!U$D''!"3_____N`$`
-M``#I=00``+C`X>0`B=&Z`````/?Q08D$)+@!````Z5D$``!(C4PD+$B+?"0(
-MNA`#``"^`0```.@`````A,`/A#,$``"+1"0L)?\#``!IP!`G``"-B!"6K_^Z
-M<XBK3(G(]^*)R"G0T>@!PL'J!T&)%"2X`0```.D!!```2(U,)"Q(BWPD"+H(
-M`P``O@$```#H`````(3`#X3;`P``BT0D+"7_`P``:<#H`P``C8C(Y??_NLMK
-M**^)R/?BB<@IT-'H`<+!Z@1!B10DN`$```#IJ0,``$B-3"0L2(M\)`BZ"`,`
-M`+X!````Z`````"$P`^$@P,```^W1"0N)?\#``!IP.@#``"-B,CE]_^ZRVLH
-MKXG(]^*)R"G0T>@!PL'J!$&)%"2X`0```.E0`P``2(U,)"Q(BWPD"+H,`P``
-MO@$```#H`````(3`#X0J`P``BT0D+"7_`P``:<#H`P``C8C(Y??_NLMK**^)
-MR/?BB<@IT-'H`<+!Z@1!B10DN`$```#I^`(``$B-3"0L2(L\)+H4`P``O@$`
-M``#H`````(3`#X33`@``BU0D+('B_P,``$AITCJX`0!(@<+C2@,`2,'J!4BX
-M0WBT<<1:?`I(]^)(P>H'08D4)+@!````Z9T"``!(C4PD+$B+?"0(NA0#``"^
-M`0```.@`````A,`/A'<"``"+5"0L@>+_`P``2&G2.K@!`$B!PN-*`P!(P>H$
-M2+B%\&CCB+7X%$CWXDC!Z@A!B10DN`$```#I00(``$B-3"0L2(M\)!"Z%`,`
-M`+X!````Z`````"$P`^$&P(``(M4)"R!XO\#``!(:=+F$T`"2('"#?].!$BX
-MO4)ZY=64O]9(]^)(P>H708D4)+@!````Z>D!``!(C4PD+$B+?"08NA0#``"^
-M`0```.@`````A,`/A,,!``"+5"0L@>+_`P``2&G2KD7A`$B!PBE2KP%(N-LT
-MMM>"WAM#2/?B2,'J$D&)%"2X`0```.F1`0``2(U,)"Q(BWPD"+JP`P``O@$`
-M``#H`````(3`#X1K`0``BT0D+,'H#X/@`4&)!"2X`0```.E8`0``@'T(`'01
-M2(M$)`B!H!@!``#_]___ZP](BT0D"(&(&`$````(``!(BWPD".@`````N`$`
-M``#I'@$``(!]"`!T$4B+1"0(@:`8`0``_^___^L/2(M$)`B!B!@!````$```
-M2(M\)`CH`````+@!````Z>0```"`?0@`=!%(BT0D"(&@&`$``/_?___K#TB+
-M1"0(@8@8`0```"```$B+?"0(Z`````"X`0```.FJ````@'T(`'012(M$)`B!
-MH!@!``#_O___ZP](BT0D"(&(&`$```!```!(BWPD".@`````N`$```#K<X!]
-M"`!T$4B+1"0(@:`8`0``___^_^L/2(M$)`B!B!@!``````$`2(M\)`CH````
-M`+@!````ZSR`?0@`=!%(BT0D"(&@&`$``/___?_K#TB+1"0(@8@8`0`````"
-M`$B+?"0(Z`````"X`0```.L%N``````/ML#K!;@`````#[;`ZQ*X`````.L+
-MQP,`````N`````!(@\0P6UU!7,-F9F:09F:09F:005=!5D%505154TB#[#A)
-MB?R)\$B)TTF)S4&)]D'![AA!B?=!P>\0#[;4B%0D$$"(="0/2(VKD!0``+@`
-M````D,8$&`!(@\`!2#T@*P``=?!,B6L@BP4`````B$-`@\`!B04`````1(AS
-M.T2(>SH/MD0D$(A#.0^V5"0/B%,XQD-!`$$/MP0D9HE#,$$/MT0D`F:)0S)!
-MBT0D!(E#-$B-DR`I``!(B9.(%```3(EM(`^V0T"(14!$B'4[1(A].@^V1"00
-MB$4Y#[9$)`^(13C&14$!00^W!"1FB44P00^W1"0"9HE%,D&+1"0$B44T2(F5
-MB!0```^W0S)F/20G#X04`0``9CTD)P^'A````&8]1"$/A``!``!F/40A=T1F
-M/2`A#X3P````9CT@(7</9CU0!P^%]````.G;````9CTB(9`/A-````!F/4`A
-M9F:09F:0#X74````Z;L```!F9I!FD&8]$"</@L````!F/1$G9I`/AJ````!F
-M+2`G9H/X`F:0#X>D````Z8L```!F9I!FD&8]@"</A'P```!F/8`G9I!W+F8]
-M0"=T;F8]0"=F9F:0=PAF/3`G=7+K7&8]1"=FD'149CU@)W5BZTQF9I!F9I!F
-M/8!R=$!F/8!R9F:09F:0=PAF/8(G=4+K+&8]@)%FD'0.9CV`E'4RZQQF9I!F
-M9I!FQT,\@)'&0SX$9L=%/("1QD4^!.L49L=#/("4QD,^!&;'13R`E,9%/@1!
-M#[9$)`B(0T)!#[9$)`B(14*Y```$`+H`````O@(```!,B>_H`````$B)`[D`
-M(```N@````"^`````$R)[^@`````2(G!2(E#$$B+`TB%P`^$Y0$``$B%R0^$
-MW`$``$B-D``"`0!(B5,(2(V````"`$B)`T@%`$```$B)10!(B54(2(E-$$2+
-M!0````!%A<!^9[X`````N0````!(Q\<`````#[<$.69!.P0D=3\/MX$`````
-M9D$[1"0"=3"+D0````"#P@&)D0````!$BXD`````187)=!5$.<IV$(G0N@``
-M``!!]_&)D0````"#Q@%(@\$81#G&=:I(BT,(2"W@?0``QP`!\`,`2(M#"$@M
-MV'T``,<``0``Z$B+>R"^>````.@`````B<(E`'```#T`(```=A2`YH^`SB!(
-MBWL@OG@```#H`````$2(="0C1(A\)"(/ME0D$(A4)"$/MD0D#XA$)""]````
-M`$&Y`````$G'Q`````!,C6PD(&9#@SPA``^$H@```$&`N0``````#X2$````
-M0;@`````2&/%3(T4Q0````!-B>M+C00"2(TTA0````"Y!````/Q,B=_SI@^7
-MP@^2P#C"=3M!#[:!`````(/``4&(@0````!!#[:1`````(32=!TXT'89#[;`
-M#[;*N@````!F]_%!B)$`````9F9FD$&-4`%)@\`!00^V@0`````YT'^0@\4!
-M28/!((/]!`^%4O___\>#$`D```$```"X`0```.L%N`````!(@\0X6UU!7$%=
-M05Y!7\-F9F:09F:005154TB)^TB)]4B+?WA!O`$```!$(B.X`````&9F9I#&
-M!"@`2(/``4B#^"AU\DB+MX@4``!(B?*P`&9FD&9FD,8$$`!(@\`!2#T``@``
-M=?!(C4XVN@````!F9F:09F:0#[9$4R&(!%$/MD13((A$40%(@\(!2(/Z%'7E
-M2(U.%+(`#[9$4PV(!%$/MD13#(A$40%(@\(!2(/Z"G7E2(U.+K(`#[9$4TF(
-M!%$/MD132(A$40%(@\(!2(/Z!'7E2(EU&$B+0U!(@\`!2(E%`$B#>V``=4'V
-M`P%T/$B+0VA(A?\/E<)(A<!T$H32=`X/MD!;@+P':`@``/]U&TB+0W"$TG0<
-M2(7`=!</MT!`@+P':`@``/]T"0^V0P&(10SK(.@`````2(7`=!*`N!4!```"
-M=0D/MD,!B$4,ZP3&10S_#[9#`HA%#;@!````]D-:$'0$#[9#7(A%#L9%$A#&
-M11$01(G@C10`OOW___]`(G4*"=9`B'4*P>`%#[9-"(/AWPG!B$T(#[=#6$C!
-MZ`>#X`'!X`:#X;\)P8A-"`^W0UA(P>@"@^`!#[95"8/B_@G"B%4)#[=#6DC!
-MZ`/!X`>#X7\)P8A-"`^W0UI(T>B#X`$!P(/B_0G"B%4)#[=#6$C!Z`.#X`'!
-MX`:#XK\)PHA5"0^W0UI(P>@$P>`'@^)_"<*(50F#R1"(30@/M@/0Z(/@`8/F
-M_@G&0(AU"@^V`X/@!(/F^PG&0(AU"F;'110`$`^V@\\```"(10\/MH/,````
-MB$4@6UU!7,-F9F:09F9FD&9FD$%6055!5%5308GU08G62(G+3(G%2(7)=!>X
-M`````&:0Q@08`$B#P`%(/:P```!U\$B%[709N`````!F9I!F9I#&!"@`2(/`
-M`4B#^"AU\DR+I_@(``!!#[;U3(GGZ`````")PF:%P'0.#[?`08"\!&@(``#_
-M=4A-BZ0D^`@``$F!Q)`4``!)B[PD^`@``.@`````02G%00^V]4R)Y^@`````
-MB<)FA<`/A$\#```/M\!!@+P$:`@``/\/A#T#```/M\)!#[:$!&@(``!F@?J!
-M``^'4@(``$F+C"20"0``#[?`2&G`R`\``$B--`%(A=L/A-8```!(BU802(72
-M='5!#[:$).@(```\_W08#[;`2&G`R`\``$B-!`&_@````$@YPG0E00^VA"3I
-M"```//]T'`^VP$AIP,@/``!(C00!2#G"=0F_@0```$"(>P*`?EH`=#"Z````
-M``^VP@^V3`9PN`$```#3X`E#((/"`3A66G81Z^3&0P+_2(M&"`^V0`V)0R#&
-M`P$/MD99B$,!2(M&>$B)0P1(BX:(````2(E##$B+AI````!(B4,4BX:@````
-MB4,<1(EK)`^VAL````")0RBX`````.DV`@``2(7M#X0H`@``187V#X@?`@``
-M#[:&P````$$YQ@^-#P(``$ECQDB-!$!(P>`$2`'P2(V0P`````^V2@B(30`/
-MME()B%4!2(N`T`````^V`(/@#XA%`H#Y`W0N@/D#=PZ`^0(/A:D```#IJP``
-M`(#Y!&9FD&9FD'1`@/D2#X60````9F:09I#K7TECQDB-!$!(P>`$2(N4!M``
-M```/MD(!@^`'#[;`P>`(#[92`@'0C02``<")103K8$ECQDB-!$!(P>`$2(N$
-M!M`````/MD`"A,!U"<=%!`````#K/`^VP(/H%(E%!.LQ26/&2(T$0$C!X`1(
-MBY0&T`````^V0@+!X`@/ME(#`="-!(`!P(E%!.L'QT4$`````$B-30A)8\9(
-MC01`2,'@!$B-A`;0````2(U0"$B+0`A(B44(2(M""$B)00A(BT(02(E!$$B+
-M0AA(B4$8N`````#IV0````^WP$B-!,!(P>`%2(G%20.L)&@)``#&0P+_Q@,"
-M28N4)&@)```/MD00.XA#`4B+A8@````/MD`-B4,@#[:%%0$``#P"=2O'0P1(
-M4%0`QT,,4F]C:\=#$&5T4W3'0Q1O<B``#[=U/DB->Q?HNL+__^M'/`-U(<9#
-M`1#'0R`!````QT,$2%!4`,=##$5*,S1FQT,0,`#K(L9#!'8/MW4\2(U[!>B"
-MPO__QD,,9`^W=3Y(C7L-Z''"___&0QQR#[9U.4B->QWH(,+__T2):R2X````
-M`.L%N/____];74%<05U!7L-F9F:09F:0055!5%5308GU2(G3N`````#&!!@`
-M2(/``4@]*`T``'7P2(NO^`@``$$/MO5(B>_H`````(G"9H7`=`T/M\"`O`5H
-M"```_W5%2(NM^`@``$B!Q9`4``!(B[WX"```Z`````!!*<5!#[;U2(GOZ```
-M``")PF:%P`^$D0,```^WP("\!6@(``#_#X2``P``#[?"#[:$!6@(``!F@?J!
-M``^'C0(``$B+C9`)```/M\!(:<#(#P``3(T$`4F+4!!(A=)T=`^VA>@(```\
-M_W08#[;`2&G`R`\``$B-!`&^@````$@YPG0C#[:%Z0@``#S_=!P/ML!(:<#(
-M#P``2(T$`4@YPG4)OH$```!`B',"08!X6@!T,KH`````#[;"00^V3`!PN`$`
-M``#3X`E#((/"`4$X4%IV$>OBQD,"_TF+0`@/MD`-B4,@Q@,!00^V0%F(0P%)
-MBT!X2(E#!$F+@(@```!(B4,,28N`D````$B)0Q1!BX"@````B4,<1(EK)$&`
-MN,``````#X2+`@``0;D`````00^V^4ACQTB-#(!(C0S+2(T$0$C!X`1,`<!(
-MC9#`````#[9R"$"(L:@````/ME()B)&I````2(N`T`````^V`(/@#XB!J@``
-M`$"`_@-T-$"`_@-W$4"`_@(/A=,```!FD.G>````0(#^!&9F9I!F9I!T2T"`
-M_A(/A;4```!F9F:0ZWU(8\](C01)2,'@!$F+E`#0````2(T,B0^V0@&#X`</
-MML#!X`@/ME("`="-!(`!P(F$RZP```#IA@```$ACUTB-!%)(P>`$28N$`-``
-M```/MD`"A,!U$4B-!)+'A,.L`````````.M:2&/72(T4D@^VP(/H%(F$TZP`
-M``#K1$ACSTB-!$E(P>`$28N4`-````!(C0R)#[9"`L'@"`^V4@,!T(T$@`'`
-MB83+K````.L22&/'2(T$@,>$PZP`````````2&/'2(T4@$B-E-.@````2(UR
-M$$B-!$!(P>`$28V$`-````!(C4@(2(M`"$B)0A!(BT$(2(E&"$B+01!(B480
-M2(M!&$B)1AA!@\$!13B(P`````^&Z0```.E?_O__#[?`2(T$P$C!X`5)B<1,
-M`Z5H"0``QD,"_\8#`DB+E6@)```/MD00.XA#`4F+A"2(````#[9`#8E#($$/
-MMH0D%0$``#P"=2W'0P1(4%0`QT,,4F]C:\=#$&5T4W3'0Q1O<B``00^W="0^
-M2(U[%^B>OO__ZTL\`W4AQD,!$,=#(`$```#'0P1(4%0`QT,,14HS-&;'0Q`P
-M`.LFQD,$=D$/MW0D/$B->P7H9+[__\9##&1!#[=T)#Y(C7L-Z%&^___&0QQR
-M00^V="0Y2(U['>C^O?__1(EK)+@`````ZPRX_____^L%N`````!;74%<05W#
-M05154T&)]$B)T[@`````D,8$&`!(@\`!2#VD#```=?!(BZ_X"```00^V]$B)
-M[^@`````B<)FA<!T#0^WP("\!6@(``#_=4=(BZWX"```2('%D!0``$B+O?@(
-M``#H`````$2)YBG&0`^V]DB)[^@`````B<)FA<`/A&<#```/M\"`O`5H"```
-M_P^$5@,```^WP@^VA`5H"```9H'Z@0`/AV<"``!(BXV0"0``#[?`2&G`R`\`
-M`$R-!`%)BU`02(72='0/MH7H"```//]T&`^VP$AIP,@/``!(C00!OH````!(
-M.<)T(P^VA>D(```\_W0<#[;`2&G`R`\``$B-!`%(.<)U";Z!````0(AS`D&`
-M>%H`=#*Z``````^VPD$/MDP`<+@!````T^`)0R"#P@%!.%!:=A'KXL9#`O])
-MBT`(#[9`#8E#(,8#`4$/MD!9B$,!28M`>$B)0P1)BX"(````2(E##$F+@)``
-M``!(B4,408N`H````(E#'$&`N,``````#X1E`@``0;D`````00^V^4ACQTB-
-M#(!(C0S+2(T$0$C!X`1,`<!(C9#`````#[9R"$"(<20/ME()B%$E2(N`T```
-M``^V`(/@#XA!)D"`_@-T,$"`_@-W#T"`_@(/A<````#IR@```$"`_@1F9I!F
-MD'1%0(#^$@^%I@```&9F9I#K<4ACSTB-!$E(P>`$28N4`-````!(C0R)#[9"
-M`8/@!P^VP,'@"`^V4@(!T(T$@`'`B43+*.MZ2&/72(T$4DC!X`1)BX0`T```
-M``^V0`*$P'4.2(T$DL=$PR@`````ZU%(8]=(C122#[;`@^@4B433*.L^2&//
-M2(T$24C!X`1)BY0`T````$B-#(D/MD("P>`(#[92`P'0C02``<")1,LHZP](
-M8\=(C02`QT3#*`````!(8\=(C12`2(U4TR!(C7(,2(T$0$C!X`1)C80`T```
-M`$B-2`A(BT`(2(E"#$B+00A(B48(2(M!$$B)1A!(BT$82(E&&$&#P0%%.(C`
-M````#X;E````Z8'^__\/M\!(C03`2,'@!4F)Q$P#I6@)``#&0P+_Q@,"2(N5
-M:`D```^V1!`[B$,!28N$)(@````/MD`-B4,@00^VA"05`0``/`)U+<=#!$A0
-M5`#'0PQ2;V-KQT,09713=,=#%&]R(`!!#[=T)#Y(C7L7Z*.Z___K2SP#=2'&
-M0P$0QT,@`0```,=#!$A05`#'0PQ%2C,T9L=#$#``ZR;&0P1V00^W="0\2(U[
-M!>AINO__QD,,9$$/MW0D/DB->PWH5KK__\9#'')!#[9T)#E(C7L=Z`.Z__^X
-M`````.L,N/_____K!;@`````6UU!7,-F9F:09F9FD&9FD$%455-!B?1(B=.X
-M`````)#&!!@`2(/``4@]``$``'7P2(NO^`@``$$/MO1(B>_H`````(G"9H7`
-M=`T/M\"`O`5H"```_W5'2(NM^`@``$B!Q9`4``!(B[WX"```Z`````!$B>8I
-MQD`/MO9(B>_H`````(G"9H7`#X39`0``#[?`@+P%:`@``/\/A,@!```/M\(/
-MMH0%:`@``&:!^H$`#X?9````2(N-D`D```^WP$AIP,@/``!(C30!2(M6$$B%
-MTG1Q#[:%Z`@``#S_=!@/ML!(:<#(#P``2(T$`;^`````2#G"=",/MH7I"```
-M//]T'`^VP$AIP,@/``!(C00!2#G"=0F_@0```$"(>P*`?EH`=#"Z``````^V
-MP@^V3`9PN`$```#3X`E#((/"`3A66G81Z^3&0P+_2(M&"`^V0`V)0R#&`P$/
-MMD99B$,!2(M&>$B)0P1(BX:(````2(E##$B+AI````!(B4,4BX:@````B4,<
-MN`````#IW@````^WP$B-!,!(P>`%28G$3`.E:`D``,9#`O_&`P)(BY5H"0``
-M#[9$$#N(0P%)BX0DB`````^V0`V)0R!!#[:$)!4!```\`G4MQT,$2%!4`,=#
-M#%)O8VO'0Q!E=%-TQT,4;W(@`$$/MW0D/DB->Q?H,;C__^M+/`-U(<9#`1#'
-M0R`!````QT,$2%!4`,=##$5*,S1FQT,0,`#K)L9#!'9!#[=T)#Q(C7L%Z/>W
-M___&0PQD00^W="0^2(U[#>CDM___QD,<<D$/MG0D.4B->QWHD;?__[@`````
-MZP6X_____UM=05S#2(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($B)^TF)
-M]$R+=WA(BT9(2(DX2(M'8$B%P'4:QH:R`````DB)]_^6R````.EJ!@``9F:0
-M9I#V0$P"=!K&AK(````"2(GW_Y;(````Z4H&``!F9I!FD$R)]^@`````2(G%
-M2(7`9I!U'D'&A"2R`````DR)YT'_E"3(````Z1H&``!F9I!FD,>`E```````
-M``!,B6!H2(M#8$B)12A(BT-@#[=`.&:)12#&122`00^VA"2P````/`(/A&D!
-M```\`G<*A,!T')#I0@,``#P##X3P`0``/`20#X4Q`P``Z;@!``!(BT-@]D!H
-M`0^$GP```$$/MH0DL0```*@"=`;&13B(ZQ"#X`0\`1G`@^`%@^AVB$4X28N4
-M))````!!#[>,))@```#&13D`2(G02,'H.(A%.DB)T$C!Z#"(13M(B=!(P>@H
-MB$4\2(G02,'H((A%/4B)T$C!Z!B(13Y(B=!(P>@0B$4_2(G02,'H"(A%0(A5
-M0<9%0@#&14,`B<AFP>@(B$5$B$U%QD5&`,9%1P#K;4$/MH0DL0```*@"=`;&
-M13@HZQ"#X`0\`1G`@^`%@\`JB$4X28N4))````!!#[>,))@```#&13D`2(G0
-M2,'H&(A%.DB)T$C!Z!"(13M(B=!(P>@(B$4\B%4]QD4^`(G(9L'H"(A%/XA-
-M0,9%00!(BT-@2`7L````2(E%4,9%,"`/M\'!X`F)132#C90````"Z?D!``!F
-M9F:000^VA"20````/!!W!?8#`G4.0<:$)+(````&Z20$``!(C7TX#[;028VT
-M))@```#H`````$B+0V!(!>P```!(B450QD4P((&-E```````$`#&126K0?:$
-M)+$````&#X22`0``08N$))0```")133I@@$``$$/MH0DL0```(/@,#P@=1'&
-M13@;QD4Y`<9%/`#I80$``,9%.#7I6`$``$B+0V`/MD!(J`%T)Z@$=".!C90`
-M`````"``00^WE"2<````9D$[E"22````=1/K8V9FD$'&A"2R````!NEF`P``
-M00^VA"2;````/.-T13SC=Q,\0G0]/+!T'3Q`=2=F9I!FD.LN/.QT#CSO="8\
-MY69F9I!U$.L<9D&)E"22````9F:0ZPY!QH0DL@````;I%`,``,9%.+!!#[>$
-M))````"(13E!#[>$))(```"(13I!#[>$))0```"(13M!#[>$))8```"(13Q!
-M#[>$))@```"(13U!#[:$))H```"(13Y!#[:$))L```"(13]!#[:$))$```"(
-M14!!#[:$)),```"(14%!#[:$))4```"(14)!#[:$))<```"(14-!#[:$))D`
-M``"(141!]H0DL0````9T)D$/MX0DG````,'@"8E%-(.-E`````3K#D'&A"2R
-M````!NE/`@``2,>%H`````````!!#[:$)+$```"H!@^$'P(``*@"=`F#C90`
-M```(ZP>#C90````03(UM6$F+G"2X````2(7;=`M!]H0DL0````%U-DF+A"3`
-M````2(7`#X0*`@``28NV2`H``+H`````3(GG_]"%P`^$\0$``$F+GD@*``!(
-MA=MT.4B)[^@`````O@````!,B>_H`````$B#PQ"+4_!(BW/X3(GOZ`````"+
-M0_1(@\,0A<`/A8D!``#KX+X`````3(GOZ`````"+130]``@``'<[3(GWZ```
-M``!(B<%(A<!U#D'&A"2R````"^E?`0``2(M`$$B)14A(B4UXBU4T2(MQ&$R)
-M[^@`````ZU0]```!`'<_3(GW9F9FD.@`````2(G!2(7`=0Y!QH0DL@````OI
-M&0$``$B+0!!(B45(2(E->(M5-$B+<1A,B>_H`````.L.0<:$)+(````&Z>X`
-M``!!#[:$)+$```"H!`^$T````$&`O"2P`````W4>28NT)*````!(A?9T$4B+
-M?4B+533H`````.FG````28N4)+@```!(A=)U$TF+A"3`````2(7`#X6X````
-MZV%,BVU(J`%U"DB)TV9FD&:0ZRE)BX0DP````$B%P'0<28NV2`H``+H!````
-M3(GG_]"%P'0'28N>2`H``$B#PQ"+4_!(BW/X3(GOZ`````"+0_!)`<6+0_1(
-M@\,0A<!U*.O>BT4T2(M-2(7`=!N)PDB)R,8``$B#P`%(@^H!=`GK\8.-E```
-M``%(B>Y,B??H`````.LQ2(GN3(GWZ`````!,B>=!_Y0DR````.L9NP````#I
-M2O[__TR+;4AF9I!F9I#I6O___TB+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#
-MQ"C#9F9FD&9F9I!F9I!F9I!54TB#[`A(B?U(B?.X`````,8$&`!(@\`!2#V`
-M````=?"#O1`)```!#Y1#$P^V53H/MDTY#[9U.`^V13N(0P.(4P*(2P%`B#.`
-M2Q$0#[=%,&:)0P0/MT4R9HE#!HN%$`D``(A#<,9#$B`/MU4R9H'Z("%T!V:!
-M^B(A=4C&0Q<"2(U#/,=#/%)O8VO'0T!E=%)!QT`(240@4\=`#%-$(#+'0!`Q
-M,G@@QT`40V]N=,=`&')O;&QFQT`<97+&0!X`Z0D!``"-@O#8__]F@_@!=A)F
-M@?I`(70+9H'Z1"$/A:L```#&0Q<$#[=5,HV"\-C__V:#^`%W1$B-0SS'0SQ2
-M;V-KQT-`97120<=`"$E$(#+'0`PW,7@@QT`04T%3(,=`%$-O;G3'0!AR;VQL
-M9L=`'&5RQD`>`.F3````9H'Z0"%T"V:!^D0A#X6!````2(U#/,=#/%)O8VO'
-M0T!E=%)!QT`(240@4\=`#%-$(#+'0!`Q-'@@QT`40V]N=,=`&')O;&QFQT`<
-M97+&0!X`ZT#&0Q<(2(U#/,=#/$1A=&''0T!#96YTQT`(97(@-\=`##(X,"#'
-M0!!3051!QT`4($-O;L=`&'1R;VS'0!QL97(`#[9#$O9C%X3`NH#___\/1,*(
-M0Q!(C4,8QT,82&EG:,=#'%!O:6['0`AT(%1EQT`,8VAN;\=`$&QO9VG'0!1E
-M<RP@QT`826YC+L9`'`!(BX4("0``2(7`=`I(BT`02(E#:.L(2(M%$$B)0VC'
-M0V``(```2(M](+Y\````Z`````")PH'B\`,``,'J!(A3<8/@#XA#<TB+?2"^
-M@````.@`````B<*!X@``\`/!ZA2(4W(E```/`,'H$(A#=$B#Q`A;7<-FD$%7
-M059!54%455-(@^P(28G]B?5(B=.X`````&9FD&:0Q@08`$B#P`%(/=````!U
-M\(EK"(/]/WX*28'%D!0``(/M0$ACQ;H`````28.\Q6@$````#X72`@``2&/%
-M28F<Q6@$``!,B6MX2(F+@````$R)@Y````!!@'U1`0^%I0(``(']A0````^/
-M@P(``$$/MH0%:`@``#S_#X1R`@``#[;`9HE$)`8/M\!(C11`2(T4D$C!X@5)
-MB=1-`Z5`"0``0?9$)$L$#X1%`@``08M$)$@E`/__`#T``/\`#X4P`@``0?9$
-M)$P$#X2<`0``0<:$).@`````00^V1"1(2(G"@^(&2(/Z!G4YJ`$/A!`!``!!
-MQD0D2@5!QD0D2P1!#[:4)($```!)BW0D6$F+?"103(GAZ`````"Z`0```.GK
-M`0``2(/Z!`^%W`$``*@!9F9FD`^$T`$``$F+7"1028M$)&!(A<`/A84```!!
-MQD0D2@-!QD0D2P2`>PX`=$^]`````$R-<V!,B??H`````$B)PDB+0VA(B5-H
-M3(DR2(E""$B)$(!Z2O]T&$DYU'030<:$).D````!N@$```#I;`$``(/%`0^V
-M0PXYZ'^Z08"\).D````!#X1-`0``3(GF3(GOZ`````"Z`0```.D]`0``@'A"
-M``^%+@$``&:#8$[]28M$)&!FQT!.(`!)BW0D8$R)[^@`````N@$```#I#`$`
-M`$F+1"10#[9`#4&`?3X`="V[``````^VZ`^VRTB)Z$C3^*@!=`^Z`````(G.
-M3(GOZ`````"#PP%!.%T^=]M!QD0D2P9!QD0D2@5F0<>$),@``````$R)YDR)
-M[^@`````N@$```#IHP```$V+9"1008!\)`X`=%U!O@````!-C7PD8$R)_^@`
-M````2(G"28M$)&A)B50D:$R).DB)0@A(B1"`>DK_="(/MD))/")T!#P-=19(
-M8\5)QX3%:`0```````"Z`````.M$08/&`44X="0.=ZX/MU0D!DB)WDR)[^@`
-M````N@$```#K(F9F9I!F9I!(8\5)QX3%:`0```````"Z`````.L%N@$```")
-MT$B#Q`A;74%<05U!7D%?PY"0D)!(BP4`````2(E'"$B)/0````##9F9FD&9F
-MD&9FD&9FD(L%``````6H`@0`PV9F9I!(A?]T&TB+%TB%TG0,2(7V=`=(BT((
-M2(D&2(G0PV9FD$B+%0````#KWV9F9I!F9I"+1A1(C80'J`($`,-F9F:04TB)
-M\TB![``!``!(BT<(2(M_$$B-M"2`````_U`X2(M#"$B)YDB+>Q#_4#@/MD0D
-M`3B$)($```!V#K@!````2('$``$``%O#<B8/MD0D`CB$)((```!WXG(6#[9$
-M)`,XA"2#````=])R!C'`Z]%FD+C_____Z\AF9I!F9I!F9I!!5%5(B?U32(L=
-M`````$B%VW4*ZWM(BQM(A=MT<TB+0Q!(A<!T<4B+50A(.U`(=>5(BW`02(M]
-M$/]22(3`=-9(BW,03(UC$$B%]G4=ZV-FD$B)[^@`````A<!X54V+)"1)BS0D
-M2(7V=$A(BT4(2(N0``$``$B%TG372#M&"'712(MV$$B+?1#_TNO-9F:09I`Q
-MP%M=05S#2,=%``````!(B5T8N`$```!(B6L06UU!7,-)BP0D2(E=&$B)10"X
-M`0```$F)+"3KRF9F9I!F9F:02(L%`````$B)!XM'$$B)/0````"%P'02BP4`
-M````B4<4`T<0B04`````\\-F9F:00515B?U32(L=`````$B%VW0Q0#A["$0/
-MMN=U"NLE9I!`.&L(=!U(BT-H2(7`9F:0=`E$B>?_T(7`=0A(BQM(A=MUW4B)
-MV%M=05S#9F:09I!,BT<82(U7&#')3#G"="-!.8B@_/__3(G`=0WK&69FD#F(
-MH/S__W0.2(L`2#G"9I!U[HE.,,.#P0'KSV9FD&:02(L5`````+C0````2(72
-M=!@QR8M"'$B+$CG!#T+(2(72=?"-@=````#SPV9FD&:02(M7&$B-3QA(.<IT
-M*CFRH/S__TB-@G#\__]U$^L=9I`YLJ#\__](C8)P_/__=`I(BQ)(.<IUZ3'`
-M\\/SPV9FD%-(BU\02(7;=!QF9I!F9I!(BT,(2(M[$/^0V````$B+&TB%VW7J
-M6\-F9F:09F9FD$B)_DB+/^D5____9F:09I"+5S"%TG@'QT<P______/#,<"%
-M]G0=,<DQTF9FD&9FD`^V!X/"`4B#QP$!P3GR=?`/ML'SPV9F9I!F9F:09F:0
-M2(L%`````$B%P'0N2(M0$$B%TG0=2#EZ$'4-9F:09I#K&D@Y>A!T$DB+$DB%
-MTF:0=?!(BP!(A<!UTO/#\\-FD$B+3QA(@\<82#GY=$-,8\KK"$B+"4@YSW0V
-M@+F`_/__!$B-@7#\__]VZ#FQJ/S__W7@A=)X'4R+@8C\__]-A<!TT$LY1,A@
-M=<GSPV9FD&:0,<##2(.YB/S__P!UM?/#D$%428G\54F-;"084^@`````28M<
-M)!A(.>MT+69FD&:0BW/X2(V[</S__X7V=!)(BX-X_/__2(M`6$B%P'0"_]!(
-MBQM(.>MUV$R)YV9FD&:0Z`````!)BT0D&$@YZ'4+D.L:2(L`2#GH=!*+2/2%
-MR9!T\%M=05RX`0```,-;74%<,<##9F9FD&9FD&9FD&9FD$%4,<!)B?Q54X"_
-MD`($``!U+4B+7Q!(A=MT(C'M9F:02(M#"$B+>Q#_D*@```!(BQL)Q4B%VW7H
-M0(3M=0<QP%M=05S#3(GGZ`````!;0`^VQ5U!7,-F9F:09F9FD&9FD$%6055!
-M5%5(B?U3Z`````!(BYTP`0``28G&2(7;#X2<````08G%2(M#"$B)VDR-I3`!
-M``!$*?"%P'X0Z8\```!(BT((1"GHA<!_.DB+0BA(A<!T!$R)8"!(B84P`0``
-M2,="(`````!(B<-(QT(H`````$B+>AC_4A!(BY4P`0``2(72=;M(B>_H````
-M`$B%VW0,2(N%,`$``$@YV'0)6UU!7$%=05[#6TB+<`A(BWT(74%<05U$*?9!
-M7ND`````6TB)[UU!7$%=05[I`````$B)[^@`````Z[EF9F:09F:054B)_5-(
-MB?-(@^P(Z`````!(BU,@2(G!2(72=!Q(BT,H2(7`=`A(B5`@2(M3($B)`DC'
-M0R``````BP-(BY4P`0``2(722(T$`4B-C3`!``!(B4,(="6)QDB+0@@I\(7`
-M?@SK,DB+0@@I\(7`?RA(C4HH2(M2*$B%TG7I2(E3*$B)&4@YG3`!``!(B4L@
-M="-(@\0(6UW#2(E3*$B)&4B-0RA(.9TP`0``2(E+($B)0B!UW4B+?0B+,TB#
-MQ`A;7>D`````9F9FD&9FD&9FD&9FD%5(B?U32(/L"$B+5B!(A=)T7DB+1BA(
-MBX\P`0``2(7`=`A(B5`@2(M6($B)`DC'1B@`````2(N%,`$``$C'1B``````
-M2(7`="=(.<%T(HM8".@`````2(M]"$B#Q`@IPXG>6UWI`````&9F9I!F9I!(
-M@\0(6UW#9F:09F:09F:054B)_5-(@^P(2(M?$$B%VW48ZRY(BT,(2(M[$/^0
-MT````$B+&TB%VW08@'MH`'3D2(M#"$B+>Q`Q]O]04&9FD.O22(/$"$B-M3@!
-M``!(B>];7>D`````9F:09F:09F:0051)B?Q54TB+7Q!(A=MU"NLT2(L;2(7;
-M="Q(BT,(2(M[$/^0X````(![:`!TY$B+0PA(BWL0O@$```#_4%!(BQM(A=MU
-MU$F+7"0828UL)!A(.>MU"NLR2(L;2#GK="J`NX#\__\!2(V[</S__W7H2(N#
-M>/S__TB+0%A(A<!TV/_02(L;2#GK==:`/0``````=05;74%<PTF-G"0X`0``
-M3(GG2(G>Z`````!!QX0D.`$```"'DP-)QX0D2`$```````!(B=Y-B:0D4`$`
-M`$R)YUM=05SI`````&9F9I!F9I!!54F)_4%454B)]5-(@^P(2(7V='U(BT4(
-M2(M]$/^0X````(!]:``/A;<```!)BUT838UE&$PYXW4.ZS]F9F:02(L;3#GC
-M=#.`NX#\__\!2(V[</S__W7H2#FKZ/S__W7?2(N#>/S__TB+0%A(A<!TS__0
-M2(L;3#GC=<U(BVT`2(7M=!M(@\0(2(GH6UU!7$%=PTB+;Q!(A>T/A7;___^`
-M/0``````=-Q)C9TX`0``3(GO2(G>Z`````!!QX4X`0```(>3`TG'A4@!````
-M````2(G>38FM4`$``$R)[^@`````ZZ!(BT4(2(M]$+X!````_U!0Z33___]F
-M9F:09F:04TB)^^@`````2(G!QT`0`````$B-@-````!(C5%02(E!2(M##"W0
-M````B4%`2(U!&$B)01A(B4$@,<!F9I!FD,8$$`!(@\`!2#V`````=?!;2(G(
-MPV9F9I!F9F:09F:02(/L&$B)'"1(B6PD"(G53(ED)!`QTCEN"$F)_$B)\W(@
-M2(GWZ`````"):!!(B<),B2!(B5@(BT,(@\`!*>B)0PA(BQPD2(ML)`A(B=!,
-MBV0D$$B#Q!C#9F:09F:09F:0B?!(C;>P````B<+I`````(M&$`-'"(/H`8E'
-M".D`````9F9FD&9F9I!F9F:09F:02(GX2(L_2(G&2(''L````.D`````9F9F
-MD&9F9I!F9I!!5D%528G]051,C6<855-(BU\83#GC=1#K6F9FD&9FD$B+&TPY
-MXW1,@+N`_/__`4B-NW#\__]UZ`^V@]3\__^H0`^%N@$``(`]``````!TT*@"
-M=<RH`0^%YP$``/:#U/S__P1UNX"+U/S__R1(BQM,.>-UM$F+72A)C6TH2#GK
-M=!%(C7OHZ`````!(BQM(.>MU[TF+;1A,.>4/A-````"0@+V`_/__!$B-O7#\
-M__]V#DB#O8C\__\`#X1R`0``2(MM`$PYY77928M=&$PYXP^$FP```$4Q]NL/
-M9F9FD&9FD$B+&T@YZW19@+N`_/__`4B-NW#\__]UZ/:#U/S__R!TWTB+@ZC\
-M__^`H]3\___;2(7`=1CI\@```&9F9I!F9I!(BP!(A<`/A-\```!(@W@8`'3M
-M2(L;0;X!````2#GK=:=)BUT823G<="5F9I!F9I#V0_`!2(VK</S__W0*2(.[
-MB/S__P!T*DB+&TPYXW7A28N%F`($`$B%P`^$NP```%M=05Q)BWT(28G#05U!
-M7D'_XP^VDX#\__^`^@1V$DB+@_#^__](A<!T%$@Y:`AT#H#J`76S]H/4_/__
-M`G2JBWTPA?\/B(4```#VA8`#```"=)8Q]DR)[^@`````2(7`2(G"=(1(.<4/
-MA'O____V@(`#```"=&B`I8`#``#]Z6;____H`````.D5_O__183V9I`/A<K^
-M__^`/0`````!9F:0#X6Z_O__Z`````#IL/[__^@`````Z83^__];74%<05U!
-M7L/H`````.D/_O__2(GN3(GOZ&CU___I:____XM%,(E",,=%,`````#I^/[_
-M_Y!!5T%6055!5%532(G[2('LB````$B%_TR+9Q@/A,P```!%,?9(BT,(2(M[
-M$$B)YO]0.`^V1"00.P4`````#XZ4````3(U[(.LG9F9FD&9FD$0Y:RA!@]8`
-MBQ4`````#[9$)!"#P@$YT(D5`````'YG]D0D$0%U$`^V!0````!$.?`/A(D`
-M``!$BVLH08.$)*`"!``!3(G_Z`````!(B<5(BT,(BS4`````2(M[$$F)V$C'
-MP0````!(B>K_4&B$P'6/2(GN3(G_Z`````!!@ZPDH`($``'K@4B+&\<%````
-M``````!(A=L/A3?___]!BX0DH`($`(/H`87`08F$)*`"!`!U0$R)Y^B$_/__
-MZS9FD`^V!0````!(Q\8`````3(GG2,<%``````````!(B1T`````:<!`0@\`
-MB04`````Z`````!(@<2(````6UU!7$%=05Y!7\-F9F:09F:09F:0055)B=5!
-M5$F)]%5(B?U32(/L"$B+7Q!(B968`@0`2(7;=0KK+$B+&TB%VW0D2(M#"$B+
-M>Q#_D/````"$P'7FQH60`@0``4B#Q`A;74%<05W#2(L=`````$B%VW099F:0
-M2(M#.$B%P'0%2(GO_]!(BQM(A=MUZDV%Y'0828M$)`A)BWPD$+X!````_U!0
-M0<9$)&@!2(M]$,>%H`($``$```#H`````$2+C:`"!`!%A<ETE$V%[7092(/$
-M"$B)[UM=05Q!7>D`````9F9FD&9FD+^@A@$`Z`````!(B>_H`````$2+A:`"
-M!`!%A<!UXNE3____9F9FD&9FD&9FD&9FD$B#[!A(B6PD"$R)9"002(G]2(D<
-M)$B+7QA)B?2#JZ`"!``!A=)X2>@`````2(7`=$I$BY.@`@0`1872=!-(BQPD
-M2(ML)`A,BV0D$$B#Q!C#2(G?2(ML)`A(BQPD3(MD)!!(@\08Z<;Z__]F9I!F
-M9I!(C7\@Z`````#KMDB+10A,B>?_D(````!(C7T@3(GFZ`````#KFV9F9I!F
-M9I!F9I!!54%454B)_5-(@^P(3(LO28M=.$V-93CK$V9FD&9FD$B->^A(BQM(
-M.6]0=$)).=QU[DB+10A(BT!02(7`=`5(B>__T$B+A9`#``!(BY68`P``2(GN
-M28U]<$B)4`A(B0)(@\0(6UU!7$%=Z0````!(BU<82(M'($B-3QA(B4((2(D0
-M2(E/($B)3QC&A[(````"Z`````#KE69F9I!F9F:005=)B==!5DF)SD%508GU
-M05152(G]4TB#[`A(BT<82(M0&$B#P!A(.<)U$>G&````2(L22#G"#X2Z````
-M@+J`_/__`4B-FG#\__]UY$0[JN#\__]UVT@[JNC\__]UTDB%VP^$CP```/9"
-M\`$/A=D```!$BZ)8_?__187D#X7)````1(N:./W__T6%VP^%N0```$B+0SA(
-MA<!U#NM29F9FD$B+`$B%P'1&2(MX&$B%_Y!T[DB+=QA(A?8/A(\```"`?D0`
-M#X2%````,<GK#P^V1D2-40%(@\$!.=!^<D@Y?,Y@=>I(QT3.8`````#KWTB)
-MW^@`````3(UE($R)Y^@`````2(7`2(G#=$!(BT4(2(G:2(M]$$V)\$R)^42)
-M[O]0:(3`N@$```!T$4B#Q`B)T%M=05Q!74%>05_#2(G>3(GGZ``````QTNO@
-M,=+KW&:0Z`````#I-____V9FD&9FD$%6055)B?5!5$F)_%532(/$@$B%]@^$
-MHP$``$F+;"002(7M=&!!BX0DI`($`$B+?1!(B>:)14!(BT4(_U`X#[9<)!!(
-MBT4(00&<)*0"!`!(BWT0_U!@2(U]((G"B=E,B>[H``````^V3"002(U]2+HH
-M````3(GNZ`````!(BVT`2(7M=:!(BPT`````NO@#``!(A<ET(&8QTF9F9I!F
-M9I"+01A(BPDYP@]"T$B%R77P@<+X`P``08N,)*0"!`!)C7PD<$R)[HT,R>@`
-M````08N,)*0"!`!)C;PDD````+H``@``3(GNZ`````!)C;PD\````+D!````
-MND@```!,B>[H`````$&+C"2D`@0`28V\)!`!``"Z*````$R)[N@`````08N,
-M)*0"!`!)C;PDT````+JP````3(GNC0S)Z`````!!QX0D:`$```$```!!QX0D
-M=`$````0``!!QX0D;`$````0``#H`````$F-O"2P````N4(A``")PDR)[N@`
-M````2(L=`````$B%VW0C9I!(BT,@2(7`=!!!BY0DI`($`$R)[DR)Y__02(L;
-M2(7;==](@^R`6UU!7$%=05[#3(MO".E4_O__9F:09F:09F:0051)B?152(LM
-M`````%-(B?OH`````(7`=!.)P$B)VI#&`@!(@\(!2(/H`77S2(,]``````!U
-M#.MQ9F9FD&9FD$B)Q4B+10!(A<!U]$B)70!(C4,83(EC",>#6`($```0``!(
-MB4,82(E#($B-0RA(B4,H2(E#,$B-0SA(B4,X2(E#0$B-@Q`"``!(B8,0`@``
-M2(F#&`(``$B-@U`"``!(B8-0`@0`6UU!7,-(B1T`````ZYUF9F:09F:09F:0
-M9F:02(/L*(`]``````)(B6PD"$R)9"00B?5(B1PD3(EL)!A)B?Q,B70D(`^$
-M%P$``$`/MOWH`````$B%P$F)Q0^$#`$``$V-="1P3(GWZ`````!(B<,QP,8$
-M&`!(@\`!2#WX`P``=?"+!0````!,B6L(3(DC@\`!B04`````B8/H`P``2(V#
-MR`,``("+@`,```%`B&L02(F#R`,``$B)@]`#``!!BT48A<!T*4B-@_@#``!(
-MB4,@08M%&(7`=!:)PDB)V,:`^`,```!(@\`!2(/J`77O2(V#H`,``,=#-`(!
-M``#'0S#_____2(F#H`,``$B)@Z@#``!(C8.P`P``2(F#L`,``$B)@[@#``!)
-MBT5(2(7`=`E(B=__T(7`=55)BTPD($B-DY`#``!)C40D&$F)5"0@2(F#D`,`
-M`$B)BY@#``!(B1'K#$"`_@$/A-_^__\QVTB)V$B+;"0(2(L<)$R+9"003(ML
-M)!A,BW0D($B#Q"C#2(G>3(GW,=OH`````.O1051(BQ4`````54B)_4@Y^E-U
-M".G3````2(G"2(72=`](BP)(.>AU\$B+10!(B0)(BT482(U=&$@YV'099F9F
-MD$B-N'#\___H`````$B+11A(.=AUZTB+12A,C64H3#G@=#)(C9W0````9F9F
-MD&9FD$B-<.A(B=](BT8@2(M6&$B)0@A(B1#H`````$B+12A,.>!UW("]D`($
-M``!U*4B+'0````!(A=MT'69F9I!F9I!(BT-`2(7`=`5(B>__T$B+&TB%VW7J
-M2(M=$$B%VW07D$B+0PA(BWL0_Y#H````2(L;2(7;=>I;74%<PTB+!TB)!0``
-M``#I-?___Y"0D)"0D$B+5R`QP,8$$`!(@\`!2(/X4'7R2(U"$$B)$DB)4@A(
-MQT(H`````$B)>C!(B4(02(E"&#'`2,=".`````##9I!(BT=(BQ4`````2(/H
-M*$@!T,-F9F:09F9FD&9FD&9FD$B+1R`QTDB+"$@YP7092(L12(M!"$B)0@A(
-MB1!(BU$82(D)2(E)"$B)T,-F9I!FD("^L`````!(BU<@=1(/MX:8````2`.&
-MD````$B)1UB#0B`!2(M':$B+OX````!,BYB8````0?_C9F9FD&9F9I#VAX`#
-M```(2(GZ2(M'('0"\\/'0$0`````2(M':$C'Q@````"`CX`#```(2(N_@```
-M`$R+F(@```!!_^-F9F:0]H>``P```;C_____="%%A,!T&@^WPL'@"87`=!!(
-MF)#&`0!(@\$!2(/H`77S,<#SPV9F9I!F9F:09F9FD&9FD/9'9$!(QT=(````
-M`'5)2(M7.$B%TG1*,?8QR>L.9F:02(L2@\$!2(72=")(@WH8`'7N2(M"$$@!
-M1TA(BT(02(L22#GP2`]'\$B%TG7>@_D#?P5(B7=`PTC'1T``````D,,Q]NOM
-M9F9FD&9F9I!F9I!(8_9(`?Y(.?=S'$B)\6:0#[91_@^V0?^(4?^(0?Y(@^D"
-M2#G/<NE(.?=T*`^V!SP@=2-(B?KK!P^V`CP@=1I(@\(!2#GR=?#&!P!(@\<!
-M2#GW=?3SPTB)^H3`="%F9I!(@\(!/"!T*@^V0O^(!TB#QP%(.=9T!P^V`H3`
-M=>)(.?YTT<8'`$B#QP%(.?=UN9#KPD@Y\G3G#[8"A,!F9F:0=+<\('2S#[9"
-M_X@'2(/'`>O%9F9FD&9F9I!F9I!F9I!(BT<@QT!$`0```,-F9F:054B)_5-(
-M@^P(]D=D`G4R2(M?.$B%VW082(M[&$B%_W0'2(M'"/]0,$B+&TB%VW7HQX7H
-M`````````$B#Q`A;7</H`````.OH9F9FD&9F9I!3]D=F`DB)^TB+1R!T!O9`
-M2`)T#(-`1`%;PV9FD&9FD#EP1'+O2(L_O@$```#H`````$B%P$B)PG3>#[:`
-ML0```$B)6E!(B==(B5I8QH*P````!,:"L@````!(QX+(`````````(/@SX/(
-M((B"L0```%OI`````&9FD&9FD&9FD%-(B?M(BS^^`0```.@`````2(7`2(G"
-M=&#V0V8"=6'&@+`````#2,>`H`````````#&@)L```!`9L>`E```````9L>`
-ME@``````9L>`F```````QH":````0&;'@)```````&;'@)(````!`&;'@)P`
-M`````$B)6E!;2(G0PV:0QH"P`````HL%`````(F"F`````^W!0````#&@I``
-M```&QX*4`````````,:"D0````!FB8*<````Z[IF9I!FD$B#[!A(B5PD"$B)
-M;"002(G[2(MO(.@F____2(G"N/____](A=)T)4C'@L@`````````@$U(`4B)
-MUDB+0VA(B[N`````_Y"8````,<!(BUPD"$B+;"002(/$&,-F9I!FD$%428GT
-M55.`?Q`$2(G[=E6`?T0`=$HQ[>L59F:09F:0#[9#1(U5`4B#Q0$YT'XQ2(M\
-MZV!(A?]TY_:'@`,```%TWDR)YN@`````#[9#1(U5`4B#Q0$YT'_69F9FD&9F
-MD%M=05S#=#CV@X`#```!9I!T[DB)W^AF_O__2(7`=.%!@P0D`4R)8%A(B<=(
-MQX#(`````````%M=05SI`````$B+7SCV@X`#```!=+3KQ&:0Z0````!F9F:0
-M9F9FD&9FD$B#[!A(B5PD"$B);"002(M?6$B++^@`````BP.#Z`&%P(D#=`](
-MBUPD"$B+;"002(/$&,-(C7,(2(GO2(M<)`A(BVPD$$B#Q!CI`````&:055-(
-M@^P(2(LM`````,<%``````````!(A>UU#>LP9I!(BVT(2(7M="6+'0````#_
-ME9`````YPW/G_Y60````2(MM"(D%`````$B%[77;2,?'`````(,%`````"CH
-M`````$B#Q`@QP%M=PV9FD&9FD$B#[!A(B5PD"$B);"002(MO4$B+72`/ME-(
-MB="#X/Z(0TB`O[(````!=$7H`````(M#0(7`=`](BUPD"$B+;"002(/$&,-(
-MBWT`2(US*,=#0`$```!(BUPD"$B+;"002(/$&$B#QUCI`````&9F9I"#XOR(
-M4TCKLV9F9I!F9F:02(M'(("G@`,``/?'A\@`````````BU!`A=)T!//#9I!(
-MBS](C7`HQT!``0```$B#QUCI`````&9FD&9FD&9FD%-(BU\@2(GX2(G&2(L[
-M2(''$`$``.@`````2(L[2,>#T`````````!(C;/0````2(F;V````$C'@^``
-M````````6TB#QTCI`````&9FD&:054B)_5-(B?-(Q\8`````2(/L"$B+/^@`
-M````2(G!2(M%.$B%P'0;2#G82(U5.'4'ZQ=(.=AT$DB)PDB+`$B%P'7P2(/$
-M"%M=PTB+`TB)WDB)STB)`DB#Q`A;7>D`````2(/L.$B)7"0(2(EL)!`Q[4R)
-M="0H3(E\)#!)B?Y,B60D&$R);"0@2(GS2(M/.$F)UTB%R70@2(G-,<!F9I!F
-MD$B#?1@!2(MM`(/8_TB%[77O@_@#?B9(B>A(BUPD"$B+;"003(MD)!A,BVPD
-M($R+="0H3(M\)#!(@\0XPTF-/!])B<SK&$DY7"0(#X2R````38LD)$V%Y`^$
-MG0```$F#?"08`'7@28M4)`A(.=IWX4F+="0028G]2(T$%D@YQW?02#G:#X21
-M`0``<\5)BSY(Q\8`````Z`````!(B<?H`````$B%P$B)P@^$:/___S'`Q@00
-M`$B#P`%(@_@@=?))BT0D"$B)0@A(B=A)*T0D"$F)7"0(2(E"$$F+!"1(B0))
-MBT0D$$@K0A!)B10D23G'28E$)!`/@FX!``!,B>7I%/___TF+!"1(A<!T.+H!
-M````ZPA(BP!(A<!T($B#>!@`D'3P2#E8"'7J28MT)!!(.7`03`]'X(/"`>O8
-M@^H!#X_3_O__28M4)!!)B<U).==W$NF0````38MM`$V%[0^$M/[__TF#?1@`
-M=>Q(B=!)`T0D"$DY10AUWDD#51!).=</AY+^__])BSY(Q\8`````Z`````!(
-MB<?H`````$B)PC'`Q@00`$B#P`%(@_@@=?),B?A)`T0D"$F)10A)BT4020-$
-M)!!,*?A)B44028L$)$B)U4B)6@A,B7H02(D"28D4).DQ_O__28L^2,?&````
-M`.@`````2(G'Z`````!(A<!(B<(/A`[^__\QP,8$$`!(@\`!2(/X('7RZ[!)
-M.?</A-?^__])BSY(Q\8`````Z`````!(B<?H`````$B%P$B)P@^$T/W__S'`
-MQ@00`$B#P`%(@_@@=?))BT0D$$R):@A,*?A(B4(0ZT=)BSY(Q\8`````Z```
-M``!(B<?H`````$B)PC'`2(72=#[&!!``2(/``4B#^"!U\DR)^$D#1"0(2(E"
-M"$F+1"003"GX2(E"$$F+!"1,B>5-B7PD$$B)`DF)%"3I3_W__TF+'"1)BSY(
-MQ\8`````2(M#"$F)1"0(2(L#28D$).@`````2(G>2(G'Z`````#I'/W__V9F
-MD&9FD$%42,?&`````%5(B?U32(L_Z`````#V160(28G$=1Q(BW4X2(7V=!-(
-MBQY,B>?H`````$B%VTB)WG7M2(M%:$B+O8````#_D(````!;2(M]>$B+M8``
-M``!=05Q(@\<@Z0````!F9F:09F9FD&9F9I!54TB)^TB#[`A(BU<X@*>``P``
-M_DB%TG0?9F9FD&9FD$B+0AA(A<!T!X"@@`,``/Y(BQ)(A=)UZ$B)WK\!````
-MZ`````!(BSO'@^@````!````2(''$`$``.@`````2(7`2(G%=&;'``$```!(
-MQT`(`````$B)11!(QT`8`````$B)6"!(BULX2(7;=#)F9I!(BT,82(7`=0KK
-M'&9FD&:02(GX2(MX&$B%_W7T2(GN2(G'Z`````!(BQM(A=MUT8M%`(/H`87`
-MB44`=`=(@\0(6UW#2(/$"$B)[UM=Z;_Z__]F9F:09F9FD&9F9I!F9I!(@^P8
-M2(E<)`A,B60D$(G328GT2,?&`````.@`````C0S;3(GF2(M<)`A,BV0D$$B)
-MQ[H@````2(/$&.D`````2(/L6(/_!TB);"0X3(ED)$!(B?5,B6PD2$B)7"0P
-M08G\3(ET)%!)B=5W54&)_D+_)/4`````B[O(````A?]U0$B+0PC'@\@````!
-M````2(VSL````$B->5A(BT!82(F;N````$C'@\``````````2(F#L````.@`
-M````9F:09I!(BUPD,$B+;"0X3(MD)$!,BVPD2$R+="102(/$6,-(BUX@OP,`
-M``!(QT8@`````.@`````2(E=(.O&2(GWZ`````!(BU@028G$2(7;=0KK$DB+
-M&TB%VW0*2#EK$&9F9I!U[DB->TCH`````$B%P&:0=(Y)C7PD2$B)6!A$B6@@
-M2,<``````$B)0`A(B<9(QT`0`````.@`````Z6'___](B??H`````$B)P4B+
-M0!A(C5$82#G0=17I1/___V9F9I!(BP!(.=`/A#3___^`N(#\__\!2(V8</S_
-M_W7D3#FH\/S__W7;08/\!P^'$?___Y!"_R3U`````$B+0WA(B>9,B>](BT`(
-M_U!X#[9$)`Z(0V(/ME0D"@^V0V:#X@$!TH/@_0G0B$-FZ=3^__](BT,@@*.`
-M`P``[XMP0(7V#X6^_O__2(G&2(UY6,=`0`$```!(@\8HZ`````#IHO[__X"+
-M@`,``!#IEO[__TB+0PA(B=__4##IA_[__V9F9I!F9I!(@^P82(GX2(E<)`A,
-MB60D$$B)QDB+7QA$BV<@2(U[2.@`````2(G91(GF2(G?3(MD)!!(BUPD"$C'
-MP@````!(@\08Z0````!F9F:09F9FD$B![!@"``"`/0``````2(F<)`@"``!(
-MB:PD$`(``$B)^W4=2(N<)`@"``!(BZPD$`(``$B!Q!@"``##9F:09I`/MD=D
-M0;@!````2(GAN@$```"^"0```(/(`X/@^XA'9.@`````A<!U2($\)'EC9VQT
-M7/9#9`%TJTB+:SA(A>V0=")(BSM(Q\8`````Z`````!(B>Y(B<?H`````$C'
-M0S@`````2(M#4$B)0RCI<O___X"C@`,``/Y(B=Z_`0```.@`````@$MD`>E5
-M____O@`"``!(B>?H`````(3`=9,/MDPD!`^V@X`#``")RH/@_<#J!(/B`@G0
-M]L$0B(.``P``=`P/MD0D!8!+9("(0V/V1"0'`707#[9398G(P.@"@^`"@\H!
-M@^+]"<*(4V7V1"0'`G05#[9398T$"8/@"(/*!(/B]PG"B%-E]D0D!PAT%0^V
-M0V7!X02#X2"#R!"#X-\)R(A#9?9$)`<$#X0"____#[9390^V1"0$@\I`@^`!
-MP>`'@^)_"<*(4V7IX_[__Y!52(U/.%-(B?M(@>P(`@``#[9!+(/@`RP!#X0@
-M`@``O^____]`(GMD2(GE2(G@0(A[9$B-E"0``@``Q@``2(/``4@YT'7L]D$L
-M`@^%[P$``$B+0RB^]____\<$)%]W85(A_D"(<V1(B40D!(!Y+`!Y#0^V0V.`
-M3"0,$(A$)`WV02T!=!T/ME-E#[9$)`R`3"0/`<'B`H/@]X/B"`G0B$0D#/9!
-M+01T'`^V4V4/MD0D#(!,)`\"T.J#X/N#X@0)T(A$)`SV02T0=!T/ME-E#[9$
-M)`R`3"0/",#J!(/@_8/B`@G0B$0D#/9!+4!T&@^V1"0,#[9398!,)`\$P.H'
-M@^#^"="(1"0,2(%[0/__'P!W"[[S____(?Y`B'-D]D$L(`^$)`$``$B+2SA(
-MA<ET/#'V2(-Y&`!T*TACQDB+40B#Q@%(C01`2(U$Q0!(B5`02(M1$$B)4!A(
-MBU$82(M20$B)4"!(BPE(A<EUQ@^V0V:^``(``$B)Y\:%_P$```&#X`&(A?X!
-M``#H`````/?813'`2(GAB(4``0``2(MS4+H!````2(G?2('N```"`$B!Y@``
-M_O_H`````$B+<SA(A?9T1#'_2(M6&$B%TG0Q2(M#4$R+0D!(8\](C0Q)@\<!
-M2HT4`$@M```"`$@E``#^_TB!Z@`(``!(*<)(B53-($B+-DB%]G6^O@`"``!(
-MB>?&A0`!````Z`````#WV$4QP$B)X8B%``$``$B+<U"Z`0```$B)WTB![@`(
-M``#H`````$B!Q`@"``!;7<-`P.X"@^8!0(AT)`[IR_[__V9FD&9FD%-(B?M(
-MBS](Q\8`````Z`````!(B<?H`````$B)PC'`2(72="C&!!``2(/``4B#^"!U
-M\DB+0RA(B4(02(M#*$B)4SA(B4-(2(E#0%O#2(G?6^D`````9F9FD&9FD&9F
-MD$B![$@#``"`/0`````"2(FL)"`#``!,B:0D*`,``$B)_4B)G"08`P``3(FL
-M)#`#``!,C6<X3(FT)#@#``!,B;PD0`,```^$JP$``$B+=U!,C7PD($&X`0``
-M`+H!````3(GY2('N``@``.@`````A<!!B<4/A!T#``!(BW500;@!````3(GY
-MN@$```!(B>](@>X```(`2('F``#^_^@`````A<!!B<8/A"\#``!!@_W_#Y3`
-M08/^_P^$Q04``$6%]@^51"07='1%A>UU;TB+=5!!N`$```!,B?FZ`0```$B)
-M[TB![@`(``#H`````(7`08G%=$>`I8`#``#^2(GNOP$```#H`````(!-9`'I
-MGP$``+X``@``3(G_Z`````"$P`^%[0(``$&`O_\!````=09!O?[____&1"07
-M`$&!/U]W85(/A#(#``!(BW502('N```"`$B)\$C!Z"!(A<`/A<0"``"`360!
-M#[8%`````#P"#X2%````+`$/A&(%``#VA8`#```!='B`I8`#``#[28V7``(`
-M`$R)^,8``$B#P`%(.=!U]#'V0;@!````3(GYN@$```!(B>_H`````(!\)"!%
-M#X3.!```@+PD'@(``%5U+H"\)!\"``"J=20QP$:+A#C*`0``187`=1%(@\`0
-M2(/X0'7IZPE,C7PD((!-9`+V160"=`T/MD5D@\@!@^#[B$5D0?9$)"P!=#1(
-MBUTX2(7;="-(BWT`2,?&`````.@`````2(G>2(G'Z`````!(QT4X`````$B+
-M15!(B44H08!\)"P`#X@6`0``0?9$)"T!#X7?````0?9$)"T$#X6G````0?9$
-M)"T0=6Y!]D0D+4!T+L9$)"`%#[9%94R)_L9$)"D`P.@'B$0D*$B+16A(B[V`
-M````_Y#`````9F:09I!(BYPD&`,``$B+K"0@`P``3(ND)"@#``!,BZPD,`,`
-M`$R+M"0X`P``3(N\)$`#``!(@<1(`P``P\9$)"`$#[9%94R)_L9$)"D`P.@%
-M@^`!B$0D*$B+16A(B[V`````_Y#`````Z6'____&1"0@`P^V165,B?[`Z`.#
-MX`&(1"0H2(M%:$B+O8````#_D,````#I+?___\9$)"`"#[9%94R)_M#H@^`!
-MB$0D*$B+16A(B[V`````_Y#`````Z?;^___&1"0@``^V16-,B?Z(1"0H2(M%
-M:$B+O8````#_D,````#IQ/[__P^VG"0?`@``O@`"``!,B?_H`````(MT)"`/
-MMM!(Q\<`````,<")V>@`````@7PD(%]W85(/A"4#``!!O?[____IGOS__T$/
-MMI__`0``O@`"``!,B?_H`````$&+-P^VT$C'QP`````QP(G9Z`````!!@3]?
-M=V%2#X3^_/__187M#X6A_/__0;W_____Z9;\__^!Y@``_O]!N`$```!,B?FZ
-M`0```$B)[^@`````A<`/A:G\__]!@3]?=V%2#X4+_?__O@`"``!,B?_H````
-M`(3`#X0I!0``08$_7W=A4@^%Z?S__[X``@``3(G_Z`````"$P`^%U/S__T&`
-M?PX`#[9%9$R)YDC'QP`````/E<*#X/O!X@()T(A%9`^V169!@+_^`0````^5
-MPH/@_@G0#[;2B$5F,<#H`````$B+15!(B>](+0```@!()0``_O](B44HZ+/Z
-M__]!]D<,$'0,@$UD@$$/MD<-B$5C0?9'#P%T&@^V565!#[9'#(/*`<#H`H/@
-M`H/B_0G"B%5E0?9'#P)T&0^V565!#[9'#(/*!`'`@^`(@^+W"<*(565!]D</
-M"'0:#[9594$/MD<,@\H0P>`$@^`@@^+?"<*(565!]D</!'0:#[9594$/MD<,
-M@\I`@^`!P>`'@^)_"<*(565(QT0D&``````QVTJ#?#L8``^%=0$``$B#PQA(
-M@_M@=>J`?"07``^$60(``#')2H-\.1@`="=*BU0Y($B+15!(@<(`"```2"G"
-M2"T```(`2"4``/[_2`'"2HE4.2!(@\$82(/Y8'7'O@`"``!,B?]!QH<``0``
-M`.@`````]]A%,<!,B?E!B(<``0``2(MU4+H!````2(GO,=M(@>X```(`2('F
-M``#^_^@`````2(MU4$&X`0```$R)^;H!````2(GO2('N_P<``$@!WN@`````
-MA<`/A!\!``!(@\,!2(/[!'7*2(-\)!@`#X3#`@``@$UD0$B)[^@`````Z<S[
-M__^$P`^$,_K__V9FD&9FD.E?^O__@'PD(5)F9I!F9I`/A2'[__]!N`$```!,
-MB?FZ`0```+X!````2(GOZ`````"`?"0@4`^%^_K__X!\)"%-#X7P^O__Z1_[
-M__]F9F:0@#T```````^%D?K__V9FD.D&^___O@`"``!,B?_H`````(3`#X1O
-M^?__Z<'\__](BWT`O@0```#H`````$B%P$B)1"08#X2%^___2HM4.QA*BW0[
-M$$B)[^A#[?__2(7`2(G!#X1(`P``2(M4)!A%A?9(B6HX=7Q*BT0[($B)0D!(
-MBU0D&$B)2DA(BT$02(E1&$B)0BCI(/[__TB+15!(B>]%,<!,B?FZ`0```$@M
-M```"`$@E``#^_TB-=`,!Z`````!(BW502,?'`````$B-A@``_O](C;0>`?C_
-M_T@E``#^_TB-5`,!,<#H`````.F(_O__187M=8A*BU0[($B+15!(@<(`"```
-M2"G"2"T```(`2"4``/[_2`'"2(M$)!A(B5!`Z5C___]%A>T/A%3^__]!@+__
-M`0````^$MP```#')2H-\.1@`="=(BT502(G"2@-4.2!(+0```@!()0``_O](
-M@>H`"```2"G"2HE4.2!(@\$82(/Y8'7'O@`"``!,B?]!QH<``0```.@`````
-M]]A%,<!,B?E!B(<``0``2(MU4+H!````2(GO,=M(@>X`"```Z`````!(BT50
-M0;@!````3(GYN@$```!(B>](+0```@!()0``_O](C70#`>@`````A<!T?DB#
-MPP%(@_L$=<?IC_W__TC'QP`````QP.@`````3(G_O@`"``!!QH?_`0```4'&
-MAP`!````Z`````#WV$4QP$R)^4&(AP`!``!(BW50N@$```!(B>](@>X```(`
-M2('F``#^_^@`````Z>O^__]!]D0D+`0/A"?X___I+/W__TB+=5!(B>]%,<!,
-MB?FZ`0```$B![O\'``!(`=[H`````$B+15!(Q\<`````2(V4&`'X__](+0``
-M`@!()0``_O](C70#`3'`Z`````#I,?___TB-G"0@`@``28UW$+KP````2(G?
-M2(/#".@`````2(V$)!@#``!(B40D".L+2(/#&$@[7"0(=&-(@SL`=.](BW,(
-M0;@!````3(GYN@$```!(B>^#YO_H`````(7`#X7\]O__3(G_Z`````!!@3_T
-M%GA:#X28````2(MS"$4QP$R)^;H!````2(GOZ`````"%P'2:Z<?V__]F9I!(
-MBW500;@!````3(GYN@$```!(B>](@>X```(`@>8``/[_Z`````"%P`^%E?;_
-M_TB+=5!%,<!,B?FZ`0```$B)[TB![@```@!(@>8``/[_Z`````"%P`^%:/;_
-M_^G<^?__2(M\)!CH`````&9FD&:0Z0OX__^^``(``$R)_^@`````Z5;___]F
-M9I!F9I!F9I!!5TF)][X!````059!54F)_4%455-(@^QX2(M_&(E4)`SH````
-M`$B)Q4F+10A(C70D0$R)__]0>$B+A9@#``!(BY60`P``2(E""$B)$$B+10!(
-MBU@82(/`&$@YPP^$GP```$R-="00ZQMF9F:09F:02(M%`$B+&TB#P!A(.=@/
-MA'T```"`NX#\__\!3(VC</S__W7<2(NSZ/S__TF+10A(.T8(#X0G`0``3(GO
-MZ`````"#^`!\2W6X28M%"$F+O"2`````3(GV_U!X#[94)$H/MD0D&M#JT.B#
-MX@&#X`$YPG^.?!T/MD0D'#A$)$QW@9!R#P^V1"1-.D0D'0^';____TB+4PA(
-MC860`P``2(F=D`,``,=%-`$```!(C;V(````OB@```!(B4,(2(D"@(V``P``
-M`4F+10A,B;V`````3(EM>$B)E9@#``!(B45HBT0D#(E%<$B+1"1`2(E%4$B)
-M12@/MD0D3HA%8@^W1"149HE%8`^V5"1*#[9%9H/B`0'2@^#]"="(16;H````
-M`$B+16A(B[V`````2(UT)$#_4'CV1"1*`4B+1"18=0GV@``!```$=0A(B>_H
-M`````$B#Q'A(B>A;74%<05U!7D%?PTB+@``!``!(A<`/A,G^__](BW8028M]
-M$/_0Z<+^__^04X!_$`%(B?MT!UNX_____\.`/0`````"=/!(BT=02"T```(`
-M2"4``/[_2(E'*.B]\O__@&-D],=#,/____](B=_H`````%LQP,-F9I!F9I!(
-M@^P8A=)(B6PD"$R)9"002(G]2(D<)$F)]'AHZ`````!(A<!(B<-T3@^V0&1(
-MBVT8J`)U;8`]``````!T&J@!=6KV0V1$=02`2V0D1(N-V`$``$6%R71>2(G>
-M2(ML)`A(BQPD3(MD)!"_`@```$B#Q!CI`````$B+10A,B>?_D(````!(C7T@
-M3(GF2(L<)$B+;"0(3(MD)!!(@\08Z0````!(B=_H`````.NL2(G?Z`````#K
-MC$B-M<`!``!(C7U(QX78`0```0```$C'A<`!````````2(FMR`$``$C'A=`!
-M````````Z`````#I9O___V9F9I!F9F:09F:09F:0055!5$F)_%532(/L"$B+
-M;SA(BU](2(M5.$B%T@^$-@$``$B)T#'V2#G8=`Q(BTL(2#E("$@/1/!(BP!(
-MA<!UYTB%]@^$A@```$B+?A!(BTL02#G/<@KK-$B+$DB%TG0Y2(-Z&`!U\4B)
-MR$@#0PA(.4((=>1(BT(02`-#$$@#?@A(*T802(EZ"$B)0A!(B=Y(B>_H````
-M`.L82(M&"$@#1A!(*7L02,=#&`````!(B4,(@$UD$$R)Y^@`````2(/$"$B)
-M[UM=05Q!7>D`````13'MZPA(BQ)(A=)T+DB#>A@`=?%(BWL(2(M*"$B)^$@#
-M0Q!(.<%T64@#2A!(.<](#T3R2(L22(72==)(A?9(QT,8`````'082(M&"$B)
-M[TB)0PA(BT802`%#$.@`````387M#X1Y____28M%$$@!0Q!,B>Y(B>_H````
-M`.EA____28G5Z7S___](QT,8`````.E,____9F9FD&9F9I!F9I!!54F)_3'_
-M051)B?154TB#[`A(A=(/A)@```!(BWI(2(7_#X2+````28M-.$B%R71R,>U%
-M,<#K#4@YPG012(L)2(7)=$5(BT$82(7`=>I(BW$023GT=PY(A>UT!D@[=1!S
-M`TB)S4B%P'732(7_9F:0=,M(BT<(2`-'$$@Y00A,#T3!2(L)2(7)=;M-A<!T
-M#TF+0!!(`T<023G$2`]&[TB%[74<,=M(@\0(2(G86UU!7$%=PTTY94`/@VO_
-M___KY$F+?0"^!````.@`````2(7`2(G#=-!,B6@X28M%4#'V28M5.$@M```"
-M`$@E``#^_TB%TDB->`%T($B+0AA(A<!T#TB+2$"X`0```"GYT^`)QDB+$DB%
-MTG7@,<FX`0```-/@A<9T'X/!`8/Y!'7M2,=#0`````!(B=\QV^@`````Z6'_
-M__](8\%(`?A(A<!(B4-`=.),B6,H2(MU"$R)XDR)[^BJX___2(7`=,I(B5@8
-M2(E#2$R)[T&`3600Z`````#I(/___V9F9I!F9F:09F:04TB)^TB+0SA(A<!U
-M"^M;D$B+`$B%P'122(MX&$B%_Y!T[DB+=QA(A?9T.(!^1`!T,C')ZP\/MD9$
-MC5$!2(/!`3G0?A](.7S.8'7J#[9&1(U1`4C'1,Y@`````$B#P0$YT'_AZ```
-M``#KFDB)WV9FD.@`````2(M#:$B+NX````#_D,@```!(B=];Z0````"054B)
-M_5-(@^P(2(M?.(!G9+](A=MT0DB+>QA(A?]T!>@`````2(L;2(7;=>I(BT4X
-MZP-(BP!(A<!T'DB+>!A(A?]T[TB#?Q@`=>CH`````$B+13A(A<!UXDB#Q`A(
-MB>];7>D`````9F9FD&9FD&9FD$%62(GX2(G&055!5%533(MO($F-O1`!``!-
-MC648Z`````!)BUT80<>%V`$```````!,.>-U"NLT2(L;3#GC="R`NX#\__\!
-M2(V[</S__W7H]H/4_/__0'3?]D/P`739Z`````!(BQM,.>-UU$F+72A)C6TH
-M2#GK=!AF9F:09F:02(U[Z.@`````2(L;2#GK=>])BVT83#GE#X3@````9I"`
-MO8#\__\$2(V]</S__W8.2(.]B/S__P`/A'H!``!(BVT`3#GE==E)BUT83#GC
-M#X2J````13'VZP]F9F:09F:02(L;2#GK=%F`NX#\__\!2(V[</S__W7H]H/4
-M_/__('3?2(N#J/S__X"CU/S__]M(A<!U&.GL````9F9FD&9FD$B+`$B%P`^$
-MV0```$B#>!@`=.U(BQM!O@$```!(.>MUITF+71A).=QU#NLR9F9FD$B+&TPY
-MXW0F1(N3H/S__TB-NW#\__]%A=)X'/9#\`%UW^@`````2(L;3#GC==I;74%<
-M05U!7L/V0_`!=,,/MH.`_/__/`0/AGX```!(@[N(_/__`'6J]H/0_O__0'6A
-M2(N#\/[__TB%P'0&2#EX"'6/#[:#M/S__X7`?B^#Z`$QR4B#P`%(BU3/8$B%
-MTG03@'H0!'8-]H)@`@``0`^%7O___TB#P0%(.<%UVN@`````Z4O___]%A/8/
-MA=+^__]FD.@`````Z<;^__\L`69F9I`/A2K____V@]3\__\"9F:0#X0:____
-MZ\/H`````&9FD.EY_O__9F9FD&9F9I!F9I!!5$F)_$B-OQ`!``!54^@`````
-M2(7`2(G%=&I)BUPD&$R)8"!)@\08QP`!````2,=`"`````!(B4402,=`&```
-M``!,.>-U$>LO9F9FD&9FD$B+&TPYXW0@@+N`_/__`4B-NW#\__]UZ$B)[N@`
-M````2(L;3#GC=>"+10"#Z`&%P(E%`'0%6UU!7,-;2(GO74%<Z1K]__]F9F:0
-M9F:09F:02(/L&$B);"0(2(D<)$B)_4R)9"002(M?(,=#0`````#VAX`#```8
-M#X6C````1(NGR````$6%Y`^%DP````^V0TBH`0^%AP```*@"3(UC$'0?3#EC
-M$'4%2#D;=!U(B>^0Z-O;___V0T@!=65F9I!FD$B+2Q!,.>%U:@^V16(Y0R!R
-M%NM,2(G62(GOZ"'8__\/MD5B.4,@<SA(B>_HX-?__TB%P$B)PG0H#[>`L```
-M`&8E_S!F/00@=<M(.1MU8?9%9@)TP(!+2`+KNF9FD&9FD$B+'"1(BVPD"$R+
-M9"002(/$&,-$BUL@187;=>1(BQ%(BT$(2(GO2(MQ&$B)0@A(B1!(B4D(2(D)
-M2(L<)$B+;"0(3(MD)!!(@\08Z9'7__](B=?&@K(````!Z`````!(B>_H2M?_
-M_TB)PNE&____9I!(@^P82(D<)$B);"0(2(G[3(ED)!!,BV=0Z`+7__^`N[``
-M```$2(G"28ML)"`/A(T```!(BX/(````QT5$`````$B)*L="(`````!(B5H8
-M2,>#R`````````!(B4(02(M%"$B)50A(B1!(B4((00^V1"1B.44@<P>+14"%
-MP'032(L<)$B+;"0(3(MD)!!(@\08PTF+/"1(C74HQT5``0```$B+'"1(BVPD
-M"$R+9"002(/$&$B#QUCI`````&9F9I#V@[$````P=`KV14@"#X1@____QH.R
-M`````4B)WTB+;"0(2(L<)$R+9"002(/$&.D`````9F9FD&9F9I!F9F:02(/L
-M*$B);"0(3(ED)!!(B?U,B6PD&$R)="0@2(D<).C\U?__3(MU4$F)Q4V+9B!!
-M@VPD(`$/MH6R````/`UT4#P1#X3(````/`MT9#P09I`/A.````!)BT402(GO
-M2(F%R````.@`````08M$)$"%P'1H2(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@
-M2(/$*,.0@+VP`````'6]@+VS``````^%NP```,:%LP````%F9I!)C40D$,:%
-ML@````!)BU0D&$V);"0828E%`$&+1"1`28E5"$R)*H7`=9A)BSY)C70D*$''
-M1"1``0```$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#QUA(@\0HZ0````!,
-MB??HZ-C__X7`=0L/MH6S````/`%V0P^VA;(````\$`^%(/___X"]L`````,/
-MA!/___])BUX@3(GV28EN(+\#````Z`````!)B5X@Z?7^___&A;(````0Z\R#
-MP`&(A;,```#I./___Y"0D)"0D)"02(LU`````$B%]G1#2(M6&$B-3AA(.<IT
-M+DB-@G#\__\YN.@#``!U%^LI9F:09F:02(V"</S__SFXZ`,``'022(L22#G*
-M=>E(BS9(A?9UO3'`\\/SPV9F9I!F9F:09F:0@'\$`'4,,<"!/WL!```/E\##
-M,<"!/WL!```/E\##9I`/M@</M@XXR'0:ZRQF9F:0#[97`0^V1@$XPG412(/'
-M`4B#Q@&$P'7H,=*)T,,/OL`/OM(IPHG0PP^^T`^^P2G"Z^AF9F:09F9FD&9F
-MD&9FD$%728GW059!B?Y!54%455-(@>R8````3(LM`````$V%[71#3(UD)!`Q
-M[4F+71!(A=MT*DR)9"0(2(M#"$B+>Q!,B>;_4#B`?"0C`'0(1#GU="N#Q0%(
-MBQM(A=MUVTV+;0!-A>UUQ#';2('$F````$B)V%M=05Q!74%>05_#387_=.8/
-MME0D)T&+!SG0?-I(BQM(A=MTTBG02(M[$$B+="0(08D'2(M#"/]0.(!\)",`
-M=-#KLF9F9I!F9F:09F9FD$%7059)B?Y!54%428G454B)S5-(@>RH````2(L%
-M`````,<"`````$B)="0(QP$`````2(7`2(E$)!`/A)X```!!O?_____'1"0<
-M`````$B+1"002(M8$$B%VP^$D````$B%[4$/E<?K'V9F9I!F9I!(BQL/MD0D
-M-T$!!"2+1"0<`44`2(7;=&A(BT,(2(M[$$B-="0@_U`X2(M#"$B+@`@!``!(
-MA<!T#T6$_W0*2(M[$/_0B40D'(!\)#,`=!-!QP0D`````$&#Q0''10``````
-M3#GS=9I(BT0D"$2)*$B!Q*@```!;74%<05U!7D%?PTB+1"002(L`2(7`2(E$
-M)!`/A4C____KUF9F9I!F9F:0055!5%4Q[5-(@>R(````3(LE`````$V%Y'0Q
-M28M<)!!(A=MT'DB+0PA(BWL02(GF_U`X@'PD$P%(BQN#W?](A=MUXDV+)"1-
-MA>1USTB!Q(@```")Z%M=05Q!7<-F9F:005=!5D%505152(G54TB![-@```")
-M="0,2(UT)`SHKOW__TF)QKC_____387V#X3Y````38MF&#'`9F9FD&9FD,8$
-M*`!(@\`!2(/X1'7R28M&"$B-="0028M^$/]0.(!\)"(0#[94)"*X#P```(MT
-M)`P/0L)(C90DP````(A$)"))BT8(28M^$/^0N````(7`#X2H````28M<)!A-
-MC6PD&$PYZP^$@0```$4Q_^L*9I!(BQM,.>MT<H"[@/S__P%,C:-P_/__=>A,
-M.[/H_/__==](BX/8_/__2(N[\/S__TB-M"20````_U!X]H0DF@````)UO`^V
-MA"2<````.T0D#'6N#[:$))T````Z1"0B<Z`/MM!!BX0DZ`,``$&#QP&)1)4(
-M1#A\)")UAC'`2('$V````%M=05Q!74%>05_#BX0DQ````(E%!(N$),````")
-M10#I/____V9FD&9FD&9FD(U'^S'2@_@'=PZ)P/\DQ0````"Z`0```(G0P[H(
-M````B=##N@(```")T,.Z!P```(G0P[H#````B=##N@0```")T,.Z!0```(G0
-MP[H&````B=##9F9FD&9FD&9FD&9FD`^VCX`#``!$#[9&"(G*@_(!@^(!B="#
-MR"!!]L`@#T3"B<*#R@+VP00/1<*)PH/*!(/A`@^V3@H/1<*)PH/*$$&#X!`/
-M1<*)PH/*0/;!`0]%PHG"@,J`@^$"#T7"#[979(G!@<D```"`]L($#T7!B<&!
-MR0```@#VP@(/1<&)P8')```!`(/B`0]%P8G"@<H```0`]D=F`0]%PL-F9I!F
-M9I!(BX=H`@``2(M/*$0/MD=$2,'H"TC!Z0M(:=#H`P``2(G0,=)(]_%$B<)(
-MB<%(BT<(#[9`"BG"B=!(F$@/K\A%A<!(C02)1(T4`'Y]08U`_S'V3(U(`4B+
-M3/=@2(7)=&#V@8`#```!=%>`>1`$=E'V@6`"``!P=$A(BU$(#[9!1`^V4@HI
-MT(T$@$2-!`!(BX%H`@``2(M)*$C!Z`M(P>D+:=#H`P``B=`QTO?Q1`^OP$6%
-MTG0%13G"=@9%B<)F9I!(@\8!3#G.=8U!@?H0)P``N!`G``!!#T;"PV9FD&9F
-MD$B+CX`"```/MH&J````/`)U<DB+01"_$"<``$B+<"A(BT$(3(M`*$B)\DPI
-MPDC!Z@M(A=)T-H!Y*`!U-$B+@:````!,*<!(P>@+2&G`Z`,``$B)T3'22/?Q
-M2(T$@`'`OQ`G```]$"<```]&^(GXPY!(*[&@````2,'N"TAIQN@#``#KS3P#
-M=%>`>2@`="-(BT$02(M0*$B)T$@K@:````!(P>H+2,'H"TAIP.@#``#KH$B+
-M@:````!(P>@+2&G0Z`,``$B+01!(BT@H2(G0,=)(P>D+2/?Q2(T$@`'`ZX"`
-M>2@`=`9(BT$(ZZ=(BX&@````2,'H"TAIT.@#``!(BT$(Z\1F9F:09F:09F:0
-M9F:03(M'&$V%P'0\00^V0$2$P`^V\'0C,<E).7A@=!Y,B<(QR>L-2(M":$B#
-MP@A(.?AT"H/!`3GQ=>PQP,-!BT`X@\`!`<C#BT<XPV9F9I!F9I`/MD=$A<!^
-M8X/H`44QR4R-4`%*BTS/8$B%R71&]H&``P```70]@'D0!'9$#[9!1(7`?B^#
-MZ`$QTDR-0`%F9F:02(M$T6!(A<!T#_:`@`,```%T!D@Y<#AT%$B#P@%,.<)U
-MWDF#P0%-.=%UIS'`\\-(.7$X=>U(B<C#9F9FD&9FD$%708G7059)B?Y!54F)
-MS4%455-(@^P(2(7_0(AT)`-$B$0D`D2(3"0!#X0)`0``@'\0!P^4P$"`_@</
-ME,*$P`^%VP```(32#X7K````187_#X0L`@``3(GMQT0D!`````!)Q\7_____
-M13'D9F:09I"+?0#H`````$B%P$B)PP^$AP```$F+!D@Y`P^%>P```(![$`%U
-M=4B)WDR)]^C?_O__,?](A<!(B<9T!$B+>$A(BTLX2(7)#X39````2(G(,=)(
-M@W@8`4B+`$B#VO](A<!U[TB#^@,/AKD````QTD4Q[8-$)`0!20'42(/%!$0Y
-M?"0$#X5X____#[9,)`*#X0^`?"0#!P^&+0$``$4QY$B#Q`A,B>!;74%<05U!
-M7D%?PP^V1T0\`0^$(?___X32=`B$P`^%00$``$6%_V9FD&:0#X0\`0``3(GM
-M,=M)Q\7_____13'DZRF`>!`!=:Y(BT!`2(7`=*5)`<1).<5,#T?H@\,!2(/%
-M!$0Y^P^$>/___XM]`.@`````2(7`=<IF9I#I=O___S'22(7V=`1(BU8H2(7)
-M=&E%,<#K(69FD&9FD$B+01A(.<9T"DB%_W0=2(7`=%=(BPE(A<ET*DB%]F:0
-M==Y(A?](BT$8=>-(A<!FD'7A2(M!$$@YT$@/1]!(BPE(A<EUUDB%_W04387`
-M=`])BT`02`-'$$@YPD@/0M!).=5,#T?JZ<?^__](BT<(2`-'$$@Y00AUNDB+
-M01!)B<A(.=!(#T?0Z[4/MD0D`_\DQ0````!!@_\!#X:]_O__08/_`DV)[`^&
-ML_[__P^VR;C_____0='OT^!(F$DAQ$2)^$P/K^#IE?[__T6%_P^%NP```$G'
-MQ?____]%,>3I9_[__T&#_P,/AG#^__\/MLFX_____TV)[-/@2)A)(<1!C4?^
-M3`^OX.E4_O__08/_`@^&1_[__P^VR;C_____38GLT^!(F$DAQ$&-1_],#Z_@
-MZ2O^__^`?"0!`0^&_0```(!\)`$"#X9+____1`^V3"0!,=)$B?A!]_&%T@^%
-M_/W__X/X`0^.\_W__TQCX$&-0?\/MLE(F$P/K^"X_____]/@2)A)(<5-#Z_E
-MZ=']__](BT=@,>TQTDB%P'4>Z;S]__]!.>\/AN#]__^)ZDF+1-9@2(7`#X2C
-M_?__2(M8.$&+?)4`Z`````!(.<-T$D$/MD9$@\4!.>@/AJW]___KPD$/MD9$
-M#[;803G?#X)M_?__A,!T9TF+1F`Q[3'22(7`=23I5_W__T$/MD9$@\4!#[;8
-M.>MV1HGJ28M$UF!(A<`/A#C]__](BU@X08M\E0#H`````$@YPW3.Z2#]__\/
-MMLFX_____TV)[-/@2)A)(<1$B?A,#Z_@Z07]__\/ML!-BV8H28MTQEA(BT8X
-M2(M(.$B%R74*ZR5(BPE(A<ET'4B#>1@`=?%(BU9(2(M""$@#0A!(.4$(==],
-M`V$003G?=ROIN_S__TF+%D@Y$`^%K/S__X!X$`$/A:+\__^#PP%,`V!`1#G[
-M#X25_/__B=A!BWR%`.@`````2(7`=<GI?/S__Y#SPV9F9I!F9F:09F:09F:0
-MBPT`````C5$!B=#!^!_!Z!Q$C00"08/@#T$IP$0[!0````"X_____W192&/!
-M2,?&`````$B-%(!(C1102(L'2(T,E0````!(B025`````$B+1PA(B40Q"$B+
-M1Q!(B40Q$$B+1QA(B40Q&$B+1R!(B40Q((M'*$2)!0````")1#$H,<#SPV9F
-M9I!F9F:09F:02(/L.`^V1Q!)B=`\`70F/`1T/4B-5"0,@_X!2(GG&<"#P!F(
-M1"0(9HE*".@`````2(/$.,.+A^@#``!(C50D#$R)1"0,B40D!.O-9F:09I!(
-MBU<X2(M'2(N2Z`,``$P#0`B)5"0$2(U4)`Q,B40D#.NF9F9FD&9F9I!F9I!F
-M9I!54TB#[!C&!"0&2(M?$$B%VW0@2(M#$#'_2(GF2(E$)`A(BT,(_Y#`````
-M2(L;2(7;=>!(@\086UW#9F:09F:02(M'4$0/MX^8````28GP08G22(NP@`(`
-M`$R+&$2)R<'A"8!^*`!T#?:'L0````0/A8@````/MY::````P>()A<E)B[-0
-M`@0`18N+6`($`'1>B=`QTD'W\8G`2,'@!$B-/`9)C7`0ZS:)T$@#!TB)1OA$
-MB<C'1O0`````28GP*=")1O`YR(G(#T9&\"G!B4;P2(UV$(7)=!=(@\<0,=)%
-MA=)UQ8G02`-'"$B)1OCKPK@!````0<=`]`$```###[>6F`````^WAIH````I
-MPD0IRL'B">EG____9F9FD&9F9I!!5$F)_%5(B?53@'Y$`'1J,=OK(DB+5DA)
-MBT0D2$B+2`A(.4H(=#D/MD5$C5,!2(/#`3G0?D1(BW3=8$B%]G3G@'X0!';.
-M3(GGZ++___^$P'356UU!7+@!````PV9F9I!)BT0D.$@Y1CATYP^V142-4P%(
-M@\,!.=!_O%M=05PQP,-F9F:09F9FD&9F9I!F9I!!54F)]4%428G\55.`?T0`
-M=%(Q[>L<3(GN2(G?Z-____]!#[9$)$2-50%(@\4!.=!^,DF+7.Q@2(7;=.6`
-M>Q`$=]1,B>Y(B=_H(____X3`C54!#Y1#4$$/MD0D1$B#Q0$YT'_.6UU!7$%=
-MPV9FD&:0@'\0`70#,<##2(7V=%I(BX:``@``2(7`=$Y,BT`(23GP=$I(BT\X
-M2(7)=#9F9F:02(M1&$B%TG0?2(7V=0=FD.O$2(G"2(M"&$B%P'7T2#GR=`5,
-M.<)UKDB+"4B%R6:0=<ZX`0```,-)B?#KMDR+0!#KL&9F9I!F9I!F9I!F9I"+
-M1QR%P'@&@W\@`W<'QT=0_O____/#9F9FD&9FD&9FD(%_',<```!V"8%_(,<`
-M``!W!\='4/[____SPV9FD&:0@7\<QP```'8)BU<@A=)X`O/#QT=0_O___\-F
-M9I!F9I"+3QR%R7@&@W\@`W<'QT=0_O____/#9F9FD&9FD&9FD(-_'`-V!H-_
-M($MW!\='4/[____SPV9F9I!F9F:09F:0@W\<`W8&@W\@5W<'QT=0_O____/#
-M9F9FD&9F9I!F9I"#?QP#=@:#?R!#=P?'1U#^____\\-F9F:09F9FD&9FD(-_
-M'`=V!H-_(`]W!\='4/[____SPV9F9I!F9F:09F:0@W\<!W8&@W\@0W<'QT=0
-M_O____/#9F9FD&9F9I!F9I"#?QP#=@:#?R`#=P?'1U#^____\\-F9F:09F9F
-MD&9FD(-_'`=V"8%_(/\```!W!\='4/[____SPV9F9I!F9F:0@W\<!W8)@7\@
-MHPP``'<'QT=0_O____/#9F9FD&9F9I"#?QP'=@F!?R`G#0``=P?'1U#^____
-M\\-F9F:09F9FD(-_'`=V"8%_(*L```!W!\='4/[____SPV9F9I!F9F:0@W\<
-M"W8&@W\@)W<'QT=0_O____/#9F9FD&9F9I!F9I"#?QP#2(M'*(L`=A-(8U<@
-MB<!(C02%!````$@YPG,'QT=0_O____/#9F9FD&9F9I"#?QP#2(M'*(L`=A-(
-M8U<@B<!(C02%!````$@YPG,'QT=0_O____/#9F9FD&9F9I!32(G[2(M'*(-[
-M'`.+.'8)@7L@K0```'<)QT-0_O___UO#Z`````!(A<!T[5MF9I##9F9FD&9F
-M9I!F9F:09F:04TB)^TB+1RB#>QP#BSAV"8%[(-<```!W"<=#4/[___];P^@`
-M````2(7`=.U;9F:0PV9F9I!F9F:09F9FD&9FD%-(B?M(BT<H@WL<`XLX=@F!
-M>R#Y````=PG'0U#^____6\/H`````$B%P'3M6V9FD,-F9F:09F9FD&9F9I!F
-M9I!32(G[2(M'*(-['`A(BTLPBSAV#(-[(`1_%F9FD&9FD,=#4/[___];PV9F
-M9I!F9I`/ME`(BT`$B0&$THA1!'04@3G#`0``=MCH`````$B%P'3.6\,]PP$`
-M`&9F9I!F9I!VONOD9F9FD&9F9I!F9F:02(/L$$B);"0(2(D<)$B)_8%_'+,`
-M``!V!H-_(`=W%<=%4/[___](BQPD2(ML)`A(@\00PTB+1RB+&(G?@^L!Z```
-M``"#^_UWW4B%P'31@'@0!';+2(.X@`(```!UP6:0Z\1F9F:09F9FD&9FD&9F
-MD$B#[!A(B6PD"$B)'"1(B?U,B60D$(-_'`AV!H-_(`=W'\=%4/[___](BQPD
-M2(ML)`A,BV0D$$B#Q!C#9F:09I!,BV<H08L<)(G?@^L!Z`````"#^_UW$DB%
-MP'0&@'@0!'<7QT50_O___TF-?"0$Z)WK__\L`76JZZ](@[B``@```'7?Z^1F
-M9F:09F9FD&9FD$B#["A(B6PD"$B)'"1(B?U,B60D$$R);"083(ET)"!(BT\H
-M2&-7'$2+,42)\$B-!(4$````2#G"<F:+=R"%]GA?@#T``````G1613'M187V
-M0;P$````=3'K369FD&9FD(G?Z`````!(BU402#D09I!U4O9`9`%T*$&#Q0%)
-M@\0$13GU=")(BTTH0HL<(8G?Z`````!(A<!UQV9F9I!F9I#'15#^____2(L<
-M)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,/'15#\____Z]IF9I!(@^P@2(D<
-M)$B);"0(2(G[3(ED)!!,B6PD&(%_'(<```!,BV<H=@F#?R`#=R-F9I#'0U#^
-M____2(L<)$B+;"0(3(MD)!!,BVPD&$B#Q"##D$$/MD0D`3P(=]9%,>V$P'4=
-MZ]2)[^@`````2(M3$$@Y$'4B08/%`44X;"0!=KE!#[;%08MLA&B)[^@`````
-M2(7`==#KF\=#4/S___]F9F:0ZY5F9F:09F9FD&9FD&9FD(-_'`-V!H-_(`-_
-M!\='4/[____SPV9F9I!F9F:09F:02(M'*(M7'+D0````BW`(1(M`#(7V=`=$
-MB<!(C4@02&/"2#G!=PR%]HM'('4,03G`=@?'1U#^____\\-F9I!FD$B#["!(
-MB1PD2(EL)`A(B?M,B60D$$R);"08@7\<KP```$R+9RAV"8-_(`-W(V9FD,=#
-M4/[___](BQPD2(ML)`A,BV0D$$R+;"082(/$(,.000^V1"0!/!!WUD4Q[83`
-M=1WKU(GOZ`````!(BU,02#D0=2)!@\4!13AL)`%VN4$/ML5!BVR$<(GOZ```
-M``!(A<!UT.N;QT-0_/___V9F9I#KE69F9I!F9F:09F:09F:02(/L($B)'"1(
-MB6PD"$B)^TR)9"003(EL)!B#?QP$2(MO*'X&@W\@`W<FQT-0_O___TB+'"1(
-MBVPD"$R+9"003(ML)!A(@\0@PV9F9I!F9I!(B>_HF.C__RP!=<X/MD4-/$!W
-MQD4Q[83`=2'KQ&9FD$2)Y^@`````2(M3$$@Y$)!U(D&#Q0%$.&T-=J5!#[;%
-M1(MDA7Q$B>?H`````$B%P'7.ZX;'0U#\____9F:09I#I?/___V9F9I!F9F:0
-M9F:02(/L($B)'"1(B6PD"$B)^TR)9"003(EL)!B!?QRS````2(MO*$2+90!V
-M!H-_(`-W'\=#4/[___](BQPD2(ML)`A,BV0D$$R+;"082(/$(,-$B>?H````
-M`$B%P'341(GGZ`````!(BU,02#D0=`G'0U#\____Z\%,C64$00^V1"0!/!!W
-MK$4Q[83`=2'KJF:0B>_H`````$B+4Q!(.1!FD'7,08/%`44X;"0!=HM!#[;%
-M08MLA'")[^@`````2(7`=<[I:O___V9FD&9FD&9FD$B#["!(B1PD2(EL)`A(
-MB?M,B60D$$R);"08@W\<"$B+;RA$BV4`=@:#?R`#=R+'0U#^____2(L<)$B+
-M;"0(3(MD)!!,BVPD&$B#Q"##9F:01(GGZ`````!(A<!TT42)Y^@`````2(M3
-M$$@Y$'0)QT-0_/___^N^3(UE!$R)Y^C=YO__+`%UIT$/MD0D#3Q`=YU%,>V$
-MP'4IZYMF9I!F9I")[^@`````2(M3$$@Y$&:0=;Q!@\4!13AL)`T/AG3___]!
-M#[;%08MLA'R)[^@`````2(7`=<KI4____V9FD&:01(M''$6%P'@&@W\@*W<'
-MQT=0_O____/#9F9FD&9F9I!(@^P02(D<)$B);"0(2(G[@W\<"$B+1RB+*'8T
-M1(M/($6%R7@KB>_H`````$B%P'0?B>_H`````$B+4Q!(.1!T%L=#4/S____K
-M#69FD&9FD,=#4/[___](BQPD2(ML)`A(@\00PV9F9I!F9F:09F:02(/L$$B)
-M'"1(B6PD"$B)^X-_'`A(BT<HBRAV-$2+5R!%A=)^*XGOZ`````!(A<!T'XGO
-MZ`````!(BU,02#D0=!;'0U#\____ZPUF9I!F9I#'0U#^____2(L<)$B+;"0(
-M2(/$$,-F9F:09F9FD&9FD$B#[!!(B1PD2(EL)`A(B?N#?QP(2(M'*(LH=C1$
-MBU\@187;>"N)[^@`````2(7`=!^)[^@`````2(M3$$@Y$'06QT-0_/___^L-
-M9F:09F:0QT-0_O___TB+'"1(BVPD"$B#Q!##9F9FD&9F9I!F9I!(@^P02(D<
-M)$B);"0(2(G[@W\<#4B+1RB+*'8LBT<@A<!X)8GOZ`````!(A<!T&8GOZ```
-M``!(BU,02#D0=!#'0U#\____ZP?'0U#^____2(L<)$B+;"0(2(/$$,-F9I!(
-M@^P02(D<)$B);"0(2(G[@W\<#4B+1RB+*'8LBT<@A<!^)8GOZ`````!(A<!T
-M&8GOZ`````!(BU,02#D0=!#'0U#\____ZP?'0U#^____2(L<)$B+;"0(2(/$
-M$,-F9I!(@^P02(D<)$B);"0(2(G[@W\<#4B+1RB+*'8LBT<@A<!X)8GOZ```
-M``!(A<!T&8GOZ`````!(BU,02#D0=!#'0U#\____ZP?'0U#^____2(L<)$B+
-M;"0(2(/$$,-F9I!(@^P02(D<)$B);"0(2(G[@W\<`TB+1RB+*'95BT<@A<!X
-M3HGOZ`````!(A<!T0HGOZ`````!(BU,02#D0=`G'0U#\____ZS"`>!`$=B-(
-MBY"``@``2(72=!>`NJL`````=0X/MH!A`@``@^`8/`AT!\=#4/[___](BQPD
-M2(ML)`A(@\00PV9F9I!F9I!F9I!(@^P02(D<)$B);"0(2(G[@W\<`TB+1RB+
-M*'8TBT<@A<!X+8GOZ`````!(A<!T(8GOZ`````!(BU,02#D0=`G'0U#\____
-MZP^`>!`!=`EFD,=#4/[___](BQPD2(ML)`A(@\00PV9F9I!F9F:09F:02(/L
-M$$B)'"1(B6PD"$B)^X-_'`-(BT<HBRAV-(M'((7`>"V)[^@`````2(7`="&)
-M[^@`````2(M3$$@Y$'0)QT-0_/___^L/@'@0`70)9I#'0U#^____2(L<)$B+
-M;"0(2(/$$,-F9F:09F9FD&9FD$B#[!A(B1PD2(EL)`A(B?M,B60D$(-_'`=(
-MBT<HBRA$BV`$=GN+5R"%TGATB>_H`````$B%P'1H1(GGZ`````!(A<!T6XGO
-MZ`````!$B>=(B<7H`````$B)PDB+10!(.T,0=`G'0U#\____ZSI(.P)U\DB+
-M10B`>`H`="2`>A`!=1Y(@WU8`'072(N%@`(``$B%P'02@+BK`````'0)9I#'
-M0U#^____2(L<)$B+;"0(3(MD)!!(@\08PV9FD&9FD$B#[!!(B1PD2(EL)`A(
-MB?N#?QP'2(M'*(LH=C2+3R"%R7@MB>_H`````$B%P'0AB>_H`````$B+4Q!(
-M.1!T"<=#4/S____K#X!X$`1W"6:0QT-0_O___TB+'"1(BVPD"$B#Q!##9F9F
-MD&9F9I!F9I!(@^P02(D<)$B);"0(2(G[@W\<5TB+1RB+*'8YBW<@A?9X,HGO
-MZ`````!(A<!T)HGOZ`````!(BU,02#D0=`G'0U#\____ZQ2`>!`$=@=(@W@8
-M`'0'QT-0_O___TB+'"1(BVPD"$B#Q!##9F:09F:02(/L$$B)'"1(B6PD"$B)
-M^X-_'$-(BT<HBRAV-HM_((7_>"^%[70RB>_H`````$B%P'0?B>_H`````$B+
-M4Q!(.1!T"<=#4/S____K#8!X$`%T!\=#4/[___](BQPD2(ML)`A(@\00PV9F
-MD&9FD&9FD$B#[!!(B1PD2(EL)`A(B?N#?QP(2(M'*(LH=CA$BT<@187`>"^%
-M[70RB>_H`````$B%P'0?B>_H`````$B+4Q!(.1!T"<=#4/S____K#8!X$`%T
-M!\=#4/[___](BQPD2(ML)`A(@\00PV9F9I!F9I!$BU<<1872>`M$BT\@187)
-M>`+SP\='4/[____#9F9FD$2+7QQ%A=MX!H-_("MW!\='4/[____SPV9F9I!F
-M9F:0BT<<A<!X!H-_(']W!\='4/[____SPV9F9I!F9I!F9I!(@^P02(D<)$B)
-M;"0(2(G[2(MO*(M/'+\0````#[95"P^V=0S!X@E`@/X"=#A(8\%(.<=W&T"`
-M[@&+2R"_$````'142&/!2#G'=B5F9I!FD,=#4/[___](BQPD2(ML)`A(@\00
-MPXG02(UX$.O`9F:0BWT`Z`````!(A<!TTXM]`.@`````2(M3$$@Y$'09QT-0
-M_/___^O`B=!(C7@02&/!2#G'=ZOKR8!X$`%UHV9FD.NE9F9FD&9F9I!F9I!F
-M9I!(@^P02(D<)$B);"0(2(G[2(MO*(M/'+\4````#[=5$`^V=1+!X@E`@/X"
-M=#A(8\%(.<=W&T"`[@&+2R"_%````'142&/!2#G'=B5F9I!FD,=#4/[___](
-MBQPD2(ML)`A(@\00PXG02(UX%.O`9F:0BWT`Z`````!(A<!TTXM]`.@`````
-M2(M3$$@Y$'09QT-0_/___^O`B=!(C7@42&/!2#G'=ZOKR8!X$`%UHV9FD.NE
-M9F9FD&9F9I!F9I!F9I!(@^P02(D<)$B);"0(2(G[@W\<`TB+1RB+*'8LBT<@
-MA<!X)8GOZ`````!(A<!T&8GOZ`````!(BU,02#D0=!#'0U#\____ZP?'0U#^
-M____2(L<)$B+;"0(2(/$$,-F9I!(@^PH2(EL)`A(B1PD2(G]3(ED)!!,B6PD
-M&$R)="0@2(M/*$AC5QQ$#[8Q1(GP2(T$A00```!(.<)R2(-_(`-V0D4Q[46%
-M]D&\!````'4DD.LXB=_H`````$B+51!(.1!U14&#Q0%)@\0$13GU=!M(BTTH
-M0HL<(8G?Z`````!(A<!US\=%4/[___](BQPD2(ML)`A,BV0D$$R+;"083(MT
-M)"!(@\0HP\=%4/S____KVDB#["A(B6PD"$B)'"1(B?U,B60D$$R);"083(ET
-M)"!(BT\H2&-7'$0/MC%$B?!(C02%!````$@YPG)(@W\@`W9"13'M187V0;P$
-M````=220ZSB)W^@`````2(M5$$@Y$'5%08/%`4F#Q`1%.?5T&TB+32A"BQPA
-MB=_H`````$B%P'7/QT50_O___TB+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#
-MQ"C#QT50_/___^O:2(/L$$B)'"1(B6PD"$B)^X-_'`=(BT<HBRAW%<=#4/[_
-M__](BQPD2(ML)`A(@\00PXGOZ`````!(A<!TWXGOZ`````!(BU,02#D0=-;'
-M0U#\____Z\UF9F:09F:09F:0@W\<`TB+1RB+`'832&-7((G`2(T$A00```!(
-M.<)S!\='4/[____SPV9F9I!F9F:04X-_'`)(B?M(BT<H#[8`=C^+5R"%TG@X
-M,?8/MOCH'MS__TB%P$B)PG0F2(M`"$B#N/@`````=!A(BT,02#E"&'0'QT-0
-M_/___UO#9F:09I#'0U#^____6\-F9F:09F:02(/L$+X<````2(D<)$B);"0(
-M2(G[2(MO*(M7'`^V302`^0)T,DACPD@YQG<5@.D!BU,@O@@```!T34ACPD@Y
-MQG8>QT-0_O___TB+'"1(BVPD"$B#Q!##BT482(UP'.O%BWT`Z`````!(A<!T
-MU8M]`.@`````2(M3$$@Y$'0:QT-0_/___^O"BT482(UP"$ACPD@YQG>LZ\B`
-M>!`!=:2`?0<0=Y[KHV9F9I!F9I!F9I!(BW]8,<"%TDB+3RAT'X!Y!`%T'$B-
-M01Q(B48(BT$8QT8$`0```(D&N`$```#SPY!(BT<P2(/`"$B)1@CKWF:02(/L
-M$$B)'"1(B6PD"$B)^XMW'$B+;RB#_@MV=(M7((72>&V`?0<`=7P/MD4&,<G!
-MX`F)P$B->`Q(8\9(.?AR4(G(2&/22(/`!$@YPG)"BWT`Z`````!(A<!T-8M]
-M`.@`````2(M3$$@Y$'0)QT-0_/___^LB@'@0`745#[9%!@^W500!T#T`(```
-M?@MF9F:0QT-0_O___TB+'"1(BVPD"$B#Q!###[9-!K\,````P>$)ZX5F9F:0
-M9F:09F:09F:02(/L$$B)'"1(B6PD"$B)^XMW'$B+;RB#_@=V*XM'((7`>"2%
-M]@^V300/ME4%>!@/MM(/MLE(F`'*P>()B=)(@\((2#G0<Q7'0U#^____2(L<
-M)$B+;"0(2(/$$,.+?0#H`````$B%P'3>BWT`Z`````!(BU,02#D0=`G'0U#\
-M____Z\N`>!`!=;YF9F:09F:0Z[QF9F:09F9FD&9FD&9FD$%4BP4`````28G\
-M54B)]8/X_U-T?HM6&$C'PP````#K"TB#PRB+`X/X_W1G.=!U\8/``71>QT50
-M`````$B)[Y#_4PB+=5"%]G5008"\))`"!```=3Z+2R"%R0^%H````$F#O"3@
-M`0```'0]28N4)!@"``!)C80D$`(``$F)K"08`@``2(E%`$B)50A(B2I;74%<
-MP\=%4/[___];2(GO3(M=2%U!7$'_XTB#>Q``28FL).`!``!T24B+0QA!QX0D
-MZ`$```$```!(B>])B:PD^`$``$G'A"0``@```````$F)A"3P`0``_U,008N$
-M).@!``"#Z`&%P$&)A"3H`0``=8Y,BUL82(GO6UU!7$'_XV:02(L'2(V7:`,`
-M`,>'$`,```__``#'AQ0#```(````QX<8`P```````$B)ER`#``!(QX<P`P``
-M`````$B)AP@#``"+A^@#``")<@1(QX=``P```````$B-M_@"``")AV@#``!(
-MB[\(`P``Z8+^__]FD%-(B?M(BW\02#F?X`$``'0/2(G?3(M;2%M!_^-F9F:0
-M2(NW$`(``$B-AQ`"``!(QX?@`0```````$@YQG332(L62(M&"$B)0@A(B1!(
-MB78(2(DVZ"C^___KMV9FD&9FD(N'Z`,``,-F9I!F9I!F9I!(@^PXB?E)B?!(
-MC50D+$B)YTB)X,8``$B#P`%(.=!U](#Y!XA,)`@/A*L```"`^09T$(#Y!'0+
-M@/D%=`:`^0B0=1@/ME0D#/:&8`(```&X`0````]$PHA$)`R`^1QT88#Y`W08
-M08N`Z`,``$B)YXE$)`3H`````$B#Q#C#28M0($B%TG3?#[:"L````(A$)`R`
-MNK``````=<M(BX*0````2(E'$`^W@I@```")1Q@/MH*Q````T.B#X`&(1"0-
-MZZ1(BX9H`@``2(E'#`^WAG0#``!FB4<4ZXQ(BT882(7`=`F+@.@#``")1PQ,
-MBT8XZ7'___]F9F:09F:09F:09F:00(@U`````,-F9F:09F9FD$B+5QA(C4\8
-M2#G*=0OK+I!(BQ)(.<IT)8"Z@/S__P%(C8)P_/__=>CV0O`!=.*%]G0-2(L2
-M@^X!2#G*==LQP//#9F9FD&9F9I!F9F:09F:02(/L&$B)7"0(3(ED)!!(B?M!
-MB?2+=S1(BS]%B>3H`````$B)QP^V@+$```!(B5]0QH>P````!$B)7UA,B6=@
-MQH>R`````$C'A\@`````````@^#/@\@@B(>Q````2(M<)`A,BV0D$$B#Q!CI
-M`````$B#["A(B1PD3(ED)!!)B?Q,B6PD&$R)="0@28GU2(EL)`A(BR])B=:+
-M=S1(B>_H`````$B-O?````!(B</H`````$C'``````!)BU0D*$B)WTC'0#``
-M````2,=`$`````!(QT`H`````$C'0#@`````2(E0"$B-4!C'0$``````2(E#
-M>$R)8U!(B5`82(E0($R):UC&@[`````$3(FSR````,:#L@````!(BQPD2(ML
-M)`A,BV0D$$R+;"083(MT)"!(@\0HZ0````!F9I!F9I!(@^P82(D<)$B);"0(
-M2(G]3(ED)!"#`@%!B?2+=S1(BS](B=/H`````$B)QT&#_`$/MI>Q````&<!(
-MB6]0@\`"QH>P````!$B)7UB#X`/&A[(`````P>`$@^+/"<*(E[$```"`?1`$
-M=A=(@[V``@```'0-2,>'R`````````#K"TC'A\@`````````Z`````!(BWT`
-M2(L<)$B+;"0(3(MD)!!(@\08Z0````!F9I!FD$B#[#A,B7PD,$R-OQ`!``!,
-MB60D&$F)_$B);"003(EL)"!,B?],B70D*$B)7"0(28GV28G5Z`````!(A<!(
-MB<4/A,,```!)BUPD&$R)8"!)@\08QP`!````3(EP"$R):!!(QT`8`````$PY
-MXW4*ZS-(BQM,.>-T*X"[@/S__P%(C;MP_/__=>CV0_`!=.)(B>J^`0```.BU
-M_O__2(L;3#GC==6+10"#Z`&%P(E%`'0C2(M<)`A(BVPD$$R+9"083(ML)"!,
-MBW0D*$R+?"0P2(/$.,-(B>Y,B?_H`````$R)[TV)\TB+7"0(2(ML)!!,BV0D
-M&$R+;"0@3(MT)"A,BWPD,$B#Q#A!_^-(Q\<`````,<#H`````.O%9F9FD&9F
-MD$B#[#A,B7PD,$R-OQ`!``!,B60D&$F)_$B);"003(EL)"!,B?],B70D*$B)
-M7"0(28GV28G5Z`````!(A<!(B<4/A+(```!)BUPD&$R)8"!)@\08QP`!````
-M3(EP"$R):!!(QT`8`````$PYXW0D9I"#NZ#\____2(V[</S__W0*2(GJ,?;H
-MIOW__TB+&TPYXW7>BT4`@^@!A<")10!T(TB+7"0(2(ML)!!,BV0D&$R+;"0@
-M3(MT)"A,BWPD,$B#Q#C#2(GN3(G_Z`````!,B>]-B?-(BUPD"$B+;"003(MD
-M)!A,BVPD($R+="0H3(M\)#!(@\0X0?_C2,?'`````#'`Z`````#KQ69F9I!F
-M9F:02(M6.%-(B?M(B7X02(72=`6+1B")`DB)W^AR^/__2(G?6^D`````9F:0
-M9F:09F:0BX;H`P``2(V6:`,``$B)O@@#``#'AA`#```/_P``QX84`P``"```
-M`$B)EB`#``#'0@0,````B89H`P``2(V&>@,``,>&&`,```````!(QX8P`P``
-M`````$B)MC@#``!(B88H`P``2,>&0`,```````!(@<;X`@``Z0````!F9I!(
+M``"ZH`,``+X!````2(G?Z`````#IN````#P##X6P````1(N7&`$``$&\````
+M`+T````J0;D`````O@````"_`````$&X!````+H!````B=")\=/@087"=1B-
+M3@;3XD$)U$$)T;@5````B?G3X`G%ZPE$B<")^=/@"<6#Q@&#QP5!@\`#@_X$
+M=<!$B<FZJ`,``$"V`4B)W^@`````B>FZQ`,``+X!````2(G?Z`````!!#[?,
+M"XL8`0``]]&ZH`,``+X!````2(G?Z`````!F9I!;74%<PV9F9I!F9F:09F:0
+M2(/L"(GQA-)T%KC^____T\`AAQ@!``#K%&9F9I!F9I"X`0```-/@"8<8`0``
+MZ`````!(@\0(PV9FD&9FD&9FD$B#[`@/M_;!Y@B-3@]!N`$```"ZF@```+X!
+M````Z`````!(@\0(PV9FD&9FD&9FD$B#[`B)\832=!:X_O___]/`9B&'``$`
+M`.L49F:09F:0N`$```#3X&8)AP`!```/M[<``0``Z`````!(@\0(PY!(@^PH
+M2(D<)$B);"0(3(ED)!!,B6PD&$R)="0@2(G]08G6#[:>S````$0/MFX"2(M^
+M<$B%_W0,#[;200^V]>@`````2(GOZ`````"`^P=W2`^VP_\DQ0````!!O/L`
+M``#K-D&\,P```.LN0;P[````ZR9!O',```#K'D&\>P```.L60;RS````ZPY!
+MO+L```#K!D&\\P```$2)YDB)[^@`````00^VUD&-=)T`0`^V]DB)[^@`````
+M2(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9F:09F9FD&9FD$%455-)
+MB?R[`````$`/MNZZ`@```(GN3(GGZ('Z__^H"'0-N`````#K(&9FD&9FD+\!
+M````Z`````"#PP&!^Q`G``!UR[C_````6UU!7,.02(/L*$B)7"0(2(EL)!!,
+MB60D&$R);"0@2(G]28G-08G40`^VWHG>Z(3___^%P'4P00^V](G:2(GOZ$+[
+M__^%P'0>N@$```")WDB)[^C_^?__08A%`+@`````ZPEF9F:0N/____](BUPD
+M"$B+;"003(MD)!A,BVPD($B#Q"C#9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL
+M)"!(B?U!B<U$#[;B0`^VWD2)X;H!````B=[HR_G__[E`````N@(```")WDB)
+M[^BW^?__B=Y(B>_HW?[__X7`=4Q%A>UT-$'VQ`%T%8G:OD````!(B>_HC_K_
+M_X7`="[K,XG:OA@```!(B>_H>OK__X7`=!GK'F9F9I")VKXH````2(GOZ&'Z
+M__^%P'4'N/\```#K!K@`````D$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F
+M9F:09F:005=!5D%505154TB#[`A)B?U)B<]%B<:)\XG5A-(/A`T!``!`#[;>
+MB1PDN60```"Z`@```(G>Z/7X__^+-"1,B>_H&O[__X7`=1"Z`P```(LT)$R)
+M[^BF^/__0`^VU;D!````BS0D3(GOZ,+^__]!O/____^$P`^%J0$``$&\````
+M`$6%]@^.F@$``$R)^\=$)`0`````08UN_TACQ4Z-/#A!B>P[;"0$=3:Y0```
+M`+H"````BS0D3(GOZ''X__],B?FZ6````(LT)$R)[^C>_?__A<!T.NE*`0``
+M9F:09I"Y1````+H"````BS0D3(GOZ#OX__](B=FZ4````(LT)$R)[^BH_?__
+MA<`/A1`!``"#1"0$`4B#PP%$.70D!`^$_````.EX____9F9FD&9FD+^@A@$`
+MZ";X__\/MNL/MLBZ`P```(GN3(GOZ.'W__^)[DR)[^@'_?__A<!T(T$/MHU!
+M$@``N@,```")[DR)[^B\]___0;S_____Z:8```"0B>J^8````$R)[^BA^/__
+MA<!T#T&\`````$6%]GYI9I#K'T$/MHU!$@``N@,```")[DR)[^AW]___0;S_
+M____ZV1,B?M!O`````!F9I!F9I"Y1````+H"````B>Y,B>_H3/?__TB)V;J`
+M````B>Y,B>_HNOS__X7`=0U!@\0!2(/#`44Y]'7)00^VC4$2``"Z`P```(GN
+M3(GOZ!+W___K!42+9"0$1(G@2(/$"%M=05Q!74%>05_#9F:09F:09F:02(/L
+M&$B)7"0(3(ED)!!)B?Q(B=!`#[;608G(2(G!O@````#HF/W__XG#N50```"Z
+M`@```+X`````3(GGZ*_V__^)V$B+7"0(3(MD)!!(@\08PV9F9I!F9F:09F:0
+M9F:02(/L&$B)7"0(3(ED)!!)B?Q(B=!`#[;608G(2(G!O@$```#H./W__XG#
+MN50```"Z`@```+X!````3(GGZ$_V__^)V$B+7"0(3(MD)!!(@\08PV9F9I!F
+M9F:09F:09F:0059!54%455-)B?U(B<U%B<:)TT0/MN:Y9````+H"````1(GF
+MZ`?V__]$B>9,B>_H+/O__X7`=1"Z`P```$2)YDR)[^BX]?__#[;3N0$```!$
+MB>9,B>_HU?O__X3`=39%A?9^.$B)Z[T`````9F9FD`^V$[D`````1(GF3(GO
+MZ*W[__^$P'4.@\4!2(/#`40Y]70)Z]NX_____^L%N`````!;74%<05U!7L-F
+M9I!F9I!(@^P82(E<)`A,B60D$$F)_$B)T$`/MM9!B<A(B<&^`0```.@H____
+MB<.Y5````+H"````O@$```!,B>?H/_7__XG82(M<)`A,BV0D$$B#Q!C#9F9F
+MD&9F9I!F9I!F9I!(@^P(2(N'``D``$B%P$@/1,=`B#4`````N2````!(Q\(`
+M````O@X```!(B<?H`````$B#Q`C#9F:09F:09F:02(/L"(GQA-)T%K@!````
+MT^!F"8=L%```ZQ1F9I!F9I"X_O___]/`9B&';!0```^VMVP4``#H`````$B#
+MQ`C#D$%7059!54%455-(@^Q82(G[28GV2(M.*$B#P0*+=AR#[@''1"14````
+M`$F+1C!(B40D,$F+1B@/ME$!@/H!=1!!QT90`````.GS!```9F:0@/H"=4F`
+M>0(!=39(BX<`"0``2(7`2`]$QTB+D/@(```/MD$#B()N%```#[9!`XB"_B@`
+M`$''1E``````Z:\$``!!QT90_O___^FB!```3(UX`8#Z!`^%]0$```^V00.#
+MZ#L\`0^'Y@$``$$/MF\"2(N?^`@``$`/MO5(B=_H`````(G"A,!T#0^VP("\
+M`V@(``#_=5!(BYOX"```2('#D!0``$B+N_@(``#H`````(GJ*,(/MO)(B=_H
+M`````(G"A,!T#0^VP("\`V@(``#_=11!QT90_____TR)]T'_5DCI(00```^V
+MP@^VA`-H"```@/J!=V0/MLA(:<G(#P``00^V=P1!#[97!<'B$$$/MD<&P>`(
+M"<)!#[9'!PG"B50D/$$/ME<(P>(000^V1PG!X`@)PD$/MD<*"<*)5"1`2(G-
+M2`.KD`D```^$Z0```(!]6`!U&>G>````0<=&4/____],B?=!_U9(Z9D#``!!
+MO`````#&1"1'`$R-;4B+1"0\2(E$)!A)C5<+2(E4)!!`#[;VB70D#$R)[^@`
+M````2(U8\$B+55!(B4503(EK$$B)4QA(B0(/MD-)/`UT!#PB=5U!#[9'`SP[
+M="(\/'5038GPBTPD/(M4)$"+="0,2(G?Z`````#&1"1'`>LR2(N[*`$``$B+
+M5"082(MT)!#H`````$V)\(M,)#R+5"1`BW0D#$B)W^@`````QD0D1P%!@\0!
+M1#AE6`^':O___X!\)$<`#X7/`@``0<=&4/____],B?=!_U9(Z;L"``!F9I!F
+MD(#Z`P^%G````(!Y`@%F9I`/A8(````/MD,^C30`#[9Y`XGZB?C!^A_W_HG5
+M.=9^6TR-:01$#[;B#[91!$2)YDB)W^@`````C47\@_@#=AB-1?2#^`-V$(U%
+M[(/X`W8(C47D@_@#=P=(@<.0%```00^V50!$B>9(B=_H`````$''1E``````
+MZ14"``!!QT90_O___^D(`@``0<=&4/[____I^P$``(`Y!78Y@'D$_F:0=3%(
+MC50D5$B+N_@(``!,B?;H`````(3`#X72`0``QT0D5`````!!QT90_____^F]
+M`0``3(NK``D``$V%[4P/1.M(B<NX`@```$@IR$B)1"0H2&/V2(ET)"#IYP``
+M`&:0#[8K3(UB`0^VT/;"`71IBTPD5(GKC40-`$$[1B`/ATP!``!!@#\!=2>)
+MR4@#3"0P08GHO@$```!,B>_H@/?__SGH="OI)@$``&9F9I!F9I")R4@#3"0P
+M08GHO@````!,B>_H6??__SGH#X4``0```5PD5$R)X^MM2&/%2HT<($B+1"0H
+M2`'82#M$)"`/C]T```!!@#\!=1Q!B>A,B>&^`0```$R)[^@5^O__A<!T(.F[
+M````08GH3(GAO@````!,B>_H^?G__X7`#X6@````@#L`=0:`>P$`=`N_$"<`
+M`)#H`````$B-4P$/MD,!A,`/A0O___\/M@.$P'1[#[;8N50```"Z`@```+X`
+M````3(GOZ-KO__^+5"1408M&("G0.<,/1]A!@#\!=1Z)T4@#3"0P08G8N@``
+M``"^`0```$R)[^AY]O__ZQR)T4@#3"0P08G8N@````"^`````$R)[^A;]O__
+MA<!X!@%$)%3K"$''1E#_____N50```"Z`@```+X`````3(GOZ&+O__]FD$F+
+M5CA(A=)T!HM$)%2)`DR)]T'_5DA(@\186UU!7$%=05Y!7\-F9F:09F9FD&9F
+MD$B#[`A(BX<`"0``2(7`2`]$QTB+N/@(```/MH=O%```A,!T#8/H`8B';Q0`
+M`(3`=1W&!0``````N2````!(Q\(`````O@X```#H`````$B#Q`C#9F9FD&9F
+MD&9FD&9FD$B#[`A(BX<`"0``2(7`2`]$QTB+N/@(``"`OVX4````=22`AV\4
+M```!Q@4``````;D@````2,?"`````+X.````Z`````!(@\0(PV9FD&:02(/L
+M&$B)7"0(3(ED)!!)B?Q(B=!`#[;608G(2(G!O@````#H*/C__XG#N50```"Z
+M`@```+X`````3(GGZ#_N__^)V$B+7"0(3(MD)!!(@\08PY"0D)"0D)"0D)"0
+MD)"0B?9(BT<(2"T``@$`2`'&BP:)!0````##9F9FD&9F9I")]DB+1PA(+0`"
+M`0!(`<:)%L-F9F:09F9FD&9FD&9FD%-(B?M(BU<(2('J``(!`,>"@``!````
+M``"+@@0!`0")!0````"`S`&)@@0!`0"Z!````+X,P@``Z`````"ZN`L``+X(
+MP@``2(G?Z`````"Z`0`,`+X`P@``2(G?Z`````"Z!````+X,PP``2(G?Z```
+M``"ZN`L``+X(PP``2(G?Z`````"Z`0`,`+X`PP``2(G?Z`````!(BT,(2"VT
+M`0``9L<```!(BT,(2"V4`0``#[<`9HD%``````^WP$B+4PA(@>J4`0``@\@$
+M9HD"2(M#"$@MF`$``&;'``0`9L>#;!0``/__6\-F9F:09F9FD$B+5PA(@>H`
+M`@$`BX)L``$`B04`````#,B)@FP``0##2(M7"$B!Z@`"`0"+@F@``0")!0``
+M```D-PGPB8)H``$`PV9F9I!F9F:09F:09F:04T@YO_@(``!U:(GPP.@"0;L`
+M````1`^VT$ECVHGP@^`#1(T,0+@'````1(G)T^#WT$2+1)]002'`1(E$GU"$
+MTG0.N`0```#3X$0)P(E$GU!)8\*+5(=000^V\\'F"('&4,(``$B+O_@(``#H
+M`````%O#B?#`Z`*#Z`1!NP$```#KDV9F9I!F9F:09F:09F:005=!5D%50515
+M4TB#[`A(B?U!B?9!B==!B<U(BT<(3(L@3(GGZ`````!(B<-(A<`/A.L```!,
+MB>?H`````$B)PDB%P`^$UP```,9%7`'&0SCAQD,Y`<9#.A#&0R6[#[9%6V:)
+M0R!,B6,HQT,TD````$B-0A!(B4-(2(E3>$B)P4B)PK@`````Q@00`$B#P`%(
+M/9````!U\,9!`8+&`4!$B'$"1(AY`T2(:01!@/T"=R%(C7D(2HT4K0````"!
+MXOP#``!)C;0DJ!(``.@`````ZRM)BX0DJ!(``$B)00A(C7D000^VU8T4E?C_
+M__](8]))C;0DL!(``.@`````2,>#H`````````!(C7M8O@````#H`````$B)
+MWDR)Y^@`````2(/$"%M=05Q!74%>05_#D$B#[#A(B5PD"$B);"003(ED)!A,
+MB6PD($R)="0H3(E\)#!(B?U!B?5!B=9!B<](BT<(3(L@3(GGZ`````!(B<-(
+MA<!T>TR)Y^@`````2(G"2(7`=&O&15P!QD,XX<9#.0'&0SH0QD,ENP^V15MF
+MB4,@3(EC*,=#-)````!(C4(02(E#2$B)4WC&0`$"QD(00$2(:`)$B'`#1(AX
+M!$C'@Z``````````2(U[6+X`````Z`````!(B=Y,B>?H`````$B+7"0(2(ML
+M)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD&9FD&9FD&9FD$%6055!
+M5%532(G[08GU08G62(M'"$B+*+D"````N@````"^`````.@`````@'M<`'08
+M2(GOZ`````"_`0```.@`````@'M<`'7H2(M#"$B+`$@%J!(``(!X`@!X.X!(
+M`H"Y`0```+H`````O@````!(B=_H`````(![7`!T&F:02(GOZ`````"_`0``
+M`.@`````@'M<`'7H1(GHP.@"1`^VX+D!````1(GBO@,```!(B=_H`````(![
+M7`!T&V9FD$B)[^@`````OP$```#H`````(![7`!UZ$B+0PA(BS!$B>GWT8/A
+M`T6$]@^5PL'B`P^VA`ZH$@``@^#G"="(A`ZH$@``N0$```!$B>*^`P```$B)
+MW^@`````6UU!7$%=05[#9F9FD&9F9I!F9I!F9I!(@^PH2(E<)`A(B6PD$$R)
+M9"083(EL)"!(B?M(B?4/MT8@9CV%`'<;3(NOD`D```^WP`^VA`=H"```3&G@
+MR`\``.L-3(NOD`D``$&\.+@/`$B+54B`>@$"=19(BT($2(F#J!(``$B+0@Q(
+MB8.P$@``2(MU>$B%]G0(2(G?Z`````!(B>Y(B=_H`````$/&1"5<`$B+7"0(
+M2(ML)!!,BV0D&$R+;"0@2(/$*,.0D)"0D$F)T4R+ET`)```/MT8@NF">`0!F
+M/84`=Q</M\`/MH0':`@``$B-%$!(C1202,'B!4V-@2`$``!!QH$@!```)V:!
+M?CCA`74I1`^V3CI!C4'_/`%W#$&Y#P```$0B3COK+D&-0>]!N0\````\`78@
+M9I!)C0020;D`````2(-X8`!T#4&Y#P```$0BB($```!!#[9``8/@\$0)R$&(
+M0`&X`0```&:!?CCA`746#[9&.H/H`3P!#Y?`#[;`9F9FD&9FD(G"P>('00^V
+M0`&#X'\)T$&(0`$/MD$&08A``@^V`4&(0`,/MD$%08A`!P^V00=!B$`/#[9!
+M`D&(0`0/MD$#08A`!0^V001!B$`&#[9!`4&(0`P/MD$*08A`"`^V00M!B$`)
+M#[9!#$&(0`H/MD$(08A`"P^V00E!B$`-PV9FD&:00`^VQ\-F9F:09F9FD&9F
+MD(GX#[;$PV9F9I!F9I!F9I#&1R0"2(M'4$"(<`)(BT=0QD`'`$B+1U"(4`S#
+M9F9FD`^V1SV(1@(/MD<\B$8##[9'.XA&!`^V1SJ(1@K#9F:0#[9'08A&`@^V
+M1T"(1@,/MD<_B$8$#[9'/HA&"@^V1SV(1@L/MD<\B$8,PV9FD&:0A=)^(;D`
+M````9F9FD&9FD(G0*<B#^`(/G<`/ML"-3`$!.<I_Z_/#9F:09F:09F:02(/L
+M*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($B)^TB)U4&)]@^V1S@\*G0E/"IW
+M$3PH#X7=````9F9FD&9FD.L0/(AT*CR*#X7(````9I#K'D0/MF-`1`^V:S](
+MB>Y(B=_H`````.L<9F9FD&9FD$0/MF-%1`^V:T1(B>Y(B=_H`````,9%!4"+
+M@Y0```"I```!`'0P1(AE`$2(;0A"C03U`````(A%`0^V0S@\*'0$/(AU"\9%
+M!F#K6V9FD&:0QD4&8>M0J0``!`!F9I!FD'0@1(AE`42(;0D/MD,X/"AT!#R(
+M=0;&108EZRK&108UZR1$B&4!#[9#.H/@#PA%!0^V0S@\*'0$/(AU!L9%!LCK
+M!,9%!LI(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9I!F9I!F
+M9I`/MD<Z"D<["D<\"D<]#[;`#[970(/B`0G0=!6Z)````+X%````Z`````#S
+MPV9F9I#&1@;L2,>'H`````````##2(/L($B)'"1(B6PD"$R)9"003(EL)!A(
+MB?M(B?4/MD<X/"]T"SR/=5GK%V9FD&:01`^V9T!$#[9O/^@`````D.L/1`^V
+M9T5$#[9O1.@`````QD4%0/:#E@````1T$D2(90%$B&T)QD4&0NL69F9FD$2(
+M90$/MD,Z@^`/"$4%QD4&0$B+'"1(BVPD"$R+9"003(ML)!A(@\0@PV9FD&9F
+MD$B)\<9"!4`/MD8X/#5T!CR1=2/K&P^W1VB#X`&#^`$9P(/@_8/H%HA"!NLD
+M9F9FD,9"!NKK&KHD````O@4```!(B<_H`````//#9F:09F:0]D$Y`G0$QD$D
+M`//#9F9FD/9'//!T#[HD````O@4```#H`````//#9F:09F:09F:02(/L"$F)
+M\+@`````9F9FD,8$"`!(@\`!2(/X#77R00^V0#@\-0^$G0```#PU=RD\*'1B
+M/"AW#CP;#X6A`P``D.F;````/"IT3#PO9F:09I`/A8H#``#K6#R/9F:09F:0
+M=$X\CW<2/(AT*SR*9F9FD`^%:@,``.L=/)%F9I!F9I!T1CSA#X56`P``9F:0
+M9F:0Z80````/MO)(B<I,B<?H`````,=$)`0!````Z3@#``!(B<Y,B<?H````
+M`,=$)`0!````Z2`#``!(B<I,B<;H`````,=$)`0!````Z0@#``!!]D`\`70A
+MQD$&<,9!!`#&00,`QD$"`,9!!4#'1"0$`0```.G@`@``QD$&X,=$)`0!````
+MZ<\"``!!@'@Y`0^%O`(``$&`>#H<#X>Q`@``00^V0#K_),4`````QD$'!,=$
+M)`0!````Z9P"``#&00<`QT0D!`$```#IBP(``,9!!NS'1"0$`0```.EZ`@``
+MQD$&[\8!`T$/MD`[@\A`B$$!QT0D!`$```#I6P(``,9!!N_&`0?'1"0$`0``
+M`.E'`@``QD$&0,9!`0'&005`QT0D!`$```#I+@(``,9!!N_&`0-!#[9`.X/(
+M"(A!`<=$)`0!````Z0\"``#&00;OQ@$"QT0D!`$```#I^P$``,9!!N_&`8+'
+M1"0$`0```.GG`0``QD$&[\8!!L=$)`0!````Z=,!``#&00;OQ@&&QT0D!`$`
+M``#IOP$``,9!!N-!#[9`.XA!`<=$)`0!````Z:8!``#&00:PQ@'8QD$#3\9!
+M!,+'1"0$`0```.F*`0``QD$&L,8!V<9!`T_&003"QT0D!`$```#I;@$``,9!
+M!K#&`=K&00-/QD$$PL=$)`0!````Z5(!``#V1V@!=!'&00;JQT0D!`$```#I
+M.P$``,9!!N?'1"0$`0```.DJ`0``QD$&[\8!JL=$)`0!````Z18!``#&00;O
+MQ@%5QT0D!`$```#I`@$``,9!!B_&00$!QD$"$,=$)`0!````Z>D```#&00;D
+M00^V0#R(`4$/MD`]B$$(00^V0#N(007'1"0$`0```.G!````00^V0#N(009!
+M#[9`/(@!00^V0#V(00)!#[9`/HA!`T$/MD`_B$$$00^V0$&(00I!#[9`0(A!
+M`<=$)`0!````Z7T```#&00;H00^V0#R(`4$/MD`]B$$(00^V0#N(005!#[9`
+M/HA!`D$/MD`_B$$#00^V0$"(001!#[9`08A!`<=$)`0!````ZSC'1"0$`0``
+M`$'V0#P!="G&009PQD$$`,9!`P#&00(`QD$%0,=$)`0!````ZPMF9I#'1"0$
+M`````(M$)`1(@\0(PV9F9I!F9F:09F9FD&9FD%-(@^P@2(GS2(M.2$C'!"0`
+M````2,=$)`@`````2,=$)!``````2,=$)!@`````]H&G````!'0-2(N1R```
+M`$B#Z@'K!HM1>(/J`8![."5U84B)T$C!Z!B(!"1(B=!(P>@0B$0D`4B)T$C!
+MZ`B(1"0"B%0D`_:!U0```!!U%,9$)`8"QD0D!P"X"````.FN````2(U\)`1(
+MC;'J````N@0```#H`````+@(````Z8X```!(B=!(P>@XB`0D2(G02,'H,(A$
+M)`%(B=!(P>@HB$0D`DB)T$C!Z""(1"0#2(G02,'H&(A$)`1(B=!(P>@0B$0D
+M!4B)T$C!Z`B(1"0&B%0D!_:!U0```!!U%<9$)`H"QD0D"P"X(````.LD9F9F
+MD$B-?"0(2(VQZ@```+H$````Z`````"X(````&9FD&:02(M[2$ACT$B)YN@`
+M````2(/$(%O#9F9FD&9F9I!F9I!32(GS2(M74$B+"@^V1C@\+W1?/"]W*SP;
+M#X0Q`0``/!MW#SP2#X5%`0``9F:09I#K0#PH=#P\*@^%,@$``&:0ZS`\BG0L
+M/(IW&#PU9F9FD`^$^@```#R(#X42`0``9I#K$#R/=`P\X0^%`@$``&:0ZW7V
+M1V@!=`J!BY0```````0`]D=J$`^$%`$``$B#?V``#X4)`0``#[9#.#PH=!`\
+M*G0,/(AT"#R*#X7Q````]D(,`744#[9R"$B)S^@`````A,`/A-<```"`>R2!
+M#X3-````@8N4```````!`+@!````Z;X```"`?CD!#X6D````@'XZ'`^'F@``
+M`$@/ODXZN`$```!(T^"I]C_`'74CJ0A`!@!U#*D``"``=2-F9I#K<X..E```
+M``BX`0```&:0ZW.#CI0````!N`$```#K98..E````""X`0```.M79I#V1V@!
+M=`J!BY0```````0`@XN4`````;@!````ZS=FD(N#E````*D``"``=!CV1V@!
+M=!T-```$`(F#E````+@!````ZQ"X`````.L)9F9FD+@!````6\.0D)"0D)"0
+MD)!(BW\(10^VP$'!X`0/MM+!X@A!"=!$B<"#R`2$R40/1<!!@_G_=!E(C9<`
+M_O[_1(G()?__`P")@@3(``!!@\@"1(D&PV9F9I!F9F:09F9FD$B+1PA(+0`"
+M`0"#S@&)L`#(``##9F9FD&9F9I!F9F:005154T&)]$B+1PB%]G1,2"T``@$`
+M2(VH`,@``(N``,@``(D%`````+L`````J`%U#^LABT4`B04`````J`%T%+\*
+M````Z`````"#PP%$.>-UX>L'N`````#K!;C_____6UU!7,-F9F:09F9FD&9F
+MD%532(/L&$B)^\=$)!0`````2(MO",:'<!0````/MA4`````2(UT)!1!N0``
+M``!!N`(```"Y`0```.CB_O__BW0D%$B)W^@F____OJ"&`0!(B=_H.?___X7`
+M=55(C84`_O[_BX`,R```B04`````B40D%#T?8P``=3?'@V`4```?8P``QX-D
+M%``````$`,>#:!0``````0!(QX-X%````````&:X``#I5P(``&9FD&:0QT0D
+M%`````!(BVL(QH-P%````0^V%0````!(C70D%$&Y_____T&X`@```+D!````
+M2(G?Z#C^__^+="042(G?Z'S^__^^$"<``$B)W^B/_O__A<!U;DB-A0#^_O^+
+M@`S(``")!0````")1"04/1]#``!T+3T?1```=4G'@V`4```?1```QX-D%```
+M```'`,>#:!0``````0#IDP$``&9FD,>#8!0``!]#``#'@V04``````0`QX-H
+M%``````!`.EM`0``QT0D%`````!(BVL(QH-P%`````^V%0````!(C70D%$&Y
+M`````$&X`@```+D!````2(G?Z'7]__^+="042(G?Z+G]__^^$"<``$B)W^C,
+M_?__A<!U4$B-A0#^_O^+@`S(``")!0````")1"04/;]#``!U,L>#8!0``+]#
+M``#'@V04`````"``QX-H%````!```$C'@W@4````````9K@``.GJ````QT0D
+M%`````!(BVL(QH-P%`````^V%0````!(C70D%$&Y`````$&X`@```+D!````
+M2(G?Z-#\__^+="042(G?Z!3]__^^$"<``$B)W^@G_?__A<!U9TB-A0#^_O^+
+M@`S(``")!0````")1"04/>\1``!T"3WO$@``=4+K(,>#8!0``.\1``#'@V04
+M``````0`QX-H%``````!`.L^QX-@%```[Q(``,>#9!0`````"`#'@V@4````
+M``$`ZQZX_____^LG9F:09I!(QX-X%````````+@`````ZQ!(QX-X%```````
+M`+@`````2(/$&%M=PV9F9I!F9I!(@^PH2(E<)!!(B6PD&$R)9"0@2(G[B?=)
+MB=1(BVL(@/D$N`0````/1\A(BX-X%```#[90!$B-="0,08GY1`^VP;D!````
+M2(G?Z,+[__^+="0,2(G?Z`;\__^^$"<``$B)W^@9_/__NO____^%P'4@2(V%
+M`/[^_XN`#,@``(D%`````(E$)`Q!B00DN@````")T$B+7"002(ML)!A,BV0D
+M($B#Q"C#9F9FD&9FD&9FD%532(/L&$B)^TB)U4B+AW@4```/ME`+2(U$)!1!
+MB?%!N`$```"Y`0```$B)QN@N^___BW0D%$B)W^AR^___OA`G``!(B=_HA?O_
+M_[K_____A<!U&DB+0PA(+?0Y``"+`(D%`````(A%`+H`````B=!(@\086UW#
+M9F:09F:09F:005=!5D%505154TB#[!A(B?M!B<U!B?=!B=:%R0^$C@```+T`
+M````3(MC"$B+@W@4```/ME`"0;G_____0;@!````N0$```!(C70D%$B)W^B,
+M^O__BW0D%$B)W^C0^O__OA`G``!(B=_HX_K__X7`=2E)C80D`/[^_XN0#,@`
+M`(D5`````$2)^"'01#CP=0>X`````.L?B50D%+\*````Z`````"#Q0%$.>T/
+MA7?___^X_____TB#Q!A;74%<05U!7D%?PV9F9I!F9F:09F9FD%-(@^P02(G[
+M2(N'>!0```^V$$B-="0,0;G_____0;@`````N0````#HX_G__XMT)`Q(B=_H
+M)_K__[X0)P``2(G?Z#KZ__^%P'4FN>"3!`"Z`@```+X#````2(G?Z,_^__^Z
+M`````(7`=`MF9I!F9I"Z_____XG02(/$$%O#9F:02(/L*$B)7"082(EL)"!(
+MB?N)]<9$)!?_2(U4)!?H`````(7`=7*`?"07`'1S2(G?Z$O___^#^/]T7DB+
+M@W@4```/ME`*2(UT)!!!B>E!N`````"Y`````$B)W^@P^?__BW0D$$B)W^AT
+M^?__OA`G``!(B=_HA_G__X7`=1NYX),$`+H`````O@,```!(B=_H'/[__X7`
+M=`BX_____^L&D+@`````2(M<)!A(BVPD($B#Q"C#9F9FD&9F9I!F9F:02(/L
+M6$B)7"0H2(EL)#!,B60D.$R);"1`3(ET)$A,B7PD4$B)_4&)]HG+2(._>!0`
+M```/A/@"``!)B==%A,`/A%P!``"#_O]U%P^WAV`4``!FB0*X`0```.GY`@``
+M9F:0@_[^=1*+AV04``")`K@!````Z=\"``"#_OUU%(N':!0``(D"N`$```#I
+MR`(``&:0`?.)7"0,.Y]D%```#X>.`@``B?.#X_Q!B?1!@^0#=&),C6PD)+D$
+M````3(GJB=[H_/O__X/#!+H$````.5PD#',-1(G@1"GPBTPD#(T4"$0YXG8N
+M1(GA3(G_9F:09F:0B<A!#[9$!0"(!TB#QP&#P0$YT77KB=!$*>"#Z`%-C7P'
+M`42+9"0,08/D_$0YXW,J3(UL)"2Y!````$R)ZHG>2(GOZ(G[__^+1"0D08D'
+M28/'!(/#!$$YW'?;.5PD#`^&XP$``$R-9"0DN00```!,B>*)WDB)[^A5^___
+MBW0D#"G>#X3``0``N0````"Z`````$$/M@040H@$.H/!`4B#P@$Y\0^$G@$`
+M`.OF9F:09I"#_O]U*X`Z#W41QH=Q%````;@!````Z9L!``#&AW$4````N`$`
+M``#IB@$``&9F9I")3"04B<@!\#N'9!0```^'3`$``("_<10````/A#\!``")
+M\+H`````][=H%```A=(/A8T```"`OW`4````=`WH`````(7`#X44`0``2(GO
+MZ)S\__^#^/\/A`,!``!(BX5X%```#[90!DB-="0D18GQ0;@`````N0````!(
+MB>_H??;__XMT)"1(B>_HP?;__[X0)P``2(GOZ-3V__^%P`^%O````+G@DP0`
+MN@````"^`P```$B)[^AE^___A<`/A9T```"%VP^$G````,=$)!``````BT0D
+M$$6+)`=$BVPD$$4!]4B+70A(@>L``@$`2(GOZ/K[__]$B:,(R```2(N%>!0`
+M``^V4`5%B>E!N`0```"Y`````$B-="0D2(GOZ-WU__^+="0D2(GOZ"'V__^^
+M$"<``$B)[^@T]O__A<!U(+F($P``N@````"^`0```$B)[^C)^O__A<!T%V9F
+MD&:0N`````#K'[@!````9F9FD.L4@T0D$`2+1"00.40D%';FZ4W___](BUPD
+M*$B+;"0P3(MD)#A,BVPD0$R+="1(3(M\)%!(@\18PY"0D)"0D)"X`````,-F
+M9F:09F:09F:0N``````Y/0````!^-TACQTC'P0````!(C01`2,'@`P^W%`AF
+MB18/MU0(`F:)5@(/ME0("(A6"`^V1`@)B$8)N`$```#SPV9F9I!F9I!F9I"X
+M("L``,-F9F:09F:09F:0N-````##9F9FD&9FD&9FD+@(````PV9F9I!F9I!F
+M9I"^`````$&X`````+D`````#[:4.>@(``"`^O]T2HV!@````&8]@0!W!X/&
+M`>LY9I`/ML)(BY=H"0``2(T$P$C!X`6`O!`5`0```W4808/``4&-0`.#^`9V
+M#H/&`4&X`````.L#@\8!2(/!`4B#^09UGXGPPV9F9I!F9F:09F9FD$B)^4&Z
+M`````$&[`````$&Y@````$`/MO:#Q@%F9F:018G(#[:!Z`@``#S_=%!F08'Y
+M@0!W"D&#P@'K/69F9I`/ML!(BY=H"0``2(T$P$C!X`6`O!`5`0```W4908/#
+M`4&-0P.#^`9V$$&#P@%!NP````#K!$&#P@%$.=9T%TB#P0%!@\$!08'YA@``
+M`'610;@`````1(G`PV9F9I!F9I#SPV9F9I!F9F:09F:09F:0QH?+`````,-F
+M9F:09F9FD+C_````2(7_=$2^_____[D`````#[:$.>H(```\_W0@#[;`2(N7
+M:`D``$B-!,!(P>`%#[:$$!0!``!`.,8/1_!(@\$!2(/Y!'7*0`^VQO/#N```
+M``##9F9FD&9FD&9FD$B+M_@(``"_`````$&X`````+D`````#[:4,>@(``"`
+M^O]T3XV!@````&8]@0!W!8/'`>L^#[;"2(N6:`D``$B-!,!(P>`%@+P0%0$`
+M``-U'T&#P`%!C4`#@_@&=A6#QP%!N`````#K"F9F9I!F9I"#QP%(@\$!2(/Y
+M!G6:2(NV^`@``$B!QI`4``"Q`&9FD`^VE#'H"```@/K_=$J-@8````!F/8$`
+M=P>#QP'K.6:0#[;"2(N6:`D``$B-!,!(P>`%@+P0%0$```-U&$&#P`%!C4`#
+M@_@&=@Z#QP%!N`````#K`X/'`4B#P0%(@_D&=9^)^,-F9F:09F9FD&9F9I")
+M\,#H!(U(5XU0,#P*#T/1B!>)\(/@#X/X"7X*B?"#X`^#P%?K"(GP@^`/@\`P
+MB$<!PV9F9I!F9F:09F:09F:02(/L$$B)'"1,B60D"$B)^T&)]$R)X`^V].BB
+M____00^V]$B#PP)(B=_HDO___TB+'"1,BV0D"$B#Q!##9F9FD,="!`````#'
+M`@````"X`````,-F9F:09F:09F:09F:02(M'8$B%P'112,=`0`````"`2$P$
+M2,='8`````!(QT=P`````$C'1V@`````BT<(@_@_?Q-(BU=X2)A(QX3":`0`
+M``````##2(M7>$B82,>$PF@"````````\\-F9F:02(M'8$B%P'112,=`0```
+M``"`8$S[2,='8`````!(QT=P`````$C'1V@`````BT<(@_@_?Q-(BU=X2)A(
+MQX3":`0```````##2(M7>$B82,>$PF@"````````\\-F9F:02(/L"$C'QP``
+M``#H`````+@`````2(/$",-F9I!F9I!54TB#[#C&!"1MQD0D`?_&1"0"(\9$
+M)`,4QD0D!#K&1"0%[\9$)`86QD0D!Y)(BZ\`"0``2(7M2`]$[TB-1"002(G"
+MQ@``2(/``4B)TTB-3"0P2#G(=>S&1"04`;D@````O@X```!(B>_H`````(7`
+M=4*_@!H&`.@`````N2````!(B=J^#P```$B)[^@`````@_@@=1Y(C7,02(GG
+MN0@```#\\Z8/E\(/DL"Y`0```#C"=!9(Q\<`````N`````#H`````+D`````
+M#[;!2(/$.%M=PV9F9I!F9F:09F9FD$%7059!54%455-(@^QH28G\3(N_^`@`
+M`$F!QY`4``!(BP=(A<!T$TB-L```_O](B3=(BW\@Z`````!)BW0D$$B%]G0*
+M28M\)"#H`````$F+="082(7V=`I)BWPD(.@`````2(U,)&5(C50D9DB-="1G
+M00^W?"0\2(U$)%I(B40D.$B-1"1<2(E$)#!(C40D5DB)1"0H2(U$)%A(B40D
+M($B-1"1@2(E$)!A(C40D8DB)1"002(U$)&-(B40D"$B-1"1>2(D$)$R-3"1D
+M3(U$)%3H`````$F+M"1`"0``2(7V="!)C;PD(`D``.@`````28NW0`D``$F-
+MOR`)``#H`````$F+M"1H"0``2(7V="!)C;PD2`D``.@`````28NW:`D``$F-
+MOT@)``#H`````$F+M"20"0``2(7V="!)C;PD<`D``.@`````28NWD`D``$F-
+MOW`)``#H`````$F+M"0P"P``2(7V="!)C;PD$`L``.@`````28NW,`L``$F-
+MOQ`+``#H`````(!\)&<`=$2]`````$V-M"1@"P``38VO8`L```^WW4F+M-R`
+M"P``3(GWZ`````!)B[3?@`L``$R)[^@`````@\4!#[9$)&=F.>AWT$F+M"00
+M$```2(7V="!)C;PD\`\``.@`````28NW$!```$F-O_`/``#H`````$F+M"1(
+M$```2(7V="!)C;PD*!```.@`````28NW2!```$F-OR@0``#H`````$F+M"2X
+M$```2(7V="!)C;PDF!```.@`````28NWN!```$F-OY@0``#H`````$F+M"2X
+M"0``2(7V="!)C;PDF`D``.@`````28NWN`D``$F-OY@)``#H`````$F+M"20
+M"@``2(7V="!)C;PD<`H``.@`````28NWD`H``$F-OW`*``#H`````$F+M"0@
+M"@``2(7V="!)C;PD``H``.@`````28NW(`H``$F-OP`*``#H`````$F+M"1(
+M"@``2(7V="!)C;PD*`H``.@`````28NW2`H``$F-OR@*``#H`````$F+M"3@
+M"@``2(7V="!)C;PDP`H``.@`````28NWX`H``$F-O\`*``#H`````$F+M"0(
+M"P``2(7V="!)C;PDZ`H``.@`````28NW"`L``$F-O^@*``#H`````$F+M"18
+M"P``2(7V="!)C;PD.`L``.@`````28NW6`L``$F-OS@+``#H`````$F+M"2@
+M#P``2(7V="!)C;PD@`\``.@`````28NWH`\``$F-OX`/``#H`````$F+M"38
+M#P``2(7V="!)C;PDN`\``.@`````28NWV`\``$F-O[@/``#H`````$F+M"2`
+M$```2(7V="!)C;PD8!```.@`````28NW@!```$F-OV`0``#H`````$F+M"2X
+M"@``2(7V="!)C;PDF`H``.@`````28NWN`H``$F-OY@*``#H`````$F+M"3@
+M$```2(7V="])BY0DZ!```$F-O"3`$```Z`````!)BY?H$```28NWX!```$F-
+MO\`0``#H`````$F+M"00$0``2(7V="])BY0D&!$``$F-O"3P$```Z`````!)
+MBY<8$0``28NW$!$``$F-O_`0``#H`````$F+M"1`$0``2(7V="])BY0D2!$`
+M`$F-O"0@$0``Z`````!)BY=($0``28NW0!$``$F-OR`1``#H`````$F+M"2@
+M$0``2(7V="])BY0DJ!$``$F-O"2`$0``Z`````!)BY>H$0``28NWH!$``$F-
+MOX`1``#H`````$F+M"1P$0``2(7V="])BY0D>!$``$F-O"10$0``Z`````!)
+MBY=X$0``28NW<!$``$F-OU`1``#H`````$F+M"30$0``2(7V="])BY0DV!$`
+M`$F-O"2P$0``Z`````!)BY?8$0``28NWT!$``$F-O[`1``#H`````$F+M"0`
+M$@``2(7V="])BY0D"!(``$F-O"3@$0``Z`````!)BY<($@``28NW`!(``$F-
+MO^`1``#H`````$F+M"0P$@``2(7V="])BY0D.!(``$F-O"00$@``Z`````!)
+MBY<X$@``28NW,!(``$F-OQ`2``#H`````$B#Q&A;74%<05U!7D%?PV9F9I!F
+M9I!(@^P82(E<)`A,B60D$$B)^^@`````2(G?Z`````!,C:.0%```3(GGZ```
+M``!(B=_H`````+_0!P``Z`````!(B=_H`````+X!````2(G?Z`````"^`0``
+M`$R)Y^@`````2(M<)`A,BV0D$$B#Q!C#2(/L"$"(=TM`#[;VZ`````"X`0``
+M`$B#Q`C#9F:09I!32(G[Z`````!(B[OX"```2(''D!0``.@`````6\-FD%-(
+MB?OH`````$B+N_@(``!(@<>0%```Z`````!;PV:02(/L".@`````#[;`@ST`
+M`````+H!````#T7"2(/$",-(@^PX2(E<)`A(B6PD$$R)9"083(EL)"!,B70D
+M*$R)?"0P2(G[08GT08G52(MO8$R+=WA(A>T/A!L!``"`O\L`````#X4.`0``
+M3(GWZ`````!)B<=(A<`/A/H```#&0#CAQD`Y`46$Y'0-08#]`1G`]]"#P`?K
+M"T&`_0$9P/?0@\`-08A'.D'&1R2`#[=%.&9!B4<@28E?*$''1S0`````2<='
+M2`````!)QX>@`````````$R)_DR)]^@`````QH/+`````6;'@\@```#T`4B%
+MVW1.2(M38$B%TG1/9H&[R````)8`=0Y(BWI0OB$```#H`````&:#J\@````!
+MO]`'``#H`````$R)]^@`````2(M38$B%TG0)@+O+`````'6[9H.[R`````!T
+M&D&`?R0`=1-(BT-@#[=`:F:)0UJ[`````.L%N_____],B?Y,B??H`````.L%
+MN_____^)V$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F9F
+MD&9F9I!F9F:09F:02(/L2$B)7"082(EL)"!,B60D*$R);"0P3(ET)#A,B7PD
+M0$B)_4&)]4R+9V!,BW=X387D#X1Y!```@+_+``````^%;`0``$R)]^@`````
+M28G'2(7`#X18!```]D4``@^%_````$&`_11W#$$/ML6-!$#!X`+K%[B)____
+M0?;E9L'H",#H!`^VP`7P````0<9'..%!QD<Y`4'&1SH<08A'.T'&1R2`00^W
+M1"0X9D&)1R!)B6\H0<='-`````!)QT=(`````$G'AZ``````````3(G^3(GW
+MZ`````#&A<L````!9L>%R````,0)2(7M=$Y(BU5@2(72=%-F@;W(````E@!U
+M#DB+>E"^(0```.@`````9H.MR`````&_T`<``.@`````3(GWZ`````!(BU5@
+M2(72=`F`O<L`````=;MF@[W(``````^$50,``+L`````08!_)``/A$H#``#I
+M0`,``$R)]^@`````2(E$)!!(A<`/A"H#``!)C5]82(M`$$B)!"1!QD<X&D'&
+M1SD(0<9'.AI!QD<[`$'&1SP00<9'/0!(BT0D$$F)1WA!QD<D@$$/MT0D.&9!
+MB4<@28EO*$B+1"002(M`$$F)1TA!QT<T$````$B+16!(!>P```!)B4=00<9'
+M,"!)QX>@`````````+X`````2(G?Z`````!!BU<T2(M$)!!(BW`82(G?Z```
+M``!,B?Y,B??H`````,:%RP````%FQX7(````^@!(A>UT3DB+56!(A=)T3V:!
+MO<@```"6`'4.2(MZ4+XA````Z`````!F@ZW(`````;_0!P``Z`````!,B??H
+M`````$B+56!(A=)T"8"]RP````!UNV:#O<@`````=`=!@'\D`'072(UT)!!,
+MB??H`````+O_____Z?T!``!,B?Y,B??H`````$R)]^@`````28G'2(7`=1U(
+MC70D$$R)]^@`````N______IW0$``&9FD&9FD$B-6%A(BSPD2(/'!$B+%"0/
+MMD(##[8$!XA"!,9'`0K&1P(`N`````!(BQ0DQ@00`$B#P`%(@_@$=>Y%A.UU
+M!H!G`_SK04$/MM5ITF#J``"X'X7K4??JP?H%@$\#`XG1P>D8B$\$B=;![A!`
+MB'<%B=#!Z`B(1P:(5P>(3PA`B'<)B$<*B%<+2(M$)!!)B4=X0<9'.!4/M@?`
+M^`?WT(/`$4&(1SE!QD<Z`$'&1SL`0<9'/!!!QD<]`(`G/T'&1R2`00^W1"0X
+M9D&)1R!)B6\H2(M$)!!(BT`028E'2$''1S00````2(M%8$@%[````$F)1U!!
+MQD<P($G'AZ``````````O@````!(B=_H`````$&+5S1(BT0D$$B+<!A(B=_H
+M`````$R)_DR)]^@`````QH7+`````6;'A<@```#Z`$B%[71.2(M58$B%TG1/
+M9H&]R````)8`=0Y(BWI0OB$```#H`````&:#K<@````!O]`'``#H`````$R)
+M]^@`````2(M58$B%TG0)@+W+`````'6[9H.]R`````!T#+L`````08!_)`!T
+M!;O_____2(UT)!!,B??H`````.L*9F:09I"[_____TR)_DR)]^@`````ZP6[
+M_____XG82(M<)!A(BVPD($R+9"0H3(ML)#!,BW0D.$R+?"1`2(/$2,-F9F:0
+M2(/L:$B)7"0X2(EL)$!,B60D2$R);"103(ET)%A,B7PD8$B)_4B)\TF)ST&)
+MU46)QDR+9V!-A>0/A+8#``"`O\L`````#X6I`P``28M$)%!(B40D,$B+5WA(
+MB50D"&;'A\@````0)TB)U^@`````2(E$)"A(A<`/A'<#``!!#[?%B40D!&9!
+M@_T$=A6)QDC'QP````"X`````.@`````ZQ1(BWPD".@`````2(E$)!!(A<!U
+M&4B+="0H2(M\)`CH`````+O_____Z4(#``"+5"0$P>()B50D)$B+1"0(2(NP
+M^`@``,9&/P%(B>J_!0```.@`````08!,)$P"2(M58+XA````2(M\)##H````
+M`$B+5"0H2(/"6$B)5"08183V=!5(BT0D*,>`E`````H```#&0#@HZRA(BU0D
+M*,>"E````!(```#&0C@J2(M$)!!(BW@0BU0D)$R)_N@`````2(M%8/9`:`$/
+MA($```!!@/X!&<"#X`*#Z'A(BU0D*(A".,9".0!(B=A(P>@XB$(Z2(G82,'H
+M,(A".TB)V$C!Z"B(0CQ(B=A(P>@@B$(]2(G82,'H&(A"/DB)V$C!Z!"(0C](
+MB=A(P>@(B$)`B%I!QD)"`,9"0P!$B>AFP>@(B$)$1(AJ1<9"1@#&0D<`ZT]!
+M@/X!&<"#X`*#P"A(BU0D*(A".,9".0!(B=A(P>@8B$(Z2(G82,'H$(A".TB)
+MV$C!Z`B(0CR(6CW&0CX`1(GH9L'H"(A"/T2(:D#&0D$`2(M\)"CH`````$B+
+M16`/MT`X2(M4)"AFB4(@QD(D@$B):BA(BU0D$$B+0A!(BU0D*$B)0DB+1"0D
+MB4(T2(M$)!!(B4)XQD(P($B+16!(!>P```!(B4)02,>"H`````````"^````
+M`$B+?"08Z`````!(BT0D*(M0-$B+1"002(MP&$B+?"08Z`````#&A<L````!
+M2(MT)"A(BWPD".@`````2(7M#X28````2(M58$B%T@^$BP```("]RP`````/
+MA/D```!F@;W(````E@!U#DB+>E"^(0```.@`````9H.MR`````&_T`<``.@`
+M````2(M\)`CH`````$B+56!(A=)T0("]RP`````/A*X```#KLTB+5"0H@'HD
+M`'4FNP````!%A/9T(8M4)"1(BT0D$$B+<!!,B?_H`````+L`````ZP6[____
+M_TB+5"0H2(-Z>`!T+X%Z-``(``!W$TB)UDB#QGA(BWPD".@`````ZQ-(BW0D
+M*$B#QGA(BWPD".@`````2(MT)"A(BWPD".@`````2(M$)`A(B[#X"```QD8_
+M`$B)ZK\&````Z`````!!@&0D3/WK'+O_____ZQ5F@[W(``````^%1O___^ER
+M____9I")V$B+7"0X2(ML)$!,BV0D2$R+;"103(MT)%A,BWPD8$B#Q&C#9F9F
+MD&9F9I!F9I!(@^P82(D<)$B);"0(3(ED)!!(B?-(BT=03(L@2(MN:`^V1B0\
+M('1(/"!W"H3`="(\!G<5ZS`\(G0V/")F9F:0<B2#P(`\`78=N`````!FD.MC
+M2(M'0,=`!`````#&A;(````!ZPK&A;(````-9F:02(-[>`!T)8%[-``(``!W
+M$$B-<WA,B>?H`````.L.9I!(C7-X3(GGZ`````!(B=Y,B>?H`````$B)[_^5
+MR````+@!````2(L<)$B+;"0(3(MD)!!(@\08PV9F9I!F9F:02(/L*$B)'"1(
+MB6PD"$R)9"003(EL)!A,B70D($B)^TF)]4F)U$B+;V!(A>UU"DB)U__6Z3X!
+M``!(@[^(`````'4.2(._@`````!T#V9F9I!,B>=!_]7I&P$``("]Z``````/
+MA0@!``"`?4K_9F9FD`^%^@```$B+16!(A<!T"H!X40`/A><```!(BWU0]D<,
+M$`^%V0```$R+-X"]@P````!T#4B)ZKX&````Z`````!,B:N(````3(FCD```
+M``^V54A(B="#X`9(@_@&=2GVP@%T?<9%2@7&14L$#[:5@0```$B+=5A(BWU0
+M2(GIZ`````#I?P```$B#^`1U>?;"`71T2(M58$B%TG0O#[="3J@"=&.#X/UF
+MB4).2(M%8&;'0$X!`$B+16#&0$(=2(MU8$R)]^@`````ZSS&14H#QD5+!$B)
+M[DR)]^@`````ZR>0QD5*!<9%2P9FQX7(``````!(B>Y,B??H`````.L(9I!,
+MB>=!_]5(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HPV9F9I!F9I!F9I!F
+M9I!32(G[2(7_#X3#````2(M_>.@`````2(G"2(7`#X1^````@+@5`0```'1U
+M@`L!#[:`%0$``#P"=3I(@WMP`'49#[:#S````(/@`XA#`@^V@A0!``"(0P'K
+M=P^V@\T```"(0P)(BT-P#[:`%`$``(A#`>M=/`-U60^V@\P```"#X`/!X`("
+M@\T```"(0P)(BT-P#[:`%`$``(A#`>LS9F:02(M#<$B%P'4+2(M#:$B%P'4.
+MZQP/MH`4`0``B$,!ZQ`/MH#"````B$,!9F:09F:06\-F9F:09F9FD&9FD&9F
+MD%532(/L"$B)^TB%_W1WO0`````/MH0=:`@``#S_=$$/MM!(C0122(T$@DC!
+MX`5(B<)(`Y-`"0``=":+0D@E`/__`#T``/\`=1?V0DL$=!%(BWI`2(7_=`CH
+M`````&9FD$B#Q0%(@?V`````=:9(BX/X"```2#G8=0Q(C;B0%```Z`````!(
+M@\0(6UW#9F9FD%532(/L"$B)^TB-KY`4``#H`````$B)0RA(B44H2(F;^`@`
+M`$B)G?@(``"+@Q`)``")A1`)``#&@VX4```!QH5N%````4B)W^@`````2(G?
+MZ`````!(B>_H`````+X`````2(G?Z`````!(B=_H`````(3`=&I(B>_H````
+M`(3`=%Y(B=_H`````+_0!P``Z`````!(B=_H`````,>#F`$``.@#``!(QX.H
+M`0```````$B)F[`!``!(C;.8`0``2(M[*.@`````O@````!(B=_H`````+@!
+M````ZPEF9F:0N`````!(@\0(6UW#9F9FD%-(B?OH`````$B!PY`4``!(B=_H
+M`````+@!````6\.005=!5D%505154TB#[!A(B70D"$B)%"2#/0``````#X5O
+M`0``QP4``````0```$2+/0````#'1"04`````$G'Q0````!(Q\,`````2<?&
+M`````.EV`@``#[>&`````,'@$$(/MQ0N"=`YQ0^%\0```$&X`````+\`````
+M9F:09I!F@SP?`'5?26/02(G12,'A!4J+!"Y(B0090HM$+@B)1!D(#[:!````
+M`$C!X@-(C3P"#[9$)!.(1+L-#[:!`````$B-/`(/MD0D$HA$NPX/MH$`````
+M2`'"QD23#P"`@0`````!ZW0/MH\`````#[;!N@````!"]S0VA=)T2P^VP4EC
+MT$B-#-4`````2(T\`0^V1"03B$2[#4C!X@4/MH(`````2(T\`0^V1"02B$2[
+M#@^V@@````!(`<'&1(L/`(""``````'K$D&#P`%(@\<@08/X!`^%)O___X.&
+M``````%!@\(!2(/&&$4Y^@^%Y?[__T&#Q`%!@_P@#X47`0``@T0D%`&!?"04
+M_P````^%.@$``$B#?"0(`'0(2(M4)`C&`@"+-0````"]`````(7V?C6Y````
+M`+T`````N@`````#J@````!(@WPD"`!T#8N"`````$B+7"0(``.#P0%(@\(8
+M.?%UVDB#/"0`#X3L````0;H`````0;D`````2<?$`````&9#@SPA``^$S0``
+M`$$/MI$`````A-)T9T&X`````$ECPDR-',4`````#[;"@^@!2(U8`4N-!`-(
+MC32%`````$B+/"2Y!````/SSI@^7P@^2P#C"=2%(@WPD"`!T#T$/MH$`````
+M2(M4)`B(`D$/MJD`````ZPE)@\`!23G8=;1!@\(!28/!($&#^@1T3.EN____
+M1(AD)!*Y`````+H`````1(GFBWPD%.@`````B<5!N@````"^`````$6%_P^/
+MC_W__^FE_O__#[9$)!2(1"030;P`````Z[E`#[;%2(/$&%M=05Q!74%>05_#
+M9F9FD&9F9I!F9F:09F:02(/L&$B)'"1(B6PD"$R)9"00B?5,BV=X2(M?8/8'
+M`71?2(M[6$B%_W000`^VU@^VLX$```#H`````$B+NR`!``!(A?]T$$`/MM4/
+MMK,-`0``Z`````!,B>?H`````$B%P'0M@+@5`0```'0D0`^VU4B+<T!,B>?H
+M`````.L29I!`#[;62(MS0$R)Y^@`````2(L<)$B+;"0(3(MD)!!(@\08PV9F
+M9I!F9I!F9I!F9I!(@^Q(2(E<)!A(B6PD($R)9"0H3(EL)#!,B70D.$R)?"1`
+M2(G[08GT2(MO8$R+;WA(A>T/A#<#``"`O\L`````#X4J`P``]@<"#X4A`P``
+M#[:%F`$``(3`=`M`./!U.I#I"P,```^V#X/A`0^VR0^V5P(/MG<!1`^VA0\!
+M``!(Q\<`````N`````#H`````+O_____Z=P"``!,B>_H`````$F)QDB%P`^$
+MPP(``$B+0V`/M@N#X0$/MLD/ME,"#[9S`44/MLQ$#[:`#P$``$C'QP````"X
+M`````.@`````0<9&..%!QD8Y`4&`_`(/E<"#P!I!B$8Z0<9&)(`/MT4X9D&)
+M1B!)B5XH0<=&-`````!)QT9(`````$G'AJ``````````3(GV3(GOZ`````#&
+M@\L````!9L>#R````/0!2(7;=$Y(BU-@2(72=%-F@;O(````E@!U#DB+>E"^
+M(0```.@`````9H.KR`````&_T`<``.@`````3(GOZ`````!(BU-@2(72=`F`
+MN\L`````=;MF@[O(``````^$MP$``$&`?B0`#X6L`0``2(M#8$B)1"002(M`
+M4$R+.$R)_^@`````2(G%2(7`=19(BT0D$,:`Z0````&[`````.E[`0``3(G_
+MZ`````!)B<1(A<!U(4B+5"00QH+I`````4B)[DR)_^@`````NP````#I2@$`
+M`$B-15A(B40D",9%..'&13D!QD4Z`TB+5"00#[=".&:)12#&A9@````/2(E=
+M*,=%-``"``!)BU0D$$B)54BX`````,8$$`!(@\`!2#T``@``=?!,B65X2,>%
+MH`````````"^`````$B+?"0(Z`````"+531)BW0D&$B+?"0(Z`````!(B>Y,
+MB?_H`````,:#RP````%FQX/(````^@!(A=MT3DB+4V!(A=)T3V:!N\@```"6
+M`'4.2(MZ4+XA````Z`````!F@ZO(`````;_0!P``Z`````!,B?_H`````$B+
+M4V!(A=)T"8"[RP````!UNV:#N\@`````=":`?20`=2!(BW5(2(M\)!#H````
+M`$B+5"00#[:"F`$``(B#SP```$B#?7@`=`Q(C75X3(G_Z`````!(B>Y,B?_H
+M`````+L`````ZP6[_____TR)]DR)[^@`````ZPQF9F:09F:0N_____^)V$B+
+M7"082(ML)"!,BV0D*$R+;"0P3(MT)#A,BWPD0$B#Q$C#9F:09F:02(/L*$B)
+M7"0(2(EL)!!,B60D&$R);"0@2(G[@#X)=Q`/M@;_),4`````9F:09F:0N/__
+M___I)@$``$B+1@A(BY``"0``2(722`]$T$B+NO@(``#&AV\4```!Z`````"X
+M`````.GW````#[96"+X`````Z)GH___IY`````^V5@B^`0```.B&Z/__Z=$`
+M```/MG8(Z`````#IPP```$0/MFX(3(MG>$B+;V"X______9'6`@/A*<```!)
+MB[0D^`@``$B)^K\%````Z`````"`34P"2(M]4$B)ZKXA````Z`````"`O8,`
+M````=!]F9F:0O]`'``#H`````$R)Y^@`````@+V#`````'7E183M=`QF@TM:
+M$&:#36H0ZPIF@V-:[V:#96KO28NT)/@(``!(B=J_!@```.@`````@&5,_;@`
+M````ZQH/MG8(Z`````"0ZPX/MG8(Z`````"X`````$B+7"0(2(ML)!!,BV0D
+M&$R+;"0@2(/$*,-F9F:09F:02(/L6$B)7"1`2(EL)$A,B60D4$B)_4R+9WA)
+MBX0D^`@``(!X/P`/A;0```!(BY^`````2(M_8$0/MH\/`0``0;@!````1")%
+M``^V30(/ME4!BW4(#[:'VP```(E$)#@/MH?:````B40D,`^VA]D```")1"0H
+M#[:'V````(E$)"`/MH?7````B40D&`^VA]8```")1"00#[:'U0```(E$)`@/
+MMH?4````B00D08/@`4C'QP````"X`````.@`````2,>%@`````````"+50A(
+MB[V0````2(GN_]/K069F9I!(C9^8````28M\)"A(B=[H`````,>%F````/0!
+M``!(QX6H`````````$B)K;````!)BWPD*$B)WN@`````2(M<)$!(BVPD2$R+
+M9"102(/$6,-F9F:09F9FD&9F9I!F9I!!5T%6055!5%532(/L"$B)/"1)B?8/
+MM])(C0122(T$@DC!X`5)B<5,`Z]`"0``3(N'^`@``$F!P)`4``!,B6Y@28EU
+M0$F#?5@`=35)@WU@`'4N2(L$)`^V>$-`A/\/A#P$``!)BW50N0````!(.[#0
+M$@``#X3\`P``Z10$``!FD$&`#@%)BT5@28E&<$F+15A)B49H2(L4)`^V>D-`
+MA/]T3DF+=5"Y`````$@[LM`2``!T&^LM#[;!2(T40$B-%)!(BP0D2#FTT-`2
+M``!U&4B+%"0/MD)!C02!08B&S````.L-N0````"#P0%`./EUQDB+!"1(BXCX
+M"```#[:!Z`@``+X`````//]T*4F+55A(A=)T&P^VP$AIP,@/``!(`X&0"0``
+MO@````!(.<)T+[X!````#[:!Z0@``#S_="M)BU582(72=!\/ML!(:<#(#P``
+M2`.!D`D``$@YPG4)08AV`>GW````@\8!N@````!FD`^VA`KJ"```//]T)P^V
+MP$B-!,!(P>`%2`.!:`D``$D[16!U#$&(=@'IP````&9FD(/&`4B#P@%(@_H$
+M=<.)\4$/MH#H"```//]T)DF+55A(A=)U!8UQ`>L8#[;`2&G`R`\``$D#@)`)
+M``!(.<)UY>LK00^V@.D(```\_W0H28M56$B%TG0<#[;`2&G`R`\``$D#@)`)
+M``!(.<)U!D&(=@'K2X/&`;H`````9F:09F:00@^VA`+J"```//]T)@^VP$B-
+M!,!(P>`%20.`:`D``$D[16!U"T&(=@'K$F9FD&:0@\8!2(/"`4B#^@1UPTB+
+M%"2`>DT!=3U)BWU82(7_=!)!#[:U@0```+H`````Z`````!)B[T@`0``2(7_
+M#X2\`0``00^VM0T!``"Z`````.@`````28.](`$````/A)P!``!)BVU8@'U8
+M`'190;P`````2(U=2$F)WTB)W^@`````2(U(\$B+55!(B4502(E9$$B)41A(
+MB0*`N0\!``#_=1"`>4D`=0I(@[D@`0```'4*08/$`40X95AWNT0X95@/A9$`
+M``!!#[:%#P$``$&(1@*`?5@`#X23`0``NP````!,C65(3(GGZ`````!(C4CP
+M2(M54$B)15!,B6$02(E1&$B)`DB+04!(A<!T/`^VD0\!```X4`)T,$B#N(``
+M````=29(@[B(`````'4<B%`"#[=1.$B+!"1(B[#X"```OP<```#H`````(/#
+M`3A=6`^&&@$``.N.00^VA8$```!!B$8"0<:%#P$``/^`?5@`#X3Z````NP``
+M``!F9F:09F:03(G_Z`````!(C4CP2(M54$B)15!,B7D02(E1&$B)`H"Y#P$`
+M`/]T3,:!#P$``/](BT%`2(7`=#P/MI&!````.%`"=#!(@[B``````'4F2(.X
+MB`````!U'(A0`@^W43A(BP0D2(NP^`@``+\'````Z`````"#PP$X75AV<NN"
+M00^VA8$```!!B$8"ZV(/ML%(C11`2(T4D$B+!"1(.;30T!(``'4B2(L4)`^V
+M0D&-!(%!B$8!08B&S````#A*0W44ZPVY`````(/!`4`X^76]0<9&`?]!QD8"
+M`$&#O9`!````=`M!BX64`0``08A&`DF-3B!)C968````28N%F````$F)1B!(
+MBT((2(E!"$B+0A!(B4$02(M"&$B)01A(BT(@2(E!($F-3@Q)C96$````28N%
+MA````$F)1@Q(BT((2(E!"(M"$(E!$$F+A<````!)B49(00^W16AF08E&6$$/
+MMT5J9D&)1EI)BT5X28E&4$$/MH6"````08A&7$$/MH68`0``08B&SP```$'V
+M14P$=0E(BSPDZ`````!!#[952$B)T(/@!DB#^`9U"_;"`74&08`.`NL$08`F
+M_4$/ME5,T.J#X@1!#[8&@^#["=!!B`9!#[9&`4&(ALX```!!#[9&`D&(ALT`
+M``!,B??H`````$F+=4"Z`````$B+/"3H`````$R)]^CF^/__2(/$"%M=05Q!
+M74%>05_#9F9FD&9FD$B#[!A(B5PD"$B);"002(G]2(N?^`@``.@`````@'U-
+M`74M2(V[D!0``(!_30%T6X"]@!0```!U%[X`````Z`````"`A8`4```!9F:0
+M9F:02(V=F`$``$B+?2A(B=[H`````,>%F`$``.@#``!(QX6H`0```````$B)
+MK;`!``!(BWTH2(G>Z`````!(BUPD"$B+;"002(/$&,-F9I!F9I!!5%532(/L
+M,$F)^TB)TTB+;BA,BV8P1`^V50M(BX?X"```2(NP^`@``+\`````0;@`````
+MN0````!F9F:09F:0#[:4,>@(``"`^O]T2HV!@````&8]@0!W!X/'`>LY9I`/
+MML)(BY9H"0``2(T$P$C!X`6`O!`5`0```W4808/``4&-0`.#^`9V#H/'`4&X
+M`````.L#@\<!2(/!`4B#^09UGT&)^4B+MO@(``!(@<:0%```L0`/MI0QZ`@`
+M`(#Z_W1/C8&`````9CV!`'<%@\<!ZSX/ML)(BY9H"0``2(T$P$C!X`6`O!`5
+M`0```W4808/``4&-0`.#^`9V%8/'`4&X`````.L*@\<!9F9FD&9FD$B#P0%(
+M@_D&=9I!.?H/C>\'``!%.=$/GL#'`P`````\_P^$U`<```^V^$AI_Y`4``!)
+M`[OX"```Z`````!(B<=(A<`/A+('```/MH`5`0``/`(/A<4!``#'`P0````/
+MMG4'2(L7#[='0+D`````@+P":`@``/\/A)D!``!`@/XC#X>``0``0`^VQO\D
+MQ0````!!QP0D15,#$;@!````9I#I;0$``$B-3"0LNA`#``"^`0```.@`````
+MA,`/A$4!``"+1"0LA<`/A$`!```E_P,``&G`$"<``(V($):O_[ISB*M,B<CW
+MXHG(*=#1Z`'"P>H'08D4)+@!````Z1(!``!(C4PD++H(`P``O@$```#H````
+M`(3`#X3J````BT0D+(7`#X3E````)?\#``!IP.@#``"-B,CE]_^ZRVLHKXG(
+M]^*)R"G0T>@!PL'J!$&)%"2X`0```.FW````2(U,)"RZ"`,``+X!````Z```
+M``"$P`^$CP```(M$)"R%P`^$B@```,'H$"7_`P``:<#H`P``C8C(Y??_NLMK
+M**^)R/?BB<@IT-'H`<+!Z@1!B10DN`$```#K7$B-3"0LN@P#``"^`0```.@`
+M````A,!T.(M$)"R%P'0W)?\#``!IP.@#``"-B,CE]_^ZRVLHKXG(]^*)R"G0
+MT>@!PL'J!$&)%"2X`0```.L,N`````#K!;@!````#[;(#[;!Z?`%```\`P^%
+MU@4``,<#!````$0/MDT'2,<$)`````!(QT0D"`````!(QT0D$`````!(QT0D
+M&`````!(BQ</MH+Y````A,`/A*$```!!N`````!)B>,/ML"#Z`%,C5`!O@``
+M``"X`0```(G'1(G!T^</MH06Z@@``#S_="@/ML!(C03`2,'@!4B)P4@#BF@)
+M``!(BX&(````2(M`(`^V0`HY^'002(/&`4B#_@0/A"8%``#KO$B%R0^$&P4`
+M``^W04"`O`)H"```_P^$"04``("Y%0$```,/A?P$``!+B0S#28/``4TYT`^%
+M<O___T&`^54/A]<$``!!#[;!_R3%`````$''!"1``P,1N`$```#IOP0``$B-
+M3"0L08U!`8/@`TB+/,2Z-`,``+X!````Z`````"$P`^$DP0```^W5"0LB50D
+M+('Z__\``'420<<$)/____^X`0```.EU!```N,#AY`")T;H`````]_%!B00D
+MN`$```#I600``$B-3"0L2(M\)`BZ$`,``+X!````Z`````"$P`^$,P0``(M$
+M)"PE_P,``&G`$"<``(V($):O_[ISB*M,B<CWXHG(*=#1Z`'"P>H'08D4)+@!
+M````Z0$$``!(C4PD+$B+?"0(N@@#``"^`0```.@`````A,`/A-L#``"+1"0L
+M)?\#``!IP.@#``"-B,CE]_^ZRVLHKXG(]^*)R"G0T>@!PL'J!$&)%"2X`0``
+M`.FI`P``2(U,)"Q(BWPD"+H(`P``O@$```#H`````(3`#X2#`P``#[=$)"XE
+M_P,``&G`Z`,``(V(R.7W_[K+:RBOB<CWXHG(*=#1Z`'"P>H$08D4)+@!````
+MZ5`#``!(C4PD+$B+?"0(N@P#``"^`0```.@`````A,`/A"H#``"+1"0L)?\#
+M``!IP.@#``"-B,CE]_^ZRVLHKXG(]^*)R"G0T>@!PL'J!$&)%"2X`0```.GX
+M`@``2(U,)"Q(BSPDNA0#``"^`0```.@`````A,`/A-,"``"+5"0L@>+_`P``
+M2&G2.K@!`$B!PN-*`P!(P>H%2+A#>+1QQ%I\"DCWXDC!Z@=!B10DN`$```#I
+MG0(``$B-3"0L2(M\)`BZ%`,``+X!````Z`````"$P`^$=P(``(M4)"R!XO\#
+M``!(:=(ZN`$`2('"XTH#`$C!Z@1(N(7P:..(M?@42/?B2,'J"$&)%"2X`0``
+M`.E!`@``2(U,)"Q(BWPD$+H4`P``O@$```#H`````(3`#X0;`@``BU0D+('B
+M_P,``$AITN830`)(@<(-_TX$2+B]0GKEU92_UDCWXDC!ZA=!B10DN`$```#I
+MZ0$``$B-3"0L2(M\)!BZ%`,``+X!````Z`````"$P`^$PP$``(M4)"R!XO\#
+M``!(:=*N1>$`2('"*5*O`4BXVS2VUX+>&T-(]^)(P>H208D4)+@!````Z9$!
+M``!(C4PD+$B+?"0(NK`#``"^`0```.@`````A,`/A&L!``"+1"0LP>@/@^`!
+M08D$)+@!````Z5@!``"`?0@`=!%(BT0D"(&@&`$``/_W___K#TB+1"0(@8@8
+M`0````@``$B+?"0(Z`````"X`0```.D>`0``@'T(`'012(M$)`B!H!@!``#_
+M[___ZP](BT0D"(&(&`$````0``!(BWPD".@`````N`$```#IY````(!]"`!T
+M$4B+1"0(@:`8`0``_]___^L/2(M$)`B!B!@!````(```2(M\)`CH`````+@!
+M````Z:H```"`?0@`=!%(BT0D"(&@&`$``/^____K#TB+1"0(@8@8`0```$``
+M`$B+?"0(Z`````"X`0```.MS@'T(`'012(M$)`B!H!@!``#___[_ZP](BT0D
+M"(&(&`$``````0!(BWPD".@`````N`$```#K/(!]"`!T$4B+1"0(@:`8`0``
+M___]_^L/2(M$)`B!B!@!``````(`2(M\)`CH`````+@!````ZP6X``````^V
+MP.L%N``````/ML#K$K@`````ZPO'`P````"X`````$B#Q#!;74%<PV9F9I!F
+M9I!F9I!!5T%6055!5%532(/L.$F)_(GP2(G328G-08GV0<'N&$&)]T'![Q`/
+MMM2(5"000(AT)`](C:N0%```N`````"0Q@08`$B#P`%(/2`K``!U\$R):R"+
+M!0````"(0T"#P`&)!0````!$B',[1(A[.@^V1"00B$,Y#[94)`^(4SC&0T$`
+M00^W!"1FB4,P00^W1"0"9HE#,D&+1"0$B4,T2(V3("D``$B)DX@4``!,B6T@
+M#[9#0(A%0$2(=3M$B'TZ#[9$)!"(13D/MD0D#XA%.,9%00%!#[<$)&:)13!!
+M#[=$)`)FB44R08M$)`2)131(B96(%```#[=#,F8])"</A!0!``!F/20G#X>$
+M````9CU$(0^$``$``&8]1"%W1&8]("$/A/````!F/2`A=P]F/5`'#X7T````
+MZ=L```!F/2(AD`^$T````&8]0"%F9I!F9I`/A=0```#INP```&9FD&:09CT0
+M)P^"P````&8]$2=FD`^&H````&8M("=F@_@"9I`/AZ0```#IBP```&9FD&:0
+M9CV`)P^$?````&8]@"=FD'<N9CU`)W1N9CU`)V9F9I!W"&8],"=U<NM<9CU$
+M)V:0=%1F/6`G=6+K3&9FD&9FD&8]@')T0&8]@')F9I!F9I!W"&8]@B=U0NLL
+M9CV`D6:0=`YF/8"4=3+K'&9FD&9FD&;'0SR`D<9#/@1FQT4\@)'&13X$ZQ1F
+MQT,\@)3&0SX$9L=%/("4QD4^!$$/MD0D"(A#0D$/MD0D"(A%0KD```0`N@``
+M``"^`@```$R)[^@`````2(D#N0`@``"Z`````+X`````3(GOZ`````!(B<%(
+MB4,02(L#2(7`#X3E`0``2(7)#X3<`0``2(V0``(!`$B)4PA(C8````(`2(D#
+M2`4`0```2(E%`$B)50A(B4T01(L%`````$6%P'YGO@````"Y`````$C'QP``
+M```/MP0Y9D$[!"1U/P^W@0````!F03M$)`)U,(N1`````(/"`8F1`````$2+
+MB0````!%A<ET%40YRG80B="Z`````$'W\8F1`````(/&`4B#P1A$.<9UJDB+
+M0PA(+>!]``#'``'P`P!(BT,(2"W8?0``QP`!``#H2(M[(+YX````Z`````")
+MPB4`<```/0`@``!V%(#FCX#.($B+>R"^>````.@`````1(AT)"-$B'PD(@^V
+M5"00B%0D(0^V1"0/B$0D(+T`````0;D`````2<?$`````$R-;"0@9D.#/"$`
+M#X2B````08"Y```````/A(0```!!N`````!(8\5,C13%`````$V)ZTN-!`)(
+MC32%`````+D$````_$R)W_.F#Y?"#Y+`.,)U.T$/MH$`````@\`!08B!````
+M`$$/MI$`````A-)T'3C0=AD/ML`/MLJZ`````&;W\4&(D0````!F9F:008U0
+M`4F#P`%!#[:!`````#G0?Y"#Q0%)@\$@@_T$#X52____QX,0"0```0```+@!
+M````ZP6X`````$B#Q#A;74%<05U!7D%?PV9F9I!F9I!!5%532(G[2(GU2(M_
+M>`^V`X/@`40/MN"X`````&9FD,8$*`!(@\`!2(/X,'7R2(NWB!0``$B)\K``
+M9F:09F:0Q@00`$B#P`%(/0`"``!U\$B-3C:Z`````&9F9I!F9I`/MD13(8@$
+M40^V1%,@B$11`4B#P@%(@_H4=>5(C4X4L@`/MD13#8@$40^V1%,,B$11`4B#
+MP@%(@_H*=>5(C4XNL@`/MD1328@$40^V1%-(B$11`4B#P@%(@_H$=>5(B74@
+M2(M#4$B#P`%(B44`2(-[8`!U0?8#`70\2(M#:$B%_P^5PDB%P'02A-)T#@^V
+M0%N`O`=H"```_W4;2(M#<(32="M(A<!T)@^W0$"`O`=H"```_W08#[:#S```
+M`,'@`@)#`HA%$$&\`````.L@Z`````!(A<!T$H"X%0$```)U"0^V0P&(11#K
+M!,9%$/\/MD,"B$41N`$```#V0UH0=`0/MD-<B$42QD46$,9%%1!$B>"-%`"^
+M_?___T`B=0X)UD"(=0[!X`4/MDT,@^'?"<&(30P/MT-82,'H!X/@`<'@!H/A
+MOPG!B$T,#[=#6$C!Z`*#X`$/ME4-@^+^"<*(50T/MT-:2,'H`\'@!X/A?PG!
+MB$T,#[=#6DC1Z(/@`0'`@^+]"<*(50T/MT-82,'H`X/@`<'@!H/BOPG"B%4-
+M#[=#6DC!Z`3!X`>#XG\)PHA5#8/)$(A-#`^V`]#H@^`!@^;^"<9`B'4.#[8#
+M@^`$@^;["<9`B'4.9L=%&``0#[:#SP```(A%$P^V@\P```"(12A;74%<PV9F
+M9I!F9F:09F9FD$%6055!5%5308GU08G62(G+3(G%2(7)=!>X`````&:0Q@08
+M`$B#P`%(/:P```!U\$B%[709N`````!F9I!F9I#&!"@`2(/``4B#^"AU\DR+
+MI_@(``!!#[;U3(GGZ`````")PF:%P'0.#[?`08"\!&@(``#_=4A-BZ0D^`@`
+M`$F!Q)`4``!)B[PD^`@``.@`````02G%00^V]4R)Y^@`````B<)FA<`/A$\#
+M```/M\!!@+P$:`@``/\/A#T#```/M\)!#[:$!&@(``!F@?J!``^'4@(``$F+
+MC"20"0``#[?`2&G`R`\``$B--`%(A=L/A-8```!(BU802(72='5!#[:$).@(
+M```\_W08#[;`2&G`R`\``$B-!`&_@````$@YPG0E00^VA"3I"```//]T'`^V
+MP$AIP,@/``!(C00!2#G"=0F_@0```$"(>P*`?EH`=#"Z``````^VP@^V3`9P
+MN`$```#3X`E#((/"`3A66G81Z^3&0P+_2(M&"`^V0`V)0R#&`P$/MD99B$,!
+M2(M&>$B)0P1(BX:(````2(E##$B+AI````!(B4,4BX:@````B4,<1(EK)`^V
+MAL````")0RBX`````.DV`@``2(7M#X0H`@``187V#X@?`@``#[:&P````$$Y
+MQ@^-#P(``$ECQDB-!$!(P>`$2`'P2(V0P`````^V2@B(30`/ME()B%4!2(N`
+MT`````^V`(/@#XA%`H#Y`W0N@/D#=PZ`^0(/A:D```#IJP```(#Y!&9FD&9F
+MD'1`@/D2#X60````9F:09I#K7TECQDB-!$!(P>`$2(N4!M`````/MD(!@^`'
+M#[;`P>`(#[92`@'0C02``<")103K8$ECQDB-!$!(P>`$2(N$!M`````/MD`"
+MA,!U"<=%!`````#K/`^VP(/H%(E%!.LQ26/&2(T$0$C!X`1(BY0&T`````^V
+M0@+!X`@/ME(#`="-!(`!P(E%!.L'QT4$`````$B-30A)8\9(C01`2,'@!$B-
+MA`;0````2(U0"$B+0`A(B44(2(M""$B)00A(BT(02(E!$$B+0AA(B4$8N```
+M``#IV0````^WP$B-!,!(P>`%2(G%20.L)&@)``#&0P+_Q@,"28N4)&@)```/
+MMD00.XA#`4B+A8@````/MD`-B4,@#[:%%0$``#P"=2O'0P1(4%0`QT,,4F]C
+M:\=#$&5T4W3'0Q1O<B``#[=U/DB->Q?HRL+__^M'/`-U(<9#`1#'0R`!````
+MQT,$2%!4`,=##$5*,S1FQT,0,`#K(L9#!'8/MW4\2(U[!>B2PO__QD,,9`^W
+M=3Y(C7L-Z('"___&0QQR#[9U.4B->QWH,,+__T2):R2X`````.L%N/____];
+M74%<05U!7L-F9F:09F:0055!5%5308GU2(G3N`````#&!!@`2(/``4@]*`T`
+M`'7P2(NO^`@``$$/MO5(B>_H`````(G"9H7`=`T/M\"`O`5H"```_W5%2(NM
+M^`@``$B!Q9`4``!(B[WX"```Z`````!!*<5!#[;U2(GOZ`````")PF:%P`^$
+MD0,```^WP("\!6@(``#_#X2``P``#[?"#[:$!6@(``!F@?J!``^'C0(``$B+
+MC9`)```/M\!(:<#(#P``3(T$`4F+4!!(A=)T=`^VA>@(```\_W08#[;`2&G`
+MR`\``$B-!`&^@````$@YPG0C#[:%Z0@``#S_=!P/ML!(:<#(#P``2(T$`4@Y
+MPG4)OH$```!`B',"08!X6@!T,KH`````#[;"00^V3`!PN`$```#3X`E#((/"
+M`4$X4%IV$>OBQD,"_TF+0`@/MD`-B4,@Q@,!00^V0%F(0P%)BT!X2(E#!$F+
+M@(@```!(B4,,28N`D````$B)0Q1!BX"@````B4,<1(EK)$&`N,``````#X2+
+M`@``0;D`````00^V^4ACQTB-#(!(C0S+2(T$0$C!X`1,`<!(C9#`````#[9R
+M"$"(L:@````/ME()B)&I````2(N`T`````^V`(/@#XB!J@```$"`_@-T-$"`
+M_@-W$4"`_@(/A=,```!FD.G>````0(#^!&9F9I!F9I!T2T"`_A(/A;4```!F
+M9F:0ZWU(8\](C01)2,'@!$F+E`#0````2(T,B0^V0@&#X`</ML#!X`@/ME("
+M`="-!(`!P(F$RZP```#IA@```$ACUTB-!%)(P>`$28N$`-`````/MD`"A,!U
+M$4B-!)+'A,.L`````````.M:2&/72(T4D@^VP(/H%(F$TZP```#K1$ACSTB-
+M!$E(P>`$28N4`-````!(C0R)#[9"`L'@"`^V4@,!T(T$@`'`B83+K````.L2
+M2&/'2(T$@,>$PZP`````````2&/'2(T4@$B-E-.@````2(UR$$B-!$!(P>`$
+M28V$`-````!(C4@(2(M`"$B)0A!(BT$(2(E&"$B+01!(B4802(M!&$B)1AA!
+M@\$!13B(P`````^&Z0```.E?_O__#[?`2(T$P$C!X`5)B<1,`Z5H"0``QD,"
+M_\8#`DB+E6@)```/MD00.XA#`4F+A"2(````#[9`#8E#($$/MH0D%0$``#P"
+M=2W'0P1(4%0`QT,,4F]C:\=#$&5T4W3'0Q1O<B``00^W="0^2(U[%^BNOO__
+MZTL\`W4AQD,!$,=#(`$```#'0P1(4%0`QT,,14HS-&;'0Q`P`.LFQD,$=D$/
+MMW0D/$B->P7H=+[__\9##&1!#[=T)#Y(C7L-Z&&^___&0QQR00^V="0Y2(U[
+M'>@.OO__1(EK)+@`````ZPRX_____^L%N`````!;74%<05W#05154T&)]$B)
+MT[@`````D,8$&`!(@\`!2#VD#```=?!(BZ_X"```00^V]$B)[^@`````B<)F
+MA<!T#0^WP("\!6@(``#_=4=(BZWX"```2('%D!0``$B+O?@(``#H`````$2)
+MYBG&0`^V]DB)[^@`````B<)FA<`/A&<#```/M\"`O`5H"```_P^$5@,```^W
+MP@^VA`5H"```9H'Z@0`/AV<"``!(BXV0"0``#[?`2&G`R`\``$R-!`%)BU`0
+M2(72='0/MH7H"```//]T&`^VP$AIP,@/``!(C00!OH````!(.<)T(P^VA>D(
+M```\_W0<#[;`2&G`R`\``$B-!`%(.<)U";Z!````0(AS`D&`>%H`=#*Z````
+M``^VPD$/MDP`<+@!````T^`)0R"#P@%!.%!:=A'KXL9#`O])BT`(#[9`#8E#
+M(,8#`4$/MD!9B$,!28M`>$B)0P1)BX"(````2(E##$F+@)````!(B4,408N`
+MH````(E#'$&`N,``````#X1E`@``0;D`````00^V^4ACQTB-#(!(C0S+2(T$
+M0$C!X`1,`<!(C9#`````#[9R"$"(<20/ME()B%$E2(N`T`````^V`(/@#XA!
+M)D"`_@-T,$"`_@-W#T"`_@(/A<````#IR@```$"`_@1F9I!FD'1%0(#^$@^%
+MI@```&9F9I#K<4ACSTB-!$E(P>`$28N4`-````!(C0R)#[9"`8/@!P^VP,'@
+M"`^V4@(!T(T$@`'`B43+*.MZ2&/72(T$4DC!X`1)BX0`T`````^V0`*$P'4.
+M2(T$DL=$PR@`````ZU%(8]=(C122#[;`@^@4B433*.L^2&//2(T$24C!X`1)
+MBY0`T````$B-#(D/MD("P>`(#[92`P'0C02``<")1,LHZP](8\=(C02`QT3#
+M*`````!(8\=(C12`2(U4TR!(C7(,2(T$0$C!X`1)C80`T````$B-2`A(BT`(
+M2(E"#$B+00A(B48(2(M!$$B)1A!(BT$82(E&&$&#P0%%.(C`````#X;E````
+MZ8'^__\/M\!(C03`2,'@!4F)Q$P#I6@)``#&0P+_Q@,"2(N5:`D```^V1!`[
+MB$,!28N$)(@````/MD`-B4,@00^VA"05`0``/`)U+<=#!$A05`#'0PQ2;V-K
+MQT,09713=,=#%&]R(`!!#[=T)#Y(C7L7Z+.Z___K2SP#=2'&0P$0QT,@`0``
+M`,=#!$A05`#'0PQ%2C,T9L=#$#``ZR;&0P1V00^W="0\2(U[!>AYNO__QD,,
+M9$$/MW0D/DB->PWH9KK__\9#'')!#[9T)#E(C7L=Z!.Z__^X`````.L,N/__
+M___K!;@`````6UU!7,-F9F:09F9FD&9FD$%455-!B?1(B=.X`````)#&!!@`
+M2(/``4@]``$``'7P2(NO^`@``$$/MO1(B>_H`````(G"9H7`=`T/M\"`O`5H
+M"```_W5'2(NM^`@``$B!Q9`4``!(B[WX"```Z`````!$B>8IQD`/MO9(B>_H
+M`````(G"9H7`#X39`0``#[?`@+P%:`@``/\/A,@!```/M\(/MH0%:`@``&:!
+M^H$`#X?9````2(N-D`D```^WP$AIP,@/``!(C30!2(M6$$B%TG1Q#[:%Z`@`
+M`#S_=!@/ML!(:<#(#P``2(T$`;^`````2#G"=",/MH7I"```//]T'`^VP$AI
+MP,@/``!(C00!2#G"=0F_@0```$"(>P*`?EH`=#"Z``````^VP@^V3`9PN`$`
+M``#3X`E#((/"`3A66G81Z^3&0P+_2(M&"`^V0`V)0R#&`P$/MD99B$,!2(M&
+M>$B)0P1(BX:(````2(E##$B+AI````!(B4,4BX:@````B4,<N`````#IW@``
+M``^WP$B-!,!(P>`%28G$3`.E:`D``,9#`O_&`P)(BY5H"0``#[9$$#N(0P%)
+MBX0DB`````^V0`V)0R!!#[:$)!4!```\`G4MQT,$2%!4`,=##%)O8VO'0Q!E
+M=%-TQT,4;W(@`$$/MW0D/DB->Q?H0;C__^M+/`-U(<9#`1#'0R`!````QT,$
+M2%!4`,=##$5*,S1FQT,0,`#K)L9#!'9!#[=T)#Q(C7L%Z`>X___&0PQD00^W
+M="0^2(U[#>CTM___QD,<<D$/MG0D.4B->QWHH;?__[@`````ZP6X_____UM=
+M05S#2(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($B)^TF)]$R+=WA(BT9(
+M2(DX2(M'8$B%P'4:QH:R`````DB)]_^6R````.EJ!@``9F:09I#V0$P"=!K&
+MAK(````"2(GW_Y;(````Z4H&``!F9I!FD$R)]^@`````2(G%2(7`9I!U'D'&
+MA"2R`````DR)YT'_E"3(````Z1H&``!F9I!FD,>`E`````````!,B6!H2(M#
+M8$B)12A(BT-@#[=`.&:)12#&122`00^VA"2P````/`(/A&D!```\`G<*A,!T
+M')#I0@,``#P##X3P`0``/`20#X4Q`P``Z;@!``!(BT-@]D!H`0^$GP```$$/
+MMH0DL0```*@"=`;&13B(ZQ"#X`0\`1G`@^`%@^AVB$4X28N4))````!!#[>,
+M))@```#&13D`2(G02,'H.(A%.DB)T$C!Z#"(13M(B=!(P>@HB$4\2(G02,'H
+M((A%/4B)T$C!Z!B(13Y(B=!(P>@0B$4_2(G02,'H"(A%0(A50<9%0@#&14,`
+MB<AFP>@(B$5$B$U%QD5&`,9%1P#K;4$/MH0DL0```*@"=`;&13@HZQ"#X`0\
+M`1G`@^`%@\`JB$4X28N4))````!!#[>,))@```#&13D`2(G02,'H&(A%.DB)
+MT$C!Z!"(13M(B=!(P>@(B$4\B%4]QD4^`(G(9L'H"(A%/XA-0,9%00!(BT-@
+M2`7L````2(E%4,9%,"`/M\'!X`F)132#C90````"Z?D!``!F9F:000^VA"20
+M````/!!W!?8#`G4.0<:$)+(````&Z20$``!(C7TX#[;028VT))@```#H````
+M`$B+0V!(!>P```!(B450QD4P((&-E```````$`#&126K0?:$)+$````&#X22
+M`0``08N$))0```")133I@@$``$$/MH0DL0```(/@,#P@=1'&13@;QD4Y`<9%
+M/`#I80$``,9%.#7I6`$``$B+0V`/MD!(J`%T)Z@$=".!C90``````"``00^W
+ME"2<````9D$[E"22````=1/K8V9FD$'&A"2R````!NEF`P``00^VA"2;````
+M/.-T13SC=Q,\0G0]/+!T'3Q`=2=F9I!FD.LN/.QT#CSO="8\Y69F9I!U$.L<
+M9D&)E"22````9F:0ZPY!QH0DL@````;I%`,``,9%.+!!#[>$))````"(13E!
+M#[>$))(```"(13I!#[>$))0```"(13M!#[>$))8```"(13Q!#[>$))@```"(
+M13U!#[:$))H```"(13Y!#[:$))L```"(13]!#[:$))$```"(14!!#[:$)),`
+M``"(14%!#[:$))4```"(14)!#[:$))<```"(14-!#[:$))D```"(141!]H0D
+ML0````9T)D$/MX0DG````,'@"8E%-(.-E`````3K#D'&A"2R````!NE/`@``
+M2,>%H`````````!!#[:$)+$```"H!@^$'P(``*@"=`F#C90````(ZP>#C90`
+M```03(UM6$F+G"2X````2(7;=`M!]H0DL0````%U-DF+A"3`````2(7`#X0*
+M`@``28NV2`H``+H`````3(GG_]"%P`^$\0$``$F+GD@*``!(A=MT.4B)[^@`
+M````O@````!,B>_H`````$B#PQ"+4_!(BW/X3(GOZ`````"+0_1(@\,0A<`/
+MA8D!``#KX+X`````3(GOZ`````"+130]``@``'<[3(GWZ`````!(B<%(A<!U
+M#D'&A"2R````"^E?`0``2(M`$$B)14A(B4UXBU4T2(MQ&$R)[^@`````ZU0]
+M```!`'<_3(GW9F9FD.@`````2(G!2(7`=0Y!QH0DL@````OI&0$``$B+0!!(
+MB45(2(E->(M5-$B+<1A,B>_H`````.L.0<:$)+(````&Z>X```!!#[:$)+$`
+M``"H!`^$T````$&`O"2P`````W4>28NT)*````!(A?9T$4B+?4B+533H````
+M`.FG````28N4)+@```!(A=)U$TF+A"3`````2(7`#X6X````ZV%,BVU(J`%U
+M"DB)TV9FD&:0ZRE)BX0DP````$B%P'0<28NV2`H``+H!````3(GG_]"%P'0'
+M28N>2`H``$B#PQ"+4_!(BW/X3(GOZ`````"+0_!)`<6+0_1(@\,0A<!U*.O>
+MBT4T2(M-2(7`=!N)PDB)R,8``$B#P`%(@^H!=`GK\8.-E`````%(B>Y,B??H
+M`````.LQ2(GN3(GWZ`````!,B>=!_Y0DR````.L9NP````#I2O[__TR+;4AF
+M9I!F9I#I6O___TB+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#9F9FD&9F
+M9I!F9I!F9I!54TB#[`A(B?U(B?.X`````,8$&`!(@\`!2#V`````=?"#O1`)
+M```!#Y1#$P^V53H/MDTY#[9U.`^V13N(0P.(4P*(2P%`B#.`2Q$0#[=%,&:)
+M0P0/MT4R9HE#!HN%$`D``(A#<,9#$B`/MU4R9H'Z("%T!V:!^B(A=4C&0Q<"
+M2(U#/,=#/%)O8VO'0T!E=%)!QT`(240@4\=`#%-$(#+'0!`Q,G@@QT`40V]N
+M=,=`&')O;&QFQT`<97+&0!X`Z0D!``"-@O#8__]F@_@!=A)F@?I`(70+9H'Z
+M1"$/A:L```#&0Q<$#[=5,HV"\-C__V:#^`%W1$B-0SS'0SQ2;V-KQT-`9712
+M0<=`"$E$(#+'0`PW,7@@QT`04T%3(,=`%$-O;G3'0!AR;VQL9L=`'&5RQD`>
+M`.F3````9H'Z0"%T"V:!^D0A#X6!````2(U#/,=#/%)O8VO'0T!E=%)!QT`(
+M240@4\=`#%-$(#+'0!`Q-'@@QT`40V]N=,=`&')O;&QFQT`<97+&0!X`ZT#&
+M0Q<(2(U#/,=#/$1A=&''0T!#96YTQT`(97(@-\=`##(X,"#'0!!3051!QT`4
+M($-O;L=`&'1R;VS'0!QL97(`#[9#$O9C%X3`NH#___\/1,*(0Q!(C4,8QT,8
+M2&EG:,=#'%!O:6['0`AT(%1EQT`,8VAN;\=`$&QO9VG'0!1E<RP@QT`826YC
+M+L9`'`!(BX4("0``2(7`=`I(BT`02(E#:.L(2(M%$$B)0VC'0V``(```2(M]
+M(+Y\````Z`````")PH'B\`,``,'J!(A3<8/@#XA#<TB+?2"^@````.@`````
+MB<*!X@``\`/!ZA2(4W(E```/`,'H$(A#=$B#Q`A;7<-FD$%7059!54%455-(
+M@^P(28G]B?5(B=.X`````&9FD&:0Q@08`$B#P`%(/=````!U\(EK"(/]/WX*
+M28'%D!0``(/M0$ACQ;H`````28.\Q6@$````#X72`@``2&/%28F<Q6@$``!,
+MB6MX2(F+@````$R)@Y````!!@'U-`0^%I0(``(']A0````^/@P(``$$/MH0%
+M:`@``#S_#X1R`@``#[;`9HE$)`8/M\!(C11`2(T4D$C!X@5)B=1-`Z5`"0``
+M0?9$)$L$#X1%`@``08M$)$@E`/__`#T``/\`#X4P`@``0?9$)$P$#X2<`0``
+M0<:$).@`````00^V1"1(2(G"@^(&2(/Z!G4YJ`$/A!`!``!!QD0D2@5!QD0D
+M2P1!#[:4)($```!)BW0D6$F+?"103(GAZ`````"Z`0```.GK`0``2(/Z!`^%
+MW`$``*@!9F9FD`^$T`$``$F+7"1028M$)&!(A<`/A84```!!QD0D2@-!QD0D
+M2P2`>PX`=$^]`````$R-<V!,B??H`````$B)PDB+0VA(B5-H3(DR2(E""$B)
+M$(!Z2O]T&$DYU'030<:$).D````!N@$```#I;`$``(/%`0^V0PXYZ'^Z08"\
+M).D````!#X1-`0``3(GF3(GOZ`````"Z`0```.D]`0``@'A"``^%+@$``&:#
+M8$[]28M$)&!FQT!.(`!)BW0D8$R)[^@`````N@$```#I#`$``$F+1"10#[9`
+M#4&`?3X`="V[``````^VZ`^VRTB)Z$C3^*@!=`^Z`````(G.3(GOZ`````"#
+MPP%!.%T^=]M!QD0D2P9!QD0D2@5F0<>$),@``````$R)YDR)[^@`````N@$`
+M``#IHP```$V+9"1008!\)`X`=%U!O@````!-C7PD8$R)_^@`````2(G"28M$
+M)&A)B50D:$R).DB)0@A(B1"`>DK_="(/MD))/")T!#P-=19(8\5)QX3%:`0`
+M``````"Z`````.M$08/&`44X="0.=ZX/MU0D!DB)WDR)[^@`````N@$```#K
+M(F9F9I!F9I!(8\5)QX3%:`0```````"Z`````.L%N@$```")T$B#Q`A;74%<
+M05U!7D%?PY"0D)!(BP4`````2(E'"$B)/0````##9F9FD&9FD&9FD&9FD(L%
+M``````6H`@0`PV9F9I!(A?]T&TB+%TB%TG0,2(7V=`=(BT((2(D&2(G0PV9F
+MD$B+%0````#KWV9F9I!F9I"+1A1(C80'J`($`,-F9F:04TB)\TB![``!``!(
+MBT<(2(M_$$B-M"2`````_U`X2(M#"$B)YDB+>Q#_4#@/MD0D`3B$)($```!V
+M#K@!````2('$``$``%O#<B8/MD0D`CB$)((```!WXG(6#[9$)`,XA"2#````
+M=])R!C'`Z]%FD+C_____Z\AF9I!F9I!F9I!!5%5(B?U32(L=`````$B%VW4*
+MZWM(BQM(A=MT<TB+0Q!(A<!T<4B+50A(.U`(=>5(BW`02(M]$/]22(3`=-9(
+MBW,03(UC$$B%]G4=ZV-FD$B)[^@`````A<!X54V+)"1)BS0D2(7V=$A(BT4(
+M2(N0``$``$B%TG372#M&"'712(MV$$B+?1#_TNO-9F:09I`QP%M=05S#2,=%
+M``````!(B5T8N`$```!(B6L06UU!7,-)BP0D2(E=&$B)10"X`0```$F)+"3K
+MRF9F9I!F9F:02(L%`````$B)!XM'$$B)/0````"%P'02BP4`````B4<4`T<0
+MB04`````\\-F9F:00515B?U32(L=`````$B%VW0Q0#A["$0/MN=U"NLE9I!`
+M.&L(=!U(BT-H2(7`9F:0=`E$B>?_T(7`=0A(BQM(A=MUW4B)V%M=05S#9F:0
+M9I!32(GS2(/L,(`]``````)T/TB+=QA(C5<8,<E(.?)T(CF.H/S__TB)\'4-
+MZQYF9I`YB*#\__]T$TB+`$@YT&:0=>Z)2S!(@\0P6\.#P0'KRTB+1G!(B[N(
+M````2(GF_U!X2(N3@`````^V1"00`T)`B4,P2(/$,%O#9F9FD&9FD$B+%0``
+M``"XT````$B%TG08,<F+0AQ(BQ(YP0]"R$B%TG7PC8'0````\\-F9I!FD$B+
+M5QA(C4\82#G*="HYLJ#\__](C8)P_/__=1/K'6:0.;*@_/__2(V"</S__W0*
+M2(L22#G*=>DQP//#\\-F9I!32(M?$$B%VW0<9F:09F:02(M#"$B+>Q#_D-@`
+M``!(BQM(A=MUZEO#9F9FD&9F9I!(B?Y(BS_IU?[__V9FD&:0BU<PA=)X!\='
+M,/_____SPS'`A?9T'3'),=)F9I!F9I`/M@>#P@%(@\<!`<$Y\G7P#[;!\\-F
+M9F:09F9FD&9FD$B+!0````!(A<!T+DB+4!!(A=)T'4@Y>A!U#69FD&:0ZQI(
+M.7H0=!)(BQ)(A=)FD'7P2(L`2(7`==+SP_/#9I!(BT\82(/'&$@Y^71#3&/*
+MZPA(BPE(.<]T-H"Y@/S__P1(C8%P_/__=N@YL:C\__]UX(72>!U,BX&(_/__
+M387`=-!+.43(8'7)\\-F9I!FD#'`PTB#N8C\__\`=;7SPY!!5$F)_%5)C6PD
+M&%/H`````$F+7"082#GK="UF9I!FD(MS^$B-NW#\__^%]G022(N#>/S__TB+
+M0%A(A<!T`O_02(L;2#GK==A,B>=F9I!FD.@`````28M$)!A(.>AU"Y#K&DB+
+M`$@YZ'02BTCTA<F0=/!;74%<N`$```##6UU!7#'`PV9F9I!F9I!F9I!F9I!!
+M5#'`28G\55.`OY`"!```=2U(BU\02(7;="(Q[69FD$B+0PA(BWL0_Y"H````
+M2(L;"<5(A=MUZ$"$[74',<!;74%<PTR)Y^@`````6T`/ML5=05S#9F9FD&9F
+M9I!F9I!!5D%505152(G]4^@`````2(N=,`$``$F)QDB%VP^$G````$&)Q4B+
+M0PA(B=I,C:4P`0``1"GPA<!^$.F/````2(M""$0IZ(7`?SI(BT(H2(7`=`1,
+MB6`@2(F%,`$``$C'0B``````2(G#2,="*`````!(BWH8_U(02(N5,`$``$B%
+MTG6[2(GOZ`````!(A=MT#$B+A3`!``!(.=AT"5M=05Q!74%>PUM(BW`(2(M]
+M"%U!7$%=1"GV05[I`````%M(B>]=05Q!74%>Z0````!(B>_H`````.NY9F9F
+MD&9FD%5(B?U32(GS2(/L".@`````2(M3($B)P4B%TG0<2(M#*$B%P'0(2(E0
+M($B+4R!(B0)(QT,@`````(L#2(N5,`$``$B%TDB-!`%(C8TP`0``2(E#"'0E
+MB<9(BT((*?"%P'X,ZS)(BT((*?"%P'\H2(U**$B+4BA(A=)UZ4B)4RA(B1E(
+M.9TP`0``2(E+('0C2(/$"%M=PTB)4RA(B1E(C4,H2#F=,`$``$B)2R!(B4(@
+M==U(BWT(BS-(@\0(6UWI`````&9F9I!F9I!F9I!F9I!32(M6($B)^TB%TG1C
+M2(M&*$B+CS`!``!(A<!T"$B)4"!(BU8@2(D"2,=&*`````!(BX,P`0``2,=&
+M(`````!(A<!T+$@YP70GZ`````!(BY,P`0``2(MR""G&A?9^$TB+>PA;Z0``
+M``!F9F:09F:06\-(Q\<`````,<#H`````+[H`P``Z]AF9I!F9I!F9I!52(G]
+M4TB#[`A(BU\02(7;=1CK+DB+0PA(BWL0_Y#0````2(L;2(7;=!B`>V@`=.1(
+MBT,(2(M[$#'V_U!09F:0Z])(@\0(2(VU.`$``$B)[UM=Z0````!F9I!F9I!F
+M9I!!5$F)_%532(M?$$B%VW4*ZS1(BQM(A=MT+$B+0PA(BWL0_Y#@````@'MH
+M`'3D2(M#"$B+>Q"^`0```/]04$B+&TB%VW7428M<)!A)C6PD&$@YZW4*ZS)(
+MBQM(.>MT*H"[@/S__P%(C;MP_/__=>A(BX-X_/__2(M`6$B%P'38_]!(BQM(
+M.>MUUH`]``````!U!5M=05S#28V<)#@!``!,B>=(B=[H`````$''A"0X`0``
+M`(>3`TG'A"1(`0```````$B)WDV)I"10`0``3(GG6UU!7.D`````9F9FD&9F
+MD$%528G]05152(GU4TB#[`A(A?9T?4B+10A(BWT0_Y#@````@'UH``^%MP``
+M`$F+71A-C6483#GC=0[K/V9F9I!(BQM,.>-T,X"[@/S__P%(C;MP_/__=>A(
+M.:OP_/__==](BX-X_/__2(M`6$B%P'3/_]!(BQM,.>-US4B+;0!(A>UT&TB#
+MQ`A(B>A;74%<05W#2(MO$$B%[0^%=O___X`]``````!TW$F-G3@!``!,B>](
+MB=[H`````$''A3@!````AY,#2<>%2`$```````!(B=Y-B:U0`0``3(GOZ```
+M``#KH$B+10A(BWT0O@$```#_4%#I-/___V9F9I!F9I!32(G[Z`````!(B<''
+M0!``````2(V`T````$B-45!(B4%(BT,,+=````")04!(C4$82(E!&$B)02`Q
+MP&9FD&:0Q@00`$B#P`%(/8````!U\%M(B<C#9F9FD&9F9I!F9I!(@^P82(D<
+M)$B);"0(B=5,B60D$#'2.6X(28G\2(GS<B!(B??H`````(EH$$B)PDR)($B)
+M6`B+0PB#P`$IZ(E#"$B+'"1(BVPD"$B)T$R+9"002(/$&,-F9I!F9I!F9I")
+M\$B-M[````")PND`````BT80`T<(@^@!B4<(Z0````!F9F:09F9FD&9F9I!F
+M9I!(B?A(BS](B<9(@<>P````Z0````!F9F:09F9FD&9FD$%6055)B?U!5$R-
+M9QA54TB+7QA,.>-U$.M:9F:09F:02(L;3#GC=$R`NX#\__\!2(V[</S__W7H
+M#[:#V/S__ZA`#X6Z`0``@#T``````'30J`)US*@!#X7G`0``]H/8_/__!'6[
+M@(O8_/__)$B+&TPYXW6T28M=*$F-;2A(.>MT$4B->^CH`````$B+&T@YZW7O
+M28MM&$PYY0^$T````)"`O8#\__\$2(V]</S__W8.2(.]B/S__P`/A'(!``!(
+MBVT`3#GE==E)BUT83#GC#X2;````13'VZP]F9F:09F:02(L;2#GK=%F`NX#\
+M__\!2(V[</S__W7H]H/8_/__('3?2(N#J/S__X"CV/S__]M(A<!U&.GR````
+M9F9FD&9FD$B+`$B%P`^$WP```$B#>!@`=.U(BQM!O@$```!(.>MUITF+71A)
+M.=QT)69FD&9FD/9#\`%(C:MP_/__=`I(@[N(_/__`'0J2(L;3#GC=>%)BX68
+M`@0`2(7`#X2[````6UU!7$F+?0A)B<-!74%>0?_C#[:3@/S__X#Z!'822(N#
+M\/[__TB%P'042#EH"'0.@.H!=;/V@]C\__\"=*J+?3"%_P^(A0```/:%@`,`
+M``)TEC'V3(GOZ`````!(A<!(B<)TA$@YQ0^$>_____:`@`,```)T:("E@`,`
+M`/WI9O___^@`````Z17^__]%A/9FD`^%RO[__X`]``````%F9I`/A;K^___H
+M`````.FP_O__Z`````#IA/[__UM=05Q!74%>P^@`````Z0_^__](B>Y,B>_H
+M&/7__^EK____BT4PB4(PQT4P`````.GX_O__D$%7059!54%455-(B?M(@>R(
+M````2(7_3(MG&`^$S````$4Q]DB+0PA(BWL02(GF_U`X#[9$)!`[!0`````/
+MCI0```!,C7L@ZR=F9F:09F:01#EK*$&#U@"+%0`````/MD0D$(/"`3G0B14`
+M````?F?V1"01`740#[8%`````$0Y\`^$B0```$2+:RA!@X0DH`($``%,B?_H
+M`````$B)Q4B+0PB+-0````!(BWL028G82,?!`````$B)ZO]0:(3`=8](B>Y,
+MB?_H`````$&#K"2@`@0``>N!2(L;QP4``````````$B%VP^%-____T&+A"2@
+M`@0`@^@!A<!!B80DH`($`'5`3(GGZ(3\___K-F:0#[8%`````$C'Q@````!,
+MB>=(QP4``````````$B)'0````!IP$!"#P")!0````#H`````$B!Q(@```!;
+M74%<05U!7D%?PV9F9I!F9I!F9I!!54F)U4%428GT54B)_5-(@^P(2(M?$$B)
+ME9@"!`!(A=MU"NLL2(L;2(7;="1(BT,(2(M[$/^0\````(3`=>;&A9`"!``!
+M2(/$"%M=05Q!7<-(BQT`````2(7;=!EF9I!(BT,X2(7`=`5(B>__T$B+&TB%
+MVW7J387D=!A)BT0D"$F+?"00O@$```#_4%!!QD0D:`%(BWT0QX6@`@0``0``
+M`.@`````1(N-H`($`$6%R724387M=!E(@\0(2(GO6UU!7$%=Z0````!F9F:0
+M9F:0OZ"&`0#H`````$B)[^@`````1(N%H`($`$6%P'7BZ5/___]F9F:09F:0
+M9F:09F:02(/L&$B);"0(3(ED)!!(B?U(B1PD2(M?&$F)](.KH`($``&%TGA)
+MZ`````!(A<!T2D2+DZ`"!`!%A=)T$TB+'"1(BVPD"$R+9"002(/$&,-(B=](
+MBVPD"$B+'"1,BV0D$$B#Q!CIQOK__V9FD&9FD$B-?R#H`````.NV2(M%"$R)
+MY_^0@````$B-?2!,B>;H`````.N;9F9FD&9FD&9FD$%505152(G]4TB#[`A,
+MBR])BUTX38UE..L39F:09F:02(U[Z$B+&T@Y;U!T0DDYW'7N2(M%"$B+0%!(
+MA<!T!4B)[__02(N%D`,``$B+E9@#``!(B>Y)C7UP2(E0"$B)`DB#Q`A;74%<
+M05WI`````$B+5QA(BT<@2(U/&$B)0@A(B1!(B4\@2(E/&,:'L@````+H````
+M`.N59F9FD&9F9I!!5TF)UT%628G.055!B?5!5%5(B?U32(/L"$B+1QA(BU`8
+M2(/`&$@YPG41Z<8```!(BQ)(.<(/A+H```"`NH#\__\!2(V:</S__W7D1#NJ
+MZ/S__W7;2#NJ\/S__W722(7;#X2/````]D+P`0^%V0```$2+HF#]__]%A>0/
+MA<D```!$BYI`_?__187;#X6Y````2(M#.$B%P'4.ZU)F9F:02(L`2(7`=$9(
+MBW@82(7_D'3N2(MW&$B%]@^$CP```(!^1``/A(4````QR>L/#[9&1(U1`4B#
+MP0$YT'YR2#E\SF!UZDC'1,Y@`````.O?2(G?Z`````!,C64@3(GGZ`````!(
+MA<!(B<-T0$B+10A(B=I(BWT038GP3(GY1(GN_U!HA,"Z`0```'012(/$"(G0
+M6UU!7$%=05Y!7\-(B=Y,B>?H`````#'2Z^`QTNO<9I#H`````.DW____9F:0
+M9F:0059!54F)]4%428G\55-(@\2`2(7V#X2C`0``28ML)!!(A>UT8$&+A"2D
+M`@0`2(M]$$B)YHE%0$B+10C_4#@/MEPD$$B+10A!`9PDI`($`$B+?1#_4&!(
+MC7T@B<*)V4R)[N@`````#[9,)!!(C7U(NB@```!,B>[H`````$B+;0!(A>UU
+MH$B+#0````"Z^`,``$B%R70@9C'29F9FD&9FD(M!&$B+"3G"#T+02(7)=?"!
+MPO@#``!!BXPDI`($`$F-?"1P3(GNC0S)Z`````!!BXPDI`($`$F-O"20````
+MN@`"``!,B>[H`````$F-O"3P````N0$```"Z2````$R)[N@`````08N,)*0"
+M!`!)C;PD$`$``+HH````3(GNZ`````!!BXPDI`($`$F-O"30````NK````!,
+MB>Z-#,GH`````$''A"1H`0```0```$''A"1T`0```!```$''A"1L`0```!``
+M`.@`````28V\)+````"Y0B$``(G"3(GNZ`````!(BQT`````2(7;="-FD$B+
+M0R!(A<!T$$&+E"2D`@0`3(GN3(GG_]!(BQM(A=MUWTB#[(!;74%<05U!7L-,
+MBV\(Z53^__]F9I!F9I!F9I!!5$F)]%5(BRT`````4TB)^^@`````A<!T$XG`
+M2(G:D,8"`$B#P@%(@^@!=?-(@ST``````'4,ZW%F9F:09F:02(G%2(M%`$B%
+MP'7T2(E=`$B-0QA,B6,(QX-8`@0``!```$B)0QA(B4,@2(U#*$B)0RA(B4,P
+M2(U#.$B)0SA(B4-`2(V#$`(``$B)@Q`"``!(B8,8`@``2(V#4`(``$B)@U`"
+M!`!;74%<PTB)'0````#KG69F9I!F9I!F9I!F9I!(@^PH@#T``````DB);"0(
+M3(ED)!")]4B)'"1,B6PD&$F)_$R)="0@#X07`0``0`^V_>@`````2(7`28G%
+M#X0,`0``38UT)'!,B??H`````$B)PS'`Q@08`$B#P`%(/?@#``!U\(L%````
+M`$R):PA,B2.#P`&)!0````")@^@#``!(C8/(`P``@(N``P```4"(:Q!(B8/(
+M`P``2(F#T`,``$&+11B%P'0I2(V#^`,``$B)0R!!BT48A<!T%HG"2(G8QH#X
+M`P```$B#P`%(@^H!=>](C8.@`P``QT,T`@$``,=#,/____](B8.@`P``2(F#
+MJ`,``$B-@[`#``!(B8.P`P``2(F#N`,``$F+14A(A<!T"4B)W__0A<!U54F+
+M3"0@2(V3D`,``$F-1"0828E4)"!(B8.0`P``2(F+F`,``$B)$>L,0(#^`0^$
+MW_[__S';2(G82(ML)`A(BQPD3(MD)!!,BVPD&$R+="0@2(/$*,-(B=Y,B?<Q
+MV^@`````Z]%!5$B+%0````!52(G]2#GZ4W4(Z=,```!(B<)(A=)T#TB+`D@Y
+MZ'7P2(M%`$B)`DB+11A(C5T82#G8=!EF9F:02(VX</S__^@`````2(M%&$@Y
+MV'7K2(M%*$R-92A,.>!T,DB-G=````!F9F:09F:02(UPZ$B)WTB+1B!(BU88
+M2(E""$B)$.@`````2(M%*$PYX'7<@+V0`@0``'4I2(L=`````$B%VW0=9F9F
+MD&9FD$B+0T!(A<!T!4B)[__02(L;2(7;=>I(BUT02(7;=!>02(M#"$B+>Q#_
+MD.@```!(BQM(A=MUZEM=05S#2(L'2(D%`````.DU____D)"0D)"02(M7(#'`
+MQ@00`$B#P`%(@_A0=?)(C4(02(D22(E2"$C'0B@`````2(EZ,$B)0A!(B4(8
+M,<!(QT(X`````,-FD$B+1TB+%0````!(@^@H2`'0PV9F9I!F9F:09F:09F:0
+M2(M'(#'22(L(2#G!=!E(BQ%(BT$(2(E""$B)$$B+41A(B0E(B4D(2(G0PV9F
+MD&:0@+ZP`````$B+5R!U$@^WAI@```!(`X:0````2(E'6(-"(`%(BT=P2(N_
+MB````$R+F)@```!!_^-F9F:09F9FD/:'@`,```A(B?I(BT<@=`+SP\=`1```
+M``!(BT=P2,?&`````("/@`,```A(B[^(````3(N8B````$'_XV9F9I#VAX`#
+M```!N/____]T(46$P'0:#[?"P>`)A<!T$$B8D,8!`$B#P0%(@^@!=?,QP//#
+M9F9FD&9F9I!F9F:09F:0]D=H0$C'1T@`````=4E(BU<X2(72=$HQ]C')ZPYF
+M9I!(BQ*#P0%(A=)T(DB#>A@`=>Y(BT(02`%'2$B+0A!(BQ)(.?!(#T?P2(72
+M==Z#^0-_!4B)=T##2,='0`````"0PS'VZ^UF9F:09F9FD&9FD$AC]D@!_D@Y
+M]W,<2(GQ9I`/ME'^#[9!_XA1_XA!_DB#Z0)(.<]RZ4@Y]W0H#[8'/"!U(TB)
+M^NL'#[8"/"!U&DB#P@%(.?)U\,8'`$B#QP%(.?=U]//#2(GZA,!T(69FD$B#
+MP@$\('0J#[9"_X@'2(/'`4@YUG0'#[8"A,!UXD@Y_G31Q@<`2(/'`4@Y]W6Y
+MD.O"2#GR=.</M@*$P&9F9I!TMSP@=+,/MD+_B`=(@\<!Z\5F9F:09F9FD&9F
+MD&9FD$B+1R#'0$0!````PV9F9I!52(G]4TB#[`CV1V@"=3)(BU\X2(7;=!A(
+MBWL82(7_=`=(BT<(_U`P2(L;2(7;=>C'A?``````````2(/$"%M=P^@`````
+MZ^AF9F:09F9FD%/V1VH"2(G[2(M'('0&]D!(`G0,@T!$`5O#9F:09F:0.7!$
+M<N](BS^^`0```.@`````2(7`2(G"=-X/MH"Q````2(E:4$B)UTB)6EC&@K``
+M```$QH*R`````$C'@L@`````````@^#/@\@@B(*Q````6^D`````9F:09F:0
+M9F:04TB)^TB+/[X!````Z`````!(A<!(B<)T8/9#:@)U8<:`L`````-(QX"@
+M`````````,:`FP```$!FQX"4``````!FQX"6``````!FQX"8``````#&@)H`
+M``!`9L>`D```````9L>`D@````$`9L>`G```````2(E:4%M(B=##9I#&@+``
+M```"BP4`````B8*8````#[<%`````,:"D`````;'@I0`````````QH*1````
+M`&:)@IP```#KNF9FD&:02(/L&$B)7"0(2(EL)!!(B?M(BV\@Z";___](B<*X
+M_____TB%TG0E2,>"R`````````"`34@!2(G62(M#<$B+NX@```#_D)@````Q
+MP$B+7"0(2(ML)!!(@\08PV9FD&:0051)B?154X!_$`1(B?MV58!_1`!T2C'M
+MZQ5F9I!F9I`/MD-$C54!2(/%`3G0?C%(BWSK8$B%_W3G]H>``P```73>3(GF
+MZ``````/MD-$C54!2(/%`3G0?]9F9F:09F:06UU!7,-T./:#@`,```%FD'3N
+M2(G?Z&;^__](A<!TX4&#!"0!3(E@6$B)QTC'@,@`````````6UU!7.D`````
+M2(M?./:#@`,```%TM.O$9I#I`````&9F9I!F9F:09F:02(/L&$B)7"0(2(EL
+M)!!(BU]82(LOZ`````"+`X/H`87`B0-T#TB+7"0(2(ML)!!(@\08PTB-<PA(
+MB>](BUPD"$B+;"002(/$&.D`````9I!54TB#[`A(BRT`````QP4`````````
+M`$B%[74-ZS!FD$B+;0A(A>UT)8L=`````/^5D````#G#<^?_E9````!(BVT(
+MB04`````2(7M==M(Q\<`````@P4`````*.@`````2(/$"#'`6UW#9F:09F:0
+M2(/L&$B)7"0(2(EL)!!(BV]02(M=(`^V4TB)T(/@_HA#2("_L@````%T1>@`
+M````BT-`A<!T#TB+7"0(2(ML)!!(@\08PTB+?0!(C7,HQT-``0```$B+7"0(
+M2(ML)!!(@\082(/'6.D`````9F9FD(/B_(A32.NS9F9FD&9F9I!(BT<@@*>`
+M`P``]\>'T`````````"+4$"%TG0$\\-FD$B+/TB-<"C'0$`!````2(/'6.D`
+M````9F:09F:09F:04TB+7R!(B?A(B<9(BSM(@<<0`0``Z`````!(BSM(QX/8
+M`````````$B-L]@```!(B9O@````2,>#Z`````````!;2(/'2.D`````9F:0
+M9I!52(G]4TB)\TC'Q@````!(@^P(2(L_Z`````!(B<%(BT4X2(7`=!M(.=A(
+MC54X=0?K%T@YV'022(G"2(L`2(7`=?!(@\0(6UW#2(L#2(G>2(G/2(D"2(/$
+M"%M=Z0````!(@^PX2(E<)`A(B6PD$#'M3(ET)"A,B7PD,$F)_DR)9"083(EL
+M)"!(B?-(BT\X28G72(7)="!(B<TQP&9FD&:02(-]&`%(BVT`@]C_2(7M=>^#
+M^`-^)DB)Z$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#28T\
+M'TF)S.L823E<)`@/A+(```!-BR0D387D#X2=````28-\)!@`=>!)BU0D"$@Y
+MVG?A28MT)!!)B?U(C0062#G'=]!(.=H/A)$!``!SQ4F+/DC'Q@````#H````
+M`$B)Q^@`````2(7`2(G"#X1H____,<#&!!``2(/``4B#^"!U\DF+1"0(2(E"
+M"$B)V$DK1"0(28E<)`A(B4(028L$)$B)`DF+1"002"M"$$F)%"1).<=)B40D
+M$`^";@$``$R)Y>D4____28L$)$B%P'0XN@$```#K"$B+`$B%P'0@2(-X&`"0
+M=/!(.5@(=>I)BW0D$$@Y<!!,#T?@@\(!Z]B#Z@$/C]/^__])BU0D$$F)S4DY
+MUW<2Z9````!-BVT`387M#X2T_O__28-]&`!U[$B)T$D#1"0(23E%"'7>20-5
+M$$DYUP^'DO[__TF+/DC'Q@````#H`````$B)Q^@`````2(G",<#&!!``2(/`
+M`4B#^"!U\DR)^$D#1"0(28E%"$F+11!)`T0D$$PI^$F)11!)BP0D2(G52(E:
+M"$R)>A!(B0))B10DZ3'^__])BSY(Q\8`````Z`````!(B<?H`````$B%P$B)
+MP@^$#O[__S'`Q@00`$B#P`%(@_@@=?+KL$DY]P^$U_[__TF+/DC'Q@````#H
+M`````$B)Q^@`````2(7`2(G"#X30_?__,<#&!!``2(/``4B#^"!U\DF+1"00
+M3(EJ"$PI^$B)0A#K1TF+/DC'Q@````#H`````$B)Q^@`````2(G",<!(A=)T
+M/L8$$`!(@\`!2(/X('7R3(GX20-$)`A(B4((28M$)!!,*?A(B4(028L$)$R)
+MY4V)?"002(D"28D4).E/_?__28L<)$F+/DC'Q@````!(BT,(28E$)`A(BP-)
+MB00DZ`````!(B=Y(B<?H`````.D<_?__9F:09F:0051(Q\8`````54B)_5-(
+MBS_H`````/9%:`A)B<1U'$B+=3A(A?9T$TB+'DR)Y^@`````2(7;2(G>=>U(
+MBT5P2(N]B````/^0@````%M(B[V`````2(NUB````%U!7$B#QR#I`````&9F
+MD&9FD&9FD%532(G[2(/L"$B+5SB`IX`#``#^2(72=!]F9F:09F:02(M"&$B%
+MP'0'@*"``P``_DB+$DB%TG7H2(G>OP$```#H`````$B+.\>#\`````$```!(
+M@<<0`0``Z`````!(A<!(B<5T9L<``0```$C'0`@`````2(E%$$C'0!@`````
+M2(E8($B+6SA(A=MT,F9FD$B+0QA(A<!U"NL<9F:09I!(B?A(BW@82(7_=?1(
+MB>Y(B<?H`````$B+&TB%VW71BT4`@^@!A<")10!T!TB#Q`A;7<-(@\0(2(GO
+M6UWIO_K__V9F9I!F9F:09F9FD&9FD$B#[!A(B5PD"$R)9"00B=-)B?1(Q\8`
+M````Z`````"-#-M,B>9(BUPD"$R+9"002(G'NB````!(@\08Z0````!(@^Q8
+M@_\'2(EL)#A,B60D0$B)]4R);"1(2(E<)#!!B?Q,B70D4$F)U7=508G^0O\D
+M]0````"+N]````"%_W5`2(M#",>#T`````$```!(C;.X````2(UY6$B+0%A(
+MB9O`````2,>#R`````````!(B8.X````Z`````!F9I!FD$B+7"0P2(ML)#A,
+MBV0D0$R+;"1(3(MT)%!(@\18PTB+7B"_`P```$C'1B``````Z`````!(B5T@
+MZ\9(B??H`````$B+6!!)B<1(A=MU"NL22(L;2(7;=`I(.6L09F9FD'7N2(U[
+M2.@`````2(7`9I!TCDF-?"1(2(E8&$2):"!(QP``````2(E`"$B)QDC'0!``
+M````Z`````#I8?___TB)]^@`````2(G!2(M`&$B-41A(.=!U%>E$____9F9F
+MD$B+`$@YT`^$-/___X"X@/S__P%(C9AP_/__=>1,.:CX_/__==M!@_P'#X<1
+M____D$+_)/4`````2(N#@````$B)YDR)[TB+0`C_4'@/MD0D$HA#9@^V5"0.
+M#[9#:H/B`0'2@^#]"="(0VKIT?[__TB+0R"`HX`#``#OBW!`A?8/A;O^__](
+MB<9(C7E8QT!``0```$B#QBCH`````.F?_O__@(N``P``$.F3_O__2(M#"$B)
+MW_]0,.F$_O__9F9FD$B#[!A(B?A(B5PD"$R)9"002(G&2(M?&$2+9R!(C7M(
+MZ`````!(B=E$B>9(B=],BV0D$$B+7"0(2,?"`````$B#Q!CI`````&9F9I!F
+M9F:02('L&`(``(`]``````!(B9PD"`(``$B)K"00`@``2(G[=1U(BYPD"`(`
+M`$B+K"00`@``2('$&`(``,-F9I!FD`^V1VA!N`$```!(B>&Z`0```+X)````
+M@\@#@^#[B$=HZ`````"%P'5(@3PD>6-G;'1<]D-H`72K2(MK.$B%[9!T(DB+
+M.TC'Q@````#H`````$B)[DB)Q^@`````2,=#.`````!(BT-02(E#*.ER____
+M@*.``P``_DB)WK\!````Z`````"`2V@!Z57___^^``(``$B)Y^@`````A,!U
+MDP^V3"0$#[:#@`,``(G*@^#]P.H$@^(""=#VP1"(@X`#``!T#`^V1"0%@$MH
+M@(A#9_9$)`<!=!</ME-IB<C`Z`*#X`*#R@&#XOT)PHA3:?9$)`<"=!4/ME-I
+MC00)@^`(@\H$@^+W"<*(4VGV1"0'"'05#[9#:<'A!(/A((/($(/@WPG(B$-I
+M]D0D!P0/A`+___\/ME-I#[9$)`2#RD"#X`'!X`>#XG\)PHA3:>GC_O__D%5(
+MC4\X4TB)^TB![`@"```/MD$P@^`#+`$/A"`"``"_[____T`B>VA(B>5(B>!`
+MB'MH2(V4)``"``#&``!(@\`!2#G0=>SV03`"#X7O`0``2(M#*+[W____QP0D
+M7W=A4B'^0(AS:$B)1"0$@'DP`'D-#[9#9X!,)`P0B$0D#?9!,0%T'0^V4VD/
+MMD0D#(!,)`\!P>("@^#W@^(("="(1"0,]D$Q!'0<#[93:0^V1"0,@$PD#P+0
+MZH/@^X/B!`G0B$0D#/9!,1!T'0^V4VD/MD0D#(!,)`\(P.H$@^#]@^(""="(
+M1"0,]D$Q0'0:#[9$)`P/ME-I@$PD#P3`Z@>#X/X)T(A$)`Q(@7M`__\?`'<+
+MOO/___\A_D"(<VCV03`@#X0D`0``2(M+.$B%R70\,?9(@WD8`'0K2&/&2(M1
+M"(/&`4B-!$!(C43%`$B)4!!(BU$02(E0&$B+41A(BU)`2(E0($B+"4B%R77&
+M#[9#:KX``@``2(GGQH7_`0```8/@`8B%_@$``.@`````]]A%,<!(B>&(A0`!
+M``!(BW-0N@$```!(B=](@>X```(`2('F``#^_^@`````2(MS.$B%]G1$,?](
+MBU882(72=#%(BT-03(M"0$ACSTB-#$F#QP%*C10`2"T```(`2"4``/[_2('J
+M``@``$@IPDB)5,T@2(LV2(7V=;Z^``(``$B)Y\:%``$```#H`````/?813'`
+M2(GAB(4``0``2(MS4+H!````2(G?2('N``@``.@`````2('$"`(``%M=PT#`
+M[@*#Y@%`B'0D#NG+_O__9F:09F:04TB)^TB+/TC'Q@````#H`````$B)Q^@`
+M````2(G",<!(A=)T*,8$$`!(@\`!2(/X('7R2(M#*$B)0A!(BT,H2(E3.$B)
+M0TA(B4-`6\-(B=];Z0````!F9F:09F:09F:02('L2`,``(`]``````)(B:PD
+M(`,``$R)I"0H`P``2(G]2(F<)!@#``!,B:PD,`,``$R-9SA,B;0D.`,``$R)
+MO"1``P``#X2K`0``2(MW4$R-?"0@0;@!````N@$```!,B?E(@>X`"```Z```
+M``"%P$&)Q0^$'0,``$B+=5!!N`$```!,B?FZ`0```$B)[TB![@```@!(@>8`
+M`/[_Z`````"%P$&)Q@^$+P,``$&#_?\/E,!!@_[_#X3%!0``187V#Y5$)!=T
+M=$6%[75O2(MU4$&X`0```$R)^;H!````2(GO2('N``@``.@`````A<!!B<5T
+M1X"E@`,``/Y(B>Z_`0```.@`````@$UH`>F?`0``O@`"``!,B?_H`````(3`
+M#X7M`@``08"__P$```!U!D&]_O___\9$)!<`08$_7W=A4@^$,@,``$B+=5!(
+M@>X```(`2(GP2,'H($B%P`^%Q`(``(!-:`$/M@4`````/`(/A(4````L`0^$
+M8@4``/:%@`,```%T>("E@`,``/M)C9<``@``3(GXQ@``2(/``4@YT'7T,?9!
+MN`$```!,B?FZ`0```$B)[^@`````@'PD($4/A,X$``"`O"0>`@``574N@+PD
+M'P(``*IU)#'`1HN$.,H!``!%A<!U$4B#P!!(@_A`=>GK"4R-?"0@@$UH`O9%
+M:`)T#0^V16B#R`&#X/N(16A!]D0D,`%T-$B+73A(A=MT(TB+?0!(Q\8`````
+MZ`````!(B=Y(B<?H`````$C'13@`````2(M%4$B)12A!@'PD,``/B!8!``!!
+M]D0D,0$/A=\```!!]D0D,00/A:<```!!]D0D,1!U;D'V1"0Q0'0NQD0D(`4/
+MMD5I3(G^QD0D*0#`Z`>(1"0H2(M%<$B+O8@```#_D,````!F9I!FD$B+G"08
+M`P``2(NL)"`#``!,BZ0D*`,``$R+K"0P`P``3(NT)#@#``!,B[PD0`,``$B!
+MQ$@#``##QD0D(`0/MD5I3(G^QD0D*0#`Z`6#X`&(1"0H2(M%<$B+O8@```#_
+MD,````#I8?___\9$)"`##[9%:4R)_L#H`X/@`8A$)"A(BT5P2(N]B````/^0
+MP````.DM____QD0D(`(/MD5I3(G^T.B#X`&(1"0H2(M%<$B+O8@```#_D,``
+M``#I]O[__\9$)"``#[9%9TR)_HA$)"A(BT5P2(N]B````/^0P````.G$_O__
+M#[:<)!\"``"^``(``$R)_^@`````BW0D(`^VT$C'QP`````QP(G9Z`````"!
+M?"0@7W=A4@^$)0,``$&]_O___^F>_/__00^VG_\!``"^``(``$R)_^@`````
+M08LW#[;02,?'`````#'`B=GH`````$&!/U]W85(/A/[\__]%A>T/A:'\__]!
+MO?_____IEOS__X'F``#^_T&X`0```$R)^;H!````2(GOZ`````"%P`^%J?S_
+M_T&!/U]W85(/A0O]__^^``(``$R)_^@`````A,`/A"D%``!!@3]?=V%2#X7I
+M_/__O@`"``!,B?_H`````(3`#X74_/__08!_#@`/MD5H3(GF2,?'``````^5
+MPH/@^\'B`@G0B$5H#[9%:D&`O_X!````#Y7"@^#^"=`/MM*(16HQP.@`````
+M2(M%4$B)[T@M```"`$@E``#^_TB)12CHL_K__T'V1PP0=`R`36B`00^V1PV(
+M16=!]D</`70:#[95:4$/MD<,@\H!P.@"@^`"@^+]"<*(56E!]D</`G09#[95
+M:4$/MD<,@\H$`<"#X`B#XO<)PHA5:4'V1P\(=!H/ME5I00^V1PR#RA#!X`2#
+MX""#XM\)PHA5:4'V1P\$=!H/ME5I00^V1PR#RD"#X`'!X`>#XG\)PHA5:4C'
+M1"08`````#';2H-\.Q@`#X5U`0``2(/#&$B#^V!UZH!\)!<`#X19`@``,<E*
+M@WPY&`!T)TJ+5#D@2(M%4$B!P@`(``!(*<)(+0```@!()0``_O](`<)*B50Y
+M($B#P1A(@_E@=<>^``(``$R)_T'&AP`!````Z`````#WV$4QP$R)^4&(AP`!
+M``!(BW50N@$```!(B>\QVTB![@```@!(@>8``/[_Z`````!(BW500;@!````
+M3(GYN@$```!(B>](@>[_!P``2`'>Z`````"%P`^$'P$``$B#PP%(@_L$=<I(
+M@WPD&``/A,,"``"`36A`2(GOZ`````#IS/O__X3`#X0S^O__9F:09F:0Z5_Z
+M__^`?"0A4F9FD&9FD`^%(?O__T&X`0```$R)^;H!````O@$```!(B>_H````
+M`(!\)"!0#X7[^O__@'PD(4T/A?#Z___I'_O__V9F9I"`/0``````#X61^O__
+M9F:0Z0;[__^^``(``$R)_^@`````A,`/A&_Y___IP?S__TB+?0"^!````.@`
+M````2(7`2(E$)!@/A(7[__]*BU0[&$J+=#L02(GOZ$/M__](A<!(B<$/A$@#
+M``!(BU0D&$6%]DB):CAU?$J+1#L@2(E"0$B+5"082(E*2$B+01!(B5$82(E"
+M*.D@_O__2(M%4$B)[T4QP$R)^;H!````2"T```(`2"4``/[_2(UT`P'H````
+M`$B+=5!(Q\<`````2(V&``#^_TB-M!X!^/__2"4``/[_2(U4`P$QP.@`````
+MZ8C^__]%A>UUB$J+5#L@2(M%4$B!P@`(``!(*<)(+0```@!()0``_O](`<)(
+MBT0D&$B)4$#I6/___T6%[0^$5/[__T&`O_\!````#X2W````,<E*@WPY&`!T
+M)TB+15!(B<)*`U0Y($@M```"`$@E``#^_TB!Z@`(``!(*<)*B50Y($B#P1A(
+M@_E@=<>^``(``$R)_T'&AP`!````Z`````#WV$4QP$R)^4&(AP`!``!(BW50
+MN@$```!(B>\QVTB![@`(``#H`````$B+15!!N`$```!,B?FZ`0```$B)[T@M
+M```"`$@E``#^_TB-=`,!Z`````"%P'1^2(/#`4B#^P1UQ^F/_?__2,?'````
+M`#'`Z`````!,B?^^``(``$'&A_\!```!0<:'``$```#H`````/?813'`3(GY
+M08B'``$``$B+=5"Z`0```$B)[TB![@```@!(@>8``/[_Z`````#IZ_[__T'V
+M1"0P!`^$)_C__^DL_?__2(MU4$B)[T4QP$R)^;H!````2('N_P<``$@!WN@`
+M````2(M%4$C'QP````!(C908`?C__T@M```"`$@E``#^_TB-=`,!,<#H````
+M`.DQ____2(V<)"`"``!)C7<0NO````!(B=](@\,(Z`````!(C80D&`,``$B)
+M1"0(ZPM(@\,82#M<)`AT8TB#.P!T[TB+<PA!N`$```!,B?FZ`0```$B)[X/F
+M_^@`````A<`/A?SV__],B?_H`````$&!/_06>%H/A)@```!(BW,(13'`3(GY
+MN@$```!(B>_H`````(7`=)KIQ_;__V9FD$B+=5!!N`$```!,B?FZ`0```$B)
+M[TB![@```@"!Y@``_O_H`````(7`#X65]O__2(MU4$4QP$R)^;H!````2(GO
+M2('N```"`$B!Y@``_O_H`````(7`#X5H]O__Z=SY__](BWPD&.@`````9F:0
+M9I#I"_C__[X``@``3(G_Z`````#I5O___V9FD&9FD&9FD$%728GWO@$```!!
+M5D%528G]05154TB#['A(BW\8B50D#.@`````2(G%28M%"$B-="1`3(G__U!X
+M2(N%F`,``$B+E9`#``!(B4((2(D02(M%`$B+6!A(@\`82#G##X2?````3(UT
+M)!#K&V9F9I!F9I!(BT4`2(L;2(/`&$@YV`^$?0```("[@/S__P%,C:-P_/__
+M==Q(B[/P_/__28M%"$@[1@@/A#<!``!,B>_H`````(/X`'Q+=;A)BT4(28N\
+M)(@```!,B?;_4'@/ME0D3@^V1"0>T.K0Z(/B`8/@`3G"?XY\'0^V1"0@.$0D
+M4'>!D'(/#[9$)%$Z1"0A#X=O____2(M3"$B-A9`#``!(B9V0`P``QT4T`0``
+M`$B-O9````"^*````$B)0PA(B0*`C8`#```!28M%"$R)O8@```!,B:V`````
+M2(F5F`,``$B)17"+1"0,B45X2(M4)$!(B550BT0D2$B)52B)16`/MD0D4HA%
+M9@^W1"189HE%9`^V5"1.#[9%:H/B`0'2@^#]"="(16KH`````$B+17!(B[V(
+M````2(UT)$#_4'CV1"1.`4B+1"1@=0GV@``!```$=0A(B>_H`````$B#Q'A(
+MB>A;74%<05U!7D%?PV9FD&9FD$B+@``!``!(A<`/A+G^__](BW8028M]$/_0
+MZ;+^__^04X!_$`%(B?MT!UNX_____\.`/0`````"=/!(BT=02"T```(`2"4`
+M`/[_2(E'*.BM\O__@&-H],=#,/____](B=_H`````%LQP,-F9I!F9I!(@^P8
+MA=)(B6PD"$R)9"002(G]2(D<)$F)]'AHZ`````!(A<!(B<-T3@^V0&A(BVT8
+MJ`)U;8`]``````!T&J@!=6KV0VA$=02`2V@D1(N-V`$``$6%R71>2(G>2(ML
+M)`A(BQPD3(MD)!"_`@```$B#Q!CI`````$B+10A,B>?_D(````!(C7T@3(GF
+M2(L<)$B+;"0(3(MD)!!(@\08Z0````!(B=_H`````.NL2(G?Z`````#KC$B-
+MM<`!``!(C7U(QX78`0```0```$C'A<`!````````2(FMR`$``$C'A=`!````
+M````Z`````#I9O___V9F9I!F9F:09F:09F:0055!5$F)_%532(/L"$B+;SA(
+MBU](2(M5.$B%T@^$-@$``$B)T#'V2#G8=`Q(BTL(2#E("$@/1/!(BP!(A<!U
+MYTB%]@^$A@```$B+?A!(BTL02#G/<@KK-$B+$DB%TG0Y2(-Z&`!U\4B)R$@#
+M0PA(.4((=>1(BT(02`-#$$@#?@A(*T802(EZ"$B)0A!(B=Y(B>_H`````.L8
+M2(M&"$@#1A!(*7L02,=#&`````!(B4,(@$UH$$R)Y^@`````2(/$"$B)[UM=
+M05Q!7>D`````13'MZPA(BQ)(A=)T+DB#>A@`=?%(BWL(2(M*"$B)^$@#0Q!(
+M.<%T64@#2A!(.<](#T3R2(L22(72==)(A?9(QT,8`````'082(M&"$B)[TB)
+M0PA(BT802`%#$.@`````387M#X1Y____28M%$$@!0Q!,B>Y(B>_H`````.EA
+M____28G5Z7S___](QT,8`````.E,____9F9FD&9F9I!F9I!!54F)_3'_051)
+MB?154TB#[`A(A=(/A)@```!(BWI(2(7_#X2+````28M-.$B%R71R,>U%,<#K
+M#4@YPG012(L)2(7)=$5(BT$82(7`=>I(BW$023GT=PY(A>UT!D@[=1!S`TB)
+MS4B%P'732(7_9F:0=,M(BT<(2`-'$$@Y00A,#T3!2(L)2(7)=;M-A<!T#TF+
+M0!!(`T<023G$2`]&[TB%[74<,=M(@\0(2(G86UU!7$%=PTTY94`/@VO____K
+MY$F+?0"^!````.@`````2(7`2(G#=-!,B6@X28M%4#'V28M5.$@M```"`$@E
+M``#^_TB%TDB->`%T($B+0AA(A<!T#TB+2$"X`0```"GYT^`)QDB+$DB%TG7@
+M,<FX`0```-/@A<9T'X/!`8/Y!'7M2,=#0`````!(B=\QV^@`````Z6'___](
+M8\%(`?A(A<!(B4-`=.),B6,H2(MU"$R)XDR)[^B:X___2(7`=,I(B5@82(E#
+M2$R)[T&`36@0Z`````#I(/___V9F9I!F9F:09F:04TB)^TB+0SA(A<!U"^M;
+MD$B+`$B%P'122(MX&$B%_Y!T[DB+=QA(A?9T.(!^1`!T,C')ZP\/MD9$C5$!
+M2(/!`3G0?A](.7S.8'7J#[9&1(U1`4C'1,Y@`````$B#P0$YT'_AZ`````#K
+MFDB)WV9FD.@`````2(M#<$B+NX@```#_D,@```!(B=];Z0````"054B)_5-(
+M@^P(2(M?.(!G:+](A=MT0DB+>QA(A?]T!>@`````2(L;2(7;=>I(BT4XZP-(
+MBP!(A<!T'DB+>!A(A?]T[TB#?Q@`=>CH`````$B+13A(A<!UXDB#Q`A(B>];
+M7>D`````9F9FD&9FD&9FD$%62(GX2(G&055!5%533(MO($F-O1`!``!-C648
+MZ`````!)BUT80<>%V`$```````!,.>-U"NLT2(L;3#GC="R`NX#\__\!2(V[
+M</S__W7H]H/8_/__0'3?]D/P`739Z`````!(BQM,.>-UU$F+72A)C6TH2#GK
+M=!AF9F:09F:02(U[Z.@`````2(L;2#GK=>])BVT83#GE#X3@````9I"`O8#\
+M__\$2(V]</S__W8.2(.]B/S__P`/A'H!``!(BVT`3#GE==E)BUT83#GC#X2J
+M````13'VZP]F9F:09F:02(L;2#GK=%F`NX#\__\!2(V[</S__W7H]H/8_/__
+M('3?2(N#J/S__X"CV/S__]M(A<!U&.GL````9F9FD&9FD$B+`$B%P`^$V0``
+M`$B#>!@`=.U(BQM!O@$```!(.>MUITF+71A,.>-U#NLR9F9FD$B+&TPYXW0F
+M1(N3H/S__TB-NW#\__]%A=)X'/9#\`%UW^@`````2(L;3#GC==I;74%<05U!
+M7L/V0_`!=,,/MH.`_/__/`0/AGX```!(@[N(_/__`'6J]H/0_O__0'6A2(N#
+M\/[__TB%P'0&2#EX"'6/#[:#M/S__X7`?B^#Z`$QR4B#P`%(BU3/8$B%TG03
+M@'H0!'8-]H)@`@``0`^%7O___TB#P0%(.<%UVN@`````Z4O___]%A/8/A=+^
+M__]FD.@`````Z<;^__\L`69F9I`/A2K____V@]C\__\"9F:0#X0:____Z\/H
+M`````&9FD.EY_O__9F9FD&9F9I!F9I!!5$F)_$B-OQ`!``!54^@`````2(7`
+M2(G%=&I)BUPD&$R)8"!)@\08QP`!````2,=`"`````!(B4402,=`&`````!,
+M.>-U$>LO9F9FD&9FD$B+&TPYXW0@@+N`_/__`4B-NW#\__]UZ$B)[N@`````
+M2(L;3#GC=>"+10"#Z`&%P(E%`'0%6UU!7,-;2(GO74%<Z1K]__]F9F:09F:0
+M9F:02(/L&$B);"0(2(D<)$B)_4R)9"002(M?(,=#0`````#VAX`#```8#X6C
+M````1(NGT````$6%Y`^%DP````^V0TBH`0^%AP```*@"3(UC$'0?3#EC$'4%
+M2#D;=!U(B>^0Z,O;___V0T@!=65F9I!FD$B+2Q!,.>%U:@^V168Y0R!R%NM,
+M2(G62(GOZ!'8__\/MD5F.4,@<SA(B>_HT-?__TB%P$B)PG0H#[>`L````&8E
+M_S!F/00@=<M(.1MU8?9%:@)TP(!+2`+KNF9FD&9FD$B+'"1(BVPD"$R+9"00
+M2(/$&,-$BUL@187;=>1(BQ%(BT$(2(GO2(MQ&$B)0@A(B1!(B4D(2(D)2(L<
+M)$B+;"0(3(MD)!!(@\08Z8'7__](B=?&@K(````!Z`````!(B>_H.M?__TB)
+MPNE&____9I!(@^P82(D<)$B);"0(2(G[3(ED)!!,BV=0Z/+6__^`N[`````$
+M2(G"28ML)"`/A(T```!(BX/(````QT5$`````$B)*L="(`````!(B5H82,>#
+MR`````````!(B4(02(M%"$B)50A(B1!(B4((00^V1"1F.44@<P>+14"%P'03
+M2(L<)$B+;"0(3(MD)!!(@\08PTF+/"1(C74HQT5``0```$B+'"1(BVPD"$R+
+M9"002(/$&$B#QUCI`````&9F9I#V@[$````P=`KV14@"#X1@____QH.R````
+M`4B)WTB+;"0(2(L<)$R+9"002(/$&.D`````9F9FD&9F9I!F9F:02(/L*$B)
+M;"0(3(ED)!!(B?U,B6PD&$R)="0@2(D<).CLU?__3(MU4$F)Q4V+9B!!@VPD
+M(`$/MH6R````/`UT4#P1#X3(````/`MT9#P09I`/A.````!)BT402(GO2(F%
+MR````.@`````08M$)$"%P'1H2(L<)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$
+M*,.0@+VP`````'6]@+VS``````^%NP```,:%LP````%F9I!)C40D$,:%L@``
+M``!)BU0D&$V);"0828E%`$&+1"1`28E5"$R)*H7`=9A)BSY)C70D*$''1"1`
+M`0```$B+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#QUA(@\0HZ0````!,B??H
+MV-C__X7`=0L/MH6S````/`%V0P^VA;(````\$`^%(/___X"]L`````,/A!/_
+M__])BUX@3(GV28EN(+\#````Z`````!)B5X@Z?7^___&A;(````0Z\R#P`&(
+MA;,```#I./___Y"0D)"0D)"02(LU`````$B%]G1#2(M6&$B-3AA(.<IT+DB-
+M@G#\__\YN.@#``!U%^LI9F:09F:02(V"</S__SFXZ`,``'022(L22#G*=>E(
+MBS9(A?9UO3'`\\/SPV9F9I!F9F:09F:0@'\$`'4,,<"!/WL!```/E\##,<"!
+M/WL!```/E\##9I`/M@</M@XXR'0:ZRQF9F:0#[97`0^V1@$XPG412(/'`4B#
+MQ@&$P'7H,=*)T,,/OL`/OM(IPHG0PP^^T`^^P2G"Z^AF9F:09F9FD&9FD&9F
+MD$%728GW059!B?Y!54%455-(@>R8````3(LM`````$V%[71#3(UD)!`Q[4F+
+M71!(A=MT*DR)9"0(2(M#"$B+>Q!,B>;_4#B`?"0C`'0(1#GU="N#Q0%(BQM(
+MA=MUVTV+;0!-A>UUQ#';2('$F````$B)V%M=05Q!74%>05_#387_=.8/ME0D
+M)T&+!SG0?-I(BQM(A=MTTBG02(M[$$B+="0(08D'2(M#"/]0.(!\)",`=-#K
+MLF9F9I!F9F:09F9FD$%7059)B?Y!54%428G454B)S5-(@>RH````2(L%````
+M`,<"`````$B)="0(QP$`````2(7`2(E$)!`/A)X```!!O?_____'1"0<````
+M`$B+1"002(M8$$B%VP^$D````$B%[4$/E<?K'V9F9I!F9I!(BQL/MD0D-T$!
+M!"2+1"0<`44`2(7;=&A(BT,(2(M[$$B-="0@_U`X2(M#"$B+@`@!``!(A<!T
+M#T6$_W0*2(M[$/_0B40D'(!\)#,`=!-!QP0D`````$&#Q0''10``````3#GS
+M=9I(BT0D"$2)*$B!Q*@```!;74%<05U!7D%?PTB+1"002(L`2(7`2(E$)!`/
+MA4C____KUF9F9I!F9F:0055!5%4Q[5-(@>R(````3(LE`````$V%Y'0Q28M<
+M)!!(A=MT'DB+0PA(BWL02(GF_U`X@'PD$P%(BQN#W?](A=MUXDV+)"1-A>1U
+MSTB!Q(@```")Z%M=05Q!7<-F9F:005=!5D%505152(G54TB![-@```")="0,
+M2(UT)`SHKOW__TF)QKC_____387V#X3Y````38MF&#'`9F9FD&9FD,8$*`!(
+M@\`!2(/X1'7R28M&"$B-="0028M^$/]0.(!\)"(0#[94)"*X#P```(MT)`P/
+M0L)(C90DP````(A$)"))BT8(28M^$/^0N````(7`#X2H````28M<)!A-C6PD
+M&$PYZP^$@0```$4Q_^L*9I!(BQM,.>MT<H"[@/S__P%,C:-P_/__=>A,.[/P
+M_/__==](BX/@_/__2(N[^/S__TB-M"20````_U!X]H0DG@````)UO`^VA"2@
+M````.T0D#'6N#[:$)*$````Z1"0B<Z`/MM!!BX0DZ`,``$&#QP&)1)4(1#A\
+M)")UAC'`2('$V````%M=05Q!74%>05_#BX0DQ````(E%!(N$),````")10#I
+M/____V9FD&9FD&9FD(U'^S'2@_@'=PZ)P/\DQ0````"Z`0```(G0P[H(````
+MB=##N@(```")T,.Z!P```(G0P[H#````B=##N@0```")T,.Z!0```(G0P[H&
+M````B=##9F9FD&9FD&9FD&9FD`^VCX`#``!$#[9&#(G*@_(!@^(!B="#R"!!
+M]L`@#T3"B<*#R@+VP00/1<*)PH/*!(/A`@^V3@X/1<*)PH/*$$&#X!`/1<*)
+MPH/*0/;!`0]%PHG"@,J`@^$"#T7"#[97:(G!@<D```"`]L($#T7!B<&!R0``
+M`@#VP@(/1<&)P8')```!`(/B`0]%P8G"@<H```0`]D=J`0]%PL-F9I!F9I!(
+MBX=H`@``2(M/*$0/MD=$2,'H"TC!Z0M(:=#H`P``2(G0,=)(]_%$B<)(B<%(
+MBT<(#[9`"BG"B=!(F$@/K\A%A<!(C02)1(T4`'Y]08U`_S'V3(U(`4B+3/=@
+M2(7)=&#V@8`#```!=%>`>1`$=E'V@6`"``!P=$A(BU$(#[9!1`^V4@HIT(T$
+M@$2-!`!(BX%H`@``2(M)*$C!Z`M(P>D+:=#H`P``B=`QTO?Q1`^OP$6%TG0%
+M13G"=@9%B<)F9I!(@\8!3#G.=8U!@?H0)P``N!`G``!!#T;"PV9FD&9FD$B+
+MCX`"```/MH&J````/`)U<DB+01"_$"<``$B+<"A(BT$(3(M`*$B)\DPIPDC!
+MZ@M(A=)T-H!Y*`!U-$B+@:````!,*<!(P>@+2&G`Z`,``$B)T3'22/?Q2(T$
+M@`'`OQ`G```]$"<```]&^(GXPY!(*[&@````2,'N"TAIQN@#``#KS3P#=%>`
+M>2@`="-(BT$02(M0*$B)T$@K@:````!(P>H+2,'H"TAIP.@#``#KH$B+@:``
+M``!(P>@+2&G0Z`,``$B+01!(BT@H2(G0,=)(P>D+2/?Q2(T$@`'`ZX"`>2@`
+M=`9(BT$(ZZ=(BX&@````2,'H"TAIT.@#``!(BT$(Z\1F9F:09F:09F:09F:0
+M3(M'&$V%P'0\00^V0$2$P`^V\'0C,<E).7A@=!Y,B<(QR>L-2(M":$B#P@A(
+M.?AT"H/!`3GQ=>PQP,-!BT`X@\`!`<C#BT<XPV9F9I!F9I`/MD=$A<!^8X/H
+M`44QR4R-4`%*BTS/8$B%R71&]H&``P```70]@'D0!'9$#[9!1(7`?B^#Z`$Q
+MTDR-0`%F9F:02(M$T6!(A<!T#_:`@`,```%T!D@Y<#AT%$B#P@%,.<)UWDF#
+MP0%-.=%UIS'`\\-(.7$X=>U(B<C#9F9FD&9FD$%708G7059)B?Y!54F)S4%4
+M55-(@^P(2(7_0(AT)`-$B$0D`D2(3"0!#X0)`0``@'\0!P^4P$"`_@</E,*$
+MP`^%VP```(32#X7K````187_#X0L`@``3(GMQT0D!`````!)Q\7_____13'D
+M9F:09I"+?0#H`````$B%P$B)PP^$AP```$F+!D@Y`P^%>P```(![$`%U=4B)
+MWDR)]^C?_O__,?](A<!(B<9T!$B+>$A(BTLX2(7)#X39````2(G(,=)(@W@8
+M`4B+`$B#VO](A<!U[TB#^@,/AKD````QTD4Q[8-$)`0!20'42(/%!$0Y?"0$
+M#X5X____#[9,)`*#X0^`?"0#!P^&+0$``$4QY$B#Q`A,B>!;74%<05U!7D%?
+MPP^V1T0\`0^$(?___X32=`B$P`^%00$``$6%_V9FD&:0#X0\`0``3(GM,=M)
+MQ\7_____13'DZRF`>!`!=:Y(BT!`2(7`=*5)`<1).<5,#T?H@\,!2(/%!$0Y
+M^P^$>/___XM]`.@`````2(7`=<IF9I#I=O___S'22(7V=`1(BU8H2(7)=&E%
+M,<#K(69FD&9FD$B+01A(.<9T"DB%_W0=2(7`=%=(BPE(A<ET*DB%]F:0==Y(
+MA?](BT$8=>-(A<!FD'7A2(M!$$@YT$@/1]!(BPE(A<EUUDB%_W04387`=`])
+MBT`02`-'$$@YPD@/0M!).=5,#T?JZ<?^__](BT<(2`-'$$@Y00AUNDB+01!)
+MB<A(.=!(#T?0Z[4/MD0D`_\DQ0````!!@_\!#X:]_O__08/_`DV)[`^&L_[_
+M_P^VR;C_____0='OT^!(F$DAQ$2)^$P/K^#IE?[__T6%_P^%NP```$G'Q?__
+M__]%,>3I9_[__T&#_P,/AG#^__\/MLFX_____TV)[-/@2)A)(<1!C4?^3`^O
+MX.E4_O__08/_`@^&1_[__P^VR;C_____38GLT^!(F$DAQ$&-1_],#Z_@Z2O^
+M__^`?"0!`0^&_0```(!\)`$"#X9+____1`^V3"0!,=)$B?A!]_&%T@^%_/W_
+M_X/X`0^.\_W__TQCX$&-0?\/MLE(F$P/K^"X_____]/@2)A)(<5-#Z_EZ=']
+M__](BT=@,>TQTDB%P'4>Z;S]__]!.>\/AN#]__^)ZDF+1-9@2(7`#X2C_?__
+M2(M8.$&+?)4`Z`````!(.<-T$D$/MD9$@\4!.>@/AJW]___KPD$/MD9$#[;8
+M03G?#X)M_?__A,!T9TF+1F`Q[3'22(7`=23I5_W__T$/MD9$@\4!#[;8.>MV
+M1HGJ28M$UF!(A<`/A#C]__](BU@X08M\E0#H`````$@YPW3.Z2#]__\/MLFX
+M_____TV)[-/@2)A)(<1$B?A,#Z_@Z07]__\/ML!-BV8H28MTQEA(BT8X2(M(
+M.$B%R74*ZR5(BPE(A<ET'4B#>1@`=?%(BU9(2(M""$@#0A!(.4$(==],`V$0
+M03G?=ROIN_S__TF+%D@Y$`^%K/S__X!X$`$/A:+\__^#PP%,`V!`1#G[#X25
+M_/__B=A!BWR%`.@`````2(7`=<GI?/S__Y#SPV9F9I!F9F:09F:09F:0BPT`
+M````C5$!B=#!^!_!Z!Q$C00"08/@#T$IP$0[!0````"X_____W192&/!2,?&
+M`````$B-%(!(C1102(L'2(T,E0````!(B025`````$B+1PA(B40Q"$B+1Q!(
+MB40Q$$B+1QA(B40Q&$B+1R!(B40Q((M'*$2)!0````")1#$H,<#SPV9F9I!F
+M9F:09F:02(/L.`^V1Q!)B=`\`70F/`1T/4B-5"0,@_X!2(GG&<"#P!F(1"0(
+M9HE*".@`````2(/$.,.+A^@#``!(C50D#$R)1"0,B40D!.O-9F:09I!(BU<X
+M2(M'2(N2Z`,``$P#0`B)5"0$2(U4)`Q,B40D#.NF9F9FD&9F9I!F9I!F9I!5
+M4TB#[!C&!"0&2(M?$$B%VW0@2(M#$#'_2(GF2(E$)`A(BT,(_Y#`````2(L;
+M2(7;=>!(@\086UW#9F:09F:02(M'4$0/MY>8````28GP08G32(NP@`(``$R+
+M"$2)T<'A"8!^*`!T#?:'L0````0/A8L````/MY::````P>()A<E)B[%0`@0`
+M08NY6`($`'1AB=`QTO?WB<!(P>`$2(T\!DF-<!#K.HG02`,'2(E&^$&+@5@"
+M!`!)B?#'1O0`````*=")1O`YR(G(#T9&\"G!B4;P2(UV$(7)=!=(@\<0,=)%
+MA=MUP8G02`-'"$B)1OCKOK@!````0<=`]`$```###[>6F`````^WAIH````I
+MPD0ITL'B">ED____9F:09I!!5$F)_%5(B?53@'Y$`'1J,=OK(DB+5DA)BT0D
+M2$B+2`A(.4H(=#D/MD5$C5,!2(/#`3G0?D1(BW3=8$B%]G3G@'X0!';.3(GG
+MZ++___^$P'356UU!7+@!````PV9F9I!)BT0D.$@Y1CATYP^V142-4P%(@\,!
+M.=!_O%M=05PQP,-F9F:09F9FD&9F9I!F9I!!54F)]4%428G\55.`?T0`=%(Q
+M[>L<3(GN2(G?Z-____]!#[9$)$2-50%(@\4!.=!^,DF+7.Q@2(7;=.6`>Q`$
+M=]1,B>Y(B=_H(____X3`C54!#Y1#4$$/MD0D1$B#Q0$YT'_.6UU!7$%=PV9F
+MD&:0@'\0`70#,<##2(7V=%I(BX:``@``2(7`=$Y,BT`(23GP=$I(BT\X2(7)
+M=#9F9F:02(M1&$B%TG0?2(7V=0=FD.O$2(G"2(M"&$B%P'7T2#GR=`5,.<)U
+MKDB+"4B%R6:0=<ZX`0```,-)B?#KMDR+0!#KL&9F9I!F9I!F9I!F9I"+1QR%
+MP'@&@W\@`W<'QT=0_O____/#9F9FD&9FD&9FD(%_',<```!V"8%_(,<```!W
+M!\='4/[____SPV9FD&:0@7\<QP```'8)BU<@A=)X`O/#QT=0_O___\-F9I!F
+M9I"+3QR%R7@&@W\@`W<'QT=0_O____/#9F9FD&9FD&9FD(-_'`-V!H-_($MW
+M!\='4/[____SPV9F9I!F9F:09F:0@W\<`W8&@W\@5W<'QT=0_O____/#9F9F
+MD&9F9I!F9I"#?QP#=@:#?R!#=P?'1U#^____\\-F9F:09F9FD&9FD(-_'`=V
+M!H-_(`]W!\='4/[____SPV9F9I!F9F:09F:0@W\<!W8&@W\@0W<'QT=0_O__
+M__/#9F9FD&9F9I!F9I"#?QP#=@:#?R`#=P?'1U#^____\\-F9F:09F9FD&9F
+MD(-_'`=V"8%_(/\```!W!\='4/[____SPV9F9I!F9F:0@W\<!W8)@7\@HPP`
+M`'<'QT=0_O____/#9F9FD&9F9I"#?QP'=@F!?R`G#0``=P?'1U#^____\\-F
+M9F:09F9FD(-_'`=V"8%_(*L```!W!\='4/[____SPV9F9I!F9F:0@W\<"W8&
+M@W\@)W<'QT=0_O____/#9F9FD&9F9I!F9I"#?QP#2(M'*(L`=A-(8U<@B<!(
+MC02%!````$@YPG,'QT=0_O____/#9F9FD&9F9I"#?QP#2(M'*(L`=A-(8U<@
+MB<!(C02%!````$@YPG,'QT=0_O____/#9F9FD&9F9I!32(G[2(M'*(-['`.+
+M.'8)@7L@K0```'<)QT-0_O___UO#Z`````!(A<!T[5MF9I##9F9FD&9F9I!F
+M9F:09F:04TB)^TB+1RB#>QP#BSAV"8%[(-<```!W"<=#4/[___];P^@`````
+M2(7`=.U;9F:0PV9F9I!F9F:09F9FD&9FD%-(B?M(BT<H@WL<`XLX=@F!>R#Y
+M````=PG'0U#^____6\/H`````$B%P'3M6V9FD,-F9F:09F9FD&9F9I!F9I!3
+M2(G[2(M'*(-['`A(BTLPBSAV#(-[(`1_%F9FD&9FD,=#4/[___];PV9F9I!F
+M9I`/ME`(BT`$B0&$THA1!'04@3G#`0``=MCH`````$B%P'3.6\,]PP$``&9F
+M9I!F9I!VONOD9F9FD&9F9I!F9F:02(/L$$B);"0(2(D<)$B)_8%_'+,```!V
+M!H-_(`=W%<=%4/[___](BQPD2(ML)`A(@\00PTB+1RB+&(G?@^L!Z`````"#
+M^_UWW4B%P'31@'@0!';+2(.X@`(```!UP6:0Z\1F9F:09F9FD&9FD&9FD$B#
+M[!A(B6PD"$B)'"1(B?U,B60D$(-_'`AV!H-_(`=W'\=%4/[___](BQPD2(ML
+M)`A,BV0D$$B#Q!C#9F:09I!,BV<H08L<)(G?@^L!Z`````"#^_UW$DB%P'0&
+M@'@0!'<7QT50_O___TF-?"0$Z)WK__\L`76JZZ](@[B``@```'7?Z^1F9F:0
+M9F9FD&9FD$B#["A(B6PD"$B)'"1(B?U,B60D$$R);"083(ET)"!(BT\H2&-7
+M'$2+,42)\$B-!(4$````2#G"<F:+=R"%]GA?@#T``````G1613'M187V0;P$
+M````=3'K369FD&9FD(G?Z`````!(BU402#D09I!U4O9`:`%T*$&#Q0%)@\0$
+M13GU=")(BTTH0HL<(8G?Z`````!(A<!UQV9F9I!F9I#'15#^____2(L<)$B+
+M;"0(3(MD)!!,BVPD&$R+="0@2(/$*,/'15#\____Z]IF9I!(@^P@2(D<)$B)
+M;"0(2(G[3(ED)!!,B6PD&(%_'(<```!,BV<H=@F#?R`#=R-F9I#'0U#^____
+M2(L<)$B+;"0(3(MD)!!,BVPD&$B#Q"##D$$/MD0D`3P(=]9%,>V$P'4=Z]2)
+M[^@`````2(M3$$@Y$'4B08/%`44X;"0!=KE!#[;%08MLA&B)[^@`````2(7`
+M==#KF\=#4/S___]F9F:0ZY5F9F:09F9FD&9FD&9FD(-_'`-V!H-_(`-_!\='
+M4/[____SPV9F9I!F9F:09F:02(M'*(M7'+D0````BW`(1(M`#(7V=`=$B<!(
+MC4@02&/"2#G!=PR%]HM'('4,03G`=@?'1U#^____\\-F9I!FD$B#["!(B1PD
+M2(EL)`A(B?M,B60D$$R);"08@7\<KP```$R+9RAV"8-_(`-W(V9FD,=#4/[_
+M__](BQPD2(ML)`A,BV0D$$R+;"082(/$(,.000^V1"0!/!!WUD4Q[83`=1WK
+MU(GOZ`````!(BU,02#D0=2)!@\4!13AL)`%VN4$/ML5!BVR$<(GOZ`````!(
+MA<!UT.N;QT-0_/___V9F9I#KE69F9I!F9F:09F:09F:02(/L($B)'"1(B6PD
+M"$B)^TR)9"003(EL)!B#?QP$2(MO*'X&@W\@`W<FQT-0_O___TB+'"1(BVPD
+M"$R+9"003(ML)!A(@\0@PV9F9I!F9I!(B>_HF.C__RP!=<X/MD4-/$!WQD4Q
+M[83`=2'KQ&9FD$2)Y^@`````2(M3$$@Y$)!U(D&#Q0%$.&T-=J5!#[;%1(MD
+MA7Q$B>?H`````$B%P'7.ZX;'0U#\____9F:09I#I?/___V9F9I!F9F:09F:0
+M2(/L($B)'"1(B6PD"$B)^TR)9"003(EL)!B!?QRS````2(MO*$2+90!V!H-_
+M(`-W'\=#4/[___](BQPD2(ML)`A,BV0D$$R+;"082(/$(,-$B>?H`````$B%
+MP'341(GGZ`````!(BU,02#D0=`G'0U#\____Z\%,C64$00^V1"0!/!!WK$4Q
+M[83`=2'KJF:0B>_H`````$B+4Q!(.1!FD'7,08/%`44X;"0!=HM!#[;%08ML
+MA'")[^@`````2(7`=<[I:O___V9FD&9FD&9FD$B#["!(B1PD2(EL)`A(B?M,
+MB60D$$R);"08@W\<"$B+;RA$BV4`=@:#?R`#=R+'0U#^____2(L<)$B+;"0(
+M3(MD)!!,BVPD&$B#Q"##9F:01(GGZ`````!(A<!TT42)Y^@`````2(M3$$@Y
+M$'0)QT-0_/___^N^3(UE!$R)Y^C=YO__+`%UIT$/MD0D#3Q`=YU%,>V$P'4I
+MZYMF9I!F9I")[^@`````2(M3$$@Y$&:0=;Q!@\4!13AL)`T/AG3___]!#[;%
+M08MLA'R)[^@`````2(7`=<KI4____V9FD&:01(M''$6%P'@&@W\@*W<'QT=0
+M_O____/#9F9FD&9F9I!(@^P02(D<)$B);"0(2(G[@W\<"$B+1RB+*'8T1(M/
+M($6%R7@KB>_H`````$B%P'0?B>_H`````$B+4Q!(.1!T%L=#4/S____K#69F
+MD&9FD,=#4/[___](BQPD2(ML)`A(@\00PV9F9I!F9F:09F:02(/L$$B)'"1(
+MB6PD"$B)^X-_'`A(BT<HBRAV-$2+5R!%A=)^*XGOZ`````!(A<!T'XGOZ```
+M``!(BU,02#D0=!;'0U#\____ZPUF9I!F9I#'0U#^____2(L<)$B+;"0(2(/$
+M$,-F9F:09F9FD&9FD$B#[!!(B1PD2(EL)`A(B?N#?QP(2(M'*(LH=C1$BU\@
+M187;>"N)[^@`````2(7`=!^)[^@`````2(M3$$@Y$'06QT-0_/___^L-9F:0
+M9F:0QT-0_O___TB+'"1(BVPD"$B#Q!##9F9FD&9F9I!F9I!(@^P02(D<)$B)
+M;"0(2(G[@W\<#4B+1RB+*'8LBT<@A<!X)8GOZ`````!(A<!T&8GOZ`````!(
+MBU,02#D0=!#'0U#\____ZP?'0U#^____2(L<)$B+;"0(2(/$$,-F9I!(@^P0
+M2(D<)$B);"0(2(G[@W\<#4B+1RB+*'8LBT<@A<!^)8GOZ`````!(A<!T&8GO
+MZ`````!(BU,02#D0=!#'0U#\____ZP?'0U#^____2(L<)$B+;"0(2(/$$,-F
+M9I!(@^P02(D<)$B);"0(2(G[@W\<#4B+1RB+*'8LBT<@A<!X)8GOZ`````!(
+MA<!T&8GOZ`````!(BU,02#D0=!#'0U#\____ZP?'0U#^____2(L<)$B+;"0(
+M2(/$$,-F9I!(@^P02(D<)$B);"0(2(G[@W\<`TB+1RB+*'95BT<@A<!X3HGO
+MZ`````!(A<!T0HGOZ`````!(BU,02#D0=`G'0U#\____ZS"`>!`$=B-(BY"`
+M`@``2(72=!>`NJL`````=0X/MH!A`@``@^`8/`AT!\=#4/[___](BQPD2(ML
+M)`A(@\00PV9F9I!F9I!F9I!(@^P02(D<)$B);"0(2(G[@W\<`TB+1RB+*'8T
+MBT<@A<!X+8GOZ`````!(A<!T(8GOZ`````!(BU,02#D0=`G'0U#\____ZP^`
+M>!`!=`EFD,=#4/[___](BQPD2(ML)`A(@\00PV9F9I!F9F:09F:02(/L$$B)
+M'"1(B6PD"$B)^X-_'`-(BT<HBRAV-(M'((7`>"V)[^@`````2(7`="&)[^@`
+M````2(M3$$@Y$'0)QT-0_/___^L/@'@0`70)9I#'0U#^____2(L<)$B+;"0(
+M2(/$$,-F9F:09F9FD&9FD$B#[!A(B1PD2(EL)`A(B?M,B60D$(-_'`=(BT<H
+MBRA$BV`$=GN+5R"%TGATB>_H`````$B%P'1H1(GGZ`````!(A<!T6XGOZ```
+M``!$B>=(B<7H`````$B)PDB+10!(.T,0=`G'0U#\____ZSI(.P)U\DB+10B`
+M>`H`="2`>A`!=1Y(@WU8`'072(N%@`(``$B%P'02@+BK`````'0)9I#'0U#^
+M____2(L<)$B+;"0(3(MD)!!(@\08PV9FD&9FD$B#[!!(B1PD2(EL)`A(B?N#
+M?QP'2(M'*(LH=C2+3R"%R7@MB>_H`````$B%P'0AB>_H`````$B+4Q!(.1!T
+M"<=#4/S____K#X!X$`1W"6:0QT-0_O___TB+'"1(BVPD"$B#Q!##9F9FD&9F
+M9I!F9I!(@^P02(D<)$B);"0(2(G[@W\<5TB+1RB+*'8YBW<@A?9X,HGOZ```
+M``!(A<!T)HGOZ`````!(BU,02#D0=`G'0U#\____ZQ2`>!`$=@=(@W@8`'0'
+MQT-0_O___TB+'"1(BVPD"$B#Q!##9F:09F:02(/L$$B)'"1(B6PD"$B)^X-_
+M'$-(BT<HBRAV-HM_((7_>"^%[70RB>_H`````$B%P'0?B>_H`````$B+4Q!(
+M.1!T"<=#4/S____K#8!X$`%T!\=#4/[___](BQPD2(ML)`A(@\00PV9FD&9F
+MD&9FD$B#[!!(B1PD2(EL)`A(B?N#?QP(2(M'*(LH=CA$BT<@187`>"^%[70R
+MB>_H`````$B%P'0?B>_H`````$B+4Q!(.1!T"<=#4/S____K#8!X$`%T!\=#
+M4/[___](BQPD2(ML)`A(@\00PV9F9I!F9I!$BU<<1872>`M$BT\@187)>`+S
+MP\='4/[____#9F9FD$2+7QQ%A=MX!H-_("MW!\='4/[____SPV9F9I!F9F:0
+MBT<<A<!X!H-_(']W!\='4/[____SPV9F9I!F9I!F9I!(@^P02(D<)$B);"0(
+M2(G[2(MO*(M/'+\0````#[95"P^V=0S!X@E`@/X"=#A(8\%(.<=W&T"`[@&+
+M2R"_$````'142&/!2#G'=B5F9I!FD,=#4/[___](BQPD2(ML)`A(@\00PXG0
+M2(UX$.O`9F:0BWT`Z`````!(A<!TTXM]`.@`````2(M3$$@Y$'09QT-0_/__
+M_^O`B=!(C7@02&/!2#G'=ZOKR8!X$`%UHV9FD.NE9F9FD&9F9I!F9I!F9I!(
+M@^P02(D<)$B);"0(2(G[2(MO*(M/'+\4````#[=5$`^V=1+!X@E`@/X"=#A(
+M8\%(.<=W&T"`[@&+2R"_%````'142&/!2#G'=B5F9I!FD,=#4/[___](BQPD
+M2(ML)`A(@\00PXG02(UX%.O`9F:0BWT`Z`````!(A<!TTXM]`.@`````2(M3
+M$$@Y$'09QT-0_/___^O`B=!(C7@42&/!2#G'=ZOKR8!X$`%UHV9FD.NE9F9F
+MD&9F9I!F9I!F9I!(@^P02(D<)$B);"0(2(G[@W\<`TB+1RB+*'8LBT<@A<!X
+M)8GOZ`````!(A<!T&8GOZ`````!(BU,02#D0=!#'0U#\____ZP?'0U#^____
+M2(L<)$B+;"0(2(/$$,-F9I!(@^PH2(EL)`A(B1PD2(G]3(ED)!!,B6PD&$R)
+M="0@2(M/*$AC5QQ$#[8Q1(GP2(T$A00```!(.<)R2(-_(`-V0D4Q[46%]D&\
+M!````'4DD.LXB=_H`````$B+51!(.1!U14&#Q0%)@\0$13GU=!M(BTTH0HL<
+M(8G?Z`````!(A<!US\=%4/[___](BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(
+M@\0HP\=%4/S____KVDB#["A(B6PD"$B)'"1(B?U,B60D$$R);"083(ET)"!(
+MBT\H2&-7'$0/MC%$B?!(C02%!````$@YPG)(@W\@`W9"13'M187V0;P$````
+M=220ZSB)W^@`````2(M5$$@Y$'5%08/%`4F#Q`1%.?5T&TB+32A"BQPAB=_H
+M`````$B%P'7/QT50_O___TB+'"1(BVPD"$R+9"003(ML)!A,BW0D($B#Q"C#
+MQT50_/___^O:2(/L$$B)'"1(B6PD"$B)^X-_'`=(BT<HBRAW%<=#4/[___](
+MBQPD2(ML)`A(@\00PXGOZ`````!(A<!TWXGOZ`````!(BU,02#D0=-;'0U#\
+M____Z\UF9F:09F:09F:0@W\<`TB+1RB+`'832&-7((G`2(T$A00```!(.<)S
+M!\='4/[____SPV9F9I!F9F:04X-_'`)(B?M(BT<H#[8`=C^+5R"%TG@X,?8/
+MMOCH'MS__TB%P$B)PG0F2(M`"$B#N/@`````=!A(BT,02#E"&'0'QT-0_/__
+M_UO#9F:09I#'0U#^____6\-F9F:09F:02(/L$+X<````2(D<)$B);"0(2(G[
+M2(MO*(M7'`^V302`^0)T,DACPD@YQG<5@.D!BU,@O@@```!T34ACPD@YQG8>
+MQT-0_O___TB+'"1(BVPD"$B#Q!##BT482(UP'.O%BWT`Z`````!(A<!TU8M]
+M`.@`````2(M3$$@Y$'0:QT-0_/___^O"BT482(UP"$ACPD@YQG>LZ\B`>!`!
+M=:2`?0<0=Y[KHV9F9I!F9I!F9I!(BW]8,<"%TDB+3RAT'X!Y!`%T'$B-01Q(
+MB48(BT$8QT8$`0```(D&N`$```#SPY!(BT<P2(/`"$B)1@CKWF:02(/L$$B)
+M'"1(B6PD"$B)^XMW'$B+;RB#_@MV=(M7((72>&V`?0<`=7P/MD4&,<G!X`F)
+MP$B->`Q(8\9(.?AR4(G(2&/22(/`!$@YPG)"BWT`Z`````!(A<!T-8M]`.@`
+M````2(M3$$@Y$'0)QT-0_/___^LB@'@0`745#[9%!@^W500!T#T`(```?@MF
+M9F:0QT-0_O___TB+'"1(BVPD"$B#Q!###[9-!K\,````P>$)ZX5F9F:09F:0
+M9F:09F:02(/L$$B)'"1(B6PD"$B)^XMW'$B+;RB#_@=V*XM'((7`>"2%]@^V
+M300/ME4%>!@/MM(/MLE(F`'*P>()B=)(@\((2#G0<Q7'0U#^____2(L<)$B+
+M;"0(2(/$$,.+?0#H`````$B%P'3>BWT`Z`````!(BU,02#D0=`G'0U#\____
+MZ\N`>!`!=;YF9F:09F:0Z[QF9F:09F9FD&9FD&9FD$%4BP4`````28G\54B)
+M]8/X_U-T?HM6&$C'PP````#K"TB#PRB+`X/X_W1G.=!U\8/``71>QT50````
+M`$B)[Y#_4PB+=5"%]G5008"\))`"!```=3Z+2R"%R0^%H````$F#O"3@`0``
+M`'0]28N4)!@"``!)C80D$`(``$F)K"08`@``2(E%`$B)50A(B2I;74%<P\=%
+M4/[___];2(GO3(M=2%U!7$'_XTB#>Q``28FL).`!``!T24B+0QA!QX0DZ`$`
+M``$```!(B>])B:PD^`$``$G'A"0``@```````$F)A"3P`0``_U,008N$).@!
+M``"#Z`&%P$&)A"3H`0``=8Y,BUL82(GO6UU!7$'_XV:02(L'2(V7:`,``,>'
+M$`,```__``#'AQ0#```(````QX<8`P```````$B)ER`#``!(QX<P`P``````
+M`$B)AP@#``"+A^@#``")<@1(QX=``P```````$B-M_@"``")AV@#``!(B[\(
+M`P``Z8+^__]FD%-(B?M(BW\02#F?X`$``'0/2(G?3(M;2%M!_^-F9F:02(NW
+M$`(``$B-AQ`"``!(QX?@`0```````$@YQG332(L62(M&"$B)0@A(B1!(B78(
+M2(DVZ"C^___KMV9FD&9FD(N'Z`,``,-F9I!F9I!F9I!(@^PXB?E)B?!(C50D
+M+$B)YTB)X,8``$B#P`%(.=!U](#Y!XA,)`@/A*L```"`^09T$(#Y!'0+@/D%
+M=`:`^0B0=1@/ME0D#/:&8`(```&X`0````]$PHA$)`R`^1QT88#Y`W0808N`
+MZ`,``$B)YXE$)`3H`````$B#Q#C#28M0($B%TG3?#[:"L````(A$)`R`NK``
+M````=<M(BX*0````2(E'$`^W@I@```")1Q@/MH*Q````T.B#X`&(1"0-ZZ1(
+MBX9H`@``2(E'#`^WAG0#``!FB4<4ZXQ(BT882(7`=`F+@.@#``")1PQ,BT8X
+MZ7'___]F9F:09F:09F:09F:00(@U`````,-F9F:09F9FD$B+5QA(C4\82#G*
+M=0OK+I!(BQ)(.<IT)8"Z@/S__P%(C8)P_/__=>CV0O`!=.*%]G0-2(L2@^X!
+M2#G*==LQP//#9F9FD&9F9I!F9F:09F:02(/L&$B)7"0(3(ED)!!(B?M!B?2+
+M=S1(BS]%B>3H`````$B)QP^V@+$```!(B5]0QH>P````!$B)7UA,B6=@QH>R
+M`````$C'A\@`````````@^#/@\@@B(>Q````2(M<)`A,BV0D$$B#Q!CI````
+M`$B#["A(B1PD3(ED)!!)B?Q,B6PD&$R)="0@28GU2(EL)`A(BR])B=:+=S1(
+MB>_H`````$B-O?````!(B</H`````$C'``````!)BU0D*$B)WTC'0#``````
+M2,=`$`````!(QT`H`````$C'0#@`````2(E0"$B-4!C'0$``````2(E#>$R)
+M8U!(B5`82(E0($R):UC&@[`````$3(FSR````,:#L@````!(BQPD2(ML)`A,
+MBV0D$$R+;"083(MT)"!(@\0HZ0````!F9I!F9I!(@^P82(D<)$B);"0(2(G]
+M3(ED)!"#`@%!B?2+=S1(BS](B=/H`````$B)QT&#_`$/MI>Q````&<!(B6]0
+M@\`"QH>P````!$B)7UB#X`/&A[(`````P>`$@^+/"<*(E[$```"`?1`$=A=(
+M@[V``@```'0-2,>'R`````````#K"TC'A\@`````````Z`````!(BWT`2(L<
+M)$B+;"0(3(MD)!!(@\08Z0````!F9I!FD$B#[#A,B7PD,$R-OQ`!``!,B60D
+M&$F)_$B);"003(EL)"!,B?],B70D*$B)7"0(28GV28G5Z`````!(A<!(B<4/
+MA,,```!)BUPD&$R)8"!)@\08QP`!````3(EP"$R):!!(QT`8`````$PYXW4*
+MZS-(BQM,.>-T*X"[@/S__P%(C;MP_/__=>CV0_`!=.)(B>J^`0```.BU_O__
+M2(L;3#GC==6+10"#Z`&%P(E%`'0C2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D
+M*$R+?"0P2(/$.,-(B>Y,B?_H`````$R)[TV)\TB+7"0(2(ML)!!,BV0D&$R+
+M;"0@3(MT)"A,BWPD,$B#Q#A!_^-(Q\<`````,<#H`````.O%9F9FD&9FD$B#
+M[#A,B7PD,$R-OQ`!``!,B60D&$F)_$B);"003(EL)"!,B?],B70D*$B)7"0(
+M28GV28G5Z`````!(A<!(B<4/A+(```!)BUPD&$R)8"!)@\08QP`!````3(EP
+M"$R):!!(QT`8`````$PYXW0D9I"#NZ#\____2(V[</S__W0*2(GJ,?;HIOW_
+M_TB+&TPYXW7>BT4`@^@!A<")10!T(TB+7"0(2(ML)!!,BV0D&$R+;"0@3(MT
+M)"A,BWPD,$B#Q#C#2(GN3(G_Z`````!,B>]-B?-(BUPD"$B+;"003(MD)!A,
+MBVPD($R+="0H3(M\)#!(@\0X0?_C2,?'`````#'`Z`````#KQ69F9I!F9F:0
+M2(M6.%-(B?M(B7X02(72=`6+1B")`DB)W^AR^/__2(G?6^D`````9F:09F:0
+M9F:0BX;H`P``2(V6:`,``$B)O@@#``#'AA`#```/_P``QX84`P``"````$B)
+MEB`#``#'0@0,````B89H`P``2(V&>@,``,>&&`,```````!(QX8P`P``````
+M`$B)MC@#``!(B88H`P``2,>&0`,```````!(@<;X`@``Z0````!F9I!(BT<0
+M2(FX*`(``$B-L"`"``!(C7A(2,>`(`(```````!(QX`P`@```````.D`````
+M9F9FD&9F9I!F9F:09F:02(M'$$B)N"@"``!(C;`@`@``2(UX2$C'@"`"````
+M````2,>`,`(```````#I`````&9F9I!F9F:09F9FD&9FD$B+1Q!(B;@H`@``
+M2(VP(`(``$B->$A(QX`@`@```````$C'@#`"````````Z0````!F9F:09F9F
+MD&9F9I!F9I!(BT<02(FX*`(``$B-L"`"``!(C7A(2,>`(`(```````!(QX`P
+M`@```````.D`````9F9FD&9F9I!F9F:09F:02(M'$$B)N"@"``!(C;`@`@``
+M2(UX2$C'@"`"````````2,>`,`(```````#I`````&9F9I!F9F:09F9FD&9F
+MD$B+1Q!(B;@H`@``2(VP(`(``$B->$A(QX`@`@```````$C'@#`"````````
+MZ0````!F9F:09F9FD&9F9I!F9I!(BT<02(FX*`(``$B-L"`"``!(C7A(2,>`
+M(`(```````!(QX`P`@```````.D`````9F9FD&9F9I!F9F:09F:02(M'$$B)
+MN"@"``!(C;`@`@``2(UX2$C'@"`"````````2,>`,`(```````#I`````&9F
+M9I!F9F:09F9FD&9FD$B+1Q!(B;@H`@``2(VP(`(``$B->$A(QX`@`@``````
+M`$C'@#`"````````Z0````!F9F:09F9FD&9F9I!F9I!(BT<02(FX*`(``$B-
+ML"`"``!(C7A(2,>`(`(```````!(QX`P`@```````.D`````9F9FD&9F9I!F
+M9F:09F:02(M'$$B)N"@"``!(C;`@`@``2(UX2$C'@"`"````````2,>`,`(`
+M``````#I`````&9F9I!F9F:09F9FD&9FD$B+1Q!(B;@H`@``2(VP(`(``$B-
+M>$A(QX`@`@```````$C'@#`"````````Z0````!F9F:09F9FD&9F9I!F9I!(
MBT<02(FX*`(``$B-L"`"``!(C7A(2,>`(`(```````!(QX`P`@```````.D`
M````9F9FD&9F9I!F9F:09F:02(M'$$B)N"@"``!(C;`@`@``2(UX2$C'@"`"
M````````2,>`,`(```````#I`````&9F9I!F9F:09F9FD&9FD$B+1Q!(B;@H
@@ -6303,420 +4975,404 @@ MD&9FD$B+1Q!(B;@H`@``2(VP(`(``$B->$A(QX`@`@```````$C'@#`"````
M````Z0````!F9F:09F9FD&9F9I!F9I!(BT<02(FX*`(``$B-L"`"``!(C7A(
M2,>`(`(```````!(QX`P`@```````.D`````9F9FD&9F9I!F9F:09F:02(M'
M$$B)N"@"``!(C;`@`@``2(UX2$C'@"`"````````2,>`,`(```````#I````
-M`&9F9I!F9F:09F9FD&9FD$B+1Q!(B;@H`@``2(VP(`(``$B->$A(QX`@`@``
-M`````$C'@#`"````````Z0````!F9F:09F9FD&9F9I!F9I!(BT<02(FX*`(`
-M`$B-L"`"``!(C7A(2,>`(`(```````!(QX`P`@```````.D`````9F9FD&9F
-M9I!F9F:09F:02(M'$$B)N"@"``!(C;`@`@``2(UX2$C'@"`"````````2,>`
-M,`(```````#I`````&9F9I!F9F:09F9FD&9FD$B+1Q!(B;@H`@``2(VP(`(`
-M`$B->$A(QX`@`@```````$C'@#`"````````Z0````!F9F:09F9FD&9F9I!F
-M9I!(BT<02(FX*`(``$B-L"`"``!(C7A(2,>`(`(```````!(QX`P`@``````
-M`.D`````9F9FD&9F9I!F9F:09F:02(M'$$B)N"@"``!(C;`@`@``2(UX2$C'
-M@"`"````````2,>`,`(```````#I`````&9F9I!F9F:09F9FD&9FD$B+1Q!(
-MB;@H`@``2(VP(`(``$B->$A(QX`@`@```````$C'@#`"````````Z0````!F
-M9F:09F9FD&9F9I!F9I!(BT<02(FX*`(``$B-L"`"``!(C7A(2,>`(`(`````
-M``!(QX`P`@```````.D`````9F9FD&9F9I!F9F:09F:02(M'$$B)N"@"``!(
-MC;`@`@``2(UX2$C'@"`"````````2,>`,`(```````#I`````&9F9I!F9F:0
-M9F9FD&9FD$B+1Q!(B;@H`@``2(VP(`(``$B->$A(QX`@`@```````$C'@#`"
-M````````Z0````!F9F:09F9FD&9F9I!F9I!(BT<02(FX*`(``$B-L"`"``!(
-MC7A(2,>`(`(```````!(QX`P`@```````.D`````9F9FD&9F9I!F9F:09F:0
-M2(M'$$B)N"@"``!(C;`@`@``2(UX2$C'@"`"````````2,>`,`(```````#I
-M`````&9F9I!F9F:09F9FD&9FD$C'1R@`````2(E_,$B-=RA(QT<X`````$B+
-M/TB#QTCI`````&9F9I!F9F:09F9FD$B+1PA(QT<P`````$B-=S!(B7\X2,='
-M0`````!(BSA(@\=(Z0````!F9F:09F9FD%.`O[(````!2(G[=!0/MH>S````
-M@\`!/`*(A[,```!V/TB+.TB+<WA(@<?P````Z`````!(BSM(QT,H`````$B-
-M<RA(B5LP2,=#.`````!;2(/'2.D`````9F9FD&9FD$B+1WC&A[(`````2,=`
-M$`````!(BT=X2(U0&$C'0"@`````2,=`,`````!(QT`X`````,=`0`````!(
-MB5`82(E0(%OI`````&9F9I!F9F:02(M'6(L0@^H!A=*)$'4D2,='*`````!(
-MB7\P2(UW*$C'1S@`````2(L_2(/'6.D`````Z0````!F9F:09F9FD$B#[!A(
-MB1PD2(EL)`A,B60D$$B+1U!(BY"``@``2(MJ"$@YQ0^$F````$B%[70)]H6`
-M`P```7482(L<)$B+;"0(3(MD)!!(@\08Z7'___^03(MG6`^VG[$```#H````
-M`$B+?0"+=33`ZP3H`````$B)QP^V@+$```"#XP/!XP1(B6]0QH>P````!$R)
-M9UC&A[(`````2,>'R`````````"#X,\)V(B'L0```$B+'"1(BVPD"$R+9"00
-M2(/$&.D`````2(MJ$.E?____9F:09I!(@^P83(ED)!!(B5PD"$F)_$B+7UA(
-MBWL0_U,(28L\)$B)WDB!QQ`!``#H`````$R)YTB+7"0(3(MD)!!(@\08Z0``
-M``!F9F:09F9FD&9FD$%428G\55-(@>S`````2(MO4$B-M"2`````2(M=>$B+
-M16A(B[V`````_U!X2(M#"$B)YDB+>Q#_4#A(C8PDM````$B-E"2X````2(VT
-M)+P```!(B=_H9LK___:$)(H````"=&R+E"2T````#[:$)(P````!PD&`O"2R
-M`````71@B[0DO````$C'QP`````QP.@`````2(GNOQH```#H`````$B+?0!)
-MBW0D6$B!QY````#H`````$R)Y^@`````2('$P````%M=05S#9F:09I"+E"2X
-M````ZY)F9F:09F:0B[0DO````$C'QP`````QP.@`````2(GNOQL```#H````
-M`.N>9F9FD&9F9I!F9F:02(/L&$B)7"0(2(EL)!!(BU]82(M#"$B+*.@`````
-M2(US,$C'0S``````2(E;.$B-?4A(QT-``````$B+7"0(2(ML)!!(@\08Z0``
-M``!F9I!(@^PX2(E<)`A(B6PD$$B)^TR)9"083(EL)"!,B70D*$R)?"0P@+^R
-M`````4B+;UA,BR],BW4(3(ME$$V+O>`!``!T&`^VA[,```"#P`$\`HB'LP``
-M``^&UP```$B+<WA)C;WP````Z`````!(B=_H`````$V%Y$F+5S`/A)\```!!
-MBX0DZ`,``(D"@\`!#X22````08".80(```1)B:PD@`(``$B-51A!@(PD80(`
-M``1)C44H2(UU,$&`I"1@`@``_4F)KH`"``!)C7U(28M-,$B)11A)B54P2(D1
-M2(E-($C'13``````2(EM.$C'14``````2(M<)`A(BVPD$$R+9"083(ML)"!,
-MBW0D*$R+?"0P2(/$..D`````9F:09I#'`O____]!QT=0_____^EA____2(M'
-M>,:'L@````!(QT`0`````$B+1WA(C5`82,=`*`````!(QT`P`````$C'0#@`
-M````QT!``````$B)4!A(B5`@2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+
-M?"0P2(/$..D`````9F9FD$%7059)B?Y!54%455-(@^P(2(MO*$R+;S"+?0#H
-M``````^V300/MG4%28G$0<=&4/____\/ME4&@/H+#X>O````@'T'"P^'I0``
-M``^VP8E$)`0/ML(#1"0$@_@+?@>Y"P```"C108A-!`^V30=`#[;6#[;!`="#
-M^`M^"+X+````0"C.08!]!`!-C7T(08AU!0^$B0```#';ZP]F9I!F9I"#PP%!
-M.%T$=G9)BW0D4`^V109(B=E(P>$)0;@!````N@$```"!X0#^`0!,B>=(@>X`
-M``(`3`'Y2('F``#^_T@!Q@^VPT@!QN@`````A<!TL$G'1E@`````38EV8$F-
-M=EA)QT9H`````$F+?A!(@\0(6UU!7$%=05Y!7^D`````08!]!0!T4S';ZP]F
-M9I!F9I"#PP%!.%T%=D`/MG4'#[;+`TPD!$D#="10#[;#0;@!````N@$```!,
-MB>?!X0E(8\E(C;0&`/C__TP!^>@`````A<!TO.EW____0<=&4`````#I:O__
-M_V9F9I!F9I!F9I!!5D%5051)B?Q54TB+7RB+.TR-<PSH`````$F)Q4F+1"0P
-MQP``````0<=$)%``````@'L'`'0'28G&28/&!(![!@!T9S'MZPF#Q0%`.&L&
-M=EI)BT50#[=S!$B)Z40/MD,'2,'A";H!````@>$`_@$`3(GO2"T```(`3`'Q
-M2"4``/[_2(UT!@M`#[;%2`'&Z`````"%P'2Q28M$)##'`/____]!QT0D4/__
-M__])QT0D6`````!-B60D8$F-="182<=$)&@`````28M\)!!;74%<05U!7ND`
-M````9F9FD&9FD%.`O[(````!2(M?6$B+2S!T/H"_D@````!U-<=#4/_____H
-M`````$C'0U@`````2(E;8$B-<UA(QT-H`````$B+>Q!;Z0````!F9F:09F:0
-MQT-0``````^VAY(```"$P(@!=1R+AY0```")001(BU,X2(72=*R+002#P`B)
-M`NNB#[:'D0```(E!!.OA9F9FD$B![,@```!(B:PDH````$B)G"28````2(G]
-M3(FD)*@```!,B:PDL````$R)M"2X````3(F\),````!(BT<H#[90`@^V"(#Z
-M`P^$*0$``(#Z!`^$20$``(!X`05V!H!X!?YT?P^V^3'VZ)/#__](B<-(BT40
-M2(M52$B)[DC'14@`````2(FH*`(``$B)D"`"``!(QX`P`@```````$B+0PA(
-MBWL0_Y#X````2(N<))@```!(BZPDH````$R+I"2H````3(NL)+````!,B[0D
-MN````$R+O"3`````2('$R````,-$BW<@,?8/MOE,C7@+1`^V8`OH!\/__TB%
-MP$B)PW0_2(M#"$B+@`@!``!(A<!T$DB+>Q#_T$0XX`^'ZP```$$HQ$B+&TB%
-MVW052(M#"$B+>Q!(B>;_4#B`?"03`'3!2(M%.,<``````$B+?1!(C758QT50
-M_____TC'15@`````2(EM8$C'16@`````Z`````#I,____P^V0`1(C;0DC```
-M``^V^8F$)(P```#H;L+__TB)P^G6_O__9F:09F:0,?8/MOE,C7`#1`^V8`/H
-M3<+__TB%P$B)PW4MZXUF9I!!*,1(BQM(A=L/A'O___](BT,(2(M[$$B)YO]0
-M.(!\)!,`#X5B____2(M#"$B+@`@!``!(A<!TRTB+>Q#_T$0XX':]18@FZ67^
-M__]%B"=(BT4X1(DPZ5;^__]F9I!F9I!(BU<02(UW6$B)?V!(QT=H`````$B+
-M@B`"``!(QT=8`````$B)1TA(B=?I`````)!!5T4QP$%6055)B?U!5%532('L
-MJ````$B+1RA(BRT`````BP!(A>V)1"0<2(M','1I3(UX!$R-="0@13'D2(M=
-M$$B%VW4.ZT5!@\0!2(L;2(7;=#E(BT,(1(E$)`A,B?9(BWL0_U`X@'PD,P!$
-MBT0D"'3923EM$'7/08/``40Y1"0<18DG=@])@\<$Z[M(BVT`2(7M=:=)BT4P
-M28M]$$F-=5A)QT58`````$V);6!)QT5H`````$2)`.@`````2('$J````%M=
-M05Q!74%>05_#BS4`````.S4`````2(M/,`^$B@```$ACQDB-%(!(C1102(L$
-ME0````!(B0%(BP25`````$B)00A(BP25`````$B)01!(BP25`````$B)01A(
-MBP25`````$B)02"+!)4`````B4$HC48!B<+!^A_!ZAP!T(/@#RG0B04`````
-M2,='6`````!(B7]@2(UW6$C'1V@`````2(M_$.D`````D,='4/_____KU69F
-M9I!F9I!(@^PH,?9(B5PD"$B);"002(G[3(ED)!A,B6PD($B+1RB+.$2+:`2+
-M:`A$BV`,Z/V___](A<!(B<%T?(7M=%A(BU,H2(M`"$4QP$B+>1!$B>Y$B>%(
-M@\(0_Y`P`0``2(M[$$B-<UA(QT-8`````$B)6V!(QT-H`````$B+7"0(2(ML
-M)!!,BV0D&$R+;"0@2(/$*.D`````2(MY$$B+4S!!N`$```!(BT`(1(GA1(GN
-M_Y`P`0``ZZ?'0U#^____ZYY5,?932(G[2('LB````$B+1RB+..A7O___2(7`
-M2(G"2(MK,'1+2(M`"$B)YDB+>A#_4#@/MT0D!&:)10`/MT0D!F:)10)(BWL0
-M2(US6$C'0U@`````2(E;8$C'0V@`````Z`````!(@<2(````6UW#QT-0_O__
-M_^O,9F9FD&9FD$B#["A(B6PD$$R)9"082(G]2(E<)`A,B6PD($B+1RA,BV\P
-MBQA,C6`$B=^#ZP'H`````(/[_4B)Q[@`````2`]'^$$/MD0D"H3`=0E!#[9$
-M)`[`Z`1%#[9$)`Y!#[9T)`P/ML!!#[94)`U)C4PD?$&)P4&#X`_HQ<7__TB+
-M?1!(C75828E%`$C'15@`````2(EM8$C'16@`````2(M<)`A(BVPD$$R+9"08
-M3(ML)"!(@\0HZ0````!F9F:09F9FD$B#["A,B60D"$R)="0828G\2(D<)$R)
-M;"003(E\)"!,BV\H3(M_,$&+70!-C74$B=^#ZP'H`````$4/MD8"00^V=02#
-M^_U!#[96`4B)QTF-372X`````$@/1_A%,<E!@^`/Z!G%__])BWPD$$F-="18
-M28D'2<=$)%@`````38ED)&!)QT0D:`````!(BQPD3(MD)`A,BVPD$$R+="08
-M3(M\)"!(@\0HZ0````!F9F:04TB+1RA(BU\P1(L03(U;!$6%TGY]3(L-````
-M`$V%R71Q13'`28M)&$F-<1A(.?%U"NM52(L)2#GQ=$V`N8#\__\!2(V!</S_
-M_W7HBX#H`P``26/008/``44YPD&)!)-UTD2)P$C'1U@`````2(E_8$B-=UA(
-MQT=H`````(D#6TB+?Q#I`````$V+"4V%R764Z\\QP.O.9F9FD&9FD&9FD%53
-M2(M'*$B+;S!$BQA(C5T$187;#X[(````3(L5`````$V%T@^$N````$4QR4F+
-M2AA-C4(83#G!=1+IDP```)!(BPE,.<$/A(8```!(@[F(_/__`$B-L7#\__]U
-MXP^V@8#\__\\!'972(N!\/[__TB%P'0-2(-X"`!T!D@Y<!!TOXN&Z`,``$EC
-MT4&#P0&)!)-%.=EUJD2)R$C'1U@`````2(E_8$B-=UA(QT=H`````(E%`%M=
-M2(M_$.D`````+`%USO:!U/S__P)TQ69F9I#KKTV+$DV%T@^%3____V:0Z[0Q
-MP.NS9F9FD&9FD&9FD$%7,?9!5D%5051)B?Q54TB![(@```!(BT<H3(MW,(LX
-MBV@$1(MX".C$N___2(7`2(G#0<=$)%#_____=#QF9I!(BT,(2(N`"`$``$B%
-MP'0,2(M[$/_0.<5\5RG%2(L;2(7;=!5(BT,(2(M[$$B)YO]0.(!\)!,`=,=)
+M`&9F9I!F9F:09F9FD&9FD$C'1R@`````2(E_,$B-=RA(QT<X`````$B+/TB#
+MQTCI`````&9F9I!F9F:09F9FD$B+1PA(QT<P`````$B-=S!(B7\X2,='0```
+M``!(BSA(@\=(Z0````!F9F:09F9FD%.`O[(````!2(G[=!0/MH>S````@\`!
+M/`*(A[,```!V/TB+.TB+<WA(@<?P````Z`````!(BSM(QT,H`````$B-<RA(
+MB5LP2,=#.`````!;2(/'2.D`````9F9FD&9FD$B+1WC&A[(`````2,=`$```
+M``!(BT=X2(U0&$C'0"@`````2,=`,`````!(QT`X`````,=`0`````!(B5`8
+M2(E0(%OI`````&9F9I!F9F:02(M'6(L0@^H!A=*)$'4D2,='*`````!(B7\P
+M2(UW*$C'1S@`````2(L_2(/'6.D`````Z0````!F9F:09F9FD$B#[!A(B1PD
+M2(EL)`A,B60D$$B+1U!(BY"``@``2(MJ"$@YQ0^$F````$B%[70)]H6``P``
+M`7482(L<)$B+;"0(3(MD)!!(@\08Z7'___^03(MG6`^VG[$```#H`````$B+
+M?0"+=33`ZP3H`````$B)QP^V@+$```"#XP/!XP1(B6]0QH>P````!$R)9UC&
+MA[(`````2,>'R`````````"#X,\)V(B'L0```$B+'"1(BVPD"$R+9"002(/$
+M&.D`````2(MJ$.E?____9F:09I!(@^P83(ED)!!(B5PD"$F)_$B+7UA(BWL0
+M_U,(28L\)$B)WDB!QQ`!``#H`````$R)YTB+7"0(3(MD)!!(@\08Z0````!F
+M9F:09F9FD&9FD$%428G\55-(@>S`````2(MO4$B-M"2`````2(N=@````$B+
+M17!(B[V(````_U!X2(M#"$B)YDB+>Q#_4#A(C8PDM````$B-E"2X````2(VT
+M)+P```!(B=_H8\K___:$)(X````"=&F+E"2T````#[:$))`````!PD&`O"2R
+M`````71=B[0DO````$C'QP`````QP.@`````2(GNOQH```#H`````$B+?0!)
+MBW0D6$B!QY````#H`````$R)Y^@`````2('$P````%M=05S#9I"+E"2X````
+MZY5F9F:09F:0B[0DO````$C'QP`````QP.@`````2(GNOQL```#H`````.NA
+M9F9FD&9F9I!F9F:02(/L&$B)7"0(2(EL)!!(BU]82(M#"$B+*.@`````2(US
+M,$C'0S``````2(E;.$B-?4A(QT-``````$B+7"0(2(ML)!!(@\08Z0````!F
+M9I!(@^PX2(E<)`A(B6PD$$B)^TR)9"083(EL)"!,B70D*$R)?"0P@+^R````
+M`4B+;UA,BR],BW4(3(ME$$V+O>`!``!T&`^VA[,```"#P`$\`HB'LP````^&
+MUP```$B+<WA)C;WP````Z`````!(B=_H`````$V%Y$F+5S`/A)\```!!BX0D
+MZ`,``(D"@\`!#X22````08".80(```1)B:PD@`(``$B-51A!@(PD80(```1)
+MC44H2(UU,$&`I"1@`@``_4F)KH`"``!)C7U(28M-,$B)11A)B54P2(D12(E-
+M($C'13``````2(EM.$C'14``````2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D
+M*$R+?"0P2(/$..D`````9F:09I#'`O____]!QT=0_____^EA____2(M'>,:'
+ML@````!(QT`0`````$B+1WA(C5`82,=`*`````!(QT`P`````$C'0#@`````
+MQT!``````$B)4!A(B5`@2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P
+M2(/$..D`````9F9FD$%7059)B?Y!54%455-(@^P(2(MO*$R+;S"+?0#H````
+M``^V300/MG4%28G$0<=&4/____\/ME4&@/H+#X>O````@'T'"P^'I0````^V
+MP8E$)`0/ML(#1"0$@_@+?@>Y"P```"C108A-!`^V30=`#[;6#[;!`="#^`M^
+M"+X+````0"C.08!]!`!-C7T(08AU!0^$B0```#';ZP]F9I!F9I"#PP%!.%T$
+M=G9)BW0D4`^V109(B=E(P>$)0;@!````N@$```"!X0#^`0!,B>=(@>X```(`
+M3`'Y2('F``#^_T@!Q@^VPT@!QN@`````A<!TL$G'1E@`````38EV8$F-=EA)
+MQT9H`````$F+?A!(@\0(6UU!7$%=05Y!7^D`````08!]!0!T4S';ZP]F9I!F
+M9I"#PP%!.%T%=D`/MG4'#[;+`TPD!$D#="10#[;#0;@!````N@$```!,B>?!
+MX0E(8\E(C;0&`/C__TP!^>@`````A<!TO.EW____0<=&4`````#I:O___V9F
+M9I!F9I!F9I!!5D%5051)B?Q54TB+7RB+.TR-<PSH`````$F)Q4F+1"0PQP``
+M````0<=$)%``````@'L'`'0'28G&28/&!(![!@!T9S'MZPF#Q0%`.&L&=EI)
+MBT50#[=S!$B)Z40/MD,'2,'A";H!````@>$`_@$`3(GO2"T```(`3`'Q2"4`
+M`/[_2(UT!@M`#[;%2`'&Z`````"%P'2Q28M$)##'`/____]!QT0D4/____])
+MQT0D6`````!-B60D8$F-="182<=$)&@`````28M\)!!;74%<05U!7ND`````
+M9F9FD&9FD%.`O[(````!2(M?6$B+2S!T/H"_D@````!U-<=#4/_____H````
+M`$C'0U@`````2(E;8$B-<UA(QT-H`````$B+>Q!;Z0````!F9F:09F:0QT-0
+M``````^VAY(```"$P(@!=1R+AY0```")001(BU,X2(72=*R+002#P`B)`NNB
+M#[:'D0```(E!!.OA9F9FD$B![,@```!(B:PDH````$B)G"28````2(G]3(FD
+M)*@```!,B:PDL````$R)M"2X````3(F\),````!(BT<H#[90`@^V"(#Z`P^$
+M*0$``(#Z!`^$20$``(!X`05V!H!X!?YT?P^V^3'VZ)/#__](B<-(BT402(M5
+M2$B)[DC'14@`````2(FH*`(``$B)D"`"``!(QX`P`@```````$B+0PA(BWL0
+M_Y#X````2(N<))@```!(BZPDH````$R+I"2H````3(NL)+````!,B[0DN```
+M`$R+O"3`````2('$R````,-$BW<@,?8/MOE,C7@+1`^V8`OH!\/__TB%P$B)
+MPW0_2(M#"$B+@`@!``!(A<!T$DB+>Q#_T$0XX`^'ZP```$$HQ$B+&TB%VW05
+M2(M#"$B+>Q!(B>;_4#B`?"03`'3!2(M%.,<``````$B+?1!(C758QT50____
+M_TC'15@`````2(EM8$C'16@`````Z`````#I,____P^V0`1(C;0DC`````^V
+M^8F$)(P```#H;L+__TB)P^G6_O__9F:09F:0,?8/MOE,C7`#1`^V8`/H3<+_
+M_TB%P$B)PW4MZXUF9I!!*,1(BQM(A=L/A'O___](BT,(2(M[$$B)YO]0.(!\
+M)!,`#X5B____2(M#"$B+@`@!``!(A<!TRTB+>Q#_T$0XX':]18@FZ67^__]%
+MB"=(BT4X1(DPZ5;^__]F9I!F9I!(BU<02(UW6$B)?V!(QT=H`````$B+@B`"
+M``!(QT=8`````$B)1TA(B=?I`````)!!5T4QP$%6055)B?U!5%532('LJ```
+M`$B+1RA(BRT`````BP!(A>V)1"0<2(M','1I3(UX!$R-="0@13'D2(M=$$B%
+MVW4.ZT5!@\0!2(L;2(7;=#E(BT,(1(E$)`A,B?9(BWL0_U`X@'PD,P!$BT0D
+M"'3923EM$'7/08/``40Y1"0<18DG=@])@\<$Z[M(BVT`2(7M=:=)BT4P28M]
+M$$F-=5A)QT58`````$V);6!)QT5H`````$2)`.@`````2('$J````%M=05Q!
+M74%>05_#BS4`````.S4`````2(M/,`^$B@```$ACQDB-%(!(C1102(L$E0``
+M``!(B0%(BP25`````$B)00A(BP25`````$B)01!(BP25`````$B)01A(BP25
+M`````$B)02"+!)4`````B4$HC48!B<+!^A_!ZAP!T(/@#RG0B04`````2,='
+M6`````!(B7]@2(UW6$C'1V@`````2(M_$.D`````D,='4/_____KU69F9I!F
+M9I!(@^PH,?9(B5PD"$B);"002(G[3(ED)!A,B6PD($B+1RB+.$2+:`2+:`A$
+MBV`,Z/V___](A<!(B<%T?(7M=%A(BU,H2(M`"$4QP$B+>1!$B>Y$B>%(@\(0
+M_Y`P`0``2(M[$$B-<UA(QT-8`````$B)6V!(QT-H`````$B+7"0(2(ML)!!,
+MBV0D&$R+;"0@2(/$*.D`````2(MY$$B+4S!!N`$```!(BT`(1(GA1(GN_Y`P
+M`0``ZZ?'0U#^____ZYY5,?932(G[2('LB````$B+1RB+..A7O___2(7`2(G"
+M2(MK,'1+2(M`"$B)YDB+>A#_4#@/MT0D!&:)10`/MT0D!F:)10)(BWL02(US
+M6$C'0U@`````2(E;8$C'0V@`````Z`````!(@<2(````6UW#QT-0_O___^O,
+M9F9FD&9FD$B#["A(B6PD$$R)9"082(G]2(E<)`A,B6PD($B+1RA,BV\PBQA,
+MC6`$B=^#ZP'H`````(/[_4B)Q[@`````2`]'^$$/MD0D"H3`=0E!#[9$)`[`
+MZ`1%#[9$)`Y!#[9T)`P/ML!!#[94)`U)C4PD?$&)P4&#X`_HQ<7__TB+?1!(
+MC75828E%`$C'15@`````2(EM8$C'16@`````2(M<)`A(BVPD$$R+9"083(ML
+M)"!(@\0HZ0````!F9F:09F9FD$B#["A,B60D"$R)="0828G\2(D<)$R);"00
+M3(E\)"!,BV\H3(M_,$&+70!-C74$B=^#ZP'H`````$4/MD8"00^V=02#^_U!
+M#[96`4B)QTF-372X`````$@/1_A%,<E!@^`/Z!G%__])BWPD$$F-="1828D'
+M2<=$)%@`````38ED)&!)QT0D:`````!(BQPD3(MD)`A,BVPD$$R+="083(M\
+M)"!(@\0HZ0````!F9F:04TB+1RA(BU\P1(L03(U;!$6%TGY]3(L-`````$V%
+MR71Q13'`28M)&$F-<1A(.?%U"NM52(L)2#GQ=$V`N8#\__\!2(V!</S__W7H
+MBX#H`P``26/008/``44YPD&)!)-UTD2)P$C'1U@`````2(E_8$B-=UA(QT=H
+M`````(D#6TB+?Q#I`````$V+"4V%R764Z\\QP.O.9F9FD&9FD&9FD%532(M'
+M*$B+;S!$BQA(C5T$187;#X[(````3(L5`````$V%T@^$N````$4QR4F+2AA-
+MC4(83#G!=1+IDP```)!(BPE,.<$/A(8```!(@[F(_/__`$B-L7#\__]UXP^V
+M@8#\__\\!'972(N!\/[__TB%P'0-2(-X"`!T!D@Y<!!TOXN&Z`,``$ECT4&#
+MP0&)!)-%.=EUJD2)R$C'1U@`````2(E_8$B-=UA(QT=H`````(E%`%M=2(M_
+M$.D`````+`%USO:!V/S__P)TQ69F9I#KKTV+$DV%T@^%3____V:0Z[0QP.NS
+M9F9FD&9FD&9FD$%7,?9!5D%5051)B?Q54TB![(@```!(BT<H3(MW,(LXBV@$
+M1(MX".C$N___2(7`2(G#0<=$)%#_____=#QF9I!(BT,(2(N`"`$``$B%P'0,
+M2(M[$/_0.<5\5RG%2(L;2(7;=!5(BT,(2(M[$$B)YO]0.(!\)!,`=,=)BWPD
+M$$F-="182<=$)%@`````38ED)&!)QT0D:`````#H`````$B!Q(@```!;74%<
+M05U!7D%?PTB+0P@QR4B+>Q!-B?!$B?J)[O^0*`$``(7`=:Q!QT0D4`````#K
+MH69F9I!F9F:005<Q]D%6055!5$F)_%532('LB````$B+1RA,BW\PBSB+:`3H
+MZ+K__TB%P$B)PT''1"10_____W1#13'M9F9FD$B+0PA(BX`(`0``2(7`=`](
+MBWL0_]`YQ7Q:*<5!`<5(BQM(A=MT%4B+0PA(BWL02(GF_U`X@'PD$P!TQ$F+
+M?"0028UT)%A)QT0D6`````!-B60D8$G'1"1H`````.@`````2('$B````%M=
+M05Q!74%>05_#2(M#"$B+@"@!``!(A<!TN$4QP#'22(M[$$R)^8GN_]"%P'6D
+M00^V1P(\_W0'1`'H08A'`D''1"10`````.N)9F9FD&9FD&9FD&9FD$%7,?9!
+M5D%5051)B?Q54TB![(@```!(BT<H3(M_,(LXBV@$Z.BY__](A<!(B<-!QT0D
+M4/____]T0T4Q[69F9I!(BT,(2(N`"`$``$B%P'0/2(M[$/_0.<5\6BG%00'%
+M2(L;2(7;=!5(BT,(2(M[$$B)YO]0.(!\)!,`=,1)BWPD$$F-="182<=$)%@`
+M````38ED)&!)QT0D:`````#H`````$B!Q(@```!;74%<05U!7D%?PTB+0PA(
+MBX`@`0``2(7`=+A(BWL03(GZB>[_T(7`=:E!#[9'`CS_=`=$`>A!B$<"0<=$
+M)%``````ZXYFD$%7,?9!5D%5051)B?Q54TB![(@```!(BT<H3(M_,(LXBV@$
+MZ/BX__](A<!(B<-!QT0D4/____]T0T4Q[69F9I!(BT,(2(N`"`$``$B%P'0/
+M2(M[$/_0.<5\6BG%00'%2(L;2(7;=!5(BT,(2(M[$$B)YO]0.(!\)!,`=,1)
MBWPD$$F-="182<=$)%@`````38ED)&!)QT0D:`````#H`````$B!Q(@```!;
-M74%<05U!7D%?PTB+0P@QR4B+>Q!-B?!$B?J)[O^0*`$``(7`=:Q!QT0D4```
-M``#KH69F9I!F9F:005<Q]D%6055!5$F)_%532('LB````$B+1RA,BW\PBSB+
-M:`3HZ+K__TB%P$B)PT''1"10_____W1#13'M9F9FD$B+0PA(BX`(`0``2(7`
-M=`](BWL0_]`YQ7Q:*<5!`<5(BQM(A=MT%4B+0PA(BWL02(GF_U`X@'PD$P!T
-MQ$F+?"0028UT)%A)QT0D6`````!-B60D8$G'1"1H`````.@`````2('$B```
-M`%M=05Q!74%>05_#2(M#"$B+@"@!``!(A<!TN$4QP#'22(M[$$R)^8GN_]"%
-MP'6D00^V1P(\_W0'1`'H08A'`D''1"10`````.N)9F9FD&9FD&9FD&9FD$%7
-M,?9!5D%5051)B?Q54TB![(@```!(BT<H3(M_,(LXBV@$Z.BY__](A<!(B<-!
-MQT0D4/____]T0T4Q[69F9I!(BT,(2(N`"`$``$B%P'0/2(M[$/_0.<5\6BG%
-M00'%2(L;2(7;=!5(BT,(2(M[$$B)YO]0.(!\)!,`=,1)BWPD$$F-="182<=$
-M)%@`````38ED)&!)QT0D:`````#H`````$B!Q(@```!;74%<05U!7D%?PTB+
-M0PA(BX`@`0``2(7`=+A(BWL03(GZB>[_T(7`=:E!#[9'`CS_=`=$`>A!B$<"
-M0<=$)%``````ZXYFD$%7,?9!5D%5051)B?Q54TB![(@```!(BT<H3(M_,(LX
-MBV@$Z/BX__](A<!(B<-!QT0D4/____]T0T4Q[69F9I!(BT,(2(N`"`$``$B%
-MP'0/2(M[$/_0.<5\6BG%00'%2(L;2(7;=!5(BT,(2(M[$$B)YO]0.(!\)!,`
-M=,1)BWPD$$F-="182<=$)%@`````38ED)&!)QT0D:`````#H`````$B!Q(@`
-M``!;74%<05U!7D%?PTB+0PA(BX`8`0``2(7`=+A(BWL03(GZB>[_T(7`=:E!
-M#[9'`CS_=`=$`>A!B$<"0<=$)%``````ZXYFD$%7,?9!5D%5051)B?Q54TB!
-M[(@```!(BT<H3(M_,(LXBV@$Z`BX__](A<!(B<-!QT0D4/____]T0T4Q[69F
-M9I!(BT,(2(N`"`$``$B%P'0/2(M[$/_0.<5\6BG%00'%2(L;2(7;=!5(BT,(
-M2(M[$$B)YO]0.(!\)!,`=,1)BWPD$$F-="182<=$)%@`````38ED)&!)QT0D
-M:`````#H`````$B!Q(@```!;74%<05U!7D%?PTB+0PA(BX`0`0``2(7`=+A(
-MBWL03(GZB>[_T(7`=:E!#[9'`CS_=`=$`>A!B$<"0<=$)%``````ZXYFD$%5
-M,?9!5%5(B?U32('LB````$B+1RB+..@CM___,=)(A<!(B<-T0D4QY&9FD&9F
-MD$B+0PA(BX`(`0``2(7`=`E(BWL0_]!!`<1(BQM(A=MT%4B+0PA(BWL02(GF
-M_U`X@'PD$P!TRD2)XDB+13!(BWT02(UU6$C'15@`````2(EM8$C'16@`````
-MB1#H`````$B!Q(@```!;74%<05W#9I!32(M'*$B)^TB+5S"+<`2+..BZN/__
-MA<!T!\=#4/____](QT-8`````$B)6V!(C7-82,=#:`````!(BWL06^D`````
-M9F9FD&9FD&9FD&9FD%5(B?TQ]E-(@>R(````2(M'*$B+7S"+..@SMO__2(7`
-M2(G"='\QP,8$&`!(@\`!2(/X1'7R2(G@2(V,)(````#&``!(@\`!2#G(=>Q(
-MBT((2(MZ$$B)YO]0.`^V1"1QB`,/MD0D<HA#`0^V1"1SB$,"#[9$)'2(0P-(
-MBWT02(UU6$C'15@`````2(EM8$C'16@`````Z`````!(@<2(````6UW#QT50
-M_____^O,9F:02(/L&$B)7"0(3(ED)!!(B?M,BV<PZ%:W__](BWL02(US6$C'
-M0U@`````08D$)$B)6V!(QT-H`````$B+7"0(3(MD)!!(@\08Z0````!F9I!5
-M2,?&`````%-(B?M(@^P(2(MO*$B)[^CDM/__A<!U,0^V12"(!0````!(QT-8
-M`````$B)6V!(C7-82,=#:`````!(BWL02(/$"%M=Z0````!(Q\8`````2(GO
-MZ*"T__^%P'43#[9%((T$Q7#^__^)!0````#KLTC'Q@````!(B>_H>K3__X7`
-M=$I(Q\8`````2(GOZ&>T__^%P'5&2(M[$$C'AR`"````````2(F?*`(``$C'
-MAS`"````````2(/$"%M=2(VW(`(``$B#QTCI``````^V12"(!0````#I1___
-M_TC'Q@````!(B>_H#K3__X7`=1%(BWL02,>'(`(```````#KI<=#4/_____I
-M%____V9F9I!F9I!F9I!F9I!(BT<P2,='6`````!(C7=82(E_8$C'1V@`````
-M2(M_$,<````!`ND`````9F:09I!!5D%505152(G]4TB#[$!(BT4H2(M_$,9$
-M)#`'@'@@`4R-9Q@9P(/``HA$)#A(BU\83#GC="5,C70D,&9FD&:0]D/P`70)
-M@+N`_/__`70]2(L;3#GC=>E(BWT02(UU6,=%4`````!(QT58`````$B);6!(
-MQT5H`````.@`````2(/$0%M=05Q!74%>PTB+@]C\__](B[OP_/__2(GF_U!X
-M#[9$)`\Z1"0X=*1(BX/8_/__2(N[\/S__TR)]O^0P````.N+9F9FD&9F9I!F
-M9F:02(/L*$B)'"1,B60D$$B)^TB);"0(3(EL)!A,B70D($B+;UA,BS=(BT4H
-M1(LH1(GOZ`````"`N[(````!28G$=!@/MH.S````@\`!/`*(@[,````/AI<`
-M``!(BW-X28V^\````.@`````2(G?Z`````"+11@]*?\``'1E/3G_``!T7DV%
-MY'0/28L$)$PY\&:0#X3`````2(M]$$B-=5C'15#^____2,=%6`````!(B6U@
-M2,=%:`````!(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HZ0````!F9I!F
-M9I!(BT4P1(DHZYEF9F:09F:02(M#>,:#L@````!(B=](QT`0`````$B+0WA(
-MC5`82,=`*`````!(QT`P`````$C'0#@`````QT!``````$B)4!A(B5`@2(L<
-M)$B+;"0(3(MD)!!,BVPD&$R+="0@2(/$*.D`````2(VP(`(``$B->$A(QX`@
-M`@```````$B)J"@"``!(QX`P`@```````$B+'"1(BVPD"$R+9"003(ML)!A,
-MBW0D($B#Q"CI`````)!(BS=(@<;H`0``Z0````"02(/L"$B+1RB+..@`````
-M2(/$"$B)Q^O89F9FD&9F9I!(@^P(2(M'*(LXZ`````!(@\0(2(G'Z[AF9F:0
-M9F9FD$B#[`A(BT<H@'@$`8LX=`5(@\0(P^@`````2(/$"$B)Q^N-9F9FD&9F
-MD&9FD&9FD$%528G]05154TB#[`A(BT<HBQ!F]\(`_W5$08G408'D_P```'XX
-M,>V[!````.L%D$F+12B+/!CH`````$B%P'01@'@0!'8+2(.X@`(```"0=!>#
-MQ0%(@\,$1#GE==)(@\0(6UU!7$%=PTB)Q^@/____Z]]F9F:09F:09F:09F:0
-M2(/L"$B+1RB+..@`````2(/$"$B)Q^GE_O__9F:09I!(@^P82(EL)!!(B5PD
-M"$B+1RB+6`2+..@`````@_L-2(G%=#2#^P%T&8/[!'04@_L'=`](BUPD"$B+
-M;"002(/$&,-(B>](BUPD"$B+;"002(/$&.F(_O__2(7`=-9(BX"``@``2(7`
-M=,I(BW@(2(7_=`SH:?[__TB+A8`"``!(BW@02(7_=;[KJF9F9I!F9I!(@^P8
-M3(ED)!!(B5PD"$B+1RB+6`2+..@`````B=])B<3H`````$R)YTB)P^@?_O__
-M2(G?3(MD)!!(BUPD"$B#Q!CI"?[__V9FD&9FD&9FD$B#[`A(BT<HBSCH````
-M`$B#Q`A(B<?IY?W__V9FD&:02(/L"$B+1RB+..@`````2(/$"$B)Q^G%_?__
-M9F:09I!32(M'*(LXZ`````!(A<!(B<-T,$B+@(`"``!(A<!T)$B+>`A(A?]T
-M#.B2_?__2(N#@`(``$B+>!!(A?]T$EOI?/W__TB)WUOI<_W__V9FD%O#9F9F
-MD&9F9I!F9I!F9I!54TB#[`A(BV\H2(/%!(!]#0!T(#';B=B#PP&+?(5\Z```
-M``!(B<?H-/W__P^V10TYV'?B2(/$"%M=PV9FD&:055-(@^P(2(MO*$B#Q02`
-M?0$`="`QVXG8@\,!BWR%<.@`````2(G'Z/3\__\/MD4!.=AWXDB#Q`A;7<-F
-M9I!FD%532(/L"$B+;RB`?0T`="`QVXG8@\,!BWR%?.@`````2(G'Z+C\__\/
-MMD4-.=AWXDB#Q`A;7<-F9I!F9I!F9I!54TB#[`A(BV\H@'T!`'0@,=N)V(/#
-M`8M\A7#H`````$B)Q^AX_/__#[9%`3G8=^)(@\0(6UW#9F:09F:09F:055-(
-M@^P(2(MO*(!]`0!T(#';B=B#PP&+?(5HZ`````!(B<?H./S__P^V10$YV'?B
-M2(/$"%M=PV9FD&9FD&9FD%532(/L"$B+;RB+?0"%_W0=,=N#PP&)V(M\A0#H
-M`````$B)Q^CW^___.5T`=^5(@\0(6UW#9F9FD&9F9I!F9I!52(G]2,?&````
-M`%-(@^P(2(M_*.@'K?__A<!U.4B+11!(BU@82(/`&$@YPW0H9I#V0_`!2(V[
-M</S__W0)@+N`_/__`7072(M%$$B+&TB#P!A(.=AUVDB#Q`A;7</H?OO__^OB
-M9F9FD&9F9I!F9F:005=!5D%505152(G]4TB![)@```!,BV\03(MW*$F+71A-
-MC6483#GC="I,C;PD@````/9#\`%(C;MP_/__=`V`NX#\__\!#X2V````2(L;
-M3#GC==Y!#[9&((@%`````$F+71!(A=MU$>M>9F9FD&9FD$B+&TB%VW1/2(M#
-M"$B+>Q!(B>;_4#CV1"01$'3C28V=.`$``$R)[TB)WN@`````0<>%.`$```"'
-MDP-)QX5(`0```````$B)WDV)K5`!``!,B>_H`````$B+?1!(C758QT50````
-M`$C'15@`````2(EM8$C'16@`````Z`````!(@<28````6UU!7$%=05Y!7\/H
-M`````,:$)(`````(00^V1B!,B?Z(A"2(````2(N#V/S__TB+N_#\____D,``
-M``#I%?___V9F9I!F9I!F9I!(@^PH2(E<)`A(B6PD$$B)_4R);"0@3(ED)!A)
-MB?6+=S1(BS_H`````$B%P$B)PP^$:0(``$4QY,:`L`````-!@7T80O\``$B)
-M:%!!#Y3$187D#X6X````28M5*#'`@'H*]`^4P(7`#X6X````187D#X1*`0``
-M#[9"$CP!#X0!`@``/`(/A,<!```/MD(/B(.;````#[=""&:)@Y0````/MT(*
-M9HF#E@````^W0@QFB8.8````#[9"#HB#F@````^W0@1FB8.0````#[="!F:)
-M@Y(````/MT(09HF#G````$R):UA(QX/(`````````$B)WTB+;"002(M<)`A,
-MBV0D&$R+;"0@2(/$*.D`````D$F+52@QP(!Z#_0/E,"%P`^$2/___TB+?0!(
-M@<>0````Z`````!(A<!(B<4/A)X!``!%A>0/A>8```!)BW4H2(/&$$B)[[H`
-M`@``Z`````"`B[$````$2(FKH````$F-=5C&@YL```#T9L>#G`````$`28M]
-M$$B):UA(QX/(`````````$''15``````2<=%6`````!-B6U@2<=%:`````#H
-M`````.DU____9F:09F:0#[9"##P!#X2<````/`)FD'1K#[9""HB#FP````^V
-M0@9FB8.4````#[9"!V:)@Y8````/MD((9HF#F`````^V0@F(@YH````/MD($
-M9HF#D`````^V0@5FB8.2````#[9""V:)@YP```#IL_[__V9FD$F+=2A(@\84
-MZ17___^`B[$````$2(U"$$B)@Z````#K@8"+L0````1(C4(42(F#H````.DB
-M_O__@(NQ`````DF+13!(@\`02(F#H````.E/____@(NQ`````DF+13!(@\`4
-M2(F#H````.GL_?__28M]$$F-=5A!QT50_?___TG'15@`````38EM8$G'16@`
-M````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HZ0````!)BWT028UU6$''15#_
-M____2<=%6`````!-B6U@2<=%:`````#H`````$B)WTB+;"002(M<)`A,BV0D
-M&$R+;"0@2(/$*.D`````9F9FD&9F9I!32(M'*$B)^XLXZ`````!(B=Y(B<=;
-MZ;7\__]F9I!FD%-(BT<H2(G[BSCH`````$B)WDB)QUOIE?S__V9FD&:02(/L
-M*$B)7"0(2(EL)!!,B6PD($R)9"0828G]3(MG*$&+/"3H`````(MP-$B+.$B)
-MQ>@`````2(7`2(G##X3*````3(EH6$B):%#&@+`````"00^V1"0$/`$/A)$`
-M```\`@^$F0```$$/ME0D!TB-NY@```!)C70D".@`````00^V1"0'B(.0````
-M08M$)!B)@Y0```!!#[9%((/H"(3`B(.1````=`])BT4P2(/`"$B)@Z@```!(
-MQX/``````````$C'@\@`````````2(G?2(ML)!!(BUPD"$R+9"083(ML)"!(
-M@\0HZ0````!F9F:0@(NQ`````NEK____9F9FD("+L0````3I6____TF+?1!)
-MC7580<=%4/W___])QT58`````$V);6!)QT5H`````$B+7"0(2(ML)!!,BV0D
-M&$R+;"0@2(/$*.D`````9F:055-(B?M(@^Q82(M'*$B+;S!(B>*+<`2+..@2
-MJ?__A<!T+\=#4/____](BWL02(US6$C'0U@`````2(E;8$C'0V@`````Z```
-M``!(@\186UW#2(L$)$B)10!(BT0D"$B)10CKQ69F9I!F9F:09F9FD$%4@#T`
-M`````4F)_%53QT=0`````$B+;RA(BU\P#X8.`0``2,?&`````$B)[^@.IO__
-MA<`/A(8```!(Q\8`````2(GOZ/>E__^%P`^%OP```$B+10!(B0-(BT4(2(E#
-M"$B+11!(B4,02(M%&,9#1`#&0T$`QD-``DB)0Q@/MD5%B$-%#[8%`````(A#
-M(&9FD$G'1"18`````$V)9"1@28UT)%A)QT0D:`````!)BWPD$%M=05SI````
-M`&9FD&9FD$B+10!(B0-(BT4(2(E#"$B+11!(B4,02(M%&,9#1`#&0T$`QD-`
-M`4B)0Q@/MD5%B$-%BP4`````!9`!``"-4`>%P`](PL'X`XA#(.N#9F:02,?&
-M`````$B)[^@AI?__A<!T9D''1"10_____^E?____2,?&`````$B)[^@`I?__
-MA<`/A=O^__](BT4`2(D#2(M%"$B)0PA(BT402(E#$$B+11C&0T0`QD-!`,9#
-M0`)(B4,8#[9%18A#10^V!0````"(0R#I!____TB+10!(B0-(BT4(2(E#"$B+
-M11!(B4,02(M%&,9#1`#&0T$`QD-``4B)0Q@/MD5%B$-%#[8%`````(A#(.G&
-M_O__9F:09F:005=)B?=!5D%505152(G]4TB!["@"``"(5"0'#[9&#\9$)!`!
-MA,!X#\9$)!``@'\0!@^$;`(``$B-1"0@9F9FD$B-E"0@`@``Q@``2(/``4@Y
-MT'7L00^V1PL/MI5@`@``B$5(00^V1PZ(145!#[9/#K@!````T^!FB45&B="#
-MR`2(A6`"``!!]D</`P^$F@$``(G02,>%:`(```````"#R`6(A6`"``!(BT4(
-M@'@+``^%E@$``$F+1Q`/ME5$2<?&_____TB)A7`"``!)BT<8A=)(B85X`@``
-M?EA%,>3K$0^V541!C40D`4F#Q`$YPGY"2HM<Y6!(BT,H2(EK&$DYQDP/1_"`
-M>Q`$==6`?"0'`$B+0SA(B40D"'5D@'PD$`!U9`^V541!C40D`4F#Q`$YPG^^
-M@'T0!P^$.@$``$B+30B`>0D`#X7Q````#[9!"BG"2&/"3`^O\$R)=2A!#[9'
-M#X/@','X`HB%@0,``$B!Q"@"``!;74%<05U!7D%?PX!\)!``='%(BT-(2(M\
-M)`A(C4PD($&X`0```+H!````2(MP".@`````A<`/A3#___^`O"0>`@``J@^$
-M#@$``#'`@'PD(%(/A.<```"%P`^$#?___TB+0TA(BWPD"$B-3"0@13'`N@$`
-M``!(BW`(Z`````#IZ?[__T4Q[4B+0TA,B>Y(BWPD"$B-3"0@13'`N@$```!)
-M@\4!2`-P".@`````28/]`@^$MO[__^O.2,>%:`(``/_____I>O[__P^W14;W
-MV$B822'&Z?_^__^#R@>`?1`*B)5@`@``#X57_O__#[9-1+@!````@^D!2-/@
-M2(E%4.D__O__@'U$``^$V_[__S')2(M$S6"-40%(@\$!2(M`*$@!12@/MD5$
-M.=!_Y.FX_O__T>B#X`&(1"00Z8;]__^`?"0A10^%#O___\9$)"!%QD0D(5+I
-M!____X"\)!\"``!5#X7D_O__L`'&A"0>`@``5<:$)!\"``"JZ<_^__]!53'V
-M051)B?Q54TB![(@```!(BT<H2(MO,(LXZ*^A__](A<!(B<,/A%(!```QP)#&
-M!"@`2(/``4B#^%AU\DF)Y4B)X$B-E"2`````Q@``2(/``4@YT'7L2(M#"$B+
-M>Q!(B>;_4#@/MD0D%DF-53Q(C4T$B$4##[9$)!2(10`/MD0D%8A%`4B+1"0\
-M2(E%!$B+0@A(B4$(2(M"$$B)01!(BT(82(E!&(M"($F-51B)02!(BT0D&$B-
-M32A(B44H2(M""$B)00A(BT(02(E!$$B+0AA(B4$8BT(@B4$@#[8$)(A%4`^V
-M1"0!B$51#[9$)`*(15(/MD0D`XA%4TB+0QB)14R`>V@`=7$/MD0D%XA%`DB+
-M&TB%VW48ZRMF9I!F9I`/MD0D%P!%`DB+&TB%VW052(M#"$B+>Q!(B>;_4#B`
-M?"03`'3;28M\)!!)C70D6$G'1"18`````$V)9"1@2<=$)&@`````Z`````!(
-M@<2(````6UU!7$%=PX!-`P3KB4''1"10_____^N[9F:09F:0055)B?TQ]D%4
-M55-(@>R(````2(M'*$B+;S"+..@?H/__2(7`2(G##X07`0``,<"0Q@0H`$B#
-MP`%(@_A,=?))B>1(B>!(C90D@````,8``$B#P`%(.=!U[$B+0PA(BWL02(GF
-M_U`X#[9$)!9)C50D/$B-302(10,/MD0D%(A%``^V1"05B$4!28M$)#Q(B44$
-M2(M""$B)00A(BT(02(E!$$B+0AA(B4$8BT(@28U4)!B)02!)BT0D&$B-32A(
-MB44H2(M""$B)00A(BT(02(E!$$B+0AA(B4$8BT(@B4$@#[9$)!>(10)(BQM(
-MA=MU$NLE#[9$)!<`10)(BQM(A=MT%4B+0PA(BWL02(GF_U`X@'PD$P!TVTF+
-M?1!)C7582<=%6`````!-B6U@2<=%:`````#H`````$B!Q(@```!;74%<05W#
-M0<=%4/_____KQV:02(/L&$R)9"0(2(D<)$F)_$R);"002(M?"$B+5Q"+0S!,
-MBRN)0C"`HV$"``#SQT,P_____X"B80(``/.+<C!)BWT(Z`````"+<S1,B>_H
-M`````$B)6%#&@+`````$2(G'3(E@6$C'@,@`````````2(L<)$R+9"0(3(ML
-M)!!(@\08Z0````!F9F:09F:09F:04TB+1RA(B?N+..@`````2(G'Z`````!(
-MQT-8`````$B)6V!(C7-82,=#:`````!(BWL06^D`````9F9FD&9FD%-(BW\(
-M2(L?Z`````!(BX/@`0``2,=`6`````!(B4!@2(UP6$C'0&@`````2(MX$%OI
-M`````&9F9I!F9I!F9I!3@W]0_4B+7T`/A/4```#V@V$"```(QH-[`P```'1I
-MBT=0@_C]#X3;`0``A<`/A>`!``!(BX.``@``2(N0H`````^W@*@```"!XO__
-M#P!(.<(/@XD```!(QX/H`@```````$B)F_`"``!(QX/@`@```````$B+`TB-
-ML^`"``!;2(MX".D`````#[:+8`(``/;!$`^$B````(M'4(/X_0^$0@$``(7`
-M#X5#`0``2(M3"`^V0T0/ME(**=!(F$@/KX-H`@``2#M#*`^#T0$``/:#80(`
-M``@/A5C___]F9I!FD/:#8`(``%`/A8D```!(QX/H`@```````$B)F_`"``#I
-M</___P^V@WL#```\`@^/_/[__X/``8B#>P,``.O/9I#VP2!U;/;!0`^$M@``
-M`/;!`0^$CP$``$2+1U!%A<!FD`^%0@$``$B+4P@/MD-$#[92"BG02)A(#Z^#
-M:`(``$@[0R@/@GC___](B=^^"0```%OIZL/__TB+@V@"```E__\_`$B#^'\/
-MAV'____IQO[__T2+3U"X"P```$6%R74IA,FP"G@C2(M3"`^V0T0/ME(**=!(
-MF$@/KX-H`@``2#M#*')WN`P```"#X5](B=Z)QXB+8`(``.@`````]H-@`@``
-M"'5O6\.`/0``````=7*#X>](B=Z_"````(B+8`(``%OI`````(`]```````/
-MA9H```!(BX.``@``@*-A`@``]TB)WK\4````2(M`$("@80(``/=;Z0````!(
-MBX,H`P``@#@`#X26_O__@^'?B(M@`@``2(G?O@$```!;Z?_"___'1U``````
-M2(G>OQP```#H``````^W@W0#``!(`8-H`@``Z23^__^#X;](B=Z_#P```(B+
-M8`(``%OI`````$B)W[X#````6^FSPO__QT=0`````$B)WK\<````Z`````#I
-M"/[__X/AOTB)WK\.````B(M@`@``6^D`````9F:02(V&:`,``/:&80(```A(
-MB;X(`P``QX88`P```````$C'AC`#````````2(F&(`,``$B-AGH#``!(B;8X
-M`P``2,>&0`,```````!(B88H`P``BX;H`P``B89H`P``=#?'AA`#```J_P``
-MQX84`P``!````(N&W`(``#'2@\`!@_AE#TS0B9;<`@``2('&^`(``.D`````
-M#[:.8`(``/;!<`^$J@```(G(@^"@/*`/A)\```!,BT8(#[9&1$$/ME`**=!(
-MF$@/KX9H`@``2#M&*`^#?````/;!$+@C_P``=0^#X2"`^0$9P/?0!27_``")
-MAA`#``!(BY8@`P``2(N&:`(``$B)0@1!@'@)`'1:#[=&1DB+EB`#``!FB4(,
-M]H9@`@``(,>&%`,```X````/A#____](BX8H`P``Q@``QX88`P```0```.DF
-M____9F:0\\-(C;[X`@``QX9(`P```````.FX^___2(M6*$@KEF@"``"Y@```
-M`$B+AB`#``!(@?J`````2`]'T6:)4`SKC4B+1T!(QX#H`@```````$B)@/`"
-M``!(C;#@`@``2(L`2(MX".D`````9F9FD&9FD$B#[!A(B6PD$$B)7"0(2(G]
-M2(M?&$B%VT@/1-\/MH-A`@``J`1T?J@(#X63````2(N3@`(``$B%T@^$@P``
-M`$B+0@A(A<`/A'8```!(@WH0`'1O@(AA`@``"$B-L^`"``!(BT(0@(AA`@``
-M"$B+`TC'@^@"````````2(F;\`(``$B+>`CH`````$B)WDB+;"002(M<)`B_
-M$@```$B#Q!CI``````^VEV`"``#VPA!U$4B%VW0$J`AU"/;"8&9FD'0/2(M<
-M)`A(BVPD$$B#Q!C#2(M%`(/B]TC'A>@"````````@\H02(FM\`(``$B-M>`"
-M``"(E6`"``!(BW@(Z`````!(B>Y(BUPD"$B+;"00OP0```!(@\08Z0````!F
-MD$%5051)B?Q54TB#[`A(BT<HBU@$BSCH`````(/[#DB)Q78]0<=$)%#^____
-M2<=$)%@`````38ED)&!)C70D6$G'1"1H`````$F+?"002(/$"%M=05Q!7>D`
-M````9F9FD(G8_R3%`````&9F9I!F9I!(B<5(BT482(7`=?2`?1`%#X3N!0``
-M@*5@`@``OTB)[K\.````Z`````!$BU4P1872#XA.!@``2(M-&+H!````Z=@#
-M``!(BT482(7`=`WV@&$"```,#X58____9O>%8`(``'`,#X5)____]H6``P``
-M`0^$//___X!]$`4/A1H&``"`?40`#X1C!@``13'M9I#K%`^V141!C54!28/%
-M`3G0#XY(!@``2HM<[6!(A=MTXH![$`1VW/:#8`(``!!UTTB+>UCH`````$B+
-M4P@/ME(*.=`/C=O^__\/MH-@`@``2,>#Z`(```````!(C;/@`@``2(F;\`(`
-M`(/@]X/($(B#8`(``$B+`TB+>`CH`````$B)WK\$````Z`````#I</___X!]
-M$`4/A(D$``"`I6`"``#G2(GNOP4```#H`````$B+31BZ`0```.G/`@``]H5@
-M`@``$`^$6/[___:%@`,```$/A$O^__^`I6`"``#E2(M%6$B)[DC'A6@"``#_
-M____OP8```!(B450Z`````!(BTT8@*5@`@``_DB%R714@'E$`'1.,?9(BT3Q
-M8$B%P'0O]H"``P```70F@'@0!'8@#[:08`(```^V@6`"``"#X@&#X/X)T*@!
-MB(%@`@``=0\/MD%$C58!2(/&`3G0?[A(BTT82(-]6`$9TH/"`ND;`@``2(M%
-M&$B%P'0-]H!A`@``#`^%F_W__V;WA6`"``!P#`^%C/W___:%@`,```$/A'_]
-M__^`?1`%#X78!```@'U$``^$=/W__T4Q[69FD&:0ZQ0/MD5$08U5`4F#Q0$Y
-MP@^-5OW__TJ+7.U@2(7;=.*`>Q`$=MSV@V`"```@==-(BWU02`M]6.@`````
-M2(M5"`^V4@HYT`^-%_W__TB+`X"+8`(``"!(C;/@`@``2,>#:`(```````!(
-MQX/H`@```````$B)F_`"``!(BW@(Z`````!(B=Z_"0```.@`````Z6W___^`
-MI6`"``#?2(GNOPH```#H`````.F^_/__@*5@`@``W^FR_/__]H6``P```0^$
-MG/S__TB#?5@`#X61_/__#[>%8`(``&8E<0QF@^@!#X5\_/__@'T0!0^%/`0`
-M`(!]1`!T-44Q[4J+7.U@2(7;=!B`>Q`$=A(/MH-@`@``@^!!+`$/A%L$```/
-MMD5$08U5`4F#Q0$YT'_.@*5@`@``]^DT_/__@*5@`@``M$C'A6@"``#_____
-M2(GN2,=%4`````"_$````.@`````2(M=&$B%VP^$E0(```^V0T2%P`^.C`(`
-M`(/H`3'V,=)(C4@!2(M$TV!(A<!T(_:`@`,```%T&H!X$`1V%/:`8`(```&X
-M`0````]%\&9FD&:02(/"`4@YRG7*A?8/A$,"``!(BTL82(G=N@$```"#^@,/
-ME<"$P`^$/@$``&9FD&:02(7)#X0P`0``2(G-2(M)&.D<`0``@*5@`@``WTB)
-M[K\+````Z`````#I7OO__V;WA6`"``!P"$B+A8`"```/A3_[__](A<`/A#;[
-M__^`N*L`````#X4I^___2(M0"$B+0!#V@H`#```!#X04^___]H"``P```0^$
-M!_O__X"B80(``.](C;7@`@``@*!A`@``[X"*80(```B`B&$"```(2(M%`$C'
-MA>@"````````2(FM\`(``$B+>`CH`````$B)[K\2````Z`````#IO/K__P^W
-MA6`"``!(BXV``@``9B5P"&8]``@/A9?Z__](A<D/A([Z__](BT$(2(M1$$B)
-M[K\3````@*!A`@``]X"B80(``/?H`````$B+31BZ`0```.G'_O__2(M-&+H#
-M````,<"$P`^%Q_[__X"-8`(```2#^@(/A.\```!(BX6``@``2(7`#X3L````
-M2(MX"$B+6!!(A?]T!>@`````2(7;#X08^O__2(G?Z`````!F9F:0Z0?Z__\Q
-MVX!]1`!U&V9FD.ER^O__#[9%1(U3`4B#PP$YT`^.7_K__TB+=-U@2(7V=..`
-M?A`$=MWVAF`"```0=-2`IF`"``#GOP4```#H`````.O!@'U$``^$'/K__S';
-MZQ,/MD5$C5,!2(/#`3G0#XX%^O__2(MTW6!(A?9TXX!^$`1VW?:&8`(``$!T
-MU("F8`(``+^_#@```.@`````Z\%(B>N`HV`"``#^2(G?Z`````#IJ?W__TB)
-M[^@`````Z4?Y__](B>_H`````&9FD.DW^?__2(GOZ`````!(BTT8N@$```#I
-M@OW__TB+?5CH`````$B+50@/ME(*.=`/C?_X__](BT4`@(U@`@``$$B-M>`"
-M``!(QX7H`@```````$B)K?`"``!(BW@(Z`````!(B>Z_!````.@`````@*5@
-M`@``]TB#?5@`#X0W^?__Z`````!(BTT8N@$```")13SI!_W__TB+?5!("WU8
-MZ`````!(BU4(#[92"CG0#XV`^/__2(M%`("-8`(``"!(C;7@`@``2,>%:`(`
-M``````!(QX7H`@```````$B)K?`"``!(BW@(Z`````!(B>Z_"0```.@`````
-MZ3_X__](BT4`@(U@`@``0$B-M>`"``!(QX5H`@```````$C'A>@"````````
-M2(FM\`(``$B+>`CH`````$B)[K\-````Z`````#IM?O__P^V@V`"``!(QX-H
-M`@```````$B-L^`"``!(QX/H`@```````$B)F_`"``"#R$"#X/>(@V`"``!(
-MBP-(BW@(Z`````!(B=Z_#0```.@`````Z5#[__]F9F:054B)_5-(@^P(]H>`
-M`P```74C#[:'80(``(/@!#P!&=N!XP#X__^!PP$(``")V$B#Q`A;7<,/MI=@
-M`@``]L("#X0S`0``2(M_6+L"````B=B`S!#VP@$/1=B)V(/(!/;"$`]%V(G8
-M@,P!]L(@#T78B=B`S`*#XD`/1=A(A?\/A2("```/MI6``P``B=A$#[951(/(
-M$/;"!$4/MLH/1=B)V(/(0(/B`@^VE6$"```/1=B)V`R`]H5@`@``"`]%V(G8
-M@,P(]L($#T78B=B`S`2#X@@/1=A%A<D/CK8```!!C4'_,?9,C4`!ZV!(BWI8
-M2(GX2/?02(5"4'0#@\L"B=B`S!#VP0$/1=B)V(/(!/;!$`]%V(G8@,P!]L$@
-M#T78B=B`S`+VP4`/1=B)V(/("$B%_P]%V(G8#("#X0@/1=AF9I!(@\8!3#G&
-M=$I(BU3U8$B%TG3M]H*``P```73D@'H0!';>#[:*8`(``/;!`@^$=____TB+
-M>ECK@4B+?U@QVTB)^$CWT$B%15`/A,#^___IMO[___;#`G01]L<09F:09I`/
-MA.H```"#X_U%A<D/CA(!``!(BU5@2(72#X1M_O__]H*``P```0^$8/[__S'_
-M@'H0!$$/ML)$C4#_#X:>````#[9R1(7V?FA(BT)@2(7`#X0W_O__]H"``P``
-M`0^$*O[__TB+0$A(@W@(``^%&_[__S')ZRU(BT)H2(7`#X0*_O__]H"``P``
-M`0^$_?W__TB+0$A(@\((2(-X"``/A>K]__^#P0$YSG7,9F9FD&9FD$PYQW1O
-M2(M4_6A(A=(/A,G]__](@\<!]H*``P```0^$N/W__X!Z$`0/AV+___](BT)(
-M2(-X"`!TQ^F>_?__9I")V"4((```@_@(#X4)____Z0'____H`````$B+50B#
-MRPB)V8#-(`^V4@HYT`],V>F__?__@<L```!`Z5W]__^0059!54%428G\55-(
-MBT<H2(M?$$2+*$2)[^@`````2(MK&$B#PQA)B<9(.=UU"^M.2(MM`$@YW71%
-M2(.]B/S__P!(C;UP_/__=>9%A>UU!O9%\`)U5TDY_G1F]H>``P```G3-@*>`
-M`P``_8!_$`%T1N@`````2(MM`$@YW76[2<=$)%@`````38ED)&!)C70D6$G'
-M1"1H`````$F+?"006UU!7$%=05[I`````(!E\/V`?Q`!=;KH`````.EP____
-M]H>``P```@^%8____X"/@`,```+KE&9F9I!F9I!F9I!(@^QH2(E<)$A(B6PD
-M4$B)^TR)9"183(EL)&!(BV\HBWT`A?]U2DB+>Q#HL9C__\=#4/S___](BWL0
-M2(US6$C'0U@`````2(E;8$C'0V@`````Z`````!(BUPD2$B+;"103(MD)%A,
-MBVPD8$B#Q&C#Z`````!)B<2+101,C6T$J`%U;:@"#X6]````J`0/A1T!``"H
-M"`^%?`$``*@09F:0#X7:`0``J$`/A3,"``"H(`^%;P(``$'V1"1D$&9F9I`/
-MA'#___])BT0D:$F+O"2`````2(GF_U!X#[9$)`Y,B>=!B$0D8N@`````Z4;_
-M___&1"0P`$$/MD4$2(UT)#"(1"0X28M$)&A)B[PD@````/^0P````(7`B4-0
-M=2!!#[9$)&2#R(!!B$0D9$$/ME4$@\@008A$)&1!B%0D8XM%!*@"#X1#____
-MQD0D,`1!#[9%!4B-="0PQD0D.0"(1"0X28M$)&A)B[PD@````/^0P````(7`
-MB4-0=2E!#[94)&6#RA!!B%0D94&`?04`#Y7`08!,)&00@^+?P>`%"<)!B%0D
-M94&+10"H!`^$Y/[__Y#&1"0P!4$/MD4&2(UT)##&1"0Y`(A$)#A)BT0D:$F+
-MO"2`````_Y#`````A<")0U!U*4$/ME0D98/*0$&(5"1E08!]!@`/E<!!@$PD
-M9!"#XG_!X`<)PD&(5"1E08M%`*@(#X2$_O__QD0D,`-!#[9%!TB-="0PB$0D
-M.$F+1"1H28N\)(````#_D,````"%P(E#4'4I00^V5"1E@\H$08A4)&5!@'T'
-M``^5P$&`3"1D$(/B]\'@`PG"08A4)&5!BT4`J!`/A"W^__]F9F:09F:0QD0D
-M,`)!#[9%"$B-="0PB$0D.$F+1"1H28N\)(````#_D,````"%P(E#4'4H00^V
-M5"1E@\H!08A4)&5!@'T(``^5P$&`3"1D$(/B_0'`"<)!B%0D94&+10"H0`^$
-MS?W__T$/MG4*,<!(Q\<`````Z`````#'0U``````08!]"@!!#[9$)&8/E<)!
-M@$PD9!"#X/X)T$&(1"1F08M%`*@@#X21_?__QD0D,`=!#[9%"4B-="0PB$0D
-M.$F+1"1H28N\)(````#_D,````")0U!!]D0D9!`/A-S\___I9_W__Y!(@^PX
-M2(E<)!A(B6PD($B)^TR)9"0H3(EL)#!(BV\HBWT`A?]U2DB+>Q#H497__\=#
+M74%<05U!7D%?PTB+0PA(BX`8`0``2(7`=+A(BWL03(GZB>[_T(7`=:E!#[9'
+M`CS_=`=$`>A!B$<"0<=$)%``````ZXYFD$%7,?9!5D%5051)B?Q54TB![(@`
+M``!(BT<H3(M_,(LXBV@$Z`BX__](A<!(B<-!QT0D4/____]T0T4Q[69F9I!(
+MBT,(2(N`"`$``$B%P'0/2(M[$/_0.<5\6BG%00'%2(L;2(7;=!5(BT,(2(M[
+M$$B)YO]0.(!\)!,`=,1)BWPD$$F-="182<=$)%@`````38ED)&!)QT0D:```
+M``#H`````$B!Q(@```!;74%<05U!7D%?PTB+0PA(BX`0`0``2(7`=+A(BWL0
+M3(GZB>[_T(7`=:E!#[9'`CS_=`=$`>A!B$<"0<=$)%``````ZXYFD$%5,?9!
+M5%5(B?U32('LB````$B+1RB+..@CM___,=)(A<!(B<-T0D4QY&9FD&9FD$B+
+M0PA(BX`(`0``2(7`=`E(BWL0_]!!`<1(BQM(A=MT%4B+0PA(BWL02(GF_U`X
+M@'PD$P!TRD2)XDB+13!(BWT02(UU6$C'15@`````2(EM8$C'16@`````B1#H
+M`````$B!Q(@```!;74%<05W#9I!32(M'*$B)^TB+5S"+<`2+..BZN/__A<!T
+M!\=#4/____](QT-8`````$B)6V!(C7-82,=#:`````!(BWL06^D`````9F9F
+MD&9FD&9FD&9FD%5(B?TQ]E-(@>R(````2(M'*$B+7S"+..@SMO__2(7`2(G"
+M='\QP,8$&`!(@\`!2(/X1'7R2(G@2(V,)(````#&``!(@\`!2#G(=>Q(BT((
+M2(MZ$$B)YO]0.`^V1"1QB`,/MD0D<HA#`0^V1"1SB$,"#[9$)'2(0P-(BWT0
+M2(UU6$C'15@`````2(EM8$C'16@`````Z`````!(@<2(````6UW#QT50____
+M_^O,9F:02(/L&$B)7"0(3(ED)!!(B?M,BV<PZ%:W__](BWL02(US6$C'0U@`
+M````08D$)$B)6V!(QT-H`````$B+7"0(3(MD)!!(@\08Z0````!F9I!52,?&
+M`````%-(B?M(@^P(2(MO*$B)[^CDM/__A<!U,0^V12"(!0````!(QT-8````
+M`$B)6V!(C7-82,=#:`````!(BWL02(/$"%M=Z0````!(Q\8`````2(GOZ*"T
+M__^%P'43#[9%((T$Q7#^__^)!0````#KLTC'Q@````!(B>_H>K3__X7`=$I(
+MQ\8`````2(GOZ&>T__^%P'5&2(M[$$C'AR`"````````2(F?*`(``$C'AS`"
+M````````2(/$"%M=2(VW(`(``$B#QTCI``````^V12"(!0````#I1____TC'
+MQ@````!(B>_H#K3__X7`=1%(BWL02,>'(`(```````#KI<=#4/_____I%___
+M_V9F9I!F9I!F9I!F9I!(BT<P2,='6`````!(C7=82(E_8$C'1V@`````2(M_
+M$,<````!`ND`````9F:09I!!5D%505152(G]4TB#[$!(BT4H2(M_$,9$)#`'
+M@'@@`4R-9Q@9P(/``HA$)#A(BU\83#GC="5,C70D,&9FD&:0]D/P`70)@+N`
+M_/__`70]2(L;3#GC=>E(BWT02(UU6,=%4`````!(QT58`````$B);6!(QT5H
+M`````.@`````2(/$0%M=05Q!74%>PTB+@^#\__](B[OX_/__2(GF_U!X#[9$
+M)!,Z1"0X=*1(BX/@_/__2(N[^/S__TR)]O^0P````.N+9F9FD&9F9I!F9F:0
+M2(/L*$B)'"1,B60D$$B)^TB);"0(3(EL)!A,B70D($B+;UA,BS=(BT4H1(LH
+M1(GOZ`````"`N[(````!28G$=!@/MH.S````@\`!/`*(@[,````/AI<```!(
+MBW-X28V^\````.@`````2(G?Z`````"+11@]*?\``'1E/3G_``!T7DV%Y'0/
+M28L$)$PY\&:0#X3`````2(M]$$B-=5C'15#^____2,=%6`````!(B6U@2,=%
+M:`````!(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HZ0````!F9I!F9I!(
+MBT4P1(DHZYEF9F:09F:02(M#>,:#L@````!(B=](QT`0`````$B+0WA(C5`8
+M2,=`*`````!(QT`P`````$C'0#@`````QT!``````$B)4!A(B5`@2(L<)$B+
+M;"0(3(MD)!!,BVPD&$R+="0@2(/$*.D`````2(VP(`(``$B->$A(QX`@`@``
+M`````$B)J"@"``!(QX`P`@```````$B+'"1(BVPD"$R+9"003(ML)!A,BW0D
+M($B#Q"CI`````)!(BS=(@<;H`0``Z0````"02(/L"$B+1RB+..@`````2(/$
+M"$B)Q^O89F9FD&9F9I!(@^P(2(M'*(LXZ`````!(@\0(2(G'Z[AF9F:09F9F
+MD$B#[`A(BT<H@'@$`8LX=`5(@\0(P^@`````2(/$"$B)Q^N-9F9FD&9FD&9F
+MD&9FD$%528G]05154TB#[`A(BT<HBQ!F]\(`_W5$08G408'D_P```'XX,>V[
+M!````.L%D$F+12B+/!CH`````$B%P'01@'@0!'8+2(.X@`(```"0=!>#Q0%(
+M@\,$1#GE==)(@\0(6UU!7$%=PTB)Q^@/____Z]]F9F:09F:09F:09F:02(/L
+M"$B+1RB+..@`````2(/$"$B)Q^GE_O__9F:09I!(@^P82(EL)!!(B5PD"$B+
+M1RB+6`2+..@`````@_L-2(G%=#2#^P%T&8/[!'04@_L'=`](BUPD"$B+;"00
+M2(/$&,-(B>](BUPD"$B+;"002(/$&.F(_O__2(7`=-9(BX"``@``2(7`=,I(
+MBW@(2(7_=`SH:?[__TB+A8`"``!(BW@02(7_=;[KJF9F9I!F9I!(@^P83(ED
+M)!!(B5PD"$B+1RB+6`2+..@`````B=])B<3H`````$R)YTB)P^@?_O__2(G?
+M3(MD)!!(BUPD"$B#Q!CI"?[__V9FD&9FD&9FD$B#[`A(BT<HBSCH`````$B#
+MQ`A(B<?IY?W__V9FD&:02(/L"$B+1RB+..@`````2(/$"$B)Q^G%_?__9F:0
+M9I!32(M'*(LXZ`````!(A<!(B<-T,$B+@(`"``!(A<!T)$B+>`A(A?]T#.B2
+M_?__2(N#@`(``$B+>!!(A?]T$EOI?/W__TB)WUOI<_W__V9FD%O#9F9FD&9F
+M9I!F9I!F9I!54TB#[`A(BV\H2(/%!(!]#0!T(#';B=B#PP&+?(5\Z`````!(
+MB<?H-/W__P^V10TYV'?B2(/$"%M=PV9FD&:055-(@^P(2(MO*$B#Q02`?0$`
+M="`QVXG8@\,!BWR%<.@`````2(G'Z/3\__\/MD4!.=AWXDB#Q`A;7<-F9I!F
+MD%532(/L"$B+;RB`?0T`="`QVXG8@\,!BWR%?.@`````2(G'Z+C\__\/MD4-
+M.=AWXDB#Q`A;7<-F9I!F9I!F9I!54TB#[`A(BV\H@'T!`'0@,=N)V(/#`8M\
+MA7#H`````$B)Q^AX_/__#[9%`3G8=^)(@\0(6UW#9F:09F:09F:055-(@^P(
+M2(MO*(!]`0!T(#';B=B#PP&+?(5HZ`````!(B<?H./S__P^V10$YV'?B2(/$
+M"%M=PV9FD&9FD&9FD%532(/L"$B+;RB+?0"%_W0=,=N#PP&)V(M\A0#H````
+M`$B)Q^CW^___.5T`=^5(@\0(6UW#9F9FD&9F9I!F9I!52(G]2,?&`````%-(
+M@^P(2(M_*.@'K?__A<!U.4B+11!(BU@82(/`&$@YPW0H9I#V0_`!2(V[</S_
+M_W0)@+N`_/__`7072(M%$$B+&TB#P!A(.=AUVDB#Q`A;7</H?OO__^OB9F9F
+MD&9F9I!F9F:005=!5D%505152(G]4TB![)@```!,BV\03(MW*$F+71A-C648
+M3#GC="I,C;PD@````/9#\`%(C;MP_/__=`V`NX#\__\!#X2V````2(L;3#GC
+M==Y!#[9&((@%`````$F+71!(A=MU$>M>9F9FD&9FD$B+&TB%VW1/2(M#"$B+
+M>Q!(B>;_4#CV1"01$'3C28V=.`$``$R)[TB)WN@`````0<>%.`$```"'DP-)
+MQX5(`0```````$B)WDV)K5`!``!,B>_H`````$B+?1!(C758QT50`````$C'
+M15@`````2(EM8$C'16@`````Z`````!(@<28````6UU!7$%=05Y!7\/H````
+M`,:$)(`````(00^V1B!,B?Z(A"2(````2(N#X/S__TB+N_C\____D,````#I
+M%?___V9F9I!F9I!F9I!(@^PH2(E<)`A,B60D&$F)]$R);"0@2(EL)!!)B?V+
+M=S1(BS_H`````$B%P$B)PP^$;`(``#'MQH"P`````T&!?"080O\``$R):%!`
+M#Y3%A>T/A;P```!)BU0D*#'`@'H*]`^4P(7`#X6\````A>T/A$\!```/MD(2
+M/`$/A`0"```\`@^$R0$```^V0@^(@YL````/MT((9HF#E`````^W0@IFB8.6
+M````#[="#&:)@Y@````/MD(.B(.:````#[="!&:)@Y`````/MT(&9HF#D@``
+M``^W0A!FB8.<````3(EC6$C'@\@`````````0<9%9@%(B=](BVPD$$B+7"0(
+M3(MD)!A,BVPD($B#Q"CI`````$F+5"0H,<"`>@_T#Y3`A<`/A$3___])BWT`
+M2(''D````.@`````2(7`28G%#X2C`0``A>T/A>,```!)BW0D*$B#QA!,B>^Z
+M``(``.@`````@(NQ````!$R)JZ````!)C70D6,:#FP```/1FQX.<`````0!)
+MBWPD$$R):UA(QX/(`````````$''1"10`````$G'1"18`````$V)9"1@2<=$
+M)&@`````Z`````#I+____P^V0@P\`0^$F0```#P"=&H/MD(*B(.;````#[9"
+M!F:)@Y0````/MD('9HF#E@````^V0@AFB8.8````#[9""8B#F@````^V0@1F
+MB8.0````#[9"!6:)@Y(````/MD(+9HF#G````.FP_O__D$F+="0H2(/&%.D8
+M____@(NQ````!$B-0A!(B8.@````ZX*`B[$````$2(U"%$B)@Z````#I(/[_
+M_X"+L0````))BT0D,$B#P!!(B8.@````Z4____^`B[$````"28M$)#!(@\`4
+M2(F#H````.GH_?__28M\)!!)C70D6$''1"10_?___TG'1"18`````$V)9"1@
+M2<=$)&@`````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HZ0````!)BWPD$$F-
+M="180<=$)%#_____2<=$)%@`````38ED)&!)QT0D:`````#H`````$B)WTB+
+M;"002(M<)`A,BV0D&$R+;"0@2(/$*.D`````9F:09F:09F:04TB+1RA(B?N+
+M..@`````2(G>2(G'6^FE_/__9F:09I!32(M'*$B)^XLXZ`````!(B=Y(B<=;
+MZ87\__]F9I!FD$B#["A(B5PD"$B);"003(EL)"!,B60D&$F)_4R+9RA!BSPD
+MZ`````"+<#1(BSA(B<7H`````$B%P$B)PP^$R@```$R):%A(B6A0QH"P````
+M`D$/MD0D!#P!#X21````/`(/A)D```!!#[94)`=(C;N8````28UT)`CH````
+M`$$/MD0D!XB#D````$&+1"08B8.4````00^V12"#Z`B$P(B#D0```'0/28M%
+M,$B#P`A(B8.H````2,>#P`````````!(QX/(`````````$B)WTB+;"002(M<
+M)`A,BV0D&$R+;"0@2(/$*.D`````9F9FD("+L0````+I:____V9F9I"`B[$`
+M```$Z5O___])BWT028UU6$''15#]____2<=%6`````!-B6U@2<=%:`````!(
+MBUPD"$B+;"003(MD)!A,BVPD($B#Q"CI`````&9FD%532(G[2(/L6$B+1RA(
+MBV\P2(GBBW`$BSCH`JG__X7`="_'0U#_____2(M[$$B-<UA(QT-8`````$B)
+M6V!(QT-H`````.@`````2(/$6%M=PTB+!"1(B44`2(M$)`A(B44(Z\5F9F:0
+M9F9FD&9F9I!!5(`]``````%)B?Q54\='4`````!(BV\H2(M?,`^&#@$``$C'
+MQ@````!(B>_H_J7__X7`#X2&````2,?&`````$B)[^CGI?__A<`/A;\```!(
+MBT4`2(D#2(M%"$B)0PA(BT402(E#$$B+11C&0T0`QD-!`,9#0`)(B4,8#[9%
+M18A#10^V!0````"(0R!F9I!)QT0D6`````!-B60D8$F-="182<=$)&@`````
+M28M\)!!;74%<Z0````!F9I!F9I!(BT4`2(D#2(M%"$B)0PA(BT402(E#$$B+
+M11C&0T0`QD-!`,9#0`%(B4,8#[9%18A#18L%``````60`0``C5`'A<`/2,+!
+M^`.(0R#K@V9FD$C'Q@````!(B>_H$:7__X7`=&9!QT0D4/_____I7____TC'
+MQ@````!(B>_H\*3__X7`#X7;_O__2(M%`$B)`TB+10A(B4,(2(M%$$B)0Q!(
+MBT48QD-$`,9#00#&0T`"2(E#&`^V146(0T4/M@4`````B$,@Z0?___](BT4`
+M2(D#2(M%"$B)0PA(BT402(E#$$B+11C&0T0`QD-!`,9#0`%(B4,8#[9%18A#
+M10^V!0````"(0R#IQO[__V9FD&9FD$%7059!54F)]4%454B)_5-(@>PH`@``
+MB%0D!P^V1@_&1"00`83`>`_&1"00`(!_$`8/A)X"``!(C40D(&9F9I!(C90D
+M(`(``,8``$B#P`%(.=!U[$$/MD4+B$5(08!]#0!T*S';ZQ!!#[9%#8U3`4B#
+MPP$YT'X708M\G7SH`````(%X8``0``!UW<9%2`-!#[9%#@^VE6`"``"(145!
+M#[9-#K@!````T^!FB45&B="#R`2(A6`"``!!]D4/`P^$F@$``(G02,>%:`(`
+M``````"#R`6(A6`"``!(BT4(@'@+``^%E@$``$F+11`/ME5$2<?'_____TB)
+MA7`"``!)BT48A=)(B85X`@``?EA%,>3K$0^V541!C40D`4F#Q`$YPGY"2HM<
+MY6!(BT,H2(EK&$DYQTP/1_B`>Q`$==6`?"0'`$B+0SA(B40D"'5D@'PD$`!U
+M9`^V541!C40D`4F#Q`$YPG^^@'T0!P^$.@$``$B+30B`>0D`#X7Q````#[9!
+M"BG"2&/"3`^O^$R)?2A!#[9%#X/@','X`HB%@0,``$B!Q"@"``!;74%<05U!
+M7D%?PX!\)!``='%(BT-(2(M\)`A(C4PD($&X`0```+H!````2(MP".@`````
+MA<`/A3#___^`O"0>`@``J@^$#@$``#'`@'PD(%(/A.<```"%P`^$#?___TB+
+M0TA(BWPD"$B-3"0@13'`N@$```!(BW`(Z`````#IZ?[__T4Q]DB+0TA,B?9(
+MBWPD"$B-3"0@13'`N@$```!)@\8!2`-P".@`````28/^`@^$MO[__^O.2,>%
+M:`(``/_____I>O[__P^W14;WV$B822''Z?_^__^#R@>`?1`*B)5@`@``#X57
+M_O__#[9-1+@!````@^D!2-/@2(E%4.D__O__@'U$``^$V_[__S')2(M$S6"-
+M40%(@\$!2(M`*$@!12@/MD5$.=!_Y.FX_O__T>B#X`&(1"00Z53]__^`?"0A
+M10^%#O___\9$)"!%QD0D(5+I!____X"\)!\"``!5#X7D_O__L`'&A"0>`@``
+M5<:$)!\"``"JZ<_^__]F9F:09F9FD&9FD&9FD$%5,?9!5$F)_%532('LB```
+M`$B+1RA(BV\PBSCH7Z'__TB%P$B)PP^$4@$``#'`D,8$*`!(@\`!2(/X6'7R
+M28GE2(G@2(V4)(````#&``!(@\`!2#G0=>Q(BT,(2(M[$$B)YO]0.`^V1"06
+M28U5/$B-302(10,/MD0D%(A%``^V1"05B$4!2(M$)#Q(B44$2(M""$B)00A(
+MBT(02(E!$$B+0AA(B4$8BT(@28U5&(E!($B+1"082(U-*$B)12A(BT((2(E!
+M"$B+0A!(B4$02(M"&$B)01B+0B")02`/M@0DB$50#[9$)`&(15$/MD0D`HA%
+M4@^V1"0#B$532(M#&(E%3(![:`!U<0^V1"07B$4"2(L;2(7;=1CK*V9FD&9F
+MD`^V1"07`$4"2(L;2(7;=!5(BT,(2(M[$$B)YO]0.(!\)!,`=-M)BWPD$$F-
+M="182<=$)%@`````38ED)&!)QT0D:`````#H`````$B!Q(@```!;74%<05W#
+M@$T#!.N)0<=$)%#_____Z[MF9I!F9I!!54F)_3'V05154TB![(@```!(BT<H
+M2(MO,(LXZ,^?__](A<!(B<,/A!<!```QP)#&!"@`2(/``4B#^$QU\DF)Y$B)
+MX$B-E"2`````Q@``2(/``4@YT'7L2(M#"$B+>Q!(B>;_4#@/MD0D%DF-5"0\
+M2(U-!(A%`P^V1"04B$4`#[9$)!6(10%)BT0D/$B)101(BT((2(E!"$B+0A!(
+MB4$02(M"&$B)01B+0B!)C50D&(E!($F+1"082(U-*$B)12A(BT((2(E!"$B+
+M0A!(B4$02(M"&$B)01B+0B")02`/MD0D%XA%`DB+&TB%VW42ZR4/MD0D%P!%
+M`DB+&TB%VW052(M#"$B+>Q!(B>;_4#B`?"03`'3;28M]$$F-=5A)QT58````
+M`$V);6!)QT5H`````.@`````2('$B````%M=05Q!7<-!QT50_____^O'9I!(
+M@^P83(ED)`A(B1PD28G\3(EL)!!(BU\(2(M7$(M#,$R+*XE",("C80(``//'
+M0S#_____@*)A`@``\XMR,$F+?0CH`````(MS-$R)[^@`````2(E84,:`L```
+M``1(B<=,B6!82,>`R`````````!(BQPD3(MD)`A,BVPD$$B#Q!CI`````&9F
+M9I!F9I!F9I!32(M'*$B)^XLXZ`````!(B<?H`````$C'0U@`````2(E;8$B-
+M<UA(QT-H`````$B+>Q!;Z0````!F9F:09F:04TB+?PA(BQ_H`````$B+@^`!
+M``!(QT!8`````$B)0&!(C7!82,=`:`````!(BW@06^D`````9F9FD&9FD&9F
+MD%.#?U#]2(M?0`^$]0```/:#80(```C&@WL#````=&F+1U"#^/T/A-L!``"%
+MP`^%X`$``$B+@X`"``!(BY"@````#[>`J````('B__\/`$@YP@^#B0```$C'
+M@^@"````````2(F;\`(``$C'@^`"````````2(L#2(VSX`(``%M(BW@(Z0``
+M```/MHM@`@``]L$0#X2(````BT=0@_C]#X1"`0``A<`/A4,!``!(BU,(#[9#
+M1`^V4@HIT$B82`^O@V@"``!(.T,H#X/1`0``]H-A`@``"`^%6/___V9FD&:0
+M]H-@`@``4`^%B0```$C'@^@"````````2(F;\`(``.EP____#[:#>P,``#P"
+M#X_\_O__@\`!B(-[`P``Z\]FD/;!('5L]L%`#X2V````]L$!#X2/`0``1(M'
+M4$6%P&:0#X5"`0``2(M3"`^V0T0/ME(**=!(F$@/KX-H`@``2#M#*`^">/__
+M_TB)W[X)````6^F:P___2(N#:`(``"7__S\`2(/X?P^'8?___^G&_O__1(M/
+M4+@+````187)=2F$R;`*>"-(BU,(#[9#1`^V4@HIT$B82`^O@V@"``!(.T,H
+M<G>X#````(/A7TB)WHG'B(M@`@``Z`````#V@V`"```(=6];PX`]``````!U
+M<H/A[TB)WK\(````B(M@`@``6^D`````@#T```````^%F@```$B+@X`"``"`
+MHV$"``#W2(G>OQ0```!(BT`0@*!A`@``]UOI`````$B+@R@#``"`.``/A);^
+M__^#X=^(BV`"``!(B=^^`0```%OIK\+__\='4`````!(B=Z_'````.@`````
+M#[>#=`,``$@!@V@"``#I)/[__X/AOTB)WK\/````B(M@`@``6^D`````2(G?
+MO@,```!;Z6/"___'1U``````2(G>OQP```#H`````.D(_O__@^&_2(G>OPX`
+M``"(BV`"``!;Z0````!F9I!(C89H`P``]H9A`@``"$B)O@@#``#'AA@#````
+M````2,>&,`,```````!(B88@`P``2(V&>@,``$B)MC@#``!(QX9``P``````
+M`$B)AB@#``"+AN@#``")AF@#``!T-\>&$`,``"K_``#'AA0#```$````BX;<
+M`@``,=*#P`&#^&4/3-")EMP"``!(@<;X`@``Z0`````/MHY@`@``]L%P#X2J
+M````B<B#X*`\H`^$GP```$R+1@@/MD9$00^V4`HIT$B82`^OAF@"``!(.T8H
+M#X-\````]L$0N"/_``!U#X/A((#Y`1G`]]`%)?\``(F&$`,``$B+EB`#``!(
+MBX9H`@``2(E"!$&`>`D`=%H/MT9&2(N6(`,``&:)0@SVAF`"```@QX84`P``
+M#@````^$/____TB+AB@#``#&``#'AA@#```!````Z2;___]F9I#SPTB-OO@"
+M``#'AD@#````````Z;C[__](BU8H2"N6:`(``+F`````2(N&(`,``$B!^H``
+M``!(#T?19HE0#.N-2(M'0$C'@.@"````````2(F`\`(``$B-L.`"``!(BP!(
+MBW@(Z0````!F9F:09F:02(/L&$B);"002(E<)`A(B?U(BU\82(7;2`]$WP^V
+M@V$"``"H!'1^J`@/A9,```!(BY.``@``2(72#X2#````2(M""$B%P`^$=@``
+M`$B#>A``=&^`B&$"```(2(VSX`(``$B+0A"`B&$"```(2(L#2,>#Z`(`````
+M``!(B9OP`@``2(MX".@`````2(G>2(ML)!!(BUPD"+\2````2(/$&.D`````
+M#[:78`(``/;"$'412(7;=`2H"'4(]L)@9F:0=`](BUPD"$B+;"002(/$&,-(
+MBT4`@^+W2,>%Z`(```````"#RA!(B:WP`@``2(VUX`(``(B58`(``$B+>`CH
+M`````$B)[DB+7"0(2(ML)!"_!````$B#Q!CI`````&:0055!5$F)_%532(/L
+M"$B+1RB+6`2+..@`````@_L.2(G%=CU!QT0D4/[___])QT0D6`````!-B60D
+M8$F-="182<=$)&@`````28M\)!!(@\0(6UU!7$%=Z0````!F9F:0B=C_),4`
+M````9F9FD&9FD$B)Q4B+11A(A<!U](!]$`4/A.X%``"`I6`"``"_2(GNOPX`
+M``#H`````$2+53!%A=(/B$X&``!(BTT8N@$```#IV`,``$B+11A(A<!T#?:`
+M80(```P/A5C___]F]X5@`@``<`P/A4G____VA8`#```!#X0\____@'T0!0^%
+M&@8``(!]1``/A&,&``!%,>UFD.L4#[9%1$&-50%)@\4!.=`/CD@&``!*BUSM
+M8$B%VW3B@'L0!';<]H-@`@``$'732(M[6.@`````2(M3"`^V4@HYT`^-V_[_
+M_P^V@V`"``!(QX/H`@```````$B-L^`"``!(B9OP`@``@^#W@\@0B(-@`@``
+M2(L#2(MX".@`````2(G>OP0```#H`````.EP____@'T0!0^$B00``("E8`(`
+M`.=(B>Z_!0```.@`````2(M-&+H!````Z<\"``#VA6`"```0#X18_O__]H6`
+M`P```0^$2_[__X"E8`(``.5(BT582(GN2,>%:`(``/____^_!@```$B)15#H
+M`````$B+31B`I6`"``#^2(7)=%2`>40`=$XQ]DB+1/%@2(7`="_V@(`#```!
+M=":`>!`$=B`/MI!@`@``#[:!8`(``(/B`8/@_@G0J`&(@6`"``!U#P^V042-
+M5@%(@\8!.=!_N$B+31A(@WU8`1G2@\("Z1L"``!(BT482(7`=`WV@&$"```,
+M#X6;_?__9O>%8`(``'`,#X6,_?__]H6``P```0^$?_W__X!]$`4/A=@$``"`
+M?40`#X1T_?__13'M9F:09I#K%`^V141!C54!28/%`3G"#XU6_?__2HM<[6!(
+MA=MTXH![$`1VW/:#8`(``"!UTTB+?5!("WU8Z`````!(BU4(#[92"CG0#XT7
+M_?__2(L#@(M@`@``($B-L^`"``!(QX-H`@```````$C'@^@"````````2(F;
+M\`(``$B+>`CH`````$B)WK\)````Z`````#I;?___X"E8`(``-](B>Z_"@``
+M`.@`````Z;[\__^`I6`"``#?Z;+\___VA8`#```!#X2<_/__2(-]6``/A9'\
+M__\/MX5@`@``9B5Q#&:#Z`$/A7S\__^`?1`%#X4\!```@'U$`'0U13'M2HM<
+M[6!(A=MT&(![$`1V$@^V@V`"``"#X$$L`0^$6P0```^V141!C54!28/%`3G0
+M?\Z`I6`"``#WZ33\__^`I6`"``"T2,>%:`(``/____](B>Y(QT50`````+\0
+M````Z`````!(BUT82(7;#X25`@``#[9#1(7`#XZ,`@``@^@!,?8QTDB-2`%(
+MBT338$B%P'0C]H"``P```70:@'@0!'84]H!@`@```;@!````#T7P9F:09I!(
+M@\(!2#G*=<J%]@^$0P(``$B+2QA(B=VZ`0```(/Z`P^5P(3`#X0^`0``9F:0
+M9I!(A<D/A#`!``!(B<U(BTD8Z1P!``"`I6`"``#?2(GNOPL```#H`````.E>
+M^___9O>%8`(``'`(2(N%@`(```^%/_O__TB%P`^$-OO__X"XJP`````/A2G[
+M__](BU`(2(M`$/:"@`,```$/A!3[___V@(`#```!#X0'^___@*)A`@``[TB-
+MM>`"``"`H&$"``#O@(IA`@``"("(80(```A(BT4`2,>%Z`(```````!(B:WP
+M`@``2(MX".@`````2(GNOQ(```#H`````.F\^O__#[>%8`(``$B+C8`"``!F
+M)7`(9CT`"`^%E_K__TB%R0^$COK__TB+00A(BU$02(GNOQ,```"`H&$"``#W
+M@*)A`@``]^@`````2(M-&+H!````Z<?^__](BTT8N@,````QP(3`#X7'_O__
+M@(U@`@``!(/Z`@^$[P```$B+A8`"``!(A<`/A.P```!(BW@(2(M8$$B%_W0%
+MZ`````!(A=L/A!CZ__](B=_H`````&9F9I#I!_K__S';@'U$`'4;9F:0Z7+Z
+M__\/MD5$C5,!2(/#`3G0#XY?^O__2(MTW6!(A?9TXX!^$`1VW?:&8`(``!!T
+MU("F8`(``.>_!0```.@`````Z\&`?40`#X0<^O__,=OK$P^V142-4P%(@\,!
+M.=`/C@7Z__](BW3=8$B%]G3C@'X0!';=]H9@`@``0'34@*9@`@``O[\.````
+MZ`````#KP4B)ZX"C8`(``/Y(B=_H`````.FI_?__2(GOZ`````#I1_G__TB)
+M[^@`````9F:0Z3?Y__](B>_H`````$B+31BZ`0```.F"_?__2(M]6.@`````
+M2(M5"`^V4@HYT`^-__C__TB+10"`C6`"```02(VUX`(``$C'A>@"````````
+M2(FM\`(``$B+>`CH`````$B)[K\$````Z`````"`I6`"``#W2(-]6``/A#?Y
+M___H`````$B+31BZ`0```(E%/.D'_?__2(M]4$@+?5CH`````$B+50@/ME(*
+M.=`/C8#X__](BT4`@(U@`@``($B-M>`"``!(QX5H`@```````$C'A>@"````
+M````2(FM\`(``$B+>`CH`````$B)[K\)````Z`````#I/_C__TB+10"`C6`"
+M``!`2(VUX`(``$C'A6@"````````2,>%Z`(```````!(B:WP`@``2(MX".@`
+M````2(GNOPT```#H`````.FU^___#[:#8`(``$C'@V@"````````2(VSX`(`
+M`$C'@^@"````````2(F;\`(``(/(0(/@]XB#8`(``$B+`TB+>`CH`````$B)
+MWK\-````Z`````#I4/O__V9F9I!52(G]4TB#[`CVAX`#```!=2,/MH=A`@``
+M@^`$/`$9VX'C`/C__X'#`0@``(G82(/$"%M=PP^VEV`"``#VP@(/A#,!``!(
+MBW]8NP(```")V(#,$/;"`0]%V(G8@\@$]L(0#T78B=B`S`'VPB`/1=B)V(#,
+M`H/B0`]%V$B%_P^%(@(```^VE8`#``")V$0/ME5$@\@0]L($10^VR@]%V(G8
+M@\A`@^("#[:580(```]%V(G8#(#VA6`"```(#T78B=B`S`CVP@0/1=B)V(#,
+M!(/B"`]%V$6%R0^.M@```$&-0?\Q]DR-0`'K8$B+>EA(B?A(]]!(A4)0=`.#
+MRP*)V(#,$/;!`0]%V(G8@\@$]L$0#T78B=B`S`'VP2`/1=B)V(#,`O;!0`]%
+MV(G8@\@(2(7_#T78B=@,@(/A"`]%V&9FD$B#Q@%,.<9T2DB+5/5@2(72=.WV
+M@H`#```!=.2`>A`$=MX/MHI@`@``]L$"#X1W____2(MZ6.N!2(M_6#';2(GX
+M2/?02(5%4`^$P/[__^FV_O__]L,"=!'VQQ!F9I!FD`^$Z@```(/C_46%R0^.
+M$@$``$B+56!(A=(/A&W^___V@H`#```!#X1@_O__,?^`>A`$00^VPD2-0/\/
+MAIX````/MG)$A?9^:$B+0F!(A<`/A#?^___V@(`#```!#X0J_O__2(M`2$B#
+M>`@`#X4;_O__,<GK+4B+0FA(A<`/A`K^___V@(`#```!#X3]_?__2(M`2$B#
+MP@A(@W@(``^%ZOW__X/!`3G.=<QF9F:09F:03#G'=&](BU3]:$B%T@^$R?W_
+M_TB#QP'V@H`#```!#X2X_?__@'H0!`^'8O___TB+0DA(@W@(`'3'Z9[]__]F
+MD(G8)0@@``"#^`@/A0G____I`?___^@`````2(M5"(/+"(G9@,T@#[92"CG0
+M#TS9Z;_]__^!RP```$#I7?W__Y!!5D%5051)B?Q54TB+1RA(BU\01(LH1(GO
+MZ`````!(BVL82(/#&$F)QD@YW74+ZTY(BVT`2#G==$5(@[V(_/__`$B-O7#\
+M__]UYD6%[74&]D7P`G5723G^=&;VAX`#```"=,V`IX`#``#]@'\0`71&Z```
+M``!(BVT`2#G==;M)QT0D6`````!-B60D8$F-="182<=$)&@`````28M\)!!;
+M74%<05U!7ND`````@&7P_8!_$`%UNN@`````Z7#____VAX`#```"#X5C____
+M@(^``P```NN49F9FD&9FD&9FD$B#[&A(B5PD2$B);"102(G[3(ED)%A,B6PD
+M8$B+;RB+?0"%_W5*2(M[$.AAF/__QT-0_/___TB+>Q!(C7-82,=#6`````!(
+MB5M@2,=#:`````#H`````$B+7"1(2(ML)%!,BV0D6$R+;"1@2(/$:,/H````
+M`$F)Q(M%!$R-;02H`0^%*0$``*@"#X5Y`0``J`0/A=D!``"H"`^%.`(``*@0
+M=6VH0'0IQT-0`````$&`?0H`00^V1"1J#Y7"08!,)&@0@^#^"=!!B$0D:D&+
+M10"H(`^%G@```$'V1"1H$`^$4O___TF+1"1P28N\)(@```!(B>;_4'@/MD0D
+M$DR)YT&(1"1FZ`````#I*/___V:0QD0D,`)!#[9%"$B-="0PB$0D.$F+1"1P
+M28N\)(@```#_D,````"%P(E#4'4H00^V5"1I@\H!08A4)&E!@'T(``^5P$&`
+M3"1H$(/B_0'`"<)!B%0D:4&+10"H0`^$7____^DQ____QD0D,`=!#[9%"4B-
+M="0PB$0D.$F+1"1P28N\)(@```#_D,````")0U!!]D0D:!`/A(O^___I-/__
+M_\9$)#``00^V101(C70D,(A$)#A)BT0D<$F+O"2(````_Y#`````A<")0U!U
+M($$/MD0D:(/(@$&(1"1H00^V502#R!!!B$0D:$&(5"1GBT4$J`(/A(?^___&
+M1"0P!$$/MD4%2(UT)##&1"0Y`(A$)#A)BT0D<$F+O"2(````_Y#`````A<")
+M0U!U*4$/ME0D:8/*$$&(5"1I08!]!0`/E<!!@$PD:!"#XM_!X`4)PD&(5"1I
+M08M%`*@$#X0H_O__D,9$)#`%00^V109(C70D,,9$)#D`B$0D.$F+1"1P28N\
+M)(@```#_D,````"%P(E#4'4I00^V5"1I@\I`08A4)&E!@'T&``^5P$&`3"1H
+M$(/B?\'@!PG"08A4)&E!BT4`J`@/A,C]___&1"0P`T$/MD4'2(UT)#"(1"0X
+M28M$)'!)B[PDB````/^0P````(7`B4-0=2E!#[94)&F#R@1!B%0D:4&`?0<`
+M#Y7`08!,)&@0@^+WP>`#"<)!B%0D:4&+10"H$`^$:OW__^G2_?__9I!(@^PX
+M2(E<)!A(B6PD($B)^TR)9"0H3(EL)#!(BV\HBWT`A?]U2DB+>Q#H(97__\=#
M4/S___](BWL02(US6$C'0U@`````2(E;8$C'0V@`````Z`````!(BUPD&$B+
-M;"0@3(MD)"A,BVPD,$B#Q#C#Z`````#V100!3(UM!$F)Q'420?9$)&00=*Q,
-MB>?H`````.NBQ@0D`$$/MD4$2(GFB$0D"$F+1"1H28N\)(````#_D,````"%
-MP(E#4'7$00^V1"1D@\B`08A$)&1!#[95!(/($$&(1"1D08A4)&/KHE-(BT<H
-M2(G[BSCH``````^V2&2!>Q@,_P``2(G&B<A`#Y3'P.@"0`^VUX/@`3G0=!J-
-M!+T`````@^'[2(GW"<&#R1"(3F3H`````$C'0U@`````2(E;8$B-<UA(QT-H
+M;"0@3(MD)"A,BVPD,$B#Q#C#Z`````#V100!3(UM!$F)Q'420?9$)&@0=*Q,
+MB>?H`````.NBQ@0D`$$/MD4$2(GFB$0D"$F+1"1P28N\)(@```#_D,````"%
+MP(E#4'7$00^V1"1H@\B`08A$)&A!#[95!(/($$&(1"1H08A4)&?KHE-(BT<H
+M2(G[BSCH``````^V2&B!>Q@,_P``2(G&B<A`#Y3'P.@"0`^VUX/@`3G0=!J-
+M!+T`````@^'[2(GW"<&#R1"(3FCH`````$C'0U@`````2(E;8$B-<UA(QT-H
M`````$B+>Q!;Z0````!F9I!!5T%608G6055!5$F)_%532('L&`(``$"(="0/
M@']$``^$F0```$6-?O]`#[;&13'MB40D".M808/_`0^&GP```(![4`!(BVLX
-M=0>`?"0/`'0-]H6``P```0^%G````$B)W^@`````]D5D$'03]H6``P```0^%
+M=0>`?"0/`'0-]H6``P```0^%G````$B)W^@`````]D5H$'03]H6``P```0^%
MY@```&9FD&9FD$&-10%)@\4!03A$)$1V,$N+7.Q@2(7;=.</MD,0/`1VEHMT
M)`A$B?)(B=_H4/___T&-10%)@\4!03A$)$1WT$R)Y^@`````2('$&`(``%M=
M05Q!74%>05_#9F9FD&9FD#P$2(G=#X2@````08/^`G6/2(GOZ`````#KA4B+
@@ -6749,7 +5405,7 @@ M]H.``P```0^$-_[__TB#NX`"````#X4I_O__9O>#8`(``%`"#X4:_O__2(M-
M=$@Y2R@/APS^__^`90_\@'L0!P^$_0$``(!]#`</A`P"``#'1"1L`````$B+
M?"081(G^Z`````!(A<!)B<</A-/]__^`?"0P!P^$!@,```^V30TQVX3)=1[I
MW@$``&9FD`^V30V-4P%(@\,!#[;!.=`/CL4!``"+?)U\B5PD:.@`````BTPD
-M;#'228G$A<EU&$B#?"00`'002(M\)!!(B<;HRX?__TB)PDR)]DR)Y^@`````
+M;#'228G$A<EU&$B#?"00`'002(M\)!!(B<;HFX?__TB)PDR)]DR)Y^@`````
M2(7`28E$WV!UHXMT)&B%]GX;3(G[,>U(BWM@@\4!2(/#".@`````.VPD:'7J
M3(G_Z`````"X_____^DI_?__0;\'````QD0D,`?&1"1``.F`_?__@'T.!P^%
M!?W__T&_"@```,9$)#`*QD0D0`#I8?W__T&_"0```,9$)#`)QD0D0`#I3/W_
@@ -6762,19 +5418,19 @@ M3@8``$B+7"00@'M$`0^$]/W__\=$)&P!````Z>_]__]!B$]$BTPD+$&`_0%!
MB4\X08E/0`^&[P4``$4/MO4/MEPD0$2(;"1[08U&_T2(="1Z13'D2(/``8E<
M)'Q(B40D"(MT)'Q(BWPD&.@`````2(7`2(G##X0O!0``,=)%A?9^'F9FD$&-
M!!1(F$F+1,=@2(E$TV!(@\(!2#M4)`AUY4&+1SA$B&M$2(GN2(G?B4,X,<!(
-M@WPD$``/E,")PHE$)"CH_MG__T2)XD2)X$4!],'Z'T'W_DB828E<QV!!#[9'
+M@WPD$``/E,")PHE$)"CHWMG__T2)XD2)X$4!],'Z'T'W_DB828E<QV!!#[9'
M1`^V5"1[`E0D>CI$)'L/AML```"(5"1[Z6/___\QVX!]#0!U'.G^^___2`%%
M=`^V10V-4P%(@\,!.=`/CCL"``"+?)U\Z`````!(BT!`2(7`==?IPOK__TR+
M970/ME4-387D#Y7`A=)^!T4Q]H3`=23'1"1H`````(3`=`HY5"1H#X0Z_?__
M#[94)&A!B%=$Z:[^__]"BWRU?$2)="1HZ`````!(B<=(BT!`23G$2(G#20]&
MW#'22(G>Z`````!(A<!+B43W8`^$]/S__T&-1@%)*=R)1"1H#[95#0^5P$F#
MQ@$[5"1H?I"$P'2:ZZ8/ML!!]O4\/T&(1T1W)@^VP#')C5`!B<:-!`Z#P@%(
-M@\$!2)A)QT3'8`````"-0O\\/W;DBU0D*$B)[DR)_^BRV/__00^V5T2%TGXU
+M@\$!2)A)QT3'8`````"-0O\\/W;DBU0D*$B)[DR)_^B2V/__00^V5T2%TGXU
M,?9(BUPD6$F+3/=@#[9#"BG"28M'*$ACTDB)TS'22/?S00^V5T1(B4$HC48!
M2(/&`3G"?\U(@WPD$``/A"<%``!(BU0D$$R)_HM"0$B)UT&)1T#H`````(3`
M#X7O````2(M,)!!!#[:'@`,``$F+7R@/MI&``P``@^#[@^($"=!!B(>``P``
M#[:1@`,``(/@_8/B`@G008B'@`,```^V04A(.5DH08A'2'<]28M'"(!X"@!U
-M#DF+1V!(BT`(@'@*`'0E2(M\)!#H#.W__T&)Q$&!Y`(0``!U?$B+1"0028M7
+M#DF+1V!(BT`(@'@*`'0E2(M\)!#H+.W__T&)Q$&!Y`(0``!U?$B+1"0028M7
M*$@Y4"AR;4B+3"00@+F!`P```@^$``4``$B+7"002(M4)!B+0S!(B=%(@\$X
M08E',$B+0CA(.<AU$>E)`@``2(L`2#G(#X0]`@``2(U0Z$B+7"002#E:4'7E
M3(EZ4.O?2(M$)%@/MD@)Z:?Y__]!O`$```!(BWPD&$B!Q]````#H`````$B)
@@ -6793,7 +5449,7 @@ M`3G0?[)!@*=@`@``O^EW____2(M\)!`Q]C'2Z,+R__](BT0D&$&+=S!(BW@(
MZ`````#IRO[__T2)XD2)X#'MP?H?3(G[0??^A<!!B<5^'$B+>V`Q]KH!````
M@\4!2(/#".A\\O__1#GM=>1!#[9'1$$YQ`^-V?C__T2)XTACPX/#`4F+?,=@
MZ`````!!#[9'1#G8?^?IN/C__T6%Y+@"````=`>`>R@`#Y7`B(.J````Z;']
-M__\QTDB#?"00`$B)[DR)_P^4PNB&U/__Z0W\__](BUPD6`^V2PGIP/;__TB+
+M__\QTDB#?"00`$B)[DR)_P^4PNAFU/__Z0W\__](BUPD6`^V2PGIP/;__TB+
M7"00@'M$``^$H_G__X!]#0`/A)GY__](BT-@13'D2(7`=3[I?_7__TB+3"00
M08U4)`$/MD%$.=`/CK,!```/MD4-.=`/CI$!``!(BU0D$$J+1.)H28/$`4B%
MP`^$1O7__TB+6#A"BWRE?.@`````2#G#=;1(BU0D$`^V0D0Z10T/AR'U__\/
@@ -6802,16 +5458,16 @@ M`3G"#XY)`0``2(M<)!!*BT3C:$F#Q`%(A<`/A-/T__](BU@X0HM\I7SH````
M`$@YPW3`Z;OT__]F9I!FD$F+!T&`CV`"``!`28VWX`(``$G'A^@"````````
M38F_\`(``$B+>`CH`````$R)_K\-````Z`````#I>/W__TR)_^@`````]D4/
M`0^%<OW__TR)_^@`````Z=G\__\QP$6%Y`^%1_S__TB+5"002(M"*.DY_/__
-M2(M\)!!(Q\(`````2(G>Z.6A__\QP.DI]/__28L'08"/8`(``!!)C;?@`@``
+M2(M\)!!(Q\(`````2(G>Z+6A__\QP.DI]/__28L'08"/8`(``!!)C;?@`@``
M2<>'Z`(```````!-B;_P`@``2(MX".@`````3(G^OP0```#H`````.GF_/__
-M2,?"`````$R)_DB)S^B-H?__,<#IT?/__TB+7"00#[9#$#P'#X3$]___Z<[W
+M2,?"`````$R)_DB)S^A=H?__,<#IT?/__TB+7"00#[9#$#P'#X3$]___Z<[W
M__\/MD$0Z^U(BTPD$$B+02B0Z9O[__](BT5T2(M,)!!)B<5,*VDH='U(8\)(
MBWS!6$R+?SA)BW<X2(7V=1'I!`$``$B+-DB%]@^$^````$B#?A@`=>U(BU=(
M2(M*$$B)R$@#0@A(.48(==A(BT802(M?*$DYQ4B)7"1P#X.4````2HT$*4B)
-M0A!(B4<H3(G_3`%N"$PI;A!!@$]D$.@`````2(M%=$B+5"002(E"*$B+11!(
+M0A!(B4<H3(G_3`%N"$PI;A!!@$]H$.@`````2(M%=$B+5"002(E"*$B+11!(
MB==(B8)P`@``2(M%&$B)@G@"``#H`````$B+3"002(L!BW$P2(MX".@`````
M#[9%#TB+7"00@^`<P?@"@+N!`P```HG"#X1K`0``2(M,)!"+@>@#``"(D8$#
-M``#IJ/+__TDIQ4B-!`%(B4(02(E'*$R)_^@`````08!/9!!,B?_H`````$V%
+M``#IJ/+__TDIQ4B-!`%(B4(02(E'*$R)_^@`````08!/:!!,B?_H`````$V%
M[7422(M%=.E?____2,=$)'``````2(M$)!`/ME4-387M1`^V<$0/E<!!.=9\
M-X3`=`5!.=9T:$B+7"001(AS1$B+173I(O___TB+3"0008/&`4TIY4B)2!@/
MME4-#Y7`1#GR?LF$P'3.26/>BWR=?.@`````2(G'2(M`0$DYQ4F)Q$T/1N4Q
@@ -6819,7 +5475,7 @@ MTDR)YN@`````2(M4)!!(A<!(B43:8'6J2(-\)'``=#M(BTPD$`^V041(BWS!
M6.@`````2(M$)!!(BW0D<#'23(G_#[981.@`````2(M4)!"#ZP%(8]M(B43:
M8$B+3"00#[9!1$0Y\`^-B?'__S'M08G$2(M$)!!!C1PL2(/%`4ACVTB+?-A@
MZ`````!(BU0D$$&-!"Q$.?!(QT3:8`````!\S^E.\?__/`(/A(W^__^(@X$#
-M``!(BT0D($C'P@````!(B=](B[#@`0``Z-^>__\QP.DC\?__9F9FD&9F9I!5
+M``!(BT0D($C'P@````!(B=](B[#@`0``Z*^>__\QP.DC\?__9F9FD&9F9I!5
M4TB)^TB#[`A(BV\HBWT`Z`````!(BWL02(U5!$B)QNB+\/__A<")PG0U@_C_
M=#=(BT,P2,=#6`````!(C7-82(E;8$C'0V@`````2(M[$(D02(/$"%M=Z0``
M``!F9I!(@\0(6UW#B4-0Z\1F9F:054B)_5-(@>RH````2(M_$$B+=2A(C40D
@@ -6835,656 +5491,596 @@ M``"+0S!)C4PD.$&)13!)BT0D.$@YR'40ZR1F9I!F9I!(BP!(.<AT%DB-4.A(
M.5I0=>Y(BP!,B6I02#G(=>HQTDB)WS'VZ#;K__]!BW4P28M\)`CH`````$R)
M[^@`````2(M5,$&+A>@#``!(C7582,=%6`````!(B6U@2,=%:`````!(BWT0
MB0)(@\0(6UU!7$%=Z0````!F9F:09F9FD$%5N/____]!5$F)_%5(B?532('L
-MR````(!_$`%(BU]X=`Y(@<3(````6UU!7$%=PTB+1VA,C:PD@````$B+OX``
-M``!,B>[_4'A(BT,(2(GF2(M[$/]0.$B-C"2T````2(V4)+@```!(C;0DO```
-M`$B)W^A9<O__#[:$)(T```"(10+VA"2*`````@^%>@$```^VA"2X`````H0D
-MC````(A%`8N$)+P```"(10!!@'PD9``/B5\!``!!#[9$)&.(10,/MH0DDP``
-M`(A%!0^VE"2(````#[9%!@^VM"2)````P.H&B=&#X/S0ZH/A`0'2"<@/MHPD
-MB0````G0C12U`````(/@\X/B"(/A`<'A`@G(B?$)T(/A$(GR@^#/@^(@"<B)
-M\0G0@^%`B?*#X#^#XH`)R`G0B$4&#[9%!P^VE"2/````@^#\@^(#"=!`]L8$
-MB$4'#X3/````QD4$`DR)[DR)Y^B9=/__2(NT))@```")10A(A?9T(TB-?0Q(
-MC5U"NI8```#H`````+XH````2(G?Z`````#&0R<`0?9$)&1!=1A)BT0D2$B)
-MA:(```!)BT0D0$B)A:H```!)BTPD.$B%R70V,?;K"$B+"4B%R70J2(M!&$B%
-MP'0<2(M`&$B%P'03BX#H`P``2&/6@\8!B825N@```(/^!W[.2('$R````#'`
-M6UU!7$%=PP^VA"2T````Z8'^__\/MH0DD@```(A%`^F:_O__@^8(0(#^`1G`
-M@^#^@\`#B$4$Z1[___]FD$B#[#A,B60D&$R);"0@28G]2(E<)`A(B6PD$$R)
-M="0H3(E\)#!(BT<H2(M?,(LHB>_H`````$F)Q(L#@^@%=!.)PDB)V,9`!0!(
-M@\`!2(/J`77RA>UT:DV%Y'1E28M$)"BZ_____TB)0Q!)BT0D&$B%P'0&BY#H
-M`P``B5,808M4)#"X_____X72#TG"B$,/28L$)$B+>`CH`````(A##D$/MH0D
-M@0,``(A##4$/MD0D$#P$=E?&0PP!08!\)$1`=F5!QT50_____TF+?1!)C758
-M2<=%6`````!-B6U@2<=%:`````!(BUPD"$B+;"003(MD)!A,BVPD($R+="0H
-M3(M\)#!(@\0XZ0`````L`76Q2(US+,9##`),B>?HH/S__X7`=9WKHTF+1"10
-M3(GG2(F#O````.@6=?__B8.P````28N$)'`"``!(B4,L28N$)'@"``!(B4,T
-M00^V?"00Z/UQ__^(@Y````!!#[9$)$5,B>>(@Y$```!!#[9$)$B(@[0```!)
-MBX0D:`(``$B)@YP```#HJ-[__TR)YXF#E````.@`````QH.2`````(F#F```
-M`$&`?"1$``^$2@$``$4Q]D4Q_TN+;/1@2(7M#X3U````@+N3``````^$^0``
-M`(!]$`0/A`@!``"+A>@#``!"B82SQ`````^VDY(```!!@\<!28/&`8/"`8B3
-MD@```$$/MD0D1$0Y^`^/D0````^VTH/Z/W\62&/"@\(!@_H_QX2#Q````/__
-M__]^ZDF+A"2``@``2(7`#X1[_O__2(M0"+G_____2(72=`:+BN@#``")BZ0`
-M``!(BU`0N?____](A=)T!HN*Z`,``(F+J````$B#>`@`#X0\_O__2(-X$``/
-MA#'^__],B>?H`````(F#K````.D>_O__9F:09I!!@_\_#X]E____2XML]&!(
-MA>T/A0O___]"QX2SQ`````````#I'____P^V?1#H?G#__XB#DP```(!]$`0/
-MA?C^__](BT4XBX#H`P``0HF$L\0```#I[_[__S'2Z1?___](@>SH````N/__
-M__](B9PDR````$R)I"38````2(GS2(FL)-````!,B:PDX````$F)_(!_$`%(
-MBV]X="A(BYPDR````$B+K"30````3(ND)-@```!,BZPDX````$B!Q.@```##
-M2(M':$R-K"2`````2(N_@````$R)[O]0>$B+10A(B>9(BWT0_U`X2(V,)+0`
-M``!(C90DN````$B-M"2\````2(GOZ-5L__\/MH0DC0```(A#`O:$)(H````"
-M#X42`0``#[:$)+@````"A"2,````B$,!BX0DO````(@#08!\)&0`#XD,`0``
-M00^V1"1CB$,##[:4)(@````/MD,&#[:T)(D```#`Z@:#X/R)T=#J@^$!`=()
-MR`^VC"2)````"="-%+4`````@^#S@^((@^$!P>$""<B)\0G0@^$0B?*#X,^#
-MXB`)R(GQ"="#X4")\H/@/X/B@`G("="(0P8/MD,'#[:4)(\```"#X/R#X@,)
-MT$#VQ@2(0P</MH0DDP```(A#!71<QD,$`DR)[DR)Y^@:;___2(NT))@```")
-M0P@QP$B%]@^$D/[__TB->PRZE@```$B#PT+H`````+XH````2(G?Z``````Q
-MP,9#)P#I9O[__P^VA"2T````Z>G^__^#Y@A`@/X!&<"#X/Z#P`.(0P3KE`^V
-MA"22````B$,#Z>W^__]F9I!F9I!F9I!!54F)_4%455-(@^P(3(MG*$&+/"2%
-M_W1(,>WK$69FD$B)W^@`````03DL)'8S@\4!B>A!BSR$Z`````"`>!`!2(G#
-M=4?V0&0"=-5(B<?H`````$B)W^@`````03DL)'?-2<=%6`````!-B6U@28UU
-M6$G'16@`````28M]$$B#Q`A;74%<05WI`````$''15#^____Z\MF9F:09F:0
-M9F:02(/L&$B)^$B)7"0(3(ED)!!(B<9(BU\03(MG"$B+.TB!Q]````#H````
-M`$R)YS'2,?;HJ>+__X"+8`(```1(B=],BV0D$$B+7"0(2(/$&.D`````9F9F
-MD&9F9I!F9F:04TB+1PA(B?E(BS@/MX&8````BY=8`@0`2,>'B`($``````!(
-MC;=H`@0`P>`)2,>'<`($``````!(B8]X`@0`2,>'@`($``````"-1`+_B=,Q
-MTO?SB8=H`@0`6^D`````4TB+1RB+..@`````2(N8@`(``(![*`!T3DB+>PA,
-MBXN@````2(M7*$DYT0^$;P$``$DYT0^']@````^$Q@$```^WBZ@````/M_%,
-M.<X/AHT!``!$#[:#J@```$2)R4$/M_%)*?'K0TB+>PA,BXN@````2(MW*$DY
-M\0^$^````$0/MH.J````183`#X70````#[>+J````(GR9D0IR@^WP4F-!`%(
-M.<8/0LI%A,!FQX.:``````!,B8N0````9HF+F````'0/08#X`W0)2(G?6^G+
-M_O__#[>#F````$B-<TA(QT-8`````$@#@Y````!,B4M(2,=#<`````!(B5MX
-M2,>#@`````````#'@X@````!````2(E#4$B-0V!(B4-@2(E#:.@`````A<!T
-MGUO#D`^WBZ@````/M_%(C00R3#G(#X*9````1`^V@ZH```!$B<EF*=$/M_'I
-M!?___V9FD$&`^`,/A";___](BT,02(MP*.D9____1`^V@ZH```!!@/@#=&A%
-MA,!UX$&X`0```,:#J@````'KT69F9I!F9I!$#[:#J@```$&`^`)T/T&`^`%T
-M0@^WBZ@````QTDR)R`^W\4CW]F:%T@^$D_[__P^W\HG1Z8G^__]F9F:09F:0
-M1`^V@ZH```#I=?[__TB)WUOI:LC__\:#J@````!(BU<HZ2O^__]$#[:#J@``
-M`.ND2(/L6`^WP4R)9"0X28G$2(E<)"A(B6PD,$R)="1(20'43(EL)$!,B7PD
-M4(G]2(ET)!!FB4PD#DF)UDB)1"083#MF4$R)PTV+>!!V2D''0%#^____2(US
-M6$C'0U@`````2(E;8$C'0V@`````3(G_2(M<)"A(BVPD,$R+9"0X3(ML)$!,
-MBW0D2$R+?"102(/$6.D`````2(M4)!!,B?^+<C3H`````$B%P$F)Q0^$HP$`
-M`,:`L@````!F@WPD#@%(B5A82,>`R`````````!(QX#```````````^$L`$`
-M`(']&?\``'0[=R6!_0O_``"0#X38````QT-0_O___TR)[^@`````3(M[$.E&
-M____@?TC_P``#X2T````@?TD_P``==1(BU0D$/9"9@(/A30!``!!QH6P````
-M`T'&A9L````D00^VA;$```"#X/N#R`)!B(6Q````08"]L`````,/A$X!``!!
-M#[:%D````#P0#X34`0``/`H/A(T"``!(BT0D$$F)15!)@W](``^$\@(``$F+
-M3T!)C54828U'.$F)5T!)B44828E-($B)$4B+7"0H2(ML)#!,BV0D.$R+;"1`
-M3(MT)$A,BWPD4$B#Q%C#9H-\)`X!#X<<____2(M$)!!(BV@X2(7M=!](BT4(
-M23G&<@U(`T4023G$#X;#`@``2(MM`$B%[77A2(M$)!#V0&8"#X26`@``2<'L
-M($'&A;`````"387D#X2X`P``0<:%F````(I!QH60````$$$/MH6Q````@\@$
-M@^#]08B%L0```.D!____3(M[$,=#4/W____I[_W__TG!["!!QH6P`````DV%
-MY`^$N0```$'&A9@```"(0<:%D````!#ILO[__TB+5"000;@!````3(GQB>Y(
-MQ\<`````,<#H`````.DM_O__3(GQ00^VUDR)\TC!Z1!)P>X82<>%H```````
-M``")R&:!X?\`0<:%F@```$`PP&9!QX60```````)T$2)\DG![@AF08F%E```
-M`##2#[;'"=!F08F%E@```$2)\##`"<%F08F-F`````^W1"0.9D&)A9(```!F
-M08F%G````.E)_O__0<:%F````"A!QH60````"NGY_?__0<:%D0`````/MT0D
-M#D6(M:$```!!QH6B`````$'&A:,`````P>`)08F%E````$R)\$C!Z#A!B(6:
-M````3(GP2,'H,$&(A9L```!,B?!(P>@H08B%G````$R)\$C!Z"!!B(6=````
-M3(GP2,'H&$&(A9X```!,B?!(P>@008B%GP```$R)\$C!Z`A!B(6@````#[=$
-M)`YFP>@(08B%I`````^V5"0.0<:%I@````!!QH6G`````$&(E:4```#I<_W_
-M_T'&A9$`````#[=$)`Y%B+6=````0<:%G@````#!X`E!B864````3(GP2,'H
-M&$&(A9H```!,B?!(P>@008B%FP```$R)\$C!Z`A!B(6<````#[=$)`YFP>@(
-M08B%GP````^V7"0.0<:%H0````!!B)V@````Z?K\__],B>](BUPD*$B+;"0P
-M3(MD)#A,BVPD0$R+="1(3(M\)%!(@\18Z0````!!QH6P`````T'&A9L````T
-MZ7K]__](BU482(722(E4)"`/A#3]__],BT(8387`#X0G_?__28MX6$R)!"3H
-M`````$R+!"1)BU`(.$(*#X8)_?__28V_\````$B+;0A!QH6P`````4R)!"3H
-M`````$B%P$B)P4R+!"0/A*\!``!,B?)(QT`0`````$C'03``````2"GJ2,=!
-M*`````!(QT$X`````$B)$$B+1"08QT%``0```$F)37A-B4502`'02(E!"$B-
-M01A(B4$82(E!($F+0`B`>`D`='1!QH6:`````4$/MDA%2-/J28F5D````$$/
-MMDA$A,D/A-W[__](BUPD($D[6&"X`0```'0?,=*#P@$XR@^$P/O__P^VPDB+
-M7"0@23M<P&!UYHU"`4&(A9L```#IHOO__T'&A9@````J0<:%D`````KI0_S_
-M_TF-AU`"!`!!B[=8`@0`0<:%F@````%)B960````28F%H`````^W1"0.9D&)
-MA9@```!!#[9X1$"$_W0V2(M4)"!).U!@N`$````/A*4````QTNL6#[;*2(M<
-M)"!(8\%).US`8`^$A````(/"`4`X^G7B#[=$)`XQTDG'AX@"!```````2<>'
-M<`($``````!-B:]X`@0`3(G_2<>'@`($``````#!X`F-1`;_]_9)C;=H`@0`
-M08F':`($`$B+7"0H2(ML)#!,BV0D.$R+;"1`3(MT)$A,BWPD4$B#Q%CI````
-M`,=#4/W____I&/K__[@!````T^!!B(6;````Z7'___]F9F:09F9FD$B#[%A(
-MA?9(B5PD*$B);"0P3(G#3(E\)%!,B60D.$B)]4R);"1`3(ET)$A!B<]-BV`0
-MB7PD%$B)5"0(18NT)%@"!`!T"?:&80(```1T24B-<UC'0U#^____2,=#6```
-M``!(B5M@2,=#:`````!,B>=(BUPD*$B+;"0P3(MD)#A,BVPD0$R+="1(3(M\
-M)%!(@\18Z0````!(BT8(#[9("H3)=*M!#[?'2`-$)`A(B40D&`^V5D0/ML$I
-MPDB+1BA(8])(B=$QTDCW\4@Y1"08#X=Z____28V$)/````!(B<=(B40D(.@`
-M````2(7`28G%#X1L`@``BW4T3(GGZ`````!(A<!)B<`/A$@"``!(BT0D&$B+
-M3"0(2<=%$`````!)QT4P`````$G'12@`````2<=%.`````!)B44(28U%&$F)
-M30!!QT5``0```$V):'A)B44828E%($'&@+`````!BP4`````28E86(7`?@P[
-MA=P"```/G\`/ML!!B4!H2(M%"(!X"0`/A,@```"+3"04@>D+_P``@_D:#X?L
-M`0``N`$```!(T^"I`(``!`^%*`(``*D`0``"#X40`@``J0$```$/A,,!``!!
-MQH":`````0^V345)QX#``````````$C3;"0(28EH4$B+3"0(0<:`L@````!)
-MQX#(`````````$F)B)````!)@WPD2``/A-0!``!)BTPD0$F-4!A)C40D.$F)
-M5"1`28E`&$F)2"!(B1%(BUPD*$B+;"0P3(MD)#A,BVPD0$R+="1(3(M\)%!(
-M@\18PT$/M\<QTHM,)!3!X`E!C40&_X'I"_\``$'W]H/Y&HG&#X<1`0``N`$`
-M``!(T^"I`(``!`^%,P$``*D`0``"#X49`0``J0$```$/A.@```!!QH":````
-M`4F-A"10`@0`28EH4$G'@,``````````2<>`R`````````!,B>=)B8"@````
-M2(M$)`AF18FXF````$'&@+(`````28F`D````$&)M"1H`@0`28VT)&@"!`!)
-MQX0DB`($``````!)QX0D<`($``````!-B80D>`($`$G'A"2``@0``````$B+
-M7"0H2(ML)#!,BV0D.$R+;"1`3(MT)$A,BWPD4$B#Q%CI`````$B+?"0@3(GN
-MZ`````!(BWL02(US6,=#4/W___](QT-8`````$B)6V!(QT-H`````.GG_/__
-M2(M\)"!,B>Y,B00DZ`````!,BP0D3(G'Z`````!,BV,0Z9_\__\!]D'&@)H`
-M```"Z>O^__]!QH":`````^G>_O__0<:`F@````+I]OW__T'&@)H````#Z>G]
-M__](BUPD*$B+;"0P3(G'3(MD)#A,BVPD0$R+="1(3(M\)%!(@\18Z0````"0
-M2(/L&$B)'"1,B60D"$B)^TR);"002(M'*(LX1`^W8`Q,BV@$Z`````"+>QA)
-MB=A$B>%,B>I(BQPD3(MD)`A,BVPD$$B)QDB#Q!CIH?O__Y!(@^P82(D<)$B)
-M;"0(2(G[3(ED)!!(BT<HBSA,BV`$#[=H#.@`````@'@0`4B)QG0CBWL8#[?-
-M28G83(GB2(L<)$B+;"0(3(MD)!!(@\08Z4S[__^+>Q@/M\U)B=A,B>)(BQPD
-M2(ML)`A,BV0D$$B#Q!CI*?3__V9FD&9FD&9FD$B#[!A(B1PD2(EL)`A(B?M,
-MB60D$$B+1RB+.$R+8`0/MV@,Z`````"`>!`!2(G&=".+>Q@/M\U)B=A,B>)(
-MBQPD2(ML)`A,BV0D$$B#Q!CIS/K__XM[&`^WS4F)V$R)XDB+'"1(BVPD"$R+
-M9"002(/$&.FI\___9F:09F:09F:02(/L&$B)'"1,B60D"$B)^TR);"002(M'
-M*(LX1`^V8`A$BV@$Z`````"+>QA)B=A$B>%,B>I(BQPD3(MD)`A,BVPD$$B)
-MQDB#Q!CI4?K__Y!(@^P82(D<)$B);"0(2(G[3(ED)!!(BT<HBSA$BV`$#[9H
-M".@`````@'@0`4B)QG0DBWL80`^VS42)XDF)V$B+;"0(2(L<)$R+9"002(/$
-M&.G[^?__BWL80`^VS42)XDF)V$B+;"0(2(L<)$R+9"002(/$&.G7\O__9F9F
-MD&9FD$B#[!A(B1PD2(EL)`A(B?M,B60D$$B+1RB+.$2+8`0/MF@(Z`````"`
-M>!`!2(G&="2+>QA`#[;-1(GB28G82(ML)`A(BQPD3(MD)!!(@\08Z7OY__^+
-M>QA`#[;-1(GB28G82(ML)`A(BQPD3(MD)!!(@\08Z5?R__]F9F:09F:0055!
-MB?5!5%5(B?U32(/L"(7VB;5<`@0`=#%(B?M%,>1$B>!(B>]!@\0!2,'@!$B-
-MM`58`@``Z`````!(B8-0`@``2(/#$$4Y['752(L%`````,>%8`($`!(```!(
-MA<!T&HM0$#F58`($`'8&B95@`@0`2(M`"$B%P'7F2(/$"%M=05Q!7<-F9F:0
-M9F:09F:055-(B?M(@^P(1(N'7`($`$6%P'0L,>V)Z$B)WX/%`4C!X`1(`=A(
-MBY!8`@``2(NP4`(``.@`````.:M<`@0`=];'@UP"!```````2(G?2(/$"%M=
-MZ0````!F9F:09F:055-(B?M(@^P(@+^P`````TB+;U@/A(P````/MH.R````
-M/!`/A)$````\!70C=Q,L`0^$D0```,=%4/____]FD.L5/`L/A8<```!F9I!F
-M9I#'15#]____2(MS>$B%]G0/2(L[2(''\````.@`````2(L[Z"G___](B=_H
-M`````$C'15@`````2(EM8$B-=5A(QT5H`````$B+?1!(@\0(6UWI`````/:'
-MFP````$/A&?____&A[(````02(M%,,8``<:#L@````''15``````ZX8\#0^$
-M=____\=%4/_____I<O___V9F9I!F9F:09F:054B)_5-(@^P(2(M?6(M#&#TD
-M_P``=&D]&?\``'1B@+VR````$'9RQT-0_____V:02(M]`$B+=7A(@<?P````
-MZ`````!(BWT`Z&/^__](B>_H`````$C'0U@`````2(E;8$B-<UA(QT-H````
-M`$B+>Q!(@\0(6UWI`````&9F9I"`O;(````,=$Q(BT,PQ@``@+VR````$'>.
-M2`^^C;(```"X`0```$C3X*D@*0$`=12H`@^$;____\=#4`````#I;/___\=#
-M4/W___]F9I!FD.E;____2(M#,+\1````Q@`!2(MU4.@`````QH6R`````>O%
-M9F9FD&9FD&9FD&9FD$B#[!A(B5PD"$B);"002(G[@W\<!TB+1RB+*'8&@W\@
-M`W<=QT-0_O___TB+7"0(2(ML)!!(@\08PV9F9I!F9I")[^@`````2(7`=->)
-M[^@`````2(L02#M3$'0)QT-0_/___^O%2(-X&`!UMX!X$`1VL8MP,(/^_W2P
-M2(MZ".@`````A<!TH\=#4/____]FD.N89F9FD&9F9I!F9I!F9I!(@^P82(D<
-M)$R)9"002(G[2(EL)`A$BX^$`P``28GT187)=0I(@[_@`P```'05,<!(BQPD
-M2(ML)`A,BV0D$$B#Q!C#BW<P@_[_=!!(BP=(BW@(Z`````"%P'73@'L0!'8_
-M9O>#8`(``'`(=<*`>T0`="<Q[4B+?.M@2(7_=`Q,B>;H>O___X3`=*0/MD-$
-MC54!2(/%`3G0?]NX`0```.N0=!-,B>9(B=_H@V3__P^VP.E[____2(M[.$R)
-MYNAO9/__#[;`Z6?___]F9F:09F:02(/L"(!_$`1V%C'`2(._@`(```!T"DB#
-MQ`C#9F:09I#H"____TB#Q`@/ML##9F:0059!54%455-(BT\H2(G[2(M7,(L!
-MQP(`````08G&08G%08'F``$``$&!Y?\```!T?T4QY+T$````ZS-F9I!FD$B#
-M>!@`=5XQ]H!X$`5(B<=(#T/PZ'?___^$P'1(08/$`4B#Q01%.>QT1DB+2RB+
-M/"GH`````$6%]G7%2(-X&`!U(V;W@&`"``!P"'48BW`P@_[_=,A(BP!(BW@(
-MZ`````"%P'2X2(M3,$&-1"0!B0)(QT-8`````$B)6V!(C7-82,=#:`````!(
-MBWL06UU!7$%=05[I`````&9F9I!F9I!!5S'2059!54%428G\55-(@^P(2(M/
-M*(L!]L3_08G%#Y3"08'E_P```(E4)`1(BU<P00^5QT6$_T0/MG0D!,<"````
-M`'1K,>U%A/9T-F9FD(GHB>N+?($$Z``````Q]H!X$`5(B<=(#T/PZ('^__^$
-MP`^$N@```(U#`4B#Q0%!.<5W=46$_W0I,=MF9I!F9I!)BT0D*(G:2(/#`8M\
-MD`3H`````$B)Q^@`````03G==]]$BU0D!$6%TG5,0<=$)%``````2<=$)%@`
-M````38ED)&!)C70D6$G'1"1H`````$F+?"002(/$"%M=05Q!74%>05_I````
-M`$6$]G2&28M,)"CI2?___T6$_W2X28M$)"B+>`3H`````$B#Q`A(B<<Q]EM=
-M05Q!74%>05_IOWS__TF+5"0PC4,!0<=$)%#_____B0+I>____V9F9I!F9I!(
-M@^Q(2(E<)#!(B6PD.$B)^TR)9"1`2(MO6$R+9U"!?1A"_P``#X2E````#[:'
-MFP```$B+53"(0@H/MX>4````B$(&#[>'E@```(A"!P^WAY@```"(0@@/MH>:
-M````B$()#[>'D````(A"!`^WAY(```"(0@4/MX><````B$(+@+NR`````0^$
-MJP```,=%4/____](B=_H`````$B+?1!(C7582,=%6`````!(B6U@2,=%:```
-M``#H`````$B+7"0P2(ML)#A,BV0D0$B#Q$C##[:'FP```$B+53"(0@\/MX>4
-M````9HE""`^WAY8```!FB4(*#[>'F````&:)0@P/MH>:````B$(.#[>'D```
-M`&:)0@0/MX>2````9HE"!@^WAYP```!FB4(0@+NR`````0^%5?___XM%&,=%
-M4``````]0O\``'15/1C_```/A4#___](BT4H@'@*\@^%,O___TF+1"1H2(GF
-M28N\)(````#_4'A(BU0D&$B!P@`!```/M@*H!`^$"/___X/@^TR)YX@"Z```
-M``#I]O[__TB+12B`>`_R#X7H_O__9F:09I#KKV9F9I!F9F:09F:09F:0058Q
-MP$%505154TB)^V9FD,8$&`!(@\`!2(/X+'7RQP,L````Z,=2__^(0P1(BP4`
-M````2(,X``^40P5(BST`````Z`````#!X`P]____`0^&CP```,9#!@7&0P<+
-M#[9#"T&\!0```$4Q[44Q]L9#"`#&0PD!QD,*#X/@_H/("(A#"^LA1(GHQD0K
-M'$"#R"!!@_P%1`]$Z$&#Q@%!@\0!08/\#70N1(GGZ`````!(A<!TZ42)YT$/
-MMN[H\E/__T&#_`:(1"L,=;Q!@\U`QD0K'`+KQ$&`_6!T&%M=05Q!74%>,<##
-MQD,&!\9#!P?I;/___TB+!0````"#N*0"!``#=MA!#[;&QD0##!+&1`,<0#'`
-M6UU!7$%=05[#9F:09F:04TB)^TB+?S#HT_[__X7`=`?'0U#_____2,=#6```
-M``!(B5M@2(US6$C'0V@`````2(M[$%OI`````&9FD&9FD$%6055)B?U!5%53
-M2(/$@$R+9Q!,B>?HI5S__T6+G"2@`@0`187;#X61````28ML)!!!QX0DH`($
-M``$```!(A>T/A*T```!(BT4(2(M]$$B)YO]0.`^V1"0000&$)*`"!`"`?"00
-M`'0U,=MF9I!F9I!(B>E(Q\(`````B=Y(B>_H`````(3`=0E!@ZPDH`($``$/
-MMD0D$(/#`3G8?]-(BVT`2(7M=:!!BX0DH`($`(/H`87`08F$)*`"!`!T0DF+
-M?1!)C7580<=%4/S___])QT58`````$V);6!)QT5H`````.@`````2(/L@%M=
-M05Q!74%>PT''A"2@`@0``````$F-M"0X`@``28U\)$A)QX0D.`(```````!-
-MB:0D0`(``$G'A"1(`@```````.@`````ZXIF9F:09F:09F:09F:0Z0````!F
-M9F:09F9FD&9FD$B#["A,B60D&$R);"0@28G\2(E<)`A(B6PD$$F)]4B+;QB#
-MK:`"!``!A=(/B+0```#H`````$B%P$B)PP^$L0```(`]``````!U-4B)WK\"
-M````Z`````"+G:`"!`"%VW0^2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HPV9F
-MD&:0#[9`9*@"=<.H`0^%@P```/9#9`1UM8!+9"3KKV9F9I!(C;4X`@``2(U]
-M2$C'A3@"````````2(FM0`(``$C'A4@"````````2(M<)`A(BVPD$$R+9"08
-M3(ML)"!(@\0HZ0````!(C7\@Z`````#I9?___TF+1"0(3(GO_Y"`````28U\
-M)"!,B>[H`````.E%____2(G?Z`````!F9I!FD.EK____9F9FD&9F9I!F9I!(
-M@^P82(D<)$R);"002(G[3(ED)`A(BT<H1(M@!(LXZ`````!$B>=)B<7H````
-M`$R)[TB)QN@`````@_@!2(M[$$B-<U@9P$C'0U@`````2(E;8/?02,=#:```
-M``")0U!(BQPD3(MD)`A,BVPD$$B#Q!CI`````&9FD&9FD&9FD$%4@#T`````
-M`%5(B?U3='%(BU\83(UG&$PYXW4+ZS.02(L;3#GC="J`NX#\__\!2(V[</S_
-M_W7H]D/P`73B#[8U`````.@`````2(L;3#GC==;'A3@!````AY,#2,>%2`$`
-M``````!(C;4X`0``2(FM4`$``$B)[UM=05SI`````%M=05S#9F9FD&9FD&9F
-MD$%505152(G]4TB![,@```!,BV\02(MW*$B-1"0,28GD2(GGQ@<`2(/'`4@Y
-MQW7TNK````!!QP0D?`$``.@`````2(M=,#'V3(GB3(GOZ.['__^#^/^)`W4#
-MB4502(M]$$B-=5A(QT58`````$B);6!(QT5H`````.@`````2('$R````%M=
-M05Q!7<-F9I!FD%4QP$B)_5-(@^P(2(M?,)#&!!@`2(/``4@]@````'7P2(G?
-MZ%CZ__^%P'0NQT50_____TC'15@`````2(EM8$B-=5A(QT5H`````$B+?1!(
-M@\0(6UWI`````,<#@````,=#/``@```QT@^V1!H,@^`/@^@#/`)W!<9$&BP&
-M2(/"`4B#^A!UXNNJ9F9FD&9FD$%7059!54F)_4%455-(@^P(2(M'*$B+7S"+
-M*#'`9F:0Q@08`$B#P`%(/?H```!U\(GOZ`````!)B<0QP&9F9I#&!!@`2(/`
-M`4@]^@```'7PA>UT9DV%Y'1A28M$)"BZ_____TB)0P1)BT0D&$B%P'0&BY#H
-M`P``B5,,08M4)#"X_____X72#TG"B$,#28L$)$B+>`CH`````(A#`D$/MH0D
-M@0,``(A#`4$/MD0D$#P$=S\L`0^$LP$``$''15#_____2<=%6`````!-B6U@
-M28UU6$G'16@`````28M]$$B#Q`A;74%<05U!7D%?Z0````#&`P%)BT0D4$R)
-MYV:)@^@```#HB%#__XF#Y````$F+A"1P`@``2(E#($F+A"1X`@``2(E#*$$/
-MMGPD$.AO3?__B(.$````00^V1"1%3(GGB(.%````28N$)&@"``!(B8/0````
-MZ":Z__],B>>)@X@```#H`````,:#A@````")@\P```!!@'PD1``/A&@!``!%
-M,?9%,?]+BVST8$B%[0^$$P$``("[AP`````/A!<!``"`?1`$#X0F`0``BX7H
-M`P``0HF$LXP````/MI.&````08/'`4F#Q@&#P@&(DX8```!!#[9$)$1$.?@/
-MCZ\````/MM*#^@]_%DACPH/"`8/Z#\>$@XP```#_____?NI)BX0D@`(``$B%
-MP`^$LO[__TB+4`BY_____TB%TG0&BXKH`P``B8O8````2(M0$+G_____2(72
-M=`:+BN@#``")B]P```!(@W@(``^$<_[__TB#>!``#X1H_O__3(GGZ`````")
-M@^````#I5?[__TB-<R#&`P),B>?HA-;__X7`#X4V_O__Z3G^__]F9F:09F:0
-M08/_#P^/1____TN+;/1@2(7M#X7M_O__0L>$LXP`````````Z0'___\/MGT0
-MZ-Y+__^(@X<```"`?1`$#X7:_O__2(M%.(N`Z`,``$*)A+.,````Z='^__\Q
-MTNGY_O__059!54F)_4%455-(BT<H2(M?,(LH,<#&!!@`2(/``4@]V````'7P
-MB>_H`````$F)Q#'`Q@08`$B#P`%(/=@```!U\(7M=#A-A>1T,TF+1"0HNO__
-M__](B4,$28M$)!A(A<!T!HN0Z`,``(E3#$$/MD0D$#P$=SDL`0^$"@$``$''
-M15#_____2<=%6`````!-B6U@28UU6$G'16@`````28M]$%M=05Q!74%>Z0``
-M``#&`P%)BX0D<`(``$B)0Q!)BX0D>`(``$B)0QA!#[9\)!#HVDK__XA#=$$/
-MMD0D14R)YXA#=4F+A"1H`@``2(F#P````.B7M___3(GGB4-XZ`````#&0W8`
-MB8.\````08!\)$0`#X2T````13'VZS2`?1`$=%`/ME-VBX7H`P``B423?`^V
-M0W:#P`$\#XA#=G=D00^V1"1$08U6`4F#Q@$YT'Y22XML]&!(A>UTY(![=P!U
-MO`^V?1#H1$K__XA#=X!]$`1UL$B+53@/MD-VBY+H`P``B52#?.NJ2(US$,8#
-M`DR)Y^C(V?__A<`/A=_^___IXO[__P^V4W:#^@]F9F:0#X_1_O__2&/"@\(!
-M@_H/QT2#?/____]^[>FY_O__,=+KY&9F9I!F9F:09F:09F:0059!54F)_4%4
-M55-(BT<H2(M?,(LH,<#&!!@`2(/``4@]K@```'7PB>_H`````$F)Q#'`Q@08
-M`$B#P`%(/:X```!U\(7M=#=-A>1T,DF+1"0HNO____^)0P1)BT0D&$B%P'0&
-MBY#H`P``B5,(00^V1"00/`1W.2P!#X0)`0``0<=%4/____])QT58`````$V)
-M;6!)C7582<=%:`````!)BWT06UU!7$%=05[I`````,8#`4F+A"1P`@``2(E#
-M#$F+A"1X`@``2(E#%$$/MGPD$.C[2/__B$-P00^V1"1%3(GGB$-Q28N$)&@"
-M``")@YP```#HN;7__TR)YXE#=.@`````QD-R`(F#F````$&`?"1$``^$L```
-M`$4Q]NLT@'T0!'10#[93<HN%Z`,``(E$DW@/MD-R@\`!/`>(0W)W9$$/MD0D
-M1$&-5@%)@\8!.=!^4DN+;/1@2(7M=.2`>W,`=;P/MGT0Z&9(__^(0W.`?1`$
-M=;!(BU4X#[9#<HN2Z`,``(E4@WCKJDB-<PS&`P),B>?HZM?__X7`#X7@_O__
-MZ>/^__\/ME-R@_H'#X_6_O__2&/"@\(!@_H'QT2#>/____]^[>F^_O__,=+K
-MY&9F9I!!54F)_4%455-(@^Q(2(M?*(L[A?]U=$B++0````#&1"0P!DB%[70W
-M3(UD)#!(BUT02(7;="!(BT,0,?],B>9(B40D.$B+0PC_D,````!(BQM(A=MU
-MX$B+;0!(A>UUSDF+?1!)C7582<=%6`````!-B6U@2<=%:`````#H`````$B#
-MQ$A;74%<05W#Z`````!(B<4/MD,$3(UC!(3`=3N`?1`!#X0B`0``0<=%4/[_
-M___V1600=*A(BT5H2(N]@````$B)YO]0>`^V1"0.2(GOB$5BZ`````#KA2P!
-M=`U!QT50_O___^ET____@'T0!)!VMT$/MD0D`3P!=$=F9F:0#X/*`0``08-]
-M'!AF9I!FD'672(V5<`(``#'`Q@00`$B#P`%(@_@0=?))BT0D!$B)`DF+1"0,
-M2(E""("-8`(```3K;D&#?1Q(#X5;____2(V-C`(``#'`Q@0(`$B#P`%(@_@$
-M=?))BT0D!$F-5"0$2(D!2(M""$B)00A(BT(02(E!$$B+0AA(B4$82(M"($B)
-M02!(BT(H2(E!*$B+0C!(B4$P2(M".$B)03B`C6`"```$]H5@`@``!`^$H?[_
-M_TB)[^@`````Z93^__]!@'PD`04/A]+^__]!#[9$)`%F9I#_),4`````08-]
-M'`EF9F:0#X6S_O__QD0D,`E!#[9$)`1(C70D,(A$)#A(BT5H2(N]@````/^0
-MP````$&)15#IC?[__T&#?1P)#X5Z_O__QD0D,`5!#[9$)`3&1"0Y`(A$)#A(
-MBT5H2(UT)#!(B[V`````_Y#`````08E%4(!-9!#I2_[__T&#?1P)#X4X_O__
-MQD0D,`1!#[9$)`3&1"0Y`(A$)#CKO$&#?1P)#X47_O__QD0D,`-!#[9$)`2(
-M1"0XZZ!!@WT<"0^%^_W__\9$)#`"Z^)!@WT<"0^%Z?W__X!-9(#&1"0P`.O,
-M9F:09I`\`G0-0<=%4/[____IT/[__T&#?1P)#[:U@0,```^%MOW__P^V0PA(
-MC7L(0#C&=$"`?1`$B(6!`P``=C2`?40`="XQR4B+5,U@2(72=!.`>A`$=@T/
-MMH6!`P``B(*!`P``#[9%1(U1`4B#P0$YT'_40(#^`G0,@(U@`@``!.E?_O__
-M@#\"=.](Q\(`````3(GN2(GOZ#=K___I$OW__V:005152(G]4TB+7RB+.TR-
-M8P3H`````$B)QHM#!*@!=#I(C99P`@``,<!F9F:09F:0Q@00`$B#P`%(@_@0
-M=?))BT0D!$B)`DF+1"0,2(E""(".8`(```1!BP0DJ`)T8TB-CHP"```QP,8$
-M"`!(@\`!2(/X0'7R28M$)!1)C50D%$B)`4B+0@A(B4$(2(M"$$B)01!(BT(8
-M2(E!&$B+0B!(B4$@2(M"*$B)02A(BT(P2(E!,$B+0CA(B4$X@(Y@`@``!/:&
-M8`(```1T"$B)]^@`````2,=%6`````!(B6U@2(UU6$C'16@`````2(M]$%M=
-M05SI`````&9FD&9FD&9FD$%505154TB)^TB![,@```!,BV<H2(GE08L\).@`
-M````28G%2(U$)`Q(B>=F9I!FD,8'`$B#QP%(.<=U]$F-="0$NK````#'10!\
-M`0``Z`````!(BWL02(GJ3(GNZ*^[__^%P(G"="R#^/]T-4B+0S!(BWL02(US
-M6$C'0U@`````2(E;8$C'0V@`````B1#H`````$B!Q,@```!;74%<05W#B4-0
-MZ\9F9F:09F:09F:005152(G]4TB+1PA(BQB+LV@"!`!(B=],BZ/@`0``Z)WE
-M__](BU4(2(M%$(MP-#ER-`]#<C1(BSKH`````$B%P$F)P`^$I`$``(L5````
-M`(72?A!(BT4(.Y#<`@``#Y_`#[;008E0:$'&@+(`````#[:%J@```(3`#X7H
-M````2(U%2$F)0'!(BT4(08"(L0````*+BU@"!`!)B4!0#[>%F@````^WE9@`
-M```IPHG(BXM@`@0`P>@)@^D!#Z_!.<(/1]"X``$``&:!^@`!#T;"9D&)@)@`
-M``"`?2@`#X3R````0?:`L0````0/A.0````/MX68````00^WD)@```!(`X60
-M````2"G0#[>5F@```$@IT$F)@)````!!@(BQ````"$V)8%A(@WM(`$G'@,@`
-M````````2<>`P``````````/A`0!``!(BTM`28U0&$B-0SA(B5-`28E`&$F)
-M2"!(B1%;74%<PSP##X00____2(M%$$&`B+$````$28E`4(N#7`($`(7`#X3*
-M````BXM8`@0`,?9(BY-0`@0`B?!(P>`$A<E(BQ00=!J)R&9FD&:0Q@(`2(/"
-M`4B#Z`%U\XN+6`($`(/&`3FS7`($`'?&Z<G^__\/MX6:````2`.%D````$F)
-M@)````#I+/___P^VA:H```"$P'5,2(M]"$B-=4CH`````$B+10A(BSCH/^3_
-M_T''1"10_____TG'1"18`````$F-="1838ED)&!)QT0D:`````!;74F+?"00
-M05SI`````#P#=;WKKEM=05Q,B<?I`````(N+6`($`.D[_O__9F9FD&9F9I!F
-M9F:09F:02(/L*$B);"002(G]2(E<)`A,B60D&$R);"0@#[:%L@```$B+5U!,
-MBV=82(L_2(N:@`(``#P!=$@\`@^$5P$``$B-<S#&A;(`````2(/'2$C'0S``
-M````2(EK.$C'0T``````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HZ0`````/
-MMX.:````9@.%F````$@[4PAFB8.:````#X3G`@``#[>#F@```&8[@Y@````/
-M@XT!```/MH6Q````2,=%>`````!(QT5P`````(/@_8/(!(B%L0```$B+4Q!(
-MB550QH6R``````^W@YH````/MY.8````BX]@`@0`@^D!*<*+AU@"!`#!Z`D/
-MK\$YP@]'T+@``0``9H'Z``$/1L)FB868````@'LH`'0-]H6Q````!`^%;@(`
-M``^W@YH```!(`X.0````2(F%D````/:%L0````(/A/T!``!(@W](``^$\@$`
-M`$B+3T!(C5482(U'.$B)5T!(B4482(E-($B)$4B+7"0(2(ML)!!,BV0D&$R+
-M;"0@2(/$*,-(BT,(QH.K`````8"@@`,``/Y(BT,0@*"``P``_DB+0PB`H&$"
-M``#W2(M#$("@80(``/=(BT,(2(LXZ`KB__\/MH.J````A,`/A/L````\`P^$
-M\P```$B)[^@`````0<=$)%#_____28M\)!!)C70D6$G'1"18`````$V)9"1@
-M2<=$)&@`````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HZ0````!F9F:02(N:
-M@`(``(![*`!(BTL(2(M3$$0/MJNJ````#X21````#[>#F````$B+DZ````!(
-M*<)!@/T!2(F3H`````^$<P$``$&`_0(/A'\!``!(@[N@``````^%CP```$B+
-M.>@]X?__183M#X0X`0``08#]`P^$+@$``$B)[^@`````2(G?2(ML)!!(BUPD
-M"$R+9"083(ML)"!(@\0HZ1*;__]FD$B+>PA(C7-(Z`````#I^_[__P^W@Y@`
-M``!(`X.@````183M2(F#H````'5I2#M!*'4'QH.J`````4B+0BA(.8.@````
-M#X1Q____2(LYZ*[@__]%A.T/A)<```!!@/T#D`^$C````$B)[^@`````9I#I
-MJ?[__TB)[TB+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*.D`````08#]`W6>2#M!
-M*'68Z17___]F.X.8````9F:0#X)(_?__9L>#F@``````Z?O\__\/MX.8````
-M#[>3F@```$@#@Y````!(*=`/MY68````2"G02(F%D````.EY_?__2(M["$B-
-M<TCH`````.EB____2(M["$B-<TCH`````.G`_O__2#M1*`^%C?[__\:#J@``
-M``#I@?[__T@[42@/A7?^___I@/[__V9FD&:0]H>Q`````DB+!\:'L@````!T
-M(TB#>$@`=!Q(BTA`2(U7&$B)4$!(@\`X2(E'&$B)3R!(B1'#Z0````!F9I!F
-MD%-(B?M(BS^+MV@"!`#HWM[__TB+`TB#>$@`=!U(BTA`2(U3&$B)4$!(@\`X
-M2(E#&$B)2R!(B1%;PTB)WUOI`````&9F9I!F9F:09F:09F:02(/L.$B)7"0(
-M2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$B+7UA,BW=@3(LK38NEX`$``$F+
-M1"0H1(LXZ`````"`>Q`$#X:=````2(NK@`(``$B%[0^$[0```$B+?0A(A?]T
-M#+H"````,?;HD+#__TB+?1!(A?]T#+H"````,?;H>[#__TB+11A(BU4@28V]
-MT````$B)[DB)4`A(B0+H`````$&-7@%$.?MT5$F+1"0HB=J+?)`$Z`````")
-MWDB+;"002(M<)`A,BV0D&$R+;"0@2(G'3(MT)"A,BWPD,$B#Q#CI"&'__TB)
-MWT&-7@'H`````$0Y^W6S9F9FD&9FD$F+?"0028UT)%A)QT0D6`````!-B60D
-M8$G'1"1H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#CI
-M`````+H"````,?9(B=_HJ:___^E'____9F9FD$B#["A,B60D$$B)7"0(28G\
-M3(EL)!A,B70D($R+=PA(BU\028L&2(G>3(GW3(NHX`$``.A(1?__2,>#@`(`
-M``````!)QX:``@```````$$/MI:``P``#[:#@`,``$F-=5B#X@2#X/L)T(B#
-M@`,``$$/MI:``P``@^#]@^(""="(@X`#``!!#[9&2(A#2$F+?1!)QT58````
-M`$V);6!)QT5H`````.@`````2(G>OQ4```#H`````$F+5"0828M$)"!)C70D
-M,$F+/DG'1"0P`````$V)9"0X2<=$)$``````2(E""$B)$$B+7"0(3(MD)!!,
-MBVPD&$R+="0@2(/$*.D`````D)"0D)"0D)"0D)"02(N'V`,``$B%P'0?2(M6
-M"$@Y$',-2(L.2#E("`^'JP```$B+0!!(A<!UY4B+EZ`#``!,C8>@`P``3#G"
-M=#IFD$B-0NB`N+``````=2-(BXB0````#[>`F````$@!R$@Y!G,-2#M."')D
-M9F9FD&9FD$B+$DDYT'7(2(N/L`,``$B!Q[`#``!(.?EU%^M&9F:0@/J`=!Q(
-MBPE(.?EF9I!FD'0Q2(U!Z`^VD+````"$TG7?2(N0D`````^W@)@```!(`=!(
-M.09SSD@[5@ASR+@!````PS'`PV9F9I!F9I!F9I!(@^P02(D<)$B);"0(2(G[
-M2(GUZ`C___^%P'4B2(N#V`,``$B)11!(B:O8`P``,<!(BQPD2(ML)`A(@\00
-MPTB#?2@`N/____]TYDB+@^`#``!(C9/@`P``2(7`=`U(C5`02(M`$$B%P'7S
-MN/____](B2KKO&9F9I!F9F:09F9FD$B+A]@#``!(C9?8`P``2#GP=`U(C5`0
-M2(M`$$@Y\'7S2(M.&$B+1A!,C4X83(N'T`,``$DYR4B)`DC'1A``````=!U(
-MBU8@28L`3(E!"$F)"$B)4`A(B0),B4X@3(E.&$B+!\=`:`$```##9F:09I!(
-M@S\`=`U(BT<(2(EP$$B)=PC#2(EW"$B)-\-F9I!FD$B#QUCI`````&9F9I!F
-M9I!32(N'@````$B)^TB%P'042,>'@`````````!(B[>(````_]!(BX/(````
-M2(L[2(US*$B)6S!(QT,X`````$B)0RA(@\=86^D`````9F9FD$B#[!A(B5PD
-M"$B)^TB);"002(MO4.@`````2(MS>$B+4QA(C4L82(M#((.MB`,```&#K80#
-M```!2(7V2(E""$B)$$B)2R!(B4L8=!9(B>](BUPD"$B+;"002(/$&.D`````
-M2(M<)`A(BVPD$$B#Q!C#9F9FD&9F9I!F9F:09F:0055!5%532(GSB=9(@^P(
-M3(M'6$R+IY````!$#[>OF````$F+B+@```!)BZB0````2(7)#X2H````00^V
-M@+$````/M]*#X`$/ML`YT`^$CP```$2+`42)YRGOP><)1#G'1(G`<PWII@``
-M`&9FD&9FD(G02(/!$(G"`Q$YUW/R1(L!*<=!#[?UB?I(`U$(02GXP>8)1(D#
-M1#G&2(E3"$B-4Q!V)4B+01@K,\=#!`````!(B=-(B4((BT$02(/!$(D"2(/"
-M$#GP<MN),\=#!`$```!(@\0(6UU!7$%=N`$```##28N`P````$B%P'06B?),
-MB<=(B=[_T(7`=`A(B=GI3____TB#Q`@QP%M=05Q!7<,QP.EJ____9F:09F:0
-M9F:0055!5%532(G[2(/L"("_L`````!(BV]0#X42`@``#[>'F````$R+IY``
-M``!*C0P@2(N%V`,``$B%P'0V#[:7L0```(/B0(32=`>+<$"%]G052#E#<'0/
-M2#L(=@I,.V`(#X+R`@``2(M`$$B%P&9FD'742(-[<``/A*$"``"`?1`$#X:I
-M`0``3(NM@`(``$V%[0^$/0(``$&`O:L`````#X4O`@``]H.Q````"`^%(@(`
-M`$B!N\@`````````#X01`@``23MM"`^%!P(``$&`?2@`#X3H`@``28N%H```
-M`$DYQ`^#(P$``$@YP0^&XP$``$B+>PB#1P@!Z`````!(B<=(BP-(B0=(BT,(
-M2(E'"(M#:(E':$F+10A,B:>0````2(E'4+Z`____28N%H````$B)7UC&A[(`
-M````2,>'P`````````!(QX?(`````````$C'A[@`````````9D0IX&:)AY@`
-M```/MH>Q````#[:3L0```(/@/R'6B=&#X4`)\+XP````"<@AUHG1@^#'@^$(
-M"?`)R(G1@^("@^$$@^#Y"<@)T`^VD[$```"#X/Z#X@$)T(B'L0```$B+4W"X
-M`0```$B%TD@/1<)(C5,82(E'<$F+10A(BXBX`P``2(F0N`,``$@%L`,``$B)
-M0QA(B4L@2(D1QH.P````@$B#Q`A;74%<05WI`````$F+11"#K80#```!2(E#
-M4$B)Q8.`A`,```&`>!`$#X>F````9I!(BY6@`P``2(V-H`,``$@YRG4L2(L#
-M2(E+&,=`:`$```!(C4,82(E!"$B)A:`#``!(B4L@2(/$"%M=05Q!7<.#>V@`
-M=3=(B[6H`P``2(U^Z(M':(7`#X@5`0``2(U#&$B)2QA(B86H`P``2(D&2(ES
-M($B#Q`A;74%<05W##X[,````2(U#&$B)4QA(B4((2(F%H`,``$B)2R!(@\0(
-M6UU!7$%=P_:#L0````0/A$_____VA6$"```@#X1"____@*5A`@``W^@`````
-M@(U@`@``!(E%/$B+`\>`E`($``$```!(BT582`E%4.D2____]H.Q````0`^%
-M4OW__TB+A>`#``!(A<!U%NE!_?__9F9FD$B+0!!(A<`/A##]__](.PAV[DP[
-M8`ASZ$B+2"!(C5,82(E0($B#P!A(B4,82(E+($B)$4B#Q`A;74%<05W#2(N5
-MJ`,``$B-0QA(B4L82(F%J`,``$B)`DB)4R#IQ/[__X-':`%(BU8(2(U#&$B)
-M<QA(B48(2(D"2(E3(.FD_O__28N%H````$@YP0^&._[__TDYQ`^#^_[__TB+
-M>PB#1P@!Z`````!(B<=(BP-(B0=(BT,(2(E'"(M#:(E':$F+11#I$_W__V9F
-M9I!F9I!F9I!32(M'4$B)^TB+=WB#@(0#```!2(7V="E(B7XP2(M_4$C'1B@`
-M````2,=&.`````#H`````(7`=1=(BT-X2(E#<$B)WUOI`````&9FD&9FD%O#
-M9F9FD&9F9I!F9I!F9I!52(GY4TB#[`B`N;(````!2(M?6$B+?U!$#[>)F```
-M``^WLY@```!(BZ^``@``=$$/MH&R````2(M["$B)SL:#L`````"(@[(```#H
-M`````$B+0PA(B=^#:`@!2(M%"(.`B`,```%(@\0(6UWI`````$B+@Y````!(
-M.8&0````=:^+04!,BT%(A<!T$HG"3(G`Q@``2(/``4B#Z@%U\TB+10A(.?AT
-M,DB)05!(BX6@````9D0ISF:)L9@```#&@;(`````2(G/2(F!D````$B#Q`A;
-M7>D`````2(M%$.O(D$%72(U'&$R-?UA!5D%528G]05154TB#[!A(B40D"$B-
-M1SA(B00D0<=%:`````#K&TB+0A!(A=))B458="U(QT(0`````$B+>@C_$DF+
-M55A).U5@==M(A=))QT5@`````$G'15@`````==--BW483#MT)`@/A&4"``#'
-M1"04`````$BX(````/____])A4;P28VN</S__TF-7A!T",=$)!0!````3(VE
-ML`,``&9FD&:02(N-H`,``$@YV0^$D@```$B+$4B+00A(B<](@^\82(E""$B)
-M$$B)20A(B0ET=`^VE8`#``#VP@$/A&(!``!$BY6(`P``1872=`^+A<0#```[
-M1V@/CZL!``"#XA@/A:(!``"+1VA,B6<8@X6(`P```8F%Q`,``$B+A;@#``!(
-MB8VX`P``2(D(2(E'($B+10C_4"A(BXV@`P``2#G9#X5N____3(VER`,``&9F
-M9I!F9I!(BXW(`P``3#GA=&1(BQ%(BT$(2(G+2(/K&$B)0@A(B1!(B4D(2(D)
-M=$9(BW-X2(7V="E(B5XP2(M[4$C'1B@`````2,=&.`````#H`````(7`=:Q(
-MBT-X2(E#<$B)W^@`````2(N-R`,``$PYX76<2(.]X`,```!,C:7@`P``="E)
-MBQPD2(7;="!(B=Y(B>_HR_3__X7`#X2$````3(UC$$F+'"1(A=MUX$V+-DP[
-M="0(#X5I_O__1(M,)!1%A<D/A+@```!)@WU8``^%]?W__T&+?6B%_P^%Z?W_
-M_TB#Q!A;74%<05U!7D%?PV9F9I#&A[(````"2(N%N`,``(.%B`,```%(B8VX
-M`P``3(EG&$B)1R!(B0CH`````.DO_O__2(M#$$B-<RA,B?])B00D2(N%V`,`
-M`$B)0Q!(B9W8`P``Z`````!!QT5H`0```.DM____2(N%H`,``$B-5QA,C:7(
-M`P``2(E0"$B)1QA(B5\@2(F5H`,``.F"_O__18N%E`($`$6%P'0=ZVU(BT(0
-M28E%2$B%TG112,="$`````!(BWH(_Q))BU5(23M54'7;2<=%4`````!)QT5(
-M`````.O12(L12(M!"$B)STB#[QA(B4((2(D02(E)"$B)"0^$X?[__^@`````
-M28M-.$@[#"1US^G-_O__0<>%E`($``````!,B>_H`````.N99I!32(L?2(-[
-M2`!T)$B+2T!(C5<82(U#.$B)4T!(B4<82(E/($B)$4B)WUOI`````.@`````
-MZ_"0D)"0D)"0D)"0,=)(A?]T#$B-1_^#P@%((<=U](G0PV9F9I!F9I!F9I!!
-M54G'Q?[___]!5%532(G[2(M[4$B+:QA(A?]U#?:#8`(```(/A9H```!%,>1(
-M"WM8Z`````!(BU,(1`'@#[92"CG0?D>`HX`#``#^]H.``P```70P2(7M="L/
-MMG5$0(3V=")(.5U@3(GH=$PQTNL-#[;*2&/!2#E<Q6!T,8/"`4`X\G7K6UU!
-M7$%=PTB+0U"`BX`#```!2(7`=+!(B<)(,U-8=3>`HV`"``#]ZYY(Q\#^____
-M2-/`2"%%6$B)Z^E,____2(M#"(!X"P$/A5C___]$#[9@"NE1____2(70D`^$
-M9O___X"+8`(```+I6O___V9F9I!F9F:09F:09F:02(MW&$0/MD9$183`="<Q
-MR3'22#E^8'45ZR!F9I!F9I`/MLI(8\%(.7S&8'0-@\(!1#C"=>NY_P```(G(
-MPV9FD$R+1CA-A<!T3TF+0!A(A<!T/DB+0!A(A<!T-4@Y^'1`#[901(72?NHQ
-M]DB+3/!@2(7)=`N`>1`$=@5(.?ET(4B#Q@$Y\G_C2(M`&$B%P'7+38L`387`
-M=;$QP,-F9I!FD+@!````PV9F9I!F9I!F9I!!5$F)U%5(B?532(G[2(/L$(!_
-M$`0/AH\```#'1"0,`````,=$)`@!````#[9/1(7)?B=(BW]@,=)(B=A(A?]T
-M$NF%````2(MX:$B#P`A(A?]U>(/"`3G*=>Q(BU,(@'H)`'0D#[9#1`^V4@HI
-MT`^O1"0(B40D"`^W0T8[1"0,#T9$)`R)1"0,2(7M=`>+1"0,B44`387D=`B+
-M1"0(08D$)$B#Q!!;74%<PTB%]G0&QP8`````387D=.=!QP0D`0```$B#Q!!;
-M74%<PTB-5"0(2(UT)`SH`````$B+4PB`>@D`=*3I>____V9F9I!F9I!32(G[
-M2(/L$$B+?PA(C50D"$B-="0,Z`````!(BWL02(UT)`1(B>+H`````(M4)`@[
-M%"2+1"0,#Y=#*#E$)`0/0T0D!`^OPKJ`````9H7`#T709HF3J````$B#Q!!;
-MPY!!5$F)]%53#[9'$$B)^SI&$'0-N`$```!;74%<PV9FD`^W1T1F.T9$=>F`
-M?T0`#X28````2(M_8$B+=F!(A?]TTC'M2(7V=,N`?Q`$=CB`?A`$=K_H````
-M`(3`=;8/ME-$C44!.<)^9$B+?.MH28MT[&A(@\4!2(7_=)A(A?9TDX!_$`1W
-MR(!^$`1WATB+1CA(.4<X#X5Y____2(M72$B+1DA(BT@(2#E*"`^%8____TB+
-M2!!(.4H0#X=5____]H-@`@```W26Z4?___\QP&:0Z4/___]F9F:09F9FD&9F
-MD%-(BU\(2(M'$$B%VW0R2(7`=&[V@X`#```!=3F`H(`#``#^QT,P_____X"C
-M@`,``/[&AZL````!6\-F9I!F9I!(A<!T[("@@`,``/[&AZL````!6\/V@(`#
-M```!=+[&AZL`````@(MA`@``!("(80(```3H`````$B)WUOI`````("C@`,`
-M`/[&AZL````!6\-F9F:09F9FD&9F9I!F9I!!5TF)]T%6055!5%5(B?U32(/L
-M&`^V5T2%T@^.C0$``$4Q[>F&````2(7`28EL)!AT"$C'0!@`````3HED[6`/
-MMI5@`@``2,>%:`(```````")T(/("J@@B(5@`@``=`F#RHJ(E6`"```/MDPD
-M%+@!````2-/@2`E%4$CWT$@A15A-A?\/A#L!``"`C6`"```$387_#X43`0``
-M#[951$&-10%)@\4!.<(/CO\```!$B6PD%$J+1.U@2(7`=`GV@(`#```!==1-
-MA?]-B?P/A5;___](BT4(#[9`"BG"2(M%*$ACTDB)T3'22/?Q2(D$)$B+10!(
-MBU@82(/`&$@YPW2:13'D2,=$)`C_____ZQ)FD$B+10!(BQM(@\`82#G8=%#V
-M0_`!3(VS</S__W3C@+N`_/__`77:]H/4_/__!'313(GV2(GOZ';[__^$P'7"
-M2(N#L/S__T@Y!"1WM4@[1"0(<ZY-B?1(B40D".ND9F9FD$V%Y`^$(?____:%
-M80(```)T:TF+1"0X2(7`=!=F9F:02(-X&``/A?_^__](BP!(A<!U[4J+1.U@
-MZ7O^___VA6`"```(=2%(@\086UU!7$%=05Y!7\-,B>:_!P```.@`````Z;/^
-M__](@\082(GO6UU!7$%=05Y!7^D`````2(LT)#'23(GGZ`````!(A<!)B<0/
-MA)/^__]*BT3M8.D7_O__9F9FD&9F9I!F9F:09F:0059!54%454B)_5-(@>P`
-M`@``@'\0!'8'@*=@`@``^_:%@`,```%T6H!]$`1V9(!]1`!T3C';2(M,W6!(
-MA<ET,P^VE8`#```/MH&``P``@^("@^#]"="(@8`#``!(BWS=8(!_$`1V!P^V
-M14B(1TCH``````^V142-4P%(@\,!.=!_M$B!Q``"``!;74%<05U!7L-,BW4X
-M0?:&@`,```$/A.$"``!,BVT813'D387M=`U-BV48387D#X0"`P``2(GC2(G@
-M2(V4)``"``#&``!(@\`!2#G0=>Q-A>3'`_06>%H/A,("``!!BT0D.(E#!$&+
-M1"1`B8/&````]H6``P```G0$@$L6`4V%Y`^$IP(``$F#_0$9P(/``HA#&$F+
-MC"2``@``2(7)=#F+`0^V4Q:)0PA(BX&@````@^+]2(E##`^V02B#X`$!P`G"
-MB%,63#EA$`^$=@(```^V@:H```"(0Q1!#[9$)$A-A>U,B>](#T3]B(/%````
-M00^VA"2!`P``B$,728M$)"A(B4,900^V1"00B$,A00^V1"1$B$,BZ+WX__^(
-M0R-!#[9$)$4/ME,EB$,D00^VA"1@`@``@^+[@^`!P>`""<*(4R5!]H0D8`(`
-M``)T!H/*`8A3)4F+1"1028V4)(P"``!(C4M=2(F#K0```$F+1"109HE#)TF+
-MA"1H`@``2(E#*4&+1"0\B8.]````28N$)'`"``!(B4-)28N$)'@"``!(B4-1
-M08N$)(@"``")0UE)BX0DS`(``$B)@YT```!)BX0DU`(``$B)@Z4```!)BX0D
-MC`(``$B)0UU(BT((2(E!"$B+0A!(B4$02(M"&$B)01A(BT(@2(E!($B+0BA(
-MB4$H2(M",$B)03!(BT(X2(E!.$V%[71]28M%*$B)[TB)0S%!#[9%$(A#.4$/
-MMD5$B$,ZZ*/W__^(0SM!#[9%10^V4SV(0SQ!#[:%8`(``(/B^X/@`<'@`@G"
-MB%,]0?:%8`(```)T!H/*`8A3/4F+15!(B8.U````28M%4&:)0S])BX5H`@``
-M2(E#04&+13R)@\$```!(B=_H`````+X``@``2(GGZ`````#WV$4QP$B)X8A#
-M%4B+=4"Z`0```$B+?3CH`````$F+1E!(BWTX13'`2(GAN@$```!(B<9(`W5`
-M2"T```(`2"4``/[_2('N``@``$@IQN@`````3(MU.$'V1F00#X3R_/__3(GW
-MZ`````!(@<0``@``6UU!7$%=05[#,<#'0P0`````Z3W]___&0Q@`Z=G^__],
-MB>A%,>U)B<3I\/S__X/*!(A3%NE__?__9F9FD&9F9I!52(UO&%-(@^P(2(M?
-M&$@YZW4*ZT=(BQM(.>MT/X"[@/S__P1(C8-P_/__=NCV@]#^__\$=-](BW@8
-M2(7_=`V02(GX2(MX&$B%_W7T2(G'Z`````!(BQM(.>MUP4B#Q`A;7<-F9F:0
-M9F:09F:09F:005154TB)^TB+?QA(A?]U].@`````3(NC@`(``(E#.$V%Y'0Q
-M28ML)`A(.=UT3N@`````2(7M08D$)'099F9FD.@`````B44X.T,X=/-(B>_H
-M`````$B)W^@`````2(M#"$B+0&!(A<!T#4B)WTF)PUM=05Q!_^-;74%<PTF+
-M;"00ZZMF9F:09F:09F:09F:0055!5%5(B?U32(/L"`^V1Q"#Z`4\!0^'U```
-M``^VP/\DQ0`````/MT=&2/?82"&':`(``/:'@`,```$/A;0!``!(BU582(72
-M=0=(@WU0`'1/@'T0"@^$N@$``("E8`(``/Y(A=)T.8"-80(``"!(@WU8`'0K
-M]H6``P```71R2(M5&$B%TG0)]H*``P```70=,?9(B>_H`````&9FD&9FD/:%
-M@`,```%T1TB+51CVA6$"```$=3[VA6`"```#=#5(BTU02(7)#X5G`0``2(72
-M=`GV@H`#```!=".`C6`"```(2(GOZ`````!F9F:09F:02(M5&$B%T@^$V0``
-M`$B#Q`A;74%<05W#13'M13'D@']$`'43Z]H/ME5$08U$)`%)@\0!.<)^3DJ+
-M7.5@2(7;=.6`>Q`$=M](B=_H`````/:#8`(```1T!X"-8`(```0/MH-@`@``
-M#[951(/@`SP"N`$```!$#T3H08U$)`%)@\0!.<)_LD6%[0^$<O___X"E8`(`
-M`/XQVX72?QCI8/___P^V142-4P%(@\,!.=`/CDW___](BWS=8$B%_W3C@'\0
-M!';=]H=@`@```734#[:'8`(``(/@OH/(`HB'8`(``.@`````Z[KVA6`"```$
-M#X0:____2(/$"$B)[UM=05Q!7>D`````2(M76$B)T$CWT$B%1U`/A#S^__^`
-MCV`"```"Z3#^__\/MDU$N`$```"#Z0%(T^!(.450#X4M_O__Z2_^__](BT58
-M2/?02(7!#X2Q_O__Z83^__]F9F:09F9FD$B#[!A(B5PD"$B);"002(G[2(GU
-MZ%?S__^$P'5#]H-A`@```DB+0PA(BW,H#[9+1`^V4`IT,3'`]H-@`@``!'4/
-M2(M<)`A(BVPD$$B#Q!C#2(G?Z``````QP.OE9F9FD+C_____Z]H/ML$/MM(I
-MT$ACT$B)\$B)US'22/?W,=)(B>](B<;H`````$B%P'312(G&2(G?Z`````#K
-MFF9F9I!!5$&)U$N-!&152(TLQE-(B?,/MG4AZ`````!(A<!(B<</A"@!``"`
-MH(`#``#^#[9#%XB'@0,``(M#!(E'.(N#Q@```(7`B4=`=0:+0P2)1T`/MH/%
-M````2(UU$(A'2`^V5A4/MH=@`@``P.H"@^(!@^#^"="(AV`"``!(BT4I2(F'
-M:`(``$*+A*.]````B4<\#[9-)+@!````T^"(3T5FB4=&2(M&"4B)1R@/MDTB
-M2,?`_____X#Y/XA/1`^&E0```$B)1UA(BT-)2(U374B-CXP"``!(B8=P`@``
-M2(M#44B)AW@"``"+0UF)AX@"``!(BX.=````2(F'S`(``$B+@Z4```!(B8?4
-M`@``2(M#74B)AXP"``!(BT((2(E!"$B+0A!(B4$02(M"&$B)01A(BT(@2(E!
-M($B+0BA(B4$H2(M",$B)03!(BT(X2(E!.%M=05Q(B?C#N`$```!(T^!(@^@!
-MZ5K___]F9F:09F9FD$B![#@"``!!N`$```"Z`0```$B)G"0(`@``3(FD)!@"
-M``!(B>%,B;0D*`(``$B)K"00`@``28G\3(FL)"`"``!,B;PD,`(``$F)YDB+
-M;SA,BS](BT502(G&2`-W0$@M```"`$@E``#^_TB)[TB![@`(``!(*<;H````
-M`(7`B<,/A,L```!)BW0D0$F+?"0X0;@!````2(GAN@$```#H`````(/X_T&)
-MQ7163(GWZ`````!!@3[T%GA:#X3$````N/____](BYPD"`(``$B+K"00`@``
-M3(ND)!@"``!,BZPD(`(``$R+M"0H`@``3(N\)#`"``!(@<0X`@``PV9F9I"%
-MVW6[2(M%4$F+?"0X0;@!````2(GAN@$```!(B<9)`W0D0$@M```"`$@E``#^
-M_TB![@`(``!(*<;H`````(7`#X1D____Z73___]F9I!FD$B)Y^@`````@3PD
-M]!9X6I!T"KO^____Z1G___^^``(``$B)Y^@`````A,`/A`3____KW[X``@``
-M2(GG9F:09I#H`````(3`#X4B____187M#X5`!```A=L/A9<%``!!@'XA!`^&
-M!O___T&`?B)`9I`/A_G^__]!@'XZ0&9FD&:0#X?I_O__28M?&$F-5QA%#[=N
-M)TT+KJT```!(.=-T)H"[@/S__P1(C:MP_/__=@Y(@[N(_/__``^$"`0``$B+
-M&T@YTW7:,=),B?9,B?_H;OS__TB%P$B)Q0^$D?[__P^VE6`"```/MDU$B="#
-MXOW0Z$$*1B6#X`$!P`G"@/D_2,?`_____XB58`(``$B+55!W#+@!````2-/@
-M2(/H`4PAZ$@)T`^VE6`"``!(B45000^V1B6#X@'`Z`*#X`$XPG0C#[:58`(`
-M`$B+10B#XOZ(E6`"``"`>`H`=`F#R@*(E6`"``!!BU8(A=)T94B+C8`"``"`
-MC6$"```$2(7)#X3I`@``@'DH``^$R0(``$F+1@Q(.8&@````=A)(B8&@````
-M00^V1A2(@:H```!!]D86!`^$D`0``$B+41!(A=(/A',$``!(BT$(2#G"#X14
-M!```BT4\03N&O0````^$6`(``("-8`(```)(QX5H`@````````^VE8`#``")
-MT(/B_=#H00I&%H/@`0'`"<*(E8`#``!!@'X8`4$/MD8C#X:;`0``1`^VZ$J+
-M7.U@2(7;#X3;`0``#[:3@`,```^V2T1(BWM0B="#XOW0Z$$*1A:#X`$!P`G"
-MB).``P``#[:38`(``(G0@^+]T.A!"D8]@^`!`<`)PH#Y/XB38`(``$C'PO__
-M__]-BX:U````00^W=C]W#+@!````2-/@2(T4$`^WQDP)P$@APD@)^DB)4U!!
-M#[9&/0^VDV`"``#`Z`*#X@&#X`$XPG0C#[:38`(``$B+0PB#XOZ(DV`"``"`
-M>`H`=`F#R@*(DV`"``!!#[9..TACP4B#?,-@``^%<OS__TR)9,-@BT,\03N&
-MP0```$F)7"08#X2%````@(M@`@```DC'@V@"````````2,?`_O___TB)WTC3
-MP$@A0UCH``````^V@V`"``"H$'4-J"!T%(/(@(B#8`(``$C'@V@"````````
-M]H6``P```71*2(N%@`(``$B%P'0^2(M0"$B%TG0U2(MX$$B%_W0L2#G52`]%
-M^N@`````,<#IV/O__TF+1D%(.8-H`@``=H!(B8-H`@``Z73___\QP.FX^___
-M#[;(28EL)!A(B>](8\%,B63%8$C'P/[___](T\!((458Z``````/MH5@`@``
-MJ!!U$:@@#X1M____@\B`B(5@`@``2,>%:`(```````#I5/___[H!````3(GV
-M3(G_Z"+Y__](A<!(B<,/A$7[__](B6@82HE$[6#I^_W__TF+1BE(.85H`@``
-M#X:I_?__2(F%:`(``.F=_?__28M&#$@Y@:`````/@T7]___I+OW__TF+1RA)
-MC5\H2#G8#X33````.U#H2(U(Z`^$M@```$B+`$@YV'7KZ;D```!,B??H````
-M`$F+="1`28M\)#A%,<!(B>&Z`0```.@`````3(GWZ`````#IF?O__XN#J/S_
-M_T$[1@0/A>C[___V0_`!#X7O````08!^&`$/AO3[__]!#[9&(TB+7,5@2(7;
-M#X3A^___]H.``P```0^$U/O__TB+>U!!#[=&/TD+OK4```!("<?H`````$B+
-M4P@/ME(*.=`/CJS[__](B>_H`````.F&^___2(7)2(F-@`(```^%,_S__TF-
-MO]````#H`````$B%P$B)P4B)A8`"```/A`'Z__\QP,8$"`!(@\`!2#VP````
-M=?!)BT<P2(U1&$B)61A)B5<P2(D02(E!($&+1@B)`4F+1@Q(B8&@````00^V
-M1A2(@:H```!!]D86`@^$Q/O__TB+A8`"``#&0"@!Z;3[__],B>]("[O`_/__
-MZ`````!(BY-X_/__#[92"CG0#X]"____Z>K^__],B??H`````$B+15!(B<9)
-M`W0D0$@M```"`$@E``#^_TB![@`(``!(*<;I?_[__[C_____2,=!"`````#I
-M/OG__TB+00A(B>I(B6D0Z8'[__](BT$(2(7`=`E(BU$0Z6_[__](BU$02(GH
-M2(EI".E?^___9F9FD&9F9I!52(G]4TB#[`A(BU\8#[9#1(3`#[;0#X0;`@``
-M,<E(.7M@=1/I#@(``&9F9I!F9I!(.6S+8'0+2(/!`4@YT6:0=>ZX`0```$C3
-MX$@)0UA(B=_H`````/:#@`,```$/A;T```!(BT,82(7`#X26`0``2(M`"$B)
-MW_]0,#'V@'M$`'1;2(M4\V!(A=)T1/:"@`,```%T.X!Z$`1V-0^VBF`"``")
-MR(/@CT@YZHB"8`(```^$7P$``/:"8`(```%T$8/ACH/)`HB*8`(``&9FD&:0
-M#[9#1$B#Q@%(.?!WI4B+@X`"``!(A<`/A`X!``!(BU`(2(72#X0!`0``2(MX
-M$$B%_P^$]````$@YTT@/1?J`IX`#``#^2(/$"%M=Z0`````/MH-@`@``@^"_
-MJ""(@V`"``!T%(/(@$C'@V@"````````B(-@`@``#[:38`(``(G0@^#^B(-@
-M`@``2(M#6$CWT$B%0U!U"8/B[(B38`(``$B+<QA(A?8/A(4```"`IF`"``#^
-M@'Y$`'1X,>TQR6:02(M4SF!(A=)T-O:"@`,```%T+8!Z$`1V)_:"8`(```%T
-M'@^V@F`"``"]`0```(/@K(/(`HB"8`(``&9FD&9FD`^V1D1(@\$!2#G(=[-(
-M@[N``@```'1>]H-@`@``!'4SA>UU.8"+80(``"!(@\0(6UW#,>WKUTB)W^@`
-M````9I#I9?[__X/AC(B*8`(``.FM_O__2(G?Z`````#KQTB)W^@`````Z[VX
-M`0```&9F9I#I!?[__TB+0QA(A<!F9F:0=`I(@[B``@```'6+BU,PA=)X#S'V
-M2(G?Z`````#I=?___TB%P`^$;/___XM`,(7`>>'I8/___Y"0D)"0D)"0D$B+
-M!0````!(A<!T,S')9I"`>`P!2(L`@]G_2(7`=?&%R70<BQ4`````C8+_#P``
-MA=(/2-#!^@R)T,'Z'_?YPXL%`````(V0_P\``(7`#TC"P?@,PV9F9I!F9F:0
-M9F9FD//#9F9FD&9F9I!F9I!F9I!(BX>(`0``2(E&&$B)MX@!``##9F9FD&9F
-MD&9FD&9FD#'`PV9F9I!F9I!F9I!F9I!!5$F)_%53BX=P`0``QX>X`0``````
-M`$F+K"20`0``2(7M=$,Y10!W:$DYK"28`0``#X2.````2(M%($F)A"20`0``
-M2,=%(`````!(BWT0_U4(28NL))`!``!!BX0D<`$``$B%[76]/7\!``!W'DF+
-MG"2(`0``2(7;=!$Q]DB+._]3"$B+6QA(A=MU[UM=05S#28N<)(@!``!(A=MT
-M[F:02(L[BW4`_U,(2(M;&$B%VW7N08N$)'`!```[10`/@U3____KQTG'A"28
-M`0```````$G'A"20`0```````.EA____9F9FD&9F9I!F9I!F9I!52(G]4TB#
-M[`A(BY^(`0``2(7;=!1(BSN^______]3"$B+6QA(A=MU[#'`2(-]6``/E<!(
-M@\0(6UW#9F:09F:04XN'N`$``$B)^X7`=`);PTB)NZ@!``!(QX>@`0``````
-M`$B-MZ`!``!(QX>P`0```````$B-?UCH`````,>#N`$```$```!;PV9F9I!F
-M9I!(@^P(2(._D`$```!T(DB+AY@!``!(B7`@2(FWF`$``.@`````N`$```!(
-M@\0(PY"+AW`!```[!G,02(FWF`$``$B)MY`!``#KUDB+?A#_5@@QP.O59F9F
-MD&9F9I!F9I!(@<=H`0``Z0````!F9F:02('':`$``.D`````D)"0D`^V1Q2)
-MP@I7%8/@^X/B!`G0#[97%8G!@^#^@^$!@^(!"<H)T(A'%`^V1R2)P@I7)8/@
-M^X/B!`G0#[97)8G!@^#^@^$!@^(!"<H)T(A'),.0#[9')8G""E<F@^#[@^($
-M"=`/ME<FB<&#X/Z#X0&#X@$)R@G0B$<E#[9'/8G""E<^@^#[@^($"=`/ME<^
-MB<&#X/Z#X0&#X@$)R@G0B$<]PP``````EC`'=RQA#NZZ40F9&<1M!X_T:G`U
-MI6/IHY5DGC*(VPZDN-QY'NG5X(C9TI<K3+8)O7RQ?@<MN.>1';^09!"W'?(@
-ML&I(<;GSWD&^A'W4VAKKY-UM4;74],>%TX-6F&P3P*AK9'KY8OWLR66*3UP!
-M%-EL!F-C/0_Z]0T(C<@@;CM>$&E,Y$%@U7)Q9Z+1Y`,\1]0$2_V%#=)KM0JE
-M^JBU-6R8LD+6R;O;0/F\K.-LV#)U7-]%SPW6W%D]T:NL,-DF.@#>48!1U\@6
-M8="_M?2T(2/$LU:9E;K/#Z6]N)ZX`B@(B`5?LMD,QB3I"[&'?&\O$4QH6*L=
-M8<$]+6:VD$'<=@9QVP&\(-*8*A#5[XF%L7$?M;8&I>2_GS/4N.BBR0=X-/D`
-M#XZH"988F`[ANPUJ?RT];0B7;&21`5QCYO11:VMB86P<V#!EA4X`8O+ME09L
-M>Z4!&\'T"()7Q`_UQMFP95#IMQ+JN+Z+?(BY_-\=W6))+=H5\WS3C&5,U/M8
-M8;)-SE&U.G0`O*/B,+O40:7?2M>5V#UMQ-&D^_36TVKI:4/\V6XT1HAGK="X
-M8-IS+01$Y1T#,U],"JK)?`W=/'$%4*I!`B<0$`N^AB`,R26U:%>SA6\@"=1F
-MN9_D8<X.^=Y>F,G9*2*8T+"TJ-?'%SVS68$-M"X[7+VWK6RZP""#N.VVL[^:
-M#.*V`YK2L70Y1]7JKW?2G14FVP2#%MQS$@MCXX0[9)0^:FT-J%IJ>@O/#N2=
-M_PF3)ZX`"K&>!WU$DP_PTJ,(AVCR`1[^P@9I75=B]\MG98!Q-FP9YP9K;G8;
-MU/[@*].)6GK:$,Q*W6=OW[GY^>^^CD.^MQ?5CK!@Z*/6UGZ3T:'$PM@X4O+?
-M3_%GN]%G5[RFW0:U/TLVLDC:*PW83!L*K_9*`S9@>@1!P^]@WU7?9ZCOCFXQ
-M>;YI1HRS8<L:@V:\H-)O)3;B:%*5=PS,`T<+N[D6`B(O)@55OCNZQ2@+O;*2
-M6K0K!&JS7*?_U\(QS]"UBY[9+!VNWENPPF2;)O)C[)RC:G4*DVT"J08)G#\V
-M#NN%9P=R$U<`!8)*OY44>KCBKBNQ>S@;M@R;CM*2#;[5Y;?OW'PAW]L+U-+3
-MAD+BU/'XL]UH;H/:'\T6OH%;)KGVX7>P;W='MQCF6@B(<&H/_\H[!F9<"P$1
-M_YYECVFN8OC3_VMA1<]L%GCB"J#NT@W75(,$3L*S`SEA)F>G]Q9@T$U':4G;
-M=VX^2FK1KMQ:UMEF"]]`\#O8-U.NO*G%GKO>?\^R1^G_M3`<\KV]BL*ZRC"3
-MLU.FH[0D!3;0NI,&U\TI5]Y4OV?9(RYZ9K.X2F'$`AMH790K;RHWO@NTH8X,
-MPQO?!5J-[P(M````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
+MR````(!_$`%(BY^`````=`Y(@<3(````6UU!7$%=PTB+1W!,C:PD@````$B+
+MOX@```!,B>[_4'A(BT,(2(GF2(M[$/]0.$B-C"2T````2(V4)+@```!(C;0D
+MO````$B)W^@F<O__#[:$))$```"(10+VA"2.`````@^%A`$```^VA"2X````
+M`H0DD````(A%`8N$)+P```"(10!!@'PD:``/B6D!``!!#[9$)&>(10,/MH0D
+MEP```(A%!0^VE"2,````#[9%!@^VM"2-````P.H&B=&#X/S0ZH/A`0'2"<@/
+MMHPDC0````G0C12U`````(/@\X/B"(/A`<'A`@G(B?$)T(/A$(GR@^#/@^(@
+M"<B)\0G0@^%`B?*#X#^#XH`)R`G0B$4&#[9%!P^VE"23````@^#\@^(#"=!`
+M]L8$B$4'#X39````QD4$`DR)[DR)Y^AF=/__2(NT)*````")10A(A?9T(TB-
+M?0Q(C5U"NI8```#H`````+XH````2(G?Z`````#&0R<`BX0DB````(E%?D'V
+M1"1H074828M$)$A(B86B````28M$)$!(B86J````28M,)#A(A<ET-C'VZPA(
+MBPE(A<ET*DB+01A(A<!T'$B+0!A(A<!T$XN`Z`,``$ACUH/&`8F$E;H```"#
+M_@=^SDB!Q,@````QP%M=05Q!7<,/MH0DM````.EW_O__#[:$))8```"(10/I
+MD/[__X/F"$"`_@$9P(/@_H/``XA%!.D4____9F:09I!(@^PX3(ED)!A,B6PD
+M($F)_4B)7"0(2(EL)!!,B70D*$R)?"0P2(M'*$B+7S"+*(GOZ`````!)B<2+
+M`X/H!703B<)(B=C&0`4`2(/``4B#Z@%U\H7M=&I-A>1T94F+1"0HNO____](
+MB4,028M$)!A(A<!T!HN0Z`,``(E3&$&+5"0PN/____^%T@])PHA##TF+!"1(
+MBW@(Z`````"(0PY!#[:$)($#``"(0PU!#[9$)!`\!'97QD,,`4&`?"1$0'9E
+M0<=%4/____])BWT028UU6$G'15@`````38EM8$G'16@`````2(M<)`A(BVPD
+M$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$..D`````+`%UL4B-<RS&0PP"3(GG
+MZ)#\__^%P'6=ZZ-)BT0D4$R)YTB)@[P```#HUG3__XF#L````$F+A"1P`@``
+M2(E#+$F+A"1X`@``2(E#-$$/MGPD$.B]<?__B(.0````00^V1"1%3(GGB(.1
+M````00^V1"1(B(.T````28N$)&@"``!(B8.<````Z+C>__],B>>)@Y0```#H
+M`````,:#D@````")@Y@```!!@'PD1``/A$H!``!%,?9%,?]+BVST8$B%[0^$
+M]0```("[DP`````/A/D```"`?1`$#X0(`0``BX7H`P``0HF$L\0````/MI.2
+M````08/'`4F#Q@&#P@&(DY(```!!#[9$)$1$.?@/CY$````/MM*#^C]_%DAC
+MPH/"`8/Z/\>$@\0```#_____?NI)BX0D@`(``$B%P`^$>_[__TB+4`BY____
+M_TB%TG0&BXKH`P``B8ND````2(M0$+G_____2(72=`:+BN@#``")BZ@```!(
+M@W@(``^$//[__TB#>!``#X0Q_O__3(GGZ`````")@ZP```#I'O[__V9FD&:0
+M08/_/P^/9?___TN+;/1@2(7M#X4+____0L>$L\0`````````Z1____\/MGT0
+MZ#YP__^(@Y,```"`?1`$#X7X_O__2(M%.(N`Z`,``$*)A+/$````Z>_^__\Q
+MTND7____2('LZ````+C_____2(F<),@```!,B:0DV````$B)\TB)K"30````
+M3(FL).````!)B?R`?Q`!2(NO@````'0H2(N<),@```!(BZPDT````$R+I"38
+M````3(NL).````!(@<3H````PTB+1W!,C:PD@````$B+OX@```!,B>[_4'A(
+MBT4(2(GF2(M]$/]0.$B-C"2T````2(V4)+@```!(C;0DO````$B)[^B2;/__
+M#[:$))$```"(0P+VA"2.`````@^%&0$```^VA"2X`````H0DD````(A#`8N$
+M)+P```"(`T&`?"1H``^)%@$``$$/MD0D9XA#`P^VE"2,````#[9#!@^VM"2-
+M````P.H&@^#\B='0ZH/A`0'2"<@/MHPDC0````G0C12U`````(/@\X/B"(/A
+M`<'A`@G(B?$)T(/A$(GR@^#/@^(@"<B)\0G0@^%`B?*#X#^#XH`)R`G0B$,&
+M#[9#!P^VE"23````@^#\@^(#"=!`]L8$B$,'#[:$))<```"(0P5T9L9#!`),
+MB>Y,B>?HUV[__TB+M"2@````B4,(,<!(A?8/A)#^__](C7L,NI8```!(@\-"
+MZ`````"^*````$B)W^@`````,<#&0R<`Z6;^__]F9F:09F:0#[:$)+0```#I
+MXO[__V9FD(/F"$"`_@$9P(/@_H/``XA#!.N*#[:$))8```"(0P/IX_[__V9F
+M9I!F9F:09F9FD$%528G]05154TB#[`A,BV<H08L\)(7_=$@Q[>L19F:02(G?
+MZ`````!!.2PD=C.#Q0&)Z$&+/(3H`````(!X$`%(B<-U1_9`:`)TU4B)Q^@`
+M````2(G?Z`````!!.2PD=\U)QT58`````$V);6!)C7582<=%:`````!)BWT0
+M2(/$"%M=05Q!7>D`````0<=%4/[____KRV9F9I!F9I!F9I!(@^P82(GX2(E<
+M)`A,B60D$$B)QDB+7Q!,BV<(2(L[2(''T````.@`````3(GG,=(Q]NB)XO__
+M@(M@`@``!$B)WTR+9"002(M<)`A(@\08Z0````!F9F:09F9FD&9F9I!32(M'
+M"$B)^4B+.`^W@9@```"+EU@"!`!(QX>(`@0``````$B-MV@"!`#!X`E(QX=P
+M`@0``````$B)CW@"!`!(QX>``@0``````(U$`O^)TS'2]_.)AV@"!`!;Z0``
+M``!32(M'*(LXZ`````!(BYB``@``@'LH`'1.2(M["$R+BZ````!(BU<H23G1
+M#X1O`0``23G1#X?V````#X3&`0``#[>+J`````^W\4PYS@^&C0$``$0/MH.J
+M````1(G)00^W\4DI\>M#2(M["$R+BZ````!(BW<H23GQ#X3X````1`^V@ZH`
+M``!%A,`/A=`````/MXNH````B?)F1"G*#[?!28T$`4@YQ@]"RD6$P&;'@YH`
+M`````$R)BY````!FB8N8````=`]!@/@#=`E(B=];Z<O^__\/MX.8````2(US
+M2$C'0U@`````2`.#D````$R)2TA(QT-P`````$B)6WA(QX.``````````,>#
+MB`````$```!(B4-02(U#8$B)0V!(B4-HZ`````"%P'2?6\.0#[>+J`````^W
+M\4B-!#),.<@/@ID```!$#[:#J@```$2)R68IT0^W\>D%____9F:008#X`P^$
+M)O___TB+0Q!(BW`HZ1G___]$#[:#J@```$&`^`-T:$6$P'7@0;@!````QH.J
+M`````>O19F9FD&9FD$0/MH.J````08#X`G0_08#X`71"#[>+J````#'23(G(
+M#[?Q2/?V9H72#X23_O__#[?RB='IB?[__V9F9I!F9I!$#[:#J@```.EU_O__
+M2(G?6^EJR/__QH.J`````$B+5RCI*_[__T0/MH.J````ZZ1(@^Q8#[?!3(ED
+M)#A)B<1(B5PD*$B);"0P3(ET)$A)`=1,B6PD0$R)?"10B?U(B70D$&:)3"0.
+M28G62(E$)!A,.V903(G#38MX$'9*0<=`4/[___](C7-82,=#6`````!(B5M@
+M2,=#:`````!,B?](BUPD*$B+;"0P3(MD)#A,BVPD0$R+="1(3(M\)%!(@\18
+MZ0````!(BU0D$$R)_XMR-.@`````2(7`28G%#X2C`0``QH"R`````&:#?"0.
+M`4B)6%A(QX#(`````````$C'@,``````````#X2P`0``@?T9_P``=#MW)8']
+M"_\``)`/A-@```#'0U#^____3(GOZ`````!,BWL0Z4;___^!_2/_```/A+0`
+M``"!_23_``!UU$B+5"00]D)J`@^%-`$``$'&A;`````#0<:%FP```"1!#[:%
+ML0```(/@^X/(`D&(A;$```!!@+VP`````P^$3@$``$$/MH60````/!`/A-0!
+M```\"@^$C0(``$B+1"0028E%4$F#?T@`#X3R`@``28M/0$F-51A)C4<X28E7
+M0$F)11A)B4T@2(D12(M<)"A(BVPD,$R+9"0X3(ML)$!,BW0D2$R+?"102(/$
+M6,-F@WPD#@$/AQS___](BT0D$$B+:#A(A>UT'TB+10A).<9R#4@#11!).<0/
+MAL,"``!(BVT`2(7M=>%(BT0D$/9`:@(/A)8"``!)P>P@0<:%L`````)-A>0/
+MA+@#``!!QH68````BD'&A9`````000^VA;$```"#R`2#X/U!B(6Q````Z0'_
+M__],BWL0QT-0_?___^GO_?__2<'L($'&A;`````"387D#X2Y````0<:%F```
+M`(A!QH60````$.FR_O__2(M4)!!!N`$```!,B?&)[DC'QP`````QP.@`````
+MZ2W^__],B?%!#[;63(GS2,'I$$G![AA)QX6@`````````(G(9H'A_P!!QH6:
+M````0##`9D''A9````````G01(GR2<'N"&9!B864````,-(/ML<)T&9!B866
+M````1(GP,,`)P69!B8V8````#[=$)`YF08F%D@```&9!B86<````Z4G^__]!
+MQH68````*$'&A9`````*Z?G]__]!QH61``````^W1"0.18BUH0```$'&A:(`
+M````0<:%HP````#!X`E!B864````3(GP2,'H.$&(A9H```!,B?!(P>@P08B%
+MFP```$R)\$C!Z"A!B(6<````3(GP2,'H($&(A9T```!,B?!(P>@808B%G@``
+M`$R)\$C!Z!!!B(6?````3(GP2,'H"$&(A:`````/MT0D#F;!Z`A!B(6D````
+M#[94)`Y!QH6F`````$'&A:<`````08B5I0```.ES_?__0<:%D0`````/MT0D
+M#D6(M9T```!!QH6>`````,'@"4&)A90```!,B?!(P>@808B%F@```$R)\$C!
+MZ!!!B(6;````3(GP2,'H"$&(A9P````/MT0D#F;!Z`A!B(6?````#[9<)`Y!
+MQH6A`````$&(G:````#I^OS__TR)[TB+7"0H2(ML)#!,BV0D.$R+;"1`3(MT
+M)$A,BWPD4$B#Q%CI`````$'&A;`````#0<:%FP```#3I>OW__TB+51A(A=)(
+MB50D(`^$-/W__TR+0AA-A<`/A"?]__])BWA83(D$).@`````3(L$)$F+4`@X
+M0@H/A@G]__])C;_P````2(MM"$'&A;`````!3(D$).@`````2(7`2(G!3(L$
+M)`^$KP$``$R)\DC'0!``````2,=!,`````!(*>I(QT$H`````$C'03@`````
+M2(D02(M$)!C'04`!````28E->$V)15!(`=!(B4$(2(U!&$B)01A(B4$@28M`
+M"(!X"0!T=$'&A9H````!00^V2$5(T^I)B960````00^V2$2$R0^$W?O__TB+
+M7"0@23M88+@!````=!\QTH/"`3C*#X3`^___#[;"2(M<)"!).US`8'7FC4(!
+M08B%FP```.FB^___0<:%F````"I!QH60````"NE#_/__28V'4`($`$&+MU@"
+M!`!!QH6:`````4F)E9````!)B86@````#[=$)`YF08F%F````$$/MGA$0(3_
+M=#9(BU0D($D[4&"X`0````^$I0```#'2ZQ8/MLI(BUPD($ACP4D[7,!@#X2$
+M````@\(!0#CZ=>(/MT0D#C'22<>'B`($``````!)QX=P`@0``````$V)KW@"
+M!`!,B?])QX>``@0``````,'@"8U$!O_W]DF-MV@"!`!!B8=H`@0`2(M<)"A(
+MBVPD,$R+9"0X3(ML)$!,BW0D2$R+?"102(/$6.D`````QT-0_?___^D8^O__
+MN`$```#3X$&(A9L```#I<?___V9F9I!F9F:02(/L6$B%]DB)7"0H2(EL)#!,
+MB<-,B7PD4$R)9"0X2(GU3(EL)$!,B70D2$&)STV+8!")?"042(E4)`A%B[0D
+M6`($`'0)]H9A`@``!'1)2(US6,=#4/[___](QT-8`````$B)6V!(QT-H````
+M`$R)YTB+7"0H2(ML)#!,BV0D.$R+;"1`3(MT)$A,BWPD4$B#Q%CI`````$B+
+M1@@/MD@*A,ETJT$/M\=(`T0D"$B)1"08#[961`^VP2G"2(M&*$ACTDB)T3'2
+M2/?Q2#E$)!@/AWK___])C80D\````$B)QTB)1"0@Z`````!(A<!)B<4/A&P"
+M``"+=31,B>?H`````$B%P$F)P`^$2`(``$B+1"082(M,)`A)QT40`````$G'
+M13``````2<=%*`````!)QT4X`````$F)10A)C44828E-`$''14`!````38EH
+M>$F)11A)B44@0<:`L`````&+!0````!)B5A8A<!^##N%W`(```^?P`^VP$&)
+M0&A(BT4(@'@)``^$R````(M,)!2!Z0O_``"#^1H/A^P!``"X`0```$C3X*D`
+M@``$#X4H`@``J0!```(/A1`"``"I`0```0^$PP$``$'&@)H````!#[9-14G'
+M@,``````````2--L)`A)B6A02(M,)`A!QH"R`````$G'@,@`````````28F(
+MD````$F#?"1(``^$U`$``$F+3"1`28U0&$F-1"0X28E4)$!)B4`828E(($B)
+M$4B+7"0H2(ML)#!,BV0D.$R+;"1`3(MT)$A,BWPD4$B#Q%C#00^WQS'2BTPD
+M%,'@"4&-1`;_@>D+_P``0??V@_D:B<8/AQ$!``"X`0```$C3X*D`@``$#X4S
+M`0``J0!```(/A1D!``"I`0```0^$Z````$'&@)H````!28V$)%`"!`!)B6A0
+M2<>`P`````````!)QX#(`````````$R)YTF)@*````!(BT0D"&9%B;B8````
+M0<:`L@````!)B8"0````08FT)&@"!`!)C;0D:`($`$G'A"2(`@0``````$G'
+MA"1P`@0``````$V)A"1X`@0`2<>$)(`"!```````2(M<)"A(BVPD,$R+9"0X
+M3(ML)$!,BW0D2$R+?"102(/$6.D`````2(M\)"!,B>[H`````$B+>Q!(C7-8
+MQT-0_?___TC'0U@`````2(E;8$C'0V@`````Z>?\__](BWPD($R)[DR)!"3H
+M`````$R+!"1,B<?H`````$R+8Q#IG_S__P'V0<:`F@````+IZ_[__T'&@)H`
+M```#Z=[^__]!QH":`````NGV_?__0<:`F@````/IZ?W__TB+7"0H2(ML)#!,
+MB<=,BV0D.$R+;"1`3(MT)$A,BWPD4$B#Q%CI`````)!(@^P82(D<)$R)9"0(
+M2(G[3(EL)!!(BT<HBSA$#[=@#$R+:`3H`````(M[&$F)V$2)X4R)ZDB+'"1,
+MBV0D"$R+;"002(G&2(/$&.FA^___D$B#[!A(B1PD2(EL)`A(B?M,B60D$$B+
+M1RB+.$R+8`0/MV@,Z`````"`>!`!2(G&=".+>Q@/M\U)B=A,B>)(BQPD2(ML
+M)`A,BV0D$$B#Q!CI3/O__XM[&`^WS4F)V$R)XDB+'"1(BVPD"$R+9"002(/$
+M&.DI]/__9F:09F:09F:02(/L&$B)'"1(B6PD"$B)^TR)9"002(M'*(LX3(M@
+M!`^W:`SH`````(!X$`%(B<9T(XM[&`^WS4F)V$R)XDB+'"1(BVPD"$R+9"00
+M2(/$&.G,^O__BWL8#[?-28G83(GB2(L<)$B+;"0(3(MD)!!(@\08Z:GS__]F
+M9I!F9I!F9I!(@^P82(D<)$R)9"0(2(G[3(EL)!!(BT<HBSA$#[9@"$2+:`3H
+M`````(M[&$F)V$2)X4R)ZDB+'"1,BV0D"$R+;"002(G&2(/$&.E1^O__D$B#
+M[!A(B1PD2(EL)`A(B?M,B60D$$B+1RB+.$2+8`0/MF@(Z`````"`>!`!2(G&
+M="2+>QA`#[;-1(GB28G82(ML)`A(BQPD3(MD)!!(@\08Z?OY__^+>QA`#[;-
+M1(GB28G82(ML)`A(BQPD3(MD)!!(@\08Z=?R__]F9F:09F:02(/L&$B)'"1(
+MB6PD"$B)^TR)9"002(M'*(LX1(M@!`^V:`CH`````(!X$`%(B<9T)(M[&$`/
+MMLU$B>))B=A(BVPD"$B+'"1,BV0D$$B#Q!CI>_G__XM[&$`/MLU$B>))B=A(
+MBVPD"$B+'"1,BV0D$$B#Q!CI5_+__V9F9I!F9I!!54&)]4%454B)_5-(@^P(
+MA?:)M5P"!`!T,4B)^T4QY$2)X$B)[T&#Q`%(P>`$2(VT!5@"``#H`````$B)
+M@U`"``!(@\,013GL==5(BP4`````QX5@`@0`$@```$B%P'0:BU`0.95@`@0`
+M=@:)E6`"!`!(BT`(2(7`=>9(@\0(6UU!7$%=PV9F9I!F9I!F9I!54TB)^TB#
+M[`A$BX=<`@0`187`="PQ[8GH2(G?@\4!2,'@!$@!V$B+D%@"``!(B[!0`@``
+MZ``````YJUP"!`!WUL>#7`($``````!(B=](@\0(6UWI`````&9F9I!F9I!5
+M4TB)^TB#[`B`O[`````#2(MO6`^$C`````^V@[(````\$`^$D0```#P%="-W
+M$RP!#X21````QT50_____V:0ZQ4\"P^%AP```&9FD&9FD,=%4/W___](BW-X
+M2(7V=`](BSM(@<?P````Z`````!(BSOH*?___TB)W^@`````2,=%6`````!(
+MB6U@2(UU6$C'16@`````2(M]$$B#Q`A;7>D`````]H>;`````0^$9____\:'
+ML@```!!(BT4PQ@`!QH.R`````<=%4`````#KACP-#X1W____QT50_____^ER
+M____9F9FD&9F9I!F9I!52(G]4TB#[`A(BU]8BT,8/23_``!T:3T9_P``=&*`
+MO;(````0=G+'0U#_____9I!(BWT`2(MU>$B!Q_````#H`````$B+?0#H8_[_
+M_TB)[^@`````2,=#6`````!(B5M@2(US6$C'0V@`````2(M[$$B#Q`A;7>D`
+M````9F9FD("]L@````QT3$B+0S#&``"`O;(````0=XY(#[Z-L@```+@!````
+M2-/@J2`I`0!U%*@"#X1O____QT-0`````.EL____QT-0_?___V9FD&:0Z5O_
+M__](BT,POQ$```#&``%(BW50Z`````#&A;(````!Z\5F9F:09F:09F:09F:0
+M2(/L&$B)7"0(2(EL)!!(B?N#?QP'2(M'*(LH=@:#?R`#=QW'0U#^____2(M<
+M)`A(BVPD$$B#Q!C#9F9FD&9FD(GOZ`````!(A<!TUXGOZ`````!(BQ!(.U,0
+M=`G'0U#\____Z\5(@W@8`'6W@'@0!':QBW`P@_[_=+!(BWH(Z`````"%P'2C
+MQT-0_____V:0ZYAF9F:09F9FD&9FD&9FD$B#[!A(B1PD3(ED)!!(B?M(B6PD
+M"$2+CX0#``!)B?1%A<EU"DB#O^`#````=!4QP$B+'"1(BVPD"$R+9"002(/$
+M&,.+=S"#_O]T$$B+!TB+>`CH`````(7`==.`>Q`$=C]F]X-@`@``<`AUPH![
+M1`!T)S'M2(M\ZV!(A?]T#$R)YNAZ____A,!TI`^V0T2-50%(@\4!.=!_V[@!
+M````ZY!T$TR)YDB)W^@S9/__#[;`Z7O___](BWLX3(GFZ!]D__\/ML#I9___
+M_V9F9I!F9I!(@^P(@'\0!'86,<!(@[^``@```'0*2(/$",-F9I!FD.@+____
+M2(/$"`^VP,-F9I!!5D%505154TB+3RA(B?M(BU<PBP''`@````!!B<9!B<5!
+M@>8``0``08'E_P```'1_13'DO00```#K,V9FD&:02(-X&`!U7C'V@'@0!4B)
+MQT@/0_#H=____X3`=$A!@\0!2(/%!$4Y['1&2(M+*(L\*>@`````187V=<5(
+M@W@8`'4C9O>`8`(``'`(=1B+<#"#_O]TR$B+`$B+>`CH`````(7`=+A(BU,P
+M08U$)`&)`DC'0U@`````2(E;8$B-<UA(QT-H`````$B+>Q!;74%<05U!7ND`
+M````9F9FD&9FD$%7,=)!5D%5051)B?Q54TB#[`A(BT\HBP'VQ/]!B<4/E,)!
+M@>7_````B50D!$B+5S!!#Y7'183_1`^V="0$QP(`````=&LQ[46$]G0V9F:0
+MB>B)ZXM\@03H`````#'V@'@0!4B)QT@/0_#H@?[__X3`#X2Z````C4,!2(/%
+M`4$YQ7=U183_="DQVV9FD&9FD$F+1"0HB=I(@\,!BWR0!.@`````2(G'Z```
+M``!!.=UWWT2+5"0$1872=4Q!QT0D4`````!)QT0D6`````!-B60D8$F-="18
+M2<=$)&@`````28M\)!!(@\0(6UU!7$%=05Y!7^D`````183V=(9)BTPD*.E)
+M____183_=+A)BT0D*(MX!.@`````2(/$"$B)QS'V6UU!7$%=05Y!7^EO?/__
+M28M4)#"-0P%!QT0D4/____^)`NE[____9F9FD&9FD$%455-(B?M(@^Q@3(MG
+M4$B+;UA(C70D,$F+1"1P28N\)(@```#_4'@/MD0D0D&(1"1F@7T80O\```^$
+MH0````^V@YL```!(BU4PB$(*#[>#E````(A"!@^W@Y8```"(0@</MX.8````
+MB$((#[:#F@```(A""0^W@Y````"(0@0/MX.2````B$(%#[>#G````(A""X"[
+ML@````$/A*<```#'15#_____2(G?Z`````!(BWT02(UU6$C'15@`````2(EM
+M8$C'16@`````Z`````!(@\1@6UU!7,-F9F:09F:0#[:#FP```$B+53"(0@\/
+MMX.4````9HE""`^W@Y8```!FB4(*#[>#F````&:)0@P/MH.:````B$(.#[>#
+MD````&:)0@0/MX.2````9HE"!@^W@YP```!FB4(0@+NR`````0^%6?___XM%
+M&,=%4``````]0O\``'15/1C_```/A43___](BT4H@'@*\@^%-O___TF+1"1P
+M2(GF28N\)(@```#_4'A(BU0D($B!P@`!```/M@*H!`^$#/___X/@^TR)YX@"
+MZ`````#I^O[__TB+12B`>`_R#X7L_O__9F:09I#KKV9F9I!F9F:09F:09F:0
+M058QP$%505154TB)^V9FD,8$&`!(@\`!2(/X+'7RQP,L````Z&=2__^(0P1(
+MBP4`````2(,X``^40P5(BST`````Z`````#!X`P]____`0^&CP```,9#!@7&
+M0P<+#[9#"T&\!0```$4Q[44Q]L9#"`#&0PD!QD,*#X/@_H/("(A#"^LA1(GH
+MQD0K'$"#R"!!@_P%1`]$Z$&#Q@%!@\0!08/\#70N1(GGZ`````!(A<!TZ42)
+MYT$/MN[HDE/__T&#_`:(1"L,=;Q!@\U`QD0K'`+KQ$&`_6!T&%M=05Q!74%>
+M,<##QD,&!\9#!P?I;/___TB+!0````"#N*0"!``#=MA!#[;&QD0##!+&1`,<
+M0#'`6UU!7$%=05[#9F:09F:04TB)^TB+?S#HT_[__X7`=`?'0U#_____2,=#
+M6`````!(B5M@2(US6$C'0V@`````2(M[$%OI`````&9FD&9FD$%6055)B?U!
+M5%532(/$@$R+9Q!,B>?H15S__T6+G"2@`@0`187;#X61````28ML)!!!QX0D
+MH`($``$```!(A>T/A*T```!(BT4(2(M]$$B)YO]0.`^V1"0000&$)*`"!`"`
+M?"00`'0U,=MF9I!F9I!(B>E(Q\(`````B=Y(B>_H`````(3`=0E!@ZPDH`($
+M``$/MD0D$(/#`3G8?]-(BVT`2(7M=:!!BX0DH`($`(/H`87`08F$)*`"!`!T
+M0DF+?1!)C7580<=%4/S___])QT58`````$V);6!)QT5H`````.@`````2(/L
+M@%M=05Q!74%>PT''A"2@`@0``````$F-M"0X`@``28U\)$A)QX0D.`(`````
+M``!-B:0D0`(``$G'A"1(`@```````.@`````ZXIF9F:09F:09F:09F:0Z0``
+M``!F9F:09F9FD&9FD$B#["A,B60D&$R);"0@28G\2(E<)`A(B6PD$$F)]4B+
+M;QB#K:`"!``!A=(/B+0```#H`````$B%P$B)PP^$L0```(`]``````!U-4B)
+MWK\"````Z`````"+G:`"!`"%VW0^2(M<)`A(BVPD$$R+9"083(ML)"!(@\0H
+MPV9FD&:0#[9`:*@"=<.H`0^%@P```/9#:`1UM8!+:"3KKV9F9I!(C;4X`@``
+M2(U]2$C'A3@"````````2(FM0`(``$C'A4@"````````2(M<)`A(BVPD$$R+
+M9"083(ML)"!(@\0HZ0````!(C7\@Z`````#I9?___TF+1"0(3(GO_Y"`````
+M28U\)"!,B>[H`````.E%____2(G?Z`````!F9I!FD.EK____9F9FD&9F9I!F
+M9I!(@^P82(D<)$R);"002(G[3(ED)`A(BT<H1(M@!(LXZ`````!$B>=)B<7H
+M`````$R)[TB)QN@`````@_@!2(M[$$B-<U@9P$C'0U@`````2(E;8/?02,=#
+M:`````")0U!(BQPD3(MD)`A,BVPD$$B#Q!CI`````&9FD&9FD&9FD$%4@#T`
+M`````%5(B?U3='%(BU\83(UG&$PYXW4+ZS.02(L;3#GC="J`NX#\__\!2(V[
+M</S__W7H]D/P`73B#[8U`````.@`````2(L;3#GC==;'A3@!````AY,#2,>%
+M2`$```````!(C;4X`0``2(FM4`$``$B)[UM=05SI`````%M=05S#9F9FD&9F
+MD&9FD$%505152(G]4TB![,@```!,BV\02(MW*$B-1"0,28GD2(GGQ@<`2(/'
+M`4@YQW7TNK````!!QP0D?`$``.@`````2(M=,#'V3(GB3(GOZ+['__^#^/^)
+M`W4#B4502(M]$$B-=5A(QT58`````$B);6!(QT5H`````.@`````2('$R```
+M`%M=05Q!7<-F9I!FD%4QP$B)_5-(@^P(2(M?,)#&!!@`2(/``4@]@````'7P
+M2(G?Z%CZ__^%P'0NQT50_____TC'15@`````2(EM8$B-=5A(QT5H`````$B+
+M?1!(@\0(6UWI`````(-+1!#'`X`````QTL=#/``@```/MD0:#(/@#X/H`SP"
+M=P7&1!HL!DB#P@%(@_H0=>+KIF9FD$%7059!54F)_4%455-(@^P(2(M'*$B+
+M7S"+*#'`9F:0Q@08`$B#P`%(/?H```!U\(GOZ`````!)B<0QP&9F9I#&!!@`
+M2(/``4@]^@```'7PA>UT9DV%Y'1A28M$)"BZ_____TB)0P1)BT0D&$B%P'0&
+MBY#H`P``B5,,08M4)#"X_____X72#TG"B$,#28L$)$B+>`CH`````(A#`D$/
+MMH0D@0,``(A#`4$/MD0D$#P$=S\L`0^$LP$``$''15#_____2<=%6`````!-
+MB6U@28UU6$G'16@`````28M]$$B#Q`A;74%<05U!7D%?Z0````#&`P%)BT0D
+M4$R)YV:)@^@```#H*%#__XF#Y````$F+A"1P`@``2(E#($F+A"1X`@``2(E#
+M*$$/MGPD$.@/3?__B(.$````00^V1"1%3(GGB(.%````28N$)&@"``!(B8/0
+M````Z!:Z__],B>>)@X@```#H`````,:#A@````")@\P```!!@'PD1``/A&@!
+M``!%,?9%,?]+BVST8$B%[0^$$P$``("[AP`````/A!<!``"`?1`$#X0F`0``
+MBX7H`P``0HF$LXP````/MI.&````08/'`4F#Q@&#P@&(DX8```!!#[9$)$1$
+M.?@/CZ\````/MM*#^@]_%DACPH/"`8/Z#\>$@XP```#_____?NI)BX0D@`(`
+M`$B%P`^$LO[__TB+4`BY_____TB%TG0&BXKH`P``B8O8````2(M0$+G_____
+M2(72=`:+BN@#``")B]P```!(@W@(``^$<_[__TB#>!``#X1H_O__3(GGZ```
+M``")@^````#I5?[__TB-<R#&`P),B>?H5-;__X7`#X4V_O__Z3G^__]F9F:0
+M9F:008/_#P^/1____TN+;/1@2(7M#X7M_O__0L>$LXP`````````Z0'___\/
+MMGT0Z'Y+__^(@X<```"`?1`$#X7:_O__2(M%.(N`Z`,``$*)A+.,````Z='^
+M__\QTNGY_O__059!54F)_4%455-(BT<H2(M?,(LH,<#&!!@`2(/``4@]V```
+M`'7PB>_H`````$F)Q#'`Q@08`$B#P`%(/=@```!U\(7M=#A-A>1T,TF+1"0H
+MNO____](B4,$28M$)!A(A<!T!HN0Z`,``(E3#$$/MD0D$#P$=SDL`0^$"@$`
+M`$''15#_____2<=%6`````!-B6U@28UU6$G'16@`````28M]$%M=05Q!74%>
+MZ0````#&`P%)BX0D<`(``$B)0Q!)BX0D>`(``$B)0QA!#[9\)!#H>DK__XA#
+M=$$/MD0D14R)YXA#=4F+A"1H`@``2(F#P````.B'M___3(GGB4-XZ`````#&
+M0W8`B8.\````08!\)$0`#X2T````13'VZS2`?1`$=%`/ME-VBX7H`P``B423
+M?`^V0W:#P`$\#XA#=G=D00^V1"1$08U6`4F#Q@$YT'Y22XML]&!(A>UTY(![
+M=P!UO`^V?1#HY$G__XA#=X!]$`1UL$B+53@/MD-VBY+H`P``B52#?.NJ2(US
+M$,8#`DR)Y^BHV?__A<`/A=_^___IXO[__P^V4W:#^@]F9F:0#X_1_O__2&/"
+M@\(!@_H/QT2#?/____]^[>FY_O__,=+KY&9F9I!F9F:09F:09F:0059!54F)
+M_4%455-(BT<H2(M?,(LH,<#&!!@`2(/``4@]K@```'7PB>_H`````$F)Q#'`
+MQ@08`$B#P`%(/:X```!U\(7M=#=-A>1T,DF+1"0HNO____^)0P1)BT0D&$B%
+MP'0&BY#H`P``B5,(00^V1"00/`1W.2P!#X0)`0``0<=%4/____])QT58````
+M`$V);6!)C7582<=%:`````!)BWT06UU!7$%=05[I`````,8#`4F+A"1P`@``
+M2(E##$F+A"1X`@``2(E#%$$/MGPD$.B;2/__B$-P00^V1"1%3(GGB$-Q28N$
+M)&@"``")@YP```#HJ;7__TR)YXE#=.@`````QD-R`(F#F````$&`?"1$``^$
+ML````$4Q]NLT@'T0!'10#[93<HN%Z`,``(E$DW@/MD-R@\`!/`>(0W)W9$$/
+MMD0D1$&-5@%)@\8!.=!^4DN+;/1@2(7M=.2`>W,`=;P/MGT0Z`9(__^(0W.`
+M?1`$=;!(BU4X#[9#<HN2Z`,``(E4@WCKJDB-<PS&`P),B>?HRM?__X7`#X7@
+M_O__Z>/^__\/ME-R@_H'#X_6_O__2&/"@\(!@_H'QT2#>/____]^[>F^_O__
+M,=+KY&9F9I!!54F)_4%455-(@^Q(2(M?*(L[A?]U=$B++0````#&1"0P!DB%
+M[70W3(UD)#!(BUT02(7;="!(BT,0,?],B>9(B40D.$B+0PC_D,````!(BQM(
+MA=MUX$B+;0!(A>UUSDF+?1!)C7582<=%6`````!-B6U@2<=%:`````#H````
+M`$B#Q$A;74%<05W#Z`````!(B<4/MD,$3(UC!(3`=3N`?1`!#X0B`0``0<=%
+M4/[____V16@0=*A(BT5P2(N]B````$B)YO]0>`^V1"022(GOB$5FZ`````#K
+MA2P!=`U!QT50_O___^ET____@'T0!)!VMT$/MD0D`3P!=$=F9F:0#X/*`0``
+M08-]'!AF9I!FD'672(V5<`(``#'`Q@00`$B#P`%(@_@0=?))BT0D!$B)`DF+
+M1"0,2(E""("-8`(```3K;D&#?1Q(#X5;____2(V-C`(``#'`Q@0(`$B#P`%(
+M@_@$=?))BT0D!$F-5"0$2(D!2(M""$B)00A(BT(02(E!$$B+0AA(B4$82(M"
+M($B)02!(BT(H2(E!*$B+0C!(B4$P2(M".$B)03B`C6`"```$]H5@`@``!`^$
+MH?[__TB)[^@`````Z93^__]!@'PD`04/A]+^__]!#[9$)`%F9I#_),4`````
+M08-]'`EF9F:0#X6S_O__QD0D,`E!#[9$)`1(C70D,(A$)#A(BT5P2(N]B```
+M`/^0P````$&)15#IC?[__T&#?1P)#X5Z_O__QD0D,`5!#[9$)`3&1"0Y`(A$
+M)#A(BT5P2(UT)#!(B[V(````_Y#`````08E%4(!-:!#I2_[__T&#?1P)#X4X
+M_O__QD0D,`1!#[9$)`3&1"0Y`(A$)#CKO$&#?1P)#X47_O__QD0D,`-!#[9$
+M)`2(1"0XZZ!!@WT<"0^%^_W__\9$)#`"Z^)!@WT<"0^%Z?W__X!-:(#&1"0P
+M`.O,9F:09I`\`G0-0<=%4/[____IT/[__T&#?1P)#[:U@0,```^%MOW__P^V
+M0PA(C7L(0#C&=$"`?1`$B(6!`P``=C2`?40`="XQR4B+5,U@2(72=!.`>A`$
+M=@T/MH6!`P``B(*!`P``#[9%1(U1`4B#P0$YT'_40(#^`G0,@(U@`@``!.E?
+M_O__@#\"=.](Q\(`````3(GN2(GOZ-=J___I$OW__V:005152(G]4TB+7RB+
+M.TR-8P3H`````$B)QHM#!*@!=#I(C99P`@``,<!F9F:09F:0Q@00`$B#P`%(
+M@_@0=?))BT0D!$B)`DF+1"0,2(E""(".8`(```1!BP0DJ`)T8TB-CHP"```Q
+MP,8$"`!(@\`!2(/X0'7R28M$)!1)C50D%$B)`4B+0@A(B4$(2(M"$$B)01!(
+MBT(82(E!&$B+0B!(B4$@2(M"*$B)02A(BT(P2(E!,$B+0CA(B4$X@(Y@`@``
+M!/:&8`(```1T"$B)]^@`````2,=%6`````!(B6U@2(UU6$C'16@`````2(M]
+M$%M=05SI`````&9FD&9FD&9FD$%505154TB)^TB![,@```!,BV<H2(GE08L\
+M).@`````28G%2(U$)`Q(B>=F9I!FD,8'`$B#QP%(.<=U]$F-="0$NK````#'
+M10!\`0``Z`````!(BWL02(GJ3(GNZ'^[__^%P(G"="R#^/]T-4B+0S!(BWL0
+M2(US6$C'0U@`````2(E;8$C'0V@`````B1#H`````$B!Q,@```!;74%<05W#
+MB4-0Z\9F9F:09F:09F:005152(G]4TB+1PA(BQB+LV@"!`!(B=],BZ/@`0``
+MZ(WE__](BU4(2(M%$(MP-#ER-`]#<C1(BSKH`````$B%P$F)P`^$I`$``(L5
+M`````(72?A!(BT4(.Y#<`@``#Y_`#[;008E0:$'&@+(`````#[:%J@```(3`
+M#X7H````2(U%2$F)0'!(BT4(08"(L0````*+BU@"!`!)B4!0#[>%F@````^W
+ME9@````IPHG(BXM@`@0`P>@)@^D!#Z_!.<(/1]"X``$``&:!^@`!#T;"9D&)
+M@)@```"`?2@`#X3R````0?:`L0````0/A.0````/MX68````00^WD)@```!(
+M`X60````2"G0#[>5F@```$@IT$F)@)````!!@(BQ````"$V)8%A(@WM(`$G'
+M@,@`````````2<>`P``````````/A`0!``!(BTM`28U0&$B-0SA(B5-`28E`
+M&$F)2"!(B1%;74%<PSP##X00____2(M%$$&`B+$````$28E`4(N#7`($`(7`
+M#X3*````BXM8`@0`,?9(BY-0`@0`B?!(P>`$A<E(BQ00=!J)R&9FD&:0Q@(`
+M2(/"`4B#Z`%U\XN+6`($`(/&`3FS7`($`'?&Z<G^__\/MX6:````2`.%D```
+M`$F)@)````#I+/___P^VA:H```"$P'5,2(M]"$B-=4CH`````$B+10A(BSCH
+M+^3__T''1"10_____TG'1"18`````$F-="1838ED)&!)QT0D:`````!;74F+
+M?"0005SI`````#P#=;WKKEM=05Q,B<?I`````(N+6`($`.D[_O__9F9FD&9F
+M9I!F9F:09F:02(/L*$B);"002(G]2(E<)`A,B60D&$R);"0@#[:%L@```$B+
+M5U!,BV=82(L_2(N:@`(``#P!=$@\`@^$5P$``$B-<S#&A;(`````2(/'2$C'
+M0S``````2(EK.$C'0T``````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HZ0``
+M```/MX.:````9@.%F````$@[4PAFB8.:````#X3G`@``#[>#F@```&8[@Y@`
+M```/@XT!```/MH6Q````2,=%>`````!(QT5P`````(/@_8/(!(B%L0```$B+
+M4Q!(B550QH6R``````^W@YH````/MY.8````BX]@`@0`@^D!*<*+AU@"!`#!
+MZ`D/K\$YP@]'T+@``0``9H'Z``$/1L)FB868````@'LH`'0-]H6Q````!`^%
+M;@(```^W@YH```!(`X.0````2(F%D````/:%L0````(/A/T!``!(@W](``^$
+M\@$``$B+3T!(C5482(U'.$B)5T!(B4482(E-($B)$4B+7"0(2(ML)!!,BV0D
+M&$R+;"0@2(/$*,-(BT,(QH.K`````8"@@`,``/Y(BT,0@*"``P``_DB+0PB`
+MH&$"``#W2(M#$("@80(``/=(BT,(2(LXZ/KA__\/MH.J````A,`/A/L````\
+M`P^$\P```$B)[^@`````0<=$)%#_____28M\)!!)C70D6$G'1"18`````$V)
+M9"1@2<=$)&@`````2(M<)`A(BVPD$$R+9"083(ML)"!(@\0HZ0````!F9F:0
+M2(N:@`(``(![*`!(BTL(2(M3$$0/MJNJ````#X21````#[>#F````$B+DZ``
+M``!(*<)!@/T!2(F3H`````^$<P$``$&`_0(/A'\!``!(@[N@``````^%CP``
+M`$B+.>@MX?__183M#X0X`0``08#]`P^$+@$``$B)[^@`````2(G?2(ML)!!(
+MBUPD"$R+9"083(ML)"!(@\0HZ0*;__]FD$B+>PA(C7-(Z`````#I^_[__P^W
+M@Y@```!(`X.@````183M2(F#H````'5I2#M!*'4'QH.J`````4B+0BA(.8.@
+M````#X1Q____2(LYZ)[@__]%A.T/A)<```!!@/T#D`^$C````$B)[^@`````
+M9I#IJ?[__TB)[TB+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*.D`````08#]`W6>
+M2#M!*'68Z17___]F.X.8````9F:0#X)(_?__9L>#F@``````Z?O\__\/MX.8
+M````#[>3F@```$@#@Y````!(*=`/MY68````2"G02(F%D````.EY_?__2(M[
+M"$B-<TCH`````.EB____2(M["$B-<TCH`````.G`_O__2#M1*`^%C?[__\:#
+MJ@````#I@?[__T@[42@/A7?^___I@/[__V9FD&:0]H>Q`````DB+!\:'L@``
+M``!T(TB#>$@`=!Q(BTA`2(U7&$B)4$!(@\`X2(E'&$B)3R!(B1'#Z0````!F
+M9I!FD%-(B?M(BS^+MV@"!`#HSM[__TB+`TB#>$@`=!U(BTA`2(U3&$B)4$!(
+M@\`X2(E#&$B)2R!(B1%;PTB)WUOI`````&9F9I!F9F:09F:09F:02(/L.$B)
+M7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$B+7UA,BW=@3(LK38NEX`$`
+M`$F+1"0H1(LXZ`````"`>Q`$#X:=````2(NK@`(``$B%[0^$[0```$B+?0A(
+MA?]T#+H"````,?;H8+#__TB+?1!(A?]T#+H"````,?;H2[#__TB+11A(BU4@
+M28V]T````$B)[DB)4`A(B0+H`````$&-7@%$.?MT5$F+1"0HB=J+?)`$Z```
+M``")WDB+;"002(M<)`A,BV0D&$R+;"0@2(G'3(MT)"A,BWPD,$B#Q#CIJ&#_
+M_TB)WT&-7@'H`````$0Y^W6S9F9FD&9FD$F+?"0028UT)%A)QT0D6`````!-
+MB60D8$G'1"1H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#
+MQ#CI`````+H"````,?9(B=_H>:___^E'____9F9FD$B#["A,B60D$$B)7"0(
+M28G\3(EL)!A,B70D($R+=PA(BU\028L&2(G>3(GW3(NHX`$``.CH1/__2,>#
+M@`(```````!)QX:``@```````$$/MI:``P``#[:#@`,``$F-=5B#X@2#X/L)
+MT(B#@`,``$$/MI:``P``@^#]@^(""="(@X`#``!!#[9&2(A#2$F+?1!)QT58
+M`````$V);6!)QT5H`````.@`````2(G>OQ4```#H`````$F+5"0828M$)"!)
+MC70D,$F+/DG'1"0P`````$V)9"0X2<=$)$``````2(E""$B)$$B+7"0(3(MD
+M)!!,BVPD&$R+="0@2(/$*.D`````D)"0D)"0D)"0D)"02(N'V`,``$B%P'0?
+M2(M6"$@Y$',-2(L.2#E("`^'JP```$B+0!!(A<!UY4B+EZ`#``!,C8>@`P``
+M3#G"=#IFD$B-0NB`N+``````=2-(BXB0````#[>`F````$@!R$@Y!G,-2#M.
+M"')D9F9FD&9FD$B+$DDYT'7(2(N/L`,``$B!Q[`#``!(.?EU%^M&9F:0@/J`
+M=!Q(BPE(.?EF9I!FD'0Q2(U!Z`^VD+````"$TG7?2(N0D`````^W@)@```!(
+M`=!(.09SSD@[5@ASR+@!````PS'`PV9F9I!F9I!F9I!(@^P02(D<)$B);"0(
+M2(G[2(GUZ`C___^%P'4B2(N#V`,``$B)11!(B:O8`P``,<!(BQPD2(ML)`A(
+M@\00PTB#?2@`N/____]TYDB+@^`#``!(C9/@`P``2(7`=`U(C5`02(M`$$B%
+MP'7SN/____](B2KKO&9F9I!F9F:09F9FD$B+A]@#``!(C9?8`P``2#GP=`U(
+MC5`02(M`$$@Y\'7S2(M.&$B+1A!,C4X83(N'T`,``$DYR4B)`DC'1A``````
+M=!U(BU8@28L`3(E!"$F)"$B)4`A(B0),B4X@3(E.&$B+!\=`:`$```##9F:0
+M9I!(@S\`=`U(BT<(2(EP$$B)=PC#2(EW"$B)-\-F9I!FD$B#QUCI`````&9F
+M9I!F9I!32(N'@````$B)^TB%P'042,>'@`````````!(B[>(````_]!(BX/(
+M````2(L[2(US*$B)6S!(QT,X`````$B)0RA(@\=86^D`````9F9FD$B#[!A(
+MB5PD"$B)^TB);"002(MO4.@`````2(MS>$B+4QA(C4L82(M#((.MB`,```&#
+MK80#```!2(7V2(E""$B)$$B)2R!(B4L8=!9(B>](BUPD"$B+;"002(/$&.D`
+M````2(M<)`A(BVPD$$B#Q!C#9F9FD&9F9I!F9F:09F:0055!5%532(GSB=9(
+M@^P(3(M'6$R+IY````!$#[>OF````$F+B+@```!)BZB0````2(7)#X2H````
+M00^V@+$````/M]*#X`$/ML`YT`^$CP```$2+`42)YRGOP><)1#G'1(G`<PWI
+MI@```&9FD&9FD(G02(/!$(G"`Q$YUW/R1(L!*<=!#[?UB?I(`U$(02GXP>8)
+M1(D#1#G&2(E3"$B-4Q!V)4B+01@K,\=#!`````!(B=-(B4((BT$02(/!$(D"
+M2(/"$#GP<MN),\=#!`$```!(@\0(6UU!7$%=N`$```##28N`P````$B%P'06
+MB?),B<=(B=[_T(7`=`A(B=GI3____TB#Q`@QP%M=05Q!7<,QP.EJ____9F:0
+M9F:09F:0055!5%532(G[2(/L"("_L`````!(BV]0#X42`@``#[>'F````$R+
+MIY````!*C0P@2(N%V`,``$B%P'0V#[:7L0```(/B0(32=`>+<$"%]G052#E#
+M<'0/2#L(=@I,.V`(#X+R`@``2(M`$$B%P&9FD'742(-[<``/A*$"``"`?1`$
+M#X:I`0``3(NM@`(``$V%[0^$/0(``$&`O:L`````#X4O`@``]H.Q````"`^%
+M(@(``$B!N\@`````````#X01`@``23MM"`^%!P(``$&`?2@`#X3H`@``28N%
+MH````$DYQ`^#(P$``$@YP0^&XP$``$B+>PB#1P@!Z`````!(B<=(BP-(B0=(
+MBT,(2(E'"(M#:(E':$F+10A,B:>0````2(E'4+Z`____28N%H````$B)7UC&
+MA[(`````2,>'P`````````!(QX?(`````````$C'A[@`````````9D0IX&:)
+MAY@````/MH>Q````#[:3L0```(/@/R'6B=&#X4`)\+XP````"<@AUHG1@^#'
+M@^$("?`)R(G1@^("@^$$@^#Y"<@)T`^VD[$```"#X/Z#X@$)T(B'L0```$B+
+M4W"X`0```$B%TD@/1<)(C5,82(E'<$F+10A(BXBX`P``2(F0N`,``$@%L`,`
+M`$B)0QA(B4L@2(D1QH.P````@$B#Q`A;74%<05WI`````$F+11"#K80#```!
+M2(E#4$B)Q8.`A`,```&`>!`$#X>F````9I!(BY6@`P``2(V-H`,``$@YRG4L
+M2(L#2(E+&,=`:`$```!(C4,82(E!"$B)A:`#``!(B4L@2(/$"%M=05Q!7<.#
+M>V@`=3=(B[6H`P``2(U^Z(M':(7`#X@5`0``2(U#&$B)2QA(B86H`P``2(D&
+M2(ES($B#Q`A;74%<05W##X[,````2(U#&$B)4QA(B4((2(F%H`,``$B)2R!(
+M@\0(6UU!7$%=P_:#L0````0/A$_____VA6$"```@#X1"____@*5A`@``W^@`
+M````@(U@`@``!(E%/$B+`\>`E`($``$```!(BT582`E%4.D2____]H.Q````
+M0`^%4OW__TB+A>`#``!(A<!U%NE!_?__9F9FD$B+0!!(A<`/A##]__](.PAV
+M[DP[8`ASZ$B+2"!(C5,82(E0($B#P!A(B4,82(E+($B)$4B#Q`A;74%<05W#
+M2(N5J`,``$B-0QA(B4L82(F%J`,``$B)`DB)4R#IQ/[__X-':`%(BU8(2(U#
+M&$B)<QA(B48(2(D"2(E3(.FD_O__28N%H````$@YP0^&._[__TDYQ`^#^_[_
+M_TB+>PB#1P@!Z`````!(B<=(BP-(B0=(BT,(2(E'"(M#:(E':$F+11#I$_W_
+M_V9F9I!F9I!F9I!32(M'4$B)^TB+=WB#@(0#```!2(7V="E(B7XP2(M_4$C'
+M1B@`````2,=&.`````#H`````(7`=1=(BT-X2(E#<$B)WUOI`````&9FD&9F
+MD%O#9F9FD&9F9I!F9I!F9I!52(GY4TB#[`B`N;(````!2(M?6$B+?U!$#[>)
+MF`````^WLY@```!(BZ^``@``=$$/MH&R````2(M["$B)SL:#L`````"(@[(`
+M``#H`````$B+0PA(B=^#:`@!2(M%"(.`B`,```%(@\0(6UWI`````$B+@Y``
+M``!(.8&0````=:^+04!,BT%(A<!T$HG"3(G`Q@``2(/``4B#Z@%U\TB+10A(
+M.?AT,DB)05!(BX6@````9D0ISF:)L9@```#&@;(`````2(G/2(F!D````$B#
+MQ`A;7>D`````2(M%$.O(D$%72(U'&$R-?UA!5D%528G]05154TB#[!A(B40D
+M"$B-1SA(B00D0<=%:`````#K&TB+0A!(A=))B458="U(QT(0`````$B+>@C_
+M$DF+55A).U5@==M(A=))QT5@`````$G'15@`````==--BW483#MT)`@/A&4"
+M``#'1"04`````$BX(````/____])A4;P28VN</S__TF-7A!T",=$)!0!````
+M3(VEL`,``&9FD&:02(N-H`,``$@YV0^$D@```$B+$4B+00A(B<](@^\82(E"
+M"$B)$$B)20A(B0ET=`^VE8`#``#VP@$/A&(!``!$BY6(`P``1872=`^+A<0#
+M```[1V@/CZL!``"#XA@/A:(!``"+1VA,B6<8@X6(`P```8F%Q`,``$B+A;@#
+M``!(B8VX`P``2(D(2(E'($B+10C_4"A(BXV@`P``2#G9#X5N____3(VER`,`
+M`&9F9I!F9I!(BXW(`P``3#GA=&1(BQ%(BT$(2(G+2(/K&$B)0@A(B1!(B4D(
+M2(D)=$9(BW-X2(7V="E(B5XP2(M[4$C'1B@`````2,=&.`````#H`````(7`
+M=:Q(BT-X2(E#<$B)W^@`````2(N-R`,``$PYX76<2(.]X`,```!,C:7@`P``
+M="E)BQPD2(7;="!(B=Y(B>_HR_3__X7`#X2$````3(UC$$F+'"1(A=MUX$V+
+M-DP[="0(#X5I_O__1(M,)!1%A<D/A+@```!)@WU8``^%]?W__T&+?6B%_P^%
+MZ?W__TB#Q!A;74%<05U!7D%?PV9F9I#&A[(````"2(N%N`,``(.%B`,```%(
+MB8VX`P``3(EG&$B)1R!(B0CH`````.DO_O__2(M#$$B-<RA,B?])B00D2(N%
+MV`,``$B)0Q!(B9W8`P``Z`````!!QT5H`0```.DM____2(N%H`,``$B-5QA,
+MC:7(`P``2(E0"$B)1QA(B5\@2(F5H`,``.F"_O__18N%E`($`$6%P'0=ZVU(
+MBT(028E%2$B%TG112,="$`````!(BWH(_Q))BU5(23M54'7;2<=%4`````!)
+MQT5(`````.O12(L12(M!"$B)STB#[QA(B4((2(D02(E)"$B)"0^$X?[__^@`
+M````28M-.$@[#"1US^G-_O__0<>%E`($``````!,B>_H`````.N99I!32(L?
+M2(-[2`!T)$B+2T!(C5<82(U#.$B)4T!(B4<82(E/($B)$4B)WUOI`````.@`
+M````Z_"0D)"0D)"0D)"0,=)(A?]T#$B-1_^#P@%((<=U](G0PV9F9I!F9I!F
+M9I!!54G'Q?[___]!5%532(G[2(M[4$B+:QA(A?]U#?:#8`(```(/A9H```!%
+M,>1("WM8Z`````!(BU,(1`'@#[92"CG0?D>`HX`#``#^]H.``P```70P2(7M
+M="L/MG5$0(3V=")(.5U@3(GH=$PQTNL-#[;*2&/!2#E<Q6!T,8/"`4`X\G7K
+M6UU!7$%=PTB+0U"`BX`#```!2(7`=+!(B<)(,U-8=3>`HV`"``#]ZYY(Q\#^
+M____2-/`2"%%6$B)Z^E,____2(M#"(!X"P$/A5C___]$#[9@"NE1____2(70
+MD`^$9O___X"+8`(```+I6O___V9F9I!F9F:09F:09F:02(MW&$0/MD9$183`
+M="<QR3'22#E^8'45ZR!F9I!F9I`/MLI(8\%(.7S&8'0-@\(!1#C"=>NY_P``
+M`(G(PV9FD$R+1CA-A<!T3TF+0!A(A<!T/DB+0!A(A<!T-4@Y^'1`#[901(72
+M?NHQ]DB+3/!@2(7)=`N`>1`$=@5(.?ET(4B#Q@$Y\G_C2(M`&$B%P'7+38L`
+M387`=;$QP,-F9I!FD+@!````PV9F9I!F9I!F9I!!5$F)U%5(B?532(G[2(/L
+M$(!_$`0/AH\```#'1"0,`````,=$)`@!````#[9/1(7)?B=(BW]@,=)(B=A(
+MA?]T$NF%````2(MX:$B#P`A(A?]U>(/"`3G*=>Q(BU,(@'H)`'0D#[9#1`^V
+M4@HIT`^O1"0(B40D"`^W0T8[1"0,#T9$)`R)1"0,2(7M=`>+1"0,B44`387D
+M=`B+1"0(08D$)$B#Q!!;74%<PTB%]G0&QP8`````387D=.=!QP0D`0```$B#
+MQ!!;74%<PTB-5"0(2(UT)`SH`````$B+4PB`>@D`=*3I>____V9F9I!F9I!3
+M2(G[2(/L$$B+?PA(C50D"$B-="0,Z`````!(BWL02(UT)`1(B>+H`````(M4
+M)`@[%"2+1"0,#Y=#*#E$)`0/0T0D!`^OPKJ`````9H7`#T709HF3J````$B#
+MQ!!;PY!!5$F)]%53#[9'$$B)^SI&$'0-N`$```!;74%<PV9FD`^W1T1F.T9$
+M=>F`?T0`#X28````2(M_8$B+=F!(A?]TTC'M2(7V=,N`?Q`$=CB`?A`$=K_H
+M`````(3`=;8/ME-$C44!.<)^9$B+?.MH28MT[&A(@\4!2(7_=)A(A?9TDX!_
+M$`1WR(!^$`1WATB+1CA(.4<X#X5Y____2(M72$B+1DA(BT@(2#E*"`^%8___
+M_TB+2!!(.4H0#X=5____]H-@`@```W26Z4?___\QP&:0Z4/___]F9F:09F9F
+MD&9FD%-(BU\(2(M'$$B%VW0R2(7`=&[V@X`#```!=3F`H(`#``#^QT,P____
+M_X"C@`,``/[&AZL````!6\-F9I!F9I!(A<!T[("@@`,``/[&AZL````!6\/V
+M@(`#```!=+[&AZL`````@(MA`@``!("(80(```3H`````$B)WUOI`````("C
+M@`,``/[&AZL````!6\-F9F:09F9FD&9F9I!F9I!!5TF)]T%6055!5%5(B?U3
+M2(/L&`^V5T2%T@^.C0$``$4Q[>F&````2(7`28EL)!AT"$C'0!@`````3HED
+M[6`/MI5@`@``2,>%:`(```````")T(/("J@@B(5@`@``=`F#RHJ(E6`"```/
+MMDPD%+@!````2-/@2`E%4$CWT$@A15A-A?\/A#L!``"`C6`"```$387_#X43
+M`0``#[951$&-10%)@\4!.<(/CO\```!$B6PD%$J+1.U@2(7`=`GV@(`#```!
+M==1-A?]-B?P/A5;___](BT4(#[9`"BG"2(M%*$ACTDB)T3'22/?Q2(D$)$B+
+M10!(BU@82(/`&$@YPW2:13'D2,=$)`C_____ZQ)FD$B+10!(BQM(@\`82#G8
+M=%#V0_`!3(VS</S__W3C@+N`_/__`77:]H/8_/__!'313(GV2(GOZ';[__^$
+MP'7"2(N#L/S__T@Y!"1WM4@[1"0(<ZY-B?1(B40D".ND9F9FD$V%Y`^$(?__
+M__:%80(```)T:TF+1"0X2(7`=!=F9F:02(-X&``/A?_^__](BP!(A<!U[4J+
+M1.U@Z7O^___VA6`"```(=2%(@\086UU!7$%=05Y!7\-,B>:_!P```.@`````
+MZ;/^__](@\082(GO6UU!7$%=05Y!7^D`````2(LT)#'23(GGZ`````!(A<!)
+MB<0/A)/^__]*BT3M8.D7_O__9F9FD&9F9I!F9F:09F:0059!54%454B)_5-(
+M@>P``@``@'\0!'8'@*=@`@``^_:%@`,```%T6H!]$`1V9(!]1`!T3C';2(M,
+MW6!(A<ET,P^VE8`#```/MH&``P``@^("@^#]"="(@8`#``!(BWS=8(!_$`1V
+M!P^V14B(1TCH``````^V142-4P%(@\,!.=!_M$B!Q``"``!;74%<05U!7L-,
+MBW4X0?:&@`,```$/A.$"``!,BVT813'D387M=`U-BV48387D#X0"`P``2(GC
+M2(G@2(V4)``"``#&``!(@\`!2#G0=>Q-A>3'`_06>%H/A,("``!!BT0D.(E#
+M!$&+1"1`B8/&````]H6``P```G0$@$L6`4V%Y`^$IP(``$F#_0$9P(/``HA#
+M&$F+C"2``@``2(7)=#F+`0^V4Q:)0PA(BX&@````@^+]2(E##`^V02B#X`$!
+MP`G"B%,63#EA$`^$=@(```^V@:H```"(0Q1!#[9$)$A-A>U,B>](#T3]B(/%
+M````00^VA"2!`P``B$,728M$)"A(B4,900^V1"00B$,A00^V1"1$B$,BZ+WX
+M__^(0R-!#[9$)$4/ME,EB$,D00^VA"1@`@``@^+[@^`!P>`""<*(4R5!]H0D
+M8`(```)T!H/*`8A3)4F+1"1028V4)(P"``!(C4M=2(F#K0```$F+1"109HE#
+M)TF+A"1H`@``2(E#*4&+1"0\B8.]````28N$)'`"``!(B4-)28N$)'@"``!(
+MB4-108N$)(@"``")0UE)BX0DS`(``$B)@YT```!)BX0DU`(``$B)@Z4```!)
+MBX0DC`(``$B)0UU(BT((2(E!"$B+0A!(B4$02(M"&$B)01A(BT(@2(E!($B+
+M0BA(B4$H2(M",$B)03!(BT(X2(E!.$V%[71]28M%*$B)[TB)0S%!#[9%$(A#
+M.4$/MD5$B$,ZZ*/W__^(0SM!#[9%10^V4SV(0SQ!#[:%8`(``(/B^X/@`<'@
+M`@G"B%,]0?:%8`(```)T!H/*`8A3/4F+15!(B8.U````28M%4&:)0S])BX5H
+M`@``2(E#04&+13R)@\$```!(B=_H`````+X``@``2(GGZ`````#WV$4QP$B)
+MX8A#%4B+=4"Z`0```$B+?3CH`````$F+1E!(BWTX13'`2(GAN@$```!(B<9(
+M`W5`2"T```(`2"4``/[_2('N``@``$@IQN@`````3(MU.$'V1F@0#X3R_/__
+M3(GWZ`````!(@<0``@``6UU!7$%=05[#,<#'0P0`````Z3W]___&0Q@`Z=G^
+M__],B>A%,>U)B<3I\/S__X/*!(A3%NE__?__9F9FD&9F9I!52(UO&%-(@^P(
+M2(M?&$@YZW4*ZT=(BQM(.>MT/X"[@/S__P1(C8-P_/__=NCV@]#^__\$=-](
+MBW@82(7_=`V02(GX2(MX&$B%_W7T2(G'Z`````!(BQM(.>MUP4B#Q`A;7<-F
+M9F:09F:09F:09F:005154TB)^TB+?QA(A?]U].@`````3(NC@`(``(E#.$V%
+MY'0Q28ML)`A(.=UT3N@`````2(7M08D$)'099F9FD.@`````B44X.T,X=/-(
+MB>_H`````$B)W^@`````2(M#"$B+0&!(A<!T#4B)WTF)PUM=05Q!_^-;74%<
+MPTF+;"00ZZMF9F:09F:09F:09F:0055!5%5(B?U32(/L"`^V1Q"#Z`4\!0^'
+MU`````^VP/\DQ0`````/MT=&2/?82"&':`(``/:'@`,```$/A;0!``!(BU58
+M2(72=0=(@WU0`'1/@'T0"@^$N@$``("E8`(``/Y(A=)T.8"-80(``"!(@WU8
+M`'0K]H6``P```71R2(M5&$B%TG0)]H*``P```70=,?9(B>_H`````&9FD&9F
+MD/:%@`,```%T1TB+51CVA6$"```$=3[VA6`"```#=#5(BTU02(7)#X5G`0``
+M2(72=`GV@H`#```!=".`C6`"```(2(GOZ`````!F9F:09F:02(M5&$B%T@^$
+MV0```$B#Q`A;74%<05W#13'M13'D@']$`'43Z]H/ME5$08U$)`%)@\0!.<)^
+M3DJ+7.5@2(7;=.6`>Q`$=M](B=_H`````/:#8`(```1T!X"-8`(```0/MH-@
+M`@``#[951(/@`SP"N`$```!$#T3H08U$)`%)@\0!.<)_LD6%[0^$<O___X"E
+M8`(``/XQVX72?QCI8/___P^V142-4P%(@\,!.=`/CDW___](BWS=8$B%_W3C
+M@'\0!';=]H=@`@```734#[:'8`(``(/@OH/(`HB'8`(``.@`````Z[KVA6`"
+M```$#X0:____2(/$"$B)[UM=05Q!7>D`````2(M76$B)T$CWT$B%1U`/A#S^
+M__^`CV`"```"Z3#^__\/MDU$N`$```"#Z0%(T^!(.450#X4M_O__Z2_^__](
+MBT582/?02(7!#X2Q_O__Z83^__]F9F:09F9FD$B#[!A(B5PD"$B);"002(G[
+M2(GUZ%?S__^$P'5#]H-A`@```DB+0PA(BW,H#[9+1`^V4`IT,3'`]H-@`@``
+M!'4/2(M<)`A(BVPD$$B#Q!C#2(G?Z``````QP.OE9F9FD+C_____Z]H/ML$/
+MMM(IT$ACT$B)\$B)US'22/?W,=)(B>](B<;H`````$B%P'312(G&2(G?Z```
+M``#KFF9F9I!!5$&)U$N-!&152(TLQE-(B?,/MG4AZ`````!(A<!(B<</A"@!
+M``"`H(`#``#^#[9#%XB'@0,``(M#!(E'.(N#Q@```(7`B4=`=0:+0P2)1T`/
+MMH/%````2(UU$(A'2`^V5A4/MH=@`@``P.H"@^(!@^#^"="(AV`"``!(BT4I
+M2(F':`(``$*+A*.]````B4<\#[9-)+@!````T^"(3T5FB4=&2(M&"4B)1R@/
+MMDTB2,?`_____X#Y/XA/1`^&E0```$B)1UA(BT-)2(U374B-CXP"``!(B8=P
+M`@``2(M#44B)AW@"``"+0UF)AX@"``!(BX.=````2(F'S`(``$B+@Z4```!(
+MB8?4`@``2(M#74B)AXP"``!(BT((2(E!"$B+0A!(B4$02(M"&$B)01A(BT(@
+M2(E!($B+0BA(B4$H2(M",$B)03!(BT(X2(E!.%M=05Q(B?C#N`$```!(T^!(
+M@^@!Z5K___]F9F:09F9FD$B![#@"``!!N`$```"Z`0```$B)G"0(`@``3(FD
+M)!@"``!(B>%,B;0D*`(``$B)K"00`@``28G\3(FL)"`"``!,B;PD,`(``$F)
+MYDB+;SA,BS](BT502(G&2`-W0$@M```"`$@E``#^_TB)[TB![@`(``!(*<;H
+M`````(7`B<,/A,L```!)BW0D0$F+?"0X0;@!````2(GAN@$```#H`````(/X
+M_T&)Q7163(GWZ`````!!@3[T%GA:#X3$````N/____](BYPD"`(``$B+K"00
+M`@``3(ND)!@"``!,BZPD(`(``$R+M"0H`@``3(N\)#`"``!(@<0X`@``PV9F
+M9I"%VW6[2(M%4$F+?"0X0;@!````2(GAN@$```!(B<9)`W0D0$@M```"`$@E
+M``#^_TB![@`(``!(*<;H`````(7`#X1D____Z73___]F9I!FD$B)Y^@`````
+M@3PD]!9X6I!T"KO^____Z1G___^^``(``$B)Y^@`````A,`/A`3____KW[X`
+M`@``2(GG9F:09I#H`````(3`#X4B____187M#X5`!```A=L/A9<%``!!@'XA
+M!`^&!O___T&`?B)`9I`/A_G^__]!@'XZ0&9FD&:0#X?I_O__28M?&$F-5QA%
+M#[=N)TT+KJT```!(.=-T)H"[@/S__P1(C:MP_/__=@Y(@[N(_/__``^$"`0`
+M`$B+&T@YTW7:,=),B?9,B?_H;OS__TB%P$B)Q0^$D?[__P^VE6`"```/MDU$
+MB="#XOW0Z$$*1B6#X`$!P`G"@/D_2,?`_____XB58`(``$B+55!W#+@!````
+M2-/@2(/H`4PAZ$@)T`^VE6`"``!(B45000^V1B6#X@'`Z`*#X`$XPG0C#[:5
+M8`(``$B+10B#XOZ(E6`"``"`>`H`=`F#R@*(E6`"``!!BU8(A=)T94B+C8`"
+M``"`C6$"```$2(7)#X3I`@``@'DH``^$R0(``$F+1@Q(.8&@````=A)(B8&@
+M````00^V1A2(@:H```!!]D86!`^$D`0``$B+41!(A=(/A',$``!(BT$(2#G"
+M#X14!```BT4\03N&O0````^$6`(``("-8`(```)(QX5H`@````````^VE8`#
+M``")T(/B_=#H00I&%H/@`0'`"<*(E8`#``!!@'X8`4$/MD8C#X:;`0``1`^V
+MZ$J+7.U@2(7;#X3;`0``#[:3@`,```^V2T1(BWM0B="#XOW0Z$$*1A:#X`$!
+MP`G"B).``P``#[:38`(``(G0@^+]T.A!"D8]@^`!`<`)PH#Y/XB38`(``$C'
+MPO____]-BX:U````00^W=C]W#+@!````2-/@2(T4$`^WQDP)P$@APD@)^DB)
+M4U!!#[9&/0^VDV`"``#`Z`*#X@&#X`$XPG0C#[:38`(``$B+0PB#XOZ(DV`"
+M``"`>`H`=`F#R@*(DV`"``!!#[9..TACP4B#?,-@``^%<OS__TR)9,-@BT,\
+M03N&P0```$F)7"08#X2%````@(M@`@```DC'@V@"````````2,?`_O___TB)
+MWTC3P$@A0UCH``````^V@V`"``"H$'4-J"!T%(/(@(B#8`(``$C'@V@"````
+M````]H6``P```71*2(N%@`(``$B%P'0^2(M0"$B%TG0U2(MX$$B%_W0L2#G5
+M2`]%^N@`````,<#IV/O__TF+1D%(.8-H`@``=H!(B8-H`@``Z73___\QP.FX
+M^___#[;(28EL)!A(B>](8\%,B63%8$C'P/[___](T\!((458Z``````/MH5@
+M`@``J!!U$:@@#X1M____@\B`B(5@`@``2,>%:`(```````#I5/___[H!````
+M3(GV3(G_Z"+Y__](A<!(B<,/A$7[__](B6@82HE$[6#I^_W__TF+1BE(.85H
+M`@``#X:I_?__2(F%:`(``.F=_?__28M&#$@Y@:`````/@T7]___I+OW__TF+
+M1RA)C5\H2#G8#X33````.U#H2(U(Z`^$M@```$B+`$@YV'7KZ;D```!,B??H
+M`````$F+="1`28M\)#A%,<!(B>&Z`0```.@`````3(GWZ`````#IF?O__XN#
+MJ/S__T$[1@0/A>C[___V0_`!#X7O````08!^&`$/AO3[__]!#[9&(TB+7,5@
+M2(7;#X3A^___]H.``P```0^$U/O__TB+>U!!#[=&/TD+OK4```!("<?H````
+M`$B+4P@/ME(*.=`/CJS[__](B>_H`````.F&^___2(7)2(F-@`(```^%,_S_
+M_TF-O]````#H`````$B%P$B)P4B)A8`"```/A`'Z__\QP,8$"`!(@\`!2#VP
+M````=?!)BT<P2(U1&$B)61A)B5<P2(D02(E!($&+1@B)`4F+1@Q(B8&@````
+M00^V1A2(@:H```!!]D86`@^$Q/O__TB+A8`"``#&0"@!Z;3[__],B>]("[O`
+M_/__Z`````!(BY-X_/__#[92"CG0#X]"____Z>K^__],B??H`````$B+15!(
+MB<9)`W0D0$@M```"`$@E``#^_TB![@`(``!(*<;I?_[__[C_____2,=!"```
+M``#I/OG__TB+00A(B>I(B6D0Z8'[__](BT$(2(7`=`E(BU$0Z6_[__](BU$0
+M2(GH2(EI".E?^___9F9FD&9F9I!52(G]4TB#[`A(BU\8#[9#1(3`#[;0#X0;
+M`@``,<E(.7M@=1/I#@(``&9F9I!F9I!(.6S+8'0+2(/!`4@YT6:0=>ZX`0``
+M`$C3X$@)0UA(B=_H`````/:#@`,```$/A;T```!(BT,82(7`#X26`0``2(M`
+M"$B)W_]0,#'V@'M$`'1;2(M4\V!(A=)T1/:"@`,```%T.X!Z$`1V-0^VBF`"
+M``")R(/@CT@YZHB"8`(```^$7P$``/:"8`(```%T$8/ACH/)`HB*8`(``&9F
+MD&:0#[9#1$B#Q@%(.?!WI4B+@X`"``!(A<`/A`X!``!(BU`(2(72#X0!`0``
+M2(MX$$B%_P^$]````$@YTT@/1?J`IX`#``#^2(/$"%M=Z0`````/MH-@`@``
+M@^"_J""(@V`"``!T%(/(@$C'@V@"````````B(-@`@``#[:38`(``(G0@^#^
+MB(-@`@``2(M#6$CWT$B%0U!U"8/B[(B38`(``$B+<QA(A?8/A(4```"`IF`"
+M``#^@'Y$`'1X,>TQR6:02(M4SF!(A=)T-O:"@`,```%T+8!Z$`1V)_:"8`(`
+M``%T'@^V@F`"``"]`0```(/@K(/(`HB"8`(``&9FD&9FD`^V1D1(@\$!2#G(
+M=[-(@[N``@```'1>]H-@`@``!'4SA>UU.8"+80(``"!(@\0(6UW#,>WKUTB)
+MW^@`````9I#I9?[__X/AC(B*8`(``.FM_O__2(G?Z`````#KQTB)W^@`````
+MZ[VX`0```&9F9I#I!?[__TB+0QA(A<!F9F:0=`I(@[B``@```'6+BU,PA=)X
+M#S'V2(G?Z`````#I=?___TB%P`^$;/___XM`,(7`>>'I8/___Y"0D)"0D)"0
+MD$B+!0````!(A<!T,S')9I"`>`P!2(L`@]G_2(7`=?&%R70<BQ4`````C8+_
+M#P``A=(/2-#!^@R)T,'Z'_?YPXL%`````(V0_P\``(7`#TC"P?@,PV9F9I!F
+M9F:09F9FD//#9F9FD&9F9I!F9I!F9I!(BX>(`0``2(E&&$B)MX@!``##9F9F
+MD&9FD&9FD&9FD#'`PV9F9I!F9I!F9I!F9I!!5$F)_%53BX=P`0``QX>X`0``
+M`````$F+K"20`0``2(7M=$,Y10!W:$DYK"28`0``#X2.````2(M%($F)A"20
+M`0``2,=%(`````!(BWT0_U4(28NL))`!``!!BX0D<`$``$B%[76]/7\!``!W
+M'DF+G"2(`0``2(7;=!$Q]DB+._]3"$B+6QA(A=MU[UM=05S#28N<)(@!``!(
+MA=MT[F:02(L[BW4`_U,(2(M;&$B%VW7N08N$)'`!```[10`/@U3____KQTG'
+MA"28`0```````$G'A"20`0```````.EA____9F9FD&9F9I!F9I!F9I!52(G]
+M4TB#[`A(BY^(`0``2(7;=!1(BSN^______]3"$B+6QA(A=MU[#'`2(-]6``/
+ME<!(@\0(6UW#9F:09F:04XN'N`$``$B)^X7`=`);PTB)NZ@!``!(QX>@`0``
+M`````$B-MZ`!``!(QX>P`0```````$B-?UCH`````,>#N`$```$```!;PV9F
+M9I!F9I!(@^P(2(._D`$```!T(DB+AY@!``!(B7`@2(FWF`$``.@`````N`$`
+M``!(@\0(PY"+AW`!```[!G,02(FWF`$``$B)MY`!``#KUDB+?A#_5@@QP.O5
+M9F9FD&9F9I!F9I!(@<=H`0``Z0````!F9F:02('':`$``.D`````D)"0D`^V
+M1Q2)P@I7%8/@^X/B!`G0#[97%8G!@^#^@^$!@^(!"<H)T(A'%`^V1R2)P@I7
+M)8/@^X/B!`G0#[97)8G!@^#^@^$!@^(!"<H)T(A'),.0#[9')8G""E<F@^#[
+M@^($"=`/ME<FB<&#X/Z#X0&#X@$)R@G0B$<E#[9'/8G""E<^@^#[@^($"=`/
+MME<^B<&#X/Z#X0&#X@$)R@G0B$<]PP``````````````````````<C<U,%]#
+M;VUP;&5T95)E<75E<W1!;F13;&]T````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M```@```$1````"`!``1$```"`0```CH```(!`0`".@``!`$```L````$`0$`
-M"P````@!```&6@$`"`$!``9:`0`0`0```Q0!`!`!`0`#%`$`(`$```8H```@
-M`0$`!B@``$`!```#$0``0`$!``<G``"``0``"T<#`(`!`0`+1P,`````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -7496,6 +6092,30 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M`````````%)O8VME="`W-3`@4T%402!#;VYT<F]L;&5R```!````````````
+M``````````````````"6,`=W+&$.[KI1"9D9Q&T'C_1J<#6E8^FCE62>,HC;
+M#J2XW'D>Z=7@B-G2ERM,M@F]?+%^!RVXYY$=OY!D$+<=\B"P:DAQN?/>0;Z$
+M?=3:&NODW6U1M=3TQX73@U:8;!/`J&MD>OEB_>S)98I/7`$4V6P&8V,]#_KU
+M#0B-R"!N.UX0:4SD06#5<G%GHM'D`SQ'U`1+_84-TFNU"J7ZJ+4U;)BR0M;)
+MN]M`^;RLXVS8,G5<WT7/#=;<63W1JZPPV28Z`-Y1@%'7R!9AT+^U]+0A(\2S
+M5IF5NL\/I;VXGK@"*`B(!5^RV0S&).D+L8=\;R\13&A8JQUAP3TM9K:00=QV
+M!G';`;P@TI@J$-7OB86Q<1^UM@:EY+^?,]2XZ*+)!W@T^0`/CJ@)EAB8#N&[
+M#6I_+3UM")=L9)$!7&/F]%%K:V)A;!S8,&6%3@!B\NV5!FQ[I0$;P?0(@E?$
+M#_7&V;!E4.FW$NJXOHM\B+G\WQW=8DDMVA7S?-.,94S4^UAALDW.4;4Z=`"\
+MH^(PN]1!I=]*UY78/6W$T:3[]-;3:NEI0_S9;C1&B&>MT+A@VG,M!$3E'0,S
+M7TP*JLE\#=T\<050JD$")Q`0"[Z&(`S));5H5[.%;R`)U&:YG^1AS@[YWEZ8
+MR=DI(IC0L+2HU\<7/;-9@0VT+CM<O;>M;+K`((.X[;:SOYH,XK8#FM*Q=#E'
+MU>JO=]*=%2;;!(,6W',2"V/CA#MDE#YJ;0VH6FIZ"\\.Y)W_"9,GK@`*L9X'
+M?423#_#2HPB':/(!'O["!FE=5V+WRV=E@'$V;!GG!FMN=AO4_N`KTXE:>MH0
+MS$K=9V_?N?GY[[Z.0[ZW%]6.L&#HH];6?I/1H<3"V#A2\M]/\6>[T6=7O*;=
+M!K4_2S:R2-HK#=A,&PJO]DH#-F!Z!$'#[V#?5=]GJ.^.;C%YOFE&C+-ARQJ#
+M9KR@TF\E-N)H4I5W#,P#1PN[N18"(B\F!56^.[K%*`N]LI):M"L$:K-<I__7
+MPC'/T+6+GMDL':[>6[#"9)LF\F/LG*-J=0J3;0*I!@F</S8.ZX5G!W(35P`%
+M@DJ_E11ZN.*N*[%[.!NV#)N.TI(-OM7EM^_<?"'?VPO4TM.&0N+4\?BSW6AN
+M@]H?S1:^@5LFN?;A=[!O=T>W&.9:"(AP:@__RCL&9EP+`1'_GF6/::YB^-/_
+M:V%%SVP6>.(*H.[2#==4@P1.PK,#.6$F9Z?W%F#034=I2=MW;CY*:M&NW%K6
+MV68+WT#P.]@W4ZZ\J<6>N]Y_S[)'Z?^U,!SRO;V*PKK*,).S4Z:CM"0%-M"Z
+MDP;7S2E7WE2_9]DC+GIFL[A*8<0"&VA=E"MO*C>^"[2AC@S#&]\%6HWO`BT`
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -7526,31 +6146,6 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M`````````````````````````````````````````````````%)O8VME="`W
-M-3`@4T%402!#;VYT<F]L;&5R```!`````````)8P!W<L80[NNE$)F1G$;0>/
-M]&IP-:5CZ:.59)XRB-L.I+C<>1[IU>"(V=*7*TRV";U\L7X'+;CGD1V_D&00
-MMQWR(+!J2'&Y\]Y!OH1]U-H:Z^3=;5&UU/3'A=.#5IAL$\"H:V1Z^6+][,EE
-MBD]<`139;`9C8ST/^O4-"(W((&X[7A!I3.1!8-5R<6>BT>0#/$?4!$O]A0W2
-M:[4*I?JHM35LF+)"ULF[VT#YO*SC;-@R=5S?1<\-UMQ9/=&KK##9)CH`WE&`
-M4=?(%F'0O[7TM"$CQ+-6F96ZSP^EO;B>N`(H"(@%7[+9#,8DZ0NQAWQO+Q%,
-M:%BK'6'!/2UFMI!!W'8&<=L!O"#2F"H0U>^)A;%Q'[6V!J7DOY\SU+CHHLD'
-M>#3Y``^.J`F6&)@.X;L-:G\M/6T(EVQDD0%<8^;T46MK8F%L'-@P985.`&+R
-M[94&;'NE`1O!]`B"5\0/]<;9L&50Z;<2ZKB^BWR(N?S?'=UB22W:%?-\TXQE
-M3-3[6&&R3<Y1M3IT`+RCXC"[U$&EWTK7E=@];<31I/OTUM-JZ6E#_-EN-$:(
-M9ZW0N&#:<RT$1.4=`S-?3`JJR7P-W3QQ!5"J00(G$!`+OH8@#,DEM6A7LX5O
-M(`G49KF?Y&'.#OG>7IC)V2DBF-"PM*C7QQ<]LUF!#;0N.UR]MZULNL`@@[CM
-MMK._F@SBM@.:TK%T.4?5ZJ]WTIT5)ML$@Q;<<Q(+8^.$.V24/FIM#:A::GH+
-MSP[DG?\)DR>N``JQG@=]1),/\-*C"(=H\@$>_L(&:5U78O?+9V6`<39L&><&
-M:VYV&]3^X"O3B5IZVA#,2MUG;]^Y^?GOOHY#OK<7U8ZP8.BCUM9^D]&AQ,+8
-M.%+RWT_Q9[O19U>\IMT&M3]+-K)(VBL-V$P;"J_V2@,V8'H$0</O8-]5WV>H
-M[XYN,7F^:4:,LV'+&H-FO*#2;R4VXFA2E7<,S`-'"[NY%@(B+R8%5;X[NL4H
-M"[VRDEJT*P1JLURG_]?",<_0M8N>V2P=KMY;L,)DFR;R8^R<HVIU"I-M`JD&
-M"9P_-@[KA6<'<A-7``6"2K^5%'JXXJXKL7LX&[8,FX[2D@V^U>6W[]Q\(=_;
-M"]32TX9"XM3Q^+/=:&Z#VA_-%KZ!6R:Y]N%WL&]W1[<8YEH(B'!J#__*.P9F
-M7`L!$?^>98]IKF+XT_]K847/;!9XX@J@[M(-UU2#!$["LP,Y829GI_<68-!-
-M1VE)VW=N/DIJT:[<6M;99@O?0/`[V#=3KKRIQ9Z[WG_/LD?I_[4P'/*]O8K"
-MNLHPD[-3IJ.T)`4VT+J3!M?-*5?>5+]GV2,N>F:SN$IAQ`(;:%V4*V\J-[X+
-MM*&.#,,;WP5:C>\"+0``````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -7560,6 +6155,10 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````"````1$````
+M(`$`!$0```(!```".@```@$!``(Z```$`0``"P````0!`0`+````"`$```9:
+M`0`(`0$`!EH!`!`!```#%`$`$`$!``,4`0`@`0``!B@``"`!`0`&*```0`$`
+M``,1``!``0$`!R<``(`!```+1P,`@`$!``M'`P``````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -7590,9 +6189,6 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````(```!$0````@`0`$1````@$```(Z```"`0$``CH```0!```+````
-M!`$!``L````(`0``!EH!``@!`0`&6@$`$`$```,4`0`0`0$``Q0!`"`!```&
-M*```(`$!``8H``!``0```Q$``$`!`0`')P``@`$```M'`P"``0$`"T<#````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -7606,6 +6202,8 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M`$1A=&%#96YT97(@-S(X,"!3051!($-O;G1R;VQL97(``0`````````;````
+M`0``````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -7617,5706 +6215,4770 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````1&%T84-E;G1E<B`W,C@P(%-!5$$@0V]N=')O;&QE
-M<@`!`````````!L````!````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M`````````````````````````````$U67U)E<75E<W0@)7`Z($-D8ELE,G@L
+M``````````!;("`@("`@("!=($-D8B!;)3)X+"4R>"PE,G@L)3)X+"`E,G@L
M)3)X+"4R>"PE,G@L("4R>"PE,G@L)3)X+"4R>"P@)3)X+"4R>"PE,G@L)3)X
-M+"`E,G@L)3)X+"4R>"PE,GA=+@!;)3`R>#HE,#)X("4P,F1=(&1I<VL@<F5M
-M;W9E9"X``$5R<F]R(&EN(&ES<W5I;F<@8V]M;6%N9"P@97)R(&EN9F\@,'@E
-M;&Q8`````````%1A<VL@9FEL92!E<G)O<BP@4W1A='5S4F5G/3!X)7@L($5R
-M<E)E9STP>"5X+"!,0D%;,"TS73TP>"5X+$Q"05LT+3==/3!X)7@N````````
-M4F5C96EV960@3E5,(%)E<2!S;&]T3F\H)7@O)7@I($5.5%)9("@E,#AX*2P@
-M97)R;W(@,'@E;&Q8`````````&`M($9)4RA3;&]T.B4P,G@I.B`E,#AX("4P
-M.'@@)3`X>"`E,#AX``!#340@2&5A9&5R.B`E,#AX("4P.'@@)3`X>"`E,#AX
-M("X@)3`X>"`E,#AX("4P.'@@)3`X>"`N("4P.'@@)3`X>"`E,#AX("4P.'@@
-M+B`E,#AX("4P.'@`6R4P,G@Z)3`R>"`E,#)D("4P,F1=(%!-(')E<75E<W0H
-M)7@I('1I;65O=70N````5&EM96]U="!(,D0@1DE3*%-L;W0Z)3`R>"DZ("4P
-M.'@@)3`X>"`E,#AX("4P.'@`6R4P,G@Z)3`R>"`E,#)D72!89F5R("5X($5R
-M<F]R(&EN9F]R;6%T:6]N(#!X)6QL6`````````!;)3`R>#HE,#)X("4P,F0@
-M)3`R9"`E,#)D72!89F5R("5X($5R<F]R(&EN9F]R;6%T:6]N(#!X)6QL6```
-M````6R4P,G@Z)3`R>"`E,#)X("4P,GA=(%!-(%AF97(@)7@@17)R;W(@:6YF
-M;W)M871I;VX@,'@E;&Q8`````````%)U;FYI;F<@2#)$($9)4RA3;&]T.B4P
-M,G@I.B`E,#AX("4P.'@@)3`X>"`E,#AX`"!31R!I=&5M("4P,G@Z(&%D9'(@
-M)6QL>"!S:7IE("5X(%-'2"!A9&1R("5L;'@@<VEZ92`E>```1F%I;&5D('1O
-M(&5N86)L92]D:7-A8FQE('-P:6X@=7`N`````````%LE,#)X.B4P,G@@)3`R
-M9%T@1&5V:6-E(')E<75E<W0H)7@I('1I;65O=70N`````%LE,#)X.B4P,G@@
-M)3`R9"`E,#)D("4P,F1=($1E=FEC92!R97%U97-T*"5X*2!T:6UE;W5T+@``
-M6R4P,G@Z)3`R>"`E,#)D72!D:7-K(')E;6]V960@*"5X*2X``````$%T=$1E
-M=E-!4T%D9');)7A=("!;56YI=$ED("5X72!S87,@861D<B`E,#)X+24P,G@M
-M)3`R>"TE,#)X+24P,G@M)3`R>"TE,#)X+24P,G@`<V%M92!S87,@861D<B`E
-M,#)X+24P,G@M)3`R>"TE,#)X+24P,G@M)3`R>"TE,#)X+24P,G@```!$979I
-M8V4@)7@@:6X@<W1A;F1B>2!M;V1E+"!S=&%R="!T;R!P;W=E<B!I="!U<"X`
-M`````````%-T87)T('1O('!O=V5R('5P(&1E=FEC92`E>"XN+@``4&]R="!R
-M97-E="AP:&%S92`E>"!P;7`@)7@I(&YO="!C;VUP;&5T92!S=6-C97-S+"!I
-M9VYO<F4@=&AE('!O<G0@*"5X(&1E=FEC92`E>"D``````````%LE,#)X.B4P
-M,G@@)3`R9%T@9&ES:R!R96UO=F5D("@E>"DN``````!$979I8V4@*%!A=&@@
-M)3`R>"!\(%1A<F=E="`E,#)X('P@125X+U,E,#)X*2!S<&EN('5P(&UO9&4@
-M;F]T('-U<'!O<G0```!;)3`R>#HE,#)X("4P,F1=('-E="!D:7-K('-P:6X@
-M=7`@;6]D92`E>"X```````!;)3`R>#HE,#)X("4P,F1=(&1I<VL@<')O8F5D
-M("AS<&EN=7`@;6]D93H@)60I+@!-5E]297%U97-T("5P.B!#9&);)3)X+"4R
-M>"PE,G@L)3)X+"`E,G@L)3)X+"4R>"PE,G@L("4R>"PE,G@L)3)X+"4R>"P@
-M)3)X+"4R>"PE,G@L)3)X72X`17)R;W(@:6X@:7-S=6EN9R!C;VUM86YD+"!E
-M<G(@:6YF;R`P>"5L;%@`````````5&%S:R!F:6QE(&5R<F]R+"!3=&%T=7-2
-M96<],'@E>"P@17)R4F5G/3!X)7@L($Q"05LP+3-=/3!X)7@L3$)!6S0M-UT]
-M,'@E>"X```````!296-E:79E9"!.54P@4F5Q('-L;W1.;R@E>"\E>"D@14Y4
-M4ED@*"4P.'@I+"!E<G)O<B`P>"5L;%@`````````8"T@1DE3*%-L;W0Z)3`R
-M>"DZ("4P.'@@)3`X>"`E,#AX("4P.'@``$--1"!(96%D97(Z("4P.'@@)3`X
-M>"`E,#AX("4P.'@@+B`E,#AX("4P.'@@)3`X>"`E,#AX("X@)3`X>"`E,#AX
-M("4P.'@@)3`X>"`N("4P.'@@)3`X>`!;)3`R>#HE,#)X("4P,F0@)3`R9%T@
-M4$T@<F5Q=65S="@E>"D@=&EM96]U="X```!4:6UE;W5T($@R1"!&25,H4VQO
-M=#HE,#)X*3H@)3`X>"`E,#AX("4P.'@@)3`X>`!;)3`R>#HE,#)X("4P,F0@
-M)3`R9"`E,#)D72!89F5R("5X($5R<F]R(&EN9F]R;6%T:6]N(#!X)6QL6```
-M````6R4P,G@Z)3`R>"`E,#)X("4P,GA=(%!-(%AF97(@)7@@17)R;W(@:6YF
-M;W)M871I;VX@,'@E;&Q8`````````%)U;FYI;F<@2#)$($9)4RA3;&]T.B4P
-M,G@I.B`E,#AX("4P.'@@)3`X>"`E,#AX`"!31R!I=&5M("4P,G@Z(&%D9'(@
-M)6QL>"!S:7IE("5X(%-'2"!A9&1R("5L;'@@<VEZ92`E>```1F%I;&5D('1O
-M(&5N86)L92]D:7-A8FQE('-P:6X@=7`N`````````%LE,#)X.B4P,G@@)3`R
-M9"`E,#)D("4P,F1=($1E=FEC92!R97%U97-T*"5X*2!T:6UE;W5T+@``071T
-M1&5V4T%3061D<ELE>%T@(%M5;FET260@)7A=('-A<R!A9&1R("4P,G@M)3`R
-M>"TE,#)X+24P,G@M)3`R>"TE,#)X+24P,G@M)3`R>`!S86UE('-A<R!A9&1R
-M("4P,G@M)3`R>"TE,#)X+24P,G@M)3`R>"TE,#)X+24P,G@M)3`R>````$1E
-M=FEC92`E>"!I;B!S=&%N9&)Y(&UO9&4L('-T87)T('1O('!O=V5R(&ET('5P
-M+@``````````4W1A<G0@=&\@<&]W97(@=7`@9&5V:6-E("5X+BXN``!0;W)T
-M(')E<V5T*'!H87-E("5X('!M<"`E>"D@;F]T(&-O;7!L971E('-U8V-E<W,L
-M(&EG;F]R92!T:&4@<&]R="`H)7@@9&5V:6-E("5X*0``````````1&5V:6-E
-M("A0871H("4P,G@@?"!487)G970@)3`R>"!\($4E>"]3)3`R>"D@<W!I;B!U
-M<"!M;V1E(&YO="!S=7!P;W)T````4V5T(&1E=FEC92`H4&%T:"`E,#)X('P@
-M5&%R9V5T("4P,G@@?"!%)7@O4R4P,G@I('-P:6X@=7`@;6]D92`E>```````
-M````071T86-H960@9&5V:6-E(&EN9&5X("4P,G@@*%!A=&@@)3`R>"!\(%1A
-M<F=E="`E,#)X('P@125X+U,E,#)X*2`@)7@E>"5X)7@E>"5X)7@E>```````
-M`$)A8VMU<"!S=&%M<"`E>"!S=6T@)7@@8F%C:V5D("5D``````````!-87-T
-M97(@<W1A;7`@)7@@<W5M("5X(&)A8VME9"`E9```````````5W)I=&4@87)R
-M87D@;65T82!D871A('1O(&UA<W1E<B`P>"5L;%@M/C!X)6QL6```5W)I=&4@
-M87)R87D@;65T82!D871A('1O(&)A8VMU<"`P>"5L;%@M/C!X)6QL6```6R5D
-M("5D72!D979I8V4@97)A<V4@=6YI="!S=6-C97-S9G5L;'DN`%LE9"`E9%T@
-M9&5V:6-E(&5R87-E('5N:70@9F%I;&5D(&]R(&%B;W)T960N`````'-E="!!
-M1$E&7U-%5%]"040@8F%D7W-E8W1O<B`E9```9&]?9&ES:U]C=&Q?8VUD.B!C
-M=&P@8V]D92`E>"!V9#TE<"P@3$)!(#!X)6QL6"!N4V5C=&]R(#!X)7@`4F5T
-M<GEI;F<@9F%I;&5D+"!D:7-K(&1O=VX_/S\`=V]R:W)O=6YD(&ER<5-T871U
-M<R`](#!X)7@`4F5Q("5P("5X("5X`$1E=FEC92`E>"\E>"!R96UO=F5D+@!/
+M72X`````4&AY("5X('-I9VYA='5R92!F<F]M(%-)1TY!5%5212!&25,@8G5S
+M>0``````````4&AY("5D('-I9VYA='5R92!F<F]M('5N87-S;V-I871E9"!&
+M25,@8G5S>0``````6R4P,G@Z)3`R>"`E,#)D72!D:7-K(')E;6]V960N``!;
+M)3`R9#HE,#)D(%`E9%T@07-Y;B!.;W1I9FEC871I;VX@4F5C96EV960`````
+M``!%<G)O<B!I;B!I<W-U:6YG(&-O;6UA;F0L(&5R<B!I;F9O(#!X)6QL6```
+M``````!;)3`R>#HE,#)X("4P,F1=(%)E<75E<W0@9F%I;&5D+B!%<G)O<B!I
+M;F9O<FUA=&EO;B`P>"5L;%@`````````6R4P,G@Z)3`R>"!-)61=(%!-(%)E
+M<75E<W0@9F%I;&5D+B!%<G)O<B!I;F9O<FUA=&EO;B`P>"5L;%@``````%L@
+M("`@("`@(%T@2#)$($9)4SH@)3`X>"`E,#AX("4P.'@@)3`X>`!;("`@("`@
+M("!=($0R2"!&25,Z("4P.'@@)3`X>"`E,#AX("4P.'@@*%-T871U<R`E>"!%
+M<G)O<B`E>"D`````4F5C96EV960@3E5,(%)E<2!S;&]T3F\H)7@O)7@I($5.
+M5%)9("@E,#AX*2P@97)R;W(@,'@E;&Q8`````````&`M($9)4RA3;&]T.B4P
+M,G@I.B`E,#AX("4P.'@@)3`X>"`E,#AX``!;)3`R>#HE,#)X("4P,F1=($1E
+M=FEC92!R97%U97-T*"5X*2!T:6UE;W5T+@````!;("`@("`@("!=($@R1"!&
+M25,H4VQO=#HE,#)X*3H@)3`X>"`E,#AX("4P.'@@)3`X>````````%)E<2`H
+M)7@I('=A:70@9F]R(&-O;7!L971E9"!D;VYE+@````````!;)3`R>#HE,#)X
+M($TE9%T@4$T@<F5Q=65S="@E>"D@=&EM96]U="X`4F5G:7-T97(@4V5T("4P
+M.'@@)3`X>"!)4E$@4U1!5"`E>````````%LE,#)X.B4P,G@@)3`R9%T@9&ES
+M:R!R96UO=F5D("@E>"DN``````!);G9A;&ED('-I9VYA='5R92`P>"5X+"!T
+M<F5A="!A<R!!5$$@<W1A='5S("5X``!;)3`R>#HE,#)X("4P,F1=($1I<VL@
+M:6X@<W1A;F1B>2!M;V1E+"!S=&%R="!T;R!P;W=E<B!I="!U<"X`````6R4P
+M,G@Z)3`R>"`E,#)D72!$:7-K('!O=V5R960@=7`N`````````%LE,#)X.B4P
+M,G@@)3`R9%T@1&5V:6-E('-T871E("5X(&9A:6QE9"`H)7@I(')E=')I960@
+M)7@`6R4P,G@Z)3`R>"`E,#)D72!);G9A;&ED(&ED96YT:69Y(&1A=&$L(')E
+M=')I97,H)60I+@````!;)3`R>#HE,#)X("4P,F1=(%-T87)T(%-O9G0@4F5S
+M970@9F]R("5X+R5X``````!;)3`R>#HE,#)X(%`E9%T@4VEG;F%T=7)E('1I
+M;65O=70@9F]R("5X+R5X``````!;)3`R9#HE,#)D($TE9%T@4$T@4F5Q=65S
+M="!O9B!S=&%T92`E>"!F;W(@)7@O)7@@9F%I;&5D`%!O<G0@<F5S970@*'!H
+M87-E("5X('!M<"`E>"D@;F]T(&-O;7!L971E('-U8V-E<W,L(&EG;F]R92!T
+M:&4@<&]R="`H)7@@9&5V:6-E("5X*0````````!;)3`R>#HE,#)X("4P,F1=
+M(%)E<V5T(%!H87-E("5X(&9A:6QE9"!F;W(@)7@O)7@``````````')E860@
+M97)R;W(@8F5F;W(@=W)I=&4@9&%T82!B86-K``````````!;)3`R>#HE,#)X
+M("4P,F1=('-P:6X@=7`@;6]D92!N;W0@<W5P<&]R="X```````!;)3`R>#HE
+M,#)X("4P,F1=('-E="!D:7-K('-P:6X@=7`@;6]D92`E>"X```````!;)3`R
+M>#HE,#)X("4P,F1=(&1I<VL@<')O8F5D("AS<&EN=7`@;6]D93H@)60I+@!-
+M5E]297%U97-T("5P.B!#9&);)3)X+"4R>"PE,G@L)3)X+"`E,G@L)3)X+"4R
+M>"PE,G@L("4R>"PE,G@L)3)X+"4R>"P@)3)X+"4R>"PE,G@L)3)X72X`17)R
+M;W(@:6X@:7-S=6EN9R!C;VUM86YD+"!E<G(@:6YF;R`P>"5L;%@`````````
+M5&%S:R!F:6QE(&5R<F]R+"!3=&%T=7-296<],'@E>"P@17)R4F5G/3!X)7@L
+M($Q"05LP+3-=/3!X)7@L3$)!6S0M-UT],'@E>"X```````!296-E:79E9"!.
+M54P@4F5Q('-L;W1.;R@E>"\E>"D@14Y44ED@*"4P.'@I+"!E<G)O<B`P>"5L
+M;%@`````````8"T@1DE3*%-L;W0Z)3`R>"DZ("4P.'@@)3`X>"`E,#AX("4P
+M.'@``$--1"!(96%D97(Z("4P.'@@)3`X>"`E,#AX("4P.'@@+B`E,#AX("4P
+M.'@@)3`X>"`E,#AX("X@)3`X>"`E,#AX("4P.'@@)3`X>"`N("4P.'@@)3`X
+M>`!;)3`R>#HE,#)X("4P,F0@)3`R9%T@4$T@<F5Q=65S="@E>"D@=&EM96]U
+M="X```!4:6UE;W5T($@R1"!&25,H4VQO=#HE,#)X*3H@)3`X>"`E,#AX("4P
+M.'@@)3`X>`!;)3`R>#HE,#)X("4P,F0@)3`R9"`E,#)D72!89F5R("5X($5R
+M<F]R(&EN9F]R;6%T:6]N(#!X)6QL6```````6R4P,G@Z)3`R>"`E,#)X("4P
+M,GA=(%!-(%AF97(@)7@@17)R;W(@:6YF;W)M871I;VX@,'@E;&Q8````````
+M`%)U;FYI;F<@2#)$($9)4RA3;&]T.B4P,G@I.B`E,#AX("4P.'@@)3`X>"`E
+M,#AX`"!31R!I=&5M("4P,G@Z(&%D9'(@)6QL>"!S:7IE("5X(%-'2"!A9&1R
+M("5L;'@@<VEZ92`E>```1F%I;&5D('1O(&5N86)L92]D:7-A8FQE('-P:6X@
+M=7`N`````````%LE,#)X.B4P,G@@)3`R9"`E,#)D("4P,F1=($1E=FEC92!R
+M97%U97-T*"5X*2!T:6UE;W5T+@``4F5Q("@E>"D@=V%I="!F;W(@8V]M<&QE
+M=&5D(&1O;F4N`````````$%T=$1E=E-!4T%D9');)7A=("!;56YI=$ED("5X
+M72!S87,@861D<B`E,#)X+24P,G@M)3`R>"TE,#)X+24P,G@M)3`R>"TE,#)X
+M+24P,G@`<V%M92!S87,@861D<B`E,#)X+24P,G@M)3`R>"TE,#)X+24P,G@M
+M)3`R>"TE,#)X+24P,G@```!$979I8V4@)7@@:6X@<W1A;F1B>2!M;V1E+"!S
+M=&%R="!T;R!P;W=E<B!I="!U<"X``````````%-T87)T('1O('!O=V5R('5P
+M(&1E=FEC92`E>"XN+@``4&]R="!R97-E="AP:&%S92`E>"!P;7`@)7@I(&YO
+M="!C;VUP;&5T92!S=6-C97-S+"!I9VYO<F4@=&AE('!O<G0@*"5X(&1E=FEC
+M92`E>"D``````````$1E=FEC92`H4&%T:"`E,#)X('P@5&%R9V5T("4P,G@@
+M?"!%)7@O4R4P,G@I('-P:6X@=7`@;6]D92!N;W0@<W5P<&]R=````%-E="!D
+M979I8V4@*%!A=&@@)3`R>"!\(%1A<F=E="`E,#)X('P@125X+U,E,#)X*2!S
+M<&EN('5P(&UO9&4@)7@``````````$%T=&%C:&5D(&1E=FEC92!I;F1E>"`E
+M,#)X("A0871H("4P,G@@?"!487)G970@)3`R>"!\($4E>"]3)3`R>"D@("5X
+M)7@E>"5X)7@E>"5X)7@```````!"86-K=7`@<W1A;7`@)7@@<W5M("5X(&)A
+M8VME9"`E9```````````36%S=&5R('-T86UP("5X('-U;2`E>"!B86-K960@
+M)60``````````%=R:71E(&%R<F%Y(&UE=&$@9&%T82!T;R!M87-T97(@,'@E
+M;&Q8+3XP>"5L;%@``%=R:71E(&%R<F%Y(&UE=&$@9&%T82!T;R!B86-K=7`@
+M,'@E;&Q8+3XP>"5L;%@``%LE9"`E9%T@9&5V:6-E(&5R87-E('5N:70@<W5C
+M8V5S<V9U;&QY+@!;)60@)61=(&1E=FEC92!E<F%S92!U;FET(&9A:6QE9"!O
+M<B!A8F]R=&5D+@````!D;U]D:7-K7V-T;%]C;60Z(&-T;"!C;V1E("5X('9D
+M/25P+"!,0D$@,'@E;&Q8(&Y396-T;W(@,'@E>`!;)3`R9#HE,#)D(%`E9%T@
+M1U-#4B!C:&%N9V5D`%%U975E(&9U;&P@)7@@)7@`4F5Q("5P("5X("5X`"5S
+M(')E<2`E<"!S;&]T:60@,'@E>`!;)3`R>#HE,#)X("4P,F1=(&1I<VL@9F%I
+M;&5D+@!$979I8V4@)7@O)7@@<F5M;W9E9"X`1F%I;&5D('1O('9E<FEF>2!C
+M;VYT<F]L;&5R`&]D:6X@<F5A9"!W<FET92!E>&-E961S("5X`&]D:6X`1&5V
+M:6-E("5X+R5X(')E;6]V960N`%)E=')Y:6YG(&9A:6QE9"P@9&ES:R!D;W=N
+M/S\_`'=O<FMR;W5N9"!I<G%3=&%T=7,@/2`P>"5X`%)E<2`E<"`E>"`E>`!/
M=F5R<F%L;"!31R!I=&5M("5X('-I>F4@)7@`4VQO="!B=7-Y+"!S;&]T("5X
M*"5X*0!$=6UP('-L;W0@:6YF;SH@)7@@)7@@)7@@)7@`0VQE86X@=7`@<VQO
M="`E>`!$,D@@1DE3.B`E,#AX("4P.'@@)3`X>"`E,#AX`"4P,G@@)3`T>#HE
-M,#1X.B4P-'@`4F5Q("@E>"D@=V%I="!F;W(@8V]M<&QE=&5D+@!$979I8V4@
-M)7@O)7@@<F5M;W9E9"X`1&5V:6-E("5X+R5X(')E;6]V960N`$1E=FEC92`E
-M>"!P;W=E<F5D('5P+@!S=&%R="!315,@9&5V:6-E("5P`$9O=6YD(%-%4R!$
-M979I8V4@)7@`1F%I;&5D('1O('9E<FEF>2!C;VYT<F]L;&5R`&]D:6X@<F5A
-M9"!W<FET92!E>&-E961S("5X`&]D:6X`1&5V:6-E("5X+R5X(')E;6]V960N
-M`%)E=')Y:6YG(&9A:6QE9"P@9&ES:R!D;W=N/S\_`'=O<FMR;W5N9"!I<G%3
-M=&%T=7,@/2`P>"5X`%)E<2`E<"`E>"`E>`!/=F5R<F%L;"!31R!I=&5M("5X
-M('-I>F4@)7@`4VQO="!B=7-Y+"!S;&]T("5X*"5X*0!$=6UP('-L;W0@:6YF
-M;SH@)7@@)7@@)7@@)7@`0VQE86X@=7`@<VQO="`E>`!$,D@@1DE3.B`E,#AX
-M("4P.'@@)3`X>"`E,#AX`"4P,G@@)3`T>#HE,#1X.B4P-'@`4F5Q("@E>"D@
-M=V%I="!F;W(@8V]M<&QE=&5D+@!$979I8V4@)7@O)7@@<F5M;W9E9"X`1&5V
-M:6-E("5X+R5X(')E;6]V960N`$1E=FEC92`E>"!P;W=E<F5D('5P+@!S=&%R
-M="!315,@9&5V:6-E("5P`$9O=6YD(%-%4R!$979I8V4@)7@`1F%I;&5D('1O
-M('9E<FEF>2!C;VYT<F]L;&5R`&]D:6X@<F5A9"!W<FET92!E>&-E961S("5X
-M`&]D:6X`<F%W("5P(&)A9%]S96-T;W(@)7@`5W)I=&4@8F%C:W5P960@;65T
-M82!D871A`$9A:6QE9"!T;R!S<&EN9&]W;B!D979I8V5S`$9A:6QE9"!T;R!F
-M;'5S:"!T87)G971S`$%U=&\@4F5B=6EL9`!296)U:6QD(%!R:6]R:71Y`$-O
-M;G1I;G5E(%)E8G5I;&1I;F<@;VX@17)R;W(`4W!I;F1O=VX@261L92!$:7-K
-M("AM:6YU=&5S*0!3=&%G9V5R960@<W!I;G5P```````````````&!`4!`P)2
-M8A4`````````!@0%`0,"V&"?-CD\``````8$!0$#`B!@D%!2```````&!`4!
-M`P+88)````````````$"`Q`$!08'$0@)"@L2#`T.#Q,4%187)!@9&ALE'!T>
-M'R8@(2(C)P``````````````````````````````````````````````````
-M```A````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M`````````````````````````````````````````````````Q%0!P``````
-M`@`````````````!```````````````&!`4!`P)28A4`````````!@0%`0,"
-MV&"?-CD\``````8$!0$#`B!@D%!2```````&!`4!`P+88)``````````````
-M`````````````````"$`````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M```#$8!R```````"``````````````$```````````````$!_P(`````````
-M```````````````````````````````````````!`````````"``````````
-M4````"@`````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````_P``````````````````````````````````````
-M``$``````````?\````````````````````````````````````````!````
-M``````+_`````````````````````````````````````````0`````````#
-M_P````````````````````````````````````````$`````````-?\`````
-M```````````````````````````````````!``````````3_````````````
-M`````````````````````````````0`````````%_P``````````````````
-M``````````````````````$`````````!O\`````````````````````````
-M``````````````````````````?_````````````````````````````````
-M```````````````````*_P``````````````````````````````````````
-M``$`````````"_\`````````````````````````````````````````````
-M``````S_```````````````````````````````````````````````````-
-M_P``````````````````````````````````````````````````#O\`````
-M``````````````````````````````````````````````__````````````
-M```````````````````````````````````````0_P``````````````````
-M````````````````````````````````$?\`````````````````````````
-M`````````````````````````!+_````````````````````````````````
-M```````````````````3_P``````````````````````````````````````
-M``$`````````-/\````````````````````````````````````````!````
-M`````!C_``````````````````````````````````````````````````!"
-M_P``````````````````````````````````````````````````&?\`````
-M`````````````````````````````````````````````!K_````````````
-M```````````````````````````````````````=_P``````````````````
-M````````````````````````````````'O\`````````````````````````
-M```````````````!`````````!__````````````````````````````````
-M```````````````````@_P``````````````````````````````````````
-M````````````(?\````````````````````````````````````````!````
-M`````"+_```````````````````````````````````````````````````C
-M_P``````````````````````````````````````````````````)/\`````
-M`````````````````````````````````````````````"7_````````````
-M```````````````````````````````````````I_P``````````````````
-M````````````````````````````````*O\`````````````````````````
-M`````````````````````````"O_````````````````````````````````
-M```````````````````L_P``````````````````````````````````````
-M``$`````````+?\`````````````````````````````````````````````
-M`````"[_`````````````````````````````````````````0`````````O
-M_P````````````````````````````````````````$`````````2?\`````
-M```````````````````````````````````!`````````#?_````````````
-M`````````````````````````````0`````````X_P``````````````````
-M````````````````````````````````.?\`````````````````````````
-M`````````````````````````#K_````````````````````````````````
-M`````````0`````````[_P``````````````````````````````````````
-M``$`````````//\````````````````````````````````````````!````
-M`````#W_`````````````````````````````````````````0`````````^
-M_P````````````````````````````````````````$`````````0_\`````
-M```````````````````````````````````!`````````$3_````````````
-M`````````````````````````````0````````!&_P``````````````````
-M``````````````````````$`````````1_\`````````````````````````
-M```````````````!`````````#+_````````````````````````````````
-M`````````0`````````S_P``````````````````````````````````````
-M````````````9/\````````````````````````````````````````!````
-M`````##_`````````````````````````````````````````0````````!F
-M_P````````````````````````````````````````$`````````9_\`````
-M```````````````````````````````````!`````````$7_````````````
-M``````````````````````````````````````!(_P``````````````````
-M````````````````````````````````_____P``````````````````````
-M`````````````````````````!0``````````0`!>!`,!PB0`0```````!0`
-M```<```````````````L`````````!0````T```````````````"````````
-M`#P```!,``````````````!N`@```````$(.$$(.&$(.($(.*$$.,$$..$0.
-M4(,'A@:,!8T$C@./`@`````````4``````````$``7@0#`<(D`$````````4
-M````'```````````````-@`````````4````-```````````````-@``````
-M```4````3```````````````1@`````````4````9```````````````1@``
-M```````4````?```````````````#``````````4``````````$``7@0#`<(
-MD`$````````4````'```````````````(@`````````4````-```````````
-M````1P`````````4````3```````````````$``````````4````9```````
-M````````7``````````4````?```````````````#0`````````4````E```
-M````````````)P`````````4````K```````````````,``````````4````
-MQ```````````````,0`````````4````W```````````````,P`````````4
-M````]```````````````W`$````````4````#`$`````````````/@``````
-M```<````)`$`````````````C@````````!$#G```````!P```!$`0``````
-M```````Y`````````$0.$```````%````&0!`````````````"@`````````
-M%````'P!`````````````"$`````````%````)0!`````````````"``````
-M````%``````````!``%X$`P'")`!````````%````!P``````````````&,`
+M,#1X.B4P-'@`1&5V:6-E("5X+R5X(')E;6]V960N`$1E=FEC92`E>"\E>"!R
+M96UO=F5D+@!$979I8V4@)7@@<&]W97)E9"!U<"X`<W1A<G0@4T53(&1E=FEC
+M92`E<`!&;W5N9"!315,@1&5V:6-E("5X`$9A:6QE9"!T;R!V97)I9GD@8V]N
+M=')O;&QE<@!O9&EN(')E860@=W)I=&4@97AC965D<R`E>`!O9&EN`&-A;&P@
+M;&1M7V]N7W1I;65R(&%F=&5R(#%M<P!R87<@)7`@8F%D7W-E8W1O<B`E>`!7
+M<FET92!B86-K=7!E9"!M971A(&1A=&$`1F%I;&5D('1O('-P:6YD;W=N(&1E
+M=FEC97,`1F%I;&5D('1O(&9L=7-H('1A<F=E=',`075T;R!296)U:6QD`%)E
+M8G5I;&0@4')I;W)I='D`0V]N=&EN=64@4F5B=6EL9&EN9R!O;B!%<G)O<@!3
+M<&EN9&]W;B!)9&QE($1I<VL@*&UI;G5T97,I`%-T86=G97)E9"!S<&EN=7``
+M````````````````````````!@0%`0,"4F(5``````````8$!0$#`MA@GS8Y
+M/``````&!`4!`P(@8)!04@``````!@0%`0,"V&"0```````````!`@,0!`4&
+M!Q$("0H+$@P-#@\3%!46%R08&1H;)1P='A\F("$B(R<`````````````````
+M````````````````````````````````````(0``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````,14`<```````(``````````````0``````````
+M````!@0%`0,"4F(5``````````8$!0$#`MA@GS8Y/``````&!`4!`P(@8)!0
+M4@``````!@0%`0,"V&"0```````````````````````````````A````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````Q&`<@```````@``````````
+M```!```````````````!`?\"````````````````````````````````````
+M`````````````0`````````@`````````%`````H````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````/\`````
+M```````````````````````````````````!``````````'_````````````
+M`````````````````````````````0`````````"_P``````````````````
+M``````````````````````$``````````_\`````````````````````````
+M```````````````!`````````#7_````````````````````````````````
+M`````````0`````````$_P``````````````````````````````````````
+M``$`````````!?\````````````````````````````````````````!````
+M``````;_```````````````````````````````````````````````````'
+M_P``````````````````````````````````````````````````"O\`````
+M```````````````````````````````````!``````````O_````````````
+M```````````````````````````````````````,_P``````````````````
+M````````````````````````````````#?\`````````````````````````
+M``````````````````````````[_````````````````````````````````
+M```````````````````/_P``````````````````````````````````````
+M````````````$/\`````````````````````````````````````````````
+M`````!'_```````````````````````````````````````````````````2
+M_P``````````````````````````````````````````````````$_\`````
+M```````````````````````````````````!`````````#3_````````````
+M`````````````````````````````0`````````8_P``````````````````
+M````````````````````````````````0O\`````````````````````````
+M`````````````````````````!G_````````````````````````````````
+M```````````````````:_P``````````````````````````````````````
+M````````````'?\`````````````````````````````````````````````
+M`````![_`````````````````````````````````````````0`````````?
+M_P``````````````````````````````````````````````````(/\`````
+M`````````````````````````````````````````````"'_````````````
+M`````````````````````````````0`````````B_P``````````````````
+M````````````````````````````````(_\`````````````````````````
+M`````````````````````````"3_````````````````````````````````
+M```````````````````E_P``````````````````````````````````````
+M````````````*?\`````````````````````````````````````````````
+M`````"K_```````````````````````````````````````````````````K
+M_P``````````````````````````````````````````````````+/\`````
+M```````````````````````````````````!`````````"W_````````````
+M```````````````````````````````````````N_P``````````````````
+M``````````````````````$`````````+_\`````````````````````````
+M```````````````!`````````$G_````````````````````````````````
+M`````````0`````````W_P``````````````````````````````````````
+M``$`````````./\`````````````````````````````````````````````
+M`````#G_```````````````````````````````````````````````````Z
+M_P````````````````````````````````````````$`````````._\`````
+M```````````````````````````````````!`````````#S_````````````
+M`````````````````````````````0`````````]_P``````````````````
+M``````````````````````$`````````/O\`````````````````````````
+M```````````````!`````````$/_````````````````````````````````
+M`````````0````````!$_P``````````````````````````````````````
+M``$`````````1O\````````````````````````````````````````!````
+M`````$?_`````````````````````````````````````````0`````````R
+M_P````````````````````````````````````````$`````````,_\`````
+M`````````````````````````````````````````````&3_````````````
+M`````````````````````````````0`````````P_P``````````````````
+M``````````````````````$`````````9O\`````````````````````````
+M```````````````!`````````&?_````````````````````````````````
+M`````````0````````!%_P``````````````````````````````````````
+M````````````2/\`````````````````````````````````````````````
+M`````/____\````````````````````````````````````````````````4
+M``````````$``7@0#`<(D`$````````4````'```````````````-@``````
+M```4````-```````````````-@`````````4````3```````````````1@``
+M```````4````9```````````````1@`````````4````?```````````````
+M#``````````4``````````$``7@0#`<(D`$````````4````'```````````
+M````(@`````````4````-```````````````1P`````````4````3```````
+M````````$``````````4````9```````````````7``````````4````?```
+M````````````#0`````````4````E```````````````)P`````````4````
+MK```````````````,``````````4````Q```````````````,0`````````4
+M````W```````````````)P`````````4````]```````````````W`$`````
+M```<````#`$`````````````AP````````!$#F```````!P````L`0``````
+M```````Y`````````$0.$```````%````$P!`````````````"@`````````
+M%````&0!`````````````"$`````````%````'P!`````````````"``````
+M````%``````````!``%X$`P'")`!````````%````!P``````````````$<`
M````````%````#0``````````````%(`````````%````$P`````````````
M`%(`````````%````&0``````````````'D`````````)````'P`````````
M`````%`!````````1`XP5(T"C`.&!(,%`````!P```"D```````````````_
M`````````$0.($J,`H,#/````,0``````````````&T"````````0@X00@X8
M0@X@0@XH00XP00XX1`Z0`8,'A@:,!8T$C@./`@```````"0````$`0``````
M``````!*`0```````$$.$$$.&$0.((,#A@(````4``````````$``7@0#`<(
-MD`$````````4````'```````````````30`````````4````-```````````
-M````@@`````````4````3```````````````=0`````````4````9```````
-M````````<0`````````4````?```````````````&0`````````<````E```
-M````````````10````````!$#A```````!P```"T```````````````A````
-M`````$0.$```````'````-0``````````````%\`````````1`X0```````\
-M````]```````````````&`(```````!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#
-M!X8&C`6-!(X#CP(`````````'````#0!`````````````.T`````````1`X0
-M```````D````5`$`````````````$P$```````!$#C!4C0*,`X8$@P4`````
-M)````'P!`````````````!@!````````0@X000X800X@@P2&`XP"`"0```"D
-M`0`````````````#!@```````$0.0%Z/`HX#C02,!88&@P<<````S`$`````
-M````````$0````````!$#A```````#P```#L`0````````````!5"P``````
-M`$(.$$(.&$(.($(.*$$.,$$..$0.D`&#!X8&C`6-!(X#CP(````````L````
-M+`(`````````````$`(```````!"#A!"#AA!#B!!#BA$#C"#!88$C`.-`@`D
-M````7`(`````````````70,```````!$#E!>CP*.`XT$C`6&!H,'/````(0"
-M`````````````.\#````````0@X00@X80@X@0@XH00XP00XX1`Y@@P>&!HP%
-MC02.`X\"`````````"0```#$`@````````````##"0```````$0.8%Z/`HX#
-MC02,!88&@P<\````[`(`````````````BPD```````!"#A!"#AA"#B!"#BA!
-M#C!!#CA'#N`!@P>&!HP%C02.`X\"````````)````"P#`````````````.H`
-M````````1`XP5(T"C`.&!(,%`````#P```!4`P````````````#`"0``````
-M`$(.$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,!8T$C@./`@`````````\````
-ME`,`````````````T@D```````!"#A!"#AA"#B!"#BA!#C!!#CA$#J`!@P>&
-M!HP%C02.`X\"````````)````-0#`````````````+L`````````0@X000X8
-M00X@@P2&`XP"`#0```#\`P````````````"^`````````$(.$$(.&$(.($$.
-M*$$.,(,&A@6,!(T#C@(`````````-````#0$`````````````%\#````````
-M0@X00@X80@X@00XH00XP@P:&!8P$C0..`@`````````<````;`0`````````
-M````R`````````!$#A```````#P```",!`````````````"?`P```````$(.
-M$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````D````S`0`
-M````````````R0,```````!$#C!4C0*,`X8$@P4`````/````/0$````````
-M`````/@#````````0@X00@X80@X@0@XH00XP00XX1`Z@`8,'A@:,!8T$C@./
-M`@```````#P````T!0````````````!Q!@```````$(.$$(.&$(.($(.*$$.
-M,$$..$0.8(,'A@:,!8T$C@./`@`````````<````=`4`````````````@0``
-M``````!$#A```````!P```"4!0`````````````.`````````$0.$```````
-M'````+0%``````````````L$````````00X01`YP@P(D````U`4`````````
-M````!@$```````!$#D!>CP*.`XT$C`6&!H,'/````/P%`````````````$,!
+MD`$````````4````'```````````````\0`````````4````-```````````
+M````30`````````4````3```````````````@@`````````4````9```````
+M````````=0`````````4````?```````````````<0`````````4````E```
+M````````````2P`````````4````K````````````````@`````````D````
+MQ```````````````%0,```````!$#C!4C0*,`X8$@P4`````/````.P`````
+M`````````/$!````````0@X00@X80@X@0@XH00XP00XX1`Y`@P>&!HP%C02.
+M`X\"`````````#P````L`0````````````"!"````````$(.$$(.&$(.($(.
+M*$$.,$$..$0.8(,'A@:,!8T$C@./`@`````````D````;`$`````````````
+M;0````````!"#A!!#AA!#B"#!(8#C`(`/````)0!`````````````-0!````
+M````0@X00@X80@X@0@XH00XP00XX1`Y`@P>&!HP%C02.`X\"`````````"0`
+M``#4`0````````````!N`0```````$0.,%2-`HP#A@2#!0`````\````_`$`
+M````````````3`0```````!"#A!"#AA"#B!"#BA!#C!!#CA$#I`!@P>&!HP%
+MC02.`X\"````````)````#P"`````````````%8!````````0@X000X800X@
+M@P2&`XP"`"0```!D`@````````````"K`@```````$0.0%Z/`HX#C02,!88&
+M@P<\````C`(`````````````&@$```````!"#A!"#AA"#B!"#BA!#C!!#CA$
+M#D"#!X8&C`6-!(X#CP(`````````)````,P"`````````````',%````````
+M1`YP7H\"C@.-!(P%A@:#!SP```#T`@````````````"]!````````$(.$$(.
+M&$(.($(.*$$.,$$..$0.4(,'A@:,!8T$C@./`@`````````D````-`,`````
+M````````[`````````!!#A!!#AA$#B"#`X8"````/````%P#````````````
+M`!@%````````0@X00@X80@X@0@XH00XP00XX1`YP@P>&!HP%C02.`X\"````
+M`````"0```"<`P````````````"X`````````$(.$$$.&$$.((,$A@.,`@`T
+M````Q`,`````````````P@````````!"#A!"#AA"#B!!#BA!#C"#!H8%C`2-
+M`XX"`````````#0```#\`P````````````!)`@```````$(.$$(.&$(.($$.
+M*$$.,(,&A@6,!(T#C@(`````````'````#0$`````````````,X`````````
+M1`X0```````<````5`0`````````````/@,```````!!#A!$#G"#`AP```!T
+M!``````````````M`````````$0.$```````/````)0$`````````````$(!
M````````0@X00@X80@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"````````
-M`#P````\!@````````````","P```````$(.$$(.&$(.($(.*$$.,$$..$0.
-ML`&#!X8&C`6-!(X#CP(````````L````?`8`````````````=P(```````!"
-M#A!"#AA!#B!!#BA$#C"#!88$C`.-`@`\````K`8`````````````$04`````
-M``!"#A!"#AA"#B!"#BA!#C!!#CA$#K`!@P>&!HP%C02.`X\"````````%```
-M```````!``%X$`P'")`!````````%````!P``````````````&\`````````
-M%````#0``````````````$(`````````%````$P``````````````%P`````
-M````%````&0``````````````%\`````````%````'P``````````````-X`
-M````````-````)0``````````````#,!````````0@X00@X80@X@00XH00XP
-M1`Y`@P:&!8P$C0..`@`````<````S```````````````1`````````!!#A"#
-M`@```#P```#L``````````````"+`````````$(.$$(.&$(.($(.*$$.,$$.
-M.$0.0(,'A@:,!8T$C@./`@`````````D````+`$`````````````9P$`````
-M``!$#E!>CP*.`XT$C`6&!H,')````%0!`````````````%P!````````1`Y0
-M7H\"C@.-!(P%A@:#!R0```!\`0````````````!%`0```````$0.0%Z/`HX#
-MC02,!88&@P<<````I`$`````````````<@````````!$#C!*A@*#`R0```#$
-M`0`````````````/`0```````$0.0%Z/`HX#C02,!88&@P<\````[`$`````
-M````````GP$```````!"#A!"#AA"#B!"#BA!#C!!#CA$#E"#!X8&C`6-!(X#
-MCP(`````````/````"P"`````````````$\!````````0@X00@X80@X@0@XH
-M00XP00XX1`Y`@P>&!HP%C02.`X\"`````````"0```!L`@`````````````)
-M`0```````$0.,%B.`HT#C`2&!8,&```D````E`(`````````````@P$`````
-M``!$#B!.C`*&`X,$````````)````+P"`````````````/\`````````1`XP
-M5(T"C`.&!(,%`````#P```#D`@````````````"@`````````$(.$$(.&$(.
-M($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````\````)`,`````````
-M````+`$```````!"#A!"#AA"#B!"#BA!#C!!#CA$#E"#!X8&C`6-!(X#CP(`
-M````````/````&0#`````````````&\$````````0@X00@X80@X@0@XH00XP
-M00XX1`Y@@P>&!HP%C02.`X\"`````````!0``````````0`!>!`,!PB0`0``
-M`````!0````<``````````````!6`````````!0````T``````````````!*
-M`````````!0``````````0`!>!`,!PB0`0```````!0````<````````````
-M```<`0```````"0````T```````````````=`0```````$$.$$$.&(,#A@(`
-M```````4````7```````````````AP`````````4````=```````````````
-M)0`````````4````C````````````````@`````````4````I```````````
-M````2P`````````4````O```````````````*@`````````4````U```````
-M````````-``````````4````[```````````````*@`````````4````!`$`
-M````````````,0`````````4````'`$`````````````*@`````````4````
-M-`$`````````````*@`````````4````3`$`````````````(``````````4
-M````9`$`````````````*@`````````4````?`$`````````````*@``````
-M```4````E`$`````````````80`````````4````K`$`````````````]@``
-M```````4````Q`$`````````````T0`````````4````W`$`````````````
-M20`````````L````]`$`````````````^@````````!"#A!"#AA!#B!!#BB#
-M!88$C`.-`@`````<````)`(`````````````+@````````!$#A```````!P`
-M``!$`@`````````````F`````````$0.$```````'````&0"````````````
-M`$8`````````1`X0```````<````A`(`````````````)@````````!$#A``
-M`````!P```"D`@`````````````J`````````$0.$```````/````,0"````
-M`````````(@!````````0@X00@X80@X@0@XH00XP00XX1`Y`@P>&!HP%C02.
-M`X\"`````````!P````$`P`````````````L`````````$0.$```````%```
-M`"0#`````````````",`````````%````#P#`````````````"<`````````
-M)````%0#`````````````.8`````````0@X000X800X@@P2&`XP"`!P```!\
-M`P`````````````^`````````$0.($J&`H,#'````)P#`````````````#X`
-M````````1`X@2H8"@P,D````O`,`````````````20,```````!!#A!!#AA$
-M#B"#`X8"````)````.0#`````````````%D!````````00X000X81`X@@P.&
-M`@```!P````,!`````````````!4`````````$0.($J&`H,#)````"P$````
-M`````````*\`````````1`X@3HP"A@.#!````````"0```!4!```````````
-M``"&`````````$0.($Z,`H8#@P0````````D````?`0`````````````\```
-M``````!$#D!>CP*.`XT$C`6&!H,')````*0$`````````````*@`````````
-M1`XP5(T"C`.&!(,%`````"0```#,!`````````````!^`0```````$$.$$$.
-M&$0.((,#A@(````D````]`0`````````````;0$```````!$#C!8C@*-`XP$
-MA@6#!@``)````!P%`````````````*D`````````1`X@3HP"A@.#!```````
-M`"0```!$!0`````````````-`0```````$0.,%2-`HP#A@2#!0`````D````
-M;`4`````````````*@$```````!$#D!>CP*.`XT$C`6&!H,')````)0%````
-M`````````!,!````````1`XP6(X"C0.,!(8%@P8``"0```"\!0``````````
-M```$`0```````$0.,%B.`HT#C`2&!8,&```D````Y`4`````````````5@$`
-M``````!$#D!>CP*.`XT$C`6&!H,'/`````P&`````````````*,#````````
-M0@X00@X80@X@0@XH00XP00XX1`Y`@P>&!HP%C02.`X\"`````````"0```!,
-M!@````````````#\`````````$0.0%Z/`HX#C02,!88&@P<D````=`8`````
-M````````Z@````````!$#D!>CP*.`XT$C`6&!H,')````)P&````````````
-M`,D`````````1`XP6(X"C0.,!(8%@P8``"0```#$!@````````````"Z````
-M`````$0.,%2-`HP#A@2#!0`````D````[`8`````````````#`$```````!!
-M#A!!#AA$#B"#`X8"````)````!0'`````````````'T!````````1`X@3HP"
-MA@.#!````````!P````\!P`````````````7`````````$$.$(,"````)```
-M`%P'`````````````"H!````````1`X@3HP"A@.#!````````"0```"$!P``
-M``````````!G`````````$$.$$$.&$0.((,#A@(````<````K`<`````````
-M````.@````````!!#A"#`@```!P```#,!P`````````````@`````````$$.
-M$(,"````'````.P'`````````````"8`````````00X0@P(````D````#`@`
-M````````````\@````````!$#C!4C0*,`X8$@P4`````)````#0(````````
-M`````.H!````````1`XP5(T"C`.&!(,%`````"0```!<"`````````````"&
-M`````````$$.$$$.&$0.((,#A@(````D````A`@`````````````A0$`````
-M``!!#A!!#AA$#B"#`X8"````/````*P(`````````````&<#````````0@X0
-M0@X80@X@0@XH00XP00XX1`Y@@P>&!HP%C02.`X\"`````````"P```#L"```
-M``````````#A`0```````$(.$$(.&$$.($$.*$0.,(,%A@2,`XT"`#P````<
-M"0````````````")`@```````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,
-M!8T$C@./`@`````````D````7`D`````````````)`$```````!$#C!4C0*,
-M`X8$@P4`````)````(0)`````````````#0!````````00X000X81`X@@P.&
-M`@```"0```"L"0````````````!+`````````$(.$$$.&$0.((,#C`(````<
-M````U`D`````````````)@````````!$#A```````!0``````````0`!>!`,
-M!PB0`0```````!0````<```````````````5`````````!0````T````````
-M```````:`````````!0```!,```````````````C`````````!0```!D````
-M``````````!!`````````!0```!\``````````````!=`````````!0```"4
-M``````````````"0`0```````"P```"L``````````````#+`````````$(.
-M$$(.&$$.($$.*(,%A@2,`XT"`````"P```#<``````````````!N````````
-M`$(.$$(.&$$.($$.*$0.,(,%A@2,`XT"`!P````,`0`````````````I````
-M`````$$.$(,"````'````"P!`````````````(4`````````1`X0```````L
-M````3`$`````````````1P$```````!"#A!"#AA!#B!!#BA$#C"#!88$C`.-
-M`@`<````?`$`````````````'P$```````!$#A```````!P```"<`0``````
-M``````"``````````$0.$```````'````+P!`````````````(``````````
-M1`X0```````\````W`$`````````````%0D```````!"#A!"#AA"#B!"#BA!
-M#C!!#CA$#G"#!X8&C`6-!(X#CP(`````````)````!P"`````````````(,!
-M````````1`X@3HP"A@.#!````````!0```!$`@````````````"=````````
-M`!0```!<`@````````````#X`````````"P```!T`@````````````#``0``
-M`````$(.$$(.&$$.($$.*$0.,(,%A@2,`XT"`!0``````````0`!>!`,!PB0
-M`0```````!0````<``````````````!_`````````!0````T````````````
-M``!B`````````!0```!,``````````````!B`````````!0```!D````````
-M``````!I`````````!0```!\```````````````'`````````!0```"4````
-M```````````S`````````!0```"L``````````````!1`````````!0```#$
-M```````````````?`````````!0```#<```````````````N`````````!P`
-M``#T``````````````"3`````````$0.$```````)````!0!````````````
-M``$!````````1`XP5(T"C`.&!(,%`````#P````\`0````````````#1`0``
-M`````$(.$$(.&$(.($(.*$$.,$$..$0.4(,'A@:,!8T$C@./`@`````````L
-M````?`$`````````````7P````````!"#A!"#AA!#B!!#BA$#C"#!88$C`.-
-M`@`D````K`$`````````````[@````````!$#D!>CP*.`XT$C`6&!H,')```
-M`-0!`````````````,X`````````1`XP6(X"C0.,!(8%@P8``!P```#\`0``
-M```````````;`0```````$$.$(,"````)````!P"`````````````*<`````
-M````1`XP5(T"C`.&!(,%`````"0```!$`@`````````````J`0```````$$.
-M$$$.&$0.((,#A@(````D````;`(`````````````PP````````!$#C!8C@*-
-M`XP$A@6#!@``)````)0"`````````````/$`````````1`XP5(T"C`.&!(,%
-M`````#P```"\`@````````````#A`````````$(.$$(.&$(.($(.*$$.,$$.
-M.$0.<(,'A@:,!8T$C@./`@`````````\````_`(`````````````X0``````
-M``!"#A!"#AA"#B!"#BA!#C!!#CA$#G"#!X8&C`6-!(X#CP(`````````/```
-M`#P#`````````````)\"````````0@X00@X80@X@0@XH00XP00XX1`YP@P>&
-M!HP%C02.`X\"`````````#0```!\`P````````````#=`@```````$(.$$(.
-M&$(.($$.*$$.,(,&A@6,!(T#C@(`````````)````+0#`````````````*<`
-M````````1`XP6(X"C0.,!(8%@P8``#P```#<`P`````````````^`P``````
-M`$(.$$(.&$(.($(.*$$.,$$..$0.<(,'A@:,!8T$C@./`@`````````\````
-M'`0`````````````60<```````!"#A!"#AA"#B!"#BA!#C!!#CA$#J`!@P>&
-M!HP%C02.`X\"````````/````%P$`````````````/4`````````0@X00@X8
-M0@X@0@XH00XP00XX1`Y`@P>&!HP%C02.`X\"`````````#0```"<!```````
-M``````#M`P```````$(.$$(.&$(.($$.*$$.,$0.8(,&A@6,!(T#C@(`````
-M/````-0$`````````````"H(````````0@X00@X80@X@0@XH00XP00XX1`Y@
-M@P>&!HP%C02.`X\"`````````"0````4!0````````````"H`````````$$.
-M$$$.&$0.((,#A@(````D````/`4`````````````:08```````!$#C!8C@*-
-M`XP$A@6#!@``)````&0%`````````````$,"````````1`X@3HP"A@.#!```
-M`````!P```",!0`````````````4`````````$0.$```````)````*P%````
-M`````````*4)````````1`Y`7H\"C@.-!(P%A@:#!R0```#4!0``````````
-M``#X`P```````$0.,%2-`HP#A@2#!0`````D````_`4`````````````)P,`
-M``````!$#C!8C@*-`XP$A@6#!@``/````"0&`````````````+P"````````
-M0@X00@X80@X@0@XH00XP00XX1`Y@@P>&!HP%C02.`X\"`````````#P```!D
-M!@````````````#O`@```````$(.$$(.&$(.($(.*$$.,$$..$<.@`6#!X8&
-MC`6-!(X#CP(````````\````I`8`````````````OP(```````!"#A!"#AA"
-M#B!"#BA!#C!!#CA'#N`$@P>&!HP%C02.`X\"````````/````.0&````````
-M`````.H#````````0@X00@X80@X@0@XH00XP00XX1PZ`!8,'A@:,!8T$C@./
-M`@```````#P````D!P````````````#L`P```````$(.$$(.&$(.($(.*$$.
-M,$$..$<.\`2#!X8&C`6-!(X#CP(````````\````9`<`````````````&`$`
-M``````!"#A!"#AA"#B!"#BA!#C!!#CA$#E"#!X8&C`6-!(X#CP(`````````
-M+````*0'``````````````$"````````0@X00@X800X@00XH1`XP@P6&!(P#
-MC0(`)````-0'`````````````#L"````````1`XP5(T"C`.&!(,%`````#P`
-M``#\!P````````````"O`````````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'
-MA@:,!8T$C@./`@`````````D````/`@`````````````@PP```````!$#D!>
-MCP*.`XT$C`6&!H,')````&0(`````````````",)````````1`Y`7H\"C@.-
+M`#P```#4!`````````````#<`@```````$(.$$(.&$(.($(.*$$.,$$..$0.
+M4(,'A@:,!8T$C@./`@`````````\````%`4`````````````=P@```````!"
+M#A!"#AA"#B!"#BA!#C!!#CA$#J`!@P>&!HP%C02.`X\"````````/````%0%
+M`````````````)\"````````0@X00@X80@X@0@XH00XP00XX1`Y`@P>&!HP%
+MC02.`X\"`````````!0``````````0`!>!`,!PB0`0```````!0````<````
+M```````````5`````````!0``````````0`!>!`,!PB0`0```````!P````<
+M```````````````H`0```````$$.$(,"````%````#P```````````````(`
+M````````%````%0``````````````)<`````````%````&P`````````````
+M`"H`````````%````(0``````````````"X`````````%````)P`````````
+M`````"H`````````%````+0``````````````"H`````````%````,P`````
+M`````````"H`````````'````.0```````````````X!````````00X0@P(`
+M```<````!`$`````````````(P$```````!!#A"#`@```!P````D`0``````
+M```````N`````````$0.$```````'````$0!`````````````$P`````````
+M1`X0```````<````9`$`````````````+`````````!$#A```````!P```"$
+M`0`````````````^`````````$0.($J&`H,#'````*0!`````````````#X`
+M````````1`X@2H8"@P,D````Q`$`````````````AP$```````!!#A!!#AA$
+M#B"#`X8"````'````.P!`````````````%\`````````1`X@2H8"@P,D````
+M#`(`````````````_`````````!!#A!!#AA$#B"#`X8"````)````#0"````
+M`````````!@!````````1`X@3HP"A@.#!````````!P```!<`@``````````
+M```7`````````$$.$(,"````)````'P"`````````````/@`````````1`X@
+M3HP"A@.#!````````"0```"D`@````````````!C`````````$$.$$$.&$0.
+M((,#A@(````<````S`(`````````````(`````````!!#A"#`@```!P```#L
+M`@`````````````@`````````$$.$(,"````)`````P#`````````````,4`
+M````````1`X@3HP"A@.#!````````"0````T`P````````````#*`0``````
+M`$0.,%2-`HP#A@2#!0`````<````7`,`````````````@P````````!$#B!*
+MA@*#`SP```!\`P`````````````;`@```````$(.$$(.&$(.($(.*$$.,$$.
+M.$0.0(,'A@:,!8T$C@./`@`````````D````O`,`````````````8P$`````
+M``!!#A!!#AA$#B"#`X8"````/````.0#`````````````&`"````````0@X0
+M0@X80@X@0@XH00XP00XX1`Y`@P>&!HP%C02.`X\"`````````!P````D!```
+M```````````\`````````$$.$(,"````'````$0$`````````````"8`````
+M````1`X0```````<````9`0`````````````)@````````!$#A```````"0`
+M``"$!`````````````!+`````````$(.$$$.&$0.((,#C`(````4````````
+M``$``7@0#`<(D`$````````4````'```````````````?P`````````4````
+M-```````````````:0`````````4````3```````````````40`````````4
+M````9```````````````+@`````````D````?```````````````GP``````
+M``!$#B!.C0*,`X,$````````)````*0``````````````.D`````````1`XP
+M5(T"C`.&!(,%`````"0```#,``````````````#L`````````$0.0%Z/`HX#
+MC02,!88&@P<D````]```````````````N0````````!$#C!8C@*-`XP$A@6#
+M!@``)````!P!`````````````!<!````````1`XP5(T"C`.&!(,%`````"P`
+M``!$`0````````````!?`````````$(.$$(.&$$.($$.*$0.,(,%A@2,`XT"
+M`!P```!T`0````````````"/`````````$0.$```````-````)0!````````
+M`````$("````````0@X00@X80@X@00XH00XP@P:&!8P$C0..`@`````````\
+M````S`$`````````````X0````````!"#A!"#AA"#B!"#BA!#C!!#CA$#G"#
+M!X8&C`6-!(X#CP(`````````/`````P"`````````````.$`````````0@X0
+M0@X80@X@0@XH00XP00XX1`YP@P>&!HP%C02.`X\"`````````#0```!,`@``
+M``````````!%`@```````$(.$$(.&$(.($$.*$$.,$0.4(,&A@6,!(T#C@(`
+M````/````(0"`````````````.D!````````0@X00@X80@X@0@XH00XP00XX
+M1`Y0@P>&!HP%C02.`X\"`````````#P```#$`@````````````!L`P``````
+M`$(.$$(.&$(.($(.*$$.,$$..$0.@`&#!X8&C`6-!(X#CP(````````\````
+M!`,`````````````WP8```````!"#A!"#AA"#B!"#BA!#C!!#CA$#J`!@P>&
+M!HP%C02.`X\"````````/````$0#`````````````/4`````````0@X00@X8
+M0@X@0@XH00XP00XX1`Y`@P>&!HP%C02.`X\"`````````#P```"$`P``````
+M``````!:!P```````$(.$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,!8T$C@./
+M`@`````````D````Q`,`````````````"@@```````!$#D!>CP*.`XT$C`6&
+M!H,')````.P#`````````````.T#````````1`XP3XP"A@.#!````````"0`
+M```4!``````````````8!0```````$0.($Z,`H8#@P0````````D````/`0`
+M````````````Z0````````!$#B!.C`*&`X,$````````-````&0$````````
+M`````$@#````````0@X00@X80@X@00XH00XP1`Y`@P:&!8P$C0..`@`````<
+M````G`0`````````````%`````````!$#A```````!P```"\!```````````
+M```8`````````$0.$```````'````-P$`````````````!@`````````1`X0
+M```````D````_`0`````````````I0````````!!#A!!#AA$#B"#`X8"````
+M+````"0%`````````````/\!````````0@X00@X800X@00XH1`XP@P6&!(P#
+MC0(`)````%0%`````````````/\!````````1`XP5(T"C`.&!(,%`````#0`
+M``!\!0````````````#M!0```````$(.$$(.&$(.($$.*$$.,$0.0(,&A@6,
+M!(T#C@(`````%``````````!``%X$`P'")`!````````%````!P`````````
+M`````#``````````%````#0``````````````"4`````````)````$P`````
+M`````````'8`````````00X000X8@P.&`@```````!P```!T````````````
+M``!+`````````$0.&$F,`H,#'````)0``````````````!H`````````00X0
+M@P(````4````M```````````````0``````````D````S```````````````
+ME0````````!!#A!!#AB#`X8"````````'````/0``````````````"<`````
+M````00X0@P(````<````%`$`````````````/P````````!$#A```````"0`
+M```T`0````````````"'`````````$0.,%2-`HP#A@2#!0`````D````7`$`
+M````````````3P````````!"#A!!#AA!#B"#!(8#C`(`)````(0!````````
+M`````'X`````````1`XP5(T"C`.&!(,%`````"0```"L`0````````````#)
+M`````````$0.,%2-`HP#A@2#!0`````\````U`$`````````````$`(`````
+M``!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````'```
+M`!0"`````````````%(`````````1`X@2HP"@P,<````-`(`````````````
+M4@````````!$#B!*C`*#`S0```!4`@````````````"J`````````$(.$$(.
+M&$(.($$.*$$.,(,&A@6,!(T#C@(`````````'````(P"`````````````%(`
+M````````1`X@2HP"@P,<````K`(`````````````-P````````!$#A``````
+M`!P```#,`@`````````````_`````````$0.$```````/````.P"````````
+M`````-X"````````0@X00@X80@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"
+M`````````!P````L`P````````````!3`````````$0.$```````'````$P#
+M`````````````$L`````````1`X0```````<````;`,`````````````4@``
+M``````!$#B!*C`*#`Q0``````````0`!>!`,!PB0`0```````!0````<````
+M```````````8`````````!0````T```````````````2`````````!P```!,
+M``````````````!.`@```````$$.$(,"````%````&P``````````````!X`
+M````````%````(0``````````````"``````````)````)P`````````````
+M`.,`````````00X000X8@P.&`@```````!0``````````0`!>!`,!PB0`0``
+M`````!0````<```````````````Q`0```````!0````T```````````````<
+M`````````!0```!,```````````````=`````````!0```!D````````````
+M```K`````````!0```!\```````````````G`````````"0```"4````````
+M``````#N`````````$0.*%.-`HP#A@2#!0`````4````O```````````````
+M0``````````D````U```````````````F@````````!$#BA3C0*,`X8$@P4`
+M````%````/P``````````````%P`````````%````!0!`````````````!<`
+M````````'````"P!`````````````-(#````````1`X0```````<````3`$`
+M````````````50$```````!!#A!$#C"#`AP```!L`0````````````#A````
+M`````$0.$```````%``````````!``%X$`P'")`!````````%````!P`````
+M`````````$0`````````%````#0``````````````!0`````````)````$P`
+M`````````````&4`````````0@X000X800X@@P2&`XP"`"0```!T````````
+M```````)`P```````$$.$$$.&$0.,(,#A@(````D````G```````````````
+MI@````````!$#C!/C`*&`X,$````````)````,0``````````````'<`````
+M````00X000X81`XP@P.&`@```#P```#L``````````````#$`````````$(.
+M$$(.&$(.($(.*$$.,$$..$0.4(,'A@:,!8T$C@./`@`````````<````+`$`
+M````````````?0````````!!#A!$#B"#`AP```!,`0````````````"T````
+M`````$0.,$J&`H,#)````&P!`````````````'D#````````1`Y@7H\"C@.-
M!(P%A@:#!Q0``````````0`!>!`,!PB0`0```````!0````<````````````
-M```P`````````!0````T```````````````E`````````"0```!,````````
-M``````!V`````````$$.$$$.&(,#A@(````````<````=```````````````
-M2P````````!$#AA)C`*#`QP```"4```````````````:`````````$$.$(,"
-M````%````+0``````````````$(`````````)````,P``````````````)4`
-M````````00X000X8@P.&`@```````"0```#T``````````````"%`0``````
-M`$(.$$$.&$$.((,$A@.,`@`<````'`$`````````````-P````````!$#A``
-M`````!P````\`0`````````````Y`````````$$.$(,"````'````%P!````
-M`````````#\`````````1`X0```````D````?`$`````````````AP``````
-M``!$#C!4C0*,`X8$@P4`````)````*0!`````````````$\`````````0@X0
-M00X800X@@P2&`XP"`"0```#,`0````````````!^`````````$0.,%2-`HP#
-MA@2#!0`````D````]`$`````````````R0````````!$#C!4C0*,`X8$@P4`
-M````/````!P"`````````````!`"````````0@X00@X80@X@0@XH00XP00XX
-M1`Y`@P>&!HP%C02.`X\"`````````!P```!<`@````````````!2````````
-M`$0.($J,`H,#'````'P"`````````````%(`````````1`X@2HP"@P,T````
-MG`(`````````````J@````````!"#A!"#AA"#B!!#BA!#C"#!H8%C`2-`XX"
-M`````````!P```#4`@````````````!2`````````$0.($J,`H,#'````/0"
-M`````````````#<`````````1`X0```````<````%`,`````````````/P``
-M``````!$#A```````#P````T`P````````````#U!````````$(.$$(.&$(.
-M($(.*$$.,$$..$0.@`&#!X8&C`6-!(X#CP(````````<````=`,`````````
-M````4P````````!$#A```````!P```"4`P````````````!+`````````$0.
-M$```````'````+0#`````````````%(`````````1`X@2HP"@P,4````````
-M``$``7@0#`<(D`$````````4````'```````````````&``````````4````
-M-```````````````$@`````````<````3```````````````3@(```````!!
-M#A"#`@```!0```!L```````````````>`````````!0```"$````````````
-M```@`````````"0```"<``````````````#C`````````$$.$$$.&(,#A@(`
-M```````\````Q```````````````+P$```````!"#A!"#AA"#B!"#BA!#C!!
-M#CA$#D"#!X8&C`6-!(X#CP(`````````)`````0!`````````````.,`````
-M````1`Y`7H\"C@.-!(P%A@:#!S0````L`0`````````````B`0```````$(.
-M$$(.&$(.($$.*$$.,(,&A@6,!(T#C@(`````````)````&0!````````````
-M`*L`````````1`XP5(T"C`.&!(,%`````!0``````````0`!>!`,!PB0`0``
-M`````!0````<```````````````[`0```````!0````T```````````````%
-M`````````!0```!,```````````````&`````````!0```!D````````````
-M```<`````````!0```!\```````````````=`````````!0```"4````````
-M```````K`````````!0```"L```````````````G`````````"0```#$````
-M```````````S`0```````$0.,%B.`HT#C`2&!8,&```4````[```````````
-M````0``````````D````!`$`````````````F@````````!$#BA3C0*,`X8$
-M@P4`````%````"P!`````````````%P`````````%````$0!````````````
-M`!<`````````'````%P!`````````````/$#````````1`X0```````<````
-M?`$`````````````50$```````!!#A!$#C"#`AP```"<`0````````````"G
-M`0```````$$.$(,"````%``````````!``%X$`P'")`!````````%````!P`
-M`````````````$0`````````%````#0``````````````!0`````````)```
-M`$P``````````````&4`````````0@X000X800X@@P2&`XP"`"0```!T````
-M```````````)`P```````$$.$$$.&$0.,(,#A@(````D````G```````````
-M````I@````````!$#C!/C`*&`X,$````````)````,0``````````````'<`
-M````````00X000X81`XP@P.&`@```#P```#L``````````````#$````````
-M`$(.$$(.&$(.($(.*$$.,$$..$0.4(,'A@:,!8T$C@./`@`````````<````
-M+`$`````````````?0````````!!#A!$#B"#`AP```!,`0````````````"T
-M`````````$0.,$J&`H,#)````&P!`````````````'D#````````1`Y@7H\"
-MC@.-!(P%A@:#!Q0``````````0`!>!`,!PB0`0```````!0````<````````
-M```````&`````````!0````T``````````````!&`````````!0```!,````
-M```````````&`````````!0```!D```````````````&`````````!0```!\
-M```````````````&`````````!0```"4``````````````!T`````````!0`
-M``"L``````````````"9`````````!0```#$```````````````"````````
-M`!0```#<```````````````(`````````!0```#T``````````````!0````
-M`````!0````,`0`````````````&`````````!0````D`0`````````````&
-M`````````!0````\`0`````````````R`````````!P```!4`0``````````
-M```\`````````$0.&$F,`H,#%````'0!`````````````!,`````````%```
-M`(P!`````````````%P`````````%````*0!`````````````%P`````````
-M'````+P!`````````````!H`````````1`X0```````D````W`$`````````
-M````U`````````!!#A!!#AA$#E"#`X8"````/`````0"`````````````#D&
-M````````0@X00@X80@X@0@XH00XP00XX1`Z@`8,'A@:,!8T$C@./`@``````
-M`!P```!$`@````````````!&`````````$0.($J,`H,#)````&0"````````
-M`````!$!````````00X000X81`X@@P.&`@```!P```",`@`````````````>
-M`````````$$.$(,"````'````*P"`````````````!X`````````00X0@P(`
-M```<````S`(`````````````$0````````!$#A```````"0```#L`@``````
-M``````"!`0```````$0.0%Z/`HX#C02,!88&@P<D````%`,`````````````
-MW`0```````!$#E!>CP*.`XT$C`6&!H,')````#P#`````````````#4$````
-M````1`YP7H\"C@.-!(P%A@:#!R0```!D`P````````````#(`````````$0.
-M($Z,`H8#@P0````````D````C`,`````````````DP$```````!$#C!8C@*-
-M`XP$A@6#!@``'````+0#`````````````-(`````````00X0@P(````D````
-MU`,`````````````C`````````!!#A!!#AA$#B"#`X8"````)````/P#````
-M`````````-P`````````00X000X81`X@@P.&`@```!P````D!```````````
-M```?`````````$$.$(,"````/````$0$`````````````/$"````````0@X0
-M0@X80@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"`````````"0```"$!```
-M``````````"C`````````$0.($Z,`H8#@P0````````D````K`0`````````
-M````H0,```````!$#E!>CP*.`XT$C`6&!H,')````-0$`````````````'D!
-M````````1`XP5(T"C`.&!(,%`````"0```#\!`````````````#8````````
-M`$0.($Z,`H8#@P0````````\````)`4`````````````Z04```````!"#A!"
-M#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````'````&0%````
-M`````````)H`````````1`X@2H8"@P,L````A`4`````````````)@D`````
-M``!"#A!!#AA!#B!$#E"#!(8#C`(````````\````M`4`````````````>00`
-M``````!"#A!"#AA"#B!"#BA!#C!!#CA$#G"#!X8&C`6-!(X#CP(`````````
-M)````/0%`````````````$\"````````0@X000X800X@@P2&`XP"`#0````<
-M!@`````````````)!````````$(.$$(.&$(.($$.*$$.,(,&A@6,!(T#C@(`
-M````````+````%0&`````````````"`$````````0@X00@X800X@00XH@P6&
-M!(P#C0(`````)````(0&`````````````/4#````````0@X000X800X@@P2&
-M`XP"`"0```"L!@````````````!@`@```````$(.$$$.&$$.((,$A@.,`@`D
-M````U`8`````````````T@8```````!$#C!8C@*-`XP$A@6#!@``)````/P&
-M`````````````'X"````````00X000X81`X@@P.&`@```#P````D!P``````
-M```````\`P```````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./
-M`@`````````4``````````$``7@0#`<(D`$````````4````'```````````
-M````+``````````4````-````````````````@`````````\````3```````
-M````````;@(```````!"#A!"#AA"#B!"#BA!#C!!#CA$#E"#!X8&C`6-!(X#
-MCP(`````````%``````````!``%X$`P'")`!````````%````!P`````````
-M`````#8`````````%````#0``````````````#8`````````%````$P`````
-M`````````$8`````````%````&0``````````````$8`````````%````'P`
-M``````````````P`````````%``````````!``%X$`P'")`!````````%```
-M`!P``````````````"(`````````%````#0``````````````$<`````````
-M%````$P``````````````!``````````%````&0``````````````%P`````
-M````%````'P```````````````T`````````%````)0``````````````"<`
-M````````%````*P``````````````#``````````%````,0`````````````
-M`#$`````````%````-P``````````````#,`````````%````/0`````````
-M`````-P!````````%`````P!`````````````#X`````````'````"0!````
-M`````````(X`````````1`YP```````<````1`$`````````````.0``````
-M``!$#A```````!0```!D`0`````````````H`````````!0```!\`0``````
-M```````A`````````!0```"4`0`````````````@`````````!0`````````
-M`0`!>!`,!PB0`0```````!0````<``````````````!C`````````!0````T
-M``````````````!2`````````!0```!,``````````````!2`````````!0`
-M``!D``````````````!Y`````````"0```!\``````````````!0`0``````
-M`$0.,%2-`HP#A@2#!0`````<````I```````````````/P````````!$#B!*
-MC`*#`SP```#$``````````````!M`@```````$(.$$(.&$(.($(.*$$.,$$.
-M.$0.D`&#!X8&C`6-!(X#CP(````````D````!`$`````````````2@$`````
-M``!!#A!!#AA$#B"#`X8"````%``````````!``%X$`P'")`!````````%```
-M`!P``````````````$T`````````%````#0``````````````((`````````
-M%````$P``````````````'4`````````%````&0``````````````'$`````
-M````%````'P``````````````!D`````````'````)0``````````````$4`
-M````````1`X0```````<````M```````````````(0````````!$#A``````
-M`!P```#4``````````````!?`````````$0.$```````/````/0`````````
-M``````,"````````0@X00@X80@X@0@XH00XP00XX1`Y`@P>&!HP%C02.`X\"
-M`````````!P````T`0````````````#M`````````$0.$```````)````%0!
-M`````````````!,!````````1`XP5(T"C`.&!(,%`````"0```!\`0``````
-M```````8`0```````$(.$$$.&$$.((,$A@.,`@`D````I`$`````````````
-M`P8```````!$#D!>CP*.`XT$C`6&!H,''````,P!`````````````!$`````
-M````1`X0```````\````[`$`````````````50L```````!"#A!"#AA"#B!"
-M#BA!#C!!#CA$#I`!@P>&!HP%C02.`X\"````````+````"P"````````````
-M`!`"````````0@X00@X800X@00XH1`XP@P6&!(P#C0(`)````%P"````````
-M`````%T#````````1`Y07H\"C@.-!(P%A@:#!SP```"$`@````````````#O
-M`P```````$(.$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,!8T$C@./`@``````
-M```D````Q`(`````````````PPD```````!$#F!>CP*.`XT$C`6&!H,'/```
-M`.P"`````````````(L)````````0@X00@X80@X@0@XH00XP00XX1P[@`8,'
-MA@:,!8T$C@./`@```````"0````L`P````````````#J`````````$0.,%2-
-M`HP#A@2#!0`````\````5`,`````````````P`D```````!"#A!"#AA"#B!"
-M#BA!#C!!#CA$#F"#!X8&C`6-!(X#CP(`````````/````)0#````````````
-M`+0)````````0@X00@X80@X@0@XH00XP00XX1`Z@`8,'A@:,!8T$C@./`@``
-M`````"0```#4`P````````````"[`````````$(.$$$.&$$.((,$A@.,`@`T
-M````_`,`````````````O@````````!"#A!"#AA"#B!!#BA!#C"#!H8%C`2-
-M`XX"`````````#0````T!`````````````!?`P```````$(.$$(.&$(.($$.
-M*$$.,(,&A@6,!(T#C@(`````````'````&P$`````````````,@`````````
-M1`X0```````\````C`0`````````````GP,```````!"#A!"#AA"#B!"#BA!
-M#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````)````,P$`````````````,D#
-M````````1`XP5(T"C`.&!(,%`````#P```#T!`````````````#X`P``````
-M`$(.$$(.&$(.($(.*$$.,$$..$0.H`&#!X8&C`6-!(X#CP(````````\````
-M-`4`````````````,08```````!"#A!"#AA"#B!"#BA!#C!!#CA$#F"#!X8&
-MC`6-!(X#CP(`````````'````'0%`````````````($`````````1`X0````
-M```<````E`4`````````````#@````````!$#A```````!P```"T!0``````
-M```````+!````````$$.$$0.<(,")````-0%``````````````8!````````
-M1`Y`7H\"C@.-!(P%A@:#!SP```#\!0````````````!#`0```````$(.$$(.
-M&$(.($(.*$$.,$$..$0.4(,'A@:,!8T$C@./`@`````````\````/`8`````
-M````````D`L```````!"#A!"#AA"#B!"#BA!#C!!#CA$#K`!@P>&!HP%C02.
-M`X\"````````+````'P&`````````````'<"````````0@X00@X800X@00XH
-M1`XP@P6&!(P#C0(`/````*P&`````````````,$$````````0@X00@X80@X@
-M0@XH00XP00XX1`ZP`8,'A@:,!8T$C@./`@```````!0``````````0`!>!`,
-M!PB0`0```````!0````<``````````````!O`````````!0````T````````
-M``````!"`````````!0```!,``````````````!<`````````!0```!D````
-M``````````!?`````````!0```!\``````````````#>`````````#0```"4
-M```````````````S`0```````$(.$$(.&$(.($$.*$$.,$0.0(,&A@6,!(T#
-MC@(`````'````,P``````````````$0`````````00X0@P(````\````[```
-M````````````BP````````!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-
-M!(X#CP(`````````)````"P!`````````````&<!````````1`Y07H\"C@.-
-M!(P%A@:#!R0```!4`0````````````!<`0```````$0.4%Z/`HX#C02,!88&
-M@P<D````?`$`````````````10$```````!$#D!>CP*.`XT$C`6&!H,''```
-M`*0!`````````````'(`````````1`XP2H8"@P,D````Q`$`````````````
-M#P$```````!$#D!>CP*.`XT$C`6&!H,'/````.P!`````````````)\!````
-M````0@X00@X80@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"`````````#P`
-M```L`@````````````!/`0```````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'
-MA@:,!8T$C@./`@`````````D````;`(`````````````"0$```````!$#C!8
-MC@*-`XP$A@6#!@``)````)0"`````````````(,!````````1`X@3HP"A@.#
-M!````````"0```"\`@````````````#_`````````$0.,%2-`HP#A@2#!0``
-M```\````Y`(`````````````H`````````!"#A!"#AA"#B!"#BA!#C!!#CA$
-M#D"#!X8&C`6-!(X#CP(`````````/````"0#`````````````"P!````````
-M0@X00@X80@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"`````````#P```!D
-M`P````````````!O!````````$(.$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,
-M!8T$C@./`@`````````4``````````$``7@0#`<(D`$````````4````'```
-M````````````5@`````````4````-```````````````2@`````````4````
-M``````$``7@0#`<(D`$````````4````'```````````````'`$````````D
-M````-```````````````'0$```````!!#A!!#AB#`X8"````````%````%P`
-M`````````````(<`````````%````'0``````````````"4`````````%```
-M`(P```````````````(`````````%````*0``````````````$L`````````
-M%````+P``````````````"H`````````%````-0``````````````#0`````
-M````%````.P``````````````"H`````````%`````0!`````````````#$`
-M````````%````!P!`````````````"H`````````%````#0!````````````
-M`"H`````````%````$P!`````````````"``````````%````&0!````````
-M`````"H`````````%````'P!`````````````"H`````````%````)0!````
-M`````````&$`````````%````*P!`````````````/8`````````%````,0!
-M`````````````-$`````````%````-P!`````````````$D`````````+```
-M`/0!`````````````/H`````````0@X00@X800X@00XH@P6&!(P#C0(`````
-M'````"0"`````````````"X`````````1`X0```````<````1`(`````````
-M````)@````````!$#A```````!P```!D`@````````````!&`````````$0.
-M$```````'````(0"`````````````"8`````````1`X0```````<````I`(`
-M````````````*@````````!$#A```````#P```#$`@````````````"(`0``
-M`````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````<
-M````!`,`````````````+`````````!$#A```````!0````D`P``````````
-M```C`````````!0````\`P`````````````G`````````"0```!4`P``````
-M``````#F`````````$(.$$$.&$$.((,$A@.,`@`<````?`,`````````````
-M/@````````!$#B!*A@*#`QP```"<`P`````````````^`````````$0.($J&
-M`H,#)````+P#`````````````$D#````````00X000X81`X@@P.&`@```"0`
-M``#D`P````````````!9`0```````$$.$$$.&$0.((,#A@(````<````#`0`
-M````````````5`````````!$#B!*A@*#`R0````L!`````````````"O````
-M`````$0.($Z,`H8#@P0````````D````5`0`````````````A@````````!$
-M#B!.C`*&`X,$````````)````'P$`````````````/``````````1`Y`7H\"
-MC@.-!(P%A@:#!R0```"D!`````````````"H`````````$0.,%2-`HP#A@2#
-M!0`````D````S`0`````````````?@$```````!!#A!!#AA$#B"#`X8"````
-M)````/0$`````````````&T!````````1`XP6(X"C0.,!(8%@P8``"0````<
-M!0````````````"I`````````$0.($Z,`H8#@P0````````D````1`4`````
-M````````#0$```````!$#C!4C0*,`X8$@P4`````)````&P%````````````
-M`"H!````````1`Y`7H\"C@.-!(P%A@:#!R0```"4!0`````````````3`0``
-M`````$0.,%B.`HT#C`2&!8,&```D````O`4`````````````!`$```````!$
-M#C!8C@*-`XP$A@6#!@``)````.0%`````````````%8!````````1`Y`7H\"
-MC@.-!(P%A@:#!SP````,!@````````````"C`P```````$(.$$(.&$(.($(.
-M*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````D````3`8`````````````
-M_`````````!$#D!>CP*.`XT$C`6&!H,')````'0&`````````````.H`````
-M````1`Y`7H\"C@.-!(P%A@:#!R0```"<!@````````````#)`````````$0.
-M,%B.`HT#C`2&!8,&```D````Q`8`````````````N@````````!$#C!4C0*,
-M`X8$@P4`````)````.P&``````````````P!````````00X000X81`X@@P.&
-M`@```"0````4!P````````````!]`0```````$0.($Z,`H8#@P0````````<
-M````/`<`````````````%P````````!!#A"#`@```"0```!<!P``````````
-M```J`0```````$0.($Z,`H8#@P0````````D````A`<`````````````9P``
-M``````!!#A!!#AA$#B"#`X8"````'````*P'`````````````#H`````````
-M00X0@P(````<````S`<`````````````(`````````!!#A"#`@```!P```#L
-M!P`````````````F`````````$$.$(,"````)`````P(`````````````/(`
-M````````1`XP5(T"C`.&!(,%`````"0````T"`````````````#J`0``````
-M`$0.,%2-`HP#A@2#!0`````D````7`@`````````````A@````````!!#A!!
-M#AA$#B"#`X8"````)````(0(`````````````(4!````````00X000X81`X@
-M@P.&`@```#P```"L"`````````````!G`P```````$(.$$(.&$(.($(.*$$.
-M,$$..$0.8(,'A@:,!8T$C@./`@`````````L````[`@`````````````X0$`
-M``````!"#A!"#AA!#B!!#BA$#C"#!88$C`.-`@`\````'`D`````````````
-MCP(```````!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`````
-M````)````%P)`````````````"0!````````1`XP5(T"C`.&!(,%`````"0`
-M``"$"0`````````````T`0```````$$.$$$.&$0.((,#A@(````D````K`D`
-M````````````2P````````!"#A!!#AA$#B"#`XP"````'````-0)````````
-M`````"8`````````1`X0```````4``````````$``7@0#`<(D`$````````4
-M````'```````````````%0`````````4````-```````````````&@``````
-M```4````3```````````````(P`````````4````9```````````````00``
-M```````4````?```````````````70`````````4````E```````````````
-MD`$````````L````K```````````````RP````````!"#A!"#AA!#B!!#BB#
-M!88$C`.-`@`````L````W```````````````;@````````!"#A!"#AA!#B!!
-M#BA$#C"#!88$C`.-`@`<````#`$`````````````*0````````!!#A"#`@``
-M`!P````L`0````````````"%`````````$0.$```````+````$P!````````
-M`````$<!````````0@X00@X800X@00XH1`XP@P6&!(P#C0(`'````'P!````
-M`````````!\!````````1`X0```````<````G`$`````````````@```````
-M``!$#A```````!P```"\`0````````````"``````````$0.$```````/```
-M`-P!`````````````!4)````````0@X00@X80@X@0@XH00XP00XX1`YP@P>&
-M!HP%C02.`X\"`````````"0````<`@````````````"#`0```````$0.($Z,
-M`H8#@P0````````4````1`(`````````````G0`````````4````7`(`````
-M````````^``````````L````=`(`````````````P`$```````!"#A!"#AA!
-M#B!!#BA$#C"#!88$C`.-`@`4``````````$``7@0#`<(D`$````````4````
-M'```````````````?P`````````4````-```````````````8@`````````4
-M````3```````````````8@`````````4````9```````````````:0``````
-M```4````?```````````````!P`````````4````E```````````````,P``
-M```````4````K```````````````40`````````4````Q```````````````
-M'P`````````4````W```````````````+@`````````<````]```````````
-M````DP````````!$#A```````"0````4`0`````````````!`0```````$0.
-M,%2-`HP#A@2#!0`````\````/`$`````````````T0$```````!"#A!"#AA"
-M#B!"#BA!#C!!#CA$#E"#!X8&C`6-!(X#CP(`````````+````'P!````````
-M`````%\`````````0@X00@X800X@00XH1`XP@P6&!(P#C0(`)````*P!````
-M`````````.X`````````1`Y`7H\"C@.-!(P%A@:#!R0```#4`0``````````
-M``#.`````````$0.,%B.`HT#C`2&!8,&```<````_`$`````````````&P$`
-M``````!!#A"#`@```"0````<`@````````````"G`````````$0.,%2-`HP#
-MA@2#!0`````D````1`(`````````````*@$```````!!#A!!#AA$#B"#`X8"
-M````)````&P"`````````````,,`````````1`XP6(X"C0.,!(8%@P8``"0`
-M``"4`@````````````#Q`````````$0.,%2-`HP#A@2#!0`````\````O`(`
-M````````````X0````````!"#A!"#AA"#B!"#BA!#C!!#CA$#G"#!X8&C`6-
-M!(X#CP(`````````/````/P"`````````````.$`````````0@X00@X80@X@
-M0@XH00XP00XX1`YP@P>&!HP%C02.`X\"`````````#P````\`P``````````
-M``"?`@```````$(.$$(.&$(.($(.*$$.,$$..$0.<(,'A@:,!8T$C@./`@``
-M```````T````?`,`````````````W0(```````!"#A!"#AA"#B!!#BA!#C"#
-M!H8%C`2-`XX"`````````"0```"T`P````````````"G`````````$0.,%B.
-M`HT#C`2&!8,&```\````W`,`````````````/@,```````!"#A!"#AA"#B!"
-M#BA!#C!!#CA$#G"#!X8&C`6-!(X#CP(`````````/````!P$````````````
-M`%D'````````0@X00@X80@X@0@XH00XP00XX1`Z@`8,'A@:,!8T$C@./`@``
-M`````#P```!<!`````````````#U`````````$(.$$(.&$(.($(.*$$.,$$.
-M.$0.0(,'A@:,!8T$C@./`@`````````T````G`0`````````````[0,`````
-M``!"#A!"#AA"#B!!#BA!#C!$#F"#!H8%C`2-`XX"`````#P```#4!```````
-M```````J"````````$(.$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,!8T$C@./
-M`@`````````D````%`4`````````````J`````````!!#A!!#AA$#B"#`X8"
-M````)````#P%`````````````&D&````````1`XP6(X"C0.,!(8%@P8``"0`
-M``!D!0````````````!#`@```````$0.($Z,`H8#@P0````````<````C`4`
-M````````````%`````````!$#A```````"0```"L!0````````````"E"0``
-M`````$0.0%Z/`HX#C02,!88&@P<D````U`4`````````````^`,```````!$
-M#C!4C0*,`X8$@P4`````)````/P%`````````````"<#````````1`XP6(X"
-MC0.,!(8%@P8``#P````D!@````````````"R`@```````$(.$$(.&$(.($(.
-M*$$.,$$..$0.8(,'A@:,!8T$C@./`@`````````\````9`8`````````````
-M[P(```````!"#A!"#AA"#B!"#BA!#C!!#CA'#H`%@P>&!HP%C02.`X\"````
-M````/````*0&`````````````+\"````````0@X00@X80@X@0@XH00XP00XX
-M1P[@!(,'A@:,!8T$C@./`@```````#P```#D!@````````````#J`P``````
-M`$(.$$(.&$(.($(.*$$.,$$..$<.@`6#!X8&C`6-!(X#CP(````````\````
-M)`<`````````````[`,```````!"#A!"#AA"#B!"#BA!#C!!#CA'#O`$@P>&
-M!HP%C02.`X\"````````/````&0'`````````````!@!````````0@X00@X8
-M0@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"`````````"P```"D!P``````
-M```````!`@```````$(.$$(.&$$.($$.*$0.,(,%A@2,`XT"`"0```#4!P``
-M```````````[`@```````$0.,%2-`HP#A@2#!0`````\````_`<`````````
-M````KP````````!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`
-M````````)````#P(`````````````',,````````1`Y`7H\"C@.-!(P%A@:#
-M!R0```!D"``````````````C"0```````$0.0%Z/`HX#C02,!88&@P<4````
-M``````$``7@0#`<(D`$````````4````'```````````````,``````````4
-M````-```````````````)0`````````D````3```````````````=@``````
-M``!!#A!!#AB#`X8"````````'````'0``````````````$L`````````1`X8
-M28P"@P,<````E```````````````&@````````!!#A"#`@```!0```"T````
-M``````````!"`````````"0```#,``````````````"5`````````$$.$$$.
-M&(,#A@(````````D````]```````````````A0$```````!"#A!!#AA!#B"#
-M!(8#C`(`'````!P!`````````````#<`````````1`X0```````<````/`$`
-M````````````)P````````!$#A```````!P```!<`0`````````````_````
-M`````$0.$```````)````'P!`````````````-4`````````1`XP6(X"C0.,
-M!(8%@P8``"0```"D`0````````````!/`````````$(.$$$.&$$.((,$A@.,
-M`@`D````S`$`````````````?@````````!$#C!4C0*,`X8$@P4`````)```
-M`/0!`````````````,D`````````1`XP5(T"C`.&!(,%`````#P````<`@``
-M```````````0`@```````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$
-MC@./`@`````````<````7`(`````````````4@````````!$#B!*C`*#`QP`
-M``!\`@````````````!2`````````$0.($J,`H,#-````)P"````````````
-M`*H`````````0@X00@X80@X@00XH00XP@P:&!8P$C0..`@`````````<````
-MU`(`````````````4@````````!$#B!*C`*#`QP```#T`@`````````````W
-M`````````$0.$```````'````!0#`````````````#\`````````1`X0````
-M```\````-`,`````````````904```````!"#A!"#AA"#B!"#BA!#C!!#CA$
-M#I`!@P>&!HP%C02.`X\"````````'````'0#`````````````%,`````````
-M1`X0```````<````E`,`````````````2P````````!$#A```````!P```"T
-M`P````````````!2`````````$0.($J,`H,#%``````````!``%X$`P'")`!
-M````````%````!P``````````````!@`````````%````#0`````````````
-M`!(`````````'````$P``````````````.@`````````00X0@P(````4````
-M;```````````````(``````````4````A```````````````(@`````````<
-M````G```````````````@@````````!!#A"#`@```#P```"\````````````
-M```O`0```````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@``
-M```````D````_```````````````XP````````!$#D!>CP*.`XT$C`6&!H,'
-M-````"0!`````````````"(!````````0@X00@X80@X@00XH00XP@P:&!8P$
-MC0..`@`````````D````7`$`````````````JP````````!$#C!4C0*,`X8$
-M@P4`````%``````````!``%X$`P'")`!````````%````!P`````````````
-M`#L!````````%````#0```````````````4`````````%````$P`````````
-M``````8`````````%````&0``````````````!P`````````%````'P`````
-M`````````!T`````````%````)0``````````````"L`````````%````*P`
-M`````````````"<`````````)````,0``````````````#,!````````1`XP
-M6(X"C0.,!(8%@P8``!0```#L``````````````!``````````"0````$`0``
-M``````````":`````````$0.*%.-`HP#A@2#!0`````4````+`$`````````
-M````7``````````4````1`$`````````````%P`````````<````7`$`````
-M````````\0,```````!$#A```````!P```!\`0````````````!5`0``````
-M`$$.$$0.,(,"'````)P!`````````````*<!````````00X0@P(````4````
-M``````$``7@0#`<(D`$````````4````'```````````````1``````````4
-M````-```````````````%``````````D````3```````````````90``````
-M``!"#A!!#AA!#B"#!(8#C`(`)````'0```````````````D#````````00X0
-M00X81`XP@P.&`@```"0```"<``````````````"F`````````$0.,$^,`H8#
-M@P0````````D````Q```````````````=P````````!!#A!!#AA$#C"#`X8"
-M````/````.P``````````````,0`````````0@X00@X80@X@0@XH00XP00XX
-M1`Y0@P>&!HP%C02.`X\"`````````!P````L`0````````````!]````````
-M`$$.$$0.((,"'````$P!`````````````+0`````````1`XP2H8"@P,D````
-M;`$`````````````>0,```````!$#F!>CP*.`XT$C`6&!H,'%``````````!
-M``%X$`P'")`!````````%````!P```````````````8`````````%````#0`
-M`````````````$8`````````%````$P```````````````8`````````%```
-M`&0```````````````8`````````%````'P```````````````8`````````
-M%````)0``````````````'0`````````%````*P``````````````)D`````
-M````%````,0```````````````(`````````%````-P```````````````@`
-M````````%````/0``````````````%``````````%`````P!````````````
-M``8`````````%````"0!`````````````/0`````````%````#P!````````
-M`````#(`````````'````%0!`````````````#P`````````1`X828P"@P,4
-M````=`$`````````````$P`````````4````C`$`````````````7```````
-M```4````I`$`````````````7``````````<````O`$`````````````&@``
-M``````!$#A```````"0```#<`0````````````#4`````````$$.$$$.&$0.
-M4(,#A@(````\````!`(`````````````.08```````!"#A!"#AA"#B!"#BA!
-M#C!!#CA$#J`!@P>&!HP%C02.`X\"````````'````$0"`````````````'``
-M````````1`X@2HP"@P,<````9`(`````````````1@````````!$#B!*C`*#
-M`QP```"$`@`````````````>`````````$$.$(,"````'````*0"````````
-M`````!X`````````00X0@P(````<````Q`(`````````````$0````````!$
-M#A```````"0```#D`@````````````"!`0```````$0.0%Z/`HX#C02,!88&
-M@P<D````#`,`````````````W`0```````!$#E!>CP*.`XT$C`6&!H,')```
-M`#0#`````````````#4$````````1`YP7H\"C@.-!(P%A@:#!R0```!<`P``
-M``````````#(`````````$0.($Z,`H8#@P0````````D````A`,`````````
-M````DP$```````!$#C!8C@*-`XP$A@6#!@``'````*P#`````````````-(`
-M````````00X0@P(````D````S`,`````````````C`````````!!#A!!#AA$
-M#B"#`X8"````)````/0#`````````````-P`````````00X000X81`X@@P.&
-M`@```!P````<!``````````````?`````````$$.$(,"````/````#P$````
-M`````````/$"````````0@X00@X80@X@0@XH00XP00XX1`Y0@P>&!HP%C02.
-M`X\"`````````"0```!\!`````````````"C`````````$0.($Z,`H8#@P0`
-M```````D````I`0`````````````F@,```````!$#E!>CP*.`XT$C`6&!H,'
-M)````,P$`````````````'D!````````1`XP5(T"C`.&!(,%`````"0```#T
-M!``````````````Q`0```````$0.8$^,`H8#@P0````````\````'`4`````
-M````````Z04```````!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#
-MCP(`````````'````%P%`````````````)H`````````1`X@2H8"@P,L````
-M?`4`````````````)@D```````!"#A!!#AA!#B!$#E"#!(8#C`(````````\
-M````K`4`````````````>00```````!"#A!"#AA"#B!"#BA!#C!!#CA$#G"#
-M!X8&C`6-!(X#CP(`````````)````.P%`````````````$4"````````0@X0
-M00X800X@@P2&`XP"`#0````4!@`````````````)!````````$(.$$(.&$(.
-M($$.*$$.,(,&A@6,!(T#C@(`````````+````$P&`````````````"`$````
-M````0@X00@X800X@00XH@P6&!(P#C0(`````)````'P&`````````````/4#
-M````````0@X000X800X@@P2&`XP"`"0```"D!@````````````!@`@``````
-M`$(.$$$.&$$.((,$A@.,`@`D````S`8`````````````T@8```````!$#C!8
-MC@*-`XP$A@6#!@``)````/0&`````````````(X"````````00X000X81`X@
-M@P.&`@```#P````<!P`````````````\`P```````$(.$$(.&$(.($(.*$$.
-M,$$..$0.0(,'A@:,!8T$C@./`@`````````4``````````$``7@0#`<(D`$`
-M```````4````'```````````````$P`````````4````-```````````````
-M#``````````4````3```````````````*0`````````4````9```````````
-M````#``````````D````?```````````````=P````````!!#A"#`DH.D`(`
-M````````)````*0``````````````,@`````````0@X000X8A@.,`D0.((,$
-M`!0```#,```````````````L`````````"0```#D``````````````!+````
-M`````$(.$$$.&(8#C`)##B"#!``4````#`$`````````````.P`````````4
-M````)`$`````````````*P`````````4````/`$`````````````/0``````
-M```<````5`$`````````````*`````````!!#A"#`@```!0```!T`0``````
-M```````+`````````!0```",`0`````````````0`````````!0```"D`0``
-M```````````E`````````!0```"\`0`````````````^`````````!0```#4
-M`0````````````!?`````````"0```#L`0````````````"#`````````$(.
-M$(P"1`X8A@-&#B"#!``D````%`(`````````````50````````!"#A",`D8.
-M&$$.((,$A@,`-````#P"`````````````-D`````````0@X00@X80@X@00XH
-MA@6,!(T#C@)$#C"#!@`````````D````=`(`````````````PP````````!!
-M#A"&`D0.&(,#1PX@````)````)P"`````````````'<`````````00X0A@)$
-M#AA$#B"#`P```"0```#$`@````````````!7`````````$$.$(8"1`X81`X@
-M@P,````D````[`(`````````````V0````````!"#A",`D0.&$$.((,$A@,`
-M+````!0#`````````````/D`````````0@X0C0)%#AA!#B"&!(P#1`XH1`XP
-M@P4`'````$0#`````````````%4`````````00X0@P(````D````9`,`````
-M````````5P````````!$#B!)A@.#!$>,`@``````%````(P#````````````
-M`!``````````%````*0#`````````````!$`````````%````+P#````````
-M`````!4`````````-````-0#`````````````&\"````````0@X00@X8C0..
-M`D4.((P$10XH00XP@P:&!0`````````\````#`0`````````````5@$`````
-M``!"#A!"#AA"#B!"#BA!#C!!#CB#!X8&C`6-!(X#CP)*#L`!````````+```
-M`$P$`````````````/,`````````0@X0C0)%#AB,`T0.((8$1`XH1`XP@P4`
-M)````'P$`````````````)8`````````1`X@2HP"A@-'@P0``````"P```"D
-M!`````````````"8`````````$(.$$(.&$$.((8$C`.-`D0.*$0.,(,%`#P`
-M``#4!`````````````!:`0```````$(.$(\"10X8C@-%#B"-!$4.*$$.,(8&
-MC`5$#CA$#D"#!P`````````T````%`4`````````````QP$```````!"#A!"
-M#AB-`XX"10X@C`1$#BA!#C!$#K`!@P:&!0```"0```!,!0````````````"S
-M`````````$(.$(P"1`X8A@-(#B"#!``D````=`4`````````````@`$`````
-M``!$#C!1C`2&!5..`HT#@P8`)````)P%`````````````/H`````````0@X0
-M2`X8A@.,`D<.((,$`!0``````````0`!>!`,!PB0`0```````!0````<````
-M```````````^`````````!0````T```````````````2`````````!0```!,
-M```````````````K`````````!0```!D```````````````X`````````!0`
-M``!\```````````````\`````````!0```"4```````````````Q````````
-M`!0```"L``````````````!E`````````!0```#$``````````````"R````
-M`````!0```#<```````````````,`````````"0```#T``````````````!(
-M`````````$$.$(8"1`X81`X@@P,````<````'`$`````````````=P``````
-M``!!#A"#`@```!P````\`0````````````"[`````````$$.$(,"````'```
-M`%P!`````````````%L`````````1`X@2H8"@P,D````?`$`````````````
-MK@````````!"#A",`D0.&$$.((,$A@,`%````*0!``````````````4`````
-M````'````+P!`````````````$X`````````1`X@2H8"@P,D````W`$`````
-M````````:@````````!!#A!!#AA$#B"#`X8"````'`````0"````````````
-M`'@`````````1`X@2H8"@P,4````)`(`````````````-P`````````<````
-M/`(`````````````2P````````!!#A"#`@```"0```!<`@````````````!@
-M`````````$$.$(8"1`X8@P-.#B`````L````A`(`````````````.@,`````
-M``!$#D!*A@:#!TR/`HX#38T$C`4````````D````M`(`````````````9```
-M``````!"#A!(#AB&`XP"1`X@@P0`)````-P"`````````````.$`````````
-M00X000X8@P.&`D<.(````!P````$`P````````````!``````````$0.($J,
-M`H,#)````"0#`````````````/D!````````1`Y@38P$A@55C@*#!HT#`!P`
-M``!,`P````````````!(`````````$0.($V,`H,#)````&P#````````````
-M`(\!````````1PZ@!%>&`H,#`````````"0```"4`P````````````!:`@``
-M`````$$.$$4.&(,#A@)*#J`$```<````O`,`````````````5@````````!!
-M#A"#`@```"P```#<`P````````````"W"@```````$<.T`97C`6&!F>/`HX#
-MC02#!P```````#P````,!`````````````#O`0```````$(.$(\"2@X80@X@
-MC02.`T4.*$$.,$$..$0.L`&#!X8&C`4````````<````3`0`````````````
-M2@````````!!#A"#`@```"0```!L!`````````````#R`````````$0.($R,
-M`H8#1X,$```````L````E`0`````````````90$```````!"#A!"#AB,`XT"
-M1`X@00XH1`XP@P6&!``L````Q`0`````````````A0$```````!"#A"-`D<.
-M&(P#1`X@00XH1`XP@P6&!``<````]`0`````````````CP````````!!#A"#
-M`@```"0````4!0````````````!F`````````$$.$(8"1`X81`X@@P,````T
-M````/`4`````````````10(```````!"#A!(#AA"#B!!#BA!#C"#!H8%C`2-
-M`XX"`````````"0```!T!0````````````"6`````````$(.$(P"2PX800X@
-M@P2&`P`D````G`4`````````````/@$```````!$#B!)@P2&`TB,`@``````
-M)````,0%`````````````/0`````````1`X@288#@P1(C`(``````"0```#L
-M!0````````````!X`0```````$0.,$J,!(8%48,&C@*-`P`4``````````$`
-M`7@0#`<(D`$````````4````'```````````````50`````````4````-```
-M````````````'@`````````4````3```````````````0@`````````\````
-M9```````````````M`````````!"#A"/`D4.&(X#10X@0@XH00XP00XX1P[0
-M`8,'A@:,!8T$````````/````*0```````````````@!````````0@X00@X8
-MC@./`D4.($(.*(P%C01$#C"&!D0..$<.X`&#!P```````"P```#D````````
-M``````!<`````````$(.$$(.&$$.((8$C`.-`D,.*$<.L`&#!3P````4`0``
-M``````````!7`0```````$(.$$(.&$(.($(.*$$.,(8&C`6-!(X#CP)$#CA'
-M#I`"@P<````````4````5`$`````````````4P`````````4````;`$`````
-M````````F@`````````4````A`$`````````````V@`````````4````G`$`
-M`````````````P$````````4````M`$`````````````20`````````4````
-MS`$`````````````>0`````````\````Y`$`````````````CP0```````!"
-M#A"/`D4.&(X#10X@C01%#BA!#C!!#CA$#D"#!X8&C`4`````````%````"0"
-M``````````````(`````````%````#P"`````````````(4`````````'```
-M`%0"`````````````'(`````````1`Y````````D````=`(`````````````
-M.@````````!!#A!!#AA$#C"#`X8"````%````)P"`````````````-@`````
-M````)````+0"`````````````($`````````0@X0C`)$#AB&`T0.((,$`"P`
-M``#<`@````````````!K`````````$(.$(T"10X8C`-$#B!!#BB#!88$````
-M`!0````,`P````````````!S`````````!0````D`P`````````````6````
-M`````!0````\`P`````````````;`````````!0```!4`P`````````````:
-M`````````!0```!L`P`````````````6`````````!0```"$`P``````````
-M```5`````````!0```"<`P`````````````5`````````!0```"T`P``````
-M```````5`````````!0```#,`P`````````````5`````````!0```#D`P``
-M```````````5`````````!0```#\`P`````````````5`````````!0````4
-M!``````````````8`````````!0````L!``````````````8`````````!0`
-M``!$!``````````````8`````````!0```!<!``````````````8````````
-M`!0```!T!``````````````5`````````!0```",!``````````````H````
-M`````!0```"D!``````````````H`````````!P```"\!``````````````Q
-M`````````$$.$(,"````'````-P$`````````````#$`````````00X0@P(`
-M```<````_`0`````````````,0````````!!#A"#`@```!P````<!0``````
-M``````!D`````````$$.$(,"````'````#P%`````````````&(`````````
-M1`X828,#A@(D````7`4`````````````A0````````!$#B!)@P2&`TB,`@``
-M````)````(0%`````````````,T`````````1`XP28,&A@52C@*-`XP$`"0`
-M``"L!0````````````"B`````````$0.*$F&!(,%38T"C`,````4````U`4`
-M````````````%0`````````4````[`4`````````````.P`````````D````
-M!`8`````````````H@````````!$#BA)A@2#!4V-`HP#````)````"P&````
-M`````````+4`````````1`XH288$@P5-C0*,`P```"0```!4!@``````````
-M``#'`````````$0.*$F&!(,%38T"C`,````D````?`8`````````````VP``
-M``````!$#BA)A@2#!4V-`HP#````%````*0&`````````````!@`````````
-M'````+P&`````````````&4`````````1`X8288"@P,<````W`8`````````
-M````90````````!$#AA)A@*#`QP```#\!@````````````!E`````````$0.
-M&$F&`H,#'````!P'`````````````%T`````````1`X8288"@P,<````/`<`
-M````````````70````````!$#AA)A@*#`QP```!<!P````````````!=````
-M`````$0.&$F&`H,#'````'P'`````````````(8`````````1`X8288"@P,<
-M````G`<`````````````90````````!$#AA)A@*#`QP```"\!P``````````
-M``!E`````````$0.&$F&`H,#)````-P'`````````````+H`````````1`X@
-M288#@P1(C`(``````!P````$"`````````````!E`````````$0.&$F&`H,#
-M'````"0(`````````````&H`````````1`X8288"@P,<````1`@`````````
-M````9P````````!$#AA)A@*#`QP```!D"`````````````!I`````````$0.
-M&$F&`H,#%````(0(`````````````!P`````````%````)P(````````````
-M`!@`````````%````+0(`````````````!8`````````'````,P(````````
-M`````+(`````````1`X8288"@P,<````[`@`````````````L@````````!$
-M#AA)A@*#`QP````,"0````````````!=`````````$0.&$F&`H,#)````"P)
-M`````````````+``````````1`XP28,&A@52C@*-`XP$`"0```!4"0``````
-M``````"P`````````$0.,$F#!H8%4HX"C0.,!``<````?`D`````````````
-M5@````````!$#AA)A@*#`Q0```"<"0`````````````H`````````!P```"T
-M"0````````````!9`````````$$.$(,"````'````-0)`````````````*8`
-M````````1`X83H8"@P,4````]`D`````````````/@`````````<````#`H`
-M````````````LP````````!$#AA)A@*#`QP````L"@````````````"2````
-M`````$0.&$F&`H,#)````$P*``````````````X!````````0@X0C`)*#AB&
-M`T<.((,$`!0```!T"@````````````!N`````````!P```","@``````````
-M``!:`````````$$.$(,"````%````*P*``````````````<`````````'```
-M`,0*`````````````/,`````````1`Y````````4````Y`H`````````````
-M"``````````4````_`H`````````````00`````````<````%`L`````````
-M````<`````````!$#B!*C`*#`R0````T"P````````````#*`````````$0.
-M,$F,!(,&38X"C0-(A@4D````7`L`````````````JP````````!$#B!)A@.#
-M!$B,`@``````+````(0+`````````````!D!````````1`Y`18\"3(P%6H,'
-MC@.-!(8&````````+````+0+``````````````@!````````1`Y`18\"3(P%
-M6H,'C@.-!(8&````````'````.0+`````````````"<`````````10X0@P(`
-M```4````!`P`````````````?0`````````4````'`P`````````````,0``
-M```````4````-`P`````````````,0`````````4````3`P`````````````
-M,0`````````4````9`P`````````````,0`````````4````?`P`````````
-M````,0`````````4````E`P`````````````,0`````````4````K`P`````
-M````````,0`````````4````Q`P`````````````,0`````````4````W`P`
-M````````````,0`````````4````]`P`````````````,0`````````4````
-M#`T`````````````,0`````````4````)`T`````````````,0`````````4
-M````/`T`````````````,0`````````4````5`T`````````````,0``````
-M```4````;`T`````````````,0`````````4````A`T`````````````,0``
-M```````4````G`T`````````````,0`````````4````M`T`````````````
-M,0`````````4````S`T`````````````,0`````````4````Y`T`````````
-M````,0`````````4````_`T`````````````)``````````4````%`X`````
-M````````*``````````<````+`X`````````````J`````````!!#A"#`@``
-M`!0```!,#@`````````````X`````````"0```!D#@````````````#+````
-M`````$0.($Z,`H8#@P0````````<````C`X`````````````10````````!$
-M#B!*@P.,`BP```"L#@`````````````$`0```````$(.$(P"1`X800X@1P[@
-M`8,$A@,``````!P```#<#@````````````!-`````````$0.($J&`H,#+```
-M`/P.`````````````)P!````````1`Y`2H8&@P=7CP*.`XT$C`4`````````
-M/````"P/`````````````(8!````````0@X00@X8C@./`D4.($(.*$$.,$$.
-M.$0.0(,'A@:,!8T$`````````#0```!L#P````````````#9`````````$(.
-M$$(.&$(.((P$C0..`D0.*$$.,(,&A@4`````````'````*0/````````````
-M`(P`````````00X0@P(````L````Q`\`````````````&@(```````!'#M`!
-M4(,'A@9CCP*.`XT$C`4````````4````]`\`````````````+P`````````\
-M````#!``````````````T`````````!"#A!%#AA"#B"-!(X#CP)%#BA!#C!!
-M#CA'#N`!@P>&!HP%````````%````$P0`````````````*D`````````)```
-M`&00`````````````,``````````1`XP3(8$@P5-C0*,`P```"0```",$```
-M``````````!Y`````````$$.$$,.&(,#A@)*#J`!```D````M!``````````
-M````N`````````!$#C!*C`.&!$V-`H,%````)````-P0`````````````*P`
-M````````1`XP2HX#C`51CP*-!(,&`!P````$$0````````````"6````````
-M`$$.$(,"````)````"01`````````````.8`````````00X000X8@P.&`@``
-M`````#P```!,$0````````````#8`````````$(.$$0.&$(.($(.*(P%C02.
-M`X\"1`XP00XX1P[``8,'A@8````````\````C!$`````````````\P``````
-M``!"#A!$#AA"#B!"#BB,!8T$C@./`D0.,$$..$<.P`&#!X8&````````/```
-M`,P1`````````````.X`````````0@X01`X80@X@0@XHC`6-!(X#CP)$#C!!
-M#CA'#L`!@P>&!@```````#P````,$@````````````#N`````````$(.$$0.
-M&$(.($(.*(P%C02.`X\"1`XP00XX1P[``8,'A@8````````\````3!(`````
-M````````[@````````!"#A!$#AA"#B!"#BB,!8T$C@./`D0.,$$..$<.P`&#
-M!X8&````````+````(P2`````````````)X`````````0@X01`X800X@A@2,
-M`XT"1`XH1PZP`8,%'````+P2`````````````$,`````````00X0@P(````D
-M````W!(`````````````K0````````!!#A"&`D8.&$<.H`&#`P``'`````03
-M`````````````$T`````````1`X@2HP"@P,D````)!,`````````````$P$`
-M``````!!#A!(#AB#`X8"1PX@````%````$P3`````````````"L`````````
-M-````&03`````````````,0`````````0@X00@X80@X@00XHA@6,!(T#C@)$
-M#C!$#G"#!@`````D````G!,`````````````GP$```````!$#C!)C`2#!E*.
-M`HT#A@4`%````,03``````````````\`````````'````-P3````````````
-M`!@`````````1`X0```````<````_!,`````````````&`````````!$#A``
-M`````!P````<%``````````````C`````````$0.$```````+````#P4````
-M`````````',`````````0@X0C0)%#AA!#B!!#BA$#C"#!88$C`,`'````&P4
-M`````````````!L`````````1`X0```````<````C!0`````````````B0``
-M``````!$#B!*@P.&`AP```"L%`````````````!'`````````$0.($J#`XP"
-M'````,P4`````````````!L`````````1`X0```````<````[!0`````````
-M````&P````````!$#A```````!P````,%0````````````!2`````````$$.
-M$(,"````)````"P5`````````````#L`````````00X000X81`X@@P.&`@``
-M`"0```!4%0`````````````[`````````$$.$$$.&$0.((,#A@(````D````
-M?!4`````````````-P````````!!#A!!#AA$#B"#`X8"````)````*05````
-M`````````#<`````````00X000X81`X@@P.&`@```"0```#,%0``````````
-M```W`````````$$.$$$.&$0.((,#A@(````D````]!4`````````````-0``
-M``````!!#A!!#AA$#B"#`X8"````)````!P6`````````````&0`````````
-M00X0A@)+#AA$#B"#`P```#P```!$%@`````````````V`0```````$(.$$(.
-M&$(.($(.*$$.,(8&C`6-!(X#CP)$#CA'#M`!@P<````````D````A!8`````
-M````````*`,```````!$#C!*A@2#!4V,`XT"````'````*P6````````````
-M`!L`````````00X0@P(````<````S!8`````````````&P````````!!#A"#
-M`@```"0```#L%@````````````!-`0```````$0.,%2,`XT"A@2#!0`````D
-M````%!<`````````````9`````````!!#A!!#AB#`X8"1PYP````)````#P7
-M`````````````,H!````````0@X0C`)+#AA!#B"#!(8#`#P```!D%P``````
-M``````#P`@```````$(.$(\"10X80@X@0@XH00XPA@:,!8T$C@-$#CA'#N`$
-M@P<````````L````I!<`````````````B@$```````!"#A!$#AB,`XT"1`X@
-M00XH1PZP`8,%A@0L````U!<`````````````3@$```````!"#A"-`D<.&$$.
-M($$.*$<.L`&#!88$C`,D````!!@`````````````A@````````!$#B!)@P2,
-M`TB-`@``````'````"P8`````````````#D`````````00X0@P(````<````
-M3!@`````````````-@````````!!#A"#`@```!P```!L&`````````````#=
-M`@```````$$.$(,"````%````(P8`````````````)`!````````%````*08
-M`````````````"D`````````'````+P8`````````````!X!````````1`X@
-M2H,#A@(L````W!@`````````````C`@```````!"#A!"#AB,`XT"1`X@00XH
-M1`XP@P6&!``D````#!D`````````````SP(```````!!#A"&`D0.&$0.((,#
-M````-````#09`````````````-8`````````0@X00@X80@X@C`2-`XX"1`XH
-M00XP@P:&!0`````````D````;!D`````````````7P,```````!$#G!*A@2#
-M!4V-`HP#````)````)09`````````````.``````````1`Y`2H8$@P5-C0*,
-M`P```!P```"\&0````````````!M`````````$$.$(,"````/````-P9````
-M`````````*\!````````0@X00@X8C@./`D4.($(.*(P%C01$#C!!#CA'#M`$
-M@P>&!@```````"0````<&@````````````"%`0```````$0.,$J&!(,%38T"
-MC`,````\````1!H`````````````2`\```````!"#A!"#AA"#B!"#BA!#C"&
-M!HP%C02.`X\"1`XX1P[``8,'````````)````(0:`````````````&P`````
-M````00X000X8@P.&`D<.(````"0```"L&@`````````````-`0```````$$.
-M$(8"1`X81P[``8,#```D````U!H`````````````30````````!!#A"&`D8.
-M&$0.((,#````+````/P:`````````````+@`````````0@X00@X800X@00XH
-M1`XP@P6&!(P#C0(`+````"P;`````````````#X"````````0@X01PX8C`.-
-M`D0.((8$1`XH1P[P`8,%+````%P;`````````````!`#````````1`Y`2HT$
-MC`57CP*.`X8&@P<`````````)````(P;``````````````<"````````1P[P
-M`56,`X,%4XT"A@0``"P```"T&P````````````"6`````````$(.$(T"10X8
-M00X@00XH1`XP@P6&!(P#`!P```#D&P````````````!4`````````$0.($V,
-M`H,#'`````0<`````````````&``````````00X0@P(````<````)!P`````
-M````````$`(```````!!#A"#`@```"P```!$'`````````````#X!@``````
-M`$0.8$B,!5^/`HT$C@.&!H,'`````````"P```!T'``````````````/!```
-M`````$0.8$V&!H,'6HX#C02,!8\"`````````"0```"D'`````````````!/
-M`````````$0.($F,`X,$2(T"```````D````S!P`````````````=P``````
-M``!$#B!)A@.#!$B,`@``````)````/0<`````````````'<`````````1`X@
-M288#@P1(C`(``````"0````<'0````````````!/`````````$0.($F,`X,$
-M2(T"```````D````1!T`````````````>0````````!$#B!)A@.#!$B,`@``
-M````)````&P=`````````````'D`````````1`X@288#@P1(C`(``````"P`
-M``"4'0````````````"&`````````$(.$(T"10X800X@A@2,`T0.*$0.,(,%
-M`"0```#$'0````````````!9`````````$$.$$$.&(,#A@)'#B`````D````
-M[!T`````````````Y0````````!!#A!!#AB#`X8"1PX@````)````!0>````
-M`````````/,`````````00X0A@)$#AA$#B"#`P```!P````\'@``````````
-M``"2`````````$0.($J&`H,#)````%P>`````````````,D`````````1`X@
-M28P"@P1(A@,``````!P```"$'@`````````````M`````````$0.$```````
-M-````*0>`````````````-D`````````0@X00@X80@X@00XH00XP@P:&!8P$
-MC0..`@`````````\````W!X`````````````20$```````!"#A!$#AA"#B!"
-M#BB,!8T$C@./`D0.,$$..$0.0(,'A@8`````````)````!P?````````````
-M`+(!````````1`Y02H8#@P1(C`(``````#0```!$'P`````````````:`0``
-M`````$(.$$0.&$(.($$.*$$.,(,&A@6,!(T#C@(`````````'````'P?````
-M`````````#H`````````00X0@P(````T````G!\`````````````,P$`````
-M``!"#A!"#AB-`XX"10X@00XH00XP1`ZP`8,&A@6,!````!0```#4'P``````
-M```````%`````````"0```#L'P`````````````E`0```````$0.,$J-`HP#
-M388$@P4````D````%"``````````````=P````````!$#B!)C0*#!$B,`P``
-M````)````#P@`````````````(8`````````0@X02`X8A@.,`D0.((,$`"P`
-M``!D(`````````````"+`````````$(.$$(.&$$.((8$C`.-`D0.*$<.\`&#
-M!20```"4(`````````````")`````````$$.$(8"1@X81`X@@P,````\````
-MO"``````````````\`(```````!"#A!"#AA"#B"-!(X#CP)%#BA!#C!!#CA$
-M#D"#!X8&C`4`````````-````/P@`````````````-(!````````0@X00@X8
-MC0..`D4.($$.*$$.,(,&A@6,!``````````T````-"$`````````````S`$`
-M``````!"#A!"#AB-`XX"10X@00XH00XP@P:&!8P$`````````"P```!L(0``
-M``````````!N`P```````$(.$(T"10X800X@00XH1`YP@P6&!(P#`"0```"<
-M(0````````````#W`````````$(.$$$.&(8#C`)$#B"#!``L````Q"$`````
-M````````I@````````!"#A!"#AA!#B!!#BB#!88$C`.-`DH.\`$D````]"$`
-M````````````80(```````!"#A!!#AB&`XP"1`X@@P0`)````!PB````````
-M`````!L$````````1`XP188$4HT"C`.#!0```!0```!$(@`````````````[
-M`````````!P```!<(@````````````!"`````````$$.$(,"````)````'PB
-M`````````````%P!````````1`Y`7H\"C@.-!(P%A@:#!R0```"D(@``````
-M```````$`0```````$0.,$J#!8P$38X"C0,````4``````````$``7@0#`<(
-MD`$````````4````'```````````````U@`````````<````-```````````
-M````=`````````!$#AA)A@*#`Q0```!4``````````````!K`````````!0`
-M``!L```````````````;`````````!0```"$```````````````)````````
-M`!P```"<``````````````!,`````````$$.$(,"````)````+P`````````
-M`````'$`````````1`X@18,#2(8"`````````"P```#D```````````````7
-M`0```````$(.$$(.&$$.($$.*(,%A@2,`XT"20XP`"P````4`0``````````
-M```&!````````$(.$$(.&$$.($$.*(,%A@2,`XT"1PXP`!P```!$`0``````
-M``````!2`````````$$.$(,"````)````&0!`````````````-\`````````
-M00X01`X81`X@@P.&`@```#P```",`0````````````!N`P```````$(.$(\"
-M2@X80@X@C02.`T4.*$$.,$$..$0.4(,'A@:,!0`````````<````S`$`````
-M````````-@````````!!#A"#`@```!0``````````0`!>!`,!PB0`0``````
-M`!0````<```````````````6`````````"P````T``````````````#R````
-M`````$(.$(T"20X800X@00XH@P6&!(P#`````!0```!D```````````````]
-M`````````!0```!\``````````````!F`````````"P```"4````````````
-M``#I`````````$(.$(P"1`X8A@-$#B"#!$<.,````````!P```#$````````
-M``````!?`````````$$.$(,"1PX@)````.0``````````````-4`````````
-M0@X0C`)$#AA!#B"#!(8#`!P````,`0````````````"1`````````$$.$(,"
-M````/````"P!`````````````!$"````````0@X0CP)%#AA"#B!"#BA!#C"&
-M!HP%C02.`T0..$0.4(,'`````````#0```!L`0````````````#8`P``````
-M`$(.$$(.&$(.($$.*(8%C`2-`XX"1`XP1PZP!(,&````)````*0!````````
-M`````&,`````````00X0A@)%#AA$#B"#`P```"0```#,`0````````````"#
-M`````````$(.$$$.&$$.((,$A@.,`@`L````]`$`````````````2`(`````
-M``!"#A!"#AA!#B"&!(P#C0)$#BA$#C"#!0`<````)`(`````````````G```
-M``````!$#B!*A@*#`R0```!$`@````````````!H`0```````$(.$(P"2`X8
-MA@-%#B"#!``L````;`(`````````````N`<```````!'#L`$;H8&C@.,!8,'
-M4X\"C00````````D````G`(`````````````AP(```````!!#A"&`D0.&$0.
-M((,#````%``````````!``%X$`P'")`!````````%````!P`````````````
-M`%0`````````%````#0```````````````(`````````%````$P`````````
-M`````!,`````````%````&0```````````````,`````````)````'P`````
-M`````````.(`````````0@X0C`)$#AA!#B"#!(8#`"0```"D````````````
-M```Z`````````$$.$(8"1`X81`X@@P,````<````S```````````````20``
-M``````!!#A"#`@```!P```#L``````````````!5`````````$0.$```````
-M%`````P!``````````````P`````````%````"0!``````````````P`````
-M````%``````````!``%X$`P'")`!````````%````!P``````````````$\`
-M````````%````#0``````````````$\``````````$=#0SH@*$=.52D@-"XR
-M+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@
-M-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.
-M52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@
-M*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#
-M0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T`
-M`$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)3
-M1%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E
-M94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;
-M1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S
-M92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L
-M96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E
-M<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@
-M<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X
-M,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P
-M-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@
-M,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR
-M+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@
-M-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.
-M52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@
-M*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#
-M0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T`
-M`$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)3
-M1%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E
-M94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;
-M1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S
-M92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L
-M96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E
-M<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@
-M<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X
-M,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P
-M-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@
-M,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@-"XR
-M+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.52D@
-M-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@*$=.
-M52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#0SH@
-M*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T``$=#
-M0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)31%T`
-M`$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E94)3
-M1%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;1G)E
-M94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S92!;
-M1G)E94)31%T``$=#0SH@*$=.52D@-"XR+C(@,C`P-S`X,S$@<')E<F5L96%S
-M92!;1G)E94)31%T``"YS>6UT86(`+G-T<G1A8@`N<VAS=')T86(`+G)E;&$N
-M=&5X=``N<F5L82YR;V1A=&$`+G)O9&%T82YS='(Q+C@`+G)O9&%T82YS='(Q
-M+C$`+G)E;&$N9&%T80`N<F5L82YE:%]F<F%M90`N8G-S`"YC;VUM96YT````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````(`````$````&````````````````
-M````0``````````?&`4`````````````````$````````````````````!L`
-M```$`````````````````````````-B+!@``````N,0!```````.`````0``
-M``@`````````&``````````K`````0````(```````````````````!@&`4`
-M`````'`H```````````````````@````````````````````)@````0`````
-M````````````````````D%`(````````70````````X````#````"```````
-M```8`````````#,````!````,@```````````````````-!`!0``````O`P`
-M``````````````````@``````````0````````!"`````0```#(`````````
-M``````````",304``````"H$```````````````````!``````````$`````
-M````5@````$````#````````````````````P%$%``````#0#0``````````
-M````````(````````````````````%$````$````````````````````````
-M`)"M"```````6!0````````.````!P````@`````````&`````````!A````
-M`0````(```````````````````"07P4``````%"<```````````````````(
-M````````````````````7`````0`````````````````````````Z,$(````
-M``!(8P````````X````)````"``````````8`````````&L````(`````P``
-M`````````````````.#[!0``````8`4``````````````````"``````````
-M``````````!P`````0````````````````````````#@^P4``````%`'````
-M```````````````!````````````````````$0````,`````````````````
-M````````,`,&``````!Y`````````````````````0``````````````````
-M``$````"`````````````````````````+`'!@``````0$0````````/````
-M=P(```@`````````&``````````)`````P````````````````````````#P
-M2P8``````.<_```````````````````!````````````````````````````
-M``````````````````````````````,``0``````````````````````````
-M``,``@````````````````````````````,``P``````````````````````
-M``````,`!`````````````````````````````,`!0``````````````````
-M``````````,`!@````````````````````````````,`!P``````````````
-M``````````````,`"`````````````````````````````,`"0``````````
-M``````````````````,`"@````````````````````````````,`"P``````
-M``````````````````````,`#`````````````````````````````,`#0``
-M``````````````````````````,`#@````````````````````````````,`
-M#P```````````````````````0````(``0!@_P```````*<`````````%0``
-M``(``0"P`@```````#8`````````(P````(``0#P!`$``````)\"````````
-M-@````(``0"0$0```````'$`````````1`````(``0!@&`````````,&````
-M````9`````(``0`00`$``````.\"````````>P````(``0"0]P````````<`
-M````````B@````(``0``\P```````/@`````````HP````(``0``>@$`````
-M`$L`````````KP````(``0!`A`$``````"<`````````RP````(``0!`_@``
-M`````!L!````````VP````(``0!``````````&X"````````]@````(``0"0
-M=P````````8!````````$`$```(``0"P"````````"@`````````)@$```(`
-M`0!0>@$``````%(`````````-P$```(``0"PGP```````&\$````````5`$`
-M``(``0`PYP```````(``````````;0$```(``0#@!P```````(X`````````
-M@0$```(``0#@"````````"$`````````H0$```(``0#0;0$``````#\`````
-M````L0$```(``0"0'@```````%4+````````S`$```(``0#`D@$``````'<`
-M````````V0$```(``0`0!0```````#``````````]P$```(``0#P@P$`````
-M`!T`````````$@(```(``0#0>@$``````!(`````````*P(```(``0!`J0``
-M`````"H`````````1@(```(``0`P`P```````$8`````````5@(```(``0``
-MCP$```````D#````````:`(```(``0#0J````````#$`````````@P(```(`
-M`0`@_````````%\`````````DP(```(``0"0T@```````(8`````````KP(`
-M``(``0#0I````````!P!````````S`(```(``0"@D0```````&<!````````
-M[0(```(``0"0^````````),``````````P,```(``0`0D0```````(L`````
-M````'@,```(``0!`F@````````D!````````1@,```(``0#PA0$``````)H`
-M````````9@,```(``0"@T````````.H!````````>0,```(``0!`E@``````
-M``\!````````FP,```(``0#PA@$``````!<`````````O@,```(``0!PE```
-M`````$4!````````W@,```(``0!P?@$``````"\!````````^@,```(``0"@
-MSP```````/(`````````$`0```(``0"0PP```````*,#````````*`0```$`
-M`P#@$@```````!L`````````,P0```(``0`0``$``````"H!````````0@0`
-M``(``0!P<P````````X`````````7@0```(``0#`10$``````.H#````````
-M=00```(``0`PL````````"P`````````B00```(``0#`<P$``````%(`````
-M````F@0```(``0"P1@```````.H`````````O`0```(``0"P>@$``````!@`
-M````````U`0```(``0"`XP```````"D`````````]`0```(``0"PWP``````
-M`!H`````````#04```(``0"@=`$``````/4$````````'04```(``0!@=`$`
-M`````#\`````````+P4```(``0`04P$``````*\`````````1`4```(``0#0
-MW0```````#0!````````704```(``0"`A0```````'<"````````?04```(`
-M`0!@?0$``````"``````````B@4```(``0#@<@```````($`````````J`4`
-M``(``0#0`P````````P`````````N04```(``0#@!````````"<`````````
-MS04```(``0`@TP```````(4!````````W@4```(``0!@:@$``````$L`````
-M````[04```(``0`P"0```````&,``````````08```(``0``B````````!$%
-M````````%@8```(``0#@C0```````%P`````````*P8```(``0#@"@``````
-M`%`!````````/P8```(``0!`R````````.H`````````8P8```(``0``````
-M`````"P`````````@08```(``0"P$@```````%\`````````F`8```(``0`0
-MV@```````(D"````````J@8```(``0`0XP```````&X`````````N08```(`
-M`0!`X@```````,L`````````U`8```(``0!0<@$``````%(`````````Y`8`
-M``$`"P!@`````````(``````````Z@8```(``0`@I````````%8`````````
-M!P<```(``0#P>0```````(P+````````(@<```(``0`0BP$``````%4!````
-M````4`<```(``0#`!0```````-P!````````;0<```(``0#`Q`$``````)H`
-M````````?0<```(``0`@=`$``````#<`````````D`<```(``0"@J```````
-M`"H`````````JP<```(``0!@+P```````.\#````````RP<```(``0#`N`$`
-M`````*$#````````Y@<```(``0"`G@```````"P!````````"P@```(``0"@
-M"0```````%(`````````'@@```(``0#@`P```````"(`````````,0@```(`
-M`0"0J0```````"H`````````1@@```(``0!`K````````$D`````````5P@`
-M``(``0`0O0```````*D`````````>0@```(``0"PYP```````!4)````````
-MB@@```(``0``+````````%T#````````H@@```(``0!@;````````'$&````
-M````P`@```(``0!PK@```````"H`````````W`@```(``0!0,P```````,,)
-M````````_`@```(``0#PL0```````#X`````````$0D```(``0#`3@$`````
-M``$"````````)@D```(``0#`7````````%\#````````/0D```(``0!`C@``
-M`````%\`````````6@D```(``0`0`@$``````/$`````````=0D```(``0!0
-MSP```````"``````````C`D```(``0"PL0```````#X`````````I`D```(`
-M`0"0K0```````"X`````````O0D```(``0!0;0$``````#<`````````S0D`
-M``(``0"@!P```````#X`````````V0D```(``0!@WP```````"8`````````
-M\PD```(``0!PN0```````*@`````````#@H```(``0#0RP```````'T!````
-M````)0H```(``0"0A@$``````%P`````````2`H```(``0!`?0$``````!X`
-M````````7`H```(``0"`!0```````#,`````````<`H```(``0!PJ0``````
-M`"``````````B@H```(``0#0WP```````",`````````H@H```(``0`0J0``
-M`````"H`````````NPH```(``0!`%P```````!@!````````V@H```(``0#@
-M#@```````$H!````````YPH```(``0`0$P```````!@"````````!`L```(`
-M`0"`_````````.X`````````&@L```(``0#0@P$``````!P`````````-PL`
-M``(``0!``0$``````,,`````````3`L```(``0#@M@```````%0`````````
-M:`L```(``0`0SP```````#H`````````@`L```(``0#`:P$``````(4!````
-M````D0L```(``0"`N````````/``````````K0L```(``0"PA0$``````$``
-M````````TPL```(``0`0$@```````!D`````````[@L```(``0#PMP``````
-M`(8`````````$PP```(``0`PL@```````$D#````````*`P```(``0#`O0``
-M``````T!````````20P```(``0!`K@```````"8`````````90P```(``0!@
-M#@$``````%D'````````>PP```(``0"@30$``````!@!````````D@P```(`
-M`0#@F0$``````)D`````````I`P```(``0#`K0```````"8`````````N@P`
-M``(``0!0FP```````(,!````````T0P```(``0!0/0$``````+P"````````
-MXPP```(``0#P*0```````!`"````````_PP```(``0`PJ````````"H`````
-M````#PT```(``0!`]@```````&(`````````+0T```(``0!`6P```````+L`
-M````````2@T```(``0"@C@```````-X`````````:@T```(``0!P@@$`````
-M`#L!````````>PT```(``0"0L````````"<`````````E`T```(``0#@(@$`
-M`````*@`````````J`T```(``0`0WP```````$L`````````OPT```(``0!P
-M#````````&T"````````T0T```(``0`P$````````$T`````````Z`T```(`
-M`0`0IP$``````-P$`````````PX```(``0#`E0```````'(`````````%PX`
-M``(``0!PS0```````"H!````````*@X```(``0`0!````````$<`````````
-M.0X```(``0`@/0```````(L)````````40X```(``0"0C0```````$(`````
-M````>PX```(``0!PA`$``````#,!````````G@X```(``0"0@`$``````"(!
-M````````N0X```(``0"@NP```````&T!````````W`X```(``0!P!```````
-M`%P`````````\`X```(``0`@C0```````&\`````````%@\```(``0!@JP``
-M`````-$`````````,`\```(``0``*@$``````$,"````````3P\```(``0`0
-M;@$``````(<`````````80\```(``0"P20$``````.P#````````=@\```(`
-M`0!08`$``````",)````````DP\```(``0``0P$``````+\"````````K`\`
-M``(``0!@Q0$``````"8)````````NP\```(``0!P+`$``````*4)````````
-MV`\```(``0"@W````````"0!````````\`\```(``0!@J````````#0`````
-M````!!````(``0!0X````````%T`````````(1````(``0``X````````$$`
-M````````-1````(``0`0IP```````(<`````````1!````(``0"0K```````
-M`/H`````````5A````(``0"@?P$``````.,`````````<1````(``0!PSP``
-M`````"8`````````A1````(``0"0WP```````!4`````````FQ````(``0`0
-M$0```````'4`````````O1````(``0``]````````,`!````````TA````(`
-M`0#P>@$``````$X"````````Z!````(``0``7````````+X`````````!1$`
-M``(``0"`?0$``````.,`````````'!$```(``0"0;0$``````#D`````````
-M+1$```(``0!P"````````#D`````````01$```(``0`@P0````````0!````
-M````:1$```(``0"@L@$``````-(`````````?A$```(``0"`I````````$H`
-M````````GQ$```$`"P!``````````!P`````````L!$```(``0`@.@$`````
-M`"<#````````S!$```(``0#P`@```````#8`````````WQ$```(``0"@IP``
-M`````"4`````````]Q$```(``0#PF````````$\!````````'!(```(``0`P
-M$@```````$4`````````/!(```(``0#`@P$```````8`````````5!(```(`
-M`0`@]P```````&D`````````8!(```(``0"0(P$``````&D&````````>1(`
-M``(``0!@\@```````)T`````````CQ(```(``0`0DP```````%P!````````
-ML!(```(``0!P_0```````,X`````````Q1(```(``0#`4P$``````(,,````
-M````X1(```(``0!0E0$``````'D#````````^!(```(``0!0+`$``````!0`
-M````````$A,```(``0!`^@```````-$!````````+!,```(``0"``P``````
-M`$8`````````0!,```(``0"09````````,D#````````5Q,```(``0"@]P``
-M`````#,`````````91,```(``0#`J0```````"H`````````?1,```(``0`P
-M^0````````$!````````D1,```(``0#PI0```````!T!````````K!,```(`
-M`0"PX````````)`!````````PQ,```(``0!`MP```````*\`````````WQ,`
-M``(``0"0!P$``````-T"````````_1,```(``0#0O@$``````.D%````````
-M%!0```(``0"@>0$``````%,`````````(10```(``0#0:@$``````$(`````
-M````+A0```(``0"`CP```````#,!````````4A0```(``0!`Y````````$<!
-M````````;10```(``0"0E`$``````+0`````````A10```(``0!@L```````
-M`",`````````H10```(``0!`^````````!\`````````L!0```(``0!@!```
-M`````!``````````PA0```(``0#P8````````)\#````````W10```(``0"`
-M$@```````"$`````````\Q0```(``0`0A`$``````"L`````````#A4```(`
-M`0"0Y0```````!\!````````(A4```(``0`0`P$``````.$`````````-A4`
-M``(``0#@G````````/\`````````4Q4```(``0!@F0$``````'0`````````
-M814```(``0!PC`$``````*<!````````>!4```(``0`0"0```````"``````
-M````BA4```(``0"@S@```````&<`````````G!4```(``0"@F@$``````%``
-M````````K14```(``0``P````````!,!````````UQ4```(``0!@"@``````
-M`'D`````````]!4```(``0#`]0```````'\`````````$18```(``0!@40``
-M`````-()````````*!8```(``0`0AP$``````/$#````````/A8```(``0`@
-MV````````.$!````````3A8```(``0!`!0```````#$`````````918```(`
-M`0`0N`$``````*,`````````@18```(``0#0!`````````T`````````F!8`
-M``$`!P!``````````"@`````````I18```(``0!P'@```````!$`````````
-MPQ8```(``0``!`$``````.$`````````UQ8```(``0"P<@$``````%(`````
-M````YQ8```$`"P````````````0`````````^18```(``0"PY@```````(``
-M````````(A<```(``0"`$````````((`````````01<```(``0!0S0``````
-M`!<`````````41<```(``0#@IP```````$L`````````:A<```(``0"@>```
-M`````$,!````````@Q<```(``0!@:````````/@#````````FQ<```(``0"P
-MU````````&<#````````N1<```(``0`@"P$``````#X#````````TQ<```(`
-M`0`P%0```````.T`````````Z1<```(``0!@J@```````/8``````````!@`
-M``(``0"@1P```````,`)````````%A@```(``0``"@```````%(`````````
-M*A@```(``0#PJ0```````&$`````````/1@```(``0"`LP$``````(P`````
-M````51@```(``0"PXP```````(4`````````<!@```(``0#`D````````$0`
-M````````EQ@```(``0``R@```````+H`````````OA@```(``0#PK0``````
-M`$8`````````V1@```(``0#0O@```````"H!````````_!@```(``0"`<P``
-M``````L$````````'1D```(``0#@G0```````*``````````/!D```(``0!P
-M"@$``````*<`````````4!D```(``0#`@0$``````*L`````````:QD```(`
-M`0#04`$``````#L"````````AQD```(``0`P#````````#\`````````F1D`
-M``(``0"P&@$``````"H(````````M!D```(``0#`L````````.8`````````
-MQAD```(``0#`%@$``````.T#````````V1D```(``0!0EP```````)\!````
-M`````AH```(``0!`QP```````/P`````````*1H```(``0`@:P$``````)4`
-M````````0QH```(``0`0G`$``````%P`````````6QH```(``0"P@P$`````
-M``4`````````<QH```(``0"P]@```````&(`````````D1H```(``0#`R@``
-M``````P!````````IAH```(``0#0IP````````(`````````NQH```(``0`P
-MR0```````,D`````````W1H```(``0`PP@```````%8!`````````0````(`
-M`0`P[P(``````*<`````````-@````(``0`@`@(``````'$``````````!L`
-M``(``0``]0$``````%P`````````>P````(``0!@YP(```````<`````````
-M%AL```(``0`0F0(``````"H`````````,QL```(``0!@LP(``````*,#````
-M````RP````(``0`0[@(``````!L!````````31L```(``0#`7`(``````#$&
-M````````;1L```(``0"0A0(``````'(`````````@QL```(``0`04`,`````
-M`",)````````HAL```(``0"`U@(``````(``````````S1L```(``0"0H`(`
-M`````.8`````````)@$```(``0#`:@,``````%(`````````X1L```(``0#P
-MDP(``````%8``````````!P```(``0`P<0,``````#L!````````$QP```(`
-M`0#`BP,``````%P`````````+1P```(``0"00P,``````',,````````2QP`
-M``(``0#`6`(``````/@#````````91P```(``0"`T`(``````)`!````````
-MH0$```(``0"`70,``````#\`````````S`$```(``0"`@0,``````'<`````
-M````?AP```(``0`0A`,``````'D#````````EQP```(``0!`F0(``````"``
-M````````LQP```(``0!P/0,``````!@!````````S!P```(``0`0]`$`````
-M`$8`````````XAP```(``0"08P(```````X``````````!T```(``0"@]0$`
-M`````#``````````(!T```(``0`0G`(``````$D`````````,QT```(``0#@
-M0@,``````*\`````````2AT```(``0!`G@(``````"H`````````:!T```(`
-M`0!P^0$``````"$`````````BAT```(``0`PF`(``````#0`````````H!T`
-M``(``0#`?0,```````D#````````@P(```(``0#PZP(``````%\`````````
-MM!T```(``0#0=0,``````/$#````````S!T```(``0#`F0(``````&$`````
-M````X1T```(``0``_0$``````&T"````````S`(```(``0!P@0(``````&<!
-M````````[0(```(``0!@Z`(``````),`````````]1T```(``0!`^@(`````
-M`*<``````````P,```(``0#@@`(``````(L`````````"QX```(``0!`:P,`
-M`````!(`````````'@,```(``0`0B@(```````D!````````)AX```(``0`P
-M-P(``````.H`````````2AX```(``0"0^@$``````%(`````````8!X```(`
-M`0"0/@,```````$"````````*`0```$``P`@)@```````"``````````,P0`
-M``(``0#@[P(``````"H!````````=QX```(``0!POP(``````/(`````````
-MCQX```(``0"`Q`(``````&<#````````KQX```(``0`0A@(```````\!````
-M````TQX```(``0"@0`,``````#L"````````\1X```(``0`0U`(``````$<!
-M````````B00```(``0#`8P,``````%(`````````#A\```(``0#`E0(`````
-M`!T!````````*Q\```(``0#@"`(```````,&````````31\```(``0#`IP(`
-M`````(8`````````?04```(``0!P;`,``````"(`````````=!\```(``0#@
-MO@(``````#H`````````CA\```(``0`PH`(``````",`````````K!\```(`
-M`0"0@`(``````$0`````````U1\```(``0"@`@(``````!D`````````\A\`
-M``(``0!`^0$``````"@`````````U`8```(``0!08@,``````%(`````````
-MY`8```$`"P!@`0```````(``````````"B````(``0"0N@(```````P!````
-M````(2````(``0"P?0(``````%P`````````."````(``0"0!@,``````.T#
-M````````32````(``0`0]@$``````#,`````````;0<```(``0`0M`,`````
-M`)H`````````8R````(``0`P<P,``````#,!````````B"````(``0#`B`(`
-M`````$\!````````KR````(``0``L@(``````%8!````````U"````(``0!@
-M3`(``````+X`````````\R````(``0`PFP(``````-$`````````#R$```(`
-M`0!``P(``````%\`````````*"$```(``0#`^0$``````&,`````````/B$`
-M``(``0#PP@(``````(4!````````42$```(``0"0\`$``````"P`````````
-M<2$```(``0"P9P(```````8!````````O0D```(``0`070,``````#<`````
-M````C2$```(``0#P?`(``````&\`````````M2$```(``0#```(``````$T`
-M````````SB$```(``0"P=`,``````)H`````````V0D```(``0`PSP(`````
-M`"8`````````\"$```(``0#@'P(``````.\#````````$B(```(``0`P;0,`
-M`````"\!````````,"(```(``0#0(P(``````,,)````````4B(```(``0#0
-MKP(``````!,!````````?B(```(``0!0C@(``````"P!````````I2(```(`
-M`0#``@(``````$4`````````QR(```(``0#`IP,``````)H#````````2`H`
-M``(``0!0;`,``````"``````````Y"(```(``0!P&@(``````!`"````````
-M`B,```(``0`0`0(``````((`````````H@H```(``0#@F`(``````"H`````
-M````(R,```(``0!@;@,``````.,`````````0",```(``0#0X@(``````/@`
-M````````6R,```(``0#P^@(``````#X#````````V@H```(``0!P_P$`````
-M`$H!````````=R,```(``0"@+0(``````(L)````````D2,```(``0!@SP(`
-M`````!4`````````J2,```(``0#0<@,``````"L`````````QB,```(``0!0
-ME`(``````$H`````````Z2,```(``0`@6@,``````$L`````````^B,```(`
-M`0#`H0(``````#X`````````$20```(``0`0:@,``````%,`````````@`L`
-M``(``0"`6P,``````(4!````````("0```(``0`@T`(``````%T`````````
-M/R0```(``0#0N0(``````+H`````````:"0```(``0#@6@,``````)4`````
-M````A"0```(``0`@K@,``````.D%````````G20```(``0#@R0(``````(\"
-M````````L20```(``0!PJP(``````&T!````````UB0```(``0"@;`,`````
-M`((`````````[R0```(``0"`Y@(``````&(`````````#R4```(``0!@F0(`
-M`````"H`````````)B4```(``0"@^0$``````"``````````.B4```(``0!0
-M[`(``````.X`````````4B4```(``0!@9`,``````#\`````````9B4```(`
-M`0!@]`$```````P`````````>24```(``0"`.0,``````.P#````````D"4`
-M``(``0!`\P$``````#8`````````D@P```(``0"@B`,``````)D`````````
-MN@P```(``0`@BP(``````(,!````````H"4```(``0#0&0,``````$,"````
-M````T0P```(``0`@+0,``````+("````````P24```(``0`@AP(``````)\!
-M````````["4```(``0``H`(``````"P``````````B8```(``0!P]0$`````
-M`"<`````````&"8```(``0`0\0(``````,,`````````+R8```(``0#`:`(`
-M`````$,!````````2B8```(``0#`]`(``````)\"````````7R8```(``0!P
-MP`(``````.H!````````="8```(``0#PL`(```````0!````````GB8```(`
-M`0"@NP(``````'T!````````MR8```(``0"0G0(``````"8`````````SR8`
-M``(``0`0?@(``````%\`````````40X```(``0!@?0(``````$(`````````
-M[B8```(``0#@00(``````+0)````````!R<```(``0`P_@(``````%D'````
-M````'R<```(``0"`UP(``````!4)````````,B<```(``0"0<@,``````!P`
-M````````42<```(``0``^0$``````#D`````````9R<```(``0!`'`,`````
-M`*4)````````AB<```(``0"@K@(``````"H!````````JR<```(``0!@]P(`
-M`````-T"````````3P\```(``0#`70,``````-4`````````RR<```(``0!@
-MG`(``````/H`````````WR<```(``0#@E@(``````(<`````````K`\```(`
-M`0"PM`,``````"8)````````\"<```(``0"`"@,``````"H(````````#2@`
-M``(``0`0T@(``````,L`````````*B@```(``0#P]`$``````!``````````
-M/B@```(``0"@S0(``````#0!````````V`\```(``0!PS`(``````"0!````
-M````62@```(``0"P!0(``````.T`````````<2@```(``0!@H`(``````"<`
-M````````C"@```(``0!P^`$``````(X`````````HB@```(``0!P]`$`````
-M`"(`````````MR@```(``0``<P,``````"<`````````U2@```(``0!0=0,`
-M`````%P`````````^B@```(``0!@:P,``````.@`````````'!$```(``0!0
-M70,``````"<`````````$BD```(``0#0SP(``````$$`````````*"D```(`
-M`0!P?@(``````-X`````````2BD```(``0`0:@(``````)`+````````9RD`
-M``(``0!@$P,``````&D&````````@BD```(``0!PO@(``````&<`````````
-MEBD```(``0#P#@(``````!$`````````:1$```(``0"@H0,``````-(`````
-M````MBD```(``0"@8P(```````L$````````V2D```(``0"0F0(``````"H`
-M````````\RD```(``0"`\P$``````#8`````````""H```(``0#0>0,`````
-M`%4!````````."H```(``0`@OP(``````"``````````42H```(``0"@EP(`
-M``````(`````````5!(```(``0#PY@(``````&D`````````:"H```(``0`@
-M.`(``````,`)````````CQ(```(``0#@@@(``````%P!````````@"H```(`
-M`0!@U0(``````!\!````````EBH```(``0#0XP(``````,`!````````K2H`
-M``(``0"@`P(```````,"````````L!(```(``0!`[0(``````,X`````````
-MS"H```(``0``8P(``````($`````````^!(```(``0`@'`,``````!0`````
-M````["H```(``0`PX@(``````)T`````````!"L```(``0"@=0(``````'<"
-M````````)BL```(``0"0Y0(``````'\`````````12L```(``0#0,@,`````
-M`+\"````````8"L```(``0"P=0,``````!<`````````5Q,```(``0!PYP(`
-M`````#,`````````A2L```(``0"@`0(``````'4`````````J2L```(``0#P
-M^@$``````'D`````````PQ,```(``0`0IP(``````*\`````````R"L```(`
-M`0"PC0(``````*``````````Z2L```(``0`0Y@(``````&(`````````"2P`
-M``(``0!P^P$``````%`!````````'RP```(``0"`H0(``````#X`````````
-M.2P```(``0`0N`(``````.H`````````7RP```(``0"@]`$``````$<`````
-M````(10```(``0"06@,``````$(`````````<"P```(``0!@G0(``````"X`
-M````````BRP```(``0!P<@,```````4`````````I2P```(``0#@+P,`````
-M`.\"````````OBP```(``0#P5`(``````,D#````````;10```(``0!0@P,`
-M`````+0`````````URP```(``0!P:@,``````$L`````````Y2P```(``0"`
-M<`,``````*L`````````H10```(``0`0Z`(``````!\``````````BT```(`
-M`0!@]0$```````T`````````&RT```(``0!0;P,``````"(!````````."T`
-M``(``0!PEP(``````"4`````````4BT```(``0#`G0(``````$8`````````
-M;RT```(``0`0Z@(``````-$!````````BRT```(``0`P^@$``````%(`````
-M````H"T```(``0`PF@(``````/8`````````W10```(``0`0`P(``````"$`
-M````````N2T```(``0"@9`,``````&4%````````RRT```(``0"`TP(`````
-M`(4`````````Z"T```(``0"PI@(``````%0`````````!BX```(``0"0-0,`
-M`````.H#````````'RX```(``0!`A`(``````$4!````````(A4```(``0#@
-M\@(``````.$`````````-A4```(``0"PC`(``````/\`````````4Q4```(`
-M`0`@B`,``````'0`````````02X```(``0``H@(``````$D#````````6"X`
-M``(``0!`J0(``````*@`````````=2X```(``0#@\0(``````/$`````````
-MDBX```(``0"@2P(``````+L`````````L2X```(``0`0#P(``````%4+````
-M````G!4```(``0!@B0,``````%``````````SBX```(``0``F`(``````"H`
-M````````X"X```(``0#0\`$``````&X"````````_2X```(``0!@P@(`````
-M`(8`````````&R\```(``0!0TP(``````"D`````````/2\```(``0"PEP(`
-M`````$L`````````6"\```(``0`@9`,``````#<`````````;2\```(``0"@
-MSP(``````",`````````/A8```(``0#PQP(``````.$!````````AR\```(`
-M`0#P*0,``````"<#````````918```(``0`0IP,``````*,`````````I2\`
-M``(``0#@T@(``````&X`````````MB\```(``0``UP(``````(``````````
-MT2\```(``0"`SP(``````!H`````````["\```(``0#`_`$``````#\`````
-M````PQ8```(``0#0\P(``````.$``````````#````(``0`P^`$``````#X`
-M````````#C````(``0!P=`,``````$``````````UQ8```(``0"P8@,`````
-M`%(`````````YQ8```$`"P```0````````0`````````01<```(``0`@O0(`
-M`````!<`````````-C````(``0#0]0$``````#$`````````3S````(``0!0
-M40(``````)\#````````;#````(``0!0?P(``````#,!````````DC````(`
-M`0"@E`(``````!P!````````L3````(``0!0]@$``````-P!````````T#``
-M``(``0#@K`(``````*D`````````]#````(``0#@S@(``````$L`````````
-M#3$```(``0`@:P,``````!@`````````)S$```(``0`0MP(``````/P`````
-M````4#$```(``0`@30(``````%\#````````:3$```(``0`@>`(``````,$$
-M````````@#$```$`"P!``0```````!P`````````DS$```(``0!0J`(`````
-M`/``````````L3$```(``0"`<@,```````8`````````/1@```(``0"`H@,`
-M`````(P`````````RS$```(``0!PF`(``````"H`````````Z#$```(``0"`
-MCP(``````&\$````````!S(```(``0"`'`(``````%T#````````(3(```(`
-M`0!`O0(``````"H!````````-C(```(``0``Z0(```````$!````````3#(`
-M``(``0"0K0(```````T!````````;S(```(``0"P<@,``````!T`````````
-MC#(```(``0!`OP(``````"8`````````HC(```(``0"P$@,``````*@`````
-M````N#(```(``0`0E@,``````-P$````````U3(```(``0``N0(``````,D`
-M````````^3(```(``0#`\P$``````$8`````````"S,```(``0#`!P(`````
-M`!@!````````+#,```(``0`P>P,``````*<!````````13,```(``0"@F`(`
-M`````#$`````````8C,```(``0`0G@(``````"8`````````@#,```(``0"`
-M%P4``````$\`````````CC,```(``0!P^P,``````*X`````````GC,```(`
-M`0#@"00``````+<*````````N#,```(``0"0"@4``````+@'````````R#,`
-M``(``0`P'@0``````)8`````````V#,```$`"P`0`@````````@`````````
-MZ#,```(``0!P^0,```````P`````````_3,```(``0#@%P0``````&4!````
-M````$C0```(``0`P!04``````&,`````````*C0```$`!P"!`P````````$`
-M````````.C0```(``0!0+P0``````(4`````````2C0```(``0"P_00`````
-M`-4`````````6S0```(``0"0_@0``````)$`````````;S0```(``0`P!@4`
-M`````$@"````````A30```(``0#P)P0``````-H`````````FS0```$`"P`8
-M`@````````0`````````J30```(``0!0_00``````%\`````````P30```(`
-M`0"@U@0``````(8`````````T#0```(``0#03`0``````$$`````````XC0`
-M``(``0"`\`,``````%H!````````]30```(``0#0*`0```````,!````````
-M#34```(``0#@X0,``````$L`````````(34```(``0!0&00``````(4!````
-M````-34```(``0"0%@0``````$H`````````0S4```(``0!`^`,``````&4`
-M````````6#4```(``0``_@,``````&``````````:34```(``0``^`,`````
-M`#$`````````@#4```$`"P`@`@````````$`````````E#4```(``0!P&P0`
-M`````&8`````````KS4```(``0"@%`0``````.\!````````PS4```(``0#@
-M&@0``````(\`````````TS4```(``0`PXP,``````"4`````````W#4```(`
-M`0!@X`,``````'<`````````^#4```(``0"`"`4``````)P`````````#C8`
-M``(``0`@!P0``````%H"````````(38```(``0"0^@0``````!8`````````
-M*C8```(``0#0%P4``````$\`````````.#8```(``0"0!00``````(\!````
-M````5#8```(``0#`2P0``````/,`````````7S8```(``0`P4`0```````@!
-M````````=38```(``0`@B@0``````!X!````````AS8```(``0`03P0`````
-M`!D!````````H#8```(``0"@[P0``````$P`````````L38```(``0"0(@0`
-M`````%4`````````O#8```(``0"0\00```````8$````````S38```(``0#0
-M^0,``````'<`````````XC8```(``0!@_`0``````.D`````````\38```(`
-M`0!@Z`,``````/D`````````!#<``!(``0#PWP,``````!,`````````*S<`
-M`!$`"P`D`@````````$`````````0#<``!``````````````````````````
-M5S<``!(``0!P%P4```````P`````````;C<``!``````````````````````
-M````@3<``!(``0#@X@,``````"@`````````DS<``!(``0!P%@4``````#H`
-M````````HC<``!(``0#@\0,``````,<!````````N3<``!(``0"@Y@,`````
-M`'<`````````T#<``!``````````````````````````Z#<``!(``0``%P4`
-M`````%4``````````3@``!(``0!0X`,```````P`````````&#@``!(``0#@
-M[P,``````)@`````````+S@``!``````````````````````````2C@``!(`
-M`0"0Y`,``````%4`````````63@``!``````````````````````````8#@`
-M`!(``0#PY`,``````-D`````````<S@``!(``0!PX@,``````"L`````````
-MBC@``!(``0!0Z@,``````!4`````````GC@``!(``0!P]`,``````(`!````
-M````M#@``!(``0`P_P0``````!$"````````T3@``!$`"P`<`@````````0`
-M````````Z#@``!(``0!0`04``````-@#`````````CD``!``````````````
-M````````````%SD``!(``0!@Z0,``````%4`````````+3D``!(``0"`_`,`
-M`````&H`````````2#D``!(``0#`3`0```````@`````````8CD``!``````
-M````````````````````=#D``!(``0"P%@4``````$D`````````B3D``!$`
-M"P```@````````@`````````F3D``!(``0"0[P0```````D`````````LCD`
-M`!(``0``Y`,``````(,`````````QSD``!$`"P`E`@````````$`````````
-MWSD``!(``0!PG`$``````!H`````````^CD``!(``0``[P0``````&L`````
-M````$3H``!``````````````````````````*#H``!(``0`@YP,``````%<`
-M````````.SH``!$`"P`(`@````````@`````````2CH``!(``0#0Y0,`````
-M`,,`````````8CH``!(``0"`YP,``````-D`````````<SH``!(``0"P2P0`
-M``````<`````````BSH``!``````````````````````````HCH``!(``0!`
-M400``````"<`````````LCH``!$`"P`C`@````````$`````````SCH``!``
-M````````````````````````X3H``!``````````````````````````]#H`
-M`!$`!P"#`P````````$`````````"#L``!(``0`@Z@,``````!``````````
-M+3L``!(``0#@]@0``````&X#````````.SL``!(``0`@C`,``````!H`````
-M````6#L``!(``0`PZ@,``````!$`````````=#L``!``````````````````
-M````````C#L``!(``0"@]00``````%(`````````H3L``!``````````````
-M````````````MSL``!(``0"@!04``````(,`````````TCL``!(``0!0^@0`
-M`````#8`````````YCL``!``````````````````````````]CL``!``````
-M````````````````````#3P``!(``0!@%P4```````P`````````)#P``!``
-M````````````````````````-SP``!(``0`@XP,``````!``````````4SP`
-M`!(``0#@X`,``````,@`````````;CP``!$`!P"``P````````$`````````
-M@3P``!(``0`0X`,```````P`````````F3P``!$`"P`A`@````````$`````
-M````M#P``!(``0!0$@4``````(<"````````U#P``!(``0!P%04```````,`
-M````````[CP``!(``0!``P0``````/D!````````!3T``!(``0"P\P,`````
-M`+,`````````&ST``!(``0!@XP,``````#X`````````-#T``!``````````
-M````````````````2ST``!(``0`@X`,``````"D`````````8ST``!``````
-M````````````````````=ST``!(``0"@X@,``````#T`````````C3T``!(`
-M`0!0%04``````!,`````````JST``!(``0!`[@,``````/,`````````RST`
-M`!``````````````````````````WST``!``````````````````````````
-M_#T``!(``0`0XP,```````L`````````%CX``!``````````````````````
-M````*3X``!(``0"`[@0``````'0`````````0#X``!``````````````````
-M````````6SX``!(``0!`%04```````(`````````;CX``!(``0#P[P0`````
-M`'$`````````@SX``!(``0"P^`,``````+(`````````FSX``!(``0#@%`4`
-M`````%0`````````N3X``!(``0"PX0,``````"P`````````YSX``!$`!P""
-M`P````````$``````````S\``!(``0#P]0,``````/H`````````&C\``!(`
-M`0!P[P0``````!L`````````+S\``!(``0#`Z0,``````%<`````````3C\`
-M`!``````````````````````````93\``!(``0#@[`,``````%8!````````
-M@C\``!(``0"@XP,``````%\`````````ES\``!(``0"P^@0``````/(`````
-M````M#\``!$`"P`B`@````````$`````````SS\``!(``0#@+P0``````'(`
-M`````````%!-7TES<W5E4F5A9$9A:6Q,960`<C<U,%]486=?26YI=`!R-S4P
-M7U5P9&%T95!H>4EN9F\`<V%S7VAA<VA?861D<@!R-S4P7U9E<FEF>4-O;6UA
-M;F1"969O<F5396YD:6YG`'(W-3!?0VAE8VM$979I8V5#:&%N9V4`36%K94%T
-M=$1E=DEN9F\`<C<U,%]$25-#7T-A;F-E;$1I<V-O=F5R`'(W-3!?0F5E<$]N
-M`'(W-3!?4T-325]!5$%?1FEL;$1A=&%&:65L9`!035]7<FET95)E9U-Y;F,`
-M<C<U,%]30U-)7TUA:V5#86-H94-O;6UA;F0`<C<U,%]#3U)%7TES<W5E4TU0
-M4F5Q=65S=`!R-S4P7TU67UIE<F]-=E)E<75E<W0`:3)C05]W<FET95]B>71E
-M<P!R-S4P7U-%4U]);G1E<FYA;%)E<4-A;&QB86-K`'(W-3!?27-S=65?4F5P
-M;W)T1V5N97)A;`!R-S4P7TU67T1U;7!297%U97-T`'(W-3!?359?26YI=&EA
-M;&EZ951A<F=E=$E$5&%B;&4`<V5T7W!M7V9A:6Q?;&5D`'(W-3!?4')E<&%R
-M94%N9%-E;F1#;VUM86YD`$]D:6Y34$E?4F1P=`!R-S4P7TU67TUA<%1O4W!E
-M8VEF:6-487)G971)1`!R-S4P7U-#4TE?051!7T9I;&Q,0D%#9&(Q,`!R-S4P
-M7U-'4$E/7U=R:71E4F5G:7-T97(`<C<U,%]&<F5E4T%405-C<F%T8VA4;U!O
-M;VP`<C<U,%]486=?1V5T3VYE`'(W-3!?3V1I;E-025]);FET`'(W-3!?1G)E
-M94EN=&5R;F%L4F5Q5&]0;V]L`'=A=&EN9U]C86QL8F%C:P!R-S4P7T-O;7!L
-M971E4F5Q=65S=$%N9%-L;W0`<C<U,%]#;W)E7T=E=%-U<'!O<G1E9$-O=6YT
-M<P!$979I8V5?36%K95!R:79A=&5396YD4V5S4F5Q=65S=`!035]3971&86EL
-M3&5D0V%L;&)A8VL`07-S:6=N16QE;65N1&5S8W)I<'1O<DYA;64`1&5V:6-E
-M7TUA:V5397-%;&5M96YT4W1A='5S4F5Q=65S=%1I;65R`'(W-3!?4T-325]!
-M5$%?5F5R:69Y5')A;G-L871I;VX`<C<U,%]?7W)E;F5W7W1I;65R`'(W-3!?
-M1&5V:6-E7TUA:V5397-28W9$:6%G4F5Q=65S=`!R-S4P7U-#4TE?051!7U-T
-M87)T4W1O<%1R86YS;&%T:6]N`'(W-3!?1&5V:6-E7U=R:71E4V5S0V]N=')O
-M;$1I86<`<C<U,%]31U!)3U]335!297%U97-T7U=R:71E`'(W-3!?1G)E941E
-M=FEC951O4&]O;`!R-S4P7U!O<G1?06)O<G1297%U97-T<P!P<F]D=6-T7VED
-M`%!-7U)E861296=3>6YC`'(W-3!?0V]R95]-;V1U;&5396YD4F5Q=65S=`!R
-M-S4P7T-H96-K5&%R9V5T0VAA;F=E`'(W-3!?1G)E95!O<G14;U!O;VP`:3)C
-M0E]W<FET95]B>71E<P!R-S4P7T-O<F5?26YT97)R=7!T4V5R=FEC95)O=71I
-M;F4`<C<U,%]31U!)3U]296%D4F5G:7-T97(`<C<U,%]$25-#7T=E=$YE9V]T
-M:6%T961,:6YK4F%T90!R-S4P7T-A;&-U;&%T95)O=71E26YD97@`<C<U,%]O
-M9&EN7VEO8W1L`'(W-3!?<V5T7V9A:6Q?;&5D`'(W-3!?4U107T1E=FEC95)E
-M<V5T`'(W-3!?1V5T17AP86YD97)&<F]M4&]O;`!R-S4P7U-!5$%?4$U?2&%N
-M9&QE1&5V:6-E56YP;'5G`%1E<W1?4&EN7U-E=`!R-S4P7T-O<F5?26YT97)N
-M86Q396YD4F5Q=65S=`!R-S4P7U1A9U])<T5M<'1Y`'(W-3!?359?36%P5&%R
-M9V5T240`<C<U,%]?7V%D9%]T:6UE<@!R-S4P7VDR8U]R97-E=`!R-S4P7VUV
-M7V1I<V%B;&5?:&)A`'(W-3!?0V]R95]297%4:6UE;W5T`'(W-3!?1FEN9$%S
-M8VEI3G5M8F5R`'(W-3!?;79?<V5T7U-!4T%D9'(`<C<U,%]%>'!A;F1E<E]3
-M35!297%U97-T7U!H>4-O;G1R;VP`<C<U,%]30U-)7TUA:V5-;V1E4&%G94-A
-M8VAI;F<`<C<U,%]#;W)E7U)E<V5T0VUD4VQO=`!R-S4P7U)E;6]V941E=FEC
-M90!R-S4P7T9I;F149W1.;P!R-S4P7U-T;W)E7T-O;F9I9U)O=71E26YF;P!I
-M,F-!7W)E861?8GET97,`86EN9F\`<C<U,%]#;W)E7TUA:V5$979I8V5297-E
-M=%)E<0!R-S4P7T-O<F5?36]D=6QE26YI=&EA;&EZ90!R-S4P7U-#4TE?051!
-M7U)E861#87!A8VET>51R86YS;&%T:6]N0V%L;&)A8VL`<C<U,%]-5E]3971,
-M0D%A;F1396-T;W)#;W5N=`!O9&EN7V-O<F5?=&EM97(`<C<U,%]S971?9F%I
-M;%]L961S`'(W-3!?1G)E94-O<F5#;VYT97AT5&]0;V]L`'(W-3!?8V]R95]H
-M86YD;&5?=&%S:V9I;&5?97)R;W(`<C<U,%]O9&EN7W-E=%]S<&EN7W5P7VUO
-M9&4`<C<U,%]0;W-T36%K95-E<T5L96UE;G13=&%T=7-297%U97-T`'(W-3!?
-M;79?96YA8FQE7WAM=`!R-S4P7TQI<W1?1V5T1FER<W0`<C<U,%]&<F5E4T53
-M4T)4;U!O;VP`<C<U,%]'9710341E=FEC90!R-S4P7T1E=FEC95]-86ME36]D
-M95-E;&5C=%)E<75E<W0`<C<U,%]$:7-C;W9E<GE330!R-S4P7U-!5$%?17)R
-M;W)(86YD;&EN9P!R-S4P7U-!5$%?4&]R=$AA;F1L94EN=&5R<G5P=`!R-S4P
-M7T=E=$-O<F5#;VYT97AT1G)O;5!O;VP`<C<U,%]305-?2&%N9&QE0V]M<&QE
-M=&5D0V]M;6%N9`!R-S4P7T9R965296=I<W1E<E-E=`!R-S4P7U-!5$%?4&]R
-M=$1E=&5C=`!R-S4P7U!O<G1?2&%N9&QE4&QU9VEN`'(W-3!?07-S:6=N16QE
-M;65N=%-L;W1.=6UB97(`<C<U,%]$979I8V5?27-S=653;V9T4F5S970`<C<U
-M,%]?7U!-7V-A;F-E;%]T:6UE<@!R-S4P7U!-7T9R965296=I<W1E<E-E=`!R
-M-S4P7T=E=%-'0G5F9F5R1G)O;5!O;VP`<V5T7V5M7V9A:6Q?;&5D`'(W-3!?
-M359?0U)#`$=E=%-!5$$V-$M38W)A=&-H1G)O;5!O;VP`<C<U,%]2=6YT:6UE
-M27-S=653;V9T4F5S970`<C<U,%]'971$979I8V5&<F]M4&]O;`!R-S4P7U-#
-M4TE?051!7U-Y;F-#86-H951R86YS;&%T:6]N`%1E<W1?4&EN7TEN:71I86QI
-M>F4`<C<U,%]-5E]'971-87!P961)1`!R-S4P7T9R965335!38W)A=&-H5&]0
-M;V]L`'(W-3!?1FEN9$9R965335!#;VYT97AT`$9R9653051!-C1+4V-R871C
-M:%1O4&]O;`!R-S4P7U-!5$%?4')E<&%R94-O;6UA;F1(96%D97(`;79?<&AY
-M7W)E<V5T`'(W-3!?4T%405](86YD;&5$979I8V55;G!L=6<`<C<U,%]035])
-M<W-U95=R:71E4F5G`'(W-3!?4T-325]!5$%?0VAE8VM#;VYD:71I;VX`<C<U
-M,%]035])<W-U95)E861296<`<C<U,%]'971);G1E<FYA;%)E<49R;VU0;V]L
-M`'(W-3!?1G)E945X<&%N9&5R5&]0;V]L`'-E=%]E;5]F86EL7VQE9',`<C<U
-M,%]2=6YT:6UE27-S=65296%D3&]G17AT`'(W-3!?4T-325]!5$%?4F5A9$-A
-M<&%C:71Y5')A;G-L871I;VX`<C<U,%]D=6UP7W5N87-S;V-I871E9%]F:7,`
-M<C<U,%]$979I8V5?36%K95-T87)T4W1O<%5N:71297%U97-T`'(W-3!?0V]M
-M<&QE=&5297%U97-T`'(W-3!?1&5V:6-E7TUA:V5-;V1E4V5N<V5297%U97-T
+M```&`````````!0````T``````````````!&`````````!0```!,````````
+M```````&`````````!0```!D```````````````&`````````!0```!\````
+M```````````&`````````!0```"4```````````````"`````````!0```"L
+M```````````````/`````````!0```#$```````````````:`````````"0`
+M``#<``````````````"(`````````$$.$$$.&(,#A@(````````4````!`$`
+M````````````!@`````````4````'`$`````````````!@`````````4````
+M-`$`````````````!@`````````4````3`$`````````````!@`````````4
+M````9`$`````````````!@`````````4````?`$`````````````!@``````
+M```4````E`$`````````````$P`````````4````K`$`````````````5```
+M```````4````Q`$`````````````5``````````<````W`$`````````````
+M&@````````!$#A```````"0```#\`0````````````#4`````````$$.$$$.
+M&$0.4(,#A@(````D````)`(`````````````Q00```````!!#A!!#AA$#H`!
+M@P.&`@``'````$P"`````````````'``````````1`X@2HP"@P,<````;`(`
+M````````````&P````````!$#A```````!P```",`@`````````````>````
+M`````$$.$(,"````'````*P"`````````````!X`````````00X0@P(````<
+M````S`(`````````````(`````````!$#A```````"0```#L`@``````````
+M``!\`0```````$0.0%Z/`HX#C02,!88&@P<D````%`,`````````````?`$`
+M``````!$#C!8C@*-`XP$A@6#!@``)````#P#`````````````,T`````````
+M1`X@3HP"A@.#!````````#0```!D`P`````````````,`@```````$(.$$(.
+M&$(.($$.*$$.,(,&A@6,!(T#C@(`````````+````)P#`````````````-P"
+M````````1`Z``5Z/`HX#C02,!88&@P<`````````)````,P#````````````
+M`$T!````````1`XP6(X"C0.,!(8%@P8``"0```#T`P````````````#L````
+M`````$$.$$$.&$0.((,#A@(````<````'`0`````````````'P````````!!
+M#A"#`@```#P````\!`````````````#Q`@```````$(.$$(.&$(.($(.*$$.
+M,$$..$0.4(,'A@:,!8T$C@./`@`````````D````?`0`````````````<P``
+M``````!$#B!.C`*&`X,$````````)````*0$`````````````(\#````````
+M1`Y`7H\"C@.-!(P%A@:#!QP```#,!`````````````"5`````````$0.$```
+M````)````.P$`````````````-@`````````1`X@3HP"A@.#!````````"0`
+M```4!0````````````#5`@```````$(.$$$.&$$.((,$A@.,`@`<````/`4`
+M````````````F@````````!$#B!*A@*#`SP```!<!0````````````!Y!```
+M`````$(.$$(.&$(.($(.*$$.,$$..$0.<(,'A@:,!8T$C@./`@`````````4
+M````G`4`````````````\@$````````D````M`4`````````````?08`````
+M``!$#C!8C@*-`XP$A@6#!@``)````-P%`````````````'X"````````00X0
+M00X81`X@@P.&`@```#P````$!@````````````".`@```````$(.$$(.&$(.
+M($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````4``````````$``7@0
+M#`<(D`$````````4````'```````````````+``````````4````-```````
+M`````````@`````````\````3```````````````;@(```````!"#A!"#AA"
+M#B!"#BA!#C!!#CA$#E"#!X8&C`6-!(X#CP(`````````%``````````!``%X
+M$`P'")`!````````%````!P``````````````#8`````````%````#0`````
+M`````````#8`````````%````$P``````````````$8`````````%````&0`
+M`````````````$8`````````%````'P```````````````P`````````%```
+M```````!``%X$`P'")`!````````%````!P``````````````"(`````````
+M%````#0``````````````$<`````````%````$P``````````````!``````
+M````%````&0``````````````%P`````````%````'P```````````````T`
+M````````%````)0``````````````"<`````````%````*P`````````````
+M`#``````````%````,0``````````````#$`````````%````-P`````````
+M`````#,`````````%````/0``````````````-P!````````%`````P!````
+M`````````#X`````````'````"0!`````````````(X`````````1`YP````
+M```<````1`$`````````````.0````````!$#A```````!0```!D`0``````
+M```````H`````````!0```!\`0`````````````A`````````!0```"4`0``
+M```````````@`````````!0``````````0`!>!`,!PB0`0```````!0````<
+M``````````````!'`````````!0````T``````````````!2`````````!0`
+M``!,``````````````!2`````````!0```!D``````````````!Y````````
+M`"0```!\``````````````!0`0```````$0.,%2-`HP#A@2#!0`````<````
+MI```````````````/P````````!$#B!*C`*#`SP```#$``````````````!M
+M`@```````$(.$$(.&$(.($(.*$$.,$$..$0.D`&#!X8&C`6-!(X#CP(`````
+M```D````!`$`````````````2@$```````!!#A!!#AA$#B"#`X8"````%```
+M```````!``%X$`P'")`!````````%````!P``````````````$T`````````
+M%````#0``````````````((`````````%````$P``````````````'4`````
+M````%````&0``````````````'$`````````%````'P``````````````!D`
+M````````'````)0``````````````$4`````````1`X0```````<````M```
+M````````````(0````````!$#A```````!P```#4``````````````!?````
+M`````$0.$```````/````/0```````````````,"````````0@X00@X80@X@
+M0@XH00XP00XX1`Y`@P>&!HP%C02.`X\"`````````!P````T`0``````````
+M``#M`````````$0.$```````)````%0!`````````````!,!````````1`XP
+M5(T"C`.&!(,%`````"0```!\`0`````````````8`0```````$(.$$$.&$$.
+M((,$A@.,`@`D````I`$``````````````P8```````!$#D!>CP*.`XT$C`6&
+M!H,''````,P!`````````````!$`````````1`X0```````\````[`$`````
+M````````50L```````!"#A!"#AA"#B!"#BA!#C!!#CA$#I`!@P>&!HP%C02.
+M`X\"````````+````"P"`````````````!`"````````0@X00@X800X@00XH
+M1`XP@P6&!(P#C0(`)````%P"`````````````%T#````````1`Y07H\"C@.-
+M!(P%A@:#!SP```"$`@````````````#O`P```````$(.$$(.&$(.($(.*$$.
+M,$$..$0.8(,'A@:,!8T$C@./`@`````````D````Q`(`````````````PPD`
+M``````!$#F!>CP*.`XT$C`6&!H,'/````.P"`````````````"4)````````
+M0@X00@X80@X@0@XH00XP00XX1P[@`8,'A@:,!8T$C@./`@```````"0````L
+M`P````````````#X`````````$$.$$$.&$0.((,#A@(````\````5`,`````
+M````````P@D```````!"#A!"#AA"#B!"#BA!#C!!#CA$#F"#!X8&C`6-!(X#
+MCP(`````````/````)0#`````````````+0)````````0@X00@X80@X@0@XH
+M00XP00XX1`Z@`8,'A@:,!8T$C@./`@```````"0```#4`P````````````"[
+M`````````$(.$$$.&$$.((,$A@.,`@`T````_`,`````````````O@``````
+M``!"#A!"#AA"#B!!#BA!#C"#!H8%C`2-`XX"`````````#0````T!```````
+M``````!?`P```````$(.$$(.&$(.($$.*$$.,(,&A@6,!(T#C@(`````````
+M'````&P$`````````````,@`````````1`X0```````\````C`0`````````
+M````GP,```````!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`
+M````````)````,P$`````````````,D#````````1`XP5(T"C`.&!(,%````
+M`#P```#T!`````````````#X`P```````$(.$$(.&$(.($(.*$$.,$$..$0.
+MH`&#!X8&C`6-!(X#CP(````````\````-`4`````````````,08```````!"
+M#A!"#AA"#B!"#BA!#C!!#CA$#F"#!X8&C`6-!(X#CP(`````````'````'0%
+M`````````````($`````````1`X0```````<````E`4`````````````#@``
+M``````!$#A```````!P```"T!0`````````````+!````````$$.$$0.<(,"
+M)````-0%``````````````8!````````1`Y`7H\"C@.-!(P%A@:#!SP```#\
+M!0````````````!#`0```````$(.$$(.&$(.($(.*$$.,$$..$0.4(,'A@:,
+M!8T$C@./`@`````````\````/`8`````````````D`L```````!"#A!"#AA"
+M#B!"#BA!#C!!#CA$#K`!@P>&!HP%C02.`X\"````````+````'P&````````
+M`````'<"````````0@X00@X800X@00XH1`XP@P6&!(P#C0(`/````*P&````
+M`````````,$$````````0@X00@X80@X@0@XH00XP00XX1`ZP`8,'A@:,!8T$
+MC@./`@```````!0``````````0`!>!`,!PB0`0```````!0````<````````
+M``````!O`````````!0````T``````````````!"`````````!0```!,````
+M``````````!<`````````!0```!D``````````````!?`````````!0```!\
+M``````````````#>`````````#0```"4```````````````S`0```````$(.
+M$$(.&$(.($$.*$$.,$0.0(,&A@6,!(T#C@(`````'````,P`````````````
+M`$0`````````00X0@P(````\````[```````````````BP````````!"#A!"
+M#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````)````"P!````
+M`````````&<!````````1`Y07H\"C@.-!(P%A@:#!R0```!4`0``````````
+M``!<`0```````$0.4%Z/`HX#C02,!88&@P<D````?`$`````````````10$`
+M``````!$#D!>CP*.`XT$C`6&!H,''````*0!`````````````'(`````````
+M1`XP2H8"@P,D````Q`$`````````````#P$```````!$#D!>CP*.`XT$C`6&
+M!H,'/````.P!`````````````)\!````````0@X00@X80@X@0@XH00XP00XX
+M1`Y0@P>&!HP%C02.`X\"`````````#P````L`@````````````!/`0``````
+M`$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````D````
+M;`(`````````````"0$```````!$#C!8C@*-`XP$A@6#!@``)````)0"````
+M`````````(,!````````1`X@3HP"A@.#!````````"0```"\`@``````````
+M``#_`````````$0.,%2-`HP#A@2#!0`````\````Y`(`````````````H```
+M``````!"#A!"#AA"#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````
+M/````"0#`````````````"P!````````0@X00@X80@X@0@XH00XP00XX1`Y0
+M@P>&!HP%C02.`X\"`````````#P```!D`P````````````!O!````````$(.
+M$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,!8T$C@./`@`````````4````````
+M``$``7@0#`<(D`$````````4````'```````````````5@`````````4````
+M-```````````````%0`````````4``````````$``7@0#`<(D`$````````4
+M````'```````````````'`$````````D````-```````````````'0$`````
+M``!!#A!!#AB#`X8"````````%````%P``````````````(<`````````%```
+M`'0``````````````"4`````````%````(P```````````````(`````````
+M%````*0``````````````$L`````````%````+P``````````````"H`````
+M````%````-0``````````````#0`````````%````.P``````````````"H`
+M````````%`````0!`````````````#$`````````%````!P!````````````
+M`"H`````````%````#0!`````````````"H`````````%````$P!````````
+M`````"``````````%````&0!`````````````"H`````````%````'P!````
+M`````````"H`````````%````)0!`````````````&$`````````%````*P!
+M`````````````/8`````````%````,0!`````````````-$`````````%```
+M`-P!`````````````$D`````````+````/0!`````````````/H`````````
+M0@X00@X800X@00XH@P6&!(P#C0(`````'````"0"`````````````"X`````
+M````1`X0```````<````1`(`````````````)@````````!$#A```````!P`
+M``!D`@````````````!&`````````$0.$```````'````(0"````````````
+M`"8`````````1`X0```````<````I`(`````````````*@````````!$#A``
+M`````#P```#$`@````````````"(`0```````$(.$$(.&$(.($(.*$$.,$$.
+M.$0.0(,'A@:,!8T$C@./`@`````````<````!`,`````````````+```````
+M``!$#A```````!0````D`P`````````````C`````````!0````\`P``````
+M```````G`````````"0```!4`P````````````#F`````````$(.$$$.&$$.
+M((,$A@.,`@`<````?`,`````````````/@````````!$#B!*A@*#`QP```"<
+M`P`````````````^`````````$0.($J&`H,#)````+P#`````````````$D#
+M````````00X000X81`X@@P.&`@```"0```#D`P````````````!9`0``````
+M`$$.$$$.&$0.((,#A@(````<````#`0`````````````5`````````!$#B!*
+MA@*#`R0````L!`````````````"O`````````$0.($Z,`H8#@P0````````D
+M````5`0`````````````A@````````!$#B!.C`*&`X,$````````)````'P$
+M`````````````/``````````1`Y`7H\"C@.-!(P%A@:#!R0```"D!```````
+M``````"H`````````$0.,%2-`HP#A@2#!0`````D````S`0`````````````
+M?@$```````!!#A!!#AA$#B"#`X8"````)````/0$`````````````&T!````
+M````1`XP6(X"C0.,!(8%@P8``"0````<!0````````````"I`````````$0.
+M($Z,`H8#@P0````````D````1`4`````````````#0$```````!$#C!4C0*,
+M`X8$@P4`````)````&P%`````````````"H!````````1`Y`7H\"C@.-!(P%
+MA@:#!R0```"4!0`````````````3`0```````$0.,%B.`HT#C`2&!8,&```D
+M````O`4`````````````!`$```````!$#C!8C@*-`XP$A@6#!@``)````.0%
+M`````````````%8!````````1`Y`7H\"C@.-!(P%A@:#!SP````,!@``````
+M``````"C`P```````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./
+M`@`````````D````3`8`````````````_`````````!$#D!>CP*.`XT$C`6&
+M!H,')````'0&`````````````.H`````````1`Y`7H\"C@.-!(P%A@:#!R0`
+M``"<!@````````````#)`````````$0.,%B.`HT#C`2&!8,&```D````Q`8`
+M````````````N@````````!$#C!4C0*,`X8$@P4`````)````.P&````````
+M``````P!````````00X000X81`X@@P.&`@```"0````4!P````````````!]
+M`0```````$0.($Z,`H8#@P0````````<````/`<`````````````%P``````
+M``!!#A"#`@```"0```!<!P`````````````J`0```````$0.($Z,`H8#@P0`
+M```````D````A`<`````````````9P````````!!#A!!#AA$#B"#`X8"````
+M'````*P'`````````````#H`````````00X0@P(````<````S`<`````````
+M````(`````````!!#A"#`@```!P```#L!P`````````````F`````````$$.
+M$(,"````)`````P(`````````````/(`````````1`XP5(T"C`.&!(,%````
+M`"0````T"`````````````#J`0```````$0.,%2-`HP#A@2#!0`````D````
+M7`@`````````````A@````````!!#A!!#AA$#B"#`X8"````)````(0(````
+M`````````(4!````````00X000X81`X@@P.&`@```#P```"L"```````````
+M``!G`P```````$(.$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,!8T$C@./`@``
+M```````L````[`@`````````````X0$```````!"#A!"#AA!#B!!#BA$#C"#
+M!88$C`.-`@`\````'`D`````````````CP(```````!"#A!"#AA"#B!"#BA!
+M#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````)````%P)`````````````"0!
+M````````1`XP5(T"C`.&!(,%`````"0```"$"0`````````````T`0``````
+M`$$.$$$.&$0.((,#A@(````D````K`D`````````````2P````````!"#A!!
+M#AA$#B"#`XP"````'````-0)`````````````"8`````````1`X0```````4
+M``````````$``7@0#`<(D`$````````4````'```````````````%0``````
+M```4````-```````````````&@`````````4````3```````````````(P``
+M```````4````9```````````````00`````````4````?```````````````
+M70`````````4````E```````````````D`$````````L````K```````````
+M````RP````````!"#A!"#AA!#B!!#BB#!88$C`.-`@`````L````W```````
+M````````;@````````!"#A!"#AA!#B!!#BA$#C"#!88$C`.-`@`<````#`$`
+M````````````*0````````!!#A"#`@```!P````L`0````````````"%````
+M`````$0.$```````+````$P!`````````````$<!````````0@X00@X800X@
+M00XH1`XP@P6&!(P#C0(`'````'P!`````````````!\!````````1`X0````
+M```<````G`$`````````````@`````````!$#A```````!P```"\`0``````
+M``````"``````````$0.$```````/````-P!`````````````!4)````````
+M0@X00@X80@X@0@XH00XP00XX1`YP@P>&!HP%C02.`X\"`````````"0````<
+M`@````````````"#`0```````$0.($Z,`H8#@P0````````4````1`(`````
+M````````G0`````````4````7`(`````````````^``````````L````=`(`
+M````````````P`$```````!"#A!"#AA!#B!!#BA$#C"#!88$C`.-`@`4````
+M``````$``7@0#`<(D`$````````4````'```````````````?P`````````4
+M````-```````````````8@`````````4````3```````````````8@``````
+M```4````9```````````````:0`````````4````?```````````````!P``
+M```````4````E```````````````,P`````````4````K```````````````
+M40`````````4````Q```````````````'P`````````4````W```````````
+M````+@`````````<````]```````````````DP````````!$#A```````"0`
+M```4`0`````````````!`0```````$0.,%2-`HP#A@2#!0`````\````/`$`
+M````````````T0$```````!"#A!"#AA"#B!"#BA!#C!!#CA$#E"#!X8&C`6-
+M!(X#CP(`````````+````'P!`````````````%\`````````0@X00@X800X@
+M00XH1`XP@P6&!(P#C0(`)````*P!`````````````.X`````````1`Y`7H\"
+MC@.-!(P%A@:#!R0```#4`0````````````#.`````````$0.,%B.`HT#C`2&
+M!8,&```<````_`$`````````````&P$```````!!#A"#`@```"0````<`@``
+M``````````"G`````````$0.,%2-`HP#A@2#!0`````D````1`(`````````
+M````*@$```````!!#A!!#AA$#B"#`X8"````)````&P"`````````````,,`
+M````````1`XP6(X"C0.,!(8%@P8``"0```"4`@````````````#Q````````
+M`$0.,%2-`HP#A@2#!0`````\````O`(`````````````X0````````!"#A!"
+M#AA"#B!"#BA!#C!!#CA$#G"#!X8&C`6-!(X#CP(`````````/````/P"````
+M`````````.$`````````0@X00@X80@X@0@XH00XP00XX1`YP@P>&!HP%C02.
+M`X\"`````````#P````\`P````````````"?`@```````$(.$$(.&$(.($(.
+M*$$.,$$..$0.<(,'A@:,!8T$C@./`@`````````T````?`,`````````````
+MW0(```````!"#A!"#AA"#B!!#BA!#C"#!H8%C`2-`XX"`````````"0```"T
+M`P````````````"G`````````$0.,%B.`HT#C`2&!8,&```\````W`,`````
+M````````/@,```````!"#A!"#AA"#B!"#BA!#C!!#CA$#G"#!X8&C`6-!(X#
+MCP(`````````/````!P$`````````````%D'````````0@X00@X80@X@0@XH
+M00XP00XX1`Z@`8,'A@:,!8T$C@./`@```````#P```!<!`````````````#U
+M`````````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@``````
+M```T````G`0`````````````[0,```````!"#A!"#AA"#B!!#BA!#C!$#F"#
+M!H8%C`2-`XX"`````#P```#4!``````````````J"````````$(.$$(.&$(.
+M($(.*$$.,$$..$0.8(,'A@:,!8T$C@./`@`````````D````%`4`````````
+M````J`````````!!#A!!#AA$#B"#`X8"````)````#P%`````````````&D&
+M````````1`XP6(X"C0.,!(8%@P8``"0```!D!0````````````!#`@``````
+M`$0.($Z,`H8#@P0````````<````C`4`````````````%`````````!$#A``
+M`````"0```"L!0````````````"E"0```````$0.0%Z/`HX#C02,!88&@P<D
+M````U`4`````````````^`,```````!$#C!4C0*,`X8$@P4`````)````/P%
+M`````````````"<#````````1`XP6(X"C0.,!(8%@P8``#P````D!@``````
+M``````"R`@```````$(.$$(.&$(.($(.*$$.,$$..$0.8(,'A@:,!8T$C@./
+M`@`````````\````9`8`````````````[P(```````!"#A!"#AA"#B!"#BA!
+M#C!!#CA'#H`%@P>&!HP%C02.`X\"````````/````*0&`````````````+\"
+M````````0@X00@X80@X@0@XH00XP00XX1P[@!(,'A@:,!8T$C@./`@``````
+M`#P```#D!@````````````#J`P```````$(.$$(.&$(.($(.*$$.,$$..$<.
+M@`6#!X8&C`6-!(X#CP(````````\````)`<`````````````[`,```````!"
+M#A!"#AA"#B!"#BA!#C!!#CA'#O`$@P>&!HP%C02.`X\"````````/````&0'
+M`````````````!@!````````0@X00@X80@X@0@XH00XP00XX1`Y0@P>&!HP%
+MC02.`X\"`````````"P```"D!P`````````````!`@```````$(.$$(.&$$.
+M($$.*$0.,(,%A@2,`XT"`"0```#4!P`````````````[`@```````$0.,%2-
+M`HP#A@2#!0`````\````_`<`````````````KP````````!"#A!"#AA"#B!"
+M#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````)````#P(````````````
+M`',,````````1`Y`7H\"C@.-!(P%A@:#!R0```!D"``````````````C"0``
+M`````$0.0%Z/`HX#C02,!88&@P<4``````````$``7@0#`<(D`$````````4
+M````'```````````````,``````````4````-```````````````)0``````
+M```D````3```````````````=@````````!!#A!!#AB#`X8"````````'```
+M`'0``````````````$L`````````1`X828P"@P,<````E```````````````
+M&@````````!!#A"#`@```!0```"T``````````````!"`````````"0```#,
+M``````````````"5`````````$$.$$$.&(,#A@(````````D````]```````
+M````````A0$```````!"#A!!#AA!#B"#!(8#C`(`'````!P!````````````
+M`#<`````````1`X0```````<````/`$`````````````)P````````!$#A``
+M`````!P```!<`0`````````````_`````````$0.$```````)````'P!````
+M`````````-4`````````1`XP6(X"C0.,!(8%@P8``"0```"D`0``````````
+M``!/`````````$(.$$$.&$$.((,$A@.,`@`D````S`$`````````````?@``
+M``````!$#C!4C0*,`X8$@P4`````)````/0!`````````````,D`````````
+M1`XP5(T"C`.&!(,%`````#P````<`@`````````````W`@```````$(.$$(.
+M&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````<````7`(`````
+M````````4@````````!$#B!*C`*#`QP```!\`@````````````!2````````
+M`$0.($J,`H,#-````)P"`````````````*H`````````0@X00@X80@X@00XH
+M00XP@P:&!8P$C0..`@`````````<````U`(`````````````4@````````!$
+M#B!*C`*#`QP```#T`@`````````````W`````````$0.$```````'````!0#
+M`````````````#\`````````1`X0```````\````-`,`````````````904`
+M``````!"#A!"#AA"#B!"#BA!#C!!#CA$#I`!@P>&!HP%C02.`X\"````````
+M'````'0#`````````````%,`````````1`X0```````<````E`,`````````
+M````2P````````!$#A```````!P```"T`P````````````!2`````````$0.
+M($J,`H,#%``````````!``%X$`P'")`!````````%````!P`````````````
+M`!@`````````%````#0``````````````!(`````````'````$P`````````
+M`````.@`````````00X0@P(````4````;```````````````(``````````4
+M````A```````````````(@`````````<````G```````````````@@``````
+M``!!#A"#`@```#P```"\```````````````O`0```````$(.$$(.&$(.($(.
+M*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````D````_```````````````
+MXP````````!$#D!>CP*.`XT$C`6&!H,'-````"0!`````````````"(!````
+M````0@X00@X80@X@00XH00XP@P:&!8P$C0..`@`````````D````7`$`````
+M````````JP````````!$#C!4C0*,`X8$@P4`````%``````````!``%X$`P'
+M")`!````````%````!P``````````````#L!````````%````#0`````````
+M``````4`````````%````$P```````````````8`````````%````&0`````
+M`````````!P`````````%````'P``````````````!T`````````%````)0`
+M`````````````"L`````````%````*P``````````````"<`````````)```
+M`,0``````````````#,!````````1`XP6(X"C0.,!(8%@P8``!0```#L````
+M``````````!``````````"0````$`0````````````":`````````$0.*%.-
+M`HP#A@2#!0`````4````+`$`````````````7``````````4````1`$`````
+M````````%P`````````<````7`$`````````````\0,```````!$#A``````
+M`!P```!\`0````````````!5`0```````$$.$$0.,(,"'````)P!````````
+M`````*<!````````00X0@P(````4``````````$``7@0#`<(D`$````````4
+M````'```````````````1``````````4````-```````````````%```````
+M```D````3```````````````90````````!"#A!!#AA!#B"#!(8#C`(`)```
+M`'0```````````````D#````````00X000X81`XP@P.&`@```"0```"<````
+M``````````"F`````````$0.,$^,`H8#@P0````````D````Q```````````
+M````=P````````!!#A!!#AA$#C"#`X8"````/````.P``````````````,0`
+M````````0@X00@X80@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"````````
+M`!P````L`0````````````!]`````````$$.$$0.((,"'````$P!````````
+M`````+0`````````1`XP2H8"@P,D````;`$`````````````>0,```````!$
+M#F!>CP*.`XT$C`6&!H,'%``````````!``%X$`P'")`!````````%````!P`
+M``````````````8`````````%````#0``````````````$8`````````%```
+M`$P```````````````8`````````%````&0```````````````8`````````
+M%````'P```````````````8`````````%````)0``````````````'0`````
+M````%````*P``````````````)D`````````%````,0```````````````(`
+M````````%````-P```````````````@`````````%````/0`````````````
+M`%``````````%`````P!``````````````8`````````%````"0!````````
+M`````/0`````````%````#P!`````````````#(`````````'````%0!````
+M`````````#P`````````1`X828P"@P,4````=`$`````````````$P``````
+M```4````C`$`````````````7``````````4````I`$`````````````7```
+M```````<````O`$`````````````&@````````!$#A```````"0```#<`0``
+M``````````#4`````````$$.$$$.&$0.4(,#A@(````\````!`(`````````
+M````.08```````!"#A!"#AA"#B!"#BA!#C!!#CA$#J`!@P>&!HP%C02.`X\"
+M````````'````$0"`````````````'``````````1`X@2HP"@P,<````9`(`
+M````````````&P````````!$#A```````!P```"$`@`````````````>````
+M`````$$.$(,"````'````*0"`````````````!X`````````00X0@P(````<
+M````Q`(`````````````(`````````!$#A```````"0```#D`@``````````
+M``"!`0```````$0.0%Z/`HX#C02,!88&@P<D````#`,`````````````W`0`
+M``````!$#E!>CP*.`XT$C`6&!H,')````#0#`````````````#4$````````
+M1`YP7H\"C@.-!(P%A@:#!R0```!<`P````````````#(`````````$0.($Z,
+M`H8#@P0````````D````A`,`````````````DP$```````!$#C!8C@*-`XP$
+MA@6#!@``'````*P#`````````````-(`````````00X0@P(````D````S`,`
+M````````````C`````````!!#A!!#AA$#B"#`X8"````)````/0#````````
+M`````.P`````````00X000X81`X@@P.&`@```!P````<!``````````````?
+M`````````$$.$(,"````/````#P$`````````````/$"````````0@X00@X8
+M0@X@0@XH00XP00XX1`Y0@P>&!HP%C02.`X\"`````````"0```!\!```````
+M``````"C`````````$0.($Z,`H8#@P0````````D````I`0`````````````
+MF@,```````!$#E!>CP*.`XT$C`6&!H,')````,P$`````````````'D!````
+M````1`XP5(T"C`.&!(,%`````"0```#T!``````````````Q`0```````$0.
+M8$^,`H8#@P0````````\````'`4`````````````Z04```````!"#A!"#AA"
+M#B!"#BA!#C!!#CA$#D"#!X8&C`6-!(X#CP(`````````'````%P%````````
+M`````)H`````````1`X@2H8"@P,L````?`4`````````````)@D```````!"
+M#A!!#AA!#B!$#E"#!(8#C`(````````\````K`4`````````````>00`````
+M``!"#A!"#AA"#B!"#BA!#C!!#CA$#G"#!X8&C`6-!(X#CP(`````````)```
+M`.P%`````````````%0"````````0@X000X800X@@P2&`XP"`#0````4!@``
+M```````````)!````````$(.$$(.&$(.($$.*$$.,(,&A@6,!(T#C@(`````
+M````+````$P&`````````````"`$````````0@X00@X800X@00XH@P6&!(P#
+MC0(`````)````'P&`````````````/4#````````0@X000X800X@@P2&`XP"
+M`"0```"D!@````````````!@`@```````$(.$$$.&$$.((,$A@.,`@`D````
+MS`8`````````````T@8```````!$#C!8C@*-`XP$A@6#!@``)````/0&````
+M`````````(X"````````00X000X81`X@@P.&`@```#P````<!P``````````
+M```\`P```````$(.$$(.&$(.($(.*$$.,$$..$0.0(,'A@:,!8T$C@./`@``
+M```````4``````````$``7@0#`<(D`$````````4````'```````````````
+M$P`````````4````-```````````````#``````````4````3```````````
+M````*0`````````4````9```````````````#``````````D````?```````
+M````````=P````````!!#A"#`DH.D`(`````````)````*0`````````````
+M`,@`````````0@X000X8A@.,`D0.((,$`!0```#,```````````````L````
+M`````"0```#D``````````````!+`````````$(.$$$.&(8#C`)##B"#!``<
+M````#`$`````````````>0````````!!#A"#`D<.0!0````L`0``````````
+M```K`````````!0```!$`0`````````````]`````````!P```!<`0``````
+M```````H`````````$$.$(,"````%````'P!``````````````L`````````
+M%````)0!`````````````!``````````%````*P!`````````````"4`````
+M````%````,0!`````````````#X`````````%````-P!`````````````%\`
+M````````)````/0!`````````````(,`````````0@X0C`)$#AB&`T8.((,$
+M`"0````<`@````````````!5`````````$(.$(P"1@X800X@@P2&`P`T````
+M1`(`````````````V0````````!"#A!"#AA"#B!!#BB&!8P$C0..`D0.,(,&
+M`````````"0```!\`@````````````##`````````$$.$(8"1`X8@P-'#B``
+M```<````I`(`````````````AP````````!!#A"#`@```"0```#$`@``````
+M``````!7`````````$$.$(8"1`X81`X@@P,````D````[`(`````````````
+MV0````````!"#A",`D0.&$$.((,$A@,`+````!0#`````````````/D`````
+M````0@X0C0)%#AA!#B"&!(P#1`XH1`XP@P4`'````$0#`````````````%4`
+M````````00X0@P(````D````9`,`````````````5P````````!$#B!)A@.#
+M!$>,`@``````%````(P#`````````````!``````````%````*0#````````
+M`````!$`````````%````+P#`````````````!4`````````-````-0#````
+M`````````&\"````````0@X00@X8C0..`D4.((P$10XH00XP@P:&!0``````
+M```\````#`0`````````````5@$```````!"#A!"#AA"#B!"#BA!#C!!#CB#
+M!X8&C`6-!(X#CP)*#L`!````````+````$P$`````````````/,`````````
+M0@X0C0)%#AB,`T0.((8$1`XH1`XP@P4`)````'P$`````````````)8`````
+M````1`X@2HP"A@-'@P0``````"P```"D!`````````````"8`````````$(.
+M$$(.&$$.((8$C`.-`D0.*$0.,(,%`#P```#4!`````````````!:`0``````
+M`$(.$(\"10X8C@-%#B"-!$4.*$$.,(8&C`5$#CA$#D"#!P`````````T````
+M%`4`````````````QP$```````!"#A!"#AB-`XX"10X@C`1$#BA!#C!$#K`!
+M@P:&!0```"0```!,!0````````````"S`````````$(.$(P"1`X8A@-(#B"#
+M!``D````=`4`````````````@`$```````!$#C!1C`2&!5..`HT#@P8`)```
+M`)P%`````````````/H`````````0@X02`X8A@.,`D<.((,$`!0`````````
+M`0`!>!`,!PB0`0```````!0````<```````````````^`````````!0````T
+M```````````````2`````````!0```!,```````````````K`````````!0`
+M``!D```````````````X`````````!0```!\```````````````\````````
+M`!0```"4```````````````Q`````````!0```"L``````````````!E````
+M`````!0```#$``````````````"R`````````!0```#<```````````````,
+M`````````"0```#T``````````````!(`````````$$.$(8"1`X81`X@@P,`
+M```<````'`$`````````````=P````````!!#A"#`@```!P````\`0``````
+M``````"[`````````$$.$(,"````'````%P!`````````````%L`````````
+M1`X@2H8"@P,D````?`$`````````````K@````````!"#A",`D0.&$$.((,$
+MA@,`%````*0!``````````````4`````````'````+P!`````````````$X`
+M````````1`X@2H8"@P,D````W`$`````````````:@````````!!#A!!#AA$
+M#B"#`X8"````'`````0"`````````````'@`````````1`X@2H8"@P,4````
+M)`(`````````````-P`````````<````/`(`````````````2P````````!!
+M#A"#`@```"0```!<`@````````````!@`````````$$.$(8"1`X8@P-.#B``
+M```L````A`(`````````````.@,```````!$#D!*A@:#!TR/`HX#38T$C`4`
+M```````D````M`(`````````````9P````````!"#A!(#AB&`XP"1`X@@P0`
+M)````-P"`````````````.$`````````00X000X8@P.&`D<.(````!P````$
+M`P````````````!``````````$0.($J,`H,#)````"0#`````````````/P!
+M````````1`Y@38P$A@55C@*#!HT#`!P```!,`P````````````!(````````
+M`$0.($V,`H,#)````&P#`````````````(\!````````1PZ@!%>&`H,#````
+M`````"0```"4`P````````````!:`@```````$$.$$4.&(,#A@)*#J`$```<
+M````O`,`````````````5@````````!!#A"#`@```"P```#<`P``````````
+M``"W"@```````$<.T`97C`6&!F>/`HX#C02#!P```````#P````,!```````
+M``````#_`0```````$(.$(\"2@X80@X@C02.`T4.*$$.,$$..$0.L`&#!X8&
+MC`4````````<````3`0`````````````2@````````!!#A"#`@```"0```!L
+M!`````````````#R`````````$0.($R,`H8#1X,$```````L````E`0`````
+M````````90$```````!"#A!"#AB,`XT"1`X@00XH1`XP@P6&!``L````Q`0`
+M````````````A0$```````!"#A"-`D<.&(P#1`X@00XH1`XP@P6&!``<````
+M]`0`````````````CP````````!!#A"#`@```"0````4!0````````````!F
+M`````````$$.$(8"1`X81`X@@P,````T````/`4`````````````10(`````
+M``!"#A!(#AA"#B!!#BA!#C"#!H8%C`2-`XX"`````````"0```!T!0``````
+M``````"6`````````$(.$(P"2PX800X@@P2&`P`D````G`4`````````````
+M/@$```````!$#B!)@P2&`TB,`@``````)````,0%`````````````/0`````
+M````1`X@288#@P1(C`(``````"0```#L!0````````````!X`0```````$0.
+M,$J,!(8%48,&C@*-`P`4``````````$``7@0#`<(D`$````````4````'```
+M````````````50`````````4````-```````````````'@`````````4````
+M3```````````````0@`````````\````9```````````````M`````````!"
+M#A"/`D4.&(X#10X@0@XH00XP00XX1P[0`8,'A@:,!8T$````````/````*0`
+M``````````````@!````````0@X00@X8C@./`D4.($(.*(P%C01$#C"&!D0.
+M.$<.X`&#!P```````"P```#D``````````````!<`````````$(.$$(.&$$.
+M((8$C`.-`D,.*$<.L`&#!3P````4`0````````````!7`0```````$(.$$(.
+M&$(.($(.*$$.,(8&C`6-!(X#CP)$#CA'#I`"@P<````````4````5`$`````
+M````````4P`````````4````;`$`````````````F@`````````4````A`$`
+M````````````V@`````````4````G`$``````````````P$````````4````
+MM`$`````````````20`````````4````S`$`````````````>0`````````\
+M````Y`$`````````````CP0```````!"#A"/`D4.&(X#10X@C01%#BA!#C!!
+M#CA$#D"#!X8&C`4`````````%````"0"``````````````(`````````%```
+M`#P"`````````````(4`````````'````%0"`````````````'(`````````
+M1`Y````````D````=`(`````````````.@````````!!#A!!#AA$#C"#`X8"
+M````%````)P"`````````````-L`````````)````+0"`````````````($`
+M````````0@X0C`)$#AB&`T0.((,$`"P```#<`@````````````!K````````
+M`$(.$(T"10X8C`-$#B!!#BB#!88$`````!0````,`P````````````!S````
+M`````!0````D`P`````````````6`````````!0````\`P`````````````;
+M`````````!0```!4`P`````````````:`````````!0```!L`P``````````
+M```6`````````!0```"$`P`````````````5`````````!0```"<`P``````
+M```````5`````````!0```"T`P`````````````5`````````!0```#,`P``
+M```````````5`````````!0```#D`P`````````````5`````````!0```#\
+M`P`````````````5`````````!0````4!``````````````8`````````!0`
+M```L!``````````````8`````````!0```!$!``````````````8````````
+M`!0```!<!``````````````8`````````!0```!T!``````````````5````
+M`````!0```",!``````````````H`````````!0```"D!``````````````H
+M`````````!P```"\!``````````````Q`````````$$.$(,"````'````-P$
+M`````````````#$`````````00X0@P(````<````_`0`````````````,0``
+M``````!!#A"#`@```!P````<!0````````````!D`````````$$.$(,"````
+M'````#P%`````````````&(`````````1`X828,#A@(D````7`4`````````
+M````A0````````!$#B!)@P2&`TB,`@``````)````(0%`````````````,T`
+M````````1`XP28,&A@52C@*-`XP$`"0```"L!0````````````"B````````
+M`$0.*$F&!(,%38T"C`,````4````U`4`````````````%0`````````4````
+M[`4`````````````.P`````````D````!`8`````````````H@````````!$
+M#BA)A@2#!4V-`HP#````)````"P&`````````````+4`````````1`XH288$
+M@P5-C0*,`P```"0```!4!@````````````#'`````````$0.*$F&!(,%38T"
+MC`,````D````?`8`````````````VP````````!$#BA)A@2#!4V-`HP#````
+M%````*0&`````````````!@`````````'````+P&`````````````&4`````
+M````1`X8288"@P,<````W`8`````````````90````````!$#AA)A@*#`QP`
+M``#\!@````````````!E`````````$0.&$F&`H,#'````!P'````````````
+M`%T`````````1`X8288"@P,<````/`<`````````````70````````!$#AA)
+MA@*#`QP```!<!P````````````!=`````````$0.&$F&`H,#'````'P'````
+M`````````(8`````````1`X8288"@P,<````G`<`````````````90``````
+M``!$#AA)A@*#`QP```"\!P````````````!E`````````$0.&$F&`H,#)```
+M`-P'`````````````+H`````````1`X@288#@P1(C`(``````!P````$"```
+M``````````!E`````````$0.&$F&`H,#'````"0(`````````````&H`````
+M````1`X8288"@P,<````1`@`````````````9P````````!$#AA)A@*#`QP`
+M``!D"`````````````!I`````````$0.&$F&`H,#%````(0(````````````
+M`!P`````````%````)P(`````````````!@`````````%````+0(````````
+M`````!8`````````'````,P(`````````````+(`````````1`X8288"@P,<
+M````[`@`````````````L@````````!$#AA)A@*#`QP````,"0``````````
+M``!=`````````$0.&$F&`H,#)````"P)`````````````+``````````1`XP
+M28,&A@52C@*-`XP$`"0```!4"0````````````"P`````````$0.,$F#!H8%
+M4HX"C0.,!``<````?`D`````````````5@````````!$#AA)A@*#`Q0```"<
+M"0`````````````H`````````!P```"T"0````````````!9`````````$$.
+M$(,"````'````-0)`````````````*8`````````1`X83H8"@P,4````]`D`
+M````````````/@`````````<````#`H`````````````LP````````!$#AA)
+MA@*#`QP````L"@````````````"2`````````$0.&$F&`H,#)````$P*````
+M``````````X!````````0@X0C`)*#AB&`T<.((,$`!0```!T"@``````````
+M``!N`````````!P```","@````````````!:`````````$$.$(,"````%```
+M`*P*``````````````<`````````'````,0*`````````````/,`````````
+M1`Y````````4````Y`H`````````````"``````````4````_`H`````````
+M````00`````````<````%`L`````````````<`````````!$#B!*C`*#`R0`
+M```T"P````````````#*`````````$0.,$F,!(,&38X"C0-(A@4D````7`L`
+M````````````JP````````!$#B!)A@.#!$B,`@``````+````(0+````````
+M`````!D!````````1`Y`18\"3(P%6H,'C@.-!(8&````````+````+0+````
+M``````````@!````````1`Y`18\"3(P%6H,'C@.-!(8&````````'````.0+
+M`````````````"<`````````10X0@P(````4````!`P`````````````?0``
+M```````4````'`P`````````````,0`````````4````-`P`````````````
+M,0`````````4````3`P`````````````,0`````````4````9`P`````````
+M````,0`````````4````?`P`````````````,0`````````4````E`P`````
+M````````,0`````````4````K`P`````````````,0`````````4````Q`P`
+M````````````,0`````````4````W`P`````````````,0`````````4````
+M]`P`````````````,0`````````4````#`T`````````````,0`````````4
+M````)`T`````````````,0`````````4````/`T`````````````,0``````
+M```4````5`T`````````````,0`````````4````;`T`````````````,0``
+M```````4````A`T`````````````,0`````````4````G`T`````````````
+M,0`````````4````M`T`````````````,0`````````4````S`T`````````
+M````,0`````````4````Y`T`````````````,0`````````4````_`T`````
+M````````)``````````4````%`X`````````````*``````````<````+`X`
+M````````````J`````````!!#A"#`@```!0```!,#@`````````````X````
+M`````"0```!D#@````````````#+`````````$0.($Z,`H8#@P0````````<
+M````C`X`````````````10````````!$#B!*@P.,`BP```"L#@``````````
+M```$`0```````$(.$(P"1`X800X@1P[@`8,$A@,``````!P```#<#@``````
+M``````!-`````````$0.($J&`H,#+````/P.`````````````)P!````````
+M1`Y`2H8&@P=7CP*.`XT$C`4`````````/````"P/`````````````(8!````
+M````0@X00@X8C@./`D4.($(.*$$.,$$..$0.0(,'A@:,!8T$`````````#0`
+M``!L#P````````````#9`````````$(.$$(.&$(.((P$C0..`D0.*$$.,(,&
+MA@4`````````'````*0/`````````````(P`````````00X0@P(````L````
+MQ`\`````````````&@(```````!'#M`!4(,'A@9CCP*.`XT$C`4````````4
+M````]`\`````````````+P`````````\````#!``````````````T```````
+M``!"#A!%#AA"#B"-!(X#CP)%#BA!#C!!#CA'#N`!@P>&!HP%````````%```
+M`$P0`````````````*D`````````)````&00`````````````,``````````
+M1`XP3(8$@P5-C0*,`P```"0```",$`````````````!Y`````````$$.$$,.
+M&(,#A@)*#J`!```D````M!``````````````N`````````!$#C!*C`.&!$V-
+M`H,%````)````-P0`````````````*P`````````1`XP2HX#C`51CP*-!(,&
+M`!P````$$0````````````"6`````````$$.$(,"````)````"01````````
+M`````.8`````````00X000X8@P.&`@```````#P```!,$0````````````#8
+M`````````$(.$$0.&$(.($(.*(P%C02.`X\"1`XP00XX1P[``8,'A@8`````
+M```\````C!$`````````````\P````````!"#A!$#AA"#B!"#BB,!8T$C@./
+M`D0.,$$..$<.P`&#!X8&````````/````,P1`````````````.X`````````
+M0@X01`X80@X@0@XHC`6-!(X#CP)$#C!!#CA'#L`!@P>&!@```````#P````,
+M$@````````````#N`````````$(.$$0.&$(.($(.*(P%C02.`X\"1`XP00XX
+M1P[``8,'A@8````````\````3!(`````````````[@````````!"#A!$#AA"
+M#B!"#BB,!8T$C@./`D0.,$$..$<.P`&#!X8&````````+````(P2````````
+M`````)X`````````0@X01`X800X@A@2,`XT"1`XH1PZP`8,%'````+P2````
+M`````````$,`````````00X0@P(````D````W!(`````````````K0``````
+M``!!#A"&`D8.&$<.H`&#`P``'`````03`````````````$T`````````1`X@
+M2HP"@P,D````)!,`````````````$P$```````!!#A!(#AB#`X8"1PX@````
+M%````$P3`````````````"L`````````-````&03`````````````,0`````
+M````0@X00@X80@X@00XHA@6,!(T#C@)$#C!$#G"#!@`````D````G!,`````
+M````````GP$```````!$#C!)C`2#!E*.`HT#A@4`%````,03````````````
+M``\`````````'````-P3`````````````!@`````````1`X0```````<````
+M_!,`````````````&`````````!$#A```````!P````<%``````````````C
+M`````````$0.$```````+````#P4`````````````',`````````0@X0C0)%
+M#AA!#B!!#BA$#C"#!88$C`,`'````&P4`````````````!L`````````1`X0
+M```````<````C!0`````````````B0````````!$#B!*@P.&`AP```"L%```
+M``````````!'`````````$0.($J#`XP"'````,P4`````````````!L`````
+M````1`X0```````<````[!0`````````````&P````````!$#A```````!P`
+M```,%0````````````!2`````````$$.$(,"````)````"P5````````````
+M`#L`````````00X000X81`X@@P.&`@```"0```!4%0`````````````[````
+M`````$$.$$$.&$0.((,#A@(````D````?!4`````````````-P````````!!
+M#A!!#AA$#B"#`X8"````)````*05`````````````#<`````````00X000X8
+M1`X@@P.&`@```"0```#,%0`````````````W`````````$$.$$$.&$0.((,#
+MA@(````D````]!4`````````````-0````````!!#A!!#AA$#B"#`X8"````
+M)````!P6`````````````&0`````````00X0A@)+#AA$#B"#`P```#P```!$
+M%@`````````````V`0```````$(.$$(.&$(.($(.*$$.,(8&C`6-!(X#CP)$
+M#CA'#M`!@P<````````D````A!8`````````````-P,```````!$#C!*C`.#
+M!4V&!(T"````'````*P6`````````````!L`````````00X0@P(````<````
+MS!8`````````````&P````````!!#A"#`@```"0```#L%@````````````!-
+M`0```````$0.,%2,`XT"A@2#!0`````D````%!<`````````````9```````
+M``!!#A!!#AB#`X8"1PYP````)````#P7`````````````,H!````````0@X0
+MC`)+#AA!#B"#!(8#`#P```!D%P`````````````B`P```````$(.$$(.&$(.
+M((T$C@./`D4.*$$.,(8&C`5$#CA'#N`$@P<````````L````I!<`````````
+M````B@$```````!"#A!$#AB,`XT"1`X@00XH1PZP`8,%A@0L````U!<`````
+M````````3@$```````!"#A"-`D<.&$$.($$.*$<.L`&#!88$C`,D````!!@`
+M````````````A@````````!$#B!)@P2,`TB-`@``````'````"P8````````
+M`````#D`````````00X0@P(````<````3!@`````````````-@````````!!
+M#A"#`@```!P```!L&`````````````#=`@```````$$.$(,"````%````(P8
+M`````````````)`!````````%````*08`````````````"D`````````'```
+M`+P8`````````````!X!````````1`X@2H,#A@(L````W!@`````````````
+MC`@```````!"#A!"#AB,`XT"1`X@00XH1`XP@P6&!``D````#!D`````````
+M````SP(```````!!#A"&`D0.&$0.((,#````-````#09`````````````-8`
+M````````0@X00@X80@X@C`2-`XX"1`XH00XP@P:&!0`````````D````;!D`
+M````````````/@,```````!$#G!*A@2#!4V-`HP#````)````)09````````
+M`````.``````````1`Y`2H8$@P5-C0*,`P```!P```"\&0````````````!M
+M`````````$$.$(,"````/````-P9`````````````*\!````````0@X00@X8
+MC@./`D4.($(.*(P%C01$#C!!#CA'#M`$@P>&!@```````"0````<&@``````
+M``````"%`0```````$0.,$J&!(,%38T"C`,````\````1!H`````````````
+M2`\```````!"#A!"#AA"#B!"#BA!#C"&!HP%C02.`X\"1`XX1P[``8,'````
+M````)````(0:`````````````&P`````````00X000X8@P.&`D<.(````"0`
+M``"L&@`````````````-`0```````$$.$(8"1`X81P[``8,#```D````U!H`
+M````````````30````````!!#A"&`D8.&$0.((,#````+````/P:````````
+M`````+@`````````0@X00@X800X@00XH1`XP@P6&!(P#C0(`+````"P;````
+M`````````$L"````````0@X01PX8C`.-`D0.((8$1`XH1P[P`8,%+````%P;
+M`````````````!`#````````1`Y`2HT$C`57CP*.`X8&@P<`````````)```
+M`(P;`````````````!0"````````1P[P`56,`X,%4XT"A@0``"P```"T&P``
+M``````````"6`````````$(.$(T"10X800X@00XH1`XP@P6&!(P#`!P```#D
+M&P````````````!4`````````$0.($V,`H,#'`````0<`````````````&``
+M````````00X0@P(````<````)!P`````````````$`(```````!!#A"#`@``
+M`"P```!$'`````````````#X!@```````$0.8$B,!5^/`HT$C@.&!H,'````
+M`````"P```!T'``````````````/!````````$0.8$V&!H,'6HX#C02,!8\"
+M`````````"0```"D'`````````````!/`````````$0.($F,`X,$2(T"````
+M```D````S!P`````````````=P````````!$#B!)A@.#!$B,`@``````)```
+M`/0<`````````````'<`````````1`X@288#@P1(C`(``````"0````<'0``
+M``````````!/`````````$0.($F,`X,$2(T"```````D````1!T`````````
+M````>0````````!$#B!)A@.#!$B,`@``````)````&P=`````````````'D`
+M````````1`X@288#@P1(C`(``````"P```"4'0````````````"&````````
+M`$(.$(T"10X800X@A@2,`T0.*$0.,(,%`"0```#$'0````````````!9````
+M`````$$.$$$.&(,#A@)'#B`````D````[!T`````````````Y0````````!!
+M#A!!#AB#`X8"1PX@````)````!0>`````````````/,`````````00X0A@)$
+M#AA$#B"#`P```!P````\'@````````````"2`````````$0.($J&`H,#)```
+M`%P>`````````````,D`````````1`X@28P"@P1(A@,``````!P```"$'@``
+M```````````M`````````$0.$```````-````*0>`````````````-D`````
+M````0@X00@X80@X@00XH00XP@P:&!8P$C0..`@`````````\````W!X`````
+M````````20$```````!"#A!$#AA"#B!"#BB,!8T$C@./`D0.,$$..$0.0(,'
+MA@8`````````+````!P?`````````````,(!````````0@X000X800X@@P2&
+M`XP"1PZ``0``````-````$P?`````````````!H!````````0@X01`X80@X@
+M00XH00XP@P:&!8P$C0..`@`````````<````A!\`````````````.@``````
+M``!!#A"#`@```#0```"D'P`````````````S`0```````$(.$$(.&(T#C@)%
+M#B!!#BA!#C!$#K`!@P:&!8P$````%````-P?``````````````4`````````
+M)````/0?`````````````"4!````````1`XP2HT"C`--A@2#!0```"0````<
+M(`````````````!W`````````$0.($F-`H,$2(P#```````D````1"``````
+M````````A@````````!"#A!(#AB&`XP"1`X@@P0`+````&P@````````````
+M`(L`````````0@X00@X800X@A@2,`XT"1`XH1P[P`8,%)````)P@````````
+M`````(T`````````00X0A@)&#AA$#B"#`P```#P```#$(`````````````#P
+M`@```````$(.$$(.&$(.((T$C@./`D4.*$$.,$$..$0.0(,'A@:,!0``````
+M```T````!"$`````````````T@$```````!"#A!"#AB-`XX"10X@00XH00XP
+M@P:&!8P$`````````#0````\(0````````````#,`0```````$(.$$(.&(T#
+MC@)%#B!!#BA!#C"#!H8%C`0`````````+````'0A`````````````&X#````
+M````0@X0C0)%#AA!#B!!#BA$#G"#!88$C`,`)````*0A`````````````/<`
+M````````0@X000X8A@.,`D0.((,$`"P```#,(0````````````"F````````
+M`$(.$$(.&$$.($$.*(,%A@2,`XT"2@[P`20```#\(0````````````!A`@``
+M`````$(.$$$.&(8#C`)$#B"#!``D````)"(`````````````&P0```````!$
+M#C!%A@12C0*,`X,%````%````$PB`````````````#L`````````'````&0B
+M`````````````$(`````````00X0@P(````D````A"(`````````````7`$`
+M``````!$#D!>CP*.`XT$C`6&!H,')````*PB``````````````0!````````
+M1`XP2H,%C`1-C@*-`P```!0``````````0`!>!`,!PB0`0```````!0````<
+M``````````````#6`````````!P````T``````````````!T`````````$0.
+M&$F&`H,#%````%0``````````````&L`````````%````&P`````````````
+M`!L`````````%````(0```````````````D`````````'````)P`````````
+M`````$P`````````00X0@P(````D````O```````````````<0````````!$
+M#B!%@P-(A@(`````````+````.0``````````````!<!````````0@X00@X8
+M00X@00XH@P6&!(P#C0))#C``+````!0!``````````````8$````````0@X0
+M0@X800X@00XH@P6&!(P#C0)'#C``'````$0!`````````````%(`````````
+M00X0@P(````D````9`$`````````````WP````````!!#A!$#AA$#B"#`X8"
+M````/````(P!`````````````&X#````````0@X0CP)*#AA"#B"-!(X#10XH
+M00XP00XX1`Y0@P>&!HP%`````````!P```#,`0`````````````V````````
+M`$$.$(,"````%``````````!``%X$`P'")`!````````%````!P`````````
+M`````!8`````````+````#0``````````````/(`````````0@X0C0))#AA!
+M#B!!#BB#!88$C`,`````%````&0``````````````#T`````````%````'P`
+M`````````````&8`````````+````)0``````````````.D`````````0@X0
+MC`)$#AB&`T0.((,$1PXP````````'````,0``````````````%\`````````
+M00X0@P)'#B`D````Y```````````````U0````````!"#A",`D0.&$$.((,$
+MA@,`'`````P!`````````````)$`````````00X0@P(````\````+`$`````
+M````````$0(```````!"#A"/`D4.&$(.($(.*$$.,(8&C`6-!(X#1`XX1`Y0
+M@P<`````````-````&P!`````````````-@#````````0@X00@X80@X@00XH
+MA@6,!(T#C@)$#C!'#K`$@P8````D````I`$`````````````8P````````!!
+M#A"&`D4.&$0.((,#````)````,P!`````````````(,`````````0@X000X8
+M00X@@P2&`XP"`"P```#T`0````````````!(`@```````$(.$$(.&$$.((8$
+MC`.-`D0.*$0.,(,%`!P````D`@````````````"<`````````$0.($J&`H,#
+M)````$0"`````````````&@!````````0@X0C`)(#AB&`T4.((,$`"P```!L
+M`@````````````"X!P```````$<.P`1NA@:.`XP%@P=3CP*-!````````"0`
+M``"<`@````````````"'`@```````$$.$(8"1`X81`X@@P,````4````````
+M``$``7@0#`<(D`$````````4````'```````````````5``````````4````
+M-````````````````@`````````4````3```````````````$P`````````4
+M````9````````````````P`````````D````?```````````````X@``````
+M``!"#A",`D0.&$$.((,$A@,`)````*0``````````````#H`````````00X0
+MA@)$#AA$#B"#`P```!P```#,``````````````!)`````````$$.$(,"````
+M'````.P``````````````%4`````````1`X0```````4````#`$`````````
+M````#``````````4````)`$`````````````#``````````4``````````$`
+M`7@0#`<(D`$````````4````'```````````````3P`````````4````-```
+M````````````3P````````````````````!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P
+M,#<P.#,Q('!A=&-H960@6T9R965"4T1=```N<WEM=&%B`"YS=')T86(`+G-H
+M<W1R=&%B`"YR96QA+G1E>'0`+G)E;&$N<F]D871A`"YR;V1A=&$N<W1R,2XX
+M`"YR;V1A=&$N<W1R,2XQ`"YR96QA+F1A=&$`+G)E;&$N96A?9G)A;64`+F)S
+M<P`N8V]M;65N=```````````````````````````````````````````````
+M````````````````````````````````````````(`````$````&````````
+M````````````0``````````/+`0`````````````````$```````````````
+M`````!L````$`````````````````````````!!G!0``````Z'P!```````.
+M`````0````@`````````&``````````K`````0````(`````````````````
+M``!@+`0``````%`8```````````````````@````````````````````)@``
+M``0`````````````````````````^.,&``````"H.0````````X````#````
+M"``````````8`````````#,````!````,@```````````````````+!$!```
+M````1`T```````````````````@``````````0````````!"`````0```#(`
+M``````````````````#T400``````#H#```````````````````!````````
+M``$`````````5@````$````#````````````````````0%4$``````#0#0``
+M````````````````(````````````````````%$````$````````````````
+M`````````*`=!P``````6!0````````.````!P````@`````````&```````
+M``!A`````0````(````````````````````08P0``````(B)````````````
+M```````(````````````````````7`````0`````````````````````````
+M^#$'```````@6`````````X````)````"``````````8`````````&L````(
+M`````P```````````````````*#L!```````0`4``````````````````"``
+M``````````````````!P`````0````````````````````````"@[`0`````
+M`"<&```````````````````!````````````````````$0````,`````````
+M````````````````Q_($``````!Y`````````````````````0``````````
+M``````````$````"`````````````````````````$#W!```````P#D`````
+M```/````!0(```@`````````&``````````)`````P``````````````````
+M````````,04```````XV```````````````````!````````````````````
+M``````````````````````````````````````,``0``````````````````
+M``````````,``@````````````````````````````,``P``````````````
+M``````````````,`!`````````````````````````````,`!0``````````
+M``````````````````,`!@````````````````````````````,`!P``````
+M``````````````````````,`"`````````````````````````````,`"0``
+M``````````````````````````,`"@````````````````````````````,`
+M"P````````````````````````````,`#```````````````````````````
+M``,`#0````````````````````````````,`#@``````````````````````
+M``````,`#P```````````````````````0````(``0```````````#8`````
+M````#P````(``0!0=````````$4"````````(@````(``0!P#P```````'$`
+M````````,`````(``0!0(````````&X!````````4`````(``0`0N```````
+M`$L`````````7`````(``0`PO@```````"<`````````>`````(``0!@G```
+M`````.D`````````B`````(``0!0$````````!4#````````G`````(``0"P
+M!0```````"@`````````L@````(``0!@N````````%(`````````PP````(`
+M`0#@!````````(<`````````UP````(``0#@!0```````"$`````````]P``
+M``(``0``K@```````#\`````````!P$```(``0!0;0```````+D`````````
+M(`$```(``0#`(0```````$P$````````.P$```(``0"`RP```````'<`````
+M````2`$```(``0!@`@```````#``````````9@$```(``0#@O0```````!T`
+M````````@0$```(``0#@N````````!(`````````F@$```(``0"050``````
+M`"H`````````M0$```(``0"``````````$8`````````Q0$```(``0#`QP``
+M``````D#````````UP$```(``0!@:````````#P`````````\@$```(``0`P
+M;P```````%\``````````@(```(``0#@80```````(,`````````'@(```(`
+M`0`@4P```````"@!````````.P(```(``0"0;P```````(\`````````40(`
+M``(``0"0OP```````)H`````````<0(```(``0`08````````,H!````````
+MA`(```(``0"0P````````!<`````````IP(```(``0!`7P```````,4`````
+M````O0(```(``0!P8@```````!L"````````U0(```$``P"P`@```````!L`
+M````````X`(```(``0"`0P```````"T`````````_`(```(``0"P6```````
+M`"P`````````$`,```(``0#PLP```````%(`````````(0,```(``0"`-0``
+M`````.P`````````0P,```(``0#`N````````!@`````````6P,```(``0#0
+MM````````-X"````````:P,```(``0"0M````````#\`````````?0,```(`
+M`0!PNP```````"``````````B@,```(``0`@`0````````P`````````FP,`
+M``(``0`P`@```````"<`````````KP,```(``0"09````````&,!````````
+MP`,```(``0"`K````````$L`````````SP,```(``0`P!@```````$<`````
+M````XP,```(``0``10```````-P"````````^`,```(``0#`!P```````%`!
+M````````#`0```(``0#P#P```````$L`````````(P0```(``0``9@``````
+M`&`"````````-00```(``0"`L@```````%(`````````100```$`"P!`````
+M`````(``````````2P0```(``0#@1P```````'<(````````9@0```(``0"0
+MQ````````%4!````````E`0```(``0```P```````-P!````````L00```(`
+M`0"`\0```````)H`````````P00```(``0!0M````````#<`````````U`0`
+M``(``0`@*@```````!H!````````]`0```(``0"0Z0```````(\#````````
+M#P4```(``0#@H````````!@`````````)04```(``0"`!@```````%(`````
+M````.`4```(``0`P`0```````"(`````````2P4```(``0!P)P```````*L"
+M````````8P4```(``0!`*P```````',%````````@04```(``0`@60``````
+M`#X`````````E@4```(``0"PH0```````/\!````````JP4```(``0`@/0``
+M`````$D"````````P@4```(``0!P:P```````.D`````````W04```(``0``
+M7P```````"``````````]`4```(``0#@6````````#X`````````#`8```(`
+M`0`P6````````"X`````````)08```(``0#0:````````"8`````````/P8`
+M``(``0!07````````!@!````````5@8```(``0!@6````````$P`````````
+M:08```(``0`PP````````%P`````````C`8```(``0!0NP```````!X`````
+M````H`8```(``0#0`@```````"<`````````M`8```(``0!@50```````"H`
+M````````S08```(``0`0#0```````/$`````````[`8```(``0#`"P``````
+M`$H!````````^08```(``0!P$P```````/$!````````%@<```(``0#`O0``
+M`````!P`````````,P<```(``0#P6@```````%\`````````3P<```(``0!0
+MOP```````$``````````=0<```(``0!`$`````````(`````````D`<```(`
+M`0!@60```````(<!````````I0<```(``0"@:````````"8`````````P0<`
+M``(``0``?````````-\&````````UP<```(``0`0)@```````%8!````````
+M\P<```(``0``50```````"H``````````P@```(``0"0.P```````+@`````
+M````(`@```(``0"`O````````#$!````````,0@```(``0``H0```````*4`
+M````````10@```(``0``:0```````$L`````````7`@```(``0!0"0``````
+M`&T"````````;@@```(``0`0#@```````$T`````````A0@```(``0!PW```
+M`````'P!````````H`@```(``0"070```````/@`````````LP@```(``0!@
+M`0```````$<`````````P@@```(``0#`,````````+T$````````V@@```(`
+M`0"PI0```````.T%````````[P@```(``0!@O@```````.X`````````$@D`
+M``(``0#``0```````%P`````````)@D```(``0#P50````````X!````````
+M0`D```(``0!`K@```````(<`````````4@D```(``0!`BP````````H(````
+M````;PD```(``0`P50```````"X`````````@PD```(``0`@7P```````"``
+M````````EPD```(``0#P#@```````'4`````````N0D```(``0``N0``````
+M`$X"````````SPD```(``0!0/````````,(`````````[`D```(``0"0NP``
+M`````.,``````````PH```(``0#0K0```````"<`````````%`H```(``0!P
+M!0```````#D`````````*`H```(``0!`T@```````!H`````````/0H```(`
+M`0``4P```````!4`````````7@H```(``0!``````````#8`````````<0H`
+M``(``0#0:0```````&D`````````?0H```(``0#0:@```````)\`````````
+MD@H```(``0`0S@```````'D#````````J0H```(``0"@H````````!0`````
+M````PPH```(``0"@=@```````.D!````````W0H```(``0#0`````````$8`
+M````````\0H```(``0#`50```````"H`````````"0L```(``0`0;@``````
+M`!<!````````'0L```(``0!@;````````.P`````````-0L```(``0`@<```
+M`````$("````````4PL```(``0"@[@```````-4"````````:@L```(``0"P
+MMP```````%,`````````=PL```(``0#PK````````$``````````A`L```(`
+M`0!0S0```````+0`````````G`L```(``0#`H````````!@`````````KPL`
+M``(``0"P`0```````!``````````P0L```(``0!P'@```````-0!````````
+MW`L```(``0``'@```````&T`````````\@L```(``0``O@```````"L`````
+M````#0P```(``0!P<@```````.$`````````(0P```(``0#PQ0```````.$`
+M````````.`P```(``0`0!@```````"``````````2@P```(``0"07@``````
+M`&,`````````7`P```(``0!`!P```````'D`````````>0P```(``0!0:0``
+M`````'\`````````E@P```(``0!P-@```````!@%````````K0P```(``0"P
+MP````````-(#````````PPP```(``0"0`@```````#$`````````V@P```(`
+M`0`0Z0```````',`````````]@P```(``0`@`@````````T`````````#0T`
+M``$`!P!``````````"@`````````&@T```(``0!@<P```````.$`````````
+M+@T```(``0#@L@```````%(`````````/@T```$`"P````````````0`````
+M````4`T```(``0!`EP```````!@%````````80T```(``0!@#@```````((`
+M````````@`T```(``0!P70```````!<`````````D`T```(``0"P0P``````
+M`$(!````````J0T```(``0!@4````````)\"````````P0T```(``0"0>```
+M`````&P#````````VPT```(``0``5P```````",!````````\@T```(``0!P
+M%0```````($(````````"`X```(``0#@!@```````%(`````````'`X```(`
+M`0!@T@```````(@`````````-`X```(``0!`0````````#X#````````50X`
+M``(``0"PHP```````/\!````````<0X```(``0`0"0```````#\`````````
+M@PX```(``0#@@P```````%H'````````G@X```(``0`PK0```````)4`````
+M````N`X```(``0#0TP```````%0`````````T`X```(``0!06P```````/P`
+M````````Y0X```(``0!05`````````(`````````^@X```(``0!0G0``````
+M`$@#````````$P\```(``0!``@(``````*<`````````(@````(``0"@%0$`
+M`````'$`````````)P\```(``0"@"`$``````%P`````````/0\```(``0!P
+M^@$```````<`````````3`\```(``0`@K`$``````"H`````````:0\```(`
+M`0!PQ@$``````*,#````````@P\```(``0`@`0(``````!L!````````DP\`
+M``(``0``<`$``````#$&````````LP\```(``0#0F`$``````'(`````````
+MR0\```(``0`@8P(``````",)````````Z`\```(``0"0Z0$``````(``````
+M````$Q````(``0"@LP$``````.8`````````L@````(``0``?@(``````%(`
+M````````)Q````(``0`PIP$``````%8`````````1A````(``0!PA`(`````
+M`#L!````````61````(``0``GP(``````%P`````````<Q````(``0"@5@(`
+M`````',,````````D1````(``0``;`$``````/@#````````JQ````(``0"0
+MXP$``````)`!````````]P````(``0"0<`(``````#\`````````.P$```(`
+M`0#`E`(``````'<`````````Q!````(``0!0EP(``````'D#````````W1``
+M``(``0!0K`$``````"``````````^1````(``0"`4`(``````!@!````````
+M$A$```(``0"P!P$``````$8`````````*!$```(``0#0=@$```````X`````
+M````1A$```(``0!`"0$``````#``````````9A$```(``0`@KP$``````$D`
+M````````>1$```(``0#P50(``````*\`````````D!$```(``0!0L0$`````
+M`"H`````````KA$```(``0`0#0$``````"$`````````T!$```(``0!`JP$`
+M`````#0`````````YA$```(``0``D0(```````D#````````\@$```(``0``
+M_P$``````%\`````````^A$```(``0`0B0(``````/$#````````$A(```(`
+M`0#0K`$``````&$`````````)Q(```(``0"`$`$``````&T"````````.Q(`
+M``(``0"PE`$``````&<!````````.P(```(``0!P^P$``````),`````````
+M7!(```(``0!0#0(``````*<`````````<A(```(``0`@E`$``````(L`````
+M````C1(```(``0"`?@(``````!(`````````J!(```(``0!0G0$```````D!
+M````````T!(```(``0!02@$``````/@`````````]!(```(``0`0#@$`````
+M`%(`````````"A,```(``0"@40(```````$"````````U0(```$``P``%@``
+M`````"``````````(1,```(``0#P`@(``````"H!````````,!,```(``0"`
+MT@$``````/(`````````2!,```(``0"0UP$``````&<#````````:!,```(`
+M`0!0F0$```````\!````````C!,```(``0"P4P(``````#L"````````JA,`
+M``(``0`@YP$``````$<!````````$`,```(``0``=P(``````%(`````````
+MQQ,```(``0#0J`$``````!T!````````Y!,```(``0!@'`$```````,&````
+M````!A0```(``0#0N@$``````(8`````````?0,```(``0"P?P(``````"(`
+M````````+10```(``0#PT0$``````#H`````````1Q0```(``0!`LP$`````
+M`",`````````910```(``0#0DP$``````$0`````````CA0```(``0`@%@$`
+M`````!D`````````JQ0```(``0#@#`$``````"@`````````-00```(``0"0
+M=0(``````%(`````````100```$`"P!``0```````(``````````PQ0```(`
+M`0"@S0$```````P!````````VA0```(``0#PD`$``````%P`````````\10`
+M``(``0"@&0(``````.T#````````!A4```(``0"P"0$``````#,`````````
+ML00```(``0`PQP(``````)H`````````'!4```(``0!PA@(``````#,!````
+M````014```(``0``G`$``````$\!````````:!4```(``0`0Q0$``````%8!
+M````````C14```(``0"@7P$``````+X`````````K!4```(``0!`K@$`````
+M`-$`````````R!4```(``0#`%@$``````%\`````````X14```(``0!@#0$`
+M`````$<`````````]Q4```(``0``U@$``````(4!````````"A8```(``0`P
+M!`$``````"P`````````*A8```(``0#P>@$```````8!````````1A8```(`
+M`0`@<`(``````#<`````````5A8```(``0`PD`$``````&\`````````?A8`
+M``(``0!`%`$``````$T`````````EQ8```(``0#PAP(``````)H`````````
+M)08```(``0!`X@$``````"8`````````N18```(``0!@,P$``````.\#````
+M````VQ8```(``0!P@`(``````"\!````````^18```(``0!0-P$``````,,)
+M````````&Q<```(``0#@P@$``````!,!````````1Q<```(``0"0H0$`````
+M`"P!````````;A<```(``0!`%@$``````$4`````````D!<```(``0#@N@(`
+M`````)H#````````C`8```(``0"0?P(``````"``````````K1<```(``0#P
+M+0$``````!`"````````RQ<```(``0"0%`$``````((`````````M`8```(`
+M`0#PJP$``````"H`````````[!<```(``0"@@0(``````.,`````````"1@`
+M``(``0#@]0$``````/@`````````)!@```(``0``#@(``````#X#````````
+M[`8```(``0#P$@$``````$H!````````0!@```(``0`@00$``````"4)````
+M````6A@```(``0!PX@$``````!4`````````<A@```(``0`0A@(``````"L`
+M````````CQ@```(``0"0IP$``````!4`````````LA@```(``0`P;0(`````
+M`$L`````````PQ@```(``0#0M`$``````#X`````````VA@```(``0!0?0(`
+M`````%,`````````Z1@```(``0"0;@(``````(4!````````^A@```(``0`P
+MXP$``````%T`````````&1D```(``0#@S`$``````+H`````````0AD```(`
+M`0#P;0(``````)4`````````7AD```(``0!`P0(``````.D%````````=QD`
+M``(``0#PW`$``````(\"````````BQD```(``0"`O@$``````&T!````````
+ML!D```(``0#@?P(``````((`````````R1D```(``0"0^0$``````&(`````
+M````Z1D```(``0!PK`$``````"H``````````!H```(``0!`#0$``````"``
+M````````%!H```(``0!@_P$``````.X`````````+!H```(``0"@=P(`````
+M`#\`````````0!H```(``0``"`$```````P`````````4QH```(``0"03`(`
+M`````.P#````````:AH```(``0#@!@$``````#8`````````>AH```(``0#@
+MFP(``````)D`````````C!H```(``0!@G@$``````(,!````````HQH```(`
+M`0#@+`(``````$,"````````Q!H```(``0`P0`(``````+("````````UAH`
+M``(``0!@F@$``````)\!`````````1L```(``0`0LP$``````"P`````````
+M%QL```(``0`0"0$``````"<`````````+1L```(``0`@!`(``````,,`````
+M````1!L```(``0``?`$``````$,!````````7QL```(``0#0!P(``````)\"
+M````````=!L```(``0"`TP$``````.H!````````B1L```(``0``Q`$`````
+M``0!````````LQL```(``0"PS@$``````'T!````````S!L```(``0"@L`$`
+M`````"8`````````Y!L```(``0!0D0$``````%\``````````QP```(``0"@
+MD`$``````$(`````````+1P```(``0`@50$``````+0)````````1AP```(`
+M`0!`$0(``````%D'````````7AP```(``0"0Z@$``````!4)````````<1P`
+M``(``0#0A0(``````!P`````````D!P```(``0"@#`$``````#D`````````
+MIAP```(``0!0+P(``````*4)````````Q1P```(``0"PP0$``````"H!````
+M````ZAP```(``0!P"@(``````-T"````````0`D```(``0#0<`(``````-4`
+M````````"AT```(``0!PKP$``````/H`````````'AT```(``0#PJ0$`````
+M`(<`````````+QT```(``0#0QP(``````"8)````````/AT```(``0"0'0(`
+M`````"H(````````6QT```(``0`@Y0$``````,L`````````>!T```(``0"0
+M"`$``````!``````````C!T```(``0"PX`$``````#0!````````IQT```(`
+M`0"`WP$``````"0!````````OQT```(``0`P&0$``````.T`````````UQT`
+M``(``0!PLP$``````"<`````````\AT```(``0`0#`$``````(X`````````
+M"!X```(``0`0"`$``````"(`````````'1X```(``0!`A@(``````"<`````
+M````.QX```(``0"0B`(``````%P`````````8!X```(``0"@?@(``````.@`
+M`````````PH```(``0!@<`(``````"<`````````>!X```(``0#@X@$`````
+M`$$`````````CAX```(``0"PD0$``````-X`````````L!X```(``0!0?0$`
+M`````)`+````````S1X```(``0!P)@(``````&D&````````Z!X```(``0"`
+MT0$``````&<`````````_!X```(``0!P(@$``````!$`````````*`H```(`
+M`0"PM`(``````-(`````````'!\```(``0#@=@$```````L$````````/Q\`
+M``(``0"@K`$``````"H`````````61\```(``0`@!P$``````#8`````````
+M;A\```(``0`0C0(``````%4!````````GA\```(``0`PT@$``````"``````
+M````MQ\```(``0"PJ@$```````(`````````<0H```(``0``^@$``````&D`
+M````````SA\```(``0!02P$``````,()````````YA\```(``0`@E@$`````
+M`%P!````````!R````(``0!PZ`$``````!\!````````'2````(``0#@]@$`
+M`````,`!````````-"````(``0`@%P$```````,"````````?0H```(``0!0
+M``(``````,X`````````4R````(``0!`=@$``````($`````````J0H```(`
+M`0`P+P(``````!0`````````<R````(``0!`]0$``````)T`````````BR``
+M``(``0#@B`$``````'<"````````K2````(``0"@^`$``````'\`````````
+MS"````(``0#@10(``````+\"````````YR````(``0#PB`(``````!<`````
+M````#"$```(``0"`^@$``````#,`````````&B$```(``0`@%0$``````'4`
+M````````/B$```(``0!P#@$``````'D`````````72$```(``0`@N@$`````
+M`*\`````````>2$```(``0#PH`$``````*``````````FB$```(``0`@^0$`
+M`````&(`````````NB$```(``0#P#@$``````%`!````````T"$```(``0"0
+MM`$``````#X`````````ZB$```(``0`@RP$``````.H`````````$"(```(`
+M`0!`"`$``````$<`````````=PL```(``0"@;0(``````$(`````````(2(`
+M``(``0!PL`$``````"X`````````/"(```(``0"PA0(```````4`````````
+M5B(```(``0#P0@(``````.\"````````;R(```(``0`P:`$``````,D#````
+M````A`L```(``0"0E@(``````+0`````````B"(```(``0"P?0(``````$L`
+M````````EB(```(``0#`@P(``````*L`````````LR(```(``0`@^P$`````
+M`!\`````````PB(```(``0``"0$```````T`````````VR(```(``0"0@@(`
+M`````"(!````````^"(```(``0"`J@$``````"4`````````$B,```(``0#0
+ML`$``````$8`````````+R,```(``0`@_0$``````-$!````````2R,```(`
+M`0"P#0$``````%(`````````8",```(``0!`K0$``````/8`````````W`L`
+M``(``0"0%@$``````"$`````````>2,```(``0#@=P(``````&4%````````
+MBR,```(``0"0Y@$``````(4`````````J",```(``0#`N0$``````%0`````
+M````QB,```(``0"@2`(``````.H#````````WR,```(``0"`EP$``````$4!
+M````````#0P```(``0#P!0(``````.$``````````20```(``0#PGP$`````
+M`/\`````````'B0```(``0!@FP(``````'0`````````+"0```(``0`0M0$`
+M`````$D#````````0R0```(``0!0O`$``````*@`````````8"0```(``0#P
+M!`(``````/$`````````?20```(``0#@7@$``````+L`````````G"0```(`
+M`0"0(@$``````%4+````````N20```(``0"@G`(``````%``````````RB0`
+M``(``0`0JP$``````"H`````````W"0```(``0!P!`$``````&X"````````
+M^20```(``0!PU0$``````(8`````````%R4```(``0!@Y@$``````"D`````
+M````.24```(``0#`J@$``````$L`````````5"4```(``0!@=P(``````#<`
+M````````:24```(``0"PX@$``````",`````````@R4```(``0``VP$`````
+M`.$!````````DR4```(``0``/0(``````"<#````````V@P```(``0`PN@(`
+M`````*,`````````L24```(``0#PY0$``````&X`````````PB4```(``0`0
+MZ@$``````(``````````W24```(``0"0X@$``````!H`````````^"4```(`
+M`0!`$`$``````#\`````````&@T```(``0#@!@(``````.$`````````#"8`
+M``(``0#0"P$``````#X`````````&B8```(``0"PAP(``````$``````````
+M+@T```(``0#P=0(``````%(`````````/@T```$`"P#@``````````0`````
+M````@`T```(``0`PT`$``````!<`````````0B8```(``0!P"0$``````#$`
+M````````6R8```(``0"09`$``````)\#````````>"8```(``0"0D@$`````
+M`#,!````````GB8```(``0"PIP$``````!P!````````O28```(``0#P"0$`
+M`````-P!````````W"8```(``0#POP$``````*D``````````"<```(``0#P
+MX0$``````$L`````````&2<```(``0!@?@(``````!@`````````,R<```(`
+M`0`@R@$``````/P`````````7"<```(``0!@8`$``````%\#````````=2<`
+M``(``0!@BP$``````,$$````````C"<```$`"P`@`0```````!P`````````
+MGR<```(``0!@NP$``````/``````````O2<```(``0#`A0(```````8`````
+M````'`X```(``0"0M0(``````(P`````````UR<```(``0"`JP$``````"H`
+M````````]"<```(``0#`H@$``````&\$````````$R@```(``0``,`$`````
+M`%T#````````+2@```(``0!0T`$``````"H!````````0B@```(``0`0_`$`
+M``````$!````````6"@```(``0"@P`$```````T!````````>R@```(``0#P
+MA0(``````!T`````````F"@```(``0!0T@$``````"8`````````KB@```(`
+M`0#`)0(``````*@`````````Q"@```(``0`@J0(``````-P$````````X2@`
+M``(``0`0S`$``````,D`````````!2D```(``0!@!P$``````$8`````````
+M%RD```(``0!`&P$``````!@!````````."D```(``0!PC@(``````*<!````
+M````42D```(``0"PJP$``````#$`````````;BD```(``0`@L0$``````"8`
+M````````C"D```(``0!P*P0``````$\`````````FBD```(``0#P#@,`````
+M`*X`````````JBD```(``0!@'0,``````+<*````````Q"D```(``0"`'@0`
+M`````+@'````````U"D```(``0#`,0,``````)8`````````Y"D```$`"P#P
+M`0````````@`````````]"D```(``0#P#`,```````P`````````"2H```(`
+M`0!P*P,``````&4!````````'BH```(``0`@&00``````&,`````````-BH`
+M``$`!P"!`P````````$`````````1BH```(``0#@0@,``````(4`````````
+M5BH```(``0"@$00``````-4`````````9RH```(``0"`$@0``````)$`````
+M````>RH```(``0`@&@0``````$@"````````D2H```(``0"`.P,``````-H`
+M````````IRH```$`"P#X`0````````0`````````M2H```(``0!`$00`````
+M`%\`````````S2H```(``0"0Z@,``````(8`````````W"H```(``0!@8`,`
+M`````$$`````````[BH```(``0``!`,``````%H!`````````2L```(``0!@
+M/`,```````,!````````&2L```(``0`0]0(``````$L`````````+2L```(`
+M`0#@+`,``````(4!````````02L```(``0`@*@,``````$H`````````3RL`
+M``(``0#`"P,``````&4`````````9"L```(``0"`$0,``````&``````````
+M=2L```(``0"`"P,``````#$`````````C"L```$`"P```@````````$`````
+M````H"L```(``0``+P,``````&8`````````NRL```(``0`@*`,``````/\!
+M````````SRL```(``0!P+@,``````(\`````````WRL```(``0"@]@(`````
+M`"4`````````Z"L```(``0"0\P(``````'<`````````!"P```(``0!P'`0`
+M`````)P`````````&BP```(``0"@&@,``````%H"````````+2P```(``0"`
+M#@0``````!8`````````-BP```(``0#`*P0``````$\`````````1"P```(`
+M`0`0&0,``````(\!````````8"P```(``0!07P,``````/,`````````:RP`
+M``(``0#`8P,```````@!````````@2P```(``0``G@,``````!X!````````
+MDRP```(``0"@8@,``````!D!````````K"P```(``0"0`P0``````$P`````
+M````O2P```(``0`@-@,``````%4`````````R"P```(``0"`!00```````8$
+M````````V2P```(``0!0#0,``````'<`````````[BP```(``0!0$`0`````
+M`.D`````````_2P```(``0#@^P(``````/D`````````$"T``!(``0`@\P(`
+M`````!,`````````-RT``!$`"P`$`@````````$`````````3"T``!``````
+M````````````````````8RT``!(``0!@*P0```````P`````````>BT``!``
+M````````````````````````C2T``!(``0!0]@(``````"@`````````GRT`
+M`!(``0!@*@0``````#H`````````KBT``!(``0!@!0,``````,<!````````
+MQ2T``!(``0`0^@(``````(<`````````W"T``!``````````````````````
+M````]"T``!(``0#P*@0``````%4`````````#2X``!(``0"`\P(```````P`
+M````````)"X``!(``0!@`P,``````)@`````````.RX``!``````````````
+M````````````5BX``!(``0``^`(``````%4`````````92X``!``````````
+M````````````````;"X``!(``0!@^`(``````-D`````````?RX``!(``0#@
+M]0(``````"L`````````EBX``!(``0#0_0(``````!4`````````JBX``!(`
+M`0#P!P,``````(`!````````P"X``!(``0`@$P0``````!$"````````W2X`
+M`!$`"P#\`0````````0`````````]"X``!(``0!`%00``````-@#````````
+M#B\``!``````````````````````````(R\``!(``0#@_`(``````%4`````
+M````.2\``!(``0``$`,``````&H`````````5"\``!(``0!08`,```````@`
+M````````;B\``!``````````````````````````@"\``!(``0"@*@0`````
+M`$D`````````E2\``!$`"P#@`0````````@`````````I2\``!(``0"``P0`
+M``````D`````````OB\``!(``0!P]P(``````(,`````````TR\``!$`"P`%
+M`@````````$`````````ZR\``!(``0`PU````````!H`````````!C```!(`
+M`0#P`@0``````&L`````````'3```!``````````````````````````-#``
+M`!(``0"@^@(``````%<`````````1S```!$`"P#H`0````````@`````````
+M5C```!(``0!`^0(``````,,`````````;C```!(``0``^P(``````-D`````
+M````?S```!(``0!`7P,```````<`````````ES```!``````````````````
+M````````KC```!(``0#09`,``````"<`````````OC```!$`"P`#`@``````
+M``$`````````VC```!``````````````````````````[3```!``````````
+M`````````````````#$``!$`!P"#`P````````$`````````%#$``!(``0"@
+M_0(``````!``````````.3$``!(``0#0"@0``````&X#````````1S$``!(`
+M`0!@GP(``````!H`````````9#$``!(``0"P_0(``````!$`````````@#$`
+M`!``````````````````````````F#$``!(``0"0"00``````%(`````````
+MK3$``!``````````````````````````PS$``!(``0"0&00``````(,`````
+M````WC$``!(``0!`#@0``````#8`````````\C$``!``````````````````
+M`````````C(``!``````````````````````````&3(``!(``0!0*P0`````
+M``P`````````,#(``!``````````````````````````0S(``!(``0"0]@(`
+M`````!``````````7S(``!(``0`0]`(``````,@`````````>C(``!$`!P"`
+M`P````````$`````````C3(``!(``0!`\P(```````P`````````I3(``!$`
+M"P`!`@````````$`````````P#(``!``````````````````````````RC(`
+M`!(``0!`)@0``````(<"````````ZC(``!(``0!@*00```````,`````````
+M!#,``!(``0#`%@,``````/P!````````&S,``!(``0`P!P,``````+,`````
+M````,3,``!(``0#0]@(``````#X`````````2C,``!``````````````````
+M````````83,``!(``0!0\P(``````"D`````````>3,``!``````````````
+M````````````C3,``!(``0`0]@(``````#T`````````HS,``!``````````
+M````````````````M#,``!(``0!`*00``````!,`````````TC,``!(``0#`
+M`0,``````/,`````````\C,``!``````````````````````````!C0``!``
+M````````````````````````(S0``!(``0"`]@(```````L`````````/30`
+M`!``````````````````````````4#0``!(``0!P`@0``````'0`````````
+M9S0``!``````````````````````````@C0``!(``0`P*00```````(`````
+M````E30``!(``0#@`P0``````'$`````````JC0``!(``0`P#`,``````+(`
+M````````PC0``!(``0#0*`0``````%0`````````X#0``!(``0#@]`(`````
+M`"P`````````#C4``!$`!P""`P````````$`````````*C4``!(``0!P"0,`
+M`````/H`````````034``!(``0!@`P0``````!L`````````5C4``!(``0!`
+M_0(``````%<`````````=34``!``````````````````````````C#4``!(`
+M`0!@``,``````%8!````````J34``!(``0`0]P(``````%\`````````OC4`
+M`!(``0"@#@0``````/(`````````VS4``!$`"P`"`@````````$`````````
+M]C4``!(``0!P0P,``````'(``````````'(W-3!?5&%G7TEN:70`<C<U,%]5
+M<&1A=&50:'E);F9O`'-A<U]H87-H7V%D9'(`<C<U,%]697)I9GE#;VUM86YD
+M0F5F;W)E4V5N9&EN9P!R-S4P7T)E97!/;@!R-S4P7U-#4TE?051!7T9I;&Q$
+M871A1FEE;&0`<&U?<VEG7W1I;65?;W5T`'-A=&%?<&]R=%]S=&]R95]S:6<`
+M<C<U,%]-5E]:97)O379297%U97-T`&DR8T%?=W)I=&5?8GET97,`<C<U,%]-
+M5E]$=6UP4F5Q=65S=`!R-S4P7TU67TEN:71I86QI>F5487)G971)1%1A8FQE
+M`'-E=%]P;5]F86EL7VQE9`!S871A7VUA:V5?<V]F=%]R97-E=%]R97$`<C<U
+M,%]0<F5P87)E06YD4V5N9$-O;6UA;F0`3V1I;E-025]29'!T`'(W-3!?359?
+M36%P5&]3<&5C:69I8U1A<F=E=$E$`'(W-3!?4T-325]!5$%?1FEL;$Q"04-D
+M8C$P`'(W-3!?4T=024]?5W)I=&5296=I<W1E<@!R-S4P7T9R9653051!4V-R
+M871C:%1O4&]O;`!R-S4P7U1A9U]'971/;F4`<C<U,%]/9&EN4U!)7TEN:70`
+M<C<U,%]&<F5E26YT97)N86Q297%4;U!O;VP`=V%T:6YG7V-A;&QB86-K`'(W
+M-3!?0V]M<&QE=&5297%U97-T06YD4VQO=`!R-S4P7T-O<F5?1V5T4W5P<&]R
+M=&5D0V]U;G1S`%!-7U-E=$9A:6Q,961#86QL8F%C:P!R-S4P7U-#4TE?051!
+M7U9E<FEF>51R86YS;&%T:6]N`'(W-3!?7U]R96YE=U]T:6UE<@!R-S4P7U-#
+M4TE?051!7U-T87)T4W1O<%1R86YS;&%T:6]N`'(W-3!?1G)E941E=FEC951O
+M4&]O;`!R-S4P7U!O<G1?06)O<G1297%U97-T<P!P<F]D=6-T7VED`'(W-3!?
+M0V]R95]-;V1U;&5396YD4F5Q=65S=`!R-S4P7T9R9650;W)T5&]0;V]L`&DR
+M8T)?=W)I=&5?8GET97,`<C<U,%]#;W)E7TEN=&5R<G5P=%-E<G9I8V52;W5T
+M:6YE`'(W-3!?4T=024]?4F5A9%)E9VES=&5R`'(W-3!?;V1I;E]I;V-T;`!R
+M-S4P7W-E=%]F86EL7VQE9`!497-T7U!I;E]3970`<C<U,%]486=?27-%;7!T
+M>0!R-S4P7TU67TUA<%1A<F=E=$E$`'(W-3!?7U]A9&1?=&EM97(`<C<U,%]I
+M,F-?<F5S970`<C<U,%]M=E]D:7-A8FQE7VAB80!R-S4P7T-O<F5?4F5Q5&EM
+M96]U=`!R-S4P7VUV7W-E=%]305-!9&1R`'(W-3!?0V]R95]297-E=$-M9%-L
+M;W0`<C<U,%]296UO=F5$979I8V4`:3)C05]R96%D7V)Y=&5S`&%I;F9O`'(W
+M-3!?0V]R95]-;V1U;&5);FET:6%L:7IE`'(W-3!?4T-325]!5$%?4F5A9$-A
+M<&%C:71Y5')A;G-L871I;VY#86QL8F%C:P!R-S4P7TU67U-E=$Q"06%N9%-E
+M8W1O<D-O=6YT`&]D:6Y?8V]R95]T:6UE<@!R-S4P7W-E=%]F86EL7VQE9',`
+M<C<U,%]C;W)E7VAA;F1L95]T87-K9FEL95]E<G)O<@!R-S4P7V]D:6Y?<V5T
+M7W-P:6Y?=7!?;6]D90!P;5]W86ET7V9O<E]S;V9T<F5S970`<C<U,%]M=E]E
+M;F%B;&5?>&UT`'(W-3!?3&ES=%]'971&:7)S=`!R-S4P7U-!5$%?17)R;W)(
+M86YD;&EN9P!R-S4P7U-!5$%?4&]R=$AA;F1L94EN=&5R<G5P=`!R-S4P7T9R
+M965296=I<W1E<E-E=`!R-S4P7U-!5$%?4&]R=$1E=&5C=`!R-S4P7U!O<G1?
+M2&%N9&QE4&QU9VEN`'(W-3!?1&5V:6-E7TES<W5E4V]F=%)E<V5T`'(W-3!?
+M7U]035]C86YC96Q?=&EM97(`<C<U,%]035]&<F5E4F5G:7-T97)3970`<C<U
+M,%]'97131T)U9F9E<D9R;VU0;V]L`$=E=%-!5$$V-$M38W)A=&-H1G)O;5!O
+M;VP`<C<U,%]'971$979I8V5&<F]M4&]O;`!&<F5E3VYE0V]M;6%N9%-L;W0`
+M<C<U,%]30U-)7T%405]3>6YC0V%C:&54<F%N<VQA=&EO;@!497-T7U!I;E])
+M;FET:6%L:7IE`'(W-3!?359?1V5T36%P<&5D240`1G)E95-!5$$V-$M38W)A
+M=&-H5&]0;V]L`'(W-3!?4T%405]0<F5P87)E0V]M;6%N9$AE861E<@!M=E]P
+M:'E?<F5S970`<C<U,%]3051!7TAA;F1L941E=FEC955N<&QU9P!R-S4P7U-#
+M4TE?051!7T-H96-K0V]N9&ET:6]N`'(W-3!?1V5T26YT97)N86Q297%&<F]M
+M4&]O;`!R-S4P7U-#4TE?051!7U)E861#87!A8VET>51R86YS;&%T:6]N`'(W
+M-3!?9'5M<%]U;F%S<V]C:6%T961?9FES`'(W-3!?0V]M<&QE=&5297%U97-T
M`'(W-3!?1V5T4T%405-C<F%T8VA&<F]M4&]O;`!R-S4P7T-O<F5?36]D=6QE
-M4W1A<G0`<C<U,%]$:7-C;W9E<GE#86QL0F%C:P!G971?:61?9G)O;5]E;F-)
-M9`!R-S4P7T=E=%-%4U-"1G)O;5!O;VP`4T537U!R:79A=&5297%#86QL8F%C
-M:P!305-?4F5P;W)T3'5N4V-A;@!R-S4P7T-O<F5?2&%N9&QE5V%I=&EN9TQI
-M<W0`<C<U,%]0<F5%;7!T>5!-`'(W-3!?1V5T36EN3F5G;W1I871E9$QI;FM2
-M871E`'(W-3!?4T%405](86YD;&5$979I8V50;'5G:6X`<C<U,%]&:6QL16YC
-M;&]S=7)E16QE;65N=%-T871U<P!R-S4P7U-#4TE?5&]?1DE3`'(W-3!?0V]R
-M95-A=F5/<FEG:6YA;$-$0@!R-S4P7U-!5$%?4&]R=%)E<V5T`'(W-3!?1V5T
-M3VYE0V]M;6%N9%-L;W0`<C<U,%]M=E]R97-E=%]P:'D`<C<U,%]7<FET941%
-M3%9?45]%;G1R>0!R-S4P7V]D:6Y?<V5T7VED;&5?<W1A;F1B>0!R-S4P7U-%
-M4U]3971&86EL3&5D`'(W-3!?1V5T4$U&<F]M4&]O;`!R-S4P7TU67T5Q=6%L
-M<P!R-S4P7TAA;F1L94-O;6UA;F11=65U90!!<W-I9VY397-/=&AE<D5L96UE
-M;G1/=F5R86QL16QE;65N=$YU;6)E<@!R-S4P7U-#4TE?051!7U)E8617<FET
-M951R86YS;&%T:6]N`'(W-3!?4TU07U-'4$E/7U-E=%]&86EL;&5D`'(W-3!?
-M4G5N=&EM94ES<W5E4V]F=%)E<V5T0V%L;&)A8VL`<C<U,%]31U1A8FQE7T%P
-M<&5N9`!R-S4P7T%S<VEG;D1E=FEC94]V97)A;&Q%;&5M96YT3G5M8F5R`'(W
-M-3!?4$U?07-S:6=N4F5G:7-T97)3970`<C<U,%]3051!7U!-2&]T<&QU9U)E
-M<4-A;&QB86-K`'!O<G1?<V5T7V9A:6Q?;&5D`'(W-3!?57!D871E5&=T1&5V
-M36%P`'(W-3!?4T%37TEN=&5R;F%L4F5Q0V%L;&)A8VL`<C<U,%]5<&1A=&54
-M87)G971$979I8V5S`&]D:6Y?96U?86-C97-S`'(W-3!?4T%405]$979I8V53
-M=&%T94UA8VAI;F4`1&5V:6-E7U)E<&]R=$QU;E)E<75E<W0`<C<U,%]0<F5%
-M;7!T>41E=FEC90!R-S4P7T1)4T-?0VAE8VM$:7-C;W9E<E-T871E`'(W-3!?
-M1G)E95--4$-O;G1E>'0`<C<U,%]'971.0U%486<`<C<U,%]3051396YS941A
-M=&$`<C<U,%]31U!)3U]335!297%U97-T7U)E860`<C<U,%]?7V-A;F-E;%]T
-M:6UE<@!R-S4P7T1)4T-?1V5T4F5S;W5R8V4`<C<U,%]#;W)E7W!A<W-?=&AR
-M=5]F:6QL7W1A<VMF:6QE`'(W-3!?1$E30U]$;T1I<V-O=F5R`'(W-3!?4T=0
-M24]?26YI=&EA;&EZ90!R-S4P7U!O<G1?2&%N9&QE1&5V:6-E4&QU9VEN`'(W
-M-3!?4T=024]?4V5T7T9A:6QL960`<V5T7W!M7V9A:6Q?;&5D<P!R-S4P7TU6
-M7T-O<'E31U1A8FQE`'(W-3!?1&5V:6-E7TUA:V5296%D0V%P86-I='E487-K
-M4F5Q=65S=`!U<&1A=&5?9&5V:6-E7V-O;F9I9P!R-S4P7T-O<F5?36]D=6QE
-M16YA8FQE1&ES86)L94E240!R-S4P7VUO9&5086=E0G5F`'(W-3!?4T%37T1E
-M=FEC95-T871E36%C:&EN90!R-S4P7U1A9U]);FET7T9)1D\`<C<U,%]#;W)E
-M7T9I;&Q396YS941A=&$`<C<U,%]0;W-T36%K95-E<T-O;F9I9W5R871I;VY2
-M97%U97-T`'(W-3!?4T%405]035](86YD;&5$979I8V50;'5G:6X`<C<U,%]3
-M0U-)7T%405]5<'!E<E=O<F0`36%K941E=DEN9F\`<C<U,%]3051!7U!-4W1A
-M=&5-86-H:6YE`'(W-3!?1$E30U]3971297-O=7)C90!$979I8V5?36%K95!R
-M:79A=&5296-V4V5S4F5Q=65S=`!035])<W-U95=R:71E1F%I;$QE9`!R-S4P
-M7U-!5$%?4$U);FET4F5Q0V%L;&)A8VL`<C<U,%]O9&EN7V9L87-H7V%C8V5S
-M<P!3051!7U!-4W1A=&5-86-H:6YE4W!I;E5P`'(W-3!?4T%405]0;W)T1&5V
-M:6-E4F5A9'D`<C<U,%]486=?4F5L96%S94]N90!R-S4P7U-!4U]%<G)O<DAA
-M;F1L:6YG`&-H96-K7U-A<T%D9'(`<C<U,%]&<F5E4T="=69F97)4;U!O;VP`
-M<C<U,%]$971E8W10;W)T5'EP90!R-S4P7U!O<G1?27-297%U97-T4G5N;FEN
-M9P!R-S4P7T1)4T-?1V5T5&=T1&5V36%P`$1E=FEC95]497-T56YI=%)E861Y
-M4F5Q=65S=`!R-S4P7T1E=FEC95]087)S94ED96YT:69Y1&%T80!R-S4P7V1E
-M=FEC95]P<F]B95]D;VYE`'(W-3!?0F5E<$]F9@!G971?9FER<W1?<&T`<C<U
-M,%]5<&1A=&53=&%T=7-6<U-E<T-O;G1R;VQ"=69F97(`<C<U,%])<W-U95]#
-M;VYF:6=2;W5T94EN9F\`3V1I;E-025]396-T;W)5;G!R;W1E8W0`<C<U,%]#
-M;W)E4F5S=&]R94]R:6=I;F%L0T1"`'-C<VEL=6Y?=&]?:6YT`'(W-3!?4T=4
-M86)L95]);FET`'(W-3!?4T%405]035]%<G)O<DAA;F1L:6YG`%-!5$%?2&%N
-M9&QE4$U?2&]T4&QU9P!R-S4P7U-#4TE?051!7T9I;&Q,0D%#9&(Q-@!R-S4P
-M7TES<W5E7T1I<V-O=F5R`$=E=$%T=$ED96YT:69Y1G)A;64`4T535&EM97)?
-M26YT97)N86Q297%#86QL8F%C:P!G971?96YC7V-O=6YT`'(W-3!?0V%T96=O
-M<GE?0T1"7U1Y<&4`<C<U,%],:7-T7T=E=$QA<W0`<C<U,%]&<F5E4$U4;U!O
-M;VP`9V5T7VUI;E]P;5!A=&A)9`!R-S4P7T1E=FEC95]-86ME4F5A9$-A<&%C
-M:71Y,39487-K4F5Q=65S=`!R-S4P7VUV7V1I<V%B;&5?<F5G:7-T97)?<V5T
-M`'(W-3!?4T%405]0;W)T1&5V:6-E1&5T96-T960`<C<U,%]0;W)T7TAA;F1L
-M955N<&QU9P!R-S4P7T%405]#1$(R5&%S:T9I;&4`4F5M;W9E4T%31&5V:6-E
-M`'(W-3!?359?4F5M;W9E5&%R9V5T240`;V1I;E]S971?:&%R9%]D:7-K7VED
-M96YT:69Y`'(W-3!?4T=486)L95]!=F%I;&%B;&4`4&]R=$UA<%]2-S4P`'(W
-M-3!?4T%405]0<F5P87)E0V]M;6%N9%1A8FQE`$=E=$1E=DED96YT:69Y1G)A
-M;64`:3)C0E]R96%D7V)Y=&5S`'-A<U]A9&1R97-S7V-O=6YT`'(W-3!?27-S
-M=65?4F5P;W)T36%N=69A8W1U<F5R26YF;W)M871I;VX`<C<U,%]0<F5P87)E
-M1&5L:79E<GE1=65U945N=')Y`%5P9&%T94AI;5!A=&A)9`!R-S4P7T9I;F12
-M=6YN:6YG4F5Q0GE486<`<C<U,%]#;W)E7TUO9'5L95-H=71D;W=N`'(W-3!?
-M4$U?0V]R95]297%4:6UE;W5T`'(W-3!?17AP86YD97)?4TU04F5Q7T-A;&QB
-M86-K`'(W-3!?57!D871E5VED95!O<G10:'E-87``<C<U,%]305-?2&%N9&QE
-M0E)$0U-4`'(W-3!?07-S:6=N4F5G:7-T97)3970`<C<U,%]397)V:6-E26YT
-M97)R=7!T`'(W-3!?;79?9&ES86)L95]X;70`<C<U,%]335!297-P3&5N9W1H
-M`'5P9&%T95]D979I8V5?8V]N9FEG7W8R`'(W-3!?27-S=65?4F5P;W)T4F]U
-M=&5);F9O`'(W-3!?4&]S=$UA:V5397-%;F-L;W-U<F53=&%T=7-297%U97-T
-M`'(W-3!?17AP86YD97)?4TU04F5Q=65S=%]297!O<G1'96YE<F%L`'(W-3!?
-M1V5T4TU04V-R871C:$9R;VU0;V]L`'(W-3!?1&5V:6-E7TUA:V5);G%U:7)Y
-M5&%S:U)E<75E<W0`<C<U,%]#;W)E7TUO9'5L94=E=%)E<V]U<F-E475O=&$`
-M<C<U,%]!<W-I9VY$979I8V5%;&5M96YT3G5M8F5R`'(W-3!?4&]R=%]&:6YD
-M5&=T3F\`<C<U,%]31U!)3U]335!297%?0V%L;&)A8VL`<C<U,%]0;W)T7U-O
-M9G1297-E=$-A;&QB86-K`'(W-3!?;79?<F5S971?>&UT`'(W-3!?;79#:&%N
-M;F5L4W1A=&5-86-H:6YE`'(W-3!?4&]R=%]-;VYI=&]R`'(W-3!?4T%37U!O
-M<G1297-E=`!R-S4P7U!O<W1-86ME4V5S16QE;65N=$1E<V-R:7!T;W)297%U
-M97-T`'(W-3!?17AP86YD97)?4TU04F5Q=65S=%]297!O<G102%E3051!`'(W
-M-3!?23)#7TUO9'5L94EN:71I86QI>F4`<C<U,%]O9&EN7W)E;6]V95]D979I
-M8V4`<C<U,%]30U-)7T%405],;W=E<E=O<F0`<C<U,%]'971-87A.96=O=&EA
-M=&5D3&EN:U)A=&4`<C<U,%]'9710;W)T1G)O;5!O;VP`<C<U,%]-5E]$=6UP
-M4F5G:7-T97(`<C<U,%]%>'!A;F1E<E]335!297%U97-T7T1I<V-O=F5R`'(W
-M-3!?1&5V:6-E7TUA:V5297%U97-T5&%S:U)E<75E<W0`9&,W,C@P7U-'5&%B
-M;&5?07!P96YD`&1C-S(X,%]&<F5E4T%405-C<F%T8VA4;U!O;VP`9&,W,C@P
-M7U!O<G1?06)O<G1297%U97-T<P!D8S<R.#!?4T%405]0;W)T2&%N9&QE26YT
-M97)R=7!T`&1C-S(X,%]315-?4V5T1F%I;$QE9`!D8S<R.#!?4T%37TEN=&5R
-M;F%L4F5Q0V%L;&)A8VL`9&,W,C@P7TES<W5E7U)E<&]R=$UA;G5F86-T=7)E
-M<DEN9F]R;6%T:6]N`&1C-S(X,%]0;W)T7TUO;FET;W(`9&,W,C@P7T-O<F5?
-M36%K941E=FEC95)E<V5T4F5Q`&1C-S(X,%]30U-)7U1O7T9)4P!D8S<R.#!?
-M;V1I;E]R96UO=F5?9&5V:6-E`&1C-S(X,%]3051!7U!-26YI=%)E<4-A;&QB
-M86-K`&1C-S(X,%]035]#;W)E7U)E<51I;65O=70`9&,W,C@P7T1)4T-?1V5T
-M5&=T1&5V36%P`&1C-S(X,%]O9&EN7V9L87-H7V%C8V5S<P!D8S<R.#!?1G)E
-M95--4%-C<F%T8VA4;U!O;VP`9&,W,C@P7T1I<V-O=F5R>4-A;&Q"86-K`&1C
-M-S(X,%]486=?4F5L96%S94]N90!D8S<R.#!?0V]R95]-;V1U;&5396YD4F5Q
-M=65S=`!D8S<R.#!?359?36%P5&]3<&5C:69I8U1A<F=E=$E$`&1C-S(X,%]'
-M9710341E=FEC90!D8S<R.#!?4U107T1E=FEC95)E<V5T`&1C-S(X,%]'971#
-M;W)E0V]N=&5X=$9R;VU0;V]L`&1C-S(X,%]-5E]);FET:6%L:7IE5&%R9V5T
-M241486)L90!D8S<R.#!?4')E16UP='E$979I8V4`9&,W,C@P7T]D:6Y34$E?
-M26YI=`!D8S<R.#!?051!7T-$0C)487-K1FEL90!D8S<R.#!?4TU04F5S<$QE
-M;F=T:`!D8S<R.#!?;79?<F5S971?<&AY`&1C-S(X,%]0;W)T7T9I;F149W1.
-M;P!D8S<R.#!?4T=024]?5W)I=&5296=I<W1E<@!D8S<R.#!?0V]R95]);G1E
-M<G)U<'1397)V:6-E4F]U=&EN90!D8S<R.#!?;79?9&ES86)L95]X;70`9&,W
-M,C@P7U-!5$%?4&]R=$1E=&5C=`!D8S<R.#!?1G)E941E=FEC951O4&]O;`!D
-M8S<R.#!?17AP86YD97)?4TU04F5Q7T-A;&QB86-K`&1C-S(X,%]$979I8V5?
-M36%K95-E<U)C=D1I86=297%U97-T`&1C-S(X,%]0;W)T7U-O9G1297-E=$-A
-M;&QB86-K`&1C-S(X,%])<W-U95]#;VYF:6=2;W5T94EN9F\`9&,W,C@P7U!O
-M<G1?27-297%U97-T4G5N;FEN9P!D8S<R.#!?5F5R:69Y0V]M;6%N9$)E9F]R
-M95-E;F1I;F<`9&,W,C@P7T1E=FEC95]-86ME4W1A<G13=&]P56YI=%)E<75E
-M<W0`9&,W,C@P7T9R965%>'!A;F1E<E1O4&]O;`!D8S<R.#!?0V]R95)E<W1O
-M<F5/<FEG:6YA;$-$0@!D8S<R.#!?4&]S=$UA:V5397-%;F-L;W-U<F53=&%T
-M=7-297%U97-T`&1C-S(X,%]D=6UP7W5N87-S;V-I871E9%]F:7,`9&,W,C@P
-M7TU67UIE<F]-=E)E<75E<W0`9&,W,C@P7T=E=%!O<G1&<F]M4&]O;`!D8S<R
-M.#!?1FEN9$%S8VEI3G5M8F5R`&1C-S(X,%]305-?4&]R=%)E<V5T`&1C-S(X
-M,%]-5E]'971-87!P961)1`!D8S<R.#!?4T-325]!5$%?4F5A9%=R:71E5')A
-M;G-L871I;VX`9&,W,C@P7U!O<W1-86ME4V5S0V]N9FEG=7)A=&EO;E)E<75E
-M<W0`9&,W,C@P7T1E=FEC95]-86ME4F5Q=65S=%1A<VM297%U97-T`&1C-S(X
-M,%]0;W)T7TAA;F1L941E=FEC95!L=6=I;@!D8S<R.#!?4$U?07-S:6=N4F5G
-M:7-T97)3970`9&,W,C@P7T-O<F5?4F5S971#;613;&]T`&1C-S(X,%]M=E]D
-M:7-A8FQE7VAB80!D8S<R.#!?7U]A9&1?=&EM97(`9&,W,C@P7U-#4TE?36%K
-M94UO9&5086=E0V%C:&EN9P!D8S<R.#!?0T]215])<W-U95--4%)E<75E<W0`
-M9&,W,C@P7T%S<VEG;D1E=FEC94]V97)A;&Q%;&5M96YT3G5M8F5R`&1C-S(X
-M,%]7<FET941%3%9?45]%;G1R>0!D8S<R.#!?4T-325]!5$%?5F5R:69Y5')A
-M;G-L871I;VX`9&,W,C@P7V-O<F5?:&%N9&QE7W1A<VMF:6QE7V5R<F]R`&1C
-M-S(X,%]31U!)3U]335!297%U97-T7U=R:71E`&1C-S(X,%]305-?2&%N9&QE
-M0V]M<&QE=&5D0V]M;6%N9`!D8S<R.#!?1&5V:6-E7TUA:V5296%D0V%P86-I
-M='DQ-E1A<VM297%U97-T`&1C-S(X,%]0;W-T36%K95-E<T5L96UE;G13=&%T
-M=7-297%U97-T`&1C-S(X,%]3051!7U!-7TAA;F1L941E=FEC95!L=6=I;@!D
-M8S<R.#!?;V1I;E]S971?<W!I;E]U<%]M;V1E`&1C-S(X,%]#;W)E7TAA;F1L
-M95=A:71I;F=,:7-T`&1C-S(X,%]0<F5P87)E1&5L:79E<GE1=65U945N=')Y
-M`&1C-S(X,%]31U!)3U]335!297%U97-T7U)E860`9&,W,C@P7T1)4T-?0V%N
-M8V5L1&ES8V]V97(`9&,W,C@P7U5P9&%T95=I9&50;W)T4&AY36%P`&1C-S(X
-M,%](86YD;&5#;VUM86YD475E=64`9&,W,C@P7T1)4T-?1V5T4F5S;W5R8V4`
-M9&,W,C@P7U-#4TE?051!7T9I;&Q,0D%#9&(Q-@!D8S<R.#!?0V]R95]-;V1U
-M;&5%;F%B;&5$:7-A8FQE25)1`&1C-S(X,%]I,F-?<F5S970`9&,W,C@P7T9R
-M965296=I<W1E<E-E=`!D8S<R.#!?0F5E<$]F9@!D8S<R.#!?1$E30U]#:&5C
-M:T1I<V-O=F5R4W1A=&4`9&,W,C@P7T5X<&%N9&5R7U--4%)E<75E<W1?4F5P
-M;W)T1V5N97)A;`!D8S<R.#!?23)#7TUO9'5L94EN:71I86QI>F4`9&,W,C@P
-M7V1E=FEC95]P<F]B95]D;VYE`&1C-S(X,%]296UO=F5$979I8V4`9&,W,C@P
-M7U)U;G1I;65)<W-U95-O9G1297-E=$-A;&QB86-K`&1C-S(X,%]31U!)3U]3
-M971?1F%I;&QE9`!D8S<R.#!?1V5T36%X3F5G;W1I871E9$QI;FM2871E`&1C
-M-S(X,%]&<F5E4T534T)4;U!O;VP`9&,W,C@P7TQI<W1?1V5T3&%S=`!D8S<R
-M.#!?4$U?27-S=657<FET95)E9P!D8S<R.#!?<V5T7V9A:6Q?;&5D`&1C-S(X
-M,%]486=?27-%;7!T>0!D8S<R.#!?57!D871E5&=T1&5V36%P`&1C-S(X,%]4
-M86=?26YI=`!D8S<R.#!?4T%405]034AO='!L=6=297%#86QL8F%C:P!D8S<R
-M.#!?4&]S=$UA:V5397-%;&5M96YT1&5S8W)I<'1O<E)E<75E<W0`9&,W,C@P
-M7T9R9650;W)T5&]0;V]L`&1C-S(X,%]-5E]-87!487)G971)1`!D8S<R.#!?
-M4$U?27-S=65296%D4F5G`&1C-S(X,%]#;W)E7TUO9'5L95-H=71D;W=N`&1C
-M-S(X,%]5<&1A=&50:'E);F9O`&1C-S(X,%]?7W)E;F5W7W1I;65R`&1C-S(X
-M,%]$979I8V5?36%K95)E861#87!A8VET>51A<VM297%U97-T`&1C-S(X,%]'
-M971$979I8V5&<F]M4&]O;`!D8S<R.#!?1V5T4T534T)&<F]M4&]O;`!D8S<R
-M.#!?07-S:6=N16QE;65N=%-L;W1.=6UB97(`9&,W,C@P7U!O<G1?2&%N9&QE
-M56YP;'5G`&1C-S(X,%]#;W)E7TUO9'5L95-T87)T`&1C-S(X,%]$:7-C;W9E
-M<GE330!D8S<R.#!?4T-325]!5$%?0VAE8VM#;VYD:71I;VX`9&,W,C@P7TU6
-M7T-O<'E31U1A8FQE`&1C-S(X,%]3051!7T1E=FEC95-T871E36%C:&EN90!D
-M8S<R.#!?1&5V:6-E7TUA:V5);G%U:7)Y5&%S:U)E<75E<W0`9&,W,C@P7T1E
-M=FEC95]087)S94ED96YT:69Y1&%T80!D8S<R.#!?4T%44V5N<V5$871A`&1C
-M-S(X,%]'971.0U%486<`9&,W,C@P7VUV0VAA;FYE;%-T871E36%C:&EN90!D
-M8S<R.#!?4W1O<F5?0V]N9FEG4F]U=&5);F9O`&1C-S(X,%]31U1A8FQE7TEN
-M:70`9&,W,C@P7T=E=$5X<&%N9&5R1G)O;5!O;VP`9&,W,C@P7U-!4U](86YD
-M;&5"4D1#4U0`9&,W,C@P7T-O<F53879E3W)I9VEN86Q#1$(`9&,W,C@P7TU6
-M7T1U;7!297%U97-T`&1C-S(X,%],:7-T7T=E=$9I<G-T`&1C-S(X,%]30U-)
-M7T%405]&:6QL1&%T849I96QD`&1C-S(X,%]30U-)7T%405]3>6YC0V%C:&54
-M<F%N<VQA=&EO;@!D8S<R.#!?4T=024]?26YI=&EA;&EZ90!D8S<R.#!?1G)E
-M95--4$-O;G1E>'0`9&,W,C@P7T9I;&Q%;F-L;W-U<F5%;&5M96YT4W1A='5S
-M`&1C-S(X,%]#;W)E7TUO9'5L94EN:71I86QI>F4`9&,W,C@P7U-!5$%?4$U3
-M=&%T94UA8VAI;F4`9&,W,C@P7T9R9650351O4&]O;`!D8S<R.#!?4T%405]0
-M<F5P87)E0V]M;6%N9%1A8FQE`&1C-S(X,%]#;W)E7TUO9'5L94=E=%)E<V]U
-M<F-E475O=&$`9&,W,C@P7T9R96531T)U9F9E<E1O4&]O;`!D8S<R.#!?5&%G
-M7TEN:71?1DE&3P!D8S<R.#!?4T-325]!5$%?4F5A9$-A<&%C:71Y5')A;G-L
-M871I;VY#86QL8F%C:P!D8S<R.#!?7U]035]C86YC96Q?=&EM97(`9&,W,C@P
-M7TU67T1U;7!296=I<W1E<@!D8S<R.#!?4V5R=FEC94EN=&5R<G5P=`!D8S<R
-M.#!?27-S=65?1&ES8V]V97(`9&,W,C@P7T1)4T-?1&]$:7-C;W9E<@!D8S<R
-M.#!?4T%405](86YD;&5$979I8V55;G!L=6<`9&,W,C@P7T-O<F5?26YT97)N
-M86Q396YD4F5Q=65S=`!D8S<R.#!?1$E30U]3971297-O=7)C90!D8S<R.#!?
-M4T%405]035](86YD;&5$979I8V55;G!L=6<`9&,W,C@P7U-!5$%?4&]R=$1E
-M=FEC941E=&5C=&5D`&1C-S(X,%]5<&1A=&5487)G971$979I8V5S`&1C-S(X
-M,%]30U-)7T%405]3=&%R=%-T;W!4<F%N<VQA=&EO;@!D8S<R.#!?0V]R95]P
-M87-S7W1H<G5?9FEL;%]T87-K9FEL90!D8S<R.#!?;79?9&ES86)L95]R96=I
-M<W1E<E]S970`9&,W,C@P7T%S<VEG;D1E=FEC945L96UE;G1.=6UB97(`9&,W
-M,C@P7T=E=$UI;DYE9V]T:6%T961,:6YK4F%T90!D8S<R.#!?;79?<V5T7U-!
-M4T%D9'(`9&,W,C@P7U!-7T9R965296=I<W1E<E-E=`!D8S<R.#!?17AP86YD
-M97)?4TU04F5Q=65S=%]0:'E#;VYT<F]L`&1C-S(X,%]-5E]%<75A;',`9&,W
-M,C@P7T=E=%-'0G5F9F5R1G)O;5!O;VP`9&,W,C@P7U-#4TE?051!7TQO=V5R
-M5V]R9`!D8S<R.#!?0VAE8VM$979I8V5#:&%N9V4`9&,W,C@P7U-!4U]%<G)O
-M<DAA;F1L:6YG`&1C-S(X,%]"965P3VX`9&,W,C@P7U-'4$E/7U--4%)E<5]#
-M86QL8F%C:P!D8S<R.#!?4T=486)L95]!=F%I;&%B;&4`9&,W,C@P7U--4%]3
-M1U!)3U]3971?1F%I;&QE9`!D8S<R.#!?0V]R95]&:6QL4V5N<V5$871A`&1C
-M-S(X,%]'971335!38W)A=&-H1G)O;5!O;VP`9&,W,C@P7U-!5$%?4&]R=$1E
-M=FEC95)E861Y`&1C-S(X,%]M=E]E;F%B;&5?>&UT`&1C-S(X,%]!<W-I9VY2
-M96=I<W1E<E-E=`!D8S<R.#!?;V1I;E]I;V-T;`!D8S<R.#!?27-S=65?4F5P
-M;W)T4F]U=&5);F9O`&1C-S(X,%]'971);G1E<FYA;%)E<49R;VU0;V]L`&1C
-M-S(X,%]#:&5C:U1A<F=E=$-H86YG90!D8S<R.#!?1&5V:6-E7U=R:71E4V5S
-M0V]N=')O;$1I86<`9&,W,C@P7T-O;7!L971E4F5Q=65S=`!D8S<R.#!?4G5N
-M=&EM94ES<W5E4V]F=%)E<V5T`&1C-S(X,%]$979I8V5?27-S=653;V9T4F5S
-M970`9&,W,C@P7U-!5$%?2&%N9&QE1&5V:6-E4&QU9VEN`&1C-S(X,%]0<F5P
-M87)E06YD4V5N9$-O;6UA;F0`9&,W,C@P7U!R945M<'1Y4$T`9&,W,C@P7U-#
-M4TE?36%K94-A8VAE0V]M;6%N9`!D8S<R.#!?0V]M<&QE=&5297%U97-T06YD
-M4VQO=`!D8S<R.#!?1$E30U]'971.96=O=&EA=&5D3&EN:U)A=&4`9&,W,C@P
-M7T9I;F12=6YN:6YG4F5Q0GE486<`9&,W,C@P7W-E=%]F86EL7VQE9',`9&,W
-M,C@P7T9I;F1&<F5E4TU00V]N=&5X=`!D8S<R.#!?4T%37T1E=FEC95-T871E
-M36%C:&EN90!D8S<R.#!?1FEN9%1G=$YO`&1C-S(X,%])<W-U95]297!O<G1'
-M96YE<F%L`&1C-S(X,%]#86QC=6QA=&52;W5T94EN9&5X`&1C-S(X,%]M=E]R
-M97-E=%]X;70`9&,W,C@P7TU67T-20P!D8S<R.#!?4T-325]!5$%?4F5A9$-A
-M<&%C:71Y5')A;G-L871I;VX`9&,W,C@P7TU67U)E;6]V951A<F=E=$E$`&1C
-M-S(X,%]3051!7U!-7T5R<F]R2&%N9&QI;F<`9&,W,C@P7U5P9&%T95-T871U
-M<U9S4V5S0V]N=')O;$)U9F9E<@!D8S<R.#!?0V]R95]'9713=7!P;W)T961#
-M;W5N=',`9&,W,C@P7TU67U-E=$Q"06%N9%-E8W1O<D-O=6YT`&1C-S(X,%]$
-M979I8V5?36%K94UO9&5396QE8W1297%U97-T`&1C-S(X,%]'971/;F5#;VUM
-M86YD4VQO=`!D8S<R.#!?4T=024]?4F5A9%)E9VES=&5R`&1C-S(X,%]%>'!A
-M;F1E<E]335!297%U97-T7U)E<&]R=%!(65-!5$$`9&,W,C@P7U!O<G1?2&%N
-M9&QE4&QU9VEN`&1C-S(X,%]#;W)E7U)E<51I;65O=70`9&,W,C@P7VUO9&50
-M86=E0G5F`&1C-S(X,%]2=6YT:6UE27-S=65296%D3&]G17AT`&1C-S(X,%]3
-M0U-)7T%405]5<'!E<E=O<F0`9&,W,C@P7T9R965#;W)E0V]N=&5X=%1O4&]O
-M;`!D8S<R.#!?4T537TEN=&5R;F%L4F5Q0V%L;&)A8VL`9&,W,C@P7U-!5$%?
-M17)R;W)(86YD;&EN9P!D8S<R.#!?1V5T4$U&<F]M4&]O;`!D8S<R.#!?1&5T
-M96-T4&]R=%1Y<&4`9&,W,C@P7T1E=FEC95]-86ME36]D95-E;G-E4F5Q=65S
-M=`!D8S<R.#!?4T-325]!5$%?1FEL;$Q"04-D8C$P`&1C-S(X,%]?7V-A;F-E
-M;%]T:6UE<@!D8S<R.#!?4T%405]0;W)T4F5S970`9&,W,C@P7V]D:6Y?<V5T
-M7VED;&5?<W1A;F1B>0!D8S<R.#!?17AP86YD97)?4TU04F5Q=65S=%]$:7-C
-M;W9E<@!D8S<R.#!?5&%G7T=E=$]N90!D8S<R.#!?4T%405]0<F5P87)E0V]M
-M;6%N9$AE861E<@!D8S<R.#!?0V%T96=O<GE?0T1"7U1Y<&4`9&,W,C@P7T9R
-M965);G1E<FYA;%)E<51O4&]O;`!D8S<R.#!?1V5T4T%405-C<F%T8VA&<F]M
-M4&]O;`!3=V%P2'!T365T858S`&QD;5]S<&EN=7!?=F1E=@!R87=?8VAE8VM?
-M9&ES:U]D97-C<FEP=&]R`&QD;5]C:&5C:U]A<G)A>0!L9&U?<F5C:&5C:U]A
-M;&P`=F1E=E]C;&%S<U]L:7-T`')A=U]I9&QE7W1I;65R7W)E<V5T`&QD;5]D
-M96QE=&5?<&%R=&ET:6]N`&QD;5]S>6YC7V-H86YG961?87)R87ES`&=R96)U
-M:6QD;VYE<G)O<@!L9&U?<75E=65?979E;G0`=')A;G-F;W)M7VYE961E9`!L
-M9&U?8VAE8VM?=')A;G-F;W)M`&QD;5]F:7AU<%]A<G)A>5]S=&%T90!C86QC
-M7W)E8G5I;&1?<')O9W)E<W,`=F)U<U]E>'1?<VEZ90!S971?=')A;G-F;W)M
-M7W-T97!?:6YF;P!L9&U?:61L95]T:6UE<@!L9&U?9FEN9%]V9&5V7W)A=P!L
-M9&U?<F5P<F]B95]D979I8V4`8V%L8U]T<F%N<V9O<FU?<')O9W)E<W,`;&1M
-M7V9I;F1?=F1E=E]C;&%S<P!L9&U?86QL;V-?<&%R=&ET:6]N`&QD;5]I;FET
-M7V1I<VL`<F5F<F5S:%]R87=?9&5V7VEN9F\`7V1E;&5T95]R87=?<&%R=`!R
-M87=?<F5A9%]W<FET95]S96-T;W)S`&=I9&QE<W1A;F1B>71I;65O=70`<F%W
-M7V-H96-K7V%R<F%Y7V1E<V-R:7!T;W(`;&1M7V-R96%T95]V9&5V7W)A=P!U
-M;G!L=6=?<F%W7W9D978`0VAE8VM3=6T`8V]M<&%R95]S;&]T7W-E<5]B>5]P
-M8VEA9&1R`&QD;5]A9&1?9&ES:U]T;U]A<G)A>0!L9&U?<WEN8U]D:7-K7VEN
-M9F\`9V5T7V)I=',`4W=A<$AP=$UE=&%6-`!R87=?8V]N=F5R=%]S<&%R95]T
-M;U]L96=A8WD`9DYO=&EF>4=520!L9&U?9FQU<VA?86QL7W1A<F=E=',`;&1M
-M7W-T87)T7W)E8G5I;&0`;&1M7W-P:6YD;W=N7V%L;%]R87=D979S`%]?;&1M
-M7V9I;FES:%]C;60`241?5$]?5D1%5@!?7W9D979?<75E=65?8VUD`')A=U]I
-M9&QE7W1I;65R7V-H96-K`&=E=%]S=')I<%]I;F9O`&QD;5]R97-U;65?861A
-M<'1E<@!H<'1N<E]L9&U?<F5G:7-T97)?:&EM7U)?-E\U-5\W-5\T-E\V-`!H
-M<'1N<E]G1VQO8F%L3F-Q1FQA9P!H<'1N<E]O<U]R97%U97-T7W1I;65R`&AP
-M=&YR7V1M87!O;VQ?9V5T7W!A9V4`:'!T;G)?;W-?9V5T7W-T86UP`&AP=&YR
-M7VQD;5]S=7-P96YD`&AP=&YR7VQD;5]I9&QE`&AP=&YR7VQD;5]G971?;65M
-M7VEN9F\`:'!T;G)?;&1M7W)E;6]V95]T:6UE<@!H<'1N<E]P8VEC9F=?<F5A
-M9%]D=V]R9`!H<'1N<E]D;6%P;V]L7VUA:V5?;W)D97(`:'!T;G)?;&1M7V=E
-M=%]V8G5S7V5X=`!H<'1N<E]L9&U?<F5L96%S95]V9&5V`&AP=&YR7V9R965L
-M:7-T7W)E<V5R=F5?9&UA`&AP=&YR7VQD;5]I;G1R`&UE;6-P>0!H<'1N<E]L
-M9&U?;VY?=&EM97(`:'!T;G)?;&1M7V=E=%]C;61?<VEZ90!H<'1N<E]L9&U?
-M9G)E95]C;61S`&AP=&YR7VQD;5]C<F5A=&5?=F1E=@!H<'1N<E]L9&U?861D
-M7W-P87)E7W1O7V%R<F%Y`&AP=&YR7V=R96)U:6QD<')I;W)I='D`:'!T;G)?
-M;&1M7W-Y;F-?87)R87E?:6YF;P!H<'1N<E]O<U]M87!?<&-I7V)A<@!H<'1N
-M<E]?7VQD;5]A;&QO8U]C;60`:'!T;G)?:6YI=%]M;V1U;&5?=F1E=E]R87<`
-M:'!T;G)?;&1M7W-E=%]A=71O<F5B=6EL9`!H<'1N<E]?7V1U;6UY7W)E9P!H
-M<'1N<E]D;6%P;V]L7V%C=&EV90!H<'1N<E]V8G5S7VQI<W0`:'!T;G)?;&1M
-M7W%U975E7W9B=7-?9'!C`&AP=&YR7VQD;5]R97-E=%]V8G5S`&AP=&YR7V=3
-M1U!)3U!A<G13=7!P;W)T`&AP=&YR7VEN:71?;6]D=6QE7VAI;5]R-S4P`&AP
-M=&YR7VQD;5]R96QE87-E7VQO8VL`:'!T;G)?;W-?=6YM87!?<&-I7V)A<@!H
-M<'1N<E]L9&U?<VAU=&1O=VX`:'!T;G)?:&EM7VQI<W0`:'!T;G)?;&1M7W)E
-M<75E<W1?=&EM97(`:'!T;G)?;&1M7W)E<W5M90!H<'1N<E]L9&U?9V5T7V1E
-M=FEC95]I9`!H<'1N<E]O<U]S8VAE9'5L95]T87-K`&AP=&YR7VQD;5]I;V-T
-M;`!H<'1N<E]G4W!I;G5P3VYE1&5V16%C:%1I;64`:'!T;G)?9G)E96QI<W1?
-M<'5T`&AP=&YR7V]S7W-T86QL97AE8P!H<'1N<E]G7VQE9V%C>5]M;V1E`&AP
-M=&YR7VQD;5]A;&QO8U]C;61S7U)?-E\U-5\W-5\T-E\V-`!H<'1N<E]L9&U?
-M<G5N`&AP=&YR7VEN:71?;6]D=6QE7VAI;5]D8S<R.#``:'!T;G)?;&1M7V9R
-M965?8VUD<U]T;U]L:7-T`&AP=&YR7V]S7VUA>%]C86-H95]S:7IE`&AP=&YR
-M7W9D979?<75E=65?8VUD`&AP=&YR7V]S7V=E=%]V8G5S7W-E<0!H<'1N<E]L
-M9&U?<WEN8U]A<G)A>5]S=&%M<`!H<'1N<E]L9&U?<75E=65?8VUD`&AP=&YR
-M7V]S7W!R:6YT:P!H<'1N<E]F<F5E;&ES=%]R97-E<G9E`&AP=&YR7V1M87!O
-M;VQ?<'5T7W!A9V4`:'!T;G)?9G)E96QI<W1?9V5T`&AP=&YR7VQD;5]U;G)E
-M9VES=&5R7V1E=FEC90!H<'1N<E]L9&U?<F5G:7-T97)?861A<'1E<@!H<'1N
-M<E]G875T;W)E8G5I;&0`:'!T;G)?;&1M7V=E=%]V8G5S7W-I>F4`:'!T;G)?
-M9&5L87E?8F5T=V5E;E]S<&EN=7``:'!T;G)?;&1M7V=E;F5R:6-?;65M8F5R
+M4W1A<G0`<C<U,%]#;W)E7TAA;F1L95=A:71I;F=,:7-T`'(W-3!?4')E16UP
+M='E030!R-S4P7U-!5$%?2&%N9&QE1&5V:6-E4&QU9VEN`'(W-3!?4T-325]4
+M;U]&25,`<C<U,%]3051!7U!O<G1297-E=`!R-S4P7T=E=$]N94-O;6UA;F13
+M;&]T`'(W-3!?;79?<F5S971?<&AY`'(W-3!?5W)I=&5$14Q67U%?16YT<GD`
+M<C<U,%]O9&EN7W-E=%]I9&QE7W-T86YD8GD`<C<U,%]'9710349R;VU0;V]L
+M`'(W-3!?359?17%U86QS`'(W-3!?2&%N9&QE0V]M;6%N9%%U975E`'!M7VEN
+M:71?<F5Q7V-A;&QB86-K`'(W-3!?4T-325]!5$%?4F5A9%=R:71E5')A;G-L
+M871I;VX`<C<U,%]31U1A8FQE7T%P<&5N9`!R-S4P7U!-7T%S<VEG;E)E9VES
+M=&5R4V5T`'!O<G1?<V5T7V9A:6Q?;&5D`'(W-3!?4T%405]$979I8V53=&%T
+M94UA8VAI;F4`<C<U,%]0<F5%;7!T>41E=FEC90!R-S4P7U]?8V%N8V5L7W1I
+M;65R`'(W-3!?0V]R95]P87-S7W1H<G5?9FEL;%]T87-K9FEL90!R-S4P7U-'
+M4$E/7TEN:71I86QI>F4`<C<U,%]0;W)T7TAA;F1L941E=FEC95!L=6=I;@!R
+M-S4P7U-'4$E/7U-E=%]&86EL;&5D`'-E=%]P;5]F86EL7VQE9',`<C<U,%]-
+M5E]#;W!Y4T=486)L90!U<&1A=&5?9&5V:6-E7V-O;F9I9P!R-S4P7T-O<F5?
+M36]D=6QE16YA8FQE1&ES86)L94E240!R-S4P7U1A9U]);FET7T9)1D\`36%K
+M941E=DEN9F\`4$U?27-S=657<FET949A:6Q,960`<C<U,%]O9&EN7V9L87-H
+M7V%C8V5S<P!3051!7U!-4W1A=&5-86-H:6YE4W!I;E5P`'(W-3!?4T%405]0
+M;W)T1&5V:6-E4F5A9'D`<C<U,%]486=?4F5L96%S94]N90!R-S4P7T9R9653
+M1T)U9F9E<E1O4&]O;`!R-S4P7T1E=&5C=%!O<G14>7!E`'!M7VUA:V5?<&U?
+M<F5G:7-T97)?<F5Q`'(W-3!?1&5V:6-E7U!A<G-E261E;G1I9GE$871A`'(W
+M-3!?9&5V:6-E7W!R;V)E7V1O;F4`<C<U,%]"965P3V9F`&=E=%]F:7)S=%]P
+M;0!/9&EN4U!)7U-E8W1O<E5N<')O=&5C=`!P;5]W86ET7V9O<E]S<&EN=7``
+M<C<U,%]31U1A8FQE7TEN:70`<C<U,%]3051!7U!-7T5R<F]R2&%N9&QI;F<`
+M4T%405](86YD;&5035](;W10;'5G`'(W-3!?4T-325]!5$%?1FEL;$Q"04-D
+M8C$V`$=E=$%T=$ED96YT:69Y1G)A;64`<C<U,%]#871E9V]R>5]#1$)?5'EP
+M90!R-S4P7TQI<W1?1V5T3&%S=`!R-S4P7T9R9650351O4&]O;`!R-S4P7VUV
+M7V1I<V%B;&5?<F5G:7-T97)?<V5T`'(W-3!?4T%405]0;W)T1&5V:6-E1&5T
+M96-T960`<C<U,%]0;W)T7TAA;F1L955N<&QU9P!R-S4P7T%405]#1$(R5&%S
+M:T9I;&4`<C<U,%]-5E]296UO=F5487)G971)1`!O9&EN7W-E=%]H87)D7V1I
+M<VM?:61E;G1I9GD`<C<U,%]31U1A8FQE7T%V86EL86)L90!0;W)T36%P7U(W
+M-3``1V5T1&5V261E;G1I9GE&<F%M90!I,F-"7W)E861?8GET97,`<V%S7V%D
+M9')E<W-?8V]U;G0`<&U?<W1A=&5?;6%C:&EN90!R-S4P7U!R97!A<F5$96QI
+M=F5R>5%U975E16YT<GD`57!D871E2&EM4&%T:$ED`'(W-3!?0V]R95]-;V1U
+M;&53:'5T9&]W;@!R-S4P7U!-7T-O<F5?4F5Q5&EM96]U=`!R-S4P7U5P9&%T
+M95=I9&50;W)T4&AY36%P`'(W-3!?07-S:6=N4F5G:7-T97)3970`<C<U,%]3
+M97)V:6-E26YT97)R=7!T`'(W-3!?;79?9&ES86)L95]X;70`=7!D871E7V1E
+M=FEC95]C;VYF:6=?=C(`<C<U,%]#;W)E7TUO9'5L94=E=%)E<V]U<F-E475O
+M=&$`<C<U,%]0;W)T7U-O9G1297-E=$-A;&QB86-K`'(W-3!?;79?<F5S971?
+M>&UT`'(W-3!?;79#:&%N;F5L4W1A=&5-86-H:6YE`'(W-3!?23)#7TUO9'5L
+M94EN:71I86QI>F4`<C<U,%]O9&EN7W)E;6]V95]D979I8V4`<C<U,%]'9710
+M;W)T1G)O;5!O;VP`<C<U,%]-5E]$=6UP4F5G:7-T97(`<&U?:&]T7W!L=6=?
+M<F5Q7V-A;&QB86-K`%!-7TES<W5E4F5A9$9A:6Q,960`9&,W,C@P7U-'5&%B
+M;&5?07!P96YD`$UA:V5!='1$979);F9O`&1C-S(X,%]&<F5E4T%405-C<F%T
+M8VA4;U!O;VP`9&,W,C@P7U!O<G1?06)O<G1297%U97-T<P!035]7<FET95)E
+M9U-Y;F,`9&,W,C@P7U-!5$%?4&]R=$AA;F1L94EN=&5R<G5P=`!D8S<R.#!?
+M4T537U-E=$9A:6Q,960`9&,W,C@P7U-!4U]);G1E<FYA;%)E<4-A;&QB86-K
+M`&1C-S(X,%])<W-U95]297!O<G1-86YU9F%C='5R97));F9O<FUA=&EO;@!D
+M8S<R.#!?4&]R=%]-;VYI=&]R`&1C-S(X,%]#;W)E7TUA:V5$979I8V5297-E
+M=%)E<0!D8S<R.#!?4T-325]4;U]&25,`9&,W,C@P7V]D:6Y?<F5M;W9E7V1E
+M=FEC90!D8S<R.#!?4T%405]034EN:71297%#86QL8F%C:P!D8S<R.#!?4$U?
+M0V]R95]297%4:6UE;W5T`&1C-S(X,%]$25-#7T=E=%1G=$1E=DUA<`!D8S<R
+M.#!?;V1I;E]F;&%S:%]A8V-E<W,`9&,W,C@P7T9R965335!38W)A=&-H5&]0
+M;V]L`&1C-S(X,%]$:7-C;W9E<GE#86QL0F%C:P!D8S<R.#!?5&%G7U)E;&5A
+M<V5/;F4`9&,W,C@P7T-O<F5?36]D=6QE4V5N9%)E<75E<W0`9&,W,C@P7TU6
+M7TUA<%1O4W!E8VEF:6-487)G971)1`!D8S<R.#!?1V5T4$U$979I8V4`9&,W
+M,C@P7U-44%]$979I8V5297-E=`!D8S<R.#!?1V5T0V]R94-O;G1E>'1&<F]M
+M4&]O;`!D8S<R.#!?359?26YI=&EA;&EZ951A<F=E=$E$5&%B;&4`9&,W,C@P
+M7U!R945M<'1Y1&5V:6-E`&1C-S(X,%]/9&EN4U!)7TEN:70`9&,W,C@P7T%4
+M05]#1$(R5&%S:T9I;&4`9&,W,C@P7U--4%)E<W!,96YG=&@`9&,W,C@P7VUV
+M7W)E<V5T7W!H>0!$979I8V5?36%K95!R:79A=&5396YD4V5S4F5Q=65S=`!D
+M8S<R.#!?4&]R=%]&:6YD5&=T3F\`07-S:6=N16QE;65N1&5S8W)I<'1O<DYA
+M;64`9&,W,C@P7U-'4$E/7U=R:71E4F5G:7-T97(`1&5V:6-E7TUA:V5397-%
+M;&5M96YT4W1A='5S4F5Q=65S=%1I;65R`&1C-S(X,%]#;W)E7TEN=&5R<G5P
+M=%-E<G9I8V52;W5T:6YE`&1C-S(X,%]M=E]D:7-A8FQE7WAM=`!D8S<R.#!?
+M4T%405]0;W)T1&5T96-T`%!-7U)E861296=3>6YC`&1C-S(X,%]&<F5E1&5V
+M:6-E5&]0;V]L`&1C-S(X,%]%>'!A;F1E<E]335!297%?0V%L;&)A8VL`9&,W
+M,C@P7T1E=FEC95]-86ME4V5S4F-V1&EA9U)E<75E<W0`9&,W,C@P7U!O<G1?
+M4V]F=%)E<V5T0V%L;&)A8VL`9&,W,C@P7TES<W5E7T-O;F9I9U)O=71E26YF
+M;P!D8S<R.#!?4&]R=%])<U)E<75E<W12=6YN:6YG`&1C-S(X,%]697)I9GE#
+M;VUM86YD0F5F;W)E4V5N9&EN9P!D8S<R.#!?1&5V:6-E7TUA:V53=&%R=%-T
+M;W!5;FET4F5Q=65S=`!D8S<R.#!?1G)E945X<&%N9&5R5&]0;V]L`&1C-S(X
+M,%]#;W)E4F5S=&]R94]R:6=I;F%L0T1"`&1C-S(X,%]0;W-T36%K95-E<T5N
+M8VQO<W5R95-T871U<U)E<75E<W0`9&,W,C@P7V1U;7!?=6YA<W-O8VEA=&5D
+M7V9I<P!D8S<R.#!?359?6F5R;TUV4F5Q=65S=`!D8S<R.#!?1V5T4&]R=$9R
+M;VU0;V]L`&1C-S(X,%]&:6YD07-C:6E.=6UB97(`9&,W,C@P7U-!4U]0;W)T
+M4F5S970`9&,W,C@P7TU67T=E=$UA<'!E9$E$`&1C-S(X,%]30U-)7T%405]2
+M96%D5W)I=&54<F%N<VQA=&EO;@!D8S<R.#!?4&]S=$UA:V5397-#;VYF:6=U
+M<F%T:6]N4F5Q=65S=`!D8S<R.#!?1&5V:6-E7TUA:V5297%U97-T5&%S:U)E
+M<75E<W0`9&,W,C@P7U!O<G1?2&%N9&QE1&5V:6-E4&QU9VEN`&1C-S(X,%]0
+M35]!<W-I9VY296=I<W1E<E-E=`!D8S<R.#!?0V]R95]297-E=$-M9%-L;W0`
+M9&,W,C@P7VUV7V1I<V%B;&5?:&)A`&1C-S(X,%]?7V%D9%]T:6UE<@!D8S<R
+M.#!?4T-325]-86ME36]D95!A9V5#86-H:6YG`&1C-S(X,%]#3U)%7TES<W5E
+M4TU04F5Q=65S=`!S971?96U?9F%I;%]L960`9&,W,C@P7T%S<VEG;D1E=FEC
+M94]V97)A;&Q%;&5M96YT3G5M8F5R`&1C-S(X,%]7<FET941%3%9?45]%;G1R
+M>0!D8S<R.#!?4T-325]!5$%?5F5R:69Y5')A;G-L871I;VX`9&,W,C@P7V-O
+M<F5?:&%N9&QE7W1A<VMF:6QE7V5R<F]R`&1C-S(X,%]31U!)3U]335!297%U
+M97-T7U=R:71E`&1C-S(X,%]305-?2&%N9&QE0V]M<&QE=&5D0V]M;6%N9`!D
+M8S<R.#!?1&5V:6-E7TUA:V5296%D0V%P86-I='DQ-E1A<VM297%U97-T`&1C
+M-S(X,%]0;W-T36%K95-E<T5L96UE;G13=&%T=7-297%U97-T`&1C-S(X,%]3
+M051!7U!-7TAA;F1L941E=FEC95!L=6=I;@!D8S<R.#!?;V1I;E]S971?<W!I
+M;E]U<%]M;V1E`&1C-S(X,%]#;W)E7TAA;F1L95=A:71I;F=,:7-T`&1C-S(X
+M,%]0<F5P87)E1&5L:79E<GE1=65U945N=')Y`&1C-S(X,%]31U!)3U]335!2
+M97%U97-T7U)E860`9&,W,C@P7T1)4T-?0V%N8V5L1&ES8V]V97(`9&,W,C@P
+M7U5P9&%T95=I9&50;W)T4&AY36%P`&1C-S(X,%](86YD;&5#;VUM86YD475E
+M=64`9&,W,C@P7T1)4T-?1V5T4F5S;W5R8V4`9&,W,C@P7U-#4TE?051!7T9I
+M;&Q,0D%#9&(Q-@!D8S<R.#!?0V]R95]-;V1U;&5%;F%B;&5$:7-A8FQE25)1
+M`&1C-S(X,%]I,F-?<F5S970`9&,W,C@P7T9R965296=I<W1E<E-E=`!D8S<R
+M.#!?0F5E<$]F9@!S971?96U?9F%I;%]L961S`&1C-S(X,%]$25-#7T-H96-K
+M1&ES8V]V97)3=&%T90!D8S<R.#!?17AP86YD97)?4TU04F5Q=65S=%]297!O
+M<G1'96YE<F%L`&1C-S(X,%]),D-?36]D=6QE26YI=&EA;&EZ90!D8S<R.#!?
+M9&5V:6-E7W!R;V)E7V1O;F4`9&,W,C@P7U)E;6]V941E=FEC90!D8S<R.#!?
+M4G5N=&EM94ES<W5E4V]F=%)E<V5T0V%L;&)A8VL`9&,W,C@P7U-'4$E/7U-E
+M=%]&86EL;&5D`&1C-S(X,%]'971-87A.96=O=&EA=&5D3&EN:U)A=&4`9&,W
+M,C@P7T9R965315-30E1O4&]O;`!D8S<R.#!?3&ES=%]'971,87-T`&1C-S(X
+M,%]035])<W-U95=R:71E4F5G`&1C-S(X,%]S971?9F%I;%]L960`9&,W,C@P
+M7U1A9U])<T5M<'1Y`&1C-S(X,%]5<&1A=&549W1$979-87``9&,W,C@P7U1A
+M9U]);FET`&=E=%]I9%]F<F]M7V5N8TED`%-%4U]0<FEV871E4F5Q0V%L;&)A
+M8VL`9&,W,C@P7U-!5$%?4$U(;W1P;'5G4F5Q0V%L;&)A8VL`4T%37U)E<&]R
+M=$QU;E-C86X`9&,W,C@P7U!O<W1-86ME4V5S16QE;65N=$1E<V-R:7!T;W)2
+M97%U97-T`&1C-S(X,%]&<F5E4&]R=%1O4&]O;`!D8S<R.#!?359?36%P5&%R
+M9V5T240`9&,W,C@P7U!-7TES<W5E4F5A9%)E9P!D8S<R.#!?0V]R95]-;V1U
+M;&53:'5T9&]W;@!D8S<R.#!?57!D871E4&AY26YF;P!D8S<R.#!?7U]R96YE
+M=U]T:6UE<@!D8S<R.#!?1&5V:6-E7TUA:V5296%D0V%P86-I='E487-K4F5Q
+M=65S=`!D8S<R.#!?1V5T1&5V:6-E1G)O;5!O;VP`9&,W,C@P7T=E=%-%4U-"
+M1G)O;5!O;VP`9&,W,C@P7T%S<VEG;D5L96UE;G13;&]T3G5M8F5R`$%S<VEG
+M;E-E<T]T:&5R16QE;65N=$]V97)A;&Q%;&5M96YT3G5M8F5R`&1C-S(X,%]0
+M;W)T7TAA;F1L955N<&QU9P!D8S<R.#!?0V]R95]-;V1U;&53=&%R=`!D8S<R
+M.#!?1&ES8V]V97)Y4TT`9&,W,C@P7U-#4TE?051!7T-H96-K0V]N9&ET:6]N
+M`&1C-S(X,%]-5E]#;W!Y4T=486)L90!D8S<R.#!?4T%405]$979I8V53=&%T
+M94UA8VAI;F4`9&,W,C@P7T1E=FEC95]-86ME26YQ=6ER>51A<VM297%U97-T
+M`&1C-S(X,%]$979I8V5?4&%R<V5)9&5N=&EF>41A=&$`9&,W,C@P7U-!5%-E
+M;G-E1&%T80!D8S<R.#!?1V5T3D-15&%G`&]D:6Y?96U?86-C97-S`&1C-S(X
+M,%]M=D-H86YN96Q3=&%T94UA8VAI;F4`9&,W,C@P7U-T;W)E7T-O;F9I9U)O
+M=71E26YF;P!D8S<R.#!?4T=486)L95]);FET`&1C-S(X,%]'971%>'!A;F1E
+M<D9R;VU0;V]L`$1E=FEC95]297!O<G1,=6Y297%U97-T`&1C-S(X,%]305-?
+M2&%N9&QE0E)$0U-4`&1C-S(X,%]#;W)E4V%V94]R:6=I;F%L0T1"`&1C-S(X
+M,%]-5E]$=6UP4F5Q=65S=`!D8S<R.#!?3&ES=%]'971&:7)S=`!D8S<R.#!?
+M4T-325]!5$%?1FEL;$1A=&%&:65L9`!D8S<R.#!?4T-325]!5$%?4WEN8T-A
+M8VAE5')A;G-L871I;VX`9&,W,C@P7U-'4$E/7TEN:71I86QI>F4`9&,W,C@P
+M7T9R965335!#;VYT97AT`&1C-S(X,%]&:6QL16YC;&]S=7)E16QE;65N=%-T
+M871U<P!D8S<R.#!?0V]R95]-;V1U;&5);FET:6%L:7IE`&1C-S(X,%]3051!
+M7U!-4W1A=&5-86-H:6YE`&1C-S(X,%]&<F5E4$U4;U!O;VP`9&,W,C@P7U-!
+M5$%?4')E<&%R94-O;6UA;F1486)L90!D8S<R.#!?0V]R95]-;V1U;&5'9712
+M97-O=7)C95%U;W1A`&1C-S(X,%]&<F5E4T="=69F97)4;U!O;VP`9&,W,C@P
+M7U1A9U]);FET7T9)1D\`9&,W,C@P7U-#4TE?051!7U)E861#87!A8VET>51R
+M86YS;&%T:6]N0V%L;&)A8VL`9&,W,C@P7U]?4$U?8V%N8V5L7W1I;65R`&1C
+M-S(X,%]-5E]$=6UP4F5G:7-T97(`9&,W,C@P7U-E<G9I8V5);G1E<G)U<'0`
+M1&5V:6-E7TUA:V50<FEV871E4F5C=E-E<U)E<75E<W0`9&,W,C@P7TES<W5E
+M7T1I<V-O=F5R`&1C-S(X,%]$25-#7T1O1&ES8V]V97(`9&,W,C@P7U-!5$%?
+M2&%N9&QE1&5V:6-E56YP;'5G`&1C-S(X,%]#;W)E7TEN=&5R;F%L4V5N9%)E
+M<75E<W0`9&,W,C@P7T1)4T-?4V5T4F5S;W5R8V4`9&,W,C@P7U-!5$%?4$U?
+M2&%N9&QE1&5V:6-E56YP;'5G`&1C-S(X,%]3051!7U!O<G1$979I8V5$971E
+M8W1E9`!D8S<R.#!?57!D871E5&%R9V5T1&5V:6-E<P!D8S<R.#!?4T-325]!
+M5$%?4W1A<G13=&]P5')A;G-L871I;VX`8VAE8VM?4V%S061D<@!D8S<R.#!?
+M0V]R95]P87-S7W1H<G5?9FEL;%]T87-K9FEL90!D8S<R.#!?;79?9&ES86)L
+M95]R96=I<W1E<E]S970`1&5V:6-E7U1E<W15;FET4F5A9'E297%U97-T`&1C
+M-S(X,%]!<W-I9VY$979I8V5%;&5M96YT3G5M8F5R`&1C-S(X,%]'971-:6Y.
+M96=O=&EA=&5D3&EN:U)A=&4`9&,W,C@P7VUV7W-E=%]305-!9&1R`&1C-S(X
+M,%]035]&<F5E4F5G:7-T97)3970`9&,W,C@P7T5X<&%N9&5R7U--4%)E<75E
+M<W1?4&AY0V]N=')O;`!D8S<R.#!?359?17%U86QS`&1C-S(X,%]'97131T)U
+M9F9E<D9R;VU0;V]L`&1C-S(X,%]30U-)7T%405],;W=E<E=O<F0`9&,W,C@P
+M7T-H96-K1&5V:6-E0VAA;F=E`&1C-S(X,%]305-?17)R;W)(86YD;&EN9P!D
+M8S<R.#!?0F5E<$]N`&1C-S(X,%]31U!)3U]335!297%?0V%L;&)A8VL`<V-S
+M:6QU;E]T;U]I;G0`9&,W,C@P7U-'5&%B;&5?079A:6QA8FQE`&1C-S(X,%]3
+M35!?4T=024]?4V5T7T9A:6QL960`9&,W,C@P7T-O<F5?1FEL;%-E;G-E1&%T
+M80!D8S<R.#!?1V5T4TU04V-R871C:$9R;VU0;V]L`&1C-S(X,%]3051!7U!O
+M<G1$979I8V5296%D>0!D8S<R.#!?;79?96YA8FQE7WAM=`!D8S<R.#!?07-S
+M:6=N4F5G:7-T97)3970`9&,W,C@P7V]D:6Y?:6]C=&P`9&,W,C@P7TES<W5E
+M7U)E<&]R=%)O=71E26YF;P!D8S<R.#!?1V5T26YT97)N86Q297%&<F]M4&]O
+M;`!D8S<R.#!?0VAE8VM487)G971#:&%N9V4`9&,W,C@P7T1E=FEC95]7<FET
+M95-E<T-O;G1R;VQ$:6%G`%-%4U1I;65R7TEN=&5R;F%L4F5Q0V%L;&)A8VL`
+M9V5T7V5N8U]C;W5N=`!D8S<R.#!?0V]M<&QE=&5297%U97-T`&1C-S(X,%]2
+M=6YT:6UE27-S=653;V9T4F5S970`9&,W,C@P7T1E=FEC95])<W-U95-O9G12
+M97-E=`!D8S<R.#!?4T%405](86YD;&5$979I8V50;'5G:6X`9&,W,C@P7U!R
+M97!A<F5!;F1396YD0V]M;6%N9`!G971?;6EN7W!M4&%T:$ED`&1C-S(X,%]0
+M<F5%;7!T>5!-`&1C-S(X,%]30U-)7TUA:V5#86-H94-O;6UA;F0`9&,W,C@P
+M7T-O;7!L971E4F5Q=65S=$%N9%-L;W0`9&,W,C@P7T1)4T-?1V5T3F5G;W1I
+M871E9$QI;FM2871E`&1C-S(X,%]&:6YD4G5N;FEN9U)E<4)Y5&%G`&1C-S(X
+M,%]S971?9F%I;%]L961S`&1C-S(X,%]&:6YD1G)E95--4$-O;G1E>'0`4F5M
+M;W9E4T%31&5V:6-E`&1C-S(X,%]305-?1&5V:6-E4W1A=&5-86-H:6YE`&1C
+M-S(X,%]&:6YD5&=T3F\`9&,W,C@P7TES<W5E7U)E<&]R=$=E;F5R86P`9&,W
+M,C@P7T-A;&-U;&%T95)O=71E26YD97@`9&,W,C@P7VUV7W)E<V5T7WAM=`!D
+M8S<R.#!?359?0U)#`&1C-S(X,%]30U-)7T%405]296%D0V%P86-I='E4<F%N
+M<VQA=&EO;@!D8S<R.#!?359?4F5M;W9E5&%R9V5T240`9&,W,C@P7U-!5$%?
+M4$U?17)R;W)(86YD;&EN9P!D8S<R.#!?57!D871E4W1A='5S5G-397-#;VYT
+M<F]L0G5F9F5R`&1C-S(X,%]#;W)E7T=E=%-U<'!O<G1E9$-O=6YT<P!D8S<R
+M.#!?359?4V5T3$)!86YD4V5C=&]R0V]U;G0`9&,W,C@P7T1E=FEC95]-86ME
+M36]D95-E;&5C=%)E<75E<W0`9&,W,C@P7T=E=$]N94-O;6UA;F13;&]T`&1C
+M-S(X,%]31U!)3U]296%D4F5G:7-T97(`9&,W,C@P7T5X<&%N9&5R7U--4%)E
+M<75E<W1?4F5P;W)T4$A94T%400!D8S<R.#!?4&]R=%](86YD;&50;'5G:6X`
+M9&,W,C@P7T-O<F5?4F5Q5&EM96]U=`!D8S<R.#!?;6]D95!A9V5"=68`9&,W
+M,C@P7U)U;G1I;65)<W-U95)E861,;V=%>'0`9&,W,C@P7U-#4TE?051!7U5P
+M<&5R5V]R9`!D8S<R.#!?1G)E94-O<F5#;VYT97AT5&]0;V]L`&1C-S(X,%]3
+M15-?26YT97)N86Q297%#86QL8F%C:P!D8S<R.#!?4T%405]%<G)O<DAA;F1L
+M:6YG`&1C-S(X,%]'9710349R;VU0;V]L`&1C-S(X,%]$971E8W10;W)T5'EP
+M90!D8S<R.#!?1&5V:6-E7TUA:V5-;V1E4V5N<V5297%U97-T`&1C-S(X,%]3
+M0U-)7T%405]&:6QL3$)!0V1B,3``9&,W,C@P7U]?8V%N8V5L7W1I;65R`&1C
+M-S(X,%]3051!7U!O<G1297-E=`!D8S<R.#!?;V1I;E]S971?:61L95]S=&%N
+M9&)Y`&1C-S(X,%]%>'!A;F1E<E]335!297%U97-T7T1I<V-O=F5R`&1C-S(X
+M,%]486=?1V5T3VYE`&1C-S(X,%]3051!7U!R97!A<F5#;VUM86YD2&5A9&5R
+M`&1C-S(X,%]#871E9V]R>5]#1$)?5'EP90!D8S<R.#!?1G)E94EN=&5R;F%L
+M4F5Q5&]0;V]L`&1C-S(X,%]'9713051!4V-R871C:$9R;VU0;V]L`%-W87!(
+M<'1-971A5C,`;&1M7W-P:6YU<%]V9&5V`')A=U]C:&5C:U]D:7-K7V1E<V-R
+M:7!T;W(`;&1M7V-H96-K7V%R<F%Y`&QD;5]R96-H96-K7V%L;`!V9&5V7V-L
+M87-S7VQI<W0`<F%W7VED;&5?=&EM97)?<F5S970`;&1M7V1E;&5T95]P87)T
+M:71I;VX`;&1M7W-Y;F-?8VAA;F=E9%]A<G)A>7,`9W)E8G5I;&1O;F5R<F]R
+M`&QD;5]Q=65U95]E=F5N=`!T<F%N<V9O<FU?;F5E9&5D`&QD;5]C:&5C:U]T
+M<F%N<V9O<FT`;&1M7V9I>'5P7V%R<F%Y7W-T871E`&-A;&-?<F5B=6EL9%]P
+M<F]G<F5S<P!V8G5S7V5X=%]S:7IE`'-E=%]T<F%N<V9O<FU?<W1E<%]I;F9O
+M`&QD;5]I9&QE7W1I;65R`&QD;5]F:6YD7W9D979?<F%W`&QD;5]R97!R;V)E
+M7V1E=FEC90!C86QC7W1R86YS9F]R;5]P<F]G<F5S<P!L9&U?9FEN9%]V9&5V
+M7V-L87-S`&QD;5]A;&QO8U]P87)T:71I;VX`;&1M7VEN:71?9&ES:P!R969R
+M97-H7W)A=U]D979?:6YF;P!?9&5L971E7W)A=U]P87)T`')A=U]R96%D7W=R
+M:71E7W-E8W1O<G,`9VED;&5S=&%N9&)Y=&EM96]U=`!R87=?8VAE8VM?87)R
+M87E?9&5S8W)I<'1O<@!L9&U?8W)E871E7W9D979?<F%W`'5N<&QU9U]R87=?
+M=F1E=@!#:&5C:U-U;0!C;VUP87)E7W-L;W1?<V5Q7V)Y7W!C:6%D9'(`;&1M
+M7V%D9%]D:7-K7W1O7V%R<F%Y`&QD;5]S>6YC7V1I<VM?:6YF;P!G971?8FET
+M<P!3=V%P2'!T365T858T`')A=U]C;VYV97)T7W-P87)E7W1O7VQE9V%C>0!F
+M3F]T:69Y1U5)`&QD;5]F;'5S:%]A;&Q?=&%R9V5T<P!L9&U?<W1A<G1?<F5B
+M=6EL9`!L9&U?<W!I;F1O=VY?86QL7W)A=V1E=G,`7U]L9&U?9FEN:7-H7V-M
+M9`!)1%]43U]61$56`%]?=F1E=E]Q=65U95]C;60`<F%W7VED;&5?=&EM97)?
+M8VAE8VL`9V5T7W-T<FEP7VEN9F\`;&1M7W)E<W5M95]A9&%P=&5R`&AP=&YR
+M7VQD;5]R96=I<W1E<E]H:6U?4E\V7S4U7S<U7S0V7S8T`&AP=&YR7V=';&]B
+M86Q.8W%&;&%G`&AP=&YR7V]S7W)E<75E<W1?=&EM97(`:'!T;G)?9&UA<&]O
+M;%]G971?<&%G90!H<'1N<E]O<U]G971?<W1A;7``:'!T;G)?;&1M7W-U<W!E
+M;F0`:'!T;G)?;&1M7VED;&4`:'!T;G)?;&1M7V=E=%]M96U?:6YF;P!H<'1N
+M<E]L9&U?<F5M;W9E7W1I;65R`&AP=&YR7W!C:6-F9U]R96%D7V1W;W)D`&AP
+M=&YR7V1M87!O;VQ?;6%K95]O<F1E<@!H<'1N<E]L9&U?9V5T7W9B=7-?97AT
+M`&AP=&YR7VQD;5]R96QE87-E7W9D978`:'!T;G)?9G)E96QI<W1?<F5S97)V
+M95]D;6$`:'!T;G)?;&1M7VEN='(`;65M8W!Y`&AP=&YR7VQD;5]O;E]T:6UE
+M<@!H<'1N<E]L9&U?9V5T7V-M9%]S:7IE`&AP=&YR7VQD;5]F<F5E7V-M9',`
+M:'!T;G)?;&1M7V-R96%T95]V9&5V`&AP=&YR7VQD;5]A9&1?<W!A<F5?=&]?
+M87)R87D`:'!T;G)?9W)E8G5I;&1P<FEO<FET>0!H<'1N<E]L9&U?<WEN8U]A
+M<G)A>5]I;F9O`&AP=&YR7V]S7VUA<%]P8VE?8F%R`&AP=&YR7U]?;&1M7V%L
+M;&]C7V-M9`!H<'1N<E]I;FET7VUO9'5L95]V9&5V7W)A=P!H<'1N<E]L9&U?
+M<V5T7V%U=&]R96)U:6QD`&AP=&YR7U]?9'5M;7E?<F5G`&AP=&YR7V1M87!O
+M;VQ?86-T:79E`&AP=&YR7W9B=7-?;&ES=`!H<'1N<E]L9&U?<75E=65?=F)U
+M<U]D<&,`:'!T;G)?;&1M7W)E<V5T7W9B=7,`:'!T;G)?9U-'4$E/4&%R=%-U
+M<'!O<G0`:'!T;G)?:6YI=%]M;V1U;&5?:&EM7W(W-3``:'!T;G)?;&1M7W)E
+M;&5A<V5?;&]C:P!H<'1N<E]O<U]U;FUA<%]P8VE?8F%R`&AP=&YR7VQD;5]S
+M:'5T9&]W;@!H<'1N<E]H:6U?;&ES=`!H<'1N<E]L9&U?<F5Q=65S=%]T:6UE
+M<@!H<'1N<E]L9&U?<F5S=6UE`&AP=&YR7VQD;5]G971?9&5V:6-E7VED`&AP
+M=&YR7V]S7W-C:&5D=6QE7W1A<VL`:'!T;G)?;&1M7VEO8W1L`&AP=&YR7V=3
+M<&EN=7!/;F5$979%86-H5&EM90!H<'1N<E]F<F5E;&ES=%]P=70`:'!T;G)?
+M;W-?<W1A;&QE>&5C`&AP=&YR7V=?;&5G86-Y7VUO9&4`:'!T;G)?;&1M7V%L
+M;&]C7V-M9'-?4E\V7S4U7S<U7S0V7S8T`&AP=&YR7VQD;5]R=6X`:'!T;G)?
+M:6YI=%]M;V1U;&5?:&EM7V1C-S(X,`!H<'1N<E]L9&U?9G)E95]C;61S7W1O
+M7VQI<W0`:'!T;G)?;W-?;6%X7V-A8VAE7W-I>F4`:'!T;G)?=F1E=E]Q=65U
+M95]C;60`:'!T;G)?;W-?9V5T7W9B=7-?<V5Q`&AP=&YR7VQD;5]S>6YC7V%R
+M<F%Y7W-T86UP`&AP=&YR7VQD;5]Q=65U95]C;60`:'!T;G)?;W-?<')I;G1K
+M`&AP=&YR7V9R965L:7-T7W)E<V5R=F4`:'!T;G)?9&UA<&]O;%]P=71?<&%G
+M90!H<'1N<E]F<F5E;&ES=%]G970`:'!T;G)?;&1M7W5N<F5G:7-T97)?9&5V
+M:6-E`&AP=&YR7VQD;5]R96=I<W1E<E]A9&%P=&5R`&AP=&YR7V=A=71O<F5B
+M=6EL9`!H<'1N<E]L9&U?9V5T7W9B=7-?<VEZ90!H<'1N<E]D96QA>5]B971W
+M965N7W-P:6YU<`!H<'1N<E]M<VD`:'!T;G)?;&1M7V=E;F5R:6-?;65M8F5R
M7V9A:6QE9`!H<'1N<E]D;6%P;V]L7V=E=%]P86=E7V%T`&AP=&YR7VQD;5]E
M=F5N=%]N;W1I9GD`:'!T;G)?;&1M7V-R96%T95]V8G5S`&AP=&YR7VAI;5]H
M86YD;&5?=&]?=F)U<P!H<'1N<E]F<F5E;&ES=%]G971?9&UA`&AP=&YR7VQD
M;5]G971?;F5X=%]V8G5S`&AP=&YR7V]S7W!C:5]W<FET96P`:'!T;G)?;&1M
-M7V9I;F1?=&%R9V5T`&AP=&YR7V1M87!O;VQ?<F5G:7-T97)?8VQI96YT`&AP
-M=&YR7VQD;5]I;FET:6%L:7IE7W9B=7-?87-Y;F,`:'!T;G)?;W-?<75E<GE?
-M=&EM90!H<'1N<E]O<U]Q=65R>5]R96UO=F5?9&5V:6-E`&AP=&YR7VQD;5]R
-M96=I<W1E<E]D979I8V4`:'!T;G)?;W-?<&-I7W)E861L`&AP=&YR7VQD;5]A
-M8W%U:7)E7VQO8VL`:'!T;G)?;W-?<F5V86QI9&%T95]D979I8V4`:'!T;G)?
-M9&UA<&]O;%]I;FET`&AP=&YR7VQD;5]F:6YI<VA?8VUD`&AP=&YR7VQD;5]I
-M9&5?9FEX<W1R:6YG`&AP=&YR7V1M87!O;VQ?;6%X7V-L87-S7W!A9V5S`&AP
-M=&YR7VQD;5]R96=I<W1E<E]V9&5V7V-L87-S7U)?-E\U-5\W-5\T-E\V-`!H
-M<'1N<E]N=6U?9')I=F5S7W!E<E]S<&EN=7``:'!T;G)?;&1M7W)E;&5A<V5?
-M=F)U<P!H<'1N<E]L9&U?<75E=65?=&%S:P!H<'1N<E]L9&U?86QL;V-?8VUD
-M<U]F<F]M7VQI<W0`:'!T;G)?9G)E96QI<W1?<'5T7V1M80!H<'1N<E]L9&U?
-M=&EM97)?<')O8F5?9&5V:6-E`&AP=&YR7VQD;5]F:6YD7W-T86UP`&AP=&YR
-M7VQD;5]C:&5C:U]A<G)A>5]O;FQI;F4`:'!T;G)?9U!R;V)E26Y);FET:6%L
-M:7II;F<`:'!T;G)?;&]G7W-E8W1O<E]R97!A:7(``'D``````````@```(H`
-M``#\_________Y(``````````@```),```#\_________Z<``````````@``
-M`"P```#\_________S4!````````"P````$````P`````````$T!````````
-M`@```.P```#\_________V,!`````````@```*X```#\_________VX!````
-M`````@```#X```#\_________X8!`````````@```*0"``#\_________Y$!
-M`````````@```$(```#\_________[`!`````````@```"D```#\________
-M_[\!`````````@```%<```#\_________\H!`````````@```"P```#\____
-M_____^@!`````````@```"P```#\_________P,"`````````@```%8```#\
-M_________R`"`````````@```*````#\_________X("`````````@```.P`
-M``#\_________Y8"`````````@```*X```#\_________S@%`````````@``
-M`$X```#\_________[H'````````"P````,``````````````%L(````````
-M"P````4``````````````&4(`````````@```*\"``#\_________Z`(````
-M`````@```(8"``#\_________X`)`````````@```)("``#\_________ZT)
-M`````````@```)("``#\_________PT*`````````@```)("``#\________
-M_X\*`````````@```)("``#\_________\D*`````````@```)("``#\____
-M_____RX+`````````@```*0"``#\_________VD+`````````@```*0"``#\
-M_________[<+`````````@```*0"``#\__________(+`````````@```*0"
-M``#\_________T@,`````````@```!$!``#\_________U(,`````````@``
-M`*0"``#\_________UP,`````````@```&<```#\_________S<-````````
-M`@```)("``#\_________U0-`````````@```)("``#\_________V,-````
-M`````@```*0"``#\_________W\-`````````@```)("``#\_________YP-
-M`````````@```)("``#\_________\H-`````````@```)("``#\________
-M_]0-`````````@```)("``#\__________P-`````````@```*0"``#\____
-M_____PD.`````````@```)("``#\_________S$.`````````@```*0"``#\
-M_________SX.`````````@```)("``#\_________V\.`````````@```)("
-M``#\_________Z`.`````````@```)("``#\_________P4/`````````@``
-M`)("``#\_________R4/`````````@```)("``#\_________TP/````````
-M`@```)("``#\_________VP/`````````@```)("``#\_________YP/````
-M`````@```)("``#\_________Z8/`````````@```)("``#\_________](/
-M`````````@```*0"``#\_________^(/`````````@```)("``#\________
-M_PH0`````````@```*0"``#\_________QH0`````````@```)("``#\____
-M_____R02`````````@```)("``#\_________VP2`````````@```-,```#\
-M_________Y@2`````````@```-,```#\_________P83`````````@```"X`
-M``#\_________V03`````````@```'\"``#\_________W`3`````````@``
-M`/8```#\_________XD3`````````@```&@```#\_________R\4````````
-M`@```"X```#\_________UX4`````````@```!@```#\_________V\4````
-M`````@```+(```#\_________XP4````````"P````$!`````````````)L4
-M````````"P````4```!8`````````*44`````````@```*\"``#\________
-M_[H4`````````@```+H"``#\_________\\4`````````@```+H"``#\____
-M_____^<4`````````@```#H```#\_________P@5`````````@```)("``#\
-M__________P5````````"P```)4```````````````$6`````````@```,(`
-M``#\_________^T6`````````@```($```#\__________@6`````````@``
-M`"P```#\_________^X7`````````@```+P```#\_________V$;````````
-M`@```/0```#\_________]D;`````````@```.````#\_________QP<````
-M`````@```+P```#\_________[P<````````"P````,`````!````````-4<
-M`````````@```!L```#\_________P<=`````````@```!L```#\________
-M_S<=`````````@```!L```#\_________V,=`````````@```!L```#\____
-M_____YH=`````````@```$T```#\_________^8=`````````@````D!``#\
-M_________W@>`````````@```)\```#\_________[<>`````````@```!0`
-M``#\_________^$>`````````@```*0"``#\_________SLA`````````@``
-M`*(```#\_________THA`````````@```'@```#\_________P$B````````
-M`@```/P```#\_________WLB`````````@```,$```#\_________Y@B````
-M`````@```/P```#\_________[PC`````````@```(0```#\_________\\C
-M`````````@````(!``#\_________STD`````````@```(0```#\________
-M_VDD`````````@````(!``#\_________P(F`````````@```$0```#\____
-M_____^HF`````````@```(8"``#\_________P0G````````"P````,```!0
-M!````````)<G`````````@```!,```#\_________Z8G`````````@```!,`
-M``#\_________R,H`````````@```(0```#\_________T\H`````````@``
-M``(!``#\_________[XH`````````@````<!``#\__________(H````````
-M`@```+````#\_________PLI`````````@````<!``#\_________QHI````
-M`````@````\!``#\_________S,I`````````@````<!``#\_________X,I
-M`````````@```*0```#\_________Y@I````````"P````4```!X````````
-M`*(I`````````@```*\"``#\_________Q0J`````````@```&@```#\____
-M_____R8J`````````@```&\```#\_________\(J`````````@```)$```#\
-M_________S\K`````````@```)$```#\_________T\K`````````@```"0`
-M``#\_________WDK`````````@```)$```#\_________Y<K`````````@``
-M`-X```#\_________\0K`````````@```$\```#\_________X,L````````
-M`@```'$```#\_________Z8L`````````@```-X```#\_________\\L````
-M`````@```)H```#\__________8L`````````@```)$```#\__________XL
-M`````````@```)H```#\_________R,M`````````@```-X```#\________
-M_XDM`````````@```#L```#\_________]<M`````````@```%4```#\____
-M______LM`````````@```&@```#\_________S(N`````````@```+H"``#\
-M_________T8N`````````@```#L```#\_________V0N`````````@```$(`
-M``#\_________VXN`````````@```*0"``#\_________[TN`````````@``
-M`+<```#\_________\0N`````````@```.X```#\_________]HN````````
-M"P````8``````````````.0N`````````@```*\"``#\_________QLO````
-M`````@```#L```#\_________RXO`````````@```%@```#\_________S8O
-M`````````@```)H```#\_________\<O`````````@```)("``#\________
-M__,O`````````@```)("``#\_________RPP`````````@```)("``#\____
-M_____VHP````````"P````4```"H`````````'0P`````````@```*\"``#\
-M_________[`P`````````@```+T```#\_________P8Q`````````@```+T`
-M``#\_________QLQ`````````@```+\```#\_________R8Q`````````@``
-M`'$```#\_________]@Q`````````@```-L```#\__________\Q````````
-M`@```-X```#\_________S0R`````````@```&@```#\_________](R````
-M`````@```-L```#\__________0R`````````@```-X```#\_________S<S
-M`````````@```&T```#\_________V@T`````````@```)("``#\________
-M_X8T`````````@```)("``#\_________Z,T`````````@```)("``#\____
-M_____P@U`````````@```)("``#\_________R\U`````````@```)("``#\
-M_________YLU`````````@```-P```#\__________@U`````````@```)("
-M``#\_________QLV`````````@```)("``#\_________SXV`````````@``
-M`)("``#\_________T8V`````````@```&0```#\_________S<W````````
-M`@```!(!``#\_________UHW`````````@```(8"``#\_________T(X````
-M`````@```(8"``#\_________[`X`````````@```(8"``#\_________^0X
-M`````````@```)("``#\_________Q\Y`````````@```)("``#\________
-M_W,Y`````````@```)("``#\_________U$Z`````````@```(8"``#\____
-M_____Z4[`````````@```(8"``#\_________RT\`````````@```(8"``#\
-M_________T`\````````"P````,```"P"0```````-4\`````````@```*0"
-M``#\_________U,]`````````@```)("``#\_________W<]`````````@``
-M`)("``#\_________Y@]````````"P````8````>`````````*(]````````
-M`@```*\"``#\_________ZP]`````````@```!`!``#\_________\P]````
-M`````@```)("``#\_________PP^`````````@```)("``#\_________YT^
-M`````````@```)("``#\_________R(_`````````@```!`!``#\________
-M_S$_`````````@```!`!``#\_________WP_````````"P````4```#X````
-M`````(8_`````````@```*\"``#\_________^\_````````"P````8````Y
-M`````````/D_`````````@```*\"``#\_________PM``````````@```"$`
-M``#\_________S5`````````"P````4````X`0```````#]``````````@``
-M`*\"``#\_________[)`````````"P````4```!@`0```````+Q`````````
-M`@```*\"``#\_________UY!`````````@```-L```#\_________W=!````
-M`````@```-X```#\_________RI"`````````@```#4```#\_________XY#
-M`````````@```"$```#\_________YY#`````````@```"X```#\________
-M_^)#`````````@```'````#\_________TE$`````````@```-L```#\____
-M_____U1$`````````@```#4```#\_________VU$`````````@```-X```#\
-M_________\=$`````````@```&@```#\_________T!%`````````@```&X`
-M``#\_________W=%`````````@```&@```#\_________QM&`````````@``
-M`)("``#\_________TI&`````````@```&@```#\_________W]&````````
-M`@```"X```#\_________Y!&`````````@```)H```#\_________]E&````
-M`````@```)("``#\_________P)'`````````@```)("``#\_________S-'
-M`````````@```)("``#\_________TA'`````````@```*D```#\________
-M_[Q'`````````@```)("``#\_________T%(`````````@```)("``#\____
-M_____VQ(`````````@```)("``#\_________WY(`````````@```(\```#\
-M_________\%(`````````@```)("``#\_________^9(`````````@```)("
-M``#\_________V-)`````````@```)("``#\_________XQ)`````````@``
-M`)("``#\_________[A)`````````@```'\"``#\_________]E)````````
-M`@```/H```#\_________QE*`````````@```&@```#\_________T]*````
-M`````@```+H"``#\_________V-*`````````@```#L```#\_________X%*
-M`````````@```(4```#\_________XM*`````````@```*0"``#\________
-M_[M*````````"P````$````@8````````.E*`````````@```)T"``#\____
-M_____Q-+`````````@```)("``#\_________RA+`````````@```)("``#\
-M_________U!+`````````@```)("``#\_________V5+`````````@```)("
-M``#\_________Y9+`````````@```)("``#\_________\U+`````````@``
-M`)("``#\_________PM,`````````@```)("``#\_________S-,````````
-M`@```)("``#\_________VA,`````````@```)("``#\_________Y],````
-M`````@```)("``#\_________P9-`````````@```)("``#\_________RM-
-M`````````@```)("``#\_________U!-`````````@```)("``#\________
-M_W5-`````````@```)("``#\_________[1-`````````@```'\"``#\____
-M_____^Y-`````````@```+H"``#\_________P).`````````@```#L```#\
-M_________Q1.`````````@```$(```#\_________QY.`````````@```*0"
-M``#\_________TM.````````"P```.X``````````````&-.`````````@``
-M`)T"``#\_________XY.`````````@```)("``#\_________\!.````````
-M`@```)("``#\__________E.`````````@```)("``#\_________R5/````
-M`````@```)("``#\_________VI/`````````@```'\"``#\_________X1/
-M`````````@```&@```#\_________[1/`````````@```+H"``#\________
-M_])/````````"P````X!`````````````.1/`````````@```)T"``#\____
-M_____Q-0`````````@```)("``#\_________SE0`````````@```)("``#\
-M_________U=0`````````@```*0"``#\_________VQ0`````````@```)("
-M``#\_________Y)0`````````@```)("``#\_________[A0`````````@``
-M`)("``#\_________]90`````````@```*0"``#\_________^M0````````
-M`@```)("``#\_________Q!1`````````@```)("``#\_________]91````
-M`````@```)("``#\__________M1`````````@```*0"``#\_________RM2
-M`````````@```)("``#\_________U)2`````````@```*0"``#\________
-M_X52`````````@```)("``#\_________ZQ2`````````@```*0"``#\____
-M______)2`````````@```,4```#\_________PU3`````````@```(8```#\
-M_________QE3`````````@```!(```#\_________TM3`````````@```$``
-M``#\_________W]3`````````@```!<```#\_________ZQ3`````````@``
-M`!(```#\_________Y)4`````````@```*0"``#\_________[E4````````
-M`@```)("``#\_________]A4`````````@```*0"``#\__________M4````
-M`````@```)("``#\_________R=5`````````@```*0"``#\_________TY5
-M`````````@```)("``#\_________W)5`````````@```*0"``#\________
-M_Y95`````````@```)("``#\_________[=5`````````@```&@```#\____
-M_____S16`````````@```#L```#\_________V]6`````````@```#L```#\
-M_________WM6`````````@```!(```#\_________[U6`````````@```&@`
-M``#\_________^)6`````````@```&@```#\_________P-7`````````@``
-M`'\"``#\_________R17`````````@```$(```#\_________RY7````````
-M`@```*0"``#\_________^97`````````@```"X```#\_________PY8````
-M`````@```!@```#\_________Q]8`````````@```+(```#\_________S)8
-M````````"P````8```!&`````````#Q8`````````@```*\"``#\________
-M_U%8`````````@```+H"``#\_________V98`````````@```+H"``#\____
-M_____X-8`````````@```#H```#\_________Z)8`````````@```(L```#\
-M_________\U8````````"P````$!`````````````-58`````````@```&@`
-M``#\__________I8`````````@```$(```#\_________P19`````````@``
-M`*0"``#\_________SM9`````````@```!@```#\_________TQ9````````
-M`@```+(```#\_________WA9````````"P````4```!8`````````()9````
-M`````@```*\"``#\_________Y=9`````````@```+H"``#\_________ZQ9
-M`````````@```+H"``#\_________\19`````````@```#H```#\________
-M_]E9`````````@```$````#\_________UI:`````````@```)("``#\____
-M_____WQ:`````````@```*0"``#\_________Y]:`````````@```)("``#\
-M_________\):`````````@```)("``#\_________^1:`````````@```*0"
-M``#\_________PA;`````````@```)("``#\_________Y);`````````@``
-M`/H```#\_________YY;`````````@```'T```#\_________^5;````````
-M`@```'4```#\__________);`````````@```/L```#\_________RA<````
-M`````@```*0"``#\_________T-<`````````@```)("``#\_________V)<
-M`````````@```)("``#\_________X%<`````````@```!(```#\________
-M_XE<`````````@````T!``#\_________[%<`````````@```)T```#\____
-M_____SA=`````````@````X!``#\_________T5=`````````@```&@```#\
-M_________]!=`````````@```",!``#\_________P1>`````````@```+<`
-M``#\_________SU>`````````@```,P```#\_________U5>`````````@``
-M`+H"``#\_________VU>`````````@```+H"``#\_________YI>````````
-M`@```*0"``#\_________[5>`````````@```)("``#\_________])>````
-M`````@```)("``#\__________%>`````````@```!(```#\__________E>
-M`````````@````T!``#\_________S]?`````````@```,4```#\________
-M_X1?`````````@```&@```#\_________P-@`````````@```)T```#\____
-M_____Q)@`````````@```"$!``#\_________XM@`````````@```)("``#\
-M_________[I@`````````@```)("``#\_________])@`````````@```',`
-M``#\_________]]@`````````@```/L```#\_________TEA`````````@``
-M`'<```#\_________VQA`````````@```-X```#\_________Y1A````````
-M`@```)H```#\_________[AA`````````@```)$```#\_________\!A````
-M`````@```)H```#\_________PEB`````````@```-X```#\_________UIB
-M`````````@```#L```#\_________VEB`````````@```&@```#\________
-M_YAB`````````@```+H"``#\_________ZQB`````````@```#L```#\____
-M_____\1B`````````@```$(```#\_________\YB`````````@```*0"``#\
-M_________^YB`````````@```.X```#\_________QUC`````````@```-X`
-M``#\_________T]C`````````@```#L```#\_________V9C`````````@``
-M`&@```#\_________X)C`````````@```!@```#\_________Y-C````````
-M`@```+(```#\_________ZAC`````````@```+H"``#\_________[UC````
-M`````@```+H"``#\_________]!C`````````@```#H```#\_________^)C
-M`````````@```/8```#\__________MC`````````@```)("``#\________
-M_U5D`````````@```!(```#\_________V!D`````````@```$````#\____
-M______9D`````````@```)("``#\_________Q%E`````````@```"$```#\
-M_________R%E`````````@```"X```#\_________T1E`````````@```"$`
-M``#\_________TQE`````````@```"D!``#\_________V5E````````"P``
-M``,````0"@```````'QE`````````@```"L!``#\_________YAE````````
-M`@```"L!``#\_________[1E`````````@```#L```#\_________]=E````
-M`````@```%4```#\_________^YE`````````@```*,```#\_________Q%F
-M`````````@```#L```#\_________R]F`````````@```%4```#\________
-M_T9F`````````@```#L```#\_________UAF`````````@```*,```#\____
-M_____W-F`````````@```#L```#\_________XAF`````````@```#L```#\
-M_________[QF`````````@```$(```#\_________\9F`````````@```*0"
-M``#\_________SEG`````````@```*8```#\_________U-G`````````@``
-M`*P```#\_________VQG`````````@```!@```#\_________WUG````````
-M`@```+(```#\_________Y!G````````"P````8```!&`````````)IG````
-M`````@```*\"``#\_________[!G`````````@```+H"``#\_________\9G
-M`````````@```+H"``#\_________]EG`````````@```#H```#\________
-M_P1H`````````@```&@```#\_________SMH`````````@```!\!``#\____
-M_____Y%H`````````@```'8```#\_________[-H`````````@```&@```#\
-M_________P1I````````"P````4```"X`0````````YI`````````@```*\"
-M``#\_________S)I`````````@```"$```#\_________V)I````````"P``
-M``4```#H`0```````&QI`````````@```*\"``#\_________^AI````````
-M"P````4```!@`0```````/)I`````````@```*\"``#\_________R5J````
-M````"P````4```"X`0```````"]J`````````@```*\"``#\_________\1J
-M`````````@```*D```#\_________]-K`````````@```-L```#\________
-M_Q)L`````````@```.T```#\_________SML````````"P````4```"X`0``
-M`````$5L`````````@```*\"``#\_________W)M`````````@```(8"``#\
-M_________YEM`````````@```)("``#\_________]!M`````````@```)("
-M``#\_________QYN`````````@```)("``#\_________X=N````````"P``
-M``$!`````````````*%N````````"P````4````8`@```````*MN````````
-M`@```*\"``#\_________^QN````````"P````4```!0`@```````/9N````
-M`````@```*\"``#\_________REO````````"P````4```"0`@```````#-O
-M`````````@```*\"``#\_________TMO````````"P````4```#0`@``````
-M`%5O`````````@```*\"``#\_________WIO````````"P````8```!<````
-M`````(1O`````````@```*\"``#\_________\%O````````"P````4`````
-M`P```````,MO`````````@```*\"``#\__________]O````````"P````8`
-M``!X``````````EP`````````@```*\"``#\_________RQP````````"P``
-M``8```"/`````````#9P`````````@```*\"``#\_________T%P````````
-M"P````8```"K`````````$MP`````````@```*\"``#\_________YMP````
-M`````@````L!``#\_________^IP`````````@```)("``#\_________PYQ
-M`````````@```)("``#\_________S!Q`````````@```)("``#\________
-M_U1Q`````````@```)("``#\_________V-Q````````"P````8```"\````
-M`````&UQ`````````@```*\"``#\_________PAR`````````@```)("``#\
-M_________S-R````````"P````8```#9`````````#UR`````````@```*\"
-M``#\_________WYR````````"P````4````X`P```````(AR`````````@``
-M`*\"``#\_________YER`````````@```&0```#\_________[!R````````
-M`@```)("``#\_________UAS`````````@```)H```#\_________W5S````
-M`````@```$P```#\__________5S`````````@```"\```#\_________PET
-M`````````@```,````#\_________R]T`````````@```+`"``#\________
-M_U%T`````````@```+`"``#\_________W)T`````````@```+`"``#\____
-M_____Y!T`````````@```+`"``#\_________[9T`````````@```+`"``#\
-M_________^%T`````````@```+`"``#\__________MT`````````@```+`"
-M``#\_________Q5U`````````@```+`"``#\_________S-U`````````@``
-M`+`"``#\_________TUU`````````@```+`"``#\_________V]U````````
-M`@```+`"``#\_________Y%U`````````@```+`"``#\_________ZYU````
-M`````@```+`"``#\_________\MU`````````@```+`"``#\_________^AU
-M`````````@```+`"``#\_________P5V`````````@```+`"``#\________
-M_R%V`````````@```+`"``#\_________T-V`````````@```+`"``#\____
-M_____UQV`````````@```+`"``#\_________X!V`````````@```(0"``#\
-M_________Z!V`````````@```(0"``#\_________\=V`````````@```(0"
-M``#\_________^MV`````````@```(0"``#\_________P]W`````````@``
-M`(0"``#\_________S)W`````````@```(0"``#\_________U)W````````
-M`@```(0"``#\_________WQW`````````@```(0"``#\_________\=W````
-M`````@```&@```#\_________]=W`````````@```(H```#\_________U!X
-M````````"P````$````@%@```````%YX`````````@```.P```#\________
-M_VIX`````````@```#X```#\_________SEY`````````@```&@```#\____
-M_____VYY`````````@```+H"``#\_________X1Y`````````@```#L```#\
-M_________Y5Y`````````@```$(```#\_________Y]Y`````````@```*0"
-M``#\_________]!Y`````````@```%$```#\_________VE[`````````@``
-M`"\```#\_________^Q[`````````@```+("``#\_________RA\````````
-M`@```+("``#\_________V-\`````````@```+("``#\_________YI\````
-M`````@```+("``#\_________])\`````````@```+("``#\_________^5\
-M`````````@```+("``#\__________M\`````````@```+("``#\________
-M_V%]`````````@```+("``#\_________ZY]`````````@```+("``#\____
-M______Y]`````````@```+("``#\_________T%^`````````@```+("``#\
-M_________X]^`````````@```+("``#\_________^=^`````````@```+("
-M``#\_________RA_`````````@```+("``#\_________U%_`````````@``
-M`,T```#\_________UU_`````````@```+("``#\_________X9_````````
-M`@```!$```#\_________Y)_`````````@```+("``#\_________[M_````
-M`````@```!$```#\_________\=_`````````@```+("``#\__________!_
-M`````````@```!$```#\__________Q_`````````@```+("``#\________
-M_R6``````````@```!$```#\_________S&``````````@```+("``#\____
-M_____XV``````````@```-0```#\_________YJ#`````````@```+T"``#\
-M_________[2#`````````@```+T"``#\_________\Z#`````````@```+T"
-M``#\_________^B#`````````@```+T"``#\_________P*$`````````@``
-M`+T"``#\_________QR$`````````@```+T"``#\_________T2$````````
-M`@```&@```#\_________YF$`````````@```+T"``#\_________[J$````
-M`````@```&@```#\_________PN%`````````@```+T"``#\_________R^%
-M`````````@```&@```#\_________Z*%`````````@```&H```#\________
-M_P&&`````````@```)("``#\_________S2&`````````@```)("``#\____
-M_____TR&`````````@```/L```#\_________Y>&`````````@```#L```#\
-M_________ZB&`````````@```$(```#\_________[*&`````````@```*0"
-M``#\_________]J&`````````@```!@```#\_________^^&`````````@``
-M`+H"``#\_________P2'`````````@```+H"``#\_________QN'````````
-M`@```#H```#\_________RN'`````````@```)("``#\_________YJ'````
-M`````@```-,```#\_________\:'`````````@```+H"``#\_________S.(
-M`````````@```+\```#\_________V2(`````````@```&@```#\________
-M_[V(````````"P````$!`````````````,R(````````"P````4```!@`P``
-M`````-:(`````````@```*\"``#\_________QJ)````````"P````4```"0
-M`P```````"2)`````````@```*\"``#\_________U>)`````````@```"$`
-M``#\_________X>)````````"P````4```#H`0```````)&)`````````@``
-M`*\"``#\_________PV*````````"P````4```!@`0```````!>*````````
-M`@```*\"``#\_________SZ*````````"P````8```!<`````````$B*````
-M`````@```*\"``#\_________XJ*````````"P````4``````P```````)2*
-M`````````@```*\"``#\_________TB+````````"P````8```#M````````
-M`%*+`````````@```*\"``#\_________UJ+`````````@```*D```#\____
-M_____VZ,`````````@```-X```#\_________YB,`````````@```-L```#\
-M_________[B,`````````@```-P```#\__________Z,`````````@```&T`
-M``#\_________XR0`````````@```)X```#\__________&0`````````@``
-M`(8"``#\__________Z0`````````@```.<```#\_________W:1````````
-M`@```(8"``#\_________]Z1`````````@```(H```#\__________*1````
-M`````@```),```#\_________P62`````````@```"P```#\_________RB2
-M`````````@```(8"``#\_________WJ2````````"P```)@`````````````
-M`,22`````````@```.P```#\_________]62`````````@```*X```#\____
-M_____^"2`````````@```#X```#\_________T^3`````````@```(H```#\
-M_________V.3`````````@```),```#\_________W:3`````````@```"P`
-M``#\_________]J3````````"P```)@``````````````"F4`````````@``
-M`.P```#\_________SJ4`````````@```*X```#\_________T64````````
-M`@```#X```#\_________\B4`````````@```(H```#\_________]R4````
-M`````@```),```#\_________^^4`````````@```"P```#\_________PR5
-M`````````@```(8"``#\_________U"5````````"P```!\`````````````
-M`'25`````````@```.P```#\_________X.5`````````@```*X```#\____
-M_____XZ5`````````@```#X```#\__________&5`````````@```)X```#\
-M_________Q^6`````````@```#@```#\_________W.6`````````@```(H`
-M``#\_________X>6`````````@```),```#\_________YJ6`````````@``
-M`"P```#\_________^R6````````"P```!\```````````````V7````````
-M`@```.P```#\_________QV7`````````@```*X```#\_________RB7````
-M`````@```#X```#\_________]B7`````````@```%,```#\_________Q:8
-M`````````@```%,```#\_________U28`````````@```'0```#\________
-M_V*8`````````@```#(```#\_________Y&8`````````@```#8```#\____
-M_____ZJ8`````````@```#(```#\_________]B8`````````@```#(```#\
-M_________ZZ9`````````@```*\```#\__________&9`````````@```*H`
-M``#\_________RR:`````````@```#8```#\_________W.:`````````@``
-M`(H```#\_________X>:`````````@```),```#\_________YJ:````````
-M`@```"P```#\_________^V:````````"P```/(```````````````Z;````
-M`````@```.P```#\_________QV;`````````@```*X```#\_________RB;
-M`````````@```#X```#\_________R^<`````````@```"D```#\________
-M_SJ<`````````@```"P```#\_________VF<`````````@```(8"``#\____
-M_____Z^<`````````@```"D```#\_________[J<`````````@```"P```#\
-M_________V&=`````````@```!4!``#\_________W2=`````````@```"D`
-M``#\_________W^=`````````@```"P```#\_________YF=`````````@``
-M`'\"``#\_________ZZ=````````"P```#,``````````````,*=````````
-M`@```)T"``#\_________SZ>`````````@```*@```#\_________RV?````
-M`````@```!H!``#\_________V&?`````````@```!H!``#\_________YF?
-M`````````@```#8```#\_________P>A`````````@```&8```#\________
-M_QFA`````````@```,\```#\_________RZA`````````@```"(!``#\____
-M_____T"A`````````@```!4!``#\_________UJA`````````@```'\"``#\
-M_________V^A````````"P```#,``````````````(FA`````````@```)T"
-M``#\_________]6A`````````@```&@```#\_________T*B`````````@``
-M`",!``#\_________VBB`````````@```+<```#\_________XRB````````
-M`@```,P```#\__________2B`````````@```&@```#\_________R^C````
-M`````@```#8```#\_________UVC`````````@```!\!``#\_________XFC
-M`````````@```"D```#\_________YBC`````````@```"P```#\________
-M_]&C`````````@```#8```#\_________XFD`````````@```)("``#\____
-M______NH`````````@```&,```#\__________VI````````"P````,```!`
-M"@```````)>J`````````@```)("``#\_________\VJ`````````@```)("
-M``#\__________BJ`````````@```)("``#\_________S*K`````````@``
-M`)("``#\_________W>K`````````@```)("``#\_________ZVK````````
-M`@```)("``#\_________]BK`````````@```)("``#\_________PVL````
-M`````@```)("``#\_________\VL````````"P````,`````"P```````.FL
-M````````"P````,````%"P```````/FL````````"P````,````$"P``````
-M``JM````````"P````,`````"P```````!NM`````````@```,X```#\____
-M_____ZVM`````````@```&@```#\_________]VM`````````@```&@```#\
-M_________PVN`````````@```&@```#\_________UVN`````````@```&@`
-M``#\_________XVN`````````@```&@```#\_________PJO`````````@``
-M`&@```#\_________U.P`````````@```-L```#\_________Y"Q````````
-M`@```"$```#\_________].Q`````````@```/D```#\_________Q.R````
-M`````@```/D```#\_________P^S`````````@```"D```#\_________QVS
-M`````````@```(,```#\_________T>T`````````@```#X```#\________
-M_W"T`````````@```.H```#\_________WRT`````````@```&,```#\____
-M_____Y6T`````````@```-X```#\_________P*U`````````@```'<```#\
-M_________VZU`````````@```'$```#\_________TBV`````````@```"P`
-M``#\_________\.V`````````@```%<```#\_________\ZV`````````@``
-M`"P```#\_________P>W`````````@```&@```#\_________Q*W````````
-M`@```!T```#\_________QJW`````````@```&\```#\_________V"W````
-M`````@```(H```#\_________W"W`````````@```),```#\_________XJW
-M`````````@```"P```#\_________\VW````````"P```+0`````````````
-M`-BW`````````@```#X```#\_________Q.X`````````@```(H```#\____
-M_____U2X````````"P```+0``````````````%^X`````````@```#X```#\
-M_________Z^X`````````@```(H```#\_________\.X`````````@```),`
-M``#\_________]:X`````````@```"P```#\_________R&Y````````"P``
-M``$````@N@```````"ZY`````````@```.P```#\_________SZY````````
-M`@```*X```#\_________TFY`````````@```#X```#\_________Y2Y````
-M`````@```(H```#\_________]2Y````````"P```*T``````````````-^Y
-M`````````@```#X```#\_________^^Y`````````@```*0"``#\________
-M__NY`````````@```*0"``#\__________JZ`````````@```"D```#\____
-M_____PJ[`````````@```(,```#\_________Q6[`````````@```"P```#\
-M_________UB[`````````@```'P```#\_________WB[`````````@```"D`
-M``#\_________XB[`````````@```(,```#\_________Y.[`````````@``
-M`"P```#\_________Y*\`````````@```*0"``#\_________YV\````````
-M`@```"P```#\_________\^\`````````@```'P```#\_________]N\````
-M`````@```*0"``#\_________^:\`````````@```"P```#\_________S"]
-M`````````@```(H```#\_________W*]`````````@```!L```#\________
-M_X&]`````````@```"P```#\_________Y>]````````"P```+0`````````
-M`````**]`````````@```#X```#\_________^:]`````````@```(H```#\
-M_________P2^`````````@```),```#\_________QZ^`````````@```"P`
-M``#\_________X*^````````"P```+0``````````````).^`````````@``
-M`.P```#\_________Z6^`````````@```*X```#\_________["^````````
-M`@```#X```#\_________P._`````````@```(H```#\_________R2_````
-M`````@```),```#\_________T"_`````````@```"P```#\_________ZJ_
-M````````"P```+0``````````````+>_`````````@```.P```#\________
-M_\B_`````````@```*X```#\_________]._`````````@```#X```#\____
-M_____RK``````````@```(H```#\_________TC``````````@```),```#\
-M_________V3``````````@```"P```#\_________\+`````````"P```+0`
-M`````````````-;``````````@```.P```#\_________^?``````````@``
-M`*X```#\__________+``````````@```#X```#\_________TK!````````
-M`@```(H```#\_________VC!`````````@```),```#\_________X3!````
-M`````@```"P```#\_________]K!````````"P```+0``````````````.?!
-M`````````@```.P```#\__________C!`````````@```*X```#\________
-M_P/"`````````@```#X```#\_________W?"`````````@```(H```#\____
-M_____R7#````````"P````$```"`M0```````#/#`````````@```.P```#\
-M_________S[#`````````@```#X```#\_________Z'%`````````@```"L!
-M``#\_________[+%`````````@```%<```#\_________PS&`````````@``
-M`&@```#\_________^;&`````````@```)$```#\_________W7'````````
-M`@```(H```#\_________Y3'`````````@```!<!``#\_________Z?'````
-M`````@```"P```#\__________S'````````"P````P!``````````````K(
-M`````````@```.P```#\_________Q7(`````````@```#X```#\________
-M_W7(`````````@```(H```#\_________XG(`````````@```!<!``#\____
-M_____^#(````````"P````P!`````````````.[(`````````@```.P```#\
-M__________G(`````````@```#X```#\_________P/)`````````@```*0"
-M``#\_________US)`````````@```(H```#\_________VS)`````````@``
-M`!<!``#\_________[_)````````"P````P!`````````````,W)````````
-M`@```.P```#\_________]C)`````````@```#X```#\_________R7*````
-M`````@```(H```#\_________S7*`````````@```!<!``#\_________X3*
-M````````"P````P!`````````````)+*`````````@```.P```#\________
-M_YW*`````````@```#X```#\_________]3*`````````@```$T```#\____
-M_____^3*`````````@```"H```#\__________#+`````````@```$T```#\
-M_________P#,`````````@```"H```#\_________W#,`````````@```+D`
-M``#\_________P/-`````````@```)<```#\_________V'-`````````@``
-M`!,!``#\_________Y#-`````````@```$T```#\_________Z#-````````
-M`@```"H```#\_________P[.`````````@```)L```#\_________W+.````
-M`````@````@!``#\_________\C.`````````@```-L```#\_________^O.
-M`````````@```'<```#\__________S.`````````@````@!``#\________
-M_S//`````````@```-L```#\_________T3/`````````@````@!``#\____
-M_____V;/`````````@```'\"``#\_________XG/`````````@```'\"``#\
-M__________#/`````````@```&D```#\_________SK0`````````@```-L`
-M``#\_________U+0`````````@```'$```#\_________UW0`````````@``
-M`+\```#\_________QS1`````````@```&@```#\_________R_1````````
-M`@```'8```#\_________T[1````````"P````L!`````````````&71````
-M`````@```)T"``#\__________G1`````````@```&@```#\_________PS2
-M`````````@```+\```#\_________R?2````````"P```%(`````````````
-M`#[2`````````@```)T"``#\__________72`````````@```-L```#\____
-M_____P#3`````````@```#4```#\_________PO3`````````@```)$```#\
-M_________Z+3````````"P````L!`````````````+G3`````````@```)T"
-M``#\_________UK4````````"P```%(``````````````''4`````````@``
-M`)T"``#\_________R36`````````@```&@```#\_________W[6````````
-M`@```($```#\_________XW6`````````@```"P```#\_________\K6````
-M`````@```%4```#\__________K6`````````@```+<```#\_________Q;7
-M`````````@```$@```#\_________T?7`````````@```&@```#\________
-M_['7`````````@```",!``#\_________\?7`````````@```($```#\____
-M_____]37`````````@```"P```#\_________T38`````````@```#L```#\
-M_________W38`````````@```$(```#\_________W[8`````````@```*0"
-M``#\_________Z38`````````@```*8```#\_________[[8`````````@``
-M`*P```#\_________^W8`````````@```!@```#\__________[8````````
-M`@```+(```#\_________Q'9````````"P````8````*`0```````!O9````
-M`````@```*\"``#\_________S#9`````````@```+H"``#\_________T79
-M`````````@```+H"``#\_________XW9`````````@```#H```#\________
-M_[39`````````@```&@```#\__________+9`````````@```!\!``#\____
-M_____SC:`````````@```#L```#\_________V?:`````````@```$(```#\
-M_________W':`````````@```*0"``#\_________Y?:`````````@```*8`
-M``#\_________[':`````````@```*P```#\_________\S:`````````@``
-M`!@```#\_________]W:`````````@```+(```#\__________K:````````
-M"P````$!`````````````!/;````````"P````4```#(`P```````!W;````
-M`````@```*\"``#\_________S+;`````````@```+H"``#\_________[+;
-M`````````@```+H"``#\_________QS<`````````@```&@```#\________
-M_U'<`````````@```+H"``#\_________W'<`````````@```#H```#\____
-M_____\;<`````````@```(H```#\_________]K<`````````@```),```#\
-M__________3<`````````@```"P```#\_________WG=````````"P```+0`
-M`````````````(K=`````````@```.P```#\_________YS=`````````@``
-M`*X```#\_________Z?=`````````@```#X```#\_________^3=````````
-M`@```$T```#\__________3=`````````@```"H```#\_________^C>````
-M`````@````@!``#\_________RG?`````````@```"H```#\_________WW?
-M`````````@```&@```#\_________UKC`````````@```*@```#\________
-M_X7C`````````@```%D```#\_________POD````````"P````$```#0\```
-M`````"SD`````````@```!P```#\_________ROE````````"P````$```#0
-M\````````%_E`````````@```!P```#\_________USF````````"P````$`
-M``#0\````````(_F`````````@```!P```#\__________?F````````"P``
-M``$```#0\````````"?G`````````@```!P```#\_________W?G````````
-M"P````$```#0\````````*?G`````````@```!P```#\_________W7H````
-M`````@```"````#\_________^WH`````````@````8!``#\_________\7I
-M`````````@```/````#\_________V/J`````````@```&P```#\________
-M_]?J`````````@```*@```#\_________P?K`````````@```$4```#\____
-M_____R3K`````````@```%H```#\_________T7L`````````@```%D```#\
-M_________PON`````````@```+L```#\_________TWN`````````@```/``
-M``#\__________3N`````````@```&P```#\_________W7O`````````@``
-M`.@```#\_________PKP`````````@```&P```#\_________[+P````````
-M`@```&P```#\_________P3Q`````````@```%D```#\_________V[Q````
-M`````@```&P```#\_________ZKQ`````````@```&P```#\__________OQ
-M`````````@```&P```#\_________SOR`````````@```&P```#\________
-M_ZWU`````````@```&P```#\_________Q#V`````````@```)("``#\____
-M_____S3V`````````@```)("``#\_________Y'W`````````@```-(```#\
-M_________]_X`````````@```)("``#\__________[X`````````@```)("
-M``#\_________QKY`````````@```"P```#\_________WGY`````````@``
-M`*0"``#\_________XGY`````````@```)("``#\_________[+Y````````
-M`@```*0"``#\_________\+Y`````````@```)("``#\_________\_Z````
-M`````@```*0"``#\_________][Z`````````@```)("``#\__________#Z
-M`````````@```*0"``#\__________CZ`````````@```)("``#\________
-M_Q?[`````````@```*0"``#\_________Q_[`````````@```)("``#\____
-M_____TG[`````````@```*0"``#\_________UC[`````````@```)("``#\
-M_________VK[`````````@```*0"``#\_________W+[`````````@```)("
-M``#\_________Y'[`````````@```*0"``#\_________YG[`````````@``
-M`)("``#\_________][[`````````@```*0"``#\_________TS\````````
-M`@```*0"``#\_________V'\`````````@```$(```#\_________[[\````
-M`````@```(H```#\_________RW]````````"P```+$``````````````#3]
-M````````"P```-<``````````````$?]`````````@```#X```#\________
-M_Z7]`````````@```(H```#\_________Q7^````````"P```#$`````````
-M`````!W^`````````@```#X```#\_________[#^`````````@```)("``#\
-M_________][^`````````@```)("``#\_________R__`````````@```-8`
-M``#\_________SS_`````````@```"T```#\_________X__`````````@``
-M`(H```#\_________^+_````````"P```#$``````````````.K_````````
-M`@```#X```#\_________X0``0```````@```)("``#\_________[(``0``
-M`````@```)("``#\__________\``0```````@```!````#\_________PP!
-M`0```````@```"T```#\_________W8!`0```````@```(H```#\________
-M_\@!`0``````"P```+$``````````````,\!`0``````"P```-<`````````
-M`````.(!`0```````@```#X```#\_________S@"`0```````@```(H```#\
-M_________Z,"`0``````"P````$````@-@$``````+4"`0```````@```#X`
-M``#\_________^("`0``````"P```!T!`````````````'X#`0```````@``
-M`*0"``#\_________XL#`0```````@```)("``#\_________Z`#`0``````
-M`@```*0"``#\_________ZH#`0```````@```)("``#\_________VX$`0``
-M`````@```*0"``#\_________WL$`0```````@```)("``#\_________Y`$
-M`0```````@```*0"``#\_________YH$`0```````@```)("``#\________
-M_S8%`0```````@```-\```#\_________V@%`0```````@````,!``#\____
-M_____W`%`0```````@```-(```#\_________[8%`0```````@```)("``#\
-M_________]8%`0```````@```)("``#\__________(%`0```````@```)("
-M``#\_________Q\&`0```````@```)("``#\_________VT&`0```````@``
-M`/$```#\_________W4&`0```````@```!8```#\_________]L&`0``````
-M`@```*0"``#\_________^L&`0```````@```)("``#\_________Q`'`0``
-M`````@```*0"``#\_________R`'`0```````@```)("``#\_________RD*
-M`0```````@```'H```#\_________]P*`0```````@```*@```#\________
-M_T8,`0```````@```*@```#\_________VD,`0```````@```*@```#\____
-M_____^(,`0```````@```"@!``#\_________P,.`0```````@```*0"``#\
-M_________RX.`0```````@```*0"``#\_________^X.`0```````@```-@`
-M``#\_________P\/`0```````@```-T```#\_________R4/`0```````@``
-M``4!``#\_________S0/`0```````@````4!``#\_________[T/`0``````
-M`@```)("``#\_________^L/`0```````@```)("``#\_________Q\0`0``
-M`````@```*0"``#\_________S<0`0```````@```)("``#\_________X40
-M`0```````@```)("``#\_________^P0`0```````@```)("``#\________
-M_U\1`0```````@```)("``#\_________Q<2`0```````@```*0"``#\____
-M_____RH2`0```````@```)("``#\_________T<2`0```````@```%0```#\
-M_________U(2`0```````@```&<```#\_________V02`0```````@```*0"
-M``#\_________WX2`0```````@```*0"``#\_________Y@2`0```````@``
-M`*0"``#\_________[@2`0```````@```(4```#\_________\D2`0``````
-M`@```)("``#\_________Q<3`0```````@```*0"``#\_________RH3`0``
-M`````@```)("``#\_________T<3`0```````@```%0```#\_________U(3
-M`0```````@```&<```#\_________V03`0```````@```*0"``#\________
-M_WX3`0```````@```*0"``#\_________Y@3`0```````@```*0"``#\____
-M_____[@3`0```````@```(4```#\_________\D3`0```````@```)("``#\
-M_________^T3`0```````@```*0"``#\__________@3`0```````@```!(`
-M``#\_________Q84`0```````@````T!``#\_________R,4`0```````@``
-M`)("``#\_________SX4`0```````@```)("``#\_________U84`0``````
-M`@```)("``#\_________T`5`0```````@```)("``#\_________]L5`0``
-M`````@```(H```#\__________D5`0```````@```),```#\_________Q46
-M`0```````@```"P```#\_________WL6`0``````"P````$````@-@$`````
-M`(@6`0```````@```.P```#\_________Y<6`0```````@```*X```#\____
-M_____Z(6`0```````@```#X```#\_________[P7`0``````"P````4```#P
-M`P```````,87`0```````@```*\"``#\_________U48`0``````"P````4`
-M``!`!````````%\8`0```````@```*\"``#\_________V\8`0```````@``
-M`!\!``#\_________XH8`0```````@```$D```#\_________UL9`0``````
-M`@```)P```#\_________]89`0``````"P```)4``````````````.$9`0``
-M`````@```,(```#\__________D9`0```````@```'T```#\_________U,:
-M`0```````@```)P```#\_________V8:`0```````@```"<!``#\________
-M_Y8:`0```````@```,P```#\_________TP;`0```````@```"$!``#\____
-M_____U8;`0```````@```*$```#\_________QL<`0```````@```!\!``#\
-M_________Y(<`0```````@```&@```#\_________^@<`0```````@```",!
-M``#\_________PT=`0```````@```+<```#\_________QT=`0```````@``
-M`,P```#\_________[T=`0```````@```.0```#\_________VL>`0``````
-M`@```&@```#\_________^@>`0```````@```.0```#\_________X`?`0``
-M`````@```+H"``#\_________Y<?`0```````@```+H"``#\_________\H?
-M`0```````@```.0```#\_________S,@`0```````@```+H"``#\________
-M_XP@`0```````@```+H"``#\_________]$@`0```````@```#L```#\____
-M_____P0A`0```````@```$(```#\_________PXA`0```````@```*0"``#\
-M_________S0A`0```````@```*8```#\_________TXA`0```````@```*P`
-M``#\_________VDA`0```````@```!@```#\_________WHA`0```````@``
-M`+(```#\_________XTA`0``````"P````8````@`0```````)<A`0``````
-M`@```*\"``#\_________ZTA`0```````@```+H"``#\_________[XA`0``
-M````"P````8````@`0```````,@A`0```````@```*\"``#\_________]XA
-M`0```````@```+H"``#\_________RHB`0```````@```+H"``#\________
-M_W4B`0```````@```#H```#\_________Y$B`0```````@```+H"``#\____
-M_____^TB`0```````@```/H```#\_________QDC`0```````@```!\!``#\
-M_________S8C`0```````@```'T```#\_________WTC`0```````@```'4`
-M``#\_________\LC`0``````"P````,```"`"P```````#$D`0```````@``
-M`-,```#\_________TTD`0```````@```(D```#\_________VDD`0``````
-M`@```(D```#\_________X4D`0```````@```(D```#\_________Z$D`0``
-M`````@```(D```#\_________\(D`0```````@```(<```#\_________^0D
-M`0```````@```(<```#\_________Q$E`0```````@```(<```#\________
-M_S,E`0```````@```(<```#\_________STE`0```````@```*0"``#\____
-M_____VHE`0```````@```(<```#\_________XPE`0```````@```(<```#\
-M_________Y8E`0```````@```*0"``#\_________[(E`0```````@```(D`
-M``#\_________\XE`0```````@```(D```#\_________^HE`0```````@``
-M`(D```#\_________PPF`0```````@```(<```#\_________R@F`0``````
-M`@```(D```#\_________WTF`0```````@```*0"``#\__________HF`0``
-M`````@```)("``#\_________Q@G`0```````@```)("``#\_________RPG
-M`0```````@```*0"``#\_________T8G`0```````@```+<```#\________
-M_U4G`0```````@```*0"``#\_________VPG`0```````@```(D```#\____
-M_____W8G`0```````@```*0"``#\_________Y(G`0```````@```(D```#\
-M_________YPG`0```````@```*0"``#\_________\DG`0```````@```(<`
-M``#\_________],G`0```````@```*0"``#\_________^\G`0```````@``
-M`(D```#\__________DG`0```````@```*0"``#\_________P,H`0``````
-M`@```-````#\_________Q$H`0```````@```$H```#\_________S,H`0``
-M`````@```(<```#\_________U4H`0```````@```(<```#\_________W<H
-M`0```````@```(<```#\_________YDH`0```````@```(<```#\________
-M_[4H`0```````@```(D```#\_________\0H`0```````@```*0"``#\____
-M_____]LH`0```````@```(D```#\_________^4H`0```````@```*0"``#\
-M_________P<I`0```````@```(<```#\_________R,I`0```````@```(D`
-M``#\_________T0I`0```````@```(<```#\_________UDI`0```````@``
-M`*$```#\_________W(I`0```````@```(D```#\_________WPI`0``````
-M`@```*0"``#\_________Z8I`0```````@```(<```#\_________[`I`0``
-M`````@```*0"``#\_________\DI`0```````@```(D```#\_________],I
-M`0```````@```*0"``#\_________P\K`0```````@```"D```#\________
-M_QHK`0```````@```"P```#\_________X4K`0```````@```)("``#\____
-M_____ZPK`0```````@```)("``#\_________^TK`0```````@```)("``#\
-M_________Q8L`0```````@```"D```#\_________R$L`0```````@```"P`
-M``#\_________RPL`0```````@```-,```#\_________ULL`0```````@``
-M`-,```#\_________Z0M`0```````@```'4```#\_________ZXM`0``````
-M`@```*0"``#\_________\TM`0```````@```'4```#\_________]<M`0``
-M`````@```*0"``#\_________V4N`0```````@```)("``#\_________WPN
-M`0```````@```)("``#\_________[LN`0```````@```*0"``#\________
-M_]0N`0```````@```+<```#\_________^\N`0```````@```-H```#\____
-M_____P0O`0```````@```-H```#\_________Q(O`0```````@```*0"``#\
-M_________T`O`0```````@```)("``#\_________V8O`0```````@```)("
-M``#\_________WXO`0```````@```*0"``#\_________X\O`0``````"P``
-M``4```!X!````````)DO`0```````@```*\"``#\_________ZDO`0``````
-M`@```(H```#\__________@O`0``````"P````$````@-@$```````,P`0``
-M`````@```#X```#\_________Q0P`0``````"P````8````V`0```````!XP
-M`0```````@```*\"``#\_________RXP`0```````@```(H```#\________
-M_WTP`0``````"P````$````@-@$``````(@P`0```````@```#X```#\____
-M_____[,P`0```````@```(H```#\_________P8Q`0``````"P````$````@
-M-@$``````!0Q`0```````@```#X```#\_________RHQ`0```````@```(H`
-M``#\_________WTQ`0``````"P````$````@-@$``````(LQ`0```````@``
-M`#X```#\_________Z$Q`0```````@```(H```#\__________`Q`0``````
-M"P````$````@-@$``````/LQ`0```````@```#X```#\_________Q@R`0``
-M`````@```(H```#\_________V<R`0``````"P````$````@-@$``````'(R
-M`0```````@```#X```#\_________X@R`0```````@```(H```#\________
-M_^(R`0``````"P````$````@-@$``````.TR`0```````@```#X```#\____
-M_____R@S`0```````@```)P```#\_________T,S`0```````@```%@```#\
-M_________YLS`0```````@```-,```#\_________]<S`0```````@```-,`
-M``#\_________^DS`0```````@```&@```#\_________SDT`0```````@``
-M`",!``#\_________V$T`0```````@```+<```#\_________W8T`0``````
-M`@```,P```#\_________Z0T`0```````@```&@```#\_________P(U`0``
-M`````@```",!``#\_________RTU`0```````@```+<```#\_________T(U
-M`0```````@```,P```#\_________WLU`0```````@```&@```#\________
-M_ZDU`0```````@```#8```#\_________\<U`0```````@```!\!``#\____
-M_____T8W`0```````@```"D```#\_________U$W`0```````@```"P```#\
-M_________]<W`0```````@```*0"``#\_________QTX`0```````@```%4`
-M``#\_________S(X`0```````@```+<```#\_________XHX`0``````"P``
-M``4```"P!````````)0X`0```````@```*\"``#\_________Z8X`0``````
-M`@```.,```#\_________R4Y`0```````@```*0"``#\_________\,Y`0``
-M`````@```"D```#\_________\XY`0```````@```"P```#\_________^4Y
-M`0```````@```"D```#\__________`Y`0```````@```"P```#\________
-M__LY`0```````@```+<```#\_________^$Z`0```````@```!@!``#\____
-M______@Z`0```````@```!@!``#\_________P\[`0```````@```)````#\
-M_________R$[`0```````@```+@```#\_________S0[`0```````@```.(`
-M``#\_________U$[`0```````@```/@```#\_________V,[`0```````@``
-M`,@```#\_________W4[`0```````@```)(```#\_________XD[`0``````
-M`@```&L```#\_________[0[`0```````@```&@```#\_________Q(\`0``
-M`````@```",!``#\_________ST\`0```````@```+<```#\_________U(\
-M`0```````@```,P```#\_________Z<\`0```````@```#8```#\________
-M_[8\`0```````@```&@```#\_________^$\`0``````"P````8```!,`0``
-M`````.L\`0```````@```*\"``#\__________@\`0```````@```#8```#\
-M_________Q@]`0```````@```!\!``#\_________[0^`0```````@```.L`
-M``#\_________\@^`0``````"P````,```"H#````````"$_`0```````@``
-M`'T```#\_________YP_`0```````@```)P```#\_________[$_`0``````
-M`@```"<!``#\_________^L_`0```````@```,P```#\_________W1``0``
-M`````@```&@```#\_________Y5``0```````@```.$```#\_________]-`
-M`0```````@```*@```#\_________X1!`0```````@```+H"``#\________
-M_[Q!`0```````@```#L```#\_________]9!`0```````@```$(```#\____
-M_____^!!`0```````@```*0"``#\_________PM"`0```````@```*8```#\
-M_________RA"`0```````@```*P```#\_________TQ"`0```````@```!@`
-M``#\_________V!"`0```````@```+(```#\_________WM"`0```````@``
-M`+H"``#\_________Y9"`0```````@```+H"``#\_________\Y"`0``````
-M`@```#H```#\_________SU#`0```````@```.$```#\_________TM#`0``
-M`````@```!4```#\_________P%$`0```````@```*@```#\_________U!%
-M`0```````@```",!``#\_________V1%`0```````@```,P```#\________
-M_Y%%`0```````@```#8```#\_________YU%`0```````@```'T```#\____
-M_____TI&`0```````@```&@```#\_________VM&`0```````@```.$```#\
-M_________Y]&`0```````@```.$```#\_________\]&`0```````@```.$`
-M``#\_________^%&`0```````@```*@```#\_________Q]'`0```````@``
-M`!L!``#\_________VI(`0```````@```+4```#\_________XQ(`0``````
-M`@```&@```#\_________Z!(`0```````@```#L```#\_________[1(`0``
-M`````@```$(```#\_________[Y(`0```````@```*0"``#\_________^9(
-M`0```````@```!@```#\__________=(`0```````@```+(```#\________
-M_PQ)`0```````@```+H"``#\_________R%)`0```````@```+H"``#\____
-M_____TU)`0```````@```#H```#\_________VA)`0```````@```(L```#\
-M_________]A)`0```````@```#\```#\__________5)`0```````@```.$`
-M``#\_________SE*`0```````@```.$```#\_________VI*`0```````@``
-M`.$```#\_________WQ*`0```````@```!L!``#\_________XY*`0``````
-M`@```$D```#\_________[=*`0```````@```!L!``#\_________PM,`0``
-M`````@```'T```#\_________S--`0```````@```",!``#\_________T)-
-M`0```````@```,P```#\_________X9-`0```````@```!\!``#\________
-M_\5-`0```````@```.$```#\_________^Q-`0```````@```+H```#\____
-M_____U9.`0```````@```!<```#\_________VM.`0``````"P```)4`````
-M`````````'9.`0```````@```,(```#\_________YI.`0```````@```+,`
-M``#\_________Z5.`0```````@```!<```#\_________]].`0```````@``
-M`-H```#\_________^U.`0```````@```*0"``#\_________SU/`0``````
-M`@```#H```#\_________U1/`0```````@```*<```#\_________X=/`0``
-M`````@```-,```#\_________ZE/`0```````@```'\"``#\_________[5/
-M`0```````@```/8```#\_________\M/`0```````@```&@```#\________
-M_^U/`0```````@```!@```#\__________Y/`0```````@```+(```#\____
-M_____Q-0`0```````@```+H"``#\_________RA0`0```````@```+H"``#\
-M_________S]0`0```````@```#H```#\_________V!0`0```````@```&@`
-M``#\_________W%0`0```````@```'T```#\_________[)0`0```````@``
-M`+<```#\_________Z%1`0```````@```"D```#\_________ZQ1`0``````
-M`@```"P```#\_________PI2`0``````"P````4```#0!````````!12`0``
-M`````@```*\"``#\_________S12`0```````@```#H```#\_________S]2
-M`0```````@```"P```#\_________W92`0```````@```/L```#\________
-M_ZQ2`0```````@```*0"``#\_________[=2`0```````@```"P```#\____
-M_____\Q2`0```````@```'4```#\_________]A2`0```````@```*0"``#\
-M_________^-2`0```````@```"P```#\_________^Y2`0```````@```'(`
-M``#\_________T13`0```````@```&@```#\_________ZQ3`0```````@``
-M`+<```#\_________R15`0```````@```(<```#\_________X!5`0``````
-M`@```"D```#\_________XM5`0```````@```"P```#\_________Y]5`0``
-M`````@```-,```#\_________\95`0``````"P````,```"P#````````/]5
-M`0```````@```)("``#\_________U%6`0```````@```)("``#\________
-M_WQ6`0```````@```)("``#\_________\Q6`0```````@```)("``#\____
-M______-6`0```````@```)("``#\_________UM7`0```````@```)("``#\
-M_________Y=7`0```````@```"D```#\_________Z)7`0```````@```"P`
-M``#\_________[)7`0```````@```!\!``#\_________^U7`0```````@``
-M`"D```#\__________A7`0```````@```"P```#\_________PY8`0``````
-M"P```-D``````````````"58`0```````@```)T"``#\_________SY8`0``
-M`````@```*0"``#\_________VM8`0```````@```,,"``#\_________Y]8
-M`0```````@```)("``#\_________\58`0```````@```)("``#\________
-M_\I8`0```````@```,,"``#\_________T19`0```````@```&@```#\____
-M_____Z!9`0```````@```!@```#\_________\!9`0```````@```+(```#\
-M_________^A9`0```````@```+H"``#\_________Y-:`0``````"P````$!
-M`````````````*Y:`0``````"P````4````H!0```````+A:`0```````@``
-M`*\"``#\_________]%:`0```````@```+H"``#\__________=:`0``````
-M`@```#H```#\_________R1;`0```````@```)("``#\_________TI;`0``
-M`````@```)("``#\_________YI;`0```````@```&@```#\_________]9;
-M`0```````@```'T```#\_________P1<`0```````@```$(```#\________
-M_PY<`0```````@```*0"``#\_________TU<`0```````@```)("``#\____
-M_____W-<`0```````@```)("``#\_________VA=`0```````@```)("``#\
-M_________XM=`0```````@```)("``#\_________QM>`0```````@```(P`
-M``#\_________SA>`0```````@````@!``#\_________W=>`0```````@``
-M`)("``#\_________YI>`0```````@```)("``#\_________]%>`0``````
-M`@```)("``#\__________1>`0```````@```)("``#\_________TE?`0``
-M`````@```)("``#\_________V]?`0```````@```)("``#\_________ZQ?
-M`0```````@```)("``#\_________]1?`0```````@```"D```#\________
-M_]]?`0```````@```"P```#\_________^I?`0```````@```-,```#\____
-M_____P%@`0```````@```$(```#\_________PM@`0```````@```*0"``#\
-M_________W5A`0```````@```"D```#\_________X!A`0```````@```"P`
-M``#\_________\]A`0```````@```"D```#\_________]IA`0```````@``
-M`"P```#\__________%A`0```````@```,P```#\__________YB`0``````
-M`@```(8"``#\_________U=C`0``````"P````8```!@`0```````&%C`0``
-M`````@```*\"``#\_________W1C`0```````@```"D```#\_________W]C
-M`0```````@```"P```#\_________\9C`0```````@```&@```#\________
-M_U-D`0```````@```&@```#\_________[MD`0```````@```,P```#\____
-M_____X5E`0```````@```*0"``#\_________PAF`0```````@```*0"``#\
-M_________UYF`0```````@```*0"``#\_________W]F`0```````@```"D`
-M``#\_________XIF`0```````@```"P```#\_________YAF`0```````@``
-M`/T```#\_________UEG`0```````@```*0"``#\_________YYG`0``````
-M`@```*0"``#\_________[]G`0```````@```"D```#\_________\IG`0``
-M`````@```"P```#\_________]AG`0```````@```/T```#\_________PYH
-M`0```````@```*0"``#\_________V=H`0```````@```*0"``#\________
-M_\1H`0```````@```*0"``#\__________]H`0```````@```)D```#\____
-M_____R]I`0```````@```"D```#\_________SII`0```````@```"P```#\
-M_________T5I`0```````@```,P```#\_________ZAI`0```````@```)("
-M``#\_________T]L`0```````@```!H```#\_________V-L`0```````@``
-M`!H```#\_________W]L`0```````@```!H```#\_________P=M`0``````
-M`@```!H```#\_________QMM`0```````@```!H```#\_________SEM`0``
-M`````@```!H```#\_________WYM`0```````@```(P```#\_________[9M
-M`0```````@```-8```#\_________\-M`0```````@```"T```#\________
-M_P9N`0```````@```,8```#\_________TEN`0```````@```",```#\____
-M_____WIN`0```````@```,4```#\_________]9N`0```````@```*0"``#\
-M_________S5T`0```````@````L````<`````````$%T`0``````"P````L`
-M```@`````````$YT`0```````@```$$```#\_________Y9T`0```````@``
-M`&(```#\_________W)U`0```````@```)8```#\_________Y]U`0``````
-M`@```/,```#\_________ZYU`0```````@```)8```#\_________Y)V`0``
-M`````@```&@```#\_________]EV`0```````@```-4```#\__________9V
-M`0```````@```(8"``#\_________PUW`0```````@```#````#\________
-M_X5W`0```````@```$<```#\_________[QW`0```````@```,4```#\____
-M_____P)X`0```````@```+8```#\_________^%X`0```````@```*0"``#\
-M_________]-Y`0```````@````L````>`````````.!Y`0``````"P````L`
-M```@`````````.IY`0```````@```$$```#\_________RMZ`0```````@``
-M``L````>`````````#AZ`0``````"P````L````@`````````$)Z`0``````
-M`@```$$```#\_________\-Z`0```````@```)("``#\_________Q%[`0``
-M`````@```)("``#\_________RE[`0```````@```"@```#\_________SM[
-M`0```````@```"@```#\_________TU[`0```````@```"@```#\________
-M_U][`0```````@```"@```#\_________W%[`0```````@```"@```#\____
-M_____X-[`0```````@```"@```#\_________Y5[`0```````@```"@```#\
-M_________Z=[`0```````@```"@```#\_________[E[`0```````@```"@`
-M``#\_________\M[`0```````@```"@```#\_________]U[`0```````@``
-M`"@```#\_________^][`0```````@```"@```#\_________P%\`0``````
-M`@```"@```#\_________Q-\`0```````@```"@```#\_________R5\`0``
-M`````@```"@```#\_________S=\`0```````@```"@```#\_________TE\
-M`0```````@```"@```#\_________UM\`0```````@```"@```#\________
-M_VU\`0```````@```"@```#\_________W]\`0```````@```"@```#\____
-M_____Y%\`0```````@```"@```#\_________Z-\`0```````@```"@```#\
-M_________[5\`0```````@```"@```#\_________\=\`0```````@```"@`
-M``#\_________]E\`0```````@```"@```#\_________^M\`0```````@``
-M`"@```#\_________U-]`0```````@```)("``#\_________W-]`0``````
-M`@```)("``#\__________5]`0```````@```"@```#\_________PI^`0``
-M`````@```"@```#\_________Q]^`0```````@```"@```#\_________S1^
-M`0```````@```"@```#\_________TE^`0```````@```"@```#\________
-M_Y5^`0```````@```(H```#\_________ZE^`0```````@```!<!``#\____
-M_____SM_`0```````@```(8"``#\_________VA_`0```````@```(8"``#\
-M_________W-_`0``````"P```!P!`````````````(%_`0```````@```.P`
-M``#\_________XQ_`0```````@```#X```#\_________]E_`0```````@``
-M`(H```#\_________^E_`0```````@```!<!``#\_________T.``0``````
-M"P```!P!`````````````%&``0```````@```.P```#\_________UR``0``
-M`````@```#X```#\_________[B``0```````@```+X```#\_________\:`
-M`0```````@```$(```#\_________]"``0```````@```*0"``#\________
-M_P2!`0```````@```#D```#\_________Q2!`0```````@```$(```#\____
-M_____QZ!`0```````@```*0"``#\_________T.!`0```````@```+X```#\
-M_________U2!`0```````@```$(```#\_________UZ!`0```````@```*0"
-M``#\_________Z6!`0```````@```#D```#\_________SV"`0```````@``
-M`($```#\_________TB"`0```````@```"P```#\_________].$`0``````
-M`@```"<```#\__________&$`0```````@```.\```#\_________]:%`0``
-M`````@```(@```#\_________^N%`0``````"P```%\``````````````"N&
-M`0```````@```"<```#\_________SV&`0```````@```.\```#\________
-M_]2&`0```````@```(@```#\_________P&'`0```````@```(@```#\____
-M_____Z^'`0```````@```*L```#\_________\>'`0```````@```#0```#\
-M_________]^'`0```````@```'X```#\_________T>(`0``````"P````,`
-M``#8#0```````+2+`0```````@```!D```#\_________T*,`0```````@``
-M`!D```#\_________UN,`0```````@```(8"``#\_________RV-`0``````
-M`@```.````#\_________[2.`0```````@```)("``#\_________\B.`0``
-M`````@```)("``#\_________]:.`0```````@```*0"``#\_________Q^/
-M`0```````@````<````$`````````&J/`0```````@```)("``#\________
-M_YZ/`0``````"P````<``````````````,:/`0```````@````<````4````
-M`````!20`0```````@```)("``#\_________XF0`0```````@````<````D
-M`````````->0`0```````@```)("``#\_________PN1`0``````"P````<`
-M```@`````````"Z1`0```````@````<````T`````````'R1`0```````@``
-M`)("``#\_________^>1`0``````"P````<````0`````````/F1`0``````
-M"P````<````P`````````(^2`0```````@```)("``#\_________R*3`0``
-M`````@```)("``#\_________\&3`0```````@```)("``#\_________^"3
-M`0```````@```*0"``#\_________ZZ4`0```````@```"4```#\________
-M_V"7`0```````@```.D```#\_________^>8`0```````@````,```#X$@``
-M`````/.8`0``````"P````<```#``0```````'><`0``````"P````<```"`
-M`````````'R<`0```````@```'<"``#\__________J<`0```````@```$$`
-M``#\_________PB=`0```````@```*0"``#\_________QV=`0```````@``
-M``0!``#\_________T>=`0``````"P````8```!T`0```````%&=`0``````
-M`@```*\"``#\_________Z:=`0```````@```)H"``#\_________[J=`0``
-M`````@```)H"``#\_________\Z=`0```````@```)H"``#\_________T&>
-M`0```````@```"\```#\_________UN>`0```````@```*,"``#\________
-M_VZ>`0```````@```*,"``#\_________XB>`0```````@```*,"``#\____
-M_____YN>`0```````@```*,"``#\_________[6>`0```````@```*,"``#\
-M_________\B>`0```````@```*,"``#\_________^*>`0```````@```*,"
-M``#\__________6>`0```````@```*,"``#\_________R.?`0```````@``
-M`*,"``#\_________S.?`0```````@```*,"``#\_________UJ?`0``````
-M`@```*,"``#\_________VV?`0```````@```*,"``#\_________X>?`0``
-M`````@```*,"``#\_________YJ?`0```````@```*,"``#\_________[2?
-M`0```````@```*,"``#\_________\>?`0```````@```*,"``#\________
-M_^&?`0```````@```*,"``#\__________2?`0```````@```*,"``#\____
-M_____PZ@`0```````@```*,"``#\_________R&@`0```````@```*,"``#\
-M_________SN@`0```````@```*,"``#\_________TZ@`0```````@```*,"
-M``#\_________VB@`0```````@```*,"``#\_________WN@`0```````@``
-M`*,"``#\_________Y6@`0```````@```*,"``#\_________ZB@`0``````
-M`@```*,"``#\_________\*@`0```````@```*,"``#\_________]6@`0``
-M`````@```*,"``#\_________^^@`0```````@```*,"``#\_________P*A
-M`0```````@```*,"``#\_________QRA`0```````@```*,"``#\________
-M_R^A`0```````@```*,"``#\_________TFA`0```````@```*,"``#\____
-M_____URA`0```````@```*,"``#\_________W:A`0```````@```*,"``#\
-M_________XFA`0```````@```*,"``#\_________Z.A`0```````@```*,"
-M``#\_________[:A`0```````@```*,"``#\_________]BA`0```````@``
-M`-("``#\__________*A`0```````@```-("``#\_________Q2B`0``````
-M`@```-("``#\_________RZB`0```````@```-("``#\_________U"B`0``
-M`````@```-("``#\_________VJB`0```````@```-("``#\_________XRB
-M`0```````@```-("``#\_________Z:B`0```````@```-("``#\________
-M_\BB`0```````@```-("``#\_________^*B`0```````@```-("``#\____
-M_____P2C`0```````@```-("``#\_________QZC`0```````@```-("``#\
-M_________T"C`0```````@```-("``#\_________UJC`0```````@```-("
-M``#\_________WRC`0```````@```-("``#\_________Y:C`0```````@``
-M`-("``#\_________\VC`0```````@```,H```#\_________]ZC`0``````
-M`@```,H```#\_________PJD`0```````@```"L```#\_________Q*D`0``
-M`````@```)0```#\_________R&D`0```````@```)0```#\_________RFD
-M`0```````@```"0!``#\_________S.D`0```````@```*0"``#\________
-M_SND`0```````@```,,```#\_________TBD`0```````@```,H```#\____
-M_____U6D`0```````@```,H```#\_________Y^D`0```````@```-,```#\
-M__________:D`0```````@```-,```#\_________R6E`0```````@````H!
-M``#\_________SBE`0```````@````H!``#\_________T6E`0```````@``
-M``H!``#\_________UBE`0```````@````H!``#\_________V6E`0``````
-M`@```$(```#\_________\VE`0```````@```(H```#\_________R^F`0``
-M````"P````$```"0F@$``````#JF`0```````@```#X```#\_________W&F
-M`0```````@```#L```#\_________X.F`0```````@```*0"``#\________
-M_XNF`0```````@```$(```#\_________]&F`0```````@```"P```#\____
-M_____UJG`0```````@```(H```#\_________]NG`0``````"P````$```"0
-MF@$``````.:G`0```````@```#X```#\_________QVH`0```````@```#L`
-M``#\_________R^H`0```````@```*0"``#\_________S>H`0```````@``
-M`$(```#\_________W2H`0```````@```),```#\__________RH`0``````
-M"P````$```"0F@$```````FI`0```````@```.P```#\_________QZI`0``
-M`````@```*X```#\_________RFI`0```````@```#X```#\_________V"I
-M`0```````@```#L```#\_________W*I`0```````@```*0"``#\________
-M_WJI`0```````@```$(```#\_________ZJI`0```````@```"D```#\____
-M_____[^I`0```````@```"P```#\_________\>I`0```````@```(H```#\
-M_________]RI`0```````@```"D```#\_________^VJ`0``````"P````$`
-M``"0F@$``````/JJ`0```````@```.P```#\_________P^K`0```````@``
-M`*X```#\_________QJK`0```````@```#X```#\_________U&K`0``````
-M`@```#L```#\_________V.K`0```````@```*0"``#\_________VNK`0``
-M`````@```$(```#\_________Z6K`0```````@```"D```#\_________[RK
-M`0```````@```"P```#\_________UNL`0```````@```(H```#\________
-M_X&L`0``````"P````8```"0`0```````(NL`0```````@```*\"``#\____
-M_____Y>L`0```````@```),```#\_________["L`0```````@```"P```#\
-M_________^*L`0```````@```+H"``#\__________NL`0```````@```#L`
-M``#\_________TNM`0```````@```(8"``#\_________S.N`0```````@``
-M`&````#\_________XNN`0``````"P````$```"0F@$``````)JN`0``````
-M`@```.P```#\_________[6N`0```````@```*X```#\_________\NN`0``
-M`````@```#X```#\_________P>O`0```````@```#L```#\_________QFO
-M`0```````@```*0"``#\_________R.O`0```````@```$(```#\________
-M_V6O`0```````@```(8"``#\_________Y>O`0```````@```"D```#\____
-M_____ZRO`0```````@```(,```#\_________[NO`0```````@```"P```#\
-M_________]BO`0```````@```+H"``#\_________[BP`0```````@```"D`
-M``#\_________\BP`0```````@```(,```#\_________].P`0```````@``
-M`"P```#\_________ZRQ`0```````@```#L```#\_________^ZQ`0``````
-M`@```",!``#\_________S2R`0```````@```-,```#\_________TFR`0``
-M`````@```+<```#\_________VBR`0```````@```,P```#\_________[*R
-M`0```````@```.8```#\_________]FS`0```````@```,D```#\________
-M_P&T`0```````@```!,!``#\_________R&T`0```````@```+P"``#\____
-M_____UFT`0```````@```"L```#\_________V&T`0```````@```%X```#\
-M_________VFT`0```````@```%X```#\_________W&T`0```````@```)0`
-M``#\_________WVT`0```````@```)0```#\_________XFT`0```````@``
-M`"0!``#\_________Y.T`0```````@```*0"``#\_________YNT`0``````
-M`@```,,```#\_________["T`0``````"P```&$``````````````,>T`0``
-M`````@```)T"``#\_________]2T`0```````@```!\!``#\__________6T
-M`0```````@```!D!``#\_________P2U`0```````@```!D!``#\________
-M_RFU`0```````@````L```#?`````````#:U`0```````@````L```#<````
-M`````$&U`0```````@````,```#X$@```````%"U`0``````"P````<```#`
-M`0```````%>U`0``````"P```%P``````````````%ZU`0``````"P````<`
-M``#4`0```````&JU`0``````"P````<```#"`0```````+6U`0``````"P``
-M`%P````<`````````,VU`0``````"P```%P````<`````````.&U`0``````
-M"P```%P````<`````````.^U`0``````"P```%P````<`````````/FU`0``
-M````"P```%P````<`````````"^V`0``````"P```%P````<`````````$.V
-M`0``````"P```%P````<`````````%&V`0``````"P```%P````<````````
-M`&RV`0``````"P````<```#,`0```````+6V`0```````@````,```#X$@``
-M`````-.V`0``````"P````<```#,`0```````.&V`0``````"P````<```#0
-M`0```````!&W`0``````"P```%P``````````````"6W`0``````"P```%P`
-M```<`````````%"W`0``````"P```%P````,`````````':W`0``````"P``
-M`%P````=`````````(6W`0``````"P```%P````<`````````+ZW`0``````
-M`@```(`"``#\_________T:X`0```````@```*P```#\_________V*X`0``
-M`````@```*8```#\_________VJX`0```````@```.8```#\_________XBX
-M`0```````@```+(```#\_________YRX`0```````@```+(```#\________
-M_T&Y`0``````"P````4```!0!0```````$NY`0```````@```*\"``#\____
-M_____UVY`0```````@```(H```#\_________X:Y`0``````"P````$!````
-M`````````)NY`0``````"P````4```"8!0```````*6Y`0```````@```*\"
-M``#\_________^JY`0``````"P````$```"0F@$``````/6Y`0```````@``
-M`#X```#\_________RRZ`0```````@```#L```#\_________SZZ`0``````
-M`@```*0"``#\_________T:Z`0```````@```$(```#\_________XFZ`0``
-M`````@```(H```#\_________Z^Z`0```````@```),```#\_________\ZZ
-M`0```````@```"P```#\_________SV[`0``````"P````$```"0F@$`````
-M`$R[`0```````@```.P```#\_________UZ[`0```````@```*X```#\____
-M_____VF[`0```````@```#X```#\_________Z"[`0```````@```#L```#\
-M_________[*[`0```````@```*0"``#\_________[J[`0```````@```$(`
-M``#\_________^J[`0```````@```.,```#\_________P^\`0```````@``
-M`"D```#\_________QJ\`0```````@```"P```#\_________S&\`0``````
-M`@```"P```#\_________Y:\`0``````"P````,```#`#@```````,N\`0``
-M`````@```.4```#\_________P2]`0```````@```&4```#\_________SJ]
-M`0```````@```+H"``#\_________T^]`0```````@```#L```#\________
-M_V:]`0```````@```*0"``#\_________VZ]`0```````@```$(```#\____
-M_____Z>]`0```````@```+H"``#\_________[N]`0```````@```*4```#\
-M_________\>]`0```````@```/\```#\_________S.^`0``````"P````$!
-M`````````````$Z^`0``````"P````4```#(!0```````%B^`0```````@``
-M`*\"``#\_________XB^`0```````@```'\"``#\_________YV^`0``````
-M"P````$```#PO0$``````+&^`0```````@```)T"``#\_________T[!`0``
-M`````@```*P```#\_________W#!`0```````@```*8```#\_________YW!
-M`0```````@```&@```#\_________PC"`0```````@```&@```#\________
-M_V3"`0```````@```+H"``#\_________Z3"`0```````@```&@```#\____
-M_____Q##`0```````@```+H"``#\_________S;$`0```````@```.4```#\
-M_________XS$`0```````@```,D```#\_________Y[$`0```````@```+(`
-M``#\_________]G$`0```````@```$(```#\___________$`0```````@``
-M`!\!``#\_________Q_%`0```````@```'\"``#\_________S3%`0``````
-M"P```&$``````````````$?%`0```````@```)T"``#\_________ZG&`0``
-M`````@```.8```#\__________W&`0``````"P````,````0#P```````"7'
-M`0```````@```#T```#\_________X#'`0```````@```#T```#\________
-M_]O'`0```````@```#T```#\_________S;(`0```````@```#T```#\____
-M_____X?)`0``````"P````,````P$````````+C)`0```````@```#T```#\
-M_________QC*`0```````@```#T```#\_________W#*`0```````@```#T`
-M``#\_________\C*`0```````@```#T```#\_________R'+`0```````@``
-M`#T```#\_________WC+`0```````@```#T```#\_________]3+`0``````
-M`@```#T```#\_________S#,`0```````@```#T```#\_________XC,`0``
-M`````@```#T```#\_________^#,`0```````@```#T```#\_________S#-
-M`0```````@```(P```#\_________VK-`0```````@```(P```#\________
-M_Z3-`0```````@```(P```#\_________][-`0```````@```(P```#\____
-M_____Q7.`0```````@```(P```#\_________TS.`0```````@```(P```#\
-M_________^;.`0```````@````L```#<`````````/+.`0```````@````L`
-M``#<`````````-_0`0```````@```(X"``#\__________G0`0```````@``
-M`(X"``#\_________T/1`0```````@````,```#X$@```````%G1`0``````
-M"P````<```#``0```````&O1`0``````"P````<```#"`0```````'G1`0``
-M````"P````<```#0`0```````(+1`0``````"P````<```#0`0```````(G1
-M`0``````"P````<```#,`0```````*/1`0``````"P````<```#0`0``````
-M`-W1`0```````@```,8"``#\___________1`0```````@```+\"``#\____
-M_____RW2`0``````"P```%P``````````````$72`0``````"P```%P````<
-M`````````&S2`0``````"P```%P````,`````````(G2`0``````"P```%P`
-M```=`````````)/2`0``````"P```%P````=`````````)O2`0``````"P``
-M`%P````<`````````+C2`0``````"P```%P````=`````````,S2`0``````
-M"P```%P````<`````````#K4`0``````"P````$!`````````````$K4`0``
-M`````@```.8```#\_________[W5`0```````@```)8```#\_________^[5
-M`0```````@```/,```#\__________W5`0```````@```)8```#\________
-M_Z#9`0```````@```)8```#\_________\[9`0```````@```/,```#\____
-M_____]W9`0```````@```)8```#\_________[_=`0```````@```)8```#\
-M_________^W=`0```````@```/,```#\__________[=`0```````@```)8`
-M``#\_________[_A`0```````@```)8```#\_________^WA`0```````@``
-M`/,```#\__________[A`0```````@```)8```#\_________V3D`0``````
-M`@```(H```#\_________V#F`0```````@```(8"``#\_________RSH`0``
-M````"P````$````PL`$``````*OH`0```````@```&````#\_________[CH
-M`0```````@```.P```#\_________\OH`0```````@```*X```#\________
-M_^GH`0```````@```.P```#\__________OH`0```````@```),```#\____
-M_____RSI`0```````@```*X```#\_________T'I`0```````@```'L```#\
-M_________W+I`0```````@```*X```#\_________[?I`0```````@```(8"
-M``#\_________RKJ`0```````@```(8"``#\_________V[J`0```````@``
-M`#X```#\_________WOJ`0```````@```"P```#\_________PCM`0``````
-M`@```,8"``#\_________RKM`0```````@```,8"``#\_________X+N`0``
-M`````@```",!``#\_________]CN`0```````@```&@```#\_________S#O
-M`0```````@```+<```#\_________V'O`0```````@```-,```#\________
-M_Y_O`0```````@```(4```#\_________\KO`0```````@```,P```#\____
-M______3O`0```````@```&@```#\_________T[P`0```````@```.0```#\
-M_________PGQ`0```````@````@"``#\_________R+Q`0```````@```$8"
-M``#\_________S?Q`0```````@```$4"``#\_________\7Q`0``````"P``
-M``$```#`\`$``````-WQ`0```````@```,4!``#\__________/Q`0``````
-M`@```"X!``#\__________[Q`0```````@```$4!``#\_________Q;R`0``
-M`````@```*0"``#\_________R'R`0```````@```%<!``#\_________T#R
-M`0```````@```#`!``#\_________T_R`0```````@```'<!``#\________
-M_UKR`0```````@```$4"``#\_________WCR`0```````@```$4"``#\____
-M_____Y/R`0```````@```'H!``#\_________[#R`0```````@```,D!``#\
-M_________Q+S`0```````@```,4!``#\_________R;S`0```````@```"X!
-M``#\_________\CU`0```````@```*T!``#\_________TKX`0``````"P``
-M``,`````$P```````.OX`0``````"P````4```#X!0```````/7X`0``````
-M`@```*\"``#\_________S#Y`0```````@```(8"``#\_________Q#Z`0``
-M`````@```)("``#\_________SWZ`0```````@```)("``#\_________YWZ
-M`0```````@```)("``#\_________Q_[`0```````@```)("``#\________
-M_UG[`0```````@```)("``#\_________[[[`0```````@```*0"``#\____
-M______G[`0```````@```*0"``#\_________T?\`0```````@```*0"``#\
-M_________X+\`0```````@```*0"``#\_________]C\`0```````@```%@!
-M``#\_________^+\`0```````@```*0"``#\_________^S\`0```````@``
-M``,"``#\_________\?]`0```````@```)("``#\_________^3]`0``````
-M`@```)("``#\__________/]`0```````@```*0"``#\_________P_^`0``
-M`````@```)("``#\_________RS^`0```````@```)("``#\_________UK^
-M`0```````@```)("``#\_________V3^`0```````@```)("``#\________
-M_XS^`0```````@```*0"``#\_________YG^`0```````@```)("``#\____
-M_____\'^`0```````@```*0"``#\_________\[^`0```````@```)("``#\
-M___________^`0```````@```)("``#\_________S#_`0```````@```)("
-M``#\_________Y7_`0```````@```)("``#\_________[7_`0```````@``
-M`)("``#\_________]S_`0```````@```)("``#\__________S_`0``````
-M`@```)("``#\_________RP``@```````@```)("``#\_________S8``@``
-M`````@```)("``#\_________V(``@```````@```*0"``#\_________W(`
-M`@```````@```)("``#\_________YH``@```````@```*0"``#\________
-M_ZH``@```````@```)("``#\_________[0"`@```````@```)("``#\____
-M______P"`@```````@```-,!``#\_________R@#`@```````@```-,!``#\
-M_________Y8#`@```````@```!8"``#\__________0#`@```````@```'\"
-M``#\_________P`$`@```````@```-0!``#\_________QD$`@```````@``
-M`,L!``#\_________\$$`@```````@```!8"``#\__________`$`@``````
-M`@```/L!``#\_________P$%`@```````@```+\!``#\_________Q0%`@``
-M````"P````8```"P`0```````!X%`@```````@```*\"``#\_________S,%
-M`@```````@```+H"``#\_________T@%`@```````@```+H"``#\________
-M_V`%`@```````@```%P!``#\_________X(%`@```````@```)("``#\____
-M_____WP&`@``````"P```$,!`````````````($&`@```````@```.$!``#\
-M_________VT'`@```````@```$(!``#\_________W@'`@```````@```$4"
-M``#\_________VX(`@```````@```,$!``#\_________^$+`@```````@``
-M`$0"``#\_________UD,`@```````@```&(!``#\_________YP,`@``````
-M`@```,$!``#\_________SP-`@``````"P````,`````%P```````%4-`@``
-M`````@```!4"``#\_________X<-`@```````@```!4"``#\_________[<-
-M`@```````@```!4"``#\_________^,-`@```````@```!4"``#\________
-M_QH.`@```````@```*0!``#\_________V8.`@```````@```!@"``#\____
-M______@.`@```````@```#H!``#\_________S</`@```````@```&,!``#\
-M_________V$/`@```````@```*0"``#\_________[L1`@```````@```"X"
-M``#\_________\H1`@```````@```/8!``#\_________X$2`@```````@``
-M`$X!``#\__________L2`@```````@```.P!``#\_________Q@3`@``````
-M`@```$X!``#\_________SP4`@```````@```$,"``#\_________T\4`@``
-M`````@```-4!``#\_________[T4`@```````@```$,"``#\_________^D4
-M`@```````@```-4!``#\_________X(6`@```````@```!<"``#\________
-M_VH7`@```````@```(8"``#\_________X07`@``````"P````,```!0%P``
-M`````!<8`@```````@```"T!``#\_________R88`@```````@```"T!``#\
-M_________Z,8`@```````@```$,"``#\_________\\8`@```````@```-4!
-M``#\_________SX9`@```````@```(H!``#\_________W(9`@```````@``
-M`'8!``#\_________XL9`@```````@```(H!``#\_________YH9`@``````
-M`@````0"``#\_________[,9`@```````@```(H!``#\_________P,:`@``
-M`````@```'X!``#\_________Q@:`@``````"P````4```!0!@```````"(:
-M`@```````@```*\"``#\_________Y0:`@```````@```,L!``#\________
-M_Z8:`@```````@```$D!``#\_________T(;`@```````@````X"``#\____
-M_____[\;`@```````@````X"``#\_________\\;`@```````@```!("``#\
-M__________D;`@```````@````X"``#\_________Q<<`@```````@```-@!
-M``#\_________T0<`@```````@```'D!``#\_________P,=`@```````@``
-M`)4!``#\_________R8=`@```````@```-@!``#\_________T\=`@``````
-M`@```(D!``#\_________W8=`@```````@````X"``#\_________WX=`@``
-M`````@```(D!``#\_________Z,=`@```````@```-@!``#\_________PD>
-M`@```````@```#$!``#\_________U<>`@```````@```/,!``#\________
-M_WL>`@```````@```,L!``#\_________[(>`@```````@```+H"``#\____
-M_____\8>`@```````@```#$!``#\_________^0>`@```````@```%<!``#\
-M_________^X>`@```````@```*0"``#\_________ST?`@```````@```+P!
-M``#\_________T0?`@```````@````4"``#\_________UH?`@``````"P``
-M``8```#&`0```````&0?`@```````@```*\"``#\_________YL?`@``````
-M`@```#$!``#\_________ZX?`@```````@```)P!``#\_________[8?`@``
-M`````@```(D!``#\_________T<@`@```````@```)("``#\_________W,@
-M`@```````@```)("``#\_________ZP@`@```````@```)("``#\________
-M_^H@`@``````"P````4```"`!@```````/0@`@```````@```*\"``#\____
-M_____S`A`@```````@```,`!``#\_________X8A`@```````@```,`!``#\
-M_________YLA`@```````@```#X"``#\_________Z8A`@```````@```)4!
-M``#\_________U@B`@```````@```$0!``#\_________W\B`@```````@``
-M`-@!``#\_________[0B`@```````@```,L!``#\_________U(C`@``````
-M`@```$0!``#\_________W0C`@```````@```-@!``#\_________[<C`@``
-M`````@```#D"``#\_________^@D`@```````@```)("``#\_________P8E
-M`@```````@```)("``#\_________R,E`@```````@```)("``#\________
-M_X@E`@```````@```)("``#\_________Z\E`@```````@```)("``#\____
-M_____QLF`@```````@```/D!``#\_________W@F`@```````@```)("``#\
-M_________YLF`@```````@```)("``#\_________[XF`@```````@```)("
-M``#\_________\8F`@```````@```($!``#\_________[<G`@```````@``
-M`$\!``#\_________]HG`@```````@```(8"``#\_________\(H`@``````
-M`@```(8"``#\_________S`I`@```````@```(8"``#\_________V0I`@``
-M`````@```)("``#\_________Y\I`@```````@```)("``#\__________,I
-M`@```````@```)("``#\_________]$J`@```````@```(8"``#\________
-M_R4L`@```````@```(8"``#\_________ZTL`@```````@```(8"``#\____
-M_____\`L`@``````"P````,```"P'````````%4M`@```````@```*0"``#\
-M_________],M`@```````@```)("``#\__________<M`@```````@```)("
-M``#\_________Q@N`@``````"P````8```#D`0```````"(N`@```````@``
-M`*\"``#\_________RPN`@```````@```-X!``#\_________TPN`@``````
-M`@```)("``#\_________XPN`@```````@```)("``#\_________QTO`@``
-M`````@```)("``#\_________Z(O`@```````@```-X!``#\_________[$O
-M`@```````@```-X!``#\__________PO`@``````"P````4```#0!@``````
-M``8P`@```````@```*\"``#\_________V\P`@``````"P````8```#_`0``
-M`````'DP`@```````@```*\"``#\_________XLP`@```````@```,H!``#\
-M_________[4P`@``````"P````4````0!P```````+\P`@```````@```*\"
-M``#\_________S(Q`@``````"P````4````X!P```````#PQ`@```````@``
-M`*\"``#\_________]XQ`@```````@```$0!``#\__________<Q`@``````
-M`@```-@!``#\_________ZHR`@```````@```+$!``#\_________PXT`@``
-M`````@```,H!``#\_________QXT`@```````@```!8"``#\_________V(T
-M`@```````@```(,!``#\_________\DT`@```````@```$0!``#\________
-M_]0T`@```````@```+$!``#\_________^TT`@```````@```-@!``#\____
-M_____T<U`@```````@```,L!``#\_________\`U`@```````@```#,!``#\
-M__________<U`@```````@```,L!``#\_________YLV`@```````@```)("
-M``#\_________\HV`@```````@```,L!``#\__________\V`@```````@``
-M`!8"``#\_________Q`W`@```````@```(D!``#\_________UDW`@``````
-M`@```)("``#\_________X(W`@```````@```)("``#\_________[,W`@``
-M`````@```)("``#\_________\@W`@```````@```)`!``#\_________SPX
-M`@```````@```)("``#\_________\$X`@```````@```)("``#\________
-M_^PX`@```````@```)("``#\__________XX`@```````@```&D!``#\____
-M_____T$Y`@```````@```)("``#\_________V8Y`@```````@```)("``#\
-M_________^,Y`@```````@```)("``#\_________PPZ`@```````@```)("
-M``#\_________S@Z`@```````@```'\"``#\_________UDZ`@```````@``
-M`.@!``#\_________YDZ`@```````@```,L!``#\_________\\Z`@``````
-M`@```+H"``#\_________^,Z`@```````@```#$!``#\_________P$[`@``
-M`````@```(\!``#\_________PL[`@```````@```*0"``#\_________SL[
-M`@``````"P````$```"`4`(``````&D[`@```````@```)T"``#\________
-M_Y,[`@```````@```)("``#\_________Z@[`@```````@```)("``#\____
-M_____]`[`@```````@```)("``#\_________^4[`@```````@```)("``#\
-M_________Q8\`@```````@```)("``#\_________TT\`@```````@```)("
-M``#\_________XL\`@```````@```)("``#\_________[,\`@```````@``
-M`)("``#\_________^@\`@```````@```)("``#\_________Q\]`@``````
-M`@```)("``#\_________X8]`@```````@```)("``#\_________ZL]`@``
-M`````@```)("``#\_________]`]`@```````@```)("``#\__________4]
-M`@```````@```)("``#\_________S0^`@```````@```'\"``#\________
-M_VX^`@```````@```+H"``#\_________X(^`@```````@```#$!``#\____
-M_____Y0^`@```````@```%<!``#\_________YX^`@```````@```*0"``#\
-M_________\L^`@``````"P````4"`````````````.,^`@```````@```)T"
-M``#\_________PX_`@```````@```)("``#\_________T`_`@```````@``
-M`)("``#\_________WD_`@```````@```)("``#\_________Z4_`@``````
-M`@```)("``#\_________^8_`@```````@```'\"``#\_________P1``@``
-M`````@```,L!``#\_________S1``@```````@```+H"``#\_________U)`
-M`@``````"P```,@!`````````````&1``@```````@```)T"``#\________
-M_Y-``@```````@```)("``#\_________[E``@```````@```)("``#\____
-M_____]=``@```````@```*0"``#\_________^Q``@```````@```)("``#\
-M_________Q)!`@```````@```)("``#\_________SA!`@```````@```)("
-M``#\_________U9!`@```````@```*0"``#\_________VM!`@```````@``
-M`)("``#\_________Y!!`@```````@```)("``#\_________U9"`@``````
-M`@```)("``#\_________WM"`@```````@```*0"``#\_________ZM"`@``
-M`````@```)("``#\_________])"`@```````@```*0"``#\_________P5#
-M`@```````@```)("``#\_________RQ#`@```````@```*0"``#\________
-M_W)#`@```````@```)X!``#\_________XU#`@```````@```.(!``#\____
-M_____YE#`@```````@```+`!``#\_________\Y#`@```````@```*P!``#\
-M_________P)$`@```````@```(T!``#\_________R]$`@```````@```+`!
-M``#\_________QA%`@```````@```*0"``#\_________S]%`@```````@``
-M`)("``#\_________UY%`@```````@```*0"``#\_________X%%`@``````
-M`@```)("``#\_________ZU%`@```````@```*0"``#\_________]1%`@``
-M`````@```)("``#\__________A%`@```````@```*0"``#\_________QQ&
-M`@```````@```)("``#\_________SU&`@```````@```,L!``#\________
-M_[I&`@```````@```#$!``#\__________5&`@```````@```#$!``#\____
-M_____P%'`@```````@```+`!``#\_________T9'`@```````@```,L!``#\
-M_________VM'`@```````@```,L!``#\_________XQ'`@```````@```'\"
-M``#\_________ZM'`@```````@```%<!``#\_________[5'`@```````@``
-M`*0"``#\_________W)(`@```````@```!8"``#\_________Y1(`@``````
-M`@```/L!``#\_________Z5(`@```````@```+\!``#\_________[A(`@``
-M````"P````8```"P`0```````,)(`@```````@```*\"``#\_________]=(
-M`@```````@```+H"``#\_________^Q(`@```````@```+H"``#\________
-M_PE)`@```````@```%P!``#\_________RA)`@```````@```&8!``#\____
-M_____U1)`@```````@```,L!``#\_________WE)`@```````@```%<!``#\
-M_________X-)`@```````@```*0"``#\_________[9)`@```````@```/L!
-M``#\_________\=)`@```````@```+\!``#\_________]I)`@``````"P``
-M``8```"P`0```````.1)`@```````@```*\"``#\__________E)`@``````
-M`@```+H"``#\_________PY*`@```````@```+H"``#\_________R9*`@``
-M`````@```%P!``#\_________SM*`@```````@```*P!``#\_________[Q*
-M`@```````@```)("``#\_________]Y*`@```````@```*0"``#\________
-M_P%+`@```````@```)("``#\_________R1+`@```````@```)("``#\____
-M_____T9+`@```````@```*0"``#\_________VI+`@```````@```)("``#\
-M__________)+`@```````@```.@!``#\__________Y+`@```````@```+,!
-M``#\_________T5,`@```````@```!`"``#\_________U),`@```````@``
-M`+<!``#\_________XA,`@```````@```*0"``#\_________Z-,`@``````
-M`@```)("``#\_________\),`@```````@```)("``#\_________^%,`@``
-M`````@```+`!``#\_________^E,`@```````@```(X!``#\_________Q%-
-M`@```````@```!$"``#\_________YA-`@```````@```,@!``#\________
-M_Z5-`@```````@```,L!``#\_________S!.`@```````@```#`"``#\____
-M_____V1.`@```````@```+P!``#\_________YU.`@```````@```!P"``#\
-M_________[5.`@```````@```+H"``#\_________\U.`@```````@```+H"
-M``#\__________I.`@```````@```*0"``#\_________Q5/`@```````@``
-M`)("``#\_________S)/`@```````@```)("``#\_________U%/`@``````
-M`@```+`!``#\_________UE/`@```````@```(X!``#\_________Y]/`@``
-M`````@```)X!``#\_________^1/`@```````@```,L!``#\_________V-0
-M`@```````@```!$"``#\_________W)0`@```````@```&\!``#\________
-M_^M0`@```````@```)("``#\_________QI1`@```````@```)("``#\____
-M_____S)1`@```````@```#$"``#\_________S]1`@```````@```+<!``#\
-M_________ZE1`@```````@```/(!``#\_________\Q1`@```````@```-@!
-M``#\__________11`@```````@```(D!``#\_________QA2`@```````@``
-M``X"``#\_________R!2`@```````@```(D!``#\_________VE2`@``````
-M`@```-@!``#\_________[I2`@```````@```#$!``#\_________\E2`@``
-M`````@```,L!``#\__________A2`@```````@```+H"``#\_________PQ3
-M`@```````@```#$!``#\_________R13`@```````@```%<!``#\________
-M_RY3`@```````@```*0"``#\_________TY3`@```````@````4"``#\____
-M_____WU3`@```````@```-@!``#\_________Z]3`@```````@```#$!``#\
-M_________\93`@```````@```,L!``#\_________^)3`@```````@```/L!
-M``#\__________-3`@```````@```+\!``#\_________PA4`@```````@``
-M`+H"``#\_________QU4`@```````@```+H"``#\_________S!4`@``````
-M`@```%P!``#\_________T)4`@```````@```-0!``#\_________UM4`@``
-M`````@```)("``#\_________[54`@```````@```+`!``#\_________\!4
-M`@```````@```*P!``#\_________U95`@```````@```)("``#\________
-M_W%5`@```````@```,H!``#\_________X%5`@```````@```!8"``#\____
-M_____Z15`@```````@```,H!``#\_________ZQ5`@```````@```-P!``#\
-M_________\55`@``````"P````,````0'0```````-Q5`@```````@```'0!
-M``#\__________A5`@```````@```'0!``#\_________Q16`@```````@``
-M`#$!``#\_________S=6`@```````@```/,!``#\_________TY6`@``````
-M`@```%`!``#\_________W%6`@```````@```#$!``#\_________X]6`@``
-M`````@```/,!``#\_________Z96`@```````@```#$!``#\_________[A6
-M`@```````@```%`!``#\_________]-6`@```````@```#$!``#\________
-M_^A6`@```````@```#$!``#\_________QQ7`@```````@```%<!``#\____
-M_____R97`@```````@```*0"``#\_________YE7`@```````@```#0!``#\
-M_________[-7`@```````@```/\!``#\_________\Q7`@```````@```/L!
-M``#\_________]U7`@```````@```+\!``#\__________!7`@``````"P``
-M``8```"P`0```````/I7`@```````@```*\"``#\_________Q!8`@``````
-M`@```+H"``#\_________R98`@```````@```+H"``#\_________SE8`@``
-M`````@```%P!``#\_________V18`@```````@```,L!``#\_________YM8
-M`@```````@```,,!``#\__________%8`@```````@```-L!``#\________
-M_Q-9`@```````@```,L!``#\_________V19`@``````"P````4```"0!P``
-M`````&Y9`@```````@```*\"``#\_________Y)9`@```````@```,H!``#\
-M_________\)9`@``````"P````4```#`!P```````,Q9`@```````@```*\"
-M``#\_________TA:`@``````"P````4````X!P```````%):`@```````@``
-M`*\"``#\_________X5:`@``````"P````4```"0!P```````(]:`@``````
-M`@```*\"``#\_________R1;`@```````@```)`!``#\_________S-<`@``
-M`````@```$0!``#\_________W)<`@```````@```"D"``#\_________YM<
-M`@``````"P````4```"0!P```````*5<`@```````@```*\"``#\________
-M_])=`@```````@```(8"``#\__________E=`@```````@```)("``#\____
-M_____S!>`@```````@```)("``#\_________WY>`@```````@```)("``#\
-M_________P-?`@``````"P````4```#P!P````````U?`@```````@```*\"
-M``#\_________T!?`@``````"P````4````P"````````$I?`@```````@``
-M`*\"``#\_________V1?`@``````"P````4```!P"````````&Y?`@``````
-M`@```*\"``#\_________Y-?`@``````"P````8````,`@```````)U?`@``
-M`````@```*\"``#\_________]I?`@``````"P````4```"@"````````.1?
-M`@```````@```*\"``#\_________QE@`@``````"P````8````H`@``````
-M`"-@`@```````@```*\"``#\_________T9@`@``````"P````8````_`@``
-M`````%!@`@```````@```*\"``#\_________UM@`@``````"P````8```!;
-M`@```````&5@`@```````@```*\"``#\_________[=@`@```````@```#T!
-M``#\_________P9A`@```````@```)("``#\_________RIA`@```````@``
-M`)("``#\_________TQA`@```````@```)("``#\_________W!A`@``````
-M`@```)("``#\_________W]A`@``````"P````8```!L`@```````(EA`@``
-M`````@```*\"``#\_________R1B`@```````@```)("``#\_________T]B
-M`@``````"P````8```")`@```````%EB`@```````@```*\"``#\________
-M_YIB`@``````"P````4```#8"````````*1B`@```````@```*\"``#\____
-M_____[=B`@```````@```($!``#\_________]!B`@```````@```)("``#\
-M_________WAC`@```````@```(D!``#\_________Y5C`@```````@```.0!
-M``#\_________Q5D`@```````@```"L"``#\_________RED`@```````@``
-M`)$!``#\_________T]D`@```````@```+`"``#\_________W%D`@``````
-M`@```+`"``#\_________Y)D`@```````@```+`"``#\_________[!D`@``
-M`````@```+`"``#\_________]9D`@```````@```+`"``#\_________P%E
-M`@```````@```+`"``#\_________QME`@```````@```+`"``#\________
-M_S5E`@```````@```+`"``#\_________U-E`@```````@```+`"``#\____
-M_____VUE`@```````@```+`"``#\_________X]E`@```````@```+`"``#\
-M_________[%E`@```````@```+`"``#\_________\YE`@```````@```+`"
-M``#\_________^ME`@```````@```+`"``#\_________PAF`@```````@``
-M`+`"``#\_________R5F`@```````@```+`"``#\_________T%F`@``````
-M`@```+`"``#\_________V-F`@```````@```+`"``#\_________WQF`@``
-M`````@```+`"``#\_________Z!F`@```````@```(0"``#\_________\!F
-M`@```````@```(0"``#\_________^=F`@```````@```(0"``#\________
-M_PMG`@```````@```(0"``#\_________R]G`@```````@```(0"``#\____
-M_____U)G`@```````@```(0"``#\_________W)G`@```````@```(0"``#\
-M_________YQG`@```````@```(0"``#\_________^=G`@```````@```,L!
-M``#\__________=G`@```````@````@"``#\_________W!H`@``````"P``
-M``$```"@!@(``````'YH`@```````@```,4!``#\_________XIH`@``````
-M`@```$4!``#\_________UEI`@```````@```,L!``#\_________XYI`@``
-M`````@```+H"``#\_________Z1I`@```````@```#$!``#\_________[5I
-M`@```````@```%<!``#\_________[]I`@```````@```*0"``#\________
-M__!I`@```````@```'@!``#\_________XEK`@```````@```"L"``#\____
-M_____PQL`@```````@```+("``#\_________TAL`@```````@```+("``#\
-M_________X-L`@```````@```+("``#\_________[IL`@```````@```+("
-M``#\__________)L`@```````@```+("``#\_________P5M`@```````@``
-M`+("``#\_________QMM`@```````@```+("``#\_________X%M`@``````
-M`@```+("``#\_________\YM`@```````@```+("``#\_________QYN`@``
-M`````@```+("``#\_________V%N`@```````@```+("``#\_________Z]N
-M`@```````@```+("``#\_________P=O`@```````@```+("``#\________
-M_TAO`@```````@```+("``#\_________W%O`@```````@```-D!``#\____
-M_____WUO`@```````@```+("``#\_________Z9O`@```````@```*8!``#\
-M_________[)O`@```````@```+("``#\_________]MO`@```````@```*8!
-M``#\_________^=O`@```````@```+("``#\_________Q!P`@```````@``
-M`*8!``#\_________QQP`@```````@```+("``#\_________T5P`@``````
-M`@```*8!``#\_________U%P`@```````@```+("``#\_________ZUP`@``
-M`````@```.8!``#\_________[YS`@```````@```+T"``#\_________]AS
-M`@```````@```+T"``#\__________)S`@```````@```+T"``#\________
-M_PQT`@```````@```+T"``#\_________R9T`@```````@```+T"``#\____
-M_____T!T`@```````@```+T"``#\_________VAT`@```````@```,L!``#\
-M_________[UT`@```````@```+T"``#\_________]YT`@```````@```,L!
-M``#\_________R]U`@```````@```+T"``#\_________U-U`@```````@``
-M`,L!``#\_________\)U`@```````@```$<!``#\_________R%V`@``````
-M`@```)("``#\_________U1V`@```````@```)("``#\_________VQV`@``
-M`````@```+<!``#\_________[=V`@```````@```#$!``#\_________\AV
-M`@```````@```%<!``#\_________])V`@```````@```*0"``#\________
-M__IV`@```````@```/L!``#\_________P]W`@```````@```+H"``#\____
-M_____R1W`@```````@```+H"``#\_________SMW`@```````@```%P!``#\
-M_________TMW`@```````@```)("``#\_________[IW`@```````@```-,!
-M``#\_________^9W`@```````@```+H"``#\_________U-X`@```````@``
-M`#X"``#\_________X1X`@```````@```,L!``#\_________^IX`@``````
-M"P````4`````"0```````/1X`@```````@```*\"``#\_________R=Y`@``
-M`````@```,H!``#\_________U=Y`@``````"P````4```#`!P```````&%Y
-M`@```````@```*\"``#\_________]UY`@``````"P````4````X!P``````
-M`.=Y`@```````@```*\"``#\_________PYZ`@``````"P````8````,`@``
-M`````!AZ`@```````@```*\"``#\_________UIZ`@``````"P````4```"@
-M"````````&1Z`@```````@```*\"``#\_________QA[`@``````"P````8`
-M``"=`@```````")[`@```````@```*\"``#\_________RI[`@```````@``
-M`)`!``#\_________SY\`@```````@```-@!``#\_________VA\`@``````
-M`@```$0!``#\_________XA\`@```````@```/D!``#\_________\Y\`@``
-M`````@```#D"``#\_________UR``@```````@```-$!``#\_________\&`
-M`@```````@```(8"``#\_________\Z``@```````@```"H"``#\________
-M_T:!`@```````@```(8"``#\_________ZZ!`@```````@````@"``#\____
-M_____\*!`@```````@```$8"``#\_________]6!`@```````@```$4"``#\
-M__________B!`@```````@```(8"``#\_________TJ"`@``````"P```*@!
-M`````````````)2"`@```````@```,4!``#\_________Z6"`@```````@``
-M`"X!``#\_________[""`@```````@```$4!``#\_________Q^#`@``````
-M`@````@"``#\_________S.#`@```````@```$8"``#\_________T:#`@``
-M`````@```$4"``#\_________ZJ#`@``````"P```*@!`````````````/F#
-M`@```````@```,4!``#\_________PJ$`@```````@```"X!``#\________
-M_Q6$`@```````@```$4!``#\_________YB$`@```````@````@"``#\____
-M_____ZR$`@```````@```$8"``#\_________[^$`@```````@```$4"``#\
-M_________]R$`@```````@```(8"``#\_________R"%`@``````"P```#@"
-M`````````````$2%`@```````@```,4!``#\_________U.%`@```````@``
-M`"X!``#\_________UZ%`@```````@```$4!``#\_________\&%`@``````
-M`@```-$!``#\_________^^%`@```````@````H"``#\_________T.&`@``
-M`````@````@"``#\_________U>&`@```````@```$8"``#\_________VJ&
-M`@```````@```$4"``#\_________[R&`@``````"P```#@"````````````
-M`-V&`@```````@```,4!``#\_________^V&`@```````@```"X!``#\____
-M______B&`@```````@```$4!``#\_________ZB'`@```````@```&X!``#\
-M_________^:'`@```````@```&X!``#\_________R2(`@```````@```+4!
-M``#\_________S*(`@```````@```%0!``#\_________V&(`@```````@``
-M`%X!``#\_________WJ(`@```````@```%0!``#\_________ZB(`@``````
-M`@```%0!``#\_________WZ)`@```````@```'T!``#\_________\&)`@``
-M`````@```+8!``#\__________R)`@```````@```%X!``#\_________T.*
-M`@```````@````@"``#\_________U>*`@```````@```$8"``#\________
-M_VJ*`@```````@```$4"``#\_________[V*`@``````"P````P"````````
-M`````-Z*`@```````@```,4!``#\_________^V*`@```````@```"X!``#\
-M__________B*`@```````@```$4!``#\__________^+`@```````@```#`!
-M``#\_________PJ,`@```````@```$4"``#\_________SF,`@```````@``
-M`(8"``#\_________W^,`@```````@```#`!``#\_________XJ,`@``````
-M`@```$4"``#\_________S&-`@```````@```&@!``#\_________T2-`@``
-M`````@```#`!``#\_________T^-`@```````@```$4"``#\_________VF-
-M`@```````@```'\"``#\_________WZ-`@``````"P```%8!````````````
-M`)*-`@```````@```)T"``#\_________PZ.`@```````@```/0!``#\____
-M______V.`@```````@```.\!``#\_________S&/`@```````@```.\!``#\
-M_________VF/`@```````@```%X!``#\_________]>0`@```````@```(4!
-M``#\_________^F0`@```````@```',!``#\__________Z0`@```````@``
-M`*L!``#\_________Q"1`@```````@```&@!``#\_________RJ1`@``````
-M`@```'\"``#\_________S^1`@``````"P```%8!`````````````%F1`@``
-M`````@```)T"``#\_________Z61`@```````@```,L!``#\_________Q*2
-M`@```````@```#`"``#\_________SB2`@```````@```+P!``#\________
-M_UR2`@```````@```!P"``#\_________\22`@```````@```,L!``#\____
-M______^2`@```````@```%X!``#\_________RV3`@```````@```,,!``#\
-M_________UF3`@```````@```#`!``#\_________VB3`@```````@```$4"
-M``#\_________Z&3`@```````@```%X!``#\_________UF4`@```````@``
-M`)("``#\_________\N8`@```````@```#<"``#\_________\V9`@``````
-M"P````,```!`'0```````&>:`@```````@```)("``#\_________YV:`@``
-M`````@```)("``#\_________\B:`@```````@```)("``#\_________P*;
-M`@```````@```)("``#\_________T>;`@```````@```)("``#\________
-M_WV;`@```````@```)("``#\_________ZB;`@```````@```)("``#\____
-M_____]V;`@```````@```)("``#\_________YV<`@``````"P````,`````
-M'@```````+F<`@``````"P````,````%'@```````,F<`@``````"P````,`
-M```$'@```````-J<`@``````"P````,`````'@```````.N<`@```````@``
-M```"``#\_________WV=`@```````@```,L!``#\_________ZV=`@``````
-M`@```,L!``#\_________]V=`@```````@```,L!``#\_________RV>`@``
-M`````@```,L!``#\_________UV>`@```````@```,L!``#\_________]J>
-M`@```````@```,L!``#\_________R.@`@```````@```$0!``#\________
-M_V"A`@```````@```,H!``#\_________Z.A`@```````@```.T!``#\____
-M_____^.A`@```````@```.T!``#\_________]^B`@```````@```#`!``#\
-M_________^VB`@```````@```(L!``#\_________Q>D`@```````@```$4!
-M``#\_________T"D`@```````@```&<!``#\_________TRD`@```````@``
-M`#<"``#\_________V6D`@```````@```-@!``#\_________]*D`@``````
-M`@```/(!``#\_________SZE`@```````@```)4!``#\_________QBF`@``
-M`````@```$4"``#\_________Y.F`@```````@```'<!``#\_________YZF
-M`@```````@```$4"``#\_________]>F`@```````@```,L!``#\________
-M_^*F`@```````@```&H!``#\_________^JF`@```````@```$D!``#\____
-M_____S"G`@```````@````@"``#\_________T"G`@```````@```$8"``#\
-M_________UJG`@```````@```$4"``#\_________YVG`@``````"P```#4!
-M`````````````*BG`@```````@```$4!``#\_________^.G`@```````@``
-M``@"``#\_________R2H`@``````"P```#4!`````````````"^H`@``````
-M`@```$4!``#\_________W^H`@```````@````@"``#\_________Y.H`@``
-M`````@```$8"``#\_________Z:H`@```````@```$4"``#\__________&H
-M`@``````"P````$```#PJ0(``````/ZH`@```````@```,4!``#\________
-M_PZI`@```````@```"X!``#\_________QFI`@```````@```$4!``#\____
-M_____V2I`@```````@````@"``#\_________Z2I`@``````"P```)T!````
-M`````````*^I`@```````@```$4!``#\_________[^I`@```````@```*0"
-M``#\_________\NI`@```````@```*0"``#\_________\JJ`@```````@``
-M`#`!``#\_________]JJ`@```````@```(L!``#\_________^6J`@``````
-M`@```$4"``#\_________RBK`@```````@````\"``#\_________TBK`@``
-M`````@```#`!``#\_________UBK`@```````@```(L!``#\_________V.K
-M`@```````@```$4"``#\_________V*L`@```````@```*0"``#\________
-M_VVL`@```````@```$4"``#\_________Y^L`@```````@````\"``#\____
-M_____ZNL`@```````@```*0"``#\_________[:L`@```````@```$4"``#\
-M_________P"M`@```````@````@"``#\_________T*M`@```````@```!4"
-M``#\_________U&M`@```````@```$4"``#\_________V>M`@``````"P``
-M`#4!`````````````'*M`@```````@```$4!``#\_________[:M`@``````
-M`@````@"``#\_________]2M`@```````@```$8"``#\_________^ZM`@``
-M`````@```$4"``#\_________U*N`@``````"P```#4!`````````````&.N
-M`@```````@```,4!``#\_________W6N`@```````@```"X!``#\________
-M_X"N`@```````@```$4!``#\_________].N`@```````@````@"``#\____
-M______2N`@```````@```$8"``#\_________Q"O`@```````@```$4"``#\
-M_________WJO`@``````"P```#4!`````````````(>O`@```````@```,4!
-M``#\_________YBO`@```````@```"X!``#\_________Z.O`@```````@``
-M`$4!``#\__________JO`@```````@````@"``#\_________QBP`@``````
-M`@```$8"``#\_________S2P`@```````@```$4"``#\_________Y*P`@``
-M````"P```#4!`````````````*:P`@```````@```,4!``#\_________[>P
-M`@```````@```"X!``#\_________\*P`@```````@```$4!``#\________
-M_QJQ`@```````@````@"``#\_________SBQ`@```````@```$8"``#\____
-M_____U2Q`@```````@```$4"``#\_________ZJQ`@``````"P```#4!````
-M`````````+>Q`@```````@```,4!``#\_________\BQ`@```````@```"X!
-M``#\_________].Q`@```````@```$4!``#\_________T>R`@```````@``
-M``@"``#\__________6R`@``````"P````$```!0I0(```````.S`@``````
-M`@```,4!``#\_________PZS`@```````@```$4!``#\_________W&U`@``
-M`````@```'0!``#\_________X*U`@```````@```'<!``#\_________]RU
-M`@```````@```,L!``#\_________[:V`@```````@````X"``#\________
-M_T6W`@```````@````@"``#\_________V2W`@```````@````$"``#\____
-M_____W>W`@```````@```$4"``#\_________\RW`@``````"P```%T!````
-M`````````-JW`@```````@```,4!``#\_________^6W`@```````@```$4!
-M``#\_________T6X`@```````@````@"``#\_________UFX`@```````@``
-M``$"``#\_________["X`@``````"P```%T!`````````````+ZX`@``````
-M`@```,4!``#\_________\FX`@```````@```$4!``#\_________].X`@``
-M`````@```*0"``#\_________RRY`@```````@````@"``#\_________SRY
-M`@```````@````$"``#\_________X^Y`@``````"P```%T!````````````
-M`)VY`@```````@```,4!``#\_________ZBY`@```````@```$4!``#\____
-M______6Y`@```````@````@"``#\_________P6Z`@```````@````$"``#\
-M_________U2Z`@``````"P```%T!`````````````&*Z`@```````@```,4!
-M``#\_________VVZ`@```````@```$4!``#\_________Z2Z`@```````@``
-M`*0!``#\_________[2Z`@```````@```$("``#\_________\"[`@``````
-M`@```*0!``#\_________]"[`@```````@```$("``#\_________T"\`@``
-M`````@```$L!``#\_________].\`@```````@```+0!``#\_________S&]
-M`@```````@```#8"``#\_________V"]`@```````@```*0!``#\________
-M_W"]`@```````@```$("``#\_________]Z]`@```````@```!0"``#\____
-M_____T*^`@```````@```"<"``#\_________YB^`@```````@```$0!``#\
-M_________[N^`@```````@```/(!``#\_________\R^`@```````@```"<"
-M``#\_________P._`@```````@```$0!``#\_________Q2_`@```````@``
-M`"<"``#\_________S:_`@```````@```'\"``#\_________UF_`@``````
-M`@```'\"``#\_________\"_`@```````@```*`!``#\_________PK``@``
-M`````@```$0!``#\_________R+``@```````@```)4!``#\_________RW`
-M`@```````@```#X"``#\_________^S``@```````@```,L!``#\________
-M___``@```````@```-L!``#\_________Q[!`@``````"P```#T!````````
-M`````#7!`@```````@```)T"``#\_________\G!`@```````@```,L!``#\
-M_________]S!`@```````@```#X"``#\__________?!`@``````"P```#("
-M``````````````["`@```````@```)T"``#\_________\7"`@```````@``
-M`$0!``#\_________]#"`@```````@```+$!``#\_________]O"`@``````
-M`@````X"``#\_________W+#`@``````"P```#T!`````````````(G#`@``
-M`````@```)T"``#\_________RK$`@``````"P```#("`````````````$'$
-M`@```````@```)T"``#\__________3%`@```````@```,L!``#\________
-M_T[&`@```````@```$(!``#\_________UW&`@```````@```$4"``#\____
-M_____YK&`@```````@```/,!``#\_________\K&`@```````@```+P!``#\
-M_________^;&`@```````@```$@!``#\_________Q?'`@```````@```,L!
-M``#\_________X''`@```````@```#`"``#\_________Y?'`@```````@``
-M`$(!``#\_________Z3'`@```````@```$4"``#\_________Q3(`@``````
-M`@```#$!``#\_________T3(`@```````@```%<!``#\_________T[(`@``
-M`````@```*0"``#\_________W3(`@```````@```#0!``#\_________X[(
-M`@```````@```/\!``#\_________[W(`@```````@```/L!``#\________
-M_\[(`@```````@```+\!``#\_________^'(`@``````"P````8```"Z`@``
-M`````.O(`@```````@```*\"``#\_________P#)`@```````@```+H"``#\
-M_________Q7)`@```````@```+H"``#\_________UW)`@```````@```%P!
-M``#\_________X3)`@```````@```,L!``#\_________\+)`@```````@``
-M`,,!``#\_________PC*`@```````@```#$!``#\_________S?*`@``````
-M`@```%<!``#\_________T'*`@```````@```*0"``#\_________V?*`@``
-M`````@```#0!``#\_________X'*`@```````@```/\!``#\_________YS*
-M`@```````@```/L!``#\_________ZW*`@```````@```+\!``#\________
-M_\#*`@``````"P````8```"Z`@```````,K*`@```````@```*\"``#\____
-M_____]_*`@```````@```+H"``#\__________#*`@``````"P````8```"Z
-M`@```````/K*`@```````@```*\"``#\_________P_+`@```````@```+H"
-M``#\_________X_+`@```````@```+H"``#\__________G+`@```````@``
-M`,L!``#\_________R[,`@```````@```+H"``#\_________T?,`@``````
-M`@```%P!``#\_________Y;,`@```````@````@"``#\_________ZK,`@``
-M`````@```$8"``#\_________\3,`@```````@```$4"``#\_________TG-
-M`@``````"P```#4!`````````````%K-`@```````@```,4!``#\________
-M_VS-`@```````@```"X!``#\_________W?-`@```````@```$4!``#\____
-M_____[3-`@```````@```*0!``#\_________\3-`@```````@```$("``#\
-M_________[C.`@```````@```"<"``#\__________G.`@```````@```$("
-M``#\_________TW/`@```````@```,L!``#\_________RK3`@```````@``
-M`/0!``#\_________U73`@```````@```!X"``#\_________]O3`@``````
-M"P````$```"@X`(``````/S3`@```````@```'L!``#\__________O4`@``
-M````"P````$```"@X`(``````"_5`@```````@```'L!``#\_________RS6
-M`@``````"P````$```"@X`(``````%_6`@```````@```'L!``#\________
-M_\?6`@``````"P````$```"@X`(``````/?6`@```````@```'L!``#\____
-M_____T?7`@``````"P````$```"@X`(``````'?7`@```````@```'L!``#\
-M_________T78`@```````@```!\"``#\_________[W8`@```````@```#8!
-M``#\_________Y79`@```````@```.`!``#\_________S/:`@```````@``
-M`+D!``#\_________Z?:`@```````@```/0!``#\_________]?:`@``````
-M`@```"`"``#\__________3:`@```````@```,0!``#\_________Q7<`@``
-M`````@```!X"``#\_________]O=`@```````@```-`!``#\_________QW>
-M`@```````@```.`!``#\_________\3>`@```````@```+D!``#\________
-M_T7?`@```````@```&`!``#\_________]K?`@```````@```+D!``#\____
-M_____X+@`@```````@```+D!``#\_________]3@`@```````@```!X"``#\
-M_________S[A`@```````@```+D!``#\_________WKA`@```````@```+D!
-M``#\_________\OA`@```````@```+D!``#\_________POB`@```````@``
-M`+D!``#\_________WWE`@```````@```+D!``#\_________^#E`@``````
-M`@```)("``#\_________P3F`@```````@```)("``#\_________V'G`@``
-M`````@```-T!``#\_________Z_H`@```````@```)("``#\_________\[H
-M`@```````@```)("``#\_________^KH`@```````@```$4"``#\________
-M_TGI`@```````@```*0"``#\_________UGI`@```````@```)("``#\____
-M_____X+I`@```````@```*0"``#\_________Y+I`@```````@```)("``#\
-M_________Y_J`@```````@```*0"``#\_________Z[J`@```````@```)("
-M``#\_________\#J`@```````@```*0"``#\_________\CJ`@```````@``
-M`)("``#\_________^?J`@```````@```*0"``#\_________^_J`@``````
-M`@```)("``#\_________QGK`@```````@```*0"``#\_________RCK`@``
-M`````@```)("``#\_________SKK`@```````@```*0"``#\_________T+K
-M`@```````@```)("``#\_________V'K`@```````@```*0"``#\________
-M_VGK`@```````@```)("``#\_________Z[K`@```````@```*0"``#\____
-M_____QSL`@```````@```*0"``#\_________S'L`@```````@```%<!``#\
-M_________X[L`@```````@````@"``#\__________WL`@``````"P```*D!
-M``````````````3M`@``````"P```#P!`````````````!?M`@```````@``
-M`$4!``#\_________W7M`@```````@````@"``#\_________^7M`@``````
-M"P```%(!`````````````.WM`@```````@```$4!``#\_________X#N`@``
-M`````@```)("``#\_________Z[N`@```````@```)("``#\___________N
-M`@```````@```.,!``#\_________PSO`@```````@```$T!``#\________
-M_U_O`@```````@````@"``#\_________[+O`@``````"P```%(!````````
-M`````+KO`@```````@```$4!``#\_________U3P`@```````@```)("``#\
-M_________X+P`@```````@```)("``#\_________\_P`@```````@```"P!
-M``#\_________]SP`@```````@```$T!``#\_________T;Q`@```````@``
-M``@"``#\_________YCQ`@``````"P```*D!`````````````)_Q`@``````
-M"P```#P!`````````````++Q`@```````@```$4!``#\_________PCR`@``
-M`````@````@"``#\_________W/R`@``````"P````$```#P)0,``````(7R
-M`@```````@```$4!``#\_________[+R`@``````"P```%\!````````````
-M`$[S`@```````@```*0"``#\_________UOS`@```````@```)("``#\____
-M_____W#S`@```````@```*0"``#\_________WKS`@```````@```)("``#\
-M_________S[T`@```````@```*0"``#\_________TOT`@```````@```)("
-M``#\_________V#T`@```````@```*0"``#\_________VKT`@```````@``
-M`)("``#\_________P;U`@```````@```#L"``#\_________SCU`@``````
-M`@```"("``#\_________T#U`@```````@```-T!``#\_________X;U`@``
-M`````@```)("``#\_________Z;U`@```````@```)("``#\_________\+U
-M`@```````@```)("``#\_________^_U`@```````@```)("``#\________
-M_SWV`@```````@````L"``#\_________T7V`@```````@```"\!``#\____
-M_____ZOV`@```````@```*0"``#\_________[OV`@```````@```)("``#\
-M_________^#V`@```````@```*0"``#\__________#V`@```````@```)("
-M``#\__________GY`@```````@```","``#\_________ZSZ`@```````@``
-M`/0!``#\_________Q;\`@```````@```/0!``#\_________SG\`@``````
-M`@```/0!``#\_________[+\`@```````@```&T!``#\_________]/]`@``
-M`````@```*0"``#\__________[]`@```````@```*0"``#\_________[[^
-M`@```````@```$$!``#\_________]_^`@```````@```.L!``#\________
-M__7^`@```````@```"8"``#\_________P3_`@```````@```"8"``#\____
-M_____XW_`@```````@```)("``#\_________[O_`@```````@```)("``#\
-M_________^__`@```````@```*0"``#\_________P<``P```````@```)("
-M``#\_________U4``P```````@```)("``#\_________[P``P```````@``
-M`)("``#\_________R\!`P```````@```)("``#\_________^<!`P``````
-M`@```*0"``#\__________H!`P```````@```)("``#\_________Q<"`P``
-M`````@```/$!``#\_________R("`P```````@````,"``#\_________S0"
-M`P```````@```*0"``#\_________TX"`P```````@```*0"``#\________
-M_V@"`P```````@```*0"``#\_________X@"`P```````@```(\!``#\____
-M_____YD"`P```````@```)("``#\_________^<"`P```````@```*0"``#\
-M__________H"`P```````@```)("``#\_________Q<#`P```````@```/$!
-M``#\_________R(#`P```````@````,"``#\_________S0#`P```````@``
-M`*0"``#\_________TX#`P```````@```*0"``#\_________V@#`P``````
-M`@```*0"``#\_________X@#`P```````@```(\!``#\_________YD#`P``
-M`````@```)("``#\_________[T#`P```````@```*0"``#\_________\@#
-M`P```````@```+`!``#\_________^8#`P```````@```(X!``#\________
-M__,#`P```````@```)("``#\_________PX$`P```````@```)("``#\____
-M_____R8$`P```````@```)("``#\_________Q`%`P```````@```)("``#\
-M_________ZL%`P```````@````@"``#\_________\D%`P```````@```$8"
-M``#\_________^4%`P```````@```$4"``#\_________TL&`P``````"P``
-M``$```#P)0,``````%@&`P```````@```,4!``#\_________V<&`P``````
-M`@```"X!``#\_________W(&`P```````@```$4!``#\_________XP'`P``
-M````"P````4````X"0```````)8'`P```````@```*\"``#\_________R4(
-M`P``````"P````4```"("0```````"\(`P```````@```*\"``#\________
-M_S\(`P```````@```,,!``#\_________UH(`P```````@```,8!``#\____
-M_____RL)`P```````@```/`!``#\_________Z8)`P``````"P```$,!````
-M`````````+$)`P```````@```.$!``#\_________\D)`P```````@```+,!
-M``#\_________R,*`P```````@```/`!``#\_________S8*`P```````@``
-M`)\!``#\_________V8*`P```````@```!P"``#\_________QD+`P``````
-M`@```&\!``#\_________R,+`P```````@```#\"``#\_________^L+`P``
-M`````@```,,!``#\_________VP,`P```````@```,L!``#\_________\$,
-M`P```````@```#`"``#\_________^,,`P```````@```+P!``#\________
-M__,,`P```````@```!P"``#\_________YL-`P```````@```)L!``#\____
-M_____TH.`P```````@```,L!``#\_________\@.`P```````@```)L!``#\
-M_________V,/`P```````@```+H"``#\_________WD/`P```````@```+H"
-M``#\_________ZP/`P```````@```)L!``#\_________Q(0`P```````@``
-M`+H"``#\_________V`0`P```````@```+H"``#\_________YX0`P``````
-M`@```#$!``#\_________]00`P```````@```%<!``#\_________]X0`P``
-M`````@```*0"``#\_________P01`P```````@```#0!``#\_________QX1
-M`P```````@```/\!``#\_________SD1`P```````@```/L!``#\________
-M_TH1`P```````@```+\!``#\_________UT1`P``````"P````8```#0`@``
-M`````&<1`P```````@```*\"``#\_________WP1`P```````@```+H"``#\
-M_________Y$1`P``````"P````8```#0`@```````)L1`P```````@```*\"
-M``#\_________[`1`P```````@```+H"``#\__________X1`P```````@``
-M`+H"``#\_________TH2`P```````@```%P!``#\_________V42`P``````
-M`@```+H"``#\_________[T2`P```````@```.@!``#\_________^D2`P``
-M`````@```,,!``#\_________P83`P```````@```+,!``#\_________TT3
-M`P```````@```!`"``#\_________YL3`P``````"P````,```"`'@``````
-M``$4`P```````@```-,!``#\_________QT4`P```````@```*X!``#\____
-M_____SD4`P```````@```*X!``#\_________U44`P```````@```*X!``#\
-M_________W$4`P```````@```*X!``#\_________Y(4`P```````@```*(!
-M``#\_________[04`P```````@```*(!``#\_________^$4`P```````@``
-M`*(!``#\_________P,5`P```````@```*(!``#\_________PT5`P``````
-M`@```*0"``#\_________SH5`P```````@```*(!``#\_________UP5`P``
-M`````@```*(!``#\_________V85`P```````@```*0"``#\_________X(5
-M`P```````@```*X!``#\_________YX5`P```````@```*X!``#\________
-M_[H5`P```````@```*X!``#\_________]P5`P```````@```*(!``#\____
-M______@5`P```````@```*X!``#\_________TT6`P```````@```*0"``#\
-M_________\H6`P```````@```)("``#\_________^@6`P```````@```)("
-M``#\__________P6`P```````@```*0"``#\_________Q87`P```````@``
-M`+P!``#\_________R47`P```````@```*0"``#\_________SP7`P``````
-M`@```*X!``#\_________T87`P```````@```*0"``#\_________V(7`P``
-M`````@```*X!``#\_________VP7`P```````@```*0"``#\_________YD7
-M`P```````@```*(!``#\_________Z,7`P```````@```*0"``#\________
-M_[\7`P```````@```*X!``#\_________\D7`P```````@```*0"``#\____
-M_____],7`P```````@```(8!``#\_________^$7`P```````@```.<!``#\
-M_________P,8`P```````@```*(!``#\_________R48`P```````@```*(!
-M``#\_________T<8`P```````@```*(!``#\_________VD8`P```````@``
-M`*(!``#\_________X48`P```````@```*X!``#\_________Y08`P``````
-M`@```*0"``#\_________ZL8`P```````@```*X!``#\_________[48`P``
-M`````@```*0"``#\_________]<8`P```````@```*(!``#\__________,8
-M`P```````@```*X!``#\_________Q09`P```````@```*(!``#\________
-M_RD9`P```````@```#\"``#\_________T(9`P```````@```*X!``#\____
-M_____TP9`P```````@```*0"``#\_________W89`P```````@```*(!``#\
-M_________X`9`P```````@```*0"``#\_________YD9`P```````@```*X!
-M``#\_________Z,9`P```````@```*0"``#\_________]\:`P```````@``
-M`#`!``#\_________^H:`P```````@```$4"``#\_________U4;`P``````
-M`@```)("``#\_________WP;`P```````@```)("``#\_________[T;`P``
-M`````@```)("``#\_________^8;`P```````@```#`!``#\__________$;
-M`P```````@```$4"``#\__________P;`P```````@```-,!``#\________
-M_RL<`P```````@```-,!``#\_________W0=`P```````@```!`"``#\____
-M_____WX=`P```````@```*0"``#\_________YT=`P```````@```!`"``#\
-M_________Z<=`P```````@```*0"``#\_________S4>`P```````@```)("
-M``#\_________TP>`P```````@```)("``#\_________XL>`P```````@``
-M`*0"``#\_________Z0>`P```````@```+P!``#\_________[\>`P``````
-M`@````("``#\_________]0>`P```````@````("``#\_________^(>`P``
-M`````@```*0"``#\_________Q`?`P```````@```)("``#\_________S8?
-M`P```````@```)("``#\_________TX?`P```````@```*0"``#\________
-M_U\?`P``````"P````4```#`"0```````&D?`P```````@```*\"``#\____
-M_____WD?`P```````@````@"``#\_________\@?`P``````"P````$```#P
-M)0,``````-,?`P```````@```$4!``#\_________^0?`P``````"P````8`
-M``#F`@```````.X?`P```````@```*\"``#\__________X?`P```````@``
-M``@"``#\_________TT@`P``````"P````$```#P)0,``````%@@`P``````
-M`@```$4!``#\_________X,@`P```````@````@"``#\_________]8@`P``
-M````"P````$```#P)0,``````.0@`P```````@```$4!``#\__________H@
-M`P```````@````@"``#\_________TTA`P``````"P````$```#P)0,`````
-M`%LA`P```````@```$4!``#\_________W$A`P```````@````@"``#\____
-M_____\`A`P``````"P````$```#P)0,``````,LA`P```````@```$4!``#\
-M_________^@A`P```````@````@"``#\_________S<B`P``````"P````$`
-M``#P)0,``````$(B`P```````@```$4!``#\_________U@B`P```````@``
-M``@"``#\_________[(B`P``````"P````$```#P)0,``````+TB`P``````
-M`@```$4!``#\__________@B`P```````@```/`!``#\_________Q,C`P``
-M`````@```)P!``#\_________VLC`P```````@```-,!``#\_________Z<C
-M`P```````@```-,!``#\_________[DC`P```````@```,L!``#\________
-M_PDD`P```````@```#`"``#\_________S$D`P```````@```+P!``#\____
-M_____T8D`P```````@```!P"``#\_________W0D`P```````@```,L!``#\
-M_________](D`P```````@```#`"``#\__________TD`P```````@```+P!
-M``#\_________Q(E`P```````@```!P"``#\_________TLE`P```````@``
-M`,L!``#\_________WDE`P```````@```%X!``#\_________Y<E`P``````
-M`@```,,!``#\_________Q8G`P```````@```#`!``#\_________R$G`P``
-M`````@```$4"``#\_________Z<G`P```````@```*0"``#\_________^TG
-M`P```````@```/,!``#\_________P(H`P```````@```+P!``#\________
-M_UHH`P``````"P````4```#X"0```````&0H`P```````@```*\"``#\____
-M_____W8H`P```````@```+X!``#\__________4H`P```````@```*0"``#\
-M_________Y,I`P```````@```#`!``#\_________YXI`P```````@```$4"
-M``#\_________[4I`P```````@```#`!``#\_________\`I`P```````@``
-M`$4"``#\_________\LI`P```````@```+P!``#\_________[$J`P``````
-M`@```+T!``#\_________\@J`P```````@```+T!``#\_________]\J`P``
-M`````@```&0!``#\__________$J`P```````@```,<!``#\_________P0K
-M`P```````@```.X!``#\_________R$K`P```````@```(0!``#\________
-M_S,K`P```````@```+(!``#\_________T4K`P```````@```#P"``#\____
-M_____UDK`P```````@```"T"``#\_________X0K`P```````@```,L!``#\
-M_________^(K`P```````@```#`"``#\_________PTL`P```````@```+P!
-M``#\_________R(L`P```````@```!P"``#\_________W<L`P```````@``
-M`%X!``#\_________X8L`P```````@```,L!``#\_________[$L`P``````
-M"P````8```#\`@```````+LL`P```````@```*\"``#\_________\@L`P``
-M`````@```%X!``#\_________^@L`P```````@```,,!``#\_________X0N
-M`P```````@```/T!``#\_________Y(N`P``````"P````,```"H'P``````
-M`.@N`P```````@```+,!``#\_________UXO`P```````@```/`!``#\____
-M_____W,O`P```````@```)\!``#\_________[(O`P```````@```!P"``#\
-M_________T0P`P```````@```,L!``#\_________V4P`P```````@```#X!
-M``#\_________Z,P`P```````@```/0!``#\_________U0Q`P```````@``
-M`+H"``#\_________XPQ`P```````@```#$!``#\_________Z8Q`P``````
-M`@```%<!``#\_________[`Q`P```````@```*0"``#\_________]LQ`P``
-M`````@```#0!``#\__________@Q`P```````@```/\!``#\_________QPR
-M`P```````@```/L!``#\_________S`R`P```````@```+\!``#\________
-M_TLR`P```````@```+H"``#\_________V8R`P```````@```+H"``#\____
-M_____YXR`P```````@```%P!``#\_________PTS`P```````@```#X!``#\
-M_________QLS`P```````@```/@!``#\_________]$S`P```````@```/0!
-M``#\_________R`U`P```````@```#`"``#\_________S0U`P```````@``
-M`!P"``#\_________V$U`P```````@```%X!``#\_________VTU`P``````
-M`@```+,!``#\_________QHV`P```````@```,L!``#\_________SLV`P``
-M`````@```#X!``#\_________V\V`P```````@```#X!``#\_________Y\V
-M`P```````@```#X!``#\_________[$V`P```````@```/0!``#\________
-M_^\V`P```````@```%,!``#\_________SHX`P```````@```.D!``#\____
-M_____UPX`P```````@```,L!``#\_________W`X`P```````@```#$!``#\
-M_________X0X`P```````@```%<!``#\_________XXX`P```````@```*0"
-M``#\_________[8X`P```````@```/L!``#\_________\<X`P```````@``
-M`+\!``#\_________]PX`P```````@```+H"``#\__________$X`P``````
-M`@```+H"``#\_________QTY`P```````@```%P!``#\_________S@Y`P``
-M`````@```&8!``#\_________Z@Y`P```````@````D"``#\_________\4Y
-M`P```````@```#X!``#\_________PDZ`P```````@```#X!``#\________
-M_SHZ`P```````@```#X!``#\_________TPZ`P```````@```%,!``#\____
-M_____UXZ`P```````@```,8!``#\_________X<Z`P```````@```%,!``#\
-M_________]L[`P```````@```+,!``#\_________P,]`P```````@```#`"
-M``#\_________Q(]`P```````@```!P"``#\_________U8]`P```````@``
-M`,,!``#\_________Y4]`P```````@```#X!``#\_________[P]`P``````
-M`@```)@!``#\_________R8^`P```````@```(T!``#\_________SL^`P``
-M````"P```$,!`````````````$8^`P```````@```.$!``#\_________VH^
-M`P```````@```*4!``#\_________W4^`P```````@```(T!``#\________
-M_Z\^`P```````@````("``#\_________[T^`P```````@```*0"``#\____
-M_____PT_`P```````@```%P!``#\_________R0_`P```````@```#H"``#\
-M_________U<_`P```````@```-,!``#\_________WD_`P```````@```'\"
-M``#\_________X4_`P```````@```-0!``#\_________YL_`P```````@``
-M`,L!``#\_________[T_`P```````@```/L!``#\_________\X_`P``````
-M`@```+\!``#\_________^,_`P```````@```+H"``#\__________@_`P``
-M`````@```+H"``#\_________P]``P```````@```%P!``#\_________S!`
-M`P```````@```,L!``#\_________T%``P```````@```+,!``#\________
-M_X)``P```````@```+P!``#\_________W%!`P```````@```#`!``#\____
-M_____WQ!`P```````@```$4"``#\_________]I!`P``````"P````4````8
-M"@```````.1!`P```````@```*\"``#\_________P1"`P```````@```%P!
-M``#\_________P]"`P```````@```$4"``#\_________T9"`P```````@``
-M`+<!``#\_________WQ"`P```````@```*0"``#\_________X="`P``````
-M`@```$4"``#\_________YQ"`P```````@```!`"``#\_________ZA"`P``
-M`````@```*0"``#\_________[-"`P```````@```$4"``#\_________[Y"
-M`P```````@```%D!``#\_________Q1#`P```````@```,L!``#\________
-M_WQ#`P```````@```+P!``#\__________1$`P```````@```*(!``#\____
-M_____U!%`P```````@```#`!``#\_________UM%`P```````@```$4"``#\
-M_________V]%`P```````@```-,!``#\_________Y9%`P``````"P````,`
-M``"P'P```````,]%`P```````@```)("``#\_________R%&`P```````@``
-M`)("``#\_________TQ&`P```````@```)("``#\_________Z]&`P``````
-M`@```)("``#\_________]9&`P```````@```)("``#\_________SM'`P``
-M`````@```)("``#\_________W='`P```````@```#`!``#\_________X)'
-M`P```````@```$4"``#\_________Y)'`P```````@```,,!``#\________
-M_\U'`P```````@```#`!``#\_________]A'`P```````@```$4"``#\____
-M_____^Y'`P``````"P```.4!``````````````5(`P```````@```)T"``#\
-M_________QY(`P```````@```*0"``#\_________TM(`P```````@```,,"
-M``#\_________W](`P```````@```)("``#\_________Z5(`P```````@``
-M`)("``#\_________ZI(`P```````@```,,"``#\_________R1)`P``````
-M`@```,L!``#\_________X!)`P```````@```/L!``#\_________Z!)`P``
-M`````@```+\!``#\_________\A)`P```````@```+H"``#\_________VE*
-M`P``````"P````8```#0`@```````'-*`P```````@```*\"``#\________
-M_XQ*`P```````@```+H"``#\_________[)*`P```````@```%P!``#\____
-M_____]]*`P```````@```)("``#\_________P5+`P```````@```)("``#\
-M_________U5+`P```````@```,L!``#\_________Y)+`P```````@```+,!
-M``#\_________\1+`P```````@```%<!``#\_________\Y+`P```````@``
-M`*0"``#\_________PU,`P```````@```)("``#\_________S-,`P``````
-M`@```)("``#\_________RA-`P```````@```)("``#\_________TM-`P``
-M`````@```)("``#\_________]M-`P```````@```)<!``#\__________A-
-M`P```````@```"<"``#\_________S=.`P```````@```)("``#\________
-M_UI.`P```````@```)("``#\_________Y%.`P```````@```)("``#\____
-M_____[1.`P```````@```)("``#\_________PE/`P```````@```)("``#\
-M_________R]/`P```````@```)("``#\_________VQ/`P```````@```)("
-M``#\_________Y1/`P```````@```#`!``#\_________Y]/`P```````@``
-M`$4"``#\_________ZI/`P```````@```-,!``#\_________\%/`P``````
-M`@```%<!``#\_________\M/`P```````@```*0"``#\_________S51`P``
-M`````@```#`!``#\_________T!1`P```````@```$4"``#\_________X]1
-M`P```````@```#`!``#\_________YI1`P```````@```$4"``#\________
-M_[%1`P```````@```!P"``#\_________[Y2`P```````@```(8"``#\____
-M_____Q=3`P``````"P````8````0`P```````"%3`P```````@```*\"``#\
-M_________S13`P```````@```#`!``#\_________S]3`P```````@```$4"
-M``#\_________X93`P```````@```,L!``#\_________Q-4`P```````@``
-M`,L!``#\_________WM4`P```````@```!P"``#\_________T55`P``````
-M`@```*0"``#\_________\A5`P```````@```*0"``#\_________QY6`P``
-M`````@```*0"``#\_________S]6`P```````@```#`!``#\_________TI6
-M`P```````@```$4"``#\_________UA6`P```````@```!L"``#\________
-M_QE7`P```````@```*0"``#\_________UY7`P```````@```*0"``#\____
-M_____W]7`P```````@```#`!``#\_________XI7`P```````@```$4"``#\
-M_________YA7`P```````@```!L"``#\_________\Y7`P```````@```*0"
-M``#\_________R=8`P```````@```*0"``#\_________X18`P```````@``
-M`*0"``#\_________[]8`P```````@```*H!``#\_________^]8`P``````
-M`@```#`!``#\__________I8`P```````@```$4"``#\_________P59`P``
-M`````@```!P"``#\_________VA9`P```````@```)("``#\_________P]<
-M`P```````@```#(!``#\_________R-<`P```````@```#(!``#\________
-M_S]<`P```````@```#(!``#\_________\=<`P```````@```#(!``#\____
-M_____]M<`P```````@```#(!``#\__________E<`P```````@```#(!``#\
-M_________SY=`P```````@```)<!``#\_________VY=`P```````@```.,!
-M``#\_________[9=`P```````@```,\!``#\__________]=`P```````@``
-M`#\!``#\_________P=>`P```````@```(@!``#\_________Q9>`P``````
-M"P````,```#8(````````%]>`P```````@```&4!``#\_________W1>`P``
-M`````@```)X!``#\_________]9>`P```````@```*0"``#\_________S5D
-M`P```````@````L````<`0```````$%D`P``````"P````L````@`0``````
-M`$YD`P```````@```&$!``#\_________Y9D`P```````@```!D"``#\____
-M_____VYE`P```````@```*<!``#\_________YME`P```````@````T"``#\
-M_________ZIE`P```````@```*<!``#\_________XIF`P```````@```,L!
-M``#\_________]%F`P```````@```-\!``#\_________^YF`P```````@``
-M`(8"``#\_________P5G`P```````@```%$!``#\_________X-G`P``````
-M`@```*,!``#\_________[IG`P```````@```)X!``#\_________P)H`P``
-M`````@```,(!``#\_________S%I`P```````@```*0"``#\_________T-J
-M`P```````@````L````>`0```````%!J`P``````"P````L````@`0``````
-M`%IJ`P```````@```&$!``#\_________YMJ`P```````@````L````>`0``
-M`````*AJ`P``````"P````L````@`0```````+)J`P```````@```&$!``#\
-M_________S-K`P```````@```)("``#\_________X%K`P```````@```)("
-M``#\_________YEK`P```````@```%4!``#\_________ZMK`P```````@``
-M`%4!``#\_________[UK`P```````@```%4!``#\_________\]K`P``````
-M`@```%4!``#\_________^%K`P```````@```%4!``#\__________-K`P``
-M`````@```%4!``#\_________Q9L`P```````@```)("``#\_________V-L
-M`P```````@```)("``#\_________X-L`P```````@```)("``#\________
-M_PQM`P```````@```%4!``#\_________U5M`P```````@````@"``#\____
-M_____VEM`P```````@````$"``#\__________MM`P```````@```(8"``#\
-M_________RAN`P```````@```(8"``#\_________S-N`P``````"P```/P!
-M`````````````$%N`P```````@```,4!``#\_________TQN`P```````@``
-M`$4!``#\_________YEN`P```````@````@"``#\_________ZEN`P``````
-M`@````$"``#\_________P-O`P``````"P```/P!`````````````!%O`P``
-M`````@```,4!``#\_________QQO`P```````@```$4!``#\_________WAO
-M`P```````@```(P!``#\_________X9O`P```````@```%<!``#\________
-M_Y!O`P```````@```*0"``#\_________\1O`P```````@```((!``#\____
-M_____]1O`P```````@```%<!``#\_________]YO`P```````@```*0"``#\
-M_________P-P`P```````@```(P!``#\_________Q1P`P```````@```%<!
-M``#\_________QYP`P```````@```*0"``#\_________V5P`P```````@``
-M`((!``#\__________UP`P```````@```$(!``#\_________PAQ`P``````
-M`@```$4"``#\_________Y-S`P```````@```#T"``#\_________[%S`P``
-M`````@```)(!``#\_________Y9T`P```````@```+H!``#\_________ZMT
-M`P``````"P```-H!`````````````.MT`P```````@```#T"``#\________
-M__UT`P```````@```)(!``#\_________Y1U`P```````@```+H!``#\____
-M_____\%U`P```````@```+H!``#\_________V]V`P```````@```'(!``#\
-M_________X=V`P```````@```'\!``#\_________Y]V`P```````@```,T!
-M``#\_________P=W`P``````"P````,````8(0```````'1Z`P```````@``
-M`,P!``#\_________P)[`P```````@```,P!``#\_________QM[`P``````
-M`@```(8"``#\_________^U[`P```````@```&(!``#\_________W1]`P``
-M`````@```)("``#\_________XA]`P```````@```)("``#\_________Y9]
-M`P```````@```*0"``#\_________]]]`P```````@````<```#D`0``````
-M`"I^`P```````@```)("``#\_________UY^`P``````"P````<```#@`0``
-M`````(9^`P```````@````<```#T`0```````-1^`P```````@```)("``#\
-M_________TE_`P```````@````<````$`@```````)=_`P```````@```)("
-M``#\_________\M_`P``````"P````<``````@```````.Y_`P```````@``
-M``<````4`@```````#R``P```````@```)("``#\_________Z>``P``````
-M"P````<```#P`0```````+F``P``````"P````<````0`@```````$^!`P``
-M`````@```)("``#\_________^*!`P```````@```)("``#\_________X&"
-M`P```````@```)("``#\_________Z""`P```````@```*0"``#\________
-M_VZ#`P```````@```$`!``#\_________R"&`P```````@```/H!``#\____
-M_____Z>'`P```````@````,````\)@```````+.'`P``````"P````<```!@
-M`P```````">,`P``````"P````<````@`@```````"R,`P```````@```'<"
-M``#\_________ZJ,`P```````@```&$!``#\_________[B,`P```````@``
-M`*0"``#\_________\V,`P```````@```"4"``#\__________>,`P``````
-M"P````8````D`P````````&-`P```````@```*\"``#\_________U:-`P``
-M`````@```)H"``#\_________VJ-`P```````@```)H"``#\_________WZ-
-M`P```````@```)H"``#\__________&-`P```````@```"L"``#\________
-M_PN.`P```````@```*,"``#\_________QZ.`P```````@```*,"``#\____
-M_____SB.`P```````@```*,"``#\_________TN.`P```````@```*,"``#\
-M_________V6.`P```````@```*,"``#\_________WB.`P```````@```*,"
-M``#\_________Y*.`P```````@```*,"``#\_________Z6.`P```````@``
-M`*,"``#\_________]..`P```````@```*,"``#\_________^..`P``````
-M`@```*,"``#\_________PJ/`P```````@```*,"``#\_________QV/`P``
-M`````@```*,"``#\_________S>/`P```````@```*,"``#\_________TJ/
-M`P```````@```*,"``#\_________V2/`P```````@```*,"``#\________
-M_W>/`P```````@```*,"``#\_________Y&/`P```````@```*,"``#\____
-M_____Z2/`P```````@```*,"``#\_________[Z/`P```````@```*,"``#\
-M_________]&/`P```````@```*,"``#\_________^N/`P```````@```*,"
-M``#\__________Z/`P```````@```*,"``#\_________QB0`P```````@``
-M`*,"``#\_________RN0`P```````@```*,"``#\_________T60`P``````
-M`@```*,"``#\_________UB0`P```````@```*,"``#\_________W*0`P``
-M`````@```*,"``#\_________X60`P```````@```*,"``#\_________Y^0
-M`P```````@```*,"``#\_________[*0`P```````@```*,"``#\________
-M_\R0`P```````@```*,"``#\_________]^0`P```````@```*,"``#\____
-M______F0`P```````@```*,"``#\_________PR1`P```````@```*,"``#\
-M_________R:1`P```````@```*,"``#\_________SF1`P```````@```*,"
-M``#\_________U.1`P```````@```*,"``#\_________V:1`P```````@``
-M`*,"``#\_________XB1`P```````@```-("``#\_________Z*1`P``````
-M`@```-("``#\_________\21`P```````@```-("``#\_________]Z1`P``
-M`````@```-("``#\_________P"2`P```````@```-("``#\_________QJ2
-M`P```````@```-("``#\_________SR2`P```````@```-("``#\________
-M_U:2`P```````@```-("``#\_________WB2`P```````@```-("``#\____
-M_____Y*2`P```````@```-("``#\_________[22`P```````@```-("``#\
-M_________\Z2`P```````@```-("``#\__________"2`P```````@```-("
-M``#\_________PJ3`P```````@```-("``#\_________RR3`P```````@``
-M`-("``#\_________T:3`P```````@```-("``#\_________W*3`P``````
-M`@```$P!``#\_________WJ3`P```````@```+@!``#\_________XF3`P``
-M`````@```+@!``#\_________Y&3`P```````@```)H!``#\_________YN3
-M`P```````@```*0"``#\_________Z.3`P```````@```,X!``#\________
-M_["3`P```````@```),!``#\_________[V3`P```````@```),!``#\____
-M_____^V3`P```````@```),!``#\__________Z3`P```````@```),!``#\
-M_________R64`P```````@```*\!``#\_________SB4`P```````@```*\!
-M``#\_________T64`P```````@```*\!``#\_________UB4`P```````@``
-M`*\!``#\_________V64`P```````@```%<!``#\_________\V4`P``````
-M`@````@"``#\_________R^5`P``````"P````$```!0B0,``````#J5`P``
-M`````@```$4!``#\_________W&5`P```````@```#$!``#\_________X.5
-M`P```````@```*0"``#\_________XN5`P```````@```%<!``#\________
-M_]&5`P```````@```$4"``#\_________UJ6`P```````@````@"``#\____
-M_____]N6`P``````"P````$```!0B0,``````.:6`P```````@```$4!``#\
-M_________QV7`P```````@```#$!``#\_________R^7`P```````@```*0"
-M``#\_________S>7`P```````@```%<!``#\_________W27`P```````@``
-M`$8"``#\__________R7`P``````"P````$```!0B0,```````F8`P``````
-M`@```,4!``#\_________QZ8`P```````@```"X!``#\_________RF8`P``
-M`````@```$4!``#\_________V"8`P```````@```#$!``#\_________W*8
-M`P```````@```*0"``#\_________WJ8`P```````@```%<!``#\________
-M_ZJ8`P```````@```#`!``#\_________[^8`P```````@```$4"``#\____
-M_____\>8`P```````@````@"``#\_________]R8`P```````@```#`!``#\
-M_________^V9`P``````"P````$```!0B0,``````/J9`P```````@```,4!
-M``#\_________P^:`P```````@```"X!``#\_________QJ:`P```````@``
-M`$4!``#\_________U&:`P```````@```#$!``#\_________V.:`P``````
-M`@```*0"``#\_________VN:`P```````@```%<!``#\_________Z6:`P``
-M`````@```#`!``#\_________[R:`P```````@```$4"``#\_________UN;
-M`P```````@````@"``#\_________X&;`P``````"P````8```!``P``````
-M`(N;`P```````@```*\"``#\_________Y>;`P```````@```$8"``#\____
-M_____[";`P```````@```$4"``#\_________^*;`P```````@```+H"``#\
-M__________N;`P```````@```#$!``#\_________TN<`P```````@```(8"
-M``#\_________S.=`P```````@```"P"``#\_________XN=`P``````"P``
-M``$```!0B0,``````)J=`P```````@```,4!``#\_________[6=`P``````
-M`@```"X!``#\_________\N=`P```````@```$4!``#\_________P>>`P``
-M`````@```#$!``#\_________QF>`P```````@```*0"``#\_________R.>
-M`P```````@```%<!``#\_________V6>`P```````@```(8"``#\________
-M_Y>>`P```````@```#`!``#\_________ZR>`P```````@```(L!``#\____
-M_____[N>`P```````@```$4"``#\_________]B>`P```````@```+H"``#\
-M_________[B?`P```````@```#`!``#\_________\B?`P```````@```(L!
-M``#\_________].?`P```````@```$4"``#\_________ZR@`P```````@``
-M`#$!``#\_________^Z@`P```````@```#`"``#\_________S2A`P``````
-M`@```-,!``#\_________TFA`P```````@```+P!``#\_________VBA`P``
-M`````@```!P"``#\_________[*A`P```````@```/4!``#\_________]FB
-M`P```````@```-8!``#\_________P&C`P```````@```#8"``#\________
-M_R&C`P```````@```+P"``#\_________UFC`P```````@```$P!``#\____
-M_____V&C`P```````@```-(!``#\_________VFC`P```````@```-(!``#\
-M_________W&C`P```````@```+@!``#\_________WVC`P```````@```+@!
-M``#\_________XFC`P```````@```)H!``#\_________Y.C`P```````@``
-M`*0"``#\_________YNC`P```````@```,X!``#\_________["C`P``````
-M"P```'$!`````````````,>C`P```````@```)T"``#\_________]2C`P``
-M`````@```,,!``#\__________6C`P```````@```-<!``#\_________P2D
-M`P```````@```-<!``#\_________RFD`P```````@````L```#?`0``````
-M`#:D`P```````@````L```#<`0```````$&D`P```````@````,````\)@``
-M`````%"D`P``````"P````<```!@`P```````%>D`P``````"P```&P!````
-M`````````%ZD`P``````"P````<```!T`P```````&JD`P``````"P````<`
-M``!B`P```````+6D`P``````"P```&P!```<`````````,VD`P``````"P``
-M`&P!```<`````````.&D`P``````"P```&P!```<`````````.^D`P``````
-M"P```&P!```<`````````/FD`P``````"P```&P!```<`````````"^E`P``
-M````"P```&P!```<`````````$.E`P``````"P```&P!```<`````````%&E
-M`P``````"P```&P!```<`````````&RE`P``````"P````<```!L`P``````
-M`+6E`P```````@````,````\)@```````-.E`P``````"P````<```!L`P``
-M`````.&E`P``````"P````<```!P`P```````!&F`P``````"P```&P!````
-M`````````"6F`P``````"P```&P!```<`````````%"F`P``````"P```&P!
-M```,`````````':F`P``````"P```&P!```=`````````(6F`P``````"P``
-M`&P!```<`````````+ZF`P```````@```(`"``#\_________T:G`P``````
-M`@```/\!``#\_________V*G`P```````@```#0!``#\_________VJG`P``
-M`````@```/4!``#\_________XBG`P```````@```+\!``#\_________YRG
-M`P```````@```+\!``#\_________T&H`P``````"P````4```!P"@``````
-M`$NH`P```````@```*\"``#\_________UVH`P```````@````@"``#\____
-M_____Y&H`P``````"P````4```"X"@```````)NH`P```````@```*\"``#\
-M_________^"H`P``````"P````$```!0B0,``````.NH`P```````@```$4!
-M``#\_________R*I`P```````@```#$!``#\_________S2I`P```````@``
-M`*0"``#\_________SRI`P```````@```%<!``#\_________W^I`P``````
-M`@````@"``#\_________Z6I`P```````@```$8"``#\_________\2I`P``
-M`````@```$4"``#\_________R^J`P``````"P````$```!0B0,``````#ZJ
-M`P```````@```,4!``#\_________U"J`P```````@```"X!``#\________
-M_UNJ`P```````@```$4!``#\_________Y*J`P```````@```#$!``#\____
-M_____Z2J`P```````@```*0"``#\_________ZRJ`P```````@```%<!``#\
-M_________]RJ`P```````@```+X!``#\_________P&K`P```````@```#`!
-M``#\_________PRK`P```````@```$4"``#\_________R.K`P```````@``
-M`$4"``#\_________X:K`P``````"P````,`````(@```````+NK`P``````
-M`@```)8!``#\__________2K`P```````@```(<!``#\_________RJL`P``
-M`````@```+H"``#\_________S^L`P```````@```#$!``#\_________U:L
-M`P```````@```*0"``#\_________UZL`P```````@```%<!``#\________
-M_Y>L`P```````@```+H"``#\_________ZNL`P```````@```$`"``#\____
-M_____[>L`P```````@```!T"``#\_________Y*M`P``````"P````4`````
-M"P```````)RM`P```````@```*\"``#\_________]"M`P```````@```'\"
-M``#\_________^6M`P``````"P````$```#@K`,``````/FM`P```````@``
-M`)T"``#\_________YZP`P```````@```/\!``#\_________\"P`P``````
-M`@```#0!``#\_________^VP`P```````@```,L!``#\_________UBQ`P``
-M`````@```,L!``#\_________[2Q`P```````@```+H"``#\__________2Q
-M`P```````@```,L!``#\_________V"R`P```````@```+H"``#\________
-M_X:S`P```````@```)8!``#\_________]RS`P```````@```-8!``#\____
-M_____^ZS`P```````@```+\!``#\_________RFT`P```````@```%<!``#\
-M_________T^T`P```````@```,,!``#\_________V^T`P```````@```'\"
-M``#\_________X2T`P``````"P```'$!`````````````)>T`P```````@``
-M`)T"``#\__________FU`P```````@```/4!``#\_________TVV`P``````
-M"P````,```!0(@```````'6V`P```````@```%L!``#\_________]"V`P``
-M`````@```%L!``#\_________RNW`P```````@```%L!``#\_________X:W
-M`P```````@```%L!``#\_________]>X`P``````"P````,```!P(P``````
-M``BY`P```````@```%L!``#\_________VBY`P```````@```%L!``#\____
-M_____\"Y`P```````@```%L!``#\_________QBZ`P```````@```%L!``#\
-M_________W&Z`P```````@```%L!``#\_________\BZ`P```````@```%L!
-M``#\_________R2[`P```````@```%L!``#\_________X"[`P```````@``
-M`%L!``#\_________]B[`P```````@```%L!``#\_________S"\`P``````
-M`@```%L!``#\_________X"\`P```````@```)<!``#\_________[J\`P``
-M`````@```)<!``#\__________2\`P```````@```)<!``#\_________RZ]
-M`P```````@```)<!``#\_________V6]`P```````@```)<!``#\________
-M_YR]`P```````@```)<!``#\_________S:^`P```````@````L```#<`0``
-M`````$*^`P```````@````L```#<`0```````"_``P```````@```(X"``#\
-M_________TG``P```````@```(X"``#\_________Y/``P```````@````,`
-M```\)@```````*G``P``````"P````<```!@`P```````+O``P``````"P``
-M``<```!B`P```````,G``P``````"P````<```!P`P```````-+``P``````
-M"P````<```!P`P```````-G``P``````"P````<```!L`P```````//``P``
-M````"P````<```!P`P```````"W!`P```````@```,8"``#\_________T_!
-M`P```````@```+\"``#\_________WW!`P``````"P```&P!````````````
-M`)7!`P``````"P```&P!```<`````````+S!`P``````"P```&P!```,````
-M`````-G!`P``````"P```&P!```=`````````./!`P``````"P```&P!```=
-M`````````.O!`P``````"P```&P!```<``````````C"`P``````"P```&P!
-M```=`````````!S"`P``````"P```&P!```<`````````'_#`P```````@``
-M`/4!``#\_________PW%`P```````@```*<!``#\_________S[%`P``````
-M`@````T"``#\_________TW%`P```````@```*<!``#\__________#(`P``
-M`````@```*<!``#\_________Q[)`P```````@````T"``#\_________RW)
-M`P```````@```*<!``#\_________P_-`P```````@```*<!``#\________
-M_SW-`P```````@````T"``#\_________T[-`P```````@```*<!``#\____
-M_____P_1`P```````@```*<!``#\_________SW1`P```````@````T"``#\
-M_________T[1`P```````@```*<!``#\_________[33`P```````@````@"
-M``#\_________[#5`P```````@```(8"``#\_________WS7`P``````"P``
-M``$````PGP,``````/O7`P```````@```"P"``#\_________PC8`P``````
-M`@```,4!``#\_________QO8`P```````@```"X!``#\_________SG8`P``
-M`````@```,4!``#\_________TO8`P```````@```$8"``#\_________WS8
-M`P```````@```"X!``#\_________Y'8`P```````@```(`!``#\________
-M_\+8`P```````@```"X!``#\_________P?9`P```````@```(8"``#\____
-M_____WK9`P```````@```(8"``#\_________[[9`P```````@```$4!``#\
-M_________\O9`P```````@```$4"``#\_________VC<`P```````@```,8"
-M``#\_________XK<`P```````@```,8"``#\_________^+=`P```````@``
-M`#`"``#\_________SC>`P```````@```,L!``#\_________Y#>`P``````
-M`@```+P!``#\_________\'>`P```````@```-,!``#\___________>`P``
-M`````@```(\!``#\_________RK?`P```````@```!P"``#\_________U3?
-M`P```````@```,L!``#\_________Z[?`P```````@```)L!``#\________
-M__/?`P```````@```)P"``#\__________[?`P```````@```)P"``#\____
-M_____Q+@`P```````@```%8"``#\_________T/@`P```````@```)0"``#\
-M_________^K@`P```````@```)0"``#\_________S3A`P```````@```&<"
-M``#\_________[/A`P```````@```$P"``#\_________\#A`P```````@``
-M`$P"``#\_________\KA`P```````@```%8"``#\_________];A`P``````
-M`@```%8"``#\_________^GA`P```````@```$P"``#\_________W/B`P``
-M`````@```$P"``#\_________V/C`P```````@```)0"``#\_________PWD
-M`P```````@```*<"``#\_________U'D`P```````@```*<"``#\________
-M_]CD`P```````@```*<"``#\__________SD`P```````@```,,"``#\____
-M_____WGE`P```````@```*<"``#\_________\/E`P```````@```*<"``#\
-M_________]WE`P```````@```,,"``#\__________+F`P```````@```,,"
-M``#\_________POH`P```````@```&("``#[_________R;H`P```````@``
-M`'\"``#\_________S[H`P``````"P```%@"``````````````'I`P``````
-M`@```&("``#[_________Q;I`P```````@```'\"``#\_________RSI`P``
-M````"P```%@"`````````````#[I`P```````@```)T"``#\_________V7I
-M`P```````@```+("``#\_________^7I`P```````@```(\"``#\________
-M_[GJ`P```````@```+4"``#[__________;J`P```````@```%,"``#\____
-M_____T?L`P```````@```,`"``#\_________W+L`P```````@```&,"``#\
-M_________XCL`P```````@```*4"``#[_________Y?L`P```````@```&P"
-M``#\_________Z'L`P```````@```%0"``#\_________[3L`P```````@``
-M`%X"``#\_________QGM`P```````@````L```!L`@```````#KM`P``````
-M`@````L```!L`@```````$KM`P```````@````L```!L`@```````%KM`P``
-M`````@```,X"``#\_________WCM`P```````@```+("``#\_________X7M
-M`P```````@````L```!L`@```````)/M`P``````"P````$```!`[P,`````
-M`*CM`P```````@```*,"``#\_________[SM`P```````@````L```!H`@``
-M`````//M`P```````@```+<"``#\__________KM`P``````"P````L```!`
-M`@````````3N`P```````@````L```!(`@````````CN`P``````"P```-,"
-M``````````````_N`P```````@````L```!4`@```````!ON`P```````@``
-M``L````\`@```````"#N`P```````@```)T"``#\_________Y3N`P``````
-M`@```$P"``#\_________^+N`P```````@```-,"``#\_________Q;O`P``
-M`````@```*0"``#\_________Q[O`P```````@```(<"``#\_________VCO
-M`P```````@```&0"``#\_________[7O`P```````@```*,"``#\________
-M_]#O`P```````@```*,"``#\_________W+P`P```````@```'$"``#\____
-M_____W+Q`P```````@```(,"``#\_________W[Q`P```````@```+("``#\
-M_________\+Q`P```````@```*,"``#\_________]'Q`P```````@```$X"
-M``#\_________T+R`P```````@```+`"``#\_________UCR`P```````@``
-M`+`"``#\_________VCR`P```````@```$P"``#\_________ZKR`P``````
-M`@```+`"``#\_________\?R`P```````@```+`"``#\_________^'R`P``
-M`````@```+`"``#\__________[R`P```````@```+`"``#\_________Q[S
-M`P```````@```+`"``#\_________T?S`P```````@```(@"``#\________
-M_U[S`P```````@```+`"``#\_________V7S`P```````@```$P"``#\____
-M_____[GS`P```````@```)0"``#\_________\+S`P```````@```+8"``#\
-M_________^#S`P```````@```)0"``#[_________UWT`P```````@```)0"
-M``#\_________W;T`P```````@```*4"``#[_________Z/T`P```````@``
-M`%P"``#\_________[ST`P```````@```+("``#\_________]?T`P``````
-M`@````L```!P`@```````.?T`P```````@````L```!P`@```````.KU`P``
-M`````@```*,"``#\__________7U`P```````@```)0"``#\_________SCV
-M`P```````@```(,"``#\_________W?V`P```````@```*,"``#\________
-M_Y#V`P```````@```$P"``#\_________^'V`P```````@```)0"``#\____
-M_____ZOE`P```````@```'D"``#\_________[OE`P```````@```*<"``#\
-M_________X_F`P```````@```'D"``#\_________P7G`P```````@```'D"
-M``#\_________W/G`P```````@```'\"``#\_________U7H`P```````@``
-M`)T"``#\_________RSJ`P```````@```-$"``#\_________SWJ`P``````
-M`@```*,"``#\_________V'J`P```````@```*D"``#\_________P7O`P``
-M`````@```*<"``#\_________TOP`P```````@```*,"``#\_________Q/W
-M`P``````"P````$```#0'@0``````#;W`P```````@````<```"X`P``````
-M`.#W`P``````"P````$```!P_0,``````,+Y`P```````@```+,"``#\____
-M______[Y`P```````@```*8"``#\_________S'Z`P``````"P````$````@
-M_`,``````%WZ`P```````@```*8"``#\_________]GZ`P```````@````,`
-M``!$)@```````.;Z`P```````@````,```!()@```````#[[`P``````"P``
-M``$```#P_`,``````+;[`P```````@```$@"``#\_________P+\`P``````
-M"P````$````P_`,``````$;\`P```````@```(D"``#\_________XG\`P``
-M`````@```)P"``#\_________X_\`P```````@````<```"T`P```````*O\
-M`P```````@````<```"X`P```````,7\`P```````@````<```"X`P``````
-M`-'\`P``````"P````<```"@`P```````-?\`P```````@````<```"W`P``
-M`````-W\`P```````@```,T"``#\_________QS]`P```````@```(D"``#\
-M_________\;]`P```````@```*,"``#\_________]3]`P``````"P````$`
-M``"`^0,```````O^`P``````"P````<```"@`P```````!?^`P```````@``
-M`(("``#\_________S'_`P``````"P````<```"@`P```````#;_`P``````
-M`@```(("``#\_________S[_`P```````@```+("``#\_________RH`!```
-M````"P````<```"@`P```````"\`!````````@```(("``#\_________S<`
-M!````````@```+("``#\_________XL`!```````"P````<```"@`P``````
-M`)``!````````@```(("``#\_________Y@`!````````@```+("``#\____
-M_____\D`!```````"P````<```"@`P```````,X`!````````@```(("``#\
-M_________]8`!````````@```+("``#\_________PX!!```````"P````<`
-M``"@`P```````!,!!````````@```(("``#\_________QL!!````````@``
-M`+("``#\_________W$!!```````"P````<```"@`P```````(8!!```````
-M`@```(("``#\_________Y$!!````````@```*,"``#\_________Z4!!```
-M````"P````<```"@`P```````+(!!````````@```(("``#\_________\\!
-M!````````@```*,"``#\_________U$"!````````@```&T"``#\________
-M_VH"!````````@```+("``#\_________X`"!```````"P````$```"P_0,`
-M`````,,"!````````@```$@"``#\_________Q8#!```````"P````<```"@
-M`P```````!L#!````````@```(("``#\_________W(#!```````"P````,`
-M``!0)@```````+<#!````````@```-`"``#\__________`#!````````@``
-M`&T"``#\__________X#!````````@```+P"``#\_________R<$!```````
-M`@```+("``#\_________T($!```````"P````$```!`!00``````%8$!```
-M`````@```-`"``#\_________V,$!````````@```+P"``#\_________[0$
-M!```````"P````,```"0)@```````!4%!````````@```-`"``#\________
-M_V$%!````````@```*,"``#\_________WL%!```````"P````$```#@%@0`
-M`````)D%!````````@```*4"``#[__________$%!````````@```&$"``#\
-M_________Q@&!```````"P````<```"@`P```````!T&!````````@```(("
-M``#\_________R@&!````````@```*,"``#\_________U$&!````````@``
-M`&T"``#\_________V<&!````````@```&8"``#\_________Z<(!```````
-M`@```&8"``#\_________]0(!````````@```&$"``#\_________S4)!```
-M`````@```&8"``#\_________UL)!````````@```&$"``#\_________XH)
-M!```````"P````<```"@`P```````(\)!````````@```(("``#\________
-M_Y<)!````````@```+("``#\_________^D)!````````@```*4"``#[____
-M_____TH*!````````@```&$"``#\_________WT*!````````@```&$"``#\
-M_________\D*!````````@```&$"``#\_________^0*!````````@```&T"
-M``#\__________H*!````````@```&8"``#\_________TH+!````````@``
-M`*4"``#\_________Y@+!````````@```&$"``#\_________PH,!```````
-M"P````<```"@`P````````\,!````````@```(("``#\_________QH,!```
-M`````@```*,"``#\_________X<-!````````@```&8"``#\_________Y4-
-M!```````"P````4```!8"P```````)X-!````````@```*\"``#\________
-M_\P-!````````@```&8"``#\_________]D-!```````"P````4```"`"P``
-M`````.(-!````````@```*\"``#\_________Q\.!````````@```&$"``#\
-M_________T$.!````````@```&8"``#\_________V,.!````````@```&8"
-M``#\_________WX.!```````"P````8```!@`P```````*T.!````````@``
-M`*\"``#\_________]L/!````````@```&8"``#\_________PL0!```````
-M`@```&$"``#\_________R\0!````````@```&$"``#\_________UD0!```
-M`````@```%\"``#\_________YT0!````````@```&$"``#\_________\(0
-M!````````@```+4"``#[_________]X0!````````@```&8"``#\________
-M__D0!````````@```(H"``#\_________WX1!````````@```&$"``#\____
-M_____XD1!```````"P````4```"H"P```````*H1!````````@```*\"``#\
-M_________TL2!````````@```&8"``#\_________W02!````````@```&$"
-M``#\_________Y\2!````````@```&$"``#\_________[D2!```````"P``
-M``8```!U`P```````,`2!````````@```*\"``#\_________]T2!```````
-M`@```&8"``#\_________PL3!````````@```&$"``#\_________T(3!```
-M`````@```&$"``#\_________TT3!```````"P````4```#8"P```````&T3
-M!````````@```*\"``#\_________X\3!````````@```(8"``#\________
-M_\P3!````````@```&$"``#\_________]P3!````````@```&L"``#\____
-M_____P`4!````````@```&$"``#\_________S,4!````````@```&$"``#\
-M_________V`4!````````@```&$"``#\_________W<4!````````@```(,"
-M``#\_________XX4!````````@```&8"``#\_________\(4!````````@``
-M`(H"``#\_________TT5!````````@```&<"``#\_________RH6!```````
-M`@```,L"``#\_________UH6!````````@```$D"``#\_________Z,6!```
-M`````@```*4"``#[_________](6!````````@```&D"``#\__________T6
-M!````````@```&0"``#\_________Q<7!````````@```+4"``#[________
-M_X87!````````@```,4"``#\_________Y`7!````````@```%X"``#\____
-M_____[(7!```````"P```$L"`````````````,D7!````````@```-`"``#\
-M_________W,8!````````@```&`"``#\_________YD8!````````@```(,"
-M``#\_________PL9!````````@```&`"``#\_________R<9!````````@``
-M`&`"``#\_________QD:!````````@```(H"``#\_________XL:!```````
-M`@```(,"``#\_________\P:!````````@```%\"``#\_________T0;!```
-M`````@```$X"``#\_________U$;!````````@```+,"``#\_________Y`;
-M!````````@```$H"``#\_________[L;!````````@```$X"``#\________
-M__X;!````````@```*,"``#\_________T`<!````````@```&,"``#\____
-M_____V4<!````````@```%,"``#\_________U(=!````````@```+,"``#\
-M_________]P=!````````@```,4"``#\__________$=!````````@```&P"
-M``#\_________QD>!````````@```%0"``#\_________S\>!````````@``
-M`+("``#\_________V(>!```````"P````$```#@&P0``````)P>!```````
-M`@```$@"``#\__________H?!````````@```,H"``#\_________V8@!```
-M````"P````$````0(00``````'4A!````````@```,H"``#\_________V0B
-M!````````@```&T"``#\_________T/Z`P```````@```*L"``#\________
-M_PO\`P```````@```*L"``#\_________R'\`P```````@```(D"``#\____
-M_____WK\`P```````@```)4"``#\_________UC]`P```````@```-`"``#\
-M_________Z/]`P```````@```-`"``#\__________?]`P```````@```-`"
-M``#\_________US^`P```````@```*,"``#\_________P`"!````````@``
-M`*,"``#\_________SP#!````````@```+`"``#\_________X0%!```````
-M`@```%H"``#\_________]()!````````@```(,"``#\_________U,7!```
-M`````@```&T"``#\_________WX7!````````@```*,"``#\_________ZL8
-M!````````@```%\"``#\_________VL;!````````@```(,"``#\________
-M_](;!````````@```%\"``#\_________\@@!````````@```-`"``#\____
-M_____P`A!````````@```,H"``#\_________QPB!````````@```-`"``#\
-M_________Y,B!````````@```)0"``#\_________WHC!````````@```)0"
-M``#\_________STD!````````@```)0"``#\_________T(E!````````@``
-M`)0"``#\__________\F!```````"P````,```#0)@```````"0K!```````
-M`@```'("``#\_________S0L!````````@```'("``#\__________`L!```
-M````"P````,````0)P```````"(N!````````@```'("``#\_________XTN
-M!````````@```'("``#\_________S$O!````````@```'("``#\________
-M_U(O!````````@````L```"``@```````&\O!````````@````L```!\`@``
-M`````(`O!```````"P````L```"@`@```````)LO!```````"P````L```"@
-M`@```````,DO!````````@````L```"``@````````PP!````````@```%$"
-M``#\_________V,U!````````@```'("``#\_________Z,U!````````@``
-M`'("``#\_________^,U!````````@```'("``#\_________TDV!```````
-M`@```'("``#\_________[`V!````````@```'("``#\_________RXW!```
-M`````@```'("``#\_________[,W!````````@```*4"``#[_________],W
-M!````````@```'("``#\_________P`X!````````@```'("``#\________
-M_Z8X!````````@```'("``#\_________\HX!````````@```'("``#\____
-M_____[8Y!````````@```'("``#\_________]HY!````````@```'("``#\
-M_________W0Z!````````@```'("``#\_________YDZ!````````@```'("
-M``#\_________Q0[!````````@```'("``#\_________R$[!````````@``
-M`'("``#\_________U,[!````````@```'("``#\_________WD[!```````
-M`@```'("``#\_________^0[!````````@```'("``#\__________$[!```
-M`````@```'("``#\_________S,\!````````@```'("``#\_________UT\
-M!````````@```'("``#\_________[@\!````````@```'("``#\________
-M_\0\!````````@```'("``#\_________R@]!````````@```'("``#\____
-M_____S0]!````````@```'("``#\_________Y@]!````````@```'("``#\
-M_________Z0]!````````@```'("``#\_________P8^!````````@```'("
-M``#\_________Q(^!````````@```'("``#\_________V8^!````````@``
-M`'("``#\_________W(^!````````@```'("``#\_________\8^!```````
-M`@```'("``#\_________](^!````````@```'("``#\_________R8_!```
-M`````@```'("``#\_________S(_!````````@```'("``#\_________[8_
-M!````````@```'("``#\_________\(_!````````@```'("``#\________
-M_R9`!````````@```'("``#\_________S)`!````````@```'("``#\____
-M_____Y]`!````````@```'("``#\_________ZQ`!````````@```'("``#\
-M_________[A`!````````@```'("``#\_________\-`!````````@```'("
-M``#\_________U9!!````````@```'("``#\_________V)!!````````@``
-M`'("``#\_________\9!!````````@```'("``#\_________])!!```````
-M`@```'("``#\_________SI"!````````@```'("``#\_________T9"!```
-M`````@```'("``#\_________ZQ"!````````@```'("``#\_________[A"
-M!````````@```'("``#\_________\1#!````````@```'("``#\________
-M_]%#!````````@```'("``#\_________X1$!````````@```'("``#\____
-M_____Y%$!````````@```'("``#\__________9$!````````@```'("``#\
-M_________P)%!````````@```'("``#\_________X5%!````````@```'("
-M``#\_________ZI%!````````@```'("``#\_________S5&!````````@``
-M`'("``#\_________UI&!````````@```'("``#\_________\1&!```````
-M`@```'("``#\_________]!&!````````@```'("``#\_________^1'!```
-M`````@```'("``#\__________%'!````````@```'("``#\_________\)(
-M!````````@```'("``#\_________\](!````````@```'("``#\________
-M_Y!)!````````@```'("``#\_________YU)!````````@```'("``#\____
-M_____]1)!````````@````<````<!````````.M)!```````"P````<````@
-M!````````#%+!```````"P````$```!`+P0``````#-,!````````@```%$"
-M``#\_________\-,!````````@```+4"``#\_________SY-!````````@``
-M`*8"``#\_________VU-!```````"P````$```#P5@0``````+]-!```````
-M`@```*8"``#\_________\Y-!````````@```+("``#\_________X5.!```
-M`````@```*8"``#\_________]I.!```````"P````$```!`6`0``````.=.
-M!```````"P````$`````6`0``````.Q.!````````@```*L"``#\________
-M_T9/!````````@```+("``#\_________^I/!````````@```*,"``#\____
-M_____QQ0!```````"P````8```".`P```````"-0!````````@```*\"``#\
-M_________V90!````````@```+("``#\__________E0!````````@```*,"
-M``#\_________RM1!```````"P````8```"I`P```````#)1!````````@``
-M`*\"``#\_________]U1!```````"P````$```#PB00```````U2!```````
-M"P````$```!@7`0``````$U2!```````"P````$```#P700``````(U2!```
-M````"P````$```#PW@0``````,U2!```````"P````$````PSP0```````U3
-M!```````"P````$```"@E@0``````$U3!```````"P````$```"@TP0`````
-M`(U3!```````"P````$```#@F@0``````,U3!```````"P````$```"`EP0`
-M``````U4!```````"P````$```!@X@0``````$U4!```````"P````$```!`
-MBP0``````(U4!```````"P````$````@U@0``````,U4!```````"P````$`
-M``#`FP0```````U5!```````"P````$```#`FP0``````$U5!```````"P``
-M``$```#@G00``````(U5!```````"P````$```#`K@0``````,U5!```````
-M"P````$```!@XP0```````U6!```````"P````$```!`L`0``````$U6!```
-M````"P````$````PUP0``````(U6!```````"P````$````PKP0``````,U6
-M!```````"P````$```"PN`0``````/16!```````"P````$````PZP0`````
-M`"A7!```````"P````$```!0N00``````(!7!````````@```*,"``#\____
-M_____XM7!```````"P````$```"0L`0``````!-8!```````"P````$````0
-M600``````)Q8!````````@```(D"``#\_________ZM8!````````@```*8"
-M``#\_________]Q8!```````"P````$`````6`0``````#M9!````````@``
-M`*,"``#\_________^I9!```````"P````4````P#````````/%9!```````
-M`@```*\"``#\__________Y9!````````@```&T"``#\_________Q-:!```
-M`````@```*,"``#\_________QM:!````````@```(D"``#\_________TI:
-M!```````"P````4````(#````````%%:!````````@```*\"``#\________
-M_UY:!````````@```&T"``#\_________XI:!````````@```(D"``#\____
-M_____Y9:!```````"P````$```"0[`0``````"A;!````````@```*,"``#\
-M_________S!;!````````@```(D"``#\_________Z1;!```````"P````$`
-M``!`A00``````'U<!````````@```'("``#\_________TA=!````````@``
-M`&$"``#\_________U1=!```````"P````$```!02P0``````,Q=!```````
-M`@```&$"``#\_________P9>!````````@```'("``#\_________W]>!```
-M`````@```&$"``#\_________Z!>!```````"P````$```!02P0``````/->
-M!````````@```(D"``#\__________M>!```````"P````$```!02P0`````
-M`-]?!```````"P````$```"`800``````+U@!```````"P````$```!02P0`
-M`````,Y@!````````@```)4"``#\_________Y]A!```````"P````$```!0
-M2P0``````,YA!````````@```)0"``#\_________U9B!```````"P````$`
-M``!02P0``````&IB!````````@```)4"``#\_________X)B!````````@``
-M``L```!\`@```````(AB!````````@````L```"``@```````*5B!```````
-M"P````L```"@`@```````+!B!```````"P````L```"H`@```````+QB!```
-M````"P````L```"P`@```````,AB!```````"P````L```"X`@```````-1B
-M!```````"P````L```#``@```````-]B!```````"P````L```#(`@``````
-M`/IB!````````@````L```!\`@````````)C!```````"P````$```!02P0`
-M`````)IC!```````"P````$```!02P0``````$%D!```````"P````$```!0
-M2P0``````%)D!````````@```)4"``#\_________Y]D!````````@```'("
-M``#\__________MD!```````"P````$```!02P0``````&5E!````````@``
-M`'("``#\_________ZEE!```````"P````$```!02P0``````/AE!```````
-M`@```)0"``#\_________TAF!```````"P````$```!02P0``````)UF!```
-M`````@```)0"``#\_________QUG!```````"P````$```!02P0``````/AG
-M!```````"P````$```!02P0```````MH!````````@```)4"``#\________
-M_]MH!```````"P````$```!02P0``````.YH!````````@```)4"``#\____
-M_____]MI!```````"P````$```!02P0``````.YI!````````@```)4"``#\
-M_________\MJ!```````"P````$```!02P0``````-YJ!````````@```)4"
-M``#\_________[MK!```````"P````$```!02P0``````,YK!````````@``
-M`)4"``#\_________YEL!```````"P````$```!02P0``````*QL!```````
-M`@```)4"``#\_________^5L!```````"P````$```!02P0``````)5M!```
-M````"P````$```!02P0``````*9M!````````@```)4"``#\_________^9M
-M!```````"P````$```!02P0``````!1N!```````"P````8```#!`P``````
-M`#9N!````````@```+4"``#\_________SYN!```````"P````$```!02P0`
-M`````&1N!```````"P````8```#.`P```````(%N!````````@```(P"``#\
-M_________XIN!```````"P````8```#?`P```````)UN!```````"P````8`
-M``#\`P```````+AN!```````"P````$```!@=@0``````.IN!````````@``
-M`%`"``#\__________9N!```````"P````8````9!````````!%O!```````
-M"P````$```!@;P0``````#AO!```````"P````$```!02P0``````,IO!```
-M````"P````$```!02P0``````-MO!````````@```)4"``#\_________V%P
-M!````````@```'("``#\_________Y5P!````````@```*,"``#\________
-M_YUP!````````@```(D"``#\_________]EP!```````"P````$```!02P0`
-M`````)AQ!```````"P````$`````A00``````.MQ!````````@```'("``#\
-M_________PMR!````````@```'("``#\_________S9R!````````@```'("
-M``#\_________XAR!````````@```'("``#\_________]MR!````````@``
-M`'("``#\_________PAS!````````@```'("``#\_________YAS!```````
-M`@```'("``#\_________Z)S!````````@```'("``#\_________]MS!```
-M`````@```'("``#\__________MS!````````@```'("``#\_________QAT
-M!````````@```'("``#\_________Y!T!````````@```'("``#\________
-M_]!T!````````@```'("``#\_________PQU!````````@```'("``#\____
-M_____TQU!````````@```'("``#\_________XQU!````````@```'("``#\
-M_________\UU!````````@```'("``#\__________=U!```````"P````8`
-M``#\`P```````+IV!````````@```&("``#\__________MV!````````@``
-M`'\"``#\_________Q%W!```````"P```%@"`````````````"-W!```````
-M`@```)T"``#\_________SIW!```````"P````$```!02P0``````$MW!```
-M`````@```)4"``#\_________V)W!````````@```$T"``#\_________\5W
-M!````````@```*8"``#\_________XMX!```````"P````$```"`T`0`````
-M`-%X!````````@```+("``#\__________MX!````````@```(8"``#\____
-M_____S!Y!```````"P````$```!@600``````$!Y!```````"P````$```!0
-M2P0``````%%Y!````````@```)4"``#\_________U)Z!```````"P````$`
-M``!02P0``````)-Z!```````"P````$```!02P0``````*1Z!````````@``
-M`)4"``#\_________]MZ!````````@```'("``#\__________MZ!```````
-M`@```'("``#\_________S1[!````````@```'("``#\_________T)[!```
-M`````@```*8"``#\_________XI[!````````@```(8"``#\_________\U[
-M!```````"P````$````P2`0``````-A[!```````"P````$```#07@0`````
-M`#!\!```````"P````$```!02P0``````)5\!```````"P````$```!02P0`
-M`````*9\!````````@```)4"``#\_________]1\!````````@```*4"``#[
-M__________9\!```````"P````8```#.`P````````U]!```````"P````8`
-M``#?`P```````%9]!````````@```%`"``#\_________V5]!```````"P``
-M``$```!02P0``````,1]!````````@```(P"``#\_________^-]!```````
-M"P````8```#\`P````````1^!```````"P````8```#!`P```````$U^!```
-M`````@```+4"``#\_________XY^!````````@```&("``#\_________T.`
-M!````````@```&$"``#\_________XV`!````````@```&$"``#\________
-M_[N`!````````@```&$"``#\_________^2"!```````"P````$```!02P0`
-M`````/>"!````````@```)4"``#\_________T&$!```````"P````$```!0
-M2P0``````%*$!````````@```)4"``#\_________[.$!````````@```,@"
-M``#\_________[Z$!````````@```*8"``#\_________]N$!```````"P``
-M``$```!P6@0```````N%!````````@```'("``#\_________Q.%!```````
-M`@```*T"``#\_________QN%!```````"P````$```!02P0``````$F%!```
-M`````@```*T"``#\_________UB%!```````"P````$```!02P0``````-Z%
-M!```````"P````$```!P400``````'2&!```````"P````$```!@B`0`````
-M`%>'!````````@```&T"``#\_________VB'!````````@```%`"``#[____
-M_____XB'!````````@```%`"``#[__________&'!````````@```&T"``#\
-M_________SV(!````````@```&T"``#\_________Z:(!```````"P````$`
-M``"`A00``````/N)!```````"P````$```!@B`0``````):*!```````"P``
-M``$```!@B`0``````*:*!````````@```*`"``#\__________^*!```````
-M"P````$```!@B`0``````!^+!````````@```*`"``#\_________U>+!```
-M`````@```'("``#\_________W&+!```````"P````$```!02P0``````*6+
-M!```````"P````,```!0)P```````-:+!````````@```&T"``#\________
-M_W2,!````````@```&H"``#\_________Y:,!```````"P````$```!@B`0`
-M`````+R,!````````@```*`"``#\_________\F,!````````@```&T"``#\
-M_________^R,!````````@```&T"``#\_________SN-!````````@```&T"
-M``#\_________SB.!````````@```&H"``#\_________V^.!```````"P``
-M``$```!@B`0``````'^.!````````@```*`"``#\_________XR.!```````
-M`@```&T"``#\_________Z6.!````````@```&T"``#\_________UN/!```
-M`````@```&T"``#\_________P60!````````@```&T"``#\_________XJ0
-M!```````"P````$```!@B`0``````)J0!````````@```*`"``#\________
-M_Z>0!````````@```&T"``#\__________20!````````@```&T"``#\____
-M_____T>1!````````@```(T"``#\_________UB1!````````@```(T"``#\
-M_________ZZ1!````````@```&T"``#\__________N1!````````@```&T"
-M``#\_________P^2!````````@```,4"``#\_________QR2!````````@``
-M`*T"``#\_________RF2!````````@```(T"``#\_________SF2!```````
-M`@```,4"``#\_________U"2!````````@```&H"``#\_________WV2!```
-M````"P````$```!@B`0``````(V2!````````@```*`"``#\_________YJ2
-M!````````@```&T"``#\_________[&2!````````@```'L"``#\________
-M_\^2!````````@```&H"``#\_________P>3!```````"P````$```!@B`0`
-M`````!>3!````````@```*`"``#\_________R23!````````@```&T"``#\
-M_________U&3!```````"P````$```!@B`0``````&&3!````````@```*`"
-M``#\_________VZ3!````````@```&T"``#\_________Y>3!```````"P``
-M``$```!@B`0``````+:3!````````@```*`"``#\_________\.3!```````
-M`@```&T"``#\_________W:6!````````@```&H"``#\_________[J6!```
-M`````@```'("``#\_________Q&7!````````@```*T"``#\_________R.7
-M!```````"P````$```!02P0``````%>7!````````@```&D"``#\________
-M_\*7!```````"P````$```!02P0``````-.7!````````@```)4"``#\____
-M______&7!````````@```'("``#\_________V>8!````````@```&D"``#\
-M_________VN:!```````"P````4```!@#````````'":!````````@```*\"
-M``#\_________R*;!```````"P````$```!02P0``````#.;!````````@``
-M`)4"``#\_________U&;!````````@```'("``#\_________VZ;!```````
-M`@```&D"``#\_________\N;!````````@```'("``#\_________P><!```
-M`````@```&D"``#\_________P^<!```````"P````$```!02P0``````).<
-M!````````@```$X"``#\__________.<!````````@```(,"``#\________
-M_R6=!````````@```&4"``#\_________T>=!````````@```&$"``#\____
-M_____X>=!````````@```&$"``#\_________Y2=!````````@```&D"``#\
-M_________\.=!````````@```$X"``#\_________PJ>!````````@```'("
-M``#\_________U&>!```````"P````$```!02P0``````$6?!````````@``
-M`*,"``#\_________X^?!````````@```'L"``#\_________Q6@!```````
-M`@```'("``#\_________S.@!```````"P````,```#()P```````$N@!```
-M`````@```%P"``#\_________XB@!````````@```%P"``#\_________\:@
-M!````````@```'("``#\__________.A!````````@```(H"``#\________
-M_S^B!````````@```'("``#\_________V^B!````````@```%T"``#\____
-M_____Y:B!````````@```$X"``#\_________Z2B!````````@```(,"``#\
-M_________T:D!````````@```(H"``#\_________P*E!````````@```'("
-M``#\_________URE!````````@```'("``#\_________W>E!````````@``
-M`%T"``#\_________TNF!````````@```%("``#\_________UFG!```````
-M`@```+("``#\_________W.G!````````@```'L"``#\_________XJG!```
-M`````@```%<"``#\_________TNH!````````@```*T"``#\_________U.H
-M!````````@```(T"``#\_________Z:H!```````"P````$```!@B`0`````
-M`+:H!````````@```*`"``#\_________\.H!````````@```&T"``#\____
-M_____R*I!```````"P````$```!@B`0``````#*I!````````@```*`"``#\
-M_________S^I!````````@```&T"``#\_________WRI!````````@```,@"
-M``#\_________]:I!````````@```$X"``#\_________YJJ!````````@``
-M`'("``#\_________PVK!````````@```'("``#\_________SFK!```````
-M"P````$```!@B`0``````$FK!````````@```*`"``#\_________U:K!```
-M`````@```&T"``#\_________V.K!````````@```(T"``#\_________W6K
-M!````````@```,4"``#\_________Y^K!```````"P````$```#`6@0`````
-M`,NK!```````"P````$```!@B`0``````-NK!````````@```*`"``#\____
-M_____^BK!````````@```&T"``#\__________2K!```````"P````$```!0
-M5P0``````+RL!````````@```%\"``#\_________^>L!````````@```(T"
-M``#\__________NL!````````@```,@"``#\_________T:M!````````@``
-M`&`"``#\_________U.M!````````@```%\"``#\_________\JM!```````
-M`@```'("``#\_________^6M!````````@```%T"``#\_________P^N!```
-M`````@```$X"``#\_________R>N!````````@```%T"``#\_________VBN
-M!````````@```$X"``#\_________YZN!```````"P````$````P<`0`````
-M`-&N!````````@```'("``#\__________BN!```````"P````$```!02P0`
-M`````!ZP!```````"P````$```!02P0``````"^P!````````@```)4"``#\
-M_________VJP!```````"P````$```!02P0``````*ZP!````````@```(D"
-M``#\_________P2Q!````````@```,@"``#\_________PRQ!````````@``
-M`(T"``#\_________R.Q!```````"P````$```!02P0``````-6R!```````
-M`@```(8"``#\_________^*R!````````@```,L"``#\_________\*S!```
-M`````@```'("``#\_________RBT!````````@```*P"``#\_________V6T
-M!```````"P````$```!02P0``````#*U!````````@```%4"``#\________
-M_RRV!````````@```%L"``#\_________UJX!````````@```(8"``#\____
-M_____V>X!````````@```,L"``#\_________]2X!````````@```%X"``#\
-M_________^BX!````````@```'("``#\__________^X!````````@```+,"
-M``#\_________P>Y!````````@```%X"``#\_________Q6Y!```````"P``
-M``$```!02P0``````'>Y!````````@```*,"``#\_________^2Y!```````
-M"P````$````0Y`0``````!BZ!````````@```'("``#\_________P>[!```
-M````"P````$```"PN00``````#6[!````````@```,<"``#\_________WR\
-M!```````"P````$```!02P0``````,*\!````````@```*8"``#\________
-M_^J\!```````"P````$```#`R@0``````"&]!````````@```(D"``#\____
-M_____\*^!```````"P````4```"`#````````,F^!````````@```*\"``#\
-M_________PG!!````````@```&H"``#\_________S;!!````````@```+("
-M``#\_________Z+"!```````"P````$```#@Z@0``````'W#!```````"P``
-M``$```!02P0```````7$!````````@```+("``#\_________QS$!```````
-M`@```*8"``#\_________X#$!````````@```(P"``#\_________QK%!```
-M````"P````$```"PRP0``````.?%!```````"P````$```"PRP0``````#7&
-M!```````"P````$```#@Z@0``````'W&!````````@```*,"``#\________
-M_Y3&!```````"P````$```!02P0``````+;&!````````@```*,"``#\____
-M_____\+&!````````@```(D"``#\_________U7'!````````@```'("``#\
-M_________Z3'!````````@```'("``#\_________R3(!````````@```'("
-M``#\_________Z7(!````````@```'("``#\__________3(!````````@``
-M`'("``#\_________W3)!````````@```'("``#\_________P?*!```````
-M`@```'H"``#\_________Q[*!````````@```)P"``#\_________Y7*!```
-M`````@```+$"``#\_________RO+!````````@```*,"``#\_________SO+
-M!````````@```(D"``#\_________T/+!```````"P````$```!02P0`````
-M`/#+!````````@```*,"``#\_________P',!````````@```(D"``#\____
-M_____PG,!```````"P````$```!02P0``````);,!````````@```&T"``#\
-M__________/,!````````@```'("``#\___________,!````````@```'("
-M``#\_________R_-!````````@```,0"``#\_________Z/-!````````@``
-M`,0"``#\_________\+.!````````@```'("``#\_________^W.!```````
-M`@```,0"``#\_________P3/!```````"P````$```!02P0``````(G/!```
-M`````@```'("``#\_________]#/!````````@```'("``#\_________]C/
-M!````````@```+,"``#\__________G/!```````"P````$```!02P0`````
-M`$70!````````@```'("``#\_________Q?1!````````@```(D"``#\____
-M_____R?1!```````"P````$```!02P0``````#C1!````````@```)4"``#\
-M_________Q32!````````@```$D"``#\_________V_2!````````@```)0"
-M``#\_________W[2!````````@```)0"``#\_________X/2!````````@``
-M`,P"``#\_________^G2!````````@```%P"``#\_________S33!```````
-M`@```)0"``#\_________WS3!```````"P````$```!02P0``````!;4!```
-M````"P````$```#PU`0``````"#4!````````@```%H"``#\_________W'4
-M!```````"P````$```!02P0``````(+4!````````@```)4"``#\________
-M_[34!```````"P````$```#@U`0``````,W4!````````@```-`"``#\____
-M_____R+5!````````@```&0"``#\_________S35!````````@```+4"``#[
-M_________T35!````````@```&T"``#\_________Z+5!```````"P````$`
-M``#@U`0``````-K5!````````@```*,"``#\__________K5!````````@``
-M`*,"``#\_________P?6!````````@```%X"``#\_________T#6!```````
-M`@```'("``#\_________TO6!````````@```'("``#\_________U;6!```
-M`````@```&@"``#\_________VO6!```````"P````$```!02P0``````*36
-M!````````@```&("``#[_________^'6!````````@```&("``#\________
-M_^;6!````````@```'0"``#\_________P/7!```````"P```%@"````````
-M`````&W7!````````@```(8"``#\_________YC7!```````"P````$```!0
-M2P0``````*G7!````````@```)4"``#\__________?7!```````"P````$`
-M``!02P0``````(/8!````````@```'("``#\_________^78!````````@``
-M`*P"``#\_________Q;9!```````"P````$```!02P0``````+39!```````
-M`@```%4"``#\_________Z[:!````````@```%L"``#\_________VK;!```
-M`````@```'("``#\_________\O;!```````"P````$```!02P0``````$#<
-M!````````@```%4"``#\_________TK=!````````@```'("``#\________
-M_ZK=!```````"P````$```!02P0``````![>!````````@```%4"``#\____
-M_____PK?!````````@```)0"``#\_________UO?!```````"P````$```!0
-M2P0``````&S?!````````@```)4"``#\_________WS?!````````@```'("
-M``#\_________\3?!````````@```&D"``#\_________[+@!````````@``
-M`(T"``#\_________]/@!```````"P````,````0*````````$KB!```````
-M"P````$````P<`0``````'+B!````````@```'("``#\_________R[C!```
-M`````@```(T"``#\_________S;C!```````"P````$```!02P0``````'SC
-M!````````@```'("``#\_________Z[C!````````@```(8"``#\________
-M_]SC!```````"P````$```!02P0``````._C!````````@```)4"``#\____
-M_____TGD!````````@```*8"``#\_________UOD!````````@```(P"``#\
-M_________T'E!```````"P````$```"`Y@0``````$SE!```````"P````$`
-M``"@,`0``````!'F!````````@```)D"``#\_________R_F!```````"P``
-M``$```!02P0``````-/F!```````"P````$```"@Z@0``````''H!```````
-M`@```(D"``#\_________XWH!```````"P````$```!02P0``````#KI!```
-M`````@```(D"``#\_________VGI!````````@```)D"``#\_________\KI
-M!````````@```(D"``#\_________UOJ!````````@```)D"``#\________
-M_VWJ!````````@```)D"``#\_________VWK!````````@```(D"``#\____
-M_____\_K!````````@```*,"``#\_________^CK!````````@```'("``#\
-M_________R#L!````````@```&4"``#\_________S_L!```````"P````$`
-M``!02P0``````"7M!```````"P````$```!02P0``````#;M!````````@``
-M`)4"``#\_________T/M!````````@```&T"``#\_________U[M!```````
-M"P````$````@5P0``````(Q-!````````@```*L"``#\_________U9.!```
-M`````@```*L"``#\_________P=/!````````@```*<"``#\_________V-1
-M!````````@```*<"``#\_________^E1!````````@```*$"``#\________
-M_QU2!````````@```-`"``#\_________UU2!````````@```-`"``#\____
-M_____YU2!````````@```-`"``#\_________]U2!````````@```-`"``#\
-M_________QU3!````````@```-`"``#\_________UU3!````````@```-`"
-M``#\_________YU3!````````@```-`"``#\_________]U3!````````@``
-M`-`"``#\_________QU4!````````@```-`"``#\_________UU4!```````
-M`@```-`"``#\_________YU4!````````@```-`"``#\_________]U4!```
-M`````@```-`"``#\_________QU5!````````@```-`"``#\_________UU5
-M!````````@```-`"``#\_________YU5!````````@```-`"``#\________
-M_]U5!````````@```-`"``#\_________QU6!````````@```-`"``#\____
-M_____UU6!````````@```-`"``#\_________YU6!````````@```-`"``#\
-M_________]U6!````````@```-`"``#\_________Q!7!````````@```-`"
-M``#\_________T17!````````@```-`"``#\_________Z57!````````@``
-M`-`"``#\__________17!````````@```*L"``#\_________R]8!```````
-M`@```-`"``#\_________S18!````````@```(D"``#\__________Y8!```
-M`````@```*L"``#\_________U%9!````````@```(D"``#\_________[E:
-M!````````@```-`"``#\_________]=;!````````@```-`"``#\________
-M_UA<!````````@```*L"``#\_________WM=!````````@```)4"``#\____
-M_____\5>!````````@```)4"``#\_________Q5?!````````@```)4"``#\
-M_________ZMA!````````@```)4"``#\_________QMC!````````@```)4"
-M``#\_________\-C!````````@```)4"``#\_________R1E!````````@``
-M`)4"``#\_________]AE!````````@```)4"``#\_________V1F!```````
-M`@```)4"``#\_________SMG!````````@```)4"``#\__________]L!```
-M`````@```)4"``#\_________PEN!````````@```)4"``#\_________UUN
-M!````````@```)4"``#\_________^!N!````````@```-`"``#\________
-M_U=O!````````@```)4"``#\_________P9Q!````````@```)4"``#\____
-M_____X)Q!````````@```*L"``#\_________\MQ!````````@```-`"``#\
-M_________]MQ!````````@```$@"``#\_________ZMX!````````@```*L"
-M``#\_________WMZ!````````@```)4"``#\_________\1Z!````````@``
-M`(D"``#\__________A[!````````@```*L"``#\_________UE\!```````
-M`@```)4"``#\_________X9]!````````@```)4"``#\__________*$!```
-M`````@```*L"``#\_________S6%!````````@```)4"``#\_________W*%
-M!````````@```)4"``#\_________P2&!````````@```*`"``#\________
-M_X*'!````````@```&T"``#\_________[:'!````````@```&T"``#\____
-M_____QN(!````````@```&T"``#\_________UF(!````````@```&T"``#\
-M__________*(!````````@```*$"``#\_________Q6*!````````@```*`"
-M``#\_________\&*!````````@```&T"``#\_________SJ+!````````@``
-M`&T"``#\_________YB+!````````@```)4"``#\_________TB7!```````
-M`@```)4"``#\_________RF<!````````@```)4"``#\_________WJ>!```
-M`````@```)4"``#\_________QFO!````````@```)4"``#\_________XFP
-M!````````@```)4"``#\_________T2Q!````````@```)4"``#\________
-M_YBT!````````@```)4"``#\_________SBY!````````@```)4"``#\____
-M_____Z"Y!````````@```%0"``#\_________PRZ!````````@```($"``#\
-M_________[*\!````````@```)4"``#\_________\C`!````````@```*L"
-M``#\__________7"!````````@```($"``#\_________[/#!````````@``
-M`)4"``#\_________W#&!````````@```($"``#\_________RO'!```````
-M`@```*L"``#\_________[7*!````````@```),"``#\_________V++!```
-M`````@```)4"``#\_________RC,!````````@```)4"``#\_________R7/
-M!````````@```)4"``#\_________R30!````````@```)4"``#\________
-M_Y;3!````````@```)4"``#\_________^'4!````````@```$L"``#\____
-M_____]'5!````````@```-`"``#\_________Y/6!````````@```)4"``#\
-M_________QW7!````````@```)T"``#\_________Q;8!````````@```)4"
-M``#\_________SW9!````````@```)4"``#\_________^S;!````````@``
-M`)4"``#\_________\O=!````````@```)4"``#\_________U/C!```````
-M`@```)4"``#\_________U#F!````````@```)4"``#\_________V+F!```
-M`````@```*L"``#\__________SF!````````@```-`"``#\_________[CH
-M!````````@```)4"``#\__________'I!````````@```*L"``#\________
-M_]?J!````````@```*L"``#\_________Q[K!````````@```*L"``#\____
-M_____W3L!````````@```)4"``#\_________Y#M!````````@```)4"``#\
-M_________P;P!````````@```'$"``#\_________TGR!```````"P````$`
-M````]@0``````(KR!````````@```(\"``#\_________]+R!```````"P``
-M``$```!P\`0``````-WR!```````"P````$`````]@0``````(;T!```````
-M`@```'L"``#\_________W+U!````````@```(\"``#\_________\3U!```
-M````"P```',"`````````````-'U!````````@```,<"``#\_________TSV
-M!````````@```*,"``#\_________W_X!```````"P```',"````````````
-M`(SX!````````@```,<"``#\_________Z#X!````````@```',"``#\____
-M_____UCY!````````@```,H"``#\_________X/Y!````````@```-`"``#\
-M_________R;Z!````````@```*L"``#\_________TCZ!````````@```$\"
-M``#\_________X#Z!````````@```*L"``#\_________Y7O!````````@``
-M`-`"``#\_________^CO!````````@```-`"``#\_________T[P!```````
-M`@```)D"``#\_________Y?S!````````@```*L"``#\_________^;U!```
-M`````@```',"``#\_________VWV!````````@```,H"``#\_________]7V
-M!````````@```*L"``#\_________WOZ!````````@```*<"``#\________
-M_^+Z!````````@```&H"``#\_________S;]!````````@```'4"``#\____
-M_____V?]!````````@```'4"``#\_________WC]!````````@```'4"``#\
-M_________P7^!````````@```%("``#\_________P3_!````````@```%<"
-M``#\__________X`!0```````@```&T"``#\_________R<!!0```````@``
-M`%T"``#\_________[\!!0```````@```(T"``#\_________VX$!0``````
-M`@```&L"``#\_________WL$!0```````@```&8"``#\_________Y@$!0``
-M`````@```&$"``#\_________\T$!0```````@```&$"``#\_________^0$
-M!0```````@```&D"``#\_________X`%!0```````@```(T"``#\________
-M_[$%!0```````@```'L"``#\_________\\%!0```````@```'L"``#\____
-M_____^$%!0```````@```'L"``#\__________$%!0```````@```(T"``#\
-M__________D%!0```````@```(T"``#\_________U(&!0``````"P````,`
-M``!`*````````,8&!0```````@```(L"``#\_________Q4'!0```````@``
-M`&\"``#\_________VL'!0```````@```%0"``#\_________P`(!0``````
-M`@```(T"``#\_________]0(!0```````@```*T"``#\_________P8)!0``
-M`````@```%T"``#\_________Q8)!0```````@```(L"``#\_________S<)
-M!0```````@```(H"``#\_________P<+!0```````@```&$"``#\________
-M_RX+!0```````@```&$"``#\_________SX+!0```````@```&L"``#\____
-M_____\H+!0```````@```&$"``#\_________^0+!0```````@```&L"``#\
-M_________P4,!0```````@```&8"``#\_________R$,!0```````@```&8"
-M``#\_________QL/!0```````@```-4"``#\_________W$/!0```````@``
-M`-4"``#\_________[X/!0```````@```-4"``#\_________WH0!0``````
-M`@```&L"``#\_________Y00!0```````@```&$"``#\_________YP0!0``
-M`````@```&L"``#\__________X0!0```````@```&H"``#\_________Q81
-M!0```````@```*T"``#\_________S<1!0```````@```+("``#\________
-M_[D1!0```````@```&H"``#\_________]D1!0```````@```&L"``#\____
-M_____Z(2!0```````@```-4"``#\_________UH4!0```````@```+,"``#\
-M_________W<4!0```````@```*T"``#\_________X$4!0```````@```(T"
-M``#\_________[D4!0```````@```(L"``#\_________PW_!````````@``
-M`&\"``#\_________QD!!0```````@```&\"``#\_________R$(!0``````
-M`@```*T"``#\_________VP3!0```````@```+,"``#\_________^,4!0``
-M`````@```$P"``#\_________P45!0```````@```*H"``#\_________R$5
-M!0```````@```*H"``#\_________\X6!0``````"P````$```"`%04`````
-M`.D6!0```````@```-`"``#\_________R$7!0```````@```),"``#\____
-M_____V@7!0```````@```-("``#\_________W@7!0```````@```+T"``#\
-M_________P`$`````````0````$```#`'`````````@$`````````0````$`
-M``#R'````````!`$`````````0````$```!\'0```````!@$`````````0``
-M``$```!\'0```````"`$`````````0````$```!\'0```````"@$````````
-M`0````$```!\'0```````#`$`````````0````$````D'0```````#@$````
-M`````0````$```!0'0```````$`$`````````0````$```!\'0```````$@$
-M`````````0````$```"1'0```````%`$`````````0````$````S)P``````
-M`%@$`````````0````$````^)P```````&`$`````````0````$````^)P``
-M`````&@$`````````0````$````^)P```````'`$`````````0````$````^
-M)P```````'@$`````````0````$````^)P```````(`$`````````0````$`
-M```^)P```````(@$`````````0````$````^)P```````)`$`````````0``
-M``$````^)P```````)@$`````````0````$````^)P```````*`$````````
-M`0````$````^)P```````*@$`````````0````$````^)P```````+`$````
-M`````0````$````^)P```````+@$`````````0````$````^)P```````,`$
-M`````````0````$````^)P```````,@$`````````0````$````^)P``````
-M`-`$`````````0````$````^)P```````-@$`````````0````$````^)P``
-M`````.`$`````````0````$````^)P```````.@$`````````0````$````^
-M)P```````/`$`````````0````$````^)P```````/@$`````````0````$`
-M```^)P`````````%`````````0````$````^)P````````@%`````````0``
-M``$````^)P```````!`%`````````0````$````^)P```````!@%````````
-M`0````$````^)P```````"`%`````````0````$````^)P```````"@%````
-M`````0````$````^)P```````#`%`````````0````$````^)P```````#@%
-M`````````0````$````^)P```````$`%`````````0````$````^)P``````
-M`$@%`````````0````$````^)P```````%`%`````````0````$````^)P``
-M`````%@%`````````0````$````^)P```````&`%`````````0````$````^
-M)P```````&@%`````````0````$````^)P```````'`%`````````0````$`
-M```()P```````'@%`````````0````$````^)P```````(`%`````````0``
-M``$````()P```````(@%`````````0````$````^)P```````)`%````````
-M`0````$````^)P```````)@%`````````0````$````^)P```````*`%````
-M`````0````$````()P```````*@%`````````0````$````()P```````+`%
-M`````````0````$````^)P```````+@%`````````0````$````^)P``````
-M`,`%`````````0````$````^)P```````,@%`````````0````$````^)P``
-M`````-`%`````````0````$````^)P```````-@%`````````0````$````^
-M)P```````.`%`````````0````$````^)P```````.@%`````````0````$`
-M```^)P```````/`%`````````0````$````^)P```````/@%`````````0``
-M``$````^)P`````````&`````````0````$````^)P````````@&````````
-M`0````$````^)P```````!`&`````````0````$````^)P```````!@&````
-M`````0````$````^)P```````"`&`````````0````$````^)P```````"@&
-M`````````0````$````^)P```````#`&`````````0````$````^)P``````
-M`#@&`````````0````$````()P```````$`&`````````0````$````^)P``
-M`````$@&`````````0````$````^)P```````%`&`````````0````$````^
-M)P```````%@&`````````0````$````^)P```````&`&`````````0````$`
-M```^)P```````&@&`````````0````$````^)P```````'`&`````````0``
-M``$````^)P```````'@&`````````0````$````^)P```````(`&````````
-M`0````$````^)P```````(@&`````````0````$````^)P```````)`&````
-M`````0````$````^)P```````)@&`````````0````$````^)P```````*`&
-M`````````0````$````^)P```````*@&`````````0````$````^)P``````
-M`+`&`````````0````$````()P```````+@&`````````0````$````()P``
-M`````,`&`````````0````$````()P```````,@&`````````0````$````(
-M)P```````-`&`````````0````$````^)P```````-@&`````````0````$`
-M```^)P```````.`&`````````0````$````^)P```````.@&`````````0``
-M``$````^)P```````/`&`````````0````$````^)P```````/@&````````
-M`0````$````^)P`````````'`````````0````$````^)P````````@'````
-M`````0````$````^)P```````!`'`````````0````$````^)P```````!@'
-M`````````0````$````^)P```````"`'`````````0````$````^)P``````
-M`"@'`````````0````$````^)P```````#`'`````````0````$````^)P``
-M`````#@'`````````0````$````^)P```````$`'`````````0````$````^
-M)P```````$@'`````````0````$````^)P```````%`'`````````0````$`
-M```^)P```````%@'`````````0````$````^)P```````&`'`````````0``
-M``$````^)P```````&@'`````````0````$````^)P```````'`'````````
-M`0````$````^)P```````'@'`````````0````$````^)P```````(`'````
-M`````0````$````^)P```````(@'`````````0````$````^)P```````)`'
-M`````````0````$````^)P```````)@'`````````0````$````^)P``````
-M`*`'`````````0````$````^)P```````*@'`````````0````$````^)P``
-M`````+`'`````````0````$````^)P```````+@'`````````0````$````^
-M)P```````,`'`````````0````$````^)P```````,@'`````````0````$`
-M```^)P```````-`'`````````0````$````^)P```````-@'`````````0``
-M``$````^)P```````.`'`````````0````$````^)P```````.@'````````
-M`0````$````^)P```````/`'`````````0````$````^)P```````/@'````
-M`````0````$````^)P`````````(`````````0````$````^)P````````@(
-M`````````0````$````^)P```````!`(`````````0````$````^)P``````
-M`!@(`````````0````$````^)P```````"`(`````````0````$````^)P``
-M`````"@(`````````0````$````()P```````#`(`````````0````$````^
-M)P```````#@(`````````0````$````^)P```````$`(`````````0````$`
-M```^)P```````$@(`````````0````$````^)P```````%`(`````````0``
-M``$````^)P```````%@(`````````0````$````^)P```````&`(````````
-M`0````$````^)P```````&@(`````````0````$````^)P```````'`(````
-M`````0````$````()P```````'@(`````````0````$````^)P```````(`(
-M`````````0````$````()P```````(@(`````````0````$````^)P``````
-M`)`(`````````0````$````^)P```````)@(`````````0````$````^)P``
-M`````*`(`````````0````$````()P```````*@(`````````0````$````(
-M)P```````+`(`````````0````$````^)P```````+@(`````````0````$`
-M```^)P```````,`(`````````0````$````^)P```````,@(`````````0``
-M``$````()P```````-`(`````````0````$````^)P```````-@(````````
-M`0````$````^)P```````.`(`````````0````$````^)P```````.@(````
-M`````0````$````^)P```````/`(`````````0````$````^)P```````/@(
-M`````````0````$````^)P`````````)`````````0````$````^)P``````
-M``@)`````````0````$````^)P```````!`)`````````0````$````^)P``
-M`````!@)`````````0````$````^)P```````"`)`````````0````$````^
-M)P```````"@)`````````0````$````^)P```````#`)`````````0````$`
-M```^)P```````#@)`````````0````$````^)P```````$`)`````````0``
-M``$````^)P```````$@)`````````0````$````^)P```````%`)````````
-M`0````$````^)P```````%@)`````````0````$````^)P```````&`)````
-M`````0````$````^)P```````&@)`````````0````$````^)P```````'`)
-M`````````0````$````()P```````'@)`````````0````$````^)P``````
-M`(`)`````````0````$````()P```````(@)`````````0````$````^)P``
-M`````)`)`````````0````$````^)P```````)@)`````````0````$````^
-M)P```````*`)`````````0````$````()P```````*@)`````````0````$`
-M```()P```````+`)`````````0````$```"4/````````+@)`````````0``
-M``$```!$/````````,`)`````````0````$```!1/````````,@)````````
-M`0````$```!V/````````-`)`````````0````$```"4/````````-@)````
-M`````0````$```"*/````````.`)`````````0````$```"`/````````.@)
-M`````````0````$```"4/````````/`)`````````0````$```"4/```````
-M`/@)`````````0````$```"4/``````````*`````````0````$```"4/```
-M``````@*`````````0````$```"`/````````!`*`````````0````$```!I
-M90```````!@*`````````0````$```"%90```````"`*`````````0````$`
-M``"A90```````"@*`````````0````$```#W90```````#`*`````````0``
-M``$```!A9@```````$`*`````````0````$````WJ@```````$@*````````
-M`0````$````1J@```````%`*`````````0````$````7J@```````%@*````
-M`````0````$```!!J@```````&`*`````````0````$````'J@```````&@*
-M`````````0````$````'J@```````'`*`````````0````$````'J@``````
-M`'@*`````````0````$````'J@```````(`*`````````0````$````'J@``
-M`````(@*`````````0````$````'J@```````)`*`````````0````$````'
-MJ@```````)@*`````````0````$````'J@```````*`*`````````0````$`
-M```'J@```````*@*`````````0````$````'J@```````+`*`````````0``
-M``$````'J@```````+@*`````````0````$````'J@```````,`*````````
-M`0````$```!'J@```````,@*`````````0````$```!!J@```````-`*````
-M`````0````$````AJ@```````-@*`````````0````$````WJ@```````.`*
-M`````````0````$````GJ@```````.@*`````````0````$````QJ@``````
-M`/`*`````````0````$```!'J@```````/@*`````````0````$````!J@``
-M`````(`+`````````0````$```#/(P$``````(@+`````````0````$````Z
-M)`$``````)`+`````````0````$```!6)`$``````)@+`````````0````$`
-M``!R)`$``````*`+`````````0````$```".)`$``````*@+`````````0``
-M``$```"J)`$``````+`+`````````0````$```#+)`$``````+@+````````
-M`0````$```!&)0$``````,`+`````````0````$```!S)0$``````,@+````
-M`````0````$````5)@$``````-`+`````````0````$```#7)0$``````-@+
-M`````````0````$```#S)0$``````.`+`````````0````$````Q)@$`````
-M`.@+`````````0````$```!/)P$``````/`+`````````0````$```!_)P$`
-M`````/@+`````````0````$```"E)P$````````,`````````0````$```#<
-M)P$```````@,`````````0````$```"^*`$``````!`,`````````0````$`
-M```"*`$``````!@,`````````0````$````,*`$``````"`,`````````0``
-M``$```"?)0$``````"@,`````````0````$```"[)0$``````#`,````````
-M`0````$```#M)`$``````#@,`````````0````$````:)0$``````$`,````
-M`````0````$```#7)0$``````$@,`````````0````$````:*`$``````%`,
-M`````````0````$```#N*`$``````%@,`````````0````$````0*0$`````
-M`&`,`````````0````$````L*0$``````&@,`````````0````$```!-*0$`
-M`````'`,`````````0````$```!?*0$``````'@,`````````0````$```""
-M*0$``````(`,`````````0````$```"V*0$``````(@,`````````0````$`
-M```\*`$``````)`,`````````0````$```!>*`$``````)@,`````````0``
-M``$```"`*`$``````*`,`````````0````$```"B*`$``````+`,````````
-M`0````$```##7P$``````+@,`````````0````$```#@50$``````,`,````
-M`````0````$````R5@$``````,@,`````````0````$```"M5@$``````-`,
-M`````````0````$````\5P$``````-@,`````````0````$```!P5P$`````
-M`.`,`````````0````$```"[5P$``````.@,`````````0````$```!16`$`
-M`````/`,`````````0````$```!;6`$``````/@,`````````0````$````N
-M7`$````````-`````````0````$````%6P$```````@-`````````0````$`
-M``#*50$``````!`-`````````0````$```##7P$``````!@-`````````0``
-M``$```##7P$``````"`-`````````0````$```##7P$``````"@-````````
-M`0````$```##7P$``````#`-`````````0````$```##7P$``````#@-````
-M`````0````$````J7P$``````$`-`````````0````$```##7P$``````$@-
-M`````````0````$```##7P$``````%`-`````````0````$```!E6`$`````
-M`%@-`````````0````$```"`6`$``````&`-`````````0````$```#%5P$`
-M`````&@-`````````0````$```!'6`$``````'`-`````````0````$````%
-M6P$``````'@-`````````0````$````>70$``````(`-`````````0````$`
-M``"&7P$``````(@-`````````0````$```"-7P$``````)`-`````````0``
-M``$```"^7P$``````)@-`````````0````$```##7P$``````*`-````````
-M`0````$```!87@$``````*@-`````````0````$```"H7@$``````+`-````
-M`````0````$```"R7@$``````+@-`````````0````$````H70$``````,`-
-M`````````0````$````U70$``````,@-`````````0````$````_70$`````
-M`-`-`````````0````$```!)70$``````-@-`````````0````$```#PB@$`
-M`````.`-`````````0````$```!+B`$``````.@-`````````0````$```!<
-MB`$``````/`-`````````0````$```!MB`$``````/@-`````````0````$`
-M``!^B`$````````.`````````0````$```#*B`$```````@.`````````0``
-M``$```#IB`$``````!`.`````````0````$```#]B`$``````!@.````````
-M`0````$```!2B0$``````"`.`````````0````$```!NB0$``````"@.````
-M`````0````$```"*B0$``````#`.`````````0````$```"FB0$``````#@.
-M`````````0````$```#.B0$``````$`.`````````0````$```#BB0$`````
-M`$@.`````````0````$```#VB0$``````%`.`````````0````$```#PB@$`
-M`````%@.`````````0````$```#PB@$``````&`.`````````0````$````/
-MB@$``````&@.`````````0````$```![B@$``````'`.`````````0````$`
-M``#PB@$``````'@.`````````0````$```#PB@$``````(`.`````````0``
-M``$````WB@$``````(@.`````````0````$```#`B@$``````)`.````````
-M`0````$```"=B`$``````)@.`````````0````$```"QB`$``````*`.````
-M`````0````$```#PB@$``````*@.`````````0````$````1B0$``````+`.
-M`````````0````$````EB0$``````+@.`````````0````$````YB0$`````
-M`,`.`````````0````$```"@O`$``````,@.`````````0````$```"@O`$`
-M`````-`.`````````0````$```#9O`$``````-@.`````````0````$```#L
-MO`$``````.`.`````````0````$```"@O`$``````.@.`````````0````$`
-M```-O0$``````/`.`````````0````$```"JO`$``````/@.`````````0``
-M``$```#_O`$````````/`````````0````$```"VO0$```````@/````````
-M`0````$```#"O0$``````!`/`````````0````$````!QP$``````!@/````
-M`````0````$```!VR`$``````"`/`````````0````$```!VR`$``````"@/
-M`````````0````$```!VR`$``````#`/`````````0````$```!VR`$`````
-M`#@/`````````0````$```!VR`$``````$`/`````````0````$```!VR`$`
-M`````$@/`````````0````$```!VR`$``````%`/`````````0````$```!V
-MR`$``````%@/`````````0````$```!VR`$``````&`/`````````0````$`
-M``!VR`$``````&@/`````````0````$```!VR`$``````'`/`````````0``
-M``$```!VR`$``````'@/`````````0````$```!VR`$``````(`/````````
-M`0````$```!VR`$``````(@/`````````0````$```!VR`$``````)`/````
-M`````0````$```!VR`$``````)@/`````````0````$```!VR`$``````*`/
-M`````````0````$```!VR`$``````*@/`````````0````$```!VR`$`````
-M`+`/`````````0````$```!VR`$``````+@/`````````0````$```!VR`$`
-M`````,`/`````````0````$```!VR`$``````,@/`````````0````$```!V
-MR`$``````-`/`````````0````$```!VR`$``````-@/`````````0````$`
-M``!VR`$``````.`/`````````0````$```!VR`$``````.@/`````````0``
-M``$```!VR`$``````/`/`````````0````$```!VR`$``````/@/````````
-M`0````$```!VR`$````````0`````````0````$```!VR`$```````@0````
-M`````0````$```!VR`$``````!`0`````````0````$````5QP$``````!@0
-M`````````0````$```!PQP$``````"`0`````````0````$```#+QP$`````
-M`"@0`````````0````$````FR`$``````#`0`````````0````$```"+R0$`
-M`````#@0`````````0````$```!7S@$``````$`0`````````0````$```!7
-MS@$``````$@0`````````0````$```!7S@$``````%`0`````````0````$`
-M``!7S@$``````%@0`````````0````$```!7S@$``````&`0`````````0``
-M``$```!7S@$``````&@0`````````0````$```!7S@$``````'`0````````
-M`0````$```!7S@$``````'@0`````````0````$```!7S@$``````(`0````
-M`````0````$```!7S@$``````(@0`````````0````$```!7S@$``````)`0
-M`````````0````$```!7S@$``````)@0`````````0````$```!7S@$`````
-M`*`0`````````0````$```!7S@$``````*@0`````````0````$```!7S@$`
-M`````+`0`````````0````$```"=R0$``````+@0`````````0````$```"=
-MR0$``````,`0`````````0````$```"=R0$``````,@0`````````0````$`
-M``!7S@$``````-`0`````````0````$```!7S@$``````-@0`````````0``
-M``$```!7S@$``````.`0`````````0````$```!7S@$``````.@0````````
-M`0````$```!7S@$``````/`0`````````0````$```!7S@$``````/@0````
-M`````0````$```!7S@$````````1`````````0````$```!7S@$```````@1
-M`````````0````$```!7S@$``````!`1`````````0````$```!7S@$`````
-M`!@1`````````0````$```!7S@$``````"`1`````````0````$```!7S@$`
-M`````"@1`````````0````$```!7S@$``````#`1`````````0````$````#
-MR@$``````#@1`````````0````$```!;R@$``````$`1`````````0````$`
-M``"SR@$``````$@1`````````0````$````,RP$``````%`1`````````0``
-M``$```!7S@$``````%@1`````````0````$```!7S@$``````&`1````````
-M`0````$```!7S@$``````&@1`````````0````$```!7S@$``````'`1````
-M`````0````$```!7S@$``````'@1`````````0````$```!7S@$``````(`1
-M`````````0````$```!7S@$``````(@1`````````0````$```!7S@$`````
-M`)`1`````````0````$```!7S@$``````)@1`````````0````$```!7S@$`
-M`````*`1`````````0````$```!7S@$``````*@1`````````0````$```!7
-MS@$``````+`1`````````0````$```!DRP$``````+@1`````````0````$`
-M``"_RP$``````,`1`````````0````$````;S`$``````,@1`````````0``
-M``$```!SS`$``````-`1`````````0````$```!7S@$``````-@1````````
-M`0````$```!7S@$``````.`1`````````0````$```!7S@$``````.@1````
-M`````0````$```!7S@$``````/`1`````````0````$```!7S@$``````/@1
-M`````````0````$```!7S@$````````2`````````0````$```!7S@$`````
-M``@2`````````0````$```!7S@$``````!`2`````````0````$```!7S@$`
-M`````!@2`````````0````$```!7S@$``````"`2`````````0````$```!7
-MS@$``````"@2`````````0````$```!7S@$``````#`2`````````0````$`
-M``#+S`$``````#@2`````````0````$```!7S@$``````$`2`````````0``
-M``$```!7S@$``````$@2`````````0````$```!7S@$``````%`2````````
-M`0````$```!7S@$``````%@2`````````0````$```!7S@$``````&`2````
-M`````0````$```!7S@$``````&@2`````````0````$```!7S@$``````'`2
-M`````````0````$```!7S@$``````'@2`````````0````$```!7S@$`````
-M`(`2`````````0````$```!7S@$``````(@2`````````0````$```!7S@$`
-M`````)`2`````````0````$```!7S@$``````)@2`````````0````$```!7
-MS@$``````*`2`````````0````$```!7S@$``````*@2`````````0````$`
-M``!7S@$``````+`2`````````0````$````$S0$``````+@2`````````0``
-M``$````^S0$``````,`2`````````0````$```!XS0$``````,@2````````
-M`0````$```"RS0$``````-`2`````````0````$```#IS0$``````-@2````
-M`````0````$````@S@$````````7`````````0````$```!`#0(```````@7
-M`````````0````$```!R#0(``````!`7`````````0````$```#\#0(`````
-M`!@7`````````0````$```#\#0(``````"`7`````````0````$```#\#0(`
-M`````"@7`````````0````$```#\#0(``````#`7`````````0````$```"D
-M#0(``````#@7`````````0````$```#0#0(``````$`7`````````0````$`
-M``#\#0(``````$@7`````````0````$````1#@(``````%`7`````````0``
-M``$```"S%P(``````%@7`````````0````$```"^%P(``````&`7````````
-M`0````$```"^%P(``````&@7`````````0````$```"^%P(``````'`7````
-M`````0````$```"^%P(``````'@7`````````0````$```"^%P(``````(`7
-M`````````0````$```"^%P(``````(@7`````````0````$```"^%P(`````
-M`)`7`````````0````$```"^%P(``````)@7`````````0````$```"^%P(`
-M`````*`7`````````0````$```"^%P(``````*@7`````````0````$```"^
-M%P(``````+`7`````````0````$```"^%P(``````+@7`````````0````$`
-M``"^%P(``````,`7`````````0````$```"^%P(``````,@7`````````0``
-M``$```"^%P(``````-`7`````````0````$```"^%P(``````-@7````````
-M`0````$```"^%P(``````.`7`````````0````$```"^%P(``````.@7````
-M`````0````$```"^%P(``````/`7`````````0````$```"^%P(``````/@7
-M`````````0````$```"^%P(````````8`````````0````$```"^%P(`````
-M``@8`````````0````$```"^%P(``````!`8`````````0````$```"^%P(`
-M`````!@8`````````0````$```"^%P(``````"`8`````````0````$```"^
-M%P(``````"@8`````````0````$```"^%P(``````#`8`````````0````$`
-M``"^%P(``````#@8`````````0````$```"^%P(``````$`8`````````0``
-M``$```"^%P(``````$@8`````````0````$```"^%P(``````%`8````````
-M`0````$```"^%P(``````%@8`````````0````$```"^%P(``````&`8````
-M`````0````$```"^%P(``````&@8`````````0````$```"^%P(``````'`8
-M`````````0````$```"(%P(``````'@8`````````0````$```"^%P(`````
-M`(`8`````````0````$```"(%P(``````(@8`````````0````$```"^%P(`
-M`````)`8`````````0````$```"^%P(``````)@8`````````0````$```"^
-M%P(``````*`8`````````0````$```"(%P(``````*@8`````````0````$`
-M``"(%P(``````+`8`````````0````$```"^%P(``````+@8`````````0``
-M``$```"^%P(``````,`8`````````0````$```"^%P(``````,@8````````
-M`0````$```"^%P(``````-`8`````````0````$```"^%P(``````-@8````
-M`````0````$```"^%P(``````.`8`````````0````$```"^%P(``````.@8
-M`````````0````$```"^%P(``````/`8`````````0````$```"^%P(`````
-M`/@8`````````0````$```"^%P(````````9`````````0````$```"^%P(`
-M``````@9`````````0````$```"^%P(``````!`9`````````0````$```"^
-M%P(``````!@9`````````0````$```"^%P(``````"`9`````````0````$`
-M``"^%P(``````"@9`````````0````$```"^%P(``````#`9`````````0``
-M``$```"^%P(``````#@9`````````0````$```"(%P(``````$`9````````
-M`0````$```"^%P(``````$@9`````````0````$```"^%P(``````%`9````
-M`````0````$```"^%P(``````%@9`````````0````$```"^%P(``````&`9
-M`````````0````$```"^%P(``````&@9`````````0````$```"^%P(`````
-M`'`9`````````0````$```"^%P(``````'@9`````````0````$```"^%P(`
-M`````(`9`````````0````$```"^%P(``````(@9`````````0````$```"^
-M%P(``````)`9`````````0````$```"^%P(``````)@9`````````0````$`
-M``"^%P(``````*`9`````````0````$```"^%P(``````*@9`````````0``
-M``$```"^%P(``````+`9`````````0````$```"(%P(``````+@9````````
-M`0````$```"(%P(``````,`9`````````0````$```"(%P(``````,@9````
-M`````0````$```"(%P(``````-`9`````````0````$```"^%P(``````-@9
-M`````````0````$```"^%P(``````.`9`````````0````$```"^%P(`````
-M`.@9`````````0````$```"^%P(``````/`9`````````0````$```"^%P(`
-M`````/@9`````````0````$```"^%P(````````:`````````0````$```"^
-M%P(```````@:`````````0````$```"^%P(``````!`:`````````0````$`
-M``"^%P(``````!@:`````````0````$```"^%P(``````"`:`````````0``
-M``$```"^%P(``````"@:`````````0````$```"^%P(``````#`:````````
-M`0````$```"^%P(``````#@:`````````0````$```"^%P(``````$`:````
-M`````0````$```"^%P(``````$@:`````````0````$```"^%P(``````%`:
-M`````````0````$```"^%P(``````%@:`````````0````$```"^%P(`````
-M`&`:`````````0````$```"^%P(``````&@:`````````0````$```"^%P(`
-M`````'`:`````````0````$```"^%P(``````'@:`````````0````$```"^
-M%P(``````(`:`````````0````$```"^%P(``````(@:`````````0````$`
-M``"^%P(``````)`:`````````0````$```"^%P(``````)@:`````````0``
-M``$```"^%P(``````*`:`````````0````$```"^%P(``````*@:````````
-M`0````$```"^%P(``````+`:`````````0````$```"^%P(``````+@:````
-M`````0````$```"^%P(``````,`:`````````0````$```"^%P(``````,@:
-M`````````0````$```"^%P(``````-`:`````````0````$```"^%P(`````
-M`-@:`````````0````$```"^%P(``````.`:`````````0````$```"^%P(`
-M`````.@:`````````0````$```"^%P(``````/`:`````````0````$```"^
-M%P(``````/@:`````````0````$```"^%P(````````;`````````0````$`
-M``"^%P(```````@;`````````0````$```"^%P(``````!`;`````````0``
-M``$```"^%P(``````!@;`````````0````$```"^%P(``````"`;````````
-M`0````$```"^%P(``````"@;`````````0````$```"(%P(``````#`;````
-M`````0````$```"^%P(``````#@;`````````0````$```"^%P(``````$`;
-M`````````0````$```"^%P(``````$@;`````````0````$```"^%P(`````
-M`%`;`````````0````$```"^%P(``````%@;`````````0````$```"^%P(`
-M`````&`;`````````0````$```"^%P(``````&@;`````````0````$```"^
-M%P(``````'`;`````````0````$```"(%P(``````'@;`````````0````$`
-M``"^%P(``````(`;`````````0````$```"(%P(``````(@;`````````0``
-M``$```"^%P(``````)`;`````````0````$```"^%P(``````)@;````````
-M`0````$```"^%P(``````*`;`````````0````$```"(%P(``````*@;````
-M`````0````$```"(%P(``````+`;`````````0````$```"^%P(``````+@;
-M`````````0````$```"^%P(``````,`;`````````0````$```"^%P(`````
-M`,@;`````````0````$```"(%P(``````-`;`````````0````$```"^%P(`
-M`````-@;`````````0````$```"^%P(``````.`;`````````0````$```"^
-M%P(``````.@;`````````0````$```"^%P(``````/`;`````````0````$`
-M``"^%P(``````/@;`````````0````$```"^%P(````````<`````````0``
-M``$```"^%P(```````@<`````````0````$```"^%P(``````!`<````````
-M`0````$```"^%P(``````!@<`````````0````$```"^%P(``````"`<````
-M`````0````$```"^%P(``````"@<`````````0````$```"^%P(``````#`<
-M`````````0````$```"^%P(``````#@<`````````0````$```"^%P(`````
-M`$`<`````````0````$```"^%P(``````$@<`````````0````$```"^%P(`
-M`````%`<`````````0````$```"^%P(``````%@<`````````0````$```"^
-M%P(``````&`<`````````0````$```"^%P(``````&@<`````````0````$`
-M``"^%P(``````'`<`````````0````$```"(%P(``````'@<`````````0``
-M``$```"^%P(``````(`<`````````0````$```"(%P(``````(@<````````
-M`0````$```"^%P(``````)`<`````````0````$```"^%P(``````)@<````
-M`````0````$```"^%P(``````*`<`````````0````$```"(%P(``````*@<
-M`````````0````$```"(%P(``````+`<`````````0````$````4+0(`````
-M`+@<`````````0````$```#$+`(``````,`<`````````0````$```#1+`(`
-M`````,@<`````````0````$```#V+`(``````-`<`````````0````$````4
-M+0(``````-@<`````````0````$````*+0(``````.`<`````````0````$`
-M````+0(``````.@<`````````0````$````4+0(``````/`<`````````0``
-M``$````4+0(``````/@<`````````0````$````4+0(````````=````````
-M`0````$````4+0(```````@=`````````0````$`````+0(``````!`=````
-M`````0````$```#)50(``````!@=`````````0````$```#E50(``````"`=
-M`````````0````$````!5@(``````"@=`````````0````$```!75@(`````
-M`#`=`````````0````$```#!5@(``````$`=`````````0````$````'F@(`
-M`````$@=`````````0````$```#AF0(``````%`=`````````0````$```#G
-MF0(``````%@=`````````0````$````1F@(``````&`=`````````0````$`
-M``#7F0(``````&@=`````````0````$```#7F0(``````'`=`````````0``
-M``$```#7F0(``````'@=`````````0````$```#7F0(``````(`=````````
-M`0````$```#7F0(``````(@=`````````0````$```#7F0(``````)`=````
-M`````0````$```#7F0(``````)@=`````````0````$```#7F0(``````*`=
-M`````````0````$```#7F0(``````*@=`````````0````$```#7F0(`````
-M`+`=`````````0````$```#7F0(``````+@=`````````0````$```#7F0(`
-M`````,`=`````````0````$````7F@(``````,@=`````````0````$````1
-MF@(``````-`=`````````0````$```#QF0(``````-@=`````````0````$`
-M```'F@(``````.`=`````````0````$```#WF0(``````.@=`````````0``
-M``$````!F@(``````/`=`````````0````$````7F@(``````/@=````````
-M`0````$```#1F0(``````(`>`````````0````$```"?$P,``````(@>````
-M`````0````$````*%`,``````)`>`````````0````$````F%`,``````)@>
-M`````````0````$```!"%`,``````*`>`````````0````$```!>%`,`````
-M`*@>`````````0````$```!Z%`,``````+`>`````````0````$```";%`,`
-M`````+@>`````````0````$````6%0,``````,`>`````````0````$```!#
-M%0,``````,@>`````````0````$```#E%0,``````-`>`````````0````$`
-M``"G%0,``````-@>`````````0````$```##%0,``````.`>`````````0``
-M``$````!%@,``````.@>`````````0````$````?%P,``````/`>````````
-M`0````$```!/%P,``````/@>`````````0````$```!U%P,````````?````
-M`````0````$```"L%P,```````@?`````````0````$```".&`,``````!`?
-M`````````0````$```#2%P,``````!@?`````````0````$```#<%P,`````
-M`"`?`````````0````$```!O%0,``````"@?`````````0````$```"+%0,`
-M`````#`?`````````0````$```"]%`,``````#@?`````````0````$```#J
-M%`,``````$`?`````````0````$```"G%0,``````$@?`````````0````$`
-M``#J%P,``````%`?`````````0````$```"^&`,``````%@?`````````0``
-M``$```#@&`,``````&`?`````````0````$```#\&`,``````&@?````````
-M`0````$````=&0,``````'`?`````````0````$````O&0,``````'@?````
-M`````0````$```!2&0,``````(`?`````````0````$```"&&0,``````(@?
-M`````````0````$````,&`,``````)`?`````````0````$````N&`,`````
-M`)@?`````````0````$```!0&`,``````*`?`````````0````$```!R&`,`
-M`````+`?`````````0````$```"#3P,``````+@?`````````0````$```"P
-M10,``````,`?`````````0````$````"1@,``````,@?`````````0````$`
-M``"01@,``````-`?`````````0````$````<1P,``````-@?`````````0``
-M``$```!01P,``````.`?`````````0````$```";1P,``````.@?````````
-M`0````$````Q2`,``````/`?`````````0````$````[2`,``````/@?````
-M`````0````$```#N2P,````````@`````````0````$```#`2@,```````@@
-M`````````0````$```":10,``````!`@`````````0````$```"#3P,`````
-M`!@@`````````0````$```"#3P,``````"`@`````````0````$```"#3P,`
-M`````"@@`````````0````$```"#3P,``````#`@`````````0````$```"#
-M3P,``````#@@`````````0````$```#J3@,``````$`@`````````0````$`
-M``"#3P,``````$@@`````````0````$```"#3P,``````%`@`````````0``
-M``$```!%2`,``````%@@`````````0````$```!@2`,``````&`@````````
-M`0````$```"E1P,``````&@@`````````0````$````G2`,``````'`@````
-M`````0````$```#`2@,``````'@@`````````0````$```#>3`,``````(`@
-M`````````0````$```!&3P,``````(@@`````````0````$```!-3P,`````
-M`)`@`````````0````$```!^3P,``````)@@`````````0````$```"#3P,`
-M`````*`@`````````0````$````83@,``````*@@`````````0````$```!H
-M3@,``````+`@`````````0````$```!R3@,``````+@@`````````0````$`
-M``#H3`,``````,`@`````````0````$```#U3`,``````,@@`````````0``
-M``$```#_3`,``````-`@`````````0````$````)30,``````-@@````````
-M`0````$````B7@,``````.`@`````````0````$````J7@,``````.@@````
-M`````0````$````R7@,``````/`@`````````0````$````Z7@,``````/@@
-M`````````0````$```!"7@,````````A`````````0````$```!*7@,`````
-M``@A`````````0````$```!27@,``````!`A`````````0````$````:7@,`
-M`````!@A`````````0````$```"P>0,``````"`A`````````0````$````+
-M=P,``````"@A`````````0````$````<=P,``````#`A`````````0````$`
-M```M=P,``````#@A`````````0````$````^=P,``````$`A`````````0``
-M``$```"*=P,``````$@A`````````0````$```"I=P,``````%`A````````
-M`0````$```"]=P,``````%@A`````````0````$````2>`,``````&`A````
-M`````0````$````N>`,``````&@A`````````0````$```!*>`,``````'`A
-M`````````0````$```!F>`,``````'@A`````````0````$```".>`,`````
-M`(`A`````````0````$```"B>`,``````(@A`````````0````$```"V>`,`
-M`````)`A`````````0````$```"P>0,``````)@A`````````0````$```"P
-M>0,``````*`A`````````0````$```#/>`,``````*@A`````````0````$`
-M```[>0,``````+`A`````````0````$```"P>0,``````+@A`````````0``
-M``$```"P>0,``````,`A`````````0````$```#W>`,``````,@A````````
-M`0````$```"`>0,``````-`A`````````0````$```!==P,``````-@A````
-M`````0````$```!Q=P,``````.`A`````````0````$```"P>0,``````.@A
-M`````````0````$```#1=P,``````/`A`````````0````$```#E=P,`````
-M`/@A`````````0````$```#Y=P,````````B`````````0````$```"0JP,`
-M``````@B`````````0````$```"0JP,``````!`B`````````0````$```#)
-MJP,``````!@B`````````0````$```#<JP,``````"`B`````````0````$`
-M``"0JP,``````"@B`````````0````$```#]JP,``````#`B`````````0``
-M``$```":JP,``````#@B`````````0````$```#OJP,``````$`B````````
-M`0````$```"FK`,``````$@B`````````0````$```"RK`,``````%`B````
-M`````0````$```!1M@,``````%@B`````````0````$```#&MP,``````&`B
-M`````````0````$```#&MP,``````&@B`````````0````$```#&MP,`````
-M`'`B`````````0````$```#&MP,``````'@B`````````0````$```#&MP,`
-M`````(`B`````````0````$```#&MP,``````(@B`````````0````$```#&
-MMP,``````)`B`````````0````$```#&MP,``````)@B`````````0````$`
-M``#&MP,``````*`B`````````0````$```#&MP,``````*@B`````````0``
-M``$```#&MP,``````+`B`````````0````$```#&MP,``````+@B````````
-M`0````$```#&MP,``````,`B`````````0````$```#&MP,``````,@B````
-M`````0````$```#&MP,``````-`B`````````0````$```#&MP,``````-@B
-M`````````0````$```#&MP,``````.`B`````````0````$```#&MP,`````
-M`.@B`````````0````$```#&MP,``````/`B`````````0````$```#&MP,`
-M`````/@B`````````0````$```#&MP,````````C`````````0````$```#&
-MMP,```````@C`````````0````$```#&MP,``````!`C`````````0````$`
-M``#&MP,``````!@C`````````0````$```#&MP,``````"`C`````````0``
-M``$```#&MP,``````"@C`````````0````$```#&MP,``````#`C````````
-M`0````$```#&MP,``````#@C`````````0````$```#&MP,``````$`C````
-M`````0````$```#&MP,``````$@C`````````0````$```#&MP,``````%`C
-M`````````0````$```!EM@,``````%@C`````````0````$```#`M@,`````
-M`&`C`````````0````$````;MP,``````&@C`````````0````$```!VMP,`
-M`````'`C`````````0````$```#;N`,``````'@C`````````0````$```"G
-MO0,``````(`C`````````0````$```"GO0,``````(@C`````````0````$`
-M``"GO0,``````)`C`````````0````$```"GO0,``````)@C`````````0``
-M``$```"GO0,``````*`C`````````0````$```"GO0,``````*@C````````
-M`0````$```"GO0,``````+`C`````````0````$```"GO0,``````+@C````
-M`````0````$```"GO0,``````,`C`````````0````$```"GO0,``````,@C
-M`````````0````$```"GO0,``````-`C`````````0````$```"GO0,`````
-M`-@C`````````0````$```"GO0,``````.`C`````````0````$```"GO0,`
-M`````.@C`````````0````$```"GO0,``````/`C`````````0````$```#M
-MN`,``````/@C`````````0````$```#MN`,````````D`````````0````$`
-M``#MN`,```````@D`````````0````$```"GO0,``````!`D`````````0``
-M``$```"GO0,``````!@D`````````0````$```"GO0,``````"`D````````
-M`0````$```"GO0,``````"@D`````````0````$```"GO0,``````#`D````
-M`````0````$```"GO0,``````#@D`````````0````$```"GO0,``````$`D
-M`````````0````$```"GO0,``````$@D`````````0````$```"GO0,`````
-M`%`D`````````0````$```"GO0,``````%@D`````````0````$```"GO0,`
-M`````&`D`````````0````$```"GO0,``````&@D`````````0````$```"G
-MO0,``````'`D`````````0````$```!3N0,``````'@D`````````0````$`
-M``"KN0,``````(`D`````````0````$````#N@,``````(@D`````````0``
-M``$```!<N@,``````)`D`````````0````$```"GO0,``````)@D````````
-M`0````$```"GO0,``````*`D`````````0````$```"GO0,``````*@D````
-M`````0````$```"GO0,``````+`D`````````0````$```"GO0,``````+@D
-M`````````0````$```"GO0,``````,`D`````````0````$```"GO0,`````
-M`,@D`````````0````$```"GO0,``````-`D`````````0````$```"GO0,`
-M`````-@D`````````0````$```"GO0,``````.`D`````````0````$```"G
-MO0,``````.@D`````````0````$```"GO0,``````/`D`````````0````$`
-M``"TN@,``````/@D`````````0````$````/NP,````````E`````````0``
-M``$```!KNP,```````@E`````````0````$```##NP,``````!`E````````
-M`0````$```"GO0,``````!@E`````````0````$```"GO0,``````"`E````
-M`````0````$```"GO0,``````"@E`````````0````$```"GO0,``````#`E
-M`````````0````$```"GO0,``````#@E`````````0````$```"GO0,`````
-M`$`E`````````0````$```"GO0,``````$@E`````````0````$```"GO0,`
-M`````%`E`````````0````$```"GO0,``````%@E`````````0````$```"G
-MO0,``````&`E`````````0````$```"GO0,``````&@E`````````0````$`
-M``"GO0,``````'`E`````````0````$````;O`,``````'@E`````````0``
-M``$```"GO0,``````(`E`````````0````$```"GO0,``````(@E````````
-M`0````$```"GO0,``````)`E`````````0````$```"GO0,``````)@E````
-M`````0````$```"GO0,``````*`E`````````0````$```"GO0,``````*@E
-M`````````0````$```"GO0,``````+`E`````````0````$```"GO0,`````
-M`+@E`````````0````$```"GO0,``````,`E`````````0````$```"GO0,`
-M`````,@E`````````0````$```"GO0,``````-`E`````````0````$```"G
-MO0,``````-@E`````````0````$```"GO0,``````.`E`````````0````$`
-M``"GO0,``````.@E`````````0````$```"GO0,``````/`E`````````0``
-M``$```!4O`,``````/@E`````````0````$```".O`,````````F````````
-M`0````$```#(O`,```````@F`````````0````$````"O0,``````!`F````
-M`````0````$````YO0,``````!@F`````````0````$```!PO0,``````%`F
-M`````````0````$```#``P0``````%@F`````````0````$```!?!`0`````
-M`&`F`````````0````$```#Z`P0``````&@F`````````0````$```#>`P0`
-M`````'`F`````````0````$```!?!`0``````'@F`````````0````$```!?
-M!`0``````(`F`````````0````$```!?!`0``````(@F`````````0````$`
-M``!?!`0``````)`F`````````0````$```#``P0``````)@F`````````0``
-M``$````J!00``````*`F`````````0````$```#``P0``````*@F````````
-M`0````$```#``P0``````+`F`````````0````$```!V`P0``````+@F````
-M`````0````$````>!00``````,`F`````````0````$```#L!`0``````,@F
-M`````````0````$```"X!`0``````-`F`````````0````$````#)P0`````
-M`-@F`````````0````$````3)P0``````.`F`````````0````$````;)P0`
-M`````.@F`````````0````$````C)P0``````/`F`````````0````$````K
-M)P0``````/@F`````````0````$````S)P0````````G`````````0````$`
-M```[)P0```````@G`````````0````$````+)P0``````!`G`````````0``
-M``$```"[*P0``````!@G`````````0````$```"3+00``````"`G````````
-M`0````$```#T+`0``````"@G`````````0````$```!J+00``````#`G````
-M`````0````$```!!+00``````#@G`````````0````$```!J+00``````$`G
-M`````````0````$```"[*P0``````$@G`````````0````$```"^*P0`````
-M`%`G`````````0````$```!CBP0``````%@G`````````0````$```#UBP0`
-M`````&`G`````````0````$```#2C`0``````&@G`````````0````$```#^
-MC`0``````'`G`````````0````$```"RC00``````'@G`````````0````$`
-M``"5C@0``````(`G`````````0````$```"NC@0``````(@G`````````0``
-M``$```"ZC@0``````)`G`````````0````$```"SBP0``````)@G````````
-M`0````$````XCP0``````*`G`````````0````$```#UCP0``````*@G````
-M`````0````$```!CBP0``````+`G`````````0````$````&D00``````+@G
-M`````````0````$````.D`0``````,`G`````````0````$```"PD`0`````
-M`,@G`````````0````$```#6GP0``````-`G`````````0````$```!'HP0`
-M`````-@G`````````0````$````0HP0``````.`G`````````0````$```#[
-MH@0``````.@G`````````0````$```#FH@0``````/`G`````````0````$`
-M``#'H@0``````/@G`````````0````$```#6GP0````````H`````````0``
-M``$```"RH@0```````@H`````````0````$````WH`0``````!`H````````
-M`0````$```"EX00``````!@H`````````0````$```"3X00``````"`H````
-M`````0````$```!WX00``````"@H`````````0````$```!6X00``````#`H
-M`````````0````$````4X00``````#@H`````````0````$```#7X`0`````
-M`$`H`````````0````$````X!P4``````$@H`````````0````$```!Q!@4`
-M`````%`H`````````0````$````X!P4``````%@H`````````0````$```!6
-M!@4``````&`H`````````0````$```!6!@4``````&@H`````````0````$`
-M``!6!@4``````(```````````0````8```"K`0```````)@``````````0``
-M``$```#@F`$``````*```````````0````$````0M0$``````*@`````````
-M`0````$````PF0$``````+```````````0````$```"0S@$``````+@`````
-M`````0````$```#0Z@$``````,```````````0````$```#PM`$``````,@`
-M`````````0````$```#0F`$``````-```````````0````$```"`F@$`````
-M`-@``````````0````$````0M`$``````.```````````0````$```!`F0$`
-M`````.@``````````0````$```!0[0$``````/```````````0````$```#P
-MF@$``````/@``````````0````$````0TP$````````!`````````0```"4!
-M``````````````@!`````````0````$`````L0$``````!`!`````````0``
-M``$```!0F0$``````!@!`````````0````$```#PXP$``````"`!````````
-M`0````$```#PJP$``````"@!`````````0````$```!@I0$``````#`!````
-M`````0````$```"PHP$``````#@!`````````0````$```"0FP$``````$`!
-M`````````0````$```!PO`$``````$@!`````````0````$```"PFP$`````
-M`%`!`````````0````$```!`I0$``````%@!`````````0````$````@I0$`
-M`````&`!`````````0````$`````I`$``````&@!`````````0````$```!P
-MG0$``````'`!`````````0````$```"0G`$``````'@!`````````0```$8`
-M`````````````(@!`````````0````$`````FP$``````)`!`````````0``
-M``$```"0X0$``````)@!`````````0````$```"0W0$``````*`!````````
-M`0````$```!PV0$``````*@!`````````0````$```!@U0$``````+`!````
-M`````0```-@``````````````"`"`````````0````8```!;`P```````#@"
-M`````````0````$```"@AP,``````$`"`````````0````$````0I`,`````
-M`$@"`````````0````$```#PAP,``````%`"`````````0````$```#@O0,`
-M`````%@"`````````0````$````@V@,``````&`"`````````0````$```#P
-MHP,``````&@"`````````0````$```"0AP,``````'`"`````````0````$`
-M``!`B0,``````'@"`````````0````$````0HP,``````(`"`````````0``
-M``$`````B`,``````(@"`````````0````$```"PW`,``````)`"````````
-M`0````$```"PB0,``````)@"`````````0````$```!@P@,``````*`"````
-M`````0```#L!`````````````*@"`````````0````$`````H`,``````+`"
-M`````````0````$````0B`,``````+@"`````````0````$```!`TP,`````
-M`,`"`````````0````$```#PF@,``````,@"`````````0````$```!@E`,`
-M`````-`"`````````0````$```#0DP,``````-@"`````````0````$```!`
-MBP,``````.`"`````````0````$```!@JP,``````.@"`````````0````$`
-M``!@BP,``````/`"`````````0````$```!`E`,``````/@"`````````0``
-M``$````@E`,````````#`````````0````$```!@DP,```````@#````````
-M`0````$````@C0,``````!`#`````````0````$```!`C`,``````!@#````
-M`````0````8"`````````````"@#`````````0````$```#`B0,``````#`#
-M`````````0````$```#@T`,``````#@#`````````0````$```#@S`,`````
-M`$`#`````````0````$```#`R`,``````$@#`````````0````$```"PQ`,`
-M`````%`#`````````0```$$!`````````````,`#`````````0````$`````
-M`P0``````,@#`````````0````$````0(`0``````-`#`````````0````$`
-M```0`@0``````.@#`````````0````$```#P]@,``````/`#`````````0``
-M``$```"@`00``````/@#`````````0````$```#`]P,``````"@$````````
-M`0````$`````,P0``````#@$`````````0````$````P;P0``````%`$````
-M`````0````$```!@,P0``````&`$`````````0````$```#`;00``````'@$
-M`````````0````$```"`,P0``````(@$`````````0````$````@@P0`````
-M`*`$`````````0````$```#@,P0``````+`$`````````0````$```!@?`0`
-M`````,@$`````````0````$`````-`0``````-@$`````````0````$```#`
-M;`0``````/`$`````````0````$```#@-`0````````%`````````0````$`
-M``"`9@0``````!@%`````````0````$```!`-00``````"@%`````````0``
-M``$````@W00``````$`%`````````0````$```!`.`0``````$@%````````
-M`0````$```!P=00``````%`%`````````0````$```!P5@0``````&@%````
-M`````0````$```"PS`0``````'`%`````````0````$````0=`0``````'@%
-M`````````0````$````P500``````)`%`````````0````$```!P/`0`````
-M`*`%`````````0````$```"`8@0``````+@%`````````0````$```"0/`0`
-M`````,@%`````````0````$```!0R00``````.`%`````````0````$```"0
-M/P0``````.@%`````````0````$```#P<P0``````/`%`````````0````$`
-M``#P5`0```````@&`````````0````$`````0`0``````!`&`````````0``
-M``$```#0<P0``````!@&`````````0````$```"P5`0``````#`&````````
-M`0````$```!P0`0``````#@&`````````0````$```"`<P0``````$`&````
-M`````0````$```!P5`0``````%@&`````````0````$````P000``````&`&
-M`````````0````$```#P<@0``````&@&`````````0````$````P5`0`````
-M`(`&`````````0````$```"@000``````(@&`````````0````$```#0<@0`
-M`````)`&`````````0````$```#P4P0``````*@&`````````0````$```"`
-M0@0``````+@&`````````0````$```!P4P0``````-`&`````````0````$`
-M``#P0@0``````.`&`````````0````$````P4P0``````/@&`````````0``
-M``$````00P0```````@'`````````0````$```!@TP0``````"`'````````
-M`0````$````P0P0``````#`'`````````0````$```#`UP0``````$@'````
-M`````0````$```!00P0``````%@'`````````0````$```#P>@0``````'`'
-M`````````0````$````01`0``````(`'`````````0````$```#0>@0`````
-M`)@'`````````0````$`````/00``````*@'`````````0````$```#0R`0`
-M`````,`'`````````0````$```!P/00``````-`'`````````0````$```"`
-MR`0``````.@'`````````0````$```#01`0``````/@'`````````0````$`
-M``#P4@0``````!`(`````````0````$````P100``````"`(`````````0``
-M``$```!0S@0``````#@(`````````0````$```#@100``````$`(````````
-M`0````$```!0<@0``````$@(`````````0````$```"P4@0``````&`(````
-M`````0````$```!0.00``````&@(`````````0````$````P=00``````'`(
-M`````````0````$````P5@0``````(@(`````````0````$```"`-00`````
-M`)@(`````````0````$```!`VP0``````+`(`````````0````$````00@0`
-M`````,`(`````````0````$```"P4P0``````-@(`````````0````$```#@
-M/00``````.@(`````````0````$`````R`0````````)`````````0````$`
-M``!`/@0``````!`)`````````0````$```"`QP0``````"@)`````````0``
-M``$```"@/@0``````#@)`````````0````$````PQP0``````%`)````````
-M`0````$```#`.@0``````%@)`````````0````$```"P=`0``````&`)````
-M`````0````$```"P500``````'@)`````````0````$`````/P0``````(@)
-M`````````0````$````0N@0``````*`)`````````0````$```"01@0`````
-M`*@)`````````0````$````@<@0``````+`)`````````0````$```!P4@0`
-M`````,@)`````````0````$```!P-@0``````-@)`````````0````$````P
-M900``````/`)`````````0````$```!P-P0``````/@)`````````0````$`
-M``"P=00````````*`````````0````$```"P5@0``````!@*`````````0``
-M``$```#`-00``````"@*`````````0````$```!0V`0``````$`*````````
-M`0````$```"@,P0``````%`*`````````0````$```"0@00``````&@*````
-M`````0````$```#`,P0``````'@*`````````0````$````0;00``````)`*
-M`````````0````$`````-@0``````*`*`````````0````$```"0LP0`````
-M`+@*`````````0````$`````.@0``````,`*`````````0````$```#P=`0`
-M`````,@*`````````0````$```#P500``````.`*`````````0````$```"0
-M.P0``````.@*`````````0````$```!P=`0``````/`*`````````0````$`
-M``!P500```````@+`````````0````$```#@-@0``````!@+`````````0``
-M``$```!P9`0``````#`+`````````0````$```"`1P0``````$`+````````
-M`0````$````0>P0``````%@+`````````0````$````0-00``````&@+````
-M`````0````$```#@900``````(`+`````````0````$````@-`0``````)`+
-M`````````0````$````@;`0``````*@+`````````0````$```!`-`0`````
-M`+@+`````````0````$````P:P0``````-`+`````````0````$```!@-`0`
-M`````.`+`````````0````$```!`:@0``````/@+`````````0````$```"`
-M-`0```````@,`````````0````$```!0:00``````"`,`````````0````$`
-M``"@-`0``````#`,`````````0````$```!0:`0``````$@,`````````0``
-M``$```#`-`0``````%@,`````````0````$```!P9P0``````'`,````````
-M`0````$````@,P0``````(`,`````````0````$```#0?`0``````)@,````
-M`````0````$```!`,P0``````*`,`````````0````$```#P=00``````*@,
-M`````````0````$````0;@0``````,`,`````````0````$```#P1@0`````
-M`-`,`````````0````$```"P800``````.@,`````````0````$````@1P0`
-M`````/@,`````````0````$```!@7P0``````!`-`````````0````$````0
-M.00``````"`-`````````0````$````P8P0``````#@-`````````0````$`
-M``#P.`0``````$@-`````````0````$```#P8P0``````&`-`````````0``
-M``$```!P2`0``````&@-`````````0````$`````<@0``````'`-````````
-M`0````$````P4@0``````(@-`````````0````$````P200``````)`-````
-M`````0````$```#@<00``````)@-`````````0````$```#P400``````"``
-M`````````0````$``````````````#@``````````0````$````P````````
-M`%```````````0````$```!``````````*@``````````0````$```"P`@``
-M`````,```````````0````$```#P`@```````-@``````````0````$````P
-M`P```````/```````````0````$```"``P````````@!`````````0````$`
-M``#0`P```````#@!`````````0````$```#@`P```````%`!`````````0``
-M``$````0!````````&@!`````````0````$```!@!````````(`!````````
-M`0````$```!P!````````)@!`````````0````$```#0!````````+`!````
-M`````0````$```#@!````````,@!`````````0````$````0!0```````.`!
-M`````````0````$```!`!0```````/@!`````````0````$```"`!0``````
-M`!`"`````````0````$```#`!0```````"@"`````````0````$```"@!P``
-M`````$`"`````````0````$```#@!P```````&`"`````````0````$```!P
-M"````````(`"`````````0````$```"P"````````)@"`````````0````$`
-M``#@"````````+`"`````````0````$````0"0```````.`"`````````0``
-M``$````P"0```````/@"`````````0````$```"@"0```````!`#````````
-M`0````$`````"@```````"@#`````````0````$```!@"@```````$`#````
-M`````0````$```#@"@```````&@#`````````0````$````P#````````(@#
-M`````````0````$```!P#````````,@#`````````0````$```#@#@``````
-M``@$`````````0````$````P$````````"`$`````````0````$```"`$```
-M`````#@$`````````0````$````0$0```````%`$`````````0````$```"0
-M$0```````&@$`````````0````$````0$@```````(`$`````````0````$`
-M```P$@```````*`$`````````0````$```"`$@```````,`$`````````0``
-M``$```"P$@```````.`$`````````0````$````0$P```````"`%````````
-M`0````$````P%0```````$`%`````````0````$````@%@```````&@%````
-M`````0````$```!`%P```````)`%`````````0````$```!@&````````+@%
-M`````````0````$```!P'@```````-@%`````````0````$```"0'@``````
-M`!@&`````````0````$```#P*0```````$@&`````````0````$`````+```
-M`````'`&`````````0````$```!@+P```````+`&`````````0````$```!0
-M,P```````-@&`````````0````$````@/0```````!@'`````````0````$`
-M``"P1@```````$`'`````````0````$```"@1P```````(`'`````````0``
-M``$```!@40```````,`'`````````0````$```!`6P```````.@'````````
-M`0````$`````7````````"`(`````````0````$```#`7````````%@(````
-M`````0````$````@8````````'@(`````````0````$```#P8````````+@(
-M`````````0````$```"09````````.`(`````````0````$```!@:```````
-M`"`)`````````0````$```!@;````````&`)`````````0````$```#@<@``
-M`````(`)`````````0````$```!P<P```````*`)`````````0````$```"`
-M<P```````,`)`````````0````$```"0=P```````.@)`````````0````$`
-M``"@>````````"@*`````````0````$```#P>0```````&@*`````````0``
-M``$```"`A0```````)@*`````````0````$`````B````````/`*````````
-M`0````$````@C0````````@+`````````0````$```"0C0```````"`+````
-M`````0````$```#@C0```````#@+`````````0````$```!`C@```````%`+
-M`````````0````$```"@C@```````&@+`````````0````$```"`CP``````
-M`*`+`````````0````$```#`D````````,`+`````````0````$````0D0``
-M```````,`````````0````$```"@D0```````"@,`````````0````$````0
-MDP```````%`,`````````0````$```!PE````````'@,`````````0````$`
-M``#`E0```````)@,`````````0````$```!`E@```````,`,`````````0``
-M``$```!0EP`````````-`````````0````$```#PF````````$`-````````
-M`0````$```!`F@```````&@-`````````0````$```!0FP```````)`-````
-M`````0````$```#@G````````+@-`````````0````$```#@G0```````/@-
-M`````````0````$```"`G@```````#@.`````````0````$```"PGP``````
-M`)`.`````````0````$````@I````````*@.`````````0````$```"`I```
-M`````-@.`````````0````$```#0I````````/`.`````````0````$```#P
-MI0```````!@/`````````0````$````0IP```````#`/`````````0````$`
-M``"@IP```````$@/`````````0````$```#0IP```````&`/`````````0``
-M``$```#@IP```````'@/`````````0````$````PJ````````)`/````````
-M`0````$```!@J````````*@/`````````0````$```"@J````````,`/````
-M`````0````$```#0J````````-@/`````````0````$````0J0```````/`/
-M`````````0````$```!`J0````````@0`````````0````$```!PJ0``````
-M`"`0`````````0````$```"0J0```````#@0`````````0````$```#`J0``
-M`````%`0`````````0````$```#PJ0```````&@0`````````0````$```!@
-MJ@```````(`0`````````0````$```!@JP```````)@0`````````0````$`
-M``!`K````````+`0`````````0````$```"0K````````.`0`````````0``
-M``$```"0K0`````````1`````````0````$```#`K0```````"`1````````
-M`0````$```#PK0```````$`1`````````0````$```!`K@```````&`1````
-M`````0````$```!PK@```````(`1`````````0````$```"@K@```````,`1
-M`````````0````$````PL````````.`1`````````0````$```!@L```````
-M`/@1`````````0````$```"0L````````!`2`````````0````$```#`L```
-M`````#@2`````````0````$```"PL0```````%@2`````````0````$```#P
-ML0```````'@2`````````0````$````PL@```````*`2`````````0````$`
-M``"`M0```````,@2`````````0````$```#@M@```````.@2`````````0``
-M``$```!`MP```````!`3`````````0````$```#PMP```````#@3````````
-M`0````$```"`N````````&`3`````````0````$```!PN0```````(@3````
-M`````0````$````@N@```````+`3`````````0````$```"@NP```````-@3
-M`````````0````$````0O0`````````4`````````0````$```#`O0``````
-M`"@4`````````0````$```#0O@```````%`4`````````0````$`````P```
-M`````'@4`````````0````$````@P0```````*`4`````````0````$````P
-MP@```````,@4`````````0````$```"0PP````````@5`````````0````$`
-M``!`QP```````#`5`````````0````$```!`R````````%@5`````````0``
-M``$````PR0```````(`5`````````0````$`````R@```````*@5````````
-M`0````$```#`R@```````-`5`````````0````$```#0RP```````/@5````
-M`````0````$```!0S0```````!@6`````````0````$```!PS0```````$`6
-M`````````0````$```"@S@```````&@6`````````0````$````0SP``````
-M`(@6`````````0````$```!0SP```````*@6`````````0````$```!PSP``
-M`````,@6`````````0````$```"@SP```````/`6`````````0````$```"@
-MT````````!@7`````````0````$```"0T@```````$`7`````````0````$`
-M```@TP```````&@7`````````0````$```"PU````````*@7`````````0``
-M``$````@V````````-@7`````````0````$````0V@```````!@8````````
-M`0````$```"@W````````$`8`````````0````$```#0W0```````&@8````
-M`````0````$````0WP```````)`8`````````0````$```!@WP```````,@8
-M`````````0````$```"0WP```````.`8`````````0````$```"PWP``````
-M`/@8`````````0````$```#0WP```````!`9`````````0````$`````X```
-M`````"@9`````````0````$```!0X````````$`9`````````0````$```"P
-MX````````%@9`````````0````$```!`X@```````(@9`````````0````$`
-M```0XP```````+@9`````````0````$```"`XP```````-@9`````````0``
-M``$```"PXP```````/@9`````````0````$```!`Y````````"@:````````
-M`0````$```"0Y0```````$@:`````````0````$```"PY@```````&@:````
-M`````0````$````PYP```````(@:`````````0````$```"PYP```````,@:
-M`````````0````$```#0\````````/`:`````````0````$```!@\@``````
-M``@;`````````0````$`````\P```````"`;`````````0````$`````]```
-M`````&@;`````````0````$```#`]0```````(`;`````````0````$```!`
-M]@```````)@;`````````0````$```"P]@```````+`;`````````0````$`
-M```@]P```````,@;`````````0````$```"0]P```````.`;`````````0``
-M``$```"@]P```````/@;`````````0````$```#@]P```````!`<````````
-M`0````$```!`^````````"@<`````````0````$```!@^````````$`<````
-M`````0````$```"0^````````&`<`````````0````$````P^0```````(@<
-M`````````0````$```!`^@```````,@<`````````0````$````@_```````
-M`/@<`````````0````$```"`_````````"`=`````````0````$```!P_0``
-M`````$@=`````````0````$```!`_@```````&@=`````````0````$```!@
-M_P```````)`=`````````0````$````0``$``````+@=`````````0````$`
-M``!``0$``````.`=`````````0````$````0`@$```````@>`````````0``
-M``$````0`P$``````$@>`````````0````$`````!`$``````(@>````````
-M`0````$```#P!`$``````,@>`````````0````$```"0!P$````````?````
-M`````0````$```!P"@$``````"@?`````````0````$````@"P$``````&@?
-M`````````0````$```!@#@$``````*@?`````````0````$```#`%0$`````
-M`.@?`````````0````$```#`%@$``````"`@`````````0````$```"P&@$`
-M`````&`@`````````0````$```#@(@$``````(@@`````````0````$```"0
-M(P$``````+`@`````````0````$`````*@$``````-@@`````````0````$`
-M``!0+`$``````/@@`````````0````$```!P+`$``````"`A`````````0``
-M``$````@-@$``````$@A`````````0````$````@.@$``````'`A````````
-M`0````$```!0/0$``````+`A`````````0````$````00`$``````/`A````
-M`````0````$`````0P$``````#`B`````````0````$```#`10$``````'`B
-M`````````0````$```"P20$``````+`B`````````0````$```"@30$`````
-M`/`B`````````0````$```#`3@$``````"`C`````````0````$```#04`$`
-M`````$@C`````````0````$````04P$``````(@C`````````0````$```#`
-M4P$``````+`C`````````0````$```!08`$``````/`C`````````0````$`
-M``"`:0$```````@D`````````0````$```"P:0$``````"`D`````````0``
-M``$```#@:0$``````$@D`````````0````$```!@:@$``````&@D````````
-M`0````$```"P:@$``````(@D`````````0````$```#0:@$``````*`D````
-M`````0````$````@:P$``````,@D`````````0````$```#`:P$``````/`D
-M`````````0````$```!0;0$``````!`E`````````0````$```"0;0$`````
-M`#`E`````````0````$```#0;0$``````%`E`````````0````$````0;@$`
-M`````'@E`````````0````$```"@;@$``````*`E`````````0````$```#P
-M;@$``````,@E`````````0````$```!P;P$``````/`E`````````0````$`
-M``!`<`$``````#`F`````````0````$```!0<@$``````%`F`````````0``
-M``$```"P<@$``````'`F`````````0````$````0<P$``````*@F````````
-M`0````$```#`<P$``````,@F`````````0````$````@=`$``````.@F````
-M`````0````$```!@=`$```````@G`````````0````$```"@=`$``````$@G
-M`````````0````$```"@>0$``````&@G`````````0````$`````>@$`````
-M`(@G`````````0````$```!0>@$``````,`G`````````0````$```"P>@$`
-M`````-@G`````````0````$```#0>@$``````/`G`````````0````$```#P
-M>@$``````!`H`````````0````$```!`?0$``````"@H`````````0````$`
-M``!@?0$``````$`H`````````0````$```"`?0$``````&@H`````````0``
-M``$```!P?@$``````*@H`````````0````$```"@?P$``````-`H````````
-M`0````$```"0@`$```````@I`````````0````$```#`@0$``````$@I````
-M`````0````$```!P@@$``````&`I`````````0````$```"P@P$``````'@I
-M`````````0````$```#`@P$``````)`I`````````0````$```#0@P$`````
-M`*@I`````````0````$```#P@P$``````,`I`````````0````$````0A`$`
-M`````-@I`````````0````$```!`A`$``````/`I`````````0````$```!P
-MA`$``````!@J`````````0````$```"PA0$``````#`J`````````0````$`
-M``#PA0$``````%@J`````````0````$```"0A@$``````'`J`````````0``
-M``$```#PA@$``````(@J`````````0````$````0AP$``````*@J````````
-M`0````$````0BP$``````,@J`````````0````$```!PC`$````````K````
-M`````0````$````@C@$``````!@K`````````0````$```!PC@$``````#`K
-M`````````0````$```"0C@$``````%@K`````````0````$`````CP$`````
-M`(`K`````````0````$````0D@$``````*@K`````````0````$```#`D@$`
-M`````-`K`````````0````$```!`DP$``````!`L`````````0````$````0
-ME`$``````#`L`````````0````$```"0E`$``````%`L`````````0````$`
-M``!0E0$``````)`L`````````0````$```#0F`$``````*@L`````````0``
-M``$```#@F`$``````,`L`````````0````$````PF0$``````-@L````````
-M`0````$```!`F0$``````/`L`````````0````$```!0F0$```````@M````
-M`````0````$```!@F0$``````"`M`````````0````$```#@F0$``````#@M
-M`````````0````$```"`F@$``````%`M`````````0````$```"0F@$`````
-M`&@M`````````0````$```"@F@$``````(`M`````````0````$```#PF@$`
-M`````)@M`````````0````$`````FP$``````+`M`````````0````$````0
-MFP$``````,@M`````````0````$```!0FP$``````.@M`````````0````$`
-M``"0FP$````````N`````````0````$```"PFP$``````!@N`````````0``
-M``$````0G`$``````#`N`````````0````$```!PG`$``````%`N````````
-M`0````$```"0G`$``````'@N`````````0````$```!PG0$``````+@N````
-M`````0````$```"PHP$``````-@N`````````0````$`````I`$````````O
-M`````````0````$````@I0$``````"`O`````````0````$```!`I0$`````
-M`$`O`````````0````$```!@I0$``````&`O`````````0````$```"`I0$`
-M`````(@O`````````0````$````0IP$``````+`O`````````0````$```#P
-MJP$``````-@O`````````0````$````PL`$````````P`````````0````$`
-M````L0$``````"@P`````````0````$```"@L@$``````$@P`````````0``
-M``$```"`LP$``````'`P`````````0````$````0M`$``````)@P````````
-M`0````$```#PM`$``````+@P`````````0````$````0M0$``````/@P````
-M`````0````$````0N`$``````"`Q`````````0````$```#`N`$``````$@Q
-M`````````0````$```!PO`$``````'`Q`````````0````$```#PO0$`````
-M`)@Q`````````0````$```#0O@$``````-@Q`````````0````$```#`Q`$`
-M`````/@Q`````````0````$```!@Q0$``````"@R`````````0````$```"0
-MS@$``````&@R`````````0````$````0TP$``````)`R`````````0````$`
-M``!@U0$``````,@R`````````0````$```!PV0$``````/@R`````````0``
-M``$```"0W0$``````"`S`````````0````$```"0X0$``````$@S````````
-M`0````$```#PXP$``````'`S`````````0````$```#0Z@$``````)@S````
-M`````0````$```!0[0$``````/`S`````````0````$```"0\`$```````@T
-M`````````0````$```#`\`$``````"`T`````````0````$```#0\`$`````
-M`'@T`````````0````$```!`\P$``````)`T`````````0````$```"`\P$`
-M`````*@T`````````0````$```#`\P$``````,`T`````````0````$````0
-M]`$``````-@T`````````0````$```!@]`$```````@U`````````0````$`
-M``!P]`$``````"`U`````````0````$```"@]`$``````#@U`````````0``
-M``$```#P]`$``````%`U`````````0````$`````]0$``````&@U````````
-M`0````$```!@]0$``````(`U`````````0````$```!P]0$``````)@U````
-M`````0````$```"@]0$``````+`U`````````0````$```#0]0$``````,@U
-M`````````0````$````0]@$``````.`U`````````0````$```!0]@$`````
-M`/@U`````````0````$````P^`$``````!`V`````````0````$```!P^`$`
-M`````#`V`````````0````$`````^0$``````%`V`````````0````$```!`
-M^0$``````&@V`````````0````$```!P^0$``````(`V`````````0````$`
-M``"@^0$``````+`V`````````0````$```#`^0$``````,@V`````````0``
-M``$````P^@$``````.`V`````````0````$```"0^@$``````/@V````````
-M`0````$```#P^@$``````!`W`````````0````$```!P^P$``````#@W````
-M`````0````$```#`_`$``````%@W`````````0````$`````_0$``````)@W
-M`````````0````$```!P_P$``````-@W`````````0````$```#```(`````
-M`/`W`````````0````$````0`0(```````@X`````````0````$```"@`0(`
-M`````"`X`````````0````$````@`@(``````#@X`````````0````$```"@
-M`@(``````%`X`````````0````$```#``@(``````'`X`````````0````$`
-M```0`P(``````)`X`````````0````$```!``P(``````+`X`````````0``
-M``$```"@`P(``````/`X`````````0````$```"P!0(``````!`Y````````
-M`0````$```"@!@(``````#@Y`````````0````$```#`!P(``````&`Y````
-M`````0````$```#@"`(``````(@Y`````````0````$```#P#@(``````*@Y
-M`````````0````$````0#P(``````.@Y`````````0````$```!P&@(`````
-M`!@Z`````````0````$```"`'`(``````$`Z`````````0````$```#@'P(`
-M`````(`Z`````````0````$```#0(P(``````*@Z`````````0````$```"@
-M+0(``````.@Z`````````0````$````P-P(``````!`[`````````0````$`
-M```@.`(``````%`[`````````0````$```#@00(``````)`[`````````0``
-M``$```"@2P(``````+@[`````````0````$```!@3`(``````/`[````````
-M`0````$````@30(``````"@\`````````0````$```"`4`(``````$@\````
-M`````0````$```!040(``````(@\`````````0````$```#P5`(``````+`\
-M`````````0````$```#`6`(``````/`\`````````0````$```#`7`(`````
-M`#`]`````````0````$`````8P(``````%`]`````````0````$```"08P(`
-M`````'`]`````````0````$```"@8P(``````)`]`````````0````$```"P
-M9P(``````+@]`````````0````$```#`:`(``````/@]`````````0````$`
-M```0:@(``````#@^`````````0````$```"@=0(``````&@^`````````0``
-M``$````@>`(``````,`^`````````0````$```#P?`(``````-@^````````
-M`0````$```!@?0(``````/`^`````````0````$```"P?0(```````@_````
-M`````0````$````0?@(``````"`_`````````0````$```!P?@(``````#@_
-M`````````0````$```!0?P(``````'`_`````````0````$```"0@`(`````
-M`)`_`````````0````$```#@@`(``````-`_`````````0````$```!P@0(`
-M`````/@_`````````0````$```#@@@(``````"!``````````0````$```!`
-MA`(``````$A``````````0````$```"0A0(``````&A``````````0````$`
-M```0A@(``````)!``````````0````$````@AP(``````-!``````````0``
-M``$```#`B`(``````!!!`````````0````$````0B@(``````#A!````````
-M`0````$````@BP(``````&!!`````````0````$```"PC`(``````(A!````
-M`````0````$```"PC0(``````,A!`````````0````$```!0C@(```````A"
-M`````````0````$```"`CP(``````&!"`````````0````$```#PDP(`````
-M`'A"`````````0````$```!0E`(``````*A"`````````0````$```"@E`(`
-M`````,!"`````````0````$```#`E0(``````.A"`````````0````$```#@
-ME@(```````!#`````````0````$```!PEP(``````!A#`````````0````$`
-M``"@EP(``````#!#`````````0````$```"PEP(``````$A#`````````0``
-M``$`````F`(``````&!#`````````0````$````PF`(``````'A#````````
-M`0````$```!PF`(``````)!#`````````0````$```"@F`(``````*A#````
-M`````0````$```#@F`(``````,!#`````````0````$````0F0(``````-A#
-M`````````0````$```!`F0(``````/!#`````````0````$```!@F0(`````
-M``A$`````````0````$```"0F0(``````"!$`````````0````$```#`F0(`
-M`````#A$`````````0````$````PF@(``````%!$`````````0````$````P
-MFP(``````&A$`````````0````$````0G`(``````(!$`````````0````$`
-M``!@G`(``````+!$`````````0````$```!@G0(``````-!$`````````0``
-M``$```"0G0(``````/!$`````````0````$```#`G0(``````!!%````````
-M`0````$````0G@(``````#!%`````````0````$```!`G@(``````%!%````
-M`````0````$```!PG@(``````)!%`````````0````$`````H`(``````+!%
-M`````````0````$````PH`(``````,A%`````````0````$```!@H`(`````
-M`.!%`````````0````$```"0H`(```````A&`````````0````$```"`H0(`
-M`````"A&`````````0````$```#`H0(``````$A&`````````0````$`````
-MH@(``````'!&`````````0````$```!0I0(``````)A&`````````0````$`
-M``"PI@(``````+A&`````````0````$````0IP(``````.!&`````````0``
-M``$```#`IP(```````A'`````````0````$```!0J`(``````#!'````````
-M`0````$```!`J0(``````%A'`````````0````$```#PJ0(``````(!'````
-M`````0````$```!PJP(``````*A'`````````0````$```#@K`(``````-!'
-M`````````0````$```"0K0(``````/A'`````````0````$```"@K@(`````
-M`"!(`````````0````$```#0KP(``````$A(`````````0````$```#PL`(`
-M`````'!(`````````0````$`````L@(``````)A(`````````0````$```!@
-MLP(``````-A(`````````0````$````0MP(```````!)`````````0````$`
-M```0N`(``````"A)`````````0````$`````N0(``````%!)`````````0``
-M``$```#0N0(``````'A)`````````0````$```"0N@(``````*!)````````
-M`0````$```"@NP(``````,A)`````````0````$````@O0(``````.A)````
-M`````0````$```!`O0(``````!!*`````````0````$```!PO@(``````#A*
-M`````````0````$```#@O@(``````%A*`````````0````$````@OP(`````
-M`'A*`````````0````$```!`OP(``````)A*`````````0````$```!POP(`
-M`````,!*`````````0````$```!PP`(``````.A*`````````0````$```!@
-MP@(``````!!+`````````0````$```#PP@(``````#A+`````````0````$`
-M``"`Q`(``````'A+`````````0````$```#PQP(``````*A+`````````0``
-M``$```#@R0(``````.A+`````````0````$```!PS`(``````!!,````````
-M`0````$```"@S0(``````#A,`````````0````$```#@S@(``````&!,````
-M`````0````$````PSP(``````)A,`````````0````$```!@SP(``````+!,
-M`````````0````$```"`SP(``````,A,`````````0````$```"@SP(`````
-M`.!,`````````0````$```#0SP(``````/A,`````````0````$````@T`(`
-M`````!!-`````````0````$```"`T`(``````"A-`````````0````$````0
-MT@(``````%A-`````````0````$```#@T@(``````(A-`````````0````$`
-M``!0TP(``````*A-`````````0````$```"`TP(``````,A-`````````0``
-M``$````0U`(``````/A-`````````0````$```!@U0(``````!A.````````
-M`0````$```"`U@(``````#A.`````````0````$`````UP(``````%A.````
-M`````0````$```"`UP(``````)A.`````````0````$```"@X`(``````,!.
-M`````````0````$````PX@(``````-A.`````````0````$```#0X@(`````
-M`/!.`````````0````$```#0XP(``````#A/`````````0````$```"0Y0(`
-M`````%!/`````````0````$````0Y@(``````&A/`````````0````$```"`
-MY@(``````(!/`````````0````$```#PY@(``````)A/`````````0````$`
-M``!@YP(``````+!/`````````0````$```!PYP(``````,A/`````````0``
-M``$```"PYP(``````.!/`````````0````$````0Z`(``````/A/````````
-M`0````$````PZ`(``````!!0`````````0````$```!@Z`(``````#!0````
-M`````0````$`````Z0(``````%A0`````````0````$````0Z@(``````)A0
-M`````````0````$```#PZP(``````,A0`````````0````$```!0[`(`````
-M`/!0`````````0````$```!`[0(``````!A1`````````0````$````0[@(`
-M`````#A1`````````0````$````P[P(``````&!1`````````0````$```#@
-M[P(``````(A1`````````0````$````0\0(``````+!1`````````0````$`
-M``#@\0(``````-A1`````````0````$```#@\@(``````!A2`````````0``
-M``$```#0\P(``````%A2`````````0````$```#`]`(``````)A2````````
-M`0````$```!@]P(``````-!2`````````0````$```!`^@(``````/A2````
-M`````0````$```#P^@(``````#A3`````````0````$````P_@(``````'A3
-M`````````0````$```"0!0,``````+A3`````````0````$```"0!@,`````
-M`/!3`````````0````$```"`"@,``````#!4`````````0````$```"P$@,`
-M`````%A4`````````0````$```!@$P,``````(!4`````````0````$```#0
-M&0,``````*A4`````````0````$````@'`,``````,A4`````````0````$`
-M``!`'`,``````/!4`````````0````$```#P)0,``````!A5`````````0``
-M``$```#P*0,``````$!5`````````0````$````@+0,``````(!5````````
-M`0````$```#@+P,``````,!5`````````0````$```#0,@,```````!6````
-M`````0````$```"0-0,``````$!6`````````0````$```"`.0,``````(!6
-M`````````0````$```!P/0,``````,!6`````````0````$```"0/@,`````
-M`/!6`````````0````$```"@0`,``````!A7`````````0````$```#@0@,`
-M`````%A7`````````0````$```"00P,``````(!7`````````0````$````0
-M4`,``````,!7`````````0````$```!`60,``````-A7`````````0````$`
-M``!P60,``````/!7`````````0````$```"@60,``````!A8`````````0``
-M``$````@6@,``````#A8`````````0````$```!P6@,``````%A8````````
-M`0````$```"06@,``````'!8`````````0````$```#@6@,``````)A8````
-M`````0````$```"`6P,``````,!8`````````0````$````070,``````.!8
-M`````````0````$```!070,```````!9`````````0````$```"`70,`````
-M`"!9`````````0````$```#`70,``````$A9`````````0````$```"@7@,`
-M`````'!9`````````0````$```#P7@,``````)A9`````````0````$```!P
-M7P,``````,!9`````````0````$```!`8`,```````!:`````````0````$`
-M``!08@,``````"!:`````````0````$```"P8@,``````$!:`````````0``
-M``$````08P,``````'A:`````````0````$```#`8P,``````)A:````````
-M`0````$````@9`,``````+A:`````````0````$```!@9`,``````-A:````
-M`````0````$```"@9`,``````!A;`````````0````$````0:@,``````#A;
-M`````````0````$```!P:@,``````%A;`````````0````$```#`:@,`````
-M`)!;`````````0````$````@:P,``````*A;`````````0````$```!`:P,`
-M`````,!;`````````0````$```!@:P,``````.!;`````````0````$```!0
-M;`,``````/A;`````````0````$```!P;`,``````!!<`````````0````$`
-M``"@;`,``````#!<`````````0````$````P;0,``````'!<`````````0``
-M``$```!@;@,``````)A<`````````0````$```!0;P,``````-!<````````
-M`0````$```"`<`,``````!!=`````````0````$````P<0,``````"A=````
-M`````0````$```!P<@,``````$!=`````````0````$```"`<@,``````%A=
-M`````````0````$```"0<@,``````'!=`````````0````$```"P<@,`````
-M`(A=`````````0````$```#0<@,``````*!=`````````0````$`````<P,`
-M`````+A=`````````0````$````P<P,``````.!=`````````0````$```!P
-M=`,``````/A=`````````0````$```"P=`,``````"!>`````````0````$`
-M``!0=0,``````#A>`````````0````$```"P=0,``````%!>`````````0``
-M``$```#0=0,``````'!>`````````0````$```#0>0,``````)!>````````
-M`0````$````P>P,``````,A>`````````0````$```#@?`,``````.!>````
-M`````0````$````P?0,``````/A>`````````0````$```!0?0,``````"!?
-M`````````0````$```#`?0,``````$A?`````````0````$```#0@`,`````
-M`'!?`````````0````$```"`@0,``````)A?`````````0````$`````@@,`
-M`````-A?`````````0````$```#0@@,``````/A?`````````0````$```!0
-M@P,``````!A@`````````0````$````0A`,``````%A@`````````0````$`
-M``"0AP,``````'!@`````````0````$```"@AP,``````(A@`````````0``
-M``$```#PAP,``````*!@`````````0````$`````B`,``````+A@````````
-M`0````$````0B`,``````-!@`````````0````$````@B`,``````.A@````
-M`````0````$```"@B`,```````!A`````````0````$```!`B0,``````!AA
-M`````````0````$```!0B0,``````#!A`````````0````$```!@B0,`````
-M`$AA`````````0````$```"PB0,``````&!A`````````0````$```#`B0,`
-M`````'AA`````````0````$```#`B@,``````)!A`````````0````$`````
-MBP,``````+!A`````````0````$```!`BP,``````,AA`````````0````$`
-M``!@BP,``````.!A`````````0````$```#`BP,``````/AA`````````0``
-M``$````@C`,``````!AB`````````0````$```!`C`,``````$!B````````
-M`0````$````@C0,``````(!B`````````0````$```!@DP,``````*!B````
-M`````0````$```#0DP,``````,!B`````````0````$````@E`,``````.!B
-M`````````0````$```!`E`,```````!C`````````0````$```!@E`,`````
-M`"!C`````````0````$```"`E`,``````$AC`````````0````$````0E@,`
-M`````'!C`````````0````$```#PF@,``````)AC`````````0````$````P
-MGP,``````,!C`````````0````$`````H`,``````.AC`````````0````$`
-M``"@H0,```````AD`````````0````$```"`H@,``````#!D`````````0``
-M``$````0HP,``````%AD`````````0````$```#PHP,``````'AD````````
-M`0````$````0I`,``````+AD`````````0````$````0IP,``````.!D````
-M`````0````$```#`IP,```````AE`````````0````$```!@JP,``````#!E
-M`````````0````$```#@K`,``````%AE`````````0````$````@K@,`````
-M`)AE`````````0````$````0M`,``````+AE`````````0````$```"PM`,`
-M`````.AE`````````0````$```#@O0,``````"AF`````````0````$```!@
-MP@,``````%!F`````````0````$```"PQ`,``````(AF`````````0````$`
-M``#`R`,``````+AF`````````0````$```#@S`,``````.!F`````````0``
-M``$```#@T`,```````AG`````````0````$```!`TP,``````#!G````````
-M`0````$````@V@,``````%AG`````````0````$```"PW`,``````+!G````
-M`````0````$```#PWP,``````,AG`````````0````$````0X`,``````.!G
-M`````````0````$````@X`,``````/AG`````````0````$```!0X`,`````
-M`!!H`````````0````$```!@X`,``````#AH`````````0````$```#@X`,`
-M`````&!H`````````0````$```"PX0,``````'AH`````````0````$```#@
-MX0,``````*!H`````````0````$````PX@,``````+AH`````````0````$`
-M``!PX@,``````-!H`````````0````$```"@X@,``````.AH`````````0``
-M``$```#@X@,```````AI`````````0````$````0XP,``````"!I````````
-M`0````$````@XP,``````#AI`````````0````$````PXP,``````%!I````
-M`````0````$```!@XP,``````&AI`````````0````$```"@XP,``````(!I
-M`````````0````$`````Y`,``````*AI`````````0````$```"0Y`,`````
-M`-!I`````````0````$```#PY`,```````AJ`````````0````$```#0Y0,`
-M`````#!J`````````0````$```"@Y@,``````%AJ`````````0````$````@
-MYP,``````(!J`````````0````$```"`YP,``````*AJ`````````0````$`
-M``!@Z`,``````-AJ`````````0````$```!@Z0,``````/AJ`````````0``
-M``$```#`Z0,``````"!K`````````0````$````@Z@,``````#AK````````
-M`0````$````PZ@,``````%!K`````````0````$```!0Z@,``````&AK````
-M`````0````$```!PZ@,``````*!K`````````0````$```#@[`,``````.!K
-M`````````0````$```!`[@,``````!!L`````````0````$```!`[P,`````
-M`#AL`````````0````$```#@[P,``````&AL`````````0````$```"`\`,`
-M`````*AL`````````0````$```#@\0,``````.!L`````````0````$```"P
-M\P,```````AM`````````0````$```!P]`,``````#!M`````````0````$`
-M``#P]0,``````'!M`````````0````$```#P]@,``````(AM`````````0``
-M``$````P]P,``````*!M`````````0````$```!0]P,``````+AM````````
-M`0````$```"`]P,``````-!M`````````0````$```#`]P,``````.AM````
-M`````0````$`````^`,```````!N`````````0````$```!`^`,``````!AN
-M`````````0````$```"P^`,``````#!N`````````0````$```!P^0,`````
-M`$AN`````````0````$```"`^0,``````'!N`````````0````$```#0^0,`
-M`````)!N`````````0````$```!0^@,``````+!N`````````0````$````0
-M^P,``````-!N`````````0````$```!P^P,``````/AN`````````0````$`
-M```@_`,``````!!O`````````0````$````P_`,``````#!O`````````0``
-M``$```"`_`,``````%AO`````````0````$```#P_`,``````'AO````````
-M`0````$```!P_0,``````)!O`````````0````$```"P_0,``````+!O````
-M`````0````$`````_@,``````-AO`````````0````$```!@_@,```````AP
-M`````````0````$```"@`00``````#!P`````````0````$````0`@0`````
-M`%AP`````````0````$``````P0``````'AP`````````0````$```!``P0`
-M`````*!P`````````0````$```!`!00``````,!P`````````0````$```"0
-M!00``````.AP`````````0````$````@!P0``````!!Q`````````0````$`
-M``"`"00``````#!Q`````````0````$```#@"00``````&!Q`````````0``
-M``$```"@%`0``````*!Q`````````0````$```"0%@0``````,!Q````````
-M`0````$```#@%@0``````.AQ`````````0````$```#@%P0``````!AR````
-M`````0````$```!0&00``````$AR`````````0````$```#@&@0``````&AR
-M`````````0````$```!P&P0``````)!R`````````0````$```#@&P0`````
-M`,AR`````````0````$````P'@0``````/!R`````````0````$```#0'@0`
-M`````!AS`````````0````$````0(`0``````$!S`````````0````$````0
-M(00``````(!S`````````0````$```"0(@0``````)AS`````````0````$`
-M``#P(@0``````+!S`````````0````$````0(P0``````,AS`````````0``
-M``$```!@(P0```````AT`````````0````$````@)`0``````$AT````````
-M`0````$````P)00``````'AT`````````0````$```"0)00``````+AT````
-M`````0````$```#P)@0``````-!T`````````0````$```!0)P0``````.AT
-M`````````0````$```#P)P0```````!U`````````0````$```#0*`0`````
-M`!AU`````````0````$```#@*00``````#!U`````````0````$````P*@0`
-M`````$AU`````````0````$```"P*@0``````(AU`````````0````$```!`
-M+P0``````*!U`````````0````$```!0+P0``````+AU`````````0````$`
-M``#@+P0``````-AU`````````0````$```!@,`0```````!V`````````0``
-M``$```"@,`0``````!AV`````````0````$```"`,00``````$!V````````
-M`0````$````0,@0``````'!V`````````0````$```"`,@0``````(AV````
-M`````0````$`````,P0``````*!V`````````0````$````@,P0``````+AV
-M`````````0````$```!`,P0``````-!V`````````0````$```!@,P0`````
-M`.AV`````````0````$```"`,P0```````!W`````````0````$```"@,P0`
-M`````!AW`````````0````$```#`,P0``````#!W`````````0````$```#@
-M,P0``````$AW`````````0````$`````-`0``````&!W`````````0````$`
-M```@-`0``````'AW`````````0````$```!`-`0``````)!W`````````0``
-M``$```!@-`0``````*AW`````````0````$```"`-`0``````,!W````````
-M`0````$```"@-`0``````-AW`````````0````$```#`-`0``````/!W````
-M`````0````$```#@-`0```````AX`````````0````$````0-00``````"!X
-M`````````0````$```!`-00``````$!X`````````0````$```"`-00`````
-M`&!X`````````0````$```#`-00``````(!X`````````0````$`````-@0`
-M`````*!X`````````0````$```!P-@0``````,!X`````````0````$```#@
-M-@0``````.AX`````````0````$```!P-P0``````!!Y`````````0````$`
-M``!`.`0``````#AY`````````0````$```#P.`0``````%!Y`````````0``
-M``$````0.00``````&AY`````````0````$```!0.00``````)!Y````````
-M`0````$`````.@0``````+AY`````````0````$```#`.@0``````.!Y````
-M`````0````$```"0.P0```````AZ`````````0````$```!P/`0``````"!Z
-M`````````0````$```"0/`0``````$!Z`````````0````$`````/00`````
-M`&!Z`````````0````$```!P/00``````(!Z`````````0````$```#@/00`
-M`````*!Z`````````0````$```!`/@0``````,!Z`````````0````$```"@
-M/@0``````.!Z`````````0````$`````/P0```````![`````````0````$`
-M``"0/P0``````"![`````````0````$`````0`0``````$![`````````0``
-M``$```!P0`0``````&A[`````````0````$````P000``````(A[````````
-M`0````$```"@000``````*A[`````````0````$````00@0``````,A[````
-M`````0````$```"`0@0``````.A[`````````0````$```#P0@0```````!\
-M`````````0````$````00P0``````!A\`````````0````$````P0P0`````
-M`#!\`````````0````$```!00P0``````%!\`````````0````$````01`0`
-M`````'!\`````````0````$```#01`0``````)!\`````````0````$````P
-M100``````+A\`````````0````$```#@100``````.!\`````````0````$`
-M``"01@0```````!]`````````0````$```#P1@0``````!A]`````````0``
-M``$````@1P0``````#A]`````````0````$```"`1P0``````%A]````````
-M`0````$````P2`0``````'!]`````````0````$```!P2`0``````)!]````
-M`````0````$````P200``````+!]`````````0````$```#0200``````-A]
-M`````````0````$```#@2@0``````/!]`````````0````$```!02P0`````
-M`!!^`````````0````$```"P2P0``````"A^`````````0````$```#`2P0`
-M`````$A^`````````0````$```#`3`0``````&!^`````````0````$```#0
-M3`0``````'A^`````````0````$````@300``````)A^`````````0````$`
-M``"0300``````,!^`````````0````$```!@3@0``````.A^`````````0``
-M``$````03P0``````!A_`````````0````$````P4`0``````$A_````````
-M`0````$```!`400``````&A_`````````0````$```!P400``````(!_````
-M`````0````$```#P400``````)A_`````````0````$````P4@0``````+!_
-M`````````0````$```!P4@0``````,A_`````````0````$```"P4@0`````
-M`.!_`````````0````$```#P4@0``````/A_`````````0````$````P4P0`
-M`````!"``````````0````$```!P4P0``````"B``````````0````$```"P
-M4P0``````$"``````````0````$```#P4P0``````%B``````````0````$`
-M```P5`0``````'"``````````0````$```!P5`0``````(B``````````0``
-M``$```"P5`0``````*"``````````0````$```#P5`0``````+B`````````
-M`0````$````P500``````-"``````````0````$```!P500``````.B`````
-M`````0````$```"P500```````"!`````````0````$```#P500``````!B!
-M`````````0````$````P5@0``````#"!`````````0````$```!P5@0`````
-M`$B!`````````0````$```"P5@0``````&"!`````````0````$```#P5@0`
-M`````'B!`````````0````$````@5P0``````)"!`````````0````$```!0
-M5P0``````+"!`````````0````$`````6`0``````,B!`````````0````$`
-M``!`6`0``````/"!`````````0````$````0600``````!""`````````0``
-M``$```!@600``````$""`````````0````$```!P6@0``````&""````````
-M`0````$```#`6@0``````)""`````````0````$```!@7`0``````-""````
-M`````0````$```#P700```````B#`````````0````$```#07@0``````"B#
-M`````````0````$```!@7P0``````%B#`````````0````$```"`800`````
-M`'"#`````````0````$```"P800``````+"#`````````0````$```"`8@0`
-M`````,B#`````````0````$````P8P0``````/"#`````````0````$```#P
-M8P0``````!B$`````````0````$```!P9`0``````$"$`````````0````$`
-M```P900``````&B$`````````0````$```#@900``````(B$`````````0``
-M``$```"`9@0``````+"$`````````0````$```!P9P0``````/"$````````
-M`0````$```!0:`0``````#"%`````````0````$```!0:00``````'"%````
-M`````0````$```!`:@0``````+"%`````````0````$````P:P0``````/"%
-M`````````0````$````@;`0``````""&`````````0````$```#`;`0`````
-M`$"&`````````0````$````0;00``````&B&`````````0````$```#`;00`
-M`````(B&`````````0````$````0;@0``````+"&`````````0````$````P
-M;P0``````,B&`````````0````$```!@;P0```````"'`````````0````$`
-M```P<`0``````"B'`````````0````$```#0<00``````$"'`````````0``
-M``$```#@<00``````&"'`````````0````$`````<@0``````("'````````
-M`0````$````@<@0``````*"'`````````0````$```!0<@0``````-"'````
-M`````0````$```#0<@0``````/"'`````````0````$```#P<@0``````!"(
-M`````````0````$```"`<P0``````#"(`````````0````$```#0<P0`````
-M`%"(`````````0````$```#P<P0``````'"(`````````0````$````0=`0`
-M`````)"(`````````0````$```!P=`0``````+B(`````````0````$```"P
-M=`0``````."(`````````0````$```#P=`0```````B)`````````0````$`
-M```P=00``````#")`````````0````$```!P=00``````%B)`````````0``
-M``$```"P=00``````(")`````````0````$```#P=00``````*B)````````
-M`0````$```!@=@0``````.B)`````````0````$```"@=P0``````!"*````
-M`````0````$```#0>@0``````#"*`````````0````$```#P>@0``````%"*
-M`````````0````$````0>P0``````'B*`````````0````$```!@?`0`````
-M`*"*`````````0````$```#0?`0``````,B*`````````0````$```"@?@0`
-M``````B+`````````0````$```"0@00``````#B+`````````0````$````@
-M@P0``````&B+`````````0````$```!PA`0``````)"+`````````0````$`
-M````A00``````+"+`````````0````$```!`A00``````-"+`````````0``
-M``$```"`A00``````/"+`````````0````$```!@B`0```````B,````````
-M`0````$```#PB00``````"",`````````0````$````@B@0``````$",````
-M`````0````$```!`BP0``````'",`````````0````$```#0DP0``````)B,
-M`````````0````$```"@E@0``````-",`````````0````$```"`EP0`````
-M`/B,`````````0````$```#@F@0``````""-`````````0````$```#`FP0`
-M`````$"-`````````0````$````PG`0``````("-`````````0````$```#@
-MG00``````*B-`````````0````$```!PGP0``````.B-`````````0````$`
-M``#`K@0``````!".`````````0````$````PKP0``````#B.`````````0``
-M``$```!`L`0``````&".`````````0````$```"0L`0``````)".````````
-M`0````$```!0L00``````,".`````````0````$```"0LP0``````/".````
-M`````0````$```"@M@0``````!B/`````````0````$```"PN`0``````$B/
-M`````````0````$```!0N00``````&B/`````````0````$```"PN00`````
-M`(B/`````````0````$````0N@0``````*B/`````````0````$````@O`0`
-M`````-B/`````````0````$````@PP0```````B0`````````0````$````P
-MQP0``````#"0`````````0````$```"`QP0``````%B0`````````0````$`
-M````R`0``````("0`````````0````$```"`R`0``````*B0`````````0``
-M``$```#0R`0``````-"0`````````0````$```!0R00``````/B0````````
-M`0````$```#0R00``````"B1`````````0````$```!@R@0``````%"1````
-M`````0````$```#`R@0``````'B1`````````0````$```"PRP0``````*"1
-M`````````0````$```"PS`0``````,"1`````````0````$```!0S00`````
-M`.B1`````````0````$````@S@0```````B2`````````0````$```!0S@0`
-M`````$"2`````````0````$````PSP0``````("2`````````0````$```"`
-MT`0``````*B2`````````0````$```!`T@0``````."2`````````0````$`
-M``!@TP0```````"3`````````0````$```"@TP0``````#B3`````````0``
-M``$```#@U`0``````%"3`````````0````$```#PU`0``````'B3````````
-M`0````$````@U@0``````*"3`````````0````$```"@U@0``````,B3````
-M`````0````$````PUP0``````/B3`````````0````$```#`UP0``````""4
-M`````````0````$```!0V`0``````&"4`````````0````$```!`VP0`````
-M`)B4`````````0````$````@W00``````-"4`````````0````$```#PW@0`
-M``````"5`````````0````$```!@X@0``````"B5`````````0````$```!@
-MXP0``````%B5`````````0````$````0Y`0``````("5`````````0````$`
-M``"`Y@0``````*B5`````````0````$```"@Z@0``````,"5`````````0``
-M``$```#@Z@0``````."5`````````0````$````PZP0```````B6````````
-M`0````$```"0[`0``````$B6`````````0````$```"@[00``````&"6````
-M`````0````$```"`[@0``````("6`````````0````$`````[P0``````)B6
-M`````````0````$```!P[P0``````+"6`````````0````$```"0[P0`````
-M`,B6`````````0````$```"@[P0``````.B6`````````0````$```#P[P0`
-M`````!"7`````````0````$```!P\`0``````$"7`````````0````$```"0
-M\00``````'"7`````````0````$```"@]00``````)"7`````````0````$`
-M````]@0``````+B7`````````0````$```#@]@0``````/B7`````````0``
-M``$```!0^@0``````#"8`````````0````$```"0^@0``````$B8````````
-M`0````$```"P^@0``````'B8`````````0````$```"P^P0``````)"8````
-M`````0````$```#P^P0``````*B8`````````0````$```!@_`0``````-B8
-M`````````0````$```!0_00``````/B8`````````0````$```"P_00`````
-M`""9`````````0````$```"0_@0``````$"9`````````0````$````P_P0`
-M`````("9`````````0````$```!0`04``````+B9`````````0````$````P
-M!04``````."9`````````0````$```"@!04```````B:`````````0````$`
-M```P!@4``````#B:`````````0````$```"`"`4``````%B:`````````0``
-M``$````@"04``````(":`````````0````$```"0"@4``````+":````````
-M`0````$```!0$@4``````/":`````````0````$```#@%`4```````B;````
-M`````0````$```!`%04``````"";`````````0````$```!0%04``````#B;
-M`````````0````$```!P%04``````%";`````````0````$```"`%04`````
-M`'B;`````````0````$```!P%@4``````*";`````````0````$```"P%@4`
-M`````,";`````````0````$`````%P4``````.";`````````0````$```!@
-M%P4``````/B;`````````0````$```!P%P4``````"B<`````````0````$`
-B``"`%P4``````$"<`````````0````$```#0%P4`````````
+M7V9I;F1?=&%R9V5T`&AP=&YR7V1E8G5G7V9L86<`:'!T;G)?9&UA<&]O;%]R
+M96=I<W1E<E]C;&EE;G0`:'!T;G)?;&1M7VEN:71I86QI>F5?=F)U<U]A<WEN
+M8P!H<'1N<E]O<U]Q=65R>5]T:6UE`&AP=&YR7V]S7W%U97)Y7W)E;6]V95]D
+M979I8V4`:'!T;G)?;&1M7W)E9VES=&5R7V1E=FEC90!H<'1N<E]O<U]P8VE?
+M<F5A9&P`:'!T;G)?;&1M7V%C<75I<F5?;&]C:P!H<'1N<E]O<U]R979A;&ED
+M871E7V1E=FEC90!H<'1N<E]D;6%P;V]L7VEN:70`:'!T;G)?;&1M7V9I;FES
+M:%]C;60`:'!T;G)?;&1M7VED95]F:7AS=')I;F<`:'!T;G)?9&UA<&]O;%]M
+M87A?8VQA<W-?<&%G97,`:'!T;G)?;&1M7W)E9VES=&5R7W9D979?8VQA<W-?
+M4E\V7S4U7S<U7S0V7S8T`&AP=&YR7VYU;5]D<FEV97-?<&5R7W-P:6YU<`!H
+M<'1N<E]L9&U?<F5L96%S95]V8G5S`&AP=&YR7VQD;5]Q=65U95]T87-K`&AP
+M=&YR7VQD;5]A;&QO8U]C;61S7V9R;VU?;&ES=`!H<'1N<E]F<F5E;&ES=%]P
+M=71?9&UA`&AP=&YR7VQD;5]T:6UE<E]P<F]B95]D979I8V4`:'!T;G)?;&1M
+M7V9I;F1?<W1A;7``:'!T;G)?;&1M7V-H96-K7V%R<F%Y7V]N;&EN90!H<'1N
+M<E]G4')O8F5);DEN:71I86QI>FEN9P!H<'1N<E]L;V=?<V5C=&]R7W)E<&%I
+M<@```(@"`````````@```#H```#\_________U0%````````"P````4`````
+M`````````%X%`````````@```#T"``#\_________Z`%`````````@```!0"
+M``#\_________V0&`````````@```"`"``#\_________XT&`````````@``
+M`"`"``#\_________^T&`````````@```"`"``#\_________V\'````````
+M`@```"`"``#\_________ZD'`````````@```"`"``#\_________PX(````
+M`````@```#("``#\_________TD(`````````@```#("``#\_________Y<(
+M`````````@```#("``#\_________]((`````````@```#("``#\________
+M_R@)`````````@```*\```#\_________S()`````````@```#("``#\____
+M_____SP)`````````@```$P```#\_________Q<*`````````@```"`"``#\
+M_________S0*`````````@```"`"``#\_________T,*`````````@```#("
+M``#\_________U\*`````````@```"`"``#\_________WP*`````````@``
+M`"`"``#\_________ZH*`````````@```"`"``#\_________[0*````````
+M`@```"`"``#\_________]P*`````````@```#("``#\_________^D*````
+M`````@```"`"``#\_________Q$+`````````@```#("``#\_________QX+
+M`````````@```"`"``#\_________T\+`````````@```"`"``#\________
+M_X`+`````````@```"`"``#\_________^4+`````````@```"`"``#\____
+M_____P4,`````````@```"`"``#\_________RP,`````````@```"`"``#\
+M_________TP,`````````@```"`"``#\_________WP,`````````@```"`"
+M``#\_________X8,`````````@```"`"``#\_________[(,`````````@``
+M`#("``#\_________\(,`````````@```"`"``#\_________^H,````````
+M`@```#("``#\__________H,`````````@```"`"``#\_________\40````
+M`````@```#("``#\_________]H0`````````@```"`"``#\_________P81
+M`````````@```#("``#\_________QL1`````````@```"`"``#\________
+M_S81````````"P````4```!8`````````$`1`````````@```#T"``#\____
+M_____X$1`````````@```#("``#\_________Y<1`````````@```"`"``#\
+M_________]01`````````@```#("``#\_________^D1`````````@```"`"
+M``#\_________R<2`````````@```#("``#\_________ST2`````````@``
+M`"`"``#\_________WH2`````````@```#("``#\_________X\2````````
+M`@```"`"``#\_________]T2`````````@```"`"``#\__________(2````
+M````"P````4```"(`````````/P2`````````@```#T"``#\_________PP3
+M`````````@```"`"``#\_________SL3`````````@```"`"``#\________
+M_\03`````````@````T"``#\_________]`3`````````@```)L```#\____
+M_____^L3`````````@```$T```#\_________U,4`````````@```$````#\
+M_________UX4`````````@```"@```#\_________XP4`````````@```!0`
+M``#\_________YX4`````````@```'@```#\_________[P4````````"P``
+M`*,``````````````,L4````````"P````4```"X`````````-44````````
+M`@```#T"``#\_________^L4`````````@```$D"``#\_________P$5````
+M`````@```$D"``#\_________QH5`````````@```"X```#\_________T`5
+M`````````@```"`"``#\_________XP5`````````@```"`"``#\________
+M_P\6`````````@```"`"``#\_________SP6`````````@```"`"``#\____
+M_____U86`````````@```!<```#\_________Z$6`````````@```"`"``#\
+M_________\86`````````@```"`"``#\_________UT7`````````@```"`"
+M``#\_________X(7`````````@```"`"``#\_________Z\7`````````@``
+M``T"``#\_________]$7`````````@```)T```#\_________Q88````````
+M`@```$T```#\_________TT8`````````@```$D"``#\_________V$8````
+M`````@```"\```#\_________W\8`````````@```%\```#\_________XD8
+M`````````@```#("``#\_________[L8````````"P````$```!P/P``````
+M`.X8`````````@```"L"``#\_________Q49`````````@```"`"``#\____
+M_____RH9`````````@```"`"``#\_________U(9`````````@```"`"``#\
+M_________V<9`````````@```"`"``#\_________Y@9`````````@```"`"
+M``#\_________\\9`````````@```"`"``#\_________Q,:`````````@``
+M`"`"``#\_________SP:`````````@```"`"``#\_________V(:````````
+M"P````4```#8`````````&P:`````````@```#T"``#\_________Y,:````
+M`````@```"`"``#\_________\H:`````````@```"`"``#\_________S0;
+M`````````@```"`"``#\_________UD;`````````@```"`"``#\________
+M_WX;`````````@```"`"``#\_________Z,;`````````@```"`"``#\____
+M______<;`````````@```$D"``#\_________R`<`````````@````T"``#\
+M_________S@<````````"P```)8``````````````$P<`````````@```"L"
+M``#\_________V8<````````"P````8``````````````'`<`````````@``
+M`#T"``#\_________Y\<`````````@```"`"``#\_________\4<````````
+M`@```"`"``#\_________^,<`````````@```#("``#\__________@<````
+M`````@```"`"``#\_________R$=`````````@```"`"``#\_________T<=
+M`````````@```"`"``#\_________V4=`````````@```#("``#\________
+M_WH=`````````@```"`"``#\_________YT=`````````@```"`"``#\____
+M_____\P=`````````@```!<```#\_________S`>`````````@```"\```#\
+M_________T\>`````````@```"\```#\_________V0>`````````@```*<`
+M``#\_________SL?`````````@```"\```#\_________U4?`````````@``
+M`"\```#\_________V(?`````````@```$T```#\_________Y,?````````
+M`@```$D"``#\_________Z<?`````````@```"\```#\_________\`?````
+M`````@```)8```#\_________Q<@`````````@```"\```#\_________S$@
+M`````````@```"\```#\_________R4A````````"P````8````=````````
+M`"\A`````````@```#T"``#\_________TDA`````````@```)D```#\____
+M_____XDA`````````@```#D```#\_________^<A`````````@```!,```#\
+M_________SLC`````````@```&T```#\_________^@C`````````@```)\`
+M``#\_________T$D`````````@```'P```#\_________UPD`````````@``
+M`)\```#\_________Q<E`````````@```%X```#\_________RHE````````
+M`@```&L```#\_________WXE`````````@```'<```#\_________YDE````
+M`````@```*@```#\_________Y\E`````````@```%`"``#[_________Z\E
+M`````````@```*T```#\_________\8E`````````@```*@```#\________
+M_],E`````````@```&\```#\_________^,E````````"P````4````(`0``
+M`````.TE`````````@```#T"``#\_________R<F`````````@```$T```#\
+M_________W(F`````````@```&4```#\_________\HF`````````@```&4`
+M``#\_________]<F`````````@```!X```#\__________LF`````````@``
+M`&4```#\_________RLG`````````@```#L```#\_________T4H````````
+M`@```"\```#\_________[4H`````````@```$T```#\_________^8H````
+M`````@```$D"``#\_________QLI`````````@```"\```#\_________R8I
+M`````````@```'D```#\_________ULI`````````@````T"``#\________
+M_W@I````````"P```)8``````````````)<I`````````@```"L"``#\____
+M_____]8I`````````@```"\```#\_________^DI`````````@```$$```#\
+M__________0I`````````@```&@```#\_________VPJ`````````@```'L`
+M``#\_________W<J`````````@```%````#\_________X0J`````````@``
+M`$````#\_________Y$J`````````@```%D```#\_________\<J````````
+M`@```$T```#\_________]8J`````````@```$````#\_________^(J````
+M`````@```%D```#\_________R(K`````````@```$X```#\_________R,L
+M`````````@```%`"``#[_________X`L`````````@```!0"``#\________
+M_Z0L`````````@```"`"``#\_________]TL`````````@```"`"``#\____
+M_____RTM`````````@```"`"``#\_________ULM`````````@```"`"``#\
+M_________]XM````````"P```*,``````````````/8M````````"P````4`
+M```X`0`````````N`````````@```#T"``#\_________RDN````````"P``
+M`*,``````````````$$N````````"P````4````X`0```````$LN````````
+M`@```#T"``#\_________WLN````````"P````4```!X`0```````(4N````
+M`````@```#T"``#\_________Y\N````````"P````4```"X`0```````*DN
+M`````````@```#T"``#\_________\,N`````````@```$````#\________
+M__8N`````````@```"`"``#\_________R(O`````````@```"`"``#\____
+M_____SPO`````````@```"`"``#\_________U<O`````````@```"`"``#\
+M_________W(O````````"P````4```#@`0```````'PO`````````@```#T"
+M``#\_________R<P`````````@```$D```#\_________T8P`````````@``
+M`"`"``#\_________W`P`````````@```"`"``#\_________^DP````````
+M`@```"`"``#\_________PDQ`````````@```"`"``#\_________RXQ````
+M`````@```*X```#\_________YLQ`````````@```"`"``#\_________R<R
+M`````````@```*X```#\_________S8R`````````@```*X```#\________
+M_X4R````````"P````4````@`@```````(\R`````````@```#T"``#\____
+M_____]XR````````"P````8````N`````````.@R`````````@```#T"``#\
+M__________HR`````````@```!H```#\_________QXS````````"P````4`
+M``!@`@```````"@S`````````@```#T"``#\_________]LS`````````@``
+M`!H```#\_________^8S`````````@```"@```#\_________S@T````````
+M`@```$\```#\_________VPT`````````@```$T```#\_________R4U````
+M`````@```$T```#\_________U(U`````````@```"@```#\_________V,U
+M`````````@```&@```#\_________Y4U`````````@```"`"``#\________
+M_\$U`````````@```"`"``#\_________]TU`````````@```"`"``#\____
+M______LU`````````@```"`"``#\_________Q<V`````````@```"`"``#\
+M_________RTV`````````@```(,```#\_________SPV`````````@```',`
+M``#\_________T@V`````````@```',```#\_________UDV`````````@``
+M`(,```#\_________^DV`````````@```"`"``#\_________PTW````````
+M`@```#("``#\_________SXW`````````@```"`"``#\_________V8W````
+M`````@```#("``#\_________YHW`````````@```"`"``#\_________\(W
+M`````````@```#("``#\_________PDX`````````@```'\```#\________
+M_R8X`````````@```&````#\_________S$X`````````@```!$```#\____
+M_____VDX`````````@```#(```#\_________[<X`````````@```"\```#\
+M_________\(X`````````@```!$```#\_________QHY`````````@```$T`
+M``#\_________S@Y`````````@```#0```#\_________T(Y`````````@``
+M`#("``#\_________WXY`````````@```!0```#\_________Y`Y````````
+M`@```'@```#\_________ZXY````````"P```*,``````````````+\Y````
+M````"P````4```"X`````````,DY`````````@```#T"``#\_________]\Y
+M`````````@```$D"``#\__________4Y`````````@```$D"``#\________
+M_PTZ`````````@```"X```#\_________R8Z`````````@```#(```#\____
+M_____[`Z`````````@```"`"``#\_________](Z`````````@```#("``#\
+M__________4Z`````````@```"`"``#\_________Q@[`````````@```"`"
+M``#\_________SH[`````````@```#("``#\_________UX[`````````@``
+M`"`"``#\_________^([`````````@```)T```#\_________^X[````````
+M`@```%@```#\_________S(\`````````@```%,```#\_________S\\````
+M`````@```)X```#\_________W@\`````````@```#("``#\_________Y,\
+M`````````@```"`"``#\_________[(\`````````@```"`"``#\________
+M_]$\`````````@```!$```#\_________]D\`````````@```*P```#\____
+M_____P4]`````````@```&H```#\_________X<]`````````@```$T```#\
+M_________Q8^`````````@```'D```#\_________RT^`````````@```$D"
+M``#\_________T0^`````````@```$D"``#\_________W8^`````````@``
+M`#("``#\_________Y$^`````````@```"`"``#\_________[$^````````
+M`@```"`"``#\_________]`^`````````@```!$```#\_________]@^````
+M`````@```*P```#\_________R`_`````````@```'\```#\_________UH_
+M`````````@```&H```#\_________^$_`````````@```"`"``#\________
+M_Q!``````````@```"`"``#\_________RA``````````@```%(```#\____
+M_____S5``````````@```)X```#\_________[5``````````@```"D```#\
+M_________]M``````````@```#X"``#\__________E``````````@```#X"
+M``#\_________Q=!`````````@```#X"``#\_________SU!`````````@``
+M`#X"``#\_________VA!`````````@```#X"``#\_________X)!````````
+M`@```#X"``#\_________Z!!`````````@```#X"``#\_________[I!````
+M`````@```#X"``#\_________]Q!`````````@```#X"``#\__________E!
+M`````````@```#X"``#\_________Q9"`````````@```#X"``#\________
+M_S-"`````````@```#X"``#\_________T]"`````````@```#X"``#\____
+M_____W-"`````````@```!("``#\_________Y-"`````````@```!("``#\
+M_________[I"`````````@```!("``#\_________]Y"`````````@```!("
+M``#\_________P)#`````````@```!("``#\_________R5#`````````@``
+M`!("``#\_________T5#`````````@```!("``#\_________V]#````````
+M`@```!("``#\_________Z1#`````````@```&@```#\_________U)$````
+M`````@```$T```#\_________X=$`````````@```$D"``#\_________YU$
+M`````````@```"\```#\_________ZM$`````````@```#0```#\________
+M_[5$`````````@```#("``#\_________]]$`````````@```#T```#\____
+M_____R]%`````````@```'L```#\_________T=%`````````@```$T```#\
+M_________X]%````````"P```*,``````````````)Y%````````"P````4`
+M``"(`@```````*A%`````````@```#T"``#\_________]U%````````"P``
+M`*,``````````````.Q%````````"P````4```"(`@```````/9%````````
+M`@```#T"``#\_________R)&`````````@```!H```#\_________T%&````
+M````"P````4```"X`@```````$M&`````````@```#T"``#\_________]Y&
+M`````````@```',```#\_________^I&````````"P````4```#P`@``````
+M`/1&`````````@```#T"``#\_________VU'`````````@```$````#\____
+M_____WE'`````````@```%D```#\_________\E'`````````@```$X```#\
+M_________R5)`````````@```"D```#\_________Z!)`````````@```$`"
+M``#\_________]Q)`````````@```$`"``#\_________Q-*`````````@``
+M`$`"``#\_________TM*`````````@```$`"``#\_________UY*````````
+M`@```$`"``#\_________W1*`````````@```$`"``#\_________]I*````
+M`````@```$`"``#\_________R5+`````````@```$`"``#\_________VA+
+M`````````@```$`"``#\_________[%+`````````@```$`"``#\________
+M_]I+`````````@```(0```#\_________^9+`````````@```$`"``#\____
+M_____P],`````````@```!````#\_________QM,`````````@```$`"``#\
+M_________T1,`````````@```!````#\_________U!,`````````@```$`"
+M``#\_________WE,`````````@```!````#\_________WQ.`````````@``
+M`$P"``#\_________Y9.`````````@```$P"``#\_________[!.````````
+M`@```$P"``#\_________\I.`````````@```$P"``#\_________^1.````
+M`````@```$P"``#\__________Y.`````````@```$P"``#\_________R1/
+M`````````@```$T```#\_________W1/`````````@```$P"``#\________
+M_Y5/`````````@```$T```#\_________^9/`````````@```$P"``#\____
+M_____PI0`````````@```$T```#\_________XU0`````````@```%0```#\
+M_________Z-0`````````@```$T```#\_________^90````````"P````4`
+M```8`P```````/!0`````````@```#T"``#\_________Q-1`````````@``
+M`!H```#\_________S)1````````"P````4```"X`@```````#Q1````````
+M`@```#T"``#\_________W%1````````"P````4````8`P```````'M1````
+M`````@```#T"``#\_________P-2`````````@```',```#\_________P]2
+M````````"P````4```#P`@```````!E2`````````@```#T"``#\________
+M_W=2`````````@```$````#\_________X-2`````````@```%D```#\____
+M_____[M2`````````@```)4```#\_________^)2````````"P````4````8
+M`P```````.Q2`````````@```#T"``#\_________PM6`````````@```"`"
+M``#\_________SY6`````````@```"`"``#\_________W56`````````@``
+M`"`"``#\_________ZI6`````````@```"`"``#\_________]]6````````
+M`@```"`"``#\_________^I6````````"P````4```!``P```````/16````
+M`````@```#T"``#\_________S=7`````````@```"`"``#\_________VI7
+M`````````@```"`"``#\_________YM7`````````@```"`"``#\________
+M_]!7`````````@```"`"``#\_________P18`````````@```"`"``#\____
+M_____P]8````````"P````4```!``P```````!E8`````````@```#T"``#\
+M_________TU8`````````@```$T```#\_________Z-8`````````@```(H`
+M``#\_________]-8`````````@```(H```#\_________P-9`````````@``
+M`)P```#\_________T-9`````````@```)P```#\_________Y!9````````
+M`@```",```#\_________YM9`````````@```%T```#\_________Y1:````
+M`````@```%4```#\_________]E:`````````@```%````#\_________Q=;
+M`````````@```$T```#\_________R);`````````@```!@```#\________
+M_RY;`````````@```%8```#\_________V1;`````````@```#D```#\____
+M_____W1;`````````@```"0```#\_________W!<`````````@```#D```#\
+M_________X!<`````````@```"0```#\__________%<`````````@```'H`
+M``#\_________X%=`````````@```+````#\_________[!=`````````@``
+M`#D```#\_________\!=`````````@```"0```#\_________Q!>````````
+M`@```&D```#\_________UQ>`````````@```*D```#\_________[A>````
+M`````@```(H```#\_________]=>`````````@```%4```#\_________^A>
+M`````````@```*D```#\_________Q9?`````````@````T"``#\________
+M_S9?`````````@````T"``#\_________Z!?`````````@```(H```#\____
+M_____\M?`````````@```%````#\_________]9?`````````@```'L```#\
+M_________XA@`````````@```$T```#\_________YM@`````````@```%0`
+M``#\_________[I@````````"P```*L``````````````-%@`````````@``
+M`"L"``#\_________TIA`````````@```$T```#\_________UUA````````
+M`@```'L```#\_________WAA````````"P```#X``````````````(]A````
+M`````@```"L"``#\_________QEB````````"P````,``````````````"!B
+M````````"P````8````[`````````"IB`````````@```#T"``#\________
+M_S1B`````````@```%D```#\_________T5B`````````@```"P```#\____
+M_____U!B`````````@```&4```#\_________SEC`````````@```$````#\
+M_________T1C`````````@```"@```#\_________Z1C`````````@```$T`
+M``#\_________TAD`````````@```&4```#\_________PYE````````"P``
+M`*L``````````````"5E`````````@```"L"``#\_________[)E````````
+M"P```#X``````````````,EE`````````@```"L"``#\_________RAF````
+M`````@```"\```#\_________S9F`````````@```#0```#\_________T!F
+M`````````@```#("``#\_________V%F`````````@```!0```#\________
+M_W)F`````````@```'@```#\_________X]F````````"P```*,`````````
+M`````*5F````````"P````4```!H`P```````*]F`````````@```#T"``#\
+M_________\1F`````````@```$D"``#\_________T1G`````````@```$D"
+M``#\_________WAG````````"P```*,``````````````(EG````````"P``
+M``8```!1`````````)-G`````````@```#T"``#\_________^IG````````
+M`@```$T```#\_________Q]H`````````@```$D"``#\_________SAH````
+M`````@```"X```#\_________X]H`````````@```(L```#\_________[UH
+M`````````@```$T```#\_________^UH`````````@```$T```#\________
+M_QEI`````````@```"0```#\_________Z!I`````````@```"`"``#\____
+M_____\1I`````````@```"`"``#\__________5J`````````@```&(```#\
+M_________U!K````````"P```"H``````````````%AK`````````@```#$`
+M``#\_________YAK`````````@```&(```#\_________P!L````````"P``
+M``$```!0DP```````!)L`````````@```#$```#\_________SIL````````
+M"P```+(``````````````*-L`````````@```&(```#\_________R5M````
+M`````@```#$```#\_________W]M`````````@```&(```#\_________^AM
+M`````````@```#$```#\_________UEN`````````@```#("``#\________
+M_VMN`````````@```"`"``#\_________Y-N`````````@```#("``#\____
+M_____Z5N`````````@```"`"``#\_________UQO`````````@```#("``#\
+M_________W%O`````````@```#0```#\_________]MO`````````@```"`"
+M``#\__________IO`````````@```"`"``#\_________Q9P`````````@``
+M`"8```#\_________]YR`````````@```#("``#\_________^MR````````
+M`@```"`"``#\_________P!S`````````@```#("``#\_________PIS````
+M`````@```"`"``#\_________\YS`````````@```#("``#\_________]MS
+M`````````@```"`"``#\__________!S`````````@```#("``#\________
+M__IS`````````@```"`"``#\_________Y=T`````````@```(P```#\____
+M_____\!T`````````@```*0```#\_________\AT`````````@```(4```#\
+M_________P]U`````````@```"`"``#\_________R]U`````````@```"`"
+M``#\_________TMU`````````@```"`"``#\_________WUU`````````@``
+M`"`"``#\_________^!U`````````@```#("``#\__________!U````````
+M`@```"`"``#\_________Q5V`````````@```#("``#\_________R5V````
+M`````@```"`"``#\_________R]W`````````@```#("``#\_________SYW
+M`````````@```"`"``#\_________U!W`````````@```#("``#\________
+M_UAW`````````@```"`"``#\_________W=W`````````@```#("``#\____
+M_____W]W`````````@```"`"``#\_________ZEW`````````@```#("``#\
+M_________[AW`````````@```"`"``#\_________\IW`````````@```#("
+M``#\_________])W`````````@```"`"``#\__________%W`````````@``
+M`#("``#\__________EW`````````@```"`"``#\_________SYX````````
+M`@```#("``#\_________VIX````````"P````4```"0`P```````'1X````
+M`````@```#T"``#\_________\EY`````````@```'(```#\_________^1Y
+M`````````@```'(```#\_________UYZ`````````@```+<```#\________
+M_Z![`````````@```#("``#\_________\M[`````````@```#("``#\____
+M_____UY\`````````@```*8```#\_________VU\`````````@```*8```#\
+M__________-\`````````@```"`"``#\_________R%]`````````@```"`"
+M``#\_________U)]`````````@```#("``#\_________VI]`````````@``
+M`"`"``#\_________[A]`````````@```"`"``#\_________Q]^````````
+M`@```"`"``#\_________Y)^`````````@```"`"``#\_________T5_````
+M`````@```#("``#\_________UA_`````````@```"`"``#\_________W1_
+M`````````@```#\```#\_________WY_`````````@```$P```#\________
+M_Y!_`````````@```#("``#\_________ZI_`````````@```#("``#\____
+M_____\1_`````````@```#("``#\_________^-_`````````@```%\```#\
+M__________1_`````````@```"`"``#\_________SR``````````@```#("
+M``#\_________T^``````````@```"`"``#\_________VN``````````@``
+M`#\```#\_________W6``````````@```$P```#\_________X>`````````
+M`@```#("``#\_________Z&``````````@```#("``#\_________[N`````
+M`````@```#("``#\_________]J``````````@```%\```#\_________^N`
+M`````````@```"`"``#\_________P^!`````````@```#("``#\________
+M_QF!`````````@```!$```#\_________SB!`````````@```*P```#\____
+M_____T6!`````````@```"`"``#\_________V"!`````````@```"`"``#\
+M_________WB!`````````@```"`"``#\_________VB"`````````@```"`"
+M``#\__________N"`````````@```&(```#\_________QF#`````````@``
+M`&8```#\_________S6#`````````@```"8```#\_________YN#````````
+M"P````$```!0DP```````*B#`````````@```)0```#\_________[>#````
+M`````@```'8```#\_________\*#`````````@```#$```#\_________WJ$
+M`````````@```&P```#\_________TN%`````````@```+0```#\________
+M_[Z%`````````@```$T```#\_________WV&`````````@```(\```#\____
+M_____RV'`````````@```$T```#\_________ZJ'`````````@```(\```#\
+M_________TB(`````````@```$D"``#\_________U^(`````````@```$D"
+M``#\_________Y&(`````````@```(\```#\_________P&)`````````@``
+M`$D"``#\_________U")`````````@```$D"``#\_________Y&)````````
+M`@```"\```#\_________Z2)`````````@```#0```#\_________ZZ)````
+M`````@```#("``#\_________\^)`````````@```!0```#\_________^")
+M`````````@```'@```#\__________.)````````"P````8```!O````````
+M`/V)`````````@```#T"``#\_________Q.*`````````@```$D"``#\____
+M_____R2*````````"P````8```!O`````````"Z*`````````@```#T"``#\
+M_________T2*`````````@```$D"``#\_________Y"*`````````@```$D"
+M``#\_________]B*`````````@```"X```#\__________2*`````````@``
+M`$D"``#\_________W.,`````````@```%,```#\_________WV,````````
+M`@```#("``#\_________YF,`````````@```%,```#\_________Z.,````
+M`````@```#("``#\_________S:-`````````@```"`"``#\_________TV-
+M`````````@```"`"``#\_________XR-`````````@```#("``#\________
+M_Z6-`````````@```'D```#\_________\*-`````````@```(D```#\____
+M_____]>-`````````@```(D```#\_________^6-`````````@```#("``#\
+M_________Q2.`````````@```"`"``#\_________SN.`````````@```"`"
+M``#\_________W6.````````"P```*,``````````````(2.````````"P``
+M``4```#``P```````(Z.`````````@```#T"``#\_________YZ.````````
+M`@```&(```#\__________2.````````"P````$```!0DP```````/^.````
+M`````@```#$```#\_________RN/````````"P```*,``````````````#J/
+M````````"P````4`````!````````$2/`````````@```#T"``#\________
+M_U2/`````````@```&(```#\_________Z./````````"P````$```!0DP``
+M`````*Z/`````````@```#$```#\_________]:/`````````@```&(```#\
+M_________RR0````````"P````$```!0DP```````#>0`````````@```#$`
+M``#\_________TV0`````````@```&(```#\_________Z.0````````"P``
+M``$```!0DP```````*Z0`````````@```#$```#\_________\20````````
+M`@```&(```#\_________Q.1````````"P````$```!0DP```````!Z1````
+M`````@```#$```#\_________SB1`````````@```&(```#\_________X>1
+M````````"P````$```!0DP```````)*1`````````@```#$```#\________
+M_ZB1`````````@```&(```#\_________P*2````````"P````$```!0DP``
+M``````V2`````````@```#$```#\_________SF2`````````@```$$```#\
+M_________VR2`````````@```*<```#\_________X22`````````@```$T`
+M``#\_________]:2`````````@```'D```#\__________^2`````````@``
+M`+0```#\_________Z*4````````"P```*,``````````````,&4````````
+M"P````4````H!````````,N4`````````@```#T"``#\_________PF5````
+M`````@```#("``#\_________VR5`````````@```(X```#\__________25
+M````````"P```*,```````````````R6````````"P````4```!@!```````
+M`!:6`````````@```#T"``#\_________SV6`````````@```#("``#\____
+M_____P>7`````````@```'D```#\_________QJ7`````````@```",```#\
+M_________R67`````````@```"8```#\_________VF7````````"P```'0`
+M`````````````'"7````````"P```+D``````````````(F7````````"P``
+M``,````@`````````+Z7````````"P```'0``````````````-N7````````
+M`@```(T```#\_________^R7````````"P```'0```````````````F8````
+M`````@```(T```#\_________QJ8````````"P```'0``````````````#>8
+M`````````@```(T```#\_________TB8````````"P```'0`````````````
+M`&68`````````@```(T```#\_________W:8````````"P```'0`````````
+M`````)*8`````````@```(T```#\_________Z.8````````"P```'0`````
+M`````````,"8`````````@```(T```#\_________]&8````````"P```'0`
+M`````````````.Z8`````````@```(T```#\__________^8````````"P``
+M`'0``````````````!R9`````````@```(T```#\_________T:9````````
+M`@```(T```#\_________V*9````````"P```'0``````````````'^9````
+M`````@```(T```#\_________["9````````"P```*,``````````````,.9
+M````````"P````4```"8!````````,V9`````````@```#T"``#\________
+M_^29````````"P```'0``````````````/.9`````````@```!T```#\____
+M_____PV:````````"P```'0``````````````!R:`````````@```!T```#\
+M_________U2:`````````@````T"``#\_________VF:````````"P```!8`
+M`````````````'V:`````````@```"L"``#\_________R&;`````````@``
+M`*<```#\_________S*;````````"P```+D``````````````$^;````````
+M`@```(T```#\_________V";````````"P```+D``````````````'V;````
+M`````@```(T```#\_________XZ;````````"P```+D``````````````*N;
+M`````````@```(T```#\_________]F;`````````@```'D```#\________
+M_P6<`````````@```*<```#\_________S.<`````````@```+0```#\____
+M_____[:<````````"P```*,``````````````,F<````````"P````4```#(
+M!````````-.<`````````@```#T"``#\_________^.<`````````@```*<`
+M``#\_________PF=`````````@````T"``#\_________QZ=````````"P``
+M`!8``````````````#*=`````````@```"L"``#\_________U*>````````
+M"P````4```#X!````````%R>`````````@```#T"``#\_________X2>````
+M`````@```$$```#\_________Y^>`````````@```",```#\_________ZJ>
+M`````````@```"8```#\_________\V>`````````@```+0```#\________
+M__6>`````````@```"`"``#\_________QB?`````````@```"`"``#\____
+M_____SN?`````````@```"`"``#\_________UZ?`````````@```"`"``#\
+M_________W&@`````````@```$$```#\_________WR@`````````@```"8`
+M``#\_________X>@`````````@```*<```#\_________ZN@`````````@``
+M`*<```#\_________\^@`````````@```*<```#\_________^^@````````
+M`@```*<```#\_________PVA`````````@```)T```#\_________SFA````
+M`````@```+0```#\_________U:A`````````@```%@```#\_________YJA
+M`````````@```%,```#\_________\^A`````````@```(D```#\________
+M_]VA`````````@```#("``#\_________RVB`````````@```"X```#\____
+M_____T2B`````````@```'$```#\_________W2B`````````@```*<```#\
+M_________Y:B`````````@````T"``#\_________Z*B`````````@```)L`
+M``#\_________[BB`````````@```$T```#\_________]JB`````````@``
+M`!0```#\_________^NB`````````@```'@```#\_________P&C````````
+M`@```$D"``#\_________Q:C`````````@```$D"``#\_________RVC````
+M`````@```"X```#\_________TZC`````````@```$T```#\_________U^C
+M`````````@```%@```#\_________Z"C`````````@```'D```#\________
+M_S^D`````````@```"8```#\_________Z"D````````"P````4````P!0``
+M`````*JD`````````@```#T"``#\_________\JD`````````@```"X```#\
+M_________]6D`````````@```"8```#\_________Q.E`````````@```)X`
+M``#\_________U"E`````````@```#("``#\_________UNE`````````@``
+M`"8```#\_________W"E`````````@```%,```#\_________WRE````````
+M`@```#("``#\_________X>E`````````@```"8```#\_________Y*E````
+M`````@```%$```#\_________["F`````````@```",```#\_________[NF
+M`````````@```"8```#\__________FF````````"P```*,`````````````
+M``^G````````"P````4```"(!0```````!FG`````````@```#T"``#\____
+M_____R>G`````````@```$$```#\_________S:G`````````@```*<```#\
+M_________VVG````````"P````4```#X!````````'>G`````````@```#T"
+M``#\_________YJG`````````@```$$```#\_________\6G`````````@``
+M`+0```#\_________PBH`````````@```"`"``#\_________RNH````````
+M`@```"`"``#\_________TZH`````````@```"`"``#\_________W&H````
+M`````@```"`"``#\_________X>H````````"P````,```#X`````````#:I
+M`````````@```",```#\_________T&I`````````@```"8```#\________
+M_U:I````````"P```(@``````````````&ZI`````````@```"L"``#\____
+M_____XNI`````````@````T"``#\_________Y:I`````````@```"8```#\
+M_________ZNI````````"P```),``````````````+^I`````````@```"L"
+M``#\_________S>J`````````@```#("``#\_________XZJ`````````@``
+M`%@```#\_________ZFJ`````````@```",```#\_________[2J````````
+M`@```"8```#\_________Q&K`````````@````T"``#\_________R:K````
+M````"P```$L``````````````#JK`````````@```"L"``#\_________TVK
+M`````````@```",```#\_________UBK`````````@```"8```#\________
+M_W&K`````````@```",```#\_________WRK`````````@```"8```#\____
+M_____X>K`````````@```*<```#\_________\BK`````````@```"`"``#\
+M_________^2M`````````@```(8```#\__________&M`````````@```"<`
+M``#\_________S:N`````````@```(````#\_________WFN`````````@``
+M`!P```#\_________ZJN`````````@```'\```#\_________P:O````````
+M`@```#("``#\_________V6T`````````@````L````<`````````'&T````
+M````"P````L````@`````````'ZT`````````@```#,```#\_________\:T
+M`````````@```$@```#\_________[.U`````````@```#<```#\________
+M_^JU`````````@```'\```#\__________BV`````````@```#("``#\____
+M_____^.W`````````@````L````>`````````/"W````````"P````L````@
+M`````````/JW`````````@```#,```#\_________SNX`````````@````L`
+M```>`````````$BX````````"P````L````@`````````%*X`````````@``
+M`#,```#\_________].X`````````@```"`"``#\_________R&Y````````
+M`@```"`"``#\_________SFY`````````@```"(```#\_________TNY````
+M`````@```"(```#\_________UVY`````````@```"(```#\_________V^Y
+M`````````@```"(```#\_________X&Y`````````@```"(```#\________
+M_Y.Y`````````@```"(```#\_________Z6Y`````````@```"(```#\____
+M_____[>Y`````````@```"(```#\_________\FY`````````@```"(```#\
+M_________]NY`````````@```"(```#\_________^VY`````````@```"(`
+M``#\__________^Y`````````@```"(```#\_________Q&Z`````````@``
+M`"(```#\_________R.Z`````````@```"(```#\_________S6Z````````
+M`@```"(```#\_________T>Z`````````@```"(```#\_________UFZ````
+M`````@```"(```#\_________VNZ`````````@```"(```#\_________WVZ
+M`````````@```"(```#\_________X^Z`````````@```"(```#\________
+M_Z&Z`````````@```"(```#\_________[.Z`````````@```"(```#\____
+M_____\6Z`````````@```"(```#\_________]>Z`````````@```"(```#\
+M_________^FZ`````````@```"(```#\__________NZ`````````@```"(`
+M``#\_________V.[`````````@```"`"``#\_________X.[`````````@``
+M`"`"``#\_________P6\`````````@```"(```#\_________QJ\````````
+M`@```"(```#\_________R^\`````````@```"(```#\_________T2\````
+M`````@```"(```#\_________UF\`````````@```"(```#\_________[F^
+M`````````@```"$```#\_________]&^`````````@```)<```#\________
+M_W:_`````````@```&$```#\_________XN_````````"P```$4`````````
+M`````,N_`````````@```"$```#\_________]V_`````````@```)<```#\
+M_________W3``````````@```&$```#\_________Z'``````````@```&$`
+M``#\_________T_!`````````@```'4```#\_________V?!`````````@``
+M`"L```#\_________W_!`````````@```%H```#\_________^?!````````
+M"P````,```!P`0```````#3%`````````@```!4```#\_________\+%````
+M`````@```!4```#\_________]O%`````````@```!0"``#\_________[3&
+M`````````@```!H```#\_________W3'`````````@```"`"``#\________
+M_XC'`````````@```"`"``#\_________Y;'`````````@```#("``#\____
+M_____]_'`````````@````<````$`````````"K(`````````@```"`"``#\
+M_________U[(````````"P````<``````````````(;(`````````@````<`
+M```4`````````-3(`````````@```"`"``#\_________TG)`````````@``
+M``<````D`````````)?)`````````@```"`"``#\_________\O)````````
+M"P````<````@`````````.[)`````````@````<````T`````````#S*````
+M`````@```"`"``#\_________Z?*````````"P````<````0`````````+G*
+M````````"P````<````P`````````$_+`````````@```"`"``#\________
+M_^++`````````@```"`"``#\_________X',`````````@```"`"``#\____
+M_____Z#,`````````@```#("``#\_________V[-`````````@```!\```#\
+M_________R#0`````````@```)(```#\_________Z?1`````````@````,`
+M``#(`@```````+/1````````"P````<```#``0```````+;2`````````@``
+M`((```#\_________^'2`````````@```+````#\_________S?4````````
+M"P````<```"``````````#S4`````````@````4"``#\_________[K4````
+M`````@```#,```#\_________\C4`````````@```#("``#\_________]W4
+M`````````@```*4```#\_________P?5````````"P````8```"%````````
+M`!'5`````````@```#T"``#\_________U[5`````````@```"@"``#\____
+M_____W#5`````````@```"@"``#\_________X+5`````````@```"@"``#\
+M__________/5`````````@```"D```#\_________PO6`````````@```#$"
+M``#\_________Q[6`````````@```#$"``#\_________S;6`````````@``
+M`#$"``#\_________TG6`````````@```#$"``#\_________V'6````````
+M`@```#$"``#\_________W36`````````@```#$"``#\_________XS6````
+M`````@```#$"``#\_________Y_6`````````@```#$"``#\_________[?6
+M`````````@```#$"``#\_________\K6`````````@```#$"``#\________
+M_^+6`````````@```#$"``#\__________76`````````@```#$"``#\____
+M_____PW7`````````@```#$"``#\_________R#7`````````@```#$"``#\
+M_________SC7`````````@```#$"``#\_________TO7`````````@```#$"
+M``#\_________V/7`````````@```#$"``#\_________W;7`````````@``
+M`#$"``#\_________X[7`````````@```#$"``#\_________Z'7````````
+M`@```#$"``#\_________[G7`````````@```#$"``#\_________\S7````
+M`````@```#$"``#\_________^37`````````@```#$"``#\__________?7
+M`````````@```#$"``#\_________P_8`````````@```#$"``#\________
+M_R+8`````````@```#$"``#\_________T'8`````````@```&("``#\____
+M_____UO8`````````@```&("``#\_________WK8`````````@```&("``#\
+M_________Y38`````````@```&("``#\_________[/8`````````@```&("
+M``#\_________\W8`````````@```&("``#\_________^S8`````````@``
+M`&("``#\_________P;9`````````@```&("``#\_________R79````````
+M`@```&("``#\_________S_9`````````@```&("``#\_________U[9````
+M`````@```&("``#\_________WC9`````````@```&("``#\_________Y?9
+M`````````@```&("``#\_________['9`````````@```&("``#\________
+M_]#9`````````@```&("``#\_________^K9`````````@```&("``#\____
+M_____Q+:`````````@```"4```#\_________QK:`````````@```&<```#\
+M_________RG:`````````@```&<```#\_________S':`````````@```+4`
+M``#\_________SO:`````````@```#("``#\_________T/:`````````@``
+M`'T```#\_________U#:`````````@```(,```#\_________UW:````````
+M`@```(,```#\_________WW:`````````@```(,```#\_________Y7:````
+M`````@```*H```#\_________ZC:`````````@```*H```#\_________[7:
+M`````````@```*H```#\_________\C:`````````@```*H```#\________
+M_]7:`````````@```#0```#\_________][:`````````@```$8"``#[____
+M_____SW;`````````@```&(```#\_________YK;````````"P````$````P
+MT@```````*7;`````````@```#$```#\_________]S;`````````@```"\`
+M``#\_________^[;`````````@```#("``#\__________;;`````````@``
+M`#0```#\_________SS<`````````@```"8```#\_________[/<````````
+M`@```&(```#\_________R[=````````"P````$````PT@```````#G=````
+M`````@```#$```#\_________W#=`````````@```"\```#\_________X+=
+M`````````@```#("``#\_________XK=`````````@```#0```#\________
+M_\+=`````````@```"8```#\_________W_>`````````@```",```#\____
+M_____XW>`````````@```%T```#\_________YC>`````````@```"8```#\
+M_________[_?`````````@```$8```#\_________P?@````````"P````$`
+M```PT@```````!3@`````````@```)0```#\_________R?@`````````@``
+M`'8```#\_________SG@`````````@```#$```#\_________VG@````````
+M`@```"\```#\_________W[@`````````@```#("``#\_________X;@````
+M`````@```#0```#\_________SGA`````````@```&(```#\_________UGA
+M````````"P````8```"A`````````&/A`````````@```#T"``#\________
+M_W7A`````````@```&8```#\_________XWA`````````@```"8```#\____
+M_____\GA`````````@```$D"``#\_________^#A`````````@```"\```#\
+M_________V/B````````"P````4```#`!0```````&WB`````````@```#T"
+M``#\_________Z/B`````````@```!0"``#\__________'B`````````@``
+M`!0"``#\_________R?C`````````@```",```#\_________SOC````````
+M`@```%T```#\_________U7C`````````@```"8```#\_________W'C````
+M`````@```$D"``#\_________VCD`````````@```"\```#\_________[KD
+M`````````@```*<```#\_________\_D`````````@```'D```#\________
+M_Q'E`````````@```$L"``#\_________TGE`````````@```"4```#\____
+M_____U'E`````````@```$0```#\_________UGE`````````@```$0```#\
+M_________V;E`````````@```(,```#\_________V[E`````````@```&<`
+M``#\_________WKE`````````@```&<```#\_________X;E`````````@``
+M`+4```#\_________Y#E`````````@```#("``#\_________YCE````````
+M`@```'T```#\_________ZWE````````"P```$<``````````````,3E````
+M`````@```"L"``#\_________]'E`````````@```+0```#\__________7E
+M`````````@```+$```#\_________P3F`````````@```+$```#\________
+M_RGF`````````@````L```"_`````````#;F`````````@````L```"\````
+M`````$'F`````````@````,```#(`@```````%#F````````"P````<```#`
+M`0```````%?F````````"P```$,``````````````%[F````````"P````<`
+M``#4`0```````&KF````````"P````<```#"`0```````+7F````````"P``
+M`$,````<`````````,WF````````"P```$,````<`````````.'F````````
+M"P```$,````<`````````._F````````"P```$,````<`````````/GF````
+M````"P```$,````<`````````"_G````````"P```$,````<`````````$/G
+M````````"P```$,````<`````````%'G````````"P```$,````<````````
+M`&SG````````"P````<```#,`0```````+7G`````````@````,```#(`@``
+M`````-/G````````"P````<```#,`0```````.'G````````"P````<```#0
+M`0```````!'H````````"P```$,``````````````"7H````````"P```$,`
+M```<`````````%#H````````"P```$,````,`````````';H````````"P``
+M`$,````=`````````(7H````````"P```$,````<`````````+[H````````
+M`@````X"``#\_________S;I`````````@```)$```#\_________U3I````
+M`````@```'@```#\_________VSI`````````@```'@```#\_________P[J
+M````````"P```*,``````````````"/J````````"P````4```#H!0``````
+M`"WJ`````````@```#T"``#\_________S_J`````````@```&(```#\____
+M_____VCJ````````"P```*,``````````````'WJ````````"P````4````8
+M!@```````(?J`````````@```#T"``#\_________\?J````````"P````$`
+M```PT@```````-+J`````````@```#$```#\_________PGK`````````@``
+M`"\```#\_________QOK`````````@```#("``#\_________R/K````````
+M`@```#0```#\_________T#K`````````@```"8```#\_________VSK````
+M`````@```&(```#\_________X[K`````````@```&8```#\_________ZGK
+M`````````@```"8```#\_________POL````````"P````$````PT@``````
+M`!CL`````````@```)0```#\_________RCL`````````@```'8```#\____
+M_____S/L`````````@```#$```#\_________VKL`````````@```"\```#\
+M_________WSL`````````@```#("``#\_________X3L`````````@```#0`
+M``#\_________[+L`````````@```(X```#\_________]/L`````````@``
+M`",```#\_________][L`````````@```"8```#\_________R_M````````
+M"P````,```!@`@```````%OM`````````@```)````#\_________XOM````
+M`````@```$H```#\_________Y?M`````````@```'````#\_________Z?M
+M`````````@```*$```#\_________P/N````````"P```*,`````````````
+M`![N````````"P````4```!(!@```````"CN`````````@```#T"``#\____
+M_____UCN`````````@````T"``#\_________VWN````````"P````$```#`
+M[0```````('N`````````@```"L"``#\_________P7Q`````````@```)``
+M``#\_________U/Q`````````@```((```#\_________V3Q`````````@``
+M`'@```#\_________YGQ`````````@```#0```#\_________[_Q````````
+M`@```+0```#\_________]_Q`````````@````T"``#\__________3Q````
+M````"P```$<```````````````?R`````````@```"L"``#\_________W;R
+M`````````@````L```"\`````````(+R`````````@````L```"\````````
+M`&_T`````````@```!P"``#\_________XGT`````````@```!P"``#\____
+M_____]/T`````````@````,```#(`@```````.GT````````"P````<```#`
+M`0```````/OT````````"P````<```#"`0````````GU````````"P````<`
+M``#0`0```````!+U````````"P````<```#0`0```````!GU````````"P``
+M``<```#,`0```````#/U````````"P````<```#0`0```````&WU````````
+M`@```%8"``#\_________X_U`````````@```$X"``#\_________[WU````
+M````"P```$,``````````````-7U````````"P```$,````<`````````/SU
+M````````"P```$,````,`````````!GV````````"P```$,````=````````
+M`"/V````````"P```$,````=`````````"OV````````"P```$,````<````
+M`````$CV````````"P```$,````=`````````%SV````````"P```$,````<
+M`````````*SW````````"P```*,``````````````!3Y`````````@```&(`
+M``#\_________ZO\````````"P````$```#PW0````````S]`````````@``
+M`$8```#\_________QG]`````````@```)0```#\_________RS]````````
+M`@```'8```#\_________TK]`````````@```)0```#\_________U[]````
+M`````@```&8```#\_________Y']`````````@```'8```#\_________Z+]
+M`````````@```%<```#\_________]7]`````````@```'8```#\________
+M_Q;^`````````@```!0"``#\_________XG^`````````@```!0"``#\____
+M_____\?^`````````@```#$```#\_________]?^`````````@```"8```#\
+M_________U@!`0```````@```%8"``#\_________WH!`0```````@```%8"
+M``#\__________`"`0```````@```$T```#\_________T@#`0```````@``
+M`'D```#\_________V\#`0```````@```*<```#\_________YD#`0``````
+M`@```$T```#\__________<#`0```````@```(\```#\_________ZD$`0``
+M`````@```)8!``#\_________\($`0```````@```-0!``#\_________]<$
+M`0```````@```-,!``#\_________V4%`0``````"P````$```!@!`$`````
+M`'T%`0```````@```%,!``#\_________Y,%`0```````@```+P```#\____
+M_____YX%`0```````@```-,```#\_________[8%`0```````@```#("``#\
+M_________\$%`0```````@```.4```#\_________^`%`0```````@```+X`
+M``#\_________^\%`0```````@````4!``#\__________H%`0```````@``
+M`-,!``#\_________Q@&`0```````@```-,!``#\_________S,&`0``````
+M`@````@!``#\_________U`&`0```````@```%<!``#\_________[(&`0``
+M`````@```%,!``#\_________\8&`0```````@```+P```#\_________V@)
+M`0```````@```#L!``#\_________^H+`0``````"P````,```#@`@``````
+M`(L,`0``````"P````4```!X!@```````)4,`0```````@```#T"``#\____
+M_____]`,`0```````@```!0"``#\_________Y0-`0```````@```"`"``#\
+M_________[T-`0```````@```"`"``#\_________QT.`0```````@```"`"
+M``#\_________Y\.`0```````@```"`"``#\_________]D.`0```````@``
+M`"`"``#\_________SX/`0```````@```#("``#\_________WD/`0``````
+M`@```#("``#\_________\</`0```````@```#("``#\_________P(0`0``
+M`````@```#("``#\_________U@0`0```````@```.8```#\_________V(0
+M`0```````@```#("``#\_________VP0`0```````@```)$!``#\________
+M_T<1`0```````@```"`"``#\_________V01`0```````@```"`"``#\____
+M_____W,1`0```````@```#("``#\_________X\1`0```````@```"`"``#\
+M_________ZP1`0```````@```"`"``#\_________]H1`0```````@```"`"
+M``#\_________^01`0```````@```"`"``#\_________PP2`0```````@``
+M`#("``#\_________QD2`0```````@```"`"``#\_________T$2`0``````
+M`@```#("``#\_________TX2`0```````@```"`"``#\_________W\2`0``
+M`````@```"`"``#\_________[`2`0```````@```"`"``#\_________Q43
+M`0```````@```"`"``#\_________S43`0```````@```"`"``#\________
+M_UP3`0```````@```"`"``#\_________WP3`0```````@```"`"``#\____
+M_____ZP3`0```````@```"`"``#\_________[83`0```````@```"`"``#\
+M_________^(3`0```````@```#("``#\__________(3`0```````@```"`"
+M``#\_________QH4`0```````@```#("``#\_________RH4`0```````@``
+M`"`"``#\_________S06`0```````@```"`"``#\_________WP6`0``````
+M`@```&$!``#\_________Z@6`0```````@```&$!``#\_________Q87`0``
+M`````@```*0!``#\_________W07`0```````@````T"``#\_________X`7
+M`0```````@```&(!``#\_________YD7`0```````@```%D!``#\________
+M_T$8`0```````@```*0!``#\_________W`8`0```````@```(D!``#\____
+M_____X$8`0```````@```$T!``#\_________Y08`0``````"P````8```#!
+M`````````)X8`0```````@```#T"``#\_________[,8`0```````@```$D"
+M``#\_________\@8`0```````@```$D"``#\_________^`8`0```````@``
+M`.H```#\_________P(9`0```````@```"`"``#\__________P9`0``````
+M"P```-$```````````````$:`0```````@```&\!``#\_________^T:`0``
+M`````@```-````#\__________@:`0```````@```-,!``#\_________^X;
+M`0```````@```$\!``#\_________V$?`0```````@```-(!``#\________
+M_]D?`0```````@```/````#\_________QP@`0```````@```$\!``#\____
+M_____[P@`0``````"P````,```#@!@```````-4@`0```````@```*,!``#\
+M_________P<A`0```````@```*,!``#\_________S<A`0```````@```*,!
+M``#\_________V,A`0```````@```*,!``#\_________YHA`0```````@``
+M`#(!``#\_________^8A`0```````@```*8!``#\_________W@B`0``````
+M`@```,@```#\_________[<B`0```````@```/$```#\_________^$B`0``
+M`````@```#("``#\_________SLE`0```````@```+P!``#\_________THE
+M`0```````@```(0!``#\_________P$F`0```````@```-P```#\________
+M_WLF`0```````@```'H!``#\_________Y@F`0```````@```-P```#\____
+M_____[PG`0```````@```-$!``#\_________\\G`0```````@```&,!``#\
+M_________STH`0```````@```-$!``#\_________VDH`0```````@```&,!
+M``#\_________P(J`0```````@```*4!``#\_________^HJ`0```````@``
+M`!0"``#\_________P0K`0``````"P````,````P!P```````)<K`0``````
+M`@```+L```#\_________Z8K`0```````@```+L```#\_________R,L`0``
+M`````@```-$!``#\_________T\L`0```````@```&,!``#\_________[XL
+M`0```````@```!@!``#\__________(L`0```````@````0!``#\________
+M_PLM`0```````@```!@!``#\_________QHM`0```````@```)(!``#\____
+M_____S,M`0```````@```!@!``#\_________X,M`0```````@````P!``#\
+M_________Y@M`0``````"P````4```#0!@```````*(M`0```````@```#T"
+M``#\_________Q0N`0```````@```%D!``#\_________R8N`0```````@``
+M`-<```#\_________\(N`0```````@```)P!``#\_________S\O`0``````
+M`@```)P!``#\_________T\O`0```````@```*`!``#\_________WDO`0``
+M`````@```)P!``#\_________Y<O`0```````@```&8!``#\_________\0O
+M`0```````@````<!``#\_________X,P`0```````@```",!``#\________
+M_Z8P`0```````@```&8!``#\_________\\P`0```````@```!<!``#\____
+M______8P`0```````@```)P!``#\__________XP`0```````@```!<!``#\
+M_________R,Q`0```````@```&8!``#\_________XDQ`0```````@```+\`
+M``#\_________]<Q`0```````@```($!``#\__________LQ`0```````@``
+M`%D!``#\_________S(R`0```````@```$D"``#\_________T8R`0``````
+M`@```+\```#\_________V0R`0```````@```.4```#\_________VXR`0``
+M`````@```#("``#\_________[TR`0```````@```$H!``#\_________\0R
+M`0```````@```),!``#\_________]HR`0``````"P````8```#7````````
+M`.0R`0```````@```#T"``#\_________QLS`0```````@```+\```#\____
+M_____RXS`0```````@```"H!``#\_________S8S`0```````@```!<!``#\
+M_________\<S`0```````@```"`"``#\__________,S`0```````@```"`"
+M``#\_________RPT`0```````@```"`"``#\_________VHT`0``````"P``
+M``4`````!P```````'0T`0```````@```#T"``#\_________[`T`0``````
+M`@```$X!``#\_________P8U`0```````@```$X!``#\_________QLU`0``
+M`````@```,P!``#\_________R8U`0```````@```",!``#\_________]@U
+M`0```````@```-(```#\__________\U`0```````@```&8!``#\________
+M_S0V`0```````@```%D!``#\_________](V`0```````@```-(```#\____
+M______0V`0```````@```&8!``#\_________S<W`0```````@```,<!``#\
+M_________V@X`0```````@```"`"``#\_________X8X`0```````@```"`"
+M``#\_________Z,X`0```````@```"`"``#\_________P@Y`0```````@``
+M`"`"``#\_________R\Y`0```````@```"`"``#\_________YLY`0``````
+M`@```(<!``#\__________@Y`0```````@```"`"``#\_________QLZ`0``
+M`````@```"`"``#\_________SXZ`0```````@```"`"``#\_________T8Z
+M`0```````@````\!``#\_________S<[`0```````@```-T```#\________
+M_UH[`0```````@```!0"``#\_________T(\`0```````@```!0"``#\____
+M_____[`\`0```````@```!0"``#\_________^0\`0```````@```"`"``#\
+M_________Q\]`0```````@```"`"``#\_________W,]`0```````@```"`"
+M``#\_________U$^`0```````@```!0"``#\_________Z4_`0```````@``
+M`!0"``#\_________RU``0```````@```!0"``#\_________T!``0``````
+M"P````,```"0#````````-5``0```````@```#("``#\_________U-!`0``
+M`````@```"`"``#\_________W=!`0```````@```"`"``#\_________YQ!
+M`0``````"P````8```#U`````````*9!`0```````@```#T"``#\________
+M_[!!`0```````@```&P!``#\_________S="`0```````@```"`"``#\____
+M_____\)"`0```````@```&P!``#\_________]%"`0```````@```&P!``#\
+M_________QQ#`0``````"P````4```!0!P```````"9#`0```````@```#T"
+M``#\_________X]#`0``````"P````8````0`0```````)E#`0```````@``
+M`#T"``#\_________ZM#`0```````@```%@!``#\_________]5#`0``````
+M"P````4```"0!P```````-]#`0```````@```#T"``#\_________U)$`0``
+M````"P````4```"X!P```````%Q$`0```````@```#T"``#\__________Y$
+M`0```````@```-(```#\_________Q=%`0```````@```&8!``#\________
+M_\I%`0```````@```#\!``#\_________RY'`0```````@```%@!``#\____
+M_____SY'`0```````@```*0!``#\_________X)'`0```````@```!$!``#\
+M_________^E'`0```````@```-(```#\__________1'`0```````@```#\!
+M``#\_________PU(`0```````@```&8!``#\_________V=(`0```````@``
+M`%D!``#\_________^!(`0```````@```,$```#\_________Q=)`0``````
+M`@```%D!``#\_________^1)`0```````@```%D!``#\_________QE*`0``
+M`````@```*0!``#\_________RI*`0```````@```!<!``#\_________V5*
+M`0```````@```"`"``#\_________Y%*`0```````@```"`"``#\________
+M_ZU*`0```````@```"`"``#\_________\M*`0```````@```"`"``#\____
+M_____^=*`0```````@```"`"``#\__________U*`0```````@```"$!``#\
+M_________PQ+`0```````@```!X!``#\_________QA+`0```````@```!X!
+M``#\_________RE+`0```````@```"$!``#\_________VQ+`0```````@``
+M`"`"``#\__________%+`0```````@```"`"``#\_________QQ,`0``````
+M`@```"`"``#\_________RY,`0```````@```/<```#\_________W%,`0``
+M`````@```"`"``#\_________Y9,`0```````@```"`"``#\_________Q--
+M`0```````@```"`"``#\_________SQ-`0```````@```"`"``#\________
+M_VA-`0```````@````T"``#\_________XE-`0```````@```'8!``#\____
+M_____\E-`0```````@```%D!``#\__________]-`0```````@```$D"``#\
+M_________Q-.`0```````@```+\```#\_________S%.`0```````@```!T!
+M``#\_________SM.`0```````@```#("``#\_________VM.`0``````"P``
+M``$```#`8P$``````)E.`0```````@```"L"``#\_________\-.`0``````
+M`@```"`"``#\_________]A.`0```````@```"`"``#\_________P!/`0``
+M`````@```"`"``#\_________Q5/`0```````@```"`"``#\_________T9/
+M`0```````@```"`"``#\_________WU/`0```````@```"`"``#\________
+M_[M/`0```````@```"`"``#\_________^-/`0```````@```"`"``#\____
+M_____QA0`0```````@```"`"``#\_________T]0`0```````@```"`"``#\
+M_________[90`0```````@```"`"``#\_________]M0`0```````@```"`"
+M``#\_________P!1`0```````@```"`"``#\_________R51`0```````@``
+M`"`"``#\_________V11`0```````@````T"``#\_________YY1`0``````
+M`@```$D"``#\_________[)1`0```````@```+\```#\_________\11`0``
+M`````@```.4```#\_________\Y1`0```````@```#("``#\__________M1
+M`0``````"P```),!`````````````!-2`0```````@```"L"``#\________
+M_SY2`0```````@```"`"``#\_________W!2`0```````@```"`"``#\____
+M_____ZE2`0```````@```"`"``#\_________]52`0```````@```"`"``#\
+M_________Q93`0```````@````T"``#\_________S13`0```````@```%D!
+M``#\_________V13`0```````@```$D"``#\_________X)3`0``````"P``
+M`%8!`````````````)13`0```````@```"L"``#\_________\-3`0``````
+M`@```"`"``#\_________^E3`0```````@```"`"``#\_________P=4`0``
+M`````@```#("``#\_________QQ4`0```````@```"`"``#\_________T)4
+M`0```````@```"`"``#\_________VA4`0```````@```"`"``#\________
+M_X94`0```````@```#("``#\_________YM4`0```````@```"`"``#\____
+M_____\!4`0```````@```"`"``#\_________Y95`0```````@```"`"``#\
+M_________[M5`0```````@```#("``#\_________^M5`0```````@```"`"
+M``#\_________Q)6`0```````@```#("``#\_________T56`0```````@``
+M`"`"``#\_________VQ6`0```````@```#("``#\_________[)6`0``````
+M`@```"P!``#\_________\U6`0```````@```'`!``#\_________]E6`0``
+M`````@```#X!``#\_________PY7`0```````@```#H!``#\_________T)7
+M`0```````@```!L!``#\_________V]7`0```````@```#X!``#\________
+M_UA8`0```````@```#("``#\_________W]8`0```````@```"`"``#\____
+M_____YY8`0```````@```#("``#\_________\%8`0```````@```"`"``#\
+M_________^U8`0```````@```#("``#\_________Q19`0```````@```"`"
+M``#\_________SA9`0```````@```#("``#\_________UQ9`0```````@``
+M`"`"``#\_________WU9`0```````@```%D!``#\__________I9`0``````
+M`@```+\```#\_________S5:`0```````@```+\```#\_________T%:`0``
+M`````@```#X!``#\_________X9:`0```````@```%D!``#\_________ZM:
+M`0```````@```%D!``#\_________\Q:`0```````@````T"``#\________
+M_^M:`0```````@```.4```#\__________5:`0```````@```#("``#\____
+M_____[);`0```````@```*0!``#\_________]1;`0```````@```(D!``#\
+M_________^5;`0```````@```$T!``#\__________A;`0``````"P````8`
+M``#!``````````)<`0```````@```#T"``#\_________Q=<`0```````@``
+M`$D"``#\_________RQ<`0```````@```$D"``#\_________TE<`0``````
+M`@```.H```#\_________VA<`0```````@```/0```#\_________Y1<`0``
+M`````@```%D!``#\_________[E<`0```````@```.4```#\_________\-<
+M`0```````@```#("``#\__________9<`0```````@```(D!``#\________
+M_P==`0```````@```$T!``#\_________QI=`0``````"P````8```#!````
+M`````"1=`0```````@```#T"``#\_________SE=`0```````@```$D"``#\
+M_________TY=`0```````@```$D"``#\_________V9=`0```````@```.H`
+M``#\_________WM=`0```````@```#H!``#\__________Q=`0```````@``
+M`"`"``#\_________QY>`0```````@```#("``#\_________T%>`0``````
+M`@```"`"``#\_________V1>`0```````@```"`"``#\_________X9>`0``
+M`````@```#("``#\_________ZI>`0```````@```"`"``#\_________S)?
+M`0```````@```'8!``#\_________SY?`0```````@```$$!``#\________
+M_X5?`0```````@```)X!``#\_________Y)?`0```````@```$4!``#\____
+M_____\A?`0```````@```#("``#\_________^-?`0```````@```"`"``#\
+M_________P)@`0```````@```"`"``#\_________R%@`0```````@```#X!
+M``#\_________RE@`0```````@```!P!``#\_________U%@`0```````@``
+M`)\!``#\_________]A@`0```````@```%8!``#\_________^5@`0``````
+M`@```%D!``#\_________W!A`0```````@```+X!``#\_________Z1A`0``
+M`````@```$H!``#\_________]UA`0```````@```*H!``#\__________5A
+M`0```````@```$D"``#\_________PUB`0```````@```$D"``#\________
+M_SIB`0```````@```#("``#\_________U5B`0```````@```"`"``#\____
+M_____W)B`0```````@```"`"``#\_________Y%B`0```````@```#X!``#\
+M_________YEB`0```````@```!P!``#\_________]]B`0```````@```"P!
+M``#\_________R1C`0```````@```%D!``#\_________Z-C`0```````@``
+M`)\!``#\_________[)C`0```````@```/T```#\_________RMD`0``````
+M`@```"`"``#\_________UID`0```````@```"`"``#\_________W)D`0``
+M`````@```+\!``#\_________W]D`0```````@```$4!``#\_________^ED
+M`0```````@```(`!``#\_________PQE`0```````@```&8!``#\________
+M_S1E`0```````@```!<!``#\_________UAE`0```````@```)P!``#\____
+M_____V!E`0```````@```!<!``#\_________ZEE`0```````@```&8!``#\
+M__________IE`0```````@```+\```#\_________PEF`0```````@```%D!
+M``#\_________SAF`0```````@```$D"``#\_________TQF`0```````@``
+M`+\```#\_________V1F`0```````@```.4```#\_________VYF`0``````
+M`@```#("``#\_________XYF`0```````@```),!``#\_________[UF`0``
+M`````@```&8!``#\_________^]F`0```````@```+\```#\_________P9G
+M`0```````@```%D!``#\_________R)G`0```````@```(D!``#\________
+M_S-G`0```````@```$T!``#\_________TAG`0```````@```$D"``#\____
+M_____UUG`0```````@```$D"``#\_________W!G`0```````@```.H```#\
+M_________X)G`0```````@```&(!``#\_________YMG`0```````@```"`"
+M``#\__________5G`0```````@```#X!``#\_________P!H`0```````@``
+M`#H!``#\_________Y9H`0```````@```"`"``#\_________[%H`0``````
+M`@```%@!``#\_________\%H`0```````@```*0!``#\_________^1H`0``
+M`````@```%@!``#\_________^QH`0```````@```&H!``#\_________P5I
+M`0``````"P````,```#P#````````!QI`0```````@````(!``#\________
+M_SAI`0```````@````(!``#\_________U1I`0```````@```+\```#\____
+M_____W=I`0```````@```($!``#\_________XYI`0```````@```-X```#\
+M_________[%I`0```````@```+\```#\_________\]I`0```````@```($!
+M``#\_________^9I`0```````@```+\```#\__________AI`0```````@``
+M`-X```#\_________Q-J`0```````@```+\```#\_________RAJ`0``````
+M`@```+\```#\_________UQJ`0```````@```.4```#\_________V9J`0``
+M`````@```#("``#\_________]EJ`0```````@```,(```#\__________-J
+M`0```````@```(T!``#\_________PQK`0```````@```(D!``#\________
+M_QUK`0```````@```$T!``#\_________S!K`0``````"P````8```#!````
+M`````#IK`0```````@```#T"``#\_________U!K`0```````@```$D"``#\
+M_________V9K`0```````@```$D"``#\_________WEK`0```````@```.H`
+M``#\_________Z1K`0```````@```%D!``#\_________]MK`0```````@``
+M`%$!``#\_________S%L`0```````@```&D!``#\_________U-L`0``````
+M`@```%D!``#\_________Z1L`0``````"P````4````0"````````*YL`0``
+M`````@```#T"``#\_________])L`0```````@```%@!``#\_________P)M
+M`0``````"P````4```!`"`````````QM`0```````@```#T"``#\________
+M_XAM`0``````"P````4```"X!P```````))M`0```````@```#T"``#\____
+M_____\5M`0``````"P````4````0"````````,]M`0```````@```#T"``#\
+M_________V1N`0```````@```!X!``#\_________W-O`0```````@```-(`
+M``#\_________[)O`0```````@```+<!``#\_________]MO`0``````"P``
+M``4````0"````````.5O`0```````@```#T"``#\_________Q)Q`0``````
+M`@```!0"``#\_________SEQ`0```````@```"`"``#\_________W!Q`0``
+M`````@```"`"``#\_________[YQ`0```````@```"`"``#\_________T-R
+M`0``````"P````4```!P"````````$UR`0```````@```#T"``#\________
+M_X!R`0``````"P````4```"P"````````(IR`0```````@```#T"``#\____
+M_____Z1R`0``````"P````4```#P"````````*YR`0```````@```#T"``#\
+M_________]-R`0``````"P````8````=`0```````-UR`0```````@```#T"
+M``#\_________QIS`0``````"P````4````@"0```````"1S`0```````@``
+M`#T"``#\_________UES`0``````"P````8````Y`0```````&-S`0``````
+M`@```#T"``#\_________X9S`0``````"P````8```!0`0```````)!S`0``
+M`````@```#T"``#\_________YMS`0``````"P````8```!L`0```````*5S
+M`0```````@```#T"``#\__________=S`0```````@```,L```#\________
+M_T9T`0```````@```"`"``#\_________VIT`0```````@```"`"``#\____
+M_____XQT`0```````@```"`"``#\_________[!T`0```````@```"`"``#\
+M_________[]T`0``````"P````8```!]`0```````,ET`0```````@```#T"
+M``#\_________V1U`0```````@```"`"``#\_________X]U`0``````"P``
+M``8```":`0```````)EU`0```````@```#T"``#\_________]IU`0``````
+M"P````4```!8"0```````.1U`0```````@```#T"``#\__________=U`0``
+M`````@````\!``#\_________Q!V`0```````@```"`"``#\_________[AV
+M`0```````@```!<!``#\_________]5V`0```````@```'(!``#\________
+M_U5W`0```````@```+D!``#\_________VEW`0```````@```!\!``#\____
+M_____X]W`0```````@```#X"``#\_________[%W`0```````@```#X"``#\
+M_________])W`0```````@```#X"``#\__________!W`0```````@```#X"
+M``#\_________Q9X`0```````@```#X"``#\_________T%X`0```````@``
+M`#X"``#\_________UMX`0```````@```#X"``#\_________W5X`0``````
+M`@```#X"``#\_________Y-X`0```````@```#X"``#\_________ZUX`0``
+M`````@```#X"``#\_________\]X`0```````@```#X"``#\__________%X
+M`0```````@```#X"``#\_________PYY`0```````@```#X"``#\________
+M_RMY`0```````@```#X"``#\_________TAY`0```````@```#X"``#\____
+M_____V5Y`0```````@```#X"``#\_________X%Y`0```````@```#X"``#\
+M_________Z-Y`0```````@```#X"``#\_________[QY`0```````@```#X"
+M``#\_________^!Y`0```````@```!("``#\_________P!Z`0```````@``
+M`!("``#\_________R=Z`0```````@```!("``#\_________TMZ`0``````
+M`@```!("``#\_________V]Z`0```````@```!("``#\_________Y)Z`0``
+M`````@```!("``#\_________[)Z`0```````@```!("``#\_________]QZ
+M`0```````@```!("``#\_________R=[`0```````@```%D!``#\________
+M_S=[`0```````@```)8!``#\_________[![`0``````"P````$````@&@$`
+M`````+Y[`0```````@```%,!``#\_________\I[`0```````@```-,```#\
+M_________YE\`0```````@```%D!``#\_________\Y\`0```````@```$D"
+M``#\_________^1\`0```````@```+\```#\__________5\`0```````@``
+M`.4```#\__________]\`0```````@```#("``#\_________S!]`0``````
+M`@````8!``#\_________\E^`0```````@```+D!``#\_________TQ_`0``
+M`````@```$`"``#\_________XA_`0```````@```$`"``#\_________\-_
+M`0```````@```$`"``#\__________I_`0```````@```$`"``#\________
+M_S*``0```````@```$`"``#\_________T6``0```````@```$`"``#\____
+M_____UN``0```````@```$`"``#\_________\&``0```````@```$`"``#\
+M_________PZ!`0```````@```$`"``#\_________UZ!`0```````@```$`"
+M``#\_________Z&!`0```````@```$`"``#\_________^^!`0```````@``
+M`$`"``#\_________T>"`0```````@```$`"``#\_________XB"`0``````
+M`@```$`"``#\_________[&"`0```````@```&<!``#\_________[V"`0``
+M`````@```$`"``#\_________^:"`0```````@```#0!``#\__________*"
+M`0```````@```$`"``#\_________QN#`0```````@```#0!``#\________
+M_R>#`0```````@```$`"``#\_________U"#`0```````@```#0!``#\____
+M_____UR#`0```````@```$`"``#\_________X6#`0```````@```#0!``#\
+M_________Y&#`0```````@```$`"``#\_________^V#`0```````@```'0!
+M``#\__________Z&`0```````@```$P"``#\_________QB'`0```````@``
+M`$P"``#\_________S*'`0```````@```$P"``#\_________TR'`0``````
+M`@```$P"``#\_________V:'`0```````@```$P"``#\_________X"'`0``
+M`````@```$P"``#\_________ZB'`0```````@```%D!``#\__________V'
+M`0```````@```$P"``#\_________QZ(`0```````@```%D!``#\________
+M_V^(`0```````@```$P"``#\_________Y.(`0```````@```%D!``#\____
+M_____P*)`0```````@```-4```#\_________V&)`0```````@```"`"``#\
+M_________Y2)`0```````@```"`"``#\_________ZR)`0```````@```$4!
+M``#\__________>)`0```````@```+\```#\_________PB*`0```````@``
+M`.4```#\_________Q**`0```````@```#("``#\_________SJ*`0``````
+M`@```(D!``#\_________T^*`0```````@```$D"``#\_________V2*`0``
+M`````@```$D"``#\_________WN*`0```````@```.H```#\_________XN*
+M`0```````@```"`"``#\__________J*`0```````@```&$!``#\________
+M_R:+`0```````@```$D"``#\_________Y.+`0```````@```,P!``#\____
+M_____\2+`0```````@```%D!``#\_________RJ,`0``````"P````4```"`
+M"0```````#2,`0```````@```#T"``#\_________V>,`0```````@```%@!
+M``#\_________Y>,`0``````"P````4```!`"````````*&,`0```````@``
+M`#T"``#\_________QV-`0``````"P````4```"X!P```````">-`0``````
+M`@```#T"``#\_________TZ-`0``````"P````8````=`0```````%B-`0``
+M`````@```#T"``#\_________YJ-`0``````"P````4````@"0```````*2-
+M`0```````@```#T"``#\_________U".`0```````@```!X!``#\________
+M_V".`0``````"P````4```"X"0```````&J.`0```````@```#T"``#\____
+M_____WZ/`0```````@```&8!``#\_________ZB/`0```````@```-(```#\
+M_________\B/`0```````@```(<!``#\_________PZ0`0```````@```,<!
+M``#\_________YR3`0```````@```%\!``#\_________P&4`0```````@``
+M`!0"``#\_________PZ4`0```````@```+@!``#\_________X:4`0``````
+M`@```!0"``#\_________^Z4`0```````@```)8!``#\_________P*5`0``
+M`````@```-0!``#\_________Q65`0```````@```-,!``#\_________SB5
+M`0```````@```!0"``#\_________XJ5`0``````"P```#8!````````````
+M`-25`0```````@```%,!``#\_________^65`0```````@```+P```#\____
+M______"5`0```````@```-,```#\_________U^6`0```````@```)8!``#\
+M_________W.6`0```````@```-0!``#\_________X:6`0```````@```-,!
+M``#\_________^J6`0``````"P```#8!`````````````#F7`0```````@``
+M`%,!``#\_________TJ7`0```````@```+P```#\_________U67`0``````
+M`@```-,```#\_________]B7`0```````@```)8!``#\_________^R7`0``
+M`````@```-0!``#\__________^7`0```````@```-,!``#\_________QR8
+M`0```````@```!0"``#\_________V"8`0``````"P```,8!````````````
+M`(28`0```````@```%,!``#\_________Y.8`0```````@```+P```#\____
+M_____YZ8`0```````@```-,```#\_________P&9`0```````@```%\!``#\
+M_________R^9`0```````@```)@!``#\_________X.9`0```````@```)8!
+M``#\_________Y>9`0```````@```-0!``#\_________ZJ9`0```````@``
+M`-,!``#\__________R9`0``````"P```,8!`````````````!V:`0``````
+M`@```%,!``#\_________RV:`0```````@```+P```#\_________SB:`0``
+M`````@```-,```#\_________^B:`0```````@```/P```#\_________R:;
+M`0```````@```/P```#\_________V2;`0```````@```$,!``#\________
+M_W*;`0```````@```.(```#\_________Z&;`0```````@```.P```#\____
+M_____[J;`0```````@```.(```#\_________^B;`0```````@```.(```#\
+M_________[Z<`0```````@````L!``#\_________P&=`0```````@```$0!
+M``#\_________SR=`0```````@```.P```#\_________X.=`0```````@``
+M`)8!``#\_________Y>=`0```````@```-0!``#\_________ZJ=`0``````
+M`@```-,!``#\__________V=`0``````"P```)H!`````````````!Z>`0``
+M`````@```%,!``#\_________RV>`0```````@```+P```#\_________SB>
+M`0```````@```-,```#\_________S^?`0```````@```+X```#\________
+M_TJ?`0```````@```-,!``#\_________WF?`0```````@```!0"``#\____
+M_____[^?`0```````@```+X```#\_________\J?`0```````@```-,!``#\
+M_________W&@`0```````@```/8```#\_________X2@`0```````@```+X`
+M``#\_________X^@`0```````@```-,!``#\_________ZF@`0```````@``
+M``T"``#\_________[Z@`0``````"P```.0``````````````-*@`0``````
+M`@```"L"``#\_________TZA`0```````@```((!``#\_________SVB`0``
+M`````@```'T!``#\_________W&B`0```````@```'T!``#\_________ZFB
+M`0```````@```.P```#\_________Q>D`0```````@```!,!``#\________
+M_RFD`0```````@````$!``#\_________SZD`0```````@```#D!``#\____
+M_____U"D`0```````@```/8```#\_________VJD`0```````@````T"``#\
+M_________W^D`0``````"P```.0``````````````)FD`0```````@```"L"
+M``#\_________^6D`0```````@```%D!``#\_________U*E`0```````@``
+M`+X!``#\_________WBE`0```````@```$H!``#\_________YRE`0``````
+M`@```*H!``#\_________P2F`0```````@```%D!``#\_________S^F`0``
+M`````@```.P```#\_________VVF`0```````@```%$!``#\_________YFF
+M`0```````@```+X```#\_________ZBF`0```````@```-,!``#\________
+M_^&F`0```````@```.P```#\_________]NK`0```````@```,4!``#\____
+M_____]VL`0``````"P````,````@#0```````'>M`0```````@```"`"``#\
+M_________ZVM`0```````@```"`"``#\_________]BM`0```````@```"`"
+M``#\_________Q*N`0```````@```"`"``#\_________U>N`0```````@``
+M`"`"``#\_________XVN`0```````@```"`"``#\_________[BN`0``````
+M`@```"`"``#\_________^VN`0```````@```"`"``#\_________ZVO`0``
+M````"P````,```#@#0```````,FO`0``````"P````,```#E#0```````-FO
+M`0``````"P````,```#D#0```````.JO`0``````"P````,```#@#0``````
+M`/NO`0```````@```(X!``#\_________XVP`0```````@```%D!``#\____
+M_____[VP`0```````@```%D!``#\_________^VP`0```````@```%D!``#\
+M_________SVQ`0```````@```%D!``#\_________VVQ`0```````@```%D!
+M``#\_________^JQ`0```````@```%D!``#\_________S.S`0```````@``
+M`-(```#\_________W"T`0```````@```%@!``#\_________[.T`0``````
+M`@```'L!``#\__________.T`0```````@```'L!``#\_________^^U`0``
+M`````@```+X```#\__________VU`0```````@```!D!``#\_________R>W
+M`0```````@```-,```#\_________U"W`0```````@```/4```#\________
+M_URW`0```````@```,4!``#\_________W6W`0```````@```&8!``#\____
+M_____^*W`0```````@```(`!``#\_________TZX`0```````@```",!``#\
+M_________RBY`0```````@```-,!``#\_________Z.Y`0```````@````4!
+M``#\_________ZZY`0```````@```-,!``#\_________^>Y`0```````@``
+M`%D!``#\__________*Y`0```````@```/@```#\__________JY`0``````
+M`@```-<```#\_________T"Z`0```````@```)8!``#\_________U"Z`0``
+M`````@```-0!``#\_________VJZ`0```````@```-,!``#\_________ZVZ
+M`0``````"P```,,``````````````+BZ`0```````@```-,```#\________
+M__.Z`0```````@```)8!``#\_________S2[`0``````"P```,,`````````
+M`````#^[`0```````@```-,```#\_________X^[`0```````@```)8!``#\
+M_________Z.[`0```````@```-0!``#\_________[:[`0```````@```-,!
+M``#\_________P&\`0``````"P````$`````O0$```````Z\`0```````@``
+M`%,!``#\_________QZ\`0```````@```+P```#\_________RF\`0``````
+M`@```-,```#\_________W2\`0```````@```)8!``#\_________[2\`0``
+M````"P```"L!`````````````+^\`0```````@```-,```#\_________\^\
+M`0```````@```#("``#\_________]N\`0```````@```#("``#\________
+M_]J]`0```````@```+X```#\_________^J]`0```````@```!D!``#\____
+M______6]`0```````@```-,!``#\_________SB^`0```````@```)T!``#\
+M_________UB^`0```````@```+X```#\_________VB^`0```````@```!D!
+M``#\_________W.^`0```````@```-,!``#\_________W*_`0```````@``
+M`#("``#\_________WV_`0```````@```-,!``#\_________Z^_`0``````
+M`@```)T!``#\_________[N_`0```````@```#("``#\_________\:_`0``
+M`````@```-,!``#\_________Q#``0```````@```)8!``#\_________U+`
+M`0```````@```*,!``#\_________V'``0```````@```-,!``#\________
+M_W?``0``````"P```,,``````````````(+``0```````@```-,```#\____
+M_____\;``0```````@```)8!``#\_________^3``0```````@```-0!``#\
+M__________[``0```````@```-,!``#\_________V+!`0``````"P```,,`
+M`````````````'/!`0```````@```%,!``#\_________X7!`0```````@``
+M`+P```#\_________Y#!`0```````@```-,```#\_________^/!`0``````
+M`@```)8!``#\_________P3"`0```````@```-0!``#\_________R#"`0``
+M`````@```-,!``#\_________XK"`0``````"P```,,``````````````)?"
+M`0```````@```%,!``#\_________ZC"`0```````@```+P```#\________
+M_[/"`0```````@```-,```#\_________PK#`0```````@```)8!``#\____
+M_____RC#`0```````@```-0!``#\_________T3#`0```````@```-,!``#\
+M_________Z+#`0``````"P```,,``````````````+;#`0```````@```%,!
+M``#\_________\?#`0```````@```+P```#\_________]+#`0```````@``
+M`-,```#\_________RK$`0```````@```)8!``#\_________TC$`0``````
+M`@```-0!``#\_________V3$`0```````@```-,!``#\_________[K$`0``
+M````"P```,,``````````````,?$`0```````@```%,!``#\_________]C$
+M`0```````@```+P```#\_________^/$`0```````@```-,```#\________
+M_U?%`0```````@```)8!``#\_________P7&`0``````"P````$```!@N`$`
+M`````!/&`0```````@```%,!``#\_________Q[&`0```````@```-,```#\
+M_________X'(`0```````@````(!``#\_________Y+(`0```````@````4!
+M``#\_________^S(`0```````@```%D!``#\_________\;)`0```````@``
+M`)P!``#\_________U7*`0```````@```)8!``#\_________W3*`0``````
+M`@```(\!``#\_________X?*`0```````@```-,!``#\_________]S*`0``
+M````"P```.L``````````````.K*`0```````@```%,!``#\__________7*
+M`0```````@```-,```#\_________U7+`0```````@```)8!``#\________
+M_VG+`0```````@```(\!``#\_________\#+`0``````"P```.L`````````
+M`````,[+`0```````@```%,!``#\_________]G+`0```````@```-,```#\
+M_________^/+`0```````@```#("``#\_________SS,`0```````@```)8!
+M``#\_________TS,`0```````@```(\!``#\_________Y_,`0``````"P``
+M`.L``````````````*W,`0```````@```%,!``#\_________[C,`0``````
+M`@```-,```#\_________P7-`0```````@```)8!``#\_________Q7-`0``
+M`````@```(\!``#\_________V3-`0``````"P```.L``````````````'+-
+M`0```````@```%,!``#\_________WW-`0```````@```-,```#\________
+M_[3-`0```````@```#(!``#\_________\3-`0```````@```-`!``#\____
+M_____]#.`0```````@```#(!``#\_________^#.`0```````@```-`!``#\
+M_________U#/`0```````@```-D```#\_________^//`0```````@```$(!
+M``#\_________T'0`0```````@```,0!``#\_________W#0`0```````@``
+M`#(!``#\_________X#0`0```````@```-`!``#\_________^[0`0``````
+M`@```*(!``#\_________U+1`0```````@```+4!``#\_________ZC1`0``
+M`````@```-(```#\_________\O1`0```````@```(`!``#\_________]S1
+M`0```````@```+4!``#\_________Q/2`0```````@```-(```#\________
+M_R32`0```````@```+4!``#\_________T;2`0```````@````T"``#\____
+M_____VG2`0```````@````T"``#\_________]#2`0```````@```"X!``#\
+M_________QK3`0```````@```-(```#\_________S+3`0```````@```",!
+M``#\_________SW3`0```````@```,P!``#\__________S3`0```````@``
+M`%D!``#\_________P_4`0```````@```&D!``#\_________R[4`0``````
+M"P```,L``````````````$74`0```````@```"L"``#\_________]G4`0``
+M`````@```%D!``#\_________^S4`0```````@```,P!``#\_________P?5
+M`0``````"P```,`!`````````````![5`0```````@```"L"``#\________
+M_]75`0```````@```-(```#\_________^#5`0```````@```#\!``#\____
+M_____^O5`0```````@```)P!``#\_________X+6`0``````"P```,L`````
+M`````````)G6`0```````@```"L"``#\_________SK7`0``````"P```,`!
+M`````````````%'7`0```````@```"L"``#\_________P39`0```````@``
+M`%D!``#\_________U[9`0```````@```-````#\_________VW9`0``````
+M`@```-,!``#\_________ZK9`0```````@```($!``#\_________]K9`0``
+M`````@```$H!``#\__________;9`0```````@```-8```#\_________R?:
+M`0```````@```%D!``#\_________Y':`0```````@```+X!``#\________
+M_Z?:`0```````@```-````#\_________[3:`0```````@```-,!``#\____
+M_____R3;`0```````@```+\```#\_________U3;`0```````@```.4```#\
+M_________U[;`0```````@```#("``#\_________X3;`0```````@```,(`
+M``#\_________Y[;`0```````@```(T!``#\_________\W;`0```````@``
+M`(D!``#\_________][;`0```````@```$T!``#\__________';`0``````
+M"P````8```"N`0```````/O;`0```````@```#T"``#\_________Q#<`0``
+M`````@```$D"``#\_________R7<`0```````@```$D"``#\_________VW<
+M`0```````@```.H```#\_________Y3<`0```````@```%D!``#\________
+M_]+<`0```````@```%$!``#\_________QC=`0```````@```+\```#\____
+M_____T?=`0```````@```.4```#\_________U'=`0```````@```#("``#\
+M_________W?=`0```````@```,(```#\_________Y'=`0```````@```(T!
+M``#\_________ZS=`0```````@```(D!``#\_________[W=`0```````@``
+M`$T!``#\_________]#=`0``````"P````8```"N`0```````-K=`0``````
+M`@```#T"``#\_________^_=`0```````@```$D"``#\_________P#>`0``
+M````"P````8```"N`0````````K>`0```````@```#T"``#\_________Q_>
+M`0```````@```$D"``#\_________Y_>`0```````@```$D"``#\________
+M_PG?`0```````@```%D!``#\_________S[?`0```````@```$D"``#\____
+M_____U??`0```````@```.H```#\_________Z;?`0```````@```)8!``#\
+M_________[K?`0```````@```-0!``#\_________]3?`0```````@```-,!
+M``#\_________UG@`0``````"P```,,``````````````&K@`0```````@``
+M`%,!``#\_________WS@`0```````@```+P```#\_________X?@`0``````
+M`@```-,```#\_________\3@`0```````@```#(!``#\_________]3@`0``
+M`````@```-`!``#\_________\CA`0```````@```+4!``#\_________PGB
+M`0```````@```-`!``#\_________UWB`0```````@```%D!``#\________
+M_SKF`0```````@```((!``#\_________V7F`0```````@```*P!``#\____
+M_____^OF`0``````"P````$```"P\P$```````SG`0```````@````D!``#\
+M_________POH`0``````"P````$```"P\P$``````#_H`0```````@````D!
+M``#\_________SSI`0``````"P````$```"P\P$``````&_I`0```````@``
+M``D!``#\_________]?I`0``````"P````$```"P\P$```````?J`0``````
+M`@````D!``#\_________U?J`0``````"P````$```"P\P$``````(?J`0``
+M`````@````D!``#\_________U7K`0```````@```*T!``#\_________\WK
+M`0```````@```,0```#\_________Z7L`0```````@```&X!``#\________
+M_T/M`0```````@```$<!``#\_________[?M`0```````@```((!``#\____
+M_____^?M`0```````@```*X!``#\_________P3N`0```````@```%(!``#\
+M_________R7O`0```````@```*P!``#\_________^OP`0```````@```%X!
+M``#\_________RWQ`0```````@```&X!``#\_________]3Q`0```````@``
+M`$<!``#\_________U7R`0```````@```.X```#\_________^KR`0``````
+M`@```$<!``#\_________Y+S`0```````@```$<!``#\_________^3S`0``
+M`````@```*P!``#\_________T[T`0```````@```$<!``#\_________XKT
+M`0```````@```$<!``#\_________]OT`0```````@```$<!``#\________
+M_QOU`0```````@```$<!``#\_________XWX`0```````@```$<!``#\____
+M______#X`0```````@```"`"``#\_________Q3Y`0```````@```"`"``#\
+M_________W'Z`0```````@```&L!``#\_________[_[`0```````@```"`"
+M``#\_________][[`0```````@```"`"``#\__________K[`0```````@``
+M`-,!``#\_________UG\`0```````@```#("``#\_________VG\`0``````
+M`@```"`"``#\_________Y+\`0```````@```#("``#\_________Z+\`0``
+M`````@```"`"``#\_________Z_]`0```````@```#("``#\_________[[]
+M`0```````@```"`"``#\_________]#]`0```````@```#("``#\________
+M_]C]`0```````@```"`"``#\__________?]`0```````@```#("``#\____
+M_______]`0```````@```"`"``#\_________RG^`0```````@```#("``#\
+M_________SC^`0```````@```"`"``#\_________TK^`0```````@```#("
+M``#\_________U+^`0```````@```"`"``#\_________W'^`0```````@``
+M`#("``#\_________WG^`0```````@```"`"``#\_________[[^`0``````
+M`@```#("``#\_________RS_`0```````@```#("``#\_________T'_`0``
+M`````@```.4```#\_________Y[_`0```````@```)8!``#\_________PT`
+M`@``````"P```#<!`````````````!0``@``````"P```,H`````````````
+M`"<``@```````@```-,```#\_________X4``@```````@```)8!``#\____
+M______4``@``````"P```.```````````````/T``@```````@```-,```#\
+M_________Y`!`@```````@```"`"``#\_________[X!`@```````@```"`"
+M``#\_________P\"`@```````@```'$!``#\_________QP"`@```````@``
+M`-L```#\_________V\"`@```````@```)8!``#\_________\("`@``````
+M"P```.```````````````,H"`@```````@```-,```#\_________V0#`@``
+M`````@```"`"``#\_________Y(#`@```````@```"`"``#\_________]\#
+M`@```````@```+H```#\_________^P#`@```````@```-L```#\________
+M_U8$`@```````@```)8!``#\_________Z@$`@``````"P```#<!````````
+M`````*\$`@``````"P```,H``````````````,($`@```````@```-,```#\
+M_________Q@%`@```````@```)8!``#\_________X,%`@``````"P````$`
+M````.0(``````)4%`@```````@```-,```#\_________\(%`@``````"P``
+M`.T``````````````%X&`@```````@```#("``#\_________VL&`@``````
+M`@```"`"``#\_________X`&`@```````@```#("``#\_________XH&`@``
+M`````@```"`"``#\_________TX'`@```````@```#("``#\_________UL'
+M`@```````@```"`"``#\_________W`'`@```````@```#("``#\________
+M_WH'`@```````@```"`"``#\_________Q8(`@```````@```,D!``#\____
+M_____T@(`@```````@```+`!``#\_________U`(`@```````@```&L!``#\
+M_________Y8(`@```````@```"`"``#\_________[8(`@```````@```"`"
+M``#\_________]((`@```````@```"`"``#\__________\(`@```````@``
+M`"`"``#\_________TT)`@```````@```)D!``#\_________U4)`@``````
+M`@```+T```#\_________[L)`@```````@```#("``#\_________\L)`@``
+M`````@```"`"``#\__________`)`@```````@```#("``#\_________P`*
+M`@```````@```"`"``#\_________PD-`@```````@```+$!``#\________
+M_[P-`@```````@```((!``#\_________R8/`@```````@```((!``#\____
+M_____TD/`@```````@```((!``#\_________\(/`@```````@```/L```#\
+M_________^,0`@```````@```#("``#\_________PX1`@```````@```#("
+M``#\_________\X1`@```````@```,\```#\_________^\1`@```````@``
+M`'D!``#\_________P42`@```````@```+0!``#\_________Q02`@``````
+M`@```+0!``#\_________YT2`@```````@```"`"``#\_________\L2`@``
+M`````@```"`"``#\__________\2`@```````@```#("``#\_________Q<3
+M`@```````@```"`"``#\_________V43`@```````@```"`"``#\________
+M_\P3`@```````@```"`"``#\_________S\4`@```````@```"`"``#\____
+M______<4`@```````@```#("``#\_________PH5`@```````@```"`"``#\
+M_________R<5`@```````@```'\!``#\_________S(5`@```````@```)$!
+M``#\_________T05`@```````@```#("``#\_________UX5`@```````@``
+M`#("``#\_________W@5`@```````@```#("``#\_________Y@5`@``````
+M`@```!T!``#\_________ZD5`@```````@```"`"``#\__________<5`@``
+M`````@```#("``#\_________PH6`@```````@```"`"``#\_________R<6
+M`@```````@```'\!``#\_________S(6`@```````@```)$!``#\________
+M_T06`@```````@```#("``#\_________UX6`@```````@```#("``#\____
+M_____W@6`@```````@```#("``#\_________Y@6`@```````@```!T!``#\
+M_________ZD6`@```````@```"`"``#\_________\T6`@```````@```#("
+M``#\_________]@6`@```````@```#X!``#\__________86`@```````@``
+M`!P!``#\_________P,7`@```````@```"`"``#\_________QX7`@``````
+M`@```"`"``#\_________S87`@```````@```"`"``#\_________R`8`@``
+M`````@```"`"``#\_________[L8`@```````@```)8!``#\_________]D8
+M`@```````@```-0!``#\__________48`@```````@```-,!``#\________
+M_UL9`@``````"P````$`````.0(``````&@9`@```````@```%,!``#\____
+M_____W<9`@```````@```+P```#\_________X(9`@```````@```-,```#\
+M_________YP:`@``````"P````4```#@"0```````*8:`@```````@```#T"
+M``#\_________S4;`@``````"P````4````P"@```````#\;`@```````@``
+M`#T"``#\_________T\;`@```````@```%$!``#\_________VH;`@``````
+M`@```%0!``#\_________SL<`@```````@```'X!``#\_________[8<`@``
+M````"P```-$``````````````,$<`@```````@```&\!``#\_________]D<
+M`@```````@```$$!``#\_________S,=`@```````@```'X!``#\________
+M_T8=`@```````@```"T!``#\_________W8=`@```````@```*H!``#\____
+M_____RD>`@```````@```/T```#\_________S,>`@```````@```,T!``#\
+M__________L>`@```````@```%$!``#\_________WP?`@```````@```%D!
+M``#\_________]$?`@```````@```+X!``#\__________,?`@```````@``
+M`$H!``#\_________P,@`@```````@```*H!``#\_________ZL@`@``````
+M`@```"D!``#\_________UHA`@```````@```%D!``#\_________]@A`@``
+M`````@```"D!``#\_________W,B`@```````@```$D"``#\_________XDB
+M`@```````@```$D"``#\_________[PB`@```````@```"D!``#\________
+M_R(C`@```````@```$D"``#\_________W`C`@```````@```$D"``#\____
+M_____ZXC`@```````@```+\```#\_________^0C`@```````@```.4```#\
+M_________^XC`@```````@```#("``#\_________Q0D`@```````@```,(`
+M``#\_________RXD`@```````@```(T!``#\_________TDD`@```````@``
+M`(D!``#\_________UHD`@```````@```$T!``#\_________VTD`@``````
+M"P````8```#$`0```````'<D`@```````@```#T"``#\_________XPD`@``
+M`````@```$D"``#\_________Z$D`@``````"P````8```#$`0```````*LD
+M`@```````@```#T"``#\_________\`D`@```````@```$D"``#\________
+M_PXE`@```````@```$D"``#\_________UHE`@```````@```.H```#\____
+M_____W4E`@```````@```$D"``#\_________\TE`@```````@```'8!``#\
+M__________DE`@```````@```%$!``#\_________Q8F`@```````@```$$!
+M``#\_________UTF`@```````@```)X!``#\_________ZLF`@``````"P``
+M``,```!@#@```````!$G`@```````@```&$!``#\_________RTG`@``````
+M`@```#P!``#\_________TDG`@```````@```#P!``#\_________V4G`@``
+M`````@```#P!``#\_________X$G`@```````@```#P!``#\_________Z(G
+M`@```````@```#`!``#\_________\0G`@```````@```#`!``#\________
+M__$G`@```````@```#`!``#\_________Q,H`@```````@```#`!``#\____
+M_____QTH`@```````@```#("``#\_________THH`@```````@```#`!``#\
+M_________VPH`@```````@```#`!``#\_________W8H`@```````@```#("
+M``#\_________Y(H`@```````@```#P!``#\_________ZXH`@```````@``
+M`#P!``#\_________\HH`@```````@```#P!``#\_________^PH`@``````
+M`@```#`!``#\_________P@I`@```````@```#P!``#\_________UTI`@``
+M`````@```#("``#\_________]HI`@```````@```"`"``#\__________@I
+M`@```````@```"`"``#\_________PPJ`@```````@```#("``#\________
+M_R8J`@```````@```$H!``#\_________S4J`@```````@```#("``#\____
+M_____TPJ`@```````@```#P!``#\_________U8J`@```````@```#("``#\
+M_________W(J`@```````@```#P!``#\_________WPJ`@```````@```#("
+M``#\_________ZDJ`@```````@```#`!``#\_________[,J`@```````@``
+M`#("``#\_________\\J`@```````@```#P!``#\_________]DJ`@``````
+M`@```#("``#\_________^,J`@```````@```!0!``#\__________$J`@``
+M`````@```'4!``#\_________Q,K`@```````@```#`!``#\_________S4K
+M`@```````@```#`!``#\_________U<K`@```````@```#`!``#\________
+M_WDK`@```````@```#`!``#\_________Y4K`@```````@```#P!``#\____
+M_____Z0K`@```````@```#("``#\_________[LK`@```````@```#P!``#\
+M_________\4K`@```````@```#("``#\_________^<K`@```````@```#`!
+M``#\_________P,L`@```````@```#P!``#\_________R0L`@```````@``
+M`#`!``#\_________SDL`@```````@```,T!``#\_________U(L`@``````
+M`@```#P!``#\_________UPL`@```````@```#("``#\_________X8L`@``
+M`````@```#`!``#\_________Y`L`@```````@```#("``#\_________ZDL
+M`@```````@```#P!``#\_________[,L`@```````@```#("``#\________
+M_^\M`@```````@```+X```#\__________HM`@```````@```-,!``#\____
+M_____V4N`@```````@```"`"``#\_________XPN`@```````@```"`"``#\
+M_________\TN`@```````@```"`"``#\__________8N`@```````@```+X`
+M``#\_________P$O`@```````@```-,!``#\_________PPO`@```````@``
+M`&$!``#\_________SLO`@```````@```&$!``#\_________X0P`@``````
+M`@```)X!``#\_________XXP`@```````@```#("``#\_________ZTP`@``
+M`````@```)X!``#\_________[<P`@```````@```#("``#\_________T4Q
+M`@```````@```"`"``#\_________UPQ`@```````@```"`"``#\________
+M_YLQ`@```````@```#("``#\_________[0Q`@```````@```$H!``#\____
+M_____\\Q`@```````@```)`!``#\_________^0Q`@```````@```)`!``#\
+M__________(Q`@```````@```#("``#\_________R`R`@```````@```"`"
+M``#\_________T8R`@```````@```"`"``#\_________UXR`@```````@``
+M`#("``#\_________V\R`@``````"P````4```!H"@```````'DR`@``````
+M`@```#T"``#\_________XDR`@```````@```)8!``#\_________]\R`@``
+M````"P````$`````.0(``````.HR`@```````@```-,```#\__________LR
+M`@``````"P````8```#:`0````````4S`@```````@```#T"``#\________
+M_Q4S`@```````@```)8!``#\_________V0S`@``````"P````$`````.0(`
+M`````&\S`@```````@```-,```#\_________YHS`@```````@```)8!``#\
+M_________^TS`@``````"P````$`````.0(``````/LS`@```````@```-,`
+M``#\_________Q$T`@```````@```)8!``#\_________V0T`@``````"P``
+M``$`````.0(``````'(T`@```````@```-,```#\_________X@T`@``````
+M`@```)8!``#\_________]<T`@``````"P````$`````.0(``````.(T`@``
+M`````@```-,```#\__________@T`@```````@```)8!``#\_________T<U
+M`@``````"P````$`````.0(``````%(U`@```````@```-,```#\________
+M_V@U`@```````@```)8!``#\_________\(U`@``````"P````$`````.0(`
+M`````,TU`@```````@```-,```#\_________P@V`@```````@```'X!``#\
+M_________R,V`@```````@```"H!``#\_________WLV`@```````@```&$!
+M``#\_________[<V`@```````@```&$!``#\_________\DV`@```````@``
+M`%D!``#\_________QDW`@```````@```+X!``#\_________T$W`@``````
+M`@```$H!``#\_________U8W`@```````@```*H!``#\_________X0W`@``
+M`````@```%D!``#\_________^(W`@```````@```+X!``#\_________PTX
+M`@```````@```$H!``#\_________R(X`@```````@```*H!``#\________
+M_ULX`@```````@```%D!``#\_________XDX`@```````@```.P```#\____
+M_____Z<X`@```````@```%$!``#\_________R8Z`@```````@```+X```#\
+M_________S$Z`@```````@```-,!``#\_________[<Z`@```````@```#("
+M``#\__________TZ`@```````@```($!``#\_________Q([`@```````@``
+M`$H!``#\_________VH[`@``````"P````4```"@"@```````'0[`@``````
+M`@```#T"``#\_________X8[`@```````@```$P!``#\_________P4\`@``
+M`````@```#("``#\_________Z,\`@```````@```+X```#\_________ZX\
+M`@```````@```-,!``#\_________\4\`@```````@```+X```#\________
+M_]`\`@```````@```-,!``#\_________]L\`@```````@```$H!``#\____
+M_____\$]`@```````@```$L!``#\_________]@]`@```````@```$L!``#\
+M_________^\]`@```````@```/(```#\_________P$^`@```````@```%4!
+M``#\_________Q0^`@```````@```'P!``#\_________S$^`@```````@``
+M`!(!``#\_________T,^`@```````@```$`!``#\_________U4^`@``````
+M`@```,H!``#\_________VD^`@```````@```+L!``#\_________Y0^`@``
+M`````@```%D!``#\__________(^`@```````@```+X!``#\_________QT_
+M`@```````@```$H!``#\_________S(_`@```````@```*H!``#\________
+M_X<_`@```````@```.P```#\_________Y8_`@```````@```%D!``#\____
+M_____\$_`@``````"P````8```#P`0```````,L_`@```````@```#T"``#\
+M_________]@_`@```````@```.P```#\__________@_`@```````@```%$!
+M``#\_________Y1!`@```````@```(L!``#\_________Z)!`@``````"P``
+M``,```"(#P```````/A!`@```````@```$$!``#\_________VY"`@``````
+M`@```'X!``#\_________X-"`@```````@```"T!``#\_________\)"`@``
+M`````@```*H!``#\_________U1#`@```````@```%D!``#\_________W5#
+M`@```````@```,P```#\_________[-#`@```````@```((!``#\________
+M_V1$`@```````@```$D"``#\_________YQ$`@```````@```+\```#\____
+M_____[9$`@```````@```.4```#\_________\!$`@```````@```#("``#\
+M_________^M$`@```````@```,(```#\_________PA%`@```````@```(T!
+M``#\_________RQ%`@```````@```(D!``#\_________T!%`@```````@``
+M`$T!``#\_________UM%`@```````@```$D"``#\_________W9%`@``````
+M`@```$D"``#\_________ZY%`@```````@```.H```#\_________QU&`@``
+M`````@```,P```#\_________RM&`@```````@```(8!``#\_________^%&
+M`@```````@```((!``#\_________S!(`@```````@```+X!``#\________
+M_T1(`@```````@```*H!``#\_________W%(`@```````@```.P```#\____
+M_____WU(`@```````@```$$!``#\_________RI)`@```````@```%D!``#\
+M_________TM)`@```````@```,P```#\_________W])`@```````@```,P`
+M``#\_________Z])`@```````@```,P```#\_________\%)`@```````@``
+M`((!``#\__________])`@```````@```.$```#\_________TI+`@``````
+M`@```'<!``#\_________VQ+`@```````@```%D!``#\_________X!+`@``
+M`````@```+\```#\_________Y1+`@```````@```.4```#\_________YY+
+M`@```````@```#("``#\_________\9+`@```````@```(D!``#\________
+M_]=+`@```````@```$T!``#\_________^Q+`@```````@```$D"``#\____
+M_____P%,`@```````@```$D"``#\_________RU,`@```````@```.H```#\
+M_________TA,`@```````@```/0```#\_________[A,`@```````@```)<!
+M``#\_________]5,`@```````@```,P```#\_________QE-`@```````@``
+M`,P```#\_________TI-`@```````@```,P```#\_________UQ-`@``````
+M`@```.$```#\_________VY-`@```````@```%0!``#\_________Y=-`@``
+M`````@```.$```#\_________^M.`@```````@```$$!``#\_________Q-0
+M`@```````@```+X!``#\_________R)0`@```````@```*H!``#\________
+M_V90`@```````@```%$!``#\_________Z50`@```````@```,P```#\____
+M_____\Q0`@```````@```"8!``#\_________S91`@```````@```!L!``#\
+M_________TM1`@``````"P```-$``````````````%91`@```````@```&\!
+M``#\_________WI1`@```````@```#,!``#\_________X51`@```````@``
+M`!L!``#\_________[]1`@```````@```)`!``#\_________\U1`@``````
+M`@```#("``#\_________QU2`@```````@```.H```#\_________S12`@``
+M`````@```,@!``#\_________V=2`@```````@```&$!``#\_________XE2
+M`@```````@````T"``#\_________Y52`@```````@```&(!``#\________
+M_ZM2`@```````@```%D!``#\_________\U2`@```````@```(D!``#\____
+M_____]Y2`@```````@```$T!``#\__________-2`@```````@```$D"``#\
+M_________PA3`@```````@```$D"``#\_________Q]3`@```````@```.H`
+M``#\_________T!3`@```````@```%D!``#\_________U%3`@```````@``
+M`$$!``#\_________Y)3`@```````@```$H!``#\_________X%4`@``````
+M`@```+X```#\_________XQ4`@```````@```-,!``#\_________^I4`@``
+M````"P````4```#`"@```````/14`@```````@```#T"``#\_________Q15
+M`@```````@```.H```#\_________Q]5`@```````@```-,!``#\________
+M_U95`@```````@```$4!``#\_________XQ5`@```````@```#("``#\____
+M_____Y=5`@```````@```-,!``#\_________ZQ5`@```````@```)X!``#\
+M_________[A5`@```````@```#("``#\_________\-5`@```````@```-,!
+M``#\_________\Y5`@```````@```.<```#\_________R16`@```````@``
+M`%D!``#\_________XQ6`@```````@```$H!``#\_________P18`@``````
+M`@```#`!``#\_________V!8`@```````@```+X```#\_________VM8`@``
+M`````@```-,!``#\_________W]8`@```````@```&$!``#\_________Z98
+M`@``````"P````,```"0#P```````-]8`@```````@```"`"``#\________
+M_S%9`@```````@```"`"``#\_________UQ9`@```````@```"`"``#\____
+M_____[]9`@```````@```"`"``#\_________^99`@```````@```"`"``#\
+M_________TM:`@```````@```"`"``#\_________X=:`@```````@```+X`
+M``#\_________Y):`@```````@```-,!``#\_________Z):`@```````@``
+M`%$!``#\_________]U:`@```````@```+X```#\_________^A:`@``````
+M`@```-,!``#\__________Y:`@``````"P```',!`````````````!5;`@``
+M`````@```"L"``#\_________RY;`@```````@```#("``#\_________UM;
+M`@```````@```%,"``#\_________X];`@```````@```"`"``#\________
+M_[5;`@```````@```"`"``#\_________[I;`@```````@```%,"``#\____
+M_____S1<`@```````@```%D!``#\_________Y!<`@```````@```(D!``#\
+M_________[!<`@```````@```$T!``#\_________]A<`@```````@```$D"
+M``#\_________WE=`@``````"P````8```#$`0```````(-=`@```````@``
+M`#T"``#\_________YQ=`@```````@```$D"``#\_________\)=`@``````
+M`@```.H```#\_________^]=`@```````@```"`"``#\_________Q5>`@``
+M`````@```"`"``#\_________V5>`@```````@```%D!``#\_________Z)>
+M`@```````@```$$!``#\_________]1>`@```````@```.4```#\________
+M_]Y>`@```````@```#("``#\_________QU?`@```````@```"`"``#\____
+M_____T-?`@```````@```"`"``#\_________SA@`@```````@```"`"``#\
+M_________UM@`@```````@```"`"``#\_________^M@`@```````@```"4!
+M``#\_________PAA`@```````@```+4!``#\_________T=A`@```````@``
+M`"`"``#\_________VIA`@```````@```"`"``#\_________Z%A`@``````
+M`@```"`"``#\_________\1A`@```````@```"`"``#\_________QEB`@``
+M`````@```"`"``#\_________S]B`@```````@```"`"``#\_________WQB
+M`@```````@```"`"``#\_________Z1B`@```````@```+X```#\________
+M_Z]B`@```````@```-,!``#\_________[IB`@```````@```&$!``#\____
+M_____]%B`@```````@```.4```#\_________]MB`@```````@```#("``#\
+M_________T5D`@```````@```+X```#\_________U!D`@```````@```-,!
+M``#\_________Y]D`@```````@```+X```#\_________ZID`@```````@``
+M`-,!``#\_________\%D`@```````@```*H!``#\_________\YE`@``````
+M`@```!0"``#\_________R=F`@``````"P````8````$`@```````#%F`@``
+M`````@```#T"``#\_________T1F`@```````@```+X```#\_________T]F
+M`@```````@```-,!``#\_________Y9F`@```````@```%D!``#\________
+M_R-G`@```````@```%D!``#\_________XMG`@```````@```*H!``#\____
+M_____U5H`@```````@```#("``#\_________]AH`@```````@```#("``#\
+M_________RYI`@```````@```#("``#\_________T]I`@```````@```+X`
+M``#\_________UII`@```````@```-,!``#\_________VAI`@```````@``
+M`*D!``#\_________REJ`@```````@```#("``#\_________VYJ`@``````
+M`@```#("``#\_________X]J`@```````@```+X```#\_________YIJ`@``
+M`````@```-,!``#\_________ZAJ`@```````@```*D!``#\_________]YJ
+M`@```````@```#("``#\_________S=K`@```````@```#("``#\________
+M_Y1K`@```````@```#("``#\_________\]K`@```````@```#@!``#\____
+M______]K`@```````@```+X```#\_________PIL`@```````@```-,!``#\
+M_________Q5L`@```````@```*H!``#\_________WAL`@```````@```"`"
+M``#\_________Q]O`@```````@```,````#\_________S-O`@```````@``
+M`,````#\_________T]O`@```````@```,````#\_________]=O`@``````
+M`@```,````#\_________^MO`@```````@```,````#\_________PEP`@``
+M`````@```,````#\_________TYP`@```````@```"4!``#\_________WYP
+M`@```````@```'$!``#\_________\9P`@```````@```%T!``#\________
+M_P]Q`@```````@```,T```#\_________Q=Q`@```````@```!8!``#\____
+M_____R9Q`@``````"P````,```"X$````````&]Q`@```````@```/,```#\
+M_________X1Q`@```````@```"P!``#\_________^9Q`@```````@```#("
+M``#\_________W5W`@```````@````L```#\`````````(%W`@``````"P``
+M``L``````0```````(YW`@```````@```.\```#\_________]9W`@``````
+M`@```*<!``#\_________ZYX`@```````@```#4!``#\_________]MX`@``
+M`````@```)L!``#\_________^IX`@```````@```#4!``#\_________\IY
+M`@```````@```%D!``#\_________Q%Z`@```````@```&T!``#\________
+M_RYZ`@```````@```!0"``#\_________T5Z`@```````@```-\```#\____
+M_____\-Z`@```````@```#$!``#\__________IZ`@```````@```"P!``#\
+M_________T)[`@```````@```%`!``#\_________W%\`@```````@```#("
+M``#\_________X-]`@```````@````L```#^`````````)!]`@``````"P``
+M``L``````0```````)I]`@```````@```.\```#\_________]M]`@``````
+M`@````L```#^`````````.A]`@``````"P````L``````0```````/)]`@``
+M`````@```.\```#\_________W-^`@```````@```"`"``#\_________\%^
+M`@```````@```"`"``#\_________]E^`@```````@```.,```#\________
+M_^M^`@```````@```.,```#\__________U^`@```````@```.,```#\____
+M_____P]_`@```````@```.,```#\_________R%_`@```````@```.,```#\
+M_________S-_`@```````@```.,```#\_________U9_`@```````@```"`"
+M``#\_________Z-_`@```````@```"`"``#\_________\-_`@```````@``
+M`"`"``#\_________TR``@```````@```.,```#\_________Y6``@``````
+M`@```)8!``#\_________ZF``@```````@```(\!``#\_________SN!`@``
+M`````@```!0"``#\_________VB!`@```````@```!0"``#\_________W.!
+M`@``````"P```(H!`````````````(&!`@```````@```%,!``#\________
+M_XR!`@```````@```-,```#\_________]F!`@```````@```)8!``#\____
+M_____^F!`@```````@```(\!``#\_________T."`@``````"P```(H!````
+M`````````%&"`@```````@```%,!``#\_________UR"`@```````@```-,`
+M``#\_________[B"`@```````@```!H!``#\_________\:"`@```````@``
+M`.4```#\_________]""`@```````@```#("``#\_________P2#`@``````
+M`@```!`!``#\_________Q2#`@```````@```.4```#\_________QZ#`@``
+M`````@```#("``#\_________T.#`@```````@```!H!``#\_________U2#
+M`@```````@```.4```#\_________UZ#`@```````@```#("``#\________
+M_Z6#`@```````@```!`!``#\_________SV$`@```````@```-````#\____
+M_____TB$`@```````@```-,!``#\_________].&`@```````@```,L!``#\
+M__________&&`@```````@```"`!``#\_________]:'`@```````@```$@!
+M``#\_________^N'`@``````"P```&@!`````````````"N(`@```````@``
+M`,L!``#\_________SV(`@```````@```"`!``#\_________]2(`@``````
+M`@```$@!``#\_________P&)`@```````@```$@!``#\_________Z^)`@``
+M`````@`````!``#\_________\>)`@```````@````T!``#\_________]^)
+M`@```````@```%L!``#\_________T>*`@``````"P````,```#X$```````
+M`+2-`@```````@```%H!``#\_________T*.`@```````@```%H!``#\____
+M_____UN.`@```````@```!0"``#\_________RV/`@```````@```/````#\
+M_________[20`@```````@```"`"``#\_________\B0`@```````@```"`"
+M``#\_________]:0`@```````@```#("``#\_________Q^1`@```````@``
+M``<```#D`0```````&J1`@```````@```"`"``#\_________YZ1`@``````
+M"P````<```#@`0```````,:1`@```````@````<```#T`0```````!22`@``
+M`````@```"`"``#\_________XF2`@```````@````<````$`@```````->2
+M`@```````@```"`"``#\_________PN3`@``````"P````<``````@``````
+M`"Z3`@```````@````<````4`@```````'R3`@```````@```"`"``#\____
+M_____^>3`@``````"P````<```#P`0```````/F3`@``````"P````<````0
+M`@```````(^4`@```````@```"`"``#\_________R*5`@```````@```"`"
+M``#\_________\&5`@```````@```"`"``#\_________^"5`@```````@``
+M`#("``#\_________ZZ6`@```````@```,X```#\_________V"9`@``````
+M`@```(@!``#\_________^>:`@```````@````,````<%@```````/.:`@``
+M````"P````<```!@`P```````&>?`@``````"P````<````@`@```````&R?
+M`@```````@````4"``#\_________^J?`@```````@```.\```#\________
+M__B?`@```````@```#("``#\_________PV@`@```````@```+,!``#\____
+M_____S>@`@``````"P````8````8`@```````$&@`@```````@```#T"``#\
+M_________Y:@`@```````@```"@"``#\_________ZJ@`@```````@```"@"
+M``#\_________[Z@`@```````@```"@"``#\_________S&A`@```````@``
+M`+D!``#\_________TNA`@```````@```#$"``#\_________UZA`@``````
+M`@```#$"``#\_________WBA`@```````@```#$"``#\_________XNA`@``
+M`````@```#$"``#\_________Z6A`@```````@```#$"``#\_________[BA
+M`@```````@```#$"``#\_________]*A`@```````@```#$"``#\________
+M_^6A`@```````@```#$"``#\_________Q.B`@```````@```#$"``#\____
+M_____R.B`@```````@```#$"``#\_________TJB`@```````@```#$"``#\
+M_________UVB`@```````@```#$"``#\_________W>B`@```````@```#$"
+M``#\_________XJB`@```````@```#$"``#\_________Z2B`@```````@``
+M`#$"``#\_________[>B`@```````@```#$"``#\_________]&B`@``````
+M`@```#$"``#\_________^2B`@```````@```#$"``#\__________ZB`@``
+M`````@```#$"``#\_________Q&C`@```````@```#$"``#\_________RNC
+M`@```````@```#$"``#\_________SZC`@```````@```#$"``#\________
+M_UBC`@```````@```#$"``#\_________VNC`@```````@```#$"``#\____
+M_____X6C`@```````@```#$"``#\_________YBC`@```````@```#$"``#\
+M_________[*C`@```````@```#$"``#\_________\6C`@```````@```#$"
+M``#\_________]^C`@```````@```#$"``#\__________*C`@```````@``
+M`#$"``#\_________PRD`@```````@```#$"``#\_________Q^D`@``````
+M`@```#$"``#\_________SFD`@```````@```#$"``#\_________TRD`@``
+M`````@```#$"``#\_________V:D`@```````@```#$"``#\_________WFD
+M`@```````@```#$"``#\_________Y.D`@```````@```#$"``#\________
+M_Z:D`@```````@```#$"``#\_________\BD`@```````@```&("``#\____
+M_____^*D`@```````@```&("``#\_________P2E`@```````@```&("``#\
+M_________QZE`@```````@```&("``#\_________T"E`@```````@```&("
+M``#\_________UJE`@```````@```&("``#\_________WRE`@```````@``
+M`&("``#\_________Y:E`@```````@```&("``#\_________[BE`@``````
+M`@```&("``#\_________]*E`@```````@```&("``#\__________2E`@``
+M`````@```&("``#\_________PZF`@```````@```&("``#\_________S"F
+M`@```````@```&("``#\_________TJF`@```````@```&("``#\________
+M_VRF`@```````@```&("``#\_________X:F`@```````@```&("``#\____
+M_____[*F`@```````@```-H```#\_________[JF`@```````@```$8!``#\
+M_________\FF`@```````@```$8!``#\_________]&F`@```````@```"@!
+M``#\_________]NF`@```````@```#("``#\_________^.F`@```````@``
+M`%P!``#\__________"F`@```````@```"$!``#\__________VF`@``````
+M`@```"$!``#\_________QVG`@```````@```"$!``#\_________S6G`@``
+M`````@```#T!``#\_________TBG`@```````@```#T!``#\_________U6G
+M`@```````@```#T!``#\_________VBG`@```````@```#T!``#\________
+M_W6G`@```````@```.4```#\_________WZG`@```````@```$8"``#[____
+M_____]VG`@```````@```)8!``#\_________S^H`@``````"P````$```"0
+MG`(``````$JH`@```````@```-,```#\_________X&H`@```````@```+\`
+M``#\_________Y.H`@```````@```#("``#\_________YNH`@```````@``
+M`.4```#\_________^&H`@```````@```-,!``#\_________VJI`@``````
+M`@```)8!``#\_________^NI`@``````"P````$```"0G`(``````/:I`@``
+M`````@```-,```#\_________RVJ`@```````@```+\```#\_________S^J
+M`@```````@```#("``#\_________T>J`@```````@```.4```#\________
+M_X2J`@```````@```-0!``#\_________PRK`@``````"P````$```"0G`(`
+M`````!FK`@```````@```%,!``#\_________RZK`@```````@```+P```#\
+M_________SFK`@```````@```-,```#\_________W"K`@```````@```+\`
+M``#\_________X*K`@```````@```#("``#\_________XJK`@```````@``
+M`.4```#\_________[JK`@```````@```+X```#\_________\^K`@``````
+M`@```-,!``#\_________]>K`@```````@```)8!``#\_________^RK`@``
+M`````@```+X```#\__________VL`@``````"P````$```"0G`(```````JM
+M`@```````@```%,!``#\_________Q^M`@```````@```+P```#\________
+M_RJM`@```````@```-,```#\_________V&M`@```````@```+\```#\____
+M_____W.M`@```````@```#("``#\_________WNM`@```````@```.4```#\
+M_________[6M`@```````@```+X```#\_________\RM`@```````@```-,!
+M``#\_________VNN`@```````@```)8!``#\_________Y&N`@``````"P``
+M``8````T`@```````)NN`@```````@```#T"``#\_________Z>N`@``````
+M`@```-0!``#\_________\"N`@```````@```-,!``#\__________*N`@``
+M`````@```$D"``#\_________PNO`@```````@```+\```#\_________UNO
+M`@```````@```!0"``#\_________T.P`@```````@```+H!``#\________
+M_YNP`@``````"P````$```"0G`(``````*JP`@```````@```%,!``#\____
+M_____\6P`@```````@```+P```#\_________]NP`@```````@```-,```#\
+M_________Q>Q`@```````@```+\```#\_________RFQ`@```````@```#("
+M``#\_________S.Q`@```````@```.4```#\_________W6Q`@```````@``
+M`!0"``#\_________Z>Q`@```````@```+X```#\_________[RQ`@``````
+M`@```!D!``#\_________\NQ`@```````@```-,!``#\_________^BQ`@``
+M`````@```$D"``#\_________\BR`@```````@```+X```#\_________]BR
+M`@```````@```!D!``#\_________^.R`@```````@```-,!``#\________
+M_[RS`@```````@```+\```#\__________ZS`@```````@```+X!``#\____
+M_____T2T`@```````@```&$!``#\_________UFT`@```````@```$H!``#\
+M_________WBT`@```````@```*H!``#\_________\*T`@```````@```(,!
+M``#\_________^FU`@```````@```&0!``#\_________Q&V`@```````@``
+M`,0!``#\_________S&V`@```````@```$L"``#\_________VFV`@``````
+M`@```-H```#\_________W&V`@```````@```&`!``#\_________WFV`@``
+M`````@```&`!``#\_________X:V`@```````@```"$!``#\_________XZV
+M`@```````@```$8!``#\_________YJV`@```````@```$8!``#\________
+M_Z:V`@```````@```"@!``#\_________["V`@```````@```#("``#\____
+M_____[BV`@```````@```%P!``#\_________\VV`@``````"P```/\`````
+M`````````.2V`@```````@```"L"``#\__________&V`@```````@```%$!
+M``#\_________Q6W`@```````@```&4!``#\_________R2W`@```````@``
+M`&4!``#\_________TFW`@```````@````L```"_`0```````%:W`@``````
+M`@````L```"\`0```````&&W`@```````@````,````<%@```````'"W`@``
+M````"P````<```!@`P```````'>W`@``````"P```/H``````````````'ZW
+M`@``````"P````<```!T`P```````(JW`@``````"P````<```!B`P``````
+M`-6W`@``````"P```/H````<`````````.VW`@``````"P```/H````<````
+M``````&X`@``````"P```/H````<``````````^X`@``````"P```/H````<
+M`````````!FX`@``````"P```/H````<`````````$^X`@``````"P```/H`
+M```<`````````&.X`@``````"P```/H````<`````````'&X`@``````"P``
+M`/H````<`````````(RX`@``````"P````<```!L`P```````-6X`@``````
+M`@````,````<%@```````/.X`@``````"P````<```!L`P````````&Y`@``
+M````"P````<```!P`P```````#&Y`@``````"P```/H``````````````$6Y
+M`@``````"P```/H````<`````````'"Y`@``````"P```/H````,````````
+M`):Y`@``````"P```/H````=`````````*6Y`@``````"P```/H````<````
+M`````-ZY`@```````@````X"``#\_________V:Z`@```````@```(T!``#\
+M_________X*Z`@```````@```,(```#\_________XJZ`@```````@```(,!
+M``#\_________ZBZ`@```````@```$T!``#\_________[RZ`@```````@``
+M`$T!``#\_________V&[`@``````"P````4````8"P```````&N[`@``````
+M`@```#T"``#\_________WV[`@```````@```)8!``#\_________[&[`@``
+M````"P````4```!@"P```````+N[`@```````@```#T"``#\_________P"\
+M`@``````"P````$```"0G`(```````N\`@```````@```-,```#\________
+M_T*\`@```````@```+\```#\_________U2\`@```````@```#("``#\____
+M_____UR\`@```````@```.4```#\_________Y^\`@```````@```)8!``#\
+M_________\6\`@```````@```-0!``#\_________^2\`@```````@```-,!
+M``#\_________T^]`@``````"P````$```"0G`(``````%Z]`@```````@``
+M`%,!``#\_________W"]`@```````@```+P```#\_________WN]`@``````
+M`@```-,```#\_________[*]`@```````@```+\```#\_________\2]`@``
+M`````@```#("``#\_________\R]`@```````@```.4```#\__________R]
+M`@```````@```$P!``#\_________R&^`@```````@```+X```#\________
+M_RR^`@```````@```-,!``#\_________T.^`@```````@```-,!``#\____
+M_____Z:^`@``````"P````,```#@$0```````-N^`@```````@```"0!``#\
+M_________Q2_`@```````@```!4!``#\_________TJ_`@```````@```$D"
+M``#\_________U^_`@```````@```+\```#\_________W:_`@```````@``
+M`#("``#\_________WZ_`@```````@```.4```#\_________[>_`@``````
+M`@```$D"``#\_________\N_`@```````@```,X!``#\_________]>_`@``
+M`````@```*L!``#\_________[+``@``````"P````4```"H"P```````+S`
+M`@```````@```#T"``#\__________#``@```````@````T"``#\________
+M_P7!`@``````"P````$`````P`(``````!G!`@```````@```"L"``#\____
+M_____[[#`@```````@```(T!``#\_________^##`@```````@```,(```#\
+M_________PW$`@```````@```%D!``#\_________WC$`@```````@```%D!
+M``#\_________]3$`@```````@```$D"``#\_________Q3%`@```````@``
+M`%D!``#\_________X#%`@```````@```$D"``#\_________Z;&`@``````
+M`@```"0!``#\__________S&`@```````@```&0!``#\_________P['`@``
+M`````@```$T!``#\_________TG'`@```````@```.4```#\_________V_'
+M`@```````@```%$!``#\_________X_'`@```````@````T"``#\________
+M_Z3'`@``````"P```/\``````````````+?'`@```````@```"L"``#\____
+M_____QG)`@```````@```(,!``#\_________VW)`@``````"P````,````P
+M$@```````)7)`@```````@```.D```#\__________#)`@```````@```.D`
+M``#\_________TO*`@```````@```.D```#\_________Z;*`@```````@``
+M`.D```#\__________?+`@``````"P````,```!0$P```````"C,`@``````
+M`@```.D```#\_________XC,`@```````@```.D```#\_________^#,`@``
+M`````@```.D```#\_________SC-`@```````@```.D```#\_________Y'-
+M`@```````@```.D```#\_________^C-`@```````@```.D```#\________
+M_T3.`@```````@```.D```#\_________Z#.`@```````@```.D```#\____
+M______C.`@```````@```.D```#\_________U#/`@```````@```.D```#\
+M_________Z#/`@```````@```"4!``#\_________]K/`@```````@```"4!
+M``#\_________Q30`@```````@```"4!``#\_________T[0`@```````@``
+M`"4!``#\_________X70`@```````@```"4!``#\_________[S0`@``````
+M`@```"4!``#\_________U;1`@```````@````L```"\`0```````&+1`@``
+M`````@````L```"\`0```````$_3`@```````@```!P"``#\_________VG3
+M`@```````@```!P"``#\_________[/3`@```````@````,````<%@``````
+M`,G3`@``````"P````<```!@`P```````-O3`@``````"P````<```!B`P``
+M`````.G3`@``````"P````<```!P`P```````/+3`@``````"P````<```!P
+M`P```````/G3`@``````"P````<```!L`P```````!/4`@``````"P````<`
+M``!P`P```````$W4`@```````@```%8"``#\_________V_4`@```````@``
+M`$X"``#\_________YW4`@``````"P```/H``````````````+74`@``````
+M"P```/H````<`````````-S4`@``````"P```/H````,`````````/G4`@``
+M````"P```/H````=``````````/5`@``````"P```/H````=``````````O5
+M`@``````"P```/H````<`````````"C5`@``````"P```/H````=````````
+M`#S5`@``````"P```/H````<`````````*[6`@```````@```(,!``#\____
+M_____SW8`@```````@```#4!``#\_________V[8`@```````@```)L!``#\
+M_________WW8`@```````@```#4!``#\_________R#<`@```````@```#4!
+M``#\_________T[<`@```````@```)L!``#\_________UW<`@```````@``
+M`#4!``#\_________S_@`@```````@```#4!``#\_________VW@`@``````
+M`@```)L!``#\_________W[@`@```````@```#4!``#\_________S_D`@``
+M`````@```#4!``#\_________VWD`@```````@```)L!``#\_________W[D
+M`@```````@```#4!``#\_________^3F`@```````@```)8!``#\________
+M_^#H`@```````@```!0"``#\_________ZSJ`@``````"P````$```!`L@(`
+M`````"OK`@```````@```+H!``#\_________SCK`@```````@```%,!``#\
+M_________TOK`@```````@```+P```#\_________VGK`@```````@```%,!
+M``#\_________WOK`@```````@```-0!``#\_________ZSK`@```````@``
+M`+P```#\_________\'K`@```````@````X!``#\__________+K`@``````
+M`@```+P```#\_________S?L`@```````@```!0"``#\_________ZKL`@``
+M`````@```!0"``#\_________^[L`@```````@```-,```#\__________OL
+M`@```````@```-,!``#\_________YCO`@```````@```%8"``#\________
+M_[KO`@```````@```%8"``#\_________Q+Q`@```````@```+X!``#\____
+M_____VCQ`@```````@```%D!``#\_________\#Q`@```````@```$H!``#\
+M__________'Q`@```````@```&$!``#\_________R_R`@```````@```!T!
+M``#\_________UKR`@```````@```*H!``#\_________X3R`@```````@``
+M`%D!``#\_________][R`@```````@```"D!``#\_________R/S`@``````
+M`@```"H"``#\_________R[S`@```````@```"H"``#\_________T+S`@``
+M`````@```.0!``#\_________W/S`@```````@```"("``#\_________QKT
+M`@```````@```"("``#\_________V3T`@```````@```/4!``#\________
+M_^/T`@```````@```-H!``#\__________#T`@```````@```-H!``#\____
+M______KT`@```````@```.0!``#\_________P;U`@```````@```.0!``#\
+M_________QGU`@```````@```-H!``#\_________VKU`@```````@```#,"
+M``#[_________^/U`@```````@```-H!``#\_________]/V`@```````@``
+M`"("``#\_________WWW`@```````@```#4"``#\_________\'W`@``````
+M`@```#4"``#\_________TCX`@```````@```#4"``#\_________VSX`@``
+M`````@```%,"``#\_________^GX`@```````@```#4"``#\_________S/Y
+M`@```````@```#4"``#\_________TWY`@```````@```%,"``#\________
+M_UKZ`@```````@```%,"``#\_________X7Z`@``````"P````8```!4`@``
+M`````(SZ`@```````@```#T"``#\_________XO[`@```````@```/`!``#[
+M_________Z;[`@```````@````T"``#\_________[[[`@``````"P```.8!
+M`````````````('\`@```````@```/`!``#[_________Y;\`@```````@``
+M``T"``#\_________ZS\`@``````"P```.8!`````````````+[\`@``````
+M`@```"L"``#\_________^7\`@```````@```$`"``#\_________V7]`@``
+M`````@```!T"``#\_________SG^`@```````@```$,"``#[_________W;^
+M`@```````@```.$!``#\_________\?_`@```````@```$\"``#\________
+M__+_`@```````@```/$!``#\_________P@``P```````@```#,"``#[____
+M_____Q<``P```````@```/H!``#\_________R$``P```````@```.(!``#\
+M_________S0``P```````@```.P!``#\_________YD``P```````@````L`
+M``!,`@```````+H``P```````@````L```!,`@```````,H``P```````@``
+M``L```!,`@```````-H``P```````@```%X"``#\__________@``P``````
+M`@```$`"``#\_________P4!`P```````@````L```!,`@```````!,!`P``
+M````"P````$```#``@,``````"@!`P```````@```#$"``#\_________SP!
+M`P```````@````L```!(`@```````',!`P```````@```$4"``#\________
+M_WH!`P``````"P````L````@`@```````(0!`P```````@````L````H`@``
+M`````(@!`P``````"P```&,"`````````````(\!`P```````@````L````T
+M`@```````)L!`P```````@````L````<`@```````*`!`P```````@```"L"
+M``#\_________Q0"`P```````@```-H!``#\_________V("`P```````@``
+M`&,"``#\_________Y8"`P```````@```#("``#\_________YX"`P``````
+M`@```!4"``#\_________^@"`P```````@```/(!``#\_________S4#`P``
+M`````@```#$"``#\_________U`#`P```````@```#$"``#\__________(#
+M`P```````@```/\!``#\__________($`P```````@```!$"``#\________
+M__X$`P```````@```$`"``#\_________T(%`P```````@```#$"``#\____
+M_____U$%`P```````@```-P!``#\_________\(%`P```````@```#X"``#\
+M_________]@%`P```````@```#X"``#\_________^@%`P```````@```-H!
+M``#\_________RH&`P```````@```#X"``#\_________T<&`P```````@``
+M`#X"``#\_________V$&`P```````@```#X"``#\_________WX&`P``````
+M`@```#X"``#\_________YX&`P```````@```#X"``#\_________\<&`P``
+M`````@```!8"``#\_________]X&`P```````@```#X"``#\_________^4&
+M`P```````@```-H!``#\_________SD'`P```````@```"("``#\________
+M_T('`P```````@```$0"``#\_________V`'`P```````@```"("``#[____
+M_____]T'`P```````@```"("``#\__________8'`P```````@```#,"``#[
+M_________R,(`P```````@```.H!``#\_________SP(`P```````@```$`"
+M``#\_________U<(`P```````@````L```!0`@```````&<(`P```````@``
+M``L```!0`@```````&H)`P```````@```#$"``#\_________W4)`P``````
+M`@```"("``#\_________[@)`P```````@```!$"``#\__________<)`P``
+M`````@```#$"``#\_________Q`*`P```````@```-H!``#\_________V$*
+M`P```````@```"("``#\_________QOY`@```````@````<"``#\________
+M_ROY`@```````@```#4"``#\___________Y`@```````@````<"``#\____
+M_____W7Z`@```````@````<"``#\__________/Z`@```````@````T"``#\
+M_________]7[`@```````@```"L"``#\_________ZS]`@```````@```&$"
+M``#\_________[W]`@```````@```#$"``#\_________^']`@```````@``
+M`#<"``#\_________X4"`P```````@```#4"``#\_________\L#`P``````
+M`@```#$"``#\_________Y,*`P``````"P````$```!@,@,``````+8*`P``
+M`````@````<```"X`P```````&`+`P``````"P````$```#P$`,``````$(-
+M`P```````@```$$"``#\_________WX-`P```````@```#0"``#\________
+M_[$-`P``````"P````$```"@#P,``````-T-`P```````@```#0"``#\____
+M_____UD.`P```````@````,````D%@```````&8.`P```````@````,````H
+M%@```````+X.`P``````"P````$```!P$`,``````#8/`P```````@```-8!
+M``#\_________X(/`P``````"P````$```"P#P,``````,8/`P```````@``
+M`!<"``#\_________PD0`P```````@```"H"``#\_________P\0`P``````
+M`@````<```"T`P```````"L0`P```````@````<```"X`P```````$40`P``
+M`````@````<```"X`P```````%$0`P``````"P````<```"@`P```````%<0
+M`P```````@````<```"W`P```````%T0`P```````@```%T"``#\________
+M_YP0`P```````@```!<"``#\_________T81`P```````@```#$"``#\____
+M_____U01`P``````"P````$`````#0,``````(L1`P``````"P````<```"@
+M`P```````)<1`P```````@```!`"``#\_________[$2`P``````"P````<`
+M``"@`P```````+82`P```````@```!`"``#\_________[X2`P```````@``
+M`$`"``#\_________ZH3`P``````"P````<```"@`P```````*\3`P``````
+M`@```!`"``#\_________[<3`P```````@```$`"``#\_________PL4`P``
+M````"P````<```"@`P```````!`4`P```````@```!`"``#\_________Q@4
+M`P```````@```$`"``#\_________TD4`P``````"P````<```"@`P``````
+M`$X4`P```````@```!`"``#\_________U84`P```````@```$`"``#\____
+M_____XX4`P``````"P````<```"@`P```````),4`P```````@```!`"``#\
+M_________YL4`P```````@```$`"``#\__________$4`P``````"P````<`
+M``"@`P````````85`P```````@```!`"``#\_________Q$5`P```````@``
+M`#$"``#\_________R45`P``````"P````<```"@`P```````#(5`P``````
+M`@```!`"``#\_________T\5`P```````@```#$"``#\_________]$5`P``
+M`````@```/L!``#\_________^H5`P```````@```$`"``#\_________P`6
+M`P``````"P````$````P$0,``````$,6`P```````@```-8!``#\________
+M_Y86`P``````"P````<```"@`P```````)L6`P```````@```!`"``#\____
+M______(6`P``````"P````,````P%@```````#<7`P```````@```&`"``#\
+M_________W`7`P```````@```/L!``#\_________WX7`P```````@```$L"
+M``#\_________Z<7`P```````@```$`"``#\_________\(7`P``````"P``
+M``$```#`&`,``````-87`P```````@```&`"``#\_________^,7`P``````
+M`@```$L"``#\_________S08`P``````"P````,```!P%@```````)@8`P``
+M`````@```&`"``#\_________^$8`P```````@```#$"``#\__________L8
+M`P``````"P````$```!P*@,``````!D9`P```````@```#,"``#[________
+M_W$9`P```````@```.\!``#\_________Y@9`P``````"P````<```"@`P``
+M`````)T9`P```````@```!`"``#\_________Z@9`P```````@```#$"``#\
+M_________]$9`P```````@```/L!``#\_________^<9`P```````@```/0!
+M``#\_________R<<`P```````@```/0!``#\_________U0<`P```````@``
+M`.\!``#\_________[4<`P```````@```/0!``#\_________]L<`P``````
+M`@```.\!``#\_________PH=`P``````"P````<```"@`P````````\=`P``
+M`````@```!`"``#\_________Q<=`P```````@```$`"``#\_________VD=
+M`P```````@```#,"``#[_________\H=`P```````@```.\!``#\________
+M__T=`P```````@```.\!``#\_________TD>`P```````@```.\!``#\____
+M_____V0>`P```````@```/L!``#\_________WH>`P```````@```/0!``#\
+M_________\H>`P```````@```#,"``#\_________Q@?`P```````@```.\!
+M``#\_________XH?`P``````"P````<```"@`P```````(\?`P```````@``
+M`!`"``#\_________YH?`P```````@```#$"``#\_________P<A`P``````
+M`@```/0!``#\_________Q4A`P``````"P````4`````#````````!XA`P``
+M`````@```#T"``#\_________TPA`P```````@```/0!``#\_________UDA
+M`P``````"P````4````H#````````&(A`P```````@```#T"``#\________
+M_Y\A`P```````@```.\!``#\_________\$A`P```````@```/0!``#\____
+M_____^,A`P```````@```/0!``#\__________XA`P``````"P````8```!P
+M`@```````"TB`P```````@```#T"``#\_________ULC`P```````@```/0!
+M``#\_________XLC`P```````@```.\!``#\_________Z\C`P```````@``
+M`.\!``#\_________]DC`P```````@```.T!``#\_________QTD`P``````
+M`@```.\!``#\_________T(D`P```````@```$,"``#[_________UXD`P``
+M`````@```/0!``#\_________WDD`P```````@```!@"``#\__________XD
+M`P```````@```.\!``#\_________PDE`P``````"P````4```!0#```````
+M`"HE`P```````@```#T"``#\_________\LE`P```````@```/0!``#\____
+M______0E`P```````@```.\!``#\_________Q\F`P```````@```.\!``#\
+M_________SDF`P``````"P````8```"%`@```````$`F`P```````@```#T"
+M``#\_________UTF`P```````@```/0!``#\_________XLF`P```````@``
+M`.\!``#\_________\(F`P```````@```.\!``#\_________\TF`P``````
+M"P````4```"`#````````.TF`P```````@```#T"``#\_________P\G`P``
+M`````@```!0"``#\_________TPG`P```````@```.\!``#\_________UPG
+M`P```````@```/D!``#\_________X`G`P```````@```.\!``#\________
+M_[,G`P```````@```.\!``#\_________^`G`P```````@```.\!``#\____
+M______<G`P```````@```!$"``#\_________PXH`P```````@```/0!``#\
+M_________T(H`P```````@```!@"``#\_________\TH`P```````@```/4!
+M``#\_________[0I`P```````@```%L"``#\_________^0I`P```````@``
+M`-<!``#\_________S,J`P```````@```#,"``#[_________V(J`P``````
+M`@```/<!``#\_________XTJ`P```````@```/(!``#\_________Z<J`P``
+M`````@```$,"``#[_________Q8K`P```````@```%4"``#\_________R`K
+M`P```````@```.P!``#\_________T(K`P``````"P```-D!````````````
+M`%DK`P```````@```&`"``#\_________P,L`P```````@```.X!``#\____
+M_____RDL`P```````@```!$"``#\_________YLL`P```````@```.X!``#\
+M_________[<L`P```````@```.X!``#\_________ZDM`P```````@```!@"
+M``#\_________QLN`P```````@```!$"``#\_________UPN`P```````@``
+M`.T!``#\_________]0N`P```````@```-P!``#\_________^$N`P``````
+M`@```$$"``#\_________R`O`P```````@```-@!``#\_________TLO`P``
+M`````@```-P!``#\_________XXO`P```````@```#$"``#\_________]`O
+M`P```````@```/$!``#\__________4O`P```````@```.$!``#\________
+M_^(P`P```````@```$$"``#\_________VPQ`P```````@```%4"``#\____
+M_____X$Q`P```````@```/H!``#\_________ZDQ`P```````@```.(!``#\
+M_________\\Q`P```````@```$`"``#\__________(Q`P``````"P````$`
+M``!P+P,``````"PR`P```````@```-8!``#\_________XHS`P```````@``
+M`%H"``#\__________8S`P``````"P````$```"@-`,```````4U`P``````
+M`@```%H"``#\__________0U`P```````@```/L!``#\_________\,-`P``
+M`````@```#D"``#\_________XL/`P```````@```#D"``#\_________Z$/
+M`P```````@```!<"``#\__________H/`P```````@```","``#\________
+M_]@0`P```````@```&`"``#\_________R,1`P```````@```&`"``#\____
+M_____W<1`P```````@```&`"``#\_________]P1`P```````@```#$"``#\
+M_________X,5`P```````@```#$"``#\_________[P6`P```````@```#X"
+M``#\_________P09`P```````@```.@!``#\_________U(=`P```````@``
+M`!$"``#\_________^,J`P```````@```/L!``#\_________PXK`P``````
+M`@```#$"``#\_________SLL`P```````@```.T!``#\__________LN`P``
+M`````@```!$"``#\_________V(O`P```````@```.T!``#\_________U@T
+M`P```````@```&`"``#\_________Y`T`P```````@```%H"``#\________
+M_ZPU`P```````@```&`"``#\_________R,V`P```````@```"("``#\____
+M_____PHW`P```````@```"("``#\_________\TW`P```````@```"("``#\
+M_________](X`P```````@```"("``#\_________X\Z`P``````"P````,`
+M``"P%@```````+0^`P```````@`````"``#\_________\0_`P```````@``
+M```"``#\_________X!``P``````"P````,```#P%@```````+)!`P``````
+M`@`````"``#\_________QU"`P```````@`````"``#\_________\%"`P``
+M`````@`````"``#\_________^)"`P```````@````L```!@`@```````/]"
+M`P```````@````L```!<`@```````!!#`P``````"P````L```"``@``````
+M`"M#`P``````"P````L```"``@```````%E#`P```````@````L```!@`@``
+M`````)Q#`P```````@```-\!``#\__________-(`P```````@`````"``#\
+M_________S-)`P```````@`````"``#\_________W-)`P```````@`````"
+M``#\_________]E)`P```````@`````"``#\_________T!*`P```````@``
+M```"``#\_________[Y*`P```````@`````"``#\_________T-+`P``````
+M`@```#,"``#[_________V-+`P```````@`````"``#\_________Y!+`P``
+M`````@`````"``#\_________S9,`P```````@`````"``#\_________UI,
+M`P```````@`````"``#\_________T9-`P```````@`````"``#\________
+M_VI-`P```````@`````"``#\_________P1.`P```````@`````"``#\____
+M_____RE.`P```````@`````"``#\_________Z1.`P```````@`````"``#\
+M_________[%.`P```````@`````"``#\_________^-.`P```````@`````"
+M``#\_________PE/`P```````@`````"``#\_________W1/`P```````@``
+M```"``#\_________X%/`P```````@`````"``#\_________\-/`P``````
+M`@`````"``#\_________^U/`P```````@`````"``#\_________TA0`P``
+M`````@`````"``#\_________U10`P```````@`````"``#\_________[A0
+M`P```````@`````"``#\_________\10`P```````@`````"``#\________
+M_RA1`P```````@`````"``#\_________S11`P```````@`````"``#\____
+M_____Y91`P```````@`````"``#\_________Z)1`P```````@`````"``#\
+M__________91`P```````@`````"``#\_________P)2`P```````@`````"
+M``#\_________U92`P```````@`````"``#\_________V)2`P```````@``
+M```"``#\_________[92`P```````@`````"``#\_________\)2`P``````
+M`@`````"``#\_________T93`P```````@`````"``#\_________U)3`P``
+M`````@`````"``#\_________[93`P```````@`````"``#\_________\)3
+M`P```````@`````"``#\_________R]4`P```````@`````"``#\________
+M_SQ4`P```````@`````"``#\_________TA4`P```````@`````"``#\____
+M_____U-4`P```````@`````"``#\_________^94`P```````@`````"``#\
+M__________)4`P```````@`````"``#\_________U95`P```````@`````"
+M``#\_________V)5`P```````@`````"``#\_________\I5`P```````@``
+M```"``#\_________]95`P```````@`````"``#\_________SQ6`P``````
+M`@`````"``#\_________TA6`P```````@`````"``#\_________U17`P``
+M`````@`````"``#\_________V%7`P```````@`````"``#\_________Q18
+M`P```````@`````"``#\_________R%8`P```````@`````"``#\________
+M_X98`P```````@`````"``#\_________Y)8`P```````@`````"``#\____
+M_____Q59`P```````@`````"``#\_________SI9`P```````@`````"``#\
+M_________\59`P```````@`````"``#\_________^I9`P```````@`````"
+M``#\_________U1:`P```````@`````"``#\_________V!:`P```````@``
+M```"``#\_________W1;`P```````@`````"``#\_________X%;`P``````
+M`@`````"``#\_________U)<`P```````@`````"``#\_________U]<`P``
+M`````@`````"``#\_________R!=`P```````@`````"``#\_________RU=
+M`P```````@`````"``#\_________V1=`P```````@````<````<!```````
+M`'M=`P``````"P````<````@!````````,%>`P``````"P````$```#00@,`
+M`````,-?`P```````@```-\!``#\_________U-@`P```````@```$,"``#\
+M_________\Y@`P```````@```#0"``#\__________U@`P``````"P````$`
+M``"`:@,``````$]A`P```````@```#0"``#\_________UYA`P```````@``
+M`$`"``#\_________Q5B`P```````@```#0"``#\_________VIB`P``````
+M"P````$```#0:P,``````'=B`P``````"P````$```"0:P,``````'QB`P``
+M`````@```#D"``#\_________]9B`P```````@```$`"``#\_________WIC
+M`P```````@```#$"``#\_________ZQC`P``````"P````8```">`@``````
+M`+-C`P```````@```#T"``#\__________9C`P```````@```$`"``#\____
+M_____XED`P```````@```#$"``#\_________[MD`P``````"P````8```"Y
+M`@```````,)D`P```````@```#T"``#\_________VUE`P``````"P````$`
+M``#0G0,``````)UE`P``````"P````$```#P;P,``````-UE`P``````"P``
+M``$```"`<0,``````!UF`P``````"P````$```#@\@,``````%UF`P``````
+M"P````$````0XP,``````)UF`P``````"P````$```"`J@,``````-UF`P``
+M````"P````$```"0YP,``````!UG`P``````"P````$```"@K@,``````%UG
+M`P``````"P````$```!@JP,``````)UG`P``````"P````$```!0]@,`````
+M`-UG`P``````"P````$````@GP,``````!UH`P``````"P````$````0Z@,`
+M`````%UH`P``````"P````$```"`KP,``````)UH`P``````"P````$```"`
+MKP,``````-UH`P``````"P````$```"@L0,``````!UI`P``````"P````$`
+M``"`P@,``````%UI`P``````"P````$```!0]P,``````)UI`P``````"P``
+M``$`````Q`,``````-UI`P``````"P````$````@ZP,``````!UJ`P``````
+M"P````$```#PP@,``````%UJ`P``````"P````$```"0S`,``````(1J`P``
+M````"P````$````@_P,``````+AJ`P``````"P````$````PS0,``````!!K
+M`P```````@```#$"``#\_________QMK`P``````"P````$```!0Q`,`````
+M`*-K`P``````"P````$```"@;`,``````"QL`P```````@```!<"``#\____
+M_____SML`P```````@```#0"``#\_________VQL`P``````"P````$```"0
+M:P,``````,ML`P```````@```#$"``#\_________WUM`P``````"P````4`
+M``#8#````````(1M`P```````@```#T"``#\_________Y%M`P```````@``
+M`/L!``#\_________Z9M`P```````@```#$"``#\_________ZYM`P``````
+M`@```!<"``#\_________]IM`P``````"P````4```"P#````````.%M`P``
+M`````@```#T"``#\_________^YM`P```````@```/L!``#\_________QIN
+M`P```````@```!<"``#\_________R9N`P``````"P````$```"```0`````
+M`+AN`P```````@```#$"``#\_________\!N`P```````@```!<"``#\____
+M_____S1O`P``````"P````$````@F0,```````UP`P```````@`````"``#\
+M_________]AP`P```````@```.\!``#\_________^1P`P``````"P````$`
+M``#@7@,``````%QQ`P```````@```.\!``#\_________Y9Q`P```````@``
+M```"``#\_________P]R`P```````@```.\!``#\_________S!R`P``````
+M"P````$```#@7@,``````(-R`P```````@```!<"``#\_________XMR`P``
+M````"P````$```#@7@,``````&]S`P``````"P````$````0=0,``````$UT
+M`P``````"P````$```#@7@,``````%YT`P```````@```","``#\________
+M_R]U`P``````"P````$```#@7@,``````%YU`P```````@```"("``#\____
+M_____^9U`P``````"P````$```#@7@,``````/IU`P```````@```","``#\
+M_________Q)V`P```````@````L```!<`@```````!AV`P```````@````L`
+M``!@`@```````#5V`P``````"P````L```"``@```````$!V`P``````"P``
+M``L```"(`@```````$QV`P``````"P````L```"0`@```````%AV`P``````
+M"P````L```"8`@```````&1V`P``````"P````L```"@`@```````&]V`P``
+M````"P````L```"H`@```````(IV`P```````@````L```!<`@```````))V
+M`P``````"P````$```#@7@,``````"IW`P``````"P````$```#@7@,`````
+M`-%W`P``````"P````$```#@7@,``````.)W`P```````@```","``#\____
+M_____R]X`P```````@`````"``#\_________XMX`P``````"P````$```#@
+M7@,``````/5X`P```````@`````"``#\_________SEY`P``````"P````$`
+M``#@7@,``````(AY`P```````@```"("``#\_________]AY`P``````"P``
+M``$```#@7@,``````"UZ`P```````@```"("``#\_________ZUZ`P``````
+M"P````$```#@7@,``````(A[`P``````"P````$```#@7@,``````)M[`P``
+M`````@```","``#\_________VM\`P``````"P````$```#@7@,``````'Y\
+M`P```````@```","``#\_________VM]`P``````"P````$```#@7@,`````
+M`'Y]`P```````@```","``#\_________UM^`P``````"P````$```#@7@,`
+M`````&Y^`P```````@```","``#\_________TM_`P``````"P````$```#@
+M7@,``````%Y_`P```````@```","``#\_________RF``P``````"P````$`
+M``#@7@,``````#R``P```````@```","``#\_________W6``P``````"P``
+M``$```#@7@,``````"6!`P``````"P````$```#@7@,``````#:!`P``````
+M`@```","``#\_________W:!`P``````"P````$```#@7@,``````*2!`P``
+M````"P````8```#1`@```````,:!`P```````@```$,"``#\_________\Z!
+M`P``````"P````$```#@7@,``````/2!`P``````"P````8```#>`@``````
+M`!&"`P```````@```!H"``#\_________QJ"`P``````"P````8```#O`@``
+M`````"V"`P``````"P````8````,`P```````$B"`P``````"P````$```#P
+MB0,``````'J"`P```````@```-X!``#\_________X:"`P``````"P````8`
+M```I`P```````*&"`P``````"P````$```#P@@,``````,B"`P``````"P``
+M``$```#@7@,``````%J#`P``````"P````$```#@7@,``````&N#`P``````
+M`@```","``#\__________&#`P```````@`````"``#\_________R6$`P``
+M`````@```#$"``#\_________RV$`P```````@```!<"``#\_________VF$
+M`P``````"P````$```#@7@,``````"B%`P``````"P````$```#@F`,`````
+M`'N%`P```````@`````"``#\_________YN%`P```````@`````"``#\____
+M_____\:%`P```````@`````"``#\_________QB&`P```````@`````"``#\
+M_________VN&`P```````@`````"``#\_________YB&`P```````@`````"
+M``#\_________RB'`P```````@`````"``#\_________S*'`P```````@``
+M```"``#\_________VN'`P```````@`````"``#\_________XN'`P``````
+M`@`````"``#\_________ZB'`P```````@`````"``#\_________R"(`P``
+M`````@`````"``#\_________V"(`P```````@`````"``#\_________YR(
+M`P```````@`````"``#\_________]R(`P```````@`````"``#\________
+M_QR)`P```````@`````"``#\_________UV)`P```````@`````"``#\____
+M_____X>)`P``````"P````8````,`P```````$J*`P```````@```/`!``#\
+M_________XN*`P```````@````T"``#\_________Z&*`P``````"P```.8!
+M`````````````+.*`P```````@```"L"``#\_________\J*`P``````"P``
+M``$```#@7@,``````-N*`P```````@```","``#\__________**`P``````
+M`@```-L!``#\_________U6+`P```````@```#0"``#\_________QJ,`P``
+M````"P````$```!@Y`,``````&6,`P```````@```$`"``#\_________X^,
+M`P```````@```!0"``#\_________\:,`P``````"P````$```#P;`,`````
+M`-B,`P``````"P````$```#@7@,``````.N,`P```````@```","``#\____
+M_____^F-`P``````"P````$```#@7@,``````#".`P``````"P````$```#@
+M7@,``````$..`P```````@```","``#\_________WN.`P```````@`````"
+M``#\_________YN.`P```````@`````"``#\_________]2.`P```````@``
+M```"``#\_________^*.`P```````@```#0"``#\_________RJ/`P``````
+M`@```!0"``#\_________VV/`P``````"P````$```#`6P,``````'B/`P``
+M````"P````$```!@<@,``````-"/`P``````"P````$```#@7@,``````#60
+M`P``````"P````$```#@7@,``````$:0`P```````@```","``#\________
+M_W20`P```````@```#,"``#[_________Y:0`P``````"P````8```#>`@``
+M`````*V0`P``````"P````8```#O`@```````/:0`P```````@```-X!``#\
+M_________P61`P``````"P````$```#@7@,``````&21`P```````@```!H"
+M``#\_________X.1`P``````"P````8````,`P```````*21`P``````"P``
+M``8```#1`@```````.V1`P```````@```$,"``#\_________RZ2`P``````
+M`@```/`!``#\_________[V2`P```````@`````"``#\_________Q64`P``
+M`````@```.\!``#\_________U^4`P```````@```.\!``#\_________XV4
+M`P```````@```.\!``#\_________\26`P``````"P````$```#@7@,`````
+M`->6`P```````@```","``#\_________R&8`P``````"P````$```#@7@,`
+M`````#*8`P```````@```","``#\_________Y.8`P```````@```%@"``#\
+M_________YZ8`P```````@```#0"``#\_________[N8`P``````"P````$`
+M````;@,``````.N8`P```````@`````"``#\__________.8`P```````@``
+M`#L"``#\__________N8`P``````"P````$```#@7@,``````"F9`P``````
+M`@```#L"``#\_________SB9`P``````"P````$```#@7@,``````+Z9`P``
+M````"P````$`````90,``````%2:`P``````"P````$```!`G`,``````#>;
+M`P```````@```/L!``#\_________TB;`P```````@```-X!``#[________
+M_VB;`P```````@```-X!``#[_________]&;`P```````@```/L!``#\____
+M_____QV<`P```````@```/L!``#\_________X:<`P``````"P````$```!@
+MF0,``````-N=`P``````"P````$```!`G`,``````':>`P``````"P````$`
+M``!`G`,``````(:>`P```````@```"X"``#\_________]^>`P``````"P``
+M``$```!`G`,``````/^>`P```````@```"X"``#\_________S>?`P``````
+M`@`````"``#\_________U&?`P``````"P````$```#@7@,``````(6?`P``
+M````"P````,````P%P```````+:?`P```````@```/L!``#\_________U2@
+M`P```````@```/@!``#\_________W:@`P``````"P````$```!`G`,`````
+M`)R@`P```````@```"X"``#\_________ZF@`P```````@```/L!``#\____
+M_____\R@`P```````@```/L!``#\_________QNA`P```````@```/L!``#\
+M_________QBB`P```````@```/@!``#\_________T^B`P``````"P````$`
+M``!`G`,``````%^B`P```````@```"X"``#\_________VRB`P```````@``
+M`/L!``#\_________X6B`P```````@```/L!``#\_________SNC`P``````
+M`@```/L!``#\_________^6C`P```````@```/L!``#\_________VJD`P``
+M````"P````$```!`G`,``````'JD`P```````@```"X"``#\_________X>D
+M`P```````@```/L!``#\_________]2D`P```````@```/L!``#\________
+M_R>E`P```````@```!L"``#\_________SBE`P```````@```!L"``#\____
+M_____XZE`P```````@```/L!``#\_________]NE`P```````@```/L!``#\
+M_________^^E`P```````@```%4"``#\__________RE`P```````@```#L"
+M``#\_________PFF`P```````@```!L"``#\_________QFF`P```````@``
+M`%4"``#\_________S"F`P```````@```/@!``#\_________UVF`P``````
+M"P````$```!`G`,``````&VF`P```````@```"X"``#\_________WJF`P``
+M`````@```/L!``#\_________Y&F`P```````@````D"``#\_________Z^F
+M`P```````@```/@!``#\_________^>F`P``````"P````$```!`G`,`````
+M`/>F`P```````@```"X"``#\_________P2G`P```````@```/L!``#\____
+M_____S&G`P``````"P````$```!`G`,``````$&G`P```````@```"X"``#\
+M_________TZG`P```````@```/L!``#\_________W>G`P``````"P````$`
+M``!`G`,``````):G`P```````@```"X"``#\_________Z.G`P```````@``
+M`/L!``#\_________U:J`P```````@```/@!``#\_________YJJ`P``````
+M`@`````"``#\__________&J`P```````@```#L"``#\_________P.K`P``
+M````"P````$```#@7@,``````#>K`P```````@```/<!``#\_________Z*K
+M`P``````"P````$```#@7@,``````+.K`P```````@```","``#\________
+M_]&K`P```````@`````"``#\_________V6L`P```````@```/<!``#\____
+M_____^*N`P``````"P````$```#@7@,``````/.N`P```````@```","``#\
+M_________Q&O`P```````@`````"``#\_________RZO`P```````@```/<!
+M``#\_________XNO`P```````@`````"``#\_________\>O`P```````@``
+M`/<!``#\_________\^O`P``````"P````$```#@7@,``````%.P`P``````
+M`@```-P!``#\_________[.P`P```````@```!$"``#\_________^6P`P``
+M`````@```/,!``#\_________P>Q`P```````@```.\!``#\_________T>Q
+M`P```````@```.\!``#\_________U2Q`P```````@```/<!``#\________
+M_X.Q`P```````@```-P!``#\_________\JQ`P```````@`````"``#\____
+M_____Q&R`P``````"P````$```#@7@,```````6S`P```````@```#$"``#\
+M_________T^S`P```````@````D"``#\_________]6S`P```````@`````"
+M``#\__________.S`P``````"P````,```"H%P````````NT`P```````@``
+M`.H!``#\_________TBT`P```````@```.H!``#\_________X:T`P``````
+M`@`````"``#\_________[.U`P```````@```!@"``#\__________^U`P``
+M`````@`````"``#\_________R^V`P```````@```.L!``#\_________U:V
+M`P```````@```-P!``#\_________V2V`P```````@```!$"``#\________
+M_P:X`P```````@```!@"``#\_________\*X`P```````@`````"``#\____
+M_____QRY`P```````@`````"``#\_________S>Y`P```````@```.L!``#\
+M_________PNZ`P```````@```.`!``#\_________QF[`P```````@```$`"
+M``#\_________S.[`P```````@````D"``#\_________TJ[`P```````@``
+M`.4!``#\_________PN\`P```````@```#L"``#\_________Q.\`P``````
+M`@```!L"``#\_________V:\`P``````"P````$```!`G`,``````':\`P``
+M`````@```"X"``#\_________X.\`P```````@```/L!``#\_________^*\
+M`P``````"P````$```!`G`,``````/*\`P```````@```"X"``#\________
+M__^\`P```````@```/L!``#\_________SR]`P```````@```%@"``#\____
+M_____Y:]`P```````@```-P!``#\_________UJ^`P```````@`````"``#\
+M_________\V^`P```````@`````"``#\__________F^`P``````"P````$`
+M``!`G`,```````F_`P```````@```"X"``#\_________Q:_`P```````@``
+M`/L!``#\_________R._`P```````@```!L"``#\_________S6_`P``````
+M`@```%4"``#\_________U^_`P``````"P````$```!0;@,``````(N_`P``
+M````"P````$```!`G`,``````)N_`P```````@```"X"``#\_________ZB_
+M`P```````@```/L!``#\_________[2_`P``````"P````$```#@:@,`````
+M`'S``P```````@```.T!``#\_________Z?``P```````@```!L"``#\____
+M_____[O``P```````@```%@"``#\_________P;!`P```````@```.X!``#\
+M_________Q/!`P```````@```.T!``#\_________XK!`P```````@`````"
+M``#\_________Z7!`P```````@```.L!``#\_________\_!`P```````@``
+M`-P!``#\_________^?!`P```````@```.L!``#\_________RC"`P``````
+M`@```-P!``#\_________U["`P``````"P````$```#`@P,``````)'"`P``
+M`````@`````"``#\_________[C"`P``````"P````$```#@7@,``````-[#
+M`P``````"P````$```#@7@,``````._#`P```````@```","``#\________
+M_RK$`P``````"P````$```#@7@,``````&[$`P```````@```!<"``#\____
+M_____\3$`P```````@```%@"``#\_________\S$`P```````@```!L"``#\
+M_________^/$`P``````"P````$```#@7@,``````)C&`P```````@```!0"
+M``#\_________Z7&`P```````@```%L"``#\_________Y+'`P```````@``
+M```"``#\__________C'`P```````@```#H"``#\_________S7(`P``````
+M"P````$```#@7@,```````+)`P```````@```.,!``#\__________S)`P``
+M`````@```.D!``#\_________RW,`P```````@```!0"``#\_________SK,
+M`P```````@```%L"``#\_________[3,`P```````@```.P!``#\________
+M_\C,`P```````@`````"``#\_________]_,`P```````@```$$"``#\____
+M_____^?,`P```````@```.P!``#\__________7,`P``````"P````$```#@
+M7@,``````%?-`P```````@```#$"``#\_________\3-`P``````"P````$`
+M````^`,``````/C-`P```````@`````"``#\_________^?.`P``````"P``
+M``$```"0S0,``````!7/`P```````@```%<"``#\_________US0`P``````
+M"P````$```#@7@,``````*+0`P```````@```#0"``#\_________\K0`P``
+M````"P````$```"@W@,```````'1`P```````@```!<"``#\_________Z+2
+M`P``````"P````4````(#0```````*G2`P```````@```#T"``#\________
+M_^G4`P```````@```/@!``#\_________Q;5`P```````@```$`"``#\____
+M_____X+6`P``````"P````$```#0_@,``````%W7`P``````"P````$```#@
+M7@,``````.77`P```````@```$`"``#\__________S7`P```````@```#0"
+M``#\_________V#8`P```````@```!H"``#\__________K8`P``````"P``
+M``$```"0WP,``````,?9`P``````"P````$```"0WP,``````!7:`P``````
+M"P````$```#0_@,``````%W:`P```````@```#$"``#\_________W3:`P``
+M````"P````$```#@7@,``````);:`P```````@```#$"``#\_________Z+:
+M`P```````@```!<"``#\_________S7;`P```````@`````"``#\________
+M_X3;`P```````@`````"``#\_________P3<`P```````@`````"``#\____
+M_____X7<`P```````@`````"``#\_________]3<`P```````@`````"``#\
+M_________U3=`P```````@`````"``#\_________^?=`P```````@````@"
+M``#\__________[=`P```````@```"H"``#\_________W7>`P```````@``
+M`#\"``#\_________PO?`P```````@```#$"``#\_________QO?`P``````
+M`@```!<"``#\_________R/?`P``````"P````$```#@7@,``````-#?`P``
+M`````@```#$"``#\_________^'?`P```````@```!<"``#\_________^G?
+M`P``````"P````$```#@7@,``````';@`P```````@```/L!``#\________
+M_]/@`P```````@`````"``#\_________]_@`P```````@`````"``#\____
+M_____P_A`P```````@```%0"``#\_________X/A`P```````@```%0"``#\
+M_________Z+B`P```````@`````"``#\_________\WB`P```````@```%0"
+M``#\_________^3B`P``````"P````$```#@7@,``````&GC`P```````@``
+M```"``#\_________[#C`P```````@`````"``#\_________[CC`P``````
+M`@```$$"``#\_________]GC`P``````"P````$```#@7@,``````"7D`P``
+M`````@`````"``#\_________POE`P```````@```!<"``#\_________QOE
+M`P``````"P````$```#@7@,``````"SE`P```````@```","``#\________
+M_P3F`P```````@```-<!``#\_________U_F`P```````@```"("``#\____
+M_____V[F`P```````@```"("``#\_________W/F`P```````@```%P"``#\
+M_________]GF`P```````@```.H!``#\_________R3G`P```````@```"("
+M``#\_________VSG`P``````"P````$```#@7@,```````;H`P``````"P``
+M``$```#@Z`,``````!#H`P```````@```.@!``#\_________V'H`P``````
+M"P````$```#@7@,``````'+H`P```````@```","``#\_________Z3H`P``
+M````"P````$```#0Z`,``````+WH`P```````@```&`"``#\_________Q+I
+M`P```````@```/(!``#\_________R3I`P```````@```$,"``#[________
+M_S3I`P```````@```/L!``#\_________Y+I`P``````"P````$```#0Z`,`
+M`````,KI`P```````@```#$"``#\_________^KI`P```````@```#$"``#\
+M__________?I`P```````@```.P!``#\_________S#J`P```````@`````"
+M``#\_________SOJ`P```````@`````"``#\_________T;J`P```````@``
+M`/8!``#\_________UOJ`P``````"P````$```#@7@,``````)3J`P``````
+M`@```/`!``#[_________]'J`P```````@```/`!``#\_________];J`P``
+M`````@````("``#\__________/J`P``````"P```.8!`````````````%WK
+M`P```````@```!0"``#\_________XCK`P``````"P````$```#@7@,`````
+M`)GK`P```````@```","``#\_________^?K`P``````"P````$```#@7@,`
+M`````'/L`P```````@`````"``#\_________]7L`P```````@```#H"``#\
+M_________P;M`P``````"P````$```#@7@,``````*3M`P```````@```.,!
+M``#\_________Y[N`P```````@```.D!``#\_________UKO`P```````@``
+M```"``#\_________[OO`P``````"P````$```#@7@,``````##P`P``````
+M`@```.,!``#\_________SKQ`P```````@`````"``#\_________YKQ`P``
+M````"P````$```#@7@,```````[R`P```````@```.,!``#\__________KR
+M`P```````@```"("``#\_________TOS`P``````"P````$```#@7@,`````
+M`%SS`P```````@```","``#\_________VSS`P```````@`````"``#\____
+M_____[3S`P```````@```/<!``#\_________Z+T`P```````@```!L"``#\
+M_________\/T`P``````"P````,```#P%P```````#KV`P``````"P````$`
+M``#`@P,``````&+V`P```````@`````"``#\_________Q[W`P```````@``
+M`!L"``#\_________R;W`P``````"P````$```#@7@,``````&SW`P``````
+M`@`````"``#\_________Y[W`P```````@```!0"``#\_________\SW`P``
+M````"P````$```#@7@,``````-_W`P```````@```","``#\_________SGX
+M`P```````@```#0"``#\_________TOX`P```````@```!H"``#\________
+M_S'Y`P``````"P````$```!P^@,``````#SY`P``````"P````$````P1`,`
+M``````'Z`P```````@```"<"``#\_________Q_Z`P``````"P````$```#@
+M7@,``````,/Z`P``````"P````$```"0_@,``````&'\`P```````@```!<"
+M``#\_________WW\`P``````"P````$```#@7@,``````"K]`P```````@``
+M`!<"``#\_________UG]`P```````@```"<"``#\_________[K]`P``````
+M`@```!<"``#\_________TO^`P```````@```"<"``#\_________UW^`P``
+M`````@```"<"``#\_________UW_`P```````@```!<"``#\_________[__
+M`P```````@```#$"``#\_________]C_`P```````@`````"``#\________
+M_Q``!````````@```/,!``#\_________R\`!```````"P````$```#@7@,`
+M`````!4!!```````"P````$```#@7@,``````"8!!````````@```","``#\
+M_________S,!!````````@```/L!``#\_________TX!!```````"P````$`
+M``"P:@,``````!QA`P```````@```#D"``#\_________^9A`P```````@``
+M`#D"``#\_________Y=B`P```````@```#4"``#\__________-D`P``````
+M`@```#4"``#\_________WEE`P```````@```"\"``#\_________ZUE`P``
+M`````@```&`"``#\_________^UE`P```````@```&`"``#\_________RUF
+M`P```````@```&`"``#\_________VUF`P```````@```&`"``#\________
+M_ZUF`P```````@```&`"``#\_________^UF`P```````@```&`"``#\____
+M_____RUG`P```````@```&`"``#\_________VUG`P```````@```&`"``#\
+M_________ZUG`P```````@```&`"``#\_________^UG`P```````@```&`"
+M``#\_________RUH`P```````@```&`"``#\_________VUH`P```````@``
+M`&`"``#\_________ZUH`P```````@```&`"``#\_________^UH`P``````
+M`@```&`"``#\_________RUI`P```````@```&`"``#\_________VUI`P``
+M`````@```&`"``#\_________ZUI`P```````@```&`"``#\_________^UI
+M`P```````@```&`"``#\_________RUJ`P```````@```&`"``#\________
+M_VUJ`P```````@```&`"``#\_________Z!J`P```````@```&`"``#\____
+M_____]1J`P```````@```&`"``#\_________S5K`P```````@```&`"``#\
+M_________X1K`P```````@```#D"``#\_________[]K`P```````@```&`"
+M``#\_________\1K`P```````@```!<"``#\_________XYL`P```````@``
+M`#D"``#\_________^%L`P```````@```!<"``#\_________TEN`P``````
+M`@```&`"``#\_________V=O`P```````@```&`"``#\_________^AO`P``
+M`````@```#D"``#\_________PMQ`P```````@```","``#\_________U5R
+M`P```````@```","``#\_________Z5R`P```````@```","``#\________
+M_SMU`P```````@```","``#\_________ZMV`P```````@```","``#\____
+M_____U-W`P```````@```","``#\_________[1X`P```````@```","``#\
+M_________VAY`P```````@```","``#\__________1Y`P```````@```","
+M``#\_________\MZ`P```````@```","``#\_________X^``P```````@``
+M`","``#\_________YF!`P```````@```","``#\_________^V!`P``````
+M`@```","``#\_________W""`P```````@```&`"``#\_________^>"`P``
+M`````@```","``#\_________Y:$`P```````@```","``#\_________Q*%
+M`P```````@```#D"``#\_________UN%`P```````@```&`"``#\________
+M_VN%`P```````@```-8!``#\_________S^,`P```````@```#D"``#\____
+M_____Q2.`P```````@```","``#\_________V..`P```````@```!<"``#\
+M_________YB/`P```````@```#D"``#\__________F/`P```````@```","
+M``#\_________R:1`P```````@```","``#\_________]*8`P```````@``
+M`#D"``#\_________Q69`P```````@```","``#\_________U*9`P``````
+M`@```","``#\_________^29`P```````@```"X"``#\_________V*;`P``
+M`````@```/L!``#\_________Y:;`P```````@```/L!``#\__________N;
+M`P```````@```/L!``#\_________SF<`P```````@```/L!``#\________
+M_]*<`P```````@```"\"``#\__________6=`P```````@```"X"``#\____
+M_____Z&>`P```````@```/L!``#\_________QJ?`P```````@```/L!``#\
+M_________WB?`P```````@```","``#\_________RBK`P```````@```","
+M``#\_________^FO`P```````@```","``#\_________SJR`P```````@``
+M`","``#\_________]G"`P```````@```","``#\_________TG$`P``````
+M`@```","``#\_________P3%`P```````@```","``#\_________VC(`P``
+M`````@```","``#\_________QC-`P```````@```","``#\_________X#-
+M`P```````@```.(!``#\_________^S-`P```````@````\"``#\________
+M_Y+0`P```````@```","``#\_________ZC4`P```````@```#D"``#\____
+M_____]76`P```````@````\"``#\_________Y/7`P```````@```","``#\
+M_________U#:`P```````@````\"``#\_________PO;`P```````@```#D"
+M``#\_________Y7>`P```````@```"$"``#\_________T+?`P```````@``
+M`","``#\_________PC@`P```````@```","``#\_________P7C`P``````
+M`@```","``#\_________P3D`P```````@```","``#\_________X;G`P``
+M`````@```","``#\_________]'H`P```````@```-D!``#\_________\'I
+M`P```````@```&`"``#\_________X/J`P```````@```","``#\________
+M_PWK`P```````@```"L"``#\_________P;L`P```````@```","``#\____
+M_____RWM`P```````@```","``#\_________]SO`P```````@```","``#\
+M_________[OQ`P```````@```","``#\_________T/W`P```````@```","
+M``#\_________T#Z`P```````@```","``#\_________U+Z`P```````@``
+M`#D"``#\_________^SZ`P```````@```&`"``#\_________ZC\`P``````
+M`@```","``#\_________^']`P```````@```#D"``#\_________\?^`P``
+M`````@```#D"``#\_________P[_`P```````@```#D"``#\_________V0`
+M!````````@```","``#\_________X`!!````````@```","``#\________
+M__8#!````````@```/\!``#\_________SD&!```````"P````$```#P"00`
+M`````'H&!````````@```!T"``#\_________\(&!```````"P````$```!@
+M!`0``````,T&!```````"P````$```#P"00``````'8(!````````@````D"
+M``#\_________V()!````````@```!T"``#\_________[0)!```````"P``
+M``$"`````````````,$)!````````@```%<"``#\_________SP*!```````
+M`@```#$"``#\_________V\,!```````"P````$"`````````````'P,!```
+M`````@```%<"``#\_________Y`,!````````@````$"``#\_________T@-
+M!````````@```%H"``#\_________W,-!````````@```&`"``#\________
+M_Q8.!````````@```#D"``#\_________S@.!````````@```-T!``#\____
+M_____W`.!````````@```#D"``#\_________X4#!````````@```&`"``#\
+M_________]@#!````````@```&`"``#\_________SX$!````````@```"<"
+M``#\_________X<'!````````@```#D"``#\_________]8)!````````@``
+M``$"``#\_________UT*!````````@```%H"``#\_________\4*!```````
+M`@```#D"``#\_________VL.!````````@```#4"``#\_________](.!```
+M`````@```/@!``#\_________R81!````````@````,"``#\_________U<1
+M!````````@````,"``#\_________V@1!````````@````,"``#\________
+M__41!````````@```.`!``#\__________02!````````@```.4!``#\____
+M_____^X4!````````@```/L!``#\_________Q<5!````````@```.L!``#\
+M_________Z\5!````````@```!L"``#\_________UX8!````````@```/D!
+M``#\_________VL8!````````@```/0!``#\_________X@8!````````@``
+M`.\!``#\_________[T8!````````@```.\!``#\_________]08!```````
+M`@```/<!``#\_________W`9!````````@```!L"``#\_________Z$9!```
+M`````@````D"``#\_________[\9!````````@````D"``#\_________]$9
+M!````````@````D"``#\_________^$9!````````@```!L"``#\________
+M_^D9!````````@```!L"``#\_________T(:!```````"P````,````@&```
+M`````+8:!````````@```!D"``#\_________P4;!````````@```/T!``#\
+M_________UL;!````````@```.(!``#\__________`;!````````@```!L"
+M``#\_________\0<!````````@```#L"``#\__________8<!````````@``
+M`.L!``#\_________P8=!````````@```!D"``#\_________R<=!```````
+M`@```!@"``#\__________<>!````````@```.\!``#\_________QX?!```
+M`````@```.\!``#\_________RX?!````````@```/D!``#\_________[H?
+M!````````@```.\!``#\_________]0?!````````@```/D!``#\________
+M__4?!````````@```/0!``#\_________Q$@!````````@```/0!``#\____
+M_____PLC!````````@```&4"``#\_________V$C!````````@```&4"``#\
+M_________ZXC!````````@```&4"``#\_________VHD!````````@```/D!
+M``#\_________X0D!````````@```.\!``#\_________XPD!````````@``
+M`/D!``#\_________^XD!````````@```/@!``#\_________P8E!```````
+M`@```#L"``#\_________R<E!````````@```$`"``#\_________ZDE!```
+M`````@```/@!``#\_________\DE!````````@```/D!``#\_________Y(F
+M!````````@```&4"``#\_________THH!````````@```$$"``#\________
+M_V<H!````````@```#L"``#\_________W$H!````````@```!L"``#\____
+M_____ZDH!````````@```!D"``#\__________T2!````````@```/T!``#\
+M_________PD5!````````@```/T!``#\_________Q$<!````````@```#L"
+M``#\_________UPG!````````@```$$"``#\_________],H!````````@``
+M`-H!``#\__________4H!````````@```#@"``#\_________Q$I!```````
+M`@```#@"``#\_________[XJ!```````"P````$```!P*00``````-DJ!```
+M`````@```&`"``#\_________Q$K!````````@```"$"``#\_________U@K
+M!````````@```&("``#\_________V@K!````````@```$P"``#\________
+M_R```````````0````$```"SEP```````"@``````````0````$```"WEP``
+M`````#```````````0````$```#IEP```````#@``````````0````$````7
+MF````````$```````````0````$```!%F````````$@``````````0````$`
+M``!SF````````%```````````0````$```"@F````````%@``````````0``
+M``$```#.F````````&```````````0````$```#\F````````&@`````````
+M`0````$```#.F````````'```````````0````$```#\F````````'@`````
+M`````0````$````JF0```````(```````````0````$```!4F0```````(@`
+M`````````0````$```"-F0```````)```````````0````$````!F@``````
+M`)@``````````0````$````JF@```````*```````````0````$```"+F@``
+M`````*@``````````0````$````OFP```````+```````````0````$```!=
+MFP```````+@``````````0````$```"+FP```````,```````````0````$`
+M``!`G````````,@``````````0````$```!`G````````-```````````0``
+M``$```!`G````````-@``````````0````$```!`G````````.``````````
+M`0````$```!`G````````.@``````````0````$```"-EP```````/``````
+M`````0````$````0G````````/@``````````0````$```"0JP`````````!
+M`````````0````$```"+J`````````@!`````````0````$```"BJ```````
+M`!`!`````````0````$```#"J````````!@!`````````0````$```#UJ```
+M`````"`!`````````0````$````&J0```````"@!`````````0````$````/
+MJ0```````#`!`````````0````$````8J0```````#@!`````````0````$`
+M``#(J0```````$`!`````````0````$```#LJ0```````$@!`````````0``
+M``$```#UJ0```````%`!`````````0````$```#^J0```````%@!````````
+M`0````$```!@J@```````&`!`````````0````$````!JP```````&@!````
+M`````0````$```!>JP```````'`!`````````0````$```!QQ````````'@!
+M`````````0````$```#KP0```````(`!`````````0````$```#\P0``````
+M`(@!`````````0````$````-P@```````)`!`````````0````$````>P@``
+M`````)@!`````````0````$```!JP@```````*`!`````````0````$```")
+MP@```````*@!`````````0````$```"=P@```````+`!`````````0````$`
+M``#RP@```````+@!`````````0````$````.PP```````,`!`````````0``
+M``$````JPP```````,@!`````````0````$```!&PP```````-`!````````
+M`0````$```!NPP```````-@!`````````0````$```""PP```````.`!````
+M`````0````$```!QQ````````.@!`````````0````$```!QQ````````/`!
+M`````````0````$```!QQ````````/@!`````````0````$```"6PP``````
+M```"`````````0````$```#_PP````````@"`````````0````$```!QQ```
+M`````!`"`````````0````$```!QQ````````!@"`````````0````$```"^
+MPP```````"`"`````````0````$```!$Q````````"@"`````````0````$`
+M```]P@```````#`"`````````0````$```!1P@```````#@"`````````0``
+M``$```!QQ````````$`"`````````0````$```"QP@```````$@"````````
+M`0````$```#%P@```````%`"`````````0````$```#9P@```````&`"````
+M`````0````$````S[0```````&@"`````````0````$````S[0```````'`"
+M`````````0````$```!F[0```````'@"`````````0````$```!V[0``````
+M`(`"`````````0````$````S[0```````(@"`````````0````$````S[0``
+M`````)`"`````````0````$````Z[0```````)@"`````````0````$```"&
+M[0```````*`"`````````0````$```"2[0```````*@"`````````0````$`
+M``"B[0```````.`&`````````0````$```#`(`$``````.@&`````````0``
+M``$```#R(`$``````/`&`````````0````$```!\(0$``````/@&````````
+M`0````$```!\(0$````````'`````````0````$```!\(0$```````@'````
+M`````0````$```!\(0$``````!`'`````````0````$````D(0$``````!@'
+M`````````0````$```!0(0$``````"`'`````````0````$```!\(0$`````
+M`"@'`````````0````$```"1(0$``````#`'`````````0````$````S*P$`
+M`````#@'`````````0````$````^*P$``````$`'`````````0````$````^
+M*P$``````$@'`````````0````$````^*P$``````%`'`````````0````$`
+M```^*P$``````%@'`````````0````$````^*P$``````&`'`````````0``
+M``$````^*P$``````&@'`````````0````$````^*P$``````'`'````````
+M`0````$````^*P$``````'@'`````````0````$````^*P$``````(`'````
+M`````0````$````^*P$``````(@'`````````0````$````^*P$``````)`'
+M`````````0````$````^*P$``````)@'`````````0````$````^*P$`````
+M`*`'`````````0````$````^*P$``````*@'`````````0````$````^*P$`
+M`````+`'`````````0````$````^*P$``````+@'`````````0````$````^
+M*P$``````,`'`````````0````$````^*P$``````,@'`````````0````$`
+M```^*P$``````-`'`````````0````$````^*P$``````-@'`````````0``
+M``$````^*P$``````.`'`````````0````$````^*P$``````.@'````````
+M`0````$````^*P$``````/`'`````````0````$````^*P$``````/@'````
+M`````0````$````^*P$````````(`````````0````$````^*P$```````@(
+M`````````0````$````^*P$``````!`(`````````0````$````^*P$`````
+M`!@(`````````0````$````^*P$``````"`(`````````0````$````^*P$`
+M`````"@(`````````0````$````^*P$``````#`(`````````0````$````^
+M*P$``````#@(`````````0````$````^*P$``````$`(`````````0````$`
+M```^*P$``````$@(`````````0````$````^*P$``````%`(`````````0``
+M``$````(*P$``````%@(`````````0````$````^*P$``````&`(````````
+M`0````$````(*P$``````&@(`````````0````$````^*P$``````'`(````
+M`````0````$````^*P$``````'@(`````````0````$````^*P$``````(`(
+M`````````0````$````(*P$``````(@(`````````0````$````(*P$`````
+M`)`(`````````0````$````^*P$``````)@(`````````0````$````^*P$`
+M`````*`(`````````0````$````^*P$``````*@(`````````0````$````^
+M*P$``````+`(`````````0````$````^*P$``````+@(`````````0````$`
+M```^*P$``````,`(`````````0````$````^*P$``````,@(`````````0``
+M``$````^*P$``````-`(`````````0````$````^*P$``````-@(````````
+M`0````$````^*P$``````.`(`````````0````$````^*P$``````.@(````
+M`````0````$````^*P$``````/`(`````````0````$````^*P$``````/@(
+M`````````0````$````^*P$````````)`````````0````$````^*P$`````
+M``@)`````````0````$````^*P$``````!`)`````````0````$````^*P$`
+M`````!@)`````````0````$````(*P$``````"`)`````````0````$````^
+M*P$``````"@)`````````0````$````^*P$``````#`)`````````0````$`
+M```^*P$``````#@)`````````0````$````^*P$``````$`)`````````0``
+M``$````^*P$``````$@)`````````0````$````^*P$``````%`)````````
+M`0````$````^*P$``````%@)`````````0````$````^*P$``````&`)````
+M`````0````$````^*P$``````&@)`````````0````$````^*P$``````'`)
+M`````````0````$````^*P$``````'@)`````````0````$````^*P$`````
+M`(`)`````````0````$````^*P$``````(@)`````````0````$````^*P$`
+M`````)`)`````````0````$````(*P$``````)@)`````````0````$````(
+M*P$``````*`)`````````0````$````(*P$``````*@)`````````0````$`
+M```(*P$``````+`)`````````0````$````^*P$``````+@)`````````0``
+M``$````^*P$``````,`)`````````0````$````^*P$``````,@)````````
+M`0````$````^*P$``````-`)`````````0````$````^*P$``````-@)````
+M`````0````$````^*P$``````.`)`````````0````$````^*P$``````.@)
+M`````````0````$````^*P$``````/`)`````````0````$````^*P$`````
+M`/@)`````````0````$````^*P$````````*`````````0````$````^*P$`
+M``````@*`````````0````$````^*P$``````!`*`````````0````$````^
+M*P$``````!@*`````````0````$````^*P$``````"`*`````````0````$`
+M```^*P$``````"@*`````````0````$````^*P$``````#`*`````````0``
+M``$````^*P$``````#@*`````````0````$````^*P$``````$`*````````
+M`0````$````^*P$``````$@*`````````0````$````^*P$``````%`*````
+M`````0````$````^*P$``````%@*`````````0````$````^*P$``````&`*
+M`````````0````$````^*P$``````&@*`````````0````$````^*P$`````
+M`'`*`````````0````$````^*P$``````'@*`````````0````$````^*P$`
+M`````(`*`````````0````$````^*P$``````(@*`````````0````$````^
+M*P$``````)`*`````````0````$````^*P$``````)@*`````````0````$`
+M```^*P$``````*`*`````````0````$````^*P$``````*@*`````````0``
+M``$````^*P$``````+`*`````````0````$````^*P$``````+@*````````
+M`0````$````^*P$``````,`*`````````0````$````^*P$``````,@*````
+M`````0````$````^*P$``````-`*`````````0````$````^*P$``````-@*
+M`````````0````$````^*P$``````.`*`````````0````$````^*P$`````
+M`.@*`````````0````$````^*P$``````/`*`````````0````$````^*P$`
+M`````/@*`````````0````$````^*P$````````+`````````0````$````^
+M*P$```````@+`````````0````$````(*P$``````!`+`````````0````$`
+M```^*P$``````!@+`````````0````$````^*P$``````"`+`````````0``
+M``$````^*P$``````"@+`````````0````$````^*P$``````#`+````````
+M`0````$````^*P$``````#@+`````````0````$````^*P$``````$`+````
+M`````0````$````^*P$``````$@+`````````0````$````^*P$``````%`+
+M`````````0````$````(*P$``````%@+`````````0````$````^*P$`````
+M`&`+`````````0````$````(*P$``````&@+`````````0````$````^*P$`
+M`````'`+`````````0````$````^*P$``````'@+`````````0````$````^
+M*P$``````(`+`````````0````$````(*P$``````(@+`````````0````$`
+M```(*P$``````)`+`````````0````$````^*P$``````)@+`````````0``
+M``$````^*P$``````*`+`````````0````$````^*P$``````*@+````````
+M`0````$````(*P$``````+`+`````````0````$````^*P$``````+@+````
+M`````0````$````^*P$``````,`+`````````0````$````^*P$``````,@+
+M`````````0````$````^*P$``````-`+`````````0````$````^*P$`````
+M`-@+`````````0````$````^*P$``````.`+`````````0````$````^*P$`
+M`````.@+`````````0````$````^*P$``````/`+`````````0````$````^
+M*P$``````/@+`````````0````$````^*P$````````,`````````0````$`
+M```^*P$```````@,`````````0````$````^*P$``````!`,`````````0``
+M``$````^*P$``````!@,`````````0````$````^*P$``````"`,````````
+M`0````$````^*P$``````"@,`````````0````$````^*P$``````#`,````
+M`````0````$````^*P$``````#@,`````````0````$````^*P$``````$`,
+M`````````0````$````^*P$``````$@,`````````0````$````^*P$`````
+M`%`,`````````0````$````(*P$``````%@,`````````0````$````^*P$`
+M`````&`,`````````0````$````(*P$``````&@,`````````0````$````^
+M*P$``````'`,`````````0````$````^*P$``````'@,`````````0````$`
+M```^*P$``````(`,`````````0````$````(*P$``````(@,`````````0``
+M``$````(*P$``````)`,`````````0````$```"40`$``````)@,````````
+M`0````$```!$0`$``````*`,`````````0````$```!10`$``````*@,````
+M`````0````$```!V0`$``````+`,`````````0````$```"40`$``````+@,
+M`````````0````$```"*0`$``````,`,`````````0````$```"`0`$`````
+M`,@,`````````0````$```"40`$``````-`,`````````0````$```"40`$`
+M`````-@,`````````0````$```"40`$``````.`,`````````0````$```"4
+M0`$``````.@,`````````0````$```"`0`$``````/`,`````````0````$`
+M```):0$``````/@,`````````0````$````E:0$````````-`````````0``
+M``$```!!:0$```````@-`````````0````$```"7:0$``````!`-````````
+M`0````$````!:@$``````"`-`````````0````$````7K0$``````"@-````
+M`````0````$```#QK`$``````#`-`````````0````$```#WK`$``````#@-
+M`````````0````$````AK0$``````$`-`````````0````$```#GK`$`````
+M`$@-`````````0````$```#GK`$``````%`-`````````0````$```#GK`$`
+M`````%@-`````````0````$```#GK`$``````&`-`````````0````$```#G
+MK`$``````&@-`````````0````$```#GK`$``````'`-`````````0````$`
+M``#GK`$``````'@-`````````0````$```#GK`$``````(`-`````````0``
+M``$```#GK`$``````(@-`````````0````$```#GK`$``````)`-````````
+M`0````$```#GK`$``````)@-`````````0````$```#GK`$``````*`-````
+M`````0````$````GK0$``````*@-`````````0````$````AK0$``````+`-
+M`````````0````$````!K0$``````+@-`````````0````$````7K0$`````
+M`,`-`````````0````$````'K0$``````,@-`````````0````$````1K0$`
+M`````-`-`````````0````$````GK0$``````-@-`````````0````$```#A
+MK`$``````&`.`````````0````$```"O)@(``````&@.`````````0````$`
+M```:)P(``````'`.`````````0````$````V)P(``````'@.`````````0``
+M``$```!2)P(``````(`.`````````0````$```!N)P(``````(@.````````
+M`0````$```"*)P(``````)`.`````````0````$```"K)P(``````)@.````
+M`````0````$````F*`(``````*`.`````````0````$```!3*`(``````*@.
+M`````````0````$```#U*`(``````+`.`````````0````$```"W*`(`````
+M`+@.`````````0````$```#3*`(``````,`.`````````0````$````1*0(`
+M`````,@.`````````0````$````O*@(``````-`.`````````0````$```!?
+M*@(``````-@.`````````0````$```"%*@(``````.`.`````````0````$`
+M``"\*@(``````.@.`````````0````$```">*P(``````/`.`````````0``
+M``$```#B*@(``````/@.`````````0````$```#L*@(````````/````````
+M`0````$```!_*`(```````@/`````````0````$```";*`(``````!`/````
+M`````0````$```#-)P(``````!@/`````````0````$```#Z)P(``````"`/
+M`````````0````$```"W*`(``````"@/`````````0````$```#Z*@(`````
+M`#`/`````````0````$```#.*P(``````#@/`````````0````$```#P*P(`
+M`````$`/`````````0````$````,+`(``````$@/`````````0````$````M
+M+`(``````%`/`````````0````$````_+`(``````%@/`````````0````$`
+M``!B+`(``````&`/`````````0````$```"6+`(``````&@/`````````0``
+M``$````<*P(``````'`/`````````0````$````^*P(``````'@/````````
+M`0````$```!@*P(``````(`/`````````0````$```""*P(``````)`/````
+M`````0````$```"38@(``````)@/`````````0````$```#`6`(``````*`/
+M`````````0````$````260(``````*@/`````````0````$```"@60(`````
+M`+`/`````````0````$````L6@(``````+@/`````````0````$```!@6@(`
+M`````,`/`````````0````$```"K6@(``````,@/`````````0````$```!!
+M6P(``````-`/`````````0````$```!+6P(``````-@/`````````0````$`
+M``#^7@(``````.`/`````````0````$```#070(``````.@/`````````0``
+M``$```"J6`(``````/`/`````````0````$```"38@(``````/@/````````
+M`0````$```"38@(````````0`````````0````$```"38@(```````@0````
+M`````0````$```"38@(``````!`0`````````0````$```"38@(``````!@0
+M`````````0````$```#Z80(``````"`0`````````0````$```"38@(`````
+M`"@0`````````0````$```"38@(``````#`0`````````0````$```!56P(`
+M`````#@0`````````0````$```!P6P(``````$`0`````````0````$```"U
+M6@(``````$@0`````````0````$````W6P(``````%`0`````````0````$`
+M``#070(``````%@0`````````0````$```#N7P(``````&`0`````````0``
+M``$```!68@(``````&@0`````````0````$```!=8@(``````'`0````````
+M`0````$```".8@(``````'@0`````````0````$```"38@(``````(`0````
+M`````0````$````H80(``````(@0`````````0````$```!X80(``````)`0
+M`````````0````$```""80(``````)@0`````````0````$```#X7P(`````
+M`*`0`````````0````$````%8`(``````*@0`````````0````$````/8`(`
+M`````+`0`````````0````$````98`(``````+@0`````````0````$````R
+M<0(``````,`0`````````0````$````Z<0(``````,@0`````````0````$`
+M``!"<0(``````-`0`````````0````$```!*<0(``````-@0`````````0``
+M``$```!2<0(``````.`0`````````0````$```!:<0(``````.@0````````
+M`0````$```!B<0(``````/`0`````````0````$````J<0(``````/@0````
+M`````0````$```#PC`(````````1`````````0````$```!+B@(```````@1
+M`````````0````$```!<B@(``````!`1`````````0````$```!MB@(`````
+M`!@1`````````0````$```!^B@(``````"`1`````````0````$```#*B@(`
+M`````"@1`````````0````$```#IB@(``````#`1`````````0````$```#]
+MB@(``````#@1`````````0````$```!2BP(``````$`1`````````0````$`
+M``!NBP(``````$@1`````````0````$```"*BP(``````%`1`````````0``
+M``$```"FBP(``````%@1`````````0````$```#.BP(``````&`1````````
+M`0````$```#BBP(``````&@1`````````0````$```#VBP(``````'`1````
+M`````0````$```#PC`(``````'@1`````````0````$```#PC`(``````(`1
+M`````````0````$````/C`(``````(@1`````````0````$```![C`(`````
+M`)`1`````````0````$```#PC`(``````)@1`````````0````$```#PC`(`
+M`````*`1`````````0````$````WC`(``````*@1`````````0````$```#`
+MC`(``````+`1`````````0````$```"=B@(``````+@1`````````0````$`
+M``"QB@(``````,`1`````````0````$```#PC`(``````,@1`````````0``
+M``$````1BP(``````-`1`````````0````$````EBP(``````-@1````````
+M`0````$````YBP(``````.`1`````````0````$```"PO@(``````.@1````
+M`````0````$```"PO@(``````/`1`````````0````$```#IO@(``````/@1
+M`````````0````$```#\O@(````````2`````````0````$```"PO@(`````
+M``@2`````````0````$````=OP(``````!`2`````````0````$```"ZO@(`
+M`````!@2`````````0````$````/OP(``````"`2`````````0````$```#&
+MOP(``````"@2`````````0````$```#2OP(``````#`2`````````0````$`
+M``!QR0(``````#@2`````````0````$```#FR@(``````$`2`````````0``
+M``$```#FR@(``````$@2`````````0````$```#FR@(``````%`2````````
+M`0````$```#FR@(``````%@2`````````0````$```#FR@(``````&`2````
+M`````0````$```#FR@(``````&@2`````````0````$```#FR@(``````'`2
+M`````````0````$```#FR@(``````'@2`````````0````$```#FR@(`````
+M`(`2`````````0````$```#FR@(``````(@2`````````0````$```#FR@(`
+M`````)`2`````````0````$```#FR@(``````)@2`````````0````$```#F
+MR@(``````*`2`````````0````$```#FR@(``````*@2`````````0````$`
+M``#FR@(``````+`2`````````0````$```#FR@(``````+@2`````````0``
+M``$```#FR@(``````,`2`````````0````$```#FR@(``````,@2````````
+M`0````$```#FR@(``````-`2`````````0````$```#FR@(``````-@2````
+M`````0````$```#FR@(``````.`2`````````0````$```#FR@(``````.@2
+M`````````0````$```#FR@(``````/`2`````````0````$```#FR@(`````
+M`/@2`````````0````$```#FR@(````````3`````````0````$```#FR@(`
+M``````@3`````````0````$```#FR@(``````!`3`````````0````$```#F
+MR@(``````!@3`````````0````$```#FR@(``````"`3`````````0````$`
+M``#FR@(``````"@3`````````0````$```#FR@(``````#`3`````````0``
+M``$```"%R0(``````#@3`````````0````$```#@R0(``````$`3````````
+M`0````$````[R@(``````$@3`````````0````$```"6R@(``````%`3````
+M`````0````$```#[RP(``````%@3`````````0````$```#'T`(``````&`3
+M`````````0````$```#'T`(``````&@3`````````0````$```#'T`(`````
+M`'`3`````````0````$```#'T`(``````'@3`````````0````$```#'T`(`
+M`````(`3`````````0````$```#'T`(``````(@3`````````0````$```#'
+MT`(``````)`3`````````0````$```#'T`(``````)@3`````````0````$`
+M``#'T`(``````*`3`````````0````$```#'T`(``````*@3`````````0``
+M``$```#'T`(``````+`3`````````0````$```#'T`(``````+@3````````
+M`0````$```#'T`(``````,`3`````````0````$```#'T`(``````,@3````
+M`````0````$```#'T`(``````-`3`````````0````$````-S`(``````-@3
+M`````````0````$````-S`(``````.`3`````````0````$````-S`(`````
+M`.@3`````````0````$```#'T`(``````/`3`````````0````$```#'T`(`
+M`````/@3`````````0````$```#'T`(````````4`````````0````$```#'
+MT`(```````@4`````````0````$```#'T`(``````!`4`````````0````$`
+M``#'T`(``````!@4`````````0````$```#'T`(``````"`4`````````0``
+M``$```#'T`(``````"@4`````````0````$```#'T`(``````#`4````````
+M`0````$```#'T`(``````#@4`````````0````$```#'T`(``````$`4````
+M`````0````$```#'T`(``````$@4`````````0````$```#'T`(``````%`4
+M`````````0````$```!SS`(``````%@4`````````0````$```#+S`(`````
+M`&`4`````````0````$````CS0(``````&@4`````````0````$```!\S0(`
+M`````'`4`````````0````$```#'T`(``````'@4`````````0````$```#'
+MT`(``````(`4`````````0````$```#'T`(``````(@4`````````0````$`
+M``#'T`(``````)`4`````````0````$```#'T`(``````)@4`````````0``
+M``$```#'T`(``````*`4`````````0````$```#'T`(``````*@4````````
+M`0````$```#'T`(``````+`4`````````0````$```#'T`(``````+@4````
+M`````0````$```#'T`(``````,`4`````````0````$```#'T`(``````,@4
+M`````````0````$```#'T`(``````-`4`````````0````$```#4S0(`````
+M`-@4`````````0````$````OS@(``````.`4`````````0````$```"+S@(`
+M`````.@4`````````0````$```#CS@(``````/`4`````````0````$```#'
+MT`(``````/@4`````````0````$```#'T`(````````5`````````0````$`
+M``#'T`(```````@5`````````0````$```#'T`(``````!`5`````````0``
+M``$```#'T`(``````!@5`````````0````$```#'T`(``````"`5````````
+M`0````$```#'T`(``````"@5`````````0````$```#'T`(``````#`5````
+M`````0````$```#'T`(``````#@5`````````0````$```#'T`(``````$`5
+M`````````0````$```#'T`(``````$@5`````````0````$```#'T`(`````
+M`%`5`````````0````$````[SP(``````%@5`````````0````$```#'T`(`
+M`````&`5`````````0````$```#'T`(``````&@5`````````0````$```#'
+MT`(``````'`5`````````0````$```#'T`(``````'@5`````````0````$`
+M``#'T`(``````(`5`````````0````$```#'T`(``````(@5`````````0``
+M``$```#'T`(``````)`5`````````0````$```#'T`(``````)@5````````
+M`0````$```#'T`(``````*`5`````````0````$```#'T`(``````*@5````
+M`````0````$```#'T`(``````+`5`````````0````$```#'T`(``````+@5
+M`````````0````$```#'T`(``````,`5`````````0````$```#'T`(`````
+M`,@5`````````0````$```#'T`(``````-`5`````````0````$```!TSP(`
+M`````-@5`````````0````$```"NSP(``````.`5`````````0````$```#H
+MSP(``````.@5`````````0````$````BT`(``````/`5`````````0````$`
+M``!9T`(``````/@5`````````0````$```"0T`(``````#`6`````````0``
+M``$```!`%P,``````#@6`````````0````$```#?%P,``````$`6````````
+M`0````$```!Z%P,``````$@6`````````0````$```!>%P,``````%`6````
+M`````0````$```#?%P,``````%@6`````````0````$```#?%P,``````&`6
+M`````````0````$```#?%P,``````&@6`````````0````$```#?%P,`````
+M`'`6`````````0````$```!`%P,``````'@6`````````0````$```"M&`,`
+M`````(`6`````````0````$```!`%P,``````(@6`````````0````$```!`
+M%P,``````)`6`````````0````$```#V%@,``````)@6`````````0````$`
+M``"A&`,``````*`6`````````0````$```!O&`,``````*@6`````````0``
+M``$````X&`,``````+`6`````````0````$```"3.@,``````+@6````````
+M`0````$```"C.@,``````,`6`````````0````$```"K.@,``````,@6````
+M`````0````$```"S.@,``````-`6`````````0````$```"[.@,``````-@6
+M`````````0````$```##.@,``````.`6`````````0````$```#+.@,`````
+M`.@6`````````0````$```";.@,``````/`6`````````0````$```!+/P,`
+M`````/@6`````````0````$````C00,````````7`````````0````$```"$
+M0`,```````@7`````````0````$```#Z0`,``````!`7`````````0````$`
+M``#10`,``````!@7`````````0````$```#Z0`,``````"`7`````````0``
+M``$```!+/P,``````"@7`````````0````$```!./P,``````#`7````````
+M`0````$```!#GP,``````#@7`````````0````$```#5GP,``````$`7````
+M`````0````$```"RH`,``````$@7`````````0````$```#>H`,``````%`7
+M`````````0````$```"2H0,``````%@7`````````0````$```!UH@,`````
+M`&`7`````````0````$```".H@,``````&@7`````````0````$```":H@,`
+M`````'`7`````````0````$```"3GP,``````'@7`````````0````$````8
+MHP,``````(`7`````````0````$```#5HP,``````(@7`````````0````$`
+M``!#GP,``````)`7`````````0````$```#FI`,``````)@7`````````0``
+M``$```#NHP,``````*`7`````````0````$```"0I`,``````*@7````````
+M`0````$```"6LP,``````+`7`````````0````$````'MP,``````+@7````
+M`````0````$```#0M@,``````,`7`````````0````$```"[M@,``````,@7
+M`````````0````$```"FM@,``````-`7`````````0````$```"'M@,`````
+M`-@7`````````0````$```"6LP,``````.`7`````````0````$```!RM@,`
+M`````.@7`````````0````$```#WLP,``````/`7`````````0````$```"5
+M]0,``````/@7`````````0````$```"#]0,````````8`````````0````$`
+M``!G]0,```````@8`````````0````$```!&]0,``````!`8`````````0``
+M``$````$]0,``````!@8`````````0````$```#']`,``````"`8````````
+M`0````$````H&P0``````"@8`````````0````$```!A&@0``````#`8````
+M`````0````$````H&P0``````#@8`````````0````$```!&&@0``````$`8
+M`````````0````$```!&&@0``````$@8`````````0````$```!&&@0`````
+M`(```````````0````8```"\`````````)@``````````0````$```"@T0``
+M`````*```````````0````$````0Y@```````*@``````````0````$```#P
+MT0```````+```````````0````$````@\@```````+@``````````0````$`
+M```@_P```````,```````````0````$```#PY0```````,@``````````0``
+M``$```"0T0```````-```````````0````$````@T@```````-@`````````
+M`0````$`````Y0```````.```````````0````$`````T@```````.@`````
+M`````0````$```"@`0$``````/```````````0````$```#PT@```````/@`
+M`````````0````$```"@]@`````````!`````````0```+8`````````````
+M``@!`````````0````$```"PXP```````!`!`````````0````$````0T@``
+M`````!@!`````````0````$```"@^````````"`!`````````0````$```#0
+MX````````"@!`````````0````$```#0V@```````#`!`````````0````$`
+M``!PV@```````#@!`````````0````$```!0TP```````$`!`````````0``
+M``$````@[0```````$@!`````````0````$```!PTP```````%`!````````
+M`0````$```"PV@```````%@!`````````0````$```"0V@```````&`!````
+M`````0````$`````V@```````&@!`````````0````$````PU0```````'`!
+M`````````0````$```!0U````````'@!`````````0```#8`````````````
+M`(@!`````````0````$`````TP```````)`!`````````0````$````0TP``
+M`````)@!`````````0````$````@TP```````*`!`````````0````$````P
+MTP```````*@!`````````0````$```!`TP```````+`!`````````0```(<`
+M`````````````"`"`````````0````8```!/`@```````#@"`````````0``
+M``$```#@F@(``````$`"`````````0````$````PMP(``````$@"````````
+M`0````$````PFP(``````%`"`````````0````$`````T0(``````%@"````
+M`````0````$```!0[0(``````&`"`````````0````$````0MP(``````&@"
+M`````````0````$```#0F@(``````'`"`````````0````$```"`G`(`````
+M`'@"`````````0````$````@M@(``````(`"`````````0````$```!`FP(`
+M`````(@"`````````0````$```#@[P(``````)`"`````````0````$```#P
+MG`(``````)@"`````````0````$```"`U0(``````*`"`````````0```,D`
+M`````````````*@"`````````0````$````0LP(``````+`"`````````0``
+M``$```!0FP(``````+@"`````````0````$```!PY@(``````,`"````````
+M`0````$`````K@(``````,@"`````````0````$```!PIP(``````-`"````
+M`````0````$````0IP(``````-@"`````````0````$```"`G@(``````.`"
+M`````````0````$```"`O@(``````.@"`````````0````$```"@G@(`````
+M`/`"`````````0````$```!0IP(``````/@"`````````0````$````PIP(`
+M```````#`````````0````$```"@I@(```````@#`````````0````$```!@
+MH`(``````!`#`````````0````$```"`GP(``````!@#`````````0```)0!
+M`````````````"@#`````````0````$`````G0(``````#`#`````````0``
+M``$````0Y`(``````#@#`````````0````$````0X`(``````$`#````````
+M`0````$```#PVP(``````$@#`````````0````$```#@UP(``````%`#````
+M`````0```,\``````````````,`#`````````0````$```"`%@,``````,@#
+M`````````0````$```"@,P,``````-`#`````````0````$```"0%0,`````
+M`.@#`````````0````$```!P"@,``````/`#`````````0````$````@%0,`
+M`````/@#`````````0````$```!`"P,``````"@$`````````0````$```"0
+M1@,``````#@$`````````0````$```#`@@,``````%`$`````````0````$`
+M``#P1@,``````&`$`````````0````$```!0@0,``````'@$`````````0``
+M``$````01P,``````(@$`````````0````$`````EP,``````*`$````````
+M`0````$```!P1P,``````+`$`````````0````$`````D`,``````,@$````
+M`````0````$```"01P,``````-@$`````````0````$```!0@`,``````/`$
+M`````````0````$```!P2`,````````%`````````0````$````0>@,`````
+M`!@%`````````0````$```#02`,``````"@%`````````0````$````0\0,`
+M`````$`%`````````0````$```#02P,``````$@%`````````0````$`````
+MB0,``````%`%`````````0````$`````:@,``````&@%`````````0````$`
+M``"0X`,``````'`%`````````0````$```"@AP,``````'@%`````````0``
+M``$```#`:`,``````)`%`````````0````$`````4`,``````*`%````````
+M`0````$````0=@,``````+@%`````````0````$````@4`,``````,@%````
+M`````0````$````PW0,``````.`%`````````0````$````@4P,``````.@%
+M`````````0````$```"`AP,``````/`%`````````0````$```"`:`,`````
+M``@&`````````0````$```"04P,``````!`&`````````0````$```!@AP,`
+M`````!@&`````````0````$```!`:`,``````#`&`````````0````$`````
+M5`,``````#@&`````````0````$````0AP,``````$`&`````````0````$`
+M````:`,``````%@&`````````0````$```#`5`,``````&`&`````````0``
+M``$```"`A@,``````&@&`````````0````$```#`9P,``````(`&````````
+M`0````$````P50,``````(@&`````````0````$```!@A@,``````)`&````
+M`````0````$```"`9P,``````*@&`````````0````$````05@,``````+@&
+M`````````0````$`````9P,``````-`&`````````0````$```"`5@,`````
+M`.`&`````````0````$```#`9@,``````/@&`````````0````$```"@5@,`
+M``````@'`````````0````$```!0YP,``````"`'`````````0````$```#`
+M5@,``````#`'`````````0````$```"PZP,``````$@'`````````0````$`
+M``#@5@,``````%@'`````````0````$```"0C@,``````'`'`````````0``
+M``$```"@5P,``````(`'`````````0````$```!PC@,``````)@'````````
+M`0````$```"04`,``````*@'`````````0````$```"PW`,``````,`'````
+M`````0````$`````40,``````-`'`````````0````$```!@W`,``````.@'
+M`````````0````$```!@6`,``````/@'`````````0````$```"`9@,`````
+M`!`(`````````0````$```#`6`,``````"`(`````````0````$````PX@,`
+M`````#@(`````````0````$```!P60,``````$`(`````````0````$```#@
+MA0,``````$@(`````````0````$```!`9@,``````&`(`````````0````$`
+M``#@3`,``````&@(`````````0````$```#`B`,``````'`(`````````0``
+M``$```#`:0,``````(@(`````````0````$````020,``````)@(````````
+M`0````$````P[P,``````+`(`````````0````$```"@50,``````,`(````
+M`````0````$```!`9P,``````-@(`````````0````$```!P40,``````.@(
+M`````````0````$```#@VP,````````)`````````0````$```#040,`````
+M`!`)`````````0````$```!@VP,``````"@)`````````0````$````P4@,`
+M`````#@)`````````0````$````0VP,``````%`)`````````0````$```!0
+M3@,``````%@)`````````0````$```!`B`,``````&`)`````````0````$`
+M``!`:0,``````'@)`````````0````$```"04@,``````(@)`````````0``
+M``$```#PS0,``````*`)`````````0````$````@6@,``````*@)````````
+M`0````$```"PA0,``````+`)`````````0````$`````9@,``````,@)````
+M`````0````$`````2@,``````-@)`````````0````$```#`>`,``````/`)
+M`````````0````$`````2P,``````/@)`````````0````$```!`B0,`````
+M```*`````````0````$```!`:@,``````!@*`````````0````$```!020,`
+M`````"@*`````````0````$```!`[`,``````$`*`````````0````$````P
+M1P,``````%`*`````````0````$```!PE0,``````&@*`````````0````$`
+M``!01P,``````'@*`````````0````$```"@@`,``````)`*`````````0``
+M``$```"020,``````*`*`````````0````$```!@QP,``````+@*````````
+M`0````$```"030,``````,`*`````````0````$```"`B`,``````,@*````
+M`````0````$```"`:0,``````.`*`````````0````$````@3P,``````.@*
+M`````````0````$`````B`,``````/`*`````````0````$`````:0,`````
+M``@+`````````0````$```!P2@,``````!@+`````````0````$`````>`,`
+M`````#`+`````````0````$````06P,``````$`+`````````0````$```"P
+MC@,``````%@+`````````0````$```"@2`,``````&@+`````````0````$`
+M``!P>0,``````(`+`````````0````$```"P1P,``````)`+`````````0``
+M``$```"P?P,``````*@+`````````0````$```#01P,``````+@+````````
+M`0````$```#`?@,``````-`+`````````0````$```#P1P,``````.`+````
+M`````0````$```#0?0,``````/@+`````````0````$````02`,```````@,
+M`````````0````$```#@?`,``````"`,`````````0````$````P2`,`````
+M`#`,`````````0````$```#@>P,``````$@,`````````0````$```!02`,`
+M`````%@,`````````0````$`````>P,``````'`,`````````0````$```"P
+M1@,``````(`,`````````0````$```!PD`,``````)@,`````````0````$`
+M``#01@,``````*`,`````````0````$```"`B0,``````*@,`````````0``
+M``$```"@@0,``````,`,`````````0````$```"`6@,``````-`,````````
+M`0````$```!`=0,``````.@,`````````0````$```"P6@,``````/@,````
+M`````0````$```#P<@,``````!`-`````````0````$```"@3`,``````"`-
+M`````````0````$```#`=@,``````#@-`````````0````$```"`3`,`````
+M`$@-`````````0````$```"`=P,``````&`-`````````0````$`````7`,`
+M`````&@-`````````0````$```"0A0,``````'`-`````````0````$```#`
+M90,``````(@-`````````0````$```#`7`,``````)`-`````````0````$`
+M``!PA0,``````)@-`````````0````$```"`90,``````"```````````0``
+M``$``````````````#@``````````0````$```!``````````%``````````
+M`0````$```"``````````&@``````````0````$```#0`````````(``````
+M`````0````$````@`0```````+```````````0````$````P`0```````,@`
+M`````````0````$```!@`0```````.```````````0````$```"P`0``````
+M`/@``````````0````$```#``0```````!`!`````````0````$````@`@``
+M`````"@!`````````0````$````P`@```````$`!`````````0````$```!@
+M`@```````%@!`````````0````$```"0`@```````'`!`````````0````$`
+M``#0`@```````(@!`````````0````$``````P```````*`!`````````0``
+M``$```#@!````````,`!`````````0````$```!P!0```````.`!````````
+M`0````$```"P!0```````/@!`````````0````$```#@!0```````!`"````
+M`````0````$````0!@```````$`"`````````0````$````P!@```````%@"
+M`````````0````$```"`!@```````'`"`````````0````$```#@!@``````
+M`(@"`````````0````$```!`!P```````*`"`````````0````$```#`!P``
+M`````,@"`````````0````$````0"0```````.@"`````````0````$```!0
+M"0```````"@#`````````0````$```#`"P```````&@#`````````0````$`
+M```0#0```````(`#`````````0````$````0#@```````)@#`````````0``
+M``$```!@#@```````+`#`````````0````$```#P#@```````,@#````````
+M`0````$```!P#P```````.`#`````````0````$```#P#P```````/@#````
+M`````0````$```!`$````````!`$`````````0````$```!0$````````#@$
+M`````````0````$```!P$P```````'@$`````````0````$```!P%0``````
+M`+@$`````````0````$`````'@```````.`$`````````0````$```!P'@``
+M`````"`%`````````0````$```!0(````````$@%`````````0````$```#`
+M(0```````(@%`````````0````$````0)@```````+`%`````````0````$`
+M``!P)P```````-@%`````````0````$````@*@```````!@&`````````0``
+M``$```!`*P```````$`&`````````0````$```#`,````````(`&````````
+M`0````$```"`-0```````*@&`````````0````$```!P-@```````.@&````
+M`````0````$```"0.P```````!`'`````````0````$```!0/````````$@'
+M`````````0````$````@/0```````(`'`````````0````$```!P/P``````
+M`*`'`````````0````$```!`0````````,`'`````````0````$```"`0P``
+M`````.`'`````````0````$```"P0P```````"`(`````````0````$`````
+M10```````&`(`````````0````$```#@1P```````*`(`````````0````$`
+M``!@4````````/@(`````````0````$`````4P```````"@)`````````0``
+M``$````@4P```````$@)`````````0````$```!05````````&`)````````
+M`0````$```!@5````````'@)`````````0````$`````50```````)`)````
+M`````0````$````P50```````*@)`````````0````$```!@50```````,`)
+M`````````0````$```"050```````-@)`````````0````$```#`50``````
+M`/`)`````````0````$```#P50```````!`*`````````0````$`````5P``
+M`````#`*`````````0````$````P6````````%`*`````````0````$```!@
+M6````````'`*`````````0````$```"P6````````)`*`````````0````$`
+M``#@6````````+`*`````````0````$````@60```````-`*`````````0``
+M``$```!@60```````/@*`````````0````$```#P6@```````!@+````````
+M`0````$```!06P```````$`+`````````0````$```!07````````&@+````
+M`````0````$```!P70```````(@+`````````0````$```"070```````+`+
+M`````````0````$```"07@```````-@+`````````0````$`````7P``````
+M`/@+`````````0````$````@7P```````!@,`````````0````$```!`7P``
+M`````$`,`````````0````$````08````````&@,`````````0````$```#@
+M80```````(@,`````````0````$```!P8@```````,@,`````````0````$`
+M``"09````````/`,`````````0````$`````9@```````#`-`````````0``
+M``$```!@:````````%`-`````````0````$```"@:````````'`-````````
+M`0````$```#0:````````)`-`````````0````$`````:0```````-`-````
+M`````0````$```!0:0```````.@-`````````0````$```#0:0`````````.
+M`````````0````$```!`:@```````!@.`````````0````$```"@:@``````
+M`#`.`````````0````$```#0:@```````%@.`````````0````$```!P:P``
+M`````(`.`````````0````$```!@;````````*@.`````````0````$```!0
+M;0```````-`.`````````0````$````0;@```````/@.`````````0````$`
+M```P;P```````"@/`````````0````$```"0;P```````$@/`````````0``
+M``$````@<````````(`/`````````0````$```!P<@```````,`/````````
+M`0````$```!@<P`````````0`````````0````$```!0=````````#@0````
+M`````0````$```"@=@```````'@0`````````0````$```"0>````````+@0
+M`````````0````$`````?````````/@0`````````0````$```#@@@``````
+M`#@1`````````0````$```#@@P```````'@1`````````0````$```!`BP``
+M`````*`1`````````0````$```!0DP```````,@1`````````0````$```!`
+MEP```````/`1`````````0````$```!@G````````!@2`````````0````$`
+M``!0G0```````%`2`````````0````$```"@H````````'`2`````````0``
+M``$```#`H````````)`2`````````0````$```#@H````````+`2````````
+M`0````$`````H0```````-@2`````````0````$```"PH0````````@3````
+M`````0````$```"PHP```````#`3`````````0````$```"PI0```````(`3
+M`````````0````$```"@JP```````)@3`````````0````$```#0JP``````
+M`+`3`````````0````$`````K````````-@3`````````0````$```"`K```
+M`````/@3`````````0````$```#0K````````!@4`````````0````$```#P
+MK````````#`4`````````0````$````PK0```````%@4`````````0````$`
+M``#0K0```````'@4`````````0````$`````K@```````)@4`````````0``
+M``$```!`K@```````,`4`````````0````$```#0K@```````.@4````````
+M`0````$````@KP```````!`5`````````0````$```"@KP```````#@5````
+M`````0````$```!PL````````'@5`````````0````$```"`L@```````)@5
+M`````````0````$```#@L@```````+@5`````````0````$```!`LP``````
+M`/`5`````````0````$```#PLP```````!`6`````````0````$```!0M```
+M`````#`6`````````0````$```"0M````````%`6`````````0````$```#0
+MM````````)`6`````````0````$```"PMP```````+`6`````````0````$`
+M```0N````````-`6`````````0````$```!@N`````````@7`````````0``
+M``$```#`N````````"`7`````````0````$```#@N````````#@7````````
+M`0````$`````N0```````%@7`````````0````$```!0NP```````'`7````
+M`````0````$```!PNP```````(@7`````````0````$```"0NP```````,@7
+M`````````0````$```"`O````````.`7`````````0````$```#`O0``````
+M`/@7`````````0````$```#@O0```````!`8`````````0````$`````O@``
+M`````"@8`````````0````$````PO@```````$`8`````````0````$```!@
+MO@```````&@8`````````0````$```!0OP```````(`8`````````0````$`
+M``"0OP```````*@8`````````0````$````PP````````,`8`````````0``
+M``$```"0P````````-@8`````````0````$```"PP````````/@8````````
+M`0````$```"0Q````````!@9`````````0````$```#PQ0```````%`9````
+M`````0````$```#@Q@```````&@9`````````0````$````PQP```````(`9
+M`````````0````$```!0QP```````*@9`````````0````$```#`QP``````
+M`-`9`````````0````$```#0R@```````/@9`````````0````$```"`RP``
+M`````"`:`````````0````$`````S````````&`:`````````0````$```#0
+MS````````(`:`````````0````$```!0S0```````*`:`````````0````$`
+M```0S@```````.`:`````````0````$```"0T0```````/@:`````````0``
+M``$```"@T0```````!`;`````````0````$```#PT0```````"@;````````
+M`0````$`````T@```````$`;`````````0````$````0T@```````%@;````
+M`````0````$````@T@```````'`;`````````0````$````PT@```````(@;
+M`````````0````$```!`T@```````*`;`````````0````$```!@T@``````
+M`,@;`````````0````$```#PT@```````.`;`````````0````$`````TP``
+M`````/@;`````````0````$````0TP```````!`<`````````0````$````@
+MTP```````"@<`````````0````$````PTP```````$`<`````````0````$`
+M``!`TP```````%@<`````````0````$```!0TP```````'`<`````````0``
+M``$```!PTP```````(@<`````````0````$```#0TP```````*`<````````
+M`0````$````PU````````,`<`````````0````$```!0U````````.@<````
+M`````0````$````PU0```````!`=`````````0````$`````V@```````#`=
+M`````````0````$```!PV@```````%`=`````````0````$```"0V@``````
+M`'`=`````````0````$```"PV@```````)`=`````````0````$```#0V@``
+M`````+`=`````````0````$```#PV@```````-@=`````````0````$```!P
+MW``````````>`````````0````$```#PW0```````"@>`````````0````$`
+M``#`W@```````&`>`````````0````$```#0X````````)`>`````````0``
+M``$```"PXP```````+@>`````````0````$`````Y0```````.`>````````
+M`0````$```#PY0`````````?`````````0````$````0Y@```````$`?````
+M`````0````$````0Z0```````&@?`````````0````$```"0Z0```````)`?
+M`````````0````$````@[0```````+`?`````````0````$```#`[0``````
+M`-@?`````````0````$```"@[@`````````@`````````0````$```"`\0``
+M`````"`@`````````0````$````@\@```````&`@`````````0````$```"@
+M]@```````'@@`````````0````$```"@^````````*`@`````````0````$`
+M```@_P```````,@@`````````0````$```"@`0$``````"`A`````````0``
+M``$````P!`$``````#@A`````````0````$```!@!`$``````%`A````````
+M`0````$```!P!`$``````*@A`````````0````$```#@!@$``````,`A````
+M`````0````$````@!P$``````-@A`````````0````$```!@!P$``````/`A
+M`````````0````$```"P!P$```````@B`````````0````$`````"`$`````
+M`#@B`````````0````$````0"`$``````%`B`````````0````$```!`"`$`
+M`````&@B`````````0````$```"0"`$``````(`B`````````0````$```"@
+M"`$``````)@B`````````0````$`````"0$``````+`B`````````0````$`
+M```0"0$``````,@B`````````0````$```!`"0$``````.`B`````````0``
+M``$```!P"0$``````/@B`````````0````$```"P"0$``````!`C````````
+M`0````$```#P"0$``````"@C`````````0````$```#0"P$``````$`C````
+M`````0````$````0#`$``````&`C`````````0````$```"@#`$``````(`C
+M`````````0````$```#@#`$``````)@C`````````0````$````0#0$`````
+M`+`C`````````0````$```!`#0$``````.`C`````````0````$```!@#0$`
+M`````/@C`````````0````$```"P#0$``````!`D`````````0````$````0
+M#@$``````"@D`````````0````$```!P#@$``````$`D`````````0````$`
+M``#P#@$``````&@D`````````0````$```!`$`$``````(@D`````````0``
+M``$```"`$`$``````,@D`````````0````$```#P$@$```````@E````````
+M`0````$```!`%`$``````"`E`````````0````$```"0%`$``````#@E````
+M`````0````$````@%0$``````%`E`````````0````$```"@%0$``````&@E
+M`````````0````$````@%@$``````(`E`````````0````$```!`%@$`````
+M`*`E`````````0````$```"0%@$``````,`E`````````0````$```#`%@$`
+M`````.`E`````````0````$````@%P$``````"`F`````````0````$````P
+M&0$``````$`F`````````0````$````@&@$``````&@F`````````0````$`
+M``!`&P$``````)`F`````````0````$```!@'`$``````+@F`````````0``
+M``$```!P(@$``````-@F`````````0````$```"0(@$``````!@G````````
+M`0````$```#P+0$``````$@G`````````0````$`````,`$``````'`G````
+M`````0````$```!@,P$``````+`G`````````0````$```!0-P$``````-@G
+M`````````0````$````@00$``````!@H`````````0````$```!02@$`````
+M`$`H`````````0````$```!02P$``````(`H`````````0````$````@50$`
+M`````,`H`````````0````$```#@7@$``````.@H`````````0````$```"@
+M7P$``````"`I`````````0````$```!@8`$``````%@I`````````0````$`
+M``#`8P$``````'@I`````````0````$```"09`$``````+@I`````````0``
+M``$````P:`$``````.`I`````````0````$`````;`$``````"`J````````
+M`0````$`````<`$``````&`J`````````0````$```!`=@$``````(`J````
+M`````0````$```#0=@$``````*`J`````````0````$```#@=@$``````,`J
+M`````````0````$```#P>@$``````.@J`````````0````$`````?`$`````
+M`"@K`````````0````$```!0?0$``````&@K`````````0````$```#@B`$`
+M`````)@K`````````0````$```!@BP$``````/`K`````````0````$````P
+MD`$```````@L`````````0````$```"@D`$``````"`L`````````0````$`
+M``#PD`$``````#@L`````````0````$```!0D0$``````%`L`````````0``
+M``$```"PD0$``````&@L`````````0````$```"0D@$``````*`L````````
+M`0````$```#0DP$``````,`L`````````0````$````@E`$````````M````
+M`````0````$```"PE`$``````"@M`````````0````$````@E@$``````%`M
+M`````````0````$```"`EP$``````'@M`````````0````$```#0F`$`````
+M`)@M`````````0````$```!0F0$``````,`M`````````0````$```!@F@$`
+M```````N`````````0````$`````G`$``````$`N`````````0````$```!0
+MG0$``````&@N`````````0````$```!@G@$``````)`N`````````0````$`
+M``#PGP$``````+@N`````````0````$```#PH`$``````/@N`````````0``
+M``$```"0H0$``````#@O`````````0````$```#`H@$``````)`O````````
+M`0````$````PIP$``````*@O`````````0````$```"0IP$``````-@O````
+M`````0````$```"PIP$``````/`O`````````0````$```#0J`$``````!@P
+M`````````0````$```#PJ0$``````#`P`````````0````$```"`J@$`````
+M`$@P`````````0````$```"PJ@$``````&`P`````````0````$```#`J@$`
+M`````'@P`````````0````$````0JP$``````)`P`````````0````$```!`
+MJP$``````*@P`````````0````$```"`JP$``````,`P`````````0````$`
+M``"PJP$``````-@P`````````0````$```#PJP$``````/`P`````````0``
+M``$````@K`$```````@Q`````````0````$```!0K`$``````"`Q````````
+M`0````$```!PK`$``````#@Q`````````0````$```"@K`$``````%`Q````
+M`````0````$```#0K`$``````&@Q`````````0````$```!`K0$``````(`Q
+M`````````0````$```!`K@$``````)@Q`````````0````$````@KP$`````
+M`+`Q`````````0````$```!PKP$``````.`Q`````````0````$```!PL`$`
+M```````R`````````0````$```"@L`$``````"`R`````````0````$```#0
+ML`$``````$`R`````````0````$````@L0$``````&`R`````````0````$`
+M``!0L0$``````(`R`````````0````$```"`L0$``````,`R`````````0``
+M``$````0LP$``````.`R`````````0````$```!`LP$``````/@R````````
+M`0````$```!PLP$``````!`S`````````0````$```"@LP$``````#@S````
+M`````0````$```"0M`$``````%@S`````````0````$```#0M`$``````'@S
+M`````````0````$````0M0$``````*`S`````````0````$```!@N`$`````
+M`,@S`````````0````$```#`N0$``````.@S`````````0````$````@N@$`
+M`````!`T`````````0````$```#0N@$``````#@T`````````0````$```!@
+MNP$``````&`T`````````0````$```!0O`$``````(@T`````````0````$`
+M````O0$``````+`T`````````0````$```"`O@$``````-@T`````````0``
+M``$```#POP$````````U`````````0````$```"@P`$``````"@U````````
+M`0````$```"PP0$``````%`U`````````0````$```#@P@$``````'@U````
+M`````0````$`````Q`$``````*`U`````````0````$````0Q0$``````,@U
+M`````````0````$```!PQ@$```````@V`````````0````$````@R@$`````
+M`#`V`````````0````$````@RP$``````%@V`````````0````$````0S`$`
+M`````(`V`````````0````$```#@S`$``````*@V`````````0````$```"@
+MS0$``````-`V`````````0````$```"PS@$``````/@V`````````0````$`
+M```PT`$``````!@W`````````0````$```!0T`$``````$`W`````````0``
+M``$```"`T0$``````&@W`````````0````$```#PT0$``````(@W````````
+M`0````$````PT@$``````*@W`````````0````$```!0T@$``````,@W````
+M`````0````$```"`T@$``````/`W`````````0````$```"`TP$``````!@X
+M`````````0````$```!PU0$``````$`X`````````0````$`````U@$`````
+M`&@X`````````0````$```"0UP$``````*@X`````````0````$`````VP$`
+M`````-@X`````````0````$```#PW`$``````!@Y`````````0````$```"`
+MWP$``````$`Y`````````0````$```"PX`$``````&@Y`````````0````$`
+M``#PX0$``````)`Y`````````0````$```!`X@$``````,@Y`````````0``
+M``$```!PX@$``````.`Y`````````0````$```"0X@$``````/@Y````````
+M`0````$```"PX@$``````!`Z`````````0````$```#@X@$``````"@Z````
+M`````0````$````PXP$``````$`Z`````````0````$```"0XP$``````%@Z
+M`````````0````$````@Y0$``````(@Z`````````0````$```#PY0$`````
+M`+@Z`````````0````$```!@Y@$``````-@Z`````````0````$```"0Y@$`
+M`````/@Z`````````0````$````@YP$``````"@[`````````0````$```!P
+MZ`$``````$@[`````````0````$```"0Z0$``````&@[`````````0````$`
+M```0Z@$``````(@[`````````0````$```"0Z@$``````,@[`````````0``
+M``$```"P\P$``````/`[`````````0````$```!`]0$```````@\````````
+M`0````$```#@]0$``````"`\`````````0````$```#@]@$``````&@\````
+M`````0````$```"@^`$``````(`\`````````0````$````@^0$``````)@\
+M`````````0````$```"0^0$``````+`\`````````0````$`````^@$`````
+M`,@\`````````0````$```!P^@$``````.`\`````````0````$```"`^@$`
+M`````/@\`````````0````$```#`^@$``````!`]`````````0````$````@
+M^P$``````"@]`````````0````$```!`^P$``````$`]`````````0````$`
+M``!P^P$``````&`]`````````0````$````0_`$``````(@]`````````0``
+M``$````@_0$``````,@]`````````0````$`````_P$``````/@]````````
+M`0````$```!@_P$``````"`^`````````0````$```!0``(``````$@^````
+M`````0````$````@`0(``````&@^`````````0````$```!``@(``````)`^
+M`````````0````$```#P`@(``````+@^`````````0````$````@!`(`````
+M`.`^`````````0````$```#P!`(```````@_`````````0````$```#P!0(`
+M`````$@_`````````0````$```#@!@(``````(@_`````````0````$```#0
+M!P(``````,@_`````````0````$```!P"@(```````!``````````0````$`
+M``!0#0(``````"A``````````0````$`````#@(``````&A``````````0``
+M``$```!`$0(``````*A``````````0````$```"@&`(``````.A`````````
+M`0````$```"@&0(``````"!!`````````0````$```"0'0(``````&!!````
+M`````0````$```#`)0(``````(A!`````````0````$```!P)@(``````+!!
+M`````````0````$```#@+`(``````-A!`````````0````$````P+P(`````
+M`/A!`````````0````$```!0+P(``````"!"`````````0````$`````.0(`
+M`````$A"`````````0````$`````/0(``````'!"`````````0````$````P
+M0`(``````+!"`````````0````$```#P0@(``````/!"`````````0````$`
+M``#@10(``````#!#`````````0````$```"@2`(``````'!#`````````0``
+M``$```"03`(``````+!#`````````0````$```"`4`(``````/!#````````
+M`0````$```"@40(``````"!$`````````0````$```"P4P(``````$A$````
+M`````0````$```#P50(``````(A$`````````0````$```"@5@(``````+!$
+M`````````0````$````@8P(``````/!$`````````0````$```!0;`(`````
+M``A%`````````0````$```"`;`(``````"!%`````````0````$```"P;`(`
+M`````$A%`````````0````$````P;0(``````&A%`````````0````$```"`
+M;0(``````(A%`````````0````$```"@;0(``````*!%`````````0````$`
+M``#P;0(``````,A%`````````0````$```"0;@(``````/!%`````````0``
+M``$````@<`(``````!!&`````````0````$```!@<`(``````#!&````````
+M`0````$```"0<`(``````%!&`````````0````$```#0<`(``````'A&````
+M`````0````$```"P<0(``````*!&`````````0````$`````<@(``````,A&
+M`````````0````$```"`<@(``````/!&`````````0````$```!0<P(`````
+M`#!'`````````0````$```"0=0(``````%!'`````````0````$```#P=0(`
+M`````'!'`````````0````$```!0=@(``````*A'`````````0````$`````
+M=P(``````,A'`````````0````$```!@=P(``````.A'`````````0````$`
+M``"@=P(```````A(`````````0````$```#@=P(``````$A(`````````0``
+M``$```!0?0(``````&A(`````````0````$```"P?0(``````(A(````````
+M`0````$`````?@(``````,!(`````````0````$```!@?@(``````-A(````
+M`````0````$```"`?@(``````/!(`````````0````$```"@?@(``````!!)
+M`````````0````$```"0?P(``````"A)`````````0````$```"P?P(`````
+M`$!)`````````0````$```#@?P(``````&!)`````````0````$```!P@`(`
+M`````*!)`````````0````$```"@@0(``````,A)`````````0````$```"0
+M@@(```````!*`````````0````$```#`@P(``````$!*`````````0````$`
+M``!PA`(``````%A*`````````0````$```"PA0(``````'!*`````````0``
+M``$```#`A0(``````(A*`````````0````$```#0A0(``````*!*````````
+M`0````$```#PA0(``````+A*`````````0````$````0A@(``````-!*````
+M`````0````$```!`A@(``````.A*`````````0````$```!PA@(``````!!+
+M`````````0````$```"PAP(``````"A+`````````0````$```#PAP(`````
+M`%!+`````````0````$```"0B`(``````&A+`````````0````$```#PB`(`
+M`````(!+`````````0````$````0B0(``````*!+`````````0````$````0
+MC0(``````,!+`````````0````$```!PC@(``````/A+`````````0````$`
+M```@D`(``````!!,`````````0````$```!PD`(``````"A,`````````0``
+M``$```"0D`(``````%!,`````````0````$`````D0(``````'A,````````
+M`0````$````0E`(``````*!,`````````0````$```#`E`(``````,A,````
+M`````0````$```!`E0(```````A-`````````0````$````0E@(``````"A-
+M`````````0````$```"0E@(``````$A-`````````0````$```!0EP(`````
+M`(A-`````````0````$```#0F@(``````*!-`````````0````$```#@F@(`
+M`````+A-`````````0````$````PFP(``````-!-`````````0````$```!`
+MFP(``````.A-`````````0````$```!0FP(```````!.`````````0````$`
+M``!@FP(``````!A.`````````0````$```#@FP(``````#!.`````````0``
+M``$```"`G`(``````$A.`````````0````$```"0G`(``````&!.````````
+M`0````$```"@G`(``````'A.`````````0````$```#PG`(``````)!.````
+M`````0````$`````G0(``````*A.`````````0````$`````G@(``````,!.
+M`````````0````$```!`G@(``````.!.`````````0````$```"`G@(`````
+M`/A.`````````0````$```"@G@(``````!!/`````````0````$`````GP(`
+M`````"A/`````````0````$```!@GP(``````$A/`````````0````$```"`
+MGP(``````'!/`````````0````$```!@H`(``````+!/`````````0````$`
+M``"@I@(``````-!/`````````0````$````0IP(``````/!/`````````0``
+M``$````PIP(``````!!0`````````0````$```!0IP(``````#!0````````
+M`0````$```!PIP(``````%!0`````````0````$```"0IP(``````'A0````
+M`````0````$````@J0(``````*!0`````````0````$`````K@(``````,A0
+M`````````0````$```!`L@(``````/!0`````````0````$````0LP(`````
+M`!A1`````````0````$```"PM`(``````#A1`````````0````$```"0M0(`
+M`````&!1`````````0````$````@M@(``````(A1`````````0````$````0
+MMP(``````*A1`````````0````$````PMP(``````.A1`````````0````$`
+M```PN@(``````!!2`````````0````$```#@N@(``````#A2`````````0``
+M``$```"`O@(``````&!2`````````0````$`````P`(``````(A2````````
+M`0````$```!`P0(``````,A2`````````0````$````PQP(``````.A2````
+M`````0````$```#0QP(``````!A3`````````0````$`````T0(``````%A3
+M`````````0````$```"`U0(``````(!3`````````0````$```#@UP(`````
+M`+A3`````````0````$```#PVP(``````.A3`````````0````$````0X`(`
+M`````!!4`````````0````$````0Y`(``````#A4`````````0````$```!P
+MY@(``````&!4`````````0````$```!0[0(``````(A4`````````0````$`
+M``#@[P(``````.!4`````````0````$````@\P(``````/A4`````````0``
+M``$```!`\P(``````!!5`````````0````$```!0\P(``````"A5````````
+M`0````$```"`\P(``````$!5`````````0````$```"0\P(``````&A5````
+M`````0````$````0]`(``````)!5`````````0````$```#@]`(``````*A5
+M`````````0````$````0]0(``````-!5`````````0````$```!@]0(`````
+M`/!5`````````0````$```#@]0(```````A6`````````0````$````0]@(`
+M`````"!6`````````0````$```!0]@(``````$!6`````````0````$```"`
+M]@(``````%A6`````````0````$```"0]@(``````'!6`````````0````$`
+M``"@]@(``````(A6`````````0````$```#0]@(``````*!6`````````0``
+M``$````0]P(``````+A6`````````0````$```!P]P(``````.!6````````
+M`0````$`````^`(```````A7`````````0````$```!@^`(``````$!7````
+M`````0````$```!`^0(``````&A7`````````0````$````0^@(``````(A7
+M`````````0````$```"@^@(``````+!7`````````0````$`````^P(`````
+M`-A7`````````0````$```#@^P(```````A8`````````0````$```#@_`(`
+M`````"A8`````````0````$```!`_0(``````%!8`````````0````$```"@
+M_0(``````&A8`````````0````$```"P_0(``````(!8`````````0````$`
+M``#0_0(``````)A8`````````0````$```#P_0(``````-!8`````````0``
+M``$```!@``,``````!!9`````````0````$```#``0,``````$!9````````
+M`0````$```#``@,``````&A9`````````0````$```!@`P,``````)A9````
+M`````0````$`````!`,``````-A9`````````0````$```!@!0,``````!!:
+M`````````0````$````P!P,``````#A:`````````0````$```#P!P,`````
+M`&!:`````````0````$```!P"0,``````*!:`````````0````$```!P"@,`
+M`````+A:`````````0````$```"P"@,``````-!:`````````0````$```#0
+M"@,``````.A:`````````0````$`````"P,```````!;`````````0````$`
+M``!`"P,``````!A;`````````0````$```"`"P,``````#!;`````````0``
+M``$```#`"P,``````$A;`````````0````$````P#`,``````&!;````````
+M`0````$```#P#`,``````'A;`````````0````$`````#0,``````*!;````
+M`````0````$```!0#0,``````,!;`````````0````$```#0#0,``````.!;
+M`````````0````$```"0#@,```````!<`````````0````$```#P#@,`````
+M`"A<`````````0````$```"@#P,``````$!<`````````0````$```"P#P,`
+M`````&!<`````````0````$`````$`,``````(A<`````````0````$```!P
+M$`,``````*A<`````````0````$```#P$`,``````,!<`````````0````$`
+M```P$0,``````.!<`````````0````$```"`$0,```````A=`````````0``
+M``$```#@$0,``````#A=`````````0````$````@%0,``````&!=````````
+M`0````$```"0%0,``````(A=`````````0````$```"`%@,``````*A=````
+M`````0````$```#`%@,``````-!=`````````0````$```#`&`,``````/!=
+M`````````0````$````0&0,``````!A>`````````0````$```"@&@,`````
+M`$!>`````````0````$`````'0,``````&!>`````````0````$```!@'0,`
+M`````)!>`````````0````$````@*`,``````-!>`````````0````$````@
+M*@,``````/!>`````````0````$```!P*@,``````!A?`````````0````$`
+M``!P*P,``````$A?`````````0````$```#@+`,``````'A?`````````0``
+M``$```!P+@,``````)A?`````````0````$`````+P,``````,!?````````
+M`0````$```!P+P,``````/A?`````````0````$```#`,0,``````"!@````
+M`````0````$```!@,@,``````$A@`````````0````$```"@,P,``````'!@
+M`````````0````$```"@-`,``````+!@`````````0````$````@-@,`````
+M`,A@`````````0````$```"`-@,``````.!@`````````0````$```"@-@,`
+M`````/A@`````````0````$```#P-@,``````#AA`````````0````$```"P
+M-P,``````'AA`````````0````$```#`.`,``````*AA`````````0````$`
+M```@.0,``````.AA`````````0````$```"`.@,```````!B`````````0``
+M``$```#@.@,``````!AB`````````0````$```"`.P,``````#!B````````
+M`0````$```!@/`,``````$AB`````````0````$```!P/0,``````&!B````
+M`````0````$```#`/0,``````'AB`````````0````$```!`/@,``````+AB
+M`````````0````$```#00@,``````-!B`````````0````$```#@0@,`````
+M`.AB`````````0````$```!P0P,```````AC`````````0````$```#P0P,`
+M`````#!C`````````0````$````P1`,``````$AC`````````0````$````0
+M10,``````'!C`````````0````$```"@10,``````*!C`````````0````$`
+M```01@,``````+AC`````````0````$```"01@,``````-!C`````````0``
+M``$```"P1@,``````.AC`````````0````$```#01@,```````!D````````
+M`0````$```#P1@,``````!AD`````````0````$````01P,``````#!D````
+M`````0````$````P1P,``````$AD`````````0````$```!01P,``````&!D
+M`````````0````$```!P1P,``````'AD`````````0````$```"01P,`````
+M`)!D`````````0````$```"P1P,``````*AD`````````0````$```#01P,`
+M`````,!D`````````0````$```#P1P,``````-AD`````````0````$````0
+M2`,``````/!D`````````0````$````P2`,```````AE`````````0````$`
+M``!02`,``````"!E`````````0````$```!P2`,``````#AE`````````0``
+M``$```"@2`,``````%!E`````````0````$```#02`,``````'!E````````
+M`0````$````020,``````)!E`````````0````$```!020,``````+!E````
+M`````0````$```"020,``````-!E`````````0````$`````2@,``````/!E
+M`````````0````$```!P2@,``````!AF`````````0````$`````2P,`````
+M`$!F`````````0````$```#02P,``````&AF`````````0````$```"`3`,`
+M`````(!F`````````0````$```"@3`,``````)AF`````````0````$```#@
+M3`,``````,!F`````````0````$```"030,``````.AF`````````0````$`
+M``!03@,``````!!G`````````0````$````@3P,``````#AG`````````0``
+M``$`````4`,``````%!G`````````0````$````@4`,``````'!G````````
+M`0````$```"04`,``````)!G`````````0````$`````40,``````+!G````
+M`````0````$```!P40,``````-!G`````````0````$```#040,``````/!G
+M`````````0````$````P4@,``````!!H`````````0````$```"04@,`````
+M`#!H`````````0````$````@4P,``````%!H`````````0````$```"04P,`
+M`````'!H`````````0````$`````5`,``````)AH`````````0````$```#`
+M5`,``````+AH`````````0````$````P50,``````-AH`````````0````$`
+M``"@50,``````/AH`````````0````$````05@,``````!AI`````````0``
+M``$```"`5@,``````#!I`````````0````$```"@5@,``````$AI````````
+M`0````$```#`5@,``````&!I`````````0````$```#@5@,``````(!I````
+M`````0````$```"@5P,``````*!I`````````0````$```!@6`,``````,!I
+M`````````0````$```#`6`,``````.AI`````````0````$```!P60,`````
+M`!!J`````````0````$````@6@,``````#!J`````````0````$```"`6@,`
+M`````$AJ`````````0````$```"P6@,``````&AJ`````````0````$````0
+M6P,``````(AJ`````````0````$```#`6P,``````*!J`````````0````$`
+M````7`,``````,!J`````````0````$```#`7`,``````.!J`````````0``
+M``$```!@70,```````AK`````````0````$```!P7@,``````"!K````````
+M`0````$```#@7@,``````$!K`````````0````$```!`7P,``````%AK````
+M`````0````$```!07P,``````'AK`````````0````$```!08`,``````)!K
+M`````````0````$```!@8`,``````*AK`````````0````$```"P8`,`````
+M`,AK`````````0````$````@80,``````/!K`````````0````$```#P80,`
+M`````!AL`````````0````$```"@8@,``````$AL`````````0````$```#`
+M8P,``````'AL`````````0````$```#09`,``````)AL`````````0````$`
+M````90,``````+!L`````````0````$```"`90,``````,AL`````````0``
+M``$```#`90,``````.!L`````````0````$`````9@,``````/AL````````
+M`0````$```!`9@,``````!!M`````````0````$```"`9@,``````"AM````
+M`````0````$```#`9@,``````$!M`````````0````$`````9P,``````%AM
+M`````````0````$```!`9P,``````'!M`````````0````$```"`9P,`````
+M`(AM`````````0````$```#`9P,``````*!M`````````0````$`````:`,`
+M`````+AM`````````0````$```!`:`,``````-!M`````````0````$```"`
+M:`,``````.AM`````````0````$```#`:`,```````!N`````````0````$`
+M````:0,``````!AN`````````0````$```!`:0,``````#!N`````````0``
+M``$```"`:0,``````$AN`````````0````$```#`:0,``````&!N````````
+M`0````$`````:@,``````'AN`````````0````$```!`:@,``````)!N````
+M`````0````$```"`:@,``````*AN`````````0````$```"P:@,``````,!N
+M`````````0````$```#@:@,``````.!N`````````0````$```"0:P,`````
+M`/AN`````````0````$```#0:P,``````"!O`````````0````$```"@;`,`
+M`````$!O`````````0````$```#P;`,``````'!O`````````0````$`````
+M;@,``````)!O`````````0````$```!0;@,``````,!O`````````0````$`
+M``#P;P,```````!P`````````0````$```"`<0,``````#AP`````````0``
+M``$```!@<@,``````%AP`````````0````$```#P<@,``````(AP````````
+M`0````$````0=0,``````*!P`````````0````$```!`=0,``````.!P````
+M`````0````$````0=@,``````/AP`````````0````$```#`=@,``````"!Q
+M`````````0````$```"`=P,``````$AQ`````````0````$`````>`,`````
+M`'!Q`````````0````$```#`>`,``````)AQ`````````0````$```!P>0,`
+M`````+AQ`````````0````$````0>@,``````.!Q`````````0````$`````
+M>P,``````"!R`````````0````$```#@>P,``````&!R`````````0````$`
+M``#@?`,``````*!R`````````0````$```#0?0,``````.!R`````````0``
+M``$```#`?@,``````"!S`````````0````$```"P?P,``````%!S````````
+M`0````$```!0@`,``````'!S`````````0````$```"@@`,``````)AS````
+M`````0````$```!0@0,``````+AS`````````0````$```"@@0,``````.!S
+M`````````0````$```#`@@,``````/AS`````````0````$```#P@@,`````
+M`#!T`````````0````$```#`@P,``````%AT`````````0````$```!@A0,`
+M`````'!T`````````0````$```!PA0,``````)!T`````````0````$```"0
+MA0,``````+!T`````````0````$```"PA0,``````-!T`````````0````$`
+M``#@A0,```````!U`````````0````$```!@A@,``````"!U`````````0``
+M``$```"`A@,``````$!U`````````0````$````0AP,``````&!U````````
+M`0````$```!@AP,``````(!U`````````0````$```"`AP,``````*!U````
+M`````0````$```"@AP,``````,!U`````````0````$`````B`,``````.AU
+M`````````0````$```!`B`,``````!!V`````````0````$```"`B`,`````
+M`#AV`````````0````$```#`B`,``````&!V`````````0````$`````B0,`
+M`````(AV`````````0````$```!`B0,``````+!V`````````0````$```"`
+MB0,``````-AV`````````0````$```#PB0,``````!AW`````````0````$`
+M```PBP,``````$!W`````````0````$```!PC@,``````&!W`````````0``
+M``$```"0C@,``````(!W`````````0````$```"PC@,``````*AW````````
+M`0````$`````D`,``````-!W`````````0````$```!PD`,``````/AW````
+M`````0````$```!`D@,``````#AX`````````0````$```!PE0,``````&AX
+M`````````0````$`````EP,``````)AX`````````0````$```!0F`,`````
+M`,!X`````````0````$```#@F`,``````.!X`````````0````$````@F0,`
+M``````!Y`````````0````$```!@F0,``````"!Y`````````0````$```!`
+MG`,``````#AY`````````0````$```#0G0,``````%!Y`````````0````$`
+M````G@,``````'!Y`````````0````$````@GP,``````*!Y`````````0``
+M``$```"PIP,``````,AY`````````0````$```"`J@,```````!Z````````
+M`0````$```!@JP,``````"AZ`````````0````$```"@K@,``````%!Z````
+M`````0````$```"`KP,``````'!Z`````````0````$```#PKP,``````+!Z
+M`````````0````$```"@L0,``````-AZ`````````0````$````PLP,`````
+M`!A[`````````0````$```"`P@,``````$![`````````0````$```#PP@,`
+M`````&A[`````````0````$`````Q`,``````)![`````````0````$```!0
+MQ`,``````,![`````````0````$````0Q0,``````/![`````````0````$`
+M``!@QP,``````"!\`````````0````$```!PR@,``````$A\`````````0``
+M``$```"0S`,``````'A\`````````0````$````PS0,``````)A\````````
+M`0````$```"0S0,``````+A\`````````0````$```#PS0,``````-A\````
+M`````0````$`````T`,```````A]`````````0````$`````UP,``````#A]
+M`````````0````$````0VP,``````&!]`````````0````$```!@VP,`````
+M`(A]`````````0````$```#@VP,``````+!]`````````0````$```!@W`,`
+M`````-A]`````````0````$```"PW`,```````!^`````````0````$````P
+MW0,``````"A^`````````0````$```"PW0,``````%A^`````````0````$`
+M``!`W@,``````(!^`````````0````$```"@W@,``````*A^`````````0``
+M``$```"0WP,``````-!^`````````0````$```"0X`,``````/!^````````
+M`0````$````PX0,``````!A_`````````0````$`````X@,``````#A_````
+M`````0````$````PX@,``````'!_`````````0````$````0XP,``````+!_
+M`````````0````$```!@Y`,``````.!_`````````0````$````PY@,`````
+M`!B``````````0````$```!0YP,``````#B``````````0````$```"0YP,`
+M`````'"``````````0````$```#0Z`,``````(B``````````0````$```#@
+MZ`,``````+"``````````0````$````0Z@,``````-B``````````0````$`
+M``"0Z@,```````"!`````````0````$````@ZP,``````#"!`````````0``
+M``$```"PZP,``````%B!`````````0````$```!`[`,``````)B!````````
+M`0````$````P[P,``````-"!`````````0````$````0\0,```````B"````
+M`````0````$```#@\@,``````#B"`````````0````$```!0]@,``````&""
+M`````````0````$```!0]P,``````)""`````````0````$`````^`,`````
+M`+B"`````````0````$```!P^@,``````.""`````````0````$```"0_@,`
+M`````/B"`````````0````$```#0_@,``````!B#`````````0````$````@
+M_P,``````$"#`````````0````$```"```0``````("#`````````0````$`
+M``"0`00``````)B#`````````0````$```!P`@0``````+B#`````````0``
+M``$```#P`@0``````-"#`````````0````$```!@`P0``````.B#````````
+M`0````$```"``P0```````"$`````````0````$```"0`P0``````""$````
+M`````0````$```#@`P0``````$B$`````````0````$```!@!`0``````'B$
+M`````````0````$```"`!00``````*B$`````````0````$```"0"00`````
+M`,B$`````````0````$```#P"00``````/"$`````````0````$```#0"@0`
+M`````#"%`````````0````$```!`#@0``````&B%`````````0````$```"`
+M#@0``````("%`````````0````$```"@#@0``````+"%`````````0````$`
+M``"@#P0``````,B%`````````0````$```#@#P0``````."%`````````0``
+M``$```!0$`0``````!"&`````````0````$```!`$00``````#"&````````
+M`0````$```"@$00``````%B&`````````0````$```"`$@0``````'B&````
+M`````0````$````@$P0``````+B&`````````0````$```!`%00``````/"&
+M`````````0````$````@&00``````!B'`````````0````$```"0&00`````
+M`$"'`````````0````$````@&@0``````'"'`````````0````$```!P'`0`
+M`````)"'`````````0````$````0'00``````+B'`````````0````$```"`
+M'@0``````.B'`````````0````$```!`)@0``````"B(`````````0````$`
+M``#0*`0``````$"(`````````0````$````P*00``````%B(`````````0``
+M``$```!`*00``````'"(`````````0````$```!@*00``````(B(````````
+M`0````$```!P*00``````+"(`````````0````$```!@*@0``````-B(````
+M`````0````$```"@*@0``````/B(`````````0````$```#P*@0``````!B)
+M`````````0````$```!0*P0``````#")`````````0````$```!@*P0`````
+M`&")`````````0````$```!P*P0``````'B)`````````0````$```#`*P0`
+$````````
`
end
diff --git a/sys/dev/hptnr/him.h b/sys/dev/hptnr/him.h
index 455818d..9805740 100644
--- a/sys/dev/hptnr/him.h
+++ b/sys/dev/hptnr/him.h
@@ -197,7 +197,8 @@ IDENTIFY_DATA, *PIDENTIFY_DATA;
typedef struct _HIM_DEVICE_CONFIG
{
HPT_U64 capacity;
-
+ HPT_U32 logical_sector_size;
+
DEVICE_FLAGS flags;
HPT_U8 path_id;
diff --git a/sys/dev/hptnr/hptintf.h b/sys/dev/hptnr/hptintf.h
index 82dce3c..fa3b36e 100644
--- a/sys/dev/hptnr/hptintf.h
+++ b/sys/dev/hptnr/hptintf.h
@@ -371,6 +371,7 @@ typedef HPT_U32 DEVICEID;
#define HPT_CAP_DUMP_METADATA 0x1
#define HPT_CAP_DISK_CHECKING 0x2
+#define HPT_CAP_REPORT_SECTOR_SIZE 0x10
typedef struct _DRIVER_CAPABILITIES {
HPT_U32 dwSize;
diff --git a/sys/dev/hptnr/hptnr_config.c b/sys/dev/hptnr/hptnr_config.c
index fe70f93..228ade1 100644
--- a/sys/dev/hptnr/hptnr_config.c
+++ b/sys/dev/hptnr/hptnr_config.c
@@ -46,7 +46,7 @@ int init_config(void)
const char driver_name[] = "hptnr";
const char driver_name_long[] = "R750/DC7280 controller driver";
-const char driver_ver[] = "v1.0.1";
+const char driver_ver[] = "v1.1.1";
int osm_max_targets = 0xff;
diff --git a/sys/dev/hptnr/hptnr_config.h b/sys/dev/hptnr/hptnr_config.h
index f59d6d2..2c91cd0 100644
--- a/sys/dev/hptnr/hptnr_config.h
+++ b/sys/dev/hptnr/hptnr_config.h
@@ -34,6 +34,7 @@
#define TARGETNAME hptnr
#define __dummy_reg hptnr___dummy_reg
#define __ldm_alloc_cmd hptnr___ldm_alloc_cmd
+#define debug_flag hptnr_debug_flag
#define delay_between_spinup hptnr_delay_between_spinup
#define dmapool_active hptnr_dmapool_active
#define dmapool_get_page hptnr_dmapool_get_page
@@ -114,6 +115,7 @@
#define ldm_timer_probe_device hptnr_ldm_timer_probe_device
#define ldm_unregister_device hptnr_ldm_unregister_device
#define log_sector_repair hptnr_log_sector_repair
+#define msi hptnr_msi
#define num_drives_per_spinup hptnr_num_drives_per_spinup
#define os_get_stamp hptnr_os_get_stamp
#define os_get_vbus_seq hptnr_os_get_vbus_seq
diff --git a/sys/dev/hptnr/hptnr_osm_bsd.c b/sys/dev/hptnr/hptnr_osm_bsd.c
index fe352d1..1a436df 100644
--- a/sys/dev/hptnr/hptnr_osm_bsd.c
+++ b/sys/dev/hptnr/hptnr_osm_bsd.c
@@ -30,7 +30,8 @@
#include <dev/hptnr/hptnr_config.h>
#include <dev/hptnr/os_bsd.h>
#include <dev/hptnr/hptintf.h>
-
+int msi = 0;
+int debug_flag = 0;
static HIM *hpt_match(device_t dev)
{
PCI_ID pci_id;
@@ -431,10 +432,61 @@ static void os_cmddone(PCOMMAND pCmd)
{
POS_CMDEXT ext = (POS_CMDEXT)pCmd->priv;
union ccb *ccb = ext->ccb;
+ HPT_U8 *cdb;
+
+ if (ccb->ccb_h.flags & CAM_CDB_POINTER)
+ cdb = ccb->csio.cdb_io.cdb_ptr;
+ else
+ cdb = ccb->csio.cdb_io.cdb_bytes;
KdPrint(("os_cmddone(%p, %d)", pCmd, pCmd->Result));
callout_stop(&ext->timeout);
+ switch(cdb[0]) {
+ case 0x85: /*ATA_16*/
+ case 0xA1: /*ATA_12*/
+ {
+ PassthroughCmd *passthru = &pCmd->uCmd.Passthrough;
+ HPT_U8 *sense_buffer = (HPT_U8 *)&ccb->csio.sense_data;
+ memset(&ccb->csio.sense_data, 0,sizeof(ccb->csio.sense_data));
+
+ sense_buffer[0] = 0x72; /* Response Code */
+ sense_buffer[7] = 14; /* Additional Sense Length */
+
+ sense_buffer[8] = 0x9; /* ATA Return Descriptor */
+ sense_buffer[9] = 0xc; /* Additional Descriptor Length */
+ sense_buffer[11] = (HPT_U8)passthru->bFeaturesReg; /* Error */
+ sense_buffer[13] = (HPT_U8)passthru->bSectorCountReg; /* Sector Count (7:0) */
+ sense_buffer[15] = (HPT_U8)passthru->bLbaLowReg; /* LBA Low (7:0) */
+ sense_buffer[17] = (HPT_U8)passthru->bLbaMidReg; /* LBA Mid (7:0) */
+ sense_buffer[19] = (HPT_U8)passthru->bLbaHighReg; /* LBA High (7:0) */
+
+ if ((cdb[0] == 0x85) && (cdb[1] & 0x1))
+ {
+ sense_buffer[10] = 1;
+ sense_buffer[12] = (HPT_U8)(passthru->bSectorCountReg >> 8); /* Sector Count (15:8) */
+ sense_buffer[14] = (HPT_U8)(passthru->bLbaLowReg >> 8); /* LBA Low (15:8) */
+ sense_buffer[16] = (HPT_U8)(passthru->bLbaMidReg >> 8); /* LBA Mid (15:8) */
+ sense_buffer[18] = (HPT_U8)(passthru->bLbaHighReg >> 8); /* LBA High (15:8) */
+ }
+
+ sense_buffer[20] = (HPT_U8)passthru->bDriveHeadReg; /* Device */
+ sense_buffer[21] = (HPT_U8)passthru->bCommandReg; /* Status */
+ KdPrint(("sts 0x%x err 0x%x low 0x%x mid 0x%x hig 0x%x dh 0x%x sc 0x%x",
+ passthru->bCommandReg,
+ passthru->bFeaturesReg,
+ passthru->bLbaLowReg,
+ passthru->bLbaMidReg,
+ passthru->bLbaHighReg,
+ passthru->bDriveHeadReg,
+ passthru->bSectorCountReg));
+ KdPrint(("result:0x%x,bFeaturesReg:0x%04x,bSectorCountReg:0x%04x,LBA:0x%04x%04x%04x ",
+ pCmd->Result,passthru->bFeaturesReg,passthru->bSectorCountReg,
+ passthru->bLbaHighReg,passthru->bLbaMidReg,passthru->bLbaLowReg));
+ }
+ default:
+ break;
+ }
switch(pCmd->Result) {
case RETURN_SUCCESS:
@@ -561,47 +613,303 @@ static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb)
ccb->ccb_h.status = CAM_REQ_CMP;
break;
- case INQUIRY:
+ case 0x85: /*ATA_16*/
+ case 0xA1: /*ATA_12*/
+ {
+ int error;
+ HPT_U8 prot;
+ PassthroughCmd *passthru;
+
+ if (mIsArray(vd->type)) {
+ ccb->ccb_h.status = CAM_PATH_INVALID;
+ break;
+ }
+
+ HPT_ASSERT(vd->type == VD_RAW && vd->u.raw.legacy_disk);
+
+ prot = (cdb[1] & 0x1e) >> 1;
+
+
+ if (prot < 3 || prot > 5)
{
- PINQUIRYDATA inquiryData;
- memset(ccb->csio.data_ptr, 0, ccb->csio.dxfer_len);
- inquiryData = (PINQUIRYDATA)ccb->csio.data_ptr;
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
- inquiryData->AdditionalLength = 31;
- inquiryData->CommandQueue = 1;
- memcpy(&inquiryData->VendorId, "HPT ", 8);
- memcpy(&inquiryData->ProductId, "DISK 0_0 ", 16);
-
- if (vd->target_id / 10) {
- inquiryData->ProductId[7] = (vd->target_id % 100) / 10 + '0';
- inquiryData->ProductId[8] = (vd->target_id % 100) % 10 + '0';
+ pCmd = ldm_alloc_cmds(vbus, vd->cmds_per_request);
+ if (!pCmd) {
+ HPT_ASSERT(0);
+ ccb->ccb_h.status = CAM_BUSY;
+ break;
+ }
+
+ passthru = &pCmd->uCmd.Passthrough;
+ if (cdb[0] == 0x85/*ATA_16*/) {
+ if (cdb[1] & 0x1) {
+ passthru->bFeaturesReg =
+ ((HPT_U16)cdb[3] << 8)
+ | cdb[4];
+ passthru->bSectorCountReg =
+ ((HPT_U16)cdb[5] << 8) |
+ cdb[6];
+ passthru->bLbaLowReg =
+ ((HPT_U16)cdb[7] << 8) |
+ cdb[8];
+ passthru->bLbaMidReg =
+ ((HPT_U16)cdb[9] << 8) |
+ cdb[10];
+ passthru->bLbaHighReg =
+ ((HPT_U16)cdb[11] << 8) |
+ cdb[12];
+ } else {
+ passthru->bFeaturesReg = cdb[4];
+ passthru->bSectorCountReg = cdb[6];
+ passthru->bLbaLowReg = cdb[8];
+ passthru->bLbaMidReg = cdb[10];
+ passthru->bLbaHighReg = cdb[12];
}
- else
- inquiryData->ProductId[7] = (vd->target_id % 100) % 10 + '0';
-
- memcpy(&inquiryData->ProductRevisionLevel, "4.00", 4);
-
- ccb->ccb_h.status = CAM_REQ_CMP;
+ passthru->bDriveHeadReg = cdb[13];
+ passthru->bCommandReg = cdb[14];
+
+ } else { /*ATA_12*/
+
+ passthru->bFeaturesReg = cdb[3];
+ passthru->bSectorCountReg = cdb[4];
+ passthru->bLbaLowReg = cdb[5];
+ passthru->bLbaMidReg = cdb[6];
+ passthru->bLbaHighReg = cdb[7];
+ passthru->bDriveHeadReg = cdb[8];
+ passthru->bCommandReg = cdb[9];
+ }
+
+ if (cdb[1] & 0xe0) {
+
+
+ if (!(passthru->bCommandReg == ATA_CMD_READ_MULTI ||
+ passthru->bCommandReg == ATA_CMD_READ_MULTI_EXT ||
+ passthru->bCommandReg == ATA_CMD_WRITE_MULTI ||
+ passthru->bCommandReg == ATA_CMD_WRITE_MULTI_EXT ||
+ passthru->bCommandReg == ATA_CMD_WRITE_MULTI_FUA_EXT)
+ ) {
+ goto error;
+ }
+ }
+
+
+ if (passthru->bFeaturesReg == ATA_SET_FEATURES_XFER &&
+ passthru->bCommandReg == ATA_CMD_SET_FEATURES) {
+ goto error;
+ }
+
+
+ passthru->nSectors = ccb->csio.dxfer_len/ATA_SECTOR_SIZE;
+ switch (prot) {
+ default: /*None data*/
+ break;
+ case 4: /*PIO data in, T_DIR=1 match check*/
+ if ((cdb[2] & 3) &&
+ (cdb[2] & 0x8) == 0)
+ {
+ OsPrint(("PIO data in, T_DIR=1 match check"));
+ goto error;
+ }
+ pCmd->flags.data_in = 1;
+ break;
+ case 5: /*PIO data out, T_DIR=0 match check*/
+ if ((cdb[2] & 3) &&
+ (cdb[2] & 0x8))
+ {
+ OsPrint(("PIO data out, T_DIR=0 match check"));
+ goto error;
+ }
+
+ pCmd->flags.data_out = 1;
+ break;
+ }
+ pCmd->type = CMD_TYPE_PASSTHROUGH;
+ pCmd->priv = ext = cmdext_get(vbus_ext);
+ HPT_ASSERT(ext);
+ ext->ccb = ccb;
+ pCmd->target = vd;
+ pCmd->done = os_cmddone;
+ pCmd->buildsgl = os_buildsgl;
+ pCmd->psg = ext->psg;
+
+ if(!ccb->csio.dxfer_len)
+ {
+ ldm_queue_cmd(pCmd);
+ return;
}
+ pCmd->flags.physical_sg = 1;
+ error = bus_dmamap_load_ccb(vbus_ext->io_dmat,
+ ext->dma_map, ccb,
+ hpt_io_dmamap_callback, pCmd,
+ BUS_DMA_WAITOK
+ );
+ KdPrint(("bus_dmamap_load return %d", error));
+ if (error && error!=EINPROGRESS) {
+ os_printk("bus_dmamap_load error %d", error);
+ cmdext_put(ext);
+ ldm_free_cmds(pCmd);
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ xpt_done(ccb);
+ }
+ return;
+error:
+ ldm_free_cmds(pCmd);
+ ccb->ccb_h.status = CAM_PATH_INVALID;
break;
+ }
+
+ case INQUIRY:
+ {
+ PINQUIRYDATA inquiryData;
+ HIM_DEVICE_CONFIG devconf;
+ HPT_U8 *rbuf;
+
+ memset(ccb->csio.data_ptr, 0, ccb->csio.dxfer_len);
+ inquiryData = (PINQUIRYDATA)ccb->csio.data_ptr;
+
+ if (cdb[1] & 1) {
+ rbuf = (HPT_U8 *)inquiryData;
+ switch(cdb[2]) {
+ case 0:
+ rbuf[0] = 0;
+ rbuf[1] = 0;
+ rbuf[2] = 0;
+ rbuf[3] = 3;
+ rbuf[4] = 0;
+ rbuf[5] = 0x80;
+ rbuf[6] = 0x83;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case 0x80: {
+ rbuf[0] = 0;
+ rbuf[1] = 0x80;
+ rbuf[2] = 0;
+ if (vd->type == VD_RAW) {
+ rbuf[3] = 20;
+ vd->u.raw.him->get_device_config(vd->u.raw.phy_dev,&devconf);
+ memcpy(&rbuf[4], devconf.pIdentifyData->SerialNumber, 20);
+ ldm_ide_fixstring(&rbuf[4], 20);
+ } else {
+ rbuf[3] = 1;
+ rbuf[4] = 0x20;
+ }
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case 0x83:
+ rbuf[0] = 0;
+ rbuf[1] = 0x83;
+ rbuf[2] = 0;
+ rbuf[3] = 12;
+ rbuf[4] = 1;
+ rbuf[5] = 2;
+ rbuf[6] = 0;
+ rbuf[7] = 8;
+ rbuf[8] = 0;
+ rbuf[9] = 0x19;
+ rbuf[10] = 0x3C;
+ rbuf[11] = 0;
+ rbuf[12] = 0;
+ rbuf[13] = 0;
+ rbuf[14] = 0;
+ rbuf[15] = 0;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+
+ break;
+ }
+ else if (cdb[2]) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+
+ inquiryData->DeviceType = 0; /*DIRECT_ACCESS_DEVICE*/
+ inquiryData->Versions = 5; /*SPC-3*/
+ inquiryData->ResponseDataFormat = 2;
+ inquiryData->AdditionalLength = 0x5b;
+ inquiryData->CommandQueue = 1;
+
+ if (ccb->csio.dxfer_len > 63) {
+ rbuf = (HPT_U8 *)inquiryData;
+ rbuf[58] = 0x60;
+ rbuf[59] = 0x3;
+
+ rbuf[64] = 0x3;
+ rbuf[66] = 0x3;
+ rbuf[67] = 0x20;
+
+ }
+
+ if (vd->type == VD_RAW) {
+ vd->u.raw.him->get_device_config(vd->u.raw.phy_dev,&devconf);
+ if ((devconf.pIdentifyData->GeneralConfiguration & 0x80))
+ inquiryData->RemovableMedia = 1;
+
+
+ memcpy(&inquiryData->VendorId, "ATA ", 8);
+ memcpy(&inquiryData->ProductId, devconf.pIdentifyData->ModelNumber, 16);
+ ldm_ide_fixstring((HPT_U8 *)&inquiryData->ProductId, 16);
+ memcpy(&inquiryData->ProductRevisionLevel, devconf.pIdentifyData->FirmwareRevision, 4);
+ ldm_ide_fixstring((HPT_U8 *)&inquiryData->ProductRevisionLevel, 4);
+ if (inquiryData->ProductRevisionLevel[0] == 0 || inquiryData->ProductRevisionLevel[0] == ' ')
+ memcpy(&inquiryData->ProductRevisionLevel, "n/a ", 4);
+ } else {
+ memcpy(&inquiryData->VendorId, "HPT ", 8);
+ snprintf((char *)&inquiryData->ProductId, 16, "DISK_%d_%d ",
+ os_get_vbus_seq(vbus_ext), vd->target_id);
+ inquiryData->ProductId[15] = ' ';
+ memcpy(&inquiryData->ProductRevisionLevel, "4.00", 4);
+ }
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
case READ_CAPACITY:
{
HPT_U8 *rbuf = ccb->csio.data_ptr;
HPT_U32 cap;
+ HPT_U8 sector_size_shift = 0;
+ HPT_U64 new_cap;
+ HPT_U32 sector_size = 0;
+
+ if (mIsArray(vd->type))
+ sector_size_shift = vd->u.array.sector_size_shift;
+ else{
+ if(vd->type == VD_RAW){
+ sector_size = vd->u.raw.logical_sector_size;
+ }
+
+ switch (sector_size) {
+ case 0x1000:
+ KdPrint(("set 4k setctor size in READ_CAPACITY"));
+ sector_size_shift = 3;
+ break;
+ default:
+ break;
+ }
+ }
+ new_cap = vd->capacity >> sector_size_shift;
- if (vd->capacity>0xfffffffful)
- cap = 0xfffffffful;
+ if (new_cap > 0xfffffffful)
+ cap = 0xffffffff;
else
- cap = vd->capacity - 1;
-
+ cap = new_cap - 1;
+
rbuf[0] = (HPT_U8)(cap>>24);
rbuf[1] = (HPT_U8)(cap>>16);
rbuf[2] = (HPT_U8)(cap>>8);
rbuf[3] = (HPT_U8)cap;
rbuf[4] = 0;
rbuf[5] = 0;
- rbuf[6] = 2;
+ rbuf[6] = 2 << sector_size_shift;
rbuf[7] = 0;
ccb->ccb_h.status = CAM_REQ_CMP;
@@ -611,8 +919,28 @@ static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb)
case SERVICE_ACTION_IN:
{
HPT_U8 *rbuf = ccb->csio.data_ptr;
- HPT_U64 cap = vd->capacity - 1;
+ HPT_U64 cap = 0;
+ HPT_U8 sector_size_shift = 0;
+ HPT_U32 sector_size = 0;
+
+ if(mIsArray(vd->type))
+ sector_size_shift = vd->u.array.sector_size_shift;
+ else{
+ if(vd->type == VD_RAW){
+ sector_size = vd->u.raw.logical_sector_size;
+ }
+ switch (sector_size) {
+ case 0x1000:
+ KdPrint(("set 4k setctor size in SERVICE_ACTION_IN"));
+ sector_size_shift = 3;
+ break;
+ default:
+ break;
+ }
+ }
+ cap = (vd->capacity >> sector_size_shift) - 1;
+
rbuf[0] = (HPT_U8)(cap>>56);
rbuf[1] = (HPT_U8)(cap>>48);
rbuf[2] = (HPT_U8)(cap>>40);
@@ -623,7 +951,7 @@ static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb)
rbuf[7] = (HPT_U8)cap;
rbuf[8] = 0;
rbuf[9] = 0;
- rbuf[10] = 2;
+ rbuf[10] = 2 << sector_size_shift;
rbuf[11] = 0;
ccb->ccb_h.status = CAM_REQ_CMP;
@@ -641,6 +969,8 @@ static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb)
case 0x8f: /* VERIFY_16 */
{
int error;
+ HPT_U8 sector_size_shift = 0;
+ HPT_U32 sector_size = 0;
pCmd = ldm_alloc_cmds(vbus, vd->cmds_per_request);
if(!pCmd){
KdPrint(("Failed to allocate command!"));
@@ -678,6 +1008,27 @@ static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb)
pCmd->uCmd.Ide.nSectors = (HPT_U16) cdb[8] | ((HPT_U16)cdb[7]<<8);
break;
}
+
+ if(mIsArray(vd->type)) {
+ sector_size_shift = vd->u.array.sector_size_shift;
+ }
+ else{
+ if(vd->type == VD_RAW){
+ sector_size = vd->u.raw.logical_sector_size;
+ }
+
+ switch (sector_size) {
+ case 0x1000:
+ KdPrint(("<8>resize sector size from 4k to 512"));
+ sector_size_shift = 3;
+ break;
+ default:
+ break;
+ }
+ }
+ pCmd->uCmd.Ide.Lba <<= sector_size_shift;
+ pCmd->uCmd.Ide.nSectors <<= sector_size_shift;
+
switch (cdb[0]) {
case READ_6:
@@ -716,7 +1067,7 @@ static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb)
}
default:
- ccb->ccb_h.status = CAM_REQ_INVALID;
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
break;
}
diff --git a/sys/dev/hptnr/i386-elf.hptnr_lib.o.uu b/sys/dev/hptnr/i386-elf.hptnr_lib.o.uu
index 30acda8..c547f65 100644
--- a/sys/dev/hptnr/i386-elf.hptnr_lib.o.uu
+++ b/sys/dev/hptnr/i386-elf.hptnr_lib.o.uu
@@ -1,2931 +1,1555 @@
begin 644 hptnr_lib.o
-M?T5,1@$!`0D```````````$``P`!```````````````X;@4``````#0`````
-M`"@`#@`+`````````````````(M$)`0/ME0D#,8`",9``1*`?"0(`'0)@$@"
-M!.L'C78`@&`"^X32=`B`8`S?ZP:)]H!(#""X%````,.-M@````#SPXVT)@``
-M``"-O"<`````55=64X/L+(ML)$"+?"1(#[9$)$R(1"0;#[94)%"(5"0:BU0D
-M1(M"&(E$)"C'0A@`````@WPD*``/A5T!``")+"3H_/___XG&N`````"%]@^$
-M_0$``(DL).C\____B40D*(7`=1:)="0$B2PDZ/S___^X`````.G7`0``QD8D
-M&L9&)0C&1B8(QD8G`,9&*/_&1BD`QD85JXM4)$0/MT(<9HE&$(EN&,=&(/\`
-M``#'1F0(````BT0D*(M`"(E&-`7_````B48XQD8<)(M$)"B)1E#'1FQ`````
-MQD84@(U>/,=$)`0`````B1PDZ/S____'1"0,_P```(M$)"B+4!"+0`R)1"0$
-MB50D"(D<).C\____B70D!(DL).C\____N\C____K&\<$).@#``#H_/___X/K
-M`8DL).C\____A-MT#`^V1A0\@'3=A,!T/8U$)"B)1"0$B2PDZ/S___\/MT8>
-MB40D!(M4)$2+0BR)!"3H_/___XET)`2)+"3H_/___[@`````Z<H```#'1E``
-M````B70D!(DL).C\____BT0D*(M8"`^V1"0:B40D"`^V1"0;B40D!(U#!(D$
-M).C\____B<;&`P#&0P$`QD,"`,9#`P")?"0$B2PDZ/S___^-5R2X`````,8$
-M$`"#P`&#^!!U](U>!,9')!7&1R41B%\HQD<I`(UW/`^VVXE?(,='9`````"+
-M5"0HBT((B4<TB5=0QT0D!`````")-"3H_/___XE<)`R+1"0HBU`0BT`,B40D
-M!(E4)`B)-"3H_/___[@!````@\0L6UY?7<.0D)"0D)!3BUPD"(M$)`R)PF:)
-M0P3&0PH`9L=#"```9H7`=!J#Z@&Y`````(L#9HD4"(/!`H/J`6:#^O]U[EO#
-MC;8`````5E.+7"0,BT0D$(G&9HE#!,9#"@%FQT,(``!FA<!T(KH`````N0``
-M``"-M"8`````BP-FB10(@\(!@\$"9CGR=>];7L.-M@````"-OP````!3BUPD
-M"(!["@%U*@^W0P@/M\B+$P^W%$J#P`%FB4,(9CM#!G(&9L=#"```9H-K!`$/
-MM\+K%(L3#[=#!(/H`6:)0P0/M\`/MP1"6\.0C70F`(/L"(D<)(ET)`2+7"0,
-MBTPD$(G.@'L*`74F#[=3!`^W0P@!P@^W0P:)QHG0P?H?]_Z+`V:)#%!F@T,$
-M`>L6B?8/MT,$#[?(BQ-FB31*@\`!9HE#!(L<)(MT)`2#Q`C#D(M$)`1F@W@$
-M``^4P`^VP,.+1"0$BP@YR'4'N0````#K"HL1BT$$B4($B1")R,.)]E=64XM4
-M)!"+3"04#[9\)!B)^(3`=#8/M@*)T[X`````.@%T%.L?#[93`0^V00&#PP&#
-MP0$XPG4-@\8!B?*)^#C"=>/K![@`````ZP6X`0```%M>7\.-="8`C;PG````
-M`(M$)`3&0`$`BU0D"(A0`L=`!`````##B?:-O"<`````55=64XM,)!2+?"08
-MBVPD'(MT)"`/ME$!#[;"C01`P>`"B<,#60B#P@&(40$!<02X`````,8$&`"#
-MP`&#^`QU](D[B6L$B?"(0PB)\@^VQHA#"<'J$(/B/P^V0PJ#X,`)T(A#"EM>
-M7UW#C;0F`````(M4)`0/MD(!.@(/DL`/ML##ZPV0D)"0D)"0D)"0D)"04P^W
-M3"0,#[9<)!"+5"0(N`````"`>@+_=0AFB0J(6@+K#(/``8/"!&8]@`!UY@^W
-MP%O#C;8`````C;PG`````(/L'(E<)`R)="00B7PD%(EL)!B+;"0@BTPD*(M<
-M)"P/MT0D)(U4A0"`>@+_=0AFB0J(6@+K&0^VPXE$)`@/M\&)1"0$B2PDZ/S_
-M__\/M\"+7"0,BW0D$(M\)!2+;"08@\0<PXVV`````(V\)P````!3#[=<)`P/
-MMDPD$(M4)`BX`````#A*`G479CD:=1+&0@+_9L<"___K$XVT)@````"#P`&#
-MP@1F/8``==@/M\!;P^L-D)"0D)"0D)"0D)"0D%93BUPD#`^W="00#[9,)!2Z
-M`````(G0.$R3`G4&9CDTDW0.@\`!@\(!@?J`````=>1F/8``=06X@`$```^W
-MP%M>PXVT)@````"-O"<`````@^P0B1PDB70D!(E\)`B);"0,BVPD%`^V120\
-M"'1(/"AT1#RH#X06`0``/(B-="8`#X1:`0``/`IT+#PJC70F`'0D/*H/A/8`
-M```\BHUT)@`/A#H!```\+W0,/(^-="8`#X7H`0``/"\/A)4````\+W<B/`IT
-M9#P*=PH\"(UT)@!U1.M6/"AT>SPJC;8`````=33K;SR/#X3T````/(^)]G<5
-M/(@/A.8````\BHUT)@!U%.G9````/*B-M"8`````='X\JG1ZO@````"_````
-M`+@`````Z68!```/MD4FP>`(#[95)PG0#[95)8/B'\'B$`G0B<:_``````^V
-M12CI/0$```^V52;!XA@/MD4GP>`0"<(/MD4I"<(/MD4HP>`("<*)UK\`````
-M#[9%*\'@"`^V52P)T.D%`0``D(UT)@`/ME4FP>(8#[9%)\'@$`G"#[9%*0G"
-M#[9%*,'@"`G"B=:_``````^V52K!XA@/MD4KP>`0"<(/MD4M"<(/MD4LP>`(
-M"=#IM@```(VV``````^V12:)PK@`````P>(8#[9-)XG+N0````#!XQ`)R`G:
-M#[9-+;L`````"<@)V@^V32B)R[D`````P>,("<@)V@^V32F)R[D`````"<@)
-MV@^V32J[``````^DRQC!X1@)R`G:#[9-*[L`````#Z3+$,'A$`G("=H/MDTL
-MNP`````/I,L(P>$(B<8)SHG7"=\/ME4NP>(8#[9%+\'@$`G"#[9%,0G"#[9%
-M,,'@"`G0C78`B758B7U<B45@9H--$@&+'"2+="0$BWPD"(ML)`R#Q!##ZPV0
-MD)"0D)"0D)"0D)"05E.+="0,#[=$)!"Z_____V:%P'0MNO____^Y`````(/H
-M`0^WP(U8`0^V!#$QT`^VP,'J"#,4A0````"#P0$YV77FB=!;7L.)]HV\)P``
-M``"#[$R+1"10#[90,XE4)$0/ME`RB50D0`^V4#&)5"0\#[90,(E4)#@/ME`O
-MB50D-`^V4"Z)5"0P#[90+8E4)"P/ME`LB50D*`^V4"N)5"0D#[90*HE4)"`/
-MME`IB50D'`^V4"B)5"08#[90)XE4)!0/ME`FB50D$`^V4"6)5"0,#[90)(E4
-M)`B)1"0$QP0D`````.C\____@\1,PY"-="8`4X/L&(M4)""+3"0D#[9!`8A"
-M`0^V00*(0@*+002)0@2+6@@/MD(!C01`P>`"BU$(B40D"(E4)`2)'"3H_/__
-M_X/$&%O#C70F`(V\)P````!3BU0D"(M:1`^V2CRX`````,8$$`"#P`&#^'!U
-M](E:1(A*/%O#C70F`(V\)P````"+5"0$N`````"-M"8`````Q@00_X/``3T`
-M`@``=?+SPXM$)`2Y`````#L`=`V+2`2+$8M!!(E"!(D0B<C#D)"04XM,)`B+
-M&8N#!`$``(G"@>)^__[_B9,$`0``)7[_\O^+402)`HM1!(E"#(M1!(E"$(M1
-M!(E"%(M1!(E"&(M1!(E"!(L!BX!4`0``HP`````E_@#__XL1B8)4`0``6\.0
-M4XM<)`@/MDPD#(L#BY`$`0``B14`````#[=#)&8]@&1T#F8]@)%T"&8]@)1U
-M$XGV#[;)@\$(N`$```#3X`G"ZP\/MLF#P0RX`0```-/@"<*+`XF0!`$``%O#
-MC;8`````4XM<)`@/MDPD#(L#BY`$`0``B14`````#[=#)&8]@&1T#F8]@)%T
-M"&8]@)1U$XGV#[;)@\$(N/[____3P"'"ZP\/MLF#P0RX_O___]/`(<*+`XF0
-M!`$``%O#C;8`````@^P(B1PDB70D!(MT)`P/MDPD$(#Y_W1N@/D?=S.+GA@!
-M``"Z`0```-/BB=#WT"'8B888`0``BX98`0``HP`````AT'1!B898`0``ZSF-
-M=@"+GAP!```/ML&#Z""Z`0```(G!T^*)T/?0(=B)AAP!``"+AF`!``"C````
-M`"'0=`:)AF`!``"+'"2+="0$@\0(P^L-D)"0D)"0D)"0D)"0D(/L'(E<)`R)
-M="00B7PD%(EL)!B+;"0H#[94)"2+1"0@BSB`^@-V?`^VVL'C`XVT'P`"``#'
-M!@P!``#'!"00)P``Z/S___^-G!\$`@``#[95`\'B&`^V10+!X!`)P@^V10`)
-MP@^V10'!X`@)PHD3QP80`0``QP0D$"<``.C\____#[95!\'B&`^V10;!X!`)
-MP@^V100)P@^V107!X`@)PHD3ZWH/MMK!XP.-M#L``@``QP8,`0``QP0D$"<`
-M`.C\____C9P[!`(```^V50/!XA@/MD4"P>`0"<(/MD4`"<(/MD4!P>`("<*)
-M$\<&$`$``,<$)!`G``#H_/___P^V50?!XA@/MD4&P>`0"<(/MD4$"<(/MD4%
-MP>`("<*)$XM<)`R+="00BWPD%(ML)!B#Q!S#ZPV0D)"0D)"0D)"0D)"0@^P<
-MB5PD%(ET)!B+="0@#[9<)"2)7"0$B30DZ/S____'!"00)P``Z/S___^)7"0$
-MB30DZ/S___^+7"04BW0D&(/$',.-M@````"-OP````!55U93@^P,BVPD(`^V
-M5"0D#[9$)"B(1"0+BT4`@'TF``^$0@$``(V8A`$``(VXT`$``+X`````#[;2
-MB50D!(GVBT0D!(GQT_BH`0^$`P$``(/^`W8.BP.C`````(/@_HD#ZPR+`Z,`
-M````@^#^B0/'!"00)P``Z/S___^`?"0+`'0^@_X#=@Z+!Z,`````@\@"B0?K
-M#(L'HP````"#R`*)!XGZ@_X#=@F+`J,`````ZP>+`J,`````J`)T9.OEB?:#
-M_@-V+,>#K`````````#'!"00)P``Z/S___^+@[````"C`````(/(`8F#L```
-M`.LTQX/,`````````,<$)!`G``#H_/___XN#T````*,`````@\@!B8/0````
-MZR.-=@"#_@-V&\=#_`$```"+`Z,`````@\@!B0/K&8VV`````,=#_`$```"+
-M`Z,`````@\@!B0.#Q@&#PPB#QP0/MD4F.?`/A]C^__^#Q`Q;7E]=PU93@^P$
-MBTPD%`^V7"08BT0D$(LP@_D#=A>-E,Z``0``BP*C`````(/@_HD"ZQ6)]HV4
-MSH`!``"+`J,`````@^#^B0*$VW19@_D#=A6-E([0`0``BP*C`````(/(`HD"
-MZQ.-E([0`0``BP*C`````(/(`HD"C82.T`$``)"-="8`@_D#=@N+$(D5````
-M`.L)D(L0B14`````]L("='/KX9"#^0-V-8T<S0````"-A#,P`@``QP``````
-MQP0D$"<``.C\____C9PS-`(``(L#HP````"#R`&)`^LVC1S-`````(V$,U`"
-M``#'``````#'!"00)P``Z/S___^-G#-4`@``BP.C`````(/(`8D#C78`@\0$
-M6U[#D)"0D)"0D)"0D%.+3"0(BQD/MX&("P``@\`!9HF!B`L``&8[@8P+``!R
-M"6;'@8@+``````^W@8@+``#!X`(#@8`*``"+5"0,BQ*)$`^W@8@+``")@RP!
-M``!;P^L-D)"0D)"0D)"0D)"0D%93BTPD&`^W5"00#[9T)!2+7"0,N`````"-
-MM"8`````Q@0(`(/``8/X!'7T9H'B_P\/MP%F)0#P"=!FB0$/ME,)P>(,BP$E
-M_P_P_PG0B0$/MD,&@^`"@_@!&=*#X@*#P@'!X@4/MD$#@^`?"="#R!"#X/>(
-M00/V0P8!=!:)\H/B?\'B!`^W00)F)0_X"=!FB4$"6U[#C70F`(V\)P````"+
-M3"0$BU0D"+@`````C78`Q@00`(/``8/X#77T#[9!)8@"#[9!)HA"`0^V02>(
-M0@(/MD$HB$(##[9!*8A"!`^V02J(0@4/MD$KB$(&]D%F!'0C#[9!+(A""`^V
-M02V(0@D/MD$NB$(*#[9!+XA""P^V03"(0@RX`0```,.0C70F`%575E.+;"04
-MBWPD&+H`````O@$```#K4`'2B=C3^*@!=!#WP@````%U%H'R=R?;`.L.]\(`
-M```!=`:!\G<GVP"#Z0&#^?]UT(/&`8/^"748B=#!Z!"(10")T,'H"(A%`8A5
-M`EM>7UW##[9</O^Y!P```.NDC;8`````C;\`````BT0D!(N`.`H``(L0BU`$
-MBU`(BT`,HP````##D(UT)@!75E.#[!"+?"0@BW0D)(M&5`^V7RN$VW0F#[90
-M";D`````]L(!=!'K%HVT)@````")T-/XJ`%U!X/!`3C9=?'&1B8,B70D!(D\
-M).C\____@\006UY?PXUV`(V\)P````"#[`R+1"00BQ!FQT`R`0#&0"8=B40D
-M!(D4).C\____@\0,PXVV`````(V\)P````!64X/L%(M$)""+,`^W1"0DP>`"
-M`X;$!0``BQB%VW1$BQ8/MT,>9L'H!0^WP(T$A0`#``")@G`!``"+%@^W2QZ#
-MX1^X`0```-/@B8)T`0``QT0D"`````")7"0$B30DZ/S___^#Q!1;7L.-M"8`
-M````55=64X/L'(ML)#"`?2L`="NY`````(M$)#3V0`D!=!#K&HM4)#0/MD()
-MT_BH`74,@\$!#[9%*V8YR'?FBU0D-(M"*(7`="6#P%B+512)1"0$B10DZ/S_
-M__^+5"0TBT(HB40D!(DL).C\____BT0D-(/`.(M4)#0Y0C@/A(\!``")1"08
-MBT0D&(D$).C\____B<:#>"``#X1.`0``@'A/``^$F0```&:#?5``#X2.````
-MOP````"-!+T``````X7$!0``BQB%VW1G#[=#$&8[1AQU768]A0!W5P^WP("\
-M*+`$``#_=$J+50`/MT,>9L'H!0^WP(T$A0`#``")@G`!``"+50`/MTL>@^$?
-MN`$```#3X(F"=`$``,9#%"''1"0(`````(E<)`2)+"3H_/___X/'`0^W15`Y
-M^`^/=____XM&(,=`8`````#V1B@$=2&)+"3H_/___XM&(,=$)`@!````B40D
-M!(DL).C\____B?:+5B`/MH*8````#[92`HT$@`^VA`(`````#[95(@^V32&)
-M1"0,B50D"(E,)`3'!"18````Z/S___^+1B"+E3P%``")1"0(B50D!,<$)`$`
-M``#H_/___XM&((N5/`4``(E$)`B)5"0$QP0D!@```.C\____QT8@`````(M4
-M)#2`:@H!B70D!(DL).C\____BU0D&(M$)#0Y4#@/A77^__^+1"0TQT`H````
-M`(M%`(N(6`$``(D-`````(7)=`F+10")B%@!``"#Q!Q;7E]=PXGV5U93@^P@
-MBW0D,(L^#[9?*X3;=#"-AY`+``"Y`````#GP=1CK'P^VP8G"P>(&C82"D`L`
-M`(T$!SGP=`Z#P0$XV77CZP6Y``````^VT8G0P>`&C020BXP'F`L``(7)#X1_
-M````]D$&`G1YC80'D`L``#E!&'5M#[9!-(3`=`B#P`&(033K78M1+(/J((U9
-M+(U"(#G8=$V#>@P`=3KK"8UV`(-Z#`!U+\9!-`''1"00``````^V@HL```")
-M1"0,B50D"(E,)`2+A_@)``")!"3H_/___^L-BU(@@^H@C4(@.=AUOH/$(%M>
-M7\.-M"8`````@^P<B5PD#(ET)!")?"04B6PD&(M<)""+?"0DBT=,BV@<#[=7
-M$&:!^H4`=W0/M\(/MH0#L`0``#S_=&5F@_I_=Q\/ML"+DW`%``!IP"@!``"+
-M1!`L#[9`!.M+C;8`````9H'Z@0!W&0^VP(N3J`4``&G`%`T``(M$$`@/MD`$
-MZR4/ML"+DXP%``!IP+````"+1!!4#[9`!.L,C;0F`````+C_````#[:T&#8%
-M``"+1U"%P'0,B40D!(D<).C\____B7PD!(D<).C\____B6PD!(GR#[;":\!<
-MC80#0`$``(D$)/^5G````(M<)`R+="00BWPD%(ML)!B#Q!S#C70F`(/L'(E<
-M)`R)="00B7PD%(EL)!B+="0DBUPD*`^W;"0L9H%^).$!=1`/MD8F@^@1OP``
-M```\`78NBT0D((L0B[IP!0``#[=&$+G8)@$`9CV%`'<1#[?`#[:$`K`$``!I
-MR"@!```!S\9#!`6`8P7^@"/?N`````!F@7XDX0%U$@^V1B:#Z`$\`0^6P`^V
-MP(UV`,'@!P^V$X/B?PG"B!,/MD9F@^`!P>`&@^*_"<*($_9&9@%T#HD\).C\
-M____9HE#".L$9HEK"`^W0PB(1A5F@7XDX0%U*P^V5B:-0O\\`7<0#[96)X/B
-M#^LIC;0F`````(U"[[H/````/`%V%HUT)@"Z`````(-_-`!T!P^V5TV#X@\/
-MM@.#X/`)T(@#BUPD#(MT)!"+?"04BVPD&(/$',.#[#R)7"0LB70D,(E\)#2)
-M;"0XBUPD1`^V0R0\"'01/"AT#3RH=`D\B'4+D(UT)@"#2V0*ZQX\"G06/"J-
-M="8`=`X\JG0*/(IU"HVV`````(-+9`(/MWLD9H'_X0%U&0^V0R:#Z!$\`7<.
-M@TMD"+@`````Z7T%``"+0R0E____`(E$)"`]X0$0``^%Y`````^W4Q!F@?J%
-M``^',@4```^WPHMT)$`/MHP&L`0``+C_____@/G_=&EF@_I_=QT/ML&+="1`
-MBY9P!0``:<`H`0``BT00+`^V0`3K1F:!^H$`=QT/ML&+="1`BY:H!0``:<`4
-M#0``BT00"`^V0`3K(@^VP8MT)$"+EHP%``!IP+````"+1!!4#[9`!(VT)@``
-M```/ML"+5"1`#[:$`C8%``!KP%R-M`)``0``BY*H!0``#[;!:<`4#0``QT0D
-M)`````#V1`(U$`^%2@(``,9#%`2+5"1(QP(`````N`$```#I@@0```^W4Q"Y
-M_P```+C_____9H'ZA0!W?@^WPHMT)$`/MHP&L`0``+C_____@/G_=&)F@_I_
-M=QT/ML&+="1`BY9P!0``:<`H`0``BT00+`^V0`3K/V:!^H$`=QT/ML&+="1`
-MBY:H!0``:<`4#0``BT00"`^V0`3K&P^VP8MT)$"+EHP%``!IP+````"+1!!4
-M#[9`!`^VR0^VP(E$)"B+5"1`#[:L$#8%``!KQ5R-M`)``0``#[?!:<`H`0``
-M`X)P!0``B40D)&:!_^$!=0L/MD,F@^@!/`%V*6:!^?\`=`J+3"0D]D$G!'48
-MQD,4!HMT)$C'!@````"X`0```.F$`P``BU0D)`^V0B2)PH/B!8/Z!74ABTPD
-M0`^V02PZ039R%(MT)$C'!@$```"X`0```.E1`P``@WPD)``/A/8```"#^@4/
-MA>T```")7"0$BT0D)(D$).C\____A,!U&,9#%`2+5"1(QP(`````N`$```#I
-M$0,``(M,)"2`>4\?=A2+="1(QP8!````N`$```#I\P(``/9#9@%T$VO%7(M4
-M)$#VA`)(`0```707ZV!KQ5R+3"1`]H0!2`$```$/A!@"``"+="0HB70D!(M$
-M)$")!"3H_/___X3`=!2+5"1(QP(!````N`$```#IF0(``/9#9@$/A.(!``!K
-MQ5R+3"1`]H0!2`$```$/A,T!``"+="0DB30DZ/S___]F@_@?#X:W`0``BT0D
-M2,<``0```+@!````Z5`"``#V1@8"=#6!?"0@X0$0``^$CP$``(M4)"0/MD)/
-M.D).<BB+3"1(QP$!````N`$```#I&P(``(VV`````(%\)"#A`1``#X1:`0``
-MBW0D)`^W1CJ`>R3A#X5(`0``@'LE`0^%/@$``-'HB<*#X@$/MD,F@^@&/`D/
-MAQ`!```/ML#_)(4`!```QT0D$`$```#'1"0,`0```(E<)`B+1"0DB40D!(M4
-M)$")%"3H_/___X3`#X7N````BTPD2,<!`@```+@!````Z8<!``#'1"00`0``
-M`,=$)`P`````B5PD"(MT)"2)="0$BT0D0(D$).C\____A,`/A:H```"+5"1(
-MQP("````N`$```#I0P$``,=$)!`!````#[;"B40D#(E<)`B+3"0DB4PD!(MT
-M)$")-"3H_/___X3`=6N+1"1(QP`"````N`$```#I!`$``,=$)!``````#[;"
-MB40D#(E<)`B+5"0DB50D!(M,)$")#"3H_/___X3`=2R+="1(QP8"````N`$`
-M``#IQ0```,9#%`2+1"1(QP``````N`$```#IK0```(M$)$`%-`D``(D$).C\
-M____A,!T%(M4)$C'`@$```"X`0```.F$````@'LDX750@'LE`75*@'LF#W5$
-M@'LI`74^#[9#*,'@"`^V4R<!T`^WP(E$)`2+3"1`B0PDZ/S___\[0TAU!(7`
-M=17&0Q0$BW0D2,<&`````+@!````ZRZX`````.LGB?:+5"1`#[:"-08``&O`
-M7(VT`D`!``"+DJ@%``"X[`8-`.E3^___BUPD+(MT)#"+?"0TBVPD.(/$/,.-
-MM"8`````@^P<BT0D+(E$)`R+1"0HB40D"(M$)"2)1"0$BT0D((L`B00DZ/S_
-M__^#Q!S#C78`55=64X/L3(M$)&"+F%P*``"+5"1D9L="'O\/C40D,(E$)`B)
-M5"0$BTPD8(D,).C\____A,!T"8M,)##I3`P``(MT)&2+1B0E____`#WA`1``
-M#X7=````QP0DB!,``.C\____#[=6$&:!^H4`#X?Q"P``#[?"BWPD8`^VC`>P
-M!```N/____^`^?]T8F:#^G]W'0^VP8MT)&"+EG`%``!IP"@!``"+1!`L#[9`
-M!.L_9H'Z@0!W'0^VP8M\)&"+EZ@%``!IP!0-``"+1!`(#[9`!.L;#[;!BW0D
-M8(N6C`4``&G`L````(M$$%0/MD`$#[;`BWPD8`^VA`<V!0``:\!<C80'0`$`
-M`(E$)!R+EZ@%```/ML%IP!0-```!PHE4)"3'1"0@`````,=$)"@`````Z7(!
-M``"+1"1D#[=0$+G_````9H'ZA0!W#P^WPHMT)&`/MHP&L`0``(M\)&0/MW<D
-M9H'^X0%U#P^V1R:#Z!$\`0^&N````&:!^H4`=W,/M\*+?"1@#[:$![`$```\
-M_W1@9H/Z?W<9#[;`BY=P!0``:<`H`0``BT00+`^V0`3K1F:!^H$`=QT/ML"+
-M?"1@BY>H!0``:<`4#0``BT00"`^V0`3K(@^VP(M\)&"+EXP%``!IP+````"+
-M1!!4#[9`!.L%N/____\/ML"+5"1@#[:$`C8%``!KP%R-A`)``0``B40D'`^W
-MP6G`*`$```."<`4``(E$)"!F@?[A`75(ZS`/M\%IP+````"+3"1@`X&,!0``
-MB40D*(MP5(ET)!S'1"0@`````,=$)"0`````ZTF+?"1D#[97)HU"[SP!=BJ-
-M0O\\`78C9H'Y_P!T"HM$)"#V0"<$=1*+5"1DQD(4!KD`````Z?8)``#'1"0D
-M`````,=$)"@`````C40D2(E$)`2+3"1@B0PDZ/S___]FB40D&HMT)&1FB48>
-MBWPD8(D\).C\____B<6Y`@```(7`#X2J"0``BT0D9(EH5`^W5"0:B50D%&G"
-ML`0``(T\&(U'((M,)&`K@5P*``")PL'Z'P.!8`H``!.19`H``(M,)$B)02"+
-M3"1(B5$DBT4,BU40BTPD2(E!*(M,)$B)42R+1"1(#[=T)!IFB7`(N`````"-
-M=@#&!#@`@\`!/;`$``!U\HM$)&1F@7@DX0%U9HG"#[9`)H/H$3P!=UF-1"0W
-MB40D#(M$)$@/MD`(B40D"(E4)`2+3"0@B0PDZ/S___^-AR`$``"+7"1@*X-<
-M"@``B<+!^A\#@V`*```3DV0*``"+3"1(B4$0BTPD2(E1%.E&`0``D(M$)!P/
-MME`&]L(!=2N+3"1DBT$D)?___P`]X0$0``^$M@```(M<)"`/MD,D@^`%@_@%
-M#X6B````BW0D9/9&9B!T$HU$)#>)1"0$B30DZ/S____K*(U$)#>)1"0,BT0D
-M2`^V0`B)1"0(BT0D9(E$)`2+5"0@B10DZ/S___^-AR`$``"+3"1@*X%<"@``
-MB<+!^A^)RP.!8`H``!.19`H``(M,)$B)01"+3"1(B5$4B?@K@UP*``")PL'Z
-M'XMT)&`#AF`*```3EF0*``"+3"1(B4$8BTPD2(E1'.MK]L("=&:)^(M4)&`K
-M@EP*``")PL'Z'XM,)&`#@6`*```3D60*``"+3"1(B4$8BTPD2(E1'(V'(`0`
-M`(M<)&`K@UP*``")PL'Z'P.#8`H``!.39`H``(M,)$B)01"+3"1(B5$4BT0D
-M2(!(`0*+1"1D#[90/8M$)$AFB5`"BU0D9(!Z/0!T/+X`````NP````"+30B+
-M1"1DBU!$BP0:B009BT0:!(E$&02+1!H(B409"(/&`8/##(M4)&0/MD(].?!W
-MSHM,)&2+42"+1"1(B5`,9H%Y).$!=5$/MD$F@^@1/`%W1@^W1"0:B40D#(M$
-M)$B)1"0(B4PD!(M<)!R)'"3H_/___XU$)#>)1"0,B7PD"(MT)&2)="0$B1PD
-MZ/S___^`8PC^Z0P%``"+5"0<#[9"!J@"#X2"!```BT0D2,9`!OZ+1"1(@&`'
-M_H-\)"``#X33````BTPD(`^V422)T(/@!H/X!@^%O0```/;"`0^$M`````^W
-M1"0:B40D#(M$)$B)1"0(BUPD9(E<)`2+="0<B30DZ/S____V0V8!=`^+1"1(
-M#[=`",'@`XA$)#B-1"0WB40D#(E\)`B+1"1DB40D!(M4)!R)%"3H_/___XM,
-M)&3V068!=`J+7"0<@$L(`>L(BW0D'(!F"/[&!Z&+5"0@#[:"M@```(/@#P^V
-M5P&#XO`)PHA7`8M,)"`/MT$<@\`!9L'`"&:)1P*)RX'#H````.F``P``D(M<
-M)&1F@7LDX0$/A3D"```/MD,F/`]T$KL`````/!`/A5H#``#IM@```(MT)&0/
-MME8HP>((#[9&)P'"BT0D2,9`!`V+1"1(@&`%_H!,)$<(BUPD2`^V1A6+="1@
-M#[:.U@```-/@9@E#"(M,)$@/MD$!@^`?@\@@B$$!BTPD9(M!*HF'.`0``(M!
-M+HF'/`0``&;!P@AFB9=$!```#[9!*8B'0@0``,8'D8M<)"`/MT,<@\`!9L'`
-M"&:)1P(/MI.V````@^(/#[9'`8/@\`G0B$<!BUPD(('#H````.F?`@``BU0D
-M2(MT)&0/MD85BUPD8`^VB]8```#3X&8)0@C&!X%FQT<"__^+="0D#[:6BP``
-M`(/B#P^V1P&#X/`)T(A'`8M$)&2#>#0`=0[&0!0AN0````#IA`0``(M4)&3V
-M0B<!="Z+6CB%VW0GB5PD!(M,)&"+@?@)``")!"3H_/___X/@#P^V5P&#XO`)
-MPHA7`>L$BUPD)(MT)&2+5C0/MD(!OA`````\@'1\/(!W'#P5=Q(\$'-D@^@"
-M/`%W0I"-="8`ZT\\%W<WZU<\A8VV`````'0D/(5W#CR!=#X\@HUT)@!U&^L@
-M/)!R%;XH````/)*0=C(\DW4'OHP```#K)[X$````ZR`/MD($C32%"````.L3
-MO@@```#K#+X,````ZP6^'````(GRP>H"BT0D2(A0!(M,)$AFP>H(@^(!#[9!
-M!8/@_@G0B$$%C9<@!```BTPD9(M!-(ET)`B)1"0$B10DZ/S____I-@$``(M<
-M)&0/MD,D@^@$/*MW00^VP/\DA2@$``"+="1D#[9&+,'@"`^V5BV-#!"#^0UW
-M%K@!````T^"IV#X``'0(BT0D2(!(`02+1"1(@$@!`>L(BT0D2(!@`?N+1"1(
-MQD`$#8M$)$B`8`7^BU0D2(M,)&0/MD$5BUPD8`^VB]8```#3X&8)0@B+1"1(
-M@&`!'\:'(`0```:+7"0@@<.@````B5PD!(V'(00``(D$).C\____B5PD!(V'
-M)00``(D$).C\____C8]$!```BU0D9(/")(MT)&2+1B2)AT0$``"+0@2)002+
-M0@B)00B+0@R)00R+5"0@BX*H````B8<X!```BX*L````B8<\!```Q@>1BTPD
-M(`^VD;8```"#X@\/MD<!@^#P"="(1P$/MT$<@\`!9L'`"&:)1P*%VP^$AP``
-M`(L#B4<$BT,$B4<(ZWJH`71V#[=$)!J)1"0,BT0D2(E$)`B+7"1DB5PD!(MT
-M)!R)-"3H_/____9#9@%T#XM$)$@/MT`(P>`#B$0D.(U$)#>)1"0,B7PD"(M$
-M)&2)1"0$BU0D'(D4).C\____BTPD9/9!9@%T"HM<)!R`2P@!ZPB+="0<@&8(
-M_HM4)&"+@L0%``"+7"1DBTPD%(D<B`^W5"0:9L'J!0^WT@^W7"0:B=F#X1^X
-M`0```-/@BW0D8`F$EL@%``"+5"1DBT(D)?___P`]X0$0`'4TC40D1(E$)`S'
-M1"0(`````(E<)`2+3"0<B0PDZ/S___\/MD0D1X/@'X/(0(A$)$?IP0```(MT
-M)&1F@7XDX0%U10^V1B:#Z!$\`7<ZBT0D*(E$)`2+5"1@B10DZ/S___^-1"1$
-MB40D#(M,)"@/MD$TB40D"(E<)`2+7"0<B1PDZ/S____K<(MT)"")="0$BT0D
-M8(D$).C\____C40D1(E$)`P/MD9"B40D"(E<)`2+5"0<B10DZ/S___\/ME8D
-MB="#X`:#^`9U+O;"`70I#[9$)$>#X!^#R&"(1"1'#[960H/B?\'B!`^W1"1&
-M9B4/^`G09HE$)$:-1"1$B40D!(M,)&")#"3H_/___XM'((M7)+D#````B=,)
-MPW1$B40D!(E4)`C'!"1X````Z/S___^Y`P```.LIBW0D8`^VAC4&``!KP%R-
-MA`9``0``B40D'(N6J`4``+CL!@T`Z8WT__^)R(/$3%M>7UW#C78`C;PG````
-M`%575E.#[!R+="0PQT0D%`````"-OMP```#IH@$``(GVB3PDZ/S___^)PX-X
-M3`!U,(DT).C\____B4-,A<!U(8V6W````(N&W````(E8!(D#B5,$B9[<````
-MZ8@!``")]HM#)"7___\`/>$!$``/A-,````/MT,09CV```^$Q0````^VT&:)
-M4Q!F@_I_=A-F@7LDX0%U(@^V0R:#Z!$\`7<79H'ZA0!W$`^WP@^VC`:P!```
-M@/G_=1C&0Q0&B5PD!(DT).C\____Z?,```"-=@`/MVLD9H']X0%U%0^V0R:(
-M1"0;@^@1/`$/A^````#K%0^VP6G`*`$```.&<`4``(E$)!3K#`^V1"0;@^@!
-M/`%V-6:!^H``="YF@?WA`74+#[9#)H/H$3P!=AR+1"04]D`G!'42QD,4!HE<
-M)`2)-"3H_/___^MZB5PD!(DT).C\____@_@"=PN#^`%S)HUT)@#K$(/X`W59
-MB?:-O"<`````ZT&)7"0$B30DZ/S___^)]NL^@WM4`'0/C4-4B40D!(DT).C\
-M____C9;<````BX;<````B5@$B0.)4P2)GMP```#K,XE<)`2)-"3H_/___Y`Y
-MOMP````/A53^___K&`^VP6G`*`$```.&<`4``(E$)!3I'____X/$'%M>7UW#
-MB?:#[#R)7"0LB70D,(E\)#2);"0XBWPD0(MW+(LN#[9&"*@0=`S&A[0````&
-MZ:("```/MI>T````@/H!#X2#````@/H!<AN`^@0/A*H```"`^@8/A>$"``#I
-M=@(``(UT)@#&A[0````!B7PD!(DL).C\____BT0D1,9`%(&`3@@(@WA4`'03
-MBT0D1(/`5(E$)`2)+"3H_/___XN%W````(M4)$2)4`2)`HV%W````(E"!(F5
-MW````(DL).C\____Z74"``"#X/>(1@B`A[<````!QH>T`````(M,)$3&010"
-MB4PD!(DL).C\____B2PDZ/S____I0`(``,:'MP````"+1"1$@WA4`'0/@\!4
-MB40D!(DL).C\____BT\@A<D/A*\!``"+402-0@&)002#^B@/AYT!``"+A=P`
-M``"+5"1$B5`$B0*-A=P```")0@2)E=P```"`?R;_=":+1S2%P'0&@'@F`'09
-MB7PD",=$)`0"````B30DZ/S____IN0$```^V1@B#X/>#R!"(1@B+5S"%TG4-
-M@'X*`'4PZ0(!``")]L=$)!``````QT0D#`(````/MD=-B40D"(E4)`2)-"3H
-M_/___^EO`0``QT0D(`````#&1"0G`(U..(E,)!R+1"0<B00DZ/S___^)1"0H
-MBT8\BU0D*(E6/(M,)!R)"HE"!(D0BT(@A<!T(HE$)`B+A3P%``")1"0$QP0D
-M!0```.C\____BT0D*(!(*`*+5"0HB50D",=$)`0&````B30DZ/S___^+3"0H
-M@'E/`'1`BUPD((/#`8%\)"!_EI@`=RN)]HDL).C\____QP0D`0```.C\____
-MBT0D*(!X3P!T"X/#`8'[@9:8`'77B5PD((!$)"<!#[94)"<X5@H/ASW___^+
-M1S2%P'4;QD<F`V;'AY0``````(E\)`2)+"3H_/___^MVB00DZ/S___^-M@``
-M``#K9@^V7R;'!"0`````Z/S___^`9@COBX7<````BTPD1(E(!(D!C87<````
-MB4$$B8W<````B7PD",=$)`0&````B30DZ/S___^`^_]U$XE\)`B)="0$B2PD
-MZ/S___^-=@")+"3H_/___XM<)"R+="0PBWPD-(ML)#B#Q#S#C70F`%575E.#
-M[&R+M"2`````BY9P!0``N-@F`0"+C"2$````9H%Y$(4`=QF+G"2$````#[=#
-M$`^VA#"P!```:<`H`0``C3P"BY8X"@``@<)`"```#[9'0L'@"`'"BPJ)#0``
-M``")R,'H$(A$)$"+EC@*``"!PD`(```/MD="P>`(`<*+0@2C`````(A$)%B)
-MPL'J"(A4)%G!Z!"(1"1:BY8X"@``@<)`"```#[9'0L'@"`'"BT((HP````"(
-M1"1;B<+!Z@B(5"1<P>@0B$0D7<9$)%X`QD0D7P")S<'M&`^V7"1`BT0D7(E$
-M)!"+1"18B40D#(EL)`B)7"0$QP0DI````.C\____B=B#\`&)PH/B`70@@'PD
-M0`!T&8N4)(0```#&0A0`N`````#IM`(``(UT)@"+C"2$````@'D4@74SC40D
-M6(E$)`R);"0(B5PD!(D,).C\____BYPDA````,9#%`*X`````.EV`@``C;8`
-M````BXPDA````(M!)"7___\`/>$!#@!U#L9!%"&X`````.E,`@``BX0DA```
-M`/9`9@%U,X32=2^`?R;_="F-1"18B40D#(EL)`B)7"0$BY0DA````(D4).C\
-M____N`````#I#`(``(E\)`2)-"3H_/___XE\)`2)-"3H_/___XL6BXPDA```
-M``^W01YFP>@%#[?`C02%``,``(F"<`$``(L&BYPDA`````^W2QZ#X1^Z`0``
-M`(G5T^6)J'0!```/MT,>P>`"`X;$!0``QP``````#[=+'HG(9L'H!0^WP(/A
-M'XG3T^.)V??1(8R&R`4``(NL)(0````/MTT>B<AFP>@%#[?`@^$?T^+WTB%4
-MAE2+50"+102)0@2)$`^W11Z-EC0)``")1"0$B10DZ/S___^`;T\!QD44@8-]
-M5`!T$8GH@\!4B40D!(DT).C\____C4<0.4<0#X3L````B40D+(V6-`D``(E4
-M)#R+3"0LB0PDZ/S___^)PXL6#[=`'F;!Z`4/M\"-!(4``P``B8)P`0``#[=+
-M'H/A'[H!````B=73Y8L&B:AT`0``#[=#'L'@`@.&Q`4``,<```````^W2QZ)
-MR&;!Z`4/M\"#X1^)U=/EB>GWT2&,AL@%```/MTL>B<AFP>@%#[?`@^$?T^+W
-MTB%4AE0/MT,>B40D!(M$)#R)!"3H_/___X!O3P&#>U0`=`^-0U2)1"0$B30D
-MZ/S___^-EMP```"+AMP```")6`2)`XE3!(F>W````(M4)"PY5Q`/A2+___^+
-MC"2$````@6%D___^_\:'M`````2)3"0$B3PDZ/S___^X`0```)"-="8`@\1L
-M6UY?7<.0C;0F`````%575E.#[$P/MVPD9(M4)&B)5"0PBT0D;(E$)#2+?"1@
-MBS>+AEP*``")1"04"U0D-`^$BP(```^WU6G"L`0``(M<)!2-#!CV02$"=!6-
-M!)4``````X;$!0``BP#&0!0"ZQ.-!)4``````X;$!0``BP#&0!0AP>("B50D
-M+(G0`X;$!0``BQ"+0B0E____`#WA`1``#X2*`0``#[="$&8]A0!W#P^WP`^V
-MA`:P!```//]U%8M$)"P#AL0%``"+`,9`%`;I+@@```^VP&G`*`$```.&<`4`
-M`(E$)!B`?"0S`'E=#[90)(G0@^`&@_@&=1_VP@%T&HL&BY!8`0``B14`````
-MA=)T"(L&B9!8`0``BP:+@%`!``"C`````(/(`HL6B8)0`0``BP:+@`0!``"C
-M`````(#,_XL6B8($`0``9O=!(`((#X3A````@'XK``^$UP```,9$)!\`NP``
-M``"-=@")V@^VRP^V1PG3^*@!=$>`^P-V'(L&!=`!``"-!(B+`*,`````P>@4
-M@^`!ZQJ-=@"+!@70`0``C02(BP"C`````,'H%(/@`83`=`NX`0```-/@"$0D
-M'X/#`8U"`3A&*W>?@'PD'P!T8@^V1"0?.$<)=5B)Z&;!Z`4/M\")Z8/A'[H!
-M````T^*%5(94=3V+5"08@+JT`````G<'QH*T`````XM$)"P#AL0%``"+`(E$
-M)`2+3"08B0PDZ/S____IT@8``,=$)!@`````]D0D,P$/A+\&``"+1"0L`X;$
-M!0``BPC&010ABT$D)?___P`]X0$.``^$G`8``(N6.`H``('"0`@``(M<)!@/
-MMD-"P>`(`<*+`J,`````BY8X"@``@<)$"```#[9#0L'@"`'"BP*C`````(N6
-M.`H``('"2`@```^V0T+!X`@!PHL"HP````")3"0$B30DZ/S____I,P8```^W
-M_8TLO0````"+AL0%```!Z(L09H%Z).$!#X4'`0``#[9:)H#[$`^'!@8``+@!
-M````B=G3X*G`,```#X73````J0```0!U4?;$@`^$X@4``&G'L`0``(M<)!2-
-M#!@/MD$SB$(4B>@#AL0%``"+`/9`$P0/A+H%``"`>!0`#X2P!0``BU`XA=(/
-MA*4%```/MD$SB`+IF@4``&G'L`0``(M4)!2-/!")Z`.&Q`4``(L0#[9'*HA"
-M%(GH`X;$!0``BP"#>#0`#X1H!0``#[:'(00``(D$).C\____B>H#EL0%``"+
-M$HM2((G#.=!V`HG3C5<HB>@#AL0%``"+`(M`-(E<)`B)5"0$B00DZ/S____I
-M'P4``(GH`X;$!0``BP#&0!0`Z0P%``")Z`.&Q`4``(L`B40D((M(2(E,)"2X
-M_____XM<)"!F@7L0A0!W%HGH`X;$!0``BP`/MT`0#[:$,+`$```/ML!IP"@!
-M``"+GG`%```!P\:#M``````/ME,DB="#X`:#^`8/A70!``#VP@$/A&L!``"+
-M?"0@QD<4`/9'9B`/A(L$``"#?"0D``^$@`0``(M$)"3V0&4"#X2L````BU<@
-MA=(/A*$```"+2%B%R708BT<TB50D"(E$)`2)#"3H_/___^F"````BU0D((-Z
-M-`!T>(M,)"2#>6@`=0:#>6P`=&B+?"0@BV\TBU0D)(M":(7`=`B)Q_9"90%T
-M+8M,)"2+06R+ECP&``#'1"0(`0```(E4)`2)#"3_T+\`````A<!T!HN^/`8`
-M`(M'"(L7B50D"(EL)`2)!"3H_/___P,OBT<$@\<0A<!TWXN6.`H``('"0`@`
-M``^V0T+!X`@!PHL"HP````")PL'J$(M\)"2(5U/!Z!AFB4=(BY8X"@``@<)$
-M"```#[9#0L'@"`'"BQ*)%0`````/ML)FB4=,#[;&9HE'3HG0P>@0#[;`9HE'
-M4,'J&(A74HN6.`H``('"3`@```^V0T+!X`@!PHL"HP`````/ML!FB4=*Z3(#
-M``!IQ[`$``"+5"04C3P0#[9',X3`#X7,````B>@#AL0%``"+`,9`%`"+3"0@
-M]D%F$`^$_0(``(-\)"0`#X3R`@``#[9',XM<)"2(0TKV0V4"#X3=`@``@WD@
-M``^$TP(``(-[:`!U#X-[;`"0C70F``^$O@(``(M$)""+>#2+5"0DBT)HA<!T
-M"(G#]D)E`70PBTPD)(M!;(N6/`8``,=$)`@!````B50D!(D,)/_0NP````"%
-MP'0)BYX\!@``C78`BT,(BQ.)5"0(B7PD!(D$).C\____`SN+0P2#PQ"%P`^%
-M3P(``.O9/`(/A0D"```/MD]`BT<XB40D1`^V5"1'#[9$)$3!X!@)P@^V1"1%
-MP>`0"<(/MD0D1L'@"(G3"<.#X7^`^7%V-L9$)"D`@_L!=@L/MD=!@^`/B$0D
-M*<9$)"H`@_L"=@@/ME="B%0D*H/[`W9<#[9/0XA,)"OK5\9$)"D`@_L"=@L/
-MMD="@^`/B$0D*<9$)"H`QD0D*P"#^P=V,P^V1T>#P`@YPW8"B</&1"0J`(/[
-M#'8(#[973(A4)"J#^PUV"@^V3TV(3"0KZP7&1"0K`(GH`X;$!0``BP"`>!P`
-M=$.%VW0_QD`4((GH`X;$!0``BP`/MD`<.-AS`P^VV(GH`X;$!0``BP"+4#B%
-MTG0CC4=`B5PD"(E$)`2)%"3H_/___^L.B>@#AL0%``"+`,9`%"*`?"0I!'4.
-MB>@#AL0%``"+`,9`%`*+1"0@.7`8#X3]````@WPD)``/A/(```#V0&80=$8/
-MMD<SBU0D)(A"2O9"90)T-8M,)"`/ME$<B=@XTW8"B="$P'0ABUPD)(M+8(7)
-M=!8/ML"-5T")1"0(B50D!(D,).C\____@'PD*0MW60^V1"0I_R2%V`8``(M\
-M)"3&1V8!Z88```"`?"0J!'41@'PD*P)U"HM$)"3&0&81ZVZ+5"0DQD)F`NMD
-MBTPD),9!9A#K6HM<)"3&0V8+ZU"+?"0DQD=F!NM&BT0D),9`9@WK/#PH=1H/
-MMD-/@^@!B$-.B>@#AL0%``"+`,9`%('K'CP(=0S'!"00)P``Z/S___^)Z`.&
-MQ`4``(L`QD`4(8/$3%M>7UW#C70F`%575E.![)P```"+K"2P````#[>%B@L`
-M`&:)1"1^BT4`BX!``0``HP````!F)?\/9HF%B@L``&8[1"1^=6Z+10"+B%`!
-M``")#0````"+10")B%`!``"X`````/?!`/__``^$.@D``(E,)`3'!"0>````
-MZ/S___^+E"2P````B10DZ/S___^X`0```.D1"0``D(M%`(N`0`$``*,`````
-M9B7_#V:)A8H+``#K%8V-Y````(E,)%2-G30)``")7"10D(N%I`H``(L`HP``
-M```/MXV*"P``)?\/```/M]$YT'6P9H'Y_P\/A14(``#I(@@``(NU7`H``&:#
-M1"1^`0^W?"1^9CN]C@L``!G`(<=FB7PD?HN5I`H``(/"!`^WQXL4@HG7P>\0
-M]\<(````#X2O````BT4`BY!0`0``B14`````BT4`B9!0`0``]\(`__\`=&&`
-M?2L`=%OVQ@%U,KX`````]\(```$`=#WK(Y"-="8`#[?&C4@(NP$```")W]/G
-MA?IU$(U($-/CA=IU!^L8O@`````/M\9KP%R-G`5``0``A=MU(NL,@\8!#[9%
-M*V8Y\'>^BX0DL````(D$).C\____Z3H'``"+E"2P````B10DZ/S___^(0POI
-M(P<``(UV`(G19H'A_P]FB4PD3@^WV8E<)$1IP[`$``"+3`8@BUP&)(F,)(``
-M``")G"2$````BW0D1,'F`HN%Q`4```'PBP")1"1XA<`/A<0!``")3"00B5PD
-M%(E4)`R+7"1$B5PD"(E<)`3'!"3P````Z/S___]F@WU0``^$I08``,:$)(L`
-M````#[:\)(L```"-!+T`````B40D6`.%Q`4``(L0A=(/A$@!``!I][`$```#
-MM5P*``"+G10*```/MD(5B40D#(E\)`B)5"0$QP0D.0```.C\____BT0D6`.%
-MQ`4``(L`B00DZ/S___^+ABP$``"+EB@$``"+CB0$``"+MB`$``")1"04B50D
-M$(E,)`R)="0(B7PD!,<$)"P!``#H_/___XGXP>`&`<.+4S2)5"1(BU,PBTLL
-MBW,HBWLDBT,@B40D7(M#'(E$)&"+0QB)1"1DBT,4B40D:(M#$(E$)&R+0PR)
-MA"24````BT,(B80DD````(M#!(F$)(P```"+&XM$)$B)1"0XB50D-(E,)#")
-M="0LB7PD*(M4)%R)5"0DBTPD8(E,)""+?"1DB7PD'(M$)&B)1"08BU0D;(E4
-M)!2+C"24````B4PD$(N\))````")?"0,BX0DC````(E$)`B)7"0$QP0D5`$`
-M`.C\____@(0DBP````$/MH0DBP```&8[15`/@Q@%``#I=O[__XUV`/?'(```
-M``^$AP$``(M4)'B`>A2!#X57`0``QD(4(0^W0A[!X`(#A<0%``#'```````/
-MMTH>B<AFP>@%#[?`@^$?N@$```")T]/CB=GWT2&,A<@%``"+?"1X#[=/'HG(
-M9L'H!0^WP(/A']/B]](A5(54#[=''HE$)`2+1"10B00DZ/S___^#?U0`=!&)
-M^(/`5(E$)`2)+"3H_/___XM,)'@/MU$09H'ZA0`/A\(````/M\(/MH0%L`0`
-M`#S_#X2O````9H/Z?W<;#[;`:<`H`0```X5P!0``BT`L@'@$_P^5P.M7BUPD
-M>`^W0Q!F/8$`=R,/M\`/MH0HL`0``&G`%`T```.%J`4``(M`"(!X!/\/E<#K
-M)HM\)'@/MT<0#[:$*+`$``!IP+`````#A8P%``"+0%2`>`3_#Y7`A,!T,XM$
-M)'B)1"0$B2PDZ/S___^-E=P```"+A=P```"+3"1XB4@$B0&)402)C=P```#I
-MGP,``(M<)%2+4P2+1"1X@\`(B4,$BWPD>(E?"(E0!(D"Z7T#```/MT0D3F;!
-MZ`4/M\")1"1P#[=<)$Z)V8/A'[@!````T^")1"1TBU0D<(5$E50/A4H#``")
-M\`.%Q`4``(L`#[=0$&:!^H4`#X>?````#[?"#[:$!;`$```\_P^$C````&:#
-M^G]W&`^VP&G`*`$```.%<`4``(M`+`^V0`3K78GP`X7$!0``BP`/MT`09CV!
-M`'<@#[?`#[:$*+`$``!IP!0-```#A:@%``"+0`@/MD`$ZRF)\`.%Q`4``(L`
-M#[=`$`^VA"BP!```:<"P`````X6,!0``BT!4#[9`!#S_=`T/ML"`O`4V!0``
-M_W4[BUPD=(M,)'"%7(U4#X6``@``BWPD>,9'%`:)/"3H_/___\=$)`@`````
-MB7PD!(DL).C\____Z5<"```/MH0%-@4``&O`7(V$!4`!``"+E"2$````"Y0D
-M@````'0>]\<"````=1;'A"2``````````,>$)(0`````````]D`&`@^$60$`
-M`(N4)(````"+C"2$````B50D"(E,)`R)7"0$B00DZ/S___^+7"1TBTPD<(5<
-MC50/A=D!``"+?"1X@'\4@0^%BP````^W1Q[!X`(#A<0%``#'```````/MT\>
-MB<IFP>H%#[?2@^$?N/[____3P"&$E<@%```/MT<>B40D!(M$)%")!"3H_/__
-M_XE\)`2)+"3H_/___X-_5`!T$8GX@\!4B40D!(DL).C\____C97<````BX7<
-M````BTPD>(E(!(D!B5$$B8W<````Z4`!``"+A>0````[1"14=$^[`````(/#
-M`8L`.40D5'7UA-MT.[X`````BWPD5(D\).C\____C4CXBU<$B4<$B3B)4`2)
-M`CM,)'AU!;X!````@.L!==2)\(3`#X7E````BTPD5(M1!(M$)'B#P`B)002+
-M7"1XB4L(B5`$B0*+1"1TBWPD<`F$O90```#IM````(N4)(````"+C"2$````
-MB50D"(E,)`R)7"0$B00DZ/S___^+A>0````[1"14=$^[`````(/#`8L`.40D
-M5'7UA-MT.[X`````BTPD5(D,).C\____C4CXBWPD5(M7!(E'!(DXB5`$B0([
-M3"1X=06^`0```(#K`770B?"$P'4WBU0D>(!Z%(%T+8M,)%2+402+1"1X@\`(
-MB4$$BUPD>(E+"(E0!(D"BT0D=(M\)'`)A+V4````D`^W5"1^9CF5B@L```^%
-MWO?__V:!O8H+``#_#W0ABX6D"@``BP"C`````"7_#P``#[>5B@L``#G0#X6"
-M]___C87D````.87D````=$>)QHDT).C\____@^@(#[=('HG+9L'K!0^WVX/A
-M'[K^____T\(AE)V4````QT0D"`````")1"0$B2PDZ/S___\YM>0```!UNXDL
-M).C\____N`$```"!Q)P```!;7E]=PY"-="8`@^P<B5PD#(ET)!")?"04B6PD
-M&(M$)""+F#P%``"+0P2+*(DM`````/?%````D'1HBT,$B2CK88'#P`P``(L#
-MBY!0`0``B14`````BP.)D%`!``"%TG0W]\(````0=!F+`\>`4`$``````!"+
-M`XN`4`$``*,`````BP/'@%`!```!````B1PDZ/S___\!QX/&`8/^`G6AZPR^
-M`````+\`````ZYF)^(3`#Y7`A>T/E<()T`^VP(M<)`R+="00BWPD%(ML)!B#
-MQ!S#C;0F`````%575E.#["R+="1`BP:+@%`!``")1"04HP````"+!HM4)!2)
-MD%`!``#W1"04`/__``^$L`<``(!^*P`/A*8'``#&1"0K``^V;"0KC4T(N`$`
-M``")PM/BA50D%'4/C4T0T^"%1"04#X1H!P``@'PD*P-V'HL&!8`!``"-!.B+
-M`*,`````P>@3@^`!ZQR0C70F`(L&!8`!``"-!.B+`*,`````P>@3@^`!A,!T
-M&XDT).C\____B>C!X`:-!*B!C`:X"P`````(`(L6@'PD*P-V%8V$ZH`!``"+
-M`*,`````)0```0#K$XV$ZH`!``"+`*,`````)0```0"%P'0K@'PD*P-V$HV$
-MZH`!``#'`````0#I_`8``(V$ZH`!``#'`````0#IZ@8``(!^.0$/A=8%``"`
-M?"0K`W89BP8%@`$``(T$Z(L`HP````"#X`'K%XUV`(L&!8`!``"-!.B+`*,`
-M````@^`!A,`/A&0!``")Z,'@!HT<J(V$'KP+``"+5A2)1"0$B10DZ/S___^+
-MA!Z8"P``A<!T'8M0*(72=!;V0C("=1")!"3H_/___X3`#X4>`0``B>C!X`:-
-M!*B+A`:8"P``A<`/A(<```")1"0D@'@*``^$I0```,9$)",`B<>#QSB)/"3H
-M_/___XG#BT<$B5\$B3N)0P2)&/9#*`)U/8M3((72=!Z+ACP%``")5"0(B40D
-M!,<$)`4```#H_/___X!+*`*)7"0(QT0D!`8```"+1"0DB00DZ/S___^`1"0C
-M`0^V5"0CBT0D)#A0"G8NZY$/MD0D*\=$)`@!````B40D!(DT).C\____QP0D
-MH(8!`.C\____N@`M,0'K!;I`2TP`B>C!X`:-'*B-##.)D;P+``#'@<0+``#`
-M7P``#[9$)"N)PL'B!HV$@I`+``"-!`:)@<@+``"-A!Z\"P``BU84B40D!(D4
-M).C\____C70F`(!\)"L#=B^-%.T`````BP8%@`$```'0BP"C`````(L&!8`!
-M```!PHL"HP````#!Z`>#X`'K+8T4[0````"+!@6``0```="+`*,`````BP8%
-M@`$```'"BP*C`````,'H!X/@`83`=%N`?"0K`W8JC0SM`````(L&!80!```!
-MR(L`HP````"+%H'"A`$```'1#0```0")`>LQC0SM`````(L&!80!```!R(L`
-MHP````"+%H'"A`$```'1#0```0")`>L@@'PD*P-V&8L&!8`!``"-!.B+`*,`
-M````P>@2@^`!ZQ>+!@6``0``C03HBP"C`````,'H$H/@`83`#X3?`0``@'PD
-M*P-V*HT,[0````"+!@6``0```<B+`*,`````#0``!`"+%H'"@`$```'1B0'K
-M*(T,[0````"+!@6``0```<B+`*,`````#0``!`"+%H'"@`$```'1B0&)Z,'@
-M!HT$J(N$!I@+``"%P'0-B<6#>"@`=7_I9@$``(!\)"L#D'8YC13M`````(L&
-M!8`!```!T(L(B0T`````BP8%@`$``(T$`HD(BP8%@`$```'"BP*C`````.E;
-M`P``C13M`````(L&!8`!```!T(L(B0T`````BP8%@`$``(T$`HD(BP8%@`$`
-M``'"BP*C`````.DB`P``BT`H#[=(,@^WT?;&`0^%V0```(G']L("#X3.````
-MB<B#X/UFB4<RC4=PBU84B40D!(D4).C\____QD0D*P"`?Q\`#X1]````QD0D
-M*P`/MD0D*XM<ASR%VW1<BU,@A=)T'HN&/`4``(E4)`B)1"0$QP0D!0```.C\
-M____@$LH`HE<)`C'1"0$!@```(DL).C\____@'M/`'0=C78`B30DZ/S____'
-M!"0!````Z/S___^`>T\`=>:`1"0K`0^V5"0K.%<?=XC'1W!`2TP`QT=X````
-M`(E_?(U'<(M6%(E$)`2)%"3H_/___XUT)@"`?"0K`W8>BP8%@`$```^V5"0K
-MC130BP*C`````,'H"(/@`>L<BP8%@`$```^V5"0KC130BP*C`````,'H"(/@
-M`83`#X0-`0``@'PD*P-V'HL&!8`!```/ME0D*XT4T(L"HP````"#\`&#X`'K
-M'(L&!8`!```/ME0D*XT4T(L"HP````"#\`&#X`&$P`^$Q`````^V1"0KB<+!
-MX@:-A(*0"P``C00&B40D'(G"BT`(A<`/A)\```")1"08B="#P"R+5A2)1"0$
-MB10DZ/S___^+1"08@'@*`'14O0````")QX/'.(D\).C\____B<.+1P2)7P2)
-M.XE#!(D8BU,@A=)T'HN&/`4``(E4)`B)1"0$QP0D!0```.C\____@$LH`H/%
-M`8GJBT0D&#A0"G>VBU0D',="+("$'@#'0C0`````B5(XB="#P"R+5A2)1"0$
-MB10DZ/S___^`?"0K`W9D#[9<)"O!XP.+!@6``0```=B+$(D5`````(L&!8`!
-M``"-!`.)$(L&!8`!``"-!`.+`*,`````BP8%,`(``(T$`\<``````,<$)!`G
-M``#H_/___XL&!30"```!PXL#HP````#K8@^V7"0KP>,#BP8%@`$```'8BQ")
-M%0````"+!@6``0``C00#B1"+!@6``0``C00#BP"C`````(L&!5`"``"-!`/'
-M``````#'!"00)P``Z/S___^+!@54`@```<.+`Z,`````@$0D*P$/MD0D*SA&
-M*P^'7_C__XL&BX!0`0``B40D%*,`````BP:+5"04B9!0`0``]\(`__\`=!WI
-M&/C__XGHP>`&C02H@8P&N`L``````0#I_OC__[@`````@\0L6UY?7<.-="8`
-MC;PG`````%575E.#[%R+;"1P#[9$)'2(1"0S#[;0B50D-(G0P>`&C020`>B+
-MB)@+``")3"0\#[:XE@L``(M%`(!\)#,#=@S'@'`!``#$`0``ZPK'@'`!``"H
-M`0``B40D6`5T`0``B40D.(M<)%B+@W0!``"C`````(M,)#2#X0.[!P```-/C
-MB=X)QHM$)%B)L'0!``#'!"3H`P``Z/S____WTR'SBU0D6(F:=`$``(!\)#,#
-M=E"+3"0TBUPD6(V4B]`!``"+`J,`````@\@(B0*)R\'C`XM4)%B-A!H``@``
-MQP`X````QP0D$"<``.C\____BTPD6(V$&00"``#'``````#K4(M<)#2+1"18
-MC928T`$``(L"HP````"#R`B)`HM<)#3!XP.+5"18C80:``(``,<`.````,<$
-M)!`G``#H_/___XM,)%B-A!D$`@``QP``````@WPD/``/A(`(``"`?2L`=#*[
-M``````^VRXM4)#P/MD()T_BH`704QT0D"`$```")3"0$B2PDZ/S___^#PP$X
-M72MWTXM,)#SV008!=&V)3"0$B2PDZ/S___^+7"0TB5PD!(DL).C\____B=C!
-MX`:-!)B-%"B+@K0+``"I```0`'0+)?__[_^)@K0+``"+1"0\B40D!(DL).C\
-M____BT0D-,'@!HM4)#2-!)#'A`68"P```````.G1!P``BTPD/(!Y-`!T&HN%
-M^`D``(E,)`2)!"3H_/___XM<)#R`:S0!N/[___\/MDPD--/`B?L@PXA<)$,/
-MA)("``"+1"0TB40D!(DL).C\____BT0D-,'@!HM4)#2-!)"-%"B+@K0+``"I
-M```0`'0+)?__[_^)@K0+```/MDPD0XM<)#R(2PF`?2L`#X2N`0``QT0D3```
-M```/ML&)1"0@BU0D6('"``(``(E4)!P/MDPD3(A,)%,/MOF+1"0@B?G3^*@!
-M#X0^`0``C1R]`````(E<)"R)^,'@!@'8#[94)$.(E`66"P``@'PD4P,/AHT`
-M``"-'/T`````BT0D'`'8QP`X````QP0D$"<``.C\____BTPD6(V$&00"``"+
-M7"0@B1C'@7`!``#$`0``BU0D.(L"HP````")^8/A`[L'````T^.)W@G&B3+'
-M!"3H`P``Z/S____WTR'SBTPD.(D9BUPD6(M$)"R-E`/0`0``BP*C`````(/(
-M"(D"Z8@```"-'/T`````BT0D'`'8QP`X````QP0D$"<``.C\____BU0D6(V$
-M&@0"``"+3"0@B0C'@G`!``"H`0``BUPD.(L#HP````")^8/A`[L'````T^.)
-MW@G&BT0D.(DPQP0DZ`,``.C\____]],AWHM4)#B),HM,)%B-E+G0`0``BP*C
-M`````(/("(D"@T0D3`$/MD0D4X/``3A%*W8EZ8_^__^)'"3H_/___XUPX(M3
-M!(E#!(D8B5`$B0*#?@P`=!?K#+X`````BUPD/(/#+(M$)#PY6"QURX7V=#C&
-M1C(`@'TK`'0NN0````"Z`````(M<)#P/MD,)T_BH`70.#[;"B$P&0(!&,@&#
-MP@&#P0$X32MWW,=$)`@`````QT0D!($```"+1"0\B00DZ/S___^+1"0TP>`&
-MBU0D-(T$D,>$!9@+````````@'TK``^%YP,``.D!!0``QT0D"`````#'1"0$
-M!@```(M,)#R)#"3H_/___XM<)#2)7"0$B2PDZ/S___^)V,'@!HT$F(T4*(N"
-MM`L``*D``!``=`LE___O_XF"M`L``(M$)#R#P"R+5"0\.4(L#X0>`@``B40D
-M%(M,)!2)#"3H_/___XU8X(E<)$2-4`@Y4`@/A-(!``"#PRB)7"08BT0D&(D$
-M).C\____C5CX@'LE#74:C9#\````BT,LBP"+0!2)5"0$B00DZ/S___^+$XM#
-M!(E"!(D0@'M/`'0:B2PDZ/S____'!"0!````Z/S___^`>T\`=>:+0R"%P`^$
-M.@$``,=`8`````"`>T\`#X2D````9H-]4``/A)D```"_`````)"-="8`C02]
-M``````.%Q`4``(LPA?9T;0^W1A!F.T,<=6-F/84`=UT/M\"`O"BP!```_W10
-MBU4`#[=&'F;!Z`4/M\"-!(4``P``B8)P`0``BU4`#[=.'H/A'[@!````T^")
-M@G0!``#&1A0AQT0D"`````")="0$B2PDZ/S___^-M@````"#QP$/MT50.?@/
-MCW'____V0R@$=1^)+"3H_/___XM#(,=$)`@!````B40D!(DL).C\____BT,@
-M#[90`@^V0`&)5"0(B40D!,<$)$8```#H_/___XM#((N5/`4``(E$)`B)5"0$
-MQP0D`0```.C\____BT,@BY4\!0``B40D"(E4)`3'!"0&````Z/S____'0R``
-M````BU0D/(!J"@&+3"1$@&DP`8E<)`2)+"3H_/___XM$)!B+7"1$.4,H#X4U
-M_O__BU0D/(!J'`&+3"1$B4PD!(DL).C\____BT0D%(M<)#PY0RP/A>;]__^+
-M1"0\@\`XBU0D/#E".`^$'P$``+X`````B<>)/"3H_/___XG#@'A/`'0VC48!
-M@?Y_EI@`=@2)QNLGB<:)+"3H_/___\<$)`$```#H_/___X![3P!T"X/&`8'^
-M@9:8`'7;BT,@A<`/A*8```#'0&``````]D,H!'4?B2PDZ/S___^+0R#'1"0(
-M`0```(E$)`2)+"3H_/___XM3(`^V@I@````/ME("C02`#[:$`@`````/ME4B
-M#[9-(8E$)`R)5"0(B4PD!,<$)%@```#H_/___XM#((N5/`4``(E$)`B)5"0$
-MQP0D`0```.C\____BT,@BY4\!0``B40D"(E4)`3'!"0&````Z/S____'0R``
-M````BTPD/(!I"@&)7"0$B2PDZ/S___^+7"0\.7LX#X7H_O__BT0D/(E$)`2)
-M+"3H_/___XM$)#3!X`:+5"0TC020QX0%F`L```````#I#_S__\=$)$@`````
-M#[9,)$.)3"0HBUPD6('#T`$``(E<)"0/MGPD2(GX#[;`B40D5(M$)"@/MDPD
-M5-/XJ`%U#(G[.%PD,P^%Q@```(GX/`-V8XM4)%C'@G`!``#$`0``BTPD.(L!
-MHP````"+3"14@^$#C0Q)NP<```#3XXG>"<:+1"0XB3#'!"3H`P``Z/S____W
-MTR'SBU0D.(D:BTPD5(M<)"2-%(N+`J,`````@\@(B0+K78M$)%C'@'`!``"H
-M`0``BU0D.(L"HP````"+3"14@^$#C0Q)NP<```#3XXG>"<:),L<$).@#``#H
-M_/____?3(=Z+3"0XB3&+7"14BT0D)(T4F(L"HP````"#R`B)`H-$)$@!C4<!
-M.$4K#X<`____@\1<6UY?7<.-M"8`````C;PG`````%575E.#[!R+?"0PBW0D
-M-`^V;RN)Z(3`="P/ME8)NP````#VP@%T$^L<C;0F`````(G0B=G3^*@!=1"#
-MPP&)Z#C#=>WK!;L`````]D8(`G4(C48X.48X=6J)-"3H_/___X3`=$^)/"3H
-M_/___XG!A<!T4(M6/(E&/(U&.(D!B5$$B0J`1@H!B7$LQD$D!<9!)0#&04T/
-MQT0D#`$```#'1"0(`0```(E,)`2)-"3H_/___^L/#[;#B40D!(D\).C\____
-M@\0<6UY?7<.-M@````!55U93@^P,BVPD(`^V?"0DB?@/ML")1"0(B<;!Y@*[
-M`````,<$)!`G``#H_/___XGZ@/H#=AJ+10`%T`$```'PBP"C`````,'H%(/@
-M`>L9D(M%``70`0``C00&BP"C`````,'H%(/@`83`=0J#PP%F@?LL`76MBT0D
-M"(E$)`2)+"3H_/___XDL).C\____BT0D",'@!HM4)`B-!)`!Z/:`E0L```%T
-M$HN`F`L``(E$)`2)+"3H_/___X/$#%M>7UW#ZPV0D)"0D)"0D)"0D)"055=6
-M4X/L'`^V1"0TB$0D&HM\)#`/MO")\,'@!HT$L(NL!Y@+``"%[0^$J@$``+C^
-M____B?'3P(1%"0^%F`$``(U%+#E%+'4-@'T*`'4HB?;I`P,```^V1"0:B<+!
-MX@:-A(*0"P``C00'B00DZ/S____IX@(``,9$)!L`C74XB?:)-"3H_/___XG#
-MBT8$B5X$B3.)0P2)&(![)0`/A1\!```/MT,<@[R'L`(```!U$8-[(``/A.@`
-M``"-M"8`````#[=#'(N$A[`"``"#>'``#X2M````QH.T``````^V4R2)T(/@
-M!H/X!G4V]L(!=#'&0R8%QD,G!`^V0TV+4S"+2RR)7"0,B40D"(E4)`2)#"3H
-M_/___^FF````C;8`````#[93)(G0@^`&@_@$=2+VP@%T'<9#)@/&0R<$B5PD
-M!(D\).C\____ZW>-M"8`````#[93)(G0@^`&@_@&=6+VP@%U7<9#)P;&0R8%
-M9L>#E```````B5PD!(D\).C\____ZSZ+0R"+ESP%``")1"0(B50D!,<$)`0`
-M``#H_/___^L?#[=#'(N7/`4``(E$)`B)5"0$QP0D`@```.C\____D(!$)!L!
-M#[9$)!LX10H/AH4!``#IJ/[__XTLM0````"[`````,<$)!`G``#H_/___X!\
-M)!H#=AF+!P70`0```>B+`*,`````P>@4@^`!ZQ>0BP<%T`$```'HBP"C````
-M`,'H%(/@`83`=0J#PP%F@?LL`76PB70D!(D\).C\____B3PDZ/S___^)\,'@
-M!HT$L(NT!Y@+``"%]@^$^0```(!_*P!T-+L`````C;8`````#[;+#[9&"=/X
-MJ`%T%,=$)`@`````B4PD!(D\).C\____@\,!.%\K=]</MD0D&HG"P>(&C82"
-MD`L``(T$!XE&&(U&+#E&+'4JC48X.48X=2+K<HD<).C\____C6C@BU,$B4,$
-MB1B)4`2)`H-]#`!T%>L.O0````"-7BR-M@`````Y7BQUS87M=%_&13(`@'\K
-M`'15N@````"[`````(UV``^V1@F)T=/XJ`%T#@^VPXA4!4"`13(!@\,!@\(!
-M.%<K=B;KW/9&!@%T#HET)`2)/"3H_/___^L0QT0D!`````")-"3H_/___X/$
-M'%M>7UW#55=64X/L#(M\)""+'XMO*`^V<RN)\(3`=%:-@Y`+``"Y`````#GX
-M=1WK19"-="8`#[;!B<+!X@:-A(*0"P``C00#.?AT"8/!`8GP.,%UX8#Y`W8A
-MBP,%T`$```^VT8T4D(L"HP````#!Z!2#X`'K'[D`````BP,%T`$```^VT8T4
-MD(L"HP````#!Z!2#X`&$P'05#[;!B6PD"(E$)`2)'"3H_/___^L/#[;!B40D
-M!(D<).C\____@\0,6UY?7<.055=64X/L'(M<)#2+1"0PB40D%(MX5(LW]D<(
-M$'0$QD`U!HM4)!0/MD(U/`%T=3P!<AD\!`^$E@```#P&C70F``^%.@,``.FG
-M`0``BTPD%,9!-0&)3"0$B30DZ/S____&0Q2!@$\("(-[5`!T#XU#5(E$)`2)
-M-"3H_/___XV6W````(N&W````(E8!(D#B5,$B9[<````B30DZ/S____IW0(`
-M`(!G"/>+1"04@$`V`<9`-0#&0Q0"B5PD!(DT).C\____B30DZ/S____IL`(`
-M``^V1PB#X/>#R!"(1PB+3"04BY&8````C4(!B8&8````@_H"#X?Y````@WM4
-M`'0/C4-4B40D!(DT).C\____C9;<````BX;<````B5@$B0.)4P2)GMP```"+
-M1"04@'@F`'4+@'\*`'4BZ:0```#'1"0(`````,=$)`0"````B3PDZ/S____I
-M)@(``,9$)!L`C6\XB2PDZ/S___^)PXM%!(E=!(DKB4,$B1B+4R"%TG0>BX8\
-M!0``B50D"(E$)`3'!"0%````Z/S___^`2R@"B5PD",=$)`0&````B3PDZ/S_
-M__^`>T\`=!J)-"3H_/___\<$)`$```#H_/___X![3P!UYH!$)!L!#[94)!LX
-M5PIW@8M,)!2)#"3H_/___^F.`0``@&<(]XM$)!3'@)@`````````@WM4`'0/
-MC4-4B40D!(DT).C\____C9;<````BX;<````B5@$B0.)4P2)GMP```#'1"0(
-M`````,=$)`0&````B3PDZ/S___^-1S@Y1S@/A)8```")Q8VT)@````")+"3H
-M_/___XG#BT`@A<!T9\=`8`````")-"3H_/___XM#(,=$)`@!````B40D!(DT
-M).C\____BT,@BY8\!0``B40D"(E4)`3'!"0!````Z/S___^+0R"+ECP%``")
-M1"0(B50D!,<$)`8```#H_/___\=#(`````")7"0$B30DZ/S___\Y;S@/A7/_
-M__^+5"04B50D!(DT).C\____QT<H`````(L&BY!8`0``B14`````A=)T"(L&
-MB9!8`0``]D<&`71<@'XK`'0AN0````#V1PD!=`SK%`^V1PG3^*@!=0^#P0$X
-M3BMW[NL%N0`````/MMF)7"0$B30DZ/S___^)?"0$B30DZ/S___^)V,'@!HT<
-MF,>$'I@+````````B?:#Q!Q;7E]=PY"-M"8`````@^PLB5PD'(ET)"")?"0D
-MB6PD*(M\)#2+="0PBT8LB40D&(LH#[=/'HG(9L'H!0^WV(/A'[@!````T^"%
-M1)U4#X7O`P``BU4`C02=``,``(F"<`$``(M%`(N0=`$``(D5`````,9'%"&+
-M1R0E____`#WA`0\`=2&)/"3H_/___\=$)`@`````B7PD!(DL).C\____Z9P#
-M```/MT\>@^$?N`$```#3X(7"=!:)/"3H_/___XDL).C\____C;8`````#[:&
-MM````#P$#X=E`P``#[;`_R2%"`<``,:&M`````''1"0(`0```(E\)`2+5"08
-MB10DZ/S____I-P,``,:&M`````+'1"0("````(E\)`2+1"08B00DZ/S____I
-M$P,``,:&M`````.)="0(QT0D!"$```"+5"08B10DZ/S___^+5C"%TG0M#[9&
-M3<=$)!``````QT0D#`$```")1"0(B50D!(M$)!B)!"3H_/___^G``@``BU0D
-M&`^V0@G'1"0(`````(E$)`2)+"3H_/___^F?`@``QH:T````!(-^,`!T2(ET
-M)`C'1"0$(0```(M$)!B)!"3H_/___P^V1DV+5C#'1"00`````,=$)`P"````
-MB40D"(E4)`2+5"08B10DZ/S____I2@(``,=$)`@`````QT0D!"$```"+1"08
-MB00DZ/S___^+5"08#[9""<=$)`@!````B40D!(DL).C\____Z0T"``"`?B;_
-M=!V)="0(QT0D!`8```"+1"08B00DZ/S____IZ@$``(ET)`C'1"0$!@```(M4
-M)!B)%"3H_/___XM.((7)=!*+402-0@&)002#^@4/AKD!``#&1B<!QD8F`(!^
-M3P!T(8VT)@````")+"3H_/___\<$)`$```#H_/___X!^3P!UYH-^,`")]G04
-MBU8(BT8,B4($B1"+1C"`:#`!ZQ.+5C2%TG0,#[9&3<=$@CP`````BQ:+1@2)
-M0@2)$(M$)!B`:`H!BY;D````A=)T&P^VAMD```#'1"0(`0```(E$)`2)%"3H
-M_/___XM6,(72=!@/MD9-QT0D"`$```")1"0$B10DZ/S___^+1B"%P`^$A@``
-M`,=`8`````")+"3H_/___XM&(,=$)`@!````B40D!(DL).C\____BT8@#[90
-M`@^V0`&)5"0(B40D!,<$)$8```#H_/___XM&((N5/`4``(E$)`B)5"0$QP0D
-M`0```.C\____BT8@BY4\!0``B40D"(E4)`3'!"0&````Z/S____'1B``````
-MB70D!(DL).C\____BU0D&(!Z!?]T7KX`````@'H*`'0XO@````"+7"08@\,X
-MC78`B1PDZ/S___^+4P2)0P2)&(E0!(D"@'@F_W4.@\8!B?"+5"08.$(*=]>)
-M\(M4)!@X0@IW$,9"!?^)5"0$B2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0L
-MPY"-M"8`````55=64X'LC````(N\)*````"+1U2)1"1XBRB+A:0*``"+`(E$
-M)'R)?"0$B2PDZ/S___^`?S8!=@3&1S4$C5\4.5\4#X2X`0``B1PDZ/S___^)
-M1"1TBT<4BU0D=(E0!(D"B5H$B5<4A=(/A)P#```/MW(>BTPD>(M!&`^V0`0/
-MME4I#[9-(@^V72&)="04B40D$(E4)`R)3"0(B5PD!,<$)*P!``#H_/___XM$
-M)'0/MT`>B40D6&GPL`0```.U7`H``(N=%`H``(M4)'2)%"3H_/___XN.+`0`
-M`(E,)$B+EB@$``"+CB0$``"+MB`$``"+1"1T#[=`'HE$)`2+1"1(B40D%(E4
-M)!")3"0,B70D",<$)-P!``#H_/___XM4)%C!X@8!TXM+-(E,)$B+4S"+2RR+
-M<RB+0R2)1"1<BT,@B40D8(M#'(E$)&2+0QB)1"1HBT,4B40D;(M#$(E$)'"+
-M0PR)A"2(````BT,(B80DA````(M#!(F$)(````"+&XM$)$B)1"0XB50D-(E,
-M)#")="0LBU0D7(E4)"B+3"1@B4PD)(M$)&2)1"0@BU0D:(E4)!R+3"1LB4PD
-M&(M$)'")1"04BY0DB````(E4)!"+C"2$````B4PD#(N$)(````")1"0(B5PD
-M!,<$)%0!``#H_/___V:#?5``=4;IY0$``)"+5"1XBT(8#[9`!`^V52D/MDTB
-M#[9=(<=$)!3___\`B40D$(E4)`R)3"0(B5PD!,<$)*P!``#H_/___^D%`@``
-MO@````"-C30)``")3"10C87<````B40D3(VT)@`````/M\;!X`(#A<0%``"+
-M&(7;#X1A`0``#[=#$&8Y1R0/A5,!```/MY6*"P``.50D?'1%@\(!#[>%C@L`
-M`#G"&<`APHN%I`H``(/`!(L$D*D```@`=1QF)?\/9CGP=1,Y7"1T=1.)+"3H
-M_/___^EU`0``.U0D?'6[#[=#$&8]A0")]@^'\0````^WP("\!;`$``#_#X3@
-M````BU0D>(!Z-``/A=(```#V0@8!#X3(````BU4`#[=#'F;!Z`4/M\"-!(4`
-M`P``B8)P`0``#[=+'H/A'[H!````B=#3X(G!BT4`B8AT`0``#[=#'L'@`@.%
-MQ`4``,<```````^W2QZ)R&;!Z`4/M\")1"1(@^$?B=#3X(G!]]&+1"1((8R%
-MR`4```^W2QZ)R&;!Z`4/M\"#X1_3XO?2(52%5#E<)'1T(HL#BU,$B5`$B0*+
-MA=P```")6`2)`XM4)$R)4P2)G=P````/MT,>B40D!(M,)%")#"3H_/___X!O
-M*0&#Q@%F.750#X=\_O__BT0D>/9`!@%T5XM,)'2+$8M!!(E"!(D0B4PD!(D\
-M).C\____ZSN+5"1XBT(8#[9`!`^V52D/MDTB#[9=(<=$)!3___\`B40D$(E4
-M)`R)3"0(B5PD!,<$)*P!``#H_/___X'$C````%M>7UW#55=64X/L;(N,)(``
-M``"+E"2(````B50D8(N$)(P```")1"1DBP&)1"0X#[>$)(0```#!X`*+7"0X
-M`X/$!0``BSAF@7\DX0%U-P^V1R:#Z!$\`7<LBW$HB70D0,=$)#P`````"U0D
-M9'5OBT0D0,9`-0#'1"0\`````.M=D(UT)@"+7"0XBY-P!0``N-@F`0!F@7\0
-MA0!W%@^W1Q"+="0X#[:$!K`$``!IP"@!```!PHE4)#S'1"1``````(M$)&`+
-M1"1D=1.+1"0\QH"T`````,=$)$``````@'\4@74$@&$(]XM$)&`+1"1D#X7@
-M````QD<4`/9'9B`/A`H&``"+1TB%P`^$_P4``(G#]D!E`G0ABTA8A<ET&HM7
-M-(72=!.+1R")1"0(B50D!(D,).C\____BTPD.(N1.`H``('"0`@``(MT)#P/
-MMD9"P>`(`<*+`J,`````B<+!ZA"(4U/!Z!AFB4-(BY$X"@``@<)$"```#[9&
-M0L'@"`'"BQ*)%0`````/ML)FB4-,#[;&9HE#3HG0P>@0#[;`9HE#4,'J&(A3
-M4HN1.`H``('"3`@```^V1D+!X`@!PHL"HP`````/ML!FB4-*Z3X%``"-M@``
-M```/MT<>:<"P!```BU0D.`."7`H``(E$)$2)Q8'%(`0``(!_%(!U"L9'%"&-
-MM@````"#?"0\``^$T0```(M<)#R+4R"%TG1>BW<@B70D5`^V@I@````/ME("
-MC02`#[:,`@````"+1"0X#[98(@^V<"&+1"1@BU0D9(E$)!2)5"08BU0D5(E4
-M)!")3"0,B5PD"(ET)`3'!"0,`@``Z/S____IS````(M?((E<)%B+="0\#[9V
-M38ET)#"+01@/MD@$BT0D.`^V6"D/MG`B#[90(8E4)`2+1"1@BU0D9(E$)!R)
-M5"0@BT0D6(E$)!B+5"0PB50D%(E,)!")7"0,B70D",<$)$`"``#H_/___^MD
-M@WPD0`!T78M?((E<)%R+01@/MD@$BW0D.`^V7BD/MG8BBT0D.`^V0"&)1"0$
-MBT0D8(M4)&2)1"08B50D'(M4)%R)5"04B4PD$(E<)`R)="0(QP0D?`(``.C\
-M____C;0F`````(M%#(M5"(M-!(M=``^W=QZ)1"04B50D$(E,)`R)7"0(B70D
-M!,<$)+@"``#H_/___XM,)$3V02(!#X3"````C5\\B5PD2(MW5(ET)%"+0P0/
-MME,!B40D"(E4)`3'!"1<````Z/S___^`?SP`#X0_`0``QD0D3P`/MG0D3XT$
-M=L'@`HM4)$B+2@@!P8G#BU0D4`-:"(M#"(E$)#2+`XM3!(E$)"B)5"0LBVD(
-MBUD$BPF+5"0TB50D'(M$)"B+5"0LB40D%(E4)!B);"00B4PD"(E<)`R)="0$
-MQP0DZ`(``.C\____@$0D3P$/ME0D3XM,)$@X$0^&MP```.EX____B?:+7"1$
-M@'LG``^)H@````^W5QZ)T&;!Z`4/M\`/M]*)1"0(B50D!,<$)'@```#H_/__
-M_XMT)#B+AM0%``"+EM`%``"+CLP%``"+GL@%``")1"00B50D#(E,)`B)7"0$
-MQP0DCP```.C\____#[=''HE$)`3'!"2K````Z/S___^+%@^W1QYFP>@%#[?`
-MC02%``,``(F"<`$``(L6#[=/'H/A'[@!````T^")@G0!``")]F:!?R3A`74<
-M#[9')H/H$3P!=Q&+1"1`B00DZ/S____I]`$```^V5"1C]L(!#X3``0``BT<D
-M)?___P`]X0$.``^$K0$``(M,)#B+D3@*``"!PD`(``"+7"0\#[9#0L'@"`'"
-MBS*)-0````"+D3@*``"!PD0(```/MD-"P>`(`<*+*HDM`````(N1.`H``('"
-M2`@```^V0T+!X`@!PHL:B1T`````BY$X"@``@<),"```BTPD/`^V04+!X`@!
-MPHL"HP````")1"00B5PD#(EL)`B)="0$QP0DO````.C\____]D=F(`^$S0``
-M`(M/2,9!9A#&1Q0@B?#!Z!"(05.)\,'H&&:)04B)WL'F"(GH#[;0C0069HE!
-M3(G>9H'F`/^)Z`^VU(T$%F:)04Z)VL'J$,'B"(GHP>@0#[;``<)FB5%0BUPD
-M.(N3.`H``('"3`@``(MT)#P/MD9"P>`(`<*+`J,`````#[;`9HE!2@^W44P/
-MMUE.#[=)4`^WP(E4)!")7"0,B4PD"(E$)`3'!"39````Z/S___^+1"0XBY`X
-M"@``@<)`"```#[9&0L'@"`'"QP(`````ZV%F@7\DX0%U(0^V1R:#Z!H\`7<6
-MQP0D(`,``.C\____QD<4(>L\C70F`(E\)`2+5"0XB10DZ/S____K)H32>2*+
-M3"0XBP&+B%@!``")#0````"%R70,BUPD.(L#B8A8`0``@\1L6UY?7<-3@^P(
-MBUPD%(M,)!`/MD,D.4L8=4$\"'16/"AT4CRHD'1-/(AT23P*=$4\*HUT)@!T
-M/3RJ=#D\BG0UBX'<````B5@$B0.-@=P```")0P2)F=P```#K&8N1X````(F9
-MX````(V!W````(D#B5,$B1J)#"3H_/___X/$"%O#C70F`(/L#(M$)!2)1"0$
-MBT0D$(D$).C\____@\0,PY"-="8`4X/L6(M<)&"-1"1*B40D-(U$)$R)1"0P
-MC40D1(E$)"R-1"1&B40D*(U$)%")1"0DC40D4HE$)""-1"13B40D'(U$)$Z)
-M1"08C40D5(E$)!2-1"1(B40D$(U$)%6)1"0,C40D5HE$)`B-1"17B40D!`^W
-M0R2)!"3H_/___P^V1"17B40D"`^V1"16B40D!(U$)$")!"3H_/___\=$)`P!
-M````#[9$)%=IP"@!``")1"0(BT,0B40D!(V#6`4``(D$).C\____QT0D#`$`
-M```/MD0D56G`L````(E$)`B+0Q")1"0$C8-T!0``B00DZ/S____'1"0,`0``
-M``^V1"16:<`4#0``B40D"(M#$(E$)`2-@Y`%``")!"3H_/___\=$)`P!````
-M#[=$)%#!X`*)1"0(BT,0B40D!(V#K`4``(D$).C\____QT0D#`$````/MT0D
-M2&O`<(E$)`B+0Q")1"0$C8-8!@``B00DZ/S____'1"0,`0````^V1"14#[=4
-M)$@/K\*-!$#!X`*)1"0(BT,0B40D!(V#"`8``(D$).C\____QT0D#`$```#'
-M1"0(``(``(M#$(E$)`2-@R0&``")!"3H_/___P^V1"17B40D#,=$)`@`"```
-MBT,0B40D!(V#``<``(D$).C\____QT0D#`$````/MD0D4XT$@,'@`HE$)`B+
-M0Q")1"0$C8.0!@``B00DZ/S____'1"0,`0```,=$)`B@````BT,0B40D!(V#
-MK`8``(D$).C\____QT0D#`$````/MD0D4FG`F````(E$)`B+0Q")1"0$C8/(
-M!@``B00DZ/S____'1"0,`0````^W1"1.C01`P>`#B40D"(M#$(E$)`2-@^0&
-M``")!"3H_/___\=$)`P!````#[=$)%`!P(E$)`B+0Q")1"0$C8,8"0``B00D
-MZ/S____'1"0,`0````^V1"17`<")1"0(BT,0B40D!(V#0`D``(D$).C\____
-MQT0D#`$````/MD0D50'`B40D"(M#$(E$)`2-@V@)``")!"3H_/___\=$)`P!
-M````#[9$)%8!P(E$)`B+0Q")1"0$C8.0"0``B00DZ/S____'1"0,`0````^V
-M0R8!P(E$)`B+0Q")1"0$C8.X"0``B00DZ/S____'1"0,`0````^W1"1&P>`%
-MB40D"(M#$(E$)`2-@W0&``")!"3H_/___\=$)`P!````BT0D0(E$)`B+0Q")
-M1"0$C8/@"0``B00DZ/S____'1"00`0```,=$)`Q`````#[=$)%#!X`:)1"0(
-MBT,0B40D!(V#_`D``(D$).C\____QT0D$`$```#'1"0,``$``,=$)`@`&0``
-MBT,0B40D!(V#(`H``(D$).C\____QT0D$`$```#'1"0,@`````^W1"10:<"P
-M!```B40D"(M#$(E$)`2-@T0*``")!"3H_/___\=$)!`!````QT0D#`0````/
-MMT0D3,'@`HE$)`B+0Q")1"0$C8-H"@``B00DZ/S____'1"00`0```,=$)`P$
-M````#[=$)$K!X`*)1"0(BT,0B40D!(V#C`H``(D$).C\____QT0D$`$```#'
-M1"0,"`````^V1"13P>`+B40D"(M#$(E$)`2-@[`*``")!"3H_/___\=$)!`!
-M````QT0D#`@```#'1"0(```(`(M#$(E$)`2-@]0*``")!"3H_/___\=$)!`!
-M````QT0D#`@````/MT0D3FG`C`$``(E$)`B+0Q")1"0$@</X"@``B1PDZ/S_
-M__^X`````(/$6%O#C78`@^PLB5PD'(ET)"")?"0DB6PD*(ML)#"+10")1"04
-MC5TLB1PDZ/S___^)QHU0X(E4)!B+1"04B00DZ/S___^)QXM%,(EU,(M4)!B)
-M6B")0B2),+@!````A?\/A(````#&1R3AQD<E`<9')A"`3R<!BU0D-(N"G```
-M`(E'2(M'3(E0'(G0!9````")1SC&1Q7,BU0D&`^V0C-FB4<0BT4`B4<8QT<@
-MD````(M$)#2)1S3'1VS0%@``QT0D!`````"-1SR)!"3H_/___XE\)`2+5"04
-MB10DZ/S___^X`````(M<)!R+="0@BWPD)(ML)"B#Q"S#C;8`````C;PG````
-M`%575E.#[!R+="0PQT0D&`````"+5"08#[:$,C8%```\_P^$S`````^VT&O"
-M7(V,!D`!``")3"04@+P&2@$````/A*T```"_`````(E$)!"-K`9X`0``C80&
-M0`$``(E$)`R)+"3H_/___XG#BT0D$`'PBY!\`0``B9A\`0``B2N)4P2)&HM#
-M((7`=!Z)1"0(BX8\!0``B40D!,<$)`4```#H_/___X!+*`*)7"0(QT0D!`(`
-M``"+1"04B00DZ/S___^`>T\`=!J)-"3H_/___\<$)`$```#H_/___X![3P!U
-MYH/'`8GZBTPD##A1"@^';O___X-$)!@!@WPD&`0/A1#___^)-"3H_/___X/$
-M'%M>7UW#C;8`````C;PG`````%575E.#['R+A"20````QD`Y`,9`.`#&0#<`
-MQH"Q#````(G"@<*0"P``N`````")]L8$$`"#P`$]$`$``'7RBX0DD`````7<
-M````BY0DD````(F"W````(F"X````(G0!>0```")@N0```")@N@```"!PNP`
-M``")5"1$BXPDD````(F1[````(F1\````(G/@<?T````B;GT````B;GX````
-M@<'\````B4PD3(N<))````")B_P```")BP`!``"!PP0!``")7"10B[0DD```
-M`(F>!`$``(F>"`$``(GU@<44`0``B:X4`0``B:X8`0``@<8<`0``B70D2(N$
-M))````")L!P!``")L"`!```%#`$``(E$)%2+E"20````B8(,`0``B8(0`0``
-MC40D=HE$)#2-1"1XB40D,(U$)&B)1"0LC40D;HE$)"B-1"1ZB40D)(U$)'")
-M1"0@C40D<8E$)!R-1"1LB40D&(U$)'.)1"04C40D:HE$)!"-1"1RB40D#(U$
-M)'2)1"0(C40D=8E$)`0/MT(DB00DZ/S___\/MD0D=8N,))````"(02X/MD0D
-M=(A!+P^V1"1RB('9````#[=$)'IFB4%0#[=$)'AFB8&,"P``#[=$)':#Z`%F
-MB8&."P``#[=$)&IFB4$Z#[=!)&8]@)%T"F8]@)0/A:T*``"+G"20````QD,U
-M!,9#*P3&0S9`QD,T`,:#U@````G&0RP`B=@%6`4``(D$).C\____B<*)@W`%
-M```/MD0D=6G`*`$``(7`=`O&`@"#P@&#Z`%U]8N$))`````%=`4``(D$).C\
-M____B<*+M"20````B8:,!0``#[9$)')IP+````"%P'0+Q@(`@\(!@^@!=?6+
-MA"20````!9`%``")!"3H_/___XG"BX0DD````(F0J`4```^V1"1T:<`4#0``
-MA<!T"\8"`(/"`8/H`77UBX0DD`````6L!0``B00DZ/S___^)PHN,))````")
-M@<0%```/MT0D>L'@`H7`=`O&`@"#P@&#Z`%U]8N$))`````%)`8``(D$).C\
-M____BYPDD````(F#/`8``(G8!0@&``")!"3H_/___XG#B[0DD````(F&(`8`
-M`(GP!5@&``")!"3H_/___XG"B89P!@``9H-\)&H`=$:Y`````(E:1`^V1"1S
-MB$(\B[0DD````(N&\````(F6\````(MT)$2),HE"!(D0#[9$)'.-!$"-'(.#
-MPG"#P0%F.4PD:G>_BX0DD`````5T!@``B00DZ/S___^)PHN$))````")D(P&
-M``!F@WPD;@!T,+D`````QD((`(N<))````"+@_@```")D_@```").HE"!(D0
-M@\(@@\$!9CE,)&YWU8N$))`````%D`8``(D$).C\____B<*+M"20````B8:H
-M!@``@'PD<0!T,[D`````BYPDD````(N#``$``(F3``$``(MT)$R),HE"!(D0
-M@\(4@\$!#[9$)'%F.<AWTHN$))`````%K`8``(D$).C\____B<*+A"20````
-MB9#$!@``C8J@````BYPDD````(N#"`$``(F3"`$``(MT)%"),HE"!(D0@\(4
-M.<IUVXG8!<@&``")!"3H_/___XG"B8/@!@``@'PD<`!T,KD`````BYPDD```
-M`(N#&`$``(F3&`$``(DJB4($B1"!PI@```"#P0$/MD0D<&8YR'?3BX0DD```
-M``7D!@``B00DZ/S___^)PHNT))````")AOP&``!F@WPD;`!T,+D`````BZPD
-MD````(N%$`$``(F5$`$``(M<)%2)&HE"!(D0@\(8@\$!9CE,)&QWU8!\)'4`
-M=$^[`````(NT))````"!Q@`'``")-"3H_/___P^WTXNL))````")A)48!P``
-MBY4@`0``B84@`0``BTPD2(D(B5`$B0*#PP$/MD0D=68YV'?#BX0DD`````48
-M"0``B00DZ/S___^+G"20````B8,P"0``B8,T"0``#[=$)'IFB8,Z"0``#[?`
-MB40D!(G8!30)``")!"3H_/___XG8!4`)``")!"3H_/___XF#6`D``(F#7`D`
-M``^V1"1U9HF#8@D```^WP(E$)`2)V`5<"0``B00DZ/S___^)V`5H"0``B00D
-MZ/S___^)@X`)``")@X0)```/MD0D<F:)@XH)```/M\")1"0$B=@%A`D``(D$
-M).C\____B=@%D`D``(D$).C\____B8.H"0``B8.L"0``#[9$)'1FB8.R"0``
-M#[?`B40D!(G8!:P)``")!"3H_/___XG8!;@)``")!"3H_/___XF#T`D``(F#
-MU`D```^V0R9FB8/:"0``#[9#)HE$)`2)V`74"0``B00DZ/S___^)V`7@"0``
-MB00DZ/S___^)PHF#^`D```^V1"1T:<!T!```B<&!P71%``!T#XG0B<K&``"#
-MP`&#Z@%U]8NT))````"+AO@)``")"(N6^`D```^V1"1TB$($#[9$)'2)1"0(
-MB4PD!(N&^`D``(D$).C\____OP````"`?B8`#X20````O@`````/M\YKR5R+
-MK"20````C;P-0`$``(T4*8GPB$<$QD<%`(FJ0`$``,9'"@#&@G0!````QH)<
-M`0```,>"F`$```````"-A`U@`0``B8)@`0``B8)D`0``@\`,B8)L`0``B8)P
-M`0``C80->`$``(F">`$``(F"?`$``,9'!@*#Q@$/MD4F9CGP#X=U____BY0D
-MD````,9"-`#&@C8%``#_QH(W!0``_\:".`4``/_&@CD%``#_@'PD=0`/A(,`
-M``"[``````^WRVG1*`$``(NT))````"+AG`%``#&1!`G`8N&<`4``,9$`B8`
-MBX9P!0``QD0"3/^+AG`%``#&1`)"_XN&<`4``&;'A`*4``````#'A(ZP`@``
-M`````(G1`XYP!0``C4$0B4$0`Y9P!0``C4(0B4(4@\,!#[9$)'5F.=AW@HNL
-M))````!FQX74``````"X`````(VV`````(N4))````#&A!"P!```_X/``3V&
-M````=>>`?"1T``^$K0```+L`````#[?#:<`4#0``BXPDD````(N1J`4``,9$
-M`C``BY&H!0``QD00,0"+D:@%``#'1!`,`````(G!B[0DD`````..J`4``(U1
-M$(E1$(G!`XZH!0``C5$0B5$4B<$#CJ@%``"-41B)41B)P0..J`4``(U1&(E1
-M'(N6J`4``(E\$`B)P0..J`4``(U1*(E1*`.&J`4``(U0*(E0+(/#`0^V1"1T
-M9CG8#X=8____BZPDD````,:%UP```("`?"1R`'1]NP`````/M]-ITK````"+
-MC"20````BX&,!0``9L=$$#($`(N!C`4``,9$`B8`BX&,!0``QD0"*/^+@8P%
-M``#&1`(T_XG1B[0DD`````..C`4``(U!%(E!%(G1`XZ,!0``C4$4B4$8BX:,
-M!0``B7P"5(/#`0^V1"1R9CG8=XB+K"20````QH78````@HGH!1@*``")1"0$
-MC4#DB00DZ/S___^)A10*``")Z`4\"@``B40D!(U`Y(D$).C\____B84X"@``
-MB>@%8`H``(E$)`2-0.2)!"3H_/___XF%7`H``(GH!80*``")1"0$C4#DB00D
-MZ/S___^)A8`*``")Z`6H"@``B40D!(U`Y(D$).C\____B86D"@``B>@%S`H`
-M`(E$)`2-0.2)!"3H_/___XG!B87("@``BYPDD````(N#S`H``(N3T`H``(!\
-M)'$`=%J)PXG6OP````")S2G%BT0D3(D$).C\____C50=`(E0"(E8#(EP$(N,
-M))````"+D0`!``")@0`!``"+3"1,B0B)4`2)`H'#``@``(/6`(/'`0^V1"1Q
-M9CGX=[.+A"20````!?`*``")1"0$BX0DD`````74"@``B00DZ/S___^)1"18
-MBYPDD````(F#[`H``(NL))````"+G?`*``"+M?0*``"_`````+T`````BT0D
-M4(D$).C\____BU0D6`'ZB5`(B5@,B7`0BXPDD````(N1"`$``(F!"`$``(M,
-M)%")"(E0!(D"@<,```$`@]8`@<<```$`@]4`B?@U```(``GH=:J+A"20````
-M!10+``")1"0$BX0DD`````7X"@``B00DZ/S___^)P8N<))````")@Q`+``"+
-MM"20````BX84"P``BY88"P``9H-\)&P`=%>)PXG6OP````")S2G%BT0D5(D$
-M).C\____C50=`(E0"(E8#(EP$(N,))````"+D1`!``")@1`!``"+3"14B0B)
-M4`2)`H'#C`$``(/6`(/'`68Y?"1L=[:#Q'Q;7E]=PXVV`````(V_`````%57
-M5E.#[`R+;"0@BWPD)(M?5`^V1RN)1"0(B6PD!(D<).C\____B<9F@T\R$(!]
-M*P!T2;D`````]D,)`70,ZSP/MD,)T_BH`74,@\$!#[9%*V8YR'?J9H/Y`W8E
-MBT4`!=`!```/M]&-%)"+`J,`````P>@4@_`!@^`!ZR.Y`````(M%``70`0``
-M#[?1C120BP*C`````,'H%(/P`8/@`83`=!0/ML&)1"0$B2PDZ/S____IA@$`
-M`(U#.#E#.`^$$0$``(7V#X0)`0``#[9&3<=$ASP`````BQ:+1@2)0@2)$(ET
-M)`C'1"0$!@```(D<).C\____@'Y/`'0?D(UT)@")+"3H_/___\<$)`$```#H
-M_/___X!^3P!UYHM&((7`=%;'0&``````]D8H!'4(B2PDZ/S___^+1B"+E3P%
-M``")1"0(B50D!,<$)`$```#H_/___XM&((N5/`4``(E$)`B)5"0$QP0D!@``
-M`.C\____QT8@`````(!K"@&)="0$B2PDZ/S___^+10"+D%@!``")%0````"%
-MTG0)BT4`B9!8`0``QD<F`&:#9S+O@'\?`'0BN@`````/M\*+1(<\A<!T!H!X
-M)O]U=8/"`0^V1Q]F.=!WXX!_,@!X#;X`````@'\?`'40ZTR)?"0$B2PDZ/S_
-M___K2`^WQHM<ASR%VW0G]D,H`G0ABT,@BY4\!0``B40D"(E4)`3'!"0&````
-MZ/S___^`8RC]@\8!#[9''V8Y\'?"9L=',@(`@&<M_8/$#%M>7UW#C70F`(V\
-M)P````!55U93@>R<````BX0DL````(E$)'2+4"R)5"1\BSJ+AZ0*``"+`(F$
-M)(````"+3"1TB4PD!(D\).C\____BVPD=("]MP````%V!\:%M`````2+1"1T
-M@\`0QT0D>`````"+5"1T.4(0="J+7"1T@\,0B1PDZ/S___^)1"1XBTPD=(M!
-M$(ML)'B):`2)10")702):1"+1"1T@W@@`'17N____P"#?"1X`'0(BU0D>`^W
-M6AZ+3"1TBU$@#[:"F`````^V4@*-!(`/MH0"``````^V5R(/MD\AB5PD$(E$
-M)`R)5"0(B4PD!,<$)$0#``#H_/___^M7O?___P"#?"1X`'0(BT0D>`^W:!Z+
-M5"1T#[9R38M,)'R+01@/MD`$#[97*0^V3R(/ME\AB6PD&(ET)!2)1"00B50D
-M#(E,)`B)7"0$QP0D=`,``.C\____@WPD>``/A&($``"+;"1X#[=M'HEL)%1I
-M];`$```#MUP*``"+GQ0*``"+1"1XB00DZ/S___^+EBP$``")5"1`BY8H!```
-MBXXD!```B[8@!```BT0D>`^W:!Z+1"1`B40D%(E4)!")3"0,B70D"(EL)`3'
-M!"3<`0``Z/S___^+1"14P>`&`<.+4S2)5"1`BU,PBTLLBW,HBVLDB6PD6(M#
-M((E$)%R+:QR);"1@BT,8B40D9(MK%(EL)&B+0Q")1"1LBVL,BT,(B80DE```
-M`(M#!(F$))````"+&XM$)$")1"0XB50D-(E,)#")="0LBU0D6(E4)"B+3"1<
-MB4PD)(M$)&")1"0@BU0D9(E4)!R+3"1HB4PD&(M$)&R)1"04B6PD$(N4))0`
-M``")5"0,BXPDD````(E,)`B)7"0$QP0D5`$``.C\____BVPD>(/%/(FL)(0`
-M``"+1"1XBT!4B80DC````(M%!`^V50&)1"0(B50D!,<$)%P```#H_/___X!]
-M`0`/A*,```#&A"2+`````)"-="8`#[:T)(L```"-!';!X`*+E"2$````BTH(
-M`<&)PXNL)(P````#70B+0PB)1"1PBP.+4P2)1"1`B50D1(MI"(M9!(L)BU0D
-M<(E4)!R+1"1`BU0D1(E$)!2)5"08B6PD$(E,)`B)7"0,B70D!,<$).@"``#H
-M_/___X"$)(L````!#[:4)(L```"+C"2$````.%$!#X=J____9H-_4``/A`("
-M``"^`````(VO-`D``(V'W````(E$)%`/M\;!X`(#A\0%``"+&(7;#X3*`0``
-M#[=#$(M4)'1F.4(<#X6X`0``#[>7B@L``#F4)(````!T8HGV@\(!#[>'C@L`
-M`#G"&<`APHN'I`H``(/`!(L$D*D```@`=31F)?\/9CGP=2LY7"1X=2Z+3"1X
-M#[=!'HE$)`3'!"3M````Z/S___^)/"3H_/___^F1`0``.Y0D@````'6@BT0D
-M?(!X-``/A3@!```/MT,09CV%``^'*@$```^WP("\![`$``#_#X09`0``@[PD
-ML``````/A/$```"+5"1T#[9")(/@!8/X!0^%W0```(L7#[=#'F;!Z`4/M\"-
-M!(4``P``B8)P`0``#[=+'H/A'[H!````B=#3X(G!BP>)B'0!```/MT,>P>`"
-M`X?$!0``QP``````#[=+'HG(9L'H!0^WP(E$)$R#X1^)T-/@B<'WT8M$)$PA
-MC(?(!0``#[=+'HG(9L'H!0^WP(/A']/B]](A5(=4.UPD>'0WBQ.+0P2)0@2)
-M$(-[5`!T#XU#5(E$)`2)/"3H_/___XN'W````(E8!(D#BU0D4(E3!(F?W```
-M``^W0QZ)1"0$B2PDZ/S___^+3"1T@&E/`>L:BT0D?/9`!@)T$(E<)`2+5"1T
-MB10DZ/S___^#Q@%F.7=0#X<3_O__@[PDL`````!T*XM,)'0/MD$D@^`%@_@%
-M=1N+;"1XBU4`BT4$B4($B1");"0$B0PDZ/S___^!Q)P```!;7E]=PY"0D)"0
-MD)"0D)"0D)!55U93@^P,BWPD(`^V="0D#[9$)"R(1"0+BT<LBPBZ``````^V
-M7"0H`?.(7"0#B?8/MH0*L`0``#S_=$8/ML!IP"@!``")1"0$`X%P!0``B?,X
-MF-H```!U*3FXY````'4A#[9<)`.(F-D```"+@7`%```/MEPD"XML)`2(G`78
-M````@\(!@?J`````=:.#Q`Q;7E]=PXUT)@"-O"<`````@^P(B1PDB70D!(MT
-M)!@/MEPD$`^V5"04BT0D#(M(,`^V@9`````\3W<I#[;`C02``=J(E,&5````
-M#[:!D````(T$@(GRB)3!E````("!D`````&+'"2+="0$@\0(PXGV5U93BWPD
-M$`^W1"04N_____]FA<!T0;O_____N0````"#Z`$/M_`/MA0YC4+0/`EW%X#[
-M_P^4P(/H`2'##[;#C02`C5Q"T.L%@/O_=0J#P0&-1@$YP77/#[;#6UY?PXGV
-M55=64XML)!0/MG0D&`^V?"0<BT4LBPBZ`````(UT)@`/MH0*L`0``#S_="L/
-MML!IP"@!```#@7`%```YJ.0```!U%(GS.)C9````=0J)^HB0VP```.L+@\(!
-M@?J`````=;Y;7E]=PXGVC;PG`````%575E.#[`2+="08#[9\)!P/MD0D)(A$
-M)`.+1BR+&(MN,+D`````#[:$&;`$```\_W1&#[;`:<`H`0``B<(#DW`%```Y
-MLN0```!U+8GX.(+9````=2.`?"0#`'0.BX+@````BU0D((D"ZQF+3"0@BP&)
-M@N````#K"X/!`8'Y@````'6CB>JY`````(VV``````^V@I0````\`78Y/!=T
-M-8GX.(*5````=2N`?"0#`'02C02)BX3%F````(M4)"")`NL=C12)BTPD((L!
-MB835F````.L+@\$!@\(H@_E0=;&#Q`1;7E]=PXGVC;PG`````%575E.#["`/
-MMFPD.(M$)#2+L.@````/MD8"P>`(#[96`XT\$`^WQX/`!#T`"```#X_M````
-MB>J$TG1.BTPD-`^VD=P```")TX/CX`^V1@&#X`^)T8/A$`G8"<B)TX/C"(/@
-M\XG1@^$$"=@)R(/B`H/@_(M<)#0/MHO<````@^$!"=`)R(A&`>M,#[96`8G3
-M@^/@BTPD-`^V@=P```"#X`^)T8/A$`G8"<B)TX/C"(/@\XG1@^$$"=@)R(/B
-M`H/@_`^V3@&#X0$)T`G(BUPD-(B#W````(U6"`^WQXU\!@0YUW8_B50D'+L`
-M````B>@/MO"-;"0<B70D#(EL)`@/ML.)1"0$BU0D-(D4).C\____BT0D'(/`
-M!(E$)!R#PP$Y^'+3@\0@6UY?7<.-M@````!3@^P8BTPD)(M9-`^V0P+!X`@/
-MME,#`=`/M\"-4`0/MT$@.<)_+HM,)""+@>@```")5"0(B5PD!(D$).C\____
-MQT0D!`````"+1"0@B00DZ/S___^#Q!A;PXVT)@````!55U93@^P<#[9\)#B+
-M1"0PBU@PB5PD&+X`````BVPD-(/%!`^V@Y0````\`79"/!=T/HGX.(.5````
-M=32-!+:+3"08C93!G````(M,)#0/MD$#/"!V!;@@````#[;`B40D"(EL)`2)
-M%"3H_/___XGV@\8!@\,H@_Y0=:B#Q!Q;7E]=PXVV`````(V\)P````"#["R)
-M7"0<B70D((E\)"2);"0HBUPD,`^V1"0TB$0D%XM#+(LHB2PDZ/S___^)QH7`
-M#X0'`0``B2PDZ/S___^)QX7`=1&)="0$B2PDZ/S____IZ````(U6/(E4)!B+
-M4`B+@^@```"+3"0\B4PD"(E$)`2)%"3H_/___\9&:`K&1A6L#[=#'&:)1A"+
-M1"1`B49(B6X8BU0D/(E6((-.9!*+1PB)1C2)?E"-@[@```")1CC&1AP@QT9L
-M`````,9&)#O&1B4"#[9,)!>(3B:+1"0XP>@0B$8GBU0D.`^VQHA&*(A6*0^V
-M1B*(1BH/MD8AB$8K#[9,)#R(3BS&1BT`QT0D!`````"+1"08B00DZ/S___^+
-M1B")1"0,BT<,BU<0B40D!(E4)`B+5"08B10DZ/S___^)="0$B2PDZ/S___^+
-M7"0<BW0D((M\)"2+;"0H@\0LPXVT)@````"-O"<`````@^PLB5PD'(ET)"")
-M?"0DB6PD*(M<)#`/MD0D-(A$)!>+0RR+*(DL).C\____B<:%P`^$[0```(DL
-M).C\____B<>%P'41B70D!(DL).C\____Z<X```"-5CR)5"08QD9H"L9&%:P/
-MMT,<9HE&$(M$)$")1DB);AC'1F0(````B7Y0BT<(B48TBU0D/(E6((V#N```
-M`(E&.,9&'"#'1FP`````QD8D/,9&)0(/MD0D%XA&)HM$)#C!Z!"(1B>+5"0X
-M#[;&B$8HB%8I#[9&(HA&*@^V1B&(1BL/MD0D/(A&+,9&+0#'1"0$`````(M4
-M)!B)%"3H_/___XM&((E$)`R+1PR+5Q")1"0$B50D"(M$)!B)!"3H_/___XET
-M)`2)+"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#D(VT)@````"#["R)7"0<
-MB70D((E\)"2);"0HBVPD,(M%+(L`B40D%(N5Z`````^V0@+!X`@/ME(#`=`/
-MM\"-6`2!^P`(```/C^\```"+1"04B00DZ/S___^)QH7`#X39````BT0D%(D$
-M).C\____B<>%P'45B70D!(M$)!2)!"3H_/___^FR````C48\B40D&(M7"(N%
-MZ````(E<)`B)1"0$B10DZ/S____&1A6L#[=%'&:)1A"+1"04B488B5X@@TYD
-M$HM'"(E&-(E^4(V%N````(E&.,9&'"#'1FP`````QD8D'<9&)1#&1B8"#[9&
-M(8A&)XA>*,=$)`0`````BT0D&(D$).C\____BT8@B40D#(M'#(M7$(E$)`2)
-M5"0(BT0D&(D$).C\____B70D!(M$)!2)!"3H_/___XM<)!R+="0@BWPD)(ML
-M)"B#Q"S#D(VT)@````"#["R)7"0DB70D*(M<)#`/ME0D-`^V="0XQT0D(```
-M``"`>R<!=$K'1"0,`0```(U$)"")1"0(#[;"B40D!(D<).C\____BT0D((7`
-M=".`"(")\(3`=`J+1"0@@$@#(.L(BT0D((!@`]^)'"3H_/___XM<)"2+="0H
-M@\0LPXUV`(/L+(E<)!R)="0@B7PD)(EL)"B+7"0P#[9$)#2(1"07BT,LBRB)
-M+"3H_/___XG&A<`/A+D```")+"3H_/___XG'A<!U$8ET)`2)+"3H_/___^F:
-M````C48\B40D&,9&%:P/MT,<9HE&$(EN&,=&9`@```")?E"+1PB)1C3'1B``
-M"```C8.X````B48XQD8<(,=&;`````#&1B0<QD8E`0^V1"07B$8FQD8G",9&
-M*`#'1"0$`````(M$)!B)!"3H_/___XM&((E$)`R+1PR+5Q")1"0$B50D"(M$
-M)!B)!"3H_/___XET)`2)+"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#C;8`
-M````C;\`````55=64X/L'(M,)#2+630/MD,"P>`(#[93`P'0#[?PC58$#[=!
-M(#G"#X^#`0``C7L(C6PS!(E\)!#&1"07`,=$)!@`````.>\/@_4```"-=@`/
-MMD0D&(A$)!8/MD<"P>`(#[97`P'09HE$)!0/M_")="0$BT0D$(/`!(D$).C\
-M____//]U:XM$)!"-5#`$B=,YU0^&^@```,9$)!?_C70F``^V0@+!X`@/ME(#
-MC300#[?&B40D!(U#!(D$).C\____//]U$8!\)!?_#X6.````D.F#````.$0D
-M%W8$B$0D%P^WQHU4`P2)TSG5=G'KLHGV*D0D%P^VP(E$)`@/MEPD%HE<)`2+
-M5"0PB10DZ/S___^)7"0(B7PD!(M$)#")!"3H_/___P^W1"04BU0D$(U\`@2)
-M?"00@T0D&`$Y_0^'#O___\=$)`0"````BT0D,(D$).C\____ZUC&1"07``^V
-M1"06B40D"(E\)`2+5"0PB10DZ/S___\/MT0D%(M4)!"-?`($B7PD$(-$)!@!
-MZ;_^__\/MD0D%HE$)`B)?"0$BT0D,(D$).C\____ZY:-="8`@\0<6UY?7<.0
-MC;0F`````%575E.#[!R+3"0TBUDT#[9#`L'@"`^V4P,!T`^WP(/`!`^W42`Y
-MT`^/'@$``(US"`^V6P&Y`````+H`````B?8"3@(/MD8#C70&!(/"`3C3<^Z$
-MR0^$TP```,9$)!L`OP````"-0?\/ML"#P`&)1"04#[94O@$`5"0;#[8$OCP!
-M=`0\%W5*#[9<)!LHTSA<)!L/AHD```"-1P$/MNB-=@`/M@2^B40D#(EL)`@/
-MML.)1"0$BT0D,(D$).C\____@\,!.EPD&W18Z]:-M@````"+3"0PBT$P@+B1
-M`````71`#[9<)!LHTSA<)!MV,XU'`0^VZ`^V!+Z)1"0,B6PD"`^VPXE$)`2+
-M1"0PB00DZ/S___^#PP$Z7"0;==B0C70F`(/'`3M\)!0/A43___^+5"0PBT(P
-MQH"1`````<=$)`0'````B10DZ/S___^#Q!Q;7E]=PXVV`````(V\)P````"#
-M["R)7"0<B70D((E\)"2);"0HBUPD,(7;#X3,````BT,LBRB)+"3H_/___XG&
-MA<`/A+4```")+"3H_/___XG'A<!U$8ET)`2)+"3H_/___^F6````C48\B40D
-M&,9&%:P/MT,<9HE&$(EN&,=&9`@```")?E"+1PB)1C3'1B``"```C8.X````
-MB48XQD8<(,=&;`````#&1B0<QD8E`<9&)@+&1B<(QD8H`,=$)`0`````BT0D
-M&(D$).C\____BT8@B40D#(M'#(M7$(E$)`2)5"0(BT0D&(D$).C\____B70D
-M!(DL).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.0@^P<B5PD$(ET)!2)?"08
-MBWPD)(MT)""+7T@/MU<09H'ZA0`/AX<````/M\(/MHP&L`0``(#Y_W1W9H/Z
-M?W<9#[;!BY9P!0``:<`H`0``BT00+`^V0`3K.&:!^H$`=QD/ML&+EJ@%``!I
-MP!0-``"+1!`(#[9`!.L8#[;!BY:,!0``:<"P````BT005`^V0`20//]T'`^V
-MP("\!C8%``#_=`^`^?]T"@^V1Q0\!G4RB?:#?U``=`^-1U")1"0$B30DZ/S_
-M__^)?"0$B30DZ/S____'0RS_____B1PD_U,HZW&$P'4Z]D=D"'09BTL<BU<T
-MBT<@B40D"(E4)`2)#"3H_/___\=#+`````"+4R"%TG0%BT,4B0*)'"3_4RCK
-M$L=#+/____^)'"3_4RB0C70F`(-_4`!T#XU'4(E$)`2)-"3H_/___XE\)`2)
-M-"3H_/___XM<)!"+="04BWPD&(/$',/K#9"0D)"0D)"0D)"0D)"#[!R)7"0,
-MB70D$(E\)!2);"08BUPD)(M\)"`/MFL4#[=#$&8]A0!W&8N7<`4```^WP`^V
-MA`>P!```:<`H`0``ZPN+EW`%``"XV"8!`(TT`HGHA,!U(6;'AI0``````(![
-M)!QU$H![)@)U#(E<)`2)-"3H_/___X-[4`!T#XU#4(E$)`2)/"3H_/___XE<
-M)`2)/"3H_/___XGH/`9T/HV>!`$``(E<)`2+1Q2)!"3H_/___\>&!`$``("$
-M'@#'A@P!````````B;80`0``B5PD!(M'%(D$).C\____BUPD#(MT)!"+?"04
-MBVPD&(/$',-55U93@^P<#[9$)#B(1"0;BU0D,(M"+(LPOP````"+;"0T@\4,
-M#[:$-[`$```\_W11#[;`:=@H`0``QT0D"`@```");"0$B=@#AG`%```%H```
-M`(D$).C\____A,!T(XN&<`4```^V5"0;B)0#V@```(N&<`4``(M4)#")E`/D
-M````@\<!@?^`````=9B#Q!Q;7E]=PXUT)@"-O"<`````55=64X/L'(M,)#2+
-M<30/MD8"P>`(#[96`P'0#[?XC5<$#[=!(#G"#X_U````C5X(C70^!(ET)!2)
-MW3G>#X;,````QT0D&`````"-M@`````/MDPD&`^V$X32#XB5````B="#X`\\
-M!@^%B````/9#`\!T"O9#!<`/A7@```#VPA!T-8![!`!T;8UU"+\`````#[9#
-M`XE$)`B)="0$BT0D,(D$).C\____@\8<@\<!B?@X0P1V0.O9@'L"`'0XC74$
-MOP`````/MLF)3"00C70F`(M$)!")1"0(B70D!(M$)#")!"3H_/___X/&'(/'
-M`8GX.$,"=]L/MD,!C5P%`HG=@T0D&`$[7"04#X)"____QT0D!`$```"+1"0P
-MB00DZ/S___^#Q!Q;7E]=PXVV`````%575E.#["R+1"1`B40D((M4)$0/ME(4
-MB%0D*XM,)$0/MU$09H'ZA0`/A[D#```/M\*+7"0@#[:,`[`$``"X_P```(#Y
-M_W1B9H/Z?W<=#[;!BUPD((N3<`4``&G`*`$``(M$$"P/MD`$ZS]F@?J!`'<=
-M#[;!BUPD((N3J`4``&G`%`T``(M$$`@/MD`$ZQL/ML&+7"0@BY.,!0``:<"P
-M````BT005`^V0`2+5"0@#[:$`C8%``")1"0<:\!<C80"0`$``(E$)"2+DG`%
-M```/ML%IP"@!``"--`*`?"0K``^%D@(``&;'AI0``````(M$)$2`>"0<#X5[
-M`@``#[9`)CP"=%H\`G<+/`$/A6<"``"0ZR$\!W0R/`H/A5@"``"+3"1$B4PD
-M!(DT).C\____Z4,"``"+7"1$B5PD!(DT).C\____Z2X"``"+1"1$B40D!(DT
-M).C\____Z1D"``"+5"1$B50D!(DT).C\____C9X$`0``B5PD!(M&+(L`BT`4
-MB00DZ/S____'A@0!``"`A!X`QX8,`0```````(FV$`$``(E<)`2+1BR+`(M`
-M%(D$).C\____QD8F_VM$)!Q<BTPD(("\`4H!````#X1Z`0``OP````")PXVL
-M`7@!``")]HDL).C\____B<:+5"0@C003BY!\`0``B;!\`0``B2Z)5@2),H!^
-M)O\/A*(```"`?B4`#X6?````B?.`OK4`````#X1/`0``#[9.)`^VT8G0@^`&
-M@_@&=2GVP@%T)(ET)`P/MD9-B40D"(M&,(E$)`2+3"0DB0PDZ/S____I%0$`
-M`(/X!'4A]L$!C;0F`````'05B5PD!(M<)"")'"3H_/___^GO````@_@&#X7F
-M````]L$!#X7=````B5PD!(M$)"")!"3H_/___^G(````B?;&AK4`````@\<!
-MBTPD((V4&4`!```/MD(*B?DXR`^'#?___SC!=7.$P'1OOP````!K7"0<7(M$
-M)""-K!AX`0``B2PDZ/S___^)QHM4)""-!!.+D'P!``")L'P!``")+HE6!(DR
-M@'XF_W0>#[9&)3PB=`0\#742QT0D!`H```")-"3H_/___^L^@\<!B?F+1"0@
-M.(P82@$``'>F:T0D'%R+5"0@QH0"10$``/^+3"0DB4PD!(D4).C\____@'PD
-M*P`/A:(```"+7"1$@WM0`'05B=B#P%")1"0$BT0D((D$).C\____BU0D1(E4
-M)`2+3"0@B0PDZ/S___^`?"0K`'1H#[>&E````(/``6:)AI0```!F@_@*=@YF
-MQX:4``````#IX/W__\=$)`0*````B30DZ/S____K,8M<)"`/MILU!@``B5PD
-M'&O#7(M4)""-A`)``0``B40D)(N2<`4``+C8)@$`Z;[\__^#Q"Q;7E]=PX/L
-M"(D<)(ET)`2+7"0,BW0D$(M4)!2+3"0<A=MT1(7V=$"%TG0\@WPD&`!T-6:!
-M^84`=RX/M\&`O`.P!```_W0AQD(DX<9")0'&0B839HE*$(ER&(M$)!B)0FRX
-M`0```.L%N`````"+'"2+="0$@\0(PXVT)@````"-O"<`````BTPD!(M!!(M`
-M!*,`````@'PD"`!T"HG"@<H```P`ZPB)PH'B___S_XM!!(D0BT$$B5`,BT$$
-MB5`0BT$$B5`4BT$$B5`8BT$$B5`$PY"0D)!64XM<)!"+3"0PBW0D.`^W1"0,
-M9CTB)W=)9CT@)W-Y9CU`(71S9CU`(7<99CT@(9!T9F8](B%T8&8]4`>-="8`
-M=6#K5&8]1"%T3F8]1"&)]G)09BT0)V:#^`%W1HUT)@#K-F8]@B=T,&8]@B>-
-M="8`=Q)F/20G="!F/8`GC70F`'4@ZQ1F/8"1=`YF/8"4B?9T!F8]@')U"L8#
-M%(M$)!3&``*+1"08Q@`$#[83BT0D+(@09L<!@`!FQP8``(M$)"#&`""+1"0D
-M9L<```$/MA.+1"0HB!`/M@-F`P%F`P:+5"0T9HD"BU0D'&:)`@^W$8M$)#QF
-MB1`/MQ&#P@N+1"1`9HD06U[#C78`C;PG`````%575E.#[`2+?"08#[9$)!R(
-M1"0##[=O4&:%[0^$W@```(N/Q`4``+X`````C70F`(L!A<`/A+8````/MU`0
-MN_\```"X_____V:!^H4`=W0/M\(/MIP'L`0``+C_____@/O_=%QF@_I_=QD/
-MML.+EW`%``!IP"@!``"+1!`L#[9`!.L]9H'Z@0!W&0^VPXN7J`4``&G`%`T`
-M`(M$$`@/MD`$ZQT/ML.+EXP%``!IP+````"+1!!4#[9`!(VV``````^VVXN7
-M<`4``#I$)`-U(0^WPVG`*`$```^V1!`D@^`%@_@%=0NP`>L;C;0F`````(/&
-M`8/!!&8Y[@^%,?___[@`````@\0$6UY?7<.-="8`55=64X/L"(M4)!R+0BR+
-M*(N%%`H``(E$)`0/MWU0N0````"^`````.M)C;8`````#[?9BX7$!0``BQ28
-MA=)T,(M")"7___\`/>$!$`!T(8M$)!P/MT`<9CM"$'43B=C!X`:+5"0$9CET
-M$`AT"XUV`(/!`68Y^7*X9CGY=!"#Q@%F@_X?=P>Y`````.OF#[?&@\0(6UY?
-M7<.0C;0F`````%.+5"0(BTPD#(M<)!"+0CB%P'06Q@!PBT(XB$@"BT(XQD`'
-M`(M".(A8#%O#C70F`//#C;0F`````(V\)P````"#[!")'"2)="0$B7PD"(EL
-M)`R+3"04#[=\)!B)^H'B_P$``(N!Q`4``(LTD(7V=#`/MIG6````#[9&%8G9
-MT^`/M^@/M]>X__\``-/@(<(YU0^5P`^VP(/H`2'&D(UT)@")\(L<)(MT)`2+
-M?"0(BVPD#(/$$,.-="8`C;PG`````(M4)`2X`````(VT)@````#&!!``@\`!
-M/;````!U\L9"*/_&0C3_C4(4B4(4B4(8PXM4)`2X`````(VT)@````#&!!``
-M@\`!/2@!``!U\L9"3/_&0D+_QD).'XU"$(E"$(E"%,.-M@````"-OP````!3
-MBT0D"(M<)`R+$XN(^````(F0^`````7T````B0*)2@2)$<<#`````%O#D(UT
-M)@!3@^P(BUPD$(M,)!2+D_````")B_````"-@^P```")`8E1!(D*@WE,`'0/
-MC4%,B40D!(D<).C\____@\0(6\.04XM$)`B+7"0,BQ.+B`@!``")D`@!```%
-M!`$``(D"B4H$B1''`P````!;PY"-="8`4XM$)`B+7"0,BQ.+B``!``")D``!
-M```%_````(D"B4H$B1''`P````!;PY"-="8`BT0D!(M4)`B+B!@!``")D!@!
-M```%%`$``(D"B4H$B1'#ZPV0D)"0D)"0D)"0D)"04XM$)`B+7"0,BQ.+B"`!
-M``")D"`!```%'`$``(D"B4H$B1''`P````!;PY"-="8`4XM$)`B+7"0,BQ.+
-MB!`!``")D!`!```%#`$``(D"B4H$B1''`P````!;PY"-="8`#[9$)`0\%W<7
-M#[;`_R2%(`<``+@T````PXVT)@````"X!````,.X/````)"-="8`P[@4````
-MP[A`````C70F`,.X'````,.X&````(UT)@##N"@```##N"````"-="8`P[A,
-M````PXGVC;PG`````%575E.+;"04BWPD&`^V5R2)T(/@!H/X!G4)]L(!#X3*
-M````@']"_P^%P````(M%`(NP&`$``(DU`````+D`````N`$```")P]/CA=YU
-M,HA/0HM5`(G8"?")@A@!``"+10"+@%@!``"C`````(G:(<)T=XM%`(F06`$`
-M`.MLC78`@\$!@_D@=;F+10"+L!P!``")-0````"Q`(VT)@````")RK@!````
-MB</3XX7>=3*-0B"(1T*+50")V`GPB8(<`0``BT4`BX!@`0``HP````")VB'"
-M=!.+10")D&`!``#K"(/!`8/Y('6W@$4L`5M>7UW#C;0F`````(V\)P````!7
-M5E.+?"00BU0D%(!Z-/\/A;<```"+!XNP&`$``(DU`````+D`````N`$```")
-MP]/CA=YU+(A*-(L7B=@)\(F"&`$``(L'BX!8`0``HP````")VB'"='&+!XF0
-M6`$``.MG@\$!@_D@=;^+!XNP'`$``(DU`````+$`C;0F`````+@!````B</3
-MXX7>=3.(2C2+%XG8"?")@AP!``"+!XN`8`$``*,`````B=HAPG09BP>)D&`!
-M``#K#XVT)@````"#P0&#^2!UN(!'+`%;7E_#4P^V7"00BT0D"(M(*(7)=#&Z
-M`````(M$D3R%P'0%.%A-=`^#P@&#^@5T%Y"-="8`Z^1F@7DDA0!W"(7`C70F
-M`'4%N`````!;PXVT)@````!55U93@^P,BVPD(`^V1"0DP>`(#[94)"B--!"`
-M?1P`#X3)````@WTX``^$OP```/9%9`D/E,")Q[D`````C78`B<L/MQ3-@`<`
-M`(GP(=!F.<(/A8L````/MA3-A0<``(#Z`W0%@/H'=0N)^#@$S80'``!U;L9%
-M%"`/M@3=A@<``(E$)`@/ML*)1"0$B2PDZ/S___^+53@/M@3=AP<``(A"#8-\
-M)"P`="N+1"0LBQB+<`2+33B)<0.+13B`"(#V168$=!"%]G0,BT4XB5@(BT4X
-M@"!_BU4X#[9%'(/H!XA"!^L,@\$!@_D0#X52____@\0,6UY?7<.-=@"-O"<`
-M````@^P,BT0D$(V0#`$``+D`````.9`,`0``=!&)%"3H_/___XG!QT`4````
-M`(G(@\0,P^L-D)"0D)"0D)"0D)"0D(/L#(M$)!"-D!P!``"Y`````#F0'`$`
-M`'0*B10DZ/S___^)P8G(@\0,PXVV`````(/L#(M$)!"-D!0!``"Y`````#F0
-M%`$``'0DB10DZ/S___^)P8G"N`````"0C70F`,8$$`"#P`$]F````'7RB<B#
-MQ`S#C;8`````C;\`````@^P,BT0D$(V0_````+D`````.9#\````=`J)%"3H
-M_/___XG!B<B#Q`S#C;8`````@^P,BT0D$(V0]````+D`````.9#T````=`Z)
-M%"3H_/___XG!QD`(`(G(@\0,PXGV55=64X/L'(E$)!")U<=$)!0`````QT0D
-M&`````"-=@"+5"08BTPD$`^VA`HP!0``//\/A"@!```/MM`/MT0D&&:#Z(!F
-M/8$`#X=\````#[?":<`4#0``B<,#F:@%``"`>S``=%6^`````(U[*(UV`(D\
-M).C\____C4CXBU,LB4,LB7D(B5$,B0*+020E`/__`#T``/\`=1CV02<$=!*+
-M02"%P'0+B>J(4`&-M@````"#Q@&)\3A+,'>VB>B(@Y(```"#Q0'IE@````^W
-MPFG`L````(G#BU0D$`.:C`4``(!['P!T0[D`````C;8`````#[;!BU2#/(72
-M="6+0B0E`/__`#T``/\`=1;V0B<$=!"+0B"%P'0)B>J(4`&-="8`@\$!.$L?
-M=\B)Z8B+I````("[I0````-U'H-$)!0!BT0D%(/``X/X!G86@\4!QT0D%```
-M``#K"8/%`8VV`````(-$)!@!@WPD&`8/A;#^__^+5"00BX(\!0``.=!U#`7`
-M#```B>KH=O[__X/$'%M>7UW#C;0F`````(V\)P````"#[`R+5"00BT0D%`^V
-M2`0/MH01-@4``,:$$38%``#_#[?`B40D!('"U`D``(D4).C\____@\0,PY"-
-MM"8`````@^P(B1PDB70D!(MT)!"+7DR%VW0DC4XDC5,,BT,,B48DBT($B4$$
-MBT((B4$(BT(,B4$,BT,<B48TBQPDBW0D!(/$",.-M@````"-OP````"#[`B)
-M'"2)="0$BW0D$(M>3(7;="B-2PR-5B2+1B2)0PR+0@2)002+0@B)00B+0@R)
-M00R+1C2)0QS&0P@!BQPDBW0D!(/$",.0C;0F`````%=64X/L$(M\)""+'V:#
-M>U``#X2[````O@````"-="8`#[?6BX/$!0``BPR0A<D/A)$````/MU$09H'Z
-MA0!W<0^WP@^VA`.P!```//]T8F:#^G]W'`^VP(N3<`4``&G`*`$``(M$$"P/
-MME`$ZTB-=@!F@?J!`'<9#[;`BY.H!0``:<`4#0``BT00"`^V4`3K)0^VP(N3
-MC`4``&G`L````(M$$%0/ME`$ZPR-M"8`````NO\````/MD<$.<)U"(D,).C\
-M____@\8!9CES4`^'3O___X/$$%M>7\.-M"8`````@^P<B5PD%(ET)!B+7"0@
-MBW0D)`^V1C0\_W09#[;`B40D!(L#B00DZ/S____&1C3_@&LL`8M<)!2+="08
-M@\0<PX/L'(E<)!2)="08BUPD((MT)"0/MD9"//]T&0^VP(E$)`2+`XD$).C\
-M____QD9"_X!K+`&+7"04BW0D&(/$',-75E.#[!"+="0@BUPD)#ES&`^$SP``
-M`(![%``/A98````/MD,D/!5T"#Q5#X6&````BT-,A<!T?XG"@'@(`75W9H%X
-M#.$!=6^+OG`%```/MT,0N=@F`0!F/84`=Q$/M\`/MH0&L`0``&G(*`$``(T$
-M#P^V4@Z`^@=T'X#Z!W<'@/H&=3/K'(#Z#(VT)@````!T((#Z#74@ZQ!F@V`Z
-M_8GVZQ5F@T@Z`NL.9H-@.O>)]NL%9H-(.@B#>U``="F!>R``"```=Q&-0U")
-M1"0$B30DZ/S____K#XU#4(E$)`2)-"3H_/___V:!>R3A`0^%!@$```^W0Q!F
-M/84`=WH/M\`/MH0&L`0``#S_=&N+EG`%``"`>Q0`=5\/ML!IP"@!``"-!`(/
-MME,F@/H'=!V`^@=W!X#Z!G4QZQJ`^@R0C70F`'0@@/H-=2#K$&:#8#K]B?;K
-M%6:#2#H"ZPYF@V`Z]XGVZP5F@T@Z"&:!>R3A`8UV``^%@@```(![)@MU?`^W
-M2Q`/MD8NC7C_B<KK')"-="8`@\(!9H'ZA0!W#0^WPH"\,+`$``#_=0D/M\(Y
-M^'SBZT1F/?\`=1GK/(/!`6:!^84`=PT/M\&`O#"P!```_W4,#[?!.<=_XKC_
-M````9HE#$,9#%(")7"0$B30DZ/S____I'`$``,9#%``Y<QAT*(M#3(7`="&`
-M>`@!=0R)7"0$B30DZ/S___^-0TR)1"0$B30DZ/S___^#>U0`=`^-0U2)1"0$
-MB30DZ/S___^)7"0$BT,8B00D_U-L#[=3)&:!^N$!=54/MD,F@^@1/`%W2@^W
-M0Q!F/84`#X>E````#[?`#[:$!K`$```\_P^$D@````^VP&G`L`````.&C`4`
-M`(!X*0!U?8!X-/]T=XE$)`2)-"3H_/___^MI#[=#$&8]A0!W7P^WP`^VC`:P
-M!```B[YP!0``BT,D)?___P`]X0$0`'0_@?G_````=#=F@?KA`740#[9#)H/H
-M$3P!=B60C70F`&G!*`$``(T$!X!X3P!U$8E$)`2)-"3H_/___Y"-="8`@\00
-M6UY?PXGVC;PG`````(/L'(E<)!")="04B7PD&(MT)""+7"0D#[=3$&:!^H4`
-M#X>*````#[?"#[:,!K`$``"`^?]T>F:#^G]W&0^VP8N6<`4``&G`*`$``(M$
-M$"P/MD`$ZSMF@?J!`'<9#[;!BY:H!0``:<`4#0``BT00"`^V0`3K&P^VP8N6
-MC`4``&G`L````(M$$%0/MD`$C70F`&8]_P!T&@^WP`^VO`8V!0``B?@\_W0)
-M#[;!9CW_`'40B5PD!(DT).C\____ZWZ)]@^V4R</MD,H#[9+*8#Y`70%@/D(
-M=5J+2TC!X`@/MM(!T"7_`0``BY;$!0``.0R"=3\/MTD>B<IFP>H%#[?2@^$?
-MN/[____3P"%$EE2+0T@/MT`>B40D!(GZ#[;":\!<C80&0`$``(D$).C\____
-MB?:)7"0$B30DZ/S___^+7"00BW0D%(M\)!B#Q!S#C70F`(/L#(E<)`2)="0(
-MBUPD$(V#[````+X`````.8/L````=!V)!"3H_/___XG&B00DZ/S___^)'"3H
-M_/___XE&3(GPBUPD!(MT)`B#Q`S#C78`@^P<B5PD$(ET)!2)?"08BWPD((M'
-M+(LPB30DZ/S___^)PX7`=&N)-"3H_/___XG"A<!U',:'M0````&)7"0$B30D
-MZ/S____K2(VT)@````#&0R0`#[=''&:)0Q#&0V@/B7,8QT,@`````,=#-```
-M``"+0@B)0SC&0QPDB5-0QT-L`````(E<)`2)-"3H_/___XM<)!"+="04BWPD
-M&(/$',/K#9"0D)"0D)"0D)"0D)"#[!R)7"00B70D%(E\)!B+?"0@BW0D)(M'
-M+(L8B1PDZ/S___^)PH7`=#W&0"0;QD`E`8GPB$(H#[=''&:)0A#&0F@/B5H8
-MQT(@`````,="-`````#'0FP`````B50D!(D<).C\____BUPD$(MT)!2+?"08
-M@\0<PXGVC;PG`````(/L+(E<)!R)="0@B7PD)(EL)"B+7"0TBT0D,(LHB2PD
-MZ/S___^)QH7`#X2B````B2PDZ/S___^)QX7`=1.)="0$B2PDZ/S____I@P``
-M`(GVC58\B50D&,9&).'&1B4!QD8F#@^W0QQFB4809H-C./>+5"0PBP*)1AC'
-M1B``"```BT<(B48TB7Y0QT9LH+T``,=$)`0`````BT0D&(D$).C\____BT8@
-MB40D#(M'#(M7$(E$)`2)5"0(BU0D&(D4).C\____B70D!(DL).C\____BUPD
-M'(MT)""+?"0DBVPD*(/$+,.-="8`C;PG`````(/L'(E<)!")="04B7PD&(MT
-M)"B+1"0@BQB)'"3H_/___XG"A<!T9<9`).'&0"4!B?"(0B;&0B</BTPD)`^W
-M01QFB4(0B5H8QT(@`````,="-`````#'0FP`````B50D!(D<).C\____B?`\
-M`742QP0D!0```.C\____ZQ"-="8`QP0D4,,``.C\____BUPD$(MT)!2+?"08
-M@\0<PXUT)@"#[!R)7"00B70D%(E\)!B+="0@BUPD)`^W4Q!F@?J%``^'BP``
-M``^WP@^VC`:P!```@/G_='MF@_I_=QD/ML&+EG`%``!IP"@!``"+1!`L#[9`
-M!.L[9H'Z@0!W&0^VP8N6J`4``&G`%`T``(M$$`@/MD`$ZQL/ML&+EHP%``!I
-MP+````"+1!!4#[9`!(UT)@`\_W0=#[;`#[:4!C8%``"`^O]T#8#Y_W0(#[9#
-M%#P&=3^#>U``="N!>R``"```B?9W$8U#4(E$)`2)-"3H_/___^L/C4-0B40D
-M!(DT).C\____B5PD!(DT).C\____ZW*+OG`%``"$P'0MQT0D"`$````/ML%I
-MP"@!``"-!`>)1"0$#[;":\!<C80&0`$``(D$).C\____@WM0`'0I@7L@``@`
-M`'<1C4-0B40D!(DT).C\____ZP^-0U")1"0$B30DZ/S___^)7"0$B30DZ/S_
-M__^+7"00BW0D%(M\)!B#Q!S#C;0F`````(V\)P````"#["R)7"0<B70D((E\
-M)"2);"0HBUPD,(ML)#0/MU409H'ZA0`/APX!```/M\(/MHP#L`0``(#Y_P^$
-M^@```&:#^G]W'`^VP8N3<`4``&G`*`$``(M$$"P/MD`$ZSJ-=@!F@?J!`'<9
-M#[;!BY.H!0``:<`4#0``BT00"`^V0`3K%P^VP8N3C`4``&G`L````(M$$%0/
-MMD`$//\/A)D````/MOD/ML`/MK0#-@4``(GP//\/A($```!F@?__`'1Z@'T4
-M!G1TBY-P!0``B50D&(!])@%U3,<$)`H```#H_/___XEL)`2)'"3H_/___\=$
-M)`@"````#[?':<`H`0```T0D&(E$)`2)\@^VPFO`7(V$`T`!``")!"3H_/__
-M_^L:B?;'!"3T`0``Z/S___^);"0$B1PDZ/S___^+7"0<BW0D((M\)"2+;"0H
-M@\0LPXUT)@"#["R)7"0@B70D)(E\)"B+?"0PBT<LBS")-"3H_/___XG#A<!U
-M"L:'M0````'K9)#&0"05QD`5JP^W1QQFB4,0B7,8QT0D$`$```#'1"0,`0``
-M`(E<)`B)?"0$B30DZ/S___^$P'49B5PD!(DT).C\____QH>U`````>L7C70F
-M`,=#;`````")7"0$B30DZ/S___^+7"0@BW0D)(M\)"B#Q"S#C;8`````C;PG
-M`````(/L+(E<)!R)="0@B7PD)(EL)"B+7"0PBT,LBRB)+"3H_/___XG&A<!U
-M#,:#M0````'IN````(DL).C\____B<>%P'4<QH.U`````8ET)`2)+"3H_/__
-M_^F2````C70F`,9&)!K&1B4(QD8F",9&)P#&1BC_QD8I`,9&%:L/MT,<9HE&
-M$(EN&,=&(/\```#'1F0(````BT<(B48T!?\```")1CC&1APDB7Y0QT9L````
-M`(U>/,=$)`0`````B1PDZ/S____'1"0,_P```(M'#(M7$(E$)`2)5"0(B1PD
-MZ/S___^)="0$B2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPXVT)@````"-
-MO"<`````@^PLB5PD'(ET)"")?"0DB6PD*(ML)#`/MD0D-(A$)!>+12R+.(D\
-M).C\____B<.%P'4-QH6U`````>FZ````D(D\).C\____B<:%P'48QH6U````
-M`8E<)`2)/"3H_/___^F3````C4,\B40D&,9#)!*`?"07`'0.QD,E`<9#)H#&
-M0RA`ZP3&0R@DQD,5JP^W11QFB4,0B7L8QT,@8````,=#9`@```"+1@B)0S2)
-M<U#'0VP`````QT0D!`````"+1"08B00DZ/S____'1"0,8````(M&#(M6$(E$
-M)`2)5"0(BT0D&(D$).C\____B5PD!(D\).C\____BUPD'(MT)""+?"0DBVPD
-M*(/$+,.-=@"#["R)7"0<B70D((E\)"2);"0HBUPD,(M#+(LHB2PDZ/S___^)
-MQH7`=0S&@[4````!Z;H```")+"3H_/___XG'A<!U',:#M0````&)="0$B2PD
-MZ/S____IE````(UT)@"-1CR)1"08QD8DGL9&)1#&1C$@QD85JP^W0QQFB480
-MB6X8QT8@(````,=&9`@```"+1PB)1C2)?E"#P"")1CC&1APDQT9L`````,9&
-M:`_'1"0$`````(M$)!B)!"3H_/___\=$)`P@````BT<,BU<0B40D!(E4)`B+
-M1"08B00DZ/S___^)="0$B2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPXVV
-M`````(V_`````(/L+(E<)!R)="0@B7PD)(EL)"B+7"0PBT,LBRB)+"3H_/__
-M_XG&A<!U#,:#M0````'IK@```(DL).C\____B<>%P'4<QH.U`````8ET)`2)
-M+"3H_/___^F(````C70F`(U&/(E$)!C&1B0EQD85JP^W0QQFB480B6X8QT8@
-M"````,=&9`@```"+1PB)1C2#P`B)1CC&1APDB7Y0QT9L`````,=$)`0`````
-MBT0D&(D$).C\____QT0D#`@```"+1PR+5Q")1"0$B50D"(M$)!B)!"3H_/__
-M_XET)`2)+"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#D(VT)@````"#["R)
-M7"0<B70D((E\)"2);"0HBT0D.(E$)!2+5"0PBSJ+CW`%``")3"08BU0D-`^W
-M0A`/MJP'L`0``(D\).C\____B<.+3"0T#[=Q'HGQ@^$?N`$```#3X(G!B?!F
-MP>@%#[?`A4R'5`^%R0```(7;#X3!````B>D/MM%ITB@!```#5"08BTPD-`^V
-M014/MH_6````T^`)\,9#).'&0R4!QD,F#XA#)V;!Z`B(0R@/MD0D%(A#*8N"
-MJ````(E#*HN"K````(E#+HM,)#2)2TC&0Q6J#[="'&:)0Q"+5"0PBP*)0QC'
-M0R``````QT,T`````,=#;$"Y``#'1"0$`````(U#/(D$).C\____B5PD!(D\
-M).C\____BT0D-`^W2!Z)R&;!Z`4/M\"#X1^Z`0```-/B"52'5(M<)!R+="0@
-MBWPD)(ML)"B#Q"S#D(UT)@!55U93@^P<#[9$)#2(1"0;BU0D,(L:9H-[4``/
-MA/X!``"]``````^WU8N#Q`4``(L,D(7)#X38`0``BWDD@>?___\`@?_A`1``
-M#X61````@WPD.``/A;@!```/MU$09H'ZA0!W9P^WP@^VA`.P!```//]T6&:#
-M^G]W&0^VP(N3<`4``&G`*`$``(M$$"P/ME`$ZSYF@?J!`'<9#[;`BY.H!0``
-M:<`4#0``BT00"`^V4`3K'@^VP(N3C`4``&G`L````(M$$%0/ME`$ZP6Z____
-M_[X`````Z:4```"0C70F``^W41!F@?J%``^'AP````^WP@^VM`.P!```B?`\
-M_W1V9H/Z?W<9#[;`BY-P!0``:<`H`0``BT00+`^V4`3K06:!^H$`=QN)\@^V
-MPHN3J`4``&G`%`T``(M$$`@/ME`$ZQ^)\@^VPHN3C`4``&G`L````(M$$%0/
-MME`$C;8`````@>;_````:<8H`0``B<8#LW`%``#K"KK_____O@````"+1"0P
-M.%`$#X6%````@WPD.`!T#HM4)#@/MT(<9CM!$'5P@'PD&P9T3H'_X0$0`'1&
-M#[96)(G0@^`&@_@&=3CVP@%U,X"^M`````!U*H'_X0$/`'0]#[9$)!N(013'
-M1"0(`0```(E,)`2+5"0PB10DZ/S____K&P^V1"0;B$$4#[?%B40D!(M4)#")
-M%"3H_/___X/%`68Y:U`/AP?^__^`?"0;@0^$-0$``(N#W````(VSW````#G&
-M#X0A`0``N@````"#P@&+`#G&=?=FA=(/A`H!``"->O^)-"3H_/___XG!@WPD
-M.`!T)XM4)#@/MT(<9CM!$'09BX/@````B8O@````B3&)002)".FY````D`^W
-M41!F@?J%`'=G#[?"#[:$`[`$```\_W189H/Z?W<9#[;`BY-P!0``:<`H`0``
-MBT00+`^V0`3K/F:!^H$`=QD/ML"+DZ@%``!IP!0-``"+1!`(#[9`!.L>#[;`
-MBY.,!0``:<"P````BT005`^V0`3K!;C_____BU0D,#I"!'4EBT$D)?___P`]
-MX0$/`'06#[9$)!N(012)3"0$B1PDZ/S____K$XN#X````(F+X````(DQB4$$
-MB0B-1_]FA?]T#SNSW````'0'B<?I^?[__X/$'%M>7UW#B?:-O"<`````@^P<
-MB5PD#(ET)!")?"04B6PD&(ML)"`/MGPD*(MU`(DT).C\____B<.%P'43BT0D
-M+,:`M0````'ID````(UV`(DT).C\____B<*%P'49B5PD!(DT).C\____BU0D
-M+,:"M0````'K9L9#).'&0R4!QD,F$(GYB$L5BTPD)`^V03-FB4,0BT4`B4,8
-MQT,@D````(U""(E#-(E34,9``1+&0@A`B?J(4`G'0VP`````QT0D!`````"-
-M0SR)!"3H_/___XE<)`2)-"3H_/___XM<)`R+="00BWPD%(ML)!B#Q!S#ZPV0
-MD)"0D)"0D)"0D)"0@^P<B5PD#(ET)!")?"04B6PD&(ML)""+?"0HBT0D+(E$
-M)`B+=0")-"3H_/___XG#A<`/A(@```")-"3H_/___XG"A<!T>L9#).'&0R4!
-MQD,F$(GYB$L5BTPD)`^V03-FB4,0BT4`B4,8QT,@D````(U""(E#-(E34,9`
-M`9'&0@A`B?J(4`D/MDPD"(A("L=#;`````#'1"0$`````(U#/(D$).C\____
-MB5PD!(DT).C\____QP0DH(8!`.C\____BUPD#(MT)!"+?"04BVPD&(/$',.-
-MM@````"-OP````"#[!R)7"0,B70D$(E\)!2);"08BWPD((ML)"B+-XDT).C\
-M____B<.%P'1RB30DZ/S___^)PH7`=&3&0R3AQD,E`<9#)A#&0Q6[BTPD)`^V
-M03-FB4,0BP>)0QC'0R"0````C4((B4,TB5-0QD`!$,9""$")ZHA0"<=#;```
-M``#'1"0$`````(U#/(D$).C\____B5PD!(DT).C\____BUPD#(MT)!"+?"04
-MBVPD&(/$',/K#9"0D)"0D)"0D)"0D)"#[!R)7"00B70D%(E\)!B+?"0@BS>)
-M-"3H_/___XG#A<!T;8DT).C\____B<*%P'1?QD,DX<9#)0'&0R80QD,5NXM,
-M)"0/MD$S9HE#$(L'B4,8QT,@D````(U""(E#-(E34,9``0#&0@A`QT-L````
-M`,=$)`0`````C4,\B00DZ/S___^)7"0$B30DZ/S___^+7"00BW0D%(M\)!B#
-MQ!S#@^P<B5PD$(ET)!2)?"08BW0D((V>U`D``(D<).C\____A,`/A;<```")
-M'"3H_/___XG!N`````")PX"\,#8%``#_=0PX1C1S$HA&-.L-B?:#PP&#P`&#
-M^`1UW8#[!`^$?`````^VPXB,!C8%```/M_EKQUR-E`9``0``N`````#&!!``
-M@\`!@_A<=?0/M\EKR5R-E`Y@`0``C00QB9!@`0``B9!D`0``@\(,B9!L`0``
-MB9!P`0``C90.>`$``(F0>`$``(F0?`$``(B81`$``&O'7(V$!D`!``#K"8UT
-M)@"X`````(M<)!"+="04BWPD&(/$',.-="8`C;PG`````(/L'(E<)!")="04
-MB7PD&(MT)""-GEP)``")'"3H_/___X3`#X47`0``B1PDZ/S___^)PK@`````
-MB<.`O#"P!```_W4<#[;`9CF&U````',=9HF&U````.L4C;0F`````(/#`8/`
-M`3V`````=<N`^X`/A,H````/ML.(E`:P!```#[?":?@H`0``B?@#AG`%``")
-M!"3H_/___XN6<`4```^VPV:)1!<<BX9P!0``QD0')@"+AG`%``#&1`<]_XN&
-M<`4``,9$!SS_BX9P!0``QD0'/O^+AG`%``#&1`=`_XN&<`4``,9$!S__BX9P
-M!0``QD0'0?^+AG`%``#&A`>V`````(N&<`4``,:$!]L```#_B30DZ/S___^+
-MEG`%``")A!?H````@'XY`74+BX9P!0``@$P'*`&)^`.&<`4``.L%N`````"+
-M7"00BW0D%(M\)!B#Q!S#C70F`(V\)P````!3@^P(BUPD$(M4)!2)V.B-XO__
-MBX,\!0``B00DZ/S___^#Q`A;PXUV`(V\)P````"#[!R)7"00B70D%(E\)!B+
-M="0@C9Z$"0``B1PDZ/S___^$P`^%W0```(D<).C\____B<*)\+N"____C;8`
-M````@+@R!0``_W47.)[8````<R"(GM@```#K&(VT)@````"#PP&#P`&`^X8/
-MA)<```#KSX#[A@^$C`````^VPXB4!K`$```/M\)I^+````")^`.&C`4``(D$
-M).C\____BY:,!0``#[;#9HE$%R2`?CD!=0V+AHP%``!FQT0',/__BX:,!0``
-MQD0')@"+AHP%``!FQT0',@``BX:,!0``9L>$!Y```````,=$)`0`````BX8\
-M!0``B00DZ/S___^)^`.&C`4``.L%N`````"+7"00BW0D%(M\)!B#Q!S#D(UT
-M)@!64X/L%(MT)""+1"0D#[=`)`^VG#"P!```QH0PL`0``/\/M]N)7"0$C8:$
-M"0``B00DZ/S___]IV[````")V`.&C`4``(!X-/]T#(E$)`2)-"3H_/___\=$
-M)`0`````BX8\!0``B00DZ/S___^#Q!1;7L.-M"8`````C;PG`````%.#[`B+
-M7"00BT0D%`^V4#,/MH0:L`0``,:$&K`$``#_#[?`B40D!(V#K`D``(D$).C\
-M____QT0D!`````"+@SP%``")!"3H_/___X/$"%O#4X/L"(M<)!2`>RC_=!J-
-M0UB)1"0$BU0D$(M"%(D$).C\____QD,H_X/$"%O#C78`4X/L"(M<)!2`>TS_
-M=!V-@^P```")1"0$BU0D$(M"%(D$).C\____QD-,_X/$"%O#@^P<B5PD#(ET
-M)!")?"04B6PD&(M<)""+;"0D#[=%'`^VO`.P!```#[?':?`H`0``B?`#@W`%
-M```%Z````(E$)`2)'"3H_/___P^W51R+A).P`@``A<!T&(-X<`!U$L>$D[`"
-M````````C;0F``````^W11S&A`.P!```_P^WQXE$)`2-@UP)``")!"3H_/__
-M_XGP`X-P!0``@'A"_W0,B40D!(D<).C\____B6PD!(D<).C\____BX-P!0``
-MQD0&)@"+@W`%``#&1`8G`8M<)`R+="00BWPD%(ML)!B#Q!S#ZPV0D)"0D)"0
-MD)"0D)"0@^P<B5PD#(ET)!")?"04B6PD&(ML)""+="0D9H%^).$!#X6Y````
-M#[9&)H/H$3P!#X>J````#[=&$&8]A0`/AU0!```/M\`/MH0%L`0``(N5C`4`
-M`#S_#X0[`0``#[;`:<"P````C1P"@&LI`8U[%(D\).C\____B<(Y\'5"B5PD
-M!(DL).C\____.WL4#X0%`0``QT-8`!)Z`,=#8`````")6V2-0UB)1"0$BT44
-MB00DZ/S____&0R@`Z=D```"0BT,4B5`$B0*)>@2)4Q2+%HM&!(E"!(D0Z;L`
-M``"-=@`/MT809CV%``^'J@````^WP`^VE`6P!```BXUP!0``BT8D)?___P`]
-MX0$0``^$A@```('Z_P```'1^:<(H`0``C1P!@&M/`8U[$(D\).C\____B<(Y
-M\'5(B5PD!(DL).C\____.WL0=$_'@^P`````$GH`QX/T`````````(F;^```
-M`(V#[````(E$)`2+112)!"3H_/___\9#3`#K&HGVBT,0B5`$B0*)>@2)4Q"+
-M%HM&!(E"!(D0BUPD#(MT)!"+?"04BVPD&(/$',.-="8`@^P<B5PD#(ET)!")
-M?"04B6PD&(M\)""+;"0D#[=5'HG09L'H!0^WV`^W\HGQ@^$?N/[____3P(G!
-M(42?5&:!^O\/=$F-!+4``````X?$!0``@S@`=#?'```````AC)_(!0``B70D
-M!(V'-`D``(D$).C\____B6PD!(D\).C\____B6PD!(D\).C\____BUPD#(MT
-M)!"+?"04BVPD&(/$',/K#9"0D)"0D)"0D)"0D)"#[!R)7"00B70D%(E\)!B+
-M?"0@BW0D)&:!?B3A`0^%D@````^V1B:#Z!$\`0^'@P````^W1A"Z_P```&8]
-MA0!W"P^WP`^VE`>P!```:<*P````B<,#GXP%``"`>RC_=3P/ME9HN`@```"$
-MTG0#C002#[;`:<!`0@\`B4-8QT-@`````(E;9(U#6(E$)`2+1Q2)!"3H_/__
-M_\9#*`"+4QB)<QB-0Q2)!HE6!(DR@$,I`>F?````#[=&$+G_````9CV%`'<+
-M#[?`#[:,![`$``"+EW`%``"+1B0E____`#WA`1``='!IP2@!``"-'`*`>TS_
-M=4T/ME9HN`@```"$TG0#C002#[;`:<!`0@\`B8/L````QX/T`````````(F;
-M^````(V#[````(E$)`2+1Q2)!"3H_/___\9#3`"0C70F`(M3%(ES%(U#$(D&
-MB58$B3*`0T\!BUPD$(MT)!2+?"08@\0<PXVV`````(V_`````%575E.#["R+
-M1"1$#[=0$&:!^H4`#X<?`P``#[?"BUPD0`^VC`.P!```N/____^`^?]T8F:#
-M^G]W'0^VP8M<)$"+DW`%``!IP"@!``"+1!`L#[9`!.L_9H'Z@0!W'0^VP8M<
-M)$"+DZ@%``!IP!0-``"+1!`(#[9`!.L;#[;!BUPD0(N3C`4``&G`L````(M$
-M$%0/MD`$#[;`BU0D0`^VK`(V!0``:\5<C80"0`$``(E$)""+DJ@%```/ML%I
-MP!0-```!PHE4)!R+1"1$BU`T#[9"`3P2="<\D0^%*@(``&O%7+D`````BU0D
-M0("\`DH!````#X3:`0``Z7$!``!KQ5P#1"1`BXA``0``B4PD*`^V6@F(7"0F
-M#[92&HA4)">[`````("X2@$```!T9K\`````:_5<BT0D0(VL,'@!``"0B2PD
-MZ/S___^)PXM4)$"-!!:+D'P!``")F'P!``")*XE3!(D:BTPD'#E+,'43#[9#
-M38M4)$0Z0A5T&(VV`````(/'`8GYBT0D0#B,,$H!``!WKHM4)$2+0E"%P'00
-MB40D!(M,)"B)#"3H_/___XM$)$2)1"0$BU0D*(D4).C\____#[:#E@```(U0
-M`8B3E@```#P#=SB`?"0G`'4QQT0D$`````#'1"0,`@```(M,)$0/MD$5B40D
-M"(M#,(E$)`2+7"0@B1PDZ/S____K-HU"`8B#E@```(#Z`G8H@'PD)P!U(<9#
-M)P+&0R;_@&,H_HE<)`2+1"0HB00DZ/S____I'P$```^V1"0GB40D#`^V1"0F
-MB40D"(M4)!R)5"0$BTPD((D,).C\____Z?0```"^`````&O=7(M$)$"-O!AX
-M`0``B3PDZ/S___^)P8M4)$"-!!.+D'P!``")B'P!``").8E1!(D*BT0D'#E!
-M,'42#[9!38M4)$0Z0A5T%Y"-="8`@\8!B?"+5"1`.(0:2@$``'>O#[91)(G0
-M@^`&@_@&=2CVP@%T(XE,)`R+7"1$#[9#%8E$)`B+03")1"0$BT0D((D$).C\
-M____BU0D1(M"4(7`=!")1"0$BTPD0(D,).C\____BUPD1(E<)`2+1"1`B00D
-MZ/S____K*8M4)$`/MJHU!@``:\5<C80"0`$``(E$)""+DJ@%``"X[`8-`.E?
-M_?__@\0L6UY?7<.-M@````!55U93@^P,BVPD((M\)"2+7"0HQD,G`<9#)@")
-M7"0(QT0D!`8```")/"3H_/___X-[,`!T$HM3"(M##(E"!(D0BT,P@&@P`8![
-M3P!T'8UV`(DL).C\____QP0D`0```.C\____@'M/`'7FBY/D````A=)T&\=$
-M)`@!````#[:#V0```(E$)`2)%"3H_/___XM3,(72=!C'1"0(`0````^V0TV)
-M1"0$B10DZ/S___^+<R"%]@^$H````(-^<``/A8@```"#?G0`#X5^````]D,H
-M!'4?B2PDZ/S____'1"0(`0```(M#((E$)`2)+"3H_/___XM3(`^V0@*)1"0(
-M#[9"`8E$)`3'!"0*`0``Z/S___^+0R")1"0(BX4\!0``B40D!,<$)`$```#H
-M_/___XM#((E$)`B+A3P%``")1"0$QP0D!@```.C\____QT,@`````,=&8```
-M``"+4S2%TG0,#[9#3<=$@CP`````BQ.+0P2)0@2)$(!O"@&)7"0$B2PDZ/S_
-M__^`?P7_=$Z`?PH`=#B[`````(UW.(VV`````(DT).C\____BU<\B4<\B3")
-M4`2)`H!X)O]U"H/#`3A?"G8'Z]LX7PIW$,9'!?^)?"0$B2PDZ/S___^#Q`Q;
-M7E]=PXVT)@````"-O"<`````55=64X/L'(M\)#C&1R<!QD<F`(E\)`C'1"0$
-M!@```(M$)#2)!"3H_/___X-_,`!T$HM7"(M'#(E"!(D0BT<P@&@P`8!_3P!T
-M)8VT)@````"+5"0PB10DZ/S____'!"0!````Z/S___^`?T\`=>*+E^0```"%
-MTG0;QT0D"`$````/MH?9````B40D!(D4).C\____BU<PA=)T&,=$)`@!````
-M#[9'38E$)`2)%"3H_/___XM?((7;#X0H`0``]D<H!'4GBTPD,(D,).C\____
-MQT0D"`$```"+1R")1"0$BT0D,(D$).C\____BU<@#[9'3XE$)!`/MH*8````
-M#[92`HT$@`^VA`(`````B40D#(M4)#`/MD(BB40D"`^V0B&)1"0$QP0DK`,`
-M`.C\____BT<@B40D"(M,)#"+@3P%``")1"0$QP0D`0```.C\____BU-PA=(/
-MA$L!```/MT<<BTPD,,>$@;`"````````QT-P`````,=$)`C_____B5PD!(M#
-M>(D$)/_2Z1@!```/MT<<BTPD,,>$@;`"````````QT-T`````(M#>(D$)/_2
-M]D<H`G0ABT<@B40D"(M4)#"+@CP%``")1"0$QP0D!@```.C\____QT<@````
-M`,=#8`````"+5S2%TG0,#[9'3<=$@CP`````BQ>+1P2)0@2)$(M,)#0/ME$*
-M@^H!B%$*BT<TA<!T!V:#>#("=7"$TG1LO@````"+;"0T@\4XB?:)+"3H_/__
-M_XG#BU0D-(M"/(E:/(DKB4,$B1B%VW0Q]D,H`G0KBT,@B40D"(M,)#"+@3P%
-M``")1"0$QP0D!@```.C\____@&,H_8VV`````(/&`8GPBU0D-#A""G>BB7PD
-M!(M,)#")#"3H_/___X/$'%M>7UW#BU-TA=(/A=W^___I^O[__XUV`(V\)P``
-M``"#["R)7"0<B70D((E\)"2);"0HBUPD,(M#+(LHB2PDZ/S___^)QH7`#X3,
-M````B2PDZ/S___^)QX7`=1C&@[4````!B70D!(DL).C\____Z:8```#&1B2@
-MC58EN`````#&!!``@\`!@_@%=?3&1BH`QD8K`,9&+`#&1BV(QD8N`,9&+P#&
-M1A6K#[=#'&:)1A");AC'1F0(````QT8@B````(M'"(E&-`6(````B48XQD8<
-M)(E^4,=&;`````"-7CS'1"0$`````(D<).C\____QT0D#(@```"+1PR+5Q")
-M1"0$B50D"(D<).C\____B70D!(DL).C\____BUPD'(MT)""+?"0DBVPD*(/$
-M+,.)]E93@^P4BW0D((V>K`D``(D<).C\____A,`/A?$```")'"3H_/___XG"
-MN8#___^`OC`%``#_=!*`OC$%``#_#X7,````N8'___\XCM<```!S!HB.UP``
-M`(#Y@@^$L`````^VP8B4!K`$```/M\)IV!0-``")V@.6J`4``+@`````Q@00
-M`(/``3T4#0``=?*)V@.6J`4``(U"$(E"$(G:`Y:H!0``C4(0B4(4B=H#EJ@%
-M``"-0AB)0AB)V@.6J`4``(U"&(E"'(G:`Y:H!0``C4(HB4(HB=H#EJ@%``"-
-M0BB)0BR+AJ@%``"(3`,SQT0D!`````"+ACP%``")!"3H_/___XG8`X:H!0``
-MZPF-="8`N`````"#Q!1;7L.0C70F`%.#[`B+1"00BY@4"@``!30)``")!"3H
-M_/___XG!#[?`P>`&C108BT0D%(D0N`````#&!!``@\`!@_A`=?0/M\&#Q`A;
-MPXUT)@"-O"<`````@^P,BT0D$(V0!`$``+D`````.9`$`0``=`J)%"3H_/__
-M_XG!B<B#Q`S#D)"0D)"0#[9$)`AIP'0$```%=$4``(M4)`2)`L.)]HV\)P``
-M``"+5"0(#[9,)`P/MT1*<(/``6:)1$IP#[92`@'0#[?`PXM4)`2X`0```(VT
-M)@````"`NCLR```!=!*#P`&!PJ0```"#^"!UZ6:X___SPXUV`%93BW0D#`^V
-M3"00#[9<)!2)\K@!````.(HX,@``=1@XFCDR``!U$&G`I````,:$!I<Q```!
-MZPZ#P`&!PJ0```"#^"!UTEM>PY"-M"8`````55=64X/L"(M\)"`/MD0D)(A$
-M)`>+;"0<BU0D*,8"_@^V702(7"0#A-MT5XGJN0````"^`````+@`````C70F
-M`#FZY$<``'4HB?,Z7"0'=19IP'0$```/MH0%V$4``(M4)"B(`NL<@\8!C;0F
-M`````(/!`8/``8'"=`0``#I,)`-UOH/$"%M>7UW#C;8`````55=64X/L'(ML
-M)#0/MEPD/(M\)#"`?"0X`708#[9W!+L`````B?"$P`^$(P$``.GX````QD0D
-M&P"#?"1```^$TP```(M4)$")5"04#[97!,9$)!L`A-)T*XGXQD0D&P"Y````
-M`#FHY$<``'4'.-ET$X/!`8!$)!L!!70$```X5"0;=>$/MFPD&VG==`0``(V$
-M'W1%``#'1"0(9````(E$)`2+1"04B00DZ/S___^`O!]T10```'1?O@````")
-MW8V4'W!%``")5"00C;0F`````(GR#[;"P>`$BU0D%(U<`F"-2P2-A"C@1P``
-MC00'C5`(BT`(B4,$BT($B4$$BT((B4$(BT(,B4$,@\8!B?"+5"00.$($=[H/
-MMD0D&VG`=`0```^VA`=T10``ZRF)^KD`````NP`````YJN1'```/E,`!PX/!
-M`8'"=`0``(GP.,%UY@^VPX/$'%M>7UW#C70F`%575E.#[`0/MD0D)(A$)`,/
-MMUPD*&:)'"2+?"08O@````")]6G6.`P``(M$)!PY1#H4=7"-3!<4N`````"-
-M=@")PP^V41R$TG0&@/KP=4B0:<4X#```C11;C130C0PZBUPD'(E9'(M$)"")
-M02"-01`/MQPD9HE8%@^V7"0#B%@4B<*+7"0LBP.)0AB+0P2)0AS&03#_ZPV#
-MP`&#P1@]@@```'6<@\8!@_X$#X5R____@\0$6UY?7<.0C;0F`````%575E.#
-M[`R+;"0DBW0D((!^!`!T2;\`````C;8`````B?@/MMAIPW0$``"`O`;810``
-M_70?QT0D"`@```");"0$C80&T$4``(D$).C\____A,!U#X/'`8GX.$8$=\*[
-M_P```(G8@\0,6UY?7<.-=@!3@^P(BUPD$(M$)!2)1"0$B1PDZ/S___^Z"0``
-M`#S_=!$/ML!IP'0$```/MI0#>D4``(G0@\0(6\.-M"8`````55=64X/L#(M\
-M)""+;"0H#[9T)"P/MUPD,(GYC9?T,```N`````#&!!``@\`!/9````!U\L:!
-M]3```!/&@?0P``!`#[;'B('Z,```B)G[,```B?"(@?TP``#'@9`Q``!0\P``
-MB;F,,0``BT5<B8&$,0``BT5@B8&(,0``C8'T,```B40D!(M$)"2)!"3H_/__
-M_X/$#%M>7UW#C;0F`````%575E.#[$P/MD0D;(A$)#\/MU0D<&:)5"0@BU0D
-M8(G7N`$```")Q8G&@+H[,@```0^%W````&G`I`````'XC9"0,0``QD('`(FX
-MC#$```^V2@9IP:0```"-E`?T,```N`````#&!!``@\`!/9````!U\FG9I```
-M`(T,.XV1\#```,9"!9#&0@1`#[=$)"`/ML2)1"0<B$(*#[9$)""(@?LP```/
-MMDPD/XA*#8M,)'2+`8E"%(M!!(E"&&G6I````(T$.L>`D#$``%#S``"+3"1@
-MB8B,,0``C907@#$``(M,)&B+05R)0@2+06")0@B)Z@^VPFG`I````(V$!_0P
-M``")1"0$BTPD9(D,).C\____ZQ2#P`&!PJ0```"#^"`/A0'___^P`8/$3%M>
-M7UW#B?955U93@^P,#[9L)"@/MGPD+(M,)"")SK@!````C70F`(G"@+D[,@``
-M`0^%P@```&G`I````(V$!I`Q``")Z8A(!(G[B%@%QD`'``^V6`9IPZ0```"-
-MC`;T,```N`````#&!`@`@\`!/9````!U\FG#I````(V$!O`P``#&0`40QD`$
-M0(GYB$@-:=*D````#[:,%I8Q``!IR:0```"-!#''@)`Q``!0\P``BUPD((F8
-MC#$``(V<%H`Q``")Z@^VPFG`=`0``(V4!L!%``"+0A")0P2+0A2)0PB-A`[T
-M,```B40D!(M,)"2)#"3H_/___^L4@\`!@<&D````@_@@#X4=____L`&#Q`Q;
-M7E]=PXUV`%93@^P4BW0D(`^V1"0HB?/&AI<Q````C8[T,```N@````#&!`H`
-M@\(!@?J0````=?'&@_4P```!QH/T,```0,>#D#$``%#S``")LXPQ```/ML!I
-MP'0$``"-E`/`10``BT(0B8.$,0``BT(4B8.(,0``C8/T,```B40D!(M$)"2)
-M!"3H_/___X/$%%M>PXUV`%93@^P4BW0D(`^V1"0HB?/&AI<Q````C8[T,```
-MN@````#&!`H`@\(!@?J0````=?'&@_4P````QH/T,```0,>#D#$``%#S``")
-MLXPQ```/ML!IP'0$``"-E`/`10``BT(0B8.$,0``BT(4B8.(,0``C8/T,```
-MB40D!(M$)"2)!"3H_/___X/$%%M>PXUV`%575E.#[$P/MGPD:`^V5"1L#[9$
-M)'"(1"0GBVPD8(GY#[;)B4PD*&G!=`0``("\!=A%``#]#X0Y"0``@/H0#X2Y
-M`@``@/H0=QR$TI"-="8`#X2A````@/H!#X45"0``D.D+`0``@/KB=!N`^O^-
-M=@!T*8#ZD`^%^0@``)"-="8`Z38'``"Y`````(!]!`")]@^%.@@``.E="```
-M:40D*'0$``#&A`7810``_X"]ES$```%U+8M<)"B)7"0(BW0D9(ET)`2+?"1@
-MB3PDZ/S___^%P`^%G`@``(!%!@'IDP@``(M$)"C&1`4'`8M4)&2)5(4,Z7T(
-M``"`O9<Q```!=5J-C?0P``!I1"0H=`0```'H#[91"8B0=D4```7010``#[91
-M"H/B`8A0"<9`"`"+3"0HB4PD"(M<)&2)7"0$BW0D8(DT).C\____A<`/A2,(
-M``"`108!Z1H(``"+?"0HQD0]!P&+1"1DB42]#.D$"```:70D*'0$``"-/"X/
-MMH4F,0``B(?&10``#[>%)#$``&:)A#7$10``C90UL$4``(N%'#$``(E"!(N%
-M(#$``(E""(V4-8!%``"+A0`Q``")0@2+A00Q``")0@B-G#6010``C4L$C94(
-M,0``BX4(,0``B4,$BT($B4$$BT((B4$(BT(,B4$,BX48,0``B80UK$4``,:'
-MV$4```&`?08?#X1B!P``NP````!I1"0H=`0```'HC;!P10``C;C`10``ZU20
-M#[;#B40D#(M4)"B)5"0(BTPD9(E,)`2+1"1@B00DZ/S___^%P'01:40D*'0$
-M``"(G`7'10``ZR"#PP&`108!.%X&#Y3`@^@!(=B(1P>`?08?=`4Z7@9RJ,:%
-MES$```$/MDT$A,D/A-D&``"Z`````(!]!P%T#.M$#[;0@'P5!P%U/\9$%0?_
-MQT0D%`````#'1"00`````,=$)`S_````B50D"(M$E0R)1"0$BU0D8(D4).C\
-M____Z8@&``"X`````(/``3C(=;#I=P8``(M,)'2)3"0P@\$8B4PD+(U,)$"+
-M7"0PBT,8B40D0(MT)"R+1@2)1"1$:40D*'0$``"--"B-EM!%``#&0@@0]D,,
-M<`^$90,``(N&W$4``(7`#X2(````#[9:"L=$)`@(````B4PD!(/`7(D$).C\
-M____A,!U:8M$)##V0`\/=%^+AMQ%``"%P'15B<:`?F4`=$T/MMN)7"0(B70D
-M!(DL).C\____BU0D+(E4)!0/M\")1"00B5PD#(ET)`B+3"1DB4PD!(M<)&")
-M'"3H_/___P^V7F:+1FB%P'0$B<;KK8MT)#`/MD8/J`T/A/T```!I5"0H=`0`
-M``^VC!5T10``@/D?#X?D````J`AT$@^VP<'@!`'0QH0%Z$<```;K&`^VP<'@
-M!&E4)"AT!````=#&A`7H1P``!P^V\8GRP>($:5PD*'0$```!VHV,%>!'``#&
-M00D`BWPD,`^V1P^(00N+1"1`B4$0BT0D1(E!%`^V1PF(00H/MD<-@^`/#[:4
-M'7I%```XT'8"B=")PH/B#P^V00R#X/`)T(A!#(GPP>`$:50D*'0$```!T(V,
-M!>!'``"+7"0P#[9#*8/@#P^VE!5Z10``.-!V`HG0P>`$#[91#(/B#PG"B%$,
-M:40D*'0$``"`A`5T10```>G"`0``J`(/A+H!``"-1"1`B40D!(DL).C\____
-MB<(\_P^%7P$```^V302$R70X#[:%V$4``#S_="VZ`````#S]=1OK(@^VPFG`
-M=`0```^VA`7810``//]T$CS]=`Z#P@$XRG7@ZP6Z``````^VPFG`=`0``(V,
-M!71%``"X`````,8$"`"#P`&#^&1U]`^VTHE4)#1ITG0$``"-'"J)^0^VP6G`
-M=`0``(V$!71%``")@]Q%``"-C!7`10``:70D*'0$``"-E#7`10``BT(0B4$(
-MBT(4B4$,BWPD9(F[Y$<```'NBX;@10``B8/@10``QH/810``_XV#<$4```^V
-M2`N+?"0P#[97"8B4"WQ%``"`0`L!#[:.>D4```^V5PV#X@\XRG8"B<J(4`II
-M5"0T=`0``(V,%<!%``"+1"1`B4$0BT0D1(E!%`'JBTPD,`^V00^(@G=%```/
-MMEPD)XB:VD4```^V104Z101U!,9%!0"`104!BW0D-,9$-0<!BWPD9(E\M0SK
-M06E$)"AT!```#[;2:<IT!```C90-=$4``#F4!=Q%``!T((T<*8V#<$4```^V
-M2`N+="0P#[96"8B4"WQ%``"`0`L!BWPD,`^V1PF)1"0(BT0D*(E$)`2)+"3H
-M_/___VE$)"AT!```@+P%QT4````/A)P```"`?08?=7#IC0(``,:&V$4``!`/
-MMD,'B40D#(M4)"B)5"0(BTPD9(E,)`2+1"1@B00DZ/S___^%P`^%6@(``(!%
-M!@$/MDL'#[;!@\`!#[:6=D4``#G0=0W&0P<`Z3@"``"-="8`C4$!B$,'@'T&
-M'P^$)`(``.L1:40D*'0$``"--"B-GL!%```/MD,'.H9V10``#X)T____Z?P!
-M``"`?08`#X7R`0``QT0D%`````#'1"00`````,=$)`R0````BU0D*(E4)`B+
-M3"1DB4PD!(M<)&")'"3H_/___^FY`0``OP````!IQS@,``"+="1D.70H%'5V
-MC5P%,+X`````B40D((UV`(`[_W53@'T&'P^$A0$``(T$=HM4)""-1,(0C40%
-M&(E$)!0/MT/VB40D$`^V0_2)1"0,BT/PB40D"(M,)&2)3"0$BT0D8(D$).C\
-M____A<!U!X!%!@'&`_"#Q@&#PQB!_H(```!UFH/'`8/_!`^%;O___X!]!@`/
-MA1@!```/MDT$A,D/A-@```"Z`````(!]!P%T#.M$#[;0@'P5!P%U0<9$%0?_
-MQT0D%`````#'1"00`````,=$)`S_````B50D"(M$E0R)1"0$BU0D8(D4).C\
-M____Z;L```"X`````(GV@\`!.,AUKNMWC;0F``````^VP6G`=`0``(V4!=!%
-M```/MD((//UT"#S_=`3&0@C^@\$!.$T$=]AI1"0H=`0``(N<!>!%``"_````
-M`(UT)@"`?"\8`749QD0O&`"+1"\4B40D!(M,)&")#"3_TXUV`(''.`P``('_
-MX#```'0VZ]#'1"04`````,=$)!``````QT0D#.(```"+7"0HB5PD"(MT)&2)
-M="0$BWPD8(D\).C\____@\1,6UY?7<.-="8`@^PLB5PD((ET)"2)?"0HBW0D
-M-(N>F````(![!@`/A(0!``"-AI````")1"0$B1PDZ/S___^)P3S_#X1H`0``
-MB?</MD8!/`%T;#P!<A@\$`^$K````#R0#X5*`0``C78`Z?H```"`NY<Q````
-MC70F``^%,0$``,:#ES$```&`:P8!QT0D%`````#'1"00`````,=$)`P`````
-M#[;!B40D"(M$)#")1"0$B1PDZ/S____I\@```("[ES$````/A>4```#&@Y<Q
-M```!@&L&`<=$)!0`````QT0D$`````#'1"0,`0````^VP8E$)`B+1"0PB40D
-M!(D<).C\____Z:8```"Z`````#J,&C@R``!U$0^VA!HY,@``.D<)=!*-="8`
-M@<*D````@?K<$P``==B`:P8!B7PD%`^V1PF)1"00QT0D#!`````/ML&)1"0(
-MBT0D,(E$)`2)'"3H_/___^M(#[:&H@```&G`I````,:$`Y<Q```!@&L&`<=$
-M)!0`````QT0D$`````#'1"0,D`````^VP8E$)`B+1"0PB40D!(D<).C\____
-MBUPD((MT)"2+?"0H@\0LPXGVC;PG`````%93BU0D$`^V="04BUPD#(72=`^)
-MV8G0Q@$`@\$!@^@!=?6)$X'J=$4``,'J`KA9MOER]^+!Z@>(4P2)\#C0<P.(
-M0P2`>P0`="6Z`````(GV#[;"QD0#!_]IP'0$``#&A`/810``_8/"`3A3!'?B
-MQD,&`,9#!0")V+H`````C78`QH"7,0```8B0EC$``(/"`06D````@_H@=>9;
-M7L.-=@!75E.+?"04BTPD$(!Y!``/A($```"[``````^V\VG&=`0``#F\`>1'
-M``!U8K@`````.)P(.#(``'4(QH0(.S(```$%I````#W<$P``=>-IQG0$``#'
-MA`'D1P```````(V4`71%``"X`````)"-="8`Q@00`(/``8/X9'7T:<9T!```
-MQH0!V$4``/V`:04!@\,!.%D$=X2)R[X`````.7L4=2W'0Q0`````QD,8`&G&
-M.`P``(U$`12Z`````(UT)@#&0!P`@\(!@\`8@/J"=?&#Q@&!PS@,``"#_@1U
-MP%M>7\/K#9"0D)"0D)"0D)"0D)!55U93@^P<#[9$)#R(1"0:BUPD,`^V0P4Z
-M0P1U!,9#!0`/ME,%B%0D&XG=B=BY`````(G.B<^+4!0[5"0T=4IIP3@,``#&
-M1`,8`0^V4P3&1"0;`(32=%O&1"0;`(M\)#0YO>1'``!U#@^VA=A%``"#P`,\
-M`78\@$0D&P&!Q70$```X5"0;="OKTX72=15IQS@,```!V(M4)#2)4!3&0!@!
-MZQ"#Q@&#P0$%.`P``(/Y!'6`B?(/ML)IP#@,``"-1`,<N@````#&!`(`@\(!
-M@?H"#```=?$/MG0D&XM\)#2)?+,,:<9T!```C90#=$4``+@`````Q@00`(/`
-M`8/X9'7T:<9T!```C90#Y$4``+@`````Q@00`(/``3T``@``=?)ISG0$``"-
-M%!F+1"0TB8+D1P``BT0D0(F"X$4``,:"V$4``/_'@MQ%````````C8P+P$4`
-M`(M\)#B+!XE!$(M'!(E!%`^V1"0:B()Z10``QT0D%`````#'1"00`````,=$
-M)`S_````B70D"(M4)#2)5"0$BWPD,(D\).C\____@$,%`8/$'%M>7UW#D)"0
-MD)!64XM4)`R+`HLP#[98*X3;=#</ME()N0````#VP@%T"NLGB=#3^*@!=0>#
-MP0$XV77Q@/D#=A@/ML&-A(;0`0``BP"C`````.L6N0`````/ML&-A(;0`0``
-MBP"C`````,'H%(/@`5M>PY"-M"8`````55=64X/L!(M$)!B+$`^V>BN]"@``
-M`(GYA,ET20^V<`F[`````+T*````N0````"0B?#3^*@!=!X/MH*V"P``@^`#
-M@\`(B$0D`XGH.D0D`W8%#[9L)`.#PP&#P0&#PD2)^#C#=<N)Z@^VPH/$!%M>
-M7UW#C;0F`````(V\)P````!55U93@^P$BT0D&(L0#[9Z*[T(````B?F$R71)
-M#[9P";L`````O0@```"Y`````)")\-/XJ`%T'@^V@K8+``"#X`.#P`B(1"0#
-MB>@Z1"0#<P4/MFPD`X/#`8/!`8/"1(GX.,-URXGJ#[;"@\0$6UY?7<.-M"8`
-M````C;PG`````%.+7"0(#[8#P.@$B<*#X@</MDL"]L$$=`.`S@(/MD,#J`1T
-M!H'*```"`/;!"'0#@,X(J`AT!H'*```(`/;!`G0#@,X$J`)T!H'*```$``^V
-M0Q3!X!@)T%O#C;0F`````(/L!(M$)`B)!"3H_/___X/$!,.-M@````"-O"<`
-M````BTPD!(N!4`4``"7___\`N@`````]4`&3`'45#[:!4P4``,#H!#P,#Y3`
-M#[;0C78`B=##C;8`````C;PG`````%.)PX72?D`/M@B$R70%@/D@=2VX````
-M`.L6C;8`````#[8,&(3)=`B`^2!U$XUV`(/``3G0=>GK#HVT)@````"X````
-M`.L%N`$```!;C78`P^L-D)"0D)"0D)"0D)"0D%.+7"0(#[9#`P^V4P+!X@@)
-MT,'@$`^V2P$/MA/!X@@)T0G(6\.-="8`C;PG`````%=64XG&B=.)SX7)=!ZY
-M``````^V%@^V1@&(`XA3`8/#`H/&`H/!`3GY=>=;7E_#D(/L'(E<)!")="04
-MB7PD&(MT)""+?"0D#[='$+K_````9CV%`'<+#[?`#[:4!K`$```/M])ITK``
-M```#EHP%``"+GC@*```/MD(TP>`(C80#3`@``(L(B0T`````@>'_````#[9"
-M-,'@"(V<`T0(``"+`Z,`````P>`("<B)@J````!FQX*<``````")?"0$B30D
-MZ/S___^+7"00BW0D%(M\)!B#Q!S#B?:-O"<`````@^P<B5PD#(ET)!")?"04
-MB6PD&(ML)"`/MGPD)(MU`(GX/`-V,`^VV,'C`XV$'C`"``#'``P```#'!"00
-M)P``Z/S___^-A!XT`@``BS")-0````#K,(GX#[;8P>,#C80S4`(``,<`#```
-M`,<$)!`G``#H_/___XV<,U0"``"+,XDU`````(GX#[;(B<C!X`:-!(B-E`60
-M"P``#[9:!8/C_(A:!8GP)0``/P`]```0`'4/B=B#R`*(0@7K&9"-="8`B<C!
-MX`:-%(B)V(/(`8B$%94+``"+7"0,BW0D$(M\)!2+;"08@\0<PY"-M"8`````
-M55=64X/L'(M$)#2+5"0PBQ*)5"08BQ+&0"4`QD`D!<9`)P:+3"0PB4@LN0``
-M``"]`````(V"``(``(E$)!2!P@0"``")5"00ZQ>-M@````"+5"0P#[9""=/X
-MJ`%U#(/!`8M$)!@Z2"MRYH#Y`W9Q#[;9P>,#BWPD%`'?QP<L````QP0D$"<`
-M`.C\____`UPD$(LSB34`````QP<D````QP0D$"<``.C\____BP.C`````,'@
-M"('F_P````G&QP<@````QP0D$"<``.C\____BQN)'0````#K;XVT)@`````/
-MMMG!XP.+?"04`=_'!RP```#'!"00)P``Z/S___\#7"00BS.)-0````#'!R0`
-M``#'!"00)P``Z/S___^+`Z,`````P>`(@>;_````"<;'!R````#'!"00)P``
-MZ/S___^+&XD=`````('^`0%IEG47BU0D,(!*"`:)V,'H$#Q0#Y3`#[;`ZT:!
-M_@$!``!U$8G8P>@0/%`/E,`/ML#K+XGVQP0DB!,``.C\____@\4!B>F`^01W
-M"KD`````Z<'^__^)V,'H$#Q0#Y3`#[;`@\0<6UY?7<.-="8`C;PG`````%57
-M5E.#[`R+="0@BVPD)(M&5(LX9H.^G`````!T,HGKQP0DZ`,``.C\____A>UT
-M!8/[`78;B3PDZ/S___]F@[Z<`````'0)@^L"Z]2-="8`@\0,6UY?7<.0C;0F
-M`````(/L'(E<)`R)="00B7PD%(EL)!B+7"0L#[9L)"0/MWPD*`^V1"0PB$0D
-M"XM4)""+0E2+,(DT).C\____B<+&0"3AQD`E`<9`)A*X#P```(GIA,EU"(M,
-M)"`/MD$KB$(GB?B(0BB)^0^VQ8A"*0^VQXA"*HG8P>@0B$(KB=C!Z!B(0BR(
-M6BV+3"0@#[=!)&:)0A")<AC'0B``````QT(T`````+@`````@'PD"P!U!;@`
-M````B4)LB50D!(DT).C\____BUPD#(MT)!"+?"04BVPD&(/$',.-=@"-O"<`
-M````@^P<B5PD#(ET)!")?"04B6PD&(M<)"P/MFPD)`^W?"0HBU0D((M"5(LP
-MB30DZ/S___^)PL9`).'&0"4!QD`F$K@/````B>F$R74(BTPD(`^V02N(0B>)
-M^(A"*(GY#[;%B$(I#[;'B$(JB=C!Z!"(0BN)V,'H&(A"+(A:+8M,)"`/MT$D
-M9HE"$(ER&,="(`````#'0C0`````QT)L`````(E4)`2)-"3H_/___XM<)`R+
-M="00BWPD%(ML)!B#Q!S#55=64X/L'(M\)#`/MD0D-(A$)!L/MVPD.(7_#X3N
-M````BS>%]@^$Y`````^V7BN%VWY#BT=4#[90";D`````]L(!=`KK,(G0T_BH
-M`74'@\$!.=EU\8/Y`WXABP8%T`$``(T$B(L`HP````#!Z!2#\`&#X`'K'[D`
-M````BP8%T`$``(T$B(L`HP````#!Z!2#\`&#X`&$P'5V@+^L`````'4&@'\F
-M`'5G#[=')("\!K`$``#_=%G&1R8E9L>'G`````$`#[?%#[94)!O'1"00`0``
-M`(M,)#R)3"0,B40D"(E4)`2)/"3H_/___\=$)`0%````B3PDZ/S____&1R8`
-M9H._G``````/E,`/ML#K!;@`````@\0<6UY?7<.-="8`@^P<B5PD#(ET)!")
-M?"04B6PD&(M\)"`/MFPD)`^W7"0HBT=4BS")-"3H_/___XG"QD`DX<9`)0'&
-M0"81N`\```")Z83)=00/MD<KB$(GB%HH#[;'B$(I#[=')&:)0A")<AC'0B``
-M````QT(T`````,=";`````")5"0$B30DZ/S___^+7"0,BW0D$(M\)!2+;"08
-M@\0<PXGVC;PG`````%575E.#[!R+?"0P#[9$)#2(1"0;#[=L)#B%_P^$\P``
-M`(LWA?8/A.D````/MEXKA=M^0XM'5`^V4`FY`````/;"`70*ZS")T-/XJ`%U
-M!X/!`3G+=?&#^0-^(8L&!=`!``"-!(B+`*,`````P>@4@_`!@^`!ZQ^Y````
-M`(L&!=`!``"-!(B+`*,`````P>@4@_`!@^`!A,!U>X"_K`````!U!H!_)@!U
-M;`^W1R2`O`:P!```_W1>QD<F)6;'AYP````!``^WQ0^V5"0;QT0D#`$```")
-M1"0(B50D!(D\).C\____QT0D!`4```")/"3H_/___\9')@!F@[^<`````'43
-MBX>@````BU0D/(D"N`$```#K!;@`````@\0<6UY?7</K#9"0D)"0D)"0D)"0
-MD)"#[!R)7"0,B70D$(E\)!2);"08BWPD(`^V;"0D#[=<)"@/MD0D+(A$)`N+
-M1U2+,(DT).C\____B<+&0"3AQD`E`<9`)A&X#P```(GIA,EU!`^V1RN(0B>(
-M6B@/ML>(0BD/MT<D9HE"$(ER&,="(`````#'0C0`````N`````"`?"0+`'4%
-MN`````")0FR)5"0$B30DZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<PXUV`(/L
-M'(E<)`R)="00B7PD%(EL)!B+;"0D#[9T)"@/MGPD+(M$)""+&(D<).C\____
-MB<*%P'40QH6U`````<9%)@/I?P```,9`).'&0"4!B?`\`1G`]]"#P`*(0B:)
-M^(3`=3^#?30`=`0/MD5-B$(G#[=%'&:)0A")6AC'0B``````QT(T`````+@@
-M.`$`B4)LB50D!(D<).C\____ZR>-=@#&0B</#[=%'&:)0A")6AC'0B``````
-MQT(T`````+@`````Z\B+7"0,BW0D$(M\)!2+;"08@\0<PY"-M"8`````55=6
-M4X/L+(ML)$B+1"1`BQ"+1"1$P>`#C;P0``(``(VT$`0"``"['`$``)"-="8`
-M@WPD1`-V&8D?QP0D$"<``.C\____BP:C`````.L7B?:)'\<$)!`G``#H_/__
-M_XL&HP````")A!ST_O__@\,$@?LX`0``=;F+1"00B44`BT0D%(E%!(M$)!B)
-M10B+1"0<B44,BT0D((E%$(M$)"2)112+1"0HB448@\0L6UY?7<-55U93@^PL
-MBVPD2(M$)$"+$(M$)$3!X`.-O!```@``C;00!`(``+L``0``D(UT)@"#?"1$
-M`W89B1_'!"00)P``Z/S___^+!J,`````ZQ>)]HD?QP0D$"<``.C\____BP:C
-M`````(F$'!#___^#PP2!^QP!``!UN8M$)!")10"+1"04B44$BT0D&(E%"(M$
-M)!R)10R+1"0@B440BT0D)(E%%(M$)"B)11B#Q"Q;7E]=PU575E.#[#R+3"14
-MB$PD$XM$)%"+`(E$)!@/MOF)^,'@!HT$N`-$)%"-D)`+``"(2@2+3"10B8B0
-M"P``QD(&`(E\)`2)#"3H_/___XUT)!R)\(GRQ@``@\`!B=.-;"0\.>AU\`^V
-M1"03B40D%(E4)`B)1"0$BU0D4(D4).C\____B1PDZ/S___^)1"0,C0R]````
-M`(GZP>(&C101BT0D4(T<`HM$)`R)@YP+``"+1"10C900H`L``(M$)"B)`HM$
-M)"R)0@2`?"03`W8IBU0D&(V$"M`!``"+`*,`````B8.T"P``C83Z@`$``(L0
-MB14`````ZS^-%+T`````BTPD&(V$$=`!``"+"(D-`````(GXP>`&`<*+1"10
-MB8P0M`L``(M4)!B-A/J``0``BQ")%0````")^,'@!HT$N`-$)%")D+@+``#V
-M@+8+```0#X0^`0``]H"5"P```G1=D(UT)@#&!@"#Q@$Y[G7VC5PD'(E<)`B+
-M3"04B4PD!(M$)%")!"3H_/___XD<).C\____B?K!X@:-%+J+3"10B801J`L`
-M`(V4$:`+``"+1"0HB4(,BT0D+(E"$.L7B?C!X`:-!+B+5"10QX0"J`L```$`
-M`@"`?"03`W8YC1S]`````(M,)!B-A`LP`@``QP`8````QP0D$"<``.C\____
-MBT0D&(V<`S0"``"+$XD5`````.LWC1S]`````(M4)!B-A!-0`@``QP`8````
-MQP0D$"<``.C\____BTPD&(V<"U0"``"+$XD5`````(GXP>`&C02XBTPD4/>$
-M`;0+``````,`=0B!XO___]_K!H'*````((!\)!,#=@^+3"08C83Y-`(``(D0
-MZPV+3"08C83Y5`(``(D0@\0\6UY?7<.0C;0F`````%575E.#[`R+?"0@BVPD
-M)(EL)`@/MT4`9H7`>0LE`!\``,'X"(A')8U'4(U-%(M5%(E74(M1!(E0!(M1
-M"(E0"(M1#(E0#(M1$(E0$(VWC````(M5+HF7C````(M5,HE6!(U?9(U--HM5
-M-HE79(M1!(E3!(M1"(E3"(M1#(E3#(M1$(E3$(M1%(E3%(M1&(E3&(M1'(E3
-M'(M1((E3((M1)(E3)+D*````B<+H0O'__[D$````B?*)\.@T\?__N10```")
-MVHG8Z";Q__]FQT<X``!FQT<Z``"+1"0(9H.XL@$```$/E,+!X@,/MD<H@^#W
-M"="(1RCVA:<````$=`9FQT<X`0#VA:0````!="1F@T\X`O:%J@````%T!6:#
-M3SH!]H6H`````70(9H%/.``!B?;VA:0````@=!=F@T\X!/:%J@```"!T"6:#
-M3SH"C70F`/:%I````$!T%V:!3SB``/:%J@```$!T"&:#3SH(C78`QD=.`O:%
-MF0````%T,P^W1SBH`70,@\@(9HE'.&:#3SH0#[:%E@```(/@'X/``8A'3CP@
-M=0O&1TX?C;0F`````/:%F`````AT!F:!3S@``O:%F`````1T!6:#3S@@]H68
-M`````G0%9H-/.!#VA:@````@=`[VA:X````@=`5F@T\X0/9'.`%T&(N%R```
-M`(N5S````(E'1(E72.L1C70F`(M5>(E71,='2`````"#1T3_@U=(__9%:@)T
-M&0^WA8````"H#W0.9H/X`AG`@\`$B$<\ZP3&1SP"QD<]_P^W57X/M\*H!'0)
-MQD<]`NL9C78`J`)T!L9'/0'K#/;"`8UV`'0$QD<]`,9'/O_V16H$=!VY````
-M``^WA;````#3^*@!=`.(3SZ#P0&#^0=UZ,=$)`0``@``B2PDZ/S___^)AY@`
-M``"+1"0(]H"F````('0@#[>`K````(/@((/X`1G`@\`"B(<D`0``ZPV-M@``
-M``#&AR0!````N`$```"#Q`Q;7E]=PXVV`````(V_`````(/L'(E<)`R)="00
-MB7PD%(EL)!B+;"0@BWT`NX#____K!8#[A7=*#[;##[:T![`$``")\#S_=#D/
-MML!IP!0-```#AZ@%```Y:`AU)<=$)`@(````BU0D)(E4)`2)!"3H_/___X3`
-M=`F)\.L2D(UT)@"#PP&`^X%VJ;C_____#[;`BUPD#(MT)!"+?"04BVPD&(/$
-M',.-M@````"-OP````!55U93@^P\BU0D4(L"@'HK``^$\P(``,=$)#@`````
-MC8@``@``B4PD&`4$`@``B40D%`^V1"0XB$0D-P^VZ(GHP>`&C02HBU0D4(T<
-M$/:#M@L``!`/A)8"``"-DY`+``"X`0```(GIT^`(0@:+FY@+``")7"0P]D(%
-M`@^$(`$```^V7"0W@\,!BW0D4#A>*P^&"P$``(T$K0````")1"0@B>K!X@:)
-M5"0<C;0F``````^V\XGPP>`&C12PBTPD4(T\"O:'M@L``!`/A,$```"+1"0@
-M`T0D'`'!B4PD+/>!J`L`````#@`/A*,```"+3"10C901H`L``(E4)"B#P@R-
-MA`&@"P``B40D)(/`#,=$)`@(````B50D!(D$).C\____A,!T:\=$)`@(````
-MBT0D*(E$)`2+5"0DB10DZ/S___^$P'1+N`$```")\=/@BU0D+('"D`L```I"
-M!HA"!HB'E@L``(-\)#``=0R+OY@+``")?"0PZQF)\,'@!HT$L(M4)#"+="10
-MB90&F`L``(GV@\,!BTPD4#A9*P^'$/___X-\)#``#X6W````BW0D4(DT).C\
-M____B40D,(7`#X1'`0``B>C!X`:-#*@!\8M$)#")@9@+```/MD0D-XG"P>(&
-MC82"D`L```'PBU0D,(E"&`^V@94+``"(0@;&0@4`B3+&0@H`QD(T`,9"'``/
-MME0D-X/"`3A6*W9?B>C!X`:-!*B-G`:0"P``C;0F``````^VR@^V0P;3^*@!
-M=!>)R,'@!HT$B(MT)#"+3"10B;0!F`L``(/"`8M$)%`X4"MV&>O.B>C!X`:-
-M!*B+3"0PBU0D4(F,`I@+``")Z,'@!HT$J(MT)%"-E`:0"P``#[9"!HM,)#"(
-M00D/MG(&@'PD-P-V)XT<[0````"+1"08`=C'`#@```#'!"00)P``Z/S___\#
-M7"04B3/K)XT<[0````"+1"08`=C'`#@```#'!"00)P``Z/S___\#7"04B3.)
-M]H-$)#@!#[9$)#>#P`&+="10.$8K#X<H_?__@\0\6UY?7<.-M"8`````C;PG
-M`````%575E.#[$R+="1@BQ[&1"1`4,9$)$$%QD0D0@3&1"1#,,9$)$01QD0D
-M1:O&1"1&`,9$)$<`QX,`0`$`$R```(L&QX`$0`$`__\``(L&QX`$0`$`````
-M`#NV/`4```^%Y````(V^P`P``(VN4`4``,=$)!`!````QT0D#`@```");"0(
-MQT0D!````@")-"3H_/___XN&2`4```^VEE,%``"#Z@2-!(*(AE,%``")-"3H
-M_/___X3`=1&+1"1`B890!0``BT0D1(E%!*$``````(93!0``@\`!HP`````/
-MMH90!0``B(=0!0``#[:&404``(B'404```^VAE(%``"(AU(%```/MH93!0``
-M@\`"B(=3!0``#[:&5`4``(B'5`4```^VAE4%``"(AU4%```/MH96!0``B(=6
-M!0``#[:&5P4``(B'5P4``(G?C8,``0``B40D*(N#``$``*,`````#[?0B50D
-M2*@@=`LEW_\``(E$)$CK%HG0@\@@B40D2(M4)"B)`HL"HP````"+!L>`!`$`
-M``````"+!L>`&`$```````"+!L>`'`$```````#'!"20T`,`Z/S____'AW`!
-M```8`0``BX=T`0``HP````"`Y/V`S`2)1"1(QX=P`0``&`$``(M$)$B)AW0!
-M``#'AW`!```H`0``QX=T`0``?W\``,>'<`$``"0!``"+AW0!``"C`````&:X
-M```-_S\``(E$)$C'AW`!```D`0``BT0D2(F'=`$``,>'<`$``#P!``#'AW0!
-M`````'H`QX=P`0``I`$``,>'=`$``'V_[__'AW`!``"X`0``BX=T`0``HP``
-M```E__\```T``/H`B40D2,>'<`$``+@!``"+1"1(B8=T`0``QX><````_P``
-M`,>'D`(``$0!``#'AY0"```&$``(QX>0`@``M`$``,>'E`(``%]P``#'AY`"
-M```P````BX>4`@``HP`````PY(#,,XE$)$B)AY0"``"`?BL`#X1Z`@``QT0D
-M+`````"-AU`"``")1"08C9=4`@``B50D%`^V1"0LB$0D,SP##X81`0``#[;H
-MC13M`````(E4)"2-A!<P`@``B40D(,<`"````,<$)!`G``#H_/___XM4)"2-
-MG!<T`@``BP.C`````(E$)$@-``"``(D#C890!0``B40D"(EL)`2)-"3H_/__
-M_XEL)`2)-"3H_/___XM$)"#'`$0!``#'!"00)P``Z/S____'`P80``B+5"0@
-MQP*T`0``QP0D$"<``.C\____QP-?<```BT0D(,<`"````,<$)!`G``#H_/__
-M_\=$)$C_5(``QP/_5```QT0D"`$```");"0$B30DZ/S___^+1"0DC90'@`$`
-M`(L"HP`````E___^_XD"QT0D2`4!R`"+5"0DC807A`$``,<`!0'(`.D.`0``
-M#[9L)#.-!.T`````B40D.(M4)!@!PHE4)!S'`@@```#'!"00)P``Z/S___^+
-M7"0X`UPD%(L#HP````")1"1(#0``@`")`XV&4`4``(E$)`B);"0$B30DZ/S_
-M__^);"0$B30DZ/S___^+1"0<QP!$`0``QP0D$"<``.C\____QP,&$``(BU0D
-M',<"M`$``,<$)!`G``#H_/___\<#7W```(M$)!S'``@```#'!"00)P``Z/S_
-M___'1"1(_U2``,<#_U0``,=$)`@!````B6PD!(DT).C\____BT0D.(V4.(`!
-M``"+`J,`````)?___O^)`L=$)$@%`<@`BU0D.(V4.H0!``")5"0TQP(%`<@`
-MQP0DH(8!`.C\____B6PD!(DT).C\____@T0D+`$/MD0D,X/``3A&*P^'HOW_
-M_XDT).C\____BX<$`0``HP````"#R`*)1"1(B8<$`0``BU0D*(L"HP`````E
-M\/___0T-```"B40D2(D"BP*C`````(N&&`H``(F'"`$``(N&'`H``(F'#`$`
-M`(N&/`H``(F'$`$``(N&0`H``(F'%`$``,>'(`$````````/MX:,"P``)?\/
-M```-```!`(F'(`$``(N&A`H``(F')`$``(N&B`H``(F'*`$``(N&I`H``,<`
-M_P\``,>'-`$````````/MX:."P``)?\/```-```!`(F'-`$``(N&J`H``(F'
-M.`$``(N&K`H``(F'/`$``,>'2`$```````#'1"1(``$``,>'3`$````!``"+
-MAP0!``"C`````(/(68F'!`$``,=$)$C[_P`,QX=4`0``^_\`#,>'7`$``/__
-M``"X`````,>$AL@%````````QT2&5`````"#P`&#^!!UY6;'AH@+``#_#V;'
-MAHH+``#_#\9&.`&P`8/$3%M>7UW#C70F`%575E.#[!R)1"04B=>+*(DL).C\
-M____B<.%P'4,QH>U`````>G`````B2PDZ/S___^)QH7`=1C&A[4````!B5PD
-M!(DL).C\____Z9H```"-0SR)1"08QD,DX<9#)0'&0R8##[=''&:)0Q#&0V@/
-MBU0D%(L"B4,8QT,@``(``(M6"(E3-+@`````C;0F`````,8$$`"#P`$]``(`
-M`'7RB7-0QT-L(#@!`,=$)`0`````BT0D&(D$).C\____BT,@B40D#(M&#(M6
-M$(E$)`2)5"0(BU0D&(D4).C\____B5PD!(DL).C\____@\0<6UY?7</K#9"0
-MD)"0D)"0D)"0D)!55U93@^Q,BT0D8(LH#[9`"83`#X17!```#[;8QT0D.```
-M``#VPP%U&;H`````B?:#P@$/MLJ)3"0XB=C3^*@!=.Z+1"0XP>`&BW0D.(T$
-ML(T4*(N"J`L``*D```(`=!`-```$`"7___W_B8*H"P``BT0D.,'@!HM\)#B-
-M!+B+A`6H"P``J0``!``/A`8#``"+A3P%``")1"1(.>AU"HV5P`P``(E4)$B+
-M1"0XP>`&BTPD.(T$B`'H#[:0LPL``(E4)"@/MI"R"P``B50D)`^VD+$+``")
-M5"0@#[:0L`L``(E4)!P/MI"O"P``B50D&`^VD*X+``")5"04#[:0K0L``(E4
-M)!`/MH"L"P``B40D#`^V12F)1"0(B4PD!,<$)-`#``#H_/___\=$)#P`````
-MBW0D.,'F`HET)$2+?"0XP><&B7PD0(M4)#R+3"1(#[:$"C`%```\_P^$H@``
-M``^VP&G`%`T``(G#`YFH!0``BW0D1(M\)$"-A#Z@"P``C7P%#+@(````_(G>
-MB<'SI@^7P@^2P#C"=6@/MD,'B40D(`^V0P:)1"0<#[9#!8E$)!@/MD,$B40D
-M%`^V0P.)1"00#[9#`HE$)`P/MD,!B40D"`^V`XE$)`3'!"0@!```Z/S___^+
-M?"1@QD<%_XE\)`2)+"3H_/___^ET`@``C70F`(-$)#P!@WPD/`(/A3;___^)
-M+"3H_/___XG#A<`/A$X"``"+1"0XP>`&BU0D.(T$D/:$!:D+```$=`2`2S4"
-MBT0D.,'@!HM,)#B-!(CVA`6J"P``!'0$@$LU$(M$)#C!X`:+="0XC02P]H0%
-MJ0L```AT!(!+-02+1"0XP>`&BWPD.(T$N/:$!:H+```(=`2`2S4@BT0D.,'@
-M!HM4)#B-!)#VA`6I"P```G0$@$LU`8M$)#C!X`:+3"0XC02(]H0%J@L```)T
-M!(!+-0C&0S``B=^+1"0XP>`&BW0D.(V$L*`+``"-1`4`BU`,B1.+0!")0P2+
-M1"1@B4,(B00DZ/S___^(@XL```"+5"1@@$(<`8!]*P!T,+D`````N@````")
-M]HMT)&`/MD8)T_BH`70.#[;"B$P#0(!#,@&#P@&#P0$X32MWW(M$)&"+2#"-
-M4R")4#"+1"1@@\`LB4,@B4LDB1&+5"1@@$(T`<=$)!``````#[:#BP```(E$
-M)`R)?"0(B50D!(N%^`D``(D$).C\____Z=H```"I```(``^$SP```(DL).C\
-M____B<.%P`^$O0```,9`)P;&0"8%9L>`E```````QD`D!L9`)0#'0$0```4`
-MQT!(`````(V(H````(M$)#C!X`:+="0XC82PH`L``(U$!0"+4`R)DZ````"+
-M0!")002+@Z````")@Y@```"+002)@YP```"+?"1@B7LLB3PDZ/S___^(@[8`
-M``!F@TLX$(D\).C\____/`EV!F:!2S@``HM$)&#&0`H!BU`\B5@\BT0D8(/`
-M.(D#B5,$B1J)7"0$B2PDZ/S___^)]H/$3%M>7UW#D(VT)@````!55U93@^PL
-MBWPD0(M<)$2%VW05#[9#!83`=`T\_P^%A`<``.D;`0``N@````"-=@`/MH0Z
-M-@4``#S_=`T/ML!KP%R-G`=``0``@\(!@_H$==^^``````^VA#XV!0``//]T
-M-@^VP&O`7(V<!T`!``#VA`=&`0```G07QT0D!`````")'"3H_/___^L-D(UT
-M)@")'"3H_/___X/&`8/^!(GV=;0/MD<F9CF'V`D```^%]`8``(7;=7>`?SD`
-M#X7F!@``QD<Y`8N$G[`"``"%P'10BU!PA=)T*,=`<`````#'A)^P`@``````
-M`,=$)`C_____B40D!(M`>(D$)/_2ZR&+4'2%TG0:QT!T`````,>$G[`"````
-M````BT!XB00D_]*#PP&#^Q0/A'L&``#KE\9#!?^)7"0$B3PDZ/S____I9`8`
-M`+H`````#[:$.C8%```\_P^$[P````^VR&O!7(V<!T`!``")7"0D@'L%_P^$
-MU````(!["@`/A"H&``"^`````&O97(VL'W@!``")+"3H_/___XG!C00[BY!\
-M`0``B8A\`0``B2F)402)"H!Y)O]T?H"YM0`````/A.@%```/MEDD#[;3B="#
-MX`:#^`9U*?;"`71'B4PD#`^V04V)1"0(BT$PB40D!(M$)"2)!"3H_/___^FN
-M!0``@_@$#X6E!0``]L,!#X2<!0``B4PD!(D\).C\____Z8L%``")3"0$B3PD
-MZ/S____I>@4``(UV`(/&`8GR.)0?2@$```^&904``.E%____@\(!@_H$#X7U
-M_O__QT0D'`````"`?SD`D`^%D@```+L`````D(UT)@"+E)^P`@``#[:$.[`$
-M``"%TG1DBTIPA<ET78-Z8`!U5SS_="T/MO!IQB@!```#AW`%``#V0"<$=!B`
-M>"4`=1*)="0(B50D!(D\).C\____ZR;'A)^P`@```````,="<`````#'1"0(
-M_____XE4)`2+0GB)!"3_T8/#`8/[%'6!QD<Y`>FO!```BTPD'`^VA#DV!0``
-M//\/A(L$```/MM!KPER-G`=``0``B5PD*("\!TH!````#X1L!```QD0D(P")
-MQ8V$!W@!``")1"00C78`BU0D$(D4).C\____B<.-1#T`BY!\`0``B9A\`0``
-MBTPD$(D+B5,$B1J`>R;_#X4-!```#[=#'(E$)!0/MI0XL`0``&:)5"0:B[2'
-ML`(``/9#*`1T:X7V=&>#?G``=&&#?F``=5N`8RC[]D,G!(UV`'05#[?"B40D
-M"(ET)`2)/"3H_/___^LYBU9PBTPD%,>$C[`"````````QT9P`````,=#(```
-M``#'1"0(_____XET)`2+1GB)!"3_TI"-="8`]D,G!`^$:@$``,:#M`````"`
-MI"](`0``Y_9#*`$/A/X```"`8RC^BT,@A<!T6(![)0!U,_9#)P1T+0^V1RF-
-M!("+5"04C02"B40D"(N'/`4``(E$)`3'!"0'````Z/S____IW0```(E$)`B+
-MASP%``")1"0$QP0D`0```.C\____Z;X```"%]G1ABU9PA=*0=%F`>R4`=2#V
-M0R<$=!H/MT0D&HE$)`B)="0$B3PDZ/S____IC````(M,)!3'A(^P`@``````
-M`,=&<`````#'0R``````QT0D"/____^)="0$BT9XB00D_]+K68![)0!U4_9#
-M)P1T30^V1RF-!("+5"04C02"B40D"(N'/`4``(E$)`3'!"0"````Z/S____K
-M(XM#((7`=!R+4'2%THUV`'02QT!T`````(M#((M`>(D$)/_2]D,H`@^$,@(`
-M`(M#((E$)`B+ASP%``")1"0$QP0D!@```.C\____@&,H_>GC`0``BT,@A<`/
-MA-@!``"#>'0`#X3.`0``QD,G`<9#)@")7"0(QT0D!`8```"+3"0HB0PDZ/S_
-M__^#>S``=!*+4PB+0PR)0@2)$(M#,(!H,`&`>T\`=!J)/"3H_/___\<$)`$`
-M``#H_/___X![3P!UYHN3Y````(72=!O'1"0(`0````^V@]D```")1"0$B10D
-MZ/S___^+4S"%TG08QT0D"`$````/MD--B40D!(D4).C\____BW,@A?8/A/8`
-M``#V0R@$=5V)/"3H_/___\=$)`@!````BT,@B40D!(D\).C\____BU,@#[9"
-M`HE$)`@/MD(!B40D!,<$)"`!``#H_/___XM#((E$)`B+ASP%``")1"0$QP0D
-M`0```.C\____ZSD/MD8"B40D"`^V1@&)1"0$QP0D(`$``.C\____BT,@B40D
-M"(N'/`4``(E$)`3'!"0!````Z/S___^+5G2%TG0>#[=#',>$A[`"````````
-MQT9T`````(M&>(D$)/_2]D,H`G0ABT,@B40D"(N'/`4``(E$)`3'!"0&````
-MZ/S___^`8RC]QT,@`````,=&8`````"+4S2%TG0,#[9#3<=$@CP`````BQ.+
-M0P2)0@2)$("L+TH!```!B5PD!(D\).C\____]D,H`G0CBT,@B40D"(N'/`4`
-M`(E$)`3'!"0&````Z/S___^`8RC]B?:`1"0C`0^V7"0C.)PO2@$```^'J?O_
-M_X-$)!P!@WPD'`0/A5'[__^X`0```(/$+%M>7UW#C;8`````C;\`````5U93
-M@^P0BW0D((L^B30DZ/S___^$P'08#[9?*X3;=#$/ME8)N0````#VP@%T'.LA
-MQD8%_XET)`2)/"3H_/___^M<B=#3^*@!=0>#P0$XV77QB3PDZ/S___^)P87`
-M=#^+5CR)1CR-1CB)`8E1!(D*@$8*`8EQ+,9!)`7&024`QD%-#\=$)`P!````
-MQT0D"`$```")3"0$B30DZ/S___^#Q!!;7E_#C70F`(V\)P````"#["R)7"0<
-MB70D((E\)"2);"0HBW0D-(M>5`^V1B8\)`^':@<```^VP/\DA0`(```/MT8R
-M#[?0]L($=`QFQT8R`0#&1B8!ZT-F@_@@=0QFQT8R"`#&1B81ZS&$TGD5]D8M
-M`W0/)'^#R`AFB48RQD8F#>L8]L((=`;&1B8'ZPWVQ@)T",9&*P#&1B8>B70D
-M!(M$)#")!"3H_/___^GP!@``QT0D#`$```#'1"0(`@```,=$)`0!````B30D
-MZ/S____IRP8``,=$)`P!````QT0D"`````#'1"0$`0```(DT).C\____Z:8&
-M``#'1"0,`0```,=$)`@!````QT0D!`$```")-"3H_/___^F!!@``QT0D#`$`
-M``#'1"0(8````,=$)`0!````B30DZ/S____I7`8```^V1BS'1"00`0```(E$
-M)`S'1"0(8````,=$)`0!````B30DZ/S____I+P8``,=$)!`!````QT0D#```
-M`03'1"0((0```,=$)`0!````B30DZ/S____I`@8``(M#&(%@*/__]__'1"00
-M`0```,=$)`P!````QT0D"`(```#'1"0$`````(DT).C\____Z<L%``#'1"00
-M`0```,=$)`P`````QT0D"`(```#'1"0$`````(DT).C\____QP0D$"<``.C\
-M____Z9(%``"+0QB!8"C___?_QT0D$`$```#'1"0,`0```,=$)`@"````QT0D
-M!`````")-"3H_/___^E;!0``QT0D$`$```#'1"0,`````,=$)`@"````QT0D
-M!`````")-"3H_/___\<$)!`G``#H_/___^DB!0``QT0D#`$```#'1"0(`@``
-M`,=$)`0`````B30DZ/S____I_00``,=$)`P!````QT0D"`````#'1"0$````
-M`(DT).C\____Z=@$``#'1"0,`0```,=$)`@!````QT0D!`````")-"3H_/__
-M_^FS!```QT0D$`$```#'1"0,_____\=$)`@!````QT0D!`````")-"3H_/__
-M_^F&!```QT0D#`$```#'1"0(`````,=$)`0`````B30DZ/S____I800```^V
-M1BN+?(8\B5\LB7<T#[9&*XA'3<9')@/&1R4`@$\D!8!#"@&+4SR-0SB)>SR)
-M!XE7!(DZQP0D@!H&`.C\____BU0D,(!Z*P!T*;X`````]D,)`70.ZQP/MD,)
-MB?'3^*@!=16#Q@&)\(M4)#`X0BMWYNL%O@````"+4QB+0BBI```(`'0*)?__
-M]_^)0BCK9(GQ#[;!C2S%`````+NX"P``B?`\`W8<BU0D,(L"!8`!```!Z(L`
-MHP````#!Z!.#X`'K'(M,)#"+`06``0``C40%`(L`HP````#!Z!.#X`&$P'41
-MQP0DZ`,``.C\____@^L!=:UFQX>4``````")?"0$BT0D,(D$).C\____Z4\#
-M``#'!"1`#0,`Z/S____'1"0,`````,=$)`@@````QT0D!`$```")-"3H_/__
-M_\<$)!`G``#H_/___^D2`P``QT0D#`````#'1"0(`0```,=$)`0`````B30D
-MZ/S____'!"00)P``Z/S____IX0(``(M#&(%@*/__]__'1"00`````,=$)`S_
-M____QT0D"`$```#'1"0$`````(DT).C\____QP0D$"<``.C\____Z9X"``#'
-M1"0,`````,=$)`@`````QT0D!`````")-"3H_/___\<$)!`G``#H_/___^EM
-M`@``B70D!(M4)#")%"3H_/___^E8`@``B70D!(M,)#")#"3H_/___^E#`@``
-MQT0D$`$```#'1"0,\````,=$)`B;````QT0D!`$```")-"3H_/___^D6`@``
-MQT0D$`$```#'1"0,H-9:*\=$)`C@`P``QT0D!`$```")-"3H_/___^GI`0``
-MQT0D$`$```#'1"0,`.`#`,=$)`BD`P``QT0D!`$```")-"3H_/___^F\`0``
-MQT0D$`$```#'1"0,Y*@&`<=$)`C$`P``QT0D!`$```")-"3H_/___^F/`0``
-MQT0D#`$```#'1"0(2`,``,=$)`0!````B30DZ/S____I:@$``,<$)$`-`P#H
-M_/___\=$)`P!````QT0D""````#'1"0$`0```(DT).C\____QP0D$"<``.C\
-M____Z2T!``#'1"00`0```,=$)`P`````QT0D""$```#'1"0$`0```(DT).C\
-M____Z0`!``#'1"0,`0```,=$)`A@````QT0D!`$```")-"3H_/___^G;````
-M#[9&+,=$)!`!````B40D#,=$)`A@````QT0D!`$```")-"3H_/___^FN````
-MQD,%`(M&5(D$).C\____Z9H```#'1"0,`0```,=$)`@!````QT0D!`````")
-M-"3H_/___\<$)!`G``#H_/___^MLBT,8@6`H___W_\=$)!`!````QT0D#/__
-M___'1"0(`0```,=$)`0`````B30DZ/S____'!"00)P``Z/S____K+,=$)`P!
-M````QT0D"`$```#'1"0$`````(DT).C\____QP0D$"<``.C\____N`$```"+
-M7"0<BW0D((M\)"2+;"0H@\0LPXVT)@````"#[!R)7"00B70D%(E\)!B+7"0@
-MBWPD)`^W5Q!F@?J%`'=^#[?"#[:$&+`$```\_W1O9H/Z?W<9#[;`:<`H`0``
-M`X-P!0``BT`L#[9(!.M6D`^W1Q!F/8$`=R`/M\`/MH08L`0``&G`%`T```.#
-MJ`4``(M`"`^V2`3K*P^W1Q`/MH08L`0``&G`L`````.#C`4``(M`5`^V2`3K
-M"I"-="8`N?____^X_____V:!?Q"%`'<,#[='$`^VA!BP!```B[.,!0``#[;1
-M@/G_=!2`O!HV!0``_W0*//]T!H!_%`9U)H-_4`!T#XU'4(E$)`2)'"3H_/__
-M_XE\)`2)'"3H_/___^GJ````#[;`:<"P`````<8/MD8F/!IT=CP:=PH\$0^%
-MFP```.L;/!N-M"8`````=&,\'`^%A@```(VV`````.MZBY,X"@``@<),"```
-M#[9&-,'@"`'"BPJ)#0`````/MLF+DS@*``"!PD0(```/MD8TP>`(`<*+`J,`
-M````P>`("<&)CI0```#&1B8:ZS'&1B8;ZRN+@S@*```%3`@```^V5C3!X@@!
-MT(L`HP````"#X/>(1BS&1B8<ZP3&1B8=@W]0`'0/C4=0B40D!(D<).C\____
-MB7PD!(D<).C\____B70D!(D<).C\____C78`BUPD$(MT)!2+?"08@\0<PX/L
-M#(M$)!")1"0$BP")!"3H_/___X/$#,.-M"8`````@^PLB5PD'(ET)"")?"0D
-MB6PD*(M<)#2+<RP/MU,<N`````"+3"0P@+P*L`0``/\/A#L)```/MD,F/`D/
-MA"\%```\"7=+/`4/A)@````\!9!W'CP##X2V````/`2-="8`#X7N"```Z>0`
-M``"0C70F`#P'#X2-!```/`>-M@`````/AQ`$``#IF0(``)"-="8`/!8/A'P#
-M```\%HVV`````'<C/!0/A)@%```\%(UT)@`/A^8"```\"@^%E@@``(GVZ1`%
-M```\&@^$-P(``#S_D`^$<`4``#P7#X5V"```B?;I0@,``(M$)#`/MF@KB>J$
-MT@^$H0````^V5@F_`````/;"`0^$@@```.F*````B?:+1AB!8"C___[_BT,L
-MQT0D#`````#'1"0(`0```(E<)`2)!"3H_/___\<$)`4```#H_/___[@!````
-MZ2$(``#'1"0,`````,=$)`@`````B5PD!(DT).C\____QP0D4,,``.C\____
-MN`$```#I[P<``(G0B?G3^*@!=1*#QP&)^(GI.,AUZ^L%OP`````/ME,DB="#
-MX`:#^`9U"?;"`0^%U0```(M6&(M"**D```$`=`TE___^_XE"*.F[````B?H/
-MML+!X`.)1"08O1`G``"0BTPD,(L1B?@\`W89BTPD&(V$$8`!``"+`*,`````
-M)0```0#K%XM,)!B-A!&``0``BP"C`````"4```$`A<!T,HGX/`-V%HM,)!B-
-MA!&``0``QP````$`Z1\'``"+3"08C801@`$``,<````!`.D)!P``QP0DZ`,`
-M`.C\____@^T!#X5Y____QD,G`L9#)O^)7"0$BT0D,(D$).C\____N`$```#I
-MYP8``/9&!@%T-HE<)`2)-"3H_/___X3`=2:]^@```(E<)`2)-"3H_/___X3`
-M=1''!"3H`P``Z/S___^#[0%UWXGZ@/H#=AR+3"0PBP$%@`$```^VTHT4T(L"
-MHP````")`NL<BU0D,(L"!8`!``")^0^VT8T4T(L"HP````")`HM#+(G:Z#+E
-M___'!"0@3@``Z/S___^X`0```.E,!@``B50D!,<$)%@$``#H_/___XMS+(L^
-MB3PDZ/S___^)P87`=1'&@[4````!N`$```#I&`8``,9`).'&0"4!QD`F%P^W
-M0QQFB4$0BP:)01C'02``````QT$T`````,=!;"`X`0")3"0$B3PDZ/S___^X
-M`0```.G4!0``B50D!,<$)#8!``#H_/___XMS+(L^B3PDZ/S___^)P87`=1'&
-M@[4````!N`$```#IH`4``,9`).'&0"4!QD`F&`^W0QQFB4$0BP:)01C'02``
-M````QT$T`````,=!;"`X`0")3"0$B3PDZ/S___^X`0```.E<!0``B=J)\.@C
-MY/__N`$```#I204``(L^B3PDZ/S___^)P@^V2SR%P'41QH.U`````;@!````
-MZ20%``#&0"3AQD`E`<9`)@6(2"</MT,<9HE"$(L&B4(8QT(@`````,="-```
-M``#'0FP@.`$`B$L_B50D!(D\).C\____N`$```#IV@0``(L^B3PDZ/S___^)
-MP@^V2SZ%P'41QH.U`````;@!````Z;4$``#&0"3AQD`E`<9`)@2(2"</MT,<
-M9HE"$(L&B4(8QT(@`````,="-`````#'0FP@.`$`B$M!B50D!(D\).C\____
-MN`$```#I:P0``(L^B3PDZ/S___^)P87`=1'&@[4````!N`$```#I2@0``,9`
-M).'&0"4!QD`F!@^W0QQFB4$0BP:)01C'02``````QT$T`````,=!;"`X`0")
-M3"0$B3PDZ/S___^X`0```.D&!```C;8`````BSZ)/"3H_/___XG!A<!U$<:#
-MM0````&X`0```.G?`P``QD`DX<9`)0'&0"8,#[=#'&:)01"+!HE!&,=!(```
-M``#'030`````QT%L(#@!`(E,)`2)/"3H_/___[@!````Z9L#``"+/HD\).C\
-M____B<&%P'41QH.U`````;@!````Z7H#``#&0"3AQD`E`<9`)A;&0"@!#[=#
-M'&:)01#&06@/BP:)01C'02``````QT$T`````,=!;"`X`0")3"0$B3PDZ/S_
-M__^X`0```.DN`P``QD,F_V;'@Y0```````^V4R2)T(/@!H/X!G4%]L(!=1Z#
-M>S0`=1B)-"20C70F`.C\____B(.V````D(UT)@"`>R<"=1J+0RR)7"0(B40D
-M!(M$)#")!"3H_/___XUV`/9&"`)U&KL`````C7XX@'X*``^%8`$``.E\`@``
-MC78`BU8H#[9:*@^VRP^V0A^#Z`$YP7TVC4,!B$(J@$(K`<9")@`/MT(R@^#^
-M@\@(9HE",HE4)`2+5"0PB10DZ/S___^X`0```.EE`@``.<%T%KL`````C7XX
-M@'X*`'4TC78`Z2\"``#&0B8`#[=",H/@]H#,`F:)0C*)5"0$BTPD,(D,).C\
-M____N`$```#I'P(``(D\).C\____B<&+1CR)3CR).8E!!(D(@'DF_P^$C@``
-M`("YM0`````/A-4!```/MEDD#[;3B="#X`:#^`9U*O;"`711#[9!38M1,(E,
-M)`R)1"0(B50D!(DT).C\____N`$```#IM@$``(/X!`^%D0$``/;#`0^$B`$`
-M`(E,)`2+1"0PB00DZ/S___^X`0```.F*`0``B4PD!(M4)#")%"3H_/___[@!
-M````Z7`!``#&@;4`````@\,!.%X*#X9!`0``Z3G___^)/"3H_/___XG!BT8\
-MB4X\B3F)002)"(!Y)O\/A)\```"`>24`#X6.````@+FU``````^$!`$```^V
-M620/MM.)T(/@!H/X!G4J]L(!=%$/MD%-BU$PB4PD#(E$)`B)5"0$B30DZ/S_
-M__^X`0```.GE````@_@$#X7`````]L,!#X2W````B4PD!(M,)#")#"3H_/__
-M_[@!````Z;D```")3"0$BT0D,(D$).C\____N`$```#IGP```,:!M0````"#
-MPP$/MD8*.-@/AS'___\XPW5.A,!T2KL`````C7XXB3PDZ/S___^)PHM&/(E6
-M/(DZB4($B1`/MD(E/")T!#P-=1?'1"0$"@```(D4).C\____N`$```#K/X/#
-M`3A>"G>^QD8%_XET)`2+5"0PB10DZ/S___^X`0```.L<N`$```#K%87MC78`
-M#X0!^?__Z1[Y__^0C70F`(M<)!R+="0@BWPD)(ML)"B#Q"S#C;8`````C;\`
-M````@^PLB5PD'(ET)"")?"0DB6PD*(M\)#"+;"0T#[=5$&:!^H4`#X>^````
-M#[?"#[:,![`$``"`^?\/A*H```!F@_I_=QP/ML&+EW`%``!IP"@!``"+1!`L
-M#[9`!.LZC78`9H'Z@0!W&0^VP8N7J`4``&G`%`T``(M$$`@/MD`$ZQ</ML&+
-MEXP%``!IP+````"+1!!4#[9`!#S_=$T/ML`/MIP'-@4``(#[_W05@/G_=!`/
-MME44@/H&=5>-M"8`````@/O_=".`^?]T'@^VP6G`*`$``(G&`[=P!0``QD8G
-M`L9&)O_I6`(``(-]4`!T#XU%4(E$)`2)/"3H_/___XEL)`2)/"3H_/___^E?
-M`@``B?8/ML%IP"@!``")Q@.W<`4``(M--(32#X2T````#[9%)CP&#X3-````
-M/`P/A,4````/MY:4````C4(!9HF&E````&:#^@EV%X!^)@9T$<9&)P+&1B;_
-M@&8H_NG2`0``QP0DZ`,``.C\____#[96)(G0@^`&@_@&=3[VP@%T.<=$)!``
-M````QT0D#`(````/MD9-B40D"(M&,(E$)`0/ML-KP%R-A`=``0``B00DZ/S_
-M___IIP$``,9&)@.)="0$B3PDZ/S____ID@$``)"-="8`#[9%)CP!=0W&1B8$
-MC70F`.E+`0``/`)U#,9&)@6-=@#I.P$``#P##X6]````B<B`?B8%=2MF@7D$
-MR#=U(P^W1AR)1"0$QP0DC`0``.C\____QD8F!ND&`0``C;8`````B40D!(DT
-M).C\____C49DNB@```#H!\#__X3`=3B-1E"Z%````.CVO___A,!U)XV&C```
-M`+H(````Z.*___^$P'43BT9$"T9(=`O&1B87B?;IJP```&:#OI0````==A'&
-M1B<"QD8F_X!F*/[ID````,<$).@#``#H_/___\9&)AIF@X:4`````>MV/!=U
-M!L9&)A7K;#P8=0K&1B86C70F`.M>/`1U!L9&)@?K5#P%B?9U!L9&)@CK2#P&
-M=0;&1B8)ZSX\#'4&QD8F"NLT/!:)]G4&QD8F%.LH/`YU)(-]4`!T#XU%4(E$
-M)`2)/"3H_/___XEL)`2)/"3H_/___^LND(-]4`!T#XU%4(E$)`2)/"3H_/__
-M_XEL)`2)/"3H_/___XET)`2)/"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#
-MZPV0D)"0D)"0D)"0D)"0@^PLB5PD'(ET)"")?"0DB6PD*(ML)#2+=2P/MT4<
-MN@````"+3"0P@+P!L`0``/\/A.L"```/MD4F/!0/A-0````\%'<[/`T/A`0!
-M```\#9!W$#P%#X6[`@``C;8`````ZU,\#@^$^P```#P/C70F``^%GP(``.G\
-M````D(UT)@`\&P^$GP```#P;C;8`````=Q`\&'0Y/!D/A7<"``")]NM'/!QT
-M73S_#X5G`@``B?;IQ@```,=$)`0`````B2PDZ/S___^Z`0```.E1`@``QT0D
-M!`$```")+"3H_/___[H!````Z3<"``#'1"0$`0```(DL).C\____N@$```#I
-M'0(``(DL).C\____N@$```#I"P(``(DL).C\____N@$```#I^0$``/9%.01T
-M$HDL).C\____N@$```#IX0$``(DL).C\____N@$```#ISP$``(DL).C\____
-MN@$```")]NF[`0``B2PDZ/S___^Z`0```.FI`0``QD4F_X!^"@`/A.D```"[
-M`````(U^.(UV`(D\).C\____B<*+1CR)5CR).HE"!(D0@'HF_P^$GP```(!Z
-M)0`/A9P```"`NK4`````#X1-`0``#[9:)`^VRXG(@^`&@_@&=2KVP0%T4HE4
-M)`P/MD)-B40D"(M",(E$)`2)-"3H_/___[H!````Z1T!``"#^`0/A0D!``#V
-MPP&0#X3_````B50D!(M$)#")!"3H_/___[H!````Z?````")5"0$BTPD,(D,
-M).C\____N@$```#IU@```(VV`````,:"M0````"#PP$/MD8*.-@/ARK___\X
-MPP^%C`````^V124\(G04/`UT$+\`````C6XX@'X*`'4<ZW#'1"0$"@```(DL
-M).C\____N@$```#I?````(DL).C\____B<.+1CR)7CR)*XE#!(D8#[9#)3PB
-M=`0\#74IB5PD!,<$)$P!``#H_/___\=$)`0*````B1PDZ/S___^Z`0```.LR
-MB?:#QP&)^#A&"G>JQD8%_XET)`2+3"0PB0PDZ/S___^Z`0```.L+N@$```"-
-MM@````")T(M<)!R+="0@BWPD)(ML)"B#Q"S#C78`C;PG`````%575E.#["R+
-M7"1$#[=3$+G_____N/____]F@?J%`'=[#[?"BW0D0`^VC`:P!```N/____^`
-M^?]T8F:#^G]W'0^VP8M\)$"+EW`%``!IP"@!``"+1!`L#[9`!.L_9H'Z@0!W
-M'0^VP8MT)$"+EJ@%``!IP!0-``"+1!`(#[9`!.L;#[;!BWPD0(N7C`4``&G`
-ML````(M$$%0/MD`$#[;`BU0D0`^VM`(V!0``:\9<C80"0`$``(E$)"0/ML%I
-MP"@!```#@G`%``")1"0HBTLT#[81P>(8#[9!`<'@$`G"#[9!`PG"#[9!`L'@
-M"`G"C5D(B=#!Z`.#^!!V!;@0````C03!B40D'#G##X>0`0``QT0D(`````!K
-M]ER)="08`W0D0(ET)!2)'"3H_/___XG%C7,$OY0(``"Y!````/SSI@^7P@^2
-MP#C"#X5$`0``@_T0#X<[`0``@T0D(`&#?"0@`74JBTPD*,>!'`$```$```")
-MJ2`!``"+`XF!J````(M#!(F!K````.D%`0``BW0D0(DT).C\____B<:%P`^$
-M_````,9`)P;&0"8%9L>`E```````QD`D!L9`)0#'0$0```4`QT!(`````,>`
-M'`$```$```")J"`!``"+5"0H@<*@````BWPD*(N'H````(F&H````(M"!(F&
-MI````(N'H````(F&F````(M"!(F&G````(L#B8:H````BT,$B8:L````BT0D
-M)(E&+(D$).C\____B(:V````9H-..!"+5"0DB10DZ/S___\\"78&9H%..``"
-MBTPD%("!2@$```&+D7P!``")L7P!``"+?"1`BTPD&(V$#W@!``")!HE6!(DR
-MB70D!(D\).C\____C;8`````@\,(.UPD'`^&A_[__X/$+%M>7UW#C70F`(V\
-M)P````!55U93@>PL`@``#[:$)$@"``"+E"1``@``BU((B50D'(L*B4PD((N4
-M)$`"```/ME(PB%0D)XN,)$`"``"#P2B)3"0HBY0D0`(``#E**`^$JP(``(!\
-M)"<`#X2@`@``#[;`B40D%(M,)"B)#"3H_/___XUX^(U$)"R)1"00BU0D%(E4
-M)`S'1"0(`0```(M,)!R)3"0$BX0D1`(``(D$).C\____@'PD+``/A/X```"]
-M`````(V7H````(E4)!B-=@")Z0^V\<=$)`@(````BT0D&(E$)`2)\\'C!(V$
-M')@```")!"3H_/___X3`#X2?````C90<C`````^V0@B#X`^(A[8````/MT\X
-M9H'AW_V)R(/($&:)1S@/MD((P.@$/`EU"8G(@\@P9HE'.(GPP>`$#[:$!)0`
-M``#`Z`0\"G4&9H%/.``"BTPD*(M1!(U'"(E!!(E/"(E7#(D"]D<H`G1`@&<H
-M_8M'((7`=#6)1"0(BU0D((N"/`4``(E$)`3'!"0&````Z/S____K%9"-="8`
-M@\4!B>DX3"0L=A'I(/___XGH.$0D+`^'-P$``(E\)`C'1"0$!@```(M4)!R)
-M%"3H_/___X!_3P!T)(VV`````(M,)"")#"3H_/___\<$)`$```#H_/___X!_
-M3P!UXHN7Y````(72=!O'1"0(`0````^VA]D```")1"0$B10DZ/S___^+5S"%
-MTG08QT0D"`$````/MD=-B40D!(D4).C\____BT<@A<!T?<=`8`````#V1R@$
-M=2>+1"0@B00DZ/S____'1"0(`0```(M'((E$)`2+5"0@B10DZ/S___^+1R")
-M1"0(BTPD((N!/`4``(E$)`3'!"0&````Z/S___^+1R")1"0(BU0D((N"/`4`
-M`(E$)`3'!"0!````Z/S____'1R``````BQ>+1P2)0@2)$(M,)!R`:0H!BX0D
-M0`(``(!H,`&)?"0$BU0D((D4).C\____BT0D*(N,)$`"```Y02AT"X!L)"<!
-M#X5G_?__@<0L`@``6UY?7<.-M"8`````55=64X'L+`(``(N\)$0"``"+A"1`
-M`@``BP")1"0D#[:T)$P"``"-7"0LB5PD$(ET)`S'1"0(`0```(N4)$`"``")
-M5"0$B3PDZ/S___^)="0(B7PD!(NT)$@"``")-"3H_/___XMN*(/M"(GS@\,H
-MC44(.=AT*P^V124\#704/")U,.L.#[9%)3P-=`8\(HGV=2#&128%QD4G!,9$
-M)"H!ZP7&1"0J`(!\)"P`=17I(`(``(MM"(/M"(U%"#G8=<60Z]_&1"0K`(N$
-M)$`"``"#P#B)1"0@BY0D2`(``(MR*(/N"(U&"#G##X0#`@``#[9$)"O!X`2-
-MO`28````C70F`,=$)`@(````B7PD!(V&H````(D$).C\____A,`/A9P!``"+
-M=@B#[@B-1@@YV`^$O0$``.O+B[0D0`(``(!&"@'&028%QH&T`````,9!)P1F
-MQX&4``````#&@98`````QT%$```%`,=!2``````/MG0D*XGPP>`$C90$C```
-M``^V0@2(020/MD(%B$$EBX0D0`(``(E!+`^V0@B#X`^(@;8````/MWDX9H'G
-MW_V)^(/($&:)03@/MD((P.@$/`EU"8GX@\@P9HE!.(GPP>`$#[:$!)0```#`
-MZ`0\"G4&9H%).``"BY0D2`(``(E1,(GRP>($#[:$%)(```"(04V-E!2,````
-MBT(,B8&@````BU(0B9&D````B8&8````B9&<````B[0D2`(``(!&,`&+E"1`
-M`@``BT(\B4H\BW0D((DQB4$$B0B+A"1(`@``BU`LC4$(B[0D2`(``(E&+(E9
-M"(E1#(D"#[91)(G0@^`&QD0D*@"#^`9U1_;"`70MB4PD#`^V04V)1"0(BX0D
-M2`(``(E$)`2+E"1``@``B10DZ/S____&1"0J`.L5B4PD!(MT)"2)-"3H_/__
-M_\9$)"H`@$0D*P$/MD0D*SA$)"P/AP/^__^`?"0J`'0MQT0D!`H```")+"3H
-M_/___^L;D(UT)@"+5"0DB10DZ/S___^)P87`#X4O_O__@<0L`@``6UY?7</K
-M#9"0D)"0D)"0D)"0D)!55U93@>PL`@``BX0D0`(``(LP#[90'(A4)":#P"R)
-M1"0HBXPD0`(``#E!+`^$T`,``(32#X3(`P``BT0D*(D$).C\____C6C@QT0D
-M$`````#'1"0,`````,=$)`@`````BY0D0`(``(E4)`2+C"1$`@``B0PDZ/S_
-M__^(1"0GA,`/A&L#``"_`````+L`````B5PD(,=$)!``````B5PD#,=$)`@!
-M````BX0D0`(``(E$)`2+E"1$`@``B10DZ/S___\/ML#!X`2#P&0]``(```^'
-MZ0$``(U,)"R)3"00B5PD#,=$)`@!````BX0D0`(``(E$)`2+E"1$`@``B10D
-MZ/S____'1"0("````(EL)`2-C"2(````B0PDZ/S___^$P`^$F`$``(M$)"B+
-M4`2-12"+3"0HB4$$B4T@B54DB0(/MD0D+HA%,8V$)(````")1"0$BX0D0`(`
-M`(D$).C\____//]T$@^VP&G`%`T```.&J`4``(E%#(GZA-)T50^V1"0OT>B#
-MX`'!X`0/ME4U@^+O"<*(534/MD0D+\'H`X/@`<'@!8/BWPG"B%4U#[9$)"_!
-MZ`*#X`'!X`.#XO<)PHA5-0^V1"0RB(6+````Z;\````/MD0D+HA%,8N,)$`"
-M``")30@/MD0D,HB%BP````^W1"0PB44X#[=$)'QFB86(````#[9$)'Z(A8H`
-M``"-37B-5"0L@\)`BT0D;(E%>(M"!(E!!(M""(E!"(M"#(E!#(U-2(U4)"R#
-MPA"+1"0\B45(BT($B4$$BT((B4$(BT(,B4$,C4U8C50D+(/"((M$)$R)15B+
-M0@2)002+0@B)00B+0@R)00R+0A")01"+0A2)012+1"1DB45PBT0D:(E%=(M$
-M)"")1"0,B6PD"(N4)$0"``")5"0$BXPD0`(``(D,).C\____Z1@!``")]H/'
-M`8/#`8GX.D0D)P^$(`$``.FZ_?__B3PDZ/S___^-6/B)7"0(QT0D!`8```"+
-ME"1``@``B10DZ/S___^`>T\`=!J)-"3H_/___\<$)`$```#H_/___X![3P!U
-MYHM#((7`=&W'0&``````]D,H!'4?B30DZ/S____'1"0(`0```(M#((E$)`2)
-M-"3H_/___XM#((E$)`B+ACP%``")1"0$QP0D`0```.C\____BT,@B40D"(N&
-M/`4``(E$)`3'!"0&````Z/S____'0R``````BQ.+0P2)0@2)$(N,)$`"``"`
-M:0H!@&TP`8E<)`2)-"3H_/___SE]*`^%&/___XN$)$`"``"`:!P!B6PD!(DT
-M).C\____BTPD*(N4)$`"```Y2BQT'(!L)"8!=!7I2/S__XU]*#E]*`^%V?[_
-M_XGVZ[V!Q"P"``!;7E]=PXUV`%575E.!["P"``"+K"1$`@``BT4`B40D'(N4
-M)$`"``")5"0$B2PDZ/S____'1"00`````,=$)`P`````QT0D"`````");"0$
-MBYPD0`(``(D<).C\____B$0D(X3`#X2^`P``QD0D(@#'1"0D`````)#'1"00
-M`````(M$)"2)1"0,QT0D"`$```");"0$BY0D0`(``(D4).C\____#[;`P>`$
-M@\!D/0`"```/AU@#``"-7"0LB5PD$(M$)"2)1"0,QT0D"`$```");"0$BY0D
-M0`(``(D4).C\____C9PDB````(E<)`2)+"3H_/___SS_#X42`P``BT0D'(D$
-M).C\____B<>%P`^$+P,``(!%'`'&0#``BX0DB````(D'BX0DC````(E'!(V$
-M)(````")1"0$B2PDZ/S___\\_W06#[;`:<`4#0``BU0D'`."J`4``(E'#`^V
-M1"0NB$<Q#[9$)"_1Z(/@`<'@!`^V5S6#XN\)PHA7-0^V1"0OP>@#@^`!P>`%
-M@^+?"<*(5S4/MD0D+\'H`H/@`<'@`X/B]PG"B%<UB6\(#[9$)#*(AXL```"+
-M1"0TB4=`BT0D.(E'1`^V1"0SB$<R#[=$)#")1S@/MT0D?&:)AX@````/MD0D
-M?HB'B@```(U/>(U4)"R#PD"+1"1LB4=XBT($B4$$BT((B4$(BT(,B4$,C4](
-MC50D+(/"$(M$)#R)1TB+0@2)002+0@B)00B+0@R)00R-3UB-5"0L@\(@BT0D
-M3(E'6(M"!(E!!(M""(E!"(M"#(E!#(M"$(E!$(M"%(E!%(M$)&2)1W"+1"1H
-MB4=TBTTPC5<@B54PC44LB4<@B4\DB1&`?"0L``^$@@$``&;'1"0J``"-73B)
-M7"08C4<HB40D%(VV`````(M4)!R)%"3H_/___XG!A<`/A(0!``"`10H!QD`F
-M!<:`M`````#&0"<$QT!$```%`,=`2`````!FQX"4```````/MW0D*HGPP>`$
-MC90$C`````^V0@2(020/MD(%B$$EB6DLB7DP#[9"!HA!30^V0@B#X`^(@;8`
-M```/MUDX9H'CW_V)V(/($&:)03@/MD((P.@$/`EU"HG8@\@P9HE!.)")\,'@
-M!`^VA`24````P.@$/`IU#&:!23@``HVV`````(GPP>`$C90$C````(M"#(F!
-MH````(M2$(F1I````(F!F````(F1G````(!',`&+13R)33R+7"08B1F)002)
-M"(M7+(U!"(E'+(M<)!2)60B)40R)`@^V422)T(/@!H/X!G4O]L(!=!J)3"0,
-M#[9!38E$)`B)?"0$B2PDZ/S____K$(E,)`2+1"0<B00DZ/S___]F@T0D*@$/
-MMD0D+&8[1"0J#X>9_O__@$0D(@&#1"0D`0^V5"0C.%0D(@^%4/S__X!]"@!U
-M%,9%!?^);"0$BUPD'(D<).C\____@<0L`@``6UY?7<.-="8`C;PG`````%57
-M5E.#["R+;"1`BWPD1,=$)!``````QT0D#`````#'1"0(`````(E\)`2)+"3H
-M_/___X3`=#B[`````(/H`0^V\(U$)"N)1"0,B5PD"(E\)`2)+"3H_/___X!\
-M)"O^#X6E````@\,!C48!.<-UTP^V1S2#Z`&(1S2$P'1UBS?&1S0`BU\L@^L@
-MC5<LC4,@.=!T=X-[#`!U2.L+D(UT)@"#>PP`=3O&1S0!B7PD!(DL).C\____
-MQT0D$``````/MH.+````B40D#(E<)`B)?"0$BX;X"0``B00DZ/S____K*8M;
-M((/K((U#(#G0=;*)]NL8B7PD!(DL).C\____B7PD!(DL).C\____@\0L6UY?
-M7<.-M"8`````C;PG`````%575E.#[`R+="0@BWPD)(LNNPH```")?"0$B30D
-MZ/S___^$P'41QP0DZ`,``.C\____@^L!==\/METKA-MT(`^V5@FY`````/;"
-M`70+ZQ"0B=#3^*@!=0>#P0$XV77QBQ>+1P2)0@2)$(!N"@&)?"0$B2PDZ/S_
-M___V1@@"=$&+1BB%P'43B2PDZ/S___^%P`^$6@$``(E&*(DHB7!4QD`J`,9`
-M*P#&0"8`9H-(,@2)1"0$B2PDZ/S____I,`$``(M&*(7`#X3+````@\!8B40D
-M!(M%%(D$).C\____BT8HB40D!(DL).C\____C7XX.7XX#X27````B3PDZ/S_
-M__^)PXM`((7`=&W'0&``````]D,H!'4?B2PDZ/S____'1"0(`0```(M#((E$
-M)`2)+"3H_/___XM#((E$)`B+A3P%``")1"0$QP0D`0```.C\____BT,@B40D
-M"(N%/`4``(E$)`3'!"0&````Z/S____'0R``````@&X*`8E<)`2)+"3H_/__
-M_SE^.`^%:?___\=&*`````"`?@H`=!.-1CB)!"3H_/___XG!@&X*`>L*B2PD
-MZ/S___^)P87)=#.+5CR)3CR-1CB)`8E1!(D*@$8*`8EQ+,9!)`7&024`QD$G
-M!L9!)@.)3"0$B2PDZ/S___^#Q`Q;7E]=PY"-M"8`````@^PLB5PD'(ET)"")
-M?"0DB6PD*(M\)#"+7"0T#[=3$&:!^H4`=WH/M\(/MHP'L`0``(#Y_W1J9H/Z
-M?W<9#[;!BY=P!0``:<`H`0``BT00+`^V0`3K.V:!^H$`=QD/ML&+EZ@%``!I
-MP!0-``"+1!`(#[9`!.L;#[;!BY>,!0``:<"P````BT005`^V0`2-="8`#[;1
-M//]T"6:!^O\`=2B)]H-[4`!T#XU#4(E$)`2)/"3H_/___XE<)`2)/"3H_/__
-M_^DZ`0``#[;`#[:,!S8%```/M\)IP"@!``")Q@.W<`4``(![%``/A*8```!K
-MP5R-K`=``0``#[9%"HE$)!`/MD4)B40D#`^V0R>)1"0(#[9#)HE$)`3'!"2L
-M!```Z/S___^+%HM&!(E"!(D0@&T*`8ET)`2)/"3H_/___XE<)`2)/"3H_/__
-M_P^V=RN)\(3`#X2J````#[9=";D`````]L,!=0WK'`^VRHG8T_BH`706B4PD
-M!(D\).C\____Z7X```"Z`````(/"`8GP.,)UUNMN:\%<C:P'0`$``(![)@%U
-M-L<$)!`G``#H_/___XE<)`2)/"3H_/___\=$)`P!````QT0D"`````")="0$
-MB2PDZ/S____K*,<$)%##``#H_/___XE<)`2)/"3H_/___XET)`2)+"3H_/__
-M_XUT)@"+7"0<BW0D((M\)"2+;"0H@\0LPXVV`````(V_`````%575E.#[!R+
-M="0PBVPD-`^V1"0XB$0D%P^V1"0\B$0D%HL&B40D&(!^"@!T=+L`````C7XX
-MB3PDZ/S___^)PHM&/(E6/(DZB4($B1`Y:C!U#P^V1"07.$)-=`V0C70F`(/#
-M`3A>"G?-.%X*=#2`?"064'4MQD(G!L9")@7&0B0'QD(E`(EJ,(ER+,:"E@``
-M``")5"0$BT0D&(D$).C\____@\0<6UY?7<.-M"8`````@^PLB5PD'(ET)"")
-M?"0DB6PD*(ML)#"+1"0T#[=0$&:!^H4`#X>&````#[?"#[:$*+`$```\_W1W
-M9H/Z?W<8#[;`:<`H`0```X5P!0``BT`L#[90!.M>BU0D-`^W0A!F/8$`=R`/
-MM\`/MH0HL`0``&G`%`T```.%J`4``(M`"`^V4`3K,(M,)#0/MT$0#[:$*+`$
-M``!IP+`````#A8P%``"+0%0/ME`$ZPN-M@````"Z_____[G_____BT0D-&:!
-M>!"%`'<0BTPD-`^W01`/MHPHL`0```^VP@^VA"@V!0``:\!<C;P%0`$```^V
-MP6G`L````(NUC`4```'&BT0D-(!X*`(/A8@````/MD`L)?````"#^"!T!8/X
-M$'5UBTPD-`^V42R)T(/@#X/X`74QB=`E\````,=$)!`!````B40D#,=$)`@"
-M````QT0D!`````")-"3H_/___^D!"@``D`^V1BN+5(8\BTPD-`^V02PE\```
-M`(/X(`^4P(/`"(B"M@```(M"-&:!8#+__NG."0``BU0D-`^V0A2$P'1#B<.#
-M>E``=!&)T(/`4(E$)`2)+"3H_/___XM,)#2)3"0$B2PDZ/S___^`^P(/A9`)
-M``")="0$B2PDZ/S____I?PD``,>&F``````````/MD8F/"0/APD)```/ML#_
-M)(6<"```BT<8]D`J"`^$,@D``(GVZ<`%``"+E3@*``"!PDP(```/MD8TP>`(
-M`<*+`J,`````@_@%=P6(1A_K!,9&'P6`?PL`=`W&1B8`QD<+`.FN"```QD8F
-M`NFE"```BY4X"@``@<),"```#[9&-,'@"`'"BP*C``````^VP&:)1B"+E3@*
-M``"!PD0(```/MD8TP>`(`<*+`J,`````B<+!Z@AFB58BP>`(9@E&(&:!^D!!
-M#Y3`@^@!@^#J@\`9B$8FZ3T(``"+E3@*``"!PD0(```/MD8TP>`(`<*+`J,`
-M````B$8=BY4X"@``@<),"```#[9&-,'@"`'"BP*C`````*@(=`;&1AX,ZQJH
-M!'0&QD8>"^L0@^`"@_@!&<#WT(/@"HA&'@^V1BL\`1G`@^`"@\`4B$8FZ<@'
-M``"+A3@*```%3`@```^V5C3!X@@!T(L`HP````"#R`B(1BS&1B8%Z9X'``#&
-M1B8`#[=&,F8E]_V#R`)FB48RBT0D-(-X4`!T#X/`4(E$)`2)+"3H_/___XM4
-M)#2)5"0$B2PDZ/S____&1P7_B7PD!(DL).C\____Z:T'``#&1B8$Z40'```/
-MMD8K@\`!B$8K.D8?<U?&1B86BTPD-(-Y4`!T$8G(@\!0B40D!(DL).C\____
-MBT0D-(E$)`2)+"3H_/___\=&6("$'@#'1F``````B79DC498BU44B40D!(D4
-M).C\____Z3X'``#&1BL`QD8F%\<$)""A!P#H_/___^G%!@``QD8F%.F\!@``
-MQD8F".FS!@``QD8F%.FJ!@``QD8N`.C\____B8:(````QD8F%>F2!@``BY4X
-M"@``@<),"```#[9&-,'@"`'"BQJ)'0`````/MMN+E3@*``"!PD0(```/MD8T
-MP>`(`<*+`J,`````Z/S___^)AHP```"#XP^#^P-U"<9&)@KI.@8``(N&B```
-M``5`#0,`.8:,````>1</MD8N/`IW#\9&)A6#P`&(1B[I$`8```^V1BN#?(8\
-M``^$R0$``,=$)!0`````@'\*`'0^QD0D&@"-7SB)'"3H_/___XE$)!0/MD8K
-MBU0D%#E4ACQT'(M#!(E3!(D:B4($B1"`1"0:`0^V3"0:.$\*=\J`;PH!BU0D
-M%(M"((7`#X1.`0``QT!@`````/9"*`1U.XDL).C\____BTPD%(M!-,:`K```
-M``&+02#'1"0(`0```(E$)`2)+"3H_/___XM4)!2+0C3&@*P`````BTPD%(M!
-M((N5/`4``(E$)`B)5"0$QP0D`0```.C\____BU0D%(M"((M(<(7)=#`/MT(<
-MQX2%L`(```````"+0B#'0'``````BT(@BU!XQT0D"/____^)1"0$B10D_]&+
-M3"04BT$@A<!T*XM0=(72="0/MT$<QX2%L`(```````"+02#'0'0`````BT$@
-MBT!XB00D_]*+1"04#[983XM0(`^V@I@````/ME("C02`#[:$`@`````/ME4B
-M#[9-(8E<)!")1"0,B50D"(E,)`3'!"0`!0``Z/S___^+5"04BT(@BY4\!0``
-MB40D"(E4)`3'!"0&````Z/S___^+3"04QT$@``````^V1BO'1(8\`````(M$
-M)!2)1"0$B2PDZ/S____&1B8)Z2\$``"+E3@*``"!PDP(```/MD8TP>`(`<*+
-M"HD-``````^VR8N5.`H``('"1`@```^V1C3!X`@!PHL"HP````#!X`@)R(E&
-M.(!^)@IT!ZD```$`=`G&1B8+Z=4#``#&1B8,#[9&*X-\ACP`=$J`?PH`#X0<
-M!```QD0D&P"-7SB)'"3H_/___XG"#[9&*SE4ACQU!H!O"@'K*(M#!(E3!(D:
-MB4($B1"`1"0;`0^V3"0;.$\*=@SKR(DL).C\____B<*%T@^$R@,```^V1BN)
-M5(8\#[9&+XB"M@```.E3`P``C78`B2PDZ/S____'!"0!````Z/S___^#ZP&#
-M^_]T"8M'&/9`*@ATV\9&)@GI(@,``(N5.`H``('"3`@```^V1C3!X`@!PHL*
-MB0T`````#[;)BY4X"@``@<)$"```#[9&-,'@"`'"BP*C``````^VP,'@"`G(
-M)?\/```]$P$```^4PCTC`0``#Y3!A-)U$(3)=0P],P$``'4YZ>P"``#&1B88
-MA-)T"<9&+PCII`(``(3)B?9T"<9&+PGIE0(``#TS`0``#X6*`@``QD8O"NF!
-M`@``#[9.*@^VT0^V1A^#Z`$YPGT3C4$!B$8J@$8K`<9&)@?I7`(``,9&*P#&
-M1B8>Z4\"``#&1B8#Z48"``#&1B8BB?;I.P(``,9&)B/I,@(``,9&)@/I*0(`
-M`(N5.`H``('"3`@```^V1C3!X`@!PHL*B0T`````BY4X"@``@<)$"```#[9&
-M-,'@"`'"BQ*)%0````")T,'@"`^VR0G(9CT#$0^%F@```(G0P>@(9CU%4W0*
-M9CU``P^%A0```&;'1B`#$6:)1B)F/453=1R`OJ4````"=!/&AJ4````"QX:H
-M````'P```.LB9H%^(D`#=1J`OJ4````#=!'&AJ4````#QX:H````#_@#`,:&
-MK`````&)-"3H_/___\:&K`````"+!HN`/`4``,=$)`0`````B00DZ/S____&
-M1B8#Z4$!``#&1B8AQH:E`````.DQ`0``BY4X"@``@<),"```#[9&-,'@"`'"
-MBP*C`````(N5.`H``('"1`@```^V1C3!X`@!PHL"HP````#&1B8?Z?````#&
-M1B8@Z><```"+E3@*``"!PDP(```/MD8TP>`(`<*+`J,`````BY4X"@``@<)$
-M"```#[9&-,'@"`'"BP*C``````^V3BL/MD8?C5$!B%8K#[;)#[;`@^@!.<$/
-MG,"#Z`&#X.>#P!^(1B;I@@```(N5.`H``('"3`@```^V1C3!X`@!PHL*B0T`
-M````#[;)BY4X"@``@<)$"```#[9&-,'@"`'"BP*C`````,'@"`G!B8Z4````
-MQD8F&NLUQD8F&^LOBX4X"@``!4P(```/ME8TP>((`="+`*,`````@^#WB$8L
-MQD8F'.L(QD8F'8UT)@"+1"0T@WA0`'0/@\!0B40D!(DL).C\____BU0D-(E4
-M)`2)+"3H_/___XET)`2)+"3H_/___^LIQD8F&.D<_?__B2PDZ/S____'!"0!
-M````Z/S___^[/D(/`.EN_/__B?:+7"0<BW0D((M\)"2+;"0H@\0LPXVV````
-M`(V_`````(/L7(E<)$R)="10B7PD5(EL)%B+;"1@BWPD9`^W5Q!F@?J%``^'
-MO@````^WP@^VC`6P!```@/G_#X2J````9H/Z?W<<#[;!BY5P!0``:<`H`0``
-MBT00+`^V0`3K.HUV`&:!^H$`=QD/ML&+E:@%``!IP!0-``"+1!`(#[9`!.L7
-M#[;!BY6,!0``:<"P````BT005`^V0`0\_W1-#[;`#[:4!38%``"`^O]T%8#Y
-M_W00#[9?%(#[!G57C;0F`````(#Z_W0C@/G_=!X/ML%IP"@!``")Q@.U<`4`
-M`,9&)P+&1B;_Z;@'``"#?U``=`^-1U")1"0$B2PDZ/S___^)?"0$B2PDZ/S_
-M___IP@<``(GV#[;!:<`H`0``B<8#M7`%```/MX:4````9HE$)#9F/:L-=P6`
-M^P)U.H-_4`!T#XU'4(E$)`2)+"3H_/___XE\)`2)+"3H_/___\9&)O_&1B<"
-MB70D!(DL).C\____Z5X'``#&1"0]`(#[('4EBT\X#[8!@^!_/'%V#0^V20&#
-MX0^(3"0]ZPL/MDD"@^$/B$PD/0^VTHE4)#!KPER-A`5``0``B40D.`^V1R0\
-M&@^$!P8``#P:=Q\\$G11/!6-="8`#X28!@``A,`/A*4%``")]NF[!@``/"4/
-MA.`"```\)9!W$SP;#X6F!@``C;8`````Z74%```\G@^$S0,``#R@D`^%B@8`
-M`.EB!@``A-N-=@`/A8,"``"+3S2`?R4`C78`=&&%R71+@'D!@'5%@'D"`'4_
-M#[9!`SP\=S</MMB-5E"X`````,8$$""#P`&#^!1U](/[$W8%NQ0```"-5E"-
-M002)7"0(B40D!(D4).C\____9L>&E```````QD8F&>D-!@``QD8F&/9!!D!U
-M$0^V`8/@'X/X#0^%8P$``.L+#[8!@^`?@_@-=0G&1B4-C78`ZP3&1B4B#[9&
-M)8E$)`3'!"1@`0``Z/S___^#?U``=`^-1U")1"0$B2PDZ/S___^)?"0$B2PD
-MZ/S___]K1"0P7("\!4H!````#X3"!0``O@````")PXV\!7@!``")/"3H_/__
-M_XT4*XN*?`$``(F"?`$``(DXB4@$B0$/MD`E/")T!#P-=0Z#Q@&)\CB4'4H!
-M``!WR&M$)#!<#[:$!4H!``")\3C(#X5E!0``A,`/A%T%``"^`````&;'1"0^
-M``#'1"1``````&M<)#!<C;P=>`$``(D\).C\____B<&-!"N+D'P!``")B'P!
-M``").8E1!(D*#[9!)3PB=`0\#744#[=!'&8[1"0^<@EFB40D/HE,)$"#Q@&)
-M\#B$'4H!``!WLH-\)$``#X3D!```BU0D0(!Z)O\/A-8$``#&0B;_B50D!(DL
-M).C\____Z<$$``"#^`%U$<9&)0'&1B;_C70F`.E[!```]D$%`70&9H%..``$
-MBU\TA=MT6XU69+@`````Q@00`(/``8/X*'7TC9:,````L`#&!!``@\`!@_@(
-M=?2-3F2-4PB+0PB)1F2+0@2)002+0@B)00B+0@R)00R+0A")01"+0A2)012+
-M0R")AHP```"#OAP!````#X4`!```QD8F'.GW`P``#[=$)#:#P`%FB8:4````
-MQP0D$"<``.C\____QD8F!>G3`P``BT\TA-L/A9`````/ME$&P>((#[9!!<'@
-M$`G"#[9!!PG"#[9!!,'@&`G"B9:P````#[81P>(8#[9!`PG"#[9!`L'@"`G"
-M#[9!`<'@$`G0B49$QT9(`````(.^L`````!U'6:#AI0````!QP0D$"<``.C\
-M____QD8F&^E5`P``@_C_=0]F@4XX``3&1B8;Z4$#``#&1B8-Z3@#``"`^R!U
-M,X!\)#T&=`>`?"0]`G4E#[=$)#:#P`%FB8:4````QP0D$"<``.C\____QD8F
-M!>D!`P``D(-_4`!T#XU'4(E$)`2)+"3H_/___XE\)`2)+"3H_/___XET)`B+
-M3"0XB4PD!(DL).C\____Z?8"``"+1S2)1"1$A-L/A1\!```/ME`*P>((#[9`
-M"<'@$`G"BTPD1`^V00L)P@^V00C!X!@)PHF6L`````^V00.)PK@`````B40D
-M*(E4)"P/MD$"B<*X`````,'B"(M,)"@)P8M<)"P)TXM$)$0/M@")1"0@QT0D
-M)`````"+1"0@B<*X`````,'B&`G!"=.+1"1$#[9``8E$)!C'1"0<`````(M$
-M)!B)PK@`````P>(0"<$)TXM$)$0/ME`&P>((#[9`!8E$)!C!X!`)PHM$)$0/
-MMD`'"<*+1"1$#[9`!(E$)!C!X!@)P@G*B59$B5Y(BU0D1/9"#`%T!6:#3CH$
-M@[ZP`````'4=9H.&E`````''!"00)P``Z/S____&1B8;Z:8!``!F@TXX`<9&
-M)@WIF`$``(#[('4S@'PD/09T!X!\)#T"=24/MT0D-H/``6:)AI0```#'!"00
-M)P``Z/S____&1B8;Z6$!``"0@W]0`'0/C4=0B40D!(DL).C\____B7PD!(DL
-M).C\____B70D"(M,)#B)3"0$B2PDZ/S____I5@$``,9&)A3I'0$``(#[('4X
-M@'PD/0:-=@!T!X!\)#T"=2</MT0D-H/``6:)AI0```#'!"00)P``Z/S____&
-M1B84Z>,```"-=@#&1B8;Z=<```"$VY"-="8`=5R+1S1F@TXX`F:#3CH!9H%.
-M.(0`@'@#`'4%@#@6=QUF@X:4`````<<$)!`G``#H_/___\9&)@WIDP```/9`
-M!@1T!V:#3CH"ZP5F@V8Z_8M'4(E&&,='4`````#K.H#[('4P@'PD/09T"(!\
-M)#T"D'4F#[=$)#:#P`%FB8:4````QP0D$"<``.C\____QD8F!>L]9H-F./G&
-M1B8.ZS*$VW4%9H-..@/&1B8/ZR.$VY!U#(E\)`2)+"3H_/___X.^'`$```$9
-MP(/@$X/`!8A&)H-_4`!T#XU'4(E$)`2)+"3H_/___XE\)`2)+"3H_/___XET
-M)`2)+"3H_/___XUV`(M<)$R+="10BWPD5(ML)%B#Q%S#D)"0D)"0D)"0D)"0
-M@^$'P>$(@,T@BT`$+>0\```/MM+!X@@!T(D(#[<`9J,`````#[;`PY"-M"8`
-M````@^$'P>$(BDPD!(#-$(M`!"WD/```#[;2P>((`=")",-55U93@^P(B<?&
-M1"0"`,9$)`,`O?_____'1"0$``````^V1"0$B$0D`8-$)`0!N`$```")Q@^V
-M3"0$T^:)\;L`````N,#AY`"Z`````/?Q.?AW'8GZ*<*)T#GJ<Q,/ME0D`8A4
-M)`*(7"0#B<6-="8`@\,!`?&#^Q!UR8-\)`0(=9\/MD0D`\'@`PI$)`(/ML"#
-MQ`A;7E]=PY"-M"8`````@^P,B5PD!(ET)`B+7"00#[9T)!3'!"0`````N0<`
-M``")\HG8Z!?___\/MH,="P``B00DN0,```")\HG8Z/_^__^+7"0$BW0D"(/$
-M#,.-=@!3B=,/MM&Y`P```.BP_O__.-@/E,`/ML!;PXVV`````%.+7"0(A=MT
-M+[H`````B?8/MH0:,@4```^VR#S_=!$/M\%IP+`````#@XP%``#K#8/"`8/Z
-M!'78N`````!;PY!64X/L!(M$)!"+F$`%``"%VW4"B<.^`````,<$)`````"Y
-M!P```(GRB=CH8?[__\<$)$0```"Y`@```(GRB=CH3/[__\<$)-````"Y````
-M`(GRB=CH-_[__\<$)`````"Y!````(GRB=CH(O[__X/&`8/^`G6DN*"&`0#H
-M,/[__XB#'0L```^VP(D$)+D#````N@````")V.CS_?__@\0$6U[#C;8`````
-MC;PG`````(/L/(E<)"R)="0PB7PD-(EL)#B+5"1`#[:"I0```#P"#X7J````
-MBXJH````B4PD%&;'1"0:``"]````*L=$)!P`````NP````"^`````+\$````
-MN@$```")T(G9T^"%1"04=1R-2P;3XF8)5"0:"50D'+@5````B?'3X`G%ZPF0
-MB?B)\=/@"<6#PP&#Q@6#QP.#^P5UO8M$)!R)1"0,QT0D"*@#``#'1"0$`0``
-M`(M4)$")%"3H_/___XEL)`S'1"0(Q`,``,=$)`0!````BTPD0(D,).C\____
-M#[=$)!J+5"1`"X*H````B40D#,=$)`B@`P``QT0D!`$```")%"3H_/___^G]
-M````C;8`````/`,/A>\```"+3"1`BXFH````B4PD*&;'1"0B``"]````*L=$
-M)"0`````NP````"^`````+\$````C;0F`````+H!````B=")V=/@A40D*'4?
-MC4L&T^)F"50D(@E4)"2X%0```(GQT^`)Q>L,C70F`(GXB?'3X`G%@\,!@\8%
-M@\<#@_L$=;J+1"0DB40D#,=$)`BH`P``QT0D!`$```"+5"1`B10DZ/S___^)
-M;"0,QT0D",0#``#'1"0$`0```(M,)$")#"3H_/___P^W1"0BBU0D0`N"J```
-M`/?0B40D#,=$)`B@`P``QT0D!`$```")%"3H_/___XM<)"R+="0PBWPD-(ML
-M)#B#Q#S#D(UT)@"#[`R+5"00#[9,)!2`?"08`'0/N/[____3P"&"J````.L-
-MN`$```#3X`F"J````(D4).C\____@\0,PY"-="8`4X/L&(M<)"!FQX.<````
-M`0#'1"00`0````^W1"0DP>`-B40D#,=$)`B@`P``QT0D!`$```")'"3H_/__
-M_\=$)`04````B1PDZ/S___^#Q!A;PXVT)@````"-O"<`````@^P,BU0D$`^V
-M3"04@'PD&`!U$+C^____T\!F(8*0````ZPZX`0```-/@9@F"D`````^W@I``
-M``")1"0$B10DZ/S___^#Q`S#D(VT)@````"#[!R)7"00B70D%(E\)!B+1"0D
-M#[9\)"@/MK"8````#[98`HM0:(72=!B)^0^VP8E$)`@/ML.)1"0$B10DZ/S_
-M__^`^P-W#XT4LXGP/`-V$XU4LP3K#8GQC580@/D#=@.-5B")^0^VP8E$)`@/
-MML*)1"0$BT0D((D$).C\____BUPD$(MT)!2+?"08@\0<PY!75E.#[!")Q[L`
-M````#[;RN0(```")\HGXZ/+Y__^H"'0.N`````#K(XVT)@````#'!"0!````
-MZ/S___^#PP&!^Q`G``!UR;C_````@\006UY?PXVV`````(V\)P````"#[`R)
-M'"2)="0$B7PD"(G&B<\/MMJ)VNB$____A<!U,(GX#[;0B=F)\.C"^O__A<!T
-M'KD!````B=J)\.AP^?__BU0D$(@"N`````#K"(UV`+C_____BQPDBW0D!(M\
-M)`B#Q`S#C;8`````C;\`````@^P<B5PD$(ET)!2)?"08B<8/MOD/MMJ)/"2Y
-M`0```(G:Z$KY___'!"1`````N0(```")VHGPZ#7Y__^)VHGPZ.S^__^%P'5.
-M@WPD(`!T-??'`0```'09B=FZ0````(GPZ!OZ__^%P'0MZS*0C70F`(G9NA@`
-M``")\.@"^O__A<!T%.L9B=FZ*````(GPZ.[Y__^%P'4'N/\```#K!;@`````
-MBUPD$(MT)!2+?"08@\0<PXVT)@````"-O"<`````55=64X/L#(G'BVPD)(G3
-MB<Z$R0^$Z@````^VVL<$)&0```"Y`@```(G:B?CH?_C__XG:B?CH-O[__X7`
-M=0ZY`P```(G:B?CH-/C__XGP#[;(QP0D`0```(G:B?CHW_[__[[_____A,`/
-MA7<!``"^`````(7M#XYJ`0``O@````"-1?^)1"0(.70D"'4UQP0D0````+D"
-M````B=J)^.@.^/__BT0D(`'PB00DN5@```")VHGXZ!?^__^%P'0YZ2,!``#'
-M!"1$````N0(```")VHGXZ-GW__^+1"0@`?")!"2Y4````(G:B?CHXOW__X7`
-M#X7O````@\8!.>X/A.0```#KA+B@A@$`Z,/W__\/MML/ML")!"2Y`P```(G:
-MB?CHC/?__XG:B?CH0_W__X7`="(/MH<="P``B00DN0,```")VHGXZ&?W__^^
-M_____^F2````B=FZ8````(GXZ%_X__^%P'0-O@````"%[7Y?B?;K'P^VAQT+
-M``")!"2Y`P```(G:B?CH)O?__[[_____ZU2^`````,<$)$0```"Y`@```(G:
-MB?CH!??__XM$)"`!\(D$)+F`````B=J)^.@._?__A<!U!X/&`3GN=<D/MH<=
-M"P``B00DN0,```")VHGXZ,OV__^)\(/$#%M>7UW#D(/L'(E<)!2)="08BW0D
-M(`^V3"0DBT0D+(E$)`2+1"0HB00DN@$```")\.CA_?__B</'!"14````N0(`
-M``"Z`0```(GPZ'?V__^)V(M<)!2+="08@\0<PXGVC;PG`````(/L'(E<)!2)
-M="08BW0D(`^V3"0DBT0D+(E$)`2+1"0HB00DN@````")\.B!_?__B</'!"14
-M````N0(```"Z`````(GPZ!?V__^)V(M<)!2+="08@\0<PXGVC;PG`````%57
-M5E.#[`R)QXML)"2)RP^V\L<$)&0```"Y`@```(GRZ-OU__^)\HGXZ)+[__^%
-MP'4.N0,```")\HGXZ)#U__\/MLO'!"0!````B?*)^.@]_/__A,!U+H7M?C&[
-M`````(M$)"`/M@P#QP0D`````(GRB?CH&/S__X3`=0F#PP$YZW0)Z]NX____
-M_^L%N`````"#Q`Q;7E]=PXVT)@````"#[!R)7"04B70D&(MT)"`/MDPD)(M$
-M)"R)1"0$BT0D*(D$)+H`````B?#H,?___XG#QP0D5````+D"````N@````")
-M\.@7]?__B=B+7"04BW0D&(/$',.)]HV\)P````"#[!R+3"0@#[94)"2+@4`%
-M``"%P'4"B<B(%2````#'1"0,(````,=$)`@@````QT0D!`X```")!"3H_/__
-M_X/$',.-M"8`````C;PG`````(/L#(M4)!`/MDPD%(!\)!@`=!"X`0```-/@
-M9@F"K`P``.L.N/[____3P&8A@JP,```/MH*L#```B40D!(D4).C\____@\0,
-MPY"-M"8`````55=64X/L3(M$)&2+2!B#P0&+4!"#Z@&)5"0DQT0D2`````"+
-M6!R)7"0H#[91`8#Z`74-QT`L`````.GE!```D(#Z`G50@'D"`74ZBW0D8(N&
-M0`4``(7`=0*)\(N`/`4```^V40.(D*X,```/ME$#B)!N&0``BT0D9,=`+```
-M``#IGP0``(M4)&3'0BS^____Z8\$``"`^@0/A3("```/MD$#@^@[/`$/AR,"
-M``"+3"1DBUD8@\,!B5PD.`^V<P*+1"1@BY@\!0``B?(/ML*)1"0$B1PDZ/S_
-M__^)PH3`=`T/ML"`O`.P!```_W56BYL\!0``@</`#```BX,\!0``B00DZ/S_
-M__^)\2C!#[;!B40D!(D<).C\____B<*$P'0-#[;`@+P#L`0``/]U%HM<)&3'
-M0RS_____B1PD_U,HZ?P#```/ML(/MH0#L`0``(#Z@7=F#[;(:<D4#0``BT0D
-M.`^V0`2(1"0WBW0D.`^V5@7!XA`/MD8&P>`("<(/MD8'"<*)5"0L#[96",'B
-M$`^V1@G!X`@)P@^V1@H)PHE4)#")S@.SJ`4```^$!P$``(!^,`!U&^G\````
-MBT0D9,=`+/____^)!"3_4"CI<`,``+\`````QD0D-@"-;BB+5"0X@\(+B50D
-M'(DL).C\____C5CXBU8LB48LB6L(B5,,B0(/MD,E/`UT"#PB#X6,````BTPD
-M.`^V00,\.W0T/#QU?(M$)&2)1"00BU0D+(E4)`R+3"0PB4PD"`^V1"0WB40D
-M!(D<).C\____QD0D-@'K3(N#Z````(M4)"R)5"0(BTPD'(E,)`2)!"3H_/__
-M_XM$)&2)1"00BU0D+(E4)`R+3"0PB4PD"`^V1"0WB40D!(D<).C\____QD0D
-M-@&#QP&)^SA>,`^'/?___X!\)#8`#X6*`@``BW0D9,=&+/____^)-"3_5BCI
-M=`(``)"-="8`@/H##X6X````@'D"`8UV``^%FP```(M4)&`/MD(FC30`#[99
-M`XG:B=C!^A_W_HG3.=9^;8UY!`^V\@^V002)1"0(B70D!(M,)&")#"3H_/__
-M_XU#_(/X`W88C4/T@_@#=A"-0^R#^`-V"(U#Y(/X`W<(@40D8,`,```/M@>)
-M1"0(B70D!(M<)&")'"3H_/___XMT)&3'1BP`````Z;,!``"+1"1DQT`L_O__
-M_^FC`0``BU0D9,="+/[____IDP$``(`Y!79*@'D$_G5$C40D2(E$)`B+3"1D
-MB4PD!(M<)&"+@SP%``")!"3H_/___X3`#X5>`0``QT0D2`````"+="1DQT8L
-M_____^E&`0``B?:+1"1@BZA`!0``A>UU`HG%B<NX`@```"G(B40D(.F3````
-M#[8SC7H!#[;(]L$!=$"+5"1(C006BUPD9#M#%`^'W0```(ET)`2+1"0H`=")
-M!"2Z`````(GHZ'/W__\Y\`^%O`````%T)$B)^^M(C78`C1PWBT0D(`'8.T0D
-M)`^/G@```(ET)`2)/"2Z`````(GHZ.KY__^%P`^%@P```(`[`'4&@'L!`'0,
-MQP0D$"<``.C\____C5,!#[9#`83`#X5>____#[8#A,!T80^VV,<$)%0```"Y
-M`@```+H`````B>CHFN___XM4)$B+="1DBT84*=`YPW8"B<.)7"0$BT0D*`'0
-MB00DN0````"Z`````(GHZ+GV__^%P'@&`40D2.L+BT0D9,=`+/_____'!"14
-M````N0(```"Z`````(GHZ#SO__^+3"1DBU$@A=)T!HM$)$B)`HM<)&2)'"3_
-M4RB#Q$Q;7E]=PXGVC;PG`````(/L'(M4)""+@D`%``"%P'4"B="+D#P%```/
-MMH*O#```A,!T#8/H`8B"KPP``(3`=2?&!2,`````QT0D#"````#'1"0((```
-M`,=$)`0.````B10DZ/S___^#Q!S#C70F`(/L'(M4)""+@D`%``"%P'4"B="+
-M@#P%``"`N*X,````=2Z`@*\,```!Q@4C`````<=$)`P@````QT0D""````#'
-M1"0$#@```(D$).C\____@\0<PXVV`````(V_`````(/L'(E<)!2)="08BW0D
-M(`^V3"0DBT0D+(E$)`2+1"0HB00DN@````")\.@A^/__B</'!"14````N0(`
-M``"Z`````(GPZ`?N__^)V(M<)!2+="08@\0<PY"0D)"0D)"0D(M$)`2+0`0M
-M``(!``-$)`B+`*,`````PY"-M"8`````BT0D!(M`!"T``@$``T0D"(M4)`R)
-M$,.)]HV\)P````!3@^P,BUPD%(M3!('J``(!`,>"@``!``````"+@@0!`0"C
-M`````(#,`8F"!`$!`,=$)`@(````QT0D!`S"``")'"3H_/___\=$)`BX"P``
-MQT0D!`C"``")'"3H_/___\=$)`@!```\QT0D!`#"``")'"3H_/___\=$)`@(
-M````QT0D!`S#``")'"3H_/___\=$)`BX"P``QT0D!`C#``")'"3H_/___\=$
-M)`@!```\QT0D!`##``")'"3H_/___\=$)`B`@("`QT0D!#C"``")'"3H_/__
-M_\=$)`@(&"@XQT0D!"#"``")'"3H_/___\=$)`B`@("`QT0D!#S"``")'"3H
-M_/___\=$)`@)&2DYQT0D!"3"``")'"3H_/___\=$)`B`@("`QT0D!$#"``")
-M'"3H_/___\=$)`@*&BHZQT0D!"C"``")'"3H_/___\=$)`B`@("`QT0D!$3"
-M``")'"3H_/___\=$)`@+&RL[QT0D!"S"``")'"3H_/___\=$)`B`@("`QT0D
-M!$C"``")'"3H_/___\=$)`A(24I+QT0D!##"``")'"3H_/___\=$)`B`@("`
-MQT0D!#C#``")'"3H_/___\=$)`@,'"P\QT0D!"##``")'"3H_/___\=$)`B`
-M@("`QT0D!#S#``")'"3H_/___\=$)`@-'2T]QT0D!"3#``")'"3H_/___\=$
-M)`B`@("`QT0D!$##``")'"3H_/___\=$)`@.'BX^QT0D!"C#``")'"3H_/__
-M_\=$)`B`@("`QT0D!$3#``")'"3H_/___\=$)`@/'R\_QT0D!"S#``")'"3H
-M_/___\=$)`B`@("`QT0D!$C#``")'"3H_/___\=$)`A,34Y/QT0D!###``")
-M'"3H_/___\=#/("`@(#'0T"`@("`QT-$@("`@,=#2("`@(#'0TR`@("`@</`
-M#```QT,\@("`@,=#0("`@(#'0T2`@("`QT-(@("`@,=#3("`@("#Q`Q;PXM$
-M)`2+4`2!Z@`"`0"+@FP``0"C`````(F";``!`,.0BT0D!(M0!('J``(!`(N"
-M:``!`*,`````"T0D"(F":``!`,.-M@````"-O"<`````@^P@B5PD$(ET)!2)
-M?"08B6PD'(MT)"0/ME0D*`^V?"0L.;8\!0``#X4(`0``B=#`Z`*]``````^V
-MP(E$)`R)T/?0@^`#C1S%`````+@'````B=G3X/?0BTPD#(M4CCPAPHE4CCR)
-M^(3`=!.X`0```(G9T^`)T(M4)`R)1)8\B>D/MMG!XPB+1CR)1"0(C8,XP@``
-MB40D!(N&/`4``(D$).C\____BT9`B40D"(V#/,(``(E$)`2+ACP%``")!"3H
-M_/___XM&1(E$)`B-@T#"``")1"0$BX8\!0``B00DZ/S___^+1DB)1"0(C8-$
-MP@``B40D!(N&/`4``(D$).C\____BT9,B40D"('#2,(``(E<)`2+ACP%``")
-M!"3H_/___XM<)!"+="04BWPD&(ML)!R#Q"##B=#`Z`*#Z`6]`0```.GP_O__
-MB?:-O"<`````55=64X/L'(M\)#`/MD0D-(A$)!L/ME0D.(A4)!H/MFPD/(M'
-M"(LPB30DZ/S___^)PX7`#X3X````B30DZ/S___^)PH7`#X3F````QD<T`<9#
-M).'&0R4!QD,F$,9#%;L/MD<S9HE#$(ES&,=#()````"-0@B)0S2)4U")P8G"
-MN`````#&!!``@\`!/9````!U\L9!`8+&`4`/MD0D&XA!`@^V5"0:B%$#B>B(
-M000\`G<CC4$(B>D/MM'!X@*-CG@+``")5"0(B4PD!(D$).C\____ZS>+AG@+
-M``")00B+AGP+``")00R#P1")Z@^VPHT$A?C___^-EH`+``")1"0(B50D!(D,
-M).C\____QT-L`````,=$)`0`````C4,\B00DZ/S___^)7"0$B30DZ/S___^#
-MQ!Q;7E]=PXVT)@````"#["R)7"0<B70D((E\)"2);"0HBWPD,(ML)#2+1"0X
-MB40D&(M4)#R)5"04BT<(BS")-"3H_/___XG#A<`/A(````")-"3H_/___XG"
-MA<!T<L9'-`'&0R3AQD,E`<9#)A#&0Q6[#[9',V:)0Q")<QC'0R"0````C4((
-MB4,TB5-0QD`!`L9""$")ZHA0`@^V5"08B%`##[94)!2(4`3'0VP`````QT0D
-M!`````"-0SR)!"3H_/___XE<)`2)-"3H_/___XM<)!R+="0@BWPD)(ML)"B#
-MQ"S#C78`C;PG`````%575E.#[!R+="0P#[9L)#0/MD0D.(A$)!N+1@B+&,=$
-M)`P"````QT0D"`````#'1"0$`````(DT).C\____@'XT`'0:B1PDZ/S____'
-M!"0!````Z/S___^`?C0`=>:+1@B+``5X"P``@'@"`'A$@$@"@,=$)`P!````
-MQT0D"`````#'1"0$`````(DT).C\____@'XT`'0:B1PDZ/S____'!"0!````
-MZ/S___^`?C0`=>:)Z,#H`@^V^,=$)`P!````B7PD",=$)`0#````B30DZ/S_
-M__^`?C0`=!Z-="8`B1PDZ/S____'!"0!````Z/S___^`?C0`=>:+1@B+&(GI
-M]]&#X0.`?"0;``^5PL'B`P^VA`MX"P``@^#G"="(A`MX"P``QT0D#`$```")
-M?"0(QT0D!`,```")-"3H_/___X/$'%M>7UW#C;0F`````(/L'(E<)`R)="00
-MB7PD%(EL)!B+7"0@BW0D)`^W1A!F/84`=QN+JZ@%```/M\`/MH0#L`0``&GX
-M%`T``.L-B?:+JZ@%``"_[`8-`(M&-(!X`0)U)(V+>`L``(U0!(M`!(F#>`L`
-M`(M"!(E!!(M""(E!"(M"#(E!#(M&4(7`=`R)1"0$B1PDZ/S___^)="0$B1PD
-MZ/S____&1#TT`(M<)`R+="00BWPD%(ML)!B#Q!S#@^P0B1PDB70D!(E\)`B)
-M;"0,BTPD%(MT)!B+5"0<BUPD((NY<`4```^W1A"]V"8!`&8]A0!W$0^WP`^V
-MA`&P!```:>@H`0``C8H@!```QH(@!```)V:!?B3A`74C#[96)HU"_SP!=PD/
-MME8G@^(/ZR2-0N^Z#P```#P!=AB-=@"-!"^Z`````(-X-`!T!P^V4$V#X@\/
-MMD$!@^#P"="(00&X`0```&:!?B3A`742#[9&)H/H`3P!#Y?`#[;`C78`B<+!
-MX@</MD$!@^!_"="(00$/MD,&B$$"#[8#B$$##[9#!8A!!P^V0P>(00\/MD,"
-MB$$$#[9#`XA!!0^V0P2(008/MD,!B$$,#[9#"HA!"`^V0PN(00D/MD,,B$$*
-M#[9#"(A!"P^V0PF(00V+'"2+="0$BWPD"(ML)`R#Q!##B?8/MD0D!,.-=@"-
-MO"<`````#[9$)`7#C78`C;PG`````%.+5"0(BUPD$,9"%`*+2CB+1"0,B$$"
-MBT(XQD`'`(M".(A8#%O#C78`C;PG`````(M4)`2+3"0(#[9"*8A!`@^V0BB(
-M00,/MD(GB$$$#[9")HA!"L.-="8`C;PG`````(M4)`2+3"0(#[9"+8A!`@^V
-M0BR(00,/MD(KB$$$#[9"*HA!"@^V0BF(00L/MD(HB$$,PXVV`````(V\)P``
-M``"+3"0,A<E^';H`````C78`B<@IT(/X`@^=P`^VP(U4`@$YT7_K\\.)]HV\
-M)P````"#[!R)7"0,B70D$(E\)!2);"08BUPD((MT)"@/MD0D)(A$)`L/MD,D
-M/"IT)CPJ=Q`\*`^%V````.L8C;8`````/(AT)#R*#X7$````C70F`.L6#[9[
-M+`^V:RN)="0$B1PDZ/S____K%`^V>S$/MFLPB70D!(D<).C\____QD8%0(M#
-M9*D```$`="R)^(@&B>B(1@@/MD0D"\'@`XA&`0^V0R0\*'0$/(AU!L9&!F#K
-M8,9&!F'K6JD```0`D(UT)@!T(HGXB$8!B>B(1@D/MD,D/"AT!#R(=0;&1@8E
-MZS+&1@8UZRR)^(A&`0^V0R:#X`\(1@4/MD,D/"AT!#R(=0;&1@;(ZPO&1@;*
-MC;0F`````(M<)`R+="00BWPD%(ML)!B#Q!S#C;8`````C;\`````@^P,BTPD
-M$`^V028*02<*02@*02D/ML`/ME$L@^(!"=!T'L=$)`@D````QT0D!`4```")
-M#"3H_/___^L3C70F`(M$)!3&0`;LQT%L`````(/$#,.-M@````"-O"<`````
-M@^P8B5PD"(ET)`R)?"00B6PD%(M<)!R+="0@#[9#)#PO=`T\CW5@ZQV-M"8`
-M````#[9[+`^V:RN)="0$B1PDZ/S____K%`^V>S$/MFLPB70D!(D<).C\____
-MQD8%0/9#9@1T$(GXB$8!B>B(1@G&1@9"ZQ.)^(A&`0^V0R:#X`\(1@7&1@9`
-MBUPD"(MT)`R+?"00BVPD%(/$&,.0C70F`%.#[`R+3"08BU0D',9"!4`/MD$D
-M/#5T"#R1=2KK(HGVBUPD%`^W0SB#X`&#^`$9P(/@_8/H%HA"!NLED(UT)@#&
-M0@;JZQK'1"0()````,=$)`0%````B0PDZ/S____K"O9!)0)T!,9!%`"#Q`Q;
-MB?;#ZPV0D)"0D)"0D)"0D)"0@^P,BT0D$/9`*/!T&,=$)`@D````QT0D!`4`
-M``")!"3H_/___X/$#,.-M"8`````4X/L$(M<)!R+3"0D#[9$)""Z`````,8$
-M"@"#P@&#^@UU]`^V4R2`^C4/A*\```"`^C5W-(#Z*'1L@/HHC70F`'<3@/H;
-M#X6:`P``D(UT)@#IJ@```(#Z*G1+@/HOC78`#X5_`P``ZUV`^H^0C70F`'13
-M@/J/=Q&`^HAT*8#ZBI`/A5\#``#K'8#ZD9"-="8`=$R`^N$/A4H#``"0C70F
-M`.F2````B4PD"`^VP(E$)`2)'"3H_/___\=$)`P!````Z2@#``")3"0$B1PD
-MZ/S____'1"0,`0```.D/`P``B4PD"(E<)`2+1"08B00DZ/S____'1"0,`0``
-M`.GN`@``]D,H`70AQD$&<,9!!`#&00,`QD$"`,9!!4#'1"0,`0```.G'`@``
-MQD$&X,=$)`P!````Z;8"``"`>R4!#X6D`@``@'LF'`^'F@(```^V0R:0_R2%
-M,`D``,9!!P3'1"0,`0```.F%`@``QD$'`,=$)`P!````Z70"``#&00;LQT0D
-M#`$```#I8P(``,9!!N_&`0,/MD,G@\A`B$$!QT0D#`$```#I10(``,9!!N_&
-M`0?'1"0,`0```.DQ`@``QD$&0,9!`0'&005`QT0D#`$```#I&`(``,9!!N_&
-M`0,/MD,G@\@(B$$!QT0D#`$```#I^@$``,9!!N_&`0+'1"0,`0```.GF`0``
-MQD$&[\8!@L=$)`P!````Z=(!``#&00;OQ@$&QT0D#`$```#IO@$``,9!!N_&
-M`8;'1"0,`0```.FJ`0``QD$&XP^V0R>(00''1"0,`0```.F2`0``QD$&L,8!
-MV,9!`T_&003"QT0D#`$```#I=@$``,9!!K#&`=G&00-/QD$$PL=$)`P!````
-MZ5H!``#&00:PQ@':QD$#3\9!!,+'1"0,`0```.D^`0``BT0D&/9`.`%T$<9!
-M!NK'1"0,`0```.DC`0``QD$&Y\=$)`P!````Z1(!``#&00;OQ@&JQT0D#`$`
-M``#I_@```,9!!N_&`57'1"0,`0```.GJ````QD$&+\9!`0'&00(0QT0D#`$`
-M``#IT0```,9!!N0/MD,HB`$/MD,IB$$(#[9#)XA!!<=$)`P!````Z:P````/
-MMD,GB$$&#[9#*(@!#[9#*8A!`@^V0RJ(00,/MD,KB$$$#[9#+8A!"@^V0RR(
-M00''1"0,`0```.MRQD$&Z`^V0RB(`0^V0RF(00@/MD,GB$$%#[9#*HA!`@^V
-M0RN(00,/MD,LB$$$#[9#+8A!`<=$)`P!````ZS3'1"0,`0```/9#*`%T)L9!
-M!G#&000`QD$#`,9!`@#&005`QT0D#`$```#K",=$)`P`````BT0D#(/$$%O#
-MC78`C;PG`````(/L/(E<)"R)="0PB7PD-(EL)#B+;"1$BW4TC7PD#/RY"```
-M`+@`````\ZOVAJ<````$=!2+CL@```"+GLP```"#P?^#T__K#8M&>(/H`8G!
-MNP````"`?20E=6>)R`^LV!B(1"0,B<@/K-@0B$0D#8G(#ZS8"(A$)`Z(3"0/
-M]H;5````$'44QD0D$@+&1"03`+D(````Z:D```"-5"00QT0D"`0```"-ANH`
-M``")1"0$B10DZ/S___^Y"````.F!````B=C!Z!B(1"0,B=C!Z!"(1"0-B=C!
-MZ`B(1"0.B%PD#XG(#ZS8&(A$)!")R`^LV!"(1"01B<@/K-@(B$0D$HA,)!/V
-MAM4````0=13&1"06`L9$)!<`N2````#K)HUV`(U4)!3'1"0(!````(V&Z@``
-M`(E$)`2)%"3H_/___[D@````BU4TC40D#(E,)`B)1"0$B10DZ/S___^+7"0L
-MBW0D,(M\)#2+;"0X@\0\PXGV5E.#[!2+3"0@BUPD)(M1+(LR#[9#)#PO=&@\
-M+W<T/!L/A#(!```\&W<./!*-="8`#X4Z`0``ZTH\*(VV`````'1`/"H/A28!
-M``"-M@````#K,#R*="P\BG<8/#6-="8`#X3R````/(@/A0(!``")]NL0/(]T
-M##SA#X7R````B?;K=?9!.`%T!X%+9```!`#V03H0#X3^````@WDT`(UV``^%
-M\0````^V0R0\*'00/"IT##R(=`@\B@^%V0```/9""`%U&`^V0@2)1"0$B30D
-MZ/S___^$P`^$NP```(![%($/A+$```"!2V0```$`N`$```#IJ0```(![)0$/
-MA8\```"`>R8<#X>%````#[Y+)K@!````T^"I]C_`'74EJ0A`!@!U#JD``"``
-M=2*0C70F`.M>@TMD"+@!````D(UT)@#K7H-+9`&X`0```.M3@TMD(+@!````
-MZTCV03@!=`>!2V0```0`@TMD`;@!````ZS"+0V2I```@`'06]D$X`707#0``
-M!`")0V2X`0```.L1D+@`````ZPFX`0```(UT)@"#Q!1;7L.0D)"0D)"0D)"0
-M@^P(B1PDB70D!(G3BW0D%(M0!`^V1"00P>`$#[;)P>$("<&`?"0,`'0#@\D$
-M@_[_=!")\"7__P,`B8($QO__@\D"B0N+'"2+="0$@\0(PY"+0`0M``(!`(/*
-M`8F0`,@``,.-M"8`````C;PG`````%=64X/L$(G7BT`$A=)T2HVP`,;__XN`
-M`,;__Z,`````NP````"H`742ZR>0C70F`(L&HP````"H`707QP0D"@```.C\
-M____@\,!.?MUXHGVZP>X`````.L%N/____^#Q!!;7E_#C70F`(V\)P````!6
-M4X/L)(M<)##'1"0@`````(MS!,:#L`P````/M@T(````C50D(,=$)`@`````
-MQT0D!`(```#'!"0!````B=CHW/[__XM4)"")V.@A____NJ"&`0")V.@U____
-MA<!U1XN&#,;__Z,`````B40D(#T?8P``=3''@Z`,```?8P``QX.D#``````$
-M`,>#J`P``````0#'@[0,````````9K@``.DZ`@``QT0D(`````"+<P3&@[`,
-M```!#[8-&````(U4)"#'1"0(_____\=$)`0"````QP0D`0```(G8Z#_^__^+
-M5"0@B=CHA/[__[H0)P``B=CHF/[__X7`=6>+A@S&__^C`````(E$)"`]'T,`
-M`'0N/1]$``!U2L>#H`P``!]$``#'@Z0,``````<`QX.H#``````!`.F$`0``
-MC70F`,>#H`P``!]#``#'@Z0,``````0`QX.H#``````!`.E=`0``QT0D(```
-M``"+<P3&@[`,````#[8-*````(U4)"#'1"0(`````,=$)`0"````QP0D`0``
-M`(G8Z(+]__^+5"0@B=CHQ_W__[H0)P``B=CHV_W__X7`=4>+A@S&__^C````
-M`(E$)"`]OT,``'4QQX.@#```OT,``,>#I`P`````(`#'@Z@,````$```QX.T
-M#```(````&:X``#IX````,=$)"``````BW,$QH.P#`````^V#3@```"-5"0@
-MQT0D"`````#'1"0$`@```,<$)`$```")V.CE_/__BU0D((G8Z"K]__^Z$"<`
-M`(G8Z#[]__^%P'5?BX8,QO__HP````")1"0@/>\1``!T"3WO$@``=4+K(,>#
-MH`P``.\1``#'@Z0,``````0`QX.H#``````!`.L\QX.@#```[Q(``,>#I`P`
-M````"`#'@Z@,``````$`ZQRX_____^LDC70F`,>#M`P``!````"X`````.L/
-MQX.T#```,````+@`````@\0D6U[#C78`C;PG`````(/L/(E<)"R)="0PB7PD
-M-(EL)#B)QHG7B4PD&(MH!`^V1"1`/`1V!;@$````#[;8BX:T#```#[9(!(U4
-M)"B)?"0(B5PD!,<$)`$```")\.C=^___BU0D*(GPZ"+\__^Z$"<``(GPZ#;\
-M__^Z_____X7`=1J+A0S&__^C`````(E$)"B+5"08B0*Z`````(G0BUPD+(MT
-M)#"+?"0TBVPD.(/$/,.-M@````"-O"<`````4X/L*(M<)#"+@[0,```/MD@+
-MC50D)(M$)#2)1"0(QT0D!`$```#'!"0!````B=CH3/O__XM4)"2)V.B1^___
-MNA`G``")V.BE^___NO____^%P'4:BT,$+?0Y``"+`*,`````BU0D.(@"N@``
-M``")T(/$*%O#C70F`(V\)P````!55U93@^PLB<.(5"0;B<V#?"1```^$DP``
-M`+X`````D(M[!(N#M`P```^V2`+'1"0(_____\=$)`0!````QP0D`0```(U4
-M)"B)V.BQ^O__BU0D*(G8Z/;Z__^Z$"<``(G8Z`K[__^%P'4JBY<,QO__B14`
-M````#[9$)!LAT(GI.,AU#;@`````ZRB-M@````")5"0HQP0D"@```.C\____
-M@\8!.W0D0`^%<____[C_____@\0L6UY?7<.-M@````!3@^PHB<.+@+0,```/
-MM@B-5"0DQT0D"/_____'1"0$`````,<$)`````")V.@/^O__BU0D)(G8Z%3Z
-M__^Z$"<``(G8Z&CZ__^%P'4DQP0DX),$`+D"````N@,```")V.C<_O__N@``
-M``"%P'0(C78`NO____^)T(/$*%O#C70F`(/L+(E<)"2)="0HBUPD,(MT)#3&
-M1"0C_XU$)".)1"0(B70D!(D<).C\____A<!U<H!\)",`='F)V.A"____@_C_
-M=%^+@[0,```/MD@*C50D'(ET)`C'1"0$`````,<$)`````")V.A5^?__BU0D
-M'(G8Z)KY__^Z$"<``(G8Z*[Y__^%P'4<QP0DX),$`+D`````N@,```")V.@B
-M_O__A<!T#KC_____ZPR-M"8`````N`````"+7"0DBW0D*(/$+,/K#9"0D)"0
-MD)"0D)"0D)!55U93@^P\BVPD4`^V1"1@@[VT#`````^$&@,``(M\)%B$P`^$
-M:P$``(-\)%3_=10/MX6@#```9HD'N`$```#I'`,``(-\)%3^=16+A:0,``")
-M![@!````Z0,#``"-=@"#?"14_749BX6H#```B0>X`0```.GG`@``C;0F````
-M`(M$)%P#1"14B40D&#N%I`P```^'GP(``(M<)%2#X_R+5"14@^(#B50D('1N
-MC70D.,<$)`0```")\8G:B>CH_OO__X/#!,=$)!P$````.5PD&',0BT0D("M$
-M)%0#1"08B40D'(M$)"`Y1"0<=BV-#`:)_HM$)!R-5`0XC;8`````#[8!B`:#
-MQ@&#P0$YT77QBT0D'"M$)""-/`>+="08@^;\.?-S),<$)`0```"-3"0XB=J)
-MZ.B'^___BT0D.(D'@\<$@\,$.=YWW#E<)!@/ANT!``"-="0XQP0D!````(GQ
-MB=J)Z.A7^___BTPD&"G9#X3+`0``N@````"-M@`````/M@06B`0Z@\(!.<H/
-MA*X!``#K[(-\)%3_=2F`/P^)]G41QH6Q#````;@!````Z:T!``#&A;$,````
-MN`$```#IG`$``(M4)%R)5"0HB=`#1"14.X6D#```#X=9`0``@+VQ#`````^$
-M3`$``(M$)%2Z`````/>UJ`P``(72#X6<````@+VP#````'08BT0D5(E$)`2)
-M+"3H_/___X7`#X44`0``B>CHAOS__X/X_P^$!`$``(N%M`P```^V2`:-5"0X
-MBT0D5(E$)`C'1"0$`````,<$)`````")Z.B1]O__BU0D.(GHZ-;V__^Z$"<`
-M`(GHZ.KV__^%P`^%N0```,<$)."3!`"Y`````+H#````B>CH6OO__X7`#X69
-M````@WPD7``/A)<```#'1"0D`````(M4)%B+1"0DBS0"B<<#?"14BUT$@>L`
-M`@$`B>CHWOO__XFS",@``(N%M`P```^V2`6)?"0(QT0D!`0```#'!"0`````
-MC50D.(GHZ/#U__^+5"0XB>CH-?;__[H0)P``B>CH2?;__X7`=1S'!"2($P``
-MN0````"Z`0```(GHZ+WZ__^%P'00N`````#K(HGVN`$```#K&8-$)"0$BU0D
-M)#E4)"AVZNE6____D(UT)@"#Q#Q;7E]=PY"0D)"0D)"0N`````##C78`C;PG
-M`````(M4)`2+3"0(N``````Y%=`+``!^-(T44L'B`P^W@AP!``!FB0$/MX(>
-M`0``9HE!`@^V@B0!``"(00@/MH(E`0``B$$)N`$```#SPY"-="8`N(`;``##
-MC78`C;PG`````+B<````PXUV`(V\)P````"X!````,.-=@"-O"<`````5U93
-MBW0D$+L`````OP````"Y``````^VE#$P!0``@/K_=$*-@8````!F/8$`=P6#
-MPP'K,0^VPHN6C`4``&G`L````("\$*4````#=16#QP&-1P.#^`9V#8/#`;\`
-M````ZP.#PP&#P0&#^09UJ8G86UY?PXVV`````(V\)P````!55U93@^P$BVPD
-M&+X`````QP0D`````+N`````#[9$)!R->`&)V0^VA"NP!```//]T26:!^X$`
-M=P>#Q@'K.8GV#[;`BY6,!0``:<"P````@+P0I0````-U&X,$)`&+!"2#P`.#
-M^`9V#X/&`<<$)`````#K`X/&`3GW=!"#PP&!^X8```!UGKD`````B<B#Q`1;
-M7E]=PXUT)@"-O"<`````\\.-M"8`````C;PG`````(M$)`3&@)<`````PXUT
-M)@!64XM<)`RX_P```(7;=$R^_____[F"````C;0F``````^VA!FP!```//]T
-M'P^VP(N3C`4``&G`L`````^VA!"D````B?(XPG8"B<:#P0&!^88```!URHGR
-M#[;"6U[#B?:X`````,.-=@"-O"<`````N`````##C78`C;PG`````(G!B=#`
-MZ`0\"78%@\!7ZP.#P#"(`8G0@^`/@_@)?A&)T(/@#X/`5^L/C;0F`````(G0
-M@^`/@\`PB$$!PXUT)@"#[`B)'"2)="0$B<:)TP^VUNBJ____#[;;@\8"B=J)
-M\.B;____BQPDBW0D!(/$",.+1"0,QT`$`````,<``````+@`````PXGVC;PG
-M`````(M,)`2+06"%P'1%QT`@`````(!(*`3'06``````QT%H`````,=!9```
-M``"+40B#^C]_#XM!;,>$D+`"````````PXM!;,>$D+`!````````\\.-M"8`
-M````C;PG`````(M,)`2+06"%P'1%QT`@`````(!@*/O'06``````QT%H````
-M`,=!9`````"+40B#^C]_#XM!;,>$D+`"````````PXM!;,>$D+`!````````
-M\\.-M"8`````C;PG`````(/L#,<$)(````#H_/___[@`````@\0,PY"-M"8`
-M````5U93@^Q`BT0D4,9$)!AMQD0D&?_&1"0:(\9$)!L4QD0D'#K&1"0=[\9$
-M)!X6QD0D'Y*+L$`%``"%]G4"B<:-1"0@B<+&``"#P`&)TXU,)$`YR'7PQD0D
-M)`''1"0,(````(E4)`C'1"0$#@```(DT).C\____A<!U3,<$)(`:!@#H_/__
-M_\=$)`P@````B5PD",=$)`0/````B30DZ/S___^#^"!U'XUT)#"-?"08N0@`
-M``#\\Z8/E\(/DL"Y`0```#C"=!''!"1T`0``Z/S___^Y``````^VP8/$0%M>
-M7\-55U93@^Q<BT0D<(N0/`4``('"P`P``(E4)#B)P8L`A<!T%BT```(`B0&)
-M1"0$BT$0B00DZ/S___^+7"1PBT,(A<!T#XE$)`2+0Q")!"3H_/___XM4)'"+
-M0@R%P'0/B40D!(M"$(D$).C\____C40D3HE$)#2-1"10B40D,(U$)$J)1"0L
-MC40D3(E$)"B-1"14B40D)(U$)%:)1"0@C40D5XE$)!R-1"12B40D&(U$)%B)
-M1"04C40D2(E$)!"-1"19B40D#(U$)%J)1"0(C40D6XE$)`2+3"1P#[=!)(D$
-M).C\____BUPD<(N#<`4``(7`=#")1"0$B=@%6`4``(D$).C\____BU0D.(N"
-M<`4``(E$)`2)T`58!0``B00DZ/S___^+3"1PBX&,!0``A<!T,(E$)`2)R`5T
-M!0``B00DZ/S___^+7"0XBX.,!0``B40D!(G8!70%``")!"3H_/___XM4)'"+
-M@J@%``"%P'0PB40D!(G0!9`%``")!"3H_/___XM,)#B+@:@%``")1"0$B<@%
-MD`4``(D$).C\____BUPD<(N#X`8``(7`=#")1"0$B=@%R`8``(D$).C\____
-MBU0D.(N"X`8``(E$)`2)T`7(!@``B00DZ/S___^`?"1;`'1:O@````"+;"1P
-M@<4`!P``BWPD.(''``<``(UV``^WWHM,)'"+A)D8!P``B40D!(DL).C\____
-MBU0D.(N$FA@'``")1"0$B3PDZ/S___^#Q@$/MD0D6V8Y\'?"BTPD<(N!@`D`
-M`(7`=#")1"0$B<@%:`D``(D$).C\____BUPD.(N#@`D``(E$)`2)V`5H"0``
-MB00DZ/S___^+5"1PBX*H"0``A<!T,(E$)`2)T`60"0``B00DZ/S___^+3"0X
-MBX&H"0``B40D!(G(!9`)``")!"3H_/___XM<)'"+@_@)``"%P'0PB40D!(G8
-M!>`)``")!"3H_/___XM4)#B+@O@)``")1"0$B=`%X`D``(D$).C\____BTPD
-M<(N!Q`4``(7`=#")1"0$B<@%K`4``(D$).C\____BUPD.(N#Q`4``(E$)`2)
-MV`6L!0``B00DZ/S___^+5"1PBX)P!@``A<!T,(E$)`2)T`58!@``B00DZ/S_
-M__^+3"0XBX%P!@``B40D!(G(!5@&``")!"3H_/___XM<)'"+@R`&``"%P'0P
-MB40D!(G8!0@&``")!"3H_/___XM4)#B+@B`&``")1"0$B=`%"`8``(D$).C\
-M____BTPD<(N!/`8``(7`=#")1"0$B<@%)`8``(D$).C\____BUPD.(N#/`8`
-M`(E$)`2)V`4D!@``B00DZ/S___^+5"1PBX*H!@``A<!T,(E$)`2)T`60!@``
-MB00DZ/S___^+3"0XBX&H!@``B40D!(G(!9`&``")!"3H_/___XM<)'"+@\0&
-M``"%P'0PB40D!(G8!:P&``")!"3H_/___XM4)#B+@L0&``")1"0$B=`%K`8`
-M`(D$).C\____BTPD<(N!_`8``(7`=#")1"0$B<@%Y`8``(D$).C\____BUPD
-M.(N#_`8``(E$)`2)V`7D!@``B00DZ/S___^+5"1PBX(P"0``A<!T,(E$)`2)
-MT`48"0``B00DZ/S___^+3"0XBX$P"0``B40D!(G(!1@)``")!"3H_/___XM<
-M)'"+@U@)``"%P'0PB40D!(G8!4`)``")!"3H_/___XM4)#B+@E@)``")1"0$
-MB=`%0`D``(D$).C\____BTPD<(N!T`D``(7`=#")1"0$B<@%N`D``(D$).C\
-M____BUPD.(N#T`D``(E$)`2)V`6X"0``B00DZ/S___^+5"1PBX*,!@``A<!T
-M,(E$)`2)T`5T!@``B00DZ/S___^+3"0XBX&,!@``B40D!(G(!70&``")!"3H
-M_/___XM<)'"+BQ0*``"%R718BX,8"@``BY,<"@``B40D"(E4)`R)3"0$B=@%
-M_`D``(D$).C\____BTPD.(N!&`H``(N1'`H``(E$)`B)5"0,BX$4"@``B40D
-M!(G(!?P)``")!"3H_/___XM<)'"+BS@*``"%R718BX,\"@``BY-`"@``B40D
-M"(E4)`R)3"0$B=@%(`H``(D$).C\____BTPD.(N!/`H``(N10`H``(E$)`B)
-M5"0,BX$X"@``B40D!(G(!2`*``")!"3H_/___XM<)'"+BUP*``"%R718BX-@
-M"@``BY-D"@``B40D"(E4)`R)3"0$B=@%1`H``(D$).C\____BTPD.(N!8`H`
-M`(N19`H``(E$)`B)5"0,BX%<"@``B40D!(G(!40*``")!"3H_/___XM<)'"+
-MBZ0*``"%R718BX.H"@``BY.L"@``B40D"(E4)`R)3"0$B=@%C`H``(D$).C\
-M____BTPD.(N!J`H``(N1K`H``(E$)`B)5"0,BX&D"@``B40D!(G(!8P*``")
-M!"3H_/___XM<)'"+BX`*``"%R718BX.$"@``BY.("@``B40D"(E4)`R)3"0$
-MB=@%:`H``(D$).C\____BTPD.(N!A`H``(N1B`H``(E$)`B)5"0,BX&`"@``
-MB40D!(G(!6@*``")!"3H_/___XM<)'"+B\@*``"%R718BX/,"@``BY/0"@``
-MB40D"(E4)`R)3"0$B=@%L`H``(D$).C\____BTPD.(N!S`H``(N1T`H``(E$
-M)`B)5"0,BX'("@``B40D!(G(!;`*``")!"3H_/___XM<)'"+B^P*``"%R718
-MBX/P"@``BY/T"@``B40D"(E4)`R)3"0$B=@%U`H``(D$).C\____BTPD.(N!
-M\`H``(N1]`H``(E$)`B)5"0,BX'L"@``B40D!(G(!=0*``")!"3H_/___XM<
-M)'"+BQ`+``"%R718BX,4"P``BY,8"P``B40D"(E4)`R)3"0$B=@%^`H``(D$
-M).C\____BTPD.(N!%`L``(N1&`L``(E$)`B)5"0,BX$0"P``B40D!(G(!?@*
-M``")!"3H_/___X/$7%M>7UW#C;8`````@^P<B5PD%(ET)!B+="0@BUPD)(A>
-M-P^VVXE<)`2)-"3H_/___XE<)`2!QL`,``")-"3H_/___[@!````BUPD%(MT
-M)!B#Q!S#D(VT)@````!64X/L%(MT)"")-"3H_/___XDT).C\____C9[`#```
-MB1PDZ/S___^)-"3H_/___\<$)-`'``#H_/___XDT).C\____QT0D!`$```")
-M-"3H_/___\=$)`0!````B1PDZ/S___^[@````(N6/`4```^VA!.P!```//]T
-M*P^VP&G`L`````."C`4``/9`,@)T%F;'0#(!`,9`)AV)1"0$B30DZ/S___^#
-MPP&!^X8```!UN(N>/`4``('#P`P``+X`````#[:$'C`%```\_W0K#[;`:<"P
-M`````X.,!0``]D`R`G069L=`,@$`QD`F'8E$)`2)'"3H_/___X/&`8/^!G7!
-M@\046U[#C78`C;PG`````%.#[`B+7"00B1PDZ/S___^+@SP%```%P`P``(D$
-M).C\____@\0(6\.0C;0F`````%.#[`B+7"00B1PDZ/S___^+@SP%```%P`P`
-M`(D$).C\____@\0(6\.0C;0F`````(/L#(M$)!")!"3H_/___P^VP(/$#,.-
-M=@"-O"<`````@^PLB5PD'(ET)"")?"0DB6PD*(G#B=>)S8MP8(M`;(E$)!2%
-M]@^$-0$``("[EP`````/A2@!``")!"3H_/___XE$)!B%P`^$%`$``,9`).'&
-M0"4!B?J$TG0-B>@\`1G`]]"#P`?K#(GJ@/H!&<#WT(/`#8M4)!B(0B;&0A2`
-M#[=&'&:)0A")6AC'0B``````QT(T`````,=";#">`0")5"0$BT0D%(D$).C\
-M____QH.7`````6;'@Y0```#T`87;=%F+0V"%P'1<9H&[E````)8`=1>)1"0(
-MQT0D!"$```"+0"R)!"3H_/___V:#JY0````!QP0DT`<``.C\____BU0D%(D4
-M).C\____BT-@A<!T"8"[EP````!UKF:#NY0`````=!R+1"08@'@4`'42BT-@
-M#[=`.F:)0UJ[`````.L%N_____^+5"08B50D!(M$)!2)!"3H_/___^L)C70F
-M`+O_____B=B+7"0<BW0D((M\)"2+;"0H@\0LPY"-="8`@^Q,B5PD/(ET)$")
-M?"1$B6PD2(MT)%`/MFPD5(M^8(M&;(E$)""%_P^$\@0``("^EP`````/A>4$
-M``")!"3H_/___XE$)"2%P`^$T00``/8&`@^%!`$``(GJ@/H4=PL/ML*-!$#!
-MX`+K&+B)____B>KVXF;!Z`C`Z`0/ML`%\````(M4)"3&0B3AQD(E`<9")AR(
-M0B?&0A2`#[=''&:)0A")<AC'0B``````QT(T`````,=";#">`0")5"0$BT0D
-M((D$).C\____QH:7`````6;'AI0```#$"87V=%F+1F"%P'1@9H&^E````)8`
-M=1>)1"0(QT0D!"$```"+0"R)!"3H_/___V:#KI0````!QP0DT`<``.C\____
-MBU0D((D4).C\____BT9@A<!T"8"^EP````!UKF:#OI0`````#X2\`P``NP``
-M``"+1"0D@'@4``^$K@,``.FD`P``BU0D((D4).C\____B40D.(7`#X2,`P``
-MBUPD)(/#/(M`"(E$)!R+1"0DQD`D&L9`)0C&0"8:QD`G`,9`*!#&0"D`BT0D
-M.(M4)"2)0E#&0A2`#[=''&:)0A")<AB+1"0XBT`(B4(TQT(@$````(M&8`6X
-M````B4(XQD(<(,=";#">`0#'1"0$`````(D<).C\____BU0D)(M"((E$)`R+
-M1"0XBU`0BT`,B40D!(E4)`B)'"3H_/___XM$)"2)1"0$BU0D((D4).C\____
-MQH:7`````6;'AI0```#Z`(7V=%F+1F"%P'1<9H&^E````)8`=1>)1"0(QT0D
-M!"$```"+0"R)!"3H_/___V:#KI0````!QP0DT`<``.C\____BT0D((D$).C\
-M____BT9@A<!T"8"^EP````!UKF:#OI0`````=`J+5"0D@'H4`'0>C40D.(E$
-M)`2+1"0@B00DZ/S___^[_____^D^`@``BU0D)(E4)`2+1"0@B00DZ/S___^+
-M5"0@B10DZ/S___^)1"0DA<!U(8U$)#B)1"0$BT0D((D$).C\____N______I
-M&`(``(UV`(M4)"2#PCR)5"0HBTPD'(/!!(M4)!P/MD(##[8$`8A"!,9!`0K&
-M00(`N`````"+5"0<Q@00`(/``8/X!'7PB>B$P'4&@&$#_.M-B>@/MM!ITF#J
-M``"X'X7K4??JP?H%@$D#`XG5P>T8B>B(002)T\'K$(A9!8G0P>@(B40D&(A!
-M!HA1!XGHB$$(B%D)#[9$)!B(00J(40N+1"0XBU0D)(E"4,9")!4/M@'`^`?W
-MT(/`$8A")<9")@#&0B<`QD(H$,9"*0"`(3_&0A2`#[=''&:)0A")<AB+1"0X
-MBT`(B4(TQT(@$````(M&8`6X````B4(XQD(<(,=";#">`0#'1"0$`````(M$
-M)"B)!"3H_/___XM4)"2+0B")1"0,BT0D.(M0$(M`#(E$)`2)5"0(BT0D*(D$
-M).C\____BU0D)(E4)`2+1"0@B00DZ/S____&AI<````!9L>&E````/H`A?9T
-M68M&8(7`=%QF@;Z4````E@!U%XE$)`C'1"0$(0```(M`+(D$).C\____9H.N
-ME`````''!"30!P``Z/S___^+5"0@B10DZ/S___^+1F"%P'0)@+Z7`````'6N
-M9H.^E`````!T#[L`````BT0D)(!X%`!T!;O_____C40D.(E$)`2+5"0@B10D
-MZ/S____K!I"[_____XM$)"2)1"0$BU0D((D4).C\____ZPJ0C70F`+O_____
-MB=B+7"0\BW0D0(M\)$2+;"1(@\1,PY"-="8`@^Q,B5PD/(ET)$")?"1$B6PD
-M2(M\)%"+7"14BW0D6`^W1"1<9HE$)!X/ME0D9(A4)!V+;V"%[0^$Z0,``("_
-MEP`````/A=P#``"+32R)3"0XBT=LB40D)&;'AY0````0)XD$).C\____B40D
-M-(7`#X2Q`P``#[=4)!Z)5"0@9H-\)!X$=A*)5"0$QP0DD`$``.C\____ZQ2+
-M3"0DB0PDZ/S___^)1"0HA<!U'HM$)#2)1"0$BU0D)(D4).C\____N______I
-M=@,``(M,)"#!X0F)3"0PBU0D)(N"/`4``,9`)P&)?"0(BX(\!0``B40D!,<$
-M)`4```#H_/___X!-*`*+1V")1"0(QT0D!"$```"+3"0XB0PDZ/S___^+1"0T
-M@\`\B40D+(!\)!T`=!&+5"0TQT)D"@```,9")"CK+HM,)#3'0602````QD$D
-M*HM4)"B+0@B+3"0PB4PD"(M4)&")5"0$B00DZ/S___^+1V#V0#@!='F`?"0=
-M`1G`@^`"@^AXBTPD-(A!),9!)0")\,'H&(A!)HGPP>@0B$$GB?#!Z`B(02B)
-M\HA1*8G8#ZSP&(A!*HG8#ZSP$(A!*XG8#ZSP"(A!+(A9+<9!+@#&02\`#[=$
-M)!YFP>@(B$$P#[9$)!Z(03'&03(`QD$S`.M6@'PD'0$9P(/@`H/`*(M4)#2(
-M0B3&0B4`B=@/K/`8BTPD-(A!)HG8#ZSP$(A!)XG8#ZSP"(A!*(A9*<9!*@`/
-MMT0D'F;!Z`B(02L/MD0D'HA!+,9!+0"+5"0TB10DZ/S___^+1V`/MT`<BTPD
-M-&:)01#&012`B7D8BU0D*(M""(E!-(M$)#")02")45#&01P@BT=@!;@```")
-M03C'06PPG@$`QT0D!`````"+5"0LB10DZ/S___^+3"0TBT$@B40D#(M,)"B+
-M00R+41")1"0$B50D"(M$)"R)!"3H_/___\:'EP````&+5"0TB50D!(M,)"2)
-M#"3H_/___X7_#X2O````BT=@A<`/A*0```"`OY<`````#X0D`0``9H&_E```
-M`)8`=1>)1"0(QT0D!"$```"+0"R)!"3H_/___V:#KY0````!QP0DT`<``.C\
-M____BT0D)(D$).C\____BT=@A<!T3H"_EP`````/A,X```"0ZZ>+5"0T@'H4
-M`'4TNP````"`?"0=`'0MBTPD*(M!"(M4)#")5"0(B40D!(M,)&")#"3H_/__
-M_[L`````ZP>)]KO_____BT0D-(-X4`!T-8%X(``(``!W%8/`4(E$)`2+5"0D
-MB10DZ/S____K%XM$)#2#P%")1"0$BTPD)(D,).C\____BT0D-(E$)`2+5"0D
-MB10DZ/S___^+3"0DBX$\!0``QD`G`(E\)`B+@3P%``")1"0$QP0D!@```.C\
-M____@&4H_>L:N______K$V:#OY0`````#X4G____Z6#___^)V(M<)#R+="1`
-MBWPD1(ML)$B#Q$S#C78`C;PG`````(/L'(E<)!")="04B7PD&(M4)""+7"0D
-MBT(LBSB+<T@/MD,4/"!T/SP@=PJ$P'0C/`9W%NLM/")T+3PBD(UT)@!R((/`
-M@#P!=AFX`````(GVZUJ+0B#'0`0`````QD9F`>L$QD9F#8-[4`!T*8%[(``(
-M``!W$8U#4(E$)`2)/"3H_/___^L/C4-0B40D!(D\).C\____B5PD!(D\).C\
-M____B30D_U9PN`$```"+7"00BW0D%(M\)!B#Q!S#C70F`(/L'(E<)!")="04
-MB7PD&(MT)""+7F"%VW46BT0D*(D$)/]4)"3I5@$``(VV`````(-^=`!U#(-^
-M<`"-M@````!T$XM$)"B)!"3_5"0DC78`Z2L!``"`N[0`````#X41`0``@'LF
-M_P^%!P$``(M#-(7`=`J`>#4`#X7V````BT,L]D`($`^%Z0```(LX@'M/`'04
-MB5PD",=$)`0&````B00DZ/S___^+1"0DB49TBT0D*(E&>`^V2R0/MM&)T(/@
-M!H/X!G4T]L(!#X2&````QD,F!<9#)P2)7"0,#[9#38E$)`B+0S")1"0$BT,L
-MB00DZ/S____IAP```(/X!`^%?@```/;!`71YBU,TA=)T,`^W0C*H`G1J@^#]
-M9HE",HM#-&;'0#(!`(M#-,9`)AV+0S2)1"0$B3PDZ/S____K0L9#)@/&0R<$
-MB5PD!(D\).C\____ZRS&0R8%QD,G!F;'@Y0``````(E<)`2)/"3H_/___^L-
-MBT0D*(D$)/]4)"2)]HM<)!"+="04BWPD&(/$',-3@^P(BUPD$(7;#X2X````
-MBT-LB00DZ/S___^)PH7`#X1[````@+BE`````'1R@`L!#[:`I0```#P"=3B#
-M>V@`=1D/MH.8````@^`#B$,"#[:"I````(A#`>MM#[:#F0```(A#`HM#:`^V
-M@*0```"(0P'K5#P#=5`/MH.8````@^`#P>`"`H.9````B$,"BT-H#[:`I```
-M`(A#`>LKC78`BT-HA<!U"XM#9(7`=1")]NL6#[:`I````(A#`>L*#[:`D@``
-M`(A#`8/$"%O#C78`5E.#[`2+="00A?9T:KL`````#[:$,[`$```\_W0W#[;`
-M:<`H`0``B<(#EG`%``!T)(M")"4`__\`/0``_P!U%?9")P1T#XM"((7`=`B)
-M!"3H_/___X/#`8'[@````'6RBX8\!0``.?!U#07`#```B00DZ/S___^#Q`1;
-M7L.-=@!64X/L%(M<)""-L\`,``")'"3H_/___XE#%(E&%(F;/`4``(F>/`4`
-M`(N#2`4``(F&2`4``,:#K@P```'&AJX,```!B1PDZ/S___^)'"3H_/___XDT
-M).C\____B1PDZ/S___^$P'1NB30DZ/S___^$P'1BB1PDZ/S____'!"30!P``
-MZ/S___^)'"3H_/___\>#*`$``.@#``#'@S`!````````B9LT`0``C8,H`0``
-MB40D!(M#%(D$).C\____QT0D!`````")'"3H_/___[@!````ZP6X`````(/$
-M%%M>PU.#[`B+7"00B1PDZ/S___^!P\`,``")'"3H_/___[@!````@\0(6\.0
-MC;0F`````%575E.#[#R#/>0`````#X6!`0``QP7D`````0```,=$)#@`````
-MZ;P"``"0C70F``^WAAX!``#!X!`/MY8<`0``"=`Y1"0H#X43`0``OP````"Y
-M`````(E\)#!F@[D``````'5[B?K!X@6+AAP!``")@@````"+AB`!``")@@0`
-M``"+AB0!``")@@@````/MH(<````C0S]`````(T$`0^V7"0OB!R%#0````^V
-M@AP```"-!`$/MEPD+H@<A0X````/MH(<`````<'&!(T/`````(""'`````'K
-M>9"-="8`#[:9'````(G8N@````#WMC`!``"%TG1-BTPD,,'A`XT$&0^V5"0O
-MB!2%#0```(M4)##!X@4/MH(<````C00!#[9<)"Z('(4.````#[:"'`````'!
-MQ@2-#P````"`@AP````!ZP^#QP&#P2"#_P0/A0/___^#AB@!```!D(UT)@"#
-MQ0&#QA@[+=`+```/A;[^__^#1"0T`8-\)#0@#X48`0``@T0D.`&!?"0X_P``
-M``^%4@$``(-\)%0`=`>+="14Q@8`BQW0"P``QT0D)`````"%VWXYN0````#'
-M1"0D`````+H`````BX(H`0```40D)(-\)%0`=`R+@BP!``"+="14``:#P0&#
-MPA@YV779@WPD6``/A`$!``"]`````+L`````9H.[```````/A.D````/MH,<
-M````B40D((7`?FK'1"08`````(T4[0````")5"0<BT0D'`-$)!B--(4,````
-MBWPD6+@$````_(G!\Z8/E\(/DL`XPG4A@WPD5`!T#0^V@QT```"+="14B`8/
-MMH,<````B40D).L/@T0D&`&+5"0@.50D&'6I@\4!@\,@@_T$=&7I:?___P^V
-M3"0TB$PD+L=$)`P`````QT0D"`````"+7"0TB5PD!(MT)#B)-"3H_/___XE$
-M)"B]`````+X`````@SW0"P````^/3OW__^F+_O__#[9$)#B(1"0OQT0D-```
-M``#KH`^V1"0D@\0\6UY?7<.)]HV\)P````"#[!R)7"00B70D%(E\)!B+1"0@
-M#[9T)"2+>&R+6&#V``%T=8M3,(72=!F)\0^VP8E$)`@/MD--B40D!(D4).C\
-M____BY/D````A=)T'(GQ#[;!B40D"`^V@]D```")1"0$B10DZ/S___^)/"3H
-M_/___X7`=#N`N*4`````=#*)\@^VPHE$)`B+0R")1"0$B3PDZ/S____K&(GQ
-M#[;!B40D"(M#((E$)`2)/"3H_/___XM<)!"+="04BWPD&(/$',.#[#R)7"0L
-MB70D,(E\)#2);"0XBWPD0`^V="1$BU]@BV]LA=L/A'8#``"`OY<`````#X5I
-M`P``]@<"#X5@`P``#[:#)`$``(3`=`N)\CC0=4/I2@,```^V@]L```")1"00
-M#[8'@^`!#[;`B40D#`^V1P*)1"0(#[9'`8E$)`3'!"0D!0``Z/S___^[____
-M_^D1`P``B2PDZ/S___^)1"0<A<`/A/@"``"+4R")\0^VP8E$)!`/MH*8````
-M#[92`HT$@`^VA`(`````B40D#`^V12*)1"0(#[9%(8E$)`3'!"1L!0``Z/S_
-M__^+1"0<QD`DX<9`)0&)\H#Z`@^5P(/`&HM,)!R(02;&012`#[=#'&:)01")
-M>1C'02``````QT$T`````,=!;#">`0")3"0$B2PDZ/S____&AY<````!9L>'
-ME````/0!A?]T58M'8(7`=%QF@;^4````E@!U%XE$)`C'1"0$(0```(M`+(D$
-M).C\____9H.OE`````''!"30!P``Z/S___^)+"3H_/___XM'8(7`=`F`OY<`
-M````=;)F@[^4``````^$V0$``(M$)!R`>!0`#X7+`0``BU=@B50D*(M"+(L`
-MB40D)(D$).C\____B<.%P'40BTPD*,:!M0````'IH@$``(M$)"2)!"3H_/__
-M_XG&A<!U)8M4)"C&@K4````!B5PD!(M,)"2)#"3H_/___[L`````Z6L!``"-
-M0SR)1"0@QD,DX<9#)0'&0R8#BU0D*`^W0AQFB4,0QD-H#XE[&,=#(``"``"+
-M5@B)4S2X`````,8$$`"#P`$]``(``'7RB7-0QT-L,)X!`,=$)`0`````BTPD
-M((D,).C\____BT,@B40D#(M&#(M6$(E$)`2)5"0(BT0D((D$).C\____B5PD
-M!(M4)"2)%"3H_/___\:'EP````%FQX>4````^@"%_W19BT=@A<!T7&:!OY0`
-M``"6`'47B40D",=$)`0A````BT`LB00DZ/S___]F@Z^4`````<<$)-`'``#H
-M_/___XM,)"2)#"3H_/___XM'8(7`=`F`OY<`````=:YF@[^4`````'0J@'L4
-M`'4DBT,TB40D!(M$)"B)!"3H_/___XM4)"@/MH(D`0``B(>;````@WM0`'03
-MC4-0B40D!(M,)"2)#"3H_/___XE<)`2+1"0DB00DZ/S___^[`````.L%N___
-M__^+5"0<B50D!(DL).C\____ZP:0N_____^)V(M<)"R+="0PBWPD-(ML)#B#
-MQ#S#D(UT)@"#[!R)7"0,B70D$(E\)!2);"08BW0D((M4)"2`.@EW$`^V`O\D
-MA:0)``"-M@````"X_____^E*`0``BU($BX)`!0``A<!U"8G0C;0F`````(N`
-M/`4``,:`KPP```&)!"3H_/___[@`````Z14!```/MDH$N@````")\.@AZ/__
-MZ0`!```/MDH$N@$```")\.@,Z/__Z>L````/MD($B40D!(DT).C\____Z=8`
-M```/MFH$BWYLBUY@N/_____V1E@(#X2]````B70D"(N'/`4``(E$)`3'!"0%
-M````Z/S___^`2R@"B5PD",=$)`0A````BT,LB00DZ/S___^`>T\`=!K'!"30
-M!P``Z/S___^)/"3H_/___X![3P!UYHGHA,!T#&:#3EH09H-+.A#K"F:#9EKO
-M9H-C.N^)="0(BX<\!0``B40D!,<$)`8```#H_/___X!C*/VX`````.LG#[9"
-M!(E$)`2)-"3H_/___^L5#[9"!(E$)`2)-"3H_/___[@`````BUPD#(MT)!"+
-M?"04BVPD&(/$',.0C;0F`````(/L+(E<)"")="0DB7PD*(MT)#"+?FR+ASP%
-M``"`>"<`=6"+7G`/MH:;````B40D$`^VAI@````/ME8"C02`#[:$`@````")
-M1"0,#[9'(HE$)`@/MD<AB40D!,<$))@%``#H_/___\=&<`````"+1@B)1"0(
-MB70D!(M&>(D$)/_3ZSB-7GR)7"0$BT<4B00DZ/S____'1GST`0``QX:$````
-MT,0!`(FVB````(E<)`2+1Q2)!"3H_/___XM<)""+="0DBWPD*(/$+,.-M@``
-M``!55U93@^P<#[=$)#AIP"@!``")Q8M4)#`#JG`%``"+NCP%``"!Q\`,``"+
-M3"0TB6E@B4T@@WTP`'4M@WTT`'4G#[9R*XGSA-L/A"`$``"+72RY`````#N:
-MF`L```^$W0,``.GY`P``BT0D-(`(`8M%-(M4)#2)0FB+13")0F2+3"0P#[9Q
-M*XGSA-MT4XM=++D`````BT0D,#N8F`L``'0:ZR\/ML&)PL'B!HT$@HM4)#`Y
-MG`*8"P``=1R+7"0P#[9#*8T$@8M4)#2(@I@```#K#KD`````@\$!B?`XP77#
-MBU0D,(N*/`4```^V@3`%``"[`````#S_="2+53"%TG08#[;`:<`4#0```X&H
-M!0``NP`````YPG0JNP$````/MH$Q!0``//]T*XM5,(72="$/ML!IP!0-```#
-M@:@%```YPG4.BTPD-(A9`>G>````B?:#PP&Z``````^VA`HR!0``//]T(P^V
-MP&G`L`````.!C`4``#M%-'4,BWPD-(A?`>FH````@\,!@\(!@_H$=<F)V0^V
-MAS`%```\_W0DBU4PA=)U!8U9`>L8#[;`:<`4#0```X>H!0``.<)UZ.LHC78`
-M#[:',04``#S_="B+53"%TG0>#[;`:<`4#0```X>H!0``.<)U"XM$)#2(6`'K
-M/HGV@\,!N@`````/MH0Z,@4``#S_="`/ML!IP+`````#AXP%```[131U"8M4
-M)#2(6@'K"X/#`8/"`8/Z!'7,BTPD,(!Y.0%U2(M5,(72=!C'1"0(``````^V
-M14V)1"0$B10DZ/S___^+E>0```"%T@^$MP$``,=$)`@`````#[:%V0```(E$
-M)`2)%"3H_/___X.]Y``````/A(\!``"+=3"`?C``=%:_`````(U>*(UT)@")
-M7"08B1PDZ/S___^-2/B+5BR)1BR)60B)40R)`H"YVP```/]U#X!Y)0!U"8.Y
-MY`````!U"H/'`8GX.$8P=\&)^CA6,`^%E`````^VA=L```"+3"0TB$$"@'XP
-M``^$C@$``+L`````C7XHC;8`````B3PDZ/S___^-2/B+5BR)1BR)>0B)40R)
-M`HM!((7`=$`/MI';````.%`"=#2#>'``=2Z#>'0`=2B(4`(/MT$<B40D"(M4
-M)#"+@CP%``")1"0$QP0D!P```.C\____C78`@\,!.%XP#X84`0``ZY(/MD5-
-MBTPD-(A!`L:%VP```/^`?C``#X3V````NP````"0BWPD&(D\).C\____C4CX
-MBU8LB48LB7D(B5$,B0*`N=L```#_=$K&@=L```#_BT$@A<!T/`^V44TX4`)T
-M,X-X<`!U+8-X=`!U)XA0`@^W01R)1"0(BU0D,(N"/`4``(E$)`3'!"0'````
-MZ/S___^)]H/#`3A>,'9XZX8/MD5-BTPD-(A!`NMI#[;!B<+!X@:-!(*+?"0P
-M.9P'F`L``'4FBU0D,`^V0BF-!(&+7"0TB$,!B(.8````.$HK=1KK$(GVN0``
-M``"#P0&)\#C!=;F+5"0TQD(!_XM,)#3&00(`@[T<`0```'0)BX4@`0``B$$"
-MBTPD-(/!((U59(M%9(M<)#2)0R"+0@2)002+0@B)00B+0@R)00R+0A")01"+
-M0A2)012+0AB)01B+0AR)01R+0B")02"+0B2)022)V8/!#(U54(M%4(E##(M"
-M!(E!!(M""(E!"(M"#(E!#(M"$(E!$(N%C````(E#2(N%D````(E#3`^W13AF
-MB4-8#[=%.F:)0UJ+142+54B)0U")4U0/MD5.B$-<#[:%)`$``(B#FP```/9%
-M*`1U#(M\)#")/"3H_/___P^V522)T(/@!H/X!G4.]L(!=0F+1"0T@`@"ZP>+
-M5"0T@"+]#[95*-#J@^($BTPD-`^V`8/@^PG0B`$/MD$!B(&:````#[9!`HB!
-MF0```(D,).C\____QT0D"`````"+12")1"0$BUPD,(D<).C\____BWPD-(D\
-M).A?^?__@\0<6UY?7<.-M"8`````@^P<B5PD%(ET)!B+="0@BYX\!0``B30D
-MZ/S___^`?CD!=2V-@\`,``"`>#D!=%^`OK@,````=1C'1"0$`````(D$).C\
-M____@(:X#````9"-GB@!``")7"0$BT84B00DZ/S____'AB@!``#H`P``QX8P
-M`0```````(FV-`$``(E<)`2+1A2)!"3H_/___XM<)!2+="08@\0<PXVV````
-M`%575E.#[$R+1"1DBU`8B50D((M`'(E$)!@/MDH+B4PD'(M4)&"+@CP%``"+
-MF#P%``"^`````+\`````N0`````/MI09,`4``(#Z_W1&C8&`````9CV!`'<'
-M@\8!ZS6)]@^VPHN3C`4``&G`L````("\$*4````#=1>#QP&-1P.#^`9V#X/&
-M`;\`````ZP6)]H/&`8/!`8/Y!G6EB?6+FSP%``"!P\`,``"Q`)"-="8`#[:4
-M&3`%``"`^O]T1HV!@````&8]@0!W!X/&`>LUB?8/ML*+DXP%``!IP+````"`
-MO!"E`````W47@\<!C4<#@_@&=@^#Q@&_`````.L%B?:#Q@&#P0&#^09UI3ET
-M)!P/C3P)```[;"0<#Y[`BTPD:,<!`````#S_#X0<"0``#[;`:<#`#```BU0D
-M8`."/`4``(D$).C\____B<&%P`^$]P@``(M$)!B)1"0D#[:!I0```#P"#X4$
-M`@``BU0D:,<"!````(M$)"`/MG`'BQ$/MT$DNP````"`O`*P!```_P^$T0$`
-M`(GR@/HC#X>W`0``#[;"_R2%S`D``(M,)"3'`453`Q&X`0```.FE`0``C40D
-M2(E$)`S'1"0($`,``,=$)`0!````B0PDZ/S___^$P`^$<0$``(M$)$B%P`^$
-M;`$``"7_`P``:<`0)P``C8@0EJ__NG.(JTR)R/?BB<@IT-'H`<+!Z@>+3"0D
-MB1&X`0```.D\`0``C40D2(E$)`S'1"0("`,``,=$)`0!````B0PDZ/S___^$
-MP`^$"`$``(M$)$B%P`^$`P$``"7_`P``:<#H`P``C8C(Y??_NLMK**^)R/?B
-MB<@IT-'H`<+!Z@2+3"0DB1&X`0```.G3````C40D2(E$)`S'1"0("`,``,=$
-M)`0!````B0PDZ/S___^$P`^$GP```(M$)$B%P`^$F@```,'H$"7_`P``:<#H
-M`P``C8C(Y??_NLMK**^)R/?BB<@IT-'H`<+!Z@2+3"0DB1&X`0```.MJC40D
-M2(E$)`S'1"0(#`,``,=$)`0!````B0PDZ/S___^$P'0ZBT0D2(7`=#DE_P,`
-M`&G`Z`,``(V(R.7W_[K+:RBOB<CWXHG(*=#1Z`'"P>H$BTPD)(D1N`$```#K
-M#+@`````ZP6X`0````^VV`^VP^GR!@``/`,/A=0&``"+1"1HQP`$````BU0D
-M(`^V4@>(5"0KQT0D.`````#'1"0\`````,=$)$``````QT0D1`````"+$0^V
-MJMD```"%[0^.CP```+\`````QT0D%`````"X`0```(G&B?G3YHM,)!0/MH01
-M,@4``#S_=!\/ML!IP+````")PP.:C`4``(M#5(M`&`^V0`8Y\'02@T0D%`&#
-M?"04!`^$+`8``.N_A=L/A"(&```/MT,D@+P"L`0``/\/A!`&``"`NZ4````#
-M#X4#!@``B5R\.(/'`3G]#X5V____@'PD*U4/A]L%```/MD0D*_\DA5P*``"+
-M1"0DQP!``P,1N`$```#IP`4``(U$)$B)1"0,QT0D"#0#``#'1"0$`0````^V
-M1"0K@\`!@^`#BT2$.(D$).C\____A,`/A(0%```/MU0D2(E4)$B!^O__``!U
-M%(M4)"3'`O____^X`0```.ED!0``N,#AY`")T;H`````]_&+5"0DB0*X`0``
-M`.E&!0``C40D2(E$)`S'1"0($`,``,=$)`0!````BT0D/(D$).C\____A,`/
-MA!4%``"+1"1()?\#``!IP!`G``"-B!"6K_^Z<XBK3(G(]^*)R"G0T>@!PL'J
-M!XM,)"2)$;@!````Z>$$``"-1"1(B40D#,=$)`@(`P``QT0D!`$```"+1"0\
-MB00DZ/S___^$P`^$L`0``(M$)$@E_P,``&G`Z`,``(V(R.7W_[K+:RBOB<CW
-MXHG(*=#1Z`'"P>H$BTPD)(D1N`$```#I?`0``(U$)$B)1"0,QT0D"`@#``#'
-M1"0$`0```(M$)#R)!"3H_/___X3`#X1+!```#[=$)$HE_P,``&G`Z`,``(V(
-MR.7W_[K+:RBOB<CWXHG(*=#1Z`'"P>H$BTPD)(D1N`$```#I%@0``(U$)$B)
-M1"0,QT0D"`P#``#'1"0$`0```(M$)#R)!"3H_/___X3`#X3E`P``BT0D2"7_
-M`P``:<#H`P``C8C(Y??_NLMK**^)R/?BB<@IT-'H`<+!Z@2+3"0DB1&X`0``
-M`.FQ`P``C40D2(E$)`S'1"0(%`,``,=$)`0!````BT0D.(D$).C\____A,`/
-MA(`#``"+1"1()?\#``"Z`````&G:.K@!`+DZN`$`]^&-%!,%XTH#`(/2`,=$
-M)`B@A@$`QT0D#`````")!"2)5"0$Z/S___^+3"0DB0&X`0```.DS`P``C40D
-M2(E$)`S'1"0(%`,``,=$)`0!````BT0D/(D$).C\____A,`/A`(#``"+1"1(
-M)?\#``"Z`````&G:.K@!`+DZN`$`]^&-%!,%XTH#`(/2`,=$)`A0PP``QT0D
-M#`````")!"2)5"0$Z/S___^+3"0DB0&X`0```.FU`@``C40D2(E$)`S'1"0(
-M%`,``,=$)`0!````BT0D0(D$).C\____A,`/A(0"``"+1"1()?\#``"Z````
-M`&G:YA-``KGF$T`"]^&-%!,%#?].!(/2`,=$)`B`EI@`QT0D#`````")!"2)
-M5"0$Z/S___^+3"0DB0&X`0```.DW`@``C40D2(E$)`S'1"0(%`,``,=$)`0!
-M````BT0D1(D$).C\____A,`/A`8"``"+1"1()?\#``"Z`````&G:KD7A`+FN
-M1>$`]^&-%!,%*5*O`8/2`,=$)`A`0@\`QT0D#`````")!"2)5"0$Z/S___^+
-M3"0DB0&X`0```.FY`0``C40D2(E$)`S'1"0(L`,``,=$)`0!````BT0D/(D$
-M).C\____A,`/A(@!``"+1"1(P>@/@^`!BU0D)(D"N`$```#I<P$``(M,)""`
-M>0@`=!"+1"0\@:"H````__?__^L.BT0D/(&(J``````(``"+1"0\B00DZ/S_
-M__^X`0```.DU`0``BT0D((!X"`!T$(M$)#R!H*@```#_[___ZPZ+1"0\@8BH
-M`````!```(M$)#R)!"3H_/___[@!````Z?<```"+5"0@@'H(`'00BT0D/(&@
-MJ````/_?___K#HM$)#R!B*@`````(```BT0D/(D$).C\____N`$```#IN0``
-M`(M,)""`>0@`=!"+1"0\@:"H````_[___^L.BT0D/(&(J`````!```"+1"0\
-MB00DZ/S___^X`0```.E[````BT0D((!X"`!T$(M$)#R!H*@```#___[_ZPZ+
-M1"0\@8BH```````!`(M$)#R)!"3H_/___[@!````ZT"+5"0@@'H(`'00BT0D
-M/(&@J````/___?_K#HM$)#R!B*@```````(`BT0D/(D$).C\____N`$```#K
-M!;@`````#[;`ZPF-="8`N``````/ML#K%K@`````ZP^+3"1HQP$`````N```
-M``"#Q$Q;7E]=PY"-M"8`````55=64X/L;(N\)(````"+A"2$````B[0DC```
-M`(G%P>T8B<+!ZA"(5"1`#[;,B$PD,(A$)"^+G"2(````@</`#```N`````"+
-ME"2(````Q@00`(/``3V`&P``=>N)<A"AX````(A"*(/``:/@````B>F(2B,/
-MMD0D0(A"(@^V3"0PB$HA#[9$)"^(0B#&0BD`#[<'9HE"&`^W1P)FB4(:BT<$
-MB4(<BY0DB````('"@!D``(N,)(@```")D;P,``")<Q`/MD$HB$,HB>B(0R,/
-MMDPD0(A+(@^V1"0PB$,A#[9,)"^(2R#&0RD!#[<'9HE#&`^W1P)FB4,:BT<$
-MB4,<B9.\#```BY0DB`````^W0AIF/20G#X0C`0``9CTD)P^'C````&8]1"$/
-MA`\!``!F/40A=TQF/2`A#X3_````9CT@(7<19CU0!P^%"@$``(GVZ>@```!F
-M/2(AC;0F``````^$UP```&8]0"&-M@`````/A>(```#IP@```)"-="8`9CT0
-M)P^"S@```&8]$2>)]@^&IP```&8M("=F@_@"B?8/A[(```#ID@```)"-="8`
-M9CV`)P^$@P```&8]@">)]G<R9CU`)W1U9CU`)XUT)@!W$&8],"</A7P```"-
-M="8`ZUMF/40G=%5F/6`GC70F`'5FZTEF/8!R=$-F/8!RB?9W"&8]@B=U4.LS
-M9CV`D8GV=`YF/8"4=4#K(XVV`````(N,)(@```!FQT$D@)'&028$9L=#)("1
-MQD,F!.L;BX0DB````&;'0"2`E,9`)@1FQT,D@)3&0R8$#[9'"(N4)(@```"(
-M0BH/MD<(B$,JQT0D#```!`#'1"0(`````,=$)`0"````B30DZ/S___^+C"2(
-M````B0''1"0,`"```,=$)`@`````QT0D!`````")-"3H_/___XG!B[0DB```
-M`(E&"(L&A<`/A.T!``"%R0^$Y0$``(V0``(!`(E6!(V````"`(D&!0!```")
-M`XE3!(E+"(LUT`L``(7V?E^[`````+D`````#[>!'`$``&8[!W4_#[>!'@$`
-M`&8[1P)U,HN1+`$``(/"`8F1+`$``(N!*`$``(E$)!B%P'05.<)V$8G0N@``
-M``#W="08B9$L`0``@\,!@\$8.?-UJXN4)(@```"+0@0MX'T``,<``?`#`(M"
-M!"W8?0``QP`!``#HBT(0QT0D!'@```")!"3H_/___XG")0!P```]`"```'8F
-MB="`Y(^`S""+C"2(````BU$0B40D",=$)`1X````B10DZ/S___^)Z(A$)%\/
-MME0D0(A4)%X/MDPD,(A,)%T/MD0D+XA$)%S'1"0H`````+T`````9H.]````
-M```/A*````"`O1P`````#X2`````NP````"+5"0HP>(#B50D)(U,)%R)3"0<
-MBT0D)`'8C32%#````+D$````_(M\)!SSI@^7P@^2P#C"=3</MH4=````@\`!
-MB(4=````#[:5'````(32=!PXT'88#[;`#[;*N@````!F]_&(E1T```"-="8`
-M@\,!#[:%'````#G8?YB#1"0H`8/%((-\)"@$#X52____B[0DB````,>&2`4`
-M``$```"X`0```.L%N`````"#Q&Q;7E]=PXUV`(V\)P````!55U93@^P,BW0D
-M((M\)"2+;FP/M@:#X`$/ML")1"0(N`````#&!#@`@\`!@_@@=?2+G;P,``")
-MVK``C;8`````Q@00`(/``3T``@``=?*-2S:Z``````^V1#(AB`0*#[9$,B"(
-M1`H!@\("@_HH=>>-2Q2R`@^V1#(+B$0*_@^V1#(*B$0*_X/"`H/Z%G7FC4LN
-ML@`/MD0R28@$"@^V1#)(B$0*`8/"`H/Z"'7GB5\8BT90BU94@\`!@](`B0>)
-M5P2#?F``=3SV!@%T-XM&9(7M#Y7"A<!T$H32=`X/MD`S@+P%L`0``/]U&8M&
-M:(32=#6%P'0Q#[=`)("\!;`$``#_=",/MH:8````#[96`HT$@`^VA`(`````
-MB$<,QT0D"`````#K(HDL).C\____A<!T$H"XI0````)U"0^V1@&(1PSK!,9'
-M#/_&1PT`QD<.`<9'$A#&1Q$0#[9$)`B-%``/ME\*@^/]"=.(7PK!X`4/MD\(
-M@^'?"<&(3P@/MT98P>@'@^`!P>`&@^&_"<&(3P@/MT98P>@"@^`!#[97"8/B
-M_@G"B%<)#[=&6L'H`\'@!X/A?PG!B$\(#[=&6M'H@^`!`<"#XOT)PHA7"0^W
-M1EC!Z`.#X`'!X`:#XK\)PHA7"0^W1EK!Z`3!X`>#XG\)PHA7"8/)$(A/"`^V
-M!M#H@^`!@^/^"<.(7PH/M@:#X`2#X_L)PXA?"F;'1Q0`$`^VAIL```"(1P\/
-MMH:8````B$<<@\0,6UY?7<.)]HV\)P````!55U93@^P(BUPD*(MT)"R%VW03
-MN`````#&!!@`@\`!/:P```!U\H7V=!*X`````)#&!#``@\`!@_@H=?2+1"0<
-MB[@\!0``#[9$)"")1"0$B3PDZ/S___^)P6:%P'0-#[?`@+P'L`0``/]U2XN_
-M/`4``(''P`P``(N'/`4``(D$).C\____*40D(`^V1"0@B40D!(D\).C\____
-MB<%FA<`/A"D#```/M\"`O`>P!```_P^$&`,```^WP0^VA`>P!```9H'Y@0`/
-MAS<"``"+CZ@%```/M\!IP!0-``"-+`&%VP^$U@```(M5#(72=&P/MH<P!0``
-M//]T%0^VP&G`%`T``(T$`;Z`````.<)T(`^VAS$%```\_W0:#[;`:<`4#0``
-MC00!.<)U"KZ!````B?"(0P*`?3(`="^Z``````^VP@^V3`5`N`$```#3X`E#
-M((/"`3A5,G80Z^3&0P+_BT4(#[9`"8E#(,8#`0^V13&(0P&+14B)0P2+14R)
-M0PB-2PR-55B+15B)0PR+0@2)002+0@B)00B+0@R)00R+17")0QR+5"0@B5,D
-M#[:%D````(E#*+@`````Z1<"``"%]@^$"@(``(-\)"0`#XC_`0``#[:%D```
-M`#E$)"0/C>X!``"+1"0DC12`C535`(V"D`````^V2`2(#@^V0`6(1@&+@I@`
-M```/M@"#X`^(1@*`^0-T(H#Y`W<.@/D"#X6.````Z9````"`^01T-8#Y$HUV
-M`'5\ZU6+5"0DC022BY3%F`````^V0@&#X`</ML#!X`@/ME("`="-!(`!P(E&
-M!.M6BU0D)(T$DHN$Q9@````/MD`"A,!U"<=&!`````#K-P^VP(/H%(E&!.LL
-MBU0D)(T$DHN4Q9@````/MD("P>`(#[92`P'0C02``<")1@3K!\=&!`````"-
-M3@B+5"0DC022C83%D````(U0#(M`#(E&"(M"!(E!!(M""(E!"(M"#(E!#(M"
-M$(E!$(M"%(E!%(M"&(E!&(M"'(E!'+@`````Z=`````/M]!ITK````")U@.W
-MC`4``,9#`O_&`P*+AXP%```/MD0"'XA#`8M&5`^V0`F)0R`/MH:E````/`)U
-M+<=#!$A05`"-0PS'0PQ2;V-KQT`$9713=,=`"&]R(``/MU8BC4,7Z/>]___K
-M13P#=2'&0P$0QT,@`0```,=#!$A05`#'0PQ%2C,T9L=#$#``ZR#&0P1V#[=6
-M((U#!>C`O?__QD,,9`^W5B*-0PWHL+W__\9#''(/ME8=C4,=Z&"]__^+1"0@
-MB4,DN`````#K!;C_____@\0(6UY?7<.0C70F`%575E.#[`R+="0HN`````#&
-M!#``@\`!/2@-``!U\HM$)""+F#P%```/MD0D)(E$)`2)'"3H_/___XG!9H7`
-M=`T/M\"`O`.P!```_W5+BYL\!0``@</`#```BX,\!0``B00DZ/S___\I1"0D
-M#[9$)"2)1"0$B1PDZ/S___^)P6:%P`^$1P,```^WP("\`[`$``#_#X0V`P``
-M#[?!#[:$`[`$``!F@?F!``^'50(``(N+J`4```^WP&G`%`T``(TL`8M5#(72
-M=&P/MH,P!0``//]T%0^VP&G`%`T``(T$`;^`````.<)T(`^V@S$%```\_W0:
-M#[;`:<`4#0``C00!.<)U"K^!````B?B(1@*`?3(`="^Z``````^VP@^V3`5`
-MN`$```#3X`E&((/"`3A5,G80Z^3&1@+_BT4(#[9`"8E&(,8&`0^V13&(1@&+
-M14B)1@2+14R)1@B-3@R-55B+15B)1@R+0@2)002+0@B)00B+0@R)00R+17")
-M1AR+1"0DB48D@+V0``````^$1@(``,9$)`L`#[9\)`N-!+_!X`.-##`!Z(V0
-MD`````^V6@2(F:@````/ME(%B)&I````BX"8````#[8`@^`/B(&J````@/L#
-M="V`^P-W#H#[`@^%K0```.FV````@/L$D(UT)@!T/H#[$@^%E0```)"-="8`
-MZV:-#+_!X0.+E`V8````#[9"`8/@!P^VP,'@"`^V4@(!T(T$@`'`B80.K```
-M`.MNC02_C13%`````(N$%9@````/MD`"A,!U#<>$%JP`````````ZTB-%+\/
-MML"#Z!2)A-:L````ZS:-#+_!X0.+E`V8````#[9"`L'@"`^V4@,!T(T$@`'`
-MB80.K````.L.C02_QX3&K`````````"-!+_!X`.-G`:@````C4L0C80%D```
-M`(U0#(M`#(E#$(M"!(E!!(M""(E!"(M"#(E!#(M"$(E!$(M"%(E!%(M"&(E!
-M&(M"'(E!'(!$)`L!#[9$)`LXA9`````/AM<```#ID?[__P^WT&G2L````(G7
-M`[N,!0``QD8"_\8&`HN#C`4```^V1`(?B$8!BT=4#[9`"8E&(`^VAZ4````\
-M`G4MQT8$2%!4`(U&#,=&#%)O8VO'0`1E=%-TQT`(;W(@``^W5R*-1A?H%[K_
-M_^M%/`-U(<9&`1#'1B`!````QT8$2%!4`,=&#$5*,S1FQT80,`#K(,9&!'8/
-MMU<@C48%Z."Y___&1@QD#[=7(HU&#>C0N?__QD8<<@^V5QV-1AWH@+G__XM$
-M)"2)1B2X`````.L,N/_____K!;@`````@\0,6UY?7<.-M"8`````C;PG````
-M`%575E.#[`R+="0HN`````#&!#``@\`!/:0,``!U\HM$)""+F#P%```/MD0D
-M)(E$)`2)'"3H_/___XG!9H7`=`T/M\"`O`.P!```_W5+BYL\!0``@</`#```
-MBX,\!0``B00DZ/S___^+5"0D*<(/ML*)1"0$B1PDZ/S___^)P6:%P`^$'@,`
-M``^WP("\`[`$``#_#X0-`P``#[?!#[:$`[`$``!F@?F!``^',P(``(N+J`4`
-M``^WP&G`%`T``(TL`8M5#(72=&P/MH,P!0``//]T%0^VP&G`%`T``(T$`;^`
-M````.<)T(`^V@S$%```\_W0:#[;`:<`4#0``C00!.<)U"K^!````B?B(1@*`
-M?3(`="^Z``````^VP@^V3`5`N`$```#3X`E&((/"`3A5,G80Z^3&1@+_BT4(
-M#[9`"8E&(,8&`0^V13&(1@&+14B)1@2+14R)1@B-3@R-55B+15B)1@R+0@2)
-M002+0@B)00B+0@R)00R+17")1AR`O9``````#X0D`@``QD0D"P`/MGPD"XT$
-MO\'@`XT,,`'HC9"0````#[9:!(A9)`^V4@6(426+@)@````/M@"#X`^(02:`
-M^P-T+8#[`W<.@/L"#X6A````Z:<```"`^P20C70F`'0[@/L2#X6)````D(UT
-M)@#K78T,O\'A`XN4#9@````/MD(!@^`'#[;`P>`(#[92`@'0C02``<")1`XH
-MZV*-!+^-%,4`````BX05F`````^V0`*$P'4*QT06*`````#K/XT4OP^VP(/H
-M%(E$UBCK,(T,O\'A`XN4#9@````/MD("P>`(#[92`P'0C02``<")1`XHZPN-
-M!+_'1,8H`````(T$O\'@`XU<!B"-2PR-A`60````C5`,BT`,B4,,BT($B4$$
-MBT((B4$(BT(,B4$,BT(0B4$0BT(4B4$4BT(8B4$8BT(<B4$<@$0D"P$/ME0D
-M"SB5D`````^&T````.FL_O__#[?0:=*P````B=<#NXP%``#&1@+_Q@8"BX.,
-M!0``#[9$`A^(1@&+1U0/MD`)B48@#[:'I0```#P"=2W'1@1(4%0`C48,QT8,
-M4F]C:\=`!&5T4W3'0`AO<B``#[=7(HU&%^A)MO__ZT4\`W4AQD8!$,=&(`$`
-M``#'1@1(4%0`QT8,14HS-&;'1A`P`.L@QD8$=@^W5R"-1@7H$K;__\9&#&0/
-MMU<BC48-Z`*V___&1AQR#[97'8U&'>BRM?__N`````#K#+C_____ZP6X````
-M`(/$#%M>7UW#C;0F`````%575E.#[`B+7"0DN`````#&!!@`@\`!/0`!``!U
-M\HM$)!R+N#P%```/MD0D((E$)`2)/"3H_/___XG!9H7`=`T/M\"`O`>P!```
-M_W5+B[\\!0``@<?`#```BX<\!0``B00DZ/S___^+5"0@*<(/ML*)1"0$B3PD
-MZ/S___^)P6:%P`^$P@$```^WP("\![`$``#_#X2Q`0``#[?!#[:$![`$``!F
-M@?F!``^'UP```(N/J`4```^WP&G`%`T``(TT`8M6#(72=&P/MH<P!0``//]T
-M%0^VP&G`%`T``(T$`;V`````.<)T(`^VAS$%```\_W0:#[;`:<`4#0``C00!
-M.<)U"KV!````B>B(0P*`?C(`="^Z``````^VP@^V3`9`N`$```#3X`E#((/"
-M`3A6,G80Z^3&0P+_BT8(#[9`"8E#(,8#`0^V1C&(0P&+1DB)0P2+1DR)0PB-
-M2PR-5EB+1EB)0PR+0@2)002+0@B)00B+0@R)00R+1G")0QRX`````.G)````
-M#[?0:=*P````B=8#MXP%``#&0P+_Q@,"BX>,!0``#[9$`A^(0P&+1E0/MD`)
-MB4,@#[:&I0```#P"=2W'0P1(4%0`C4,,QT,,4F]C:\=`!&5T4W3'0`AO<B``
-M#[=6(HU#%^CEL___ZT4\`W4AQD,!$,=#(`$```#'0P1(4%0`QT,,14HS-&;'
-M0Q`P`.L@QD,$=@^W5B"-0P7HKK/__\9##&0/MU8BC4,-Z)ZS___&0QQR#[96
-M'8U#'>A.L___N`````#K!;C_____@\0(6UY?7<.-=@"-O"<`````@^PLB5PD
-M'(ET)"")?"0DB6PD*(M\)#"+;"0TBT=LB40D%(M%)(DXBT=@A<!U$L9%9@*)
-M+"3_57#IN`4``(UV`/9`*`)T$L9%9@*)+"2-=@#_57#IG04``(M,)!2)#"3H
-M_/___XG&A<!U%L9%9@*)+"3_57#I?`4``(VT)@````#'0&0`````B6A(BT=@
-MB488BT=@#[=`'&:)1A#&1A2`#[9%9#P"#X19`0``/`)W"83`="+INP(``#P#
-MC;8`````#X3!`0``/`0/A:4"``")]NF-`0``BT=@]D`X`8UT)@`/A)`````/
-MMD5EJ`)T!L9&)(CK$(/@!#P!&<"#X`6#Z':(1B2+34B+74P/MT509HE$)!K&
-M1B4`B=C!Z!B(1B:)V,'H$(A&)XG8P>@(B$8HB%XIB<@/K-@8B$8JB<@/K-@0
-MB$8KB<@/K-@(B$8LB$XMQD8N`,9&+P`/MT0D&F;!Z`B(1C`/MDPD&HA.,<9&
-M,@#&1C,`ZVL/MD5EJ`)T!L9&)"CK$(/@!#P!&<"#X`6#P"J(1B2+34B+74P/
-MMT509HE$)!K&1B4`B<@/K-@8B$8FB<@/K-@0B$8GB<@/K-@(B$8HB$XIQD8J
-M``^W1"0:9L'H"(A&*P^V3"0:B$XLQD8M`(M'8`6X````B48XQD8<(`^W1"0:
-MP>`)B48@@TYD`NE\`0``#[9%2#P0=P7V!P)U"<9%9@;IK0,``(U.)`^VP(U5
-M4(E$)`B)5"0$B0PDZ/S___^+1V`%N````(E&.,9&'""!3F0``!``QD85J_9%
-M908/A"D!``"+14R)1B#I'@$```^V166#X#`\('41QD8D&\9&)0'&1B@`Z0(!
-M``#&1B0UZ?D```"+1V`/MD`D@^`%@_@%=1.!3F0``"``#[=55&8[54IU#NM<
-MQD5F!HUV`.D2`P``#[9%4SSCD(UT)@!T0SSC=Q(\0G0[/+"-="8`="`\0'4B
-MZRT\[(VV`````'00/.]T'SSE=0Z-M@````#K$V:)54KK#<9%9@:-="8`Z<("
-M``#&1B2P#[=%2(A&)0^W14J(1B8/MT5,B$8G#[=%3HA&*`^W15"(1BD/MD52
-MB$8J#[9%4XA&*P^V14F(1BP/MD5+B$8M#[9%38A&+@^V14^(1B\/MD51B$8P
-M]D5E!G0=#[=%5,'@"8E&((-.9`3K#<9%9@;I2P(``(UT)@#'1FSPM@$`#[9%
-M9:@&#X0>`@``J`)T!H-.9`CK!(-.9!"-?CR+76B%VW0&]D5E`74\BU5LA=(/
-MA","``#'1"0(`````(M,)!2+@3P&``")1"0$B2PD_]*%P`^$``(``(M$)!2+
-MF#P&``"%VW1(B30DZ/S____'1"0$`````(D\).C\____@\,0BT/PB40D#(M#
-M^(M3_(E$)`2)5"0(B3PDZ/S___^+0_2#PQ"%P`^%@@$``.O3QT0D!`````")
-M/"3H_/___XM&(#T`"```=T.+3"04B0PDZ/S___^)PH7`=0G&168+Z5T!``"+
-M0`B)1C2)5E"+1B")1"0,BT(,BU(0B40D!(E4)`B)/"3H_/___^M3/0```0!W
-M0XM$)!2)!"3H_/___XG"A<!U"<9%9@OI$P$``(M`"(E&-(E64(M&((E$)`R+
-M0@R+4A")1"0$B50D"(D\).C\____ZPG&168&Z>(````/MD5EJ`20C70F``^$
-MOP```(!]9`-U(HM-6(7)=!N+5C2+1B")1"0(B4PD!(D4).C\____Z9<```"+
-M56B%TG4-BU5LA=(/A;D```#K:(M^-*@!=0F)TY"-="8`ZS"+56R%TG0IQT0D
-M"`$```"+3"04BX$\!@``B40D!(DL)/_2A<!T"HM$)!2+F#P&``"#PQ"+0_B+
-M4_")5"0(B40D!(D\).C\____`WOPBT/T@\,0A<!U'>O;BT8@BU8TA<!T$<8"
-M`(/"`8/H`70&Z_.#3F0!B70D!(M,)!2)#"3H_/___^LNB70D!(M$)!2)!"3H
-M_/___XDL)/]5<.L6NP````#I3/[__XM^-(UT)@#I5/___XM<)!R+="0@BWPD
-M)(ML)"B#Q"S#C;0F`````%=64X/L$(M\)""+="0DN`````#&!#``@\`!@_AX
-M=?2#OT@%```!#Y1&$P^V5R(/MD\A#[9?(`^V1R.(1@.(5@*(3@&('H!.$1`/
-MMT<89HE&!`^W1QIFB48&BX=(!0``B$9LQD82(`^W5QIF@?H@(70'9H'Z(B%U
-M1\9&%P*-1CS'1CQ2;V-KQT`$97120<=`"$E$(%/'0`Q31"`RQT`0,3)X(,=`
-M%$-O;G3'0!AR;VQL9L=`'&5RQD`>`.G^````C8+PV/__9H/X`7829H'Z0"%T
-M"V:!^D0A#X6E````QD87!`^W5QJ-@O#8__]F@_@!=T.-1CS'1CQ2;V-KQT`$
-M97120<=`"$E$(#+'0`PW,7@@QT`04T%3(,=`%$-O;G3'0!AR;VQL9L=`'&5R
-MQD`>`.F)````9H'Z0"%T!V:!^D0A=7N-1CS'1CQ2;V-KQT`$97120<=`"$E$
-M(%/'0`Q31"`RQT`0,31X(,=`%$-O;G3'0!AR;VQL9L=`'&5RQD`>`.L[QD87
-M"(U&/,=&/%)O8VO'0`1E="`WQT`(-3`@4\=`#$%402#'0!!#;VYTQT`4<F]L
-M;&;'0!AE<L9`&@#&1A<HQD82`<9&$"B-1AC'1AA(:6=HQT`$4&]I;L=`"'0@
-M5&7'0`QC:&YOQT`0;&]G:<=`%&5S+"#'0!A);F,NQD`<`(N'1`4``(7`=!"+
-M0`B)1F2)PL'Z'XE6:.L.BT<(B49DB<+!^A^)5FC'1F``(```QT0D!'P```"+
-M1Q")!"3H_/___XG"@>+P`P``P>H$B%9M@^`/B$9OQT0D!(````"+1Q")!"3H
-M_/___XG"@>(``/`#P>H4B%9N)0``#P#!Z!"(1G"#Q!!;7E_#C;8`````55=6
-M4X/L'(M\)#"+="0TBUPD.+@`````Q@08`(/``3V<````=?*)<PB#_A-^"8''
-MP`P``(/N%+@`````@[RWL`(````/A9\"``")G+>P`@``B7MLBT0D/(E#<(M,
-M)$")2WB`?SD!#X5X`@``@?Z%````#X]:`@``#[:$-[`$```\_P^$2@(```^V
-MP&:)1"08#[?`:<`H`0``B<4#KW`%``#V12<$#X0G`@``BT4D)0#__P`]``#_
-M``^%%`(``/9%*`0/A(<!``#&A;0`````#[9-)`^VT8G0@^`&@_@&=3GVP@$/
-MA`,!``#&128%QD4G!(EL)`P/MD5-B40D"(M%,(E$)`2+12R)!"3H_/___[@!
-M````Z=`!``"#^`0/A<(!``#VP0$/A+D!``"+72R+132%P`^%@@```,9%)@/&
-M12<$@'L*`'11O@````"-0SB)1"04BTPD%(D,).C\____B<*+0SR)4SR+3"04
-MB0J)0@2)$(!Z)O]T%3G5=!'&A;4````!N`$```#I7`$``(/&`0^V0PHY\'^[
-M@+VU`````0^$/P$``(EL)`2)/"3H_/___[@!````Z2X!``"`>"8`#X4?`0``
-M9H-@,OV+131FQT`R(`"+132)1"0$B3PDZ/S___^X`0```.G]````BT4L#[9`
-M"8!_)@!T+[L`````#[;P#[;+B?#3^*@!=!3'1"0(`````(E,)`2)/"3H_/__
-M_X/#`3A?)G?9QD4G!L9%)@5FQX64``````");"0$B3PDZ/S___^X`0```.F:
-M````BVTL@'T*`'1>QD0D&P"-13B)1"00BTPD$(D,).C\____B<*+13R)53R+
-M3"00B0J)0@2)$(!Z)O]T'@^V0B4\(G0$/`UU$L>$M[`"````````N`````#K
-M0H!$)!L!#[9$)!LX10IWK@^W1"08B40D"(E<)`2)/"3H_/___[@!````ZQ?'
-MA+>P`@```````+@`````ZP6X`0```(/$'%M>7UW#D)"0D)"0D)"0D)"0D)"0
-MBT0D!`^V5"0,Q@`(QD`!$H!\)`@`=`F`2`($ZP>-=@"`8`+[A-)T"(!@#-_K
-M!HGV@$@,(+@4````PXVV`````//#C;0F`````(V\)P````!55U93@^PLBVPD
-M0(M\)$@/MD0D3(A$)!L/ME0D4(A4)!J+5"1$BT(8B40D*,="&`````"#?"0H
-M``^%70$``(DL).C\____B<:X`````(7V#X3]`0``B2PDZ/S___^)1"0HA<!U
-M%HET)`2)+"3H_/___[@`````Z=<!``#&1B0:QD8E",9&)@C&1B<`QD8H_\9&
-M*0#&1A6KBU0D1`^W0AQFB480B6X8QT8@_P```,=&9`@```"+1"0HBT`(B48T
-M!?\```")1CC&1APDBT0D*(E&4,=&;'#W`0#&1A2`C5X\QT0D!`````")'"3H
-M_/___\=$)`S_````BT0D*(M0$(M`#(E$)`2)5"0(B1PDZ/S___^)="0$B2PD
-MZ/S___^[R/___^L;QP0DZ`,``.C\____@^L!B2PDZ/S___^$VW0,#[9&%#R`
-M=-V$P'0]C40D*(E$)`2)+"3H_/___P^W1AZ)1"0$BU0D1(M"+(D$).C\____
-MB70D!(DL).C\____N`````#IR@```,=&4`````")="0$B2PDZ/S___^+1"0H
-MBU@(#[9$)!J)1"0(#[9$)!N)1"0$C4,$B00DZ/S___^)QL8#`,9#`0#&0P(`
-MQD,#`(E\)`2)+"3H_/___XU7)+@`````Q@00`(/``8/X$'7TC5X$QD<D%<9'
-M)1&(7RC&1RD`C7<\#[;;B5\@QT=D`````(M4)"B+0@B)1S2)5U#'1"0$````
-M`(DT).C\____B5PD#(M$)"B+4!"+0`R)1"0$B50D"(DT).C\____N`$```"#
-MQ"Q;7E]=PY"0D)"0D%.+7"0(BT0D#(G"9HE#!,9#"@!FQT,(``!FA<!T&H/J
-M`;D`````BP-FB10(@\$"@^H!9H/Z_W7N6\.-M@````!64XM<)`R+1"00B<9F
-MB4,$QD,*`6;'0P@``&:%P'0BN@````"Y`````(VT)@````"+`V:)%`B#P@&#
-MP0)F.?)U[UM>PXVV`````(V_`````%.+7"0(@'L*`74J#[=#"`^WR(L3#[<4
-M2H/``6:)0PAF.T,&<@9FQT,(``!F@VL$`0^WPNL4BQ,/MT,$@^@!9HE#!`^W
-MP`^W!$);PY"-="8`@^P(B1PDB70D!(M<)`R+3"00B<Z`>PH!=28/MU,$#[=#
-M"`'"#[=#!HG&B=#!^A_W_HL#9HD,4&:#0P0!ZQ:)]@^W0P0/M\B+$V:)-$J#
-MP`%FB4,$BQPDBW0D!(/$",.0BT0D!&:#>`0`#Y3`#[;`PXM$)`2+"#G(=0>Y
-M`````.L*BQ&+002)0@2)$(G(PXGV5U93BU0D$(M,)!0/MGPD&(GXA,!T-@^V
-M`HG3O@`````Z`704ZQ\/ME,!#[9!`8/#`8/!`3C"=0V#Q@&)\HGX.,)UX^L'
-MN`````#K!;@!````6UY?PXUT)@"-O"<`````BT0D!,9``0"+5"0(B%`"QT`$
-M`````,.)]HV\)P````!55U93BTPD%(M\)!B+;"0<BW0D(`^V40$/ML*-!$#!
-MX`*)PP-9"(/"`8A1`0%Q!+@`````Q@08`(/``8/X#'7TB3N):P2)\(A#"(GR
-M#[;&B$,)P>H0@^(_#[9#"H/@P`G0B$,*6UY?7<.-M"8`````BU0D!`^V0@$Z
-M`@^2P`^VP,/K#9"0D)"0D)"0D)"0D)!3#[=,)`P/MEPD$(M4)`BX`````(!Z
-M`O]U"&:)"HA:`NL,@\`!@\($9CV``'7F#[?`6\.-M@````"-O"<`````@^P<
-MB5PD#(ET)!")?"04B6PD&(ML)""+3"0HBUPD+`^W1"0DC52%`(!Z`O]U"&:)
-M"HA:`NL9#[;#B40D"`^WP8E$)`2)+"3H_/___P^WP(M<)`R+="00BWPD%(ML
-M)!B#Q!S#C;8`````C;PG`````%,/MUPD#`^V3"00BU0D"+@`````.$H"=1=F
-M.1IU$L9"`O]FQP+__^L3C;0F`````(/``8/"!&8]@`!UV`^WP%O#ZPV0D)"0
-MD)"0D)"0D)"05E.+7"0,#[=T)!`/MDPD%+H`````B=`X3),"=09F.323=`Z#
-MP`&#P@&!^H````!UY&8]@`!U!;B``0``#[?`6U[#C;0F`````(V\)P````"#
-M[!")'"2)="0$B7PD"(EL)`R+;"04#[9%)#P(=$@\*'1$/*@/A!8!```\B(UT
-M)@`/A%H!```\"G0L/"J-="8`="0\J@^$]@```#R*C70F``^$.@$``#PO=`P\
-MCXUT)@`/A>@!```\+P^$E0```#PO=R(\"G1D/`IW"CP(C70F`'5$ZU8\*'1[
-M/"J-M@````!U-.MO/(\/A/0````\CXGV=Q4\B`^$Y@```#R*C70F`'44Z=D`
-M```\J(VT)@````!T?CRJ='J^`````+\`````N`````#I9@$```^V12;!X`@/
-MME4G"=`/ME4E@^(?P>(0"=")QK\`````#[9%*.D]`0``#[95)L'B&`^V12?!
-MX!`)P@^V12D)P@^V12C!X`@)PHG6OP`````/MD4KP>`(#[95+`G0Z04!``"0
-MC70F``^V52;!XA@/MD4GP>`0"<(/MD4I"<(/MD4HP>`("<*)UK\`````#[95
-M*L'B&`^V12O!X!`)P@^V12T)P@^V12S!X`@)T.FV````C;8`````#[9%)HG"
-MN`````#!XA@/MDTGB<NY`````,'C$`G("=H/MDTMNP`````)R`G:#[9-*(G+
-MN0````#!XP@)R`G:#[9-*8G+N0`````)R`G:#[9-*KL`````#Z3+&,'A&`G(
-M"=H/MDTKNP`````/I,L0P>$0"<@)V@^V32R[``````^DRPC!X0B)Q@G.B=<)
-MWP^V52[!XA@/MD4OP>`0"<(/MD4Q"<(/MD4PP>`("="-=@")=5B)?5R)16!F
-M@TT2`8L<)(MT)`2+?"0(BVPD#(/$$,/K#9"0D)"0D)"0D)"0D)!64XMT)`P/
-MMT0D$+K_____9H7`="VZ_____[D`````@^@!#[?`C5@!#[8$,3'0#[;`P>H(
-M,Q2%X`L``(/!`3G9=>:)T%M>PXGVC;PG`````(/L3(M$)%`/ME`SB50D1`^V
-M4#*)5"1`#[90,8E4)#P/ME`PB50D.`^V4"^)5"0T#[90+HE4)#`/ME`MB50D
-M+`^V4"R)5"0H#[90*XE4)"0/ME`JB50D(`^V4"F)5"0<#[90*(E4)!@/ME`G
-MB50D%`^V4":)5"00#[90)8E4)`P/ME`DB50D"(E$)`3'!"3(!0``Z/S___^#
-MQ$S#D(UT)@!3@^P8BU0D((M,)"0/MD$!B$(!#[9!`HA"`HM!!(E"!(M:"`^V
+M?T5,1@$!`0D```````````$``P`!``````````````"P<`0``````#0`````
+M`"@`#@`+`````````````````%.+7"0(BT0D#(G"9HE#!,9#"@!FQT,(``!F
+MA<!T&H/J`;D`````BP-FB10(@\$"@^H!9H/Z_W7N6\.-M@````!64XM<)`R+
+M1"00B<9FB4,$QD,*`6;'0P@``&:%P'0BN@````"Y`````(VT)@````"+`V:)
+M%`B#P@&#P0)F.?)U[UM>PXVV`````(V_`````%.+7"0(@'L*`74J#[=#"`^W
+MR(L3#[<42H/``6:)0PAF.T,&<@9FQT,(``!F@VL$`0^WPNL4BQ,/MT,$@^@!
+M9HE#!`^WP`^W!$);PY"-="8`@^P(B1PDB70D!(M<)`R+3"00B<Z`>PH!=28/
+MMU,$#[=#"`'"#[=#!HG&B=#!^A_W_HL#9HD,4&:#0P0!ZQ:)]@^W0P0/M\B+
+M$V:)-$J#P`%FB4,$BQPDBW0D!(/$",.0BT0D!&:#>`0`#Y3`#[;`PXM$)`2+
+M"#G(=0>Y`````.L*BQ&+002)0@2)$(G(PXGV5U93BU0D$(M,)!0/MGPD&(GX
+MA,!T-@^V`HG3O@`````Z`704ZQ\/ME,!#[9!`8/#`8/!`3C"=0V#Q@&)\HGX
+M.,)UX^L'N`````#K!;@!````6UY?PXUT)@"-O"<`````BT0D!,9``0"+5"0(
+MB%`"QT`$`````,.)]HV\)P````!55U93BTPD%(M\)!B+;"0<BW0D(`^V40$/
+MML*-!$#!X`*)PP-9"(/"`8A1`0%Q!+@`````Q@08`(/``8/X#'7TB3N):P2)
+M\(A#"(GR#[;&B$,)P>H0@^(_#[9#"H/@P`G0B$,*6UY?7<.-M"8`````BU0D
+M!`^V0@$Z`@^2P`^VP,/K#9"0D)"0D)"0D)"0D)!3#[=,)`P/MEPD$(M4)`BX
+M`````(!Z`O]U"&:)"HA:`NL,@\`!@\($9CV``'7F#[?`6\.-M@````"-O"<`
+M````@^P<B5PD#(ET)!")?"04B6PD&(ML)""+3"0HBUPD+`^W1"0DC52%`(!Z
+M`O]U"&:)"HA:`NL9#[;#B40D"`^WP8E$)`2)+"3H_/___P^WP(M<)`R+="00
+MBWPD%(ML)!B#Q!S#C;8`````C;PG`````%,/MUPD#`^V3"00BU0D"+@`````
+M.$H"=1=F.1IU$L9"`O]FQP+__^L3C;0F`````(/``8/"!&8]@`!UV`^WP%O#
+MZPV0D)"0D)"0D)"0D)"05E.+7"0,#[=T)!`/MDPD%+H`````B=`X3),"=09F
+M.323=`Z#P`&#P@&!^H````!UY`^WP%M>PXGVC;PG`````(/L$(D<)(ET)`2)
+M?"0(B6PD#(ML)!0/MD4D/`AT2#PH=$0\J`^$%@$``#R(C70F``^$6@$``#P*
+M="P\*HUT)@!T)#RJ#X3V````/(J-="8`#X0Z`0``/"]T##R/C70F``^%Z`$`
+M`#PO#X25````/"]W(CP*=&0\"G<*/`B-="8`=43K5CPH='L\*HVV`````'4T
+MZV\\CP^$]````#R/B?9W%3R(#X3F````/(J-="8`=13IV0```#RHC;0F````
+M`'1^/*IT>KX`````OP````"X`````.EF`0``#[9%)L'@"`^V52<)T`^V526#
+MXA_!XA`)T(G&OP`````/MD4HZ3T!```/ME4FP>(8#[9%)\'@$`G"#[9%*0G"
+M#[9%*,'@"`G"B=:_``````^V12O!X`@/ME4L"=#I!0$``)"-="8`#[95)L'B
+M&`^V12?!X!`)P@^V12D)P@^V12C!X`@)PHG6OP`````/ME4JP>(8#[9%*\'@
+M$`G"#[9%+0G"#[9%+,'@"`G0Z;8```"-M@`````/MD4FB<*X`````,'B&`^V
+M32>)R[D`````P>,0"<@)V@^V32V[``````G("=H/MDTHB<NY`````,'C"`G(
+M"=H/MDTIB<NY``````G("=H/MDTJNP`````/I,L8P>$8"<@)V@^V32N[````
+M``^DRQ#!X1`)R`G:#[9-++L`````#Z3+",'A"(G&"<Z)UPG?#[95+L'B&`^V
+M12_!X!`)P@^V13$)P@^V13#!X`@)T(UV`(EU6(E]7(E%8&:#31(!BQPDBW0D
+M!(M\)`B+;"0,@\00P^L-D)"0D)"0D)"0D)"0D(/L3(M$)%`/ME`SB50D0`^V
+M4#*)5"0\#[90,8E4)#@/ME`PB50D-`^V4"^)5"0P#[90+HE4)"P/ME`MB50D
+M*`^V4"R)5"0D#[90*XE4)"`/ME`JB50D'`^V4"F)5"08#[90*(E4)!0/ME`G
+MB50D$`^V4":)5"0,#[90)8E4)`@/MD`DB40D!,<$)`````#H_/___X/$3,.)
+M]HV\)P````!3@^P8BU0D((M,)"0/MD$!B$(!#[9!`HA"`HM!!(E"!(M:"`^V
M0@&-!$#!X`*+40B)1"0(B50D!(D<).C\____@\086\.-="8`C;PG`````%.+
-M5"0(BUI$#[9*/+@`````Q@00`(/``8/X<'7TB5I$B$H\6\.-="8`C;PG````
+M5"0(BUI$#[9*/+@`````Q@00`(/``8/X='7TB5I$B$H\6\.-="8`C;PG````
M`(M4)`2X`````(VT)@````#&!!#_@\`!/0`"``!U\O/#BT0D!+D`````.P!T
-M#8M(!(L1BT$$B4($B1")R,.0D)!3BTPD"(L9BX,$`0``B<*!XG[__O^)DP0!
-M```E?O_R_XM1!(D"BU$$B4(,BU$$B4(0BU$$B4(4BU$$B4(8BU$$B4($BP&+
-M@%0!``"C`````"7^`/__BQ&)@E0!``!;PY!3BUPD"`^V3"0,BP.+D`0!``")
+M#8M(!(L1BT$$B4($B1")R,.0D)!3BUPD"(L+BY$$`0``B=`E?O_^_XF!!`$`
+M`('B?O_R_XM#!(D0BT,$B5`,BP.+@%0!``"C`````"7^`/__BQ.)@E0!``!;
+MPXGVC;PG`````%.+7"0(#[9,)`R+`XN0!`$``(D5``````^W0R1F/8!D=`YF
+M/8"1=`AF/8"4=1.)]@^VR8/!"+@!````T^`)PNL/#[;)@\$,N`$```#3X`G"
+MBP.)D`0!``!;PXVV`````%.+7"0(#[9,)`R+`XN0!`$``(D5``````^W0R1F
+M/8!D=`YF/8"1=`AF/8"4=1.)]@^VR8/!"+C^____T\`APNL/#[;)@\$,N/[_
+M___3P"'"BP.)D`0!``!;PXVV`````(/L"(D<)(ET)`2+="0,#[9,)!"`^?]T
+M;H#Y'W<SBYX8`0``N@$```#3XHG0]]`AV(F&&`$``(N&6`$``*,`````(=!T
+M08F&6`$``.LYC78`BYX<`0``#[;!@^@@N@$```")P=/BB=#WT"'8B88<`0``
+MBX9@`0``HP`````AT'0&B89@`0``BQPDBW0D!(/$",/K#9"0D)"0D)"0D)"0
+MD)"#[!R)7"0,B70D$(E\)!2);"08BVPD*`^V5"0DBT0D((LX@/H#=GP/MMK!
+MXP.-M!\``@``QP8,`0``QP0D$"<``.C\____C9P?!`(```^V50/!XA@/MD4"
+MP>`0"<(/MD4`"<(/MD4!P>`("<*)$\<&$`$``,<$)!`G``#H_/___P^V50?!
+MXA@/MD4&P>`0"<(/MD4$"<(/MD4%P>`("<*)$^MZ#[;:P>,#C;0[``(``,<&
+M#`$``,<$)!`G``#H_/___XV<.P0"```/ME4#P>(8#[9%`L'@$`G"#[9%``G"
+M#[9%`<'@"`G"B1/'!A`!``#'!"00)P``Z/S___\/ME4'P>(8#[9%!L'@$`G"
+M#[9%!`G"#[9%!<'@"`G"B1.+7"0,BW0D$(M\)!2+;"08@\0<P^L-D)"0D)"0
+MD)"0D)"0D(/L'(E<)!2)="08BW0D(`^V7"0DB5PD!(DT).C\____QP0D$"<`
+M`.C\____B5PD!(DT).C\____BUPD%(MT)!B#Q!S#C;8`````C;\`````55=6
+M4X/L#(ML)"`/ME0D)`^V1"0HB$0D"XM%`(!])@`/A$(!``"-F(0!``"-N-`!
+M``"^``````^VTHE4)`2)]HM$)`2)\=/XJ`$/A`,!``"#_@-V#HL#HP````"#
+MX/Z)`^L,BP.C`````(/@_HD#QP0D$"<``.C\____@'PD"P!T/H/^`W8.BP>C
+M`````(/(`HD'ZPR+!Z,`````@\@"B0>)^H/^`W8)BP*C`````.L'BP*C````
+M`*@"=&3KY8GV@_X#=BS'@ZP`````````QP0D$"<``.C\____BX.P````HP``
+M``"#R`&)@[````#K-,>#S`````````#'!"00)P``Z/S___^+@]````"C````
+M`(/(`8F#T````.LCC78`@_X#=AO'0_P!````BP.C`````(/(`8D#ZQF-M@``
+M``#'0_P!````BP.C`````(/(`8D#@\8!@\,(@\<$#[9%)CGP#X?8_O__@\0,
+M6UY?7<-64X/L!(M,)!0/MEPD&(M$)!"+,(/Y`W87C93.@`$``(L"HP````"#
+MX/Z)`NL5B?:-E,Z``0``BP*C`````(/@_HD"A-MT68/Y`W85C92.T`$``(L"
+MHP````"#R`*)`NL3C92.T`$``(L"HP````"#R`*)`HV$CM`!``"0C70F`(/Y
+M`W8+BQ")%0````#K"9"+$(D5`````/;"`G1SZ^&0@_D#=C6-',T`````C80S
+M,`(``,<``````,<$)!`G``#H_/___XV<,S0"``"+`Z,`````@\@!B0/K-HT<
+MS0````"-A#-0`@``QP``````QP0D$"<``.C\____C9PS5`(``(L#HP````"#
+MR`&)`XUV`(/$!%M>PY"0D)"0D)"0D)"#[!")'"2)="0$B7PD"(EL)`R+7"08
+MBTPD'`^W;"0@9H%[).$!=1`/MD,F@^@1O@`````\`78OBT0D%(L0B[K4!```
+M#[=#$+XDVP``9CV#`'<1#[?`#[:$`A@$``!I\-P```"--#?&000%@&$%_H`A
+MW[@`````9H%[).$!=1(/MD,F@^@!/`$/EL`/ML"-=@")PL'B!P^V`8/@/PG0
+MB`'V0V8!=01FB6D(#[=!"(A#%6:!>R3A`74H#[93)HU"_SP!=PT/ME,G@^(/
+MZR:-="8`C4+ON@\````\`786C70F`+H`````@WXP`'0'#[9618/B#P^V`8/@
+M\`G0B`&+'"2+="0$BWPD"(ML)`R#Q!##D%.+3"0(BQD/MX$\"```@\`!9HF!
+M/`@``&8[@4`(``!R"6;'@3P(``````^W@3P(``#!X`(#@30'``"+5"0,BQ*)
+M$`^W@3P(``")@RP!``!;P^L-D)"0D)"0D)"0D)"0D%93BTPD&`^W5"00#[9T
+M)!2+7"0,N`````"-M"8`````Q@0(`(/``8/X!'7T9H'B_P\/MP%F)0#P"=!F
+MB0$/ME,(P>(,BP$E_P_P_PG0B0$/MD,&@^`"@_@!&=*#X@*#P@'!X@4/MD$#
+M@^`?"="#R!"#X/>(00/V0P8!=!:)\H/B?\'B!`^W00)F)0_X"=!FB4$"6U[#
+MC70F`(V\)P````"+3"0$BU0D"+@`````C78`Q@00`(/``8/X#77T#[9!)8@"
+M#[9!)HA"`0^V02>(0@(/MD$HB$(##[9!*8A"!`^V02J(0@4/MD$KB$(&]D%F
+M!'0C#[9!+(A""`^V02V(0@D/MD$NB$(*#[9!+XA""P^V03"(0@RX`0```,.0
+MC70F`%575E.+;"04BWPD&+H`````O@$```#K4`'2B=C3^*@!=!#WP@````%U
+M%H'R=R?;`.L.]\(````!=`:!\G<GVP"#Z0&#^?]UT(/&`8/^"748B=#!Z!"(
+M10")T,'H"(A%`8A5`EM>7UW##[9</O^Y!P```.NDC;8`````C;\`````4XM<
+M)`@/MT0D#,'@`@.##`4``(L(A<ET,(L3#[=!'F;!Z`4/M\"-!(4``P``B8)P
+M`0``BQ,/MTD>@^$?N`$```#3X(F"=`$``%O#D(UT)@#SPXVT)@````"-O"<`
+M````@^P<B5PD#(ET)!")?"04B6PD&(ML)"`/MG0D)`^V5"0HB?`/MOB-'/T`
+M````C00[C43%`,>`<`@```````"$T@^$J@$``(GP/`-V-(M%``4``@```=C'
+M`"````#'!"00)P``Z/S___^+10`%!`(``(T$`XL`HP````#K.8UT)@")\`^V
+MV,'C`XM%``4``@```=C'`"````#'!"00)P``Z/S___^+10`%!`(```'#BP.C
+M`````,'H$(3`>2:)\`^VT`^V12F-!(*)1"0$QP0D6````.C\____N`````#I
+MA`$``(GP/`-V>`^VV,'C`XM%``4``@```=C'`"P```#'!"00)P``Z/S___^+
+M10`%!`(``(T$`XL`HP````"-%/\E_P```(F$U7`(``"+10`%``(``(T$`\<`
+M)````,<$)!`G``#H_/___XM%``4$`@```<.+`Z,`````)?___P#K>(GP#[;8
+MP>,#BT4`!0`"```!V,<`+````,<$)!`G``#H_/___XM%``4$`@``C00#BP"C
+M`````(T4_R7_````B835<`@``(M%``4``@``C00#QP`D````QP0D$"<``.C\
+M____BT4`!00"```!PXL#HP`````E____`(T4_\'@"`F$U7`(``"X`0```.MZ
+MC70F`(GP#[;0B=/!XPB)V0.-[`8``(L!HP````#!Z!"$P'D@#[9%*8T$@HE$
+M)`3'!"2$````Z/S___^X`````.LXB?:+20R)#0````"-%/^-5-4`B8IP"```
+MB=@#A>P&``"+0`2C`````,'@"`G(B8)P"```N`$```"+7"0,BW0D$(M\)!2+
+M;"08@\0<PXVV`````%575E.#[!R+;"0P@'TK`'0KN0````"+1"0T]D`(`700
+MZQJ+5"0T#[9""-/XJ`%U#(/!`0^V12MF.<AWYHM4)#2+0AR%P'0E@\!HBU44
+MB40D!(D4).C\____BU0D-(M"'(E$)`2)+"3H_/___XM$)#2#P"B+5"0T.4(H
+M#X1?`0``B40D&(M$)!B)!"3H_/___XG'@W@@``^$'@$``(!X1P!T:6:#?4P`
+M=&*^`````(GVC02U``````.%#`4``(L8A=MT/0^W0Q!F.T<<=3-F/8,`=RT/
+MM\"`O"@8!```_W0@QD,4(0^W0QZ)1"0$B2PDZ/S___^)7"0$B2PDZ/S___^#
+MQ@$/MT5,.?!_I8M'(,=`9`````#V1R@$=26)+"3H_/___XM'(,=$)`@!````
+MB40D!(DL).C\____C;8`````BU<@#[:"EP````^V4@*-!(`/MH0"``````^V
+M52(/MDTAB40D#(E4)`B)3"0$QP0DL````.C\____BT<@BY6@!```B40D"(E4
+M)`3'!"0!````Z/S___^+1R"+E:`$``")1"0(B50D!,<$)`8```#H_/___\='
+M(`````"+5"0T@&H)`8E\)`2)+"3H_/___XM4)!B+1"0T.5`H#X6E_O__BT0D
+M-,=`'`````"+10"+D%@!``")%0````"%TG0)BT4`B9!8`0``@\0<6UY?7<.)
+M]E575E.#["R+="1`BP:+@%`!``")1"0<HP````"+%B7P__\`B8)0`0``C;0F
+M`````/=$)!P`__\`#X1G!@``@'XK``^$708``,9$)"L`C78`#[9L)"N-30BX
+M`0```(G"T^*%5"0<=0^-31#3X(5$)!P/A!P&``"`?"0K`W89BP8%@`$``(T$
+MZ(L`HP````#!Z!.#X`'K%XL&!8`!``"-!.B+`*,`````P>@3@^`!A,!T)\=$
+M)`@`````B6PD!(DT).C\____A,!T#XU$[0"!C,9L"``````(`(L6@'PD*P-V
+M%8V$ZH`!``"+`*,`````)0```0#K$XV$ZH`!``"+`*,`````)0```0"%P'0Z
+M@'PD*P-V$HV$ZH`!``#'`````0#IK`4``(V$ZH`!``#'`````0#IF@4``(U$
+M[0"!C,9L"``````!`(!^,P$/A6\$``"`?"0K`W88BP8%@`$``(T$Z(L`HP``
+M``"#X`'K%HGVBP8%@`$``(T$Z(L`HP````"#X`&$P`^$60$``(U<[0#!XP.-
+MA!YT"```BU84B40D!(D4).C\____BX0>3`@``(7`=!V+4!R%TG06]D(N`G40
+MB00DZ/S___^$P`^%%`$``(U$[0"+A,9,"```A<`/A(L```")1"0D@'@)``^$
+MJ0```,9$)",`B<>#QRB-="8`B3PDZ/S___^)PXM'!(E?!(D[B4,$B1CV0R@"
+M=3V+4R"%TG0>BX:@!```B50D"(E$)`3'!"0%````Z/S___^`2R@"B5PD",=$
+M)`0&````BT0D)(D$).C\____@$0D(P$/ME0D(XM$)"0X4`EV+NN1#[9$)"O'
+M1"0(`0```(E$)`2)-"3H_/___\<$)*"&`0#H_/___[@`+3$!ZP6X0$M,`(U,
+M[0#!X0.-%#&)@G0(``#'@GP(``"P/0``#[9$)"N-!,"-A,9$"```B8*`"```
+MC80.=`@``(M6%(E$)`2)%"3H_/___X!\)"L#=C2-%.T`````BP8%@`$```'0
+MBP"C`````(L&!8`!```!PHL"HP````#!Z`>#X`'K,I"-="8`C13M`````(L&
+M!8`!```!T(L`HP````"+!@6``0```<*+`J,`````P>@'@^`!A,!T7X!\)"L#
+M=BJ-#.T`````BP8%A`$```'(BP"C`````(L6@<*$`0```=$-```!`(D!ZS6-
+M#.T`````BP8%A`$```'(BP"C`````(L6@<*$`0```=$-```!`(D!ZR2-="8`
+M@'PD*P-V&8L&!8`!``"-!.B+`*,`````P>@2@^`!ZQ>+!@6``0``C03HBP"C
+M`````,'H$H/@`83`#X31`0``#[9&*8U$A0`/ME8B#[9.(8E$)`R)5"0(B4PD
+M!,<$)-````#H_/___X!\)"L#=BJ-#.T`````BP8%@`$```'(BP"C``````T`
+M``0`BQ:!PH`!```!T8D!ZRB-#.T`````BP8%@`$```'(BP"C``````T```0`
+MBQ:!PH`!```!T8D!C43M`(N$QDP(``"%P'0+@W@<`'5_Z38!``"`?"0K`Y!V
+M.8T4[0````"+!@6``0```="+"(D-`````(L&!8`!``"-!`*)"(L&!8`!```!
+MPHL"HP````#IV@$``(T4[0````"+!@6``0```="+"(D-`````(L&!8`!``"-
+M!`*)"(L&!8`!```!PHL"HP````#IH0$``(MX'/9'+@(/A(4```#&1"0K`(!_
+M'@!T1L9$)"L`#[9$)"N+7(<XA=MT)8M3((72=!Z+AJ`$``")5"0(B40D!,<$
+M)`4```#H_/___X!+*`*`1"0K`0^V5"0K.%<>=[^-7VB+1A2)7"0$B00DZ/S_
+M___'1VA`2TP`QT=P`````(E_=(M&%(E<)`2)!"3H_/___^LJ#[9&*8U$A0`/
+MME8B#[9.(8E$)`R)5"0(B4PD!,<$)`````#H_/___XGV@'PD*P-V:0^V7"0K
+MP>,#BP8%@`$```'8BQ")%0````"+!@6``0``C00#B1"+!@6``0``C00#BP"C
+M`````(L&!3`"``"-!`/'``````#'!"00)P``Z/S___^+!@4T`@```<.+`Z,`
+M````ZV>0C70F``^V7"0KP>,#BP8%@`$```'8BQ")%0````"+!@6``0``C00#
+MB1"+!@6``0``C00#BP"C`````(L&!5`"``"-!`/'``````#'!"00)P``Z/S_
+M__^+!@54`@```<.+`Z,`````@$0D*P$/MD0D*SA&*P^'J_G__XL&BX!0`0``
+MB40D'*,`````BQ8E\/__`(F"4`$``/=$)!P`__\`=";I7OG__\=$)`@!````
+MB6PD!(DT).C\____A,`/A4KZ___I5/K__[@`````@\0L6UY?79##ZPV0D)"0
+MD)"0D)"0D)"05U93@^P0BW0D((L^@'X>`'0ONP`````/ML.+1(8XA<!T%XE$
+M)`C'1"0$(0```(M&3(D$).C\____@\,!.%X>=];'1"0(`````,=$)`0A````
+MBT9,B00DZ/S___]FQT8N(0#&1B81B70D!(D\).C\____@\006UY?PXVT)@``
+M``!55U93@^P<BTPD-(MT)#"+?DR++P^V1P>H$'0)QD8Q!ND]`0``#[96,8#Z
+M!'0.@/H&#X6=`0``Z28!``"#X/>#R!"(1P>+EH0```"-0@&)AH0```"#^@(/
+MAP4!``"+A90```")2`2)`8V%E````(E!!(F-E````(!^)@!T#;L`````@'X>
+M`'4/ZS2`?PD`B?9U2>FW````#[;#BT2&.(7`=!2)1"0(QT0D!"$```")/"3H
+M_/___X/#`3A>'G?9QT0D"`````#'1"0$(0```(D\).C\____Z?D```#&1"0;
+M`(U'*(E$)!2+5"04B10DZ/S___^)PXM'+(E?+(M4)!2)$XE#!(D8BT,@A<!T
+M'HE$)`B+A:`$``")1"0$QP0D!0```.C\____@$LH`HE<)`C'1"0$!@```(D\
+M).C\____@$0D&P$/MD0D&SA'"7>9]D8N`@^$?````(DT).C\____ZW*`9P?W
+MQX:$`````````(N%E````(E(!(D!C864````B4$$B8V4````@'X>`'0LNP``
+M```/ML.+1(8XA<!T%(E$)`C'1"0$!@```(D\).C\____@\,!.%X>=]G'1"0(
+M`````,=$)`0&````B3PDZ/S___^#Q!Q;7E]=PXUT)@"#[!R)7"00B70D%(E\
+M)!B+?"0@BW0D)`^W3B1F@?GA`74/#[9&)H/H$3P!#X8&`0``#[=&$+K_````
+M9CV#`'<+#[?`#[:4!Q@$```/M\)IP-P```")PP.?U`0``&:!^>$!=0T/MD8F
+M@^@!/`%V)XGV9H'Z_P!T!O9#)P1U&,9&%`:+1"0HQP``````N`$```#IJP``
+M``^V0R2#X`6#^`5U<P^V5RP/MD<Q.,)R*P^VP(E$)`@/ML*)1"0$QP0D'0``
+M`.C\____BT0D*,<``0```+@!````ZVB)="0$B1PDZ/S___^$P'45QD84(8M$
+M)"C'``````"X`0```.M#@'M''W81BT0D*,<``0```+@!````ZRR-ARP&``")
+M!"3H_/___X3`=!&+1"0HQP`!````N`$```#K";@`````C70F`(M<)!"+="04
+MBWPD&(/$',-55U93@^Q,BVPD9(M$)&"+L!`'``!FQT4>_P^-1"0PB40D"(EL
+M)`2+5"1@B10DZ/S___^$P'0)BT0D,.EX!```#[=5$+O_````9H'Z@P!W#P^W
+MPHM,)&`/MIP!&`0```^W321F@?GA`74/#[9%)H/H$3P!#X:4````9H'Z@P!W
+M3P^WPHM\)&`/MH0'&`0``#S_=#QF@_I_=QD/ML"+E]0$``!IP-P```"+1!`L
+M#[9`!.LB#[;`BWPD8(N7\`0``&G`E````(M$$$P/MD`$ZP6X_____P^VP(M4
+M)&`/MH0"G`0``&O`3(V$`N@```")1"0<#[?#:<#<`````X+4!```B40D(&:!
+M^>$!=3SK*`^WPVG`E````(M,)&`#@?`$``")1"0DBWA,B7PD',=$)"``````
+MZSD/ME4FC4+O/`%V)HU"_SP!=A]F@?O_`'0*BT0D(/9`)P1U#L9%%`:X````
+M`.E2`P``QT0D)`````"-1"1(B40D!(M4)&")%"3H_/___V:)1"0:9HE%'HM-
+M4(E,)"@/M_B)?"04:<>P!```C30PC48@BU0D8"N"$`<``(G"P?H?BTPD8`.!
+M%`<``!.1&`<``(M,)$B)02"+3"1(B5$DBWPD*(M'#(M7$(M,)$B)02B+3"1(
+MB5$LBT0D2`^W5"0:9HE0"+@`````C70F`,8$,`"#P`$]L`0``'7R9H%]).$!
+M=6H/MD4F@^@1/`%W7XU$)#>)1"0,BT0D2`^V0`B)1"0(B6PD!(M,)"")#"3H
+M_/___XV&(`0``(M\)&`KAQ`'``")PL'Z'P.'%`<``!.7&`<``(M,)$B)01"+
+M3"1(B5$4Z:\```"-M"8`````BWPD'/9'!@$/A)H```#V168@=!*-1"0WB40D
+M!(DL).C\____ZR2-1"0WB40D#(M$)$@/MD`(B40D"(EL)`2+1"0@B00DZ/S_
+M__^-AB`$``"+5"1@*X(0!P``B<+!^A^+3"1@`X$4!P``$Y$8!P``BTPD2(E!
+M$(M,)$B)412)\(M\)&`KAQ`'``")PL'Z'P.'%`<``!.7&`<``(M,)$B)01B+
+M3"1(B5$<#[95/8M$)$AFB5`"@'T]`'0XOP````"[`````(M$)"B+2`B+542+
+M!!J)!!F+1!H$B409!(M$&@B)1!D(@\<!@\,,#[9%/3GX=]*+52"+1"1(B5`,
+M#[=<)!J)7"0,BT0D2(E$)`B);"0$BU0D'(D4).C\____C40D-XE$)`R)="0(
+MB6PD!(M,)&")#"3H_/___XM\)&"+APP%``"+5"04B2R0#[=4)!IFP>H%#[?2
+MB=F#X1^X`0```-/@"827$`4``&:!?23A`75/#[9%)H/H$3P!=T2+3"0DB4PD
+M!(D\).C\____C40D1(E$)`R+?"0D#[9',(E$)`B)7"0$BT0D'(D$).C\____
+M@ST``````G4_ZWB0C70F`(M4)"")5"0$BTPD8(D,).C\____C40D1(E$)`R+
+M?"0@#[9'.HE$)`B)7"0$BT0D'(D$).C\____C40D1(E$)`2+5"1@B10DZ/S_
+M__^+1B"+5B2)T0G!=!N)1"0$B50D",<$)/P```#H_/___[@#````ZP6X`P``
+M`(/$3%M>7UW#55=64X/L#(MT)""-OI0```#I"@$``(D\).C\____B<,/ME`0
+M9HE0$&:#^G]V$V:!>"3A`74B#[9`)H/H$3P!=Q=F@?J#`'<0#[?"#[:4!A@$
+M``"`^O]U&,9#%`:)7"0$B30DZ/S____ILP```(UV`&:!>R3A`748#[9+)HU!
+M[SP!#X>G````ZRZ-M"8`````#[;":<#<`````X;4!```]D`G!'42QD,4!HE<
+M)`2)-"3H_/___^MIB5PD!(DT).C\____@_@"=PJ#^`%S)8UV`.L0@_@#=4F)
+M]HV\)P````#K+(E<)`2)-"3H_/___XGVZRZ-EI0```"+AI0```")6`2)`XE3
+M!(F>E````.M#B5PD!(DT).C\____C;8`````.;Z4````#X7J_O__ZR.+KM0$
+M``"-0?\\`0^&>/___P^VPFG`W````(U$!0#I3O___X/$#%M>7UW#C;0F````
+M`(/L+(E<)!R)="0@B7PD)(EL)"B+?"0TBT0D,(MP+(LNNP````!F@7\DX0%U
+M$P^V1R:#Z`$\`0^6P`^VV(UT)@"+5"0P#[:"E````#P$=!$\!@^%40(``.GG
+M`0``C70F`(M,)##&@98`````BT0D,(M(((7)=1\/MI#9````C4(!BTPD,(B!
+MV0```(#Z`@^'L`$``.L2BU$$C4(!B4$$@_HH#X><`0``BX64````B7@$B0>-
+MA90```")1P2)O90```#&1Q2`BT0D,(E$)`C'1"0$(0```(DT).C\____A=L/
+MA<,!``"+5"0P@'HF_W0XB=&+4C"%T@^$K`$``(!Z)@!T)?9"+@(/A)P!```/
+MMDE%N`$```#3X`E"-(M$)#"`2"@0Z8$!```/MD8'@^#W@\@0B$8'@'X)`'1:
+MOP````"-5BB)5"08BTPD&(D,).C\____B<.+1BR)7BR+5"08B1.)0P2)&(M#
+M((7`=!Z)1"0(BX6@!```B40D!,<$)`4```#H_/___X!+*`*#QP&)^3A."7>R
+MBT0D,(M0,(72=3;&0"8#9L>`C```````B40D",=$)`0A````B30DZ/S___^+
+M5"0PB50D!(DL).C\____Z=,```#V0BX"#X3)````BT0D,`^V2$6X`0```-/@
+M"4(TBU0D,(!**!"+0C"#P&B)1"0$BT44B00DZ/S___^+3"0PBT$PQT!H@(0>
+M`(M!,,=`<`````"+03")0'2+03"#P&B)1"0$BT44B00DZ/S____K98M$)#`/
+MME@F@&8'[XN%E````(EX!(D'C864````B4<$B;V4````BU0D,(E4)`C'1"0$
+M!@```(DT).C\____@/O_=1J+3"0PB4PD"(ET)`2)+"3H_/___XVV`````(DL
+M).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.-="8`55=64X/L#(ML)""+C=0$
+M``"+5"0D#[="$+HDVP``9CV#`'<1#[?`#[:$!1@$``!IT-P```"--!&)="0$
+MB2PDZ/S___^)="0$B2PDZ/S___^+3"0D#[=!'HE$)`2)+"3H_/___XM4)"0/
+MMT(>B40D!(DL).C\____BTPD)&;'01[_#XL1BT$$B4($B1"`;D<!C7X0.7X0
+M=%N-A90```")1"0(B3PDZ/S___^)PP^W0!Z)1"0$B2PDZ/S___\/MT,>B40D
+M!(DL).C\____9L=#'O\/@&Y'`8N%E````(E8!(D#BU0D"(E3!(F=E````#E^
+M$'6OQH:4````!(M,)"2)3"0$B30DZ/S___^X`0```(/$#%M>7UW#B?:-O"<`
+M````55=64X/L;(N<)(````"+C"2(````B4PD6(N$)(P```")1"1<BRL/MX0D
+MA````,'@`@.%#`4``(LX9H%_).$!=2\/MD<F@^@1/`%W)(M3'`^V0C"(1"0G
+MO@`````+3"1<=5G&0C$`O@````#K3HUV`(N5U`0``+@DVP``9H%_$(,`=Q(/
+MMT<0#[:$!1@$``!IP-P```"--`(/ME8ZB%0D)[H`````BT0D6`M$)%QU#,:&
+ME`````"Z`````(!_%(%U!(!C!_>+1"18"T0D7`^%+P$``,9'%`"#/0`````!
+M=1=F@7\DX0%U#P^V1R:#Z!$\`7<$QD<4(?9'9B`/A"\$``"+1TB%P`^$)`0`
+M`(G#]D!E`G0ABTA8A<ET&HM7-(72=!.+1R")1"0(B50D!(D,).C\____BY7L
+M!@``@<)`"```#[9&.L'@"`'"BP*C`````(G"P>H0B%-3P>@89HE#2(N5[`8`
+M`('"1`@```^V1CK!X`@!PHL2B14`````#[;"9HE#3`^VQF:)0TZ)T,'H$`^V
+MP&:)0U#!ZAB(4U*+E>P&``"!PDP(```/MD8ZP>`(`<*+`J,`````#[;`9HE#
+M2HN5[`8``('"2`@```^V1CK!X`@!PHL"HP````")PL'B"&8)4TR)PH'B`/\`
+M`&8)4T[!Z`@E`/\``&8)0U#I+@,```^W1QYIP+`$```#A1`'``")1"0H!2`$
+M``")1"0L@'\4@'4+QD<4(8VT)@````"%]@^$H0```(M6((72=$L/MH*7````
+M#[92`HT$@`^VC`(`````#[9=(@^V=2&+1"18BU0D7(E$)!")5"04B4PD#(E<
+M)`B)="0$QP0D*`$``.C\____Z98```"+4Q@/MD4I#[92!(T$@@^V5D6-!(`/
+MMHP"``````^V72(/MG4ABT0D6(M4)%R)1"00B50D%(E,)`R)7"0(B70D!,<$
+M)"@!``#H_/___^M'A=)T0XM#&`^V32D/MD`$C0R(#[9=(@^V=2&+1"18BU0D
+M7(E$)!")5"04B4PD#(E<)`B)="0$QP0D9`$``.C\____D(UT)@"+3"0LBT$,
+MBU$(B<N+202+&XE$)!")5"0,B4PD"(E<)`3'!"2@`0``Z/S___^+1"0H]D`B
+M`749@'@G`'D3#[=''HE$)`2)+"3H_/___XUV``^V1"1;J`$/A$H!```/ME0D
+M)\'B"(N%[`8```5`"````="+"(D-`````(G+P>L0B%PD0(G(P>@8B$0D,(N%
+M[`8```5$"```C00"BS")-0````"+A>P&```%2`@``(T$`HL8B1T`````BX7L
+M!@``!4P(```!PHL2B50D5(D5``````^V1"0P#[94)$")1"08B50D%(M4)%2)
+M5"00B5PD#(ET)`B)3"0$QP0DR`$``.C\____9H%_).$!=14/MD<F@^@1/`$/
+MAO8```"-M@````#&1Q0"]D=F('1<BT](#[9$)$"(05,/MD0D,&:)04B)W\'G
+M"(GP#[;0C0079HE!3(G?9H'G`/^)\`^VU(T$%V:)04Z)VL'J$,'B"(GPP>@0
+M#[;``<)FB5%0#[9$)%1FB4%*Z8H```!F@7\DX0%U"P^V1R:#Z!H\`79WB7PD
+M!(DL).C\____ZVF$P'EE@'PD)Q]W+HM%`(N06`$``(D5`````+@!````#[9,
+M)"?3X"'"=#^+10")D%@!``#K-(UT)@"+10"+D&`!``")%0`````/MDPD)X/I
+M(+@!````T^`APG0.BT4`B9!@`0``D(UT)@"#Q&Q;7E]=PY"-M"8`````55=6
+M4X/L?(NT))`````/MX8^"```9HE$)"Z+AE@'``"+`*,`````9B7_#V:)ACX(
+M``!F.T0D+G5`BP:+@%`!``"C`````(L6)?#__P")@E`!``"Z`````(7`#X19
+M!```BY0DD````(D4).C\____N@$```#I0`0``&:!OCX(``#_#P^%N`,``.G5
+M`P``C78`BYX0!P``9H-$)"X!#[=,)"YF.XY""```&<`AP6:)3"0NBY98!P``
+M@\($#[?!BQ2"B=#!Z!"(1"1`J`@/A*\```"+!HN84`$``(D=`````(L6B=@E
+M\/__`(F"4`$``(7`=&"`?BL`=%KVQP%U,;\`````]\,```$`=#SK(HUT)@`/
+MM\>-2`BZ`0```(G5T^6%ZW40C4@0T^*%TW4'ZQB_``````^WQVO`3(V<!N@`
+M``"%VW4BZPR#QP$/MD8K9CGX=[Z+A"20````B00DZ/S____IZ@(``(N4))``
+M``")%"3H_/___XA#"NG3`@``C78`B=%F@>'_#V:)3"1<#[?):<&P!```BWP#
+M((ML`R2)?"1@B6PD9(T<C0````"+A@P%```!V(LXA?\/A>(```"+?"1@BVPD
+M9(E\)!");"04B50D#(E,)`B)3"0$QP0D"`(``.C\____9H-^3``/A%\"``#&
+M1"1K``^V?"1KC2R]`````(EL)%B)Z`.&#`4``(L0A=)T<FG?L`0```.>$`<`
+M``^V0A6)1"0,B7PD"(E4)`3'!"0N````Z/S___^)Z`.&#`4``(L`B00DZ/S_
+M__^+@RP$``"+DR@$``"+BR0$``"+FR`$``")1"04B50D$(E,)`R)7"0(B7PD
+M!,<$)$0"``#H_/___X!$)&L!#[9$)&MF.T9,#X.V`0``Z5?___^0B=@#A@P%
+M``"+``^W4!!F@?J#`'=G#[?"#[:$!A@$```\_W189H/Z?W<8#[;`:<#<````
+M`X;4!```BT`L#[9`!.LIB=@#A@P%``"+``^W0!`/MH0P&`0``&G`E`````.&
+M\`0``(M`3`^V0`0\_W0-#[;`@+P&G`0``/]U'<9'%`:)/"3H_/___XE\)`2)
+M-"3H_/___^D7`0``#[:$!IP$``!KP$R-A`;H````BU0D9`M4)&!T%_9$)$`"
+M=1#'1"1@`````,=$)&0`````]D`&`@^%V@````^W3"1<B4PD;(M4)&"+3"1D
+MB50D"(E,)`R+3"1LB4PD!(D$).C\____BX:<````.T0D/'1*NP````"#PP&+
+M`#E$)#QU]83;=#;&1"1?`(ML)#R)+"3H_/___XU(^(M5!(E%!(DHB5`$B0(Y
+M^74%QD0D7P&`ZP%UUH!\)%\`=5N`?Q2!=%5F@7\>_P]T38M$)#R+4`2-1PB+
+M3"0\B4$$B4\(B5`$B0(/MU0D7&;!Z@4/M]*+3"1L@^$?N`$```#3X`E$EE#K
+M%(UT)@"-OIP```")?"0\C;8`````#[=L)"YF.:X^"```#X4N_/__C8:<````
+M.8:<````=#R)QXD\).C\____@^@(#[=('HG+9L'K!0^WVX/A'[K^____T\(A
+M5)Y0B40D!(DT).C\____.;Z<````=<:)-"3H_/___[H!````B="#Q'Q;7E]=
+MPXVV`````(V\)P````!64X/L%(M,)""+D:`$``"+0@2+,(DU`````/?&````
+MD'0%BT($B3"+F:`$``#WQ@``!`!T*XL#BY!0`0``B14`````A=)T&8L#B9!0
+M`0``BP.+@%`!``"C`````(UT)@#WQ@``"`!T+8'#A`D``(L#BY!0`0``B14`
+M````A=)T%8L#B9!0`0``BP.+@%`!``"C`````(N#H`0``,=$)`0`````B00D
+MZ/S___^+FZ`$``")'"3H_/___XV#A`D``(D$).C\____BX.@!```QT0D!`$`
+M``")!"3H_/___X7V#Y7`#[;`@\046U[#D(UT)@!55U93@^P\#[9$)%2(1"0F
+M#[;HC43M`(M4)%"-!,*+N$P(```/MH!*"```B$0D)XL"@'PD)@-V#,>`<`$`
+M`,0!``#K"L>`<`$``*@!``")1"0X!70!``")1"0HBTPD.(N!=`$``*,`````
+MB>F#X0.[!P```-/CB=X)QHM$)#B)L'0!``#'!"3H`P``Z/S____WTR'SBU0D
+M.(F:=`$``(!\)"8#=DJ+3"0XC92IT`$``(L"HP````"#R`B)`HT<[0````"-
+MA!D``@``QP`X````QP0D$"<``.C\____BU0D.(V$&@0"``#'``````#K2(M,
+M)#B-E*G0`0``BP*C`````(/("(D"C1SM`````(V$&0`"``#'`#@```#'!"00
+M)P``Z/S___^+5"0XC80:!`(``,<``````(7_#X2=`P``BTPD4(!Y*P!T.+L`
+M````B?8/MLL/MD<(T_BH`708QT0D"`$```")3"0$BT0D4(D$).C\____@\,!
+MBU0D4#A:*W?/]D<&`71GB7PD!(M,)%")#"3H_/___XEL)`2+7"10B1PDZ/S_
+M__^-1.T`C13#BX)H"```J0``$`!T"R7__^__B8)H"```B7PD!(M$)%")!"3H
+M_/___XU$[0"+5"10QX3"3`@```````#I[@(``+C^____B>G3P")$)">(1"0O
+M#X6Z`0``QT0D"`````#'1"0$!@```(D\).C\____B6PD!(M<)%")'"3H_/__
+M_XU$[0"-%,.+@F@(``"I```0`'0+)?__[_^)@F@(``"-1R`Y1R!U^XU'*#E'
+M*`^$/`$``,=$)#``````B40D&(M4)!B)%"3H_/___XG&@'A'`'0^BUPD,(/#
+M`8%\)#!_EI@`=RF+3"10B0PDZ/S____'!"0!````Z/S___^`?D<`=`N#PP&!
+M^X&6F`!UUXE<)#"+1B"%P`^$L@```,=`9`````#V1B@$=2.+7"10B1PDZ/S_
+M__^+1B#'1"0(`0```(E$)`2)'"3H_/___XM6(`^V@I<````/ME("C02`#[:$
+M`@````"+3"10#[91(@^V22&)1"0,B50D"(E,)`3'!"2P````Z/S___^+1B"+
+M7"10BY.@!```B40D"(E4)`3'!"0!````Z/S___^+1B"+DZ`$``")1"0(B50D
+M!,<$)`8```#H_/___\=&(`````"`;PD!B70D!(M$)%")!"3H_/___XM4)!@Y
+M5R@/A=#^__^)?"0$BTPD4(D,).C\____C43M`(M<)%#'A,-,"````````(M$
+M)%"`>"L`#X0/`0``QT0D-``````/ME0D+XE4)""+3"0X@<'0`0``B4PD'(UT
+M)@`/MGPD-(G[#[;KBT0D((GIT_BH`74*.%PD)@^%MP```(G[@/L#=EF+1"0X
+MQX!P`0``Q`$``(M4)"B+`J,`````B>F#X0.-#$F[!P```-/CB=X)QHDRQP0D
+MZ`,``.C\____]],A\XM,)"B)&8M<)!R-%*N+`J,`````@\@(B0+K5XM$)#C'
+M@'`!``"H`0``BU0D*(L"HP````")Z8/A`XT,2;L'````T^.)W@G&B3+'!"3H
+M`P``Z/S____WTR'>BTPD*(DQBUPD'(T4JXL"HP````"#R`B)`H-$)#0!C4<!
+MBU0D4#A"*P^'%/___X/$/%M>7UW#C;8`````C;\`````55=64X/L'(M\)#"+
+M="0T#[9O*XGHA,!T+`^V5@B[`````/;"`703ZQR-M"8`````B=")V=/XJ`%U
+M$(/#`8GH.,-U[>L%NP````#V1@<"=0B-1B@Y1BAU:HDT).C\____A,!T3XD\
+M).C\____B<&%P'10BU8LB48LC48HB0&)402)"H!&"0&)<2S&020%QD$E`,9!
+M10_'1"0,`0```,=$)`@!````B4PD!(DT).C\____ZP\/ML.)1"0$B3PDZ/S_
+M__^#Q!Q;7E]=PXVV`````%575E.#[`R+;"0@#[9\)"2)^`^VP(E$)`B)QL'F
+M`KL`````QP0D$"<``.C\____B?J`^@-V&HM%``70`0```?"+`*,`````P>@4
+M@^`!ZQF0BT4`!=`!``"-!`:+`*,`````P>@4@^`!A,!U"H/#`6:!^RP!=:V+
+M1"0(B40D!(DL).C\____B2PDZ/S___^+5"0(C032C43%`/:`20@```%T$HN`
+M3`@``(E$)`2)+"3H_/___X/$#%M>7UW#C70F`%575E.#[!P/MD0D-(A$)!N+
+M="0P#[;XC03_BZS&3`@``(7M#X0``0``N/[___^)^=/`A$4(#X7N````@'T)
+M``^$NP$``+\`````C5THC78`B1PDZ/S___^)PHM#!(E3!(D:B4($B1"`>B4`
+M#X6E````#[="'(.\AA@"````=0:#>B``=',/MT(<BX2&&`(``(-X<`!T0\:"
+ME``````/MDHDB<B#X`:#^`9U!?;!`75F#[9*)(G(@^`&@_@$=5CVP0%T4\9"
+M)@/&0B<$B50D!(DT).C\____ZSV+0B"+EJ`$``")1"0(B50D!,<$)`0```#H
+M_/___^L>#[="'(N6H`0``(E$)`B)5"0$QP0D`@```.C\____@\<!B?@X10D/
+MAMP```#I)____XTLO0````"[`````,<$)!`G``#H_/___X!\)!L#=AB+!@70
+M`0```>B+`*,`````P>@4@^`!ZQ:+!@70`0```>B+`*,`````P>@4@^`!A,!U
+M"H/#`6:!^RP!=;&)?"0$B30DZ/S___^)-"3H_/___XT$_XN\QDP(``"%_W1:
+M@'XK`'0NNP`````/MLL/MD<(T_BH`704QT0D"`````")3"0$B30DZ/S___^#
+MPP$X7BMWUP^V1"0;C03`C83&1`@``(E'&/9'!@%T#HE\)`2)-"3H_/___XGV
+M@\0<6UY?7<.0C;0F`````%=64X/L$(MT)""+'HM^*`^V4RN$TG1*C8-$"```
+MN0`````Y\'43ZSD/ML&-!,"-A,-$"```.?!T!X/!`3C1=>B`^0-V(8L#!=`!
+M```/MM&-%)"+`J,`````P>@4@^`!ZQ^Y`````(L#!=`!```/MM&-%)"+`J,`
+M````P>@4@^`!A,!T%0^VP8E\)`B)1"0$B1PDZ/S____K#P^VP8E$)`2)'"3H
+M_/___X/$$%M>7\.04X/L6(M<)&"-1"1*B40D-(U$)$R)1"0PC40D1(E$)"R-
+M1"1&B40D*(U$)%")1"0DC40D4HE$)""-1"13B40D'(U$)$Z)1"08C40D5(E$
+M)!2-1"1(B40D$(U$)%6)1"0,C40D5HE$)`B-1"17B40D!`^W0R2)!"3H_/__
+M_\=$)`P!````#[9$)%=IP-P```")1"0(BT,0B40D!(V#O`0``(D$).C\____
+MQT0D#`$````/MD0D56G`E````(E$)`B+0Q")1"0$C8/8!```B00DZ/S____'
+M1"0,`0````^W1"10P>`"B40D"(M#$(E$)`2-@_0$``")!"3H_/___\=$)`P!
+M````#[=$)$AKP'2)1"0(BT,0B40D!(V#H`4``(D$).C\____QT0D#`$````/
+MMD0D5`^W5"1(#Z_"C01`P>`"B40D"(M#$(E$)`2-@U`%``")!"3H_/___\=$
+M)`P!````QT0D"``"``"+0Q")1"0$C8-L!0``B00DZ/S____'1"0,`0````^V
+M1"13C02`P>`"B40D"(M#$(E$)`2-@[P%``")!"3H_/___\=$)`P!````QT0D
+M"*````"+0Q")1"0$C8/8!0``B00DZ/S____'1"0,`0````^W1"1.C01`P>`#
+MB40D"(M#$(E$)`2-@_0%``")!"3H_/___\=$)`P!````#[=$)%`!P(E$)`B+
+M0Q")1"0$C8,0!@``B00DZ/S____'1"0,`0````^V1"17`<")1"0(BT,0B40D
+M!(V#.`8``(D$).C\____QT0D#`$````/MD0D50'`B40D"(M#$(E$)`2-@V`&
+M``")!"3H_/___\=$)`P!````#[9#)@'`B40D"(M#$(E$)`2-@X@&``")!"3H
+M_/___\=$)!`!````QT0D#$`````/MT0D4,'@!HE$)`B+0Q")1"0$C8.P!@``
+MB00DZ/S____'1"00`0```,=$)`P``0``QT0D"`!)``"+0Q")1"0$C8/4!@``
+MB00DZ/S____'1"00`0```,=$)`R`````#[=$)%!IP+`$``")1"0(BT,0B40D
+M!(V#^`8``(D$).C\____QT0D$`$```#'1"0,!`````^W1"1,P>`"B40D"(M#
+M$(E$)`2-@QP'``")!"3H_/___\=$)!`!````QT0D#`0````/MT0D2L'@`HE$
+M)`B+0Q")1"0$C8-`!P``B00DZ/S____'1"00`0```,=$)`P(````#[9$)%/!
+MX`R)1"0(BT,0B40D!(V#9`<``(D$).C\____QT0D$`$```#'1"0,"````,=$
+M)`@```@`BT,0B40D!(V#B`<``(D$).C\____QT0D$`$```#'1"0,"`````^W
+M1"1.:<",`0``B40D"(M#$(E$)`2!PZP'``")'"3H_/___[@`````@\186\.0
+MC70F`%.#[`B+3"00BU0D%(N9F````(F1F````(V!E````(D"B5H$B1.)#"3H
+M_/___X/$"%O#C;0F`````(V\)P````!55U93@^P<BW0D,,=$)!@`````BU0D
+M&`^VA#*<!```//\/A,P````/MM!KPDR-C`;H````B4PD%("\!O$`````#X2M
+M````OP````")1"00C:P&$`$``(V$!N````")1"0,B2PDZ/S___^)PXM$)!`!
+M\(N0%`$``(F8%`$``(DKB5,$B1J+0R"%P'0>B40D"(N&H`0``(E$)`3'!"0%
+M````Z/S___^`2R@"B5PD",=$)`0A````BT0D%(D$).C\____@'M'`'0:B30D
+MZ/S____'!"0!````Z/S___^`>T<`=>:#QP&)^HM,)`PX41$/AV[___^#1"08
+M`8-\)!@$#X40____B30DZ/S___^#Q!Q;7E]=PXVV`````(V\)P````!55U93
+M@^PLBT0D0(E$)!R+<"R++HN%6`<``(L`B40D*(M4)!R)5"0$B2PDZ/S___^+
+M7"0<@\,0QT0D(`````"+3"0<.5D0="*)'"3H_/___XE$)""+5"0<BT(0BTPD
+M((E(!(D!B5D$B4H0BT0D'(M0((72=%"X__\``(-\)"``=`B+3"0@#[=!'HE$
+M)!`/MH*7````#[92`HT$@`^VA`(`````B40D#`^V12*)1"0(#[9%(8E$)`3'
+M!"1L`@``Z/S____K6;C__P``@WPD(`!T"(M4)"`/MT(>B40D$`^V12F+5A@/
+MME($C02"BTPD'`^V446-!(`/MH0"`````(E$)`P/MD4BB40D"`^V12&)1"0$
+MQP0D;`(``.C\____@WPD(``/A.@!``"+1"0@#[=8'FG;L`0```.=$`<``(VS
+M(`0``(D$).C\____BT8,B40D%(M&"(E$)!"+1@2)1"0,BX,@!```B40D"(M4
+M)"`/MT(>B40D!,<$))P"``#H_/___V:#?4P`#X1(`0``9L=$)"8``(V-E```
+M`(E,)!B)]@^W5"0FBX4,!0``BS20A?8/A`H!``"+1"0<#[=X'&8[?A`/A?@`
+M```/MY4^"```.50D*'1A#[>=0@@``(N-6`<``(/!!(/"`3G:&<`APHL$D:D`
+M``@`=3AF)?\/9CM$)"9U+3ET)"!U+8DL).C\____BU0D(`^W0AZ)1"0$QP0D
+MT`(``.C\____Z>,```")]CM4)"AUKV:!_X,`D(UT)@!W?@^WQX"\!1@$``#_
+M='&#?"1``'1JBTPD'`^V022#X`6#^`5U6CMT)"!T(HL&BU8$B5`$B0*+A90`
+M``")<`2)!HM$)!B)1@2)M90````/MT8>B40D!(DL).C\____#[=&'HE$)`2)
+M+"3H_/___V;'1A[_#XM4)!R`:D<!C70F`&:#1"0F`0^W3"0F9CE-3`^'R_[_
+M_X-\)$``=#6+5"0<#[9")(/@!8/X!74EQH*4````!(M,)""+$8M!!(E"!(D0
+MB4PD!(M$)!R)!"3H_/___X/$+%M>7UW#C;0F`````%575E.#[&R+A"2`````
+MQD`S`,9`,@#&@'4)````B<*!PD0(``"X`````(VV`````,8$$`"#P`$](`$`
+M`'7RBX0D@`````64````BY0D@````(F"E````(F"F````(G0!9P```")@IP`
+M``")@J````")UH'&I````(FRI````(FRJ````(U`$(F"K````(F"L````('"
+MM````(E4)#R+C"2`````B9&T````B9&X````@<&\````B4PD0(N<)(````")
+MB[P```")B\````"!P\0```")7"1$B[PD@````(F?Q````(F?R````(U$)&:)
+M1"0TC40D:(E$)#"-1"18B40D+(U$)%Z)1"0HC40D:HE$)"2-1"1@B40D((U$
+M)&&)1"0<C40D7(E$)!B-1"1CB40D%(U$)%J)1"00C40D8HE$)`R-1"1DB40D
+M"(U$)&6)1"0$#[=')(D$).C\____#[9$)&6(1RX/MD0D8HB'DP````^W1"1J
+M9HE'3`^W1"1H9HF'0`@```^W1"1F@^@!9HF'0@@```^W1"1:9HE'-`^W1R1F
+M/8"1=`IF/8"4#X7O!P``BX0D@````,9`,`3&0"L$QD`Q0,9`+P#&@)(````)
+MQD`L`(N$)(`````%O`0``(D$).C\____B<*+C"2`````B8'4!```#[9$)&5I
+MP-P```"%P'0+Q@(`@\(!@^@!=?6+A"2`````!=@$``")!"3H_/___XG"BYPD
+M@````(F#\`0```^V1"1B:<"4````A<!T"\8"`(/"`8/H`77UBX0D@`````7T
+M!```B00DZ/S___^)PHN\)(````")APP%```/MT0D:L'@`H7`=`O&`@"#P@&#
+MZ`%U]8N$)(`````%;`4``(D$).C\____BY0D@````(F"A`4``(G0!5`%``")
+M!"3H_/___XG#BXPD@````(F!:`4``(G(!:`%``")!"3H_/___XG"B[PD@```
+M`(F'N`4``&:#?"1:`'1"N0````")6D0/MD0D8XA"/(N\)(````"+AZ@```")
+MEZ@```"),HE"!(D0#[9$)&.-!$"-'(.#PG2#P0%F.4PD6G?#BX0D@`````6\
+M!0``B00DZ/S___^)PHN$)(````")D-0%``"`?"1A`'0SN0````"+G"2`````
+MBX.X````B9.X````BW0D/(DRB4($B1"#PA2#P0$/MD0D868YR'?2BX0D@```
+M``78!0``B00DZ/S___^)PHN\)(````")A_`%``"-B*````"+G"2`````BX/`
+M````B9/`````BW0D0(DRB4($B1"#PA0YRG7;B=@%]`4``(D$).C\____B<*)
+M@PP&``!F@WPD7`!T,+D`````B[PD@````(N'R````(F7R````(M<)$2)&HE"
+M!(D0@\(8@\$!9CE,)%QWU8N$)(`````%$`8``(D$).C\____B[0D@````(F&
+M*`8``(F&+`8```^W1"1J9HF&,@8```^WP(E$)`2)\`4L!@``B00DZ/S___^)
+M\`4X!@``B00DZ/S___^)AE`&``")AE0&```/MD0D96:)AEH&```/M\")1"0$
+MB?`%5`8``(D$).C\____B?`%8`8``(D$).C\____B89X!@``B89\!@``#[9$
+M)&)FB8:"!@``#[?`B40D!(GP!7P&``")!"3H_/___XGP!8@&``")!"3H_/__
+M_XF&H`8``(F&I`8```^V1B9FB8:J!@``#[9&)HE$)`2)\`6D!@``B00DZ/S_
+M__^_`````(!^)@`/A((```"^``````^WQFO`3(N4)(````"-O`+H````C100
+MC9K@````B?&(2PS&0PT`BXPD@````(F*Z````,9#$0#'@C`!````````C80!
+M``$``(U("(F*"`$``(F*#`$``(/`$(F"$`$``(F"%`$``,9##@*#Q@&+G"2`
+M````#[9#)F8Y\'>#B[0D@````,9&+P#&AIP$``#_QH:=!```_\:&G@0``/_&
+MAI\$``#_@'PD90`/A(,```"[``````^WRVG1W````(NT)(````"+AM0$``#&
+M1!`G`8N&U`0``,9$`B8`BX;4!```QD0"1/^+AM0$``#&1`(Z_XN&U`0``&;'
+MA`*,``````#'A(X8`@```````(G1`X[4!```C4$0B4$0`Y;4!```C4(0B4(4
+M@\,!#[9$)&5F.=AW@HN$)(````!FQX"0``````"X`````(N4)(````#&A!`8
+M!```_X/``3V$````=>>`?"1B`'1]NP`````/M]-ITI0```"+C"2`````BX'P
+M!```9L=$$"X$`(N!\`0``,9$`B8`BX'P!```QD0")_^+@?`$``#&1`(P_XG1
+MB[0D@`````..\`0``(U!%(E!%(G1`X[P!```C4$4B4$8BX;P!```B7P"3(/#
+M`0^V1"1B9CG8=XB+A"2`````!<P&``")1"0$BX0D@`````6P!@``B00DZ/S_
+M__^+O"2`````B8?(!@``B?@%\`8``(E$)`2-0.2)!"3H_/___XF'[`8``(GX
+M!10'``")1"0$C4#DB00DZ/S___^)AQ`'``")^`4X!P``B40D!(U`Y(D$).C\
+M____B8<T!P``B?@%7`<``(E$)`2-0.2)!"3H_/___XF'6`<``(GX!8`'``")
+M1"0$C4#DB00DZ/S___^)P8F'?`<``(N<)(````"+@X`'``"+DX0'``"`?"1A
+M`'1:B<.)UK\`````B<TIQ8M$)#R)!"3H_/___XU4'0")4`B)6`R)<!"+C"2`
+M````BY&X````B8&X````BTPD/(D(B5`$B0*!PP`0``"#U@"#QP$/MD0D868Y
+M^'>SBX0D@`````6D!P``B40D!(N$)(`````%B`<``(D$).C\____B40D2(N<
+M)(````")@Z`'``"+O"2`````BY^D!P``B[>H!P``OP````"]`````(M$)$")
+M!"3H_/___XM4)$@!^HE0"(E8#(EP$(N,)(````"+D<````")@<````"+3"1`
+MB0B)4`2)`H'#```!`(/6`(''```!`(/5`(GX-0``"``)Z'6JBX0D@`````7(
+M!P``B40D!(N$)(`````%K`<``(D$).C\____B<&+G"2`````B8/$!P``B[0D
+M@````(N&R`<``(N6S`<``&:#?"1<`'17B<.)UK\`````B<TIQ8M$)$2)!"3H
+M_/___XU4'0")4`B)6`R)<!"+C"2`````BY'(````B8'(````BTPD1(D(B5`$
+MB0*!PXP!``"#U@"#QP%F.7PD7'>V@\1L6UY?7<.-M"8`````55=64X/L+(M$
+M)$")1"0<BW!,BRZ+A5@'``"+`(E$)"B+5"0<B50D!(DL).C\____BUPD'(/#
+M%(M,)!PY610/A,P```")'"3H_/___XE$)""+5"0<BT(4BTPD((E(!(D!B5D$
+MB4H4A<D/A#`"```/MT$>B40D$`^V12F+5A@/ME($C02"B40D#`^V12*)1"0(
+M#[9%(8E$)`3'!"3T`@``Z/S___^+1"0@#[=8'FG;L`0```.=$`<``(VS(`0`
+M`(D$).C\____BT8,B40D%(M&"(E$)!"+1@2)1"0,BX,@!```B40D"(M4)"`/
+MMT(>B40D!,<$))P"``#H_/___V:#?4P`=4?I<0$``(VT)@````#'1"00__\`
+M``^V12F+5A@/ME($C02"B40D#`^V12*)1"0(#[9%(8E$)`3'!"3T`@``Z/S_
+M___IB0$``&;'1"0F``"-C90```")3"08C70F``^W5"0FBX4,!0``BS20A?8/
+MA.\```"+1"0<#[=X)&8[?A`/A=T````/MY4^"```.50D*'1A#[>=0@@``(N-
+M6`<``(/!!(/"`3G:&<`APHL$D:D```@`=3AF)?\/9CM$)"9U+3ET)"!U+8DL
+M).C\____BU0D(`^W0AZ)1"0$QP0DT`(``.C\____Z>8```")]CM4)"AUKV:!
+M_X,`D(UT)@!W8P^WQX"\!1@$``#_=%8Y="0@="*+!HM6!(E0!(D"BX64````
+MB7`$B0:+3"08B4X$B;64````#[=&'HE$)`2)+"3H_/___P^W1AZ)1"0$B2PD
+MZ/S___]FQT8>_P^+1"0<@&@H`6:#1"0F`0^W5"0F9CE53`^'YO[__XM,)""+
+M$8M!!(E"!(D0BT0D',9`,02)3"0$B00DZ/S____K-L=$)!#__P``#[9%*8M6
+M&`^V4@2-!(*)1"0,#[9%(HE$)`@/MD4AB40D!,<$)/0"``#H_/___X/$+%M>
+M7UW#D)"0D(!\)`@!&<#WT"4```R`BU0D!(M2!(E"#,.0D)"0D)"05U93BUPD
+M%(M\)#"+3"0TBW0D/`^W5"009H'Z(B=W6&:!^B`G#X.(````9H'Z0"$/A'T`
+M``!F@?I`(7<89H'Z("%T;V:!^B(A=&AF@?I0!Y!U:NM>9H'Z1"&-M"8`````
+M=%!F@?I$(7)3C8+PV/__9H/X`7='ZSMF@?J")W0T9H'Z@B=W$&:!^B0G="9F
+M@?J`)W4IZQUF@?J`D8VV`````'009H'Z@)1T"6:!^H!RB?9U"L8#%(M$)!C&
+M``"+1"0<Q@`$9H'Z4`=T!L8'`.L&D`^V`X@'9L<!@`!FQP8``(M$)"3&`""+
+M1"0H9L<```$/MA.+1"0LB!`/M@-F`P%F`P:+5"0X9HD"BU0D(&:)`@^W$8M$
+M)$!FB1`/MQ&#P@N+1"1$9HD06UY?PXVV`````//#C;0F`````(V\)P````!5
+M5U93B<>)UKT`````C78`#[:$/9@$```\_W1;#[;`:<"4````B<,#G_`$``"`
+M>QX`=#FZ``````^VPHM,@SB%R70ABT$D)0#__P`]``#_`'42]D$G!'0,BT$@
+MA<!T!8GQB$@!@\(!.%,>=\R)\(B#D````(/&`8/%`8/]!'61BX>@!```.?AU
+M#`6$"0``B?+H:____UM>7UW#C;8`````BU0D!+@`````C;0F`````,8$$`"#
+MP`$]E````'7RQD(G_\9",/^-0A2)0A2)0AC#BU0D!+@`````C;0F`````,8$
+M$`"#P`$]W````'7RQD)$_\9".O_&0D8?C4(0B4(0B4(4PXVV`````(V_````
+M`%.+1"0(BUPD#(L3BXC`````B9#`````!;P```")`HE*!(D1QP,`````6\.0
+MC70F`%.+1"0(BUPD#(L3BXBX````B9"X````!;0```")`HE*!(D1QP,`````
+M6\.0C70F`%.+1"0(BUPD#(L3BXC(````B9#(````!<0```")`HE*!(D1QP,`
+M````6\.0C70F`%=64X/L$(M\)""+5"0D@'HP_P^%Y0```(L'B[`8`0``B34`
+M````N0````"0C70F`+@!````B</3XX7>=3.(2C"+%XG8"?")@A@!``"+!XN`
+M6`$``*,`````B=HAP@^$E@```(L'B9!8`0``Z8D```"#P0&#^2!UN(L'B[`<
+M`0``B34`````L0"X`0```(G#T^.%WG4LB$HPBQ>)V`GPB8(<`0``BP>+@&`!
+M``"C`````(G:(<)T0HL'B9!@`0``ZSB#P0&#^2!UOXM'!(L`BP>+D!P!``"+
+M@!@!``"C`````(E$)`R)1"0(B40D!,<$)!P#``#H_/___X!'+`&#Q!!;7E_#
+MC;8`````C;\`````55=64X/L'(ML)#"+?"0T#[97)(G0@^`&@_@&=0GVP@$/
+MA/@```"`?SK_#X7N````BT4`B[`8`0``B34`````N0````"X`0```(G#T^.%
+MWG4VB$\ZBU4`B=@)\(F"&`$``(M%`(N`6`$``*,`````B=HAP@^$H0```(M%
+M`(F06`$``.F3````@\$!@_D@=;6+10"+L!P!``")-0````"Q`(G*N`$```")
+MP]/CA=YU,HU"((A'.HM5`(G8"?")@AP!``"+10"+@&`!``"C`````(G:(<)T
+M1(M%`(F08`$``.LY@\$!@_D@=;>+102+`(M%`(N0'`$``(N`&`$``*,`````
+MB40D#(E$)`B)1"0$QP0D'`,``.C\____@$4L`8/$'%M>7UW#C78`C;PG````
+M`(/L#(M$)!"-D,0```"Y`````#F0Q````'01B10DZ/S___^)P<=`%`````")
+MR(/$#,/K#9"0D)"0D)"0D)"0D)"#[!R)7"00B70D%(E\)!B+?"0@#[=4)"0/
+MM_*+APP%``#'!+``````9L'J!0^WTHGS@^,?N/[___^)V=/`(827$`4``(ET
+M)`2-CRP&``")#"3H_/___XM<)!"+="04BWPD&(/$',.-=@"-O"<`````@^P,
+MBU0D$(M$)!0/MD@$#[:$$9P$``#&A!&<!```_P^WP(E$)`2!PJ0&``")%"3H
+M_/___X/$#,.0C;0F`````(/L'(E<)!2)="08BUPD((MT)"0/MD8P//]T&0^V
+MP(E$)`2+`XD$).C\____QD8P_X!K+`&+7"04BW0D&(/$',.#[!R)7"04B70D
+M&(M<)""+="0D#[9&.CS_=!D/ML")1"0$BP.)!"3H_/___\9&.O^`:RP!BUPD
+M%(MT)!B#Q!S#5E.#[!2+="0@BUPD)#ES&'0U@WM,`'0O@'M4`'4I@7L@`!``
+M`'<1C4-,B40D!(DT).C\____ZP^-0TR)1"0$B30DZ/S___]F@7LDX0$/A8T`
+M```/MT,09CV#`'=U#[?`#[:$!A@$```\_W1FBY;4!```@'L4`'5:#[;`:<#<
+M````C00"#[93)H#Z!W0<@/H'=P>`^@9U,.L9@/H,C70F`'0@@/H-=2#K$&:#
+M8#;]B?;K%6:#2#8"ZPYF@V`V]XGVZP5F@T@V"&:!>R3A`8UV`'4.@'LF"W4(
+MQD,4`(UT)@")7"0$BT,8B00D_U-L9H%[).$!=4L/MD,F@^@1/`%W0`^W0Q!F
+M/8,`=W8/M\`/MH0&&`0``#S_=&</ML!IP)0````#AO`$``"`>"@`=5*)1"0$
+MB30DZ/S____K1(UT)@`/MT,09CV#`'<V#[?`#[:$!A@$``"+EM0$```\_W0A
+M#[;`:<#<````C00"@'A'`'4/B40D!(DT).C\____C78`@\046U[#C78`C;PG
+M`````(/L#(E<)`2)="0(BW0D$(V&I````+L`````.8:D````="6)!"3H_/__
+M_XG#B00DZ/S____&0Q2`B30DZ/S___^)0U#&0W`!B=B+7"0$BW0D"(/$#,.-
+M="8`C;PG`````(/L'(E<)!")="04B7PD&(MT)""-GJ0&``")'"3H_/___X3`
+M#X6G````B1PDZ/S___^)P;@`````B<.`O#"<!```_W4,.$8O<Q*(1B_K#8GV
+M@\,!@\`!@_@$==V`^P1T<`^VPXB,!IP$```/M_EKQTR-E`;H````N`````"-
+M="8`Q@00`(/``8/X3'7T#[?!:\!,C90&``$``(U*"`'PB8@(`0``B8@,`0``
+M@\(0B9`0`0``B9`4`0``B)CL````:\=,C80&Z````.L*D(UT)@"X`````(M<
+M)!"+="04BWPD&(/$',.-="8`C;PG`````(/L'(E<)!")="04B7PD&(MT)""-
+MGE0&``")'"3H_/___X3`#X6W````B1PDZ/S___^)PK@`````B<.`O#`8!```
+M_W4<#[;`9CF&D````',=9HF&D````.L4C;0F`````(/#`8/``3V`````=<N`
+M^X!T;@^VPXB4!A@$```/M\)I^-P```")^`.&U`0``(D$).C\____BY;4!```
+M#[;#9HE$%QR+AM0$``#&1`<F`(N&U`0``,9$!SC_BX;4!```QD0'.?^`?C,!
+M=0N+AM0$``"`3`<H`8GX`X;4!```ZP:0N`````"+7"00BW0D%(M\)!B#Q!S#
+MC70F`(V\)P````!3@^P(BUPD$(M4)!2)V.B]]O__BX.@!```B00DZ/S___^#
+MQ`A;PXUV`(V\)P````"#[!R)7"00B70D%(E\)!B+="0@C9Y\!@``B1PDZ/S_
+M__^$P`^%MP```(D<).C\____B<*)\+^`____C;8`````@+B8!```_W03@\<!
+M@\`!B?F`^80/A(8```#KY(GX/(1T?@^VP(B4!A@$```/M]IIVY0```")V`.&
+M\`0``(D$).C\____BY;P!```B?D/ML%FB403)(N&\`0``,9$`R8`BX;P!```
+M9L=$`RX``(N&\`0``&;'A`.```````#'1"0$`````(N&H`0``(D$).C\____
+MB=@#AO`$``#K"(UV`+@`````BUPD$(MT)!2+?"08@\0<PXUT)@"-O"<`````
+M5E.#[!2+="0@BT0D)`^W0"0/MIPP&`0``,:$,!@$``#_#[?;B5PD!(V&?`8`
+M`(D$).C\____:=N4````B=@#AO`$``"`>##_=`R)1"0$B30DZ/S____'1"0$
+M`````(N&H`0``(D$).C\____@\046U[#C;0F`````(V\)P````!3@^P(BUPD
+M%(![)_]T&HU#4(E$)`2+5"00BT(4B00DZ/S____&0R?_@\0(6\.-=@!3@^P(
+MBUPD%(![1/]T'8V#N````(E$)`2+5"00BT(4B00DZ/S____&0T3_@\0(6\.#
+M[!R)7"00B70D%(E\)!B+="0@BWPD)`^W1QP/MHPP&`0``(N4AA@"``"%TG02
+M@WIP`'4,QX2&&`(```````"0#[='',:$!A@$``#_#[?9B5PD!(V&5`8``(D$
+M).C\____:=O<````B=@#AM0$``"`>#K_=`R)1"0$B30DZ/S___^)?"0$B30D
+MZ/S___^+AM0$``#&1`,F`(N&U`0``,9$`R<!BUPD$(MT)!2+?"08@\0<PXVV
+M`````(V\)P````"#[!R)7"0,B70D$(E\)!2);"08BVPD((M\)"1F@7\DX0$/
+MA;D````/MD<F@^@1/`$/AZH````/MT<09CV#``^'1`$```^WP`^VA`48!```
+MBY7P!```//\/A"L!```/ML!IP)0```"-'`*`:R@!C7,4B30DZ/S___^)PCGX
+M=4*)7"0$B2PDZ/S___\[<Q0/A/4```#'0U``$GH`QT-8`````(E;7(U#4(E$
+M)`2+112)!"3H_/___\9#)P#IR0```)"+0Q2)4`2)`HER!(E3%(L7BT<$B4($
+MB1#IJP```(UV``^W1Q!F/8,`#X>:````#[?`#[:$!1@$``"+E=0$```\_P^$
+M@0````^VP&G`W````(T<`H!K1P&-<Q")-"3H_/___XG".?AU2(E<)`2)+"3H
+M_/___SMS$'1/QX.X`````!)Z`,>#P`````````")F\0```"-@[@```")1"0$
+MBT44B00DZ/S____&0T0`ZQJ)]HM#$(E0!(D"B7($B5,0BQ>+1P2)0@2)$(M<
+M)`R+="00BWPD%(ML)!B#Q!S#C70F`(/L'(E<)!2)="08BW0D((M<)"0/MTL>
+M9H'Y_P]T#P^WT8N&#`4``(,\D`!U(P^WP8E$)`R)7"0(QT0D!`````#'!"0[
+M````Z/S____K+XGV#[?!B40D!(DT).C\____9L=#'O\/B5PD!(DT).C\____
+MB5PD!(DT).C\____BUPD%(MT)!B#Q!S#C;0F`````%575E.#[`P/MD0D)(A$
+M)`N+5"0@BQIF@WM,``^$O@```+\`````#[?7BX,,!0``BS20A?8/A)@````/
+MMTX09H'Y@P!W2P^WP0^VA`,8!```//]T/&:#^7]W&0^VP(N3U`0``&G`W```
+M`(M$$"P/MD`$ZR(/ML"+D_`$``!IP)0```"+1!!,#[9`!.L)C70F`+C_____
+MBU0D(#I"!'4T@WPD*`!T"HM$)"AF.T@<=2,/ME0D"XA6%`^WQXE$)`2)'"3H
+M_/___XET)`2)'"3H_/___X/'`68Y>TP/AT?___^`?"0+@0^$``$``(N#E```
+M`(V[E````#GX#X3L````O0````"#Q0&+`#GX=?=FA>T/A-4```")/"3H_/__
+M_XG!#[=P$&:!_H,`=T</M\8/MH0#&`0``#S_=#AF@_Y_=QD/ML"+D]0$``!I
+MP-P```"+1!`L#[9`!.L>#[;`BY/P!```:<"4````BT003`^V0`3K!;C_____
+M@WPD*`!T(XM4)"AF.W(<=!F+@Y@```")BY@```").8E!!(D(ZSR-="8`BU0D
+M(#I"!'4<@'D4@'4(#[9$)`N(012)3"0$B1PDZ/S____K$XN#F````(F+F```
+M`(DYB4$$B0AF@^T!=`PYNY0````/A2O___^#Q`Q;7E]=PXVT)@````"-O"<`
+M````5E.#[!2+3"0@BW0D)&:!?B3A`0^%EP````^V1B:#Z!$\`0^'B`````^W
+M1A"Z_P```&8]@P!W"P^WP`^VE`$8!```:<*4````B<,#F?`$``"`>R?_=3P/
+MME9HN`@```"$TG0#C002#[;`:<!`0@\`B4-0QT-8`````(E;7(U#4(E$)`2+
+M012)!"3H_/___\9#)P"+4QB)<QB-0Q2)!HE6!(DR@$,H`>F/````D(UT)@`/
+MMT80NO\```!F/8,`=PL/M\`/MI0!&`0``&G"W````(G#`YG4!```@'M$_W5(
+M#[96:+@(````A-)T`XT$$@^VP&G`0$(/`(F#N````,>#P`````````")F\0`
+M``"-@[@```")1"0$BT$4B00DZ/S____&0T0`BU,4B7,4C4,0B0:)5@2),H!#
+M1P&#Q!1;7L-55U93@^P<BVPD.,9%)P'&128`B6PD",=$)`0&````BT0D-(D$
+M).C\____@'U'`'0>BU0D,(D4).C\____QP0D`0```.C\____@'U'`'7BBUT@
+MA=L/A"P!``#V12@$B?9U)XM,)#")#"3H_/___\=$)`@!````BT4@B40D!(M$
+M)#")!"3H_/___XM5(`^V14>)1"00#[:"EP````^V4@*-!(`/MH0"`````(E$
+M)`R+5"0P#[9"(HE$)`@/MD(AB40D!,<$)$`#``#H_/___XM%((E$)`B+3"0P
+MBX&@!```B40D!,<$)`$```#H_/___XM3<(72#X2<`0``#[=%'(M,)##'A($8
+M`@```````,=#<`````#'1"0(_____XE<)`2+0WB)!"3_TNEI`0``#[=%'(M,
+M)##'A($8`@```````,=#=`````"+0WB)!"3_TO9%*`)T(8M%((E$)`B+5"0P
+MBX*@!```B40D!,<$)`8```#H_/___\=%(`````#'0V0`````ZTF+3"0P#[9!
+M*8M,)#2+41@/ME($C02"#[9518T$@`^VA`(`````B40D#(M4)#`/MD(BB40D
+M"`^V0B&)1"0$QP0D40```.C\____BU4PA=)T#`^V147'1((X`````(M5`(M%
+M!(E"!(D0BTPD-`^V40F#Z@&(40F+13"%P'0'9H-X+@)U=832='&^`````(M\
+M)#2#QRB-M"8`````B3PDZ/S___^)PXM4)#2+0BR)6BR).XE#!(D8A=MT,?9#
+M*`)T*XM#((E$)`B+3"0PBX&@!```B40D!,<$)`8```#H_/___X!C*/V-M@``
+M``"#Q@&)\(M4)#0X0@EWHHEL)`2+3"0PB0PDZ/S___^#Q!Q;7E]=PXM3=(72
+M#X6,_O__Z:G^__^-=@"-O"<`````4X/L"(M,)!"+7"04BY&H````B9FH````
+MC8&D````B0.)4P2)&H-[4`!T#XU#4(E$)`2)#"3H_/___\9#<`"#Q`A;PXVV
+M`````(V\)P````"#[`R+1"00C9"T````N0`````YD+0```!T"HD4).C\____
+MB<&)R(/$#,.-M@````"#[`R+1"00C9"\````N0`````YD+P```!T"HD4).C\
+M____B<&)R(/$#,.-M@````!3@^P(BT0D$(N8R`8```4L!@``B00DZ/S___^)
+MP0^WP,'@!HT4&(M$)!2)$+@`````Q@00`(/``8/X0'7T#[?!@\0(6\.0D)"0
+MD)"0D)"0D%93BU0D#(L"BS`/ME@KA-MT-P^V4@BY`````/;"`70*ZR>)T-/X
+MJ`%U!X/!`3C9=?&`^0-V&`^VP8V$AM`!``"+`*,`````ZQ:Y``````^VP8V$
+MAM`!``"+`*,`````P>@4@^`!6U[#D(VT)@````!3BUPD"`^V`\#H!(G"@^('
+M#[9+`O;!!'0#@,X"#[9#`Z@$=`:!R@```@#VP0AT`X#."*@(=`:!R@``"`#V
+MP0)T`X#.!*@"=`:!R@``!``/MD,4P>`8"=!;PXVT)@````!3B<.%TGY`#[8(
+MA,ET!8#Y('4MN`````#K%HVV``````^V#!B$R70(@/D@=1.-=@"#P`$YT'7I
+MZPZ-M"8`````N`````#K!;@!````6XUV`,/K#9"0D)"0D)"0D)"0D)!75E.)
+MQHG3B<^%R70>N0`````/MA8/MD8!B`.(4P&#PP*#Q@*#P0$Y^77G6UY?PY"#
+M[!R)7"00B70D%(E\)!B+?"0@BUPD)(M'3(LPB30DZ/S____&0"3AQD`E`<9`
+M)A+&0"</QD`HH,9`*0,/MM>(4"J)VL'J$(A0*XG:P>H8B%`LB%@M#[=7)&:)
+M4!")<!C'0"``````QT`T`````,=`;`````")1"0$B30DZ/S___^+7"00BW0D
+M%(M\)!B#Q!S#ZPV0D)"0D)"0D)"0D)"0@^P<B5PD#(ET)!")?"04B6PD&(ML
+M)"0/MG0D*`^V?"0LBT0D((L8B1PDZ/S___^)PH7`=1#&A94````!QD4F`^E_
+M````QD`DX<9`)0&)\#P!&<#WT(/``HA")HGXA,!U/X-],`!T!`^V146(0B</
+MMT4<9HE"$(E:&,="(`````#'0C0`````N."0``")0FR)5"0$B1PDZ/S____K
+M)XUV`,9")P\/MT4<9HE"$(E:&,="(`````#'0C0`````N`````#KR(M<)`R+
+M="00BWPD%(ML)!B#Q!S#D(VT)@````"#[!R)7"0,B70D$(E\)!2);"08#[9\
+M)"0/MFPD*`^W="0LBU0D((M"3(L8B1PDZ/S___^)PH7`='[&0"3AQD`E`8GY
+M@/D!#Y3`@\`1B$(FN`\```")Z83)=0B+3"0@#[9!*8A")XGPB$(HB?$/ML6(
+M0BF)^#P!=1V+3"0P#[;%B$(JB<C!Z!"(0BN)R,'H&(A"+(A*+8M,)"`/MT$D
+M9HE"$(E:&(M$)#2)0FR)5"0$B1PDZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<
+MPY"-="8`@^P<B5PD#(ET)!")?"04B6PD&(ML)"0/MG0D*`^V?"0LBT0D((L8
+MB1PDZ/S___^)PH7`=0W&A94````!QD4F`^M4QD`DX<9`)0&)\#P!&<#WT(/`
+M`HA")K@/````B?F$R74$#[9%18A")P^W11QFB4(0B5H8QT(@`````,="-```
+M``"+1"0PB4)LB50D!(D<).C\____BUPD#(MT)!"+?"04BVPD&(/$',.-M@``
+M``"#[!R)7"0,B70D$(E\)!2);"08BVPD(`^V?"0DBW4`B?@\`W8P#[;8P>,#
+MC80>,`(``,<`#````,<$)!`G``#H_/___XV$'C0"``"+,(DU`````.LPB?@/
+MMMC!XP.-A#-0`@``QP`,````QP0D$"<``.C\____C9PS5`(``(LSB34`````
+MB?@/MM"-!-*-C,5`"```#[99"8/C_(A9"8GP)0``/P`]```0`'4*B=B#R`*(
+M00GK#XT4THG8@\@!B(3520@``(M<)`R+="00BWPD%(ML)!B#Q!S#C;0F````
+M`%575E.#[`R+="0@BVPD)(M&3(LX9H.^B`````!T,HGKQP0DZ`,``.C\____
+MA>UT!8/[`78;B3PDZ/S___]F@[Z(`````'0)@^L"Z]2-="8`@\0,6UY?7<.0
+MC;0F`````(/L'(E<)!")="04B7PD&(MT)""+?"0D#[='$+K_````9CV#`'<+
+M#[?`#[:4!A@$```/M])ITI0````#EO`$``"+GNP&```/MD(PP>`(C80#3`@`
+M`(L(B0T`````@>'_````#[9",,'@"(V<`T0(``"+`Z,`````P>`("<B)@HP`
+M``!FQX*(``````")?"0$B30DZ/S___^+7"00BW0D%(M\)!B#Q!S#B?:-O"<`
+M````55=64X/L!(M\)!B+;"0<B2PD#[=%`&:%P'D+)0`?``#!^`B(1R6-1TB-
+M312+512)5TB+402)4`2+40B)4`B+40R)4`R+41")4!"-MX0```"+52Z)EX0`
+M``"+53*)5@2-7UR-33:+53:)5UR+402)4P2+40B)4PB+40R)4PR+41")4Q"+
+M412)4Q2+41B)4QB+41R)4QR+42")4R"+422)4R2Y"@```(G"Z#/Z__^Y!```
+M`(GRB?#H)?K__[D4````B=J)V.@7^O__9L='-```9L='-@``BP0D9H.XL@$`
+M``$/E,+!X@,/MD<H@^#W"="(1RCVA:<````$=`9FQT<T`0#VA:0````!="9F
+M@T\T`O:%J@````%T!6:#3S8!]H6H`````70*9H%/-``!C70F`/:%I````"!T
+M%V:#3S0$]H6J````('0)9H-/-@*-="8`]H6D````0'079H%/-(``]H6J````
+M0'0(9H-/-@B-=@#&1T8!]D<T`706BX7(````BY7,````B4<\B5=`ZP^)]HM5
+M>(E7/,='0``````/MX74````)0#0``"Z``(``#T`4```=1L/MX7L````P>`0
+M#[>5Z@````'0C10`D(UT)@")EY````"#1SS_@U=`_\9'.`+V16H"=!@/MX6`
+M````J`]T#6:#^`(9P(/`!(A'.)#&1SG_]D5J!'0>N0````"0#[>%L````-/X
+MJ`%T`XA/.8/!`8/Y!W7HQH?8`````(L$)/:`I@```"!T&`^W@*P```"#X""#
+M^`$9P(/``HB'V````+@!````@\0$6UY?7<-55U93@^PLBVPD2(M$)$"+$(M$
+M)$3!X`.-O!```@``C;00!`(``+L<`0``D(UT)@"#?"1$`W89B1_'!"00)P``
+MZ/S___^+!J,`````ZQ>)]HD?QP0D$"<``.C\____BP:C`````(F$'/3^__^#
+MPP2!^S@!``!UN8M$)!")10"+1"04B44$BT0D&(E%"(M$)!R)10R+1"0@B440
+MBT0D)(E%%(M$)"B)11B#Q"Q;7E]=PU575E.#["R+;"1(BT0D0(L0BT0D1,'@
+M`XV\$``"``"-M!`$`@``NP`!``"0C70F`(-\)$0#=AF)'\<$)!`G``#H_/__
+M_XL&HP````#K%XGVB1_'!"00)P``Z/S___^+!J,`````B80<$/___X/#!('[
+M'`$``'6YBT0D$(E%`(M$)!2)102+1"08B44(BT0D'(E%#(M$)"")11"+1"0D
+MB444BT0D*(E%&(/$+%M>7UW#55=64X/L/(M\)%"+1"14B$0D&XLO#[;PC13V
+MC137C8I`"```B$$(B;I$"```QD$*`(ET)`2)/"3H_/___XU$)!R)PL8``(/`
+M`8G3C4PD/#G(=?`/MD0D&XE4)`B)1"0$B3PDZ/S___^)'"3H_/___XT<]0``
+M``"-%#/!X@.-##J)@5`(``"-E!=0"```BT0D*(E"!(M$)"R)0@B`?"0;`W8E
+MC82UT`$``(L`HP````")@6@(``"-A!V``0``BQ")%0````#K+XV$M=`!``"+
+M"(D-`````(T4]0````"-!#*)C,=H"```C805@`$``(L0B14`````C03VC03'
+MB9!L"```]H!J"```$`^$LP```/:`20@```)U"L>`7`@```$``@"`?"0;`W8Q
+MC1SU`````(V$*S`"``#'`!@```#'!"00)P``Z/S___^-G"LT`@``BQ.)%0``
+M``#K+XT<]0````"-A"M0`@``QP`8````QP0D$"<``.C\____C9PK5`(``(L3
+MB14`````C03V]X3':`@``````P!U"('B____W^L&@<H````@@'PD&P-V"XV$
+M]30"``")$.L)C83U5`(``(D0@\0\6UY?7<.-M@````!55U93@^P<BT0D-(M4
+M)#"+$HE4)!B+$L9`)0#&0"0%QD`G!HM,)#")2"RY`````+T`````C8(``@``
+MB40D%('"!`(``(E4)!#K%XVV`````(M4)#`/MD((T_BH`74,@\$!BT0D&#I(
+M*W+F@/D#=G$/MMG!XP.+?"04`=_'!RP```#'!"00)P``Z/S___\#7"00BS.)
+M-0````#'!R0```#'!"00)P``Z/S___^+`Z,`````P>`(@>;_````"<;'!R``
+M``#'!"00)P``Z/S___^+&XD=`````.MOC;0F``````^VV<'C`XM\)!0!W\<'
+M+````,<$)!`G``#H_/___P-<)!"+,XDU`````,<')````,<$)!`G``#H_/__
+M_XL#HP````#!X`B!YO\````)QL<'(````,<$)!`G``#H_/___XL;B1T`````
+M@?X!`6F6=1>+5"0P@$H'!HG8P>@0/%`/E,`/MMCK6H'^`0$``'41B=C!Z!`\
+M4`^4P`^VV.M#B?;'!"2($P``Z/S___^#Q0&)Z8#Y!'<*N0````#IP?[__XG8
+MP>@0/%`/E,`/MMB)7"0(B70D!,<$)&0#``#H_/___XG8@\0<6UY?7<.0C70F
+M`%575E.#[#R+5"10BP*`>BL`#X3)`@``QT0D.`````"-B``"``")3"0<!00"
+M``")1"08#[9$)#B(1"0W#[;HC43M`(M4)%"-',+V@VH(```0#X1P`@``C9-`
+M"```N`$```")Z=/@"$(*BYM,"```B5PD,/9""0(/A!@!```/MEPD-X/#`8MT
+M)%`X7BL/A@,!``"-1.T`B40D((VT)@`````/MO.-!/;!X`.+5"10C3P0]H=J
+M"```$`^$QP```(M,)"#!X0,!RHE4)"SW@EP(``````X`#X2J````BU0D4(V$
+M`E`(``")1"0HB<*#PA"+1"10C8P(4`@``(E,)"2)R(/`$,=$)`@(````B50D
+M!(D$).C\____A,!T:HM$)"B#P`2+5"0D@\($QT0D"`@```")1"0$B10DZ/S_
+M__^$P'1$N`$```")\=/@BU0D+('"0`@```I""HA""HB'2@@``(-\)#``=0R+
+MOTP(``")?"0PZQ*-!/:+5"0PBW0D4(F4QDP(``"#PP&+3"10.%DK#X<,____
+M@WPD,``/A:$```"+="10B30DZ/S___^)1"0PA<`/A"D!``"-1.T`C03&BU0D
+M,(F03`@```^V5"0WC132C9361`@``(M,)#")41@/MH!)"```B$$&QD$%`(DQ
+MQD$)``^V5"0W@\(!.%8K=E2-1.T`C9S&0`@``(VV``````^VR@^V0PK3^*@!
+M=!*-!,F+3"0PBW0D4(F,QDP(``"#P@&+="10.%8K=ACKTXUV`(U$[0"+3"0P
+MBU0D4(F,PDP(``"-'.T`````C00KBW0D4(V$QD`(```/ME`*BTPD,(A1"`^V
+M<`J`?"0W`W8CBT0D'`'8QP`X````QP0D$"<``.C\____BU0D&(T$$XDPZR6-
+M'.T`````BT0D'`'8QP`X````QP0D$"<``.C\____`UPD&(DS@T0D.`$/MD0D
+M-X/``8M,)%`X02L/AU+]__^#Q#Q;7E]=PY"-M"8`````55=64X/L/(M$)%"+
+M",9$)#!0QD0D,0'&1"0RD\9$)#/`QD0D-!'&1"0U`\9$)#8`QD0D-P`[@*`$
+M```/A9X```")PH'"A`D``(M$)#"+7"10B8.T!```BT0D-(F#N`0``*$`````
+M`(.W!```@\`!HP`````/MH.T!```B(*T!```#[:#M00``(B"M00```^V@[8$
+M``"(@K8$```/MH.W!```@\`"B(*W!```#[:#N`0``(B"N`0```^V@[D$``"(
+M@KD$```/MH.Z!```B(*Z!```#[:#NP0``(B"NP0``(G/C8$``0``B40D&(N!
+M``$``*,`````#[?0B50D.*@@=`LEW_\``(E$)#CK%HG0@\@@B40D.(M4)!B)
+M`HL"HP````"+3"10BP''@`0!````````BP''@!@!````````BP''@!P!````
+M````QP0DD-`#`.C\____QX=P`0``&`$``(N'=`$``*,`````@.3]@,P$B40D
+M.,>'<`$``!@!``"+1"0XB8=T`0``QX=P`0``*`$``,>'=`$``']_``#'AW`!
+M```D`0``BX=T`0``HP````!FN```#?\_``")1"0XQX=P`0``)`$``(M$)#B)
+MAW0!``#'AW`!```\`0``QX=T`0````!Z`,>'<`$``*0!``#'AW0!``!]O^__
+MQX=P`0``N`$``(N'=`$``*,`````)?__```-``#Z`(E$)#C'AW`!``"X`0``
+MBT0D.(F'=`$``,>'G````/\```#'AY`"``!$`0``QX>4`@``!A``",>'D`(`
+M`+0!``#'AY0"``!?<```QX>0`@``,````(N'E`(``*,`````,.2`S#.)1"0X
+MB8>4`@``BUPD4(![*P`/A'T"``#'1"0<`````(V'4`(``(E$)!"-EU0"``")
+M5"0,#[9,)!R(3"0C@/D##X80`0``#[;IC1SM`````(E<)!2-M!\P`@``QP8(
+M````QP0D$"<``.C\____BT0D%(V<!S0"``"+`Z,`````B40D.`T``(``B0.+
+M1"10!;0$``")1"0(B6PD!(M4)%")%"3H_/___XEL)`2+3"10B0PDZ/S____'
+M!D0!``#'!"00)P``Z/S____'`P80``C'!K0!``#'!"00)P``Z/S____'`U]P
+M``#'!@@```#'!"00)P``Z/S____'1"0X_U2``,<#_U0``,=$)`@!````B6PD
+M!(M<)%")'"3H_/___XM$)!2-E`>``0``BP*C`````"7___[_B0+'1"0X!0'(
+M`(M4)!2-A!>$`0``QP`%`<@`Z0D!```/MFPD(XT,[0````")3"0HBW0D$`'.
+MQP8(````QP0D$"<``.C\____BUPD*`-<)`R+`Z,`````B40D.`T``(``B0.+
+M1"10!;0$``")1"0(B6PD!(M$)%")!"3H_/___XEL)`2+5"10B10DZ/S____'
+M!D0!``#'!"00)P``Z/S____'`P80``C'!K0!``#'!"00)P``Z/S____'`U]P
+M``#'!@@```#'!"00)P``Z/S____'1"0X_U2``,<#_U0``,=$)`@!````B6PD
+M!(M,)%")#"3H_/___XM<)"B-E#N``0``BP*C`````"7___[_B0+'1"0X!0'(
+M`(V$.X0!``")1"0DQP`%`<@`QP0DH(8!`.C\____B6PD!(M4)%")%"3H_/__
+M_X-$)!P!#[9$)".#P`&+3"10.$$K#X>?_?__BUPD4(D<).C\____BX<$`0``
+MHP````"#R`*)1"0XB8<$`0``BU0D&(L"HP`````E\/___0T-```"B40D.(D"
+MBP*C`````(M,)%"+@<P&``")AP@!``"+@=`&``")APP!``"+7"10BX/P!@``
+MB8<0`0``BX/T!@``B8<4`0``QX<@`0````````^W@T`(```E_P\```T```$`
+MB8<@`0``BTPD4(N!.`<``(F')`$``(N!/`<``(F'*`$``(N!6`<``,<`_P\`
+M`,>'-`$````````/MX%""```)?\/```-```!`(F'-`$``(M<)%"+@UP'``")
+MAS@!``"+@V`'``")ASP!``#'AT@!````````QT0D.``!``#'ATP!`````0``
+MBX<$`0``HP````"#R%F)AP0!``#'1"0X^_\`#,>'5`$``/O_``S'AUP!``#_
+M_P``N`````"+5"10QX2"$`4```````"#P`&#^!!UZ6;'@CP(``#_#V;'@CX(
+M``#_#[`!@\0\6UY?7<.0C70F`%575E.#[!R)1"04B=>+*(DL).C\____B<.%
+MP'4,QH>5`````>G`````B2PDZ/S___^)QH7`=1C&AY4````!B5PD!(DL).C\
+M____Z9H```"-0SR)1"08QD,DX<9#)0'&0R8##[=''&:)0Q#&0V@/BU0D%(L"
+MB4,8QT,@``(``(M6"(E3-+@`````C;0F`````,8$$`"#P`$]``(``'7RB7-,
+MQT-LX)```,=$)`0`````BT0D&(D$).C\____BT,@B40D#(M&#(M6$(E$)`2)
+M5"0(BU0D&(D4).C\____B5PD!(DL).C\____@\0<6UY?7</K#9"0D)"0D)"0
+MD)"0D)!55U93@^PLBWPD0(M<)$2%VW05#[9#!83`=`T\_P^%C08``.D+`0``
+MN@````"-=@`/MH0ZG`0``#S_=`T/ML!KP$R-G`?H````@\(!@_H$==^^````
+M``^VA#Z<!```//]T'P^VP&O`3(V<!^@```#VA`?N`````G4(B1PDZ/S___^#
+MQ@&#_@1US0^V1R9F.8>H!@``#X46!@``A=L/A7P```"`?S,`#X4$!@``QD<S
+M`8N$GQ@"``"%P'15BU!PA=)T*,=`<`````#'A)\8`@```````,=$)`C_____
+MB40D!(M`>(D$)/_2ZR:+4'2%TG0?QT!T`````,>$GQ@"````````BT!XB00D
+M_]*0C70F`(/#`8/[%`^$E`4``.N2QD,%_XE<)`2)/"3H_/___^E]!0``N@``
+M```/MH0ZG`0``#S_=&P/MLAKP4R-A`?@````@'@-_W19@'@1``^$3P4``+L`
+M````:^E,C;0O$`$``(DT).C\____C4P]`(N1%`$``(F!%`$``(DPB5`$B0*`
+M>";_#X47!0``@\,!.)GQ````#X8(!0``Z\:-M@````"#P@&#^@1U@,=$)"``
+M````@'\S``^%C@```+L`````D(N4GQ@"```/MH0[&`0``(72=&2+2G"%R71=
+M@WID`'57//]T+0^V\&G&W`````.'U`0``/9`)P1T&(!X)0!U$HET)`B)5"0$
+MB3PDZ/S____K)L>$GQ@"````````QT)P`````,=$)`C_____B50D!(M">(D$
+M)/_1@\,!@_L4=8'&1S,!Z5@$``"+5"0@#[:$.IP$```\_P^$+@0```^VT&O"
+M3(V,!^@```")3"0H@+P'\0`````/A`\$``#&1"0G`(G%C80'$`$``(E$)!2-
+M=@"+5"04B10DZ/S___^)PXU$/0"+D!0!``")F!0!``"+3"04B0N)4P2)&H![
+M)O\/A;`#```/MT,<B40D&`^VE#@8!```9HE4)!Z+M(<8`@``]D,H!'1KA?9T
+M9X-^<`!T88-^9`!U6X!C*/OV0R<$C78`=!4/M\*)1"0(B70D!(D\).C\____
+MZSF+5G"+3"08QX2/&`(```````#'1G``````QT,@`````,=$)`C_____B70D
+M!(M&>(D$)/_2D(UT)@#V0R<$#X1J`0``QH.4`````("D+^\```#G]D,H`0^$
+M_@```(!C*/Z+0R"%P'18@'LE`'4S]D,G!'0M#[9'*8T$@(M4)!B-!(*)1"0(
+MBX>@!```B40D!,<$)`<```#H_/___^G=````B40D"(N'H`0``(E$)`3'!"0!
+M````Z/S____IO@```(7V=&&+5G"%TI!T68![)0!U(/9#)P1T&@^W1"0>B40D
+M"(ET)`2)/"3H_/___^F,````BTPD&,>$CQ@"````````QT9P`````,=#(```
+M``#'1"0(_____XET)`2+1GB)!"3_TNM9@'LE`'53]D,G!'1-#[9'*8T$@(M4
+M)!B-!(*)1"0(BX>@!```B40D!,<$)`(```#H_/___^LCBT,@A<!T'(M0=(72
+MC78`=!+'0'0`````BT,@BT!XB00D_]+V0R@"#X35`0``BT,@B40D"(N'H`0`
+M`(E$)`3'!"0&````Z/S___^`8RC]Z8@!``"+0R"%P`^$?0$``(-X=``/A',!
+M``#&0R<!QD,F`(E<)`C'1"0$!@```(M,)"B)#"3H_/___X![1P!T&Y")/"3H
+M_/___\<$)`$```#H_/___X![1P!UYHMS((7V#X3V````]D,H!'5=B3PDZ/S_
+M___'1"0(`0```(M#((E$)`2)/"3H_/___XM3(`^V0@*)1"0(#[9"`8E$)`3'
+M!"1O````Z/S___^+0R")1"0(BX>@!```B40D!,<$)`$```#H_/___^LY#[9&
+M`HE$)`@/MD8!B40D!,<$)&\```#H_/___XM#((E$)`B+AZ`$``")1"0$QP0D
+M`0```.C\____BU9TA=)T'@^W0QS'A(<8`@```````,=&=`````"+1GB)!"3_
+MTO9#*`)T(8M#((E$)`B+AZ`$``")1"0$QP0D!@```.C\____@&,H_<=#(```
+M``#'1F0`````BU,PA=)T#`^V0T7'1((X`````(L3BT,$B4($B1"`K"_Q````
+M`8E<)`2)/"3H_/____9#*`)T(8M#((E$)`B+AZ`$``")1"0$QP0D!@```.C\
+M____@&,H_8!$)"<!#[9$)"<XA"_Q````#X<&_/__@T0D(`&#?"0@!`^%KOO_
+M_XVV`````+@!````@\0L6UY?7<.-=@"#["R)7"0<B70D((E\)"2);"0HBUPD
+M-(M[+`^W0QRZ`````(M,)#"`O`$8!```_P^$<`<```^V0R8\"0^$@@4``#P)
+M=TL\!0^$F````#P%D'<>/`,/A+8````\!(UT)@`/A2H'``#IY````)"-="8`
+M/`</A.8$```\!XVV``````^';`0``.F.`@``D(UT)@`\%@^$VP,``#P6C;8`
+M````=R,\%`^$ZP4``#P4C70F``^'$`,``#P*#X72!@``B?;I8P4``#P:#X0X
+M`@``//^0#X3#!0``/!</A;(&``")]NFA`P``BW0D,`^V;BN)Z(3`#X2A````
+M#[97"+X`````]L(!#X2"````Z8H```")]HM'&(%@*/___O^+0RS'1"0,````
+M`,=$)`@!````B5PD!(D$).C\____QP0D!0```.C\____N@$```#I5@8``,=$
+M)`P`````QT0D"`````")7"0$B3PDZ/S____'!"10PP``Z/S___^Z`0```.DD
+M!@``B=")\=/XJ`%U$H/&`8GPB>DXR'7KZP6^``````^V4R2)T(/@!H/X!G4)
+M]L(!#X75````BU<8BT(HJ0```0!T#27___[_B4(HZ;L```")\@^VPL'@`XE$
+M)!B]$"<``)"+3"0PBQ&)\#P#=AF+3"08C801@`$``(L`HP`````E```!`.L7
+MBTPD&(V$$8`!``"+`*,`````)0```0"%P'0RB?`\`W86BTPD&(V$$8`!``#'
+M`````0#I6P4``(M,)!B-A!&``0``QP````$`Z44%``#'!"3H`P``Z/S___^#
+M[0$/A7G____&0R<"QD,F_XE<)`2+="0PB30DZ/S___^Z`0```.D<!0``]D<&
+M`70VB5PD!(D\).C\____A,!U)KWZ````B5PD!(D\).C\____A,!U$<<$).@#
+M``#H_/___X/M`77?B?`\`W8>BU0D,(L"!8`!``")\0^VT8T4T(L"HP````")
+M`NL<BU0D,(L"!8`!``")\0^VT8T4T(L"HP````")`HM#+(G:Z#'U__^Z`0``
+M`.F,!```BW0D,`^V1BF+5Q@/ME($C02"#[9318T$@`^VA`(`````#[96(@^V
+M3B&)1"0,B50D"(E,)`3'!"24`P``Z/S___^+<RR+/HD\).C\____B<&%P'41
+MQH.5`````;H!````Z2<$``#&0"3AQD`E`<9`)A</MT,<9HE!$,9!:`^+!HE!
+M&,=!(`````#'030`````QT%LX)```(E,)`2)/"3H_/___[H!````Z=\#``"+
+M5"0P#[9"*8M7&`^V4@2-!((/ME-%C02`#[:$`@````"+3"0P#[91(@^V22&)
+M1"0,B50D"(E,)`3'!"34`P``Z/S___^+<RR+/HD\).C\____B<&%P'41QH.5
+M`````;H!````Z78#``#&0"3AQD`E`<9`)A@/MT,<9HE!$(L&B4$8QT$@````
+M`,=!-`````#'06S@D```B4PD!(D\).C\____N@$```#I,@,``(G:B?CHQ//_
+M_[H!````Z1\#``"+-XDT).C\____B<$/MD,XA<EU$<:#E0````&Z`0```.GZ
+M`@``QD$DX<9!)0'&028%B$$G#[=#'&:)01"+!XE!&,=!(`````#'030`````
+MQT%LX)```(E,)`2)-"3H_/___[H!````Z;,"``"+-XDT).C\____B<$/MD,Y
+MA<EU$<:#E0````&Z`0```.F.`@``QD$DX<9!)0'&028$B$$G#[=#'&:)01"+
+M!XE!&,=!(`````#'030`````QT%LX)```(E,)`2)-"3H_/___[H!````Z4<"
+M``"+-XDT).C\____B<&%P'41QH.5`````;H!````Z28"``#&0"3AQD`E`<9`
+M)@8/MT,<9HE!$(L'B4$8QT$@`````,=!-`````#'06S@D```B4PD!(DT).C\
+M____N@$```#IX@$``(LWB30DZ/S___^)P87`=1'&@Y4````!N@$```#IP0$`
+M`,9`).'&0"4!QD`F#`^W0QQFB4$0BP>)01C'02``````QT$T`````,=!;."0
+M``")3"0$B30DZ/S___^Z`0```.E]`0``BS>)-"3H_/___XG!A<!U$<:#E0``
+M``&Z`0```.E<`0``QD`DX<9`)0'&0"86QD`H`0^W0QQFB4$0QD%H#XL'B4$8
+MQT$@`````,=!-`````#'06S@D```B4PD!(DT).C\____N@$```#I$`$``,9#
+M)O]FQX.,``````"`>R<"=1B+0RR)7"0(B40D!(MT)#")-"3H_/___Y#V1P<"
+M=1.[`````(UW*(!_"0!U+.F6````BT<<@$`I`8E$)`2+1"0PB00DZ/S___^Z
+M`0```.FK````C;8`````B30DZ/S___^)PHM'+(E7+(DRB4($B1"`>B;_=$J`
+M>B4`=3V`NI4`````=&0/MDHDB<B#X`:#^`9T5H/X!'51]L$!=$R)5"0$BU0D
+M,(D4).C\____N@$```#K2I"-="8`QH*5`````(/#`3A?"7>1QD<%_XE\)`2+
+M3"0PB0PDZ/S___^Z`0```.L;C;8`````N@$```#K#H7M#X3(^O__D.GD^O__
+MB="+7"0<BW0D((M\)"2+;"0H@\0LPY"-="8`@^P\B5PD+(ET)#")?"0TB6PD
+M.(M\)$"+;"1$BT4TB40D*`^V728/MU409H'Z@P`/AQP#```/M\(/MHP'&`0`
+M`(#Y_P^$"`,``&:#^G]W&0^VP8N7U`0``&G`W````(M$$"P/MD`$ZQ</ML&+
+ME_`$``!IP)0```"+1!!,#[9`!#S_#X3*`@``#[;`#[:$!YP$```\_W0.@/G_
+M=`D/ME44@/H&=3`\_P^$I0(``(#Y_Y`/A)L"```/ML%IP-P```")Q@.WU`0`
+M`,9&)P+&1B;_Z7$"```/ML%IP-P```")Q@.WU`0``(32#X2H````@/L&#X2?
+M````@/L,#X2\`0``#[>&C````(E$)!@/ML*)1"04#[9&)HE$)!`/MD<IBU8L
+MBU(8#[92!(T$@@^V5D6-!(`/MH0"`````(E$)`P/MD<BB40D"`^V1R&)1"0$
+MQP0D^`,``.C\____#[>6C````(U"`6:)AHP```!F@_H!=A.`?B8&=`W&1B<"
+MQD8F_^G"`0``QP0DZ`,``.C\____D.FP`0``@/L!=0O&1B8$B?;IH`$``(#[
+M`G4+QD8F!8GVZ9`!``"`^P,/A?T```"+1"0H@'XF&G4<9H%X!,@WB?9U$F;'
+MAHP``````,9&)@;I80$``(E$)`2)-"3H_/___XU&7+HH````Z!/8__^$P'4_
+MC49(NA0```#H`MC__X3`=2Z-AH0```"Z"````.CNU___A,!U&HM&/`M&0'02
+M9L>&C```````QD8F%^D%`0``#[>&C````(E$)!`/MD<IBU8LBU(8#[92!(T$
+M@@^V5D6-!(`/MH0"`````(E$)`P/MD<BB40D"`^V1R&)1"0$QP0D,`0``.C\
+M____9H.^C````!UV#<9&)P+&1B;_Z:,```#'!"3H`P``Z/S___]F@X:,````
+M`>F*````@/L7=0]FQX:,``````#&1B85ZW:`^QAU#V;'AHP``````,9&)A;K
+M8H#[!'4/9L>&C```````QD8F!^M.@/L%=0]FQX:,``````#&1B8(ZSJ`^P9U
+M#V;'AHP``````,9&)@GK)H#[#'4/9L>&C```````QD8F"NL2@/L6=0UFQX:,
+M``````#&1B84B70D!(D\).C\____@WU,`'0/C45,B40D!(D\).C\____B6PD
+M!(D\).C\____BUPD+(MT)#"+?"0TBVPD.(/$/,.-=@"-O"<`````5E.#["2+
+M="0TBUY,#[=6+KD`````]L(@=06Y`````(!^)AH/AW<%```/MD8F_R2%'```
+M``^V5BD/MD8>.,(/@PH%```/ML*+1(8XA<`/A.T$``#IPP0``,9&)@'&1BD`
+MQT0D%`````#'1"00`````,=$)`P"````QT0D"`$```#'1"0$`````(DT).C\
+M____N`````#I"P4``,=$)!0`````QT0D$`````#'1"0,`````,=$)`@!````
+MQT0D!`````")-"3H_/___[@`````Z=$$``#'1"04`````,=$)!``````QT0D
+M#`$```#'1"0(`0```,=$)`0`````B30DZ/S___^X`````.F7!```QT0D%```
+M``#'1"00`````,=$)`Q@````QT0D"`$```#'1"0$`````(DT).C\____N```
+M``#I700``,=$)!0`````#[9&*HE$)!#'1"0,8````,=$)`@!````QT0D!`$`
+M``")-"3H_/___[@`````Z2,$``#'1"04`````,=$)!````$$QT0D#"$```#'
+M1"0(`0```,=$)`0!````B30DZ/S___^X`````.GI`P``QT0D%`````#'1"00
+M`0```,=$)`P"````QT0D"`````#'1"0$`0```(DT).C\____N`````#IKP,`
+M`,=$)!0`````QT0D$`````#'1"0,`@```,=$)`@`````QT0D!`$```")-"3H
+M_/___[@`````Z74#``")3"04QT0D$`````#'1"0,`````,=$)`@`````QT0D
+M!`````")-"3H_/___[@`````Z3\#``"+0QB!8"C___;_QT0D%`````#'1"00
+M_____\=$)`P!````QT0D"`````#'1"0$`0```(DT).C\____N`````#I^P(`
+M``^V3BF+0Q@/ME`$B4PD%(E4)!"+7"0P#[9#*8T$@HT$@`^VA`$`````B40D
+M#`^V0R*)1"0(#[9#(8E$)`3'!"1H!```Z/S____'1"00`````,=$)`P`````
+MQT0D"`$````/MD8IBT2&.(E$)`2+1DR)!"3H_/___[@`````Z7D"``#'1"00
+M`````,=$)`P`````QT0D"``````/MD8IBT2&.(E$)`2)'"3H_/___[@`````
+MZ4,"``"+0QCW0"@```D`=`;&1B80ZTO&AI(`````C5YHB5PD!(M4)#"+0A2)
+M!"3H_/___\=&:$!"#P#'1G``````B79TB5PD!(M<)#"+0Q2)!"3H_/___[@!
+M````Z>8!``#V1BX@=&.#?C0`=$[&1B82#[9>'H3;=&Z+5C2Y`````+@!````
+M]L(!=1+K&I"-="8`N`$```#3X(7"=!6(3BGWT"%&-.M`N0````"-M@````"#
+MP0$XV779ZRS&1BD`QD8F&6:#9B[?ZQT/MD8I@\`!B$8I.D8><@K&1BD`QD8F
+M&>L$QD8F"XET)`2+1"0PB00DZ/S___^X`0```.E&`0``QT0D%`````#'1"00
+M`````,=$)`P@````QT0D"`$```#'1"0$`````(DT).C\____N`````#I#`$`
+M`,=$)!0`````QT0D$`````#'1"0,`0```,=$)`@`````QT0D!`````")-"3H
+M_/___[@`````Z=(```#'1"04`````,=$)!#_____QT0D#`$```#'1"0(````
+M`,=$)`0!````B30DZ/S___^X`````.F8````C78`#[;"BT2&.(7`="7&0"8:
+MQD`G!HE$)`2+5"0PB10DZ/S___^X`0```.MKC;8`````@\(!B%8I#[9&'CC0
+M=\(XPG5.QD8I`,9&)A&)="0$BUPD,(D<).C\____N`$```#K-(G0@\@"9HE&
+M+L9&)@"+1DS&0`7_BT9,B40D!(M$)#")!"3H_/___[@!````ZP:0N`$```"#
+MQ"1;7L.0C70F`(/L+(E<)"")="0DB7PD*(MT)#"+/HM&3(M0&/="*```"0!U
+M30^VAI(````\"G96#[9.*0^V4@2)3"04B50D$`^V1RF-!(*-!(`/MH0!````
+M`(E$)`P/MD<BB40D"`^V1R&)1"0$QP0DE`0``.C\____QD8F$(ET)`2+!HD$
+M).C\____ZSN#P`&(AI(```"-7FB)7"0$BT<4B00DZ/S____'1FA`0@\`QT9P
+M`````(EV=(E<)`2+1Q2)!"3H_/___XM<)""+="0DBWPD*(/$+,-55U93@^PL
+MBWPD0(M$)$0/MU`09H'Z@P!W5@^WP@^VA#@8!```//]T1V:#^G]W&`^VP&G`
+MW`````.'U`0``(M`+`^V4`3K+HM4)$0/MT(0#[:$.!@$``!IP)0````#A_`$
+M``"+0$P/ME`$ZPF-="8`NO____^Y_____XM$)$1F@7@0@P!W$(M,)$0/MT$0
+M#[:,.!@$```/ML(/MH0XG`0``&O`3(VT!^@````/ML%IP)0```"+K_`$```!
+MQ8M$)$2`>!0`#X36````#[95*8E4)"0/MDTFB4PD*(M&&`^V4`0/MD<IC02"
+MB40D#`^V3R(/ME\ABT0D)(E$)!B)5"04BU0D*(E4)!")3"0(B5PD!,<$),`$
+M``#H_/___X!]'@!T*+L`````#[;#BT2%.(7`=!")1"0(B70D!(D\).C\____
+M@\,!.%T>=]V+3"1$@WE,`'01B<B#P$R)1"0$B3PDZ/S___^+1"1$B40D!(D\
+M).C\____9H--+@+&128`BT5,QD`%_XM%3(E$)`2)/"3H_/___^F:`0``C;0F
+M`````(N7[`8``('"0`@```^V13#!X`@!PHL"HP````"+E^P&``"!PD0(```/
+MMD4PP>`(`<*+"HD-`````(N7[`8``('"2`@```^V13#!X`@!PHL"HP````"+
+ME^P&``"!PDP(```/MD4PP>`(`<*+$HD5``````^V128\$70K/!%W#3P+#X7Q
+M````Z9T````\$HUV`'1X/!,/A=T```"-M@````#I?0```(G(P>`("T4T#[;2
+M"=")132Y`````(!]'@!T.+D`````N`$```#V130!=0[K%K@!````T^"%131T
+M$HA-*??0(44TZQ"Y`````(UV`(/!`3A-'G?:.$T>#Y3`C03%$@```(A%)NMM
+MB<C!X`BI```!!'0&QD4F$^M;QD4F"^M5QD4F"^M/BT5,BT`8@6`H___W_\9%
+M)A")T(/@#X/X`W48#[9%*8M$A3B%P'0&]D`H$'0BQD4F#.L<#[9%*8M$A3B%
+MP'00B40D"(ET)`2)/"3H_/___XM4)$2)5"0$B3PDZ/S___^);"0$B3PDZ/S_
+M__^#Q"Q;7E]=PY"-="8`@^P,BT0D$(E$)`2+`(D$).C\____@\0,PXVT)@``
+M``"#[`R+1"00QD`F"(E$)`2+`(D$).C\____@\0,PXUV`(/L#(M$)!#&0"8.
+MB40D!(L`B00DZ/S___^#Q`S#C78`5U93@^P0BW0D((L^B30DZ/S___^$P'08
+M#[9?*X3;=#$/ME8(N0````#VP@%T'.LAQD8%_XET)`2)/"3H_/___^M<B=#3
+M^*@!=0>#P0$XV77QB3PDZ/S___^)P87`=#^+5BR)1BR-1BB)`8E1!(D*@$8)
+M`8EQ+,9!)`7&024`QD%%#\=$)`P!````QT0D"`$```")3"0$B30DZ/S___^#
+MQ!!;7E_#C70F`(V\)P````!55U93@^P,BW0D((M\)"2++KL*````B7PD!(DT
+M).C\____A,!U$<<$).@#``#H_/___X/K`77?#[9=*X3;="`/ME8(N0````#V
+MP@%T"^L0D(G0T_BH`74'@\$!.-EU\8L7BT<$B4($B1"`;@D!B7PD!(DL).C\
+M____]D8'`G0^BT8<A<!U$XDL).C\____A<`/A%<!``")1AR)*(EP3,9`*0#&
+M0"8`9L=`+@$`B40D!(DL).C\____Z3`!``"+1AR%P`^$RP```(/`:(E$)`2+
+M112)!"3H_/___XM&'(E$)`2)+"3H_/___XU^*#E^*`^$EP```(D\).C\____
+MB<.+0""%P'1MQT!D`````/9#*`1U'XDL).C\____QT0D"`$```"+0R")1"0$
+MB2PDZ/S___^+0R")1"0(BX6@!```B40D!,<$)`$```#H_/___XM#((E$)`B+
+MA:`$``")1"0$QP0D!@```.C\____QT,@`````(!N"0&)7"0$B2PDZ/S___\Y
+M?B@/A6G____'1AP`````@'X)`'03C48HB00DZ/S___^)P8!N"0'K"HDL).C\
+M____B<&%R70SBU8LB4XLC48HB0&)402)"H!&"0&)<2S&020%QD$E`,9!)P;&
+M028#B4PD!(DL).C\____@\0,6UY?7<.-="8`C;PG`````(/L+(E<)!R)="0@
+MB7PD)(EL)"B+;"0PBUPD-`^W4Q!F@?J#`'=:#[?"#[:,!1@$``"`^?]T2F:#
+M^G]W&0^VP8N5U`0``&G`W````(M$$"P/MD`$ZQ</ML&+E?`$``!IP)0```"+
+M1!!,#[9`!`^VR3S_=`UF@?G_`'47C;8`````B5PD!(DL).C\____Z3D!```/
+MML`/MI0%G`0```^WP6G`W````(G&`[74!```@'L4``^$J0```&O"3(V\!>``
+M```/MD<1B40D$`^V1Q")1"0,#[9#)XE$)`@/MD,FB40D!,<$)/@$``#H_/__
+M_XL6BT8$B4($B1"`;Q$!B70D!(DL).C\____B5PD!(DL).C\____#[9U*XGP
+MA,`/A*D````/ME\0N0````#VPP%U#>L<#[;*B=C3^*@!=!:)3"0$B2PDZ/S_
+M___I?0```+H`````@\(!B?`XPG76ZVV-=@!KPDR-O`7H````@'LF`74VQP0D
+M$"<``.C\____B5PD!(DL).C\____QT0D#`$```#'1"0(`````(ET)`2)/"3H
+M_/___^LDQP0D4,,``.C\____B5PD!(DL).C\____B70D!(D\).C\____BUPD
+M'(MT)""+?"0DBVPD*(/$+,.)]E575E.#["R+="1`BT0D1`^W4!!F@?J#`'=6
+M#[?"#[:$,!@$```\_W1'9H/Z?W<8#[;`:<#<`````X;4!```BT`L#[90!.LN
+MBU0D1`^W0A`/MH0P&`0``&G`E`````.&\`0``(M`3`^V4`3K"8UT)@"Z____
+M_[G_____BUPD1&:!>Q"#`'<0BTPD1`^W01`/MHPP&`0```^VP@^VA#"<!```
+M:\!,C;P&Z````(M<)$0/MD,F@^@!QT0D)``````\`7<3#[;!:<#<`````X;4
+M!```B40D)(MO'(M$)$2`>!0`#X1J`0``@WA,`'0/@\!,B40D!(DT).C\____
+MBU0D1(E4)`2)-"3H_/___XM,)$0/ME$FC4+_/`$/AX<```"`^@$/E,(/MM*+
+M1Q@/MD`$B40D'`^V32D/MD8IBUPD'(T$@XT$@`^VA`$`````B40D#`^V7B(/
+MMD8AB40D!(E4)!B)3"04BU0D'(E4)!")7"0(QP0D3`4``.C\____BTPD)(E,
+M)`B)?"0$B30DZ/S____&1280B6PD!(DT).C\____Z5($```/METIB5PD*`^V
+M12:)1"0@BT<8#[90!`^V1BF-!(*)1"0,#[9.(@^V7B&+1"0HB40D&(E4)!2+
+M5"0@B50D$(E,)`B)7"0$QP0DP`0``.C\____@'T>`'0HNP`````/ML.+1(4X
+MA<!T$(E$)`B)?"0$B30DZ/S___^#PP$X71YWW6:#32X"QD4F`(M%3,9`!?^+
+M14R)1"0$B30DZ/S____IK@,``(VT)@`````/MD4F@^@-N@````"Y`````#P!
+M=G*+ENP&``"!PD`(```/MD4PP>`(`<*+`J,`````BY;L!@``@<)$"```#[9%
+M,,'@"`'"BPJ)#0````"+ENP&``"!PD@(```/MD4PP>`(`<*+`J,`````BY;L
+M!@``@<),"```#[9%,,'@"`'"BQ*)%0`````/MD4F/`X/AQ0#```/ML#_)(6(
+M````@_H%=P6(51[K!,9%'@7&128"D.F[`@``B<C!X`@/MM()T&:)12")R,'H
+M"&:)12+&128#Z9L"``"(31SVP@AT!L9%'0SK(?;"!'0*QD4="XUT)@#K$HG0
+M@^`"@_@!&<#WT(/@"HA%'<9%)@3I8P(``(G0@\@(B$4JQD4F!>E2`@``QD4F
+M!NE)`@``QD4F!^E``@``#[9%*8/``8A%*3I%'G-3BTPD1(-Y3`!T$8G(@\!,
+MB40D!(DT).C\____BUPD1(E<)`2)-"3H_/___\=%:("$'@#'17``````B6UT
+MC45HBU84B40D!(D4).C\____Z14"``#&12D`C5UHBT84B5PD!(D$).C\____
+MBT0D1(E$)`2)-"3H_/___\=%:$!"#P#'17``````B6UTBT84B5PD!(D$).C\
+M____Z<H!```/MD4I@\`!B$4I.D4>#X6``0``QD4I`,9%*V3&128+Z6\!``#&
+M128*Z68!``#&128+Z5T!``"+14R+0!B!8"C___?_B="#X`^#^`-U"<9%)@SI
+M/0$```^V12N$P'07@^@!B$4KQP0DZ`,``.C\____Z1X!```/MD4I@\`!B$4I
+M.D4>#X(+`0``QD4I`,9%)AGI_@````^V12F+1(4XA<!T%HG!@&`H[XL0BT`$
+MB4($B1"`;PD!ZSZ)-"3H_/___XG!A<!U,(M4)$2#>DP`=!&)T(/`3(E$)`2)
+M-"3H_/___XM,)$2)3"0$B30DZ/S____IU0```,9%)@T/MD4IB4R%.(EY+(EI
+M,`^V12F(047&024`@$DD!8!'"0&-1RB+4`2)2`2)`8E1!(D*ZV>-76B+1A2)
+M7"0$B00DZ/S____'16A0PP``QT5P`````(EM=(M&%(E<)`2)!"3H_/___XM<
+M)$2#>TP`=!&)V(/`3(E$)`2)-"3H_/___XM$)$2)1"0$B30DZ/S____K/\9%
+M)@^-="8`BU0D1(-Z3`!T$8G0@\!,B40D!(DT).C\____BTPD1(E,)`2)-"3H
+M_/___XEL)`2)-"3H_/___X/$+%M>7UW#D(/A!\'A"(#-((M`!"WD/```#[;2
+MP>((`=")"`^W`&:C``````^VP,.0C;0F`````(/A!\'A"(I,)`2`S1"+0`0M
+MY#P```^VTL'B"`'0B0C#55=64X/L"(G'QD0D`@#&1"0#`+W_____QT0D!```
+M```/MD0D!(A$)`&#1"0$`;@!````B<8/MDPD!-/FB?&[`````+C`X>0`N@``
+M``#W\3GX=QV)^BG"B=`YZG,3#[94)`&(5"0"B%PD`XG%C70F`(/#`0'Q@_L0
+M=<F#?"0$"'6?#[9$)`/!X`,*1"0"#[;`@\0(6UY?7<.0C;0F`````(/L#(E<
+M)`2)="0(BUPD$`^V="04QP0D`````+D'````B?*)V.@7____#[:#T0<``(D$
+M)+D#````B?*)V.C__O__BUPD!(MT)`B#Q`S#C78`4XG3#[;1N0,```#HL/[_
+M_SC8#Y3`#[;`6\.-M@````!3BUPD"(7;="^Z`````(GV#[:$&I@$```/ML@\
+M_W01#[?!:<"4`````X/P!```ZPV#P@&#^@1UV+@`````6\.05E.#[`2+1"00
+MBYBD!```A=MU`HG#O@````#'!"0`````N0<```")\HG8Z&'^___'!"1$````
+MN0(```")\HG8Z$S^___'!"30````N0````")\HG8Z#?^___'!"0`````N00`
+M``")\HG8Z"+^__^#Q@&#_@)UI+B@A@$`Z##^__^(@]$'```/ML")!"2Y`P``
+M`+H`````B=CH\_W__X/$!%M>PXVV`````(V\)P````!3@^P(BUPD$&;'@X@`
+M```!``^W1"04P>`-B40D!(D<).C\____QT0D!!0```")'"3H_/___X/$"%O#
+MC;8`````@^P,BU0D$`^V3"04@'PD&`!U$+C^____T\!F(8*`````ZPZX`0``
+M`-/@9@F"@`````^W@H````")1"0$B10DZ/S___^#Q`S#D(VT)@````"#[!R)
+M7"00B70D%(E\)!B+1"0D#[9\)"@/MK"7````#[98`HM0:(72=!B)^0^VP8E$
+M)`@/ML.)1"0$B10DZ/S___^`^P-W#XT4LXGP/`-V$XU4LP3K#8GQC580@/D#
+M=@.-5B")^0^VP8E$)`@/ML*)1"0$BT0D((D$).C\____BUPD$(MT)!2+?"08
+M@\0<PY!75E.#[!")Q[L`````#[;RN0(```")\HGXZ'+\__^H"'0.N`````#K
+M(XVT)@````#'!"0!````Z/S___^#PP&!^Q`G``!UR;C_````@\006UY?PXVV
+M`````(V\)P````"#[`R)'"2)="0$B7PD"(G&B<\/MMJ)VNB$____A<!U,(GX
+M#[;0B=F)\.A"_?__A<!T'KD!````B=J)\.CP^___BU0D$(@"N`````#K"(UV
+M`+C_____BQPDBW0D!(M\)`B#Q`S#C;8`````C;\`````@^P<B5PD$(ET)!2)
+M?"08B<8/MOD/MMJ)/"2Y`0```(G:Z,K[___'!"1`````N0(```")VHGPZ+7[
+M__^)VHGPZ.S^__^%P'5.@WPD(`!T-??'`0```'09B=FZ0````(GPZ)O\__^%
+MP'0MZS*0C70F`(G9NA@```")\.B"_/__A<!T%.L9B=FZ*````(GPZ&[\__^%
+MP'4'N/\```#K!;@`````BUPD$(MT)!2+?"08@\0<PXVT)@````"-O"<`````
+M55=64X/L'(G'BVPD-(G3B<Z$R0^$#P$```^VVHE<)!C'!"1D````N0(```")
+MVHGXZ/OZ__^+5"08B?CH,/[__X7`=1"Y`P```(M4)!B)^.BL^O__B?`/MLC'
+M!"0!````BU0D&(GXZ-7^__^^_____X3`#X6H`0``O@````"%[0^.FP$``+L`
+M````C47_B40D%(M$)#`#1"04B40D$(MT)!0YWG4[QP0D0````+D"````BU0D
+M&(GXZ'3Z__^+1"00B00DN5@```"+5"08B?CH_?W__X7`=$'I1`$``(UT)@#'
+M!"1$````N0(```"+5"08B?CH.?K__XM$)#`!V(D$)+E0````BU0D&(GXZ,#]
+M__^%P`^%_P```(/#`3GK#X3T````Z77___^XH(8!`(UV`.@;^O__#[;;#[;`
+MB00DN0,```")VHGXZ.3Y__^)VHGXZ!O]__^%P'0G#[:'T0<``(D$)+D#````
+MB=J)^.B_^?__OO_____II0```)"-="8`B=FZ8````(GXZ++Z__^%P'00O@``
+M``"%[7YBD(UT)@#K'P^VA]$'``")!"2Y`P```(G:B?CH=OG__[[_____ZU^^
+M`````,<$)$0```"Y`@```(G:B?CH5?G__XM$)#`!\(D$)+F`````B=J)^.C>
+M_/__A<!U!X/&`3GN=<D/MH?1!P``B00DN0,```")VHGXZ!OY___K"8G>C;0F
+M`````(GP@\0<6UY?7<.-M@````"#[!R)7"04B70D&(MT)"`/MDPD)(M$)"R)
+M1"0$BT0D*(D$)+H!````B?#HH?W__XG#QP0D5````+D"````N@$```")\.BW
+M^/__B=B+7"04BW0D&(/$',.)]HV\)P````"#[!R)7"04B70D&(MT)"`/MDPD
+M)(M$)"R)1"0$BT0D*(D$)+H`````B?#H0?W__XG#QP0D5````+D"````N@``
+M``")\.A7^/__B=B+7"04BW0D&(/$',.)]HV\)P````!55U93@^P,B<>+;"0D
+MB<L/MO+'!"1D````N0(```")\N@;^/__B?*)^.A2^___A<!U#KD#````B?*)
+M^.C0]___#[;+QP0D`0```(GRB?CH_?O__X3`=2Z%[7XQNP````"+1"0@#[8,
+M`\<$)`````")\HGXZ-C[__^$P'4)@\,!.>MT">O;N/_____K!;@`````@\0,
+M6UY?7<.-M"8`````@^P<B5PD%(ET)!B+="0@#[9,)"2+1"0LB40D!(M$)"B)
+M!"2Z`````(GPZ#'___^)P\<$)%0```"Y`@```+H`````B?#H5_?__XG8BUPD
+M%(MT)!B#Q!S#B?:-O"<`````@^P<BTPD(`^V5"0DBX&D!```A<!U`HG(B!4@
+M````QT0D#"````#'1"0((````,=$)`0.````B00DZ/S___^#Q!S#C;0F````
+M`(V\)P````"#[`R+5"00#[9,)!2`?"08`'00N`$```#3X&8)@G`)``#K#KC^
+M____T\!F(8)P"0``#[:"<`D``(E$)`2)%"3H_/___X/$#,.0C;0F`````%57
+M5E.#[!R+1"0TBT@8@\$!BU`0@^H!B50D$(M`'(E$)!@/MD$!/`%U&(M4)#3'
+M0BP`````QT0D%`````#IB`(``#P"=6"`>0(!=4*+5"0PBX*D!```A<!U`HG0
+MBX"@!```#[91`XB0<@D```^V40.(D/82``"+1"0TQT`L`````,=$)!0`````
+MZ3P"``"+5"0TQT(L_O___\=$)!0`````Z20"```\`P^%S0```(!Y`@$/A:L`
+M``"+5"0P#[9")HTT``^V60.)VHG8P?H?]_Z)TSG6?G6->00/MO(/MD$$B40D
+M"(ET)`2+1"0PB00DZ/S___^-0_R#^`-V&(U#](/X`W80C4/L@_@#=@B-0^2#
+M^`-W"(%$)#"$"0``#[8'B40D"(ET)`2+5"0PB10DZ/S___^+1"0TQT`L````
+M`,=$)!0`````Z7\!``"+5"0TQT(L_O___\=$)!0`````Z6<!``"+1"0TQT`L
+M_O___\=$)!0`````Z4\!``"+5"0PBZJD!```A>UU`HG5B<O'1"04`````+@"
+M````*<B)1"0,Z9(````/MC.->@$/MLCVP0%T/XM$)!2-'`:+5"0T.UH4#X?@
+M````B70D!(M$)!@#1"04B00DN@````")Z.B.^?__.?`/A;T```")7"04B?OK
+M18T<-XM$)`P!V#M$)!`/CZ(```")="0$B3PDN@````")Z.A(_/__A<`/A8<`
+M``"`.P!U!H![`0!T#,<$)!`G``#H_/___XU3`0^V0P&$P`^%7____XMT)!0/
+MM@.$P'1A#[;8QP0D5````+D"````N@````")Z.@T]/__BU0D-(M"%"M$)!0Y
+MPW8"B<.)7"0$BT0D&`'PB00DN0````"Z`````(GHZ-7X__^%P'@(`?")1"04
+MZPN+1"0TQT`L_____\<$)%0```"Y`@```+H`````B>CHUO/__XM4)#2+0B"%
+MP'0&BU0D%(D0BT0D-(D$)/]0*(/$'%M>7UW#C78`@^P<BU0D((N"I`0``(7`
+M=0*)T(N0H`0```^V@G,)``"$P'0-@^@!B()S"0``A,!U)\8%(P````#'1"0,
+M(````,=$)`@@````QT0D!`X```")%"3H_/___X/$',.-="8`@^P<BU0D((N"
+MI`0``(7`=0*)T(N`H`0``("X<@D```!U+H"`<PD```'&!2,````!QT0D#"``
+M``#'1"0((````,=$)`0.````B00DZ/S___^#Q!S#C;8`````C;\`````@^P<
+MB5PD%(ET)!B+="0@#[9,)"2+1"0LB40D!(M$)"B)!"2Z`````(GPZ('Z__^)
+MP\<$)%0```"Y`@```+H`````B?#HI_+__XG8BUPD%(MT)!B#Q!S#D)"0D)"0
+MD)"0BT0D!(M`!"T``@$``T0D"(L`HP````##D(VT)@````"+1"0$BT`$+0`"
+M`0`#1"0(BU0D#(D0PXGVC;PG`````%.#[`R+7"04BU,$@>H``@$`QX*```$`
+M`````(N"!`$!`*,`````@,P!B8($`0$`QT0D"`@```#'1"0$#,(``(D<).C\
+M____QT0D"+@+``#'1"0$",(``(D<).C\____QT0D"`$``#S'1"0$`,(``(D<
+M).C\____QT0D"`@```#'1"0$#,,``(D<).C\____QT0D"+@+``#'1"0$",,`
+M`(D<).C\____QT0D"`$``#S'1"0$`,,``(D<).C\____QT0D"("`@(#'1"0$
+M.,(``(D<).C\____QT0D"`@8*#C'1"0$(,(``(D<).C\____QT0D"("`@(#'
+M1"0$/,(``(D<).C\____QT0D"`D9*3G'1"0$),(``(D<).C\____QT0D"("`
+M@(#'1"0$0,(``(D<).C\____QT0D"`H:*CK'1"0$*,(``(D<).C\____QT0D
+M"("`@(#'1"0$1,(``(D<).C\____QT0D"`L;*SO'1"0$+,(``(D<).C\____
+MQT0D"("`@(#'1"0$2,(``(D<).C\____QT0D"$A)2DO'1"0$,,(``(D<).C\
+M____QT0D"("`@(#'1"0$.,,``(D<).C\____QT0D"`P<+#S'1"0$(,,``(D<
+M).C\____QT0D"("`@(#'1"0$/,,``(D<).C\____QT0D"`T=+3W'1"0$),,`
+M`(D<).C\____QT0D"("`@(#'1"0$0,,``(D<).C\____QT0D"`X>+C['1"0$
+M*,,``(D<).C\____QT0D"("`@(#'1"0$1,,``(D<).C\____QT0D"`\?+S_'
+M1"0$+,,``(D<).C\____QT0D"("`@(#'1"0$2,,``(D<).C\____QT0D"$Q-
+M3D_'1"0$,,,``(D<).C\____QT,X@("`@,=#/("`@(#'0T"`@("`QT-$@("`
+M@,=#2("`@("!PX0)``#'0SB`@("`QT,\@("`@,=#0("`@(#'0T2`@("`QT-(
+M@("`@(/$#%O#BT0D!(M0!('J``(!`(N";``!`*,`````B8)L``$`PY"+1"0$
+MBU`$@>H``@$`BX)H``$`HP`````+1"0(B8)H``$`PXVV`````(V\)P````"#
+M["")7"00B70D%(E\)!B);"0<BW0D)`^V5"0H#[9\)"PYMJ`$```/A0@!``")
+MT,#H`KT`````#[;`B40D#(G0]]"#X`.-',4`````N`<```")V=/@]]"+3"0,
+MBU2.."'"B52..(GXA,!T$[@!````B=G3X`G0BU0D#(E$ECB)Z0^VV<'C"(M&
+M.(E$)`B-@SC"``")1"0$BX:@!```B00DZ/S___^+1CR)1"0(C8,\P@``B40D
+M!(N&H`0``(D$).C\____BT9`B40D"(V#0,(``(E$)`2+AJ`$``")!"3H_/__
+M_XM&1(E$)`B-@T3"``")1"0$BX:@!```B00DZ/S___^+1DB)1"0(@<-(P@``
+MB5PD!(N&H`0``(D$).C\____BUPD$(MT)!2+?"08BVPD'(/$(,.)T,#H`H/H
+M!;T!````Z?#^__^0D)"0D)"0D)"#[!")'"2)="0$B7PD"(EL)`R+3"04BW0D
+M&(M4)!R+7"0@B[G4!```#[=&$+TDVP``9CV#`'<1#[?`#[:$`1@$``!IZ-P`
+M``"-BB`$``#&@B`$```G9H%^).$!=2,/ME8FC4+_/`%W"0^V5B>#X@_K)(U"
+M[[H/````/`%V&(UV`(T$+[H`````@W@P`'0'#[9018/B#P^V00&#X/`)T(A!
+M`;@!````9H%^).$!=1(/MD8F@^@!/`$/E\`/ML"-=@")PL'B!P^V00&#X'\)
+MT(A!`0^V0P:(00(/M@.(00,/MD,%B$$'#[9#!XA!#P^V0P*(000/MD,#B$$%
+M#[9#!(A!!@^V0P&(00P/MD,*B$$(#[9#"XA!"0^V0PR(00H/MD,(B$$+#[9#
+M"8A!#8L<)(MT)`2+?"0(BVPD#(/$$,.)]E.+5"0(BUPD$,9"%`*+2CB+1"0,
+MB$$"BT(XQD`'`(M".(A8#%O#C78`C;PG`````(M4)`2+3"0(#[9"*8A!`@^V
+M0BB(00,/MD(GB$$$#[9")HA!"L.-="8`C;PG`````(M4)`2+3"0(#[9"+8A!
+M`@^V0BR(00,/MD(KB$$$#[9"*HA!"@^V0BF(00L/MD(HB$$,PXVV`````(V\
+M)P````"+3"0,A<E^';H`````C78`B<@IT(/X`@^=P`^VP(U4`@$YT7_K\\.)
+M]HV\)P````"#[!B)7"0(B70D#(E\)!");"04BUPD'(M\)"0/MD,D/"IT'SPJ
+M=PL\*`^%H0```)#K$#R(="(\B@^%D@```(GVZQ8/MG,L#[9K*XE\)`2)'"3H
+M_/___^L4#[9S,0^V:S")?"0$B1PDZ/S____&1P5`BT-DJ0```0!U5JD```0`
+M="6)\(A'`8GHB$<)#[9#)#PH=`0\B'4)QD<&)>LSC78`QD<&->LJB?"(1P$/
+MMD,F@^`/"$<%#[9#)#PH=`0\B'4&QD<&R.L)QD<&RI"-="8`BUPD"(MT)`R+
+M?"00BVPD%(/$&,.-M@````"-OP````"#[`R+3"00#[9!)@I!)PI!*`I!*0^V
+MP`^V42R#X@$)T'0>QT0D""0```#'1"0$!0```(D,).C\____ZQ.-="8`BT0D
+M%,9`!NS'06P`````@\0,PXVV`````(V\)P````"#[!B)7"0(B70D#(E\)!")
+M;"04BUPD'(MT)"`/MD,D/"]T#3R/=6#K'8VT)@`````/MGLL#[9K*XET)`2)
+M'"3H_/___^L4#[9[,0^V:S")="0$B1PDZ/S____&1@5`]D-F!'00B?B(1@&)
+MZ(A&"<9&!D+K$XGXB$8!#[9#)H/@#PA&!<9&!D"+7"0(BW0D#(M\)!"+;"04
+M@\08PY"-="8`4X/L#(M,)!B+5"0<QD(%0`^V020\-70(/)%U*NLBB?:+7"04
+M#[=#-(/@`8/X`1G`@^#]@^@6B$(&ZR60C70F`,9"!NKK&L=$)`@D````QT0D
+M!`4```")#"3H_/___^L*]D$E`G0$QD$4`(/$#%N)]L/K#9"0D)"0D)"0D)"0
+MD)"#[`R+1"00]D`H\'08QT0D""0```#'1"0$!0```(D$).C\____@\0,PXVT
+M)@````!3@^P0BUPD'(M,)"0/MD0D(+H`````Q@0*`(/"`8/Z#77T#[93)(#Z
+M-0^$KP```(#Z-7<T@/HH=&R`^BB-="8`=Q.`^AL/A84#``"0C70F`.FJ````
+M@/HJ=$N`^B^-=@`/A6H#``#K78#ZCY"-="8`=%.`^H]W$8#ZB'0I@/J*D`^%
+M2@,``.L=@/J1D(UT)@!T3(#ZX0^%-0,``)"-="8`Z9(```")3"0(#[;`B40D
+M!(D<).C\____QT0D#`$```#I$P,``(E,)`2)'"3H_/___\=$)`P!````Z?H"
+M``")3"0(B5PD!(M$)!B)!"3H_/___\=$)`P!````Z=D"``#V0R@!="'&009P
+MQD$$`,9!`P#&00(`QD$%0,=$)`P!````Z;("``#&00;@QT0D#`$```#IH0(`
+M`(![)0$/A8\"``"`>R8<#X>%`@``#[9#)I#_)(7$````QD$'!,=$)`P!````
+MZ7`"``#&00<`QT0D#`$```#I7P(``,9!!NS'1"0,`0```.E.`@``QD$&[\8!
+M`P^V0R>#R$"(00''1"0,`0```.DP`@``QD$&[\8!!\=$)`P!````Z1P"``#&
+M009`QD$!`<9!!4#'1"0,`0```.D#`@``QD$&[\8!`P^V0R>#R`B(00''1"0,
+M`0```.GE`0``QD$&[\8!`L=$)`P!````Z=$!``#&00;OQ@&"QT0D#`$```#I
+MO0$``,9!!N_&`0;'1"0,`0```.FI`0``QD$&[\8!AL=$)`P!````Z94!``#&
+M00;C#[9#)XA!`<=$)`P!````Z7T!``#&00:PQ@'8QD$#3\9!!,+'1"0,`0``
+M`.EA`0``QD$&L,8!V<9!`T_&003"QT0D#`$```#I10$``,9!!K#&`=K&00-/
+MQD$$PL=$)`P!````Z2D!``"+1"08]D`T`701QD$&ZL=$)`P!````Z0X!``#&
+M00;GQT0D#`$```#I_0```,9!!N_&`:K'1"0,`0```.GI````QD$&[\8!5<=$
+M)`P!````Z=4```#&00;D#[9#*(@!#[9#*8A!"`^V0R>(007'1"0,`0```.FP
+M````#[9#)XA!!@^V0RB(`0^V0RF(00(/MD,JB$$##[9#*XA!!`^V0RV(00H/
+MMD,LB$$!QT0D#`$```#K=L9!!N@/MD,HB`$/MD,IB$$(#[9#)XA!!0^V0RJ(
+M00(/MD,KB$$##[9#+(A!!`^V0RV(00''1"0,`0```.LXQT0D#`$```#V0R@!
+M="K&009PQD$$`,9!`P#&00(`QD$%0,=$)`P!````ZPR-="8`QT0D#`````"+
+M1"0,@\006\/K#9"0D)"0D)"0D)"0D)"#[#R)7"0LB70D,(E\)#2);"0XBVPD
+M1(MU-(U\)`S\N0@```"X`````/.K]H:G````!'04BX[(````BY[,````@\'_
+M@]/_ZPV+1GB#Z`&)P;L`````@'TD)75GB<@/K-@8B$0D#(G(#ZS8$(A$)`V)
+MR`^LV`B(1"0.B$PD#_:&U0```!!U%,9$)!("QD0D$P"Y"````.FI````C50D
+M$,=$)`@$````C8;J````B40D!(D4).C\____N0@```#I@0```(G8P>@8B$0D
+M#(G8P>@0B$0D#8G8P>@(B$0D#HA<)`^)R`^LV!B(1"00B<@/K-@0B$0D$8G(
+M#ZS8"(A$)!*(3"03]H;5````$'44QD0D%@+&1"07`+D@````ZR:-=@"-5"04
+MQT0D"`0```"-ANH```")1"0$B10DZ/S___^Y(````(M5-(U$)`R)3"0(B40D
+M!(D4).C\____BUPD+(MT)#"+?"0TBVPD.(/$/,.)]H/L#(M4)!0/MD(D/#4/
+MA(\````\-7<K/"AT33PHC78`=Q`\$G1"/!L/A9(```")]NMP/"IT,CPO#X6"
+M````B?;K)CR/="(\CW<./(B-="8`=!8\BG5JZQ`\L(VV`````'1U/.%U6NL:
+MBT0D$/9`-`%T98%*9```!`"X`0```(GVZUJ`>B4!=4B`>B8<=T(/ODHFN`$`
+M``#3X*G^/\8==3?K+HM$)!#V0#0!="N!2F0```0`N`$```#K(HVV`````(D4
+M).C\____N`````#K#9"X`````.L%N`$```"#Q`R0PY"0D)"0D)"0D)"0D)"0
+MD(/L"(D<)(ET)`2)TXMT)!2+4`0/MD0D$,'@!`^VR<'A"`G!@'PD#`!T`X/)
+M!(/^_W00B?`E__\#`(F"!,;__X/)`HD+BQPDBW0D!(/$",.0BT`$+0`"`0"#
+MR@&)D`#(``##C;0F`````(V\)P````!75E.#[!")UXM`!(72=$J-L`#&__^+
+M@`#&__^C`````+L`````J`%U$NLGD(UT)@"+!J,`````J`%T%\<$)`H```#H
+M_/___X/#`3G[=>*)]NL'N`````#K!;C_____@\006UY?PXUT)@"-O"<`````
+M5E.#["2+7"0PQT0D(`````"+<P3&@W0)````#[8-"````(U4)"#'1"0(````
+M`,=$)`0"````QP0D`0```(G8Z-S^__^+5"0@B=CH(?___[J@A@$`B=CH-?__
+M_X7`=4>+A@S&__^C`````(E$)"`]'V,``'4QQX-D"0``'V,``,>#:`D`````
+M!`#'@VP)``````$`QX-X"0```````&:X``#I.@(``,=$)"``````BW,$QH-T
+M"0```0^V#1@```"-5"0@QT0D"/_____'1"0$`@```,<$)`$```")V.@__O__
+MBU0D((G8Z(3^__^Z$"<``(G8Z)C^__^%P'5GBX8,QO__HP````")1"0@/1]#
+M``!T+CT?1```=4K'@V0)```?1```QX-H"0`````'`,>#;`D``````0#IA`$`
+M`(UT)@#'@V0)```?0P``QX-H"0`````$`,>#;`D``````0#I70$``,=$)"``
+M````BW,$QH-T"0````^V#2@```"-5"0@QT0D"`````#'1"0$`@```,<$)`$`
+M``")V.B"_?__BU0D((G8Z,?]__^Z$"<``(G8Z-O]__^%P'5'BX8,QO__HP``
+M``")1"0@/;]#``!U,<>#9`D``+]#``#'@V@)`````"``QX-L"0```!```,>#
+M>`D``"````!FN```Z>````#'1"0@`````(MS!,:#=`D````/M@TX````C50D
+M(,=$)`@`````QT0D!`(```#'!"0!````B=CHY?S__XM4)"")V.@J_?__NA`G
+M``")V.@^_?__A<!U7XN&#,;__Z,`````B40D(#WO$0``=`D][Q(``'5"ZR#'
+M@V0)``#O$0``QX-H"0`````$`,>#;`D``````0#K/,>#9`D``.\2``#'@V@)
+M``````@`QX-L"0`````!`.L<N/_____K)(UT)@#'@W@)```0````N`````#K
+M#\>#>`D``#````"X`````(/$)%M>PXUV`(V\)P````"#[#R)7"0LB70D,(E\
+M)#2);"0XB<:)UXE,)!B+:`0/MD0D0#P$=@6X!`````^VV(N&>`D```^V2`2-
+M5"0HB7PD"(E<)`3'!"0!````B?#HW?O__XM4)"B)\.@B_/__NA`G``")\.@V
+M_/__NO____^%P'4:BX4,QO__HP````")1"0HBU0D&(D"N@````")T(M<)"R+
+M="0PBWPD-(ML)#B#Q#S#C;8`````C;PG`````%.#["B+7"0PBX-X"0``#[9(
+M"XU4)"2+1"0TB40D",=$)`0!````QP0D`0```(G8Z$S[__^+5"0DB=CHD?O_
+M_[H0)P``B=CHI?O__[K_____A<!U&HM#!"WT.0``BP"C`````(M4)#B(`KH`
+M````B="#Q"A;PXUT)@"-O"<`````55=64X/L+(G#B%0D&XG-@WPD0``/A),`
+M``"^`````)"+>P2+@W@)```/MD@"QT0D"/_____'1"0$`0```,<$)`$```"-
+M5"0HB=CHL?K__XM4)"B)V.CV^O__NA`G``")V.@*^___A<!U*HN7#,;__XD5
+M``````^V1"0;(=")Z3C(=0VX`````.LHC;8`````B50D*,<$)`H```#H_/__
+M_X/&`3MT)$`/A7/___^X_____X/$+%M>7UW#C;8`````4X/L*(G#BX!X"0``
+M#[8(C50D),=$)`C_____QT0D!`````#'!"0`````B=CH#_K__XM4)"2)V.A4
+M^O__NA`G``")V.AH^O__A<!U),<$)."3!`"Y`@```+H#````B=CHW/[__[H`
+M````A<!T"(UV`+K_____B="#Q"A;PXUT)@"#["R)7"0DB70D*(M<)#"+="0T
+MQD0D(_^-1"0CB40D"(ET)`2)'"3H_/___X7`=7*`?"0C`'1YB=CH0O___X/X
+M_W1?BX-X"0``#[9("HU4)!R)="0(QT0D!`````#'!"0`````B=CH5?G__XM4
+M)!R)V.B:^?__NA`G``")V.BN^?__A<!U',<$)."3!`"Y`````+H#````B=CH
+M(O[__X7`=`ZX_____^L,C;0F`````+@`````BUPD)(MT)"B#Q"S#ZPV0D)"0
+MD)"0D)"0D)"055=64X/L/(ML)%`/MD0D8(.]>`D````/A!H#``"+?"18A,`/
+MA&L!``"#?"14_W44#[>%9`D``&:)![@!````Z1P#``"#?"14_G45BX5H"0``
+MB0>X`0```.D#`P``C78`@WPD5/UU&8N%;`D``(D'N`$```#IYP(``(VT)@``
+M``"+1"1<`T0D5(E$)!@[A6@)```/AY\"``"+7"14@^/\BU0D5(/B`XE4)"!T
+M;HUT)#C'!"0$````B?&)VHGHZ/[[__^#PP3'1"0<!````#E<)!AS$(M$)"`K
+M1"14`T0D&(E$)!R+1"0@.40D''8MC0P&B?Z+1"0<C50$.(VV``````^V`8@&
+M@\8!@\$!.=%U\8M$)!PK1"0@C3P'BW0D&(/F_#GS<R3'!"0$````C4PD.(G:
+MB>CHA_O__XM$)#B)!X/'!(/#!#G>=]PY7"08#X;M`0``C70D.,<$)`0```")
+M\8G:B>CH5_O__XM,)!@IV0^$RP$``+H`````C;8`````#[8$%H@$.H/"`3G*
+M#X2N`0``Z^R#?"14_W4I@#\/B?9U$<:%=0D```&X`0```.FM`0``QH5U"0``
+M`+@!````Z9P!``"+5"1<B50D*(G0`T0D5#N%:`D```^'60$``("]=0D````/
+MA$P!``"+1"14N@````#WM6P)``"%T@^%G````("]=`D```!T&(M$)%2)1"0$
+MB2PDZ/S___^%P`^%%`$``(GHZ(;\__^#^/\/A`0!``"+A7@)```/MD@&C50D
+M.(M$)%2)1"0(QT0D!`````#'!"0`````B>CHD?;__XM4)#B)Z.C6]O__NA`G
+M``")Z.CJ]O__A<`/A;D```#'!"3@DP0`N0````"Z`P```(GHZ%K[__^%P`^%
+MF0```(-\)%P`#X27````QT0D)`````"+5"18BT0D)(LT`HG'`WPD5(M=!('K
+M``(!`(GHZ-[[__^)LPC(``"+A7@)```/MD@%B7PD",=$)`0$````QP0D````
+M`(U4)#B)Z.CP]?__BU0D.(GHZ#7V__^Z$"<``(GHZ$GV__^%P'4<QP0DB!,`
+M`+D`````N@$```")Z.B]^O__A<!T$+@`````ZR*)]K@!````ZQF#1"0D!(M4
+M)"0Y5"0H=NKI5O___Y"-="8`@\0\6UY?7<.0D)"0D)"0D+@`````PXUV`(V\
+M)P````"+5"0$BTPD"+@`````.15\`0``?C2-%%+!X@,/MX(<`0``9HD!#[>"
+M'@$``&:)00(/MH(D`0``B$$(#[:")0$``(A!";@!````\\.0C70F`+@(%0``
+MPXUV`(V\)P````"XG````,.-=@"-O"<`````N`0```##C78`C;PG`````//#
+MC;0F`````(V\)P````"+1"0$QH"6`````(M$)`C&0'``PXVV`````(V_````
+M`(M4)`2%TG01BT)HA<!T"@^V@)````"(0@'SPY"-="8`5E.#[`2+="00A?9T
+M:KL`````#[:$,Q@$```\_W0W#[;`:<#<````B<(#EM0$``!T)(M")"4`__\`
+M/0``_P!U%?9")P1T#XM"((7`=`B)!"3H_/___X/#`8'[@````'6RBX:@!```
+M.?!U#06$"0``B00DZ/S___^#Q`1;7L.-=@"X`````,.-=@"-O"<`````N```
+M``##C78`C;PG`````+C_____PXUV`(V\)P````"X_____\.-=@"-O"<`````
+MN/_____#C78`C;PG`````+C_____PXUV`(V\)P````"+1"0,QT`$`````,<`
+M`````+@`````PXGVC;PG`````(M,)`2+062%P'1#QT`@`````(!(*`3'060`
+M````QT%H`````(M1"(/Z/W\4BT%LQX20&`(```````##D(UT)@"+06S'A)`8
+M`0```````//#BTPD!(M!9(7`=$/'0"``````@&`H^\=!9`````#'06@`````
+MBU$(@_H_?Q2+06S'A)`8`@```````,.0C70F`(M!;,>$D!@!````````\\.#
+M[`S'!"2`````Z/S___^X`````(/$#,.0C;0F`````%=64X/L0(M$)%#&1"08
+M;<9$)!G_QD0D&B/&1"0;%,9$)!PZQD0D'>_&1"0>%L9$)!^2B["D!```A?9U
+M`HG&C40D((G"Q@``@\`!B=.-3"1`.<AU\,9$)"0!QT0D#"````")5"0(QT0D
+M!`X```")-"3H_/___X7`=4S'!"2`&@8`Z/S____'1"0,(````(E<)`C'1"0$
+M#P```(DT).C\____@_@@=1^-="0PC7PD&+D(````_/.F#Y?"#Y+`N0$````X
+MPG01QP0DA0```.C\____N0`````/ML&#Q$!;7E_#5E.#[&2+="1PBYZ@!```
+M@<.$"0``BP:%P'06+0```@")!HE$)`2+1A")!"3H_/___XM&"(7`=`^)1"0$
+MBT80B00DZ/S___^+1@R%P'0/B40D!(M&$(D$).C\____C40D5HE$)#2-1"18
+MB40D,(U$)%*)1"0LC40D5(E$)"B-1"1<B40D)(U$)%Z)1"0@C40D7XE$)!R-
+M1"1:B40D&(U$)&")1"04C40D4(E$)!"-1"1AB40D#(U$)&*)1"0(C40D8XE$
+M)`0/MT8DB00DZ/S___^+AM0$``"%P'0JB40D!(V&O`0``(D$).C\____BX/4
+M!```B40D!(V#O`0``(D$).C\____BX;P!```A<!T*HE$)`2-AM@$``")!"3H
+M_/___XN#\`0``(E$)`2-@]@$``")!"3H_/___XN&>`8``(7`="J)1"0$C89@
+M!@``B00DZ/S___^+@W@&``")1"0$C8-@!@``B00DZ/S___^+A@P%``"%P'0J
+MB40D!(V&]`0``(D$).C\____BX,,!0``B40D!(V#]`0``(D$).C\____BX:X
+M!0``A<!T*HE$)`2-AJ`%``")!"3H_/___XN#N`4``(E$)`2-@Z`%``")!"3H
+M_/___XN&:`4``(7`="J)1"0$C890!0``B00DZ/S___^+@V@%``")1"0$C8-0
+M!0``B00DZ/S___^+AH0%``"%P'0JB40D!(V&;`4``(D$).C\____BX.$!0``
+MB40D!(V#;`4``(D$).C\____BX;4!0``A<!T*HE$)`2-AKP%``")!"3H_/__
+M_XN#U`4``(E$)`2-@[P%``")!"3H_/___XN&\`4``(7`="J)1"0$C8;8!0``
+MB00DZ/S___^+@_`%``")1"0$C8/8!0``B00DZ/S___^+A@P&``"%P'0JB40D
+M!(V&]`4``(D$).C\____BX,,!@``B40D!(V#]`4``(D$).C\____BX8H!@``
+MA<!T*HE$)`2-AA`&``")!"3H_/___XN#*`8``(E$)`2-@Q`&``")!"3H_/__
+M_XN&4`8``(7`="J)1"0$C88X!@``B00DZ/S___^+@U`&``")1"0$C8,X!@``
+MB00DZ/S___^+AJ`&``"%P'0JB40D!(V&B`8``(D$).C\____BX.@!@``B40D
+M!(V#B`8``(D$).C\____BX[(!@``A<ET4HN&S`8``(N6T`8``(E$)`B)5"0,
+MB4PD!(V&L`8``(D$).C\____BX/,!@``BY/0!@``B40D"(E4)`R+@\@&``")
+M1"0$C8.P!@``B00DZ/S___^+CNP&``"%R712BX;P!@``BY;T!@``B40D"(E4
+M)`R)3"0$C8;4!@``B00DZ/S___^+@_`&``"+D_0&``")1"0(B50D#(N#[`8`
+M`(E$)`2-@]0&``")!"3H_/___XN.$`<``(7)=%*+AA0'``"+EA@'``")1"0(
+MB50D#(E,)`2-AO@&``")!"3H_/___XN#%`<``(N3&`<``(E$)`B)5"0,BX,0
+M!P``B40D!(V#^`8``(D$).C\____BXY8!P``A<ET4HN&7`<``(N68`<``(E$
+M)`B)5"0,B4PD!(V&0`<``(D$).C\____BX-<!P``BY-@!P``B40D"(E4)`R+
+M@U@'``")1"0$C8-`!P``B00DZ/S___^+CC0'``"%R712BX8X!P``BY8\!P``
+MB40D"(E4)`R)3"0$C88<!P``B00DZ/S___^+@S@'``"+DSP'``")1"0(B50D
+M#(N#-`<``(E$)`2-@QP'``")!"3H_/___XN.?`<``(7)=%*+AH`'``"+EH0'
+M``")1"0(B50D#(E,)`2-AF0'``")!"3H_/___XN#@`<``(N3A`<``(E$)`B)
+M5"0,BX-\!P``B40D!(V#9`<``(D$).C\____BXZ@!P``A<ET4HN&I`<``(N6
+MJ`<``(E$)`B)5"0,B4PD!(V&B`<``(D$).C\____BX.D!P``BY.H!P``B40D
+M"(E4)`R+@Z`'``")1"0$C8.(!P``B00DZ/S___^+CL0'``"%R712BX;(!P``
+MBY;,!P``B40D"(E4)`R)3"0$C8:L!P``B00DZ/S___^+@\@'``"+D\P'``")
+M1"0(B50D#(N#Q`<``(E$)`2-@ZP'``")!"3H_/___X/$9%M>PY"-="8`@^P<
+MB5PD%(ET)!B+7"0@B1PDZ/S___^)'"3H_/___XVSA`D``(DT).C\____B1PD
+MZ/S____'!"30!P``Z/S___^)'"3H_/___\=$)`0!````B1PDZ/S____'1"0$
+M`0```(DT).C\____BUPD%(MT)!B#Q!S#C70F`(V\)P````"#[`R+5"00BT0D
+M%(A",@^VP(E$)`2)%"3H_/___[@!````@\0,PXUV`(V\)P````!3@^P(BUPD
+M$(D<).C\____BX.@!```!80)``")!"3H_/___X/$"%O#D(VT)@````!3@^P(
+MBUPD$(D<).C\____BX.@!```!80)``")!"3H_/___X/$"%O#D(VT)@````"#
+M[`R+1"00B00DZ/S___^Z`0```(,]``````!U`P^VT(G0@\0,PXUV`(V\)P``
+M``"#["R)7"0<B70D((E\)"2);"0HB<.)UXG-BW!DBT!LB40D%(7V#X0M`0``
+M@+N6``````^%(`$``(D$).C\____B40D&(7`#X0,`0``QD`DX<9`)0&)^H32
+M=`V)Z#P!&<#WT(/`!^L,B>J`^@$9P/?0@\`-BU0D&(A")@^W1AQFB4(0B5H8
+MQT(@`````,="-`````#'0FRPT0``B50D!(M$)!2)!"3H_/___\:#E@````%F
+MQX.4````]`&%VW19BT-DA<!T7&:!NY0```"6`'47B40D",=$)`0A````BT`L
+MB00DZ/S___]F@ZN4`````<<$)-`'``#H_/___XM4)!2)%"3H_/___XM#9(7`
+M=`F`NY8`````=:YF@[N4`````'0<BT0D&(!X%`!U$HM#9`^W0#9FB4->NP``
+M``#K!;O_____BU0D&(E4)`2+1"04B00DZ/S____K!;O_____B=B+7"0<BW0D
+M((M\)"2+;"0H@\0LPXVV`````(V\)P````"#["R)7"0<B70D((E\)"2);"0H
+MBW0D,`^V7"0TBWYDBVYLA?\/A"@!``"`OI8`````#X4;`0``B2PDZ/S___^)
+M1"08A<`/A`<!``#V!@(/A><```"`^Q1W"P^VPXT$0,'@`NL6N(G____VXV;!
+MZ`C`Z`0/ML`%\````(M4)!C&0B3AQD(E`<9")AR(0B</MT<<9HE"$(ER&,="
+M(`````#'0C0`````QT)LL-$``(E4)`2)+"3H_/___\:&E@````%FQX:4````
+MQ`F%]G15BT9DA<!T6&:!OI0```"6`'47B40D",=$)`0A````BT`LB00DZ/S_
+M__]F@ZZ4`````<<$)-`'``#H_/___XDL).C\____BT9DA<!T"8"^E@````!U
+MLF:#OI0`````=`^[`````(M$)!B`>!0`=`6[_____XM4)!B)5"0$B2PDZ/S_
+M___K!;O_____B=B+7"0<BW0D((M\)"2+;"0H@\0LPXUV`(/L'(E<)!")="04
+MB7PD&(M4)""+7"0DBT(LBSB+<T@/MD,4/`9T/SP&=PJ$P'0A/`)U#^LK/"%T
+M+3R`D(UT)@!T)+@`````ZVV-M"8`````BT(@QT`$`````,9&9@'K"L9&9A#K
+M!,9&9@V#>TP`="^!>R``$```=Q>-0TR)1"0$B3PDZ/S____K%8VV`````(U#
+M3(E$)`2)/"3H_/___XE<)`2)/"3H_/___XDT)/]6<+@!````BUPD$(MT)!2+
+M?"08@\0<PXUV`(V\)P````!55U93@^P<B<.)U8MT)#"+?"0T#[=$)#AFB40D
+M$@^V5"0\BT5LB40D%(U#/(E$)!B`^@$9P(/@"(/`"HE#9(M%9/9`-`%T>8#Z
+M`1G`@^`"@^AXB$,DQD,E`(GXP>@8B$,FB?C!Z!"(0R>)^,'H"(A#*(GZB%,I
+MB?`/K/@8B$,JB?`/K/@0B$,KB?`/K/@(B$,LB?"(0RW&0RX`QD,O``^W1"02
+M9L'H"(A#,`^V1"02B$,QQD,R`,9#,P#K4HUT)@"`^@$9P(/@`H/`*(A#),9#
+M)0")\`^L^!B(0R:)\`^L^!"(0R>)\`^L^`B(0RB)\(A#*<9#*@`/MT0D$F;!
+MZ`B(0RL/MD0D$HA#+,9#+0")'"3H_/___XM%9`^W0!QFB4,0QD,4@(EK&(M#
+M3(M`"(E#-`^W1"02#Z]%6(E#(,9#'""+160%EP```(E#.,=#;+#1``#'1"0$
+M`````(M$)!B)!"3H_/___XM#((E$)`R+0TR+4!"+0`R)1"0$B50D"(M$)!B)
+M!"3H_/___\:%E@````&)7"0$BT0D%(D$).C\____A>UT;XM%9(7`=&B`O98`
+M````=&9F@;V4````E@!U%XE$)`C'1"0$(0```(M`+(D$).C\____9H.ME```
+M``''!"30!P``Z/S___^+1"04B00DZ/S___^+162%P'06@+V6`````'04ZZRX
+M`````(![%`!T$[C_____ZPQF@[V4`````'3OZ^*#Q!Q;7E]=PX/L/(E<)"R)
+M="0PB7PD-(EL)#B+7"1$BW0D2`^W;"1,#[9$)%2(1"03BU0D0(MZ9(7_#X2L
+M`@``@+J6``````^%GP(``(M'+(E$)""+4FR)5"04BT0D0&;'@)0````0)XD4
+M).C\____B40D'(7`#X1P`@``9H/]!'86#[?%B40D!,<$)*$```#H_/___^L5
+MD(M4)!2)%"3H_/___XE$)!B%P'4>BT0D'(E$)`2+5"04B10DZ/S___^[____
+M_^DG`@``BU0D&(M$)!R)4$S&0%0!BU0D%(N"H`0``,9`)P&+1"1`B40D"(N"
+MH`0``(E$)`3'!"0%````Z/S___^`3R@"BU0D0(M"9(E$)`C'1"0$(0```(M$
+M)"")!"3H_/___XM4)$"#>F0`#X0B`0``@+J6``````^%%0$```^WU8G0P>`)
+MB40D*(M$)$"+2%C&1"0G`('Y`!```'4<B=B#X`>(1"0G#ZSS`\'N`P^VP(U$
+M`@>)Q<'M`X!\)!,`=6R!^0`0``!U/<=$)`P!````#[?%B40D"(D<)(ET)`2+
+M5"1`BT0D'.@G_/__A<!T%L<$)(`%``#H_/___[O_____Z9(````/MD0D)\'@
+M"8M4)!@#0@B+5"0HB50D"(M4)%")5"0$B00DZ/S___\/MD0D$XE$)`P/M\6)
+M1"0(B1PDB70D!(M4)$"+1"0<Z,+[__^%P'4^NP````"`?"03`'0W#[9$)"?!
+MX`F+5"08`T((BU0D*(E4)`B)1"0$BT0D4(D$).C\____NP````#K"8UT)@"[
+M_____XM4)!R#>DP`=#^!>B``$```=Q>)T(/`3(E$)`2+1"04B00DZ/S____K
+M%XM$)!R#P$R)1"0$BU0D%(D4).C\____BT0D',9`5`"+5"0<B50D!(M$)!2)
+M!"3H_/___XM4)!2+@J`$``#&0"<`BT0D0(E$)`B+@J`$``")1"0$QP0D!@``
+M`.C\____@&<H_>L%N_____^)V(M<)"R+="0PBWPD-(ML)#B#Q#S#D(/L'(E<
+M)!")="04B7PD&(MT)""+7F2%VW46BT0D*(D$)/]4)"3I!@$``(VV`````(-^
+M=`!U#(-^<`"-M@````!T$XM$)"B)!"3_5"0DC78`Z=L```"`NY0`````#X6^
+M````@'LF_P^%M````(M#,(7`=!2`>#$`#X6C````]D`N`@^$F0```(M#+/9`
+M!Q")]@^%B@```(LX@'M'`'04B5PD",=$)`0&````B00DZ/S___^+1"0DB49T
+MBT0D*(E&>`^V4R2)T(/@!H/X!G1B@_@$=5WVP@%T6(M#,(7`C78`="3V0"X"
+M=$AFQT`N`0"+0S#&0"8!BT,PB40D!(D\).C\____ZRK&0R8#QD,G!(E<)`2)
+M/"3H_/___^L4C70F`(M$)"B)!"3_5"0DD(UT)@"+7"00BW0D%(M\)!B#Q!S#
+M5E.#[!2+7"0@C;.$"0``B1PDZ/S___^)0Q2)1A2)FZ`$``")GJ`$``"+@ZP$
+M``")AJP$``#&@W()```!QH9R"0```8D<).C\____B1PDZ/S___^)-"3H_/__
+M_\=$)`0`````B1PDZ/S___^)'"3H_/___X3`=&Z)-"3H_/___X3`=&*)'"3H
+M_/___\<$)-`'``#H_/___XD<).C\____QX/0````Z`,``,>#V`````````")
+MF]P```"-@]````")1"0$BT,4B00DZ/S____'1"0$`````(D<).C\____N`$`
+M``#K!;@`````@\046U[#4X/L"(M<)!")'"3H_/___X'#A`D``(D<).C\____
+MN`$```"#Q`A;PY"-M"8`````55=64X/L/(,]Q``````/A8$!``#'!<0````!
+M````QT0D.`````#IO`(``)"-="8`#[>&'@$``,'@$`^WEAP!```)T#E$)"@/
+MA1,!``"_`````+D`````B7PD,&:#N0``````=7N)^L'B!8N&'`$``(F"````
+M`(N&(`$``(F"!````(N&)`$``(F""`````^V@AP```"-#/T`````C00!#[9<
+M)"^('(4-````#[:"'````(T$`0^V7"0NB!R%#@````^V@AP````!P<8$C0\`
+M````@((<`````>MYD(UT)@`/MID<````B=BZ`````/>V,`$``(72=$V+3"0P
+MP>$#C009#[94)"^(%(4-````BU0D,,'B!0^V@AP```"-!`$/MEPD+H@<A0X`
+M```/MH(<`````<'&!(T/`````(""'`````'K#X/'`8/!((/_!`^%`____X.&
+M*`$```&0C70F`(/%`8/&&#LM?`$```^%OO[__X-$)#0!@WPD-"`/A1@!``"#
+M1"0X`8%\)#C_````#X52`0``@WPD5`!T!XMT)%3&!@"+'7P!``#'1"0D````
+M`(7;?CFY`````,=$)"0`````N@````"+@B@!```!1"0D@WPD5`!T#(N"+`$`
+M`(MT)%0`!H/!`8/"&#G9==F#?"18``^$`0$``+T`````NP````!F@[L`````
+M``^$Z0````^V@QP```")1"0@A<!^:L=$)!@`````C13M`````(E4)!R+1"0<
+M`T0D&(TTA0P```"+?"18N`0```#\B<'SI@^7P@^2P#C"=2&#?"14`'0-#[:#
+M'0```(MT)%2(!@^V@QP```")1"0DZP^#1"08`8M4)"`Y5"08=:F#Q0&#PR"#
+M_01T9>EI____#[9,)#2(3"0NQT0D#`````#'1"0(`````(M<)#2)7"0$BW0D
+M.(DT).C\____B40D*+T`````O@````"#/7P!````#X]._?__Z8O^__\/MD0D
+M.(A$)"_'1"0T`````.N@#[9$)"2#Q#Q;7E]=PXGVC;PG`````(/L'(E<)!")
+M="04B7PD&(M$)"`/MG0D)(M8;(MX9/8``70OB1PDZ/S___^%P'0[@+B1````
+M`'0RB?(/ML*)1"0(BT<@B40D!(D<).C\____ZQB)\@^VPHE$)`B+1R")1"0$
+MB1PDZ/S___^+7"00BW0D%(M\)!B#Q!S#C;8`````@^P\B5PD+(ET)#")?"0T
+MB6PD.(M\)$`/MG0D1(M?9(MO;(7;#X1M`P``@+^6``````^%8`,``/8'`@^%
+M5P,```^V@]@```"$P'0+B?(XT'51Z4$#``"+4R")\0^VP8E$)!`/MH*7````
+M#[92`HT$@`^VA`(`````B40D#`^V12*)1"0(#[9%(8E$)`3'!"2D!0``Z/S_
+M__^X_____^GZ`@``B2PDZ/S___^)1"0@A<`/A.$"``"+4R")\0^VP8E$)!`/
+MMH*7````#[92`HT$@`^VA`(`````B40D#`^V12*)1"0(#[9%(8E$)`3'!"30
+M!0``Z/S___^+1"0@QD`DX<9`)0&)\H#Z`@^5P(/`&HM,)""(028/MT,<9HE!
+M$(EY&,=!(`````#'030`````QT%LL-$``(E,)`2)+"3H_/___\:'E@````%F
+MQX>4````]`&%_W15BT=DA<!T3F:!OY0```"6`'47B40D",=$)`0A````BT`L
+MB00DZ/S___]F@Z^4`````<<$)-`'``#H_/___XDL).C\____BT=DA<!T"8"_
+ME@````!ULHM$)"")1"0$B2PDZ/S___]F@[^4``````^$QP$``(M4)""`>A0`
+M#X6Y`0``BT]DB4PD*(M!+(LHB2PDZ/S___^)PX7`=16+1"0HQH"5`````;@`
+M````Z98!``")+"3H_/___XG&A<!U(8M4)"C&@I4````!B5PD!(DL).C\____
+MN`````#I9P$``(U+/(E,)"3&0R3AQD,E`<9#)@.+5"0H#[="'&:)0Q#&0V@/
+MB7L8QT,@``(``(M6"(E3-+@`````Q@00`(/``3T``@``=?*)<TS'0VRPT0``
+MQT0D!`````"+3"0DB0PDZ/S___^+0R")1"0,BT8,BU80B40D!(E4)`B+1"0D
+MB00DZ/S___^)7"0$B2PDZ/S____&AY8````!9L>'E````/H`A?]T58M'9(7`
+M=%AF@;^4````E@!U%XE$)`C'1"0$(0```(M`+(D$).C\____9H.OE`````''
+M!"30!P``Z/S___^)+"3H_/___XM'9(7`=`F`OY8`````=;)F@[^4`````'0J
+M@'L4`'4DBT,TB40D!(M4)"B)%"3H_/___XM,)"@/MH'8````B(>:````@WM,
+M`'0/C4-,B40D!(DL).C\____B5PD!(DL).C\____N`````#K$9"-="8`N/__
+M___K!;C_____BUPD+(MT)#"+?"0TBVPD.(/$/,.#[`R+5"04@#H)=PH/M@+_
+M)(4X`0``N/_____IH````(M2!(N"I`0``(7`=0.)T)"+@*`$``#&@',)```!
+MB00DZ/S___^X`````.MT#[9*!+H`````BT0D$.@2[?__ZV`/MDH$N@$```"+
+M1"00Z/[L___K3`^V0@2)1"0$BT0D$(D$).C\____ZS8/MD($B40D!(M$)!")
+M!"3H_/___^L@#[9"!(E$)`2+1"00B00DZ/S___^X`````(VT)@````"#Q`S#
+MC;8`````C;\`````@^PLB5PD((ET)"2)?"0HBW0D,(M^;(N'H`0``(!X)P!U
+M8(M><`^VAIH```")1"00#[:&EP````^V5@*-!(`/MH0"`````(E$)`P/MD<B
+MB40D"`^V1R&)1"0$QP0D_`4``.C\____QT9P`````(M&"(E$)`B)="0$BT9X
+MB00D_]/K.(U>?(E<)`2+1Q2)!"3H_/___\=&?/0!``#'AH0```"0[P``B;:(
+M````B5PD!(M'%(D$).C\____BUPD((MT)"2+?"0H@\0LPXVV`````%575E.#
+M[!R+;"0PBWPD-`^W1"0X:<#<````B<,#G=0$``"+A:`$```%A`D``(E$)!B)
+M7V2)>R#&@]D`````@WLP`'4G#[9U*XGQA,D/A"P!``"+2RRZ`````#N-3`@`
+M``^$[0```.D%`0``@`\!BT,PB4=H#[9U*XGPA,!T/HM+++H`````.XU,"```
+M=!'K'@^VPHT$P#F,Q4P(``!U%`^V12F-!(*(AY<```#K#KH`````@\(!B?`X
+MPG74BXV@!```O@````"Z`````(UT)@`/MH0*F`0``#S_=!X/ML!IP)0````#
+M@?`$```[0S!U!XGQB$\!ZT2#Q@&#P@&#^@1USK(`BTPD&`^VA`J8!```//]T
+M'P^VP&G`E`````.!\`0``#M#,'4(B?"(1P'K#)"#Q@&#P@&#^@1UR0^V0T6(
+M1P+K5`^VPHT$P#F,Q4P(``!U(@^V12F-!(*(1P&(AY<````X52MU&NL4C;8`
+M````N@````"#P@&)\#C"=<;&1P'_QD<"`(.[T`````!T"8N#U````(A'`HU/
+M((U37(M#7(E'((M"!(E!!(M""(E!"(M"#(E!#(M"$(E!$(M"%(E!%(M"&(E!
+M&(M"'(E!'(M"((E!((M")(E!)(U/#(U32(M#2(E'#(M"!(E!!(M""(E!"(M"
+M#(E!#(M"$(E!$(N#A````(E'2(N#B````(E'3`^W0S1FB4=<#[=#-F:)1UZ+
+M0SR+4T")1U")5U2+@Y````")1U@/MD-&B$=@#[:#V````(B'F@```/9#*`1U
+M"(DL).C\____#[93)(G0@^`&@_@&=0OVP@%T"8VV`````(`G_0^V4RC0ZH/B
+M!`^V!X/@^PG0B`</MD<!B(>9````#[9'`HB'F````(D\).C\____QT0D"```
+M``"+0R")1"0$B2PDZ/S___^)/"3H;_S__X/$'%M>7UW#C;0F`````(/L'(E<
+M)!2)="08BW0D((N>H`0``(DT).C\____@'XS`74MC8.$"0``@'@S`71?@+Y\
+M"0```'48QT0D!`````")!"3H_/___X"&?`D```&0C9[0````B5PD!(M&%(D$
+M).C\____QX;0````Z`,``,>&V`````````")MMP```")7"0$BT84B00DZ/S_
+M__^+7"04BW0D&(/$',.-M@````!55U93@^QLB[PD@````(N$)(0```"+M"2,
+M````B<7![1B)PL'J$(A4)$`/MLR(3"0PB$0D+XN<)(@```"!PX0)``"X````
+M`(N4)(@```#&!!``@\`!/0@5``!UZXER$*'`````B$(H@\`!H\````")Z8A*
+M(P^V1"1`B$(B#[9,)#"(2B$/MD0D+XA"(,9"*0`/MP=FB4(8#[='`F:)0AJ+
+M1P2)0AR+E"2(````@<(($P``BXPDB````(F1@`D``(ES$`^V02B(0RB)Z(A#
+M(P^V3"1`B$LB#[9$)#"(0R$/MDPD+XA+(,9#*0$/MP=FB4,8#[='`F:)0QJ+
+M1P2)0QR)DX`)``"+E"2(````#[="&F8])"</A",!``!F/20G#X>,````9CU$
+M(0^$#P$``&8]1"%W3&8]("$/A/\```!F/2`A=Q%F/5`'#X4*`0``B?;IZ```
+M`&8](B&-M"8`````#X37````9CU`(8VV``````^%X@```.G"````D(UT)@!F
+M/1`G#X+.````9CT1)XGV#X:G````9BT@)V:#^`*)]@^'L@```.F2````D(UT
+M)@!F/8`G#X2#````9CV`)XGV=S)F/4`G='5F/4`GC70F`'<09CTP)P^%?```
+M`(UT)@#K6V8]1"=T568]8">-="8`=6;K268]@')T0V8]@'*)]G<(9CV")W50
+MZS-F/8"1B?9T#F8]@)1U0.LCC;8`````BXPDB````&;'022`D<9!)@1FQT,D
+M@)'&0R8$ZQN+A"2(````9L=`)("4QD`F!&;'0R2`E,9#)@0/MD<(BY0DB```
+M`(A"*@^V1PB(0RK'1"0,```$`,=$)`@`````QT0D!`(```")-"3H_/___XN,
+M)(@```")`<=$)`P`(```QT0D"`````#'1"0$`````(DT).C\____B<&+M"2(
+M````B48(BP:%P`^$[0$``(7)#X3E`0``C9```@$`B58$C8````(`B08%`$``
+M`(D#B5,$B4L(BS5\`0``A?9^7[L`````N0`````/MX$<`0``9CL'=3\/MX$>
+M`0``9CM'`G4RBY$L`0``@\(!B9$L`0``BX$H`0``B40D&(7`=!4YPG81B="Z
+M`````/=T)!B)D2P!``"#PP&#P1@Y\W6KBY0DB````(M"!"W@?0``QP`!\`,`
+MBT($+=A]``#'``$``.B+0A#'1"0$>````(D$).C\____B<(E`'```#T`(```
+M=B:)T(#DCX#,((N,)(@```"+41")1"0(QT0D!'@```")%"3H_/___XGHB$0D
+M7P^V5"1`B%0D7@^V3"0PB$PD70^V1"0OB$0D7,=$)"@`````O0````!F@[T`
+M``````^$H````("]'``````/A(````"[`````(M4)"C!X@.)5"0DC4PD7(E,
+M)!R+1"0D`=B--(4,````N00```#\BWPD'/.F#Y?"#Y+`.,)U-P^VA1T```"#
+MP`&(A1T````/MI4<````A-)T'#C0=A@/ML`/MLJZ`````&;W\8B5'0```(UT
+M)@"#PP$/MH4<````.=A_F(-$)"@!@\4@@WPD*`0/A5+___^+M"2(````QX:L
+M!````0```+@!````ZP6X`````(/$;%M>7UW#C78`C;PG`````%575E.#[`2+
+M="08BWPD'(MN;`^V!H/@`0^VP(D$)+@`````Q@0X`(/``8/X)'7TBYV`"0``
+MB=JP`(VT)@````#&!!``@\`!/0`"``!U\HU+-KH`````#[9$,B&(!`H/MD0R
+M((A$"@&#P@*#^BAUYXU+%+("#[9$,@N(1`K^#[9$,@J(1`K_@\("@_H6=>:-
+M2RZR``^V1#))B`0*#[9$,DB(1`H!@\("@_H(=>>)7QR+5E"+3E2#P@&#T0")
+M%XE/!(M&6(E'"#T`$```=1")T(G*#Z3"`\'@`XD'B5<$@WYD`'4>]@8!=!F+
+M1FB%P'0RA>UT+@^W0"2`O`48!```_W0@#[:&EP````^V5@*-!(`/MH0"````
+M`(A'$,<$)`````#&1Q$`QD<2`<9'%A#&1Q40#[8$)(T4``^V7PZ#X_T)TXA?
+M#L'@!0^V5PR#XM\)PHA7#`^W1ES!Z`>#X`'!X`:#XK\)PHA7#`^W1ES!Z`*#
+MX`$/MD\-@^'^"<&(3PT/MT9>P>@#P>`'@^)_"<*(5PP/MT9>T>B#X`$!P(/A
+M/0G!B$\-@\H0B%<,#[8&T.B#X`&#X_X)PXA?#@^V!H/@!(/C^PG#B%\.9L='
+M&``0#[:&F@```(A'$P^VAI<```"(1R"#Q`1;7E]=PXVT)@````"#["R)7"0<
+MB70D((E\)"2);"0HBUPD,(M#;(E$)!B+5"0TBT(DB1B+0V2%P'42QD)F`HD4
+M)/]2<.F8!0``C78`]D`H`G0:BTPD-,9!9@*)#"3_47#I?`4``(VT)@````"+
+M1"08B00DZ/S___^)QH7`=1.+5"0TQD)F`HD4)/]2<.E0!0``QT!D`````(M,
+M)#2)2$B+0V2)1AB+0V0/MT`<9HE&$`^V060\`@^$4P$``#P"=PR$P'0CZ8H"
+M``"-=@`\`P^$C0$``#P$C;8`````#X5Q`@``Z5$!``"+1"0TBWA(BVA,#[=(
+M4(%[6``0``!U"P^L[P/![0-FP>D#BT-D]D`T`0^$@0```(M4)#0/MD)EJ`)T
+M!L9&)(CK$(/@!#P!&<"#X`6#Z':(1B3&1B4`B>C!Z!B(1B:)Z,'H$(A&)XGH
+MP>@(B$8HB>J(5BF)^`^LZ!B(1BJ)^`^LZ!"(1BN)^`^LZ`B(1BR)^(A&+<9&
+M+@#&1B\`B<AFP>@(B$8PB$XQQD8R`,9&,P#K6HM4)#0/MD)EJ`)T!L9&)"CK
+M$(/@!#P!&<"#X`6#P"J(1B3&1B4`B?@/K.@8B$8FB?@/K.@0B$8GB?@/K.@(
+MB$8HB?B(1BG&1BH`B<AFP>@(B$8KB$XLQD8M`(M#9`67````B48XQD8<(`^W
+MP0^O0UB)1B#I40$``(M4)#2`>D@0=P7V`P)U#8M,)#3&068&Z80#``"+1"0T
+MQD!F!NEW`P``BU0D-`^V0F6#X#`\('41QD8D&\9&)0'&1B@`Z0@!``#&1B0U
+MZ?\```"+0V0/MD`D@^`%@_@%=1>!3F0``"``BTPD-`^W451F.U%*=0_K7HM$
+M)#3&0&8&Z1L#``"+3"0T#[9!4SSC=$4\XW<0/$)T/3RPB?9T(#Q`=2;K,3SL
+MC;8`````=!`\[W0C/.5U$HVV`````.L7BT0D-&:)4$KK#8M4)#3&0F8&Z<H"
+M``#&1B2PBTPD-`^W04B(1B4/MT%*B$8F#[=!3(A&)P^W04Z(1B@/MT%0B$8I
+M#[9!4HA&*@^V05.(1BL/MD%)B$8L#[9!2XA&+0^V04V(1BX/MD%/B$8O#[9!
+M48A&,/9!909T&0^W053!X`F)1B#K#8M$)#3&0&8&Z4\"``#'1FP@WP``BU0D
+M-`^V0F6H!@^$)@(``(U^/(M::(7;=`2H`75$BTPD-(M1;(72#X0W`@``QT0D
+M"`````"+3"08BX&$!0``B40D!(M$)#2)!"3_TH7`#X00`@``BU0D&(N:A`4`
+M`(7;=$B)-"3H_/___\=$)`0`````B3PDZ/S___^#PQ"+0_")1"0,BT/XBU/\
+MB40D!(E4)`B)/"3H_/___XM#](/#$(7`#X6.`0``Z]/'1"0$`````(D\).C\
+M____BT8@/0`0``!W1XM,)!B)#"3H_/___XG"A<!U#8M$)#3&0&8+Z64!``"+
+M0`B)1C2)5DR+1B")1"0,BT(,BU(0B40D!(E4)`B)/"3H_/___^M;/0```0!W
+M1XM4)!B)%"3H_/___XG"A<!U#8M,)#3&068+Z1<!``"+0`B)1C2)5DR+1B")
+M1"0,BT(,BU(0B40D!(E4)`B)/"3H_/___^L-BT0D-,9`9@;IX@```(M4)#0/
+MMD)EJ`0/A,````"`>F0#=2*+2EB%R70;BU8TBT8@B40D"(E,)`2)%"3H_/__
+M_^F8````BTPD-(M1:(72=0V+46R%T@^%N@```.MKBWXTJ`%U!(G3ZSB+1"0T
+MBU!LA=)T+<=$)`@!````BTPD&(N!A`4``(E$)`2+1"0TB00D_]*%P'0*BU0D
+M&(N:A`4``(/#$(M#^(M3\(E4)`B)1"0$B3PDZ/S___\#>_"+0_2#PQ"%P'47
+MZ]N+1B"+5C2%P'0+Q@(`@\(!@^@!=?6)="0$BTPD&(D,).C\____ZS*)="0$
+MBT0D&(D$).C\____BU0D-(D4)/]2<.L6NP````#I//[__XM^-(UT)@#I4O__
+M_XM<)!R+="0@BWPD)(ML)"B#Q"S#C;0F`````%=64X/L$(M\)""+="0DN```
+M``#&!#``@\`!@_AX=?2#OZP$```!#Y1&$P^V5R(/MD\A#[9?(`^V1R.(1@.(
+M5@*(3@&('H!.$1`/MT<89HE&!`^W1QIFB48&BX>L!```B$9LQD82(`^W5QIF
+M@?H@(70'9H'Z(B%U1\9&%P*-1CS'1CQ2;V-KQT`$97120<=`"$E$(%/'0`Q3
+M1"`RQT`0,3)X(,=`%$-O;G3'0!AR;VQL9L=`'&5RQD`>`.G^````C8+PV/__
+M9H/X`7829H'Z0"%T"V:!^D0A#X6E````QD87!`^W5QJ-@O#8__]F@_@!=T.-
+M1CS'1CQ2;V-KQT`$97120<=`"$E$(#+'0`PW,7@@QT`04T%3(,=`%$-O;G3'
+M0!AR;VQL9L=`'&5RQD`>`.F)````9H'Z0"%T!V:!^D0A=7N-1CS'1CQ2;V-K
+MQT`$97120<=`"$E$(%/'0`Q31"`RQT`0,31X(,=`%$-O;G3'0!AR;VQL9L=`
+M'&5RQD`>`.L[QD87"(U&/,=&/%)O8VO'0`1E="`WQT`(-3`@4\=`#$%402#'
+M0!!#;VYTQT`4<F]L;&;'0!AE<L9`&@#&1A<HQD82`<9&$"B-1AC'1AA(:6=H
+MQT`$4&]I;L=`"'0@5&7'0`QC:&YOQT`0;&]G:<=`%&5S+"#'0!A);F,NQD`<
+M`(N'J`0``(7`=!"+0`B)1F2)PL'Z'XE6:.L.BT<(B49DB<+!^A^)5FC'1F``
+M(```QT0D!'P```"+1Q")!"3H_/___XG"@>+P`P``P>H$B%9M@^`/B$9OQT0D
+M!(````"+1Q")!"3H_/___XG"@>(``/`#P>H4B%9N)0``#P#!Z!"(1G"#Q!!;
+M7E_#C;8`````55=64X/L'(ML)#"+="0TBUPD.+@`````Q@08`(/``3V<````
+M=?*)<PB#_A-^"8'%A`D``(/N%+@`````@[RU&`(````/A?T!``")G+48`@``
+MB6MLBT0D/(E#<(M,)$")2WB`?3,!#X76`0``@?Z#````#X^X`0``#[:$-1@$
+M```\_P^$J`$```^VP&:)1"08#[?`:<#<````B<<#O=0$``#V1R<$#X2%`0``
+MBT<D)0#__P`]``#_``^%<@$``/9'*`0/A.0```#&AY0`````#[97)(G0@^`&
+M@_@&#X1A`0``@_@$#X58`0``]L(!#X1/`0``BU\LBT<PA<`/A8(```#&1R8#
+MQD<G!(!["0!T4;X`````C4,HB40D%(M,)!2)#"3H_/___XG"BT,LB5,LBTPD
+M%(D*B4($B1"`>B;_=!4YUW01QH>5`````;@!````Z?(```"#Q@$/MD,).?!_
+MNX"_E0````$/A-4```")?"0$B2PDZ/S___^X`0```.G$````@'@F``^%M0``
+M`&;'0"X!`(M',(E$)`2)+"3H_/___[@!````Z9L```"+?RR`?PD`=%[&1"0;
+M`(U'*(E$)!"+3"00B0PDZ/S___^)PHM'+(E7+(M,)!")"HE"!(D0@'HF_W0>
+M#[9")3PB=`0\#742QX2U&`(```````"X`````.M#@$0D&P$/MD0D&SA'"7>N
+M#[=$)!B)1"0(B5PD!(DL).C\____N`$```#K&)#'A+48`@```````+@`````
+MZP6X`0```(/$'%M>7UW#D(M$)`0/ME0D#,8`",9``1*`?"0(`'0)@$@"!.L'
+MC78`@&`"^X32=`B`8`S?ZP:)]H!(#""X%````,.-M@````#SPXVT)@````"-
+MO"<`````55=64X/L+(ML)$"+?"1(#[9$)$R(1"0;#[94)%"(5"0:BU0D1(M"
+M&(E$)"C'0A@`````@WPD*``/A5T!``")+"3H_/___XG&N`````"%]@^$_0$`
+M`(DL).C\____B40D*(7`=1:)="0$B2PDZ/S___^X`````.G7`0``QD8D&L9&
+M)0C&1B8(QD8G`,9&*/_&1BD`QD85JXM4)$0/MT(<9HE&$(EN&,=&(/\```#'
+M1F0(````BT0D*(M`"(E&-`7_````B48XQD8<)(M$)"B)1E#'1FR@!0$`QD84
+M@(U>/,=$)`0`````B1PDZ/S____'1"0,_P```(M$)"B+4!"+0`R)1"0$B50D
+M"(D<).C\____B70D!(DL).C\____N\C____K&\<$).@#``#H_/___X/K`8DL
+M).C\____A-MT#`^V1A0\@'3=A,!T/8U$)"B)1"0$B2PDZ/S___\/MT8>B40D
+M!(M4)$2+0BR)!"3H_/___XET)`2)+"3H_/___[@`````Z<H```#'1E``````
+MB70D!(DL).C\____BT0D*(M8"`^V1"0:B40D"`^V1"0;B40D!(U#!(D$).C\
+M____B<;&`P#&0P$`QD,"`,9#`P")?"0$B2PDZ/S___^-5R2X`````,8$$`"#
+MP`&#^!!U](U>!,9')!7&1R41B%\HQD<I`(UW/`^VVXE?(,='9`````"+5"0H
+MBT((B4<TB5=0QT0D!`````")-"3H_/___XE<)`R+1"0HBU`0BT`,B40D!(E4
+M)`B)-"3H_/___[@!````@\0L6UY?7<.0D)"0D)!3BUPD"(M$)`R)PF:)0P3&
+M0PH`9L=#"```9H7`=!J#Z@&Y`````(L#9HD4"(/!`H/J`6:#^O]U[EO#C;8`
+M````5E.+7"0,BT0D$(G&9HE#!,9#"@%FQT,(``!FA<!T(KH`````N0````"-
+MM"8`````BP-FB10(@\(!@\$"9CGR=>];7L.-M@````"-OP````!3BUPD"(![
+M"@%U*@^W0P@/M\B+$P^W%$J#P`%FB4,(9CM#!G(&9L=#"```9H-K!`$/M\+K
+M%(L3#[=#!(/H`6:)0P0/M\`/MP1"6\.0C70F`(/L"(D<)(ET)`2+7"0,BTPD
+M$(G.@'L*`74F#[=3!`^W0P@!P@^W0P:)QHG0P?H?]_Z+`V:)#%!F@T,$`>L6
+MB?8/MT,$#[?(BQ-FB31*@\`!9HE#!(L<)(MT)`2#Q`C#D(M$)`1F@W@$``^4
+MP`^VP,.+1"0$BP@YR'4'N0````#K"HL1BT$$B4($B1")R,.)]E=64XM4)!"+
+M3"04#[9\)!B)^(3`=#8/M@*)T[X`````.@%T%.L?#[93`0^V00&#PP&#P0$X
+MPG4-@\8!B?*)^#C"=>/K![@`````ZP6X`0```%M>7\.-="8`C;PG`````(M$
+M)`3&0`$`BU0D"(A0`L=`!`````##B?:-O"<`````55=64XM,)!2+?"08BVPD
+M'(MT)"`/ME$!#[;"C01`P>`"B<,#60B#P@&(40$!<02X`````,8$&`"#P`&#
+M^`QU](D[B6L$B?"(0PB)\@^VQHA#"<'J$(/B/P^V0PJ#X,`)T(A#"EM>7UW#
+MC;0F`````(M4)`0/MD(!.@(/DL`/ML##ZPV0D)"0D)"0D)"0D)"04P^W3"0,
+M#[9<)!"+5"0(N`````"`>@+_=0AFB0J(6@+K#(/``8/"!&8]@`!UY@^WP%O#
+MC;8`````C;PG`````(/L'(E<)`R)="00B7PD%(EL)!B+;"0@BTPD*(M<)"P/
+MMT0D)(U4A0"`>@+_=0AFB0J(6@+K&0^VPXE$)`@/M\&)1"0$B2PDZ/S___\/
+MM\"+7"0,BW0D$(M\)!2+;"08@\0<PXVV`````(V\)P````!3#[=<)`P/MDPD
+M$(M4)`BX`````#A*`G479CD:=1+&0@+_9L<"___K$XVT)@````"#P`&#P@1F
+M/8``==@/M\!;P^L-D)"0D)"0D)"0D)"0D%93BUPD#`^W="00#[9,)!2Z````
+M`(G0.$R3`G4&9CDTDW0.@\`!@\(!@?J`````=>1F/8``=06X@`$```^WP%M>
+MPXVT)@````"-O"<`````@^P0B1PDB70D!(E\)`B);"0,BVPD%`^V120\"'1(
+M/"AT1#RH#X06`0``/(B-="8`#X1:`0``/`IT+#PJC70F`'0D/*H/A/8````\
+MBHUT)@`/A#H!```\+W0,/(^-="8`#X7H`0``/"\/A)4````\+W<B/`IT9#P*
+M=PH\"(UT)@!U1.M6/"AT>SPJC;8`````=33K;SR/#X3T````/(^)]G<5/(@/
+MA.8````\BHUT)@!U%.G9````/*B-M"8`````='X\JG1ZO@````"_`````+@`
+M````Z68!```/MD4FP>`(#[95)PG0#[95)8/B'\'B$`G0B<:_``````^V12CI
+M/0$```^V52;!XA@/MD4GP>`0"<(/MD4I"<(/MD4HP>`("<*)UK\`````#[9%
+M*\'@"`^V52P)T.D%`0``D(UT)@`/ME4FP>(8#[9%)\'@$`G"#[9%*0G"#[9%
+M*,'@"`G"B=:_``````^V52K!XA@/MD4KP>`0"<(/MD4M"<(/MD4LP>`("=#I
+MM@```(VV``````^V12:)PK@`````P>(8#[9-)XG+N0````#!XQ`)R`G:#[9-
+M+;L`````"<@)V@^V32B)R[D`````P>,("<@)V@^V32F)R[D`````"<@)V@^V
+M32J[``````^DRQC!X1@)R`G:#[9-*[L`````#Z3+$,'A$`G("=H/MDTLNP``
+M```/I,L(P>$(B<8)SHG7"=\/ME4NP>(8#[9%+\'@$`G"#[9%,0G"#[9%,,'@
+M"`G0C78`B758B7U<B45@9H--$@&+'"2+="0$BWPD"(ML)`R#Q!##ZPV0D)"0
+MD)"0D)"0D)"05E.+="0,#[=$)!"Z_____V:%P'0MNO____^Y`````(/H`0^W
+MP(U8`0^V!#$QT`^VP,'J"#,4A8`!``"#P0$YV77FB=!;7L.)]HV\)P````"#
+M[$R+1"10#[90,XE4)$0/ME`RB50D0`^V4#&)5"0\#[90,(E4)#@/ME`OB50D
+M-`^V4"Z)5"0P#[90+8E4)"P/ME`LB50D*`^V4"N)5"0D#[90*HE4)"`/ME`I
+MB50D'`^V4"B)5"08#[90)XE4)!0/ME`FB50D$`^V4"6)5"0,#[90)(E4)`B)
+M1"0$QP0D+`8``.C\____@\1,PY"-="8`4X/L&(M4)""+3"0D#[9!`8A"`0^V
+M00*(0@*+002)0@2+6@@/MD(!C01`P>`"BU$(B40D"(E4)`2)'"3H_/___X/$
+M&%O#C70F`(V\)P````!3BU0D"(M:1`^V2CRX`````,8$$`"#P`&#^'!U](E:
+M1(A*/%O#C70F`(V\)P````"+5"0$N`````"-M"8`````Q@00_X/``3T``@``
+M=?+SPXM$)`2Y`````#L`=`V+2`2+$8M!!(E"!(D0B<C#D)"04XM<)`B+"XN1
+M!`$``(G0)7[__O^)@00!``"!XG[_\O^+0P2)$(M#!(E0#(L#BX!4`0``HP``
+M```E_@#__XL3B8)4`0``6\.)]HV\)P````!3BUPD"`^V3"0,BP.+D`0!``")
M%0`````/MT,D9CV`9'0.9CV`D70(9CV`E'43B?8/MLF#P0BX`0```-/@"<+K
M#P^VR8/!#+@!````T^`)PHL#B9`$`0``6\.-M@````!3BUPD"`^V3"0,BP.+
MD`0!``")%0`````/MT,D9CV`9'0.9CV`D70(9CV`E'43B?8/MLF#P0BX_O__
@@ -2957,8 +1581,8 @@ MB0*-A([0`0``D(UT)@"#^0-V"XL0B14`````ZPF0BQ")%0````#VP@)T<^OA
MD(/Y`W8UC1S-`````(V$,S`"``#'``````#'!"00)P``Z/S___^-G#,T`@``
MBP.C`````(/(`8D#ZS:-',T`````C80S4`(``,<``````,<$)!`G``#H_/__
M_XV<,U0"``"+`Z,`````@\@!B0.-=@"#Q`1;7L.0D)"0D)"0D)"04XM,)`B+
-M&0^W@90+``"#P`%FB8&4"P``9CN!F`L``'()9L>!E`L`````#[>!E`L``,'@
-M`@.!C`H``(M4)`R+$HD0#[>!E`L``(F#+`$``%O#ZPV0D)"0D)"0D)"0D)"0
+M&0^W@9`+``"#P`%FB8&0"P``9CN!E`L``'()9L>!D`L`````#[>!D`L``,'@
+M`@.!B`H``(M4)`R+$HD0#[>!D`L``(F#+`$``%O#ZPV0D)"0D)"0D)"0D)"0
M5E.+3"08#[=4)!`/MG0D%(M<)`RX`````(VT)@````#&!`@`@\`!@_@$=?1F
M@>+_#P^W`68E`/`)T&:)`0^V4PG!X@R+`27_#_#_"=")`0^V0P:#X`*#^`$9
MTH/B`H/"`<'B!0^V00.#X!\)T(/($(/@]XA!`_9#!@%T%HGR@^)_P>($#[=!
@@ -2968,39 +1592,39 @@ M*HA"!0^V02N(0@;V068$=",/MD$LB$((#[9!+8A""0^V02Z(0@H/MD$OB$(+
M#[9!,(A"#+@!````PY"-="8`55=64XML)!2+?"08N@````"^`0```.M0`=*)
MV-/XJ`%T$/?"`````746@?)W)]L`ZP[WP@````%T!H'R=R?;`(/I`8/Y_W70
M@\8!@_X)=1B)T,'H$(A%`(G0P>@(B$4!B%4"6UY?7<,/MEP^_[D'````ZZ2-
-MM@````"-OP````"+1"0$BX!$"@``BQ"+4`2+4`B+0`RC`````,.0C70F`%=6
+MM@````"-OP````"+1"0$BX!`"@``BQ"+4`2+4`B+0`RC`````,.0C70F`%=6
M4X/L$(M\)""+="0DBT94#[9?*X3;="8/ME`)N0````#VP@%T$>L6C;0F````
M`(G0T_BH`74'@\$!.-EU\<9&)@R)="0$B3PDZ/S___^#Q!!;7E_#C78`C;PG
M`````(/L#(M$)!"+$&;'0#(!`,9`)AV)1"0$B10DZ/S___^#Q`S#C;8`````
-MC;PG`````%93@^P4BT0D((LP#[=$)"3!X`(#AM`%``"+&(7;=$2+%@^W0QYF
+MC;PG`````%93@^P4BT0D((LP#[=$)"3!X`(#ALP%``"+&(7;=$2+%@^W0QYF
MP>@%#[?`C02%``,``(F"<`$``(L6#[=+'H/A'[@!````T^")@G0!``#'1"0(
M`````(E<)`2)-"3H_/___X/$%%M>PXVT)@````!55U93@^P<BVPD,(!]*P!T
M*[D`````BT0D-/9`"0%T$.L:BU0D-`^V0@G3^*@!=0R#P0$/MD4K9CG(=^:+
M5"0TBT(HA<!T)8/`6(M5%(E$)`2)%"3H_/___XM4)#2+0BB)1"0$B2PDZ/S_
M__^+1"0T@\`XBU0D-#E".`^$=0$``(E$)!B+1"08B00DZ/S___^)QH-X(``/
-MA#0!``"`>$\`#X29````9H-]7``/A(X```"_`````(T$O0`````#A=`%``"+
-M&(7;=&</MT,09CM&''5=9CV%`'=7#[?`@+PHO`0``/]T2HM5``^W0QYFP>@%
+MA#0!``"`>$\`#X29````9H-]6``/A(X```"_`````(T$O0`````#A<P%``"+
+M&(7;=&</MT,09CM&''5=9CV%`'=7#[?`@+PHN`0``/]T2HM5``^W0QYFP>@%
M#[?`C02%``,``(F"<`$``(M5``^W2QZ#X1^X`0```-/@B8)T`0``QD,4(<=$
-M)`@`````B5PD!(DL).C\____@\<!#[=%7#GX#X]W____BT8@QT!@`````/9&
+M)`@`````B5PD!(DL).C\____@\<!#[=%6#GX#X]W____BT8@QT!@`````/9&
M*`1U(8DL).C\____BT8@QT0D"`$```")1"0$B2PDZ/S___^)]HM&(`^V4`(/
-MMD`!B50D"(E$)`3'!"2P`0``Z/S___^+1B"+E4@%``")1"0(B50D!,<$)`$`
-M``#H_/___XM&((N52`4``(E$)`B)5"0$QP0D!@```.C\____QT8@`````(M4
+MMD`!B50D"(E$)`3'!"3!````Z/S___^+1B"+E40%``")1"0(B50D!,<$)`$`
+M``#H_/___XM&((N51`4``(E$)`B)5"0$QP0D!@```.C\____QT8@`````(M4
M)#2`:@H!B70D!(DL).C\____BU0D&(M$)#0Y4#@/A8_^__^+1"0TQT`H````
M`(M%`(N(6`$``(D-`````(7)=`F+10")B%@!``"#Q!Q;7E]=PXVV`````(V_
-M`````%=64X/L((MT)#"+/@^V7RN$VW0QC8><"P``N0`````Y\'49ZR`/ML&)
-MPL'B!HV$@I`+``"-1`<,.?!T#H/!`3C9=>+K!;D`````#[;1B=#!X`:-!)"+
-MC`>D"P``A<D/A'X```#V008"='B-A`><"P``.4$8=6P/MD$TA,!T"(/``8A!
+M`````%=64X/L((MT)#"+/@^V7RN$VW0QC8>8"P``N0`````Y\'49ZR`/ML&)
+MPL'B!HV$@I`+``"-1`<(.?!T#H/!`3C9=>+K!;D`````#[;1B=#!X`:-!)"+
+MC`>@"P``A<D/A'X```#V008"='B-A`>8"P``.4$8=6P/MD$TA,!T"(/``8A!
M-.M<BU$L@^H@C5DLC4(@.=AT3(-Z#`!U.>L(B?:#>@P`=2_&030!QT0D$```
-M```/MH*+````B40D#(E4)`B)3"0$BX<$"@``B00DZ/S____K#8M2((/J((U"
+M```/MH*+````B40D#(E4)`B)3"0$BX<`"@``B00DZ/S____K#8M2((/J((U"
M(#G8=;Z#Q"!;7E_#C;0F`````(/L'(E<)`R)="00B7PD%(EL)!B+7"0@BWPD
-M)(M'3(MH'`^W5Q!F@?J%`'=T#[?"#[:$`[P$```\_W1E9H/Z?W<?#[;`BY-\
-M!0``:<`H`0``BT00+`^V0`3K2XVV`````&:!^H$`=QD/ML"+D[0%``!IP!0-
-M``"+1!`(#[9`!.LE#[;`BY.8!0``:<"P````BT005`^V0`3K#(VT)@````"X
-M_P````^VM!A"!0``BT=0A<!T#(E$)`2)'"3H_/___XE\)`2)'"3H_/___XEL
-M)`2)\@^VPFO`7(V$`TP!``")!"3_E9P```"+7"0,BW0D$(M\)!2+;"08@\0<
+M)(M'3(MH'`^W5Q!F@?J%`'=T#[?"#[:$`[@$```\_W1E9H/Z?W<?#[;`BY-X
+M!0``:<`H`0``BT00+`^V0`3K2XVV`````&:!^H$`=QD/ML"+D[`%``!IP!0-
+M``"+1!`(#[9`!.LE#[;`BY.4!0``:<"P````BT005`^V0`3K#(VT)@````"X
+M_P````^VM!@^!0``BT=0A<!T#(E$)`2)'"3H_/___XE\)`2)'"3H_/___XEL
+M)`2)\@^VPFO`7(V$`T@!``")!"3_E9P```"+7"0,BW0D$(M\)!2+;"08@\0<
MPXUT)@"#[!R)7"0,B70D$(E\)!2);"08BW0D)(M<)"@/MVPD+&:!?B3A`740
-M#[9&)H/H$;\`````/`%V+HM$)""+$(NZ?`4```^W1A"YV"8!`&8]A0!W$0^W
-MP`^VA`*\!```:<@H`0```<_&0P0%@&,%_H`CW[@`````9H%^).$!=1(/MD8F
+M#[9&)H/H$;\`````/`%V+HM$)""+$(NZ>`4```^W1A"YV"8!`&8]A0!W$0^W
+MP`^VA`*X!```:<@H`0```<_&0P0%@&,%_H`CW[@`````9H%^).$!=1(/MD8F
M@^@!/`$/EL`/ML"-=@#!X`</MA.#XG\)PH@3#[9&9H/@`<'@!H/BOPG"B!/V
M1F8!=`Z)/"3H_/___V:)0PCK!&:):P@/MT,(B$859H%^).$!=2L/ME8FC4+_
M/`%W$`^V5B>#X@_K*8VT)@````"-0N^Z#P```#P!=A:-="8`N@````"#?S0`
@@ -3008,67 +1632,67 @@ M=`</ME=-@^(/#[8#@^#P"="(`XM<)`R+="00BWPD%(ML)!B#Q!S#@^P\B5PD
M+(ET)#")?"0TB6PD.(M<)$0/MD,D/`AT$3PH=`T\J'0)/(AU"Y"-="8`@TMD
M"NL>/`IT%CPJC70F`'0./*IT"CR*=0J-M@````"#2V0"#[=[)&:!_^$!=1D/
MMD,F@^@1/`%W#H-+9`BX`````.E]!0``BT,D)?___P")1"0@/>$!$``/A>0`
-M```/MU,09H'ZA0`/AS(%```/M\*+="1`#[:,!KP$``"X_____X#Y_W1I9H/Z
-M?W<=#[;!BW0D0(N6?`4``&G`*`$``(M$$"P/MD`$ZT9F@?J!`'<=#[;!BW0D
-M0(N6M`4``&G`%`T``(M$$`@/MD`$ZR(/ML&+="1`BY:8!0``:<"P````BT00
-M5`^V0`2-M"8`````#[;`BU0D0`^VA`)"!0``:\!<C;0"3`$``(N2M`4```^V
+M```/MU,09H'ZA0`/AS(%```/M\*+="1`#[:,!K@$``"X_____X#Y_W1I9H/Z
+M?W<=#[;!BW0D0(N6>`4``&G`*`$``(M$$"P/MD`$ZT9F@?J!`'<=#[;!BW0D
+M0(N6L`4``&G`%`T``(M$$`@/MD`$ZR(/ML&+="1`BY:4!0``:<"P````BT00
+M5`^V0`2-M"8`````#[;`BU0D0`^VA`(^!0``:\!<C;0"2`$``(N2L`4```^V
MP6G`%`T``,=$)"0`````]D0"-1`/A4H"``#&0Q0$BU0D2,<"`````+@!````
-MZ8($```/MU,0N?\```"X_____V:!^H4`=WX/M\*+="1`#[:,!KP$``"X____
-M_X#Y_W1B9H/Z?W<=#[;!BW0D0(N6?`4``&G`*`$``(M$$"P/MD`$ZS]F@?J!
-M`'<=#[;!BW0D0(N6M`4``&G`%`T``(M$$`@/MD`$ZQL/ML&+="1`BY:8!0``
-M:<"P````BT005`^V0`0/MLD/ML")1"0HBU0D0`^VK!!"!0``:\5<C;0"3`$`
-M``^WP6G`*`$```."?`4``(E$)"1F@?_A`74+#[9#)H/H`3P!=BEF@?G_`'0*
+MZ8($```/MU,0N?\```"X_____V:!^H4`=WX/M\*+="1`#[:,!K@$``"X____
+M_X#Y_W1B9H/Z?W<=#[;!BW0D0(N6>`4``&G`*`$``(M$$"P/MD`$ZS]F@?J!
+M`'<=#[;!BW0D0(N6L`4``&G`%`T``(M$$`@/MD`$ZQL/ML&+="1`BY:4!0``
+M:<"P````BT005`^V0`0/MLD/ML")1"0HBU0D0`^VK!`^!0``:\5<C;0"2`$`
+M``^WP6G`*`$```.">`4``(E$)"1F@?_A`74+#[9#)H/H`3P!=BEF@?G_`'0*
MBTPD)/9!)P1U&,9#%`:+="1(QP8`````N`$```#IA`,``(M4)"0/MD(DB<*#
-MX@6#^@5U(8M,)$`/MD$L.D$V<A2+="1(QP8!````N`$```#I40,``(-\)"0`
+MX@6#^@5U(8M,)$`/MD$L.D$R<A2+="1(QP8!````N`$```#I40,``(-\)"0`
M#X3V````@_H%#X7M````B5PD!(M$)"2)!"3H_/___X3`=1C&0Q0$BU0D2,<"
M`````+@!````Z1$#``"+3"0D@'E/'W84BW0D2,<&`0```+@!````Z?,"``#V
-M0V8!=!-KQ5R+5"1`]H0"5`$```%T%^M@:\5<BTPD0/:$`50!```!#X08`@``
+M0V8!=!-KQ5R+5"1`]H0"4`$```%T%^M@:\5<BTPD0/:$`5`!```!#X08`@``
MBW0D*(ET)`2+1"1`B00DZ/S___^$P'04BU0D2,<"`0```+@!````Z9D"``#V
-M0V8!#X3B`0``:\5<BTPD0/:$`50!```!#X3-`0``BW0D)(DT).C\____9H/X
+M0V8!#X3B`0``:\5<BTPD0/:$`5`!```!#X3-`0``BW0D)(DT).C\____9H/X
M'P^&MP$``(M$)$C'``$```"X`0```.E0`@``]D8&`G0U@7PD(.$!$``/A(\!
M``"+5"0D#[9"3SI"3G(HBTPD2,<!`0```+@!````Z1L"``"-M@````"!?"0@
MX0$0``^$6@$``(MT)"0/MT8Z@'LDX0^%2`$``(![)0$/A3X!``#1Z(G"@^(!
-M#[9#)H/H!CP)#X<0`0``#[;`_R2%X`\``,=$)!`!````QT0D#`$```")7"0(
+M#[9#)H/H!CP)#X<0`0``#[;`_R2%@`4``,=$)!`!````QT0D#`$```")7"0(
MBT0D)(E$)`2+5"1`B10DZ/S___^$P`^%[@```(M,)$C'`0(```"X`0```.F'
M`0``QT0D$`$```#'1"0,`````(E<)`B+="0DB70D!(M$)$")!"3H_/___X3`
M#X6J````BU0D2,<"`@```+@!````Z4,!``#'1"00`0````^VPHE$)`R)7"0(
MBTPD)(E,)`2+="1`B30DZ/S___^$P'5KBT0D2,<``@```+@!````Z00!``#'
M1"00``````^VPHE$)`R)7"0(BU0D)(E4)`2+3"1`B0PDZ/S___^$P'4LBW0D
M2,<&`@```+@!````Z<4```#&0Q0$BT0D2,<``````+@!````Z:T```"+1"1`
-M!4`)``")!"3H_/___X3`=!2+5"1(QP(!````N`$```#IA````(![).%U4(![
+M!3P)``")!"3H_/___X3`=!2+5"1(QP(!````N`$```#IA````(![).%U4(![
M)0%U2H![)@]U1(![*0%U/@^V0RC!X`@/ME,G`=`/M\")1"0$BTPD0(D,).C\
M____.T-(=02%P'45QD,4!(MT)$C'!@````"X`0```.LNN`````#K)XGVBU0D
-M0`^V@D$&``!KP%R-M`),`0``BY*T!0``N.P&#0#I4_O__XM<)"R+="0PBWPD
+M0`^V@CT&``!KP%R-M`)(`0``BY*P!0``N.P&#0#I4_O__XM<)"R+="0PBWPD
M-(ML)#B#Q#S#C;0F`````(/L'(M$)"R)1"0,BT0D*(E$)`B+1"0DB40D!(M$
-M)""+`(D$).C\____@\0<PXUV`%575E.#[$R+1"1@BYAH"@``BU0D9&;'0A[_
+M)""+`(D$).C\____@\0<PXUV`%575E.#[$R+1"1@BYAD"@``BU0D9&;'0A[_
M#XU$)#")1"0(B50D!(M,)&")#"3H_/___X3`=`F+3"0PZ4P,``"+="1DBT8D
M)?___P`]X0$0``^%W0```,<$)(@3``#H_/___P^W5A!F@?J%``^'\0L```^W
-MPHM\)&`/MHP'O`0``+C_____@/G_=&)F@_I_=QT/ML&+="1@BY9\!0``:<`H
-M`0``BT00+`^V0`3K/V:!^H$`=QT/ML&+?"1@BY>T!0``:<`4#0``BT00"`^V
-M0`3K&P^VP8MT)&"+EI@%``!IP+````"+1!!4#[9`!`^VP(M\)&`/MH0'0@4`
-M`&O`7(V$!TP!``")1"0<BY>T!0``#[;!:<`4#0```<*)5"0DQT0D(`````#'
-M1"0H`````.ER`0``BT0D9`^W4!"Y_P```&:!^H4`=P\/M\*+="1@#[:,!KP$
+MPHM\)&`/MHP'N`0``+C_____@/G_=&)F@_I_=QT/ML&+="1@BY9X!0``:<`H
+M`0``BT00+`^V0`3K/V:!^H$`=QT/ML&+?"1@BY>P!0``:<`4#0``BT00"`^V
+M0`3K&P^VP8MT)&"+EI0%``!IP+````"+1!!4#[9`!`^VP(M\)&`/MH0'/@4`
+M`&O`7(V$!T@!``")1"0<BY>P!0``#[;!:<`4#0```<*)5"0DQT0D(`````#'
+M1"0H`````.ER`0``BT0D9`^W4!"Y_P```&:!^H4`=P\/M\*+="1@#[:,!K@$
M``"+?"1D#[=W)&:!_N$!=0\/MD<F@^@1/`$/AK@```!F@?J%`'=S#[?"BWPD
-M8`^VA`>\!```//]T8&:#^G]W&0^VP(N7?`4``&G`*`$``(M$$"P/MD`$ZT9F
-M@?J!`'<=#[;`BWPD8(N7M`4``&G`%`T``(M$$`@/MD`$ZR(/ML"+?"1@BY>8
-M!0``:<"P````BT005`^V0`3K!;C_____#[;`BU0D8`^VA`)"!0``:\!<C80"
-M3`$``(E$)!P/M\%IP"@!```#@GP%``")1"0@9H'^X0%U2.LP#[?!:<"P````
-MBTPD8`.!F`4``(E$)"B+<%2)="0<QT0D(`````#'1"0D`````.M)BWPD9`^V
+M8`^VA`>X!```//]T8&:#^G]W&0^VP(N7>`4``&G`*`$``(M$$"P/MD`$ZT9F
+M@?J!`'<=#[;`BWPD8(N7L`4``&G`%`T``(M$$`@/MD`$ZR(/ML"+?"1@BY>4
+M!0``:<"P````BT005`^V0`3K!;C_____#[;`BU0D8`^VA`(^!0``:\!<C80"
+M2`$``(E$)!P/M\%IP"@!```#@G@%``")1"0@9H'^X0%U2.LP#[?!:<"P````
+MBTPD8`.!E`4``(E$)"B+<%2)="0<QT0D(`````#'1"0D`````.M)BWPD9`^V
M5R:-0N\\`78JC4+_/`%V(V:!^?\`=`J+1"0@]D`G!'42BU0D9,9"%`:Y````
M`.GV"0``QT0D)`````#'1"0H`````(U$)$B)1"0$BTPD8(D,).C\____9HE$
M)!J+="1D9HE&'HM\)&")/"3H_/___XG%N0(```"%P`^$J@D``(M$)&2):%0/
-MMU0D&HE4)!1IPK`$``"-/!B-1R"+3"1@*X%H"@``B<+!^A\#@6P*```3D7`*
+MMU0D&HE4)!1IPK`$``"-/!B-1R"+3"1@*X%D"@``B<+!^A\#@6@*```3D6P*
M``"+3"1(B4$@BTPD2(E1)(M%#(M5$(M,)$B)02B+3"1(B5$LBT0D2`^W="0:
M9HEP"+@`````C78`Q@0X`(/``3VP!```=?*+1"1D9H%X).$!=6:)P@^V0":#
MZ!$\`7=9C40D-XE$)`R+1"1(#[9`"(E$)`B)5"0$BTPD((D,).C\____C8<@
-M!```BUPD8"N#:`H``(G"P?H?`X-L"@``$Y-P"@``BTPD2(E!$(M,)$B)413I
+M!```BUPD8"N#9`H``(G"P?H?`X-H"@``$Y-L"@``BTPD2(E!$(M,)$B)413I
M1@$``)"+1"0<#[90!O;"`74KBTPD9(M!)"7___\`/>$!$``/A+8```"+7"0@
M#[9#)(/@!8/X!0^%H@```(MT)&3V1F8@=!*-1"0WB40D!(DT).C\____ZRB-
M1"0WB40D#(M$)$@/MD`(B40D"(M$)&2)1"0$BU0D((D4).C\____C8<@!```
-MBTPD8"N!:`H``(G"P?H?B<L#@6P*```3D7`*``"+3"1(B4$0BTPD2(E1%(GX
-M*X-H"@``B<+!^A^+="1@`X9L"@``$Y9P"@``BTPD2(E!&(M,)$B)41SK:_;"
-M`G1FB?B+5"1@*X)H"@``B<+!^A^+3"1@`X%L"@``$Y%P"@``BTPD2(E!&(M,
-M)$B)41R-AR`$``"+7"1@*X-H"@``B<+!^A\#@VP*```3DW`*``"+3"1(B4$0
+MBTPD8"N!9`H``(G"P?H?B<L#@6@*```3D6P*``"+3"1(B4$0BTPD2(E1%(GX
+M*X-D"@``B<+!^A^+="1@`X9H"@``$Y9L"@``BTPD2(E!&(M,)$B)41SK:_;"
+M`G1FB?B+5"1@*X)D"@``B<+!^A^+3"1@`X%H"@``$Y%L"@``BTPD2(E!&(M,
+M)$B)41R-AR`$``"+7"1@*X-D"@``B<+!^A\#@V@*```3DVP*``"+3"1(B4$0
MBTPD2(E1%(M$)$B`2`$"BT0D9`^V4#V+1"1(9HE0`HM4)&2`>CT`=#R^````
M`+L`````BTT(BT0D9(M01(L$&HD$&8M$&@2)1!D$BT0:"(E$&0B#Q@&#PPR+
M5"1D#[9"/3GP=\Z+3"1DBU$@BT0D2(E0#&:!>23A`751#[9!)H/H$3P!=T8/
@@ -3081,20 +1705,20 @@ MB10DZ/S___^+3"1D]D%F`70*BUPD'(!+"`'K"(MT)!R`9@C^Q@>ABU0D(`^V
M@K8```"#X`\/ME<!@^+P"<*(5P&+3"0@#[=!'(/``6;!P`AFB4<"B<N!PZ``
M``#I@`,``)"+7"1D9H%[).$!#X4Y`@``#[9#)CP/=!*[`````#P0#X5:`P``
MZ;8```"+="1D#[96*,'B"`^V1B<!PHM$)$C&0`0-BT0D2(!@!?Z`3"1'"(M<
-M)$@/MD85BW0D8`^VCN(```#3X&8)0PB+3"1(#[9!`8/@'X/(((A!`8M,)&2+
+M)$@/MD85BW0D8`^VCMX```#3X&8)0PB+3"1(#[9!`8/@'X/(((A!`8M,)&2+
M02J)AS@$``"+02Z)ASP$``!FP<((9HF71`0```^V02F(AT($``#&!Y&+7"0@
M#[=#'(/``6;!P`AFB4<"#[:3M@```(/B#P^V1P&#X/`)T(A'`8M<)""!PZ``
-M``#IGP(``(M4)$B+="1D#[9&%8M<)&`/MHOB````T^!F"4((Q@>!9L='`O__
+M``#IGP(``(M4)$B+="1D#[9&%8M<)&`/MHO>````T^!F"4((Q@>!9L='`O__
MBW0D)`^VEHL```"#X@\/MD<!@^#P"="(1P&+1"1D@W@T`'4.QD`4(;D`````
-MZ80$``"+5"1D]D(G`70NBUHXA=MT)XE<)`2+3"1@BX$$"@``B00DZ/S___^#
+MZ80$``"+5"1D]D(G`70NBUHXA=MT)XE<)`2+3"1@BX$`"@``B00DZ/S___^#
MX`\/ME<!@^+P"<*(5P'K!(M<)"2+="1DBU8T#[9"`;X0````/(!T?#R`=QP\
M%7<2/!!S9(/H`CP!=T*0C70F`.M//!=W-^M7/(6-M@````!T)#R%=PX\@70^
M/(*-="8`=1OK(#R0<A6^*````#R2D'8R/)-U![Z,````ZR>^!````.L@#[9"
M!(TTA0@```#K$[X(````ZPR^#````.L%OAP```")\L'J`HM$)$B(4`2+3"1(
M9L'J"(/B`0^V006#X/X)T(A!!8V7(`0``(M,)&2+032)="0(B40D!(D4).C\
-M____Z38!``"+7"1D#[9#)(/H!#RK=T$/ML#_)(4($```BW0D9`^V1BS!X`@/
+M____Z38!``"+7"1D#[9#)(/H!#RK=T$/ML#_)(6H!0``BW0D9`^V1BS!X`@/
MME8MC0P0@_D-=Q:X`0```-/@J=@^``!T"(M$)$B`2`$$BT0D2(!(`0'K"(M$
-M)$B`8`'[BT0D2,9`!`V+1"1(@&`%_HM4)$B+3"1D#[9!%8M<)&`/MHOB````
+M)$B`8`'[BT0D2,9`!`V+1"1(@&`%_HM4)$B+3"1D#[9!%8M<)&`/MHO>````
MT^!F"4((BT0D2(!@`1_&AR`$```&BUPD(('#H````(E<)`2-AR$$``")!"3H
M_/___XE<)`2-AR4$``")!"3H_/___XV/1`0``(M4)&2#PB2+="1DBT8DB8=$
M!```BT($B4$$BT((B4$(BT(,B4$,BU0D((N"J````(F'.`0``(N"K````(F'
@@ -3102,1905 +1726,1905 @@ M/`0``,8'D8M,)"`/MI&V````@^(/#[9'`8/@\`G0B$<!#[=!'(/``6;!P`AF
MB4<"A=L/A(<```"+`XE'!(M#!(E'".MZJ`%T=@^W1"0:B40D#(M$)$B)1"0(
MBUPD9(E<)`2+="0<B30DZ/S____V0V8!=`^+1"1(#[=`",'@`XA$)#B-1"0W
MB40D#(E\)`B+1"1DB40D!(M4)!R)%"3H_/___XM,)&3V068!=`J+7"0<@$L(
-M`>L(BW0D'(!F"/Z+5"1@BX+0!0``BUPD9(M,)!2)'(@/MU0D&F;!Z@4/M](/
-MMUPD&HG9@^$?N`$```#3X(MT)&`)A);4!0``BU0D9(M")"7___\`/>$!$`!U
+M`>L(BW0D'(!F"/Z+5"1@BX+,!0``BUPD9(M,)!2)'(@/MU0D&F;!Z@4/M](/
+MMUPD&HG9@^$?N`$```#3X(MT)&`)A);0!0``BU0D9(M")"7___\`/>$!$`!U
M-(U$)$2)1"0,QT0D"`````")7"0$BTPD'(D,).C\____#[9$)$>#X!^#R$"(
M1"1'Z<$```"+="1D9H%^).$!=44/MD8F@^@1/`%W.HM$)"B)1"0$BU0D8(D4
M).C\____C40D1(E$)`R+3"0H#[9!-(E$)`B)7"0$BUPD'(D<).C\____ZW"+
M="0@B70D!(M$)&")!"3H_/___XU$)$2)1"0,#[9&0HE$)`B)7"0$BU0D'(D4
M).C\____#[96)(G0@^`&@_@&=2[VP@%T*0^V1"1'@^`?@\A@B$0D1P^V5D*#
MXG_!X@0/MT0D1F8E#_@)T&:)1"1&C40D1(E$)`2+3"1@B0PDZ/S___^+1R"+
-M5R2Y`P```(G3"<-T1(E$)`2)5"0(QP0D(`8``.C\____N0,```#K*8MT)&`/
-MMH9!!@``:\!<C80&3`$``(E$)!R+EK0%``"X[`8-`.F-]/__B<B#Q$Q;7E]=
-MPXUV`(V\)P````!55U93@^P<BW0D,,=$)!0`````C;[H````Z:(!``")]HD\
-M).C\____B<.#>$P`=3")-"3H_/___XE#3(7`=2&-EN@```"+AN@```")6`2)
-M`XE3!(F>Z````.F(`0``B?:+0R0E____`#WA`1``#X33````#[=#$&8]@``/
+M5R2Y`P```(G3"<-T1(E$)`2)5"0(QP0DA`8``.C\____N0,```#K*8MT)&`/
+MMH8]!@``:\!<C80&2`$``(E$)!R+EK`%``"X[`8-`.F-]/__B<B#Q$Q;7E]=
+MPXUV`(V\)P````!55U93@^P<BW0D,,=$)!0`````C;[D````Z:(!``")]HD\
+M).C\____B<.#>$P`=3")-"3H_/___XE#3(7`=2&-EN0```"+AN0```")6`2)
+M`XE3!(F>Y````.F(`0``B?:+0R0E____`#WA`1``#X33````#[=#$&8]@``/
MA,4````/MM!FB5,09H/Z?W839H%[).$!=2(/MD,F@^@1/`%W%V:!^H4`=Q`/
-MM\(/MHP&O`0``(#Y_W48QD,4!HE<)`2)-"3H_/___^GS````C78`#[=K)&:!
-M_>$!=14/MD,FB$0D&X/H$3P!#X?@````ZQ4/ML%IP"@!```#AGP%``")1"04
+MM\(/MHP&N`0``(#Y_W48QD,4!HE<)`2)-"3H_/___^GS````C78`#[=K)&:!
+M_>$!=14/MD,FB$0D&X/H$3P!#X?@````ZQ4/ML%IP"@!```#AG@%``")1"04
MZPP/MD0D&X/H`3P!=C5F@?J``'0N9H']X0%U"P^V0R:#Z!$\`78<BT0D%/9`
M)P1U$L9#%`:)7"0$B30DZ/S____K>HE<)`2)-"3H_/___X/X`G<+@_@!<R:-
M="8`ZQ"#^`-U68GVC;PG`````.M!B5PD!(DT).C\____B?;K/H-[5`!T#XU#
-M5(E$)`2)-"3H_/___XV6Z````(N&Z````(E8!(D#B5,$B9[H````ZS.)7"0$
-MB30DZ/S___^0.;[H````#X54_O__ZQ@/ML%IP"@!```#AGP%``")1"04Z1__
+M5(E$)`2)-"3H_/___XV6Y````(N&Y````(E8!(D#B5,$B9[D````ZS.)7"0$
+MB30DZ/S___^0.;[D````#X54_O__ZQ@/ML%IP"@!```#AG@%``")1"04Z1__
M__^#Q!Q;7E]=PXGV@^P\B5PD+(ET)#")?"0TB6PD.(M\)$"+=RR++@^V1@BH
M$'0,QH>T````!NFB`@``#[:7M````(#Z`0^$@P```(#Z`7(;@/H$#X2J````
M@/H&#X7A`@``Z78"``"-="8`QH>T`````8E\)`2)+"3H_/___XM$)$3&0!2!
-M@$X("(-X5`!T$XM$)$2#P%2)1"0$B2PDZ/S___^+A>@```"+5"1$B5`$B0*-
-MA>@```")0@2)E>@```")+"3H_/___^EU`@``@^#WB$8(@(>W`````<:'M```
+M@$X("(-X5`!T$XM$)$2#P%2)1"0$B2PDZ/S___^+A>0```"+5"1$B5`$B0*-
+MA>0```")0@2)E>0```")+"3H_/___^EU`@``@^#WB$8(@(>W`````<:'M```
M``"+3"1$QD$4`HE,)`2)+"3H_/___XDL).C\____Z4`"``#&A[<`````BT0D
M1(-X5`!T#X/`5(E$)`2)+"3H_/___XM/((7)#X2O`0``BU$$C4(!B4$$@_HH
-M#X>=`0``BX7H````BU0D1(E0!(D"C87H````B4($B97H````@'\F_W0FBT<T
+M#X>=`0``BX7D````BU0D1(E0!(D"C87D````B4($B97D````@'\F_W0FBT<T
MA<!T!H!X)@!T&8E\)`C'1"0$`@```(DT).C\____Z;D!```/MD8(@^#W@\@0
MB$8(BU<PA=)U#8!^"@!U,.D"`0``B?;'1"00`````,=$)`P"````#[9'38E$
M)`B)5"0$B30DZ/S____I;P$``,=$)"``````QD0D)P"-3CB)3"0<BT0D'(D$
-M).C\____B40D*(M&/(M4)"B)5CR+3"0<B0J)0@2)$(M"((7`="*)1"0(BX5(
+M).C\____B40D*(M&/(M4)"B)5CR+3"0<B0J)0@2)$(M"((7`="*)1"0(BX5$
M!0``B40D!,<$)`4```#H_/___XM$)"B`2"@"BU0D*(E4)`C'1"0$!@```(DT
M).C\____BTPD*(!Y3P!T0(M<)""#PP&!?"0@?Y:8`'<KB?:)+"3H_/___\<$
M)`$```#H_/___XM$)"B`>$\`=`N#PP&!^X&6F`!UUXE<)""`1"0G`0^V5"0G
M.%8*#X<]____BT<TA<!U&\9')@-FQX>4``````")?"0$B2PDZ/S____K=HD$
-M).C\____C;8`````ZV8/ME\FQP0DQ@$``.C\____@&8([XN%Z````(M,)$2)
-M2`2)`8V%Z````(E!!(F-Z````(E\)`C'1"0$!@```(DT).C\____@/O_=1.)
+M).C\____C;8`````ZV8/ME\FQP0DUP```.C\____@&8([XN%Y````(M,)$2)
+M2`2)`8V%Y````(E!!(F-Y````(E\)`C'1"0$!@```(DT).C\____@/O_=1.)
M?"0(B70D!(DL).C\____C78`B2PDZ/S___^+7"0LBW0D,(M\)#2+;"0X@\0\
-MPXUT)@!55U93@^QLB[0D@````(N6?`4``+C8)@$`BXPDA````&:!>1"%`'<9
-MBYPDA`````^W0Q`/MH0PO`0``&G`*`$``(T\`HN61`H``('"0`@```^V1T+!
-MX`@!PHL*B0T`````B<C!Z!"(1"1`BY9$"@``@<)`"```#[9'0L'@"`'"BT($
-MHP````"(1"18B<+!Z@B(5"19P>@0B$0D6HN61`H``('"0`@```^V1T+!X`@!
+MPXUT)@!55U93@^QLB[0D@````(N6>`4``+C8)@$`BXPDA````&:!>1"%`'<9
+MBYPDA`````^W0Q`/MH0PN`0``&G`*`$``(T\`HN60`H``('"0`@```^V1T+!
+MX`@!PHL*B0T`````B<C!Z!"(1"1`BY9`"@``@<)`"```#[9'0L'@"`'"BT($
+MHP````"(1"18B<+!Z@B(5"19P>@0B$0D6HN60`H``('"0`@```^V1T+!X`@!
MPHM""*,`````B$0D6XG"P>H(B%0D7,'H$(A$)%W&1"1>`,9$)%\`B<W![1@/
-MMEPD0(M$)%R)1"00BT0D6(E$)`R);"0(B5PD!,<$)$P&``#H_/___XG8@_`!
+MMEPD0(M$)%R)1"00BT0D6(E$)`R);"0(B5PD!,<$)+`&``#H_/___XG8@_`!
MB<*#X@%T((!\)$``=!F+E"2$````QD(4`+@`````Z;0"``"-="8`BXPDA```
M`(!Y%(%U,XU$)%B)1"0,B6PD"(E<)`2)#"3H_/___XN<)(0```#&0Q0"N```
M``#I=@(``(VV`````(N,)(0```"+020E____`#WA`0X`=0[&010AN`````#I
M3`(``(N$)(0```#V0&8!=3.$TG4O@'\F_W0IC40D6(E$)`R);"0(B5PD!(N4
M)(0```")%"3H_/___[@`````Z0P"``")?"0$B30DZ/S___^)?"0$B30DZ/S_
M__^+%HN,)(0````/MT$>9L'H!0^WP(T$A0`#``")@G`!``"+!HN<)(0````/
-MMTL>@^$?N@$```")U=/EB:AT`0``#[=#'L'@`@.&T`4``,<```````^W2QZ)
-MR&;!Z`4/M\"#X1^)T]/CB=GWT2&,AM0%``"+K"2$````#[=-'HG(9L'H!0^W
-MP(/A']/B]](A5(9@BU4`BT4$B4($B1`/MT4>C99`"0``B40D!(D4).C\____
+MMTL>@^$?N@$```")U=/EB:AT`0``#[=#'L'@`@.&S`4``,<```````^W2QZ)
+MR&;!Z`4/M\"#X1^)T]/CB=GWT2&,AM`%``"+K"2$````#[=-'HG(9L'H!0^W
+MP(/A']/B]](A5(9<BU4`BT4$B4($B1`/MT4>C98\"0``B40D!(D4).C\____
M@&]/`<9%%(&#?50`=!&)Z(/`5(E$)`2)-"3H_/___XU'$#E'$`^$[````(E$
-M)"R-ED`)``")5"0\BTPD+(D,).C\____B<.+%@^W0!YFP>@%#[?`C02%``,`
-M`(F"<`$```^W2QZ#X1^Z`0```(G5T^6+!HFH=`$```^W0Q[!X`(#AM`%``#'
-M```````/MTL>B<AFP>@%#[?`@^$?B=73Y8GI]]$AC(;4!0``#[=+'HG(9L'H
-M!0^WP(/A']/B]](A5(9@#[=#'HE$)`2+1"0\B00DZ/S___^`;T\!@WM4`'0/
-MC4-4B40D!(DT).C\____C9;H````BX;H````B5@$B0.)4P2)GN@```"+5"0L
+M)"R-ECP)``")5"0\BTPD+(D,).C\____B<.+%@^W0!YFP>@%#[?`C02%``,`
+M`(F"<`$```^W2QZ#X1^Z`0```(G5T^6+!HFH=`$```^W0Q[!X`(#ALP%``#'
+M```````/MTL>B<AFP>@%#[?`@^$?B=73Y8GI]]$AC(;0!0``#[=+'HG(9L'H
+M!0^WP(/A']/B]](A5(9<#[=#'HE$)`2+1"0\B00DZ/S___^`;T\!@WM4`'0/
+MC4-4B40D!(DT).C\____C9;D````BX;D````B5@$B0.)4P2)GN0```"+5"0L
M.5<0#X4B____BXPDA````(%A9/___O_&A[0````$B4PD!(D\).C\____N`$`
M``"0C70F`(/$;%M>7UW#D(VT)@````!55U93@^Q,#[=L)&2+5"1HB50D,(M$
-M)&R)1"0TBWPD8(LWBX9H"@``B40D%`M4)#0/A(L"```/M]5IPK`$``"+7"04
-MC0P8]D$A`G05C025``````.&T`4``(L`QD`4`NL3C025``````.&T`4``(L`
-MQD`4(<'B`HE4)"R)T`.&T`4``(L0BT(D)?___P`]X0$0``^$B@$```^W0A!F
-M/84`=P\/M\`/MH0&O`0``#S_=16+1"0L`X;0!0``BP#&0!0&Z2X(```/ML!I
-MP"@!```#AGP%``")1"08@'PD,P!Y70^V4"2)T(/@!H/X!G4?]L(!=!J+!HN0
+M)&R)1"0TBWPD8(LWBX9D"@``B40D%`M4)#0/A(L"```/M]5IPK`$``"+7"04
+MC0P8]D$A`G05C025``````.&S`4``(L`QD`4`NL3C025``````.&S`4``(L`
+MQD`4(<'B`HE4)"R)T`.&S`4``(L0BT(D)?___P`]X0$0``^$B@$```^W0A!F
+M/84`=P\/M\`/MH0&N`0``#S_=16+1"0L`X;,!0``BP#&0!0&Z2X(```/ML!I
+MP"@!```#AG@%``")1"08@'PD,P!Y70^V4"2)T(/@!H/X!G4?]L(!=!J+!HN0
M6`$``(D5`````(72=`B+!HF06`$``(L&BX!0`0``HP````"#R`*+%HF"4`$`
M`(L&BX`$`0``HP````"`S/^+%HF"!`$``&;W02`""`^$X0```(!^*P`/A-<`
M``#&1"0?`+L`````C78`B=H/MLL/MD<)T_BH`71'@/L#=AR+!@70`0``C02(
MBP"C`````,'H%(/@`>L:C78`BP8%T`$``(T$B(L`HP````#!Z!2#X`&$P'0+
MN`$```#3X`A$)!^#PP&-0@$X1BMWGX!\)!\`=&(/MD0D'SA'"758B>AFP>@%
-M#[?`B>F#X1^Z`0```-/BA52&8'4]BU0D&("ZM`````)W!\:"M`````.+1"0L
-M`X;0!0``BP")1"0$BTPD&(D,).C\____Z=(&``#'1"08`````/9$)#,!#X2_
-M!@``BT0D+`.&T`4``(L(QD$4(8M!)"7___\`/>$!#@`/A)P&``"+ED0*``"!
-MPD`(``"+7"08#[9#0L'@"`'"BP*C`````(N61`H``('"1`@```^V0T+!X`@!
-MPHL"HP````"+ED0*``"!PD@(```/MD-"P>`(`<*+`J,`````B4PD!(DT).C\
-M____Z3,&```/M_V-++T`````BX;0!0```>B+$&:!>B3A`0^%!P$```^V6B:`
+M#[?`B>F#X1^Z`0```-/BA52&7'4]BU0D&("ZM`````)W!\:"M`````.+1"0L
+M`X;,!0``BP")1"0$BTPD&(D,).C\____Z=(&``#'1"08`````/9$)#,!#X2_
+M!@``BT0D+`.&S`4``(L(QD$4(8M!)"7___\`/>$!#@`/A)P&``"+ED`*``"!
+MPD`(``"+7"08#[9#0L'@"`'"BP*C`````(N60`H``('"1`@```^V0T+!X`@!
+MPHL"HP````"+ED`*``"!PD@(```/MD-"P>`(`<*+`J,`````B4PD!(DT).C\
+M____Z3,&```/M_V-++T`````BX;,!0```>B+$&:!>B3A`0^%!P$```^V6B:`
M^Q`/AP8&``"X`0```(G9T^"IP#````^%TP```*D```$`=5'VQ(`/A.(%``!I
-MQ[`$``"+7"04C0P8#[9!,XA"%(GH`X;0!0``BP#V0!,$#X2Z!0``@'@4``^$
-ML`4``(M0.(72#X2E!0``#[9!,X@"Z9H%``!IQ[`$``"+5"04C3P0B>@#AM`%
-M``"+$`^V1RJ(0A2)Z`.&T`4``(L`@W@T``^$:`4```^VAR$$``")!"3H_/__
-M_XGJ`Y;0!0``BQ*+4B")PSG0=@*)TXU7*(GH`X;0!0``BP"+0#2)7"0(B50D
-M!(D$).C\____Z1\%``")Z`.&T`4``(L`QD`4`.D,!0``B>@#AM`%``"+`(E$
-M)""+2$B)3"0DN/____^+7"0@9H%[$(4`=Q:)Z`.&T`4``(L`#[=`$`^VA#"\
-M!```#[;`:<`H`0``BYY\!0```</&@[0`````#[93)(G0@^`&@_@&#X5T`0``
+MQ[`$``"+7"04C0P8#[9!,XA"%(GH`X;,!0``BP#V0!,$#X2Z!0``@'@4``^$
+ML`4``(M0.(72#X2E!0``#[9!,X@"Z9H%``!IQ[`$``"+5"04C3P0B>@#ALP%
+M``"+$`^V1RJ(0A2)Z`.&S`4``(L`@W@T``^$:`4```^VAR$$``")!"3H_/__
+M_XGJ`Y;,!0``BQ*+4B")PSG0=@*)TXU7*(GH`X;,!0``BP"+0#2)7"0(B50D
+M!(D$).C\____Z1\%``")Z`.&S`4``(L`QD`4`.D,!0``B>@#ALP%``"+`(E$
+M)""+2$B)3"0DN/____^+7"0@9H%[$(4`=Q:)Z`.&S`4``(L`#[=`$`^VA#"X
+M!```#[;`:<`H`0``BYYX!0```</&@[0`````#[93)(G0@^`&@_@&#X5T`0``
M]L(!#X1K`0``BWPD(,9'%`#V1V8@#X2+!```@WPD)``/A(`$``"+1"0D]D!E
M`@^$K````(M7((72#X2A````BTA8A<ET&(M'-(E4)`B)1"0$B0PDZ/S____I
M@@```(M4)""#>C0`='B+3"0D@WEH`'4&@WEL`'1HBWPD((MO-(M4)"2+0FB%
-MP'0(B<?V0F4!="V+3"0DBT%LBY9(!@``QT0D"`$```")5"0$B0PD_]"_````
-M`(7`=`:+OD@&``"+1PB+%XE4)`B);"0$B00DZ/S___\#+XM'!(/'$(7`=-^+
-MED0*``"!PD`(```/MD-"P>`(`<*+`J,`````B<+!ZA"+?"0DB%=3P>@89HE'
-M2(N61`H``('"1`@```^V0T+!X`@!PHL2B14`````#[;"9HE'3`^VQF:)1TZ)
-MT,'H$`^VP&:)1U#!ZAB(5U*+ED0*``"!PDP(```/MD-"P>`(`<*+`J,`````
-M#[;`9HE'2NDR`P``:<>P!```BU0D%(T\$`^V1S.$P`^%S````(GH`X;0!0``
+MP'0(B<?V0F4!="V+3"0DBT%LBY9$!@``QT0D"`$```")5"0$B0PD_]"_````
+M`(7`=`:+OD0&``"+1PB+%XE4)`B);"0$B00DZ/S___\#+XM'!(/'$(7`=-^+
+MED`*``"!PD`(```/MD-"P>`(`<*+`J,`````B<+!ZA"+?"0DB%=3P>@89HE'
+M2(N60`H``('"1`@```^V0T+!X`@!PHL2B14`````#[;"9HE'3`^VQF:)1TZ)
+MT,'H$`^VP&:)1U#!ZAB(5U*+ED`*``"!PDP(```/MD-"P>`(`<*+`J,`````
+M#[;`9HE'2NDR`P``:<>P!```BU0D%(T\$`^V1S.$P`^%S````(GH`X;,!0``
MBP#&0!0`BTPD(/9!9A`/A/T"``"#?"0D``^$\@(```^V1S.+7"0DB$-*]D-E
M`@^$W0(``(-Y(``/A-,"``"#>V@`=0^#>VP`D(UT)@`/A+X"``"+1"0@BW@T
-MBU0D)(M":(7`=`B)P_9"90%T,(M,)"2+06R+ED@&``#'1"0(`0```(E4)`2)
-M#"3_T+L`````A<!T"8N>2`8``(UV`(M#"(L3B50D"(E\)`2)!"3H_/___P,[
+MBU0D)(M":(7`=`B)P_9"90%T,(M,)"2+06R+ED0&``#'1"0(`0```(E4)`2)
+M#"3_T+L`````A<!T"8N>1`8``(UV`(M#"(L3B50D"(E\)`2)!"3H_/___P,[
MBT,$@\,0A<`/A4\"``#KV3P"#X4)`@``#[9/0(M'.(E$)$0/ME0D1P^V1"1$
MP>`8"<(/MD0D1<'@$`G"#[9$)$;!X`B)TPG#@^%_@/EQ=C;&1"0I`(/[`78+
M#[9'08/@#XA$)"G&1"0J`(/[`G8(#[970HA4)"J#^P-V7`^V3T.(3"0KZU?&
M1"0I`(/[`G8+#[9'0H/@#XA$)"G&1"0J`,9$)"L`@_L'=C,/MD='@\`(.<-V
M`HG#QD0D*@"#^PQV"`^V5TR(5"0J@_L-=@H/MD]-B$PD*^L%QD0D*P")Z`.&
-MT`4``(L`@'@<`'1#A=MT/\9`%"")Z`.&T`4``(L`#[9`'#C8<P,/MMB)Z`.&
-MT`4``(L`BU`XA=)T(XU'0(E<)`B)1"0$B10DZ/S____K#HGH`X;0!0``BP#&
-M0!0B@'PD*01U#HGH`X;0!0``BP#&0!0"BT0D(#EP&`^$_0```(-\)"0`#X3R
+MS`4``(L`@'@<`'1#A=MT/\9`%"")Z`.&S`4``(L`#[9`'#C8<P,/MMB)Z`.&
+MS`4``(L`BU`XA=)T(XU'0(E<)`B)1"0$B10DZ/S____K#HGH`X;,!0``BP#&
+M0!0B@'PD*01U#HGH`X;,!0``BP#&0!0"BT0D(#EP&`^$_0```(-\)"0`#X3R
M````]D!F$'1&#[9',XM4)"2(0DKV0F4"=#6+3"0@#[91'(G8.--V`HG0A,!T
M(8M<)"2+2V"%R706#[;`C5=`B40D"(E4)`2)#"3H_/___X!\)"D+=UD/MD0D
-M*?\DA;@2``"+?"0DQD=F`>F&````@'PD*@1U$8!\)"L"=0J+1"0DQD!F$>MN
+M*?\DA5@(``"+?"0DQD=F`>F&````@'PD*@1U$8!\)"L"=0J+1"0DQD!F$>MN
MBU0D),9"9@+K9(M,)"3&0680ZUJ+7"0DQD-F"^M0BWPD),9'9@;K1HM$)"3&
-M0&8-ZSP\*'4:#[9#3X/H`8A#3HGH`X;0!0``BP#&0!2!ZQX\"'4,QP0D$"<`
-M`.C\____B>@#AM`%``"+`,9`%"&#Q$Q;7E]=PXUT)@!55U93@>R<````BZPD
-ML`````^WA98+``!FB40D?HM%`(N`0`$``*,`````9B7_#V:)A98+``!F.T0D
-M?G5NBT4`BXA0`0``B0T`````BT4`B8A0`0``N`````#WP0#__P`/A#H)``")
-M3"0$QP0DY`$``.C\____BY0DL````(D4).C\____N`$```#I$0D``)"+10"+
-M@$`!``"C`````&8E_P]FB866"P``ZQ6-C?````")3"14C9U`"0``B5PD4)"+
-MA;`*``"+`*,`````#[>-E@L``"7_#P``#[?1.=!UL&:!^?\/#X45"```Z2((
-M``"+M6@*``!F@T0D?@$/MWPD?F8[O9H+```9P"''9HE\)'Z+E;`*``"#P@0/
-MM\>+%(*)U\'O$/?'"`````^$KP```(M%`(N04`$``(D5`````(M%`(F04`$`
-M`/?"`/__`'1A@'TK`'1;]L8!=3*^`````/?"```!`'0]ZR.0C70F``^WQHU(
-M"+L!````B=_3YX7Z=1"-2!#3XX7:=0?K&+X`````#[?&:\!<C9P%3`$``(7;
-M=2+K#(/&`0^V12MF.?!WOHN$)+````")!"3H_/___^DZ!P``BY0DL````(D4
-M).C\____B$,+Z2,'``"-=@")T6:!X?\/9HE,)$X/M]F)7"1$:<.P!```BTP&
-M((M<!B2)C"2`````B9PDA````(MT)$3!Y@*+A=`%```!\(L`B40D>(7`#X7$
-M`0``B4PD$(E<)!2)5"0,BUPD1(E<)`B)7"0$QP0DF`8``.C\____9H-]7``/
-MA*4&``#&A"2+``````^VO"2+````C02]`````(E$)%@#A=`%``"+$(72#X1(
-M`0``:?>P!````[5H"@``BYT@"@``#[9"%8E$)`R)?"0(B50D!,<$)/\!``#H
-M_/___XM$)%@#A=`%``"+`(D$).C\____BX8L!```BY8H!```BXXD!```B[8@
-M!```B40D%(E4)!")3"0,B70D"(E\)`3'!"34!@``Z/S___^)^,'@!@'#BU,T
-MB50D2(M3,(M++(MS*(M[)(M#((E$)%R+0QR)1"1@BT,8B40D9(M#%(E$)&B+
-M0Q")1"1LBT,,B80DE````(M#"(F$))````"+0P2)A"2,````BQN+1"1(B40D
-M.(E4)#2)3"0PB70D+(E\)"B+5"1<B50D)(M,)&")3"0@BWPD9(E\)!R+1"1H
-MB40D&(M4)&R)5"04BXPDE````(E,)!"+O"20````B7PD#(N$)(P```")1"0(
-MB5PD!,<$)/P&``#H_/___X"$)(L````!#[:$)(L```!F.T5<#X,8!0``Z7;^
-M__^-=@#WQR`````/A(<!``"+5"1X@'H4@0^%5P$``,9"%"$/MT(>P>`"`X70
-M!0``QP``````#[=*'HG(9L'H!0^WP(/A'[H!````B=/3XXG9]]$AC(74!0``
-MBWPD>`^W3QZ)R&;!Z`4/M\"#X1_3XO?2(52%8`^W1QZ)1"0$BT0D4(D$).C\
-M____@W]4`'01B?B#P%2)1"0$B2PDZ/S___^+3"1X#[=1$&:!^H4`#X?"````
-M#[?"#[:$!;P$```\_P^$KP```&:#^G]W&P^VP&G`*`$```.%?`4``(M`+(!X
-M!/\/E<#K5XM<)'@/MT,09CV!`'<C#[?`#[:$*+P$``!IP!0-```#A;0%``"+
-M0`B`>`3_#Y7`ZR:+?"1X#[='$`^VA"B\!```:<"P`````X68!0``BT!4@'@$
-M_P^5P(3`=#.+1"1XB40D!(DL).C\____C97H````BX7H````BTPD>(E(!(D!
-MB5$$B8WH````Z9\#``"+7"14BU,$BT0D>(/`"(E#!(M\)'B)7PB)4`2)`NE]
-M`P``#[=$)$YFP>@%#[?`B40D<`^W7"1.B=F#X1^X`0```-/@B40D=(M4)'"%
-M1)5@#X5*`P``B?`#A=`%``"+``^W4!!F@?J%``^'GP````^WP@^VA`6\!```
-M//\/A(P```!F@_I_=Q@/ML!IP"@!```#A7P%``"+0"P/MD`$ZUV)\`.%T`4`
-M`(L`#[=`$&8]@0!W(`^WP`^VA"B\!```:<`4#0```X6T!0``BT`(#[9`!.LI
-MB?`#A=`%``"+``^W0!`/MH0HO`0``&G`L`````.%F`4``(M`5`^V0`0\_W0-
-M#[;`@+P%0@4``/]U.XM<)'2+3"1PA5R-8`^%@`(``(M\)'C&1Q0&B3PDZ/S_
-M___'1"0(`````(E\)`2)+"3H_/___^E7`@``#[:$!4(%``!KP%R-A`5,`0``
-MBY0DA`````N4)(````!T'O?'`@```'46QX0D@`````````#'A"2$````````
-M`/9`!@(/A%D!``"+E"2`````BXPDA````(E4)`B)3"0,B5PD!(D$).C\____
-MBUPD=(M,)'"%7(U@#X79`0``BWPD>(!_%($/A8L````/MT<>P>`"`X70!0``
-MQP``````#[=/'HG*9L'J!0^WTH/A'[C^____T\`AA)74!0``#[=''HE$)`2+
-M1"10B00DZ/S___^)?"0$B2PDZ/S___^#?U0`=!&)^(/`5(E$)`2)+"3H_/__
-M_XV5Z````(N%Z````(M,)'B)2`2)`8E1!(F-Z````.E``0``BX7P````.T0D
-M5'1/NP````"#PP&+`#E$)%1U]83;=#N^`````(M\)%2)/"3H_/___XU(^(M7
-M!(E'!(DXB5`$B0([3"1X=06^`0```(#K`774B?"$P`^%Y0```(M,)%2+402+
-M1"1X@\`(B4$$BUPD>(E+"(E0!(D"BT0D=(M\)'`)A+V@````Z;0```"+E"2`
-M````BXPDA````(E4)`B)3"0,B5PD!(D$).C\____BX7P````.T0D5'1/NP``
-M``"#PP&+`#E$)%1U]83;=#N^`````(M,)%2)#"3H_/___XU(^(M\)%2+5P2)
-M1P2).(E0!(D".TPD>'4%O@$```"`ZP%UT(GPA,!U-XM4)'B`>A2!="V+3"14
-MBU$$BT0D>(/`"(E!!(M<)'B)2PB)4`2)`HM$)'2+?"1P"82]H````)`/MU0D
-M?F8YE98+```/A=[W__]F@;V6"P``_P]T(8N%L`H``(L`HP`````E_P\```^W
-ME98+```YT`^%@O?__XV%\````#F%\````'1'B<:)-"3H_/___X/H"`^W2!Z)
-MRV;!ZP4/M]N#X1^Z_O___]/"(92=H````,=$)`@`````B40D!(DL).C\____
-M.;7P````=;N)+"3H_/___[@!````@<2<````6UY?7<.0C70F`(/L'(E<)`R)
-M="00B7PD%(EL)!B+1"0@BYA(!0``BT,$BRB)+0````#WQ0```)!T:(M#!(DH
-MZV&!P\P,``"+`XN04`$``(D5`````(L#B9!0`0``A=)T-_?"````$'09BP/'
-M@%`!```````0BP.+@%`!``"C`````(L#QX!0`0```0```(D<).C\____`<>#
-MQ@&#_@)UH>L,OP````"^`````.N9B?B$P`^5P(7M#Y7""=`/ML"+7"0,BW0D
-M$(M\)!2+;"08@\0<PXVT)@````!55U93@^PLBW0D0(L&BX!0`0``B40D%*,`
-M````BP:+5"04B9!0`0``]T0D%`#__P`/A+$'``"`?BL`#X2G!P``QD0D*P`/
-MMFPD*XU-"+@!````B<+3XH54)!1U#XU-$-/@A40D%`^$:0<``(!\)"L#=AZ+
-M!@6``0``C03HBP"C`````,'H$X/@`>L<D(UT)@"+!@6``0``C03HBP"C````
-M`,'H$X/@`83`=!N)-"3H_/___XGHP>`&C02H@8P&Q`L`````"`"+%H!\)"L#
-M=A6-A.J``0``BP"C`````"4```$`ZQ.-A.J``0``BP"C`````"4```$`A<!T
-M*X!\)"L#=A*-A.J``0``QP````$`Z?T&``"-A.J``0``QP````$`Z>L&``"`
-M?CD!#X77!0``@'PD*P-V&8L&!8`!``"-!.B+`*,`````@^`!ZQ>-=@"+!@6`
-M`0``C03HBP"C`````(/@`83`#X1D`0``B>C!X`:-'*B-A![("P``BU84B40D
-M!(D4).C\____BX0>I`L``(7`=!V+4"B%TG06]D(R`G40B00DZ/S___^$P`^%
-M'@$``(GHP>`&C02HBX0&I`L``(7`#X2'````B40D)(!X"@`/A*4```#&1"0C
-M`(G'@\<XB3PDZ/S___^)PXM'!(E?!(D[B4,$B1CV0R@"=3V+4R"%TG0>BX9(
-M!0``B50D"(E$)`3'!"0%````Z/S___^`2R@"B5PD",=$)`0&````BTPD)(D,
-M).C\____@$0D(P$/MD0D(XM4)"0X0@IV+NN1#[9$)"O'1"0(`0```(E$)`2)
-M-"3H_/___\<$)*"&`0#H_/___[H`+3$!ZP6Z0$M,`(GHP>`&C1RHC0PSB9'(
-M"P``QX'0"P``P%8"``^V1"0KB<+!X@:-A(*0"P``C40&#(F!U`L``(V$'L@+
-M``"+5A2)1"0$B10DZ/S___^-=@"`?"0K`W8OC13M`````(L&!8`!```!T(L`
-MHP````"+!@6``0```<*+`J,`````P>@'@^`!ZRV-%.T`````BP8%@`$```'0
-MBP"C`````(L&!8`!```!PHL"HP````#!Z`>#X`&$P'1;@'PD*P-V*HT,[0``
-M``"+!@6$`0```<B+`*,`````BQ:!PH0!```!T0T```$`B0'K,8T,[0````"+
-M!@6$`0```<B+`*,`````BQ:!PH0!```!T0T```$`B0'K((!\)"L#=AF+!@6`
-M`0``C03HBP"C`````,'H$H/@`>L7BP8%@`$``(T$Z(L`HP````#!Z!*#X`&$
-MP`^$WP$``(!\)"L#=BJ-#.T`````BP8%@`$```'(BP"C``````T```0`BQ:!
-MPH`!```!T8D!ZRB-#.T`````BP8%@`$```'(BP"C``````T```0`BQ:!PH`!
-M```!T8D!B>C!X`:-!*B+A`:D"P``A<!T#8G%@W@H`'5_Z68!``"`?"0K`Y!V
-M.8T4[0````"+!@6``0```="+"(D-`````(L&!8`!``"-!`*)"(L&!8`!```!
-MPHL"HP````#I7`,``(T4[0````"+!@6``0```="+"(D-`````(L&!8`!``"-
-M!`*)"(L&!8`!```!PHL"HP````#I(P,``(M`*`^W2#(/M]'VQ@$/A=D```")
-MQ_;"`@^$S@```(G(@^#]9HE',HU'<(M6%(E$)`2)%"3H_/___\9$)"L`@'\?
-M``^$?0```,9$)"L`#[9$)"N+7(<\A=MT7(M3((72=!Z+AD@%``")5"0(B40D
-M!,<$)`4```#H_/___X!+*`*)7"0(QT0D!`8```")+"3H_/___X![3P!T'8UV
-M`(DT).C\____QP0D`0```.C\____@'M/`'7F@$0D*P$/MDPD*SA/'W>(QT=P
-M0$M,`,='>`````")?WR-1W"+5A2)1"0$B10DZ/S___^-="8`@'PD*P-V'HL&
-M!8`!```/ME0D*XT4T(L"HP````#!Z`B#X`'K'(L&!8`!```/ME0D*XT4T(L"
-MHP````#!Z`B#X`&$P`^$#@$``(!\)"L#=AZ+!@6``0``#[94)"N-%-"+`J,`
-M````@_`!@^`!ZQR+!@6``0``#[94)"N-%-"+`J,`````@_`!@^`!A,`/A,4`
-M```/MD0D*XG"P>(&C82"D`L``(T$!HU0#(E4)!R+4@B%T@^$GP```(E4)!B#
-MP#B+5A2)1"0$B10DZ/S___^+1"08@'@*`'14O0````")QX/'.(D\).C\____
-MB<.+1P2)7P2).XE#!(D8BU,@A=)T'HN&2`4``(E4)`B)1"0$QP0D!0```.C\
-M____@$LH`H/%`8GJBTPD&#A1"G>VBT0D',=`+("$'@#'0#0`````B4`XBT0D
-M'(/`+(M6%(E$)`2)%"3H_/___X!\)"L#=F0/MEPD*\'C`XL&!8`!```!V(L0
-MB14`````BP8%@`$``(T$`XD0BP8%@`$``(T$`XL`HP````"+!@4P`@``C00#
-MQP``````QP0D$"<``.C\____BP8%-`(```'#BP.C`````.MB#[9<)"O!XP.+
-M!@6``0```=B+$(D5`````(L&!8`!``"-!`.)$(L&!8`!``"-!`.+`*,`````
-MBP8%4`(``(T$`\<``````,<$)!`G``#H_/___XL&!50"```!PXL#HP````"`
-M1"0K`0^V5"0K.%8K#X=>^/__BP:+@%`!``")1"04HP````"+!HM,)!2)B%`!
-M``#WP0#__P!T'>D7^/__B>C!X`:-!*B!C`;$"P`````!`.G]^/__N`````"#
-MQ"Q;7E]=PXUV`(V\)P````!55U93@^Q<BVPD<`^V1"1TB$0D,P^VT(E4)#2)
-MT,'@!HT$D`'HBXBD"P``B4PD/`^VN*(+``"+10"`?"0S`W8,QX!P`0``Q`$`
-M`.L*QX!P`0``J`$``(E$)%@%=`$``(E$)#B+7"18BX-T`0``HP````"+3"0T
-M@^$#NP<```#3XXG>"<:+1"18B;!T`0``QP0DZ`,``.C\____]],A\XM4)%B)
-MFG0!``"`?"0S`W90BTPD-(M<)%B-E(O0`0``BP*C`````(/("(D"B<O!XP.+
-M5"18C80:``(``,<`.````,<$)!`G``#H_/___XM,)%B-A!D$`@``QP``````
-MZU"+7"0TBT0D6(V4F-`!``"+`J,`````@\@(B0*+7"0TP>,#BU0D6(V$&@`"
-M``#'`#@```#'!"00)P``Z/S___^+3"18C809!`(``,<``````(-\)#P`#X1F
-M"```@'TK`'0RNP`````/MLN+5"0\#[9""=/XJ`%T%,=$)`@!````B4PD!(DL
-M).C\____@\,!.%TK=].+3"0\]D$&`71MB4PD!(DL).C\____BUPD-(E<)`2)
-M+"3H_/___XG8P>`&C028C10HBX+`"P``J0``$`!T"R7__^__B8+`"P``BT0D
-M/(E$)`2)+"3H_/___XM$)#3!X`:+5"0TC020QX0%I`L```````#IMP<``(M,
-M)#R`>30`=!J+A00*``")3"0$B00DZ/S___^+7"0\@&LT`;C^____#[9,)#33
-MP(G[(,.(7"1##X22`@``BT0D-(E$)`2)+"3H_/___XM$)#3!X`:+5"0TC020
-MC10HBX+`"P``J0``$`!T"R7__^__B8+`"P``#[9,)$.+7"0\B$L)@'TK``^$
-MK@$``,=$)$P`````#[;!B40D((M4)%B!P@`"``")5"0<#[9,)$R(3"13#[;Y
-MBT0D((GYT_BH`0^$/@$``(T<O0````")7"0LB?C!X`8!V`^V5"1#B)0%H@L`
-M`(!\)%,##X:-````C1S]`````(M$)!P!V,<`.````,<$)!`G``#H_/___XM,
-M)%B-A!D$`@``BUPD((D8QX%P`0``Q`$``(M4)#B+`J,`````B?F#X0.[!P``
-M`-/CB=X)QHDRQP0DZ`,``.C\____]],A\XM,)#B)&8M<)%B+1"0LC90#T`$`
-M`(L"HP````"#R`B)`NF(````C1S]`````(M$)!P!V,<`.````,<$)!`G``#H
-M_/___XM4)%B-A!H$`@``BTPD((D(QX)P`0``J`$``(M<)#B+`Z,`````B?F#
-MX0.[!P```-/CB=X)QHM$)#B),,<$).@#``#H_/____?3(=Z+5"0XB3*+3"18
-MC92YT`$``(L"HP````"#R`B)`H-$)$P!#[9$)%.#P`$X12MV)>F/_O__B1PD
-MZ/S___^-<."+4P2)0P2)&(E0!(D"@WX,`'07ZPR^`````(M<)#R#PRR+1"0\
-M.5@L=<N%]G0XQD8R`(!]*P!T+KD`````N@````"+7"0\#[9#"=/XJ`%T#@^V
-MPHA,!D"`1C(!@\(!@\$!.$TK=]S'1"0(`````,=$)`2!````BT0D/(D$).C\
-M____BT0D-,'@!HM4)#2-!)#'A`6D"P```````(!]*P`/A<T#``#IYP0``,=$
-M)`@`````QT0D!`8```"+3"0\B0PDZ/S___^+7"0TB5PD!(DL).C\____B=C!
-MX`:-!)B-%"B+@L`+``"I```0`'0+)?__[_^)@L`+``"+1"0\@\`LBU0D/#E"
-M+`^$'@(``(E$)!2+3"04B0PDZ/S___^-6.")7"1$C5`(.5`(#X32`0``@\,H
-MB5PD&(M$)!B)!"3H_/___XU8^(![)0UU&HV0_````(M#+(L`BT`4B50D!(D$
-M).C\____BQ.+0P2)0@2)$(![3P!T&HDL).C\____QP0D`0```.C\____@'M/
-M`'7FBT,@A<`/A#H!``#'0&``````@'M/``^$I````&:#?5P`#X29````OP``
-M``"0C70F`(T$O0`````#A=`%``"+,(7V=&T/MT809CM#''5C9CV%`'==#[?`
-M@+PHO`0``/]T4(M5``^W1AYFP>@%#[?`C02%``,``(F"<`$``(M5``^W3AZ#
-MX1^X`0```-/@B8)T`0``QD84(<=$)`@`````B70D!(DL).C\____C;8`````
-M@\<!#[=%7#GX#X]Q____]D,H!'4?B2PDZ/S___^+0R#'1"0(`0```(E$)`2)
-M+"3H_/___XM#(`^V4`(/MD`!B50D"(E$)`3'!"2P`0``Z/S___^+0R"+E4@%
-M``")1"0(B50D!,<$)`$```#H_/___XM#((N52`4``(E$)`B)5"0$QP0D!@``
-M`.C\____QT,@`````(M4)#R`:@H!BTPD1(!I,`&)7"0$B2PDZ/S___^+1"08
-MBUPD1#E#*`^%-?[__XM4)#R`:AP!BTPD1(E,)`2)+"3H_/___XM$)!2+7"0\
-M.4,L#X7F_?__BT0D/(/`.(M4)#PY0C@/A`4!``"^`````(G'B3PDZ/S___^)
-MPX!X3P!T-HU&`8'^?Y:8`'8$B<;K)XG&B2PDZ/S____'!"0!````Z/S___^`
-M>T\`=`N#Q@&!_H&6F`!UVXM#((7`#X2,````QT!@`````/9#*`1U'XDL).C\
-M____BT,@QT0D"`$```")1"0$B2PDZ/S___^+0R`/ME`"#[9``8E4)`B)1"0$
-MQP0DL`$``.C\____BT,@BY5(!0``B40D"(E4)`3'!"0!````Z/S___^+0R"+
-ME4@%``")1"0(B50D!,<$)`8```#H_/___\=#(`````"+3"0\@&D*`8E<)`2)
-M+"3H_/___XM<)#PY>S@/A0+___^+1"0\B40D!(DL).C\____BT0D-,'@!HM4
-M)#2-!)#'A`6D"P```````.DI_/__QT0D2``````/MDPD0XE,)"B+7"18@</0
-M`0``B5PD)`^V?"1(B?@/ML")1"14BT0D*`^V3"14T_BH`74,B?LX7"0S#X7&
-M````B?@\`W9CBU0D6,>"<`$``,0!``"+3"0XBP&C`````(M,)%2#X0.-#$F[
-M!P```-/CB=X)QHM$)#B),,<$).@#``#H_/____?3(?.+5"0XB1J+3"14BUPD
-M)(T4BXL"HP````"#R`B)`NM=BT0D6,>`<`$``*@!``"+5"0XBP*C`````(M,
-M)%2#X0.-#$F[!P```-/CB=X)QHDRQP0DZ`,``.C\____]],AWHM,)#B),8M<
-M)%2+1"0DC128BP*C`````(/("(D"@T0D2`&-1P$X12L/AP#___^#Q%Q;7E]=
-MPY"-M"8`````55=64X/L'(M\)#"+="0T#[9O*XGHA,!T+`^V5@F[`````/;"
-M`703ZQR-M"8`````B=")V=/XJ`%U$(/#`8GH.,-U[>L%NP````#V1@@"=0B-
-M1C@Y1CAU:HDT).C\____A,!T3XD\).C\____B<&%P'10BU8\B48\C48XB0&)
-M402)"H!&"@&)<2S&020%QD$E`,9!30_'1"0,`0```,=$)`@!````B4PD!(DT
-M).C\____ZP\/ML.)1"0$B3PDZ/S___^#Q!Q;7E]=PXVV`````%575E.#[`R+
-M;"0@#[9\)"2)^`^VP(E$)`B)QL'F`KL`````QP0D$"<``.C\____B?J`^@-V
-M&HM%``70`0```?"+`*,`````P>@4@^`!ZQF0BT4`!=`!``"-!`:+`*,`````
-MP>@4@^`!A,!U"H/#`6:!^RP!=:V+1"0(B40D!(DL).C\____B2PDZ/S___^+
-M1"0(P>`&BU0D"(T$D`'H]H"A"P```702BX"D"P``B40D!(DL).C\____@\0,
-M6UY?7</K#9"0D)"0D)"0D)"0D)!55U93@^P<#[9$)#2(1"0:BWPD,`^V\(GP
-MP>`&C02PBZP'I`L``(7M#X2J`0``N/[___^)\=/`A$4)#X68`0``C44L.44L
-M=0V`?0H`=2F)]ND#`P``#[9$)!J)PL'B!HV$@I`+``"-1`<,B00DZ/S____I
-MX0(``,9$)!L`C74XD(DT).C\____B<.+1@2)7@2),XE#!(D8@'LE``^%'P$`
-M``^W0QR#O(>\`@```'41@WL@``^$Z````(VT)@`````/MT,<BX2'O`(``(-X
-M<``/A*T```#&@[0`````#[93)(G0@^`&@_@&=3;VP@%T,<9#)@7&0R<$#[9#
-M38M3,(M++(E<)`R)1"0(B50D!(D,).C\____Z:8```"-M@`````/ME,DB="#
-MX`:#^`1U(O;"`70=QD,F`\9#)P2)7"0$B3PDZ/S____K=XVT)@`````/ME,D
-MB="#X`:#^`9U8O;"`75=QD,G!L9#)@5FQX.4``````")7"0$B3PDZ/S____K
-M/HM#((N72`4``(E$)`B)5"0$QP0D!````.C\____ZQ\/MT,<BY=(!0``B40D
-M"(E4)`3'!"0"````Z/S___^0@$0D&P$/MD0D&SA%"@^&A0$``.FH_O__C2RU
-M`````+L`````QP0D$"<``.C\____@'PD&@-V&8L'!=`!```!Z(L`HP````#!
-MZ!2#X`'K%Y"+!P70`0```>B+`*,`````P>@4@^`!A,!U"H/#`6:!^RP!=;")
-M="0$B3PDZ/S___^)/"3H_/___XGPP>`&C02PB[0'I`L``(7V#X3Y````@'\K
-M`'0TNP````"-M@`````/MLL/MD8)T_BH`704QT0D"`````")3"0$B3PDZ/S_
-M__^#PP$X7RMWUP^V1"0:B<+!X@:-A(*0"P``C40'#(E&&(U&+#E&+'4JC48X
-M.48X=2+K<8D<).C\____C6C@BU,$B4,$B1B)4`2)`H-]#`!T%.L-O0````"-
-M7BR0C70F`#E>+'7.A>UT7\9%,@"`?RL`=%6Z`````+L`````C78`#[9&"8G1
-MT_BH`70.#[;#B%0%0(!%,@&#PP&#P@$X5RMV)NO<]D8&`70.B70D!(D\).C\
-M____ZQ#'1"0$`````(DT).C\____@\0<6UY?7<-55U93@^P,BWPD((L?BV\H
-M#[9S*XGPA,!T5XV#G`L``+D`````.?AU'NM&D(UT)@`/ML&)PL'B!HV$@I`+
-M``"-1`,,.?AT"8/!`8GP.,%UX(#Y`W8ABP,%T`$```^VT8T4D(L"HP````#!
-MZ!2#X`'K'[D`````BP,%T`$```^VT8T4D(L"HP````#!Z!2#X`&$P'05#[;!
-MB6PD"(E$)`2)'"3H_/___^L/#[;!B40D!(D<).C\____@\0,6UY?7<-55U93
-M@^P<BUPD-(M$)#")1"04BWA4BS?V1P@0=`3&0#4&BU0D%`^V0C4\`71U/`%R
-M&3P$#X26````/`:-="8`#X4Z`P``Z:<!``"+3"04QD$U`8E,)`2)-"3H_/__
-M_\9#%(&`3P@(@WM4`'0/C4-4B40D!(DT).C\____C9;H````BX;H````B5@$
-MB0.)4P2)GN@```")-"3H_/___^G=`@``@&<(]XM$)!2`0#8!QD`U`,9#%`*)
-M7"0$B30DZ/S___^)-"3H_/___^FP`@``#[9'"(/@]X/($(A'"(M,)!2+D9@`
-M``"-0@&)@9@```"#^@(/A_D```"#>U0`=`^-0U2)1"0$B30DZ/S___^-EN@`
-M``"+AN@```")6`2)`XE3!(F>Z````(M$)!2`>"8`=0N`?PH`=2+II````,=$
-M)`@`````QT0D!`(```")/"3H_/___^DF`@``QD0D&P"-;SB)+"3H_/___XG#
-MBT4$B5T$B2N)0P2)&(M3((72=!Z+AD@%``")5"0(B40D!,<$)`4```#H_/__
-M_X!+*`*)7"0(QT0D!`8```")/"3H_/___X![3P!T&HDT).C\____QP0D`0``
-M`.C\____@'M/`'7F@$0D&P$/ME0D&SA7"G>!BTPD%(D,).C\____Z8X!``"`
-M9PCWBT0D%,>`F`````````"#>U0`=`^-0U2)1"0$B30DZ/S___^-EN@```"+
-MAN@```")6`2)`XE3!(F>Z````,=$)`@`````QT0D!`8```")/"3H_/___XU'
-M.#E'.`^$E@```(G%C;0F`````(DL).C\____B<.+0""%P'1GQT!@`````(DT
-M).C\____BT,@QT0D"`$```")1"0$B30DZ/S___^+0R"+ED@%``")1"0(B50D
-M!,<$)`$```#H_/___XM#((N62`4``(E$)`B)5"0$QP0D!@```.C\____QT,@
-M`````(E<)`2)-"3H_/___SEO.`^%<____XM4)!2)5"0$B30DZ/S____'1R@`
-M````BP:+D%@!``")%0````"%TG0(BP:)D%@!``#V1P8!=%R`?BL`="&Y````
-M`/9'"0%T#.L4#[9'"=/XJ`%U#X/!`3A.*W?NZP6Y``````^VV8E<)`2)-"3H
-M_/___XE\)`2)-"3H_/___XG8P>`&C1R8QX0>I`L```````")]H/$'%M>7UW#
-MD(VT)@````"#["R)7"0<B70D((E\)"2);"0HBWPD-(MT)#"+1BR)1"08BR@/
-MMT\>B<AFP>@%#[?8@^$?N`$```#3X(5$G6`/A>\#``"+50"-!)T``P``B8)P
-M`0``BT4`BY!T`0``B14`````QD<4(8M')"7___\`/>$!#P!U(8D\).C\____
-MQT0D"`````")?"0$B2PDZ/S____IG`,```^W3QZ#X1^X`0```-/@A<)T%HD\
-M).C\____B2PDZ/S___^-M@`````/MH:T````/`0/AV4#```/ML#_)(7H$@``
-MQH:T`````<=$)`@!````B7PD!(M4)!B)%"3H_/___^DW`P``QH:T`````L=$
-M)`@(````B7PD!(M$)!B)!"3H_/___^D3`P``QH:T`````XET)`C'1"0$(0``
-M`(M4)!B)%"3H_/___XM6,(72="T/MD9-QT0D$`````#'1"0,`0```(E$)`B)
-M5"0$BT0D&(D$).C\____Z<`"``"+5"08#[9""<=$)`@`````B40D!(DL).C\
-M____Z9\"``#&AK0````$@WXP`'1(B70D",=$)`0A````BT0D&(D$).C\____
-M#[9&38M6,,=$)!``````QT0D#`(```")1"0(B50D!(M4)!B)%"3H_/___^E*
-M`@``QT0D"`````#'1"0$(0```(M$)!B)!"3H_/___XM4)!@/MD()QT0D"`$`
-M``")1"0$B2PDZ/S____I#0(``(!^)O]T'8ET)`C'1"0$!@```(M$)!B)!"3H
-M_/___^GJ`0``B70D",=$)`0&````BU0D&(D4).C\____BTX@A<ET$HM1!(U"
-M`8E!!(/Z!0^&N0$``,9&)P'&1B8`@'Y/`'0AC;0F`````(DL).C\____QP0D
-M`0```.C\____@'Y/`'7F@WXP`(GV=!2+5@B+1@R)0@2)$(M&,(!H,`'K$XM6
-M-(72=`P/MD9-QT2"/`````"+%HM&!(E"!(D0BT0D&(!H"@&+EN0```"%TG0;
-M#[:&V0```,=$)`@!````B40D!(D4).C\____BU8PA=)T&`^V1DW'1"0(`0``
-M`(E$)`2)%"3H_/___XM&((7`#X2&````QT!@`````(DL).C\____BT8@QT0D
-M"`$```")1"0$B2PDZ/S___^+1B`/ME`"#[9``8E4)`B)1"0$QP0DL`$``.C\
-M____BT8@BY5(!0``B40D"(E4)`3'!"0!````Z/S___^+1B"+E4@%``")1"0(
-MB50D!,<$)`8```#H_/___\=&(`````")="0$B2PDZ/S___^+5"08@'H%_W1>
-MO@````"`>@H`=#B^`````(M<)!B#PSB-=@")'"3H_/___XM3!(E#!(D8B5`$
-MB0*`>";_=0Z#Q@&)\(M4)!@X0@IWUXGPBU0D&#A""G<0QD(%_XE4)`2)+"3H
-M_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#D(VT)@````!55U93@>R,````B[PD
-MH````(M'5(E$)'B+*(N%L`H``(L`B40D?(E\)`2)+"3H_/___X!_-@%V!,9'
-M-02-7Q0Y7Q0/A+@!``")'"3H_/___XE$)'2+1Q2+5"1TB5`$B0*)6@2)5Q2%
-MT@^$G`,```^W<AZ+3"1XBT$8#[9`!`^V52D/MDTB#[9=(8ET)!2)1"00B50D
-M#(E,)`B)7"0$QP0D5`<``.C\____BT0D=`^W0!Z)1"18:?"P!````[5H"@``
-MBYT@"@``BU0D=(D4).C\____BXXL!```B4PD2(N6*`0``(N.)`0``(NV(`0`
-M`(M$)'0/MT`>B40D!(M$)$B)1"04B50D$(E,)`R)="0(QP0DA`<``.C\____
-MBU0D6,'B!@'3BTLTB4PD2(M3,(M++(MS*(M#)(E$)%R+0R")1"1@BT,<B40D
-M9(M#&(E$)&B+0Q2)1"1LBT,0B40D<(M##(F$)(@```"+0PB)A"2$````BT,$
-MB80D@````(L;BT0D2(E$)#B)5"0TB4PD,(ET)"R+5"1<B50D*(M,)&")3"0D
-MBT0D9(E$)""+5"1HB50D'(M,)&R)3"08BT0D<(E$)!2+E"2(````B50D$(N,
-M)(0```")3"0,BX0D@````(E$)`B)7"0$QP0D_`8``.C\____9H-]7`!U1NGE
-M`0``D(M4)'B+0A@/MD`$#[95*0^V32(/METAQT0D%/___P")1"00B50D#(E,
-M)`B)7"0$QP0D5`<``.C\____Z04"``"^`````(V-0`D``(E,)%"-A>@```")
-M1"1,C;0F``````^WQL'@`@.%T`4``(L8A=L/A&$!```/MT,09CE')`^%4P$`
-M``^WE98+```Y5"1\=$6#P@$/MX6:"P``.<(9P"'"BX6P"@``@\`$BP20J0``
-M"`!U'&8E_P]F.?!U$SE<)'1U$XDL).C\____Z74!```[5"1\=;L/MT,09CV%
-M`(GV#X?Q````#[?`@+P%O`0``/\/A.````"+5"1X@'HT``^%T@```/9"!@$/
-MA,@```"+50`/MT,>9L'H!0^WP(T$A0`#``")@G`!```/MTL>@^$?N@$```")
-MT-/@B<&+10")B'0!```/MT,>P>`"`X70!0``QP``````#[=+'HG(9L'H!0^W
-MP(E$)$B#X1^)T-/@B<'WT8M$)$@AC(74!0``#[=+'HG(9L'H!0^WP(/A']/B
-M]](A5(5@.5PD='0BBP.+4P2)4`2)`HN%Z````(E8!(D#BU0D3(E3!(F=Z```
-M``^W0QZ)1"0$BTPD4(D,).C\____@&\I`8/&`68Y=5P/AWS^__^+1"1X]D`&
-M`717BTPD=(L1BT$$B4($B1")3"0$B3PDZ/S____K.XM4)'B+0A@/MD`$#[95
-M*0^V32(/METAQT0D%/___P")1"00B50D#(E,)`B)7"0$QP0D5`<``.C\____
-M@<2,````6UY?7<-55U93@^QLBXPD@````(N4)(@```")5"1@BX0DC````(E$
-M)&2+`8E$)#P/MX0DA````,'@`HM<)#P#@]`%``"+.&:!?R3A`74W#[9')H/H
-M$3P!=RR+<2B)="1$QT0D0``````+5"1D=6^+1"1$QD`U`,=$)$``````ZUV0
-MC70F`(M<)#R+DWP%``"XV"8!`&:!?Q"%`'<6#[='$(MT)#P/MH0&O`0``&G`
-M*`$```'"B50D0,=$)$0`````BT0D8`M$)&1U$XM$)$#&@+0`````QT0D1```
-M``"`?Q2!=02`80CWBT0D8`M$)&0/A>````#&1Q0`]D=F(`^$J`4``(M'2(7`
-M#X2=!0``B</V0&4"="&+2%B%R70:BU<TA=)T$XM'((E$)`B)5"0$B0PDZ/S_
-M__^+3"0\BY%$"@``@<)`"```BW0D0`^V1D+!X`@!PHL"HP````")PL'J$(A3
-M4\'H&&:)0TB+D40*``"!PD0(```/MD9"P>`(`<*+$HD5``````^VPF:)0TP/
-MML9FB4-.B=#!Z!`/ML!FB4-0P>H8B%-2BY%$"@``@<),"```#[9&0L'@"`'"
-MBP*C``````^VP&:)0TKIW`0``(VV``````^W1QYIP+`$``"+5"0\`X)H"@``
-MB40D2(G%@<4@!```@'\4@'4*QD<4(8VV`````(-\)$``='*+7"1`@WL@``^%
-MP0```(MW((ET)%@/MD--B40D-(M!&`^V2`2+5"0\#[9:*0^V<B(/MD(AB40D
-M!(M$)&"+5"1DB40D'(E4)""+5"18B50D&(M$)#2)1"04B4PD$(E<)`R)="0(
-MQP0DM`<``.C\____ZUV#?"1$`'16BU<@B50D7(M!&`^V2`2+="0\#[9>*0^V
-M=B*+1"0\#[9`(8E$)`2+1"1@BU0D9(E$)!B)5"0<BU0D7(E4)!2)3"00B5PD
-M#(ET)`C'!"3P!P``Z/S___^+10R+50B+302+70`/MW<>B40D%(E4)!")3"0,
-MB5PD"(ET)`3'!"0L"```Z/S___^+3"1(]D$B`0^$Q````(U?/(E<)$R+=U2)
-M="14BT,$#[93`8E$)`B)5"0$QP0D#`(``.C\____@'\\``^$/P$``,9$)%,`
-MC70F``^V="13C01VP>`"BU0D3(M*"`'!B<.+5"14`UH(BT,(B40D.(L#BU,$
-MB40D*(E4)"R+:0B+602+"8M4)#B)5"0<BT0D*(M4)"R)1"04B50D&(EL)!")
-M3"0(B5PD#(ET)`3'!"1<"```Z/S___^`1"13`0^V5"13BTPD3#@1#X:S````
-MZ7C___^+7"1(@'LG``^)H`````^W5QZ)T&;!Z`4/M\`/M]*)1"0(B50D!,<$
-M)"@"``#H_/___XMT)#R+AN`%``"+EMP%``"+CM@%``"+GM0%``")1"00B50D
-M#(E,)`B)7"0$QP0D/P(``.C\____#[=''HE$)`3'!"1;`@``Z/S___^+%@^W
-M1QYFP>@%#[?`C02%``,``(F"<`$``(L6#[=/'H/A'[@!````T^")@G0!``!F
-M@7\DX0%U(@^V1R:#Z!$\`7<7BT0D1(D$).C\____Z?P!``"-M@`````/ME0D
-M8_;"`0^$P@$``(M')"7___\`/>$!#@`/A*\!``"+3"0\BY%$"@``@<)`"```
-MBUPD0`^V0T+!X`@!PHLRB34`````BY%$"@``@<)$"```#[9#0L'@"`'"BRJ)
-M+0````"+D40*``"!PD@(```/MD-"P>`(`<*+&HD=`````(N11`H``('"3`@`
-M`(M,)$`/MD%"P>`(`<*+`J,`````B40D$(E<)`R);"0(B70D!,<$)&P"``#H
-M_/____9'9B`/A,T```"+3TC&0680QD<4((GPP>@0B$%3B?#!Z!AFB4%(B=[!
-MY@B)Z`^VT(T$%F:)04R)WF:!Y@#_B>@/MM2-!!9FB4%.B=K!ZA#!X@B)Z,'H
-M$`^VP`'"9HE14(M<)#R+DT0*``"!PDP(``"+="1`#[9&0L'@"`'"BP*C````
-M``^VP&:)04H/MU%,#[=93@^W25`/M\")5"00B5PD#(E,)`B)1"0$QP0DB0(`
-M`.C\____BT0D/(N01`H``('"0`@```^V1D+!X`@!PL<"`````.MC9H%_).$!
-M=1T/MD<F@^@:/`%W$L<$))0(``#H_/___\9'%"'K/HE\)`2+5"0\B10DZ/S_
-M___K+(VV`````(32>2*+3"0\BP&+B%@!``")#0````"%R70,BUPD/(L#B8A8
-M`0``@\1L6UY?7<.)]E.#[`B+7"04BTPD$`^V0R0Y2QAU03P(=%8\*'12/*B0
-M=$T\B'1)/`IT13PJC70F`'0]/*IT.3R*=#6+@>@```")6`2)`XV!Z````(E#
-M!(F9Z````.L9BY'L````B9GL````C8'H````B0.)4P2)&HD,).C\____@\0(
-M6\.-="8`@^P,BT0D%(E$)`2+1"00B00DZ/S___^#Q`S#D(UT)@!3@^Q8BUPD
-M8(U$)$J)1"0TC40D3(E$)#"-1"1$B40D+(U$)$:)1"0HC40D4(E$)"2-1"12
-MB40D((U$)%.)1"0<C40D3HE$)!B-1"14B40D%(U$)$B)1"00C40D58E$)`R-
-M1"16B40D"(U$)%>)1"0$#[=#)(D$).C\____#[9$)%>)1"0(#[9$)%:)1"0$
-MC40D0(D$).C\____QT0D#`$````/MD0D5VG`*`$``(E$)`B+0Q")1"0$C8-D
-M!0``B00DZ/S____'1"0,`0````^V1"15:<"P````B40D"(M#$(E$)`2-@X`%
-M``")!"3H_/___\=$)`P!````#[9$)%9IP!0-``")1"0(BT,0B40D!(V#G`4`
-M`(D$).C\____QT0D#`$````/MT0D4,'@`HE$)`B+0Q")1"0$C8.X!0``B00D
-MZ/S____'1"0,`0````^W1"1(:\!PB40D"(M#$(E$)`2-@V0&``")!"3H_/__
-M_\=$)`P!````#[9$)%0/MU0D2`^OPHT$0,'@`HE$)`B+0Q")1"0$C8,4!@``
-MB00DZ/S____'1"0,`0```,=$)`@``@``BT,0B40D!(V#,`8``(D$).C\____
-M#[9$)%>)1"0,QT0D"``(``"+0Q")1"0$C8,,!P``B00DZ/S____'1"0,`0``
-M``^V1"13C02`P>`"B40D"(M#$(E$)`2-@YP&``")!"3H_/___\=$)`P!````
-MQT0D"*````"+0Q")1"0$C8.X!@``B00DZ/S____'1"0,`0````^V1"12:<"8
-M````B40D"(M#$(E$)`2-@]0&``")!"3H_/___\=$)`P!````#[=$)$Z-!$#!
-MX`.)1"0(BT,0B40D!(V#\`8``(D$).C\____QT0D#`$````/MT0D4`'`B40D
-M"(M#$(E$)`2-@R0)``")!"3H_/___\=$)`P!````#[9$)%<!P(E$)`B+0Q")
-M1"0$C8-,"0``B00DZ/S____'1"0,`0````^V1"15`<")1"0(BT,0B40D!(V#
-M=`D``(D$).C\____QT0D#`$````/MD0D5@'`B40D"(M#$(E$)`2-@YP)``")
-M!"3H_/___\=$)`P!````#[9#)@'`B40D"(M#$(E$)`2-@\0)``")!"3H_/__
-M_\=$)`P!````#[=$)$;!X`6)1"0(BT,0B40D!(V#@`8``(D$).C\____QT0D
-M#`$```"+1"1`B40D"(M#$(E$)`2-@^P)``")!"3H_/___\=$)!`!````QT0D
-M#$`````/MT0D4,'@!HE$)`B+0Q")1"0$C8,("@``B00DZ/S____'1"00`0``
-M`,=$)`P``0``QT0D"``9``"+0Q")1"0$C8,L"@``B00DZ/S____'1"00`0``
-M`,=$)`R`````#[=$)%!IP+`$``")1"0(BT,0B40D!(V#4`H``(D$).C\____
-MQT0D$`$```#'1"0,!`````^W1"1,P>`"B40D"(M#$(E$)`2-@W0*``")!"3H
-M_/___\=$)!`!````QT0D#`0````/MT0D2L'@`HE$)`B+0Q")1"0$C8.8"@``
-MB00DZ/S____'1"00`0```,=$)`P(````#[9$)%/!X`N)1"0(BT,0B40D!(V#
-MO`H``(D$).C\____QT0D$`$```#'1"0,"````,=$)`@```@`BT,0B40D!(V#
-MX`H``(D$).C\____QT0D$`$```#'1"0,"`````^W1"1.:<",`0``B40D"(M#
-M$(E$)`2!PP0+``")'"3H_/___[@`````@\186\.-=@"#["R)7"0<B70D((E\
-M)"2);"0HBVPD,(M%`(E$)!2-72R)'"3H_/___XG&C5#@B50D&(M$)!2)!"3H
-M_/___XG'BT4PB74PBU0D&(E:((E")(DPN`$```"%_P^$@````,9').'&1R4!
-MQD<F$(!/)P&+5"0TBX*<````B4=(BT=,B5`<B=`%D````(E'.,9'%<R+5"08
-M#[9",V:)1Q"+10")1QC'1R"0````BT0D-(E'-,=';/`-`@#'1"0$`````(U'
-M/(D$).C\____B7PD!(M4)!2)%"3H_/___[@`````BUPD'(MT)""+?"0DBVPD
-M*(/$+,.-M@````"-O"<`````55=64X/L'(MT)##'1"08`````(M4)!@/MH0R
-M0@4``#S_#X3,````#[;0:\)<C8P&3`$``(E,)!2`O`96`0````^$K0```+\`
-M````B40D$(VL!H0!``"-A`9``0``B40D#(DL).C\____B<.+1"00`?"+D(@!
-M``")F(@!``")*XE3!(D:BT,@A<!T'HE$)`B+AD@%``")1"0$QP0D!0```.C\
-M____@$LH`HE<)`C'1"0$`@```(M$)!2)!"3H_/___X![3P!T&HDT).C\____
-MQP0D`0```.C\____@'M/`'7F@\<!B?J+3"0,.%$6#X=N____@T0D&`&#?"08
-M!`^%$/___XDT).C\____@\0<6UY?7<.-M@````"-O"<`````55=64X/L?(N$
-M))````#&0#D`QD`X`,9`-P#&@+T,````B<*!PIP+``"X`````(GVQ@00`(/`
-M`3T0`0``=?*+A"20````!>@```"+E"20````B8+H````B8+L````B=`%\```
-M`(F"\````(F"]````('"^````(E4)$2+C"20````B9'X````B9'\````B<^!
-MQP`!``")N0`!``")N00!``"!P0@!``")3"1,BYPDD````(F+"`$``(F+#`$`
-M`('#$`$``(E<)%"+M"20````B9X0`0``B9X4`0``B?6!Q2`!``")KB`!``")
-MKB0!``"!QB@!``")="1(BX0DD````(FP*`$``(FP+`$```48`0``B40D5(N4
-M))````")@A@!``")@AP!``"-1"1VB40D-(U$)'B)1"0PC40D:(E$)"R-1"1N
-MB40D*(U$)'J)1"0DC40D<(E$)""-1"1QB40D'(U$)&R)1"08C40D<XE$)!2-
-M1"1JB40D$(U$)'*)1"0,C40D=(E$)`B-1"1UB40D!`^W0B2)!"3H_/___P^V
-M1"1UBXPDD````(A!+@^V1"1TB$$O#[9$)'*(@>4````/MT0D>F:)05P/MT0D
-M>&:)@9@+```/MT0D=H/H`6:)@9H+```/MT0D:F:)03H/MT$D9CV`D70*9CV`
-ME`^%X0H``(N<))````#&0S4$QD,K!,9#-D#&0S0`QH/B````"<9#+`")V`5D
-M!0``B00DZ/S___^)PHF#?`4```^V1"1U:<`H`0``A<!T"\8"`(/"`8/H`77U
-MBX0DD`````6`!0``B00DZ/S___^)PHNT))````")AI@%```/MD0D<FG`L```
-M`(7`=`O&`@"#P@&#Z`%U]8N$))`````%G`4``(D$).C\____B<*+A"20````
-MB9"T!0``#[9$)'1IP!0-``"%P'0+Q@(`@\(!@^@!=?6+A"20````!;@%``")
-M!"3H_/___XG"BXPDD````(F!T`4```^W1"1ZP>`"A<!T"\8"`(/"`8/H`77U
-MBX0DD`````4P!@``B00DZ/S___^+G"20````B8-(!@``B=@%%`8``(D$).C\
-M____B<.+M"20````B88L!@``B?`%9`8``(D$).C\____B<*)AGP&``!F@WPD
-M:@!T1KD`````B5I$#[9$)'.(0CR+M"20````BX;\````B9;\````BW0D1(DR
-MB4($B1`/MD0D<XT$0(T<@X/"<(/!`68Y3"1J=[^+A"20````!8`&``")!"3H
-M_/___XG"BX0DD````(F0F`8``&:#?"1N`'0PN0````#&0@@`BYPDD````(N#
-M!`$``(F3!`$``(DZB4($B1"#PB"#P0%F.4PD;G?5BX0DD`````6<!@``B00D
-MZ/S___^)PHNT))````")AK0&``"`?"1Q`'0SN0````"+G"20````BX,,`0``
-MB9,,`0``BW0D3(DRB4($B1"#PA2#P0$/MD0D<68YR'?2BX0DD`````6X!@``
-MB00DZ/S___^)PHN$))````")D-`&``"-BJ````"+G"20````BX,4`0``B9,4
-M`0``BW0D4(DRB4($B1"#PA0YRG7;B=@%U`8``(D$).C\____B<*)@^P&``"`
-M?"1P`'0RN0````"+G"20````BX,D`0``B9,D`0``B2J)0@2)$('"F````(/!
-M`0^V1"1P9CG(=].+A"20````!?`&``")!"3H_/___XG"B[0DD````(F&"`<`
-M`&:#?"1L`'0PN0````"+G"20````BX,<`0``B9,<`0``BW0D5(DRB4($B1"#
-MPAB#P0%F.4PD;'?5@'PD=0!T3[L`````B[0DD````('&#`<``(DT).C\____
-M#[?3BXPDD````(F$D20'``"+D2P!``")@2P!``"+3"1(B0B)4`2)`H/#`0^V
-M1"1U9CG8=\.+A"20````!20)``")!"3H_/___XN<))````")@SP)``")@T`)
-M```/MT0D>F:)@T8)```/M\")1"0$B=@%0`D``(D$).C\____B=@%3`D``(D$
-M).C\____B8-D"0``B8-H"0``#[9$)'5FB8-N"0``#[?`B40D!(G8!6@)``")
-M!"3H_/___XG8!70)``")!"3H_/___XF#C`D``(F#D`D```^V1"1R9HF#E@D`
-M``^WP(E$)`2)V`60"0``B00DZ/S___^)V`6<"0``B00DZ/S___^)@[0)``")
-M@[@)```/MD0D=&:)@[X)```/M\")1"0$B=@%N`D``(D$).C\____B=@%Q`D`
-M`(D$).C\____B8/<"0``B8/@"0``#[9#)F:)@^8)```/MD,FB40D!(G8!>`)
-M``")!"3H_/___XG8!>P)``")!"3H_/___XG"B8,$"@``#[9$)'1IP'0$``")
-MP8'!=$4``'0/B=")RL8``(/``8/J`77UB[0DD````(N&!`H``(D(BY8$"@``
-M#[9$)'2(0@0/MD0D=(E$)`B)3"0$BX8$"@``B00DZ/S___^]`````(!^)@`/
-MA*<```"_``````^WWVO;7(N$))````"-K!A,`0``C00#C;!``0``B?J(5A#&
-M1A$`BXPDD````(F(3`$``,9&%@#&@(`!````QH!H`0```,>`I`$```````"-
-ME!E@`0``C4H,B8AL`0``B8AP`0``@\(8B9!X`0``B9!\`0``BXPDD````(V4
-M&80!``")D(0!``")D(@!``#&1A("@\<!#[9!)F8Y^`^'7O___XN<))````#&
-M0S0`QH-"!0``_\:#0P4``/_&@T0%``#_QH-%!0``_X!\)'4`#X2#````NP``
-M```/M\MIT2@!``"+M"20````BX9\!0``QD00)P&+AGP%``#&1`(F`(N&?`4`
-M`,9$`DS_BX9\!0``QD0"0O^+AGP%``!FQX0"E```````QX2.O`(```````")
-MT0..?`4``(U!$(E!$`.6?`4``(U"$(E"%(/#`0^V1"1U9CG8=X*+A"20````
-M9L>`X```````N`````"+E"20````QH00O`0``/^#P`$]A@```'7G@'PD=``/
-MA*T```"[``````^WPVG`%`T``(N,))````"+D;0%``#&1`(P`(N1M`4``,9$
-M$#$`BY&T!0``QT00#`````")P8NT))`````#CK0%``"-41")41")P0..M`4`
-M`(U1$(E1%(G!`XZT!0``C5$8B5$8B<$#CK0%``"-41B)41R+EK0%``");!`(
-MB<$#CK0%``"-42B)42@#AK0%``"-4"B)4"R#PP$/MD0D=&8YV`^'6/___XN$
-M))````#&@.,```"`@'PD<@!T?;L`````#[?3:=*P````BXPDD````(N!F`4`
-M`&;'1!`R!`"+@9@%``#&1`(F`(N!F`4``,9$`BC_BX&8!0``QD0"-/^)T8NT
-M))`````#CI@%``"-012)012)T0..F`4``(U!%(E!&(N&F`4``(EL`E2#PP$/
-MMD0D<F8YV'>(BX0DD````,:`Y````(*+A"20````!20*``")1"0$BX0DD```
-M``4("@``B00DZ/S___^+E"20````B8(@"@``B=`%2`H``(E$)`2-0.2)!"3H
-M_/___XN,))````")@40*``")R`5L"@``B40D!(U`Y(D$).C\____BYPDD```
-M`(F#:`H``(G8!9`*``")1"0$C4#DB00DZ/S___^)@XP*``")V`6T"@``B40D
-M!(U`Y(D$).C\____B8.P"@``B=@%V`H``(E$)`2-0.2)!"3H_/___XG!B8/4
-M"@``B[0DD````(N&V`H``(N6W`H``(!\)'$`=%J)PXG6OP````")S2G%BT0D
-M3(D$).C\____C50=`(E0"(E8#(EP$(N,))````"+D0P!``")@0P!``"+3"1,
-MB0B)4`2)`H'#``@``(/6`(/'`0^V1"1Q9CGX=[.+A"20````!?P*``")1"0$
-MBX0DD`````7@"@``B00DZ/S___^)1"18BYPDD````(F#^`H``(N$))````"+
-MF/P*``"+L``+``"_`````+T`````BU0D4(D4).C\____BU0D6`'ZB5`(B5@,
-MB7`0BXPDD````(N1%`$``(F!%`$``(M,)%")"(E0!(D"@<,```$`@]8`@<<`
-M``$`@]4`B?@U```(``GH=:J+A"20````!2`+``")1"0$BX0DD`````4$"P``
-MB00DZ/S___^)P8N<))````")@QP+``"+M"20````BX8@"P``BY8D"P``9H-\
-M)&P`=%>)PXG6OP````")S2G%BT0D5(D$).C\____C50=`(E0"(E8#(EP$(N,
-M))````"+D1P!``")@1P!``"+3"14B0B)4`2)`H'#C`$``(/6`(/'`68Y?"1L
-M=[:#Q'Q;7E]=PY"-M"8`````55=64X/L#(ML)""+?"0DBU]4#[9'*XE$)`B)
-M;"0$B1PDZ/S___^)QF:#3S(0@'TK`'1)N0````#V0PD!=`SK/`^V0PG3^*@!
-M=0R#P0$/MD4K9CG(=^IF@_D#=B6+10`%T`$```^WT8T4D(L"HP````#!Z!2#
-M\`&#X`'K([D`````BT4`!=`!```/M]&-%)"+`J,`````P>@4@_`!@^`!A,!T
-M%`^VP8E$)`2)+"3H_/___^F&`0``C4,X.4,X#X01`0``A?8/A`D!```/MD9-
-MQT2'/`````"+%HM&!(E"!(D0B70D",=$)`0&````B1PDZ/S___^`?D\`=!^0
-MC70F`(DL).C\____QP0D`0```.C\____@'Y/`'7FBT8@A<!T5L=`8`````#V
-M1B@$=0B)+"3H_/___XM&((N52`4``(E$)`B)5"0$QP0D`0```.C\____BT8@
-MBY5(!0``B40D"(E4)`3'!"0&````Z/S____'1B``````@&L*`8ET)`2)+"3H
-M_/___XM%`(N06`$``(D5`````(72=`F+10")D%@!``#&1R8`9H-G,N^`?Q\`
-M="*Z``````^WPHM$ASR%P'0&@'@F_W5U@\(!#[9''V8YT'?C@'\R`'@-O@``
-M``"`?Q\`=1#K3(E\)`2)+"3H_/___^M(#[?&BUR'/(7;="?V0R@"="&+0R"+
-ME4@%``")1"0(B50D!,<$)`8```#H_/___X!C*/V#Q@$/MD<?9CGP=\)FQT<R
-M`@"`9RW]@\0,6UY?7<.-="8`C;PG`````%575E.![)P```"+A"2P````B40D
-M=(M0+(E4)'R+.HN'L`H``(L`B80D@````(M,)'2)3"0$B3PDZ/S___^+;"1T
-M@+VW`````78'QH6T````!(M$)'2#P!#'1"1X`````(M4)'0Y0A!T*HM<)'2#
-MPQ")'"3H_/___XE$)'B+3"1TBT$0BVPD>(EH!(E%`(E=!(EI$(M$)'2#>"``
-M=5>]____`(-\)'@`=`B+5"1X#[=J'HM,)'0/MG%-BU0D?(M"&`^V0`0/ME<I
-M#[9/(@^V7R&);"08B70D%(E$)!")5"0,B4PD"(E<)`3'!"2X"```Z/S___^#
-M?"1X``^$8P0``(M,)'@/MTD>B4PD5&GQL`0```.W:`H``(N?(`H``(ML)'B)
-M+"3H_/___XN&+`0``(E$)$"+EB@$``"+CB0$``"+MB`$``"+1"1X#[=H'HM$
-M)$")1"04B50D$(E,)`R)="0(B6PD!,<$)(0'``#H_/___XM$)%3!X`8!PXM3
-M-(E4)$"+4S"+2RR+<RB+:R2);"18BT,@B40D7(MK'(EL)&"+0QB)1"1DBVL4
-MB6PD:(M#$(E$)&R+:PR+0PB)A"24````BT,$B80DD````(L;BT0D0(E$)#B)
-M5"0TB4PD,(ET)"R+5"18B50D*(M,)%R)3"0DBT0D8(E$)""+5"1DB50D'(M,
-M)&B)3"08BT0D;(E$)!2);"00BY0DE````(E4)`R+C"20````B4PD"(E<)`3'
-M!"3\!@``Z/S___^+;"1X@\4\B:PDA````(M$)'B+0%2)A"2,````BT4$#[95
-M`8E$)`B)5"0$QP0D#`(``.C\____@'T!``^$G@```,:$)(L`````#[:T)(L`
-M``"-!';!X`*+E"2$````BTH(`<&)PXNL)(P````#70B+0PB)1"1PBP.+4P2)
-M1"1`B50D1(MI"(M9!(L)BU0D<(E4)!R+1"1`BU0D1(E$)!2)5"08B6PD$(E,
-M)`B)7"0,B70D!,<$)%P(``#H_/___X"$)(L````!#[:4)(L```"+C"2$````
-M.%$!#X=J____9H-_7``/A`@"``"^`````(VO0`D``(V'Z````(E$)%"-M@``
-M```/M\;!X`(#A]`%``"+&(7;#X3*`0``#[=#$(M4)'1F.4(<#X6X`0``#[>7
-ME@L``#F4)(````!T88/"`0^WAYH+```YPAG`(<*+A[`*``"#P`2+!)"I```(
-M`'4U9B7_#V8Y\'4L.5PD>'4OBTPD>`^W01Z)1"0$QP0DG0(``.C\____B3PD
-MZ/S____IDP$``)`[E"2`````=9^+1"1\@'@T``^%.0$```^W0Q!F/84`#X<K
-M`0``#[?`@+P'O`0``/\/A!H!``"#O"2P``````^$\0```(M4)'0/MD(D@^`%
-M@_@%#X7=````BQ</MT,>9L'H!0^WP(T$A0`#``")@G`!```/MTL>@^$?N@$`
-M``")T-/@B<&+!XF(=`$```^W0Q[!X`(#A]`%``#'```````/MTL>B<AFP>@%
-M#[?`B40D3(/A'XG0T^")P??1BT0D3"&,A]0%```/MTL>B<AFP>@%#[?`@^$?
-MT^+WTB%4AV`[7"1X=#>+$XM#!(E"!(D0@WM4`'0/C4-4B40D!(D\).C\____
-MBX?H````B5@$B0.+5"10B5,$B9_H````#[=#'HE$)`2)+"3H_/___XM,)'2`
-M:4\!ZQN+1"1\]D`&`G01B5PD!(M4)'2)%"3H_/___Y"#Q@%F.7=<#X<3_O__
-M@[PDL`````!T*XM,)'0/MD$D@^`%@_@%=1N+;"1XBU4`BT4$B4($B1");"0$
-MB0PDZ/S___^!Q)P```!;7E]=PY"0D%575E.#[`R+?"0@#[9T)"0/MD0D+(A$
-M)`N+1RR+"+H`````#[9<)"@!\XA<)`.)]@^VA`J\!```//]T1@^VP&G`*`$`
-M`(E$)`0#@7P%``")\SB8V@```'4I.;CD````=2$/MEPD`XB8V0```(N!?`4`
-M``^V7"0+BVPD!(B<!=@```"#P@&!^H````!UHX/$#%M>7UW#C70F`(V\)P``
-M``"#[`B)'"2)="0$BW0D&`^V7"00#[94)!2+1"0,BT@P#[:!D````#Q/=RD/
-MML"-!(`!VHB4P94````/MH&0````C02`B?*(E,&4````@(&0`````8L<)(MT
-M)`2#Q`C#B?975E.+?"00#[=$)!2[_____V:%P'1!N_____^Y`````(/H`0^W
-M\`^V%#F-0M`\"7<7@/O_#Y3`@^@!(<,/ML.-!("-7$+0ZP6`^_]U"H/!`8U&
-M`3G!=<\/ML-;7E_#B?955U93BVPD%`^V="08#[9\)!R+12R+"+H`````C70F
-M``^VA`J\!```//]T*P^VP&G`*`$```.!?`4``#FHY````'44B?,XF-D```!U
-M"HGZB)#;````ZPN#P@&!^H````!UOEM>7UW#B?:-O"<`````55=64X/L!(MT
-M)!@/MGPD'`^V1"0DB$0D`XM&+(L8BVXPN0`````/MH09O`0``#S_=$8/ML!I
-MP"@!``")P@.3?`4``#FRY````'4MB?@X@MD```!U(X!\)`,`=`Z+@N````"+
-M5"0@B0+K&8M,)""+`8F"X````.L+@\$!@?F`````=:.)ZKD`````C;8`````
-M#[:"E````#P!=CD\%W0UB?@X@I4```!U*X!\)`,`=!*-!(F+A,68````BU0D
-M((D"ZQV-%(F+3"0@BP&)A-68````ZPN#P0&#PBB#^5!UL8/$!%M>7UW#B?:-
-MO"<`````55=64X/L(`^V;"0XBT0D-(NPZ`````^V1@+!X`@/ME8#C3P0#[?'
-M@\`$/0`(```/C^T```")ZH32=$Z+3"0T#[:1W````(G3@^/@#[9&`8/@#XG1
-M@^$0"=@)R(G3@^,(@^#SB=&#X00)V`G(@^("@^#\BUPD-`^VB]P```"#X0$)
-MT`G(B$8!ZTP/ME8!B=.#X^"+3"0T#[:!W````(/@#XG1@^$0"=@)R(G3@^,(
-M@^#SB=&#X00)V`G(@^("@^#\#[9.`8/A`0G0"<B+7"0TB(/<````C58(#[?'
-MC7P&!#G7=C^)5"0<NP````")Z`^V\(UL)!R)="0,B6PD"`^VPXE$)`2+5"0T
-MB10DZ/S___^+1"0<@\`$B40D'(/#`3GX<M.#Q"!;7E]=PXVV`````%.#[!B+
-M3"0DBUDT#[9#`L'@"`^V4P,!T`^WP(U0!`^W02`YPG\NBTPD((N!Z````(E4
-M)`B)7"0$B00DZ/S____'1"0$`````(M$)"")!"3H_/___X/$&%O#C;0F````
-M`%575E.#[!P/MGPD.(M$)#"+6#")7"08O@````"+;"0T@\4$#[:#E````#P!
-M=D(\%W0^B?@X@Y4```!U-(T$MHM,)!B-E,&<````BTPD-`^V00,\('8%N"``
-M```/ML")1"0(B6PD!(D4).C\____B?:#Q@&#PRB#_E!UJ(/$'%M>7UW#C;8`
-M````C;PG`````(/L+(E<)!R)="0@B7PD)(EL)"B+7"0P#[9$)#2(1"07BT,L
-MBRB)+"3H_/___XG&A<`/A`<!``")+"3H_/___XG'A<!U$8ET)`2)+"3H_/__
-M_^GH````C58\B50D&(M0"(N#Z````(M,)#R)3"0(B40D!(D4).C\____QD9H
-M"L9&%:P/MT,<9HE&$(M$)$")1DB);AB+5"0\B58@@TYD$HM'"(E&-(E^4(V#
-MN````(E&.,9&'"#'1FP`````QD8D.\9&)0(/MDPD%XA.)HM$)#C!Z!"(1B>+
-M5"0X#[;&B$8HB%8I#[9&(HA&*@^V1B&(1BL/MDPD/(A.+,9&+0#'1"0$````
-M`(M$)!B)!"3H_/___XM&((E$)`R+1PR+5Q")1"0$B50D"(M4)!B)%"3H_/__
-M_XET)`2)+"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#C;0F`````(V\)P``
-M``"#["R)7"0<B70D((E\)"2);"0HBUPD,`^V1"0TB$0D%XM#+(LHB2PDZ/S_
-M__^)QH7`#X3M````B2PDZ/S___^)QX7`=1&)="0$B2PDZ/S____IS@```(U6
-M/(E4)!C&1F@*QD85K`^W0QQFB480BT0D0(E&2(EN&,=&9`@```")?E"+1PB)
-M1C2+5"0\B58@C8.X````B48XQD8<(,=&;`````#&1B0\QD8E`@^V1"07B$8F
-MBT0D.,'H$(A&)XM4)#@/ML:(1BB(5BD/MD8BB$8J#[9&(8A&*P^V1"0\B$8L
-MQD8M`,=$)`0`````BU0D&(D4).C\____BT8@B40D#(M'#(M7$(E$)`2)5"0(
-MBT0D&(D$).C\____B70D!(DL).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.0
-MC;0F`````(/L+(E<)!R)="0@B7PD)(EL)"B+;"0PBT4LBP")1"04BY7H````
-M#[9"`L'@"`^V4@,!T`^WP(U8!('[``@```^/[P```(M$)!2)!"3H_/___XG&
-MA<`/A-D```"+1"04B00DZ/S___^)QX7`=16)="0$BT0D%(D$).C\____Z;(`
-M``"-1CR)1"08BU<(BX7H````B5PD"(E$)`2)%"3H_/___\9&%:P/MT4<9HE&
-M$(M$)!2)1AB)7B"#3F02BT<(B48TB7Y0C86X````B48XQD8<(,=&;`````#&
-M1B0=QD8E$,9&)@(/MD8AB$8GB%XHQT0D!`````"+1"08B00DZ/S___^+1B")
-M1"0,BT<,BU<0B40D!(E4)`B+1"08B00DZ/S___^)="0$BT0D%(D$).C\____
-MBUPD'(MT)""+?"0DBVPD*(/$+,.0C;0F`````(/L+(E<)"2)="0HBUPD,`^V
-M5"0T#[9T)#C'1"0@`````(![)P%T2L=$)`P!````C40D((E$)`@/ML*)1"0$
-MB1PDZ/S___^+1"0@A<!T(X`(@(GPA,!T"HM$)""`2`,@ZPB+1"0@@&`#WXD<
-M).C\____BUPD)(MT)"B#Q"S#C78`@^PLB5PD'(ET)"")?"0DB6PD*(M<)#`/
-MMD0D-(A$)!>+0RR+*(DL).C\____B<:%P`^$N0```(DL).C\____B<>%P'41
-MB70D!(DL).C\____Z9H```"-1CR)1"08QD85K`^W0QQFB480B6X8QT9D"```
-M`(E^4(M'"(E&-,=&(``(``"-@[@```")1CC&1AP@QT9L`````,9&)!S&1B4!
-M#[9$)!>(1B;&1B<(QD8H`,=$)`0`````BT0D&(D$).C\____BT8@B40D#(M'
-M#(M7$(E$)`2)5"0(BT0D&(D$).C\____B70D!(DL).C\____BUPD'(MT)""+
-M?"0DBVPD*(/$+,.-M@````"-OP````!55U93@^P<BTPD-(M9-`^V0P+!X`@/
-MME,#`=`/M_"-5@0/MT$@.<(/CX,!``"->PB-;#,$B7PD$,9$)!<`QT0D&```
-M```Y[P^#]0```(UV``^V1"08B$0D%@^V1P+!X`@/ME<#`=!FB40D%`^W\(ET
-M)`2+1"00@\`$B00DZ/S___\\_W5KBT0D$(U4,`2)TSG5#X;Z````QD0D%_^-
-M="8`#[9"`L'@"`^V4@.--!`/M\:)1"0$C4,$B00DZ/S___\\_W41@'PD%_\/
-MA8X```"0Z8,````X1"07=@2(1"07#[?&C50#!(G3.=5V<>NRB?8J1"07#[;`
-MB40D"`^V7"06B5PD!(M4)#")%"3H_/___XE<)`B)?"0$BT0D,(D$).C\____
-M#[=$)!2+5"00C7P"!(E\)!"#1"08`3G]#X<.____QT0D!`(```"+1"0PB00D
-MZ/S____K6,9$)!<`#[9$)!:)1"0(B7PD!(M4)#")%"3H_/___P^W1"04BU0D
-M$(U\`@2)?"00@T0D&`'IO_[__P^V1"06B40D"(E\)`2+1"0PB00DZ/S____K
-MEHUT)@"#Q!Q;7E]=PY"-M"8`````55=64X/L'(M,)#2+630/MD,"P>`(#[93
-M`P'0#[?`@\`$#[=1(#G0#X\>`0``C7,(#[9;`;D`````N@````")]@).`@^V
-M1@.-=`8$@\(!.--S[H3)#X33````QD0D&P"_`````(U!_P^VP(/``8E$)!0/
-MME2^`0!4)!L/M@2^/`%T!#P7=4H/MEPD&RC3.%PD&P^&B0```(U'`0^VZ(UV
-M``^V!+Z)1"0,B6PD"`^VPXE$)`2+1"0PB00DZ/S___^#PP$Z7"0;=%CKUHVV
-M`````(M,)#"+03"`N)$````!=$`/MEPD&RC3.%PD&W8SC4<!#[;H#[8$OHE$
-M)`R);"0(#[;#B40D!(M$)#")!"3H_/___X/#`3I<)!MUV)"-="8`@\<!.WPD
-M%`^%1/___XM4)#"+0C#&@)$````!QT0D!`<```")%"3H_/___X/$'%M>7UW#
-MC;8`````C;PG`````(/L+(E<)!R)="0@B7PD)(EL)"B+7"0PA=L/A,P```"+
-M0RR+*(DL).C\____B<:%P`^$M0```(DL).C\____B<>%P'41B70D!(DL).C\
-M____Z98```"-1CR)1"08QD85K`^W0QQFB480B6X8QT9D"````(E^4(M'"(E&
-M-,=&(``(``"-@[@```")1CC&1AP@QT9L`````,9&)!S&1B4!QD8F`L9&)PC&
-M1B@`QT0D!`````"+1"08B00DZ/S___^+1B")1"0,BT<,BU<0B40D!(E4)`B+
-M1"08B00DZ/S___^)="0$B2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPY"#
-M[!R)7"00B70D%(E\)!B+?"0DBW0D((M?2`^W5Q!F@?J%``^'AP````^WP@^V
-MC`:\!```@/G_='=F@_I_=QD/ML&+EGP%``!IP"@!``"+1!`L#[9`!.LX9H'Z
-M@0!W&0^VP8N6M`4``&G`%`T``(M$$`@/MD`$ZQ@/ML&+EI@%``!IP+````"+
-M1!!4#[9`!)`\_W0<#[;`@+P&0@4``/]T#X#Y_W0*#[9'%#P&=3*)]H-_4`!T
-M#XU'4(E$)`2)-"3H_/___XE\)`2)-"3H_/___\=#+/____^)'"3_4RCK<83`
-M=3KV1V0(=!F+2QR+5S2+1R")1"0(B50D!(D,).C\____QT,L`````(M3((72
-M=`6+0Q2)`HD<)/]3*.L2QT,L_____XD<)/]3*)"-="8`@W]0`'0/C4=0B40D
-M!(DT).C\____B7PD!(DT).C\____BUPD$(MT)!2+?"08@\0<P^L-D)"0D)"0
-MD)"0D)"0D(/L'(E<)`R)="00B7PD%(EL)!B+7"0DBWPD(`^V:Q0/MT,09CV%
-M`'<9BY=\!0``#[?`#[:$![P$``!IP"@!``#K"XN7?`4``+C8)@$`C30"B>B$
-MP'4A9L>&E```````@'LD''42@'LF`G4,B5PD!(DT).C\____@WM0`'0/C4-0
-MB40D!(D\).C\____B5PD!(D\).C\____B>@\!G0^C9X$`0``B5PD!(M'%(D$
-M).C\____QX8$`0``@(0>`,>&#`$```````")MA`!``")7"0$BT<4B00DZ/S_
-M__^+7"0,BW0D$(M\)!2+;"08@\0<PU575E.#[!P/MD0D.(A$)!N+5"0PBT(L
-MBS"_`````(ML)#2#Q0P/MH0WO`0``#S_=%$/ML!IV"@!``#'1"0("````(EL
-M)`2)V`.&?`4```6@````B00DZ/S___^$P'0CBX9\!0``#[94)!N(E`/:````
-MBX9\!0``BU0D,(F4`^0```"#QP&!_X````!UF(/$'%M>7UW#C70F`(V\)P``
-M``!55U93@^P<BTPD-(MQ-`^V1@+!X`@/ME8#`=`/M_B-5P0/MT$@.<(/C_4`
-M``"-7@B-=#X$B70D%(G=.=X/ALP```#'1"08`````(VV``````^V3"08#[83
-MA-(/B)4```")T(/@#SP&#X6(````]D,#P'0*]D,%P`^%>````/;"$'0U@'L$
-M`'1MC74(OP`````/MD,#B40D"(ET)`2+1"0PB00DZ/S___^#QAR#QP&)^#A#
-M!'9`Z]F`>P(`=#B-=02_``````^VR8E,)!"-="8`BT0D$(E$)`B)="0$BT0D
-M,(D$).C\____@\8<@\<!B?@X0P)WVP^V0P&-7`4"B=V#1"08`3M<)!0/@D+_
-M___'1"0$`0```(M$)#")!"3H_/___X/$'%M>7UW#C;8`````55=64X/L+(M$
-M)$")1"0@BU0D1`^V4A2(5"0KBTPD1`^W41!F@?J%``^'N0,```^WPHM<)"`/
-MMHP#O`0``+C_````@/G_=&)F@_I_=QT/ML&+7"0@BY-\!0``:<`H`0``BT00
-M+`^V0`3K/V:!^H$`=QT/ML&+7"0@BY.T!0``:<`4#0``BT00"`^V0`3K&P^V
-MP8M<)""+DY@%``!IP+````"+1!!4#[9`!(M4)"`/MH0"0@4``(E$)!QKP%R-
-MA`),`0``B40D)(N2?`4```^VP6G`*`$``(TT`H!\)"L`#X62`@``9L>&E```
-M````BT0D1(!X)!P/A7L"```/MD`F/`)T6CP"=PL\`0^%9P(``)#K(3P'=#(\
-M"@^%6`(``(M,)$2)3"0$B30DZ/S____I0P(``(M<)$2)7"0$B30DZ/S____I
-M+@(``(M$)$2)1"0$B30DZ/S____I&0(``(M4)$2)5"0$B30DZ/S___^-G@0!
-M``")7"0$BT8LBP"+0!2)!"3H_/___\>&!`$``("$'@#'A@P!````````B;80
-M`0``B5PD!(M&+(L`BT`4B00DZ/S____&1B;_:T0D'%R+3"0@@+P!5@$````/
-MA'H!``"_`````(G#C:P!A`$``(GVB2PDZ/S___^)QHM4)""-!!.+D(@!``")
-ML(@!``")+HE6!(DR@'XF_P^$H@```(!^)0`/A9\```")\X"^M0`````/A$\!
-M```/MDXD#[;1B="#X`:#^`9U*?;"`70DB70D#`^V1DV)1"0(BT8PB40D!(M,
-M)"2)#"3H_/___^D5`0``@_@$=2'VP0&-M"8`````=!6)7"0$BUPD((D<).C\
-M____Z>\```"#^`8/A>8```#VP0$/A=T```")7"0$BT0D((D$).C\____Z<@`
-M``")]L:&M0````"#QP&+3"0@C9090`$```^V0A:)^3C(#X<-____.,%U<X3`
-M=&^_`````&M<)!Q<BT0D((VL&(0!``")+"3H_/___XG&BU0D((T$$XN0B`$`
-M`(FPB`$``(DNB58$B3*`?B;_=!X/MD8E/")T!#P-=1+'1"0$"@```(DT).C\
-M____ZSZ#QP&)^8M$)"`XC!A6`0``=Z9K1"0<7(M4)"#&A`)1`0``_XM,)"2)
-M3"0$B10DZ/S___^`?"0K``^%H@```(M<)$2#>U``=!6)V(/`4(E$)`2+1"0@
-MB00DZ/S___^+5"1$B50D!(M,)"")#"3H_/___X!\)"L`=&@/MX:4````@\`!
-M9HF&E````&:#^`IV#F;'AI0``````.G@_?__QT0D!`H```")-"3H_/___^LQ
-MBUPD(`^VFT$&``")7"0<:\-<BU0D((V$`DP!``")1"0DBY)\!0``N-@F`0#I
-MOOS__X/$+%M>7UW#@^P(B1PDB70D!(M<)`R+="00BU0D%(M,)!R%VW1$A?9T
-M0(72=#R#?"08`'0U9H'YA0!W+@^WP8"\`[P$``#_="'&0B3AQD(E`<9")A-F
-MB4H0B7(8BT0D&(E";+@!````ZP6X`````(L<)(MT)`2#Q`C#C;0F`````(V\
-M)P````"+3"0$BT$$BT`$HP````"`?"0(`'0*B<*!R@``#`#K"(G"@>+___/_
-MBT$$B1"+002)4`R+002)4!"+002)4!2+002)4!B+002)4`3#D)"0D%93BUPD
-M$(M,)#"+="0X#[=$)`QF/2(G=TEF/2`G<WEF/4`A='-F/4`A=QEF/2`AD'1F
-M9CTB(71@9CU0!XUT)@!U8.M49CU$(71.9CU$(8GV<E!F+1`G9H/X`7=&C70F
-M`.LV9CV")W0P9CV")XUT)@!W$F8])"=T(&8]@">-="8`=2#K%&8]@)%T#F8]
-M@)2)]G0&9CV`<G4*Q@-`BT0D%,8``HM$)!C&``0/MA.+1"0LB!!FQP&``&;'
-M!@``BT0D(,8`((M$)"1FQP```0^V$XM$)"B($`^V`V8#`68#!HM4)#1FB0*+
-M5"0<9HD"#[<1BT0D/&:)$`^W$8/""XM$)$!FB1!;7L.-=@"-O"<`````55=6
-M4X/L!(M\)!@/MD0D'(A$)`,/MV]<9H7M#X3>````BX_0!0``O@````"-="8`
-MBP&%P`^$M@````^W4!"[_P```+C_____9H'ZA0!W=`^WP@^VG`>\!```N/__
-M__^`^_]T7&:#^G]W&0^VPXN7?`4``&G`*`$``(M$$"P/MD`$ZSUF@?J!`'<9
-M#[;#BY>T!0``:<`4#0``BT00"`^V0`3K'0^VPXN7F`4``&G`L````(M$$%0/
-MMD`$C;8`````#[;;BY=\!0``.D0D`W4A#[?#:<`H`0``#[9$$"2#X`6#^`5U
-M"[`!ZQN-M"8`````@\8!@\$$9CGN#X4Q____N`````"#Q`1;7E]=PXUT)@!5
-M5U93@^P(BU0D'(M"+(LHBX4@"@``B40D!`^W?5RY`````+X`````ZTF-M@``
-M```/M]F+A=`%``"+%)B%TG0PBT(D)?___P`]X0$0`'0ABT0D'`^W0!QF.T(0
-M=1.)V,'@!HM4)`1F.700"'0+C78`@\$!9CGY<KAF.?ET$(/&`6:#_A]W![D`
-M````Z^8/M\:#Q`A;7E]=PY"-M"8`````4XM4)`B+3"0,BUPD$(M".(7`=!;&
-M`'"+0CB(2`*+0CC&0`<`BT(XB%@,6\.-="8`\\.-M"8`````C;PG`````(/L
-M$(D<)(ET)`2)?"0(B6PD#(M,)!0/MWPD&(GZ@>+_`0``BX'0!0``BS20A?9T
-M,`^VF>(````/MD85B=G3X`^WZ`^WU[C__P``T^`APCG5#Y7`#[;`@^@!(<:0
-MC70F`(GPBQPDBW0D!(M\)`B+;"0,@\00PXUT)@"-O"<`````BU0D!+@`````
-MC;0F`````,8$$`"#P`$]L````'7RQD(H_\9"-/^-0A2)0A2)0AC#BU0D!+@`
-M````C;0F`````,8$$`"#P`$]*`$``'7RQD),_\9"0O_&0DX?C4(0B4(0B4(4
-MPXVV`````(V_`````%.+1"0(BUPD#(L3BX@$`0``B9`$`0``!0`!``")`HE*
-M!(D1QP,`````6\.0C70F`%.#[`B+7"00BTPD%(N3_````(F+_````(V#^```
-M`(D!B5$$B0J#>4P`=`^-04R)1"0$B1PDZ/S___^#Q`A;PY!3BT0D"(M<)`R+
-M$XN(%`$``(F0%`$```40`0``B0*)2@2)$<<#`````%O#D(UT)@!3BT0D"(M<
-M)`R+$XN(#`$``(F0#`$```4(`0``B0*)2@2)$<<#`````%O#D(UT)@"+1"0$
-MBU0D"(N()`$``(F0)`$```4@`0``B0*)2@2)$</K#9"0D)"0D)"0D)"0D)!3
-MBT0D"(M<)`R+$XN(+`$``(F0+`$```4H`0``B0*)2@2)$<<#`````%O#D(UT
-M)@!3BT0D"(M<)`R+$XN('`$``(F0'`$```48`0``B0*)2@2)$<<#`````%O#
-MD(UT)@`/MD0D!#P7=Q</ML#_)(4`$P``N#0```##C;0F`````+@$````P[@\
-M````D(UT)@##N!0```##N$````"-="8`P[@<````P[@8````C70F`,.X*```
-M`,.X(````(UT)@##N$P```##B?:-O"<`````55=64XML)!2+?"08#[97)(G0
-M@^`&@_@&=0GVP@$/A,H```"`?T+_#X7`````BT4`B[`8`0``B34`````N0``
-M``"X`0```(G#T^.%WG4RB$]"BU4`B=@)\(F"&`$``(M%`(N`6`$``*,`````
-MB=HAPG1WBT4`B9!8`0``ZVR-=@"#P0&#^2!UN8M%`(NP'`$``(DU`````+$`
-MC;0F`````(G*N`$```")P]/CA=YU,HU"((A'0HM5`(G8"?")@AP!``"+10"+
-M@&`!``"C`````(G:(<)T$XM%`(F08`$``.L(@\$!@_D@=;>`12P!6UY?7<.-
-MM"8`````C;PG`````%=64XM\)!"+5"04@'HT_P^%MP```(L'B[`8`0``B34`
-M````N0````"X`0```(G#T^.%WG4LB$HTBQ>)V`GPB8(8`0``BP>+@%@!``"C
-M`````(G:(<)T<8L'B9!8`0``ZV>#P0&#^2!UOXL'B[`<`0``B34`````L0"-
-MM"8`````N`$```")P]/CA=YU,XA*-(L7B=@)\(F"'`$``(L'BX!@`0``HP``
-M``")VB'"=!F+!XF08`$``.L/C;0F`````(/!`8/Y('6X@$<L`5M>7\-3#[9<
-M)!"+1"0(BT@HA<ET,;H`````BT21/(7`=`4X6$UT#X/"`8/Z!707D(UT)@#K
-MY&:!>22%`'<(A<"-="8`=06X`````%O#C;0F`````%575E.#[`R+;"0@#[9$
-M)"3!X`@/ME0D*(TT$(!]'``/A,D```"#?3@`#X2_````]D5D"0^4P(G'N0``
-M``"-=@")RP^W%,U@$P``B?`AT&8YP@^%BP````^V%,UE$P``@/H#=`6`^@=U
-M"XGX.`3-9!,``'5NQD44(`^V!-UF$P``B40D"`^VPHE$)`2)+"3H_/___XM5
-M.`^V!-UG$P``B$(-@WPD+`!T*XM$)"R+&(MP!(M-.(EQ`XM%.(`(@/9%9@1T
-M$(7V=`R+13B)6`B+13B`('^+53@/MD4<@^@'B$('ZPR#P0&#^1`/A5+___^#
-MQ`Q;7E]=PXUV`(V\)P````"#[`R+1"00C9`8`0``N0`````YD!@!``!T$8D4
-M).C\____B<''0!0`````B<B#Q`S#ZPV0D)"0D)"0D)"0D)"0@^P,BT0D$(V0
-M*`$``+D`````.9`H`0``=`J)%"3H_/___XG!B<B#Q`S#C;8`````@^P,BT0D
-M$(V0(`$``+D`````.9`@`0``="2)%"3H_/___XG!B<*X`````)"-="8`Q@00
-M`(/``3V8````=?*)R(/$#,.-M@````"-OP````"#[`R+1"00C9`(`0``N0``
-M```YD`@!``!T"HD4).C\____B<&)R(/$#,.-M@````"#[`R+1"00C9```0``
-MN0`````YD``!``!T#HD4).C\____B<'&0`@`B<B#Q`S#B?955U93@^P<B40D
-M$(G5QT0D%`````#'1"08`````(UV`(M4)!B+3"00#[:$"CP%```\_P^$*`$`
-M``^VT`^W1"089H/H@&8]@0`/AWP````/M\)IP!0-``")PP.9M`4``(![,`!T
-M5;X`````C7LHC78`B3PDZ/S___^-2/B+4RR)0RR)>0B)40R)`HM!)"4`__\`
-M/0``_P!U&/9!)P1T$HM!((7`=`N)ZHA0`8VV`````(/&`8GQ.$LP=[:)Z(B#
-MD@```(/%`>F6````#[?":<"P````B<.+5"00`YJ8!0``@'L?`'1#N0````"-
-MM@`````/ML&+5(,\A=)T)8M")"4`__\`/0``_P!U%O9")P1T$(M"((7`=`F)
-MZHA0`8UT)@"#P0$X2Q]WR(GIB(ND````@+NE`````W4>@T0D%`&+1"04@\`#
-M@_@&=A:#Q0''1"04`````.L)@\4!C;8`````@T0D&`&#?"08!@^%L/[__XM4
-M)!"+@D@%```YT'4,!<P,``")ZNAV_O__@\0<6UY?7<.-M"8`````C;PG````
-M`(/L#(M4)!"+1"04#[9(!`^VA!%"!0``QH010@4``/\/M\")1"0$@<+@"0``
-MB10DZ/S___^#Q`S#D(VT)@````"#[`B)'"2)="0$BW0D$(M>3(7;="2-3B2-
-M4PR+0PR)1B2+0@2)002+0@B)00B+0@R)00R+0QR)1C2+'"2+="0$@\0(PXVV
-M`````(V_`````(/L"(D<)(ET)`2+="00BUY,A=MT*(U+#(U6)(M&)(E##(M"
-M!(E!!(M""(E!"(M"#(E!#(M&-(E#',9#"`&+'"2+="0$@\0(PY"-M"8`````
-M5U93@^P0BWPD((L?9H-[7``/A+L```"^`````(UT)@`/M]:+@]`%``"+#)"%
-MR0^$D0````^W41!F@?J%`'=Q#[?"#[:$`[P$```\_W1B9H/Z?W<<#[;`BY-\
-M!0``:<`H`0``BT00+`^V4`3K2(UV`&:!^H$`=QD/ML"+D[0%``!IP!0-``"+
-M1!`(#[90!.LE#[;`BY.8!0``:<"P````BT005`^V4`3K#(VT)@````"Z_P``
-M``^V1P0YPG4(B0PDZ/S___^#Q@%F.7-<#X=.____@\006UY?PXVT)@````"#
-M[!R)7"04B70D&(M<)""+="0D#[9&-#S_=!D/ML")1"0$BP.)!"3H_/___\9&
-M-/^`:RP!BUPD%(MT)!B#Q!S#@^P<B5PD%(ET)!B+7"0@BW0D)`^V1D(\_W09
-M#[;`B40D!(L#B00DZ/S____&1D+_@&LL`8M<)!2+="08@\0<PU=64X/L$(MT
-M)""+7"0D.7,8#X3/````@'L4``^%E@````^V0R0\%70(/%4/A88```"+0TR%
-MP'1_B<*`>`@!=7=F@7@,X0%U;XN^?`4```^W0Q"YV"8!`&8]A0!W$0^WP`^V
-MA`:\!```:<@H`0``C00/#[92#H#Z!W0?@/H'=P>`^@9U,^L<@/H,C;0F````
-M`'0@@/H-=2#K$&:#8#K]B?;K%6:#2#H"ZPYF@V`Z]XGVZP5F@T@Z"(-[4`!T
-M*8%[(``(``!W$8U#4(E$)`2)-"3H_/___^L/C4-0B40D!(DT).C\____9H%[
-M).$!#X4&`0``#[=#$&8]A0!W>@^WP`^VA`:\!```//]T:XN6?`4``(![%`!U
-M7P^VP&G`*`$``(T$`@^V4R:`^@=T'8#Z!W<'@/H&=3'K&H#Z#)"-="8`=""`
-M^@UU(.L09H-@.OV)]NL59H-(.@+K#F:#8#KWB?;K!6:#2#H(9H%[).$!C78`
-M#X6"````@'LF"W5\#[=+$`^V1BZ->/^)RNL<D(UT)@"#P@%F@?J%`'<-#[?"
-M@+PPO`0``/]U"0^WPCGX?.+K1&8]_P!U&>L\@\$!9H'YA0!W#0^WP8"\,+P$
-M``#_=0P/M\$YQW_BN/\```!FB4,0QD,4@(E<)`2)-"3H_/___^D<`0``QD,4
-M`#ES&'0HBT-,A<!T(8!X"`%U#(E<)`2)-"3H_/___XU#3(E$)`2)-"3H_/__
-M_X-[5`!T#XU#5(E$)`2)-"3H_/___XE<)`2+0QB)!"3_4VP/MU,D9H'ZX0%U
-M50^V0R:#Z!$\`7=*#[=#$&8]A0`/AZ4````/M\`/MH0&O`0``#S_#X22````
-M#[;`:<"P`````X:8!0``@'@I`'5]@'@T_W1WB40D!(DT).C\____ZVD/MT,0
-M9CV%`'=?#[?`#[:,!KP$``"+OGP%``"+0R0E____`#WA`1``=#^!^?\```!T
-M-V:!^N$!=1`/MD,F@^@1/`%V)9"-="8`:<$H`0``C00'@'A/`'41B40D!(DT
-M).C\____D(UT)@"#Q!!;7E_#B?:-O"<`````@^P<B5PD$(ET)!2)?"08BW0D
-M((M<)"0/MU,09H'ZA0`/AXH````/M\(/MHP&O`0``(#Y_W1Z9H/Z?W<9#[;!
-MBY9\!0``:<`H`0``BT00+`^V0`3K.V:!^H$`=QD/ML&+EK0%``!IP!0-``"+
-M1!`(#[9`!.L;#[;!BY:8!0``:<"P````BT005`^V0`2-="8`9CW_`'0:#[?`
-M#[:\!D(%``")^#S_=`D/ML%F/?\`=1")7"0$B30DZ/S____K?HGV#[93)P^V
-M0R@/MDLI@/D!=`6`^0AU6HM+2,'@"`^VT@'0)?\!``"+EM`%```Y#()U/P^W
-M21Z)RF;!Z@4/M]*#X1^X_O___]/`(4268(M#2`^W0!Z)1"0$B?H/ML)KP%R-
-MA`9,`0``B00DZ/S___^)]HE<)`2)-"3H_/___XM<)!"+="04BWPD&(/$',.-
-M="8`@^P,B5PD!(ET)`B+7"00C8/X````O@`````Y@_@```!T'8D$).C\____
-MB<:)!"3H_/___XD<).C\____B49,B?"+7"0$BW0D"(/$#,.-=@"#[!R)7"00
-MB70D%(E\)!B+?"0@BT<LBS")-"3H_/___XG#A<!T:XDT).C\____B<*%P'4<
-MQH>U`````8E<)`2)-"3H_/___^M(C;0F`````,9#)``/MT<<9HE#$,9#:`^)
-M<QC'0R``````QT,T`````(M""(E#.,9#'"2)4U#'0VP`````B5PD!(DT).C\
-M____BUPD$(MT)!2+?"08@\0<P^L-D)"0D)"0D)"0D)"0D(/L'(E<)!")="04
-MB7PD&(M\)""+="0DBT<LBQB)'"3H_/___XG"A<!T/<9`)!O&0"4!B?"(0B@/
-MMT<<9HE"$,9":`^)6AC'0B``````QT(T`````,=";`````")5"0$B1PDZ/S_
-M__^+7"00BW0D%(M\)!B#Q!S#B?:-O"<`````@^PLB5PD'(ET)"")?"0DB6PD
-M*(M<)#2+1"0PBRB)+"3H_/___XG&A<`/A*(```")+"3H_/___XG'A<!U$XET
-M)`2)+"3H_/___^F#````B?:-5CR)5"08QD8DX<9&)0'&1B8.#[=#'&:)1A!F
-M@V,X]XM4)#"+`HE&&,=&(``(``"+1PB)1C2)?E#'1FP0M`(`QT0D!`````"+
-M1"08B00DZ/S___^+1B")1"0,BT<,BU<0B40D!(E4)`B+5"08B10DZ/S___^)
-M="0$B2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPXUT)@"-O"<`````@^P<
-MB5PD$(ET)!2)?"08BW0D*(M$)""+&(D<).C\____B<*%P'1EQD`DX<9`)0&)
-M\(A")L9")P^+3"0D#[=!'&:)0A")6AC'0B``````QT(T`````,=";`````")
-M5"0$B1PDZ/S___^)\#P!=1+'!"0%````Z/S____K$(UT)@#'!"10PP``Z/S_
-M__^+7"00BW0D%(M\)!B#Q!S#C70F`(/L'(E<)!")="04B7PD&(MT)""+7"0D
-M#[=3$&:!^H4`#X>+````#[?"#[:,!KP$``"`^?]T>V:#^G]W&0^VP8N6?`4`
-M`&G`*`$``(M$$"P/MD`$ZSMF@?J!`'<9#[;!BY:T!0``:<`4#0``BT00"`^V
-M0`3K&P^VP8N6F`4``&G`L````(M$$%0/MD`$C70F`#S_=!T/ML`/MI0&0@4`
-M`(#Z_W0-@/G_=`@/MD,4/`9U/X-[4`!T*X%[(``(``")]G<1C4-0B40D!(DT
-M).C\____ZP^-0U")1"0$B30DZ/S___^)7"0$B30DZ/S____K<HN^?`4``(3`
-M="W'1"0(`0````^VP6G`*`$``(T$!XE$)`0/ML)KP%R-A`9,`0``B00DZ/S_
-M__^#>U``="F!>R``"```=Q&-0U")1"0$B30DZ/S____K#XU#4(E$)`2)-"3H
-M_/___XE<)`2)-"3H_/___XM<)!"+="04BWPD&(/$',.-M"8`````C;PG````
-M`(/L+(E<)!R)="0@B7PD)(EL)"B+7"0PBVPD-`^W51!F@?J%``^'#@$```^W
-MP@^VC`.\!```@/G_#X3Z````9H/Z?W<<#[;!BY-\!0``:<`H`0``BT00+`^V
-M0`3K.HUV`&:!^H$`=QD/ML&+D[0%``!IP!0-``"+1!`(#[9`!.L7#[;!BY.8
-M!0``:<"P````BT005`^V0`0\_P^$F0````^V^0^VP`^VM`-"!0``B?`\_P^$
-M@0```&:!__\`='J`?10&='2+DWP%``")5"08@'TF`75,QP0D"@```.C\____
-MB6PD!(D<).C\____QT0D"`(````/M\=IP"@!```#1"08B40D!(GR#[;":\!<
-MC80#3`$``(D$).C\____ZQJ)]L<$)/0!``#H_/___XEL)`2)'"3H_/___XM<
-M)!R+="0@BWPD)(ML)"B#Q"S#C70F`(/L+(E<)"")="0DB7PD*(M\)#"+1RR+
-M,(DT).C\____B<.%P'4*QH>U`````>MDD,9`)!7&0!6K#[=''&:)0Q")<QC'
-M1"00`0```,=$)`P!````B5PD"(E\)`2)-"3H_/___X3`=1F)7"0$B30DZ/S_
-M___&A[4````!ZQ>-="8`QT-L`````(E<)`2)-"3H_/___XM<)""+="0DBWPD
-M*(/$+,.-M@````"-O"<`````@^PLB5PD'(ET)"")?"0DB6PD*(M<)#"+0RR+
-M*(DL).C\____B<:%P'4,QH.U`````>FX````B2PDZ/S___^)QX7`=1S&@[4`
-M```!B70D!(DL).C\____Z9(```"-="8`QD8D&L9&)0C&1B8(QD8G`,9&*/_&
-M1BD`QD85JP^W0QQFB480B6X8QT8@_P```,=&9`@```"+1PB)1C0%_P```(E&
-M.,9&'"2)?E#'1FP`````C5X\QT0D!`````")'"3H_/___\=$)`S_````BT<,
-MBU<0B40D!(E4)`B)'"3H_/___XET)`2)+"3H_/___XM<)!R+="0@BWPD)(ML
-M)"B#Q"S#C;0F`````(V\)P````"#["R)7"0<B70D((E\)"2);"0HBVPD,`^V
-M1"0TB$0D%XM%+(LXB3PDZ/S___^)PX7`=0W&A;4````!Z;H```"0B3PDZ/S_
-M__^)QH7`=1C&A;4````!B5PD!(D\).C\____Z9,```"-0SR)1"08QD,D$H!\
-M)!<`=`[&0R4!QD,F@,9#*$#K!,9#*"3&0Q6K#[=%'&:)0Q")>QC'0R!@````
-MQT-D"````(M&"(E#-(ES4,=#;`````#'1"0$`````(M$)!B)!"3H_/___\=$
-M)`Q@````BT8,BU80B40D!(E4)`B+1"08B00DZ/S___^)7"0$B3PDZ/S___^+
-M7"0<BW0D((M\)"2+;"0H@\0LPXUV`(/L+(E<)!R)="0@B7PD)(EL)"B+7"0P
-MBT,LBRB)+"3H_/___XG&A<!U#,:#M0````'IN@```(DL).C\____B<>%P'4<
-MQH.U`````8ET)`2)+"3H_/___^F4````C70F`(U&/(E$)!C&1B2>QD8E$,9&
-M,2#&1A6K#[=#'&:)1A");AC'1B`@````QT9D"````(M'"(E&-(E^4(/`((E&
-M.,9&'"3'1FP`````QD9H#\=$)`0`````BT0D&(D$).C\____QT0D#"````"+
-M1PR+5Q")1"0$B50D"(M$)!B)!"3H_/___XET)`2)+"3H_/___XM<)!R+="0@
-MBWPD)(ML)"B#Q"S#C;8`````C;\`````@^PLB5PD'(ET)"")?"0DB6PD*(M<
-M)#"+0RR+*(DL).C\____B<:%P'4,QH.U`````>FN````B2PDZ/S___^)QX7`
-M=1S&@[4````!B70D!(DL).C\____Z8@```"-="8`C48\B40D&,9&)"7&1A6K
-M#[=#'&:)1A");AC'1B`(````QT9D"````(M'"(E&-(/`"(E&.,9&'"2)?E#'
-M1FP`````QT0D!`````"+1"08B00DZ/S____'1"0,"````(M'#(M7$(E$)`2)
-M5"0(BT0D&(D$).C\____B70D!(DL).C\____BUPD'(MT)""+?"0DBVPD*(/$
-M+,.0C;0F`````(/L+(E<)!R)="0@B7PD)(EL)"B+1"0XB40D%(M4)#"+.HN/
-M?`4``(E,)!B+5"0T#[="$`^VK`>\!```B3PDZ/S___^)PXM,)#0/MW$>B?&#
-MX1^X`0```-/@B<&)\&;!Z`4/M\"%3(=@#X7)````A=L/A,$```")Z0^VT6G2
-M*`$```-4)!B+3"0T#[9!%0^VC^(```#3X`GPQD,DX<9#)0'&0R8/B$,G9L'H
-M"(A#*`^V1"04B$,IBX*H````B4,JBX*L````B4,NBTPD-(E+2,9#%:H/MT(<
-M9HE#$(M4)#"+`HE#&,=#(`````#'0S0`````QT-LL*\"`,=$)`0`````C4,\
-MB00DZ/S___^)7"0$B3PDZ/S___^+1"0T#[=('HG(9L'H!0^WP(/A'[H!````
-MT^()5(=@BUPD'(MT)""+?"0DBVPD*(/$+,.0C70F`%575E.#[!P/MD0D-(A$
-M)!N+5"0PBQIF@WM<``^$_@$``+T`````#[?5BX/0!0``BPR0A<D/A-@!``"+
-M>22!Y____P"!_^$!$``/A9$```"#?"0X``^%N`$```^W41!F@?J%`'=G#[?"
-M#[:$`[P$```\_W189H/Z?W<9#[;`BY-\!0``:<`H`0``BT00+`^V4`3K/F:!
-M^H$`=QD/ML"+D[0%``!IP!0-``"+1!`(#[90!.L>#[;`BY.8!0``:<"P````
-MBT005`^V4`3K!;K_____O@````#II0```)"-="8`#[=1$&:!^H4`#X>'````
-M#[?"#[:T`[P$``")\#S_='9F@_I_=QD/ML"+DWP%``!IP"@!``"+1!`L#[90
-M!.M!9H'Z@0!W&XGR#[;"BY.T!0``:<`4#0``BT00"`^V4`3K'XGR#[;"BY.8
-M!0``:<"P````BT005`^V4`2-M@````"!YO\```!IQB@!``")Q@.S?`4``.L*
-MNO____^^`````(M$)#`X4`0/A84```"#?"0X`'0.BU0D.`^W0AQF.T$0=7"`
-M?"0;!G1.@?_A`1``=$8/ME8DB="#X`:#^`9U./;"`74S@+ZT`````'4J@?_A
-M`0\`=#T/MD0D&XA!%,=$)`@!````B4PD!(M4)#")%"3H_/___^L;#[9$)!N(
-M010/M\6)1"0$BU0D,(D4).C\____@\4!9CEK7`^'!_[__X!\)!N!#X0U`0``
-MBX/H````C;/H````.<8/A"$!``"Z`````(/"`8L`.<9U]V:%T@^$"@$``(UZ
-M_XDT).C\____B<&#?"0X`'0GBU0D.`^W0AQF.T$0=!F+@^P```")B^P```")
-M,8E!!(D(Z;D```"0#[=1$&:!^H4`=V</M\(/MH0#O`0``#S_=%AF@_I_=QD/
-MML"+DWP%``!IP"@!``"+1!`L#[9`!.L^9H'Z@0!W&0^VP(N3M`4``&G`%`T`
-M`(M$$`@/MD`$ZQX/ML"+DY@%``!IP+````"+1!!4#[9`!.L%N/____^+5"0P
-M.D($=26+020E____`#WA`0\`=!8/MD0D&XA!%(E,)`2)'"3H_/___^L3BX/L
-M````B8OL````B3&)002)"(U'_V:%_W0/.[/H````=`>)Q^GY_O__@\0<6UY?
-M7<.)]HV\)P````"#[!R)7"0,B70D$(E\)!2);"08BVPD(`^V?"0HBW4`B30D
-MZ/S___^)PX7`=1.+1"0LQH"U`````>F0````C78`B30DZ/S___^)PH7`=1F)
-M7"0$B30DZ/S___^+5"0LQH*U`````>MFQD,DX<9#)0'&0R80B?F(2Q6+3"0D
-M#[9!,V:)0Q"+10")0QC'0R"0````C4((B4,TB5-0QD`!$L9""$")^HA0"<=#
-M;`````#'1"0$`````(U#/(D$).C\____B5PD!(DT).C\____BUPD#(MT)!"+
-M?"04BVPD&(/$',/K#9"0D)"0D)"0D)"0D)"#[!R)7"0,B70D$(E\)!2);"08
-MBVPD((M\)"B+1"0LB40D"(MU`(DT).C\____B<.%P`^$B````(DT).C\____
-MB<*%P'1ZQD,DX<9#)0'&0R80B?F(2Q6+3"0D#[9!,V:)0Q"+10")0QC'0R"0
-M````C4((B4,TB5-0QD`!D<9""$")^HA0"0^V3"0(B$@*QT-L`````,=$)`0`
-M````C4,\B00DZ/S___^)7"0$B30DZ/S____'!"2@A@$`Z/S___^+7"0,BW0D
-M$(M\)!2+;"08@\0<PXVV`````(V_`````(/L'(E<)`R)="00B7PD%(EL)!B+
-M?"0@BVPD*(LWB30DZ/S___^)PX7`='*)-"3H_/___XG"A<!T9,9#).'&0R4!
-MQD,F$,9#%;N+3"0D#[9!,V:)0Q"+!XE#&,=#()````"-0@B)0S2)4U#&0`$0
-MQD((0(GJB%`)QT-L`````,=$)`0`````C4,\B00DZ/S___^)7"0$B30DZ/S_
-M__^+7"0,BW0D$(M\)!2+;"08@\0<P^L-D)"0D)"0D)"0D)"0D(/L'(E<)!")
-M="04B7PD&(M\)""+-XDT).C\____B<.%P'1MB30DZ/S___^)PH7`=%_&0R3A
-MQD,E`<9#)A#&0Q6[BTPD)`^V03-FB4,0BP>)0QC'0R"0````C4((B4,TB5-0
-MQD`!`,9""$#'0VP`````QT0D!`````"-0SR)!"3H_/___XE<)`2)-"3H_/__
-M_XM<)!"+="04BWPD&(/$',.#[!R)7"0,B70D$(E\)!2);"08BW0D((V>X`D`
-M`(D<).C\____A,`/A;@```")'"3H_/___XG#N`````")P8"\,$(%``#_=0HX
-M1C1S$(A&-.L+@\$!@\`!@_@$==^`^00/A'\````/ML&(G`9"!0``#[?K:\5<
-MC90&3`$``+@`````Q@00`(/``8/X7'7T#[?;B5PD"&O[7(V4/F`!``"-6@R-
-M!#>)F&P!``")F'`!``"#PAB)D'@!``")D'P!``"-E#Z$`0``B9"$`0``B9"(
-M`0``B(A0`0``:\5<C80&3`$``.L%N`````"+7"0,BW0D$(M\)!2+;"08@\0<
-MPXGV@^P<B5PD$(ET)!2)?"08BW0D((V>:`D``(D<).C\____A,`/A1<!``")
-M'"3H_/___XG"N`````")PX"\,+P$``#_=1P/ML!F.8;@````<QUFB8;@````
-MZQ2-M"8`````@\,!@\`!/8````!URX#[@`^$R@````^VPXB4!KP$```/M\)I
-M^"@!``")^`.&?`4``(D$).C\____BY9\!0``#[;#9HE$%QR+AGP%``#&1`<F
-M`(N&?`4``,9$!SW_BX9\!0``QD0'//^+AGP%``#&1`<^_XN&?`4``,9$!T#_
-MBX9\!0``QD0'/_^+AGP%``#&1`=!_XN&?`4``,:$![8`````BX9\!0``QH0'
-MVP```/^)-"3H_/___XN6?`4``(F$%^@```"`?CD!=0N+AGP%``"`3`<H`8GX
-M`X9\!0``ZP6X`````(M<)!"+="04BWPD&(/$',.-="8`C;PG`````%.#[`B+
-M7"00BU0D%(G8Z(WB__^+@T@%``")!"3H_/___X/$"%O#C78`C;PG`````(/L
-M'(E<)!")="04B7PD&(MT)""-GI`)``")'"3H_/___X3`#X7=````B1PDZ/S_
-M__^)PHGPNX+___^-M@````"`N#X%``#_=1<XGN0```!S((B>Y````.L8C;0F
-M`````(/#`8/``8#[A@^$EP```.O/@/N&#X2,````#[;#B)0&O`0```^WPFGX
-ML````(GX`X:8!0``B00DZ/S___^+EI@%```/ML-FB407)(!^.0%U#8N&F`4`
-M`&;'1`<P__^+AI@%``#&1`<F`(N&F`4``&;'1`<R``"+AI@%``!FQX0'D```
-M`/__QT0D!`````"+AD@%``")!"3H_/___XGX`X:8!0``ZP6X`````(M<)!"+
-M="04BWPD&(/$',.0C70F`%93@^P4BW0D((M$)"0/MT`D#[:<,+P$``#&A#"\
-M!```_P^WVXE<)`2-AI`)``")!"3H_/___VG;L````(G8`X:8!0``@'@T_W0,
-MB40D!(DT).C\____QT0D!`````"+AD@%``")!"3H_/___X/$%%M>PXVT)@``
-M``"-O"<`````4X/L"(M<)!"+1"04#[90,P^VA!J\!```QH0:O`0``/\/M\")
-M1"0$C8.X"0``B00DZ/S____'1"0$`````(N#2`4``(D$).C\____@\0(6\-3
-M@^P(BUPD%(![*/]T&HU#6(E$)`2+5"00BT(4B00DZ/S____&0RC_@\0(6\.-
-M=@!3@^P(BUPD%(![3/]T'8V#[````(E$)`2+5"00BT(4B00DZ/S____&0TS_
-M@\0(6\.#[!R)7"0,B70D$(E\)!2);"08BUPD((ML)"0/MT4<#[:\`[P$```/
-MM\=I\"@!``")\`.#?`4```7H````B40D!(D<).C\____#[=5'(N$D[P"``"%
-MP'08@WAP`'42QX23O`(```````"-M"8`````#[=%',:$`[P$``#_#[?'B40D
-M!(V#:`D``(D$).C\____B?`#@WP%``"`>$+_=`R)1"0$B1PDZ/S___^);"0$
-MB1PDZ/S___^+@WP%``#&1`8F`(N#?`4``,9$!B<!BUPD#(MT)!"+?"04BVPD
-M&(/$',/K#9"0D)"0D)"0D)"0D)"#[!R)7"0,B70D$(E\)!2);"08BVPD((MT
-M)"1F@7XDX0$/A;D````/MD8F@^@1/`$/AZH````/MT809CV%``^'5`$```^W
-MP`^VA`6\!```BY68!0``//\/A#L!```/ML!IP+````"-'`*`:RD!C7L4B3PD
-MZ/S___^)PCGP=4*)7"0$B2PDZ/S___\[>Q0/A`4!``#'0U@`$GH`QT-@````
-M`(E;9(U#6(E$)`2+112)!"3H_/___\9#*`#IV0```)"+0Q2)4`2)`HEZ!(E3
-M%(L6BT8$B4($B1#INP```(UV``^W1A!F/84`#X>J````#[?`#[:4!;P$``"+
-MC7P%``"+1B0E____`#WA`1``#X2&````@?K_````='YIPB@!``"-'`&`:T\!
-MC7L0B3PDZ/S___^)PCGP=4B)7"0$B2PDZ/S___\[>Q!T3\>#[``````2>@#'
-M@_0`````````B9OX````C8/L````B40D!(M%%(D$).C\____QD-,`.L:B?:+
-M0Q")4`2)`HEZ!(E3$(L6BT8$B4($B1"+7"0,BW0D$(M\)!2+;"08@\0<PXUT
-M)@"#[!R)7"0,B70D$(E\)!2);"08BWPD((ML)"0/MU4>B=!FP>@%#[?8#[?R
-MB?&#X1^X_O___]/`B<$A1)]@9H'Z_P]T28T$M0`````#A]`%``"#.`!T-\<`
-M`````"&,G]0%``")="0$C8=`"0``B00DZ/S___^);"0$B3PDZ/S___^);"0$
-MB3PDZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<P^L-D)"0D)"0D)"0D)"0D(/L
-M'(E<)!")="04B7PD&(M\)""+="0D9H%^).$!#X62````#[9&)H/H$3P!#X>#
-M````#[=&$+K_````9CV%`'<+#[?`#[:4![P$``!IPK````")PP.?F`4``(![
-M*/]U/`^V5FBX"````(32=`.-!!(/ML!IP$!"#P")0UC'0V``````B5MDC4-8
-MB40D!(M'%(D$).C\____QD,H`(M3&(ES&(U#%(D&B58$B3*`0RD!Z9\````/
-MMT80N?\```!F/84`=PL/M\`/MHP'O`0``(N7?`4``(M&)"7___\`/>$!$`!T
-M<&G!*`$``(T<`H![3/]U30^V5FBX"````(32=`.-!!(/ML!IP$!"#P")@^P`
-M``#'@_0`````````B9OX````C8/L````B40D!(M'%(D$).C\____QD-,`)"-
-M="8`BU,4B7,4C4,0B0:)5@2),H!#3P&+7"00BW0D%(M\)!B#Q!S#C;8`````
-MC;\`````55=64X/L+(M$)$0/MU`09H'ZA0`/AQ\#```/M\*+7"1`#[:,`[P$
-M``"X_____X#Y_W1B9H/Z?W<=#[;!BUPD0(N3?`4``&G`*`$``(M$$"P/MD`$
-MZS]F@?J!`'<=#[;!BUPD0(N3M`4``&G`%`T``(M$$`@/MD`$ZQL/ML&+7"1`
-MBY.8!0``:<"P````BT005`^V0`0/ML"+5"1`#[:L`D(%``!KQ5R-A`),`0``
-MB40D((N2M`4```^VP6G`%`T```'"B50D'(M$)$2+4#0/MD(!/!)T)SR1#X4J
-M`@``:\5<N0````"+5"1`@+P"5@$````/A-H!``#I<0$``&O%7`-$)$"+B$P!
-M``")3"0H#[9:"8A<)"8/ME(:B%0D)[L`````@+A6`0```'1FOP````!K]5R+
-M1"1`C:PPA`$``)")+"3H_/___XG#BU0D0(T$%HN0B`$``(F8B`$``(DKB5,$
-MB1J+3"0<.4LP=1,/MD--BU0D1#I"%708C;8`````@\<!B?F+1"1`.(PP5@$`
-M`'>NBU0D1(M"4(7`=!")1"0$BTPD*(D,).C\____BT0D1(E$)`2+5"0HB10D
-MZ/S___\/MH.6````C5`!B).6````/`-W.(!\)"<`=3''1"00`````,=$)`P"
-M````BTPD1`^V016)1"0(BT,PB40D!(M<)"")'"3H_/___^LVC4(!B(.6````
-M@/H"=BB`?"0G`'4AQD,G`L9#)O^`8RC^B5PD!(M$)"B)!"3H_/___^D?`0``
-M#[9$)">)1"0,#[9$)":)1"0(BU0D'(E4)`2+3"0@B0PDZ/S____I]````+X`
-M````:]U<BT0D0(V\&(0!``")/"3H_/___XG!BU0D0(T$$XN0B`$``(F(B`$`
-M`(DYB5$$B0J+1"0<.4$P=1(/MD%-BU0D1#I"%707D(UT)@"#Q@&)\(M4)$`X
-MA!I6`0``=Z\/ME$DB="#X`:#^`9U*/;"`70CB4PD#(M<)$0/MD,5B40D"(M!
-M,(E$)`2+1"0@B00DZ/S___^+5"1$BT)0A<!T$(E$)`2+3"1`B0PDZ/S___^+
-M7"1$B5PD!(M$)$")!"3H_/___^LIBU0D0`^VJD$&``!KQ5R-A`),`0``B40D
-M((N2M`4``+CL!@T`Z5_]__^#Q"Q;7E]=PXVV`````%575E.#[`R+;"0@BWPD
-M)(M<)"C&0R<!QD,F`(E<)`C'1"0$!@```(D\).C\____@WLP`'02BU,(BT,,
-MB4($B1"+0S"`:#`!@'M/`'0=C78`B2PDZ/S____'!"0!````Z/S___^`>T\`
-M=>:+D^0```"%TG0;QT0D"`$````/MH/9````B40D!(D4).C\____BU,PA=)T
-M&,=$)`@!````#[9#38E$)`2)%"3H_/___XMS((7V#X2@````@WYP``^%B```
-M`(-^=``/A7X```#V0R@$=1^)+"3H_/___\=$)`@!````BT,@B40D!(DL).C\
-M____BU,@#[9"`HE$)`@/MD(!B40D!,<$)+H"``#H_/___XM#((E$)`B+A4@%
-M``")1"0$QP0D`0```.C\____BT,@B40D"(N%2`4``(E$)`3'!"0&````Z/S_
-M___'0R``````QT9@`````(M3-(72=`P/MD--QT2"/`````"+$XM#!(E"!(D0
-M@&\*`8E<)`2)+"3H_/___X!_!?]T3H!_"@!T.+L`````C7<XC;8`````B30D
-MZ/S___^+5SR)1SR),(E0!(D"@'@F_W4*@\,!.%\*=@?KVSA?"G<0QD<%_XE\
-M)`2)+"3H_/___X/$#%M>7UW#C;0F`````(V\)P````!55U93@^P,BVPD*,9%
-M)P'&128`B6PD",=$)`0&````BT0D)(D$).C\____@WTP`'02BU4(BT4,B4($
-MB1"+13"`:#`!@'U/`'0EC;0F`````(M4)"")%"3H_/___\<$)`$```#H_/__
-M_X!]3P!UXHN5Y````(72=!O'1"0(`0````^VA=D```")1"0$B10DZ/S___^+
-M53"%TG08QT0D"`$````/MD5-B40D!(D4).C\____BUT@A=L/A$$!``#V12@$
-M=6F+3"0@B0PDZ/S____'1"0(`0```(M%((E$)`2+1"0@B00DZ/S___^+52`/
-MMD("B40D"`^V0@&)1"0$QP0DN@(``.C\____BT4@B40D"(M4)""+@D@%``")
-M1"0$QP0D`0```.C\____ZST/MD,"B40D"`^V0P&)1"0$QP0DN@(``.C\____
-MBT4@B40D"(M,)""+@4@%``")1"0$QP0D`0```.C\____BU-PA=(/A$0!```/
-MMT4<BTPD(,>$@;P"````````QT-P`````,=$)`C_____B5PD!(M#>(D$)/_2
-MZ1$!```/MT4<BTPD(,>$@;P"````````QT-T`````(M#>(D$)/_2]D4H`G0A
-MBT4@B40D"(M4)""+@D@%``")1"0$QP0D!@```.C\____QT4@`````,=#8```
-M``"+532%TG0,#[9%3<=$@CP`````BU4`BT4$B4($B1"+3"0D#[91"H/J`8A1
-M"HM%-(7`=`=F@W@R`G5HA-)T9+X`````BWPD)(/'.(D\).C\____B<.+5"0D
-MBT(\B5H\B3N)0P2)&(7;="OV0R@"="6+0R")1"0(BTPD((N!2`4``(E$)`3'
-M!"0&````Z/S___^`8RC]@\8!B?"+5"0D.$(*=ZB);"0$BTPD((D,).C\____
-M@\0,6UY?7<.+4W2%T@^%Y/[__^D!____D(VT)@````"#["R)7"0<B70D((E\
-M)"2);"0HBUPD,(M#+(LHB2PDZ/S___^)QH7`#X3,````B2PDZ/S___^)QX7`
-M=1C&@[4````!B70D!(DL).C\____Z:8```#&1B2@C58EN`````#&!!``@\`!
-M@_@%=?3&1BH`QD8K`,9&+`#&1BV(QD8N`,9&+P#&1A6K#[=#'&:)1A");AC'
-M1F0(````QT8@B````(M'"(E&-`6(````B48XQD8<)(E^4,=&;`````"-7CS'
-M1"0$`````(D<).C\____QT0D#(@```"+1PR+5Q")1"0$B50D"(D<).C\____
-MB70D!(DL).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.)]E93@^P4BW0D((V>
-MN`D``(D<).C\____A,`/A?$```")'"3H_/___XG"N8#___^`OCP%``#_=!*`
-MOCT%``#_#X7,````N8'___\XCN,```!S!HB.XP```(#Y@@^$L`````^VP8B4
-M!KP$```/M\)IV!0-``")V@.6M`4``+@`````Q@00`(/``3T4#0``=?*)V@.6
-MM`4``(U"$(E"$(G:`Y:T!0``C4(0B4(4B=H#EK0%``"-0AB)0AB)V@.6M`4`
-M`(U"&(E"'(G:`Y:T!0``C4(HB4(HB=H#EK0%``"-0BB)0BR+AK0%``"(3`,S
-MQT0D!`````"+AD@%``")!"3H_/___XG8`X:T!0``ZPF-="8`N`````"#Q!1;
-M7L.0C70F`%.#[`B+1"00BY@@"@``!4`)``")!"3H_/___XG!#[?`P>`&C108
-MBT0D%(D0N`````#&!!``@\`!@_A`=?0/M\&#Q`A;PXUT)@"-O"<`````@^P,
-MBT0D$(V0$`$``+D`````.9`0`0``=`J)%"3H_/___XG!B<B#Q`S#D)"0D)"0
-M#[9$)`AIP'0$```%=$4``(M4)`2)`L.)]HV\)P````"+5"0(#[9,)`P/MT1*
-M<(/``6:)1$IP#[92`@'0#[?`PXM4)`2X`0```(VT)@````"`NCLR```!=!*#
-MP`&!PJ0```"#^"!UZ6:X___SPXUV`%93BW0D#`^V3"00#[9<)!2)\K@!````
-M.(HX,@``=1@XFCDR``!U$&G`I````,:$!I<Q```!ZPZ#P`&!PJ0```"#^"!U
-MTEM>PY"-M"8`````55=64X/L"(M\)"`/MD0D)(A$)`>+;"0<BU0D*,8"_@^V
-M702(7"0#A-MT5XGJN0````"^`````+@`````C70F`#FZY$<``'4HB?,Z7"0'
-M=19IP'0$```/MH0%V$4``(M4)"B(`NL<@\8!C;0F`````(/!`8/``8'"=`0`
-M`#I,)`-UOH/$"%M>7UW#C;8`````55=64X/L'(ML)#0/MEPD/(M\)#"`?"0X
-M`708#[9W!+L`````B?"$P`^$(P$``.GX````QD0D&P"#?"1```^$TP```(M4
-M)$")5"04#[97!,9$)!L`A-)T*XGXQD0D&P"Y`````#FHY$<``'4'.-ET$X/!
-M`8!$)!L!!70$```X5"0;=>$/MFPD&VG==`0``(V$'W1%``#'1"0(9````(E$
-M)`2+1"04B00DZ/S___^`O!]T10```'1?O@````")W8V4'W!%``")5"00C;0F
-M`````(GR#[;"P>`$BU0D%(U<`F"-2P2-A"C@1P``C00'C5`(BT`(B4,$BT($
-MB4$$BT((B4$(BT(,B4$,@\8!B?"+5"00.$($=[H/MD0D&VG`=`0```^VA`=T
-M10``ZRF)^KD`````NP`````YJN1'```/E,`!PX/!`8'"=`0``(GP.,%UY@^V
-MPX/$'%M>7UW#C70F`%575E.#[`0/MD0D)(A$)`,/MUPD*&:)'"2+?"08O@``
-M``")]6G6.`P``(M$)!PY1#H4=7"-3!<4N`````"-=@")PP^V41R$TG0&@/KP
-M=4B0:<4X#```C11;C130C0PZBUPD'(E9'(M$)"")02"-01`/MQPD9HE8%@^V
-M7"0#B%@4B<*+7"0LBP.)0AB+0P2)0AS&03#_ZPV#P`&#P1@]@@```'6<@\8!
-M@_X$#X5R____@\0$6UY?7<.0C;0F`````%575E.#[`R+;"0DBW0D((!^!`!T
-M2;\`````C;8`````B?@/MMAIPW0$``"`O`;810``_70?QT0D"`@```");"0$
-MC80&T$4``(D$).C\____A,!U#X/'`8GX.$8$=\*[_P```(G8@\0,6UY?7<.-
-M=@!3@^P(BUPD$(M$)!2)1"0$B1PDZ/S___^Z"0```#S_=!$/ML!IP'0$```/
-MMI0#>D4``(G0@\0(6\.-M"8`````55=64X/L#(M\)""+;"0H#[9T)"P/MUPD
-M,(GYC9?T,```N`````#&!!``@\`!/9````!U\L:!]3```!/&@?0P``!`#[;'
-MB('Z,```B)G[,```B?"(@?TP``#'@9`Q``#0Z0(`B;F,,0``BT5<B8&$,0``
-MBT5@B8&(,0``C8'T,```B40D!(M$)"2)!"3H_/___X/$#%M>7UW#C;0F````
-M`%575E.#[$P/MD0D;(A$)#\/MU0D<&:)5"0@BU0D8(G7N`$```")Q8G&@+H[
-M,@```0^%W````&G`I`````'XC9"0,0``QD('`(FXC#$```^V2@9IP:0```"-
-ME`?T,```N`````#&!!``@\`!/9````!U\FG9I````(T,.XV1\#```,9"!9#&
-M0@1`#[=$)"`/ML2)1"0<B$(*#[9$)""(@?LP```/MDPD/XA*#8M,)'2+`8E"
-M%(M!!(E"&&G6I````(T$.L>`D#$``-#I`@"+3"1@B8B,,0``C907@#$``(M,
-M)&B+05R)0@2+06")0@B)Z@^VPFG`I````(V$!_0P``")1"0$BTPD9(D,).C\
-M____ZQ2#P`&!PJ0```"#^"`/A0'___^P`8/$3%M>7UW#B?955U93@^P,#[9L
-M)"@/MGPD+(M,)"")SK@!````C70F`(G"@+D[,@```0^%P@```&G`I````(V$
-M!I`Q``")Z8A(!(G[B%@%QD`'``^V6`9IPZ0```"-C`;T,```N`````#&!`@`
-M@\`!/9````!U\FG#I````(V$!O`P``#&0`40QD`$0(GYB$@-:=*D````#[:,
-M%I8Q``!IR:0```"-!#''@)`Q``#0Z0(`BUPD((F8C#$``(V<%H`Q``")Z@^V
-MPFG`=`0``(V4!L!%``"+0A")0P2+0A2)0PB-A`[T,```B40D!(M,)"2)#"3H
-M_/___^L4@\`!@<&D````@_@@#X4=____L`&#Q`Q;7E]=PXUV`%93@^P4BW0D
-M(`^V1"0HB?/&AI<Q````C8[T,```N@````#&!`H`@\(!@?J0````=?'&@_4P
-M```!QH/T,```0,>#D#$``-#I`@")LXPQ```/ML!IP'0$``"-E`/`10``BT(0
-MB8.$,0``BT(4B8.(,0``C8/T,```B40D!(M$)"2)!"3H_/___X/$%%M>PXUV
-M`%93@^P4BW0D(`^V1"0HB?/&AI<Q````C8[T,```N@````#&!`H`@\(!@?J0
-M````=?'&@_4P````QH/T,```0,>#D#$``-#I`@")LXPQ```/ML!IP'0$``"-
-ME`/`10``BT(0B8.$,0``BT(4B8.(,0``C8/T,```B40D!(M$)"2)!"3H_/__
-M_X/$%%M>PXUV`%575E.#[$P/MGPD:`^V5"1L#[9$)'"(1"0GBVPD8(GY#[;)
-MB4PD*&G!=`0``("\!=A%``#]#X0Y"0``@/H0#X2Y`@``@/H0=QR$TI"-="8`
-M#X2A````@/H!#X45"0``D.D+`0``@/KB=!N`^O^-=@!T*8#ZD`^%^0@``)"-
-M="8`Z38'``"Y`````(!]!`")]@^%.@@``.E="```:40D*'0$``#&A`7810``
-M_X"]ES$```%U+8M<)"B)7"0(BW0D9(ET)`2+?"1@B3PDZ/S___^%P`^%G`@`
-M`(!%!@'IDP@``(M$)"C&1`4'`8M4)&2)5(4,Z7T(``"`O9<Q```!=5J-C?0P
-M``!I1"0H=`0```'H#[91"8B0=D4```7010``#[91"H/B`8A0"<9`"`"+3"0H
-MB4PD"(M<)&2)7"0$BW0D8(DT).C\____A<`/A2,(``"`108!Z1H(``"+?"0H
-MQD0]!P&+1"1DB42]#.D$"```:70D*'0$``"-/"X/MH4F,0``B(?&10``#[>%
-M)#$``&:)A#7$10``C90UL$4``(N%'#$``(E"!(N%(#$``(E""(V4-8!%``"+
-MA0`Q``")0@2+A00Q``")0@B-G#6010``C4L$C94(,0``BX4(,0``B4,$BT($
-MB4$$BT((B4$(BT(,B4$,BX48,0``B80UK$4``,:'V$4```&`?08?#X1B!P``
-MNP````!I1"0H=`0```'HC;!P10``C;C`10``ZU20#[;#B40D#(M4)"B)5"0(
-MBTPD9(E,)`2+1"1@B00DZ/S___^%P'01:40D*'0$``"(G`7'10``ZR"#PP&`
-M108!.%X&#Y3`@^@!(=B(1P>`?08?=`4Z7@9RJ,:%ES$```$/MDT$A,D/A-D&
-M``"Z`````(!]!P%T#.M$#[;0@'P5!P%U/\9$%0?_QT0D%`````#'1"00````
-M`,=$)`S_````B50D"(M$E0R)1"0$BU0D8(D4).C\____Z8@&``"X`````(/`
-M`3C(=;#I=P8``(M,)'2)3"0P@\$8B4PD+(U,)$"+7"0PBT,8B40D0(MT)"R+
-M1@2)1"1$:40D*'0$``"--"B-EM!%``#&0@@0]D,,<`^$90,``(N&W$4``(7`
-M#X2(````#[9:"L=$)`@(````B4PD!(/`7(D$).C\____A,!U:8M$)##V0`\/
-M=%^+AMQ%``"%P'15B<:`?F4`=$T/MMN)7"0(B70D!(DL).C\____BU0D+(E4
-M)!0/M\")1"00B5PD#(ET)`B+3"1DB4PD!(M<)&")'"3H_/___P^V7F:+1FB%
-MP'0$B<;KK8MT)#`/MD8/J`T/A/T```!I5"0H=`0```^VC!5T10``@/D?#X?D
-M````J`AT$@^VP<'@!`'0QH0%Z$<```;K&`^VP<'@!&E4)"AT!````=#&A`7H
-M1P``!P^V\8GRP>($:5PD*'0$```!VHV,%>!'``#&00D`BWPD,`^V1P^(00N+
-M1"1`B4$0BT0D1(E!%`^V1PF(00H/MD<-@^`/#[:4'7I%```XT'8"B=")PH/B
-M#P^V00R#X/`)T(A!#(GPP>`$:50D*'0$```!T(V,!>!'``"+7"0P#[9#*8/@
-M#P^VE!5Z10``.-!V`HG0P>`$#[91#(/B#PG"B%$,:40D*'0$``"`A`5T10``
-M`>G"`0``J`(/A+H!``"-1"1`B40D!(DL).C\____B<(\_P^%7P$```^V302$
-MR70X#[:%V$4``#S_="VZ`````#S]=1OK(@^VPFG`=`0```^VA`7810``//]T
-M$CS]=`Z#P@$XRG7@ZP6Z``````^VPFG`=`0``(V,!71%``"X`````,8$"`"#
-MP`&#^&1U]`^VTHE4)#1ITG0$``"-'"J)^0^VP6G`=`0``(V$!71%``")@]Q%
-M``"-C!7`10``:70D*'0$``"-E#7`10``BT(0B4$(BT(4B4$,BWPD9(F[Y$<`
-M``'NBX;@10``B8/@10``QH/810``_XV#<$4```^V2`N+?"0P#[97"8B4"WQ%
-M``"`0`L!#[:.>D4```^V5PV#X@\XRG8"B<J(4`II5"0T=`0``(V,%<!%``"+
-M1"1`B4$0BT0D1(E!%`'JBTPD,`^V00^(@G=%```/MEPD)XB:VD4```^V104Z
-M101U!,9%!0"`104!BW0D-,9$-0<!BWPD9(E\M0SK06E$)"AT!```#[;2:<IT
-M!```C90-=$4``#F4!=Q%``!T((T<*8V#<$4```^V2`N+="0P#[96"8B4"WQ%
-M``"`0`L!BWPD,`^V1PF)1"0(BT0D*(E$)`2)+"3H_/___VE$)"AT!```@+P%
-MQT4````/A)P```"`?08?=7#IC0(``,:&V$4``!`/MD,'B40D#(M4)"B)5"0(
-MBTPD9(E,)`2+1"1@B00DZ/S___^%P`^%6@(``(!%!@$/MDL'#[;!@\`!#[:6
-M=D4``#G0=0W&0P<`Z3@"``"-="8`C4$!B$,'@'T&'P^$)`(``.L1:40D*'0$
-M``"--"B-GL!%```/MD,'.H9V10``#X)T____Z?P!``"`?08`#X7R`0``QT0D
-M%`````#'1"00`````,=$)`R0````BU0D*(E4)`B+3"1DB4PD!(M<)&")'"3H
-M_/___^FY`0``OP````!IQS@,``"+="1D.70H%'5VC5P%,+X`````B40D((UV
-M`(`[_W53@'T&'P^$A0$``(T$=HM4)""-1,(0C40%&(E$)!0/MT/VB40D$`^V
-M0_2)1"0,BT/PB40D"(M,)&2)3"0$BT0D8(D$).C\____A<!U!X!%!@'&`_"#
-MQ@&#PQB!_H(```!UFH/'`8/_!`^%;O___X!]!@`/A1@!```/MDT$A,D/A-@`
-M``"Z`````(!]!P%T#.M$#[;0@'P5!P%U0<9$%0?_QT0D%`````#'1"00````
-M`,=$)`S_````B50D"(M$E0R)1"0$BU0D8(D4).C\____Z;L```"X`````(GV
-M@\`!.,AUKNMWC;0F``````^VP6G`=`0``(V4!=!%```/MD((//UT"#S_=`3&
-M0@C^@\$!.$T$=]AI1"0H=`0``(N<!>!%``"_`````(UT)@"`?"\8`749QD0O
-M&`"+1"\4B40D!(M,)&")#"3_TXUV`(''.`P``('_X#```'0VZ]#'1"04````
-M`,=$)!``````QT0D#.(```"+7"0HB5PD"(MT)&2)="0$BWPD8(D\).C\____
-M@\1,6UY?7<.-="8`@^PLB5PD((ET)"2)?"0HBW0D-(N>F````(![!@`/A(0!
-M``"-AI````")1"0$B1PDZ/S___^)P3S_#X1H`0``B?</MD8!/`%T;#P!<A@\
-M$`^$K````#R0#X5*`0``C78`Z?H```"`NY<Q````C70F``^%,0$``,:#ES$`
-M``&`:P8!QT0D%`````#'1"00`````,=$)`P`````#[;!B40D"(M$)#")1"0$
-MB1PDZ/S____I\@```("[ES$````/A>4```#&@Y<Q```!@&L&`<=$)!0`````
-MQT0D$`````#'1"0,`0````^VP8E$)`B+1"0PB40D!(D<).C\____Z:8```"Z
-M`````#J,&C@R``!U$0^VA!HY,@``.D<)=!*-="8`@<*D````@?K<$P``==B`
-M:P8!B7PD%`^V1PF)1"00QT0D#!`````/ML&)1"0(BT0D,(E$)`2)'"3H_/__
-M_^M(#[:&H@```&G`I````,:$`Y<Q```!@&L&`<=$)!0`````QT0D$`````#'
-M1"0,D`````^VP8E$)`B+1"0PB40D!(D<).C\____BUPD((MT)"2+?"0H@\0L
-MPXGVC;PG`````%93BU0D$`^V="04BUPD#(72=`^)V8G0Q@$`@\$!@^@!=?6)
-M$X'J=$4``,'J`KA9MOER]^+!Z@>(4P2)\#C0<P.(0P2`>P0`="6Z`````(GV
-M#[;"QD0#!_]IP'0$``#&A`/810``_8/"`3A3!'?BQD,&`,9#!0")V+H`````
-MC78`QH"7,0```8B0EC$``(/"`06D````@_H@=>9;7L.-=@!75E.+?"04BTPD
-M$(!Y!``/A($```"[``````^V\VG&=`0``#F\`>1'``!U8K@`````.)P(.#(`
-M`'4(QH0(.S(```$%I````#W<$P``=>-IQG0$``#'A`'D1P```````(V4`71%
-M``"X`````)"-="8`Q@00`(/``8/X9'7T:<9T!```QH0!V$4``/V`:04!@\,!
-M.%D$=X2)R[X`````.7L4=2W'0Q0`````QD,8`&G&.`P``(U$`12Z`````(UT
-M)@#&0!P`@\(!@\`8@/J"=?&#Q@&!PS@,``"#_@1UP%M>7\/K#9"0D)"0D)"0
-MD)"0D)!55U93@^P<#[9$)#R(1"0:BUPD,`^V0P4Z0P1U!,9#!0`/ME,%B%0D
-M&XG=B=BY`````(G.B<^+4!0[5"0T=4IIP3@,``#&1`,8`0^V4P3&1"0;`(32
-M=%O&1"0;`(M\)#0YO>1'``!U#@^VA=A%``"#P`,\`78\@$0D&P&!Q70$```X
-M5"0;="OKTX72=15IQS@,```!V(M4)#2)4!3&0!@!ZQ"#Q@&#P0$%.`P``(/Y
-M!'6`B?(/ML)IP#@,``"-1`,<N@````#&!`(`@\(!@?H"#```=?$/MG0D&XM\
-M)#2)?+,,:<9T!```C90#=$4``+@`````Q@00`(/``8/X9'7T:<9T!```C90#
-MY$4``+@`````Q@00`(/``3T``@``=?)ISG0$``"-%!F+1"0TB8+D1P``BT0D
-M0(F"X$4``,:"V$4``/_'@MQ%````````C8P+P$4``(M\)#B+!XE!$(M'!(E!
-M%`^V1"0:B()Z10``QT0D%`````#'1"00`````,=$)`S_````B70D"(M4)#2)
-M5"0$BWPD,(D\).C\____@$,%`8/$'%M>7UW#D)"0D)!64XM4)`R+`HLP#[98
-M*X3;=#</ME()N0````#VP@%T"NLGB=#3^*@!=0>#P0$XV77Q@/D#=A@/ML&-
-MA(;0`0``BP"C`````.L6N0`````/ML&-A(;0`0``BP"C`````,'H%(/@`5M>
-MPY"-M"8`````55=64X/L!(M$)!B+$`^V>BN]"@```(GYA,ET20^V<`F[````
-M`+T*````N0````"0B?#3^*@!=!X/MH+""P``@^`#@\`(B$0D`XGH.D0D`W8%
-M#[9L)`.#PP&#P0&#PD2)^#C#=<N)Z@^VPH/$!%M>7UW#C;0F`````(V\)P``
-M``!55U93@^P$BT0D&(L0#[9Z*[T(````B?F$R71)#[9P";L`````O0@```"Y
-M`````)")\-/XJ`%T'@^V@L(+``"#X`.#P`B(1"0#B>@Z1"0#<P4/MFPD`X/#
-M`8/!`8/"1(GX.,-URXGJ#[;"@\0$6UY?7<.-M"8`````C;PG`````%.+7"0(
-M#[8#P.@$B<*#X@</MDL"]L$$=`.`S@(/MD,#J`1T!H'*```"`/;!"'0#@,X(
-MJ`AT!H'*```(`/;!`G0#@,X$J`)T!H'*```$``^V0Q3!X!@)T%O#C;0F````
-M`(/L!(M$)`B)!"3H_/___X/$!,.-M@````"-O"<`````BTPD!(N!7`4``"7_
-M__\`N@`````]4`&3`'45#[:!7P4``,#H!#P,#Y3`#[;0C78`B=##C;8`````
-MC;PG`````%.)PX72?D`/M@B$R70%@/D@=2VX`````.L6C;8`````#[8,&(3)
-M=`B`^2!U$XUV`(/``3G0=>GK#HVT)@````"X`````.L%N`$```!;C78`P^L-
-MD)"0D)"0D)"0D)"0D%.+7"0(#[9#`P^V4P+!X@@)T,'@$`^V2P$/MA/!X@@)
-MT0G(6\.-="8`C;PG`````%=64XG&B=.)SX7)=!ZY``````^V%@^V1@&(`XA3
-M`8/#`H/&`H/!`3GY=>=;7E_#D(/L'(E<)!")="04B7PD&(MT)""+?"0D#[='
-M$+K_````9CV%`'<+#[?`#[:4!KP$```/M])ITK`````#EI@%``"+GD0*```/
-MMD(TP>`(C80#3`@``(L(B0T`````@>'_````#[9"-,'@"(V<`T0(``"+`Z,`
-M````P>`("<B)@J````!FQX*<``````")?"0$B30DZ/S___^+7"00BW0D%(M\
-M)!B#Q!S#B?:-O"<`````@^P<B5PD#(ET)!")?"04B6PD&(ML)"`/MGPD)(MU
-M`(GX/`-V,`^VV,'C`XV$'C`"``#'``P```#'!"00)P``Z/S___^-A!XT`@``
-MBS")-0````#K,(GX#[;8P>,#C80S4`(``,<`#````,<$)!`G``#H_/___XV<
-M,U0"``"+,XDU`````(GX#[;(B<C!X`:-!(B-E`60"P``#[9:$8/C_(A:$8GP
-M)0``/P`]```0`'4/B=B#R`*(0A'K&9"-="8`B<C!X`:-%(B)V(/(`8B$%:$+
-M``"+7"0,BW0D$(M\)!2+;"08@\0<PY"-M"8`````55=64X/L'(M$)#2+5"0P
-MBQ*)5"08BQ+&0"4`QD`D!<9`)P:+3"0PB4@LN0````"]`````(V"``(``(E$
-M)!2!P@0"``")5"00ZQ>-M@````"+5"0P#[9""=/XJ`%U#(/!`8M$)!@Z2"MR
-MYH#Y`W9Q#[;9P>,#BWPD%`'?QP<L````QP0D$"<``.C\____`UPD$(LSB34`
-M````QP<D````QP0D$"<``.C\____BP.C`````,'@"('F_P````G&QP<@````
-MQP0D$"<``.C\____BQN)'0````#K;XVT)@`````/MMG!XP.+?"04`=_'!RP`
-M``#'!"00)P``Z/S___\#7"00BS.)-0````#'!R0```#'!"00)P``Z/S___^+
-M`Z,`````P>`(@>;_````"<;'!R````#'!"00)P``Z/S___^+&XD=`````('^
-M`0%IEG47BU0D,(!*"`:)V,'H$#Q0#Y3`#[;`ZT:!_@$!``!U$8G8P>@0/%`/
-ME,`/ML#K+XGVQP0DB!,``.C\____@\4!B>F`^01W"KD`````Z<'^__^)V,'H
-M$#Q0#Y3`#[;`@\0<6UY?7<.-="8`C;PG`````%575E.#[`R+="0@BVPD)(M&
-M5(LX9H.^G`````!T,HGKQP0DZ`,``.C\____A>UT!8/[`78;B3PDZ/S___]F
-M@[Z<`````'0)@^L"Z]2-="8`@\0,6UY?7<.0C;0F`````(/L'(E<)`R)="00
-MB7PD%(EL)!B+7"0L#[9L)"0/MWPD*`^V1"0PB$0D"XM4)""+0E2+,(DT).C\
-M____B<+&0"3AQD`E`<9`)A*X#P```(GIA,EU"(M,)"`/MD$KB$(GB?B(0BB)
-M^0^VQ8A"*0^VQXA"*HG8P>@0B$(KB=C!Z!B(0BR(6BV+3"0@#[=!)&:)0A")
-M<AC'0B``````QT(T`````+@`````@'PD"P!U!;@`````B4)LB50D!(DT).C\
-M____BUPD#(MT)!"+?"04BVPD&(/$',.-=@"-O"<`````@^P<B5PD#(ET)!")
-M?"04B6PD&(M<)"P/MFPD)`^W?"0HBU0D((M"5(LPB30DZ/S___^)PL9`).'&
-M0"4!QD`F$K@/````B>F$R74(BTPD(`^V02N(0B>)^(A"*(GY#[;%B$(I#[;'
-MB$(JB=C!Z!"(0BN)V,'H&(A"+(A:+8M,)"`/MT$D9HE"$(ER&,="(`````#'
-M0C0`````QT)L`````(E4)`2)-"3H_/___XM<)`R+="00BWPD%(ML)!B#Q!S#
-M55=64X/L'(M\)#`/MD0D-(A$)!L/MVPD.(7_#X3N````BS>%]@^$Y`````^V
-M7BN%VWY#BT=4#[90";D`````]L(!=`KK,(G0T_BH`74'@\$!.=EU\8/Y`WXA
-MBP8%T`$``(T$B(L`HP````#!Z!2#\`&#X`'K'[D`````BP8%T`$``(T$B(L`
-MHP````#!Z!2#\`&#X`&$P'5V@+^L`````'4&@'\F`'5G#[=')("\!KP$``#_
-M=%G&1R8E9L>'G`````$`#[?%#[94)!O'1"00`0```(M,)#R)3"0,B40D"(E4
-M)`2)/"3H_/___\=$)`0%````B3PDZ/S____&1R8`9H._G``````/E,`/ML#K
-M!;@`````@\0<6UY?7<.-="8`@^P<B5PD#(ET)!")?"04B6PD&(M\)"`/MFPD
-M)`^W7"0HBT=4BS")-"3H_/___XG"QD`DX<9`)0'&0"81N`\```")Z83)=00/
-MMD<KB$(GB%HH#[;'B$(I#[=')&:)0A")<AC'0B``````QT(T`````,=";```
-M``")5"0$B30DZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<PXGVC;PG`````%57
-M5E.#[!R+?"0P#[9$)#2(1"0;#[=L)#B%_P^$\P```(LWA?8/A.D````/MEXK
-MA=M^0XM'5`^V4`FY`````/;"`70*ZS")T-/XJ`%U!X/!`3G+=?&#^0-^(8L&
-M!=`!``"-!(B+`*,`````P>@4@_`!@^`!ZQ^Y`````(L&!=`!``"-!(B+`*,`
-M````P>@4@_`!@^`!A,!U>X"_K`````!U!H!_)@!U;`^W1R2`O`:\!```_W1>
-MQD<F)6;'AYP````!``^WQ0^V5"0;QT0D#`$```")1"0(B50D!(D\).C\____
-MQT0D!`4```")/"3H_/___\9')@!F@[^<`````'43BX>@````BU0D/(D"N`$`
-M``#K!;@`````@\0<6UY?7</K#9"0D)"0D)"0D)"0D)"#[!R)7"0,B70D$(E\
-M)!2);"08BWPD(`^V;"0D#[=<)"@/MD0D+(A$)`N+1U2+,(DT).C\____B<+&
-M0"3AQD`E`<9`)A&X#P```(GIA,EU!`^V1RN(0B>(6B@/ML>(0BD/MT<D9HE"
-M$(ER&,="(`````#'0C0`````N`````"`?"0+`'4%N`````")0FR)5"0$B30D
-MZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<PXUV`(/L'(E<)`R)="00B7PD%(EL
-M)!B+;"0D#[9T)"@/MGPD+(M$)""+&(D<).C\____B<*%P'40QH6U`````<9%
-M)@/I?P```,9`).'&0"4!B?`\`1G`]]"#P`*(0B:)^(3`=3^#?30`=`0/MD5-
-MB$(G#[=%'&:)0A")6AC'0B``````QT(T`````+C`+@,`B4)LB50D!(D<).C\
-M____ZR>-=@#&0B</#[=%'&:)0A")6AC'0B``````QT(T`````+@`````Z\B+
-M7"0,BW0D$(M\)!2+;"08@\0<PY"-M"8`````55=64X/L+(ML)$B+1"1`BQ"+
-M1"1$P>`#C;P0``(``(VT$`0"``"['`$``)"-="8`@WPD1`-V&8D?QP0D$"<`
-M`.C\____BP:C`````.L7B?:)'\<$)!`G``#H_/___XL&HP````")A!ST_O__
-M@\,$@?LX`0``=;F+1"00B44`BT0D%(E%!(M$)!B)10B+1"0<B44,BT0D((E%
-M$(M$)"2)112+1"0HB448@\0L6UY?7<-55U93@^PLBVPD2(M$)$"+$(M$)$3!
-MX`.-O!```@``C;00!`(``+L``0``D(UT)@"#?"1$`W89B1_'!"00)P``Z/S_
-M__^+!J,`````ZQ>)]HD?QP0D$"<``.C\____BP:C`````(F$'!#___^#PP2!
-M^QP!``!UN8M$)!")10"+1"04B44$BT0D&(E%"(M$)!R)10R+1"0@B440BT0D
-M)(E%%(M$)"B)11B#Q"Q;7E]=PU575E.#[#R+3"14B$PD$XM$)%"+`(E$)!@/
-MMOF)^,'@!HT$N`-$)%"-D)`+``"(2A"+3"10B8B<"P``QD(2`(E\)`2)#"3H
-M_/___XUT)!R)\(GRQ@``@\`!B=.-;"0\.>AU\`^V1"03B40D%(E4)`B)1"0$
-MBU0D4(D4).C\____B1PDZ/S___^)1"0,C0R]`````(GZP>(&C101BT0D4(T<
-M`HM$)`R)@Z@+``"+1"10C900H`L``(M$)"B)0@R+1"0LB4(0@'PD$P-V*8M4
-M)!B-A`K0`0``BP"C`````(F#P`L``(V$^H`!``"+$(D5`````.L_C12]````
-M`(M,)!B-A!'0`0``BPB)#0````")^,'@!@'"BT0D4(F,$,`+``"+5"08C83Z
-M@`$``(L0B14`````B?C!X`:-!+@#1"10B9#$"P``]H#""P``$`^$/0$``/:`
-MH0L```)T7(UT)@#&!@"#Q@$Y[G7VC5PD'(E<)`B+3"04B4PD!(M$)%")!"3H
-M_/___XD<).C\____B?K!X@:-%+J+3"10B801M`L``(V4$:`+``"+1"0HB4(8
-MBT0D+(E"'.L7B?C!X`:-!+B+5"10QX0"M`L```$``@"`?"03`W8YC1S]````
-M`(M,)!B-A`LP`@``QP`8````QP0D$"<``.C\____BT0D&(V<`S0"``"+$XD5
-M`````.LWC1S]`````(M4)!B-A!-0`@``QP`8````QP0D$"<``.C\____BTPD
-M&(V<"U0"``"+$XD5`````(GXP>`&C02XBTPD4/>$`<`+``````,`=0B!XO__
-M_]_K!H'*````((!\)!,#=@^+3"08C83Y-`(``(D0ZPV+3"08C83Y5`(``(D0
-M@\0\6UY?7<.0C;0F`````%575E.#[`R+?"0@BVPD)(EL)`@/MT4`9H7`>0LE
-M`!\``,'X"(A')8U'4(U-%(M5%(E74(M1!(E0!(M1"(E0"(M1#(E0#(M1$(E0
-M$(VWC````(M5+HF7C````(M5,HE6!(U?9(U--HM5-HE79(M1!(E3!(M1"(E3
-M"(M1#(E3#(M1$(E3$(M1%(E3%(M1&(E3&(M1'(E3'(M1((E3((M1)(E3)+D*
-M````B<+H0O'__[D$````B?*)\.@T\?__N10```")VHG8Z";Q__]FQT<X``!F
-MQT<Z``"+1"0(9H.XL@$```$/E,+!X@,/MD<H@^#W"="(1RCVA:<````$=`9F
-MQT<X`0#VA:0````!="1F@T\X`O:%J@````%T!6:#3SH!]H6H`````70(9H%/
-M.``!B?;VA:0````@=!=F@T\X!/:%J@```"!T"6:#3SH"C70F`/:%I````$!T
-M%V:!3SB``/:%J@```$!T"&:#3SH(C78`QD=.`O:%F0````%T,P^W1SBH`70,
-M@\@(9HE'.&:#3SH0#[:%E@```(/@'X/``8A'3CP@=0O&1TX?C;0F`````/:%
-MF`````AT!F:!3S@``O:%F`````1T!6:#3S@@]H68`````G0%9H-/.!#VA:@`
-M```@=`[VA:X````@=`5F@T\X0/9'.`%T&(N%R````(N5S````(E'1(E72.L1
-MC70F`(M5>(E71,='2`````"#1T3_@U=(__9%:@)T&0^WA8````"H#W0.9H/X
-M`AG`@\`$B$<\ZP3&1SP"QD<]_P^W57X/M\*H!'0)QD<]`NL9C78`J`)T!L9'
-M/0'K#/;"`8UV`'0$QD<]`,9'/O_V16H$=!VY``````^WA;````#3^*@!=`.(
-M3SZ#P0&#^0=UZ,=$)`0``@``B2PDZ/S___^)AY@```"+1"0(]H"F````('0@
-M#[>`K````(/@((/X`1G`@\`"B(<D`0``ZPV-M@````#&AR0!````N`$```"#
-MQ`Q;7E]=PXVV`````(V_`````(/L'(E<)`R)="00B7PD%(EL)!B+;"0@BWT`
-MNX#____K!8#[A7=*#[;##[:T![P$``")\#S_=#D/ML!IP!0-```#A[0%```Y
-M:`AU)<=$)`@(````BU0D)(E4)`2)!"3H_/___X3`=`F)\.L2D(UT)@"#PP&`
-M^X%VJ;C_____#[;`BUPD#(MT)!"+?"04BVPD&(/$',.-M@````"-OP````!5
-M5U93@^P\BU0D4(L"@'HK``^$`P,``,=$)#@`````C8@``@``B4PD&`4$`@``
-MB40D%`^V1"0XB$0D-P^VZ(GHP>`&C02HBU0D4(T<$/:#P@L``!`/A*8"``"-
-MDY`+``"X`0```(GIT^`(0A*+FZ0+``")7"0P]D(1`@^$,`$```^V7"0W@\,!
-MBW0D4#A>*P^&&P$``(T$K0````")1"0@B>K!X@:)5"0<C;0F``````^V\XGP
-MP>`&C02PBTPD4(T\"/:'P@L``!`/A-$```"+3"0@`TPD'(M4)%`!RHE4)"SW
-M@K0+``````X`#X2O````BU0D4(V$`J`+``")1"0HB<*#PAB+1"10C8P(H`L`
-M`(E,)"2)R(/`&,=$)`@(````B50D!(D$).C\____A,!T;XM$)"B#P`R+5"0D
-M@\(,QT0D"`@```")1"0$B10DZ/S___^$P'1)N`$```")\=/@BU0D+('"D`L`
-M``I"$HA"$HB'H@L``(-\)#``=0R+OZ0+``")?"0PZQ>)\,'@!HT$L(M4)#"+
-M="10B90&I`L``(/#`8M,)%`X62L/AP#___^#?"0P``^%MP```(MT)%")-"3H
-M_/___XE$)#"%P`^$1P$``(GHP>`&C0RH`?&+1"0PB8&D"P``#[9$)#>)PL'B
-M!HV$@I`+``"-1`8,BU0D,(E"&`^V@:$+``"(0@;&0@4`B3+&0@H`QD(T`,9"
-M'``/ME0D-X/"`3A6*W9=B>C!X`:-!*B-G`:0"P``D(UT)@`/MLH/MD,2T_BH
-M`707B<C!X`:-!(B+="0PBTPD4(FT`:0+``"#P@&+1"10.%`K=AGKSHGHP>`&
-MC02HBTPD,(M4)%")C`*D"P``B>C!X`:-!*B+="10C90&D`L```^V0A*+3"0P
-MB$$)#[9R$H!\)#<#=B>-'.T`````BT0D&`'8QP`X````QP0D$"<``.C\____
-M`UPD%(DSZR>-'.T`````BT0D&`'8QP`X````QP0D$"<``.C\____`UPD%(DS
-MB?:#1"0X`0^V1"0W@\`!BW0D4#A&*P^'&/W__X/$/%M>7UW#C;0F`````(V\
-M)P````!55U93@^Q,BW0D8(L>QD0D0%#&1"1!!<9$)$($QD0D0S#&1"1$$<9$
-M)$6KQD0D1@#&1"1'`,>#`$`!`!,@``"+!L>`!$`!`/__``"+!L>`!$`!````
-M```[MD@%```/A>0```"-OLP,``"-KEP%``#'1"00`0```,=$)`P(````B6PD
-M",=$)`0```(`B30DZ/S___^+AE0%```/MI9?!0``@^H$C02"B(9?!0``B30D
-MZ/S___^$P'41BT0D0(F&7`4``(M$)$2)102A``````"&7P4``(/``:,`````
-M#[:&7`4``(B'7`4```^VAET%``"(AUT%```/MH9>!0``B(=>!0``#[:&7P4`
-M`(/``HB'7P4```^VAF`%``"(AV`%```/MH9A!0``B(=A!0``#[:&8@4``(B'
-M8@4```^VAF,%``"(AV,%``")WXV#``$``(E$)"B+@P`!``"C``````^WT(E4
-M)$BH('0+)=__``")1"1(ZQ:)T(/(((E$)$B+5"0HB0*+`J,`````BP;'@`0!
-M````````BP;'@!@!````````BP;'@!P!````````QP0DD-`#`.C\____QX=P
-M`0``&`$``(N'=`$``*,`````@.3]@,P$B40D2,>'<`$``!@!``"+1"1(B8=T
-M`0``QX=P`0``*`$``,>'=`$``']_``#'AW`!```D`0``BX=T`0``HP````!F
-MN```#?\_``")1"1(QX=P`0``)`$``(M$)$B)AW0!``#'AW`!```\`0``QX=T
-M`0````!Z`,>'<`$``*0!``#'AW0!``!]O^__QX=P`0``N`$``(N'=`$``*,`
-M````)?__```-``#Z`(E$)$C'AW`!``"X`0``BT0D2(F'=`$``,>'G````/\`
-M``#'AY`"``!$`0``QX>4`@``!A``",>'D`(``+0!``#'AY0"``!?<```QX>0
-M`@``,````(N'E`(``*,`````,.2`S#.)1"1(B8>4`@``@'XK``^$>@(``,=$
-M)"P`````C8=0`@``B40D&(V75`(``(E4)!0/MD0D+(A$)#,\`P^&$0$```^V
-MZ(T4[0````")5"0DC807,`(``(E$)"#'``@```#'!"00)P``Z/S___^+5"0D
-MC9P7-`(``(L#HP````")1"1(#0``@`")`XV&7`4``(E$)`B);"0$B30DZ/S_
-M__^);"0$B30DZ/S___^+1"0@QP!$`0``QP0D$"<``.C\____QP,&$``(BU0D
-M(,<"M`$``,<$)!`G``#H_/___\<#7W```(M$)"#'``@```#'!"00)P``Z/S_
-M___'1"1(_U2``,<#_U0``,=$)`@!````B6PD!(DT).C\____BT0D)(V4!X`!
-M``"+`J,`````)?___O^)`L=$)$@%`<@`BU0D)(V$%X0!``#'``4!R`#I#@$`
-M``^V;"0SC03M`````(E$)#B+5"08`<*)5"0<QP((````QP0D$"<``.C\____
-MBUPD.`-<)!2+`Z,`````B40D2`T``(``B0.-AEP%``")1"0(B6PD!(DT).C\
-M____B6PD!(DT).C\____BT0D',<`1`$``,<$)!`G``#H_/___\<#!A``"(M4
-M)!S'`K0!``#'!"00)P``Z/S____'`U]P``"+1"0<QP`(````QP0D$"<``.C\
-M____QT0D2/]4@`#'`_]4``#'1"0(`0```(EL)`2)-"3H_/___XM$)#B-E#B`
-M`0``BP*C`````"7___[_B0+'1"1(!0'(`(M4)#B-E#J$`0``B50D-,<"!0'(
-M`,<$)*"&`0#H_/___XEL)`2)-"3H_/___X-$)"P!#[9$)#.#P`$X1BL/AZ+]
-M__^)-"3H_/___XN'!`$``*,`````@\@"B40D2(F'!`$``(M4)"B+`J,`````
-M)?#___T-#0```HE$)$B)`HL"HP````"+AB0*``")AP@!``"+AB@*``")APP!
-M``"+AD@*``")AQ`!``"+ADP*``")AQ0!``#'AR`!````````#[>&F`L``"7_
-M#P``#0```0")AR`!``"+AI`*``")AR0!``"+AI0*``")AR@!``"+AK`*``#'
-M`/\/``#'AS0!````````#[>&F@L``"7_#P``#0```0")AS0!``"+AK0*``")
-MAS@!``"+AK@*``")ASP!``#'AT@!````````QT0D2``!``#'ATP!`````0``
-MBX<$`0``HP````"#R%F)AP0!``#'1"1(^_\`#,>'5`$``/O_``S'AUP!``#_
-M_P``N`````#'A(;4!0```````,=$AF``````@\`!@_@0=>5FQX:4"P``_P]F
-MQX:6"P``_P_&1C@!L`&#Q$Q;7E]=PXUT)@!55U93@^P<B40D%(G7BRB)+"3H
-M_/___XG#A<!U#,:'M0````'IP````(DL).C\____B<:%P'48QH>U`````8E<
-M)`2)+"3H_/___^F:````C4,\B40D&,9#).'&0R4!QD,F`P^W1QQFB4,0QD-H
-M#XM4)!2+`HE#&,=#(``"``"+5@B)4S2X`````(VT)@````#&!!``@\`!/0`"
-M``!U\HES4,=#;,`N`P#'1"0$`````(M$)!B)!"3H_/___XM#((E$)`R+1@R+
-M5A")1"0$B50D"(M4)!B)%"3H_/___XE<)`2)+"3H_/___X/$'%M>7UW#ZPV0
-MD)"0D)"0D)"0D)"055=64X/L3(M$)&"+*`^V0`F$P`^$5P0```^VV,=$)#@`
-M````]L,!=1FZ`````(GV@\(!#[;*B4PD.(G8T_BH`73NBT0D.,'@!HMT)#B-
-M!+"-%"B+@K0+``"I```"`'00#0``!``E___]_XF"M`L``(M$)#C!X`:+?"0X
-MC02XBX0%M`L``*D```0`#X0&`P``BX5(!0``B40D2#GH=0J-E<P,``")5"1(
-MBT0D.,'@!HM,)#B-!(@!Z`^VD+\+``")5"0H#[:0O@L``(E4)"0/MI"]"P``
-MB50D(`^VD+P+``")5"0<#[:0NPL``(E4)!@/MI"Z"P``B50D%`^VD+D+``")
-M5"00#[:`N`L``(E$)`P/MD4IB40D"(E,)`3'!"3P"```Z/S____'1"0\````
-M`(MT)#C!Y@*)="1$BWPD.,'G!HE\)$"+5"0\BTPD2`^VA`H\!0``//\/A*(`
-M```/ML!IP!0-``")PP.9M`4``(MT)$2+?"1`C80^H`L``(U\!1BX"````/R)
-MWHG!\Z8/E\(/DL`XPG5H#[9#!XE$)"`/MD,&B40D'`^V0P6)1"08#[9#!(E$
-M)!0/MD,#B40D$`^V0P*)1"0,#[9#`8E$)`@/M@.)1"0$QP0D0`D``.C\____
-MBWPD8,9'!?^)?"0$B2PDZ/S____I=`(``(UT)@"#1"0\`8-\)#P"#X4V____
-MB2PDZ/S___^)PX7`#X1.`@``BT0D.,'@!HM4)#B-!)#VA`6U"P``!'0$@$LU
-M`HM$)#C!X`:+3"0XC02(]H0%M@L```1T!(!+-1"+1"0XP>`&BW0D.(T$L/:$
-M!;4+```(=`2`2S4$BT0D.,'@!HM\)#B-!+CVA`6V"P``"'0$@$LU((M$)#C!
-MX`:+5"0XC020]H0%M0L```)T!(!+-0&+1"0XP>`&BTPD.(T$B/:$!;8+```"
-M=`2`2S4(QD,P`(G?BT0D.,'@!HMT)#B-A+"@"P``C40%`(M0&(D3BT`<B4,$
-MBT0D8(E#"(D$).C\____B(.+````BU0D8(!"'`&`?2L`=#"Y`````+H`````
-MB?:+="1@#[9&"=/XJ`%T#@^VPHA,`T"`0S(!@\(!@\$!.$TK=]R+1"1@BT@P
-MC5,@B5`PBT0D8(/`+(E#((E+)(D1BU0D8(!"-`''1"00``````^V@XL```")
-M1"0,B7PD"(E4)`2+A00*``")!"3H_/___^G:````J0``"``/A,\```")+"3H
-M_/___XG#A<`/A+T```#&0"<&QD`F!6;'@)0``````,9`)`;&0"4`QT!$```%
-M`,=`2`````"-B*````"+1"0XP>`&BW0D.(V$L*`+``"-1`4`BU`8B9.@````
-MBT`<B4$$BX.@````B8.8````BT$$B8.<````BWPD8(E[+(D\).C\____B(.V
-M````9H-+.!")/"3H_/___SP)=@9F@4LX``*+1"1@QD`*`8M0/(E8/(M$)&"#
-MP#B)`XE3!(D:B5PD!(DL).C\____B?:#Q$Q;7E]=PY"-M"8`````55=64X/L
-M+(M\)$"+7"1$A=MT%0^V0P6$P'0-//\/A90'``#I'`$``+H`````C78`#[:$
-M.D(%```\_W0-#[;`:\!<C9P'3`$``(/"`8/Z!'7?O@`````/MH0^0@4``#S_
-M=#$/ML!KP%R-G`=,`0``]H0'4@$```)T$L=$)`0`````B1PDZ/S____K"(D<
-M).C\____@\8!@_X$=;L/MD<F9CF'Y`D```^%"P<``(7;=7^`?SD`#X7]!@``
-MQD<Y`8GVBX2?O`(``(7`=%:+4'"%TG0NQT!P`````,>$G[P"````````QT0D
-M"/____^)1"0$BT!XB00D_]+K)XVV`````(M0=(72=!K'0'0`````QX2?O`(`
-M``````"+0'B)!"3_TH/#`8/[0`^$B@8``.N1QD,%_XE<)`2)/"3H_/___^ES
-M!@``N@````"-M"8`````#[:$.D(%```\_P^$]P````^VR&O!7(V<!TP!``")
-M7"0DC80'0`$``(!X$?\/A-4```"`>!8`#X0K!@``O@````!KV5R-K!^$`0``
-MB2PDZ/S___^)P8T$.XN0B`$``(F(B`$``(DIB5$$B0J`>2;_='^`N;4`````
-M#X3I!0``#[99)`^VTXG0@^`&@_@&=2GVP@%T1XE,)`P/MD%-B40D"(M!,(E$
-M)`2+1"0DB00DZ/S____IKP4``(/X!`^%I@4``/;#`0^$G04``(E,)`2)/"3H
-M_/___^F,!0``B4PD!(D\).C\____Z7L%``"-="8`@\8!B?(XE!]6`0``#X9E
-M!0``Z43___^#P@&#^@0/A>W^___'1"0<`````(!_.0"0#X62````NP````"0
-MC70F`(N4G[P"```/MH0[O`0``(72=&2+2G"%R71=@WI@`'57//]T+0^V\&G&
-M*`$```.'?`4``/9`)P1T&(!X)0!U$HET)`B)5"0$B3PDZ/S____K)L>$G[P"
-M````````QT)P`````,=$)`C_____B50D!(M">(D$)/_1@\,!@_M`=8'&1SD!
-MZ:\$``"+3"0<#[:$.4(%```\_P^$BP0```^VT&O"7(V<!TP!``")7"0H@+P'
-M5@$````/A&P$``#&1"0C`(G%C80'A`$``(E$)!"-=@"+5"00B10DZ/S___^)
-MPXU$/0"+D(@!``")F(@!``"+3"00B0N)4P2)&H![)O\/A0T$```/MT,<B40D
-M%`^VE#B\!```9HE4)!J+M(>\`@``]D,H!'1KA?9T9X-^<`!T88-^8`!U6X!C
-M*/OV0R<$C78`=!4/M\*)1"0(B70D!(D\).C\____ZSF+5G"+3"04QX2/O`(`
-M``````#'1G``````QT,@`````,=$)`C_____B70D!(M&>(D$)/_2D(UT)@#V
-M0R<$#X1F`0``QH.T`````("D+U0!``#G]D,H`0^$_0```(!C*/Z+0R"%P'15
-M@'LE`'4P]D,G!'0J#[9'*<'@!@-$)!2)1"0(BX=(!0``B40D!,<$)`<```#H
-M_/___^G<````B40D"(N'2`4``(E$)`3'!"0!````Z/S____IO0```(7V=&2+
-M5G"%THUT)@!T68![)0!U(/9#)P1T&@^W1"0:B40D"(ET)`2)/"3H_/___^F(
-M````BT0D%,>$A[P"````````QT9P`````,=#(`````#'1"0(_____XET)`2+
-M1GB)!"3_TNM5@'LE`'5/]D,G!'1)#[9'*<'@!@-$)!2)1"0(BX=(!0``B40D
-M!,<$)`(```#H_/___^LBB?:+0R"%P'09BU!TA=)T$L=`=`````"+0R"+0'B)
-M!"3_TO9#*`(/A#8"``"+0R")1"0(BX=(!0``B40D!,<$)`8```#H_/___X!C
-M*/WIY`$``(M#((7`#X39`0``@WAT`)`/A,X!``#&0R<!QD,F`(E<)`C'1"0$
-M!@```(M4)"B)%"3H_/___X-[,`!T$HM3"(M##(E"!(D0BT,P@&@P`8![3P!T
-M&HD\).C\____QP0D`0```.C\____@'M/`'7FBY/D````A=)T&\=$)`@!````
-M#[:#V0```(E$)`2)%"3H_/___XM3,(72=!C'1"0(`0````^V0TV)1"0$B10D
-MZ/S___^+<R"%]@^$]@```/9#*`1U78D\).C\____QT0D"`$```"+0R")1"0$
-MB3PDZ/S___^+4R`/MD("B40D"`^V0@&)1"0$QP0DT`(``.C\____BT,@B40D
-M"(N'2`4``(E$)`3'!"0!````Z/S____K.0^V1@*)1"0(#[9&`8E$)`3'!"30
-M`@``Z/S___^+0R")1"0(BX=(!0``B40D!,<$)`$```#H_/___XM6=(72=!X/
-MMT,<QX2'O`(```````#'1G0`````BT9XB00D_]+V0R@"="&+0R")1"0(BX=(
-M!0``B40D!,<$)`8```#H_/___X!C*/W'0R``````QT9@`````(M3-(72=`P/
-MMD--QT2"/`````"+$XM#!(E"!(D0@*PO5@$```&)7"0$B3PDZ/S____V0R@"
-M=":+0R")1"0(BX=(!0``B40D!,<$)`8```#H_/___X!C*/V0C70F`(!$)",!
-M#[9,)",XC"]6`0``#X>I^___@T0D'`&#?"0<!`^%4?O__[@!````@\0L6UY?
-M7<.-M@````"-OP````!75E.#[!"+="0@BSZ)-"3H_/___X3`=!@/ME\KA-MT
-M,0^V5@FY`````/;"`70<ZR'&1@7_B70D!(D\).C\____ZUR)T-/XJ`%U!X/!
-M`3C9=?&)/"3H_/___XG!A<!T/XM6/(E&/(U&.(D!B5$$B0J`1@H!B7$LQD$D
-M!<9!)0#&04T/QT0D#`$```#'1"0(`0```(E,)`2)-"3H_/___X/$$%M>7\.-
-M="8`C;PG`````(/L+(E<)!R)="0@B7PD)(EL)"B+="0TBUY4#[9&)CPD#X=J
-M!P``#[;`_R2%X!,```^W1C(/M]#VP@1T#&;'1C(!`,9&)@'K0V:#^"!U#&;'
-M1C((`,9&)A'K,832>17V1BT#=`\D?X/("&:)1C+&1B8-ZQCVP@AT!L9&)@?K
-M#?;&`G0(QD8K`,9&)AZ)="0$BT0D,(D$).C\____Z?`&``#'1"0,`0```,=$
-M)`@"````QT0D!`$```")-"3H_/___^G+!@``QT0D#`$```#'1"0(`````,=$
-M)`0!````B30DZ/S____II@8``,=$)`P!````QT0D"`$```#'1"0$`0```(DT
-M).C\____Z8$&``#'1"0,`0```,=$)`A@````QT0D!`$```")-"3H_/___^E<
-M!@``#[9&+,=$)!`!````B40D#,=$)`A@````QT0D!`$```")-"3H_/___^DO
-M!@``QT0D$`$```#'1"0,```!!,=$)`@A````QT0D!`$```")-"3H_/___^D"
-M!@``BT,8@6`H___W_\=$)!`!````QT0D#`$```#'1"0(`@```,=$)`0`````
-MB30DZ/S____IRP4``,=$)!`!````QT0D#`````#'1"0(`@```,=$)`0`````
-MB30DZ/S____'!"00)P``Z/S____ID@4``(M#&(%@*/__]__'1"00`0```,=$
-M)`P!````QT0D"`(```#'1"0$`````(DT).C\____Z5L%``#'1"00`0```,=$
-M)`P`````QT0D"`(```#'1"0$`````(DT).C\____QP0D$"<``.C\____Z2(%
-M``#'1"0,`0```,=$)`@"````QT0D!`````")-"3H_/___^G]!```QT0D#`$`
-M``#'1"0(`````,=$)`0`````B30DZ/S____IV`0``,=$)`P!````QT0D"`$`
-M``#'1"0$`````(DT).C\____Z;,$``#'1"00`0```,=$)`S_____QT0D"`$`
-M``#'1"0$`````(DT).C\____Z88$``#'1"0,`0```,=$)`@`````QT0D!```
-M``")-"3H_/___^EA!```#[9&*XM\ACR)7RR)=S0/MD8KB$=-QD<F`\9')0"`
-M3R0%@$,*`8M3/(U#.(E[/(D'B5<$B3K'!"2`&@8`Z/S___^+5"0P@'HK`'0I
-MO@````#V0PD!=`[K'`^V0PF)\=/XJ`%U%8/&`8GPBU0D,#A"*W?FZP6^````
-M`(M3&(M"**D```@`=`HE___W_XE"*.MDB?$/ML&-+,4`````N[@+``")\#P#
-M=AR+5"0PBP(%@`$```'HBP"C`````,'H$X/@`>L<BTPD,(L!!8`!``"-1`4`
-MBP"C`````,'H$X/@`83`=1''!"3H`P``Z/S___^#ZP%UK6;'AY0``````(E\
-M)`2+1"0PB00DZ/S____I3P,``,<$)$`-`P#H_/___\=$)`P`````QT0D""``
-M``#'1"0$`0```(DT).C\____QP0D$"<``.C\____Z1(#``#'1"0,`````,=$
-M)`@!````QT0D!`````")-"3H_/___\<$)!`G``#H_/___^GA`@``BT,8@6`H
-M___W_\=$)!``````QT0D#/_____'1"0(`0```,=$)`0`````B30DZ/S____'
-M!"00)P``Z/S____IG@(``,=$)`P`````QT0D"`````#'1"0$`````(DT).C\
-M____QP0D$"<``.C\____Z6T"``")="0$BU0D,(D4).C\____Z5@"``")="0$
-MBTPD,(D,).C\____Z4,"``#'1"00`0```,=$)`SP````QT0D")L```#'1"0$
-M`0```(DT).C\____Z18"``#'1"00`0```,=$)`R@UEHKQT0D".`#``#'1"0$
-M`0```(DT).C\____Z>D!``#'1"00`0```,=$)`P`X`,`QT0D"*0#``#'1"0$
-M`0```(DT).C\____Z;P!``#'1"00`0```,=$)`SDJ`8!QT0D",0#``#'1"0$
-M`0```(DT).C\____Z8\!``#'1"0,`0```,=$)`A(`P``QT0D!`$```")-"3H
-M_/___^EJ`0``QP0D0`T#`.C\____QT0D#`$```#'1"0((````,=$)`0!````
-MB30DZ/S____'!"00)P``Z/S____I+0$``,=$)!`!````QT0D#`````#'1"0(
-M(0```,=$)`0!````B30DZ/S____I``$``,=$)`P!````QT0D"&````#'1"0$
-M`0```(DT).C\____Z=L````/MD8LQT0D$`$```")1"0,QT0D"&````#'1"0$
-M`0```(DT).C\____Z:X```#&0P4`BT94B00DZ/S____IF@```,=$)`P!````
-MQT0D"`$```#'1"0$`````(DT).C\____QP0D$"<``.C\____ZVR+0QB!8"C_
-M__?_QT0D$`$```#'1"0,_____\=$)`@!````QT0D!`````")-"3H_/___\<$
-M)!`G``#H_/___^LLQT0D#`$```#'1"0(`0```,=$)`0`````B30DZ/S____'
-M!"00)P``Z/S___^X`0```(M<)!R+="0@BWPD)(ML)"B#Q"S#C;0F`````(/L
-M'(E<)!")="04B7PD&(M<)""+?"0D#[=7$&:!^H4`=WX/M\(/MH08O`0``#S_
-M=&]F@_I_=QD/ML!IP"@!```#@WP%``"+0"P/MD@$ZU:0#[='$&8]@0!W(`^W
-MP`^VA!B\!```:<`4#0```X.T!0``BT`(#[9(!.LK#[='$`^VA!B\!```:<"P
-M`````X.8!0``BT!4#[9(!.L*D(UT)@"Y_____[C_____9H%_$(4`=PP/MT<0
-M#[:$&+P$``"+LY@%```/MM&`^?]T%("\&D(%``#_=`H\_W0&@'\4!G4F@W]0
-M`'0/C4=0B40D!(D<).C\____B7PD!(D<).C\____Z>H````/ML!IP+`````!
-MQ@^V1B8\&G1V/!IW"CP1#X6;````ZQL\&XVT)@````!T8SP<#X6&````C;8`
-M````ZWJ+DT0*``"!PDP(```/MD8TP>`(`<*+"HD-``````^VR8N31`H``('"
-M1`@```^V1C3!X`@!PHL"HP````#!X`@)P8F.E````,9&)AKK,<9&)AOK*XN#
-M1`H```5,"```#[96-,'B"`'0BP"C`````(/@]XA&+,9&)ASK!,9&)AV#?U``
-M=`^-1U")1"0$B1PDZ/S___^)?"0$B1PDZ/S___^)="0$B1PDZ/S___^-=@"+
-M7"00BW0D%(M\)!B#Q!S#@^P,BT0D$(E$)`2+`(D$).C\____@\0,PXVT)@``
-M``"#["R)7"0<B70D((E\)"2);"0HBUPD-(MS+`^W4QRX`````(M,)#"`O`J\
-M!```_P^$.PD```^V0R8\"0^$+P4``#P)=TL\!0^$F````#P%D'<>/`,/A+8`
-M```\!(UT)@`/A>X(``#IY````)"-="8`/`</A(T$```\!XVV``````^'$`0`
-M`.F9`@``D(UT)@`\%@^$?`,``#P6C;8`````=R,\%`^$F`4``#P4C70F``^'
-MY@(``#P*#X66"```B?;I$`4``#P:#X0W`@``//^0#X1P!0``/!</A78(``")
-M]NE"`P``BT0D,`^V:"N)ZH32#X2A````#[96";\`````]L(!#X2"````Z8H`
-M``")]HM&&(%@*/___O^+0RS'1"0,`````,=$)`@!````B5PD!(D$).C\____
-MQP0D!0```.C\____N`$```#I(0@``,=$)`P`````QT0D"`````")7"0$B30D
-MZ/S____'!"10PP``Z/S___^X`0```.GO!P``B=")^=/XJ`%U$H/'`8GXB>DX
-MR'7KZP6_``````^V4R2)T(/@!H/X!G4)]L(!#X75````BU88BT(HJ0```0!T
-M#27___[_B4(HZ;L```")^@^VPL'@`XE$)!B]$"<``)"+3"0PBQ&)^#P#=AF+
-M3"08C801@`$``(L`HP`````E```!`.L7BTPD&(V$$8`!``"+`*,`````)0``
-M`0"%P'0RB?@\`W86BTPD&(V$$8`!``#'`````0#I'P<``(M,)!B-A!&``0``
-MQP````$`Z0D'``#'!"3H`P``Z/S___^#[0$/A7G____&0R<"QD,F_XE<)`2+
-M1"0PB00DZ/S___^X`0```.GG!@``]D8&`70VB5PD!(DT).C\____A,!U)KWZ
-M````B5PD!(DT).C\____A,!U$<<$).@#``#H_/___X/M`77?B?J`^@-V'(M,
-M)#"+`06``0``#[;2C130BP*C`````(D"ZQR+5"0PBP(%@`$``(GY#[;1C130
-MBP*C`````(D"BT,LB=KH(N7__\<$)"!.``#H_/___[@!````Z4P&``")5"0$
-MQP0D>`D``.C\____BW,LBSZ)/"3H_/___XG!A<!U$<:#M0````&X`0```.D8
-M!@``QD`DX<9`)0'&0"87#[=#'&:)01"+!HE!&,=!(`````#'030`````QT%L
-MP"X#`(E,)`2)/"3H_/___[@!````Z=0%``")5"0$QP0DY@(``.C\____BW,L
-MBSZ)/"3H_/___XG!A<!U$<:#M0````&X`0```.F@!0``QD`DX<9`)0'&0"88
-M#[=#'&:)01"+!HE!&,=!(`````#'030`````QT%LP"X#`(E,)`2)/"3H_/__
-M_[@!````Z5P%``")VHGPZ!/D__^X`0```.E)!0``BSZ)/"3H_/___XG"#[9+
-M/(7`=1'&@[4````!N`$```#I)`4``,9`).'&0"4!QD`F!8A()P^W0QQFB4(0
-MBP:)0AC'0B``````QT(T`````,=";,`N`P"(2S^)5"0$B3PDZ/S___^X`0``
-M`.G:!```BSZ)/"3H_/___XG"#[9+/H7`=1'&@[4````!N`$```#IM00``,9`
-M).'&0"4!QD`F!(A()P^W0QQFB4(0BP:)0AC'0B``````QT(T`````,=";,`N
-M`P"(2T&)5"0$B3PDZ/S___^X`0```.EK!```BSZ)/"3H_/___XG!A<!U$<:#
-MM0````&X`0```.E*!```QD`DX<9`)0'&0"8&#[=#'&:)01"+!HE!&,=!(```
-M``#'030`````QT%LP"X#`(E,)`2)/"3H_/___[@!````Z08$``"-M@````"+
-M/HD\).C\____B<&%P'41QH.U`````;@!````Z=\#``#&0"3AQD`E`<9`)@P/
-MMT,<9HE!$(L&B4$8QT$@`````,=!-`````#'06S`+@,`B4PD!(D\).C\____
-MN`$```#IFP,``(L^B3PDZ/S___^)P87`=1'&@[4````!N`$```#I>@,``,9`
-M).'&0"4!QD`F%L9`*`$/MT,<9HE!$,9!:`^+!HE!&,=!(`````#'030`````
-MQT%LP"X#`(E,)`2)/"3H_/___[@!````Z2X#``#&0R;_9L>#E```````#[93
-M)(G0@^`&@_@&=07VP@%U'H-[-`!U&(DT))"-="8`Z/S___^(@[8```"0C70F
-M`(![)P)U&HM#+(E<)`B)1"0$BT0D,(D$).C\____C78`]D8(`G4:NP````"-
-M?CB`?@H`#X5@`0``Z7P"``"-=@"+5B@/MEHJ#[;+#[9"'X/H`3G!?3:-0P&(
-M0BJ`0BL!QD(F``^W0C*#X/Z#R`AFB4(RB50D!(M4)#")%"3H_/___[@!````
-MZ64"```YP706NP````"-?CB`?@H`=32-=@#I+P(``,9")@`/MT(R@^#V@,P"
-M9HE",HE4)`2+3"0PB0PDZ/S___^X`0```.D?`@``B3PDZ/S___^)P8M&/(E.
-M/(DYB4$$B0B`>2;_#X2.````@+FU``````^$U0$```^V620/MM.)T(/@!H/X
-M!G4J]L(!=%$/MD%-BU$PB4PD#(E$)`B)5"0$B30DZ/S___^X`0```.FV`0``
-M@_@$#X61`0``]L,!#X2(`0``B4PD!(M$)#")!"3H_/___[@!````Z8H!``")
-M3"0$BU0D,(D4).C\____N`$```#I<`$``,:!M0````"#PP$X7@H/AD$!``#I
-M.?___XD\).C\____B<&+1CR)3CR).8E!!(D(@'DF_P^$GP```(!Y)0`/A8X`
-M``"`N;4`````#X0$`0``#[99)`^VTXG0@^`&@_@&=2KVP@%T40^V04V+43")
-M3"0,B40D"(E4)`2)-"3H_/___[@!````Z>4```"#^`0/A<````#VPP$/A+<`
-M``")3"0$BTPD,(D,).C\____N`$```#IN0```(E,)`2+1"0PB00DZ/S___^X
-M`0```.F?````QH&U`````(/#`0^V1@HXV`^',?___SC#=4Z$P'1*NP````"-
-M?CB)/"3H_/___XG"BT8\B58\B3J)0@2)$`^V0B4\(G0$/`UU%\=$)`0*````
-MB10DZ/S___^X`0```.L_@\,!.%X*=[[&1@7_B70D!(M4)#")%"3H_/___[@!
-M````ZQRX`0```.L5A>V-=@`/A`'Y___I'OG__Y"-="8`BUPD'(MT)""+?"0D
-MBVPD*(/$+,.-M@````"-OP````"#["R)7"0<B70D((E\)"2);"0HBWPD,(ML
-M)#0/MU409H'ZA0`/A[X````/M\(/MHP'O`0``(#Y_P^$J@```&:#^G]W'`^V
-MP8N7?`4``&G`*`$``(M$$"P/MD`$ZSJ-=@!F@?J!`'<9#[;!BY>T!0``:<`4
-M#0``BT00"`^V0`3K%P^VP8N7F`4``&G`L````(M$$%0/MD`$//]T30^VP`^V
-MG`="!0``@/O_=!6`^?]T$`^V512`^@9U5XVT)@````"`^_]T(X#Y_W0>#[;!
-M:<`H`0``B<8#MWP%``#&1B<"QD8F_^E8`@``@WU0`'0/C450B40D!(D\).C\
-M____B6PD!(D\).C\____Z5\"``")]@^VP6G`*`$``(G&`[=\!0``BTTTA-(/
-MA+0````/MD4F/`8/A,T````\#`^$Q0````^WEI0```"-0@%FB8:4````9H/Z
-M"787@'XF!G01QD8G`L9&)O^`9BC^Z=(!``#'!"3H`P``Z/S___\/ME8DB="#
-MX`:#^`9U/O;"`70YQT0D$`````#'1"0,`@````^V1DV)1"0(BT8PB40D!`^V
-MPVO`7(V$!TP!``")!"3H_/___^FG`0``QD8F`XET)`2)/"3H_/___^F2`0``
-MD(UT)@`/MD4F/`%U#<9&)@2-="8`Z4L!```\`G4,QD8F!8UV`.D[`0``/`,/
-MA;T```")R(!^)@5U*V:!>03(-W4C#[=&'(E$)`3'!"2L"0``Z/S____&1B8&
-MZ08!``"-M@````")1"0$B30DZ/S___^-1F2Z*````.CGO___A,!U.(U&4+H4
-M````Z-:___^$P'4GC8:,````N@@```#HPK___X3`=1.+1D0+1DAT"\9&)A>)
-M]NFK````9H.^E````!UV$<9&)P+&1B;_@&8H_NF0````QP0DZ`,``.C\____
-MQD8F&F:#AI0````!ZW8\%W4&QD8F%>ML/!AU"L9&)A:-="8`ZUX\!'4&QD8F
-M!^M4/`6)]G4&QD8F".M(/`9U!L9&)@GK/CP,=0;&1B8*ZS0\%HGV=0;&1B84
-MZR@\#G4D@WU0`'0/C450B40D!(D\).C\____B6PD!(D\).C\____ZRZ0@WU0
-M`'0/C450B40D!(D\).C\____B6PD!(D\).C\____B70D!(D\).C\____BUPD
-M'(MT)""+?"0DBVPD*(/$+,/K#9"0D)"0D)"0D)"0D)"#["R)7"0<B70D((E\
-M)"2);"0HBVPD-(MU+`^W11RZ`````(M,)#"`O`&\!```_P^$ZP(```^V128\
-M%`^$U````#P4=SL\#0^$!`$``#P-D'<0/`4/A;L"``"-M@````#K4SP.#X3[
-M````/`^-="8`#X6?`@``Z?P```"0C70F`#P;#X2?````/!N-M@````!W$#P8
-M=#D\&0^%=P(``(GVZT<\''1=//\/A6<"``")]NG&````QT0D!`````")+"3H
-M_/___[H!````Z5$"``#'1"0$`0```(DL).C\____N@$```#I-P(``,=$)`0!
-M````B2PDZ/S___^Z`0```.D=`@``B2PDZ/S___^Z`0```.D+`@``B2PDZ/S_
-M__^Z`0```.GY`0``]D4Y!'02B2PDZ/S___^Z`0```.GA`0``B2PDZ/S___^Z
-M`0```.G/`0``B2PDZ/S___^Z`0```(GVZ;L!``")+"3H_/___[H!````Z:D!
-M``#&12;_@'X*``^$Z0```+L`````C7XXC78`B3PDZ/S___^)PHM&/(E6/(DZ
-MB4($B1"`>B;_#X2?````@'HE``^%G````("ZM0`````/A$T!```/MEHD#[;+
-MB<B#X`:#^`9U*O;!`712B50D#`^V0DV)1"0(BT(PB40D!(DT).C\____N@$`
-M``#I'0$``(/X!`^%"0$``/;#`9`/A/\```")5"0$BT0D,(D$).C\____N@$`
-M``#I\````(E4)`2+3"0PB0PDZ/S___^Z`0```.G6````C;8`````QH*U````
-M`(/#`0^V1@HXV`^'*O___SC##X6,````#[9%)3PB=!0\#700OP````"-;CB`
-M?@H`=1SK<,=$)`0*````B2PDZ/S___^Z`0```.E\````B2PDZ/S___^)PXM&
-M/(E>/(DKB4,$B1@/MD,E/")T!#P-=2F)7"0$QP0D_`(``.C\____QT0D!`H`
-M``")'"3H_/___[H!````ZS*)]H/'`8GX.$8*=ZK&1@7_B70D!(M,)#")#"3H
-M_/___[H!````ZPNZ`0```(VV`````(G0BUPD'(MT)""+?"0DBVPD*(/$+,.-
-M=@"-O"<`````55=64X/L+(M<)$0/MU,0N?____^X_____V:!^H4`=WL/M\*+
-M="1`#[:,!KP$``"X_____X#Y_W1B9H/Z?W<=#[;!BWPD0(N7?`4``&G`*`$`
-M`(M$$"P/MD`$ZS]F@?J!`'<=#[;!BW0D0(N6M`4``&G`%`T``(M$$`@/MD`$
-MZQL/ML&+?"1`BY>8!0``:<"P````BT005`^V0`0/ML"+5"1`#[:T`D(%``!K
-MQER-A`),`0``B40D)`^VP6G`*`$```."?`4``(E$)"B+2S0/MA'!XA@/MD$!
-MP>`0"<(/MD$#"<(/MD$"P>`("<*-60B)T,'H`X/X$'8%N!````"-!,&)1"0<
-M.<,/AY`!``#'1"0@`````&OV7(ET)!@#="1`B70D%(D<).C\____B<6-<P2_
-M=!0``+D$````_/.F#Y?"#Y+`.,(/A40!``"#_1`/ASL!``"#1"0@`8-\)"`!
-M=2J+3"0HQX$<`0```0```(FI(`$``(L#B8&H````BT,$B8&L````Z04!``"+
-M="1`B30DZ/S___^)QH7`#X3\````QD`G!L9`)@5FQX"4``````#&0"0&QD`E
-M`,=`1```!0#'0$@`````QX`<`0```0```(FH(`$``(M4)"B!PJ````"+?"0H
-MBX>@````B8:@````BT($B8:D````BX>@````B8:8````BT($B8:<````BP.)
-MAJ@```"+0P2)AJP```"+1"0DB48LB00DZ/S___^(AK8```!F@TXX$(M4)"2)
-M%"3H_/___SP)=@9F@4XX``*+3"04@(%6`0```8N1B`$``(FQB`$``(M\)$"+
-M3"08C80/A`$``(D&B58$B3*)="0$B3PDZ/S___^-M@````"#PP@[7"0<#X:'
-M_O__@\0L6UY?7<.-="8`C;PG`````%575E.!["P"```/MH0D2`(``(N4)$`"
-M``"+4@B)5"0<BPJ)3"0@BY0D0`(```^V4C"(5"0GBXPD0`(``(/!*(E,)"B+
-ME"1``@``.4HH#X2K`@``@'PD)P`/A*`"```/ML")1"04BTPD*(D,).C\____
-MC7CXC40D+(E$)!"+5"04B50D#,=$)`@!````BTPD'(E,)`2+A"1$`@``B00D
-MZ/S___^`?"0L``^$_@```+T`````C9>@````B50D&(UV`(GI#[;QQT0D"`@`
-M``"+1"08B40D!(GSP>,$C80<F````(D$).C\____A,`/A)\```"-E!R,````
-M#[9""(/@#XB'M@````^W3SAF@>'?_8G(@\@09HE'.`^V0@C`Z`0\"74)B<B#
-MR#!FB4<XB?#!X`0/MH0$E````,#H!#P*=09F@4\X``*+3"0HBU$$C4<(B4$$
-MB4\(B5<,B0+V1R@"=$"`9RC]BT<@A<!T-8E$)`B+5"0@BX)(!0``B40D!,<$
-M)`8```#H_/___^L5D(UT)@"#Q0&)Z3A,)"QV$>D@____B>@X1"0L#X<W`0``
-MB7PD",=$)`0&````BU0D'(D4).C\____@']/`'0DC;8`````BTPD((D,).C\
-M____QP0D`0```.C\____@']/`'7BBY?D````A=)T&\=$)`@!````#[:'V0``
-M`(E$)`2)%"3H_/___XM7,(72=!C'1"0(`0````^V1TV)1"0$B10DZ/S___^+
-M1R"%P'1]QT!@`````/9'*`1U)XM$)"")!"3H_/___\=$)`@!````BT<@B40D
-M!(M4)"")%"3H_/___XM'((E$)`B+3"0@BX%(!0``B40D!,<$)`8```#H_/__
-M_XM'((E$)`B+5"0@BX)(!0``B40D!,<$)`$```#H_/___\='(`````"+%XM'
-M!(E"!(D0BTPD'(!I"@&+A"1``@``@&@P`8E\)`2+5"0@B10DZ/S___^+1"0H
-MBXPD0`(``#E!*'0+@&PD)P$/A6?]__^!Q"P"``!;7E]=PXVT)@````!55U93
-M@>PL`@``B[PD1`(``(N$)$`"``"+`(E$)"0/MK0D3`(``(U<)"R)7"00B70D
-M#,=$)`@!````BY0D0`(``(E4)`2)/"3H_/___XET)`B)?"0$B[0D2`(``(DT
-M).C\____BVXH@^T(B?.#PRB-10@YV'0K#[9%)3P-=!0\(G4PZPX/MD4E/`UT
-M!CPBB?9U(,9%)@7&12<$QD0D*@'K!<9$)"H`@'PD+`!U%>D@`@``BVT(@^T(
-MC44(.=AUQ9#KW\9$)"L`BX0D0`(``(/`.(E$)""+E"1(`@``BW(H@^X(C48(
-M.<,/A`,"```/MD0D*\'@!(V\!)@```"-="8`QT0D"`@```")?"0$C8:@````
-MB00DZ/S___^$P`^%G`$``(MV"(/N"(U&"#G8#X2]`0``Z\N+M"1``@``@$8*
-M`<9!)@7&@;0`````QD$G!&;'@90``````,:!E@````#'040```4`QT%(````
-M``^V="0KB?#!X`2-E`2,````#[9"!(A!)`^V0@6(026+A"1``@``B4$L#[9"
-M"(/@#XB!M@````^W>3AF@>??_8GX@\@09HE!.`^V0@C`Z`0\"74)B?B#R#!F
-MB4$XB?#!X`0/MH0$E````,#H!#P*=09F@4DX``*+E"1(`@``B5$PB?+!X@0/
-MMH04D@```(A!38V4%(P```"+0@R)@:````"+4A")D:0```")@9@```")D9P`
-M``"+M"1(`@``@$8P`8N4)$`"``"+0CR)2CR+="0@B3&)002)"(N$)$@"``"+
-M4"R-00B+M"1(`@``B48LB5D(B5$,B0(/ME$DB="#X`;&1"0J`(/X!G5']L(!
-M="V)3"0,#[9!38E$)`B+A"1(`@``B40D!(N4)$`"``")%"3H_/___\9$)"H`
-MZQ6)3"0$BW0D)(DT).C\____QD0D*@"`1"0K`0^V1"0K.$0D+`^'`_[__X!\
-M)"H`="W'1"0$"@```(DL).C\____ZQN0C70F`(M4)"2)%"3H_/___XG!A<`/
-MA2_^__^!Q"P"``!;7E]=P^L-D)"0D)"0D)"0D)"0D%575E.!["P"``"+A"1`
-M`@``BS`/ME`<B%0D)H/`+(E$)"B+C"1``@``.4$L#X30`P``A-(/A,@#``"+
-M1"0HB00DZ/S___^-:.#'1"00`````,=$)`P`````QT0D"`````"+E"1``@``
-MB50D!(N,)$0"``")#"3H_/___XA$)">$P`^$:P,``+\`````NP````")7"0@
-MQT0D$`````")7"0,QT0D"`$```"+A"1``@``B40D!(N4)$0"``")%"3H_/__
-M_P^VP,'@!(/`9#T``@``#X?I`0``C4PD+(E,)!")7"0,QT0D"`$```"+A"1`
-M`@``B40D!(N4)$0"``")%"3H_/___\=$)`@(````B6PD!(V,)(@```")#"3H
-M_/___X3`#X28`0``BT0D*(M0!(U%((M,)"B)002)32")522)`@^V1"0NB$4Q
-MC80D@````(E$)`2+A"1``@``B00DZ/S___\\_W02#[;`:<`4#0```X:T!0``
-MB44,B?J$TG15#[9$)"_1Z(/@`<'@!`^V536#XN\)PHA5-0^V1"0OP>@#@^`!
-MP>`%@^+?"<*(534/MD0D+\'H`H/@`<'@`X/B]PG"B%4U#[9$)#*(A8L```#I
-MOP````^V1"0NB$4QBXPD0`(``(E-"`^V1"0RB(6+````#[=$)#")13@/MT0D
-M?&:)A8@````/MD0D?HB%B@```(U->(U4)"R#PD"+1"1LB45XBT($B4$$BT((
-MB4$(BT(,B4$,C4U(C50D+(/"$(M$)#R)14B+0@2)002+0@B)00B+0@R)00R-
-M35B-5"0L@\(@BT0D3(E%6(M"!(E!!(M""(E!"(M"#(E!#(M"$(E!$(M"%(E!
-M%(M$)&2)17"+1"1HB45TBT0D((E$)`R);"0(BY0D1`(``(E4)`2+C"1``@``
-MB0PDZ/S____I&`$``(GV@\<!@\,!B?@Z1"0G#X0@`0``Z;K]__^)/"3H_/__
-M_XU8^(E<)`C'1"0$!@```(N4)$`"``")%"3H_/___X![3P!T&HDT).C\____
-MQP0D`0```.C\____@'M/`'7FBT,@A<!T;<=`8`````#V0R@$=1^)-"3H_/__
-M_\=$)`@!````BT,@B40D!(DT).C\____BT,@B40D"(N&2`4``(E$)`3'!"0!
-M````Z/S___^+0R")1"0(BX9(!0``B40D!,<$)`8```#H_/___\=#(`````"+
-M$XM#!(E"!(D0BXPD0`(``(!I"@&`;3`!B5PD!(DT).C\____.7TH#X48____
-MBX0D0`(``(!H'`&);"0$B30DZ/S___^+3"0HBY0D0`(``#E*+'0<@&PD)@%T
-M%>E(_/__C7TH.7TH#X79_O__B?;KO8'$+`(``%M>7UW#C78`55=64X'L+`(`
-M`(NL)$0"``"+10")1"0<BY0D0`(``(E4)`2)+"3H_/___\=$)!``````QT0D
-M#`````#'1"0(`````(EL)`2+G"1``@``B1PDZ/S___^(1"0CA,`/A+X#``#&
-M1"0B`,=$)"0`````D,=$)!``````BT0D)(E$)`S'1"0(`0```(EL)`2+E"1`
-M`@``B10DZ/S___\/ML#!X`2#P&0]``(```^'6`,``(U<)"R)7"00BT0D)(E$
-M)`S'1"0(`0```(EL)`2+E"1``@``B10DZ/S___^-G"2(````B5PD!(DL).C\
-M____//\/A1(#``"+1"0<B00DZ/S___^)QX7`#X0O`P``@$4<`<9`,`"+A"2(
-M````B0>+A"2,````B4<$C80D@````(E$)`2)+"3H_/___SS_=!8/ML!IP!0-
-M``"+5"0<`X*T!0``B4<,#[9$)"Z(1S$/MD0D+]'H@^`!P>`$#[97-8/B[PG"
-MB%<U#[9$)"_!Z`.#X`'!X`6#XM\)PHA7-0^V1"0OP>@"@^`!P>`#@^+W"<*(
-M5S6);P@/MD0D,HB'BP```(M$)#2)1T"+1"0XB4=$#[9$)#.(1S(/MT0D,(E'
-M.`^W1"1\9HF'B`````^V1"1^B(>*````C4]XC50D+(/"0(M$)&R)1WB+0@2)
-M002+0@B)00B+0@R)00R-3TB-5"0L@\(0BT0D/(E'2(M"!(E!!(M""(E!"(M"
-M#(E!#(U/6(U4)"R#PB"+1"1,B4=8BT($B4$$BT((B4$(BT(,B4$,BT(0B4$0
-MBT(4B4$4BT0D9(E'<(M$)&B)1W2+33"-5R")53"-12R)1R")3R2)$8!\)"P`
-M#X2"`0``9L=$)"H``(U=.(E<)!B-1RB)1"04C;8`````BU0D'(D4).C\____
-MB<&%P`^$A`$``(!%"@'&0"8%QH"T`````,9`)P3'0$0```4`QT!(`````&;'
-M@)0```````^W="0JB?#!X`2-E`2,````#[9"!(A!)`^V0@6(026):2R)>3`/
-MMD(&B$%-#[9""(/@#XB!M@````^W63AF@>/?_8G8@\@09HE!.`^V0@C`Z`0\
-M"74*B=B#R#!FB4$XD(GPP>`$#[:$!)0```#`Z`0\"G4,9H%).``"C;8`````
-MB?#!X`2-E`2,````BT(,B8&@````BU(0B9&D````B8&8````B9&<````@$<P
-M`8M%/(E-/(M<)!B)&8E!!(D(BU<LC4$(B4<LBUPD%(E9"(E1#(D"#[91)(G0
-M@^`&@_@&=2_VP@%T&HE,)`P/MD%-B40D"(E\)`2)+"3H_/___^L0B4PD!(M$
-M)!R)!"3H_/___V:#1"0J`0^V1"0L9CM$)"H/AYG^__^`1"0B`8-$)"0!#[94
-M)",X5"0B#X50_/__@'T*`'44QD4%_XEL)`2+7"0<B1PDZ/S___^!Q"P"``!;
-M7E]=PXUT)@"-O"<`````55=64X/L+(ML)$"+?"1$QT0D$`````#'1"0,````
-M`,=$)`@`````B7PD!(DL).C\____A,!T.+L`````@^@!#[;PC40D*XE$)`R)
-M7"0(B7PD!(DL).C\____@'PD*_X/A:4```"#PP&-1@$YPW73#[9'-(/H`8A'
-M-(3`='6+-\9'-`"+7RR#ZR"-5RR-0R`YT'1W@WL,`'5(ZPN0C70F`(-[#`!U
-M.\9'-`&)?"0$B2PDZ/S____'1"00``````^V@XL```")1"0,B5PD"(E\)`2+
-MA@0*``")!"3H_/___^LIBUL@@^L@C4,@.=!ULHGVZQB)?"0$B2PDZ/S___^)
-M?"0$B2PDZ/S___^#Q"Q;7E]=PXVT)@````"-O"<`````55=64X/L#(MT)""+
-M?"0DBRZ["@```(E\)`2)-"3H_/___X3`=1''!"3H`P``Z/S___^#ZP%UWP^V
-M72N$VW0@#[96";D`````]L(!=`OK$)")T-/XJ`%U!X/!`3C9=?&+%XM'!(E"
-M!(D0@&X*`8E\)`2)+"3H_/____9&"`)T08M&*(7`=1.)+"3H_/___X7`#X1:
-M`0``B48HB2B)<%3&0"H`QD`K`,9`)@!F@T@R!(E$)`2)+"3H_/___^DP`0``
-MBT8HA<`/A,L```"#P%B)1"0$BT44B00DZ/S___^+1BB)1"0$B2PDZ/S___^-
-M?C@Y?C@/A)<```")/"3H_/___XG#BT`@A<!T;<=`8`````#V0R@$=1^)+"3H
-M_/___\=$)`@!````BT,@B40D!(DL).C\____BT,@B40D"(N%2`4``(E$)`3'
-M!"0!````Z/S___^+0R")1"0(BX5(!0``B40D!,<$)`8```#H_/___\=#(```
-M``"`;@H!B5PD!(DL).C\____.7XX#X5I____QT8H`````(!^"@!T$XU&.(D$
-M).C\____B<&`;@H!ZPJ)+"3H_/___XG!A<ET,XM6/(E./(U&.(D!B5$$B0J`
-M1@H!B7$LQD$D!<9!)0#&02<&QD$F`XE,)`2)+"3H_/___X/$#%M>7UW#D(VT
-M)@````"#["R)7"0<B70D((E\)"2);"0HBWPD,(M<)#0/MU,09H'ZA0!W>@^W
-MP@^VC`>\!```@/G_=&IF@_I_=QD/ML&+EWP%``!IP"@!``"+1!`L#[9`!.L[
-M9H'Z@0!W&0^VP8N7M`4``&G`%`T``(M$$`@/MD`$ZQL/ML&+EY@%``!IP+``
-M``"+1!!4#[9`!(UT)@`/MM$\_W0)9H'Z_P!U*(GV@WM0`'0/C4-0B40D!(D\
-M).C\____B5PD!(D\).C\____Z3H!```/ML`/MHP'0@4```^WPFG`*`$``(G&
-M`[=\!0``@'L4``^$I@```&O!7(VL!T`!```/MD46B40D$`^V116)1"0,#[9#
-M)XE$)`@/MD,FB40D!,<$),P)``#H_/___XL6BT8$B4($B1"`;18!B70D!(D\
-M).C\____B5PD!(D\).C\____#[9W*XGPA,`/A*H````/MET5N0````#VPP%U
-M#>L<#[;*B=C3^*@!=!:)3"0$B3PDZ/S____I?@```+H`````@\(!B?`XPG76
-MZVYKP5R-K`=,`0``@'LF`74VQP0D$"<``.C\____B5PD!(D\).C\____QT0D
-M#`$```#'1"0(`````(ET)`2)+"3H_/___^LHQP0D4,,``.C\____B5PD!(D\
-M).C\____B70D!(DL).C\____C70F`(M<)!R+="0@BWPD)(ML)"B#Q"S#C;8`
-M````C;\`````55=64X/L'(MT)#"+;"0T#[9$)#B(1"07#[9$)#R(1"06BP:)
-M1"08@'X*`'1TNP````"-?CB)/"3H_/___XG"BT8\B58\B3J)0@2)$#EJ,'4/
-M#[9$)!<X0DUT#9"-="8`@\,!.%X*=\TX7@IT-(!\)!90=2W&0B<&QD(F!<9"
-M)`?&0B4`B6HPB7(LQH*6`````(E4)`2+1"08B00DZ/S___^#Q!Q;7E]=PXVT
-M)@````"#["R)7"0<B70D((E\)"2);"0HBVPD,(M$)#0/MU`09H'ZA0`/AX8`
-M```/M\(/MH0HO`0``#S_='=F@_I_=Q@/ML!IP"@!```#A7P%``"+0"P/ME`$
-MZUZ+5"0T#[="$&8]@0!W(`^WP`^VA"B\!```:<`4#0```X6T!0``BT`(#[90
-M!.LPBTPD-`^W01`/MH0HO`0``&G`L`````.%F`4``(M`5`^V4`3K"XVV````
-M`+K_____N?____^+1"0T9H%X$(4`=Q"+3"0T#[=!$`^VC"B\!```#[;"#[:$
-M*$(%``!KP%R-O`5,`0``#[;!:<"P````B[68!0```<:+1"0T@'@H`@^%B```
-M``^V0"PE\````(/X('0%@_@0=76+3"0T#[91+(G0@^`/@_@!=3&)T"7P````
-MQT0D$`$```")1"0,QT0D"`(```#'1"0$`````(DT).C\____Z0$*``"0#[9&
-M*XM4ACR+3"0T#[9!+"7P````@_@@#Y3`@\`(B(*V````BT(T9H%@,O_^Z<X)
-M``"+5"0T#[9"%(3`=$.)PX-Z4`!T$8G0@\!0B40D!(DL).C\____BTPD-(E,
-M)`2)+"3H_/___X#[`@^%D`D``(ET)`2)+"3H_/___^E_"0``QX:8````````
-M``^V1B8\)`^'"0D```^VP/\DA7P4``"+1QCV0"H(#X0R"0``B?;IMP4``(N5
-M1`H``('"3`@```^V1C3!X`@!PHL"HP````"#^`5W!8A&'^L$QD8?!8!_"P!T
-M#<9&)@#&1PL`Z:X(``#&1B8"Z:4(``"+E40*``"!PDP(```/MD8TP>`(`<*+
-M`J,`````#[;`9HE&((N51`H``('"1`@```^V1C3!X`@!PHL"HP````")PL'J
-M"&:)5B+!X`AF"48@9H'Z0$%U"<9&)AGI1@@``&:!?B(5EP^4P(/H`8/@WX/`
-M)(A&)NDL"```BY5$"@``@<)$"```#[9&-,'@"`'"BP*C`````(A&'8N51`H`
-M`('"3`@```^V1C3!X`@!PHL"HP````"H"'0&QD8>#.L:J`1T!L9&'@OK$(/@
-M`H/X`1G`]]"#X`J(1AX/MD8K/`$9P(/@`H/`%(A&)NFW!P``BX5$"@``!4P(
-M```/ME8TP>((`="+`*,`````@\@(B$8LQD8F!>F-!P``QD8F``^W1C)F)??]
-M@\@"9HE&,HM$)#2#>%``=`^#P%")1"0$B2PDZ/S___^+5"0TB50D!(DL).C\
-M____QD<%_XE\)`2)+"3H_/___^F<!P``QD8F!.DS!P``#[9&*X/``8A&*SI&
-M'W-7QD8F%HM,)#2#>5``=!&)R(/`4(E$)`2)+"3H_/___XM$)#2)1"0$B2PD
-MZ/S____'1EB`A!X`QT9@`````(EV9(U&6(M5%(E$)`2)%"3H_/___^DM!P``
-MQD8K`,9&)A?'!"0@H0<`Z/S____IM`8``,9&)A3IJP8``,9&)@B-M"8`````
-MZ9L&``#&1B84Z9(&``#&1BX`Z/S___^)AH@```#&1B85Z7H&``"+E40*``"!
-MPDP(```/MD8TP>`(`<*+&HD=``````^VVXN51`H``('"1`@```^V1C3!X`@!
-MPHL"HP````#H_/___XF&C````(/C#X/[`W4)QD8F"NDB!@``BX:(````!4`-
-M`P`YAHP```!Y%P^V1BX\"G</QD8F%8/``8A&+NGX!0``#[9&*X-\ACP`#X2G
-M`0``QT0D%`````"`?PH`=#[&1"0:`(U?.(D<).C\____B40D%`^V1BN+5"04
-M.52&/'0<BT,$B5,$B1J)0@2)$(!$)!H!#[9,)!HX3PIWRH!O"@&+5"04BT(@
-MA<`/A"P!``#'0&``````]D(H!'4[B2PDZ/S___^+3"04BT$TQH"L`````8M!
-M(,=$)`@!````B40D!(DL).C\____BU0D%(M"-,:`K`````"+3"04BT$@BY5(
-M!0``B40D"(E4)`3'!"0!````Z/S___^+5"04BT(@BTAPA<ET,`^W0AS'A(6\
-M`@```````(M"(,=`<`````"+0B"+4'C'1"0(_____XE$)`2)%"3_T8M,)!2+
-M02"%P'0KBU!TA=)T)`^W01S'A(6\`@```````(M!(,=`=`````"+02"+0'B)
-M!"3_THM4)!2+0B`/ME`"#[9``8E4)`B)1"0$QP0DT`(``.C\____BTPD%(M!
-M((N52`4``(E$)`B)5"0$QP0D!@```.C\____BT0D%,=`(``````/MD8KQT2&
-M/`````"+5"04B50D!(DL).C\____QD8F">DY!```BY5$"@``@<),"```#[9&
-M-,'@"`'"BPJ)#0`````/MLF+E40*``"!PD0(```/MD8TP>`(`<*+`J,`````
-MP>`("<B)1CB`?B8*=`>I```!`'0)QD8F"^G?`P``QD8F#`^V1BN#?(8\`'1.
-M@'\*``^$)@0``,9$)!L`C5\XB1PDZ/S___^)P@^V1BLY5(8\=0J`;PH!ZRR-
-M="8`BT,$B5,$B1J)0@2)$(!$)!L!#[9,)!LX3PIV#.O$B2PDZ/S___^)PH72
-M#X30`P``#[9&*XE4ACP/MD8OB(*V````Z5D#``")+"3H_/___\<$)`$```#H
-M_/___X/K`8/[_W0)BT<8]D`J"'3;QD8F">DK`P``BY5$"@``@<),"```#[9&
-M-,'@"`'"BPJ)#0`````/MLF+E40*``"!PD0(```/MD8TP>`(`<*+`J,`````
-M#[;`P>`("<@E_P\``#T3`0``#Y3"/2,!```/E,&$TG43A,EU#STS`0``=4*-
-M=@#I\@(``,9&)AB$TI"-="8`=`G&1B\(Z:4"``"$R8UV`'0)QD8O">F5`@``
-M/3,!```/A8H"``#&1B\*Z8$"```/MDXJ#[;1#[9&'X/H`3G"?1.-00&(1BJ`
-M1BL!QD8F!^E<`@``QD8K`,9&)A[I3P(``,9&)@/I1@(``,9&)B*)]ND[`@``
-MQD8F(^DR`@``QD8F`^DI`@``BY5$"@``@<),"```#[9&-,'@"`'"BPJ)#0``
-M``"+E40*``"!PD0(```/MD8TP>`(`<*+$HD5`````(G0P>`(#[;)"<AF/0,1
-M#X6:````B=#!Z`AF/453=`IF/4`##X6%````9L=&(`,19HE&(F8]15-U'("^
-MI0````)T$\:&I0````+'AJ@````?````ZR)F@7XB0`-U&H"^I0````-T$<:&
-MI0````/'AJ@````/^`,`QH:L`````8DT).C\____QH:L`````(L&BX!(!0``
-MQT0D!`````")!"3H_/___\9&)@/I00$``,9&)B'&AJ4`````Z3$!``"+E40*
-M``"!PDP(```/MD8TP>`(`<*+`J,`````BY5$"@``@<)$"```#[9&-,'@"`'"
-MBP*C`````,9&)A_I\````,9&)B#IYP```(N51`H``('"3`@```^V1C3!X`@!
-MPHL"HP````"+E40*``"!PD0(```/MD8TP>`(`<*+`J,`````#[9.*P^V1A^-
-M40&(5BL/MLD/ML"#Z`$YP0^<P(/H`8/@YX/`'XA&)NF"````BY5$"@``@<),
-M"```#[9&-,'@"`'"BPJ)#0`````/MLF+E40*``"!PD0(```/MD8TP>`(`<*+
-M`J,`````P>`("<&)CI0```#&1B8:ZS7&1B8;ZR^+A40*```%3`@```^V5C3!
-MX@@!T(L`HP````"#X/>(1BS&1B8<ZPC&1B8=C70F`(M$)#2#>%``=`^#P%")
-M1"0$B2PDZ/S___^+5"0TB50D!(DL).C\____B70D!(DL).C\____ZRG&1B88
-MZ1O]__^)+"3H_/___\<$)`$```#H_/___[L^0@\`Z67\__^)]HM<)!R+="0@
-MBWPD)(ML)"B#Q"S#C;8`````C;\`````@^Q<B5PD3(ET)%")?"14B6PD6(ML
-M)&"+?"1D#[=7$&:!^H4`#X>^````#[?"#[:,!;P$``"`^?\/A*H```!F@_I_
-M=QP/ML&+E7P%``!IP"@!``"+1!`L#[9`!.LZC78`9H'Z@0!W&0^VP8N5M`4`
-M`&G`%`T``(M$$`@/MD`$ZQ</ML&+E9@%``!IP+````"+1!!4#[9`!#S_=$T/
-MML`/MI0%0@4``(#Z_W05@/G_=!`/ME\4@/L&=5>-M"8`````@/K_=".`^?]T
-M'@^VP6G`*`$``(G&`[5\!0``QD8G`L9&)O_IN`<``(-_4`!T#XU'4(E$)`2)
-M+"3H_/___XE\)`2)+"3H_/___^G"!P``B?8/ML%IP"@!``")Q@.U?`4```^W
-MAI0```!FB40D-F8]JPUW!8#[`G4Z@W]0`'0/C4=0B40D!(DL).C\____B7PD
-M!(DL).C\____QD8F_\9&)P*)="0$B2PDZ/S____I7@<``,9$)#T`@/L@=26+
-M3S@/M@&#X'\\<78-#[9)`8/A#XA,)#WK"P^V20*#X0^(3"0]#[;2B50D,&O"
-M7(V$!4P!``")1"0X#[9')#P:#X0'!@``/!IW'SP2=%$\%8UT)@`/A)@&``"$
-MP`^$I04``(GVZ;L&```\)0^$X`(``#PED'<3/!L/A:8&``"-M@````#I=04`
-M`#R>#X3-`P``/*"0#X6*!@``Z6(&``"$VXUV``^%@P(``(M/-(!_)0"-=@!T
-M887)=$N`>0&`=46`>0(`=3\/MD$#/#QW-P^VV(U64+@`````Q@00((/``8/X
-M%'7T@_L3=@6[%````(U64(U!!(E<)`B)1"0$B10DZ/S___]FQX:4``````#&
-M1B89Z0T&``#&1B88]D$&0'41#[8!@^`?@_@-#X5C`0``ZPL/M@&#X!^#^`UU
-M"<9&)0V-=@#K!,9&)2(/MD8EB40D!,<$)!`#``#H_/___X-_4`!T#XU'4(E$
-M)`2)+"3H_/___XE\)`2)+"3H_/___VM$)#!<@+P%5@$````/A,(%``"^````
-M`(G#C;P%A`$``(D\).C\____C10KBXJ(`0``B8*(`0``B3B)2`2)`0^V0"4\
-M(G0$/`UU#H/&`8GR.)0=5@$``'?(:T0D,%P/MH0%5@$``(GQ.,@/A64%``"$
-MP`^$704``+X`````9L=$)#X``,=$)$``````:UPD,%R-O!V$`0``B3PDZ/S_
-M__^)P8T$*XN0B`$``(F(B`$``(DYB5$$B0H/MD$E/")T!#P-=10/MT$<9CM$
-M)#YR"6:)1"0^B4PD0(/&`8GP.(0=5@$``'>R@WPD0``/A.0$``"+5"1`@'HF
-M_P^$U@0``,9")O^)5"0$B2PDZ/S____IP00``(/X`741QD8E`<9&)O^-="8`
-MZ7L$``#V004!=`9F@4XX``2+7S2%VW1;C59DN`````#&!!``@\`!@_@H=?2-
-MEHP```"P`,8$$`"#P`&#^`AU](U.9(U3"(M#"(E&9(M"!(E!!(M""(E!"(M"
-M#(E!#(M"$(E!$(M"%(E!%(M#((F&C````(.^'`$````/A0`$``#&1B8<Z?<#
-M```/MT0D-H/``6:)AI0```#'!"00)P``Z/S____&1B8%Z=,#``"+3S2$VP^%
-MD`````^V40;!X@@/MD$%P>`0"<(/MD$'"<(/MD$$P>`8"<*)EK`````/MA'!
-MXA@/MD$#"<(/MD$"P>`("<(/MD$!P>`0"=")1D3'1D@`````@[ZP`````'4=
-M9H.&E`````''!"00)P``Z/S____&1B8;Z54#``"#^/]U#V:!3C@`!,9&)AOI
-M00,``,9&)@WI.`,``(#[('4S@'PD/09T!X!\)#T"=24/MT0D-H/``6:)AI0`
-M``#'!"00)P``Z/S____&1B8%Z0$#``"0@W]0`'0/C4=0B40D!(DL).C\____
-MB7PD!(DL).C\____B70D"(M,)#B)3"0$B2PDZ/S____I]@(``(M'-(E$)$2$
-MVP^%'P$```^V4`K!X@@/MD`)P>`0"<*+3"1$#[9!"PG"#[9!",'@&`G"B9:P
-M````#[9!`XG"N`````")1"0HB50D+`^V00*)PK@`````P>((BTPD*`G!BUPD
-M+`G3BT0D1`^V`(E$)"#'1"0D`````(M$)"")PK@`````P>(8"<$)TXM$)$0/
-MMD`!B40D&,=$)!P`````BT0D&(G"N`````#!XA`)P0G3BT0D1`^V4`;!X@@/
-MMD`%B40D&,'@$`G"BT0D1`^V0`<)PHM$)$0/MD`$B40D&,'@&`G""<J)5D2)
-M7DB+5"1$]D(,`70%9H-..@2#OK``````=1UF@X:4`````<<$)!`G``#H_/__
-M_\9&)AOII@$``&:#3C@!QD8F#>F8`0``@/L@=3.`?"0]!G0'@'PD/0)U)0^W
-M1"0V@\`!9HF&E````,<$)!`G``#H_/___\9&)AOI80$``)"#?U``=`^-1U")
-M1"0$B2PDZ/S___^)?"0$B2PDZ/S___^)="0(BTPD.(E,)`2)+"3H_/___^E6
-M`0``QD8F%.D=`0``@/L@=3B`?"0]!HUV`'0'@'PD/0)U)P^W1"0V@\`!9HF&
-ME````,<$)!`G``#H_/___\9&)A3IXP```(UV`,9&)AOIUP```(3;D(UT)@!U
-M7(M'-&:#3C@"9H-..@%F@4XXA`"`>`,`=06`.!9W'6:#AI0````!QP0D$"<`
-M`.C\____QD8F#>F3````]D`&!'0'9H-..@+K!6:#9CK]BT=0B488QT=0````
-M`.LZ@/L@=3"`?"0]!G0(@'PD/0*0=28/MT0D-H/``6:)AI0```#'!"00)P``
-MZ/S____&1B8%ZSUF@V8X^<9&)@[K,H3;=05F@TXZ`\9&)@_K(X3;D'4,B7PD
-M!(DL).C\____@[X<`0```1G`@^`3@\`%B$8F@W]0`'0/C4=0B40D!(DL).C\
-M____B7PD!(DL).C\____B70D!(DL).C\____C78`BUPD3(MT)%"+?"14BVPD
-M6(/$7,.0D)"0D)"0D)"0D)"#X0?!X0B`S2"+0`0MY#P```^VTL'B"`'0B0@/
-MMP!FHP`````/ML##D(VT)@````"#X0?!X0B*3"0$@,T0BT`$+>0\```/MM+!
-MX@@!T(D(PU575E.#[`B)Q\9$)`(`QD0D`P"]_____\=$)`0`````#[9$)`2(
-M1"0!@T0D!`&X`0```(G&#[9,)`33YHGQNP````"XP.'D`+H`````]_$Y^'<=
-MB?HIPHG0.>IS$P^V5"0!B%0D`HA<)`.)Q8UT)@"#PP$!\8/[$'7)@WPD!`AU
-MGP^V1"0#P>`#"D0D`@^VP(/$"%M>7UW#D(VT)@````"#[`R)7"0$B70D"(M<
-M)!`/MG0D%,<$)`````"Y!P```(GRB=CH%____P^V@RD+``")!"2Y`P```(GR
-MB=CH__[__XM<)`2+="0(@\0,PXUV`%.)TP^VT;D#````Z+#^__\XV`^4P`^V
-MP%O#C;8`````4XM<)`B%VW0ON@````")]@^VA!H^!0``#[;(//]T$0^WP6G`
-ML`````.#F`4``.L-@\(!@_H$==BX`````%O#D%93@^P$BT0D$(N83`4``(7;
-M=0*)P[X`````QP0D`````+D'````B?*)V.AA_O__QP0D1````+D"````B?*)
-MV.A,_O__QP0DT````+D`````B?*)V.@W_O__QP0D`````+D$````B?*)V.@B
-M_O__@\8!@_X"=:2XH(8!`.@P_O__B(,I"P``#[;`B00DN0,```"Z`````(G8
-MZ//]__^#Q`1;7L.-M@````"-O"<`````@^P\B5PD+(ET)#")?"0TB6PD.(M4
-M)$`/MH*E````/`(/A>H```"+BJ@```")3"049L=$)!H``+T````JQT0D'```
-M``"[`````+X`````OP0```"Z`0```(G0B=G3X(5$)!1U'(U+!M/B9@E4)!H)
-M5"0<N!4```")\=/@"<7K"9")^(GQT^`)Q8/#`8/&!8/'`X/[!76]BT0D'(E$
-M)`S'1"0(J`,``,=$)`0!````BU0D0(D4).C\____B6PD#,=$)`C$`P``QT0D
-M!`$```"+3"1`B0PDZ/S___\/MT0D&HM4)$`+@J@```")1"0,QT0D"*`#``#'
-M1"0$`0```(D4).C\____Z?T```"-M@`````\`P^%[P```(M,)$"+B:@```")
-M3"0H9L=$)"(``+T````JQT0D)`````"[`````+X`````OP0```"-M"8`````
-MN@$```")T(G9T^"%1"0H=1^-2P;3XF8)5"0B"50D)+@5````B?'3X`G%ZPR-
-M="8`B?B)\=/@"<6#PP&#Q@6#QP.#^P1UNHM$)"2)1"0,QT0D"*@#``#'1"0$
-M`0```(M4)$")%"3H_/___XEL)`S'1"0(Q`,``,=$)`0!````BTPD0(D,).C\
-M____#[=$)"*+5"1`"X*H````]]")1"0,QT0D"*`#``#'1"0$`0```(D4).C\
-M____BUPD+(MT)#"+?"0TBVPD.(/$/,.0C70F`(/L#(M4)!`/MDPD%(!\)!@`
-M=`^X_O___]/`(8*H````ZPVX`0```-/@"8*H````B10DZ/S___^#Q`S#D(UT
-M)@"#[!S'1"00`0````^W1"0DP>`(@\`/B40D#,=$)`B:````QT0D!`$```"+
-M1"0@B00DZ/S___^#Q!S#C;8`````@^P,BU0D$`^V3"04@'PD&`!T$+C^____
-MT\!F(8*0````ZPZX`0```-/@9@F"D`````^W@I````")1"0$B10DZ/S___^#
-MQ`S#D(VT)@````"#["R)7"0<B70D((E\)"2);"0HBW0D,(M$)#0/ME0D.(A4
-M)!L/MIB8````#[9H`HM0:(72=!H/MD0D&XE$)`B)Z0^VP8E$)`2)%"3H_/__
-M_XDT).C\____@/L'=TH/ML/_)(40%0``O_L```"-="8`ZS6_,P```.LNOSL`
-M``")]NLEOW,```#K'K][````B?;K%;^S````ZPZ_NP```(GVZP6_\P```(E\
-M)`2)-"3H_/___P^V1"0;B40D"(U$G0`/ML")1"0$B30DZ/S___^+7"0<BW0D
-M((M\)"2+;"0H@\0LPXVV`````(V\)P````!75E.#[!")Q[L`````#[;RN0(`
-M``")\HGXZ++Y__^H"'0.N`````#K(XVT)@````#'!"0!````Z/S___^#PP&!
-M^Q`G``!UR;C_````@\006UY?PXVV`````(V\)P````"#[`R)'"2)="0$B7PD
-M"(G&B<\/MMJ)VNB$____A<!U,(GX#[;0B=F)\.B"^O__A<!T'KD!````B=J)
-M\.@P^?__BU0D$(@"N`````#K"(UV`+C_____BQPDBW0D!(M\)`B#Q`S#C;8`
-M````C;\`````@^P<B5PD$(ET)!2)?"08B<8/MOD/MMJ)/"2Y`0```(G:Z`KY
-M___'!"1`````N0(```")VHGPZ/7X__^)VHGPZ.S^__^%P'5.@WPD(`!T-??'
-M`0```'09B=FZ0````(GPZ-OY__^%P'0MZS*0C70F`(G9NA@```")\.C"^?__
-MA<!T%.L9B=FZ*````(GPZ*[Y__^%P'4'N/\```#K!;@`````BUPD$(MT)!2+
-M?"08@\0<PXVT)@````"-O"<`````55=64X/L#(G'BVPD)(G3B<Z$R0^$Z@``
-M``^VVL<$)&0```"Y`@```(G:B?CH/_C__XG:B?CH-O[__X7`=0ZY`P```(G:
-MB?CH]/?__XGP#[;(QP0D`0```(G:B?CHW_[__[[_____A,`/A7<!``"^````
-M`(7M#XYJ`0``O@````"-1?^)1"0(.70D"'4UQP0D0````+D"````B=J)^.C.
-M]___BT0D(`'PB00DN5@```")VHGXZ!?^__^%P'0YZ2,!``#'!"1$````N0(`
-M``")VHGXZ)GW__^+1"0@`?")!"2Y4````(G:B?CHXOW__X7`#X7O````@\8!
-M.>X/A.0```#KA+B@A@$`Z(/W__\/MML/ML")!"2Y`P```(G:B?CH3/?__XG:
-MB?CH0_W__X7`="(/MH<I"P``B00DN0,```")VHGXZ"?W__^^_____^F2````
-MB=FZ8````(GXZ!_X__^%P'0-O@````"%[7Y?B?;K'P^VARD+``")!"2Y`P``
-M`(G:B?CHYO;__[[_____ZU2^`````,<$)$0```"Y`@```(G:B?CHQ?;__XM$
-M)"`!\(D$)+F`````B=J)^.@._?__A<!U!X/&`3GN=<D/MH<I"P``B00DN0,`
-M``")VHGXZ(OV__^)\(/$#%M>7UW#D(/L'(E<)!2)="08BW0D(`^V3"0DBT0D
-M+(E$)`2+1"0HB00DN@````")\.CA_?__B</'!"14````N0(```"Z`````(GP
-MZ#?V__^)V(M<)!2+="08@\0<PXGVC;PG`````(/L'(E<)!2)="08BW0D(`^V
-M3"0DBT0D+(E$)`2+1"0HB00DN@$```")\.B!_?__B</'!"14````N0(```"Z
-M`0```(GPZ-?U__^)V(M<)!2+="08@\0<PXGVC;PG`````%575E.#[`R)QXML
-M)"2)RP^V\L<$)&0```"Y`@```(GRZ)OU__^)\HGXZ)+[__^%P'4.N0,```")
-M\HGXZ%#U__\/MLO'!"0!````B?*)^.@]_/__A,!U+H7M?C&[`````(M$)"`/
-MM@P#QP0D`````(GRB?CH&/S__X3`=0F#PP$YZW0)Z]NX_____^L%N`````"#
+M0&8-ZSP\*'4:#[9#3X/H`8A#3HGH`X;,!0``BP#&0!2!ZQX\"'4,QP0D$"<`
+M`.C\____B>@#ALP%``"+`,9`%"&#Q$Q;7E]=PXUT)@!55U93@>R<````BZPD
+ML`````^WA9(+``!FB40D?HN%K`H``(L`HP````!F)?\/9HF%D@L``&8[1"1^
+M=5:+10"+B%`!``")#0````"+10")RH'B\/__`(F04`$``+@`````A=(/A.`(
+M``")3"0$QP0D]0```.C\____BY0DL````(D4).C\____N`$```#IMP@``&:!
+MO9(+``#_#P^%(`@``.E!"```B[5D"@``9H-$)'X!#[=,)'YF.XV6"P``&<`A
+MP6:)3"1^BY6L"@``@\($#[?!BQ2"B=?![Q#WQP@````/A+````"+10"+F%`!
+M``")'0````"+50")V"7P__\`B8)0`0``A<!T8H!]*P!T7/;'`74MO@````#W
+MPP```0!T/NL>#[?&C4@(N@$```")U]/GA?MU$(U($-/BA=-U!^L>O@`````/
+MM\9KP%R-G`5(`0``A=MU*.L2C;8`````@\8!#[9%*V8Y\'>XBX0DL````(D$
+M).C\____Z54'``"+E"2P````B10DZ/S___^(0POI/@<``(G19H'A_P]FB4PD
+M3@^WV8E<)$1IP[`$``"+3`8@BUP&)(F,)(````")G"2$````BW0D1,'F`HN%
+MS`4```'PBP")1"1XA<`/A<T!``")3"00B5PD%(E4)`R+7"1$B5PD"(E<)`3'
+M!"3\!@``Z/S___]F@WU8``^$PP8``,:$)(L`````C;8`````#[:\)(L```"-
+M!+T`````B40D6`.%S`4``(L0A=(/A$@!``!I][`$```#M60*``"+G1P*```/
+MMD(5B40D#(E\)`B)5"0$QP0D$`$``.C\____BT0D6`.%S`4``(L`B00DZ/S_
+M__^+ABP$``"+EB@$``"+CB0$``"+MB`$``")1"04B50D$(E,)`R)="0(B7PD
+M!,<$)#@'``#H_/___XGXP>`&`<.+4S2)5"1(BU,PBTLLBW,HBWLDBT,@B40D
+M7(M#'(E$)&"+0QB)1"1DBT,4B40D:(M#$(E$)&R+0PR)A"24````BT,(B80D
+MD````(M#!(F$)(P```"+&XM$)$B)1"0XB50D-(E,)#")="0LB7PD*(M4)%R)
+M5"0DBTPD8(E,)""+?"1DB7PD'(M$)&B)1"08BU0D;(E4)!2+C"24````B4PD
+M$(N\))````")?"0,BX0DC````(E$)`B)7"0$QP0D8`<``.C\____@(0DBP``
+M``$/MH0DBP```&8[15@/@S`%``#I=O[__XVV`````/?'(`````^$AP$``(M4
+M)'B`>A2!#X57`0``QD(4(0^W0A[!X`(#A<P%``#'```````/MTH>B<AFP>@%
+M#[?`@^$?N@$```")T]/CB=GWT2&,A=`%``"+?"1X#[=/'HG(9L'H!0^WP(/A
+M']/B]](A5(5<#[=''HE$)`2+1"10B00DZ/S___^#?U0`=!&)^(/`5(E$)`2)
+M+"3H_/___XM,)'@/MU$09H'ZA0`/A\(````/M\(/MH0%N`0``#S_#X2O````
+M9H/Z?W<;#[;`:<`H`0```X5X!0``BT`L@'@$_P^5P.M7BUPD>`^W0Q!F/8$`
+M=R,/M\`/MH0HN`0``&G`%`T```.%L`4``(M`"(!X!/\/E<#K)HM\)'@/MT<0
+M#[:$*+@$``!IP+`````#A90%``"+0%2`>`3_#Y7`A,!T,XM$)'B)1"0$B2PD
+MZ/S___^-E>0```"+A>0```"+3"1XB4@$B0&)402)C>0```#IM`,``(M<)%2+
+M4P2+1"1X@\`(B4,$BWPD>(E?"(E0!(D"Z9(#```/MT0D3F;!Z`4/M\")1"1P
+M#[=<)$Z)V8/A'[@!````T^")1"1TBU0D<(5$E5P/A5\#``")\`.%S`4``(L`
+M#[=0$&:!^H4`#X>?````#[?"#[:$!;@$```\_P^$C````&:#^G]W&`^VP&G`
+M*`$```.%>`4``(M`+`^V0`3K78GP`X7,!0``BP`/MT`09CV!`'<@#[?`#[:$
+M*+@$``!IP!0-```#A;`%``"+0`@/MD`$ZRF)\`.%S`4``(L`#[=`$`^VA"BX
+M!```:<"P`````X64!0``BT!4#[9`!#S_=`T/ML"`O`4^!0``_W4[BUPD=(M,
+M)'"%7(U<#X65`@``BWPD>,9'%`:)/"3H_/___\=$)`@`````B7PD!(DL).C\
+M____Z6P"```/MH0%/@4``&O`7(V$!4@!``"+E"2$````"Y0D@````'0>]\<"
+M````=1;'A"2``````````,>$)(0`````````]D`&`@^$60$``(N4)(````"+
+MC"2$````B50D"(E,)`R)7"0$B00DZ/S___^+7"1TBTPD<(5<C5P/A>X!``"+
+M?"1X@'\4@0^%BP````^W1Q[!X`(#A<P%``#'```````/MT\>B<IFP>H%#[?2
+M@^$?N/[____3P"&$E=`%```/MT<>B40D!(M$)%")!"3H_/___XE\)`2)+"3H
+M_/___X-_5`!T$8GX@\!4B40D!(DL).C\____C97D````BX7D````BTPD>(E(
+M!(D!B5$$B8WD````Z54!``"+A>P````[1"14=$^[`````(/#`8L`.40D5'7U
+MA-MT.[X`````BWPD5(D\).C\____C4CXBU<$B4<$B3B)4`2)`CM,)'AU!;X!
+M````@.L!==2)\(3`#X7Z````BTPD5(M1!(M$)'B#P`B)002+7"1XB4L(B5`$
+MB0*+1"1TBWPD<`F$O9P```#IR0```(N4)(````"+C"2$````B50D"(E,)`R)
+M7"0$B00DZ/S___^+A>P````[1"14=$^[`````(/#`8L`.40D5'7UA-MT.[X`
+M````BTPD5(D,).C\____C4CXBWPD5(M7!(E'!(DXB5`$B0([3"1X=06^`0``
+M`(#K`770B?"$P'5,BU0D>(!Z%(%T0HM,)%2+402+1"1X@\`(B4$$BUPD>(E+
+M"(E0!(D"BT0D=(M\)'`)A+V<````ZQ2-E>P```")5"14C8T\"0``B4PD4`^W
+M7"1^9CF=D@L```^%O_?__XV%[````#F%[````'1'B<:)-"3H_/___X/H"`^W
+M2!Z)RV;!ZP4/M]N#X1^Z_O___]/"(92=G````,=$)`@`````B40D!(DL).C\
+M____.;7L````=;N)+"3H_/___[@!````@<2<````6UY?7<.-M@````"-OP``
+M``!64X/L%(M,)""+D40%``"+0@2+,(DU`````/?&````D'0%BT($B3"+F40%
+M``#WQ@``!`!T*XL#BY!0`0``B14`````A=)T&8L#B9!0`0``BP.+@%`!``"C
+M`````(UT)@#WQ@``"`!T+8'#R`P``(L#BY!0`0``B14`````A=)T%8L#B9!0
+M`0``BP.+@%`!``"C`````(N#1`4``,=$)`0`````B00DZ/S___^+FT0%``")
+M'"3H_/___XV#R`P``(D$).C\____BX-$!0``QT0D!`$```")!"3H_/___[@!
+M````A?9U"[@`````@'LS`'4`@\046U[#B?:-O"<`````55=64X/L+(MT)$"+
+M!HN`4`$``(E$)!2C`````(L6)?#__P")@E`!``"-M"8`````]T0D%`#__P`/
+MA+D'``"`?BL`#X2O!P``QD0D*P"-=@`/MFPD*XU-"+@!````B<+3XH54)!1U
+M#XU-$-/@A40D%`^$;@<``(!\)"L#=AF+!@6``0``C03HBP"C`````,'H$X/@
+M`>L7BP8%@`$``(T$Z(L`HP````#!Z!.#X`&$P'0?B30DZ/S___^)Z,'@!HT$
+MJ(&,!L`+``````@`C70F`(L6@'PD*P-V%XV$ZH`!``"+`*,`````)0```0#K
+M%8GVC83J@`$``(L`HP`````E```!`(7`="N`?"0K`W82C83J@`$``,<````!
+M`.D$!P``C83J@`$``,<````!`.GR!@``@'XU`0^%VP4``(!\)"L#=AV+!@6`
+M`0``C03HBP"C`````(/@`>L;C;0F`````(L&!8`!``"-!.B+`*,`````@^`!
+MA,`/A&0!``")Z,'@!HT<J(V$'L0+``"+5A2)1"0$B10DZ/S___^+A!Z@"P``
+MA<!T'8M0*(72=!;V0C("=1")!"3H_/___X3`#X4>`0``B>C!X`:-!*B+A`:@
+M"P``A<`/A(<```")1"0D@'@*``^$I0```,9$)",`B<>#QSB)/"3H_/___XG#
+MBT<$B5\$B3N)0P2)&/9#*`)U/8M3((72=!Z+AD0%``")5"0(B40D!,<$)`4`
+M``#H_/___X!+*`*)7"0(QT0D!`8```"+3"0DB0PDZ/S___^`1"0C`0^V1"0C
+MBU0D)#A""G8NZY$/MD0D*\=$)`@!````B40D!(DT).C\____QP0DH(8!`.C\
+M____N@`M,0'K!;I`2TP`B>C!X`:-'*B-##.)D<0+``#'@<P+``#09`$`#[9$
+M)"N)PL'B!HV$@I`+``"-1`8(B8'0"P``C80>Q`L``(M6%(E$)`2)%"3H_/__
+M_XUV`(!\)"L#=B^-%.T`````BP8%@`$```'0BP"C`````(L&!8`!```!PHL"
+MHP````#!Z`>#X`'K+8T4[0````"+!@6``0```="+`*,`````BP8%@`$```'"
+MBP*C`````,'H!X/@`83`=%N`?"0K`W8JC0SM`````(L&!80!```!R(L`HP``
+M``"+%H'"A`$```'1#0```0")`>LQC0SM`````(L&!80!```!R(L`HP````"+
+M%H'"A`$```'1#0```0")`>L@@'PD*P-V&8L&!8`!``"-!.B+`*,`````P>@2
+M@^`!ZQ>+!@6``0``C03HBP"C`````,'H$H/@`83`#X3?`0``@'PD*P-V*HT,
+M[0````"+!@6``0```<B+`*,`````#0``!`"+%H'"@`$```'1B0'K*(T,[0``
+M``"+!@6``0```<B+`*,`````#0``!`"+%H'"@`$```'1B0&)Z,'@!HT$J(N$
+M!J`+``"%P'0-B<6#>"@`=7_I9@$``(!\)"L#D'8YC13M`````(L&!8`!```!
+MT(L(B0T`````BP8%@`$``(T$`HD(BP8%@`$```'"BP*C`````.E<`P``C13M
+M`````(L&!8`!```!T(L(B0T`````BP8%@`$``(T$`HD(BP8%@`$```'"BP*C
+M`````.DC`P``BT`H#[=(,@^WT?;&`0^%V0```(G']L("#X3.````B<B#X/UF
+MB4<RC4=PBU84B40D!(D4).C\____QD0D*P"`?Q\`#X1]````QD0D*P`/MD0D
+M*XM<ASR%VW1<BU,@A=)T'HN&1`4``(E4)`B)1"0$QP0D!0```.C\____@$LH
+M`HE<)`C'1"0$!@```(DL).C\____@'M/`'0=C78`B30DZ/S____'!"0!````
+MZ/S___^`>T\`=>:`1"0K`0^V3"0K.$\?=XC'1W!`2TP`QT=X`````(E_?(U'
+M<(M6%(E$)`2)%"3H_/___XUT)@"`?"0K`W8>BP8%@`$```^V5"0KC130BP*C
+M`````,'H"(/@`>L<BP8%@`$```^V5"0KC130BP*C`````,'H"(/@`83`#X0.
+M`0``@'PD*P-V'HL&!8`!```/ME0D*XT4T(L"HP````"#\`&#X`'K'(L&!8`!
+M```/ME0D*XT4T(L"HP````"#\`&#X`&$P`^$Q0````^V1"0KB<+!X@:-A(*0
+M"P``C00&C5`(B50D'(M2"(72#X2?````B50D&(/`-(M6%(E$)`2)%"3H_/__
+M_XM$)!B`>`H`=%2]`````(G'@\<XB3PDZ/S___^)PXM'!(E?!(D[B4,$B1B+
+M4R"%TG0>BX9$!0``B50D"(E$)`3'!"0%````Z/S___^`2R@"@\4!B>J+3"08
+M.%$*=[:+1"0<QT`L@(0>`,=`-`````")0#B+1"0<@\`LBU84B40D!(D4).C\
+M____@'PD*P-V9`^V7"0KP>,#BP8%@`$```'8BQ")%0````"+!@6``0``C00#
+MB1"+!@6``0``C00#BP"C`````(L&!3`"``"-!`/'``````#'!"00)P``Z/S_
+M__^+!@4T`@```<.+`Z,`````ZV(/MEPD*\'C`XL&!8`!```!V(L0B14`````
+MBP8%@`$``(T$`XD0BP8%@`$``(T$`XL`HP````"+!@50`@``C00#QP``````
+MQP0D$"<``.C\____BP8%5`(```'#BP.C`````(!$)"L!#[94)"LX5BL/AUGX
+M__^+!HN`4`$``(E$)!2C`````(L6)?#__P")@E`!``#W1"04`/__`'0=Z0SX
+M__^)Z,'@!HT$J(&,!L`+``````$`Z?;X__^X`````(/$+%M>7UW#C;0F````
+M`%575E.#[%R+;"1P#[9$)'2(1"0S#[;0B50D-(G0P>`&C020`>B+B*`+``")
+M3"0\#[:XG@L``(M%`(!\)#,#=@S'@'`!``#$`0``ZPK'@'`!``"H`0``B40D
+M6`5T`0``B40D.(M<)%B+@W0!``"C`````(M,)#2#X0.[!P```-/CB=X)QHM$
+M)%B)L'0!``#'!"3H`P``Z/S____WTR'SBU0D6(F:=`$``(!\)#,#=E"+3"0T
+MBUPD6(V4B]`!``"+`J,`````@\@(B0*)R\'C`XM4)%B-A!H``@``QP`X````
+MQP0D$"<``.C\____BTPD6(V$&00"``#'``````#K4(M<)#2+1"18C928T`$`
+M`(L"HP````"#R`B)`HM<)#3!XP.+5"18C80:``(``,<`.````,<$)!`G``#H
+M_/___XM,)%B-A!D$`@``QP``````@WPD/``/A&8(``"`?2L`=#*[``````^V
+MRXM4)#P/MD()T_BH`704QT0D"`$```")3"0$B2PDZ/S___^#PP$X72MWTXM,
+M)#SV008!=&V)3"0$B2PDZ/S___^+7"0TB5PD!(DL).C\____B=C!X`:-!)B-
+M%"B+@KP+``"I```0`'0+)?__[_^)@KP+``"+1"0\B40D!(DL).C\____BT0D
+M-,'@!HM4)#2-!)#'A`6@"P```````.FW!P``BTPD/(!Y-`!T&HN%``H``(E,
+M)`2)!"3H_/___XM<)#R`:S0!N/[___\/MDPD--/`B?L@PXA<)$,/A)("``"+
+M1"0TB40D!(DL).C\____BT0D-,'@!HM4)#2-!)"-%"B+@KP+``"I```0`'0+
+M)?__[_^)@KP+```/MDPD0XM<)#R(2PF`?2L`#X2N`0``QT0D3``````/ML&)
+M1"0@BU0D6('"``(``(E4)!P/MDPD3(A,)%,/MOF+1"0@B?G3^*@!#X0^`0``
+MC1R]`````(E<)"R)^,'@!@'8#[94)$.(E`6>"P``@'PD4P,/AHT```"-'/T`
+M````BT0D'`'8QP`X````QP0D$"<``.C\____BTPD6(V$&00"``"+7"0@B1C'
+M@7`!``#$`0``BU0D.(L"HP````")^8/A`[L'````T^.)W@G&B3+'!"3H`P``
+MZ/S____WTR'SBTPD.(D9BUPD6(M$)"R-E`/0`0``BP*C`````(/("(D"Z8@`
+M``"-'/T`````BT0D'`'8QP`X````QP0D$"<``.C\____BU0D6(V$&@0"``"+
+M3"0@B0C'@G`!``"H`0``BUPD.(L#HP````")^8/A`[L'````T^.)W@G&BT0D
+M.(DPQP0DZ`,``.C\____]],AWHM4)#B),HM,)%B-E+G0`0``BP*C`````(/(
+M"(D"@T0D3`$/MD0D4X/``3A%*W8EZ8_^__^)'"3H_/___XUPX(M3!(E#!(D8
+MB5`$B0*#?@P`=!?K#+X`````BUPD/(/#+(M$)#PY6"QURX7V=#C&1C(`@'TK
+M`'0NN0````"Z`````(M<)#P/MD,)T_BH`70.#[;"B$P&0(!&,@&#P@&#P0$X
+M32MWW,=$)`@`````QT0D!($```"+1"0\B00DZ/S___^+1"0TP>`&BU0D-(T$
+MD,>$!:`+````````@'TK``^%S0,``.GG!```QT0D"`````#'1"0$!@```(M,
+M)#R)#"3H_/___XM<)#2)7"0$B2PDZ/S___^)V,'@!HT$F(T4*(N"O`L``*D`
+M`!``=`LE___O_XF"O`L``(M$)#R#P"R+5"0\.4(L#X0>`@``B40D%(M,)!2)
+M#"3H_/___XU8X(E<)$2-4`@Y4`@/A-(!``"#PRB)7"08BT0D&(D$).C\____
+MC5CX@'LE#74:C9#\````BT,LBP"+0!2)5"0$B00DZ/S___^+$XM#!(E"!(D0
+M@'M/`'0:B2PDZ/S____'!"0!````Z/S___^`>T\`=>:+0R"%P`^$.@$``,=`
+M8`````"`>T\`#X2D````9H-]6``/A)D```"_`````)"-="8`C02]``````.%
+MS`4``(LPA?9T;0^W1A!F.T,<=6-F/84`=UT/M\"`O"BX!```_W10BU4`#[=&
+M'F;!Z`4/M\"-!(4``P``B8)P`0``BU4`#[=.'H/A'[@!````T^")@G0!``#&
+M1A0AQT0D"`````")="0$B2PDZ/S___^-M@````"#QP$/MT58.?@/CW'____V
+M0R@$=1^)+"3H_/___XM#(,=$)`@!````B40D!(DL).C\____BT,@#[90`@^V
+M0`&)5"0(B40D!,<$),$```#H_/___XM#((N51`4``(E$)`B)5"0$QP0D`0``
+M`.C\____BT,@BY5$!0``B40D"(E4)`3'!"0&````Z/S____'0R``````BU0D
+M/(!J"@&+3"1$@&DP`8E<)`2)+"3H_/___XM$)!B+7"1$.4,H#X4U_O__BU0D
+M/(!J'`&+3"1$B4PD!(DL).C\____BT0D%(M<)#PY0RP/A>;]__^+1"0\@\`X
+MBU0D/#E".`^$!0$``+X`````B<>)/"3H_/___XG#@'A/`'0VC48!@?Y_EI@`
+M=@2)QNLGB<:)+"3H_/___\<$)`$```#H_/___X![3P!T"X/&`8'^@9:8`'7;
+MBT,@A<`/A(P```#'0&``````]D,H!'4?B2PDZ/S___^+0R#'1"0(`0```(E$
+M)`2)+"3H_/___XM#(`^V4`(/MD`!B50D"(E$)`3'!"3!````Z/S___^+0R"+
+ME40%``")1"0(B50D!,<$)`$```#H_/___XM#((N51`4``(E$)`B)5"0$QP0D
+M!@```.C\____QT,@`````(M,)#R`:0H!B5PD!(DL).C\____BUPD/#E[.`^%
+M`O___XM$)#R)1"0$B2PDZ/S___^+1"0TP>`&BU0D-(T$D,>$!:`+````````
+MZ2G\___'1"1(``````^V3"1#B4PD*(M<)%B!P]`!``")7"0D#[9\)$B)^`^V
+MP(E$)%2+1"0H#[9,)%33^*@!=0R)^SA<)#,/A<8```")^#P#=F.+5"18QX)P
+M`0``Q`$``(M,)#B+`:,`````BTPD5(/A`XT,2;L'````T^.)W@G&BT0D.(DP
+MQP0DZ`,``.C\____]],A\XM4)#B)&HM,)%2+7"0DC12+BP*C`````(/("(D"
+MZUV+1"18QX!P`0``J`$``(M4)#B+`J,`````BTPD5(/A`XT,2;L'````T^.)
+MW@G&B3+'!"3H`P``Z/S____WTR'>BTPD.(DQBUPD5(M$)"2-%)B+`J,`````
+M@\@(B0*#1"1(`8U'`3A%*P^'`/___X/$7%M>7UW#D(VT)@````!55U93@^P<
+MBWPD,(MT)#0/MF\KB>B$P'0L#[96";L`````]L(!=!/K'(VT)@````")T(G9
+MT_BH`740@\,!B>@XPW7MZP6[`````/9&"`)U"(U&.#E&.'5JB30DZ/S___^$
+MP'1/B3PDZ/S___^)P87`=%"+5CR)1CR-1CB)`8E1!(D*@$8*`8EQ+,9!)`7&
+M024`QD%-#\=$)`P!````QT0D"`$```")3"0$B30DZ/S____K#P^VPXE$)`2)
+M/"3H_/___X/$'%M>7UW#C;8`````55=64X/L#(ML)"`/MGPD)(GX#[;`B40D
+M"(G&P>8"NP````#'!"00)P``Z/S___^)^H#Z`W8:BT4`!=`!```!\(L`HP``
+M``#!Z!2#X`'K&9"+10`%T`$``(T$!HL`HP````#!Z!2#X`&$P'4*@\,!9H'[
+M+`%UK8M$)`B)1"0$B2PDZ/S___^)+"3H_/___XM$)`C!X`:+5"0(C020`>CV
+M@)T+```!=!*+@*`+``")1"0$B2PDZ/S___^#Q`Q;7E]=P^L-D)"0D)"0D)"0
+MD)"0D%575E.#[!P/MD0D-(A$)!J+?"0P#[;PB?#!X`:-!+"+K`>@"P``A>T/
+MA*H!``"X_O___XGQT\"$10D/A9@!``"-12PY12QU#8!]"@!U*8GVZ0,#```/
+MMD0D&HG"P>(&C82"D`L``(U$!PB)!"3H_/___^GA`@``QD0D&P"-=3B0B30D
+MZ/S___^)PXM&!(E>!(DSB4,$B1B`>R4`#X4?`0``#[=#'(.\A[@"````=1&#
+M>R``#X3H````C;0F``````^W0QR+A(>X`@``@WAP``^$K0```,:#M``````/
+MME,DB="#X`:#^`9U-O;"`70QQD,F!<9#)P0/MD--BU,PBTLLB5PD#(E$)`B)
+M5"0$B0PDZ/S____II@```(VV``````^V4R2)T(/@!H/X!'4B]L(!=!W&0R8#
+MQD,G!(E<)`2)/"3H_/___^MWC;0F``````^V4R2)T(/@!H/X!G5B]L(!=5W&
+M0R<&QD,F!6;'@Y0``````(E<)`2)/"3H_/___^L^BT,@BY=$!0``B40D"(E4
+M)`3'!"0$````Z/S____K'P^W0QR+ET0%``")1"0(B50D!,<$)`(```#H_/__
+M_Y"`1"0;`0^V1"0;.$4*#X:%`0``Z:C^__^-++4`````NP````#'!"00)P``
+MZ/S___^`?"0:`W89BP<%T`$```'HBP"C`````,'H%(/@`>L7D(L'!=`!```!
+MZ(L`HP````#!Z!2#X`&$P'4*@\,!9H'[+`%UL(ET)`2)/"3H_/___XD\).C\
+M____B?#!X`:-!+"+M`>@"P``A?8/A/D```"`?RL`=#2[`````(VV``````^V
+MRP^V1@G3^*@!=!3'1"0(`````(E,)`2)/"3H_/___X/#`3A?*W?7#[9$)!J)
+MPL'B!HV$@I`+``"-1`<(B488C48L.48L=2J-1C@Y1CAU(NMQB1PDZ/S___^-
+M:."+4P2)0P2)&(E0!(D"@WT,`'04ZPV]`````(U>+)"-="8`.5XL=<Z%[71?
+MQD4R`(!_*P!T5;H`````NP````"-=@`/MD8)B='3^*@!=`X/ML.(5`5`@$4R
+M`8/#`8/"`3A7*W8FZ]SV1@8!=`Z)="0$B3PDZ/S____K$,=$)`0`````B30D
+MZ/S___^#Q!Q;7E]=PU575E.#[`R+?"0@BQ^+;R@/MG,KB?"$P'17C8.8"P``
+MN0`````Y^'4>ZT:0C70F``^VP8G"P>(&C82"D`L``(U$`P@Y^'0)@\$!B?`X
+MP77@@/D#=B&+`P70`0``#[;1C120BP*C`````,'H%(/@`>L?N0````"+`P70
+M`0``#[;1C120BP*C`````,'H%(/@`83`=!4/ML&);"0(B40D!(D<).C\____
+MZP\/ML&)1"0$B1PDZ/S___^#Q`Q;7E]=PU575E.#[!R+7"0TBT0D,(E$)!2+
+M>%2+-_9'"!!T!,9`-0:+5"04#[9"-3P!='4\`7(9/`0/A)8````\!HUT)@`/
+MA3H#``#IIP$``(M,)!3&034!B4PD!(DT).C\____QD,4@8!/"`B#>U0`=`^-
+M0U2)1"0$B30DZ/S___^-EN0```"+AN0```")6`2)`XE3!(F>Y````(DT).C\
+M____Z=T"``"`9PCWBT0D%(!`-@'&0#4`QD,4`HE<)`2)-"3H_/___XDT).C\
+M____Z;`"```/MD<(@^#W@\@0B$<(BTPD%(N1F````(U"`8F!F````(/Z`@^'
+M^0```(-[5`!T#XU#5(E$)`2)-"3H_/___XV6Y````(N&Y````(E8!(D#B5,$
+MB9[D````BT0D%(!X)@!U"X!_"@!U(NFD````QT0D"`````#'1"0$`@```(D\
+M).C\____Z28"``#&1"0;`(UO.(DL).C\____B<.+102)702)*XE#!(D8BU,@
+MA=)T'HN&1`4``(E4)`B)1"0$QP0D!0```.C\____@$LH`HE<)`C'1"0$!@``
+M`(D\).C\____@'M/`'0:B30DZ/S____'!"0!````Z/S___^`>T\`=>:`1"0;
+M`0^V5"0;.%<*=X&+3"04B0PDZ/S____IC@$``(!G"/>+1"04QX"8````````
+M`(-[5`!T#XU#5(E$)`2)-"3H_/___XV6Y````(N&Y````(E8!(D#B5,$B9[D
+M````QT0D"`````#'1"0$!@```(D\).C\____C4<X.4<X#X26````B<6-M"8`
+M````B2PDZ/S___^)PXM`((7`=&?'0&``````B30DZ/S___^+0R#'1"0(`0``
+M`(E$)`2)-"3H_/___XM#((N61`4``(E$)`B)5"0$QP0D`0```.C\____BT,@
+MBY9$!0``B40D"(E4)`3'!"0&````Z/S____'0R``````B5PD!(DT).C\____
+M.6\X#X5S____BU0D%(E4)`2)-"3H_/___\='*`````"+!HN06`$``(D5````
+M`(72=`B+!HF06`$``/9'!@%T7(!^*P!T(;D`````]D<)`70,ZQ0/MD<)T_BH
+M`74/@\$!.$XK=^[K!;D`````#[;9B5PD!(DT).C\____B7PD!(DT).C\____
+MB=C!X`:-')C'A!Z@"P```````(GV@\0<6UY?7<.0C;0F`````(/L+(E<)!R)
+M="0@B7PD)(EL)"B+?"0TBW0D,(M&+(E$)!B+*`^W3QZ)R&;!Z`4/M]B#X1^X
+M`0```-/@A42=7`^%[P,``(M5`(T$G0`#``")@G`!``"+10"+D'0!``")%0``
+M``#&1Q0ABT<D)?___P`]X0$/`'4AB3PDZ/S____'1"0(`````(E\)`2)+"3H
+M_/___^F<`P``#[=/'H/A'[@!````T^"%PG06B3PDZ/S___^)+"3H_/___XVV
+M``````^VAK0````\!`^'90,```^VP/\DA8@(``#&AK0````!QT0D"`$```")
+M?"0$BU0D&(D4).C\____Z3<#``#&AK0````"QT0D"`@```")?"0$BT0D&(D$
+M).C\____Z1,#``#&AK0````#B70D",=$)`0A````BU0D&(D4).C\____BU8P
+MA=)T+0^V1DW'1"00`````,=$)`P!````B40D"(E4)`2+1"08B00DZ/S____I
+MP`(``(M4)!@/MD()QT0D"`````")1"0$B2PDZ/S____IGP(``,:&M`````2#
+M?C``=$B)="0(QT0D!"$```"+1"08B00DZ/S___\/MD9-BU8PQT0D$`````#'
+M1"0,`@```(E$)`B)5"0$BU0D&(D4).C\____Z4H"``#'1"0(`````,=$)`0A
+M````BT0D&(D$).C\____BU0D&`^V0@G'1"0(`0```(E$)`2)+"3H_/___^D-
+M`@``@'XF_W0=B70D",=$)`0&````BT0D&(D$).C\____Z>H!``")="0(QT0D
+M!`8```"+5"08B10DZ/S___^+3B"%R702BU$$C4(!B4$$@_H%#X:Y`0``QD8G
+M`<9&)@"`?D\`="&-M"8`````B2PDZ/S____'!"0!````Z/S___^`?D\`=>:#
+M?C``B?9T%(M6"(M&#(E"!(D0BT8P@&@P`>L3BU8TA=)T#`^V1DW'1((\````
+M`(L6BT8$B4($B1"+1"08@&@*`8N6Y````(72=!L/MH;9````QT0D"`$```")
+M1"0$B10DZ/S___^+5C"%TG08#[9&3<=$)`@!````B40D!(D4).C\____BT8@
+MA<`/A(8```#'0&``````B2PDZ/S___^+1B#'1"0(`0```(E$)`2)+"3H_/__
+M_XM&(`^V4`(/MD`!B50D"(E$)`3'!"3!````Z/S___^+1B"+E40%``")1"0(
+MB50D!,<$)`$```#H_/___XM&((N51`4``(E$)`B)5"0$QP0D!@```.C\____
+MQT8@`````(ET)`2)+"3H_/___XM4)!B`>@7_=%Z^`````(!Z"@!T.+X`````
+MBUPD&(/#.(UV`(D<).C\____BU,$B4,$B1B)4`2)`H!X)O]U#H/&`8GPBU0D
+M&#A""G?7B?"+5"08.$(*=Q#&0@7_B50D!(DL).C\____BUPD'(MT)""+?"0D
+MBVPD*(/$+,.0C;0F`````%575E.![(P```"+O"2@````BT=4B40D>(LHBX6L
+M"@``BP")1"1\B7PD!(DL).C\____@'\V`78$QD<U!(U?%#E?%`^$N`$``(D<
+M).C\____B40D=(M'%(M4)'2)4`2)`HE:!(E7%(72#X2<`P``#[=R'HM,)'B+
+M01@/MD`$#[95*0^V32(/METAB70D%(E$)!")5"0,B4PD"(E<)`3'!"2X!P``
+MZ/S___^+1"1T#[=`'HE$)%AI\+`$```#M60*``"+G1P*``"+5"1TB10DZ/S_
+M__^+CBP$``")3"1(BY8H!```BXXD!```B[8@!```BT0D=`^W0!Z)1"0$BT0D
+M2(E$)!2)5"00B4PD#(ET)`C'!"3H!P``Z/S___^+5"18P>(&`=.+2S2)3"1(
+MBU,PBTLLBW,HBT,DB40D7(M#((E$)&"+0QR)1"1DBT,8B40D:(M#%(E$)&R+
+M0Q")1"1PBT,,B80DB````(M#"(F$)(0```"+0P2)A"2`````BQN+1"1(B40D
+M.(E4)#2)3"0PB70D+(M4)%R)5"0HBTPD8(E,)"2+1"1DB40D((M4)&B)5"0<
+MBTPD;(E,)!B+1"1PB40D%(N4)(@```")5"00BXPDA````(E,)`R+A"2`````
+MB40D"(E<)`3'!"1@!P``Z/S___]F@WU8`'5&Z>4!``"0BU0D>(M"&`^V0`0/
+MME4I#[9-(@^V72''1"04____`(E$)!")5"0,B4PD"(E<)`3'!"2X!P``Z/S_
+M___I!0(``+X`````C8T\"0``B4PD4(V%Y````(E$)$R-M"8`````#[?&P>`"
+M`X7,!0``BQB%VP^$80$```^W0Q!F.4<D#X53`0``#[>5D@L``#E4)'QT18/"
+M`0^WA98+```YPAG`(<*+A:P*``"#P`2+!)"I```(`'4<9B7_#V8Y\'43.5PD
+M='43B2PDZ/S____I=0$``#M4)'QUNP^W0Q!F/84`B?8/A_$````/M\"`O`6X
+M!```_P^$X````(M4)'B`>C0`#X72````]D(&`0^$R````(M5``^W0QYFP>@%
+M#[?`C02%``,``(F"<`$```^W2QZ#X1^Z`0```(G0T^")P8M%`(F(=`$```^W
+M0Q[!X`(#A<P%``#'```````/MTL>B<AFP>@%#[?`B40D2(/A'XG0T^")P??1
+MBT0D2"&,A=`%```/MTL>B<AFP>@%#[?`@^$?T^+WTB%4A5PY7"1T="*+`XM3
+M!(E0!(D"BX7D````B5@$B0.+5"1,B5,$B9WD````#[=#'HE$)`2+3"10B0PD
+MZ/S___^`;RD!@\8!9CEU6`^'?/[__XM$)'CV0`8!=%>+3"1TBQ&+002)0@2)
+M$(E,)`2)/"3H_/___^L[BU0D>(M"&`^V0`0/ME4I#[9-(@^V72''1"04____
+M`(E$)!")5"0,B4PD"(E<)`3'!"2X!P``Z/S___^!Q(P```!;7E]=PU575E.#
+M[&R+C"2`````BY0DB````(E4)&"+A"2,````B40D9(L!B40D/`^WA"2$````
+MP>`"BUPD/`.#S`4``(LX9H%_).$!=3</MD<F@^@1/`%W+(MQ*(ET)$3'1"1`
+M``````M4)&1U;XM$)$3&0#4`QT0D0`````#K79"-="8`BUPD/(N3>`4``+C8
+M)@$`9H%_$(4`=Q8/MT<0BW0D/`^VA`:X!```:<`H`0```<*)5"1`QT0D1```
+M``"+1"1@"T0D9'43BT0D0,:`M`````#'1"1$`````(!_%(%U!(!A"/>+1"1@
+M"T0D9`^%X````,9'%`#V1V8@#X2H!0``BT=(A<`/A)T%``")P_9`90)T(8M(
+M6(7)=!J+5S2%TG03BT<@B40D"(E4)`2)#"3H_/___XM,)#R+D4`*``"!PD`(
+M``"+="1`#[9&0L'@"`'"BP*C`````(G"P>H0B%-3P>@89HE#2(N10`H``('"
+M1`@```^V1D+!X`@!PHL2B14`````#[;"9HE#3`^VQF:)0TZ)T,'H$`^VP&:)
+M0U#!ZAB(4U*+D4`*``"!PDP(```/MD9"P>`(`<*+`J,`````#[;`9HE#2NG<
+M!```C;8`````#[=''FG`L`0``(M4)#P#@F0*``")1"1(B<6!Q2`$``"`?Q2`
+M=0K&1Q0AC;8`````@WPD0`!T<HM<)$"#>R``#X7!````BW<@B70D6`^V0TV)
+M1"0TBT$8#[9(!(M4)#P/MEHI#[9R(@^V0B&)1"0$BT0D8(M4)&2)1"0<B50D
+M((M4)%B)5"08BT0D-(E$)!2)3"00B5PD#(ET)`C'!"08"```Z/S____K78-\
+M)$0`=%:+5R")5"1<BT$8#[9(!(MT)#P/MEXI#[9V(HM$)#P/MD`AB40D!(M$
+M)&"+5"1DB40D&(E4)!R+5"1<B50D%(E,)!")7"0,B70D",<$)%0(``#H_/__
+M_XM%#(M5"(M-!(M=``^W=QZ)1"04B50D$(E,)`R)7"0(B70D!,<$))`(``#H
+M_/___XM,)$CV02(!#X3$````C5\\B5PD3(MW5(ET)%2+0P0/ME,!B40D"(E4
+M)`3'!"0=`0``Z/S___^`?SP`#X0_`0``QD0D4P"-="8`#[9T)%.-!';!X`*+
+M5"1,BTH(`<&)PXM4)%0#6@B+0PB)1"0XBP.+4P2)1"0HB50D+(MI"(M9!(L)
+MBU0D.(E4)!R+1"0HBU0D+(E$)!2)5"08B6PD$(E,)`B)7"0,B70D!,<$),`(
+M``#H_/___X!$)%,!#[94)%.+3"1,.!$/AK,```#I>/___XM<)$B`>R<`#XF@
+M````#[=7'HG09L'H!0^WP`^WTHE$)`B)5"0$QP0D.0$``.C\____BW0D/(N&
+MW`4``(N6V`4``(N.U`4``(N>T`4``(E$)!")5"0,B4PD"(E<)`3'!"10`0``
+MZ/S___\/MT<>B40D!,<$)&P!``#H_/___XL6#[=''F;!Z`4/M\"-!(4``P``
+MB8)P`0``BQ8/MT\>@^$?N`$```#3X(F"=`$``&:!?R3A`74B#[9')H/H$3P!
+M=Q>+1"1$B00DZ/S____I_`$``(VV``````^V5"1C]L(!#X3"`0``BT<D)?__
+M_P`]X0$.``^$KP$``(M,)#R+D4`*``"!PD`(``"+7"1`#[9#0L'@"`'"BS*)
+M-0````"+D4`*``"!PD0(```/MD-"P>`(`<*+*HDM`````(N10`H``('"2`@`
+M``^V0T+!X`@!PHL:B1T`````BY%`"@``@<),"```BTPD0`^V04+!X`@!PHL"
+MHP````")1"00B5PD#(EL)`B)="0$QP0D?0$``.C\____]D=F(`^$S0```(M/
+M2,9!9A#&1Q0@B?#!Z!"(05.)\,'H&&:)04B)WL'F"(GH#[;0C0069HE!3(G>
+M9H'F`/^)Z`^VU(T$%F:)04Z)VL'J$,'B"(GHP>@0#[;``<)FB5%0BUPD/(N3
+M0`H``('"3`@``(MT)$`/MD9"P>`(`<*+`J,`````#[;`9HE!2@^W44P/MUE.
+M#[=)4`^WP(E4)!")7"0,B4PD"(E$)`3'!"2:`0``Z/S___^+1"0\BY!`"@``
+M@<)`"```#[9&0L'@"`'"QP(`````ZV-F@7\DX0%U'0^V1R:#Z!H\`7<2QP0D
+M^`@``.C\____QD<4(>L^B7PD!(M4)#R)%"3H_/___^LLC;8`````A-)Y(HM,
+M)#R+`8N(6`$``(D-`````(7)=`R+7"0\BP.)B%@!``"#Q&Q;7E]=PXGV4X/L
+M"(M<)!2+3"00#[9#)#E+&'5!/`AT5CPH=%(\J)!T33R(=$D\"G1%/"J-="8`
+M=#T\JG0Y/(IT-8N!Y````(E8!(D#C8'D````B4,$B9GD````ZQF+D>@```")
+MF>@```"-@>0```")`XE3!(D:B0PDZ/S___^#Q`A;PXUT)@"#[`R+1"04B40D
+M!(M$)!")!"3H_/___X/$#,.0C70F`%.#[%B+7"1@C40D2HE$)#2-1"1,B40D
+M,(U$)$2)1"0LC40D1HE$)"B-1"10B40D)(U$)%*)1"0@C40D4XE$)!R-1"1.
+MB40D&(U$)%2)1"04C40D2(E$)!"-1"15B40D#(U$)%:)1"0(C40D5XE$)`0/
+MMT,DB00DZ/S___\/MD0D5XE$)`@/MD0D5HE$)`2-1"1`B00DZ/S____'1"0,
+M`0````^V1"17:<`H`0``B40D"(M#$(E$)`2-@V`%``")!"3H_/___\=$)`P!
+M````#[9$)%5IP+````")1"0(BT,0B40D!(V#?`4``(D$).C\____QT0D#`$`
+M```/MD0D5FG`%`T``(E$)`B+0Q")1"0$C8.8!0``B00DZ/S____'1"0,`0``
+M``^W1"10P>`"B40D"(M#$(E$)`2-@[0%``")!"3H_/___\=$)`P!````#[=$
+M)$AKP'")1"0(BT,0B40D!(V#8`8``(D$).C\____QT0D#`$````/MD0D5`^W
+M5"1(#Z_"C01`P>`"B40D"(M#$(E$)`2-@Q`&``")!"3H_/___\=$)`P!````
+MQT0D"``"``"+0Q")1"0$C8,L!@``B00DZ/S___\/MD0D5XE$)`S'1"0(``@`
+M`(M#$(E$)`2-@P@'``")!"3H_/___\=$)`P!````#[9$)%.-!(#!X`*)1"0(
+MBT,0B40D!(V#F`8``(D$).C\____QT0D#`$```#'1"0(H````(M#$(E$)`2-
+M@[0&``")!"3H_/___\=$)`P!````#[9$)%)IP)@```")1"0(BT,0B40D!(V#
+MT`8``(D$).C\____QT0D#`$````/MT0D3HT$0,'@`XE$)`B+0Q")1"0$C8/L
+M!@``B00DZ/S____'1"0,`0````^W1"10`<")1"0(BT,0B40D!(V#(`D``(D$
+M).C\____QT0D#`$````/MD0D5P'`B40D"(M#$(E$)`2-@T@)``")!"3H_/__
+M_\=$)`P!````#[9$)%4!P(E$)`B+0Q")1"0$C8-P"0``B00DZ/S____'1"0,
+M`0````^V1"16`<")1"0(BT,0B40D!(V#F`D``(D$).C\____QT0D#`$````/
+MMD,F`<")1"0(BT,0B40D!(V#P`D``(D$).C\____QT0D#`$````/MT0D1L'@
+M!8E$)`B+0Q")1"0$C8-\!@``B00DZ/S____'1"0,`0```(M$)$")1"0(BT,0
+MB40D!(V#Z`D``(D$).C\____QT0D$`$```#'1"0,0`````^W1"10P>`&B40D
+M"(M#$(E$)`2-@P0*``")!"3H_/___\=$)!`!````QT0D#``!``#'1"0(`!D`
+M`(M#$(E$)`2-@R@*``")!"3H_/___\=$)!`!````QT0D#(`````/MT0D4&G`
+ML`0``(E$)`B+0Q")1"0$C8-,"@``B00DZ/S____'1"00`0```,=$)`P$````
+M#[=$)$S!X`*)1"0(BT,0B40D!(V#<`H``(D$).C\____QT0D$`$```#'1"0,
+M!`````^W1"1*P>`"B40D"(M#$(E$)`2-@Y0*``")!"3H_/___\=$)!`!````
+MQT0D#`@````/MD0D4\'@"XE$)`B+0Q")1"0$C8.X"@``B00DZ/S____'1"00
+M`0```,=$)`P(````QT0D"```"`"+0Q")1"0$C8/<"@``B00DZ/S____'1"00
+M`0```,=$)`P(````#[=$)$YIP(P!``")1"0(BT,0B40D!('#``L``(D<).C\
+M____N`````"#Q%A;PXUV`(/L+(E<)!R)="0@B7PD)(EL)"B+;"0PBT4`B40D
+M%(U=+(D<).C\____B<:-4.")5"08BT0D%(D$).C\____B<>+13")=3"+5"08
+MB5H@B4(DB3"X`0```(7_#X2`````QD<DX<9')0'&1R80@$\G`8M4)#2+@IP`
+M``")1TB+1TR)4!R)T`60````B4<XQD<5S(M4)!@/MD(S9HE'$(M%`(E'&,='
+M()````"+1"0TB4<TQT=L$!P!`,=$)`0`````C4<\B00DZ/S___^)?"0$BU0D
+M%(D4).C\____N`````"+7"0<BW0D((M\)"2+;"0H@\0LPXVV`````(V\)P``
+M``!55U93@^P<BW0D,,=$)!@`````BU0D&`^VA#(^!0``//\/A,P````/MM!K
+MPER-C`9(`0``B4PD%("\!E(!````#X2M````OP````")1"00C:P&@`$``(V$
+M!D`!``")1"0,B2PDZ/S___^)PXM$)!`!\(N0A`$``(F8A`$``(DKB5,$B1J+
+M0R"%P'0>B40D"(N&1`4``(E$)`3'!"0%````Z/S___^`2R@"B5PD",=$)`0"
+M````BT0D%(D$).C\____@'M/`'0:B30DZ/S____'!"0!````Z/S___^`>T\`
+M=>:#QP&)^HM,)`PX41(/AV[___^#1"08`8-\)!@$#X40____B30DZ/S___^#
+MQ!Q;7E]=PXVV`````(V\)P````!55U93@^Q\BX0DD````,9`-0#&0#0`QD`S
+M`,:`N0P```")PH'"F`L``+@`````B?;&!!``@\`!/1`!``!U\HN$))`````%
+MY````(N4))````")@N0```")@N@```")T`7L````B8+L````B8+P````@<+T
+M````B50D1(N,))````")D?0```")D?@```")SX''_````(FY_````(FY``$`
+M`('!!`$``(E,)$R+G"20````B8L$`0``B8L(`0``@<,,`0``B5PD4(NT))``
+M``")G@P!``")GA`!``")]8'%'`$``(FN'`$``(FN(`$``('&)`$``(ET)$B+
+MA"20````B;`D`0``B;`H`0``!10!``")1"14BY0DD````(F"%`$``(F"&`$`
+M`(U$)':)1"0TC40D>(E$)#"-1"1HB40D+(U$)&Z)1"0HC40D>HE$)"2-1"1P
+MB40D((U$)'&)1"0<C40D;(E$)!B-1"1SB40D%(U$)&J)1"00C40D<HE$)`R-
+M1"1TB40D"(U$)'6)1"0$#[=")(D$).C\____#[9$)'6+C"20````B$$N#[9$
+M)'2(02\/MD0D<HB!X0````^W1"1Z9HE!6`^W1"1X9HF!E`L```^W1"1V@^@!
+M9HF!E@L```^W1"1J9HE!-@^W021F/8"1=`IF/8"4#X7A"@``BYPDD````,9#
+M,03&0RL$QD,R0,9#,`#&@]X````)QD,L`(G8!6`%``")!"3H_/___XG"B8-X
+M!0``#[9$)'5IP"@!``"%P'0+Q@(`@\(!@^@!=?6+A"20````!7P%``")!"3H
+M_/___XG"B[0DD````(F&E`4```^V1"1R:<"P````A<!T"\8"`(/"`8/H`77U
+MBX0DD`````68!0``B00DZ/S___^)PHN$))````")D+`%```/MD0D=&G`%`T`
+M`(7`=`O&`@"#P@&#Z`%U]8N$))`````%M`4``(D$).C\____B<*+C"20````
+MB8',!0``#[=$)'K!X`*%P'0+Q@(`@\(!@^@!=?6+A"20````!2P&``")!"3H
+M_/___XN<))````")@T0&``")V`40!@``B00DZ/S___^)PXNT))````")AB@&
+M``")\`5@!@``B00DZ/S___^)PHF&>`8``&:#?"1J`'1&N0````")6D0/MD0D
+M<XA"/(NT))````"+AO@```")EO@```"+="1$B3*)0@2)$`^V1"1SC01`C1R#
+M@\)P@\$!9CE,)&IWOXN$))`````%?`8``(D$).C\____B<*+A"20````B9"4
+M!@``9H-\)&X`=#"Y`````,9""`"+G"20````BX,``0``B9,``0``B3J)0@2)
+M$(/"((/!`68Y3"1N=]6+A"20````!9@&``")!"3H_/___XG"B[0DD````(F&
+ML`8``(!\)'$`=#.Y`````(N<))````"+@P@!``")DP@!``"+="1,B3*)0@2)
+M$(/"%(/!`0^V1"1Q9CG(=]*+A"20````!;0&``")!"3H_/___XG"BX0DD```
+M`(F0S`8``(V*H````(N<))````"+@Q`!``")DQ`!``"+="10B3*)0@2)$(/"
+M%#G*==N)V`70!@``B00DZ/S___^)PHF#Z`8``(!\)'``=#*Y`````(N<))``
+M``"+@R`!``")DR`!``")*HE"!(D0@<*8````@\$!#[9$)'!F.<AWTXN$))``
+M```%[`8``(D$).C\____B<*+M"20````B88$!P``9H-\)&P`=#"Y`````(N<
+M))````"+@Q@!``")DQ@!``"+="14B3*)0@2)$(/"&(/!`68Y3"1L=]6`?"1U
+M`'1/NP````"+M"20````@<8(!P``B30DZ/S___\/M].+C"20````B821(`<`
+M`(N1*`$``(F!*`$``(M,)$B)"(E0!(D"@\,!#[9$)'5F.=AWPXN$))`````%
+M(`D``(D$).C\____BYPDD````(F#.`D``(F#/`D```^W1"1Z9HF#0@D```^W
+MP(E$)`2)V`4\"0``B00DZ/S___^)V`5("0``B00DZ/S___^)@V`)``")@V0)
+M```/MD0D=6:)@VH)```/M\")1"0$B=@%9`D``(D$).C\____B=@%<`D``(D$
+M).C\____B8.("0``B8.,"0``#[9$)')FB8.2"0``#[?`B40D!(G8!8P)``")
+M!"3H_/___XG8!9@)``")!"3H_/___XF#L`D``(F#M`D```^V1"1T9HF#N@D`
+M``^WP(E$)`2)V`6T"0``B00DZ/S___^)V`7`"0``B00DZ/S___^)@]@)``")
+M@]P)```/MD,F9HF#X@D```^V0R:)1"0$B=@%W`D``(D$).C\____B=@%Z`D`
+M`(D$).C\____B<*)@P`*```/MD0D=&G`=`0``(G!@<%T10``=`^)T(G*Q@``
+M@\`!@^H!=?6+M"20````BX8`"@``B0B+E@`*```/MD0D=(A"!`^V1"1TB40D
+M"(E,)`2+A@`*``")!"3H_/___[T`````@'XF``^$IP```+\`````#[??:]M<
+MBX0DD````(VL&$@!``"-!`.-L$`!``")^HA6#,9&#0"+C"20````B8A(`0``
+MQD82`,:`?`$```#&@&0!````QX"@`0```````(V4&6`!``"-2@B)B&@!``")
+MB&P!``"#PA2)D'0!``")D'@!``"+C"20````C909@`$``(F0@`$``(F0A`$`
+M`,9&#@*#QP$/MD$F9CGX#X=>____BYPDD````,9#,`#&@SX%``#_QH,_!0``
+M_\:#0`4``/_&@T$%``#_@'PD=0`/A(,```"[``````^WRVG1*`$``(NT))``
+M``"+AG@%``#&1!`G`8N&>`4``,9$`B8`BX9X!0``QD0"3/^+AG@%``#&1`)"
+M_XN&>`4``&;'A`*4``````#'A(ZX`@```````(G1`XYX!0``C4$0B4$0`Y9X
+M!0``C4(0B4(4@\,!#[9$)'5F.=AW@HN$))````!FQX#<``````"X`````(N4
+M))````#&A!"X!```_X/``3V&````=>>`?"1T``^$K0```+L`````#[?#:<`4
+M#0``BXPDD````(N1L`4``,9$`C``BY&P!0``QD00,0"+D;`%``#'1!`,````
+M`(G!B[0DD`````..L`4``(U1$(E1$(G!`XZP!0``C5$0B5$4B<$#CK`%``"-
+M41B)41B)P0..L`4``(U1&(E1'(N6L`4``(EL$`B)P0..L`4``(U1*(E1*`.&
+ML`4``(U0*(E0+(/#`0^V1"1T9CG8#X=8____BX0DD````,:`WP```("`?"1R
+M`'1]NP`````/M]-ITK````"+C"20````BX&4!0``9L=$$#($`(N!E`4``,9$
+M`B8`BX&4!0``QD0"*/^+@90%``#&1`(T_XG1B[0DD`````..E`4``(U!%(E!
+M%(G1`XZ4!0``C4$4B4$8BX:4!0``B6P"5(/#`0^V1"1R9CG8=XB+A"20````
+MQH#@````@HN$))`````%(`H``(E$)`2+A"20````!00*``")!"3H_/___XN4
+M))````")@AP*``")T`5$"@``B40D!(U`Y(D$).C\____BXPDD````(F!0`H`
+M`(G(!6@*``")1"0$C4#DB00DZ/S___^+G"20````B8-D"@``B=@%C`H``(E$
+M)`2-0.2)!"3H_/___XF#B`H``(G8!;`*``")1"0$C4#DB00DZ/S___^)@ZP*
+M``")V`74"@``B40D!(U`Y(D$).C\____B<&)@]`*``"+M"20````BX;4"@``
+MBY;8"@``@'PD<0!T6HG#B=:_`````(G-*<6+1"1,B00DZ/S___^-5!T`B5`(
+MB5@,B7`0BXPDD````(N1"`$``(F!"`$``(M,)$R)"(E0!(D"@<,`"```@]8`
+M@\<!#[9$)'%F.?AWLXN$))`````%^`H``(E$)`2+A"20````!=P*``")!"3H
+M_/___XE$)%B+G"20````B8/T"@``BX0DD````(N8^`H``(NP_`H``+\`````
+MO0````"+5"10B10DZ/S___^+5"18`?J)4`B)6`R)<!"+C"20````BY$0`0``
+MB8$0`0``BTPD4(D(B5`$B0*!PP```0"#U@"!QP```0"#U0")^#4```@`">AU
+MJHN$))`````%'`L``(E$)`2+A"20````!0`+``")!"3H_/___XG!BYPDD```
+M`(F#&`L``(NT))````"+AAP+``"+EB`+``!F@WPD;`!T5XG#B=:_`````(G-
+M*<6+1"14B00DZ/S___^-5!T`B5`(B5@,B7`0BXPDD````(N1&`$``(F!&`$`
+M`(M,)%2)"(E0!(D"@<.,`0``@]8`@\<!9CE\)&QWMH/$?%M>7UW#D(VT)@``
+M``!55U93@^P,BVPD((M\)"2+7U0/MD<KB40D"(EL)`2)'"3H_/___XG&9H-/
+M,A"`?2L`=$FY`````/9#"0%T#.L\#[9#"=/XJ`%U#(/!`0^V12MF.<AWZF:#
+M^0-V)8M%``70`0``#[?1C120BP*C`````,'H%(/P`8/@`>LCN0````"+10`%
+MT`$```^WT8T4D(L"HP````#!Z!2#\`&#X`&$P'04#[;!B40D!(DL).C\____
+MZ88!``"-0S@Y0S@/A!$!``"%]@^$"0$```^V1DW'1(<\`````(L6BT8$B4($
+MB1")="0(QT0D!`8```")'"3H_/___X!^3P!T'Y"-="8`B2PDZ/S____'!"0!
+M````Z/S___^`?D\`=>:+1B"%P'16QT!@`````/9&*`1U"(DL).C\____BT8@
+MBY5$!0``B40D"(E4)`3'!"0!````Z/S___^+1B"+E40%``")1"0(B50D!,<$
+M)`8```#H_/___\=&(`````"`:PH!B70D!(DL).C\____BT4`BY!8`0``B14`
+M````A=)T"8M%`(F06`$``,9')@!F@V<R[X!_'P!T(KH`````#[?"BT2'/(7`
+M=`:`>";_=76#P@$/MD<?9CG0=^.`?S(`>`V^`````(!_'P!U$.M,B7PD!(DL
+M).C\____ZT@/M\:+7(<\A=MT)_9#*`)T(8M#((N51`4``(E$)`B)5"0$QP0D
+M!@```.C\____@&,H_8/&`0^V1Q]F.?!WPF;'1S("`(!G+?V#Q`Q;7E]=PXUT
+M)@"-O"<`````55=64X'LG````(N$)+````")1"1TBU`LB50D?(LZBX>L"@``
+MBP")A"2`````BTPD=(E,)`2)/"3H_/___XML)'2`O;<````!=@?&A;0````$
+MBT0D=(/`$,=$)'@`````BU0D=#E"$'0JBUPD=(/#$(D<).C\____B40D>(M,
+M)'2+01"+;"1XB6@$B44`B5T$B6D0BT0D=(-X(`!U5[W___\`@WPD>`!T"(M4
+M)'@/MVH>BTPD=`^V<4V+5"1\BT(8#[9`!`^V5RD/MD\B#[9?(8EL)!B)="04
+MB40D$(E4)`R)3"0(B5PD!,<$)!P)``#H_/___X-\)'@`#X1C!```BTPD>`^W
+M21Z)3"14:?&P!````[=D"@``BY\<"@``BVPD>(DL).C\____BX8L!```B40D
+M0(N6*`0``(N.)`0``(NV(`0``(M$)'@/MV@>BT0D0(E$)!2)5"00B4PD#(ET
+M)`B);"0$QP0DZ`<``.C\____BT0D5,'@!@'#BU,TB50D0(M3,(M++(MS*(MK
+M)(EL)%B+0R")1"1<BVL<B6PD8(M#&(E$)&2+:Q2);"1HBT,0B40D;(MK#(M#
+M"(F$))0```"+0P2)A"20````BQN+1"1`B40D.(E4)#2)3"0PB70D+(M4)%B)
+M5"0HBTPD7(E,)"2+1"1@B40D((M4)&2)5"0<BTPD:(E,)!B+1"1LB40D%(EL
+M)!"+E"24````B50D#(N,))````")3"0(B5PD!,<$)&`'``#H_/___XML)'B#
+MQ3R)K"2$````BT0D>(M`5(F$)(P```"+100/ME4!B40D"(E4)`3'!"0=`0``
+MZ/S___^`?0$`#X2>````QH0DBP`````/MK0DBP```(T$=L'@`HN4)(0```"+
+M2@@!P8G#BZPDC`````-="(M#"(E$)'"+`XM3!(E$)$")5"1$BVD(BUD$BPF+
+M5"1PB50D'(M$)$"+5"1$B40D%(E4)!B);"00B4PD"(E<)`R)="0$QP0DP`@`
+M`.C\____@(0DBP````$/MI0DBP```(N,)(0````X40$/AVK___]F@W]8``^$
+M"`(``+X`````C:\\"0``C8?D````B40D4(VV``````^WQL'@`@.'S`4``(L8
+MA=L/A,H!```/MT,0BU0D=&8Y0AP/A;@!```/MY>2"P``.90D@````'1A@\(!
+M#[>'E@L``#G"&<`APHN'K`H``(/`!(L$D*D```@`=35F)?\/9CGP=2PY7"1X
+M=2^)/"3H_/___XM,)'@/MT$>B40D!,<$)%0)``#H_/___^F3`0``D#N4)(``
+M``!UGXM$)'R`>#0`#X4Y`0``#[=#$&8]A0`/ARL!```/M\"`O`>X!```_P^$
+M&@$``(.\)+``````#X3Q````BU0D=`^V0B2#X`6#^`4/A=T```"+%P^W0QYF
+MP>@%#[?`C02%``,``(F"<`$```^W2QZ#X1^Z`0```(G0T^")P8L'B8AT`0``
+M#[=#'L'@`@.'S`4``,<```````^W2QZ)R&;!Z`4/M\")1"1,@^$?B=#3X(G!
+M]]&+1"1,(8R'T`4```^W2QZ)R&;!Z`4/M\"#X1_3XO?2(52'7#M<)'AT-XL3
+MBT,$B4($B1"#>U0`=`^-0U2)1"0$B3PDZ/S___^+A^0```")6`2)`XM4)%")
+M4P2)G^0````/MT,>B40D!(DL).C\____BTPD=(!I3P'K&XM$)'SV0`8"=!&)
+M7"0$BU0D=(D4).C\____D(/&`68Y=U@/AQ/^__^#O"2P`````'0KBTPD=`^V
+M022#X`6#^`5U&XML)'B+50"+102)0@2)$(EL)`2)#"3H_/___X'$G````%M>
+M7UW#D)"055=64X/L#(M\)"`/MG0D)`^V1"0LB$0D"XM'+(L(N@`````/MEPD
+M*`'SB%PD`XGV#[:$"K@$```\_W1&#[;`:<`H`0``B40D!`.!>`4``(GS.)C:
+M````=2DYN.0```!U(0^V7"0#B)C9````BX%X!0``#[9<)`N+;"0$B)P%V```
+M`(/"`8'Z@````'6C@\0,6UY?7<.-="8`C;PG`````(/L"(D<)(ET)`2+="08
+M#[9<)!`/ME0D%(M$)`R+2#`/MH&0````/$]W*0^VP(T$@`':B)3!E0````^V
+M@9````"-!(")\HB4P90```"`@9`````!BQPDBW0D!(/$",.)]E=64XM\)!`/
+MMT0D%+O_____9H7`=$&[_____[D`````@^@!#[?P#[84.8U"T#P)=Q>`^_\/
+ME,"#Z`$APP^VPXT$@(U<0M#K!8#[_W4*@\$!C48!.<%USP^VPUM>7\.)]E57
+M5E.+;"04#[9T)!@/MGPD'(M%+(L(N@````"-="8`#[:$"K@$```\_W0K#[;`
+M:<`H`0```X%X!0``.:CD````=12)\SB8V0```'4*B?J(D-L```#K"X/"`8'Z
+M@````'6^6UY?7<.)]HV\)P````!55U93@^P$BW0D&`^V?"0<#[9$)"2(1"0#
+MBT8LBQB+;C"Y``````^VA!FX!```//]T1@^VP&G`*`$``(G"`Y-X!0``.;+D
+M````=2V)^#B"V0```'4C@'PD`P!T#HN"X````(M4)"")`NL9BTPD((L!B8+@
+M````ZPN#P0&!^8````!UHXGJN0````"-M@`````/MH*4````/`%V.3P7=#6)
+M^#B"E0```'4K@'PD`P!T$HT$B8N$Q9@```"+5"0@B0+K'8T4B8M,)""+`8F$
+MU9@```#K"X/!`8/"*(/Y4'6Q@\0$6UY?7<.)]HV\)P````!55U93@^P@#[9L
+M)#B+1"0TB[#H````#[9&`L'@"`^V5@.-/!`/M\>#P`0]``@```^/[0```(GJ
+MA-)T3HM,)#0/MI'<````B=.#X^`/MD8!@^`/B=&#X1`)V`G(B=.#XPB#X/.)
+MT8/A!`G8"<B#X@*#X/R+7"0T#[:+W````(/A`0G0"<B(1@'K3`^V5@&)TX/C
+MX(M,)#0/MH'<````@^`/B=&#X1`)V`G(B=.#XPB#X/.)T8/A!`G8"<B#X@*#
+MX/P/MDX!@^$!"=`)R(M<)#2(@]P```"-5@@/M\>-?`8$.==V/XE4)!R[````
+M`(GH#[;PC6PD'(ET)`R);"0(#[;#B40D!(M4)#2)%"3H_/___XM$)!R#P`2)
+M1"0<@\,!.?ARTX/$(%M>7UW#C;8`````4X/L&(M,)"2+630/MD,"P>`(#[93
+M`P'0#[?`C5`$#[=!(#G"?RZ+3"0@BX'H````B50D"(E<)`2)!"3H_/___\=$
+M)`0`````BT0D((D$).C\____@\086\.-M"8`````55=64X/L'`^V?"0XBT0D
+M,(M8,(E<)!B^`````(ML)#2#Q00/MH.4````/`%V0CP7=#Z)^#B#E0```'4T
+MC02VBTPD&(V4P9P```"+3"0T#[9!`SP@=@6X(`````^VP(E$)`B);"0$B10D
+MZ/S___^)]H/&`8/#*(/^4'6H@\0<6UY?7<.-M@````"-O"<`````@^PLB5PD
+M'(ET)"")?"0DB6PD*(M<)#`/MD0D-(A$)!>+0RR+*(DL).C\____B<:%P`^$
+M!P$``(DL).C\____B<>%P'41B70D!(DL).C\____Z>@```"-5CR)5"08BU`(
+MBX/H````BTPD/(E,)`B)1"0$B10DZ/S____&1F@*QD85K`^W0QQFB480BT0D
+M0(E&2(EN&(M4)#R)5B"#3F02BT<(B48TB7Y0C8.X````B48XQD8<(,=&;```
+M``#&1B0[QD8E`@^V3"07B$XFBT0D.,'H$(A&)XM4)#@/ML:(1BB(5BD/MD8B
+MB$8J#[9&(8A&*P^V3"0\B$XLQD8M`,=$)`0`````BT0D&(D$).C\____BT8@
+MB40D#(M'#(M7$(E$)`2)5"0(BU0D&(D4).C\____B70D!(DL).C\____BUPD
+M'(MT)""+?"0DBVPD*(/$+,.-M"8`````C;PG`````(/L+(E<)!R)="0@B7PD
+M)(EL)"B+7"0P#[9$)#2(1"07BT,LBRB)+"3H_/___XG&A<`/A.T```")+"3H
+M_/___XG'A<!U$8ET)`2)+"3H_/___^G.````C58\B50D&,9&:`K&1A6L#[=#
+M'&:)1A"+1"1`B49(B6X8QT9D"````(E^4(M'"(E&-(M4)#R)5B"-@[@```")
+M1CC&1AP@QT9L`````,9&)#S&1B4"#[9$)!>(1B:+1"0XP>@0B$8GBU0D.`^V
+MQHA&*(A6*0^V1B*(1BH/MD8AB$8K#[9$)#R(1BS&1BT`QT0D!`````"+5"08
+MB10DZ/S___^+1B")1"0,BT<,BU<0B40D!(E4)`B+1"08B00DZ/S___^)="0$
+MB2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPY"-M"8`````@^PLB5PD'(ET
+M)"")?"0DB6PD*(ML)#"+12R+`(E$)!2+E>@````/MD("P>`(#[92`P'0#[?`
+MC5@$@?L`"```#X_O````BT0D%(D$).C\____B<:%P`^$V0```(M$)!2)!"3H
+M_/___XG'A<!U%8ET)`2+1"04B00DZ/S____IL@```(U&/(E$)!B+5PB+A>@`
+M``")7"0(B40D!(D4).C\____QD85K`^W11QFB480BT0D%(E&&(E>((-.9!*+
+M1PB)1C2)?E"-A;@```")1CC&1AP@QT9L`````,9&)!W&1B40QD8F`@^V1B&(
+M1B>(7BC'1"0$`````(M$)!B)!"3H_/___XM&((E$)`R+1PR+5Q")1"0$B50D
+M"(M$)!B)!"3H_/___XET)`2+1"04B00DZ/S___^+7"0<BW0D((M\)"2+;"0H
+M@\0LPY"-M"8`````@^PLB5PD)(ET)"B+7"0P#[94)#0/MG0D.,=$)"``````
+M@'LG`71*QT0D#`$```"-1"0@B40D"`^VPHE$)`2)'"3H_/___XM$)""%P'0C
+M@`B`B?"$P'0*BT0D((!(`R#K"(M$)""`8`/?B1PDZ/S___^+7"0DBW0D*(/$
+M+,.-=@"#["R)7"0<B70D((E\)"2);"0HBUPD,`^V1"0TB$0D%XM#+(LHB2PD
+MZ/S___^)QH7`#X2Y````B2PDZ/S___^)QX7`=1&)="0$B2PDZ/S____IF@``
+M`(U&/(E$)!C&1A6L#[=#'&:)1A");AC'1F0(````B7Y0BT<(B48TQT8@``@`
+M`(V#N````(E&.,9&'"#'1FP`````QD8D',9&)0$/MD0D%XA&)L9&)PC&1B@`
+MQT0D!`````"+1"08B00DZ/S___^+1B")1"0,BT<,BU<0B40D!(E4)`B+1"08
+MB00DZ/S___^)="0$B2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPXVV````
+M`(V_`````%575E.#[!R+3"0TBUDT#[9#`L'@"`^V4P,!T`^W\(U6!`^W02`Y
+MP@^/@P$``(U["(UL,P2)?"00QD0D%P#'1"08`````#GO#X/U````C78`#[9$
+M)!B(1"06#[9'`L'@"`^V5P,!T&:)1"04#[?PB70D!(M$)!"#P`2)!"3H_/__
+M_SS_=6N+1"00C50P!(G3.=4/AOH```#&1"07_XUT)@`/MD("P>`(#[92`XTT
+M$`^WQHE$)`2-0P2)!"3H_/___SS_=1&`?"07_P^%C@```)#I@P```#A$)!=V
+M!(A$)!</M\:-5`,$B=,YU79QZ[*)]BI$)!</ML")1"0(#[9<)!:)7"0$BU0D
+M,(D4).C\____B5PD"(E\)`2+1"0PB00DZ/S___\/MT0D%(M4)!"-?`($B7PD
+M$(-$)!@!.?T/AP[____'1"0$`@```(M$)#")!"3H_/___^M8QD0D%P`/MD0D
+M%HE$)`B)?"0$BU0D,(D4).C\____#[=$)!2+5"00C7P"!(E\)!"#1"08`>F_
+M_O__#[9$)!:)1"0(B7PD!(M$)#")!"3H_/___^N6C70F`(/$'%M>7UW#D(VT
+M)@````!55U93@^P<BTPD-(M9-`^V0P+!X`@/ME,#`=`/M\"#P`0/MU$@.=`/
+MCQX!``"-<P@/MEL!N0````"Z`````(GV`DX"#[9&`XUT!@2#P@$XTW/NA,D/
+MA-,```#&1"0;`+\`````C4'_#[;`@\`!B40D%`^V5+X!`%0D&P^V!+X\`70$
+M/!=U2@^V7"0;*-,X7"0;#X:)````C4<!#[;HC78`#[8$OHE$)`R);"0(#[;#
+MB40D!(M$)#")!"3H_/___X/#`3I<)!MT6.O6C;8`````BTPD,(M!,("XD0``
+M``%T0`^V7"0;*-,X7"0;=C.-1P$/MN@/M@2^B40D#(EL)`@/ML.)1"0$BT0D
+M,(D$).C\____@\,!.EPD&W78D(UT)@"#QP$[?"04#X5$____BU0D,(M",,:`
+MD0````''1"0$!P```(D4).C\____@\0<6UY?7<.-M@````"-O"<`````@^PL
+MB5PD'(ET)"")?"0DB6PD*(M<)#"%VP^$S````(M#+(LHB2PDZ/S___^)QH7`
+M#X2U````B2PDZ/S___^)QX7`=1&)="0$B2PDZ/S____IE@```(U&/(E$)!C&
+M1A6L#[=#'&:)1A");AC'1F0(````B7Y0BT<(B48TQT8@``@``(V#N````(E&
+M.,9&'"#'1FP`````QD8D',9&)0'&1B8"QD8G",9&*`#'1"0$`````(M$)!B)
+M!"3H_/___XM&((E$)`R+1PR+5Q")1"0$B50D"(M$)!B)!"3H_/___XET)`2)
+M+"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#D(/L'(E<)!")="04B7PD&(M\
+M)"2+="0@BU](#[=7$&:!^H4`#X>'````#[?"#[:,!K@$``"`^?]T=V:#^G]W
+M&0^VP8N6>`4``&G`*`$``(M$$"P/MD`$ZSAF@?J!`'<9#[;!BY:P!0``:<`4
+M#0``BT00"`^V0`3K&`^VP8N6E`4``&G`L````(M$$%0/MD`$D#S_=!P/ML"`
+MO`8^!0``_W0/@/G_=`H/MD<4/`9U,HGV@W]0`'0/C4=0B40D!(DT).C\____
+MB7PD!(DT).C\____QT,L_____XD<)/]3*.MQA,!U.O9'9`AT&8M+'(M7-(M'
+M((E$)`B)5"0$B0PDZ/S____'0RP`````BU,@A=)T!8M#%(D"B1PD_U,HZQ+'
+M0RS_____B1PD_U,HD(UT)@"#?U``=`^-1U")1"0$B30DZ/S___^)?"0$B30D
+MZ/S___^+7"00BW0D%(M\)!B#Q!S#ZPV0D)"0D)"0D)"0D)"0@^P<B5PD#(ET
+M)!")?"04B6PD&(M<)"2+?"0@#[9K%`^W0Q!F/84`=QF+EW@%```/M\`/MH0'
+MN`0``&G`*`$``.L+BY=X!0``N-@F`0"--`*)Z(3`=2%FQX:4``````"`>R0<
+M=1*`>R8"=0R)7"0$B30DZ/S___^#>U``=`^-0U")1"0$B3PDZ/S___^)7"0$
+MB3PDZ/S___^)Z#P&=#Z-G@0!``")7"0$BT<4B00DZ/S____'A@0!``"`A!X`
+MQX8,`0```````(FV$`$``(E<)`2+1Q2)!"3H_/___XM<)`R+="00BWPD%(ML
+M)!B#Q!S#55=64X/L'`^V1"0XB$0D&XM4)#"+0BR+,+\`````BVPD-(/%#`^V
+MA#>X!```//]T40^VP&G8*`$``,=$)`@(````B6PD!(G8`X9X!0``!:````")
+M!"3H_/___X3`=".+AG@%```/ME0D&XB4`]H```"+AG@%``"+5"0PB90#Y```
+M`(/'`8'_@````'68@\0<6UY?7<.-="8`C;PG`````%575E.#[!R+3"0TBW$T
+M#[9&`L'@"`^V5@,!T`^W^(U7!`^W02`YP@^/]0```(U>"(UT/@2)="04B=TY
+MW@^&S````,=$)!@`````C;8`````#[9,)!@/MA.$T@^(E0```(G0@^`//`8/
+MA8@```#V0P/`=`KV0P7`#X5X````]L(0=#6`>P0`=&V-=0B_``````^V0P.)
+M1"0(B70D!(M$)#")!"3H_/___X/&'(/'`8GX.$,$=D#KV8![`@!T.(UU!+\`
+M````#[;)B4PD$(UT)@"+1"00B40D"(ET)`2+1"0PB00DZ/S___^#QAR#QP&)
+M^#A#`G?;#[9#`8U<!0*)W8-$)!@!.UPD%`^"0O___\=$)`0!````BT0D,(D$
+M).C\____@\0<6UY?7<.-M@````!55U93@^PLBT0D0(E$)""+5"1$#[92%(A4
+M)"N+3"1$#[=1$&:!^H4`#X>Y`P``#[?"BUPD(`^VC`.X!```N/\```"`^?]T
+M8F:#^G]W'0^VP8M<)""+DW@%``!IP"@!``"+1!`L#[9`!.L_9H'Z@0!W'0^V
+MP8M<)""+D[`%``!IP!0-``"+1!`(#[9`!.L;#[;!BUPD((N3E`4``&G`L```
+M`(M$$%0/MD`$BU0D(`^VA`(^!0``B40D'&O`7(V$`D@!``")1"0DBY)X!0``
+M#[;!:<`H`0``C30"@'PD*P`/A9("``!FQX:4``````"+1"1$@'@D'`^%>P(`
+M``^V0"8\`G1:/`)W"SP!#X5G`@``D.LA/`=T,CP*#X58`@``BTPD1(E,)`2)
+M-"3H_/___^E#`@``BUPD1(E<)`2)-"3H_/___^DN`@``BT0D1(E$)`2)-"3H
+M_/___^D9`@``BU0D1(E4)`2)-"3H_/___XV>!`$``(E<)`2+1BR+`(M`%(D$
+M).C\____QX8$`0``@(0>`,>&#`$```````")MA`!``")7"0$BT8LBP"+0!2)
+M!"3H_/___\9&)O]K1"0<7(M,)""`O`%2`0````^$>@$``+\`````B<.-K`&`
+M`0``B?:)+"3H_/___XG&BU0D((T$$XN0A`$``(FPA`$``(DNB58$B3*`?B;_
+M#X2B````@'XE``^%GP```(GS@+ZU``````^$3P$```^V3B0/MM&)T(/@!H/X
+M!G4I]L(!="2)="0,#[9&38E$)`B+1C")1"0$BTPD)(D,).C\____Z14!``"#
+M^`1U(?;!`8VT)@````!T%8E<)`2+7"0@B1PDZ/S____I[P```(/X!@^%Y@``
+M`/;!`0^%W0```(E<)`2+1"0@B00DZ/S____IR````(GVQH:U`````(/'`8M,
+M)""-E!E``0``#[9"$HGY.,@/APW___\XP75SA,!T;[\`````:UPD'%R+1"0@
+MC:P8@`$``(DL).C\____B<:+5"0@C003BY"$`0``B;"$`0``B2Z)5@2),H!^
+M)O]T'@^V1B4\(G0$/`UU$L=$)`0*````B30DZ/S____K/H/'`8GYBT0D(#B,
+M&%(!``!WIFM$)!Q<BU0D(,:$`DT!``#_BTPD)(E,)`2)%"3H_/___X!\)"L`
+M#X6B````BUPD1(-[4`!T%8G8@\!0B40D!(M$)"")!"3H_/___XM4)$2)5"0$
+MBTPD((D,).C\____@'PD*P!T:`^WAI0```"#P`%FB8:4````9H/X"G8.9L>&
+ME```````Z>#]___'1"0$"@```(DT).C\____ZS&+7"0@#[:;/08``(E<)!QK
+MPUR+5"0@C80"2`$``(E$)"2+DG@%``"XV"8!`.F^_/__@\0L6UY?7<.#[`B)
+M'"2)="0$BUPD#(MT)!"+5"04BTPD'(7;=$2%]G1`A=)T/(-\)!@`=#5F@?F%
+M`'<N#[?!@+P#N`0``/]T(<9").'&0B4!QD(F$V:)2A")<AB+1"08B4)LN`$`
+M``#K!;@`````BQPDBW0D!(/$",.-M"8`````C;PG`````(!\)`@!&<#WT"4`
+M``R`BU0D!(M2!(E"#,.0D)"0D)"05E.+7"00BTPD,(MT)#@/MT0D#&8](B=W
+M268]("=S>68]0"%T<V8]0"%W&68]("&0=&9F/2(A=&!F/5`'C70F`'5@ZU1F
+M/40A=$YF/40AB?9R4&8M$"=F@_@!=T:-="8`ZS9F/8(G=#!F/8(GC70F`'<2
+M9CTD)W0@9CV`)XUT)@!U(.L49CV`D70.9CV`E(GV=`9F/8!R=0K&`T"+1"04
+MQ@`"BT0D&,8`!`^V$XM$)"R($&;'`8``9L<&``"+1"0@Q@`@BT0D)&;'```!
+M#[83BT0D*(@0#[8#9@,!9@,&BU0D-&:)`HM4)!QFB0(/MQ&+1"0\9HD0#[<1
+M@\(+BT0D0&:)$%M>PXUV`(V\)P````!55U93@^P$BWPD&`^V1"0<B$0D`P^W
+M;UAFA>T/A-X```"+C\P%``"^`````(UT)@"+`87`#X2V````#[=0$+O_````
+MN/____]F@?J%`'=T#[?"#[:<![@$``"X_____X#[_W1<9H/Z?W<9#[;#BY=X
+M!0``:<`H`0``BT00+`^V0`3K/6:!^H$`=QD/ML.+E[`%``!IP!0-``"+1!`(
+M#[9`!.L=#[;#BY>4!0``:<"P````BT005`^V0`2-M@`````/MMN+EW@%```Z
+M1"0#=2$/M\-IP"@!```/MD00)(/@!8/X!74+L`'K&XVT)@````"#Q@&#P01F
+M.>X/A3'___^X`````(/$!%M>7UW#C70F`%575E.#[`B+5"0<BT(LBRB+A1P*
+M``")1"0$#[=]6+D`````O@````#K28VV``````^WV8N%S`4``(L4F(72=#"+
+M0B0E____`#WA`1``="&+1"0<#[=`'&8[0A!U$XG8P>`&BU0D!&8Y=!`(=`N-
+M=@"#P0%F.?ERN&8Y^700@\8!9H/^'W<'N0````#KY@^WQH/$"%M>7UW#D(VT
+M)@````!3BU0D"(M,)`R+7"00BT(XA<!T%L8`<(M".(A(`HM".,9`!P"+0CB(
+M6`Q;PXUT)@#SPXVT)@````"-O"<`````@^P0B1PDB70D!(E\)`B);"0,BTPD
+M%`^W?"08B?J!XO\!``"+@<P%``"+-)"%]G0P#[:9W@````^V1A6)V=/@#[?H
+M#[?7N/__``#3X"'".=4/E<`/ML"#Z`$AQI"-="8`B?"+'"2+="0$BWPD"(ML
+M)`R#Q!##C70F`(V\)P````"+5"0$N`````"-M"8`````Q@00`(/``3VP````
+M=?+&0BC_QD(T_XU"%(E"%(E"&,.+5"0$N`````"-M"8`````Q@00`(/``3TH
+M`0``=?+&0DS_QD)"_\9"3A^-0A")0A")0A3#C;8`````C;\`````4XM$)`B+
+M7"0,BQ.+B``!``")D``!```%_````(D"B4H$B1''`P````!;PY"-="8`4X/L
+M"(M<)!"+3"04BY/X````B8OX````C8/T````B0&)402)"H-Y3`!T#XU!3(E$
+M)`2)'"3H_/___X/$"%O#D%.+1"0(BUPD#(L3BX@0`0``B9`0`0``!0P!``")
+M`HE*!(D1QP,`````6\.0C70F`%.+1"0(BUPD#(L3BX@(`0``B9`(`0``!00!
+M``")`HE*!(D1QP,`````6\.0C70F`(M$)`2+5"0(BX@@`0``B9`@`0``!1P!
+M``")`HE*!(D1P^L-D)"0D)"0D)"0D)"0D%.+1"0(BUPD#(L3BX@H`0``B9`H
+M`0``!20!``")`HE*!(D1QP,`````6\.0C70F`%.+1"0(BUPD#(L3BX@8`0``
+MB9`8`0``!10!``")`HE*!(D1QP,`````6\.0C70F``^V1"0$/!=W%P^VP/\D
+MA:`(``"X-````,.-M"8`````N`0```##N#P```"0C70F`,.X%````,.X0```
+M`(UT)@##N!P```##N!@```"-="8`P[@H````P[@@````C70F`,.X3````,.)
+M]HV\)P````!55U93BVPD%(M\)!@/ME<DB="#X`:#^`9U"?;"`0^$R@```(!_
+M0O\/A<````"+10"+L!@!``")-0````"Y`````+@!````B</3XX7>=3*(3T*+
+M50")V`GPB8(8`0``BT4`BX!8`0``HP````")VB'"='>+10")D%@!``#K;(UV
+M`(/!`8/Y('6YBT4`B[`<`0``B34`````L0"-M"8`````B<JX`0```(G#T^.%
+MWG4RC4(@B$="BU4`B=@)\(F"'`$``(M%`(N`8`$``*,`````B=HAPG03BT4`
+MB9!@`0``ZPB#P0&#^2!UMX!%+`%;7E]=PXVT)@````"-O"<`````5U93BWPD
+M$(M4)!2`>C3_#X6W````BP>+L!@!``")-0````"Y`````+@!````B</3XX7>
+M=2R(2C2+%XG8"?")@A@!``"+!XN`6`$``*,`````B=HAPG1QBP>)D%@!``#K
+M9X/!`8/Y('6_BP>+L!P!``")-0````"Q`(VT)@````"X`0```(G#T^.%WG4S
+MB$HTBQ>)V`GPB8(<`0``BP>+@&`!``"C`````(G:(<)T&8L'B9!@`0``ZP^-
+MM"8`````@\$!@_D@=;B`1RP!6UY?PU,/MEPD$(M$)`B+2"B%R70QN@````"+
+M1)$\A<!T!3A8370/@\(!@_H%=!>0C70F`.OD9H%Y)(4`=PB%P(UT)@!U!;@`
+M````6\.-M"8`````55=64X/L#(ML)"`/MD0D),'@"`^V5"0HC300@'T<``^$
+MR0```(-].``/A+\```#V160)#Y3`B<>Y`````(UV`(G+#[<4S0`)``")\"'0
+M9CG"#X6+````#[84S04)``"`^@-T!8#Z!W4+B?@X!,T$"0``=6[&110@#[8$
+MW08)``")1"0(#[;"B40D!(DL).C\____BU4X#[8$W0<)``"(0@V#?"0L`'0K
+MBT0D+(L8BW`$BTTXB7$#BT4X@`B`]D5F!'00A?9T#(M%.(E8"(M%.(`@?XM5
+M.`^V11R#Z`>(0@?K#(/!`8/Y$`^%4O___X/$#%M>7UW#C78`C;PG`````(/L
+M#(M$)!"-D!0!``"Y`````#F0%`$``'01B10DZ/S___^)P<=`%`````")R(/$
+M#,/K#9"0D)"0D)"0D)"0D)"#[`R+1"00C9`D`0``N0`````YD"0!``!T"HD4
+M).C\____B<&)R(/$#,.-M@````"#[`R+1"00C9`<`0``N0`````YD!P!``!T
+M)(D4).C\____B<&)PK@`````D(UT)@#&!!``@\`!/9@```!U\HG(@\0,PXVV
+M`````(V_`````(/L#(M$)!"-D`0!``"Y`````#F0!`$``'0*B10DZ/S___^)
+MP8G(@\0,PXVV`````(/L#(M$)!"-D/P```"Y`````#F0_````'0.B10DZ/S_
+M__^)P<9`"`")R(/$#,.)]E575E.#[!R)1"00B=7'1"04`````,=$)!@`````
+MC78`BU0D&(M,)!`/MH0*.`4``#S_#X0H`0``#[;0#[=$)!AF@^B`9CV!``^'
+M?`````^WPFG`%`T``(G#`YFP!0``@'LP`'15O@````"->RB-=@")/"3H_/__
+M_XU(^(M3+(E#+(EY"(E1#(D"BT$D)0#__P`]``#_`'48]D$G!'02BT$@A<!T
+M"XGJB%`!C;8`````@\8!B?$X2S!WMHGHB(.2````@\4!Z98````/M\)IP+``
+M``")PXM4)!`#FI0%``"`>Q\`=$.Y`````(VV``````^VP8M4@SR%TG0EBT(D
+M)0#__P`]``#_`'46]D(G!'00BT(@A<!T"8GJB%`!C70F`(/!`3A+'W?(B>F(
+MBZ0```"`NZ4````#=1Z#1"04`8M$)!2#P`.#^`9V%H/%`<=$)!0`````ZPF#
+MQ0&-M@````"#1"08`8-\)!@&#X6P_O__BU0D$(N"1`4``#G0=0P%R`P``(GJ
+MZ';^__^#Q!Q;7E]=PXVT)@````"-O"<`````@^P,BU0D$(M$)!0/MD@$#[:$
+M$3X%``#&A!$^!0``_P^WP(E$)`2!PMP)``")%"3H_/___X/$#,.0C;0F````
+M`(/L"(D<)(ET)`2+="00BUY,A=MT)(U.)(U3#(M##(E&)(M"!(E!!(M""(E!
+M"(M"#(E!#(M#'(E&-(L<)(MT)`2#Q`C#C;8`````C;\`````@^P(B1PDB70D
+M!(MT)!"+7DR%VW0HC4L,C58DBT8DB4,,BT($B4$$BT((B4$(BT(,B4$,BT8T
+MB4,<QD,(`8L<)(MT)`2#Q`C#D(VT)@````!75E.#[!"+?"0@BQ]F@WM8``^$
+MNP```+X`````C70F``^WUHN#S`4``(L,D(7)#X21````#[=1$&:!^H4`=W$/
+MM\(/MH0#N`0``#S_=&)F@_I_=QP/ML"+DW@%``!IP"@!``"+1!`L#[90!.M(
+MC78`9H'Z@0!W&0^VP(N3L`4``&G`%`T``(M$$`@/ME`$ZR4/ML"+DY0%``!I
+MP+````"+1!!4#[90!.L,C;0F`````+K_````#[9'!#G"=0B)#"3H_/___X/&
+M`68Y<U@/AT[___^#Q!!;7E_#C;0F`````(/L'(E<)!2)="08BUPD((MT)"0/
+MMD8T//]T&0^VP(E$)`2+`XD$).C\____QD8T_X!K+`&+7"04BW0D&(/$',.#
+M[!R)7"04B70D&(M<)""+="0D#[9&0CS_=!D/ML")1"0$BP.)!"3H_/___\9&
+M0O^`:RP!BUPD%(MT)!B#Q!S#5U93@^P0BW0D((M<)"0Y<Q@/A,\```"`>Q0`
+M#X66````#[9#)#P5=`@\50^%A@```(M#3(7`='^)PH!X"`%U=V:!>`SA`75O
+MB[YX!0``#[=#$+G8)@$`9CV%`'<1#[?`#[:$!K@$``!IR"@!``"-!`\/ME(.
+M@/H'=!^`^@=W!X#Z!G4SZQR`^@R-M"8`````=""`^@UU(.L09H-@.OV)]NL5
+M9H-(.@+K#F:#8#KWB?;K!6:#2#H(@WM0`'0I@7L@``@``'<1C4-0B40D!(DT
+M).C\____ZP^-0U")1"0$B30DZ/S___]F@7LDX0$/A08!```/MT,09CV%`'=Z
+M#[?`#[:$!K@$```\_W1KBY9X!0``@'L4`'5?#[;`:<`H`0``C00"#[93)H#Z
+M!W0=@/H'=P>`^@9U,>L:@/H,D(UT)@!T((#Z#74@ZQ!F@V`Z_8GVZQ5F@T@Z
+M`NL.9H-@.O>)]NL%9H-(.@AF@7LDX0&-=@`/A8(```"`>R8+=7P/MTL0#[9&
+M+HUX_XG*ZQR0C70F`(/"`6:!^H4`=PT/M\*`O#"X!```_W4)#[?".?A\XNM$
+M9CW_`'49ZSR#P0%F@?F%`'<-#[?!@+PPN`0``/]U#`^WP3G'?^*X_P```&:)
+M0Q#&0Q2`B5PD!(DT).C\____Z1P!``#&0Q0`.7,8="B+0TR%P'0A@'@(`74,
+MB5PD!(DT).C\____C4-,B40D!(DT).C\____@WM4`'0/C4-4B40D!(DT).C\
+M____B5PD!(M#&(D$)/]3;`^W4R1F@?KA`755#[9#)H/H$3P!=TH/MT,09CV%
+M``^'I0````^WP`^VA`:X!```//\/A)(````/ML!IP+`````#AI0%``"`>"D`
+M=7V`>#3_='>)1"0$B30DZ/S____K:0^W0Q!F/84`=U\/M\`/MHP&N`0``(N^
+M>`4``(M#)"7___\`/>$!$`!T/X'Y_P```'0W9H'ZX0%U$`^V0R:#Z!$\`78E
+MD(UT)@!IP2@!``"-!`>`>$\`=1&)1"0$B30DZ/S___^0C70F`(/$$%M>7\.)
+M]HV\)P````"#[!R)7"00B70D%(E\)!B+="0@BUPD)`^W4Q!F@?J%``^'B@``
+M``^WP@^VC`:X!```@/G_='IF@_I_=QD/ML&+EG@%``!IP"@!``"+1!`L#[9`
+M!.L[9H'Z@0!W&0^VP8N6L`4``&G`%`T``(M$$`@/MD`$ZQL/ML&+EI0%``!I
+MP+````"+1!!4#[9`!(UT)@!F/?\`=!H/M\`/MKP&/@4``(GX//]T"0^VP68]
+M_P!U$(E<)`2)-"3H_/___^M^B?8/ME,G#[9#*`^V2RF`^0%T!8#Y"'5:BTM(
+MP>`(#[;2`=`E_P$``(N6S`4``#D,@G4_#[=)'HG*9L'J!0^WTH/A'[C^____
+MT\`A1)9<BT-(#[=`'HE$)`2)^@^VPFO`7(V$!D@!``")!"3H_/___XGVB5PD
+M!(DT).C\____BUPD$(MT)!2+?"08@\0<PXUT)@"#[`R)7"0$B70D"(M<)!"-
+M@_0```"^`````#F#]````'0=B00DZ/S___^)QHD$).C\____B1PDZ/S___^)
+M1DR)\(M<)`2+="0(@\0,PXUV`(/L'(E<)!")="04B7PD&(M\)""+1RR+,(DT
+M).C\____B<.%P'1KB30DZ/S___^)PH7`=1S&A[4````!B5PD!(DT).C\____
+MZTB-M"8`````QD,D``^W1QQFB4,0QD-H#XES&,=#(`````#'0S0`````BT((
+MB4,XQD,<)(E34,=#;`````")7"0$B30DZ/S___^+7"00BW0D%(M\)!B#Q!S#
+MZPV0D)"0D)"0D)"0D)"0@^P<B5PD$(ET)!2)?"08BWPD((MT)"2+1RR+&(D<
+M).C\____B<*%P'0]QD`D&\9`)0&)\(A"*`^W1QQFB4(0QD)H#XE:&,="(```
+M``#'0C0`````QT)L`````(E4)`2)'"3H_/___XM<)!"+="04BWPD&(/$',.)
+M]HV\)P````"#["R)7"0<B70D((E\)"2);"0HBUPD-(M$)#"+*(DL).C\____
+MB<:%P`^$H@```(DL).C\____B<>%P'43B70D!(DL).C\____Z8,```")]HU6
+M/(E4)!C&1B3AQD8E`<9&)@X/MT,<9HE&$&:#8SCWBU0D,(L"B488QT8@``@`
+M`(M'"(E&-(E^4,=&;/#!`0#'1"0$`````(M$)!B)!"3H_/___XM&((E$)`R+
+M1PR+5Q")1"0$B50D"(M4)!B)%"3H_/___XET)`2)+"3H_/___XM<)!R+="0@
+MBWPD)(ML)"B#Q"S#C70F`(V\)P````"#[!R)7"00B70D%(E\)!B+="0HBT0D
+M((L8B1PDZ/S___^)PH7`=&7&0"3AQD`E`8GPB$(FQD(G#XM,)"0/MT$<9HE"
+M$(E:&,="(`````#'0C0`````QT)L`````(E4)`2)'"3H_/___XGP/`%U$L<$
+M)`4```#H_/___^L0C70F`,<$)%##``#H_/___XM<)!"+="04BWPD&(/$',.-
+M="8`@^P<B5PD$(ET)!2)?"08BW0D((M<)"0/MU,09H'ZA0`/AXL````/M\(/
+MMHP&N`0``(#Y_W1[9H/Z?W<9#[;!BY9X!0``:<`H`0``BT00+`^V0`3K.V:!
+M^H$`=QD/ML&+EK`%``!IP!0-``"+1!`(#[9`!.L;#[;!BY:4!0``:<"P````
+MBT005`^V0`2-="8`//]T'0^VP`^VE`8^!0``@/K_=`V`^?]T"`^V0Q0\!G4_
+M@WM0`'0K@7L@``@``(GV=Q&-0U")1"0$B30DZ/S____K#XU#4(E$)`2)-"3H
+M_/___XE<)`2)-"3H_/___^MRB[YX!0``A,!T+<=$)`@!````#[;!:<`H`0``
+MC00'B40D!`^VPFO`7(V$!D@!``")!"3H_/___X-[4`!T*8%[(``(``!W$8U#
+M4(E$)`2)-"3H_/___^L/C4-0B40D!(DT).C\____B5PD!(DT).C\____BUPD
+M$(MT)!2+?"08@\0<PXVT)@````"-O"<`````@^PLB5PD'(ET)"")?"0DB6PD
+M*(M<)#"+;"0T#[=5$&:!^H4`#X<.`0``#[?"#[:,`[@$``"`^?\/A/H```!F
+M@_I_=QP/ML&+DW@%``!IP"@!``"+1!`L#[9`!.LZC78`9H'Z@0!W&0^VP8N3
+ML`4``&G`%`T``(M$$`@/MD`$ZQ</ML&+DY0%``!IP+````"+1!!4#[9`!#S_
+M#X29````#[;Y#[;`#[:T`SX%``")\#S_#X2!````9H'__P!T>H!]%`9T=(N3
+M>`4``(E4)!B`?28!=4S'!"0*````Z/S___^);"0$B1PDZ/S____'1"0(`@``
+M``^WQVG`*`$```-$)!B)1"0$B?(/ML)KP%R-A`-(`0``B00DZ/S____K&HGV
+MQP0D]`$``.C\____B6PD!(D<).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.-
+M="8`@^PLB5PD((ET)"2)?"0HBWPD,(M'+(LPB30DZ/S___^)PX7`=0K&A[4`
+M```!ZV20QD`D%<9`%:L/MT<<9HE#$(ES&,=$)!`!````QT0D#`$```")7"0(
+MB7PD!(DT).C\____A,!U&8E<)`2)-"3H_/___\:'M0````'K%XUT)@#'0VP`
+M````B5PD!(DT).C\____BUPD((MT)"2+?"0H@\0LPXVV`````(V\)P````"#
+M["R)7"0<B70D((E\)"2);"0HBUPD,(M#+(LHB2PDZ/S___^)QH7`=0S&@[4`
+M```!Z;@```")+"3H_/___XG'A<!U',:#M0````&)="0$B2PDZ/S____ID@``
+M`(UT)@#&1B0:QD8E",9&)@C&1B<`QD8H_\9&*0#&1A6K#[=#'&:)1A");AC'
+M1B#_````QT9D"````(M'"(E&-`7_````B48XQD8<)(E^4,=&;`````"-7CS'
+M1"0$`````(D<).C\____QT0D#/\```"+1PR+5Q")1"0$B50D"(D<).C\____
+MB70D!(DL).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.-M"8`````C;PG````
+M`(/L+(E<)!R)="0@B7PD)(EL)"B+;"0P#[9$)#2(1"07BT4LBSB)/"3H_/__
+M_XG#A<!U#<:%M0````'IN@```)")/"3H_/___XG&A<!U&,:%M0````&)7"0$
+MB3PDZ/S____IDP```(U#/(E$)!C&0R02@'PD%P!T#L9#)0'&0R:`QD,H0.L$
+MQD,H),9#%:L/MT4<9HE#$(E[&,=#(&````#'0V0(````BT8(B4,TB7-0QT-L
+M`````,=$)`0`````BT0D&(D$).C\____QT0D#&````"+1@R+5A")1"0$B50D
+M"(M$)!B)!"3H_/___XE<)`2)/"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#
+MC78`@^PLB5PD'(ET)"")?"0DB6PD*(M<)#"+0RR+*(DL).C\____B<:%P'4,
+MQH.U`````>FZ````B2PDZ/S___^)QX7`=1S&@[4````!B70D!(DL).C\____
+MZ90```"-="8`C48\B40D&,9&))[&1B40QD8Q(,9&%:L/MT,<9HE&$(EN&,=&
+M("````#'1F0(````BT<(B48TB7Y0@\`@B48XQD8<),=&;`````#&1F@/QT0D
+M!`````"+1"08B00DZ/S____'1"0,(````(M'#(M7$(E$)`2)5"0(BT0D&(D$
+M).C\____B70D!(DL).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.-M@````"-
+MOP````"#["R)7"0<B70D((E\)"2);"0HBUPD,(M#+(LHB2PDZ/S___^)QH7`
+M=0S&@[4````!Z:X```")+"3H_/___XG'A<!U',:#M0````&)="0$B2PDZ/S_
+M___IB````(UT)@"-1CR)1"08QD8D)<9&%:L/MT,<9HE&$(EN&,=&(`@```#'
+M1F0(````BT<(B48T@\`(B48XQD8<)(E^4,=&;`````#'1"0$`````(M$)!B)
+M!"3H_/___\=$)`P(````BT<,BU<0B40D!(E4)`B+1"08B00DZ/S___^)="0$
+MB2PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPY"-M"8`````@^PLB5PD'(ET
+M)"")?"0DB6PD*(M$)#B)1"04BU0D,(LZBX]X!0``B4PD&(M4)#0/MT(0#[:L
+M![@$``")/"3H_/___XG#BTPD-`^W<1Z)\8/A'[@!````T^")P8GP9L'H!0^W
+MP(5,AUP/A<D```"%VP^$P0```(GI#[;1:=(H`0```U0D&(M,)#0/MD$5#[:/
+MW@```-/@"?#&0R3AQD,E`<9#)@^(0R=FP>@(B$,H#[9$)!2(0RF+@J@```")
+M0RJ+@JP```")0RZ+3"0TB4M(QD,5J@^W0AQFB4,0BU0D,(L"B4,8QT,@````
+M`,=#-`````#'0VR0O0$`QT0D!`````"-0SR)!"3H_/___XE<)`2)/"3H_/__
+M_XM$)#0/MT@>B<AFP>@%#[?`@^$?N@$```#3X@E4AUR+7"0<BW0D((M\)"2+
+M;"0H@\0LPY"-="8`55=64X/L'`^V1"0TB$0D&XM4)#"+&F:#>U@`#X3^`0``
+MO0`````/M]6+@\P%``"+#)"%R0^$V`$``(MY)('G____`('_X0$0``^%D0``
+M`(-\)#@`#X6X`0``#[=1$&:!^H4`=V</M\(/MH0#N`0``#S_=%AF@_I_=QD/
+MML"+DW@%``!IP"@!``"+1!`L#[90!.L^9H'Z@0!W&0^VP(N3L`4``&G`%`T`
+M`(M$$`@/ME`$ZQX/ML"+DY0%``!IP+````"+1!!4#[90!.L%NO____^^````
+M`.FE````D(UT)@`/MU$09H'ZA0`/AX<````/M\(/MK0#N`0``(GP//]T=F:#
+M^G]W&0^VP(N3>`4``&G`*`$``(M$$"P/ME`$ZT%F@?J!`'<;B?(/ML*+D[`%
+M``!IP!0-``"+1!`(#[90!.L?B?(/ML*+DY0%``!IP+````"+1!!4#[90!(VV
+M`````('F_P```&G&*`$``(G&`[-X!0``ZPJZ_____[X`````BT0D,#A0!`^%
+MA0```(-\)#@`=`Z+5"0X#[="'&8[01!U<(!\)!L&=$Z!_^$!$`!T1@^V5B2)
+MT(/@!H/X!G4X]L(!=3.`OK0`````=2J!_^$!#P!T/0^V1"0;B$$4QT0D"`$`
+M``")3"0$BU0D,(D4).C\____ZQL/MD0D&XA!%`^WQ8E$)`2+5"0PB10DZ/S_
+M__^#Q0%F.6M8#X<'_O__@'PD&X$/A#4!``"+@^0```"-L^0````YQ@^$(0$`
+M`+H`````@\(!BP`YQG7W9H72#X0*`0``C7K_B30DZ/S___^)P8-\)#@`=">+
+M5"0X#[="'&8[01!T&8N#Z````(F+Z````(DQB4$$B0CIN0```)`/MU$09H'Z
+MA0!W9P^WP@^VA`.X!```//]T6&:#^G]W&0^VP(N3>`4``&G`*`$``(M$$"P/
+MMD`$ZSYF@?J!`'<9#[;`BY.P!0``:<`4#0``BT00"`^V0`3K'@^VP(N3E`4`
+M`&G`L````(M$$%0/MD`$ZP6X_____XM4)#`Z0@1U)8M!)"7___\`/>$!#P!T
+M%@^V1"0;B$$4B4PD!(D<).C\____ZQ.+@^@```")B^@```"),8E!!(D(C4?_
+M9H7_=`\[L^0```!T!XG'Z?G^__^#Q!Q;7E]=PXGVC;PG`````(/L'(E<)`R)
+M="00B7PD%(EL)!B+;"0@#[9\)"B+=0")-"3H_/___XG#A<!U$XM$)"S&@+4`
+M```!Z9````"-=@")-"3H_/___XG"A<!U&8E<)`2)-"3H_/___XM4)"S&@K4`
+M```!ZV;&0R3AQD,E`<9#)A")^8A+%8M,)"0/MD$S9HE#$(M%`(E#&,=#()``
+M``"-0@B)0S2)4U#&0`$2QD((0(GZB%`)QT-L`````,=$)`0`````C4,\B00D
+MZ/S___^)7"0$B30DZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<P^L-D)"0D)"0
+MD)"0D)"0D(/L'(E<)`R)="00B7PD%(EL)!B+;"0@BWPD*(M$)"R)1"0(BW4`
+MB30DZ/S___^)PX7`#X2(````B30DZ/S___^)PH7`='K&0R3AQD,E`<9#)A")
+M^8A+%8M,)"0/MD$S9HE#$(M%`(E#&,=#()````"-0@B)0S2)4U#&0`&1QD((
+M0(GZB%`)#[9,)`B(2`K'0VP`````QT0D!`````"-0SR)!"3H_/___XE<)`2)
+M-"3H_/___\<$)*"&`0#H_/___XM<)`R+="00BWPD%(ML)!B#Q!S#C;8`````
+MC;\`````@^P<B5PD#(ET)!")?"04B6PD&(M\)""+;"0HBS>)-"3H_/___XG#
+MA<!T<HDT).C\____B<*%P'1DQD,DX<9#)0'&0R80QD,5NXM,)"0/MD$S9HE#
+M$(L'B4,8QT,@D````(U""(E#-(E34,9``1#&0@A`B>J(4`G'0VP`````QT0D
+M!`````"-0SR)!"3H_/___XE<)`2)-"3H_/___XM<)`R+="00BWPD%(ML)!B#
+MQ!S#ZPV0D)"0D)"0D)"0D)"0@^P<B5PD$(ET)!2)?"08BWPD((LWB30DZ/S_
+M__^)PX7`=&V)-"3H_/___XG"A<!T7\9#).'&0R4!QD,F$,9#%;N+3"0D#[9!
+M,V:)0Q"+!XE#&,=#()````"-0@B)0S2)4U#&0`$`QD((0,=#;`````#'1"0$
+M`````(U#/(D$).C\____B5PD!(DT).C\____BUPD$(MT)!2+?"08@\0<PX/L
+M'(E<)`R)="00B7PD%(EL)!B+="0@C9[<"0``B1PDZ/S___^$P`^%N````(D<
+M).C\____B<.X`````(G!@+PP/@4``/]U"CA&,',0B$8PZPN#P0&#P`&#^`1U
+MWX#Y!`^$?P````^VP8B<!CX%```/M^MKQ5R-E`9(`0``N`````#&!!``@\`!
+M@_A<=?0/M]N)7"0(:_M<C90^8`$``(U:"(T$-XF8:`$``(F8;`$``(/"%(F0
+M=`$``(F0>`$``(V4/H`!``")D(`!``")D(0!``"(B$P!``!KQ5R-A`9(`0``
+MZP6X`````(M<)`R+="00BWPD%(ML)!B#Q!S#B?:#[!R)7"00B70D%(E\)!B+
+M="0@C9YD"0``B1PDZ/S___^$P`^%%P$``(D<).C\____B<*X`````(G#@+PP
+MN`0``/]U'`^VP&8YAMP```!S'6:)AMP```#K%(VT)@````"#PP&#P`$]@```
+M`'7+@/N`#X3*````#[;#B)0&N`0```^WPFGX*`$``(GX`X9X!0``B00DZ/S_
+M__^+EG@%```/ML-FB407'(N&>`4``,9$!R8`BX9X!0``QD0'/?^+AG@%``#&
+M1`<\_XN&>`4``,9$!S[_BX9X!0``QD0'0/^+AG@%``#&1`<__XN&>`4``,9$
+M!T'_BX9X!0``QH0'M@````"+AG@%``#&A`?;````_XDT).C\____BY9X!0``
+MB807Z````(!^-0%U"XN&>`4``(!,!R@!B?@#AG@%``#K!;@`````BUPD$(MT
+M)!2+?"08@\0<PXUT)@"-O"<`````4X/L"(M<)!"+5"04B=CHC>+__XN#1`4`
+M`(D$).C\____@\0(6\.-=@"-O"<`````@^P<B5PD$(ET)!2)?"08BW0D((V>
+MC`D``(D<).C\____A,`/A=T```")'"3H_/___XG"B?"[@O___XVV`````("X
+M.@4``/]U%SB>X````',@B)[@````ZQB-M"8`````@\,!@\`!@/N&#X27````
+MZ\^`^X8/A(P````/ML.(E`:X!```#[?":?BP````B?@#AI0%``")!"3H_/__
+M_XN6E`4```^VPV:)1!<D@'XU`74-BX:4!0``9L=$!S#__XN&E`4``,9$!R8`
+MBX:4!0``9L=$!S(``(N&E`4``&;'A`>0````___'1"0$`````(N&1`4``(D$
+M).C\____B?@#AI0%``#K!;@`````BUPD$(MT)!2+?"08@\0<PY"-="8`5E.#
+M[!2+="0@BT0D)`^W0"0/MIPPN`0``,:$,+@$``#_#[?;B5PD!(V&C`D``(D$
+M).C\____:=NP````B=@#AI0%``"`>#3_=`R)1"0$B30DZ/S____'1"0$````
+M`(N&1`4``(D$).C\____@\046U[#C;0F`````(V\)P````!3@^P(BUPD$(M$
+M)!0/ME`S#[:$&K@$``#&A!JX!```_P^WP(E$)`2-@[0)``")!"3H_/___\=$
+M)`0`````BX-$!0``B00DZ/S___^#Q`A;PU.#[`B+7"04@'LH_W0:C4-8B40D
+M!(M4)!"+0A2)!"3H_/___\9#*/^#Q`A;PXUV`%.#[`B+7"04@'M,_W0=C8/L
+M````B40D!(M4)!"+0A2)!"3H_/___\9#3/^#Q`A;PX/L'(E<)`R)="00B7PD
+M%(EL)!B+7"0@BVPD)`^W11P/MKP#N`0```^WQVGP*`$``(GP`X-X!0``!>@`
+M``")1"0$B1PDZ/S___\/MU4<BX23N`(``(7`=!B#>'``=1+'A).X`@``````
+M`(VT)@`````/MT4<QH0#N`0``/\/M\>)1"0$C8-D"0``B00DZ/S___^)\`.#
+M>`4``(!X0O]T#(E$)`2)'"3H_/___XEL)`2)'"3H_/___XN#>`4``,9$!B8`
+MBX-X!0``QD0&)P&+7"0,BW0D$(M\)!2+;"08@\0<P^L-D)"0D)"0D)"0D)"0
+MD(/L'(E<)`R)="00B7PD%(EL)!B+;"0@BW0D)&:!?B3A`0^%N0````^V1B:#
+MZ!$\`0^'J@````^W1A!F/84`#X=4`0``#[?`#[:$!;@$``"+E90%```\_P^$
+M.P$```^VP&G`L````(T<`H!K*0&->Q2)/"3H_/___XG".?!U0HE<)`2)+"3H
+M_/___SM[%`^$!0$``,=#6``2>@#'0V``````B5MDC4-8B40D!(M%%(D$).C\
+M____QD,H`.G9````D(M#%(E0!(D"B7H$B5,4BQ:+1@2)0@2)$.F[````C78`
+M#[=&$&8]A0`/AZH````/M\`/MI0%N`0``(N->`4``(M&)"7___\`/>$!$``/
+MA(8```"!^O\```!T?FG"*`$``(T<`8!K3P&->Q")/"3H_/___XG".?!U2(E<
+M)`2)+"3H_/___SM[$'1/QX/L`````!)Z`,>#]`````````")F_@```"-@^P`
+M``")1"0$BT44B00DZ/S____&0TP`ZQJ)]HM#$(E0!(D"B7H$B5,0BQ:+1@2)
+M0@2)$(M<)`R+="00BWPD%(ML)!B#Q!S#C70F`(/L'(E<)`R)="00B7PD%(EL
+M)!B+?"0@BVPD)`^W51Z)T&;!Z`4/M]@/M_*)\8/A'[C^____T\")P2%$GUQF
+M@?K_#W1)C02U``````.'S`4``(,X`'0WQP``````(8R?T`4``(ET)`2-ASP)
+M``")!"3H_/___XEL)`2)/"3H_/___XEL)`2)/"3H_/___XM<)`R+="00BWPD
+M%(ML)!B#Q!S#ZPV0D)"0D)"0D)"0D)"0@^P<B5PD$(ET)!2)?"08BWPD((MT
+M)"1F@7XDX0$/A9(````/MD8F@^@1/`$/AX,````/MT80NO\```!F/84`=PL/
+MM\`/MI0'N`0``&G"L````(G#`Y^4!0``@'LH_W4\#[96:+@(````A-)T`XT$
+M$@^VP&G`0$(/`(E#6,=#8`````")6V2-0UB)1"0$BT<4B00DZ/S____&0R@`
+MBU,8B7,8C4,4B0:)5@2),H!#*0'IGP````^W1A"Y_P```&8]A0!W"P^WP`^V
+MC`>X!```BY=X!0``BT8D)?___P`]X0$0`'1P:<$H`0``C1P"@'M,_W5-#[96
+M:+@(````A-)T`XT$$@^VP&G`0$(/`(F#[````,>#]`````````")F_@```"-
+M@^P```")1"0$BT<4B00DZ/S____&0TP`D(UT)@"+4Q2)<Q2-0Q")!HE6!(DR
+M@$-/`8M<)!"+="04BWPD&(/$',.-M@````"-OP````!55U93@^PLBT0D1`^W
+M4!!F@?J%``^''P,```^WPHM<)$`/MHP#N`0``+C_____@/G_=&)F@_I_=QT/
+MML&+7"1`BY-X!0``:<`H`0``BT00+`^V0`3K/V:!^H$`=QT/ML&+7"1`BY.P
+M!0``:<`4#0``BT00"`^V0`3K&P^VP8M<)$"+DY0%``!IP+````"+1!!4#[9`
+M!`^VP(M4)$`/MJP"/@4``&O%7(V$`D@!``")1"0@BY*P!0``#[;!:<`4#0``
+M`<*)5"0<BT0D1(M0-`^V0@$\$G0G/)$/A2H"``!KQ5RY`````(M4)$"`O`)2
+M`0````^$V@$``.EQ`0``:\5<`T0D0(N(2`$``(E,)"@/MEH)B%PD)@^V4AJ(
+M5"0GNP````"`N%(!````=&:_`````&OU7(M$)$"-K#"``0``D(DL).C\____
+MB<.+5"1`C006BY"$`0``B9B$`0``B2N)4P2)&HM,)!PY2S!U$P^V0TV+5"1$
+M.D(5=!B-M@````"#QP&)^8M$)$`XC#!2`0``=ZZ+5"1$BT)0A<!T$(E$)`2+
+M3"0HB0PDZ/S___^+1"1$B40D!(M4)"B)%"3H_/___P^V@Y8```"-4`&(DY8`
+M```\`W<X@'PD)P!U,<=$)!``````QT0D#`(```"+3"1$#[9!%8E$)`B+0S")
+M1"0$BUPD((D<).C\____ZS:-0@&(@Y8```"`^@)V*(!\)"<`=2'&0R<"QD,F
+M_X!C*/Z)7"0$BT0D*(D$).C\____Z1\!```/MD0D)XE$)`P/MD0D)HE$)`B+
+M5"0<B50D!(M,)"")#"3H_/___^GT````O@````!KW5R+1"1`C;P8@`$``(D\
+M).C\____B<&+5"1`C003BY"$`0``B8B$`0``B3F)402)"HM$)!PY03!U$@^V
+M04V+5"1$.D(5=!>0C70F`(/&`8GPBU0D0#B$&E(!``!WKP^V422)T(/@!H/X
+M!G4H]L(!=".)3"0,BUPD1`^V0Q6)1"0(BT$PB40D!(M$)"")!"3H_/___XM4
+M)$2+0E"%P'00B40D!(M,)$")#"3H_/___XM<)$2)7"0$BT0D0(D$).C\____
+MZRF+5"1`#[:J/08``&O%7(V$`D@!``")1"0@BY*P!0``N.P&#0#I7_W__X/$
+M+%M>7UW#C;8`````55=64X/L#(ML)""+?"0DBUPD*,9#)P'&0R8`B5PD",=$
+M)`0&````B3PDZ/S___^#>S``=!*+4PB+0PR)0@2)$(M#,(!H,`&`>T\`=!V-
+M=@")+"3H_/___\<$)`$```#H_/___X![3P!UYHN3Y````(72=!O'1"0(`0``
+M``^V@]D```")1"0$B10DZ/S___^+4S"%TG08QT0D"`$````/MD--B40D!(D4
+M).C\____BW,@A?8/A*````"#?G``#X6(````@WYT``^%?@```/9#*`1U'XDL
+M).C\____QT0D"`$```"+0R")1"0$B2PDZ/S___^+4R`/MD("B40D"`^V0@&)
+M1"0$QP0DK@$``.C\____BT,@B40D"(N%1`4``(E$)`3'!"0!````Z/S___^+
+M0R")1"0(BX5$!0``B40D!,<$)`8```#H_/___\=#(`````#'1F``````BU,T
+MA=)T#`^V0TW'1((\`````(L3BT,$B4($B1"`;PH!B5PD!(DL).C\____@'\%
+M_W1.@'\*`'0XNP````"-=SB-M@````")-"3H_/___XM7/(E'/(DPB5`$B0*`
+M>";_=0J#PP$X7PIV!^O;.%\*=Q#&1P7_B7PD!(DL).C\____@\0,6UY?7<.-
+MM"8`````C;PG`````%575E.#[`R+;"0HQD4G`<9%)@");"0(QT0D!`8```"+
+M1"0DB00DZ/S___^#?3``=!*+50B+10R)0@2)$(M%,(!H,`&`?4\`="6-M"8`
+M````BU0D((D4).C\____QP0D`0```.C\____@'U/`'7BBY7D````A=)T&\=$
+M)`@!````#[:%V0```(E$)`2)%"3H_/___XM5,(72=!C'1"0(`0````^V14V)
+M1"0$B10DZ/S___^+72"%VP^$00$``/9%*`1U:8M,)"")#"3H_/___\=$)`@!
+M````BT4@B40D!(M$)"")!"3H_/___XM5(`^V0@*)1"0(#[9"`8E$)`3'!"2N
+M`0``Z/S___^+12")1"0(BU0D((N"1`4``(E$)`3'!"0!````Z/S____K/0^V
+M0P*)1"0(#[9#`8E$)`3'!"2N`0``Z/S___^+12")1"0(BTPD((N!1`4``(E$
+M)`3'!"0!````Z/S___^+4W"%T@^$1`$```^W11R+3"0@QX2!N`(```````#'
+M0W``````QT0D"/____^)7"0$BT-XB00D_]+I$0$```^W11R+3"0@QX2!N`(`
+M``````#'0W0`````BT-XB00D_]+V12@"="&+12")1"0(BU0D((N"1`4``(E$
+M)`3'!"0&````Z/S____'12``````QT-@`````(M5-(72=`P/MD5-QT2"/```
+M``"+50"+102)0@2)$(M,)"0/ME$*@^H!B%$*BT4TA<!T!V:#>#("=6B$TG1D
+MO@````"+?"0D@\<XB3PDZ/S___^)PXM4)"2+0CR)6CR).XE#!(D8A=MT*_9#
+M*`)T)8M#((E$)`B+3"0@BX%$!0``B40D!,<$)`8```#H_/___X!C*/V#Q@&)
+M\(M4)"0X0@IWJ(EL)`2+3"0@B0PDZ/S___^#Q`Q;7E]=PXM3=(72#X7D_O__
+MZ0'___^0C;0F`````(/L+(E<)!R)="0@B7PD)(EL)"B+7"0PBT,LBRB)+"3H
+M_/___XG&A<`/A,P```")+"3H_/___XG'A<!U&,:#M0````&)="0$B2PDZ/S_
+M___II@```,9&)*"-5B6X`````,8$$`"#P`&#^`5U],9&*@#&1BL`QD8L`,9&
+M+8C&1BX`QD8O`,9&%:L/MT,<9HE&$(EN&,=&9`@```#'1B"(````BT<(B48T
+M!8@```")1CC&1APDB7Y0QT9L`````(U>/,=$)`0`````B1PDZ/S____'1"0,
+MB````(M'#(M7$(E$)`2)5"0(B1PDZ/S___^)="0$B2PDZ/S___^+7"0<BW0D
+M((M\)"2+;"0H@\0LPXGV5E.#[!2+="0@C9ZT"0``B1PDZ/S___^$P`^%\0``
+M`(D<).C\____B<*Y@/___X"^.`4``/]T$H"^.04``/\/A<P```"Y@?___SB.
+MWP```',&B([?````@/F"#X2P````#[;!B)0&N`0```^WPFG8%`T``(G:`Y:P
+M!0``N`````#&!!``@\`!/10-``!U\HG:`Y:P!0``C4(0B4(0B=H#EK`%``"-
+M0A")0A2)V@.6L`4``(U"&(E"&(G:`Y:P!0``C4(8B4(<B=H#EK`%``"-0BB)
+M0BB)V@.6L`4``(U"*(E"+(N&L`4``(A,`S/'1"0$`````(N&1`4``(D$).C\
+M____B=@#AK`%``#K"8UT)@"X`````(/$%%M>PY"-="8`4X/L"(M$)!"+F!P*
+M```%/`D``(D$).C\____B<$/M\#!X`:-%!B+1"04B1"X`````,8$$`"#P`&#
+M^$!U]`^WP8/$"%O#C70F`(V\)P````"#[`R+1"00C9`,`0``N0`````YD`P!
+M``!T"HD4).C\____B<&)R(/$#,.0D)"0D)`/MD0D"&G`=`0```5T10``BU0D
+M!(D"PXGVC;PG`````(M4)`@/MDPD#`^W1$IP@\`!9HE$2G`/ME("`=`/M\##
+MBU0D!+@!````C;0F`````("Z.S(```%T$H/``8'"I````(/X('7I9KC___/#
+MC78`5E.+="0,#[9,)!`/MEPD%(GRN`$````XBC@R``!U&#B:.3(``'40:<"D
+M````QH0&ES$```'K#H/``8'"I````(/X('726U[#D(VT)@````!55U93@^P(
+MBWPD(`^V1"0DB$0D!XML)!R+5"0HQ@+^#[9=!(A<)`.$VW17B>JY`````+X`
+M````N`````"-="8`.;KD1P``=2B)\SI<)`=U%FG`=`0```^VA`7810``BU0D
+M*(@"ZQR#Q@&-M"8`````@\$!@\`!@<)T!```.DPD`W6^@\0(6UY?7<.-M@``
+M``!55U93@^P<BVPD-`^V7"0\BWPD,(!\)#@!=!@/MG<$NP````")\(3`#X0C
+M`0``Z?@```#&1"0;`(-\)$``#X33````BU0D0(E4)!0/ME<$QD0D&P"$TG0K
+MB?C&1"0;`+D`````.:CD1P``=0<XV703@\$!@$0D&P$%=`0``#A4)!MUX0^V
+M;"0;:=UT!```C80?=$4``,=$)`AD````B40D!(M$)!2)!"3H_/___X"\'W1%
+M````=%^^`````(G=C90?<$4``(E4)!"-M"8`````B?(/ML+!X`2+5"04C5P"
+M8(U+!(V$*.!'``"-!`>-4`B+0`B)0P2+0@2)002+0@B)00B+0@R)00R#Q@&)
+M\(M4)!`X0@1WN@^V1"0;:<!T!```#[:$!W1%``#K*8GZN0````"[`````#FJ
+MY$<```^4P`'#@\$!@<)T!```B?`XP77F#[;#@\0<6UY?7<.-="8`55=64X/L
+M!`^V1"0DB$0D`P^W7"0H9HD<)(M\)!B^`````(GU:=8X#```BT0D'#E$.A1U
+M<(U,%Q2X`````(UV`(G##[91'(32=`:`^O!U2)!IQ3@,``"-%%N-%-"-##J+
+M7"0<B5D<BT0D((E!((U!$`^W'"1FB5@6#[9<)`.(6!2)PHM<)"R+`XE"&(M#
+M!(E"',9!,/_K#8/``8/!&#V"````=9R#Q@&#_@0/A7+___^#Q`1;7E]=PY"-
+MM"8`````55=64X/L#(ML)"2+="0@@'X$`'1)OP````"-M@````")^`^VV&G#
+M=`0``("\!MA%``#]=!_'1"0("````(EL)`2-A`;010``B00DZ/S___^$P'4/
+M@\<!B?@X1@1WPKO_````B=B#Q`Q;7E]=PXUV`%.#[`B+7"00BT0D%(E$)`2)
+M'"3H_/___[H)````//]T$0^VP&G`=`0```^VE`-Z10``B="#Q`A;PXVT)@``
+M``!55U93@^P,BWPD((ML)"@/MG0D+`^W7"0PB?F-E_0P``"X`````,8$$`"#
+MP`$]D````'7RQH'U,```$\:!]#```$`/ML>(@?HP``"(F?LP``")\(B!_3``
+M`,>!D#$``+#W`0")N8PQ``"+15R)@80Q``"+16")@8@Q``"-@?0P``")1"0$
+MBT0D)(D$).C\____@\0,6UY?7<.-M"8`````55=64X/L3`^V1"1LB$0D/P^W
+M5"1P9HE4)""+5"1@B=>X`0```(G%B<:`NCLR```!#X7<````:<"D`````?B-
+MD)`Q``#&0@<`B;B,,0``#[9*!FG!I````(V4!_0P``"X`````,8$$`"#P`$]
+MD````'7R:=FD````C0P[C9'P,```QD(%D,9"!$`/MT0D(`^VQ(E$)!R(0@H/
+MMD0D((B!^S````^V3"0_B$H-BTPD=(L!B4(4BT$$B4(8:=:D````C00ZQX"0
+M,0``L/<!`(M,)&")B(PQ``"-E!>`,0``BTPD:(M!7(E"!(M!8(E""(GJ#[;"
+M:<"D````C80']#```(E$)`2+3"1DB0PDZ/S____K%(/``8'"I````(/X(`^%
+M`?___[`!@\1,6UY?7<.)]E575E.#[`P/MFPD*`^V?"0LBTPD((G.N`$```"-
+M="8`B<*`N3LR```!#X7"````:<"D````C80&D#$``(GIB$@$B?N(6`7&0`<`
+M#[98!FG#I````(V,!O0P``"X`````,8$"`"#P`$]D````'7R:<.D````C80&
+M\#```,9`!1#&0`1`B?F(2`UITJ0````/MHP6EC$``&G)I````(T$,<>`D#$`
+M`+#W`0"+7"0@B9B,,0``C9P6@#$``(GJ#[;":<!T!```C90&P$4``(M"$(E#
+M!(M"%(E#"(V$#O0P``")1"0$BTPD)(D,).C\____ZQ2#P`&!P:0```"#^"`/
+MA1W___^P`8/$#%M>7UW#C78`5E.#[!2+="0@#[9$)"B)\\:&ES$```"-CO0P
+M``"Z`````,8$"@"#P@&!^I````!U\<:#]3````'&@_0P``!`QX.0,0``L/<!
+M`(FSC#$```^VP&G`=`0``(V4`\!%``"+0A")@X0Q``"+0A2)@X@Q``"-@_0P
+M``")1"0$BT0D)(D$).C\____@\046U[#C78`5E.#[!2+="0@#[9$)"B)\\:&
+MES$```"-CO0P``"Z`````,8$"@"#P@&!^I````!U\<:#]3````#&@_0P``!`
+MQX.0,0``L/<!`(FSC#$```^VP&G`=`0``(V4`\!%``"+0A")@X0Q``"+0A2)
+M@X@Q``"-@_0P``")1"0$BT0D)(D$).C\____@\046U[#C78`55=64X/L3`^V
+M?"1H#[94)&P/MD0D<(A$)">+;"1@B?D/MLF)3"0H:<%T!```@+P%V$4``/T/
+MA#D)``"`^A`/A+D"``"`^A!W'(32D(UT)@`/A*$```"`^@$/A14)``"0Z0L!
+M``"`^N)T&X#Z_XUV`'0I@/J0#X7Y"```D(UT)@#I-@<``+D`````@'T$`(GV
+M#X4Z"```Z5T(``!I1"0H=`0``,:$!=A%``#_@+V7,0```74MBUPD*(E<)`B+
+M="1DB70D!(M\)&")/"3H_/___X7`#X6<"```@$4&`>F3"```BT0D*,9$!0<!
+MBU0D9(E4A0SI?0@``("]ES$```%U6HV-]#```&E$)"AT!````>@/ME$)B)!V
+M10``!=!%```/ME$*@^(!B%`)QD`(`(M,)"B)3"0(BUPD9(E<)`2+="1@B30D
+MZ/S___^%P`^%(P@``(!%!@'I&@@``(M\)"C&1#T'`8M$)&2)1+T,Z00(``!I
+M="0H=`0``(T\+@^VA28Q``"(A\9%```/MX4D,0``9HF$-<1%``"-E#6P10``
+MBX4<,0``B4($BX4@,0``B4((C90U@$4``(N%`#$``(E"!(N%!#$``(E""(V<
+M-9!%``"-2P2-E0@Q``"+A0@Q``")0P2+0@2)002+0@B)00B+0@R)00R+A1@Q
+M``")A#6L10``QH?810```8!]!A\/A&('``"[`````&E$)"AT!````>B-L'!%
+M``"-N,!%``#K5)`/ML.)1"0,BU0D*(E4)`B+3"1DB4PD!(M$)&")!"3H_/__
+M_X7`=!%I1"0H=`0``(B<!<=%``#K((/#`8!%!@$X7@8/E,"#Z`$AV(A'!X!]
+M!A]T!3I>!G*HQH67,0```0^V302$R0^$V08``+H`````@'T'`70,ZT0/MM"`
+M?!4'`74_QD05!__'1"04`````,=$)!``````QT0D#/\```")5"0(BT25#(E$
+M)`2+5"1@B10DZ/S____IB`8``+@`````@\`!.,AUL.EW!@``BTPD=(E,)#"#
+MP1B)3"0LC4PD0(M<)#"+0QB)1"1`BW0D+(M&!(E$)$1I1"0H=`0``(TT*(V6
+MT$4``,9""!#V0PQP#X1E`P``BX;<10``A<`/A(@````/MEH*QT0D"`@```")
+M3"0$@\!<B00DZ/S___^$P'5IBT0D,/9`#P]T7XN&W$4``(7`=%6)QH!^90!T
+M30^VVXE<)`B)="0$B2PDZ/S___^+5"0LB50D%`^WP(E$)!")7"0,B70D"(M,
+M)&2)3"0$BUPD8(D<).C\____#[9>9HM&:(7`=`2)QNNMBW0D,`^V1@^H#0^$
+M_0```&E4)"AT!```#[:,%71%``"`^1\/A^0```"H"'02#[;!P>`$`=#&A`7H
+M1P``!NL8#[;!P>`$:50D*'0$```!T,:$!>A'```'#[;QB?+!X@1I7"0H=`0`
+M``':C8P5X$<``,9!"0"+?"0P#[9'#XA!"XM$)$")01"+1"1$B4$4#[9'"8A!
+M"@^V1PV#X`\/MI0=>D4``#C0=@*)T(G"@^(/#[9!#(/@\`G0B$$,B?#!X`1I
+M5"0H=`0```'0C8P%X$<``(M<)#`/MD,I@^`/#[:4%7I%```XT'8"B=#!X`0/
+MME$,@^(/"<*(40QI1"0H=`0``("$!71%```!Z<(!``"H`@^$N@$``(U$)$")
+M1"0$B2PDZ/S___^)PCS_#X5?`0``#[9-!(3)=#@/MH7810``//]T+;H`````
+M//UU&^LB#[;":<!T!```#[:$!=A%```\_W02//UT#H/"`3C*=>#K!;H`````
+M#[;":<!T!```C8P%=$4``+@`````Q@0(`(/``8/X9'7T#[;2B50D-&G2=`0`
+M`(T<*HGY#[;!:<!T!```C80%=$4``(F#W$4``(V,%<!%``!I="0H=`0``(V4
+M-<!%``"+0A")00B+0A2)00R+?"1DB;OD1P```>Z+AN!%``")@^!%``#&@]A%
+M``#_C8-P10``#[9("XM\)#`/ME<)B)0+?$4``(!`"P$/MHYZ10``#[97#8/B
+M#SC*=@*)RHA0"FE4)#1T!```C8P5P$4``(M$)$")01"+1"1$B4$4`>J+3"0P
+M#[9!#XB"=T4```^V7"0GB)K:10``#[9%!3I%!'4$QD4%`(!%!0&+="0TQD0U
+M!P&+?"1DB7RU#.M!:40D*'0$```/MM)IRG0$``"-E`UT10``.90%W$4``'0@
+MC1PIC8-P10``#[9("XMT)#`/ME8)B)0+?$4``(!`"P&+?"0P#[9'"8E$)`B+
+M1"0HB40D!(DL).C\____:40D*'0$``"`O`7'10````^$G````(!]!A]U<.F-
+M`@``QH;810``$`^V0P>)1"0,BU0D*(E4)`B+3"1DB4PD!(M$)&")!"3H_/__
+M_X7`#X5:`@``@$4&`0^V2P</ML&#P`$/MI9V10``.=!U#<9#!P#I.`(``(UT
+M)@"-00&(0P>`?08?#X0D`@``ZQ%I1"0H=`0``(TT*(V>P$4```^V0P<ZAG9%
+M```/@G3____I_`$``(!]!@`/A?(!``#'1"04`````,=$)!``````QT0D#)``
+M``"+5"0HB50D"(M,)&2)3"0$BUPD8(D<).C\____Z;D!``"_`````&G'.`P`
+M`(MT)&0Y="@4=7:-7`4PO@````")1"0@C78`@#O_=5.`?08?#X2%`0``C01V
+MBU0D((U$PA"-1`48B40D%`^W0_:)1"00#[9#](E$)`R+0_")1"0(BTPD9(E,
+M)`2+1"1@B00DZ/S___^%P'4'@$4&`<8#\(/&`8/#&('^@@```'6:@\<!@_\$
+M#X5N____@'T&``^%&`$```^V302$R0^$V````+H`````@'T'`70,ZT0/MM"`
+M?!4'`75!QD05!__'1"04`````,=$)!``````QT0D#/\```")5"0(BT25#(E$
+M)`2+5"1@B10DZ/S____INP```+@`````B?:#P`$XR'6NZW>-M"8`````#[;!
+M:<!T!```C90%T$4```^V0@@\_70(//]T!,9""/Z#P0$X301WV&E$)"AT!```
+MBYP%X$4``+\`````C70F`(!\+Q@!=1G&1"\8`(M$+Q2)1"0$BTPD8(D,)/_3
+MC78`@<<X#```@?_@,```=#;KT,=$)!0`````QT0D$`````#'1"0,X@```(M<
+M)"B)7"0(BW0D9(ET)`2+?"1@B3PDZ/S___^#Q$Q;7E]=PXUT)@"#["R)7"0@
+MB70D)(E\)"B+="0TBYZ8````@'L&``^$A`$``(V&D````(E$)`2)'"3H_/__
+M_XG!//\/A&@!``")]P^V1@$\`71L/`%R&#P0#X2L````/)`/A4H!``"-=@#I
+M^@```("[ES$```"-="8`#X4Q`0``QH.7,0```8!K!@''1"04`````,=$)!``
+M````QT0D#``````/ML&)1"0(BT0D,(E$)`2)'"3H_/___^GR````@+N7,0``
+M``^%Y0```,:#ES$```&`:P8!QT0D%`````#'1"00`````,=$)`P!````#[;!
+MB40D"(M$)#")1"0$B1PDZ/S____II@```+H`````.HP:.#(``'41#[:$&CDR
+M```Z1PET$HUT)@"!PJ0```"!^MP3``!UV(!K!@&)?"04#[9'"8E$)!#'1"0,
+M$`````^VP8E$)`B+1"0PB40D!(D<).C\____ZT@/MH:B````:<"D````QH0#
+MES$```&`:P8!QT0D%`````#'1"00`````,=$)`R0````#[;!B40D"(M$)#")
+M1"0$B1PDZ/S___^+7"0@BW0D)(M\)"B#Q"S#B?:-O"<`````5E.+5"00#[9T
+M)!2+7"0,A=)T#XG9B=#&`0"#P0&#Z`%U]8D3@>IT10``P>H"N%FV^7+WXL'J
+M!XA3!(GP.-!S`XA#!(![!`!T);H`````B?8/ML+&1`,'_VG`=`0``,:$`]A%
+M``#]@\(!.%,$=^+&0P8`QD,%`(G8N@````"-=@#&@)<Q```!B)"6,0``@\(!
+M!:0```"#^B!UYEM>PXUV`%=64XM\)!2+3"00@'D$``^$@0```+L`````#[;S
+M:<9T!```.;P!Y$<``'5BN``````XG`@X,@``=0C&A`@[,@```06D````/=P3
+M``!UXVG&=`0``,>$`>1'````````C90!=$4``+@`````D(UT)@#&!!``@\`!
+M@_AD=?1IQG0$``#&A`'810``_8!I!0&#PP$X601WA(G+O@`````Y>Q1U+<=#
+M%`````#&0Q@`:<8X#```C40!%+H`````C70F`,9`'`"#P@&#P!B`^H)U\8/&
+M`8'#.`P``(/^!'7`6UY?P^L-D)"0D)"0D)"0D)"0D%575E.#[!P/MD0D/(A$
+M)!J+7"0P#[9#!3I#!'4$QD,%``^V4P6(5"0;B=V)V+D`````B<Z)SXM0%#M4
+M)#1U2FG!.`P``,9$`Q@!#[93!,9$)!L`A-)T6\9$)!L`BWPD-#F]Y$<``'4.
+M#[:%V$4``(/``SP!=CR`1"0;`8'%=`0``#A4)!MT*^O3A=)U%6G'.`P```'8
+MBU0D-(E0%,9`&`'K$(/&`8/!`04X#```@_D$=8")\@^VPFG`.`P``(U$`QRZ
+M`````,8$`@"#P@&!^@(,``!U\0^V="0;BWPD-(E\LPQIQG0$``"-E`-T10``
+MN`````#&!!``@\`!@_AD=?1IQG0$``"-E`/D10``N`````#&!!``@\`!/0`"
+M``!U\FG.=`0``(T4&8M$)#2)@N1'``"+1"1`B8+@10``QH+810``_\>"W$4`
+M``````"-C`O`10``BWPD.(L'B4$0BT<$B4$4#[9$)!J(@GI%``#'1"04````
+M`,=$)!``````QT0D#/\```")="0(BU0D-(E4)`2+?"0PB3PDZ/S___^`0P4!
+M@\0<6UY?7<.0D)"0D%93BU0D#(L"BS`/ME@KA-MT-P^V4@FY`````/;"`70*
+MZR>)T-/XJ`%U!X/!`3C9=?&`^0-V&`^VP8V$AM`!``"+`*,`````ZQ:Y````
+M``^VP8V$AM`!``"+`*,`````P>@4@^`!6U[#D(VT)@````!55U93@^P$BT0D
+M&(L0#[9Z*[T*````B?F$R71)#[9P";L`````O0H```"Y`````)")\-/XJ`%T
+M'@^V@KX+``"#X`.#P`B(1"0#B>@Z1"0#=@4/MFPD`X/#`8/!`8/"1(GX.,-U
+MRXGJ#[;"@\0$6UY?7<.-M"8`````C;PG`````%575E.#[`2+1"08BQ`/MGHK
+MO0@```")^83)=$D/MG`)NP````"]"````+D`````D(GPT_BH`70>#[:"O@L`
+M`(/@`X/`"(A$)`.)Z#I$)`-S!0^V;"0#@\,!@\$!@\)$B?@XPW7+B>H/ML*#
+MQ`1;7E]=PXVT)@````"-O"<`````4XM<)`@/M@/`Z`2)PH/B!P^V2P+VP01T
+M`X#.`@^V0P.H!'0&@<H```(`]L$(=`.`S@BH"'0&@<H```@`]L$"=`.`S@2H
+M`G0&@<H```0`#[9#%,'@&`G06\.-M"8`````@^P$BT0D"(D$).C\____@\0$
+MPXVV`````(V\)P````"+3"0$BX%8!0``)?___P"Z`````#U0`9,`=14/MH%;
+M!0``P.@$/`P/E,`/MM"-=@")T,.-M@````"-O"<`````4XG#A=)^0`^V"(3)
+M=`6`^2!U+;@`````ZQ:-M@`````/M@P8A,ET"(#Y('43C78`@\`!.=!UZ>L.
+MC;0F`````+@`````ZP6X`0```%N-=@##ZPV0D)"0D)"0D)"0D)"04XM<)`@/
+MMD,##[93`L'B"`G0P>`0#[9+`0^V$\'B"`G1"<A;PXUT)@"-O"<`````5U93
+MB<:)TXG/A<ET'KD`````#[86#[9&`8@#B%,!@\,"@\8"@\$!.?EUYUM>7\.0
+M@^P<B5PD$(ET)!2)?"08BW0D((M\)"0/MT<0NO\```!F/84`=PL/M\`/MI0&
+MN`0```^WTFG2L`````.6E`4``(N>0`H```^V0C3!X`B-A`-,"```BPB)#0``
+M``"!X?\````/MD(TP>`(C9P#1`@``(L#HP````#!X`@)R(F"H````&;'@IP`
+M`````(E\)`2)-"3H_/___XM<)!"+="04BWPD&(/$',.)]HV\)P````"#[!R)
+M7"0,B70D$(E\)!2);"08BVPD(`^V?"0DBW4`B?@\`W8P#[;8P>,#C80>,`(`
+M`,<`#````,<$)!`G``#H_/___XV$'C0"``"+,(DU`````.LPB?@/MMC!XP.-
+MA#-0`@``QP`,````QP0D$"<``.C\____C9PS5`(``(LSB34`````B?@/MLB)
+MR,'@!HT$B(V4!9`+```/MEH-@^/\B%H-B?`E```_`#T``!``=0^)V(/(`HA"
+M#>L9D(UT)@")R,'@!HT4B(G8@\@!B(05G0L``(M<)`R+="00BWPD%(ML)!B#
+MQ!S#D(VT)@````!55U93@^P<BT0D-(M4)#"+$HE4)!B+$L9`)0#&0"0%QD`G
+M!HM,)#")2"RY`````+T`````C8(``@``B40D%('"!`(``(E4)!#K%XVV````
+M`(M4)#`/MD()T_BH`74,@\$!BT0D&#I(*W+F@/D#=G$/MMG!XP.+?"04`=_'
+M!RP```#'!"00)P``Z/S___\#7"00BS.)-0````#'!R0```#'!"00)P``Z/S_
+M__^+`Z,`````P>`(@>;_````"<;'!R````#'!"00)P``Z/S___^+&XD=````
+M`.MOC;0F``````^VV<'C`XM\)!0!W\<'+````,<$)!`G``#H_/___P-<)!"+
+M,XDU`````,<')````,<$)!`G``#H_/___XL#HP````#!X`B!YO\````)QL<'
+M(````,<$)!`G``#H_/___XL;B1T`````@?X!`6F6=1>+5"0P@$H(!HG8P>@0
+M/%`/E,`/ML#K1H'^`0$``'41B=C!Z!`\4`^4P`^VP.LOB?;'!"2($P``Z/S_
+M__^#Q0&)Z8#Y!'<*N0````#IP?[__XG8P>@0/%`/E,`/ML"#Q!Q;7E]=PXUT
+M)@"-O"<`````55=64X/L#(MT)""+;"0DBT94BSAF@[Z<`````'0RB>O'!"3H
+M`P``Z/S___^%[70%@_L!=AN)/"3H_/___V:#OIP`````=`F#ZP+KU(UT)@"#
+MQ`Q;7E]=PY"-M"8`````@^P<B5PD#(ET)!")?"04B6PD&(M<)"P/MFPD)`^W
+M?"0H#[9$)#"(1"0+BU0D((M"5(LPB30DZ/S___^)PL9`).'&0"4!QD`F$K@/
+M````B>F$R74(BTPD(`^V02N(0B>)^(A"*(GY#[;%B$(I#[;'B$(JB=C!Z!"(
+M0BN)V,'H&(A"+(A:+8M,)"`/MT$D9HE"$(ER&,="(`````#'0C0`````N```
+M``"`?"0+`'4%N`````")0FR)5"0$B30DZ/S___^+7"0,BW0D$(M\)!2+;"08
+M@\0<PXUV`(V\)P````"#[!R)7"0,B70D$(E\)!2);"08BUPD+`^V;"0D#[=\
+M)"B+5"0@BT)4BS")-"3H_/___XG"QD`DX<9`)0'&0"82N`\```")Z83)=0B+
+M3"0@#[9!*XA")XGXB$(HB?D/ML6(0BD/ML>(0BJ)V,'H$(A"*XG8P>@8B$(L
+MB%HMBTPD(`^W021FB4(0B7(8QT(@`````,="-`````#'0FP`````B50D!(DT
+M).C\____BUPD#(MT)!"+?"04BVPD&(/$',-55U93@^P<BWPD,`^V1"0TB$0D
+M&P^W;"0XA?\/A.X```"+-X7V#X3D````#[9>*X7;?D.+1U0/ME`)N0````#V
+MP@%T"NLPB=#3^*@!=0>#P0$YV77Q@_D#?B&+!@70`0``C02(BP"C`````,'H
+M%(/P`8/@`>L?N0````"+!@70`0``C02(BP"C`````,'H%(/P`8/@`83`=7:`
+MOZP`````=0:`?R8`=6</MT<D@+P&N`0``/]T6<9')B5FQX><`````0`/M\4/
+MME0D&\=$)!`!````BTPD/(E,)`R)1"0(B50D!(D\).C\____QT0D!`4```")
+M/"3H_/___\9')@!F@[^<``````^4P`^VP.L%N`````"#Q!Q;7E]=PXUT)@"#
+M[!R)7"0,B70D$(E\)!2);"08BWPD(`^V;"0D#[=<)"B+1U2+,(DT).C\____
+MB<+&0"3AQD`E`<9`)A&X#P```(GIA,EU!`^V1RN(0B>(6B@/ML>(0BD/MT<D
+M9HE"$(ER&,="(`````#'0C0`````QT)L`````(E4)`2)-"3H_/___XM<)`R+
+M="00BWPD%(ML)!B#Q!S#B?:-O"<`````55=64X/L'(M\)#`/MD0D-(A$)!L/
+MMVPD.(7_#X3S````BS>%]@^$Z0````^V7BN%VWY#BT=4#[90";D`````]L(!
+M=`KK,(G0T_BH`74'@\$!.<MU\8/Y`WXABP8%T`$``(T$B(L`HP````#!Z!2#
+M\`&#X`'K'[D`````BP8%T`$``(T$B(L`HP````#!Z!2#\`&#X`&$P'5[@+^L
+M`````'4&@'\F`'5L#[=')("\!K@$``#_=%[&1R8E9L>'G`````$`#[?%#[94
+M)!O'1"0,`0```(E$)`B)5"0$B3PDZ/S____'1"0$!0```(D\).C\____QD<F
+M`&:#OYP`````=1.+AZ````"+5"0\B0*X`0```.L%N`````"#Q!Q;7E]=P^L-
+MD)"0D)"0D)"0D)"0D(/L'(E<)`R)="00B7PD%(EL)!B+?"0@#[9L)"0/MUPD
+M*`^V1"0LB$0D"XM'5(LPB30DZ/S___^)PL9`).'&0"4!QD`F$;@/````B>F$
+MR74$#[9'*XA")XA:*`^VQXA"*0^W1R1FB4(0B7(8QT(@`````,="-`````"X
+M`````(!\)`L`=06X`````(E";(E4)`2)-"3H_/___XM<)`R+="00BWPD%(ML
+M)!B#Q!S#C78`@^P<B5PD#(ET)!")?"04B6PD&(ML)"0/MG0D*`^V?"0LBT0D
+M((L8B1PDZ/S___^)PH7`=1#&A;4````!QD4F`^E_````QD`DX<9`)0&)\#P!
+M&<#WT(/``HA")HGXA,!U/X-]-`!T!`^V14V(0B</MT4<9HE"$(E:&,="(```
+M``#'0C0`````N*`\`@")0FR)5"0$B1PDZ/S____K)XUV`,9")P\/MT4<9HE"
+M$(E:&,="(`````#'0C0`````N`````#KR(M<)`R+="00BWPD%(ML)!B#Q!S#
+MD(VT)@````!55U93@^PLBVPD2(M$)$"+$(M$)$3!X`.-O!```@``C;00!`(`
+M`+L<`0``D(UT)@"#?"1$`W89B1_'!"00)P``Z/S___^+!J,`````ZQ>)]HD?
+MQP0D$"<``.C\____BP:C`````(F$'/3^__^#PP2!^S@!``!UN8M$)!")10"+
+M1"04B44$BT0D&(E%"(M$)!R)10R+1"0@B440BT0D)(E%%(M$)"B)11B#Q"Q;
+M7E]=PU575E.#["R+;"1(BT0D0(L0BT0D1,'@`XV\$``"``"-M!`$`@``NP`!
+M``"0C70F`(-\)$0#=AF)'\<$)!`G``#H_/___XL&HP````#K%XGVB1_'!"00
+M)P``Z/S___^+!J,`````B80<$/___X/#!('['`$``'6YBT0D$(E%`(M$)!2)
+M102+1"08B44(BT0D'(E%#(M$)"")11"+1"0DB444BT0D*(E%&(/$+%M>7UW#
+M55=64X/L/(M,)%2(3"03BT0D4(L`B40D&`^V^8GXP>`&C02X`T0D4(V0D`L`
+M`(A*#(M,)%")B)@+``#&0@X`B7PD!(D,).C\____C70D'(GPB?+&``"#P`&)
+MTXUL)#PYZ'7P#[9$)!.)1"04B50D"(E$)`2+5"10B10DZ/S___^)'"3H_/__
+M_XE$)`R-#+T`````B?K!X@:-%!&+1"10C1P"BT0D#(F#I`L``(M$)%"-E!"@
+M"P``BT0D*(E""(M$)"R)0@R`?"03`W8IBU0D&(V$"M`!``"+`*,`````B8.\
+M"P``C83Z@`$``(L0B14`````ZS^-%+T`````BTPD&(V$$=`!``"+"(D-````
+M`(GXP>`&`<*+1"10B8P0O`L``(M4)!B-A/J``0``BQ")%0````")^,'@!HT$
+MN`-$)%")D,`+``#V@+X+```0#X0]`0``]H"="P```G1<C70F`,8&`(/&`3GN
+M=?:-7"0<B5PD"(M,)!2)3"0$BT0D4(D$).C\____B1PDZ/S___^)^L'B!HT4
+MNHM,)%")A!&P"P``C901H`L``(M$)"B)0A2+1"0LB4(8ZQ>)^,'@!HT$N(M4
+M)%#'A`*P"P```0`"`(!\)!,#=CF-'/T`````BTPD&(V$"S`"``#'`!@```#'
+M!"00)P``Z/S___^+1"08C9P#-`(``(L3B14`````ZS>-'/T`````BU0D&(V$
+M$U`"``#'`!@```#'!"00)P``Z/S___^+3"08C9P+5`(``(L3B14`````B?C!
+MX`:-!+B+3"10]X0!O`L``````P!U"('B____W^L&@<H````@@'PD$P-V#XM,
+M)!B-A/DT`@``B1#K#8M,)!B-A/E4`@``B1"#Q#Q;7E]=PY"-M"8`````55=6
+M4X/L#(M\)""+;"0DB6PD"`^W10!FA<!Y"R4`'P``P?@(B$<EC4=0C4T4BU44
+MB5=0BU$$B5`$BU$(B5`(BU$,B5`,BU$0B5`0C;>,````BU4NB9>,````BU4R
+MB58$C5]DC4TVBU4VB5=DBU$$B5,$BU$(B5,(BU$,B5,,BU$0B5,0BU$4B5,4
+MBU$8B5,8BU$<B5,<BU$@B5,@BU$DB5,DN0H```")PNA"\?__N00```")\HGP
+MZ#3Q__^Y%````(G:B=CH)O'__V;'1S@``&;'1SH``(M$)`AF@[BR`0```0^4
+MPL'B`P^V1RB#X/<)T(A'*/:%IP````1T!F;'1S@!`/:%I`````%T)&:#3S@"
+M]H6J`````70%9H-/.@'VA:@````!=`AF@4\X``&)]O:%I````"!T%V:#3S@$
+M]H6J````('0)9H-/.@*-="8`]H6D````0'079H%/.(``]H6J````0'0(9H-/
+M.@B-=@#&1TX"]H69`````70S#[='.*@!=`R#R`AFB4<X9H-/.A`/MH66````
+M@^`?@\`!B$=./"!U"\9'3A^-M"8`````]H68````"'0&9H%/.``"]H68````
+M!'0%9H-/."#VA9@````"=`5F@T\X$/:%J````"!T#O:%K@```"!T!6:#3SA`
+M]D<X`708BX7(````BY7,````B4=$B5=(ZQ&-="8`BU5XB5=$QT=(`````(-'
+M1/^#5TC_]D5J`G09#[>%@````*@/=`YF@_@"&<"#P`2(1SSK!,9'/`+&1SW_
+M#[=5?@^WPJ@$=`G&1ST"ZQF-=@"H`G0&QD<]`>L,]L(!C78`=`3&1ST`QD<^
+M__9%:@1T';D`````#[>%L````-/XJ`%T`XA//H/!`8/Y!W7HQT0D!``"``")
+M+"3H_/___XF'F````(M$)`CV@*8````@="`/MX"L````@^`@@_@!&<"#P`*(
+MAR0!``#K#8VV`````,:')`$```"X`0```(/$#%M>7UW#C;8`````C;\`````
+M@^P<B5PD#(ET)!")?"04B6PD&(ML)""+?0"[@/___^L%@/N%=TH/ML,/MK0'
+MN`0``(GP//]T.0^VP&G`%`T```.'L`4``#EH"'4EQT0D"`@```"+5"0DB50D
+M!(D$).C\____A,!T"8GPZQ*0C70F`(/#`8#[@7:IN/____\/ML"+7"0,BW0D
+M$(M\)!2+;"08@\0<PXVV`````(V_`````%575E.#[#R+5"10BP*`>BL`#X0#
+M`P``QT0D.`````"-B``"``")3"08!00"``")1"04#[9$)#B(1"0W#[;HB>C!
+MX`:-!*B+5"10C1P0]H.^"P``$`^$I@(``(V3D`L``+@!````B>G3X`A"#HN;
+MH`L``(E<)##V0@T"#X0P`0``#[9<)#>#PP&+="10.%XK#X8;`0``C02M````
+M`(E$)"")ZL'B!HE4)!R-M"8`````#[;SB?#!X`:-!+"+3"10C3P(]H>^"P``
+M$`^$T0```(M,)"`#3"0<BU0D4`'*B50D+/>"L`L`````#@`/A*\```"+5"10
+MC80"H`L``(E$)"B)PH/"%(M$)%"-C`B@"P``B4PD)(G(@\`4QT0D"`@```")
+M5"0$B00DZ/S___^$P'1OBT0D*(/`"(M4)"2#P@C'1"0("````(E$)`2)%"3H
+M_/___X3`=$FX`0```(GQT^"+5"0L@<*0"P``"D(.B$(.B(>>"P``@WPD,`!U
+M#(N_H`L``(E\)##K%XGPP>`&C02PBU0D,(MT)%")E`:@"P``@\,!BTPD4#A9
+M*P^'`/___X-\)#``#X6W````BW0D4(DT).C\____B40D,(7`#X1'`0``B>C!
+MX`:-#*@!\8M$)#")@:`+```/MD0D-XG"P>(&C82"D`L``(U$!@B+5"0PB4(8
+M#[:!G0L``(A"!L9"!0"),L9""@#&0C0`QD(<``^V5"0W@\(!.%8K=EV)Z,'@
+M!HT$J(V<!I`+``"0C70F``^VR@^V0P[3^*@!=!>)R,'@!HT$B(MT)#"+3"10
+MB;0!H`L``(/"`8M$)%`X4"MV&>O.B>C!X`:-!*B+3"0PBU0D4(F,`J`+``")
+MZ,'@!HT$J(MT)%"-E`:0"P``#[9"#HM,)#"(00D/MG(.@'PD-P-V)XT<[0``
+M``"+1"08`=C'`#@```#'!"00)P``Z/S___\#7"04B3/K)XT<[0````"+1"08
+M`=C'`#@```#'!"00)P``Z/S___\#7"04B3.)]H-$)#@!#[9$)#>#P`&+="10
+M.$8K#X<8_?__@\0\6UY?7<.-M"8`````C;PG`````%575E.#[$R+="1@BQ[&
+M1"1`4,9$)$$%QD0D0@3&1"1#,,9$)$01QD0D1:O&1"1&`,9$)$<`QX,`0`$`
+M$R```(L&QX`$0`$`__\``(L&QX`$0`$``````#NV1`4```^%Y````(V^R`P`
+M`(VN6`4``,=$)!`!````QT0D#`@```");"0(QT0D!````@")-"3H_/___XN&
+M4`4```^VEEL%``"#Z@2-!(*(AEL%``")-"3H_/___X3`=1&+1"1`B898!0``
+MBT0D1(E%!*$``````(9;!0``@\`!HP`````/MH98!0``B(=8!0``#[:&604`
+M`(B'604```^VAEH%``"(AUH%```/MH9;!0``@\`"B(=;!0``#[:&7`4``(B'
+M7`4```^VAET%``"(AUT%```/MH9>!0``B(=>!0``#[:&7P4``(B'7P4``(G?
+MC8,``0``B40D*(N#``$``*,`````#[?0B50D2*@@=`LEW_\``(E$)$CK%HG0
+M@\@@B40D2(M4)"B)`HL"HP````"+!L>`!`$```````"+!L>`&`$```````"+
+M!L>`'`$```````#'!"20T`,`Z/S____'AW`!```8`0``BX=T`0``HP````"`
+MY/V`S`2)1"1(QX=P`0``&`$``(M$)$B)AW0!``#'AW`!```H`0``QX=T`0``
+M?W\``,>'<`$``"0!``"+AW0!``"C`````&:X```-_S\``(E$)$C'AW`!```D
+M`0``BT0D2(F'=`$``,>'<`$``#P!``#'AW0!`````'H`QX=P`0``I`$``,>'
+M=`$``'V_[__'AW`!``"X`0``BX=T`0``HP`````E__\```T``/H`B40D2,>'
+M<`$``+@!``"+1"1(B8=T`0``QX><````_P```,>'D`(``$0!``#'AY0"```&
+M$``(QX>0`@``M`$``,>'E`(``%]P``#'AY`"```P````BX>4`@``HP`````P
+MY(#,,XE$)$B)AY0"``"`?BL`#X1Z`@``QT0D+`````"-AU`"``")1"08C9=4
+M`@``B50D%`^V1"0LB$0D,SP##X81`0``#[;HC13M`````(E4)"2-A!<P`@``
+MB40D(,<`"````,<$)!`G``#H_/___XM4)"2-G!<T`@``BP.C`````(E$)$@-
+M``"``(D#C898!0``B40D"(EL)`2)-"3H_/___XEL)`2)-"3H_/___XM$)"#'
+M`$0!``#'!"00)P``Z/S____'`P80``B+5"0@QP*T`0``QP0D$"<``.C\____
+MQP-?<```BT0D(,<`"````,<$)!`G``#H_/___\=$)$C_5(``QP/_5```QT0D
+M"`$```");"0$B30DZ/S___^+1"0DC90'@`$``(L"HP`````E___^_XD"QT0D
+M2`4!R`"+5"0DC807A`$``,<`!0'(`.D.`0``#[9L)#.-!.T`````B40D.(M4
+M)!@!PHE4)!S'`@@```#'!"00)P``Z/S___^+7"0X`UPD%(L#HP````")1"1(
+M#0``@`")`XV&6`4``(E$)`B);"0$B30DZ/S___^);"0$B30DZ/S___^+1"0<
+MQP!$`0``QP0D$"<``.C\____QP,&$``(BU0D',<"M`$``,<$)!`G``#H_/__
+M_\<#7W```(M$)!S'``@```#'!"00)P``Z/S____'1"1(_U2``,<#_U0``,=$
+M)`@!````B6PD!(DT).C\____BT0D.(V4.(`!``"+`J,`````)?___O^)`L=$
+M)$@%`<@`BU0D.(V4.H0!``")5"0TQP(%`<@`QP0DH(8!`.C\____B6PD!(DT
+M).C\____@T0D+`$/MD0D,X/``3A&*P^'HOW__XDT).C\____BX<$`0``HP``
+M``"#R`*)1"1(B8<$`0``BU0D*(L"HP`````E\/___0T-```"B40D2(D"BP*C
+M`````(N&(`H``(F'"`$``(N&)`H``(F'#`$``(N&1`H``(F'$`$``(N&2`H`
+M`(F'%`$``,>'(`$````````/MX:4"P``)?\/```-```!`(F'(`$``(N&C`H`
+M`(F')`$``(N&D`H``(F'*`$``(N&K`H``,<`_P\``,>'-`$````````/MX:6
+M"P``)?\/```-```!`(F'-`$``(N&L`H``(F'.`$``(N&M`H``(F'/`$``,>'
+M2`$```````#'1"1(``$``,>'3`$````!``"+AP0!``"C`````(/(68F'!`$`
+M`,=$)$C[_P`,QX=4`0``^_\`#,>'7`$``/__``"X`````,>$AM`%````````
+MQT2&7`````"#P`&#^!!UY6;'AI`+``#_#V;'AI(+``#_#\9&-`&P`8/$3%M>
+M7UW#C70F`%575E.#[!R)1"04B=>+*(DL).C\____B<.%P'4,QH>U`````>G`
+M````B2PDZ/S___^)QH7`=1C&A[4````!B5PD!(DL).C\____Z9H```"-0SR)
+M1"08QD,DX<9#)0'&0R8##[=''&:)0Q#&0V@/BU0D%(L"B4,8QT,@``(``(M6
+M"(E3-+@`````C;0F`````,8$$`"#P`$]``(``'7RB7-0QT-LH#P"`,=$)`0`
+M````BT0D&(D$).C\____BT,@B40D#(M&#(M6$(E$)`2)5"0(BU0D&(D4).C\
+M____B5PD!(DL).C\____@\0<6UY?7</K#9"0D)"0D)"0D)"0D)!55U93@^Q,
+MBT0D8(LH#[9`"83`#X17!```#[;8QT0D.`````#VPP%U&;H`````B?:#P@$/
+MMLJ)3"0XB=C3^*@!=.Z+1"0XP>`&BW0D.(T$L(T4*(N"L`L``*D```(`=!`-
+M```$`"7___W_B8*P"P``BT0D.,'@!HM\)#B-!+B+A`6P"P``J0``!``/A`8#
+M``"+A40%``")1"1(.>AU"HV5R`P``(E4)$B+1"0XP>`&BTPD.(T$B`'H#[:0
+MNPL``(E4)"@/MI"Z"P``B50D)`^VD+D+``")5"0@#[:0N`L``(E4)!P/MI"W
+M"P``B50D&`^VD+8+``")5"04#[:0M0L``(E4)!`/MH"T"P``B40D#`^V12F)
+M1"0(B4PD!,<$)'@)``#H_/___\=$)#P`````BW0D.,'F`HET)$2+?"0XP><&
+MB7PD0(M4)#R+3"1(#[:$"C@%```\_P^$H@````^VP&G`%`T``(G#`YFP!0``
+MBW0D1(M\)$"-A#Z@"P``C7P%%+@(````_(G>B<'SI@^7P@^2P#C"=6@/MD,'
+MB40D(`^V0P:)1"0<#[9#!8E$)!@/MD,$B40D%`^V0P.)1"00#[9#`HE$)`P/
+MMD,!B40D"`^V`XE$)`3'!"3("0``Z/S___^+?"1@QD<%_XE\)`2)+"3H_/__
+M_^ET`@``C70F`(-$)#P!@WPD/`(/A3;___^)+"3H_/___XG#A<`/A$X"``"+
+M1"0XP>`&BU0D.(T$D/:$!;$+```$=`2`2S4"BT0D.,'@!HM,)#B-!(CVA`6R
+M"P``!'0$@$LU$(M$)#C!X`:+="0XC02P]H0%L0L```AT!(!+-02+1"0XP>`&
+MBWPD.(T$N/:$!;(+```(=`2`2S4@BT0D.,'@!HM4)#B-!)#VA`6Q"P```G0$
+M@$LU`8M$)#C!X`:+3"0XC02(]H0%L@L```)T!(!+-0C&0S``B=^+1"0XP>`&
+MBW0D.(V$L*`+``"-1`4`BU`4B1.+0!B)0P2+1"1@B4,(B00DZ/S___^(@XL`
+M``"+5"1@@$(<`8!]*P!T,+D`````N@````")]HMT)&`/MD8)T_BH`70.#[;"
+MB$P#0(!#,@&#P@&#P0$X32MWW(M$)&"+2#"-4R")4#"+1"1@@\`LB4,@B4LD
+MB1&+5"1@@$(T`<=$)!``````#[:#BP```(E$)`R)?"0(B50D!(N%``H``(D$
+M).C\____Z=H```"I```(``^$SP```(DL).C\____B<.%P`^$O0```,9`)P;&
+M0"8%9L>`E```````QD`D!L9`)0#'0$0```4`QT!(`````(V(H````(M$)#C!
+MX`:+="0XC82PH`L``(U$!0"+4!2)DZ````"+0!B)002+@Z````")@Y@```"+
+M002)@YP```"+?"1@B7LLB3PDZ/S___^(@[8```!F@TLX$(D\).C\____/`EV
+M!F:!2S@``HM$)&#&0`H!BU`\B5@\BT0D8(/`.(D#B5,$B1J)7"0$B2PDZ/S_
+M__^)]H/$3%M>7UW#D(VT)@````!55U93@^PLBWPD0(M<)$2%VW05#[9#!83`
+M=`T\_P^%E`<``.D<`0``N@````"-=@`/MH0Z/@4``#S_=`T/ML!KP%R-G`=(
+M`0``@\(!@_H$==^^``````^VA#X^!0``//]T,0^VP&O`7(V<!T@!``#VA`=.
+M`0```G02QT0D!`````")'"3H_/___^L(B1PDZ/S___^#Q@&#_@1UNP^V1R9F
+M.8?@"0``#X4+!P``A=MU?X!_-0`/A?T&``#&1S4!B?:+A)^X`@``A<!T5HM0
+M<(72="['0'``````QX2?N`(```````#'1"0(_____XE$)`2+0'B)!"3_TNLG
+MC;8`````BU!TA=)T&L=`=`````#'A)^X`@```````(M`>(D$)/_2@\,!@_M`
+M#X2*!@``ZY'&0P7_B5PD!(D\).C\____Z7,&``"Z`````(VT)@`````/MH0Z
+M/@4``#S_#X3W````#[;(:\%<C9P'2`$``(E<)"2-A`=``0``@'@-_P^$U0``
+M`(!X$@`/A"L&``"^`````&O97(VL'X`!``")+"3H_/___XG!C00[BY"$`0``
+MB8B$`0``B2F)402)"H!Y)O]T?X"YM0`````/A.D%```/MEDD#[;3B="#X`:#
+M^`9U*?;"`71'B4PD#`^V04V)1"0(BT$PB40D!(M$)"2)!"3H_/___^FO!0``
+M@_@$#X6F!0``]L,!#X2=!0``B4PD!(D\).C\____Z8P%``")3"0$B3PDZ/S_
+M___I>P4``(UT)@"#Q@&)\CB4'U(!```/AF4%``#I1/___X/"`8/Z!`^%[?[_
+M_\=$)!P`````@'\U`)`/A9(```"[`````)"-="8`BY2?N`(```^VA#NX!```
+MA=)T9(M*<(7)=%V#>F``=5<\_W0M#[;P:<8H`0```X=X!0``]D`G!'08@'@E
+M`'42B70D"(E4)`2)/"3H_/___^LFQX2?N`(```````#'0G``````QT0D"/__
+M__^)5"0$BT)XB00D_]&#PP&#^T!U@<9'-0'IKP0``(M,)!P/MH0Y/@4``#S_
+M#X2+!```#[;0:\)<C9P'2`$``(E<)"B`O`=2`0````^$;`0``,9$)",`B<6-
+MA`>``0``B40D$(UV`(M4)!")%"3H_/___XG#C40]`(N0A`$``(F8A`$``(M,
+M)!")"XE3!(D:@'LF_P^%#00```^W0QR)1"04#[:4.+@$``!FB50D&HNTA[@"
+M``#V0R@$=&N%]G1G@WYP`'1A@WY@`'5;@&,H^_9#)P2-=@!T%0^WPHE$)`B)
+M="0$B3PDZ/S____K.8M6<(M,)!3'A(^X`@```````,=&<`````#'0R``````
+MQT0D"/____^)="0$BT9XB00D_]*0C70F`/9#)P0/A&8!``#&@[0`````@*0O
+M4`$``.?V0R@!#X3]````@&,H_HM#((7`=%6`>R4`=3#V0R<$="H/MD<IP>`&
+M`T0D%(E$)`B+AT0%``")1"0$QP0D!P```.C\____Z=P```")1"0(BX=$!0``
+MB40D!,<$)`$```#H_/___^F]````A?9T9(M6<(72C70F`'19@'LE`'4@]D,G
+M!'0:#[=$)!J)1"0(B70D!(D\).C\____Z8@```"+1"04QX2'N`(```````#'
+M1G``````QT,@`````,=$)`C_____B70D!(M&>(D$)/_2ZU6`>R4`=4_V0R<$
+M=$D/MD<IP>`&`T0D%(E$)`B+AT0%``")1"0$QP0D`@```.C\____ZR*)]HM#
+M((7`=!F+4'2%TG02QT!T`````(M#((M`>(D$)/_2]D,H`@^$-@(``(M#((E$
+M)`B+AT0%``")1"0$QP0D!@```.C\____@&,H_>GD`0``BT,@A<`/A-D!``"#
+M>'0`D`^$S@$``,9#)P'&0R8`B5PD",=$)`0&````BU0D*(D4).C\____@WLP
+M`'02BU,(BT,,B4($B1"+0S"`:#`!@'M/`'0:B3PDZ/S____'!"0!````Z/S_
+M__^`>T\`=>:+D^0```"%TG0;QT0D"`$````/MH/9````B40D!(D4).C\____
+MBU,PA=)T&,=$)`@!````#[9#38E$)`2)%"3H_/___XMS((7V#X3V````]D,H
+M!'5=B3PDZ/S____'1"0(`0```(M#((E$)`2)/"3H_/___XM3(`^V0@*)1"0(
+M#[9"`8E$)`3'!"3$`0``Z/S___^+0R")1"0(BX=$!0``B40D!,<$)`$```#H
+M_/___^LY#[9&`HE$)`@/MD8!B40D!,<$),0!``#H_/___XM#((E$)`B+AT0%
+M``")1"0$QP0D`0```.C\____BU9TA=)T'@^W0QS'A(>X`@```````,=&=```
+M``"+1GB)!"3_TO9#*`)T(8M#((E$)`B+AT0%``")1"0$QP0D!@```.C\____
+M@&,H_<=#(`````#'1F``````BU,TA=)T#`^V0TW'1((\`````(L3BT,$B4($
+MB1"`K"]2`0```8E<)`2)/"3H_/____9#*`)T)HM#((E$)`B+AT0%``")1"0$
+MQP0D!@```.C\____@&,H_9"-="8`@$0D(P$/MDPD(SB,+U(!```/AZG[__^#
+M1"0<`8-\)!P$#X51^___N`$```"#Q"Q;7E]=PXVV`````(V_`````%=64X/L
+M$(MT)""+/HDT).C\____A,!T&`^V7RN$VW0Q#[96";D`````]L(!=!SK(<9&
+M!?^)="0$B3PDZ/S____K7(G0T_BH`74'@\$!.-EU\8D\).C\____B<&%P'0_
+MBU8\B48\C48XB0&)402)"H!&"@&)<2S&020%QD$E`,9!30_'1"0,`0```,=$
+M)`@!````B4PD!(DT).C\____@\006UY?PXUT)@"-O"<`````@^PLB5PD'(ET
+M)"")?"0DB6PD*(MT)#2+7E0/MD8F/"0/AVH'```/ML#_)(6`"0``#[=&,@^W
+MT/;"!'0,9L=&,@$`QD8F`>M#9H/X('4,9L=&,@@`QD8F$>LQA-)Y%?9&+0-T
+M#R1_@\@(9HE&,L9&)@WK&/;""'0&QD8F!^L-]L8"=`C&1BL`QD8F'HET)`2+
+M1"0PB00DZ/S____I\`8``,=$)`P!````QT0D"`(```#'1"0$`0```(DT).C\
+M____Z<L&``#'1"0,`0```,=$)`@`````QT0D!`$```")-"3H_/___^FF!@``
+MQT0D#`$```#'1"0(`0```,=$)`0!````B30DZ/S____I@08``,=$)`P!````
+MQT0D"&````#'1"0$`0```(DT).C\____Z5P&```/MD8LQT0D$`$```")1"0,
+MQT0D"&````#'1"0$`0```(DT).C\____Z2\&``#'1"00`0```,=$)`P```$$
+MQT0D""$```#'1"0$`0```(DT).C\____Z0(&``"+0QB!8"C___?_QT0D$`$`
+M``#'1"0,`0```,=$)`@"````QT0D!`````")-"3H_/___^G+!0``QT0D$`$`
+M``#'1"0,`````,=$)`@"````QT0D!`````")-"3H_/___\<$)!`G``#H_/__
+M_^F2!0``BT,8@6`H___W_\=$)!`!````QT0D#`$```#'1"0(`@```,=$)`0`
+M````B30DZ/S____I6P4``,=$)!`!````QT0D#`````#'1"0(`@```,=$)`0`
+M````B30DZ/S____'!"00)P``Z/S____I(@4``,=$)`P!````QT0D"`(```#'
+M1"0$`````(DT).C\____Z?T$``#'1"0,`0```,=$)`@`````QT0D!`````")
+M-"3H_/___^G8!```QT0D#`$```#'1"0(`0```,=$)`0`````B30DZ/S____I
+MLP0``,=$)!`!````QT0D#/_____'1"0(`0```,=$)`0`````B30DZ/S____I
+MA@0``,=$)`P!````QT0D"`````#'1"0$`````(DT).C\____Z6$$```/MD8K
+MBWR&/(E?+(EW-`^V1BN(1TW&1R8#QD<E`(!/)`6`0PH!BU,\C4,XB7L\B0>)
+M5P2).L<$)(`:!@#H_/___XM4)#"`>BL`="F^`````/9#"0%T#NL<#[9#"8GQ
+MT_BH`745@\8!B?"+5"0P.$(K=^;K!;X`````BU,8BT(HJ0``"`!T"B7___?_
+MB4(HZV2)\0^VP8TLQ0````"[N`L``(GP/`-V'(M4)#"+`@6``0```>B+`*,`
+M````P>@3@^`!ZQR+3"0PBP$%@`$``(U$!0"+`*,`````P>@3@^`!A,!U$<<$
+M).@#``#H_/___X/K`76M9L>'E```````B7PD!(M$)#")!"3H_/___^E/`P``
+MQP0D0`T#`.C\____QT0D#`````#'1"0((````,=$)`0!````B30DZ/S____'
+M!"00)P``Z/S____I$@,``,=$)`P`````QT0D"`$```#'1"0$`````(DT).C\
+M____QP0D$"<``.C\____Z>$"``"+0QB!8"C___?_QT0D$`````#'1"0,____
+M_\=$)`@!````QT0D!`````")-"3H_/___\<$)!`G``#H_/___^F>`@``QT0D
+M#`````#'1"0(`````,=$)`0`````B30DZ/S____'!"00)P``Z/S____I;0(`
+M`(ET)`2+5"0PB10DZ/S____I6`(``(ET)`2+3"0PB0PDZ/S____I0P(``,=$
+M)!`!````QT0D#/````#'1"0(FP```,=$)`0!````B30DZ/S____I%@(``,=$
+M)!`!````QT0D#*#66BO'1"0(X`,``,=$)`0!````B30DZ/S____IZ0$``,=$
+M)!`!````QT0D#`#@`P#'1"0(I`,``,=$)`0!````B30DZ/S____IO`$``,=$
+M)!`!````QT0D#.2H!@''1"0(Q`,``,=$)`0!````B30DZ/S____ICP$``,=$
+M)`P!````QT0D"$@#``#'1"0$`0```(DT).C\____Z6H!``#'!"1`#0,`Z/S_
+M___'1"0,`0```,=$)`@@````QT0D!`$```")-"3H_/___\<$)!`G``#H_/__
+M_^DM`0``QT0D$`$```#'1"0,`````,=$)`@A````QT0D!`$```")-"3H_/__
+M_^D``0``QT0D#`$```#'1"0(8````,=$)`0!````B30DZ/S____IVP````^V
+M1BS'1"00`0```(E$)`S'1"0(8````,=$)`0!````B30DZ/S____IK@```,9#
+M!0"+1E2)!"3H_/___^F:````QT0D#`$```#'1"0(`0```,=$)`0`````B30D
+MZ/S____'!"00)P``Z/S____K;(M#&(%@*/__]__'1"00`0```,=$)`S_____
+MQT0D"`$```#'1"0$`````(DT).C\____QP0D$"<``.C\____ZRS'1"0,`0``
+M`,=$)`@!````QT0D!`````")-"3H_/___\<$)!`G``#H_/___[@!````BUPD
+M'(MT)""+?"0DBVPD*(/$+,.-M"8`````@^P<B5PD$(ET)!2)?"08BUPD((M\
+M)"0/MU<09H'ZA0!W?@^WP@^VA!BX!```//]T;V:#^G]W&0^VP&G`*`$```.#
+M>`4``(M`+`^V2`3K5I`/MT<09CV!`'<@#[?`#[:$&+@$``!IP!0-```#@[`%
+M``"+0`@/MD@$ZRL/MT<0#[:$&+@$``!IP+`````#@Y0%``"+0%0/MD@$ZPJ0
+MC70F`+G_____N/____]F@7\0A0!W#`^W1Q`/MH08N`0``(NSE`4```^VT8#Y
+M_W04@+P:/@4``/]T"CS_=`:`?Q0&=2:#?U``=`^-1U")1"0$B1PDZ/S___^)
+M?"0$B1PDZ/S____IZ@````^VP&G`L`````'&#[9&)CP:='8\&G<*/!$/A9L`
+M``#K&SP;C;0F`````'1C/!P/A88```"-M@````#K>HN30`H``('"3`@```^V
+M1C3!X`@!PHL*B0T`````#[;)BY-`"@``@<)$"```#[9&-,'@"`'"BP*C````
+M`,'@"`G!B8Z4````QD8F&NLQQD8F&^LKBX-`"@``!4P(```/ME8TP>((`="+
+M`*,`````@^#WB$8LQD8F'.L$QD8F'8-_4`!T#XU'4(E$)`2)'"3H_/___XE\
+M)`2)'"3H_/___XET)`2)'"3H_/___XUV`(M<)!"+="04BWPD&(/$',.#[`R+
+M1"00B40D!(L`B00DZ/S___^#Q`S#C;0F`````(/L+(E<)!R)="0@B7PD)(EL
+M)"B+7"0TBW,L#[=3'+@`````BTPD,("\"K@$``#_#X0["0``#[9#)CP)#X0O
+M!0``/`EW2SP%#X28````/`60=QX\`P^$M@```#P$C70F``^%[@@``.GD````
+MD(UT)@`\!P^$D00``#P'C;8`````#X<4!```Z9D"``"0C70F`#P6#X2``P``
+M/!:-M@````!W(SP4#X28!0``/!2-="8`#X?J`@``/`H/A98(``")]ND0!0``
+M/!H/A#<"```\_Y`/A'`%```\%P^%=@@``(GVZ48#``"+1"0P#[9H*XGJA-(/
+MA*$````/ME8)OP````#VP@$/A((```#IB@```(GVBT88@6`H___^_XM#+,=$
+M)`P`````QT0D"`$```")7"0$B00DZ/S____'!"0%````Z/S___^X`0```.DA
+M"```QT0D#`````#'1"0(`````(E<)`2)-"3H_/___\<$)%##``#H_/___[@!
+M````Z>\'``")T(GYT_BH`742@\<!B?B)Z3C(=>OK!;\`````#[93)(G0@^`&
+M@_@&=0GVP@$/A=4```"+5AB+0BBI```!`'0-)?___O^)0BCINP```(GZ#[;"
+MP>`#B40D&+T0)P``D(M,)#"+$8GX/`-V&8M,)!B-A!&``0``BP"C`````"4`
+M``$`ZQ>+3"08C801@`$``(L`HP`````E```!`(7`=#*)^#P#=A:+3"08C801
+M@`$``,<````!`.D?!P``BTPD&(V$$8`!``#'`````0#I"0<``,<$).@#``#H
+M_/___X/M`0^%>?___\9#)P+&0R;_B5PD!(M$)#")!"3H_/___[@!````Z><&
+M``#V1@8!=#:)7"0$B30DZ/S___^$P'4FO?H```")7"0$B30DZ/S___^$P'41
+MQP0DZ`,``.C\____@^T!==^)^H#Z`W8<BTPD,(L!!8`!```/MM*-%-"+`J,`
+M````B0+K'(M4)#"+`@6``0``B?D/MM&-%-"+`J,`````B0*+0RR)VN@BY?__
+MQP0D($X``.C\____N`$```#I3`8``(E4)`3'!"0`"@``Z/S___^+<RR+/HD\
+M).C\____B<&%P'41QH.U`````;@!````Z1@&``#&0"3AQD`E`<9`)A</MT,<
+M9HE!$,9!:`^+!HE!&,=!(`````#'030`````QT%LH#P"`(E,)`2)/"3H_/__
+M_[@!````Z=`%``")5"0$QP0DV@$``.C\____BW,LBSZ)/"3H_/___XG!A<!U
+M$<:#M0````&X`0```.F<!0``QD`DX<9`)0'&0"88#[=#'&:)01"+!HE!&,=!
+M(`````#'030`````QT%LH#P"`(E,)`2)/"3H_/___[@!````Z5@%``")VHGP
+MZ`_D__^X`0```.E%!0``BSZ)/"3H_/___XG"#[9+/(7`=1'&@[4````!N`$`
+M``#I(`4``,9`).'&0"4!QD`F!8A()P^W0QQFB4(0BP:)0AC'0B``````QT(T
+M`````,=";*`\`@"(2S^)5"0$B3PDZ/S___^X`0```.G6!```BSZ)/"3H_/__
+M_XG"#[9+/H7`=1'&@[4````!N`$```#IL00``,9`).'&0"4!QD`F!(A()P^W
+M0QQFB4(0BP:)0AC'0B``````QT(T`````,=";*`\`@"(2T&)5"0$B3PDZ/S_
+M__^X`0```.EG!```BSZ)/"3H_/___XG!A<!U$<:#M0````&X`0```.E&!```
+MQD`DX<9`)0'&0"8&#[=#'&:)01"+!HE!&,=!(`````#'030`````QT%LH#P"
+M`(E,)`2)/"3H_/___[@!````Z0($``")]HL^B3PDZ/S___^)P87`=1'&@[4`
+M```!N`$```#IWP,``,9`).'&0"4!QD`F#`^W0QQFB4$0BP:)01C'02``````
+MQT$T`````,=!;*`\`@")3"0$B3PDZ/S___^X`0```.F;`P``BSZ)/"3H_/__
+M_XG!A<!U$<:#M0````&X`0```.EZ`P``QD`DX<9`)0'&0"86QD`H`0^W0QQF
+MB4$0QD%H#XL&B4$8QT$@`````,=!-`````#'06R@/`(`B4PD!(D\).C\____
+MN`$```#I+@,``,9#)O]FQX.4```````/ME,DB="#X`:#^`9U!?;"`74>@WLT
+M`'48B30DD(UT)@#H_/___XB#M@```)"-="8`@'LG`G4:BT,LB5PD"(E$)`2+
+M1"0PB00DZ/S___^-=@#V1@@"=1J[`````(U^.(!^"@`/A6`!``#I?`(``(UV
+M`(M6*`^V6BH/MLL/MD(?@^@!.<%]-HU#`8A"*H!"*P'&0B8`#[=",H/@_H/(
+M"&:)0C*)5"0$BU0D,(D4).C\____N`$```#I90(``#G!=!:[`````(U^.(!^
+M"@!U-(UV`.DO`@``QD(F``^W0C*#X/:`S`)FB4(RB50D!(M,)#")#"3H_/__
+M_[@!````Z1\"``")/"3H_/___XG!BT8\B4X\B3F)002)"(!Y)O\/A(X```"`
+MN;4`````#X35`0``#[99)`^VTXG0@^`&@_@&=2KVP@%T40^V04V+43")3"0,
+MB40D"(E4)`2)-"3H_/___[@!````Z;8!``"#^`0/A9$!``#VPP$/A(@!``")
+M3"0$BT0D,(D$).C\____N`$```#IB@$``(E,)`2+5"0PB10DZ/S___^X`0``
+M`.EP`0``QH&U`````(/#`3A>"@^&00$``.DY____B3PDZ/S___^)P8M&/(E.
+M/(DYB4$$B0B`>2;_#X2?````@'DE``^%C@```("YM0`````/A`0!```/MEDD
+M#[;3B="#X`:#^`9U*O;"`711#[9!38M1,(E,)`R)1"0(B50D!(DT).C\____
+MN`$```#IY0```(/X!`^%P````/;#`0^$MP```(E,)`2+3"0PB0PDZ/S___^X
+M`0```.FY````B4PD!(M$)#")!"3H_/___[@!````Z9\```#&@;4`````@\,!
+M#[9&"CC8#X<Q____.,-U3H3`=$J[`````(U^.(D\).C\____B<*+1CR)5CR)
+M.HE"!(D0#[9")3PB=`0\#747QT0D!`H```")%"3H_/___[@!````ZS^#PP$X
+M7@IWOL9&!?^)="0$BU0D,(D4).C\____N`$```#K'+@!````ZQ6%[8UV``^$
+M`?G__^D>^?__D(UT)@"+7"0<BW0D((M\)"2+;"0H@\0LPXVV`````(V_````
+M`(/L+(E<)!R)="0@B7PD)(EL)"B+?"0PBVPD-`^W51!F@?J%``^'O@````^W
+MP@^VC`>X!```@/G_#X2J````9H/Z?W<<#[;!BY=X!0``:<`H`0``BT00+`^V
+M0`3K.HUV`&:!^H$`=QD/ML&+E[`%``!IP!0-``"+1!`(#[9`!.L7#[;!BY>4
+M!0``:<"P````BT005`^V0`0\_W1-#[;`#[:<!SX%``"`^_]T%8#Y_W00#[95
+M%(#Z!G57C;0F`````(#[_W0C@/G_=!X/ML%IP"@!``")Q@.W>`4``,9&)P+&
+M1B;_Z5@"``"#?5``=`^-15")1"0$B3PDZ/S___^);"0$B3PDZ/S____I7P(`
+M`(GV#[;!:<`H`0``B<8#MW@%``"+332$T@^$M`````^V128\!@^$S0```#P,
+M#X3%````#[>6E````(U"`6:)AI0```!F@_H)=A>`?B8&=!'&1B<"QD8F_X!F
+M*/[IT@$``,<$).@#``#H_/___P^V5B2)T(/@!H/X!G4^]L(!=#G'1"00````
+M`,=$)`P"````#[9&38E$)`B+1C")1"0$#[;#:\!<C80'2`$``(D$).C\____
+MZ:<!``#&1B8#B70D!(D\).C\____Z9(!``"0C70F``^V128\`74-QD8F!(UT
+M)@#I2P$``#P"=0S&1B8%C78`Z3L!```\`P^%O0```(G(@'XF!74K9H%Y!,@W
+M=2,/MT8<B40D!,<$)#0*``#H_/___\9&)@;I!@$``(VV`````(E$)`2)-"3H
+M_/___XU&9+HH````Z.>___^$P'4XC490NA0```#HUK___X3`=2>-AHP```"Z
+M"````.C"O___A,!U$XM&1`M&2'0+QD8F%XGVZ:L```!F@[Z4````'781QD8G
+M`L9&)O^`9BC^Z9````#'!"3H`P``Z/S____&1B8:9H.&E`````'K=CP7=0;&
+M1B85ZVP\&'4*QD8F%HUT)@#K7CP$=0;&1B8'ZU0\!8GV=0;&1B8(ZT@\!G4&
+MQD8F">L^/`QU!L9&)@KK-#P6B?9U!L9&)A3K*#P.=22#?5``=`^-15")1"0$
+MB3PDZ/S___^);"0$B3PDZ/S____K+I"#?5``=`^-15")1"0$B3PDZ/S___^)
+M;"0$B3PDZ/S___^)="0$B3PDZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LP^L-
+MD)"0D)"0D)"0D)"0D(/L+(E<)!R)="0@B7PD)(EL)"B+;"0TBW4L#[=%'+H`
+M````BTPD,("\`;@$``#_#X3K`@``#[9%)CP4#X34````/!1W.SP-#X0$`0``
+M/`V0=Q`\!0^%NP(``(VV`````.M3/`X/A/L````\#XUT)@`/A9\"``#I_```
+M`)"-="8`/!L/A)\````\&XVV`````'<0/!AT.3P9#X5W`@``B?;K1SP<=%T\
+M_P^%9P(``(GVZ<8```#'1"0$`````(DL).C\____N@$```#I40(``,=$)`0!
+M````B2PDZ/S___^Z`0```.DW`@``QT0D!`$```")+"3H_/___[H!````Z1T"
+M``")+"3H_/___[H!````Z0L"``")+"3H_/___[H!````Z?D!``#V13D$=!*)
+M+"3H_/___[H!````Z>$!``")+"3H_/___[H!````Z<\!``")+"3H_/___[H!
+M````B?;INP$``(DL).C\____N@$```#IJ0$``,9%)O^`?@H`#X3I````NP``
+M``"-?CB-=@")/"3H_/___XG"BT8\B58\B3J)0@2)$(!Z)O\/A)\```"`>B4`
+M#X6<````@+JU``````^$30$```^V6B0/MLN)R(/@!H/X!G4J]L$!=%*)5"0,
+M#[9"38E$)`B+0C")1"0$B30DZ/S___^Z`0```.D=`0``@_@$#X4)`0``]L,!
+MD`^$_P```(E4)`2+1"0PB00DZ/S___^Z`0```.GP````B50D!(M,)#")#"3H
+M_/___[H!````Z=8```"-M@````#&@K4`````@\,!#[9&"CC8#X<J____.,,/
+MA8P````/MD4E/")T%#P-=!"_`````(UN.(!^"@!U'.MPQT0D!`H```")+"3H
+M_/___[H!````Z7P```")+"3H_/___XG#BT8\B5X\B2N)0P2)&`^V0R4\(G0$
+M/`UU*8E<)`3'!"3P`0``Z/S____'1"0$"@```(D<).C\____N@$```#K,HGV
+M@\<!B?@X1@IWJL9&!?^)="0$BTPD,(D,).C\____N@$```#K"[H!````C;8`
+M````B="+7"0<BW0D((M\)"2+;"0H@\0LPXUV`(V\)P````!55U93@^PLBUPD
+M1`^W4Q"Y_____[C_____9H'ZA0!W>P^WPHMT)$`/MHP&N`0``+C_____@/G_
+M=&)F@_I_=QT/ML&+?"1`BY=X!0``:<`H`0``BT00+`^V0`3K/V:!^H$`=QT/
+MML&+="1`BY:P!0``:<`4#0``BT00"`^V0`3K&P^VP8M\)$"+EY0%``!IP+``
+M``"+1!!4#[9`!`^VP(M4)$`/MK0"/@4``&O&7(V$`D@!``")1"0D#[;!:<`H
+M`0```X)X!0``B40D*(M+-`^V$<'B&`^V00'!X!`)P@^V00,)P@^V00+!X`@)
+MPHU9"(G0P>@#@_@0=@6X$````(T$P8E$)!PYPP^'D`$``,=$)"``````:_9<
+MB70D&`-T)$")="04B1PDZ/S___^)Q8US!+\4"@``N00```#\\Z8/E\(/DL`X
+MP@^%1`$``(/]$`^'.P$``(-$)"`!@WPD(`%U*HM,)"C'@1P!```!````B:D@
+M`0``BP.)@:@```"+0P2)@:P```#I!0$``(MT)$")-"3H_/___XG&A<`/A/P`
+M``#&0"<&QD`F!6;'@)0``````,9`)`;&0"4`QT!$```%`,=`2`````#'@!P!
+M```!````B:@@`0``BU0D*('"H````(M\)"B+AZ````")AJ````"+0@2)AJ0`
+M``"+AZ````")AI@```"+0@2)AIP```"+`XF&J````(M#!(F&K````(M$)"2)
+M1BR)!"3H_/___XB&M@```&:#3C@0BU0D)(D4).C\____/`EV!F:!3C@``HM,
+M)!2`@5(!```!BY&$`0``B;&$`0``BWPD0(M,)!B-A`^``0``B0:)5@2),HET
+M)`2)/"3H_/___XVV`````(/#"#M<)!P/AH?^__^#Q"Q;7E]=PXUT)@"-O"<`
+M````55=64X'L+`(```^VA"1(`@``BY0D0`(``(M2"(E4)!R+"HE,)""+E"1`
+M`@``#[92,(A4)">+C"1``@``@\$HB4PD*(N4)$`"```Y2B@/A*L"``"`?"0G
+M``^$H`(```^VP(E$)!2+3"0HB0PDZ/S___^->/B-1"0LB40D$(M4)!2)5"0,
+MQT0D"`$```"+3"0<B4PD!(N$)$0"``")!"3H_/___X!\)"P`#X3^````O0``
+M``"-EZ````")5"08C78`B>D/MO''1"0("````(M$)!B)1"0$B?/!XP2-A!R8
+M````B00DZ/S___^$P`^$GP```(V4'(P````/MD((@^`/B(>V````#[=/.&:!
+MX=_]B<B#R!!FB4<X#[9"",#H!#P)=0F)R(/(,&:)1SB)\,'@!`^VA`24````
+MP.@$/`IU!F:!3S@``HM,)"B+402-1PB)002)3PB)5PR)`O9'*`)T0(!G*/V+
+M1R"%P'0UB40D"(M4)""+@D0%``")1"0$QP0D!@```.C\____ZQ60C70F`(/%
+M`8GI.$PD+'81Z2#___^)Z#A$)"P/AS<!``")?"0(QT0D!`8```"+5"0<B10D
+MZ/S___^`?T\`="2-M@````"+3"0@B0PDZ/S____'!"0!````Z/S___^`?T\`
+M=>*+E^0```"%TG0;QT0D"`$````/MH?9````B40D!(D4).C\____BU<PA=)T
+M&,=$)`@!````#[9'38E$)`2)%"3H_/___XM'((7`='W'0&``````]D<H!'4G
+MBT0D((D$).C\____QT0D"`$```"+1R")1"0$BU0D((D4).C\____BT<@B40D
+M"(M,)""+@40%``")1"0$QP0D!@```.C\____BT<@B40D"(M4)""+@D0%``")
+M1"0$QP0D`0```.C\____QT<@`````(L7BT<$B4($B1"+3"0<@&D*`8N$)$`"
+M``"`:#`!B7PD!(M4)"")%"3H_/___XM$)"B+C"1``@``.4$H=`N`;"0G`0^%
+M9_W__X'$+`(``%M>7UW#C;0F`````%575E.!["P"``"+O"1$`@``BX0D0`(`
+M`(L`B40D)`^VM"1,`@``C5PD+(E<)!")="0,QT0D"`$```"+E"1``@``B50D
+M!(D\).C\____B70D"(E\)`2+M"1(`@``B30DZ/S___^+;BB#[0B)\X/#*(U%
+M"#G8="L/MD4E/`UT%#PB=3#K#@^V124\#70&/"*)]G4@QD4F!<9%)P3&1"0J
+M`>L%QD0D*@"`?"0L`'45Z2`"``"+;0B#[0B-10@YV'7%D.O?QD0D*P"+A"1`
+M`@``@\`XB40D((N4)$@"``"+<BB#[@B-1@@YPP^$`P(```^V1"0KP>`$C;P$
+MF````(UT)@#'1"0("````(E\)`2-AJ````")!"3H_/___X3`#X6<`0``BW8(
+M@^X(C48(.=@/A+T!``#KRXNT)$`"``"`1@H!QD$F!<:!M`````#&02<$9L>!
+ME```````QH&6`````,=!1```!0#'04@`````#[9T)"N)\,'@!(V4!(P````/
+MMD($B$$D#[9"!8A!)8N$)$`"``")02P/MD((@^`/B(&V````#[=Y.&:!Y]_]
+MB?B#R!!FB4$X#[9"",#H!#P)=0F)^(/(,&:)03B)\,'@!`^VA`24````P.@$
+M/`IU!F:!23@``HN4)$@"``")43")\L'B!`^VA!22````B$%-C904C````(M"
+M#(F!H````(M2$(F1I````(F!F````(F1G````(NT)$@"``"`1C`!BY0D0`(`
+M`(M"/(E*/(MT)""),8E!!(D(BX0D2`(``(M0+(U!"(NT)$@"``")1BR)60B)
+M40R)`@^V422)T(/@!L9$)"H`@_@&=4?VP@%T+8E,)`P/MD%-B40D"(N$)$@"
+M``")1"0$BY0D0`(``(D4).C\____QD0D*@#K%8E,)`2+="0DB30DZ/S____&
+M1"0J`(!$)"L!#[9$)"LX1"0L#X<#_O__@'PD*@!T+<=$)`0*````B2PDZ/S_
+M___K&Y"-="8`BU0D)(D4).C\____B<&%P`^%+_[__X'$+`(``%M>7UW#ZPV0
+MD)"0D)"0D)"0D)"055=64X'L+`(``(N$)$`"``"+,`^V4!R(5"0F@\`LB40D
+M*(N,)$`"```Y02P/A-`#``"$T@^$R`,``(M$)"B)!"3H_/___XUHX,=$)!``
+M````QT0D#`````#'1"0(`````(N4)$`"``")5"0$BXPD1`(``(D,).C\____
+MB$0D)X3`#X1K`P``OP````"[`````(E<)"#'1"00`````(E<)`S'1"0(`0``
+M`(N$)$`"``")1"0$BY0D1`(``(D4).C\____#[;`P>`$@\!D/0`"```/A^D!
+M``"-3"0LB4PD$(E<)`S'1"0(`0```(N$)$`"``")1"0$BY0D1`(``(D4).C\
+M____QT0D"`@```");"0$C8PDB````(D,).C\____A,`/A)@!``"+1"0HBU`$
+MC44@BTPD*(E!!(E-((E5)(D"#[9$)"Z(13&-A"2`````B40D!(N$)$`"``")
+M!"3H_/___SS_=!(/ML!IP!0-```#AK`%``")10R)^H32=%4/MD0D+]'H@^`!
+MP>`$#[95-8/B[PG"B%4U#[9$)"_!Z`.#X`'!X`6#XM\)PHA5-0^V1"0OP>@"
+M@^`!P>`#@^+W"<*(534/MD0D,HB%BP```.F_````#[9$)"Z(13&+C"1``@``
+MB4T(#[9$)#*(A8L````/MT0D,(E%.`^W1"1\9HF%B`````^V1"1^B(6*````
+MC4UXC50D+(/"0(M$)&R)17B+0@2)002+0@B)00B+0@R)00R-34B-5"0L@\(0
+MBT0D/(E%2(M"!(E!!(M""(E!"(M"#(E!#(U-6(U4)"R#PB"+1"1,B458BT($
+MB4$$BT((B4$(BT(,B4$,BT(0B4$0BT(4B4$4BT0D9(E%<(M$)&B)172+1"0@
+MB40D#(EL)`B+E"1$`@``B50D!(N,)$`"``")#"3H_/___^D8`0``B?:#QP&#
+MPP&)^#I$)"</A"`!``#INOW__XD\).C\____C5CXB5PD",=$)`0&````BY0D
+M0`(``(D4).C\____@'M/`'0:B30DZ/S____'!"0!````Z/S___^`>T\`=>:+
+M0R"%P'1MQT!@`````/9#*`1U'XDT).C\____QT0D"`$```"+0R")1"0$B30D
+MZ/S___^+0R")1"0(BX9$!0``B40D!,<$)`$```#H_/___XM#((E$)`B+AD0%
+M``")1"0$QP0D!@```.C\____QT,@`````(L3BT,$B4($B1"+C"1``@``@&D*
+M`8!M,`&)7"0$B30DZ/S___\Y?2@/A1C___^+A"1``@``@&@<`8EL)`2)-"3H
+M_/___XM,)"B+E"1``@``.4HL=!R`;"0F`705Z4C\__^-?2@Y?2@/A=G^__^)
+M]NN]@<0L`@``6UY?7<.-=@!55U93@>PL`@``BZPD1`(``(M%`(E$)!R+E"1`
+M`@``B50D!(DL).C\____QT0D$`````#'1"0,`````,=$)`@`````B6PD!(N<
+M)$`"``")'"3H_/___XA$)".$P`^$O@,``,9$)"(`QT0D)`````"0QT0D$```
+M``"+1"0DB40D#,=$)`@!````B6PD!(N4)$`"``")%"3H_/___P^VP,'@!(/`
+M9#T``@``#X=8`P``C5PD+(E<)!"+1"0DB40D#,=$)`@!````B6PD!(N4)$`"
+M``")%"3H_/___XV<)(@```")7"0$B2PDZ/S___\\_P^%$@,``(M$)!R)!"3H
+M_/___XG'A<`/A"\#``"`11P!QD`P`(N$)(@```")!XN$)(P```")1P2-A"2`
+M````B40D!(DL).C\____//]T%@^VP&G`%`T``(M4)!P#@K`%``")1PP/MD0D
+M+HA',0^V1"0OT>B#X`'!X`0/ME<U@^+O"<*(5S4/MD0D+\'H`X/@`<'@!8/B
+MWPG"B%<U#[9$)"_!Z`*#X`'!X`.#XO<)PHA7-8EO"`^V1"0RB(>+````BT0D
+M-(E'0(M$)#B)1T0/MD0D,XA',@^W1"0PB4<X#[=$)'QFB8>(````#[9$)'Z(
+MAXH```"-3WB-5"0L@\)`BT0D;(E'>(M"!(E!!(M""(E!"(M"#(E!#(U/2(U4
+M)"R#PA"+1"0\B4=(BT($B4$$BT((B4$(BT(,B4$,C4]8C50D+(/"((M$)$R)
+M1UB+0@2)002+0@B)00B+0@R)00R+0A")01"+0A2)012+1"1DB4=PBT0D:(E'
+M=(M-,(U7((E5,(U%+(E'((E/)(D1@'PD+``/A((!``!FQT0D*@``C5TXB5PD
+M&(U'*(E$)!2-M@````"+5"0<B10DZ/S___^)P87`#X2$`0``@$4*`<9`)@7&
+M@+0`````QD`G!,=`1```!0#'0$@`````9L>`E```````#[=T)"J)\,'@!(V4
+M!(P````/MD($B$$D#[9"!8A!)8EI+(EY,`^V0@:(04T/MD((@^`/B(&V````
+M#[=9.&:!X]_]B=B#R!!FB4$X#[9"",#H!#P)=0J)V(/(,&:)03B0B?#!X`0/
+MMH0$E````,#H!#P*=0QF@4DX``*-M@````")\,'@!(V4!(P```"+0@R)@:``
+M``"+4A")D:0```")@9@```")D9P```"`1S`!BT4\B4T\BUPD&(D9B4$$B0B+
+M5RR-00B)1RR+7"04B5D(B5$,B0(/ME$DB="#X`:#^`9U+_;"`70:B4PD#`^V
+M04V)1"0(B7PD!(DL).C\____ZQ")3"0$BT0D'(D$).C\____9H-$)"H!#[9$
+M)"QF.T0D*@^'F?[__X!$)"(!@T0D)`$/ME0D(SA4)"(/A5#\__^`?0H`=13&
+M107_B6PD!(M<)!R)'"3H_/___X'$+`(``%M>7UW#C70F`(V\)P````!55U93
+M@^PLBVPD0(M\)$3'1"00`````,=$)`P`````QT0D"`````")?"0$B2PDZ/S_
+M__^$P'0XNP````"#Z`$/MO"-1"0KB40D#(E<)`B)?"0$B2PDZ/S___^`?"0K
+M_@^%I0```(/#`8U&`3G#==,/MD<T@^@!B$<TA,!T=8LWQD<T`(M?+(/K((U7
+M+(U#(#G0='>#>PP`=4CK"Y"-="8`@WL,`'4[QD<T`8E\)`2)+"3H_/___\=$
+M)!``````#[:#BP```(E$)`R)7"0(B7PD!(N&``H``(D$).C\____ZRF+6R"#
+MZR"-0R`YT'6RB?;K&(E\)`2)+"3H_/___XE\)`2)+"3H_/___X/$+%M>7UW#
+MC;0F`````(V\)P````!55U93@^P,BW0D((M\)"2++KL*````B7PD!(DT).C\
+M____A,!U$<<$).@#``#H_/___X/K`77?#[9=*X3;="`/ME8)N0````#VP@%T
+M"^L0D(G0T_BH`74'@\$!.-EU\8L7BT<$B4($B1"`;@H!B7PD!(DL).C\____
+M]D8(`G1!BT8HA<!U$XDL).C\____A<`/A%H!``")1BB)*(EP5,9`*@#&0"L`
+MQD`F`&:#2#($B40D!(DL).C\____Z3`!``"+1BB%P`^$RP```(/`6(E$)`2+
+M112)!"3H_/___XM&*(E$)`2)+"3H_/___XU^.#E^.`^$EP```(D\).C\____
+MB<.+0""%P'1MQT!@`````/9#*`1U'XDL).C\____QT0D"`$```"+0R")1"0$
+MB2PDZ/S___^+0R")1"0(BX5$!0``B40D!,<$)`$```#H_/___XM#((E$)`B+
+MA40%``")1"0$QP0D!@```.C\____QT,@`````(!N"@&)7"0$B2PDZ/S___\Y
+M?C@/A6G____'1B@`````@'X*`'03C48XB00DZ/S___^)P8!N"@'K"HDL).C\
+M____B<&%R70SBU8\B4X\C48XB0&)402)"H!&"@&)<2S&020%QD$E`,9!)P;&
+M028#B4PD!(DL).C\____@\0,6UY?7<.0C;0F`````(/L+(E<)!R)="0@B7PD
+M)(EL)"B+?"0PBUPD-`^W4Q!F@?J%`'=Z#[?"#[:,![@$``"`^?]T:F:#^G]W
+M&0^VP8N7>`4``&G`*`$``(M$$"P/MD`$ZSMF@?J!`'<9#[;!BY>P!0``:<`4
+M#0``BT00"`^V0`3K&P^VP8N7E`4``&G`L````(M$$%0/MD`$C70F``^VT3S_
+M=`EF@?K_`'4HB?:#>U``=`^-0U")1"0$B3PDZ/S___^)7"0$B3PDZ/S____I
+M.@$```^VP`^VC`<^!0``#[?":<`H`0``B<8#MW@%``"`>Q0`#X2F````:\%<
+MC:P'0`$```^V11*)1"00#[9%$8E$)`P/MD,GB40D"`^V0R:)1"0$QP0D5`H`
+M`.C\____BQ:+1@2)0@2)$(!M$@&)="0$B3PDZ/S___^)7"0$B3PDZ/S___\/
+MMG<KB?"$P`^$J@````^V71&Y`````/;#`74-ZQP/MLJ)V-/XJ`%T%HE,)`2)
+M/"3H_/___^E^````N@````"#P@&)\#C"==;K;FO!7(VL!T@!``"`>R8!=3;'
+M!"00)P``Z/S___^)7"0$B3PDZ/S____'1"0,`0```,=$)`@`````B70D!(DL
+M).C\____ZRC'!"10PP``Z/S___^)7"0$B3PDZ/S___^)="0$B2PDZ/S___^-
+M="8`BUPD'(MT)""+?"0DBVPD*(/$+,.-M@````"-OP````!55U93@^P<BW0D
+M,(ML)#0/MD0D.(A$)!</MD0D/(A$)!:+!HE$)!B`?@H`='2[`````(U^.(D\
+M).C\____B<*+1CR)5CR).HE"!(D0.6HP=0\/MD0D%SA"370-D(UT)@"#PP$X
+M7@IWS3A>"G0T@'PD%E!U+<9")P;&0B8%QD(D!\9")0"):C")<BS&@I8`````
+MB50D!(M$)!B)!"3H_/___X/$'%M>7UW#C;0F`````(/L+(E<)!R)="0@B7PD
+M)(EL)"B+;"0PBT0D-`^W4!!F@?J%``^'A@````^WP@^VA"BX!```//]T=V:#
+M^G]W&`^VP&G`*`$```.%>`4``(M`+`^V4`3K7HM4)#0/MT(09CV!`'<@#[?`
+M#[:$*+@$``!IP!0-```#A;`%``"+0`@/ME`$ZS"+3"0T#[=!$`^VA"BX!```
+M:<"P`````X64!0``BT!4#[90!.L+C;8`````NO____^Y_____XM$)#1F@7@0
+MA0!W$(M,)#0/MT$0#[:,*+@$```/ML(/MH0H/@4``&O`7(V\!4@!```/ML%I
+MP+````"+M90%```!QHM$)#2`>"@"#X6(````#[9`+"7P````@_@@=`6#^!!U
+M=8M,)#0/ME$LB="#X`^#^`%U,8G0)?````#'1"00`0```(E$)`S'1"0(`@``
+M`,=$)`0`````B30DZ/S____I`0H``)`/MD8KBU2&/(M,)#0/MD$L)?````"#
+M^"`/E,"#P`B(@K8```"+0C1F@6`R__[IS@D``(M4)#0/MD(4A,!T0XG#@WI0
+M`'01B="#P%")1"0$B2PDZ/S___^+3"0TB4PD!(DL).C\____@/L"#X60"0``
+MB70D!(DL).C\____Z7\)``#'AI@`````````#[9&)CPD#X<)"0``#[;`_R2%
+M'`H``(M'&/9`*@@/A#()``")]NFW!0``BY5`"@``@<),"```#[9&-,'@"`'"
+MBP*C`````(/X!7<%B$8?ZP3&1A\%@'\+`'0-QD8F`,9'"P#IK@@``,9&)@+I
+MI0@``(N50`H``('"3`@```^V1C3!X`@!PHL"HP`````/ML!FB48@BY5`"@``
+M@<)$"```#[9&-,'@"`'"BP*C`````(G"P>H(9HE6(L'@"&8)1B!F@?I`074)
+MQD8F&>E&"```9H%^(A67#Y3`@^@!@^#?@\`DB$8FZ2P(``"+E4`*``"!PD0(
+M```/MD8TP>`(`<*+`J,`````B$8=BY5`"@``@<),"```#[9&-,'@"`'"BP*C
+M`````*@(=`;&1AX,ZQJH!'0&QD8>"^L0@^`"@_@!&<#WT(/@"HA&'@^V1BL\
+M`1G`@^`"@\`4B$8FZ;<'``"+A4`*```%3`@```^V5C3!X@@!T(L`HP````"#
+MR`B(1BS&1B8%Z8T'``#&1B8`#[=&,F8E]_V#R`)FB48RBT0D-(-X4`!T#X/`
+M4(E$)`2)+"3H_/___XM4)#2)5"0$B2PDZ/S____&1P7_B7PD!(DL).C\____
+MZ9P'``#&1B8$Z3,'```/MD8K@\`!B$8K.D8?<U?&1B86BTPD-(-Y4`!T$8G(
+M@\!0B40D!(DL).C\____BT0D-(E$)`2)+"3H_/___\=&6("$'@#'1F``````
+MB79DC498BU44B40D!(D4).C\____Z2T'``#&1BL`QD8F%\<$)""A!P#H_/__
+M_^FT!@``QD8F%.FK!@``QD8F"(VT)@````#IFP8``,9&)A3ID@8``,9&+@#H
+M_/___XF&B````,9&)A7I>@8``(N50`H``('"3`@```^V1C3!X`@!PHL:B1T`
+M````#[;;BY5`"@``@<)$"```#[9&-,'@"`'"BP*C`````.C\____B8:,````
+M@^,/@_L#=0G&1B8*Z2(&``"+AH@````%0`T#`#F&C````'D7#[9&+CP*=P_&
+M1B85@\`!B$8NZ?@%```/MD8K@WR&/``/A*<!``#'1"04`````(!_"@!T/L9$
+M)!H`C5\XB1PDZ/S___^)1"04#[9&*XM4)!0Y5(8\=!R+0P2)4P2)&HE"!(D0
+M@$0D&@$/MDPD&CA/"G?*@&\*`8M4)!2+0B"%P`^$+`$``,=`8`````#V0B@$
+M=3N)+"3H_/___XM,)!2+033&@*P````!BT$@QT0D"`$```")1"0$B2PDZ/S_
+M__^+5"04BT(TQH"L`````(M,)!2+02"+E40%``")1"0(B50D!,<$)`$```#H
+M_/___XM4)!2+0B"+2'"%R70P#[="',>$A;@"````````BT(@QT!P`````(M"
+M((M0>,=$)`C_____B40D!(D4)/_1BTPD%(M!((7`="N+4'2%TG0D#[=!',>$
+MA;@"````````BT$@QT!T`````(M!((M`>(D$)/_2BU0D%(M"(`^V4`(/MD`!
+MB50D"(E$)`3'!"3$`0``Z/S___^+3"04BT$@BY5$!0``B40D"(E4)`3'!"0&
+M````Z/S___^+1"04QT`@``````^V1BO'1(8\`````(M4)!2)5"0$B2PDZ/S_
+M___&1B8)Z3D$``"+E4`*``"!PDP(```/MD8TP>`(`<*+"HD-``````^VR8N5
+M0`H``('"1`@```^V1C3!X`@!PHL"HP````#!X`@)R(E&.(!^)@IT!ZD```$`
+M=`G&1B8+Z=\#``#&1B8,#[9&*X-\ACP`=$Z`?PH`#X0F!```QD0D&P"-7SB)
+M'"3H_/___XG"#[9&*SE4ACQU"H!O"@'K+(UT)@"+0P2)4P2)&HE"!(D0@$0D
+M&P$/MDPD&SA/"G8,Z\2)+"3H_/___XG"A=(/A-`#```/MD8KB52&/`^V1B^(
+M@K8```#I60,``(DL).C\____QP0D`0```.C\____@^L!@_O_=`F+1QCV0"H(
+M=-O&1B8)Z2L#``"+E4`*``"!PDP(```/MD8TP>`(`<*+"HD-``````^VR8N5
+M0`H``('"1`@```^V1C3!X`@!PHL"HP`````/ML#!X`@)R"7_#P``/1,!```/
+ME,(](P$```^4P832=1.$R74//3,!``!U0HUV`.GR`@``QD8F&(32D(UT)@!T
+M"<9&+PCII0(``(3)C78`=`G&1B\)Z94"```],P$```^%B@(``,9&+PKI@0(`
+M``^V3BH/MM$/MD8?@^@!.<)]$XU!`8A&*H!&*P'&1B8'Z5P"``#&1BL`QD8F
+M'NE/`@``QD8F`^E&`@``QD8F(HGVZ3L"``#&1B8CZ3("``#&1B8#Z2D"``"+
+ME4`*``"!PDP(```/MD8TP>`(`<*+"HD-`````(N50`H``('"1`@```^V1C3!
+MX`@!PHL2B14`````B=#!X`@/MLD)R&8]`Q$/A9H```")T,'H"&8]15-T"F8]
+M0`,/A84```!FQT8@`Q%FB48B9CU%4W4<@+ZE`````G03QH:E`````L>&J```
+M`!\```#K(F:!?B)``W4:@+ZE`````W01QH:E`````\>&J`````_X`P#&AJP`
+M```!B30DZ/S____&AJP`````BP:+@$0%``#'1"0$`````(D$).C\____QD8F
+M`^E!`0``QD8F(<:&I0````#I,0$``(N50`H``('"3`@```^V1C3!X`@!PHL"
+MHP````"+E4`*``"!PD0(```/MD8TP>`(`<*+`J,`````QD8F'^GP````QD8F
+M(.GG````BY5`"@``@<),"```#[9&-,'@"`'"BP*C`````(N50`H``('"1`@`
+M``^V1C3!X`@!PHL"HP`````/MDXK#[9&'XU1`8A6*P^VR0^VP(/H`3G!#YS`
+M@^@!@^#G@\`?B$8FZ8(```"+E4`*``"!PDP(```/MD8TP>`(`<*+"HD-````
+M``^VR8N50`H``('"1`@```^V1C3!X`@!PHL"HP````#!X`@)P8F.E````,9&
+M)AKK-<9&)AOK+XN%0`H```5,"```#[96-,'B"`'0BP"C`````(/@]XA&+,9&
+M)ASK",9&)AV-="8`BT0D-(-X4`!T#X/`4(E$)`2)+"3H_/___XM4)#2)5"0$
+MB2PDZ/S___^)="0$B2PDZ/S____K*<9&)ACI&_W__XDL).C\____QP0D`0``
+M`.C\____NSY"#P#I9?S__XGVBUPD'(MT)""+?"0DBVPD*(/$+,.-M@````"-
+MOP````"#[%R)7"1,B70D4(E\)%2);"18BVPD8(M\)&0/MU<09H'ZA0`/A[X`
+M```/M\(/MHP%N`0``(#Y_P^$J@```&:#^G]W'`^VP8N5>`4``&G`*`$``(M$
+M$"P/MD`$ZSJ-=@!F@?J!`'<9#[;!BY6P!0``:<`4#0``BT00"`^V0`3K%P^V
+MP8N5E`4``&G`L````(M$$%0/MD`$//]T30^VP`^VE`4^!0``@/K_=!6`^?]T
+M$`^V7Q2`^P9U5XVT)@````"`^O]T(X#Y_W0>#[;!:<`H`0``B<8#M7@%``#&
+M1B<"QD8F_^FX!P``@W]0`'0/C4=0B40D!(DL).C\____B7PD!(DL).C\____
+MZ<('``")]@^VP6G`*`$``(G&`[5X!0``#[>&E````&:)1"0V9CVK#7<%@/L"
+M=3J#?U``=`^-1U")1"0$B2PDZ/S___^)?"0$B2PDZ/S____&1B;_QD8G`HET
+M)`2)+"3H_/___^E>!P``QD0D/0"`^R!U)8M/.`^V`8/@?SQQ=@T/MDD!@^$/
+MB$PD/>L+#[9)`H/A#XA,)#T/MM*)5"0P:\)<C80%2`$``(E$)#@/MD<D/!H/
+MA`<&```\&G<?/!)T43P5C70F``^$F`8``(3`#X2E!0``B?;INP8``#PE#X3@
+M`@``/"60=Q,\&P^%I@8``(VV`````.EU!0``/)X/A,T#```\H)`/A8H&``#I
+M8@8``(3;C78`#X6#`@``BT\T@'\E`(UV`'1AA<ET2X!Y`8!U18!Y`@!U/P^V
+M00,\/'<W#[;8C590N`````#&!!`@@\`!@_@4=?2#^Q-V!;L4````C590C4$$
+MB5PD"(E$)`2)%"3H_/___V;'AI0``````,9&)AGI#08``,9&)ACV009`=1$/
+MM@&#X!^#^`T/A6,!``#K"P^V`8/@'X/X#74)QD8E#8UV`.L$QD8E(@^V1B6)
+M1"0$QP0D!`(``.C\____@W]0`'0/C4=0B40D!(DL).C\____B7PD!(DL).C\
+M____:T0D,%R`O`52`0````^$P@4``+X`````B<.-O`6``0``B3PDZ/S___^-
+M%"N+BH0!``")@H0!``").(E(!(D!#[9`)3PB=`0\#74.@\8!B?(XE!U2`0``
+M=\AK1"0P7`^VA`52`0``B?$XR`^%904``(3`#X1=!0``O@````!FQT0D/@``
+MQT0D0`````!K7"0P7(V\'8`!``")/"3H_/___XG!C00KBY"$`0``B8B$`0``
+MB3F)402)"@^V024\(G0$/`UU%`^W01QF.T0D/G()9HE$)#Z)3"1`@\8!B?`X
+MA!U2`0``=[*#?"1```^$Y`0``(M4)$"`>B;_#X36!```QD(F_XE4)`2)+"3H
+M_/___^G!!```@_@!=1'&1B4!QD8F_XUT)@#I>P0``/9!!0%T!F:!3C@`!(M?
+M-(7;=%N-5F2X`````,8$$`"#P`&#^"AU](V6C````+``Q@00`(/``8/X"'7T
+MC4YDC5,(BT,(B49DBT($B4$$BT((B4$(BT(,B4$,BT(0B4$0BT(4B4$4BT,@
+MB8:,````@[X<`0````^%``0``,9&)ASI]P,```^W1"0V@\`!9HF&E````,<$
+M)!`G``#H_/___\9&)@7ITP,``(M/-(3;#X60````#[91!L'B"`^V007!X!`)
+MP@^V00<)P@^V003!X!@)PHF6L`````^V$<'B&`^V00,)P@^V00+!X`@)P@^V
+M00'!X!`)T(E&1,=&2`````"#OK``````=1UF@X:4`````<<$)!`G``#H_/__
+M_\9&)AOI50,``(/X_W4/9H%..``$QD8F&^E!`P``QD8F#>DX`P``@/L@=3.`
+M?"0]!G0'@'PD/0)U)0^W1"0V@\`!9HF&E````,<$)!`G``#H_/___\9&)@7I
+M`0,``)"#?U``=`^-1U")1"0$B2PDZ/S___^)?"0$B2PDZ/S___^)="0(BTPD
+M.(E,)`2)+"3H_/___^GV`@``BT<TB40D1(3;#X4?`0``#[90"L'B"`^V0`G!
+MX!`)PHM,)$0/MD$+"<(/MD$(P>`8"<*)EK`````/MD$#B<*X`````(E$)"B)
+M5"0L#[9!`HG"N`````#!X@B+3"0H"<&+7"0L"=.+1"1$#[8`B40D(,=$)"0`
+M````BT0D((G"N`````#!XA@)P0G3BT0D1`^V0`&)1"08QT0D'`````"+1"08
+MB<*X`````,'B$`G!"=.+1"1$#[90!L'B"`^V0`6)1"08P>`0"<*+1"1$#[9`
+M!PG"BT0D1`^V0`2)1"08P>`8"<()RHE61(E>2(M4)$3V0@P!=`5F@TXZ!(.^
+ML`````!U'6:#AI0````!QP0D$"<``.C\____QD8F&^FF`0``9H-..`'&1B8-
+MZ9@!``"`^R!U,X!\)#T&=`>`?"0]`G4E#[=$)#:#P`%FB8:4````QP0D$"<`
+M`.C\____QD8F&^EA`0``D(-_4`!T#XU'4(E$)`2)+"3H_/___XE\)`2)+"3H
+M_/___XET)`B+3"0XB4PD!(DL).C\____Z58!``#&1B84Z1T!``"`^R!U.(!\
+M)#T&C78`=`>`?"0]`G4G#[=$)#:#P`%FB8:4````QP0D$"<``.C\____QD8F
+M%.GC````C78`QD8F&^G7````A-N0C70F`'5<BT<T9H-..`)F@TXZ`6:!3CB$
+M`(!X`P!U!8`X%G<=9H.&E`````''!"00)P``Z/S____&1B8-Z9,```#V0`8$
+M=`=F@TXZ`NL%9H-F.OV+1U")1AC'1U``````ZSJ`^R!U,(!\)#T&=`B`?"0]
+M`I!U)@^W1"0V@\`!9HF&E````,<$)!`G``#H_/___\9&)@7K/6:#9CCYQD8F
+M#NLRA-MU!6:#3CH#QD8F#^LCA-N0=0R)?"0$B2PDZ/S___^#OAP!```!&<"#
+MX!.#P`6(1B:#?U``=`^-1U")1"0$B2PDZ/S___^)?"0$B2PDZ/S___^)="0$
+MB2PDZ/S___^-=@"+7"1,BW0D4(M\)%2+;"18@\1<PY"0D)"0D)"0D)"0D(/A
+M!\'A"(#-((M`!"WD/```#[;2P>((`=")"`^W`&:C``````^VP,.0C;0F````
+M`(/A!\'A"(I,)`2`S1"+0`0MY#P```^VTL'B"`'0B0C#55=64X/L"(G'QD0D
+M`@#&1"0#`+W_____QT0D!``````/MD0D!(A$)`&#1"0$`;@!````B<8/MDPD
+M!-/FB?&[`````+C`X>0`N@````#W\3GX=QV)^BG"B=`YZG,3#[94)`&(5"0"
+MB%PD`XG%C70F`(/#`0'Q@_L0=<F#?"0$"'6?#[9$)`/!X`,*1"0"#[;`@\0(
+M6UY?7<.0C;0F`````(/L#(E<)`2)="0(BUPD$`^V="04QP0D`````+D'````
+MB?*)V.@7____#[:#)0L``(D$)+D#````B?*)V.C__O__BUPD!(MT)`B#Q`S#
+MC78`4XG3#[;1N0,```#HL/[__SC8#Y3`#[;`6\.-M@````!3BUPD"(7;="^Z
+M`````(GV#[:$&CH%```/ML@\_W01#[?!:<"P`````X.4!0``ZPV#P@&#^@1U
+MV+@`````6\.05E.#[`2+1"00BYA(!0``A=MU`HG#O@````#'!"0`````N0<`
+M``")\HG8Z&'^___'!"1$````N0(```")\HG8Z$S^___'!"30````N0````")
+M\HG8Z#?^___'!"0`````N00```")\HG8Z"+^__^#Q@&#_@)UI+B@A@$`Z##^
+M__^(@R4+```/ML")!"2Y`P```+H`````B=CH\_W__X/$!%M>PXVV`````(V\
+M)P````"#[#R)7"0LB70D,(E\)#2);"0XBU0D0`^V@J4````\`@^%Z@```(N*
+MJ````(E,)!1FQT0D&@``O0```"K'1"0<`````+L`````O@````"_!````+H!
+M````B=")V=/@A40D%'4<C4L&T^)F"50D&@E4)!RX%0```(GQT^`)Q>L)D(GX
+MB?'3X`G%@\,!@\8%@\<#@_L%=;V+1"0<B40D#,=$)`BH`P``QT0D!`$```"+
+M5"1`B10DZ/S___^);"0,QT0D",0#``#'1"0$`0```(M,)$")#"3H_/___P^W
+M1"0:BU0D0`N"J````(E$)`S'1"0(H`,``,=$)`0!````B10DZ/S____I_0``
+M`(VV`````#P##X7O````BTPD0(N)J````(E,)"AFQT0D(@``O0```"K'1"0D
+M`````+L`````O@````"_!````(VT)@````"Z`0```(G0B=G3X(5$)"AU'XU+
+M!M/B9@E4)"()5"0DN!4```")\=/@"<7K#(UT)@")^(GQT^`)Q8/#`8/&!8/'
+M`X/[!'6ZBT0D)(E$)`S'1"0(J`,``,=$)`0!````BU0D0(D4).C\____B6PD
+M#,=$)`C$`P``QT0D!`$```"+3"1`B0PDZ/S___\/MT0D(HM4)$`+@J@```#W
+MT(E$)`S'1"0(H`,``,=$)`0!````B10DZ/S___^+7"0LBW0D,(M\)#2+;"0X
+M@\0\PY"-="8`@^P,BU0D$`^V3"04@'PD&`!T#[C^____T\`A@J@```#K#;@!
+M````T^`)@J@```")%"3H_/___X/$#,.0C70F`(/L',=$)!`!````#[=$)"3!
+MX`B#P`^)1"0,QT0D")H```#'1"0$`0```(M$)"")!"3H_/___X/$',.-M@``
+M``"#[`R+5"00#[9,)!2`?"08`'00N/[____3P&8A@I````#K#K@!````T^!F
+M"8*0````#[>"D````(E$)`2)%"3H_/___X/$#,.0C;0F`````(/L+(E<)!R)
+M="0@B7PD)(EL)"B+="0PBT0D-`^V5"0XB%0D&P^VF)@````/MF@"BU!HA=)T
+M&@^V1"0;B40D"(GI#[;!B40D!(D4).C\____B30DZ/S___^`^P=W2@^VP_\D
+MA;`*``"_^P```(UT)@#K-;\S````ZRZ_.P```(GVZR6_<P```.L>OWL```")
+M]NL5O[,```#K#K^[````B?;K!;_S````B7PD!(DT).C\____#[9$)!N)1"0(
+MC42=``^VP(E$)`2)-"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#C;8`````
+MC;PG`````%=64X/L$(G'NP`````/MO*Y`@```(GRB?CHLOG__Z@(=`ZX````
+M`.LCC;0F`````,<$)`$```#H_/___X/#`8'[$"<``'7)N/\```"#Q!!;7E_#
+MC;8`````C;PG`````(/L#(D<)(ET)`2)?"0(B<:)SP^VVHG:Z(3___^%P'4P
+MB?@/MM")V8GPZ(+Z__^%P'0>N0$```")VHGPZ##Y__^+5"00B`*X`````.L(
+MC78`N/____^+'"2+="0$BWPD"(/$#,.-M@````"-OP````"#[!R)7"00B70D
+M%(E\)!B)Q@^V^0^VVHD\)+D!````B=KH"OG__\<$)$````"Y`@```(G:B?#H
+M]?C__XG:B?#H[/[__X7`=4Z#?"0@`'0U]\<!````=!F)V;I`````B?#HV_G_
+M_X7`="WK,I"-="8`B=FZ&````(GPZ,+Y__^%P'04ZQF)V;HH````B?#HKOG_
+M_X7`=0>X_P```.L%N`````"+7"00BW0D%(M\)!B#Q!S#C;0F`````(V\)P``
+M``!55U93@^P<B<>+;"0TB=.)SH3)#X0/`0``#[;:B5PD&,<$)&0```"Y`@``
+M`(G:B?CH._C__XM4)!B)^.@P_O__A<!U$+D#````BU0D&(GXZ.SW__^)\`^V
+MR,<$)`$```"+5"08B?CHU?[__[[_____A,`/A:@!``"^`````(7M#XZ;`0``
+MNP````"-1?^)1"04BT0D,`-$)!2)1"00BW0D%#G>=3O'!"1`````N0(```"+
+M5"08B?CHM/?__XM$)!")!"2Y6````(M4)!B)^.C]_?__A<!T0>E$`0``C70F
+M`,<$)$0```"Y`@```(M4)!B)^.AY]___BT0D,`'8B00DN5````"+5"08B?CH
+MP/W__X7`#X7_````@\,!.>L/A/0```#I=?___[B@A@$`C78`Z%OW__\/MML/
+MML")!"2Y`P```(G:B?CH)/?__XG:B?CH&_W__X7`="</MH<E"P``B00DN0,`
+M``")VHGXZ/_V__^^_____^FE````D(UT)@")V;I@````B?CH\O?__X7`=!"^
+M`````(7M?F*0C70F`.L?#[:')0L``(D$)+D#````B=J)^.BV]O__OO_____K
+M7[X`````QP0D1````+D"````B=J)^.B5]O__BT0D,`'PB00DN8````")VHGX
+MZ-[\__^%P'4'@\8!.>YUR0^VAR4+``")!"2Y`P```(G:B?CH6_;__^L)B=Z-
+MM"8`````B?"#Q!Q;7E]=PXVV`````(/L'(E<)!2)="08BW0D(`^V3"0DBT0D
+M+(E$)`2+1"0HB00DN@````")\.BA_?__B</'!"14````N0(```"Z`````(GP
+MZ/?U__^)V(M<)!2+="08@\0<PXGVC;PG`````(/L'(E<)!2)="08BW0D(`^V
+M3"0DBT0D+(E$)`2+1"0HB00DN@$```")\.A!_?__B</'!"14````N0(```"Z
+M`0```(GPZ)?U__^)V(M<)!2+="08@\0<PXGVC;PG`````%575E.#[`R)QXML
+M)"2)RP^V\L<$)&0```"Y`@```(GRZ%OU__^)\HGXZ%+[__^%P'4.N0,```")
+M\HGXZ!#U__\/MLO'!"0!````B?*)^.C]^___A,!U+H7M?C&[`````(M$)"`/
+MM@P#QP0D`````(GRB?CHV/O__X3`=0F#PP$YZW0)Z]NX_____^L%N`````"#
MQ`Q;7E]=PXVT)@````"#[!R)7"04B70D&(MT)"`/MDPD)(M$)"R)1"0$BT0D
-M*(D$)+H!````B?#H,?___XG#QP0D5````+D"````N@$```")\.C7]/__B=B+
-M7"04BW0D&(/$',.)]HV\)P````"#[!R+3"0@#[94)"2+@4P%``"%P'4"B<B(
-M%2`!``#'1"0,(````,=$)`@@`0``QT0D!`X```")!"3H_/___X/$',.-M"8`
-M````C;PG`````(/L#(M4)!`/MDPD%(!\)!@`=!"X`0```-/@9@F"N`P``.L.
-MN/[____3P&8A@K@,```/MH*X#```B40D!(D4).C\____@\0,PY"-M"8`````
+M*(D$)+H!````B?#H,?___XG#QP0D5````+D"````N@$```")\.B7]/__B=B+
+M7"04BW0D&(/$',.)]HV\)P````"#[!R+3"0@#[94)"2+@4@%``"%P'4"B<B(
+M%0`!``#'1"0,(````,=$)`@``0``QT0D!`X```")!"3H_/___X/$',.-M"8`
+M````C;PG`````(/L#(M4)!`/MDPD%(!\)!@`=!"X`0```-/@9@F"M`P``.L.
+MN/[____3P&8A@K0,```/MH*T#```B40D!(D4).C\____@\0,PY"-M"8`````
M55=64X/L3(M$)&2+2!B#P0*+4!"#Z@&)5"0DQT0D2`````"+6!R)7"0HB<:+
-M0!@/ME$!@/H!=0S'1BP`````Z6P%``"`^@)U4X!Y`@&-=@!U.HM4)&"+@DP%
-M``"%P'4"B="+@$@%```/ME$#B)"Z#```#[91`XB0AAD``(M,)&3'02P`````
+M0!@/ME$!@/H!=0S'1BP`````Z6P%``"`^@)U4X!Y`@&-=@!U.HM4)&"+@D@%
+M``"%P'4"B="+@$0%```/ME$#B)"V#```#[91`XB0?AD``(M,)&3'02P`````
MZ20%``"+7"1DQT,L_O___^D4!0``@\`!B40D+(#Z!`^%)0(```^V00.#Z#L\
-M`0^'%@(``(M$)"P/MG`"BU0D8(N:2`4``(GQ#[;!B40D!(D<).C\____B<*$
-MP'0-#[;`@+P#O`0``/]U5HN;2`4``('#S`P``(N#2`4``(D$).C\____B?(H
-MP@^VPHE$)`2)'"3H_/___XG"A,!T#0^VP("\`[P$``#_=1:+3"1DQT$L____
-M_XD,)/]1*.F$!```#[;"#[:$`[P$``"`^H%W9@^VR&G)%`T``(M$)"P/MD`$
+M`0^'%@(``(M$)"P/MG`"BU0D8(N:1`4``(GQ#[;!B40D!(D<).C\____B<*$
+MP'0-#[;`@+P#N`0``/]U5HN;1`4``('#R`P``(N#1`4``(D$).C\____B?(H
+MP@^VPHE$)`2)'"3H_/___XG"A,!T#0^VP("\`[@$``#_=1:+3"1DQT$L____
+M_XD,)/]1*.F$!```#[;"#[:$`[@$``"`^H%W9@^VR&G)%`T``(M$)"P/MD`$
MB$0D.XMT)"P/ME8%P>(0#[9&!L'@"`G"#[9&!PG"B50D,`^V5@C!XA`/MD8)
-MP>`("<(/MD8*"<*)5"0TB<X#L[0%```/A`D!``"`?C``=1WI_@```(M$)&3'
+MP>`("<(/MD8*"<*)5"0TB<X#L[`%```/A`D!``"`?C``=1WI_@```(M$)&3'
M0"S_____B00D_U`HB?;I]@,``+\`````QD0D.@"-;BB+5"0L@\(+B50D'(DL
M).C\____C5CXBU8LB48LB6L(B5,,B0(/MD,E/`UT"#PB#X6,````BTPD+`^V
M00,\.W0T/#QU?(M$)&2)1"00BU0D,(E4)`R+3"0TB4PD"`^V1"0[B40D!(D<
@@ -5009,48 +3633,48 @@ M)&2)1"00BU0D,(E4)`R+3"0TB4PD"`^V1"0[B40D!(D<).C\____QD0D.@&#
MQP&)^SA>,`^'/?___X!\)#H`#X40`P``BW0D9,=&+/____^)-"3_5BCI^@(`
M`(#Z`P^%MP```(!Y`@&)]@^%FP```(M4)&`/MD(FC30`#[99`XG:B=C!^A_W
M_HG3.=9^;8UY!`^V\@^V002)1"0(B70D!(M,)&")#"3H_/___XU#_(/X`W88
-MC4/T@_@#=A"-0^R#^`-V"(U#Y(/X`W<(@40D8,P,```/M@>)1"0(B70D!(M<
+MC4/T@_@#=A"-0^R#^`-V"(U#Y(/X`W<(@40D8,@,```/M@>)1"0(B70D!(M<
M)&")'"3H_/___XMT)&3'1BP`````Z3\"``"+1"1DQT`L_O___^DO`@``BU0D
M9,="+/[____I'P(``(`Y!79*@'D$_G5$C40D2(E$)`B+3"1DB4PD!(M<)&"+
-M@T@%``")!"3H_/___X3`#X7J`0``QT0D2`````"+="1DQT8L_____^G2`0``
-MB?:+1"1@BZA,!0``A>UU`HG%B<NX`@```"G(B40D(.GN````#[8SC7H!#[;(
+M@T0%``")!"3H_/___X3`#X7J`0``QT0D2`````"+="1DQT8L_____^G2`0``
+MB?:+1"1@BZA(!0``A>UU`HG%B<NX`@```"G(B40D(.GN````#[8SC7H!#[;(
M]L$!='"+5"1(B70D&(T$%HM<)&0[0Q0/AV$!``"+1"0L@#@!=2*)="0$BT0D
-M*`'0B00DN@$```")Z.AF]___.?!T)NDV`0``B70D!(M$)"@!T(D$)+H`````
-MB>CH1/?__SGP#X45`0``BU0D&`%4)$B)^^MPC1PWBT0D(`'8.T0D)`^/]@``
+M*`'0B00DN@$```")Z.@F]___.?!T)NDV`0``B70D!(M$)"@!T(D$)+H`````
+MB>CH!/?__SGP#X45`0``BU0D&`%4)$B)^^MPC1PWBT0D(`'8.T0D)`^/]@``
M`(M$)"R`.`%U'(ET)`2)/"2Z`0```(GHZ+'Y__^%P'0@Z=$```")="0$B3PD
MN@````")Z.B5^?__A<`/A;8```"`.P!U"H![`0"-="8`=`['!"00)P``Z/S_
M__^)]HU3`0^V0P&$P`^%`____P^V`X3`#X2*````#[;8QP0D5````+D"````
-MN@````")Z.C[[O__BU0D2(M,)&2+010IT#G#=@*)PXMT)"R`/@%U((E<)`2+
-M1"0H`=")!"2Y`````+H!````B>CH4?;__^L>B5PD!(M$)"@!T(D$)+D`````
-MN@````")Z.@Q]O__A<!X!@%$)$CK"XM$)&3'0"S_____QP0D5````+D"````
-MN@````")Z.AT[O__C70F`(M,)&2+42"%TG0&BT0D2(D"BUPD9(D<)/]3*(/$
-M3%M>7UW#C;8`````C;PG`````(/L'(M4)""+@DP%``"%P'4"B="+D$@%```/
-MMH*[#```A,!T#8/H`8B"NPP``(3`=2?&!2,!````QT0D#"````#'1"0((`$`
-M`,=$)`0.````B10DZ/S___^#Q!S#C70F`(/L'(M4)""+@DP%``"%P'4"B="+
-M@$@%``"`N+H,````=2Z`@+L,```!Q@4C`0```<=$)`P@````QT0D""`!``#'
+MN@````")Z.B[[O__BU0D2(M,)&2+010IT#G#=@*)PXMT)"R`/@%U((E<)`2+
+M1"0H`=")!"2Y`````+H!````B>CH$?;__^L>B5PD!(M$)"@!T(D$)+D`````
+MN@````")Z.CQ]?__A<!X!@%$)$CK"XM$)&3'0"S_____QP0D5````+D"````
+MN@````")Z.@T[O__C70F`(M,)&2+42"%TG0&BT0D2(D"BUPD9(D<)/]3*(/$
+M3%M>7UW#C;8`````C;PG`````(/L'(M4)""+@D@%``"%P'4"B="+D$0%```/
+MMH*W#```A,!T#8/H`8B"MPP``(3`=2?&!0,!````QT0D#"````#'1"0(``$`
+M`,=$)`0.````B10DZ/S___^#Q!S#C70F`(/L'(M4)""+@D@%``"%P'4"B="+
+M@$0%``"`N+8,````=2Z`@+<,```!Q@4#`0```<=$)`P@````QT0D"``!``#'
M1"0$#@```(D$).C\____@\0<PXVV`````(V_`````(/L'(E<)!2)="08BW0D
M(`^V3"0DBT0D+(E$)`2+1"0HB00DN@````")\.B1]___B</'!"14````N0(`
-M``"Z`````(GPZ#?M__^)V(M<)!2+="08@\0<PY"0D)"0D)"0D(M$)`2+0`0M
+M``"Z`````(GPZ/?L__^)V(M<)!2+="08@\0<PY"0D)"0D)"0D(M$)`2+0`0M
M``(!``-$)`B+`*,`````PY"-M"8`````BT0D!(M`!"T``@$``T0D"(M4)`R)
M$,.)]HV\)P````!3@^P,BUPD%(M3!('J``(!`,>"@``!``````"+@@0!`0"C
M`````(#,`8F"!`$!`,=$)`@$````QT0D!`S"``")'"3H_/___\=$)`BX"P``
MQT0D!`C"``")'"3H_/___\=$)`@!``P`QT0D!`#"``")'"3H_/___\=$)`@$
M````QT0D!`S#``")'"3H_/___\=$)`BX"P``QT0D!`C#``")'"3H_/___\=$
M)`@!``P`QT0D!`##``")'"3H_/___XM#!"VT`0``9L<```"+0P0ME`$```^W
-M`&:C``````^WP(M3!('JE`$``(/(!&:)`HM#!"V8`0``9L<`!`!FQX.X#```
+M`&:C``````^WP(M3!('JE`$``(/(!&:)`HM#!"V8`0``9L<`!`!FQX.T#```
M__^#Q`Q;PXVV`````(M$)`2+4`2!Z@`"`0"+@FP``0"C``````S(B8)L``$`
MP^L-D)"0D)"0D)"0D)"0D(M$)`2+4`2!Z@`"`0"+@F@``0"C`````"0W"T0D
M"(F":``!`,.-="8`C;PG`````(/L((E<)!")="04B7PD&(EL)!R+7"0D#[9,
-M)"@/MGPD+#F;2`4``'5\B<C`Z`*]``````^VT(G(@^`#C31`N`<```")\=/@
-M]]`C1),\B40D#(E$DSR)^(3`=`^X!````-/@"T0D#(E$DSR+1),\B40D"(GJ
-M#[;"P>`(!5#"``")1"0$BX-(!0``B00DZ/S___^+7"00BW0D%(M\)!B+;"0<
+M)"@/MGPD+#F;1`4``'5\B<C`Z`*]``````^VT(G(@^`#C31`N`<```")\=/@
+M]]`C1),XB40D#(E$DSB)^(3`=`^X!````-/@"T0D#(E$DSB+1),XB40D"(GJ
+M#[;"P>`(!5#"``")1"0$BX-$!0``B00DZ/S___^+7"00BW0D%(M\)!B+;"0<
M@\0@PXG(P.@"@^@$O0$```#I?/___XGVC;PG`````%575E.#[!R+?"0P#[9$
M)#2(1"0;#[94)#B(5"0:#[9L)#R+1PB+,(DT).C\____B<.%P`^$^````(DT
M).C\____B<*%P`^$Y@```,9'-`'&0R3AQD,E`<9#)A#&0Q6[#[9',V:)0Q")
M<QC'0R"0````C4((B4,TB5-0B<&)PK@`````Q@00`(/``3V0````=?+&00&"
-MQ@%`#[9$)!N(00(/ME0D&HA1`XGHB$$$/`)W(XU!"(GI#[;1P>("C8Z$"P``
-MB50D"(E,)`2)!"3H_/___^LWBX:$"P``B4$(BX:("P``B4$,@\$0B>H/ML*-
-M!(7X____C9:,"P``B40D"(E4)`2)#"3H_/___\=#;`````#'1"0$`````(U#
+MQ@%`#[9$)!N(00(/ME0D&HA1`XGHB$$$/`)W(XU!"(GI#[;1P>("C8Z`"P``
+MB50D"(E,)`2)!"3H_/___^LWBX:`"P``B4$(BX:$"P``B4$,@\$0B>H/ML*-
+M!(7X____C9:("P``B40D"(E4)`2)#"3H_/___\=#;`````#'1"0$`````(U#
M/(D$).C\____B5PD!(DT).C\____@\0<6UY?7<.-M"8`````@^PLB5PD'(ET
M)"")?"0DB6PD*(M\)#"+;"0TBT0D.(E$)!B+5"0\B50D%(M'"(LPB30DZ/S_
M__^)PX7`#X2`````B30DZ/S___^)PH7`='+&1S0!QD,DX<9#)0'&0R80QD,5
@@ -5059,17 +3683,17 @@ M&(A0`P^V5"04B%`$QT-L`````,=$)`0`````C4,\B00DZ/S___^)7"0$B30D
MZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPXUV`(V\)P````!55U93@^P<BW0D
M,`^V;"0T#[9$)#B(1"0;BT8(BQC'1"0,`@```,=$)`@`````QT0D!`````")
M-"3H_/___X!^-`!T&HD<).C\____QP0D`0```.C\____@'XT`'7FBT8(BP`%
-MA`L``(!X`@!X1(!(`H#'1"0,`0```,=$)`@`````QT0D!`````")-"3H_/__
+M@`L``(!X`@!X1(!(`H#'1"0,`0```,=$)`@`````QT0D!`````")-"3H_/__
M_X!^-`!T&HD<).C\____QP0D`0```.C\____@'XT`'7FB>C`Z`(/MOC'1"0,
M`0```(E\)`C'1"0$`P```(DT).C\____@'XT`'0>C70F`(D<).C\____QP0D
-M`0```.C\____@'XT`'7FBT8(BQB)Z??1@^$#@'PD&P`/E<+!X@,/MH0+A`L`
-M`(/@YPG0B(0+A`L``,=$)`P!````B7PD",=$)`0#````B30DZ/S___^#Q!Q;
+M`0```.C\____@'XT`'7FBT8(BQB)Z??1@^$#@'PD&P`/E<+!X@,/MH0+@`L`
+M`(/@YPG0B(0+@`L``,=$)`P!````B7PD",=$)`0#````B30DZ/S___^#Q!Q;
M7E]=PXVT)@````"#[!R)7"0,B70D$(E\)!2);"08BUPD((MT)"0/MT809CV%
-M`'<;BZNT!0``#[?`#[:$`[P$``!I^!0-``#K#8GVBZNT!0``O^P&#0"+1C2`
-M>`$"=22-BX0+``"-4`2+0`2)@X0+``"+0@2)002+0@B)00B+0@R)00R+1E"%
+M`'<;BZNP!0``#[?`#[:$`[@$``!I^!0-``#K#8GVBZNP!0``O^P&#0"+1C2`
+M>`$"=22-BX`+``"-4`2+0`2)@X`+``"+0@2)002+0@B)00B+0@R)00R+1E"%
MP'0,B40D!(D<).C\____B70D!(D<).C\____QD0]-`"+7"0,BW0D$(M\)!2+
-M;"08@\0<PX/L$(D<)(ET)`2)?"0(B6PD#(M,)!2+="08BU0D'(M<)""+N7P%
-M```/MT80O=@F`0!F/84`=Q$/M\`/MH0!O`0``&GH*`$``(V*(`0``,:"(`0`
+M;"08@\0<PX/L$(D<)(ET)`2)?"0(B6PD#(M,)!2+="08BU0D'(M<)""+N7@%
+M```/MT80O=@F`0!F/84`=Q$/M\`/MH0!N`0``&GH*`$``(V*(`0``,:"(`0`
M`"=F@7XDX0%U(P^V5B:-0O\\`7<)#[96)X/B#^LDC4+ON@\````\`788C78`
MC00ON@````"#>#0`=`</ME!-@^(/#[9!`8/@\`G0B$$!N`$```!F@7XDX0%U
M$@^V1B:#Z`$\`0^7P`^VP(UV`(G"P>('#[9!`8/@?PG0B$$!#[9#!HA!`@^V
@@ -5104,7 +3728,7 @@ M^I&0C70F`'1,@/KA#X5*`P``D(UT)@#ID@```(E,)`@/ML")1"0$B1PDZ/S_
M___'1"0,`0```.DH`P``B4PD!(D<).C\____QT0D#`$```#I#P,``(E,)`B)
M7"0$BT0D&(D$).C\____QT0D#`$```#I[@(``/9#*`%T(<9!!G#&000`QD$#
M`,9!`@#&005`QT0D#`$```#IQP(``,9!!N#'1"0,`0```.FV`@``@'LE`0^%
-MI`(``(![)AP/AYH"```/MD,FD/\DA3`5``#&00<$QT0D#`$```#IA0(``,9!
+MI`(``(![)AP/AYH"```/MD,FD/\DA=`*``#&00<$QT0D#`$```#IA0(``,9!
M!P#'1"0,`0```.ET`@``QD$&[,=$)`P!````Z6,"``#&00;OQ@$##[9#)X/(
M0(A!`<=$)`P!````Z44"``#&00;OQ@$'QT0D#`$```#I,0(``,9!!D#&00$!
MQD$%0,=$)`P!````Z1@"``#&00;OQ@$##[9#)X/("(A!`<=$)`P!````Z?H!
@@ -5142,257 +3766,257 @@ M$,'@!`^VR<'A"`G!@'PD#`!T`X/)!(/^_W00B?`E__\#`(F"!,;__X/)`HD+
MBQPDBW0D!(/$",.0BT`$+0`"`0"#R@&)D`#(``##C;0F`````(V\)P````!7
M5E.#[!")UXM`!(72=$J-L`#&__^+@`#&__^C`````+L`````J`%U$NLGD(UT
M)@"+!J,`````J`%T%\<$)`H```#H_/___X/#`3G[=>*)]NL'N`````#K!;C_
-M____@\006UY?PXUT)@"-O"<`````5E.#["2+7"0PQT0D(`````"+<P3&@[P,
+M____@\006UY?PXUT)@"-O"<`````5E.#["2+7"0PQT0D(`````"+<P3&@[@,
M````#[8-2`$``(U4)"#'1"0(`````,=$)`0"````QP0D`0```(G8Z-S^__^+
M5"0@B=CH(?___[J@A@$`B=CH-?___X7`=4>+A@S&__^C`````(E$)"`]'V,`
-M`'4QQX.L#```'V,``,>#L`P`````!`#'@[0,``````$`QX/`#```0`$``&:X
-M``#I.@(``,=$)"``````BW,$QH.\#````0^V#5@!``"-5"0@QT0D"/_____'
+M`'4QQX.H#```'V,``,>#K`P`````!`#'@[`,``````$`QX.\#```0`$``&:X
+M``#I.@(``,=$)"``````BW,$QH.X#````0^V#5@!``"-5"0@QT0D"/_____'
M1"0$`@```,<$)`$```")V.@__O__BU0D((G8Z(3^__^Z$"<``(G8Z)C^__^%
-MP'5GBX8,QO__HP````")1"0@/1]#``!T+CT?1```=4K'@ZP,```?1```QX.P
-M#``````'`,>#M`P``````0#IA`$``(UT)@#'@ZP,```?0P``QX.P#``````$
-M`,>#M`P``````0#I70$``,=$)"``````BW,$QH.\#`````^V#6@!``"-5"0@
+MP'5GBX8,QO__HP````")1"0@/1]#``!T+CT?1```=4K'@Z@,```?1```QX.L
+M#``````'`,>#L`P``````0#IA`$``(UT)@#'@Z@,```?0P``QX.L#``````$
+M`,>#L`P``````0#I70$``,=$)"``````BW,$QH.X#`````^V#6@!``"-5"0@
MQT0D"`````#'1"0$`@```,<$)`$```")V.B"_?__BU0D((G8Z,?]__^Z$"<`
-M`(G8Z-O]__^%P'5'BX8,QO__HP````")1"0@/;]#``!U,<>#K`P``+]#``#'
-M@[`,`````"``QX.T#````!```,>#P`P``&`!``!FN```Z>````#'1"0@````
-M`(MS!,:#O`P````/M@UX`0``C50D(,=$)`@`````QT0D!`(```#'!"0!````
+M`(G8Z-O]__^%P'5'BX8,QO__HP````")1"0@/;]#``!U,<>#J`P``+]#``#'
+M@ZP,`````"``QX.P#````!```,>#O`P``&`!``!FN```Z>````#'1"0@````
+M`(MS!,:#N`P````/M@UX`0``C50D(,=$)`@`````QT0D!`(```#'!"0!````
MB=CHY?S__XM4)"")V.@J_?__NA`G``")V.@^_?__A<!U7XN&#,;__Z,`````
-MB40D(#WO$0``=`D][Q(``'5"ZR#'@ZP,``#O$0``QX.P#``````$`,>#M`P`
-M`````0#K/,>#K`P``.\2``#'@[`,``````@`QX.T#``````!`.L<N/_____K
-M)(UT)@#'@\`,``!0`0``N`````#K#\>#P`P``'`!``"X`````(/$)%M>PXUV
+MB40D(#WO$0``=`D][Q(``'5"ZR#'@Z@,``#O$0``QX.L#``````$`,>#L`P`
+M`````0#K/,>#J`P``.\2``#'@ZP,``````@`QX.P#``````!`.L<N/_____K
+M)(UT)@#'@[P,``!0`0``N`````#K#\>#O`P``'`!``"X`````(/$)%M>PXUV
M`(V\)P````"#[#R)7"0LB70D,(E\)#2);"0XB<:)UXE,)!B+:`0/MD0D0#P$
-M=@6X!`````^VV(N&P`P```^V2`2-5"0HB7PD"(E<)`3'!"0!````B?#HW?O_
+M=@6X!`````^VV(N&O`P```^V2`2-5"0HB7PD"(E<)`3'!"0!````B?#HW?O_
M_XM4)"B)\.@B_/__NA`G``")\.@V_/__NO____^%P'4:BX4,QO__HP````")
M1"0HBU0D&(D"N@````")T(M<)"R+="0PBWPD-(ML)#B#Q#S#C;8`````C;PG
-M`````%.#["B+7"0PBX/`#```#[9("XU4)"2+1"0TB40D",=$)`0!````QP0D
+M`````%.#["B+7"0PBX.\#```#[9("XU4)"2+1"0TB40D",=$)`0!````QP0D
M`0```(G8Z$S[__^+5"0DB=CHD?O__[H0)P``B=CHI?O__[K_____A<!U&HM#
M!"WT.0``BP"C`````(M4)#B(`KH`````B="#Q"A;PXUT)@"-O"<`````55=6
-M4X/L+(G#B%0D&XG-@WPD0``/A),```"^`````)"+>P2+@\`,```/MD@"QT0D
+M4X/L+(G#B%0D&XG-@WPD0``/A),```"^`````)"+>P2+@[P,```/MD@"QT0D
M"/_____'1"0$`0```,<$)`$```"-5"0HB=CHL?K__XM4)"B)V.CV^O__NA`G
M``")V.@*^___A<!U*HN7#,;__XD5``````^V1"0;(=")Z3C(=0VX`````.LH
MC;8`````B50D*,<$)`H```#H_/___X/&`3MT)$`/A7/___^X_____X/$+%M>
-M7UW#C;8`````4X/L*(G#BX#`#```#[8(C50D),=$)`C_____QT0D!`````#'
+M7UW#C;8`````4X/L*(G#BX"\#```#[8(C50D),=$)`C_____QT0D!`````#'
M!"0`````B=CH#_K__XM4)"2)V.A4^O__NA`G``")V.AH^O__A<!U),<$)."3
M!`"Y`@```+H#````B=CHW/[__[H`````A<!T"(UV`+K_____B="#Q"A;PXUT
M)@"#["R)7"0DB70D*(M<)#"+="0TQD0D(_^-1"0CB40D"(ET)`2)'"3H_/__
-M_X7`=7*`?"0C`'1YB=CH0O___X/X_W1?BX/`#```#[9("HU4)!R)="0(QT0D
+M_X7`=7*`?"0C`'1YB=CH0O___X/X_W1?BX.\#```#[9("HU4)!R)="0(QT0D
M!`````#'!"0`````B=CH5?G__XM4)!R)V.B:^?__NA`G``")V.BN^?__A<!U
M',<$)."3!`"Y`````+H#````B=CH(O[__X7`=`ZX_____^L,C;0F`````+@`
M````BUPD)(MT)"B#Q"S#ZPV0D)"0D)"0D)"0D)"055=64X/L/(ML)%`/MD0D
-M8(.]P`P````/A!H#``"+?"18A,`/A&L!``"#?"14_W44#[>%K`P``&:)![@!
-M````Z1P#``"#?"14_G45BX6P#```B0>X`0```.D#`P``C78`@WPD5/UU&8N%
-MM`P``(D'N`$```#IYP(``(VT)@````"+1"1<`T0D5(E$)!@[A;`,```/AY\"
+M8(.]O`P````/A!H#``"+?"18A,`/A&L!``"#?"14_W44#[>%J`P``&:)![@!
+M````Z1P#``"#?"14_G45BX6L#```B0>X`0```.D#`P``C78`@WPD5/UU&8N%
+ML`P``(D'N`$```#IYP(``(VT)@````"+1"1<`T0D5(E$)!@[A:P,```/AY\"
M``"+7"14@^/\BU0D5(/B`XE4)"!T;HUT)#C'!"0$````B?&)VHGHZ/[[__^#
MPP3'1"0<!````#E<)!AS$(M$)"`K1"14`T0D&(E$)!R+1"0@.40D''8MC0P&
MB?Z+1"0<C50$.(VV``````^V`8@&@\8!@\$!.=%U\8M$)!PK1"0@C3P'BW0D
M&(/F_#GS<R3'!"0$````C4PD.(G:B>CHA_O__XM$)#B)!X/'!(/#!#G>=]PY
M7"08#X;M`0``C70D.,<$)`0```")\8G:B>CH5_O__XM,)!@IV0^$RP$``+H`
M````C;8`````#[8$%H@$.H/"`3G*#X2N`0``Z^R#?"14_W4I@#\/B?9U$<:%
-MO0P```&X`0```.FM`0``QH6]#````+@!````Z9P!``"+5"1<B50D*(G0`T0D
-M5#N%L`P```^'60$``("]O0P````/A$P!``"+1"14N@````#WM;0,``"%T@^%
-MG````("]O`P```!T&(M$)%2)1"0$B2PDZ/S___^%P`^%%`$``(GHZ(;\__^#
-M^/\/A`0!``"+A<`,```/MD@&C50D.(M$)%2)1"0(QT0D!`````#'!"0`````
+MN0P```&X`0```.FM`0``QH6Y#````+@!````Z9P!``"+5"1<B50D*(G0`T0D
+M5#N%K`P```^'60$``("]N0P````/A$P!``"+1"14N@````#WM;`,``"%T@^%
+MG````("]N`P```!T&(M$)%2)1"0$B2PDZ/S___^%P`^%%`$``(GHZ(;\__^#
+M^/\/A`0!``"+A;P,```/MD@&C50D.(M$)%2)1"0(QT0D!`````#'!"0`````
MB>CHD?;__XM4)#B)Z.C6]O__NA`G``")Z.CJ]O__A<`/A;D```#'!"3@DP0`
MN0````"Z`P```(GHZ%K[__^%P`^%F0```(-\)%P`#X27````QT0D)`````"+
-M5"18BT0D)(LT`HG'`WPD5(M=!('K``(!`(GHZ-[[__^)LPC(``"+A<`,```/
+M5"18BT0D)(LT`HG'`WPD5(M=!('K``(!`(GHZ-[[__^)LPC(``"+A;P,```/
MMD@%B7PD",=$)`0$````QP0D`````(U4)#B)Z.CP]?__BU0D.(GHZ#7V__^Z
M$"<``(GHZ$GV__^%P'4<QP0DB!,``+D`````N@$```")Z.B]^O__A<!T$+@`
M````ZR*)]K@!````ZQF#1"0D!(M4)"0Y5"0H=NKI5O___Y"-="8`@\0\6UY?
-M7<.0D)"0D)"0D+@`````PXUV`(V\)P````"+5"0$BTPD"+@`````.14`&```
+M7<.0D)"0D)"0D+@`````PXUV`(V\)P````"+5"0$BTPD"+@`````.16@#0``
M?C2-%%+!X@,/MX(<`@``9HD!#[>"'@(``&:)00(/MH(D`@``B$$(#[:")0(`
-M`(A!";@!````\\.0C70F`+B8&P``PXUV`(V\)P````"XG````,.-=@"-O"<`
+M`(A!";@!````\\.0C70F`+B0&P``PXUV`(V\)P````"XG````,.-=@"-O"<`
M````N`0```##C78`C;PG`````%=64XMT)!"[`````+\`````N0`````/MI0Q
-M/`4``(#Z_W1"C8&`````9CV!`'<%@\,!ZS$/ML*+EI@%``!IP+````"`O!"E
+M.`4``(#Z_W1"C8&`````9CV!`'<%@\,!ZS$/ML*+EI0%``!IP+````"`O!"E
M`````W45@\<!C4<#@_@&=@V#PP&_`````.L#@\,!@\$!@_D&=:F)V%M>7\.-
MM@````"-O"<`````55=64X/L!(ML)!B^`````,<$)`````"[@`````^V1"0<
-MC7@!B=D/MH0KO`0``#S_=$EF@?N!`'<'@\8!ZSF)]@^VP(N5F`4``&G`L```
+MC7@!B=D/MH0KN`0``#S_=$EF@?N!`'<'@\8!ZSF)]@^VP(N5E`4``&G`L```
M`("\$*4````#=1N#!"0!BP0D@\`#@_@&=@^#Q@''!"0`````ZP.#Q@$Y]W00
M@\,!@?N&````=9ZY`````(G(@\0$6UY?7<.-="8`C;PG`````//#C;0F````
M`(V\)P````"+1"0$QH"7`````,.-="8`5E.+7"0,N/\```"%VW1,N8(```"^
-M_____XVT)@`````/MH09O`0``#S_=!\/ML"+DY@%``!IP+`````/MH00I```
+M_____XVT)@`````/MH09N`0``#S_=!\/ML"+DY0%``!IP+`````/MH00I```
M`(GR.,)V`HG&@\$!@?F&````=<J)\@^VPEM>PXGVN`````##C78`C;PG````
-M`%=64XM$)!"+F$@%``"^`````+\`````N0````"-="8`#[:4&3P%``"`^O]T
-M1HV!@````&8]@0!W!X/&`>LUB?8/ML*+DY@%``!IP+````"`O!"E`````W47
-M@\<!C4<#@_@&=@^#Q@&_`````.L%B?:#Q@&#P0&#^09UI8N;2`4``('#S`P`
-M`+$`C;0F``````^VE!D\!0``@/K_=$:-@8````!F/8$`=P>#Q@'K-8GV#[;"
-MBY.8!0``:<"P````@+P0I0````-U%X/'`8U'`X/X!G8/@\8!OP````#K!8GV
+M`%=64XM$)!"+F$0%``"^`````+\`````N0````"-="8`#[:4&3@%``"`^O]T
+M1HV!@````&8]@0!W!X/&`>LUB?8/ML*+DY0%``!IP+````"`O!"E`````W47
+M@\<!C4<#@_@&=@^#Q@&_`````.L%B?:#Q@&#P0&#^09UI8N;1`4``('#R`P`
+M`+$`C;0F``````^VE!DX!0``@/K_=$:-@8````!F/8$`=P>#Q@'K-8GV#[;"
+MBY.4!0``:<"P````@+P0I0````-U%X/'`8U'`X/X!G8/@\8!OP````#K!8GV
M@\8!@\$!@_D&=:6)\%M>7\/K#9"0D)"0D)"0D)"0D)")P8G0P.@$/`EV!8/`
M5^L#@\`PB`&)T(/@#X/X"7X1B="#X`^#P%?K#XVT)@````")T(/@#X/`,(A!
M`<.-="8`@^P(B1PDB70D!(G&B=,/MM;HJO___P^VVX/&`HG:B?#HF____XL<
M)(MT)`2#Q`C#BT0D#,=`!`````#'``````"X`````,.)]HV\)P````"+3"0$
MBT%@A<!T1<=`(`````"`2"@$QT%@`````,=!:`````#'060`````BU$(@_H_
-M?P^+06S'A)"\`@```````,.+06S'A)"\`0```````//#C;0F`````(V\)P``
+M?P^+06S'A)"X`@```````,.+06S'A)"X`0```````//#C;0F`````(V\)P``
M``"+3"0$BT%@A<!T1<=`(`````"`8"C[QT%@`````,=!:`````#'060`````
-MBU$(@_H_?P^+06S'A)"\`@```````,.+06S'A)"\`0```````//#C;0F````
+MBU$(@_H_?P^+06S'A)"X`@```````,.+06S'A)"X`0```````//#C;0F````
M`(V\)P````"#[`S'!"2``0``Z/S___^X`````(/$#,.0C;0F`````%=64X/L
M0(M$)%#&1"08;<9$)!G_QD0D&B/&1"0;%,9$)!PZQD0D'>_&1"0>%L9$)!^2
-MB[!,!0``A?9U`HG&C40D((G"Q@``@\`!B=.-3"1`.<AU\,9$)"0!QT0D#"``
+MB[!(!0``A?9U`HG&C40D((G"Q@``@\`!B=.-3"1`.<AU\,9$)"0!QT0D#"``
M``")5"0(QT0D!`X```")-"3H_/___X7`=4S'!"2`&@8`Z/S____'1"0,(```
M`(E<)`C'1"0$#P```(DT).C\____@_@@=1^-="0PC7PD&+D(````_/.F#Y?"
-M#Y+`N0$````XPG01QP0D)`,``.C\____N0`````/ML&#Q$!;7E_#55=64X/L
-M7(M$)'"+D$@%``"!PLP,``")5"0XB<&+`(7`=!8M```"`(D!B40D!(M!$(D$
+M#Y+`N0$````XPG01QP0D&`(``.C\____N0`````/ML&#Q$!;7E_#55=64X/L
+M7(M$)'"+D$0%``"!PL@,``")5"0XB<&+`(7`=!8M```"`(D!B40D!(M!$(D$
M).C\____BUPD<(M#"(7`=`^)1"0$BT,0B00DZ/S___^+5"1PBT(,A<!T#XE$
M)`2+0A")!"3H_/___XU$)$Z)1"0TC40D4(E$)#"-1"1*B40D+(U$)$R)1"0H
MC40D5(E$)"2-1"16B40D((U$)%>)1"0<C40D4HE$)!B-1"18B40D%(U$)$B)
M1"00C40D68E$)`R-1"1:B40D"(U$)%N)1"0$BTPD<`^W022)!"3H_/___XM<
-M)'"+@WP%``"%P'0PB40D!(G8!60%``")!"3H_/___XM4)#B+@GP%``")1"0$
-MB=`%9`4``(D$).C\____BTPD<(N!F`4``(7`=#")1"0$B<@%@`4``(D$).C\
-M____BUPD.(N#F`4``(E$)`2)V`6`!0``B00DZ/S___^+5"1PBX*T!0``A<!T
-M,(E$)`2)T`6<!0``B00DZ/S___^+3"0XBX&T!0``B40D!(G(!9P%``")!"3H
-M_/___XM<)'"+@^P&``"%P'0PB40D!(G8!=0&``")!"3H_/___XM4)#B+@NP&
-M``")1"0$B=`%U`8``(D$).C\____@'PD6P!T6KX`````BVPD<('%#`<``(M\
-M)#B!QPP'``"-=@`/M]Z+3"1PBX29)`<``(E$)`2)+"3H_/___XM4)#B+A)HD
-M!P``B40D!(D\).C\____@\8!#[9$)%MF.?!WPHM,)'"+@8P)``"%P'0PB40D
-M!(G(!70)``")!"3H_/___XM<)#B+@XP)``")1"0$B=@%=`D``(D$).C\____
-MBU0D<(N"M`D``(7`=#")1"0$B=`%G`D``(D$).C\____BTPD.(N!M`D``(E$
-M)`2)R`6<"0``B00DZ/S___^+7"1PBX,$"@``A<!T,(E$)`2)V`7L"0``B00D
-MZ/S___^+5"0XBX($"@``B40D!(G0!>P)``")!"3H_/___XM,)'"+@=`%``"%
-MP'0PB40D!(G(!;@%``")!"3H_/___XM<)#B+@]`%``")1"0$B=@%N`4``(D$
-M).C\____BU0D<(N"?`8``(7`=#")1"0$B=`%9`8``(D$).C\____BTPD.(N!
-M?`8``(E$)`2)R`5D!@``B00DZ/S___^+7"1PBX,L!@``A<!T,(E$)`2)V`44
-M!@``B00DZ/S___^+5"0XBX(L!@``B40D!(G0!10&``")!"3H_/___XM,)'"+
-M@4@&``"%P'0PB40D!(G(!3`&``")!"3H_/___XM<)#B+@T@&``")1"0$B=@%
-M,`8``(D$).C\____BU0D<(N"M`8``(7`=#")1"0$B=`%G`8``(D$).C\____
-MBTPD.(N!M`8``(E$)`2)R`6<!@``B00DZ/S___^+7"1PBX/0!@``A<!T,(E$
-M)`2)V`6X!@``B00DZ/S___^+5"0XBX+0!@``B40D!(G0!;@&``")!"3H_/__
-M_XM,)'"+@0@'``"%P'0PB40D!(G(!?`&``")!"3H_/___XM<)#B+@P@'``")
-M1"0$B=@%\`8``(D$).C\____BU0D<(N"/`D``(7`=#")1"0$B=`%)`D``(D$
-M).C\____BTPD.(N!/`D``(E$)`2)R`4D"0``B00DZ/S___^+7"1PBX-D"0``
-MA<!T,(E$)`2)V`5,"0``B00DZ/S___^+5"0XBX)D"0``B40D!(G0!4P)``")
-M!"3H_/___XM,)'"+@=P)``"%P'0PB40D!(G(!<0)``")!"3H_/___XM<)#B+
-M@]P)``")1"0$B=@%Q`D``(D$).C\____BU0D<(N"F`8``(7`=#")1"0$B=`%
-M@`8``(D$).C\____BTPD.(N!F`8``(E$)`2)R`6`!@``B00DZ/S___^+7"1P
-MBXL@"@``A<ET6(N#)`H``(N3*`H``(E$)`B)5"0,B4PD!(G8!0@*``")!"3H
-M_/___XM,)#B+@20*``"+D2@*``")1"0(B50D#(N!(`H``(E$)`2)R`4("@``
-MB00DZ/S___^+7"1PBXM$"@``A<ET6(N#2`H``(N33`H``(E$)`B)5"0,B4PD
-M!(G8!2P*``")!"3H_/___XM,)#B+@4@*``"+D4P*``")1"0(B50D#(N!1`H`
-M`(E$)`2)R`4L"@``B00DZ/S___^+7"1PBXMH"@``A<ET6(N#;`H``(N3<`H`
-M`(E$)`B)5"0,B4PD!(G8!5`*``")!"3H_/___XM,)#B+@6P*``"+D7`*``")
-M1"0(B50D#(N!:`H``(E$)`2)R`50"@``B00DZ/S___^+7"1PBXNP"@``A<ET
-M6(N#M`H``(N3N`H``(E$)`B)5"0,B4PD!(G8!9@*``")!"3H_/___XM,)#B+
-M@;0*``"+D;@*``")1"0(B50D#(N!L`H``(E$)`2)R`68"@``B00DZ/S___^+
-M7"1PBXN,"@``A<ET6(N#D`H``(N3E`H``(E$)`B)5"0,B4PD!(G8!70*``")
-M!"3H_/___XM,)#B+@9`*``"+D90*``")1"0(B50D#(N!C`H``(E$)`2)R`5T
-M"@``B00DZ/S___^+7"1PBXO4"@``A<ET6(N#V`H``(N3W`H``(E$)`B)5"0,
-MB4PD!(G8!;P*``")!"3H_/___XM,)#B+@=@*``"+D=P*``")1"0(B50D#(N!
-MU`H``(E$)`2)R`6\"@``B00DZ/S___^+7"1PBXOX"@``A<ET6(N#_`H``(N3
-M``L``(E$)`B)5"0,B4PD!(G8!>`*``")!"3H_/___XM,)#B+@?P*``"+D0`+
-M``")1"0(B50D#(N!^`H``(E$)`2)R`7@"@``B00DZ/S___^+7"1PBXL<"P``
-MA<ET6(N#(`L``(N3)`L``(E$)`B)5"0,B4PD!(G8!00+``")!"3H_/___XM,
-M)#B+@2`+``"+D20+``")1"0(B50D#(N!'`L``(E$)`2)R`4$"P``B00DZ/S_
+M)'"+@W@%``"%P'0PB40D!(G8!6`%``")!"3H_/___XM4)#B+@G@%``")1"0$
+MB=`%8`4``(D$).C\____BTPD<(N!E`4``(7`=#")1"0$B<@%?`4``(D$).C\
+M____BUPD.(N#E`4``(E$)`2)V`5\!0``B00DZ/S___^+5"1PBX*P!0``A<!T
+M,(E$)`2)T`68!0``B00DZ/S___^+3"0XBX&P!0``B40D!(G(!9@%``")!"3H
+M_/___XM<)'"+@^@&``"%P'0PB40D!(G8!=`&``")!"3H_/___XM4)#B+@N@&
+M``")1"0$B=`%T`8``(D$).C\____@'PD6P!T6KX`````BVPD<('%"`<``(M\
+M)#B!QP@'``"-=@`/M]Z+3"1PBX29(`<``(E$)`2)+"3H_/___XM4)#B+A)H@
+M!P``B40D!(D\).C\____@\8!#[9$)%MF.?!WPHM,)'"+@8@)``"%P'0PB40D
+M!(G(!7`)``")!"3H_/___XM<)#B+@X@)``")1"0$B=@%<`D``(D$).C\____
+MBU0D<(N"L`D``(7`=#")1"0$B=`%F`D``(D$).C\____BTPD.(N!L`D``(E$
+M)`2)R`68"0``B00DZ/S___^+7"1PBX,`"@``A<!T,(E$)`2)V`7H"0``B00D
+MZ/S___^+5"0XBX(`"@``B40D!(G0!>@)``")!"3H_/___XM,)'"+@<P%``"%
+MP'0PB40D!(G(!;0%``")!"3H_/___XM<)#B+@\P%``")1"0$B=@%M`4``(D$
+M).C\____BU0D<(N">`8``(7`=#")1"0$B=`%8`8``(D$).C\____BTPD.(N!
+M>`8``(E$)`2)R`5@!@``B00DZ/S___^+7"1PBX,H!@``A<!T,(E$)`2)V`40
+M!@``B00DZ/S___^+5"0XBX(H!@``B40D!(G0!1`&``")!"3H_/___XM,)'"+
+M@40&``"%P'0PB40D!(G(!2P&``")!"3H_/___XM<)#B+@T0&``")1"0$B=@%
+M+`8``(D$).C\____BU0D<(N"L`8``(7`=#")1"0$B=`%F`8``(D$).C\____
+MBTPD.(N!L`8``(E$)`2)R`68!@``B00DZ/S___^+7"1PBX/,!@``A<!T,(E$
+M)`2)V`6T!@``B00DZ/S___^+5"0XBX+,!@``B40D!(G0!;0&``")!"3H_/__
+M_XM,)'"+@00'``"%P'0PB40D!(G(!>P&``")!"3H_/___XM<)#B+@P0'``")
+M1"0$B=@%[`8``(D$).C\____BU0D<(N".`D``(7`=#")1"0$B=`%(`D``(D$
+M).C\____BTPD.(N!.`D``(E$)`2)R`4@"0``B00DZ/S___^+7"1PBX-@"0``
+MA<!T,(E$)`2)V`5("0``B00DZ/S___^+5"0XBX)@"0``B40D!(G0!4@)``")
+M!"3H_/___XM,)'"+@=@)``"%P'0PB40D!(G(!<`)``")!"3H_/___XM<)#B+
+M@]@)``")1"0$B=@%P`D``(D$).C\____BU0D<(N"E`8``(7`=#")1"0$B=`%
+M?`8``(D$).C\____BTPD.(N!E`8``(E$)`2)R`5\!@``B00DZ/S___^+7"1P
+MBXL<"@``A<ET6(N#(`H``(N3)`H``(E$)`B)5"0,B4PD!(G8!00*``")!"3H
+M_/___XM,)#B+@2`*``"+D20*``")1"0(B50D#(N!'`H``(E$)`2)R`4$"@``
+MB00DZ/S___^+7"1PBXM`"@``A<ET6(N#1`H``(N32`H``(E$)`B)5"0,B4PD
+M!(G8!2@*``")!"3H_/___XM,)#B+@40*``"+D4@*``")1"0(B50D#(N!0`H`
+M`(E$)`2)R`4H"@``B00DZ/S___^+7"1PBXMD"@``A<ET6(N#:`H``(N3;`H`
+M`(E$)`B)5"0,B4PD!(G8!4P*``")!"3H_/___XM,)#B+@6@*``"+D6P*``")
+M1"0(B50D#(N!9`H``(E$)`2)R`5,"@``B00DZ/S___^+7"1PBXNL"@``A<ET
+M6(N#L`H``(N3M`H``(E$)`B)5"0,B4PD!(G8!90*``")!"3H_/___XM,)#B+
+M@;`*``"+D;0*``")1"0(B50D#(N!K`H``(E$)`2)R`64"@``B00DZ/S___^+
+M7"1PBXN("@``A<ET6(N#C`H``(N3D`H``(E$)`B)5"0,B4PD!(G8!7`*``")
+M!"3H_/___XM,)#B+@8P*``"+D9`*``")1"0(B50D#(N!B`H``(E$)`2)R`5P
+M"@``B00DZ/S___^+7"1PBXO0"@``A<ET6(N#U`H``(N3V`H``(E$)`B)5"0,
+MB4PD!(G8!;@*``")!"3H_/___XM,)#B+@=0*``"+D=@*``")1"0(B50D#(N!
+MT`H``(E$)`2)R`6X"@``B00DZ/S___^+7"1PBXOT"@``A<ET6(N#^`H``(N3
+M_`H``(E$)`B)5"0,B4PD!(G8!=P*``")!"3H_/___XM,)#B+@?@*``"+D?P*
+M``")1"0(B50D#(N!]`H``(E$)`2)R`7<"@``B00DZ/S___^+7"1PBXL8"P``
+MA<ET6(N#'`L``(N3(`L``(E$)`B)5"0,B4PD!(G8!0`+``")!"3H_/___XM,
+M)#B+@1P+``"+D2`+``")1"0(B50D#(N!&`L``(E$)`2)R`4`"P``B00DZ/S_
M__^#Q%Q;7E]=PXVV`````(/L'(E<)!2)="08BUPD((D<).C\____B1PDZ/S_
-M__^-L\P,``")-"3H_/___XD<).C\____QP0DT`<``.C\____B1PDZ/S____'
+M__^-L\@,``")-"3H_/___XD<).C\____QP0DT`<``.C\____B1PDZ/S____'
M1"0$`0```(D<).C\____QT0D!`$```")-"3H_/___XM<)!2+="08@\0<PXUT
-M)@"-O"<`````@^P<B5PD%(ET)!B+="0@BUPD)(A>-P^VVXE<)`2)-"3H_/__
-M_XE<)`2!QLP,``")-"3H_/___[@!````BUPD%(MT)!B#Q!S#D(VT)@````!3
-M@^P(BUPD$(D<).C\____BX-(!0``!<P,``")!"3H_/___X/$"%O#D(VT)@``
-M``!3@^P(BUPD$(D<).C\____BX-(!0``!<P,``")!"3H_/___X/$"%O#D(VT
-M)@````"#[`R+1"00B00DZ/S___\/ML"#Q`S#C78`C;PG`````(/L+(E<)!R)
-M="0@B7PD)(EL)"B)PXG7B<V+<&"+0&R)1"04A?8/A#4!``"`NY<`````#X4H
-M`0``B00DZ/S___^)1"08A<`/A!0!``#&0"3AQD`E`8GZA-)T#8GH/`$9P/?0
-M@\`'ZPR)ZH#Z`1G`]]"#P`V+5"08B$(FQD(4@`^W1AQFB4(0B5H8QT(@````
-M`,="-`````#'0FQ`DP,`B50D!(M$)!2)!"3H_/___\:#EP````%FQX.4````
-M]`&%VW19BT-@A<!T7&:!NY0```"6`'47B40D",=$)`0A````BT`LB00DZ/S_
-M__]F@ZN4`````<<$)-`'``#H_/___XM4)!2)%"3H_/___XM#8(7`=`F`NY<`
-M````=:YF@[N4`````'0<BT0D&(!X%`!U$HM#8`^W0#IFB4-:NP````#K!;O_
-M____BU0D&(E4)`2+1"04B00DZ/S____K"8UT)@"[_____XG8BUPD'(MT)""+
-M?"0DBVPD*(/$+,.0C70F`(/L3(E<)#R)="1`B7PD1(EL)$B+="10#[9L)%2+
-M?F"+1FR)1"0@A?\/A/($``"`OI<`````#X7E!```B00DZ/S___^)1"0DA<`/
-MA-$$``#V!@(/A00!``")ZH#Z%'<+#[;"C01`P>`"ZQBXB?___XGJ]N)FP>@(
-MP.@$#[;`!?````"+5"0DQD(DX<9")0'&0B8<B$(GQD(4@`^W1QQFB4(0B7(8
-MQT(@`````,="-`````#'0FQ`DP,`B50D!(M$)"")!"3H_/___\:&EP````%F
-MQX:4````Q`F%]G19BT9@A<!T8&:!OI0```"6`'47B40D",=$)`0A````BT`L
-MB00DZ/S___]F@ZZ4`````<<$)-`'``#H_/___XM4)"")%"3H_/___XM&8(7`
-M=`F`OI<`````=:YF@[Z4``````^$O`,``+L`````BT0D)(!X%``/A*X#``#I
-MI`,``(M4)"")%"3H_/___XE$)#B%P`^$C`,``(M<)"2#PSR+0`B)1"0<BT0D
-M),9`)!K&0"4(QD`F&L9`)P#&0"@0QD`I`(M$)#B+5"0DB4)0QD(4@`^W1QQF
-MB4(0B7(8BT0D.(M`"(E"-,="(!````"+1F`%N````(E".,9"'"#'0FQ`DP,`
-MQT0D!`````")'"3H_/___XM4)"2+0B")1"0,BT0D.(M0$(M`#(E$)`2)5"0(
-MB1PDZ/S___^+1"0DB40D!(M4)"")%"3H_/___\:&EP````%FQX:4````^@"%
-M]G19BT9@A<!T7&:!OI0```"6`'47B40D",=$)`0A````BT`LB00DZ/S___]F
-M@ZZ4`````<<$)-`'``#H_/___XM$)"")!"3H_/___XM&8(7`=`F`OI<`````
-M=:YF@[Z4`````'0*BU0D)(!Z%`!T'HU$)#B)1"0$BT0D((D$).C\____N___
-M___I/@(``(M4)"2)5"0$BT0D((D$).C\____BU0D((D4).C\____B40D)(7`
-M=2&-1"0XB40D!(M$)"")!"3H_/___[O_____Z1@"``"-=@"+5"0D@\(\B50D
-M*(M,)!R#P02+5"0<#[9"`P^V!`&(0@3&00$*QD$"`+@`````BU0D',8$$`"#
-MP`&#^`1U\(GHA,!U!H!A`_SK38GH#[;0:=)@Z@``N!^%ZU'WZL'Z!8!)`P.)
-MU<'M&(GHB$$$B=/!ZQ"(606)T,'H"(E$)!B(00:(40>)Z(A!"(A9"0^V1"08
-MB$$*B%$+BT0D.(M4)"2)0E#&0B05#[8!P/@']]"#P!&(0B7&0B8`QD(G`,9"
-M*!#&0BD`@"$_QD(4@`^W1QQFB4(0B7(8BT0D.(M`"(E"-,="(!````"+1F`%
-MN````(E".,9"'"#'0FQ`DP,`QT0D!`````"+1"0HB00DZ/S___^+5"0DBT(@
-MB40D#(M$)#B+4!"+0`R)1"0$B50D"(M$)"B)!"3H_/___XM4)"2)5"0$BT0D
-M((D$).C\____QH:7`````6;'AI0```#Z`(7V=%F+1F"%P'1<9H&^E````)8`
-M=1>)1"0(QT0D!"$```"+0"R)!"3H_/___V:#KI0````!QP0DT`<``.C\____
-MBU0D((D4).C\____BT9@A<!T"8"^EP````!UKF:#OI0`````=`^[`````(M$
-M)"2`>!0`=`6[_____XU$)#B)1"0$BU0D((D4).C\____ZP:0N_____^+1"0D
-MB40D!(M4)"")%"3H_/___^L*D(UT)@"[_____XG8BUPD/(MT)$"+?"1$BVPD
-M2(/$3,.0C70F`(/L3(E<)#R)="1`B7PD1(EL)$B+?"10BUPD5(MT)%@/MT0D
-M7&:)1"0>#[94)&2(5"0=BV]@A>T/A.D#``"`OY<`````#X7<`P``BTTLB4PD
-M.(M';(E$)"1FQX>4````$">)!"3H_/___XE$)#2%P`^$L0,```^W5"0>B50D
-M(&:#?"0>!'82B50D!,<$)$`#``#H_/___^L4BTPD)(D,).C\____B40D*(7`
-M=1Z+1"0TB40D!(M4)"2)%"3H_/___[O_____Z78#``"+3"0@P>$)B4PD,(M4
-M)"2+@D@%``#&0"<!B7PD"(N"2`4``(E$)`3'!"0%````Z/S___^`32@"BT=@
-MB40D",=$)`0A````BTPD.(D,).C\____BT0D-(/`/(E$)"R`?"0=`'01BU0D
-M-,="9`H```#&0B0HZRZ+3"0TQT%D$@```,9!)"J+5"0HBT((BTPD,(E,)`B+
-M5"1@B50D!(D$).C\____BT=@]D`X`71Y@'PD'0$9P(/@`H/H>(M,)#2(023&
-M024`B?#!Z!B(02:)\,'H$(A!)XGPP>@(B$$HB?*(42F)V`^L\!B(02J)V`^L
-M\!"(02N)V`^L\`B(02R(62W&02X`QD$O``^W1"0>9L'H"(A!,`^V1"0>B$$Q
-MQD$R`,9!,P#K5H!\)!T!&<"#X`*#P"B+5"0TB$(DQD(E`(G8#ZSP&(M,)#2(
-M02:)V`^L\!"(02>)V`^L\`B(02B(62G&02H`#[=$)!YFP>@(B$$K#[9$)!Z(
-M02S&02T`BU0D-(D4).C\____BT=@#[=`'(M,)#1FB4$0QD$4@(EY&(M4)"B+
-M0@B)032+1"0PB4$@B5%0QD$<((M'8`6X````B4$XQT%L0),#`,=$)`0`````
-MBU0D+(D4).C\____BTPD-(M!((E$)`R+3"0HBT$,BU$0B40D!(E4)`B+1"0L
-MB00DZ/S____&AY<````!BU0D-(E4)`2+3"0DB0PDZ/S___^%_P^$KP```(M'
-M8(7`#X2D````@+^7``````^$)`$``&:!OY0```"6`'47B40D",=$)`0A````
-MBT`LB00DZ/S___]F@Z^4`````<<$)-`'``#H_/___XM$)"2)!"3H_/___XM'
-M8(7`=$Z`OY<`````#X3.````D.NGBU0D-(!Z%`!U-+L`````@'PD'0!T+8M,
-M)"B+00B+5"0PB50D"(E$)`2+3"1@B0PDZ/S___^[`````.L'B?:[_____XM$
-M)#2#>%``=#6!>"``"```=Q6#P%")1"0$BU0D)(D4).C\____ZQ>+1"0T@\!0
-MB40D!(M,)"2)#"3H_/___XM$)#2)1"0$BU0D)(D4).C\____BTPD)(N!2`4`
-M`,9`)P")?"0(BX%(!0``B40D!,<$)`8```#H_/___X!E*/WK&KO_____ZQ-F
-M@[^4``````^%)____^E@____B=B+7"0\BW0D0(M\)$2+;"1(@\1,PXUV`(V\
-M)P````"#[!R)7"00B70D%(E\)!B+5"0@BUPD)(M"+(LXBW-(#[9#%#P@=#\\
-M('<*A,!T(SP&=Q;K+3PB="T\(I"-="8`<B"#P(`\`789N`````")]NM:BT(@
-MQT`$`````,9&9@'K!,9&9@V#>U``="F!>R``"```=Q&-0U")1"0$B3PDZ/S_
-M___K#XU#4(E$)`2)/"3H_/___XE<)`2)/"3H_/___XDT)/]6<+@!````BUPD
-M$(MT)!2+?"08@\0<PXUT)@"#[!R)7"00B70D%(E\)!B+="0@BUY@A=MU%HM$
-M)"B)!"3_5"0DZ58!``"-M@````"#?G0`=0R#?G``C;8`````=!.+1"0HB00D
-M_U0D)(UV`.DK`0``@+NT``````^%$0$``(![)O\/A0<!``"+0S2%P'0*@'@U
-M``^%]@```(M#+/9`"!`/A>D```"+.(![3P!T%(E<)`C'1"0$!@```(D$).C\
-M____BT0D)(E&=(M$)"B)1G@/MDLD#[;1B="#X`:#^`9U-/;"`0^$A@```,9#
-M)@7&0R<$B5PD#`^V0TV)1"0(BT,PB40D!(M#+(D$).C\____Z8<```"#^`0/
-MA7X```#VP0%T>8M3-(72=#`/MT(RJ`)T:H/@_6:)0C*+0S1FQT`R`0"+0S3&
-M0"8=BT,TB40D!(D\).C\____ZT+&0R8#QD,G!(E<)`2)/"3H_/___^LLQD,F
-M!<9#)P9FQX.4``````")7"0$B3PDZ/S____K#8M$)"B)!"3_5"0DB?:+7"00
-MBW0D%(M\)!B#Q!S#4X/L"(M<)!"%VP^$N````(M#;(D$).C\____B<*%P`^$
-M>P```("XI0````!T<H`+`0^V@*4````\`G4X@WMH`'49#[:#F````(/@`XA#
-M`@^V@J0```"(0P'K;0^V@YD```"(0P*+0V@/MH"D````B$,!ZU0\`W50#[:#
-MF````(/@`\'@`@*#F0```(A#`HM#:`^V@*0```"(0P'K*XUV`(M#:(7`=0N+
-M0V2%P'40B?;K%@^V@*0```"(0P'K"@^V@)(```"(0P&#Q`A;PXUV`%93@^P$
-MBW0D$(7V=&J[``````^VA#.\!```//]T-P^VP&G`*`$``(G"`Y9\!0``="2+
-M0B0E`/__`#T``/\`=17V0B<$=`^+0B"%P'0(B00DZ/S___^#PP&!^X````!U
-MLHN&2`4``#GP=0T%S`P``(D$).C\____@\0$6U[#C78`5E.#[!2+7"0@C;/,
-M#```B1PDZ/S___^)0Q2)1A2)FT@%``")GD@%``"+@U0%``")AE0%``#&@[H,
-M```!QH:Z#````8D<).C\____B1PDZ/S___^)-"3H_/___XD<).C\____A,!T
-M;HDT).C\____A,!T8HD<).C\____QP0DT`<``.C\____B1PDZ/S____'@S0!
-M``#H`P``QX,\`0```````(F;0`$``(V#-`$``(E$)`2+0Q2)!"3H_/___\=$
+M)@"-O"<`````@^P,BU0D$(M$)!2(0C,/ML")1"0$B10DZ/S___^X`0```(/$
+M#,.-=@"-O"<`````4X/L"(M<)!")'"3H_/___XN#1`4```7(#```B00DZ/S_
+M__^#Q`A;PY"-M"8`````4X/L"(M<)!")'"3H_/___XN#1`4```7(#```B00D
+MZ/S___^#Q`A;PY"-M"8`````@^P,BT0D$(D$).C\____N@$```"#/0``````
+M=0,/MM")T(/$#,.-=@"-O"<`````@^PLB5PD'(ET)"")?"0DB6PD*(G#B=>)
+MS8MP8(M`;(E$)!2%]@^$-0$``("[EP`````/A2@!``")!"3H_/___XE$)!B%
+MP`^$%`$``,9`).'&0"4!B?J$TG0-B>@\`1G`]]"#P`?K#(GJ@/H!&<#WT(/`
+M#8M4)!B(0B;&0A2`#[=&'&:)0A")6AC'0B``````QT(T`````,=";&"A`@")
+M5"0$BT0D%(D$).C\____QH.7`````6;'@Y0```#T`87;=%F+0V"%P'1<9H&[
+ME````)8`=1>)1"0(QT0D!"$```"+0"R)!"3H_/___V:#JY0````!QP0DT`<`
+M`.C\____BU0D%(D4).C\____BT-@A<!T"8"[EP````!UKF:#NY0`````=!R+
+M1"08@'@4`'42BT-@#[=`.F:)0UJ[`````.L%N_____^+5"08B50D!(M$)!2)
+M!"3H_/___^L)C70F`+O_____B=B+7"0<BW0D((M\)"2+;"0H@\0LPY"-="8`
+M@^Q,B5PD/(ET)$")?"1$B6PD2(MT)%`/MFPD5(M^8(M&;(E$)""%_P^$\@0`
+M`("^EP`````/A>4$``")!"3H_/___XE$)"2%P`^$T00``/8&`@^%!`$``(GJ
+M@/H4=PL/ML*-!$#!X`+K&+B)____B>KVXF;!Z`C`Z`0/ML`%\````(M4)"3&
+M0B3AQD(E`<9")AR(0B?&0A2`#[=''&:)0A")<AC'0B``````QT(T`````,="
+M;&"A`@")5"0$BT0D((D$).C\____QH:7`````6;'AI0```#$"87V=%F+1F"%
+MP'1@9H&^E````)8`=1>)1"0(QT0D!"$```"+0"R)!"3H_/___V:#KI0````!
+MQP0DT`<``.C\____BU0D((D4).C\____BT9@A<!T"8"^EP````!UKF:#OI0`
+M````#X2\`P``NP````"+1"0D@'@4``^$K@,``.FD`P``BU0D((D4).C\____
+MB40D.(7`#X2,`P``BUPD)(/#/(M`"(E$)!R+1"0DQD`D&L9`)0C&0"8:QD`G
+M`,9`*!#&0"D`BT0D.(M4)"2)0E#&0A2`#[=''&:)0A")<AB+1"0XBT`(B4(T
+MQT(@$````(M&8`6X````B4(XQD(<(,=";&"A`@#'1"0$`````(D<).C\____
+MBU0D)(M"((E$)`R+1"0XBU`0BT`,B40D!(E4)`B)'"3H_/___XM$)"2)1"0$
+MBU0D((D4).C\____QH:7`````6;'AI0```#Z`(7V=%F+1F"%P'1<9H&^E```
+M`)8`=1>)1"0(QT0D!"$```"+0"R)!"3H_/___V:#KI0````!QP0DT`<``.C\
+M____BT0D((D$).C\____BT9@A<!T"8"^EP````!UKF:#OI0`````=`J+5"0D
+M@'H4`'0>C40D.(E$)`2+1"0@B00DZ/S___^[_____^D^`@``BU0D)(E4)`2+
+M1"0@B00DZ/S___^+5"0@B10DZ/S___^)1"0DA<!U(8U$)#B)1"0$BT0D((D$
+M).C\____N______I&`(``(UV`(M4)"2#PCR)5"0HBTPD'(/!!(M4)!P/MD(#
+M#[8$`8A"!,9!`0K&00(`N`````"+5"0<Q@00`(/``8/X!'7PB>B$P'4&@&$#
+M_.M-B>@/MM!ITF#J``"X'X7K4??JP?H%@$D#`XG5P>T8B>B(002)T\'K$(A9
+M!8G0P>@(B40D&(A!!HA1!XGHB$$(B%D)#[9$)!B(00J(40N+1"0XBU0D)(E"
+M4,9")!4/M@'`^`?WT(/`$8A")<9")@#&0B<`QD(H$,9"*0"`(3_&0A2`#[='
+M'&:)0A")<AB+1"0XBT`(B4(TQT(@$````(M&8`6X````B4(XQD(<(,=";&"A
+M`@#'1"0$`````(M$)"B)!"3H_/___XM4)"2+0B")1"0,BT0D.(M0$(M`#(E$
+M)`2)5"0(BT0D*(D$).C\____BU0D)(E4)`2+1"0@B00DZ/S____&AI<````!
+M9L>&E````/H`A?9T68M&8(7`=%QF@;Z4````E@!U%XE$)`C'1"0$(0```(M`
+M+(D$).C\____9H.NE`````''!"30!P``Z/S___^+5"0@B10DZ/S___^+1F"%
+MP'0)@+Z7`````'6N9H.^E`````!T#[L`````BT0D)(!X%`!T!;O_____C40D
+M.(E$)`2+5"0@B10DZ/S____K!I"[_____XM$)"2)1"0$BU0D((D4).C\____
+MZPJ0C70F`+O_____B=B+7"0\BW0D0(M\)$2+;"1(@\1,PY"-="8`@^Q,B5PD
+M/(ET)$")?"1$B6PD2(M\)%"+7"14BW0D6`^W1"1<9HE$)!X/ME0D9(A4)!V+
+M;V"%[0^$Z0,``("_EP`````/A=P#``"+32R)3"0XBT=LB40D)&;'AY0````0
+M)XD$).C\____B40D-(7`#X2Q`P``#[=4)!Z)5"0@9H-\)!X$=A*)5"0$QP0D
+M-`(``.C\____ZQ2+3"0DB0PDZ/S___^)1"0HA<!U'HM$)#2)1"0$BU0D)(D4
+M).C\____N______I=@,``(M,)"#!X0F)3"0PBU0D)(N"1`4``,9`)P&)?"0(
+MBX)$!0``B40D!,<$)`4```#H_/___X!-*`*+1V")1"0(QT0D!"$```"+3"0X
+MB0PDZ/S___^+1"0T@\`\B40D+(!\)!T`=!&+5"0TQT)D"@```,9")"CK+HM,
+M)#3'0602````QD$D*HM4)"B+0@B+3"0PB4PD"(M4)&")5"0$B00DZ/S___^+
+M1V#V0#@!='F`?"0=`1G`@^`"@^AXBTPD-(A!),9!)0")\,'H&(A!)HGPP>@0
+MB$$GB?#!Z`B(02B)\HA1*8G8#ZSP&(A!*HG8#ZSP$(A!*XG8#ZSP"(A!+(A9
+M+<9!+@#&02\`#[=$)!YFP>@(B$$P#[9$)!Z(03'&03(`QD$S`.M6@'PD'0$9
+MP(/@`H/`*(M4)#2(0B3&0B4`B=@/K/`8BTPD-(A!)HG8#ZSP$(A!)XG8#ZSP
+M"(A!*(A9*<9!*@`/MT0D'F;!Z`B(02L/MD0D'HA!+,9!+0"+5"0TB10DZ/S_
+M__^+1V`/MT`<BTPD-&:)01#&012`B7D8BU0D*(M""(E!-(M$)#")02")45#&
+M01P@BT=@!;@```")03C'06Q@H0(`QT0D!`````"+5"0LB10DZ/S___^+3"0T
+MBT$@B40D#(M,)"B+00R+41")1"0$B50D"(M$)"R)!"3H_/___\:'EP````&+
+M5"0TB50D!(M,)"2)#"3H_/___X7_#X2O````BT=@A<`/A*0```"`OY<`````
+M#X0D`0``9H&_E````)8`=1>)1"0(QT0D!"$```"+0"R)!"3H_/___V:#KY0`
+M```!QP0DT`<``.C\____BT0D)(D$).C\____BT=@A<!T3H"_EP`````/A,X`
+M``"0ZZ>+5"0T@'H4`'4TNP````"`?"0=`'0MBTPD*(M!"(M4)#")5"0(B40D
+M!(M,)&")#"3H_/___[L`````ZP>)]KO_____BT0D-(-X4`!T-8%X(``(``!W
+M%8/`4(E$)`2+5"0DB10DZ/S____K%XM$)#2#P%")1"0$BTPD)(D,).C\____
+MBT0D-(E$)`2+5"0DB10DZ/S___^+3"0DBX%$!0``QD`G`(E\)`B+@40%``")
+M1"0$QP0D!@```.C\____@&4H_>L:N______K$V:#OY0`````#X4G____Z6#_
+M__^)V(M<)#R+="1`BWPD1(ML)$B#Q$S#C78`C;PG`````(/L'(E<)!")="04
+MB7PD&(M4)""+7"0DBT(LBSB+<T@/MD,4/"!T/SP@=PJ$P'0C/`9W%NLM/")T
+M+3PBD(UT)@!R((/`@#P!=AFX`````(GVZUJ+0B#'0`0`````QD9F`>L$QD9F
+M#8-[4`!T*8%[(``(``!W$8U#4(E$)`2)/"3H_/___^L/C4-0B40D!(D\).C\
+M____B5PD!(D\).C\____B30D_U9PN`$```"+7"00BW0D%(M\)!B#Q!S#C70F
+M`(/L'(E<)!")="04B7PD&(MT)""+7F"%VW46BT0D*(D$)/]4)"3I5@$``(VV
+M`````(-^=`!U#(-^<`"-M@````!T$XM$)"B)!"3_5"0DC78`Z2L!``"`N[0`
+M````#X41`0``@'LF_P^%!P$``(M#-(7`=`J`>#4`#X7V````BT,L]D`($`^%
+MZ0```(LX@'M/`'04B5PD",=$)`0&````B00DZ/S___^+1"0DB49TBT0D*(E&
+M>`^V2R0/MM&)T(/@!H/X!G4T]L(!#X2&````QD,F!<9#)P2)7"0,#[9#38E$
+M)`B+0S")1"0$BT,LB00DZ/S____IAP```(/X!`^%?@```/;!`71YBU,TA=)T
+M,`^W0C*H`G1J@^#]9HE",HM#-&;'0#(!`(M#-,9`)AV+0S2)1"0$B3PDZ/S_
+M___K0L9#)@/&0R<$B5PD!(D\).C\____ZRS&0R8%QD,G!F;'@Y0``````(E<
+M)`2)/"3H_/___^L-BT0D*(D$)/]4)"2)]HM<)!"+="04BWPD&(/$',-3@^P(
+MBUPD$(7;#X2X````BT-LB00DZ/S___^)PH7`#X1[````@+BE`````'1R@`L!
+M#[:`I0```#P"=3B#>V@`=1D/MH.8````@^`#B$,"#[:"I````(A#`>MM#[:#
+MF0```(A#`HM#:`^V@*0```"(0P'K5#P#=5`/MH.8````@^`#P>`"`H.9````
+MB$,"BT-H#[:`I````(A#`>LKC78`BT-HA<!U"XM#9(7`=1")]NL6#[:`I```
+M`(A#`>L*#[:`D@```(A#`8/$"%O#C78`5E.#[`2+="00A?9T:KL`````#[:$
+M,[@$```\_W0W#[;`:<`H`0``B<(#EG@%``!T)(M")"4`__\`/0``_P!U%?9"
+M)P1T#XM"((7`=`B)!"3H_/___X/#`8'[@````'6RBX9$!0``.?!U#07(#```
+MB00DZ/S___^#Q`1;7L.-=@!64X/L%(M<)""-L\@,``")'"3H_/___XE#%(E&
+M%(F;1`4``(F>1`4``(N#4`4``(F&4`4``,:#M@P```'&AK8,```!B1PDZ/S_
+M__^)'"3H_/___XDT).C\____QT0D!`````")'"3H_/___XD<).C\____A,!T
+M;HDT).C\____A,!T8HD<).C\____QP0DT`<``.C\____B1PDZ/S____'@S`!
+M``#H`P``QX,X`0```````(F;/`$``(V#,`$``(E$)`2+0Q2)!"3H_/___\=$
M)`0`````B1PDZ/S___^X`0```.L%N`````"#Q!1;7L-3@^P(BUPD$(D<).C\
-M____@</,#```B1PDZ/S___^X`0```(/$"%O#D(VT)@````!55U93@^P\@SWD
-M`0````^%@0$``,<%Y`$```$```#'1"0X`````.F\`@``D(UT)@`/MX8>`@``
+M____@</(#```B1PDZ/S___^X`0```(/$"%O#D(VT)@````!55U93@^P\@SW$
+M`0````^%@0$``,<%Q`$```$```#'1"0X`````.F\`@``D(UT)@`/MX8>`@``
MP>`0#[>6'`(```G0.40D*`^%$P$``+\`````N0````")?"0P9H.Y``````!U
M>XGZP>(%BX8<`@``B8(`````BX8@`@``B8($````BX8D`@``B8((````#[:"
M'````(T,_0````"-!`$/MEPD+X@<A0T````/MH(<````C00!#[9<)"Z('(4.
M````#[:"'`````'!Q@2-#P````"`@AP````!ZWF0C70F``^VF1P```")V+H`
M````][8P`@``A=)T38M,)##!X0.-!!D/ME0D+X@4A0T```"+5"0PP>(%#[:"
M'````(T$`0^V7"0NB!R%#@````^V@AP````!P<8$C0\`````@((<`````>L/
-M@\<!@\$@@_\$#X4#____@X8H`@```9"-="8`@\4!@\88.RT`&```#X6^_O__
+M@\<!@\$@@_\$#X4#____@X8H`@```9"-="8`@\4!@\88.RV@#0``#X6^_O__
M@T0D-`&#?"0T(`^%&`$``(-$)#@!@7PD./\````/A5(!``"#?"14`'0'BW0D
-M5,8&`(L=`!@``,=$)"0`````A=M^.;D`````QT0D)`````"Z`````(N"*`(`
+M5,8&`(L=H`T``,=$)"0`````A=M^.;D`````QT0D)`````"Z`````(N"*`(`
M``%$)"2#?"14`'0,BX(L`@``BW0D5``&@\$!@\(8.=EUV8-\)%@`#X0!`0``
MO0````"[`````&:#NP``````#X3I````#[:#'````(E$)""%P'YJQT0D&```
M``"-%.T`````B50D'(M$)!P#1"08C32%#````(M\)%BX!````/R)P?.F#Y?"
M#Y+`.,)U(8-\)%0`=`T/MH,=````BW0D5(@&#[:#'````(E$)"3K#X-$)!@!
MBU0D(#E4)!AUJ8/%`8/#((/]!'1EZ6G___\/MDPD-(A,)"['1"0,`````,=$
-M)`@`````BUPD-(E<)`2+="0XB30DZ/S___^)1"0HO0````"^`````(,]`!@`
+M)`@`````BUPD-(E<)`2+="0XB30DZ/S___^)1"0HO0````"^`````(,]H`T`
M```/CT[]___IB_[__P^V1"0XB$0D+\=$)#0`````ZZ`/MD0D)(/$/%M>7UW#
MB?:-O"<`````@^P<B5PD$(ET)!2)?"08BT0D(`^V="0DBWALBUA@]@`!='6+
M4S"%TG09B?$/ML&)1"0(#[9#38E$)`2)%"3H_/___XN3Y````(72=!R)\0^V
@@ -5401,18 +4025,18 @@ MB?(/ML*)1"0(BT,@B40D!(D\).C\____ZQB)\0^VP8E$)`B+0R")1"0$B3PD
MZ/S___^+7"00BW0D%(M\)!B#Q!S#@^P\B5PD+(ET)#")?"0TB6PD.(M\)$`/
MMG0D1(M?8(MO;(7;#X1V`P``@+^7``````^%:0,``/8'`@^%8`,```^V@R0!
M``"$P'0+B?(XT'5#Z4H#```/MH/;````B40D$`^V!X/@`0^VP(E$)`P/MD<"
-MB40D"`^V1P&)1"0$QP0D(`H``.C\____N______I$0,``(DL).C\____B40D
+MB40D"`^V1P&)1"0$QP0DJ`H``.C\____N______I$0,``(DL).C\____B40D
M'(7`#X3X`@``B?(/ML*)1"04BT=@#[:`VP```(E$)!`/M@>#X`$/ML")1"0,
-M#[9'`HE$)`@/MD<!B40D!,<$)&@*``#H_/___XM$)!S&0"3AQD`E`8GR@/H"
+M#[9'`HE$)`@/MD<!B40D!,<$)/`*``#H_/___XM$)!S&0"3AQD`E`8GR@/H"
M#Y7`@\`:BU0D'(A")L9"%(`/MT,<9HE"$(EZ&,="(`````#'0C0`````QT)L
-M0),#`(E4)`2)+"3H_/___\:'EP````%FQX>4````]`&%_W15BT=@A<!T7&:!
+M8*$"`(E4)`2)+"3H_/___\:'EP````%FQX>4````]`&%_W15BT=@A<!T7&:!
MOY0```"6`'47B40D",=$)`0A````BT`LB00DZ/S___]F@Z^4`````<<$)-`'
M``#H_/___XDL).C\____BT=@A<!T"8"_EP````!ULF:#OY0`````#X39`0``
MBT0D'(!X%``/A<L!``"+5V")5"0HBT(LBP")1"0DB00DZ/S___^)PX7`=1"+
M1"0HQH"U`````>FB`0``BU0D)(D4).C\____B<:%P'4EBT0D*,:`M0````&)
M7"0$BU0D)(D4).C\____NP````#I:P$``(U#/(E$)"#&0R3AQD,E`<9#)@.+
M5"0H#[="'&:)0Q#&0V@/B7L8QT,@``(``(M6"(E3-+@`````Q@00`(/``3T`
-M`@``=?*)<U#'0VQ`DP,`QT0D!`````"+1"0@B00DZ/S___^+0R")1"0,BT8,
+M`@``=?*)<U#'0VQ@H0(`QT0D!`````"+1"0@B00DZ/S___^+0R")1"0,BT8,
MBU80B40D!(E4)`B+5"0@B10DZ/S___^)7"0$BT0D)(D$).C\____QH>7````
M`6;'AY0```#Z`(7_=%F+1V"%P'1<9H&_E````)8`=1>)1"0(QT0D!"$```"+
M0"R)!"3H_/___V:#KY0````!QP0DT`<``.C\____BU0D)(D4).C\____BT=@
@@ -5420,46 +4044,46 @@ MA<!T"8"_EP````!UKF:#OY0`````="J`>Q0`=22+0S2)1"0$BT0D*(D$).C\
M____BU0D*`^V@B0!``"(AYL```"#>U``=!.-0U")1"0$BT0D)(D$).C\____
MB5PD!(M4)"2)%"3H_/___[L`````ZP6[_____XM$)!R)1"0$B2PDZ/S____K
M"(UV`+O_____B=B+7"0LBW0D,(M\)#2+;"0X@\0\PY"-="8`@^P<B5PD#(ET
-M)!")?"04B6PD&(MT)""+5"0D@#H)=Q`/M@+_)(7`%0``C;8`````N/_____I
-M2@$``(M2!(N"3`4``(7`=0F)T(VT)@````"+@$@%``#&@+L,```!B00DZ/S_
-M__^X`````.D5`0``#[9*!+H`````B?#H(>C__^D``0``#[9*!+H!````B?#H
-M#.C__^GK````#[9"!(E$)`2)-"3H_/___^G6````#[9J!(M^;(M>8+C_____
-M]D98"`^$O0```(ET)`B+AT@%``")1"0$QP0D!0```.C\____@$LH`HE<)`C'
+M)!")?"04B6PD&(MT)""+5"0D@#H)=Q`/M@+_)(5@"P``C;8`````N/_____I
+M2@$``(M2!(N"2`4``(7`=0F)T(VT)@````"+@$0%``#&@+<,```!B00DZ/S_
+M__^X`````.D5`0``#[9*!+H`````B?#H$>C__^D``0``#[9*!+H!````B?#H
+M_.?__^GK````#[9"!(E$)`2)-"3H_/___^G6````#[9J!(M^;(M>8+C_____
+M]D98"`^$O0```(ET)`B+AT0%``")1"0$QP0D!0```.C\____@$LH`HE<)`C'
M1"0$(0```(M#+(D$).C\____@'M/`'0:QP0DT`<``.C\____B3PDZ/S___^`
-M>T\`=>:)Z(3`=`QF@TY:$&:#2SH0ZPIF@V9:[V:#8SKOB70D"(N'2`4``(E$
+M>T\`=>:)Z(3`=`QF@TY:$&:#2SH0ZPIF@V9:[V:#8SKOB70D"(N'1`4``(E$
M)`3'!"0&````Z/S___^`8RC]N`````#K)P^V0@2)1"0$B30DZ/S____K%0^V
M0@2)1"0$B30DZ/S___^X`````(M<)`R+="00BWPD%(ML)!B#Q!S#D(VT)@``
-M``"#[$R)7"1`B70D1(E\)$B+?"10BW=LBX9(!0``@'@G``^%N@```(M?<(M7
+M``"#[$R)7"1`B70D1(E\)$B+?"10BW=LBX9$!0``@'@G``^%N@```(M?<(M7
M8`^V@J<```")1"0T#[:"I@```(E$)#`/MH*E````B40D+`^V@J0```")1"0H
M#[:"HP```(E$)"0/MH*B````B40D(`^V@J$```")1"0<#[:"H````(E$)!@/
MMH+;````B40D%`^V!X/@`0^VP(E$)!`/MD<"B40D#`^V1P&)1"0(BT<(B40D
-M!,<$)*P*``#H_/___\='<`````"+1PB)1"0(B7PD!(M'>(D$)/_3ZSV0C70F
-M`(U??(E<)`2+1A2)!"3H_/___\='?/0!``#'AX0```!`N@,`B;^(````B5PD
+M!,<$)#0+``#H_/___\='<`````"+1PB)1"0(B7PD!(M'>(D$)/_3ZSV0C70F
+M`(U??(E<)`2+1A2)!"3H_/___\='?/0!``#'AX0```!@R`(`B;^(````B5PD
M!(M&%(D$).C\____BUPD0(MT)$2+?"1(@\1,PY"-M"8`````55=64X/L'`^W
-M1"0X:<`H`0``B<6+5"0P`ZI\!0``B[I(!0``@<?,#```BTPD-(EI8(E-((-]
-M,`!U+8-]-`!U)P^V<BN)\X3;#X0@!```BUTLN0`````[FJ0+```/A-T#``#I
+M1"0X:<`H`0``B<6+5"0P`ZIX!0``B[I$!0``@<?(#```BTPD-(EI8(E-((-]
+M,`!U+8-]-`!U)P^V<BN)\X3;#X0@!```BUTLN0`````[FJ`+```/A-T#``#I
M^0,``(M$)#2`"`&+132+5"0TB4)HBT4PB4)DBTPD,`^V<2N)\X3;=%.+72RY
-M`````(M$)#`[F*0+``!T&NLO#[;!B<+!X@:-!(*+5"0P.9P"I`L``'4<BUPD
-M,`^V0RF-!(&+5"0TB(*8````ZPZY`````(/!`8GP.,%UPXM4)#"+BD@%```/
-MMH$\!0``NP`````\_W0DBU4PA=)T&`^VP&G`%`T```.!M`4``+L`````.<)T
-M*KL!````#[:!/04``#S_="N+53"%TG0A#[;`:<`4#0```X&T!0``.<)U#HM,
-M)#2(60'IW@```(GV@\,!N@`````/MH0*/@4``#S_=",/ML!IP+`````#@9@%
-M```[131U#(M\)#2(7P'IJ````(/#`8/"`8/Z!'7)B=D/MH<\!0``//]T)(M5
-M,(72=06-60'K&`^VP&G`%`T```.'M`4``#G"=>CK*(UV``^VAST%```\_W0H
-MBU4PA=)T'@^VP&G`%`T```.'M`4``#G"=0N+1"0TB%@!ZSZ)]H/#`;H`````
-M#[:$.CX%```\_W0@#[;`:<"P`````X>8!0``.T4T=0F+5"0TB%H!ZPN#PP&#
-MP@&#^@1US(M,)#"`>3D!=4B+53"%TG08QT0D"``````/MD5-B40D!(D4).C\
+M`````(M$)#`[F*`+``!T&NLO#[;!B<+!X@:-!(*+5"0P.9P"H`L``'4<BUPD
+M,`^V0RF-!(&+5"0TB(*8````ZPZY`````(/!`8GP.,%UPXM4)#"+BD0%```/
+MMH$X!0``NP`````\_W0DBU4PA=)T&`^VP&G`%`T```.!L`4``+L`````.<)T
+M*KL!````#[:!.04``#S_="N+53"%TG0A#[;`:<`4#0```X&P!0``.<)U#HM,
+M)#2(60'IW@```(GV@\,!N@`````/MH0*.@4``#S_=",/ML!IP+`````#@90%
+M```[131U#(M\)#2(7P'IJ````(/#`8/"`8/Z!'7)B=D/MH<X!0``//]T)(M5
+M,(72=06-60'K&`^VP&G`%`T```.'L`4``#G"=>CK*(UV``^VASD%```\_W0H
+MBU4PA=)T'@^VP&G`%`T```.'L`4``#G"=0N+1"0TB%@!ZSZ)]H/#`;H`````
+M#[:$.CH%```\_W0@#[;`:<"P`````X>4!0``.T4T=0F+5"0TB%H!ZPN#PP&#
+MP@&#^@1US(M,)#"`>34!=4B+53"%TG08QT0D"``````/MD5-B40D!(D4).C\
M____BY7D````A=(/A+<!``#'1"0(``````^VA=D```")1"0$B10DZ/S___^#
MO>0`````#X2/`0``BW4P@'XP`'16OP````"-7BB-="8`B5PD&(D<).C\____
MC4CXBU8LB48LB5D(B5$,B0*`N=L```#_=0^`>24`=0F#N>0`````=0J#QP&)
M^#A&,'?!B?HX5C`/A90````/MH7;````BTPD-(A!`H!^,``/A(X!``"[````
M`(U^*(VV`````(D\).C\____C4CXBU8LB48LB7D(B5$,B0*+02"%P'1`#[:1
-MVP```#A0`G0T@WAP`'4N@WAT`'4HB%`"#[=!'(E$)`B+5"0PBX)(!0``B40D
+MVP```#A0`G0T@WAP`'4N@WAT`'4HB%`"#[=!'(E$)`B+5"0PBX)$!0``B40D
M!,<$)`<```#H_/___XUV`(/#`3A>,`^&%`$``.N2#[9%38M,)#2(00+&A=L`
M``#_@'XP``^$]@```+L`````D(M\)!B)/"3H_/___XU(^(M6+(E&+(EY"(E1
M#(D"@+G;````_W1*QH';````_XM!((7`=#P/ME%-.%`"=#.#>'``=2V#>'0`
-M=2>(4`(/MT$<B40D"(M4)#"+@D@%``")1"0$QP0D!P```.C\____B?:#PP$X
-M7C!V>.N&#[9%38M,)#2(00+K:0^VP8G"P>(&C02"BWPD,#F<!Z0+``!U)HM4
+M=2>(4`(/MT$<B40D"(M4)#"+@D0%``")1"0$QP0D!P```.C\____B?:#PP$X
+M7C!V>.N&#[9%38M,)#2(00+K:0^VP8G"P>(&C02"BWPD,#F<!Z`+``!U)HM4
M)#`/MD(IC02!BUPD-(A#`8B#F````#A**W4:ZQ")]KD`````@\$!B?`XP76Y
MBU0D-,9"`?^+3"0TQD$"`(.]'`$```!T"8N%(`$``(A!`HM,)#2#P2"-562+
M162+7"0TB4,@BT($B4$$BT((B4$(BT(,B4$,BT(0B4$0BT(4B4$4BT(8B4$8
@@ -5469,20 +4093,20 @@ MBT5$BU5(B4-0B5-4#[9%3HA#7`^VA20!``"(@YL```#V12@$=0R+?"0PB3PD
MZ/S___\/ME4DB="#X`:#^`9U#O;"`74)BT0D-(`(`NL'BU0D-(`B_0^V52C0
MZH/B!(M,)#0/M@&#X/L)T(@!#[9!`8B!F@````^V00*(@9D```")#"3H_/__
M_\=$)`@`````BT4@B40D!(M<)#")'"3H_/___XM\)#2)/"3H__C__X/$'%M>
-M7UW#C;0F`````(/L'(E<)!2)="08BW0D((N>2`4``(DT).C\____@'XY`74M
-MC8/,#```@'@Y`71?@+[$#````'48QT0D!`````")!"3H_/___X"&Q`P```&0
-MC9XT`0``B5PD!(M&%(D$).C\____QX8T`0``Z`,``,>&/`$```````")MD`!
+M7UW#C;0F`````(/L'(E<)!2)="08BW0D((N>1`4``(DT).C\____@'XU`74M
+MC8/(#```@'@U`71?@+[`#````'48QT0D!`````")!"3H_/___X"&P`P```&0
+MC9XP`0``B5PD!(M&%(D$).C\____QX8P`0``Z`,``,>&.`$```````")MCP!
M``")7"0$BT84B00DZ/S___^+7"04BW0D&(/$',.-M@````!55U93@^Q,BT0D
-M9(M0&(E4)""+0!R)1"08#[9*"XE,)!R+5"1@BX)(!0``BYA(!0``O@````"_
-M`````+D`````#[:4&3P%``"`^O]T1HV!@````&8]@0!W!X/&`>LUB?8/ML*+
-MDY@%``!IP+````"`O!"E`````W47@\<!C4<#@_@&=@^#Q@&_`````.L%B?:#
-MQ@&#P0&#^09UI8GUBYM(!0``@</,#```L0"0C70F``^VE!D\!0``@/K_=$:-
-M@8````!F/8$`=P>#Q@'K-8GV#[;"BY.8!0``:<"P````@+P0I0````-U%X/'
+M9(M0&(E4)""+0!R)1"08#[9*"XE,)!R+5"1@BX)$!0``BYA$!0``O@````"_
+M`````+D`````#[:4&3@%``"`^O]T1HV!@````&8]@0!W!X/&`>LUB?8/ML*+
+MDY0%``!IP+````"`O!"E`````W47@\<!C4<#@_@&=@^#Q@&_`````.L%B?:#
+MQ@&#P0&#^09UI8GUBYM$!0``@</(#```L0"0C70F``^VE!DX!0``@/K_=$:-
+M@8````!F/8$`=P>#Q@'K-8GV#[;"BY.4!0``:<"P````@+P0I0````-U%X/'
M`8U'`X/X!G8/@\8!OP````#K!8GV@\8!@\$!@_D&=:4Y="0<#XT\"0``.VPD
-M'`^>P(M,)&C'`0`````\_P^$'`D```^VP&G`S`P``(M4)&`#@D@%``")!"3H
+M'`^>P(M,)&C'`0`````\_P^$'`D```^VP&G`R`P``(M4)&`#@D0%``")!"3H
M_/___XG!A<`/A/<(``"+1"08B40D)`^V@:4````\`@^%!`(``(M4)&C'`@0`
-M``"+1"0@#[9P!XL1#[=!)+L`````@+P"O`0``/\/A-$!``")\H#Z(P^'MP$`
-M``^VPO\DA>@5``"+3"0DQP%%4P,1N`$```#II0$``(U$)$B)1"0,QT0D"!`#
+M``"+1"0@#[9P!XL1#[=!)+L`````@+P"N`0``/\/A-$!``")\H#Z(P^'MP$`
+M``^VPO\DA8@+``"+3"0DQP%%4P,1N`$```#II0$``(U$)$B)1"0,QT0D"!`#
M``#'1"0$`0```(D,).C\____A,`/A'$!``"+1"1(A<`/A&P!```E_P,``&G`
M$"<``(V($):O_[ISB*M,B<CWXHG(*=#1Z`'"P>H'BTPD)(D1N`$```#I/`$`
M`(U$)$B)1"0,QT0D"`@#``#'1"0$`0```(D,).C\____A,`/A`@!``"+1"1(
@@ -5493,11 +4117,11 @@ M:RBOB<CWXHG(*=#1Z`'"P>H$BTPD)(D1N`$```#K:HU$)$B)1"0,QT0D"`P#
M``#'1"0$`0```(D,).C\____A,!T.HM$)$B%P'0Y)?\#``!IP.@#``"-B,CE
M]_^ZRVLHKXG(]^*)R"G0T>@!PL'J!(M,)"2)$;@!````ZPRX`````.L%N`$`
M```/MM@/ML/I\@8``#P##X74!@``BT0D:,<`!````(M4)"`/ME('B%0D*\=$
-M)#@`````QT0D/`````#'1"1``````,=$)$0`````BQ$/MJKE````A>T/CH\`
-M``"_`````,=$)!0`````N`$```")QHGYT^:+3"04#[:$$3X%```\_W0?#[;`
-M:<"P````B<,#FI@%``"+0U2+0!@/MD`&.?!T$H-$)!0!@WPD%`0/A"P&``#K
-MOX7;#X0B!@``#[=#)("\`KP$``#_#X00!@``@+NE`````P^%`P8``(E<O#B#
-MQP$Y_0^%=O___X!\)"M5#X?;!0``#[9$)"O_)(5X%@``BT0D),<`0`,#$;@!
+M)#@`````QT0D/`````#'1"1``````,=$)$0`````BQ$/MJKA````A>T/CH\`
+M``"_`````,=$)!0`````N`$```")QHGYT^:+3"04#[:$$3H%```\_W0?#[;`
+M:<"P````B<,#FI0%``"+0U2+0!@/MD`&.?!T$H-$)!0!@WPD%`0/A"P&``#K
+MOX7;#X0B!@``#[=#)("\`K@$``#_#X00!@``@+NE`````P^%`P8``(E<O#B#
+MQP$Y_0^%=O___X!\)"M5#X?;!0``#[9$)"O_)(48#```BT0D),<`0`,#$;@!
M````Z<`%``"-1"1(B40D#,=$)`@T`P``QT0D!`$````/MD0D*X/``8/@`XM$
MA#B)!"3H_/___X3`#X2$!0``#[=4)$B)5"1(@?K__P``=12+5"0DQP+_____
MN`$```#I9`4``+C`X>0`B=&Z`````/?QBU0D)(D"N`$```#I1@4``(U$)$B)
@@ -5533,11 +4157,11 @@ M`0"+1"0\B00DZ/S___^X`0```.M`BU0D((!Z"`!T$(M$)#R!H*@```#___W_
MZPZ+1"0\@8BH```````"`(M$)#R)!"3H_/___[@!````ZP6X``````^VP.L)
MC70F`+@`````#[;`ZQ:X`````.L/BTPD:,<!`````+@`````@\1,6UY?7<.0
MC;0F`````%575E.#[&R+O"2`````BX0DA````(NT)(P```")Q<'M&(G"P>H0
-MB%0D0`^VS(A,)#"(1"0OBYPDB````('#S`P``+@`````BY0DB````,8$$`"#
-MP`$]F!L``'7KB7(0H>`!``"(0BB#P`&CX`$``(GIB$HC#[9$)$"(0B(/MDPD
+MB%0D0`^VS(A,)#"(1"0OBYPDB````('#R`P``+@`````BY0DB````,8$$`"#
+MP`$]D!L``'7KB7(0H<`!``"(0BB#P`&CP`$``(GIB$HC#[9$)$"(0B(/MDPD
M,(A*(0^V1"0OB$(@QD(I``^W!V:)0A@/MT<"9HE"&HM'!(E"'(N4)(@```"!
-MPI@9``"+C"2(````B9'(#```B7,0#[9!*(A#*(GHB$,C#[9,)$"(2R(/MD0D
-M,(A#(0^V3"0OB$L@QD,I`0^W!V:)0Q@/MT<"9HE#&HM'!(E#'(F3R`P``(N4
+MPI`9``"+C"2(````B9'$#```B7,0#[9!*(A#*(GHB$,C#[9,)$"(2R(/MD0D
+M,(A#(0^V3"0OB$L@QD,I`0^W!V:)0Q@/MT<"9HE#&HM'!(E#'(F3Q`P``(N4
M)(@````/MT(:9CTD)P^$(P$``&8])"</AXP```!F/40A#X0/`0``9CU$(7=,
M9CT@(0^$_P```&8]("%W$68]4`</A0H!``")]NGH````9CTB(8VT)@`````/
MA-<```!F/4`AC;8`````#X7B````Z<(```"0C70F`&8]$"</@LX```!F/1$G
@@ -5548,7 +4172,7 @@ ME'5`ZR.-M@````"+C"2(````9L=!)("1QD$F!&;'0R2`D<9#)@3K&XN$)(@`
M``!FQT`D@)3&0"8$9L=#)("4QD,F!`^V1PB+E"2(````B$(J#[9'"(A#*L=$
M)`P```0`QT0D"`````#'1"0$`@```(DT).C\____BXPDB````(D!QT0D#``@
M``#'1"0(`````,=$)`0`````B30DZ/S___^)P8NT)(@```")1@B+!H7`#X3M
-M`0``A<D/A.4!``"-D``"`0")5@2-@````@")!@4`0```B0.)4P2)2PB+-0`8
+M`0``A<D/A.4!``"-D``"`0")5@2-@````@")!@4`0```B0.)4P2)2PB+-:`-
M``"%]GY?NP````"Y``````^W@1P"``!F.P=U/P^W@1X"``!F.T<"=3*+D2P"
M``"#P@&)D2P"``"+@2@"``")1"08A<!T%3G"=A&)T+H`````]W0D&(F1+`(`
M`(/#`8/!&#GS=:N+E"2(````BT($+>!]``#'``'P`P"+0@0MV'T``,<``0``
@@ -5558,4077 +4182,3711 @@ M)#"(3"1=#[9$)"^(1"1<QT0D*`````"]`````&:#O0``````#X2@````@+T<
M``````^$@````+L`````BU0D*,'B`XE4)"2-3"1<B4PD'(M$)"0!V(TTA0P`
M``"Y!````/R+?"0<\Z8/E\(/DL`XPG4W#[:%'0```(/``8B%'0````^VE1P`
M``"$TG0<.-!V&`^VP`^VRKH`````9O?QB)4=````C70F`(/#`0^VA1P````Y
-MV'^8@T0D*`&#Q2"#?"0H!`^%4O___XNT)(@```#'AE0%```!````N`$```#K
+MV'^8@T0D*`&#Q2"#?"0H!`^%4O___XNT)(@```#'AE`%```!````N`$```#K
M!;@`````@\1L6UY?7<.-=@"-O"<`````55=64X/L#(MT)""+?"0DBVYL#[8&
-M@^`!B$0D"[@`````Q@0X`(/``8/X('7TBYW(#```B=JP`,8$$`"#P`$]``(`
-M`'7RC4LVN@````"-=@`/MD0R(8@$"@^V1#(@B$0*`8/"`H/Z*'7GC4L4L@(/
-MMD0R"XA$"OX/MD0R"HA$"O^#P@*#^A9UYHU++K(`#[9$,DF(!`H/MD0R2(A$
-M"@&#P@*#^@AUYXE?&(M&4(M65(/``8/2`(D'B5<$@WY@`'4\]@8!=#>+1F2%
-M[0^5PH7`=!*$TG0.#[9`,X"\!;P$``#_=1F+1FB$TG0;A<!T%P^W0"2`O`6\
-M!```_W0)#[9&`8A'#.LBB2PDZ/S___^%P'02@+BE`````G4)#[9&`8A'#.L$
-MQD<,_P^V1@*(1PVX`0```/9&6A!T!`^V1ER(1P[&1Q(0QD<1$`^V1"0+C10`
-M#[9?"H/C_0G3B%\*P>`%#[9/"(/AWPG!B$\(#[=&6,'H!X/@`<'@!H/AOPG!
-MB$\(#[=&6,'H`H/@`0^V5PF#XOX)PHA7"0^W1EK!Z`/!X`>#X7\)P8A/"`^W
-M1EK1Z(/@`0'`@^+]"<*(5PD/MT98P>@#@^`!P>`&@^*_"<*(5PD/MT9:P>@$
-MP>`'@^)_"<*(5PF#R1"(3P@/M@;0Z(/@`8/C_@G#B%\*#[8&@^`$@^/["<.(
-M7PIFQT<4`!`/MH:;````B$</#[:&F````(A''(/$#%M>7UW#D(VT)@````!5
-M5U93@^P(BUPD*(MT)"R%VW03N`````#&!!@`@\`!/:P```!U\H7V=!*X````
-M`)#&!#``@\`!@_@H=?2+1"0<B[A(!0``#[9$)"")1"0$B3PDZ/S___^)P6:%
-MP'0-#[?`@+P'O`0``/]U2XN_2`4``(''S`P``(N'2`4``(D$).C\____*40D
-M(`^V1"0@B40D!(D\).C\____B<%FA<`/A"D#```/M\"`O`>\!```_P^$&`,`
-M``^WP0^VA`>\!```9H'Y@0`/AS<"``"+C[0%```/M\!IP!0-``"-+`&%VP^$
-MU@```(M5#(72=&P/MH<\!0``//]T%0^VP&G`%`T``(T$`;Z`````.<)T(`^V
-MAST%```\_W0:#[;`:<`4#0``C00!.<)U"KZ!````B?"(0P*`?3(`="^Z````
-M``^VP@^V3`5`N`$```#3X`E#((/"`3A5,G80Z^3&0P+_BT4(#[9`"8E#(,8#
-M`0^V13&(0P&+14B)0P2+14R)0PB-2PR-55B+15B)0PR+0@2)002+0@B)00B+
-M0@R)00R+17")0QR+5"0@B5,D#[:%D````(E#*+@`````Z1<"``"%]@^$"@(`
-M`(-\)"0`#XC_`0``#[:%D````#E$)"0/C>X!``"+1"0DC12`C535`(V"D```
-M``^V2`2(#@^V0`6(1@&+@I@````/M@"#X`^(1@*`^0-T(H#Y`W<.@/D"#X6.
-M````Z9````"`^01T-8#Y$HUV`'5\ZU6+5"0DC022BY3%F`````^V0@&#X`</
-MML#!X`@/ME("`="-!(`!P(E&!.M6BU0D)(T$DHN$Q9@````/MD`"A,!U"<=&
-M!`````#K-P^VP(/H%(E&!.LLBU0D)(T$DHN4Q9@````/MD("P>`(#[92`P'0
-MC02``<")1@3K!\=&!`````"-3@B+5"0DC022C83%D````(U0#(M`#(E&"(M"
-M!(E!!(M""(E!"(M"#(E!#(M"$(E!$(M"%(E!%(M"&(E!&(M"'(E!'+@`````
-MZ=`````/M]!ITK````")U@.WF`4``,9#`O_&`P*+AY@%```/MD0"'XA#`8M&
-M5`^V0`F)0R`/MH:E````/`)U+<=#!$A05`"-0PS'0PQ2;V-KQT`$9713=,=`
-M"&]R(``/MU8BC4,7Z#>^___K13P#=2'&0P$0QT,@`0```,=#!$A05`#'0PQ%
-M2C,T9L=#$#``ZR#&0P1V#[=6((U#!>@`OO__QD,,9`^W5B*-0PWH\+W__\9#
-M''(/ME8=C4,=Z*"]__^+1"0@B4,DN`````#K!;C_____@\0(6UY?7<.0C70F
-M`%575E.#[`R+="0HN`````#&!#``@\`!/2@-``!U\HM$)""+F$@%```/MD0D
-M)(E$)`2)'"3H_/___XG!9H7`=`T/M\"`O`.\!```_W5+BYM(!0``@</,#```
-MBX-(!0``B00DZ/S___\I1"0D#[9$)"2)1"0$B1PDZ/S___^)P6:%P`^$1P,`
-M``^WP("\`[P$``#_#X0V`P``#[?!#[:$`[P$``!F@?F!``^'50(``(N+M`4`
-M``^WP&G`%`T``(TL`8M5#(72=&P/MH,\!0``//]T%0^VP&G`%`T``(T$`;^`
-M````.<)T(`^V@ST%```\_W0:#[;`:<`4#0``C00!.<)U"K^!````B?B(1@*`
-M?3(`="^Z``````^VP@^V3`5`N`$```#3X`E&((/"`3A5,G80Z^3&1@+_BT4(
-M#[9`"8E&(,8&`0^V13&(1@&+14B)1@2+14R)1@B-3@R-55B+15B)1@R+0@2)
-M002+0@B)00B+0@R)00R+17")1AR+1"0DB48D@+V0``````^$1@(``,9$)`L`
-M#[9\)`N-!+_!X`.-##`!Z(V0D`````^V6@2(F:@````/ME(%B)&I````BX"8
-M````#[8`@^`/B(&J````@/L#="V`^P-W#H#[`@^%K0```.FV````@/L$D(UT
-M)@!T/H#[$@^%E0```)"-="8`ZV:-#+_!X0.+E`V8````#[9"`8/@!P^VP,'@
-M"`^V4@(!T(T$@`'`B80.K````.MNC02_C13%`````(N$%9@````/MD`"A,!U
-M#<>$%JP`````````ZTB-%+\/ML"#Z!2)A-:L````ZS:-#+_!X0.+E`V8````
-M#[9"`L'@"`^V4@,!T(T$@`'`B80.K````.L.C02_QX3&K`````````"-!+_!
-MX`.-G`:@````C4L0C80%D````(U0#(M`#(E#$(M"!(E!!(M""(E!"(M"#(E!
-M#(M"$(E!$(M"%(E!%(M"&(E!&(M"'(E!'(!$)`L!#[9$)`LXA9`````/AM<`
-M``#ID?[__P^WT&G2L````(G7`[N8!0``QD8"_\8&`HN#F`4```^V1`(?B$8!
+M@^`!#[;`B40D"+@`````Q@0X`(/``8/X)'7TBYW$#```B=JP`(VV`````,8$
+M$`"#P`$]``(``'7RC4LVN@`````/MD0R(8@$"@^V1#(@B$0*`8/"`H/Z*'7G
+MC4L4L@(/MD0R"XA$"OX/MD0R"HA$"O^#P@*#^A9UYHU++K(`#[9$,DF(!`H/
+MMD0R2(A$"@&#P@*#^@AUYXE?'(M&4(M65(/``8/2`(D'B5<$@WY@`'4\]@8!
+M=#>+1F2%[0^5PH7`=!*$TG0.#[9`,X"\!;@$``#_=1F+1FB$TG0LA<!T*`^W
+M0"2`O`6X!```_W0:#[:&F````,'@`@)&`HA'$,=$)`@`````ZR*)+"3H_/__
+M_X7`=!*`N*4````"=0D/MD8!B$<0ZP3&1Q#_#[9&`HA'$;@!````]D9:$'0$
+M#[9&7(A'$L9'%A#&1Q40#[9$)`B-%``/ME\.@^/]"=.(7P[!X`4/MD\,@^'?
+M"<&(3PP/MT98P>@'@^`!P>`&@^&_"<&(3PP/MT98P>@"@^`!#[97#8/B_@G"
+MB%<-#[=&6L'H`\'@!X/A?PG!B$\,#[=&6M'H@^`!`<"#XOT)PHA7#0^W1EC!
+MZ`.#X`'!X`:#XK\)PHA7#0^W1EK!Z`3!X`>#XG\)PHA7#8/)$(A/#`^V!M#H
+M@^`!@^/^"<.(7PX/M@:#X`2#X_L)PXA?#F;'1Q@`$`^VAIL```"(1Q,/MH:8
+M````B$<@@\0,6UY?7<.055=64X/L"(M<)"B+="0LA=MT$[@`````Q@08`(/`
+M`3VL````=?*%]G02N`````"0Q@0P`(/``8/X*'7TBT0D'(NX1`4```^V1"0@
+MB40D!(D\).C\____B<%FA<!T#0^WP("\![@$``#_=4N+OT0%``"!Q\@,``"+
+MAT0%``")!"3H_/___RE$)"`/MD0D((E$)`2)/"3H_/___XG!9H7`#X0I`P``
+M#[?`@+P'N`0``/\/A!@#```/M\$/MH0'N`0``&:!^8$`#X<W`@``BX^P!0``
+M#[?`:<`4#0``C2P!A=L/A-8```"+50R%TG1L#[:'.`4``#S_=!4/ML!IP!0-
+M``"-!`&^@````#G"="`/MH<Y!0``//]T&@^VP&G`%`T``(T$`3G"=0J^@0``
+M`(GPB$,"@'TR`'0ON@`````/ML(/MDP%0+@!````T^`)0R"#P@$X53)V$.OD
+MQD,"_XM%"`^V0`F)0R#&`P$/MD4QB$,!BT5(B4,$BT5,B4,(C4L,C558BT58
+MB4,,BT($B4$$BT((B4$(BT(,B4$,BT5PB4,<BU0D((E3)`^VA9````")0RBX
+M`````.D7`@``A?8/A`H"``"#?"0D``^(_P$```^VA9`````Y1"0D#XWN`0``
+MBT0D)(T4@(U4U0"-@I`````/MD@$B`X/MD`%B$8!BX*8````#[8`@^`/B$8"
+M@/D#="*`^0-W#H#Y`@^%C@```.F0````@/D$=#6`^1*-=@!U?.M5BU0D)(T$
+MDHN4Q9@````/MD(!@^`'#[;`P>`(#[92`@'0C02``<")1@3K5HM4)"2-!)*+
+MA,68````#[9``H3`=0G'1@0`````ZS</ML"#Z!2)1@3K+(M4)"2-!)*+E,68
+M````#[9"`L'@"`^V4@,!T(T$@`'`B48$ZP?'1@0`````C4X(BU0D)(T$DHV$
+MQ9````"-4`R+0`R)1@B+0@2)002+0@B)00B+0@R)00R+0A")01"+0A2)012+
+M0AB)01B+0AR)01RX`````.G0````#[?0:=*P````B=8#MY0%``#&0P+_Q@,"
+MBX>4!0``#[9$`A^(0P&+1E0/MD`)B4,@#[:&I0```#P"=2W'0P1(4%0`C4,,
+MQT,,4F]C:\=`!&5T4W3'0`AO<B``#[=6(HU#%^@GOO__ZT4\`W4AQD,!$,=#
+M(`$```#'0P1(4%0`QT,,14HS-&;'0Q`P`.L@QD,$=@^W5B"-0P7H\+W__\9#
+M#&0/MU8BC4,-Z."]___&0QQR#[96'8U#'>B0O?__BT0D((E#)+@`````ZP6X
+M_____X/$"%M>7UW#D(UT)@!55U93@^P,BW0D*+@`````Q@0P`(/``3TH#0``
+M=?*+1"0@BYA$!0``#[9$)"2)1"0$B1PDZ/S___^)P6:%P'0-#[?`@+P#N`0`
+M`/]U2XN;1`4``('#R`P``(N#1`4``(D$).C\____*40D)`^V1"0DB40D!(D<
+M).C\____B<%FA<`/A$<#```/M\"`O`.X!```_P^$-@,```^WP0^VA`.X!```
+M9H'Y@0`/AU4"``"+B[`%```/M\!IP!0-``"-+`&+50R%TG1L#[:#.`4``#S_
+M=!4/ML!IP!0-``"-!`&_@````#G"="`/MH,Y!0``//]T&@^VP&G`%`T``(T$
+M`3G"=0J_@0```(GXB$8"@'TR`'0ON@`````/ML(/MDP%0+@!````T^`)1B"#
+MP@$X53)V$.ODQD8"_XM%"`^V0`F)1B#&!@$/MD4QB$8!BT5(B48$BT5,B48(
+MC4X,C558BT58B48,BT($B4$$BT((B4$(BT(,B4$,BT5PB48<BT0D)(E&)("]
+MD``````/A$8"``#&1"0+``^V?"0+C02_P>`#C0PP`>B-D)`````/MEH$B)FH
+M````#[92!8B1J0```(N`F`````^V`(/@#XB!J@```(#[`W0M@/L#=PZ`^P(/
+MA:T```#IM@```(#[!)"-="8`=#Z`^Q(/A94```"0C70F`.MFC0R_P>$#BY0-
+MF`````^V0@&#X`</ML#!X`@/ME("`="-!(`!P(F$#JP```#K;HT$OXT4Q0``
+M``"+A!68````#[9``H3`=0W'A!:L`````````.M(C12_#[;`@^@4B836K```
+M`.LVC0R_P>$#BY0-F`````^V0@+!X`@/ME(#`="-!(`!P(F$#JP```#K#HT$
+MO\>$QJP`````````C02_P>`#C9P&H````(U+$(V$!9````"-4`R+0`R)0Q"+
+M0@2)002+0@B)00B+0@R)00R+0A")01"+0A2)012+0AB)01B+0AR)01R`1"0+
+M`0^V1"0+.(60````#X;7````Z9'^__\/M]!ITK````")UP.[E`4``,9&`O_&
+M!@*+@Y0%```/MD0"'XA&`8M'5`^V0`F)1B`/MH>E````/`)U+<=&!$A05`"-
+M1@S'1@Q2;V-KQT`$9713=,=`"&]R(``/MU<BC487Z$>Z___K13P#=2'&1@$0
+MQT8@`0```,=&!$A05`#'1@Q%2C,T9L=&$#``ZR#&1@1V#[=7((U&!>@0NO__
+MQD8,9`^W5R*-1@WH`+K__\9&''(/ME<=C48=Z+"Y__^+1"0DB48DN`````#K
+M#+C_____ZP6X`````(/$#%M>7UW#C;0F`````(V\)P````!55U93@^P,BW0D
+M*+@`````Q@0P`(/``3VD#```=?*+1"0@BYA$!0``#[9$)"2)1"0$B1PDZ/S_
+M__^)P6:%P'0-#[?`@+P#N`0``/]U2XN;1`4``('#R`P``(N#1`4``(D$).C\
+M____BU0D)"G"#[;"B40D!(D<).C\____B<%FA<`/A!X#```/M\"`O`.X!```
+M_P^$#0,```^WP0^VA`.X!```9H'Y@0`/AS,"``"+B[`%```/M\!IP!0-``"-
+M+`&+50R%TG1L#[:#.`4``#S_=!4/ML!IP!0-``"-!`&_@````#G"="`/MH,Y
+M!0``//]T&@^VP&G`%`T``(T$`3G"=0J_@0```(GXB$8"@'TR`'0ON@`````/
+MML(/MDP%0+@!````T^`)1B"#P@$X53)V$.ODQD8"_XM%"`^V0`F)1B#&!@$/
+MMD4QB$8!BT5(B48$BT5,B48(C4X,C558BT58B48,BT($B4$$BT((B4$(BT(,
+MB4$,BT5PB48<@+V0``````^$)`(``,9$)`L`#[9\)`N-!+_!X`.-##`!Z(V0
+MD`````^V6@2(620/ME(%B%$EBX"8````#[8`@^`/B$$F@/L#="V`^P-W#H#[
+M`@^%H0```.FG````@/L$D(UT)@!T.X#[$@^%B0```)"-="8`ZUV-#+_!X0.+
+ME`V8````#[9"`8/@!P^VP,'@"`^V4@(!T(T$@`'`B40.*.MBC02_C13%````
+M`(N$%9@````/MD`"A,!U"L=$%B@`````ZS^-%+\/ML"#Z!2)1-8HZS"-#+_!
+MX0.+E`V8````#[9"`L'@"`^V4@,!T(T$@`'`B40.*.L+C02_QT3&*`````"-
+M!+_!X`.-7`8@C4L,C80%D````(U0#(M`#(E##(M"!(E!!(M""(E!"(M"#(E!
+M#(M"$(E!$(M"%(E!%(M"&(E!&(M"'(E!'(!$)`L!#[94)`LXE9`````/AM``
+M``#IK/[__P^WT&G2L````(G7`[N4!0``QD8"_\8&`HN#E`4```^V1`(?B$8!
MBT=4#[9`"8E&(`^VAZ4````\`G4MQT8$2%!4`(U&#,=&#%)O8VO'0`1E=%-T
-MQT`(;W(@``^W5R*-1A?H5[K__^M%/`-U(<9&`1#'1B`!````QT8$2%!4`,=&
-M#$5*,S1FQT80,`#K(,9&!'8/MU<@C48%Z""Z___&1@QD#[=7(HU&#>@0NO__
-MQD8<<@^V5QV-1AWHP+G__XM$)"2)1B2X`````.L,N/_____K!;@`````@\0,
-M6UY?7<.-M"8`````C;PG`````%575E.#[`R+="0HN`````#&!#``@\`!/:0,
-M``!U\HM$)""+F$@%```/MD0D)(E$)`2)'"3H_/___XG!9H7`=`T/M\"`O`.\
-M!```_W5+BYM(!0``@</,#```BX-(!0``B00DZ/S___^+5"0D*<(/ML*)1"0$
-MB1PDZ/S___^)P6:%P`^$'@,```^WP("\`[P$``#_#X0-`P``#[?!#[:$`[P$
-M``!F@?F!``^',P(``(N+M`4```^WP&G`%`T``(TL`8M5#(72=&P/MH,\!0``
-M//]T%0^VP&G`%`T``(T$`;^`````.<)T(`^V@ST%```\_W0:#[;`:<`4#0``
-MC00!.<)U"K^!````B?B(1@*`?3(`="^Z``````^VP@^V3`5`N`$```#3X`E&
-M((/"`3A5,G80Z^3&1@+_BT4(#[9`"8E&(,8&`0^V13&(1@&+14B)1@2+14R)
-M1@B-3@R-55B+15B)1@R+0@2)002+0@B)00B+0@R)00R+17")1AR`O9``````
-M#X0D`@``QD0D"P`/MGPD"XT$O\'@`XT,,`'HC9"0````#[9:!(A9)`^V4@6(
-M426+@)@````/M@"#X`^(02:`^P-T+8#[`W<.@/L"#X6A````Z:<```"`^P20
-MC70F`'0[@/L2#X6)````D(UT)@#K78T,O\'A`XN4#9@````/MD(!@^`'#[;`
-MP>`(#[92`@'0C02``<")1`XHZV*-!+^-%,4`````BX05F`````^V0`*$P'4*
-MQT06*`````#K/XT4OP^VP(/H%(E$UBCK,(T,O\'A`XN4#9@````/MD("P>`(
-M#[92`P'0C02``<")1`XHZPN-!+_'1,8H`````(T$O\'@`XU<!B"-2PR-A`60
-M````C5`,BT`,B4,,BT($B4$$BT((B4$(BT(,B4$,BT(0B4$0BT(4B4$4BT(8
-MB4$8BT(<B4$<@$0D"P$/ME0D"SB5D`````^&T````.FL_O__#[?0:=*P````
-MB=<#NY@%``#&1@+_Q@8"BX.8!0``#[9$`A^(1@&+1U0/MD`)B48@#[:'I0``
-M`#P"=2W'1@1(4%0`C48,QT8,4F]C:\=`!&5T4W3'0`AO<B``#[=7(HU&%^B)
-MMO__ZT4\`W4AQD8!$,=&(`$```#'1@1(4%0`QT8,14HS-&;'1A`P`.L@QD8$
-M=@^W5R"-1@7H4K;__\9&#&0/MU<BC48-Z$*V___&1AQR#[97'8U&'>CRM?__
-MN`````#K#+C_____ZP6X`````(/$#%M>7UW#C;0F`````%575E.#[`B+7"0D
-MN`````#&!!@`@\`!/0`!``!U\HM$)!R+N$@%```/MD0D((E$)`2)/"3H_/__
-M_XG!9H7`=`T/M\"`O`>\!```_W5+B[](!0``@<?,#```BX=(!0``B00DZ/S_
-M__^+5"0@*<(/ML*)1"0$B3PDZ/S___^)P6:%P`^$P@$```^WP("\![P$``#_
-M#X2Q`0``#[?!#[:$![P$``!F@?F!``^'UP```(N/M`4```^WP&G`%`T``(TT
-M`8M6#(72=&P/MH<\!0``//]T%0^VP&G`%`T``(T$`;V`````.<)T(`^VAST%
-M```\_W0:#[;`:<`4#0``C00!.<)U"KV!````B>B(0P*`?C(`="^Z``````^V
-MP@^V3`9`N`$```#3X`E#((/"`3A6,G80Z^3&0P+_BT8(#[9`"8E#(,8#`0^V
-M1C&(0P&+1DB)0P2+1DR)0PB-2PR-5EB+1EB)0PR+0@2)002+0@B)00B+0@R)
-M00R+1G")0QRX`````.G)````#[?0:=*P````B=8#MY@%``#&0P+_Q@,"BX>8
-M!0``#[9$`A^(0P&+1E0/MD`)B4,@#[:&I0```#P"=2W'0P1(4%0`C4,,QT,,
-M4F]C:\=`!&5T4W3'0`AO<B``#[=6(HU#%^@EM/__ZT4\`W4AQD,!$,=#(`$`
-M``#'0P1(4%0`QT,,14HS-&;'0Q`P`.L@QD,$=@^W5B"-0P7H[K/__\9##&0/
-MMU8BC4,-Z-ZS___&0QQR#[96'8U#'>B.L___N`````#K!;C_____@\0(6UY?
-M7<.-=@"-O"<`````@^PLB5PD'(ET)"")?"0DB6PD*(M\)#"+;"0TBT=LB40D
-M%(M%)(DXBT=@A<!U$L9%9@*)+"3_57#IN`4``(UV`/9`*`)T$L9%9@*)+"2-
-M=@#_57#IG04``(M,)!2)#"3H_/___XG&A<!U%L9%9@*)+"3_57#I?`4``(VT
-M)@````#'0&0`````B6A(BT=@B488BT=@#[=`'&:)1A#&1A2`#[9%9#P"#X19
-M`0``/`)W"83`="+INP(``#P#C;8`````#X3!`0``/`0/A:4"``")]NF-`0``
-MBT=@]D`X`8UT)@`/A)`````/MD5EJ`)T!L9&)(CK$(/@!#P!&<"#X`6#Z':(
-M1B2+34B+74P/MT509HE$)!K&1B4`B=C!Z!B(1B:)V,'H$(A&)XG8P>@(B$8H
-MB%XIB<@/K-@8B$8JB<@/K-@0B$8KB<@/K-@(B$8LB$XMQD8N`,9&+P`/MT0D
-M&F;!Z`B(1C`/MDPD&HA.,<9&,@#&1C,`ZVL/MD5EJ`)T!L9&)"CK$(/@!#P!
-M&<"#X`6#P"J(1B2+34B+74P/MT509HE$)!K&1B4`B<@/K-@8B$8FB<@/K-@0
-MB$8GB<@/K-@(B$8HB$XIQD8J``^W1"0:9L'H"(A&*P^V3"0:B$XLQD8M`(M'
-M8`6X````B48XQD8<(`^W1"0:P>`)B48@@TYD`NE\`0``#[9%2#P0=P7V!P)U
-M"<9%9@;IK0,``(U.)`^VP(U54(E$)`B)5"0$B0PDZ/S___^+1V`%N````(E&
-M.,9&'""!3F0``!``QD85J_9%908/A"D!``"+14R)1B#I'@$```^V166#X#`\
-M('41QD8D&\9&)0'&1B@`Z0(!``#&1B0UZ?D```"+1V`/MD`D@^`%@_@%=1.!
-M3F0``"``#[=55&8[54IU#NM<QD5F!HUV`.D2`P``#[9%4SSCD(UT)@!T0SSC
-M=Q(\0G0[/+"-="8`="`\0'4BZRT\[(VV`````'00/.]T'SSE=0Z-M@````#K
-M$V:)54KK#<9%9@:-="8`Z<("``#&1B2P#[=%2(A&)0^W14J(1B8/MT5,B$8G
-M#[=%3HA&*`^W15"(1BD/MD52B$8J#[9%4XA&*P^V14F(1BP/MD5+B$8M#[9%
-M38A&+@^V14^(1B\/MD51B$8P]D5E!G0=#[=%5,'@"8E&((-.9`3K#<9%9@;I
-M2P(``(UT)@#'1FQ@K`,`#[9%9:@&#X0>`@``J`)T!H-.9`CK!(-.9!"-?CR+
-M76B%VW0&]D5E`74\BU5LA=(/A","``#'1"0(`````(M,)!2+@4@&``")1"0$
-MB2PD_]*%P`^$``(``(M$)!2+F$@&``"%VW1(B30DZ/S____'1"0$`````(D\
-M).C\____@\,0BT/PB40D#(M#^(M3_(E$)`2)5"0(B3PDZ/S___^+0_2#PQ"%
-MP`^%@@$``.O3QT0D!`````")/"3H_/___XM&(#T`"```=T.+3"04B0PDZ/S_
-M__^)PH7`=0G&168+Z5T!``"+0`B)1C2)5E"+1B")1"0,BT(,BU(0B40D!(E4
-M)`B)/"3H_/___^M3/0```0!W0XM$)!2)!"3H_/___XG"A<!U"<9%9@OI$P$`
-M`(M`"(E&-(E64(M&((E$)`R+0@R+4A")1"0$B50D"(D\).C\____ZPG&168&
-MZ>(````/MD5EJ`20C70F``^$OP```(!]9`-U(HM-6(7)=!N+5C2+1B")1"0(
-MB4PD!(D4).C\____Z9<```"+56B%TG4-BU5LA=(/A;D```#K:(M^-*@!=0F)
-MTY"-="8`ZS"+56R%TG0IQT0D"`$```"+3"04BX%(!@``B40D!(DL)/_2A<!T
-M"HM$)!2+F$@&``"#PQ"+0_B+4_")5"0(B40D!(D\).C\____`WOPBT/T@\,0
-MA<!U'>O;BT8@BU8TA<!T$<8"`(/"`8/H`70&Z_.#3F0!B70D!(M,)!2)#"3H
-M_/___^LNB70D!(M$)!2)!"3H_/___XDL)/]5<.L6NP````#I3/[__XM^-(UT
-M)@#I5/___XM<)!R+="0@BWPD)(ML)"B#Q"S#C;0F`````%=64X/L$(M\)""+
-M="0DN`````#&!#``@\`!@_AX=?2#OU0%```!#Y1&$P^V5R(/MD\A#[9?(`^V
-M1R.(1@.(5@*(3@&('H!.$1`/MT<89HE&!`^W1QIFB48&BX=4!0``B$9LQD82
-M(`^W5QIF@?H@(70'9H'Z(B%U1\9&%P*-1CS'1CQ2;V-KQT`$97120<=`"$E$
-M(%/'0`Q31"`RQT`0,3)X(,=`%$-O;G3'0!AR;VQL9L=`'&5RQD`>`.D"`0``
-MC8+PV/__9H/X`7829H'Z0"%T"V:!^D0A#X6E````QD87!`^W5QJ-@O#8__]F
-M@_@!=T.-1CS'1CQ2;V-KQT`$97120<=`"$E$(#+'0`PW,7@@QT`04T%3(,=`
-M%$-O;G3'0!AR;VQL9L=`'&5RQD`>`.F-````9H'Z0"%T!V:!^D0A=7^-1CS'
-M1CQ2;V-KQT`$97120<=`"$E$(%/'0`Q31"`RQT`0,31X(,=`%$-O;G3'0!AR
-M;VQL9L=`'&5RQD`>`.L_QD87"(U&/,=&/$1A=&''0`1#96YTQT`(97(@-\=`
-M##(X,"#'0!!3051!QT`4($-O;L=`&'1R;VS'0!QL97(`#[9&$O9F%XA&$(3`
-M=03&1A"`C488QT882&EG:,=`!%!O:6['0`AT(%1EQT`,8VAN;\=`$&QO9VG'
-M0!1E<RP@QT`826YC+L9`'`"+AU`%``"%P'00BT`(B49DB<+!^A^)5FCK#HM'
-M"(E&9(G"P?H?B59HQT9@`"```,=$)`1\````BT<0B00DZ/S___^)PH'B\`,`
-M`,'J!(A6;8/@#XA&;\=$)`2`````BT<0B00DZ/S___^)PH'B``#P`\'J%(A6
-M;B4```\`P>@0B$9P@\006UY?PXVV`````(V_`````%575E.#[!R+?"0PBW0D
-M-(M<)#BX`````,8$&`"#P`$]G````'7RB7,(@_X_?@F!Q\P,``"#[D"X````
-M`(.\M[P"````#X6?`@``B9RWO`(``(E[;(M$)#R)0W"+3"1`B4MX@'\Y`0^%
-M>`(``('^A0````^/6@(```^VA#>\!```//\/A$H"```/ML!FB40D&`^WP&G`
-M*`$``(G%`Z]\!0``]D4G!`^$)P(``(M%)"4`__\`/0``_P`/A10"``#V12@$
-M#X2'`0``QH6T``````^V320/MM&)T(/@!H/X!G4Y]L(!#X0#`0``QD4F!<9%
-M)P2);"0,#[9%38E$)`B+13")1"0$BT4LB00DZ/S___^X`0```.G0`0``@_@$
-M#X7"`0``]L$!#X2Y`0``BUTLBT4TA<`/A8(```#&128#QD4G!(!["@!T4;X`
-M````C4,XB40D%(M,)!2)#"3H_/___XG"BT,\B5,\BTPD%(D*B4($B1"`>B;_
-M=!4YU701QH6U`````;@!````Z5P!``"#Q@$/MD,*.?!_NX"]M0````$/A#\!
-M``");"0$B3PDZ/S___^X`0```.DN`0``@'@F``^%'P$``&:#8#+]BT4T9L=`
-M,B``BT4TB40D!(D\).C\____N`$```#I_0```(M%+`^V0`F`?R8`="^[````
-M``^V\`^VRXGPT_BH`704QT0D"`````")3"0$B3PDZ/S___^#PP$X7R9WV<9%
-M)P;&128%9L>%E```````B6PD!(D\).C\____N`$```#IF@```(MM+(!]"@!T
-M7L9$)!L`C44XB40D$(M,)!")#"3H_/___XG"BT4\B54\BTPD$(D*B4($B1"`
-M>B;_=!X/MD(E/")T!#P-=1+'A+>\`@```````+@`````ZT*`1"0;`0^V1"0;
-M.$4*=ZX/MT0D&(E$)`B)7"0$B3PDZ/S___^X`0```.L7QX2WO`(```````"X
-M`````.L%N`$```"#Q!Q;7E]=PY"0D)"0D)"0D)"0D)"0D(M4)`2A`````(E"
-M!(D5`````,.-M@````"-O"<`````H0`````%F`$#`,.0C70F`(M$)`2+3"0(
-MA<!T%(L0A=)T"87)=`6+0@2)`8G0PXGVBQ4`````Z^:0C;0F`````(M$)`2+
-M5"0(!9@!`P`#0A##ZPV0D)"0D)"0D)"0D)"04X'L^````(N4)``!``"-A"2`
-M````BYPD!`$``(M*!(E$)`2+0@B)!"3_41R-1"0(BU,$B40D!(M#"(D$)/]2
-M'`^V1"0).(0D@0```'8-N`$```"!Q/@```!;PW(D#[9$)`HXA"2"````=^-R
-M%`^V1"0+.(0D@P```'?3<@0QP.O2N/_____KRY"-M"8`````5U93@^P0BQT`
-M````BW0D((7;=0CK>HL;A=MT=(M#"(7`=':+5@0[4`1UZXM`"(E$)`2+1@B)
-M!"3_4B2$P'37BU,(C7L(A=)U'^MFD(UT)@")5"0$B30DZ/S___^%P'A1BS^+
-M%X72=$F+1@2+B(````"%R73;.T($==:+0@B)1"0$BT8(B00D_]'KT9"-="8`
-M,<"#Q!!;7E_#QP8`````N`$```")7@R)<PB#Q!!;7E_#BP>)7@R)!K@!````
-MB3?KT>L-D)"0D)"0D)"0D)"0D(M4)`2A`````(D"BT(,B14`````A<!T$*$`
-M````B4(0`T(,HP````#SPXVV`````%=64X/L$(L=``````^V="0@A=MT+8GP
-M.$,$=":)\`^V^.L'B?`X0P1T&(M#0(7`=`F)/"3_T(7`=0B+&X7;B?9UX8/$
-M$(G86UY?PY"-="8`5HG64S'2BU@,@\`,.=AT'CF3]/W__XG9=0[K&(UT)@`Y
-MD?3]__]T#(L).<AU\HE6'%M>PX/"`>O3C;0F`````(L5`````+AT````A=)T
-M%##`BTH8.<AS`HG(BQ*%TG7Q@\!T\\.-="8`C;PG`````%.+1"0(BUPD#(M0
-M#(U(##G*=0CK$XL2.<IT#8V"V/W__SE8''7O6\-;,<##C70F`%.#[`B+1"00
-MBU@(A=MT$Y"+4P2+0PB)!"3_4FR+&X7;=>Z#Q`A;PXGVC;PG`````(M$)`2)
-MPHL`Z2/___^-=@"+1"0$BU`<A=)X!\=`'/_____SPXVV`````(V_`````%.+
-M7"0,,<"%VW07BU0D"#')`=,/M@*#P@$!P3G:=?0/ML%;PXVV`````(V_````
-M`*$`````BTPD!(7`="2+4`B%TG07.4H(=0SK&)"-="8`.4H(=`R+$H72=?6+
-M`(7`==SSP_/#C70F`(V\)P````!75E.+1"00BW0D%(M\)!B+4`R-6`PYVG4-
-MZS&0C70F`(L2.=-T)HV"V/W__X!X"`1V[CEP)'7IA?]X%XM(#(7)=-XY1+E(
-M==A;7E_#6S'`7E_#BT@,A<EUQ^OMD(UT)@!75E.#[!"+?"0@B3PDC7<,Z/S_
-M__^+7PPY\W0JC70F`(V3V/W__XN")`(``(7`=!"+0@2+0#B%P'0&B10D_]"0
-MBQLY\W7:B3PDZ/S___^+1PPY\'4(ZQF+`#GP=!.+6/B%VW3S@\00N`$```!;
-M7E_#@\00,<!;7E_#C;0F`````%<QP%93@^P0BWPD(("_A`$#``!U)XM?"(7;
-M=!XQ]HGVBT,$BU,(B10D_U!4BQL)QH7;=>R)\(3`=0DQP(/$$%M>7\.)/"3H
-M_/___X/$$(GR6P^VPEY?PXGVC;PG`````%575E.#[`R+="0@Z/S___^+GL@`
-M``")QX7;#X2,````BT,$B=J-KL@````I^(7`?@[IA@```(M"!"GXA<!_,XM"
-M%(7`=`.):!")AL@```")PXM"#,="$`````#'0A0`````B00D_U((BY;(````
-MA=)UQ(DT).C\____A=MT"HN&R````#G8=`B#Q`Q;7E]=PXM`!"GXB40D!(M&
-M!(D$).C\____@\0,6UY?7<.)="0@@\0,6UY?7>G\____B30DZ/S____KN(UV
-M`(V\)P````!75E.+="04BWPD$.C\____BTX0A<ET%HM6%(72=`:)2A"+3A")
-M$<=&$`````"+E\@```")P0,.C9_(````A=*)3@1U#.L^C5H4BU(4A=)T-(M"
-M!"G(A<!^[8E6%(U&%(DS.;?(````B5X0B4(0=26+!HE$)!2+1P2)1"006UY?
-MZ?S___^)5A2),SFWR````(E>$'3;6UY?PY"-M"8`````5E.#[`2+3"04BW0D
-M$(M1$(72=%"+012+GL@```"%P'0&B5`0BU$0B0+'010`````BX;(````QT$0
-M`````(7`=",YPW0?BU@$Z/S___\IPXE<)!2+1@2)1"00@\0$6U[I_/___X/$
-M!%M>PXVV`````%93@^P4BW0D((M>"(7;=13K+HM3!(M#"(D$)/]2:(L;A=MT
-M'(![1`!TZ(M3!,=$)`0`````BT,(B00D_U(HZ]*-ALP```")-"2)1"0$Z/S_
-M__^#Q!1;7L.0C;0F`````%=64X/L$(M\)""+7PB%VW4(ZS*+&X7;="R+4P2+
-M0PB)!"3_4G"`>T0`=.B+4P3'1"0$`0```(M#"(D$)/]2*(L;A=MUU(M?#(UW
-M##GS=0CK)XL;.?-T(8V3V/W__X!Z"`%U[HM"!(M`.(7`=.2)%"3_T(L;.?-U
-MWX`]``````!T.(V?S````(E<)`2)/"3H_/___\>'S`````"'DP/'A]0`````
-M````B;_8````B5PD!(D\).C\____@\006UY?PU575E.#[`R+="0DBVPD((7V
-M=%Z+5@2+1@B)!"3_4G"`?D0`#X6:````BUT,C7T,.?MU".LLBQLY^W0FC9/8
-M_?__@'H(`77N.7)8=>F+0@2+0#B%P'3?B10D_]"+&SG[==J+-H7V=!&#Q`R)
-M\%M>7UW#BW4(A?9UFX`]``````!TYHV=S````(E<)`2)+"3H_/___\>%S```
-M``"'DP/'A=0`````````B:W8````B5PD!(DL).C\____@\0,B?!;7E]=PXM6
-M!,=$)`0!````BT8(B00D_U(HZ4W___^-="8`4X/L"(M<)!")'"3H_/___XG!
-MQT`(`````(U`=(E!)(M##(U1*(/H=(E!((U!#(E!#(E!$#'`Q@00`(/``8/X
-M3'7T@\0(B<A;PXVT)@````"#[`PQTHE<)`2+7"04B70D"(MT)!@Y<PAR(8D<
-M).C\____B<*+1"00B7((B5H$B0*+0PB#P`$I\(E#"(M<)`2)T(MT)`B#Q`S#
-MC;0F`````(/L#(M4)!"+1"04B10DB40D"(U":(E$)`3H_/___X/$#,.-M"8`
-M````C;PG`````(M,)`B+1"0$BU$(`U`(@^H!B5`(Z?S___^-M"8`````@^P,
-MBT0D$(E$)`2+`(/`:(D$).C\____@\0,PXUT)@!5B<575E.#[`R+<`R->`PY
-M_G4(ZT>+-CG^=$&-GMC]__^`>P@!=>X/MD-,J$`/A6T!``"`/0``````=-FH
-M`G75J`$/A9T!``#V0TP$C70F`'7#@$M,)(LV.?YUOXM=%(UU%#GS=!&-0_2)
-M!"3H_/___XL;.?-U[XMU##G^#X2:````C8;8_?__@'@(!'8+BU@,A=L/A#H!
-M``"+-CG^=>.+70PY^W1VQD0D"P#K"8UV`(L;.?-T/HV3V/W__X!Z"`%U[O9"
-M3"!TZ(M")(!B3-N%P'4/Z=4```"+`(7`#X3+````BT@4A<ET[XL;QD0D"P$Y
-M\W7"BW4,.?=T(9"-="8`C9[8_?__]H,<`@```70'BT,,A<!T((LV.?YUY(N5
-MC`$#`(72=`B+102)!"3_TH/$#%M>7UW##[93"(#Z!'8/BX-D`0``A<!T$#E8
-M!'0+@.H!=</V0TP"=+V+0QR%P(GV#XB/````]H,<`@```G2GQT0D!`````")
-M+"3H_/___X7`B<)TD3G#=(WV@!P"```"='.`HQP"``#]Z7C___^)]HD<).C\
-M____Z6C^__^`?"0+``^%^/[__X`]``````&0#X7J_O__B10DZ/S____IW?[_
-M_XD$).C\____D(UT)@#IM/[__XD<).C\____C78`Z5/^__^)VHGHZ&+V__^)
-M]NEA____BT,<B4(<QT,<`````.G__O__B?:-O"<`````55=64X'LG````(N<
-M)+````"%VXM[#`^$WP```,=$)!@`````C50D)(M#!(E4)`2+4PB)%"3_4!P/
-MMD0D-#L%-`(```^.G@```(U#$(E$)!3K(#EK&(-4)!@`BQ4T`@``#[9$)#2#
-MP@$YT(D5-`(``'YU]D0D-0%U$0^V!0`````[1"08#X2-````BVL8BU0D%(.'
-MD`$#``&)%"3H_/___XM3!(E<)!#'1"0,8/L#`(E$)`B)QJ$T`@``B40D!(M#
-M"(D$)/]2-(3`=8>+1"04B70D!(D$).C\____@Z^0`0,``>ES____BQO'!30"
-M````````A=L/A2G___^+AY`!`P"#Z`&%P(F'D`$#`'4[B?CHR_S__^LR#[8%
-M`````,<%)`(```````")'2@"``#'1"0$'`(``&G`0$(/`(D\)*,<`@``Z/S_
-M__^!Q)P```!;7E]=PXVV`````(V_`````%575E.#[`R+="0@BVPD*(M\)"2+
-M7@B)KHP!`P"%VW4(ZR6+&X7;=!^+0P2+4PB)%"3_4'B$P'7JQH:$`0,``8/$
-M#%M>7UW#BQT`````A=MT$HM#*(7`=`6)-"3_T(L;A=MU[H7_=!B+5P3'1"0$
-M`0```(M'"(D$)/]2*,9'1`&+1@C'AI`!`P`!````B00DZ/S___^+AI`!`P"%
-MP'2AA>UT$(ET)""#Q`Q;7E]=Z?S____'!"2@A@$`Z/S___^)-"3H_/___XN^
-MD`$#`(7_=>+I:O___XUT)@"-O"<`````@^P<B70D%(MT)"")?"08BT0D*(E<
-M)!"+?"0DBUX,@ZN0`0,``87`>$>)1"0(B7PD!(DT).C\____A<!T1(N#D`$#
-M`(7`=!"+7"00BW0D%(M\)!B#Q!S#B=B+="04BUPD$(M\)!B#Q!SI,_O__XUV
-M`(U&$(E\)`2)!"3H_/___^N\BT8$B3PD_U!`C480B7PD!(D$).C\____ZZ*0
-MC70F`%575E.#[`R+?"0@BP>+<!R-:!R)1"0(ZQ&-M"8`````C5[TBS8Y>RAT
-M/SGU=?*+1P2+0#2%P'0%B3PD_]"+ARP"``"+ER@"``")0@2)$(M$)`B)?"0$
-M@\`XB00DZ/S___^#Q`Q;7E]=PXM3#(U+#(M#$(E"!(D0B4L0B4L,QD-F`HD<
-M).C\____ZY^0C70F`%575E.#[!R+?"0PBVPD-(M'#(M0#(/`##G"=0_IHP``
-M`(L2.<(/A)D```"-FMC]__^`>P@!=>H[:U1UY3M[6'7@A=MT?_:#'`(```$/
-MA=(```"+@Z0```"%P`^%Q````(N#E````(7`#X6V````BT,DA<!U".M%BP"%
-MP'0_BU`4A=)T\XMR#(7V#X2A````@'XP``^$EP```#')ZP\/MD8P@\$!.<@/
-MCH0````Y5(Y(=>O'1(Y(`````.OAB1PDZ/S___^-=Q")-"3H_/___X7`B<-T
-M3XM$)#R+5P2)7"0(B6PD!(E$)!"+1"0XB40D#(M'"(D$)/]2-+H!````A,!T
-M"H/$'(G06UY?7<.)7"0$B30DZ/S___^#Q!PQTEN)T%Y?7<.#Q!PQTEN)T%Y?
-M7<.)%"3H_/___^DQ____C78`55=64X'LG````(NL)+0```"+O"2P````A>T/
-MA+X!``"+=PB%]G1QBX>4`0,`BU8$B48HC40D)(E$)`2+1@B)!"3_4AR+5@2+
-M1@@/MEPD-`&?E`$#`(D$)/]2,(E<)`R);"0$B40D"(U&$(D$).C\____#[9$
-M)#3'1"0(%````(EL)`2)1"0,C48LB00DZ/S___^+-H7V=8^A`````+I@`@``
-MA<!T%S')BU`4.=%S`HG1BP"%P'7QC9%@`@``BX>4`0,`B50D"(EL)`2-!,")
-M1"0,C4<XB00DZ/S___^+AY0!`P#'1"0(``(``(EL)`2)1"0,C4=0B00DZ/S_
-M__^-AY@```")!"3'1"0,`0```,=$)`@L````B6PD!.C\____BX>4`0,`QT0D
-M"!0```");"0$B40D#(V'L````(D$).C\____BX>4`0,`QT0D"&@```");"0$
-MC03`B40D#(V'@````(D$).C\____QX?D`````0```,>'\``````0``#'A^@`
-M````$```Z/S____'1"0,0B$``(EL)`2)1"0(C4=HB00DZ/S___^+'0````"%
-MVW0@BU,<A=)T$XN'E`$#`(EL)`2)/"2)1"0(_]*+&X7;=>"!Q)P```!;7E]=
-MPXMO!.DZ_O__C78`C;PG`````%93BQT`````Z/S___^+="0,A<!T#8GRQ@(`
-M@\(!@^@!=?6A`````(7`=0?K6HUV`(G#BP.%P'7XB3.+1"00QX9D`0,``!``
-M`(E&!(U&#(E&#(E&$(U&%(E&%(E&&(U&'(E&'(E&((V&0`$``(F&0`$``(F&
-M1`$``(V&8`$``(F&8`$#`%M>PXDU`````.NKD(/L'(`]``````*)="00#[9T
-M)"2)7"0,B7PD%(EL)!@/A``!``")\@^VPHD$).C\____A<")QP^$\P```(ML
-M)""#Q3B)+"3H_/___XG#,<"0Q@08`(/``3U@`@``=?*A.`(``(E[!(/``:,X
-M`@``B8-8`@``C8-(`@``@(L<`@```8F#2`(``(F#3`(``(GPB$,(BT<4BU0D
-M((7`B1-T(8M7%(V#8`(``(E#$(72=!$QP,:$&&`"````@\`!.=!U\8V#,`(`
-M`(F#,`(``(F#-`(``(V#.`(``(F#.`(``(F#/`(``(M',,=#(`(!``#'0QS_
-M____A<!T"8D<)/_0A<!U18M$)""-DR@"``"+2!")4!"#P`R)@R@"``")BRP"
-M``")$>L,B?`L`0^$]O[__S';B=B+="00BUPD#(M\)!2+;"08@\0<PXE<)`0Q
-MVXDL).C\____Z]J)]HV\)P````!75E.#[!"+%0````"+="0@.?)U#NFQ````
-MC;0F`````(G"A=)T"HL".?!U](L&B0*+1@R-7@PYV'0:C;8`````+2@"``")
-M!"3H_/___XM&##G8=>R+1A2-?A0Y^'0GC9Z`````@^@,BT@,BU`0B5$$B0J)
-M1"0$B1PDZ/S___^+1A0Y^'7?@+Z$`0,``'4<BQT`````A=MT$HM#+(7`=`6)
-M-"3_T(L;A=MU[HM>"(7;=!*+4P2+0PB)!"3_4G2+&X7;=>Z#Q!!;7E_#BP:C
-M`````.E:____D)"0D)"0D)"0D(M,)`0QP(M1$(VT)@````#&!!``@\`!@_@L
-M=?2-0@B)0@B)0@PQP(D2B5($QT(4<#`$`(E*&,="'`````##B?:+0"2#Z!0#
-M!7@"``##C78`BT`0,=*+"#G!=!*+$8M!!(E"!(D0BU$,B0F)202)T,.#[!R)
-MT8E<)!2)PXET)!B+<!"`>F0`=1(/MT)0,=(#04@344R)0T")4T2#1A`!BT-<
-MBU-0B4PD!(D$)/]23(M<)!2+="08@\0<PXVV`````(/L#(M$)!#V@!P"```(
-MBU`0=2;'0B0`````BU!0@(@<`@``"(E$)`C'1"0$X`@$`(M`7(D$)/]21(/$
-M#,.-=@!6N?____]3BT0D#(MT)!P/MUPD&`^V5"0@]H`<`@```70=A-)T%P^W
-MT\'B"872=`TQP,8$,`"#P`$YT'7U,<E;B<A>PXVV`````(V_`````(/L$(ET
-M)`2+="04B1PDB7PD"(EL)`SV1DQ`QT8P`````,=&-`````!U68M.)(7)=',Q
-M_S'M,=OK$(VT)@````"#PP&+"87)="V+012%P'7PBT$,BU$0`48P$58TBU$0
-MBT$,.>IRW7<$.?AVUXL)B<>)U87)==.#^P-_"(E^*(EN+.L.QT8H`````,=&
-M+`````"+'"2+="0$BWPD"(ML)`R#Q!##,?\Q[>O1C;8`````5E.+="0,B?,#
-M7"00.=YS%XG9#[91_@^V0?^(4?^(0?Z#Z0(YSG+K.=YT)0^V!CP@=2&)\NL'
-M#[8"/"!U&(/"`3G:=?*)\<8!`(/!`3G9=?9;7L.)\HGQA,!T()"-="8`@\(!
-M/"!T&P^V0O^(`8/!`3G3=`</M@*$P'7E.<MUQY#KSCG:=/4/M@*$P)"-="8`
-M=,4\('3!#[9"_X@!@\$!Z]/K#9"0D)"0D)"0D)"0D)"+1"0$BT`0QT`D`0``
-M`,.05E.#[`2+="00]D9,`G4MBUXDA=MT%HM3%(72=`F+0@2)%"3_4"2+&X7;
-M=>K'AJ0`````````@\0$6U[#B30DZ/S____'AJ0`````````@\0$6U[#C;8`
-M````C;\`````4X/L"(M<)!"+5"04]D-.`HM#$'0+]D`H`G05D(UT)@"#0"0!
-M@\0(6\.-M"8`````.5`D<NO'1"0$`0```(L#B00DZ/S___^%P(G"=-</MD!E
-MB5HHB5HLQD)D!(/@SX/(((A"9<9"9@#'0G"P!P0`B50D$(/$"%OI_/___XUT
-M)@!3B<.#[`C'1"0$`0```(L`B00DZ/S___^%P(G"=$#V0TX"=4'&0&0#QT!8
-M`````,9`4T!FQT!,``!FQT!.``!FQT!0``#&0%)`9L=`2```9L=`2@$`9L=`
-M5```B5HH@\0(B=!;P\9`9`*A!!@``(E"4`^W!0@8``#&0D@&QT),`````,9"
-M20!FB4)4Z\Z-=@"#[!R)7"04B<.)="08BW`0Z%O___^Z_____X7`=!W'0'!P
-M"`0`@$XH`8M34(E$)`2+0UR)!"3_4DPQTHM<)!2)T(MT)!B#Q!S#C;0F````
-M`%=64X/L$(M<)""+?"0D@'L(!'9&@'LP`'0Y,?;K#8GV#[9#,(/&`3GP?BB+
-M1+-(A<!T[?:`'`(```%TY(D$)(/&`8E\)`3H_/___P^V0S`Y\'_8@\006UY?
-MPW0P]H,<`@```73NB=CHM/[__X7`=..#!P&)>"S'0'#`!P0`B40D((/$$%M>
-M7^G\____BULD]H,<`@```72[Z\N-M@````#I_/___XUT)@"-O"<`````@^P<
-MBT0D((E<)!2)="08BU@LBS")!"3H_/___XL#@^@!A<")`W4/C4,$B40D!(DT
-M).C\____BUPD%(MT)!B#Q!S#C;0F`````(V\)P````!64X/L!(LU`````,<%
-M>`(```````"%]G4.ZRB0C70F`(MV!(7V=!R+'7@"``#_5D@YPW/L_U9(BW8$
-MA?:C>`(``'7DQP0D8`(``(,%>`(``!3H_/___X/$!#'`6U[#B?:#[!R+3"0@
-MB5PD%(ET)!B+<2B+7A`/ME,HB="#X/Z(0RB`>68!=#F)#"3H_/___XM3((72
-M=1N-0Q3'0R`!````B40D!(L&@\`LB00DZ/S___^+7"04BW0D&(/$',.-=@"#
-MXOR(4RCKOY"-M"8`````@^P,BU0D$(M"$("B'`(``/?'@I0`````````BT@@
-MA<EU&\=`(`$```"#P!2)1"0$BP*#P"R)!"3H_/___X/$#,/K#9"0D)"0D)"0
-MD)"0D)!3@^P(BT0D$(M8$(E$)`2+`P6P````B00DZ/S___^-@Y@```#'@Y@`
-M``!0!00`B9N<````QX.@`````````(E$)`2+`X/`)(D$).C\____@\0(6\.-
-MM@````"-OP````!64X/L%(MT)"#'1"0$8`(``(M<)"2+!HD$).C\____B<&+
-M1B2%P'05.=B-5B1U!NL2.=AT#HG"BP"%P'7T@\046U[#BP.)`HE<)"2)3"0@
-M@\046U[I_/___XVT)@````!5B<U7B==6,?93@^Q,BU0D9(E$)"2+1"1@B50D
-M'(M4)"2)1"08BU(DA=*)5"0X=!:)UC'`@WX4`8LV@]C_A?9U\X/X`WX*@\1,
-MB?!;7E]=PXM$)!B+5"0<BTPD.`'X$>J)3"0\B40D$(E4)!3K*HGVBUPD/(M3
-M"(M#!#'J,?@)P@^$`@$``(M4)#R+$H72B50D/`^$YP```(M4)#R+0A2%P'7-
-MBUH(BTH$.>MWV7($.?EWTXM4)!2+1"00B50D+(M4)#R)1"0HBT(,BU(0B40D
-M,`'(B50D-!':.50D+'>G<@8Y1"0H=Y^)VHG(,>HQ^`G"#X1/`@``.>MWBP^#
-M7@$``(M4)"3'1"0$8`(``(L"B00DZ/S___^)!"3H_/___X7`B<$/A!W___\Q
-MP,8$"`"#P`&#^!AU](M<)#R+0P2+4PB)002)^(E1"(GJ*T,$&U,(B7L$B4$,
-MBP.)41"+4Q"):PB)`8M##"M!#!M1$#E4)!R)"XE##(E3$`^&5@(``(MT)#SI
-MOO[__XL+A<ET5KL!````ZP:+"87)=$"+012%P'3SBU$(BT$$,>HQ^`G"=>6+
-M00R+41")1"0(BT0D/(E4)`P[4!!R#W<)BU0D"#M0#'8$B4PD/(/#`>NZ@^L!
-M#X]B_O__BUPD/(M+#(M;$#E<)!R)3"1`B5PD1'=P<@8Y3"08=VB+5"0DQT0D
-M!&`"``"+`HD$).C\____B00DZ/S___^%P(G"#X0:_O__,<#&!!``@\`!@_@8
-M=?2+7"0<B=:+3"08B7H$B6H(B5H0BUPD/(E*#(L#B0*)$^GG_?__.?D/@Q_^
-M___IE?[__XM<)#CK"HL;A=L/A,K]__^+0Q2%P'7OBTPD/(M$)$"+5"1$`T$$
-M$U$(BTL(,T,$,=$)P771BT0D0(M4)$0#0PP34Q`Y5"0<#X>-_?__<@HY1"08
-M#X>!_?__BW0D),=$)`1@`@``BP:)!"3H_/___XD$).C\____B<$QP,8$"`"#
-MP`&#^!AU](MT)#R+1"08BU0D'`-&!!-6"(E#!(M##(E3"(M3$`-&#!-6$"M$
-M)!@;5"0<B7D$B4,,BT0D&(E3$(M4)!R):0B)00R+!HE1$(D!B0Z)SND`_?__
-MBU0D'(M$)!@S5"0T,T0D,`G"#X0A_O__BTPD),=$)`1@`@``BP&)!"3H_/__
-M_XD$).C\____A<")P0^$P/S__S'`Q@0(`(/``8/X&'7TBUPD/(M##(G>*T0D
-M&(M3$!M4)!R)00R+1"0HB5$0BU0D+(E!!(L#B5$(BU0D&(D!B0N+3"0<B5,,
-MB4L0Z7'\__]R"CE$)!@/@Y[]__^+5"0DQT0D!&`"``"+`HD$).C\____B00D
-MZ/S___^)P3'`A<ET4\8$"`"#P`&#^!AU](M<)#R+1"08BU0D'`-#!(G>$U,(
-MB4$$BT,,*T0D&(E1"(M3$!M4)!R)00R+`XE1$(M4)!R)`8M$)!B)"XE3$(E#
-M#.GL^___BTPD/(L9BT,$BU,(B4$$BP.)40B+5"0DB0''1"0$8`(``(L"B00D
-MZ/S___^)7"0$B00DZ/S____IK_O__XGVC;PG`````%=64X/L$(M\)"#'1"0$
-M8`(``(L'B00DZ/S____V1TP(B<9U((M')(7`=!F0C70F`(L8B40D!(DT).C\
-M____A=N)V'7LBU=0BT=<B00D_U)`BT=<B40D!(M'6(/`$(D$).C\____@\00
-M6UY?PXUT)@!64X/L%(M<)""+4R2`HQP"``#^A=)T%(M"%(7`=`>`H!P"``#^
-MBQ*%TG7LB5PD!,<$)`$```#H_/___XL#QX.D`````0````6P````B00DZ/S_
-M__^%P(G&=%S'``$```#'0`0P"00`B48(QT`,`````(E8$(M;)(7;=#"0C70F
-M`(M3%(72=0OK'(VT)@````")PHM"#(7`=?>)="0$B10DZ/S___^+&X7;==6+
-M!H/H`87`B09T!H/$%%M>PXET)""#Q!1;7NEF^?__C;8`````4X/L&(M$)""+
-M7"0HQT0D!&`"``")!"3H_/___XM4)"2-'-N)7"0,QT0D"!@```")5"0$B00D
-MZ/S___^#Q!A;PX/L/(E\)#2+?"1`B70D,(MT)$2);"0XBVPD2(E<)"R#_P=W
-M3/\DO0P8``"+LY0```"%]G4[BT,$QX.4`````0```(M`.(F;C````,>#D```
-M``````")@X@```"-@X@```")1"0$C4$LB00DZ/S___^+7"0LBW0D,(M\)#2+
-M;"0X@\0\PXM>$,=&$`````")="0$QP0D`P```.C\____B5X0Z\V)-"3H_/__
-M_XM8"(G'A=MU".L,BQN%VW0&.7,(D'7TC4,LB00DZ/S___^%P'2?B5@,B6@0
-MQP#@$00`B4`$QT`(`````(E$)`2-1R2)!"3H_/___^EU____B30DZ/S___^)
-MP8M`#(U1##G0=0_I7/___XL`.=`/A%+___^-F-C]__^`>P@!=>HY:UQUY8/_
-M!P^'./____\DO2P8``"+0UB+4`2-1"0,B40D!(DL)/]2/`^V1"0:B$-*#[94
-M)!8/MD-.@^(!`=*#X/T)T(A#3NGZ_O__BT,0@*,<`@``[XM0((72#X7E_O__
-MQT`@`0```(/`%(E$)`2-02R)!"3H_/___^G'_O__@(L<`@``$.F[_O__BT,$
-MB1PD_U`DB?;IJ_[__XUT)@"-O"<`````@^P<BT0D((E<)!2)="08BU@,BW`0
-MB40D!(U#+(D$).C\____B5PD#(ET)`2)'"3'1"0(,"<$`.C\____BUPD%(MT
-M)!B#Q!S#D(VT)@````"!["P"``"`/0``````B9PD)`(``(N<)#`"``")M"0H
-M`@``=1R+G"0D`@``B[0D*`(``('$+`(``,.-M"8`````#[9#3(UT)"2#R`.#
-MX/N(0TS'1"04`0```(ET)!#'1"0,`0```,=$)`0)````QT0D"`````")'"3H
-M_/___X7`=4^!?"0D>6-G;'1E]D-,`9!TDHMS)(7V="7'1"0$8`(``(L#B00D
-MZ/S___^)="0$B00DZ/S____'0R0`````BT,XBU,\B4,4B5,8Z57___^0@*,<
-M`@``_HE<)`3'!"0!````Z/S___^`2TP!Z33____'1"0$``(``(DT).C\____
-MA,!UAP^V3"0H#[:#'`(``(G*P.H$@^#]@^(""="(@QP"``#V1"0H$'0,@$M,
-M@`^V1"0IB$-+]D0D*P%T%P^V4TV)R,#H`H/@`H/*`8/B_0G"B%--]D0D*P)T
-M%0^V4TV-!`F#X`B#R@2#XO<)PHA33?9$)"L(=!4/MD--P>$$@^$@@\@0@^#?
-M"<B(0TWV1"0K!`^$]/[__P^V4TT/MD0D*(/*0(/@`8/B?\'@!PG"B%--Z=7^
-M__^-=@"-O"<`````55=64X'L'`(``(N,)#`"``"#P20/MD$H@^`#+`$/A+\"
-M``"+E"0P`@``#[9"3(/@[XG&B$),C40D'(VV`````,8``(V<)!P"``"#P`$Y
-MV'7O]D$H`@^%AP(``(N\)#`"``")\X/C]XA?3(N\)#`"``#'1"0<7W=A4HM'
-M%(M7&(E$)"")5"0D@'DH`'D-@$PD*!`/MD=+B$0D*?9!*0%T)(N$)#`"``"`
-M3"0K`0^V4$T/MD0D*,'B`H/B"(/@]PG0B$0D*/9!*01T(XN\)#`"``"`3"0K
-M`@^V1"0H#[9738/@^]#J@^($"="(1"0H]D$I$'0DBX0D,`(``(!,)"L(#[90
-M30^V1"0HP.H$@^("@^#]"="(1"0H]D$I0'0AB[PD,`(``(!,)"L$#[9$)"@/
-MME=-@^#^P.H'"="(1"0HBX0D,`(``(-X+``/AIX!``#V02@@#X2S`0``BY0D
-M,`(``(MR)(7V=$`Q_XMN%(7M=#&+1@2-#'^#QP&+5@B-3,P<B4$0B5$4BT8,
-MBU80B4$8BT84B5$<BU`LBT`HB5$DB4$@BS:%]G7"BXPD,`(``(U<)!R-?"0<
-M#[9!3HD<),:$)!L"```!QT0D!``"``"#X`&(A"0:`@``Z/S___^+C"0P`@``
-MB7PD$,=$)!0`````QT0D#`$```#WV(B$)!P!``"+03B+43R)#"0%``#^_X/2
-M_R4``/[_B40D!(E4)`CH_/___XN<)#`"``"+>R2%_W1/,>V+3Q2%R71`BYPD
-M,`(``(UT;0"+0SB+4SR+62R+22@!P1'3@<$`^/__@]/_!0``_O^#TO\E``#^
-M_RG!&=.#Q0&)3/0\B5ST0(L_A?]ULXU\)!S&A"0<`0```,=$)`0``@``B3PD
-MZ/S___^+C"0P`@``QT0D%`````#'1"0,`0```/?8B(0D'`$``(U$)!R)1"00
-MBT$XBU$\B0PD!0#X__^#TO^)1"0$B50D".C\____@<0<`@``6UY?7<.!>"C_
-M_Q\`#X=5_O__B?.#X_.(6$SV02@@#X5-_O__P.L"@^,!B%PD*ND^_O__D(UT
-M)@!3B<.#[`C'1"0$8`(``(L`B00DZ/S___^)!"3H_/___XG!,<"%R70RQ@0(
-M`(/``8/X&'7TBT,4BU,8B4$,B5$0BT,4BU,8B4LDB4,PB5,TB4,HB5,L@\0(
-M6\.)'"3H_/___^OQC;8`````C;\`````55=64X'L/`,``(N\)%`#``"`/0``
-M```"C7<D#X0O`0``C40D2,=$)!0!````B40D$,=$)`P!````BT<XBU<\B3PD
-M!0#X__^#TO^)1"0$B50D".C\____A<")1"0L#X3O`P``C6PD2,=$)!0!````
-MB6PD$,=$)`P!````BT<XBU<\B3PD!0``_O^#TO\E``#^_XE$)`2)5"0(Z/S_
-M__^%P(E$)"@/A$8#``"#?"0L_P^4P(-\)"C_#X34!@``BT0D*(7`#Y5$)"</
-MA#("``"+1"0LA<`/A28"``"-3"1(QT0D%`$```")3"00QT0D#`$```"+1SB+
-M5SR)/"0%`/C__X/2_XE$)`2)5"0(Z/S___^%P(E$)"P/A.0!``"`IQP"``#^
-MB7PD!,<$)`$```#H_/___X!/3`&!Q#P#``!;7E]=PX`]```````/A0`"``"0
-M@$],`O9'3`)T#0^V1TR#R`&#X/N(1TSV1B@!=#B+7R2%VW0EQT0D!&`"``"+
-M!XD$).C\____B5PD!(D$).C\____QT<D`````(M'.(M7/(E'%(E7&(!^*``/
-MB/$```#V1BD!#X6U````]D8I!'5\]D8I$'4^]D8I0`^$:/___\9$)$@%#[9'
-M38UL)$C&1"1-`,#H!XA$)$R+5U");"0$BT=<B00D_U)@@<0\`P``6UY?7</&
-M1"1(!`^V1TV-3"1(QD0D30#`Z`6#X`&(1"1,BU=0B4PD!(M'7(D$)/]28/9&
-M*4`/A/[^___KE,9$)$@##[9'3<#H`X/@`8A$)$R-1"1(BU=0B40D!(M'7(D$
-M)/]28/9&*1`/A%G____KE<9$)$@"#[9'38UL)$C0Z(/@`8A$)$R+5U");"0$
-MBT=<B00D_U)@]D8I!`^$(?___^N;QD0D2``/MD=+C4PD2(A$)$R+5U")3"0$
-MBT=<B00D_U)@]D8I`0^$[O[__^NAC50D2,=$)`0``@``B10DZ/S___^$P`^%
-M4`$``("\)$<"````=0C'1"0L_O___\9$)"<`@7PD2%]W85(/A`L"``"+3SB+
-M7SR!P0``_O^#T_^)R(G:)0``_O^)T#'2B=4)Q0^%=`$``(!/3`$/M@4`````
-M/`(/A`G^__\L`0^$\_W___:''`(```$/A/C]__^`IQP"``#[C40D2(V4)$@"
-M``")]L8``(/``3G0=?:-;"1(QT0D%`$```");"00QT0D#`$```#'1"0$````
-M`,=$)`@`````B3PDZ/S___^`?"1(10^$\`,``("\)$8"``!5#X61_?__@+PD
-M1P(``*H/A8/]__\QP(N4!!("``"%T@^%;OW__X/`$(/X0'7IZ67]__^0C40D
-M2`^VG"1'`@``QT0D!``"``")!"3H_/___XE<)`S'!"0D"P``#[;`B40D"(M$
-M)$B)1"0$Z/S___^!?"1(7W=A4@^$E/[__XM$)"R%P`^%>/S__\=$)"S_____
-MZ6O\__^-5"1(#[:<)$<"``")%"3'1"0$``(``.C\____B5PD#,<$)``+```/
-MML")1"0(BT0D2(E$)`3H_/___X%\)$A?=V%2#X1J`P``QT0D+/[____IN_O_
-M_XU$)$@QTHE$)!")R"4``/[_QT0D%`$```#'1"0,`0```(E$)`2)5"0(B3PD
-MZ/S___^%P`^%._S__X%\)$A?=V%2#X5%_O__C50D2,=$)`0``@``B10DZ/S_
-M__^$P`^$[@8``(%\)$A?=V%2#X4;_O__C50D2,=$)`0``@``B10DZ/S___^$
-MP`^%__W__X!\)%8`#[9'3`^5PL'B`H/@^PG0B$=,#[9'3H"\)$8"````#Y7"
-M@^#^"=`/MM*(1TZ)5"0(B70D!,<$)&`#``#H_/___XM'.(M7/`4``/[_B<&#
-MTO^!X0``_O^)^(E/%(E7&.CS^?__]D0D5!!T#(!/3(`/MD0D58A'2_9$)%<!
-M=!H/ME=-#[9$)%2#R@'`Z`*#XOV#X`()PHA73?9$)%<"=!D/ME=-#[9$)%2#
-MR@0!P(/B]X/@"`G"B%=-]D0D5PAT&@^V5TT/MD0D5(/*$,'@!(/BWX/@(`G"
-MB%=-]D0D5P1T&@^V5TT/MD0D5(/*0(/@`8/B?\'@!PG"B%=-QT0D-``````Q
-M[8M$+&`+1"QD#X7;`0``@\48@_U@=>J`?"0G``^$0P,``&8Q[8M$+&`+1"QD
-M=#2+3"QHBT<XBUPL;(M7/('!``@``(/3`"G!&=,%``#^_X/2_R4``/[_`<$1
-MTXE,+&B)7"QL@\48@_U@=;J-5"1(B10DQH0D2`$```#'1"0$``(``.C\____
-MC4PD2,=$)!0`````B4PD$,=$)`P!````]]B(A"1(`0``BT<XBU<\B3PD!0``
-M_O^#TO\E``#^_XE$)`2)5"0(Z/S____'1"0X`````,=$)#P`````C6PD2,=$
-M)!0!````B6PD$,=$)`P!````BT<XBU<\B3PD!0'X__^#TO\#1"0X$U0D/(E$
-M)`2)5"0(Z/S___^%P`^$70$``(-$)#@!BT0D.(-4)#P`@_`$"T0D/'6CBTPD
-M-(7)#X34`P``@$],0(D\).C\____Z13Z__^$P`^$)/G__XVT)@````#I=_G_
-M_X!\)$E2C;8`````#X7_^___C40D2,=$)!0!````B40D$,=$)`P!````QT0D
-M!`$```#'1"0(`````(D\).C\____@'PD2%`/A<3[__^`?"1)30^%N?O__XUT
-M)@#I2_G__XU,)$C'1"0$``(``(D,).C\____A,`/A$+X___I=?S__\=$)`0$
-M````BP>)!"3H_/___X7`B40D-`^$\_C__XM$+&"+5"QDB00DB?B)5"0$BU0L
-M6(M,+%SH#NK__X7`B40D,`^$X@0``(M,)#2)>22+1"0HA<`/A=D```"+1"QH
-MBU0L;(E!*(E1+(M,)#"+5"0TB4HPBTPD,(M!#(M1$(M,)#2)012+1"0PB5$8
-MB4@4Z9']__^-1"1(QT0D%`````")1"00QT0D#`$```"+1SB+5SR)/"0%``#^
-M_X/2_R4``/[_@\`!@](``T0D.!-4)#R)1"0$B50D".C\____BT\XBU\\QP0D
-M2`L``(G(!0``_O^)VH/2_R4``/[_@\`!@](``T0D.!-4)#R!P0'X__^#T_\#
-M3"0X$UPD/(E$)`R)5"00B4PD!(E<)`CH_/___^D#_O__BT0D+(7`#X4I____
-MBTPL:(M'.(M<+&R+5SR!P0`(``"#TP`IP1G3!0``_O^#TO\E``#^_P'!BT0D
-M-!'3B4@HB5@LZ>[^__^+7"0LA=L/A,?]__^`O"1'`@````^$(`$``#'MBT0L
-M8`M$+&1T-(M'.(M7/(G!`TPL:(G3$UPL;('!`/C__X/3_P4``/[_@]+_)0``
-M_O\IP1G3B4PL:(E<+&R#Q1B#_6!UNHUL)$C&A"1(`0```,=$)`0``@``B2PD
-MZ/S____'1"04`````,=$)`P!````]]B(A"1(`0``C40D2(E$)!"+1SB+5SR)
-M/"0%`/C__X/2_XE$)`2)5"0(Z/S____'1"1``````,=$)$0`````C50D2,=$
-M)!0!````B50D$,=$)`P!````BT<XBU<\B3PD!0``_O^#TO\E``#^_X/``8/2
-M``-$)$`35"1$B40D!(E4)`CH_/___X7`#X2F````@T0D0`&+1"1`@U0D1`"#
-M\`0+1"1$=9CIF?S__\<$)'4#``#H_/___XU4)$B)%"3&A"1'`@```<:$)$@!
-M````QT0D!``"``#H_/___XU,)$C'1"04`````(E,)!#'1"0,`0```/?8B(0D
-M2`$``(M'.(M7/(D\)`4``/[_@]+_)0``_O^)1"0$B50D".C\____Z6?^___V
-M1B@$#X3:]___B?;I&_S__XU,)$B)3"00QT0D%`````#'1"0,`0```(M'.(M7
-M/(D\)`4!^/__@]+_`T0D0!-4)$2)1"0$B50D".C\____BT<XBU<\BTPD0(M<
-M)$0%`?C__X/2_P'!$=,%_P?^_X/2_R4``/[_@\`!@](``T0D0!-4)$2)3"0,
-MB5PD$(E$)`2)5"0(QP0D>`L``.C\____Z<;^__^-E"1(`@``C40D6,=$)`CP
-M````C9PD4`(``(E$)`2-K"1``P``B10DZ/S____K"X/#&#GK#X21````BP,+
-M0P1T[HU,)$@QTL=$)!0!````B4PD$,=$)`P!````BT,(B50D"(D\)(E$)`3H
-M_/___X7`#X6M]/__C40D2(D$).C\____@7PD2/06>%H/A-@```"-3"1(QT0D
-M%`````")3"00QT0D#`$```"+0PB+4PR)/"2)1"0$B50D".C\____A<`/A&G_
-M___I6/3__XUL)$C'1"04`0```(EL)!#'1"0,`0```(M'.(D\)`4``/[_,=(E
-M``#^_XE$)`2)5"0(Z/S___^%P`^%&?3__XU$)$C'1"04`````(E$)!#'1"0,
-M`0```(M'.(M7/(D\)`4``/[_@]+_)0``_O^)1"0$B50D".C\____A<`/A=;S
-M___IP/?__Y"-="8`BU0D-(D4).C\____Z=;S__^-5"1(QT0D!``"``")%"3H
-M_/___^D/____C;8`````55=64X/L3(ML)&#'1"0$`0```(M%#(D$).C\____
-MC50D+(G'BT4$B50D!(M4)&2)%"3_4#R+ARP"``"+ER@"``")0@2)$(L'BU@,
-M@\`,.<-U#>M_BP>+&X/`##G8='2-L]C]__^`?@@!=>F+1EB+500[4`0/A"8!
-M``")1"0$B2PDZ/S___^#^`!\2'7'C40D#(M5!(E$)`2+1ER)!"3_4CP/ME0D
-M-@^V1"06T.K0Z(/B`8/@`3G"?YM\&`^V1"08.$0D.'>.<@L/MD0D.3I$)!EW
-M@8M3!(V'*`(``(E#!(F?*`(``,='(`$```")`H"/'`(```&+102)ERP"``")
-M1U"+5"1DB6]8B5=<BT0D:(E'5(M$)"R+5"0PB4<XB5<\B4<4B5<8#[9$)#J(
-M1TH/MT0D0&:)1T@/ME0D-@^V1TZ#X@$!TH/@_0G0B$=.C4=@B00DQT0D!"@`
-M``#H_/___XU$)"R+5U")1"0$BT=<B00D_U(\BT0D1/9$)#8!=0GV@``!```$
-M=0B)/"3H_/___X/$3(GX6UY?7<.-M@````"+DH````"%T@^$S/[__XM`"(E$
-M)`2+10B)!"3_TNG$_O__C;0F`````(V\)P````!3@^P(BUPD$(!["`%T"KC_
-M____@\0(6\.`/0`````"=.V+0SB+4SP%``#^_XG!@]+_@>$``/[_B=B)2Q2)
-M4QCH_.___X!C3/3'0QS_____B1PDZ/S___\QP.NXD(UT)@"#[!R+1"0HB70D
-M%(MT)"")?"08BWPD)(E<)!"%P'AQB40D"(E\)`2)-"3H_/___X7`B<-T3`^V
-M0$R+=@RH`G5P@#T``````'08J`%U;?9#3$1U!(!+3"2+AB0!``"%P'1CB5PD
-M)(MT)!3'1"0@`@```(M<)!"+?"08@\0<Z?S___^+1@2)/"3_4$"-M@````"-
-M1A"+7"00B7PD)(MT)!2)1"0@BWPD&(/$'.G\____D(D<).C\____ZZ>)'"3H
-M_/___^N)C888`0``QX8D`0```0```,>&&`$```````")MAP!``#'AB`!````
-M````B40D!(U&)(D$).C\____Z5____^-M"8`````C;PG`````%575E.#[#R+
-M1"10B40D&(MH)(MX,(MU)(7V#X0"`@``B?/'1"0<`````.L*C70F`(L;A=MT
-M(#G[=/:+4PB+3PB+0P0S1P0QT0G!=>2)7"0<BQN%VW7@BT0D'(7`#X3Y````
-MBTPD'(M'#(M1#(M)$(E$)"")5"00BU<0B4PD%#G1B50D)'):=P8Y1"00<E*)
-M?"0$B2PDZ/S___^`34P0BT0D&(D$).C\____B6PD4(/$/%M>7UWI_/___XVV
-M`````(M$)""+5"0DBTX(`T<$$U<(,T8$,=$)P71`BS:%]G0-BUX4A=MTV8LV
-MA?9U\XM,)!S'1Q0`````BT$$`T$,BU$($U$0B4<$BT0D$"E'#(E7"(M4)!09
-M5Q#K@(M,)!R+400!5"00BTD($4PD%(M$)!"+5"04BTPD'(E&!(M&#(E6"(M6
-M$`-'#!-7$"M!#!M1$(E&#(E6$.DS____,=OK!Y"+-H7V=%F+3A2%R77SBU8$
-MBTX(BT<$B50D,(M7"(E,)#2+3"0TB40D*`-'#(E4)"P35Q`S1"0P,=$)P71^
-MBT0D,(M4)#2+3"0L`T8,$U80,T0D*#'1"<%UIXET)!SKH8M4)!S'1Q0`````
-MA=)T*(M,)!R+002+40B)1P2+00R)5PB+41`!1PP15Q")3"0$B2PDZ/S___^%
-MVP^$G/[__XM##(M3$`%'#!%7$(E<)`2)+"3H_/___^E__O__B?/I/O___\='
-M%`````"-M"8`````Z67^__^-="8`C;PG`````%4Q[5=64X/L+(M\)$R+1"1$
-MBU0D2(7_B40D$(E4)!0/A``!``"+5"1,BVHPA>T/A/$```"+1"1`BU@DA=L/
-MA)$```#'1"08`````,=$)!P`````ZPPY1"1,=`V+&X7;=$F+0Q2%P'7MBTL0
-M.4PD%(M3#'<,<FHY5"00=F2-="8`A<!UUX7M=-.+102+50B+2P@#10P351`S
-M0P0QT0G!=;N)7"0<BQN%VW6WBT0D'(7`=!:+3"0<BT$,BU$0`T4,$U40.50D
-M%'8QBT0D&(7`#X5^````,>V#Q"R)Z%M>7UW#BW0D&(7V=`N+="08.TX0=X]S
-M'XE<)!CKAXVT)@````!S1(EL)!B+1"08A<!TQHGVZT`[5@P/@V7___^)7"08
-MD.E;____BTPD0(M<)!0Y62QRH@^'_/[__XMT)!`Y<2ARD^GN_O__.40D$`^'
-M>/___^NPBUPD0,=$)`0$````BP.)!"3H_/___X7`B<4/A&3___^)6"2+="1`
-MBTXXBUX\@<$``/[_B<B#T_\E``#^_XE$)""#1"0@`8E<)"2#5"0D`#';BU8D
-MA=)T(XVV`````(M"%(7`=!"+2"BX`0```"M,)"#3X`G#BQ*%TG7C,<FX`0``
-M`-/@A<-T*H/!`8/Y!'7MQT4H`````,=%+`````")+"0Q[>C\____@\0LB>A;
-M7E]=PXG*B<C!^A\#1"0@$U0D)(E%*(G1"<&)52QTT8MT)!2+7"00BT0D0(EU
-M&(MT)!B)712+7"00BU8$BTX(BW0D%(D<)(ET)`3H(=W__X7`=)V):!2)13"+
-M="1`@$Y,$(DT).C\____Z6C^__^)]E93@^P$BW0D$(M&)(7`=0CK3XL`A<!T
-M28M0%(72C78`=/"+6@R%VW0N@'LP`'0H,<GK"P^V0S"#P0$YR'X9.52+2'7O
-M#[9#,,=$BT@`````@\$!.<A_YXD4).C\____ZZB)-"3H_/___XM64(M&7(D$
-M)/]29(ET)!"#Q`1;7NG\____C;8`````C;PG`````%93@^P$BW0D$(M>)(!F
-M3+^%VW0PBT,4A<!T"(D$).C\____BQN%VW7KBU8DA=)T%(M"%(7`=`>+2`R%
-MR704BQ*%TG7LB70D$(/$!%M>Z?S___^)!"3H_/___XM6).O-D%575E.#[`R+
-M1"0@BV@0B40D!(V%L````(D$)(U]#.C\____BUT,QX4D`0```````#G[=0CK
-M+XL;.?MT*8V#V/W__X!X"`%U[O9`3$!TZ/:`'`(```%TWXD$).C\____BQLY
-M^W77BUT4C744.?-T$I"-0_2)!"3H_/___XL;.?-U[XMU##G^#X2N````C70F
-M`(V&V/W__X!X"`1V"XM8#(7;#X1!`0``BS8Y_G7CBUT,.?L/A((```#&1"0+
-M`.L'D(L;.?-T/HV3V/W__X!Z"`%U[O9"3"!TZ(M")(!B3-N%P'4/Z<@```"+
-M`(7`#X2^````BT@4A<ET[XL;QD0D"P$Y\W7"BUT,.=]U"^LMC78`BQLY^W0D
-MC8/8_?__BV@<A>UX'_:`'`(```%UY(D$).C\____BQLY^W7<@\0,6UY?7</V
-M@!P"```!=,4/ME`(@/H$=G:+<`R%]G6U]H!(`0``0'6LBY!D`0``A=)T!3E"
-M!'6=#[9P,(7V?B0QR8M4B$B%TG03@'H(!'8-]H)(`0``0`^%>/___X/!`3GQ
-M==Z)!"3H_/___^ED____C70F`(!\)`L`#X4%____B10DB?;H_/___^GV_O__
-M@.H!C78`#X4Z____]D!,`HVV``````^$*O___^NWB00DD(UT)@#H_/___^FM
-M_O__C;8`````5U93@^P0BWPD((V'L````(D$).C\____A<")QG15BU\,B7@0
-M@\<,QP`!````QT`$X"T$`#G[B48(QT`,`````'4(ZR2+&SG[=!Z-@]C]__^`
-M>`@!=>Z)="0$B00DZ/S___^+&SG[=>*+!H/H`87`B09T!X/$$%M>7\.)="0@
-M@\006UY?Z7?]__^-M"8`````@^P<B70D%(MT)"")7"00B7PD&(M>$,=#(```
-M``#VAAP"```8=7R+AI0```"%P'5R#[9#**@!=6JH`HU["'06.7L(=00Y&W04
-MB?#H`=;___9#*`%U38M+"#GY=58/MD9*.4,0<A+K.XGPZ"+2__\/MD9*.4,0
-M<RN)\.CRT?__A<")PG0>#[=`9&8E_S!F/00@==4Y&W5+]D9.`G3+@$LH`NO%
-MBUPD$(MT)!2+?"08@\0<PXM[$(7_=>F+$8M!!(E"!(D0BU$,B?")"8E)!(M<
-M)!"+="04BWPD&(/$'.FOT?__QD)F`8D4).C\____B?#H?-'__XG"Z6S___^0
-MC70F`(/L'(E<)!"+7"0@B70D%(E\)!B)V(M[*.A#T?__@'MD!(MW$(G"='B+
-M0W#'1B0`````B3+'0A``````B4((BT8$B5H,B58$QT-P0#($`(E"!(D0#[9'
-M2CE&$','BT8@A<!T$(M<)!"+="04BWPD&(/$',.-1A3'1B`!````B40D!(L'
-M@\`LB00DZ/S___^+7"00BW0D%(M\)!B#Q!S#B?;V0V4P=`KV1B@"#X1X____
-MQD-F`8MT)!2)7"0@BWPD&(M<)!"#Q!SI_/___XUT)@"#[!R)="00BW0D((E<
-M)`R)?"04B6PD&(GPZ'+0__^+7BB+>Q")Q8-O$`$/MD9F/`UT7CP1#X1]````
-M/`MT8CP0#X20````BT4(B49PB30DZ/S___^+1R"%P'4;C4<4QT<@`0```(E$
-M)`2+`X/`+(D$).C\____BUPD#(MT)!"+?"04BVPD&(/$',.-M@````"`?F0`
-M=;"`?F<`=6K&1F<!QD9F`(M7#(U'"(EO#(E%`(E5!(DJZYV)V.C"T___A<!U
-M"`^V1F<\`79"#[9&9CP0#X5P____@'YD`P^$9O___XM#$(ES$(E<)`3'!"0#
-M````B40D".C\____BT0D"(E#$.E`____QD9F$.O*@\`!B$9GZXR0D)"0D)"0
-MD)"0D)!64XL=`````(MT)`R%VW0MBU,,C4L,.<IU#.L;C70F`(L2.<IT$8V"
-MV/W__SFP6`(``'7L6U[#BQN%VW73,<"0Z_*-M"8`````C;PG`````(!X!`!U
-M#8$X>P$```^7P`^VP,.!.'L!```/E\`/ML##4XG!#[8:#[8`.-AT%>LID`^V
-M60$/MD(!.,-U$(/!`8/"`83`=>HQTEN)T,,/OM,/OL!;*<*)T,,/OM`/OL,I
-MPNOFC;0F`````(V\)P````!55U93@>R<````BRT`````B40D&(E4)!2%[71!
-M,?:-?"0DBUT(A=MT+8E\)!"-=@"+4P2)?"0$BT,(B00D_U(<@'PD-P!T"3MT
-M)!AT'X/&`8L;A=MUVHMM`(7M=<4QVX'$G````(G86UY?7<.+1"04A<!TZXM4
-M)!2+`@^V5"0[.=!\W(L;A=MTUBG0BU0D%(D"BT0D$(M3!(E$)`2+0PB)!"3_
-M4AR`?"0W`'3(ZZ^)]E575HG.4X'LG````(E$)`RA`````(N\)+````#'`0``
-M``")5"0(A<#'!P````")1"00#X21````O?_____'1"04`````(M4)!"+6@B%
-MVP^$@````(7_#Y5$)!OK%HUV`(L;#[9$)#L!!HM4)!0!%X7;=&&-5"0DBT,$
-MB50D!(M3"(D4)/]0'(M#!(N0A````(72=!.`?"0;`'0,BT,(B00D_]*)1"04
-M@'PD-P!T#\<&`````(/%`<<'`````#M<)`QUG8M$)`B)*('$G````%M>7UW#
-MBT0D$(L`A<")1"00#X5?____Z^&0C;0F`````%575C'V4X'LC````(L]````
-M`(7_="^-;"04BU\(A=MT'HM3!(EL)`2+0PB)!"3_4AR+&X!\)"<!@][_A=MU
-MXHL_A?]UU8'$C````(GP6UY?7<.-M"8`````C;PG`````%57B<]64X'LO```
-M`(E4)!B-5"08Z.?]__^)1"00BU0D$+C_____A=(/A/D```"+1"00BW`,,<#&
-M!#@`@\`!@_A$=?2+5"00BTPD$(M"!(U4)!R)5"0$BU$(B10D_U`<@'PD+@]V
-M!<9$)"X/BT0D$(M,)!"+4`2-A"2T````B40D"(M$)!B)1"0$BT$(B00D_U)<
-MA<`/A)@```"+7@R-;@PYZP^$?0```,9$)!<`ZP>0BQLYZW1OC;/8_?__@'X(
-M`77NBT0D$#M&6'7EC8PDE````(M64(E,)`2+1ER)!"3_4CSVA"2>`````G7$
-M#[:$)*`````[1"08=;8/MH0DH0```#I$)"YSJ`^VT(N&6`(``(!$)!<!B427
-M"`^V1"07.$0D+G6+,<"!Q+P```!;7E]=PXN$)+@```")1P2+A"2T````B0?I
-M4/___XVV`````(/H!3'2@_@'=PS_)(5,&```N@$```")T,.Z"````(G0P[H"
-M````B=##N@<```")T,.Z`P```(G0P[H$````B=##N@4```")T,.Z!@```(G0
-MP^L-D)"0D)"0D)"0D)"0D%:)UE,/MH@<`@``B<,/ME((B<B#\`&#X`'VPB!T
-M`X/((/;!!'0#@\@"@^$"=`.#R`2#XA!T`X/($`^V5@KVP@%T`X/(0(/B`G0"
-M#(`/ME-,]L($=`4-````@/;"`G0%#0```@"#X@%T!0T```$`]D-.`70%#0``
-M!`!;7L.-="8`55>_Z`,``%93@^PLBT0D0(N84`$``(N(3`$```^V:#`/K-D+
-MB<C!ZPOWYVGSZ`,``(G!C1P6BW0D0(M6&(M&%(D,)(E<)`2)ZP^LT`O!Z@N)
-M1"0(B50D#.C\____BTX$#[9)!BG+N0H```#WX_?AA>V)1"0D#XZ2````,?:-
-M=@"+1"1`BURP2(7;=';V@QP"```!=&V`>P@$=F?V@T@!``!P=%Z+4P0/MD,P
-M#[92!BG0BY-0`0``C02`C3P`BX-,`0``#ZS0"VG(Z`,``(M#%,'J"XM3&`^L
-MT`O!Z@N)1"08B<B+3"0DB50D'#'2]W0D&`^O^(7)=`8Y?"0D=@2)?"0D@\8!
-M.?4/A7/___^+1"0D/1`G``!V!;@0)P``@\0L6UY?7<.-="8`C;PG`````(/L
-M+(M$)#")7"0<B70D((E\)"2);"0HBZAD`0``#[9%9CP"#X6J````BT4(BU`4
-MBT@8BT4$B50D$(MT)!")3"04BWPD%(M(%(M8&+@0)P``*<X9WP^L_@O![PN)
-M^@GR=$Z`?10`=5R+15R+56`IR!G:#ZS0"[GH`P``P>H+:=KH`P``]^&)="0(
-MB7PD#(T4$XD$)(E4)`3H_/___[D*````]^$]$"<``'8%N!`G``"+7"0<BW0D
-M((M\)"2+;"0H@\0LPXM$)!"+5"04*T5<&U5@ZYX\`P^$E0```(!]%`!T/HM%
-M"(M8&+[H`P``BT@4B=J)R"M%7!M58`^LV0O!ZPL/K-`+P>H+:?KH`P``]^:)
-M3"0(B5PD#(T4%^EQ____BUU@O^@#``"+35P/K-D+B<CWY\'K"VGSZ`,``(G!
-MBT4(C1P6BU`8BT`4B0PDB5PD!`^LT`O!Z@N)1"0(B50D#.C\____N0H```#W
-MX>DS____@'T4`'0(BT4$Z6;___^+76"_Z`,``(M-7`^LV0N)R/?GP>L+:?/H
-M`P``B<&+102-'!;KGXVV`````(V_`````%93BT@,B<.%R70S#[9!,(3`#[;P
-M=!@QTCE92'06,=+K!CE<D4AT#(/"`3GR=?-;,<!>PXM!)%M>@\`!`=##BT`D
-M6U[#C;8`````C;\`````55>)UU93@^P$B00D#[9H,(7M?E,Q]HL$)(M4L$B%
-MTG0_]H(<`@```70V@'H(!'9!#[9:,(7;?B@QR8VV`````(M$BDB%P'0.]H`<
-M`@```70%.7@D=!.#P0$YV77CC78`@\8!.>YUKS'`@\0$6UY?7<,Y>B1UZHG0
-MZ^^-M@````!55U93@^Q`B40D&(M<)!B(5"07#[9$)%@/ME0D7(E,)!"%VXA$
-M)`^(5"0.#X1/`0``BTPD&(!Y"`</E,"`?"07!P^4PH3`#X48`0``A-(/A2P!
-M``"+3"00A<D/A"<#``#'1"0<_____S'_,>W'1"0@_____\=$)#@`````C70F
-M`(M4)#B+3"14BP21B00DZ/S___^%P(G##X2W````BU0D&(L`.P(/A:D```"`
-M>P@!#X6?````BT0D&(G:Z,#^___'1"0L`````(7`B<9T!XM(,(E,)"R+6R2%
-MVP^$%0$``(G8,=(QR8-X%`!T!H/"`8/1`(L`A<!U[H/Y`'<)@_H##X;O````
-MQT0D)`````#'1"0H`````,=$)!P`````QT0D(``````#?"0DBU0D$!-L)"B#
-M1"0X`3E4)#@/A3____\/MDPD#X/A#X!\)!<'#X;'`0``,?\Q[8/$0(GXB>I;
-M7E]=PXM,)!@/MD$P/`$/A.#^__^$TG0(A,`/A?L!``"+7"00A=L/A/L!```Q
-MVS'_,>W'1"0<_____\=$)"#_____ZSF`>`@!=:J+4"R+0"B)T0G!=)X!QQ'5
-M.50D('(0=P8Y1"0<=@B)1"0<B50D((/#`3M<)!`/A&3___^+5"14BP2:B00D
-MZ/S___^%P'6TZ5____^%]L=$)"0`````QT0D*`````!T#HM&%(M6&(E$)"2)
-M5"0HA=L/A)8```#'1"0P`````.LDC;0F`````(M#%#G&=!"+5"0LA=)T'H7`
-M#X2A````BQN%VW0VA?:0==Z+5"0LBT,4A=)UXH7`=>:+4Q`[5"0HBT,,<MIW
-M!CM$)"1VTHL;B40D)(E4)"B%VW7*BT0D+(7`="J+="0PA?9T(HM,)#"+00R+
-M41"+3"0L`T$,$U$0.50D*'<(<F(Y1"0D<ER+1"0H.40D(`^"8_[__W<.BU0D
-M)#E4)!P/AE/^__^+1"0DBU0D*(E$)!R)5"0@Z3[^__^+3"0LBT$$BU$(`T$,
-M$U$0BTL(,T,$,=$)P0^%6?___XE<)##I4/___XE$)"2)5"0HZYH/MD0D%_\D
-MA6P8``"#?"00`0^&(O[__X-\)!`"BWPD'(ML)"`/AA/^__\/ML&Z_____XG!
-MBT0D'-/BB=/1;"00(="+5"0@BTPD$,'['R':B=8/K_'WX8G'C2P6Z=W]__^+
-M5"00A=(/A?H````Q_S'MQT0D'/_____'1"0@_____^FA_?__@WPD$`,/AJG]
-M__\/ML&Z_____XG!BT0D'-/BBTPD$(G3P?L?(="+5"0@@^D"(=KKF8-\)!`"
-M#X9X_?__#[;!NO____^)P8M$)!S3XHM,)!")T\'['R'0BU0D((/I`2':Z67_
-M__^`?"0.`0^&,0$``(!\)`X"#X8,____#[9T)`XQTHM$)!#W]H72B<,/A2+]
-M__^#ZP$/CAG]__^#[@'W[HG&#[;!B<&+1"0<B=>Z_____]/BB=,AT(M4)"#!
-M^Q^)P0^OSXE$)`0AVHG3#Z_>B50D"/?F`=F)QXTL$>G7_/__BT%(,?:%P'4?
-MZ<7\__\Y="00#X;G_/__BU0D&(M$LDB%P`^$J_S__XM,)%2+6"2+!+&)!"3H
-M_/___SG#=!6+5"08@\8!#[9",#GP#X:N_/__Z[N+3"08#[9!,`^VT#E4)!")
-M5"0T#X)G_/__A,!T=HM!2#'VA<!U+.E5_/__D(M,)!B#Q@$/MD$P#[;0.?*)
-M5"0T=E&+3"08BT2Q2(7`#X0N_/__BU0D5(M8)(L$LHD$).C\____.<-TQ.D3
-M_/__#[;!NO____^)P8M$)!S3XHM,)!")T\'['R'0BU0D("':Z0/^__^+3"08
-M#[;`BW2!1(MY%(MI&(M&)(M8)(7;=0CK+XL;A=MT*8M#%(7`D'7RBTXPBT$$
-MBU$(`T$,$U$0BTL(,T,$,=$)P777`WL,$VL0BU0D-#E4)!`/AI?[__^+3"14
-MC1R1ZSJ-M@````"+3"08BP`[`0^%=OO__X!Z"`$/A6S[__\#>BB+1"00$VHL
-M@\,$@T0D-`$Y1"0T#X14^___BP.)!"3H_/___X7`B<)UO.D[^___C;0F````
-M`//#C;0F`````(V\)P````!6BS5$`@``4XM,)`R-5@&)T,'X'\'H'(T<`H/C
-M#RG#N/____\['4`"``!T;8L!:]8LB8)@`@``BT$$B8)D`@``BT$(B8)H`@``
-MBT$,B8)L`@``BT$0B8)P`@``BT$4B8)T`@``BT$8B8)X`@``BT$<B8)\`@``
-MBT$@B8*``@``BT$DB8*$`@``BT$HB1U$`@``B8*(`@``,<!;7L.-="8`@^P\
-MBU0D0(E<)#2+3"1(B70D.(M<)$P/MW0D4`^V0@@\`70R/`1T2(U4)!2#?"1$
-M`1G`@\`9B$0D$(U$)`AFB7((B00DZ/S___^+7"0TBW0D.(/$/,.+@E@"``"-
-M5"04B4PD%(E<)!B)1"0,Z[Z)]HM",(M2)`-(!(N26`(``!-8"(E,)!2)5"0,
-MC50D%(E<)!CKF(VV`````(V_`````%93@^PDQD0D'`:+6`B%VW0BC70D'(M#
-M"(E$)""+0P2)="0$QP0D`````/]08(L;A=MUXH/$)%M>PXVT)@````!55U93
-M@^P$BU0D&(ML)!R+0B@/MUI0BXAD`0``B=^+,,'G"8!Y%`!T"O9"900/A8H`
-M```/MU%:P>()BXY@`0,`A?^+MF0!`P")-"1T7(G0,=+W]HT$0(G3C32!C4T0
-MZR^+!@'8B4'XBP0D*=@Y^(E!\'8"B?@IQXG-A?^)0?#'0?0`````C4D0=!^#
-MQ@PQVXML)""%[77),=*)V`-&!!-6"(E!^(E1_.N^QT7T`0```(/$!+@!````
-M6UY?7<,/MU%8#[=!6BG"*=K!X@GI:?___^L-D)"0D)"0D)"0D)"0D%6)U5=6
-M4X/L!(D$)(!Z,`!T:3'_ZR:+%"2+1C"+2C"+4`B+0`2+60@S000QTPG#=#0/
-MMD4P@\<!.?A^/XMTO4B%]G3M@'X(!';,BP0DB?+HK/___X3`=-F#Q`2X`0``
-M`%M>7UW#BQ0DBT8D.T(D=.@/MD4P@\<!.?A_P8/$!#'`6UY?7<.-="8`C;PG
-M`````%6)U5>)QU93@'@P`'1`,?;K%(GJB=CHY?___P^V1S"#Q@$Y\'XHBURW
-M2(7;=.V`>P@$=]Z)ZHG8Z#/___^$P`^40S0/MD<P@\8!.?!_V%M>7UW#C;8`
-M````C;PG`````%93B=.`>`@!=`5;,<!>PX72=%&+DF0!``"%TG1'BW($.=YT
-M1(M0)(72=#&0C70F`(M"%(7`=!^%VW4)D(UT)@#KR(G(BT@,A<EU]SG8C78`
-M=`0Y\'6TBQ*%TG746[@!````7L.)WNN\BW((Z[>-=@"+1"0$BU`0A=)X!H-X
-M%`-W!\=`+/[____SPXVV`````(M$)`2!>!#'````=@F!>!3'````=P?'0"S^
-M____\\.0BT0D!(%X$,<```!V"8M(%(7)>`+SP\=`+/[____#B?:+1"0$BU`0
-MA=)X!H-X%`-W!\=`+/[____SPXVV`````(M$)`2#>!`#=@:#>!1+=P?'0"S^
-M____\\.-M"8`````BT0D!(-X$`-V!H-X%%=W!\=`+/[____SPXVT)@````"+
-M1"0$@W@0`W8&@W@40W<'QT`L_O____/#C;0F`````(M$)`2#>!`'=@:#>!0/
-M=P?'0"S^____\\.-M"8`````BT0D!(-X$`=V!H-X%$-W!\=`+/[____SPXVT
-M)@````"+1"0$@W@0`W8&@W@4`W<'QT`L_O____/#C;0F`````(M$)`2#>!`'
-M=@F!>!3_````=P?'0"S^____\\.-="8`BT0D!(-X$`=V"8%X%*,,``!W!\=`
-M+/[____SPXUT)@"+1"0$@W@0!W8)@7@4)PT``'<'QT`L_O____/#C70F`(M$
-M)`2#>!`'=@F!>!2K````=P?'0"S^____\\.-="8`BT0D!(-X$`MV!H-X%"=W
-M!\=`+/[____SPXVT)@````"+5"0$BT(8@WH0`XL`=@R-!(4$````.4(4<P?'
-M0BS^____\\.-M@````"-OP````"+5"0$BT(8@WH0`XL`=@R-!(4$````.4(4
-M<P?'0BS^____\\.-M@````"-OP````!3@^P$BUPD#(M#&(-[$`.+`'8)@7L4
-MK0```'<,QT,L_O___X/$!%O#B00DZ/S___^%P'3H@\0$6\.-M"8`````4X/L
-M!(M<)`R+0QB#>Q`#BP!V"8%[%-<```!W#,=#+/[___^#Q`1;PXD$).C\____
-MA<!TZ(/$!%O#C;0F`````%.#[`2+7"0,BT,8@WL0`XL`=@F!>Q3Y````=PS'
-M0RS^____@\0$6\.)!"3H_/___X7`=.B#Q`1;PXVT)@````"#[`R)7"0$BUPD
-M$(ET)`B+0QB#>Q`(BTL<BS!V!H-[%`1_$\=#+/[___^+7"0$BW0D"(/$#,,/
-MME`(BT`$A-*)`8A1!'0@@3G#`0``=M6)-"3H_/___X7`=,F+7"0$BW0D"(/$
-M#,,]PP$``':VZ]^0@^P,B70D"(MT)!")7"0$@7X0LP```'8&@WX4!W<3QT8L
-M_O___XM<)`2+="0(@\0,PXM&&(L8B1PD@^L!Z/S___^#^_UWWX7`=-2`>`@$
-MB?9VS(N(9`$``(7)=<+KQXGV@^P0B70D"(MT)!2)7"0$B7PD#(-^$`AV!H-^
-M%`=W%\=&+/[___^+7"0$BW0D"(M\)`R#Q!##BWX8BQ^)'"2#ZP'H_/___X/[
-M_7<1A<!T!H!X"`1W%<=&+/[___^-1P3HC.G__RP!=;?KO(N89`$``(7;=>'K
-MYHUV`(V\)P````"#[!2)?"0,BWPD&(E<)`2)="0(B6PD$(M7&(LJC02M!```
-M`#E'$')*BW<4A?9X0X`]``````)T.C'VA>UU"XGVZS<Y[G0SBU<8@\8!BQRR
-MB1PDZ/S___^%P'07B1PDZ/S___^)PHL`.T<(=2'V0DP!==#'1RS^____BUPD
-M!(MT)`B+?"0,BVPD$(/$%,/'1RS\____Z^.-=@"-O"<`````@^P4B7PD#(M\
-M)!B)7"0$B70D"(EL)!"!?Q"'````BW<8=@V#?Q0#=R>-M"8`````QT<L_O__
-M_XM<)`2+="0(BWPD#(ML)!"#Q!3#D(UT)@`/MD8!/`AWV#'MA,!U'HGVZ]6)
-M'"3H_/___XL`.T<(D'4A@\4!B>@X1@%VNXGJ#[;"BUR&:(D<).C\____A<!U
-MT>N=QT<L_/___XVV`````.N5C;0F`````(V\)P````"+1"0$@W@0`W8&@W@4
-M`W\'QT`L_O____/#C;0F`````(/L"+H0````BTPD#(D<)(ET)`2+01B+6`B+
-M<`R+01"%VW0#C580.<)W"X7;BT$4=0LYQG8'QT$L_O___XL<)(MT)`2#Q`C#
-MB?:-O"<`````@^P4B7PD#(M\)!B)7"0$B70D"(EL)!"!?Q"O````BW<8=@V#
-M?Q0#=R>-M"8`````QT<L_O___XM<)`2+="0(BWPD#(ML)!"#Q!3#D(UT)@`/
-MMD8!/!!WV#'MA,!U'HGVZ]6)'"3H_/___XL`.T<(D'4A@\4!B>@X1@%VNXGJ
-M#[;"BUR&<(D<).C\____A<!UT>N=QT<L_/___XVV`````.N5C;0F`````(V\
-M)P````"#[!2)7"0$BUPD&(ET)`B)?"0,B6PD$(-[$`2+<QA^!H-[%`-W&\=#
-M+/[___^+7"0$BW0D"(M\)`R+;"00@\04PXGPZ+CF__\L`77:#[9&#3Q`=](Q
-M[83`=1_KT8UT)@")/"3H_/___XL`.T,(=2&#Q0&)Z#A&#7:TB>H/ML*+?(9\
-MB3PDZ/S___^%P'72ZY;'0RS\____ZY2-M"8`````@^P4B5PD!(M<)!B)="0(
-MB7PD#(EL)!"+>QB!>Q"S````BS=V!H-[%`-W&\=#+/[___^+7"0$BW0D"(M\
-M)`R+;"00@\04PXDT).C\____A<!TV8DT).C\____BP`[0PAT"<=#+/S____K
-MR(/'!`^V1P$\$'>V,>V$P'4>Z[6-=@")-"3H_/___XL`.T,(==*#Q0&)Z#A'
-M`7:9B>H/ML*+=(=PB30DZ/S___^%P'72Z7C___^-M@````"-O"<`````@^P4
-MB5PD!(M<)!B)="0(B7PD#(EL)!"+>QB#>Q`(BS=V!H-[%`-W&\=#+/[___^+
-M7"0$BW0D"(M\)`R+;"00@\04PXDT).C\____A<!TV8DT).C\____BP`[0PAT
-M"<=#+/S____KR(/'!(GXZ"_E__\L`76S#[9'#3Q`=ZLQ[83`=1OKJHDT).C\
-M____BP`[0PAURH/%`8GH.$<-=I&)Z@^VPHMTAWR)-"3H_/___X7`==+I</__
-M_Y"-M"8`````BT0D!(M0$(72>`:#>!0K=P?'0"S^____\\.-M@````"#[`R)
-M7"0$BUPD$(ET)`B+0QB#>Q`(BS!V-HM+%(7)>"^)-"3H_/___X7`=".)-"3H
-M_/___XL`.T,(=!O'0RS\____BUPD!(MT)`B#Q`S#D,=#+/[___^+7"0$BW0D
-M"(/$#,.-M@````"-O"<`````@^P,B5PD!(M<)!")="0(BT,8@WL0"(LP=C:+
-M0Q2%P'XOB30DZ/S___^%P'0CB30DZ/S___^+`#M#"'0;QT,L_/___XM<)`2+
-M="0(@\0,PY#'0RS^____BUPD!(MT)`B#Q`S#C;8`````C;PG`````(/L#(E<
-M)`2+7"00B70D"(M#&(-[$`B+,'8VBT,4A<!X+XDT).C\____A<!T(XDT).C\
-M____BP`[0PAT&\=#+/S___^+7"0$BW0D"(/$#,.0QT,L_O___XM<)`2+="0(
-M@\0,PXVV`````(V\)P````"#[`R)7"0$BUPD$(ET)`B+0QB#>Q`-BS!V-HM#
-M%(7`>"^)-"3H_/___X7`=".)-"3H_/___XL`.T,(=!O'0RS\____BUPD!(MT
-M)`B#Q`S#D,=#+/[___^+7"0$BW0D"(/$#,.-M@````"-O"<`````@^P,B5PD
-M!(M<)!")="0(BT,8@WL0#8LP=C:+0Q2%P'XOB30DZ/S___^%P'0CB30DZ/S_
-M__^+`#M#"'0;QT,L_/___XM<)`2+="0(@\0,PY#'0RS^____BUPD!(MT)`B#
-MQ`S#C;8`````C;PG`````(/L#(E<)`2+7"00B70D"(M#&(-[$`V+,'8VBT,4
-MA<!X+XDT).C\____A<!T(XDT).C\____BP`[0PAT&\=#+/S___^+7"0$BW0D
-M"(/$#,.0QT,L_O___XM<)`2+="0(@\0,PXVV`````(V\)P````"#[`R)7"0$
-MBUPD$(ET)`B+0QB#>Q`#BS!V6XM#%(7`>%2)-"3H_/___X7`=$B)-"3H_/__
-M_XG"BP`[0PAT$\=#+/S___^+7"0$BW0D"(/$#,.`>@@$=AZ+@F0!``"%P'04
-M@'AG`'4.#[:"20$``(/@&#P(=`?'0RS^____BUPD!(MT)`B#Q`S#D(VT)@``
-M``"#[`R)7"0$BUPD$(ET)`B+0QB#>Q`#BS!V/8M3%(72>#:)-"3H_/___X7`
-M="J)-"3H_/___XG"BP`[0PAT$\=#+/S___^+7"0$BW0D"(/$#,.`>@@!=`?'
-M0RS^____BUPD!(MT)`B#Q`S#C;8`````@^P,B5PD!(M<)!")="0(BT,8@WL0
-M`XLP=CV+2Q2%R7@VB30DZ/S___^%P'0JB30DZ/S___^)PHL`.T,(=!/'0RS\
-M____BUPD!(MT)`B#Q`S#@'H(`70'QT,L_O___XM<)`2+="0(@\0,PXVV````
-M`(/L$(E<)`2+7"04B70D"(E\)`R+0QB#>Q`'BS"+>`1V?XM#%(7`>'B)-"3H
-M_/___X7`=&R)/"3H_/___X7`B?9T7HDT).C\____B3PDB<;H_/___XG"BP8[
-M0PAT%\=#+/S___^+7"0$BW0D"(M\)`R#Q!##.P)UY8M&!(!X!@!T'X!Z"`%U
-M&8M&0`M&1'01BX9D`0``A<!T#H!X9P!T")#'0RS^____BUPD!(MT)`B+?"0,
-M@\00PXGVC;PG`````(/L#(E<)`2+7"00B70D"(M#&(-[$`>+,'8]BT,4A<!X
-M-HDT).C\____A<!T*HDT).C\____B<*+`#M#"'03QT,L_/___XM<)`2+="0(
-M@\0,PX!Z"`1W!\=#+/[___^+7"0$BW0D"(/$#,.-M@````"#[`R)7"0$BUPD
-M$(ET)`B+0QB#>Q!7BS!V1HM#%(7`>#^)-"3H_/___X7`=#.)-"3H_/___XG"
-MBP`[0PAT$\=#+/S___^+7"0$BW0D"(/$#,.`>@@$=@F+0@R%P'0)B?;'0RS^
-M____BUPD!(MT)`B#Q`S#C;8`````C;PG`````(/L#(ET)`B+="00B5PD!(M&
-M&(-^$$.+&'8XBT84A<!X,87;=#2)'"3H_/___X7`D'0@B1PDZ/S___^)PHL`
-M.T8(=`G'1BS\____ZPV`>@@!=`?'1BS^____BUPD!(MT)`B#Q`S#C70F`(V\
-M)P````"#[`R)="0(BW0D$(E<)`2+1AB#?A`(BQAV.(M&%(7`>#&%VW0TB1PD
-MZ/S___^%P)!T((D<).C\____B<*+`#M&"'0)QT8L_/___^L-@'H(`70'QT8L
-M_O___XM<)`2+="0(@\0,PXUT)@"-O"<`````BT0D!(M($(7)>`F+4!2%TG@"
-M\\/'0"S^____PXUT)@"+1"0$BU`0A=)X!H-X%"MW!\=`+/[____SPXVV````
-M`(M$)`2+2!"%R7@&@W@4?W<'QT`L_O____/#C;8`````@^P0B7PD#(M\)!2)
-M="0(OA````")7"0$BU\8BU<0#[9#"P^V2PS!X`F`^0)T,CG6=Q&`Z0&+5Q2^
-M$````'11.=9V(L='+/[___^+7"0$BW0D"(M\)`R#Q!##C;8`````C7`0Z\F+
-M`XD$).C\____A<!TT(L#B00DZ/S___^)PHL`.T<(=!/'1RS\____Z[N0C7`0
-M.=9WK.O,@'H(`8UV`'6AZZ:-M@````"-OP````"#[!")?"0,BWPD%(ET)`B^
-M%````(E<)`2+7QB+5Q`/MT,0#[9+$L'@"8#Y`G0R.=9W$8#I`8M7%+X4````
-M=%$YUG8BQT<L_O___XM<)`2+="0(BWPD#(/$$,.-M@````"-<!3KR8L#B00D
-MZ/S___^%P'30BP.)!"3H_/___XG"BP`[1PAT$\='+/S____KNY"-<!0YUG>L
-MZ\R`>@@!C78`=:'KIHVV`````(V_`````(/L#(E<)`2+7"00B70D"(M#&(-[
-M$`.+,'8VBT,4A<!X+XDT).C\____A<!T(XDT).C\____BP`[0PAT&\=#+/S_
-M__^+7"0$BW0D"(/$#,.0QT,L_O___XM<)`2+="0(@\0,PXVV`````(V\)P``
-M``"#[!2)?"0,BWPD&(E<)`2)="0(B6PD$(M7&`^V*HT$K00````Y1Q!R/X-_
-M%`-V.3'VA>UU">LX.>YT-(M7&(/&`8L<LHD<).C\____A<!T&(D<).C\____
-MBP`[1PATV,='+/S____K!\='+/[___^+7"0$BW0D"(M\)`R+;"00@\04PXVV
-M`````(V\)P````"#[!2)?"0,BWPD&(E<)`2)="0(B6PD$(M7&`^V*HT$K00`
-M```Y1Q!R/X-_%`-V.3'VA>UU">LX.>YT-(M7&(/&`8L<LHD<).C\____A<!T
-M&(D<).C\____BP`[1PATV,='+/S____K!\='+/[___^+7"0$BW0D"(M\)`R+
-M;"00@\04PXVV`````(V\)P````"#[`R)7"0$BUPD$(ET)`B+0QB#>Q`'BS!W
-M%L=#+/[___^+7"0$BW0D"(/$#,.-=@")-"3H_/___X7`=-Z)-"3H_/___XL`
-M.T,(=-;'0RS\____BUPD!(MT)`B#Q`S#B?:+5"0$BT(8@WH0`XL`=@R-!(4$
-M````.4(4<P?'0BS^____\\.-M@````"-OP````!3@^P(BUPD$(M#&(-[$`(/
-MM@!V/(M3%(72>#4QT@^VP.B+VO__A<")PG0EBT`$BT!\A<!T&XM"##M#"'0:
-MQT,L_/___X/$"%O#C;0F`````,=#+/[___^#Q`A;PXUT)@"#[`RY'````(E<
-M)`2+7"00B70D"(MS&(M#$`^V5@2`^@)T+3G!=Q&`Z@&+0Q2Y"````'1..<%V
-M(,=#+/[___^+7"0$BW0D"(/$#,.0C70F`(M.&(/!'.O+BP:)!"3H_/___X7`
-M=-*+!HD$).C\____B<*+`#M#"'05QT,L_/___^N]BTX8@\$(.<%WK.O*@'H(
-M`76D@'X'$'>>C;8`````ZYV-M"8`````C;PG`````%.+1"0(BUPD#(M(+#'`
-M@WPD$`"+41AT'8!Z!`%T&8U"'(E#"(M"&,=#!`$```")`[@!````6\.+01R#
-MP`B)0PCKXHVT)@````"-O"<`````@^P0B70D"(MT)!2)7"0$B7PD#(M6$(M>
-M&(/Z"W9EBWX4A?]X7H![!P!U=0^V0P;!X`F-2`PQP#G*<DB#P`0YQW)!BP.)
-M!"3H_/___X7`=#.+`XD$).C\____B<*+`#M&"'0)QT8L_/___^L>@'H(`741
-M#[9#!@^W4P0!T#T`(```?@?'1BS^____BUPD!(MT)`B+?"0,@\00PXVV````
-M``^V0P:Y#````,'@">N)B?:#[!")7"0$BUPD%(ET)`B)?"0,BTL0BW,8@_D'
-M=B6+>Q2%_W@>A<D/ME8$#[9&!7@2#[;`#[;2`=#!X`F#P`@YQW,7QT,L_O__
-M_XM<)`2+="0(BWPD#(/$$,.+!HD$).C\____A<!TVXL&B00DZ/S___^)PHL`
-M.T,(=`G'0RS\____Z\:`>@@!=;F-M@````#KN(VT)@````"-O"<`````5XG'
-M5HG64X/L$*'``@``@_C_=&^+4@R[P`(``.L,B?:#PQ2+`X/X_W19.=!U\H/`
-M`710QT8L`````(DT)(UV`/]3!(M&+(7`=4V`OX0!`P``=3"+2Q"%R0^%C0``
-M`(N7*`$``(72=#J+ET0!``"-AT`!``")MT0!``")!HE6!(DRZPW'1BS^____
-MB30D_U8H@\006UY?PXDT)/]6*(UV`.ONBT,(B;<H`0``A<!T/(M##,>'+`$`
-M``$```")MS0!``#'AS@!````````B8<P`0``B30D_U,(BX<L`0``@^@!A<")
-MARP!``!UI8DT)/]3#.N=C;8`````C;PG`````%.+"(V8"`(``,>`V`$```__
-M``")F.0!``")B-0!``"+B%@"``#'@-P!```(````QX#@`0```````,>`[`$`
-M``````")B`@"``")4P2-D,P!``#'@/0!```@0@0`BX#4`0``6^F8_O__D(VT
-M)@````"#[`R)7"0$BUPD$(ET)`B+<P@YGB@!``!T%HE<)!"+2RB+="0(BUPD
-M!(/$#/_AB?:+CD`!``"-AD`!``#'AB@!````````.<%TT(L1BT$$B4($B1")
-MRHGPB0F)203H+O[__^NVC;8`````C;\`````BT0D!(N`6`(``,.0C70F`%=6
-M4X/L-(M,)$B-="0(#[94)$2)\(G+Q@``C7PD-(/``3GX=?*`^@>(5"00#X2M
-M````@/H&=#2`^@1T+X#Z!9!T*8#Z"'0D@/H<=&Z`^@.0="Z+@U@"``")-"2)
-M1"0,Z/S___^#Q#1;7E_#]H%(`0```733@/H<QD0D%`%USNLZBTL0A<ETRP^V
-M062(1"04@'ED`'6]BT%(BU%,B40D&(E4)!P/MT%0B40D(`^V0670Z(/@`8A$
-M)!7KF(N!3`$``(N14`$``(E$)!0/MX$4`@``B50D&&:)1"0<Z7/___^+00R%
-MP'0*BX!8`@``B40D%(M9).E:____D(VT)@````"+1"0(H@````##C;8`````
-M4XM$)`B+7"0,BU`,C4@,.<IU".LHBQ(YRG0BC8+8_?__@'@(`77N]H`<`@``
-M`73EA=MT"XL2@^L!.<IUWC'`6\/K#9"0D)"0D)"0D)"0D)"#[!R)7"04B<.)
-M="08BT`@B=:)1"0$BP.)!"3H_/___P^V4&6)6"B)6"R)<#"#XL^#RB"(4&7&
-M0&0$QD!F`,=`<'!H!`")!"3H_/___XM<)!2+="08@\0<PXVT)@````"#[!R)
-M="00B7PD%(G'B6PD&(G5B5PD#(L8BT`@B4PD"(D<)('#F````(E$)`3H_/__
-M_XD<)(G&Z/S____'``````#'0`0`````BU<4BT\8QT`@`````,=`$`````")
-M4`B-4!2)2`S'0!P`````QT`D`````(E0%(E0&,=`*`````")1CS&1F0$BT0D
-M"(E^*(EN+,9&9@")1G")-"3H_/___XM<)`R+="00BWPD%(ML)!B#Q!S#C70F
-M`(V\)P````"#[!R)7"00B<N)="04B=:)?"08B<>#`0&+0"")1"0$BP>)!"3H
-M_/___X/^`8G!&<`/ME%E@\`"@^`#P>`$B7DH@^+/"<*(467&060$B5DLQD%F
-M`(!_"`1V%XN'9`$``(7`=`W'07#@:00`ZPN-="8`QT%PD&D$`(D,).C\____
-MBP>)!"3H_/___XM<)!"+="04BWPD&(/$',.-M"8`````55=64X/L'(M\)#"+
-M1"0TBVPD.(V/L````(E$)!2)3"08B0PDZ/S___^%P(G&#X2.````BU\,QP`!
-M````BT0D%(E^$(/'#(EN"#G[B48$QT8,`````'4/ZS2-M"8`````BQLY^W0G
-MC8/8_?__@'@(`77N]H`<`@```73EB?&Z`0```.C9_O__BQLY^W79BP:#Z`&%
-MP(D&=`B#Q!Q;7E]=PXM,)!B)="0$B0PDZ/S___^+3"04B6PD,(/$'%M>7UW_
-MX<<$)(X#``#H_/___^OAD%575E.#[!R+?"0PBT0D-(ML)#B-C[````")1"04
-MB4PD&(D,).C\____A<")QG1SBU\,QP`!````BT0D%(E^$(/'#(EN"#G[B48$
-MQT8,`````'0;C8/8_?__@W@<_W0)B?$QTN@H_O__BQLY^W7EBP:#Z`&%P(D&
-M=`B#Q!Q;7E]=PXM,)!B)="0$B0PDZ/S___^+3"04B6PD,(/$'%M>7UW_X<<$
-M)*D#``#H_/___^OA4X/L"(M4)!2+7"00BTH@B5H(A<ET!8M"%(D!B=CH3OG_
-M_XE<)!"#Q`A;Z?S___^04XM$)`R+7"0(BY!8`@``C8@(`@``B9C4`0``QX#8
-M`0``#_\``(F(Y`$``(F0"`(``(V0%@(``,>`W`$```@```#'000,````B9#H
-M`0``QX#@`0```````,>`[`$```````")@/`!``#'@/0!``#`G00`!<P!``")
-M1"0,B5PD"%OI_/___XUT)@"-O"<`````@^P,BT0D$(M0"(F"3`$``(V"2`$`
-M`,>"2`$``+!M!`#'@E`!````````@\(DB40D!(D4).C\____@\0,PXUV`(/L
-M#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!``"@;P0`QX)0`0```````(/")(E$
-M)`2)%"3H_/___X/$#,.-=@"#[`R+1"00BU`(B8),`0``C8)(`0``QX)(`0``
-M@/8$`,>"4`$```````"#PB2)1"0$B10DZ/S___^#Q`S#C78`@^P,BT0D$(M0
-M"(F"3`$``(V"2`$``,>"2`$``(#G!`#'@E`!````````@\(DB40D!(D4).C\
-M____@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!````JP0`QX)0
-M`0```````(/")(E$)`2)%"3H_/___X/$#,.-=@"#[`R+1"00BU`(B8),`0``
-MC8)(`0``QX)(`0``8.L$`,>"4`$```````"#PB2)1"0$B10DZ/S___^#Q`S#
-MC78`@^P,BT0D$(M0"(F"3`$``(V"2`$``,>"2`$``."N!`#'@E`!````````
-M@\(DB40D!(D4).C\____@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'
-M@D@!``#0JP0`QX)0`0```````(/")(E$)`2)%"3H_/___X/$#,.-=@"#[`R+
-M1"00BU`(B8),`0``C8)(`0``QX)(`0``\/D$`,>"4`$```````"#PB2)1"0$
-MB10DZ/S___^#Q`S#C78`@^P,BT0D$(M0"(F"3`$``(V"2`$``,>"2`$``!"?
-M!`#'@E`!````````@\(DB40D!(D4).C\____@\0,PXUV`(/L#(M$)!"+4`B)
-M@DP!``"-@D@!``#'@D@!``#`[00`QX)0`0```````(/")(E$)`2)%"3H_/__
-M_X/$#,.-=@"#[`R+1"00BU`(B8),`0``C8)(`0``QX)(`0``P*\$`,>"4`$`
-M``````"#PB2)1"0$B10DZ/S___^#Q`S#C78`@^P,BT0D$(M0"(F"3`$``(V"
-M2`$``,>"2`$``,"O!`#'@E`!````````@\(DB40D!(D4).C\____@\0,PXUV
-M`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!```@L@0`QX)0`0```````(/"
-M)(E$)`2)%"3H_/___X/$#,.-=@"#[`R+1"00BU`(B8),`0``C8)(`0``QX)(
-M`0``<,4$`,>"4`$```````"#PB2)1"0$B10DZ/S___^#Q`S#C78`@^P,BT0D
-M$(M0"(F"3`$``(V"2`$``,>"2`$``"#[!`#'@E`!````````@\(DB40D!(D4
-M).C\____@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!``#`Q@0`
-MQX)0`0```````(/")(E$)`2)%"3H_/___X/$#,.-=@"#[`R+1"00BU`(B8),
-M`0``C8)(`0``QX)(`0``T.X$`,>"4`$```````"#PB2)1"0$B10DZ/S___^#
-MQ`S#C78`@^P,BT0D$(M0"(F"3`$``(V"2`$``,>"2`$``.#%!`#'@E`!````
-M````@\(DB40D!(D4).C\____@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!
-M``#'@D@!``#@S@0`QX)0`0```````(/")(E$)`2)%"3H_/___X/$#,.-=@"#
-M[`R+1"00C5`4QT`4P`(%`(E`&,=`'`````")5"0$BP"#P"2)!"3H_/___X/$
-M#,.#[`R+1"00C5`8QT`8<,\$`(E`',=`(`````")5"0$BT`$BP"#P"2)!"3H
-M_/___X/$#,.-M@````"-O"<`````4X/L"(M<)!"`>V8!=`X/MD-G@\`!/`*(
-M0V=V1(M#/(E$)`2+`P68````B00DZ/S___^-0Q3'0Q00QP0`B5L8QT,<````
-M`(E$)`2+`X/`)(D$).C\____@\0(6\.-="8`BT,\QD-F`,=`$`````"+0SR-
-M4!3'0!P`````QT`@`````,=`)`````")4!2)4!C'0"@`````B5PD$(/$"%OI
-M_/___XVV`````(V\)P````"#[`R+3"00BT$LBQ"#Z@&%THD0=2N-013'012@
-M:@0`B4D8QT$<`````(E$)`2+`8/`+(D$).C\____@\0,PXGVB4PD$(/$#.G\
-M____C70F`(/L'(M,)"")7"00B70D%(E\)!B+02B+D&0!``"+>@0YQP^$BP``
-M`(7_=`GVAQP"```!=1R)3"0@BUPD$(MT)!2+?"08@\0<Z63___^-="8`BW$L
-M#[9998D,).C\____BT<@P.L$@^,#B40D!(L'P>,$B00DZ/S___\/ME!EB7@H
-MQD!D!(EP+(/BSPG:B%!EQD!F`,=`<)!I!`"+7"00B40D((MT)!2+?"08@\0<
-MZ?S___^+>@CI;?___XVV`````(/L'(ET)!B+="0@B5PD%(M>+(M#"(D$)/]3
-M!(E<)`2+!@6P````B00DZ/S___^+7"04B70D((MT)!B#Q!SI_/___XVT)@``
-M``"-O"<`````5U93@>S`````B[PDT````(V$))0```"+=RB+7EB+5E")1"0$
-MBT9<B00D_U(\C40D'(M3!(E$)`2+0PB)!"3_4AR-A"2T````B00DC8PDN```
-M`(G8C90DO````.B`R?__]H0DG@````)T:8N4)+0````/MH0DH````(!_9@&-
-M!`)T7HE$)`B+A"2\````QP0DT`L``(E$)`3H_/___XET)`3'!"0:````Z/S_
-M__^+1RR)1"0$BP:#P%")!"3H_/___XD\).C\____@<3`````6UY?PXN4)+@`
-M``#KE8UT)@")1"0(BX0DO````,<$)*@+``")1"0$Z/S___^)="0$QP0D&P``
-M`.C\____ZZ"-=@"#[!R+5"0@B5PD%(ET)!B+6BR+0P2+,(D4).C\____QT,8
-M\`,%`(E;'(/&),=#(`````"#PQB)7"0$B30DZ/S___^+7"04BW0D&(/$',.)
-M]H/L+(E<)!R+7"0PB70D((E\)"2);"0HBRN+<RR+A2@!``"+?@B)1"04BT8$
-MB40D&(![9@%T$@^V0V>#P`$\`HA#9P^&OP```(M#/(E$)`2-A9@```")!"3H
-M_/___XD<).C\____BT0D%(7_BU`<#X1]````BX=8`@``B0*#P`%T=HM$)!B-
-M5@R`B$D!```$@(])`0``!("G2`$``/V)MV0!``")L&0!``"+31B-112)1@R-
-M1AB)51C'1AA@EP0`B4X0B78<QT8@`````(D1B40D!(U%)(D$).C\____BUPD
-M'(MT)""+?"0DBVPD*(/$+,/'`O____^+1"04QT`L_____^EZ____BT,\QD-F
-M`,=`$`````"+0SR-4!3'0!P`````QT`@`````,=`)`````")4!2)4!C'0"@`
-M````BW0D((E<)#"+?"0DBUPD'(ML)"B#Q"SI_/___XVT)@````!55U93@^PL
-MBT0D0(MH&(M0'(M%`(E4)!R)!"3H_/___XE$)"B+1"1`#[9-!`^V707'0"S_
-M____#[95!H#Z"P^'W````(!]!PL/A](````/ML&)1"0@#[;"`T0D((/X"WX'
-MN0L````HT8M4)!R(2@0/MDT'#[;3#[;!`="#^`M^![L+````*,N+3"0<BT0D
-M'(/!"(E,)"2`>`0`B%@%#X2N````,?_K$HM,)!R#QP&)^CA1!`^&F````(GZ
-MBTPD*`^V\HGPP>`)`T0D),=$)!0!````QT0D#`$```")1"00BT$XBU$\#[9-
-M!@4``/[_@]+_)0``_O\QVP'($=HQVP'PB40D!(M$)"@1VHE4)`B)!"3H_/__
-M_X7`=(V-M@````"+3"1`B<B#P##'03"0700`B4DTQT$X`````(E$)`2+00B)
-M!"3H_/___X/$+%M>7UW#BT0D'(!X!0!T>C'_ZP^0BT0D'(/'`8GY.$@%=F>+
-M3"0@B?H/MO+'1"04`0```,=$)`P!````C00.P>`)`T0D)(E$)!"+1"0HBT@X
-MBU@\#[9%!X'!`/C__X/3_S'2`<$1TS'2`?$1TXM4)"B)3"0$B5PD"(D4).C\
-M____A<!TD.E+____BU0D0,="+`````#I.____XUT)@"-O"<`````55=64X/L
-M+(M$)$"+>!B+!XD$).C\____BU0D0(E$)"2+0AS'``````#'0BP`````@'\'
-M``^$T0```(G&@\8$B70D*(!_!@`/A(T````Q[>L*@\4!B>@X1P9V?P^V1P>)
-MZC';#[;2BW0D),=$)`P!````B50D((E$)!2)T,'@"0-$)"B)1"00#[=/!(M&
-M.(M6/(DT)(/!"X/3``4``/[_@]+_)0``_O\!P8M$)"`1TS'2`<$1TXE,)`2)
-M7"0(Z/S___^%P'2+BU0D0(M"',<`_____\="+/____^+5"1`B="#P##'0C"0
-M700`B5(TQT(X`````(E$)`2+0@B)!"3H_/___X/$+%M>7UW#C4<,B40D*.DL
-M____B?:-O"<`````5E.#[!2+3"0@BUDL@'EF`8MS''0^@'E*`'4XQT,L____
-M_XD,).C\____C4,PQT,PD%T$`(E;-,=#.`````")1"0$BT,(B00DZ/S___^#
-MQ!1;7L/'0RP`````#[9!2H3`B`9U'(M!3(E&!(M3((72=+&+1@2#P`B)`NNG
-MD(UT)@`/MD%)B48$Z^&-M"8`````@>RL````B;0DH````(NT)+````")G"2<
-M````B;PDI````(FL)*@```"+1A@/ME`"#[8(@/H##X0D`0``@/H$#X0\`0``
-M@'@!!78'@'@%_I!T8@^VP3'2Z'3"__^)PXM&"(M6*,=&*&!S!`")L$P!``")
-MD$@!``"+4P3'@%`!````````B70D!(M#"(D$)/]2?(N<))P```"+M"2@````
-MB[PDI````(NL)*@```"!Q*P```##C5`+B50D%`^V>`LQTHM&%(E$)!@/ML'H
-M`,+__X7`B<-T3(UL)""-M@````"+0P2+D(0```"%TG08BT,(B00D_]*)^CC0
-M#X?T````B?HHPHG7BQN%VW07BU,$B6PD!(M#"(D$)/]2'(!\)#,`=+Z+1B#'
-M``````"-1C#'1BS_____QT8PD%T$`(EV-,=&.`````")1"0$BT8(B00DZ/S_
-M___I-____XVV``````^V0`2-E"28````B80DF`````^VP>A6P?__B</IW?[_
-M_XU0`XE4)!`QT@^V>`,/ML'H.L'__X7`B<-TCXUL)"#K*XGZ*,*)UXL;A=L/
-MA'G___^+4P2);"0$BT,(B00D_U(<@'PD,P`/A5[___^+0P2+D(0```"%TG3.
-MBT,(B00D_]*)^CC0=KJ+1"00B!#I:_[__XM$)!2($(M&((M4)!B)$.E7_O__
-MB?:-O"<`````@^P,BT0D$(M("(E`-,=`.`````"+D4@!``#'0#"0700`B5`H
-M@\`PB40D!(D,).C\____@\0,PXGVC;PG`````%575E.![)P```"+-0````"+
-ME"2P````QT0D&`````"%]HM"&(L`B40D$(M"''1P@\`$,?^)1"04C6PD)(M>
-M"(7;=0OK2H/'`8L;A=MT08M3!(EL)`2+0PB)!"3_4AR`?"0W`'3CBX0DL```
-M`#EP"'74@T0D&`&+5"04BT0D&#E$)!").G8/@\($B50D%.NVBS:%]G6GBY0D
-ML````(M"'(M4)!B)$(N$)+````"+E"2P````QT`PD%T$`(E`-,=`.`````"#
-MP#")1"0$BT((B00DZ/S___^!Q)P```!;7E]=P^L-D)"0D)"0D)"0D)"0D%93
-M@^P4BS5``@``BUPD(#LU1`(``(M+'`^$I0```&O6+(N"8`(``(D!BX)D`@``
-MB4$$BX)H`@``B4$(BX)L`@``B4$,BX)P`@``B4$0BX)T`@``B4$4BX)X`@``
-MB4$8BX)\`@``B4$<BX*``@``B4$@BX*$`@``B4$DBX*(`@``B4$HC48!B<+!
-M^A_!ZAP!T(/@#RG0HT`"``"-0S#'0S"0700`B5LTQT,X`````(E$)`2+0PB)
-M!"3H_/___X/$%%M>P\=#+/_____KSHUT)@"#["PQTHE<)!R+7"0PB70D((E\
-M)"2);"0HBT,8BV@$BW`(BW@,BP#HE+[__X7`B<%T?H7V=&"+0`3'1"00````
-M`(E\)`R+4QB#PA")5"0(B6PD!(M1"(D4)/^0F````(U#,,=#,)!=!`")6S3'
-M0S@`````B40D!(M#"(D$).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.+0`3'
-M1"00`0```(E\)`R+4QSKH8VV`````,=#+/[____KIHVT)@````!6,=)3@>R4
-M````BYPDH````(M#&(L`Z.6]__^+<QR%P(G!=%&+4`2-1"0<B40D!(M!"(D$
-M)/]2'`^W1"0@9HD&#[=$)")FB48"C4,PQT,PD%T$`(E;-,=#.`````")1"0$
-MBT,(B00DZ/S___^!Q)0```!;7L/'0RS^____Z\N)]H/L+(E\)"2+?"0PB70D
-M((EL)"B)7"0<BT<8BQB-<`2+1QR)'"2#ZP&)1"08Z/S___^#^_Z)Q1G`(<4/
-MMD8*A,!U!P^V1@[`Z`0/ML`/MDX-#[96#(E$)`@/MD8.@^`/B40D!(U&?(D$
-M)(GHZ/#$__^+3"08QT<PD%T$`(E_-,='.`````")`8U',(E1!(E$)`2+1PB)
-M!"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#@^PLB70D((MT)#");"0HB5PD
-M'(E\)"2+?AB+1AR+'XUO!(E$)!B)'"2#ZP'H_/___X/[_@^V30&)PAG`(=`/
-MME<$@\=TQT0D"``````/MET"B3PD@^,/B5PD!.A0Q/__BTPD&,=&,)!=!`")
-M=C3'1C@`````B0&-1C")402)1"0$BT8(B00DZ/S___^+7"0<BW0D((M\)"2+
-M;"0H@\0LPU575E.#[`R+1"0@BU0D((M`'(G%B40D"(M"&(/%!(LXA?\/CGX`
-M``"+-0````"%]G1T,=N+5@R-3@PYRG4(ZUZ+$CG*=%B-@MC]__^`>`@!=>Z+
-M@%@"``")1)T`@\,!.=]UW8G8BU0D"(D"BT0D((M4)"#'0#"0700`B4`TQT`X
-M`````(/`,(E$)`2+0@B)!"3H_/___X/$#%M>7UW#BS:%]G60Z[TQP.N[C;8`
-M````55=64X/L'(M$)#"+5"0PBT`<B40D%(/`!(E$)!B+0AB+*(7M#X[(````
-MBST`````A?\/A+H````Q]HM7#(U?##G:=1;IF0```(VT)@````"+$CG:#X2(
-M````C8+8_?__BT@,A<EUZ0^V2`B`^01V8HN(9`$``(7)=`N#>00`=`4Y00AT
-MRXN`6`(``(M,)!B)!+&#Q@$Y[G6WB?"+3"0PBU0D%,=!,)!=!`")`HG(@\`P
-MB4DTQT$X`````(E$)`2+00B)!"3H_/___X/$'%M>7UW#@.D!=;[V0$P"=+B-
-M=@#KHXL_A?\/A4[___^-="8`ZZ<QP.NEC78`C;PG`````%575E.![)P```"+
-MO"2P````BT<8BU`(BW`$BP")5"08BU<<B50D%#'2Z%*Z___'1RS_____A<")
-MPW0]C6PD))"+0P2+D(0```"%TG0.BT,(B00D_](YQGQ-*<:+&X7;=!>+4P2)
-M;"0$BT,(B00D_U(<@'PD-P!TR(U',,=',)!=!`")?S3'1S@`````B40D!(M'
-M"(D$).C\____@<2<````6UY?7<.+5"04BT,$QT0D#`````")="0$B50D$(M4
-M)!B)5"0(BU,(B10D_Y"4````A<!UH\='+`````#KFHGV55=64X'LG````(N\
-M)+````"+1QB+5QR+<`2+`(E4)!@QTNAYN?__QT<L_____X7`B<-T0#'MBT,$
-MBY"$````A=)T$(M#"(D$)/_2.<9\4RG&`<6+&X7;=!N-1"0DBU,$B40D!(M#
-M"(D$)/]2'(!\)#<`=,*-1S#'1S"0700`B7\TQT<X`````(E$)`2+1PB)!"3H
-M_/___X'$G````%M>7UW#BT,$BY"4````A=)TQ8M$)!C'1"00`````,=$)`@`
-M````B70D!(E$)`R+0PB)!"3_TH7`=9V+5"08#[9"`CS_=`4!Z(A"`L='+```
-M``#K@^L-D)"0D)"0D)"0D)"0D%575E.![)P```"+O"2P````BT<8BU<<BW`$
-MBP")5"08,=+H>;C__\='+/____^%P(G#=$`Q[8M#!(N0A````(72=!"+0PB)
-M!"3_TCG&?%,IQ@'%BQN%VW0;C40D)(M3!(E$)`2+0PB)!"3_4AR`?"0W`'3"
-MC4<PQT<PD%T$`(E_-,='.`````")1"0$BT<(B00DZ/S___^!Q)P```!;7E]=
-MPXM#!(N0D````(72=,6+1"08B70D!(E$)`B+0PB)!"3_TH7`=:V+5"08#[9"
-M`CS_=`4!Z(A"`L='+`````#KD^L-D)"0D)"0D)"0D)"0D%575E.![)P```"+
-MO"2P````BT<8BU<<BW`$BP")5"08,=+HB;?__\='+/____^%P(G#=$`Q[8M#
-M!(N0A````(72=!"+0PB)!"3_TCG&?%,IQ@'%BQN%VW0;C40D)(M3!(E$)`2+
-M0PB)!"3_4AR`?"0W`'3"C4<PQT<PD%T$`(E_-,='.`````")1"0$BT<(B00D
-MZ/S___^!Q)P```!;7E]=PXM#!(N0C````(72=,6+1"08B70D!(E$)`B+0PB)
-M!"3_TH7`=:V+5"08#[9"`CS_=`4!Z(A"`L='+`````#KD^L-D)"0D)"0D)"0
-MD)"0D%575E.![)P```"+O"2P````BT<8BU<<BW`$BP")5"08,=+HF;;__\='
-M+/____^%P(G#=$`Q[8M#!(N0A````(72=!"+0PB)!"3_TCG&?%,IQ@'%BQN%
-MVW0;C40D)(M3!(E$)`2+0PB)!"3_4AR`?"0W`'3"C4<PQT<PD%T$`(E_-,='
-M.`````")1"0$BT<(B00DZ/S___^!Q)P```!;7E]=PXM#!(N0B````(72=,6+
-M1"08B70D!(E$)`B+0PB)!"3_TH7`=:V+5"08#[9"`CS_=`4!Z(A"`L='+```
-M``#KD^L-D)"0D)"0D)"0D)"0D%4QTE=64X'LC````(N\)*````"+1QB+`.BS
-MM?__,=*%P(G#=$$Q]HUL)!20C70F`(M#!(N0A````(72=`J+0PB)!"3_T@'&
-MBQN%VW07BU,$B6PD!(M#"(D$)/]2'(!\)"<`=,R)\HM'',=',)!=!`")?S3'
-M1S@`````B1"-1S")1"0$BT<(B00DZ/S___^!Q(P```!;7E]=PXVT)@````!3
-M@^P(BUPD$(M#&(M+'(M0!(L`Z!BW__^%P'0'QT,L_____XU#,,=#,)!=!`")
-M6S3'0S@`````B40D!(M#"(D$).C\____@\0(6\.0C70F`%<QTE93@>R0````
-MB[0DH````(M&&(M>'(L`Z,&T__^%P`^$E````#'2C;0F`````,8$&@"#P@&#
-M^D1U](U,)!B)RL8"`(V\))````"#P@$Y^G7OBU`$B4PD!(M`"(D$)/]2'`^V
-MA"2%````B`,/MH0DA@```(A#`0^VA"2'````B$,"#[:$)(@```"(0P.-1C#'
-M1C"0700`B78TQT8X`````(E$)`2+1@B)!"3H_/___X'$D````%M>7\/'1BS_
-M____Z\J-M@````"-OP````"#[!R)7"04BUPD((ET)!B+<QSHF;7__\=#,)!=
-M!`")6S3'0S@`````B0:-0S")1"0$BT,(B00DZ/S___^+7"04BW0D&(/$',.0
-MC;0F`````%:ZP0,``%.#[!2+="0@BUX8B=CH6+/__X7`=30/MD,@H@````"-
-M1C#'1C"0700`B78TQT8X`````(E$)`2+1@B)!"3H_/___X/$%%M>PXGVNLX#
-M``")V.@4L___A<!U$@^V0R"-!,5P_O__HP````#KL[K?`P``B=CH\K+__X7`
-M=$2Z_`,``(G8Z.*R__^%P'5"BT8(QX!(`0``4(@$`(FP3`$``(V02`$``,>`
-M4`$```````"#P"2)5"0$B00DZ/S____K@@^V0R"B`````.E1____NAD$``")
-MV.B0LO__A<!U#XM&",>`2`$``*"!!`#KK,=&+/_____I)O___Y"#[`R+1"00
-MBU`<QT`PD%T$`(E`-,=`.`````#'`@```0*-4#")5"0$BT`(B00DZ/S___^#
-MQ`S#B?:-O"<`````55=64X/L/(ML)%"+11B+50C&1"0T!X!X(`&->@P9P(/`
-M`HA$)#B+<@PY_G0AC78`C9[8_?__]H,<`@```70&@'L(`70XBS8Y_G7EBU4(
-MQT4L`````(U%,,=%,)!=!`");33'13@`````B40D!(D4).C\____@\0\6UY?
-M7<.-5"04BT-0B50D!(M37(D4)/]0/`^V1"0C.D0D.'2IC40D-(M34(E$)`2+
-M0UR)!"3_4F#KDXVT)@````"-O"<`````@^P<B5PD#(M<)"")?"04B70D$(EL
-M)!B+`XMS+(E$)`B+1AB+*(DL).C\____@'MF`8G'=!(/MD-G@\`!/`*(0V</
-MAHD```"+0SR)1"0$BT0D"`68````B00DZ/S___^)'"3H_/___XM&##TI_P``
-M=%4].?\``'1.A?]T#(L7.U0D"`^$F@```(U&,,=&+/[____'1C"0700`B78T
-MQT8X`````(E$)`2+1@B)!"3H_/___XM<)`R+="00BWPD%(ML)!B#Q!S#BT8<
-MB2CKJXUV`(M#/,9#9@#'0!``````BT,\C5`4QT`<`````,=`(`````#'0"0`
-M````B5`4B5`8QT`H`````(MT)!")7"0@BWPD%(M<)`R+;"08@\0<Z?S___^-
-M@D@!``#'@D@!```0EP0`B;),`0``QX)0`0```````(E$)`2-0B2)!"3H_/__
-M_^E<____C78`C;PG`````(/L#(L0B00D@<(L`0``B50D!.C\____@\0,PY"-
-M="8`@^P,BT0D$(M`&(L`B00DZ/S___^#Q`SKQXVT)@````"#[`R+1"00BT`8
-MBP")!"3H_/___X/$#.NGC;0F`````(/L#(M$)!"+0!B`>`0!BQ!T!(/$#,.)
-M%"3H_/___X/$#.EZ____C78`C;PG`````%575E.#[`R+;"0@BT48BQ!F]\(`
-M_W5%B=>!Y_\```!^.S'VNP0```#K"8VV`````(M%&(L$&(D$).C\____A<!T
-M$(!X"`1V"HN09`$``(72=!*#Q@&#PP0Y_G74@\0,6UY?7</H!____^OGD(UT
-M)@"#[`R+1"00BT`8BP")!"3H_/___X/$#.GD_O__C70F`(/L#(M$)!")="0(
-MB5PD!(M`&(M8!(L`B00DZ/S___^#^PV)QG0O@_L!=!B#^P2)]G01@_L'=`R+
-M7"0$BW0D"(/$#,.)\(M<)`2+="0(@\0,Z8O^__^%P'3>BX!D`0``A<!TU(M0
-M!(72=`V)T.AO_O__BX9D`0``BT`(A<!TN8M<)`2+="0(@\0,Z5+^__^)]H/L
-M#(M$)!")="0(B5PD!(M`&(M8!(L`B00DZ/S___^)'"2)QNC\____B<.)\.@>
-M_O__B=B+="0(BUPD!(/$#.D,_O__C;8`````C;\`````@^P,BT0D$(M`&(L`
-MB00DZ/S___^#Q`SIY/W__XUT)@"#[`R+1"00BT`8BP")!"3H_/___X/$#.G$
-M_?__C70F`%.#[`B+1"00BT`8BP")!"3H_/___X7`B<-T-8N`9`$``(7`="N+
-M4`2%TG0-B=#HC?W__XN#9`$``(M`"(7`=""#Q`A;Z7?]__^-M"8`````B=B#
-MQ`A;Z67]__^0C70F`(/$"%O#C70F`(V\)P````!64X/L!(M$)!"+<!B#Q@2`
-M?@T`=!XQVXM$GGR#PP&)!"3H_/___^@E_?__#[9&#3G8=^2#Q`1;7L.-M"8`
-M````5E.#[`2+1"00BW`8@\8$@'X!`'0>,=N+1)YP@\,!B00DZ/S____HY?S_
-M_P^V1@$YV'?D@\0$6U[#C;0F`````%93@^P$BT0D$(MP&(!^#0!T'C';BT2>
-M?(/#`8D$).C\____Z*C\__\/MD8-.=AWY(/$!%M>PXUV`(V\)P````!64X/L
-M!(M$)!"+<!B`?@$`=!XQVXM$GG"#PP&)!"3H_/___^AH_/__#[9&`3G8=^2#
-MQ`1;7L.-=@"-O"<`````5E.#[`2+1"00BW`8@'X!`'0>,=N+1)YH@\,!B00D
-MZ/S____H*/S__P^V1@$YV'?D@\0$6U[#C78`C;PG`````%93@^P$BT0D$(MP
-M&(L.A<ET&C';BT2>!(/#`8D$).C\____Z.C[__\Y'G?H@\0$6U[#C;0F````
-M`(V\)P````!6NOP#``!3@^P$BW0D$(M&&.C*J___A<!U+HM&"(M8#(/`##G#
-M="&-@]C]___V@!P"```!=`:`>`@!=!*+1@B+&X/`##G8==^#Q`1;7L/H??O_
-M_^OGC70F`(V\)P````!55U93@>R,````BX0DH````(MH"(M0&(MU#(U]#(E4
-M)`@Y_G0?C9[8_?__]H,<`@```70*@'L(`0^$N@```(LV.?YUX8M4)`@/MD(@
-MH@````"+70B%VW1=C70D#.L(B?:+&X7;=$^+4P2)="0$BT,(B00D_U(<]D0D
-M'1!TXXV=S````(E<)`2)+"3H_/___\>%S`````"'DP/'A=0`````````B:W8
-M````B5PD!(DL).C\____BX0DH````(N4)*````#'0"P`````QT`PD%T$`(E`
-M-,=`.`````"#P#")1"0$BT((B00DZ/S___^!Q(P```!;7E]=PXD<).C\____
-MBU0D",:$)(0````(#[9"((B$)(@```"-A"2$````BU-0B40D!(M#7(D$)/]2
-M8.D+____C;8`````C;PG`````(/L'(E<)`R)="00B<:);"08B=6)?"04BT`@
-MB40D!(L&B00DZ/S___^%P(G##X3E`0``QD!D`X%]#$+_``")<"@/E,`/MOB%
-M_P^%E````(M5&#'`@'H*]`^4P(7`#X64````A?\/A!8!```/MD(2/`$/A(\!
-M```\`@^$:0$```^V0@^(0U,/MT((9HE#3`^W0@IFB4-.#[="#&:)0U`/MD(.
-MB$-2#[="!&:)0T@/MT(&9HE#2@^W0A!FB4-4B6LLQT-P@.@$`(D<).C\____
-MBUPD#(MT)!"+?"04BVPD&(/$',.+51@QP(!Z#_0/E,"%P`^$;/___XL&@\!0
-MB00DZ/S___^%P(G&#X0Y`0``A?\/A;L```"+11B#P!#'1"0(``(``(E$)`2)
-M-"3H_/___XU%,(!+902)<UC&0U/T9L=#5`$`B7,LQT-P\&H$`,=%+`````#'
-M13"0700`B6TTQT4X`````(E$)`2+10B)!"3H_/___^E-____C;0F``````^V
-M0@P\`71N/`)T3P^V0@J(0U,/MD(&9HE#3`^V0@=FB4-.#[9""&:)0U`/MD()
-MB$-2#[9"!&:)0T@/MD(%9HE#2@^V0@MFB4-4Z>W^__^0BT48@\`4Z4#___^`
-M2V4$C4(0B4-8ZZ6`2V4$C4(4B4-8Z8C^__^`2V4"BT4<@\`0B4-8ZX>`2V4"
-MBT4<@\`4B4-8Z6?^__^-13#'12S]____QT4PD%T$`(EM-,=%.`````")1"0$
-MBT4(B00DZ/S____IB/[__XU%,,=%+/_____'13"0700`B6TTQT4X`````(E$
-M)`2+10B)!"3H_/___XD<).C\____Z5'^__^-=@!3@^P(BUPD$(M#&(L`B00D
-MZ/S___^)VH/$"%OI8/W__U.#[`B+7"00BT,8BP")!"3H_/___XG:@\0(6^E`
-M_?__@^P<B6PD&(ML)"")7"0,B70D$(E\)!2+?1B+!XD$).C\____B<:+0"")
-M1"0$BP:)!"3H_/___X7`B<,/A(L```"):"R)<"C&0&0"#[9'!#P!=&T\`G1O
-M#[9'!XU+4(U7"(E4)`2)#"2)1"0(Z/S___\/MD<'B$-(BT<8B4-,#[9%%(/H
-M"(3`B$-)=`F+11R#P`B)0V#'0VR`6@0`QT-PP'`$`(MT)!")7"0@BWPD%(M<
-M)`R+;"08@\0<Z?S___^0@$ME`NN1@$ME!.N+C44PQT4L_?___\=%,)!=!`")
-M;33'13@`````B40D!(M%"(D$).C\____BUPD#(MT)!"+?"04BVPD&(/$',.-
-MM@````!64X/L9(M<)'"-3"0@BT,8BW,<BU`$BP#HHZC__X7`=##'0RS_____
-MC4,PQT,PD%T$`(E;-,=#.`````")1"0$BT,(B00DZ/S___^#Q&1;7L.+1"0@
-MB0:+1"0DB48$BT0D*(E&"(M$)"R)1@SKNHGV5U93@^P0BWPD((`]``````&+
-M7QB+=QS'1RP`````#X8<`0``NLX#``")V.C0I?__A<`/A(D```"ZWP,``(G8
-MZ+RE__^%P`^%UP```(L#B0:+0P2)1@2+0PB)1@B+0PR)1@R+0Q")1A"+0Q2)
-M1A2+0QB)1AB+0QS&1D0`QD9!`,9&0`*)1AP/MD-%B$9%#[8%`````(A&((U'
-M,,=',)!=!`")?S3'1S@`````B40D!(M'"(D$).C\____@\006UY?PXL#B0:+
-M0P2)1@2+0PB)1@B+0PR)1@R+0Q")1A"+0Q2)1A2+0QB)1AB+0QS&1D0`QD9!
-M`,9&0`&)1AP/MD-%B$9%BQ4`````@<*0`0``B=#!^!_!Z!T!T,'X`XA&(.ET
-M____NOP#``")V.C1I/__A<!T<<='+/_____I6/___Y"ZP0,``(G8Z+2D__^%
-MP`^%T/[__XL#B0:+0P2)1@2+0PB)1@B+0PR)1@R+0Q")1A"+0Q2)1A2+0QB)
-M1AB+0QS&1D0`QD9!`,9&0`*)1AP/MD-%B$9%#[8%`````(A&(.GS_O__BP.)
-M!HM#!(E&!(M#"(E&"(M##(E&#(M#$(E&$(M#%(E&%(M#&(E&&(M#',9&1`#&
-M1D$`QD9``8E&'`^V0T6(1D4/M@4`````B$8@Z:/^__^-M@````"-OP````!5
-M5XG'5E.![%P"``")5"0DB$PD(P^V0@_&1"0P`83`>`^`?P@&QD0D,``/A!@#
-M``"-1"10Q@``C90D4`(``(/``3G0=>^+7"0D#[:72`$```^V0PN(1S0/MD,.
-MB$<Q#[9+#K@!````T^!FB4<RB="#R`2(AT@!``#V0P\##X0G`@``B="#R`6(
-MAT@!``"+1P3'ATP!````````QX=0`0```````(!X!P`/A3@"``"+7"0DC8]4
-M`0``BU0D)`^V=S"+0Q"#PA"%]HF'5`$``(M"!(E!!(M""(E!"(M"#(E!#,=$
-M)"C_____QT0D+/____]^5#'MZPL/MG<P@\4!.>Y^18M<KTB+4Q@Y5"0LB7L,
-MBT,4<A!W!CE$)"AV"(E$)"B)5"0L@'L(!'7,@'PD(P"+<R1U<H!\)#``=78/
-MMG<P@\4!.>Y_NX!_"`</A,P!``"+;P2`?04`#X5E`0``#[9%!HM,)"R+7"0H
-M*<:)\HGPP?H?#Z_:#Z_.]V0D*`'9C101B4<4B5<8BU0D)`^V0@^#X!S!^`*(
-MAQT"``"!Q%P"``!;7E]=PX!\)#``#X22````C50D4,=$)!0!````B50D$,=$
-M)`P!````BT,PBU`(BT`$B30DB50D"(E$)`3H_/___X7`#X4,____@+PD3@(`
-M`*H/A'@!```QP(!\)%!2#X11`0``A<`/A.G^__^-1"10QT0D%`````")1"00
-MQT0D#`$```"+0S"+4`B+0`2)-"2)5"0(B40D!.C\____Z;/^___'1"1(````
-M`,=$)$P`````C40D4,=$)!0`````B40D$,=$)`P!````BT,PBU`(BT`$`T0D
-M2!-4)$R)-"2)1"0$B50D".C\____@T0D2`&+1"1(@U0D3`"#\`(+1"1,#X1/
-M_O__ZZK'ATP!``#_____QX=0`0``_____^GL_?__#[=/,HM$)"B+5"0L]]F)
-MRR'(P?L?(=J)1"0HB50D+.EW_O__@\H'@'\("HB72`$```^%M?W__P^V3S`Q
-MP#'2@^D!]L$@#Y3`#Y7"T^+3X(E'.(E7/.F2_?__@'\P``^$8?[__S')BT2/
-M2(M0&(M`%`%'%`^V1S`15QB#P0$YR'_EZ3_^___1Z(/@`8A$)##IVOS__X!\
-M)%%%#X6D_O__QD0D4$7&1"114NF=_O__@+PD3P(``%4/A7K^__^P`<:$)$X"
-M``!5QH0D3P(``*KI9?[__XUT)@"-O"<`````53'25U93@>R,````B[PDH```
-M`(M'&(MW'(L`Z)"@__^%P(G##X1O`0``,<"-="8`Q@0P`(/``8/X6'7TC6PD
-M%(GHQ@``C90DC````(/``3G0=>^+4P2);"0$BT,(B00D_U(<#[9$)"J-5@2(
-M1@,/MD0D*(@&#[9$)"F(1@&+1"10B48$BT0D5(E"!(M$)%B)0@B+1"1<B4(,
-MBT0D8(E"$(M$)&2)0A2+1"1HB4(8BT0D;(E"'(M$)'")0B"+1"0LC58HB48H
-MBT0D,(E"!(M$)#2)0@B+1"0XB4(,BT0D/(E"$(M$)$")0A2+1"1$B4(8BT0D
-M2(E"'(M$)$R)0B`/MD0D%(A&4`^V1"05B$91#[9$)!:(1E(/MD0D%XA&4XM#
-M#(E&3(![1`!U:0^V1"0KB$8"BQN%VW46ZRN-M@`````/MD0D*P!&`HL;A=MT
-M%XM3!(EL)`2+0PB)!"3_4AR`?"0G`'3;C4<PQT<PD%T$`(E_-,='.`````")
-M1"0$BT<(B00DZ/S___^!Q(P```!;7E]=PX!.`P3KD<='+/_____KPXVT)@``
-M``"-O"<`````53'25U93@>R,````B[PDH````(M'&(MW'(L`Z.">__^%P(G#
-M#X0Y`0``,<"-="8`Q@0P`(/``8/X3'7TC6PD%(GHQ@``C90DC````(/``3G0
-M=>^+4P2);"0$BT,(B00D_U(<#[9$)"J-5@2(1@,/MD0D*(@&#[9$)"F(1@&+
-M1"10B48$BT0D5(E"!(M$)%B)0@B+1"1<B4(,BT0D8(E"$(M$)&2)0A2+1"1H
-MB4(8BT0D;(E"'(M$)'")0B"+1"0LC58HB48HBT0D,(E"!(M$)#2)0@B+1"0X
-MB4(,BT0D/(E"$(M$)$")0A2+1"1$B4(8BT0D2(E"'(M$)$R)0B`/MD0D*XA&
-M`HL;A=MU$NLGB?8/MD0D*P!&`HL;A=MT%XM3!(EL)`2+0PB)!"3_4AR`?"0G
-M`'3;C4<PQT<PD%T$`(E_-,='.`````")1"0$BT<(B00DZ/S___^!Q(P```!;
-M7E]=P\='+/_____KR8UT)@"#[!R)="04B<:)7"00B7PD&(M8!(M0"(M#'(L[
-MB4(<@*-)`0``\\=#'/____^+0AR`HDD!``#SB40D!(M'!(D$).C\____BT,@
-MB3PDB40D!.C\____B5@HB7`LQD!D!,=`<`!L!`")!"3H_/___XM<)!"+="04
-MBWPD&(/$',.)]E.#[`B+7"00BT,8BP")!"3H_/___XD$).C\____C4,PQT,P
-MD%T$`(E;-,=#.`````")1"0$BT,(B00DZ/S___^#Q`A;PXUT)@"-O"<`````
-M4X/L"(M$)!"+0`2+&(D$).C\____BX,H`0``C5`PQT`PD%T$`(E`-,=`.```
-M``")5"0$BT`(B00DZ/S___^#Q`A;PXVV`````(V\)P````"#[!R+5"0@B5PD
-M$(ET)!2)?"08@WHL_8MZ)`^$\P```/:'20$```C&AQ<"````='2+0BR#^/T/
-MA+8"``"%P`^%MP(``(N'9`$``#'),?:+4%P/MUAD@>+__P\`.?$/@U,!``#'
-MA\0!``#@8@0`B;_(`0``QX?``0```````(V'P`$``(E$)`2+!XM`!(D$).C\
-M____BUPD$(MT)!2+?"08@\0<PP^VMT@!``#WQA`````/A(D```"+0BR#^/T/
-MA-@!``"%P`^%W0$``(M/!`^V1S"+GU`!```/MDD&*<B+CTP!``")PL'Z'P^O
-MV`^ORO>G3`$```'9C101.U<8#X+=`0``#X8I`@``N@,```#I<@$```^VAQ<"
-M```\`@^/_O[__X/``8B'%P(``,>'Q`$``(";!`")O\@!``#I/?____?&(```
-M``^%M````/?&0`````^$//____?&`0```(GV#X0G`@``BUHLA=L/A?P!``"+
-M3P0/MD<PBY]0`0``#[9)!BG(BX],`0``B<+!^A\/K]@/K\KWITP!```!V8T4
-M$3M7&'(A=P4[1Q1R&KH)````Z<\```!W#CG:C;8`````#X*=_O__]H=(`0``
-M4(UV``^$5?___XN'3`$``#'2)?__/P"#^@`/AS____^#^'\/AS;____I:?[_
-M_XVV`````(M2++@+````A=)U4(GRL`J$TGA(BT\$#[9',(N?4`$```^V208I
-MR(N/3`$``(G"P?H?#Z_8#Z_*]Z=,`0```=F-%!$[5Q@/@F$!``!W"3M'%`^"
-M5@$``+@,````@^9?B?*(ET@!``")?"0$B00DZ/S____VAT@!```(#X04_O__
-MN@$```")^(M<)!"+="04BWPD&(/$'.G5PO__@#T```````^%E````(/F[XGP
-MB(=(`0``B7PD!,<$)`@```#H_/___^G,_?__QT(L`````(E\)`3'!"0<````
-MZ/S___^0]H=)`0``"`^$V?[__^E2_?__@#T``````'7-BX=D`0``@*=)`0``
-M]XM`"("@20$``/>)?"0$QP0D%````.C\____BUPD$(MT)!2+?"08@\0<PSM'
-M%'*IZ<W]___'0BP`````B7PD!,<$)!P```#H_/___P^WAQ0"```QT@&'3`$`
-M`!&74`$``.E>_?__@^:_B?"(AT@!``")?"0$QP0D#P```.C\____Z0?]__^#
-MYK^)\HB72`$``(E\)`3'!"0.````Z/S____IY_S__XN'Z`$``(`X``^$"O[_
-M_X/FWXGPB(=(`0``Z;3^__^-="8`@^P4B70D"(MT)!R);"00BVPD&(E<)`2)
-M?"0,C88(`@``B8;D`0``C886`@``B8;H`0``BX98`@``]H9)`0``"(FNU`$`
-M`,>&X`$```````#'ANP!````````B;;P`0``QX;T`0``L)<$`(F&"`(``'16
-MQX;8`0``*O\``,>&W`$```0```"+AKP!```QTH/``8/X90^=PH/J`2'0B8:\
-M`0``C8;,`0``BUPD!(EL)!B+="0(B40D'(M\)`R+;"00@\04Z?S___\/MKY(
-M`0``]\=P````#X3-````B?B#X*`\H`^$Z````(M6!`^V1C")%"0/MDH&BYY0
-M`0``*<B+CDP!``")PL'Z'P^OV`^ORO>F3`$```'9C101.U88#X.=````]\<0
-M````N"/_``!U$(/G((GX/`$9P/?0!27_``"+EE`!``"+CN0!``")AM@!``"+
-MADP!``")40B+%"2)002`>@4`#X21````BY;D`0``#[=&,F:)0@SVAD@!```@
-MQX;<`0``#@````^$]O[__XN&Z`$``,8``,>&X`$```$```#IWO[__XM<)`2+
-M="0(BWPD#(ML)!"#Q!3#C70F`'<..T84#X)8____D(UT)@"-ALP!``#'AO@!
-M````````BUPD!(E$)!B+="0(BWPD#(ML)!"#Q!3I-/K__XM&%(M6&"N&3`$`
-M`!N64`$``(N.Y`$``(/Z`'8.N(````!FB4$,Z5+___\]@````';PB?;KYXVT
-M)@````"-O"<`````@^P,BT0D$(M`)(V0P`$``,>`Q`$``(";!`")@,@!``")
-M5"0$BP"+0`2)!"3H_/___X/$#,.-="8`C;PG`````(/L'(ET)!B+="0@B5PD
-M%(M>#(7;#X3N````#[:#20$``*@$='NH"'5GBY-D`0``A=)T78M"!(7`=%:+
-M2@B%R71/@(A)`0``"(M""("(20$```B-@\`!``#'@\0!``"`FP0`B9O(`0``
-MB40D!(L#BT`$B00DZ/S___^)7"0$QP0D$@```.C\____C;0F`````(M<)!2+
-M="08@\0<PXUT)@`/MI9(`0``]L(0=>2%VW0$J`AUW/;"8'77@^+W@\H0C8;`
-M`0``B)9(`0``QX;$`0``@)L$`(FVR`$``(E$)`2+!HM`!(D$).C\____B70D
-M!,<$)`0```#H_/___XM<)!2+="08@\0<PXGSZ0O___^055=64X/L#(ML)""+
-M11B+6`2+`(D$).C\____@_L.B<9V,L=%+/[___^-13#'13"0700`B6TTQT4X
-M`````(E$)`2+10B)!"3H_/___X/$#%M>7UW#_R2=C!@``)"-="8`B<:+1@R%
-MP'7W@'X(!8UV``^$"08``("F2`$``+^)="0$QP0D#@```.C\____BUX<A=L/
-MB&T&``"+3@RZ`0```.D$!```BT`,A<!T#?:`20$```P/A6G___]F]X9(`0``
-M<`P/A5K____VAAP"```!#X1-____@'X(!0^%.P8``(!^,``/A)`&```Q_Y"-
-M="8`ZP\/MD8P@\<!.?@/CG@&``"+7+Y(A=MTZ8!["`1VX_:#2`$``!!UVHM3
-M1(M#0(E4)`2)!"3H_/___XM3!`^V4@8YT`^-Z?[__P^V@T@!``#'@\0!``"`
-MFP0`B9O(`0``@^#W@\@0B(-(`0``C8/``0``B40D!(L#BT`$B00DZ/S___^)
-M7"0$QP0D!````.C\____Z6K___^`>`@%#X2=!```@*!(`0``YXE$)`3'!"0%
-M````Z/S___^+3@RZ`0```.GS`@``]H!(`0``$`^$7_[___:`'`(```$/A%+^
-M__^`H$@!``#EBU9$BT!`QX9,`0``_____\>&4`$``/____^)5CR)1CB)="0$
-MQP0D!@```.C\____BTX,@*9(`0``_H7)=$V`>3``=$<QVXM$F4B%P'0O]H`<
-M`@```70F@'@(!'8@#[:02`$```^V@4@!``"#X@&#X/X)T*@!B(%(`0``=0L/
-MMD$P@\,!.=A_OHM.#(M&0`M&1(/X`1G2@\("Z30"``"+0`R%P'0-]H!)`0``
-M#`^%F?W__V;WAD@!``!P#`^%BOW___:&'`(```$/A'W]__^`?@@%#X7R!```
-M@'XP``^$</W__\=$)`@`````ZQ.#1"0(`0^V1C`[1"0(#XY3_?__BT0D"(M\
-MADB%_W3A@'\(!';;]H=(`0``('72BTXXBUX\BT9`BU9$"<@)VHE4)`2)!"3H
-M_/___XM6!`^V4@8YT`^-!OW__XV'P`$``("/2`$``"#'ATP!````````QX=0
-M`0```````,>'Q`$``(";!`")O\@!``")1"0$BP>+0`2)!"3H_/___XE\)`3'
-M!"0)````Z/S____I4/___X"@2`$``-^)1"0$QP0D"@```.C\____Z9K\__^`
-MH$@!``#?Z8[\___V@!P"```!#X1Z_/__BT!`"T9$#X5N_/__#[>&2`$``&8E
-M<0QF@^@!#X59_/__@'X(!0^%4`0``(!^,`!T+3'_BUR^2(7;=!B`>P@$=A(/
-MMH-(`0``@^!!+`$/A'\$```/MD8P@\<!.?A_U8"F2`$``/?I%_S__X"@2`$`
-M`+3'@$P!``#_____QX!0`0``_____\=`.`````#'0#P`````B40D!,<$)!``
-M``#H_/___XM>#(7;#X1[`@``#[9+,(7)#XYQ`@``,=(Q]HM$DTB%P'0B]H`<
-M`@```709@'@(!'83]H!(`0```70*O@$```"0C70F`(/"`3G*=<^%]@^$-`(`
-M`(M+#(G>N@$```"#^@,/E<"$P`^$,P$``(7)#X0K`0``B<Z+20SI&0$``("@
-M2`$``-^)1"0$QP0D"P```.C\____Z43[__]F]X9(`0``<`B+@&0!```/A2C[
-M__^%P`^$(/O__X!X9P`/A1;[__^+4`2+0`CV@AP"```!#X0#^___]H`<`@``
-M`0^$]OK__X"B20$``.^`H$D!``#O@(I)`0``"("(20$```B-AL`!``#'AL0!
-M``"`FP0`B;;(`0``B40D!(L&BT`$B00DZ/S___^)="0$QP0D$@```.C\____
-MZ:7Z__^+B&0!```/MX!(`0``9B5P"&8]``@/A8/Z__^%R0^$>_K__XM!!(M1
-M"("@20$``/>`HDD!``#WB70D!,<$)!,```#H_/___XM.#+H!````Z='^__^+
-M2`RZ`P```#'`A,`/A<W^__^`CD@!```$@_H"#X3M````BX9D`0``A<`/A.T`
-M``"+4`2+6`B%TG0(B10DZ/S___^%VP^$!_K__XD<).C\____Z?KY__\QVX!X
-M,`!U&.E<^O__C70F``^V1C"#PP$YV`^.2?K__XM$GDB%P'3I@'@(!';C]H!(
-M`0``$'3:@*!(`0``YXE$)`3'!"0%````Z/S____KP8!^,``/A`3Z__\QVY"-
-M="8`ZP\/MD8P@\,!.=@/CNSY__^+1)Y(A<!TZ8!X"`1VX_:`2`$``$!TVH"@
-M2`$``+^)1"0$QP0D#@```.C\____Z\&)\X"C2`$``/Z)'"3H_/___^FX_?__
-MB30DZ/S___^0Z33Y__^)-"3H_/___XUV`.DD^?__B30DZ/S___^+3@RZ`0``
-M`.F/_?__BU9$BT9`B50D!(D$).C\____BU8$#[92!CG0#XWG^/__C8;``0``
-M@(Y(`0``$,>&Q`$``(";!`")ML@!``")1"0$BP:+0`2)!"3H_/___XET)`3'
-M!"0$````Z/S___^+1D"`ID@!``#W"T9$#X0,^?__Z/S___^+3@RZ`0```(E&
-M*.D(_?__BTXXBUX\BT9`BU9$"<@)VHE4)`2)!"3H_/___XM6!`^V4@8YT`^-
-M5OC__XV&P`$``(".2`$``"#'ADP!````````QX90`0```````,>&Q`$``(";
-M!`")ML@!``")1"0$BP:+0`2)!"3H_/___XET)`3'!"0)````Z/S____I!OC_
-M_XV&P`$``(".2`$``$#'ADP!````````QX90`0```````,>&Q`$``(";!`")
-MML@!``")1"0$BP:+0`2)!"3H_/___XET)`3'!"0-````Z/S____IC/O__P^V
-M@T@!``#'@TP!````````QX-0`0```````,>#Q`$``(";!`"#R$"#X/>(@T@!
-M``"-@\`!``")F\@!``")1"0$BP.+0`2)!"3H_/___XE<)`3'!"0-````Z/S_
-M___I'OO__XUV`%575E.#[!R)1"00]H`<`@```74D#[:`20$``(/@!#P!&?^!
-MYP#X__^!QP$(``"#Q!R)^%M>7UW#BTPD$`^VL4@!``#WQ@(````/A%4!``"+
-M1"00BTA`BUA$OP(```#WQ@$```!T!H'/`!```/?&$````'0#@\\$]\8@````
-M=`:!SP`!``"#YD!T!H'/``(``(G:"<H/A3L"``"+;"00#[:%'`(``*@$=`.#
-MSQ"H`G0#@\]`BT0D$/:`2`$```AT!H'/@````(M4)!`/MH))`0``J`1T!H'/
-M``@``*@(=`:!SP`$``"+3"00#[9),(7)B4PD&`^.T@```#'MZVV+<42+64")
-M\HG8]](C43SWT"-!.(G1"<%T`X//`O9$)!<!=`:!SP`0``#V1"07$'0#@\\$
-M]D0D%R!T!H'/``$``/9$)!=`=`:!SP`"``")\`G8=`.#SPCV1"07"'0&@<^`
-M````@\4!.6PD&'1ABT0D$(M,J$B%R73K]H$<`@```73B@'D(!';<#[:12`$`
-M`(A4)!>#X@(/A&3___^+64"+<43I<____XG/BTE`BU]$B<B)VO?0]](C5SPC
-M1S@Q_XG5"<4/A)C^___ICO[___?'`@```'06]\<`$```C;0F``````^$V@``
-M`(/G_8MT)!B%]@^.#0$``(M4)!"+6DB%VP^$*O[__S'M]H,<`@```0^$&_[_
-M_X!["`0/AI,````/MG,PA?9^6XM#2(7`#X3^_?__]H`<`@```0^$\?W__XM0
-M,(M"!`M""`^%XOW__S')ZRB+1(M(A<`/A-+]___V@!P"```!#X3%_?__BU`P
-MBT($"T((#X6V_?__@\$!.<YUT9"#Q0$Y;"08='F+3"00BURI2(7;#X25_?__
-M]H,<`@```0^$B/W__X!["`0/AVW___^+4S"+0@0+0@ATQ>EN_?__B?@E""``
-M`(/X"`^%&?___^D1____B0PD@\\(B5PD!.C\____BTPD$(M1!`^V4@8YT`^-
-MH_W__X'/`"```.F8_?__@<\```!`Z2']__^-=@!55U93@^P,BWPD((M'&(M?
-M"(LHB2PDZ/S___^+<PR#PPPYWHE$)`AU#>M/D(UT)@"+-CG>=$2-AMC]__^+
-M4`R%TG7MA>UU"?:`'`(```)U#SE$)`AT6?:`'`(```)TT8"@'`(``/V`>`@!
-M=#F)!"3H_/___XLV.=YUO(U',,=',)!=!`")?S3'1S@`````B40D!(M'"(D$
-M).C\____@\0,6UY?7<.)!"3H_/___^N!]H`<`@```@^%=/___X"('`(```+K
-MH8UT)@"-O"<`````@^Q,B7PD1(M\)%")7"0\B70D0(EL)$B+7QB+`X7`=4:+
-M1PCH>)?__\='+/S___^-1S#'1S"0700`B7\TQT<X`````(E$)`2+1PB)!"3H
-M_/___XM<)#R+="1`BWPD1(ML)$B#Q$S#B00DC6L$Z/S___^)QHM#!*@!=6>H
-M`@^%K@```*@$#X7^````J`B-="8`#X5*`0``J!`/A=8!``"H0`^%CP$``*@@
-M#X4B`@``]D9,$`^$=____XU$)!2+5E")1"0$BT9<B00D_U(\#[9$)"*(1DJ)
-M-"3H_/___^E.____QD0D-``/MD4$B$0D.(U$)#2+5E")1"0$BT9<B00D_U)@
-MA<")1RQU&0^V1DR)PH/(D(/*@(A63`^V502(1DR(5DN+0P2H`@^$5?___XUV
-M`,9$)#0$#[9%!<9$)#D`B$0D.(U$)#2+5E")1"0$BT9<B00D_U)@A<")1RQU
-M(`^V5DV#RA"(5DV`?04`#Y7`@^+?@$Y,$,'@!0G"B%9-BT4`J`0/A`+____&
-M1"0T!0^V10;&1"0Y`(A$)#B-1"0TBU90B40D!(M&7(D$)/]28(7`B4<L=2`/
-MME9-@\I`B%9-@'T&``^5P(/B?X!.3!#!X`<)PHA638M%`*@(#X2V_O__QD0D
-M-`,/MD4'B$0D.(U$)#2+5E")1"0$BT9<B00D_U)@A<")1RQU(`^V5DV#R@2(
-M5DV`?0<`#Y7`@^+W@$Y,$,'@`PG"B%9-BT4`J!`/A&O^___K/P^V10K'!"0`
-M#```B40D!.C\____QT<L``````^V1DZ`?0H`#Y7"@^#^"="`3DP0B$9.BT4`
-MJ"`/A#S^___K7,9$)#0"#[9%"(A$)#B-1"0TBU90B40D!(M&7(D$)/]28(7`
-MB4<L=1\/ME9-@\H!B%9-@'T(``^5P(/B_8!.3!`!P`G"B%9-BT4`J$`/A.#]
-M___I:O___Y"-="8`QD0D-`</MD4)B$0D.(U$)#2+5E")1"0$BT9<B00D_U)@
-MB4<L]D9,$`^$,?W__^FU_?__C;8`````C;PG`````(/L+(ET)""+="0PB5PD
-M'(E\)"2);"0HBUX8BP.%P'5&BT8(Z&B4___'1BS\____C48PQT8PD%T$`(EV
-M-,=&.`````")1"0$BT8(B00DZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPXD$
-M)(UK!.C\____]D,$`8G'=1?V1TP0=+")/"3H_/___^NFC;0F`````,9$)!0`
-M#[9%!(A$)!B-1"04BU=0B40D!(M'7(D$)/]28(7`B48L=<$/MD=,B<*#R)"#
-MRH"(5TP/ME4$B$=,B%=+ZZ:-M@````"-O"<`````@^P<B5PD#(M<)"")="00
-MB7PD%(EL)!B]`0```(M#&(L`B00DZ/S___^!>PP,_P``B<8/E,`/MDY,B<>)
-MR,#H`B'%B?@/MM`YU70:C02]`````(/A^PG!@\D0B$Y,B30DZ/S___^-0S#'
-M0S"0700`B5LTQT,X`````(E$)`2+0PB)!"3H_/___XM<)`R+="00BWPD%(ML
-M)!B#Q!S#C70F`%57B<=64X'L+`(``(E,)"2(5"0K@'@P``^$B0```(G(,>V#
-MZ`&)1"0@ZU*0C70F`(-\)"`!#X:%````@'LT`(MS)'4'@'PD*P!T#?:&'`(`
-M``$/A8,```")'"3H_/____9&3!!T#?:&'`(```$/A?(```"#Q0&)Z#A','8J
-MBURO2(7;=.X/MD,(/`1VHP^V5"0KB=B#Q0&+3"0DZ&#___^)Z#A','?6B3PD
-MZ/S___^!Q"P"``!;7E]=PXVV`````#P$B=X/A,D```"#?"0D`G6BB30DZ/S_
-M___KF(U$)"S'1"04`0```(E$)!#'1"0,`0```(M#,(M0"(M`!(DT)(E4)`B)
-M1"0$Z/S___^%P`^%1/___X"\)"H"``!5=%<QP(!\)"Q%='R%P`^$*?___XU$
-M)"S'1"04`````(E$)!#'1"0,`0```(M#,(M0"(M`!(DT)(E4)`B)1"0$Z/S_
-M___I\_[__XDT).C\____C78`Z?[^__^`O"0K`@``JG6?L`'&A"0J`@``JL:$
-M)"L"``!5ZXV+<R2)'"3H_/___^DG____@'PD+5(/A7G____&1"0L4L9$)"U%
-MZ7+___^-=@"#[!R)7"0,BUPD((ET)!")?"04B6PD&(M#&(M3"(MH!(L`B50D
-M"(D$).C\____B[!D`0``A?8/A(0```"+5@2%TG1=BXH@`@``A<ET1XM#',<`
-M_____\=#+/____^-0S#'0S"0700`B5LTQT,X`````(E$)`2+0PB)!"3H_/__
-M_XM<)`R+="00BWPD%(ML)!B#Q!S#BY)4`@``A=)UKXGVBU8(A=)T&8NZ(`(`
-M`(7_=9R+BE0"``"%R762D(UT)@#V@$@!``!P=80/MG@PA?]^)#')BU2(2(72
-M=!.`>@@$=@WV@D@!``!P#X5?____@\$!.?EUWH/E`P^4P87VB<]T4(M&!(7`
-M=`H/MM$QR>@N_?__BT8(A<!T#(GY#[;1,<GH&_W__XM&$(M6#(E"!(D0BT0D
-M"(ET)`2#Z(")!"3H_/___XM#',<``````.D,____#[;1,<GHY?S__^OFC78`
-M55=6B<Y3@>RL````B50D'(E$)"#H_/___XM6>(E4)#2)1"0LBT9TB40D,`^V
-M1@Z)PL#J!(32B%0D/W4,#[9."H3)B$PD/W1C#[96#8/@#XA&#H#Z0'<+@/H!
-M=Q:`?@P'=!"X_____X'$K````%M>7UW#A-)T/#';ZQV-M@````#V@!P"```!
-M=-D/ME8-@\,!#[;".=A^&XM$GGR)!"3H_/___X!X"`%TU^NWQD0D/P'KEH!^
-M#`AWJ@^V1@R-="8`_R2%R!@``,9$)#X,QD0D0`#'A"2,````#````(N$)(P`
-M``")!"3H_/___X7`B40D5`^$:____X!\)#\!QT0D6`````!V,`^V1@TQT@^V
-M3"0_9O?Q9H72#X5%____#[9$)$")!"3H_/___X7`B40D6`^$+/___XM4)#0+
-M5"0P#X68`P``@'PD/@</A"8$``#'1"0P_____S';QT0D-/____^`?@T`#X3>
-M!P``BT2>?(D$).C\____BU`L.50D-(M`*'(0=P8Y1"0P=@B)1"0PB50D-`^V
-M1@V#PP$YV'_-BU0D5`^V6@6$VW4:BT0D6(7`#X2U````BU0D6(!Z!0`/A*<`
-M```/MD8.NO____^)P8M$)##3XHG3P?L?(="+5"0TB40D,(E&="':BUPD5(E4
-M)#2)5GB`>P4`=#4/MD8-]G0D/XM,)#0/MM`/MD,&*<*+1"0PB=7!_1\/K\H/
-MK\4!P8M$)##WXHTL$8E&=(EN>(M$)%B%P'0TBU0D6(!Z!0!T*@^V2@8/MD0D
-M/XM>="G(BTYXB<+!^A\/K]H/K\CW9G0!V8T4$8E&=(E6>(M$)!R%P`^$@```
-M`(M,)!R`>0@$#X;=_?__BQF+1"0@B5PD)#G##X7+_?__]H$<`@```0^$OOW_
-M_XN!9`$``(7`#X6P_?__9O>!2`$``%`"#X6A_?__BU$8.U9XBT$4#X>2_?__
-M<@D[1G0/AX?]__^`9@_\BUPD'(!["`</A,T!``"`?@P'#X3;`0``,?^+A"2,
-M````BU0D((E$)`2)%"3H_/___X7`B40D7`^$1OW__X!\)#X'#X0/!0``#[96
-M#<>$))0`````````A-)U).EU`@``D(/"`8F4))0````/ME8-#[;".X0DE```
-M``^.5@(``(N,))0```"+1(Y\B00DZ/S___^)PS'`A?]U$XML)!R%[70+BT0D
-M'(G:Z'2$__^+5"0TB40D#(M$)#")'"2)5"0(B40D!.C\____BY0DE````(M,
-M)%R%P(E$D4AUA8N$))0```"%P'X>,=N+5"1<BT2:2(/#`8D$).C\____.YPD
-ME````'7DBTPD7(D,).C\____N/_____I;?S__\9$)#X'QD0D0`#'A"2,````
-M!P```.G(_/__@'X.!P^%1/S__\9$)#X*QD0D0`#'A"2,````"@```.FD_/__
-MQD0D/@G&1"1``,>$)(P````)````Z8K\___&1"0^",9$)$``QX0DC`````@`
-M``#I</S__X#Z`@^&N@0``,9$)#X%QD0D/P+&1"1`!L>$)(P````%````Z4C\
-M__^`?"0_`\9$)#X%QX0DC`````4````9VX/C_H/#"(A<)$#I(OS__X!^#`</
-MA+X'``"+7"0<@'LP`0^$)?[__[\!````Z1W^__^+3"14#[99!83;=#H/MD8-
-M]G0D/P^V408/ML`IT(G"P?H?B40D"(M$)#")5"0,BU0D-(D$)(E4)`3H_/__
-M_XE$)#")5"0TBU0D6(72#X1X_/__BU0D6(!Z!0`/A&K\__\/ME(&#[9$)#\I
-MT(M4)#2)1"0(B<&+1"0PP?D?B4PD#(E4)`2)!"3H_/___XE$)#")5"0TZ3'\
-M__\QVX!^#0!U&NF'"````49T#[9&#1%6>(/#`3G8#XZR`P``BT2>?(D$).C\
-M____BU`LBT`HB=$)P773Z:[Z__^+7"1<B%,PBU0D+(M$)%R)4"2)4"R`?"0_
-M`0^&2`8```^V3"1`,>T/MGPD/XF,))@```"+G"28````BT0D((E<)`2)!"3H
-M_/___X7`B<,/A)L%``"+3"1<C52I2#')A?]^$(L"@\($B42+2(/!`3G/=?`/
-MMD0D/XA#,(M4)%R+0B2)\HE#)#'`@WPD'``/E,")P8E$)"B)V.C_U?__B>J)
-MZ,'Z'XM,)%SW_P^V43")7(%(#[9$)#\!Z`'].-`/@G#___\/ML+V="0_/#^(
-M03!W(8M<)%P/ML"-2`&-5(-(@\$!C4'_QP(`````@\($/#]V[8M$)%R)\HM,
-M)"CHF]7__XM$)%P/ME`PA=)^3#'_BTPD7(M<N4B#QP&+3"14#[9!!HM,)%PI
-MPHG0P?@?B50D"(E$)`R+012+41B)!"2)5"0$Z/S___^)4QB)0Q2+7"1<#[93
-M,#GZ?[:+7"0<A=L/A%$&``"+5"0<BTPD7(M"+(E!+(E,)`2)%"3H_/___X3`
-M#X4;`@``BUPD'(M,)%P/MI,<`@``#[:!'`(``(/B!(/@^PG0B($<`@``#[:3
-M'`(``(/@_8/B`@G0B($<`@``#[9#-(A!-(M<)!R+4Q@[41B+0Q1W67(%.T$4
-M=U*+5"1<BT($@'@&`'4,BT)(BT`$@'@&`'0YBT0D'.B][/__B<>!YP(0```/
-MA9H!``"+3"0<BUPD7(M1&#M3&(M!%`^"@P$``'<).T,4#X)X`0``BT0D'("X
-M'0(```(/A``&``"+5"0<BTPD7(M<)""+0AR)01R+0QR)V8/!'#G(=0_I8`,`
-M`(L`.<@/A%8#``"-4/2+7"0<.5HH=>J+7"1<B5HHZ^&+?G2+;G@/ME8-B?D)
-MZ0^5P(72?@^$P,>$))0`````````=3;'A"24`````````(3`=`TYE"24````
-M#X1%^___#[:$))0```"+5"1<B$(PZ3']__^-M@````"+G"24````BT2>?(D$
-M).C\____BT@LBU`HB7PD8(EL)&0YS7(.=P0YUW8(B50D8(E,)&2+3"1DBU0D
-M8,=$)`P`````B00DB4PD"(E4)`3H_/___XN,))0```"+7"1<A<")1(M(#X3!
-M^O__*WPD8!ML)&2#A"24`````8G[#[96#0GK#Y7`.Y0DE`````^.0____X3`
-M#X1,____Z6'____&1"0^!L9$)$``QX0DC`````8```#ID_?__XM$)%0/ME@%
-MZ5#X__^_`0```(M$)""#Z(")!"3H_/___XG#,<#&!!@`@\`!@_AH=?3H_/__
-M_XM4)%R)4PB)`XM$)!R)0P2)'"3H_/___XM,)%R+002`>`8`#X5<`@``BT%(
-MBT`$@'@&``^%3`(``,9#9@.`>Q0`#X3+`P``@'MF`P^$S0,``(M,)%R+012+
-M41B`>V8"B4-<B5-@#X1I`P``BT0D'("X'0(```(/A%@#``"+5"0<@(I)`0``
-M!(M,)%R`B4D!```$@*%(`0``_8F99`$``(F:9`$``(M$)""-4PR+2!B)4!B#
-MP!2)0PR)$8M4)!R)2Q")%"3H_/___XM,)%R)#"3H_/___P^V1@^H`0^%C0``
-M`*@"='J`?"0_`0^&/0,``(M<)%B`>P8`#X0O`P``BT0D7(!X,`!T5S'VBU0D
-M7(M<LDB#Q@&-@\`!``"`BT@!```0QX/$`0``@)L$`(F;R`$``(E$)`2+`XM`
-M!(D$).C\____B5PD!,<$)`0```#H_/___XM,)%P/MD$P.?!_JXM4)%R+@E@"
-M``#I>O7__X!\)#\!#X8^`0``BT0D6(!X!@`/A#`!``"+5"1<@'HP`'17,?:+
-M3"1<BURQ2(/&`8V#P`$``("+2`$``$#'@\0!``"`FP0`B9O(`0``B40D!(L#
-MBT`$B00DZ/S___^)7"0$QP0D#0```.C\____BUPD7`^V0S`Y\'^KBT0D7("@
-M2`$``+_I9____XM$)!PQR3'2Z%SQ__^+5"1<BTPD((M"'(E$)`2+002)!"3H
-M_/___^FE_O__B>J)Z,'Z'_?_A<")QGX;BU0D7+D!````BT2:2#'2@\,!Z!?Q
-M__\Y\W7EBTPD7`^V03`YQ0^-!_C__XUTJ4B)ZXL&@\,!@\8$B00DZ/S___^+
-M5"1<#[9",#G8?^3IX/?__X7_N`(```!T!X![%``/E<"(0V;IH/W__S')BT0D
-M7(GR@WPD'``/E,'H']#__^G7^O__BU0D7(G0!<`!``"`BD@!``!`QX+$`0``
-M@)L$`(F2R`$``(E$)`2+`HM`!(D$).C\____BTPD7,<$)`T```")3"0$Z/S_
-M___I7/[__XM$)!R`>#``#X0T^/__@'X-``^$*OC__XM`2#'_A<!U-.FZ\___
-MBUPD'(/'`0^V0S`Y^`^.=0$```^V1@TY^`^.3P$``(M,)!R+1+E(A<`/A(OS
-M__^+6"2+1+Y\B00DZ/S___\YPW6^BTPD'`^V03`Z1@T/AV?S__\/MLB%R0^.
-M,`$``(M<)!PQ_XM#2(7`=2CI2O/__XM<)!R#QP$/MDLP.?D/C@L!``"+5"0<
-MBT2Z2(7`#X0G\___BU@DBT2^?(D$).C\____.<-TRND/\___BT0D'+E0;`0`
-MB=KH[9[__S'`Z?WR__^+3"1<B0PDZ/S____V1@\!#X5M_?__BUPD7(D<).C\
-M____Z</\__\QP#'2A?\/A3W\__^+3"0<BT$4BU$8Z2[\__^+7"1<B=@%P`$`
-M`("+2`$``!#'@\0!``"`FP0`B9O(`0``B40D!(L#BT`$B00DZ/S___^)7"0$
-MQP0D!````.C\____Z>K\__^+5"1<N>!H!`#H3I[__S'`Z5[R__^+3"14#[99
-M!>F0\___BU0D'`^V0@@\!P^$GO;__^FG]O__D(UT)@`/MD,(Z^B+7"0<BT9T
-MBU9XB<>)U2M[%!MK&(GK"?L/A-D```"+1"0<BTR(1(E,)'R+422)5"1XBUHD
-MA=MU#^DV`0``BQN%VP^$+`$``(M#%(7`=>^+3"1\BTDPBT$,BU$0B8PDB```
-M`(F$)(````")E"2$`````T$$$U$(BTL(,T,$,=$)P76[BU0D?(M"%(M2&(E$
-M)'"+0PR)5"1TBU,0.=4/AXH"``!R"#G'#X.``@``BX0D@````(N4)(0```"+
-MC"2(`````?@1ZHE!#(E1$(M,)'R)012)41@!>P01:P@I>PP9:Q"+7"1X@$M,
-M$(D<).C\____BT9TBU9XBTPD'(M<)!R)41B-5A")012+1A"!P50!``")@U0!
-M``"+0@2)002+0@B)00B+0@R)00R)'"3H_/___XM#'(E$)`2+`XM`!(D$).C\
-M____#[9&#X/@','X`H"['0(```*)P@^$*`(``(M,)!R+@5@"``"(D1T"``#I
-MOO#__\=$)'``````QT0D=`````"+5"0<B?D)Z0^5P`^V4C")E"2<````#[96
-M#3F4))P````/C;0```"$P`^$N0```(N<))P```#'A"20`````````(E<)!B+
-MG"20`````UPD&(M$GGR)!"3H_/___XM(+(M0*(E\)&B);"1L.<UR#G<$.==V
-M"(E4)&B)3"1LBTPD;(M4)&C'1"0,`````(D$)(E,)`B)5"0$Z/S___^+3"0<
-MA<")1)E(=&@K?"1HBU0D'!ML)&R)^8.$))P````!">F)4`P/ME8-#Y7`@X0D
-MD`````$[E"2<````?RR$P'0).90DG````'0HBT0D'`^VG"2<````B%@PBT9T
-MBU9XZ7+^__^0C70F`(3`=-WI-?___XM<)'0+7"1P=$N+5"0<#[9",(M$@D2)
-M!"3H_/___XM,)!R+5"1TBT0D<`^V63")5"0(BU0D>,=$)`P`````B40D!(/K
-M`8D4).C\____BTPD'(E$F4B+7"0<#[9#,#N$))P````/C2_O__^-7(-(,?:)
-MQXL#@\8!B00DZ/S___^-!#['`P````"#PP0[A"2<````?-[I`.___XN,)(@`
-M```IQQG5`X0D@````!.4)(0```")00R)41"+3"1\B4$4B5$8B5PD!(M<)'B)
-M'"3H_/___X!+3!")'"3H_/___XGH"?@/A0C^__^+1G2+5GCI<?W__SP"#X30
-M_?__B(,=`@``BT0D)+E@@@0`BY`H`0``B=CH<)K__S'`Z8#N__^)]HV\)P``
-M``!64X/L%(MT)""+7AB+`XD$).C\____C4L$B<*+1@CH[>W__X7`B<)T+8/X
-M_W0RBT8<QT8PD%T$`(EV-,=&.`````")$(U&,(E$)`2+1@B)!"3H_/___X/$
-M%%M>PXUT)@#'1BS_____Z\6-M"8`````55=64X'LK````(N\),````"-="00
-MB?"-5"0<BV\(BU\8Q@``@\`!.=!U]HU&#,<&?`$``(E<)`3'1"0(:````(D$
-M).C\____C5-HQT9T`````(U.?,=&>`````"+0VB)1GR+0@2)002+0@B)00B+
-M0@R)00R+0A")01"+0A2)012+0AB)01B+0APQTHE!'(GQB>B+7QSH!NW__XD#
-M@\`!=0?'1RS_____C4<PQT<PD%T$`(E_-,='.`````")1"0$BT<(B00DZ/S_
-M__^!Q*P```!;7E]=PXUV`(V\)P````!6,=)3@^P4BW0D((M.&(M&"(M>'.BG
-M[/__B0.#P`%U!\=&+/____^-1C#'1C"0700`B78TQT8X`````(E$)`2+1@B)
-M!"3H_/___X/$%%M>PU575E.#[`R+1"0@BRB+6"B+>"R+M2@!``")!"3H_/__
-M_XM#'(U-'(E''(M%'#G(=0CK&(L`.<AT$HU0]#E:*)!U\8L`B7HH.<AU[C')
-M,=*)V.CZZ/__BT<<B40D!(M%!(D$).C\____B3PDZ/S___^+AU@"``"+5AS'
-M1C"0700`B78TQT8X`````(D"C48PB40D!(M&"(D$).C\____@\0,6UY?7<.-
-M=@"-O"<`````55>)QU:)UE.![+P```"+6%BX_____X!_"`%T"X'$O````%M>
-M7UW#C:PDD````(M74(EL)`2+1UR)!"3_4CR-1"08BU,$B40D!(M#"(D$)/]2
-M'(V$)+````")!"2-C"2T````B=B-E"2X````Z)]L__\/MH0DG0```(A&`O:$
-M))H````"#X5\`0``#[:$)+0````"A"2<````B$8!BX0DN````(@&@'],``^)
-M9`$```^V1TN(1@,/MH0DHP```(A&!0^VE"28````#[9&!@^VG"29````P.H&
-MB=&#X/R#X0$)R`^VC"29````T.H!T@G0@^$!@^#SP>$"C12=``````G(@^((
-MB=D)T(/A$(/@SXG:@^(@"<@)T(G9@^%`@^`_B=H)R(/B@`G0B$8&#[9&!P^V
-ME"2?````@^#\@^(#"=#VPP2(1@</A-<```#&1@0"B>J)^.BW;O__BY0DJ```
-M`(72B48(="Z-1@R-7D*)5"0$QT0D")8```")!"3H_/___\=$)`0H````B1PD
-MZ/S____&0R<`]D=,074DBT<PBU<TB8:B````B9:F````BT<HBU<LB8:J````
-MB9:N````BU<DA=)T,S')ZPR-M@````"+$H72=".+0A2%P'07BT`,A<!T$(N`
-M6`(``(F$CKH```"#P0&#^0=^UX'$O````#'`6UY?7<,/MH0DL````.E__O__
-M#[:$)*(```"(1@/ID_[__X/C"(#[`1G`@^#^@\`#B$8$Z1?___^-M"8`````
-M55=64X/L#(M4)""+0AB+6AR+,(DT).C\____BQ.#Z@6)QW0.,<#&1!@%`(/`
-M`3G"=?2%]G1>A?]T6HM'%(M7&(E#$(M'#(E3%+K_____A<!T!HN06`(``(E3
-M&(M7'(G0P?@?"="(0P^+!XM`!(D$).C\____B$,.#[:''0(``(A##0^V1P@\
-M!'9&QD,,`8!_,$!V5(M$)"#'0"S_____BU0D((G0@\`PQT(PD%T$`(E2-,="
-M.`````")1"0$BT((B00DZ/S___^#Q`Q;7E]=PRP!=<#&0PP"C5,LB?CHWOS_
-M_X7`=:[KMXM'.(M7/(F#O````(GXB9/`````Z"]P__^-EU0!``"-2RR)@[``
-M``"+AU0!``")0RR+0@2)002+0@B)00B+0@R)00P/MD<(Z#QL__^(@Y`````/
-MMD<QB(.1````#[9'-(B#M````(N'3`$``(N74`$``(F#G````(GXB9.@````
-MZ(/<__^)@Y0```")/"3H_/___\:#D@````")@Y@```"`?S``#X0Q`0``,>V+
-M=*](A?8/A.4```"`NY,`````#X3H````@'X(!`^$]P```(N&6`(``(F$J\0`
-M```/MI.2````@\4!@\(!B).2````#[9',#GH#X^-````#[;2@_H_?QB-A)/$
-M````@\(!QP#_____@\`$@_H_?N^+AV0!``"%P`^$CO[__XM0!+G_____A=)T
-M!HN*6`(``(F+I````(M0"+G_____A=)T!HN*6`(``(F+J````(MP!(7V#X13
-M_O__BT@(A<D/A$C^__^)/"3H_/___XF#K````.DU_O__C;8`````@_T_#X]J
-M____BW2O2(7V#X4;____QX2KQ`````````#I+____P^V1@CHTFK__XB#DP``
-M`(!^"`0/A0G___^+1B2+@%@"``")A*O$````Z0'___\QTNDA____C;8`````
-M@>S,````B;PDQ````(G'@'\(`8FT),````")UHF<)+P```")K"3(````BUA8
-MN/____]T(XN<)+P```"+M"3`````B[PDQ````(NL),@```"!Q,P```##BT=<
-MC:PDD````(M74(EL)`2)!"3_4CR-1"08BU,$B40D!(M#"(D$)/]2'(V$)+``
-M``")!"2-C"2T````B=B-E"2X````Z%]G__\/MH0DG0```/:$))H````"B$8"
-M#X46`0``#[:$)+0````"A"2<````B$8!BX0DN````(@&@'],``^)%`$```^V
-M1TN(1@,/MI0DF`````^V1@8/MIPDF0```,#J!HG1@^#\@^$!"<@/MHPDF0``
-M`-#J`=()T(/A`8/@\\'A`HT4G0`````)R(/B"(G9"="#X1"#X,^)VH/B(`G(
-M"=")V8/A0(/@/XG:"<B#XH`)T`^VE"2?````B$8&#[9&!X/B`X/@_`G0]L,$
-MB$8'#[:$)*,```"(1@5T:,9&!`*)ZHGXZ'MI__^+E"2H````B48(,<"%T@^$
-MF_[__XU&#(U>0HE4)`3'1"0(E@```(D$).C\____QT0D!"@```")'"3H_/__
-M_S'`QD,G`.EF_O__B?8/MH0DL````.GE_O__C78`@^,(@/L!&<"#X/Z#P`.(
-M1@3KB0^VA"2B````B$8#Z>/^__^-M@````"-O"<`````55=64X/L#(ML)""+
-M?1B+!X7`=$0Q]NL/B1PD@\8!Z/S___\Y-W8QBT2W!(D$).C\____@'@(`8G#
-M=4CV0$P"=->)!"2#Q@'H_/___XD<).C\____.3=WSXU%,,=%,)!=!`");33'
-M13@`````B40D!(M%"(D$).C\____@\0,6UY?7</'12S^____Z\R-="8`@^P<
-MBT0D((E<)!2)="08BU@(BW`$B40D!(L#@^B`B00DZ/S___^)\#'),=+HO^#_
-M_X"+2`$```2+="08B5PD((M<)!2#Q!SI_/___XUT)@"#[!PQTHE<)!2+7"0@
-MB70D&(M#!(LP#[=#6(N.9`$#`,'@"8F>>`$#`,>&@`$#``````"-1`'_]_''
-MAG0!`P#0^P0`QX9\`0,``````(F&<`$#`(V&<`$#`(DT)(E$)`3H_/___XM<
-M)!2+="08@\0<P^L-D)"0D)"0D)"0D)"0D(/L/(M$)$")7"0LB70D,(E\)#2)
-M;"0XBT`8BP")!"3H_/___XN`9`$``(E$)!B`>!0`#X2+````B<*+0%R+4F")
-M1"0@BT0D&(E4)"2+5"0DBT@$BT0D((MY%(MI&#'X,>H)P@^$'P(``#EL)"0/
-M@V,!``"+5"0DBT0D(#'J,?@)P@^$%0(``(M,)!@Q]CMT)"0/MTED9HE,)!X/
-MM]D/@GT!``!W"CM<)"`/AG$!```/MT0D(#'V#[?89HE$)![I70$``(M$)!B+
-M2%R+6&"+0`2)VHMP%(MX&(G(,?`Q^@G"#X1Z`0``BT0D&`^V:&:)ZH32#X5(
-M`0``BT0D&#'2#[=`9&:)1"0>#[?``<@1VCG7=PX/@\H!``!F*<YFB70D'HM4
-M)!@/MT0D'F;'0EH``(E*4(E:5&:)0EB)ZH32="6`^@-T((M$)!B+7"0LBW0D
-M,(M\)#2)1"1`BVPD.(/$/.D<_O__BT0D&#'2B4@DB<''0#0`````B5@H#[=`
-M6`-!4!-15,=!0,#/!`")02R)R(/`.(E!.(E!/(/H%(E1,(E)1,=!2`````#'
-M04P!````B40D!(M!!(D$).C\____A<!T@HM<)"R+="0PBWPD-(ML)#B#Q#S#
-M=PHY?"0@#X:1_O__BU0D&(GX,?8/MU)D#[?:`=AFB50D'HGJ$?([5"0D<AX/
-MAN<````/MTPD(#'V9BGY9HE,)!X/M]F-M@````"+1"0@BU0D)"G8&?*)P8G3
-MBU0D&`^V:F;IX_[__XUV`(#Z`P^$K_[__XM4)!B+0@B+<!2+>!CIG?[__Y"-
-M="8`BT0D&`^V:&:)ZH#Z`P^$E````(GHA,!UT(M4)!B]`0```,9"9@'KP8M4
-M)!@/MD)F/`)T<2P!#X2#````BT0D&#'VBU0D((M,)"0/MT!DB70D#(D4)(E,
-M)`0/M]B)7"0(9HE$)![H_/___V:%P`^$3?___P^WV#'V9HE$)![I/O___SG&
-M#X,V_O__Z2G^__\[1"0@#X(G____C;0F`````.D#____B="+7"0LBW0D,(M\
-M)#2+;"0X@\0\Z3'#__^+1"08QD!F`(MY%(MI&.DW_?__C;0F`````(V\)P``
-M``"#[&R)5"0TBU0D=(E\)&2+?"1\B6PD:(G%BT0D<(E<)%R)5"0L#[=4)'B)
-M="1@BT\(,?:)1"0HBT0D*&:)5"0F#[?:BU0D+(E,)""+3"0T`=B)1"0X$?*)
-M5"0\.U$\#X-^````BU0D-(M,)""+0B")#"2)1"0$Z/S___^%P(E$)$0/A%P!
-M``"+1"1$QD!F`&:#?"0F`8EX+,=`<&#C!`#'0&P`````#X0[`@``@?T9_P``
-M#X2*````=W2!_0O_```/A#`!``#'1RS^____BT0D1(D$).C\____BU<(B50D
-M(.L)=C_'1RS^____BTPD((U',,=',)!=!`")?S3'1S@`````BUPD7(E$)'2+
-M="1@B4PD<(M\)&2+;"1H@\1LZ?S___\[03@/ACC____KMH'](_\```^$O```
-M`('])/\``'6$BT0D-/9`3@(/A50!``"+="1$QD9D`\9&4R2+?"1$#[9'98/@
-M^X/(`HA'98M$)$2`>&0##X2A`0``BTPD1`^V04@\$`^$1@(``#P*#X3Y`@``
-MBUPD((M,)#2+5"1$BT,DB4HHA<`/A%D#``"+="0@BU0D1(M\)$2+3B")\(/"
-M#(/`'(E6((E'#(E/$(D1BUPD7(MT)&"+?"1DBVPD:(/$;,.+7PC'1RS]____
-MB5PD(.GU_O__9H-\)"8!#X?$_O__BT0D-(MH)(7M=$^-=@"+50@Y5"0LBT4$
-M#X*W````=PHY1"0H#X*K`````T4,$U40.50D/`^'FP````^#BP```(M5%(72
-MB50D3'0/BTH,A<F)3"1(#X7H`@``BT0D-/9`3@(/A+@"``"+5"1$QD)D`HM<
-M)#R+3"0XB=DQVPG+#X2M`@``QD)0BL9"2!"+?"1$#[9'98/(!(/@_8A'9>G)
-M_O__BU0D1,9"9`*+7"0\BTPD.(G9,=L)RP^$``$``,9"4(C&0D@0Z8_^__\Y
-M1"0X#X9K____BVT`A>T/A2[____I=?___XM,)"R+5"0HQT0D%`$```");"0$
-MB4PD$(M,)#2)5"0,QP0D(`P``(E,)`CH_/___^F0_?__QT!8`````(M4)"R+
-M1"0H#ZS0$,'J$`^V5"0HB<$PP&:!X?\`"="+5"1$9HE"3(MT)"R+7"0H#ZSS
-M",'N"`^VPXGWB=X/K/X0B70D*`^W5"0HP>\0B7PD+(M\)$0PT@G09HE'3HM4
-M)"R+1"0H#ZS0"(E$)"@/MT0D*,'J"(E4)"S&1U)`9L='2```,,`)P6:)3U`/
-MMU0D)F:)5TIFB5=4Z=/]__^+7"1$QD-0*,9#2`KIB_W__\9!20`/MT0D)L'@
-M"8E!3(M4)"R+1"0HB=`QTL'H&(A!4HM4)"R+1"0HB=`QTL'H$(A!4XM4)"R+
-M1"0HB=`QTL'H"(A!5(M4)"R+1"0HB=`QTHA!58M4)"R+1"0H#ZS0&(A!5L'J
-M&(M$)"B+5"0L#ZS0$(A!5\'J$(M$)"B+5"0L#ZS0"(A!6`^V7"0HP>H(QD%:
-M`,9!6P"(65D/MT0D)F;!Z`B(05P/MD0D)L9!7@"(05W&05\`Z0?]__^+5"1$
-MQD))``^W1"0FP>`)B4),BU0D+(M$)"B+3"1$#ZS0&(A!4L'J&(M$)"B+5"0L
-M#ZS0$(A!4\'J$(M$)"B+5"0L#ZS0"(A!5`^V7"0HP>H(QD%6`(A950^W1"0F
-M9L'H"(A!5P^V1"0FQD%9`(A!6.F1_/__BU0D1(E4)'"+7"1<BW0D8(M\)&2+
-M;"1H@\1LZ?S___^+="1$QD9D`\9&4S3I6_W__XM<)$3&0U`JQD-("NE*_?__
-MBTPD2(M11(M!0(E4)`2)!"3H_/___XM,)$B+400X0@8/AO+\__^+50B+102)
-M5"14BU0D1(E$)%#&0F0!BT0D(`68````B00DZ/S___^%P(G!#X3C`0``BWPD
-M*"M\)%"+;"0L&VPD5`'[QT`0`````!'NB7`,BW0D2(EH!(E8"(M<)$3'0"``
-M````B3C'0!P`````QT`D`````(U`%(E!%(E!&(M&!,=!*`$```")2SR)<RB`
-M>`4`#X2,````QD-2`0^V3C$/K>_3[?;!('0$B>\Q[8E[2(EK3`^V3C"$R70R
-MBWPD3+@!````.WY(#X0[`0``,=+K%8M<)$@/ML*+="1,.W2#2`^$'P$``(/"
-M`3C*=>2+1"0@BT`DA<`/A)S^__^+7"0@BU0D1(MT)$2+2R")V(/"#(/`'(E3
-M((E&#(E.$(D1Z4+[__^+1"0@BTPD1(N09`$#`,9!4@&+1"0@B7E(B6E,!6`!
-M`P")050/MUPD)F:)65"+="1(#[9>,(3;="Z+?"1,N`$````[?D@/A(X````Q
-MP.L1BW0D2`^VR(M\)$P[?(Y(='*#P`$XV'7H#[=$)":)TXMT)""+?"1$P>`)
-MC40"_S'2]_/'AH`!`P``````QX9T`0,`<`(%`(F^>`$#`,>&?`$#``````")
-MAG`!`P")\(M<)%P%<`$#`(M\)&2)="1PBVPD:(E$)'2+="1@@\1LZ?S___^X
-M`0```-/@BTPD1(A!4^N%C4(!BWPD1(A'4^G9_O__QT<L_?___^E#^?__C;8`
-M````@^Q,B5PD/(M<)%R);"1(B=6+5"14B70D0(7MB7PD1(E$)"2+2PB+1"10
-MB50D'`^W5"18B4PD$(E$)!B+@60!`P!FB50D%HE$)"AT"?:%20$```1T/XM4
-M)!"-0S#'0RS^____QT,PD%T$`(E;-,=#.`````")1"14B50D4(M<)#R+="1`
-MBWPD1(ML)$B#Q$SI_/___XM%!`^V2`:$R72V#[=$)!8/MM$Q_XG&#[9%,`-T
-M)!@3?"0<*=")P<'Y'XE$)`B)3"0,BT44BU48B00DB50D!.C\____.=</AW7_
-M__]R"#G&#X=K____BT0D$`68````B40D+(D$).C\____A<")1"0P#X1!`0``
-MBT4@BU0D$(E$)`2)%"3H_/___X7`B40D-`^$#@$``(M,)#"+1"08BU0D,,=!
-M(`````")`8G(@\`4QT(0`````(M4)!R)012)01B+1"0TB7$(B5$$B7D,QT$<
-M`````,=!)`````#'02@!````B4@\B5@LQD!D`:$`````A<!^##N%O`$```^?
-MP`^VP(M4)#2)0C2+102`>`4`=#^+3"0D@>D+_P``@_D:#X:%`0``BT0D,(M4
-M)"R)1"0$B10DZ/S___^+3"0TB0PDZ/S___^+0PB)1"00Z7#^__\/MT0D%HM4
-M)"B+3"0DP>`)C40"_S'2]W0D*('I"_\``(/Y&HG&=FN+5"0PBTPD+(E4)`2)
-M#"3H_/___XM$)#2)!"3H_/___XM3"(E4)!#I'?[__XM,)#"+1"0LB4PD!(D$
-M).C\____C4,PQT,L_?___\=#,)!=!`")6S3'0S@`````B40D5(M#"(E$)%#I
-M!?[__[@!````T^"I`(``!`^%:@$``*D`0``"#X50`0``J0$```$/A&W___^+
-M3"0TQD%2`8M$)!"+3"0T!6`!`P")052+3"0TBT0D&(M4)!R):2B)04B)44P/
-MMUPD%L9!9@#'06P`````QT%P0.0$`&:)65"+1"00BU0D$(FP<`$#`,>`@`$#
-M``````#'@'0!`P!P`@4`B8AX`0,`QX!\`0,```````5P`0,`BUPD/(E$)%2+
-M="1`B50D4(M\)$2+;"1(@\1,Z?S___^X`0```-/@J0"```0/A;T```"I`$``
-M`@^%I0```*D!```!#X13_O__QD)2`0^V33&+5"0<BT0D&`^MT-/J]L$@=`2)
-MT#'2BTPD-(E!2(E13,9!9@"+7"00QT%L`````(EI*,=!<$#D!`"+0R2%P'1L
-MBU0D-(M<)!"#P@R+2R")V(E3((M<)#2#P!R)0PR)2Q")$8M<)#R+="1`BWPD
-M1(ML)$B#Q$S#BT0D-`'VQD!2`NFT_O__BUPD-,9#4@/II_[__XM,)#3&05("
-MZ5W___^+7"0TQD-2`^E0____BTPD-(M<)#R+="1`BWPD1(E,)%"+;"1(@\1,
-MZ?S___^-M@````"#["R)7"0<BUPD,(ET)"")?"0DB6PD*(M#&(MP!(MX"`^W
-M:`R+`(D$).C\____B<*+0PR)7"0,B6PD"(DT)(E\)`3H>?O__XM<)!R+="0@
-MBWPD)(ML)"B#Q"S#D(UT)@"#["R)7"0<BUPD,(ET)"")?"0DB6PD*(M#&(MP
-M!(MX"`^W:`R+`(D$).C\____@'@(`8G!=#"+0PP/M]6)5"0(B<J)7"0,B30D
-MB7PD!.@.^___BUPD'(MT)""+?"0DBVPD*(/$+,.+0PP/M]6)5"0(B<J)7"0,
-MB30DB7PD!.A.\___Z\Z-M@````"-OP````"#["R)7"0<BUPD,(ET)"")?"0D
-MB6PD*(M#&(MP!(MX"`^W:`R+`(D$).C\____@'@(`8G!=#"+0PP/M]6)5"0(
-MB<J)7"0,B30DB7PD!.A^^O__BUPD'(MT)""+?"0DBVPD*(/$+,.+0PP/M]6)
-M5"0(B<J)7"0,B30DB7PD!.B^\O__Z\Z-M@````"-OP````"#["R)7"0<BUPD
-M,(E\)"0Q_XET)"");"0HBT,8#[9H"(MP!(L`B00DZ/S___^)PHM##(E<)`R)
-M;"0(B30DB7PD!.CZ^?__BUPD'(MT)""+?"0DBVPD*(/$+,.-M@````"#[!R)
-M7"00BUPD((ET)!2)?"08BT,8BW@$#[9P"(L`B00DZ/S___^`>`@!B<%T,HM#
-M#(E<)`R)\P^VTXE4)`B)RHD\),=$)`0`````Z(_Y__^+7"00BW0D%(M\)!B#
-MQ!S#BT,,B5PD#(GS#[;3B50D"(G*B3PDQT0D!`````#HS?'__XM<)!"+="04
-MBWPD&(/$',.-M@````"-O"<`````@^P<B5PD$(M<)"")="04B7PD&(M#&(MX
-M!`^V<`B+`(D$).C\____@'@(`8G!=#*+0PR)7"0,B?,/MM.)5"0(B<J)/"3'
-M1"0$`````.CO^/__BUPD$(MT)!2+?"08@\0<PXM##(E<)`R)\P^VTXE4)`B)
-MRHD\),=$)`0`````Z"WQ__^+7"00BW0D%(M\)!B#Q!S#C;8`````C;PG````
-M`%6)U5=6B<93@^P,A=*)EF@!`P!T,8G#,?^-M"8`````C01_@\<!C82&9`$`
-M`(E$)`2)-"3H_/___XF#8`$``(/###GO==JA`````,>&;`$#`!(```"%P'0?
-MC;0F`````(M0"#F6;`$#`'8&B99L`0,`BT`$A<!UZ(/$#%M>7UW#5U:)QE.#
-M[!"+@&@!`P"%P'0XB?,Q_XN#9`$``(/'`8N3:`$``(E$)`B)5"0,BX-@`0``
-M@\,,B30DB40D!.C\____.;YH`0,`=\S'AF@!`P``````B30DZ/S___^#Q!!;
-M7E_#C;8`````C;PG`````%93@^P4BW0D((!^9`.+7BP/A(P````/MD9F/!`/
-MA(X````\!70@=QHL`8VV``````^$A````,=#+/____^-=@#K#CP+=7W'0RS]
-M____C78`BT8\A<!T$XE$)`2+!@68````B00DZ/S___^+!N@?____B30DZ/S_
-M__^-0S#'0S"0700`B5LTQT,X`````(E$)`2+0PB)!"3H_/___X/$%%M>P_9&
-M4P$/A&K____&1F80BT,<Q@`!QD9F`<=#+`````#KC3P-#X1[____QT,L____
-M_^EY____B?:-O"<`````5E.#[!2+="0@BUXLBT,,/23_``!T:CT9_P``=&.`
-M?F80=F_'0RS_____C;8`````BT8\B40D!(L&!9@```")!"3H_/___XL&Z&/^
-M__^)-"3H_/___XU#,,=#,)!=!`")6S3'0S@`````B40D!(M#"(D$).C\____
-M@\046U[#B?:`?F8,=#^+0QS&``"`?F80=Y$/ODYFN`$```#3X*D@*0$`=12H
-M`@^$=____\=#+`````#I>/___\=#+/W___^0Z6O___^+0QS&``&+1BC'!"01
-M````B40D!.C\____QD9F`>O(C;8`````C;\`````@^P<B5PD%(M<)"")="08
-MBT,8@WL0!XLP=@:#>Q0#=Q/'0RS^____BUPD%(MT)!B#Q!S#B30DZ/S___^%
-MP'3AB30DZ/S___^+$#M3"'0)QT,L_/___^O0BT@,A<EUPH!X"`1VO(M`'(/X
-M_W2[B40D!(M"!(D$).C\____A<!TJ,=#+/_____KGY"-M"8`````@^P<B5PD
-M$(G#B7PD&(G7B70D%(N`(`(``(7`=0J+LU0"``"%]G09,<"+7"00BW0D%(M\
-M)!B#Q!S#C;0F`````(M#'(/X_W05B40D!(L#BT`$B00DZ/S___^%P'7*@'L(
-M!'8X9O>#2`$``'`(=;F`>S``="`Q]HM$LTB%P'0+B?KH>____X3`=)X/MD,P
-M@\8!.?!_XK@!````ZXYT$8GZB=CH&E___P^VP.E[____BT,DB?KH"%___P^V
-MP.EI____@^P,@'@(!'87,<F#N&0!````=`R)R(/$#,.-M@````#H&____X/$
-M#`^VR(G(PXGV55=64X/L#(MT)""+3AB+5AR+`<<"`````(G%B<>!Y0`!``"!
-MY_\```!T;#';ZR*0BT@,A<EU6X!X"`49TO?2(<+HBO___X3`=$@Y^W1)BTX8
-M@\,!BP29B00DZ/S___^%[77-BU`,A=)U*&;W@$@!``!P"'4=BU`<@_K_=,V)
-M5"0$BP"+0`2)!"3H_/___X7`=+B+1AR)&(U&,,=&,)!=!`")=C3'1C@`````
-MB40D!(M&"(D$).C\____@\0,6UY?7<.-M"8`````C;PG`````%575E.#[`R+
-M="0@BT88BQ`QP/;&_P^4P`^V^HE$)`B+1APQVP^V;"0(QP``````D#G[<CR%
-M_W0E,=N-M@````"+1AB#PP&+!)B)!"3H_/___XD$).C\____.?MUXXM<)`B%
-MVW5LQT8L`````.LXB?:)Z(3`=+Z+1AB#PP&+!)B)!"3H_/___X!X"`49TO?2
-M(<+H:O[__X3`=9:+1AS'1BS_____B1B-1C#'1C"0700`B78TQT8X`````(E$
-M)`2+1@B)!"3H_/___X/$#%M>7UW#A?]TT8M&&(M`!(D$).C\____@\0,,=);
-M7E]=Z?]V___K#9"0D)"0D)"0D)"0D)"#[#R)="0TBW0D0(E<)#")?"0XBUXL
-MBWXH@7L,0O\```^$B@````^V1E.+4QR(0@H/MT9,B$(&#[=&3HA"!P^W1E"(
-M0@@/MD92B$()#[=&2(A"!`^W1DJ(0@4/MT94B$(+@'YF`0^$E0```,=#+/__
-M__^)-"3H_/___XU#,,=#,)!=!`")6S3'0S@`````B40D!(M#"(D$).C\____
-MBUPD,(MT)#2+?"0X@\0\PXUV``^V1E.+4QR(0@\/MT9,9HE""`^W1DYFB4(*
-M#[=&4&:)0@P/MD92B$(.#[=&2&:)0@0/MT9*9HE"!@^W1E1FB4(0@'YF`0^%
-M</___Y"-="8`BT,,QT,L`````#U"_P``=%,]&/\```^%5O___XM#&(!X"O(/
-MA4G___^-5"00BT=0B50D!(M77(D4)/]0/(M4)"B!P@`!```/M@*H!`^$(/__
-M_X/@^X@"B3PDZ/S____I#O___XM#&(!X#_(/A0'____KMHVV`````(V\)P``
-M``!55U93B<.#[`PQP)"-="8`Q@08`(/``8/X+'7TQP,L````Z)E+__^(0P2A
-M`````(LPA?8/E$,%H0````")!"3H_/___\'@##W___\!#X:)````QD,&!<9#
-M!PL/MD,+,>V_!0```,9#"`#&0PD!QD,*#X/@_H/("(A#"\9$)`L`ZQ6#_P7&
-M1!X<0'0X@\4!@\<!@_\-=#2)/"3H_/___X7`=.R)Z`^V\(GXZ,),__^#_P:(
-M1!X,=<K&1!X<`H!,)`M`Z\B`3"0+(.O!@'PD"V!T%X/$##'`6UY?7</&0P8'
-MQD,'!^ER____H0````"#N)0!`P`#=MN)Z@^VPL9$&`P2QD08'$"#Q`PQP%M>
-M7UW#D%.#[`B+7"00BT,<Z.#^__^%P'0'QT,L_____XU#,,=#,)!=!`")6S3'
-M0S@`````B40D!(M#"(D$).C\____@\0(6\.-M@````"-O"<`````55=64X'L
-MG````(NL)+````"+?0B)^.CU5___BX>0`0,`A<`/A84```"+=PC'AY`!`P`!
-M````A?8/A*4```"-5"0DBT8$B50D!(M6"(D4)/]0'`^V1"0T`8>0`0,`@'PD
-M-`!T,3';B70D#,=$)`B0[`0`B5PD!(DT).C\____A,!U!X.OD`$#``$/MD0D
-M-(/#`3G8?]&+-H7V=:.+AY`!`P"#Z`&%P(F'D`$#`'0_C44PQT4L_/___\=%
-M,)!=!`");33'13@`````B40D!(M%"(D$).C\____@<2<````6UY?7</'AY`!
-M`P``````C8=4`0``QX=4`0``@.P$`(F_6`$``,>'7`$```````")1"0$C4<D
-MB00DZ/S____KD(GVZ?S___^-="8`C;PG`````(/L'(E\)!2+?"0@B6PD&(M$
-M)"B)7"0,BVPD)(ET)!"+=PR#KI`!`P`!A<`/B+0```")1"0(B6PD!(D\).C\
-M____A<")PP^$K@```(`]``````!U+HE<)`3'!"0"````Z/S___^+AI`!`P"%
-MP'0TBUPD#(MT)!"+?"04BVPD&(/$',,/MD!,J`)URJ@!#X6$````]D-,!'6\
-M@$M,)(UT)@#KLHV&5`$``,>&5`$``(#L!`")ME@!``#'AEP!````````BUPD
-M#(E$)"2-1B2+?"04B40D((MT)!"+;"08@\0<Z?S___^-1Q");"0$B00DZ/S_
-M___I:____XM'!(DL)/]00(U'$(EL)`2)!"3H_/___^E.____B1PDZ/S___^)
-M]NEM____C70F`(V\)P````"#[!R)7"00BUPD((E\)!B)="04BT,8BW`$BP")
-M!"3H_/___XDT)(G'Z/S___^)/"2)1"0$Z/S____'0S"0700`B5LTQT,X````
-M`(/X`1G`]]")0RR-0S")1"0$BT,(B00DZ/S___^+7"00BW0D%(M\)!B#Q!S#
-MC78`C;PG`````%=64X/L$(`]``````"+?"0@=&V+7PR-=PPY\W4)ZS60BQLY
-M\W0NC9/8_?__@'H(`77N]H(<`@```73E#[8%`````(D4)(E$)`3H_/___XL;
-M.?-UTL>'S`````"'DP.-A\P```#'A]0`````````B;_8````B40D!(D\).C\
-M____@\006UY?PXGVC;PG`````%575E.![,P```"+M"3@````C7PD$(GXC50D
-M'(MN"(M.&,8``(/``3G0=?:-1PS'!WP!``")3"0$QT0D"+````")!"3H_/__
-M_S'2B?F)Z(M>'.A:Q/__B0.#P`%U!\=&+/____^-1C#'1C"0700`B78TQT8X
-M`````(E$)`2+1@B)!"3H_/___X'$S````%M>7UW#C;0F`````(V\)P````!6
-M,<!3@^P4BW0D((M>'(GVQ@08`(/``3V`````=?*)V.AK^O__A<!T,,=&+/__
-M__^-1C#'1C"0700`B78TQT8X`````(E$)`2+1@B)!"3H_/___X/$%%M>P\<#
-M@````#'2QT,\`"````^V1!H,@^`/@^@#/`)W!<9$&BP&@\(!@_H0=>3KJHUV
-M`(V\)P````!55U93@^P,BU0D((M"&(M:'(LP,<#&!!@`@\`!/?H```!U\HDT
-M).C\____B<4QP)#&!!@`@\`!/?H```!U\H7V=%V%[719BT44BU48B4,$BT4,
-MB5,(NO____^%P'0&BY!8`@``B5,,BU4<B=#!^!\)T(A#`XM%`(M`!(D$).C\
-M____B$,"#[:%'0(``(A#`0^V10@\!'=$+`$/A*\!``"+1"0@QT`L_____XM4
-M)"")T(/`,,=",)!=!`")4C3'0C@`````B40D!(M""(D$).C\____@\0,6UY?
-M7</&`P&+13AFB8/H````B>CH04K__XV55`$``(U+((F#Y````(N%5`$``(E#
-M((M"!(E!!(M""(E!"(M"#(E!#`^V10CH3D;__XB#A`````^V13&(@X4```"+
-MA4P!``"+E5`!``")@]````")Z(F3U````.B?MO__B8.(````B2PDZ/S____&
-M@X8`````B8/,````@'TP``^$3@$``#'_BW2]2(7V#X0"`0``@+N'``````^$
-M!0$``(!^"`0/A!0!``"+AE@"``")A+N,````#[:3A@```(/'`8/"`8B3A@``
-M``^V13`Y^`^/H0````^VTH/Z#W\8C823C````(/"`<<`_____X/`!(/Z#W[O
-MBX5D`0``A<`/A+7^__^+4`2Y_____X72=`:+BE@"``")B]@```"+4`BY____
-M_X72=`:+BE@"``")B]P```"+4`2%T@^$>O[__XM`"(7`#X1O_O__B2PDZ/S_
-M__^)@^````#I7/[__\8#`HU3((GHZ&75__^%P`^%//[__^E"_O__@_\/D(UT
-M)@`/CU'___^+=+U(A?:-="8`#X7^_O__QX2[C`````````#I$O___P^V1@CH
-MT43__XB#AP```(!^"`0/A>S^__^+1B2+@%@"``")A+N,````Z>3^__\QTND$
-M____D(UT)@!55U93@^P,BU0D((M"&(M:'(LP,<#&!!@`@\`!/=@```!U\HDT
-M).C\____B<<QP)#&!!@`@\`!/=@```!U\H7V=#6%_W0QBT<4BU<8B4,$BT<,
-MB5,(NO____^%P'0&BY!8`@``B5,,#[9'"#P$=T0L`0^$&`$``(M$)"#'0"S_
-M____BU0D((G0@\`PQT(PD%T$`(E2-,=".`````")1"0$BT((B00DZ/S___^#
-MQ`Q;7E]=P\8#`8N'5`$``(V75`$``(U+$(E#$(M"!(E!!(M""(E!"(M"#(E!
-M#`^V1PCHO4/__XA#=`^V1S&(0W6+ATP!``"+EU`!``")@\````")^(F3Q```
-M`.@4M/__B4-XB3PDZ/S____&0W8`B8.\````@'\P``^$I0```#'MZRV`?@@$
-M=$</ME-VBX98`@``B423?`^V0W:#P`$\#XA#=G=8#[9',(/%`3GH?DV+=*](
-MA?9T[8![=P!UQ0^V1@CH+4/__XA#=X!^"`1UN8M6)`^V0W:+DE@"``")5(-\
-MZ[3&`P*-4Q")^.ADV/__A<`/A=/^___IV?[__P^V4W:#^@\/C\S^__^-1)-\
-M@\(!QP#_____@\`$@_H/?N_ILO[__S'2Z^*-M@````"-OP````!55U93@^P,
-MBU0D((M"&(M:'(LP,<#&!!@`@\`!/:X```!U\HDT).C\____B<<QP)#&!!@`
-M@\`!/:X```!U\H7V="^%_W0KBT<4NO____^)0P2+1PR%P'0&BY!8`@``B5,(
-M#[9'"#P$=T0L`0^$#`$``(M$)"#'0"S_____BU0D((G0@\`PQT(PD%T$`(E2
-M-,=".`````")1"0$BT((B00DZ/S___^#Q`Q;7E]=P\8#`8N'5`$``(V75`$`
-M`(U+#(E##(M"!(E!!(M""(E!"(M"#(E!#`^V1PCHXT'__XA#<`^V1S&(0W&+
-MATP!``")@YP```")^.A&LO__B4-TB3PDZ/S____&0W(`B8.8````@'\P``^$
-MIP```#'MZRV`?@@$=$</ME-RBX98`@``B423>`^V0W*#P`$\!XA#<G=8#[9'
-M,(/%`3GH?DV+=*](A?9T[8![<P!UQ0^V1@CH7T'__XA#<X!^"`1UN8M6)`^V
-M0W*+DE@"``")5(-XZ[3&`P*-4PR)^.B6UO__A<`/A=_^___IY?[__P^V4W*#
-M^@>)]@^/UO[__XU$DWB#P@''`/____^#P`2#^@=^[^F\_O__,=+KXHVV````
-M`(V_`````%575E.#[#R+;"10BUT8BP.%P'5KBS4`````QD0D-`:%]G0QC7PD
-M-(M>"(7;="")]HM#"(E$)#B+0P2)?"0$QP0D`````/]08(L;A=MUXHLVA?9U
-MTXU%,,=%,)!=!`");33'13@`````B40D!(M%"(D$).C\____@\0\6UY?7<.)
-M!"2->P3H_/___XG&#[9#!(3`=3V`?@@!#X0_`0``QT4L_O____9&3!!TJ8U$
-M)!2+5E")1"0$BT9<B00D_U(\#[9$)"*(1DJ)-"3H_/___^N#+`%T$,=%+/[_
-M__^-="8`Z6____^`?@@$=K,/MD<!/`%T20^#W0$``(-]$!B-=@!UG(V.5`$`
-M`#'`Q@0(`(/``8/X$'7TBT<$C5<$B0&+0@2)002+0@B)00B+0@R)00R`CD@!
-M```$Z8<```"#?1!(#X58____C8YL`0``,<#&!`@`@\`!@_@$=?2+5P2-1P2)
-M$8M0!(E1!(M0"(E1"(M0#(E1#(M0$(E1$(M0%(E1%(M0&(E1&(M0'(E1'(M0
-M((E1((M0)(E1)(M0*(E1*(M0+(E1+(M0,(E1,(M0-(E1-(M0.(E1.(M`/(E!
-M/(".2`$```3VAD@!```$#X2$_O__B30DZ/S____I=_[__X!_`04/A[?^__\/
-MMD<!D(UT)@#_)(7L&```@WT0"9"-="8`#X68_O__QD0D-`D/MD<$B$0D.(U$
-M)#2+5E")1"0$BT9<B00D_U)@B44LZ7;^__^0@WT0"0^%9/[__\9$)#0%#[9'
-M!,9$)#D`B$0D.(U$)#2+5E")1"0$BT9<B00D_U)@B44L@$Y,$.DY_O__C70F
-M`(-]$`D/A23^___&1"0T!`^V1P3&1"0Y`(A$)#CKOHGV@WT0"0^%!/[__\9$
-M)#0##[9'!(A$)#CKHXVT)@````"#?1`)#X7D_?__QD0D-`+KWH-]$`D/A=/]
-M__^`3DR`QD0D-`#KR3P"=`S'12S^____Z=W^__^#?1`)#[:^'0(```^%I_W_
-M_XU#"(GZB40D"`^V0P@XPG0Z@'X(!(B&'0(``'8N@'XP`'0H,<F+5(Y(A=)T
-M$X!Z"`1V#0^VAAT"``"(@AT"```/MD8P@\$!.<A_VHGX/`)T#(".2`$```3I
-M;_[__XM4)`B`.@)TZ[E@@@0`B>J)\.CE9?__Z0?]__]55U93@^P,BVPD((M=
-M&(L#C7L$B00DZ/S___^)QHM#!*@!=#N-CE0!```QP(UT)@#&!`@`@\`!@_@0
-M=?2+1P2-5P2)`8M"!(E!!(M""(E!"(M"#(E!#(".2`$```2+!Z@"#X1^````
-MC8YL`0``,<"0Q@0(`(/``8/X0'7TBU<4C4<4B1&+4`2)402+4`B)40B+4`R)
-M40R+4!")41"+4!2)412+4!B)41B+4!R)41R+4"")42"+4"2)422+4"B)42B+
-M4"R)42R+4#")43"+4#2)432+4#B)43B+0#R)03R`CD@!```$]H9(`0``!'0(
-MB30DZ/S___^-13#'13"0700`B6TTQT4X`````(E$)`2+10B)!"3H_/___X/$
-M#%M>7UW#ZPV0D)"0D)"0D)"0D)"055=64X'LS````(NT).````"-7"00BWX8
-MBP>)!"3H_/___XU4)!R)Q8G8C;8`````Q@``@\`!.=!U]HU7!(U##,<#?`$`
-M`(E4)`3'1"0(L````(D$).C\____BT8(B>J)V>CZM___A<")PG0M@_C_=#.+
-M1AS'1C"0700`B78TQT8X`````(D0C48PB40D!(M&"(D$).C\____@<3,````
-M6UY?7</'1BS_____Z\2-=@!55U93@^P<BT0D,(E$)!2+0`2+,(N.*`$``(GP
-MBY9P`0,`B4PD&.AUYO__BVPD%(M%"(M-!(M0((M!(#G0<P*)T(E$)`2+`8D$
-M).C\____A<")QP^$B`$``(L5`````(72?A.+3"04BT$$.Y"\`0``#Y_`#[;0
-MQD=F`(ML)!2)5S0/MD5FA,`/A=8```"+1"04BU0D%(/`)(E'.(M"!(!/90*+
-MCF0!`P")1RB+;"04B<K!Z@D/MT5:#[==6"G#BX9L`0,`@^@!#Z_0.=-V`HG3
-M9H'[``%FB5]0=@9FQT=0``&+1"04@'@4``^$UP```/9'900/A,T```")P0^W
-M0%@QTHG-`T%0$U%4,=L/MT]0*<@/MTU:&=HQVRG(&=J)1TB)5TR`3V4(BTXD
-MBT0D&,='<$#^!`#'1VRP0P0`A<F)1RP/A`X!``"+3B"-5PR-1AR)5B")1PR)
-M3Q")$8/$'%M>7UW#/`,/A"+___^+3"04BT$(@$]E!(N>:`$#`(E'*(7;#X3>
-M````BXYD`0,`,>TQVXN&8`$#`(7)BP08=!6)PHG(Q@(`@\(!@^@!=?6+CF0!
-M`P"#Q0&#PPPYKF@!`P!WT.GE_O__BTPD%#'2#[=!6@-!4!-15(E'2(E73.E"
-M____BU0D%`^V0F:$P'5BBT0D%(M,)!2#P"2)1"0$BT$$B00DZ/S___^+;"04
-MBT4$BP#H"^7__XM$)!B+5"08QT`L_____\=`,)!=!`")0#3'0#@`````@\`P
-MB40D!(M""(D$).C\____@\0<6UY?7<,\`W6TZYB)?"0P@\0<6UY?7>G\____
-MBXYD`0,`Z3O^__^#["R)?"0DBWPD,(E<)!R)="0@B6PD*(M'+(M7*(LOB40D
-M%`^V1V:+LF0!```\`71#/`(/A`D!``"-1AC&1V8`QT88,`(%`(E^',=&(```
-M``")1"0$C44DB00DZ/S___^+7"0<BW0D((M\)"2+;"0H@\0LPP^W1EIF`T=0
-M.U8$9HE&6@^$MP(```^W1EIF.T98#X,Y`0``#[9'9<='/`````#'1S@`````
-M@^#]@\@$B$=EBU8(B5<HQD=F``^W1EH/MTY8BY5D`0,`*<&+A6P!`P#!Z@F#
-MZ`$/K]`YT78"B=%F@?D``6:)3U!V!F;'1U```8!^%`!T"O9'900/A5,"```/
-MMT9:,=(#1E`35E2)1TB)5TSV1V4"#X3;`0``BW4DA?8/A-`!``"+32"-5PR-
-M11R)52")1PR)3Q")$>D>____BT8$QD9G`8"@'`(``/Z+1@B`H!P"``#^BT8$
-M@*!)`0``]XM&"("@20$``/>+1@2+`.@XX___#[9&9H3`#X3D````/`,/A-P`
-M``")/"3H_/___XM4)!3'0BS_____B="#P##'0C"0700`B5(TQT(X`````(E$
-M)`2+0@B)!"3H_/___^F7_O__C;0F`````(NR9`$``(M&!(M6"(E$)!")5"08
-M#[9N9H!^%``/A(T```"+3EPQT@^W1EB+7F`IP8GH&=,L`8E.7(E>8`^$G`$`
-M`(GJ@/H"#X2N`0``BT9<"T9@#X6B````BU0D$(L"Z'SB__^)Z(3`#X19`0``
-M/`,/A%$!``")/"3H_/___XGPBUPD'(MT)""+?"0DBVPD*(/$+.GHE?__C48D
-MB40D!(M&!(D$).C\____Z0W___\/MT98,=N)ZHG!`TY<$UY@A-*)3ER)7F!U
-M?(M$)!"+4!@QVHE4)`B+4!2+1"0(,<H)T'4$QD9F`8M$)!B+4!@S2!0QV@G*
-M#X1>____BU0D$(L"Z-KA__^)Z(3`#X2@````/`,/A)@```")/"3H_/___XM4
-M)!3IIO[__XE\)#"+7"0<BW0D((M\)"2+;"0H@\0LZ?S___^)ZH#Z`W6;BT0D
-M$(M0&#':B50D"(M0%(M$)`@QR@G0=8'I[O[__Y"-="8`9CM&6`^";OW__V;'
-M1EH``.DT_?__#[=.6C'2#[=&6`-&4!-65#';*<@/MT]0&=HQVRG(&=J)1TB)
-M5TSIE/W__XU&)(E$)`2+1@2)!"3H_/___^E1____C48DB40D!(M&!(D$).C\
-M____Z9C^__^+1"00BU`8,T@4,=H)R@^%6_[__\9&9@#I4O[__XM$)!"+4!@S
-M2!0QV@G*#X4^_O__Z47^__^-M@````"-OP````!3BUPD"/9#90*+`\9#9@!T
-M'XM0)(72=!B+2""-4PR)4""#P!R)0PR)2Q")$5O#B?:)7"0(6^G\____C;8`
-M````4X/L"(M<)!"+`XN0<`$#`.CKW___BP.+2"2%R709BT@@C5,,B5`@@\`<
-MB4,,B4L0B1&#Q`A;PXE<)!"#Q`A;Z?S___^-M@````"-OP````"#["R+5"0P
-MB5PD'(ET)"")?"0DB6PD*(M:+(LKB[TH`0``BT<8BP")1"04BT(PB10DB40D
-M&.C\____@'L(!`^&C````(NS9`$``(7V#X3*````BT8$A<!T#+D"````,=+H
-M.ZW__XM&"(7`=`RY`@```#'2Z"BM__^+1A"+5@R)0@2)$(V%@````(ET)`2)
-M!"3H_/___XM<)!B#PP$[7"04=$.+1QB+5"08BT20"(D$).C\____B=J+="0@
-MBUPD'(M\)"2+;"0H@\0LZ>%;__^0B1PDZ/S___^+7"08@\,!.UPD%'6]C4<P
-MQT<PD%T$`(E_-,='.`````")1"0$BT<(B00DZ/S___^+7"0<BW0D((M\)"2+
-M;"0H@\0LP[D"````,=*)V.AVK/__Z6;___^0@^P<B5PD#(M<)"")="00B7PD
-M%(EL)!B+:P2+<PB+10")\HNX*`$``(GHZ`%!___'AF0!````````#[:5'`(`
-M`,>%9`$````````/MH8<`@``@^($@^#["="(AAP"```/MI4<`@``@^#]@^("
-M"="(AAP"```/MD4TB$8TC4<PQT<PD%T$`(E_-,='.`````")1"0$BT<(B00D
-MZ/S___^)="0$QP0D%0```.C\____BT,0BU,,QT,8H&@$`(E;',=#(`````"#
-MPQB)0@2)$(E<)`2+10")!"3H_/___XM<)`R+="00BWPD%(ML)!B#Q!S#58G5
-M5U93@^P,B00DBX!0`@``A<!T08M="(MU#(UT)@`Y<`1W*W($.1AS)8M(##M-
-M!(M0"'8-@\0,N`$```!;7E]=PW(+.U4`=^R-M@````"+0!"%P'7)BP0DB[@P
-M`@``!3`"``")1"0$.<=T18UV`(U/](!Y9`!U+HM92#'2#[=!4(MQ3`'8$?(Y
-M501W&7(%.44`<Q([=0QRG(VV`````'<%.UT(<H^+/SE\)`2-=@!UOHL4)(NZ
-M.`(``('".`(``(E4)`@YUW43ZUB0C70F`#R`=!.+/SM\)`AT1XU/]`^V062$
-MP'7IBUE(,=(/MT%0BW%,`=@1\CE5!'?8<@4Y10!ST3MU#`^"*O___XUT)@!W
-MPCM="`^"&____XL_.WPD"'6Y@\0,,<!;7E]=PXUV`(/L"(D<)(M<)`R)="0$
-MBW0D$(G8B?+HM?[__X7`=1R+@U`"``")1A`QP(FS4`(``(L<)(MT)`2#Q`C#
-MBU8<N/____^%TG3IBY-4`@``C8-4`@``A=)T"HU"$(M2$(72=?:),+C_____
-MZ\:-M@````"#[!");"0,BVPD%(D<)(M,)!B)="0$B7PD"(N%4`(``(V54`(`
-M`#G(=!"-M@````"-4!"+0!`YR'7VBUD4C7D4BT$0B[5,`@``.=^)`L=!$```
-M``!T%8M1&(L&B7,$B1Z)4`2)`HEY&(EY%(M%`,=`-`$```"+'"2+="0$BWPD
-M"(ML)`R#Q!##D(VT)@````"+5"0$BTPD"(L"A<!T"HM"!(E("(E*!,.)2@2)
-M"L.)]HM$)`2#P"R)1"0$Z?S___]3@^P(BUPD$(M30(72=!.+0T3'0T``````
-MB1PDB40D!/_2BT-PB5L8QT,<`````(E#%(U#%(E$)`2+`X/`+(D$).C\____
-M@\0(6\.0C70F`(/L'(E<)!2+7"0@B70D&(MS*(D<).C\____BT,0C4L,BU,,
-M@ZXD`@```8.N(`(```&)0@2)$(M#/(E+#(E+$(7`=`R)1"0$B30DZ/S___^+
-M7"04BW0D&(/$',.0C70F`%575E.#["R+="1`BWPD1(M.+(M&2(M63(M9:(E$
-M)!B)5"0<BT%(BU%,A=N)1"0@B50D)`^W=E`/A*,````/MD%E#[=4)$B#X`$/
-MML`YT`^$C````(M,)!@K3"0@BRO!X0DYZ8GH<POIH0```(UT)@")T(/#$(G"
-M`Q,YT7/SBRLIP0^W]L'F"8G(B<HQR0-3"!-+#"G%.>Z)5PB)3PR-3Q")+W8F
-MBT,8BU,<*S?'1P0`````B<^)00B+0Q"#PQ")40R)`8/!$#GP<MJ)-[@!````
-MQT<$`0```(/$+%M>7UW#BT%LA<!T'(M4)$B)?"0$B0PDB50D"/_0A<!T!XG[
-MZ5'___^#Q"PQP%M>7UW#,<#I:____XVV`````(V_`````%575E.#["R+="1`
-MBT8HB40D((!^9``/A;8```"+3"0@,=*+?D@/MT90BVY,BYE0`@```?@1ZH7;
-M#X0B`0``#[9.98/A0(3)=`J#>R@`#X0"`0``.5XX#X3Y````.U,$D`^"[P``
-M`'<..P.-M@`````/AM\````[:PR-M"8`````#X?/````#X/`````BTL8C58,
-MC4,4B5,8B48,B4X0B1&#Q"Q;7E]=PXM4)!R+3"0@BT((@ZD@`@```8E&*(.`
-M(`(```&)1"0@@'@(!`^'4P(``(M<)""+3"0@BY,P`@``@<$P`@``.<IU(XL&
-MB4X,QT`T`0```(U&#(E!!(F#,`(``(E.$(/$+%M>7UW#@WXT``^%Z@$``(M$
-M)""+F#0"``"->_2+1S2%P`^(PP(``(M4)""-1@R)3@R)`XF"-`(``(E>$(/$
-M+%M>7UW#.WL(#X(W____BUL0A=L/A>7^__^+3CB%R0^$#`(``(M,)""`>0@$
-M#X99____BUPD((N;9`$``(7;B5PD'`^$E@$``(![9P`/A8P!``#V1F4(#X6"
-M`0``@7YP``X%``^$=0$``(M,)"`[2P0/A6@!``"`>Q0`#X1%`@``BTM<BUM@
-MB4PD"#G=B5PD#`^'R_[__W((.<\/@\'^__\[5"0,D(UT)@!W%`^"+0$``#M$
-M)`B-="8`#X8?`0``BT8$@T`(`8D$).C\____BU0D'(E$)"2+!HM<)"2)`XM&
-M!(E#!(M&-(E#-(M"!(M,)"2)>4B):4R+7"0<B4$HB7$LQT%L\`<%``^W0US'
-M07``#@4`QD%F`,=!:`````!F*?AFB4%0#[9690^V066)TXG1@^.`@^`_@^%`
-M"=@)R(G3@^,P@^#'B=$)V(/A"`G(B=&#X02#X/F#X@()R`G0#[9698/@_H/B
-M`0G0BU0D)(A"98M&.(7`#X2V`0``B4(XBUPD'(U6#(M#!(N(/`(``(F0/`(`
-M``4X`@``B48,B1'&1F2`BT0D)(E.$(E$)$"#Q"Q;7E]=Z?S___\/CLL```"-
-M1@R)0@2)3A"+3"0@B58,B8$P`@``@\0L6UY?7</V1F4$#X2C_?__BU0D(/:"
-M20$``"`/A)+]__^`HDD!``#?Z/S___^+3"0@@(E(`0``!(E!*(L&QX"(`0,`
-M`0```(M!0`E!.(M!1`E!/.E;_?__]D9E0`^%ZOW__XM,)""+F50"``"%VW49
-MZ=?]__\[>P@/@N_\__^+6Q"%VP^$P_W__SM3!'+PC78`=P0[`W;G.VL,C;0F
-M`````'?;#X+$_/__D(VT)@````#KPHM<)""-1@R)3@R+DS0"``")@S0"``")
-M`HE6$.D3_?__BU,$C48,@T<T`8E#!(E>#(E6$(D"Z?G\__^+7"0<BTM<BUM@
-MB4PD$#G:B5PD%`^"@OS__W<(.<@/AGC\__\[;"04<A`/A^G^__\[?"00#X/?
-M_O__BT8$@T`(`8D$).C\____BU0D'(E$)"2+!HM<)"2)`XM&!(E#!(M&-(E#
-M-(M"".F[_?__BTPD),=!.`$```#I/?[__XVT)@````!3@^P(BUPD$(M#*(.`
-M(`(```&+0SR%P'0JQT`<`````(E8(,=`)`````")1"0$BT,HB00DZ/S___^%
-MP'43BT,\B4,XB5PD$(/$"%OI_/___X/$"%O#C70F`(V\)P````"#["R)="0@
-MBW0D,(E<)!R)?"0DB6PD*(M&*(M>+(E$)!B+N&0!```/MT90#[=K4&:)1"06
-M@'YF`71'#[9&9L9#9`"(0V:)="0$BT,$B00DZ/S___^+0P2#:`@!BT<$@X`D
-M`@```8MT)"")7"0PBWPD)(M<)!R+;"0H@\0LZ?S___^+5DR+2TR+1D@S0T@Q
-MT0G!=:>+1B"+5B2%P'0.C78`Q@(`@\(!@^@!=?6+1P0[1"08=#B)1BB+5V"+
-M1UR)5DR)1DAF*VPD%L9&9@!FB6Y0BUPD'(ET)#"+?"0DBW0D((ML)"B#Q"SI
-M_/___XM'".O#ZPV0D)"0D)"0D)"0D)"055=64X/L'(M$)#"+3"0P@\`,B40D
-M$(M$)#"#P1R)3"0,@\`LB40D"(M,)##'030`````ZQV+0@B%THM,)#")02QT
-M+8M"!,=""`````")!"3_$HM$)#"+4"P[4#!UUX72QT`P`````,=`+`````!U
-MTXM$)#"+3"00BT`,.<B)1"04#X0S`@``QT0D&`````"+="04@>XH`@``BX8@
-M`@``A<!U$(M$)!3VAAP"```@C7@(=`^+3"04QT0D&`$```"->0B-KC@"``"+
-MCC`"```Y^71_BQ&)RXM!!(/K#(E"!(D0B4D$B0ET:0^VEAP"``#VP@$/A#@!
-M``"+AB0"``"%P'0/BX9$`@``.T,T#X^&`0``@^(8#X5]`0``BT,TB6L,@X8D
-M`@```8F&1`(``(N&/`(``(F./`(``(D(B4,0BT8$B1PD_U`@BXXP`@``.?EU
-M@8V^2`(``(N.2`(``#GY=%F+$8G+BT$$@^L,B4($B1")202)"71#BT,\A<!T
-M*L=`'`````")6"#'0"0`````B40D!(M#*(D$).C\____A<!UM8M#/(E#.(D<
-M).C\____BXY(`@``.?EUIXN^5`(``(7_="B-OE0"``"-M@````"+'X7;=!:)
-MVHGPZ`'T__^%P'1]C7L0BQ^%VW7JBT0D%(M,)!"+`#G(B40D%`^%C?[__XM<
-M)!B%VP^$K````(M,)#"+42R%T@^%"_[__XM!-(7`#X4`_O__@\0<6UY?7</&
-M0V8"BX8\`@``@X8D`@```8F./`(``(EK#(E#$(D(B1PDZ/S____I;/[__XUT
-M)@"+0Q")!XN&4`(``(E#$(U#'(F>4`(``(E$)`2+1"0(B00DZ/S___^+3"0P
-MQT$T`0```.DY____BX8P`@``C5,,B5`$B7L0C;Y(`@``B4,,B98P`@``Z9W^
-M__^+1"0PBXB(`0,`A<ET'^MMBT((BTPD,(E!)(72=$V+0@3'0@@`````B00D
-M_Q*+3"0PBU$D.U$H==?'02@`````QT$D`````.O1BT$$BQ&)0@2)$(G(@^@,
-MB0F)200/A/'^__^)!"3H_/___XM$)#"+2!P[3"0,=='IU_[__\>`B`$#````
-M``")!"3H_/___^N<D(UT)@"#[`R)7"0$BUPD$(ET)`B+,XM&)(7`="B+3B"-
-M4PR-1AR)5B")0PR)2Q")$8ET)!"+7"0$BW0D"(/$#.G\____B1PDZ/S____K
-MXI"0D)"0D%4Q[5=64XM\)!B+="04B?@)\'0?B?&)^X/%`8/!_X/3_XGPB?HA
-MR"':B<:)T(G7"?!UX8GH6UY?7<.-M@````!55U93@^P,BW0D((M&#(E$)`B+
-M7CR+3CB)V`G(=0WVAD@!```"#X7:````,?^+1D"+5D0)R`G:B50D!(D$).C\
-M____BU8$#[92!@'X.=!^7("F'`(``/[VAAP"```!=$2+1"0(A<!T/(M<)`@/
-MME,PA-)T,(M$)`BY_O___[O_____.7!(=&TQP.L2D(UT)@"+7"0(#[;(.72+
-M2'0^@\`!.-!U[(/$#%M>7UW#BVX\BWXX@(X<`@```8GI"?ETF(M>1(M.0#'K
-M,?F)V`G(=4R`ID@!``#]Z7S___\QP#'2]L$@#Y3`#Y7"T^+3X(G3B<'WT_?1
-MBT0D""%(0(G&(5A$Z0;___^+1@2`>`<!#X49____#[9X!ND2____B=J)R"'J
-M(?B)T0G!#X0J____@(Y(`0```ND>____C;0F`````%93BT@,B<,/MG$PB?"$
-MP'0A,<`QTCE92'4/ZQN-="8`#[;".5R!2'0.@\(!B?`XPG7NN/\```!;7L.-
-MM@````!75HG&4XMZ)(7_=$.+1Q2%P'0VBT`,A<!T+SGP=#4/ME`PA=)^[3';
-MBTR82(7)=`J`>0@$=@0Y\709@\,!.=J0?^:+0`R%P'71BS^%_W6],<#K!;@!
-M````6UY?PXUT)@!75E.#[!R+7"0LBW0D,(M\)#2`>P@$=GS'1"08`````,=$
-M)!0!````#[9+,(7)?A^+4T@QP(72=`_K=)"-="8`BU2#2(72=6>#P`$YR'7Q
-MBU,$@'H%`'0A#[9#,`^V4@8IT`^O1"04B40D%`^W0S([1"08=@2)1"08A?9T
-M!HM$)!B)!H7_=`:+1"04B0>#Q!Q;7E_#A?9T!L<&`````(7_=.O'!P$```"#
-MQ!Q;7E_#C40D%(E$)`B-1"08B10DB40D!.C\____BU,$@'H%`'2IZX:-M"8`
-M````C;PG`````%.#[!R+7"0DC40D%(E$)`B-1"08B40D!(M#!(D$).C\____
-MC40D#(E$)`B-1"00B40D!(M#"(D$).C\____BTPD%#M,)`P/ET,4BU0D&(M$
-M)!`YT',"B=`/K\%FA<!FB4-D=09FQT-D@`"#Q!Q;PY"#[!B);"04BVPD'(M4
-M)"")7"0(B70D#(E\)!`/MD4(.D((=!RX`0```(M<)`B+="0,BWPD$(ML)!2#
-MQ!C#C78`#[=%,&8[0C!UVH!],``/A+,```"+34B+4DB%R73&,?^%TG3`@'D(
-M!'8]@'H(!(GV=K*)5"0$B0PDZ/S___^$P'6B#[9%,(/'`3GX?GJ+3+U(BT0D
-M((7)BU2X2'2'A=)T@X!Y"`1WPX!Z"`20C70F``^';O___XM!)#M")`^%8O__
-M_XMQ,(M:,(M6"(M+"(M&!#-#!#'1"<$/A4;___^+5A`[4Q"+1@P/AS?___]R
-M"3M##`^'+/____:%2`$```.0=(#I'?___S'`Z1O___^)]E.#[`B+5"00BUH$
-MBT((A=MT+H7`=&[V@QP"```!=36`H!P"``#^@*,<`@``_L=#'/_____&0F<!
-M@\0(6\.-=@"%P'3P@*`<`@``_L9"9P&#Q`A;P_:`'`(```%TPL9"9P"`BTD!
-M```$@(A)`0``!(D4).C\____B5PD$(/$"%OI_/___X"C'`(``/[&0F<!@\0(
-M6\.-M@````"-OP````!55U93@^PLBUPD0(M$)$2)1"00#[93,(72#XZ_`0``
-MQT0D%`````#II0```(UT)@"%P(E=#'0'QT`,`````(M$)!3'@TP!````````
-MQX-0`0```````(EL@T@/MI-(`0``B="#R`JH((B#2`$``'0)@\J*B)-(`0``
-M#[9,)!0QP#'2]L$@#Y3`#Y7"T^+3X`E3//?2"4,X]]`A4T0A0T"+3"00A<D/
-MA$0!``"`BT@!```$BU0D$(72#X4@`0``@T0D%`$/ME,P.U0D%`^.#0$``(M,
-M)!2+1(M(A<!T"?:`'`(```%UV(ML)!"%[0^%/O___XM#!`^V0`8IPHG0P?@?
-MB50D"(E$)`R+0Q2+4QB)!"2)5"0$Z/S___^)1"0@BP.)5"0DBW`,@\`,.<9T
-MD,=$)!C_____QT0D'/_____K"XL#BS:#P`PY\'19C;[8_?__]H<<`@```73F
-M@'\(`77@]D=,!'3:B?J)V.@Q^___A,!US8M7+#E4)"2+1RAWP9!R!CE$)"!W
-MN#M4)!R-="8`=ZX/@[,```")_8E$)!B)5"0<ZYR%[0^$$O____:#20$```)T
-M7XM%)(7`=!6-="8`BW`4A?8/A?/^__^+`(7`=>^+3"04BT2+2.E2_O__]H-(
-M`0``"'4=@\0L6UY?7<.);"0$QP0D!P```.C\____Z:?^__^)7"1`@\0L6UY?
-M7>G\____BU0D((M,)"2)+"3'1"0,`````(E4)`2)3"0(Z/S___^%P(G%#X2`
-M_O__BU0D%(M$DTCIY?W__SM$)!@/@^O^___I/O___XVV`````%575E.![!P"
-M``"+M"0P`@``@'X(!'8'@*9(`0``^_:&'`(```%T5H!^"`1V6X!^,`!T2C';
-MBTR>2(7)=#4/MI8<`@``#[:!'`(``(/B`H/@_0G0B($<`@``BU2>2(!Z"`1V
-M!P^V1C2(0C2)%"3H_/___P^V1C"#PP$YV'^X@<0<`@``6UY?7<.+1B2)1"08
-M]H`<`@```0^$1`,``(MN##'_A>UT"XM]#(7_#X1H`P``C5PD'(G8Q@``C90D
-M'`(``(/``3G0=>^%_\<#]!9X6@^$+`,``(M')(E#!(M'+(F#Q@```/:&'`(`
-M``)T!(!+%@&%_P^$%@,``(/]`1G`@\`"B$,8BX]D`0``A<ET-HL!BU%@B4,(
-MBT%<B5,0#[93%HE##`^V012#XOV#X`$!P`G"B%,6.7D(#X3M`@``#[9!9HA#
-M%`^V1S2%[8B#Q0````^VAQT"``"(0Q>+1Q2+5QB)0QF)4QT/MD<(B$,A#[9'
-M,(A#(HGH#X2G`@``Z'_X__\/ME,E@^+[B$,C#[9',8A#)`^VAT@!``"#X`'!
-MX`()PHA3)?:'2`$```)T!H/*`8A3)8M'.(U+28M7/(F#K0```(F3L0```(M'
-M.&:)0R>+ATP!``"+EU`!``")0RF)4RV+1RB-EU0!``")@[T```"+AU0!``")
-M0TF+0@2)002+0@B)00B+0@R-EZP!``")00R+AV@!``"-BYT```")0UF+AZP!
-M``")@YT```"+0@2)002+0@B)00B+0@R)00R+EVP!``"-AVP!``"-2UV)4UV+
-M4`2)402+4`B)40B+4`R)40R+4!")41"+4!2)412+4!B)41B+4!R)41R+4"")
-M42"+4"2)422+4"B)42B+4"R)42R+4#")43"+4#2)432+4#B)43B+0#R)03R%
-M[0^$AP```(M%%(M5&(E#,8E3-0^V10B(0SD/MD4PB$,ZB?#H+??__P^V4SV#
-MXON(0SL/MD4QB$,\#[:%2`$``(/@`<'@`@G"B%,]]H5(`0```G0&@\H!B%,]
-MBT4XBU4\B8.U````B9.Y````BT4X9HE#/XN%3`$``(N54`$``(E#08E318M%
-M*(F#P0```(D<).C\____B1PDQT0D!``"``#H_/___XE<)!#'1"04`````,=$
-M)`P!````]]B(1"0QBT8HBU8LB40D!(E4)`B+1B2)!"3H_/___XM,)!B+03B+
-M43R)7"00QT0D%`````#'1"0,`0```(G!`TXHB=,37BR!P0#X__^#T_\%``#^
-M_X/2_R4``/[_*<$9TXE,)`2)7"0(BT8DB00DZ/S___^+=B2)="08BT0D&/9`
-M3!`/A(_\__^)!"3H_/___X'$'`(``%M>7UW#,<#'0P0`````Z<_\___&0Q@`
-MZ9+^__^)Z#'MB<?IC?S__XGPZ5+]__^#R@2(4Q;I"/W__XUT)@"-O"<`````
-M5E.#[`2+1"00BU@,C7`,.?-U".LYBQLY\W0SC9/8_?__@'H(!';N]H)(`0``
-M!'3EBT(,A<!T"8G"BT(,A<!U]XD4).C\____BQLY\W7-@\0$6U[#C;8`````
-MC;\`````5U93@^P0BUPD(.L&C70F`(G#BT,,A<!U]^C\____B[MD`0``A?^)
-M0R1T*HMW!#G>=$CH_/___X7VB0=T&(UV`.C\____B48D.T,D=/.)-"3H_/__
-M_XD<).C\____BT,$BT@\A<ET#(E<)""#Q!!;7E__X8/$$%M>7\.+=PCKLY"#
-M["R)="0@BW0D,(E<)!R)?"0DB6PD*`^V1@B#Z`4\!0^'Z@````^VP/\DA009
-M```/MT8R,=+WV(/2`/?:(89,`0``(990`0``]H8<`@```0^%Q@$``(M^0(MN
-M1(GH"?AU"(M&.`M&/'16@'X("@^$T@$``("F2`$``/Z)Z@GZ=#^+1D"`CDD!
-M```@"T9$=##VAAP"```!='>+?@R%_W0)]H<<`@```70CQT0D!`````")-"3H
-M_/___XVT)@````#VAAP"```!=$>+?@SVADD!```$=3[VAD@!```#=#6+1CB+
-M5CR)1"00B50D%`G"#X5_`0``A?]T"?:''`(```%T&H".2`$```B)-"3H_/__
-M_XM^#(7_#X38````BUPD'(MT)""+?"0DBVPD*(/$+,,Q_S'M@'XP`'42Z]60
-MC70F``^V1C"#QP$Y^'Y$BUR^2(7;=.V`>P@$=N>)'"3H_/____:#2`$```1T
-M!X".2`$```0/MH-(`0``@^`#/`)UP0^V1C"#QP&]`0```#GX?[R%[0^$>?__
-M_X"F2`$``/XQVX7`?QOI9____XVT)@`````/MD8P@\,!.=@/CE'___^+5)Y(
-MA=)TZ8!Z"`1VX_:"2`$```%TV@^V@D@!``"#X+Z#R`*(@D@!``")%"3H_/__
-M_^N]]H9(`0``!`^$&____XET)#"+7"0<BW0D((M\)"2+;"0H@\0LZ?S___^+
-M;D2+?D")ZHGX]](C5CSWT"-&.(G1"<$/A"+^__^`CD@!```"Z1;^__\/MDXP
-M,<`QTH/I`?;!(`^4P`^5PM/BT^"+3CPS1C@QT0G!#X4&_O__Z0C^__^+7D2+
-M1D")V8G"]]$C3"04]](C5"00B<@)T`^$@/[__^E<_O__D(VT)@````"#["R)
-M?"0HBWPD,(M4)#2)7"0@B70D)(GXZ&+R__^$P'5>BT<4BU<8B40D&(M'!(E4
-M)!P/MD\P]H=)`0```@^V4`9T43'`]H=(`0``!'41BUPD((MT)"2+?"0H@\0L
-MPY")/"3H_/___XM<)"`QP(MT)"2+?"0H@\0LPXVV`````(M<)""X_____XMT
-M)"2+?"0H@\0LPP^VP0^VTBG0B<+!^A_'1"0,`````(MT)`R)1"0(BT0D&(E4
-M)`R+5"0<B00DB50D!.C\____B70D#(E4)`B+5"0TB40D!(D4).C\____A<!T
-MFHE$)`2)/"3H_/___^E-____B?:-O"<`````55>)UU93C11)@^P,C2S7B4PD
-M"`^V52&)!"2)5"0$Z/S___^%P(G&#X1T`0``@*`<`@``_@^V1Q>(AAT"``"+
-M1P2)1B2+A\8```"%P(E&+'4&BT<$B48L#[:'Q0```(U=$(A&-`^V4Q4/MH9(
-M`0``P.H"@^(!@^#^"="(AD@!``"+12F+52V)ADP!``")EE`!``"+5"0(BX27
-MO0```(E&*`^V322X`0```-/@B$XQ9HE&,HM#"8M3#8E&%+C_____B588#[9-
-M(KK_____@/D_B$XP#X;8````B59$C5=)B49`BT=)C8Y4`0``B894`0``BT($
-MB4$$BT((B4$(BT(,C9>=````B4$,BT=9C8ZL`0``B89H`0``BX>=````B8:L
-M`0``BT($B4$$BT((B4$(BT(,B4$,BU==C4==C8YL`0``B99L`0``BU`$B5$$
-MBU`(B5$(BU`,B5$,BU`0B5$0BU`4B5$4BU`8B5$8BU`<B5$<BU`@B5$@BU`D
-MB5$DBU`HB5$HBU`LB5$LBU`PB5$PBU`TB5$TBU`XB5$XBT`\B4$\@\0,B?!;
-M7E]=PY"-="8`,<`QTO;!(`^4P`^5PM/@T^*#P/^#TO_I#/___XUT)@"![&P"
-M``"+A"1P`@``C4PD6(F<)%P"``"+E"1P`@``B;0D8`(``(NT)'`"``")O"1D
-M`@``B:PD:`(``(L`B40D/(MZ)(M'.(M7/(E,)!#'1"04`0```,=$)`P!````
-MB<$#3BB)TQ->+(D\)('!`/C__X/3_P4``/[_@]+_)0``_O\IP1G3B4PD!(E<
-M)`CH_/___X7`B<8/A`P!``"+G"1P`@``C4PD6,=$)!0!````B4PD$,=$)`P!
-M````BT,HBU,LB40D!(E4)`B+0R2)!"3H_/___X/X_XG%=$6-3"18B0PDZ/S_
-M__^!?"18]!9X6@^$\0```+C_____BYPD7`(``(NT)&`"``"+O"1D`@``BZPD
-M:`(``('$;`(``,.-=@"%]G71BT<XBU<\QT0D%`$```#'1"0,`0```(E$)""+
-MA"1P`@``B50D)(M,)""-5"18BUPD)(E4)!"+5"0D`T@H$U@LBT0D(('!`/C_
-M_X/3_P4``/[_@]+_)0``_O\IP1G3BY0D<`(``(E,)`2)7"0(BT(DB00DZ/S_
-M__^%P`^$./___^E-____C40D6(D$).C\____@7PD6/06>%IT"K[^____Z=3^
-M__^-5"18QT0D!``"``")%"3H_/___X3`#X2X_O__Z]B-7"18QT0D!``"``")
-M'"3H_/___X3`#X7S_O__A>T/A3L&``"%]HUT)@`/A80&``"`?"1Y!`^&U/[_
-M_X!\)'I`#X?)_O__@+PDD@```$`/A[O^__^+="0\,=*+G"0)`0``#[=$)'^+
-MC"0%`0``"=.+5@R)7"1$"<&)3"1`B?&#P0PYRG0=C;K8_?__@'\(!'8+BT<,
-MA<`/A)$&``"+$CG*=>.+1"0\,<F-5"18Z)G[__^%P(G'#X14_O__#[:72`$`
-M`(G0@^+]T.@*1"1]@^`!`<`)PHM'.(B72`$``(M7/(E$)"B)5"0L#[9',,=$
-M)!C_____QT0D'/____\\/W<EB<&)SL'N!8/F`8GS@_,!T^/3YHE<)!B#1"08
-M_XET)!R#5"0<_XM$)$"+3"0H(T0D&(M4)$0C5"0<"<&)3SB+1"0L"=`/MI=(
-M`0``B4<\#[9$)'V#X@'`Z`*#X`$XPG0B#[:72`$``(M'!(/B_HB72`$``(!X
-M!@!T"8/*`HB72`$``(M$)&"%P'1BBX]D`0``@(])`0``!(7)#X35`P``@'D4
-M``^$?P0``(M4)&@Y46"+1"1D=P=R$SE!7'8.B4%<B5%@#[9$)&R(06;V1"1N
-M!`^$BP,``(M1"(72#X1S`P``BT$$.<(/A%<#``"+1R@[A"05`0``#X0.`P``
-M@(](`0```L>'3`$```````#'AU`!````````#[:7'`(``(G0@^+]T.@*1"1N
-M@^`!`<`)PHB7'`(```^V1"1[@'PD<`$/AEL"```/MMB+=)](A?8/A"0"```/
-MMI8<`@``B="#XOW0Z`I$)&Z#X`$!P`G"B)8<`@``#[:62`$``(G0@^+]T.@*
-MA"25````@^`!`<`)PHM&.(B62`$``(M6/(N,)!$!```/MYPDEP```(E$)%")
-M5"14BY0D#0$``(E,)$R)5"1(#[9.,,=$)##_____QT0D-/____^`^3]W(S'`
-M,=+VP2`/E,`/E<+3X-/BB40D,(-$)##_B50D-(-4)#3_BTPD,`^WPS'2"T0D
-M2(M<)#0+5"1,(<&+1"10(=,/MI9(`0``"<B)1CB+1"14@^(!"=B)1CP/MH0D
-ME0```,#H`H/@`3C"="(/MI9(`0``BT8$@^+^B)9(`0``@'@&`'0)@\H"B)9(
-M`0``#[:,)),```"+;(Y(A>T/A93[__^+E"1P`@``BT8HB52.2#N$)!D!``")
-M<@P/A*<```"`CD@!```"QX9,`0```````,>&4`$````````QP#'2]L$@#Y3`
-M#Y7"T^+3X/?2]]`A5D0A1D")-"3H_/___P^VAD@!``"H$'4-J"!T'8/(@(B&
-M2`$``,>&3`$```````#'AE`!````````]H<<`@```70MBX=D`0``A<!T(XM0
-M!(72=!R+0`B%P'05.==T`HG0B00DZ/S___\QP.G;^O__,<#IU/K__XN4))T`
-M```YEE`!``"+A"29````#X):____=PPYADP!```/ADS___^)ADP!``")EE`!
-M``#I.____XM$)#RY`0```(U4)%CHO_?__X7`B<8/A'KZ__^)>`R)1)](Z;3]
-M__\/ML@QTHN<)'`"```QP/;!(`^4P`^5PM/BT^#WTO?0(5=$(4=`B5R/2(E[
-M#(D\).C\____#[:'2`$``*@0=1&H(`^$&____X/(@(B'2`$``,>'3`$`````
-M``#'AU`!````````Z?G^__^+E"2%````.9=0`0``BX0D@0````^"\_S__W<,
-M.8=,`0``#X;E_/__B8=,`0``B9=0`0``Z=3\__^X_____\=!!`````#IP/G_
-M_XM!!(GZB7D(Z8/\__^+002%P`^$XP```(M1".EP_/__BW0D/(M&%(GS@\,4
-M.=AT*(M4)&"-2/0Y4/1T#HL`.=AT%CE0](U(]'7RA<F)CV0!```/A?/[__^+
-M1"0\@^B`B00DZ/S___^%P(G!B8=D`0``#X1$^?__,<#&!`@`@\`!@_AH=?2+
-M5"0\BW0D/(E9#(M"&(U1#(E6&(D0BU0D:(E!$(M$)&")`8M$)&2)46")05P/
-MMD0D;(A!9O9$)&X"#X2&^___BX=D`0``QD`4`>EW^___BU0D:#E18(M$)&0/
-MAY+[__\/@G[[__\Y05P/@X/[__^)]NEN^___BU$(B?B)>02-=@#IA?O__XUT
-M)%B)-"2-7"18Z/S___^+C"1P`@``C40D6,=$)!0`````B40D$,=$)`P!````
-MBT$HBU$LB40D!(E4)`B+022)!"3H_/___XD<).C\____Z7SY__^-="18B30D
-MZ/S___^+1SB-3"18B[0D<`(``(M7/(E,)!#'1"04`````(G!QT0D#`$````#
-M3BB)TQ->+('!`/C__X/3_P4``/[_@]+_)0``_O\IP1G3B4PD!(E<)`B+1B2)
-M!"3H_/___XU$)%B)!"3H_/___^D#^?__BT<D.T0D7`^%8OG___:''`(```%U
-M=X!\)'`!#X9M^?__#[9$)'N+=(=(A?8/A%SY___VAAP"```!#X1/^?__BTXX
-MBX0D#0$``(M>/(N4)!$!```)R`^WC"27````"=HQVPG:"<B)5"0$B00DZ/S_
-M__^+5@0/ME(&.=`/C@[Y__^)/"3H_/___^GH^/__BT0D0(M4)$0+5SP+1SB)
-M5"0$B00DZ/S___^+5P0/ME(&.=!_SNE?____C;8`````55<Q_U93@^P,BT0D
-M((MH#(E$)`@/MD4PA,`/MO`/A(`"``"+5"0(,<DQVSE52'46Z6X"``"-!(T`
-M````BU0D"#E4!4AT$H/!`8/3`(G(B=HQ\#'Z"<)UW3'`,=+VP2`/E,`/E<+3
-MXM/@"45`"55$B2PDZ/S____VA1P"```!#X7&````BT4,A<`/A.,!``"+0`2)
-M+"3_4"0QR3';@'TP`'1GC02-`````(M4!4B%TG1"]H(<`@```70Y@'H(!'8S
-M#[:R2`$``(GP@^"/B()(`0``.U0D"`^$HP$``/:"2`$```%T#H/FCH/.`HGP
-MB()(`0``@\$!#[9%,(/3`#'2.=IWGP^#1P$``(N%9`$``(7`#X0P`0``BU`$
-MA=(/A"4!``"+0`B%P`^$&@$``#G5=`*)T("@'`(``/Z)1"0@@\0,6UY?7>G\
-M____#[:%2`$``(/@OZ@@B(5(`0``=!V#R("(A4@!``#'A4P!````````QX50
-M`0````````^VM4@!``"+742+34")\(/@_HG:B(5(`0``]]*)R"-5//?0(T4X
-MB=$)P74+@^;LB?"(A4@!``"+=0R%]@^$JP```("F2`$``/XQR3';,?^`?C``
-M#X24````C02-`````(M4!DB%TG0P]H(<`@```70G@'H(!'8A]H)(`0```708
-M#[:"2`$``+\!````@^"L@\@"B()(`0``@\$!#[9&,(/3`#'2.=IWL7,XBYUD
-M`0``A=L/A'P```#VA4@!```$=5.%_W59@(U)`0``((/$#%M>7UW#D#G(#X=*
-M_O__Z:S^__\YR)`/AV[____KO3'_C;8`````Z[.)+"3H_/___^D9_O__@^:,
-MB?"(@D@!``#I9/[__XDL).C\____ZZ>)+"3H_/___^N=N`$````QTNFZ_?__
-MBT4,A<!T#HN(9`$``(7)#X5O____BU4<A=)X%<=$)`0`````B2PDZ/S____I
-M4____X7`#X1+____BT`<A<"-=@!YV>D\____D)"0D)"0D)"0H0````"%P'0R
-M,<F0C70F`(!X"`&+`(/9_X7`=?.%R70:H0````")PL'Z'\'J%`'"P?H,B=#!
-M^A_W^<.+%0````")T,'X'\'H%`'0P?@,PY#SPXVT)@````"-O"<`````BTPD
-M!(M4)`B+@?P```")0@R)D?P```##D(VT)@`````QP,.-M@````"-O"<`````
-M5U93@^P0BWPD((N'[````,>'%`$```````"-M@````"+MP`!``"%]G0Y.09W
-M9#FW!`$```^$BP```(M&$(F'``$``(M&",=&$`````")!"3_5@2+MP`!``"+
-MA^P```"%]G7'/7\!``!W(8N?_````(7;=!?'1"0$`````(L#B00D_U,$BUL,
-MA=MUZ8/$$%M>7\.+G_P```"%VW3OC70F`(L&B40D!(L#B00D_U,$BUL,A=MU
-MZXN'[````#L&#X-=____Z\;'AP0!````````QX<``0```````.EE____B?96
-M4X/L%(MT)""+GOP```"%VW07QT0D!/____^+`XD$)/]3!(M;#(7;=>DQP(-^
-M+``/E<"#Q!1;7L.-M"8`````4X/L"(M<)!"+@Q0!``"%P'4YC8,(`0``QX,(
-M`0``$#(%`(F;#`$``,>#$`$```````")1"0$C4,LB00DZ/S____'@Q0!```!
-M````@\0(6\.#[`R+5"00BTPD%(N"``$``(7`=""+@@0!``")2!")B@0!``")
-M%"3H_/___[@!````@\0,PXN"[````#L!<PZ)B@0!``")B@`!``#KUXM!"(D$
-M)/]1!#'`Z]>-M@````"+1"0$!>0```")1"0$Z?S___^-M"8`````C;PG````
-M`(M$)`0%Y````(E$)`3I_/___Y"0D)"0D)"0D)"0D)"04XM<)`@/MD,4B<*#
-MX/L*4Q6#X@0)T`^V4Q6)P8/@_H/A`8/B`0G*"="(0Q0/MD,DB<*#X/L*4R6#
-MX@0)T`^V4R6)P8/@_H/A`8/B`0G*"="(0R1;PXUT)@"-O"<`````4XM<)`@/
-MMD,EB<*#X/L*4R:#X@0)T`^V4R:)P8/@_H/A`8/B`0G*"="(0R4/MD,]B<*#
-MX/L*4SZ#X@0)T`^V4SZ)P8/@_H/A`8/B`0G*"="(0SU;PP``````````````
-M`````)8P!W<L80[NNE$)F1G$;0>/]&IP-:5CZ:.59)XRB-L.I+C<>1[IU>"(
-MV=*7*TRV";U\L7X'+;CGD1V_D&00MQWR(+!J2'&Y\]Y!OH1]U-H:Z^3=;5&U
-MU/3'A=.#5IAL$\"H:V1Z^6+][,EEBD]<`139;`9C8ST/^O4-"(W((&X[7A!I
-M3.1!8-5R<6>BT>0#/$?4!$O]A0W2:[4*I?JHM35LF+)"ULF[VT#YO*SC;-@R
-M=5S?1<\-UMQ9/=&KK##9)CH`WE&`4=?(%F'0O[7TM"$CQ+-6F96ZSP^EO;B>
-MN`(H"(@%7[+9#,8DZ0NQAWQO+Q%,:%BK'6'!/2UFMI!!W'8&<=L!O"#2F"H0
-MU>^)A;%Q'[6V!J7DOY\SU+CHHLD'>#3Y``^.J`F6&)@.X;L-:G\M/6T(EVQD
-MD0%<8^;T46MK8F%L'-@P985.`&+R[94&;'NE`1O!]`B"5\0/]<;9L&50Z;<2
-MZKB^BWR(N?S?'=UB22W:%?-\TXQE3-3[6&&R3<Y1M3IT`+RCXC"[U$&EWTK7
-ME=@];<31I/OTUM-JZ6E#_-EN-$:(9ZW0N&#:<RT$1.4=`S-?3`JJR7P-W3QQ
-M!5"J00(G$!`+OH8@#,DEM6A7LX5O(`G49KF?Y&'.#OG>7IC)V2DBF-"PM*C7
-MQQ<]LUF!#;0N.UR]MZULNL`@@[CMMK._F@SBM@.:TK%T.4?5ZJ]WTIT5)ML$
-M@Q;<<Q(+8^.$.V24/FIM#:A::GH+SP[DG?\)DR>N``JQG@=]1),/\-*C"(=H
-M\@$>_L(&:5U78O?+9V6`<39L&><&:VYV&]3^X"O3B5IZVA#,2MUG;]^Y^?GO
-MOHY#OK<7U8ZP8.BCUM9^D]&AQ,+8.%+RWT_Q9[O19U>\IMT&M3]+-K)(VBL-
-MV$P;"J_V2@,V8'H$0</O8-]5WV>H[XYN,7F^:4:,LV'+&H-FO*#2;R4VXFA2
-ME7<,S`-'"[NY%@(B+R8%5;X[NL4H"[VRDEJT*P1JLURG_]?",<_0M8N>V2P=
-MKMY;L,)DFR;R8^R<HVIU"I-M`JD&"9P_-@[KA6<'<A-7``6"2K^5%'JXXJXK
-ML7LX&[8,FX[2D@V^U>6W[]Q\(=_;"]32TX9"XM3Q^+/=:&Z#VA_-%KZ!6R:Y
-M]N%WL&]W1[<8YEH(B'!J#__*.P9F7`L!$?^>98]IKF+XT_]K847/;!9XX@J@
-M[M(-UU2#!$["LP,Y829GI_<68-!-1VE)VW=N/DIJT:[<6M;99@O?0/`[V#=3
-MKKRIQ9Z[WG_/LD?I_[4P'/*]O8K"NLHPD[-3IJ.T)`4VT+J3!M?-*5?>5+]G
-MV2,N>F:SN$IAQ`(;:%V4*V\J-[X+M*&.#,,;WP5:C>\"+2H=``!N'0``,!X`
-M`#`>```P'@``,!X``+(=``#Q'0``,!X``$@>``"?*```J2@``*DH``"I*```
-MJ2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I
-M*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH
-M``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``!R*```J2@`
-M`'(H``"I*```J2@``*DH``!R*```<B@``*DH``"I*```J2@``*DH``"I*```
-MJ2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I
-M*```<B@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH
-M``"I*```J2@``*DH``"I*```<B@``'(H``!R*```<B@``*DH``"I*```J2@`
-M`*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```
-MJ2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I
-M*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH
-M``"I*```J2@``*DH``"I*```J2@``*DH``!R*```J2@``*DH``"I*```J2@`
-M`*DH``"I*```J2@``*DH``!R*```J2@``'(H``"I*```J2@``*DH``!R*```
-M<B@``*DH``"I*```J2@``'(H``"I*```J2@``*DH``"I*```J2@``*DH``"I
-M*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH``"I*```J2@``*DH
-M``"I*```J2@``'(H``"I*```<B@``*DH``"I*```J2@``'(H``!R*```OCT`
-M`'$]``!^/0``H#T``+X]``"T/0``JCT``+X]``"^/0``OCT``+X]``"J/0``
-MZ60```UE```Q90``I64``#=F````````X:T``+:M``#!K0``YZT``+"M``"P
-MK0``L*T``+"M``"PK0``L*T``+"M``"PK0``L*T``+"M``"PK0``L*T``/&M
-M``#GK0``QZT``.&M``#1K0``UZT``/&M``"CK0```"````1$````(`$`!$0`
-M``(!```".@```@$!``(Z```$`0``"P````0!`0`+````"`$```9:`0`(`0$`
-M!EH!`!`!```#%`$`$`$!``,4`0`@`0``!B@``"`!`0`&*```0`$```,1``!`
-M`0$`!R<``(`!```+1P,`@`$!``M'`P#P)`$`8"4!`(4E`0"J)0$`SR4!`/0E
-M`0`A)@$`OB8!`/4F`0#*)P$`>"<!`)TG`0#O)P$``2D!`#XI`0!O*0$`LBD!
-M`.8J`0#C*0$`^"D!`"XG`0!3)P$`3B8!`(4F`0!X)P$`#2H!`",K`0!0*P$`
-M=2L!`*(K`0"V*P$`Y"L!`"0L`0`Z*@$`9RH!`)0J`0#!*@$````````````@
-M80$`-5@!`'M8`0#C6`$`6%D!`()9`0#360$`9%H!`&U:`0#^70$`\5P!`"%8
-M`0`@80$`(&$!`"!A`0`@80$`(&$!`)Y@`0`@80$`(&$!`'9:`0".6@$`W%D!
-M`%M:`0#Q7`$`T5X!`.M@`0#Q8`$`&&$!`"!A`0#O7P$`,&`!`#E@`0#:7@$`
-MY5X!`.Y>`0#W7@$`M8X!`">,`0`XC`$`28P!`%J,`0"EC`$`PXP!`->,`0`K
-MC0$`1XT!`&.-`0!_C0$`JXT!`+^-`0#3C0$`M8X!`+6.`0#LC0$`2XX!`+6.
-M`0"UC@$`$8X!`(F.`0!XC`$`C(P!`+6.`0#KC`$`_XP!`!.-`0!@PP$`8,,!
-M`)_#`0"TPP$`8,,!`-[#`0!JPP$`R<,!`(W$`0"?Q`$`RLT!`'?/`0!WSP$`
-M=\\!`'?/`0!WSP$`=\\!`'?/`0!WSP$`=\\!`'?/`0!WSP$`=\\!`'?/`0!W
-MSP$`=\\!`'?/`0!WSP$`=\\!`'?/`0!WSP$`=\\!`'?/`0!WSP$`=\\!`'?/
-M`0!WSP$`=\\!`'?/`0!WSP$`=\\!`'?/`0#>S0$`1\X!`+#.`0`9SP$`@]`!
-M`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`
-M4M8!`%+6`0!2U@$`4M8!`)?0`0"7T`$`E]`!`%+6`0!2U@$`4M8!`%+6`0!2
-MU@$`4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!`%+6`0`1T0$`=M$!`-O1
-M`0!!T@$`4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!
-M`%+6`0!2U@$`IM(!`"33`0"BTP$`(-0!`%+6`0!2U@$`4M8!`%+6`0!2U@$`
-M4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!`)[4`0!2U@$`4M8!`%+6`0!2
-MU@$`4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!`%+6`0!2U@$`4M8!`%+6
-M`0#DU`$`(M4!`&#5`0">U0$`W-4!`!?6`0!2;V-K970@-S4P(%-!5$$@0V]N
-M=')O;&QE<@```0````````````````````````"6,`=W+&$.[KI1"9D9Q&T'
-MC_1J<#6E8^FCE62>,HC;#J2XW'D>Z=7@B-G2ERM,M@F]?+%^!RVXYY$=OY!D
-M$+<=\B"P:DAQN?/>0;Z$?=3:&NODW6U1M=3TQX73@U:8;!/`J&MD>OEB_>S)
-M98I/7`$4V6P&8V,]#_KU#0B-R"!N.UX0:4SD06#5<G%GHM'D`SQ'U`1+_84-
-MTFNU"J7ZJ+4U;)BR0M;)N]M`^;RLXVS8,G5<WT7/#=;<63W1JZPPV28Z`-Y1
-M@%'7R!9AT+^U]+0A(\2S5IF5NL\/I;VXGK@"*`B(!5^RV0S&).D+L8=\;R\1
-M3&A8JQUAP3TM9K:00=QV!G';`;P@TI@J$-7OB86Q<1^UM@:EY+^?,]2XZ*+)
-M!W@T^0`/CJ@)EAB8#N&[#6I_+3UM")=L9)$!7&/F]%%K:V)A;!S8,&6%3@!B
-M\NV5!FQ[I0$;P?0(@E?$#_7&V;!E4.FW$NJXOHM\B+G\WQW=8DDMVA7S?-.,
-M94S4^UAALDW.4;4Z=`"\H^(PN]1!I=]*UY78/6W$T:3[]-;3:NEI0_S9;C1&
-MB&>MT+A@VG,M!$3E'0,S7TP*JLE\#=T\<050JD$")Q`0"[Z&(`S));5H5[.%
-M;R`)U&:YG^1AS@[YWEZ8R=DI(IC0L+2HU\<7/;-9@0VT+CM<O;>M;+K`((.X
-M[;:SOYH,XK8#FM*Q=#E'U>JO=]*=%2;;!(,6W',2"V/CA#MDE#YJ;0VH6FIZ
-M"\\.Y)W_"9,GK@`*L9X'?423#_#2HPB':/(!'O["!FE=5V+WRV=E@'$V;!GG
-M!FMN=AO4_N`KTXE:>MH0S$K=9V_?N?GY[[Z.0[ZW%]6.L&#HH];6?I/1H<3"
-MV#A2\M]/\6>[T6=7O*;=!K4_2S:R2-HK#=A,&PJO]DH#-F!Z!$'#[V#?5=]G
-MJ.^.;C%YOFE&C+-ARQJ#9KR@TF\E-N)H4I5W#,P#1PN[N18"(B\F!56^.[K%
-M*`N]LI):M"L$:K-<I__7PC'/T+6+GMDL':[>6[#"9)LF\F/LG*-J=0J3;0*I
-M!@F</S8.ZX5G!W(35P`%@DJ_E11ZN.*N*[%[.!NV#)N.TI(-OM7EM^_<?"'?
-MVPO4TM.&0N+4\?BSW6AN@]H?S1:^@5LFN?;A=[!O=T>W&.9:"(AP:@__RCL&
-M9EP+`1'_GF6/::YB^-/_:V%%SVP6>.(*H.[2#==4@P1.PK,#.6$F9Z?W%F#0
-M34=I2=MW;CY*:M&NW%K6V68+WT#P.]@W4ZZ\J<6>N]Y_S[)'Z?^U,!SRO;V*
-MPKK*,).S4Z:CM"0%-M"ZDP;7S2E7WE2_9]DC+GIFL[A*8<0"&VA=E"MO*C>^
-M"[2AC@S#&]\%6HWO`BU*%`(`CA0"`%`5`@!0%0(`4!4"`%`5`@#2%`(`$14"
-M`%`5`@!H%0(`OQ\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`
-MR1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)
-M'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?
-M`@#)'P(`R1\"`,D?`@#)'P(`DA\"`,D?`@"2'P(`R1\"`,D?`@#)'P(`DA\"
-M`)(?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`
-MR1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`)(?`@#)'P(`R1\"`,D?`@#)
-M'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`)(?
-M`@"2'P(`DA\"`)(?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"
-M`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`
-MR1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)
-M'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?
-M`@#)'P(`DA\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`DA\"
-M`,D?`@"2'P(`R1\"`,D?`@#)'P(`DA\"`)(?`@#)'P(`R1\"`,D?`@"2'P(`
-MR1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)
-M'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@#)'P(`R1\"`,D?`@"2'P(`R1\"`)(?
-M`@#)'P(`R1\"`,D?`@"2'P(`DA\"`-XT`@"1-`(`GC0"`,`T`@#>-`(`U#0"
-M`,HT`@#>-`(`WC0"`-XT`@#>-`(`RC0"`.E;`@`-7`(`,5P"`*5<`@`W70(`
-M`````%&D`@`FI`(`,:0"`%>D`@`@I`(`(*0"`""D`@`@I`(`(*0"`""D`@`@
-MI`(`(*0"`""D`@`@I`(`(*0"`""D`@!AI`(`5Z0"`#>D`@!1I`(`0:0"`$>D
-M`@!AI`(`$Z0"```@```$1````"`!``1$```"`0```CH```(!`0`".@``!`$`
-M``L````$`0$`"P````@!```&6@$`"`$!``9:`0`0`0```Q0!`!`!`0`#%`$`
-M(`$```8H```@`0$`!B@``$`!```#$0``0`$!``<G``"``0``"T<#`(`!`0`+
-M1P,`D!L#```<`P`E'`,`2AP#`&\<`P"4'`,`P1P#`%X=`P"5'0,`:AX#`!@>
-M`P`]'@,`CQX#`*$?`P#>'P,`#R`#`%(@`P"&(0,`@R`#`)@@`P#.'0,`\QT#
-M`.X<`P`E'0,`&!X#`*T@`P##(0,`\"$#`!4B`P!"(@,`5B(#`(0B`P#$(@,`
-MVB`#``<A`P`T(0,`82$#````````````P%<#`-5.`P`;3P,`E$\#``E0`P`S
-M4`,`A%`#`!51`P`E40,`E50#`(=3`P#!3@,`P%<#`,!7`P#`5P,`P%<#`,!7
-M`P`^5P,`P%<#`,!7`P`N40,`1E$#`(U0`P`,40,`AU,#`'%5`P"+5P,`D5<#
-M`+A7`P#`5P,`CU8#`-!6`P#95@,`>E4#`(55`P".50,`EU4#`.)F`P#I9@,`
-M\F8#`/EF`P`"9P,`"6<#`!)G`P#79@,`Q8,#`#>!`P!(@0,`68$#`&J!`P"U
-M@0,`TX$#`.>!`P`[@@,`5X(#`'."`P"/@@,`NX(#`,^"`P#C@@,`Q8,#`,6#
-M`P#\@@,`6X,#`,6#`P#%@P,`(8,#`)F#`P"(@0,`G($#`,6#`P#[@0,`#X(#
-M`"."`P``````````````````````````````````````T+@#`-"X`P`/N0,`
-M)+D#`-"X`P!.N0,`VK@#`#FY`P#]N0,`#[H#`)K#`P!'Q0,`1\4#`$?%`P!'
-MQ0,`1\4#`$?%`P!'Q0,`1\4#`$?%`P!'Q0,`1\4#`$?%`P!'Q0,`1\4#`$?%
-M`P!'Q0,`1\4#`$?%`P!'Q0,`1\4#`$?%`P!'Q0,`1\4#`$?%`P!'Q0,`1\4#
-M`$?%`P!'Q0,`1\4#`$?%`P!'Q0,`KL,#`!?$`P"`Q`,`Z<0#`%/&`P`BS`,`
-M(LP#`"+,`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`B
-MS`,`(LP#`"+,`P!GQ@,`9\8#`&?&`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,
-M`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`BS`,`X<8#`$;'`P"KQP,`$<@#
-M`"+,`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`BS`,`
-M(LP#`';(`P#TR`,`<LD#`/#)`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`B
-MS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P!NR@,`(LP#`"+,`P`BS`,`(LP#`"+,
-M`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`BS`,`(LP#`"+,`P`BS`,`M,H#
-M`/+*`P`PRP,`;LL#`*S+`P#GRP,``````````````````````$1A=&%#96YT
-M97(@-S(X,"!3051!($-O;G1R;VQL97(``0```!L````!````@!`$``L1!`"S
-M$`0`E!`$``L1!``+$00`"Q$$``L1!`"`$`0`Q1$$`(`0!`"`$`0`.Q`$`+D1
-M!`"&$00`3Q$$`($W!`"1-P0`F3<$`*$W!`"I-P0`L3<$`+DW!`")-P0`5#T$
-M``5`!``G/P0`T3\$`*`_!`#1/P0`5#T$`%@]!``RGP0`M9\$`)B@!`#&H`0`
-MA:$$`(.B!`"?H@0`JZ($`'*?!``BHP0`V:,$`#*?!`#HI`0`]:,$`)2D!`#B
-MLP0`%+@$`.RW!`#2MP0`N+<$`)2W!`#BLP0`>K<$`$>T!`!!^00`,/D$`!#Y
-M!`#P^`0`L/@$`'?X!`!O(`4`EA\%`&\@!0!P'P4`<!\%`'`?!0!-5E]297%U
-M97-T("5P.B!#9&);)3)X+"4R>"PE,G@L)3)X+"`E,G@L)3)X+"4R>"PE,G@L
-M("4R>"PE,G@L)3)X+"4R>"P@)3)X+"4R>"PE,G@L)3)X72X`6R4P,G@Z)3`R
-M>"`E,#)D72!D:7-K(')E;6]V960N``!%<G)O<B!I;B!I<W-U:6YG(&-O;6UA
-M;F0L(&5R<B!I;F9O(#!X)6QL6````%1A<VL@9FEL92!E<G)O<BP@4W1A='5S
-M4F5G/3!X)7@L($5R<E)E9STP>"5X+"!,0D%;,"TS73TP>"5X+$Q"05LT+3==
-M/3!X)7@N``!296-E:79E9"!.54P@4F5Q('-L;W1.;R@E>"\E>"D@14Y44ED@
-M*"4P.'@I+"!E<G)O<B`P>"5L;%@```!@+2!&25,H4VQO=#HE,#)X*3H@)3`X
-M>"`E,#AX("4P.'@@)3`X>```0TU$($AE861E<CH@)3`X>"`E,#AX("4P.'@@
-M)3`X>"`N("4P.'@@)3`X>"`E,#AX("4P.'@@+B`E,#AX("4P.'@@)3`X>"`E
-M,#AX("X@)3`X>"`E,#AX`%LE,#)X.B4P,G@@)3`R9"`E,#)D72!032!R97%U
-M97-T*"5X*2!T:6UE;W5T+@```%1I;65O=70@2#)$($9)4RA3;&]T.B4P,G@I
-M.B`E,#AX("4P.'@@)3`X>"`E,#AX`%LE,#)X.B4P,G@@)3`R9%T@6&9E<B`E
-M>"!%<G)O<B!I;F9O<FUA=&EO;B`P>"5L;%@```!;)3`R>#HE,#)X("4P,F0@
-M)3`R9"`E,#)D72!89F5R("5X($5R<F]R(&EN9F]R;6%T:6]N(#!X)6QL6`!;
-M)3`R>#HE,#)X("4P,G@@)3`R>%T@4$T@6&9E<B`E>"!%<G)O<B!I;F9O<FUA
-M=&EO;B`P>"5L;%@```!2=6YN:6YG($@R1"!&25,H4VQO=#HE,#)X*3H@)3`X
-M>"`E,#AX("4P.'@@)3`X>``@4T<@:71E;2`E,#)X.B!A9&1R("5L;'@@<VEZ
-M92`E>"!31T@@861D<B`E;&QX('-I>F4@)7@``$9A:6QE9"!T;R!E;F%B;&4O
-M9&ES86)L92!S<&EN('5P+@```%LE,#)X.B4P,G@@)3`R9%T@1&5V:6-E(')E
-M<75E<W0H)7@I('1I;65O=70N`````%LE,#)X.B4P,G@@)3`R9"`E,#)D("4P
-M,F1=($1E=FEC92!R97%U97-T*"5X*2!T:6UE;W5T+@``6R4P,G@Z)3`R>"`E
-M,#)D72!D:7-K(')E;6]V960@*"5X*2X`071T1&5V4T%3061D<ELE>%T@(%M5
+MQT`(;W(@``^W5R*-1A?H>;;__^M%/`-U(<9&`1#'1B`!````QT8$2%!4`,=&
+M#$5*,S1FQT80,`#K(,9&!'8/MU<@C48%Z$*V___&1@QD#[=7(HU&#>@RMO__
+MQD8<<@^V5QV-1AWHXK7__[@`````ZPRX_____^L%N`````"#Q`Q;7E]=PXVT
+M)@````!55U93@^P(BUPD)+@`````Q@08`(/``3T``0``=?*+1"0<B[A$!0``
+M#[9$)"")1"0$B3PDZ/S___^)P6:%P'0-#[?`@+P'N`0``/]U2XN_1`4``(''
+MR`P``(N'1`4``(D$).C\____BU0D("G"#[;"B40D!(D\).C\____B<%FA<`/
+MA,(!```/M\"`O`>X!```_P^$L0$```^WP0^VA`>X!```9H'Y@0`/A]<```"+
+MC[`%```/M\!IP!0-``"--`&+5@R%TG1L#[:'.`4``#S_=!4/ML!IP!0-``"-
+M!`&]@````#G"="`/MH<Y!0``//]T&@^VP&G`%`T``(T$`3G"=0J]@0```(GH
+MB$,"@'XR`'0ON@`````/ML(/MDP&0+@!````T^`)0R"#P@$X5C)V$.ODQD,"
+M_XM&"`^V0`F)0R#&`P$/MD8QB$,!BT9(B4,$BT9,B4,(C4L,C598BT98B4,,
+MBT($B4$$BT((B4$(BT(,B4$,BT9PB4,<N`````#IR0````^WT&G2L````(G6
+M`[>4!0``QD,"_\8#`HN'E`4```^V1`(?B$,!BT94#[9`"8E#(`^VAJ4````\
+M`G4MQT,$2%!4`(U##,=##%)O8VO'0`1E=%-TQT`(;W(@``^W5B*-0Q?H%;3_
+M_^M%/`-U(<9#`1#'0R`!````QT,$2%!4`,=##$5*,S1FQT,0,`#K(,9#!'8/
+MMU8@C4,%Z-ZS___&0PQD#[=6(HU##>C.L___QD,<<@^V5AV-0QWH?K/__[@`
+M````ZP6X_____X/$"%M>7UW#C78`C;PG`````(/L+(E<)!R)="0@B7PD)(EL
+M)"B+?"0PBVPD-(M';(E$)!2+122).(M'8(7`=1+&168"B2PD_U5PZ;@%``"-
+M=@#V0"@"=!+&168"B2PDC78`_U5PZ9T%``"+3"04B0PDZ/S___^)QH7`=1;&
+M168"B2PD_U5PZ7P%``"-M"8`````QT!D`````(EH2(M'8(E&&(M'8`^W0!QF
+MB480QD84@`^V160\`@^$60$``#P"=PF$P'0BZ;L"```\`XVV``````^$P0$`
+M`#P$#X6E`@``B?;IC0$``(M'8/9`.`&-="8`#X20````#[9%9:@"=`;&1B2(
+MZQ"#X`0\`1G`@^`%@^AVB$8DBTU(BUU,#[=%4&:)1"0:QD8E`(G8P>@8B$8F
+MB=C!Z!"(1B>)V,'H"(A&*(A>*8G(#ZS8&(A&*HG(#ZS8$(A&*XG(#ZS8"(A&
+M+(A.+<9&+@#&1B\`#[=$)!IFP>@(B$8P#[9,)!J(3C'&1C(`QD8S`.MK#[9%
+M9:@"=`;&1B0HZQ"#X`0\`1G`@^`%@\`JB$8DBTU(BUU,#[=%4&:)1"0:QD8E
+M`(G(#ZS8&(A&)HG(#ZS8$(A&)XG(#ZS8"(A&*(A.*<9&*@`/MT0D&F;!Z`B(
+M1BL/MDPD&HA.+,9&+0"+1V`%N````(E&.,9&'"`/MT0D&L'@"8E&((-.9`+I
+M?`$```^V14@\$'<%]@<"=0G&168&Z:T#``"-3B0/ML"-55")1"0(B50D!(D,
+M).C\____BT=@!;@```")1CC&1AP@@4YD```0`,9&%:OV164&#X0I`0``BT5,
+MB48@Z1X!```/MD5E@^`P/"!U$<9&)!O&1B4!QD8H`.D"`0``QD8D->GY````
+MBT=@#[9`)(/@!8/X!743@4YD```@``^W551F.U5*=0[K7,9%9@:-=@#I$@,`
+M``^V15,\XY"-="8`=$,\XW<2/$)T.SRPC70F`'0@/$!U(NLM/.R-M@````!T
+M$#SO=!\\Y74.C;8`````ZQ-FB55*ZPW&168&C70F`.G"`@``QD8DL`^W14B(
+M1B4/MT5*B$8F#[=%3(A&)P^W14Z(1B@/MT50B$8I#[9%4HA&*@^V15.(1BL/
+MMD5)B$8L#[9%2XA&+0^V14V(1BX/MD5/B$8O#[9%48A&,/9%909T'0^W153!
+MX`F)1B"#3F0$ZPW&168&Z4L"``"-="8`QT9L<+H"``^V166H!@^$'@(``*@"
+M=`:#3F0(ZP2#3F00C7X\BUUHA=MT!O9%90%U/(M5;(72#X0C`@``QT0D"```
+M``"+3"04BX%$!@``B40D!(DL)/_2A<`/A``"``"+1"04BYA$!@``A=MT2(DT
+M).C\____QT0D!`````")/"3H_/___X/#$(M#\(E$)`R+0_B+4_R)1"0$B50D
+M"(D\).C\____BT/T@\,0A<`/A8(!``#KT\=$)`0`````B3PDZ/S___^+1B`]
+M``@``'=#BTPD%(D,).C\____B<*%P'4)QD5F"^E=`0``BT`(B48TB590BT8@
+MB40D#(M"#(M2$(E$)`2)5"0(B3PDZ/S____K4ST```$`=T.+1"04B00DZ/S_
+M__^)PH7`=0G&168+Z1,!``"+0`B)1C2)5E"+1B")1"0,BT(,BU(0B40D!(E4
+M)`B)/"3H_/___^L)QD5F!NGB````#[9%9:@$D(UT)@`/A+\```"`?60#=2*+
+M35B%R70;BU8TBT8@B40D"(E,)`2)%"3H_/___^F7````BU5HA=)U#8M5;(72
+M#X6Y````ZVB+?C2H`74)B=.0C70F`.LPBU5LA=)T*<=$)`@!````BTPD%(N!
+M1`8``(E$)`2)+"3_TH7`=`J+1"04BYA$!@``@\,0BT/XBU/PB50D"(E$)`2)
+M/"3H_/___P-[\(M#](/#$(7`=1WKVXM&((M6-(7`=!'&`@"#P@&#Z`%T!NOS
+M@TYD`8ET)`2+3"04B0PDZ/S____K+HET)`2+1"04B00DZ/S___^)+"3_57#K
+M%KL`````Z4S^__^+?C2-="8`Z53___^+7"0<BW0D((M\)"2+;"0H@\0LPXVT
+M)@````!75E.#[!"+?"0@BW0D)+@`````Q@0P`(/``8/X>'7T@[]0!0```0^4
+M1A,/ME<B#[9/(0^V7R`/MD<CB$8#B%8"B$X!B!Z`3A$0#[='&&:)1@0/MT<:
+M9HE&!HN'4`4``(A&;,9&$B`/MU<:9H'Z("%T!V:!^B(A=4?&1A<"C48\QT8\
+M4F]C:\=`!&5T4D''0`A)1"!3QT`,4T0@,L=`$#$R>"#'0!1#;VYTQT`8<F]L
+M;&;'0!QE<L9`'@#I`@$``(V"\-C__V:#^`%V$F:!^D`A=`MF@?I$(0^%I0``
+M`,9&%P0/MU<:C8+PV/__9H/X`7=#C48\QT8\4F]C:\=`!&5T4D''0`A)1"`R
+MQT`,-S%X(,=`$%-!4R#'0!1#;VYTQT`8<F]L;&;'0!QE<L9`'@#IC0```&:!
+M^D`A=`=F@?I$(75_C48\QT8\4F]C:\=`!&5T4D''0`A)1"!3QT`,4T0@,L=`
+M$#$T>"#'0!1#;VYTQT`8<F]L;&;'0!QE<L9`'@#K/\9&%PB-1CS'1CQ$871A
+MQT`$0V5N=,=`"&5R(#?'0`PR.#`@QT`04T%40<=`%"!#;V['0!AT<F]LQT`<
+M;&5R``^V1A+V9A>(1A"$P'4$QD80@(U&&,=&&$AI9VC'0`10;VENQT`(="!4
+M9<=`#&-H;F_'0!!L;V=IQT`497,L(,=`&$EN8R[&0!P`BX=,!0``A<!T$(M`
+M"(E&9(G"P?H?B59HZPZ+1PB)1F2)PL'Z'XE6:,=&8``@``#'1"0$?````(M'
+M$(D$).C\____B<*!XO`#``#!Z@2(5FV#X`^(1F_'1"0$@````(M'$(D$).C\
+M____B<*!X@``\`/!ZA2(5FXE```/`,'H$(A&<(/$$%M>7\.-M@````"-OP``
+M``!55U93@^P<BWPD,(MT)#2+7"0XN`````#&!!@`@\`!/9P```!U\HES"(/^
+M/WX)@<?(#```@^Y`N`````"#O+>X`@````^%GP(``(F<M[@"``")>VR+1"0\
+MB4-PBTPD0(E+>(!_-0$/A7@"``"!_H4````/CUH"```/MH0WN`0``#S_#X1*
+M`@``#[;`9HE$)!@/M\!IP"@!``")Q0.O>`4``/9%)P0/A"<"``"+120E`/__
+M`#T``/\`#X44`@``]D4H!`^$AP$``,:%M``````/MDTD#[;1B="#X`:#^`9U
+M.?;"`0^$`P$``,9%)@7&12<$B6PD#`^V14V)1"0(BT4PB40D!(M%+(D$).C\
+M____N`$```#IT`$``(/X!`^%P@$``/;!`0^$N0$``(M=+(M%-(7`#X6"````
+MQD4F`\9%)P2`>PH`=%&^`````(U#.(E$)!2+3"04B0PDZ/S___^)PHM#/(E3
+M/(M,)!2)"HE"!(D0@'HF_W05.=5T$<:%M0````&X`0```.E<`0``@\8!#[9#
+M"CGP?[N`O;4````!#X0_`0``B6PD!(D\).C\____N`$```#I+@$``(!X)@`/
+MA1\!``!F@V`R_8M%-&;'0#(@`(M%-(E$)`2)/"3H_/___[@!````Z?T```"+
+M12P/MD`)@'\F`'0ONP`````/MO`/MLN)\-/XJ`%T%,=$)`@`````B4PD!(D\
+M).C\____@\,!.%\F=]G&12<&QD4F!6;'A90``````(EL)`2)/"3H_/___[@!
+M````Z9H```"+;2R`?0H`=%[&1"0;`(U%.(E$)!"+3"00B0PDZ/S___^)PHM%
+M/(E5/(M,)!")"HE"!(D0@'HF_W0>#[9")3PB=`0\#742QX2WN`(```````"X
+M`````.M"@$0D&P$/MD0D&SA%"G>N#[=$)!B)1"0(B5PD!(D\).C\____N`$`
+M``#K%\>$M[@"````````N`````#K!;@!````@\0<6UY?7<.0D)"0D)"0D)"0
+MD)"0D)"+5"0$H0````")0@2)%0````##C;8`````C;PG`````*$`````!9@!
+M`P##D(UT)@"+1"0$BTPD"(7`=!2+$(72=`F%R70%BT($B0&)T,.)]HL5````
+M`.OFD(VT)@````"+1"0$BU0D"`68`0,``T(0P^L-D)"0D)"0D)"0D)"0D%.!
+M[/@```"+E"0``0``C80D@````(N<)`0!``"+2@2)1"0$BT((B00D_U$<C40D
+M"(M3!(E$)`2+0PB)!"3_4AP/MD0D"3B$)($```!V#;@!````@<3X````6\-R
+M)`^V1"0*.(0D@@```'?C<A0/MD0D"SB$)(,```!WTW($,<#KTKC_____Z\N0
+MC;0F`````%=64X/L$(L=`````(MT)""%VW4(ZWJ+&X7;='2+0PB%P'1VBU8$
+M.U`$=>N+0`B)1"0$BT8(B00D_U(DA,!TUXM3"(U["(72=1_K9I"-="8`B50D
+M!(DT).C\____A<!X48L_BQ>%TG1)BT8$BXB`````A<ETVSM"!'76BT((B40D
+M!(M&"(D$)/_1Z]&0C70F`#'`@\006UY?P\<&`````+@!````B5X,B7,(@\00
+M6UY?PXL'B5X,B0:X`0```(DWZ]'K#9"0D)"0D)"0D)"0D)"+5"0$H0````")
+M`HM"#(D5`````(7`=!"A`````(E"$`-"#*,`````\\.-M@````!75E.#[!"+
+M'0`````/MG0D((7;="V)\#A#!'0FB?`/MOCK!XGP.$,$=!B+0T"%P'0)B3PD
+M_]"%P'4(BQN%VXGV=>&#Q!")V%M>7\.0C70F`%:)UE.#[$2`/0`````"=#2+
+M6`PQR8/`##G8=!HYB_3]__^)VG4*ZQ<YBO3]__]T#XL2.<)U\HE.'(/$1%M>
+MPX/!`>O4C40D((M25(E$)`2+1F")!"3_4CR+5EP/MD0D,`-"*(E&'(/$1%M>
+MPXUT)@"+%0````"X=````(72=!0PP(M*&#G(<P*)R(L2A=)U\8/`=//#C70F
+M`(V\)P````!3BT0D"(M<)`R+4`R-2`PYRG4(ZQ.+$CG*=`V-@MC]__\Y6!QU
+M[UO#6S'`PXUT)@!3@^P(BT0D$(M8"(7;=!.0BU,$BT,(B00D_U)LBQN%VW7N
+M@\0(6\.)]HV\)P````"+1"0$B<*+`.GS_O__C78`BT0D!(M0'(72>`?'0!S_
+M____\\.-M@````"-OP````!3BUPD##'`A=MT%XM4)`@QR0'3#[8"@\(!`<$Y
+MVG7T#[;!6\.-M@````"-OP````"A`````(M,)`2%P'0DBU`(A=)T%SE*"'4,
+MZQB0C70F`#E*"'0,BQ*%TG7UBP"%P'7<\\/SPXUT)@"-O"<`````5U93BT0D
+M$(MT)!2+?"08BU`,C5@,.=IU#>LQD(UT)@"+$CG3=":-@MC]__^`>`@$=NXY
+M<"1UZ87_>!>+2`R%R73>.42Y2'786UY?PULQP%Y?PXM(#(7)=<?K[9"-="8`
+M5U93@^P0BWPD((D\)(UW#.C\____BU\,.?-T*HUT)@"-D]C]__^+@B0"``"%
+MP'00BT($BT`XA<!T!HD4)/_0D(L;.?-UVHD\).C\____BT<,.?!U".L9BP`Y
+M\'03BUCXA=MT\X/$$+@!````6UY?PX/$$#'`6UY?PXVT)@````!7,<!64X/L
+M$(M\)""`OX0!`P``=2>+7PB%VW0>,?:)]HM#!(M3"(D4)/]05(L;"<:%VW7L
+MB?"$P'4),<"#Q!!;7E_#B3PDZ/S___^#Q!")\EL/ML)>7\.)]HV\)P````!5
+M5U93@^P,BW0D(.C\____BY[(````B<>%VP^$C````(M#!(G:C:[(````*?B%
+MP'X.Z88```"+0@0I^(7`?S.+0A2%P'0#B6@0B8;(````B<.+0@S'0A``````
+MQT(4`````(D$)/]2"(N6R````(72=<2)-"3H_/___X7;=`J+AL@````YV'0(
+M@\0,6UY?7<.+0`0I^(E$)`2+1@2)!"3H_/___X/$#%M>7UW#B70D((/$#%M>
+M7UWI_/___XDT).C\____Z[B-=@"-O"<`````5U93BW0D%(M\)!#H_/___XM.
+M$(7)=!:+5A2%TG0&B4H0BTX0B1''1A``````BY?(````B<$##HV?R````(72
+MB4X$=0SK/HU:%(M2%(72=#2+0@0IR(7`?NV)5A2-1A2),SFWR````(E>$(E"
+M$'4EBP:)1"04BT<$B40D$%M>7^G\____B584B3,YM\@```")7A!TVUM>7\.0
+MC;0F`````%93@^P$BTPD%(M<)!"+41"%TG1<BT$4B[/(````A<!T!HE0$(M1
+M$(D"QT$4`````(N#R````,=!$`````"%P'0O.<9T*^C\____BY/(````BU($
+M*<*%THG0?AN)1"04BT,$B40D$(/$!%M>Z?S___^#Q`1;7L/'!"14`@``Z/S_
+M__^XZ`,``.O2C;0F`````%93@^P4BW0D((M>"(7;=13K+HM3!(M#"(D$)/]2
+M:(L;A=MT'(![1`!TZ(M3!,=$)`0`````BT,(B00D_U(HZ]*-ALP```")-"2)
+M1"0$Z/S___^#Q!1;7L.0C;0F`````%=64X/L$(M\)""+7PB%VW4(ZS*+&X7;
+M="R+4P2+0PB)!"3_4G"`>T0`=.B+4P3'1"0$`0```(M#"(D$)/]2*(L;A=MU
+MU(M?#(UW##GS=0CK)XL;.?-T(8V3V/W__X!Z"`%U[HM"!(M`.(7`=.2)%"3_
+MT(L;.?-UWX`]``````!T.(V?S````(E<)`2)/"3H_/___\>'S`````"'DP/'
+MA]0`````````B;_8````B5PD!(D\).C\____@\006UY?PU575E.#[`R+="0D
+MBVPD((7V=%Z+5@2+1@B)!"3_4G"`?D0`#X6:````BUT,C7T,.?MU".LLBQLY
+M^W0FC9/8_?__@'H(`77N.7)<=>F+0@2+0#B%P'3?B10D_]"+&SG[==J+-H7V
+M=!&#Q`R)\%M>7UW#BW4(A?9UFX`]``````!TYHV=S````(E<)`2)+"3H_/__
+M_\>%S`````"'DP/'A=0`````````B:W8````B5PD!(DL).C\____@\0,B?!;
+M7E]=PXM6!,=$)`0!````BT8(B00D_U(HZ4W___^-="8`4X/L"(M<)!")'"3H
+M_/___XG!QT`(`````(U`=(E!)(M##(U1*(/H=(E!((U!#(E!#(E!$#'`Q@00
+M`(/``8/X3'7T@\0(B<A;PXVT)@````"#[`PQTHE<)`2+7"04B70D"(MT)!@Y
+M<PAR(8D<).C\____B<*+1"00B7((B5H$B0*+0PB#P`$I\(E#"(M<)`2)T(MT
+M)`B#Q`S#C;0F`````(/L#(M4)!"+1"04B10DB40D"(U":(E$)`3H_/___X/$
+M#,.-M"8`````C;PG`````(M,)`B+1"0$BU$(`U`(@^H!B5`(Z?S___^-M"8`
+M````@^P,BT0D$(E$)`2+`(/`:(D$).C\____@\0,PXUT)@!5B<575E.#[`R+
+M<`R->`PY_G4(ZT>+-CG^=$&-GMC]__^`>P@!=>X/MD-0J$`/A6T!``"`/0``
+M````=-FH`G75J`$/A9T!``#V0U`$C70F`'7#@$M0)(LV.?YUOXM=%(UU%#GS
+M=!&-0_2)!"3H_/___XL;.?-U[XMU##G^#X2:````C8;8_?__@'@(!'8+BU@,
+MA=L/A#H!``"+-CG^=>.+70PY^W1VQD0D"P#K"8UV`(L;.?-T/HV3V/W__X!Z
+M"`%U[O9"4"!TZ(M")(!B4-N%P'4/Z=4```"+`(7`#X3+````BT@4A<ET[XL;
+MQD0D"P$Y\W7"BW4,.?=T(9"-="8`C9[8_?__]H,<`@```70'BT,,A<!T((LV
+M.?YUY(N5C`$#`(72=`B+102)!"3_TH/$#%M>7UW##[93"(#Z!'8/BX-D`0``
+MA<!T$#E8!'0+@.H!=</V0U`"=+V+0QR%P(GV#XB/````]H,<`@```G2GQT0D
+M!`````")+"3H_/___X7`B<)TD3G#=(WV@!P"```"='.`HQP"``#]Z7C___^)
+M]HD<).C\____Z6C^__^`?"0+``^%^/[__X`]``````&0#X7J_O__B10DZ/S_
+M___IW?[__XD$).C\____D(UT)@#IM/[__XD<).C\____C78`Z5/^__^)VHGH
+MZ!+V__^)]NEA____BT,<B4(<QT,<`````.G__O__B?:-O"<`````55=64X'L
+MG````(N<)+````"%VXM[#`^$WP```,=$)!@`````C50D)(M#!(E4)`2+4PB)
+M%"3_4!P/MD0D-#L%%`(```^.G@```(U#$(E$)!3K(#EK&(-4)!@`BQ44`@``
+M#[9$)#2#P@$YT(D5%`(``'YU]D0D-0%U$0^V!0`````[1"08#X2-````BVL8
+MBU0D%(.'D`$#``&)%"3H_/___XM3!(E<)!#'1"0,X`D#`(E$)`B)QJ$4`@``
+MB40D!(M#"(D$)/]2-(3`=8>+1"04B70D!(D$).C\____@Z^0`0,``>ES____
+MBQO'!10"````````A=L/A2G___^+AY`!`P"#Z`&%P(F'D`$#`'4[B?CHR_S_
+M_^LR#[8%`````,<%!`(```````")'0@"``#'1"0$_`$``&G`0$(/`(D\)*/\
+M`0``Z/S___^!Q)P```!;7E]=PXVV`````(V_`````%575E.#[`R+="0@BVPD
+M*(M\)"2+7@B)KHP!`P"%VW4(ZR6+&X7;=!^+0P2+4PB)%"3_4'B$P'7JQH:$
+M`0,``8/$#%M>7UW#BQT`````A=MT$HM#*(7`=`6)-"3_T(L;A=MU[H7_=!B+
+M5P3'1"0$`0```(M'"(D$)/]2*,9'1`&+1@C'AI`!`P`!````B00DZ/S___^+
+MAI`!`P"%P'2AA>UT$(ET)""#Q`Q;7E]=Z?S____'!"2@A@$`Z/S___^)-"3H
+M_/___XN^D`$#`(7_=>+I:O___XUT)@"-O"<`````@^P<B70D%(MT)"")?"08
+MBT0D*(E<)!"+?"0DBUX,@ZN0`0,``87`>$>)1"0(B7PD!(DT).C\____A<!T
+M1(N#D`$#`(7`=!"+7"00BW0D%(M\)!B#Q!S#B=B+="04BUPD$(M\)!B#Q!SI
+M,_O__XUV`(U&$(E\)`2)!"3H_/___^N\BT8$B3PD_U!`C480B7PD!(D$).C\
+M____ZZ*0C70F`%575E.#[`R+?"0@BP>+<!R-:!R)1"0(ZQ&-M"8`````C5[T
+MBS8Y>RAT/SGU=?*+1P2+0#2%P'0%B3PD_]"+ARP"``"+ER@"``")0@2)$(M$
+M)`B)?"0$@\`XB00DZ/S___^#Q`Q;7E]=PXM3#(U+#(M#$(E"!(D0B4L0B4L,
+MQD-F`HD<).C\____ZY^0C70F`%575E.#[!R+?"0PBVPD-(M'#(M0#(/`##G"
+M=0_IHP```(L2.<(/A)D```"-FMC]__^`>P@!=>H[:UAUY3M[7'7@A=MT?_:#
+M'`(```$/A=(```"+@Z@```"%P`^%Q````(N#F````(7`#X6V````BT,DA<!U
+M".M%BP"%P'0_BU`4A=)T\XMR#(7V#X2A````@'XP``^$EP```#')ZP\/MD8P
+M@\$!.<@/CH0````Y5(Y(=>O'1(Y(`````.OAB1PDZ/S___^-=Q")-"3H_/__
+M_X7`B<-T3XM$)#R+5P2)7"0(B6PD!(E$)!"+1"0XB40D#(M'"(D$)/]2-+H!
+M````A,!T"H/$'(G06UY?7<.)7"0$B30DZ/S___^#Q!PQTEN)T%Y?7<.#Q!PQ
+MTEN)T%Y?7<.)%"3H_/___^DQ____C78`55=64X'LG````(NL)+0```"+O"2P
+M````A>T/A+X!``"+=PB%]G1QBX>4`0,`BU8$B48HC40D)(E$)`2+1@B)!"3_
+M4AR+5@2+1@@/MEPD-`&?E`$#`(D$)/]2,(E<)`R);"0$B40D"(U&$(D$).C\
+M____#[9$)#3'1"0(%````(EL)`2)1"0,C48LB00DZ/S___^+-H7V=8^A````
+M`+I@`@``A<!T%S')BU`4.=%S`HG1BP"%P'7QC9%@`@``BX>4`0,`B50D"(EL
+M)`2-!,")1"0,C4<XB00DZ/S___^+AY0!`P#'1"0(``(``(EL)`2)1"0,C4=0
+MB00DZ/S___^-AY@```")!"3'1"0,`0```,=$)`@L````B6PD!.C\____BX>4
+M`0,`QT0D"!0```");"0$B40D#(V'L````(D$).C\____BX>4`0,`QT0D"&@`
+M``");"0$C03`B40D#(V'@````(D$).C\____QX?D`````0```,>'\``````0
+M``#'A^@`````$```Z/S____'1"0,0B$``(EL)`2)1"0(C4=HB00DZ/S___^+
+M'0````"%VW0@BU,<A=)T$XN'E`$#`(EL)`2)/"2)1"0(_]*+&X7;=>"!Q)P`
+M``!;7E]=PXMO!.DZ_O__C78`C;PG`````%93BQT`````Z/S___^+="0,A<!T
+M#8GRQ@(`@\(!@^@!=?6A`````(7`=0?K6HUV`(G#BP.%P'7XB3.+1"00QX9D
+M`0,``!```(E&!(U&#(E&#(E&$(U&%(E&%(E&&(U&'(E&'(E&((V&0`$``(F&
+M0`$``(F&1`$``(V&8`$``(F&8`$#`%M>PXDU`````.NKD(/L'(`]``````*)
+M="00#[9T)"2)7"0,B7PD%(EL)!@/A``!``")\@^VPHD$).C\____A<")QP^$
+M\P```(ML)""#Q3B)+"3H_/___XG#,<"0Q@08`(/``3U@`@``=?*A&`(``(E[
+M!(/``:,8`@``B8-8`@``C8-(`@``@(L<`@```8F#2`(``(F#3`(``(GPB$,(
+MBT<4BU0D((7`B1-T(8M7%(V#8`(``(E#$(72=!$QP,:$&&`"````@\`!.=!U
+M\8V#,`(``(F#,`(``(F#-`(``(V#.`(``(F#.`(``(F#/`(``(M',,=#(`(!
+M``#'0QS_____A<!T"8D<)/_0A<!U18M$)""-DR@"``"+2!")4!"#P`R)@R@"
+M``")BRP"``")$>L,B?`L`0^$]O[__S';B=B+="00BUPD#(M\)!2+;"08@\0<
+MPXE<)`0QVXDL).C\____Z]J)]HV\)P````!75E.#[!"+%0````"+="0@.?)U
+M#NFQ````C;0F`````(G"A=)T"HL".?!U](L&B0*+1@R-7@PYV'0:C;8`````
+M+2@"``")!"3H_/___XM&##G8=>R+1A2-?A0Y^'0GC9Z`````@^@,BT@,BU`0
+MB5$$B0J)1"0$B1PDZ/S___^+1A0Y^'7?@+Z$`0,``'4<BQT`````A=MT$HM#
+M+(7`=`6)-"3_T(L;A=MU[HM>"(7;=!*+4P2+0PB)!"3_4G2+&X7;=>Z#Q!!;
+M7E_#BP:C`````.E:____D)"0D)"0D)"0D(M,)`0QP(M1$(VT)@````#&!!``
+M@\`!@_@L=?2-0@B)0@B)0@PQP(D2B5($QT(4\#X#`(E*&,="'`````##B?:+
+M0"2#Z!0#!7@"``##C78`BT`0,=*+"#G!=!*+$8M!!(E"!(D0BU$,B0F)202)
+MT,.#[!R)T8E<)!2)PXET)!B+<!"`>F0`=1(/MT)0,=(#04@344R)0T")4T2#
+M1A`!BT-@BU-4B4PD!(D$)/]23(M<)!2+="08@\0<PXVV`````(/L#(M$)!#V
+M@!P"```(BU`0=2;'0B0`````BU!4@(@<`@``"(E$)`C'1"0$8!<#`(M`8(D$
+M)/]21(/$#,.-=@!6N?____]3BT0D#(MT)!P/MUPD&`^V5"0@]H`<`@```70=
+MA-)T%P^WT\'B"872=`TQP,8$,`"#P`$YT'7U,<E;B<A>PXVV`````(V_````
+M`(/L$(ET)`2+="04B1PDB7PD"(EL)`SV1E!`QT8P`````,=&-`````!U68M.
+M)(7)=',Q_S'M,=OK$(VT)@````"#PP&+"87)="V+012%P'7PBT$,BU$0`48P
+M$58TBU$0BT$,.>IRW7<$.?AVUXL)B<>)U87)==.#^P-_"(E^*(EN+.L.QT8H
+M`````,=&+`````"+'"2+="0$BWPD"(ML)`R#Q!##,?\Q[>O1C;8`````5E.+
+M="0,B?,#7"00.=YS%XG9#[91_@^V0?^(4?^(0?Z#Z0(YSG+K.=YT)0^V!CP@
+M=2&)\NL'#[8"/"!U&(/"`3G:=?*)\<8!`(/!`3G9=?9;7L.)\HGQA,!T()"-
+M="8`@\(!/"!T&P^V0O^(`8/!`3G3=`</M@*$P'7E.<MUQY#KSCG:=/4/M@*$
+MP)"-="8`=,4\('3!#[9"_X@!@\$!Z]/K#9"0D)"0D)"0D)"0D)"+1"0$BT`0
+MQT`D`0```,.05E.#[`2+="00]D90`G4MBUXDA=MT%HM3%(72=`F+0@2)%"3_
+M4"2+&X7;=>K'AJ@`````````@\0$6U[#B30DZ/S____'AJ@`````````@\0$
+M6U[#C;8`````C;\`````4X/L"(M<)!"+5"04]D-2`HM#$'0+]D`H`G05D(UT
+M)@"#0"0!@\0(6\.-M"8`````.5`D<NO'1"0$`0```(L#B00DZ/S___^%P(G"
+M=-</MD!EB5HHB5HLQD)D!(/@SX/(((A"9<9"9@#'0G`P%@,`B50D$(/$"%OI
+M_/___XUT)@!3B<.#[`C'1"0$`0```(L`B00DZ/S___^%P(G"=$#V0U("=4'&
+M0&0#QT!8`````,9`4T!FQT!,``!FQT!.``!FQT!0``#&0%)`9L=`2```9L=`
+M2@$`9L=`5```B5HH@\0(B=!;P\9`9`*AI`T``(E"4`^W!:@-``#&0D@&QT),
+M`````,9"20!FB4)4Z\Z-=@"#[!R)7"04B<.)="08BW`0Z%O___^Z_____X7`
+M=!W'0'#P%@,`@$XH`8M35(E$)`2+0V")!"3_4DPQTHM<)!2)T(MT)!B#Q!S#
+MC;0F`````%=64X/L$(M<)""+?"0D@'L(!'9&@'LP`'0Y,?;K#8GV#[9#,(/&
+M`3GP?BB+1+-(A<!T[?:`'`(```%TY(D$)(/&`8E\)`3H_/___P^V0S`Y\'_8
+M@\006UY?PW0P]H,<`@```73NB=CHM/[__X7`=..#!P&)>"S'0'!`%@,`B40D
+M((/$$%M>7^G\____BULD]H,<`@```72[Z\N-M@````#I_/___XUT)@"-O"<`
+M````@^P<BT0D((E<)!2)="08BU@LBS")!"3H_/___XL#@^@!A<")`W4/C4,$
+MB40D!(DT).C\____BUPD%(MT)!B#Q!S#C;0F`````(V\)P````!64X/L!(LU
+M`````,<%>`(```````"%]G4.ZRB0C70F`(MV!(7V=!R+'7@"``#_5D@YPW/L
+M_U9(BW8$A?:C>`(``'7DQP0D8`(``(,%>`(``!3H_/___X/$!#'`6U[#B?:#
+M[!R+3"0@B5PD%(ET)!B+<2B+7A`/ME,HB="#X/Z(0RB`>68!=#F)#"3H_/__
+M_XM3((72=1N-0Q3'0R`!````B40D!(L&@\`LB00DZ/S___^+7"04BW0D&(/$
+M',.-=@"#XOR(4RCKOY"-M"8`````@^P,BU0D$(M"$("B'`(``/?'@I@`````
+M````BT@@A<EU&\=`(`$```"#P!2)1"0$BP*#P"R)!"3H_/___X/$#,/K#9"0
+MD)"0D)"0D)"0D)!3@^P(BT0D$(M8$(E$)`2+`P6P````B00DZ/S___^-@YP`
+M``#'@YP```#0$P,`B9N@````QX.D`````````(E$)`2+`X/`)(D$).C\____
+M@\0(6\.-M@````"-OP````!64X/L%(MT)"#'1"0$8`(``(M<)"2+!HD$).C\
+M____B<&+1B2%P'05.=B-5B1U!NL2.=AT#HG"BP"%P'7T@\046U[#BP.)`HE<
+M)"2)3"0@@\046U[I_/___XVT)@````!5B<U7B==6,?93@^Q,BU0D9(E$)"2+
+M1"1@B50D'(M4)"2)1"08BU(DA=*)5"0X=!:)UC'`@WX4`8LV@]C_A?9U\X/X
+M`WX*@\1,B?!;7E]=PXM$)!B+5"0<BTPD.`'X$>J)3"0\B40D$(E4)!3K*HGV
+MBUPD/(M3"(M#!#'J,?@)P@^$`@$``(M4)#R+$H72B50D/`^$YP```(M4)#R+
+M0A2%P'7-BUH(BTH$.>MWV7($.?EWTXM4)!2+1"00B50D+(M4)#R)1"0HBT(,
+MBU(0B40D,`'(B50D-!':.50D+'>G<@8Y1"0H=Y^)VHG(,>HQ^`G"#X1/`@``
+M.>MWBP^#7@$``(M4)"3'1"0$8`(``(L"B00DZ/S___^)!"3H_/___X7`B<$/
+MA!W___\QP,8$"`"#P`&#^!AU](M<)#R+0P2+4PB)002)^(E1"(GJ*T,$&U,(
+MB7L$B4$,BP.)41"+4Q"):PB)`8M##"M!#!M1$#E4)!R)"XE##(E3$`^&5@(`
+M`(MT)#SIOO[__XL+A<ET5KL!````ZP:+"87)=$"+012%P'3SBU$(BT$$,>HQ
+M^`G"=>6+00R+41")1"0(BT0D/(E4)`P[4!!R#W<)BU0D"#M0#'8$B4PD/(/#
+M`>NZ@^L!#X]B_O__BUPD/(M+#(M;$#E<)!R)3"1`B5PD1'=P<@8Y3"08=VB+
+M5"0DQT0D!&`"``"+`HD$).C\____B00DZ/S___^%P(G"#X0:_O__,<#&!!``
+M@\`!@_@8=?2+7"0<B=:+3"08B7H$B6H(B5H0BUPD/(E*#(L#B0*)$^GG_?__
+M.?D/@Q_^___IE?[__XM<)#CK"HL;A=L/A,K]__^+0Q2%P'7OBTPD/(M$)$"+
+M5"1$`T$$$U$(BTL(,T,$,=$)P771BT0D0(M4)$0#0PP34Q`Y5"0<#X>-_?__
+M<@HY1"08#X>!_?__BW0D),=$)`1@`@``BP:)!"3H_/___XD$).C\____B<$Q
+MP,8$"`"#P`&#^!AU](MT)#R+1"08BU0D'`-&!!-6"(E#!(M##(E3"(M3$`-&
+M#!-6$"M$)!@;5"0<B7D$B4,,BT0D&(E3$(M4)!R):0B)00R+!HE1$(D!B0Z)
+MSND`_?__BU0D'(M$)!@S5"0T,T0D,`G"#X0A_O__BTPD),=$)`1@`@``BP&)
+M!"3H_/___XD$).C\____A<")P0^$P/S__S'`Q@0(`(/``8/X&'7TBUPD/(M#
+M#(G>*T0D&(M3$!M4)!R)00R+1"0HB5$0BU0D+(E!!(L#B5$(BU0D&(D!B0N+
+M3"0<B5,,B4L0Z7'\__]R"CE$)!@/@Y[]__^+5"0DQT0D!&`"``"+`HD$).C\
+M____B00DZ/S___^)P3'`A<ET4\8$"`"#P`&#^!AU](M<)#R+1"08BU0D'`-#
+M!(G>$U,(B4$$BT,,*T0D&(E1"(M3$!M4)!R)00R+`XE1$(M4)!R)`8M$)!B)
+M"XE3$(E##.GL^___BTPD/(L9BT,$BU,(B4$$BP.)40B+5"0DB0''1"0$8`(`
+M`(L"B00DZ/S___^)7"0$B00DZ/S____IK_O__XGVC;PG`````%=64X/L$(M\
+M)"#'1"0$8`(``(L'B00DZ/S____V1U`(B<9U((M')(7`=!F0C70F`(L8B40D
+M!(DT).C\____A=N)V'7LBU=4BT=@B00D_U)`BT=@B40D!(M'7(/`$(D$).C\
+M____@\006UY?PXUT)@!64X/L%(M<)""+4R2`HQP"``#^A=)T%(M"%(7`=`>`
+MH!P"``#^BQ*%TG7LB5PD!,<$)`$```#H_/___XL#QX.H`````0````6P````
+MB00DZ/S___^%P(G&=%S'``$```#'0`2P%P,`B48(QT`,`````(E8$(M;)(7;
+M=#"0C70F`(M3%(72=0OK'(VT)@````")PHM"#(7`=?>)="0$B10DZ/S___^+
+M&X7;==6+!H/H`87`B09T!H/$%%M>PXET)""#Q!1;7NEF^?__C;8`````4X/L
+M&(M$)""+7"0HQT0D!&`"``")!"3H_/___XM4)"2-'-N)7"0,QT0D"!@```")
+M5"0$B00DZ/S___^#Q!A;PX/L3(E\)$2+?"10B70D0(MT)%2);"1(BVPD6(E<
+M)#R#_P=W3/\DO:P-``"+LY@```"%]G4[BT,$QX.8`````0```(M`.(F;D```
+M`,>#E`````````")@XP```"-@XP```")1"0$C4$LB00DZ/S___^+7"0\BW0D
+M0(M\)$2+;"1(@\1,PXM>$,=&$`````")="0$QP0D`P```.C\____B5X0Z\V)
+M-"3H_/___XM8"(G'A=MU".L,BQN%VW0&.7,(D'7TC4,LB00DZ/S___^%P'2?
+MB5@,B6@0QP!@(`,`B4`$QT`(`````(E$)`2-1R2)!"3H_/___^EU____B30D
+MZ/S___^)P8M`#(U1##G0=0_I7/___XL`.=`/A%+___^-F-C]__^`>P@!=>HY
+M:V!UY8/_!P^'./____\DO<P-``"+0UR+4`2-1"08B40D!(DL)/]2/`^V1"0J
+MB$-.#[94)"8/MD-2@^(!`=*#X/T)T(A#4NGZ_O__BT,0@*,<`@``[XM0((72
+M#X7E_O__QT`@`0```(/`%(E$)`2-02R)!"3H_/___^G'_O__@(L<`@``$.F[
+M_O__BT,$B1PD_U`DB?;IJ_[__XUT)@"-O"<`````@^P<BT0D((E<)!2)="08
+MBU@,BW`0B40D!(U#+(D$).C\____B5PD#(ET)`2)'"3'1"0(L#4#`.C\____
+MBUPD%(MT)!B#Q!S#D(VT)@````"!["P"``"`/0``````B9PD)`(``(N<)#`"
+M``")M"0H`@``=1R+G"0D`@``B[0D*`(``('$+`(``,.-M"8`````#[9#4(UT
+M)"2#R`.#X/N(0U#'1"04`0```(ET)!#'1"0,`0```,=$)`0)````QT0D"```
+M``")'"3H_/___X7`=4^!?"0D>6-G;'1E]D-0`9!TDHMS)(7V="7'1"0$8`(`
+M`(L#B00DZ/S___^)="0$B00DZ/S____'0R0`````BT,XBU,\B4,4B5,8Z57_
+M__^0@*,<`@``_HE<)`3'!"0!````Z/S___^`2U`!Z33____'1"0$``(``(DT
+M).C\____A,!UAP^V3"0H#[:#'`(``(G*P.H$@^#]@^(""="(@QP"``#V1"0H
+M$'0,@$M0@`^V1"0IB$-/]D0D*P%T%P^V4U&)R,#H`H/@`H/*`8/B_0G"B%-1
+M]D0D*P)T%0^V4U&-!`F#X`B#R@2#XO<)PHA34?9$)"L(=!4/MD-1P>$$@^$@
+M@\@0@^#?"<B(0U'V1"0K!`^$]/[__P^V4U$/MD0D*(/*0(/@`8/B?\'@!PG"
+MB%-1Z=7^__^-=@"-O"<`````55=64X'L'`(``(N,)#`"``"#P20/MD$L@^`#
+M+`$/A+\"``"+E"0P`@``#[9"4(/@[XG&B$)0C40D'(VV`````,8``(V<)!P"
+M``"#P`$YV'7O]D$L`@^%AP(``(N\)#`"``")\X/C]XA?4(N\)#`"``#'1"0<
+M7W=A4HM'%(M7&(E$)"")5"0D@'DL`'D-@$PD*!`/MD=/B$0D*?9!+0%T)(N$
+M)#`"``"`3"0K`0^V4%$/MD0D*,'B`H/B"(/@]PG0B$0D*/9!+01T(XN\)#`"
+M``"`3"0K`@^V1"0H#[9748/@^]#J@^($"="(1"0H]D$M$'0DBX0D,`(``(!,
+M)"L(#[9040^V1"0HP.H$@^("@^#]"="(1"0H]D$M0'0AB[PD,`(``(!,)"L$
+M#[9$)"@/ME=1@^#^P.H'"="(1"0HBX0D,`(``(-X+``/AIX!``#V02P@#X2S
+M`0``BY0D,`(``(MR)(7V=$`Q_XMN%(7M=#&+1@2-#'^#QP&+5@B-3,P<B4$0
+MB5$4BT8,BU80B4$8BT84B5$<BU`LBT`HB5$DB4$@BS:%]G7"BXPD,`(``(U<
+M)!R-?"0<#[9!4HD<),:$)!L"```!QT0D!``"``"#X`&(A"0:`@``Z/S___^+
+MC"0P`@``B7PD$,=$)!0`````QT0D#`$```#WV(B$)!P!``"+03B+43R)#"0%
+M``#^_X/2_R4``/[_B40D!(E4)`CH_/___XN<)#`"``"+>R2%_W1/,>V+3Q2%
+MR71`BYPD,`(``(UT;0"+0SB+4SR+62R+22@!P1'3@<$`^/__@]/_!0``_O^#
+MTO\E``#^_RG!&=.#Q0&)3/0\B5ST0(L_A?]ULXU\)!S&A"0<`0```,=$)`0`
+M`@``B3PDZ/S___^+C"0P`@``QT0D%`````#'1"0,`0```/?8B(0D'`$``(U$
+M)!R)1"00BT$XBU$\B0PD!0#X__^#TO^)1"0$B50D".C\____@<0<`@``6UY?
+M7<.!>"C__Q\`#X=5_O__B?.#X_.(6%#V02P@#X5-_O__P.L"@^,!B%PD*ND^
+M_O__D(UT)@!3B<.#[`C'1"0$8`(``(L`B00DZ/S___^)!"3H_/___XG!,<"%
+MR70RQ@0(`(/``8/X&'7TBT,4BU,8B4$,B5$0BT,4BU,8B4LDB4,PB5,TB4,H
+MB5,L@\0(6\.)'"3H_/___^OQC;8`````C;\`````55=64X'L/`,``(N\)%`#
+M``"`/0`````"C7<D#X0O`0``C40D2,=$)!0!````B40D$,=$)`P!````BT<X
+MBU<\B3PD!0#X__^#TO^)1"0$B50D".C\____A<")1"0L#X3O`P``C6PD2,=$
+M)!0!````B6PD$,=$)`P!````BT<XBU<\B3PD!0``_O^#TO\E``#^_XE$)`2)
+M5"0(Z/S___^%P(E$)"@/A$8#``"#?"0L_P^4P(-\)"C_#X34!@``BT0D*(7`
+M#Y5$)"</A#("``"+1"0LA<`/A28"``"-3"1(QT0D%`$```")3"00QT0D#`$`
+M``"+1SB+5SR)/"0%`/C__X/2_XE$)`2)5"0(Z/S___^%P(E$)"P/A.0!``"`
+MIQP"``#^B7PD!,<$)`$```#H_/___X!/4`&!Q#P#``!;7E]=PX`]```````/
+MA0`"``"0@$]0`O9'4`)T#0^V1U"#R`&#X/N(1U#V1BP!=#B+7R2%VW0EQT0D
+M!&`"``"+!XD$).C\____B5PD!(D$).C\____QT<D`````(M'.(M7/(E'%(E7
+M&(!^+``/B/$```#V1BT!#X6U````]D8M!'5\]D8M$'4^]D8M0`^$:/___\9$
+M)$@%#[9'48UL)$C&1"1-`,#H!XA$)$R+5U2);"0$BT=@B00D_U)@@<0\`P``
+M6UY?7</&1"1(!`^V1U&-3"1(QD0D30#`Z`6#X`&(1"1,BU=4B4PD!(M'8(D$
+M)/]28/9&+4`/A/[^___KE,9$)$@##[9'4<#H`X/@`8A$)$R-1"1(BU=4B40D
+M!(M'8(D$)/]28/9&+1`/A%G____KE<9$)$@"#[9'48UL)$C0Z(/@`8A$)$R+
+M5U2);"0$BT=@B00D_U)@]D8M!`^$(?___^N;QD0D2``/MD=/C4PD2(A$)$R+
+M5U2)3"0$BT=@B00D_U)@]D8M`0^$[O[__^NAC50D2,=$)`0``@``B10DZ/S_
+M__^$P`^%4`$``("\)$<"````=0C'1"0L_O___\9$)"<`@7PD2%]W85(/A`L"
+M``"+3SB+7SR!P0``_O^#T_^)R(G:)0``_O^)T#'2B=4)Q0^%=`$``(!/4`$/
+MM@4`````/`(/A`G^__\L`0^$\_W___:''`(```$/A/C]__^`IQP"``#[C40D
+M2(V4)$@"``")]L8``(/``3G0=?:-;"1(QT0D%`$```");"00QT0D#`$```#'
+M1"0$`````,=$)`@`````B3PDZ/S___^`?"1(10^$\`,``("\)$8"``!5#X61
+M_?__@+PD1P(``*H/A8/]__\QP(N4!!("``"%T@^%;OW__X/`$(/X0'7IZ67]
+M__^0C40D2`^VG"1'`@``QT0D!``"``")!"3H_/___XE<)`S'!"2L"P``#[;`
+MB40D"(M$)$B)1"0$Z/S___^!?"1(7W=A4@^$E/[__XM$)"R%P`^%>/S__\=$
+M)"S_____Z6O\__^-5"1(#[:<)$<"``")%"3'1"0$``(``.C\____B5PD#,<$
+M)(@+```/ML")1"0(BT0D2(E$)`3H_/___X%\)$A?=V%2#X1J`P``QT0D+/[_
+M___IN_O__XU$)$@QTHE$)!")R"4``/[_QT0D%`$```#'1"0,`0```(E$)`2)
+M5"0(B3PDZ/S___^%P`^%._S__X%\)$A?=V%2#X5%_O__C50D2,=$)`0``@``
+MB10DZ/S___^$P`^$[@8``(%\)$A?=V%2#X4;_O__C50D2,=$)`0``@``B10D
+MZ/S___^$P`^%__W__X!\)%8`#[9'4`^5PL'B`H/@^PG0B$=0#[9'4H"\)$8"
+M````#Y7"@^#^"=`/MM*(1U*)5"0(B70D!,<$)'`"``#H_/___XM'.(M7/`4`
+M`/[_B<&#TO^!X0``_O^)^(E/%(E7&.CS^?__]D0D5!!T#(!/4(`/MD0D58A'
+M3_9$)%<!=!H/ME=1#[9$)%2#R@'`Z`*#XOV#X`()PHA74?9$)%<"=!D/ME=1
+M#[9$)%2#R@0!P(/B]X/@"`G"B%=1]D0D5PAT&@^V5U$/MD0D5(/*$,'@!(/B
+MWX/@(`G"B%=1]D0D5P1T&@^V5U$/MD0D5(/*0(/@`8/B?\'@!PG"B%=1QT0D
+M-``````Q[8M$+&`+1"QD#X7;`0``@\48@_U@=>J`?"0G``^$0P,``&8Q[8M$
+M+&`+1"QD=#2+3"QHBT<XBUPL;(M7/('!``@``(/3`"G!&=,%``#^_X/2_R4`
+M`/[_`<$1TXE,+&B)7"QL@\48@_U@=;J-5"1(B10DQH0D2`$```#'1"0$``(`
+M`.C\____C4PD2,=$)!0`````B4PD$,=$)`P!````]]B(A"1(`0``BT<XBU<\
+MB3PD!0``_O^#TO\E``#^_XE$)`2)5"0(Z/S____'1"0X`````,=$)#P`````
+MC6PD2,=$)!0!````B6PD$,=$)`P!````BT<XBU<\B3PD!0'X__^#TO\#1"0X
+M$U0D/(E$)`2)5"0(Z/S___^%P`^$70$``(-$)#@!BT0D.(-4)#P`@_`$"T0D
+M/'6CBTPD-(7)#X34`P``@$]00(D\).C\____Z13Z__^$P`^$)/G__XVT)@``
+M``#I=_G__X!\)$E2C;8`````#X7_^___C40D2,=$)!0!````B40D$,=$)`P!
+M````QT0D!`$```#'1"0(`````(D\).C\____@'PD2%`/A<3[__^`?"1)30^%
+MN?O__XUT)@#I2_G__XU,)$C'1"0$``(``(D,).C\____A,`/A$+X___I=?S_
+M_\=$)`0$````BP>)!"3H_/___X7`B40D-`^$\_C__XM$+&"+5"QDB00DB?B)
+M5"0$BU0L6(M,+%SH#NK__X7`B40D,`^$X@0``(M,)#2)>22+1"0HA<`/A=D`
+M``"+1"QHBU0L;(E!*(E1+(M,)#"+5"0TB4HPBTPD,(M!#(M1$(M,)#2)012+
+M1"0PB5$8B4@4Z9']__^-1"1(QT0D%`````")1"00QT0D#`$```"+1SB+5SR)
+M/"0%``#^_X/2_R4``/[_@\`!@](``T0D.!-4)#R)1"0$B50D".C\____BT\X
+MBU\\QP0DT`L``(G(!0``_O^)VH/2_R4``/[_@\`!@](``T0D.!-4)#R!P0'X
+M__^#T_\#3"0X$UPD/(E$)`R)5"00B4PD!(E<)`CH_/___^D#_O__BT0D+(7`
+M#X4I____BTPL:(M'.(M<+&R+5SR!P0`(``"#TP`IP1G3!0``_O^#TO\E``#^
+M_P'!BT0D-!'3B4@HB5@LZ>[^__^+7"0LA=L/A,?]__^`O"1'`@````^$(`$`
+M`#'MBT0L8`M$+&1T-(M'.(M7/(G!`TPL:(G3$UPL;('!`/C__X/3_P4``/[_
+M@]+_)0``_O\IP1G3B4PL:(E<+&R#Q1B#_6!UNHUL)$C&A"1(`0```,=$)`0`
+M`@``B2PDZ/S____'1"04`````,=$)`P!````]]B(A"1(`0``C40D2(E$)!"+
+M1SB+5SR)/"0%`/C__X/2_XE$)`2)5"0(Z/S____'1"1``````,=$)$0`````
+MC50D2,=$)!0!````B50D$,=$)`P!````BT<XBU<\B3PD!0``_O^#TO\E``#^
+M_X/``8/2``-$)$`35"1$B40D!(E4)`CH_/___X7`#X2F````@T0D0`&+1"1`
+M@U0D1`"#\`0+1"1$=9CIF?S__\<$)(4"``#H_/___XU4)$B)%"3&A"1'`@``
+M`<:$)$@!````QT0D!``"``#H_/___XU,)$C'1"04`````(E,)!#'1"0,`0``
+M`/?8B(0D2`$``(M'.(M7/(D\)`4``/[_@]+_)0``_O^)1"0$B50D".C\____
+MZ6?^___V1BP$#X3:]___B?;I&_S__XU,)$B)3"00QT0D%`````#'1"0,`0``
+M`(M'.(M7/(D\)`4!^/__@]+_`T0D0!-4)$2)1"0$B50D".C\____BT<XBU<\
+MBTPD0(M<)$0%`?C__X/2_P'!$=,%_P?^_X/2_R4``/[_@\`!@](``T0D0!-4
+M)$2)3"0,B5PD$(E$)`2)5"0(QP0D``P``.C\____Z<;^__^-E"1(`@``C40D
+M6,=$)`CP````C9PD4`(``(E$)`2-K"1``P``B10DZ/S____K"X/#&#GK#X21
+M````BP,+0P1T[HU,)$@QTL=$)!0!````B4PD$,=$)`P!````BT,(B50D"(D\
+M)(E$)`3H_/___X7`#X6M]/__C40D2(D$).C\____@7PD2/06>%H/A-@```"-
+M3"1(QT0D%`````")3"00QT0D#`$```"+0PB+4PR)/"2)1"0$B50D".C\____
+MA<`/A&G____I6/3__XUL)$C'1"04`0```(EL)!#'1"0,`0```(M'.(D\)`4`
+M`/[_,=(E``#^_XE$)`2)5"0(Z/S___^%P`^%&?3__XU$)$C'1"04`````(E$
+M)!#'1"0,`0```(M'.(M7/(D\)`4``/[_@]+_)0``_O^)1"0$B50D".C\____
+MA<`/A=;S___IP/?__Y"-="8`BU0D-(D4).C\____Z=;S__^-5"1(QT0D!``"
+M``")%"3H_/___^D/____C;8`````55=64X/L7(ML)'#'1"0$`0```(M%#(D$
+M).C\____C50D.(G'BT4$B50D!(M4)'2)%"3_4#R+ARP"``"+ER@"``")0@2)
+M$(L'BU@,@\`,.<-U#>M_BP>+&X/`##G8='2-L]C]__^`?@@!=>F+1ER+500[
+M4`0/A"<!``")1"0$B2PDZ/S___^#^`!\2'7'C40D%(M5!(E$)`2+1F")!"3_
+M4CP/ME0D1@^V1"0BT.K0Z(/B`8/@`3G"?YM\&`^V1"0D.$0D2'>.<@L/MD0D
+M23I$)"5W@8M3!(V'*`(``(E#!(F?*`(``,='(`$```")`H"/'`(```&+102)
+MERP"``")1U2+5"1TB6]<B5=@BT0D>(E'6(M4)#B+3"0\B5<XB4\\BT0D0(E/
+M&(E7%(E'2`^V1"1*B$=.#[=$)%!FB4=,#[94)$8/MD=2@^(!`=*#X/T)T(A'
+M4HU'9(D$),=$)`0H````Z/S___^-1"0XBU=4B40D!(M'8(D$)/]2/(M$)%3V
+M1"1&`74)]H```0``!'4(B3PDZ/S___^#Q%R)^%M>7UW#BY*`````A=(/A,O^
+M__^+0`B)1"0$BT4(B00D_]+IP_[__XVV`````(V\)P````!3@^P(BUPD$(![
+M"`%T"KC_____@\0(6\.`/0`````"=.V+0SB+4SP%``#^_XG!@]+_@>$``/[_
+MB=B)2Q2)4QCH_.___X!C4/3'0QS_____B1PDZ/S___\QP.NXD(UT)@"#[!R+
+M1"0HB70D%(MT)"")?"08BWPD)(E<)!"%P'AQB40D"(E\)`2)-"3H_/___X7`
+MB<-T3`^V0%"+=@RH`G5P@#T``````'08J`%U;?9#4$1U!(!+4"2+AB0!``"%
+MP'1CB5PD)(MT)!3'1"0@`@```(M<)!"+?"08@\0<Z?S___^+1@2)/"3_4$"-
+MM@````"-1A"+7"00B7PD)(MT)!2)1"0@BWPD&(/$'.G\____D(D<).C\____
+MZZ>)'"3H_/___^N)C888`0``QX8D`0```0```,>&&`$```````")MAP!``#'
+MAB`!````````B40D!(U&)(D$).C\____Z5____^-M"8`````C;PG`````%57
+M5E.#[#R+1"10B40D&(MH)(MX,(MU)(7V#X0"`@``B?/'1"0<`````.L*C70F
+M`(L;A=MT(#G[=/:+4PB+3PB+0P0S1P0QT0G!=>2)7"0<BQN%VW7@BT0D'(7`
+M#X3Y````BTPD'(M'#(M1#(M)$(E$)"")5"00BU<0B4PD%#G1B50D)'):=P8Y
+M1"00<E*)?"0$B2PDZ/S___^`35`0BT0D&(D$).C\____B6PD4(/$/%M>7UWI
+M_/___XVV`````(M$)""+5"0DBTX(`T<$$U<(,T8$,=$)P71`BS:%]G0-BUX4
+MA=MTV8LVA?9U\XM,)!S'1Q0`````BT$$`T$,BU$($U$0B4<$BT0D$"E'#(E7
+M"(M4)!095Q#K@(M,)!R+400!5"00BTD($4PD%(M$)!"+5"04BTPD'(E&!(M&
+M#(E6"(M6$`-'#!-7$"M!#!M1$(E&#(E6$.DS____,=OK!Y"+-H7V=%F+3A2%
+MR77SBU8$BTX(BT<$B50D,(M7"(E,)#2+3"0TB40D*`-'#(E4)"P35Q`S1"0P
+M,=$)P71^BT0D,(M4)#2+3"0L`T8,$U80,T0D*#'1"<%UIXET)!SKH8M4)!S'
+M1Q0`````A=)T*(M,)!R+002+40B)1P2+00R)5PB+41`!1PP15Q")3"0$B2PD
+MZ/S___^%VP^$G/[__XM##(M3$`%'#!%7$(E<)`2)+"3H_/___^E__O__B?/I
+M/O___\='%`````"-M"8`````Z67^__^-="8`C;PG`````%4Q[5=64X/L+(M\
+M)$R+1"1$BU0D2(7_B40D$(E4)!0/A``!``"+5"1,BVHPA>T/A/$```"+1"1`
+MBU@DA=L/A)$```#'1"08`````,=$)!P`````ZPPY1"1,=`V+&X7;=$F+0Q2%
+MP'7MBTL0.4PD%(M3#'<,<FHY5"00=F2-="8`A<!UUX7M=-.+102+50B+2P@#
+M10P351`S0P0QT0G!=;N)7"0<BQN%VW6WBT0D'(7`=!:+3"0<BT$,BU$0`T4,
+M$U40.50D%'8QBT0D&(7`#X5^````,>V#Q"R)Z%M>7UW#BW0D&(7V=`N+="08
+M.TX0=X]S'XE<)!CKAXVT)@````!S1(EL)!B+1"08A<!TQHGVZT`[5@P/@V7_
+M__^)7"08D.E;____BTPD0(M<)!0Y62QRH@^'_/[__XMT)!`Y<2ARD^GN_O__
+M.40D$`^'>/___^NPBUPD0,=$)`0$````BP.)!"3H_/___X7`B<4/A&3___^)
+M6"2+="1`BTXXBUX\@<$``/[_B<B#T_\E``#^_XE$)""#1"0@`8E<)"2#5"0D
+M`#';BU8DA=)T(XVV`````(M"%(7`=!"+2"BX`0```"M,)"#3X`G#BQ*%TG7C
+M,<FX`0```-/@A<-T*H/!`8/Y!'7MQT4H`````,=%+`````")+"0Q[>C\____
+M@\0LB>A;7E]=PXG*B<C!^A\#1"0@$U0D)(E%*(G1"<&)52QTT8MT)!2+7"00
+MBT0D0(EU&(MT)!B)712+7"00BU8$BTX(BW0D%(D<)(ET)`3H(=W__X7`=)V)
+M:!2)13"+="1`@$Y0$(DT).C\____Z6C^__^)]E93@^P$BW0D$(M&)(7`=0CK
+M3XL`A<!T28M0%(72C78`=/"+6@R%VW0N@'LP`'0H,<GK"P^V0S"#P0$YR'X9
+M.52+2'7O#[9#,,=$BT@`````@\$!.<A_YXD4).C\____ZZB)-"3H_/___XM6
+M5(M&8(D$)/]29(ET)!"#Q`1;7NG\____C;8`````C;PG`````%93@^P$BW0D
+M$(M>)(!F4+^%VW0PBT,4A<!T"(D$).C\____BQN%VW7KBU8DA=)T%(M"%(7`
+M=`>+2`R%R704BQ*%TG7LB70D$(/$!%M>Z?S___^)!"3H_/___XM6).O-D%57
+M5E.#[`R+1"0@BV@0B40D!(V%L````(D$)(U]#.C\____BUT,QX4D`0``````
+M`#G[=0CK+XL;.?MT*8V#V/W__X!X"`%U[O9`4$!TZ/:`'`(```%TWXD$).C\
+M____BQLY^W77BUT4C744.?-T$I"-0_2)!"3H_/___XL;.?-U[XMU##G^#X2N
+M````C70F`(V&V/W__X!X"`1V"XM8#(7;#X1!`0``BS8Y_G7CBUT,.?L/A((`
+M``#&1"0+`.L'D(L;.?-T/HV3V/W__X!Z"`%U[O9"4"!TZ(M")(!B4-N%P'4/
+MZ<@```"+`(7`#X2^````BT@4A<ET[XL;QD0D"P$Y\W7"BUT,.=]U"^LMC78`
+MBQLY^W0DC8/8_?__BV@<A>UX'_:`'`(```%UY(D$).C\____BQLY^W7<@\0,
+M6UY?7</V@!P"```!=,4/ME`(@/H$=G:+<`R%]G6U]H!(`0``0'6LBY!D`0``
+MA=)T!3E"!'6=#[9P,(7V?B0QR8M4B$B%TG03@'H(!'8-]H)(`0``0`^%>/__
+M_X/!`3GQ==Z)!"3H_/___^ED____C70F`(!\)`L`#X4%____B10DB?;H_/__
+M_^GV_O__@.H!C78`#X4Z____]D!0`HVV``````^$*O___^NWB00DD(UT)@#H
+M_/___^FM_O__C;8`````5U93@^P0BWPD((V'L````(D$).C\____A<")QG15
+MBU\,B7@0@\<,QP`!````QT`$8#P#`#G[B48(QT`,`````'4(ZR2+&SG[=!Z-
+M@]C]__^`>`@!=>Z)="0$B00DZ/S___^+&SG[=>*+!H/H`87`B09T!X/$$%M>
+M7\.)="0@@\006UY?Z7?]__^-M"8`````@^P<B70D%(MT)"")7"00B7PD&(M>
+M$,=#(`````#VAAP"```8=7R+AI@```"%P'5R#[9#**@!=6JH`HU["'06.7L(
+M=00Y&W04B?#H`=;___9#*`%U38M+"#GY=58/MD9..4,0<A+K.XGPZ"+2__\/
+MMD9..4,0<RN)\.CRT?__A<")PG0>#[=`9&8E_S!F/00@==4Y&W5+]D92`G3+
+M@$LH`NO%BUPD$(MT)!2+?"08@\0<PXM[$(7_=>F+$8M!!(E"!(D0BU$,B?")
+M"8E)!(M<)!"+="04BWPD&(/$'.FOT?__QD)F`8D4).C\____B?#H?-'__XG"
+MZ6S___^0C70F`(/L'(E<)!"+7"0@B70D%(E\)!B)V(M[*.A#T?__@'MD!(MW
+M$(G"='B+0W#'1B0`````B3+'0A``````B4((BT8$B5H,B58$QT-PP$`#`(E"
+M!(D0#[9'3CE&$','BT8@A<!T$(M<)!"+="04BWPD&(/$',.-1A3'1B`!````
+MB40D!(L'@\`LB00DZ/S___^+7"00BW0D%(M\)!B#Q!S#B?;V0V4P=`KV1B@"
+M#X1X____QD-F`8MT)!2)7"0@BWPD&(M<)!"#Q!SI_/___XUT)@"#[!R)="00
+MBW0D((E<)`R)?"04B6PD&(GPZ'+0__^+7BB+>Q")Q8-O$`$/MD9F/`UT7CP1
+M#X1]````/`MT8CP0#X20````BT4(B49PB30DZ/S___^+1R"%P'4;C4<4QT<@
+M`0```(E$)`2+`X/`+(D$).C\____BUPD#(MT)!"+?"04BVPD&(/$',.-M@``
+M``"`?F0`=;"`?F<`=6K&1F<!QD9F`(M7#(U'"(EO#(E%`(E5!(DJZYV)V.C"
+MT___A<!U"`^V1F<\`79"#[9&9CP0#X5P____@'YD`P^$9O___XM#$(ES$(E<
+M)`3'!"0#````B40D".C\____BT0D"(E#$.E`____QD9F$.O*@\`!B$9GZXR0
+MD)"0D)"0D)"0D)!64XL=`````(MT)`R%VW0MBU,,C4L,.<IU#.L;C70F`(L2
+M.<IT$8V"V/W__SFP6`(``'7L6U[#BQN%VW73,<"0Z_*-M"8`````C;PG````
+M`(!X!`!U#8$X>P$```^7P`^VP,.!.'L!```/E\`/ML##4XG!#[8:#[8`.-AT
+M%>LID`^V60$/MD(!.,-U$(/!`8/"`83`=>HQTEN)T,,/OM,/OL!;*<*)T,,/
+MOM`/OL,IPNOFC;0F`````(V\)P````!55U93@>R<````BRT`````B40D&(E4
+M)!2%[71!,?:-?"0DBUT(A=MT+8E\)!"-=@"+4P2)?"0$BT,(B00D_U(<@'PD
+M-P!T"3MT)!AT'X/&`8L;A=MUVHMM`(7M=<4QVX'$G````(G86UY?7<.+1"04
+MA<!TZXM4)!2+`@^V5"0[.=!\W(L;A=MTUBG0BU0D%(D"BT0D$(M3!(E$)`2+
+M0PB)!"3_4AR`?"0W`'3(ZZ^)]E575HG.4X'LG````(E$)`RA`````(N\)+``
+M``#'`0````")5"0(A<#'!P````")1"00#X21````O?_____'1"04`````(M4
+M)!"+6@B%VP^$@````(7_#Y5$)!OK%HUV`(L;#[9$)#L!!HM4)!0!%X7;=&&-
+M5"0DBT,$B50D!(M3"(D4)/]0'(M#!(N0A````(72=!.`?"0;`'0,BT,(B00D
+M_]*)1"04@'PD-P!T#\<&`````(/%`<<'`````#M<)`QUG8M$)`B)*('$G```
+M`%M>7UW#BT0D$(L`A<")1"00#X5?____Z^&0C;0F`````%575C'V4X'LC```
+M`(L]`````(7_="^-;"04BU\(A=MT'HM3!(EL)`2+0PB)!"3_4AR+&X!\)"<!
+M@][_A=MUXHL_A?]UU8'$C````(GP6UY?7<.-M"8`````C;PG`````%57B<]6
+M4X'LS````(E4)!B-5"08Z.?]__^)1"00BU0D$+C_____A=(/A/D```"+1"00
+MBW`,,<#&!#@`@\`!@_A$=?2+5"00BTPD$(M"!(U4)"B)5"0$BU$(B10D_U`<
+M@'PD.@]V!<9$)#H/BT0D$(M,)!"+4`2-A"3$````B40D"(M$)!B)1"0$BT$(
+MB00D_U)<A<`/A)@```"+7@R-;@PYZP^$?0```,9$)!<`ZP>0BQLYZW1OC;/8
+M_?__@'X(`77NBT0D$#M&7'7EC8PDH````(M65(E,)`2+1F")!"3_4CSVA"2N
+M`````G7$#[:$)+`````[1"08=;8/MH0DL0```#I$)#ISJ`^VT(N&6`(``(!$
+M)!<!B427"`^V1"07.$0D.G6+,<"!Q,P```!;7E]=PXN$),@```")1P2+A"3$
+M````B0?I4/___XVV`````(/H!3'2@_@'=PS_)(7L#0``N@$```")T,.Z"```
+M`(G0P[H"````B=##N@<```")T,.Z`P```(G0P[H$````B=##N@4```")T,.Z
+M!@```(G0P^L-D)"0D)"0D)"0D)"0D%:)UE,/MH@<`@``B<,/ME(,B<B#\`&#
+MX`'VPB!T`X/((/;!!'0#@\@"@^$"=`.#R`2#XA!T`X/($`^V5@[VP@%T`X/(
+M0(/B`G0"#(`/ME-0]L($=`4-````@/;"`G0%#0```@"#X@%T!0T```$`]D-2
+M`70%#0``!`!;7L.-="8`55>_Z`,``%93@^PLBT0D0(N84`$``(N(3`$```^V
+M:#`/K-D+B<C!ZPOWYVGSZ`,``(G!C1P6BW0D0(M6&(M&%(D,)(E<)`2)ZP^L
+MT`O!Z@N)1"0(B50D#.C\____BTX$#[9)!BG+N0H```#WX_?AA>V)1"0D#XZ2
+M````,?:-=@"+1"1`BURP2(7;=';V@QP"```!=&V`>P@$=F?V@T@!``!P=%Z+
+M4P0/MD,P#[92!BG0BY-0`0``C02`C3P`BX-,`0``#ZS0"VG(Z`,``(M#%,'J
+M"XM3&`^LT`O!Z@N)1"08B<B+3"0DB50D'#'2]W0D&`^O^(7)=`8Y?"0D=@2)
+M?"0D@\8!.?4/A7/___^+1"0D/1`G``!V!;@0)P``@\0L6UY?7<.-="8`C;PG
+M`````(/L+(M$)#")7"0<B70D((E\)"2);"0HBZAD`0``#[9%9CP"#X6J````
+MBT4(BU`4BT@8BT4$B50D$(MT)!")3"04BWPD%(M(%(M8&+@0)P``*<X9WP^L
+M_@O![PN)^@GR=$Z`?10`=5R+15R+56`IR!G:#ZS0"[GH`P``P>H+:=KH`P``
+M]^&)="0(B7PD#(T4$XD$)(E4)`3H_/___[D*````]^$]$"<``'8%N!`G``"+
+M7"0<BW0D((M\)"2+;"0H@\0LPXM$)!"+5"04*T5<&U5@ZYX\`P^$E0```(!]
+M%`!T/HM%"(M8&+[H`P``BT@4B=J)R"M%7!M58`^LV0O!ZPL/K-`+P>H+:?KH
+M`P``]^:)3"0(B5PD#(T4%^EQ____BUU@O^@#``"+35P/K-D+B<CWY\'K"VGS
+MZ`,``(G!BT4(C1P6BU`8BT`4B0PDB5PD!`^LT`O!Z@N)1"0(B50D#.C\____
+MN0H```#WX>DS____@'T4`'0(BT4$Z6;___^+76"_Z`,``(M-7`^LV0N)R/?G
+MP>L+:?/H`P``B<&+102-'!;KGXVV`````(V_`````%93BT@,B<.%R70S#[9!
+M,(3`#[;P=!@QTCE92'06,=+K!CE<D4AT#(/"`3GR=?-;,<!>PXM!)%M>@\`!
+M`=##BT`D6U[#C;8`````C;\`````55>)UU93@^P$B00D#[9H,(7M?E,Q]HL$
+M)(M4L$B%TG0_]H(<`@```70V@'H(!'9!#[9:,(7;?B@QR8VV`````(M$BDB%
+MP'0.]H`<`@```70%.7@D=!.#P0$YV77CC78`@\8!.>YUKS'`@\0$6UY?7<,Y
+M>B1UZHG0Z^^-M@````!55U93@^Q`B40D&(M<)!B(5"07#[9$)%@/ME0D7(E,
+M)!"%VXA$)`^(5"0.#X1/`0``BTPD&(!Y"`</E,"`?"07!P^4PH3`#X48`0``
+MA-(/A2P!``"+3"00A<D/A"<#``#'1"0<_____S'_,>W'1"0@_____\=$)#@`
+M````C70F`(M4)#B+3"14BP21B00DZ/S___^%P(G##X2W````BU0D&(L`.P(/
+MA:D```"`>P@!#X6?````BT0D&(G:Z,#^___'1"0L`````(7`B<9T!XM(,(E,
+M)"R+6R2%VP^$%0$``(G8,=(QR8-X%`!T!H/"`8/1`(L`A<!U[H/Y`'<)@_H#
+M#X;O````QT0D)`````#'1"0H`````,=$)!P`````QT0D(``````#?"0DBU0D
+M$!-L)"B#1"0X`3E4)#@/A3____\/MDPD#X/A#X!\)!<'#X;'`0``,?\Q[8/$
+M0(GXB>I;7E]=PXM,)!@/MD$P/`$/A.#^__^$TG0(A,`/A?L!``"+7"00A=L/
+MA/L!```QVS'_,>W'1"0<_____\=$)"#_____ZSF`>`@!=:J+4"R+0"B)T0G!
+M=)X!QQ'5.50D('(0=P8Y1"0<=@B)1"0<B50D((/#`3M<)!`/A&3___^+5"14
+MBP2:B00DZ/S___^%P'6TZ5____^%]L=$)"0`````QT0D*`````!T#HM&%(M6
+M&(E$)"2)5"0HA=L/A)8```#'1"0P`````.LDC;0F`````(M#%#G&=!"+5"0L
+MA=)T'H7`#X2A````BQN%VW0VA?:0==Z+5"0LBT,4A=)UXH7`=>:+4Q`[5"0H
+MBT,,<MIW!CM$)"1VTHL;B40D)(E4)"B%VW7*BT0D+(7`="J+="0PA?9T(HM,
+M)#"+00R+41"+3"0L`T$,$U$0.50D*'<(<F(Y1"0D<ER+1"0H.40D(`^"8_[_
+M_W<.BU0D)#E4)!P/AE/^__^+1"0DBU0D*(E$)!R)5"0@Z3[^__^+3"0LBT$$
+MBU$(`T$,$U$0BTL(,T,$,=$)P0^%6?___XE<)##I4/___XE$)"2)5"0HZYH/
+MMD0D%_\DA0P.``"#?"00`0^&(O[__X-\)!`"BWPD'(ML)"`/AA/^__\/ML&Z
+M_____XG!BT0D'-/BB=/1;"00(="+5"0@BTPD$,'['R':B=8/K_'WX8G'C2P6
+MZ=W]__^+5"00A=(/A?H````Q_S'MQT0D'/_____'1"0@_____^FA_?__@WPD
+M$`,/AJG]__\/ML&Z_____XG!BT0D'-/BBTPD$(G3P?L?(="+5"0@@^D"(=KK
+MF8-\)!`"#X9X_?__#[;!NO____^)P8M$)!S3XHM,)!")T\'['R'0BU0D((/I
+M`2':Z67___^`?"0.`0^&,0$``(!\)`X"#X8,____#[9T)`XQTHM$)!#W]H72
+MB<,/A2+]__^#ZP$/CAG]__^#[@'W[HG&#[;!B<&+1"0<B=>Z_____]/BB=,A
+MT(M4)"#!^Q^)P0^OSXE$)`0AVHG3#Z_>B50D"/?F`=F)QXTL$>G7_/__BT%(
+M,?:%P'4?Z<7\__\Y="00#X;G_/__BU0D&(M$LDB%P`^$J_S__XM,)%2+6"2+
+M!+&)!"3H_/___SG#=!6+5"08@\8!#[9",#GP#X:N_/__Z[N+3"08#[9!,`^V
+MT#E4)!")5"0T#X)G_/__A,!T=HM!2#'VA<!U+.E5_/__D(M,)!B#Q@$/MD$P
+M#[;0.?*)5"0T=E&+3"08BT2Q2(7`#X0N_/__BU0D5(M8)(L$LHD$).C\____
+M.<-TQ.D3_/__#[;!NO____^)P8M$)!S3XHM,)!")T\'['R'0BU0D("':Z0/^
+M__^+3"08#[;`BW2!1(MY%(MI&(M&)(M8)(7;=0CK+XL;A=MT*8M#%(7`D'7R
+MBTXPBT$$BU$(`T$,$U$0BTL(,T,$,=$)P777`WL,$VL0BU0D-#E4)!`/AI?[
+M__^+3"14C1R1ZSJ-M@````"+3"08BP`[`0^%=OO__X!Z"`$/A6S[__\#>BB+
+M1"00$VHL@\,$@T0D-`$Y1"0T#X14^___BP.)!"3H_/___X7`B<)UO.D[^___
+MC;0F`````//#C;0F`````(V\)P````!6BS4D`@``4XM,)`R-5@&)T,'X'\'H
+M'(T<`H/C#RG#N/____\['2`"``!T;8L!:]8LB8)``@``BT$$B8)$`@``BT$(
+MB8)(`@``BT$,B8),`@``BT$0B8)0`@``BT$4B8)4`@``BT$8B8)8`@``BT$<
+MB8)<`@``BT$@B8)@`@``BT$DB8)D`@``BT$HB1TD`@``B8)H`@``,<!;7L.-
+M="8`@^P\BU0D0(E<)#2+3"1(B70D.(M<)$P/MW0D4`^V0@@\`70R/`1T2(U4
+M)!2#?"1$`1G`@\`9B$0D$(U$)`AFB7((B00DZ/S___^+7"0TBW0D.(/$/,.+
+M@E@"``"-5"04B4PD%(E<)!B)1"0,Z[Z)]HM",(M2)`-(!(N26`(``!-8"(E,
+M)!2)5"0,C50D%(E<)!CKF(VV`````(V_`````%93@^PDQD0D'`:+6`B%VW0B
+MC70D'(M#"(E$)""+0P2)="0$QP0D`````/]08(L;A=MUXH/$)%M>PXVT)@``
+M``!55U93@^P$BU0D&(ML)!R+0B@/MUI0BXAD`0``B=^+,,'G"8!Y%`!T"O9"
+M900/A8H````/MU%:P>()BXY@`0,`A?^+MF0!`P")-"1T7(G0,=+W]HT$0(G3
+MC32!C4T0ZR^+!@'8B4'XBP0D*=@Y^(E!\'8"B?@IQXG-A?^)0?#'0?0`````
+MC4D0=!^#Q@PQVXML)""%[77),=*)V`-&!!-6"(E!^(E1_.N^QT7T`0```(/$
+M!+@!````6UY?7<,/MU%8#[=!6BG"*=K!X@GI:?___^L-D)"0D)"0D)"0D)"0
+MD%6)U5=64X/L!(D$)(!Z,`!T:3'_ZR:+%"2+1C"+2C"+4`B+0`2+60@S000Q
+MTPG#=#0/MD4P@\<!.?A^/XMTO4B%]G3M@'X(!';,BP0DB?+HK/___X3`=-F#
+MQ`2X`0```%M>7UW#BQ0DBT8D.T(D=.@/MD4P@\<!.?A_P8/$!#'`6UY?7<.-
+M="8`C;PG`````%6)U5>)QU93@'@P`'1`,?;K%(GJB=CHY?___P^V1S"#Q@$Y
+M\'XHBURW2(7;=.V`>P@$=]Z)ZHG8Z#/___^$P`^40S0/MD<P@\8!.?!_V%M>
+M7UW#C;8`````C;PG`````%93B=.`>`@!=`5;,<!>PX72=%&+DF0!``"%TG1'
+MBW($.=YT1(M0)(72=#&0C70F`(M"%(7`=!^%VW4)D(UT)@#KR(G(BT@,A<EU
+M]SG8C78`=`0Y\'6TBQ*%TG746[@!````7L.)WNN\BW((Z[>-=@"+1"0$BU`0
+MA=)X!H-X%`-W!\=`+/[____SPXVV`````(M$)`2!>!#'````=@F!>!3'````
+M=P?'0"S^____\\.0BT0D!(%X$,<```!V"8M(%(7)>`+SP\=`+/[____#B?:+
+M1"0$BU`0A=)X!H-X%`-W!\=`+/[____SPXVV`````(M$)`2#>!`#=@:#>!1+
+M=P?'0"S^____\\.-M"8`````BT0D!(-X$`-V!H-X%%=W!\=`+/[____SPXVT
+M)@````"+1"0$@W@0`W8&@W@40W<'QT`L_O____/#C;0F`````(M$)`2#>!`'
+M=@:#>!0/=P?'0"S^____\\.-M"8`````BT0D!(-X$`=V!H-X%$-W!\=`+/[_
+M___SPXVT)@````"+1"0$@W@0`W8&@W@4`W<'QT`L_O____/#C;0F`````(M$
+M)`2#>!`'=@F!>!3_````=P?'0"S^____\\.-="8`BT0D!(-X$`=V"8%X%*,,
+M``!W!\=`+/[____SPXUT)@"+1"0$@W@0!W8)@7@4)PT``'<'QT`L_O____/#
+MC70F`(M$)`2#>!`'=@F!>!2K````=P?'0"S^____\\.-="8`BT0D!(-X$`MV
+M!H-X%"=W!\=`+/[____SPXVT)@````"+5"0$BT(8@WH0`XL`=@R-!(4$````
+M.4(4<P?'0BS^____\\.-M@````"-OP````"+5"0$BT(8@WH0`XL`=@R-!(4$
+M````.4(4<P?'0BS^____\\.-M@````"-OP````!3@^P$BUPD#(M#&(-[$`.+
+M`'8)@7L4K0```'<,QT,L_O___X/$!%O#B00DZ/S___^%P'3H@\0$6\.-M"8`
+M````4X/L!(M<)`R+0QB#>Q`#BP!V"8%[%-<```!W#,=#+/[___^#Q`1;PXD$
+M).C\____A<!TZ(/$!%O#C;0F`````%.#[`2+7"0,BT,8@WL0`XL`=@F!>Q3Y
+M````=PS'0RS^____@\0$6\.)!"3H_/___X7`=.B#Q`1;PXVT)@````"#[`R)
+M7"0$BUPD$(ET)`B+0QB#>Q`(BTL<BS!V!H-[%`1_$\=#+/[___^+7"0$BW0D
+M"(/$#,,/ME`(BT`$A-*)`8A1!'0@@3G#`0``=M6)-"3H_/___X7`=,F+7"0$
+MBW0D"(/$#,,]PP$``':VZ]^0@^P,B70D"(MT)!")7"0$@7X0LP```'8&@WX4
+M!W<3QT8L_O___XM<)`2+="0(@\0,PXM&&(L8B1PD@^L!Z/S___^#^_UWWX7`
+M=-2`>`@$B?9VS(N(9`$``(7)=<+KQXGV@^P0B70D"(MT)!2)7"0$B7PD#(-^
+M$`AV!H-^%`=W%\=&+/[___^+7"0$BW0D"(M\)`R#Q!##BWX8BQ^)'"2#ZP'H
+M_/___X/[_7<1A<!T!H!X"`1W%<=&+/[___^-1P3HC.G__RP!=;?KO(N89`$`
+M`(7;=>'KYHUV`(V\)P````"#[!2)?"0,BWPD&(E<)`2)="0(B6PD$(M7&(LJ
+MC02M!````#E'$')*BW<4A?9X0X`]``````)T.C'VA>UU"XGVZS<Y[G0SBU<8
+M@\8!BQRRB1PDZ/S___^%P'07B1PDZ/S___^)PHL`.T<(=2'V0E`!==#'1RS^
+M____BUPD!(MT)`B+?"0,BVPD$(/$%,/'1RS\____Z^.-=@"-O"<`````@^P4
+MB7PD#(M\)!B)7"0$B70D"(EL)!"!?Q"'````BW<8=@V#?Q0#=R>-M"8`````
+MQT<L_O___XM<)`2+="0(BWPD#(ML)!"#Q!3#D(UT)@`/MD8!/`AWV#'MA,!U
+M'HGVZ]6)'"3H_/___XL`.T<(D'4A@\4!B>@X1@%VNXGJ#[;"BUR&:(D<).C\
+M____A<!UT>N=QT<L_/___XVV`````.N5C;0F`````(V\)P````"+1"0$@W@0
+M`W8&@W@4`W\'QT`L_O____/#C;0F`````(/L"+H0````BTPD#(D<)(ET)`2+
+M01B+6`B+<`R+01"%VW0#C580.<)W"X7;BT$4=0LYQG8'QT$L_O___XL<)(MT
+M)`2#Q`C#B?:-O"<`````@^P4B7PD#(M\)!B)7"0$B70D"(EL)!"!?Q"O````
+MBW<8=@V#?Q0#=R>-M"8`````QT<L_O___XM<)`2+="0(BWPD#(ML)!"#Q!3#
+MD(UT)@`/MD8!/!!WV#'MA,!U'HGVZ]6)'"3H_/___XL`.T<(D'4A@\4!B>@X
+M1@%VNXGJ#[;"BUR&<(D<).C\____A<!UT>N=QT<L_/___XVV`````.N5C;0F
+M`````(V\)P````"#[!2)7"0$BUPD&(ET)`B)?"0,B6PD$(-[$`2+<QA^!H-[
+M%`-W&\=#+/[___^+7"0$BW0D"(M\)`R+;"00@\04PXGPZ+CF__\L`77:#[9&
+M#3Q`=](Q[83`=1_KT8UT)@")/"3H_/___XL`.T,(=2&#Q0&)Z#A&#7:TB>H/
+MML*+?(9\B3PDZ/S___^%P'72ZY;'0RS\____ZY2-M"8`````@^P4B5PD!(M<
+M)!B)="0(B7PD#(EL)!"+>QB!>Q"S````BS=V!H-[%`-W&\=#+/[___^+7"0$
+MBW0D"(M\)`R+;"00@\04PXDT).C\____A<!TV8DT).C\____BP`[0PAT"<=#
+M+/S____KR(/'!`^V1P$\$'>V,>V$P'4>Z[6-=@")-"3H_/___XL`.T,(==*#
+MQ0&)Z#A'`7:9B>H/ML*+=(=PB30DZ/S___^%P'72Z7C___^-M@````"-O"<`
+M````@^P4B5PD!(M<)!B)="0(B7PD#(EL)!"+>QB#>Q`(BS=V!H-[%`-W&\=#
+M+/[___^+7"0$BW0D"(M\)`R+;"00@\04PXDT).C\____A<!TV8DT).C\____
+MBP`[0PAT"<=#+/S____KR(/'!(GXZ"_E__\L`76S#[9'#3Q`=ZLQ[83`=1OK
+MJHDT).C\____BP`[0PAURH/%`8GH.$<-=I&)Z@^VPHMTAWR)-"3H_/___X7`
+M==+I</___Y"-M"8`````BT0D!(M0$(72>`:#>!0K=P?'0"S^____\\.-M@``
+M``"#[`R)7"0$BUPD$(ET)`B+0QB#>Q`(BS!V-HM+%(7)>"^)-"3H_/___X7`
+M=".)-"3H_/___XL`.T,(=!O'0RS\____BUPD!(MT)`B#Q`S#D,=#+/[___^+
+M7"0$BW0D"(/$#,.-M@````"-O"<`````@^P,B5PD!(M<)!")="0(BT,8@WL0
+M"(LP=C:+0Q2%P'XOB30DZ/S___^%P'0CB30DZ/S___^+`#M#"'0;QT,L_/__
+M_XM<)`2+="0(@\0,PY#'0RS^____BUPD!(MT)`B#Q`S#C;8`````C;PG````
+M`(/L#(E<)`2+7"00B70D"(M#&(-[$`B+,'8VBT,4A<!X+XDT).C\____A<!T
+M(XDT).C\____BP`[0PAT&\=#+/S___^+7"0$BW0D"(/$#,.0QT,L_O___XM<
+M)`2+="0(@\0,PXVV`````(V\)P````"#[`R)7"0$BUPD$(ET)`B+0QB#>Q`-
+MBS!V-HM#%(7`>"^)-"3H_/___X7`=".)-"3H_/___XL`.T,(=!O'0RS\____
+MBUPD!(MT)`B#Q`S#D,=#+/[___^+7"0$BW0D"(/$#,.-M@````"-O"<`````
+M@^P,B5PD!(M<)!")="0(BT,8@WL0#8LP=C:+0Q2%P'XOB30DZ/S___^%P'0C
+MB30DZ/S___^+`#M#"'0;QT,L_/___XM<)`2+="0(@\0,PY#'0RS^____BUPD
+M!(MT)`B#Q`S#C;8`````C;PG`````(/L#(E<)`2+7"00B70D"(M#&(-[$`V+
+M,'8VBT,4A<!X+XDT).C\____A<!T(XDT).C\____BP`[0PAT&\=#+/S___^+
+M7"0$BW0D"(/$#,.0QT,L_O___XM<)`2+="0(@\0,PXVV`````(V\)P````"#
+M[`R)7"0$BUPD$(ET)`B+0QB#>Q`#BS!V6XM#%(7`>%2)-"3H_/___X7`=$B)
+M-"3H_/___XG"BP`[0PAT$\=#+/S___^+7"0$BW0D"(/$#,.`>@@$=AZ+@F0!
+M``"%P'04@'AG`'4.#[:"20$``(/@&#P(=`?'0RS^____BUPD!(MT)`B#Q`S#
+MD(VT)@````"#[`R)7"0$BUPD$(ET)`B+0QB#>Q`#BS!V/8M3%(72>#:)-"3H
+M_/___X7`="J)-"3H_/___XG"BP`[0PAT$\=#+/S___^+7"0$BW0D"(/$#,.`
+M>@@!=`?'0RS^____BUPD!(MT)`B#Q`S#C;8`````@^P,B5PD!(M<)!")="0(
+MBT,8@WL0`XLP=CV+2Q2%R7@VB30DZ/S___^%P'0JB30DZ/S___^)PHL`.T,(
+M=!/'0RS\____BUPD!(MT)`B#Q`S#@'H(`70'QT,L_O___XM<)`2+="0(@\0,
+MPXVV`````(/L$(E<)`2+7"04B70D"(E\)`R+0QB#>Q`'BS"+>`1V?XM#%(7`
+M>'B)-"3H_/___X7`=&R)/"3H_/___X7`B?9T7HDT).C\____B3PDB<;H_/__
+M_XG"BP8[0PAT%\=#+/S___^+7"0$BW0D"(M\)`R#Q!##.P)UY8M&!(!X!@!T
+M'X!Z"`%U&8M&0`M&1'01BX9D`0``A<!T#H!X9P!T")#'0RS^____BUPD!(MT
+M)`B+?"0,@\00PXGVC;PG`````(/L#(E<)`2+7"00B70D"(M#&(-[$`>+,'8]
+MBT,4A<!X-HDT).C\____A<!T*HDT).C\____B<*+`#M#"'03QT,L_/___XM<
+M)`2+="0(@\0,PX!Z"`1W!\=#+/[___^+7"0$BW0D"(/$#,.-M@````"#[`R)
+M7"0$BUPD$(ET)`B+0QB#>Q!7BS!V1HM#%(7`>#^)-"3H_/___X7`=#.)-"3H
+M_/___XG"BP`[0PAT$\=#+/S___^+7"0$BW0D"(/$#,.`>@@$=@F+0@R%P'0)
+MB?;'0RS^____BUPD!(MT)`B#Q`S#C;8`````C;PG`````(/L#(ET)`B+="00
+MB5PD!(M&&(-^$$.+&'8XBT84A<!X,87;=#2)'"3H_/___X7`D'0@B1PDZ/S_
+M__^)PHL`.T8(=`G'1BS\____ZPV`>@@!=`?'1BS^____BUPD!(MT)`B#Q`S#
+MC70F`(V\)P````"#[`R)="0(BW0D$(E<)`2+1AB#?A`(BQAV.(M&%(7`>#&%
+MVW0TB1PDZ/S___^%P)!T((D<).C\____B<*+`#M&"'0)QT8L_/___^L-@'H(
+M`70'QT8L_O___XM<)`2+="0(@\0,PXUT)@"-O"<`````BT0D!(M($(7)>`F+
+M4!2%TG@"\\/'0"S^____PXUT)@"+1"0$BU`0A=)X!H-X%"MW!\=`+/[____S
+MPXVV`````(M$)`2+2!"%R7@&@W@4?W<'QT`L_O____/#C;8`````@^P0B7PD
+M#(M\)!2)="0(OA````")7"0$BU\8BU<0#[9#"P^V2PS!X`F`^0)T,CG6=Q&`
+MZ0&+5Q2^$````'11.=9V(L='+/[___^+7"0$BW0D"(M\)`R#Q!##C;8`````
+MC7`0Z\F+`XD$).C\____A<!TT(L#B00DZ/S___^)PHL`.T<(=!/'1RS\____
+MZ[N0C7`0.=9WK.O,@'H(`8UV`'6AZZ:-M@````"-OP````"#[!")?"0,BWPD
+M%(ET)`B^%````(E<)`2+7QB+5Q`/MT,0#[9+$L'@"8#Y`G0R.=9W$8#I`8M7
+M%+X4````=%$YUG8BQT<L_O___XM<)`2+="0(BWPD#(/$$,.-M@````"-<!3K
+MR8L#B00DZ/S___^%P'30BP.)!"3H_/___XG"BP`[1PAT$\='+/S____KNY"-
+M<!0YUG>LZ\R`>@@!C78`=:'KIHVV`````(V_`````(/L#(E<)`2+7"00B70D
+M"(M#&(-[$`.+,'8VBT,4A<!X+XDT).C\____A<!T(XDT).C\____BP`[0PAT
+M&\=#+/S___^+7"0$BW0D"(/$#,.0QT,L_O___XM<)`2+="0(@\0,PXVV````
+M`(V\)P````"#[!2)?"0,BWPD&(E<)`2)="0(B6PD$(M7&`^V*HT$K00````Y
+M1Q!R/X-_%`-V.3'VA>UU">LX.>YT-(M7&(/&`8L<LHD<).C\____A<!T&(D<
+M).C\____BP`[1PATV,='+/S____K!\='+/[___^+7"0$BW0D"(M\)`R+;"00
+M@\04PXVV`````(V\)P````"#[!2)?"0,BWPD&(E<)`2)="0(B6PD$(M7&`^V
+M*HT$K00````Y1Q!R/X-_%`-V.3'VA>UU">LX.>YT-(M7&(/&`8L<LHD<).C\
+M____A<!T&(D<).C\____BP`[1PATV,='+/S____K!\='+/[___^+7"0$BW0D
+M"(M\)`R+;"00@\04PXVV`````(V\)P````"#[`R)7"0$BUPD$(ET)`B+0QB#
+M>Q`'BS!W%L=#+/[___^+7"0$BW0D"(/$#,.-=@")-"3H_/___X7`=-Z)-"3H
+M_/___XL`.T,(=-;'0RS\____BUPD!(MT)`B#Q`S#B?:+5"0$BT(8@WH0`XL`
+M=@R-!(4$````.4(4<P?'0BS^____\\.-M@````"-OP````!3@^P(BUPD$(M#
+M&(-[$`(/M@!V/(M3%(72>#4QT@^VP.B+VO__A<")PG0EBT`$BT!\A<!T&XM"
+M##M#"'0:QT,L_/___X/$"%O#C;0F`````,=#+/[___^#Q`A;PXUT)@"#[`RY
+M'````(E<)`2+7"00B70D"(MS&(M#$`^V5@2`^@)T+3G!=Q&`Z@&+0Q2Y"```
+M`'1..<%V(,=#+/[___^+7"0$BW0D"(/$#,.0C70F`(M.&(/!'.O+BP:)!"3H
+M_/___X7`=-*+!HD$).C\____B<*+`#M#"'05QT,L_/___^N]BTX8@\$(.<%W
+MK.O*@'H(`76D@'X'$'>>C;8`````ZYV-M"8`````C;PG`````%.+1"0(BUPD
+M#(M(+#'`@WPD$`"+41AT'8!Z!`%T&8U"'(E#"(M"&,=#!`$```")`[@!````
+M6\.+01R#P`B)0PCKXHVT)@````"-O"<`````@^P0B70D"(MT)!2)7"0$B7PD
+M#(M6$(M>&(/Z"W9EBWX4A?]X7H![!P!U=0^V0P;!X`F-2`PQP#G*<DB#P`0Y
+MQW)!BP.)!"3H_/___X7`=#.+`XD$).C\____B<*+`#M&"'0)QT8L_/___^L>
+M@'H(`741#[9#!@^W4P0!T#T`(```?@?'1BS^____BUPD!(MT)`B+?"0,@\00
+MPXVV``````^V0P:Y#````,'@">N)B?:#[!")7"0$BUPD%(ET)`B)?"0,BTL0
+MBW,8@_D'=B6+>Q2%_W@>A<D/ME8$#[9&!7@2#[;`#[;2`=#!X`F#P`@YQW,7
+MQT,L_O___XM<)`2+="0(BWPD#(/$$,.+!HD$).C\____A<!TVXL&B00DZ/S_
+M__^)PHL`.T,(=`G'0RS\____Z\:`>@@!=;F-M@````#KN(VT)@````"-O"<`
+M````5XG'5HG64X/L$*'``@``@_C_=&^+4@R[P`(``.L,B?:#PQ2+`X/X_W19
+M.=!U\H/``710QT8L`````(DT)(UV`/]3!(M&+(7`=4V`OX0!`P``=3"+2Q"%
+MR0^%C0```(N7*`$``(72=#J+ET0!``"-AT`!``")MT0!``")!HE6!(DRZPW'
+M1BS^____B30D_U8H@\006UY?PXDT)/]6*(UV`.ONBT,(B;<H`0``A<!T/(M#
+M#,>'+`$```$```")MS0!``#'AS@!````````B8<P`0``B30D_U,(BX<L`0``
+M@^@!A<")ARP!``!UI8DT)/]3#.N=C;8`````C;PG`````%.+"(V8"`(``,>`
+MV`$```__``")F.0!``")B-0!``"+B%@"``#'@-P!```(````QX#@`0``````
+M`,>`[`$```````")B`@"``")4P2-D,P!``#'@/0!``"@4`,`BX#4`0``6^F8
+M_O__D(VT)@````"#[`R)7"0$BUPD$(ET)`B+<P@YGB@!``!T%HE<)!"+2RB+
+M="0(BUPD!(/$#/_AB?:+CD`!``"-AD`!``#'AB@!````````.<%TT(L1BT$$
+MB4($B1")RHGPB0F)203H+O[__^NVC;8`````C;\`````BT0D!(N`6`(``,.0
+MC70F`%=64X/L-(M,)$B-="0(#[94)$2)\(G+Q@``C7PD-(/``3GX=?*`^@>(
+M5"00#X2M````@/H&=#2`^@1T+X#Z!9!T*8#Z"'0D@/H<=&Z`^@.0="Z+@U@"
+M``")-"2)1"0,Z/S___^#Q#1;7E_#]H%(`0```733@/H<QD0D%`%USNLZBTL0
+MA<ETRP^V062(1"04@'ED`'6]BT%(BU%,B40D&(E4)!P/MT%0B40D(`^V0670
+MZ(/@`8A$)!7KF(N!3`$``(N14`$``(E$)!0/MX$4`@``B50D&&:)1"0<Z7/_
+M__^+00R%P'0*BX!8`@``B40D%(M9).E:____D(VT)@````"+1"0(H@````##
+MC;8`````4XM$)`B+7"0,BU`,C4@,.<IU".LHBQ(YRG0BC8+8_?__@'@(`77N
+M]H`<`@```73EA=MT"XL2@^L!.<IUWC'`6\/K#9"0D)"0D)"0D)"0D)"#[!R)
+M7"04B<.)="08BT`@B=:)1"0$BP.)!"3H_/___P^V4&6)6"B)6"R)<#"#XL^#
+MRB"(4&7&0&0$QD!F`,=`</!V`P")!"3H_/___XM<)!2+="08@\0<PXVT)@``
+M``"#[!R)="00B7PD%(G'B6PD&(G5B5PD#(L8BT`@B4PD"(D<)('#F````(E$
+M)`3H_/___XD<)(G&Z/S____'``````#'0`0`````BU<4BT\8QT`@`````,=`
+M$`````")4`B-4!2)2`S'0!P`````QT`D`````(E0%(E0&,=`*`````")1CS&
+M1F0$BT0D"(E^*(EN+,9&9@")1G")-"3H_/___XM<)`R+="00BWPD%(ML)!B#
+MQ!S#C70F`(V\)P````"#[!R)7"00B<N)="04B=:)?"08B<>#`0&+0"")1"0$
+MBP>)!"3H_/___X/^`8G!&<`/ME%E@\`"@^`#P>`$B7DH@^+/"<*(467&060$
+MB5DLQD%F`(!_"`1V%XN'9`$``(7`=`W'07!@>`,`ZPN-="8`QT%P$'@#`(D,
+M).C\____BP>)!"3H_/___XM<)!"+="04BWPD&(/$',.-M"8`````55=64X/L
+M'(M\)#"+1"0TBVPD.(V/L````(E$)!2)3"08B0PDZ/S___^%P(G&#X2.````
+MBU\,QP`!````BT0D%(E^$(/'#(EN"#G[B48$QT8,`````'4/ZS2-M"8`````
+MBQLY^W0GC8/8_?__@'@(`77N]H`<`@```73EB?&Z`0```.C9_O__BQLY^W79
+MBP:#Z`&%P(D&=`B#Q!Q;7E]=PXM,)!B)="0$B0PDZ/S___^+3"04B6PD,(/$
+M'%M>7UW_X<<$))X"``#H_/___^OAD%575E.#[!R+?"0PBT0D-(ML)#B-C[``
+M``")1"04B4PD&(D,).C\____A<")QG1SBU\,QP`!````BT0D%(E^$(/'#(EN
+M"#G[B48$QT8,`````'0;C8/8_?__@W@<_W0)B?$QTN@H_O__BQLY^W7EBP:#
+MZ`&%P(D&=`B#Q!Q;7E]=PXM,)!B)="0$B0PDZ/S___^+3"04B6PD,(/$'%M>
+M7UW_X<<$)+D"``#H_/___^OA4X/L"(M4)!2+7"00BTH@B5H(A<ET!8M"%(D!
+MB=CH3OG__XE<)!"#Q`A;Z?S___^04XM$)`R+7"0(BY!8`@``C8@(`@``B9C4
+M`0``QX#8`0``#_\``(F(Y`$``(F0"`(``(V0%@(``,>`W`$```@```#'000,
+M````B9#H`0``QX#@`0```````,>`[`$```````")@/`!``#'@/0!``!PK`,`
+M!<P!``")1"0,B5PD"%OI_/___XUT)@"-O"<`````@^P,BT0D$(M0"(F"3`$`
+M`(V"2`$``,>"2`$``#!\`P#'@E`!````````@\(DB40D!(D4).C\____@\0,
+MPXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!```@?@,`QX)0`0``````
+M`(/")(E$)`2)%"3H_/___X/$#,.-=@"#[`R+1"00BU`(B8),`0``C8)(`0``
+MQX)(`0``$`4$`,>"4`$```````"#PB2)1"0$B10DZ/S___^#Q`S#C78`@^P,
+MBT0D$(M0"(F"3`$``(V"2`$``,>"2`$``!#V`P#'@E`!````````@\(DB40D
+M!(D4).C\____@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!``"P
+MN0,`QX)0`0```````(/")(E$)`2)%"3H_/___X/$#,.-=@"#[`R+1"00BU`(
+MB8),`0``C8)(`0``QX)(`0``\/D#`,>"4`$```````"#PB2)1"0$B10DZ/S_
+M__^#Q`S#C78`@^P,BT0D$(M0"(F"3`$``(V"2`$``,>"2`$``'"]`P#'@E`!
+M````````@\(DB40D!(D4).C\____@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-
+M@D@!``#'@D@!``"`N@,`QX)0`0```````(/")(E$)`2)%"3H_/___X/$#,.-
+M=@"#[`R+1"00BU`(B8),`0``C8)(`0``QX)(`0``@`@$`,>"4`$```````"#
+MPB2)1"0$B10DZ/S___^#Q`S#C78`@^P,BT0D$(M0"(F"3`$``(V"2`$``,>"
+M2`$``,"M`P#'@E`!````````@\(DB40D!(D4).C\____@\0,PXUV`(/L#(M$
+M)!"+4`B)@DP!``"-@D@!``#'@D@!``!0_`,`QX)0`0```````(/")(E$)`2)
+M%"3H_/___X/$#,.-=@"#[`R+1"00BU`(B8),`0``C8)(`0``QX)(`0``4+X#
+M`,>"4`$```````"#PB2)1"0$B10DZ/S___^#Q`S#C78`@^P,BT0D$(M0"(F"
+M3`$``(V"2`$``,>"2`$``%"^`P#'@E`!````````@\(DB40D!(D4).C\____
+M@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!``"PP`,`QX)0`0``
+M`````(/")(E$)`2)%"3H_/___X/$#,.-=@"#[`R+1"00BU`(B8),`0``C8)(
+M`0``QX)(`0```-0#`,>"4`$```````"#PB2)1"0$B10DZ/S___^#Q`S#C78`
+M@^P,BT0D$(M0"(F"3`$``(V"2`$``,>"2`$``+`)!`#'@E`!````````@\(D
+MB40D!(D4).C\____@\0,PXUV`(/L#(M$)!"+4`B)@DP!``"-@D@!``#'@D@!
+M``!0U0,`QX)0`0```````(/")(E$)`2)%"3H_/___X/$#,.-=@"#[`R+1"00
+MBU`(B8),`0``C8)(`0``QX)(`0``8/T#`,>"4`$```````"#PB2)1"0$B10D
+MZ/S___^#Q`S#C78`@^P,BT0D$(M0"(F"3`$``(V"2`$``,>"2`$``'#4`P#'
+M@E`!````````@\(DB40D!(D4).C\____@\0,PXUV`(/L#(M$)!"+4`B)@DP!
+M``"-@D@!``#'@D@!``!PW0,`QX)0`0```````(/")(E$)`2)%"3H_/___X/$
+M#,.-=@"#[`R+1"00C5`4QT`44!$$`(E`&,=`'`````")5"0$BP"#P"2)!"3H
+M_/___X/$#,.#[`R+1"00C5`8QT`8`-X#`(E`',=`(`````")5"0$BT`$BP"#
+MP"2)!"3H_/___X/$#,.-M@````"-O"<`````4X/L"(M<)!"`>V8!=`X/MD-G
+M@\`!/`*(0V=V1(M#/(E$)`2+`P68````B00DZ/S___^-0Q3'0Q2@U0,`B5L8
+MQT,<`````(E$)`2+`X/`)(D$).C\____@\0(6\.-="8`BT,\QD-F`,=`$```
+M``"+0SR-4!3'0!P`````QT`@`````,=`)`````")4!2)4!C'0"@`````B5PD
+M$(/$"%OI_/___XVV`````(V\)P````"#[`R+3"00BT$LBQ"#Z@&%THD0=2N-
+M013'010@>0,`B4D8QT$<`````(E$)`2+`8/`+(D$).C\____@\0,PXGVB4PD
+M$(/$#.G\____C70F`(/L'(M,)"")7"00B70D%(E\)!B+02B+D&0!``"+>@0Y
+MQP^$BP```(7_=`GVAQP"```!=1R)3"0@BUPD$(MT)!2+?"08@\0<Z63___^-
+M="8`BW$L#[9998D,).C\____BT<@P.L$@^,#B40D!(L'P>,$B00DZ/S___\/
+MME!EB7@HQD!D!(EP+(/BSPG:B%!EQD!F`,=`<!!X`P"+7"00B40D((MT)!2+
+M?"08@\0<Z?S___^+>@CI;?___XVV`````(/L'(ET)!B+="0@B5PD%(M>+(M#
+M"(D$)/]3!(E<)`2+!@6P````B00DZ/S___^+7"04B70D((MT)!B#Q!SI_/__
+M_XVT)@````"-O"<`````5U93@>S`````B[PDT````(V$))````"+=RB+7ER+
+M5E2)1"0$BT9@B00D_U(\C40D&(M3!(E$)`2+0PB)!"3_4AR-A"2T````B00D
+MC8PDN````(G8C90DO````.B`R?__]H0DG@````)T:8N4)+0````/MH0DH```
+M`(!_9@&-!`)T7HE$)`B+A"2\````QP0D6`P``(E$)`3H_/___XET)`3'!"0:
+M````Z/S___^+1RR)1"0$BP:#P%")!"3H_/___XD\).C\____@<3`````6UY?
+MPXN4)+@```#KE8UT)@")1"0(BX0DO````,<$)#`,``")1"0$Z/S___^)="0$
+MQP0D&P```.C\____ZZ"-=@"#[!R+5"0@B5PD%(ET)!B+6BR+0P2+,(D4).C\
+M____QT,8@!($`(E;'(/&),=#(`````"#PQB)7"0$B30DZ/S___^+7"04BW0D
+M&(/$',.)]H/L+(E<)!R+7"0PB70D((E\)"2);"0HBRN+<RR+A2@!``"+?@B)
+M1"04BT8$B40D&(![9@%T$@^V0V>#P`$\`HA#9P^&OP```(M#/(E$)`2-A9@`
+M``")!"3H_/___XD<).C\____BT0D%(7_BU`<#X1]````BX=8`@``B0*#P`%T
+M=HM$)!B-5@R`B$D!```$@(])`0``!("G2`$``/V)MV0!``")L&0!``"+31B-
+M112)1@R-1AB)51C'1A@0I@,`B4X0B78<QT8@`````(D1B40D!(U%)(D$).C\
+M____BUPD'(MT)""+?"0DBVPD*(/$+,/'`O____^+1"04QT`L_____^EZ____
+MBT,\QD-F`,=`$`````"+0SR-4!3'0!P`````QT`@`````,=`)`````")4!2)
+M4!C'0"@`````BW0D((E<)#"+?"0DBUPD'(ML)"B#Q"SI_/___XVT)@````!5
+M5U93@^PLBT0D0(MH&(M0'(M%`(E4)!R)!"3H_/___XE$)"B+1"1`#[9-!`^V
+M707'0"S_____#[95!H#Z"P^'W````(!]!PL/A](````/ML&)1"0@#[;"`T0D
+M((/X"WX'N0L````HT8M4)!R(2@0/MDT'#[;3#[;!`="#^`M^![L+````*,N+
+M3"0<BT0D'(/!"(E,)"2`>`0`B%@%#X2N````,?_K$HM,)!R#QP&)^CA1!`^&
+MF````(GZBTPD*`^V\HGPP>`)`T0D),=$)!0!````QT0D#`$```")1"00BT$X
+MBU$\#[9-!@4``/[_@]+_)0``_O\QVP'($=HQVP'PB40D!(M$)"@1VHE4)`B)
+M!"3H_/___X7`=(V-M@````"+3"1`B<B#P##'03`0;`,`B4DTQT$X`````(E$
+M)`2+00B)!"3H_/___X/$+%M>7UW#BT0D'(!X!0!T>C'_ZP^0BT0D'(/'`8GY
+M.$@%=F>+3"0@B?H/MO+'1"04`0```,=$)`P!````C00.P>`)`T0D)(E$)!"+
+M1"0HBT@XBU@\#[9%!X'!`/C__X/3_S'2`<$1TS'2`?$1TXM4)"B)3"0$B5PD
+M"(D4).C\____A<!TD.E+____BU0D0,="+`````#I.____XUT)@"-O"<`````
+M55=64X/L+(M$)$"+>!B+!XD$).C\____BU0D0(E$)"2+0AS'``````#'0BP`
+M````@'\'``^$T0```(G&@\8$B70D*(!_!@`/A(T````Q[>L*@\4!B>@X1P9V
+M?P^V1P>)ZC';#[;2BW0D),=$)`P!````B50D((E$)!2)T,'@"0-$)"B)1"00
+M#[=/!(M&.(M6/(DT)(/!"X/3``4``/[_@]+_)0``_O\!P8M$)"`1TS'2`<$1
+MTXE,)`2)7"0(Z/S___^%P'2+BU0D0(M"',<`_____\="+/____^+5"1`B="#
+MP##'0C`0;`,`B5(TQT(X`````(E$)`2+0@B)!"3H_/___X/$+%M>7UW#C4<,
+MB40D*.DL____B?:-O"<`````5E.#[!2+3"0@BUDL@'EF`8MS''0^@'E*`'4X
+MQT,L_____XD,).C\____C4,PQT,P$&P#`(E;-,=#.`````")1"0$BT,(B00D
+MZ/S___^#Q!1;7L/'0RP`````#[9!2H3`B`9U'(M!3(E&!(M3((72=+&+1@2#
+MP`B)`NNGD(UT)@`/MD%)B48$Z^&-M"8`````@>RL````B;0DH````(NT)+``
+M``")G"2<````B;PDI````(FL)*@```"+1A@/ME`"#[8(@/H##X0D`0``@/H$
+M#X0\`0``@'@!!78'@'@%_I!T8@^VP3'2Z'3"__^)PXM&"(M6*,=&*."!`P")
+ML$P!``")D$@!``"+4P3'@%`!````````B70D!(M#"(D$)/]2?(N<))P```"+
+MM"2@````B[PDI````(NL)*@```"!Q*P```##C5`+B50D%`^V>`LQTHM&%(E$
+M)!@/ML'H`,+__X7`B<-T3(UL)""-M@````"+0P2+D(0```"%TG08BT,(B00D
+M_]*)^CC0#X?T````B?HHPHG7BQN%VW07BU,$B6PD!(M#"(D$)/]2'(!\)#,`
+M=+Z+1B#'``````"-1C#'1BS_____QT8P$&P#`(EV-,=&.`````")1"0$BT8(
+MB00DZ/S____I-____XVV``````^V0`2-E"28````B80DF`````^VP>A6P?__
+MB</IW?[__XU0`XE4)!`QT@^V>`,/ML'H.L'__X7`B<-TCXUL)"#K*XGZ*,*)
+MUXL;A=L/A'G___^+4P2);"0$BT,(B00D_U(<@'PD,P`/A5[___^+0P2+D(0`
+M``"%TG3.BT,(B00D_]*)^CC0=KJ+1"00B!#I:_[__XM$)!2($(M&((M4)!B)
+M$.E7_O__B?:-O"<`````@^P,BT0D$(M("(E`-,=`.`````"+D4@!``#'0#`0
+M;`,`B5`H@\`PB40D!(D,).C\____@\0,PXGVC;PG`````%575E.![)P```"+
+M-0````"+E"2P````QT0D&`````"%]HM"&(L`B40D$(M"''1P@\`$,?^)1"04
+MC6PD)(M>"(7;=0OK2H/'`8L;A=MT08M3!(EL)`2+0PB)!"3_4AR`?"0W`'3C
+MBX0DL````#EP"'74@T0D&`&+5"04BT0D&#E$)!").G8/@\($B50D%.NVBS:%
+M]G6GBY0DL````(M"'(M4)!B)$(N$)+````"+E"2P````QT`P$&P#`(E`-,=`
+M.`````"#P#")1"0$BT((B00DZ/S___^!Q)P```!;7E]=P^L-D)"0D)"0D)"0
+MD)"0D%93@^P4BS4@`@``BUPD(#LU)`(``(M+'`^$I0```&O6+(N"0`(``(D!
+MBX)$`@``B4$$BX)(`@``B4$(BX),`@``B4$,BX)0`@``B4$0BX)4`@``B4$4
+MBX)8`@``B4$8BX)<`@``B4$<BX)@`@``B4$@BX)D`@``B4$DBX)H`@``B4$H
+MC48!B<+!^A_!ZAP!T(/@#RG0HR`"``"-0S#'0S`0;`,`B5LTQT,X`````(E$
+M)`2+0PB)!"3H_/___X/$%%M>P\=#+/_____KSHUT)@"#["PQTHE<)!R+7"0P
+MB70D((E\)"2);"0HBT,8BV@$BW`(BW@,BP#HE+[__X7`B<%T?H7V=&"+0`3'
+M1"00`````(E\)`R+4QB#PA")5"0(B6PD!(M1"(D4)/^0F````(U#,,=#,!!L
+M`P")6S3'0S@`````B40D!(M#"(D$).C\____BUPD'(MT)""+?"0DBVPD*(/$
+M+,.+0`3'1"00`0```(E\)`R+4QSKH8VV`````,=#+/[____KIHVT)@````!6
+M,=)3@>R4````BYPDH````(M#&(L`Z.6]__^+<QR%P(G!=%&+4`2-1"0<B40D
+M!(M!"(D$)/]2'`^W1"0@9HD&#[=$)")FB48"C4,PQT,P$&P#`(E;-,=#.```
+M``")1"0$BT,(B00DZ/S___^!Q)0```!;7L/'0RS^____Z\N)]H/L+(E\)"2+
+M?"0PB70D((EL)"B)7"0<BT<8BQB-<`2+1QR)'"2#ZP&)1"08Z/S___^#^_Z)
+MQ1G`(<4/MD8*A,!U!P^V1@[`Z`0/ML`/MDX-#[96#(E$)`@/MD8.@^`/B40D
+M!(U&?(D$)(GHZ/#$__^+3"08QT<P$&P#`(E_-,='.`````")`8U',(E1!(E$
+M)`2+1PB)!"3H_/___XM<)!R+="0@BWPD)(ML)"B#Q"S#@^PLB70D((MT)#")
+M;"0HB5PD'(E\)"2+?AB+1AR+'XUO!(E$)!B)'"2#ZP'H_/___X/[_@^V30&)
+MPAG`(=`/ME<$@\=TQT0D"``````/MET"B3PD@^,/B5PD!.A0Q/__BTPD&,=&
+M,!!L`P")=C3'1C@`````B0&-1C")402)1"0$BT8(B00DZ/S___^+7"0<BW0D
+M((M\)"2+;"0H@\0LPU575E.#[`R+1"0@BU0D((M`'(G%B40D"(M"&(/%!(LX
+MA?\/CGX```"+-0````"%]G1T,=N+5@R-3@PYRG4(ZUZ+$CG*=%B-@MC]__^`
+M>`@!=>Z+@%@"``")1)T`@\,!.=]UW8G8BU0D"(D"BT0D((M4)"#'0#`0;`,`
+MB4`TQT`X`````(/`,(E$)`2+0@B)!"3H_/___X/$#%M>7UW#BS:%]G60Z[TQ
+MP.N[C;8`````55=64X/L'(M$)#"+5"0PBT`<B40D%(/`!(E$)!B+0AB+*(7M
+M#X[(````BST`````A?\/A+H````Q]HM7#(U?##G:=1;IF0```(VT)@````"+
+M$CG:#X2(````C8+8_?__BT@,A<EUZ0^V2`B`^01V8HN(9`$``(7)=`N#>00`
+M=`4Y00ATRXN`6`(``(M,)!B)!+&#Q@$Y[G6WB?"+3"0PBU0D%,=!,!!L`P")
+M`HG(@\`PB4DTQT$X`````(E$)`2+00B)!"3H_/___X/$'%M>7UW#@.D!=;[V
+M0%`"=+B-=@#KHXL_A?\/A4[___^-="8`ZZ<QP.NEC78`C;PG`````%575E.!
+M[)P```"+O"2P````BT<8BU`(BW`$BP")5"08BU<<B50D%#'2Z%*Z___'1RS_
+M____A<")PW0]C6PD))"+0P2+D(0```"%TG0.BT,(B00D_](YQGQ-*<:+&X7;
+M=!>+4P2);"0$BT,(B00D_U(<@'PD-P!TR(U',,=',!!L`P")?S3'1S@`````
+MB40D!(M'"(D$).C\____@<2<````6UY?7<.+5"04BT,$QT0D#`````")="0$
+MB50D$(M4)!B)5"0(BU,(B10D_Y"4````A<!UH\='+`````#KFHGV55=64X'L
+MG````(N\)+````"+1QB+5QR+<`2+`(E4)!@QTNAYN?__QT<L_____X7`B<-T
+M0#'MBT,$BY"$````A=)T$(M#"(D$)/_2.<9\4RG&`<6+&X7;=!N-1"0DBU,$
+MB40D!(M#"(D$)/]2'(!\)#<`=,*-1S#'1S`0;`,`B7\TQT<X`````(E$)`2+
+M1PB)!"3H_/___X'$G````%M>7UW#BT,$BY"4````A=)TQ8M$)!C'1"00````
+M`,=$)`@`````B70D!(E$)`R+0PB)!"3_TH7`=9V+5"08#[9"`CS_=`4!Z(A"
+M`L='+`````#K@^L-D)"0D)"0D)"0D)"0D%575E.![)P```"+O"2P````BT<8
+MBU<<BW`$BP")5"08,=+H>;C__\='+/____^%P(G#=$`Q[8M#!(N0A````(72
+M=!"+0PB)!"3_TCG&?%,IQ@'%BQN%VW0;C40D)(M3!(E$)`2+0PB)!"3_4AR`
+M?"0W`'3"C4<PQT<P$&P#`(E_-,='.`````")1"0$BT<(B00DZ/S___^!Q)P`
+M``!;7E]=PXM#!(N0D````(72=,6+1"08B70D!(E$)`B+0PB)!"3_TH7`=:V+
+M5"08#[9"`CS_=`4!Z(A"`L='+`````#KD^L-D)"0D)"0D)"0D)"0D%575E.!
+M[)P```"+O"2P````BT<8BU<<BW`$BP")5"08,=+HB;?__\='+/____^%P(G#
+M=$`Q[8M#!(N0A````(72=!"+0PB)!"3_TCG&?%,IQ@'%BQN%VW0;C40D)(M3
+M!(E$)`2+0PB)!"3_4AR`?"0W`'3"C4<PQT<P$&P#`(E_-,='.`````")1"0$
+MBT<(B00DZ/S___^!Q)P```!;7E]=PXM#!(N0C````(72=,6+1"08B70D!(E$
+M)`B+0PB)!"3_TH7`=:V+5"08#[9"`CS_=`4!Z(A"`L='+`````#KD^L-D)"0
+MD)"0D)"0D)"0D%575E.![)P```"+O"2P````BT<8BU<<BW`$BP")5"08,=+H
+MF;;__\='+/____^%P(G#=$`Q[8M#!(N0A````(72=!"+0PB)!"3_TCG&?%,I
+MQ@'%BQN%VW0;C40D)(M3!(E$)`2+0PB)!"3_4AR`?"0W`'3"C4<PQT<P$&P#
+M`(E_-,='.`````")1"0$BT<(B00DZ/S___^!Q)P```!;7E]=PXM#!(N0B```
+M`(72=,6+1"08B70D!(E$)`B+0PB)!"3_TH7`=:V+5"08#[9"`CS_=`4!Z(A"
+M`L='+`````#KD^L-D)"0D)"0D)"0D)"0D%4QTE=64X'LC````(N\)*````"+
+M1QB+`.BSM?__,=*%P(G#=$$Q]HUL)!20C70F`(M#!(N0A````(72=`J+0PB)
+M!"3_T@'&BQN%VW07BU,$B6PD!(M#"(D$)/]2'(!\)"<`=,R)\HM'',=',!!L
+M`P")?S3'1S@`````B1"-1S")1"0$BT<(B00DZ/S___^!Q(P```!;7E]=PXVT
+M)@````!3@^P(BUPD$(M#&(M+'(M0!(L`Z!BW__^%P'0'QT,L_____XU#,,=#
+M,!!L`P")6S3'0S@`````B40D!(M#"(D$).C\____@\0(6\.0C70F`%<QTE93
+M@>R0````B[0DH````(M&&(M>'(L`Z,&T__^%P`^$E````#'2C;0F`````,8$
+M&@"#P@&#^D1U](U,)!B)RL8"`(V\))````"#P@$Y^G7OBU`$B4PD!(M`"(D$
+M)/]2'`^VA"2%````B`,/MH0DA@```(A#`0^VA"2'````B$,"#[:$)(@```"(
+M0P.-1C#'1C`0;`,`B78TQT8X`````(E$)`2+1@B)!"3H_/___X'$D````%M>
+M7\/'1BS_____Z\J-M@````"-OP````"#[!R)7"04BUPD((ET)!B+<QSHF;7_
+M_\=#,!!L`P")6S3'0S@`````B0:-0S")1"0$BT,(B00DZ/S___^+7"04BW0D
+M&(/$',.0C;0F`````%:ZT0(``%.#[!2+="0@BUX8B=CH6+/__X7`=30/MD,@
+MH@````"-1C#'1C`0;`,`B78TQT8X`````(E$)`2+1@B)!"3H_/___X/$%%M>
+MPXGVNMX"``")V.@4L___A<!U$@^V0R"-!,5P_O__HP````#KL[KO`@``B=CH
+M\K+__X7`=$2Z#`,``(G8Z.*R__^%P'5"BT8(QX!(`0``T)8#`(FP3`$``(V0
+M2`$``,>`4`$```````"#P"2)5"0$B00DZ/S____K@@^V0R"B`````.E1____
+MNBD#``")V.B0LO__A<!U#XM&",>`2`$``""0`P#KK,=&+/_____I)O___Y"#
+M[`R+1"00BU`<QT`P$&P#`(E`-,=`.`````#'`@```0*-4#")5"0$BT`(B00D
+MZ/S___^#Q`S#B?:-O"<`````55=64X/L/(ML)%"+11B+50C&1"0T!X!X(`&-
+M>@P9P(/``HA$)#B+<@PY_G0AC78`C9[8_?__]H,<`@```70&@'L(`70XBS8Y
+M_G7EBU4(QT4L`````(U%,,=%,!!L`P");33'13@`````B40D!(D4).C\____
+M@\0\6UY?7<.-5"00BT-4B50D!(M38(D4)/]0/`^V1"0C.D0D.'2IC40D-(M3
+M5(E$)`2+0V")!"3_4F#KDXVT)@````"-O"<`````@^P<B5PD#(M<)"")?"04
+MB70D$(EL)!B+`XMS+(E$)`B+1AB+*(DL).C\____@'MF`8G'=!(/MD-G@\`!
+M/`*(0V</AHD```"+0SR)1"0$BT0D"`68````B00DZ/S___^)'"3H_/___XM&
+M##TI_P``=%4].?\``'1.A?]T#(L7.U0D"`^$F@```(U&,,=&+/[____'1C`0
+M;`,`B78TQT8X`````(E$)`2+1@B)!"3H_/___XM<)`R+="00BWPD%(ML)!B#
+MQ!S#BT8<B2CKJXUV`(M#/,9#9@#'0!``````BT,\C5`4QT`<`````,=`(```
+M``#'0"0`````B5`4B5`8QT`H`````(MT)!")7"0@BWPD%(M<)`R+;"08@\0<
+MZ?S___^-@D@!``#'@D@!``#`I0,`B;),`0``QX)0`0```````(E$)`2-0B2)
+M!"3H_/___^E<____C78`C;PG`````(/L#(L0B00D@<(L`0``B50D!.C\____
+M@\0,PY"-="8`@^P,BT0D$(M`&(L`B00DZ/S___^#Q`SKQXVT)@````"#[`R+
+M1"00BT`8BP")!"3H_/___X/$#.NGC;0F`````(/L#(M$)!"+0!B`>`0!BQ!T
+M!(/$#,.)%"3H_/___X/$#.EZ____C78`C;PG`````%575E.#[`R+;"0@BT48
+MBQ!F]\(`_W5%B=>!Y_\```!^.S'VNP0```#K"8VV`````(M%&(L$&(D$).C\
+M____A<!T$(!X"`1V"HN09`$``(72=!*#Q@&#PP0Y_G74@\0,6UY?7</H!___
+M_^OGD(UT)@"#[`R+1"00BT`8BP")!"3H_/___X/$#.GD_O__C70F`(/L#(M$
+M)!")="0(B5PD!(M`&(M8!(L`B00DZ/S___^#^PV)QG0O@_L!=!B#^P2)]G01
+M@_L'=`R+7"0$BW0D"(/$#,.)\(M<)`2+="0(@\0,Z8O^__^%P'3>BX!D`0``
+MA<!TU(M0!(72=`V)T.AO_O__BX9D`0``BT`(A<!TN8M<)`2+="0(@\0,Z5+^
+M__^)]H/L#(M$)!")="0(B5PD!(M`&(M8!(L`B00DZ/S___^)'"2)QNC\____
+MB<.)\.@>_O__B=B+="0(BUPD!(/$#.D,_O__C;8`````C;\`````@^P,BT0D
+M$(M`&(L`B00DZ/S___^#Q`SIY/W__XUT)@"#[`R+1"00BT`8BP")!"3H_/__
+M_X/$#.G$_?__C70F`%.#[`B+1"00BT`8BP")!"3H_/___X7`B<-T-8N`9`$`
+M`(7`="N+4`2%TG0-B=#HC?W__XN#9`$``(M`"(7`=""#Q`A;Z7?]__^-M"8`
+M````B=B#Q`A;Z67]__^0C70F`(/$"%O#C70F`(V\)P````!64X/L!(M$)!"+
+M<!B#Q@2`?@T`=!XQVXM$GGR#PP&)!"3H_/___^@E_?__#[9&#3G8=^2#Q`1;
+M7L.-M"8`````5E.#[`2+1"00BW`8@\8$@'X!`'0>,=N+1)YP@\,!B00DZ/S_
+M___HY?S__P^V1@$YV'?D@\0$6U[#C;0F`````%93@^P$BT0D$(MP&(!^#0!T
+M'C';BT2>?(/#`8D$).C\____Z*C\__\/MD8-.=AWY(/$!%M>PXUV`(V\)P``
+M``!64X/L!(M$)!"+<!B`?@$`=!XQVXM$GG"#PP&)!"3H_/___^AH_/__#[9&
+M`3G8=^2#Q`1;7L.-=@"-O"<`````5E.#[`2+1"00BW`8@'X!`'0>,=N+1)YH
+M@\,!B00DZ/S____H*/S__P^V1@$YV'?D@\0$6U[#C78`C;PG`````%93@^P$
+MBT0D$(MP&(L.A<ET&C';BT2>!(/#`8D$).C\____Z.C[__\Y'G?H@\0$6U[#
+MC;0F`````(V\)P````!6N@P#``!3@^P$BW0D$(M&&.C*J___A<!U+HM&"(M8
+M#(/`##G#="&-@]C]___V@!P"```!=`:`>`@!=!*+1@B+&X/`##G8==^#Q`1;
+M7L/H??O__^OGC70F`(V\)P````!55U93@>R,````BX0DH````(MH"(M0&(MU
+M#(U]#(E4)`@Y_G0?C9[8_?__]H,<`@```70*@'L(`0^$N@```(LV.?YUX8M4
+M)`@/MD(@H@````"+70B%VW1=C70D#.L(B?:+&X7;=$^+4P2)="0$BT,(B00D
+M_U(<]D0D'1!TXXV=S````(E<)`2)+"3H_/___\>%S`````"'DP/'A=0`````
+M````B:W8````B5PD!(DL).C\____BX0DH````(N4)*````#'0"P`````QT`P
+M$&P#`(E`-,=`.`````"#P#")1"0$BT((B00DZ/S___^!Q(P```!;7E]=PXD<
+M).C\____BU0D",:$)(0````(#[9"((B$)(@```"-A"2$````BU-4B40D!(M#
+M8(D$)/]28.D+____C;8`````C;PG`````(/L'(E<)`R)?"04B=>);"08B<6)
+M="00BT`@B40D!(M%`(D$).C\____A<")PP^$Y`$``,9`9`.!?PQ"_P``B6@H
+M#Y3`#[;PA?8/A9@```"+5Q@QP(!Z"O0/E,"%P`^%F````(7V#X05`0``#[9"
+M$CP!#X2.`0``/`(/A&@!```/MD(/B$-3#[=""&:)0TP/MT(*9HE#3@^W0@QF
+MB4-0#[9"#HA#4@^W0@1FB4-(#[="!F:)0TH/MT(09HE#5(E[+,=#<!#W`P#&
+M14X!B1PDZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<PXM7&#'`@'H/]`^4P(7`
+M#X1H____BT4`@\!0B00DZ/S___^%P(G%#X0S`0``A?8/A;4```"+1QB#P!#'
+M1"0(``(``(E$)`2)+"3H_/___XU',(!+902):UC&0U/T9L=#5`$`B6LLQT-P
+M<'D#`(E$)`2+1PC'1RP`````QT<P$&P#`(E_-,='.`````")!"3H_/___^E,
+M____D`^V0@P\`71N/`)T3P^V0@J(0U,/MD(&9HE#3`^V0@=FB4-.#[9""&:)
+M0U`/MD()B$-2#[9"!&:)0T@/MD(%9HE#2@^V0@MFB4-4Z>[^__^0BT<8@\`4
+MZ4;___^`2V4$C4(0B4-8ZZ6`2V4$C4(4B4-8Z8G^__^`2V4"BT<<@\`0B4-8
+MZX>`2V4"BT<<@\`4B4-8Z6C^__^-1S")1"0$BT<(QT<L_?___\=',!!L`P")
+M?S3'1S@`````B00DZ/S____IC?[__XU',(E$)`2+1PC'1RS_____QT<P$&P#
+M`(E_-,='.`````")!"3H_/___XD<).C\____Z5;^__^-=@!3@^P(BUPD$(M#
+M&(L`B00DZ/S___^)VH/$"%OI8/W__U.#[`B+7"00BT,8BP")!"3H_/___XG:
+M@\0(6^E`_?__@^P<B6PD&(ML)"")7"0,B70D$(E\)!2+?1B+!XD$).C\____
+MB<:+0"")1"0$BP:)!"3H_/___X7`B<,/A(L```"):"R)<"C&0&0"#[9'!#P!
+M=&T\`G1O#[9'!XU+4(U7"(E4)`2)#"2)1"0(Z/S___\/MD<'B$-(BT<8B4-,
+M#[9%%(/H"(3`B$-)=`F+11R#P`B)0V#'0VP`:0,`QT-P0'\#`(MT)!")7"0@
+MBWPD%(M<)`R+;"08@\0<Z?S___^0@$ME`NN1@$ME!.N+C44PQT4L_?___\=%
+M,!!L`P");33'13@`````B40D!(M%"(D$).C\____BUPD#(MT)!"+?"04BVPD
+M&(/$',.-M@````!64X/L9(M<)'"-3"0@BT,8BW,<BU`$BP#HHZC__X7`=##'
+M0RS_____C4,PQT,P$&P#`(E;-,=#.`````")1"0$BT,(B00DZ/S___^#Q&1;
+M7L.+1"0@B0:+1"0DB48$BT0D*(E&"(M$)"R)1@SKNHGV5U93@^P0BWPD((`]
+M``````&+7QB+=QS'1RP`````#X8<`0``NMX"``")V.C0I?__A<`/A(D```"Z
+M[P(``(G8Z+RE__^%P`^%UP```(L#B0:+0P2)1@2+0PB)1@B+0PR)1@R+0Q")
+M1A"+0Q2)1A2+0QB)1AB+0QS&1D0`QD9!`,9&0`*)1AP/MD-%B$9%#[8%````
+M`(A&((U',,=',!!L`P")?S3'1S@`````B40D!(M'"(D$).C\____@\006UY?
+MPXL#B0:+0P2)1@2+0PB)1@B+0PR)1@R+0Q")1A"+0Q2)1A2+0QB)1AB+0QS&
+M1D0`QD9!`,9&0`&)1AP/MD-%B$9%BQ4`````@<*0`0``B=#!^!_!Z!T!T,'X
+M`XA&(.ET____N@P#``")V.C1I/__A<!T<<='+/_____I6/___Y"ZT0(``(G8
+MZ+2D__^%P`^%T/[__XL#B0:+0P2)1@2+0PB)1@B+0PR)1@R+0Q")1A"+0Q2)
+M1A2+0QB)1AB+0QS&1D0`QD9!`,9&0`*)1AP/MD-%B$9%#[8%`````(A&(.GS
+M_O__BP.)!HM#!(E&!(M#"(E&"(M##(E&#(M#$(E&$(M#%(E&%(M#&(E&&(M#
+M',9&1`#&1D$`QD9``8E&'`^V0T6(1D4/M@4`````B$8@Z:/^__^-M@````"-
+MOP````!55XG'5E.![%P"``")5"0DB$PD(P^V0@_&1"0P`83`>`^`?P@&QD0D
+M,``/A%(#``"-1"10Q@``C90D4`(``(/``3G0=>^+7"0D#[9#"XA'-(![#0!T
+M,#';ZP^+5"0D@\,!#[9"#3G8?AV+5"0DBT2:?(D$).C\____@7A(`!```'78
+MQD<T`XM<)"0/MI=(`0``#[9##HA',0^V2PZX`0```-/@9HE',HG0@\@$B(=(
+M`0``]D,/`P^$)P(``(G0@\@%B(=(`0``BT<$QX=,`0```````,>'4`$`````
+M``"`>`<`#X4X`@``BUPD)(V/5`$``(M4)"0/MG<PBT,0@\(0A?:)AU0!``"+
+M0@2)002+0@B)00B+0@R)00S'1"0H_____\=$)"S_____?E0Q[>L+#[9W,(/%
+M`3GN?D6+7*](BU,8.50D+(E[#(M#%'(0=P8Y1"0H=@B)1"0HB50D+(!["`1U
+MS(!\)",`BW,D=7*`?"0P`'5V#[9W,(/%`3GN?[N`?P@'#X3,`0``BV\$@'T%
+M``^%90$```^V10:+3"0LBUPD*"G&B?*)\,'Z'P^OV@^OSO=D)"@!V8T4$8E'
+M%(E7&(M4)"0/MD(/@^`<P?@"B(<=`@``@<1<`@``6UY?7<.`?"0P``^$D@``
+M`(U4)%#'1"04`0```(E4)!#'1"0,`0```(M#,(M0"(M`!(DT)(E4)`B)1"0$
+MZ/S___^%P`^%#/___X"\)$X"``"J#X1X`0``,<"`?"104@^$40$``(7`#X3I
+M_O__C40D4,=$)!0`````B40D$,=$)`P!````BT,PBU`(BT`$B30DB50D"(E$
+M)`3H_/___^FS_O__QT0D2`````#'1"1,`````(U$)%#'1"04`````(E$)!#'
+M1"0,`0```(M#,(M0"(M`!`-$)$@35"1,B30DB40D!(E4)`CH_/___X-$)$@!
+MBT0D2(-4)$P`@_`""T0D3`^$3_[__^NJQX=,`0``_____\>'4`$``/_____I
+M[/W__P^W3S*+1"0HBU0D+/?9B<LAR,'['R':B40D*(E4)"SI=_[__X/*!X!_
+M"`J(ET@!```/A;7]__\/MD\P,<`QTH/I`?;!(`^4P`^5PM/BT^")1SB)5SSI
+MDOW__X!_,``/A&'^__\QR8M$CTB+4!B+0!0!1Q0/MD<P$5<8@\$!.<A_Y>D_
+M_O__T>B#X`&(1"0PZ:#\__^`?"1110^%I/[__\9$)%!%QD0D45+IG?[__X"\
+M)$\"``!5#X5Z_O__L`'&A"1.`@``5<:$)$\"``"JZ67^__^053'25U93@>R,
+M````B[PDH````(M'&(MW'(L`Z&"@__^%P(G##X1O`0``,<"-="8`Q@0P`(/`
+M`8/X6'7TC6PD%(GHQ@``C90DC````(/``3G0=>^+4P2);"0$BT,(B00D_U(<
+M#[9$)"J-5@2(1@,/MD0D*(@&#[9$)"F(1@&+1"10B48$BT0D5(E"!(M$)%B)
+M0@B+1"1<B4(,BT0D8(E"$(M$)&2)0A2+1"1HB4(8BT0D;(E"'(M$)'")0B"+
+M1"0LC58HB48HBT0D,(E"!(M$)#2)0@B+1"0XB4(,BT0D/(E"$(M$)$")0A2+
+M1"1$B4(8BT0D2(E"'(M$)$R)0B`/MD0D%(A&4`^V1"05B$91#[9$)!:(1E(/
+MMD0D%XA&4XM##(E&3(![1`!U:0^V1"0KB$8"BQN%VW46ZRN-M@`````/MD0D
+M*P!&`HL;A=MT%XM3!(EL)`2+0PB)!"3_4AR`?"0G`'3;C4<PQT<P$&P#`(E_
+M-,='.`````")1"0$BT<(B00DZ/S___^!Q(P```!;7E]=PX!.`P3KD<='+/__
+M___KPXVT)@````"-O"<`````53'25U93@>R,````B[PDH````(M'&(MW'(L`
+MZ+">__^%P(G##X0Y`0``,<"-="8`Q@0P`(/``8/X3'7TC6PD%(GHQ@``C90D
+MC````(/``3G0=>^+4P2);"0$BT,(B00D_U(<#[9$)"J-5@2(1@,/MD0D*(@&
+M#[9$)"F(1@&+1"10B48$BT0D5(E"!(M$)%B)0@B+1"1<B4(,BT0D8(E"$(M$
+M)&2)0A2+1"1HB4(8BT0D;(E"'(M$)'")0B"+1"0LC58HB48HBT0D,(E"!(M$
+M)#2)0@B+1"0XB4(,BT0D/(E"$(M$)$")0A2+1"1$B4(8BT0D2(E"'(M$)$R)
+M0B`/MD0D*XA&`HL;A=MU$NLGB?8/MD0D*P!&`HL;A=MT%XM3!(EL)`2+0PB)
+M!"3_4AR`?"0G`'3;C4<PQT<P$&P#`(E_-,='.`````")1"0$BT<(B00DZ/S_
+M__^!Q(P```!;7E]=P\='+/_____KR8UT)@"#[!R)="04B<:)7"00B7PD&(M8
+M!(M0"(M#'(L[B4(<@*-)`0``\\=#'/____^+0AR`HDD!``#SB40D!(M'!(D$
+M).C\____BT,@B3PDB40D!.C\____B5@HB7`LQD!D!,=`<(!Z`P")!"3H_/__
+M_XM<)!"+="04BWPD&(/$',.)]E.#[`B+7"00BT,8BP")!"3H_/___XD$).C\
+M____C4,PQT,P$&P#`(E;-,=#.`````")1"0$BT,(B00DZ/S___^#Q`A;PXUT
+M)@"-O"<`````4X/L"(M$)!"+0`2+&(D$).C\____BX,H`0``C5`PQT`P$&P#
+M`(E`-,=`.`````")5"0$BT`(B00DZ/S___^#Q`A;PXVV`````(V\)P````"#
+M[!R+5"0@B5PD$(ET)!2)?"08@WHL_8MZ)`^$\P```/:'20$```C&AQ<"````
+M='2+0BR#^/T/A+8"``"%P`^%MP(``(N'9`$``#'),?:+4%P/MUAD@>+__P\`
+M.?$/@U,!``#'A\0!``!@<0,`B;_(`0``QX?``0```````(V'P`$``(E$)`2+
+M!XM`!(D$).C\____BUPD$(MT)!2+?"08@\0<PP^VMT@!``#WQA`````/A(D`
+M``"+0BR#^/T/A-@!``"%P`^%W0$``(M/!`^V1S"+GU`!```/MDD&*<B+CTP!
+M``")PL'Z'P^OV`^ORO>G3`$```'9C101.U<8#X+=`0``#X8I`@``N@,```#I
+M<@$```^VAQ<"```\`@^/_O[__X/``8B'%P(``,>'Q`$``#"J`P")O\@!``#I
+M/?____?&(`````^%M````/?&0`````^$//____?&`0```(GV#X0G`@``BUHL
+MA=L/A?P!``"+3P0/MD<PBY]0`0``#[9)!BG(BX],`0``B<+!^A\/K]@/K\KW
+MITP!```!V8T4$3M7&'(A=P4[1Q1R&KH)````Z<\```!W#CG:C;8`````#X*=
+M_O__]H=(`0``4(UV``^$5?___XN'3`$``#'2)?__/P"#^@`/AS____^#^'\/
+MAS;____I:?[__XVV`````(M2++@+````A=)U4(GRL`J$TGA(BT\$#[9',(N?
+M4`$```^V208IR(N/3`$``(G"P?H?#Z_8#Z_*]Z=,`0```=F-%!$[5Q@/@F$!
+M``!W"3M'%`^"5@$``+@,````@^9?B?*(ET@!``")?"0$B00DZ/S____VAT@!
+M```(#X04_O__N@$```")^(M<)!"+="04BWPD&(/$'.FEPO__@#T```````^%
+ME````(/F[XGPB(=(`0``B7PD!,<$)`@```#H_/___^G,_?__QT(L`````(E\
+M)`3'!"0<````Z/S___^0]H=)`0``"`^$V?[__^E2_?__@#T``````'7-BX=D
+M`0``@*=)`0``]XM`"("@20$``/>)?"0$QP0D%````.C\____BUPD$(MT)!2+
+M?"08@\0<PSM'%'*IZ<W]___'0BP`````B7PD!,<$)!P```#H_/___P^WAQ0"
+M```QT@&'3`$``!&74`$``.E>_?__@^:_B?"(AT@!``")?"0$QP0D#P```.C\
+M____Z0?]__^#YK^)\HB72`$``(E\)`3'!"0.````Z/S____IY_S__XN'Z`$`
+M`(`X``^$"O[__X/FWXGPB(=(`0``Z;3^__^-="8`@^P4B70D"(MT)!R);"00
+MBVPD&(E<)`2)?"0,C88(`@``B8;D`0``C886`@``B8;H`0``BX98`@``]H9)
+M`0``"(FNU`$``,>&X`$```````#'ANP!````````B;;P`0``QX;T`0``8*8#
+M`(F&"`(``'16QX;8`0``*O\``,>&W`$```0```"+AKP!```QTH/``8/X90^=
+MPH/J`2'0B8:\`0``C8;,`0``BUPD!(EL)!B+="0(B40D'(M\)`R+;"00@\04
+MZ?S___\/MKY(`0``]\=P````#X3-````B?B#X*`\H`^$Z````(M6!`^V1C")
+M%"0/MDH&BYY0`0``*<B+CDP!``")PL'Z'P^OV`^ORO>F3`$```'9C101.U88
+M#X.=````]\<0````N"/_``!U$(/G((GX/`$9P/?0!27_``"+EE`!``"+CN0!
+M``")AM@!``"+ADP!``")40B+%"2)002`>@4`#X21````BY;D`0``#[=&,F:)
+M0@SVAD@!```@QX;<`0``#@````^$]O[__XN&Z`$``,8``,>&X`$```$```#I
+MWO[__XM<)`2+="0(BWPD#(ML)!"#Q!3#C70F`'<..T84#X)8____D(UT)@"-
+MALP!``#'AO@!````````BUPD!(E$)!B+="0(BWPD#(ML)!"#Q!3I-/K__XM&
+M%(M6&"N&3`$``!N64`$``(N.Y`$``(/Z`'8.N(````!FB4$,Z5+___\]@```
+M`';PB?;KYXVT)@````"-O"<`````@^P,BT0D$(M`)(V0P`$``,>`Q`$``#"J
+M`P")@,@!``")5"0$BP"+0`2)!"3H_/___X/$#,.-="8`C;PG`````(/L'(ET
+M)!B+="0@B5PD%(M>#(7;#X3N````#[:#20$``*@$='NH"'5GBY-D`0``A=)T
+M78M"!(7`=%:+2@B%R71/@(A)`0``"(M""("(20$```B-@\`!``#'@\0!```P
+MJ@,`B9O(`0``B40D!(L#BT`$B00DZ/S___^)7"0$QP0D$@```.C\____C;0F
+M`````(M<)!2+="08@\0<PXUT)@`/MI9(`0``]L(0=>2%VW0$J`AUW/;"8'77
+M@^+W@\H0C8;``0``B)9(`0``QX;$`0``,*H#`(FVR`$``(E$)`2+!HM`!(D$
+M).C\____B70D!,<$)`0```#H_/___XM<)!2+="08@\0<PXGSZ0O___^055=6
+M4X/L#(ML)""+11B+6`2+`(D$).C\____@_L.B<9V,L=%+/[___^-13#'13`0
+M;`,`B6TTQT4X`````(E$)`2+10B)!"3H_/___X/$#%M>7UW#_R2=+`X``)"-
+M="8`B<:+1@R%P'7W@'X(!8UV``^$"08``("F2`$``+^)="0$QP0D#@```.C\
+M____BUX<A=L/B&T&``"+3@RZ`0```.D$!```BT`,A<!T#?:`20$```P/A6G_
+M__]F]X9(`0``<`P/A5K____VAAP"```!#X1-____@'X(!0^%.P8``(!^,``/
+MA)`&```Q_Y"-="8`ZP\/MD8P@\<!.?@/CG@&``"+7+Y(A=MTZ8!["`1VX_:#
+M2`$``!!UVHM31(M#0(E4)`2)!"3H_/___XM3!`^V4@8YT`^-Z?[__P^V@T@!
+M``#'@\0!```PJ@,`B9O(`0``@^#W@\@0B(-(`0``C8/``0``B40D!(L#BT`$
+MB00DZ/S___^)7"0$QP0D!````.C\____Z6K___^`>`@%#X2=!```@*!(`0``
+MYXE$)`3'!"0%````Z/S___^+3@RZ`0```.GS`@``]H!(`0``$`^$7_[___:`
+M'`(```$/A%+^__^`H$@!``#EBU9$BT!`QX9,`0``_____\>&4`$``/____^)
+M5CR)1CB)="0$QP0D!@```.C\____BTX,@*9(`0``_H7)=$V`>3``=$<QVXM$
+MF4B%P'0O]H`<`@```70F@'@(!'8@#[:02`$```^V@4@!``"#X@&#X/X)T*@!
+MB(%(`0``=0L/MD$P@\,!.=A_OHM.#(M&0`M&1(/X`1G2@\("Z30"``"+0`R%
+MP'0-]H!)`0``#`^%F?W__V;WAD@!``!P#`^%BOW___:&'`(```$/A'W]__^`
+M?@@%#X7R!```@'XP``^$</W__\=$)`@`````ZQ.#1"0(`0^V1C`[1"0(#XY3
+M_?__BT0D"(M\ADB%_W3A@'\(!';;]H=(`0``('72BTXXBUX\BT9`BU9$"<@)
+MVHE4)`2)!"3H_/___XM6!`^V4@8YT`^-!OW__XV'P`$``("/2`$``"#'ATP!
+M````````QX=0`0```````,>'Q`$``#"J`P")O\@!``")1"0$BP>+0`2)!"3H
+M_/___XE\)`3'!"0)````Z/S____I4/___X"@2`$``-^)1"0$QP0D"@```.C\
+M____Z9K\__^`H$@!``#?Z8[\___V@!P"```!#X1Z_/__BT!`"T9$#X5N_/__
+M#[>&2`$``&8E<0QF@^@!#X59_/__@'X(!0^%4`0``(!^,`!T+3'_BUR^2(7;
+M=!B`>P@$=A(/MH-(`0``@^!!+`$/A'\$```/MD8P@\<!.?A_U8"F2`$``/?I
+M%_S__X"@2`$``+3'@$P!``#_____QX!0`0``_____\=`.`````#'0#P`````
+MB40D!,<$)!````#H_/___XM>#(7;#X1[`@``#[9+,(7)#XYQ`@``,=(Q]HM$
+MDTB%P'0B]H`<`@```709@'@(!'83]H!(`0```70*O@$```"0C70F`(/"`3G*
+M=<^%]@^$-`(``(M+#(G>N@$```"#^@,/E<"$P`^$,P$``(7)#X0K`0``B<Z+
+M20SI&0$``("@2`$``-^)1"0$QP0D"P```.C\____Z43[__]F]X9(`0``<`B+
+M@&0!```/A2C[__^%P`^$(/O__X!X9P`/A1;[__^+4`2+0`CV@AP"```!#X0#
+M^___]H`<`@```0^$]OK__X"B20$``.^`H$D!``#O@(I)`0``"("(20$```B-
+MAL`!``#'AL0!```PJ@,`B;;(`0``B40D!(L&BT`$B00DZ/S___^)="0$QP0D
+M$@```.C\____Z:7Z__^+B&0!```/MX!(`0``9B5P"&8]``@/A8/Z__^%R0^$
+M>_K__XM!!(M1"("@20$``/>`HDD!``#WB70D!,<$)!,```#H_/___XM.#+H!
+M````Z='^__^+2`RZ`P```#'`A,`/A<W^__^`CD@!```$@_H"#X3M````BX9D
+M`0``A<`/A.T```"+4`2+6`B%TG0(B10DZ/S___^%VP^$!_K__XD<).C\____
+MZ?KY__\QVX!X,`!U&.E<^O__C70F``^V1C"#PP$YV`^.2?K__XM$GDB%P'3I
+M@'@(!';C]H!(`0``$'3:@*!(`0``YXE$)`3'!"0%````Z/S____KP8!^,``/
+MA`3Z__\QVY"-="8`ZP\/MD8P@\,!.=@/CNSY__^+1)Y(A<!TZ8!X"`1VX_:`
+M2`$``$!TVH"@2`$``+^)1"0$QP0D#@```.C\____Z\&)\X"C2`$``/Z)'"3H
+M_/___^FX_?__B30DZ/S___^0Z33Y__^)-"3H_/___XUV`.DD^?__B30DZ/S_
+M__^+3@RZ`0```.F/_?__BU9$BT9`B50D!(D$).C\____BU8$#[92!CG0#XWG
+M^/__C8;``0``@(Y(`0``$,>&Q`$``#"J`P")ML@!``")1"0$BP:+0`2)!"3H
+M_/___XET)`3'!"0$````Z/S___^+1D"`ID@!``#W"T9$#X0,^?__Z/S___^+
+M3@RZ`0```(E&*.D(_?__BTXXBUX\BT9`BU9$"<@)VHE4)`2)!"3H_/___XM6
+M!`^V4@8YT`^-5OC__XV&P`$``(".2`$``"#'ADP!````````QX90`0``````
+M`,>&Q`$``#"J`P")ML@!``")1"0$BP:+0`2)!"3H_/___XET)`3'!"0)````
+MZ/S____I!OC__XV&P`$``(".2`$``$#'ADP!````````QX90`0```````,>&
+MQ`$``#"J`P")ML@!``")1"0$BP:+0`2)!"3H_/___XET)`3'!"0-````Z/S_
+M___IC/O__P^V@T@!``#'@TP!````````QX-0`0```````,>#Q`$``#"J`P"#
+MR$"#X/>(@T@!``"-@\`!``")F\@!``")1"0$BP.+0`2)!"3H_/___XE<)`3'
+M!"0-````Z/S____I'OO__XUV`%575E.#[!R)1"00]H`<`@```74D#[:`20$`
+M`(/@!#P!&?^!YP#X__^!QP$(``"#Q!R)^%M>7UW#BTPD$`^VL4@!``#WQ@(`
+M```/A%4!``"+1"00BTA`BUA$OP(```#WQ@$```!T!H'/`!```/?&$````'0#
+M@\\$]\8@````=`:!SP`!``"#YD!T!H'/``(``(G:"<H/A3L"``"+;"00#[:%
+M'`(``*@$=`.#SQ"H`G0#@\]`BT0D$/:`2`$```AT!H'/@````(M4)!`/MH))
+M`0``J`1T!H'/``@``*@(=`:!SP`$``"+3"00#[9),(7)B4PD&`^.T@```#'M
+MZVV+<42+64")\HG8]](C43SWT"-!.(G1"<%T`X//`O9$)!<!=`:!SP`0``#V
+M1"07$'0#@\\$]D0D%R!T!H'/``$``/9$)!=`=`:!SP`"``")\`G8=`.#SPCV
+M1"07"'0&@<^`````@\4!.6PD&'1ABT0D$(M,J$B%R73K]H$<`@```73B@'D(
+M!';<#[:12`$``(A4)!>#X@(/A&3___^+64"+<43I<____XG/BTE`BU]$B<B)
+MVO?0]](C5SPC1S@Q_XG5"<4/A)C^___ICO[___?'`@```'06]\<`$```C;0F
+M``````^$V@```(/G_8MT)!B%]@^.#0$``(M4)!"+6DB%VP^$*O[__S'M]H,<
+M`@```0^$&_[__X!["`0/AI,````/MG,PA?9^6XM#2(7`#X3^_?__]H`<`@``
+M`0^$\?W__XM0,(M"!`M""`^%XOW__S')ZRB+1(M(A<`/A-+]___V@!P"```!
+M#X3%_?__BU`PBT($"T((#X6V_?__@\$!.<YUT9"#Q0$Y;"08='F+3"00BURI
+M2(7;#X25_?__]H,<`@```0^$B/W__X!["`0/AVW___^+4S"+0@0+0@ATQ>EN
+M_?__B?@E""```(/X"`^%&?___^D1____B0PD@\\(B5PD!.C\____BTPD$(M1
+M!`^V4@8YT`^-H_W__X'/`"```.F8_?__@<\```!`Z2']__^-=@!55U93@^P,
+MBWPD((M'&(M?"(LHB2PDZ/S___^+<PR#PPPYWHE$)`AU#>M/D(UT)@"+-CG>
+M=$2-AMC]__^+4`R%TG7MA>UU"?:`'`(```)U#SE$)`AT6?:`'`(```)TT8"@
+M'`(``/V`>`@!=#F)!"3H_/___XLV.=YUO(U',,=',!!L`P")?S3'1S@`````
+MB40D!(M'"(D$).C\____@\0,6UY?7<.)!"3H_/___^N!]H`<`@```@^%=/__
+M_X"('`(```+KH8UT)@"-O"<`````@^Q,B7PD1(M\)%")7"0\B70D0(EL)$B+
+M7QB+`X7`=4:+1PCH2)?__\='+/S___^-1S#'1S`0;`,`B7\TQT<X`````(E$
+M)`2+1PB)!"3H_/___XM<)#R+="1`BWPD1(ML)$B#Q$S#B00DC6L$Z/S___^)
+MQHM#!*@!#X42`0``J`(/A5H!``"H!`^%J@$``*@(#X7Z`0``J!!U9JA`C70F
+M`'0AQT<L``````^V1E*`?0H`#Y7"@^#^"="`3E`0B$92BT4`J"`/A8P```#V
+M1E`0#X1:____C40D$(M65(E$)`2+1F")!"3_4CP/MD0D(HA&3HDT).C\____
+MZ3'___^)]L9$)#0"#[9%"(A$)#B-1"0TBU94B40D!(M&8(D$)/]28(7`B4<L
+M=1\/ME91@\H!B%91@'T(``^5P(/B_8!.4!`!P`G"B%91BT4`J$`/A''____I
+M2____\9$)#0'#[9%"8A$)#B-1"0TBU94B40D!(M&8(D$)/]28(E'+/9&4!`/
+MA*K^___I2____XVV`````,9$)#0`#[9%!(A$)#B-1"0TBU94B40D!(M&8(D$
+M)/]28(7`B4<L=1D/MD90B<*#R)"#RH"(5E`/ME4$B$90B%9/BT,$J`(/A*K^
+M__^-="8`QD0D-`0/MD4%QD0D.0"(1"0XC40D-(M65(E$)`2+1F")!"3_4F"%
+MP(E'+'4@#[9648/*$(A648!]!0`/E<"#XM^`3E`0P>`%"<*(5E&+10"H!`^$
+M5O[__\9$)#0%#[9%!L9$)#D`B$0D.(U$)#2+5E2)1"0$BT9@B00D_U)@A<")
+M1RQU(`^V5E&#RD"(5E&`?08`#Y7`@^)_@$Y0$,'@!PG"B%91BT4`J`@/A`;^
+M___&1"0T`P^V10>(1"0XC40D-(M65(E$)`2+1F")!"3_4F"%P(E'+'4@#[96
+M48/*!(A648!]!P`/E<"#XO>`3E`0P>`#"<*(5E&+10"H$`^$M_W__^D8_O__
+MD(VT)@````"#["R)="0@BW0D,(E<)!R)?"0DB6PD*(M>&(L#A<!U1HM&".A8
+ME/__QT8L_/___XU&,,=&,!!L`P")=C3'1C@`````B40D!(M&"(D$).C\____
+MBUPD'(MT)""+?"0DBVPD*(/$+,.)!"2-:P3H_/____9#!`&)QW47]D=0$'2P
+MB3PDZ/S____KIHVT)@````#&1"04``^V102(1"08C40D%(M75(E$)`2+1V")
+M!"3_4F"%P(E&+'7!#[9'4(G"@\B0@\J`B%=0#[95!(A'4(A73^NFC;8`````
+MC;PG`````(/L'(E<)`R+7"0@B70D$(E\)!2);"08O0$```"+0QB+`(D$).C\
+M____@7L,#/\``(G&#Y3`#[9.4(G'B<C`Z`(AQ8GX#[;0.=5T&HT$O0````"#
+MX?L)P8/)$(A.4(DT).C\____C4,PQT,P$&P#`(E;-,=#.`````")1"0$BT,(
+MB00DZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<PXUT)@!55XG'5E.!["P"``")
+M3"0DB%0D*X!X,``/A(D```")R#'M@^@!B40D(.M2D(UT)@"#?"0@`0^&A0``
+M`(![-`"+<R1U!X!\)"L`=`WVAAP"```!#X6#````B1PDZ/S____V1E`0=`WV
+MAAP"```!#X7R````@\4!B>@X1S!V*HM<KTB%VW3N#[9#"#P$=J,/ME0D*XG8
+M@\4!BTPD).A@____B>@X1S!WUHD\).C\____@<0L`@``6UY?7<.-M@`````\
+M!(G>#X3)````@WPD)`)UHHDT).C\____ZYB-1"0LQT0D%`$```")1"00QT0D
+M#`$```"+0S"+4`B+0`2)-"2)5"0(B40D!.C\____A<`/A43___^`O"0J`@``
+M5717,<"`?"0L171\A<`/A"G___^-1"0LQT0D%`````")1"00QT0D#`$```"+
+M0S"+4`B+0`2)-"2)5"0(B40D!.C\____Z?/^__^)-"3H_/___XUV`.G^_O__
+M@+PD*P(``*IUG[`!QH0D*@(``*K&A"0K`@``5>N-BW,DB1PDZ/S____I)___
+M_X!\)"U2#X5Y____QD0D+%+&1"0M1>ER____C78`@^P<B5PD#(M<)"")="00
+MB7PD%(EL)!B+0QB+4PB+:`2+`(E4)`B)!"3H_/___XNP9`$``(7V#X2$````
+MBU8$A=)T78N*(`(``(7)=$>+0QS'`/_____'0RS_____C4,PQT,P$&P#`(E;
+M-,=#.`````")1"0$BT,(B00DZ/S___^+7"0,BW0D$(M\)!2+;"08@\0<PXN2
+M5`(``(72=:^)]HM6"(72=!F+NB`"``"%_W6<BXI4`@``A<EUDI"-="8`]H!(
+M`0``<'6$#[9X,(7_?B0QR8M4B$B%TG03@'H(!'8-]H)(`0``<`^%7____X/!
+M`3GY==Z#Y0,/E,&%]HG/=%"+1@2%P'0*#[;1,<GH+OW__XM&"(7`=`R)^0^V
+MT3')Z!O]__^+1A"+5@R)0@2)$(M$)`B)="0$@^B`B00DZ/S___^+0QS'````
+M``#I#/___P^VT3')Z.7\___KYHUV`%575HG.4X'LK````(E4)!R)1"0@Z/S_
+M__^+5GB)5"0TB40D+(M&=(E$)#`/MD8.B<+`Z@2$THA4)#]U#`^V3@J$R8A,
+M)#]T8P^V5@V#X`^(1@Z`^D!W"X#Z`7<6@'X,!W00N/____^!Q*P```!;7E]=
+MPX32=#PQV^L=C;8`````]H`<`@```739#[96#8/#`0^VPCG8?AN+1)Y\B00D
+MZ/S___^`>`@!=-?KM\9$)#\!ZY:`?@P(=ZH/MD8,C70F`/\DA6@.``#&1"0^
+M#,9$)$``QX0DC`````P```"+A"2,````B00DZ/S___^%P(E$)%0/A&O___^`
+M?"0_`<=$)%@`````=C`/MD8-,=(/MDPD/V;W\6:%T@^%1?___P^V1"1`B00D
+MZ/S___^%P(E$)%@/A"S___^+5"0T"U0D,`^%F`,``(!\)#X'#X0F!```QT0D
+M,/____\QV\=$)#3_____@'X-``^$W@<``(M$GGR)!"3H_/___XM0+#E4)#2+
+M0"AR$'<&.40D,'8(B40D,(E4)#0/MD8-@\,!.=A_S8M4)%0/MEH%A-MU&HM$
+M)%B%P`^$M0```(M4)%B`>@4`#X2G````#[9&#KK_____B<&+1"0PT^*)T\'[
+M'R'0BU0D-(E$)#")1G0AVHM<)%2)5"0TB59X@'L%`'0U#[9&#?9T)#^+3"0T
+M#[;0#[9#!BG"BT0D,(G5P?T?#Z_*#Z_%`<&+1"0P]^*-+!&)1G2);GB+1"18
+MA<!T-(M4)%B`>@4`="H/MDH&#[9$)#^+7G0IR(M.>(G"P?H?#Z_:#Z_(]V9T
+M`=F-%!&)1G2)5GB+1"0<A<`/A(````"+3"0<@'D(!`^&W?W__XL9BT0D((E<
+M)"0YPP^%R_W___:!'`(```$/A+[]__^+@60!``"%P`^%L/W__V;W@4@!``!0
+M`@^%H?W__XM1&#M6>(M!%`^'DOW__W().T9T#X>'_?__@&8/_(M<)!R`>P@'
+M#X3-`0``@'X,!P^$VP$``#'_BX0DC````(M4)"")1"0$B10DZ/S___^%P(E$
+M)%P/A$;]__^`?"0^!P^$#P4```^V5@W'A"24`````````(32=23I=0(``)"#
+MP@&)E"24````#[96#0^VPCN$))0````/CE8"``"+C"24````BT2.?(D$).C\
+M____B<,QP(7_=1.+;"0<A>UT"XM$)!R)VNADA/__BU0D-(E$)`R+1"0PB1PD
+MB50D"(E$)`3H_/___XN4))0```"+3"1<A<")1)%(=86+A"24````A<!^'C';
+MBU0D7(M$FDB#PP&)!"3H_/___SN<))0```!UY(M,)%R)#"3H_/___[C_____
+MZ6W\___&1"0^!\9$)$``QX0DC`````<```#IR/S__X!^#@</A43\___&1"0^
+M"L9$)$``QX0DC`````H```#II/S__\9$)#X)QD0D0`#'A"2,````"0```.F*
+M_/__QD0D/@C&1"1``,>$)(P````(````Z7#\__^`^@(/AKH$``#&1"0^!<9$
+M)#\"QD0D0`;'A"2,````!0```.E(_/__@'PD/P/&1"0^!<>$)(P````%````
+M&=N#X_Z#PPB(7"1`Z2+\__^`?@P'#X2^!P``BUPD'(![,`$/A"7^__^_`0``
+M`.D=_O__BTPD5`^V606$VW0Z#[9&#?9T)#\/ME$&#[;`*=")PL'Z'XE$)`B+
+M1"0PB50D#(M4)#2)!"2)5"0$Z/S___^)1"0PB50D-(M4)%B%T@^$>/S__XM4
+M)%B`>@4`#X1J_/__#[92!@^V1"0_*="+5"0TB40D"(G!BT0D,,'Y'XE,)`R)
+M5"0$B00DZ/S___^)1"0PB50D-.DQ_/__,=N`?@T`=1KIAP@```%&=`^V1@T1
+M5GB#PP$YV`^.L@,``(M$GGR)!"3H_/___XM0+(M`*(G1"<%UT^FN^O__BUPD
+M7(A3,(M4)"R+1"1<B5`DB5`L@'PD/P$/AD@&```/MDPD0#'M#[9\)#^)C"28
+M````BYPDF````(M$)"")7"0$B00DZ/S___^%P(G##X2;!0``BTPD7(U4J4@Q
+MR87_?A"+`H/"!(E$BTB#P0$YSW7P#[9$)#^(0S"+5"1<BT(DB?*)0R0QP(-\
+M)!P`#Y3`B<&)1"0HB=CH[]7__XGJB>C!^A^+3"1<]_\/ME$PB5R!2`^V1"0_
+M`>@!_3C0#X)P____#[;"]G0D/SP_B$$P=R&+7"1<#[;`C4@!C52#2(/!`8U!
+M_\<"`````(/"!#P_=NV+1"1<B?*+3"0HZ(O5__^+1"1<#[90,(72?DPQ_XM,
+M)%R+7+E(@\<!BTPD5`^V00:+3"1<*<*)T,'X'XE4)`B)1"0,BT$4BU$8B00D
+MB50D!.C\____B5,8B4,4BUPD7`^V4S`Y^G^VBUPD'(7;#X11!@``BU0D'(M,
+M)%R+0BR)02R)3"0$B10DZ/S___^$P`^%&P(``(M<)!R+3"1<#[:3'`(```^V
+M@1P"``"#X@2#X/L)T(B!'`(```^VDQP"``"#X/V#X@()T(B!'`(```^V0S2(
+M032+7"0<BU,8.U$8BT,4=UER!3M!%'=2BU0D7(M"!(!X!@!U#(M"2(M`!(!X
+M!@!T.8M$)!SHW>S__XG'@><"$```#X6:`0``BTPD'(M<)%R+41@[4QB+010/
+M@H,!``!W"3M#%`^">`$``(M$)!R`N!T"```"#X0`!@``BU0D'(M,)%R+7"0@
+MBT(<B4$<BT,<B=F#P1PYR'4/Z6`#``"+`#G(#X16`P``C5#TBUPD'#E:*'7J
+MBUPD7(E:*.OABWYTBVYX#[96#8GY">D/E<"%TGX/A,#'A"24`````````'4V
+MQX0DE`````````"$P'0-.90DE`````^$1?O__P^VA"24````BU0D7(A",.DQ
+M_?__C;8`````BYPDE````(M$GGR)!"3H_/___XM(+(M0*(E\)&");"1D.<UR
+M#G<$.==V"(E4)&")3"1DBTPD9(M4)&#'1"0,`````(D$)(E,)`B)5"0$Z/S_
+M__^+C"24````BUPD7(7`B42+2`^$P?K__RM\)&`;;"1D@X0DE`````&)^P^V
+M5@T)ZP^5P#N4))0````/CD/___^$P`^$3/___^EA____QD0D/@;&1"1``,>$
+M)(P````&````Z9/W__^+1"14#[98!>E0^/__OP$```"+1"0@@^B`B00DZ/S_
+M__^)PS'`Q@08`(/``8/X:'7TZ/S___^+5"1<B5,(B0.+1"0<B4,$B1PDZ/S_
+M__^+3"1<BT$$@'@&``^%7`(``(M!2(M`!(!X!@`/A4P"``#&0V8#@'L4``^$
+MRP,``(![9@,/A,T#``"+3"1<BT$4BU$8@'MF`HE#7(E38`^$:0,``(M$)!R`
+MN!T"```"#X18`P``BU0D'("*20$```2+3"1<@(E)`0``!("A2`$``/V)F60!
+M``")FF0!``"+1"0@C5,,BT@8B5`8@\`4B4,,B1&+5"0<B4L0B10DZ/S___^+
+M3"1<B0PDZ/S___\/MD8/J`$/A8T```"H`G1Z@'PD/P$/ACT#``"+7"18@'L&
+M``^$+P,``(M$)%R`>#``=%<Q]HM4)%R+7+)(@\8!C8/``0``@(M(`0``$,>#
+MQ`$``#"J`P")F\@!``")1"0$BP.+0`2)!"3H_/___XE<)`3'!"0$````Z/S_
+M__^+3"1<#[9!,#GP?ZN+5"1<BX)8`@``Z7KU__^`?"0_`0^&/@$``(M$)%B`
+M>`8`#X0P`0``BU0D7(!Z,`!T5S'VBTPD7(M<L4B#Q@&-@\`!``"`BT@!``!`
+MQX/$`0``,*H#`(F;R`$``(E$)`2+`XM`!(D$).C\____B5PD!,<$)`T```#H
+M_/___XM<)%P/MD,P.?!_JXM$)%R`H$@!``"_Z6?___^+1"0<,<DQTNA<\?__
+MBU0D7(M,)""+0AR)1"0$BT$$B00DZ/S____II?[__XGJB>C!^A_W_X7`B<9^
+M&XM4)%RY`0```(M$FD@QTH/#`>@7\?__.?-UY8M,)%P/MD$P.<4/C0?X__^-
+M=*E(B>N+!H/#`8/&!(D$).C\____BU0D7`^V0C`YV'_DZ>#W__^%_[@"````
+M=`>`>Q0`#Y7`B$-FZ:#]__\QR8M$)%R)\H-\)!P`#Y3!Z`_0___IU_K__XM4
+M)%R)T`7``0``@(I(`0``0,>"Q`$``#"J`P")DL@!``")1"0$BP*+0`2)!"3H
+M_/___XM,)%S'!"0-````B4PD!.C\____Z5S^__^+1"0<@'@P``^$-/C__X!^
+M#0`/A"KX__^+0$@Q_X7`=33INO/__XM<)!R#QP$/MD,P.?@/CG4!```/MD8-
+M.?@/CD\!``"+3"0<BT2Y2(7`#X2+\___BU@DBT2^?(D$).C\____.<-UOHM,
+M)!P/MD$P.D8-#X=G\___#[;(A<D/CC`!``"+7"0<,?^+0TB%P'4HZ4KS__^+
+M7"0<@\<!#[9+,#GY#XX+`0``BU0D'(M$NDB%P`^$)_/__XM8)(M$OGR)!"3H
+M_/___SG#=,KI#_/__XM$)!RYT'H#`(G:Z-V>__\QP.G]\O__BTPD7(D,).C\
+M____]D8/`0^%;?W__XM<)%R)'"3H_/___^G#_/__,<`QTH7_#X4]_/__BTPD
+M'(M!%(M1&.DN_/__BUPD7(G8!<`!``"`BT@!```0QX/$`0``,*H#`(F;R`$`
+M`(E$)`2+`XM`!(D$).C\____B5PD!,<$)`0```#H_/___^GJ_/__BU0D7+E@
+M=P,`Z#Z>__\QP.E>\O__BTPD5`^V607ID//__XM4)!P/MD((/`</A)[V___I
+MI_;__Y"-="8`#[9#".OHBUPD'(M&=(M6>(G'B=4K>Q0;:QB)ZPG[#X39````
+MBT0D'(M,B$2)3"1\BU$DB50D>(M:)(7;=0_I-@$``(L;A=L/A"P!``"+0Q2%
+MP'7OBTPD?(M),(M!#(M1$(F,)(@```")A"2`````B90DA`````-!!!-1"(M+
+M"#-#!#'1"<%UNXM4)'R+0A2+4AB)1"1PBT,,B50D=(M3$#G5#X>*`@``<@@Y
+MQP^#@`(``(N$)(````"+E"2$````BXPDB`````'X$>J)00R)41"+3"1\B4$4
+MB5$8`7L$$6L(*7L,&6L0BUPD>(!+4!")'"3H_/___XM&=(M6>(M,)!R+7"0<
+MB5$8C580B4$4BT80@<%4`0``B8-4`0``BT($B4$$BT((B4$(BT(,B4$,B1PD
+MZ/S___^+0QR)1"0$BP.+0`2)!"3H_/___P^V1@^#X!S!^`*`NQT"```"B<(/
+MA"@"``"+3"0<BX%8`@``B)$=`@``Z;[P___'1"1P`````,=$)'0`````BU0D
+M'(GY">D/E<`/ME(PB90DG`````^V5@TYE"2<````#XVT````A,`/A+D```"+
+MG"2<````QX0DD`````````")7"08BYPDD`````-<)!B+1)Y\B00DZ/S___^+
+M2"R+4"B)?"1HB6PD;#G-<@YW!#G7=@B)5"1HB4PD;(M,)&R+5"1HQT0D#```
+M``")!"2)3"0(B50D!.C\____BTPD'(7`B4292'1H*WPD:(M4)!P;;"1LB?F#
+MA"2<`````0GIB5`,#[96#0^5P(.$))`````!.Y0DG````'\LA,!T"3F4))P`
+M``!T*(M$)!P/MIPDG````(A8,(M&=(M6>.ER_O__D(UT)@"$P'3=Z37___^+
+M7"1T"UPD<'1+BU0D'`^V0C"+1()$B00DZ/S___^+3"0<BU0D=(M$)'`/MEDP
+MB50D"(M4)'C'1"0,`````(E$)`2#ZP&)%"3H_/___XM,)!R)1)E(BUPD'`^V
+M0S`[A"2<````#XTO[___C5R#2#'VB<>+`X/&`8D$).C\____C00^QP,`````
+M@\,$.X0DG````'S>Z0#O__^+C"2(````*<<9U0.$)(`````3E"2$````B4$,
+MB5$0BTPD?(E!%(E1&(E<)`2+7"1XB1PDZ/S___^`2U`0B1PDZ/S___^)Z`GX
+M#X4(_O__BT9TBU9XZ7']__\\`@^$T/W__XB#'0(``(M$)"2YX)`#`(N0*`$`
+M`(G8Z&":__\QP.F`[O__B?:-O"<`````5E.#[!2+="0@BUX8BP.)!"3H_/__
+M_XU+!(G"BT8(Z.WM__^%P(G"="V#^/]T,HM&',=&,!!L`P")=C3'1C@`````
+MB1"-1C")1"0$BT8(B00DZ/S___^#Q!1;7L.-="8`QT8L_____^O%C;0F````
+M`%575E.![*P```"+O"3`````C70D$(GPC50D'(MO"(M?&,8``(/``3G0=?:-
+M1@S'!GP!``")7"0$QT0D"&@```")!"3H_/___XU3:,=&=`````"-3GS'1G@`
+M````BT-HB49\BT($B4$$BT((B4$(BT(,B4$,BT(0B4$0BT(4B4$4BT(8B4$8
+MBT(<,=*)01R)\8GHBU\<Z`;M__^)`X/``74'QT<L_____XU',,=',!!L`P")
+M?S3'1S@`````B40D!(M'"(D$).C\____@<2L````6UY?7<.-=@"-O"<`````
+M5C'24X/L%(MT)""+3AB+1@B+7ASHI^S__XD#@\`!=0?'1BS_____C48PQT8P
+M$&P#`(EV-,=&.`````")1"0$BT8(B00DZ/S___^#Q!1;7L-55U93@^P,BT0D
+M((LHBU@HBW@LB[4H`0``B00DZ/S___^+0QR-31R)1QR+11PYR'4(ZQB+`#G(
+M=!*-4/0Y6BB0=?&+`(EZ*#G(=>XQR3'2B=CH^NC__XM''(E$)`2+102)!"3H
+M_/___XD\).C\____BX=8`@``BU8<QT8P$&P#`(EV-,=&.`````")`HU&,(E$
+M)`2+1@B)!"3H_/___X/$#%M>7UW#C78`C;PG`````%57B<=6B=93@>R\````
+MBUA<N/____^`?P@!=`N!Q+P```!;7E]=PXVL)(P```"+5U2);"0$BT=@B00D
+M_U(\C40D%(M3!(E$)`2+0PB)!"3_4AR-A"2P````B00DC8PDM````(G8C90D
+MN````.B/;/__#[:$))T```"(1@+VA"2:`````@^%@`$```^VA"2T`````H0D
+MG````(A&`8N$)+@```"(!H!_4``/B6@!```/MD=/B$8##[:$)*,```"(1@4/
+MMI0DF`````^V1@8/MIPDF0```,#J!HG1@^#\@^$!"<@/MHPDF0```-#J`=()
+MT(/A`8/@\\'A`HT4G0`````)R(/B"(G9"="#X1"#X,^)VH/B(`G("=")V8/A
+M0(/@/XG:"<B#XH`)T(A&!@^V1@</MI0DGP```(/@_(/B`PG0]L,$B$8'#X3;
+M````QD8$`HGJB?CHIV[__XN4)*@```"%THE&"'0NC48,C5Y"B50D!,=$)`B6
+M````B00DZ/S____'1"0$*````(D<).C\____QD,G`(N$))0```")1G[V1U!!
+M=22+1S"+5S2)AJ(```")EJ8```"+1RB+5RR)AJH```")EJX```"+5R2%TG0M
+M,<GK!HL2A=)T(XM"%(7`=!>+0`R%P'00BX!8`@``B82.N@```(/!`8/Y!W[7
+M@<2\````,<!;7E]=PP^VA"2P````Z7O^__\/MH0DH@```(A&`^F/_O__@^,(
+M@/L!&<"#X/Z#P`.(1@3I$____XUV`%575E.#[`R+5"0@BT(8BUH<BS")-"3H
+M_/___XL3@^H%B<=T#C'`QD08!0"#P`$YPG7TA?9T7H7_=%J+1Q2+5QB)0Q"+
+M1PR)4Q2Z_____X7`=`:+D%@"``")4QB+5QR)T,'X'PG0B$,/BP>+0`2)!"3H
+M_/___XA##@^VAQT"``"(0PT/MD<(/`1V1L9##`&`?S!`=E2+1"0@QT`L____
+M_XM4)"")T(/`,,=",!!L`P")4C3'0C@`````B40D!(M""(D$).C\____@\0,
+M6UY?7<,L`77`QD,,`HU3+(GXZ-[\__^%P'6NZ[>+1SB+5SR)@[P```")^(F3
+MP````.@?</__C9=4`0``C4LLB8.P````BX=4`0``B4,LBT($B4$$BT((B4$(
+MBT(,B4$,#[9'".@L;/__B(.0````#[9',8B#D0````^V1S2(@[0```"+ATP!
+M``"+EU`!``")@YP```")^(F3H````.BCW/__B8.4````B3PDZ/S____&@Y(`
+M````B8.8````@'\P``^$,0$``#'MBW2O2(7V#X3E````@+N3``````^$Z```
+M`(!^"`0/A/<```"+AE@"``")A*O$````#[:3D@```(/%`8/"`8B3D@````^V
+M1S`YZ`^/C0````^VTH/Z/W\8C823Q````(/"`<<`_____X/`!(/Z/W[OBX=D
+M`0``A<`/A([^__^+4`2Y_____X72=`:+BE@"``")BZ0```"+4`BY_____X72
+M=`:+BE@"``")BZ@```"+<`2%]@^$4_[__XM("(7)#X1(_O__B3PDZ/S___^)
+M@ZP```#I-?[__XVV`````(/]/P^/:O___XMTKTB%]@^%&____\>$J\0`````
+M````Z2____\/MD8(Z,)J__^(@Y,```"`?@@$#X4)____BT8DBX!8`@``B82K
+MQ````.D!____,=+I(?___XVV`````('LS````(F\),0```")QX!_"`&)M"3`
+M````B=:)G"2\````B:PDR````(M87+C_____=".+G"2\````B[0DP````(N\
+M),0```"+K"3(````@<3,````PXM'8(VL)(P```"+5U2);"0$B00D_U(\C40D
+M%(M3!(E$)`2+0PB)!"3_4AR-A"2P````B00DC8PDM````(G8C90DN````.A/
+M9___#[:$))T```#VA"2:`````HA&`@^%%@$```^VA"2T`````H0DG````(A&
+M`8N$)+@```"(!H!_4``/B10!```/MD=/B$8##[:4))@````/MD8&#[:<))D`
+M``#`Z@:)T8/@_(/A`0G(#[:,))D```#0Z@'2"="#X0&#X//!X0*-%)T`````
+M"<B#X@B)V0G0@^$0@^#/B=J#XB`)R`G0B=F#X4"#X#^)V@G(@^*`"=`/MI0D
+MGP```(A&!@^V1@>#X@.#X/P)T/;#!(A&!P^VA"2C````B$8%=&C&1@0"B>J)
+M^.AK:?__BY0DJ````(E&"#'`A=(/A)O^__^-1@R-7D*)5"0$QT0D")8```")
+M!"3H_/___\=$)`0H````B1PDZ/S___\QP,9#)P#I9O[__XGV#[:$)+````#I
+MY?[__XUV`(/C"(#[`1G`@^#^@\`#B$8$ZXD/MH0DH@```(A&`^GC_O__C;8`
+M````C;PG`````%575E.#[`R+;"0@BWT8BP>%P'1$,?;K#XD<)(/&`>C\____
+M.3=V,8M$MP2)!"3H_/___X!X"`&)PW5(]D!0`G37B00D@\8!Z/S___^)'"3H
+M_/___SDW=\^-13#'13`0;`,`B6TTQT4X`````(E$)`2+10B)!"3H_/___X/$
+M#%M>7UW#QT4L_O___^O,C70F`(/L'(M$)"")7"04B70D&(M8"(MP!(E$)`2+
+M`X/H@(D$).C\____B?`QR3'2Z+_@__^`BT@!```$BW0D&(E<)""+7"04@\0<
+MZ?S___^-="8`@^P<,=*)7"04BUPD((ET)!B+0P2+,`^W0UB+CF0!`P#!X`F)
+MGG@!`P#'AH`!`P``````C40!__?QQX9T`0,`8`H$`,>&?`$#``````")AG`!
+M`P"-AG`!`P")-"2)1"0$Z/S___^+7"04BW0D&(/$',/K#9"0D)"0D)"0D)"0
+MD)"#[#R+1"1`B5PD+(ET)#")?"0TB6PD.(M`&(L`B00DZ/S___^+@&0!``")
+M1"08@'@4``^$BP```(G"BT!<BU)@B40D((M$)!B)5"0DBU0D)(M(!(M$)""+
+M>12+:1@Q^#'J"<(/A!\"```Y;"0D#X-C`0``BU0D)(M$)"`QZC'X"<(/A!4"
+M``"+3"08,?8[="0D#[=)9&:)3"0>#[?9#X)]`0``=PH[7"0@#X9Q`0``#[=$
+M)"`Q]@^WV&:)1"0>Z5T!``"+1"08BTA<BUA@BT`$B=J+<!2+>!B)R#'P,?H)
+MP@^$>@$``(M$)!@/MFAFB>J$T@^%2`$``(M$)!@QT@^W0&1FB40D'@^WP`'(
+M$=HYUW<.#X/*`0``9BG.9HET)!Z+5"08#[=$)!YFQT):``")2E")6E1FB4)8
+MB>J$TG0E@/H#=""+1"08BUPD+(MT)#"+?"0TB40D0(ML)#B#Q#SI'/[__XM$
+M)!@QTHE()(G!QT`T`````(E8*`^W0%@#05`3453'04!0W@,`B4$LB<B#P#B)
+M03B)03R#Z!2)43")243'04@`````QT%,`0```(E$)`2+002)!"3H_/___X7`
+M=(*+7"0LBW0D,(M\)#2+;"0X@\0\PW<*.7PD(`^&D?[__XM4)!B)^#'V#[=2
+M9`^WV@'89HE4)!Z)ZA'R.U0D)'(>#X;G````#[=,)"`Q]F8I^6:)3"0>#[?9
+MC;8`````BT0D((M4)"0IV!GRB<&)TXM4)!@/MFIFZ>/^__^-=@"`^@,/A*_^
+M__^+5"08BT((BW`4BW@8Z9W^__^0C70F`(M$)!@/MFAFB>J`^@,/A)0```")
+MZ(3`=="+5"08O0$```#&0F8!Z\&+5"08#[9"9CP"='$L`0^$@P```(M$)!@Q
+M]HM4)""+3"0D#[=`9(ET)`R)%"2)3"0$#[?8B5PD"&:)1"0>Z/S___]FA<`/
+MA$W___\/M]@Q]F:)1"0>Z3[___\YQ@^#-O[__^DI_O__.T0D(`^")____XVT
+M)@````#I`____XG0BUPD+(MT)#"+?"0TBVPD.(/$/.E1P___BT0D&,9`9@"+
+M>12+:1CI-_W__XVT)@````"-O"<`````@^QLB50D-(M4)'2)?"1DBWPD?(EL
+M)&B)Q8M$)'")7"1<B50D+`^W5"1XB70D8(M/"#'VB40D*(M$)"AFB50D)@^W
+MVHM4)"R)3"0@BTPD-`'8B40D.!'RB50D/#M1/`^#?@```(M4)#2+3"0@BT(@
+MB0PDB40D!.C\____A<")1"1$#X1<`0``BT0D1,9`9@!F@WPD)@&)>"S'0'#P
+M\0,`QT!L``````^$.P(``(']&?\```^$B@```'=T@?T+_P``#X0P`0``QT<L
+M_O___XM$)$2)!"3H_/___XM7"(E4)"#K"78_QT<L_O___XM,)""-1S#'1S`0
+M;`,`B7\TQT<X`````(M<)%R)1"1TBW0D8(E,)'"+?"1DBVPD:(/$;.G\____
+M.T$X#X8X____Z[:!_2/_```/A+P```"!_23_``!UA(M$)#3V0%("#X54`0``
+MBW0D1,9&9`/&1E,DBWPD1`^V1V6#X/N#R`*(1V6+1"1$@'AD`P^$H0$``(M,
+M)$0/MD%(/!`/A$8"```\"@^$^0(``(M<)""+3"0TBU0D1(M#)(E**(7`#X19
+M`P``BW0D((M4)$2+?"1$BTX@B?"#P@R#P!R)5B")1PR)3Q")$8M<)%R+="1@
+MBWPD9(ML)&B#Q&S#BU\(QT<L_?___XE<)"#I]?[__V:#?"0F`0^'Q/[__XM$
+M)#2+:"2%[71/C78`BU4(.50D+(M%!`^"MP```'<*.40D*`^"JP````-%#!-5
+M$#E4)#P/AYL````/@XL```"+512%THE4)$QT#XM*#(7)B4PD2`^%Z`(``(M$
+M)#3V0%("#X2X`@``BU0D1,9"9`*+7"0\BTPD.(G9,=L)RP^$K0(``,9"4(K&
+M0D@0BWPD1`^V1V6#R`2#X/V(1V7IR?[__XM4)$3&0F0"BUPD/(M,)#B)V3';
+M"<L/A``!``#&0E"(QD)($.F/_O__.40D.`^&:____XMM`(7M#X4N____Z77_
+M__^+3"0LBU0D*,=$)!0!````B6PD!(E,)!"+3"0TB50D#,<$)(@,``")3"0(
+MZ/S____ID/W__\=`6`````"+5"0LBT0D*`^LT!#!ZA`/ME0D*(G!,,!F@>'_
+M``G0BU0D1&:)0DR+="0LBUPD*`^L\PC![@@/ML.)]XG>#ZS^$(ET)"@/MU0D
+M*,'O$(E\)"R+?"1$,-()T&:)1TZ+5"0LBT0D*`^LT`B)1"0H#[=$)"C!Z@B)
+M5"0LQD=20&;'1T@``##`"<%FB4]0#[=4)"9FB5=*9HE75.G3_?__BUPD1,9#
+M4"C&0T@*Z8O]___&04D`#[=$)";!X`F)04R+5"0LBT0D*(G0,=+!Z!B(05*+
+M5"0LBT0D*(G0,=+!Z!"(05.+5"0LBT0D*(G0,=+!Z`B(052+5"0LBT0D*(G0
+M,=*(056+5"0LBT0D*`^LT!B(05;!ZAB+1"0HBU0D+`^LT!"(05?!ZA"+1"0H
+MBU0D+`^LT`B(05@/MEPD*,'J",9!6@#&05L`B%E9#[=$)"9FP>@(B$%<#[9$
+M)";&05X`B$%=QD%?`.D'_?__BU0D1,9"20`/MT0D)L'@"8E"3(M4)"R+1"0H
+MBTPD1`^LT!B(05+!ZAB+1"0HBU0D+`^LT!"(05/!ZA"+1"0HBU0D+`^LT`B(
+M050/MEPD*,'J",9!5@"(654/MT0D)F;!Z`B(05</MD0D)L9!60"(05CID?S_
+M_XM4)$2)5"1PBUPD7(MT)&"+?"1DBVPD:(/$;.G\____BW0D1,9&9`/&1E,T
+MZ5O]__^+7"1$QD-0*L9#2`KI2OW__XM,)$B+442+04")5"0$B00DZ/S___^+
+M3"1(BU$$.$(&#X;R_/__BU4(BT4$B50D5(M4)$2)1"10QD)D`8M$)"`%F```
+M`(D$).C\____A<")P0^$XP$``(M\)"@K?"10BVPD+!ML)%0!^\=`$``````1
+M[HEP#(MT)$B):`2)6`B+7"1$QT`@`````(DXQT`<`````,=`)`````"-0!2)
+M012)01B+1@3'02@!````B4L\B7,H@'@%``^$C````,9#4@$/MDXQ#ZWOT^WV
+MP2!T!(GO,>V)>TB):TP/MDXPA,ET,HM\)$RX`0```#M^2`^$.P$``#'2ZQ6+
+M7"1(#[;"BW0D3#MT@T@/A!\!``"#P@$XRG7DBT0D((M`)(7`#X2<_O__BUPD
+M((M4)$2+="1$BTL@B=B#P@R#P!R)4R")1@R)3A")$>E"^___BT0D((M,)$2+
+MD&0!`P#&05(!BT0D((EY2(EI3`5@`0,`B4%4#[=<)"9FB5E0BW0D2`^V7C"$
+MVW0NBWPD3+@!````.WY(#X2.````,<#K$8MT)$@/MLB+?"1,.WR.2'1R@\`!
+M.-AUZ`^W1"0FB=.+="0@BWPD1,'@"8U$`O\QTO?SQX:``0,``````,>&=`$#
+M```1!`")OG@!`P#'AGP!`P``````B89P`0,`B?"+7"1<!7`!`P"+?"1DB70D
+M<(ML)&B)1"1TBW0D8(/$;.G\____N`$```#3X(M,)$2(05/KA8U"`8M\)$2(
+M1U/IV?[__\='+/W____I0_G__XVV`````(/L3(E<)#R+7"1<B6PD2(G5BU0D
+M5(ET)$"%[8E\)$2)1"0DBTL(BT0D4(E4)!P/MU0D6(E,)!")1"08BX%D`0,`
+M9HE4)!:)1"0H=`GVA4D!```$=#^+5"00C4,PQT,L_O___\=#,!!L`P")6S3'
+M0S@`````B40D5(E4)%"+7"0\BW0D0(M\)$2+;"1(@\1,Z?S___^+100/MD@&
+MA,ETM@^W1"06#[;1,?^)Q@^V13`#="08$WPD'"G0B<'!^1^)1"0(B4PD#(M%
+M%(M5&(D$)(E4)`3H_/___SG7#X=U____<@@YQ@^':____XM$)!`%F````(E$
+M)"R)!"3H_/___X7`B40D,`^$00$``(M%((M4)!")1"0$B10DZ/S___^%P(E$
+M)#0/A`X!``"+3"0PBT0D&(M4)##'02``````B0&)R(/`%,="$`````"+5"0<
+MB4$4B4$8BT0D-(EQ"(E1!(EY#,=!'`````#'020`````QT$H`0```(E(/(E8
+M+,9`9`&A`````(7`?@P[A;P!```/G\`/ML"+5"0TB4(TBT4$@'@%`'0_BTPD
+M)('I"_\``(/Y&@^&A0$``(M$)#"+5"0LB40D!(D4).C\____BTPD-(D,).C\
+M____BT,(B40D$.EP_O__#[=$)!:+5"0HBTPD),'@"8U$`O\QTO=T)"B!Z0O_
+M``"#^1J)QG9KBU0D,(M,)"R)5"0$B0PDZ/S___^+1"0TB00DZ/S___^+4PB)
+M5"00Z1W^__^+3"0PBT0D+(E,)`2)!"3H_/___XU#,,=#+/W____'0S`0;`,`
+MB5LTQT,X`````(E$)%2+0PB)1"10Z07^__^X`0```-/@J0"```0/A6H!``"I
+M`$```@^%4`$``*D!```!#X1M____BTPD-,9!4@&+1"00BTPD-`5@`0,`B4%4
+MBTPD-(M$)!B+5"0<B6DHB4%(B5%,#[=<)!;&068`QT%L`````,=!<-#R`P!F
+MB5E0BT0D$(M4)!")L'`!`P#'@(`!`P``````QX!T`0,``!$$`(F(>`$#`,>`
+M?`$#```````%<`$#`(M<)#R)1"14BW0D0(E4)%"+?"1$BVPD2(/$3.G\____
+MN`$```#3X*D`@``$#X6]````J0!```(/A:4```"I`0```0^$4_[__\9"4@$/
+MMDTQBU0D'(M$)!@/K=#3ZO;!('0$B=`QTHM,)#2)04B)44S&068`BUPD$,=!
+M;`````"):2C'07#0\@,`BT,DA<!T;(M4)#2+7"00@\(,BTL@B=B)4R"+7"0T
+M@\`<B4,,B4L0B1&+7"0\BW0D0(M\)$2+;"1(@\1,PXM$)#0!]L9`4@+IM/[_
+M_XM<)#3&0U(#Z:?^__^+3"0TQD%2`NE=____BUPD-,9#4@/I4/___XM,)#2+
+M7"0\BW0D0(M\)$2)3"10BVPD2(/$3.G\____C;8`````@^PLB5PD'(M<)#")
+M="0@B7PD)(EL)"B+0QB+<`2+>`@/MV@,BP")!"3H_/___XG"BT,,B5PD#(EL
+M)`B)-"2)?"0$Z'G[__^+7"0<BW0D((M\)"2+;"0H@\0LPY"-="8`@^PLB5PD
+M'(M<)#")="0@B7PD)(EL)"B+0QB+<`2+>`@/MV@,BP")!"3H_/___X!X"`&)
+MP70PBT,,#[?5B50D"(G*B5PD#(DT)(E\)`3H#OO__XM<)!R+="0@BWPD)(ML
+M)"B#Q"S#BT,,#[?5B50D"(G*B5PD#(DT)(E\)`3H3O/__^O.C;8`````C;\`
+M````@^PLB5PD'(M<)#")="0@B7PD)(EL)"B+0QB+<`2+>`@/MV@,BP")!"3H
+M_/___X!X"`&)P70PBT,,#[?5B50D"(G*B5PD#(DT)(E\)`3H?OK__XM<)!R+
+M="0@BWPD)(ML)"B#Q"S#BT,,#[?5B50D"(G*B5PD#(DT)(E\)`3HOO+__^O.
+MC;8`````C;\`````@^PLB5PD'(M<)#")?"0D,?^)="0@B6PD*(M#&`^V:`B+
+M<`2+`(D$).C\____B<*+0PR)7"0,B6PD"(DT)(E\)`3H^OG__XM<)!R+="0@
+MBWPD)(ML)"B#Q"S#C;8`````@^P<B5PD$(M<)"")="04B7PD&(M#&(MX!`^V
+M<`B+`(D$).C\____@'@(`8G!=#*+0PR)7"0,B?,/MM.)5"0(B<J)/"3'1"0$
+M`````.B/^?__BUPD$(MT)!2+?"08@\0<PXM##(E<)`R)\P^VTXE4)`B)RHD\
+M),=$)`0`````Z,WQ__^+7"00BW0D%(M\)!B#Q!S#C;8`````C;PG`````(/L
+M'(E<)!"+7"0@B70D%(E\)!B+0QB+>`0/MG`(BP")!"3H_/___X!X"`&)P70R
+MBT,,B5PD#(GS#[;3B50D"(G*B3PDQT0D!`````#H[_C__XM<)!"+="04BWPD
+M&(/$',.+0PR)7"0,B?,/MM.)5"0(B<J)/"3'1"0$`````.@M\?__BUPD$(MT
+M)!2+?"08@\0<PXVV`````(V\)P````!5B=575HG&4X/L#(72B99H`0,`=#&)
+MPS'_C;0F`````(T$?X/'`8V$AF0!``")1"0$B30DZ/S___^)@V`!``"#PPPY
+M[W7:H0````#'AFP!`P`2````A<!T'XVT)@````"+4`@YEFP!`P!V!HF6;`$#
+M`(M`!(7`=>B#Q`Q;7E]=PU=6B<93@^P0BX!H`0,`A<!T.(GS,?^+@V0!``"#
+MQP&+DV@!``")1"0(B50D#(N#8`$``(/##(DT)(E$)`3H_/___SF^:`$#`'?,
+MQX9H`0,``````(DT).C\____@\006UY?PXVV`````(V\)P````!64X/L%(MT
+M)""`?F0#BUXL#X2,````#[9&9CP0#X2.````/`5T('<:+`&-M@`````/A(0`
+M``#'0RS_____C78`ZPX\"W5]QT,L_?___XUV`(M&/(7`=!.)1"0$BP8%F```
+M`(D$).C\____BP;H'____XDT).C\____C4,PQT,P$&P#`(E;-,=#.`````")
+M1"0$BT,(B00DZ/S___^#Q!1;7L/V1E,!#X1J____QD9F$(M#',8``<9&9@''
+M0RP`````ZXT\#0^$>____\=#+/_____I>?___XGVC;PG`````%93@^P4BW0D
+M((M>+(M###TD_P``=&H]&?\``'1C@'YF$'9OQT,L_____XVV`````(M&/(E$
+M)`2+!@68````B00DZ/S___^+!NAC_O__B30DZ/S___^-0S#'0S`0;`,`B5LT
+MQT,X`````(E$)`2+0PB)!"3H_/___X/$%%M>PXGV@'YF#'0_BT,<Q@``@'YF
+M$'>1#[Y.9K@!````T^"I("D!`'44J`(/A'?____'0RP`````Z7C____'0RS]
+M____D.EK____BT,<Q@`!BT8HQP0D$0```(E$)`3H_/___\9&9@'KR(VV````
+M`(V_`````(/L'(E<)!2+7"0@B70D&(M#&(-[$`>+,'8&@WL4`W<3QT,L_O__
+M_XM<)!2+="08@\0<PXDT).C\____A<!TX8DT).C\____BQ`[4PAT"<=#+/S_
+M___KT(M(#(7)=<*`>`@$=KR+0!R#^/]TNXE$)`2+0@2)!"3H_/___X7`=*C'
+M0RS_____ZY^0C;0F`````(/L'(E<)!")PXE\)!B)UXET)!2+@"`"``"%P'4*
+MB[-4`@``A?9T&3'`BUPD$(MT)!2+?"08@\0<PXVT)@````"+0QR#^/]T%8E$
+M)`2+`XM`!(D$).C\____A<!URH!["`1V.&;W@T@!``!P"'6Y@'LP`'0@,?:+
+M1+-(A<!T"XGZZ'O___^$P'2>#[9#,(/&`3GP?^*X`0```.N.=!&)^HG8Z`I?
+M__\/ML#I>____XM#)(GZZ/A>__\/ML#I:?___X/L#(!X"`1V%S')@[AD`0``
+M`'0,B<B#Q`S#C;8`````Z!O___^#Q`P/MLB)R,.)]E575E.#[`R+="0@BTX8
+MBU8<BP''`@````")Q8G'@>4``0``@>?_````=&PQV^LBD(M(#(7)=5N`>`@%
+M&=+WTB'"Z(K___^$P'1(.?MT28M.&(/#`8L$F8D$).C\____A>UUS8M0#(72
+M=2AF]X!(`0``<`AU'8M0'(/Z_W3-B50D!(L`BT`$B00DZ/S___^%P'2XBT8<
+MB1B-1C#'1C`0;`,`B78TQT8X`````(E$)`2+1@B)!"3H_/___X/$#%M>7UW#
+MC;0F`````(V\)P````!55U93@^P,BW0D((M&&(L0,<#VQO\/E,`/MOJ)1"0(
+MBT8<,=L/MFPD",<``````)`Y^W(\A?]T)3';C;8`````BT88@\,!BP28B00D
+MZ/S___^)!"3H_/___SG[=>.+7"0(A=MU;,=&+`````#K.(GVB>B$P'2^BT88
+M@\,!BP28B00DZ/S___^`>`@%&=+WTB'"Z&K^__^$P'66BT8<QT8L_____XD8
+MC48PQT8P$&P#`(EV-,=&.`````")1"0$BT8(B00DZ/S___^#Q`Q;7E]=PX7_
+M=-&+1AB+0`2)!"3H_/___X/$##'26UY?7>GO=O__ZPV0D)"0D)"0D)"0D)"0
+M5U93@^Q@BW0D<(U$)#R+?BB+7BR+5U2)1"0$BT=@B00D_U(\#[9$)$Z(1TZ!
+M>PQ"_P``='X/MD93BU,<B$(*#[=&3(A"!@^W1DZ(0@</MT90B$((#[9&4HA"
+M"0^W1DB(0@0/MT9*B$(%#[=&5(A""X!^9@$/A(8```#'0RS_____B30DZ/S_
+M__^-0S#'0S`0;`,`B5LTQT,X`````(E$)`2+0PB)!"3H_/___X/$8%M>7\,/
+MMD93BU,<B$(/#[=&3&:)0@@/MT9.9HE""@^W1E!FB4(,#[9&4HA"#@^W1DAF
+MB4($#[=&2F:)0@8/MT949HE"$(!^9@%U@(VV`````(M##,=#+``````]0O\`
+M`'13/1C_```/A67___^+0QB`>`KR#X58____C50D&(M'5(E4)`2+5V")%"3_
+M4#R+5"0T@<(``0``#[8"J`0/A"____^#X/N(`HD\).C\____Z1W___^+0QB`
+M>`_R#X40____Z[:-M@````"-O"<`````55=64XG#@^P,,<"0C70F`,8$&`"#
+MP`&#^"QU],<#+````.B)2___B$,$H0````"+,(7V#Y1#!:$`````B00DZ/S_
+M___!X`P]____`0^&B0```,9#!@7&0P<+#[9#"[\%````,>W&0P@`QD,)`<9#
+M"@^#X/Z#R`B(0PO&1"0+`.L5@_\%QD0>'$!T.(/%`8/'`8/_#70TB3PDZ/S_
+M__^%P'3LB>@/MO")^.BR3/__@_\&B$0>#'7*QD0>'`*`3"0+0.O(@$PD"R#K
+MP8!\)`M@=!>#Q`PQP%M>7UW#QD,&!\9#!P?I<O___Z$`````@[B4`0,``W;;
+MB>H/ML+&1!@,$L9$&!Q`@\0,,<!;7E]=PY!3@^P(BUPD$(M#'.C@_O__A<!T
+M!\=#+/____^-0S#'0S`0;`,`B5LTQT,X`````(E$)`2+0PB)!"3H_/___X/$
+M"%O#C;8`````C;PG`````%575E.![)P```"+K"2P````BWT(B?CHY5?__XN'
+MD`$#`(7`#X6%````BW<(QX>0`0,``0```(7V#X2E````C50D)(M&!(E4)`2+
+M5@B)%"3_4!P/MD0D-`&'D`$#`(!\)#0`=#$QVXET)`S'1"0((/L#`(E<)`2)
+M-"3H_/___X3`=0>#KY`!`P`!#[9$)#2#PP$YV'_1BS:%]G6CBX>0`0,`@^@!
+MA<")AY`!`P!T/XU%,,=%+/S____'13`0;`,`B6TTQT4X`````(E$)`2+10B)
+M!"3H_/___X'$G````%M>7UW#QX>0`0,``````(V'5`$``,>'5`$``!#[`P")
+MOU@!``#'AUP!````````B40D!(U')(D$).C\____ZY")]NG\____C70F`(V\
+M)P````"#[!R)?"04BWPD((EL)!B+1"0HB5PD#(ML)"2)="00BW<,@ZZ0`0,`
+M`87`#XBT````B40D"(EL)`2)/"3H_/___X7`B<,/A*X```"`/0``````=2Z)
+M7"0$QP0D`@```.C\____BX:0`0,`A<!T-(M<)`R+="00BWPD%(ML)!B#Q!S#
+M#[9`4*@"=<JH`0^%A````/9#4`1UO(!+4"2-="8`Z[*-AE0!``#'AE0!```0
+M^P,`B;98`0``QX9<`0```````(M<)`R)1"0DC48DBWPD%(E$)""+="00BVPD
+M&(/$'.G\____C4<0B6PD!(D$).C\____Z6O___^+1P2)+"3_4$"-1Q");"0$
+MB00DZ/S____I3O___XD<).C\____B?;I;?___XUT)@"-O"<`````@^P<B5PD
+M$(M<)"")?"08B70D%(M#&(MP!(L`B00DZ/S___^)-"2)Q^C\____B3PDB40D
+M!.C\____QT,P$&P#`(E;-,=#.`````"#^`$9P/?0B4,LC4,PB40D!(M#"(D$
+M).C\____BUPD$(MT)!2+?"08@\0<PXUV`(V\)P````!75E.#[!"`/0``````
+MBWPD('1MBU\,C7<,.?-U">LUD(L;.?-T+HV3V/W__X!Z"`%U[O:"'`(```%T
+MY0^V!0````")%"2)1"0$Z/S___^+&SGS==+'A\P`````AY,#C8?,````QX?4
+M`````````(F_V````(E$)`2)/"3H_/___X/$$%M>7\.)]HV\)P````!55U93
+M@>S,````B[0DX````(U\)!")^(U4)!R+;@B+3AC&``"#P`$YT'7VC4<,QP=\
+M`0``B4PD!,=$)`BP````B00DZ/S___\QTHGYB>B+7ASH6L3__XD#@\`!=0?'
+M1BS_____C48PQT8P$&P#`(EV-,=&.`````")1"0$BT8(B00DZ/S___^!Q,P`
+M``!;7E]=PXVT)@````"-O"<`````5C'`4X/L%(MT)""+7AR)]L8$&`"#P`$]
+M@````'7RB=CH:_K__X7`=##'1BS_____C48PQT8P$&P#`(EV-,=&.`````")
+M1"0$BT8(B00DZ/S___^#Q!1;7L.#2T00,=+'`X````#'0SP`(```#[9$&@R#
+MX`^#Z`,\`G<%QD0:+`:#P@&#^A!UY.NFC;8`````55=64X/L#(M4)""+0AB+
+M6AR+,#'`Q@08`(/``3WZ````=?*)-"3H_/___XG%,<"0Q@08`(/``3WZ````
+M=?*%]G1=A>UT68M%%(M5&(E#!(M%#(E3"+K_____A<!T!HN06`(``(E3#(M5
+M'(G0P?@?"="(0P.+10"+0`2)!"3H_/___XA#`@^VA1T"``"(0P$/MD4(/`1W
+M1"P!#X2O`0``BT0D(,=`+/____^+5"0@B="#P##'0C`0;`,`B5(TQT(X````
+M`(E$)`2+0@B)!"3H_/___X/$#%M>7UW#Q@,!BT4X9HF#Z````(GHZ#%*__^-
+ME50!``"-2R")@^0```"+A50!``")0R"+0@2)002+0@B)00B+0@R)00P/MD4(
+MZ#Y&__^(@X0````/MD4QB(.%````BX5,`0``BY50`0``B8/0````B>B)D]0`
+M``#HO[;__XF#B````(DL).C\____QH.&`````(F#S````(!],``/A$X!```Q
+M_XMTO4B%]@^$`@$``("[AP`````/A`4!``"`?@@$#X04`0``BX98`@``B82[
+MC`````^VDX8```"#QP&#P@&(DX8````/MD4P.?@/CZ$````/MM*#^@]_&(V$
+MDXP```"#P@''`/____^#P`2#^@]^[XN%9`$``(7`#X2U_O__BU`$N?____^%
+MTG0&BXI8`@``B8O8````BU`(N?____^%TG0&BXI8`@``B8O<````BU`$A=(/
+MA'K^__^+0`B%P`^$;_[__XDL).C\____B8/@````Z5S^___&`P*-4R")Z.AE
+MU?__A<`/A3S^___I0O[__X/_#Y"-="8`#X]1____BW2]2(7VC70F``^%_O[_
+M_\>$NXP`````````Z1+___\/MD8(Z,%$__^(@X<```"`?@@$#X7L_O__BT8D
+MBX!8`@``B82[C````.GD_O__,=+I!/___Y"-="8`55=64X/L#(M4)""+0AB+
+M6AR+,#'`Q@08`(/``3W8````=?*)-"3H_/___XG',<"0Q@08`(/``3W8````
+M=?*%]G0UA?]T,8M'%(M7&(E#!(M'#(E3"+K_____A<!T!HN06`(``(E3#`^V
+M1P@\!'=$+`$/A!@!``"+1"0@QT`L_____XM4)"")T(/`,,=",!!L`P")4C3'
+M0C@`````B40D!(M""(D$).C\____@\0,6UY?7</&`P&+AU0!``"-EU0!``"-
+M2Q")0Q"+0@2)002+0@B)00B+0@R)00P/MD<(Z*U#__^(0W0/MD<QB$-UBX=,
+M`0``BY=0`0``B8/`````B?B)D\0```#H-+3__XE#>(D\).C\____QD-V`(F#
+MO````(!_,``/A*4````Q[>LM@'X(!'1'#[93=HN&6`(``(E$DWP/MD-V@\`!
+M/`^(0W9W6`^V1S"#Q0$YZ'Y-BW2O2(7V=.V`>W<`=<4/MD8(Z!U#__^(0W>`
+M?@@$=;F+5B0/MD-VBY)8`@``B52#?.NTQ@,"C5,0B?CH9-C__X7`#X73_O__
+MZ=G^__\/ME-V@_H/#X_,_O__C423?(/"`<<`_____X/`!(/Z#W[OZ;+^__\Q
+MTNOBC;8`````C;\`````55=64X/L#(M4)""+0AB+6AR+,#'`Q@08`(/``3VN
+M````=?*)-"3H_/___XG',<"0Q@08`(/``3VN````=?*%]G0OA?]T*XM'%+K_
+M____B4,$BT<,A<!T!HN06`(``(E3"`^V1P@\!'=$+`$/A`P!``"+1"0@QT`L
+M_____XM4)"")T(/`,,=",!!L`P")4C3'0C@`````B40D!(M""(D$).C\____
+M@\0,6UY?7</&`P&+AU0!``"-EU0!``"-2PR)0PR+0@2)002+0@B)00B+0@R)
+M00P/MD<(Z--!__^(0W`/MD<QB$-QBX=,`0``B8.<````B?CH9K+__XE#=(D\
+M).C\____QD-R`(F#F````(!_,``/A*<````Q[>LM@'X(!'1'#[93<HN&6`(`
+M`(E$DW@/MD-R@\`!/`>(0W)W6`^V1S"#Q0$YZ'Y-BW2O2(7V=.V`>W,`=<4/
+MMD8(Z$]!__^(0W.`?@@$=;F+5B0/MD-RBY)8`@``B52#>.NTQ@,"C5,,B?CH
+MEM;__X7`#X7?_O__Z>7^__\/ME-R@_H'B?8/C];^__^-1)-X@\(!QP#_____
+M@\`$@_H'?N_IO/[__S'2Z^*-M@````"-OP````!55U93@^P\BVPD4(M=&(L#
+MA<!U:XLU`````,9$)#0&A?9T,8U\)#2+7@B%VW0@B?:+0PB)1"0XBT,$B7PD
+M!,<$)`````#_4&"+&X7;=>*+-H7V==.-13#'13`0;`,`B6TTQT4X`````(E$
+M)`2+10B)!"3H_/___X/$/%M>7UW#B00DC7L$Z/S___^)Q@^V0P2$P'4]@'X(
+M`0^$/P$``,=%+/[____V1E`0=*F-1"00BU94B40D!(M&8(D$)/]2/`^V1"0B
+MB$9.B30DZ/S____K@RP!=!#'12S^____C70F`.EO____@'X(!':S#[9'`3P!
+M=$D/@]T!``"#?1`8C78`=9R-CE0!```QP,8$"`"#P`&#^!!U](M'!(U7!(D!
+MBT($B4$$BT((B4$(BT(,B4$,@(Y(`0``!.F'````@WT02`^%6/___XV.;`$`
+M`#'`Q@0(`(/``8/X!'7TBU<$C4<$B1&+4`2)402+4`B)40B+4`R)40R+4!")
+M41"+4!2)412+4!B)41B+4!R)41R+4"")42"+4"2)422+4"B)42B+4"R)42R+
+M4#")43"+4#2)432+4#B)43B+0#R)03R`CD@!```$]H9(`0``!`^$A/[__XDT
+M).C\____Z7?^__^`?P$%#X>W_O__#[9'`9"-="8`_R2%C`X``(-]$`F0C70F
+M``^%F/[__\9$)#0)#[9'!(A$)#B-1"0TBU94B40D!(M&8(D$)/]28(E%+.EV
+M_O__D(-]$`D/A63^___&1"0T!0^V1P3&1"0Y`(A$)#B-1"0TBU94B40D!(M&
+M8(D$)/]28(E%+(!.4!#I.?[__XUT)@"#?1`)#X4D_O__QD0D-`0/MD<$QD0D
+M.0"(1"0XZ[Z)]H-]$`D/A03^___&1"0T`P^V1P2(1"0XZZ.-M"8`````@WT0
+M"0^%Y/W__\9$)#0"Z]Z#?1`)#X73_?__@$Y0@,9$)#0`Z\D\`G0,QT4L_O__
+M_^G=_O__@WT0"0^VOAT"```/A:?]__^-0PB)^HE$)`@/MD,(.,)T.H!^"`2(
+MAAT"``!V+H!^,`!T*#')BU2.2(72=!.`>@@$=@T/MH8=`@``B((=`@``#[9&
+M,(/!`3G(?]J)^#P"=`R`CD@!```$Z6_^__^+5"0(@#H"=.NYX)`#`(GJB?#H
+MU67__^D'_?__55=64X/L#(ML)""+71B+`XU[!(D$).C\____B<:+0P2H`70[
+MC8Y4`0``,<"-="8`Q@0(`(/``8/X$'7TBT<$C5<$B0&+0@2)002+0@B)00B+
+M0@R)00R`CD@!```$BP>H`@^$?@```(V.;`$``#'`D,8$"`"#P`&#^$!U](M7
+M%(U'%(D1BU`$B5$$BU`(B5$(BU`,B5$,BU`0B5$0BU`4B5$4BU`8B5$8BU`<
+MB5$<BU`@B5$@BU`DB5$DBU`HB5$HBU`LB5$LBU`PB5$PBU`TB5$TBU`XB5$X
+MBT`\B4$\@(Y(`0``!/:&2`$```1T"(DT).C\____C44PQT4P$&P#`(EM-,=%
+M.`````")1"0$BT4(B00DZ/S___^#Q`Q;7E]=P^L-D)"0D)"0D)"0D)"0D%57
+M5E.![,P```"+M"3@````C5PD$(M^&(L'B00DZ/S___^-5"0<B<6)V(VV````
+M`,8``(/``3G0=?:-5P2-0PS'`WP!``")5"0$QT0D"+````")!"3H_/___XM&
+M"(GJB=GH^K?__X7`B<)T+8/X_W0SBT8<QT8P$&P#`(EV-,=&.`````")$(U&
+M,(E$)`2+1@B)!"3H_/___X'$S````%M>7UW#QT8L_____^O$C78`55=64X/L
+M'(M$)#")1"04BT`$BS"+CB@!``")\(N6<`$#`(E,)!CH=>;__XML)!2+10B+
+M302+4""+02`YT',"B=")1"0$BP&)!"3H_/___X7`B<</A(@!``"+%0````"%
+MTGX3BTPD%(M!!#N0O`$```^?P`^VT,9'9@"+;"04B5<T#[9%9H3`#X76````
+MBT0D%(M4)!2#P"2)1SB+0@2`3V4"BXYD`0,`B4<HBVPD%(G*P>H)#[=%6@^W
+M75@IPXN&;`$#`(/H`0^OT#G3=@*)TV:!^P`!9HE?4'8&9L='4``!BT0D%(!X
+M%``/A-<```#V1V4$#X3-````B<$/MT!8,=*)S0-!4!-15#';#[=/4"G(#[=-
+M6AG:,=LIR!G:B4=(B5=,@$]E"(M.)(M$)!C'1W#0#`0`QT=L,%(#`(7)B4<L
+M#X0.`0``BTX@C5<,C48<B58@B4<,B4\0B1&#Q!Q;7E]=PSP##X0B____BTPD
+M%(M!"(!/902+GF@!`P")1RB%VP^$W@```(N.9`$#`#'M,=N+AF`!`P"%R8L$
+M&'05B<*)R,8"`(/"`8/H`77UBXYD`0,`@\4!@\,,.:YH`0,`=]#IY?[__XM,
+M)!0QT@^W05H#05`3452)1TB)5TSI0O___XM4)!0/MD)FA,!U8HM$)!2+3"04
+M@\`DB40D!(M!!(D$).C\____BVPD%(M%!(L`Z`OE__^+1"08BU0D&,=`+/__
+M___'0#`0;`,`B4`TQT`X`````(/`,(E$)`2+0@B)!"3H_/___X/$'%M>7UW#
+M/`-UM.N8B7PD,(/$'%M>7UWI_/___XN.9`$#`.D[_O__@^PLB7PD)(M\)#")
+M7"0<B70D((EL)"B+1RR+5RB++XE$)!0/MD=FB[)D`0``/`%T0SP"#X0)`0``
+MC488QD=F`,=&&,`0!`")?AS'1B``````B40D!(U%)(D$).C\____BUPD'(MT
+M)""+?"0DBVPD*(/$+,,/MT9:9@-'4#M6!&:)1EH/A+<"```/MT9:9CM&6`^#
+M.0$```^V1V7'1SP`````QT<X`````(/@_8/(!(A'98M6"(E7*,9'9@`/MT9:
+M#[=.6(N59`$#`"G!BX5L`0,`P>H)@^@!#Z_0.=%V`HG19H'Y``%FB4]0=@9F
+MQT=0``&`?A0`=`KV1V4$#X53`@``#[=&6C'2`T90$U94B4=(B5=,]D=E`@^$
+MVP$``(MU)(7V#X30`0``BTT@C5<,C44<B54@B4<,B4\0B1'I'O___XM&!,9&
+M9P&`H!P"``#^BT8(@*`<`@``_HM&!("@20$``/>+1@B`H$D!``#WBT8$BP#H
+M../__P^V1F:$P`^$Y````#P##X3<````B3PDZ/S___^+5"04QT(L_____XG0
+M@\`PQT(P$&P#`(E2-,=".`````")1"0$BT((B00DZ/S____IE_[__XVT)@``
+M``"+LF0!``"+1@2+5@B)1"00B50D&`^V;F:`?A0`#X2-````BTY<,=(/MT98
+MBUY@*<&)Z!G3+`&)3ER)7F`/A)P!``")ZH#Z`@^$K@$``(M&7`M&8`^%H@``
+M`(M4)!"+`NA\XO__B>B$P`^$60$``#P##X11`0``B3PDZ/S___^)\(M<)!R+
+M="0@BWPD)(ML)"B#Q"SI");__XU&)(E$)`2+1@2)!"3H_/___^D-____#[=&
+M6#';B>J)P0-.7!->8(32B4Y<B5Y@=7R+1"00BU`8,=J)5"0(BU`4BT0D"#'*
+M"=!U!,9&9@&+1"08BU`8,T@4,=H)R@^$7O___XM4)!"+`NC:X?__B>B$P`^$
+MH````#P##X28````B3PDZ/S___^+5"04Z:;^__^)?"0PBUPD'(MT)""+?"0D
+MBVPD*(/$+.G\____B>J`^@-UFXM$)!"+4!@QVHE4)`B+4!2+1"0(,<H)T'6!
+MZ>[^__^0C70F`&8[1E@/@F[]__]FQT9:``#I-/W__P^W3EHQT@^W1E@#1E`3
+M5E0QVRG(#[=/4!G:,=LIR!G:B4=(B5=,Z93]__^-1B2)1"0$BT8$B00DZ/S_
+M___I4?___XU&)(E$)`2+1@2)!"3H_/___^F8_O__BT0D$(M0&#-(%#':"<H/
+MA5O^___&1F8`Z5+^__^+1"00BU`8,T@4,=H)R@^%/O[__^E%_O__C;8`````
+MC;\`````4XM<)`CV0V4"BP/&0V8`=!^+4"2%TG08BT@@C5,,B5`@@\`<B4,,
+MB4L0B1%;PXGVB5PD"%OI_/___XVV`````%.#[`B+7"00BP.+D'`!`P#HZ]__
+M_XL#BT@DA<ET&8M(((U3#(E0((/`'(E##(E+$(D1@\0(6\.)7"00@\0(6^G\
+M____C;8`````C;\`````@^PLBU0D,(E<)!R)="0@B7PD)(EL)"B+6BR+*XN]
+M*`$``(M'&(L`B40D%(M",(D4)(E$)!CH_/___X!["`0/AHP```"+LV0!``"%
+M]@^$R@```(M&!(7`=`RY`@```#'2Z#NM__^+1@B%P'0,N0(````QTN@HK?__
+MBT80BU8,B4($B1"-A8````")="0$B00DZ/S___^+7"08@\,!.UPD%'1#BT<8
+MBU0D&(M$D`B)!"3H_/___XG:BW0D((M<)!R+?"0DBVPD*(/$+.G16___D(D<
+M).C\____BUPD&(/#`3M<)!1UO8U',,=',!!L`P")?S3'1S@`````B40D!(M'
+M"(D$).C\____BUPD'(MT)""+?"0DBVPD*(/$+,.Y`@```#'2B=CH=JS__^EF
+M____D(/L'(E<)`R+7"0@B70D$(E\)!2);"08BVL$BW,(BT4`B?*+N"@!``")
+MZ.CQ0/__QX9D`0````````^VE1P"``#'A60!````````#[:&'`(``(/B!(/@
+M^PG0B(8<`@``#[:5'`(``(/@_8/B`@G0B(8<`@``#[9%-(A&-(U',,=',!!L
+M`P")?S3'1S@`````B40D!(M'"(D$).C\____B70D!,<$)!4```#H_/___XM#
+M$(M3#,=#&"!W`P")6QS'0R``````@\,8B4($B1")7"0$BT4`B00DZ/S___^+
+M7"0,BW0D$(M\)!2+;"08@\0<PU6)U5=64X/L#(D$)(N`4`(``(7`=$&+70B+
+M=0R-="8`.7`$=RMR!#D8<R6+2`P[302+4`AV#8/$#+@!````6UY?7<-R"SM5
+M`'?LC;8`````BT`0A<!UR8L$)(NX,`(```4P`@``B40D!#G'=$6-=@"-3_2`
+M>60`=2Z+64@QT@^W05"+<4P!V!'R.54$=QER!3E%`',2.W4,<IR-M@````!W
+M!3M="'*/BS\Y?"0$C78`=;Z+%"2+NC@"``"!PC@"``")5"0(.==U$^M8D(UT
+M)@`\@'03BS\[?"0(=$>-3_0/MD%DA,!UZ8M92#'2#[=!4(MQ3`'8$?(Y501W
+MV'(%.44`<]$[=0P/@BK___^-="8`=\([70@/@AO___^+/SM\)`AUN8/$##'`
+M6UY?7<.-=@"#[`B)'"2+7"0,B70D!(MT)!")V(GRZ+7^__^%P'4<BX-0`@``
+MB480,<")LU`"``"+'"2+="0$@\0(PXM6'+C_____A=)TZ8N35`(``(V#5`(`
+M`(72=`J-0A"+4A"%TG7VB3"X_____^O&C;8`````@^P0B6PD#(ML)!2)'"2+
+M3"08B70D!(E\)`B+A5`"``"-E5`"```YR'00C;8`````C5`0BT`0.<AU]HM9
+M%(UY%(M!$(NU3`(``#G?B0+'01``````=!6+41B+!HES!(D>B5`$B0*)>1B)
+M>12+10#'0#0!````BQPDBW0D!(M\)`B+;"0,@\00PY"-M"8`````BU0D!(M,
+M)`B+`H7`=`J+0@2)2`B)2@3#B4H$B0K#B?:+1"0$@\`LB40D!.G\____4X/L
+M"(M<)!"+4T"%TG03BT-$QT-``````(D<)(E$)`3_THM#<(E;&,=#'`````")
+M0Q2-0Q2)1"0$BP.#P"R)!"3H_/___X/$"%O#D(UT)@"#[!R)7"04BUPD((ET
+M)!B+<RB)'"3H_/___XM#$(U+#(M3#(.N)`(```&#KB`"```!B4($B1"+0SR)
+M2PR)2Q"%P'0,B40D!(DT).C\____BUPD%(MT)!B#Q!S#D(UT)@!55U93@^PL
+MBW0D0(M\)$2+3BR+1DB+5DR+66B)1"08B50D'(M!2(M13(7;B40D((E4)"0/
+MMW90#X2C````#[9!90^W5"1(@^`!#[;`.=`/A(P```"+3"08*TPD((LKP>$)
+M.>F)Z',+Z:$```"-="8`B="#PQ")P@,3.=%S\XLK*<$/M_;!Y@F)R(G*,<D#
+M4P@32PPIQ3GNB5<(B4\,C4\0B2]V)HM#&(M3'"LWQT<$`````(G/B4$(BT,0
+M@\,0B5$,B0&#P1`Y\'+:B3>X`0```,='!`$```"#Q"Q;7E]=PXM!;(7`=!R+
+M5"1(B7PD!(D,)(E4)`C_T(7`=`>)^^E1____@\0L,<!;7E]=PS'`Z6O___^-
+MM@````"-OP````!55U93@^PLBW0D0(M&*(E$)""`?F0`#X6V````BTPD(#'2
+MBWY(#[=&4(MN3(N94`(```'X$>J%VP^$(@$```^V3F6#X4"$R70*@WLH``^$
+M`@$``#E>.`^$^0```#M3!)`/@N\```!W#CL#C;8`````#X;?````.VL,C;0F
+M``````^'SP````^#P````(M+&(U6#(U#%(E3&(E&#(E.$(D1@\0L6UY?7<.+
+M5"0<BTPD((M""(.I(`(```&)1BB#@"`"```!B40D((!X"`0/AU,"``"+7"0@
+MBTPD((N3,`(``('!,`(``#G*=2.+!HE.#,=`-`$```"-1@R)002)@S`"``")
+M3A"#Q"Q;7E]=PX-^-``/A>H!``"+1"0@BY@T`@``C7OTBT<TA<`/B,,"``"+
+M5"0@C48,B4X,B0.)@C0"``")7A"#Q"Q;7E]=PSM["`^"-____XM;$(7;#X7E
+M_O__BTXXA<D/A`P"``"+3"0@@'D(!`^&6?___XM<)""+FV0!``"%VXE<)!P/
+MA)8!``"`>V<`#X6,`0``]D9E"`^%@@$``(%^<)`<!``/A'4!``"+3"0@.TL$
+M#X5H`0``@'L4``^$10(``(M+7(M;8(E,)`@YW8E<)`P/A\O^__]R"#G/#X/!
+M_O__.U0D#)"-="8`=Q0/@BT!```[1"0(C70F``^&'P$``(M&!(-`"`&)!"3H
+M_/___XM4)!R)1"0DBP:+7"0DB0.+1@2)0P2+1C2)0S2+0@2+3"0DB7E(B6E,
+MBUPD'(E!*(EQ+,=!;(`6!``/MT-<QT%PD!P$`,9!9@#'06@`````9BGX9HE!
+M4`^V5F4/MD%EB=.)T8/C@(/@/X/A0`G8"<B)TX/C,(/@QXG1"=B#X0@)R(G1
+M@^$$@^#Y@^(""<@)T`^V5F6#X/Z#X@$)T(M4)"2(0F6+1CB%P`^$M@$``(E"
+M.(M<)!R-5@R+0P2+B#P"``")D#P"```%.`(``(E&#(D1QD9D@(M$)"2)3A")
+M1"1`@\0L6UY?7>G\____#X[+````C48,B4($B4X0BTPD((E6#(F!,`(``(/$
+M+%M>7UW#]D9E!`^$H_W__XM4)"#V@DD!```@#X22_?__@*))`0``W^C\____
+MBTPD((")2`$```2)02B+!L>`B`$#``$```"+04`)03B+040)03SI6_W___9&
+M94`/A>K]__^+3"0@BYE4`@``A=MU&>G7_?__.WL(#X+O_/__BUL0A=L/A,/]
+M__\[4P1R\(UV`'<$.P-VYSMK#(VT)@````!WVP^"Q/S__Y"-M"8`````Z\*+
+M7"0@C48,B4X,BY,T`@``B8,T`@``B0*)5A#I$_W__XM3!(U&#(-'-`&)0P2)
+M7@R)5A")`NGY_/__BUPD'(M+7(M;8(E,)!`YVHE<)!0/@H+\__]W"#G(#X9X
+M_/__.VPD%'(0#X?I_O__.WPD$`^#W_[__XM&!(-`"`&)!"3H_/___XM4)!R)
+M1"0DBP:+7"0DB0.+1@2)0P2+1C2)0S2+0@CIN_W__XM,)"3'03@!````Z3W^
+M__^-M"8`````4X/L"(M<)!"+0RB#@"`"```!BT,\A<!T*L=`'`````")6"#'
+M0"0`````B40D!(M#*(D$).C\____A<!U$XM#/(E#.(E<)!"#Q`A;Z?S___^#
+MQ`A;PXUT)@"-O"<`````@^PLB70D((MT)#")7"0<B7PD)(EL)"B+1BB+7BR)
+M1"08B[AD`0``#[=&4`^W:U!FB40D%H!^9@%T1P^V1F;&0V0`B$-FB70D!(M#
+M!(D$).C\____BT,$@V@(`8M'!(.`)`(```&+="0@B5PD,(M\)"2+7"0<BVPD
+M*(/$+.G\____BU9,BTM,BT9(,T-(,=$)P76GBT8@BU8DA<!T#HUV`,8"`(/"
+M`8/H`77UBT<$.T0D&'0XB48HBU=@BT=<B59,B49(9BML)!;&1F8`9HEN4(M<
+M)!R)="0PBWPD)(MT)""+;"0H@\0LZ?S___^+1PCKP^L-D)"0D)"0D)"0D)"0
+MD%575E.#[!R+1"0PBTPD,(/`#(E$)!"+1"0P@\$<B4PD#(/`+(E$)`B+3"0P
+MQT$T`````.L=BT((A=*+3"0PB4$L="V+0@3'0@@`````B00D_Q*+1"0PBU`L
+M.U`P==>%TL=`,`````#'0"P`````==.+1"0PBTPD$(M`##G(B40D%`^$,P(`
+M`,=$)!@`````BW0D%('N*`(``(N&(`(``(7`=1"+1"04]H8<`@``((UX"'0/
+MBTPD%,=$)!@!````C7D(C:XX`@``BXXP`@``.?ET?XL1B<N+002#ZPR)0@2)
+M$(E)!(D)=&D/MI8<`@``]L(!#X0X`0``BX8D`@``A<!T#XN&1`(``#M#-`^/
+MA@$``(/B&`^%?0$``(M#-(EK#(.&)`(```&)AD0"``"+ACP"``")CCP"``")
+M"(E#$(M&!(D<)/]0((N.,`(``#GY=8&-OD@"``"+CD@"```Y^719BQ&)RXM!
+M!(/K#(E"!(D0B4D$B0ET0XM#/(7`="K'0!P`````B5@@QT`D`````(E$)`2+
+M0RB)!"3H_/___X7`=;6+0SR)0SB)'"3H_/___XN.2`(``#GY=:>+OE0"``"%
+M_W0HC;Y4`@``C;8`````BQ^%VW06B=J)\.@!]/__A<!T?8U[$(L?A=MUZHM$
+M)!2+3"00BP`YR(E$)!0/A8W^__^+7"08A=L/A*P```"+3"0PBU$LA=(/A0O^
+M__^+032%P`^%`/[__X/$'%M>7UW#QD-F`HN&/`(``(.&)`(```&)CCP"``")
+M:PR)0Q")"(D<).C\____Z6S^__^-="8`BT,0B0>+AE`"``")0Q"-0QR)GE`"
+M``")1"0$BT0D"(D$).C\____BTPD,,=!-`$```#I.?___XN&,`(``(U3#(E0
+M!(E[$(V^2`(``(E##(F6,`(``.F=_O__BT0D,(N(B`$#`(7)=!_K;8M""(M,
+M)#")022%TG1-BT($QT((`````(D$)/\2BTPD,(M1)#M1*'77QT$H`````,=!
+M)`````#KT8M!!(L1B4($B1")R(/H#(D)B4D$#X3Q_O__B00DZ/S___^+1"0P
+MBT@<.TPD#'71Z=?^___'@(@!`P``````B00DZ/S____KG)"-="8`@^P,B5PD
+M!(M<)!")="0(BS.+1B2%P'0HBTX@C5,,C48<B58@B4,,B4L0B1&)="00BUPD
+M!(MT)`B#Q`SI_/___XD<).C\____Z^*0D)"0D)!5,>U75E.+?"08BW0D%(GX
+M"?!T'XGQB?N#Q0&#P?^#T_^)\(GZ(<@AVHG&B=")UPGP=>&)Z%M>7UW#C;8`
+M````55=64X/L#(MT)""+1@R)1"0(BUX\BTXXB=@)R'4-]H9(`0```@^%V@``
+M`#'_BT9`BU9$"<@)VHE4)`2)!"3H_/___XM6!`^V4@8!^#G0?ER`IAP"``#^
+M]H8<`@```71$BT0D"(7`=#R+7"0(#[93,(32=#"+1"0(N?[___^[_____SEP
+M2'1M,<#K$I"-="8`BUPD"`^VR#ETBTAT/H/``3C0=>R#Q`Q;7E]=PXMN/(M^
+M.(".'`(```&)Z0GY=)B+7D2+3D`QZS'YB=@)R'5,@*9(`0``_>E\____,<`Q
+MTO;!(`^4P`^5PM/BT^")TXG!]]/WT8M$)`@A2$")QB%81.D&____BT8$@'@'
+M`0^%&?___P^V>`;I$O___XG:B<@AZB'XB=$)P0^$*O___X".2`$```+I'O__
+M_XVT)@````!64XM(#(G##[9Q,(GPA,!T(3'`,=(Y64AU#^L;C70F``^VPCE<
+M@4AT#H/"`8GP.,)U[KC_````6U[#C;8`````5U:)QE.+>B2%_W1#BT<4A<!T
+M-HM`#(7`="\Y\'0U#[90,(72?NTQVXM,F$B%R70*@'D(!'8$.?%T&8/#`3G:
+MD'_FBT`,A<!UT8L_A?]UO3'`ZP6X`0```%M>7\.-="8`5U93@^P<BUPD+(MT
+M)#"+?"0T@'L(!'9\QT0D&`````#'1"04`0````^V2S"%R7X?BU-(,<"%TG0/
+MZW20C70F`(M4@TB%TG5G@\`!.<AU\8M3!(!Z!0!T(0^V0S`/ME(&*=`/KT0D
+M%(E$)!0/MT,R.T0D&'8$B40D&(7V=`:+1"08B0:%_W0&BT0D%(D'@\0<6UY?
+MPX7V=`;'!@````"%_W3KQP<!````@\0<6UY?PXU$)!2)1"0(C40D&(D4)(E$
+M)`3H_/___XM3!(!Z!0!TJ>N&C;0F`````(V\)P````!3@^P<BUPD)(U$)!2)
+M1"0(C40D&(E$)`2+0P2)!"3H_/___XU$)`R)1"0(C40D$(E$)`2+0PB)!"3H
+M_/___XM,)!0[3"0,#Y=#%(M4)!B+1"00.=!S`HG0#Z_!9H7`9HE#9'4&9L=#
+M9(``@\0<6\.0@^P8B6PD%(ML)!R+5"0@B5PD"(ET)`R)?"00#[9%"#I""'0<
+MN`$```"+7"0(BW0D#(M\)!"+;"04@\08PXUV``^W13!F.T(P==J`?3``#X2S
+M````BTU(BU)(A<ETQC'_A=)TP(!Y"`1V/8!Z"`2)]G:RB50D!(D,).C\____
+MA,!UH@^V13"#QP$Y^'YZBTR]2(M$)""%R8M4N$ATAX72=(.`>0@$=\.`>@@$
+MD(UT)@`/AV[___^+020[0B0/A6+___^+<3"+6C"+5@B+2PB+1@0S0P0QT0G!
+M#X5&____BU80.U,0BT8,#X<W____<@D[0PP/ARS____VA4@!```#D'2`Z1W_
+M__\QP.D;____B?93@^P(BU0D$(M:!(M""(7;="Z%P'1N]H,<`@```74U@*`<
+M`@``_H"C'`(``/['0QS_____QD)G`8/$"%O#C78`A<!T\("@'`(``/[&0F<!
+M@\0(6\/V@!P"```!=,+&0F<`@(M)`0``!("(20$```2)%"3H_/___XE<)!"#
+MQ`A;Z?S___^`HQP"``#^QD)G`8/$"%O#C;8`````C;\`````55=64X/L+(M<
+M)$"+1"1$B40D$`^V4S"%T@^.OP$``,=$)!0`````Z:4```"-="8`A<")70QT
+M!\=`#`````"+1"04QX-,`0```````,>#4`$```````");(-(#[:32`$``(G0
+M@\@*J""(@T@!``!T"8/*BHB32`$```^V3"04,<`QTO;!(`^4P`^5PM/BT^`)
+M4SSWT@E#./?0(5-$(4-`BTPD$(7)#X1$`0``@(M(`0``!(M4)!"%T@^%(`$`
+M`(-$)!0!#[93,#M4)!0/C@T!``"+3"04BT2+2(7`=`GV@!P"```!==B+;"00
+MA>T/A3[___^+0P0/MD`&*<*)T,'X'XE4)`B)1"0,BT,4BU,8B00DB50D!.C\
+M____B40D((L#B50D)(MP#(/`##G&=)#'1"08_____\=$)!S_____ZPN+`XLV
+M@\`,.?!T68V^V/W___:''`(```%TYH!_"`%UX/9'4`1TVHGZB=CH,?O__X3`
+M=<V+5RPY5"0DBT<H=\&0<@8Y1"0@=[@[5"0<C70F`'>N#X.S````B?V)1"08
+MB50D'.N<A>T/A!+____V@TD!```"=%^+122%P'05C70F`(MP%(7V#X7S_O__
+MBP"%P'7OBTPD%(M$BTCI4O[___:#2`$```AU'8/$+%M>7UW#B6PD!,<$)`<`
+M``#H_/___^FG_O__B5PD0(/$+%M>7UWI_/___XM4)""+3"0DB2PDQT0D#```
+M``")5"0$B4PD".C\____A<")Q0^$@/[__XM4)!2+1)-(Z>7]__\[1"08#X/K
+M_O__Z3[___^-M@````!55U93@>P<`@``B[0D,`(``(!^"`1V!X"F2`$``/OV
+MAAP"```!=%:`?@@$=EN`?C``=$HQVXM,GDB%R70U#[:6'`(```^V@1P"``"#
+MX@*#X/T)T(B!'`(``(M4GDB`>@@$=@</MD8TB$(TB10DZ/S___\/MD8P@\,!
+M.=A_N('$'`(``%M>7UW#BT8DB40D&/:`'`(```$/A$0#``"+;@PQ_X7M=`N+
+M?0R%_P^$:`,``(U<)!R)V,8``(V4)!P"``"#P`$YT'7OA?_'`_06>%H/A"P#
+M``"+1R2)0P2+1RR)@\8```#VAAP"```"=`2`2Q8!A?\/A!8#``"#_0$9P(/`
+M`HA#&(N/9`$``(7)=#:+`8M18(E#"(M!7(E3$`^V4Q:)0PP/MD$4@^+]@^`!
+M`<`)PHA3%CEY"`^$[0(```^V06:(0Q0/MD<TA>V(@\4````/MH<=`@``B$,7
+MBT<4BU<8B4,9B5,=#[9'"(A#(0^V1S"(0R*)Z`^$IP(``.A_^/__#[93)8/B
+M^XA#(P^V1S&(0R0/MH=(`0``@^`!P>`""<*(4R7VAT@!```"=`:#R@&(4R6+
+M1SB-2TF+5SR)@ZT```")D[$```"+1SAFB4,GBX=,`0``BY=0`0``B4,IB5,M
+MBT<HC9=4`0``B8.]````BX=4`0``B4-)BT($B4$$BT((B4$(BT(,C9>L`0``
+MB4$,BX=H`0``C8N=````B4-9BX>L`0``B8.=````BT($B4$$BT((B4$(BT(,
+MB4$,BY=L`0``C8=L`0``C4M=B5-=BU`$B5$$BU`(B5$(BU`,B5$,BU`0B5$0
+MBU`4B5$4BU`8B5$8BU`<B5$<BU`@B5$@BU`DB5$DBU`HB5$HBU`LB5$LBU`P
+MB5$PBU`TB5$TBU`XB5$XBT`\B4$\A>T/A(<```"+112+51B)0S&)4S4/MD4(
+MB$,Y#[9%,(A#.HGPZ"WW__\/ME,]@^+[B$,[#[9%,8A#/`^VA4@!``"#X`'!
+MX`()PHA3/?:%2`$```)T!H/*`8A3/8M%.(M5/(F#M0```(F3N0```(M%.&:)
+M0S^+A4P!``"+E5`!``")0T&)4T6+12B)@\$```")'"3H_/___XD<),=$)`0`
+M`@``Z/S___^)7"00QT0D%`````#'1"0,`0```/?8B$0D,8M&*(M6+(E$)`2)
+M5"0(BT8DB00DZ/S___^+3"08BT$XBU$\B5PD$,=$)!0`````QT0D#`$```")
+MP0-.*(G3$UXL@<$`^/__@]/_!0``_O^#TO\E``#^_RG!&=.)3"0$B5PD"(M&
+M)(D$).C\____BW8DB70D&(M$)!CV0%`0#X2/_/__B00DZ/S___^!Q!P"``!;
+M7E]=PS'`QT,$`````.G/_/__QD,8`.F2_O__B>@Q[8G'Z8W\__^)\.E2_?__
+M@\H$B%,6Z0C]__^-="8`C;PG`````%93@^P$BT0D$(M8#(UP##GS=0CK.8L;
+M.?-T,XV3V/W__X!Z"`1V[O:"2`$```1TY8M"#(7`=`F)PHM"#(7`=?>)%"3H
+M_/___XL;.?-US8/$!%M>PXVV`````(V_`````%=64X/L$(M<)"#K!HUT)@")
+MPXM##(7`=??H_/___XN[9`$``(7_B4,D="J+=P0YWG1(Z/S___^%]HD'=!B-
+M=@#H_/___XE&)#M#)'3SB30DZ/S___^)'"3H_/___XM#!(M(/(7)=`R)7"0@
+M@\006UY?_^&#Q!!;7E_#BW<(Z[.0@^PLB70D((MT)#")7"0<B7PD)(EL)"@/
+MMD8(@^@%/`4/A^H````/ML#_)(6D#@``#[=&,C'2]]B#T@#WVB&&3`$``"&6
+M4`$``/:&'`(```$/A<8!``"+?D"+;D2)Z`GX=0B+1C@+1CQT5H!^"`H/A-(!
+M``"`ID@!``#^B>H)^G0_BT9`@(Y)`0``(`M&1'0P]H8<`@```71WBWX,A?]T
+M"?:''`(```%T(\=$)`0`````B30DZ/S___^-M"8`````]H8<`@```71'BWX,
+M]H9)`0``!'4^]H9(`0```W0UBT8XBU8\B40D$(E4)!0)P@^%?P$``(7_=`GV
+MAQP"```!=!J`CD@!```(B30DZ/S___^+?@R%_P^$V````(M<)!R+="0@BWPD
+M)(ML)"B#Q"S#,?\Q[8!^,`!U$NO5D(UT)@`/MD8P@\<!.?A^1(M<ODB%VW3M
+M@'L(!';GB1PDZ/S____V@T@!```$=`>`CD@!```$#[:#2`$``(/@`SP"=<$/
+MMD8P@\<!O0$````Y^'^\A>T/A'G___^`ID@!``#^,=N%P'\;Z6?___^-M"8`
+M````#[9&,(/#`3G8#XY1____BU2>2(72=.F`>@@$=N/V@D@!```!=-H/MH)(
+M`0``@^"^@\@"B()(`0``B10DZ/S____KO?:&2`$```0/A!O___^)="0PBUPD
+M'(MT)""+?"0DBVPD*(/$+.G\____BVY$BWY`B>J)^/?2(U8\]]`C1CB)T0G!
+M#X0B_O__@(Y(`0```ND6_O__#[9.,#'`,=*#Z0'VP2`/E,`/E<+3XM/@BTX\
+M,T8X,=$)P0^%!O[__^D(_O__BUY$BT9`B=F)PO?1(TPD%/?2(U0D$(G("=`/
+MA(#^___I7/[__Y"-M"8`````@^PLB7PD*(M\)#"+5"0TB5PD((ET)"2)^.AB
+M\O__A,!U7HM'%(M7&(E$)!B+1P2)5"0<#[9/,/:'20$```(/ME`&=%$QP/:'
+M2`$```1U$8M<)""+="0DBWPD*(/$+,.0B3PDZ/S___^+7"0@,<"+="0DBWPD
+M*(/$+,.-M@````"+7"0@N/____^+="0DBWPD*(/$+,,/ML$/MM(IT(G"P?H?
+MQT0D#`````"+="0,B40D"(M$)!B)5"0,BU0D'(D$)(E4)`3H_/___XET)`R)
+M5"0(BU0D-(E$)`2)%"3H_/___X7`=)J)1"0$B3PDZ/S____I3?___XGVC;PG
+M`````%57B==64XT428/L#(TLUXE,)`@/ME4AB00DB50D!.C\____A<")Q@^$
+M=`$``("@'`(``/X/MD<7B(8=`@``BT<$B48DBX?&````A<")1BQU!HM'!(E&
+M+`^VA\4```"-71"(1C0/ME,5#[:&2`$``,#J`H/B`8/@_@G0B(9(`0``BT4I
+MBU4MB89,`0``B990`0``BU0D"(N$E[T```")1B@/MDTDN`$```#3X(A.,6:)
+M1C*+0PF+4PV)1A2X_____XE6&`^V32*Z_____X#Y/XA.,`^&V````(E61(U7
+M28E&0(M'28V.5`$``(F&5`$``(M"!(E!!(M""(E!"(M"#(V7G0```(E!#(M'
+M68V.K`$``(F&:`$``(N'G0```(F&K`$``(M"!(E!!(M""(E!"(M"#(E!#(M7
+M78U'78V.;`$``(F6;`$``(M0!(E1!(M0"(E1"(M0#(E1#(M0$(E1$(M0%(E1
+M%(M0&(E1&(M0'(E1'(M0((E1((M0)(E1)(M0*(E1*(M0+(E1+(M0,(E1,(M0
+M-(E1-(M0.(E1.(M`/(E!/(/$#(GP6UY?7<.0C70F`#'`,=+VP2`/E,`/E<+3
+MX-/B@\#_@]+_Z0S___^-="8`@>QL`@``BX0D<`(``(U,)%B)G"1<`@``BY0D
+M<`(``(FT)&`"``"+M"1P`@``B;PD9`(``(FL)&@"``"+`(E$)#R+>B2+1SB+
+M5SR)3"00QT0D%`$```#'1"0,`0```(G!`TXHB=,37BR)/"2!P0#X__^#T_\%
+M``#^_X/2_R4``/[_*<$9TXE,)`2)7"0(Z/S___^%P(G&#X0,`0``BYPD<`(`
+M`(U,)%C'1"04`0```(E,)!#'1"0,`0```(M#*(M3+(E$)`2)5"0(BT,DB00D
+MZ/S___^#^/^)Q71%C4PD6(D,).C\____@7PD6/06>%H/A/$```"X_____XN<
+M)%P"``"+M"1@`@``B[PD9`(``(NL)&@"``"!Q&P"``##C78`A?9UT8M'.(M7
+M/,=$)!0!````QT0D#`$```")1"0@BX0D<`(``(E4)"2+3"0@C50D6(M<)"2)
+M5"00BU0D)`-(*!-8+(M$)""!P0#X__^#T_\%``#^_X/2_R4``/[_*<$9TXN4
+M)'`"``")3"0$B5PD"(M")(D$).C\____A<`/A#C____I3?___XU$)%B)!"3H
+M_/___X%\)%CT%GA:=`J^_O___^G4_O__C50D6,=$)`0``@``B10DZ/S___^$
+MP`^$N/[__^O8C5PD6,=$)`0``@``B1PDZ/S___^$P`^%\_[__X7M#X4[!@``
+MA?:-="8`#X6$!@``@'PD>00/AM3^__^`?"1Z0`^'R?[__X"\))(```!`#X>[
+M_O__BW0D/#'2BYPD"0$```^W1"1_BXPD!0$```G3BU8,B5PD1`G!B4PD0(GQ
+M@\$,.<IT'8VZV/W__X!_"`1V"XM'#(7`#X21!@``BQ(YRG7CBT0D/#')C50D
+M6.B9^___A<")QP^$5/[__P^VET@!``")T(/B_=#H"D0D?8/@`0'`"<*+1SB(
+MET@!``"+5SR)1"0HB50D+`^V1S#'1"08_____\=$)!S_____/#]W)8G!B<[!
+M[@6#Y@&)\X/S`=/CT^:)7"08@T0D&/^)="0<@U0D'/^+1"1`BTPD*"-$)!B+
+M5"1$(U0D'`G!B4\XBT0D+`G0#[:72`$``(E'/`^V1"1]@^(!P.@"@^`!.,)T
+M(@^VET@!``"+1P2#XOZ(ET@!``"`>`8`=`F#R@*(ET@!``"+1"1@A<!T8HN/
+M9`$``("/20$```2%R0^$U0,``(!Y%``/A'\$``"+5"1H.5%@BT0D9'<'<A,Y
+M05QV#HE!7(E18`^V1"1LB$%F]D0D;@0/A(L#``"+40B%T@^$<P,``(M!!#G"
+M#X17`P``BT<H.X0D%0$```^$#@,``("/2`$```+'ATP!````````QX=0`0``
+M``````^VEQP"``")T(/B_=#H"D0D;H/@`0'`"<*(EQP"```/MD0D>X!\)'`!
+M#X9;`@``#[;8BW2?2(7V#X0D`@``#[:6'`(``(G0@^+]T.@*1"1N@^`!`<`)
+MPHB6'`(```^VED@!``")T(/B_=#H"H0DE0```(/@`0'`"<*+1CB(ED@!``"+
+M5CR+C"01`0``#[><))<```")1"10B50D5(N4)`T!``")3"1,B50D2`^V3C#'
+M1"0P_____\=$)#3_____@/D_=R,QP#'2]L$@#Y3`#Y7"T^#3XHE$)#"#1"0P
+M_XE4)#2#5"0T_XM,)#`/M\,QT@M$)$B+7"0T"U0D3"'!BT0D4"'3#[:62`$`
+M``G(B48XBT0D5(/B`0G8B48\#[:$))4```#`Z`*#X`$XPG0B#[:62`$``(M&
+M!(/B_HB62`$``(!X!@!T"8/*`HB62`$```^VC"23````BVR.2(7M#X64^___
+MBY0D<`(``(M&*(E4CD@[A"09`0``B7(,#X2G````@(Y(`0```L>&3`$`````
+M``#'AE`!````````,<`QTO;!(`^4P`^5PM/BT^#WTO?0(59$(49`B30DZ/S_
+M__\/MH9(`0``J!!U#:@@=!V#R("(AD@!``#'ADP!````````QX90`0``````
+M`/:''`(```%T+8N'9`$``(7`=".+4`2%TG0<BT`(A<!T%3G7=`*)T(D$).C\
+M____,<#IV_K__S'`Z=3Z__^+E"2=````.990`0``BX0DF0````^"6O___W<,
+M.89,`0``#X9,____B89,`0``B990`0``Z3O___^+1"0\N0$```"-5"18Z+_W
+M__^%P(G&#X1Z^O__B7@,B42?2.FT_?__#[;(,=*+G"1P`@``,<#VP2`/E,`/
+ME<+3XM/@]]+WT"%71"%'0(E<CTB)>PR)/"3H_/___P^VAT@!``"H$'41J"`/
+MA!O___^#R("(AT@!``#'ATP!````````QX=0`0```````.GY_O__BY0DA0``
+M`#F74`$``(N$)($````/@O/\__]W##F'3`$```^&Y?S__XF'3`$``(F74`$`
+M`.G4_/__N/_____'000`````Z<#Y__^+002)^HEY".F#_/__BT$$A<`/A.,`
+M``"+40CI</S__XMT)#R+1A2)\X/#%#G8="B+5"1@C4CT.5#T=`Z+`#G8=!8Y
+M4/2-2/1U\H7)B8]D`0``#X7S^___BT0D/(/H@(D$).C\____A<")P8F'9`$`
+M``^$1/G__S'`Q@0(`(/``8/X:'7TBU0D/(MT)#R)60R+0AB-40R)5AB)$(M4
+M)&B)01"+1"1@B0&+1"1DB5%@B4%<#[9$)&R(06;V1"1N`@^$AOO__XN'9`$`
+M`,9`%`'I=_O__XM4)&@Y46"+1"1D#X>2^___#X)^^___.4%<#X.#^___B?;I
+M;OO__XM1"(GXB7D$C78`Z87[__^-="18B30DC5PD6.C\____BXPD<`(``(U$
+M)%C'1"04`````(E$)!#'1"0,`0```(M!*(M1+(E$)`2)5"0(BT$DB00DZ/S_
+M__^)'"3H_/___^E\^?__C70D6(DT).C\____BT<XC4PD6(NT)'`"``"+5SR)
+M3"00QT0D%`````")P<=$)`P!`````TXHB=,37BR!P0#X__^#T_\%``#^_X/2
+M_R4``/[_*<$9TXE,)`2)7"0(BT8DB00DZ/S___^-1"18B00DZ/S____I`_G_
+M_XM')#M$)%P/A6+Y___VAQP"```!=7>`?"1P`0^&;?G__P^V1"1[BW2'2(7V
+M#X1<^?__]H8<`@```0^$3_G__XM..(N$)`T!``"+7CR+E"01`0``"<@/MXPD
+MEP````G:,=L)V@G(B50D!(D$).C\____BU8$#[92!CG0#XX.^?__B3PDZ/S_
+M___IZ/C__XM$)$"+5"1$"U<\"T<XB50D!(D$).C\____BU<$#[92!CG0?\[I
+M7____XVV`````%57,?]64X/L#(M$)""+:`R)1"0(#[9%,(3`#[;P#X2``@``
+MBU0D"#'),=LY54AU%NEN`@``C02-`````(M4)`@Y5`5(=!*#P0&#TP")R(G:
+M,?`Q^@G"==TQP#'2]L$@#Y3`#Y7"T^+3X`E%0`E51(DL).C\____]H4<`@``
+M`0^%Q@```(M%#(7`#X3C`0``BT`$B2PD_U`D,<DQVX!],`!T9XT$C0````"+
+M5`5(A=)T0O:"'`(```%T.8!Z"`1V,P^VLD@!``")\(/@CXB"2`$``#M4)`@/
+MA*,!``#V@D@!```!=`Z#YHZ#S@*)\(B"2`$``(/!`0^V13"#TP`QTCG:=Y\/
+M@T<!``"+A60!``"%P`^$,`$``(M0!(72#X0E`0``BT`(A<`/A!H!```YU70"
+MB="`H!P"``#^B40D((/$#%M>7UWI_/___P^VA4@!``"#X+^H((B%2`$``'0=
+M@\B`B(5(`0``QX5,`0```````,>%4`$````````/MK5(`0``BUU$BTU`B?"#
+MX/Z)VHB%2`$``/?2B<@C53SWT"-%.(G1"<%U"X/F[(GPB(5(`0``BW4,A?8/
+MA*L```"`ID@!``#^,<DQVS'_@'XP``^$E````(T$C0````"+5`9(A=)T,/:"
+M'`(```%T)X!Z"`1V(?:"2`$```%T&`^V@D@!``"_`0```(/@K(/(`HB"2`$`
+M`(/!`0^V1C"#TP`QTCG:=[%S.(N=9`$``(7;#X1\````]H5(`0``!'53A?]U
+M68"-20$``""#Q`Q;7E]=PY`YR`^'2O[__^FL_O__.<B0#X=N____Z[TQ_XVV
+M`````.NSB2PDZ/S____I&?[__X/FC(GPB()(`0``Z63^__^)+"3H_/___^NG
+MB2PDZ/S____KG;@!````,=+INOW__XM%#(7`=`Z+B&0!``"%R0^%;____XM5
+M'(72>!7'1"0$`````(DL).C\____Z5/___^%P`^$2____XM`'(7`C78`>=GI
+M//___Y"0D)"0D)"0D*$`````A<!T,C')D(UT)@"`>`@!BP"#V?^%P'7SA<ET
+M&J$`````B<+!^A_!ZA0!PL'Z#(G0P?H?]_G#BQ4`````B=#!^!_!Z!0!T,'X
+M#,.0\\.-M"8`````C;PG`````(M,)`2+5"0(BX'\````B4(,B9'\````PY"-
+MM"8`````,<##C;8`````C;PG`````%=64X/L$(M\)""+A^P```#'AQ0!````
+M````C;8`````B[<``0``A?9T.3D&=V0YMP0!```/A(L```"+1A")AP`!``"+
+M1@C'1A``````B00D_U8$B[<``0``BX?L````A?9UQSU_`0``=R&+G_P```"%
+MVW07QT0D!`````"+`XD$)/]3!(M;#(7;=>F#Q!!;7E_#BY_\````A=MT[XUT
+M)@"+!HE$)`2+`XD$)/]3!(M;#(7;=>N+A^P````[!@^#7?___^O&QX<$`0``
+M`````,>'``$```````#I9?___XGV5E.#[!2+="0@BY[\````A=MT%\=$)`3_
+M____BP.)!"3_4P2+6PR%VW7I,<"#?BP`#Y7`@\046U[#C;0F`````%.#[`B+
+M7"00BX,4`0``A<!U.8V#"`$``,>#"`$``*!`!`")FPP!``#'@Q`!````````
+MB40D!(U#+(D$).C\____QX,4`0```0```(/$"%O#@^P,BU0D$(M,)!2+@@`!
+M``"%P'0@BX($`0``B4@0B8H$`0``B10DZ/S___^X`0```(/$#,.+@NP````[
+M`7,.B8H$`0``B8H``0``Z]>+00B)!"3_400QP.O7C;8`````BT0D!`7D````
+MB40D!.G\____C;0F`````(V\)P````"+1"0$!>0```")1"0$Z?S___^0D)"0
+MD)"0D)"0D)"0D%.+7"0(#[9#%(G"@^#["E,5@^($"=`/ME,5B<&#X/Z#X0&#
+MX@$)R@G0B$,4#[9#)(G"@^#["E,E@^($"=`/ME,EB<&#X/Z#X0&#X@$)R@G0
+MB$,D6\.-="8`C;PG`````%.+7"0(#[9#)8G"@^#["E,F@^($"=`/ME,FB<&#
+MX/Z#X0&#X@$)R@G0B$,E#[9#/8G"@^#["E,^@^($"=`/ME,^B<&#X/Z#X0&#
+MX@$)R@G0B$,]6\,```````````````````````````````````!R-S4P7T-O
+M;7!L971E4F5Q=65S=$%N9%-L;W0`R)0``,R4```*E0``1)4``'Z5``"XE0``
+M\I4``"R6``!FE@``+)8``&:6``"@E@``UI8``!J7``"<EP``TI<``"^8``#/
+MF```"9D``$.9```0F@``$)H``!":```0F@``$)H``*24``#AF0``%ZD```VF
+M```EI@``1:8``'VF``".I@``EZ8``*"F``!-IP``<:<``'JG``"#IP``XJ<`
+M`'FH``#8J```$,0``)?!``"HP0``N<$``,K!```5P@``,\(``$?"``";P@``
+MM\(``-/"``#OP@``&\,``"_#```0Q```$,0``!#$``!#PP``HL,``!#$```0
+MQ```:,,``.##``#HP0``_,$``!#$``!;P@``;\(``(/"``#6[@``UNX```SO
+M```@[P``UNX``-;N``#@[@``-.\``$KO``!@[P``4F]C:V5T(#<U,"!3051!
+M($-O;G1R;VQL97(```$`````````EC`'=RQA#NZZ40F9&<1M!X_T:G`UI6/I
+MHY5DGC*(VPZDN-QY'NG5X(C9TI<K3+8)O7RQ?@<MN.>1';^09!"W'?(@L&I(
+M<;GSWD&^A'W4VAKKY-UM4;74],>%TX-6F&P3P*AK9'KY8OWLR66*3UP!%-EL
+M!F-C/0_Z]0T(C<@@;CM>$&E,Y$%@U7)Q9Z+1Y`,\1]0$2_V%#=)KM0JE^JBU
+M-6R8LD+6R;O;0/F\K.-LV#)U7-]%SPW6W%D]T:NL,-DF.@#>48!1U\@68="_
+MM?2T(2/$LU:9E;K/#Z6]N)ZX`B@(B`5?LMD,QB3I"[&'?&\O$4QH6*L=8<$]
+M+6:VD$'<=@9QVP&\(-*8*A#5[XF%L7$?M;8&I>2_GS/4N.BBR0=X-/D`#XZH
+M"988F`[ANPUJ?RT];0B7;&21`5QCYO11:VMB86P<V#!EA4X`8O+ME09L>Z4!
+M&\'T"()7Q`_UQMFP95#IMQ+JN+Z+?(BY_-\=W6))+=H5\WS3C&5,U/M88;)-
+MSE&U.G0`O*/B,+O40:7?2M>5V#UMQ-&D^_36TVKI:4/\V6XT1HAGK="X8-IS
+M+01$Y1T#,U],"JK)?`W=/'$%4*I!`B<0$`N^AB`,R26U:%>SA6\@"=1FN9_D
+M8<X.^=Y>F,G9*2*8T+"TJ-?'%SVS68$-M"X[7+VWK6RZP""#N.VVL[^:#.*V
+M`YK2L70Y1]7JKW?2G14FVP2#%MQS$@MCXX0[9)0^:FT-J%IJ>@O/#N2=_PF3
+M)ZX`"K&>!WU$DP_PTJ,(AVCR`1[^P@9I75=B]\MG98!Q-FP9YP9K;G8;U/[@
+M*].)6GK:$,Q*W6=OW[GY^>^^CD.^MQ?5CK!@Z*/6UGZ3T:'$PM@X4O+?3_%G
+MN]%G5[RFW0:U/TLVLDC:*PW83!L*K_9*`S9@>@1!P^]@WU7?9ZCOCFXQ>;YI
+M1HRS8<L:@V:\H-)O)3;B:%*5=PS,`T<+N[D6`B(O)@55OCNZQ2@+O;*26K0K
+M!&JS7*?_U\(QS]"UBY[9+!VNWENPPF2;)O)C[)RC:G4*DVT"J08)G#\V#NN%
+M9P=R$U<`!8)*OY44>KCBKBNQ>S@;M@R;CM*2#;[5Y;?OW'PAW]L+U-+3AD+B
+MU/'XL]UH;H/:'\T6OH%;)KGVX7>P;W='MQCF6@B(<&H/_\H[!F9<"P$1_YYE
+MCVFN8OC3_VMA1<]L%GCB"J#NT@W75(,$3L*S`SEA)F>G]Q9@T$U':4G;=VX^
+M2FK1KMQ:UMEF"]]`\#O8-U.NO*G%GKO>?\^R1^G_M3`<\KV]BL*ZRC"3LU.F
+MH[0D!3;0NI,&U\TI5]Y4OV?9(RYZ9K.X2F'$`AMH790K;RHWO@NTH8X,PQO?
+M!5J-[P(M:B(!`*XB`0!P(P$`<",!`'`C`0!P(P$`\B(!`#$C`0!P(P$`B",!
+M`-\M`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`
+MZ2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I
+M+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM
+M`0#I+0$`Z2T!`+(M`0#I+0$`LBT!`.DM`0#I+0$`Z2T!`+(M`0"R+0$`Z2T!
+M`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`
+MZ2T!`.DM`0#I+0$`Z2T!`.DM`0"R+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I
+M+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0"R+0$`LBT!`+(M
+M`0"R+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!
+M`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`
+MZ2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I
+M+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`+(M
+M`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`+(M`0#I+0$`LBT!
+M`.DM`0#I+0$`Z2T!`+(M`0"R+0$`Z2T!`.DM`0#I+0$`LBT!`.DM`0#I+0$`
+MZ2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I
+M+0$`Z2T!`.DM`0#I+0$`Z2T!`.DM`0#I+0$`LBT!`.DM`0"R+0$`Z2T!`.DM
+M`0#I+0$`LBT!`+(M`0#^0@$`L4(!`+Y"`0#@0@$`_D(!`/1"`0#J0@$`_D(!
+M`/Y"`0#^0@$`_D(!`.I"`0#Y:0$`'6H!`$%J`0"U:@$`1VL!```````QL@$`
+M!K(!`!&R`0`WL@$``+(!``"R`0``L@$``+(!``"R`0``L@$``+(!``"R`0``
+ML@$``+(!``"R`0``L@$`0;(!`#>R`0`7L@$`,;(!`"&R`0`GL@$`0;(!`/.Q
+M`0``(```!$0````@`0`$1````@$```(Z```"`0$``CH```0!```+````!`$!
+M``L````(`0``!EH!``@!`0`&6@$`$`$```,4`0`0`0$``Q0!`"`!```&*```
+M(`$!``8H``!``0```Q$``$`!`0`')P``@`$```M'`P"``0$`"T<#`'`I`@#@
+M*0(`!2H"`"HJ`@!/*@(`="H"`*$J`@`^*P(`=2L"`$HL`@#X*P(`'2P"`&\L
+M`@"!+0(`OBT"`.\M`@`R+@(`9B\"`&,N`@!X+@(`KBL"`-,K`@#.*@(`!2L"
+M`/@K`@"-+@(`HR\"`-`O`@#U+P(`(C`"`#8P`@!D,`(`I#`"`+HN`@#G+@(`
+M%"\"`$$O`@```````````*!E`@"U7`(`^UP"`'1=`@#I70(`$UX"`&1>`@#U
+M7@(`!5\"`'5B`@!G80(`H5P"`*!E`@"@90(`H&4"`*!E`@"@90(`'F4"`*!E
+M`@"@90(`#E\"`"9?`@!M7@(`[%X"`&=A`@!18P(`:V4"`'%E`@"890(`H&4"
+M`&]D`@"P9`(`N60"`%IC`@!E8P(`;F,"`'=C`@#"=`(`R70"`-)T`@#9=`(`
+MXG0"`.ET`@#R=`(`MW0"`.61`@!7CP(`:(\"`'F/`@"*CP(`U8\"`/./`@`'
+MD`(`6Y`"`'>0`@"3D`(`KY`"`-N0`@#OD`(``Y$"`.61`@#ED0(`')$"`'N1
+M`@#ED0(`Y9$"`$&1`@"YD0(`J(\"`+R/`@#ED0(`&Y`"`"^0`@!#D`(`````
+M`````````````````````````````````/#&`@#PQ@(`+\<"`$3'`@#PQ@(`
+M;L<"`/K&`@!9QP(`'<@"`"_(`@"ZT0(`9],"`&?3`@!GTP(`9],"`&?3`@!G
+MTP(`9],"`&?3`@!GTP(`9],"`&?3`@!GTP(`9],"`&?3`@!GTP(`9],"`&?3
+M`@!GTP(`9],"`&?3`@!GTP(`9],"`&?3`@!GTP(`9],"`&?3`@!GTP(`9],"
+M`&?3`@!GTP(`9],"`,[1`@`WT@(`H-("``G3`@!SU`(`0MH"`$+:`@!"V@(`
+M0MH"`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:`@!"
+MV@(`A]0"`(?4`@"'U`(`0MH"`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:
+M`@!"V@(`0MH"`$+:`@!"V@(`0MH"``'5`@!FU0(`R]4"`#'6`@!"V@(`0MH"
+M`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:`@"6U@(`
+M%-<"`)+7`@`0V`(`0MH"`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:`@!"
+MV@(`0MH"`$+:`@!"V@(`CM@"`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:
+M`@!"V@(`0MH"`$+:`@!"V@(`0MH"`$+:`@!"V@(`0MH"`-38`@`2V0(`4-D"
+M`([9`@#,V0(`!]H"``````````````````````!$871A0V5N=&5R(#<R.#`@
+M4T%402!#;VYT<F]L;&5R``$````;`````0`````?`P"+'P,`,Q\#`!0?`P"+
+M'P,`BQ\#`(L?`P"+'P,``!\#`$4@`P``'P,``!\#`+L>`P`Y(`,`!B`#`,\?
+M`P`!1@,`$48#`!E&`P`A1@,`*48#`#%&`P`Y1@,`"48#`-1+`P"%3@,`ITT#
+M`%%.`P`@3@,`44X#`-1+`P#82P,`XJT#`&6N`P!(KP,`=J\#`#6P`P`SL0,`
+M3[$#`%NQ`P`BK@,`TK$#`(FR`P#BK0,`F+,#`*6R`P!$LP,`<L(#`*3&`P!\
+MQ@,`8L8#`$C&`P`DQ@,`<L(#``K&`P#7P@,`T0<$`,`'!`"@!P0`@`<$`$`'
+M!``'!P0`_RX$`"8N!`#_+@0``"X$```N!```+@0`6R`@("`@("`@72!#9&(@
+M6R4R>"PE,G@L)3)X+"4R>"P@)3)X+"4R>"PE,G@L)3)X+"`E,G@L)3)X+"4R
+M>"PE,G@L("4R>"PE,G@L)3)X+"4R>%TN`````%!H>2`E>"!S:6=N871U<F4@
+M9G)O;2!324=.05154D4@1DE3(&)U<WD`````4&AY("5D('-I9VYA='5R92!F
+M<F]M('5N87-S;V-I871E9"!&25,@8G5S>0!;)3`R>#HE,#)X("4P,F1=(&1I
+M<VL@<F5M;W9E9"X``%LE,#)D.B4P,F0@4"5D72!!<WEN($YO=&EF:6-A=&EO
+M;B!296-E:79E9```17)R;W(@:6X@:7-S=6EN9R!C;VUM86YD+"!E<G(@:6YF
+M;R`P>"5L;%@```!;)3`R>#HE,#)X("4P,F1=(%)E<75E<W0@9F%I;&5D+B!%
+M<G)O<B!I;F9O<FUA=&EO;B`P>"5L;%@```!;)3`R>#HE,#)X($TE9%T@4$T@
+M4F5Q=65S="!F86EL960N($5R<F]R(&EN9F]R;6%T:6]N(#!X)6QL6`!;("`@
+M("`@("!=($@R1"!&25,Z("4P.'@@)3`X>"`E,#AX("4P.'@`6R`@("`@("`@
+M72!$,D@@1DE3.B`E,#AX("4P.'@@)3`X>"`E,#AX("A3=&%T=7,@)7@@17)R
+M;W(@)7@I`````%)E8V5I=F5D($Y53"!297$@<VQO=$YO*"5X+R5X*2!%3E12
+M62`H)3`X>"DL(&5R<F]R(#!X)6QL6````&`M($9)4RA3;&]T.B4P,G@I.B`E
+M,#AX("4P.'@@)3`X>"`E,#AX``!;)3`R>#HE,#)X("4P,F1=($1E=FEC92!R
+M97%U97-T*"5X*2!T:6UE;W5T+@````!;("`@("`@("!=($@R1"!&25,H4VQO
+M=#HE,#)X*3H@)3`X>"`E,#AX("4P.'@@)3`X>```4F5Q("@E>"D@=V%I="!F
+M;W(@8V]M<&QE=&5D(&1O;F4N````6R4P,G@Z)3`R>"!-)61=(%!-(')E<75E
+M<W0H)7@I('1I;65O=70N`%)E9VES=&5R(%-E="`E,#AX("4P.'@@25)1(%-4
+M050@)7@``%LE,#)X.B4P,G@@)3`R9%T@9&ES:R!R96UO=F5D("@E>"DN`$EN
+M=F%L:60@<VEG;F%T=7)E(#!X)7@L('1R96%T(&%S($%402!S=&%T=7,@)7@`
+M`%LE,#)X.B4P,G@@)3`R9%T@1&ES:R!I;B!S=&%N9&)Y(&UO9&4L('-T87)T
+M('1O('!O=V5R(&ET('5P+@````!;)3`R>#HE,#)X("4P,F1=($1I<VL@<&]W
+M97)E9"!U<"X```!;)3`R>#HE,#)X("4P,F1=($1E=FEC92!S=&%T92`E>"!F
+M86EL960@*"5X*2!R971R:65D("5X`%LE,#)X.B4P,G@@)3`R9%T@26YV86QI
+M9"!I9&5N=&EF>2!D871A+"!R971R:65S*"5D*2X`````6R4P,G@Z)3`R>"`E
+M,#)D72!3=&%R="!3;V9T(%)E<V5T(&9O<B`E>"\E>`!;)3`R>#HE,#)X(%`E
+M9%T@4VEG;F%T=7)E('1I;65O=70@9F]R("5X+R5X`%LE,#)D.B4P,F0@325D
+M72!032!297%U97-T(&]F('-T871E("5X(&9O<B`E>"\E>"!F86EL960`4&]R
+M="!R97-E="`H<&AA<V4@)7@@<&UP("5X*2!N;W0@8V]M<&QE=&4@<W5C8V5S
+M<RP@:6=N;W)E('1H92!P;W)T("@E>"!D979I8V4@)7@I````6R4P,G@Z)3`R
+M>"`E,#)D72!297-E="!0:&%S92`E>"!F86EL960@9F]R("5X+R5X`````')E
+M860@97)R;W(@8F5F;W(@=W)I=&4@9&%T82!B86-K`````%LE,#)X.B4P,G@@
+M)3`R9%T@<W!I;B!U<"!M;V1E(&YO="!S=7!P;W)T+@``6R4P,G@Z)3`R>"`E
+M,#)D72!S970@9&ES:R!S<&EN('5P(&UO9&4@)7@N``!;)3`R>#HE,#)X("4P
+M,F1=(&1I<VL@<')O8F5D("AS<&EN=7`@;6]D93H@)60I+@!-5E]297%U97-T
+M("5P.B!#9&);)3)X+"4R>"PE,G@L)3)X+"`E,G@L)3)X+"4R>"PE,G@L("4R
+M>"PE,G@L)3)X+"4R>"P@)3)X+"4R>"PE,G@L)3)X72X`17)R;W(@:6X@:7-S
+M=6EN9R!C;VUM86YD+"!E<G(@:6YF;R`P>"5L;%@```!487-K(&9I;&4@97)R
+M;W(L(%-T871U<U)E9STP>"5X+"!%<G)296<],'@E>"P@3$)!6S`M,UT],'@E
+M>"Q,0D%;-"TW73TP>"5X+@``4F5C96EV960@3E5,(%)E<2!S;&]T3F\H)7@O
+M)7@I($5.5%)9("@E,#AX*2P@97)R;W(@,'@E;&Q8````8"T@1DE3*%-L;W0Z
+M)3`R>"DZ("4P.'@@)3`X>"`E,#AX("4P.'@``$--1"!(96%D97(Z("4P.'@@
+M)3`X>"`E,#AX("4P.'@@+B`E,#AX("4P.'@@)3`X>"`E,#AX("X@)3`X>"`E
+M,#AX("4P.'@@)3`X>"`N("4P.'@@)3`X>`!;)3`R>#HE,#)X("4P,F0@)3`R
+M9%T@4$T@<F5Q=65S="@E>"D@=&EM96]U="X```!4:6UE;W5T($@R1"!&25,H
+M4VQO=#HE,#)X*3H@)3`X>"`E,#AX("4P.'@@)3`X>`!;)3`R>#HE,#)X("4P
+M,F0@)3`R9"`E,#)D72!89F5R("5X($5R<F]R(&EN9F]R;6%T:6]N(#!X)6QL
+M6`!;)3`R>#HE,#)X("4P,G@@)3`R>%T@4$T@6&9E<B`E>"!%<G)O<B!I;F9O
+M<FUA=&EO;B`P>"5L;%@```!2=6YN:6YG($@R1"!&25,H4VQO=#HE,#)X*3H@
+M)3`X>"`E,#AX("4P.'@@)3`X>``@4T<@:71E;2`E,#)X.B!A9&1R("5L;'@@
+M<VEZ92`E>"!31T@@861D<B`E;&QX('-I>F4@)7@``$9A:6QE9"!T;R!E;F%B
+M;&4O9&ES86)L92!S<&EN('5P+@```%LE,#)X.B4P,G@@)3`R9"`E,#)D("4P
+M,F1=($1E=FEC92!R97%U97-T*"5X*2!T:6UE;W5T+@``4F5Q("@E>"D@=V%I
+M="!F;W(@8V]M<&QE=&5D(&1O;F4N````071T1&5V4T%3061D<ELE>%T@(%M5
M;FET260@)7A=('-A<R!A9&1R("4P,G@M)3`R>"TE,#)X+24P,G@M)3`R>"TE
M,#)X+24P,G@M)3`R>`!S86UE('-A<R!A9&1R("4P,G@M)3`R>"TE,#)X+24P
M,G@M)3`R>"TE,#)X+24P,G@M)3`R>````$1E=FEC92`E>"!I;B!S=&%N9&)Y
M(&UO9&4L('-T87)T('1O('!O=V5R(&ET('5P+@````!3=&%R="!T;R!P;W=E
M<B!U<"!D979I8V4@)7@N+BX``%!O<G0@<F5S970H<&AA<V4@)7@@<&UP("5X
M*2!N;W0@8V]M<&QE=&4@<W5C8V5S<RP@:6=N;W)E('1H92!P;W)T("@E>"!D
-M979I8V4@)7@I`````%LE,#)X.B4P,G@@)3`R9%T@9&ES:R!R96UO=F5D("@E
-M>"DN`$1E=FEC92`H4&%T:"`E,#)X('P@5&%R9V5T("4P,G@@?"!%)7@O4R4P
-M,G@I('-P:6X@=7`@;6]D92!N;W0@<W5P<&]R=````%LE,#)X.B4P,G@@)3`R
-M9%T@<V5T(&1I<VL@<W!I;B!U<"!M;V1E("5X+@``6R4P,G@Z)3`R>"`E,#)D
-M72!D:7-K('!R;V)E9"`H<W!I;G5P(&UO9&4Z("5D*2X`359?4F5Q=65S="`E
-M<#H@0V1B6R4R>"PE,G@L)3)X+"4R>"P@)3)X+"4R>"PE,G@L)3)X+"`E,G@L
-M)3)X+"4R>"PE,G@L("4R>"PE,G@L)3)X+"4R>%TN`$5R<F]R(&EN(&ES<W5I
-M;F<@8V]M;6%N9"P@97)R(&EN9F\@,'@E;&Q8````5&%S:R!F:6QE(&5R<F]R
-M+"!3=&%T=7-296<],'@E>"P@17)R4F5G/3!X)7@L($Q"05LP+3-=/3!X)7@L
-M3$)!6S0M-UT],'@E>"X``%)E8V5I=F5D($Y53"!297$@<VQO=$YO*"5X+R5X
-M*2!%3E1262`H)3`X>"DL(&5R<F]R(#!X)6QL6````&`M($9)4RA3;&]T.B4P
-M,G@I.B`E,#AX("4P.'@@)3`X>"`E,#AX``!#340@2&5A9&5R.B`E,#AX("4P
-M.'@@)3`X>"`E,#AX("X@)3`X>"`E,#AX("4P.'@@)3`X>"`N("4P.'@@)3`X
-M>"`E,#AX("4P.'@@+B`E,#AX("4P.'@`6R4P,G@Z)3`R>"`E,#)D("4P,F1=
-M(%!-(')E<75E<W0H)7@I('1I;65O=70N````5&EM96]U="!(,D0@1DE3*%-L
-M;W0Z)3`R>"DZ("4P.'@@)3`X>"`E,#AX("4P.'@`6R4P,G@Z)3`R>"`E,#)D
-M("4P,F0@)3`R9%T@6&9E<B`E>"!%<G)O<B!I;F9O<FUA=&EO;B`P>"5L;%@`
-M6R4P,G@Z)3`R>"`E,#)X("4P,GA=(%!-(%AF97(@)7@@17)R;W(@:6YF;W)M
-M871I;VX@,'@E;&Q8````4G5N;FEN9R!(,D0@1DE3*%-L;W0Z)3`R>"DZ("4P
-M.'@@)3`X>"`E,#AX("4P.'@`(%-'(&ET96T@)3`R>#H@861D<B`E;&QX('-I
-M>F4@)7@@4T=((&%D9'(@)6QL>"!S:7IE("5X``!&86EL960@=&\@96YA8FQE
-M+V1I<V%B;&4@<W!I;B!U<"X```!;)3`R>#HE,#)X("4P,F0@)3`R9"`E,#)D
-M72!$979I8V4@<F5Q=65S="@E>"D@=&EM96]U="X``$%T=$1E=E-!4T%D9');
-M)7A=("!;56YI=$ED("5X72!S87,@861D<B`E,#)X+24P,G@M)3`R>"TE,#)X
-M+24P,G@M)3`R>"TE,#)X+24P,G@`<V%M92!S87,@861D<B`E,#)X+24P,G@M
-M)3`R>"TE,#)X+24P,G@M)3`R>"TE,#)X+24P,G@```!$979I8V4@)7@@:6X@
-M<W1A;F1B>2!M;V1E+"!S=&%R="!T;R!P;W=E<B!I="!U<"X`````4W1A<G0@
-M=&\@<&]W97(@=7`@9&5V:6-E("5X+BXN``!0;W)T(')E<V5T*'!H87-E("5X
-M('!M<"`E>"D@;F]T(&-O;7!L971E('-U8V-E<W,L(&EG;F]R92!T:&4@<&]R
-M="`H)7@@9&5V:6-E("5X*0````!$979I8V4@*%!A=&@@)3`R>"!\(%1A<F=E
-M="`E,#)X('P@125X+U,E,#)X*2!S<&EN('5P(&UO9&4@;F]T('-U<'!O<G0`
-M``!3970@9&5V:6-E("A0871H("4P,G@@?"!487)G970@)3`R>"!\($4E>"]3
-M)3`R>"D@<W!I;B!U<"!M;V1E("5X`````$%T=&%C:&5D(&1E=FEC92!I;F1E
-M>"`E,#)X("A0871H("4P,G@@?"!487)G970@)3`R>"!\($4E>"]3)3`R>"D@
-M("5X)7@E>"5X)7@E>"5X)7@``$)A8VMU<"!S=&%M<"`E>"!S=6T@)7@@8F%C
-M:V5D("5D`````$UA<W1E<B!S=&%M<"`E>"!S=6T@)7@@8F%C:V5D("5D````
-M`%=R:71E(&%R<F%Y(&UE=&$@9&%T82!T;R!M87-T97(@,'@E;&Q8+3XP>"5L
-M;%@``%=R:71E(&%R<F%Y(&UE=&$@9&%T82!T;R!B86-K=7`@,'@E;&Q8+3XP
-M>"5L;%@``%LE9"`E9%T@9&5V:6-E(&5R87-E('5N:70@<W5C8V5S<V9U;&QY
-M+@!;)60@)61=(&1E=FEC92!E<F%S92!U;FET(&9A:6QE9"!O<B!A8F]R=&5D
-M+@````!S970@041)1E]3151?0D%$(&)A9%]S96-T;W(@)60``&1O7V1I<VM?
-M8W1L7V-M9#H@8W1L(&-O9&4@)7@@=F0])7`L($Q"02`P>"5L;%@@;E-E8W1O
-M<B`P>"5X`%)E=')Y:6YG(&9A:6QE9"P@9&ES:R!D;W=N/S\_`'=O<FMR;W5N
-M9"!I<G%3=&%T=7,@/2`P>"5X`%)E<2`E<"`E>"`E>`!$979I8V4@)7@O)7@@
-M<F5M;W9E9"X`3W9E<G)A;&P@4T<@:71E;2`E>"!S:7IE("5X`%-L;W0@8G5S
-M>2P@<VQO="`E>"@E>"D`1'5M<"!S;&]T(&EN9F\Z("5X("5X("5X("5X`$-L
-M96%N('5P('-L;W0@)7@`1#)(($9)4SH@)3`X>"`E,#AX("4P.'@@)3`X>``E
-M,#)X("4P-'@Z)3`T>#HE,#1X`%)E<2`H)7@I('=A:70@9F]R(&-O;7!L971E
-M9"X`1&5V:6-E("5X+R5X(')E;6]V960N`$1E=FEC92`E>"\E>"!R96UO=F5D
-M+@!$979I8V4@)7@@<&]W97)E9"!U<"X`<W1A<G0@4T53(&1E=FEC92`E<`!&
-M;W5N9"!315,@1&5V:6-E("5X`$9A:6QE9"!T;R!V97)I9GD@8V]N=')O;&QE
-M<@!O9&EN(')E860@=W)I=&4@97AC965D<R`E>`!O9&EN`$1E=FEC92`E>"\E
-M>"!R96UO=F5D+@!2971R>6EN9R!F86EL960L(&1I<VL@9&]W;C\_/P!W;W)K
-M<F]U;F0@:7)Q4W1A='5S(#T@,'@E>`!297$@)7`@)7@@)7@`3W9E<G)A;&P@
-M4T<@:71E;2`E>"!S:7IE("5X`%-L;W0@8G5S>2P@<VQO="`E>"@E>"D`1'5M
-M<"!S;&]T(&EN9F\Z("5X("5X("5X("5X`$-L96%N('5P('-L;W0@)7@`1#)(
-M($9)4SH@)3`X>"`E,#AX("4P.'@@)3`X>``E,#)X("4P-'@Z)3`T>#HE,#1X
-M`%)E<2`H)7@I('=A:70@9F]R(&-O;7!L971E9"X`1&5V:6-E("5X+R5X(')E
-M;6]V960N`$1E=FEC92`E>"\E>"!R96UO=F5D+@!$979I8V4@)7@@<&]W97)E
-M9"!U<"X`<W1A<G0@4T53(&1E=FEC92`E<`!&;W5N9"!315,@1&5V:6-E("5X
-M`$9A:6QE9"!T;R!V97)I9GD@8V]N=')O;&QE<@!O9&EN(')E860@=W)I=&4@
-M97AC965D<R`E>`!O9&EN`')A=R`E<"!B861?<V5C=&]R("5X`%=R:71E(&)A
-M8VMU<&5D(&UE=&$@9&%T80!&86EL960@=&\@<W!I;F1O=VX@9&5V:6-E<P!&
-M86EL960@=&\@9FQU<V@@=&%R9V5T<P!!=71O(%)E8G5I;&0`4F5B=6EL9"!0
-M<FEO<FET>0!#;VYT:6YU92!296)U:6QD:6YG(&]N($5R<F]R`%-P:6YD;W=N
-M($ED;&4@1&ES:R`H;6EN=71E<RD`4W1A9V=E<F5D('-P:6YU<```````````
-M```````````````````````````````&!`4!`P)28A4`````````!@0%`0,"
-MV&"?-CD\``````8$!0$#`B!@D%!2```````&!`4!`P+88)````````````$"
-M`Q`$!08'$0@)"@L2#`T.#Q,4%187)!@9&ALE'!T>'R8@(2(C)P``````````
-M`````````````````````*L!````````(0```("<`0"@NP$`T)P!`)#6`0"@
-M\0$`<+L!`'"<`0`@G@$`D+H!`."<`0`P]`$`H)X!`&#;`0``````L+<!`/"<
-M`0"0ZP$`D+(!`+"K`0#PJ0$`,)\!`###`0!0GP$`@*L!`%"K`0!`J@$`$*$!
-M`#"@`0```````````+">`0`PZ0$`<.4!`(#A`0"@W0$```````,14`<`````
-M``(``````````````0````````````````````8$!0$#`E)B%0`````````&
-M!`4!`P+88)\V.3P`````!@0%`0,"(&"04%(```````8$!0$#`MA@D```````
-M``!;`P```````"$```"0D0,`$+$#`."1`P!@S`,`8.<#`."P`P"`D0,`,),#
-M``"P`P#PD0,``.H#`+"3`P`PT0,``````""M`P``D@,`4.$#``"H`P`@H0,`
-M<*`#`#"5`P"@N`,`4)4#`/"@`P#`H`,`\)\#`!"7`P`PE@,```````````#`
-MDP,`\-X#`##;`P!`UP,`8-,#```````#$8!R```````"``````````````$`
-M```````````````````!`?\"````````````````````````````````````
-M```````!`````````!@`````````+````!0```#0#P0`<#$$```/!```````
-M`````)`"!`"0#@0`4`,$````````````````````````````````````````
-M``````````#_``#P100``````&"!!``!`````?\``%!&!```````$(`$``$`
-M```"_P``<$8$```````@E00``0````/_``#01@0``````&"-!``!````-?\`
-M`/!&!```````\'X$``$````$_P``T$<$``````"@>`0``0````7_```P2`0`
-M`````+#T!``!````!O\``.!*!`!PAP0`\&<$```````'_P``,.4$``"&!`"P
-M9@0```````K_``#03@0``````)!T!``!````"_\``/!.!```````T.$$````
-M```,_P``(%($`."%!`!P9@0```````W_``"04@0`P(4$`#!F!```````#O\`
-M``!3!`!PA00`\&4$```````/_P``P%,$`."$!`"P900``````!#_```P5`0`
-MP(0$`'!E!```````$?\``"!5!```````\&0$```````2_P``D%4$``````"P
-M9`0``````!/_``"P500``````!#K!``!````-/\``-!5!```````<.\$``$`
-M```8_P``\%4$```````PC`0``````$+_``"@5@0``````!",!```````&?\`
-M`&!/!```````,.$$```````:_P``T$\$``````#0X`0``````!W_``!05P0`
-M`````'!D!```````'O\``,!7!```````L.8$``$````?_P``4%@$`%"$!``P
-M9`0``````"#_````3`0`,(<$`+!G!```````(?\``'!(!```````T/($``$`
-M```B_P``L%0$```````P900``````"/_``!`4`0``````$#@!```````)/\`
-M`+!0!```````L-\$```````E_P``(%$$``````!0WP0``````"G_``!0300`
-ML(8$`#!G!```````*O\``)!1!```````0-`$```````K_P``X%@$`""$!`#P
-M8P0``````"S_``!@200``````%!W!``!````+?\``$!*!`"PAP0`,&@$````
-M```N_P``L$@$````````\`0``0```"__``"01@0``````'"3!``!````2?\`
-M`+!&!```````0'\$``$````W_P``\$@$````````R@0``0```#C_``"P3`0`
-M\(8$`'!G!```````.?\``!!.!`!PA@0`\&8$```````Z_P``P$D$``````"@
-M=@0``0```#O_``#0600``````%",!``!````//\```!(!```````\'<$``$`
-M```]_P``$$<$``````!0?@0``0```#[_```P1P0``````&!]!``!````0_\`
-M`%!'!```````<'P$``$```!$_P``<$<$``````"`>P0``0```$;_``"01P0`
-M`````(!Z!``!````1_\``+!'!```````H'D$``$````R_P``$$8$``````#0
-MC00``0```#/_```P1@0`\(<$`&"`!```````9/\``$!9!```````H',$``$`
-M```P_P``<%D$``````!0<00``0```&;_``"P2P0``````&!U!``!````9_\`
-M`)!+!```````('8$``$```!%_P``T%H$``"$!`"P8P0``````$C_``"`6P0`
-MX(,$`'!C!```````_____P````````````````````````````````!'0T,Z
-M("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'
-M0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=
-M``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"
-M4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R
-M965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@
-M6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A
-M<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E
-M;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R
-M97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q
-M('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P
-M.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P
-M,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR
-M(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N
-M,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I
-M(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'
-M3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z
-M("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'
-M0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=
-M``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"
-M4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R
-M965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@
-M6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A
-M<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E
-M;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R
-M97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q
-M('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P
-M.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P
-M,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR
-M(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N
-M,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I
-M(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'
-M3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'0T,Z
-M("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=``!'
-M0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"4T1=
-M``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R965"
-M4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@6T9R
-M965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A<V4@
-M6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E;&5A
-M<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R97)E
-M;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q('!R
-M97)E;&5A<V4@6T9R965"4T1=``!'0T,Z("A'3E4I(#0N,BXR(#(P,#<P.#,Q
-M('!R97)E;&5A<V4@6T9R965"4T1=```N<WEM=&%B`"YS=')T86(`+G-H<W1R
-M=&%B`"YR96PN=&5X=``N<F5L+G)O9&%T80`N<F]D871A+G-T<C$N-``N<F]D
-M871A+G-T<C$N,0`N<F5L+F1A=&$`+F)S<P`N8V]M;65N=```````````````
-M`````````````````````````````````````````!\````!````!@``````
-M``!`````U30%````````````$``````````;````"0``````````````Y-T%
-M`#"9```,`````0````0````(````*0````$````"`````````"`U!0`<&0``
-M```````````@`````````"4````)```````````````4=P8``!\```P````#
-M````!`````@````Q`````0```#(`````````/$X%`%P,``````````````0`
-M```!````0`````$````R`````````)A:!0`J!``````````````!`````0``
-M`%,````!`````P````````#@7@4`F`<`````````````(`````````!/````
-M"0``````````````%)8&`,@&```,````!P````0````(````60````@````#
-M`````````(!F!0`@!0`````````````@`````````%X````!````````````
-M``"`9@4`4`<``````````````0`````````1`````P``````````````T&T%
-M`&<```````````````$``````````0````(``````````````&AP!0"`+0``
-M#0```'4"```$````$`````D````#``````````````#HG04`^S\`````````
-M`````0```````````````````````````````````````````````P`!````
-M``````````````,``@`````````````````#``,``````````````````P`$
-M``````````````````,`!0`````````````````#``8`````````````````
-M`P`'``````````````````,`"``````````````````#``D`````````````
-M`````P`*``````````````````,`"P`````````````````#``P`````````
-M`````````P`-``$```#``0$`EP````(``0`5````L`(``#H````"``$`(P``
-M`(`&`0"8`@```@`!`#8`````$@``=`````(``0!$`````!D```D&```"``$`
-M9````*!!`0`)`P```@`!`'L````@^@``$P````(``0"*````L/4``.$````"
-M``$`HP```!!\`0!4`````@`!`*\```#`AP$`)P````(``0#+````H``!`!P!
-M```"``$`VP```%````!:`@```@`!`/8```"@>0``\P````(``0`0`0``,`H`
-M`"4````"``$`)@$``'!\`0!7`````@`!`#<!``!0HP``(`0```(``0!4`0``
-M0.D``(T````"``$`;0$``$`)``";`````@`!`($!``!@"@``(`````(``0"A
-M`0``H&\!`$@````"``$`L0$``$`?``"6#````@`!`,P!``!PE@$`=0````(`
-M`0#9`0``<`4``&,````"``$`]P$``%"'`0`E`````@`!`!("``#P?`$`%P``
-M``(``0`K`@``T*P``"L````"``$`1@(``$`#``!+`````@`!`%8"``#0D@$`
-MY@(```(``0!H`@``8*P``#\````"``$`@P(``*#^``!8`````@`!`),"``#`
-MU```H0````(``0"O`@``0*@```8!```"``$`S`(``("5``!2`0```@`!`.T"
-M``!`^P``IP````(``0`#`P``\)0``(,````"``$`'@,``"">``#_`````@`!
-M`$8#``"`B0$`FP````(``0!F`P``$-,``*P!```"``$`>0,``/"9```$`0``
-M`@`!`)L#``"@B@$`*0````(``0"^`P``()@``$@!```"``$`W@,``*"!`0`Y
-M`0```@`!`/H#```@T@``X0````(``0`0!```H,8``&<#```"``$`*`0``+0+
-M```;`````0`#`#,$``!@`@$`(0$```(``0!"!```0'0``!L````"``$`7@0`
-M`-!'`0`-!````@`!`'4$``#@LP``.`````(``0")!```8'4!`%<````"``$`
-MF@0``,!'``#)`````@`!`+P$``#0?`$`&`````(``0#4!```D.4``#D````"
-M``$`]`0``-#A```@`````@`!``T%``!@=@$`1P4```(``0`=!0``$'8!`$@`
-M```"``$`+P4``'!5`0"I`````@`!`$0%```0X```&P$```(``0!=!0``@(@`
-M`$4"```"``$`?04``""``0`C`````@`!`(H%``#`<P``?`````(``0"H!0``
-M\`,``!`````"``$`N04``#`%```S`````@`!`,T%``!PU0``9`$```(``0#>
-M!0``@&L!`$T````"``$`[04``*`*``!?`````@`!``$&``#0B@``PP4```(`
-M`0`6!@``H)$``%X````"``$`*P8``&`,```Q`0```@`!`#\&````RP``U```
-M``(``0!C!@```````#H````"``$`@08``#`3``!I`````@`!`)@&``!`W```
-MM@(```(``0"J!@``(.4``&T````"``$`N08``&#D``"X`````@`!`-0&````
-M=`$`5P````(``0#D!@``8````(`````!``D`Z@8``'"G``!R`````@`!``<'
-M``#`>P``M`P```(``0`B!P``T(X!`&X!```"``$`4`<``(`&``!A`@```@`!
-M`&T'``"`RP$`F@````(``0!]!P``P'4!`$(````"``$`D`<``#"L```K````
-M`@`!`*L'```@,0``Z`,```(``0#+!P``<+\!`+L#```"``$`Y@<``""B```J
-M`0```@`!``L(````"P``6@````(``0`>"`````0``!X````"``$`,0@``#"M
-M```K`````@`!`$8(``#0KP``20````(``0!7"```<,```*,````"``$`>0@`
-M`-#I``!\"0```@`!`(H(``#0+0``3`,```(``0"B"```L&P``!`'```"``$`
-MP`@``!"R```N`````@`!`-P(```0-0``_`@```(``0#\"```X+4``$`````"
-M``$`$0D``%!1`0#X`0```@`!`"8)``!@7```8`,```(``0`]"0```)(``&<`
-M```"``$`6@D``$`$`0#8`````@`!`'4)``#`T0``+0````(``0","0``H+4`
-M`$`````"``$`I`D``""Q```Q`````@`!`+T)````;P$`.P````(``0#-"0``
-M\`@``$<````"``$`V0D``(#A```J`````@`!`/,)````O0``G`````(``0`.
-M"@``0,X``%4!```"``$`)0H``""*`0!Q`````@`!`$@*````@`$`'P````(`
-M`0!<"@``,`8``$(````"``$`<`H```"M```A`````@`!`(H*``#PX0``+0``
-M``(``0"B"@``H*P``"L````"``$`NPH``-`7```P`0```@`!`-H*``!@#P``
-M%@$```(``0#G"@``H!,``#X"```"``$`!`L```#_``#6`````@`!`!H+```@
-MAP$`)@````(``0`W"P``D`,!`*T````"``$`3`L``)"Z``!-`````@`!`&@+
-M``!PT0``4`````(``0"`"P``X&P!`!L"```"``$`D0L``!"\``#E`````@`!
-M`*T+```@B0$`4P````(``0#3"P``@!(``!L````"``$`[@L``)"[``!W````
-M`@`!`!,,```@M@``%P,```(``0`H#```(,$```(!```"``$`20P``."Q```J
-M`````@`!`&4,``#@#P$`[`8```(``0![#```,%`!`!(!```"``$`D@P``("=
-M`0"5`````@`!`*0,``!@L0``*@````(``0"Z#```()\``&$!```"``$`T0P`
-M`/`^`0"E`@```@`!`.,,``#@*P``[@$```(``0#_#```P*L``#`````"``$`
-M#PT``,#X``!R`````@`!`"T-``#`6@``R@````(``0!*#0``<)(``.<````"
-M``$`:@T``,"%`0`^`0```@`!`'L-``!PM```2`````(``0"4#0``$"0!`*4`
-M```"``$`J`T``##A``!%`````@`!`+\-``#P#0``<`$```(``0#1#0``@!``
-M`%$````"``$`Z`T``%"M`0`[!0```@`!``,.``!PF0``?0````(``0`7#@``
-MT,\``!L!```"``$`*@X``"`$``!5`````@`!`#D.```0/@``JPD```(``0!1
-M#@``0)$``%X````"``$`>PX``/"'`0`D`0```@`!`)X.``#`@P$`20$```(`
-M`0"Y#@``(+\``$P!```"``$`W`X``*`$``!I`````@`!`/`.``"@D```E0``
-M``(``0`6#P```*\``-`````"``$`,`\``'`L`0```@```@`!`$\/``#P;P$`
-MCP````(``0!A#P``X$L!`$4$```"``$`=@\``*!A`0#D"````@`!`),/``"P
-M1`$`$0,```(``0"L#P``(,P!`&@*```"``$`NP\``)`N`0"$"0```@`!`-@/
-M````WP``#@$```(``0#P#P``\*L``#0````"``$`!!```'#B``"*`````@`!
-M`"$0```@X@``2`````(``0`U$```8*H``)@````"``$`1!```""P``#V````
-M`@`!`%80``#@@@$`U@````(``0!Q$```\-$``#`````"``$`A1```+#A```7
-M`````@`!`)L0``"`$0``>P````(``0"]$```H/8``*L!```"``$`TA```!!]
-M`0#P`@```@`!`.@0``"06P``P0````(``0`%$0``4(`!`$<!```"``$`'!$`
-M`$!O`0!2`````@`!`"T1``#@"0``10````(``0!!$0``4,0``/@````"``$`
-M:1$``$"Y`0#-`````@`!`'X1``#PIP``3`````(``0"?$0``0````!P````!
-M``D`L!$``+`[`0`V`P```@`!`,P1``#P`@``1`````(``0#?$0```*L``"P`
-M```"``$`]Q$``,"<``!3`0```@`!`!P2``"@$@``5@````(``0`\$@``$(<!
-M``8````"``$`5!(``,#Y``!9`````@`!`&`2``#`)`$`J0<```(``0!Y$@``
-M$/4``)T````"``$`CQ(``."6```X`0```@`!`+`2``#@_P``P`````(``0#%
-M$@``(%8!`'0+```"``$`X1(```"9`0!H`P```@`!`/@2``!P+@$`&0````(`
-M`0`2$P``X/P``+4!```"``$`+!,``)`#``!?`````@`!`$`3```09```2`0`
-M``(``0!7$P``0/H``#,````"``$`91,``&"M```K`````@`!`'T3``#P^P``
-MZ`````(``0"1$P``4*D```P!```"``$`K!,```#C``!<`0```@`!`,,3``#@
-MN@``H0````(``0#?$P``(`D!`/0"```"``$`_1,``*#%`0#9!0```@`!`!04
-M``"P>P$`7`````(``0`A%```\&L!`#\````"``$`+A0``&"3```J`0```@`!
-M`%(4``!PY@``+@$```(``0!M%```,)@!`,$````"``$`A10``""T``!$````
-M`@`!`*$4``#@^@``)0````(``0"P%```@`0``!<````"``$`PA0``(!@``"(
-M`P```@`!`-T4````$P``(P````(``0#S%```@(<!`#,````"``$`#A4``*#G
-M```-`0```@`!`"(5```@!0$`L`````(``0`V%0``D*```/`````"``$`4Q4`
-M``"=`0!S`````@`!`&$5``!`D`$`I@$```(``0!X%0``@`H``!T````"``$`
-MBA4``/#0``!R`````@`!`)P5``!`G@$`7@````(``0"M%0``0,,```0!```"
-M``$`UQ4``,`+``"1`````@`!`/05``!0^```:`````(``0`1%@``T%```.()
-M```"``$`*!8``-"*`0#V`P```@`!`#X6``!0V@``X@$```(``0!.%@``X`4`
-M`$$````"``$`918``+"^`0#``````@`!`($6```0!0``$0````(``0"8%@``
-M0````"@````!``<`I18``!`?```M`````@`!`,,6``#0!0$`L`````(``0#7
-M%@``8'0!`%<````"``$`YQ8````````$`````0`)`/D6``"PZ```C0````(`
-M`0`B%P``X!```)4````"``$`01<``*#/```F`````@`!`%$7``!`JP``=0``
-M``(``0!J%P``H'H``!,!```"``$`@Q<``&!H``!0!````@`!`)L7``#@U@``
-M:@,```(``0"Y%P``P`P!`!(#```"``$`TQ<``.`5``#I`````@`!`.D7````
-MK@``\@````(``0``&```D$@``#4(```"``$`%A@``&`+``!:`````@`!`"H8
-M``"0K0``9P````(``0`]&```$+H!`'T````"``$`51@``-#E``"9`````@`!
-M`'`8``"0E```60````(``0"7&```H,P``*`````"``$`OA@``)"Q``!$````
-M`@`!`-D8```PP@``#0$```(``0#\&```8'0``#T%```"``$`'1D``("A``"5
-M`````@`!`#P9```@#`$`E`````(``0!0&0``$(4!`+`````"``$`:QD``%!3
-M`0`4`@```@`!`(<9``"@#0``1`````(``0"9&0``4!P!`+0'```"``$`M!D`
-M`,"T``#9`````@`!`,89``#0%P$`>`0```(``0#9&0```)L``+@!```"``$`
-M`AH``!#*``#A`````@`!`"D:```P;`$`HP````(``0!#&@``L)\!`%(````"
-M``$`6QH```"'`0`&`````@`!`',:``!`^0``<@````(``0"1&@``0,T``/4`
-M```"``$`IAH``#"K```"`````@`!`+L:``#@RP``L0````(``0#=&@``4,4`
-M`$L!```"``$``0```$#X`@"7`````@`!`#8````P"0(`=`````(``0``&P``
-MT/L!`&D````"``$`>P```*#P`@`3`````@`!`!8;``!`HP(`*P````(``0`S
-M&P``$+T"`&<#```"``$`RP```"#W`@`<`0```@`!`$T;``"P8P(`K@8```(`
-M`0!M&P``X(\"`'T````"``$`@QL``$!8`P#D"````@`!`*(;```PWP(`C0``
-M``(``0#-&P``,*L"`-D````"``$`)@$``.!S`P!7`````@`!`.$;``#@G0(`
-M<@````(``0``'```T'H#`#X!```"``$`$QP``+"5`P!2`````@`!`"T<``#`
-M3`,`=`L```(``0!+'```8%\"`%`$```"``$`91P``(#9`@!<`0```@`!`*$!
-M```@9@,`2`````(``0#,`0``@(L#`'4````"``$`?AP``!".`P!H`P```@`!
-M`)<<``!PHP(`(0````(``0"S'```T$8#`!(!```"``$`S!P``,#Z`0!?````
-M`@`!`.(<``#@:@(`&P````(``0``'0``H/P!`&,````"``$`(!T``$"F`@!)
-M`````@`!`#,=```03`,`J0````(``0!*'0``@*@"`"X````"``$`:!T``)`!
-M`@`@`````@`!`(H=``!@H@(`-`````(``0"@'0``X(<#`.8"```"``$`@P(`
-M`"#U`@!8`````@`!`+0=``#@?P,`]@,```(``0#,'0```*0"`&<````"``$`
-MX1T``"`%`@!P`0```@`!`,P"``#PBP(`4@$```(``0#M`@``P/$"`*<````"
-M``$`]1T``*`"`P"4`````@`!``,#``!@BP(`@P````(``0`+'@``8'0#`!<`
-M```"``$`'@,``)"4`@#_`````@`!`"8>``#@/@(`R0````(``0!*'@``D`("
-M`%H````"``$`8!X``/!'`P#X`0```@`!`"@$``#@%P``(`````$``P`S!```
-MX/@"`"$!```"``$`=QX``)#(`@#A`````@`!`(\>``!0S0(`:@,```(``0"O
-M'@``8)`"``0!```"``$`TQX``/!)`P`4`@```@`!`/$>``#PW`(`+@$```(`
-M`0")!```0&P#`%<````"``$`#A\``,"?`@`,`0```@`!`"L?```@$`(`"08`
-M``(``0!-'P```+("`'<````"``$`?04``,!U`P`E`````@`!`'0?``#@QP(`
-M4`````(``0".'P``D*H"`$0````"``$`K!\```"+`@!9`````@`!`-4?``"P
-M"0(`&P````(``0#R'P``8`$"`"4````"``$`U`8``.!J`P!7`````@`!`.0&
-M``!@`0``@`````$`"0`*(```L,,"`/X````"``$`(2```!"(`@!>`````@`!
-M`#@@``!@#@,`>`0```(``0!-(```8/T!`$(````"``$`;0<``%#!`P":````
-M`@`!`&,@````?0,`)`$```(``0"((```,),"`%,!```"``$`KR```,"[`@!+
-M`0```@`!`-0@``"04@(`P0````(``0#S(```<*4"`-`````"``$`#R$``&`*
-M`@!I`````@`!`"@A``#0`0(`7P````(``0`^(0``X,L"`&0!```"``$`42$`
-M`##W`0`Z`````@`!`'$A``!`<`(`\P````(``0"]"0``H&4#`#L````"``$`
-MC2$``!"'`@"5`````@`!`+4A``"P!P(`40````(``0#.(0``D'X#`)L````"
-M``$`V0D```#8`@`J`````@`!`/`A``!`*`(`Z`,```(``0`2(@``L'8#`#D!
-M```"``$`,"(``#`L`@#\"````@`!`%(B``"PN0(`!`$```(``0!^(@``D)@"
-M`"H!```"``$`I2(``-`)`@!6`````@`!`,<B``#@M`,`NP,```(``0!("@``
-MD'4#`"$````"``$`Y"(````C`@#N`0```@`!``(C```0"`(`E0````(``0"B
-M"@``$*,"`"L````"``$`(R,``/!W`P#6`````@`!`$`C```P[`(`X0````(`
-M`0!;(P``0`,#`"(#```"``$`V@H``)`&`@`6`0```@`!`'<C```P-0(`JPD`
-M``(``0"1(P``,-@"`!<````"``$`J2,``)!\`P`S`````@`!`,8C``!@G@(`
-M3`````(``0#I(P``(&(#`$T````"``$`^B,``%"L`@!``````@`!`!$D```@
-M<P,`7`````(``0"`"P``@&,#`!L"```"``$`("0``/#8`@"*`````@`!`#\D
-M```0PP(`H`````(``0!H)```T&(#`*,````"``$`A"0``'"[`P#9!0```@`!
-M`)TD``"PT@(`R`(```(``0"Q)```D+4"`$P!```"``$`UB0``/!U`P"W````
-M`@`!`.\D``#`[P(`<@````(``0`/)0``H*,"`"L````"``$`)B4``+`!`@`=
-M`````@`!`#HE``"`]0(`U@````(``0!2)0``\&P#`$@````"``$`9B4``"#[
-M`0`0`````@`!`'DE``"`0@,`100```(``0"0)0``X/D!`#H````"``$`D@P`
-M`)"2`P"5`````@`!`+H,``"0E0(`80$```(``0"@)0``$",#```"```"``$`
-MT0P``)`U`P"E`@```@`!`,$E``!PD0(`N`$```(``0#L)0``4*H"`#@````"
-M``$``B8``&#\`0`S`````@`!`!@F```0^@(`K0````(``0`O)@``0'$"`!,!
-M```"``$`2B8```#]`@"8`@```@`!`%\F``"`R0(`K`$```(``0!T)@``P+H"
-M`/@````"``$`GB8``+#$`@!5`0```@`!`+<F``#0IP(`*@````(``0#/)@``
-M<(@"`&<````"``$`40X``+"'`@!>`````@`!`.XF``#P1P(`R`D```(``0`'
-M)P``<`8#`.P&```"``$`'R<``%#@`@!\"0```@`!`#(G```P?`,`)@````(`
-M`0!1)P``$`$"`$4````"``$`9R<``#`E`P"$"0```@`!`(8G``"@N`(`#0$`
-M``(``0"K)P``H/\"`/0"```"``$`3P\``'!F`P#C`````@`!`,LG``"0I@(`
-M]@````(``0#?)P``T*`"`)@````"``$`K`\``/#!`P!H"@```@`!`/`G``#@
-M$@,`Q`<```(``0`-*```X-H"`+@````"``$`*B@``+#[`0`7`````@`!`#XH
-M``"0U@(`&P$```(``0#8#P``@-4"``X!```"``$`62@````-`@#I`````@`!
-M`'$H``#@J@(`2`````(``0",*```<``"`)L````"``$`HB@``##[`0`>````
-M`@`!`+<H``#0?`,`)P````(``0#5*```,'\#`'$````"``$`^B@``(!T`P`*
-M`0```@`!`!P1``#@90,`.@````(``0`2*0``H-@"`$@````"``$`*"D``."(
-M`@#G`````@`!`$HI``!@<@(`Z`P```(``0!G*0``8!L#`*D'```"``$`@BD`
-M`&#'`@!R`````@`!`)8I```P%@(`+0````(``0!I$0``L*X#`,T````"``$`
-MMBD```!K`@`]!0```@`!`-DI``#0HP(`*P````(``0#S*0``(/H!`$0````"
-M``$`""H``."#`P!N`0```@`!`#@J```PR`(`+0````(``0!1*@``H*$"``(`
-M```"``$`5!(``$#P`@!9`````@`!`&@J``"P/P(`-@@```(``0"/$@``4(T"
-M`#@!```"``$`@"H``"#>`@`-`0```@`!`)8J```@[0(`JP$```(``0"M*@``
-MT`H"`"0"```"``$`L!(``&#V`@#``````@`!`,PJ``!@:@(`?`````(``0#X
-M$@``$"4#`!D````"``$`["H``)#K`@"=`````@`!``0K``!0?P(`10(```(`
-M`0`F*P``T.X"`&@````"``$`12L``%`[`P`1`P```@`!`&`K``"P?P,`*0``
-M``(``0!7$P``P/`"`#,````"``$`A2L``+`(`@![`````@`!`*DK``#P`@(`
-MD0````(``0##$P``4+$"`*$````"``$`R"L``/"7`@"5`````@`!`.DK``!`
-M[P(`<@````(``0`)+```D`,"`#$!```"``$`'RP``!"L`@!``````@`!`#DL
-M``!PP0(`U`````(``0!?+```4/L!`%4````"``$`(10``)!B`P`_`````@`!
-M`'`L``"0IP(`,0````(``0"++```$'P#``8````"``$`I2P``$`X`P`)`P``
-M`@`!`+XL```06P(`2`0```(``0!M%```0(T#`,$````"``$`URP``(!S`P!4
-M`````@`!`.4L```@>@,`L`````(``0"A%```8/$"`"4````"``$``BT``$#\
-M`0`1`````@`!`!LM``#0>`,`20$```(``0`X+0``<*$"`"P````"``$`4BT`
-M``"H`@!$`````@`!`&\M``!@\P(`M0$```(``0"++0``,`("`%H````"``$`
-MH"T``'"D`@#R`````@`!`-T4```P"@(`(P````(``0"Y+0``0&T#`-,%```"
-M``$`RRT``%#<`@"9`````@`!`.@M````L0(`30````(``0`&+@``<#X#``T$
-M```"``$`'RX``)".`@!(`0```@`!`"(5``"@^P(`L`````(``0`V%0```)<"
-M`/`````"``$`4Q4``!"2`P!S`````@`!`$$N``"0K`(`%P,```(``0!8+@``
-M<+,"`)P````"``$`=2X``,#Z`@#8`````@`!`)(N``#`40(`R@````(``0"Q
-M+@``8!8"`)8,```"``$`G!4``%"3`P!>`````@`!`,XN```PH@(`,`````(`
-M`0#@+@``@/<!`%H"```"``$`_2X``##+`@"A`````@`!`!LO```0W`(`.0``
-M``(``0`]+P``L*$"`'4````"``$`6"\``*!L`P!"`````@`!`&TO``!PV`(`
-M+0````(``0`^%@``P-`"`.(!```"``$`AR\``%`R`P`V`P```@`!`&46```@
-MM`,`P`````(``0"E+P``H-L"`&T````"``$`MB\``,#?`@"-`````@`!`-$O
-M``!0V`(`(`````(``0#L+P``T`0"`$0````"``$`PQ8``%#\`@"P`````@`!
-M```P```@``(`1P````(``0`.,```,'X#`%,````"``$`UQ8``$!K`P!7````
-M`@`!`.<6`````0``!`````$`"0!!%P``$,8"`"8````"``$`-C```!#]`0!!
-M`````@`!`$\P``"`5P(`B`,```(``0!L,```T(D"`"H!```"``$`DC```+">
-M`@`&`0```@`!`+$P``"P_0$`80(```(``0#0,```X+8"`*,````"``$`]#``
-M`+#7`@!%`````@`!``TQ``!`=`,`&`````(``0`G,0``@,`"`.$````"``$`
-M4#$``&!3`@!@`P```@`!`&DQ``"@@0(`;04```(``0"`,0``0`$``!P````!
-M``D`DS$``("R`@#E`````@`!`+$Q```@?`,`!@````(``0`]&```@*\#`'T`
-M```"``$`RS$``*"B`@`K`````@`!`.@Q``#`F0(`(`0```(``0`',@``\"0"
-M`$P#```"``$`(3(``$#&`@`;`0```@`!`#8R``!P\@(`Z`````(``0!,,@``
-MD+<"``(!```"``$`;S(``&!\`P`E`````@`!`(PR``!@R`(`,`````(``0"B
-M,@``L!H#`*4````"``$`N#(``,"B`P`[!0```@`!`-4R``!0P@(`L0````(`
-M`0#Y,@``</H!`$L````"``$`"S,``/`.`@`P`0```@`!`"PS``!0A0,`I@$`
-M``(``0!%,P``T*("`#\````"``$`8C,``%"H`@`J`````@`!`(`S```@-`4`
-M50````(``0".,P``$`<$`)H````"``$`GC,``(`7!`!Z#0```@`!`+@S``"P
-M)`4`R@D```(``0#(,P``X"\$`(D````"``$`V#,```@"```$`````0`)`.@S
-M``!`!00`#P````(``0#],P``0"@$`#4"```"``$`$C0``&`>!0!4`````@`!
-M`"HT``!!`@```0````$`!P`Z-```,$($`)P````"``$`2C0``!`6!0`.`0``
-M`@`!`%LT```@%P4`E`````(``0!O-```0!\%`)@"```"``$`A30``%`X!``E
-M`0```@`!`)LT```,`@``!`````$`"0"I-```H!4%`&\````"``$`P30``$#N
-M!`"'`````@`!`-`T```@7P0`00````(``0#B-```D/P#`#T!```"``$`]30`
-M`(`Y!`"D`0```@`!``TU```0[P,`2P````(``0`A-0``@"H$`&X"```"``$`
-M-34``-`F!`!;`````@`!`$,U``#@`P0`J@````(``0!8-0``D`D$`%D````"
-M``$`:34``)`#!`!$`````@`!`(`U```4`@```0````$`"0"4-0``@"T$`%\`
-M```"``$`KS4````E!`#"`0```@`!`,,U``#P+`0`@P````(``0#3-0``8/`#
-M`"0````"``$`W#4``(#M`P"(`````@`!`/@U``#@(04`]P````(``0`.-@``
-M\!,$`!L#```"``$`(38``*`2!0`Z`````@`!`"HV``"`-`4`50````(``0`X
-M-@``,!($`+8!```"``$`5#8``!!>!`#X`````@`!`%\V````8@0`L`````(`
-M`0!U-@```)X$``\!```"``$`AS8``#!A!`#/`````@`!`*`V``!`!P4`2P``
-M``(``0"Q-@``8#,$`$(````"``$`O#8``!`)!0")!````@`!`,TV``"P!00`
-M?`````(``0#B-@``P!0%`-(````"``$`\38``!#U`P#<`````@`!``0W````
-M[0,`$P```!(``0`K-P``&`(```$````1``D`0#<`````````````$````%<W
-M````-`4`$@```!(``0!N-P`````````````0````@3<```#P`P`G````$@`!
-M`),W``#P,@4`.0```!(``0"B-P``T/T#`.8!```2``$`N3<``(#S`P!J````
-M$@`!`-`W`````````````!````#H-P``@#,%`%H````2``$``3@``&#M`P`1
-M````$@`!`!@X````_`,`BP```!(``0`O.``````````````0````2C@``+#Q
-M`P!7````$@`!`%DX`````````````!````!@.```$/(#`,8````2``$`<S@`
-M`*#O`P`E````$@`!`(HX``#@]@,`'````!(``0">.```4``$`%<!```2``$`
-MM#@``,`7!0!:`@``$@`!`-$X```0`@``!````!$`"0#H.```(!H%`#4$```2
-M``$``CD`````````````$````!<Y``#P]0,`20```!(``0`M.0``$`@$`%X`
-M```2``$`2#D``!!?!``*````$@`!`&(Y`````````````!````!T.0``,#,%
-M`%`````2``$`B3D````"```$````$0`)`)DY```P!P4`$````!(``0"R.0``
-M,/$#`'D````2``$`QSD``!D"```!````$0`)`-\Y```0H`$`&````!(``0#Z
-M.0`````````````0````!#H``(`&!0"(````$@`!`!LZ`````````````!``
-M```R.@``\/,#`%@````2``$`13H`````````````$````$\Z```$`@``!```
-M`!$`"0!>.@``X/(#`)@````2``$`=CH``%#T`P#`````$@`!`(<Z````7@0`
-M"P```!(``0"?.@`````````````0````MCH``+!B!``O````$@`!`,8Z```7
-M`@```0```!$`"0#B.@`````````````0````]3H`````````````$`````@[
-M``!#`@```0```!$`!P`<.P``D/8#`"(````2``$`03L````/!0!+`P``$@`!
-M`$\[```0E@,`&````!(``0!L.P``P/8#`!D````2``$`B#L`````````````
-M$````*`[``"@#04`50```!(``0"U.P`````````````0````RSL``,`>!0!_
-M````$@`!`.8[``!0$@4`2@```!(``0#Z.P`````````````0````"CP`````
-M````````$````"$\``#@,P4`$@```!(``0`X/``````````````0````2SP`
-M`$#P`P`4````$@`!`&<\```0[@,`P0```!(``0""/```0`(```$````1``<`
-ME3P``"#M`P`+````$@`!`*T\```5`@```0```!$`"0#(/```@"X%`/<"```2
-M``$`Z#P````R!0`#````$@`!``(]```0$`0`Q0$``!(``0`9/0``P/\#`(\`
-M```2``$`+ST``)#P`P`U````$@`!`$@]`````````````!````!?/0``,.T#
-M`"@````2``$`=ST`````````````$````(L]``#0[P,`+````!(``0"A/0``
-MX#$%`!@````2``$`OST``(#Z`P#5````$@`!`-\]`````````````!````#S
-M/0`````````````0````$#X``##P`P`-````$@`!`"H^`````````````!``
-M```]/@``$`8%`&H````2``$`5#X`````````````$````&\^``#0,04``@``
-M`!(``0""/@``D`<%`%L````2``$`ESX``)`$!`"A````$@`!`*\^``"`,04`
-M3P```!(``0#-/@``X.X#`"H````2``$`^SX``$("```!````$0`'`!<_``"P
-M`00`U@```!(``0`N/P``$`<%`!X````2``$`0S\``$#V`P!)````$@`!`&(_
-M`````````````!````!Y/P``(/D#`%0!```2``$`EC\``-#P`P!;````$@`!
-M`*L_``#@$@4`.0$``!(``0#(/P``%@(```$````1``D`XS\``-!"!`"4````
-M$@`!``!035])<W-U95)E861&86EL3&5D`'(W-3!?5&%G7TEN:70`<C<U,%]5
-M<&1A=&50:'E);F9O`'-A<U]H87-H7V%D9'(`<C<U,%]697)I9GE#;VUM86YD
-M0F5F;W)E4V5N9&EN9P!R-S4P7T-H96-K1&5V:6-E0VAA;F=E`$UA:V5!='1$
-M979);F9O`'(W-3!?1$E30U]#86YC96Q$:7-C;W9E<@!R-S4P7T)E97!/;@!R
-M-S4P7U-#4TE?051!7T9I;&Q$871A1FEE;&0`4$U?5W)I=&5296=3>6YC`'(W
-M-3!?4T-325]-86ME0V%C:&5#;VUM86YD`'(W-3!?0T]215])<W-U95--4%)E
-M<75E<W0`<C<U,%]-5E]:97)O379297%U97-T`&DR8T%?=W)I=&5?8GET97,`
-M<C<U,%]315-?26YT97)N86Q297%#86QL8F%C:P!R-S4P7TES<W5E7U)E<&]R
-M=$=E;F5R86P`<C<U,%]-5E]$=6UP4F5Q=65S=`!R-S4P7TU67TEN:71I86QI
-M>F5487)G971)1%1A8FQE`'-E=%]P;5]F86EL7VQE9`!R-S4P7U!R97!A<F5!
-M;F1396YD0V]M;6%N9`!/9&EN4U!)7U)D<'0`<C<U,%]-5E]-87!4;U-P96-I
-M9FEC5&%R9V5T240`<C<U,%]30U-)7T%405]&:6QL3$)!0V1B,3``<C<U,%]3
-M1U!)3U]7<FET95)E9VES=&5R`'(W-3!?1G)E95-!5$%38W)A=&-H5&]0;V]L
-M`'(W-3!?5&%G7T=E=$]N90!R-S4P7T]D:6Y34$E?26YI=`!R-S4P7T9R965)
-M;G1E<FYA;%)E<51O4&]O;`!W871I;F=?8V%L;&)A8VL`<C<U,%]#;VUP;&5T
-M95)E<75E<W1!;F13;&]T`'(W-3!?0V]R95]'9713=7!P;W)T961#;W5N=',`
-M1&5V:6-E7TUA:V50<FEV871E4V5N9%-E<U)E<75E<W0`4$U?4V5T1F%I;$QE
-M9$-A;&QB86-K`$%S<VEG;D5L96UE;D1E<V-R:7!T;W).86UE`$1E=FEC95]-
-M86ME4V5S16QE;65N=%-T871U<U)E<75E<W14:6UE<@!R-S4P7U-#4TE?051!
-M7U9E<FEF>51R86YS;&%T:6]N`'(W-3!?7U]R96YE=U]T:6UE<@!R-S4P7T1E
-M=FEC95]-86ME4V5S4F-V1&EA9U)E<75E<W0`<C<U,%]30U-)7T%405]3=&%R
-M=%-T;W!4<F%N<VQA=&EO;@!R-S4P7T1E=FEC95]7<FET95-E<T-O;G1R;VQ$
-M:6%G`'(W-3!?4T=024]?4TU04F5Q=65S=%]7<FET90!R-S4P7T9R965$979I
-M8V54;U!O;VP`<C<U,%]0;W)T7T%B;W)T4F5Q=65S=',`<')O9'5C=%]I9`!0
-M35]296%D4F5G4WEN8P!R-S4P7T-O<F5?36]D=6QE4V5N9%)E<75E<W0`<C<U
-M,%]#:&5C:U1A<F=E=$-H86YG90!R-S4P7T9R9650;W)T5&]0;V]L`&DR8T)?
-M=W)I=&5?8GET97,`<C<U,%]#;W)E7TEN=&5R<G5P=%-E<G9I8V52;W5T:6YE
-M`'(W-3!?4T=024]?4F5A9%)E9VES=&5R`'(W-3!?1$E30U]'971.96=O=&EA
-M=&5D3&EN:U)A=&4`<C<U,%]#86QC=6QA=&52;W5T94EN9&5X`'(W-3!?;V1I
-M;E]I;V-T;`!R-S4P7W-E=%]F86EL7VQE9`!R-S4P7U-44%]$979I8V5297-E
-M=`!R-S4P7T=E=$5X<&%N9&5R1G)O;5!O;VP`<C<U,%]3051!7U!-7TAA;F1L
-M941E=FEC955N<&QU9P!497-T7U!I;E]3970`<C<U,%]#;W)E7TEN=&5R;F%L
-M4V5N9%)E<75E<W0`<C<U,%]486=?27-%;7!T>0!R-S4P7TU67TUA<%1A<F=E
-M=$E$`'(W-3!?7U]A9&1?=&EM97(`<C<U,%]I,F-?<F5S970`<C<U,%]M=E]D
-M:7-A8FQE7VAB80!R-S4P7T-O<F5?4F5Q5&EM96]U=`!R-S4P7T9I;F1!<V-I
-M:4YU;6)E<@!R-S4P7VUV7W-E=%]305-!9&1R`'(W-3!?17AP86YD97)?4TU0
-M4F5Q=65S=%]0:'E#;VYT<F]L`'(W-3!?4T-325]-86ME36]D95!A9V5#86-H
-M:6YG`'(W-3!?0V]R95]297-E=$-M9%-L;W0`<C<U,%]296UO=F5$979I8V4`
-M<C<U,%]&:6YD5&=T3F\`<C<U,%]3=&]R95]#;VYF:6=2;W5T94EN9F\`:3)C
-M05]R96%D7V)Y=&5S`&%I;F9O`'(W-3!?0V]R95]-86ME1&5V:6-E4F5S9712
-M97$`<C<U,%]#;W)E7TUO9'5L94EN:71I86QI>F4`<C<U,%]30U-)7T%405]2
-M96%D0V%P86-I='E4<F%N<VQA=&EO;D-A;&QB86-K`'(W-3!?359?4V5T3$)!
-M86YD4V5C=&]R0V]U;G0`;V1I;E]C;W)E7W1I;65R`'(W-3!?<V5T7V9A:6Q?
-M;&5D<P!R-S4P7T9R965#;W)E0V]N=&5X=%1O4&]O;`!R-S4P7V-O<F5?:&%N
-M9&QE7W1A<VMF:6QE7V5R<F]R`'(W-3!?;V1I;E]S971?<W!I;E]U<%]M;V1E
-M`'(W-3!?4&]S=$UA:V5397-%;&5M96YT4W1A='5S4F5Q=65S=`!R-S4P7VUV
-M7V5N86)L95]X;70`<C<U,%],:7-T7T=E=$9I<G-T`'(W-3!?1G)E95-%4U-"
-M5&]0;V]L`'(W-3!?1V5T4$U$979I8V4`<C<U,%]$979I8V5?36%K94UO9&53
-M96QE8W1297%U97-T`'(W-3!?1&ES8V]V97)Y4TT`<C<U,%]3051!7T5R<F]R
-M2&%N9&QI;F<`<C<U,%]3051!7U!O<G1(86YD;&5);G1E<G)U<'0`<C<U,%]'
-M971#;W)E0V]N=&5X=$9R;VU0;V]L`'(W-3!?4T%37TAA;F1L94-O;7!L971E
-M9$-O;6UA;F0`<C<U,%]&<F5E4F5G:7-T97)3970`<C<U,%]3051!7U!O<G1$
-M971E8W0`<C<U,%]0;W)T7TAA;F1L95!L=6=I;@!R-S4P7T%S<VEG;D5L96UE
-M;G13;&]T3G5M8F5R`'(W-3!?1&5V:6-E7TES<W5E4V]F=%)E<V5T`'(W-3!?
-M7U]035]C86YC96Q?=&EM97(`<C<U,%]035]&<F5E4F5G:7-T97)3970`<C<U
-M,%]'97131T)U9F9E<D9R;VU0;V]L`'-E=%]E;5]F86EL7VQE9`!R-S4P7TU6
-M7T-20P!'9713051!-C1+4V-R871C:$9R;VU0;V]L`'(W-3!?4G5N=&EM94ES
-M<W5E4V]F=%)E<V5T`'(W-3!?1V5T1&5V:6-E1G)O;5!O;VP`<C<U,%]30U-)
-M7T%405]3>6YC0V%C:&54<F%N<VQA=&EO;@!497-T7U!I;E]);FET:6%L:7IE
-M`'(W-3!?359?1V5T36%P<&5D240`<C<U,%]&<F5E4TU04V-R871C:%1O4&]O
-M;`!R-S4P7T9I;F1&<F5E4TU00V]N=&5X=`!&<F5E4T%4038T2U-C<F%T8VA4
-M;U!O;VP`<C<U,%]3051!7U!R97!A<F5#;VUM86YD2&5A9&5R`&UV7W!H>5]R
-M97-E=`!R-S4P7U-!5$%?2&%N9&QE1&5V:6-E56YP;'5G`'(W-3!?4$U?27-S
-M=657<FET95)E9P!R-S4P7U-#4TE?051!7T-H96-K0V]N9&ET:6]N`'(W-3!?
-M4$U?27-S=65296%D4F5G`'(W-3!?1V5T26YT97)N86Q297%&<F]M4&]O;`!R
-M-S4P7T9R965%>'!A;F1E<E1O4&]O;`!S971?96U?9F%I;%]L961S`'(W-3!?
-M4G5N=&EM94ES<W5E4F5A9$QO9T5X=`!R-S4P7U-#4TE?051!7U)E861#87!A
-M8VET>51R86YS;&%T:6]N`'(W-3!?9'5M<%]U;F%S<V]C:6%T961?9FES`'(W
-M-3!?1&5V:6-E7TUA:V53=&%R=%-T;W!5;FET4F5Q=65S=`!R-S4P7T-O;7!L
-M971E4F5Q=65S=`!R-S4P7T1E=FEC95]-86ME36]D95-E;G-E4F5Q=65S=`!R
-M-S4P7T=E=%-!5$%38W)A=&-H1G)O;5!O;VP`<C<U,%]#;W)E7TUO9'5L95-T
-M87)T`'(W-3!?1&ES8V]V97)Y0V%L;$)A8VL`9V5T7VED7V9R;VU?96YC260`
-M<C<U,%]'971315-30D9R;VU0;V]L`%-%4U]0<FEV871E4F5Q0V%L;&)A8VL`
-M4T%37U)E<&]R=$QU;E-C86X`<C<U,%]#;W)E7TAA;F1L95=A:71I;F=,:7-T
-M`'(W-3!?4')E16UP='E030!R-S4P7T=E=$UI;DYE9V]T:6%T961,:6YK4F%T
-M90!R-S4P7U-!5$%?2&%N9&QE1&5V:6-E4&QU9VEN`'(W-3!?1FEL;$5N8VQO
-M<W5R945L96UE;G13=&%T=7,`<C<U,%]30U-)7U1O7T9)4P!R-S4P7T-O<F53
-M879E3W)I9VEN86Q#1$(`<C<U,%]3051!7U!O<G1297-E=`!R-S4P7T=E=$]N
-M94-O;6UA;F13;&]T`'(W-3!?;79?<F5S971?<&AY`'(W-3!?5W)I=&5$14Q6
-M7U%?16YT<GD`<C<U,%]O9&EN7W-E=%]I9&QE7W-T86YD8GD`<C<U,%]315-?
-M4V5T1F%I;$QE9`!R-S4P7T=E=%!-1G)O;5!O;VP`<C<U,%]-5E]%<75A;',`
-M<C<U,%](86YD;&5#;VUM86YD475E=64`07-S:6=N4V5S3W1H97)%;&5M96YT
-M3W9E<F%L;$5L96UE;G1.=6UB97(`<C<U,%]30U-)7T%405]296%D5W)I=&54
-M<F%N<VQA=&EO;@!R-S4P7U--4%]31U!)3U]3971?1F%I;&QE9`!R-S4P7U)U
-M;G1I;65)<W-U95-O9G1297-E=$-A;&QB86-K`'(W-3!?4T=486)L95]!<'!E
-M;F0`<C<U,%]!<W-I9VY$979I8V5/=F5R86QL16QE;65N=$YU;6)E<@!R-S4P
-M7U!-7T%S<VEG;E)E9VES=&5R4V5T`'(W-3!?4T%405]034AO='!L=6=297%#
-M86QL8F%C:P!P;W)T7W-E=%]F86EL7VQE9`!R-S4P7U5P9&%T951G=$1E=DUA
-M<`!R-S4P7U-!4U]);G1E<FYA;%)E<4-A;&QB86-K`'(W-3!?57!D871E5&%R
-M9V5T1&5V:6-E<P!O9&EN7V5M7V%C8V5S<P!R-S4P7U-!5$%?1&5V:6-E4W1A
-M=&5-86-H:6YE`$1E=FEC95]297!O<G1,=6Y297%U97-T`'(W-3!?4')E16UP
-M='E$979I8V4`<C<U,%]$25-#7T-H96-K1&ES8V]V97)3=&%T90!R-S4P7T9R
-M965335!#;VYT97AT`'(W-3!?1V5T3D-15&%G`'(W-3!?4T%44V5N<V5$871A
-M`'(W-3!?4T=024]?4TU04F5Q=65S=%]296%D`'(W-3!?7U]C86YC96Q?=&EM
-M97(`<C<U,%]$25-#7T=E=%)E<V]U<F-E`'(W-3!?0V]R95]P87-S7W1H<G5?
-M9FEL;%]T87-K9FEL90!R-S4P7T1)4T-?1&]$:7-C;W9E<@!R-S4P7U-'4$E/
-M7TEN:71I86QI>F4`<C<U,%]0;W)T7TAA;F1L941E=FEC95!L=6=I;@!R-S4P
-M7U-'4$E/7U-E=%]&86EL;&5D`'-E=%]P;5]F86EL7VQE9',`<C<U,%]-5E]#
-M;W!Y4T=486)L90!R-S4P7T1E=FEC95]-86ME4F5A9$-A<&%C:71Y5&%S:U)E
-M<75E<W0`=7!D871E7V1E=FEC95]C;VYF:6<`<C<U,%]#;W)E7TUO9'5L945N
-M86)L941I<V%B;&5)4E$`<C<U,%]M;V1E4&%G94)U9@!R-S4P7U-!4U]$979I
-M8V53=&%T94UA8VAI;F4`<C<U,%]486=?26YI=%]&249/`'(W-3!?0V]R95]&
-M:6QL4V5N<V5$871A`'(W-3!?4&]S=$UA:V5397-#;VYF:6=U<F%T:6]N4F5Q
-M=65S=`!R-S4P7U-!5$%?4$U?2&%N9&QE1&5V:6-E4&QU9VEN`'(W-3!?4T-3
-M25]!5$%?57!P97)7;W)D`$UA:V5$979);F9O`'(W-3!?4T%405]035-T871E
-M36%C:&EN90!R-S4P7T1)4T-?4V5T4F5S;W5R8V4`1&5V:6-E7TUA:V50<FEV
-M871E4F5C=E-E<U)E<75E<W0`4$U?27-S=657<FET949A:6Q,960`<C<U,%]3
-M051!7U!-26YI=%)E<4-A;&QB86-K`'(W-3!?;V1I;E]F;&%S:%]A8V-E<W,`
-M4T%405]035-T871E36%C:&EN95-P:6Y5<`!R-S4P7U-!5$%?4&]R=$1E=FEC
-M95)E861Y`'(W-3!?5&%G7U)E;&5A<V5/;F4`<C<U,%]305-?17)R;W)(86YD
-M;&EN9P!C:&5C:U]387-!9&1R`'(W-3!?1G)E95-'0G5F9F5R5&]0;V]L`'(W
-M-3!?1&5T96-T4&]R=%1Y<&4`<C<U,%]0;W)T7TES4F5Q=65S=%)U;FYI;F<`
-M<C<U,%]$25-#7T=E=%1G=$1E=DUA<`!$979I8V5?5&5S=%5N:71296%D>5)E
-M<75E<W0`<C<U,%]$979I8V5?4&%R<V5)9&5N=&EF>41A=&$`<C<U,%]D979I
-M8V5?<')O8F5?9&]N90!R-S4P7T)E97!/9F8`9V5T7V9I<G-T7W!M`'(W-3!?
-M57!D871E4W1A='5S5G-397-#;VYT<F]L0G5F9F5R`'(W-3!?27-S=65?0V]N
-M9FEG4F]U=&5);F9O`$]D:6Y34$E?4V5C=&]R56YP<F]T96-T`'(W-3!?0V]R
-M95)E<W1O<F5/<FEG:6YA;$-$0@!S8W-I;'5N7W1O7VEN=`!R-S4P7U-'5&%B
-M;&5?26YI=`!R-S4P7U-!5$%?4$U?17)R;W)(86YD;&EN9P!3051!7TAA;F1L
-M95!-7TAO=%!L=6<`<C<U,%]30U-)7T%405]&:6QL3$)!0V1B,38`<C<U,%])
-M<W-U95]$:7-C;W9E<@!'971!='1)9&5N=&EF>49R86UE`%-%4U1I;65R7TEN
-M=&5R;F%L4F5Q0V%L;&)A8VL`9V5T7V5N8U]C;W5N=`!R-S4P7T-A=&5G;W)Y
-M7T-$0E]4>7!E`'(W-3!?3&ES=%]'971,87-T`'(W-3!?1G)E95!-5&]0;V]L
-M`&=E=%]M:6Y?<&U0871H260`<C<U,%]$979I8V5?36%K95)E861#87!A8VET
-M>3$V5&%S:U)E<75E<W0`<C<U,%]M=E]D:7-A8FQE7W)E9VES=&5R7W-E=`!R
-M-S4P7U-!5$%?4&]R=$1E=FEC941E=&5C=&5D`'(W-3!?4&]R=%](86YD;&55
-M;G!L=6<`<C<U,%]!5$%?0T1",E1A<VM&:6QE`%)E;6]V95-!4T1E=FEC90!R
-M-S4P7TU67U)E;6]V951A<F=E=$E$`&]D:6Y?<V5T7VAA<F1?9&ES:U]I9&5N
-M=&EF>0!R-S4P7U-'5&%B;&5?079A:6QA8FQE`%!O<G1-87!?4C<U,`!R-S4P
-M7U-!5$%?4')E<&%R94-O;6UA;F1486)L90!'971$979)9&5N=&EF>49R86UE
-M`&DR8T)?<F5A9%]B>71E<P!S87-?861D<F5S<U]C;W5N=`!R-S4P7TES<W5E
-M7U)E<&]R=$UA;G5F86-T=7)E<DEN9F]R;6%T:6]N`'(W-3!?4')E<&%R941E
-M;&EV97)Y475E=65%;G1R>0!5<&1A=&5(:6U0871H260`<C<U,%]&:6YD4G5N
-M;FEN9U)E<4)Y5&%G`'(W-3!?0V]R95]-;V1U;&53:'5T9&]W;@!R-S4P7U!-
-M7T-O<F5?4F5Q5&EM96]U=`!R-S4P7T5X<&%N9&5R7U--4%)E<5]#86QL8F%C
-M:P!R-S4P7U5P9&%T95=I9&50;W)T4&AY36%P`'(W-3!?4T%37TAA;F1L94)2
-M1$-35`!R-S4P7T%S<VEG;E)E9VES=&5R4V5T`'(W-3!?4V5R=FEC94EN=&5R
-M<G5P=`!R-S4P7VUV7V1I<V%B;&5?>&UT`'(W-3!?4TU04F5S<$QE;F=T:`!U
-M<&1A=&5?9&5V:6-E7V-O;F9I9U]V,@!R-S4P7TES<W5E7U)E<&]R=%)O=71E
-M26YF;P!R-S4P7U!O<W1-86ME4V5S16YC;&]S=7)E4W1A='5S4F5Q=65S=`!R
-M-S4P7T5X<&%N9&5R7U--4%)E<75E<W1?4F5P;W)T1V5N97)A;`!R-S4P7T=E
-M=%--4%-C<F%T8VA&<F]M4&]O;`!R-S4P7T1E=FEC95]-86ME26YQ=6ER>51A
-M<VM297%U97-T`'(W-3!?0V]R95]-;V1U;&5'971297-O=7)C95%U;W1A`'(W
-M-3!?07-S:6=N1&5V:6-E16QE;65N=$YU;6)E<@!R-S4P7U!O<G1?1FEN9%1G
-M=$YO`'(W-3!?4T=024]?4TU04F5Q7T-A;&QB86-K`'(W-3!?4&]R=%]3;V9T
-M4F5S971#86QL8F%C:P!R-S4P7VUV7W)E<V5T7WAM=`!R-S4P7VUV0VAA;FYE
-M;%-T871E36%C:&EN90!R-S4P7U!O<G1?36]N:71O<@!R-S4P7U-!4U]0;W)T
-M4F5S970`<C<U,%]0;W-T36%K95-E<T5L96UE;G1$97-C<FEP=&]R4F5Q=65S
-M=`!R-S4P7T5X<&%N9&5R7U--4%)E<75E<W1?4F5P;W)T4$A94T%400!R-S4P
-M7TDR0U]-;V1U;&5);FET:6%L:7IE`'(W-3!?;V1I;E]R96UO=F5?9&5V:6-E
-M`'(W-3!?4T-325]!5$%?3&]W97)7;W)D`'(W-3!?1V5T36%X3F5G;W1I871E
-M9$QI;FM2871E`'(W-3!?1V5T4&]R=$9R;VU0;V]L`'(W-3!?359?1'5M<%)E
-M9VES=&5R`'(W-3!?17AP86YD97)?4TU04F5Q=65S=%]$:7-C;W9E<@!R-S4P
-M7T1E=FEC95]-86ME4F5Q=65S=%1A<VM297%U97-T`&1C-S(X,%]31U1A8FQE
-M7T%P<&5N9`!D8S<R.#!?1G)E95-!5$%38W)A=&-H5&]0;V]L`&1C-S(X,%]0
-M;W)T7T%B;W)T4F5Q=65S=',`9&,W,C@P7U-!5$%?4&]R=$AA;F1L94EN=&5R
-M<G5P=`!D8S<R.#!?4T537U-E=$9A:6Q,960`9&,W,C@P7U-!4U]);G1E<FYA
-M;%)E<4-A;&QB86-K`&1C-S(X,%])<W-U95]297!O<G1-86YU9F%C='5R97))
-M;F9O<FUA=&EO;@!D8S<R.#!?4&]R=%]-;VYI=&]R`&1C-S(X,%]#;W)E7TUA
-M:V5$979I8V5297-E=%)E<0!D8S<R.#!?4T-325]4;U]&25,`9&,W,C@P7V]D
-M:6Y?<F5M;W9E7V1E=FEC90!D8S<R.#!?4T%405]034EN:71297%#86QL8F%C
-M:P!D8S<R.#!?4$U?0V]R95]297%4:6UE;W5T`&1C-S(X,%]$25-#7T=E=%1G
-M=$1E=DUA<`!D8S<R.#!?;V1I;E]F;&%S:%]A8V-E<W,`9&,W,C@P7T9R9653
-M35!38W)A=&-H5&]0;V]L`&1C-S(X,%]$:7-C;W9E<GE#86QL0F%C:P!D8S<R
-M.#!?5&%G7U)E;&5A<V5/;F4`9&,W,C@P7T-O<F5?36]D=6QE4V5N9%)E<75E
-M<W0`9&,W,C@P7TU67TUA<%1O4W!E8VEF:6-487)G971)1`!D8S<R.#!?1V5T
-M4$U$979I8V4`9&,W,C@P7U-44%]$979I8V5297-E=`!D8S<R.#!?1V5T0V]R
-M94-O;G1E>'1&<F]M4&]O;`!D8S<R.#!?359?26YI=&EA;&EZ951A<F=E=$E$
-M5&%B;&4`9&,W,C@P7U!R945M<'1Y1&5V:6-E`&1C-S(X,%]/9&EN4U!)7TEN
-M:70`9&,W,C@P7T%405]#1$(R5&%S:T9I;&4`9&,W,C@P7U--4%)E<W!,96YG
-M=&@`9&,W,C@P7VUV7W)E<V5T7W!H>0!D8S<R.#!?4&]R=%]&:6YD5&=T3F\`
-M9&,W,C@P7U-'4$E/7U=R:71E4F5G:7-T97(`9&,W,C@P7T-O<F5?26YT97)R
-M=7!T4V5R=FEC95)O=71I;F4`9&,W,C@P7VUV7V1I<V%B;&5?>&UT`&1C-S(X
-M,%]3051!7U!O<G1$971E8W0`9&,W,C@P7T9R965$979I8V54;U!O;VP`9&,W
-M,C@P7T5X<&%N9&5R7U--4%)E<5]#86QL8F%C:P!D8S<R.#!?1&5V:6-E7TUA
-M:V5397-28W9$:6%G4F5Q=65S=`!D8S<R.#!?4&]R=%]3;V9T4F5S971#86QL
-M8F%C:P!D8S<R.#!?27-S=65?0V]N9FEG4F]U=&5);F9O`&1C-S(X,%]0;W)T
-M7TES4F5Q=65S=%)U;FYI;F<`9&,W,C@P7U9E<FEF>4-O;6UA;F1"969O<F53
-M96YD:6YG`&1C-S(X,%]$979I8V5?36%K95-T87)T4W1O<%5N:71297%U97-T
-M`&1C-S(X,%]&<F5E17AP86YD97)4;U!O;VP`9&,W,C@P7T-O<F5297-T;W)E
-M3W)I9VEN86Q#1$(`9&,W,C@P7U!O<W1-86ME4V5S16YC;&]S=7)E4W1A='5S
-M4F5Q=65S=`!D8S<R.#!?9'5M<%]U;F%S<V]C:6%T961?9FES`&1C-S(X,%]-
-M5E]:97)O379297%U97-T`&1C-S(X,%]'9710;W)T1G)O;5!O;VP`9&,W,C@P
-M7T9I;F1!<V-I:4YU;6)E<@!D8S<R.#!?4T%37U!O<G1297-E=`!D8S<R.#!?
-M359?1V5T36%P<&5D240`9&,W,C@P7U-#4TE?051!7U)E8617<FET951R86YS
-M;&%T:6]N`&1C-S(X,%]0;W-T36%K95-E<T-O;F9I9W5R871I;VY297%U97-T
-M`&1C-S(X,%]$979I8V5?36%K95)E<75E<W1487-K4F5Q=65S=`!D8S<R.#!?
-M4&]R=%](86YD;&5$979I8V50;'5G:6X`9&,W,C@P7U!-7T%S<VEG;E)E9VES
-M=&5R4V5T`&1C-S(X,%]#;W)E7U)E<V5T0VUD4VQO=`!D8S<R.#!?;79?9&ES
-M86)L95]H8F$`9&,W,C@P7U]?861D7W1I;65R`&1C-S(X,%]30U-)7TUA:V5-
-M;V1E4&%G94-A8VAI;F<`9&,W,C@P7T-/4D5?27-S=65335!297%U97-T`&1C
-M-S(X,%]!<W-I9VY$979I8V5/=F5R86QL16QE;65N=$YU;6)E<@!D8S<R.#!?
-M5W)I=&5$14Q67U%?16YT<GD`9&,W,C@P7U-#4TE?051!7U9E<FEF>51R86YS
-M;&%T:6]N`&1C-S(X,%]C;W)E7VAA;F1L95]T87-K9FEL95]E<G)O<@!D8S<R
-M.#!?4T=024]?4TU04F5Q=65S=%]7<FET90!D8S<R.#!?4T%37TAA;F1L94-O
-M;7!L971E9$-O;6UA;F0`9&,W,C@P7T1E=FEC95]-86ME4F5A9$-A<&%C:71Y
-M,39487-K4F5Q=65S=`!D8S<R.#!?4&]S=$UA:V5397-%;&5M96YT4W1A='5S
-M4F5Q=65S=`!D8S<R.#!?4T%405]035](86YD;&5$979I8V50;'5G:6X`9&,W
-M,C@P7V]D:6Y?<V5T7W-P:6Y?=7!?;6]D90!D8S<R.#!?0V]R95](86YD;&57
-M86ET:6YG3&ES=`!D8S<R.#!?4')E<&%R941E;&EV97)Y475E=65%;G1R>0!D
-M8S<R.#!?4T=024]?4TU04F5Q=65S=%]296%D`&1C-S(X,%]$25-#7T-A;F-E
-M;$1I<V-O=F5R`&1C-S(X,%]5<&1A=&57:61E4&]R=%!H>4UA<`!D8S<R.#!?
-M2&%N9&QE0V]M;6%N9%%U975E`&1C-S(X,%]$25-#7T=E=%)E<V]U<F-E`&1C
-M-S(X,%]30U-)7T%405]&:6QL3$)!0V1B,38`9&,W,C@P7T-O<F5?36]D=6QE
-M16YA8FQE1&ES86)L94E240!D8S<R.#!?:3)C7W)E<V5T`&1C-S(X,%]&<F5E
-M4F5G:7-T97)3970`9&,W,C@P7T)E97!/9F8`9&,W,C@P7T1)4T-?0VAE8VM$
-M:7-C;W9E<E-T871E`&1C-S(X,%]%>'!A;F1E<E]335!297%U97-T7U)E<&]R
-M=$=E;F5R86P`9&,W,C@P7TDR0U]-;V1U;&5);FET:6%L:7IE`&1C-S(X,%]D
-M979I8V5?<')O8F5?9&]N90!D8S<R.#!?4F5M;W9E1&5V:6-E`&1C-S(X,%]2
-M=6YT:6UE27-S=653;V9T4F5S971#86QL8F%C:P!D8S<R.#!?4T=024]?4V5T
-M7T9A:6QL960`9&,W,C@P7T=E=$UA>$YE9V]T:6%T961,:6YK4F%T90!D8S<R
-M.#!?1G)E95-%4U-"5&]0;V]L`&1C-S(X,%],:7-T7T=E=$QA<W0`9&,W,C@P
-M7U!-7TES<W5E5W)I=&5296<`9&,W,C@P7W-E=%]F86EL7VQE9`!D8S<R.#!?
-M5&%G7TES16UP='D`9&,W,C@P7U5P9&%T951G=$1E=DUA<`!D8S<R.#!?5&%G
-M7TEN:70`9&,W,C@P7U-!5$%?4$U(;W1P;'5G4F5Q0V%L;&)A8VL`9&,W,C@P
-M7U!O<W1-86ME4V5S16QE;65N=$1E<V-R:7!T;W)297%U97-T`&1C-S(X,%]&
-M<F5E4&]R=%1O4&]O;`!D8S<R.#!?359?36%P5&%R9V5T240`9&,W,C@P7U!-
-M7TES<W5E4F5A9%)E9P!D8S<R.#!?0V]R95]-;V1U;&53:'5T9&]W;@!D8S<R
-M.#!?57!D871E4&AY26YF;P!D8S<R.#!?7U]R96YE=U]T:6UE<@!D8S<R.#!?
-M1&5V:6-E7TUA:V5296%D0V%P86-I='E487-K4F5Q=65S=`!D8S<R.#!?1V5T
-M1&5V:6-E1G)O;5!O;VP`9&,W,C@P7T=E=%-%4U-"1G)O;5!O;VP`9&,W,C@P
-M7T%S<VEG;D5L96UE;G13;&]T3G5M8F5R`&1C-S(X,%]0;W)T7TAA;F1L955N
-M<&QU9P!D8S<R.#!?0V]R95]-;V1U;&53=&%R=`!D8S<R.#!?1&ES8V]V97)Y
-M4TT`9&,W,C@P7U-#4TE?051!7T-H96-K0V]N9&ET:6]N`&1C-S(X,%]-5E]#
-M;W!Y4T=486)L90!D8S<R.#!?4T%405]$979I8V53=&%T94UA8VAI;F4`9&,W
-M,C@P7T1E=FEC95]-86ME26YQ=6ER>51A<VM297%U97-T`&1C-S(X,%]$979I
-M8V5?4&%R<V5)9&5N=&EF>41A=&$`9&,W,C@P7U-!5%-E;G-E1&%T80!D8S<R
-M.#!?1V5T3D-15&%G`&1C-S(X,%]M=D-H86YN96Q3=&%T94UA8VAI;F4`9&,W
-M,C@P7U-T;W)E7T-O;F9I9U)O=71E26YF;P!D8S<R.#!?4T=486)L95]);FET
-M`&1C-S(X,%]'971%>'!A;F1E<D9R;VU0;V]L`&1C-S(X,%]305-?2&%N9&QE
-M0E)$0U-4`&1C-S(X,%]#;W)E4V%V94]R:6=I;F%L0T1"`&1C-S(X,%]-5E]$
-M=6UP4F5Q=65S=`!D8S<R.#!?3&ES=%]'971&:7)S=`!D8S<R.#!?4T-325]!
-M5$%?1FEL;$1A=&%&:65L9`!D8S<R.#!?4T-325]!5$%?4WEN8T-A8VAE5')A
-M;G-L871I;VX`9&,W,C@P7U-'4$E/7TEN:71I86QI>F4`9&,W,C@P7T9R9653
-M35!#;VYT97AT`&1C-S(X,%]&:6QL16YC;&]S=7)E16QE;65N=%-T871U<P!D
-M8S<R.#!?0V]R95]-;V1U;&5);FET:6%L:7IE`&1C-S(X,%]3051!7U!-4W1A
-M=&5-86-H:6YE`&1C-S(X,%]&<F5E4$U4;U!O;VP`9&,W,C@P7U-!5$%?4')E
-M<&%R94-O;6UA;F1486)L90!D8S<R.#!?0V]R95]-;V1U;&5'971297-O=7)C
-M95%U;W1A`&1C-S(X,%]&<F5E4T="=69F97)4;U!O;VP`9&,W,C@P7U1A9U])
-M;FET7T9)1D\`9&,W,C@P7U-#4TE?051!7U)E861#87!A8VET>51R86YS;&%T
-M:6]N0V%L;&)A8VL`9&,W,C@P7U]?4$U?8V%N8V5L7W1I;65R`&1C-S(X,%]-
-M5E]$=6UP4F5G:7-T97(`9&,W,C@P7U-E<G9I8V5);G1E<G)U<'0`9&,W,C@P
-M7TES<W5E7T1I<V-O=F5R`&1C-S(X,%]$25-#7T1O1&ES8V]V97(`9&,W,C@P
-M7U-!5$%?2&%N9&QE1&5V:6-E56YP;'5G`&1C-S(X,%]#;W)E7TEN=&5R;F%L
-M4V5N9%)E<75E<W0`9&,W,C@P7T1)4T-?4V5T4F5S;W5R8V4`9&,W,C@P7U-!
-M5$%?4$U?2&%N9&QE1&5V:6-E56YP;'5G`&1C-S(X,%]3051!7U!O<G1$979I
-M8V5$971E8W1E9`!D8S<R.#!?57!D871E5&%R9V5T1&5V:6-E<P!D8S<R.#!?
-M4T-325]!5$%?4W1A<G13=&]P5')A;G-L871I;VX`9&,W,C@P7T-O<F5?<&%S
-M<U]T:')U7V9I;&Q?=&%S:V9I;&4`9&,W,C@P7VUV7V1I<V%B;&5?<F5G:7-T
-M97)?<V5T`&1C-S(X,%]!<W-I9VY$979I8V5%;&5M96YT3G5M8F5R`&1C-S(X
-M,%]'971-:6Y.96=O=&EA=&5D3&EN:U)A=&4`9&,W,C@P7VUV7W-E=%]305-!
-M9&1R`&1C-S(X,%]035]&<F5E4F5G:7-T97)3970`9&,W,C@P7T5X<&%N9&5R
-M7U--4%)E<75E<W1?4&AY0V]N=')O;`!D8S<R.#!?359?17%U86QS`&1C-S(X
-M,%]'97131T)U9F9E<D9R;VU0;V]L`&1C-S(X,%]30U-)7T%405],;W=E<E=O
-M<F0`9&,W,C@P7T-H96-K1&5V:6-E0VAA;F=E`&1C-S(X,%]305-?17)R;W)(
-M86YD;&EN9P!D8S<R.#!?0F5E<$]N`&1C-S(X,%]31U!)3U]335!297%?0V%L
-M;&)A8VL`9&,W,C@P7U-'5&%B;&5?079A:6QA8FQE`&1C-S(X,%]335!?4T=0
-M24]?4V5T7T9A:6QL960`9&,W,C@P7T-O<F5?1FEL;%-E;G-E1&%T80!D8S<R
-M.#!?1V5T4TU04V-R871C:$9R;VU0;V]L`&1C-S(X,%]3051!7U!O<G1$979I
-M8V5296%D>0!D8S<R.#!?;79?96YA8FQE7WAM=`!D8S<R.#!?07-S:6=N4F5G
-M:7-T97)3970`9&,W,C@P7V]D:6Y?:6]C=&P`9&,W,C@P7TES<W5E7U)E<&]R
-M=%)O=71E26YF;P!D8S<R.#!?1V5T26YT97)N86Q297%&<F]M4&]O;`!D8S<R
-M.#!?0VAE8VM487)G971#:&%N9V4`9&,W,C@P7T1E=FEC95]7<FET95-E<T-O
-M;G1R;VQ$:6%G`&1C-S(X,%]#;VUP;&5T95)E<75E<W0`9&,W,C@P7U)U;G1I
-M;65)<W-U95-O9G1297-E=`!D8S<R.#!?1&5V:6-E7TES<W5E4V]F=%)E<V5T
-M`&1C-S(X,%]3051!7TAA;F1L941E=FEC95!L=6=I;@!D8S<R.#!?4')E<&%R
-M94%N9%-E;F1#;VUM86YD`&1C-S(X,%]0<F5%;7!T>5!-`&1C-S(X,%]30U-)
-M7TUA:V5#86-H94-O;6UA;F0`9&,W,C@P7T-O;7!L971E4F5Q=65S=$%N9%-L
-M;W0`9&,W,C@P7T1)4T-?1V5T3F5G;W1I871E9$QI;FM2871E`&1C-S(X,%]&
-M:6YD4G5N;FEN9U)E<4)Y5&%G`&1C-S(X,%]S971?9F%I;%]L961S`&1C-S(X
-M,%]&:6YD1G)E95--4$-O;G1E>'0`9&,W,C@P7U-!4U]$979I8V53=&%T94UA
-M8VAI;F4`9&,W,C@P7T9I;F149W1.;P!D8S<R.#!?27-S=65?4F5P;W)T1V5N
-M97)A;`!D8S<R.#!?0V%L8W5L871E4F]U=&5);F1E>`!D8S<R.#!?;79?<F5S
-M971?>&UT`&1C-S(X,%]-5E]#4D,`9&,W,C@P7U-#4TE?051!7U)E861#87!A
-M8VET>51R86YS;&%T:6]N`&1C-S(X,%]-5E]296UO=F5487)G971)1`!D8S<R
-M.#!?4T%405]035]%<G)O<DAA;F1L:6YG`&1C-S(X,%]5<&1A=&53=&%T=7-6
-M<U-E<T-O;G1R;VQ"=69F97(`9&,W,C@P7T-O<F5?1V5T4W5P<&]R=&5D0V]U
-M;G1S`&1C-S(X,%]-5E]3971,0D%A;F1396-T;W)#;W5N=`!D8S<R.#!?1&5V
-M:6-E7TUA:V5-;V1E4V5L96-T4F5Q=65S=`!D8S<R.#!?1V5T3VYE0V]M;6%N
-M9%-L;W0`9&,W,C@P7U-'4$E/7U)E861296=I<W1E<@!D8S<R.#!?17AP86YD
-M97)?4TU04F5Q=65S=%]297!O<G102%E3051!`&1C-S(X,%]0;W)T7TAA;F1L
-M95!L=6=I;@!D8S<R.#!?0V]R95]297%4:6UE;W5T`&1C-S(X,%]M;V1E4&%G
-M94)U9@!D8S<R.#!?4G5N=&EM94ES<W5E4F5A9$QO9T5X=`!D8S<R.#!?4T-3
-M25]!5$%?57!P97)7;W)D`&1C-S(X,%]&<F5E0V]R94-O;G1E>'14;U!O;VP`
-M9&,W,C@P7U-%4U]);G1E<FYA;%)E<4-A;&QB86-K`&1C-S(X,%]3051!7T5R
-M<F]R2&%N9&QI;F<`9&,W,C@P7T=E=%!-1G)O;5!O;VP`9&,W,C@P7T1E=&5C
-M=%!O<G14>7!E`&1C-S(X,%]$979I8V5?36%K94UO9&5396YS95)E<75E<W0`
-M9&,W,C@P7U-#4TE?051!7T9I;&Q,0D%#9&(Q,`!D8S<R.#!?7U]C86YC96Q?
-M=&EM97(`9&,W,C@P7U-!5$%?4&]R=%)E<V5T`&1C-S(X,%]O9&EN7W-E=%]I
-M9&QE7W-T86YD8GD`9&,W,C@P7T5X<&%N9&5R7U--4%)E<75E<W1?1&ES8V]V
-M97(`9&,W,C@P7U1A9U]'971/;F4`9&,W,C@P7U-!5$%?4')E<&%R94-O;6UA
-M;F1(96%D97(`9&,W,C@P7T-A=&5G;W)Y7T-$0E]4>7!E`&1C-S(X,%]&<F5E
-M26YT97)N86Q297%4;U!O;VP`9&,W,C@P7T=E=%-!5$%38W)A=&-H1G)O;5!O
-M;VP`4W=A<$AP=$UE=&%6,P!L9&U?<W!I;G5P7W9D978`<F%W7V-H96-K7V1I
-M<VM?9&5S8W)I<'1O<@!L9&U?8VAE8VM?87)R87D`;&1M7W)E8VAE8VM?86QL
-M`'9D979?8VQA<W-?;&ES=`!R87=?:61L95]T:6UE<E]R97-E=`!L9&U?9&5L
-M971E7W!A<G1I=&EO;@!L9&U?<WEN8U]C:&%N9V5D7V%R<F%Y<P!G<F5B=6EL
-M9&]N97)R;W(`;&1M7W%U975E7V5V96YT`'1R86YS9F]R;5]N965D960`;&1M
-M7V-H96-K7W1R86YS9F]R;0!L9&U?9FEX=7!?87)R87E?<W1A=&4`8V%L8U]R
-M96)U:6QD7W!R;V=R97-S`'9B=7-?97AT7W-I>F4`<V5T7W1R86YS9F]R;5]S
-M=&5P7VEN9F\`;&1M7VED;&5?=&EM97(`;&1M7V9I;F1?=F1E=E]R87<`;&1M
-M7W)E<')O8F5?9&5V:6-E`&-A;&-?=')A;G-F;W)M7W!R;V=R97-S`&QD;5]F
-M:6YD7W9D979?8VQA<W,`;&1M7V%L;&]C7W!A<G1I=&EO;@!L9&U?:6YI=%]D
-M:7-K`')E9G)E<VA?<F%W7V1E=E]I;F9O`%]D96QE=&5?<F%W7W!A<G0`<F%W
-M7W)E861?=W)I=&5?<V5C=&]R<P!G:61L97-T86YD8GET:6UE;W5T`')A=U]C
-M:&5C:U]A<G)A>5]D97-C<FEP=&]R`&QD;5]C<F5A=&5?=F1E=E]R87<`=6YP
-M;'5G7W)A=U]V9&5V`$-H96-K4W5M`&-O;7!A<F5?<VQO=%]S97%?8GE?<&-I
-M861D<@!L9&U?861D7V1I<VM?=&]?87)R87D`;&1M7W-Y;F-?9&ES:U]I;F9O
-M`&=E=%]B:71S`%-W87!(<'1-971A5C0`<F%W7V-O;G9E<G1?<W!A<F5?=&]?
-M;&5G86-Y`&9.;W1I9GE'54D`;&1M7V9L=7-H7V%L;%]T87)G971S`&QD;5]S
-M=&%R=%]R96)U:6QD`&QD;5]S<&EN9&]W;E]A;&Q?<F%W9&5V<P!?7VQD;5]F
-M:6YI<VA?8VUD`$E$7U1/7U9$158`7U]V9&5V7W%U975E7V-M9`!R87=?:61L
-M95]T:6UE<E]C:&5C:P!G971?<W1R:7!?:6YF;P!L9&U?<F5S=6UE7V%D87!T
-M97(`:'!T;G)?;&1M7W)E9VES=&5R7VAI;5]27S9?-35?-S5?-#9?-C0`:'!T
-M;G)?9T=L;V)A;$YC<49L86<`:'!T;G)?;W-?<F5Q=65S=%]T:6UE<@!H<'1N
-M<E]D;6%P;V]L7V=E=%]P86=E`&AP=&YR7V]S7V=E=%]S=&%M<`!H<'1N<E]L
-M9&U?<W5S<&5N9`!H<'1N<E]L9&U?:61L90!H<'1N<E]L9&U?9V5T7VUE;5]I
-M;F9O`&AP=&YR7VQD;5]R96UO=F5?=&EM97(`:'!T;G)?<&-I8V9G7W)E861?
-M9'=O<F0`:'!T;G)?9&UA<&]O;%]M86ME7V]R9&5R`&AP=&YR7VQD;5]G971?
-M=F)U<U]E>'0`:'!T;G)?;&1M7W)E;&5A<V5?=F1E=@!H<'1N<E]F<F5E;&ES
-M=%]R97-E<G9E7V1M80!H<'1N<E]L9&U?:6YT<@!M96UC<'D`:'!T;G)?;&1M
-M7V]N7W1I;65R`&AP=&YR7VQD;5]G971?8VUD7W-I>F4`:'!T;G)?;&1M7V9R
-M965?8VUD<P!H<'1N<E]L9&U?8W)E871E7W9D978`:'!T;G)?;&1M7V%D9%]S
-M<&%R95]T;U]A<G)A>0!H<'1N<E]G<F5B=6EL9'!R:6]R:71Y`&AP=&YR7VQD
-M;5]S>6YC7V%R<F%Y7VEN9F\`:'!T;G)?;W-?;6%P7W!C:5]B87(`:'!T;G)?
-M7U]L9&U?86QL;V-?8VUD`&AP=&YR7VEN:71?;6]D=6QE7W9D979?<F%W`&AP
-M=&YR7VQD;5]S971?875T;W)E8G5I;&0`:'!T;G)?7U]D=6UM>5]R96<`:'!T
-M;G)?9&UA<&]O;%]A8W1I=F4`:'!T;G)?=F)U<U]L:7-T`&AP=&YR7VQD;5]Q
-M=65U95]V8G5S7V1P8P!H<'1N<E]L9&U?<F5S971?=F)U<P!H<'1N<E]G4T=0
-M24]087)T4W5P<&]R=`!H<'1N<E]I;FET7VUO9'5L95]H:6U?<C<U,`!?7W5M
-M;V1D:3,`:'!T;G)?;&1M7W)E;&5A<V5?;&]C:P!H<'1N<E]O<U]U;FUA<%]P
-M8VE?8F%R`&AP=&YR7VQD;5]S:'5T9&]W;@!?7W5D:79D:3,`:'!T;G)?:&EM
-M7VQI<W0`:'!T;G)?;&1M7W)E<75E<W1?=&EM97(`:'!T;G)?;&1M7W)E<W5M
-M90!H<'1N<E]L9&U?9V5T7V1E=FEC95]I9`!H<'1N<E]O<U]S8VAE9'5L95]T
-M87-K`&AP=&YR7VQD;5]I;V-T;`!H<'1N<E]G4W!I;G5P3VYE1&5V16%C:%1I
-M;64`:'!T;G)?9G)E96QI<W1?<'5T`&AP=&YR7V]S7W-T86QL97AE8P!H<'1N
-M<E]G7VQE9V%C>5]M;V1E`&AP=&YR7VQD;5]A;&QO8U]C;61S7U)?-E\U-5\W
-M-5\T-E\V-`!H<'1N<E]L9&U?<G5N`&AP=&YR7VEN:71?;6]D=6QE7VAI;5]D
-M8S<R.#``:'!T;G)?;&1M7V9R965?8VUD<U]T;U]L:7-T`&AP=&YR7V]S7VUA
-M>%]C86-H95]S:7IE`&AP=&YR7W9D979?<75E=65?8VUD`&AP=&YR7V]S7V=E
-M=%]V8G5S7W-E<0!H<'1N<E]L9&U?<WEN8U]A<G)A>5]S=&%M<`!H<'1N<E]L
-M9&U?<75E=65?8VUD`&AP=&YR7V]S7W!R:6YT:P!H<'1N<E]F<F5E;&ES=%]R
-M97-E<G9E`&AP=&YR7V1M87!O;VQ?<'5T7W!A9V4`:'!T;G)?9G)E96QI<W1?
-M9V5T`&AP=&YR7VQD;5]U;G)E9VES=&5R7V1E=FEC90!H<'1N<E]L9&U?<F5G
-M:7-T97)?861A<'1E<@!H<'1N<E]G875T;W)E8G5I;&0`:'!T;G)?;&1M7V=E
-M=%]V8G5S7W-I>F4`:'!T;G)?9&5L87E?8F5T=V5E;E]S<&EN=7``:'!T;G)?
-M;&1M7V=E;F5R:6-?;65M8F5R7V9A:6QE9`!H<'1N<E]D;6%P;V]L7V=E=%]P
-M86=E7V%T`&AP=&YR7VQD;5]E=F5N=%]N;W1I9GD`:'!T;G)?;&1M7V-R96%T
-M95]V8G5S`&AP=&YR7VAI;5]H86YD;&5?=&]?=F)U<P!H<'1N<E]F<F5E;&ES
-M=%]G971?9&UA`&AP=&YR7VQD;5]G971?;F5X=%]V8G5S`&AP=&YR7V]S7W!C
-M:5]W<FET96P`:'!T;G)?;&1M7V9I;F1?=&%R9V5T`&AP=&YR7V1M87!O;VQ?
-M<F5G:7-T97)?8VQI96YT`&AP=&YR7VQD;5]I;FET:6%L:7IE7W9B=7-?87-Y
-M;F,`:'!T;G)?;W-?<75E<GE?=&EM90!H<'1N<E]O<U]Q=65R>5]R96UO=F5?
-M9&5V:6-E`&AP=&YR7VQD;5]R96=I<W1E<E]D979I8V4`:'!T;G)?;W-?<&-I
-M7W)E861L`&AP=&YR7VQD;5]A8W%U:7)E7VQO8VL`:'!T;G)?;W-?<F5V86QI
-M9&%T95]D979I8V4`:'!T;G)?9&UA<&]O;%]I;FET`&AP=&YR7VQD;5]F:6YI
-M<VA?8VUD`&AP=&YR7VQD;5]I9&5?9FEX<W1R:6YG`&AP=&YR7V1M87!O;VQ?
-M;6%X7V-L87-S7W!A9V5S`&AP=&YR7VQD;5]R96=I<W1E<E]V9&5V7V-L87-S
-M7U)?-E\U-5\W-5\T-E\V-`!H<'1N<E]N=6U?9')I=F5S7W!E<E]S<&EN=7``
-M:'!T;G)?;&1M7W)E;&5A<V5?=F)U<P!H<'1N<E]L9&U?<75E=65?=&%S:P!H
-M<'1N<E]L9&U?86QL;V-?8VUD<U]F<F]M7VQI<W0`:'!T;G)?9G)E96QI<W1?
-M<'5T7V1M80!H<'1N<E]L9&U?=&EM97)?<')O8F5?9&5V:6-E`&AP=&YR7VQD
-M;5]F:6YD7W-T86UP`&AP=&YR7VQD;5]C:&5C:U]A<G)A>5]O;FQI;F4`:'!T
-M;G)?9U!R;V)E26Y);FET:6%L:7II;F<`:'!T;G)?;&]G7W-E8W1O<E]R97!A
-M:7(``)(````"B```J0````*1``"]`````BH``"0!```!`0``.P$```+J``!=
-M`0```JP``&D!```"/```?`$```*D`@"'`0```D```*<!```")P``O@$```)5
-M``#*`0```BH``.<!```"*@``"P(```)4```H`@```IX``'L"```"Z@``F0(`
-M``*L``"X!0```DP``"<)```!`P``S@D```$%``#3"0```J\"`!P*```"A`(`
-M[`H```&0`@`4"P```9`"`'0+```!D`(`_0L```&0`@`X#````9`"`*(,```"
-MI`(`W`P```*D`@`>#0```J0"`%@-```"I`(`O`T```(/`0#(#0```J0"`-0-
-M```"90``2`X```&0`@!6#@```9`"`&<.```"I`(`>@X```&0`@"(#@```9`"
-M`)L.```!D`(`I`X```&0`@#'#@```J0"`-(.```!D`(`\PX```*D`@#^#@``
-M`9`"`!\/```!D`(`.@\```&0`@"##P```9`"`)H/```!D`(`M@\```&0`@#+
-M#P```9`"`.D/```!D`(`]`\```&0`@`A$````J0"`"\0```!D`(`5A````*D
-M`@!D$````9`"`)82```!D`(`ZQ(```+1```;$P```M$``(\3```"+```]1,`
-M``)]`@`(%````O0``"P4```"9@``S!0```(L``#S%````A8```H5```"L```
-M)14```'_``!`%0```04``$45```"KP(`8A4```*Z`@!_%0```KH"`)H5```"
-M.```Q14```&0`@".%@```9,``*\6```"P```C!<```)_``"8%P```BH``(@8
-M```"N@``Q!L```+R``!`'````MX``(,<```"N@``)AT```$#``!.'0```AD`
-M`)(=```"&0``U1T```(9```4'@```AD``%4>```"2P``I1X```('`0`U'P``
-M`IT``&\?```"$@``GQ\```*D`@#V(0```J````\B```"=@``UR(```+Z``!>
-M(P```K\``(@C```"^@``Z20```*"```%)0```@`!`'TE```"@@``LB4```(`
-M`0!K)P```D(``%`H```"A`(`;B@```$#```%*0```A$``!<I```"$0``R2D`
-M``*"``#^*0```@`!`(HJ```"!0$`R2H```*N``#M*@```@4!``,K```"#0$`
-M(RL```(%`0!S*P```J(``),K```!!0``F"L```*O`@`$+````F8``!0L```"
-M;0``I"P```*/```@+0```H\``"XM```"(@``6BT```*/``!S+0```MP``)LM
-M```"30``/RX```)O``!D+@```MP``(HN```"F```MRX```*/``"_+@```I@`
-M`.0N```"W```1B\```(Y``"0+P```E,``+4O```"9@``[R\```*Z`@`/,```
-M`CD``#0P```"0```0#````*D`@",,````K4``)8P```"[```J3````$&``"N
-M,````J\"`.0P```".0``^3````)6```$,0```I@``'TQ```!D`(`HS$```&0
-M`@#4,0```9`"`!LR```!!0``(#(```*O`@!Q,@```KL``.8R```"NP``_#(`
-M``*]```(,P```F\``+HS```"V0``V3,```+<``#_,P```F8``)$T```"V0``
-MJC0```+<``#R-````FL```TV```!D`(`)C8```&0`@`^-@```9`"`)$V```!
-MD`(`K38```&0`@`I-P```MH``(0W```!D`(`H#<```&0`@"\-P```9`"`,@W
-M```"8@``IS@```(0`0#<.````H0"`+,Y```"A`(`+CH```*$`@!6.@```9`"
-M`(8Z```!D`(`PCH```&0`@"A.P```H0"`-$\```"A`(`6CT```*$`@!M/0``
-M`0,``/(]```"I`(`-SX```&0`@!8/@```9`"`'T^```!!@``@CX```*O`@"1
-M/@```@X!`*H^```!D`(`V3X```&0`@!,/P```9`"`,T_```"#@$`X3\```(.
-M`0!70````04``%Q````"KP(`NT````$&``#`0````J\"`-1````"'P``!T$`
-M``$%```,00```J\"`-5!```!!0``VD$```*O`@"!0@```MD``)A"```"W```
-M2D,```(S``"<1````A\``+!$```"+```(44```)N``"&10```MD``))%```"
-M,P``J44```+<``#]10```F8``'I&```";```JT8```)F```V1P```9`"`&)'
-M```"9@``ET<```(L``"G1P```I@``.1'```!D`(`!T@```&0`@`T2````9`"
-M`$A(```"IP``J$@```&0`@`/20```9`"`"U)```!D`(`/TD```*-``!I20``
-M`9`"`'Y)```!D`(`U$D```&0`@#M20```9`"`!9*```"?0(`-DH```+X``!U
-M2@```F8``*M*```"N@(`QTH```(Y``#U2@```H,```%+```"I`(`*$L```$!
-M``!82P```IT"`'I+```!D`(`BDL```&0`@"I2P```9`"`+E+```!D`(`X4L`
-M``&0`@`+3````9`"`#9,```!D`(`3TP```&0`@![3````9`"`*5,```!D`(`
-M]DP```&0`@`230```9`"`"]-```!D`(`2TT```&0`@")30```GT"`,M-```"
-MN@(`XTT```(Y``#T30```D````!.```"I`(`(TX```'L```X3@```IT"`%E.
-M```!D`(`=TX```&0`@"B3@```9`"`,!.```!D`(`"T\```)]`@`G3P```F8`
-M`%=/```"N@(`>T\```$,`0"23P```IT"`+)/```!D`(`ST\```&0`@#K3P``
-M`J0"`/M/```!D`(`%E````&0`@`S4````9`"`$]0```"I`(`7U````&0`@"#
-M4````9`"`#Y1```!D`(`9E$```*D`@"140```9`"`+A1```"I`(`X5$```&0
-M`@`*4@```J0"`%92```"PP``=%(```*$``"$4@```A```+=2```"/@``\5(`
-M``(5```C4P```A```.-3```"I`(`"50```&0`@`G5````J0"`$=4```!D`(`
-M<%0```*D`@"65````9`"`+A4```"I`(`U%0```&0`@#X5````F8``'U5```"
-M.0``P54```(Y``#150```A```!A6```"9@``/E8```)F``!A5@```GT"`'E6
-M```"0```A58```*D`@`V5P```BP``%E7```"%@``<%<```*P``"*5P```08`
-M`(]7```"KP(`K%<```*Z`@#)5P```KH"`.Q7```".```%5@```*)``!)6```
-M`F8``&I8```"0```=E@```*D`@"G6````A8``+Y8```"L```UU@```'_``#R
-M6````04``/=8```"KP(`%%D```*Z`@`Q60```KH"`$Q9```".```:5D```(^
-M``#N60```9`"`!5:```"I`(`,5H```&0`@!16@```9`"`'1:```"I`(`D%H`
-M``&0`@`<6P```O@``"A;```">P``;5L```)S``!^6P```OD``+M;```"I`(`
-MTUL```&0`@#N6P```9`"`!)<```"$```&EP```(+`0!%7````IL``,U<```"
-M#`$`Y%P```)F``!Q70```B$!`*-=```"M0``W%T```+*``#[70```KH"`!M>
-M```"N@(`3%X```*D`@!C7@```9`"`'Q>```!D`(`G%X```(0``"D7@```@L!
-M`.U>```"PP``)E\```)F``"B7P```IL``+1?```"'P$`)&````&0`@!%8```
-M`9`"`&)@```"<0``<V````+Y``#;8````G4``/A@```"W```&F$```*8```_
-M80```H\``$=A```"F```BF$```+<``#180```CD``.9A```"9@``%F(```*Z
-M`@`N8@```CD``#QB```"0```2&(```*D`@!I8@```NP``)5B```"W```QV(`
-M``(Y``#D8@```F8``/QB```"%@``$V,```*P```P8P```KH"`$UC```"N@(`
-M8&,```(X``!Y8P```O0``(YC```!D`(`VV,```(0``#G8P```CX``'!D```!
-MD`(`BV0```(?``"?9````BP``+YD```"'P``QF0```(G`0#E9````0,```1E
-M```"*0$`*&4```(I`0!,90```CD``'ME```"4P``G&4```*A``#&90```CD`
-M`/%E```"4P``$F8```(Y```N9@```J$``%%F```".0``;F8```(Y``"D9@``
-M`D```+!F```"I`(`'&<```*D```[9P```JH``%5G```"%@``;&<```*P``"&
-M9P```08``(MG```"KP(`J&<```*Z`@#%9P```KH"`-AG```".```!&@```)F
-M``!`:````AT!`(YH```"=```K&@```)F````:0```04```5I```"KP(`+VD`
-M``(?``!R:0```04``'=I```"KP(`2FH```$%``!/:@```J\"`))J```!!0``
-MEVH```*O`@`G:P```J<``"]L```"V0``9&P```+K``"<;````04``*%L```"
-MKP(`WFT```*$`@`";@```9`"`"YN```!D`(`:FX```&0`@#?;@```?\``!9O
-M```!!0``&V\```*O`@"!;P```04``(9O```"KP(`X&\```$%``#E;P```J\"
-M`!=P```!!0``''````*O`@!.<````08``%-P```"KP(`RG````$%``#/<```
-M`J\"`!EQ```!!@``'G$```*O`@!1<0```08``%9Q```"KP(`97$```$&``!J
-M<0```J\"`+MQ```""0$`!G(```&0`@`C<@```9`"`$!R```!D`(`8'(```&0
-M`@!W<@```08``'QR```"KP(``',```&0`@`M<P```08``#)S```"KP(`;7,`
-M``$%``!R<P```J\"`(QS```"8@``I',```&0`@`S=````I@``%-T```"2@``
-MV'0```(M``#V=````KX``")U```"L`(`3G4```*P`@!Z=0```K`"`*-U```"
-ML`(`S'4```*P`@``=@```K`"`"5V```"L`(`2W8```*P`@!W=@```K`"`)QV
-M```"L`(`R'8```*P`@#T=@```K`"`!QW```"L`(`1'<```*P`@!L=P```K`"
-M`)1W```"L`(`NW<```*P`@#D=P```K`"``EX```"L`(`.G@```*"`@!G>```
-M`H("`)MX```"@@(`S'@```*"`@#]>````H("`"YY```"@@(`6WD```*"`@"/
-M>0```H("`,5Y```"9@``VGD```*(``!3>@```0$``&9Z```"Z@``=GH```(\
-M```%>P```F8``$%[```"N@(`77L```(Y``!K>P```D```'=[```"I`(`IWL`
-M``)/``!8?0```BT``.Q]```"L@(`(GX```*R`@!??@```K("`)Q^```"L@(`
-MUGX```*R`@#R?@```K("`!!_```"L@(`>G\```*R`@#5?P```K("`#*````"
-ML@(`>X````*R`@#0@````K("`#B!```"L@(`@8$```*R`@"V@0```LL``,6!
-M```"L@(`\X$```(/```"@@```K("`#""```"#P``/X(```*R`@!M@@```@\`
-M`'R"```"L@(`JH(```(/``"Y@@```K("`!V#```"T@``$X8```*]`@`OA@``
-M`KT"`$N&```"O0(`9X8```*]`@"#A@```KT"`)^&```"O0(`VH8```)F```_
-MAP```KT"`'F'```"9@``YX<```*]`@`JB````F8``**(```":```[8@```&0
-M`@`2B0```9`"`"Z)```"^0``<8D```(Y``"$B0```D```)")```"I`(`LHD`
-M``(6``#/B0```KH"`.R)```"N@(``XH```(X```2B@```9`"`&^*```"T0``
-MGXH```*Z`@`)BP```KT``$2+```"9@``FHL```'_``"YBP```04``+Z+```"
-MKP(`$HP```$%```7C````J\"`$R,```"'P``CXP```$%``"4C````J\"`%F-
-M```!!0``7HT```*O`@"0C0```08``)6-```"KP(`'8X```$%```BC@```J\"
-M`.&.```!!@``YHX```*O`@#NC@```J<``/:/```"W```'I````+9``!"D```
-M`MH``(20```":P``;)0```*<``#,E````H0"`."4```"Y0``6I4```*$`@"I
-ME0```H@``+N5```"D0``S94```(J``#VE0```H0"`#B6```!E@``C98```+J
-M``"NE@```JP``+J6```"/```"9<```*(```;EP```I$``"V7```"*@``?I<`
-M``&6``#3EP```NH``/27```"K````)@```(\``!MF````H@``(.8```"D0``
-MF9@```(J``"^F````H0"`/68```!'0``'YD```+J``!`F0```JP``%"9```"
-M/```LID```*<``#=F0```C8``!F:```"B```*YH```*1```]F@```BH``(.:
-M```!'0``KYH```+J``#0F@```JP``-R:```"/```?9L```)1``"\FP```E$`
-M``R<```"<@``()P```(P``!2G````C0``'*<```",```IIP```(P``![G0``
-M`JT``,Z=```"J```!YX```(T``!(G@```H@``%J>```"D0``;)X```(J``"R
-MG@```?```-J>```"Z@``^YX```*L```'GP```CP``.&?```")P``[9\```(J
-M```?H````H0"`&&@```")P``;:````(J```#H0```A,!`!BA```")P``)*$`
-M``(J```_H0```GT"`%.A```!,0``:*$```*=`@#7H0```J8``,2B```"&`$`
-M!*,```(8`0`^HP```C0``'JD```"9```CZ0```+-``"DI````B`!`+FD```"
-M$P$`TZ0```)]`@#GI````3$```&E```"G0(`-*4```)F``"HI0```B$!`,ZE
-M```"M0``]:4```+*``!$I@```F8``(*F```"-```MZ8```(=`0#AI@```B<`
-M`/6F```"*@``,:<```(T``#[IP```9`"`):L```"80``GZT```$#```XK@``
-M`9`"`&BN```!D`(`DZX```&0`@#,K@```9`"`!^O```!D`(`3:\```&0`@!S
-MKP```9`"`*6O```!D`(`9K````$#``![L````0,``(ZP```!`P``G+````$#
-M``"OL````LP``+JP```!`P``/K$```)F``!^L0```F8``*ZQ```"9@``_K$`
-M``)F```NL@```F8``+2R```"9@``$+0```+9``"!M0```A\``,BU```"]P``
-M"+8```+W``#QM@```B<```*W```"@0``"[@```(\```RN````N@``$&X```"
-M80``5K@```+<``#!N````G4``">Y```";P``^+D```(J``!JN@```E4``'BZ
-M```"*@``MKH```)F``#`N@```AL``,BZ```";0``_+H```*(```*NP```I$`
-M`".[```"*@``8;L```&R``!MNP```CP``+"[```"B```Y[L```&R``#SNP``
-M`CP``#&\```"B```0[P```*1``!5O````BH``)R\```!`0``L+P```+J``#1
-MO````JP``-V\```"/```';T```*(``!8O0```:L``&2]```"/```=KT```*D
-M`@"(O0```J0"`&V^```")P``?KX```*!``"*O@```BH``,.^```">@``X;X`
-M``(G``#RO@```H$``/Z^```"*@``_+\```*D`@`(P````BH``#C````">@``
-M2,````*D`@!4P````BH``(S````"B```S\````(9``#?P````BH``//````!
-ML@``_\````(\``!`P0```H@``%K!```"D0``<\$```(J``#-P0```;(``.#!
-M```"Z@``_L$```*L```*P@```CP``%G"```"B```=,(```*1``"-P@```BH`
-M`./"```!L@``]\(```+J```9PP```JP``"7#```"/```8,,```*(``!ZPP``
-M`I$``)/#```"*@``YL,```&R``#^PP```NH``"#$```"K```+,0```(\``!P
-MQ````H@``(K$```"D0``H\0```(J``#NQ````;(```+%```"Z@``),4```*L
-M```PQ0```CP``(_%```"B```1<8```$!``!8Q@```NH``&3&```"/```D<@`
-M``(I`0"NR````E4``/S(```"9@``S\D```*/```SR@```H@``%3*```"%0$`
-M9LH```(J``"ZR@```0H!`,W*```"Z@``V<H```(\```JRP```H@``#S+```"
-M%0$`D<L```$*`0"DRP```NH``+#+```"/```O,L```*D`@`!S````H@```_,
-M```"%0$`6LP```$*`0!MS````NH``'G,```"/```N<P```*(``#'S````A4!
-M``W-```!"@$`(,T```+J```LS0```CP``%W-```"2P``;<T```(H``!=S@``
-M`DL``&W.```"*```U<X```*W``!4SP```I4``+W/```"$0$`[<\```)+``#]
-MSP```B@``&G0```"F0``R-````(&`0`BT0```MD``$+1```"=0``6-$```(&
-M`0"AT0```MD``+?1```"!@$`X-$```)]`@`3T@```GT"`&72```"9P``K=(`
-M``+9``#'T@```F\``-/2```"O0``A-,```)F``"6TP```G0``*W3```!"0$`
-MPM,```*=`@`^U````F8``%#4```"O0``:=0```%0``"$U````IT"`#'5```"
-MV0``/=4```(S``!)U0```H\``._5```!"0$`!-8```*=`@"(U@```5```*/6
-M```"G0(`)-@```)F``")V````G\``)W8```"*@``Y]@```)3```:V0```K4`
-M`$79```"1@``9=D```)F``#DV0```B$!`/_9```"?P``$]H```(J``![V@``
-M`CD``*3:```"0```L-H```*D`@#;V@```J0``/K:```"J@``)]L```(6```^
-MVP```K```%C;```!!@``7=L```*O`@!ZVP```KH"`)?;```"N@(`TML```(X
-M``#TVP```F8``";<```"'0$`9]P```(Y``"8W````D```*3<```"I`(`S]P`
-M``*D``#NW````JH```O=```"%@``)MT```*P``!'W0```?\``&;=```!!0``
-M:]T```*O`@",W0```KH"`!/>```"N@(`=-X```)F``"RW@```KH"`-K>```"
-M.```(-\```*(```RWP```I$``$O?```"*@``N=\```&R``#,WP```NH``.K?
-M```"K```]M\```(\```CX````DL``#/@```"*```#N$```(&`0!'X0```B@`
-M`)[A```"9@``J>,```*$`@!LY0```J8``*3E```"5P``+^8```$!``!=Y@``
-M`AH``#GG```!`0``?.<```(:``!%Z````0$``(OH```"&@``]>@```$!```S
-MZ0```AH``(7I```!`0``P^D```(:``"<Z@```AX``!7K```"!`$`'^P```+N
-M``"S[````FH``#KM```"I@``;>T```)#``"8[0```E@``,SN```"5P``DO``
-M``*Y``#>\````NX``(+Q```":@``^?$```+F``"`\@```FH``$#S```":@``
-M@?,```)7``#\\P```FH``$CT```":@``J?0```)J``#S]````FH``#OX```"
-M:@``D_@```&0`@"K^````9`"`"OZ```"T```F/L```&0`@"S^P```9`"`-/[
-M```"*@``,/P```*D`@`__````9`"`&+\```"I`(`<?P```&0`@!I_0```J0"
-M`'7]```!D`(`A_T```*D`@"._0```9`"`*O]```"I`(`L_T```&0`@#:_0``
-M`J0"`.;]```!D`(`^/T```*D`@#__0```9`"`!S^```"I`(`)/X```&0`@!H
-M_@```J0"`,C^```"I`(`V?X```)````W_P```H@``*/_```!U0``K_\```&O
-M``"^_P```CP```X``0`"B```?``!``$O``"(``$``CP```<!`0`!D`(`*`$!
-M``&0`@"'`0$``M0``)<!`0`"*P``Z@$!``*(```S`@$``2\``#\"`0`"/```
-MQP(!``&0`@#H`@$``9`"`#\#`0`"#@``3P,!``(K``##`P$``H@```H$`0`!
-MU0``%@0!``&O```E!`$``CP``&L$`0`"B```R`0!``$!``#7!`$``CP``/X$
-M`0`!&P$`804!``*D`@!H!0$``9`"`'H%`0`"I`(`@04!``&0`@`1!@$``J0"
-M`!@&`0`!D`(`*@8!``*D`@`Q!@$``9`"`,<&`0`"W0``_`8!``(!`0`$!P$`
-M`M```%D'`0`!D`(`;@<!``&0`@"*!P$``9`"`*\'`0`!D`(``@@!``+O```*
-M"`$``A0``'8(`0`"I`(`B0@!``&0`@"O"`$``J0"`,((`0`!D`(`R0L!``)X
-M``!_#`$``J8``-T-`0`"I@``_0T!``*F``!S#@$``B8!`'T/`0`"I`(`I`\!
-M``*D`@!O$`$``M8``)`0`0`"VP``JA`!``$#`0"X$`$``0,!`#H1`0`!D`(`
-M9A$!``&0`@"6$0$``J0"`*L1`0`!D`(`\A$!``&0`@!0$@$``9`"`+D2`0`!
-MD`(`*A,!``*D`@`\$P$``9`"`%T3`0`"4@``:1,!``)E``!_$P$``J0"`)L3
-M`0`"I`(`MQ,!``*D`@#9$P$``H,``.L3`0`!D`(`/!0!``*D`@!+%`$``9`"
-M`&P4`0`"4@``>!0!``)E``".%`$``J0"`*H4`0`"I`(`QA0!``*D`@#H%`$`
-M`H,``/H4`0`!D`(`*A4!``*D`@`V%0$``A```%05`0`""P$`7Q4!``&0`@!W
-M%0$``9`"`(X5`0`!D`(`8Q8!``&0`@#C%@$``H@``/T6`0`"D0``%A<!``(J
-M``!T%P$``0$``(@7`0`"Z@``J1<!``*L``"U%P$``CP``.\8`0`!!0``]!@!
-M``*O`@"J&0$``04``*\9`0`"KP(`PQD!``(=`0#D&0$``D<``,P:`0`"F@``
-M/!L!``&3``!=&P$``L```'4;`0`">P``]1L!``*:```('`$``B4!`#H<`0`"
-MR@``U1P!``(?`0#D'`$``I\``(H=`0`"'0$`X!T!``)F``!`'@$``B$!`&,>
-M`0`"M0``=!X!``+*```+'P$``N(``)@?`0`"9@``$2`!``+B``"N(`$``KH"
-M`,T@`0`"N@(`_R`!``+B``!K(0$``KH"`+<A`0`"N@(`]2$!``(Y```;(@$`
-M`D```"<B`0`"I`(`4B(!``*D``!Q(@$``JH``(HB`0`"%@``H2(!``*P``"[
-M(@$``08``,`B`0`"KP(`W2(!``*Z`@#V(@$``08``/LB`0`"KP(`&",!``*Z
-M`@!@(P$``KH"`*,C`0`".```QB,!``*Z`@`@)`$``O@``$PD`0`"'0$`920!
-M``)[``"J)`$``G,``.PD`0`!`P``5R4!``+1``!\)0$``H<``*$E`0`"AP``
-MQB4!``*'``#K)0$``H<``!@F`0`"A0``128!``*%``!\)@$``H4``*DF`0`"
-MA0``M28!``*D`@#L)@$``H4``!DG`0`"A0``)2<!``*D`@!*)P$``H<``&\G
-M`0`"AP``E"<!``*'``#!)P$``H4``.8G`0`"AP``+"@!``*D`@"F*`$``9`"
-M`,0H`0`!D`(`VB@!``*D`@#X*`$``K4```DI`0`"I`(`*2D!``*'```U*0$`
-M`J0"`%HI`0`"AP``9BD!``*D`@"=*0$``H4``*DI`0`"I`(`SBD!``*'``#:
-M*0$``J0"`.\I`0`"S@``!"H!``)(```Q*@$``H4``%XJ`0`"A0``BRH!``*%
-M``"X*@$``H4``-TJ`0`"AP``[BH!``*D`@`.*P$``H<``!HK`0`"I`(`1RL!
-M``*%``!L*P$``H<``)DK`0`"A0``K2L!``*?``#2*P$``H<``-XK`0`"I`(`
-M$BP!``*%```>+`$``J0"`$`L`0`"AP``3"P!``*D`@!A+0$``B<``&TM`0`"
-M*@``RRT!``&0`@#J+0$``9`"`!PN`0`!D`(`02X!``(G``!-+@$``BH``%DN
-M`0`"T0``@2X!``+1``#%+P$``G,``-$O`0`"I`(`]R\!``)S```#,`$``J0"
-M`(HP`0`!D`(`HS`!``&0`@#J,`$``J0"``LQ`0`"M0``)S$!``+8```\,0$`
-M`M@``$PQ`0`"I`(`<#$!``&0`@".,0$``9`"`*8Q`0`"I`(`NS$!``$%``#`
-M,0$``J\"`,TQ`0`"B```$C(!``$!```>,@$``CP``#,R`0`!!@``.#(!``*O
-M`@!%,@$``H@``(HR`0`!`0``EC(!``(\``"],@$``H@```DS`0`!`0``&#,!
-M``(\```L,P$``H@``'@S`0`!`0``AS,!``(\``";,P$``H@``.`S`0`!`0``
-M[#,!``(\```&-`$``H@``$LT`0`!`0``5S0!``(\``!K-`$``H@``+@T`0`!
-M`0``Q#0!``(\```!-0$``IH``"DU`0`"5@``C34!``+1``#3-0$``M$``.4U
-M`0`"9@``/#8!``(A`0!H-@$``K4``((V`0`"R@``K#8!``)F```--P$``B$!
-M`#DW`0`"M0``4S<!``+*``"+-P$``F8``+8W`0`"-```V3<!``(=`0`9.0$`
-M`B<``"4Y`0`"*@``ECD!``*D`@#=.0$``E,``/(Y`0`"M0``2#H!``$%``!-
-M.@$``J\"`&@Z`0`"X0``V#H!``*D`@!-.P$``B<``%D[`0`"*@``<3L!``(G
-M``!].P$``BH``(D[`0`"M0``<3P!``(6`0"+/`$``A8!`*4\`0`"C@``MSP!
-M``*V``#)/`$``N```.$\`0`"]@``\SP!``+&```%/0$``I```!D]`0`":0``
-M1#T!``)F``"E/0$``B$!`-(]`0`"M0``[#T!``+*``!&/@$``C0``%@^`0`"
-M9@``?CX!``$&``"#/@$``J\"`),^`0`"-```NCX!``(=`0`80`$``ND``")`
-M`0`!`P``@T`!``)[```<00$``IH``#-!`0`")0$`=D$!``+*```-0@$``F8`
-M`#]"`0`"WP``A4(!``*F```E0P$``KH"`&!#`0`".0``>$,!``)```"$0P$`
-M`J0"`*]#`0`"I```SD,!``*J``#N0P$``A8```E$`0`"L```*D0!``*Z`@!+
-M1`$``KH"`']$`0`".```^40!``+?```010$``A,``,9%`0`"I@``3D<!``(A
-M`0!E1P$``LH``)5'`0`"-```J$<!``)[```22`$``F8``$=(`0`"WP``CT@!
-M``+?``#12`$``M\``.Q(`0`"I@``+TD!``(9`0"%2@$``K,``*M*`0`"9@``
-MR4H!``(Y``#72@$``D```.-*`0`"I`(`!4L!``(6```<2P$``K```#E+`0`"
-MN@(`5DL!``*Z`@""2P$``C@``*)+`0`"B0``!TP!``(]```R3`$``M\``'=,
-M`0`"WP``MDP!``+?``#)3`$``AD!`-U,`0`"1P``%4T!``(9`0"(3@$``GL`
-M`+M/`0`"(0$`S4\!``+*```64`$``AT!`%]0`0`"WP``AE`!``*X``#B4`$`
-M`A4``.I0`0`!DP``"U$!``+````J40$``K$``#91`0`"%0``;E$!``+8``!^
-M40$``J0"`,51`0`".```VE$!``*E```'4@$``M$``"E2`0`"?0(`.%(!``+T
-M``!,4@$``F8``&I2`0`"%@``@5(!``*P``">4@$``KH"`+M2`0`"N@(`TE(!
-M``(X``#S4@$``F8```-3`0`">P``/%,!``*U```!5`$``B<```U4`0`"*@``
-M:50!``$%``!N5`$``J\"`(A4`0`".```E%0!``(J``#)5`$``OD``/I4`0`"
-MI`(`!E4!``(J```B50$``G,``#!5`0`"I`(`/%4!``(J``!(50$``G```*E5
-M`0`"9@``#58!``*U``!V5P$``H4``--7`0`")P``XU<!``(J``#X5P$``M$`
-M`!U8`0`!`P``35@!``&0`@"36`$``9`"`+98`0`!D`(`^U@!``&0`@`:60$`
-M`9`"`&]9`0`!D`(`JED!``(G``"Z60$``BH``,I9`0`"'0$`!EH!``(G```6
-M6@$``BH``"1:`0`!UP``.5H!``*=`@!26@$``J0"`'M:`0`"PP(`IUH!``&0
-M`@#&6@$``9`"`,M:`0`"PP(`.5L!``)F``"/6P$``A8``+1;`0`"L```XUL!
-M``*Z`@!X7`$``?\``)=<`0`!!0``G%P!``*O`@"]7`$``KH"`.1<`0`".```
-M"ET!``&0`@`I70$``9`"`'!=`0`"9@``J%T!``)[``#470$``D```.!=`0`"
-MI`(`%UX!``&0`@`V7@$``9`"`!!?`0`!D`(`+5\!``&0`@"S7P$``HH``-)?
-M`0`"!@$`!V`!``&0`@`C8`$``9`"`%%@`0`!D`(`;6`!``&0`@"W8`$``9`"
-M`-9@`0`!D`(`"&$!``&0`@`U80$``B<``$5A`0`"*@``46$!``+1``!D80$`
-M`D```'!A`0`"I`(`F6(!``(G``"E8@$``BH``.EB`0`")P``]6(!``(J```)
-M8P$``LH``!UD`0`"A`(`<60!``$&``!V9`$``J\"`(MD`0`")P``EV0!``(J
-M``#`9`$``F8``#=E`0`"9@``IF4!``+*``!@9@$``J0"`-YF`0`"I`(`,F<!
-M``*D`@!19P$``B<``%UG`0`"*@``<6<!``+[``"-:`$``J0"`-)H`0`"I`(`
-M\6@!``(G``#]:`$``BH``!%I`0`"^P``4&D!``*D`@"@:0$``J0"`/EI`0`"
-MI`(`*FH!``*7``!1:@$``B<``%UJ`0`"*@``:6H!``+*``"P:@$``9`"`)9M
-M`0`"&```MFT!``(8``#A;0$``A@``)9N`0`"&```MFX!``(8``#C;@$``A@`
-M`#-O`0`"B@``>6\!``+4``");P$``BL``.!O`0`"Q```+G`!``(A``!K<`$`
-M`L,``+AP`0`"I`(`VG4!``$)``#J=0$``0D``/IU`0`"/P``4'8!``)@```V
-M=P$``I0``&-W`0`"\0``=G<!``*4``!+>`$``F8``*5X`0`"TP``RG@!``*$
-M`@#S>`$``BX``'YY`0`"10``O7D!``+#```:>@$``K0``/%Z`0`"I`(`XWL!
-M``$)``#T>P$``0D```1\`0`"/P``.WP!``$)``!,?`$``0D``%Q\`0`"/P``
-MXWP!``&0`@`R?0$``9`"`%-]`0`")@``:WT!``(F``"#?0$``B8``)M]`0`"
-M)@``LWT!``(F``#+?0$``B8``.-]`0`")@``^WT!``(F```3?@$``B8``"M^
-M`0`")@``0WX!``(F``!;?@$``B8``'-^`0`")@``BWX!``(F``"C?@$``B8`
-M`+M^`0`")@``TWX!``(F``#K?@$``B8```-_`0`")@``&W\!``(F```S?P$`
-M`B8``$M_`0`")@``8W\!``(F``![?P$``B8``)-_`0`")@``JW\!``(F```4
-M@`$``9`"`#2``0`!D`(`\8`!``(F```0@0$``B8``"^!`0`")@``3H$!``(F
-M``!M@0$``B8``,N!`0`"B```W8$!``(5`0!N@@$``H0"`*>"`0`"A`(`KH(!
-M``$:`0#!@@$``NH``,V"`0`"/```%(,!``*(```F@P$``A4!`'^#`0`!&@$`
-MDH,!``+J``">@P$``CP``/J#`0`"O```"(0!``)````4A`$``J0"`$Z$`0`"
-M-P``7(0!``)```!HA`$``J0"`)*$`0`"O```I(0!``)```"PA`$``J0"`/V$
-M`0`"-P``EX4!``)_``"CA0$``BH``%*(`0`")0``:(@!``+M``!6B0$``H8`
-M`&N)`0`!70``P(D!``(E``#6B0$``NT``'J*`0`"A@``P8H!``*&``"$BP$`
-M`JD``)V+`0`",@``OHL!``)\```CC`$``0,``(2/`0`"%P``"I`!``(7```F
-MD`$``H0"`!"1`0`"W@``?)(!``&0`@"3D@$``9`"`*.2`0`"I`(`[I(!``$'
-M```VDP$``9`"`&F3`0`!!P``BY,!``$'``#3DP$``9`"`$B4`0`!!P``D)0!
-M``&0`@##E`$``0<``.64`0`!!P``+94!``&0`@"6E0$``0<``*>5`0`!!P``
-M.I8!``&0`@#/E@$``9`"`&*7`0`!D`(`C)<!``*D`@!8F`$``B,``!>;`0`"
-MYP``CYP!``$#``">G`$``0<``*B<`0`!!P``LYP!``$'``"]G`$``0<``!:@
-M`0`!!P``&Z`!``)U`@"AH`$``C\``+&@`0`"I`(`S:`!``("`0#XH`$``08`
-M`/V@`0`"KP(`1:$!``*9`@!?H0$``ID"`'FA`0`"F0(`\:$!``(M```2H@$`
-M`J,"`"^B`0`"HP(`4*(!``*C`@!MH@$``J,"`(ZB`0`"HP(`JZ(!``*C`@#,
-MH@$``J,"`.FB`0`"HP(`)J,!``*C`@`]HP$``J,"`&NC`0`"HP(`B*,!``*C
-M`@"IHP$``J,"`,:C`0`"HP(`YZ,!``*C`@`$I`$``J,"`"6D`0`"HP(`0J0!
-M``*C`@!CI`$``J,"`("D`0`"HP(`H:0!``*C`@"^I`$``J,"`-^D`0`"HP(`
-M_*0!``*C`@`=I0$``J,"`#JE`0`"HP(`6Z4!``*C`@!XI0$``J,"`)FE`0`"
-MHP(`MJ4!``*C`@#7I0$``J,"`/2E`0`"HP(`%:8!``*C`@`RI@$``J,"`%.F
-M`0`"HP(`<*8!``*C`@"1I@$``J,"`*ZF`0`"HP(`XZ8!``+2`@`4IP$``M("
-M`$FG`0`"T@(`>J<!``+2`@"OIP$``M("`."G`0`"T@(`%:@!``+2`@!&J`$`
-M`M("`'NH`0`"T@(`K*@!``+2`@#AJ`$``M("`!*I`0`"T@(`1ZD!``+2`@!X
-MJ0$``M("`*VI`0`"T@(`WJD!``+2`@`1J@$``L@``".J`0`"R```3:H!``(I
-M``!5J@$``I(``&.J`0`"D@``:ZH!``(B`0!WJ@$``J0"`'^J`0`"P0``CZH!
-M``+(``"?J@$``L@``.&J`0`"T0``-*L!``+1``!<JP$``@@!`&^K`0`""`$`
-MC*L!``((`0"?JP$``@@!`+NK`0`"0```#*P!``*(``!JK`$``0$``'JL`0`"
-M/```MZP!``(Y``#+K`$``J0"`->L`0`"0```)JT!``(J``"/K0$``H@```6N
-M`0`!`0``%:X!``(\``!2K@$``CD``&:N`0`"I`(`<JX!``)```"TK@$``I$`
-M`"NO`0`!`0``.Z\!``+J``!@KP$``JP``'2O`0`"/```L:\!``(Y``#%KP$`
-M`J0"`-&O`0`"0```";`!``(G```GL`$``BH``#.P`0`"B```3[`!``(G``!9
-ML0$``0$``&VQ`0`"Z@``EK$!``*L``"JL0$``CP``.>Q`0`".0``^[$!``*D
-M`@`'L@$``D```$FR`0`")P``9;(!``(J``#UL@$``H@``!VS`0`!!@``(K,!
-M``*O`@`PLP$``I$``$RS`0`"*@``B;,!``*Z`@"HLP$``CD``/FS`0`"A`(`
-MW;0!``)>```=M0$``0$``#&U`0`"Z@``6K4!``*L``!UM0$``CP``+>U`0`"
-M.0``R[4!``*D`@#7M0$``D```".V`0`"A`(`5[8!``(G``!PM@$``H$``(2V
-M`0`"*@``K+8!``*Z`@!PMP$``B<``(&W`0`"@0``C;<!``(J``!2N`$``CD`
-M`*"X`0`"(0$`Z+@!``+1``#^N`$``K4``!VY`0`"R@``5[D!``+D``!AN@$`
-M`L<``(.Z`0`"$0$`H[H!``*\`@#7N@$``BD``-^Z`0`"7```Y[H!``)<``#O
-MN@$``I(``/NZ`0`"D@``![L!``(B`0`3NP$``J0"`!N[`0`"P0``+[L!``%?
-M``!*NP$``IT"`%J[`0`"'0$`?+L!``(7`0"*NP$``A<!`*F[`0`!"0``MKL!
-M``$)``#3NP$``0<``-V[`0`!!P``_KL!``%:```,O`$``0<``!*\`0`!6@``
-M&+P!``$'```>O`$``5H``"2\`0`!!P``*KP!``%:```QO`$``5H``$>\`0`!
-M6@``3KP!``%:``!=O`$``5H``&2\`0`!6@``;;P!``%:``!TO`$``5H``(.\
-M`0`!6@``D+P!``$'``"JO`$``5H``+B\`0`!6@``Q[P!``%:``#.O`$``5H`
-M`->\`0`!6@``WKP!``%:``#VO`$``0<```B]`0`!`P``1;T!``$#``!IO0$`
-M`0<``'J]`0`!!P``IKT!``%:``"TO0$``5H``-Z]`0`!6@``!+X!``%:```1
-MO@$``5H``&.^`0`"?@(`=[X!``$#``#OO@$``JH``!6_`0`"I```';\!``+D
-M``!"OP$``K```%R_`0`"L```\;\!``$%``#VOP$``J\"``C``0`"B```-L`!
-M``'_``!1P`$``04``%;``0`"KP(`F,`!``$!``"DP`$``CP``.'``0`".0``
-M]<`!``*D`@#]P`$``D```$'!`0`"B```8\$!``*1``"$P0$``BH``-[!`0`!
-M`0``\L$!``+J```3P@$``JP``"/"`0`"/```8,(!``(Y``!TP@$``J0"`(#"
-M`0`"0```L\(!``+A``#=P@$``B<``.W"`0`"*@``"<,!``(J``!6PP$``0,`
-M`)'#`0`"XP``U<,!``)C```-Q`$``KH"`"C$`0`".0``.L0!``*D`@!"Q`$`
-M`D```'[$`0`"N@(`F<0!``*C``"KQ`$``OT``!+%`0`!_P``+<4!``$%```R
-MQ0$``J\"`&#%`0`"?0(`<<4!``$!``"&Q0$``IT"`/''`0`"J@``&L@!``*D
-M``!(R`$``F8``+3(`0`"9@``"<D!``*Z`@!(R0$``F8``*K)`0`"N@(`\,H!
-M``+C``!&RP$``L<``&'+`0`"L```F<L!``)```#$RP$``AT!`.'+`0`"?0(`
-M]<L!``%?```*S`$``IT"`&7-`0`"Y```QLT!``$#``#ZS0$``CL``&/.`0`"
-M.P``S,X!``([```USP$``CL``'_0`0`!`P``PM`!``([```QT0$``CL``);1
-M`0`".P``^]$!``([``!AT@$``CL``,;2`0`".P``$-,!``*;`@!$TP$``CL`
-M`([3`0`"FP(`PM,!``([```,U`$``IL"`$#4`0`".P``BM0!``*;`@"^U`$`
-M`CL``!35`0`"B@``4M4!``**``"0U0$``HH``,[5`0`"B@``#-8!``**``!'
-MU@$``HH``/#6`0`!"0``^]8!``$)```9V0$``HP"`$+9`0`"C`(`A-D!``$#
-M``"9V0$``0<``*79`0`!!P``L=D!``$'``"ZV0$``0<``,#9`0`!!P``W=D!
-M``$'```=V@$``L8"`%':`0`"OP(`AMH!``%:``"3V@$``5H``+_:`0`!6@``
-MW-H!``%:``#EV@$``5H``.S:`0`!6@``"-L!``%:```6VP$``5H``'3<`0`!
-M_P``B=P!``+D``#SW0$``I0``"'>`0`"\0``-MX!``*4``"UX0$``I0``./A
-M`0`"\0``^.$!``*4``"EY0$``I0``-/E`0`"\0``Z.4!``*4``!EZ0$``I0`
-M`)/I`0`"\0``J.D!``*4``#PZP$``H@``+_M`0`"A`(`$^\!``$!``"![P$`
-M`EX``)'O`0`"Z@``L>\!``*L``#1[P$``NH``.?O`0`"D0``'/`!``*L```Q
-M\`$``GD``&;P`0`"K```I?`!``*$`@`7\0$``H0"`%'Q`0`"/```8_$!``(J
-M``#?\P$``L8"``;T`0`"Q@(`._4!``(A`0"+]0$``F8``-WU`0`"M0``#O8!
-M``+1``!,]@$``H,``''V`0`"R@``G/8!``)F``#W]@$``N(``,+W`0`"!@(`
-MV?<!``)$`@#M]P$``D,"`%3X`0`!`0``:_@!``+#`0"-^`$``BP!`)GX`0`"
-M0P$`K/@!``*D`@"W^`$``E4!`-?X`0`"+@$`[O@!``)U`0#Z^`$``D,"`!?Y
-M`0`"0P(`._D!``)X`0!8^0$``L<!`*OY`0`"PP$`R?D!``(L`0#H_`$``JL!
-M`%<``@`!`P``_@`"``$%```#`0(``J\"`$P!`@`"A`(`'`("``&0`@!$`@(`
-M`9`"`*0"`@`!D`(`+0,"``&0`@!H`P(``9`"`-(#`@`"I`(`#`0"``*D`@!.
-M!`(``J0"`(@$`@`"I`(`[`0"``)6`0#X!`(``J0"``0%`@`"`0(`>`4"``&0
-M`@"&!0(``9`"`)<%`@`"I`(`J@4"``&0`@"X!0(``9`"`,L%`@`!D`(`U`4"
-M``&0`@#W!0(``J0"``(&`@`!D`(`(P8"``*D`@`N!@(``9`"`$\&`@`!D`(`
-M:@8"``&0`@"S!@(``9`"`,H&`@`!D`(`Y@8"``&0`@#[!@(``9`"`!D'`@`!
-MD`(`)`<"``&0`@!1!P(``J0"`%\'`@`!D`(`A@<"``*D`@"4!P(``9`"`,8)
-M`@`!D`(`&PH"``+1`0!+"@(``M$!`+\*`@`"%`(`)0L"``)]`@`X"P(``M(!
-M`%P+`@`"R0$`_`L"``(4`@`C#`(``OD!`#H,`@`"O0$`5@P"``$&``!;#`(`
-M`J\"`'@,`@`"N@(`E0P"``*Z`@"P#`(``EH!`-L,`@`!D`(`K@T"``%!`0#/
-M#0(``M\!`*P.`@`"0`$`N`X"``)#`@"H#P(``K\!`.02`@`"0@(`8!,"``)@
-M`0"C$P(``K\!`$84`@`!`P``;A0"``(3`@"R%`(``A,"`/44`@`"$P(`-!4"
-M``(3`@!U%0(``J(!`,45`@`"%@(`518"``(X`0"/%@(``F$!`+\6`@`"I`(`
-M%AD"``(L`@`O&0(``O0!`/<9`@`"3`$`?AH"``+J`0"H&@(``DP!``D<`@`"
-M00(`)1P"``+3`0"='`(``D$"`-(<`@`"TP$`BQX"``(5`@!P'P(``H0"`(X?
-M`@`!`P``)2`"``(K`0`W(`(``BL!`.D@`@`"00(`'B$"``+3`0"J(0(``H@!
-M`.DA`@`"=`$`#2("``*(`0`C(@(``@("`$,B`@`"B`$`DR("``)\`0"S(@(`
-M`04``+@B`@`"KP(`)","``+)`0`T(P(``D<!`,0C`@`"#`(`0"0"``(,`@!.
-M)`(``A`"`'HD`@`"#`(`DR0"``+6`0"[)`(``G<!`%\E`@`"DP$`A"4"``+6
-M`0"J)0(``H<!`-<E`@`"#`(`WR4"``*'`0`$)@(``M8!`&8F`@`"+P$`L"8"
-M``+Q`0#5)@(``LD!``\G`@`"N@(`+R<"``(O`0!4)P(``E4!`&`G`@`"I`(`
-MK"<"``*Z`0"V)P(``@,"`,DG`@`!!@``SB<"``*O`@`$*`(``B\!`!DH`@`"
-MF@$`)"@"``*'`0"=*`(``9`"`,,H`@`!D`(`]"@"``&0`@`[*0(``04``$`I
-M`@`"KP(`D2D"``*^`0`&*@(``KX!`!PJ`@`"/`(`*"H"``*3`0#:*@(``D(!
-M`/DJ`@`"U@$`'RL"``+)`0"Q*P(``D(!`,HK`@`"U@$`$BP"``(W`@`M+0(`
-M`9`"`$8M`@`!D`(`7BT"``&0`@"Q+0(``9`"`,TM`@`!D`(`22X"``+W`0"D
-M+@(``9`"`,`N`@`!D`(`W"X"``&0`@#H+@(``G\!`,<O`@`"30$`_"\"``*$
-M`@#3,`(``H0"`$XQ`@`"A`(`=C$"``&0`@"F,0(``9`"`.(Q`@`!D`(`P3("
-M``*$`@#Q,P(``H0"`'HT`@`"A`(`C30"``$#```2-0(``J0"`%<U`@`!D`(`
-M>#4"``&0`@"=-0(``08``*(U`@`"KP(`L34"``+<`0#*-0(``9`"`/DU`@`!
-MD`(`;#8"``&0`@#M-@(``MP!``$W`@`"W`$`=S<"``$%``!\-P(``J\"`-LW
-M`@`!!@``X#<"``*O`@#T-P(``L@!`"<X`@`!!0``+#@"``*O`@#U.`(``04`
-M`/HX`@`"KP(`H3D"``)"`0"X.0(``M8!`&HZ`@`"KP$`O#L"``+(`0#0.P(`
-M`A0"`$$\`@`"@0$`ICP"``)"`0"R/`(``J\!`,D\`@`"U@$`'3T"``+)`0":
-M/0(``C$!`,L]`@`"R0$`5CX"``&0`@""/@(``LD!`+<^`@`"%`(`QSX"``*'
-M`0`$/P(``9`"`"<_`@`!D`(`5#\"``&0`@!H/P(``HX!`,@_`@`!D`(`+T`"
-M``&0`@!-0`(``9`"`%]``@`"9P$`B4`"``&0`@">0`(``9`"`/1``@`!D`(`
-M#4$"``&0`@`V00(``GT"`%9!`@`"Y@$`E4$"``+)`0#+00(``KH"`.=!`@`"
-M+P$`%4("``*-`0`A0@(``J0"`$A"`@`!`0``>4("``*=`@":0@(``9`"`*I"
-M`@`!D`(`R4("``&0`@#90@(``9`"``%#`@`!D`(`*T,"``&0`@!60P(``9`"
-M`&]#`@`!D`(`FT,"``&0`@#%0P(``9`"`!9$`@`!D`(`,D0"``&0`@!/1`(`
-M`9`"`&M$`@`!D`(`J40"``)]`@#K1`(``KH"``-%`@`"+P$`%$4"``)5`0`@
-M10(``J0"`$-%`@`!`P(`6$4"``*=`@!Y10(``9`"`)=%`@`!D`(`PD4"``&0
-M`@#@10(``9`"`"I&`@`"?0(`1D8"``+)`0!V1@(``KH"`)I&`@`!Q@$`LT8"
-M``*=`@#31@(``9`"`/!&`@`!D`(`#$<"``*D`@`<1P(``9`"`#='`@`!D`(`
-M5$<"``&0`@!P1P(``J0"`(!'`@`!D`(`I$<"``&0`@!>2`(``9`"`(9(`@`"
-MI`(`L4@"``&0`@#82`(``J0"``%)`@`!D`(`*DD"``*D`@!V20(``IP!`)1)
-M`@`"X`$`I$D"``*N`0#720(``JH!`!%*`@`"BP$`0TH"``*N`0`#2P(``J0"
-M`"E+`@`!D`(`1TL"``*D`@!G2P(``9`"`)!+`@`"I`(`MDL"``&0`@#82P(`
-M`J0"`/1+`@`!D`(`&$P"``+)`0"=3`(``B\!`.%,`@`"+P$`\4P"``*N`0`X
-M30(``LD!`%Y-`@`"R0$`@4T"``)]`@"930(``E4!`*5-`@`"I`(`5DX"``(4
-M`@!Y3@(``OD!`)!.`@`"O0$`JDX"``$&``"O3@(``J\"`,Q.`@`"N@(`Z4X"
-M``*Z`@`,3P(``EH!`#5/`@`"9`$`:4\"``+)`0"*3P(``E4!`)9/`@`"I`(`
-MQT\"``+Y`0#>3P(``KT!`/A/`@`!!@``_4\"``*O`@`:4`(``KH"`#=0`@`"
-MN@(`4E`"``):`0!O4`(``JH!`/10`@`!D`(`&U$"``*D`@`W40(``9`"`%=1
-M`@`!D`(`>E$"``*D`@"640(``9`"`!Q2`@`"Y@$`*%("``*Q`0!M4@(``@X"
-M`'Y2`@`"M0$`NU("``*D`@#34@(``9`"`.Y2`@`!D`(`$E,"``*N`0`:4P(`
-M`HP!`$53`@`"#P(`SE,"``+&`0#D4P(``LD!`'%4`@`"+@(`HU0"``*Z`0#<
-M5`(``AH"`/M4`@`"N@(`&U4"``*Z`@!,50(``J0"`&-5`@`!D`(`?%4"``&0
-M`@"<50(``JX!`*15`@`"C`$`[54"``*<`0`G5@(``LD!`*)6`@`"#P(`M%8"
-M``)M`0`E5P(``9`"`$97`@`!D`(`8U<"``(O`@!T5P(``K4!`-M7`@`"\`$`
-M^%<"``+6`0`:6`(``H<!`#]8`@`"#`(`1U@"``*'`0"*6`(``M8!`-%8`@`"
-M+P$`YE@"``+)`0`660(``KH"`"Y9`@`"+P$`/%D"``)5`0!(60(``J0"`&E9
-M`@`"`P(`E5D"``+6`0#'60(``B\!`.19`@`"R0$`_%D"``+Y`0`36@(``KT!
-M`#!:`@`"N@(`35H"``*Z`@!@6@(``EH!`'E:`@`"T@$`CEH"``&0`@#;6@(`
-M`JX!`.=:`@`"J@$`<%L"``&0`@"+6P(``L@!`)];`@`"%`(`OEL"``+(`0#&
-M6P(``MH!`.5;`@`!`P``!%P"``)R`0`H7`(``G(!`$Q<`@`"+P$`>UP"``+Q
-M`0"<7`(``DX!`,9<`@`"+P$`\5P"``+Q`0`270(``B\!`"Y=`@`"3@$`45T"
-M``(O`0!N70(``B\!`*1=`@`"50$`L%T"``*D`@`<7@(``C(!`#M>`@`"_0$`
-M55X"``+Y`0!L7@(``KT!`(9>`@`!!@``BUX"``*O`@"H7@(``KH"`,5>`@`"
-MN@(`V%X"``):`0`$7P(``LD!`$!?`@`"P0$`CE\"``+9`0"L7P(``LD!``!@
-M`@`!!0``!6`"``*O`@`O8`(``L@!`')@`@`!!0``=V`"``*O`@!*80(``04`
-M`$]A`@`"KP(`DF$"``$%``"780(``J\"`"=B`@`"C@$`+V,"``)"`0!D8P(`
-M`B<"`)QC`@`!!0``H6,"``*O`@#>9`(``H0"``)E`@`!D`(`+F4"``&0`@!J
-M90(``9`"`!YF`@`!!0``(V8"``*O`@!]9@(``04``()F`@`"KP(`K68"``$%
-M``"R9@(``J\"`.1F`@`!!@``Z68"``*O`@!D9P(``04``&EG`@`"KP(`L6<"
-M``$&``"V9P(``J\"`.EG`@`!!@``[F<"``*O`@#]9P(``08```)H`@`"KP(`
-M46@"``([`0"B:`(``9`"`+]H`@`!D`(`W&@"``&0`@#\:`(``9`"`!-I`@`!
-M!@``&&D"``*O`@"<:0(``9`"`,EI`@`!!@``SFD"``*O`@`):@(``04```YJ
-M`@`"KP(`)&H"``)_`0!":@(``9`"`--J`@`"AP$`\VH"``+B`0!X:P(``BD"
-M`)9K`@`"CP$`PFL"``*P`@#N:P(``K`"`!IL`@`"L`(`0VP"``*P`@!L;`(`
-M`K`"`*!L`@`"L`(`Q6P"``*P`@#K;`(``K`"`!=M`@`"L`(`/&T"``*P`@!H
-M;0(``K`"`)1M`@`"L`(`O&T"``*P`@#D;0(``K`"``QN`@`"L`(`-&X"``*P
-M`@!;;@(``K`"`(1N`@`"L`(`J6X"``*P`@#:;@(``H("``=O`@`"@@(`.V\"
-M``*"`@!L;P(``H("`)UO`@`"@@(`SF\"``*"`@#[;P(``H("`"]P`@`"@@(`
-M97`"``+)`0!Z<`(``@8"`/-P`@`!`0``!G$"``+#`0`6<0(``D,!`*5Q`@`"
-MR0$`X7$"``*Z`@#]<0(``B\!``MR`@`"50$`%W("``*D`@!'<@(``G8!`/AS
-M`@`"*0(`C'0"``*R`@#"=`(``K("`/]T`@`"L@(`/'4"``*R`@!V=0(``K("
-M`))U`@`"L@(`L'4"``*R`@`:=@(``K("`'5V`@`"L@(`TG8"``*R`@`;=P(`
-M`K("`'!W`@`"L@(`V'<"``*R`@`A>`(``K("`%9X`@`"UP$`97@"``*R`@"3
-M>`(``J0!`*)X`@`"L@(`T'@"``*D`0#?>`(``K("``UY`@`"I`$`''D"``*R
-M`@!*>0(``J0!`%EY`@`"L@(`O7D"``+D`0#2?`(``KT"`/5\`@`"O0(`&'T"
-M``*]`@`[?0(``KT"`%=]`@`"O0(`<WT"``*]`@"N?0(``LD!`!-^`@`"O0(`
-M37X"``+)`0"[?@(``KT"`/Y^`@`"R0$`<G\"``)%`0"]?P(``9`"`.)_`@`!
-MD`(`_G\"``*U`0!!@`(``B\!`%2``@`"50$`8(`"``*D`@""@`(``OD!`)^`
-M`@`"N@(`O(`"``*Z`@#3@`(``EH!`.*``@`!D`(`/X$"``+1`0!O@0(``KH"
-M`-F!`@`"/`(`%(("``+)`0"+@@(``04``)""`@`"KP(`Q8("``+(`0`(@P(`
-M`04```V#`@`"KP(`TH,"``$%``#7@P(``J\"``F$`@`!!@``#H0"``*O`@"1
-MA`(``04``):$`@`"KP(`684"``$&``!>A0(``J\"`&:%`@`"C@$`;X8"``+6
-M`0"7A@(``D(!`+N&`@`"]P$`_H8"``(W`@#<B@(``L\!`#R+`@`"A`(`4(L"
-M``(H`@#*BP(``H0"`!F,`@`"!@(`*XP"``)$`@`]C`(``D,"`&:,`@`"A`(`
-MJ(P"``&F`0#]C`(``L,!`!Z-`@`"+`$`*HT"``)#`0!YC0(``@8"`(N-`@`"
-M1`(`G8T"``)#`@#NC0(``:8!`$..`@`"PP$`9(X"``(L`0!PC@(``D,!`-V.
-M`@`"!@(`\XX"``)$`@`)CP(``D,"`"Z/`@`"A`(`98\"``$V`@"/CP(``L,!
-M`+"/`@`"+`$`P(\"``)#`0`BD`(``L\!`$V0`@`""`(`B9`"``(&`@";D`(`
-M`D0"`*V0`@`"0P(`\Y`"``$V`@`?D0(``L,!`$"1`@`"+`$`3)$"``)#`0#M
-MD0(``FP!`"R2`@`";`$`?)("``*S`0"0D@(``E(!`,*2`@`"7`$`XI("``)2
-M`0`6DP(``E(!`.N3`@`">P$`/I0"``*T`0!WE`(``EP!`+B4`@`"!@(`RI0"
-M``)$`@#<E`(``D,"`"*5`@`!"@(`2I4"``+#`0!KE0(``BP!`'>5`@`"0P$`
-M498"``(N`0!=E@(``D,"`(^6`@`"A`(`T98"``(N`0#=E@(``D,"`'.7`@`"
-M9@$`B)<"``(N`0"4EP(``D,"`*^7`@`"?0(`PY<"``%4`0#8EP(``IT"`$>8
-M`@`"\@$`-)D"``+M`0!TF0(``NT!`*Z9`@`"7`$`ZIH"``*#`0#_F@(``G$!
-M`!2;`@`"J0$`*9L"``)F`0!#FP(``GT"`%>;`@`!5`$`<9L"``*=`@"DFP(`
-M`LD!`!B<`@`"+@(`/IP"``*Z`0!EG`(``AH"`+2<`@`"R0$`\IP"``)<`0`G
-MG0(``L$!`%&=`@`"+@$`99T"``)#`@"AG0(``EP!`&N>`@`!D`(`!J,"``(U
-M`@`/I`(``0,``*BD`@`!D`(`V*0"``&0`@`#I0(``9`"`#RE`@`!D`(`CZ4"
-M``&0`@"]I0(``9`"`..E`@`!D`(`%:8"``&0`@#6I@(``0,``.NF`@`!`P``
-M_J8"``$#```,IP(``0,``!^G`@`"_@$`*J<"``$#``"NIP(``LD!`.ZG`@`"
-MR0$`'J@"``+)`0!NJ`(``LD!`)ZH`@`"R0$`)*D"``+)`0"`J@(``D(!`/&K
-M`@`"R`$`.*P"``+K`0!XK`(``NL!`&&M`@`"+@$`<JT"``*)`0![K@(``D,!
-M`**N`@`"90$`L:X"``(U`@#&K@(``M8!`#&O`@`"\`$`EZ\"``*3`0!HL`(`
-M`D,"`-JP`@`"=0$`Z+`"``)#`@`FL0(``LD!`#"Q`@`":`$`.+$"``)'`0!L
-ML0(``@8"`'JQ`@`"1`(`D[$"``)#`@#1L0(``3,!`-VQ`@`"0P$`(+("``(&
-M`@!7L@(``3,!`&.R`@`"0P$`H;("``(&`@"SL@(``D0"`,6R`@`"0P(`#+,"
-M``$!```@LP(``L,!`$&S`@`"+`$`3;,"``)#`0"-LP(``@8"`,BS`@`!FP$`
-MU+,"``)#`0#FLP(``J0"`/BS`@`"I`(`W;0"``(N`0#NM`(``HD!`/JT`@`"
-M0P(`,[4"``(-`@!1M0(``BX!`&*U`@`"B0$`;K4"``)#`@!LM@(``J0"`'BV
-M`@`"0P(`J+8"``(-`@"XM@(``J0"`,2V`@`"0P(`_+8"``(&`@`_MP(``A,"
-M`$^W`@`"0P(`8[<"``$S`0!OMP(``D,!`+"W`@`"!@(`RK<"``)$`@#CMP(`
-M`D,"`#VX`@`!,P$`4+@"``+#`0!NN`(``BP!`'JX`@`"0P$`R;@"``(&`@#D
-MN`(``D0"`/VX`@`"0P(`4[D"``$S`0!GN0(``L,!`(FY`@`"+`$`E;D"``)#
-M`0#0N0(``@8"`.JY`@`"1`(``[H"``)#`@!6N@(``3,!`&ZZ`@`"PP$`D+H"
-M``(L`0"<N@(``D,!`."Z`@`"!@(`^KH"``)$`@`3NP(``D,"`%Z[`@`!,P$`
-M<KL"``+#`0"4NP(``BP!`*"[`@`"0P$`_[L"``(&`@"UO`(``0$``,B\`@`"
-MPP$`U+P"``)#`0`!OP(``G(!`!Z_`@`"=0$`;+\"``+)`0`_P`(``@P"`*/`
-M`@`"!@(`Q,`"``+_`0#6P`(``D,"`"K!`@`!6P$`/<$"``+#`0!)P0(``D,!
-M`)K!`@`"!@(`K,$"``+_`0`!P@(``5L!`!3"`@`"PP$`(,("``)#`0`LP@(`
-M`J0"`''"`@`"!@(`?\("``+_`0#*P@(``5L!`-W"`@`"PP$`Z<("``)#`0`I
-MPP(``@8"`#?#`@`"_P$`?<,"``%;`0"0PP(``L,!`)S#`@`"0P$`T<,"``*B
-M`0#APP(``D`"`,W$`@`"H@$`W<0"``)``@!%Q0(``DD!`,3%`@`"L@$`+<8"
-M``(T`@!=Q@(``J(!`&W&`@`"0`(`V<8"``(2`@`XQP(``B4"`)+'`@`"0@$`
-MLL<"``+P`0#(QP(``B4"`!'(`@`"0@$`)\@"``(E`@!0R`(``GT"`(/(`@`"
-M?0(`U<@"``*>`0`=R0(``D(!`#?)`@`"DP$`0\D"``(\`@#TR0(``LD!``;*
-M`@`"V0$`'<H"``$[`0`RR@(``IT"`*[*`@`"R0$`P,H"``(\`@#9R@(``3`"
-M`/3*`@`"G0(`H<L"``)"`0"MRP(``J\!`+G+`@`"#`(`7\P"``$[`0!TS`(`
-M`IT"`/C,`@`!,`(`$\T"``*=`@"4S@(``LD!`/G.`@`"0`$`#<\"``)#`@!7
-MSP(``O$!`(K/`@`"N@$`M<\"``)&`0#5SP(``LD!`%30`@`"+@(`;]`"``)`
-M`0"#T`(``D,"`.O0`@`"+P$`%-$"``)5`0`@T0(``J0"`$O1`@`",@$`:M$"
-M``+]`0"7T0(``OD!`*[1`@`"O0$`R-$"``$&``#-T0(``J\"`.K1`@`"N@(`
-M!]("``*Z`@!"T@(``EH!`&32`@`"R0$`EM("``+!`0#7T@(``B\!``C3`@`"
-M50$`%-,"``*D`@`_TP(``C(!`%[3`@`"_0$`>],"``+Y`0"6TP(``KT!`+#3
-M`@`!!@``M=,"``*O`@#6TP(``KH"`._3`@`!!@``]-,"``*O`@`5U`(``KH"
-M`)S4`@`"N@(`_-0"``+)`0`ZU0(``KH"`%S5`@`"6@$`H-4"``(&`@"RU0(`
-M`D0"`,O5`@`"0P(`.=8"``$S`0!,U@(``L,!`&K6`@`"+`$`=M8"``)#`0"C
-MU@(``J(!`+/6`@`"0`(`CM<"``(E`@#'UP(``D`"`![8`@`"R0$`*=H"``*$
-M`@#LVP(``O(!`"3<`@`"'`(`K]P"``$!``#=W`(``GD!`+G=`@`!`0``_-T"
-M``)Y`0#%W@(``0$```O?`@`">0$`==\"``$!``"SWP(``GD!``7@`@`!`0``
-M0^`"``)Y`0`<X0(``AT"`)7A`@`"-`$`G^("``+>`0`SXP(``K<!`+KC`@`"
-M\@$`[>,"``(>`@`8Y`(``L(!`$SE`@`"'`(`$N<"``+.`0!>YP(``MX!``+H
-M`@`"MP$`>>@"``)>`0``Z0(``K<!`,#I`@`"MP$``>H"``(<`@!\Z@(``K<!
-M`,CJ`@`"MP$`*>L"``*W`0!SZP(``K<!`+ON`@`"MP$`$^\"``&0`@`K[P(`
-M`9`"`*OP`@`"VP$`&/("``&0`@`S\@(``9`"`%/R`@`"0P(`L/("``*D`@"_
-M\@(``9`"`.+R`@`"I`(`\?("``&0`@#I\P(``J0"`/7S`@`!D`(`!_0"``*D
-M`@`.]`(``9`"`"OT`@`"I`(`,_0"``&0`@!:]`(``J0"`&;T`@`!D`(`>/0"
-M``*D`@!_]`(``9`"`)ST`@`"I`(`I/0"``&0`@#H]`(``J0"`$CU`@`"I`(`
-M6?4"``)5`0"W]0(``@8"`"/V`@`!.@$`+_8"``&G`0`^]@(``D,!`([V`@`"
-M!@(`_/8"``%0`0`(]P(``D,!`(?W`@`!D`(`J/<"``&0`@`'^`(``N$!`!?X
-M`@`"2P$`:O@"``(&`@"S^`(``5`!`+_X`@`"0P$`1_D"``&0`@!H^0(``9`"
-M`+_Y`@`"*@$`S_D"``)+`0!#^@(``@8"`(KZ`@`!.@$`EOH"``&G`0"E^@(`
-M`D,!`.OZ`@`"!@(`2/L"``$!``!7^P(``D,!`'[[`@`!70$`X?L"``*D`@#H
-M^P(``9`"`/K[`@`"I`(``?P"``&0`@"1_`(``J0"`)C\`@`!D`(`JOP"``*D
-M`@"Q_`(``9`"`$?]`@`".0(`?/T"``(@`@"$_0(``ML!`-K]`@`!D`(`[_T"
-M``&0`@`+_@(``9`"`##^`@`!D`(`@OX"``()`@"*_@(``BT!`/;^`@`"I`(`
-M"?\"``&0`@`O_P(``J0"`$+_`@`!D`(`20(#``(A`@#_`@,``O(!`&D$`P`"
-M\@$`CP0#``+R`0`#!0,``FL!``T&`P`"I`(`-`8#``*D`@#_!@,``C\!`"`'
-M`P`"Z0$`.@<#``$D`@!(!P,``20"`,H'`P`!D`(`]@<#``&0`@`F"`,``J0"
-M`#L(`P`!D`(`@@@#``&0`@#@"`,``9`"`$D)`P`!D`(`N@D#``*D`@#,"0,`
-M`9`"`.T)`P`"[P$`^0D#``(!`@`/"@,``J0"`"L*`P`"I`(`1PH#``*D`@!I
-M"@,``HT!`'L*`P`!D`(`S`H#``*D`@#;"@,``9`"`/P*`P`"[P$`"`L#``(!
-M`@`>"P,``J0"`#H+`P`"I`(`5@L#``*D`@!X"P,``HT!`(H+`P`!D`(`N@L#
-M``*D`@#&"P,``JX!`.0+`P`"C`$`[PL#``&0`@`'#`,``9`"`!X,`P`!D`(`
-M\PP#``&0`@!S#0,``@8"`(T-`P`"1`(`I@T#``)#`@`$#@,``0$``!@.`P`"
-MPP$`.0X#``(L`0!%#@,``D,!`'\/`P`!!0``A`\#``*O`@`Z$`,``04``#\0
-M`P`"KP(`4Q`#``+!`0!T$`,``L0!`%P1`P`"[@$`S!$#``%!`0#M$0,``M\!
-M``42`P`"L0$`A1(#``+N`0"8$@,``IT!`,H2`P`"&@(`91,#``)M`0!O$P,`
-M`CT"`!L4`P`"P0$`?Q0#``+)`0#?%`,``BX"``(5`P`"N@$`$Q4#``(:`@"K
-M%0,``ID!`#@6`P`"R0$`L18#``*9`0!+%P,``KH"`&H7`P`"N@(`GQ<#``*9
-M`0`(&`,``KH"`%,8`P`"N@(`DA@#``(O`0"X&`,``E4!`,08`P`"I`(`[Q@#
-M``(R`0`.&0,``OT!`"<9`P`"^0$`/AD#``*]`0!8&0,``08``%T9`P`"KP(`
-M>AD#``*Z`@"3&0,``08``)@9`P`"KP(`M1D#``*Z`@#]&0,``KH"`$`:`P`"
-M6@$`8QH#``*Z`@#`&@,``N8!`.P:`P`"P0$`!1L#``*Q`0!*&P,``@X"`(P;
-M`P`!`P``]QL#``+1`0`<'`,``JP!`$$<`P`"K`$`9AP#``*L`0"+'`,``JP!
-M`+@<`P`"H`$`Y1P#``*@`0`<'0,``J`!`$D=`P`"H`$`51T#``*D`@",'0,`
-M`J`!`+D=`P`"H`$`Q1T#``*D`@#J'0,``JP!``\>`P`"K`$`-!X#``*L`0!A
-M'@,``J`!`(8>`P`"K`$`S!X#``*D`@!&'P,``9`"`&0?`P`!D`(`>A\#``*D
-M`@"8'P,``KH!`*D?`P`"I`(`R1\#``*L`0#5'P,``J0"`/H?`P`"K`$`!B`#
-M``*D`@`](`,``J`!`$D@`P`"I`(`;B`#``*L`0!Z(`,``J0"`(\@`P`"A`$`
-MI"`#``+E`0#1(`,``J`!`/X@`P`"H`$`*R$#``*@`0!8(0,``J`!`'TA`P`"
-MK`$`CB$#``*D`@"N(0,``JP!`+HA`P`"I`(`YR$#``*@`0`,(@,``JP!`#DB
-M`P`"H`$`32(#``(]`@!R(@,``JP!`'XB`P`"I`(`LB(#``*@`0"^(@,``J0"
-M`.`B`P`"K`$`["(#``*D`@`!)`,``BX!``TD`P`"0P(`:R0#``&0`@"*)`,`
-M`9`"`+PD`P`!D`(`X20#``(N`0#M)`,``D,"`/DD`P`"T0$`(24#``+1`0!E
-M)@,``@X"`'$F`P`"I`(`ER8#``(.`@"C)@,``J0"`"HG`P`!D`(`0R<#``&0
-M`@"*)P,``J0"`*LG`P`"N@$`QR<#``(``@#<)P,``@`"`.PG`P`"I`(`$"@#
-M``&0`@`N*`,``9`"`$8H`P`"I`(`6R@#``$%``!@*`,``J\"`&TH`P`"!@(`
-MLB@#``$!``"^*`,``D,!`-,H`P`!!@``V"@#``*O`@#E*`,``@8"`"HI`P`!
-M`0``-BD#``)#`0!=*0,``@8"`*DI`P`!`0``N"D#``)#`0#,*0,``@8"`!@J
-M`P`!`0``)RH#``)#`0`[*@,``@8"`(`J`P`!`0``C"H#``)#`0"F*@,``@8"
-M`.LJ`P`!`0``]RH#``)#`0`+*P,``@8"`%@K`P`!`0``9"L#``)#`0"A*P,`
-M`NX!`,DK`P`"F@$`+2P#``+1`0!S+`,``M$!`(4L`P`"R0$`W"P#``(N`@`(
-M+0,``KH!`"(M`P`"&@(`3"T#``+)`0"M+0,``BX"`-DM`P`"N@$`\RT#``(:
-M`@`K+@,``LD!`%8N`P`"7`$`>2X#``+!`0"Y+P,``BX!`,4O`P`"0P(`-C`#
-M``*D`@!],`,``O$!`)(P`P`"N@$`Z#`#``$%``#M,`,``J\"``@Q`P`"O`$`
-M>#$#``*D`@#M,0,``BX!`/DQ`P`"0P(`$3(#``(N`0`=,@,``D,"`"DR`P`"
-MN@$`$3,#``*[`0`K,P,``KL!`$4S`P`"8@$`5S,#``+%`0!I,P,``NP!`($S
-M`P`"@@$`DS,#``*P`0"E,P,``CH"`+DS`P`"*P(`Y#,#``+)`0!%-`,``BX"
-M`'(T`P`"N@$`C#0#``(:`@#F-`,``EP!`/@T`P`"R0$`'C4#``$&```C-0,`
-M`J\"`#,U`P`"7`$`6C4#``+!`0"X-@,``OL!`,(V`P`!`P``(S<#``*Q`0"\
-M-P,``NX!`-,W`P`"G0$`%C@#``(:`@"M.`,``LD!`-\X`P`"/`$`)3D#``+R
-M`0#%.0,``KH"```Z`P`"+P$`&#H#``)5`0`D.@,``J0"`$\Z`P`",@$`;CH#
-M``+]`0"..@,``OD!`*DZ`P`"O0$`RCH#``*Z`@#K.@,``KH"`!\[`P`"6@$`
-MF3L#``(\`0"P.P,``O8!`&8\`P`"\@$`[CT#``(N`@`%/@,``AH"`#4^`P`"
-M7`$`2#X#``*Q`0"R/@,``LD!`.<^`P`"/`$`+S\#``(\`0!Q/P,``CP!`(P_
-M`P`"\@$`SS\#``)1`0`E00,``N<!`$M!`P`"R0$`:4$#``(O`0!W00,``E4!
-M`(-!`P`"I`(`I4$#``+Y`0"\00,``KT!`-E!`P`"N@(`]D$#``*Z`@`B0@,`
-M`EH!`$)"`P`"9`$`IT(#``('`@#20@,``CP!`!=#`P`"/`$`5D,#``(\`0!I
-M0P,``E$!`'U#`P`"Q`$`M4,#``)1`0`H10,``K$!`%M&`P`"+@(`;48#``(:
-M`@"V1@,``L$!`/]&`P`"/`$`)D<#``*6`0""1P,``HL!`(I'`P`!00$`JT<#
-M``+?`0#*1P,``J,!`-9'`P`"BP$`#D@#``(``@`>2`,``J0"`&5(`P`"6@$`
-M>D@#``(X`@"G2`,``M$!`,E(`P`"?0(`V$@#``+2`0#L2`,``LD!``I)`P`"
-M^0$`(4D#``*]`0`^20,``KH"`%M)`P`"N@(`<DD#``):`0"320,``LD!`*-)
-M`P`"L0$`W$D#``*Z`0"A2@,``BX!`*U*`P`"0P(`"4L#``$%```.2P,``J\"
-M`"A+`P`"6@$`-$L#``)#`@!I2P,``K4!`)I+`P`"I`(`IDL#``)#`@#"2P,`
-M`@X"`-!+`P`"I`(`W$L#``)#`@#H2P,``E<!`$E,`P`"R0$`K4P#``*Z`0`6
-M3@,``J`!`'-.`P`"+@$`@TX#``)#`@"83@,``M$!`+U.`P`!`P``[4X#``&0
-M`@`S3P,``9`"`%9/`P`!D`(`K$\#``&0`@#+3P,``9`"`"!0`P`!D`(`6U`#
-M``(N`0!K4`,``D,"`'M0`P`"P0$`MU`#``(N`0#'4`,``D,"`-50`P`!XP$`
-MZE`#``*=`@`#40,``J0"`#-1`P`"PP(`7U$#``&0`@!^40,``9`"`(-1`P`"
-MPP(`\5$#``+)`0!'4@,``OD!`&Q2`P`"O0$`FU(#``*Z`@`M4P,``08``#)3
-M`P`"KP(`4U,#``*Z`@!Z4P,``EH!`*!3`P`!D`(`OU,#``&0`@`&5`,``LD!
-M`$)4`P`"L0$`:U0#``)5`0!W5`,``J0"`*Y4`P`!D`(`S50#``&0`@"P50,`
-M`9`"`,U5`P`!D`(`4U8#``*5`0!R5@,``B4"`*=6`P`!D`(`PU8#``&0`@#Q
-M5@,``9`"``U7`P`!D`(`5U<#``&0`@!V5P,``9`"`*A7`P`!D`(`U5<#``(N
-M`0#E5P,``D,"`/%7`P`"T0$`!%@#``)5`0`06`,``J0"`#E9`P`"+@$`15D#
-M``)#`@")60,``BX!`)59`P`"0P(`J5D#``(:`@"]6@,``H0"`!%;`P`!!@``
-M%EL#``*O`@`K6P,``BX!`#=;`P`"0P(`8%L#``+)`0#76P,``LD!`$9<`P`"
-M&@(``%T#``*D`@!^70,``J0"`-)=`P`"I`(`\5T#``(N`0#]70,``D,"`!%>
-M`P`"&0(`+5\#``*D`@!R7P,``J0"`)%?`P`"+@$`G5\#``)#`@"Q7P,``AD"
-M`/!?`P`"I`(`0&`#``*D`@"98`,``J0"`,I@`P`"J`$`\6`#``(N`0#]8`,`
-M`D,"``EA`P`"&@(`4&$#``&0`@`V9`,``C`!`%9D`P`",`$`@60#``(P`0`V
-M90,``C`!`%9E`P`",`$`@V4#``(P`0#390,``I4!`!)F`P`"X0$`8&8#``+-
-M`0"\9@,``CT!`,1F`P`"A@$`TV8#``$#```?9P,``F,!`#MG`P`"G`$`F&<#
-M``*D`@"Z;`,``0D``,IL`P`!"0``VFP#``)?`0`P;0,``A<"`!IN`P`"I0$`
-M1VX#``(+`@!:;@,``J4!`#%O`P`"R0$`BV\#``+=`0"P;P,``H0"`-EO`P`"
-M3P$`7G`#``*A`0"=<`,``IP!`/IP`P`"P`$`*G(#``*D`@!3<P,``0D``&1S
-M`P`!"0``=',#``)?`0"K<P,``0D``+QS`P`!"0``S',#``)?`0!3=`,``9`"
-M`*)T`P`!D`(`PW0#``)3`0#;=`,``E,!`/-T`P`"4P$`"W4#``)3`0`C=0,`
-M`E,!`#MU`P`"4P$`674#``&0`@"D=0,``9`"`-1U`P`!D`(`?78#``)3`0#;
-M=@,``@8"`.UV`P`"_P$`?G<#``*$`@"W=P,``H0"`+YW`P`!^@$`T7<#``+#
-M`0#==P,``D,!`"1X`P`"!@(`-G@#``+_`0"/>`,``?H!`*)X`P`"PP$`KG@#
-M``)#`0`*>0,``HH!`!AY`P`"50$`)'D#``*D`@!>>0,``H`!`&QY`P`"50$`
-M>'D#``*D`@"B>0,``HH!`+1Y`P`"50$`P'D#``*D`@`->@,``H`!`*=Z`P`"
-M0`$`LWH#``)#`@!B?0,``CL"`'A]`P`"D`$`9GX#``*X`0![?@,``=@!`-!^
-M`P`".P(`YGX#``*0`0"*?P,``K@!`-%_`P`"N`$`E(`#``)P`0"M@`,``GT!
-M`,Z``P`"RP$`,X$#``$#``"4A`,``LH!`!J%`P`"R@$`-H4#``*$`@`@A@,`
-M`F`!`(R'`P`!D`(`HX<#``&0`@"SAP,``J0"`/Z'`P`!!P``1H@#``&0`@!Y
-MB`,``0<``)N(`P`!!P``XX@#``&0`@!8B0,``0<``*")`P`!D`(`TXD#``$'
-M``#UB0,``0<``#V*`P`!D`(`IHH#``$'``"WB@,``0<``$J+`P`!D`(`WXL#
-M``&0`@!RC`,``9`"`)R,`P`"I`(`:(T#``(^`0`GD`,``O@!`)^1`P`!`P``
-MKI$#``$'``"XD0,``0<``,.1`P`!!P``S9$#``$'```6E@,``0<``!N6`P`"
-M=0(`H98#``)?`0"QE@,``J0"`,V6`P`"(P(`^)8#``$&``#]E@,``J\"`$67
-M`P`"F0(`7Y<#``*9`@!YEP,``ID"`/&7`P`"*0(`$I@#``*C`@`OF`,``J,"
-M`%"8`P`"HP(`;9@#``*C`@".F`,``J,"`*N8`P`"HP(`S)@#``*C`@#IF`,`
-M`J,"`":9`P`"HP(`/9D#``*C`@!KF0,``J,"`(B9`P`"HP(`J9D#``*C`@#&
-MF0,``J,"`.>9`P`"HP(`!)H#``*C`@`EF@,``J,"`$*:`P`"HP(`8YH#``*C
-M`@"`F@,``J,"`*&:`P`"HP(`OIH#``*C`@#?F@,``J,"`/R:`P`"HP(`'9L#
-M``*C`@`ZFP,``J,"`%N;`P`"HP(`>)L#``*C`@"9FP,``J,"`+:;`P`"HP(`
-MUYL#``*C`@#TFP,``J,"`!6<`P`"HP(`,IP#``*C`@!3G`,``J,"`'"<`P`"
-MHP(`D9P#``*C`@"NG`,``J,"`..<`P`"T@(`%)T#``+2`@!)G0,``M("`'J=
-M`P`"T@(`KYT#``+2`@#@G0,``M("`!6>`P`"T@(`1IX#``+2`@![G@,``M("
-M`*R>`P`"T@(`X9X#``+2`@`2GP,``M("`$>?`P`"T@(`>)\#``+2`@"MGP,`
-M`M("`-Z?`P`"T@(``Z`#``)*`0`+H`,``K8!`!F@`P`"M@$`(:`#``*8`0`M
-MH`,``J0"`#6@`P`"S`$`1:`#``*1`0!5H`,``I$!`)&@`P`"D0$`HZ`#``*1
-M`0#,H`,``JT!`-^@`P`"K0$`_*`#``*M`0`/H0,``JT!`"NA`P`"50$`?*$#
-M``(&`@#:H0,``0$``.JA`P`"0P$`)Z(#``(O`0`[H@,``J0"`$>B`P`"50$`
-MEJ(#``)#`@#_H@,``@8"`'6C`P`!`0``A:,#``)#`0#"HP,``B\!`-:C`P`"
-MI`(`XJ,#``)5`0`DI`,``D0"`)ND`P`!`0``JZ0#``+#`0#0I`,``BP!`.2D
-M`P`"0P$`(:4#``(O`0`UI0,``J0"`$&E`P`"50$`>:4#``(N`0"7I0,``D,"
-M`*.E`P`"!@(`OZ4#``(N`0#)I@,``0$``-VF`P`"PP$`!J<#``(L`0`:IP,`
-M`D,!`%>G`P`"+P$`:Z<#``*D`@!WIP,``E4!`+FG`P`"+@$`U:<#``)#`@!E
-MJ`,``@8"`(VH`P`!!@``DJ@#``*O`@"@J`,``D0"`+RH`P`"0P(`^:@#``*Z
-M`@`8J0,``B\!`&FI`P`"A`(`3:H#``(J`@"-J@,``0$``*&J`P`"PP$`RJH#
-M``(L`0#EJ@,``D,!`">K`P`"+P$`.ZL#``*D`@!'JP,``E4!`).K`P`"A`(`
-MQZL#``(N`0#@JP,``HD!`/2K`P`"0P(`'*P#``*Z`@#@K`,``BX!`/&L`P`"
-MB0$`_:P#``)#`@#"K0,``B\!`!"N`P`"+@(`6*X#``+1`0!NK@,``KH!`(VN
-M`P`"&@(`QZX#``+S`0#1KP,``M0!`/.O`P`"-`(`$[`#``*\`@!'L`,``DH!
-M`$^P`P`"T`$`5[`#``+0`0!?L`,``K8!`&NP`P`"M@$`=[`#``*8`0"#L`,`
-M`J0"`(NP`P`"S`$`G[`#``%O`0"ZL`,``IT"`,JP`P`"P0$`[+`#``+5`0#Z
-ML`,``M4!`!FQ`P`!"0``)K$#``$)``!#L0,``0<``$VQ`P`!!P``;K$#``%J
-M`0!\L0,``0<``(*Q`P`!:@$`B+$#``$'``".L0,``6H!`)2Q`P`!!P``FK$#
-M``%J`0"AL0,``6H!`+>Q`P`!:@$`OK$#``%J`0#-L0,``6H!`-2Q`P`!:@$`
-MW;$#``%J`0#DL0,``6H!`/.Q`P`!:@$``+(#``$'```:L@,``6H!`"BR`P`!
-M:@$`-[(#``%J`0`^L@,``6H!`$>R`P`!:@$`3K(#``%J`0!FL@,``0<``'BR
-M`P`!`P``M;(#``$#``#9L@,``0<``.JR`P`!!P``%K,#``%J`0`DLP,``6H!
-M`$ZS`P`!:@$`=+,#``%J`0"!LP,``6H!`-.S`P`"?@(`Y[,#``$#``!?M`,`
-M`OT!`(6T`P`",@$`C;0#``+S`0"RM`,``KT!`,RT`P`"O0$`8;4#``$%``!F
-MM0,``J\"`'BU`P`"!@(`O[4#``$%``#$M0,``J\"``:V`P`!`0``$K8#``)#
-M`0!/M@,``B\!`&.V`P`"I`(`:[8#``)5`0"OM@,``@8"`-&V`P`"1`(`\K8#
-M``)#`@!,MP,``0$``&"W`P`"PP$`@;<#``(L`0"1MP,``D,!`,ZW`P`"+P$`
-MXK<#``*D`@#NMP,``E4!`"&X`P`"O`$`2[@#``(N`0!;N`,``D,"`'>X`P`"
-M0P(`QK@#``$#```!N0,``I0!`$6Y`P`"A0$`?;D#``*Z`@"8N0,``B\!`*JY
-M`P`"I`(`LKD#``)5`0#NN0,``KH"``FZ`P`"/@(`&[H#``(;`@#VN@,``04`
-M`/NZ`P`"KP(`+KL#``)]`@`_NP,``0$``%2[`P`"G0(`P;T#``+]`0#JO0,`
-M`C(!`!B^`P`"R0$`A+X#``+)`0#9O@,``KH"`!B_`P`"R0$`>K\#``*Z`@#`
-MP`,``I0!`!;!`P`"U`$`,<$#``*]`0!IP0,``E4!`)3!`P`"P0$`L<$#``)]
-M`@#%P0,``6\!`-K!`P`"G0(`-<,#``+S`0"6PP,``0,``,K#`P`"60$`,\0#
-M``)9`0"<Q`,``ED!``7%`P`"60$`3\8#``$#``"2Q@,``ED!``''`P`"60$`
-M9L<#``)9`0#+QP,``ED!`#'(`P`"60$`EL@#``)9`0#@R`,``IL"`!3)`P`"
-M60$`7LD#``*;`@"2R0,``ED!`-S)`P`"FP(`$,H#``)9`0!:R@,``IL"`([*
-M`P`"60$`Y,H#``*5`0`BRP,``I4!`&#+`P`"E0$`GLL#``*5`0#<RP,``I4!
-M`!?,`P`"E0$`P,P#``$)``#+S`,``0D``.G.`P`"C`(`$L\#``*,`@!4SP,`
-M`0,``&G/`P`!!P``=<\#``$'``"!SP,``0<``(K/`P`!!P``D,\#``$'``"M
-MSP,``0<``.W/`P`"Q@(`(=`#``*_`@!6T`,``6H!`&/0`P`!:@$`C]`#``%J
-M`0"LT`,``6H!`+70`P`!:@$`O-`#``%J`0#8T`,``6H!`.;0`P`!:@$`.=(#
-M``+S`0"STP,``J4!`.'3`P`""P(`]M,#``*E`0!UUP,``J4!`*/7`P`""P(`
-MN-<#``*E`0!EVP,``J4!`)/;`P`""P(`J-L#``*E`0`EWP,``J4!`%/?`P`"
-M"P(`:-\#``*E`0"PX0,``@8"`'_C`P`"A`(`T^0#``$!``!!Y0,``BH"`%'E
-M`P`"PP$`<>4#``(L`0"1Y0,``L,!`*?E`P`"1`(`W.4#``(L`0#QY0,``GX!
-M`";F`P`"+`$`9>8#``*$`@#7Y@,``H0"`!'G`P`"0P$`(^<#``)#`@"IZ0,`
-M`L8"`-#I`P`"Q@(`"^L#``(N`@!;ZP,``LD!`*WK`P`"N@$`WNL#``+1`0`<
-M[`,``HT!`$'L`P`"&@(`;.P#``+)`0#'[`,``ID!``7M`P`!G`(`#NT#``&<
-M`@`A[0,``50"`%+M`P`!D@(`&.X#``&2`@!H[@,``F4"`.7N`P`!2@(`\.X#
-M``%*`@#Y[@,``50"``3O`P`!5`(`&.\#``%*`@"B[P,``4H"`)'P`P`!D@(`
-M0?$#``*G`@!Z\0,``J<"`/?Q`P`"IP(`'/(#``+#`@"&\@,``J<"`+#R`P`"
-M=P(`T/(#``*G`@#L\@,``L,"`,GS`P`"PP(`/O0#``)]`@#*]`,``6`"`-_T
-M`P`"?0(`\_0#``%6`@`%]0,``IT"`(KU`P`!8`(`G_4#``)]`@"S]0,``58"
-M`,7U`P`"G0(`_/4#``*R`@!>]@,``HT"`*KV`P`"T0(`]/8#``*I`@`U]P,`
-M`;4"`&WW`P`"40(`>_@#``+``@"D^`,``F$"`+KX`P`!I0(`RO@#``)J`@#7
-M^`,``E("`.GX`P`"7`(`7_D#``$)``!\^0,``0D``(SY`P`!"0``G/D#``'.
-M`@"\^0,``K("`,OY`P`!`0``UOD#``$)``#W^0,``J,"``OZ`P`!"0``.OH#
-M``&W`@!`^@,``0D``$3Z`P`!TP(`2OH#``$)``!2^@,``0D``&#Z`P`!"0``
-M9?H#``*=`@#)^@,``4H"`!#[`P`"TP(`.OL#``*D`@!"^P,``H4"`)7[`P`"
-M8@(`V_L#``*C`@#U^P,``J,"`%W\`P`"HP(`A?P#``)O`@!0_0,``H$"`%O]
-M`P`"L@(`I/T#``*C`@#$_0,``DP"`#[^`P`"L`(`7OX#``*P`@!I_@,``4H"
-M`*G^`P`"L`(`ROX#``*P`@#L_@,``K`"`!#_`P`"L`(`-_\#``*P`@!:_P,`
-M`H8"`'7_`P`"L`(`>_\#``%*`@#$_P,``9("`,G_`P`"M@(`X_\#``&2`@!)
-M``0``9("`%4`!``!I0(`?@`$``):`@"7``0``K("`*\`!``!"0``N@`$``$)
-M``"A`00``J,"`+@!!``!D@(`^0$$``*!`@`J`@0``J,"`$`"!``!2@(`?0($
-M``&2`@#(\@,``J<"`&#S`P`"=P(`X/,#``)W`@#5]@,``J,"`"[[`P`"IP(`
-MOP($``$!``#8`@0``0<``'P#!``!`0``D`4$``*S`@#S!00``J8"`!L&!``!
-M`0``1`8$``*F`@":!@0``0,``*0&!``!`P``X08$``$!``!7!P0``D8"`(D'
-M!``!`0``V`<$``*'`@#R!P0``I,"`!<(!``!G`(`'0@$``$'```Y"`0``0<`
-M`$T(!``!!P``5@@$``$'``!<"`0``0<``&((!``"S0(`FP@$``*'`@"]"`0`
-M`M`"`!D)!``"T`(`2@D$``*C`@!:"00``0$``'L)!``"T`(`G0D$``$'``"K
-M"00``H`"`/D*!``!!P```PL$``*``@`+"P0``K("`/P+!``!!P``!@P$``*`
-M`@`.#`0``K("`+T,!``!!P``QPP$``*``@#/#`0``K("`%8-!``!!P``8`T$
-M``*``@!H#00``K("`-D-!``!!P``XPT$``*``@#K#00``K("`&@.!``!!P``
-M<@X$``*``@!^#@0``J,"`)X.!``!!P``J`X$``*``@#*#@0``J,"`/$.!``"
-MHP(`-P\$``)K`@!0#P0``K("`&,/!``!`0``H0\$``)&`@#@#P0``0<``.@/
-M!``"@`(`!Q`$``*P`@`W$`0``0,``'P0!``"T`(`JA`$``)K`@"W$`0``KP"
-M`-D0!``"L@(`Z1`$``$!```"$00``M`"``\1!``"O`(`2Q$$``$#``"P$00`
-M`M`"```2!``"HP(`$Q($``$!```8$@0``E@"`#@2!``!I0(`J1($``)?`@#-
-M$@0``0<``-<2!``"@`(`XQ($``*C`@`3$P0``FL"`"P3!``"9`(`R!4$``)D
-M`@`/%@0``E\"`(@6!``"9`(`SA8$``)?`@`:%P0``0<``"07!``"@`(`+!<$
-M``*R`@!N%P0``H$"`),7!``!I0(`TQ<$``)?`@`:&`0``E\"`(P8!``"7P(`
-MKQ@$``)K`@#$&`0``;4"`/@8!``!!P```AD$``*``@`.&00``J,"`%T:!``"
-M9`(`NQH$``&E`@`F&P0``E\"`(@;!``"9`(`DQL$``$%``"G&P0``J\"`.H;
-M!``"9`(`]1L$``$%```)'`0``J\"`%4<!``"7P(`?QP$``)D`@"I'`0``F0"
-M`/$<!``!!@``]AP$``*O`@`_'@0``F0"`(,>!``"7P(`T1X$``)?`@`('P0`
-M`ET"`&(?!``"7P(`E1\$``)D`@"T'P0``H@"`'\@!``"7P(`C"`$``$%``#1
-M(`0``J\"`)LA!``"9`(`VB$$``)?`@`S(@0``E\"`%XB!``!!@``8R($``*O
-M`@"'(@0``F0"`,LB!``"7P(`'R,$``)?`@!K(P0``04``'`C!``"KP(`HB,$
-M``*$`@#C(P0``E\"`/<C!``":0(`,R0$``)?`@!W)`0``E\"`+HD!``"7P(`
-MV"0$``*!`@#Q)`0``F0"`!HE!``"B`(`@B4$``)E`@!<)@0``LL"`(PF!``"
-M1P(`ZB8$``&E`@`C)P0``F<"`%LG!``"8@(`<B<$``&U`@#D)P0``L4"`.XG
-M!``"7`(`"B@$``%)`@`I*`0``M`"`-8H!``"7@(`YB@$``*!`@`R*@0``EX"
-M`%(J!``"7@(`Y"L$``*(`@!V+`0``H$"`.4L!``"70(`2RT$``),`@!5+00`
-M`K,"`)\M!``"2`(`UBT$``),`@#_+00``J,"`#LN!``"80(`5RX$``)1`@`0
-M+P0``K,"`(,O!``"Q0(`H2\$``)J`@#1+P0``E("`/0O!``"L@(`$#`$``$!
-M```^,`0``D8"`%DQ!``"R@(`NC$$``$!``#Z,00``M`"`)`R!``"R@(`LC($
-M``+0`@`V,P0``FL"`"@&!``"JP(`F`<$``*K`@"Q!P0``H<"`.4)!``"HP(`
-MK2<$``)K`@#;)P0``J,"`/8H!``"70(`;RT$``*!`@#.+00``ET"`#@R!``"
-MR@(`9#,$``&2`@`L-`0``9("`.$T!``!D@(`SC4$``&2`@!]-P0``0,``*DX
-M!``"FP(`&#H$``*;`@#@.@0``IL"`(\\!``"<`(`Z#T$``)P`@`C/P0``0,`
-M`+=`!``"<`(`-$$$``)P`@`*0@0``G`"`#-"!``!"0``5D($``$)``!C0@0`
-M`0D``&Q"!``!"0``=4($``$)``!^0@0``0D``(="!``!"0``D$($``$)``"9
-M0@0``0D``*)"!``!"0``JT($``$)``"T0@0``0D``+U"!``!"0``PT($``$)
-M```60P0``D\"`%Q(!``"<`(`G$@$``)P`@#<2`0``G`"`$))!``"<`(`G4D$
-M``)P`@`"2@0``G`"`'%*!``!I0(`DTH$``)P`@"?2@0``G`"`$9+!``"<`(`
-M:4L$``)P`@!F3`0``G`"`(E,!``"<`(`%$T$``)P`@`V300``G`"`)I-!``"
-M<`(`IDT$``)P`@#4300``G`"`/9-!``"<`(`5TX$``)P`@!C3@0``G`"`)E.
-M!``"<`(`NTX$``)P`@`53P0``G`"`"%/!``"<`(`A4\$``)P`@"13P0``G`"
-M`/5/!``"<`(``5`$``)P`@!E4`0``G`"`'%0!``"<`(`U5`$``)P`@#A4`0`
-M`G`"`$51!``"<`(`45$$``)P`@"U400``G`"`,%1!``"<`(`15($``)P`@!1
-M4@0``G`"`+52!``"<`(`P5($``)P`@`L4P0``G`"`#A3!``"<`(`1E,$``)P
-M`@!04P0``G`"`.53!``"<`(`\5,$``)P`@!55`0``G`"`&%4!``"<`(`V50$
-M``)P`@#F5`0``G`"`$E5!``"<`(`5E4$``)P`@!;5@0``G`"`&E6!``"<`(`
-M"U<$``)P`@`95P0``G`"`'57!``"<`(`@5<$``)P`@`(6`0``G`"`!18!``"
-M<`(`F%@$``)P`@"D6`0``G`"`!19!``"<`(`(%D$``)P`@`N6@0``G`"`#Q:
-M!``"<`(`&%L$``)P`@`F6P0``G`"`.!;!``"<`(`[EL$``)P`@`K7`0``0<`
-M`#A<!``!!P``>%T$``$!``!P7@0``D\"`!5?!``!M0(`C%\$``*F`@"Q7P0`
-M`0$``+E?!``"JP(`_E\$``*F`@`(8`0``K("`&U@!``"JP(`M6`$``*F`@#V
-M8`0``0$```-A!``!`0``"V$$``*K`@`5800``J<"`%5A!``"L@(`W&$$``*C
-M`@#T800``08``/EA!``"KP(`)6($``*R`@"-8@0``J,"`*5B!``!!@``JF($
-M``*O`@!.8P0``0$``(QC!``!`0``I6,$``+0`@#,8P0``0$``.5C!``"T`(`
-M#&0$``$!```E9`0``M`"`$QD!``!`0``960$``+0`@",9`0``0$``*5D!``"
-MT`(`S&0$``$!``#E9`0``M`"``QE!``!`0``)64$``+0`@!,900``0$``&5E
-M!``"T`(`C&4$``$!``"E900``M`"`,QE!``!`0``Y64$``+0`@`,9@0``0$`
-M`"5F!``"T`(`3&8$``$!``!E9@0``M`"`(QF!``!`0``I68$``+0`@#,9@0`
-M`0$``.5F!``"T`(`#&<$``$!```E9P0``M`"`$QG!``!`0``96<$``+0`@",
-M9P0``0$``*5G!``"T`(`S&<$``$!``#E9P0``M`"``QH!``!`0``)6@$``+0
-M`@!,:`0``0$``&5H!``"T`(`?6@$``$!``"8:`0``M`"`*UH!``!`0``RV@$
-M``+0`@`.:00``J,"`!AI!``!`0``,VD$``+0`@"K:00``0$``,9I!``"T`(`
-M.VH$``*'`@!5:@0``J8"`'9J!``!`0``RFH$``*C`@"`:P0``04``(EK!``"
-MKP(`F6L$``)K`@"M:P0``J,"`+5K!``"AP(`WFL$``$%``#G:P0``J\"`/=K
-M!``":P(`&VP$``*'`@`B;`0``0$``#YL!``"T`(`J6P$``*C`@"Q;`0``H<"
-M``MM!``!`0``*6T$``+0`@#,;00``G`"`,)N!``"7P(`W&X$``$!``#U;@0`
-M`I,"`'AO!``"7P(`M&\$``)P`@!><`0``E\"`(9P!``!`0``GW`$``*3`@#F
-M<`0``H<"`/!P!``!`0``"7$$``*3`@"W<00``0$``(AR!``!`0``H7($``*3
-M`@!]<P0``0$``(]S!``"DP(`K',$``&2`@!6=`0``0$``')T!``"DP(`EW0$
-M``$)``"A=`0``0D``+-T!``!"0``NW0$``$)``#$=`0``0D``,UT!``!"0``
-MUG0$``$)``#?=`0``0D``.AT!``!"0``\70$``$)``#Z=`0``0D```-U!``!
-M"0``#'4$``$)```F=00``0D``#!U!``!`0``274$``*3`@#%=00``0$``-YU
-M!``"DP(`;W8$``$!``"(=@0``I,"`,UV!``"<`(`%W<$``$!```X=P0``I,"
-M`'UW!``"<`(`MW<$``$!``#8=P0``I,"`!IX!``!D@(`9G@$``$!``"">`0`
-M`I,"`,QX!``!D@(`1GD$``$!``!F>00``I,"`!YZ!``!`0``-WH$``*3`@#Z
-M>@0``0$``!-[!``"DP(`^GL$``$!```3?`0``I,"`.I\!``!`0```WT$``*3
-M`@#:?00``0$``/-]!``"DP(`O'X$``$!``#:?@0``I,"`!E_!``!`0``,G\$
-M``*3`@#4?P0``0$``.U_!``"DP(`*H`$``$!``!(@`0``I,"`&*`!``!!@``
-M@8`$``&U`@"+@`0``0$``*2`!``"DP(`L8`$``$&``#,@`0``8H"`-.`!``!
-M!@``XX`$``$&``#[@`0``0$``""!!``"T`(`*X$$``%.`@`U@00``08``$V!
-M!``!`0``;8$$``$!``"/@00``I,"`/N!!``!`0``$8($``*3`@")@@0``G`"
-M`+N"!``"HP(`PX($``*'`@#U@@0``0$```Z#!``"DP(`CH,$``$!``"M@P0`
-M`M`"`-.#!``"1@(`\(,$``)P`@`0A`0``G`"`#J$!``"<`(`BH0$``)P`@#0
-MA`0``G`"`/N$!``"<`(`BX4$``)P`@"5A00``G`"`-"%!``"<`(`\(4$``)P
-M`@`1A@0``G`"`)*&!``"<`(`TH8$``)P`@`/AP0``G`"`$^'!``"<`(`CX<$
-M``)P`@#/AP0``G`"`/*'!``!!@``G8@$``%@`@#;B`0``GT"`.^(!``!5@(`
-M`8D$``*=`@`=B00``0$``#F)!``"DP(`3(D$``)+`@"TB00``J8"`%**!``!
-M`0``6HH$``*K`@"/B@0``K("`+N*!``"A`(`V8H$``$!``#GB@0``0$```"+
-M!``"DP(`M(L$``$!``#-BP0``I,"`..+!``!`0``_(L$``*3`@`$C`0``H<"
-M`"&,!``"<`(`08P$``)P`@!PC`0``G`"`(.,!``"I@(`O8P$``*$`@#HC`0`
-M`0$``.^,!``!`0``*8T$``$!``!"C00``I,"`(Z-!``!`0``IXT$``*3`@#<
-MC00``:4"`/6-!``!!@``"8X$``$&``!@C@0``4X"`&V.!``!`0``AHX$``*3
-M`@#4C@0``8H"`/2.!``!!@``$8\$``$&``!HCP0``;4"`+B/!``!8`(`KI$$
-M``)?`@`*D@0``E\"`%B2!``"7P(`VY0$``$!``#TE`0``I,"`%N6!``!`0``
-M=)8$``*3`@#2E@0``L@"`.&6!``"I@(`\I8$``$!``#ZE@0``JL"`"&7!``"
-M<`(`*9<$``*M`@`SEP0``0$``$R7!``"DP(`<9<$``*M`@"!EP0``0$``)J7
-M!``"DP(`&9@$``$!``!`F`0``J`"`.&8!``!`0``'YH$``)K`@!-F@0``4X"
-M`&^:!``":P(`BYH$``)K`@"DF@0``4X"`,Z:!``":P(`_YH$``)K`@`TFP0`
-M`FL"`%2;!``":P(`YIL$``$!``#6G00``0$``.V=!``"H`(`7IX$``$!``!U
-MG@0``J`"`(6>!``":P(`T9X$``$!``#HG@0``J`"`/B>!``":P(`)Y\$``)P
-M`@`_GP0``0$``%B?!``"DP(`9Y\$``$#``"9GP0``FL"`#:@!``":`(`5J`$
-M``$!``!_H`0``J`"`(^@!``":P(`M:`$``)K`@`3H00``FL"`!FB!``":`(`
-M4Z($``$!``!JH@0``J`"`'JB!``":P(`EJ($``)K`@!7HP0``FL"`.RC!``"
-M:P(`9*0$``$!``![I`0``J`"`(ND!``":P(`UZ0$``)K`@`FI00``HL"`#:E
-M!``"BP(`B:4$``)K`@#;I00``FL"`.ZE!``"Q0(`^Z4$``*M`@`)I@0``HL"
-M`!FF!``"Q0(`.*8$``)H`@!>I@0``0$``'6F!``"H`(`A:8$``)K`@"=I@0`
-M`GD"`,FF!``":`(``Z<$``$!```:IP0``J`"`"JG!``":P(`6J<$``$!``!Q
-MIP0``J`"`(&G!``":P(`JZ<$``$!``#4IP0``J`"`.2G!``":P(`T*H$``)H
-M`@`7JP0``G`"`'"K!``"K0(`@*L$``$!``"9JP0``I,"`*FK!``"9P(`!:P$
-M``$!```>K`0``I,"`#VL!``"<`(`J*P$``)G`@`,K@0``04``!6N!``"KP(`
-M%:\$``$!```NKP0``I,"`$VO!``"<`(`8Z\$``)G`@#EKP0``G`"`"&P!``"
-M9P(`*[`$``$!``!$L`0``I,"`+RP!``"3`(`"[$$``*!`@`UL00``F,"`&BQ
-M!``"7P(`O+$$``)?`@#)L00``F<"`/JQ!``"3`(`2K($``)P`@"#L@0``0$`
-M`)RR!``"DP(`7[,$``*C`@"5LP0``GD"`!^T!``"<`(`0[0$``$#``!GM`0`
-M`EH"`*:T!``"6@(`\[0$``)P`@",M@0``H@"`.VV!``"<`(`)+<$``);`@!7
-MMP0``DP"`&RW!``"@0(`EK@$``*;`@#DN`0``IL"`!^Y!``"<`(`>KD$``*(
-M`@!WN@0``IL"`*^Z!``"4`(`'[P$``)P`@!?O`0``EL"`.:\!``"L@(`^[P$
-M``)Y`@`3O00``E4"`,2]!``"K0(`T+T$``*+`@`GO@0``0$``#Z^!``"H`(`
-M3KX$``)K`@"PO@0``0$``,>^!``"H`(`U[X$``)K`@`:OP0``L@"`&^_!``"
-M3`(`SK\$``$!``#EOP0``J`"`/F_!``":P(`8L`$``)P`@#&P`0``G`"`-C`
-M!``!`0``\L`$``*+`@`(P00``L4"`$3!!``!`0``6\$$``*@`@!KP00``FL"
-M`'G!!``!`0``H\($``)=`@#CP@0``HL"`/?"!``"R`(`D<,$``)P`@#1PP0`
-M`EL"`&/$!``"3`(`DL0$``);`@#$Q`0``DP"`!?%!``"7@(`(\4$``)=`@!/
-MQ00``0$``(+%!``"<`(`I,4$``$!``#"Q00``I,"`"3&!``"A`(`CL8$``$!
-M``"GQ@0``I,"`.W&!``!`0``!L<$``*3`@`MQP0``H<"`'3'!``"R`(`?,<$
-M``*+`@",QP0``0$``*K'!``"DP(`/<D$``*$`@!-R00``LL"`!?*!``"<`(`
-M<<H$``*L`@"KR@0``0$``,3*!``"DP(`=\L$``)3`@!;S`0``ED"`'_.!``"
-MA`(`C\X$``++`@#_S@0``EP"``_/!``"<`(`*,\$``*S`@`PSP0``EP"`#[/
-M!``!`0``5\\$``*3`@"2SP0``J,"`/_/!``!`0``(=`$``)_`@!@T`0``G`"
-M`,;1!``!`0``^M$$``+'`@`&TP0``I<"`/?3!``"I@(`&]0$``$!``!5U`0`
-M`H<"`'74!``!`0``BM8$``$%``"3U@0``J\"`-;8!``":`(`#=D$``*R`@">
-MV@0``0$``';;!``!`0``Y-L$``*;`@`+W`0``K("`"K<!``"I@(`DMP$``&*
-M`@#9W`0``J,"`.7<!``"AP(`+-T$``*C`@`XW00``H<"`%C=!``"HP(`:=T$
-M``$!``#OW00``0$``!7>!``!`0``L]X$``$!``!ZWP0``G`"`-K?!``"<`(`
-M:N`$``)P`@#YX`0``G`"`%/A!``"<`(`\^$$``)P`@"EX@0``G@"`+?B!``!
-MG`(`+N,$``*Q`@!(XP0``I$"`,;C!``"HP(`U>,$``*'`@#?XP0``0$``/CC
-M!``"DP(`@N0$``*C`@"1Y`0``H<"`)OD!``!`0``M.0$``*3`@`:Y00``FL"
-M`&?E!``"<`(`<^4$``)P`@"GY00``L0"`!7F!``"Q`(`"^<$``)P`@`ZYP0`
-M`L0"`$WG!``!`0``9N<$``*3`@#-YP0``G`"`-7G!``"LP(``^@$``)P`@`L
-MZ`0``0$``$7H!``"DP(`7^@$``)P`@#VZ`0``H<"``#I!``!`0``&>D$``*3
-M`@#;Z00``D<"`"OJ!``!D@(`..H$``&2`@!`Z@0``LP"`)KJ!``"6@(`Z>H$
-M``&2`@`QZP0``0$``$KK!``"DP(`SNL$``$!``#:ZP0``E@"`!OL!``!`0``
-M-.P$``*3`@!9[`0``0$``'CL!``"T`(`S>P$``)B`@#=[`0``;4"`/#L!``"
-M:P(`/NT$``$!``"`[00``J,"`)WM!``"HP(`JNT$``)<`@#?[00``G`"`.GM
-M!``"<`(`]>T$``)F`@#\[00``0$``"+N!``"DP(`2.X$``%@`@!^[@0``6`"
-M`(KN!``"<@(`JNX$``%6`@"\[@0``IT"`!3O!``"A`(`.N\$``$!``!3[P0`
-M`I,"`*;O!``!`0``O^\$``*3`@`G\`0``G`"`'[P!``"K`(`MO`$``$!``#/
-M\`0``I,"`%OQ!``"4P(`/_($``)9`@#W\@0``G`"`%[S!``!`0``=_,$``*3
-M`@#C\P0``E,"`-?T!``"<`(`./4$``$!``!1]00``I,"`+'U!``"4P(`EO8$
-M``&2`@#:]@0``0$``//V!``"DP(`!O<$``)P`@!+]P0``F<"`%3X!``"BP(`
-M<_@$``$#``#>^00``0$```?Z!``"<`(`XOH$``*+`@#L^@0``0$```7[!``"
-MDP(`/OL$``)P`@!V^P0``H0"`)?[!``!`0``M?L$``*3`@`;_`0``J8"`"O\
-M!``!B@(``?T$``$!```(_00``0$``-/]!``"F`(`]_T$``$!```3_@0``I,"
-M`(/^!``!`0``G/X$``+0`@#0_P0``H<"`.?_!``!`0`````%``*3`@"*``4`
-M`H<"`+8`!0`"F`(`+`$%``*'`@#.`04``I@"`.4!!0`"F`(`]@(%``*'`@!1
-M`P4``J,"`'$#!0`"<`(`E`,%``)C`@"K`P4``0$``,0#!0`"DP(`<00%``$!
-M``"*!`4``I,"`)H$!0`":P(`IP0%``$!``#(!`4``I,"`-MB!``"IP(`86,$
-M``*A`@!_:00``JL"`-AI!``"AP(`CFH$``*K`@#>:@0``H<"`*5M!``"JP(`
-M?H,$``*K`@`+C00``JL"`$2<!``"H0(`N,\$``)2`@"?U`0``I,"`)[8!``"
-MJP(`V]H$``)_`@"@VP0``I,"`$K>!``"?P(`1M\$``*K`@"![`0``DD"`''M
-M!``"T`(`,?X$``*K`@!1`04``JL"`&8"!0`"JP(`L`(%``*K`@""!P4``M`"
-M`*8'!0`";P(`VP<%``*8`@"V"@4``0$``"$+!0`"C0(`6PL%``$!``!F"P4`
-M`0$``%@,!0`">0(`80T%``*-`@"\#04``7$"`-4-!0`"QP(`4`X%``*C`@"!
-M$`4``7$"`)H0!0`"QP(`K!`%``)Q`@!3$04``LH"`(,1!0`"T`(`(1(%``*K
-M`@!%$@4``DT"`)02!0`"JP(`/`<%``+0`@`-#`4``JL"`.P-!0`"<0(`?0X%
-M``+*`@#H#@4``JL"`(P2!0`"IP(`'Q,%``)H`@"#%04``G,"`+\5!0`"<P(`
-MVA4%``)S`@"*%@4``E`"`),7!0`"50(`UA@%``*;`@"[&04``FL"`/`9!0`"
-M6P(`CAH%``*+`@!='04``FD"`&T=!0`"9`(`H!T%``)?`@#U'04``E\"`!(>
-M!0`"9P(`I!X%``*+`@#:'@4``GD"`/,>!0`">0(``1\%``)Y`@`1'P4``HL"
-M`!D?!0`"BP(`;!\%``$#``#U'P4``HD"`$P@!0`";0(`G2`%``)2`@`M(04`
-M`HL"`$0B!0`"K0(`IB(%``*;`@"^(@4``EL"`,XB!0`"B0(`_R(%``*(`@`^
-M)04``E\"`(`E!0`"7P(`DR4%``)I`@!')@4``E\"`&`F!0`":0(`B"8%``)D
-M`@"F)@4``F0"`&DJ!0`"U0(`Q"H%``+5`@!G*P4``M4"`$TL!0`"L@(``2T%
-M``)I`@`Y+04``E\"`$$M!0`":0(`4BT%``)I`@"N+04``E\"`+HM!0`":0(`
-M,"X%``)H`@!'+@4``JT"`&8N!0`":`(`\RX%``+5`@#V,`4``K,"`!,Q!0`"
-MK0(`'3$%``*+`@!7,04``HD"`*`7!0`";0(`T!D%``)M`@!8(04``JT"`,8O
-M!0`"LP(`@3$%``%*`@"B,04``:H"`+TQ!0`!J@(`3C,%``$!``!M,P4``M`"
-M`*@S!0`"D0(`[C,%``+2`@`.-`4``KT"```$```!`0``!`0```$!```(!```
-M`0$```P$```!`0``$`0```$!```4!````0$``!@$```!`0``'`0```$!```@
-M!````0$``"0$```!`0``*`0```$!```L!````0$``#`$```!`0``-`0```$!
-M```X!````0$``#P$```!`0``0`0```$!``!$!````0$``$@$```!`0``3`0`
-M``$!``!0!````0$``%0$```!`0``6`0```$!``!<!````0$``&`$```!`0``
-M9`0```$!``!H!````0$``&P$```!`0``<`0```$!``!T!````0$``'@$```!
-M`0``?`0```$!``"`!````0$``(0$```!`0``B`0```$!``",!````0$``)`$
-M```!`0``E`0```$!``"8!````0$``)P$```!`0``H`0```$!``"D!````0$`
-M`*@$```!`0``K`0```$!``"P!````0$``+0$```!`0``N`0```$!``"\!```
-M`0$``,`$```!`0``Q`0```$!``#(!````0$``,P$```!`0``T`0```$!``#4
-M!````0$``-@$```!`0``W`0```$!``#@!````0$``.0$```!`0``Z`0```$!
-M``#L!````0$``/`$```!`0``]`0```$!``#X!````0$``/P$```!`0````4`
-M``$!```$!0```0$```@%```!`0``#`4```$!```0!0```0$``!0%```!`0``
-M&`4```$!```<!0```0$``"`%```!`0``)`4```$!```H!0```0$``"P%```!
-M`0``,`4```$!```T!0```0$``#@%```!`0``/`4```$!``!`!0```0$``$0%
-M```!`0``2`4```$!``!,!0```0$``%`%```!`0``5`4```$!``!8!0```0$`
-M`%P%```!`0``8`4```$!``!D!0```0$``&@%```!`0``;`4```$!``!P!0``
-M`0$``'0%```!`0``>`4```$!``!\!0```0$``(`%```!`0``A`4```$!``"(
-M!0```0$``(P%```!`0``D`4```$!``"4!0```0$``)@%```!`0``G`4```$!
-M``"@!0```0$``*0%```!`0``J`4```$!``"L!0```0$``+`%```!`0``M`4`
-M``$!``"X!0```0$``+P%```!`0``P`4```$!``#$!0```0$``,@%```!`0``
-MS`4```$!``#0!0```0$``-0%```!`0``V`4```$!``#<!0```0$``.`%```!
-M`0``Y`4```$!``#H!0```0$``.P%```!`0``\`4```$!``#T!0```0$``/@%
-M```!`0``_`4```$!````!@```0$```0&```!`0``"`8```$!```,!@```0$`
-M`!`&```!`0``%`8```$!```8!@```0$``!P&```!`0``(`8```$!```D!@``
-M`0$``"@&```!`0``+`8```$!```P!@```0$``#0&```!`0``.`8```$!```\
-M!@```0$``$`&```!`0``1`8```$!``!(!@```0$``$P&```!`0``4`8```$!
-M``!4!@```0$``%@&```!`0``7`8```$!``!@!@```0$``&0&```!`0``:`8`
-M``$!``!L!@```0$``'`&```!`0``=`8```$!``!X!@```0$``'P&```!`0``
-M@`8```$!``"$!@```0$``(@&```!`0``C`8```$!``"0!@```0$``)0&```!
-M`0``F`8```$!``"<!@```0$``*`&```!`0``I`8```$!``"H!@```0$``*P&
-M```!`0``L`8```$!``"T!@```0$``+@&```!`0``O`8```$!``#`!@```0$`
-M`,0&```!`0``R`8```$!``#,!@```0$``-`&```!`0``U`8```$!``#8!@``
-M`0$``-P&```!`0``X`8```$!``#D!@```0$``.@&```!`0``[`8```$!``#P
-M!@```0$``/0&```!`0``^`8```$!``#\!@```0$````'```!`0``!`<```$!
-M```(!P```0$```P'```!`0``$`<```$!```4!P```0$``!@'```!`0``(`<`
-M``$!```D!P```0$``"@'```!`0``+`<```$!```P!P```0$``#0'```!`0``
-M.`<```$!```\!P```0$``$`'```!`0``1`<```$!``!(!P```0$``$P'```!
-M`0``4`<```$!``!4!P```0$``%@'```!`0``7`<```$!``!@!P```0$``&0'
-M```!`0``:`<```$!``!L!P```0$``'`'```!`0``=`<```$!``!X!P```0$`
-M`'P'```!`0````@```$!```$"````0$```@(```!`0``#`@```$!```0"```
-M`0$``!0(```!`0``&`@```$!```<"````0$``"`(```!`0``)`@```$!```H
-M"````0$``"P(```!`0``,`@```$!```T"````0$``#@(```!`0``/`@```$!
-M``!`"````0$``$0(```!`0``2`@```$!``!,"````0$``%`(```!`0``5`@`
-M``$!``!8"````0$``%P(```!`0``8`@```$!``!D"````0$``&@(```!`0``
-M;`@```$!``!P"````0$``'0(```!`0``>`@```$!``!\"````0$``(`(```!
-M`0``A`@```$!``"("````0$``(P(```!`0``D`@```$!``"<"````0$``*`(
+M979I8V4@)7@I`````$1E=FEC92`H4&%T:"`E,#)X('P@5&%R9V5T("4P,G@@
+M?"!%)7@O4R4P,G@I('-P:6X@=7`@;6]D92!N;W0@<W5P<&]R=````%-E="!D
+M979I8V4@*%!A=&@@)3`R>"!\(%1A<F=E="`E,#)X('P@125X+U,E,#)X*2!S
+M<&EN('5P(&UO9&4@)7@`````071T86-H960@9&5V:6-E(&EN9&5X("4P,G@@
+M*%!A=&@@)3`R>"!\(%1A<F=E="`E,#)X('P@125X+U,E,#)X*2`@)7@E>"5X
+M)7@E>"5X)7@E>```0F%C:W5P('-T86UP("5X('-U;2`E>"!B86-K960@)60`
+M````36%S=&5R('-T86UP("5X('-U;2`E>"!B86-K960@)60`````5W)I=&4@
+M87)R87D@;65T82!D871A('1O(&UA<W1E<B`P>"5L;%@M/C!X)6QL6```5W)I
+M=&4@87)R87D@;65T82!D871A('1O(&)A8VMU<"`P>"5L;%@M/C!X)6QL6```
+M6R5D("5D72!D979I8V4@97)A<V4@=6YI="!S=6-C97-S9G5L;'DN`%LE9"`E
+M9%T@9&5V:6-E(&5R87-E('5N:70@9F%I;&5D(&]R(&%B;W)T960N`````&1O
+M7V1I<VM?8W1L7V-M9#H@8W1L(&-O9&4@)7@@=F0])7`L($Q"02`P>"5L;%@@
+M;E-E8W1O<B`P>"5X`%LE,#)D.B4P,F0@4"5D72!'4T-2(&-H86YG960`475E
+M=64@9G5L;"`E>"`E>`!297$@)7`@)7@@)7@`)7,@<F5Q("5P('-L;W1I9"`P
+M>"5X`%LE,#)X.B4P,G@@)3`R9%T@9&ES:R!F86EL960N`$1E=FEC92`E>"\E
+M>"!R96UO=F5D+@!&86EL960@=&\@=F5R:69Y(&-O;G1R;VQL97(`;V1I;B!R
+M96%D('=R:71E(&5X8V5E9',@)7@`;V1I;@!$979I8V4@)7@O)7@@<F5M;W9E
+M9"X`4F5T<GEI;F<@9F%I;&5D+"!D:7-K(&1O=VX_/S\`=V]R:W)O=6YD(&ER
+M<5-T871U<R`](#!X)7@`4F5Q("5P("5X("5X`$]V97)R86QL(%-'(&ET96T@
+M)7@@<VEZ92`E>`!3;&]T(&)U<WDL('-L;W0@)7@H)7@I`$1U;7`@<VQO="!I
+M;F9O.B`E>"`E>"`E>"`E>`!#;&5A;B!U<"!S;&]T("5X`$0R2"!&25,Z("4P
+M.'@@)3`X>"`E,#AX("4P.'@`)3`R>"`E,#1X.B4P-'@Z)3`T>`!$979I8V4@
+M)7@O)7@@<F5M;W9E9"X`1&5V:6-E("5X+R5X(')E;6]V960N`$1E=FEC92`E
+M>"!P;W=E<F5D('5P+@!S=&%R="!315,@9&5V:6-E("5P`$9O=6YD(%-%4R!$
+M979I8V4@)7@`1F%I;&5D('1O('9E<FEF>2!C;VYT<F]L;&5R`&]D:6X@<F5A
+M9"!W<FET92!E>&-E961S("5X`&]D:6X`8V%L;"!L9&U?;VY?=&EM97(@869T
+M97(@,6US`')A=R`E<"!B861?<V5C=&]R("5X`%=R:71E(&)A8VMU<&5D(&UE
+M=&$@9&%T80!&86EL960@=&\@<W!I;F1O=VX@9&5V:6-E<P!&86EL960@=&\@
+M9FQU<V@@=&%R9V5T<P!!=71O(%)E8G5I;&0`4F5B=6EL9"!0<FEO<FET>0!#
+M;VYT:6YU92!296)U:6QD:6YG(&]N($5R<F]R`%-P:6YD;W=N($ED;&4@1&ES
+M:R`H;6EN=71E<RD`4W1A9V=E<F5D('-P:6YU<``````````&!`4!`P)28A4`
+M````````!@0%`0,"V&"?-CD\``````8$!0$#`B!@D%!2```````&!`4!`P+8
+M8)````````````$"`Q`$!08'$0@)"@L2#`T.#Q,4%187)!@9&ALE'!T>'R8@
+M(2(C)P```````````````````````````````+P`````````(0```"#1``"`
+MYP``<-$``-#S``"```$`4.<``!#1``"@T0``8.8``(#1```0`P$`<-(``*#X
+M````````(.4``)#1``"0^@``(.(```#<``!PVP``T-(``,#N``#PT@``T-L`
+M`*#;``#PV@``D-0``+#3`````````````(#2``"0T@``H-(``+#2``#`T@``
+M``````,14`<```````(``````````````0````````````````````8$!0$#
+M`E)B%0`````````&!`4!`P+88)\V.3P`````!@0%`0,"(&"04%(```````8$
+M!0$#`MA@D`````````!/`@```````"$```"PGP(`,+\"``"@`@"`V@(`D/4"
+M``"_`@"@GP(`4*$"`!"^`@`0H`(`,/@"`-"A`@!0WP(``````#"[`@`@H`(`
+M@.\"`!"V`@`@KP(`D*X"`%"C`@#`Q@(`<*,"`/"N`@#`K@(`$*X"`#"E`@!0
+MI`(```````````#@H0(`(.T"`&#I`@!PY0(`D.$"```````#$8!R```````"
+M``````````````$````````````````````!`?\"````````````````````
+M```````````````````````!`````````!@`````````+````!0```!0'@,`
+M\#\#`(`=`P```````````!`1`P`0'0,`T!$#````````````````````````
+M``````````````````````````#_``!P5`,``````."/`P`!`````?\``-!4
+M`P``````D(X#``$````"_P``\%0#``````#0HP,``0````/_``!050,`````
+M`.";`P`!````-?\``'!5`P``````<(T#``$````$_P``4%8#```````@AP,`
+M`0````7_``"P5@,``````$`#!``!````!O\``&!9`P#PE0,`<'8#```````'
+M_P``P/,#`("4`P`P=0,```````K_``!070,``````!"#`P`!````"_\``'!=
+M`P``````8/`#```````,_P``H&`#`&"4`P#P=`,```````W_```080,`0)0#
+M`+!T`P``````#O\``(!A`P#PDP,`<'0#```````/_P``0&(#`&"3`P`P=`,`
+M`````!#_``"P8@,`0),#`/!S`P``````$?\``*!C`P``````<',#```````2
+M_P``$&0#```````P<P,``````!/_```P9`,``````*#Y`P`!````-/\``%!D
+M`P```````/X#``$````8_P``<&0#``````"PF@,``````$+_```@90,`````
+M`)":`P``````&?\``.!=`P``````P.\#```````:_P``4%X#``````!@[P,`
+M`````!W_``#090,``````/!R`P``````'O\``$!F`P``````0/4#``$````?
+M_P``T&8#`-"2`P"P<@,``````"#_``"`6@,`L)4#`#!V`P``````(?\``/!6
+M`P``````8`$$``$````B_P``,&,#``````"P<P,``````"/_``#`7@,`````
+M`-#N`P``````)/\``#!?`P``````0.X#```````E_P``H%\#``````#@[0,`
+M`````"G_``#06P,`,)4#`+!U`P``````*O\``!!@`P``````T-X#```````K
+M_P``8&<#`*"2`P!P<@,``````"S_``#@5P,``````-"%`P`!````+?\``,!8
+M`P`PE@,`L'8#```````N_P``,%<#``````"0_@,``0```"__```050,`````
+M`""B`P`!````2?\``#!5`P``````P(T#``$````W_P``<%<#``````"0V`,`
+M`0```#C_```P6P,`<)4#`/!U`P``````.?\``)!<`P#PE`,`<'4#```````Z
+M_P``0%@#```````@A0,``0```#O_``!0:`,``````-":`P`!````//\``(!6
+M`P``````<(8#``$````]_P``D%4#``````#0C`,``0```#[_``"P50,`````
+M`."+`P`!````0_\``-!5`P``````\(H#``$```!$_P``\%4#````````B@,`
+M`0```$;_```05@,```````")`P`!````1_\``#!6`P``````((@#``$````R
+M_P``D%0#``````!0G`,``0```#/_``"P5`,`<)8#`.".`P``````9/\``,!G
+M`P``````(((#``$````P_P``\&<#``````#0?P,``0```&;_```P6@,`````
+M`."#`P`!````9_\``!!:`P``````H(0#``$```!%_P``4&D#`("2`P`P<@,`
+M`````$C_````:@,`8)(#`/!Q`P``````_____P``````````````````````
+M``````````!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=``!'0T,Z("A'3E4I(#0N,BXQ(#(P,#<P.#,Q('!A=&-H960@6T9R
+M965"4T1=```N<WEM=&%B`"YS=')T86(`+G-H<W1R=&%B`"YR96PN=&5X=``N
+M<F5L+G)O9&%T80`N<F]D871A+G-T<C$N-``N<F]D871A+G-T<C$N,0`N<F5L
+M+F1A=&$`+F)S<P`N8V]M;65N=```````````````````````````````````
+M```````````````````````?`````0````8`````````0````&5#!```````
+M`````!``````````&P````D``````````````(3/!``0@0``#`````$````$
+M````"````"D````!`````@````````#`0P0`O`X`````````````(```````
+M```E````"0``````````````E%`%`#@3```,`````P````0````(````,0``
+M``$````R`````````'Q2!`#$#``````````````$`````0```$`````!````
+M,@````````!`7P0`.@,``````````````0````$```!3`````0````,`````
+M````@&($`)@'`````````````"``````````3P````D``````````````,QC
+M!0#(!@``#`````<````$````"````%D````(`````P`````````@:@0```4`
+M````````````(`````````!>`````0``````````````(&H$`"<&````````
+M``````$`````````$0````,``````````````$=P!`!G```````````````!
+M``````````$````"``````````````#@<@0`@"8```T````#`@``!````!``
+M```)`````P``````````````8)D$`"(V``````````````$`````````````
+M``````````````````````````````````,``0`````````````````#``(`
+M`````````````````P`#``````````````````,`!``````````````````#
+M``4``````````````````P`&``````````````````,`!P``````````````
+M```#``@``````````````````P`)``````````````````,`"@``````````
+M```````#``L``````````````````P`,``````````````````,`#0`!````
+M`````#H````"``$`#P```#!T``#*`0```@`!`"(```#P#P``=`````(``0`P
+M````T!X``%`!```"``$`4`````"V``!4`````@`!`%P```!PO0``)P````(`
+M`0!X````()H``-`````"``$`B````-`0``!Z`@```@`!`)P````@!P``)0``
+M``(``0"R````8+8``%<````"``$`PP```#`&``"7`````@`!`-<```!0!P``
+M(`````(``0#W````L*L``$@````"``$`!P$``-!M``"J`````@`!`"`!```@
+M(```P`0```(``0`[`0``$,L``'4````"``$`2`$``,`"``!C`````@`!`&8!
+M````O0``)0````(``0"!`0``X+8``!<````"``$`F@$``$!6```K`````@`!
+M`+4!``"0````2P````(``0#%`0``<,<``.8"```"``$`UP$``"!I``!#````
+M`@`!`/(!``!@;P``6`````(``0`"`@``H&(``(D````"``$`'@(``,!3```J
+M`0```@`!`#L"``#`;P``IP````(``0!1`@``\+X``)L````"``$`<0(```!A
+M``"<`0```@`!`(0"```0P```*0````(``0"G`@``0&```+,````"``$`O0(`
+M`#!C``#R`0```@`!`-4"``!@`0``&P````$``P#@`@``D$(``#(````"``$`
+M_`(``)!9```X`````@`!`!`#``"PL0``5P````(``0`A`P``,#0``.L````"
+M``$`0P,``,"V```8`````@`!`%L#``"PL@``[0(```(``0!K`P``8+(``$@`
+M```"``$`?0,``!"Z```C`````@`!`(H#``!``0``$`````(``0";`P``@`(`
+M`#,````"``$`KP,``#!E``!``0```@`!`,`#```0J@``30````(``0#/`P``
+MD`<``$<````"``$`XP,``/!#```9`P```@`!`/@#``!`"0``,0$```(``0`,
+M!```<!```$L````"``$`(P0``'!F``"F`@```@`!`#4$``!0L```5P````(`
+M`0!%!```0````(`````!``D`2P0``!!'``"I"0```@`!`&8$```PQ```;@$`
+M``(``0"4!```P`,``&$"```"``$`L00``##S``":`````@`!`,$$```0L@``
+M0@````(``0#4!````"D``!<!```"``$`]`0``!#K``"P`P```@`!``\%``!P
+MG@``'0````(``0`E!0``X`<``%H````"``$`.`4``%`!```>`````@`!`$L%
+M``!`)@``O`(```(``0!C!0``("H``#@%```"``$`@04``!!:``!``````@`!
+M`)8%``!`GP``]0$```(``0"K!0``H#L```@"```"``$`P@4``"!L``#8````
+M`@`!`-T%``#@7P``+0````(``0#T!0``T%D``$`````"``$`#`8``.!8```Q
+M`````@`!`"4&``"@:0``*@````(``0`_!@``,%T``/4````"``$`5@8``"!9
+M``!F`````@`!`&D&``"0OP``<0````(``0",!@``\+D``!\````"``$`H`8`
+M`(`#```W`````@`!`+0&```05@``*P````(``0#-!@``8`T```\!```"``$`
+M[`8``$`,```6`0```@`!`/D&``!0$P``#@(```(``0`6!P``T+P``"8````"
+M``$`,P<``.!;``!5`````@`!`$\'``"0O@``4P````(``0!U!P``P!````(`
+M```"``$`D`<``%!:``"&`0```@`!`*4'``!P:0``*@````(``0#!!P``P'H`
+M`)L&```"``$`UP<``.`D``!9`0```@`!`/,'``"@50``,`````(``0`#"```
+M$#H``,H````"``$`(`@``)"[```^`0```@`!`#$(``"0G@``I0````(``0!%
+M"```T&D``$4````"``$`7`@``-`*``!P`0```@`!`&X(``!P#@``40````(`
+M`0"%"```L-T``&T!```"``$`H`@``&!>``#U`````@`!`+,(``!P`0``50``
+M``(``0#""```8"\``,,$```"``$`V@@``""C``#_!0```@`!`.\(``"@O0``
+MY`````(``0`2"0``\`$``&D````"``$`)@D``*!6```$`0```@`!`$`)````
+MK```CP````(``0!2"0``((D``+L'```"``$`;PD``-!5```T`````@`!`(,)
+M```08```,`````(``0"7"0``<`\``'L````"``$`N0D```"W``#P`@```@`!
+M`,\)``#@.@``O`````(``0#L"0``0+H``$<!```"``$``PH``'"K```Z````
+M`@`!`!0*``#0!@``10````(``0`H"@``T-$``!L````"``$`/0H``*!3```9
+M`````@`!`%X*``!`````1`````(``0!Q"@``D&H``%D````"``$`?0H``(!K
+M``"1`````@`!`)(*``"@S0``:`,```(``0"I"@``,)X``!D````"``$`PPH`
+M``!V``#+`0```@`!`-T*``#@````7P````(``0#Q"@``<%8``"L````"``$`
+M"0L``(!N``#9`````@`!`!T+````;0``RP````(``0`U"P``<'```&`"```"
+M``$`4PL``&#P``#)`@```@`!`&H+``"@M0``7`````(``0!W"P``@*H``#\`
+M```"``$`A`L``-#,``#!`````@`!`)P+``!0G@``'0````(``0"O"P``T`$`
+M`!<````"``$`P0L``/`<``#<`0```@`!`-P+``!P'```>0````(``0#R"P``
+M,+T``#,````"``$`#0P``-!R``"P`````@`!`"$,``"@Q0``X0````(``0`X
+M#```<`<``!T````"``$`2@P``&!?``!R`````@`!`%P,``"@"```D0````(`
+M`0!Y#```(&H``&@````"``$`E@P``"`U``#D!````@`!`*T,``!`P```X0,`
+M``(``0###```,`,``$$````"``$`V@P``)#J``!Z`````@`!`/8,``!@`@``
+M$0````(``0`-#0``0````"@````!``<`&@T``(!S``"P`````@`!`"X-``"P
+ML```5P````(``0`^#0````````0````!``D`4`T``'"4``"K!0```@`!`&$-
+M``#0#@``E0````(``0"`#0``,%X``"8````"``$`D`T``-!"```3`0```@`!
+M`*D-``#`4```W`(```(``0#!#0``T'<``.@"```"``$`VPT``+!7```F`0``
+M`@`!`/(-``!@%0```0<```(``0`(#@``0`@``%H````"``$`'`X``/#1``!]
+M`````@`!`#0.``!@/@``*P0```(``0!5#@``0*$``-X!```"``$`<0X``(`*
+M``!$`````@`!`(,.``!@@@``O08```(``0">#@``P*H``*,````"``$`N`X`
+M`$#3``!0`````@`!`-`.``!`7```Y0````(``0#E#@``\%0```(````"``$`
+M^@X``/":```[`P```@`!`!,/```@!@(`EP````(``0`B````4!<!`'0````"
+M``$`)P\````*`0!I`````@`!`#T/``"`_@$`$P````(``0!,#P``(+$!`"L`
+M```"``$`:0\``/#*`0!G`P```@`!`(,/````!0(`'`$```(``0"3#P``P'$!
+M`*X&```"``$`LP\``/"=`0!]`````@`!`,D/```@9@(`Y`@```(``0#H#P``
+M$.T!`(T````"``$`$Q```!"Y`0#9`````@`!`+(`````@@(`5P````(``0`G
+M$```\*L!`'(````"``$`1A```/"(`@`^`0```@`!`%D0``#0HP(`4@````(`
+M`0!S$```H%H"`'0+```"``$`D1```'!M`0!0!````@`!`*L0``!@YP$`7`$`
+M``(``0#W`````'0"`$@````"``$`.P$``*"9`@!U`````@`!`,00```PG`(`
+M:`,```(``0#=$```4+$!`"$````"``$`^1```+!4`@`2`0```@`!`!(1``#P
+M"`$`7P````(``0`H$0``\'@!`!L````"``$`1A$``-`*`0!C`````@`!`&81
+M```@M`$`20````(``0!Y$0``\%D"`*D````"``$`D!$``&"V`0`N`````@`!
+M`*X1``#`#P$`(`````(``0#0$0``0+`!`#0````"``$`YA$```"6`@#F`@``
+M`@`!`/(!`````P(`6`````(``0#Z$0```(X"`/8#```"``$`$A(``."Q`0!G
+M`````@`!`"<2``!`$P$`<`$```(``0`[$@```)H!`%(!```"``$`.P(``*#_
+M`0"G`````@`!`%P2``"`$`(`E`````(``0!R$@``<)D!`(,````"``$`C1(`
+M`(""`@`7`````@`!`*@2``"@H@$`_P````(``0#0$@``L$P!`/<````"``$`
+M]!(``+`0`0!:`````@`!``H3``#050(`^`$```(``0#5`@``@`T``"`````!
+M``,`(1,``,`&`@`A`0```@`!`#`3``!PU@$`X0````(``0!($P``,-L!`&H#
+M```"``$`:!,``'">`0`$`0```@`!`(P3``#05P(`%`(```(``0"J$P``T.H!
+M`"X!```"``$`$`,``&!Z`@!7`````@`!`,<3``"@K0$`#`$```(``0#D$P``
+M0!X!``D&```"``$`!A0``."_`0!W`````@`!`'T#``#@@P(`)0````(``0`M
+M%```P-4!`%`````"``$`1Q0``'"X`0!$`````@`!`&44```0F0$`60````(`
+M`0".%```T!<!`!L````"``$`JQ0``)`/`0`E`````@`!`#4$````>0(`5P``
+M``(``0!%!```0`$``(`````!``D`PQ0``)#1`0#^`````@`!`-H4```@E@$`
+M7@````(``0#Q%```0!P"`'@$```"``$`!A4``)`+`0!"`````@`!`+$$``!P
+MSP(`F@````(``0`<%0``((L"`"0!```"``$`014``$"A`0!3`0```@`!`&@5
+M``"@R0$`2P$```(``0"-%0``H&`!`,$````"``$`K!4``%"S`0#0`````@`!
+M`,@5``"`&`$`:0````(``0#A%0```!`!`$<````"``$`]Q4``,#9`0!D`0``
+M`@`!``H6``!@!0$`.@````(``0`J%@``4'X!`/,````"``$`1A8``(!S`@`[
+M`````@`!`%86```@E0$`E0````(``0!^%@``T!4!`%$````"``$`EQ8``+",
+M`@";`````@`!`"4&``#@Y0$`*@````(``0"Y%@``8#8!`.@#```"``$`VQ8`
+M`-"$`@`Y`0```@`!`/D6``!0.@$`_`@```(``0`;%P``D,<!``0!```"``$`
+M1Q<``*"F`0`J`0```@`!`&X7``#P%P$`5@````(``0"0%P```,,"`+L#```"
+M``$`C`8``+"#`@`A`````@`!`*T7```@,0$`[@$```(``0#+%P``,!8!`)4`
+M```"``$`M`8``/"P`0`K`````@`!`.P7```0A@(`U@````(``0`)&```$/H!
+M`.$````"``$`)!@``"`1`@`B`P```@`!`.P&``"P%`$`%@$```(``0!`&```
+M4$,!`%0)```"``$`6A@``!#F`0`7`````@`!`'(8``"PB@(`,P````(``0"/
+M&```<*P!`!D````"``$`LA@```!P`@!-`````@`!`,,8```PN@$`0`````(`
+M`0#:&```0($"`%P````"``$`Z1@``&!Q`@`;`@```@`!`/H8``#0Y@$`B@``
+M``(``0`9&0``\-`!`*`````"``$`0AD``+!P`@"C`````@`!`%X9``"0R0(`
+MV04```(``0!W&0``D.`!`,@"```"``$`BQD``'##`0!,`0```@`!`+`9```0
+MA`(`MP````(``0#)&0``H/T!`'(````"``$`Z1D``("Q`0`K`````@`!```:
+M``#@#P$`'0````(``0`4&@``8`,"`-8````"``$`+!H``!![`@!(`````@`!
+M`$`:``!0"0$`$`````(``0!3&@``8%`"`$4$```"``$`:AH``!`(`0`Z````
+M`@`!`'H:``"PH`(`E0````(``0",&@``H*,!`&$!```"``$`HQH``/`P`@``
+M`@```@`!`,0:``!P0P(`I0(```(``0#6&@``@)\!`+@!```"``$``1L``#"X
+M`0`X`````@`!`!<;``"0"@$`,P````(``0`M&P``\`<"`*T````"``$`1!L`
+M`%!_`0`3`0```@`!`%\;``#@"@(`F`(```(``0!T&P``8-<!`*P!```"``$`
+MB1L``*#(`0#X`````@`!`+,;``"0T@$`50$```(``0#,&P``L+4!`"H````"
+M``$`Y!L``("6`0!G`````@`!``,<``#`E0$`7@````(``0`M'````%8!`,@)
+M```"``$`1AP``%`4`@#L!@```@`!`%X<```P[@$`?`D```(``0!Q'```4(H"
+M`"8````"``$`D!P``$`/`0!%`````@`!`*8<```0,P(`A`D```(``0#%'```
+M@,8!``T!```"``$`ZAP``(`-`@#T`@```@`!`$`)``!0=`(`XP````(``0`*
+M'0``<+0!`/8````"``$`'AT``+"N`0"8`````@`!`"\=```0T`(`:`H```(`
+M`0`^'0``P"`"`,0'```"``$`6QT``,#H`0"X`````@`!`'@=``#@"0$`%P``
+M``(``0",'0``<.0!`!L!```"``$`IQT``&#C`0`.`0```@`!`+\=```@&P$`
+MZ0````(``0#7'0``P+@!`$@````"``$`\AT``*`.`0";`````@`!``@>``!@
+M"0$`'@````(``0`='@``\(H"`"<````"``$`.QX``%"-`@!Q`````@`!`&`>
+M``"@@@(`"@$```(``0`#"@``P',"`#H````"``$`>!X``(#F`0!(`````@`!
+M`(X>``#PE@$`YP````(``0"P'@``<(`!`.@,```"``$`S1X``$`I`@"I!P``
+M`@`!`.@>``!`U0$`<@````(``0#\'@``4"0!`"T````"``$`*`H``,"\`@#-
+M`````@`!`!P?```0>0$`/04```(``0`_'P``L+$!`"L````"``$`61\``%`(
+M`0!$`````@`!`&X?````D@(`;@$```(``0">'P``$-8!`"T````"``$`MQ\`
+M`("O`0`"`````@`!`'$*```@_@$`60````(``0#.'P``L$T!`$D(```"``$`
+MYA\``&";`0`X`0```@`!``<@````[`$`#0$```(``0`=(````/L!`*L!```"
+M``$`-"```/`8`0`D`@```@`!`'T*``!`!`(`P`````(``0!3(```<'@!`'P`
+M```"``$`J0H``/`R`@`9`````@`!`',@``!P^0$`G0````(``0"+(```8(T!
+M`$4"```"``$`K2```+#\`0!H`````@`!`,P@```P20(`$0,```(``0#G(```
+MT(T"`"D````"``$`#"$``*#^`0`S`````@`!`!HA``#0%@$`>P````(``0`^
+M(0``$!$!`)$````"``$`72$``#"_`0"A`````@`!`'DA````I@$`E0````(`
+M`0":(0``(/T!`'(````"``$`NB$``+`1`0`Q`0```@`!`-`A``#PN0$`0```
+M``(``0#J(0``4,\!`-0````"``$`$"(``(`)`0!5`````@`!`'<+``!P<`(`
+M/P````(``0`A(@``<+4!`#$````"``$`/"(``#"*`@`&`````@`!`%8B```@
+M1@(`"0,```(``0!O(@``(&D!`$@$```"``$`A`L``&";`@#!`````@`!`(@B
+M``"@@0(`5`````(``0"6(@``0(@"`+`````"``$`LR(``$#_`0`E`````@`!
+M`,(B``!P"@$`$0````(``0#;(@``\(8"`$D!```"``$`^"(``%"O`0`L````
+M`@`!`!(C``#@M0$`1`````(``0`O(P``0`$"`+4!```"``$`2R,``%`0`0!:
+M`````@`!`&`C``!0L@$`\@````(``0#<"P``4!@!`",````"``$`>2,``&![
+M`@#3!0```@`!`(LC```PZ@$`F0````(``0"H(P``X+X!`$T````"``$`QB,`
+M`%!,`@`-!````@`!`-\C``"@G`$`2`$```(``0`-#```@`D"`+`````"``$`
+M`20``!"E`0#P`````@`!`!XD```PH`(`<P````(``0`L)```<+H!`!<#```"
+M``$`0R0``%#!`0"<`````@`!`&`D``"@"`(`V`````(``0!])```T%\!`,H`
+M```"``$`G"0``(`D`0"6#````@`!`+DD``!PH0(`7@````(``0#*)```$+`!
+M`#`````"``$`W"0``+`%`0!:`@```@`!`/DD```0V0$`H0````(``0`7)0``
+M\.D!`#D````"``$`.24``)"O`0!U`````@`!`%0E``#`>@(`0@````(``0!I
+M)0``4.8!`"T````"``$`@R4``*#>`0#B`0```@`!`),E```P0`(`-@,```(`
+M`0#:#```0,("`,`````"``$`L24``(#I`0!M`````@`!`,(E``"@[0$`C0``
+M``(``0#=)0``,.8!`"`````"``$`^"4``/`2`0!$`````@`!`!H-```P"@(`
+ML`````(``0`,)@``4`X!`$<````"``$`&B8``%",`@!3`````@`!`"X-``!@
+M>0(`5P````(``0`^#0``X`````0````!``D`@`T``/#3`0`F`````@`!`$(F
+M``!`"P$`00````(``0!;)@``D&4!`(@#```"``$`>"8``."7`0`J`0```@`!
+M`)XF``"0K`$`!@$```(``0"])@``X`L!`&$"```"``$`W"8``,#$`0"C````
+M`@`!```G``"0Y0$`10````(``0`9)P``8(("`!@````"``$`,R<``&#.`0#A
+M`````@`!`%PG``!P80$`8`,```(``0!U)P``L(\!`&T%```"``$`C"<``"`!
+M```<`````0`)`)\G``!@P`$`Y0````(``0"])P``0(H"``8````"``$`'`X`
+M`)"]`@!]`````@`!`-<G``"`L`$`*P````(``0#T)P``T*<!`"`$```"``$`
+M$R@``!`S`0!,`P```@`!`"TH```@U`$`&P$```(``0!"*```4``"`.@````"
+M``$`6"@``'#%`0`"`0```@`!`'LH``"`B@(`)0````(``0"8*```0-8!`#``
+M```"``$`KB@``)`H`@"E`````@`!`,0H``#0L`(`.P4```(``0#A*```,-`!
+M`+$````"``$`!2D``*`(`0!+`````@`!`!<I```0'0$`,`$```(``0`X*0``
+M<),"`*8!```"``$`42D``+"P`0`_`````@`!`&XI```PM@$`*@````(``0",
+M*0``L$($`%4````"``$`FBD``)`5`P":`````@`!`*HI````)@,`>@T```(`
+M`0#$*0``0#,$`,H)```"``$`U"D``&`^`P")`````@`!`.0I``#H`0``!```
+M``$`"0#T*0``P!,#``\````"``$`"2H``,`V`P`U`@```@`!`!XJ``#P+`0`
+M5`````(``0`V*@``00(```$````!``<`1BH``+!0`P"<`````@`!`%8J``"@
+M)`0`#@$```(``0!G*@``L"4$`)0````"``$`>RH``-`M!`"8`@```@`!`)$J
+M``#01@,`)0$```(``0"G*@``[`$```0````!``D`M2H``#`D!`!O`````@`!
+M`,TJ``#0_`,`AP````(``0#<*@``H&T#`$$````"``$`[BH``!`+`P`]`0``
+M`@`!``$K````2`,`I`$```(``0`9*P``0/T"`$L````"``$`+2L````Y`P!N
+M`@```@`!`$$K``!0-0,`6P````(``0!/*P``8!(#`*H````"``$`9"L``!`8
+M`P!9`````@`!`'4K```0$@,`1`````(``0",*P``]`$```$````!``D`H"L`
+M```\`P!?`````@`!`+LK``"`,P,`PP$```(``0#/*P``<#L#`(,````"``$`
+MWRL``,#^`@`D`````@`!`.@K``"P^P(`B`````(``0`$+```<#`$`/<````"
+M``$`&BP``'`B`P`;`P```@`!`"TL```P(00`.@````(``0`V+```$$,$`%4`
+M```"``$`1"P``+`@`P"V`0```@`!`&`L``"0;`,`^`````(``0!K+```@'`#
+M`+`````"``$`@2P``+"L`P`/`0```@`!`),L``"P;P,`SP````(``0"L+```
+MT!4$`$L````"``$`O2P``.!!`P!"`````@`!`,@L``"@%P0`B00```(``0#9
+M+```,!0#`'P````"``$`[BP``%`C!`#2`````@`!`/TL``"0`P,`W`````(`
+M`0`0+0``,/L"`!,````2``$`-RT``/@!```!````$0`)`$PM````````````
+M`!````!C+0``D$($`!(````2``$`>BT`````````````$````(TM``!@_@(`
+M)P```!(``0"?+0``@$$$`#D````2``$`KBT``%`,`P#F`0``$@`!`,4M``#@
+M`0,`B0```!(``0#<+0`````````````0````]"T``!!"!`!:````$@`!``TN
+M``"0^P(`$0```!(``0`D+@``@`H#`(L````2``$`.RX`````````````$```
+M`%8N```0``,`5P```!(``0!E+@`````````````0````;"X``'```P#&````
+M$@`!`'\N````_@(`)0```!(``0"6+@``8`4#`!P````2``$`JBX``-`.`P!7
+M`0``$@`!`,`N``!0)@0`6@(``!(``0#=+@``\`$```0````1``D`]"X``+`H
+M!``U!```$@`!``XO`````````````!`````C+P``<`0#`$D````2``$`.2\`
+M`)`6`P!>````$@`!`%0O``"0;0,`"@```!(``0!N+P`````````````0````
+M@"\``,!!!`!0````$@`!`)4O``#@`0``!````!$`"0"E+P``P!4$`!`````2
+M``$`OB\``)#_`@!Y````$@`!`-,O``#Y`0```0```!$`"0#K+P``D-,``!@`
+M```2``$`!C``````````````$````!`P```0%00`B````!(``0`G,```````
+M```````0````/C```'`"`P!8````$@`!`%$P`````````````!````!;,```
+MY`$```0````1``D`:C```$`!`P"8````$@`!`((P``#0`@,`P````!(``0"3
+M,```@&P#``L````2``$`JS``````````````$````,(P```P<0,`+P```!(`
+M`0#2,```]P$```$````1``D`[C``````````````$`````$Q````````````
+M`!`````4,0``0P(```$````1``<`*#$``!`%`P`B````$@`!`$TQ``"0'00`
+M2P,``!(``0!;,0``,*0"`!@````2``$`>#$``$`%`P`9````$@`!`)0Q````
+M`````````!````"L,0``,!P$`%4````2``$`P3$`````````````$````-<Q
+M``!0+00`?P```!(``0#R,0``X"`$`$H````2``$`!C(`````````````$```
+M`!8R`````````````!`````M,@``<$($`!(````2``$`1#(`````````````
+M$````%<R``"@_@(`%````!(``0!S,@``0/P"`,$````2``$`CC(``$`"```!
+M````$0`'`*$R``!0^P(`"P```!(``0"Y,@``]0$```$````1``D`U#(`````
+M````````$````-XR```0/00`]P(``!(``0#^,@``D$`$``,````2``$`&#,`
+M`)`>`P#%`0``$@`!`"\S``!`#@,`CP```!(``0!%,P``\/X"`#4````2``$`
+M7C,`````````````$````'4S``!@^P(`*````!(``0"-,P`````````````0
+M````H3,``##^`@`L````$@`!`+<S`````````````!````#(,P``<$`$`!@`
+M```2``$`YC,````)`P#5````$@`!``8T`````````````!`````:-```````
+M```````0````-S0``)#^`@`-````$@`!`%$T`````````````!````!D-```
+MH!0$`&H````2``$`>S0`````````````$````)8T``!@0`0``@```!(``0"I
+M-```(!8$`%L````2``$`OC0``!`3`P"A````$@`!`-8T```00`0`3P```!(`
+M`0#T-```$/T"`"H````2``$`(C4``$("```!````$0`'`#XU```P$`,`U@``
+M`!(``0!5-0``H!4$`!X````2``$`:C4``,`$`P!)````$@`!`(DU````````
+M`````!````"@-0``H`<#`%0!```2``$`O34``##_`@!;````$@`!`-(U``!P
+M(00`.0$``!(``0#O-0``]@$```$````1``D`"C8``%!1`P"4````$@`!``!R
+M-S4P7U1A9U]);FET`'(W-3!?57!D871E4&AY26YF;P!S87-?:&%S:%]A9&1R
+M`'(W-3!?5F5R:69Y0V]M;6%N9$)E9F]R95-E;F1I;F<`<C<U,%]"965P3VX`
+M<C<U,%]30U-)7T%405]&:6QL1&%T849I96QD`'!M7W-I9U]T:6UE7V]U=`!S
+M871A7W!O<G1?<W1O<F5?<VEG`'(W-3!?359?6F5R;TUV4F5Q=65S=`!I,F-!
+M7W=R:71E7V)Y=&5S`'(W-3!?359?1'5M<%)E<75E<W0`<C<U,%]-5E]);FET
+M:6%L:7IE5&%R9V5T241486)L90!S971?<&U?9F%I;%]L960`<V%T85]M86ME
+M7W-O9G1?<F5S971?<F5Q`'(W-3!?4')E<&%R94%N9%-E;F1#;VUM86YD`$]D
+M:6Y34$E?4F1P=`!R-S4P7TU67TUA<%1O4W!E8VEF:6-487)G971)1`!R-S4P
+M7U-#4TE?051!7T9I;&Q,0D%#9&(Q,`!R-S4P7U-'4$E/7U=R:71E4F5G:7-T
+M97(`<C<U,%]&<F5E4T%405-C<F%T8VA4;U!O;VP`<C<U,%]486=?1V5T3VYE
+M`'(W-3!?3V1I;E-025]);FET`'(W-3!?1G)E94EN=&5R;F%L4F5Q5&]0;V]L
+M`'=A=&EN9U]C86QL8F%C:P!R-S4P7T-O;7!L971E4F5Q=65S=$%N9%-L;W0`
+M<C<U,%]#;W)E7T=E=%-U<'!O<G1E9$-O=6YT<P!035]3971&86EL3&5D0V%L
+M;&)A8VL`<C<U,%]30U-)7T%405]697)I9GE4<F%N<VQA=&EO;@!R-S4P7U]?
+M<F5N97=?=&EM97(`<C<U,%]30U-)7T%405]3=&%R=%-T;W!4<F%N<VQA=&EO
+M;@!R-S4P7T9R965$979I8V54;U!O;VP`<C<U,%]0;W)T7T%B;W)T4F5Q=65S
+M=',`<')O9'5C=%]I9`!R-S4P7T-O<F5?36]D=6QE4V5N9%)E<75E<W0`<C<U
+M,%]&<F5E4&]R=%1O4&]O;`!I,F-"7W=R:71E7V)Y=&5S`'(W-3!?0V]R95])
+M;G1E<G)U<'1397)V:6-E4F]U=&EN90!R-S4P7U-'4$E/7U)E861296=I<W1E
+M<@!R-S4P7V]D:6Y?:6]C=&P`<C<U,%]S971?9F%I;%]L960`5&5S=%]0:6Y?
+M4V5T`'(W-3!?5&%G7TES16UP='D`<C<U,%]-5E]-87!487)G971)1`!R-S4P
+M7U]?861D7W1I;65R`'(W-3!?:3)C7W)E<V5T`'(W-3!?;79?9&ES86)L95]H
+M8F$`<C<U,%]#;W)E7U)E<51I;65O=70`<C<U,%]M=E]S971?4T%3061D<@!R
+M-S4P7T-O<F5?4F5S971#;613;&]T`'(W-3!?4F5M;W9E1&5V:6-E`&DR8T%?
+M<F5A9%]B>71E<P!A:6YF;P!R-S4P7T-O<F5?36]D=6QE26YI=&EA;&EZ90!R
+M-S4P7U-#4TE?051!7U)E861#87!A8VET>51R86YS;&%T:6]N0V%L;&)A8VL`
+M<C<U,%]-5E]3971,0D%A;F1396-T;W)#;W5N=`!O9&EN7V-O<F5?=&EM97(`
+M<C<U,%]S971?9F%I;%]L961S`'(W-3!?8V]R95]H86YD;&5?=&%S:V9I;&5?
+M97)R;W(`<C<U,%]O9&EN7W-E=%]S<&EN7W5P7VUO9&4`<&U?=V%I=%]F;W)?
+M<V]F=')E<V5T`'(W-3!?;79?96YA8FQE7WAM=`!R-S4P7TQI<W1?1V5T1FER
+M<W0`<C<U,%]3051!7T5R<F]R2&%N9&QI;F<`<C<U,%]3051!7U!O<G1(86YD
+M;&5);G1E<G)U<'0`<C<U,%]&<F5E4F5G:7-T97)3970`<C<U,%]3051!7U!O
+M<G1$971E8W0`<C<U,%]0;W)T7TAA;F1L95!L=6=I;@!R-S4P7T1E=FEC95])
+M<W-U95-O9G1297-E=`!R-S4P7U]?4$U?8V%N8V5L7W1I;65R`'(W-3!?4$U?
+M1G)E95)E9VES=&5R4V5T`'(W-3!?1V5T4T="=69F97)&<F]M4&]O;`!'9713
+M051!-C1+4V-R871C:$9R;VU0;V]L`'(W-3!?1V5T1&5V:6-E1G)O;5!O;VP`
+M1G)E94]N94-O;6UA;F13;&]T`'(W-3!?4T-325]!5$%?4WEN8T-A8VAE5')A
+M;G-L871I;VX`5&5S=%]0:6Y?26YI=&EA;&EZ90!R-S4P7TU67T=E=$UA<'!E
+M9$E$`$9R9653051!-C1+4V-R871C:%1O4&]O;`!R-S4P7U-!5$%?4')E<&%R
+M94-O;6UA;F1(96%D97(`;79?<&AY7W)E<V5T`'(W-3!?4T%405](86YD;&5$
+M979I8V55;G!L=6<`<C<U,%]30U-)7T%405]#:&5C:T-O;F1I=&EO;@!R-S4P
+M7T=E=$EN=&5R;F%L4F5Q1G)O;5!O;VP`<C<U,%]30U-)7T%405]296%D0V%P
+M86-I='E4<F%N<VQA=&EO;@!R-S4P7V1U;7!?=6YA<W-O8VEA=&5D7V9I<P!R
+M-S4P7T-O;7!L971E4F5Q=65S=`!R-S4P7T=E=%-!5$%38W)A=&-H1G)O;5!O
+M;VP`<C<U,%]#;W)E7TUO9'5L95-T87)T`'(W-3!?0V]R95](86YD;&5786ET
+M:6YG3&ES=`!R-S4P7U!R945M<'1Y4$T`<C<U,%]3051!7TAA;F1L941E=FEC
+M95!L=6=I;@!R-S4P7U-#4TE?5&]?1DE3`'(W-3!?4T%405]0;W)T4F5S970`
+M<C<U,%]'971/;F5#;VUM86YD4VQO=`!R-S4P7VUV7W)E<V5T7W!H>0!R-S4P
+M7U=R:71E1$5,5E]17T5N=')Y`'(W-3!?;V1I;E]S971?:61L95]S=&%N9&)Y
+M`'(W-3!?1V5T4$U&<F]M4&]O;`!R-S4P7TU67T5Q=6%L<P!R-S4P7TAA;F1L
+M94-O;6UA;F11=65U90!P;5]I;FET7W)E<5]C86QL8F%C:P!R-S4P7U-#4TE?
+M051!7U)E8617<FET951R86YS;&%T:6]N`'(W-3!?4T=486)L95]!<'!E;F0`
+M<C<U,%]035]!<W-I9VY296=I<W1E<E-E=`!P;W)T7W-E=%]F86EL7VQE9`!R
+M-S4P7U-!5$%?1&5V:6-E4W1A=&5-86-H:6YE`'(W-3!?4')E16UP='E$979I
+M8V4`<C<U,%]?7V-A;F-E;%]T:6UE<@!R-S4P7T-O<F5?<&%S<U]T:')U7V9I
+M;&Q?=&%S:V9I;&4`<C<U,%]31U!)3U]);FET:6%L:7IE`'(W-3!?4&]R=%](
+M86YD;&5$979I8V50;'5G:6X`<C<U,%]31U!)3U]3971?1F%I;&QE9`!S971?
+M<&U?9F%I;%]L961S`'(W-3!?359?0V]P>5-'5&%B;&4`=7!D871E7V1E=FEC
+M95]C;VYF:6<`<C<U,%]#;W)E7TUO9'5L945N86)L941I<V%B;&5)4E$`<C<U
+M,%]486=?26YI=%]&249/`$UA:V5$979);F9O`%!-7TES<W5E5W)I=&5&86EL
+M3&5D`'(W-3!?;V1I;E]F;&%S:%]A8V-E<W,`4T%405]035-T871E36%C:&EN
+M95-P:6Y5<`!R-S4P7U-!5$%?4&]R=$1E=FEC95)E861Y`'(W-3!?5&%G7U)E
+M;&5A<V5/;F4`<C<U,%]&<F5E4T="=69F97)4;U!O;VP`<C<U,%]$971E8W10
+M;W)T5'EP90!P;5]M86ME7W!M7W)E9VES=&5R7W)E<0!R-S4P7T1E=FEC95]0
+M87)S94ED96YT:69Y1&%T80!R-S4P7V1E=FEC95]P<F]B95]D;VYE`'(W-3!?
+M0F5E<$]F9@!G971?9FER<W1?<&T`3V1I;E-025]396-T;W)5;G!R;W1E8W0`
+M<&U?=V%I=%]F;W)?<W!I;G5P`'(W-3!?4T=486)L95]);FET`'(W-3!?4T%4
+M05]035]%<G)O<DAA;F1L:6YG`%-!5$%?2&%N9&QE4$U?2&]T4&QU9P!R-S4P
+M7U-#4TE?051!7T9I;&Q,0D%#9&(Q-@!'971!='1)9&5N=&EF>49R86UE`'(W
+M-3!?0V%T96=O<GE?0T1"7U1Y<&4`<C<U,%],:7-T7T=E=$QA<W0`<C<U,%]&
+M<F5E4$U4;U!O;VP`<C<U,%]M=E]D:7-A8FQE7W)E9VES=&5R7W-E=`!R-S4P
+M7U-!5$%?4&]R=$1E=FEC941E=&5C=&5D`'(W-3!?4&]R=%](86YD;&55;G!L
+M=6<`<C<U,%]!5$%?0T1",E1A<VM&:6QE`'(W-3!?359?4F5M;W9E5&%R9V5T
+M240`;V1I;E]S971?:&%R9%]D:7-K7VED96YT:69Y`'(W-3!?4T=486)L95]!
+M=F%I;&%B;&4`4&]R=$UA<%]2-S4P`$=E=$1E=DED96YT:69Y1G)A;64`:3)C
+M0E]R96%D7V)Y=&5S`'-A<U]A9&1R97-S7V-O=6YT`'!M7W-T871E7VUA8VAI
+M;F4`<C<U,%]0<F5P87)E1&5L:79E<GE1=65U945N=')Y`%5P9&%T94AI;5!A
+M=&A)9`!R-S4P7T-O<F5?36]D=6QE4VAU=&1O=VX`<C<U,%]035]#;W)E7U)E
+M<51I;65O=70`<C<U,%]5<&1A=&57:61E4&]R=%!H>4UA<`!R-S4P7T%S<VEG
+M;E)E9VES=&5R4V5T`'(W-3!?4V5R=FEC94EN=&5R<G5P=`!R-S4P7VUV7V1I
+M<V%B;&5?>&UT`'5P9&%T95]D979I8V5?8V]N9FEG7W8R`'(W-3!?0V]R95]-
+M;V1U;&5'971297-O=7)C95%U;W1A`'(W-3!?4&]R=%]3;V9T4F5S971#86QL
+M8F%C:P!R-S4P7VUV7W)E<V5T7WAM=`!R-S4P7VUV0VAA;FYE;%-T871E36%C
+M:&EN90!R-S4P7TDR0U]-;V1U;&5);FET:6%L:7IE`'(W-3!?;V1I;E]R96UO
+M=F5?9&5V:6-E`'(W-3!?1V5T4&]R=$9R;VU0;V]L`'(W-3!?359?1'5M<%)E
+M9VES=&5R`'!M7VAO=%]P;'5G7W)E<5]C86QL8F%C:P!035])<W-U95)E861&
+M86EL3&5D`&1C-S(X,%]31U1A8FQE7T%P<&5N9`!-86ME071T1&5V26YF;P!D
+M8S<R.#!?1G)E95-!5$%38W)A=&-H5&]0;V]L`&1C-S(X,%]0;W)T7T%B;W)T
+M4F5Q=65S=',`4$U?5W)I=&5296=3>6YC`&1C-S(X,%]3051!7U!O<G1(86YD
+M;&5);G1E<G)U<'0`9&,W,C@P7U-%4U]3971&86EL3&5D`&1C-S(X,%]305-?
+M26YT97)N86Q297%#86QL8F%C:P!D8S<R.#!?27-S=65?4F5P;W)T36%N=69A
+M8W1U<F5R26YF;W)M871I;VX`9&,W,C@P7U!O<G1?36]N:71O<@!D8S<R.#!?
+M0V]R95]-86ME1&5V:6-E4F5S971297$`9&,W,C@P7U-#4TE?5&]?1DE3`&1C
+M-S(X,%]O9&EN7W)E;6]V95]D979I8V4`9&,W,C@P7U-!5$%?4$U);FET4F5Q
+M0V%L;&)A8VL`9&,W,C@P7U!-7T-O<F5?4F5Q5&EM96]U=`!D8S<R.#!?1$E3
+M0U]'97149W1$979-87``9&,W,C@P7V]D:6Y?9FQA<VA?86-C97-S`&1C-S(X
+M,%]&<F5E4TU04V-R871C:%1O4&]O;`!D8S<R.#!?1&ES8V]V97)Y0V%L;$)A
+M8VL`9&,W,C@P7U1A9U]296QE87-E3VYE`&1C-S(X,%]#;W)E7TUO9'5L95-E
+M;F1297%U97-T`&1C-S(X,%]-5E]-87!4;U-P96-I9FEC5&%R9V5T240`9&,W
+M,C@P7T=E=%!-1&5V:6-E`&1C-S(X,%]35%!?1&5V:6-E4F5S970`9&,W,C@P
+M7T=E=$-O<F5#;VYT97AT1G)O;5!O;VP`9&,W,C@P7TU67TEN:71I86QI>F54
+M87)G971)1%1A8FQE`&1C-S(X,%]0<F5%;7!T>41E=FEC90!D8S<R.#!?3V1I
+M;E-025]);FET`&1C-S(X,%]!5$%?0T1",E1A<VM&:6QE`&1C-S(X,%]335!2
+M97-P3&5N9W1H`&1C-S(X,%]M=E]R97-E=%]P:'D`1&5V:6-E7TUA:V50<FEV
+M871E4V5N9%-E<U)E<75E<W0`9&,W,C@P7U!O<G1?1FEN9%1G=$YO`$%S<VEG
+M;D5L96UE;D1E<V-R:7!T;W).86UE`&1C-S(X,%]31U!)3U]7<FET95)E9VES
+M=&5R`$1E=FEC95]-86ME4V5S16QE;65N=%-T871U<U)E<75E<W14:6UE<@!D
+M8S<R.#!?0V]R95]);G1E<G)U<'1397)V:6-E4F]U=&EN90!D8S<R.#!?;79?
+M9&ES86)L95]X;70`9&,W,C@P7U-!5$%?4&]R=$1E=&5C=`!035]296%D4F5G
+M4WEN8P!D8S<R.#!?1G)E941E=FEC951O4&]O;`!D8S<R.#!?17AP86YD97)?
+M4TU04F5Q7T-A;&QB86-K`&1C-S(X,%]$979I8V5?36%K95-E<U)C=D1I86=2
+M97%U97-T`&1C-S(X,%]0;W)T7U-O9G1297-E=$-A;&QB86-K`&1C-S(X,%])
+M<W-U95]#;VYF:6=2;W5T94EN9F\`9&,W,C@P7U!O<G1?27-297%U97-T4G5N
+M;FEN9P!D8S<R.#!?5F5R:69Y0V]M;6%N9$)E9F]R95-E;F1I;F<`9&,W,C@P
+M7T1E=FEC95]-86ME4W1A<G13=&]P56YI=%)E<75E<W0`9&,W,C@P7T9R965%
+M>'!A;F1E<E1O4&]O;`!D8S<R.#!?0V]R95)E<W1O<F5/<FEG:6YA;$-$0@!D
+M8S<R.#!?4&]S=$UA:V5397-%;F-L;W-U<F53=&%T=7-297%U97-T`&1C-S(X
+M,%]D=6UP7W5N87-S;V-I871E9%]F:7,`9&,W,C@P7TU67UIE<F]-=E)E<75E
+M<W0`9&,W,C@P7T=E=%!O<G1&<F]M4&]O;`!D8S<R.#!?1FEN9$%S8VEI3G5M
+M8F5R`&1C-S(X,%]305-?4&]R=%)E<V5T`&1C-S(X,%]-5E]'971-87!P961)
+M1`!D8S<R.#!?4T-325]!5$%?4F5A9%=R:71E5')A;G-L871I;VX`9&,W,C@P
+M7U!O<W1-86ME4V5S0V]N9FEG=7)A=&EO;E)E<75E<W0`9&,W,C@P7T1E=FEC
+M95]-86ME4F5Q=65S=%1A<VM297%U97-T`&1C-S(X,%]0;W)T7TAA;F1L941E
+M=FEC95!L=6=I;@!D8S<R.#!?4$U?07-S:6=N4F5G:7-T97)3970`9&,W,C@P
+M7T-O<F5?4F5S971#;613;&]T`&1C-S(X,%]M=E]D:7-A8FQE7VAB80!D8S<R
+M.#!?7U]A9&1?=&EM97(`9&,W,C@P7U-#4TE?36%K94UO9&5086=E0V%C:&EN
+M9P!D8S<R.#!?0T]215])<W-U95--4%)E<75E<W0`<V5T7V5M7V9A:6Q?;&5D
+M`&1C-S(X,%]!<W-I9VY$979I8V5/=F5R86QL16QE;65N=$YU;6)E<@!D8S<R
+M.#!?5W)I=&5$14Q67U%?16YT<GD`9&,W,C@P7U-#4TE?051!7U9E<FEF>51R
+M86YS;&%T:6]N`&1C-S(X,%]C;W)E7VAA;F1L95]T87-K9FEL95]E<G)O<@!D
+M8S<R.#!?4T=024]?4TU04F5Q=65S=%]7<FET90!D8S<R.#!?4T%37TAA;F1L
+M94-O;7!L971E9$-O;6UA;F0`9&,W,C@P7T1E=FEC95]-86ME4F5A9$-A<&%C
+M:71Y,39487-K4F5Q=65S=`!D8S<R.#!?4&]S=$UA:V5397-%;&5M96YT4W1A
+M='5S4F5Q=65S=`!D8S<R.#!?4T%405]035](86YD;&5$979I8V50;'5G:6X`
+M9&,W,C@P7V]D:6Y?<V5T7W-P:6Y?=7!?;6]D90!D8S<R.#!?0V]R95](86YD
+M;&5786ET:6YG3&ES=`!D8S<R.#!?4')E<&%R941E;&EV97)Y475E=65%;G1R
+M>0!D8S<R.#!?4T=024]?4TU04F5Q=65S=%]296%D`&1C-S(X,%]$25-#7T-A
+M;F-E;$1I<V-O=F5R`&1C-S(X,%]5<&1A=&57:61E4&]R=%!H>4UA<`!D8S<R
+M.#!?2&%N9&QE0V]M;6%N9%%U975E`&1C-S(X,%]$25-#7T=E=%)E<V]U<F-E
+M`&1C-S(X,%]30U-)7T%405]&:6QL3$)!0V1B,38`9&,W,C@P7T-O<F5?36]D
+M=6QE16YA8FQE1&ES86)L94E240!D8S<R.#!?:3)C7W)E<V5T`&1C-S(X,%]&
+M<F5E4F5G:7-T97)3970`9&,W,C@P7T)E97!/9F8`<V5T7V5M7V9A:6Q?;&5D
+M<P!D8S<R.#!?1$E30U]#:&5C:T1I<V-O=F5R4W1A=&4`9&,W,C@P7T5X<&%N
+M9&5R7U--4%)E<75E<W1?4F5P;W)T1V5N97)A;`!D8S<R.#!?23)#7TUO9'5L
+M94EN:71I86QI>F4`9&,W,C@P7V1E=FEC95]P<F]B95]D;VYE`&1C-S(X,%]2
+M96UO=F5$979I8V4`9&,W,C@P7U)U;G1I;65)<W-U95-O9G1297-E=$-A;&QB
+M86-K`&1C-S(X,%]31U!)3U]3971?1F%I;&QE9`!D8S<R.#!?1V5T36%X3F5G
+M;W1I871E9$QI;FM2871E`&1C-S(X,%]&<F5E4T534T)4;U!O;VP`9&,W,C@P
+M7TQI<W1?1V5T3&%S=`!D8S<R.#!?4$U?27-S=657<FET95)E9P!D8S<R.#!?
+M<V5T7V9A:6Q?;&5D`&1C-S(X,%]486=?27-%;7!T>0!D8S<R.#!?57!D871E
+M5&=T1&5V36%P`&1C-S(X,%]486=?26YI=`!G971?:61?9G)O;5]E;F-)9`!3
+M15-?4')I=F%T95)E<4-A;&QB86-K`&1C-S(X,%]3051!7U!-2&]T<&QU9U)E
+M<4-A;&QB86-K`%-!4U]297!O<G1,=6Y38V%N`&1C-S(X,%]0;W-T36%K95-E
+M<T5L96UE;G1$97-C<FEP=&]R4F5Q=65S=`!D8S<R.#!?1G)E95!O<G14;U!O
+M;VP`9&,W,C@P7TU67TUA<%1A<F=E=$E$`&1C-S(X,%]035])<W-U95)E8612
+M96<`9&,W,C@P7T-O<F5?36]D=6QE4VAU=&1O=VX`9&,W,C@P7U5P9&%T95!H
+M>4EN9F\`9&,W,C@P7U]?<F5N97=?=&EM97(`9&,W,C@P7T1E=FEC95]-86ME
+M4F5A9$-A<&%C:71Y5&%S:U)E<75E<W0`9&,W,C@P7T=E=$1E=FEC949R;VU0
+M;V]L`&1C-S(X,%]'971315-30D9R;VU0;V]L`&1C-S(X,%]!<W-I9VY%;&5M
+M96YT4VQO=$YU;6)E<@!!<W-I9VY397-/=&AE<D5L96UE;G1/=F5R86QL16QE
+M;65N=$YU;6)E<@!D8S<R.#!?4&]R=%](86YD;&55;G!L=6<`9&,W,C@P7T-O
+M<F5?36]D=6QE4W1A<G0`9&,W,C@P7T1I<V-O=F5R>5--`&1C-S(X,%]30U-)
+M7T%405]#:&5C:T-O;F1I=&EO;@!D8S<R.#!?359?0V]P>5-'5&%B;&4`9&,W
+M,C@P7U-!5$%?1&5V:6-E4W1A=&5-86-H:6YE`&1C-S(X,%]$979I8V5?36%K
+M94EN<75I<GE487-K4F5Q=65S=`!D8S<R.#!?1&5V:6-E7U!A<G-E261E;G1I
+M9GE$871A`&1C-S(X,%]3051396YS941A=&$`9&,W,C@P7T=E=$Y#451A9P!O
+M9&EN7V5M7V%C8V5S<P!D8S<R.#!?;79#:&%N;F5L4W1A=&5-86-H:6YE`&1C
+M-S(X,%]3=&]R95]#;VYF:6=2;W5T94EN9F\`9&,W,C@P7U-'5&%B;&5?26YI
+M=`!D8S<R.#!?1V5T17AP86YD97)&<F]M4&]O;`!$979I8V5?4F5P;W)T3'5N
+M4F5Q=65S=`!D8S<R.#!?4T%37TAA;F1L94)21$-35`!D8S<R.#!?0V]R95-A
+M=F5/<FEG:6YA;$-$0@!D8S<R.#!?359?1'5M<%)E<75E<W0`9&,W,C@P7TQI
+M<W1?1V5T1FER<W0`9&,W,C@P7U-#4TE?051!7T9I;&Q$871A1FEE;&0`9&,W
+M,C@P7U-#4TE?051!7U-Y;F-#86-H951R86YS;&%T:6]N`&1C-S(X,%]31U!)
+M3U]);FET:6%L:7IE`&1C-S(X,%]&<F5E4TU00V]N=&5X=`!D8S<R.#!?1FEL
+M;$5N8VQO<W5R945L96UE;G13=&%T=7,`9&,W,C@P7T-O<F5?36]D=6QE26YI
+M=&EA;&EZ90!D8S<R.#!?4T%405]035-T871E36%C:&EN90!D8S<R.#!?1G)E
+M95!-5&]0;V]L`&1C-S(X,%]3051!7U!R97!A<F5#;VUM86YD5&%B;&4`9&,W
+M,C@P7T-O<F5?36]D=6QE1V5T4F5S;W5R8V51=6]T80!D8S<R.#!?1G)E95-'
+M0G5F9F5R5&]0;V]L`&1C-S(X,%]486=?26YI=%]&249/`&1C-S(X,%]30U-)
+M7T%405]296%D0V%P86-I='E4<F%N<VQA=&EO;D-A;&QB86-K`&1C-S(X,%]?
+M7U!-7V-A;F-E;%]T:6UE<@!D8S<R.#!?359?1'5M<%)E9VES=&5R`&1C-S(X
+M,%]397)V:6-E26YT97)R=7!T`$1E=FEC95]-86ME4')I=F%T95)E8W9397-2
+M97%U97-T`&1C-S(X,%])<W-U95]$:7-C;W9E<@!D8S<R.#!?1$E30U]$;T1I
+M<V-O=F5R`&1C-S(X,%]3051!7TAA;F1L941E=FEC955N<&QU9P!D8S<R.#!?
+M0V]R95]);G1E<FYA;%-E;F1297%U97-T`&1C-S(X,%]$25-#7U-E=%)E<V]U
+M<F-E`&1C-S(X,%]3051!7U!-7TAA;F1L941E=FEC955N<&QU9P!D8S<R.#!?
+M4T%405]0;W)T1&5V:6-E1&5T96-T960`9&,W,C@P7U5P9&%T951A<F=E=$1E
+M=FEC97,`9&,W,C@P7U-#4TE?051!7U-T87)T4W1O<%1R86YS;&%T:6]N`&-H
+M96-K7U-A<T%D9'(`9&,W,C@P7T-O<F5?<&%S<U]T:')U7V9I;&Q?=&%S:V9I
+M;&4`9&,W,C@P7VUV7V1I<V%B;&5?<F5G:7-T97)?<V5T`$1E=FEC95]497-T
+M56YI=%)E861Y4F5Q=65S=`!D8S<R.#!?07-S:6=N1&5V:6-E16QE;65N=$YU
+M;6)E<@!D8S<R.#!?1V5T36EN3F5G;W1I871E9$QI;FM2871E`&1C-S(X,%]M
+M=E]S971?4T%3061D<@!D8S<R.#!?4$U?1G)E95)E9VES=&5R4V5T`&1C-S(X
+M,%]%>'!A;F1E<E]335!297%U97-T7U!H>4-O;G1R;VP`9&,W,C@P7TU67T5Q
+M=6%L<P!D8S<R.#!?1V5T4T="=69F97)&<F]M4&]O;`!D8S<R.#!?4T-325]!
+M5$%?3&]W97)7;W)D`&1C-S(X,%]#:&5C:T1E=FEC94-H86YG90!D8S<R.#!?
+M4T%37T5R<F]R2&%N9&QI;F<`9&,W,C@P7T)E97!/;@!D8S<R.#!?4T=024]?
+M4TU04F5Q7T-A;&QB86-K`'-C<VEL=6Y?=&]?:6YT`&1C-S(X,%]31U1A8FQE
+M7T%V86EL86)L90!D8S<R.#!?4TU07U-'4$E/7U-E=%]&86EL;&5D`&1C-S(X
+M,%]#;W)E7T9I;&Q396YS941A=&$`9&,W,C@P7T=E=%--4%-C<F%T8VA&<F]M
+M4&]O;`!D8S<R.#!?4T%405]0;W)T1&5V:6-E4F5A9'D`9&,W,C@P7VUV7V5N
+M86)L95]X;70`9&,W,C@P7T%S<VEG;E)E9VES=&5R4V5T`&1C-S(X,%]O9&EN
+M7VEO8W1L`&1C-S(X,%])<W-U95]297!O<G12;W5T94EN9F\`9&,W,C@P7T=E
+M=$EN=&5R;F%L4F5Q1G)O;5!O;VP`9&,W,C@P7T-H96-K5&%R9V5T0VAA;F=E
+M`&1C-S(X,%]$979I8V5?5W)I=&5397-#;VYT<F]L1&EA9P!315-4:6UE<E])
+M;G1E<FYA;%)E<4-A;&QB86-K`&=E=%]E;F-?8V]U;G0`9&,W,C@P7T-O;7!L
+M971E4F5Q=65S=`!D8S<R.#!?4G5N=&EM94ES<W5E4V]F=%)E<V5T`&1C-S(X
+M,%]$979I8V5?27-S=653;V9T4F5S970`9&,W,C@P7U-!5$%?2&%N9&QE1&5V
+M:6-E4&QU9VEN`&1C-S(X,%]0<F5P87)E06YD4V5N9$-O;6UA;F0`9V5T7VUI
+M;E]P;5!A=&A)9`!D8S<R.#!?4')E16UP='E030!D8S<R.#!?4T-325]-86ME
+M0V%C:&5#;VUM86YD`&1C-S(X,%]#;VUP;&5T95)E<75E<W1!;F13;&]T`&1C
+M-S(X,%]$25-#7T=E=$YE9V]T:6%T961,:6YK4F%T90!D8S<R.#!?1FEN9%)U
+M;FYI;F=297%">51A9P!D8S<R.#!?<V5T7V9A:6Q?;&5D<P!D8S<R.#!?1FEN
+M9$9R965335!#;VYT97AT`%)E;6]V95-!4T1E=FEC90!D8S<R.#!?4T%37T1E
+M=FEC95-T871E36%C:&EN90!D8S<R.#!?1FEN9%1G=$YO`&1C-S(X,%])<W-U
+M95]297!O<G1'96YE<F%L`&1C-S(X,%]#86QC=6QA=&52;W5T94EN9&5X`&1C
+M-S(X,%]M=E]R97-E=%]X;70`9&,W,C@P7TU67T-20P!D8S<R.#!?4T-325]!
+M5$%?4F5A9$-A<&%C:71Y5')A;G-L871I;VX`9&,W,C@P7TU67U)E;6]V951A
+M<F=E=$E$`&1C-S(X,%]3051!7U!-7T5R<F]R2&%N9&QI;F<`9&,W,C@P7U5P
+M9&%T95-T871U<U9S4V5S0V]N=')O;$)U9F9E<@!D8S<R.#!?0V]R95]'9713
+M=7!P;W)T961#;W5N=',`9&,W,C@P7TU67U-E=$Q"06%N9%-E8W1O<D-O=6YT
+M`&1C-S(X,%]$979I8V5?36%K94UO9&5396QE8W1297%U97-T`&1C-S(X,%]'
+M971/;F5#;VUM86YD4VQO=`!D8S<R.#!?4T=024]?4F5A9%)E9VES=&5R`&1C
+M-S(X,%]%>'!A;F1E<E]335!297%U97-T7U)E<&]R=%!(65-!5$$`9&,W,C@P
+M7U!O<G1?2&%N9&QE4&QU9VEN`&1C-S(X,%]#;W)E7U)E<51I;65O=70`9&,W
+M,C@P7VUO9&5086=E0G5F`&1C-S(X,%]2=6YT:6UE27-S=65296%D3&]G17AT
+M`&1C-S(X,%]30U-)7T%405]5<'!E<E=O<F0`9&,W,C@P7T9R965#;W)E0V]N
+M=&5X=%1O4&]O;`!D8S<R.#!?4T537TEN=&5R;F%L4F5Q0V%L;&)A8VL`9&,W
+M,C@P7U-!5$%?17)R;W)(86YD;&EN9P!D8S<R.#!?1V5T4$U&<F]M4&]O;`!D
+M8S<R.#!?1&5T96-T4&]R=%1Y<&4`9&,W,C@P7T1E=FEC95]-86ME36]D95-E
+M;G-E4F5Q=65S=`!D8S<R.#!?4T-325]!5$%?1FEL;$Q"04-D8C$P`&1C-S(X
+M,%]?7V-A;F-E;%]T:6UE<@!D8S<R.#!?4T%405]0;W)T4F5S970`9&,W,C@P
+M7V]D:6Y?<V5T7VED;&5?<W1A;F1B>0!D8S<R.#!?17AP86YD97)?4TU04F5Q
+M=65S=%]$:7-C;W9E<@!D8S<R.#!?5&%G7T=E=$]N90!D8S<R.#!?4T%405]0
+M<F5P87)E0V]M;6%N9$AE861E<@!D8S<R.#!?0V%T96=O<GE?0T1"7U1Y<&4`
+M9&,W,C@P7T9R965);G1E<FYA;%)E<51O4&]O;`!D8S<R.#!?1V5T4T%405-C
+M<F%T8VA&<F]M4&]O;`!3=V%P2'!T365T858S`&QD;5]S<&EN=7!?=F1E=@!R
+M87=?8VAE8VM?9&ES:U]D97-C<FEP=&]R`&QD;5]C:&5C:U]A<G)A>0!L9&U?
+M<F5C:&5C:U]A;&P`=F1E=E]C;&%S<U]L:7-T`')A=U]I9&QE7W1I;65R7W)E
+M<V5T`&QD;5]D96QE=&5?<&%R=&ET:6]N`&QD;5]S>6YC7V-H86YG961?87)R
+M87ES`&=R96)U:6QD;VYE<G)O<@!L9&U?<75E=65?979E;G0`=')A;G-F;W)M
+M7VYE961E9`!L9&U?8VAE8VM?=')A;G-F;W)M`&QD;5]F:7AU<%]A<G)A>5]S
+M=&%T90!C86QC7W)E8G5I;&1?<')O9W)E<W,`=F)U<U]E>'1?<VEZ90!S971?
+M=')A;G-F;W)M7W-T97!?:6YF;P!L9&U?:61L95]T:6UE<@!L9&U?9FEN9%]V
+M9&5V7W)A=P!L9&U?<F5P<F]B95]D979I8V4`8V%L8U]T<F%N<V9O<FU?<')O
+M9W)E<W,`;&1M7V9I;F1?=F1E=E]C;&%S<P!L9&U?86QL;V-?<&%R=&ET:6]N
+M`&QD;5]I;FET7V1I<VL`<F5F<F5S:%]R87=?9&5V7VEN9F\`7V1E;&5T95]R
+M87=?<&%R=`!R87=?<F5A9%]W<FET95]S96-T;W)S`&=I9&QE<W1A;F1B>71I
+M;65O=70`<F%W7V-H96-K7V%R<F%Y7V1E<V-R:7!T;W(`;&1M7V-R96%T95]V
+M9&5V7W)A=P!U;G!L=6=?<F%W7W9D978`0VAE8VM3=6T`8V]M<&%R95]S;&]T
+M7W-E<5]B>5]P8VEA9&1R`&QD;5]A9&1?9&ES:U]T;U]A<G)A>0!L9&U?<WEN
+M8U]D:7-K7VEN9F\`9V5T7V)I=',`4W=A<$AP=$UE=&%6-`!R87=?8V]N=F5R
+M=%]S<&%R95]T;U]L96=A8WD`9DYO=&EF>4=520!L9&U?9FQU<VA?86QL7W1A
+M<F=E=',`;&1M7W-T87)T7W)E8G5I;&0`;&1M7W-P:6YD;W=N7V%L;%]R87=D
+M979S`%]?;&1M7V9I;FES:%]C;60`241?5$]?5D1%5@!?7W9D979?<75E=65?
+M8VUD`')A=U]I9&QE7W1I;65R7V-H96-K`&=E=%]S=')I<%]I;F9O`&QD;5]R
+M97-U;65?861A<'1E<@!H<'1N<E]L9&U?<F5G:7-T97)?:&EM7U)?-E\U-5\W
+M-5\T-E\V-`!H<'1N<E]G1VQO8F%L3F-Q1FQA9P!H<'1N<E]O<U]R97%U97-T
+M7W1I;65R`&AP=&YR7V1M87!O;VQ?9V5T7W!A9V4`:'!T;G)?;W-?9V5T7W-T
+M86UP`&AP=&YR7VQD;5]S=7-P96YD`&AP=&YR7VQD;5]I9&QE`&AP=&YR7VQD
+M;5]G971?;65M7VEN9F\`:'!T;G)?;&1M7W)E;6]V95]T:6UE<@!H<'1N<E]P
+M8VEC9F=?<F5A9%]D=V]R9`!H<'1N<E]D;6%P;V]L7VUA:V5?;W)D97(`:'!T
+M;G)?;&1M7V=E=%]V8G5S7V5X=`!H<'1N<E]L9&U?<F5L96%S95]V9&5V`&AP
+M=&YR7V9R965L:7-T7W)E<V5R=F5?9&UA`&AP=&YR7VQD;5]I;G1R`&UE;6-P
+M>0!H<'1N<E]L9&U?;VY?=&EM97(`:'!T;G)?;&1M7V=E=%]C;61?<VEZ90!H
+M<'1N<E]L9&U?9G)E95]C;61S`&AP=&YR7VQD;5]C<F5A=&5?=F1E=@!H<'1N
+M<E]L9&U?861D7W-P87)E7W1O7V%R<F%Y`&AP=&YR7V=R96)U:6QD<')I;W)I
+M='D`:'!T;G)?;&1M7W-Y;F-?87)R87E?:6YF;P!H<'1N<E]O<U]M87!?<&-I
+M7V)A<@!H<'1N<E]?7VQD;5]A;&QO8U]C;60`:'!T;G)?:6YI=%]M;V1U;&5?
+M=F1E=E]R87<`:'!T;G)?;&1M7W-E=%]A=71O<F5B=6EL9`!H<'1N<E]?7V1U
+M;6UY7W)E9P!H<'1N<E]D;6%P;V]L7V%C=&EV90!H<'1N<E]V8G5S7VQI<W0`
+M:'!T;G)?;&1M7W%U975E7W9B=7-?9'!C`&AP=&YR7VQD;5]R97-E=%]V8G5S
+M`&AP=&YR7V=31U!)3U!A<G13=7!P;W)T`&AP=&YR7VEN:71?;6]D=6QE7VAI
+M;5]R-S4P`%]?=6UO9&1I,P!H<'1N<E]L9&U?<F5L96%S95]L;V-K`&AP=&YR
+M7V]S7W5N;6%P7W!C:5]B87(`:'!T;G)?;&1M7W-H=71D;W=N`%]?=61I=F1I
+M,P!H<'1N<E]H:6U?;&ES=`!H<'1N<E]L9&U?<F5Q=65S=%]T:6UE<@!H<'1N
+M<E]L9&U?<F5S=6UE`&AP=&YR7VQD;5]G971?9&5V:6-E7VED`&AP=&YR7V]S
+M7W-C:&5D=6QE7W1A<VL`:'!T;G)?;&1M7VEO8W1L`&AP=&YR7V=3<&EN=7!/
+M;F5$979%86-H5&EM90!H<'1N<E]F<F5E;&ES=%]P=70`:'!T;G)?;W-?<W1A
+M;&QE>&5C`&AP=&YR7V=?;&5G86-Y7VUO9&4`:'!T;G)?;&1M7V%L;&]C7V-M
+M9'-?4E\V7S4U7S<U7S0V7S8T`&AP=&YR7VQD;5]R=6X`:'!T;G)?:6YI=%]M
+M;V1U;&5?:&EM7V1C-S(X,`!H<'1N<E]L9&U?9G)E95]C;61S7W1O7VQI<W0`
+M:'!T;G)?;W-?;6%X7V-A8VAE7W-I>F4`:'!T;G)?=F1E=E]Q=65U95]C;60`
+M:'!T;G)?;W-?9V5T7W9B=7-?<V5Q`&AP=&YR7VQD;5]S>6YC7V%R<F%Y7W-T
+M86UP`&AP=&YR7VQD;5]Q=65U95]C;60`:'!T;G)?;W-?<')I;G1K`&AP=&YR
+M7V9R965L:7-T7W)E<V5R=F4`:'!T;G)?9&UA<&]O;%]P=71?<&%G90!H<'1N
+M<E]F<F5E;&ES=%]G970`:'!T;G)?;&1M7W5N<F5G:7-T97)?9&5V:6-E`&AP
+M=&YR7VQD;5]R96=I<W1E<E]A9&%P=&5R`&AP=&YR7V=A=71O<F5B=6EL9`!H
+M<'1N<E]L9&U?9V5T7W9B=7-?<VEZ90!H<'1N<E]D96QA>5]B971W965N7W-P
+M:6YU<`!H<'1N<E]M<VD`:'!T;G)?;&1M7V=E;F5R:6-?;65M8F5R7V9A:6QE
+M9`!H<'1N<E]D;6%P;V]L7V=E=%]P86=E7V%T`&AP=&YR7VQD;5]E=F5N=%]N
+M;W1I9GD`:'!T;G)?;&1M7V-R96%T95]V8G5S`&AP=&YR7VAI;5]H86YD;&5?
+M=&]?=F)U<P!H<'1N<E]F<F5E;&ES=%]G971?9&UA`&AP=&YR7VQD;5]G971?
+M;F5X=%]V8G5S`&AP=&YR7V]S7W!C:5]W<FET96P`:'!T;G)?;&1M7V9I;F1?
+M=&%R9V5T`&AP=&YR7V1E8G5G7V9L86<`:'!T;G)?9&UA<&]O;%]R96=I<W1E
+M<E]C;&EE;G0`:'!T;G)?;&1M7VEN:71I86QI>F5?=F)U<U]A<WEN8P!H<'1N
+M<E]O<U]Q=65R>5]T:6UE`&AP=&YR7V]S7W%U97)Y7W)E;6]V95]D979I8V4`
+M:'!T;G)?;&1M7W)E9VES=&5R7V1E=FEC90!H<'1N<E]O<U]P8VE?<F5A9&P`
+M:'!T;G)?;&1M7V%C<75I<F5?;&]C:P!H<'1N<E]O<U]R979A;&ED871E7V1E
+M=FEC90!H<'1N<E]D;6%P;V]L7VEN:70`:'!T;G)?;&1M7V9I;FES:%]C;60`
+M:'!T;G)?;&1M7VED95]F:7AS=')I;F<`:'!T;G)?9&UA<&]O;%]M87A?8VQA
+M<W-?<&%G97,`:'!T;G)?;&1M7W)E9VES=&5R7W9D979?8VQA<W-?4E\V7S4U
+M7S<U7S0V7S8T`&AP=&YR7VYU;5]D<FEV97-?<&5R7W-P:6YU<`!H<'1N<E]L
+M9&U?<F5L96%S95]V8G5S`&AP=&YR7VQD;5]Q=65U95]T87-K`&AP=&YR7VQD
+M;5]A;&QO8U]C;61S7V9R;VU?;&ES=`!H<'1N<E]F<F5E;&ES=%]P=71?9&UA
+M`&AP=&YR7VQD;5]T:6UE<E]P<F]B95]D979I8V4`:'!T;G)?;&1M7V9I;F1?
+M<W1A;7``:'!T;G)?;&1M7V-H96-K7V%R<F%Y7V]N;&EN90!H<'1N<E]G4')O
+M8F5);DEN:71I86QI>FEN9P!H<'1N<E]L;V=?<V5C=&]R7W)E<&%I<@````@#
+M```".```N@8```$%``"_!@```CT"``P'```"$@(`Q`<```$>`@#T!P```1X"
+M`%0(```!'@(`W0@```$>`@`8"0```1X"`(()```",@(`O`D```(R`@#^"0``
+M`C("`#@*```",@(`G`H```*M``"H"@```C("`+0*```"2@``*`L```$>`@`V
+M"P```1X"`$<+```",@(`6@L```$>`@!H"P```1X"`'L+```!'@(`A`L```$>
+M`@"G"P```C("`+(+```!'@(`TPL```(R`@#>"P```1X"`/\+```!'@(`&@P`
+M``$>`@!C#````1X"`'H,```!'@(`E@P```$>`@"K#````1X"`,D,```!'@(`
+MU`P```$>`@`!#0```C("``\-```!'@(`-@T```(R`@!$#0```1X"`#01```"
+M,@(`1A$```$>`@!P$0```C("`($1```!'@(`GQ$```$%``"D$0```CT"`-81
+M```",@(`Z!$```$>`@`4$@```C("`"42```!'@(`4!(```(R`@!B$@```1X"
+M`(X2```",@(`GQ(```$>`@#5$@```1X"`.X2```!!0``\Q(```(]`@`%$P``
+M`1X"`"(3```!'@(`I1,```(+`@"X$P```ID``-P3```"2P``0!0```(^``!,
+M%````B8``&\4```"$@``AA0```)V``"E%````:$``,`4```!!0``Q10```(]
+M`@#B%````DD"`/\4```"20(`&A4```(L``!%%0```1X"`'@5```!'@(`ZA4`
+M``$>`@`#%@```1X"`"$6```"%0``2Q8```$>`@!@%@```1X"`,46```!'@(`
+MW18```$>`@`%%P```@L"`"47```"FP``9!<```)+``":%P```DD"`+87```"
+M+0``Y!<```)=``#P%P```C("`!88```!`0``01@```(K`@!?&````1X"`&\8
+M```!'@(`DQ@```$>`@"C&````1X"`,L8```!'@(`]1@```$>`@`D&0```1X"
+M`#T9```!'@(`;AD```$%``!S&0```CT"`)$9```!'@(`NQD```$>`@`&&@``
+M`1X"`"(:```!'@(`/QH```$>`@!;&@```1X"`*L:```"20(`T!H```(+`@#>
+M&@```90``/`:```"*P(`%1L```$&```:&P```CT"`#P;```!'@(`61L```$>
+M`@!U&P```C("`(4;```!'@(`I1L```$>`@#"&P```1X"`-X;```",@(`[AL`
+M``$>`@`2'````1X"`$(<```"%0``I1P```(M``#('````BT``-X<```"I0``
+MHAT```(M``#"'0```BT``-\=```"2P``$QX```))`@`K'@```BT``$P>```"
+ME```H!X```(M``#`'@```BT``(X?```!!@``DQ\```(]`@"P'P```I<``.X?
+M```"-P``3R````(1``">(0```FL``&$B```"G0``P"(```)Z``#F(@```IT`
+M`+DC```"7```U2,```)I```H)````G4``$PD```"I@``4B0```%0`@!P)```
+M`JL``)0D```"I@``J"0```)M``##)````04``,@D```"/0(`^B0```)+``!$
+M)0```F,``)$E```"8P``GR4```(<``#*)0```F,``/8E```".0``&2<```(M
+M``".)P```DL``,(G```"20(`_"<```(M```,*````G<``$HH```""P(`8B@`
+M``&4``!]*````BL"`+TH```"+0``UB@```(_``#D*````F8``$`I```">0``
+M3"D```).``!@*0```CX``'0I```"5P``IBD```)+``"X*0```CX``,@I```"
+M5P``!BH```),``#Y*@```5`"`%$K```"$@(`;2L```$>`@"9*P```1X"`-4K
+M```!'@(`^"L```$>`@!Q+````:$``)PL```!!0``H2P```(]`@##+````:$`
+M`.XL```!!0``\RP```(]`@`R+0```04``#<M```"/0(`9"T```$%``!I+0``
+M`CT"`(DM```"/@``MBT```$>`@#>+0```1X"`/0M```!'@(`#2X```$>`@`Z
+M+@```04``#\N```"/0(`X2X```)'``#]+@```1X"`"LO```!'@(`@R\```$>
+M`@"B+P```1X"`,LO```"K```.S````$>`@"],````JP``-$P```"K```/3$`
+M``$%``!",0```CT"`),Q```!!@``F#$```(]`@"J,0```A@``-TQ```!!0``
+MXC$```(]`@"$,@```A@``)`R```")@``^S(```)-```L,P```DL``-8S```"
+M2P```#0```(F```0-````F8``$8T```!'@(`;S0```$>`@"(-````1X"`*@T
+M```!'@(`P30```$>`@#7-````H$``.4T```"<0``\S0```)Q```)-0```H$`
+M`(8U```!'@(`K#4```(R`@#3-0```1X"`/@U```",@(`'38```$>`@!"-@``
+M`C("`)$V```"?0``LS8```)>``##-@```@\``/(V```",```.3<```(M``!)
+M-P```@\``)0W```"2P``N3<```(R``#%-P```C("`/XW```"$@``%3@```)V
+M```N.````:$``$TX```!!0``4C@```(]`@!S.````DD"`)`X```"20(`JS@`
+M``(L``#(.````C```$PY```!'@(`;3D```(R`@"%.0```1X"`*4Y```!'@(`
+MQCD```(R`@#>.0```1X"`&PZ```"FP``>#H```)6``"].@```E$``,XZ```"
+MG```"SL```(R`@`C.P```1X"`#X[```!'@(`8CL```(/``!J.P```JH``)`[
+M```":```]#L```)+``!S/````G<``)(\```"20(`LCP```))`@#=/````C("
+M`/0\```!'@(`##T```$>`@`L/0```@\``#0]```"J@``;CT```)]``":/0``
+M`F@```4^```!'@(`)CX```$>`@!#/@```E```%0^```"G```V#X```(G```$
+M/P```CX"`#`_```"/@(`63\```(^`@""/P```CX"`+8_```"/@(`VS\```(^
+M`@`'0````CX"`"Q````"/@(`6$````(^`@"`0````CX"`*A````"/@(`T$``
+M``(^`@#W0````CX"`"A!```"$`(`54$```(0`@")00```A`"`+I!```"$`(`
+MZT$```(0`@`<0@```A`"`$E"```"$`(`?4(```(0`@"Y0@```F8``#5#```"
+M2P``<4,```))`@"-0P```BT``)M#```",@``IT,```(R`@#70P```CL``!Q$
+M```">0``/$0```)+``"/1````:$``*I$```!!0``KT0```(]`@#J1````:$`
+M``5%```!!0``"D4```(]`@`W10```A@``&E%```!!0``;D4```(]`@#]10``
+M`G$``!!&```!!0``%48```(]`@"*1@```CX``)I&```"5P``_48```),``!J
+M2````B<``/1(```"0`(`,4D```)``@!N20```D`"`*A)```"0`(`Q$D```)`
+M`@#B20```D`"`$]*```"0`(`K$H```)``@#U2@```D`"`$E+```"0`(`?DL`
+M``*"``"-2P```D`"`+M+```"#@``RDL```)``@#X2P```@X```=,```"0`(`
+M-4P```(.``!13@```DP"`'1.```"3`(`D$X```),`@"L3@```DP"`,A.```"
+M3`(`Y$X```),`@`?3P```DL``(1/```"3`(`OD\```)+```L4````DP"`&]0
+M```"2P``[%````)2```(40```DL``%M1```!!0``8%$```(]`@""40```A@`
+M`+11```!!0``N5$```(]`@#]40```04```)2```"/0(`C5(```)Q``"@4@``
+M`04``*52```"/0(``U,```(^```34P```E<``%A3```"DP``BU,```$%``"0
+M4P```CT"`,)6```!'@(`]58```$>`@`B5P```1X"`$U7```!'@(`?5<```$>
+M`@"05P```04``)57```"/0(`ZU<```$>`@`;6````1X"`$I8```!'@(`?%@`
+M``$>`@"N6````1X"`,%8```!!0``QE@```(]`@#^6````DL``')9```"B```
+MP%D```*(``#X60```IH``#A:```"F@``@EH```(A``"36@```EL``(9;```"
+M4P``R5L```).```&7````DL``!!<```"%@``'%P```)4``!=7````C<``&U<
+M```"(@``35T```(W``!=70```B(``,%=```">```35X```*N``!]7@```C<`
+M`(U>```"(@``X5X```)G```O7P```J<``))?```"B```LE\```)3``#(7P``
+M`J<```!@```""P(`,V````(+`@"=8````H@``+U@```"3@``R6````)Y``!T
+M80```DL``(9A```"4@``G6$```&I``"R80```BL"`!YB```"2P``,&(```)Y
+M``!)8@```3P``&1B```"*P(`W&(```$#``#C8@```08``.AB```"/0(`^V(`
+M``)7```-8P```BH``!EC```"8P``\F,```(^``#^8P```B8``$ED```"2P``
+M[V0```)C``"E90```:D``+IE```"*P(`,V8```$\``!.9@```BL"`)=F```"
+M+0``J68```(R``"U9@```C("`-IF```"$@``]68```)V```69P```:$``#5G
+M```!!0``.F<```(]`@!;9P```DD"`.)G```"20(`%V@```&A```V:````08`
+M`#MH```"/0(`E&@```)+``#2:````DD"`/IH```"+```5FD```*)``".:0``
+M`DL``+YI```"2P``YVD```(B``!C:@```1X"`'MJ```!'@(`H&L```)@``#Q
+M:P```2@``/UK```"+P``2VP```)@``"H;````0$``+=L```"+P``WFP```&P
+M```O;0```F```+-M```"+P``^VT```)@``!B;@```B\``,!N```",@(`SVX`
+M``$>`@#R;@```C("``%O```!'@(`B&\```(R`@"9;P```C(``!AP```!'@(`
+M,W````$>`@!3<````B0``!%S```",@(`&',```$>`@`J<P```C("`#%S```!
+M'@(`P7,```(R`@#(<P```1X"`-IS```",@(`X7,```$>`@!I=````HH``)1T
+M```"H@``G'0```*#``#<=````1X"`/%T```!'@(``G4```$>`@`B=0```1X"
+M`'5U```",@(`A'4```$>`@"F=0```C("`+5U```!'@(`B78```(R`@"5=@``
+M`1X"`*=V```",@(`KG8```$>`@#+=@```C("`--V```!'@(`^G8```(R`@`&
+M=P```1X"`!AW```",@(`'W<```$>`@`\=P```C("`$1W```!'@(`B'<```(R
+M`@"X=P```04``+UW```"/0(`XG@```)P```(>0```G```'=Y```"M0``8GH`
+M``(R`@",>@```C("`")[```!I```,'L```&D``"R>P```1X"`-Y[```!'@(`
+M$GP```(R`@`G?````1X"`&Y\```!'@(`S'P```$>`@`U?0```1X"`*=]```"
+M,@(`N7T```$>`@#A?0```CT``/%]```"2@```WX```(R`@`;?@```C("`#-^
+M```",@(`67X```)=``!K?@```1X"`+A^```",@(`QWX```$>`@#O?@```CT`
+M`/]^```"2@``$7\```(R`@`I?P```C("`$%_```",@(`9W\```)=``!Y?P``
+M`1X"`*5_```",@(`M7\```(/``#;?P```JH``.9_```!'@(`_G\```$>`@`5
+M@````1X"`/J````!'@(`<X$```)@``"-@0```F0``*:!```")```!((```$!
+M```8@@```I(``#F"```"=```18(```(O``#=@@```FH``(J#```"L@``U(,`
+M``)+``![A````HT```B%```"2P``@84```*-```>A@```DD"`#V&```"20(`
+M;X8```*-``#;A@```DD"`">'```"20(`98<```(M``!TAP```C(``("'```"
+M,@(`GX<```(2``"VAP```G8``-"'```!!@``U8<```(]`@#RAP```DD"``N(
+M```!!@``$(@```(]`@`MB````DD"`'6(```"20(`N(@```(L``#;B````DD"
+M`%6*```"40``88H```(R`@"'B@```E$``).*```",@(`&HL```$>`@`SBP``
+M`1X"`'J+```",@(`FXL```)W``"WBP```H<``,R+```"AP``W(L```(R`@`!
+MC````1X"`!^,```!'@(`5HP```&A``!QC````04``':,```"/0(`@XP```)@
+M``#,C````0$``-B,```"+P```XT```&A```BC0```04``">-```"/0(`-(T`
+M``)@``!YC0```0$``(6-```"+P``K(T```)@``#XC0```0$```2.```"+P``
+M&(X```)@``!DC@```0$``'".```"+P``A(X```)@``#)C@```0$``-6.```"
+M+P``Z8X```)@```NCP```0$``#J/```"+P``3H\```)@``";CP```0$``*>/
+M```"+P``VX\```(_```,D````J4``"20```"2P``<)````)W``"?D````K(`
+M`!62```!H0``,)(```$%```UD@```CT"`&N2```",@(`S)(```*,``!'DP``
+M`:$``&*3```!!0``9Y,```(]`@"*DP```C("`"V4```"=P``0I0```(A``!.
+ME````B0``(&4```!MP``BY0```%R``"@E````0,``-24```!<@``_)0```*+
+M```.E0```7(``#:5```"BP``2)4```%R``!PE0```HL``(*5```!<@``JI4`
+M``*+``"\E0```7(``.25```"BP``]I4```%R```>E@```HL``#"6```!<@``
+M6)8```*+``!JE@```7(``)*6```"BP``R)8```*+``#DE@```7(```R7```"
+MBP``/Y<```&A``!:EP```04``%^7```"/0(`9Y<```%R``".EP```AL``*"7
+M```!<@``Q)<```(;``#]EP```@L"``N8```!%```(9@```(K`@#!F````J4`
+M`-.8```!MP``^Y@```*+```-F0```;<``#69```"BP``1YD```&W``!OF0``
+M`HL``)^9```"=P``UID```*E```$F@```K(``&V:```!H0``B)H```$%``"-
+MF@```CT"`)^:```"I0``O)H```(+`@#*F@```10``-R:```"*P(``YP```$%
+M```(G````CT"`"Z<```"/P``49P```(A``!AG````B0``("<```"L@``J)P`
+M``$>`@#%G````1X"`.&<```!'@(`_IP```$>`@`#G@```C\``!.>```")```
+M'YX```*E``!!G@```J4``&6>```"I0``A9X```*E``"@G@```IL``,R>```"
+ML@``Y9X```)6```JGP```E$``%Z?```"AP``;I\```(R`@"UGP```BP``,J?
+M```";P``])\```*E```6H````@L"`"6@```"F0``.:````)+``!7H````A(`
+M`&Z@```"=@``BZ````))`@"HH````DD"`+^@```"+```X*````)+``#PH```
+M`E8``"FA```"=P``R*$```(D```DH@```04``"FB```"/0(`0Z(```(L``!/
+MH@```B0``(2B```"G```N*(```(R`@#$H@```B0``."B```"40``[J(```(R
+M`@#ZH@```B0```:C```"3P``%Z0```(A```GI````B0``&BD```!H0``DZ0`
+M``$%``"8I````CT"`*RD```"/P``O*0```*E```.I0```04``!.E```"/0(`
+M.:4```(_``!@I0```K(``)VE```!'@(`NJ4```$>`@#6I0```1X"`/.E```!
+M'@(`":8```$#``#&I@```B$``-:F```")```Y*8```&&``#YI@```BL"`!2G
+M```""P(`)*<```(D```RIP```9$``$2G```"*P(`N:<```(R`@`(J````E8`
+M`"FH```"(0``.:@```(D``"'J````@L"`)6H```!20``IZ@```(K`@#"J```
+M`B$``-*H```")```]Z@```(A```'J0```B0``!.I```"I0``0*D```$>`@"1
+MJP```H0``*&K```")0``\*L```)^```^K````AH``'NL```"?0``R*P```(R
+M`@`JL@```0D``#JR```!"0``2K(```(Q``"@L@```D8``*"S```"-0``W[,`
+M``)]``#CM````C("`-.U```!"0``Y+4```$)``#TM0```C$``"NV```!"0``
+M/+8```$)``!,M@```C$``-.V```!'@(`(K<```$>`@!#MP```B```%NW```"
+M(```<[<```(@``"+MP```B```*.W```"(```N[<```(@``#3MP```B```.NW
+M```"(````[@```(@```;N````B```#.X```"(```2[@```(@``!CN````B``
+M`'NX```"(```D[@```(@``"KN````B```,.X```"(```V[@```(@``#SN```
+M`B````NY```"(```([D```(@```[N0```B```%.Y```"(```:[D```(@``"#
+MN0```B```)NY```"(```!+H```$>`@`DN@```1X"`.&Z```"(````+L```(@
+M```?NP```B```#Z[```"(```7;L```(@``#RO0```A\```B^```"E0``QKX`
+M``)?``#;O@```4,``#"_```"'P``1K\```*5``#JOP```E\``#'````"7P``
+M],````)S```-P0```BD``"[!```"6```D\$```$#``#DQ````A,``&K%```"
+M$P``AL4```(2`@!DQ@```A@``!S'```!'@(`,\<```$>`@!#QP```C("`(['
+M```!!P``UL<```$>`@`)R````0<``"O(```!!P``<\@```$>`@#HR````0<`
+M`##)```!'@(`8\D```$'``"%R0```0<``,W)```!'@(`-LH```$'``!'R@``
+M`0<``-K*```!'@(`;\L```$>`@`"S````1X"`"S,```",@(`^,P```(=``"W
+MSP```I```"_1```!`P``/M$```$'``!(T0```0<``%/1```!!P``7=$```$'
+M``!!T@```H```&/2```"K@``EM,```$'``";TP```@,"`"'4```",0``,=0`
+M``(R`@!-U````J,``'C4```!!@``?=0```(]`@"]U````B<"`-/4```")P(`
+MZ=0```(G`@!=U0```B<``'G5```",0(`D=4```(Q`@"MU0```C$"`,75```"
+M,0(`X=4```(Q`@#YU0```C$"`!76```",0(`+=8```(Q`@!)U@```C$"`&'6
+M```",0(`?=8```(Q`@"5U@```C$"`+'6```",0(`R=8```(Q`@#EU@```C$"
+M`/W6```",0(`&=<```(Q`@`QUP```C$"`$W7```",0(`9=<```(Q`@"!UP``
+M`C$"`)G7```",0(`M=<```(Q`@#-UP```C$"`.G7```",0(``=@```(Q`@`Q
+MV````F("`%W8```"8@(`C=@```)B`@"YV````F("`.G8```"8@(`%=D```)B
+M`@!%V0```F("`''9```"8@(`H=D```)B`@#-V0```F("`/W9```"8@(`*=H`
+M``)B`@!9V@```F("`(7:```"8@(`M=H```)B`@#AV@```F("``/;```"(P``
+M"]L```)E```9VP```F4``"';```"LP``+=L```(R`@`UVP```GL``$7;```"
+M@0``5=L```*!``")VP```H$``*S;```"J```O]L```*H``#<VP```J@``._;
+M```"J```"]P```(R```6W````48"`&S<```"8```QMP```$!``#6W````B\`
+M`!/=```"+0``)]T```(R`@`SW0```C(``(+=```")```Z]T```)@``!9W@``
+M`0$``&7>```"+P``HMX```(M``"VW@```C("`+[>```",@``_-X```(D``"D
+MWP```B$``+O?```"6P``Q]\```(D```"X0```D0``#_A```!`0``4^$```*2
+M``!WX0```G0``([A```"+P``Q.$```(M``#8X0```C("`.3A```",@``A.(`
+M``)@``"DX@```08``*GB```"/0(`N.(```)D``#4X@```B0``!GC```"20(`
+M/.,```(M``#0XP```04``-7C```"/0(`!N0```(2`@!AY````A("`)GD```"
+M(0``LN0```);``#.Y````B0``/KD```"20(`SN4```(M```@Y@```J4``#;F
+M```"=P``<^8```)+`@"GY@```B,``*_F```"0@``M^8```)"``#'Y@```H$`
+M`,_F```"90``V^8```)E``#GY@```K,``//F```",@(`^^8```)[```/YP``
+M`44``"KG```"*P(`.N<```*R``!<YP```J\``&KG```"KP``B><```$)``"6
+MYP```0D``+/G```!!P``O><```$'``#>YP```4$``.SG```!!P``\N<```%!
+M``#XYP```0<``/[G```!00``!.@```$'```*Z````4$``!'H```!00``)^@`
+M``%!```NZ````4$``#WH```!00``1.@```%!``!-Z````4$``%3H```!00``
+M8^@```%!``!PZ````0<``(KH```!00``F.@```%!``"GZ````4$``*[H```!
+M00``M^@```%!``"^Z````4$``-;H```!!P``Z.@```$#```EZ0```0,``$GI
+M```!!P``6ND```$'``"&Z0```4$``)3I```!00``OND```%!``#DZ0```4$`
+M`/'I```!00``0^H```(,`@!7Z@```0,``+?J```"CP``W.H```)V``#VZ@``
+M`G8``(3K```!H0``G^L```$%``"DZP```CT"`+;K```"8```Y.L```&A``#_
+MZP```04```3L```"/0(`0NP```$!``!.[````B\``(OL```"+0``G^P```(R
+M`@"G[````C(``,?L```")```]^P```)@```:[0```F0``#?M```")```D>T`
+M``$!``"E[0```I(``,;M```"=```TNT```(O```/[@```BT``"/N```",@(`
+M*^X```(R``!>[@```HP``(3N```"(0``D.X```(D``#2[@```0,```'O```"
+MC@``1.\```)(``!:[P```FX``'#O```"GP``TN\```&A``#M[P```04``/+O
+M```"/0(`(/````(+`@`Q\````0$``$;P```"*P(`L_(```*.``#^\@```H``
+M`!7S```"=@``2?,```(R``!T\P```K(``)'S```""P(`I?,```%%``"Z\P``
+M`BL"`##T```!"0``._0```$)``!9]@```AH"`(+V```"&@(`Q/8```$#``#9
+M]@```0<``.7V```!!P``\?8```$'``#Z]@```0<```#W```!!P``'?<```$'
+M``!=]P```E8"`)'W```"3@(`QO<```%!``#3]P```4$``/_W```!00``'/@`
+M``%!```E^````4$``"SX```!00``2/@```%!``!6^````4$``+/Y```!H0``
+M^/H```)@``#G_0```0$``%'^```"1```8?X```*2``"!_@```G0``*'^```"
+MD@``M_X```)D``#P_@```G0```7_```"50``/O\```)T``"`_P```A("`/G_
+M```"$@(`+0`!``(O```_``$``B0``+\"`0`"5@(`Y@(!``)6`@`S!`$``DL`
+M`(4$`0`"=P``K@0!``*E``#9!`$``DL``#0%`0`"C0``\@4!``*4`0`)!@$`
+M`M(!`!T&`0`"T0$`A`8!``$!``";!@$``E$!`+T&`0`"N@``R08!``+1``#<
+M!@$``C("`.<&`0`"XP``!P<!``*\```>!P$``@,!`"H'`0`"T0$`1P<!``+1
+M`0!K!P$``@8!`(@'`0`"50$`VP<!``)1`0#Y!P$``KH``!@+`0`".0$`APX!
+M``$#```N#P$``04``#,/`0`"/0(`?`\!``(2`@`T$`$``1X"`&00`0`!'@(`
+MQ!`!``$>`@!-$0$``1X"`(@1`0`!'@(`\A$!``(R`@`L$@$``C("`&X2`0`"
+M,@(`J!(!``(R`@`,$P$``N0``!@3`0`",@(`)!,!``*/`0"8$P$``1X"`*83
+M`0`!'@(`MQ,!``(R`@#*$P$``1X"`-@3`0`!'@(`ZQ,!``$>`@#T$P$``1X"
+M`!<4`0`",@(`(A0!``$>`@!#%`$``C("`$X4`0`!'@(`;Q0!``$>`@"*%`$`
+M`1X"`-,4`0`!'@(`ZA0!``$>`@`&%0$``1X"`!L5`0`!'@(`.14!``$>`@!$
+M%0$``1X"`'$5`0`",@(`?Q4!``$>`@"F%0$``C("`+05`0`!'@(`YA<!``$>
+M`@`[&`$``E\!`&L8`0`"7P$`WQ@!``*B`0!%&0$``@L"`%@9`0`"8`$`?!D!
+M``)7`0`<&@$``J(!`$,:`0`"AP$`6AH!``)+`0!V&@$``08``'L:`0`"/0(`
+MF!H!``))`@"U&@$``DD"`-`:`0`"Z```^QH!``$>`@#.&P$``<\``.\;`0`"
+M;0$`S!P!``+.``#8'`$``M$!`,@=`0`"30$`!"$!``+0`0"`(0$``NX``,,A
+M`0`"30$`9B(!``$#``".(@$``J$!`-(B`0`"H0$`%2,!``*A`0!4(P$``J$!
+M`)4C`0`",`$`Y2,!``*D`0!U)`$``L8``*\D`0`"[P``WR0!``(R`@`V)P$`
+M`KH!`$\G`0`"@@$`%R@!``+:``">*`$``G@!`,@H`0`"V@``*2H!``+/`0!%
+M*@$``F$!`+TJ`0`"SP$`\BH!``)A`0"K+`$``J,!`)`M`0`"$@(`KBT!``$#
+M``!%+@$``KD``%<N`0`"N0``"2\!``+/`0`^+P$``F$!`,HO`0`"%@$`"3`!
+M``("`0`M,`$``A8!`$,P`0`"D`$`8S`!``(6`0"S,`$``@H!`-,P`0`!!0``
+MV#`!``(]`@!$,0$``E<!`%0Q`0`"U0``Y#$!``*:`0!@,@$``IH!`&XR`0`"
+MG@$`FC(!``*:`0"S,@$``F0!`-LR`0`"!0$`?S,!``(A`0"D,P$``F0!`,HS
+M`0`"%0$`]S,!``*:`0#_,P$``A4!`"0T`0`"9`$`AC0!``*]``#0-`$``G\!
+M`/4T`0`"5P$`+S4!``))`@!/-0$``KT``'0U`0`"XP``@#4!``(R`@#,-0$`
+M`D@!`-8U`0`"D0$`Z34!``$&``#N-0$``CT"`"0V`0`"O0``.38!``(H`0!$
+M-@$``A4!`+TV`0`!'@(`XS8!``$>`@`4-P$``1X"`%LW`0`!!0``8#<!``(]
+M`@"Q-P$``DP!`"8X`0`"3`$`/#@!``+*`0!(.`$``B$!`/HX`0`"T```&3D!
+M``)D`0`_.0$``E<!`-$Y`0`"T```ZCD!``)D`0`R.@$``L4!`$T[`0`!'@(`
+M9CL!``$>`@!^.P$``1X"`-$[`0`!'@(`[3L!``$>`@!I/`$``H4!`,0\`0`!
+M'@(`X#P!``$>`@#\/`$``1X"``@]`0`"#0$`YST!``+;```</@$``A("`/,^
+M`0`"$@(`;C\!``(2`@"6/P$``1X"`,8_`0`!'@(``D`!``$>`@#A0`$``A("
+M`!%"`0`"$@(`FD(!``(2`@"M0@$``0,``#)#`0`",@(`=D,!``$>`@"70P$`
+M`1X"`,!#`0`!!@``Q4,!``(]`@#40P$``FH!`$)$`0`!'@(`QT0!``)J`0#;
+M1`$``FH!`$Y%`0`!!0``4T4!``(]`@"X10$``08``+U%`0`"/0(`T44!``)6
+M`0`$1@$``04```E&`0`"/0(`TD8!``$%``#71@$``CT"`(%'`0`"T```F$<!
+M``)D`0!*2`$``CT!`)Q)`0`"5@$`L$D!``*B`0`A2@$``@\!`(9*`0`"T```
+MDDH!``(]`0"I2@$``F0!`/U*`0`"5P$`>DL!``*_``"K2P$``E<!`$M,`0`"
+M5P$`@$P!``*B`0"03`$``A4!`,9,`0`!'@(`[TP!``$>`@`(30$``1X"`"A-
+M`0`!'@(`04T!``$>`@!730$``A\!`&5-`0`"'`$`<TT!``(<`0")30$``A\!
+M`,A-`0`!'@(`.DX!``$>`@!33@$``1X"`&5.`0`"]0``DTX!``$>`@"J3@$`
+M`1X"``!/`0`!'@(`'4\!``$>`@!&3P$``@L"`&9/`0`"=`$`I4\!``)7`0#;
+M3P$``DD"`/=/`0`"O0``)5`!``(;`0`Q4`$``C("`%A0`0`!`0``B5`!``(K
+M`@"J4`$``1X"`+I0`0`!'@(`V5`!``$>`@#I4`$``1X"`!%1`0`!'@(`.U$!
+M``$>`@!F40$``1X"`']1`0`!'@(`JU$!``$>`@#540$``1X"`"92`0`!'@(`
+M0E(!``$>`@!?4@$``1X"`'M2`0`!'@(`N5(!``(+`@#[4@$``DD"`!-3`0`"
+MO0``)%,!``+C```P4P$``C("`%-3`0`!D0$`:%,!``(K`@")4P$``1X"`*=3
+M`0`!'@(`TE,!``$>`@#P4P$``1X"`#I4`0`""P(`5E0!``)7`0"&5`$``DD"
+M`*I4`0`!5`$`PU0!``(K`@#C5`$``1X"``!5`0`!'@(`'%4!``(R`@`L50$`
+M`1X"`$=5`0`!'@(`9%4!``$>`@"`50$``C("`)!5`0`!'@(`M%4!``$>`@!N
+M5@$``1X"`)96`0`",@(`P58!``$>`@#H5@$``C("`!%7`0`!'@(`.E<!``(R
+M`@"&5P$``BH!`*17`0`";@$`M%<!``(\`0#G5P$``C@!`"%8`0`"&0$`4U@!
+M``(\`0`360$``C("`#E9`0`!'@(`5UD!``(R`@!W60$``1X"`*!9`0`",@(`
+MQED!``$>`@#H60$``C("``1:`0`!'@(`*%H!``)7`0"M6@$``KT``/%:`0`"
+MO0```5L!``(\`0!(6P$``E<!`&Y;`0`"5P$`D5L!``(+`@"I6P$``N,``+5;
+M`0`",@(`9EP!``*B`0")7`$``H<!`*!<`0`"2P$`NEP!``$&``"_7`$``CT"
+M`-Q<`0`"20(`^5P!``))`@`<70$``N@``$5=`0`"\@``>5T!``)7`0":70$`
+M`N,``*9=`0`",@(`UUT!``*'`0#N70$``DL!``A>`0`!!@``#5X!``(]`@`J
+M7@$``DD"`$=>`0`"20(`8EX!``+H``!_7@$``C@!``1?`0`!'@(`*U\!``(R
+M`@!'7P$``1X"`&=?`0`!'@(`BE\!``(R`@"F7P$``1X"`"Q@`0`"=`$`.&`!
+M``(_`0!]8`$``IP!`(Y@`0`"0P$`RV`!``(R`@#C8`$``1X"`/Y@`0`!'@(`
+M(F$!``(\`0`J80$``AH!`%5A`0`"G0$`WF$!``)4`0#T80$``E<!`(%B`0`"
+MO`$`LV(!``)(`0#L8@$``J@!``MC`0`"20(`*V,!``))`@!<8P$``C("`'-C
+M`0`!'@(`C&,!``$>`@"L8P$``CP!`+1C`0`"&@$`_6,!``(J`0`W9`$``E<!
+M`+)D`0`"G0$`Q&0!``+[```U90$``1X"`%9E`0`!'@(`<V4!``*]`0"$90$`
+M`D,!`.ME`0`"?@$`"&8!``)D`0`J9@$``A4!`$]F`0`"F@$`5V8!``(5`0":
+M9@$``F0!`.%F`0`"O0``]F8!``)7`0`F9P$``DD"`#YG`0`"O0``3&<!``+C
+M``!89P$``C("`'EG`0`"D0$`I6<!``)D`0#79P$``KT``/1G`0`"5P$`#&@!
+M``*'`0`C:`$``DL!`$!H`0`"20(`76@!``))`@!P:`$``N@``(EH`0`"8`$`
+MGF@!``$>`@#K:`$``CP!`/=H`0`".`$`@&D!``$>`@";:0$``E8!`*]I`0`"
+MH@$`SFD!``)6`0#6:0$``F@!`/5I`0`!`P``%&H!``(``0`X:@$``@`!`%QJ
+M`0`"O0``BVH!``)_`0"L:@$``MP``-9J`0`"O0```6L!``)_`0`B:P$``KT`
+M`#YK`0`"W```86L!``*]``!^:P$``KT``+1K`0`"XP``P&L!``(R`@`L;`$`
+M`L```$ML`0`"BP$`96P!``*'`0!\;`$``DL!`)9L`0`!!@``FVP!``(]`@"X
+M;`$``DD"`-5L`0`"20(`Z&P!``+H```4;0$``E<!`%!M`0`"3P$`GFT!``)G
+M`0"\;0$``E<!`!!N`0`!!0``%6X!``(]`@`_;@$``E8!`()N`0`!!0``AVX!
+M``(]`@!:;P$``04``%]O`0`"/0(`HF\!``$%``"G;P$``CT"`#=P`0`"'`$`
+M/W$!``+0``!T<0$``K4!`*QQ`0`!!0``L7$!``(]`@#N<@$``A("`!)S`0`!
+M'@(`/G,!``$>`@!Z<P$``1X"`"YT`0`!!0``,W0!``(]`@"-=`$``04``))T
+M`0`"/0(`O70!``$%``#"=`$``CT"`/1T`0`!!@``^70!``(]`@!T=0$``04`
+M`'EU`0`"/0(`P74!``$&``#&=0$``CT"`/EU`0`!!@``_G4!``(]`@`-=@$`
+M`08``!)V`0`"/0(`878!``+)``"R=@$``1X"`,]V`0`!'@(`['8!``$>`@`,
+M=P$``1X"`"-W`0`!!@``*'<!``(]`@"L=P$``1X"`-EW`0`!!@``WG<!``(]
+M`@`9>`$``04``!YX`0`"/0(`-'@!``(-`0!2>`$``1X"`.-X`0`"%0$``WD!
+M``)P`0"(>0$``K<!`*9Y`0`"'0$`TGD!``(^`@#^>0$``CX"`"IZ`0`"/@(`
+M4WH!``(^`@!\>@$``CX"`+!Z`0`"/@(`U7H!``(^`@#[>@$``CX"`"=[`0`"
+M/@(`3'L!``(^`@!X>P$``CX"`*1[`0`"/@(`S'L!``(^`@#T>P$``CX"`!Q\
+M`0`"/@(`1'P!``(^`@!K?`$``CX"`)1\`0`"/@(`N7P!``(^`@#J?`$``A`"
+M`!=]`0`"$`(`2WT!``(0`@!\?0$``A`"`*U]`0`"$`(`WGT!``(0`@`+?@$`
+M`A`"`#]^`0`"$`(`=7X!``)7`0"*?@$``I0!``-_`0`!`0``%G\!``)1`0`F
+M?P$``M$``+5_`0`"5P$`\7\!``))`@`-@`$``KT``!N``0`"XP``)X`!``(R
+M`@!7@`$``@0!``B"`0`"MP$`G((!``)``@#2@@$``D`"``^#`0`"0`(`3(,!
+M``)``@"&@P$``D`"`**#`0`"0`(`P(,!``)``@`JA`$``D`"`(6$`0`"0`(`
+MXH0!``)``@`KA0$``D`"`("%`0`"0`(`Z(4!``)``@`QA@$``D`"`&:&`0`"
+M90$`=88!``)``@"CA@$``C(!`+*&`0`"0`(`X(8!``(R`0#OA@$``D`"`!V'
+M`0`",@$`+(<!``)``@!:AP$``C(!`&F'`0`"0`(`S8<!``)R`0#BB@$``DP"
+M``6+`0`"3`(`*(L!``),`@!+BP$``DP"`&>+`0`"3`(`@XL!``),`@"^BP$`
+M`E<!`".,`0`"3`(`78P!``)7`0#+C`$``DP"``Z-`0`"5P$`@HT!``+3``#-
+MC0$``1X"`/*-`0`!'@(`#HX!``)#`0!1C@$``KT``&2.`0`"XP``<(X!``(R
+M`@"2C@$``H<!`*^.`0`"20(`S(X!``))`@#CC@$``N@``/*.`0`!'@(`3X\!
+M``)?`0!_CP$``DD"`.F/`0`"R@$`))`!``)7`0";D`$``04``*"0`0`"/0(`
+MU9`!``)6`0`8D0$``04``!V1`0`"/0(`XI$!``$%``#GD0$``CT"`!F2`0`!
+M!@``'I(!``(]`@"AD@$``04``*:2`0`"/0(`7I,!``(<`0!QDP$``04``':3
+M`0`"/0(`?Y0!``)D`0"GE`$``M```,N4`0`"A0$`#I4!``+%`0#LF`$``ET!
+M`$R9`0`"$@(`8)D!``*V`0#:F0$``A("`"F:`0`"E`$`.YH!``+2`0!-F@$`
+M`M$!`'::`0`"$@(`N)H!``$T`0`-FP$``E$!`"Z;`0`"N@``.IL!``+1``")
+MFP$``I0!`)N;`0`"T@$`K9L!``+1`0#^FP$``30!`%.<`0`"40$`=)P!``*Z
+M``"`G`$``M$``.V<`0`"E`$``YT!``+2`0`9G0$``M$!`#Z=`0`"$@(`=9T!
+M``'$`0"?G0$``E$!`,"=`0`"N@``T)T!``+1```RG@$``ET!`%V>`0`"E@$`
+MF9X!``*4`0"KG@$``M(!`+V>`0`"T0$``Y\!``'$`0`OGP$``E$!`%"?`0`"
+MN@``7)\!``+1``#]GP$``OH``#R@`0`"^@``C*`!``)!`0"@H`$``N```-*@
+M`0`"Z@``\J`!``+@```FH0$``N```/NA`0`""0$`3J(!``)"`0"'H@$``NH`
+M`,BB`0`"E`$`VJ(!``+2`0#LH@$``M$!`#*C`0`!F`$`6J,!``)1`0![HP$`
+M`KH``(>C`0`"T0``8:0!``*\``!MI`$``M$!`)^D`0`"$@(`X:0!``*\``#M
+MI`$``M$!`(.E`0`"]```F*4!``*\``"DI0$``M$!`+^E`0`""P(`TZ4!``'B
+M``#HI0$``BL"`%>F`0`"@`$`1*<!``)[`0"$IP$``GL!`+ZG`0`"Z@``^J@!
+M``(1`0`/J0$``O\``"2I`0`"-P$`.:D!``+T``!3J0$``@L"`&>I`0`!X@``
+M@:D!``(K`@"TJ0$``E<!`"BJ`0`"O`$`3JH!``)(`0!UJ@$``J@!`,2J`0`"
+M5P$``JL!``+J```WJP$``D\!`&&K`0`"O```=:L!``+1`0"QJP$``NH``.:P
+M`0`"PP$`[[$!``$#``"(L@$``1X"`+BR`0`!'@(`X[(!``$>`@`<LP$``1X"
+M`&^S`0`!'@(`G;,!``$>`@##LP$``1X"`/6S`0`!'@(`MK0!``$#``#+M`$`
+M`0,``-ZT`0`!`P``[+0!``$#``#_M`$``HP!``JU`0`!`P``CK4!``)7`0#.
+MM0$``E<!`/ZU`0`"5P$`3K8!``)7`0!^M@$``E<!``2W`0`"5P$`8+@!``+0
+M``#1N0$``E8!`!BZ`0`">0$`6+H!``)Y`0!!NP$``KP``%*[`0`"%P$`6[P!
+M``+1``""O`$``O,``)&\`0`"PP$`IKP!``)D`0`1O0$``GX!`'>]`0`"(0$`
+M2+X!``+1`0"ZO@$``@,!`,B^`0`"T0$`!K\!``)7`0`0OP$``O8``!B_`0`"
+MU0``3+\!``*4`0!:OP$``M(!`'._`0`"T0$`L;\!``'!``"]OP$``M$```#`
+M`0`"E`$`-\`!``'!``!#P`$``M$``('``0`"E`$`D\`!``+2`0"EP`$``M$!
+M`.S``0`!`0```,$!``)1`0`AP0$``KH``"W!`0`"T0``;<$!``*4`0"HP0$`
+M`2D!`+3!`0`"T0``QL$!``(R`@#8P0$``C("`+W"`0`"O```SL(!``(7`0#:
+MP@$``M$!`!/#`0`"FP$`,<,!``*\``!"PP$``A<!`$[#`0`"T0$`3,0!``(R
+M`@!8Q`$``M$!`(C$`0`"FP$`F,0!``(R`@"DQ`$``M$!`-S$`0`"E`$`'\4!
+M``*A`0`OQ0$``M$!`$/%`0`!P0``3\4!``+1``"0Q0$``I0!`*K%`0`"T@$`
+MP\4!``+1`0`=Q@$``<$``##&`0`"40$`3L8!``*Z``!:Q@$``M$``*G&`0`"
+ME`$`Q,8!``+2`0#=Q@$``M$!`#/'`0`!P0``1\<!``)1`0!IQP$``KH``'7'
+M`0`"T0``L,<!``*4`0#*QP$``M(!`./'`0`"T0$`-L@!``'!``!.R`$``E$!
+M`'#(`0`"N@``?,@!``+1``#`R`$``I0!`-K(`0`"T@$`\\@!``+1`0`^R0$`
+M`<$``%+)`0`"40$`=,D!``*Z``"`R0$``M$``-_)`0`"E`$`E<H!``$!``"H
+MR@$``E$!`+3*`0`"T0``X<P!``(``0#^S`$``@,!`$S-`0`"5P$`'\X!``*:
+M`0"#S@$``I0!`*3.`0`"C0$`MLX!``+1`0`*SP$``>D``!W/`0`"40$`*<\!
+M``+1``!ZSP$``I0!`(S/`0`"C0$`X<\!``'I``#TSP$``E$!``#0`0`"T0``
+M#-`!``(R`@!1T`$``I0!`%_0`0`"C0$`JM`!``'I``"]T`$``E$!`,G0`0`"
+MT0``"=$!``*4`0`7T0$``HT!`%W1`0`!Z0``<-$!``)1`0!\T0$``M$``+'1
+M`0`",`$`P=$!``+.`0"MT@$``C`!`+W2`0`"S@$`)=,!``+7``"DTP$``D`!
+M``W4`0`"P@$`/=0!``(P`0!-U`$``LX!`+G4`0`"H`$`&-4!``*S`0!RU0$`
+M`M```)+5`0`"?@$`J-4!``*S`0#QU0$``M````?6`0`"LP$`,-8!``(+`@!C
+MU@$``@L"`+76`0`"+`$`_=8!``+0```7UP$``B$!`"/7`0`"R@$`U-<!``)7
+M`0#FUP$``F<!`/W7`0`!R0``$M@!``(K`@".V`$``E<!`*#8`0`"R@$`N=@!
+M``&^`0#4V`$``BL"`('9`0`"T```C=D!``(]`0"9V0$``IH!`#_:`0`!R0``
+M5-H!``(K`@#8V@$``;X!`//:`0`"*P(`=-P!``)7`0#9W`$``LX``.W<`0`"
+MT0$`-]T!``)_`0!JW0$``D@!`)7=`0`"U```M=T!``)7`0`TW@$``KP!`$_>
+M`0`"S@``8]X!``+1`0#+W@$``KT``/3>`0`"XP```-\!``(R`@`KWP$``L``
+M`$K?`0`"BP$`=]\!``*'`0".WP$``DL!`*C?`0`!!@``K=\!``(]`@#*WP$`
+M`DD"`.??`0`"20(`(N`!``+H``!$X`$``E<!`';@`0`"3P$`M^`!``*]``#H
+MX`$``N,``/3@`0`",@(`'^$!``+````^X0$``HL!`%OA`0`"AP$`=N$!``)+
+M`0"0X0$``08``)7A`0`"/0(`MN$!``))`@#/X0$``08``-3A`0`"/0(`]>$!
+M``))`@!\X@$``DD"`-SB`0`"5P$`&N,!``))`@`\XP$``N@``(#C`0`"E`$`
+MDN,!``+2`0"KXP$``M$!`!GD`0`!P0``+.0!``)1`0!*Y`$``KH``%;D`0`"
+MT0``@^0!``(P`0"3Y`$``LX!`&[E`0`"LP$`I^4!``+.`0#^Y0$``E<!``GH
+M`0`"$@(`S.D!``*``0`$Z@$``JH!`(_J`0`!`0``O>H!``('`0"9ZP$``0$`
+M`-SK`0`"!P$`I>P!``$!``#K[`$``@<!`%7M`0`!`0``D^T!``('`0#E[0$`
+M`0$``"/N`0`"!P$`_.X!``*K`0!U[P$``L(``'_P`0`";`$`$_$!``)%`0":
+M\0$``H`!`,WQ`0`"K`$`^/$!``)0`0`L\P$``JH!`/+T`0`"7`$`/O4!``)L
+M`0#B]0$``D4!`%GV`0`"[```X/8!``)%`0"@]P$``D4!`.'W`0`"J@$`7/@!
+M``)%`0"H^`$``D4!``GY`0`"10$`4_D!``)%`0";_`$``D4!`//\`0`!'@(`
+M"_T!``$>`@"+_@$``FD!`/C_`0`!'@(`$P`"``$>`@`S``(``M$!`)```@`"
+M,@(`GP`"``$>`@#"``(``C("`-$``@`!'@(`R0$"``(R`@#5`0(``1X"`.<!
+M`@`",@(`[@$"``$>`@`+`@(``C("`!,"`@`!'@(`.@("``(R`@!&`@(``1X"
+M`%@"`@`",@(`7P("``$>`@!\`@(``C("`(0"`@`!'@(`R`("``(R`@`H`P(`
+M`C("`#D#`@`"XP``EP,"``*4`0`#!`(``<@```\$`@`!-0$`'@0"``+1``!N
+M!`(``I0!`-P$`@`!W@``Z`0"``+1``!G!0(``1X"`(@%`@`!'@(`YP4"``)O
+M`0#W!0(``MD``$H&`@`"E`$`DP8"``'>``"?!@(``M$``"<'`@`!'@(`2`<"
+M``$>`@"?!P(``K@``*\'`@`"V0``(P@"``*4`0!J"`(``<@``'8(`@`!-0$`
+MA0@"``+1``#+"`(``I0!`"@)`@`!`0``-PD"``+1``!>"0(``>L``,$)`@`"
+M,@(`R`D"``$>`@#:"0(``C("`.$)`@`!'@(`<0H"``(R`@!X"@(``1X"`(H*
+M`@`",@(`D0H"``$>`@`G"P(``L<!`%P+`@`"K@$`9`L"``)I`0"Z"P(``1X"
+M`,\+`@`!'@(`ZPL"``$>`@`0#`(``1X"`&(,`@`"EP$`:@P"``*[``#6#`(`
+M`C("`.D,`@`!'@(`#PT"``(R`@`B#0(``1X"`"D0`@`"KP$`WQ`"``*``0!)
+M$@(``H`!`&\2`@`"@`$`XQ("``+Y``#M$P(``C("`!04`@`",@(`WQ0"``+-
+M````%0(``G<!`!H5`@`!L@$`*!4"``&R`0"J%0(``1X"`-85`@`!'@(`!A8"
+M``(R`@`;%@(``1X"`&(6`@`!'@(`P!8"``$>`@`I%P(``1X"`)H7`@`",@(`
+MK!<"``$>`@#-%P(``GT!`-D7`@`"CP$`[Q<"``(R`@`+&`(``C("`"<8`@`"
+M,@(`21@"``(;`0!;&`(``1X"`*P8`@`",@(`NQ@"``$>`@#<&`(``GT!`.@8
+M`@`"CP$`_A@"``(R`@`:&0(``C("`#89`@`",@(`6!D"``(;`0!J&0(``1X"
+M`)H9`@`",@(`IAD"``(\`0#$&0(``AH!`,\9`@`!'@(`YQD"``$>`@#^&0(`
+M`1X"`-,:`@`!'@(`4QL"``*4`0!M&P(``M(!`(8;`@`"T0$`Y!L"``$!``#X
+M&P(``E$!`!D<`@`"N@``)1P"``+1``!?'0(``04``&0=`@`"/0(`&AX"``$%
+M```?'@(``CT"`#,>`@`"3P$`5!X"``)2`0`\'P(``GP!`*P?`@`!SP``S1\"
+M``)M`0#E'P(``C\!`&4@`@`"?`$`>"`"``(K`0"J(`(``J@!`$4A`@`"^P``
+M3R$"``++`0#[(0(``D\!`%\B`@`"5P$`OR("``*\`0#B(@(``D@!`/,B`@`"
+MJ`$`BR,"``(G`0`8)`(``E<!`)$D`@`")P$`*R4"``))`@!*)0(``DD"`'\E
+M`@`")P$`Z"4"``))`@`S)@(``DD"`'(F`@`"O0``F"8"``+C``"D)@(``C("
+M`,\F`@`"P```[B8"``*+`0`')P(``H<!`!XG`@`"2P$`."<"``$&```])P(`
+M`CT"`%HG`@`"20(`<R<"``$&``!X)P(``CT"`)4G`@`"20(`W2<"``))`@`@
+M*`(``N@``$,H`@`"20(`H"@"``)T`0#,*`(``D\!`.4H`@`"/P$`*BD"``*<
+M`0!L*0(``0,``-<I`@`"7P$`_"D"``(Z`0`A*@(``CH!`$8J`@`".@$`:RH"
+M``(Z`0"8*@(``BX!`,4J`@`"+@$`_"H"``(N`0`I*P(``BX!`#4K`@`",@(`
+M;"L"``(N`0"9*P(``BX!`*4K`@`",@(`RBL"``(Z`0#O*P(``CH!`!0L`@`"
+M.@$`02P"``(N`0!F+`(``CH!`*PL`@`",@(`)BT"``$>`@!$+0(``1X"`%HM
+M`@`",@(`>"T"``)(`0")+0(``C("`*DM`@`".@$`M2T"``(R`@#:+0(``CH!
+M`.8M`@`",@(`'2X"``(N`0`I+@(``C("`$XN`@`".@$`6BX"``(R`@!O+@(`
+M`A(!`(0N`@`"<P$`L2X"``(N`0#>+@(``BX!``LO`@`"+@$`."\"``(N`0!=
+M+P(``CH!`&XO`@`",@(`CB\"``(Z`0":+P(``C("`,<O`@`"+@$`["\"``(Z
+M`0`9,`(``BX!`"TP`@`"RP$`4C`"``(Z`0!>,`(``C("`)(P`@`"+@$`GC`"
+M``(R`@#`,`(``CH!`,PP`@`",@(`X3$"``*\``#M,0(``M$!`$LR`@`!'@(`
+M:C("``$>`@"<,@(``1X"`,$R`@`"O```S3("``+1`0#9,@(``E\!``$S`@`"
+M7P$`130"``*<`0!1-`(``C("`'<T`@`"G`$`@S0"``(R`@`*-0(``1X"`",U
+M`@`!'@(`:C4"``(R`@"+-0(``D@!`*<U`@`"C@$`O#4"``*.`0#,-0(``C("
+M`/`U`@`!'@(`#C8"``$>`@`F-@(``C("`#LV`@`!!0``0#8"``(]`@!--@(`
+M`I0!`)8V`@`!`0``HC8"``+1``"W-@(``08``+PV`@`"/0(`R38"``*4`0`.
+M-P(``0$``!HW`@`"T0``03<"``*4`0"--P(``0$``)PW`@`"T0``L#<"``*4
+M`0#\-P(``0$```LX`@`"T0``'S@"``*4`0!D.`(``0$``'`X`@`"T0``AC@"
+M``*4`0#+.`(``0$``-<X`@`"T0``ZS@"``*4`0`X.0(``0$``$0Y`@`"T0``
+M@3D"``)\`0"I.0(``B@!``TZ`@`"7P$`4SH"``)?`0!E.@(``E<!`+PZ`@`"
+MO`$`Z#H"``)(`0`".P(``J@!`"P[`@`"5P$`C3L"``*\`0"Y.P(``D@!`-,[
+M`@`"J`$`"SP"``)7`0`V/`(``NH``%D\`@`"3P$`F3T"``*\``"E/0(``M$!
+M`!8^`@`",@(`73X"``)_`0!R/@(``D@!`,@^`@`!!0``S3X"``(]`@#H/@(`
+M`DH!`%@_`@`",@(`S3\"``*\``#9/P(``M$!`/$_`@`"O```_3\"``+1`0`)
+M0`(``D@!`/%``@`"20$`"T$"``))`0`E00(``O```#=!`@`"4P$`24$"``)Z
+M`0!A00(``A`!`'-!`@`"/@$`A4$"``+(`0"900(``KD!`,1!`@`"5P$`)4("
+M``*\`0!20@(``D@!`&Q"`@`"J`$`QD("``+J``#80@(``E<!`/Y"`@`!!@``
+M`T,"``(]`@`30P(``NH``#I#`@`"3P$`F$0"``*)`0"B1`(``0,```-%`@`"
+M/P$`G$4"``)\`0"S10(``BL!`/9%`@`"J`$`C48"``)7`0"_1@(``LH```5'
+M`@`"@`$`I4<"``))`@#@1P(``KT``/A'`@`"XP``!$@"``(R`@`O2`(``L``
+M`$Y(`@`"BP$`;D@"``*'`0")2`(``DL!`*I(`@`"20(`RT@"``))`@#_2`(`
+M`N@``'E)`@`"R@``D$D"``*$`0!&2@(``H`!`,Y+`@`"O`$`Y4L"``*H`0`5
+M3`(``NH``"A,`@`"/P$`DDP"``)7`0#'3`(``LH```]-`@`"R@``44T"``+*
+M``!L30(``H`!`*]-`@`"WP``!4\"``)U`0`K3P(``E<!`$E/`@`"O0``5T\"
+M``+C``!C3P(``C("`(5/`@`"AP$`G$\"``)+`0"Y3P(``DD"`-9/`@`"20(`
+M`E`"``+H```B4`(``O(``(=0`@`"E0$`LE`"``+*``#W4`(``LH``#91`@`"
+MR@``25$"``+?``!=40(``E(!`)51`@`"WP``"%,"``(_`0`[5`(``KP!`$U4
+M`@`"J`$`EE0"``)/`0#?5`(``LH```95`@`")`$`8E4"``(9`0!J50(``<\`
+M`(M5`@`";0$`JE4"``(Q`0"V50(``AD!`.Y5`@`"C@$`_E4"``(R`@!%5@(`
+M`N@``%I6`@`"Q@$`AU8"``)?`0"I5@(``@L"`+A6`@`"8`$`S%8"``)7`0#J
+M5@(``H<!``%7`@`"2P$`'E<"``))`@`[5P(``DD"`%)7`@`"Z```<U<"``)7
+M`0"#5P(``C\!`+Q7`@`"2`$`@5@"``*\``"-6`(``M$!`.E8`@`!!0``[E@"
+M``(]`@`(60(``N@``!19`@`"T0$`25D"``)#`0!Z60(``C("`(99`@`"T0$`
+MHED"``*<`0"P60(``C("`+Q9`@`"T0$`R%D"``+E```I6@(``E<!`(U:`@`"
+M2`$`]EL"``(N`0!37`(``KP``&-<`@`"T0$`>%P"``)?`0"=7`(``0,``,U<
+M`@`!'@(`$UT"``$>`@`V70(``1X"`(Q=`@`!'@(`JUT"``$>`@``7@(``1X"
+M`#M>`@`"O```2UX"``+1`0!;7@(``D\!`)=>`@`"O```IUX"``+1`0"U7@(`
+M`7$!`,I>`@`"*P(`XUX"``(R`@`37P(``E,"`#]?`@`!'@(`7E\"``$>`@!C
+M7P(``E,"`-%?`@`"5P$`)V`"``*'`0!,8`(``DL!`'M@`@`"20(`#6$"``$&
+M```280(``CT"`#-A`@`"20(`6F$"``+H``"`80(``1X"`)]A`@`!'@(`YF$"
+M``)7`0`B8@(``C\!`$MB`@`"XP``5V("``(R`@".8@(``1X"`*UB`@`!'@(`
+MD&,"``$>`@"M8P(``1X"`#-D`@`"(P$`4F0"``*S`0"'9`(``1X"`*-D`@`!
+M'@(`T60"``$>`@#M9`(``1X"`#=E`@`!'@(`5F4"``$>`@"(90(``1X"`+5E
+M`@`"O```Q64"``+1`0#190(``E\!`.1E`@`"XP``\&4"``(R`@`99P(``KP`
+M`"5G`@`"T0$`:6<"``*\``!U9P(``M$!`(EG`@`"J`$`G6@"``(2`@#Q:`(`
+M`08``/9H`@`"/0(`"VD"``*\```7:0(``M$!`$!I`@`"5P$`MVD"``)7`0`F
+M:@(``J@!`.!J`@`",@(`7FL"``(R`@"R:P(``C("`-%K`@`"O```W6L"``+1
+M`0#Q:P(``J<!``UM`@`",@(`4FT"``(R`@!Q;0(``KP``'UM`@`"T0$`D6T"
+M``*G`0#0;0(``C("`"!N`@`",@(`>6X"``(R`@"J;@(``C8!`-%N`@`"O```
+MW6X"``+1`0#I;@(``J@!`#!O`@`!'@(`%G("``*^```V<@(``KX``&%R`@`"
+MO@``%G,"``*^```V<P(``KX``&-S`@`"O@``LW,"``(C`0#R<P(``F\!`$!T
+M`@`"6P$`G'0"``++``"D=`(``A0!`+-T`@`!`P``_W0"``+Q```;=0(``BH!
+M`'AU`@`",@(`VGH"``$)``#J>@(``0D``/IZ`@`"[0``4'L"``*E`0`Z?`(`
+M`C,!`&=\`@`"F0$`>GP"``(S`0!1?0(``E<!`*M]`@`":P$`T'T"``(2`@#Y
+M?0(``MT``'Y^`@`"+P$`O7X"``(J`0`:?P(``DX!`$J``@`",@(`<X$"``$)
+M``"$@0(``0D``)2!`@`"[0``RX$"``$)``#<@0(``0D``.R!`@`"[0``<X("
+M``$>`@#"@@(``1X"`.."`@`"X0``^X("``+A```3@P(``N$``"N#`@`"X0``
+M0X,"``+A``!;@P(``N$``'F#`@`!'@(`Q(,"``$>`@#T@P(``1X"`)V$`@`"
+MX0``^X0"``*4`0`-A0(``HT!`)Z%`@`"$@(`UX4"``(2`@#>A0(``8@!`/&%
+M`@`"40$`_84"``+1``!$A@(``I0!`%:&`@`"C0$`KX8"``&(`0#"A@(``E$!
+M`,Z&`@`"T0``*H<"``(8`0`XAP(``N,``$2'`@`",@(`?H<"``(.`0",AP(`
+M`N,``)B'`@`",@(`PH<"``(8`0#4AP(``N,``."'`@`",@(`+8@"``(.`0#'
+MB`(``LX``-.(`@`"T0$`@HL"``+)`0"8BP(``AX!`(:,`@`"1@$`FXP"``%F
+M`0#PC`(``LD!``:-`@`"'@$`JHT"``)&`0#QC0(``D8!`+2.`@`"_@``S8X"
+M``(+`0#NC@(``ED!`%./`@`!`P``M)("``)8`0`ZDP(``E@!`%:3`@`"$@(`
+M0)0"``+N``"LE0(``1X"`,.5`@`!'@(`TY4"``(R`@`>E@(``0<``&:6`@`!
+M'@(`F98"``$'``"[E@(``0<```.7`@`!'@(`>)<"``$'``#`EP(``1X"`/.7
+M`@`!!P``%9@"``$'``!=F`(``1X"`,:8`@`!!P``UY@"``$'``!JF0(``1X"
+M`/^9`@`!'@(`DIH"``$>`@"\F@(``C("`(B;`@`"S```1YX"``*&`0"_GP(`
+M`0,``,Z?`@`!!P``V)\"``$'``#CGP(``0<``.V?`@`!!P``-J0"``$'```[
+MI`(``@,"`,&D`@`"[0``T:0"``(R`@#MI`(``K$!`!BE`@`!!@``':4"``(]
+M`@!EI0(``B<"`'^E`@`")P(`F:4"``(G`@`1I@(``K<!`#*F`@`",0(`3Z8"
+M``(Q`@!PI@(``C$"`(VF`@`",0(`KJ8"``(Q`@#+I@(``C$"`.RF`@`",0(`
+M":<"``(Q`@!&IP(``C$"`%VG`@`",0(`BZ<"``(Q`@"HIP(``C$"`,FG`@`"
+M,0(`YJ<"``(Q`@`'J`(``C$"`"2H`@`",0(`1:@"``(Q`@!BJ`(``C$"`(.H
+M`@`",0(`H*@"``(Q`@#!J`(``C$"`-ZH`@`",0(`_Z@"``(Q`@`<J0(``C$"
+M`#VI`@`",0(`6JD"``(Q`@![J0(``C$"`)BI`@`",0(`N:D"``(Q`@#6J0(`
+M`C$"`/>I`@`",0(`%*H"``(Q`@`UJ@(``C$"`%*J`@`",0(`<ZH"``(Q`@"0
+MJ@(``C$"`+&J`@`",0(`SJH"``(Q`@`#JP(``F("`#2K`@`"8@(`::L"``)B
+M`@":JP(``F("`,^K`@`"8@(``*P"``)B`@`UK`(``F("`&:L`@`"8@(`FZP"
+M``)B`@#,K`(``F("``&M`@`"8@(`,JT"``)B`@!GK0(``F("`)BM`@`"8@(`
+MS:T"``)B`@#^K0(``F("`".N`@`"V```*ZX"``)$`0`YK@(``D0!`$&N`@`"
+M)@$`3:X"``(R`@!5K@(``EH!`&6N`@`"'P$`=:X"``(?`0"IK@(``A\!`,RN
+M`@`".P$`WZX"``([`0#\K@(``CL!``^O`@`".P$`*Z\"``+C```VKP(``48"
+M`(RO`@`"E`$`ZJ\"``$!``#ZKP(``M$``#>P`@`"O0``2[`"``(R`@!7L`(`
+M`N,``*:P`@`"T0$`#[$"``*4`0"%L0(``0$``)6Q`@`"T0``TK$"``*]``#F
+ML0(``C("`/*Q`@`"XP``-+("``+2`0"KL@(``0$``+NR`@`"40$`X+("``*Z
+M``#TL@(``M$``#&S`@`"O0``1;,"``(R`@!1LP(``N,``(FS`@`"O```I[,"
+M``+1`0"SLP(``I0!`,^S`@`"O```V;0"``$!``#MM`(``E$!`!:U`@`"N@``
+M*K4"``+1``!GM0(``KT``'NU`@`",@(`A[4"``+C``#)M0(``KP``.6U`@`"
+MT0$`=;8"``*4`0"=M@(``08``**V`@`"/0(`L+8"``+2`0#,M@(``M$!``FW
+M`@`"20(`*+<"``*]``!YMP(``A("`%VX`@`"N`$`G;@"``$!``"QN`(``E$!
+M`-JX`@`"N@``];@"``+1```WN0(``KT``$NY`@`",@(`5[D"``+C``"CN0(`
+M`A("`->Y`@`"O```\+D"``(7`0`$N@(``M$!`"RZ`@`"20(`\+H"``*\```!
+MNP(``A<!``V[`@`"T0$`TKL"``*]```@O`(``KP!`&B\`@`"7P$`?KP"``)(
+M`0"=O`(``J@!`->\`@`"@0$`X;T"``)B`0`#O@(``L(!`".^`@`"2P(`5[X"
+M``+8``!?O@(``EX!`&>^`@`"7@$`=[X"``(?`0!_O@(``D0!`(N^`@`"1`$`
+ME[X"``(F`0"CO@(``C("`*N^`@`"6@$`O[X"``']``#:O@(``BL"`.J^`@`"
+M3P$`#+\"``)C`0`:OP(``F,!`#F_`@`!"0``1K\"``$)``!COP(``0<``&V_
+M`@`!!P``CK\"``'X``"<OP(``0<``**_`@`!^```J+\"``$'``"NOP(``?@`
+M`+2_`@`!!P``NK\"``'X``#!OP(``?@``->_`@`!^```WK\"``'X``#MOP(`
+M`?@``/2_`@`!^```_;\"``'X```$P`(``?@``!/``@`!^```(,`"``$'```Z
+MP`(``?@``$C``@`!^```5\`"``'X``!>P`(``?@``&?``@`!^```;L`"``'X
+M``"&P`(``0<``)C``@`!`P``U<`"``$#``#YP`(``0<```K!`@`!!P``-L$"
+M``'X``!$P0(``?@``&[!`@`!^```E,$"``'X``"AP0(``?@``//!`@`"#`(`
+M!\("``$#``!_P@(``HL!`*7"`@`"P```K<("``*!`0#2P@(``DL!`.S"`@`"
+M2P$`@<,"``$%``"&PP(``CT"`)C#`@`"E`$`W\,"``$%``#DPP(``CT"`";$
+M`@`!`0``,L0"``+1``!OQ`(``KT``(/$`@`",@(`B\0"``+C``#/Q`(``I0!
+M`/'$`@`"T@$`$L4"``+1`0!LQ0(``0$``(#%`@`"40$`H<4"``*Z``"QQ0(`
+M`M$``.[%`@`"O0```L8"``(R`@`.Q@(``N,``$'&`@`"2@$`:\8"``*\``![
+MQ@(``M$!`)?&`@`"T0$`YL8"``$#```AQP(``B(!`&7'`@`"$P$`G<<"``))
+M`@"XQP(``KT``,K'`@`",@(`TL<"``+C```.R`(``DD"`"G(`@`"S`$`.\@"
+M``*I`0`6R0(``04``!O)`@`"/0(`3LD"``(+`@!?R0(``0$``'3)`@`"*P(`
+MX<L"``*+`0`*S`(``L```#C,`@`"5P$`I,P"``)7`0#YS`(``DD"`#C-`@`"
+M5P$`FLT"``))`@#@S@(``B(!`#;/`@`"8@$`4<\"``)+`0")SP(``N,``+3/
+M`@`"3P$`T<\"``(+`@#ESP(``?T``/K/`@`"*P(`5=$"``*!`0"VT0(``0,`
+M`.K1`@`"YP``4]("``+G``"\T@(``N<``"73`@`"YP``;]0"``$#``"RU`(`
+M`N<``"'5`@`"YP``AM4"``+G``#KU0(``N<``%'6`@`"YP``MM8"``+G````
+MUP(``BD"`#37`@`"YP``?M<"``(I`@"RUP(``N<``/S7`@`"*0(`,-@"``+G
+M``!ZV`(``BD"`*[8`@`"YP``!-D"``(C`0!"V0(``B,!`(#9`@`"(P$`OMD"
+M``(C`0#\V0(``B,!`#?:`@`"(P$`X-H"``$)``#KV@(``0D```G=`@`"&@(`
+M,MT"``(:`@!TW0(``0,``(G=`@`!!P``E=T"``$'``"AW0(``0<``*K=`@`!
+M!P``L-T"``$'``#-W0(``0<```W>`@`"5@(`0=X"``).`@!VW@(``?@``(/>
+M`@`!^```K]X"``'X``#,W@(``?@``-7>`@`!^```W-X"``'X``#XW@(``?@`
+M``;?`@`!^```<.`"``*!`0#CX0(``C,!`!'B`@`"F0$`)N("``(S`0"EY0(`
+M`C,!`-/E`@`"F0$`Z.4"``(S`0"5Z0(``C,!`,/I`@`"F0$`V.D"``(S`0!5
+M[0(``C,!`(/M`@`"F0$`F.T"``(S`0#@[P(``I0!`*_Q`@`"$@(``_,"``$!
+M``!Q\P(``K@!`('S`@`"40$`H?,"``*Z``#!\P(``E$!`-?S`@`"T@$`#/0"
+M``*Z```A]`(``@P!`%;T`@`"N@``E?0"``(2`@`']0(``A("`$'U`@`"T0``
+M4_4"``+1`0#9]P(``E8"``#X`@`"5@(`._D"``*\`0"+^0(``E<!`-WY`@`"
+M2`$`#OH"``)?`0!,^@(``AL!`''Z`@`"J`$`G/H"``)7`0#W^@(``B<!`#7[
+M`@`!*@(`/OL"``$J`@!1^P(``>(!`(+[`@`!(`(`2/P"``$@`@"8_`(``O,!
+M`!7]`@`!V`$`(/T"``'8`0`I_0(``>(!`#3]`@`!X@$`2/T"``'8`0"9_0(`
+M`3,"``+^`@`!V`$`\?X"``$@`@"A_P(``C4"`-K_`@`"-0(`5P`#``(U`@!\
+M``,``E,"`.8``P`"-0(`$`$#``(%`@`P`0,``C4"`$P!`P`"4P(`)@(#``)3
+M`@!9`@,``08``%X"`P`"/0(`O@(#``(+`@!*`P,``>X!`%\#`P`""P(`<P,#
+M``'D`0"%`P,``BL"``H$`P`![@$`'P0#``(+`@`S!`,``>0!`$4$`P`"*P(`
+M?`0#``)``@#>!`,``AL"`"H%`P`"80(`=`4#``(W`@"U!0,``4,"`.T%`P`"
+MWP$`^P8#``)/`@`D!P,``N\!`#H'`P`!,P(`2@<#``+X`0!7!P,``N`!`&D'
+M`P`"Z@$`WP<#``$)``#\!P,``0D```P(`P`!"0``'`@#``%>`@`\"`,``D`"
+M`$L(`P`!`0``5@@#``$)``!W"`,``C$"`(L(`P`!"0``N@@#``%%`@#`"`,`
+M`0D``,0(`P`!8P(`R@@#``$)``#2"`,``0D``.`(`P`!"0``Y0@#``(K`@!)
+M"0,``=@!`)`)`P`"8P(`N@D#``(R`@#""0,``A,"`!4*`P`"\`$`6PH#``(Q
+M`@!U"@,``C$"`-T*`P`",0(`!0L#``+]`0#0"P,``@\"`-L+`P`"0`(`)`P#
+M``(Q`@!$#`,``MH!`+X,`P`"/@(`W@P#``(^`@#I#`,``=@!`"D-`P`"/@(`
+M2@T#``(^`@!L#0,``CX"`)`-`P`"/@(`MPT#``(^`@#:#0,``A0"`/4-`P`"
+M/@(`^PT#``'8`0!$#@,``2`"`$D.`P`"1`(`8PX#``$@`@#)#@,``2`"`-4.
+M`P`!,P(`_@X#``+H`0`7#P,``D`"`"\/`P`!"0``.@\#``$)```A$`,``C$"
+M`#@0`P`!(`(`>1`#``(/`@"J$`,``C$"`,`0`P`!V`$`_1`#``$@`@`H`0,`
+M`C4"`,`!`P`"!0(`3`(#``(%`@!5!0,``C$"`*X)`P`"-0(`/Q$#``$!``!8
+M$0,``0<``/P1`P`!`0``$!0#``)!`@!S%`,``C0"`)L4`P`!`0``Q!0#``(T
+M`@`:%0,``0,``"05`P`!`P``814#``$!``#7%0,``M0!``D6`P`!`0``6!8#
+M``(5`@!R%@,``B$"`)<6`P`!*@(`G18#``$'``"Y%@,``0<``,T6`P`!!P``
+MUA8#``$'``#<%@,``0<``.(6`P`"70(`&Q<#``(5`@`]%P,``F`"`)D7`P`"
+M8`(`RA<#``(Q`@#:%P,``0$``/L7`P`"8`(`'1@#``$'```K&`,``@X"`'D9
+M`P`!!P``@QD#``(.`@"+&0,``D`"`'P:`P`!!P``AAH#``(.`@".&@,``D`"
+M`#T;`P`!!P``1QL#``(.`@!/&P,``D`"`-8;`P`!!P``X!L#``(.`@#H&P,`
+M`D`"`%D<`P`!!P``8QP#``(.`@!K'`,``D`"`.@<`P`!!P``\AP#``(.`@#^
+M'`,``C$"`!X=`P`!!P``*!T#``(.`@!*'0,``C$"`'$=`P`",0(`MQT#``+Y
+M`0#0'0,``D`"`.,=`P`!`0``(1X#``+4`0!@'@,``0<``&@>`P`"#@(`AQX#
+M``(^`@"W'@,``0,``/P>`P`"8`(`*A\#``+Y`0`W'P,``DL"`%D?`P`"0`(`
+M:1\#``$!``""'P,``F`"`(\?`P`"2P(`RQ\#``$#```P(`,``F`"`(`@`P`"
+M,0(`DR`#``$!``"8(`,``N8!`+@@`P`!,P(`*2$#``+M`0!-(0,``0<``%<A
+M`P`"#@(`8R$#``(Q`@"3(0,``OD!`*PA`P`"\@$`2"0#``+R`0"/)`,``NT!
+M``@E`P`"\@$`3B4#``+M`0":)0,``0<``*0E`P`"#@(`K"4#``)``@#N)0,`
+M`@\"`!,F`P`!,P(`4R8#``+M`0":)@,``NT!``PG`P`"[0$`+R<#``+Y`0!$
+M)P,``4,"`'@G`P`!!P``@B<#``(.`@".)P,``C$"`-TH`P`"\@$`.RD#``$S
+M`@"F*0,``NT!``@J`P`"\@$`$RH#``$%```G*@,``CT"`&HJ`P`"\@$`=2H#
+M``$%``")*@,``CT"`-4J`P`"[0$`_RH#``+R`0`I*P,``O(!`'$K`P`!!@``
+M=BL#``(]`@"_+`,``O(!``,M`P`"[0$`42T#``+M`0"(+0,``NL!`.(M`P`"
+M[0$`%2X#``+R`0`T+@,``A8"`/\N`P`"[0$`#"\#``$%``!1+P,``CT"`!LP
+M`P`"\@$`6C`#``+M`0"S,`,``NT!`-XP`P`!!@``XS`#``(]`@`',0,``O(!
+M`$LQ`P`"[0$`GS$#``+M`0#K,0,``04``/`Q`P`"/0(`(C(#``(2`@!C,@,`
+M`NT!`'<R`P`"]P$`LS(#``+M`0#W,@,``NT!`#HS`P`"[0$`6#,#``(/`@!Q
+M,P,``O(!`)HS`P`"%@(``C0#``+S`0#C-`,``EL"`!,U`P`"U0$`:C4#``$S
+M`@"C-0,``O4!`-LU`P`"\`$`\C4#``%#`@!D-@,``E4"`&XV`P`"Z@$`BC8#
+M``'7`0"I-@,``F`"`%8W`P`"[`$`9C<#``(/`@"R.`,``NP!`-(X`P`"[`$`
+M9#H#``(6`@#V.@,``@\"`&4[`P`"ZP$`RSL#``+:`0#5.P,``D$"`!\\`P`"
+MU@$`5CP#``+:`0!_/`,``C$"`+L\`P`"[P$`USP#``+?`0"0/0,``D$"``,^
+M`P`"50(`(3X#``+X`0!1/@,``N`!`'0^`P`"0`(`D#X#``$!``"^/@,``M0!
+M`-D_`P`"6@(`.D`#``$!``!Z0`,``F`"`!!!`P`"6@(`,D$#``)@`@"V00,`
+M`OD!`*@4`P`".0(`&!8#``(Y`@`Q%@,``A4"`&48`P`",0(`+38#``+Y`0!;
+M-@,``C$"`'8W`P`"ZP$`[SL#``(/`@!./`,``NL!`+A``P`"6@(`Y$$#``$@
+M`@"L0@,``2`"`&%#`P`!(`(`3D0#``$@`@#]10,``0,``"E'`P`"*0(`F$@#
+M``(I`@!@20,``BD"``]+`P`"_@$`:$P#``+^`0"C30,``0,``#=/`P`"_@$`
+MM$\#``+^`0"*4`,``OX!`+-0`P`!"0``UE`#``$)``#C4`,``0D``.Q0`P`!
+M"0``]5`#``$)``#^4`,``0D```=1`P`!"0``$%$#``$)```940,``0D``")1
+M`P`!"0``*U$#``$)```T40,``0D``#U1`P`!"0``0U$#``$)``"640,``MT!
+M`-Q6`P`"_@$`'%<#``+^`0!<5P,``OX!`,)7`P`"_@$`'5@#``+^`0""6`,`
+M`OX!`/%8`P`!,P(`$UD#``+^`0`?60,``OX!`,99`P`"_@$`Z5D#``+^`0#F
+M6@,``OX!``E;`P`"_@$`E%L#``+^`0"V6P,``OX!`!I<`P`"_@$`)EP#``+^
+M`0!47`,``OX!`'9<`P`"_@$`UUP#``+^`0#C7`,``OX!`!E=`P`"_@$`.UT#
+M``+^`0"570,``OX!`*%=`P`"_@$`!5X#``+^`0`17@,``OX!`'5>`P`"_@$`
+M@5X#``+^`0#E7@,``OX!`/%>`P`"_@$`55\#``+^`0!A7P,``OX!`,5?`P`"
+M_@$`T5\#``+^`0`U8`,``OX!`$%@`P`"_@$`Q6`#``+^`0#18`,``OX!`#5A
+M`P`"_@$`06$#``+^`0"L80,``OX!`+AA`P`"_@$`QF$#``+^`0#080,``OX!
+M`&5B`P`"_@$`<6(#``+^`0#58@,``OX!`.%B`P`"_@$`66,#``+^`0!F8P,`
+M`OX!`,EC`P`"_@$`UF,#``+^`0#;9`,``OX!`.ED`P`"_@$`BV4#``+^`0"9
+M90,``OX!`/5E`P`"_@$``68#``+^`0"(9@,``OX!`)1F`P`"_@$`&&<#``+^
+M`0`D9P,``OX!`)1G`P`"_@$`H&<#``+^`0"N:`,``OX!`+QH`P`"_@$`F&D#
+M``+^`0"F:0,``OX!`&!J`P`"_@$`;FH#``+^`0"K:@,``0<``+AJ`P`!!P``
+M^&L#``$!``#P;`,``MT!`)5M`P`!0P(`#&X#``(T`@`Q;@,``0$``#EN`P`"
+M.0(`?FX#``(T`@"(;@,``D`"`.UN`P`".0(`-6\#``(T`@!V;P,``0$``(-O
+M`P`!`0``BV\#``(Y`@"5;P,``C4"`-5O`P`"0`(`7'`#``(Q`@!T<`,``08`
+M`'EP`P`"/0(`I7`#``)``@`-<0,``C$"`"5Q`P`!!@``*G$#``(]`@#.<0,`
+M`0$```QR`P`!`0``)7(#``)@`@!,<@,``0$``&5R`P`"8`(`C'(#``$!``"E
+M<@,``F`"`,QR`P`!`0``Y7(#``)@`@`,<P,``0$``"5S`P`"8`(`3',#``$!
+M``!E<P,``F`"`(QS`P`!`0``I7,#``)@`@#,<P,``0$``.5S`P`"8`(`#'0#
+M``$!```E=`,``F`"`$QT`P`!`0``970#``)@`@",=`,``0$``*5T`P`"8`(`
+MS'0#``$!``#E=`,``F`"``QU`P`!`0``)74#``)@`@!,=0,``0$``&5U`P`"
+M8`(`C'4#``$!``"E=0,``F`"`,QU`P`!`0``Y74#``)@`@`,=@,``0$``"5V
+M`P`"8`(`3'8#``$!``!E=@,``F`"`(QV`P`!`0``I78#``)@`@#,=@,``0$`
+M`.5V`P`"8`(`_78#``$!```8=P,``F`"`"UW`P`!`0``2W<#``)@`@".=P,`
+M`C$"`)AW`P`!`0``LW<#``)@`@`K>`,``0$``$9X`P`"8`(`NW@#``(5`@#5
+M>`,``C0"`/9X`P`!`0``2GD#``(Q`@``>@,``04```EZ`P`"/0(`&7H#``+Y
+M`0`M>@,``C$"`#5Z`P`"%0(`7GH#``$%``!G>@,``CT"`'=Z`P`"^0$`FWH#
+M``(5`@"B>@,``0$``+YZ`P`"8`(`*7L#``(Q`@`Q>P,``A4"`(M[`P`!`0``
+MJ7L#``)@`@!,?`,``OX!`$)]`P`"[0$`7'T#``$!``!U?0,``B$"`/A]`P`"
+M[0$`-'X#``+^`0#>?@,``NT!``9_`P`!`0``'W\#``(A`@!F?P,``A4"`'!_
+M`P`!`0``B7\#``(A`@`W@`,``0$```B!`P`!`0``(8$#``(A`@#]@0,``0$`
+M``^"`P`"(0(`+((#``$@`@#6@@,``0$``/*"`P`"(0(`%X,#``$)```A@P,`
+M`0D``#.#`P`!"0``.X,#``$)``!$@P,``0D``$V#`P`!"0``5H,#``$)``!?
+M@P,``0D``&B#`P`!"0``<8,#``$)``!Z@P,``0D``(.#`P`!"0``C(,#``$)
+M``"F@P,``0D``+"#`P`!`0``R8,#``(A`@!%A`,``0$``%Z$`P`"(0(`[X0#
+M``$!```(A0,``B$"`$V%`P`"_@$`EX4#``$!``"XA0,``B$"`/V%`P`"_@$`
+M-X8#``$!``!8A@,``B$"`)J&`P`!(`(`YH8#``$!```"AP,``B$"`$R'`P`!
+M(`(`QH<#``$!``#FAP,``B$"`)Z(`P`!`0``MX@#``(A`@!ZB0,``0$``).)
+M`P`"(0(`>HH#``$!``"3B@,``B$"`&J+`P`!`0``@XL#``(A`@!:C`,``0$`
+M`'.,`P`"(0(`/(T#``$!``!:C0,``B$"`)F-`P`!`0``LHT#``(A`@!4C@,`
+M`0$``&V.`P`"(0(`JHX#``$!``#(C@,``B$"`.*.`P`!!@```8\#``%#`@`+
+MCP,``0$``"2/`P`"(0(`,8\#``$&``!,CP,``1@"`%./`P`!!@``8X\#``$&
+M``![CP,``0$``*"/`P`"8`(`JX\#``'<`0"UCP,``08``,V/`P`!`0``[8\#
+M``$!```/D`,``B$"`'N0`P`!`0``D9`#``(A`@`)D0,``OX!`#N1`P`",0(`
+M0Y$#``(5`@!UD0,``0$``(Z1`P`"(0(`#I(#``$!```MD@,``F`"`%.2`P`"
+MU`$`<)(#``+^`0"0D@,``OX!`+J2`P`"_@$`"I,#``+^`0!0DP,``OX!`'N3
+M`P`"_@$`"Y0#``+^`0`5E`,``OX!`%"4`P`"_@$`<)0#``+^`0"1E`,``OX!
+M`!*5`P`"_@$`4I4#``+^`0"/E0,``OX!`,^5`P`"_@$`#Y8#``+^`0!/E@,`
+M`OX!`'*6`P`!!@``'9<#``'N`0!;EP,``@L"`&^7`P`!Y`$`@9<#``(K`@"=
+MEP,``0$``+F7`P`"(0(`S)<#``+9`0`UF`,``C0"`-.8`P`!`0``WY@#``(Y
+M`@`5F0,``D`"`$&9`P`"$@(`7YD#``$!``!TF0,``0$``(:9`P`"(0(`.YH#
+M``$!``!-F@,``B$"`&J:`P`!`0``?)H#``(A`@"$F@,``A4"`*&:`P`"_@$`
+MP9H#``+^`0#PF@,``OX!``.;`P`"-`(`/9L#``(2`@!HFP,``0$``&^;`P`!
+M`0``J9L#``$!``#"FP,``B$"``Z<`P`!`0``)YP#``(A`@!<G`,``3,"`'6<
+M`P`!!@``B9P#``$&``#@G`,``=P!`.V<`P`!`0``!IT#``(A`@!4G0,``1@"
+M`'2=`P`!!@``D9T#``$&``#HG0,``4,"`#B>`P`![@$`Q9X#``+^`0!HH`,`
+M`NT!`,2@`P`"[0$`$J$#``+M`0"+HP,``0$``*2C`P`"(0(`"Z4#``$!```D
+MI0,``B$"`(*E`P`"6`(`D:4#``(T`@"BI0,``0$``*JE`P`".0(`T:4#``+^
+M`0#9I0,``CL"`..E`P`!`0``_*4#``(A`@`AI@,``CL"`#&F`P`!`0``2J8#
+M``(A`@#)I@,``0$``/"F`P`"+@(`D:<#``$!``#/J`,``OD!`/VH`P`!W`$`
+M'ZD#``+Y`0`[J0,``OD!`%2I`P`!W`$`?JD#``+Y`0"OJ0,``OD!`.2I`P`"
+M^0$`!*H#``+Y`0"6J@,``0$``(:L`P`!`0``G:P#``(N`@`.K0,``0$``"6M
+M`P`"+@(`-:T#``+Y`0"!K0,``0$``)BM`P`"+@(`J*T#``+Y`0#7K0,``OX!
+M`.^M`P`!`0``"*X#``(A`@`7K@,``0,``$FN`P`"^0$`YJX#``+V`0`&KP,`
+M`0$``"^O`P`"+@(`/Z\#``+Y`0!EKP,``OD!`,.O`P`"^0$`R;`#``+V`0`#
+ML0,``0$``!JQ`P`"+@(`*K$#``+Y`0!&L0,``OD!``>R`P`"^0$`G+(#``+Y
+M`0`4LP,``0$``"NS`P`"+@(`.[,#``+Y`0"'LP,``OD!`-:S`P`"&0(`YK,#
+M``(9`@`YM`,``OD!`(NT`P`"^0$`GK0#``)5`@"KM`,``CL"`+FT`P`"&0(`
+MR;0#``)5`@#HM`,``O8!``ZU`P`!`0``);4#``(N`@`UM0,``OD!`$VU`P`"
+M!P(`>;4#``+V`0"SM0,``0$``,JU`P`"+@(`VK4#``+Y`0`*M@,``0$``"&V
+M`P`"+@(`,;8#``+Y`0!;M@,``0$``(2V`P`"+@(`E+8#``+Y`0"`N0,``O8!
+M`,>Y`P`"_@$`(+H#``([`@`PN@,``0$``$FZ`P`"(0(`6;H#``+U`0"UN@,`
+M`0$``,ZZ`P`"(0(`[;H#``+^`0!UNP,``O4!`*6]`P`!`0``OKT#``(A`@#=
+MO0,``OX!`/.]`P`"]0$`=;X#``+^`0"QO@,``O4!`+N^`P`!`0``U+X#``(A
+M`@!,OP,``MH!`)N_`P`"#P(`Q;\#``+Q`0#XOP,``NT!`$S``P`"[0$`6<`#
+M``+U`0"*P`,``MH!`-K``P`"_@$`$\$#``$!```LP0,``B$"`._!`P`",0(`
+M)<(#``('`@"OP@,``OX!`-/"`P`!`P``]\(#``+H`0`VPP,``N@!`(/#`P`"
+M_@$`',4#``(6`@!]Q0,``OX!`+3%`P`"Z0$`Y\4#``+:`0#\Q0,``@\"`";'
+M`P`"*0(`=,<#``(I`@"OQP,``OX!``K(`P`"%@(`!\D#``(I`@`_R0,``MX!
+M`*_*`P`"_@$`[\H#``+I`0!VRP,``D`"`(O+`P`"!P(`H\L#``+C`0!4S`,`
+M`CL"`&#,`P`"&0(`M\P#``$!``#.S`,``BX"`-[,`P`"^0$`0,T#``$!``!7
+MS0,``BX"`&?-`P`"^0$`JLT#``)8`@#_S0,``MH!`%[.`P`!`0``=<X#``(N
+M`@")S@,``OD!`/+.`P`"_@$`5L\#``+^`0!HSP,``0$``(+/`P`"&0(`F,\#
+M``)5`@#4SP,``0$``.O/`P`"+@(`^\\#``+Y`0`)T`,``0$``#/1`P`"ZP$`
+M<]$#``(9`@"'T0,``E@"`"'2`P`"_@$`8=(#``+I`0#ST@,``MH!`"+3`P`"
+MZ0$`5-,#``+:`0"GTP,``NP!`+/3`P`"ZP$`W],#``$!```2U`,``OX!`#34
+M`P`!`0``4M0#``(A`@"TU`,``A("`![5`P`!`0``-]4#``(A`@!]U0,``0$`
+M`);5`P`"(0(`O=4#``(5`@`$U@,``E@"``S6`P`"&0(`'-8#``$!```ZU@,`
+M`B$"`,W7`P`"$@(`W=<#``);`@"GV`,``OX!``'9`P`".@(`.]D#``$!``!4
+MV0,``B$"``?:`P`"X0$`Z]H#``+G`0`/W0,``A("`!_=`P`"6P(`C]T#``+J
+M`0"?W0,``OX!`+C=`P`"00(`P-T#``+J`0#.W0,``0$``.?=`P`"(0(`(MX#
+M``(Q`@"/W@,``0$``+'>`P`"#0(`\-X#``+^`0!6X`,``0$``(K@`P`"5P(`
+MEN$#``(E`@"'X@,``C0"`*OB`P`!`0``Y>(#``(5`@`%XP,``0$``!KE`P`!
+M!0``(^4#``(]`@!FYP,``O8!`)WG`P`"0`(`+ND#``$!```&Z@,``0$``'3J
+M`P`"*0(`F^H#``)``@"ZZ@,``C0"`"+K`P`!&`(`:>L#``(Q`@!UZP,``A4"
+M`+SK`P`",0(`R.L#``(5`@#HZP,``C$"`/GK`P`!`0``?^P#``$!``"E[`,`
+M`0$``$/M`P`!`0``"NX#``+^`0!J[@,``OX!`/KN`P`"_@$`B>\#``+^`0#C
+M[P,``OX!`(/P`P`"_@$`-?$#``(&`@!'\0,``2H"`+[Q`P`"/P(`V/$#``(?
+M`@!6\@,``C$"`&7R`P`"%0(`;_(#``$!``"(\@,``B$"`!+S`P`",0(`(?,#
+M``(5`@`K\P,``0$``$3S`P`"(0(`JO,#``+Y`0#W\P,``OX!``/T`P`"_@$`
+M-_0#``)4`@"E]`,``E0"`)OU`P`"_@$`RO4#``)4`@#=]0,``0$``/;U`P`"
+M(0(`7?8#``+^`0!E]@,``D$"`)/V`P`"_@$`O/8#``$!``#5]@,``B$"`._V
+M`P`"_@$`E?<#``(5`@"?]P,``0$``+CW`P`"(0(`:_@#``+5`0"[^`,``2`"
+M`,CX`P`!(`(`T/@#``)<`@`J^0,``N@!`'GY`P`!(`(`P?D#``$!``#:^0,`
+M`B$"`%[Z`P`!`0``:OH#``+F`0"K^@,``0$``,3Z`P`"(0(`Z?H#``$!```(
+M^P,``F`"`%W[`P`"\`$`;?L#``%#`@"`^P,``OD!`,[[`P`!`0``$/P#``(Q
+M`@`M_`,``C$"`#K\`P`"Z@$`;_P#``+^`0!Y_`,``OX!`(7\`P`"]`$`C/P#
+M``$!``"R_`,``B$"`-C\`P`![@$`#OT#``'N`0`:_0,``@`"`#K]`P`!Y`$`
+M3/T#``(K`@"D_0,``A("`,K]`P`!`0``X_T#``(A`@`V_@,``0$``$_^`P`"
+M(0(`M_X#``+^`0`._P,``CH"`$;_`P`!`0``7_\#``(A`@#K_P,``N$!`,\`
+M!``"YP$`AP$$``+^`0#N`00``0$```<"!``"(0(`<P($``+A`0!G`P0``OX!
+M`,@#!``!`0``X0,$``(A`@!!!`0``N$!`"8%!``!(`(`:@4$``$!``"#!00`
+M`B$"`)8%!``"_@$`VP4$``+U`0#D!@0``AD"``,'!``!`P``;@@$``$!``"7
+M"`0``OX!`'()!``"&0(`?`D$``$!``"5"00``B$"`,X)!``"_@$`!@H$``(2
+M`@`G"@0``0$``$4*!``"(0(`JPH$``(T`@"["@0``1@"`)$+!``!`0``F`L$
+M``$!``!C#`0``B8"`(<,!``!`0``HPP$``(A`@`3#00``0$``"P-!``"8`(`
+M8`X$``(5`@!W#@0``0$``)`.!``"(0(`&@\$``(5`@!&#P0``B8"`+P/!``"
+M%0(`7A`$``(F`@!U$`0``B8"`(81!``"%0(`X1$$``(Q`@`!$@0``OX!`"02
+M!``"\0$`.Q($``$!``!4$@0``B$"``$3!``!`0``&A,$``(A`@`J$P0``OD!
+M`#<3!``!`0``6!,$``(A`@!;<0,``C4"`.%Q`P`"+P(`_W<#``(Y`@!8>`,`
+M`A4"``YY`P`".0(`7GD#``(5`@`E?`,``CD"`/Z1`P`".0(`BYL#``(Y`@#T
+MJ@,``B\"`$C>`P`"X`$`+^,#``(A`@`NYP,``CD"`&OI`P`"#0(`,.H#``(A
+M`@#:[`,``@T"`-;M`P`".0(`$?L#``+7`0`!_`,``F`"`,$,!``".0(`X0\$
+M``(Y`@#V$`0``CD"`$`1!``".0(`$A8$``)@`@`V%@0``OT!`&L6!``")@(`
+M1AD$``$!``"Q&00``AL"`.L9!``!`0``]AD$``$!``#H&@0``@<"`/$;!``"
+M&P(`3!P$``'_`0!E'`0``E<"`.`<!``",0(`$1\$``'_`0`J'P0``E<"`#P?
+M!``"_P$`XQ\$``):`@`3(`0``F`"`+$@!``".0(`U2`$``+;`0`D(00``CD"
+M`,P5!``"8`(`G1H$``(Y`@!\'`0``O\!``T=!``"6@(`>!T$``(Y`@`<(00`
+M`C4"`*\A!``"]@$`$R0$``(!`@!/)`0``@$"`&HD!``"`0(`&B4$``+>`0`C
+M)@0``N,!`&8G!``"*0(`2R@$``+Y`0"`*`0``ND!`!XI!``"&0(`[2L$``+W
+M`0#]*P0``O(!`#`L!``"[0$`A2P$``+M`0"B+`0``O4!`#0M!``"&0(`:BT$
+M``('`@"#+00``@<"`)$M!``"!P(`H2T$``(9`@"I+00``AD"`/PM!``!`P``
+MA2X$``(7`@#<+@0``OL!`"TO!``"X`$`O2\$``(9`@#4,`0``CL"`#8Q!``"
+M*0(`3C$$``+I`0!>,00``A<"`(\Q!``"%@(`SC,$``+M`0`0-`0``NT!`",T
+M!``"]P$`US0$``+M`0#P-`0``O<!`!@U!``"\@$`-C4$``+R`0#Y.`0``F4"
+M`%0Y!``"90(`]SD$``)E`@#=.@0``D`"`)$[!``"]P$`R3L$``+M`0#1.P0`
+M`O<!`.([!``"]P$`/CP$``+M`0!*/`0``O<!`,`\!``"]@$`USP$``([`@#V
+M/`0``O8!`(,]!``"90(`AC\$``)!`@"C/P0``CL"`*T_!``"&0(`YS\$``(7
+M`@`P)@0``OL!`&`H!``"^P$`Z"\$``([`@!6/@0``D$"`!%`!``!V`$`,D`$
+M``$X`@!-0`0``3@"`-Y!!``!`0``_4$$``)@`@`X0@0``A\"`'Y"!``"8@(`
+MGD($``),`@`<`````0$``"`````!`0``)`````$!```H`````0$``"P````!
+M`0``,`````$!```T`````0$``#@````!`0``/`````$!``!``````0$``$0`
+M```!`0``2`````$!``!,`````0$``%`````!`0``5`````$!``!8`````0$`
+M`%P````!`0``8`````$!``!D`````0$``&@````!`0``;`````$!``!P````
+M`0$``'0````!`0``>`````$!``!\`````0$``(`````!`0``A`````$!``"(
+M`````0$``(P````!`0``D`````$!``"4`````0$``)@````!`0``G`````$!
+M``"@`````0$``*0````!`0``J`````$!``"L`````0$``+`````!`0``M```
+M``$!``"X`````0$``+P````!`0``P`````$!``#$`````0$``,@````!`0``
+MS`````$!``#0`````0$``-0````!`0``V`````$!``#<`````0$``.`````!
+M`0``Y`````$!``#H`````0$``.P````!`0``\`````$!``#T`````0$``/@`
+M```!`0``_`````$!`````0```0$```0!```!`0``"`$```$!```,`0```0$`
+M`!`!```!`0``%`$```$!```8`0```0$``!P!```!`0``(`$```$!```D`0``
+M`0$``"@!```!`0``+`$```$!```P`0```0$``#0!```!`0``.`$```$!```\
+M`0```0$``$`!```!`0``1`$```$!``!(`0```0$``$P!```!`0``4`$```$!
+M``!4`0```0$``%@!```!`0``7`$```$!``"`!0```0$``(0%```!`0``B`4`
+M``$!``",!0```0$``)`%```!`0``E`4```$!``"8!0```0$``)P%```!`0``
+MH`4```$!``"D!0```0$``*@%```!`0``K`4```$!``"P!0```0$``+0%```!
+M`0``N`4```$!``"\!0```0$``,`%```!`0``Q`4```$!``#(!0```0$``,P%
+M```!`0``T`4```$!``#4!0```0$``-@%```!`0``W`4```$!``#@!0```0$`
+M`.0%```!`0``Z`4```$!``#L!0```0$``/`%```!`0``]`4```$!``#X!0``
+M`0$``/P%```!`0````8```$!```$!@```0$```@&```!`0``#`8```$!```0
+M!@```0$``!0&```!`0``&`8```$!```<!@```0$``"`&```!`0``)`8```$!
+M```H!@```0$``"P&```!`0``,`8```$!```T!@```0$``#@&```!`0``/`8`
+M``$!``!`!@```0$``$0&```!`0``2`8```$!``!,!@```0$``%`&```!`0``
+M5`8```$!``!8!@```0$``%P&```!`0``8`8```$!``!D!@```0$``&@&```!
+M`0``;`8```$!``!P!@```0$``'0&```!`0``>`8```$!``!\!@```0$``(`&
+M```!`0``A`8```$!``"(!@```0$``(P&```!`0``D`8```$!``"4!@```0$`
+M`)@&```!`0``G`8```$!``"@!@```0$``*0&```!`0``J`8```$!``"L!@``
+M`0$``+`&```!`0``M`8```$!``"X!@```0$``+P&```!`0``P`8```$!``#$
+M!@```0$``,@&```!`0``S`8```$!``#0!@```0$``-0&```!`0``V`8```$!
+M``#<!@```0$``.`&```!`0``Y`8```$!``#H!@```0$``.P&```!`0``\`8`
+M``$!``#T!@```0$``/@&```!`0``_`8```$!````!P```0$```0'```!`0``
+M"`<```$!```,!P```0$``!`'```!`0``%`<```$!```8!P```0$``!P'```!
+M`0``(`<```$!```D!P```0$``"@'```!`0``+`<```$!```P!P```0$``#0'
+M```!`0``.`<```$!```\!P```0$``$`'```!`0``1`<```$!``!(!P```0$`
+M`$P'```!`0``4`<```$!``!4!P```0$``%@'```!`0``7`<```$!``!@!P``
+M`0$``&0'```!`0``:`<```$!``!L!P```0$``'`'```!`0``=`<```$!``!X
+M!P```0$``'P'```!`0``@`<```$!``"$!P```0$``(@'```!`0``C`<```$!
+M``"0!P```0$``)0'```!`0``F`<```$!``"<!P```0$``*`'```!`0``I`<`
+M``$!``"H!P```0$``*P'```!`0``L`<```$!``"T!P```0$``+@'```!`0``
+MO`<```$!``#`!P```0$``,0'```!`0``R`<```$!``#,!P```0$``-`'```!
+M`0``U`<```$!``#8!P```0$``-P'```!`0``X`<```$!``#D!P```0$``.@'
+M```!`0``[`<```$!``#P!P```0$``/0'```!`0``^`<```$!``#\!P```0$`
+M```(```!`0``!`@```$!```("````0$```P(```!`0``$`@```$!```4"```
+M`0$``!@(```!`0``'`@```$!```@"````0$``"0(```!`0``*`@```$!```L
+M"````0$``#`(```!`0``-`@```$!```X"````0$``#P(```!`0``0`@```$!
+M``!$"````0$``$@(```!`0``3`@```$!``!0"````0$``%0(```!`0``6`@`
+M``$!``!<"````0$``&`(```!`0``9`@```$!``!H"````0$``&P(```!`0``
+M<`@```$!``!T"````0$``'@(```!`0``?`@```$!``"`"````0$``(0(```!
+M`0``B`@```$!``","````0$``)`(```!`0``E`@```$!``"8"````0$``*`(
M```!`0``I`@```$!``"H"````0$``*P(```!`0``L`@```$!``"T"````0$`
M`+@(```!`0``O`@```$!``#`"````0$``,0(```!`0``R`@```$!``#,"```
M`0$``-`(```!`0``U`@```$!``#8"````0$``-P(```!`0``X`@```$!``#D
M"````0$``.@(```!`0``[`@```$!``#P"````0$``/0(```!`0``^`@```$!
-M``#\"````0$````)```!`0``!`D```$!```("0```0$```P)```!`0``$`D`
-M``$!```4"0```0$``!@)```!`0``'`D```$!```@"0```0$``"0)```!`0``
-M*`D```$!```L"0```0$``#`)```!`0``-`D```$!```X"0```0$``#P)```!
-M`0``0`D```$!``!$"0```0$``$@)```!`0``3`D```$!``!0"0```0$``%0)
-M```!`0``6`D```$!``!<"0```0$``&`)```!`0``9`D```$!``!H"0```0$`
-M`&P)```!`0``<`D```$!``!T"0```0$``'@)```!`0``?`D```$!``"`"0``
-M`0$``(0)```!`0``B`D```$!``","0```0$``)`)```!`0``E`D```$!``"8
-M"0```0$``)P)```!`0``H`D```$!``"D"0```0$``*@)```!`0``K`D```$!
-M``"P"0```0$``+0)```!`0``N`D```$!``"\"0```0$``,`)```!`0``Q`D`
-M``$!``#("0```0$``,P)```!`0``T`D```$!``#4"0```0$``-@)```!`0``
-MW`D```$!``#@"0```0$``.0)```!`0``Z`D```$!``#L"0```0$``/`)```!
-M`0``]`D```$!``#X"0```0$``/P)```!`0````H```$!```$"@```0$```@*
-M```!`0``#`H```$!```0"@```0$``!0*```!`0``&`H```$!```<"@```0$`
-M`"`*```!`0``)`H```$!```H"@```0$``"P*```!`0``,`H```$!```T"@``
-M`0$``#@*```!`0``/`H```$!``!`"@```0$``$0*```!`0``2`H```$!``!,
-M"@```0$``%`*```!`0``5`H```$!``!8"@```0$``%P*```!`0``8`H```$!
-M``!D"@```0$``&@*```!`0``;`H```$!``!P"@```0$``'0*```!`0``>`H`
-M``$!``!\"@```0$``(`*```!`0``A`H```$!``"("@```0$``(P*```!`0``
-MD`H```$!``"4"@```0$``)@*```!`0``G`H```$!``"@"@```0$``*0*```!
-M`0``J`H```$!``"L"@```0$``+`*```!`0``M`H```$!``"X"@```0$``+P*
-M```!`0``P`H```$!``#$"@```0$``,@*```!`0``S`H```$!``#0"@```0$`
-M`-0*```!`0``V`H```$!``#<"@```0$``.`*```!`0``Y`H```$!``#H"@``
-M`0$``.P*```!`0``\`H```$!``#T"@```0$``/@*```!`0``_`H```$!````
-M"P```0$```0+```!`0``"`L```$!```,"P```0$``!`+```!`0``%`L```$!
-M```8"P```0$``!P+```!`0``(`L```$!```D"P```0$``"@+```!`0``+`L`
-M``$!```P"P```0$``#0+```!`0``.`L```$!```\"P```0$``$`+```!`0``
-M1`L```$!``!("P```0$``$P+```!`0``4`L```$!``!4"P```0$``%@+```!
-M`0``7`L```$!``!@"P```0$``&0+```!`0``:`L```$!``!L"P```0$``'`+
-M```!`0``=`L```$!``!X"P```0$``'P+```!`0``@`L```$!``"$"P```0$`
-M`(@+```!`0``C`L```$!``"0"P```0$``)0+```!`0``F`L```$!``"<"P``
-M`0$``*`+```!`0``I`L```$!``"H"P```0$``*P+```!`0``L`L```$!``#@
-M#P```0$``.0/```!`0``Z`\```$!``#L#P```0$``/`/```!`0``]`\```$!
-M``#X#P```0$``/P/```!`0```!````$!```$$````0$```@0```!`0``#!``
-M``$!```0$````0$``!00```!`0``&!````$!```<$````0$``"`0```!`0``
-M)!````$!```H$````0$``"P0```!`0``,!````$!```T$````0$``#@0```!
-M`0``/!````$!``!`$````0$``$00```!`0``2!````$!``!,$````0$``%`0
-M```!`0``5!````$!``!8$````0$``%P0```!`0``8!````$!``!D$````0$`
-M`&@0```!`0``;!````$!``!P$````0$``'00```!`0``>!````$!``!\$```
-M`0$``(`0```!`0``A!````$!``"($````0$``(P0```!`0``D!````$!``"4
-M$````0$``)@0```!`0``G!````$!``"@$````0$``*00```!`0``J!````$!
-M``"L$````0$``+`0```!`0``M!````$!``"X$````0$``+P0```!`0``P!``
-M``$!``#$$````0$``,@0```!`0``S!````$!``#0$````0$``-00```!`0``
-MV!````$!``#<$````0$``.`0```!`0``Y!````$!``#H$````0$``.P0```!
-M`0``\!````$!``#T$````0$``/@0```!`0``_!````$!````$0```0$```01
-M```!`0``"!$```$!```,$0```0$``!`1```!`0``%!$```$!```8$0```0$`
-M`!P1```!`0``(!$```$!```D$0```0$``"@1```!`0``+!$```$!```P$0``
-M`0$``#01```!`0``.!$```$!```\$0```0$``$`1```!`0``1!$```$!``!(
-M$0```0$``$P1```!`0``4!$```$!``!4$0```0$``%@1```!`0``7!$```$!
-M``!@$0```0$``&01```!`0``:!$```$!``!L$0```0$``'`1```!`0``=!$`
-M``$!``!X$0```0$``'P1```!`0``@!$```$!``"$$0```0$``(@1```!`0``
-MC!$```$!``"0$0```0$``)01```!`0``F!$```$!``"<$0```0$``*`1```!
-M`0``I!$```$!``"H$0```0$``*P1```!`0``L!$```$!``"T$0```0$``+@1
-M```!`0``O!$```$!``#`$0```0$``,01```!`0``R!$```$!``#,$0```0$`
-M`-`1```!`0``U!$```$!``#8$0```0$``-P1```!`0``X!$```$!``#D$0``
-M`0$``.@1```!`0``[!$```$!``#P$0```0$``/01```!`0``^!$```$!``#\
-M$0```0$````2```!`0``!!(```$!```($@```0$```P2```!`0``$!(```$!
-M```4$@```0$``!@2```!`0``'!(```$!```@$@```0$``"02```!`0``*!(`
-M``$!```L$@```0$``#`2```!`0``-!(```$!```X$@```0$``#P2```!`0``
-M0!(```$!``!$$@```0$``$@2```!`0``3!(```$!``!0$@```0$``%02```!
-M`0``6!(```$!``!<$@```0$``&`2```!`0``9!(```$!``!H$@```0$``&P2
-M```!`0``<!(```$!``!T$@```0$``'@2```!`0``?!(```$!``"`$@```0$`
-M`(02```!`0``B!(```$!``",$@```0$``)`2```!`0``E!(```$!``"8$@``
-M`0$``)P2```!`0``H!(```$!``"D$@```0$``*@2```!`0``K!(```$!``"P
-M$@```0$``+02```!`0``N!(```$!``"\$@```0$``,`2```!`0``Q!(```$!
-M``#($@```0$``,P2```!`0``T!(```$!``#4$@```0$``-@2```!`0``W!(`
-M``$!``#@$@```0$``.02```!`0``Z!(```$!``#L$@```0$``/`2```!`0``
-M]!(```$!``#X$@```0$````3```!`0``!!,```$!```($P```0$```P3```!
-M`0``$!,```$!```4$P```0$``!@3```!`0``'!,```$!```@$P```0$``"03
-M```!`0``*!,```$!```L$P```0$``#`3```!`0``-!,```$!```X$P```0$`
-M`#P3```!`0``0!,```$!``!$$P```0$``$@3```!`0``3!,```$!``!0$P``
-M`0$``%03```!`0``6!,```$!``!<$P```0$``.`3```!`0``Y!,```$!``#H
-M$P```0$``.P3```!`0``\!,```$!``#T$P```0$``/@3```!`0``_!,```$!
-M````%````0$```04```!`0``"!0```$!```,%````0$``!`4```!`0``%!0`
-M``$!```8%````0$``!P4```!`0``(!0```$!```D%````0$``"@4```!`0``
-M+!0```$!```P%````0$``#04```!`0``.!0```$!```\%````0$``$`4```!
-M`0``1!0```$!``!(%````0$``$P4```!`0``4!0```$!``!4%````0$``%@4
-M```!`0``7!0```$!``!@%````0$``&04```!`0``:!0```$!``!L%````0$`
-M`'`4```!`0``?!0```$!``"`%````0$``(04```!`0``B!0```$!``",%```
-M`0$``)`4```!`0``E!0```$!``"8%````0$``)P4```!`0``H!0```$!``"D
-M%````0$``*@4```!`0``K!0```$!``"P%````0$``+04```!`0``N!0```$!
-M``"\%````0$``,`4```!`0``Q!0```$!``#(%````0$``,P4```!`0``T!0`
-M``$!``#4%````0$``-@4```!`0``W!0```$!``#@%````0$``.04```!`0``
-MZ!0```$!``#L%````0$``/`4```!`0``]!0```$!``#X%````0$``/P4```!
-M`0```!4```$!```$%0```0$```@5```!`0``#!4```$!```0%0```0$``!05
-M```!`0``&!4```$!```<%0```0$``"`5```!`0``)!4```$!```H%0```0$`
-M`"P5```!`0``,!4```$!```T%0```0$``#@5```!`0``/!4```$!``!`%0``
-M`0$``$05```!`0``2!4```$!``!,%0```0$``%`5```!`0``5!4```$!``!8
-M%0```0$``%P5```!`0``8!4```$!``!D%0```0$``&@5```!`0``;!4```$!
-M``!P%0```0$``'05```!`0``>!4```$!``!\%0```0$``(`5```!`0``A!4`
-M``$!``"(%0```0$``(P5```!`0``D!4```$!``"4%0```0$``)@5```!`0``
-MG!4```$!``"@%0```0$``,`5```!`0``Q!4```$!``#(%0```0$``,P5```!
-M`0``T!4```$!``#4%0```0$``-@5```!`0``W!4```$!``#@%0```0$``.05
-M```!`0``Z!4```$!``#L%0```0$``/`5```!`0``]!4```$!``#X%0```0$`
-M`/P5```!`0```!8```$!```$%@```0$```@6```!`0``#!8```$!```0%@``
-M`0$``!06```!`0``&!8```$!```<%@```0$``"`6```!`0``)!8```$!```H
-M%@```0$``"P6```!`0``,!8```$!```T%@```0$``#@6```!`0``/!8```$!
-M``!`%@```0$``$06```!`0``2!8```$!``!,%@```0$``%`6```!`0``5!8`
-M``$!``!8%@```0$``%P6```!`0``8!8```$!``!D%@```0$``&@6```!`0``
-M;!8```$!``!P%@```0$``'06```!`0``>!8```$!``!\%@```0$``(`6```!
-M`0``A!8```$!``"(%@```0$``(P6```!`0``D!8```$!``"4%@```0$``)@6
-M```!`0``G!8```$!``"@%@```0$``*06```!`0``J!8```$!``"L%@```0$`
-M`+`6```!`0``M!8```$!``"X%@```0$``+P6```!`0``P!8```$!``#$%@``
-M`0$``,@6```!`0``S!8```$!``#0%@```0$``-06```!`0``V!8```$!``#<
-M%@```0$``.`6```!`0``Y!8```$!``#H%@```0$``.P6```!`0``\!8```$!
-M``#T%@```0$``/@6```!`0``_!8```$!````%P```0$```07```!`0``"!<`
-M``$!```,%P```0$``!`7```!`0``%!<```$!```8%P```0$``!P7```!`0``
-M(!<```$!```D%P```0$``"@7```!`0``+!<```$!```P%P```0$``#07```!
-M`0``.!<```$!```\%P```0$``$`7```!`0``1!<```$!``!(%P```0$``$P7
-M```!`0``4!<```$!``!4%P```0$``%@7```!`0``7!<```$!``!@%P```0$`
-M`&07```!`0``:!<```$!``!L%P```0$``'`7```!`0``=!<```$!``!X%P``
-M`0$``'P7```!`0``@!<```$!``"$%P```0$``(@7```!`0``C!<```$!``"0
-M%P```0$``)07```!`0``F!<```$!``"<%P```0$``*`7```!`0``I!<```$!
-M``"H%P```0$``*P7```!`0``L!<```$!``"T%P```0$``+@7```!`0``O!<`
-M``$!``#`%P```0$``,07```!`0``R!<```$!``#,%P```0$```P8```!`0``
-M$!@```$!```4&````0$``!@8```!`0``'!@```$!```@&````0$``"08```!
-M`0``*!@```$!```L&````0$``#`8```!`0``-!@```$!```X&````0$``#P8
-M```!`0``0!@```$!``!$&````0$``$@8```!`0``3!@```$!``!0&````0$`
-M`%08```!`0``6!@```$!``!<&````0$``&`8```!`0``9!@```$!``!H&```
-M`0$``&P8```!`0``<!@```$!``!T&````0$``'@8```!`0``?!@```$!``"`
-M&````0$``(08```!`0``B!@```$!``",&````0$``)`8```!`0``E!@```$!
-M``"8&````0$``)P8```!`0``H!@```$!``"D&````0$``*@8```!`0``K!@`
-M``$!``"P&````0$``+08```!`0``N!@```$!``"\&````0$``,`8```!`0``
-MQ!@```$!``#(&````0$``,P8```!`0``T!@```$!``#4&````0$``-@8```!
-M`0``W!@```$!``#@&````0$``.08```!`0``Z!@```$!``#L&````0$``/`8
-M```!`0``]!@```$!``#X&````0$``/P8```!`0```!D```$!```$&0```0$`
-M``@9```!`0``#!D```$!```0&0```0$``!09```!`0``&!D```$!``"`````
-M`08``(P````!`0``D`````$!``"4`````0$``)@````!`0``G`````$!``"@
-M`````0$``*0````!`0``J`````$!``"L`````0$``+`````!`0``M`````$!
-M``"X`````0$``+P````!`0``P`````$C`0#$`````0$``,@````!`0``S```
-M``$!``#0`````0$``-0````!`0``V`````$!``#<`````0$``.`````!`0``
-MY`````$!``#H`````0$``.P````!`0``\`````$!``#T`````0$``/@````!
-M`0``_`````%$```$`0```0$```@!```!`0``#`$```$!```0`0```0$``!0!
-M```!`0``&`$```'6``"``0```08``(P!```!`0``D`$```$!``"4`0```0$`
-M`)@!```!`0``G`$```$!``"@`0```0$``*0!```!`0``J`$```$!``"L`0``
-M`0$``+`!```!`0``M`$```$!``"X`0```0$``+P!```!`0``P`$```$Y`0#$
-M`0```0$``,@!```!`0``S`$```$!``#0`0```0$``-0!```!`0``V`$```$!
-M``#<`0```0$``.`!```!`0``Y`$```$!``#H`0```0$``.P!```!`0``\`$`
-M``$!``#T`0```0$``/@!```!`0``_`$```$$`@`$`@```0$```@"```!`0``
-M#`(```$!```0`@```0$``!0"```!`0``&`(```$_`0!\`@```0$``(`"```!
-M`0``A`(```$!``"0`@```0$``)0"```!`0``F`(```$!``#$`@```0$``,P"
-M```!`0``V`(```$!``#@`@```0$``.P"```!`0``]`(```$!`````P```0$`
-M``@#```!`0``%`,```$!```<`P```0$``"@#```!`0``,`,```$!```\`P``
-M`0$``$0#```!`0``4`,```$!``!4`P```0$``%@#```!`0``9`,```$!``!H
-M`P```0$``&P#```!`0``>`,```$!``"``P```0$``(P#```!`0``E`,```$!
-M``"@`P```0$``*0#```!`0``J`,```$!``"T`P```0$``+@#```!`0``O`,`
-M``$!``#(`P```0$``,P#```!`0``T`,```$!``#<`P```0$``.`#```!`0``
-MY`,```$!``#P`P```0$``/0#```!`0``^`,```$!```$!````0$```P$```!
-M`0``&`0```$!```@!````0$``"P$```!`0``-`0```$!``!`!````0$``$@$
-M```!`0``5`0```$!``!<!````0$``&@$```!`0``<`0```$!``!\!````0$`
-M`(0$```!`0``D`0```$!``"8!````0$``*0$```!`0``K`0```$!``"X!```
-M`0$``,`$```!`0``S`0```$!``#0!````0$``-0$```!`0``X`0```$!``#D
-M!````0$``.@$```!`0``]`0```$!``#\!````0$```@%```!`0``$`4```$!
-M```<!0```0$``"0%```!`0``,`4```$!```X!0```0$``$0%```!`0``3`4`
-M``$!``!8!0```0$``%P%```!`0``8`4```$!``!L!0```0$``'0%```!`0``
-M@`4```$!``"$!0```0$``(@%```!`0``E`4```$!``"<!0```0$``*@%```!
-M`0``K`4```$!``"P!0```0$``+P%```!`0``Q`4```$!``#0!0```0$``-@%
-M```!`0``Y`4```$!``#L!0```0$``/@%```!`0````8```$!```,!@```0$`
-M`!`&```!`0``%`8```$!```@!@```0$``"0&```!`0``*`8```$!```T!@``
-M`0$``#P&```!`0``2`8```$!``!0!@```0$``%P&```!`0``9`8```$!``!P
-M!@```0$``'@&```!`0``A`8```$!``",!@```0$``)@&```!`0``H`8```$!
-M``"L!@```0$``+0&```!`0``P`8```$!``#(!@```0$``-0&```!`0``W`8`
-M``$!``#H!@```0$``/`&```!`0``_`8```$!````!P```0$```0'```!`0``
-M$`<```$!```8!P```0$``"0'```!`0``+`<```$!```X!P```0$``$`'```!
-M`0``3`<```$!``!4!P```0$``&`'```!`0``9`<```$!``!H!P```0$``'0'
-6```!`0``>`<```$!``!\!P```0$`````
+M``#\"````0$``(`)```!`0``A`D```$!``"("0```0$``(P)```!`0``D`D`
+M``$!``"4"0```0$``)@)```!`0``G`D```$!``"@"0```0$``*0)```!`0``
+MJ`D```$!``"L"0```0$``+`)```!`0``M`D```$!``"X"0```0$``+P)```!
+M`0``P`D```$!``#$"0```0$``,@)```!`0``S`D```$!``#0"0```0$``-0)
+M```!`0``V`D```$!``#<"0```0$``.`)```!`0``Y`D```$!``#H"0```0$`
+M`.P)```!`0``\`D```$!``#T"0```0$``/@)```!`0``_`D```$!````"@``
+M`0$```0*```!`0``"`H```$!```,"@```0$``!`*```!`0``'`H```$!```@
+M"@```0$``"0*```!`0``*`H```$!```L"@```0$``#`*```!`0``-`H```$!
+M```X"@```0$``#P*```!`0``0`H```$!``!$"@```0$``$@*```!`0``3`H`
+M``$!``!0"@```0$``%0*```!`0``6`H```$!``!<"@```0$``&`*```!`0``
+M9`H```$!``!H"@```0$``&P*```!`0``<`H```$!``!T"@```0$``'@*```!
+M`0``?`H```$!``"`"@```0$``(0*```!`0``B`H```$!``","@```0$``)`*
+M```!`0``E`H```$!``"8"@```0$``)P*```!`0``H`H```$!``"D"@```0$`
+M`*@*```!`0``K`H```$!``"P"@```0$``+0*```!`0``N`H```$!``"\"@``
+M`0$``,`*```!`0``Q`H```$!``#("@```0$``,P*```!`0``T`H```$!``#4
+M"@```0$``-@*```!`0``W`H```$!``#@"@```0$``.0*```!`0``Z`H```$!
+M``#L"@```0$``/`*```!`0``]`H```$!``#X"@```0$``/P*```!`0````L`
+M``$!```$"P```0$```@+```!`0``#`L```$!```0"P```0$``!0+```!`0``
+M&`L```$!```<"P```0$``"`+```!`0``)`L```$!```H"P```0$``"P+```!
+M`0``,`L```$!```T"P```0$``#@+```!`0``/`L```$!``!`"P```0$``&`+
+M```!`0``9`L```$!``!H"P```0$``&P+```!`0``<`L```$!``!T"P```0$`
+M`'@+```!`0``?`L```$!``"`"P```0$``(0+```!`0``B`L```$!``","P``
+M`0$``)`+```!`0``E`L```$!``"8"P```0$``)P+```!`0``H`L```$!``"D
+M"P```0$``*@+```!`0``K`L```$!``"P"P```0$``+0+```!`0``N`L```$!
+M``"\"P```0$``,`+```!`0``Q`L```$!``#("P```0$``,P+```!`0``T`L`
+M``$!``#4"P```0$``-@+```!`0``W`L```$!``#@"P```0$``.0+```!`0``
+MZ`L```$!``#L"P```0$``/`+```!`0``]`L```$!``#X"P```0$``/P+```!
+M`0````P```$!```$#````0$```@,```!`0``#`P```$!```0#````0$``!0,
+M```!`0``&`P```$!```<#````0$``"`,```!`0``)`P```$!```H#````0$`
+M`"P,```!`0``,`P```$!```T#````0$``#@,```!`0``/`P```$!``!`#```
+M`0$``$0,```!`0``2`P```$!``!,#````0$``%`,```!`0``5`P```$!``!8
+M#````0$``%P,```!`0``8`P```$!``!D#````0$``&@,```!`0``;`P```$!
+M``!P#````0$``'0,```!`0``>`P```$!``!\#````0$``(`,```!`0``A`P`
+M``$!``"(#````0$``(P,```!`0``D`P```$!``"4#````0$``)@,```!`0``
+MG`P```$!``"@#````0$``*0,```!`0``J`P```$!``"L#````0$``+`,```!
+M`0``M`P```$!``"X#````0$``+P,```!`0``P`P```$!``#$#````0$``,@,
+M```!`0``S`P```$!``#0#````0$``-0,```!`0``V`P```$!``#<#````0$`
+M`.`,```!`0``Y`P```$!``#H#````0$``.P,```!`0``\`P```$!``#T#```
+M`0$``/@,```!`0``_`P```$!````#0```0$```0-```!`0``"`T```$!```,
+M#0```0$``!`-```!`0``%`T```$!```8#0```0$``!P-```!`0``(`T```$!
+M```D#0```0$``"@-```!`0``+`T```$!```P#0```0$``#0-```!`0``.`T`
+M``$!```\#0```0$``$`-```!`0``1`T```$!``!(#0```0$``$P-```!`0``
+M4`T```$!``!4#0```0$``%@-```!`0``7`T```$!``!@#0```0$``&0-```!
+M`0``:`T```$!``!L#0```0$``*P-```!`0``L`T```$!``"T#0```0$``+@-
+M```!`0``O`T```$!``#`#0```0$``,0-```!`0``R`T```$!``#,#0```0$`
+M`-`-```!`0``U`T```$!``#8#0```0$``-P-```!`0``X`T```$!``#D#0``
+M`0$``.@-```!`0``[`T```$!``#P#0```0$``/0-```!`0``^`T```$!``#\
+M#0```0$````.```!`0``!`X```$!```(#@```0$```P.```!`0``$`X```$!
+M```4#@```0$``!@.```!`0``'`X```$!```@#@```0$``"0.```!`0``*`X`
+M``$!```L#@```0$``#`.```!`0``-`X```$!```X#@```0$``#P.```!`0``
+M0`X```$!``!$#@```0$``$@.```!`0``3`X```$!``!0#@```0$``%0.```!
+M`0``6`X```$!``!<#@```0$``&`.```!`0``9`X```$!``!H#@```0$``&P.
+M```!`0``<`X```$!``!T#@```0$``'@.```!`0``?`X```$!``"`#@```0$`
+M`(0.```!`0``B`X```$!``",#@```0$``)`.```!`0``E`X```$!``"8#@``
+M`0$``)P.```!`0``H`X```$!``"D#@```0$``*@.```!`0``K`X```$!``"P
+M#@```0$``+0.```!`0``N`X```$!``"``````08``(P````!`0``D`````$!
+M``"4`````0$``)@````!`0``G`````$!``"@`````0$``*0````!`0``J```
+M``$!``"L`````0$``+`````!`0``M`````$!``"X`````0$``+P````!`0``
+MP`````&T``#$`````0$``,@````!`0``S`````$!``#0`````0$``-0````!
+M`0``V`````$!``#<`````0$``.`````!`0``Y`````$!``#H`````0$``.P`
+M```!`0``\`````$!``#T`````0$``/@````!`0``_`````$T```$`0```0$`
+M``@!```!`0``#`$```$!```0`0```0$``!0!```!`0``&`$```&%``"``0``
+M`08``(P!```!`0``D`$```$!``"4`0```0$``)@!```!`0``G`$```$!``"@
+M`0```0$``*0!```!`0``J`$```$!``"L`0```0$``+`!```!`0``M`$```$!
+M``"X`0```0$``+P!```!`0``P`$```''``#$`0```0$``,@!```!`0``S`$`
+M``$!``#0`0```0$``-0!```!`0``V`$```$!``#<`0```0$``.`!```!`0``
+MY`$```$!``#H`0```0$``.P!```!`0``\`$```$!``#T`0```0$``/@!```!
+M`0``_`$```&2`0`$`@```0$```@"```!`0``#`(```$!```0`@```0$``!0"
+M```!`0``&`(```'-``!\`@```0$``(`"```!`0``A`(```$!``"0`@```0$`
+M`)0"```!`0``F`(```$!``#$`@```0$``,P"```!`0``V`(```$!``#@`@``
+M`0$``.P"```!`0``]`(```$!`````P```0$```@#```!`0``%`,```$!```<
+M`P```0$``"@#```!`0``,`,```$!```\`P```0$``$0#```!`0``4`,```$!
+M``!4`P```0$``%@#```!`0``9`,```$!``!H`P```0$``&P#```!`0``>`,`
+M``$!``"``P```0$``(P#```!`0``E`,```$!``"@`P```0$``*0#```!`0``
+MJ`,```$!``"T`P```0$``+@#```!`0``O`,```$!``#(`P```0$``,P#```!
+M`0``T`,```$!``#<`P```0$``.`#```!`0``Y`,```$!``#P`P```0$``/0#
+M```!`0``^`,```$!```$!````0$```P$```!`0``&`0```$!```@!````0$`
+M`"P$```!`0``-`0```$!``!`!````0$``$@$```!`0``5`0```$!``!<!```
+M`0$``&@$```!`0``<`0```$!``!\!````0$``(0$```!`0``D`0```$!``"8
+M!````0$``*0$```!`0``K`0```$!``"X!````0$``,`$```!`0``S`0```$!
+M``#0!````0$``-0$```!`0``X`0```$!``#D!````0$``.@$```!`0``]`0`
+M``$!``#\!````0$```@%```!`0``$`4```$!```<!0```0$``"0%```!`0``
+M,`4```$!```X!0```0$``$0%```!`0``3`4```$!``!8!0```0$``%P%```!
+M`0``8`4```$!``!L!0```0$``'0%```!`0``@`4```$!``"$!0```0$``(@%
+M```!`0``E`4```$!``"<!0```0$``*@%```!`0``K`4```$!``"P!0```0$`
+M`+P%```!`0``Q`4```$!``#0!0```0$``-@%```!`0``Y`4```$!``#L!0``
+M`0$``/@%```!`0````8```$!```,!@```0$``!`&```!`0``%`8```$!```@
+M!@```0$``"0&```!`0``*`8```$!```T!@```0$``#P&```!`0``2`8```$!
+M``!0!@```0$``%P&```!`0``9`8```$!``!P!@```0$``'@&```!`0``A`8`
+M``$!``",!@```0$``)@&```!`0``H`8```$!``"L!@```0$``+0&```!`0``
+MP`8```$!``#(!@```0$``-0&```!`0``W`8```$!``#H!@```0$``/`&```!
+M`0``_`8```$!````!P```0$```0'```!`0``$`<```$!```8!P```0$``"0'
+M```!`0``+`<```$!```X!P```0$``$`'```!`0``3`<```$!``!4!P```0$`
+M`&`'```!`0``9`<```$!``!H!P```0$``'0'```!`0``>`<```$!``!\!P``
+$`0$`````
`
end
diff --git a/sys/dev/hptnr/ldm.h b/sys/dev/hptnr/ldm.h
index 9a0ee65..f5c6834 100644
--- a/sys/dev/hptnr/ldm.h
+++ b/sys/dev/hptnr/ldm.h
@@ -243,6 +243,7 @@ typedef struct hpt_raw_disk
#endif
__HPT_RAW_LBA real_capacity;
__HPT_RAW_LBA head_position;
+ HPT_U32 logical_sector_size;
HPT_U16 max_sectors_per_cmd;
HPT_U8 max_queue_depth;
diff --git a/sys/dev/hptnr/os_bsd.h b/sys/dev/hptnr/os_bsd.h
index b568eb1..5b41a76 100644
--- a/sys/dev/hptnr/os_bsd.h
+++ b/sys/dev/hptnr/os_bsd.h
@@ -191,7 +191,7 @@ VBUS_EXT, *PVBUS_EXT;
#define hpt_assert_vbus_locked(vbus_ext) mtx_assert(&(vbus_ext)->lock, MA_OWNED)
-#define HPT_OSM_TIMEOUT (20*hz) /* timeout value for OS commands */
+#define HPT_OSM_TIMEOUT (120*hz) /* timeout value for OS commands */
#define HPT_DO_IOCONTROL _IOW('H', 0, HPT_IOCTL_PARAM)
diff --git a/sys/dev/hwpmc/hwpmc_core.c b/sys/dev/hwpmc/hwpmc_core.c
index 67269af..f50dfb6c 100644
--- a/sys/dev/hwpmc/hwpmc_core.c
+++ b/sys/dev/hwpmc/hwpmc_core.c
@@ -410,7 +410,7 @@ iaf_start_pmc(int cpu, int ri)
iafc->pc_resync = 0;
iafc->pc_globalctrl |= (1ULL << (ri + IAF_OFFSET));
msr = rdmsr(IA_GLOBAL_CTRL) & ~IAF_GLOBAL_CTRL_MASK;
- wrmsr(IA_GLOBAL_CTRL, msr | (iafc->pc_globalctrl &
+ wrmsr(IA_GLOBAL_CTRL, msr | (iafc->pc_globalctrl &
IAF_GLOBAL_CTRL_MASK));
} while (iafc->pc_resync != 0);
@@ -487,7 +487,7 @@ iaf_write_pmc(int cpu, int ri, pmc_value_t v)
/* Turn off fixed counters */
msr = rdmsr(IAF_CTRL) & ~IAF_CTRL_MASK;
- wrmsr(IAF_CTRL, msr);
+ wrmsr(IAF_CTRL, msr);
wrmsr(IAF_CTR0 + ri, v & ((1ULL << core_iaf_width) - 1));
@@ -574,7 +574,8 @@ struct iap_event_descr {
#define IAP_F_HW (1 << 10) /* CPU: Haswell */
#define IAP_F_CAS (1 << 11) /* CPU: Atom Silvermont */
#define IAP_F_HWX (1 << 12) /* CPU: Haswell Xeon */
-#define IAP_F_FM (1 << 13) /* Fixed mask */
+#define IAP_F_BW (1 << 13) /* CPU: Broadwell */
+#define IAP_F_FM (1 << 14) /* Fixed mask */
#define IAP_F_ALLCPUSCORE2 \
(IAP_F_CC | IAP_F_CC2 | IAP_F_CC2E | IAP_F_CA)
@@ -704,7 +705,7 @@ static struct iap_event_descr iap_events[] = {
IAPDESCR(0CH_02H, 0x0C, 0x02, IAP_F_FM | IAP_F_CC2),
IAPDESCR(0CH_03H, 0x0C, 0x03, IAP_F_FM | IAP_F_CA),
- IAPDESCR(0DH_03H, 0x0D, 0x03, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_HW |
+ IAPDESCR(0DH_03H, 0x0D, 0x03, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_HW |
IAP_F_IB | IAP_F_IBX | IAP_F_HWX),
IAPDESCR(0DH_40H, 0x0D, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_SBX),
@@ -1316,7 +1317,7 @@ static struct iap_event_descr iap_events[] = {
IAPDESCR(A6H_01H, 0xA6, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM),
IAPDESCR(A7H_01H, 0xA7, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM),
- IAPDESCR(A8H_01H, 0xA8, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IBX |
+ IAPDESCR(A8H_01H, 0xA8, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IBX |
IAP_F_IB |IAP_F_SB | IAP_F_SBX | IAP_F_HW | IAP_F_HWX),
IAPDESCR(AAH_01H, 0xAA, 0x01, IAP_F_FM | IAP_F_CC2),
@@ -1466,7 +1467,7 @@ static struct iap_event_descr iap_events[] = {
IAPDESCR(C3H_01H, 0xC3, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 |
IAP_F_I7 | IAP_F_WM | IAP_F_CAS),
IAPDESCR(C3H_02H, 0xC3, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM |
- IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW |
+ IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW |
IAP_F_CAS | IAP_F_HWX),
IAPDESCR(C3H_04H, 0xC3, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 |
IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX |
@@ -1623,10 +1624,10 @@ static struct iap_event_descr iap_events[] = {
IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX),
IAPDESCR(D1H_04H, 0xD1, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM |
IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX),
- IAPDESCR(D1H_08H, 0xD1, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IB |
+ IAPDESCR(D1H_08H, 0xD1, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IB |
IAP_F_IBX | IAP_F_HW | IAP_F_HWX),
IAPDESCR(D1H_10H, 0xD1, 0x10, IAP_F_HW | IAP_F_IB | IAP_F_IBX | IAP_F_HWX),
- IAPDESCR(D1H_20H, 0xD1, 0x20, IAP_F_FM | IAP_F_SBX | IAP_F_IBX | IAP_F_IB |
+ IAPDESCR(D1H_20H, 0xD1, 0x20, IAP_F_FM | IAP_F_SBX | IAP_F_IBX | IAP_F_IB |
IAP_F_HW | IAP_F_HWX),
IAPDESCR(D1H_40H, 0xD1, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_IB |
IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX),
@@ -1716,7 +1717,7 @@ static struct iap_event_descr iap_events[] = {
IAPDESCR(E6H_02H, 0xE6, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM),
IAPDESCR(E6H_08H, 0xE6, 0x08, IAP_F_CAS),
IAPDESCR(E6H_10H, 0xE6, 0x10, IAP_F_CAS),
- IAPDESCR(E6H_1FH, 0xE6, 0x1F, IAP_F_FM | IAP_F_IB |
+ IAPDESCR(E6H_1FH, 0xE6, 0x1F, IAP_F_FM | IAP_F_IB |
IAP_F_IBX | IAP_F_HW | IAP_F_HWX),
IAPDESCR(E7H_01H, 0xE7, 0x01, IAP_F_CAS),
@@ -1876,7 +1877,7 @@ iap_is_event_architectural(enum pmc_event pe, enum pmc_event *map)
return (EV_IS_NOTARCH);
}
- return (((core_architectural_events & (1 << ae)) == 0) ?
+ return (((core_architectural_events & (1 << ae)) == 0) ?
EV_IS_ARCH_NOTSUPP : EV_IS_ARCH_SUPP);
}
@@ -2074,6 +2075,7 @@ iap_allocate_pmc(int cpu, int ri, struct pmc *pm,
if (iap_event_corei7_ok_on_counter(ev, ri) == 0)
return (EINVAL);
break;
+ case PMC_CPU_INTEL_BROADWELL:
case PMC_CPU_INTEL_SANDYBRIDGE:
case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
case PMC_CPU_INTEL_IVYBRIDGE:
@@ -2106,6 +2108,9 @@ iap_allocate_pmc(int cpu, int ri, struct pmc *pm,
case PMC_CPU_INTEL_ATOM_SILVERMONT:
cpuflag = IAP_F_CAS;
break;
+ case PMC_CPU_INTEL_BROADWELL:
+ cpuflag = IAP_F_BW;
+ break;
case PMC_CPU_INTEL_CORE:
cpuflag = IAP_F_CC;
break;
diff --git a/sys/dev/hwpmc/hwpmc_e500.c b/sys/dev/hwpmc/hwpmc_e500.c
new file mode 100644
index 0000000..d81b333
--- /dev/null
+++ b/sys/dev/hwpmc/hwpmc_e500.c
@@ -0,0 +1,660 @@
+/*-
+ * Copyright (c) 2015 Justin Hibbits
+ * Copyright (c) 2005, Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+#include <sys/systm.h>
+
+#include <machine/pmc_mdep.h>
+#include <machine/cpu.h>
+
+#include <ddb/ddb.h>
+
+#include "hwpmc_powerpc.h"
+
+#define POWERPC_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | \
+ PMC_CAP_SYSTEM | PMC_CAP_EDGE | \
+ PMC_CAP_THRESHOLD | PMC_CAP_READ | \
+ PMC_CAP_WRITE | PMC_CAP_INVERT | \
+ PMC_CAP_QUALIFIER)
+
+#define E500_PMC_HAS_OVERFLOWED(x) (e500_pmcn_read(x) & (0x1 << 31))
+
+struct e500_event_code_map {
+ enum pmc_event pe_ev; /* enum value */
+ uint8_t pe_counter_mask; /* Which counter this can be counted in. */
+ uint8_t pe_code; /* numeric code */
+ uint8_t pe_cpu; /* e500 core (v1,v2,mc), mask */
+};
+
+#define E500_MAX_PMCS 4
+#define PMC_PPC_MASK0 0
+#define PMC_PPC_MASK1 1
+#define PMC_PPC_MASK2 2
+#define PMC_PPC_MASK3 3
+#define PMC_PPC_MASK_ALL 0x0f
+#define PMC_PPC_E500V1 1
+#define PMC_PPC_E500V2 2
+#define PMC_PPC_E500MC 4
+#define PMC_PPC_E500_ANY 7
+#define PMC_E500_EVENT(id, mask, number, core) \
+ [PMC_EV_E500_##id - PMC_EV_E500_FIRST] = \
+ { .pe_ev = PMC_EV_E500_##id, .pe_counter_mask = mask, \
+ .pe_code = number, .pe_cpu = core }
+#define PMC_E500MC_ONLY(id, number) \
+ PMC_E500_EVENT(id, PMC_PPC_MASK_ALL, number, PMC_PPC_E500MC)
+#define PMC_E500_COMMON(id, number) \
+ PMC_E500_EVENT(id, PMC_PPC_MASK_ALL, number, PMC_PPC_E500_ANY)
+
+static struct e500_event_code_map e500_event_codes[] = {
+ PMC_E500_COMMON(CYCLES, 1),
+ PMC_E500_COMMON(INSTR_COMPLETED, 2),
+ PMC_E500_COMMON(UOPS_COMPLETED, 3),
+ PMC_E500_COMMON(INSTR_FETCHED, 4),
+ PMC_E500_COMMON(UOPS_DECODED, 5),
+ PMC_E500_COMMON(PM_EVENT_TRANSITIONS, 6),
+ PMC_E500_COMMON(PM_EVENT_CYCLES, 7),
+ PMC_E500_COMMON(BRANCH_INSTRS_COMPLETED, 8),
+ PMC_E500_COMMON(LOAD_UOPS_COMPLETED, 9),
+ PMC_E500_COMMON(STORE_UOPS_COMPLETED, 10),
+ PMC_E500_COMMON(CQ_REDIRECTS, 11),
+ PMC_E500_COMMON(BRANCHES_FINISHED, 12),
+ PMC_E500_COMMON(TAKEN_BRANCHES_FINISHED, 13),
+ PMC_E500_COMMON(FINISHED_UNCOND_BRANCHES_MISS_BTB, 14),
+ PMC_E500_COMMON(BRANCH_MISPRED, 15),
+ PMC_E500_COMMON(BTB_BRANCH_MISPRED_FROM_DIRECTION, 16),
+ PMC_E500_COMMON(BTB_HITS_PSEUDO_HITS, 17),
+ PMC_E500_COMMON(CYCLES_DECODE_STALLED, 18),
+ PMC_E500_COMMON(CYCLES_ISSUE_STALLED, 19),
+ PMC_E500_COMMON(CYCLES_BRANCH_ISSUE_STALLED, 20),
+ PMC_E500_COMMON(CYCLES_SU1_SCHED_STALLED, 21),
+ PMC_E500_COMMON(CYCLES_SU2_SCHED_STALLED, 22),
+ PMC_E500_COMMON(CYCLES_MU_SCHED_STALLED, 23),
+ PMC_E500_COMMON(CYCLES_LRU_SCHED_STALLED, 24),
+ PMC_E500_COMMON(CYCLES_BU_SCHED_STALLED, 25),
+ PMC_E500_COMMON(TOTAL_TRANSLATED, 26),
+ PMC_E500_COMMON(LOADS_TRANSLATED, 27),
+ PMC_E500_COMMON(STORES_TRANSLATED, 28),
+ PMC_E500_COMMON(TOUCHES_TRANSLATED, 29),
+ PMC_E500_COMMON(CACHEOPS_TRANSLATED, 30),
+ PMC_E500_COMMON(CACHE_INHIBITED_ACCESS_TRANSLATED, 31),
+ PMC_E500_COMMON(GUARDED_LOADS_TRANSLATED, 32),
+ PMC_E500_COMMON(WRITE_THROUGH_STORES_TRANSLATED, 33),
+ PMC_E500_COMMON(MISALIGNED_LOAD_STORE_ACCESS_TRANSLATED, 34),
+ PMC_E500_COMMON(TOTAL_ALLOCATED_TO_DLFB, 35),
+ PMC_E500_COMMON(LOADS_TRANSLATED_ALLOCATED_TO_DLFB, 36),
+ PMC_E500_COMMON(STORES_COMPLETED_ALLOCATED_TO_DLFB, 37),
+ PMC_E500_COMMON(TOUCHES_TRANSLATED_ALLOCATED_TO_DLFB, 38),
+ PMC_E500_COMMON(STORES_COMPLETED, 39),
+ PMC_E500_COMMON(DATA_L1_CACHE_LOCKS, 40),
+ PMC_E500_COMMON(DATA_L1_CACHE_RELOADS, 41),
+ PMC_E500_COMMON(DATA_L1_CACHE_CASTOUTS, 42),
+ PMC_E500_COMMON(LOAD_MISS_DLFB_FULL, 43),
+ PMC_E500_COMMON(LOAD_MISS_LDQ_FULL, 44),
+ PMC_E500_COMMON(LOAD_GUARDED_MISS, 45),
+ PMC_E500_COMMON(STORE_TRANSLATE_WHEN_QUEUE_FULL, 46),
+ PMC_E500_COMMON(ADDRESS_COLLISION, 47),
+ PMC_E500_COMMON(DATA_MMU_MISS, 48),
+ PMC_E500_COMMON(DATA_MMU_BUSY, 49),
+ PMC_E500_COMMON(PART2_MISALIGNED_CACHE_ACCESS, 50),
+ PMC_E500_COMMON(LOAD_MISS_DLFB_FULL_CYCLES, 51),
+ PMC_E500_COMMON(LOAD_MISS_LDQ_FULL_CYCLES, 52),
+ PMC_E500_COMMON(LOAD_GUARDED_MISS_CYCLES, 53),
+ PMC_E500_COMMON(STORE_TRANSLATE_WHEN_QUEUE_FULL_CYCLES, 54),
+ PMC_E500_COMMON(ADDRESS_COLLISION_CYCLES, 55),
+ PMC_E500_COMMON(DATA_MMU_MISS_CYCLES, 56),
+ PMC_E500_COMMON(DATA_MMU_BUSY_CYCLES, 57),
+ PMC_E500_COMMON(PART2_MISALIGNED_CACHE_ACCESS_CYCLES, 58),
+ PMC_E500_COMMON(INSTR_L1_CACHE_LOCKS, 59),
+ PMC_E500_COMMON(INSTR_L1_CACHE_RELOADS, 60),
+ PMC_E500_COMMON(INSTR_L1_CACHE_FETCHES, 61),
+ PMC_E500_COMMON(INSTR_MMU_TLB4K_RELOADS, 62),
+ PMC_E500_COMMON(INSTR_MMU_VSP_RELOADS, 63),
+ PMC_E500_COMMON(DATA_MMU_TLB4K_RELOADS, 64),
+ PMC_E500_COMMON(DATA_MMU_VSP_RELOADS, 65),
+ PMC_E500_COMMON(L2MMU_MISSES, 66),
+ PMC_E500_COMMON(BIU_MASTER_REQUESTS, 67),
+ PMC_E500_COMMON(BIU_MASTER_INSTR_SIDE_REQUESTS, 68),
+ PMC_E500_COMMON(BIU_MASTER_DATA_SIDE_REQUESTS, 69),
+ PMC_E500_COMMON(BIU_MASTER_DATA_SIDE_CASTOUT_REQUESTS, 70),
+ PMC_E500_COMMON(BIU_MASTER_RETRIES, 71),
+ PMC_E500_COMMON(SNOOP_REQUESTS, 72),
+ PMC_E500_COMMON(SNOOP_HITS, 73),
+ PMC_E500_COMMON(SNOOP_PUSHES, 74),
+ PMC_E500_COMMON(SNOOP_RETRIES, 75),
+ PMC_E500_EVENT(DLFB_LOAD_MISS_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
+ 76, PMC_PPC_E500_ANY),
+ PMC_E500_EVENT(ILFB_FETCH_MISS_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
+ 77, PMC_PPC_E500_ANY),
+ PMC_E500_EVENT(EXT_INPU_INTR_LATENCY_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
+ 78, PMC_PPC_E500_ANY),
+ PMC_E500_EVENT(CRIT_INPUT_INTR_LATENCY_CYCLES, PMC_PPC_MASK0|PMC_PPC_MASK1,
+ 79, PMC_PPC_E500_ANY),
+ PMC_E500_EVENT(EXT_INPUT_INTR_PENDING_LATENCY_CYCLES,
+ PMC_PPC_MASK0|PMC_PPC_MASK1, 80, PMC_PPC_E500_ANY),
+ PMC_E500_EVENT(CRIT_INPUT_INTR_PENDING_LATENCY_CYCLES,
+ PMC_PPC_MASK0|PMC_PPC_MASK1, 81, PMC_PPC_E500_ANY),
+ PMC_E500_COMMON(PMC0_OVERFLOW, 82),
+ PMC_E500_COMMON(PMC1_OVERFLOW, 83),
+ PMC_E500_COMMON(PMC2_OVERFLOW, 84),
+ PMC_E500_COMMON(PMC3_OVERFLOW, 85),
+ PMC_E500_COMMON(INTERRUPTS_TAKEN, 86),
+ PMC_E500_COMMON(EXT_INPUT_INTR_TAKEN, 87),
+ PMC_E500_COMMON(CRIT_INPUT_INTR_TAKEN, 88),
+ PMC_E500_COMMON(SYSCALL_TRAP_INTR, 89),
+ PMC_E500_EVENT(TLB_BIT_TRANSITIONS, PMC_PPC_MASK_ALL, 90,
+ PMC_PPC_E500V2 | PMC_PPC_E500MC),
+ PMC_E500MC_ONLY(L2_LINEFILL_BUFFER, 91),
+ PMC_E500MC_ONLY(LV2_VS, 92),
+ PMC_E500MC_ONLY(CASTOUTS_RELEASED, 93),
+ PMC_E500MC_ONLY(INTV_ALLOCATIONS, 94),
+ PMC_E500MC_ONLY(DLFB_RETRIES_TO_MBAR, 95),
+ PMC_E500MC_ONLY(STORE_RETRIES, 96),
+ PMC_E500MC_ONLY(STASH_L1_HITS, 97),
+ PMC_E500MC_ONLY(STASH_L2_HITS, 98),
+ PMC_E500MC_ONLY(STASH_BUSY_1, 99),
+ PMC_E500MC_ONLY(STASH_BUSY_2, 100),
+ PMC_E500MC_ONLY(STASH_BUSY_3, 101),
+ PMC_E500MC_ONLY(STASH_HITS, 102),
+ PMC_E500MC_ONLY(STASH_HIT_DLFB, 103),
+ PMC_E500MC_ONLY(STASH_REQUESTS, 106),
+ PMC_E500MC_ONLY(STASH_REQUESTS_L1, 107),
+ PMC_E500MC_ONLY(STASH_REQUESTS_L2, 108),
+ PMC_E500MC_ONLY(STALLS_NO_CAQ_OR_COB, 109),
+ PMC_E500MC_ONLY(L2_CACHE_ACCESSES, 110),
+ PMC_E500MC_ONLY(L2_HIT_CACHE_ACCESSES, 111),
+ PMC_E500MC_ONLY(L2_CACHE_DATA_ACCESSES, 112),
+ PMC_E500MC_ONLY(L2_CACHE_DATA_HITS, 113),
+ PMC_E500MC_ONLY(L2_CACHE_INSTR_ACCESSES, 114),
+ PMC_E500MC_ONLY(L2_CACHE_INSTR_HITS, 115),
+ PMC_E500MC_ONLY(L2_CACHE_ALLOCATIONS, 116),
+ PMC_E500MC_ONLY(L2_CACHE_DATA_ALLOCATIONS, 117),
+ PMC_E500MC_ONLY(L2_CACHE_DIRTY_DATA_ALLOCATIONS, 118),
+ PMC_E500MC_ONLY(L2_CACHE_INSTR_ALLOCATIONS, 119),
+ PMC_E500MC_ONLY(L2_CACHE_UPDATES, 120),
+ PMC_E500MC_ONLY(L2_CACHE_CLEAN_UPDATES, 121),
+ PMC_E500MC_ONLY(L2_CACHE_DIRTY_UPDATES, 122),
+ PMC_E500MC_ONLY(L2_CACHE_CLEAN_REDUNDANT_UPDATES, 123),
+ PMC_E500MC_ONLY(L2_CACHE_DIRTY_REDUNDANT_UPDATES, 124),
+ PMC_E500MC_ONLY(L2_CACHE_LOCKS, 125),
+ PMC_E500MC_ONLY(L2_CACHE_CASTOUTS, 126),
+ PMC_E500MC_ONLY(L2_CACHE_DATA_DIRTY_HITS, 127),
+ PMC_E500MC_ONLY(INSTR_LFB_WENT_HIGH_PRIORITY, 128),
+ PMC_E500MC_ONLY(SNOOP_THROTTLING_TURNED_ON, 129),
+ PMC_E500MC_ONLY(L2_CLEAN_LINE_INVALIDATIONS, 130),
+ PMC_E500MC_ONLY(L2_INCOHERENT_LINE_INVALIDATIONS, 131),
+ PMC_E500MC_ONLY(L2_COHERENT_LINE_INVALIDATIONS, 132),
+ PMC_E500MC_ONLY(COHERENT_LOOKUP_MISS_DUE_TO_VALID_BUT_INCOHERENT_MATCHES, 133),
+ PMC_E500MC_ONLY(IAC1S_DETECTED, 140),
+ PMC_E500MC_ONLY(IAC2S_DETECTED, 141),
+ PMC_E500MC_ONLY(DAC1S_DTECTED, 144),
+ PMC_E500MC_ONLY(DAC2S_DTECTED, 145),
+ PMC_E500MC_ONLY(DVT0_DETECTED, 148),
+ PMC_E500MC_ONLY(DVT1_DETECTED, 149),
+ PMC_E500MC_ONLY(DVT2_DETECTED, 150),
+ PMC_E500MC_ONLY(DVT3_DETECTED, 151),
+ PMC_E500MC_ONLY(DVT4_DETECTED, 152),
+ PMC_E500MC_ONLY(DVT5_DETECTED, 153),
+ PMC_E500MC_ONLY(DVT6_DETECTED, 154),
+ PMC_E500MC_ONLY(DVT7_DETECTED, 155),
+ PMC_E500MC_ONLY(CYCLES_COMPLETION_STALLED_NEXUS_FIFO_FULL, 156),
+ PMC_E500MC_ONLY(FPU_DOUBLE_PUMP, 160),
+ PMC_E500MC_ONLY(FPU_FINISH, 161),
+ PMC_E500MC_ONLY(FPU_DIVIDE_CYCLES, 162),
+ PMC_E500MC_ONLY(FPU_DENORM_INPUT_CYCLES, 163),
+ PMC_E500MC_ONLY(FPU_RESULT_STALL_CYCLES, 164),
+ PMC_E500MC_ONLY(FPU_FPSCR_FULL_STALL, 165),
+ PMC_E500MC_ONLY(FPU_PIPE_SYNC_STALLS, 166),
+ PMC_E500MC_ONLY(FPU_INPUT_DATA_STALLS, 167),
+ PMC_E500MC_ONLY(DECORATED_LOADS, 176),
+ PMC_E500MC_ONLY(DECORATED_STORES, 177),
+ PMC_E500MC_ONLY(LOAD_RETRIES, 178),
+ PMC_E500MC_ONLY(STWCX_SUCCESSES, 179),
+ PMC_E500MC_ONLY(STWCX_FAILURES, 180),
+};
+
+const size_t e500_event_codes_size =
+ sizeof(e500_event_codes) / sizeof(e500_event_codes[0]);
+
+static pmc_value_t
+e500_pmcn_read(unsigned int pmc)
+{
+ switch (pmc) {
+ case 0:
+ return mfpmr(PMR_PMC0);
+ break;
+ case 1:
+ return mfpmr(PMR_PMC1);
+ break;
+ case 2:
+ return mfpmr(PMR_PMC2);
+ break;
+ case 3:
+ return mfpmr(PMR_PMC3);
+ break;
+ default:
+ panic("Invalid PMC number: %d\n", pmc);
+ }
+}
+
+static void
+e500_pmcn_write(unsigned int pmc, uint32_t val)
+{
+ switch (pmc) {
+ case 0:
+ mtpmr(PMR_PMC0, val);
+ break;
+ case 1:
+ mtpmr(PMR_PMC1, val);
+ break;
+ case 2:
+ mtpmr(PMR_PMC2, val);
+ break;
+ case 3:
+ mtpmr(PMR_PMC3, val);
+ break;
+ default:
+ panic("Invalid PMC number: %d\n", pmc);
+ }
+}
+
+static int
+e500_read_pmc(int cpu, int ri, pmc_value_t *v)
+{
+ struct pmc *pm;
+ pmc_value_t tmp;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < E500_MAX_PMCS,
+ ("[powerpc,%d] illegal row index %d", __LINE__, ri));
+
+ pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
+ KASSERT(pm,
+ ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu,
+ ri));
+
+ tmp = e500_pmcn_read(ri);
+ PMCDBG(MDP,REA,2,"ppc-read id=%d -> %jd", ri, tmp);
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ *v = POWERPC_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
+ else
+ *v = tmp;
+
+ return 0;
+}
+
+static int
+e500_write_pmc(int cpu, int ri, pmc_value_t v)
+{
+ struct pmc *pm;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < E500_MAX_PMCS,
+ ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
+
+ pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
+
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ v = POWERPC_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
+
+ PMCDBG(MDP,WRI,1,"powerpc-write cpu=%d ri=%d v=%jx", cpu, ri, v);
+
+ e500_pmcn_write(ri, v);
+
+ return 0;
+}
+
+static int
+e500_config_pmc(int cpu, int ri, struct pmc *pm)
+{
+ struct pmc_hw *phw;
+
+ PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < E500_MAX_PMCS,
+ ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+
+ KASSERT(pm == NULL || phw->phw_pmc == NULL,
+ ("[powerpc,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
+ __LINE__, pm, phw->phw_pmc));
+
+ phw->phw_pmc = pm;
+
+ return 0;
+}
+
+static int
+e500_start_pmc(int cpu, int ri)
+{
+ uint32_t config;
+ struct pmc *pm;
+ struct pmc_hw *phw;
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+ pm = phw->phw_pmc;
+ config = pm->pm_md.pm_powerpc.pm_powerpc_evsel;
+
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ config |= PMLCax_CE;
+
+ /* Enable the PMC. */
+ switch (ri) {
+ case 0:
+ mtpmr(PMR_PMLCa0, config);
+ break;
+ case 1:
+ mtpmr(PMR_PMLCa1, config);
+ break;
+ case 2:
+ mtpmr(PMR_PMLCa2, config);
+ break;
+ case 3:
+ mtpmr(PMR_PMLCa3, config);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int
+e500_stop_pmc(int cpu, int ri)
+{
+ struct pmc *pm;
+ struct pmc_hw *phw;
+ register_t pmc_pmlc;
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+ pm = phw->phw_pmc;
+
+ /*
+ * Disable the PMCs.
+ */
+ switch (ri) {
+ case 0:
+ pmc_pmlc = mfpmr(PMR_PMLCa0);
+ pmc_pmlc |= PMLCax_FC;
+ mtpmr(PMR_PMLCa0, pmc_pmlc);
+ break;
+ case 1:
+ pmc_pmlc = mfpmr(PMR_PMLCa1);
+ pmc_pmlc |= PMLCax_FC;
+ mtpmr(PMR_PMLCa1, pmc_pmlc);
+ break;
+ case 2:
+ pmc_pmlc = mfpmr(PMR_PMLCa2);
+ pmc_pmlc |= PMLCax_FC;
+ mtpmr(PMR_PMLCa2, pmc_pmlc);
+ break;
+ case 3:
+ pmc_pmlc = mfpmr(PMR_PMLCa3);
+ pmc_pmlc |= PMLCax_FC;
+ mtpmr(PMR_PMLCa3, pmc_pmlc);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
+e500_pcpu_init(struct pmc_mdep *md, int cpu)
+{
+ int first_ri, i;
+ struct pmc_cpu *pc;
+ struct powerpc_cpu *pac;
+ struct pmc_hw *phw;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] wrong cpu number %d", __LINE__, cpu));
+ PMCDBG(MDP,INI,1,"powerpc-init cpu=%d", cpu);
+
+ /* Freeze all counters. */
+ mtpmr(PMR_PMGC0, PMGC_FAC | PMGC_PMIE | PMGC_FCECE);
+
+ powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu), M_PMC,
+ M_WAITOK|M_ZERO);
+ pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * E500_MAX_PMCS,
+ M_PMC, M_WAITOK|M_ZERO);
+ pac->pc_class = PMC_CLASS_E500;
+ pc = pmc_pcpu[cpu];
+ first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
+ KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
+
+ for (i = 0, phw = pac->pc_ppcpmcs; i < E500_MAX_PMCS; i++, phw++) {
+ phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
+ PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
+ phw->phw_pmc = NULL;
+ pc->pc_hwpmcs[i + first_ri] = phw;
+
+ /* Initialize the PMC to stopped */
+ e500_stop_pmc(cpu, i);
+ }
+ /* Unfreeze global register. */
+ mtpmr(PMR_PMGC0, PMGC_PMIE | PMGC_FCECE);
+
+ return 0;
+}
+
+static int
+e500_pcpu_fini(struct pmc_mdep *md, int cpu)
+{
+ uint32_t pmgc0 = mfpmr(PMR_PMGC0);
+
+ pmgc0 |= PMGC_FAC;
+ mtpmr(PMR_PMGC0, pmgc0);
+ mtmsr(mfmsr() & ~PSL_PMM);
+
+ free(powerpc_pcpu[cpu]->pc_ppcpmcs, M_PMC);
+ free(powerpc_pcpu[cpu], M_PMC);
+
+ return 0;
+}
+
+static int
+e500_allocate_pmc(int cpu, int ri, struct pmc *pm,
+ const struct pmc_op_pmcallocate *a)
+{
+ enum pmc_event pe;
+ uint32_t caps, config, counter;
+ struct e500_event_code_map *ev;
+ uint16_t vers;
+ uint8_t pe_cpu_mask;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < E500_MAX_PMCS,
+ ("[powerpc,%d] illegal row index %d", __LINE__, ri));
+
+ caps = a->pm_caps;
+
+ pe = a->pm_ev;
+ config = PMLCax_FCS | PMLCax_FCU |
+ PMLCax_FCM1 | PMLCax_FCM1;
+ if (pe < PMC_EV_E500_FIRST || pe > PMC_EV_E500_LAST)
+ return (EINVAL);
+
+ ev = &e500_event_codes[pe-PMC_EV_E500_FIRST];
+ if (ev->pe_code == 0)
+ return (EINVAL);
+
+ vers = mfpvr() >> 16;
+ switch (vers) {
+ case FSL_E500v1:
+ pe_cpu_mask = ev->pe_code & PMC_PPC_E500V1;
+ break;
+ case FSL_E500v2:
+ pe_cpu_mask = ev->pe_code & PMC_PPC_E500V2;
+ break;
+ case FSL_E500mc:
+ pe_cpu_mask = ev->pe_code & PMC_PPC_E500MC;
+ break;
+ }
+ if (pe_cpu_mask == 0)
+ return (EINVAL);
+
+ config |= PMLCax_EVENT(ev->pe_code);
+ counter = ev->pe_counter_mask;
+ if ((counter & (1 << ri)) == 0)
+ return (EINVAL);
+
+ if (caps & PMC_CAP_SYSTEM)
+ config &= ~PMLCax_FCS;
+ if (caps & PMC_CAP_USER)
+ config &= ~PMLCax_FCU;
+ if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
+ config &= ~(PMLCax_FCS|PMLCax_FCU);
+
+ pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
+
+ PMCDBG(MDP,ALL,2,"powerpc-allocate ri=%d -> config=0x%x", ri, config);
+
+ return 0;
+}
+
+static int
+e500_release_pmc(int cpu, int ri, struct pmc *pmc)
+{
+ struct pmc_hw *phw;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < E500_MAX_PMCS,
+ ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
+ KASSERT(phw->phw_pmc == NULL,
+ ("[powerpc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
+
+ return 0;
+}
+
+static int
+e500_intr(int cpu, struct trapframe *tf)
+{
+ int i, error, retval;
+ uint32_t config;
+ struct pmc *pm;
+ struct powerpc_cpu *pac;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[powerpc,%d] out of range CPU %d", __LINE__, cpu));
+
+ PMCDBG(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf,
+ TRAPF_USERMODE(tf));
+
+ retval = 0;
+
+ pac = powerpc_pcpu[cpu];
+
+ config = mfpmr(PMR_PMGC0) & ~PMGC_FAC;
+
+ /*
+ * look for all PMCs that have interrupted:
+ * - look for a running, sampling PMC which has overflowed
+ * and which has a valid 'struct pmc' association
+ *
+ * If found, we call a helper to process the interrupt.
+ */
+
+ for (i = 0; i < E500_MAX_PMCS; i++) {
+ if ((pm = pac->pc_ppcpmcs[i].phw_pmc) == NULL ||
+ !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
+ continue;
+ }
+
+ if (!E500_PMC_HAS_OVERFLOWED(i))
+ continue;
+
+ retval = 1; /* Found an interrupting PMC. */
+
+ if (pm->pm_state != PMC_STATE_RUNNING)
+ continue;
+
+ /* Stop the counter if logging fails. */
+ error = pmc_process_interrupt(cpu, PMC_HR, pm, tf,
+ TRAPF_USERMODE(tf));
+ if (error != 0)
+ e500_stop_pmc(cpu, i);
+
+ /* reload count. */
+ e500_write_pmc(cpu, i, pm->pm_sc.pm_reloadcount);
+ }
+
+ atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
+ &pmc_stats.pm_intr_ignored, 1);
+
+ /* Re-enable PERF exceptions. */
+ if (retval)
+ mtpmr(PMR_PMGC0, config | PMGC_PMIE);
+
+ return (retval);
+}
+
+int
+pmc_e500_initialize(struct pmc_mdep *pmc_mdep)
+{
+ struct pmc_classdep *pcd;
+
+ pmc_mdep->pmd_cputype = PMC_CPU_PPC_E500;
+
+ pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
+ pcd->pcd_caps = POWERPC_PMC_CAPS;
+ pcd->pcd_class = PMC_CLASS_E500;
+ pcd->pcd_num = E500_MAX_PMCS;
+ pcd->pcd_ri = pmc_mdep->pmd_npmc;
+ pcd->pcd_width = 32;
+
+ pcd->pcd_allocate_pmc = e500_allocate_pmc;
+ pcd->pcd_config_pmc = e500_config_pmc;
+ pcd->pcd_pcpu_fini = e500_pcpu_fini;
+ pcd->pcd_pcpu_init = e500_pcpu_init;
+ pcd->pcd_describe = powerpc_describe;
+ pcd->pcd_get_config = powerpc_get_config;
+ pcd->pcd_read_pmc = e500_read_pmc;
+ pcd->pcd_release_pmc = e500_release_pmc;
+ pcd->pcd_start_pmc = e500_start_pmc;
+ pcd->pcd_stop_pmc = e500_stop_pmc;
+ pcd->pcd_write_pmc = e500_write_pmc;
+
+ pmc_mdep->pmd_npmc += E500_MAX_PMCS;
+ pmc_mdep->pmd_intr = e500_intr;
+
+ return (0);
+}
diff --git a/sys/dev/hwpmc/hwpmc_intel.c b/sys/dev/hwpmc/hwpmc_intel.c
index 05880c9..486dfa0 100644
--- a/sys/dev/hwpmc/hwpmc_intel.c
+++ b/sys/dev/hwpmc/hwpmc_intel.c
@@ -179,6 +179,10 @@ pmc_intel_initialize(void)
cputype = PMC_CPU_INTEL_IVYBRIDGE_XEON;
nclasses = 3;
break;
+ case 0x3D:
+ cputype = PMC_CPU_INTEL_BROADWELL;
+ nclasses = 3;
+ break;
case 0x3F: /* Per Intel document 325462-045US 09/2014. */
case 0x46: /* Per Intel document 325462-045US 09/2014. */
/* Should 46 be XEON. probably its own? */
@@ -227,6 +231,7 @@ pmc_intel_initialize(void)
*/
case PMC_CPU_INTEL_ATOM:
case PMC_CPU_INTEL_ATOM_SILVERMONT:
+ case PMC_CPU_INTEL_BROADWELL:
case PMC_CPU_INTEL_CORE:
case PMC_CPU_INTEL_CORE2:
case PMC_CPU_INTEL_CORE2EXTREME:
@@ -295,6 +300,7 @@ pmc_intel_initialize(void)
case PMC_CPU_INTEL_HASWELL:
case PMC_CPU_INTEL_SANDYBRIDGE:
case PMC_CPU_INTEL_WESTMERE:
+ case PMC_CPU_INTEL_BROADWELL:
error = pmc_uncore_initialize(pmc_mdep, ncpus);
break;
default:
@@ -319,6 +325,7 @@ pmc_intel_finalize(struct pmc_mdep *md)
#if defined(__i386__) || defined(__amd64__)
case PMC_CPU_INTEL_ATOM:
case PMC_CPU_INTEL_ATOM_SILVERMONT:
+ case PMC_CPU_INTEL_BROADWELL:
case PMC_CPU_INTEL_CORE:
case PMC_CPU_INTEL_CORE2:
case PMC_CPU_INTEL_CORE2EXTREME:
@@ -360,6 +367,7 @@ pmc_intel_finalize(struct pmc_mdep *md)
*/
#if defined(__i386__) || defined(__amd64__)
switch (md->pmd_cputype) {
+ case PMC_CPU_INTEL_BROADWELL:
case PMC_CPU_INTEL_COREI7:
case PMC_CPU_INTEL_HASWELL:
case PMC_CPU_INTEL_SANDYBRIDGE:
diff --git a/sys/dev/hwpmc/hwpmc_mips74k.c b/sys/dev/hwpmc/hwpmc_mips74k.c
new file mode 100644
index 0000000..3a5ff33
--- /dev/null
+++ b/sys/dev/hwpmc/hwpmc_mips74k.c
@@ -0,0 +1,261 @@
+/*-
+ * Copyright (c) 2010 George V. Neville-Neil <gnn@freebsd.org>
+ * Copyright (c) 2015 Adrian Chadd <adrian@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/pmc_mdep.h>
+
+#define MIPS74K_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | \
+ PMC_CAP_SYSTEM | PMC_CAP_EDGE | \
+ PMC_CAP_THRESHOLD | PMC_CAP_READ | \
+ PMC_CAP_WRITE | PMC_CAP_INVERT | \
+ PMC_CAP_QUALIFIER)
+
+/* 0x1 - Exception_enable */
+#define MIPS74K_PMC_INTERRUPT_ENABLE 0x10 /* Enable interrupts */
+#define MIPS74K_PMC_USER_ENABLE 0x08 /* Count in USER mode */
+#define MIPS74K_PMC_SUPER_ENABLE 0x04 /* Count in SUPERVISOR mode */
+#define MIPS74K_PMC_KERNEL_ENABLE 0x02 /* Count in KERNEL mode */
+#define MIPS74K_PMC_ENABLE (MIPS74K_PMC_USER_ENABLE | \
+ MIPS74K_PMC_SUPER_ENABLE | \
+ MIPS74K_PMC_KERNEL_ENABLE)
+
+#define MIPS74K_PMC_SELECT 5 /* Which bit position the event starts at. */
+
+const struct mips_event_code_map mips_event_codes[] = {
+ { PMC_EV_MIPS74K_CYCLES, MIPS_CTR_ALL, 0 },
+ { PMC_EV_MIPS74K_INSTR_EXECUTED, MIPS_CTR_ALL, 1 },
+ { PMC_EV_MIPS74K_PREDICTED_JR_31, MIPS_CTR_0, 2 },
+ { PMC_EV_MIPS74K_JR_31_MISPREDICTIONS, MIPS_CTR_1, 2 },
+ { PMC_EV_MIPS74K_REDIRECT_STALLS, MIPS_CTR_0, 3 },
+ { PMC_EV_MIPS74K_JR_31_NO_PREDICTIONS, MIPS_CTR_1, 3 },
+ { PMC_EV_MIPS74K_ITLB_ACCESSES, MIPS_CTR_0, 4 },
+ { PMC_EV_MIPS74K_ITLB_MISSES, MIPS_CTR_1, 4 },
+ { PMC_EV_MIPS74K_JTLB_INSN_MISSES, MIPS_CTR_1, 5 },
+ { PMC_EV_MIPS74K_ICACHE_ACCESSES, MIPS_CTR_0, 6 },
+ { PMC_EV_MIPS74K_ICACHE_MISSES, MIPS_CTR_1, 6 },
+ { PMC_EV_MIPS74K_ICACHE_MISS_STALLS, MIPS_CTR_0, 7 },
+ { PMC_EV_MIPS74K_UNCACHED_IFETCH_STALLS, MIPS_CTR_0, 8 },
+ { PMC_EV_MIPS74K_PDTRACE_BACK_STALLS, MIPS_CTR_1, 8 },
+ { PMC_EV_MIPS74K_IFU_REPLAYS, MIPS_CTR_0, 9 },
+ { PMC_EV_MIPS74K_KILLED_FETCH_SLOTS, MIPS_CTR_1, 9 },
+ { PMC_EV_MIPS74K_IFU_IDU_MISS_PRED_UPSTREAM_CYCLES, MIPS_CTR_0, 11 },
+ { PMC_EV_MIPS74K_IFU_IDU_NO_FETCH_CYCLES, MIPS_CTR_1, 11 },
+ { PMC_EV_MIPS74K_IFU_IDU_CLOGED_DOWNSTREAM_CYCLES, MIPS_CTR_0, 12 },
+ { PMC_EV_MIPS74K_DDQ0_FULL_DR_STALLS, MIPS_CTR_0, 13 },
+ { PMC_EV_MIPS74K_DDQ1_FULL_DR_STALLS, MIPS_CTR_1, 13 },
+ { PMC_EV_MIPS74K_ALCB_FULL_DR_STALLS, MIPS_CTR_0, 14 },
+ { PMC_EV_MIPS74K_AGCB_FULL_DR_STALLS, MIPS_CTR_1, 14 },
+ { PMC_EV_MIPS74K_CLDQ_FULL_DR_STALLS, MIPS_CTR_0, 15 },
+ { PMC_EV_MIPS74K_IODQ_FULL_DR_STALLS, MIPS_CTR_1, 15 },
+ { PMC_EV_MIPS74K_ALU_EMPTY_CYCLES, MIPS_CTR_0, 16 },
+ { PMC_EV_MIPS74K_AGEN_EMPTY_CYCLES, MIPS_CTR_1, 16 },
+ { PMC_EV_MIPS74K_ALU_OPERANDS_NOT_READY_CYCLES, MIPS_CTR_0, 17 },
+ { PMC_EV_MIPS74K_AGEN_OPERANDS_NOT_READY_CYCLES, MIPS_CTR_1, 17 },
+ { PMC_EV_MIPS74K_ALU_NO_ISSUES_CYCLES, MIPS_CTR_0, 18 },
+ { PMC_EV_MIPS74K_AGEN_NO_ISSUES_CYCLES, MIPS_CTR_1, 18 },
+ { PMC_EV_MIPS74K_ALU_BUBBLE_CYCLES, MIPS_CTR_0, 19 },
+ { PMC_EV_MIPS74K_AGEN_BUBBLE_CYCLES, MIPS_CTR_1, 19 },
+ { PMC_EV_MIPS74K_SINGLE_ISSUE_CYCLES, MIPS_CTR_0, 20 },
+ { PMC_EV_MIPS74K_DUAL_ISSUE_CYCLES, MIPS_CTR_1, 20 },
+ { PMC_EV_MIPS74K_OOO_ALU_ISSUE_CYCLES, MIPS_CTR_0, 21 },
+ { PMC_EV_MIPS74K_OOO_AGEN_ISSUE_CYCLES, MIPS_CTR_1, 21 },
+ { PMC_EV_MIPS74K_JALR_JALR_HB_INSNS, MIPS_CTR_0, 22 },
+ { PMC_EV_MIPS74K_DCACHE_LINE_REFILL_REQUESTS, MIPS_CTR_1, 22 },
+ { PMC_EV_MIPS74K_DCACHE_LOAD_ACCESSES, MIPS_CTR_0, 23 },
+ { PMC_EV_MIPS74K_DCACHE_ACCESSES, MIPS_CTR_1, 23 },
+ { PMC_EV_MIPS74K_DCACHE_WRITEBACKS, MIPS_CTR_0, 24 },
+ { PMC_EV_MIPS74K_DCACHE_MISSES, MIPS_CTR_1, 24 },
+ { PMC_EV_MIPS74K_JTLB_DATA_ACCESSES, MIPS_CTR_0, 25 },
+ { PMC_EV_MIPS74K_JTLB_DATA_MISSES, MIPS_CTR_1, 25 },
+ { PMC_EV_MIPS74K_LOAD_STORE_REPLAYS, MIPS_CTR_0, 26 },
+ { PMC_EV_MIPS74K_VA_TRANSALTION_CORNER_CASES, MIPS_CTR_1, 26 },
+ { PMC_EV_MIPS74K_LOAD_STORE_BLOCKED_CYCLES, MIPS_CTR_0, 27 },
+ { PMC_EV_MIPS74K_LOAD_STORE_NO_FILL_REQUESTS, MIPS_CTR_1, 27 },
+ { PMC_EV_MIPS74K_L2_CACHE_WRITEBACKS, MIPS_CTR_0, 28 },
+ { PMC_EV_MIPS74K_L2_CACHE_ACCESSES, MIPS_CTR_1, 28 },
+ { PMC_EV_MIPS74K_L2_CACHE_MISSES, MIPS_CTR_0, 29 },
+ { PMC_EV_MIPS74K_L2_CACHE_MISS_CYCLES, MIPS_CTR_1, 29 },
+ { PMC_EV_MIPS74K_FSB_FULL_STALLS, MIPS_CTR_0, 30 },
+ { PMC_EV_MIPS74K_FSB_OVER_50_FULL, MIPS_CTR_1, 30 },
+ { PMC_EV_MIPS74K_LDQ_FULL_STALLS, MIPS_CTR_0, 31 },
+ { PMC_EV_MIPS74K_LDQ_OVER_50_FULL, MIPS_CTR_1, 31 },
+ { PMC_EV_MIPS74K_WBB_FULL_STALLS, MIPS_CTR_0, 32 },
+ { PMC_EV_MIPS74K_WBB_OVER_50_FULL, MIPS_CTR_1, 32 },
+ { PMC_EV_MIPS74K_LOAD_MISS_CONSUMER_REPLAYS, MIPS_CTR_0, 35 },
+ { PMC_EV_MIPS74K_CP1_CP2_LOAD_INSNS, MIPS_CTR_1, 35 },
+ { PMC_EV_MIPS74K_JR_NON_31_INSNS, MIPS_CTR_0, 36 },
+ { PMC_EV_MIPS74K_MISPREDICTED_JR_31_INSNS, MIPS_CTR_1, 36 },
+ { PMC_EV_MIPS74K_BRANCH_INSNS, MIPS_CTR_0, 37 },
+ { PMC_EV_MIPS74K_CP1_CP2_COND_BRANCH_INSNS, MIPS_CTR_1, 37 },
+ { PMC_EV_MIPS74K_BRANCH_LIKELY_INSNS, MIPS_CTR_0, 38 },
+ { PMC_EV_MIPS74K_MISPREDICTED_BRANCH_LIKELY_INSNS, MIPS_CTR_1, 38 },
+ { PMC_EV_MIPS74K_COND_BRANCH_INSNS, MIPS_CTR_0, 39 },
+ { PMC_EV_MIPS74K_MISPREDICTED_BRANCH_INSNS, MIPS_CTR_1, 39 },
+ { PMC_EV_MIPS74K_INTEGER_INSNS, MIPS_CTR_0, 40 },
+ { PMC_EV_MIPS74K_FPU_INSNS, MIPS_CTR_1, 40 },
+ { PMC_EV_MIPS74K_LOAD_INSNS, MIPS_CTR_0, 41 },
+ { PMC_EV_MIPS74K_STORE_INSNS, MIPS_CTR_1, 41 },
+ { PMC_EV_MIPS74K_J_JAL_INSNS, MIPS_CTR_0, 42 },
+ { PMC_EV_MIPS74K_MIPS16_INSNS, MIPS_CTR_1, 42 },
+ { PMC_EV_MIPS74K_NOP_INSNS, MIPS_CTR_0, 43 },
+ { PMC_EV_MIPS74K_NT_MUL_DIV_INSNS, MIPS_CTR_1, 43 },
+ { PMC_EV_MIPS74K_DSP_INSNS, MIPS_CTR_0, 44 },
+ { PMC_EV_MIPS74K_ALU_DSP_SATURATION_INSNS, MIPS_CTR_1, 44 },
+ { PMC_EV_MIPS74K_DSP_BRANCH_INSNS, MIPS_CTR_0, 45 },
+ { PMC_EV_MIPS74K_MDU_DSP_SATURATION_INSNS, MIPS_CTR_1, 45 },
+ { PMC_EV_MIPS74K_UNCACHED_LOAD_INSNS, MIPS_CTR_0, 46 },
+ { PMC_EV_MIPS74K_UNCACHED_STORE_INSNS, MIPS_CTR_1, 46 },
+ { PMC_EV_MIPS74K_EJTAG_INSN_TRIGGERS, MIPS_CTR_0, 49 },
+ { PMC_EV_MIPS74K_CP1_BRANCH_MISPREDICTIONS, MIPS_CTR_0, 50 },
+ { PMC_EV_MIPS74K_SC_INSNS, MIPS_CTR_0, 51 },
+ { PMC_EV_MIPS74K_FAILED_SC_INSNS, MIPS_CTR_1, 51 },
+ { PMC_EV_MIPS74K_PREFETCH_INSNS, MIPS_CTR_0, 52 },
+ { PMC_EV_MIPS74K_CACHE_HIT_PREFETCH_INSNS, MIPS_CTR_1, 52 },
+ { PMC_EV_MIPS74K_NO_INSN_CYCLES, MIPS_CTR_0, 53 },
+ { PMC_EV_MIPS74K_LOAD_MISS_INSNS, MIPS_CTR_1, 53 },
+ { PMC_EV_MIPS74K_ONE_INSN_CYCLES, MIPS_CTR_0, 54 },
+ { PMC_EV_MIPS74K_TWO_INSNS_CYCLES, MIPS_CTR_1, 54 },
+ { PMC_EV_MIPS74K_GFIFO_BLOCKED_CYCLES, MIPS_CTR_0, 55 },
+ { PMC_EV_MIPS74K_CP1_CP2_STORE_INSNS, MIPS_CTR_1, 55 },
+ { PMC_EV_MIPS74K_MISPREDICTION_STALLS, MIPS_CTR_0, 56 },
+ { PMC_EV_MIPS74K_MISPREDICTED_BRANCH_INSNS_CYCLES, MIPS_CTR_0, 57 },
+ { PMC_EV_MIPS74K_EXCEPTIONS_TAKEN, MIPS_CTR_0, 58 },
+ { PMC_EV_MIPS74K_GRADUATION_REPLAYS, MIPS_CTR_1, 58 },
+ { PMC_EV_MIPS74K_COREEXTEND_EVENTS, MIPS_CTR_0, 59 },
+ { PMC_EV_MIPS74K_ISPRAM_EVENTS, MIPS_CTR_0, 62 },
+ { PMC_EV_MIPS74K_DSPRAM_EVENTS, MIPS_CTR_1, 62 },
+ { PMC_EV_MIPS74K_L2_CACHE_SINGLE_BIT_ERRORS, MIPS_CTR_0, 63 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_0, MIPS_CTR_0, 64 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_1, MIPS_CTR_1, 64 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_2, MIPS_CTR_0, 65 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_3, MIPS_CTR_1, 65 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_4, MIPS_CTR_0, 66 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_5, MIPS_CTR_1, 66 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_6, MIPS_CTR_0, 67 },
+ { PMC_EV_MIPS74K_SYSTEM_EVENT_7, MIPS_CTR_1, 67 },
+ { PMC_EV_MIPS74K_OCP_ALL_REQUESTS, MIPS_CTR_0, 68 },
+ { PMC_EV_MIPS74K_OCP_ALL_CACHEABLE_REQUESTS, MIPS_CTR_1, 68 },
+ { PMC_EV_MIPS74K_OCP_READ_REQUESTS, MIPS_CTR_0, 69 },
+ { PMC_EV_MIPS74K_OCP_READ_CACHEABLE_REQUESTS, MIPS_CTR_1, 69 },
+ { PMC_EV_MIPS74K_OCP_WRITE_REQUESTS, MIPS_CTR_0, 70 },
+ { PMC_EV_MIPS74K_OCP_WRITE_CACHEABLE_REQUESTS, MIPS_CTR_1, 70 },
+ { PMC_EV_MIPS74K_FSB_LESS_25_FULL, MIPS_CTR_0, 74 },
+ { PMC_EV_MIPS74K_FSB_25_50_FULL, MIPS_CTR_1, 74 },
+ { PMC_EV_MIPS74K_LDQ_LESS_25_FULL, MIPS_CTR_0, 75 },
+ { PMC_EV_MIPS74K_LDQ_25_50_FULL, MIPS_CTR_1, 75 },
+ { PMC_EV_MIPS74K_WBB_LESS_25_FULL, MIPS_CTR_0, 76 },
+ { PMC_EV_MIPS74K_WBB_25_50_FULL, MIPS_CTR_1, 76 },
+};
+
+const int mips_event_codes_size =
+ sizeof(mips_event_codes) / sizeof(mips_event_codes[0]);
+
+struct mips_pmc_spec mips_pmc_spec = {
+ .ps_cpuclass = PMC_CLASS_MIPS74K,
+ .ps_cputype = PMC_CPU_MIPS_74K,
+ .ps_capabilities = MIPS74K_PMC_CAPS,
+ .ps_counter_width = 32
+};
+
+/*
+ * Performance Count Register N
+ */
+uint64_t
+mips_pmcn_read(unsigned int pmc)
+{
+ uint32_t reg = 0;
+
+ KASSERT(pmc < mips_npmcs, ("[mips74k,%d] illegal PMC number %d",
+ __LINE__, pmc));
+
+ /* The counter value is the next value after the control register. */
+ switch (pmc) {
+ case 0:
+ reg = mips_rd_perfcnt1();
+ break;
+ case 1:
+ reg = mips_rd_perfcnt3();
+ break;
+ default:
+ return 0;
+ }
+ return (reg);
+}
+
+uint64_t
+mips_pmcn_write(unsigned int pmc, uint64_t reg)
+{
+
+ KASSERT(pmc < mips_npmcs, ("[mips74k,%d] illegal PMC number %d",
+ __LINE__, pmc));
+
+ switch (pmc) {
+ case 0:
+ mips_wr_perfcnt1(reg);
+ break;
+ case 1:
+ mips_wr_perfcnt3(reg);
+ break;
+ default:
+ return 0;
+ }
+ return (reg);
+}
+
+uint32_t
+mips_get_perfctl(int cpu, int ri, uint32_t event, uint32_t caps)
+{
+ uint32_t config;
+
+ config = event;
+
+ config <<= MIPS74K_PMC_SELECT;
+
+ if (caps & PMC_CAP_SYSTEM)
+ config |= (MIPS74K_PMC_SUPER_ENABLE |
+ MIPS74K_PMC_KERNEL_ENABLE);
+ if (caps & PMC_CAP_USER)
+ config |= MIPS74K_PMC_USER_ENABLE;
+ if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
+ config |= MIPS74K_PMC_ENABLE;
+ if (caps & PMC_CAP_INTERRUPT)
+ config |= MIPS74K_PMC_INTERRUPT_ENABLE;
+
+ PMCDBG(MDP,ALL,2,"mips74k-get_perfctl ri=%d -> config=0x%x", ri, config);
+
+ return (config);
+}
diff --git a/sys/dev/hwpmc/hwpmc_mpc7xxx.c b/sys/dev/hwpmc/hwpmc_mpc7xxx.c
index 171523b..eaa440e 100644
--- a/sys/dev/hwpmc/hwpmc_mpc7xxx.c
+++ b/sys/dev/hwpmc/hwpmc_mpc7xxx.c
@@ -567,7 +567,7 @@ mpc7xxx_pcpu_init(struct pmc_mdep *md, int cpu)
M_PMC, M_WAITOK|M_ZERO);
pac->pc_class = PMC_CLASS_PPC7450;
pc = pmc_pcpu[cpu];
- first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC7450].pcd_ri;
+ first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
for (i = 0, phw = pac->pc_ppcpmcs; i < MPC7XXX_MAX_PMCS; i++, phw++) {
@@ -729,7 +729,7 @@ pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep)
pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450;
- pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC7450];
+ pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
pcd->pcd_caps = POWERPC_PMC_CAPS;
pcd->pcd_class = PMC_CLASS_PPC7450;
pcd->pcd_num = MPC7XXX_MAX_PMCS;
diff --git a/sys/dev/hwpmc/hwpmc_powerpc.c b/sys/dev/hwpmc/hwpmc_powerpc.c
index ad251d3..889a5d0 100644
--- a/sys/dev/hwpmc/hwpmc_powerpc.c
+++ b/sys/dev/hwpmc/hwpmc_powerpc.c
@@ -175,6 +175,11 @@ pmc_md_initialize()
case IBM970MP:
error = pmc_ppc970_initialize(pmc_mdep);
break;
+ case FSL_E500v1:
+ case FSL_E500v2:
+ case FSL_E500mc:
+ error = pmc_e500_initialize(pmc_mdep);
+ break;
default:
error = -1;
break;
diff --git a/sys/dev/hwpmc/hwpmc_powerpc.h b/sys/dev/hwpmc/hwpmc_powerpc.h
index 8f0b8ce..66eaa21 100644
--- a/sys/dev/hwpmc/hwpmc_powerpc.h
+++ b/sys/dev/hwpmc/hwpmc_powerpc.h
@@ -51,6 +51,7 @@ struct powerpc_cpu {
extern struct powerpc_cpu **powerpc_pcpu;
+extern int pmc_e500_initialize(struct pmc_mdep *pmc_mdep);
extern int pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep);
extern int pmc_ppc970_initialize(struct pmc_mdep *pmc_mdep);
diff --git a/sys/dev/hwpmc/hwpmc_ppc970.c b/sys/dev/hwpmc/hwpmc_ppc970.c
index c6e8f4c..f477be3 100644
--- a/sys/dev/hwpmc/hwpmc_ppc970.c
+++ b/sys/dev/hwpmc/hwpmc_ppc970.c
@@ -555,7 +555,7 @@ ppc970_pcpu_init(struct pmc_mdep *md, int cpu)
pac->pc_class = PMC_CLASS_PPC970;
pc = pmc_pcpu[cpu];
- first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970].pcd_ri;
+ first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
for (i = 0, phw = pac->pc_ppcpmcs; i < PPC970_MAX_PMCS; i++, phw++) {
@@ -661,7 +661,7 @@ pmc_ppc970_initialize(struct pmc_mdep *pmc_mdep)
pmc_mdep->pmd_cputype = PMC_CPU_PPC_970;
- pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970];
+ pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
pcd->pcd_caps = POWERPC_PMC_CAPS;
pcd->pcd_class = PMC_CLASS_PPC970;
pcd->pcd_num = PPC970_MAX_PMCS;
diff --git a/sys/dev/hwpmc/pmc_events.h b/sys/dev/hwpmc/pmc_events.h
index 400a394..7f878cb 100644
--- a/sys/dev/hwpmc/pmc_events.h
+++ b/sys/dev/hwpmc/pmc_events.h
@@ -1554,6 +1554,11 @@ __PMC_EV_ALIAS("BACLEARS.RETURN", IAP_EVENT_E6H_08H) \
__PMC_EV_ALIAS("BACLEARS.COND", IAP_EVENT_E6H_10H) \
__PMC_EV_ALIAS("MS_DECODED.MS_ENTRY", IAP_EVENT_E7H_01H)
+/*
+ * Aliases for Broadwell PMC events.
+ */
+#define __PMC_EV_ALIAS_BROADWELL() \
+__PMC_EV_ALIAS_INTEL_ARCHITECTURAL()
/*
* Aliases for Core PMC events.
@@ -4228,6 +4233,11 @@ __PMC_EV(UCP, EVENT_86H_01H)
#define PMC_EV_UCP_FIRST PMC_EV_UCP_EVENT_00H_01H
#define PMC_EV_UCP_LAST PMC_EV_UCP_EVENT_86H_01H
+/*
+ * Aliases for Broadwell uncore PMC events
+ */
+#define __PMC_EV_ALIAS_BROADWELLUC()
+
#define __PMC_EV_ALIAS_COREI7UC() \
__PMC_EV_ALIAS("GQ_CYCLES_FULL.READ_TRACKER", UCP_EVENT_00H_01H) \
__PMC_EV_ALIAS("GQ_CYCLES_FULL.WRITE_TRACKER", UCP_EVENT_00H_02H) \
@@ -4893,6 +4903,138 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
#define PMC_EV_MIPS24K_LAST PMC_EV_MIPS24K_WBB_FULL_PIPELINE_STALLS
/*
+ * MIPS74k events. Similar to MIPS24k, the arrangement
+ * is (0,2) then (1,3) events.
+ */
+#define __PMC_EV_MIPS74K() \
+ __PMC_EV(MIPS74K, CYCLES) \
+ __PMC_EV(MIPS74K, INSTR_EXECUTED) \
+ __PMC_EV(MIPS74K, PREDICTED_JR_31) \
+ __PMC_EV(MIPS74K, JR_31_MISPREDICTIONS) \
+ __PMC_EV(MIPS74K, REDIRECT_STALLS) \
+ __PMC_EV(MIPS74K, JR_31_NO_PREDICTIONS) \
+ __PMC_EV(MIPS74K, ITLB_ACCESSES) \
+ __PMC_EV(MIPS74K, ITLB_MISSES) \
+ __PMC_EV(MIPS74K, JTLB_INSN_MISSES) \
+ __PMC_EV(MIPS74K, ICACHE_ACCESSES) \
+ __PMC_EV(MIPS74K, ICACHE_MISSES) \
+ __PMC_EV(MIPS74K, ICACHE_MISS_STALLS) \
+ __PMC_EV(MIPS74K, UNCACHED_IFETCH_STALLS) \
+ __PMC_EV(MIPS74K, PDTRACE_BACK_STALLS) \
+ __PMC_EV(MIPS74K, IFU_REPLAYS) \
+ __PMC_EV(MIPS74K, KILLED_FETCH_SLOTS) \
+ __PMC_EV(MIPS74K, IFU_IDU_MISS_PRED_UPSTREAM_CYCLES) \
+ __PMC_EV(MIPS74K, IFU_IDU_NO_FETCH_CYCLES) \
+ __PMC_EV(MIPS74K, IFU_IDU_CLOGED_DOWNSTREAM_CYCLES) \
+ __PMC_EV(MIPS74K, DDQ0_FULL_DR_STALLS) \
+ __PMC_EV(MIPS74K, DDQ1_FULL_DR_STALLS) \
+ __PMC_EV(MIPS74K, ALCB_FULL_DR_STALLS) \
+ __PMC_EV(MIPS74K, AGCB_FULL_DR_STALLS) \
+ __PMC_EV(MIPS74K, CLDQ_FULL_DR_STALLS) \
+ __PMC_EV(MIPS74K, IODQ_FULL_DR_STALLS) \
+ __PMC_EV(MIPS74K, ALU_EMPTY_CYCLES) \
+ __PMC_EV(MIPS74K, AGEN_EMPTY_CYCLES) \
+ __PMC_EV(MIPS74K, ALU_OPERANDS_NOT_READY_CYCLES) \
+ __PMC_EV(MIPS74K, AGEN_OPERANDS_NOT_READY_CYCLES) \
+ __PMC_EV(MIPS74K, ALU_NO_ISSUES_CYCLES) \
+ __PMC_EV(MIPS74K, AGEN_NO_ISSUES_CYCLES) \
+ __PMC_EV(MIPS74K, ALU_BUBBLE_CYCLES) \
+ __PMC_EV(MIPS74K, AGEN_BUBBLE_CYCLES) \
+ __PMC_EV(MIPS74K, SINGLE_ISSUE_CYCLES) \
+ __PMC_EV(MIPS74K, DUAL_ISSUE_CYCLES) \
+ __PMC_EV(MIPS74K, OOO_ALU_ISSUE_CYCLES) \
+ __PMC_EV(MIPS74K, OOO_AGEN_ISSUE_CYCLES) \
+ __PMC_EV(MIPS74K, JALR_JALR_HB_INSNS) \
+ __PMC_EV(MIPS74K, DCACHE_LINE_REFILL_REQUESTS) \
+ __PMC_EV(MIPS74K, DCACHE_LOAD_ACCESSES) \
+ __PMC_EV(MIPS74K, DCACHE_ACCESSES) \
+ __PMC_EV(MIPS74K, DCACHE_WRITEBACKS) \
+ __PMC_EV(MIPS74K, DCACHE_MISSES) \
+ __PMC_EV(MIPS74K, JTLB_DATA_ACCESSES) \
+ __PMC_EV(MIPS74K, JTLB_DATA_MISSES) \
+ __PMC_EV(MIPS74K, LOAD_STORE_REPLAYS) \
+ __PMC_EV(MIPS74K, VA_TRANSALTION_CORNER_CASES) \
+ __PMC_EV(MIPS74K, LOAD_STORE_BLOCKED_CYCLES) \
+ __PMC_EV(MIPS74K, LOAD_STORE_NO_FILL_REQUESTS) \
+ __PMC_EV(MIPS74K, L2_CACHE_WRITEBACKS) \
+ __PMC_EV(MIPS74K, L2_CACHE_ACCESSES) \
+ __PMC_EV(MIPS74K, L2_CACHE_MISSES) \
+ __PMC_EV(MIPS74K, L2_CACHE_MISS_CYCLES) \
+ __PMC_EV(MIPS74K, FSB_FULL_STALLS) \
+ __PMC_EV(MIPS74K, FSB_OVER_50_FULL) \
+ __PMC_EV(MIPS74K, LDQ_FULL_STALLS) \
+ __PMC_EV(MIPS74K, LDQ_OVER_50_FULL) \
+ __PMC_EV(MIPS74K, WBB_FULL_STALLS) \
+ __PMC_EV(MIPS74K, WBB_OVER_50_FULL) \
+ __PMC_EV(MIPS74K, LOAD_MISS_CONSUMER_REPLAYS) \
+ __PMC_EV(MIPS74K, CP1_CP2_LOAD_INSNS) \
+ __PMC_EV(MIPS74K, JR_NON_31_INSNS) \
+ __PMC_EV(MIPS74K, MISPREDICTED_JR_31_INSNS) \
+ __PMC_EV(MIPS74K, BRANCH_INSNS) \
+ __PMC_EV(MIPS74K, CP1_CP2_COND_BRANCH_INSNS) \
+ __PMC_EV(MIPS74K, BRANCH_LIKELY_INSNS) \
+ __PMC_EV(MIPS74K, MISPREDICTED_BRANCH_LIKELY_INSNS) \
+ __PMC_EV(MIPS74K, COND_BRANCH_INSNS) \
+ __PMC_EV(MIPS74K, MISPREDICTED_BRANCH_INSNS) \
+ __PMC_EV(MIPS74K, INTEGER_INSNS) \
+ __PMC_EV(MIPS74K, FPU_INSNS) \
+ __PMC_EV(MIPS74K, LOAD_INSNS) \
+ __PMC_EV(MIPS74K, STORE_INSNS) \
+ __PMC_EV(MIPS74K, J_JAL_INSNS) \
+ __PMC_EV(MIPS74K, MIPS16_INSNS) \
+ __PMC_EV(MIPS74K, NOP_INSNS) \
+ __PMC_EV(MIPS74K, NT_MUL_DIV_INSNS) \
+ __PMC_EV(MIPS74K, DSP_INSNS) \
+ __PMC_EV(MIPS74K, ALU_DSP_SATURATION_INSNS) \
+ __PMC_EV(MIPS74K, DSP_BRANCH_INSNS) \
+ __PMC_EV(MIPS74K, MDU_DSP_SATURATION_INSNS) \
+ __PMC_EV(MIPS74K, UNCACHED_LOAD_INSNS) \
+ __PMC_EV(MIPS74K, UNCACHED_STORE_INSNS) \
+ __PMC_EV(MIPS74K, EJTAG_INSN_TRIGGERS) \
+ __PMC_EV(MIPS74K, CP1_BRANCH_MISPREDICTIONS) \
+ __PMC_EV(MIPS74K, SC_INSNS) \
+ __PMC_EV(MIPS74K, FAILED_SC_INSNS) \
+ __PMC_EV(MIPS74K, PREFETCH_INSNS) \
+ __PMC_EV(MIPS74K, CACHE_HIT_PREFETCH_INSNS) \
+ __PMC_EV(MIPS74K, NO_INSN_CYCLES) \
+ __PMC_EV(MIPS74K, LOAD_MISS_INSNS) \
+ __PMC_EV(MIPS74K, ONE_INSN_CYCLES) \
+ __PMC_EV(MIPS74K, TWO_INSNS_CYCLES) \
+ __PMC_EV(MIPS74K, GFIFO_BLOCKED_CYCLES) \
+ __PMC_EV(MIPS74K, CP1_CP2_STORE_INSNS) \
+ __PMC_EV(MIPS74K, MISPREDICTION_STALLS) \
+ __PMC_EV(MIPS74K, MISPREDICTED_BRANCH_INSNS_CYCLES) \
+ __PMC_EV(MIPS74K, EXCEPTIONS_TAKEN) \
+ __PMC_EV(MIPS74K, GRADUATION_REPLAYS) \
+ __PMC_EV(MIPS74K, COREEXTEND_EVENTS) \
+ __PMC_EV(MIPS74K, ISPRAM_EVENTS) \
+ __PMC_EV(MIPS74K, DSPRAM_EVENTS) \
+ __PMC_EV(MIPS74K, L2_CACHE_SINGLE_BIT_ERRORS) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_0) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_1) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_2) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_3) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_4) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_5) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_6) \
+ __PMC_EV(MIPS74K, SYSTEM_EVENT_7) \
+ __PMC_EV(MIPS74K, OCP_ALL_REQUESTS) \
+ __PMC_EV(MIPS74K, OCP_ALL_CACHEABLE_REQUESTS) \
+ __PMC_EV(MIPS74K, OCP_READ_REQUESTS) \
+ __PMC_EV(MIPS74K, OCP_READ_CACHEABLE_REQUESTS) \
+ __PMC_EV(MIPS74K, OCP_WRITE_REQUESTS) \
+ __PMC_EV(MIPS74K, OCP_WRITE_CACHEABLE_REQUESTS) \
+ __PMC_EV(MIPS74K, FSB_LESS_25_FULL) \
+ __PMC_EV(MIPS74K, FSB_25_50_FULL) \
+ __PMC_EV(MIPS74K, LDQ_LESS_25_FULL) \
+ __PMC_EV(MIPS74K, LDQ_25_50_FULL) \
+ __PMC_EV(MIPS74K, WBB_LESS_25_FULL) \
+ __PMC_EV(MIPS74K, WBB_25_50_FULL)
+
+#define PMC_EV_MIPS74K_FIRST PMC_EV_MIPS74K_CYCLES
+#define PMC_EV_MIPS74K_LAST PMC_EV_MIPS74K_WBB_25_50_FULL
+
+/*
* Cavium Octeon counters. Obtained from cvmx-core.h
*/
#define __PMC_EV_OCTEON() \
@@ -5237,6 +5379,168 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
#define PMC_EV_PPC970_FIRST PMC_EV_PPC970_INSTR_COMPLETED
#define PMC_EV_PPC970_LAST PMC_EV_PPC970_ADDER
+
+#define __PMC_EV_E500() \
+ __PMC_EV(E500, CYCLES) \
+ __PMC_EV(E500, INSTR_COMPLETED) \
+ __PMC_EV(E500, UOPS_COMPLETED) \
+ __PMC_EV(E500, INSTR_FETCHED) \
+ __PMC_EV(E500, UOPS_DECODED) \
+ __PMC_EV(E500, PM_EVENT_TRANSITIONS) \
+ __PMC_EV(E500, PM_EVENT_CYCLES) \
+ __PMC_EV(E500, BRANCH_INSTRS_COMPLETED) \
+ __PMC_EV(E500, LOAD_UOPS_COMPLETED) \
+ __PMC_EV(E500, STORE_UOPS_COMPLETED) \
+ __PMC_EV(E500, CQ_REDIRECTS) \
+ __PMC_EV(E500, BRANCHES_FINISHED) \
+ __PMC_EV(E500, TAKEN_BRANCHES_FINISHED) \
+ __PMC_EV(E500, FINISHED_UNCOND_BRANCHES_MISS_BTB) \
+ __PMC_EV(E500, BRANCH_MISPRED) \
+ __PMC_EV(E500, BTB_BRANCH_MISPRED_FROM_DIRECTION) \
+ __PMC_EV(E500, BTB_HITS_PSEUDO_HITS) \
+ __PMC_EV(E500, CYCLES_DECODE_STALLED) \
+ __PMC_EV(E500, CYCLES_ISSUE_STALLED) \
+ __PMC_EV(E500, CYCLES_BRANCH_ISSUE_STALLED) \
+ __PMC_EV(E500, CYCLES_SU1_SCHED_STALLED) \
+ __PMC_EV(E500, CYCLES_SU2_SCHED_STALLED) \
+ __PMC_EV(E500, CYCLES_MU_SCHED_STALLED) \
+ __PMC_EV(E500, CYCLES_LRU_SCHED_STALLED) \
+ __PMC_EV(E500, CYCLES_BU_SCHED_STALLED) \
+ __PMC_EV(E500, TOTAL_TRANSLATED) \
+ __PMC_EV(E500, LOADS_TRANSLATED) \
+ __PMC_EV(E500, STORES_TRANSLATED) \
+ __PMC_EV(E500, TOUCHES_TRANSLATED) \
+ __PMC_EV(E500, CACHEOPS_TRANSLATED) \
+ __PMC_EV(E500, CACHE_INHIBITED_ACCESS_TRANSLATED) \
+ __PMC_EV(E500, GUARDED_LOADS_TRANSLATED) \
+ __PMC_EV(E500, WRITE_THROUGH_STORES_TRANSLATED) \
+ __PMC_EV(E500, MISALIGNED_LOAD_STORE_ACCESS_TRANSLATED) \
+ __PMC_EV(E500, TOTAL_ALLOCATED_TO_DLFB) \
+ __PMC_EV(E500, LOADS_TRANSLATED_ALLOCATED_TO_DLFB) \
+ __PMC_EV(E500, STORES_COMPLETED_ALLOCATED_TO_DLFB) \
+ __PMC_EV(E500, TOUCHES_TRANSLATED_ALLOCATED_TO_DLFB) \
+ __PMC_EV(E500, STORES_COMPLETED) \
+ __PMC_EV(E500, DATA_L1_CACHE_LOCKS) \
+ __PMC_EV(E500, DATA_L1_CACHE_RELOADS) \
+ __PMC_EV(E500, DATA_L1_CACHE_CASTOUTS) \
+ __PMC_EV(E500, LOAD_MISS_DLFB_FULL) \
+ __PMC_EV(E500, LOAD_MISS_LDQ_FULL) \
+ __PMC_EV(E500, LOAD_GUARDED_MISS) \
+ __PMC_EV(E500, STORE_TRANSLATE_WHEN_QUEUE_FULL) \
+ __PMC_EV(E500, ADDRESS_COLLISION) \
+ __PMC_EV(E500, DATA_MMU_MISS) \
+ __PMC_EV(E500, DATA_MMU_BUSY) \
+ __PMC_EV(E500, PART2_MISALIGNED_CACHE_ACCESS) \
+ __PMC_EV(E500, LOAD_MISS_DLFB_FULL_CYCLES) \
+ __PMC_EV(E500, LOAD_MISS_LDQ_FULL_CYCLES) \
+ __PMC_EV(E500, LOAD_GUARDED_MISS_CYCLES) \
+ __PMC_EV(E500, STORE_TRANSLATE_WHEN_QUEUE_FULL_CYCLES) \
+ __PMC_EV(E500, ADDRESS_COLLISION_CYCLES) \
+ __PMC_EV(E500, DATA_MMU_MISS_CYCLES) \
+ __PMC_EV(E500, DATA_MMU_BUSY_CYCLES) \
+ __PMC_EV(E500, PART2_MISALIGNED_CACHE_ACCESS_CYCLES) \
+ __PMC_EV(E500, INSTR_L1_CACHE_LOCKS) \
+ __PMC_EV(E500, INSTR_L1_CACHE_RELOADS) \
+ __PMC_EV(E500, INSTR_L1_CACHE_FETCHES) \
+ __PMC_EV(E500, INSTR_MMU_TLB4K_RELOADS) \
+ __PMC_EV(E500, INSTR_MMU_VSP_RELOADS) \
+ __PMC_EV(E500, DATA_MMU_TLB4K_RELOADS) \
+ __PMC_EV(E500, DATA_MMU_VSP_RELOADS) \
+ __PMC_EV(E500, L2MMU_MISSES) \
+ __PMC_EV(E500, BIU_MASTER_REQUESTS) \
+ __PMC_EV(E500, BIU_MASTER_INSTR_SIDE_REQUESTS) \
+ __PMC_EV(E500, BIU_MASTER_DATA_SIDE_REQUESTS) \
+ __PMC_EV(E500, BIU_MASTER_DATA_SIDE_CASTOUT_REQUESTS) \
+ __PMC_EV(E500, BIU_MASTER_RETRIES) \
+ __PMC_EV(E500, SNOOP_REQUESTS) \
+ __PMC_EV(E500, SNOOP_HITS) \
+ __PMC_EV(E500, SNOOP_PUSHES) \
+ __PMC_EV(E500, SNOOP_RETRIES) \
+ __PMC_EV(E500, DLFB_LOAD_MISS_CYCLES) \
+ __PMC_EV(E500, ILFB_FETCH_MISS_CYCLES) \
+ __PMC_EV(E500, EXT_INPU_INTR_LATENCY_CYCLES) \
+ __PMC_EV(E500, CRIT_INPUT_INTR_LATENCY_CYCLES) \
+ __PMC_EV(E500, EXT_INPUT_INTR_PENDING_LATENCY_CYCLES) \
+ __PMC_EV(E500, CRIT_INPUT_INTR_PENDING_LATENCY_CYCLES) \
+ __PMC_EV(E500, PMC0_OVERFLOW) \
+ __PMC_EV(E500, PMC1_OVERFLOW) \
+ __PMC_EV(E500, PMC2_OVERFLOW) \
+ __PMC_EV(E500, PMC3_OVERFLOW) \
+ __PMC_EV(E500, INTERRUPTS_TAKEN) \
+ __PMC_EV(E500, EXT_INPUT_INTR_TAKEN) \
+ __PMC_EV(E500, CRIT_INPUT_INTR_TAKEN) \
+ __PMC_EV(E500, SYSCALL_TRAP_INTR) \
+ __PMC_EV(E500, TLB_BIT_TRANSITIONS) \
+ __PMC_EV(E500, L2_LINEFILL_BUFFER) \
+ __PMC_EV(E500, LV2_VS) \
+ __PMC_EV(E500, CASTOUTS_RELEASED) \
+ __PMC_EV(E500, INTV_ALLOCATIONS) \
+ __PMC_EV(E500, DLFB_RETRIES_TO_MBAR) \
+ __PMC_EV(E500, STORE_RETRIES) \
+ __PMC_EV(E500, STASH_L1_HITS) \
+ __PMC_EV(E500, STASH_L2_HITS) \
+ __PMC_EV(E500, STASH_BUSY_1) \
+ __PMC_EV(E500, STASH_BUSY_2) \
+ __PMC_EV(E500, STASH_BUSY_3) \
+ __PMC_EV(E500, STASH_HITS) \
+ __PMC_EV(E500, STASH_HIT_DLFB) \
+ __PMC_EV(E500, STASH_REQUESTS) \
+ __PMC_EV(E500, STASH_REQUESTS_L1) \
+ __PMC_EV(E500, STASH_REQUESTS_L2) \
+ __PMC_EV(E500, STALLS_NO_CAQ_OR_COB) \
+ __PMC_EV(E500, L2_CACHE_ACCESSES) \
+ __PMC_EV(E500, L2_HIT_CACHE_ACCESSES) \
+ __PMC_EV(E500, L2_CACHE_DATA_ACCESSES) \
+ __PMC_EV(E500, L2_CACHE_DATA_HITS) \
+ __PMC_EV(E500, L2_CACHE_INSTR_ACCESSES) \
+ __PMC_EV(E500, L2_CACHE_INSTR_HITS) \
+ __PMC_EV(E500, L2_CACHE_ALLOCATIONS) \
+ __PMC_EV(E500, L2_CACHE_DATA_ALLOCATIONS) \
+ __PMC_EV(E500, L2_CACHE_DIRTY_DATA_ALLOCATIONS) \
+ __PMC_EV(E500, L2_CACHE_INSTR_ALLOCATIONS) \
+ __PMC_EV(E500, L2_CACHE_UPDATES) \
+ __PMC_EV(E500, L2_CACHE_CLEAN_UPDATES) \
+ __PMC_EV(E500, L2_CACHE_DIRTY_UPDATES) \
+ __PMC_EV(E500, L2_CACHE_CLEAN_REDUNDANT_UPDATES) \
+ __PMC_EV(E500, L2_CACHE_DIRTY_REDUNDANT_UPDATES) \
+ __PMC_EV(E500, L2_CACHE_LOCKS) \
+ __PMC_EV(E500, L2_CACHE_CASTOUTS) \
+ __PMC_EV(E500, L2_CACHE_DATA_DIRTY_HITS) \
+ __PMC_EV(E500, INSTR_LFB_WENT_HIGH_PRIORITY) \
+ __PMC_EV(E500, SNOOP_THROTTLING_TURNED_ON) \
+ __PMC_EV(E500, L2_CLEAN_LINE_INVALIDATIONS) \
+ __PMC_EV(E500, L2_INCOHERENT_LINE_INVALIDATIONS) \
+ __PMC_EV(E500, L2_COHERENT_LINE_INVALIDATIONS) \
+ __PMC_EV(E500, COHERENT_LOOKUP_MISS_DUE_TO_VALID_BUT_INCOHERENT_MATCHES) \
+ __PMC_EV(E500, IAC1S_DETECTED) \
+ __PMC_EV(E500, IAC2S_DETECTED) \
+ __PMC_EV(E500, DAC1S_DTECTED) \
+ __PMC_EV(E500, DAC2S_DTECTED) \
+ __PMC_EV(E500, DVT0_DETECTED) \
+ __PMC_EV(E500, DVT1_DETECTED) \
+ __PMC_EV(E500, DVT2_DETECTED) \
+ __PMC_EV(E500, DVT3_DETECTED) \
+ __PMC_EV(E500, DVT4_DETECTED) \
+ __PMC_EV(E500, DVT5_DETECTED) \
+ __PMC_EV(E500, DVT6_DETECTED) \
+ __PMC_EV(E500, DVT7_DETECTED) \
+ __PMC_EV(E500, CYCLES_COMPLETION_STALLED_NEXUS_FIFO_FULL) \
+ __PMC_EV(E500, FPU_DOUBLE_PUMP) \
+ __PMC_EV(E500, FPU_FINISH) \
+ __PMC_EV(E500, FPU_DIVIDE_CYCLES) \
+ __PMC_EV(E500, FPU_DENORM_INPUT_CYCLES) \
+ __PMC_EV(E500, FPU_RESULT_STALL_CYCLES) \
+ __PMC_EV(E500, FPU_FPSCR_FULL_STALL) \
+ __PMC_EV(E500, FPU_PIPE_SYNC_STALLS) \
+ __PMC_EV(E500, FPU_INPUT_DATA_STALLS) \
+ __PMC_EV(E500, DECORATED_LOADS) \
+ __PMC_EV(E500, DECORATED_STORES) \
+ __PMC_EV(E500, LOAD_RETRIES) \
+ __PMC_EV(E500, STWCX_SUCCESSES) \
+ __PMC_EV(E500, STWCX_FAILURES) \
+
+#define PMC_EV_E500_FIRST PMC_EV_E500_CYCLES
+#define PMC_EV_E500_LAST PMC_EV_E500_STWCX_FAILURES
/*
* All known PMC events.
*
@@ -5256,6 +5560,11 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
* 0x11100 0x0100 INTEL Pentium Pro/P-II/P-III/Pentium-M events
* 0x11200 0x00FF INTEL XScale events
* 0x11300 0x00FF MIPS 24K events
+ * 0x11400 0x00FF Octeon events
+ * 0x11500 0x00FF MIPS 74K events
+ * 0x13000 0x00FF MPC7450 events
+ * 0x13100 0x00FF IBM PPC970 events
+ * 0x13300 0x00FF Freescale e500 events
* 0x14000 0x0100 ARMv7 events
* 0x20000 0x1000 Software events
*/
@@ -5282,6 +5591,8 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
__PMC_EV_MIPS24K() \
__PMC_EV_BLOCK(OCTEON, 0x11400) \
__PMC_EV_OCTEON() \
+ __PMC_EV_BLOCK(MIPS74K, 0x11500) \
+ __PMC_EV_MIPS74K() \
__PMC_EV_BLOCK(UCF, 0x12000) \
__PMC_EV_UCF() \
__PMC_EV_BLOCK(UCP, 0x12080) \
@@ -5290,6 +5601,8 @@ __PMC_EV_ALIAS("IMPC_C0H_TRK_REQUEST.ALL", UCP_EVENT_84H_01H)
__PMC_EV_PPC7450() \
__PMC_EV_BLOCK(PPC970, 0x13100) \
__PMC_EV_PPC970() \
+ __PMC_EV_BLOCK(E500, 0x13300) \
+ __PMC_EV_E500() \
__PMC_EV_BLOCK(ARMV7, 0x14000) \
__PMC_EV_ARMV7() \
diff --git a/sys/dev/hyperv/include/hyperv.h b/sys/dev/hyperv/include/hyperv.h
index 8a45d89..5360b7c 100644
--- a/sys/dev/hyperv/include/hyperv.h
+++ b/sys/dev/hyperv/include/hyperv.h
@@ -46,6 +46,7 @@
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/sema.h>
+#include <sys/smp.h>
#include <sys/mutex.h>
#include <sys/bus.h>
#include <vm/vm.h>
@@ -63,11 +64,22 @@ typedef uint8_t hv_bool_uint8_t;
#define HV_ERROR_MACHINE_LOCKED 0x800704F7
/*
- * A revision number of vmbus that is used for ensuring both ends on a
- * partition are using compatible versions.
+ * VMBUS version is 32 bit, upper 16 bit for major_number and lower
+ * 16 bit for minor_number.
+ *
+ * 0.13 -- Windows Server 2008
+ * 1.1 -- Windows 7
+ * 2.4 -- Windows 8
+ * 3.0 -- Windows 8.1
*/
+#define HV_VMBUS_VERSION_WS2008 ((0 << 16) | (13))
+#define HV_VMBUS_VERSION_WIN7 ((1 << 16) | (1))
+#define HV_VMBUS_VERSION_WIN8 ((2 << 16) | (4))
+#define HV_VMBUS_VERSION_WIN8_1 ((3 << 16) | (0))
+
+#define HV_VMBUS_VERSION_INVALID -1
-#define HV_VMBUS_REVISION_NUMBER 13
+#define HV_VMBUS_VERSION_CURRENT HV_VMBUS_VERSION_WIN8_1
/*
* Make maximum size of pipe payload of 16K
@@ -112,6 +124,18 @@ typedef struct hv_guid {
unsigned char data[16];
} __packed hv_guid;
+#define HV_NIC_GUID \
+ .data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, \
+ 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
+
+#define HV_IDE_GUID \
+ .data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, \
+ 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}
+
+#define HV_SCSI_GUID \
+ .data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, \
+ 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}
+
/*
* At the center of the Channel Management library is
* the Channel Offer. This struct contains the
@@ -147,7 +171,11 @@ typedef struct hv_vmbus_channel_offer {
} __packed pipe;
} u;
- uint32_t padding;
+ /*
+ * Sub_channel_index, newly added in Win8.
+ */
+ uint16_t sub_channel_index;
+ uint16_t padding;
} __packed hv_vmbus_channel_offer;
@@ -344,7 +372,25 @@ typedef struct {
hv_vmbus_channel_offer offer;
uint32_t child_rel_id;
uint8_t monitor_id;
- hv_bool_uint8_t monitor_allocated;
+ /*
+ * This field has been split into a bit field on Win7
+ * and higher.
+ */
+ uint8_t monitor_allocated:1;
+ uint8_t reserved:7;
+ /*
+ * Following fields were added in win7 and higher.
+ * Make sure to check the version before accessing these fields.
+ *
+ * If "is_dedicated_interrupt" is set, we must not set the
+ * associated bit in the channel bitmap while sending the
+ * interrupt to the host.
+ *
+ * connection_id is used in signaling the host.
+ */
+ uint16_t is_dedicated_interrupt:1;
+ uint16_t reserved1:15;
+ uint32_t connection_id;
} __packed hv_vmbus_channel_offer_channel;
/*
@@ -394,9 +440,11 @@ typedef struct
hv_gpadl_handle ring_buffer_gpadl_handle;
/*
- * GPADL for the channel's server context save area.
+ * Before win8, all incoming channel interrupts are only
+ * delivered on cpu 0. Setting this value to 0 would
+ * preserve the earlier behavior.
*/
- hv_gpadl_handle server_context_area_gpadl_handle;
+ uint32_t target_vcpu;
/*
* The upstream ring buffer begins at offset zero in the memory described
@@ -646,14 +694,42 @@ typedef struct {
} hv_vmbus_ring_buffer_info;
typedef void (*hv_vmbus_pfn_channel_callback)(void *context);
+typedef void (*hv_vmbus_sc_creation_callback)(void *context);
typedef enum {
HV_CHANNEL_OFFER_STATE,
HV_CHANNEL_OPENING_STATE,
HV_CHANNEL_OPEN_STATE,
+ HV_CHANNEL_OPENED_STATE,
HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE,
} hv_vmbus_channel_state;
+/*
+ * Connection identifier type
+ */
+typedef union {
+ uint32_t as_uint32_t;
+ struct {
+ uint32_t id:24;
+ uint32_t reserved:8;
+ } u;
+
+} __packed hv_vmbus_connection_id;
+
+/*
+ * Definition of the hv_vmbus_signal_event hypercall input structure
+ */
+typedef struct {
+ hv_vmbus_connection_id connection_id;
+ uint16_t flag_number;
+ uint16_t rsvd_z;
+} __packed hv_vmbus_input_signal_event;
+
+typedef struct {
+ uint64_t align8;
+ hv_vmbus_input_signal_event event;
+} __packed hv_vmbus_input_signal_event_buffer;
+
typedef struct hv_vmbus_channel {
TAILQ_ENTRY(hv_vmbus_channel) list_entry;
struct hv_device* device;
@@ -688,8 +764,82 @@ typedef struct hv_vmbus_channel {
hv_vmbus_pfn_channel_callback on_channel_callback;
void* channel_callback_context;
+ /*
+ * If batched_reading is set to "true", mask the interrupt
+ * and read until the channel is empty.
+ * If batched_reading is set to "false", the channel is not
+ * going to perform batched reading.
+ *
+ * Batched reading is enabled by default; specific
+ * drivers that don't want this behavior can turn it off.
+ */
+ boolean_t batched_reading;
+
+ boolean_t is_dedicated_interrupt;
+
+ /*
+ * Used as an input param for HV_CALL_SIGNAL_EVENT hypercall.
+ */
+ hv_vmbus_input_signal_event_buffer signal_event_buffer;
+ /*
+ * 8-bytes aligned of the buffer above
+ */
+ hv_vmbus_input_signal_event *signal_event_param;
+
+ /*
+ * From Win8, this field specifies the target virtual process
+ * on which to deliver the interupt from the host to guest.
+ * Before Win8, all channel interrupts would only be
+ * delivered on cpu 0. Setting this value to 0 would preserve
+ * the earlier behavior.
+ */
+ uint32_t target_vcpu;
+ /* The corresponding CPUID in the guest */
+ uint32_t target_cpu;
+
+ /*
+ * Support for multi-channels.
+ * The initial offer is considered the primary channel and this
+ * offer message will indicate if the host supports multi-channels.
+ * The guest is free to ask for multi-channels to be offerred and can
+ * open these multi-channels as a normal "primary" channel. However,
+ * all multi-channels will have the same type and instance guids as the
+ * primary channel. Requests sent on a given channel will result in a
+ * response on the same channel.
+ */
+
+ /*
+ * Multi-channel creation callback. This callback will be called in
+ * process context when a Multi-channel offer is received from the host.
+ * The guest can open the Multi-channel in the context of this callback.
+ */
+ hv_vmbus_sc_creation_callback sc_creation_callback;
+
+ struct mtx sc_lock;
+
+ /*
+ * Link list of all the multi-channels if this is a primary channel
+ */
+ TAILQ_HEAD(, hv_vmbus_channel) sc_list_anchor;
+ TAILQ_ENTRY(hv_vmbus_channel) sc_list_entry;
+
+ /*
+ * The primary channel this sub-channle belongs to.
+ * This will be NULL for the primary channel.
+ */
+ struct hv_vmbus_channel *primary_channel;
+ /*
+ * Support per channel state for use by vmbus drivers.
+ */
+ void *per_channel_state;
} hv_vmbus_channel;
+static inline void
+hv_set_channel_read_state(hv_vmbus_channel* channel, boolean_t state)
+{
+ channel->batched_reading = state;
+}
+
typedef struct hv_device {
hv_guid class_id;
hv_guid device_id;
@@ -760,6 +910,8 @@ int hv_vmbus_channel_teardown_gpdal(
hv_vmbus_channel* channel,
uint32_t gpadl_handle);
+struct hv_vmbus_channel* vmbus_select_outgoing_channel(struct hv_vmbus_channel *promary);
+
/*
* Work abstraction defines
*/
@@ -819,6 +971,7 @@ typedef struct hv_vmbus_service {
extern uint8_t* receive_buffer[];
extern hv_vmbus_service service_table[];
+extern uint32_t hv_vmbus_protocal_version;
void hv_kvp_callback(void *context);
int hv_kvp_init(hv_vmbus_service *serv);
diff --git a/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c b/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
index d00d279..f8a871b 100644
--- a/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
+++ b/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/condvar.h>
+#include <sys/time.h>
#include <sys/systm.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
@@ -53,8 +54,12 @@ __FBSDID("$FreeBSD$");
#include <sys/callout.h>
#include <vm/vm.h>
#include <vm/pmap.h>
+#include <vm/uma.h>
#include <sys/lock.h>
#include <sys/sema.h>
+#include <sys/sglist.h>
+#include <machine/bus.h>
+#include <sys/bus_dma.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@@ -66,7 +71,6 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/scsi_all.h>
#include <cam/scsi/scsi_message.h>
-
#include <dev/hyperv/include/hyperv.h>
#include "hv_vstorage.h"
@@ -77,8 +81,29 @@ __FBSDID("$FreeBSD$");
#define BLKVSC_MAX_IO_REQUESTS STORVSC_MAX_IO_REQUESTS
#define STORVSC_MAX_TARGETS (2)
+#define STORVSC_WIN7_MAJOR 4
+#define STORVSC_WIN7_MINOR 2
+
+#define STORVSC_WIN8_MAJOR 5
+#define STORVSC_WIN8_MINOR 1
+
+#define HV_ALIGN(x, a) roundup2(x, a)
+
struct storvsc_softc;
+struct hv_sgl_node {
+ LIST_ENTRY(hv_sgl_node) link;
+ struct sglist *sgl_data;
+};
+
+struct hv_sgl_page_pool{
+ LIST_HEAD(, hv_sgl_node) in_use_sgl_list;
+ LIST_HEAD(, hv_sgl_node) free_sgl_list;
+ boolean_t is_init;
+} g_hv_sgl_page_pool;
+
+#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * HV_MAX_MULTIPAGE_BUFFER_COUNT
+
enum storvsc_request_type {
WRITE_TYPE,
READ_TYPE,
@@ -96,20 +121,24 @@ struct hv_storvsc_request {
struct storvsc_softc *softc;
struct callout callout;
struct sema synch_sema; /*Synchronize the request/response if needed */
+ struct sglist *bounce_sgl;
+ unsigned int bounce_sgl_count;
+ uint64_t not_aligned_seg_bits;
};
struct storvsc_softc {
struct hv_device *hs_dev;
- LIST_HEAD(, hv_storvsc_request) hs_free_list;
- struct mtx hs_lock;
- struct storvsc_driver_props *hs_drv_props;
- int hs_unit;
- uint32_t hs_frozen;
- struct cam_sim *hs_sim;
- struct cam_path *hs_path;
+ LIST_HEAD(, hv_storvsc_request) hs_free_list;
+ struct mtx hs_lock;
+ struct storvsc_driver_props *hs_drv_props;
+ int hs_unit;
+ uint32_t hs_frozen;
+ struct cam_sim *hs_sim;
+ struct cam_path *hs_path;
uint32_t hs_num_out_reqs;
boolean_t hs_destroy;
boolean_t hs_drain_notify;
+ boolean_t hs_open_multi_channel;
struct sema hs_drain_sema;
struct hv_storvsc_request hs_init_req;
struct hv_storvsc_request hs_reset_req;
@@ -124,7 +153,7 @@ struct storvsc_softc {
* The first can be tested by "sg_senddiag -vv /dev/daX",
* and the second and third can be done by
* "sg_wr_mode -v -p 08 -c 0,1a -m 0,ff /dev/daX".
- */
+ */
#define HVS_TIMEOUT_TEST 0
/*
@@ -138,7 +167,7 @@ struct storvsc_driver_props {
char *drv_name;
char *drv_desc;
uint8_t drv_max_luns_per_target;
- uint8_t drv_max_ios_per_target;
+ uint8_t drv_max_ios_per_target;
uint32_t drv_ringbuffer_size;
};
@@ -150,6 +179,8 @@ enum hv_storage_type {
#define HS_MAX_ADAPTERS 10
+#define HV_STORAGE_SUPPORTS_MULTI_CHANNEL 0x1
+
/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
static const hv_guid gStorVscDeviceType={
.data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
@@ -171,13 +202,16 @@ static struct storvsc_driver_props g_drv_props_table[] = {
STORVSC_RINGBUFFER_SIZE}
};
+static int storvsc_current_major;
+static int storvsc_current_minor;
+
/* static functions */
static int storvsc_probe(device_t dev);
static int storvsc_attach(device_t dev);
static int storvsc_detach(device_t dev);
static void storvsc_poll(struct cam_sim * sim);
static void storvsc_action(struct cam_sim * sim, union ccb * ccb);
-static void create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp);
+static int create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp);
static void storvsc_free_request(struct storvsc_softc *sc, struct hv_storvsc_request *reqp);
static enum hv_storage_type storvsc_get_storage_type(device_t dev);
static void hv_storvsc_on_channel_callback(void *context);
@@ -186,6 +220,14 @@ static void hv_storvsc_on_iocompletion( struct storvsc_softc *sc,
struct hv_storvsc_request *request);
static int hv_storvsc_connect_vsp(struct hv_device *device);
static void storvsc_io_done(struct hv_storvsc_request *reqp);
+static void storvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl,
+ bus_dma_segment_t *orig_sgl,
+ unsigned int orig_sgl_count,
+ uint64_t seg_bits);
+void storvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl,
+ unsigned int dest_sgl_count,
+ struct sglist* src_sgl,
+ uint64_t seg_bits);
static device_method_t storvsc_methods[] = {
/* Device interface */
@@ -207,7 +249,7 @@ MODULE_DEPEND(storvsc, vmbus, 1, 1, 1);
/**
- * The host is capable of sending messages to us that are
+ * The host is capable of sending messages to us that are
* completely unsolicited. So, we need to address the race
* condition where we may be in the process of unloading the
* driver when the host may send us an unsolicited message.
@@ -223,7 +265,7 @@ MODULE_DEPEND(storvsc, vmbus, 1, 1, 1);
* destroyed.
*
* 3. Once the device is marked as being destroyed, we only
- * permit incoming traffic to properly account for
+ * permit incoming traffic to properly account for
* packets already sent out.
*/
static inline struct storvsc_softc *
@@ -260,6 +302,113 @@ get_stor_device(struct hv_device *device,
}
/**
+ * @brief Callback handler, will be invoked when receive mutil-channel offer
+ *
+ * @param context new multi-channel
+ */
+static void
+storvsc_handle_sc_creation(void *context)
+{
+ hv_vmbus_channel *new_channel;
+ struct hv_device *device;
+ struct storvsc_softc *sc;
+ struct vmstor_chan_props props;
+ int ret = 0;
+
+ new_channel = (hv_vmbus_channel *)context;
+ device = new_channel->primary_channel->device;
+ sc = get_stor_device(device, TRUE);
+ if (sc == NULL)
+ return;
+
+ if (FALSE == sc->hs_open_multi_channel)
+ return;
+
+ memset(&props, 0, sizeof(props));
+
+ ret = hv_vmbus_channel_open(new_channel,
+ sc->hs_drv_props->drv_ringbuffer_size,
+ sc->hs_drv_props->drv_ringbuffer_size,
+ (void *)&props,
+ sizeof(struct vmstor_chan_props),
+ hv_storvsc_on_channel_callback,
+ new_channel);
+
+ return;
+}
+
+/**
+ * @brief Send multi-channel creation request to host
+ *
+ * @param device a Hyper-V device pointer
+ * @param max_chans the max channels supported by vmbus
+ */
+static void
+storvsc_send_multichannel_request(struct hv_device *dev, int max_chans)
+{
+ struct storvsc_softc *sc;
+ struct hv_storvsc_request *request;
+ struct vstor_packet *vstor_packet;
+ int request_channels_cnt = 0;
+ int ret;
+
+ /* get multichannels count that need to create */
+ request_channels_cnt = MIN(max_chans, mp_ncpus);
+
+ sc = get_stor_device(dev, TRUE);
+ if (sc == NULL) {
+ printf("Storvsc_error: get sc failed while send mutilchannel "
+ "request\n");
+ return;
+ }
+
+ request = &sc->hs_init_req;
+
+ /* Establish a handler for multi-channel */
+ dev->channel->sc_creation_callback = storvsc_handle_sc_creation;
+
+ /* request the host to create multi-channel */
+ memset(request, 0, sizeof(struct hv_storvsc_request));
+
+ sema_init(&request->synch_sema, 0, ("stor_synch_sema"));
+
+ vstor_packet = &request->vstor_packet;
+
+ vstor_packet->operation = VSTOR_OPERATION_CREATE_MULTI_CHANNELS;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+ vstor_packet->u.multi_channels_cnt = request_channels_cnt;
+
+ ret = hv_vmbus_channel_send_packet(
+ dev->channel,
+ vstor_packet,
+ sizeof(struct vstor_packet),
+ (uint64_t)(uintptr_t)request,
+ HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
+ HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+ /* wait for 5 seconds */
+ ret = sema_timedwait(&request->synch_sema, 5 * hz);
+ if (ret != 0) {
+ printf("Storvsc_error: create multi-channel timeout, %d\n",
+ ret);
+ return;
+ }
+
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
+ vstor_packet->status != 0) {
+ printf("Storvsc_error: create multi-channel invalid operation "
+ "(%d) or statue (%u)\n",
+ vstor_packet->operation, vstor_packet->status);
+ return;
+ }
+
+ sc->hs_open_multi_channel = TRUE;
+
+ if (bootverbose)
+ printf("Storvsc create multi-channel success!\n");
+}
+
+/**
* @brief initialize channel connection to parent partition
*
* @param dev a Hyper-V device pointer
@@ -272,11 +421,15 @@ hv_storvsc_channel_init(struct hv_device *dev)
struct hv_storvsc_request *request;
struct vstor_packet *vstor_packet;
struct storvsc_softc *sc;
+ uint16_t max_chans = 0;
+ boolean_t support_multichannel = FALSE;
+
+ max_chans = 0;
+ support_multichannel = FALSE;
sc = get_stor_device(dev, TRUE);
- if (sc == NULL) {
- return ENODEV;
- }
+ if (sc == NULL)
+ return (ENODEV);
request = &sc->hs_init_req;
memset(request, 0, sizeof(struct hv_storvsc_request));
@@ -300,15 +453,13 @@ hv_storvsc_channel_init(struct hv_device *dev)
HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
+ if (ret != 0)
goto cleanup;
- }
-
- ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
- if (ret != 0) {
+ /* wait 5 seconds */
+ ret = sema_timedwait(&request->synch_sema, 5 * hz);
+ if (ret != 0)
goto cleanup;
- }
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
vstor_packet->status != 0) {
@@ -321,7 +472,8 @@ hv_storvsc_channel_init(struct hv_device *dev)
vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
- vstor_packet->u.version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
+ vstor_packet->u.version.major_minor =
+ VMSTOR_PROTOCOL_VERSION(storvsc_current_major, storvsc_current_minor);
/* revision is only significant for Windows guests */
vstor_packet->u.version.revision = 0;
@@ -334,21 +486,19 @@ hv_storvsc_channel_init(struct hv_device *dev)
HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0) {
+ if (ret != 0)
goto cleanup;
- }
- ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
+ /* wait 5 seconds */
+ ret = sema_timedwait(&request->synch_sema, 5 * hz);
- if (ret) {
+ if (ret)
goto cleanup;
- }
/* TODO: Check returned version */
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
- vstor_packet->status != 0) {
+ vstor_packet->status != 0)
goto cleanup;
- }
/**
* Query channel properties
@@ -365,22 +515,30 @@ hv_storvsc_channel_init(struct hv_device *dev)
HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if ( ret != 0) {
+ if ( ret != 0)
goto cleanup;
- }
- ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
+ /* wait 5 seconds */
+ ret = sema_timedwait(&request->synch_sema, 5 * hz);
- if (ret != 0) {
+ if (ret != 0)
goto cleanup;
- }
/* TODO: Check returned version */
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
- vstor_packet->status != 0) {
+ vstor_packet->status != 0) {
goto cleanup;
}
+ /* multi-channels feature is supported by WIN8 and above version */
+ max_chans = vstor_packet->u.chan_props.max_channel_cnt;
+ if ((hv_vmbus_protocal_version != HV_VMBUS_VERSION_WIN7) &&
+ (hv_vmbus_protocal_version != HV_VMBUS_VERSION_WS2008) &&
+ (vstor_packet->u.chan_props.flags &
+ HV_STORAGE_SUPPORTS_MULTI_CHANNEL)) {
+ support_multichannel = TRUE;
+ }
+
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation = VSTOR_OPERATION_ENDINITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
@@ -397,16 +555,22 @@ hv_storvsc_channel_init(struct hv_device *dev)
goto cleanup;
}
- ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
+ /* wait 5 seconds */
+ ret = sema_timedwait(&request->synch_sema, 5 * hz);
- if (ret != 0) {
+ if (ret != 0)
goto cleanup;
- }
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
- vstor_packet->status != 0) {
+ vstor_packet->status != 0)
goto cleanup;
- }
+
+ /*
+ * If multi-channel is supported, send multichannel create
+ * request to host.
+ */
+ if (support_multichannel)
+ storvsc_send_multichannel_request(dev, max_chans);
cleanup:
sema_destroy(&request->synch_sema);
@@ -443,8 +607,7 @@ hv_storvsc_connect_vsp(struct hv_device *dev)
(void *)&props,
sizeof(struct vmstor_chan_props),
hv_storvsc_on_channel_callback,
- dev);
-
+ dev->channel);
if (ret != 0) {
return ret;
@@ -490,7 +653,7 @@ hv_storvsc_host_reset(struct hv_device *dev)
goto cleanup;
}
- ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
+ ret = sema_timedwait(&request->synch_sema, 5 * hz); /* KYS 5 seconds */
if (ret) {
goto cleanup;
@@ -498,7 +661,7 @@ hv_storvsc_host_reset(struct hv_device *dev)
/*
- * At this point, all outstanding requests in the adapter
+ * At this point, all outstanding requests in the adapter
* should have been flushed out and return to us
*/
@@ -521,6 +684,7 @@ hv_storvsc_io_request(struct hv_device *device,
{
struct storvsc_softc *sc;
struct vstor_packet *vstor_packet = &request->vstor_packet;
+ struct hv_vmbus_channel* outgoing_channel = NULL;
int ret = 0;
sc = get_stor_device(device, TRUE);
@@ -539,19 +703,20 @@ hv_storvsc_io_request(struct hv_device *device,
vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB;
+ outgoing_channel = vmbus_select_outgoing_channel(device->channel);
mtx_unlock(&request->softc->hs_lock);
if (request->data_buf.length) {
ret = hv_vmbus_channel_send_packet_multipagebuffer(
- device->channel,
+ outgoing_channel,
&request->data_buf,
- vstor_packet,
- sizeof(struct vstor_packet),
+ vstor_packet,
+ sizeof(struct vstor_packet),
(uint64_t)(uintptr_t)request);
} else {
ret = hv_vmbus_channel_send_packet(
- device->channel,
+ outgoing_channel,
vstor_packet,
sizeof(struct vstor_packet),
(uint64_t)(uintptr_t)request,
@@ -610,7 +775,8 @@ static void
hv_storvsc_on_channel_callback(void *context)
{
int ret = 0;
- struct hv_device *device = (struct hv_device *)context;
+ hv_vmbus_channel *channel = (hv_vmbus_channel *)context;
+ struct hv_device *device = NULL;
struct storvsc_softc *sc;
uint32_t bytes_recvd;
uint64_t request_id;
@@ -618,15 +784,22 @@ hv_storvsc_on_channel_callback(void *context)
struct hv_storvsc_request *request;
struct vstor_packet *vstor_packet;
+ if (channel->primary_channel != NULL){
+ device = channel->primary_channel->device;
+ } else {
+ device = channel->device;
+ }
+
+ KASSERT(device, ("device is NULL"));
+
sc = get_stor_device(device, FALSE);
if (sc == NULL) {
+ printf("Storvsc_error: get stor device failed.\n");
return;
}
- KASSERT(device, ("device"));
-
ret = hv_vmbus_channel_recv_packet(
- device->channel,
+ channel,
packet,
roundup2(sizeof(struct vstor_packet), 8),
&bytes_recvd,
@@ -634,21 +807,28 @@ hv_storvsc_on_channel_callback(void *context)
while ((ret == 0) && (bytes_recvd > 0)) {
request = (struct hv_storvsc_request *)(uintptr_t)request_id;
- KASSERT(request, ("request"));
if ((request == &sc->hs_init_req) ||
(request == &sc->hs_reset_req)) {
memcpy(&request->vstor_packet, packet,
sizeof(struct vstor_packet));
- sema_post(&request->synch_sema);
+ sema_post(&request->synch_sema);
} else {
vstor_packet = (struct vstor_packet *)packet;
switch(vstor_packet->operation) {
case VSTOR_OPERATION_COMPLETEIO:
+ if (request == NULL)
+ panic("VMBUS: storvsc received a "
+ "packet with NULL request id in "
+ "COMPLETEIO operation.");
+
hv_storvsc_on_iocompletion(sc,
vstor_packet, request);
break;
case VSTOR_OPERATION_REMOVEDEVICE:
+ case VSTOR_OPERATION_ENUMERATE_BUS:
+ printf("VMBUS: storvsc operation %d not "
+ "implemented.\n", vstor_packet->operation);
/* TODO: implement */
break;
default:
@@ -656,7 +836,7 @@ hv_storvsc_on_channel_callback(void *context)
}
}
ret = hv_vmbus_channel_recv_packet(
- device->channel,
+ channel,
packet,
roundup2(sizeof(struct vstor_packet), 8),
&bytes_recvd,
@@ -680,7 +860,16 @@ storvsc_probe(device_t dev)
{
int ata_disk_enable = 0;
int ret = ENXIO;
-
+
+ if ((HV_VMBUS_VERSION_WIN8 == hv_vmbus_protocal_version) ||
+ (HV_VMBUS_VERSION_WIN8_1 == hv_vmbus_protocal_version)){
+ storvsc_current_major = STORVSC_WIN8_MAJOR;
+ storvsc_current_minor = STORVSC_WIN8_MINOR;
+ } else {
+ storvsc_current_major = STORVSC_WIN7_MAJOR;
+ storvsc_current_minor = STORVSC_WIN7_MINOR;
+ }
+
switch (storvsc_get_storage_type(dev)) {
case DRIVER_BLKVSC:
if(bootverbose)
@@ -721,9 +910,11 @@ storvsc_attach(device_t dev)
enum hv_storage_type stor_type;
struct storvsc_softc *sc;
struct cam_devq *devq;
- int ret, i;
+ int ret, i, j;
struct hv_storvsc_request *reqp;
struct root_hold_token *root_mount_token = NULL;
+ struct hv_sgl_node *sgl_node = NULL;
+ void *tmp_buff = NULL;
/*
* We need to serialize storvsc attach calls.
@@ -764,8 +955,41 @@ storvsc_attach(device_t dev)
LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link);
}
+ /* create sg-list page pool */
+ if (FALSE == g_hv_sgl_page_pool.is_init) {
+ g_hv_sgl_page_pool.is_init = TRUE;
+ LIST_INIT(&g_hv_sgl_page_pool.in_use_sgl_list);
+ LIST_INIT(&g_hv_sgl_page_pool.free_sgl_list);
+
+ /*
+ * Pre-create SG list, each SG list with
+ * HV_MAX_MULTIPAGE_BUFFER_COUNT segments, each
+ * segment has one page buffer
+ */
+ for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++) {
+ sgl_node = malloc(sizeof(struct hv_sgl_node),
+ M_DEVBUF, M_WAITOK|M_ZERO);
+
+ sgl_node->sgl_data =
+ sglist_alloc(HV_MAX_MULTIPAGE_BUFFER_COUNT,
+ M_WAITOK|M_ZERO);
+
+ for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) {
+ tmp_buff = malloc(PAGE_SIZE,
+ M_DEVBUF, M_WAITOK|M_ZERO);
+
+ sgl_node->sgl_data->sg_segs[j].ss_paddr =
+ (vm_paddr_t)tmp_buff;
+ }
+
+ LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list,
+ sgl_node, link);
+ }
+ }
+
sc->hs_destroy = FALSE;
sc->hs_drain_notify = FALSE;
+ sc->hs_open_multi_channel = FALSE;
sema_init(&sc->hs_drain_sema, 0, "Store Drain Sema");
ret = hv_storvsc_connect_vsp(hv_dev);
@@ -834,6 +1058,20 @@ cleanup:
LIST_REMOVE(reqp, link);
free(reqp, M_DEVBUF);
}
+
+ while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
+ sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
+ LIST_REMOVE(sgl_node, link);
+ for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) {
+ if (NULL !=
+ (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) {
+ free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
+ }
+ }
+ sglist_free(sgl_node->sgl_data);
+ free(sgl_node, M_DEVBUF);
+ }
+
return (ret);
}
@@ -853,6 +1091,8 @@ storvsc_detach(device_t dev)
struct storvsc_softc *sc = device_get_softc(dev);
struct hv_storvsc_request *reqp = NULL;
struct hv_device *hv_device = vmbus_get_devctx(dev);
+ struct hv_sgl_node *sgl_node = NULL;
+ int j = 0;
mtx_lock(&hv_device->channel->inbound_lock);
sc->hs_destroy = TRUE;
@@ -884,6 +1124,20 @@ storvsc_detach(device_t dev)
free(reqp, M_DEVBUF);
}
mtx_unlock(&sc->hs_lock);
+
+ while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
+ sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
+ LIST_REMOVE(sgl_node, link);
+ for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){
+ if (NULL !=
+ (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) {
+ free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
+ }
+ }
+ sglist_free(sgl_node->sgl_data);
+ free(sgl_node, M_DEVBUF);
+ }
+
return (0);
}
@@ -939,7 +1193,7 @@ storvsc_timeout_test(struct hv_storvsc_request *reqp,
ticks, __func__, (ret == 0)?
"IO return detected" :
"IO return not detected");
- /*
+ /*
* Now both the timer handler and io done are running
* simultaneously. We want to confirm the io done always
* finishes after the timer handler exits. So reqp used by
@@ -1023,7 +1277,7 @@ storvsc_poll(struct cam_sim *sim)
mtx_assert(&sc->hs_lock, MA_OWNED);
mtx_unlock(&sc->hs_lock);
- hv_storvsc_on_channel_callback(sc->hs_dev);
+ hv_storvsc_on_channel_callback(sc->hs_dev->channel);
mtx_lock(&sc->hs_lock);
}
@@ -1151,9 +1405,13 @@ storvsc_action(struct cam_sim *sim, union ccb *ccb)
bzero(reqp, sizeof(struct hv_storvsc_request));
reqp->softc = sc;
-
- ccb->ccb_h.status |= CAM_SIM_QUEUED;
- create_storvsc_request(ccb, reqp);
+
+ ccb->ccb_h.status |= CAM_SIM_QUEUED;
+ if ((res = create_storvsc_request(ccb, reqp)) != 0) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
callout_init(&reqp->callout, CALLOUT_MPSAFE);
@@ -1194,6 +1452,212 @@ storvsc_action(struct cam_sim *sim, union ccb *ccb)
}
/**
+ * @brief destroy bounce buffer
+ *
+ * This function is responsible for destroy a Scatter/Gather list
+ * that create by storvsc_create_bounce_buffer()
+ *
+ * @param sgl- the Scatter/Gather need be destroy
+ * @param sg_count- page count of the SG list.
+ *
+ */
+static void
+storvsc_destroy_bounce_buffer(struct sglist *sgl)
+{
+ struct hv_sgl_node *sgl_node = NULL;
+
+ sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.in_use_sgl_list);
+ LIST_REMOVE(sgl_node, link);
+ if (NULL == sgl_node) {
+ printf("storvsc error: not enough in use sgl\n");
+ return;
+ }
+ sgl_node->sgl_data = sgl;
+ LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list, sgl_node, link);
+}
+
+/**
+ * @brief create bounce buffer
+ *
+ * This function is responsible for create a Scatter/Gather list,
+ * which hold several pages that can be aligned with page size.
+ *
+ * @param seg_count- SG-list segments count
+ * @param write - if WRITE_TYPE, set SG list page used size to 0,
+ * otherwise set used size to page size.
+ *
+ * return NULL if create failed
+ */
+static struct sglist *
+storvsc_create_bounce_buffer(uint16_t seg_count, int write)
+{
+ int i = 0;
+ struct sglist *bounce_sgl = NULL;
+ unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
+ struct hv_sgl_node *sgl_node = NULL;
+
+ /* get struct sglist from free_sgl_list */
+ sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
+ LIST_REMOVE(sgl_node, link);
+ if (NULL == sgl_node) {
+ printf("storvsc error: not enough free sgl\n");
+ return NULL;
+ }
+ bounce_sgl = sgl_node->sgl_data;
+ LIST_INSERT_HEAD(&g_hv_sgl_page_pool.in_use_sgl_list, sgl_node, link);
+
+ bounce_sgl->sg_maxseg = seg_count;
+
+ if (write == WRITE_TYPE)
+ bounce_sgl->sg_nseg = 0;
+ else
+ bounce_sgl->sg_nseg = seg_count;
+
+ for (i = 0; i < seg_count; i++)
+ bounce_sgl->sg_segs[i].ss_len = buf_len;
+
+ return bounce_sgl;
+}
+
+/**
+ * @brief copy data from SG list to bounce buffer
+ *
+ * This function is responsible for copy data from one SG list's segments
+ * to another SG list which used as bounce buffer.
+ *
+ * @param bounce_sgl - the destination SG list
+ * @param orig_sgl - the segment of the source SG list.
+ * @param orig_sgl_count - the count of segments.
+ * @param orig_sgl_count - indicate which segment need bounce buffer,
+ * set 1 means need.
+ *
+ */
+static void
+storvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl,
+ bus_dma_segment_t *orig_sgl,
+ unsigned int orig_sgl_count,
+ uint64_t seg_bits)
+{
+ int src_sgl_idx = 0;
+
+ for (src_sgl_idx = 0; src_sgl_idx < orig_sgl_count; src_sgl_idx++) {
+ if (seg_bits & (1 << src_sgl_idx)) {
+ memcpy((void*)bounce_sgl->sg_segs[src_sgl_idx].ss_paddr,
+ (void*)orig_sgl[src_sgl_idx].ds_addr,
+ orig_sgl[src_sgl_idx].ds_len);
+
+ bounce_sgl->sg_segs[src_sgl_idx].ss_len =
+ orig_sgl[src_sgl_idx].ds_len;
+ }
+ }
+}
+
+/**
+ * @brief copy data from SG list which used as bounce to another SG list
+ *
+ * This function is responsible for copy data from one SG list with bounce
+ * buffer to another SG list's segments.
+ *
+ * @param dest_sgl - the destination SG list's segments
+ * @param dest_sgl_count - the count of destination SG list's segment.
+ * @param src_sgl - the source SG list.
+ * @param seg_bits - indicate which segment used bounce buffer of src SG-list.
+ *
+ */
+void
+storvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl,
+ unsigned int dest_sgl_count,
+ struct sglist* src_sgl,
+ uint64_t seg_bits)
+{
+ int sgl_idx = 0;
+
+ for (sgl_idx = 0; sgl_idx < dest_sgl_count; sgl_idx++) {
+ if (seg_bits & (1 << sgl_idx)) {
+ memcpy((void*)(dest_sgl[sgl_idx].ds_addr),
+ (void*)(src_sgl->sg_segs[sgl_idx].ss_paddr),
+ src_sgl->sg_segs[sgl_idx].ss_len);
+ }
+ }
+}
+
+/**
+ * @brief check SG list with bounce buffer or not
+ *
+ * This function is responsible for check if need bounce buffer for SG list.
+ *
+ * @param sgl - the SG list's segments
+ * @param sg_count - the count of SG list's segment.
+ * @param bits - segmengs number that need bounce buffer
+ *
+ * return -1 if SG list needless bounce buffer
+ */
+static int
+storvsc_check_bounce_buffer_sgl(bus_dma_segment_t *sgl,
+ unsigned int sg_count,
+ uint64_t *bits)
+{
+ int i = 0;
+ int offset = 0;
+ uint64_t phys_addr = 0;
+ uint64_t tmp_bits = 0;
+ boolean_t found_hole = FALSE;
+ boolean_t pre_aligned = TRUE;
+
+ if (sg_count < 2){
+ return -1;
+ }
+
+ *bits = 0;
+
+ phys_addr = vtophys(sgl[0].ds_addr);
+ offset = phys_addr - trunc_page(phys_addr);
+
+ if (offset != 0) {
+ pre_aligned = FALSE;
+ tmp_bits |= 1;
+ }
+
+ for (i = 1; i < sg_count; i++) {
+ phys_addr = vtophys(sgl[i].ds_addr);
+ offset = phys_addr - trunc_page(phys_addr);
+
+ if (offset == 0) {
+ if (FALSE == pre_aligned){
+ /*
+ * This segment is aligned, if the previous
+ * one is not aligned, find a hole
+ */
+ found_hole = TRUE;
+ }
+ pre_aligned = TRUE;
+ } else {
+ tmp_bits |= 1 << i;
+ if (!pre_aligned) {
+ if (phys_addr != vtophys(sgl[i-1].ds_addr +
+ sgl[i-1].ds_len)) {
+ /*
+ * Check whether connect to previous
+ * segment,if not, find the hole
+ */
+ found_hole = TRUE;
+ }
+ } else {
+ found_hole = TRUE;
+ }
+ pre_aligned = FALSE;
+ }
+ }
+
+ if (!found_hole) {
+ return (-1);
+ } else {
+ *bits = tmp_bits;
+ return 0;
+ }
+}
+
+/**
* @brief Fill in a request structure based on a CAM control block
*
* Fills in a request structure based on the contents of a CAM control
@@ -1203,7 +1667,7 @@ storvsc_action(struct cam_sim *sim, union ccb *ccb)
* @param ccb pointer to a CAM contorl block
* @param reqp pointer to a request structure
*/
-static void
+static int
create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
{
struct ccb_scsiio *csio = &ccb->csio;
@@ -1211,6 +1675,7 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
uint32_t bytes_to_copy = 0;
uint32_t pfn_num = 0;
uint32_t pfn;
+ uint64_t not_aligned_seg_bits = 0;
/* refer to struct vmscsi_req for meanings of these two fields */
reqp->vstor_packet.u.vm_srb.port =
@@ -1231,48 +1696,172 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
}
switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
- case CAM_DIR_OUT:
- reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE;
- break;
- case CAM_DIR_IN:
- reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE;
- break;
- case CAM_DIR_NONE:
- reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
- break;
- default:
- reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
- break;
+ case CAM_DIR_OUT:
+ reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE;
+ break;
+ case CAM_DIR_IN:
+ reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE;
+ break;
+ case CAM_DIR_NONE:
+ reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
+ break;
+ default:
+ reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
+ break;
}
reqp->sense_data = &csio->sense_data;
reqp->sense_info_len = csio->sense_len;
reqp->ccb = ccb;
- /*
- KASSERT((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0,
- ("ccb is scatter gather valid\n"));
- */
- if (csio->dxfer_len != 0) {
- reqp->data_buf.length = csio->dxfer_len;
+
+ if (0 == csio->dxfer_len) {
+ return (0);
+ }
+
+ reqp->data_buf.length = csio->dxfer_len;
+
+ switch (ccb->ccb_h.flags & CAM_DATA_MASK) {
+ case CAM_DATA_VADDR:
+ {
bytes_to_copy = csio->dxfer_len;
phys_addr = vtophys(csio->data_ptr);
- reqp->data_buf.offset = phys_addr - trunc_page(phys_addr);
+ reqp->data_buf.offset = phys_addr & PAGE_MASK;
+
+ while (bytes_to_copy != 0) {
+ int bytes, page_offset;
+ phys_addr =
+ vtophys(&csio->data_ptr[reqp->data_buf.length -
+ bytes_to_copy]);
+ pfn = phys_addr >> PAGE_SHIFT;
+ reqp->data_buf.pfn_array[pfn_num] = pfn;
+ page_offset = phys_addr & PAGE_MASK;
+
+ bytes = min(PAGE_SIZE - page_offset, bytes_to_copy);
+
+ bytes_to_copy -= bytes;
+ pfn_num++;
+ }
+ break;
}
- while (bytes_to_copy != 0) {
- int bytes, page_offset;
- phys_addr = vtophys(&csio->data_ptr[reqp->data_buf.length -
- bytes_to_copy]);
- pfn = phys_addr >> PAGE_SHIFT;
- reqp->data_buf.pfn_array[pfn_num] = pfn;
- page_offset = phys_addr - trunc_page(phys_addr);
+ case CAM_DATA_SG:
+ {
+ int i = 0;
+ int offset = 0;
+ int ret;
+
+ bus_dma_segment_t *storvsc_sglist =
+ (bus_dma_segment_t *)ccb->csio.data_ptr;
+ u_int16_t storvsc_sg_count = ccb->csio.sglist_cnt;
+
+ printf("Storvsc: get SG I/O operation, %d\n",
+ reqp->vstor_packet.u.vm_srb.data_in);
+
+ if (storvsc_sg_count > HV_MAX_MULTIPAGE_BUFFER_COUNT){
+ printf("Storvsc: %d segments is too much, "
+ "only support %d segments\n",
+ storvsc_sg_count, HV_MAX_MULTIPAGE_BUFFER_COUNT);
+ return (EINVAL);
+ }
+
+ /*
+ * We create our own bounce buffer function currently. Idealy
+ * we should use BUS_DMA(9) framework. But with current BUS_DMA
+ * code there is no callback API to check the page alignment of
+ * middle segments before busdma can decide if a bounce buffer
+ * is needed for particular segment. There is callback,
+ * "bus_dma_filter_t *filter", but the parrameters are not
+ * sufficient for storvsc driver.
+ * TODO:
+ * Add page alignment check in BUS_DMA(9) callback. Once
+ * this is complete, switch the following code to use
+ * BUS_DMA(9) for storvsc bounce buffer support.
+ */
+ /* check if we need to create bounce buffer */
+ ret = storvsc_check_bounce_buffer_sgl(storvsc_sglist,
+ storvsc_sg_count, &not_aligned_seg_bits);
+ if (ret != -1) {
+ reqp->bounce_sgl =
+ storvsc_create_bounce_buffer(storvsc_sg_count,
+ reqp->vstor_packet.u.vm_srb.data_in);
+ if (NULL == reqp->bounce_sgl) {
+ printf("Storvsc_error: "
+ "create bounce buffer failed.\n");
+ return (ENOMEM);
+ }
+
+ reqp->bounce_sgl_count = storvsc_sg_count;
+ reqp->not_aligned_seg_bits = not_aligned_seg_bits;
+
+ /*
+ * if it is write, we need copy the original data
+ *to bounce buffer
+ */
+ if (WRITE_TYPE == reqp->vstor_packet.u.vm_srb.data_in) {
+ storvsc_copy_sgl_to_bounce_buf(
+ reqp->bounce_sgl,
+ storvsc_sglist,
+ storvsc_sg_count,
+ reqp->not_aligned_seg_bits);
+ }
+
+ /* transfer virtual address to physical frame number */
+ if (reqp->not_aligned_seg_bits & 0x1){
+ phys_addr =
+ vtophys(reqp->bounce_sgl->sg_segs[0].ss_paddr);
+ }else{
+ phys_addr =
+ vtophys(storvsc_sglist[0].ds_addr);
+ }
+ reqp->data_buf.offset = phys_addr & PAGE_MASK;
+
+ pfn = phys_addr >> PAGE_SHIFT;
+ reqp->data_buf.pfn_array[0] = pfn;
+
+ for (i = 1; i < storvsc_sg_count; i++) {
+ if (reqp->not_aligned_seg_bits & (1 << i)) {
+ phys_addr =
+ vtophys(reqp->bounce_sgl->sg_segs[i].ss_paddr);
+ } else {
+ phys_addr =
+ vtophys(storvsc_sglist[i].ds_addr);
+ }
+
+ pfn = phys_addr >> PAGE_SHIFT;
+ reqp->data_buf.pfn_array[i] = pfn;
+ }
+ } else {
+ phys_addr = vtophys(storvsc_sglist[0].ds_addr);
+
+ reqp->data_buf.offset = phys_addr & PAGE_MASK;
- bytes = min(PAGE_SIZE - page_offset, bytes_to_copy);
+ for (i = 0; i < storvsc_sg_count; i++) {
+ phys_addr = vtophys(storvsc_sglist[i].ds_addr);
+ pfn = phys_addr >> PAGE_SHIFT;
+ reqp->data_buf.pfn_array[i] = pfn;
+ }
- bytes_to_copy -= bytes;
- pfn_num++;
+ /* check the last segment cross boundary or not */
+ offset = phys_addr & PAGE_MASK;
+ if (offset) {
+ phys_addr =
+ vtophys(storvsc_sglist[i-1].ds_addr +
+ PAGE_SIZE - offset);
+ pfn = phys_addr >> PAGE_SHIFT;
+ reqp->data_buf.pfn_array[i] = pfn;
+ }
+
+ reqp->bounce_sgl_count = 0;
+ }
+ break;
+ }
+ default:
+ printf("Unknow flags: %d\n", ccb->ccb_h.flags);
+ return(EINVAL);
}
+
+ return(0);
}
/**
@@ -1291,7 +1880,29 @@ storvsc_io_done(struct hv_storvsc_request *reqp)
struct ccb_scsiio *csio = &ccb->csio;
struct storvsc_softc *sc = reqp->softc;
struct vmscsi_req *vm_srb = &reqp->vstor_packet.u.vm_srb;
-
+ bus_dma_segment_t *ori_sglist = NULL;
+ int ori_sg_count = 0;
+
+ /* destroy bounce buffer if it is used */
+ if (reqp->bounce_sgl_count) {
+ ori_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr;
+ ori_sg_count = ccb->csio.sglist_cnt;
+
+ /*
+ * If it is READ operation, we should copy back the data
+ * to original SG list.
+ */
+ if (READ_TYPE == reqp->vstor_packet.u.vm_srb.data_in) {
+ storvsc_copy_from_bounce_buf_to_sgl(ori_sglist,
+ ori_sg_count,
+ reqp->bounce_sgl,
+ reqp->not_aligned_seg_bits);
+ }
+
+ storvsc_destroy_bounce_buffer(reqp->bounce_sgl);
+ reqp->bounce_sgl_count = 0;
+ }
+
if (reqp->retries > 0) {
mtx_lock(&sc->hs_lock);
#if HVS_TIMEOUT_TEST
@@ -1309,7 +1920,7 @@ storvsc_io_done(struct hv_storvsc_request *reqp)
mtx_unlock(&sc->hs_lock);
}
- /*
+ /*
* callout_drain() will wait for the timer handler to finish
* if it is running. So we don't need any lock to synchronize
* between this routine and the timer handler.
diff --git a/sys/dev/hyperv/storvsc/hv_vstorage.h b/sys/dev/hyperv/storvsc/hv_vstorage.h
index 2632676..deb9183 100644
--- a/sys/dev/hyperv/storvsc/hv_vstorage.h
+++ b/sys/dev/hyperv/storvsc/hv_vstorage.h
@@ -53,7 +53,7 @@
* V1 RC > 2008/1/31 2.0
*/
-#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(2, 0)
+#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(5, 1)
/**
* Packet structure ops describing virtual storage requests.
@@ -69,7 +69,10 @@ enum vstor_packet_ops {
VSTOR_OPERATION_ENDINITIALIZATION = 8,
VSTOR_OPERATION_QUERYPROTOCOLVERSION = 9,
VSTOR_OPERATION_QUERYPROPERTIES = 10,
- VSTOR_OPERATION_MAXIMUM = 10
+ VSTOR_OPERATION_ENUMERATE_BUS = 11,
+ VSTOR_OPERATION_FCHBA_DATA = 12,
+ VSTOR_OPERATION_CREATE_MULTI_CHANNELS = 13,
+ VSTOR_OPERATION_MAXIMUM = 13
};
@@ -123,10 +126,12 @@ struct vmstor_chan_props {
uint8_t path_id;
uint8_t target_id;
+ uint16_t max_channel_cnt;
+
/**
* Note: port number is only really known on the client side
*/
- uint32_t port;
+ uint16_t port;
uint32_t flags;
uint32_t max_transfer_bytes;
@@ -193,6 +198,11 @@ struct vstor_packet {
* Used during version negotiations.
*/
struct vmstor_proto_ver version;
+
+ /**
+ * Number of multichannels to create
+ */
+ uint16_t multi_channels_cnt;
} u;
} __packed;
diff --git a/sys/dev/hyperv/utilities/hv_kvp.c b/sys/dev/hyperv/utilities/hv_kvp.c
index 848d364..4598510 100644
--- a/sys/dev/hyperv/utilities/hv_kvp.c
+++ b/sys/dev/hyperv/utilities/hv_kvp.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/_null.h>
#include <sys/signal.h>
#include <sys/syslog.h>
+#include <sys/systm.h>
#include <sys/mutex.h>
#include <net/if_arp.h>
@@ -232,7 +233,7 @@ hv_kvp_negotiate_version(struct hv_vmbus_icmsg_hdr *icmsghdrp,
*/
if ((icframe_vercnt >= 2) && (negop->icversion_data[1].major == 3)) {
icframe_vercnt = 3;
- if (icmsg_vercnt >= 2)
+ if (icmsg_vercnt > 2)
icmsg_vercnt = 4;
else
icmsg_vercnt = 3;
@@ -734,8 +735,8 @@ hv_kvp_process_request(void *context)
recvlen = 0;
ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE,
&recvlen, &requestid);
- hv_kvp_log_info("%s: read: context %p, pending_cnt %ju ret =%d, recvlen=%d\n",
- __func__, context, pending_cnt, ret, recvlen);
+ hv_kvp_log_info("%s: read: context %p, pending_cnt %llu ret =%d, recvlen=%d\n",
+ __func__, context, (unsigned long long)pending_cnt, ret, recvlen);
}
}
@@ -813,9 +814,9 @@ static void
hv_kvp_dev_destroy(void)
{
- if (daemon_task != NULL) {
+ if (daemon_task != NULL) {
PROC_LOCK(daemon_task);
- kern_psignal(daemon_task, SIGKILL);
+ kern_psignal(daemon_task, SIGKILL);
PROC_UNLOCK(daemon_task);
}
diff --git a/sys/dev/hyperv/utilities/hv_util.c b/sys/dev/hyperv/utilities/hv_util.c
index 3e545cf..dc4b1e2 100644
--- a/sys/dev/hyperv/utilities/hv_util.c
+++ b/sys/dev/hyperv/utilities/hv_util.c
@@ -408,6 +408,15 @@ hv_util_attach(device_t dev)
}
}
+ /*
+ * These services are not performance critical and do not need
+ * batched reading. Furthermore, some services such as KVP can
+ * only handle one message from the host at a time.
+ * Turn off batched reading for all util drivers before we open the
+ * channel.
+ */
+ hv_set_channel_read_state(hv_dev->channel, FALSE);
+
ret = hv_vmbus_channel_open(hv_dev->channel, 4 * PAGE_SIZE,
4 * PAGE_SIZE, NULL, 0,
service->callback, hv_dev->channel);
diff --git a/sys/dev/hyperv/vmbus/hv_channel.c b/sys/dev/hyperv/vmbus/hv_channel.c
index 103260a..94137fb 100644
--- a/sys/dev/hyperv/vmbus/hv_channel.c
+++ b/sys/dev/hyperv/vmbus/hv_channel.c
@@ -75,7 +75,7 @@ vmbus_channel_set_event(hv_vmbus_channel *channel)
(uint32_t *)&monitor_page->
trigger_group[channel->monitor_group].u.pending);
} else {
- hv_vmbus_set_event(channel->offer_msg.child_rel_id);
+ hv_vmbus_set_event(channel);
}
}
@@ -99,6 +99,18 @@ hv_vmbus_channel_open(
hv_vmbus_channel_open_channel* open_msg;
hv_vmbus_channel_msg_info* open_info;
+ mtx_lock(&new_channel->sc_lock);
+ if (new_channel->state == HV_CHANNEL_OPEN_STATE) {
+ new_channel->state = HV_CHANNEL_OPENING_STATE;
+ } else {
+ mtx_unlock(&new_channel->sc_lock);
+ if(bootverbose)
+ printf("VMBUS: Trying to open channel <%p> which in "
+ "%d state.\n", new_channel, new_channel->state);
+ return (EINVAL);
+ }
+ mtx_unlock(&new_channel->sc_lock);
+
new_channel->on_channel_callback = pfn_on_channel_callback;
new_channel->channel_callback_context = context;
@@ -162,7 +174,7 @@ hv_vmbus_channel_open(
new_channel->ring_buffer_gpadl_handle;
open_msg->downstream_ring_buffer_page_offset = send_ring_buffer_size
>> PAGE_SHIFT;
- open_msg->server_context_area_gpadl_handle = 0;
+ open_msg->target_vcpu = new_channel->target_vcpu;
if (user_data_len)
memcpy(open_msg->user_data, user_data, user_data_len);
@@ -182,10 +194,14 @@ hv_vmbus_channel_open(
ret = sema_timedwait(&open_info->wait_sema, 500); /* KYS 5 seconds */
- if (ret)
+ if (ret) {
+ if(bootverbose)
+ printf("VMBUS: channel <%p> open timeout.\n", new_channel);
goto cleanup;
+ }
if (open_info->response.open_result.status == 0) {
+ new_channel->state = HV_CHANNEL_OPENED_STATE;
if(bootverbose)
printf("VMBUS: channel <%p> open success.\n", new_channel);
} else {
@@ -497,16 +513,20 @@ cleanup:
return (ret);
}
-/**
- * @brief Close the specified channel
- */
-void
-hv_vmbus_channel_close(hv_vmbus_channel *channel)
+static void
+hv_vmbus_channel_close_internal(hv_vmbus_channel *channel)
{
int ret = 0;
hv_vmbus_channel_close_channel* msg;
hv_vmbus_channel_msg_info* info;
+ channel->state = HV_CHANNEL_OPEN_STATE;
+ channel->sc_creation_callback = NULL;
+
+ /*
+ * Grab the lock to prevent race condition when a packet received
+ * and unloading driver is in the process.
+ */
mtx_lock(&channel->inbound_lock);
channel->on_channel_callback = NULL;
mtx_unlock(&channel->inbound_lock);
@@ -545,23 +565,37 @@ hv_vmbus_channel_close(hv_vmbus_channel *channel)
M_DEVBUF);
free(info, M_DEVBUF);
+}
+
+/**
+ * @brief Close the specified channel
+ */
+void
+hv_vmbus_channel_close(hv_vmbus_channel *channel)
+{
+ hv_vmbus_channel* sub_channel;
+
+ if (channel->primary_channel != NULL) {
+ /*
+ * We only close multi-channels when the primary is
+ * closed.
+ */
+ return;
+ }
/*
- * If we are closing the channel during an error path in
- * opening the channel, don't free the channel
- * since the caller will free the channel
+ * Close all multi-channels first.
*/
- if (channel->state == HV_CHANNEL_OPEN_STATE) {
- mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
- TAILQ_REMOVE(
- &hv_vmbus_g_connection.channel_anchor,
- channel,
- list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
-
- hv_vmbus_free_vmbus_channel(channel);
+ TAILQ_FOREACH(sub_channel, &channel->sc_list_anchor,
+ sc_list_entry) {
+ if (sub_channel->state != HV_CHANNEL_OPENED_STATE)
+ continue;
+ hv_vmbus_channel_close_internal(sub_channel);
}
-
+ /*
+ * Then close the primary channel.
+ */
+ hv_vmbus_channel_close_internal(channel);
}
/**
@@ -581,6 +615,7 @@ hv_vmbus_channel_send_packet(
uint32_t packet_len;
uint64_t aligned_data;
uint32_t packet_len_aligned;
+ boolean_t need_sig;
hv_vmbus_sg_buffer_list buffer_list[3];
packet_len = sizeof(hv_vm_packet_descriptor) + buffer_len;
@@ -604,12 +639,11 @@ hv_vmbus_channel_send_packet(
buffer_list[2].data = &aligned_data;
buffer_list[2].length = packet_len_aligned - packet_len;
- ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3);
+ ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3,
+ &need_sig);
/* TODO: We should determine if this is optional */
- if (ret == 0
- && !hv_vmbus_get_ring_buffer_interrupt_mask(
- &channel->outbound)) {
+ if (ret == 0 && need_sig) {
vmbus_channel_set_event(channel);
}
@@ -632,6 +666,7 @@ hv_vmbus_channel_send_packet_pagebuffer(
int ret = 0;
int i = 0;
+ boolean_t need_sig;
uint32_t packet_len;
uint32_t packetLen_aligned;
hv_vmbus_sg_buffer_list buffer_list[3];
@@ -675,11 +710,11 @@ hv_vmbus_channel_send_packet_pagebuffer(
buffer_list[2].data = &alignedData;
buffer_list[2].length = packetLen_aligned - packet_len;
- ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3);
+ ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3,
+ &need_sig);
/* TODO: We should determine if this is optional */
- if (ret == 0 &&
- !hv_vmbus_get_ring_buffer_interrupt_mask(&channel->outbound)) {
+ if (ret == 0 && need_sig) {
vmbus_channel_set_event(channel);
}
@@ -700,6 +735,7 @@ hv_vmbus_channel_send_packet_multipagebuffer(
int ret = 0;
uint32_t desc_size;
+ boolean_t need_sig;
uint32_t packet_len;
uint32_t packet_len_aligned;
uint32_t pfn_count;
@@ -750,11 +786,11 @@ hv_vmbus_channel_send_packet_multipagebuffer(
buffer_list[2].data = &aligned_data;
buffer_list[2].length = packet_len_aligned - packet_len;
- ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3);
+ ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3,
+ &need_sig);
/* TODO: We should determine if this is optional */
- if (ret == 0 &&
- !hv_vmbus_get_ring_buffer_interrupt_mask(&channel->outbound)) {
+ if (ret == 0 && need_sig) {
vmbus_channel_set_event(channel);
}
diff --git a/sys/dev/hyperv/vmbus/hv_channel_mgmt.c b/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
index 011e305..783f6bc 100644
--- a/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
+++ b/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
@@ -50,6 +50,8 @@ static void vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_process_offer(void *context);
+struct hv_vmbus_channel*
+ vmbus_select_outgoing_channel(struct hv_vmbus_channel *promary);
/**
* Channel message dispatch table
@@ -233,6 +235,9 @@ hv_vmbus_allocate_channel(void)
return (NULL);
mtx_init(&channel->inbound_lock, "channel inbound", NULL, MTX_DEF);
+ mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF);
+
+ TAILQ_INIT(&channel->sc_list_anchor);
channel->control_work_queue = hv_work_queue_create("control");
@@ -262,6 +267,7 @@ ReleaseVmbusChannel(void *context)
void
hv_vmbus_free_vmbus_channel(hv_vmbus_channel* channel)
{
+ mtx_destroy(&channel->sc_lock);
mtx_destroy(&channel->inbound_lock);
/*
* We have to release the channel's workqueue/thread in
@@ -279,10 +285,10 @@ hv_vmbus_free_vmbus_channel(hv_vmbus_channel* channel)
static void
vmbus_channel_process_offer(void *context)
{
- int ret;
hv_vmbus_channel* new_channel;
boolean_t f_new;
hv_vmbus_channel* channel;
+ int ret;
new_channel = (hv_vmbus_channel*) context;
f_new = TRUE;
@@ -291,38 +297,76 @@ vmbus_channel_process_offer(void *context)
/*
* Make sure this is a new offer
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_lock);
TAILQ_FOREACH(channel, &hv_vmbus_g_connection.channel_anchor,
list_entry)
{
- if (!memcmp(
- &channel->offer_msg.offer.interface_type,
- &new_channel->offer_msg.offer.interface_type,
- sizeof(hv_guid))
- && !memcmp(
- &channel->offer_msg.offer.interface_instance,
+ if (memcmp(&channel->offer_msg.offer.interface_type,
+ &new_channel->offer_msg.offer.interface_type,
+ sizeof(hv_guid)) == 0 &&
+ memcmp(&channel->offer_msg.offer.interface_instance,
&new_channel->offer_msg.offer.interface_instance,
- sizeof(hv_guid))) {
- f_new = FALSE;
- break;
- }
+ sizeof(hv_guid)) == 0) {
+ f_new = FALSE;
+ break;
+ }
}
if (f_new) {
- /* Insert at tail */
- TAILQ_INSERT_TAIL(
- &hv_vmbus_g_connection.channel_anchor,
- new_channel,
- list_entry);
+ /* Insert at tail */
+ TAILQ_INSERT_TAIL(
+ &hv_vmbus_g_connection.channel_anchor,
+ new_channel,
+ list_entry);
}
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_lock);
+
+ /*XXX add new channel to percpu_list */
if (!f_new) {
+ /*
+ * Check if this is a sub channel.
+ */
+ if (new_channel->offer_msg.offer.sub_channel_index != 0) {
+ /*
+ * It is a sub channel offer, process it.
+ */
+ new_channel->primary_channel = channel;
+ mtx_lock(&channel->sc_lock);
+ TAILQ_INSERT_TAIL(
+ &channel->sc_list_anchor,
+ new_channel,
+ sc_list_entry);
+ mtx_unlock(&channel->sc_lock);
+
+ /* Insert new channel into channel_anchor. */
+ printf("Storvsc get multi-channel offer, rel=%u.\n",
+ new_channel->offer_msg.child_rel_id);
+ mtx_lock(&hv_vmbus_g_connection.channel_lock);
+ TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_anchor,
+ new_channel, list_entry);
+ mtx_unlock(&hv_vmbus_g_connection.channel_lock);
+
+ if(bootverbose)
+ printf("VMBUS: new multi-channel offer <%p>.\n",
+ new_channel);
+
+ /*XXX add it to percpu_list */
+
+ new_channel->state = HV_CHANNEL_OPEN_STATE;
+ if (channel->sc_creation_callback != NULL) {
+ channel->sc_creation_callback(new_channel);
+ }
+ return;
+ }
+
hv_vmbus_free_vmbus_channel(new_channel);
return;
}
+ new_channel->state = HV_CHANNEL_OPEN_STATE;
+
/*
* Start the process of binding this offer to the driver
* (We need to set the device field before calling
@@ -333,35 +377,86 @@ vmbus_channel_process_offer(void *context)
new_channel->offer_msg.offer.interface_instance, new_channel);
/*
- * TODO - the HV_CHANNEL_OPEN_STATE flag should not be set below
- * but in the "open" channel request. The ret != 0 logic below
- * doesn't take into account that a channel
- * may have been opened successfully
- */
-
- /*
* Add the new device to the bus. This will kick off device-driver
* binding which eventually invokes the device driver's AddDevice()
* method.
*/
ret = hv_vmbus_child_device_register(new_channel->device);
if (ret != 0) {
- mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
- TAILQ_REMOVE(
- &hv_vmbus_g_connection.channel_anchor,
- new_channel,
- list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
- hv_vmbus_free_vmbus_channel(new_channel);
- } else {
- /*
- * This state is used to indicate a successful open
- * so that when we do close the channel normally,
- * we can clean up properly
- */
- new_channel->state = HV_CHANNEL_OPEN_STATE;
+ mtx_lock(&hv_vmbus_g_connection.channel_lock);
+ TAILQ_REMOVE(
+ &hv_vmbus_g_connection.channel_anchor,
+ new_channel,
+ list_entry);
+ mtx_unlock(&hv_vmbus_g_connection.channel_lock);
+ hv_vmbus_free_vmbus_channel(new_channel);
+ }
+}
+
+/**
+ * Array of device guids that are performance critical. We try to distribute
+ * the interrupt load for these devices across all online cpus.
+ */
+static const hv_guid high_perf_devices[] = {
+ {HV_NIC_GUID, },
+ {HV_IDE_GUID, },
+ {HV_SCSI_GUID, },
+};
+
+enum {
+ PERF_CHN_NIC = 0,
+ PERF_CHN_IDE,
+ PERF_CHN_SCSI,
+ MAX_PERF_CHN,
+};
+/*
+ * We use this static number to distribute the channel interrupt load.
+ */
+static uint32_t next_vcpu;
+
+/**
+ * Starting with Win8, we can statically distribute the incoming
+ * channel interrupt load by binding a channel to VCPU. We
+ * implement here a simple round robin scheme for distributing
+ * the interrupt load.
+ * We will bind channels that are not performance critical to cpu 0 and
+ * performance critical channels (IDE, SCSI and Network) will be uniformly
+ * distributed across all available CPUs.
+ */
+static void
+vmbus_channel_select_cpu(hv_vmbus_channel *channel, hv_guid *guid)
+{
+ uint32_t current_cpu;
+ int i;
+ boolean_t is_perf_channel = FALSE;
+
+ for (i = PERF_CHN_NIC; i < MAX_PERF_CHN; i++) {
+ if (memcmp(guid->data, high_perf_devices[i].data,
+ sizeof(hv_guid)) == 0) {
+ is_perf_channel = TRUE;
+ break;
+ }
+ }
+
+ if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
+ (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) ||
+ (!is_perf_channel)) {
+ /* Host's view of guest cpu */
+ channel->target_vcpu = 0;
+ /* Guest's own view of cpu */
+ channel->target_cpu = 0;
+ return;
}
+ /* mp_ncpus should have the number cpus currently online */
+ current_cpu = (++next_vcpu % mp_ncpus);
+ channel->target_cpu = current_cpu;
+ channel->target_vcpu =
+ hv_vmbus_g_context.hv_vcpu_index[current_cpu];
+ if (bootverbose)
+ printf("VMBUS: Total online cpus %d, assign perf channel %d "
+ "to vcpu %d, cpu %d\n", mp_ncpus, i, channel->target_vcpu,
+ current_cpu);
}
/**
@@ -391,6 +486,38 @@ vmbus_channel_on_offer(hv_vmbus_channel_msg_header* hdr)
if (new_channel == NULL)
return;
+ /*
+ * By default we setup state to enable batched
+ * reading. A specific service can choose to
+ * disable this prior to opening the channel.
+ */
+ new_channel->batched_reading = TRUE;
+
+ new_channel->signal_event_param =
+ (hv_vmbus_input_signal_event *)
+ (HV_ALIGN_UP((unsigned long)
+ &new_channel->signal_event_buffer,
+ HV_HYPERCALL_PARAM_ALIGN));
+
+ new_channel->signal_event_param->connection_id.as_uint32_t = 0;
+ new_channel->signal_event_param->connection_id.u.id =
+ HV_VMBUS_EVENT_CONNECTION_ID;
+ new_channel->signal_event_param->flag_number = 0;
+ new_channel->signal_event_param->rsvd_z = 0;
+
+ if (hv_vmbus_protocal_version != HV_VMBUS_VERSION_WS2008) {
+ new_channel->is_dedicated_interrupt =
+ (offer->is_dedicated_interrupt != 0);
+ new_channel->signal_event_param->connection_id.u.id =
+ offer->connection_id;
+ }
+
+ /*
+ * Bind the channel to a chosen cpu.
+ */
+ vmbus_channel_select_cpu(new_channel,
+ &offer->offer.interface_type);
+
memcpy(&new_channel->offer_msg, offer,
sizeof(hv_vmbus_channel_offer_channel));
new_channel->monitor_group = (uint8_t) offer->monitor_id / 32;
@@ -666,7 +793,7 @@ hv_vmbus_release_unattached_channels(void)
{
hv_vmbus_channel *channel;
- mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_lock);
while (!TAILQ_EMPTY(&hv_vmbus_g_connection.channel_anchor)) {
channel = TAILQ_FIRST(&hv_vmbus_g_connection.channel_anchor);
@@ -676,5 +803,61 @@ hv_vmbus_release_unattached_channels(void)
hv_vmbus_child_device_unregister(channel->device);
hv_vmbus_free_vmbus_channel(channel);
}
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_lock);
+}
+
+/**
+ * @brief Select the best outgoing channel
+ *
+ * The channel whose vcpu binding is closest to the currect vcpu will
+ * be selected.
+ * If no multi-channel, always select primary channel
+ *
+ * @param primary - primary channel
+ */
+struct hv_vmbus_channel *
+vmbus_select_outgoing_channel(struct hv_vmbus_channel *primary)
+{
+ hv_vmbus_channel *new_channel = NULL;
+ hv_vmbus_channel *outgoing_channel = primary;
+ int old_cpu_distance = 0;
+ int new_cpu_distance = 0;
+ int cur_vcpu = 0;
+ int smp_pro_id = PCPU_GET(cpuid);
+
+ if (TAILQ_EMPTY(&primary->sc_list_anchor)) {
+ return outgoing_channel;
+ }
+
+ if (smp_pro_id >= MAXCPU) {
+ return outgoing_channel;
+ }
+
+ cur_vcpu = hv_vmbus_g_context.hv_vcpu_index[smp_pro_id];
+
+ TAILQ_FOREACH(new_channel, &primary->sc_list_anchor, sc_list_entry) {
+ if (new_channel->state != HV_CHANNEL_OPENED_STATE){
+ continue;
+ }
+
+ if (new_channel->target_vcpu == cur_vcpu){
+ return new_channel;
+ }
+
+ old_cpu_distance = ((outgoing_channel->target_vcpu > cur_vcpu) ?
+ (outgoing_channel->target_vcpu - cur_vcpu) :
+ (cur_vcpu - outgoing_channel->target_vcpu));
+
+ new_cpu_distance = ((new_channel->target_vcpu > cur_vcpu) ?
+ (new_channel->target_vcpu - cur_vcpu) :
+ (cur_vcpu - new_channel->target_vcpu));
+
+ if (old_cpu_distance < new_cpu_distance) {
+ continue;
+ }
+
+ outgoing_channel = new_channel;
+ }
+
+ return(outgoing_channel);
}
diff --git a/sys/dev/hyperv/vmbus/hv_connection.c b/sys/dev/hyperv/vmbus/hv_connection.c
index c8e0b48..0300828 100644
--- a/sys/dev/hyperv/vmbus/hv_connection.c
+++ b/sys/dev/hyperv/vmbus/hv_connection.c
@@ -45,14 +45,113 @@ hv_vmbus_connection hv_vmbus_g_connection =
{ .connect_state = HV_DISCONNECTED,
.next_gpadl_handle = 0xE1E10, };
+uint32_t hv_vmbus_protocal_version = HV_VMBUS_VERSION_WS2008;
+
+static uint32_t
+hv_vmbus_get_next_version(uint32_t current_ver)
+{
+ switch (current_ver) {
+ case (HV_VMBUS_VERSION_WIN7):
+ return(HV_VMBUS_VERSION_WS2008);
+
+ case (HV_VMBUS_VERSION_WIN8):
+ return(HV_VMBUS_VERSION_WIN7);
+
+ case (HV_VMBUS_VERSION_WIN8_1):
+ return(HV_VMBUS_VERSION_WIN8);
+
+ case (HV_VMBUS_VERSION_WS2008):
+ default:
+ return(HV_VMBUS_VERSION_INVALID);
+ }
+}
+
+/**
+ * Negotiate the highest supported hypervisor version.
+ */
+static int
+hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
+ uint32_t version)
+{
+ int ret = 0;
+ hv_vmbus_channel_initiate_contact *msg;
+
+ sema_init(&msg_info->wait_sema, 0, "Msg Info Sema");
+ msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg;
+
+ msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
+ msg->vmbus_version_requested = version;
+
+ msg->interrupt_page = hv_get_phys_addr(
+ hv_vmbus_g_connection.interrupt_page);
+
+ msg->monitor_page_1 = hv_get_phys_addr(
+ hv_vmbus_g_connection.monitor_pages);
+
+ msg->monitor_page_2 =
+ hv_get_phys_addr(
+ ((uint8_t *) hv_vmbus_g_connection.monitor_pages
+ + PAGE_SIZE));
+
+ /**
+ * Add to list before we send the request since we may receive the
+ * response before returning from this routine
+ */
+ mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+
+ TAILQ_INSERT_TAIL(
+ &hv_vmbus_g_connection.channel_msg_anchor,
+ msg_info,
+ msg_list_entry);
+
+ mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+
+ ret = hv_vmbus_post_message(
+ msg,
+ sizeof(hv_vmbus_channel_initiate_contact));
+
+ if (ret != 0) {
+ mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ TAILQ_REMOVE(
+ &hv_vmbus_g_connection.channel_msg_anchor,
+ msg_info,
+ msg_list_entry);
+ mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ return (ret);
+ }
+
+ /**
+ * Wait for the connection response
+ */
+ ret = sema_timedwait(&msg_info->wait_sema, 500); /* KYS 5 seconds */
+
+ mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ TAILQ_REMOVE(
+ &hv_vmbus_g_connection.channel_msg_anchor,
+ msg_info,
+ msg_list_entry);
+ mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+
+ /**
+ * Check if successful
+ */
+ if (msg_info->response.version_response.version_supported) {
+ hv_vmbus_g_connection.connect_state = HV_CONNECTED;
+ } else {
+ ret = ECONNREFUSED;
+ }
+
+ return (ret);
+}
+
/**
* Send a connect request on the partition service connection
*/
int
hv_vmbus_connect(void) {
int ret = 0;
+ uint32_t version;
hv_vmbus_channel_msg_info* msg_info = NULL;
- hv_vmbus_channel_initiate_contact* msg;
/**
* Make sure we are not connecting or connected
@@ -74,7 +173,7 @@ hv_vmbus_connect(void) {
TAILQ_INIT(&hv_vmbus_g_connection.channel_anchor);
mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel",
- NULL, MTX_SPIN);
+ NULL, MTX_DEF);
/**
* Setup the vmbus event connection for channel interrupt abstraction
@@ -130,71 +229,30 @@ hv_vmbus_connect(void) {
goto cleanup;
}
- sema_init(&msg_info->wait_sema, 0, "Msg Info Sema");
- msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg;
-
- msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
- msg->vmbus_version_requested = HV_VMBUS_REVISION_NUMBER;
-
- msg->interrupt_page = hv_get_phys_addr(
- hv_vmbus_g_connection.interrupt_page);
-
- msg->monitor_page_1 = hv_get_phys_addr(
- hv_vmbus_g_connection.monitor_pages);
-
- msg->monitor_page_2 =
- hv_get_phys_addr(
- ((uint8_t *) hv_vmbus_g_connection.monitor_pages
- + PAGE_SIZE));
-
- /**
- * Add to list before we send the request since we may receive the
- * response before returning from this routine
+ /*
+ * Find the highest vmbus version number we can support.
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
-
- TAILQ_INSERT_TAIL(
- &hv_vmbus_g_connection.channel_msg_anchor,
- msg_info,
- msg_list_entry);
-
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
-
- ret = hv_vmbus_post_message(
- msg,
- sizeof(hv_vmbus_channel_initiate_contact));
-
- if (ret != 0) {
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
- TAILQ_REMOVE(
- &hv_vmbus_g_connection.channel_msg_anchor,
- msg_info,
- msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
- goto cleanup;
- }
+ version = HV_VMBUS_VERSION_CURRENT;
+
+ do {
+ ret = hv_vmbus_negotiate_version(msg_info, version);
+ if (ret == EWOULDBLOCK) {
+ /*
+ * We timed out.
+ */
+ goto cleanup;
+ }
- /**
- * Wait for the connection response
- */
- ret = sema_timedwait(&msg_info->wait_sema, 500); /* KYS 5 seconds */
+ if (hv_vmbus_g_connection.connect_state == HV_CONNECTED)
+ break;
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
- TAILQ_REMOVE(
- &hv_vmbus_g_connection.channel_msg_anchor,
- msg_info,
- msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ version = hv_vmbus_get_next_version(version);
+ } while (version != HV_VMBUS_VERSION_INVALID);
- /**
- * Check if successful
- */
- if (msg_info->response.version_response.version_supported) {
- hv_vmbus_g_connection.connect_state = HV_CONNECTED;
- } else {
- ret = ECONNREFUSED;
- goto cleanup;
- }
+ hv_vmbus_protocal_version = version;
+ if (bootverbose)
+ printf("VMBUS: Portocal Version: %d.%d\n",
+ version >> 16, version & 0xFFFF);
sema_destroy(&msg_info->wait_sema);
free(msg_info, M_DEVBUF);
@@ -286,7 +344,7 @@ hv_vmbus_get_channel_from_rel_id(uint32_t rel_id) {
* and channels are accessed without the need to take this lock or search
* the list.
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_lock);
TAILQ_FOREACH(channel,
&hv_vmbus_g_connection.channel_anchor, list_entry) {
@@ -295,7 +353,7 @@ hv_vmbus_get_channel_from_rel_id(uint32_t rel_id) {
break;
}
}
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_lock);
return (foundChannel);
}
@@ -306,7 +364,10 @@ hv_vmbus_get_channel_from_rel_id(uint32_t rel_id) {
static void
VmbusProcessChannelEvent(uint32_t relid)
{
+ void* arg;
+ uint32_t bytes_to_read;
hv_vmbus_channel* channel;
+ boolean_t is_batched_reading;
/**
* Find the channel based on this relid and invokes
@@ -327,31 +388,98 @@ VmbusProcessChannelEvent(uint32_t relid)
* callback to NULL. This closes the window.
*/
- mtx_lock(&channel->inbound_lock);
+ /*
+ * Disable the lock due to newly added WITNESS check in r277723.
+ * Will seek other way to avoid race condition.
+ * -- whu
+ */
+ // mtx_lock(&channel->inbound_lock);
if (channel->on_channel_callback != NULL) {
- channel->on_channel_callback(channel->channel_callback_context);
+ arg = channel->channel_callback_context;
+ is_batched_reading = channel->batched_reading;
+ /*
+ * Optimize host to guest signaling by ensuring:
+ * 1. While reading the channel, we disable interrupts from
+ * host.
+ * 2. Ensure that we process all posted messages from the host
+ * before returning from this callback.
+ * 3. Once we return, enable signaling from the host. Once this
+ * state is set we check to see if additional packets are
+ * available to read. In this case we repeat the process.
+ */
+ do {
+ if (is_batched_reading)
+ hv_ring_buffer_read_begin(&channel->inbound);
+
+ channel->on_channel_callback(arg);
+
+ if (is_batched_reading)
+ bytes_to_read =
+ hv_ring_buffer_read_end(&channel->inbound);
+ else
+ bytes_to_read = 0;
+ } while (is_batched_reading && (bytes_to_read != 0));
}
- mtx_unlock(&channel->inbound_lock);
+ // mtx_unlock(&channel->inbound_lock);
}
+#ifdef HV_DEBUG_INTR
+extern uint32_t hv_intr_count;
+extern uint32_t hv_vmbus_swintr_event_cpu[MAXCPU];
+extern uint32_t hv_vmbus_intr_cpu[MAXCPU];
+#endif
+
/**
* Handler for events
*/
void
hv_vmbus_on_events(void *arg)
{
- int dword;
int bit;
+ int cpu;
+ int dword;
+ void *page_addr;
+ uint32_t* recv_interrupt_page = NULL;
int rel_id;
- int maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5;
+ int maxdword;
+ hv_vmbus_synic_event_flags *event;
/* int maxdword = PAGE_SIZE >> 3; */
- /*
- * receive size is 1/2 page and divide that by 4 bytes
- */
-
- uint32_t* recv_interrupt_page =
- hv_vmbus_g_connection.recv_interrupt_page;
+ cpu = (int)(long)arg;
+ KASSERT(cpu <= mp_maxid, ("VMBUS: hv_vmbus_on_events: "
+ "cpu out of range!"));
+
+#ifdef HV_DEBUG_INTR
+ int i;
+ hv_vmbus_swintr_event_cpu[cpu]++;
+ if (hv_intr_count % 10000 == 0) {
+ printf("VMBUS: Total interrupt %d\n", hv_intr_count);
+ for (i = 0; i < mp_ncpus; i++)
+ printf("VMBUS: hw cpu[%d]: %d, event sw intr cpu[%d]: %d\n",
+ i, hv_vmbus_intr_cpu[i], i, hv_vmbus_swintr_event_cpu[i]);
+ }
+#endif
+
+ if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
+ (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
+ maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5;
+ /*
+ * receive size is 1/2 page and divide that by 4 bytes
+ */
+ recv_interrupt_page =
+ hv_vmbus_g_connection.recv_interrupt_page;
+ } else {
+ /*
+ * On Host with Win8 or above, the event page can be
+ * checked directly to get the id of the channel
+ * that has the pending interrupt.
+ */
+ maxdword = HV_EVENT_FLAGS_DWORD_COUNT;
+ page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
+ event = (hv_vmbus_synic_event_flags *)
+ page_addr + HV_VMBUS_MESSAGE_SINT;
+ recv_interrupt_page = event->flags32;
+ }
/*
* Check events
@@ -416,16 +544,16 @@ int hv_vmbus_post_message(void *buffer, size_t bufferLen) {
* Send an event notification to the parent
*/
int
-hv_vmbus_set_event(uint32_t child_rel_id) {
+hv_vmbus_set_event(hv_vmbus_channel *channel) {
int ret = 0;
+ uint32_t child_rel_id = channel->offer_msg.child_rel_id;
/* Each uint32_t represents 32 channels */
synch_set_bit(child_rel_id & 31,
(((uint32_t *)hv_vmbus_g_connection.send_interrupt_page
+ (child_rel_id >> 5))));
- ret = hv_vmbus_signal_event();
+ ret = hv_vmbus_signal_event(channel->signal_event_param);
return (ret);
}
-
diff --git a/sys/dev/hyperv/vmbus/hv_hv.c b/sys/dev/hyperv/vmbus/hv_hv.c
index 80a1f42..84e2a5e 100644
--- a/sys/dev/hyperv/vmbus/hv_hv.c
+++ b/sys/dev/hyperv/vmbus/hv_hv.c
@@ -67,8 +67,6 @@ static inline void do_cpuid_inline(unsigned int op, unsigned int *eax,
hv_vmbus_context hv_vmbus_g_context = {
.syn_ic_initialized = FALSE,
.hypercall_page = NULL,
- .signal_event_param = NULL,
- .signal_event_buffer = NULL,
};
static struct timecounter hv_timecounter = {
@@ -256,28 +254,6 @@ hv_vmbus_init(void)
hv_vmbus_g_context.hypercall_page = virt_addr;
- /*
- * Setup the global signal event param for the signal event hypercall
- */
- hv_vmbus_g_context.signal_event_buffer =
- malloc(sizeof(hv_vmbus_input_signal_event_buffer), M_DEVBUF,
- M_ZERO | M_NOWAIT);
- KASSERT(hv_vmbus_g_context.signal_event_buffer != NULL,
- ("Error VMBUS: Failed to allocate signal_event_buffer\n"));
- if (hv_vmbus_g_context.signal_event_buffer == NULL)
- goto cleanup;
-
- hv_vmbus_g_context.signal_event_param =
- (hv_vmbus_input_signal_event*)
- (HV_ALIGN_UP((unsigned long)
- hv_vmbus_g_context.signal_event_buffer,
- HV_HYPERCALL_PARAM_ALIGN));
- hv_vmbus_g_context.signal_event_param->connection_id.as_uint32_t = 0;
- hv_vmbus_g_context.signal_event_param->connection_id.u.id =
- HV_VMBUS_EVENT_CONNECTION_ID;
- hv_vmbus_g_context.signal_event_param->flag_number = 0;
- hv_vmbus_g_context.signal_event_param->rsvd_z = 0;
-
tc_init(&hv_timecounter); /* register virtual timecount */
return (0);
@@ -303,12 +279,6 @@ hv_vmbus_cleanup(void)
{
hv_vmbus_x64_msr_hypercall_contents hypercall_msr;
- if (hv_vmbus_g_context.signal_event_buffer != NULL) {
- free(hv_vmbus_g_context.signal_event_buffer, M_DEVBUF);
- hv_vmbus_g_context.signal_event_buffer = NULL;
- hv_vmbus_g_context.signal_event_param = NULL;
- }
-
if (hv_vmbus_g_context.guest_id == HV_FREEBSD_GUEST_ID) {
if (hv_vmbus_g_context.hypercall_page != NULL) {
hypercall_msr.as_uint64_t = 0;
@@ -370,13 +340,13 @@ hv_vmbus_post_msg_via_msg_ipc(
* event IPC. (This involves a hypercall.)
*/
hv_vmbus_status
-hv_vmbus_signal_event()
+hv_vmbus_signal_event(void *con_id)
{
hv_vmbus_status status;
status = hv_vmbus_do_hypercall(
HV_CALL_SIGNAL_EVENT,
- hv_vmbus_g_context.signal_event_param,
+ con_id,
0) & 0xFFFF;
return (status);
@@ -390,6 +360,7 @@ hv_vmbus_synic_init(void *arg)
{
int cpu;
+ uint64_t hv_vcpu_index;
hv_vmbus_synic_simp simp;
hv_vmbus_synic_siefp siefp;
hv_vmbus_synic_scontrol sctrl;
@@ -403,23 +374,14 @@ hv_vmbus_synic_init(void *arg)
return;
/*
- * KYS: Looks like we can only initialize on cpu0; don't we support
- * SMP guests?
- *
- * TODO: Need to add SMP support for FreeBSD V9
- */
-
- if (cpu != 0)
- return;
-
- /*
* TODO: Check the version
*/
version = rdmsr(HV_X64_MSR_SVERSION);
-
- hv_vmbus_g_context.syn_ic_msg_page[cpu] = setup_args->page_buffers[0];
- hv_vmbus_g_context.syn_ic_event_page[cpu] = setup_args->page_buffers[1];
+ hv_vmbus_g_context.syn_ic_msg_page[cpu] =
+ setup_args->page_buffers[2 * cpu];
+ hv_vmbus_g_context.syn_ic_event_page[cpu] =
+ setup_args->page_buffers[2 * cpu + 1];
/*
* Setup the Synic's message page
@@ -443,9 +405,10 @@ hv_vmbus_synic_init(void *arg)
wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
/*HV_SHARED_SINT_IDT_VECTOR + 0x20; */
+ shared_sint.as_uint64_t = 0;
shared_sint.u.vector = setup_args->vector;
shared_sint.u.masked = FALSE;
- shared_sint.u.auto_eoi = FALSE;
+ shared_sint.u.auto_eoi = TRUE;
wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
shared_sint.as_uint64_t);
@@ -458,6 +421,13 @@ hv_vmbus_synic_init(void *arg)
hv_vmbus_g_context.syn_ic_initialized = TRUE;
+ /*
+ * Set up the cpuid mapping from Hyper-V to FreeBSD.
+ * The array is indexed using FreeBSD cpuid.
+ */
+ hv_vcpu_index = rdmsr(HV_X64_MSR_VP_INDEX);
+ hv_vmbus_g_context.hv_vcpu_index[cpu] = (uint32_t)hv_vcpu_index;
+
return;
}
@@ -469,14 +439,10 @@ void hv_vmbus_synic_cleanup(void *arg)
hv_vmbus_synic_sint shared_sint;
hv_vmbus_synic_simp simp;
hv_vmbus_synic_siefp siefp;
- int cpu = PCPU_GET(cpuid);
if (!hv_vmbus_g_context.syn_ic_initialized)
return;
- if (cpu != 0)
- return; /* TODO: XXXKYS: SMP? */
-
shared_sint.as_uint64_t = rdmsr(
HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT);
diff --git a/sys/dev/hyperv/vmbus/hv_ring_buffer.c b/sys/dev/hyperv/vmbus/hv_ring_buffer.c
index f7c1965..5e4f52a 100644
--- a/sys/dev/hyperv/vmbus/hv_ring_buffer.c
+++ b/sys/dev/hyperv/vmbus/hv_ring_buffer.c
@@ -144,6 +144,69 @@ get_ring_buffer_indices(hv_vmbus_ring_buffer_info* ring_info)
return (uint64_t) ring_info->ring_buffer->write_index << 32;
}
+void
+hv_ring_buffer_read_begin(
+ hv_vmbus_ring_buffer_info* ring_info)
+{
+ ring_info->ring_buffer->interrupt_mask = 1;
+ mb();
+}
+
+uint32_t
+hv_ring_buffer_read_end(
+ hv_vmbus_ring_buffer_info* ring_info)
+{
+ uint32_t read, write;
+
+ ring_info->ring_buffer->interrupt_mask = 0;
+ mb();
+
+ /*
+ * Now check to see if the ring buffer is still empty.
+ * If it is not, we raced and we need to process new
+ * incoming messages.
+ */
+ get_ring_buffer_avail_bytes(ring_info, &read, &write);
+
+ return (read);
+}
+
+/*
+ * When we write to the ring buffer, check if the host needs to
+ * be signaled. Here is the details of this protocol:
+ *
+ * 1. The host guarantees that while it is draining the
+ * ring buffer, it will set the interrupt_mask to
+ * indicate it does not need to be interrupted when
+ * new data is placed.
+ *
+ * 2. The host guarantees that it will completely drain
+ * the ring buffer before exiting the read loop. Further,
+ * once the ring buffer is empty, it will clear the
+ * interrupt_mask and re-check to see if new data has
+ * arrived.
+ */
+static boolean_t
+hv_ring_buffer_needsig_on_write(
+ uint32_t old_write_location,
+ hv_vmbus_ring_buffer_info* rbi)
+{
+ mb();
+ if (rbi->ring_buffer->interrupt_mask)
+ return (FALSE);
+
+ /* Read memory barrier */
+ rmb();
+ /*
+ * This is the only case we need to signal when the
+ * ring transitions from being empty to non-empty.
+ */
+ if (old_write_location == rbi->ring_buffer->read_index)
+ return (TRUE);
+
+ return (FALSE);
+}
+
static uint32_t copy_to_ring_buffer(
hv_vmbus_ring_buffer_info* ring_info,
uint32_t start_write_offset,
@@ -204,11 +267,13 @@ int
hv_ring_buffer_write(
hv_vmbus_ring_buffer_info* out_ring_info,
hv_vmbus_sg_buffer_list sg_buffers[],
- uint32_t sg_buffer_count)
+ uint32_t sg_buffer_count,
+ boolean_t *need_sig)
{
int i = 0;
uint32_t byte_avail_to_write;
uint32_t byte_avail_to_read;
+ uint32_t old_write_location;
uint32_t total_bytes_to_write = 0;
volatile uint32_t next_write_location;
@@ -242,6 +307,8 @@ hv_ring_buffer_write(
*/
next_write_location = get_next_write_location(out_ring_info);
+ old_write_location = next_write_location;
+
for (i = 0; i < sg_buffer_count; i++) {
next_write_location = copy_to_ring_buffer(out_ring_info,
next_write_location, (char *) sg_buffers[i].data,
@@ -258,9 +325,9 @@ hv_ring_buffer_write(
(char *) &prev_indices, sizeof(uint64_t));
/*
- * Make sure we flush all writes before updating the writeIndex
+ * Full memory barrier before upding the write index.
*/
- wmb();
+ mb();
/*
* Now, update the write location
@@ -269,6 +336,9 @@ hv_ring_buffer_write(
mtx_unlock_spin(&out_ring_info->ring_lock);
+ *need_sig = hv_ring_buffer_needsig_on_write(old_write_location,
+ out_ring_info);
+
return (0);
}
diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
index ca28fd5..f9432c8 100644
--- a/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
+++ b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
@@ -53,22 +53,17 @@ __FBSDID("$FreeBSD$");
#include <machine/stdarg.h>
#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
+#include <machine/segments.h>
#include <sys/pcpu.h>
+#include <x86/apicvar.h>
#include "hv_vmbus_priv.h"
#define VMBUS_IRQ 0x5
-static struct intr_event *hv_msg_intr_event;
-static struct intr_event *hv_event_intr_event;
-static void *msg_swintr;
-static void *event_swintr;
static device_t vmbus_devp;
-static void *vmbus_cookiep;
-static int vmbus_rid;
-struct resource *intr_res;
-static int vmbus_irq = VMBUS_IRQ;
static int vmbus_inited;
static hv_setup_args setup_args; /* only CPU 0 supported at this time */
@@ -77,14 +72,17 @@ static hv_setup_args setup_args; /* only CPU 0 supported at this time */
* the hypervisor.
*/
static void
-vmbus_msg_swintr(void *dummy)
+vmbus_msg_swintr(void *arg)
{
int cpu;
void* page_addr;
hv_vmbus_message* msg;
hv_vmbus_message* copied;
- cpu = PCPU_GET(cpuid);
+ cpu = (int)(long)arg;
+ KASSERT(cpu <= mp_maxid, ("VMBUS: vmbus_msg_swintr: "
+ "cpu out of range!"));
+
page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
@@ -130,17 +128,8 @@ vmbus_msg_swintr(void *dummy)
*
* The purpose of this routine is to determine the type of VMBUS protocol
* message to process - an event or a channel message.
- * As this is an interrupt filter routine, the function runs in a very
- * restricted envinronment. From the manpage for bus_setup_intr(9)
- *
- * In this restricted environment, care must be taken to account for all
- * races. A careful analysis of races should be done as well. It is gener-
- * ally cheaper to take an extra interrupt, for example, than to protect
- * variables with spinlocks. Read, modify, write cycles of hardware regis-
- * ters need to be carefully analyzed if other threads are accessing the
- * same registers.
*/
-static int
+static inline int
hv_vmbus_isr(void *unused)
{
int cpu;
@@ -149,8 +138,6 @@ hv_vmbus_isr(void *unused)
void* page_addr;
cpu = PCPU_GET(cpuid);
- /* (Temporary limit) */
- KASSERT(cpu == 0, ("hv_vmbus_isr: Interrupt on CPU other than zero"));
/*
* The Windows team has advised that we check for events
@@ -162,9 +149,21 @@ hv_vmbus_isr(void *unused)
event = (hv_vmbus_synic_event_flags*)
page_addr + HV_VMBUS_MESSAGE_SINT;
- /* Since we are a child, we only need to check bit 0 */
- if (synch_test_and_clear_bit(0, &event->flags32[0])) {
- swi_sched(event_swintr, 0);
+ if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
+ (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
+ /* Since we are a child, we only need to check bit 0 */
+ if (synch_test_and_clear_bit(0, &event->flags32[0])) {
+ swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
+ }
+ } else {
+ /*
+ * On host with Win8 or above, we can directly look at
+ * the event page. If bit n is set, we have an interrupt
+ * on the channel with id n.
+ * Directly schedule the event software interrupt on
+ * current cpu.
+ */
+ swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
}
/* Check if there are actual msgs to be process */
@@ -172,12 +171,47 @@ hv_vmbus_isr(void *unused)
msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
- swi_sched(msg_swintr, 0);
+ swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0);
}
return FILTER_HANDLED;
}
+#ifdef HV_DEBUG_INTR
+uint32_t hv_intr_count = 0;
+#endif
+uint32_t hv_vmbus_swintr_event_cpu[MAXCPU];
+uint32_t hv_vmbus_intr_cpu[MAXCPU];
+
+void
+hv_vector_handler(struct trapframe *trap_frame)
+{
+#ifdef HV_DEBUG_INTR
+ int cpu;
+#endif
+
+ /*
+ * Disable preemption.
+ */
+ critical_enter();
+
+#ifdef HV_DEBUG_INTR
+ /*
+ * Do a little interrupt counting.
+ */
+ cpu = PCPU_GET(cpuid);
+ hv_vmbus_intr_cpu[cpu]++;
+ hv_intr_count++;
+#endif
+
+ hv_vmbus_isr(NULL);
+
+ /*
+ * Enable preemption.
+ */
+ critical_exit();
+}
+
static int
vmbus_read_ivar(
device_t dev,
@@ -316,6 +350,81 @@ vmbus_probe(device_t dev) {
return (BUS_PROBE_NOWILDCARD);
}
+#ifdef HYPERV
+extern inthand_t IDTVEC(rsvd), IDTVEC(hv_vmbus_callback);
+
+/**
+ * @brief Find a free IDT slot and setup the interrupt handler.
+ */
+static int
+vmbus_vector_alloc(void)
+{
+ int vector;
+ uintptr_t func;
+ struct gate_descriptor *ip;
+
+ /*
+ * Search backwards form the highest IDT vector available for use
+ * as vmbus channel callback vector. We install 'hv_vmbus_callback'
+ * handler at that vector and use it to interrupt vcpus.
+ */
+ vector = APIC_SPURIOUS_INT;
+ while (--vector >= APIC_IPI_INTS) {
+ ip = &idt[vector];
+ func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
+ if (func == (uintptr_t)&IDTVEC(rsvd)) {
+#ifdef __i386__
+ setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYS386IGT,
+ SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
+#else
+ setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYSIGT,
+ SEL_KPL, 0);
+#endif
+
+ return (vector);
+ }
+ }
+ return (0);
+}
+
+/**
+ * @brief Restore the IDT slot to rsvd.
+ */
+static void
+vmbus_vector_free(int vector)
+{
+ uintptr_t func;
+ struct gate_descriptor *ip;
+
+ if (vector == 0)
+ return;
+
+ KASSERT(vector >= APIC_IPI_INTS && vector < APIC_SPURIOUS_INT,
+ ("invalid vector %d", vector));
+
+ ip = &idt[vector];
+ func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
+ KASSERT(func == (uintptr_t)&IDTVEC(hv_vmbus_callback),
+ ("invalid vector %d", vector));
+
+ setidt(vector, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
+}
+
+#else /* HYPERV */
+
+static int
+vmbus_vector_alloc(void)
+{
+ return(0);
+}
+
+static void
+vmbus_vector_free(int vector)
+{
+}
+
+#endif /* HYPERV */
+
/**
* @brief Main vmbus driver initialization routine.
*
@@ -331,22 +440,7 @@ vmbus_probe(device_t dev) {
static int
vmbus_bus_init(void)
{
- struct ioapic_intsrc {
- struct intsrc io_intsrc;
- u_int io_irq;
- u_int io_intpin:8;
- u_int io_vector:8;
- u_int io_cpu:8;
- u_int io_activehi:1;
- u_int io_edgetrigger:1;
- u_int io_masked:1;
- int io_bus:4;
- uint32_t io_lowreg;
- };
- int i, ret;
- unsigned int vector = 0;
- struct intsrc *isrc;
- struct ioapic_intsrc *intpin;
+ int i, j, n, ret;
if (vmbus_inited)
return (0);
@@ -361,80 +455,100 @@ vmbus_bus_init(void)
return (ret);
}
- ret = swi_add(&hv_msg_intr_event, "hv_msg", vmbus_msg_swintr,
- NULL, SWI_CLOCK, 0, &msg_swintr);
-
- if (ret)
- goto cleanup;
-
/*
- * Message SW interrupt handler checks a per-CPU page and
- * thus the thread needs to be bound to CPU-0 - which is where
- * all interrupts are processed.
+ * Find a free IDT slot for vmbus callback.
*/
- ret = intr_event_bind(hv_msg_intr_event, 0);
-
- if (ret)
- goto cleanup1;
+ hv_vmbus_g_context.hv_cb_vector = vmbus_vector_alloc();
- ret = swi_add(&hv_event_intr_event, "hv_event", hv_vmbus_on_events,
- NULL, SWI_CLOCK, 0, &event_swintr);
-
- if (ret)
- goto cleanup1;
+ if (hv_vmbus_g_context.hv_cb_vector == 0) {
+ if(bootverbose)
+ printf("Error VMBUS: Cannot find free IDT slot for "
+ "vmbus callback!\n");
+ goto cleanup;
+ }
- intr_res = bus_alloc_resource(vmbus_devp,
- SYS_RES_IRQ, &vmbus_rid, vmbus_irq, vmbus_irq, 1, RF_ACTIVE);
+ if(bootverbose)
+ printf("VMBUS: vmbus callback vector %d\n",
+ hv_vmbus_g_context.hv_cb_vector);
- if (intr_res == NULL) {
- ret = ENOMEM; /* XXXKYS: Need a better errno */
- goto cleanup2;
+ /*
+ * Notify the hypervisor of our vector.
+ */
+ setup_args.vector = hv_vmbus_g_context.hv_cb_vector;
+
+ CPU_FOREACH(j) {
+ hv_vmbus_intr_cpu[j] = 0;
+ hv_vmbus_swintr_event_cpu[j] = 0;
+ hv_vmbus_g_context.hv_event_intr_event[j] = NULL;
+ hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
+ hv_vmbus_g_context.event_swintr[j] = NULL;
+ hv_vmbus_g_context.msg_swintr[j] = NULL;
+
+ for (i = 0; i < 2; i++)
+ setup_args.page_buffers[2 * j + i] = NULL;
}
/*
- * Setup interrupt filter handler
+ * Per cpu setup.
*/
- ret = bus_setup_intr(vmbus_devp, intr_res,
- INTR_TYPE_NET | INTR_MPSAFE, hv_vmbus_isr, NULL,
- NULL, &vmbus_cookiep);
-
- if (ret != 0)
- goto cleanup3;
-
- ret = bus_bind_intr(vmbus_devp, intr_res, 0);
- if (ret != 0)
- goto cleanup4;
-
- isrc = intr_lookup_source(vmbus_irq);
- if ((isrc == NULL) || (isrc->is_event == NULL)) {
- ret = EINVAL;
- goto cleanup4;
- }
+ CPU_FOREACH(j) {
+ /*
+ * Setup software interrupt thread and handler for msg handling.
+ */
+ ret = swi_add(&hv_vmbus_g_context.hv_msg_intr_event[j],
+ "hv_msg", vmbus_msg_swintr, (void *)(long)j, SWI_CLOCK, 0,
+ &hv_vmbus_g_context.msg_swintr[j]);
+ if (ret) {
+ if(bootverbose)
+ printf("VMBUS: failed to setup msg swi for "
+ "cpu %d\n", j);
+ goto cleanup1;
+ }
- /* vector = isrc->is_event->ie_vector; */
- intpin = (struct ioapic_intsrc *)isrc;
- vector = intpin->io_vector;
+ /*
+ * Bind the swi thread to the cpu.
+ */
+ ret = intr_event_bind(hv_vmbus_g_context.hv_msg_intr_event[j],
+ j);
+ if (ret) {
+ if(bootverbose)
+ printf("VMBUS: failed to bind msg swi thread "
+ "to cpu %d\n", j);
+ goto cleanup1;
+ }
- if(bootverbose)
- printf("VMBUS: irq 0x%x vector 0x%x\n", vmbus_irq, vector);
+ /*
+ * Setup software interrupt thread and handler for
+ * event handling.
+ */
+ ret = swi_add(&hv_vmbus_g_context.hv_event_intr_event[j],
+ "hv_event", hv_vmbus_on_events, (void *)(long)j,
+ SWI_CLOCK, 0, &hv_vmbus_g_context.event_swintr[j]);
+ if (ret) {
+ if(bootverbose)
+ printf("VMBUS: failed to setup event swi for "
+ "cpu %d\n", j);
+ goto cleanup1;
+ }
- /**
- * Notify the hypervisor of our irq.
- */
- setup_args.vector = vector;
- for(i = 0; i < 2; i++) {
- setup_args.page_buffers[i] =
+ /*
+ * Prepare the per cpu msg and event pages to be called on each cpu.
+ */
+ for(i = 0; i < 2; i++) {
+ setup_args.page_buffers[2 * j + i] =
malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
- if (setup_args.page_buffers[i] == NULL) {
- KASSERT(setup_args.page_buffers[i] != NULL,
+ if (setup_args.page_buffers[2 * j + i] == NULL) {
+ KASSERT(setup_args.page_buffers[2 * j + i] != NULL,
("Error VMBUS: malloc failed!"));
- if (i > 0)
- free(setup_args.page_buffers[0], M_DEVBUF);
- goto cleanup4;
+ goto cleanup1;
+ }
}
}
- /* only CPU #0 supported at this time */
+ if (bootverbose)
+ printf("VMBUS: Calling smp_rendezvous, smp_started = %d\n",
+ smp_started);
+
smp_rendezvous(NULL, hv_vmbus_synic_init, NULL, &setup_args);
/*
@@ -443,26 +557,32 @@ vmbus_bus_init(void)
ret = hv_vmbus_connect();
if (ret != 0)
- goto cleanup4;
+ goto cleanup1;
hv_vmbus_request_channel_offers();
return (ret);
- cleanup4:
-
+ cleanup1:
/*
- * remove swi, bus and intr resource
+ * Free pages alloc'ed
*/
- bus_teardown_intr(vmbus_devp, intr_res, vmbus_cookiep);
+ for (n = 0; n < 2 * MAXCPU; n++)
+ if (setup_args.page_buffers[n] != NULL)
+ free(setup_args.page_buffers[n], M_DEVBUF);
- cleanup3:
- bus_release_resource(vmbus_devp, SYS_RES_IRQ, vmbus_rid, intr_res);
-
- cleanup2:
- swi_remove(event_swintr);
+ /*
+ * remove swi and vmbus callback vector;
+ */
+ CPU_FOREACH(j) {
+ if (hv_vmbus_g_context.msg_swintr[j] != NULL)
+ swi_remove(hv_vmbus_g_context.msg_swintr[j]);
+ if (hv_vmbus_g_context.event_swintr[j] != NULL)
+ swi_remove(hv_vmbus_g_context.event_swintr[j]);
+ hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
+ hv_vmbus_g_context.hv_event_intr_event[j] = NULL;
+ }
- cleanup1:
- swi_remove(msg_swintr);
+ vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
cleanup:
hv_vmbus_cleanup();
@@ -515,20 +635,24 @@ vmbus_bus_exit(void)
smp_rendezvous(NULL, hv_vmbus_synic_cleanup, NULL, NULL);
- for(i = 0; i < 2; i++) {
+ for(i = 0; i < 2 * MAXCPU; i++) {
if (setup_args.page_buffers[i] != 0)
free(setup_args.page_buffers[i], M_DEVBUF);
}
hv_vmbus_cleanup();
- /* remove swi, bus and intr resource */
- bus_teardown_intr(vmbus_devp, intr_res, vmbus_cookiep);
-
- bus_release_resource(vmbus_devp, SYS_RES_IRQ, vmbus_rid, intr_res);
+ /* remove swi */
+ CPU_FOREACH(i) {
+ if (hv_vmbus_g_context.msg_swintr[i] != NULL)
+ swi_remove(hv_vmbus_g_context.msg_swintr[i]);
+ if (hv_vmbus_g_context.event_swintr[i] != NULL)
+ swi_remove(hv_vmbus_g_context.event_swintr[i]);
+ hv_vmbus_g_context.hv_msg_intr_event[i] = NULL;
+ hv_vmbus_g_context.hv_event_intr_event[i] = NULL;
+ }
- swi_remove(msg_swintr);
- swi_remove(event_swintr);
+ vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
return;
}
@@ -603,6 +727,6 @@ devclass_t vmbus_devclass;
DRIVER_MODULE(vmbus, nexus, vmbus_driver, vmbus_devclass, vmbus_modevent, 0);
MODULE_VERSION(vmbus,1);
-/* TODO: We want to be earlier than SI_SUB_VFS */
-SYSINIT(vmb_init, SI_SUB_VFS, SI_ORDER_MIDDLE, vmbus_init, NULL);
+/* We want to be started after SMP is initialized */
+SYSINIT(vmb_init, SI_SUB_SMP + 1, SI_ORDER_FIRST, vmbus_init, NULL);
diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
index 6bc875d..faa6dec 100644
--- a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
+++ b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
@@ -181,49 +181,30 @@ enum {
#define HV_HYPERCALL_PARAM_ALIGN sizeof(uint64_t)
-/*
- * Connection identifier type
- */
-typedef union {
- uint32_t as_uint32_t;
- struct {
- uint32_t id:24;
- uint32_t reserved:8;
- } u;
-
-} __packed hv_vmbus_connection_id;
-
-/*
- * Definition of the hv_vmbus_signal_event hypercall input structure
- */
-typedef struct {
- hv_vmbus_connection_id connection_id;
- uint16_t flag_number;
- uint16_t rsvd_z;
-} __packed hv_vmbus_input_signal_event;
-
-typedef struct {
- uint64_t align8;
- hv_vmbus_input_signal_event event;
-} __packed hv_vmbus_input_signal_event_buffer;
-
typedef struct {
uint64_t guest_id;
void* hypercall_page;
hv_bool_uint8_t syn_ic_initialized;
+
+ hv_vmbus_handle syn_ic_msg_page[MAXCPU];
+ hv_vmbus_handle syn_ic_event_page[MAXCPU];
/*
- * This is used as an input param to HV_CALL_SIGNAL_EVENT hypercall.
- * The input param is immutable in our usage and
- * must be dynamic mem (vs stack or global).
+ * For FreeBSD cpuid to Hyper-V vcpuid mapping.
*/
- hv_vmbus_input_signal_event_buffer *signal_event_buffer;
+ uint32_t hv_vcpu_index[MAXCPU];
/*
- * 8-bytes aligned of the buffer above
+ * Each cpu has its own software interrupt handler for channel
+ * event and msg handling.
*/
- hv_vmbus_input_signal_event *signal_event_param;
-
- hv_vmbus_handle syn_ic_msg_page[MAXCPU];
- hv_vmbus_handle syn_ic_event_page[MAXCPU];
+ struct intr_event *hv_event_intr_event[MAXCPU];
+ struct intr_event *hv_msg_intr_event[MAXCPU];
+ void *event_swintr[MAXCPU];
+ void *msg_swintr[MAXCPU];
+ /*
+ * Host use this vector to intrrupt guest for vmbus channel
+ * event and msg.
+ */
+ unsigned int hv_cb_vector;
} hv_vmbus_context;
/*
@@ -368,7 +349,8 @@ typedef struct {
TAILQ_HEAD(, hv_vmbus_channel_msg_info) channel_msg_anchor;
struct mtx channel_msg_lock;
/**
- * List of channels
+ * List of primary channels. Sub channels will be linked
+ * under their primary channel.
*/
TAILQ_HEAD(, hv_vmbus_channel) channel_anchor;
struct mtx channel_lock;
@@ -560,6 +542,8 @@ typedef union {
uint32_t flags32[HV_EVENT_FLAGS_DWORD_COUNT];
} hv_vmbus_synic_event_flags;
+/* MSR used to provide vcpu index */
+#define HV_X64_MSR_VP_INDEX (0x40000002)
/*
* Define synthetic interrupt controller model specific registers
@@ -618,7 +602,8 @@ void hv_ring_buffer_cleanup(
int hv_ring_buffer_write(
hv_vmbus_ring_buffer_info *ring_info,
hv_vmbus_sg_buffer_list sg_buffers[],
- uint32_t sg_buff_count);
+ uint32_t sg_buff_count,
+ boolean_t *need_sig);
int hv_ring_buffer_peek(
hv_vmbus_ring_buffer_info *ring_info,
@@ -638,6 +623,12 @@ void hv_vmbus_dump_ring_info(
hv_vmbus_ring_buffer_info *ring_info,
char *prefix);
+void hv_ring_buffer_read_begin(
+ hv_vmbus_ring_buffer_info *ring_info);
+
+uint32_t hv_ring_buffer_read_end(
+ hv_vmbus_ring_buffer_info *ring_info);
+
hv_vmbus_channel* hv_vmbus_allocate_channel(void);
void hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel);
void hv_vmbus_on_channel_message(void *context);
@@ -652,7 +643,7 @@ uint16_t hv_vmbus_post_msg_via_msg_ipc(
void *payload,
size_t payload_size);
-uint16_t hv_vmbus_signal_event(void);
+uint16_t hv_vmbus_signal_event(void *con_id);
void hv_vmbus_synic_init(void *irq_arg);
void hv_vmbus_synic_cleanup(void *arg);
int hv_vmbus_query_hypervisor_presence(void);
@@ -674,7 +665,7 @@ hv_vmbus_channel* hv_vmbus_get_channel_from_rel_id(uint32_t rel_id);
int hv_vmbus_connect(void);
int hv_vmbus_disconnect(void);
int hv_vmbus_post_message(void *buffer, size_t buf_size);
-int hv_vmbus_set_event(uint32_t child_rel_id);
+int hv_vmbus_set_event(hv_vmbus_channel *channel);
void hv_vmbus_on_events(void *);
@@ -718,7 +709,7 @@ static inline uint64_t hv_generate_guest_id(
typedef struct {
unsigned int vector;
- void *page_buffers[2];
+ void *page_buffers[2 * MAXCPU];
} hv_setup_args;
#endif /* __HYPERV_PRIV_H__ */
diff --git a/sys/dev/ichsmb/ichsmb_pci.c b/sys/dev/ichsmb/ichsmb_pci.c
index de0d074..ae8b179 100644
--- a/sys/dev/ichsmb/ichsmb_pci.c
+++ b/sys/dev/ichsmb/ichsmb_pci.c
@@ -86,9 +86,11 @@ __FBSDID("$FreeBSD$");
#define ID_CPT 0x1c228086
#define ID_PPT 0x1e228086
#define ID_AVOTON 0x1f3c8086
-#define ID_COLETOCRK 0x23B08086
+#define ID_COLETOCRK 0x23B08086
#define ID_LPT 0x8c228086
+#define ID_LPTLP 0x9c228086
#define ID_WCPT 0x8ca28086
+#define ID_WCPTLP 0x9ca28086
#define PCIS_SERIALBUS_SMBUS_PROGIF 0x00
@@ -198,9 +200,15 @@ ichsmb_pci_probe(device_t dev)
case ID_LPT:
device_set_desc(dev, "Intel Lynx Point SMBus controller");
break;
+ case ID_LPTLP:
+ device_set_desc(dev, "Intel Lynx Point-LP SMBus controller");
+ break;
case ID_WCPT:
device_set_desc(dev, "Intel Wildcat Point SMBus controller");
break;
+ case ID_WCPTLP:
+ device_set_desc(dev, "Intel Wildcat Point-LP SMBus controller");
+ break;
case ID_COLETOCRK:
device_set_desc(dev, "Intel Coleto Creek SMBus controller");
break;
diff --git a/sys/dev/iicbus/iic.c b/sys/dev/iicbus/iic.c
index 16d113ee..84e1314 100644
--- a/sys/dev/iicbus/iic.c
+++ b/sys/dev/iicbus/iic.c
@@ -37,6 +37,7 @@
#include <sys/sx.h>
#include <sys/systm.h>
#include <sys/uio.h>
+#include <sys/errno.h>
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/iicbus.h>
@@ -44,28 +45,32 @@
#include "iicbus_if.h"
-#define BUFSIZE 1024
-
struct iic_softc {
-
device_t sc_dev;
- u_char sc_addr; /* 7 bit address on iicbus */
- int sc_count; /* >0 if device opened */
-
- char sc_buffer[BUFSIZE]; /* output buffer */
- char sc_inbuf[BUFSIZE]; /* input buffer */
-
struct cdev *sc_devnode;
- struct sx sc_lock;
};
-#define IIC_LOCK(sc) sx_xlock(&(sc)->sc_lock)
-#define IIC_UNLOCK(sc) sx_xunlock(&(sc)->sc_lock)
+struct iic_cdevpriv {
+ struct sx lock;
+ struct iic_softc *sc;
+ bool started;
+ uint8_t addr;
+};
+
+
+#define IIC_LOCK(cdp) sx_xlock(&(cdp)->lock)
+#define IIC_UNLOCK(cdp) sx_xunlock(&(cdp)->lock)
+
+static MALLOC_DEFINE(M_IIC, "iic", "I2C device data");
static int iic_probe(device_t);
static int iic_attach(device_t);
static int iic_detach(device_t);
static void iic_identify(driver_t *driver, device_t parent);
+static void iicdtor(void *data);
+static int iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last);
+static int iicuio(struct cdev *dev, struct uio *uio, int ioflag);
+static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags);
static devclass_t iic_devclass;
@@ -89,18 +94,13 @@ static driver_t iic_driver = {
};
static d_open_t iicopen;
-static d_close_t iicclose;
-static d_write_t iicwrite;
-static d_read_t iicread;
static d_ioctl_t iicioctl;
static struct cdevsw iic_cdevsw = {
.d_version = D_VERSION,
- .d_flags = D_TRACKCLOSE,
.d_open = iicopen,
- .d_close = iicclose,
- .d_read = iicread,
- .d_write = iicwrite,
+ .d_read = iicuio,
+ .d_write = iicuio,
.d_ioctl = iicioctl,
.d_name = "iic",
};
@@ -127,16 +127,15 @@ iic_probe(device_t dev)
static int
iic_attach(device_t dev)
{
- struct iic_softc *sc = (struct iic_softc *)device_get_softc(dev);
+ struct iic_softc *sc;
+ sc = device_get_softc(dev);
sc->sc_dev = dev;
- sx_init(&sc->sc_lock, "iic");
sc->sc_devnode = make_dev(&iic_cdevsw, device_get_unit(dev),
UID_ROOT, GID_WHEEL,
0600, "iic%d", device_get_unit(dev));
if (sc->sc_devnode == NULL) {
device_printf(dev, "failed to create character device\n");
- sx_destroy(&sc->sc_lock);
return (ENXIO);
}
sc->sc_devnode->si_drv1 = sc;
@@ -147,11 +146,12 @@ iic_attach(device_t dev)
static int
iic_detach(device_t dev)
{
- struct iic_softc *sc = (struct iic_softc *)device_get_softc(dev);
+ struct iic_softc *sc;
+
+ sc = device_get_softc(dev);
if (sc->sc_devnode)
destroy_dev(sc->sc_devnode);
- sx_destroy(&sc->sc_lock);
return (0);
}
@@ -159,238 +159,331 @@ iic_detach(device_t dev)
static int
iicopen(struct cdev *dev, int flags, int fmt, struct thread *td)
{
- struct iic_softc *sc = dev->si_drv1;
+ struct iic_cdevpriv *priv;
+ int error;
- IIC_LOCK(sc);
- if (sc->sc_count > 0) {
- IIC_UNLOCK(sc);
- return (EBUSY);
- }
+ priv = malloc(sizeof(*priv), M_IIC, M_WAITOK | M_ZERO);
- sc->sc_count++;
- IIC_UNLOCK(sc);
+ sx_init(&priv->lock, "iic");
+ priv->sc = dev->si_drv1;
- return (0);
+ error = devfs_set_cdevpriv(priv, iicdtor);
+ if (error != 0)
+ free(priv, M_IIC);
+
+ return (error);
}
-static int
-iicclose(struct cdev *dev, int flags, int fmt, struct thread *td)
+static void
+iicdtor(void *data)
{
- struct iic_softc *sc = dev->si_drv1;
+ device_t iicdev, parent;
+ struct iic_cdevpriv *priv;
- IIC_LOCK(sc);
- if (!sc->sc_count) {
- /* XXX: I don't think this can happen. */
- IIC_UNLOCK(sc);
- return (EINVAL);
- }
+ priv = data;
+ KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
- sc->sc_count--;
+ iicdev = priv->sc->sc_dev;
+ parent = device_get_parent(iicdev);
- if (sc->sc_count < 0)
- panic("%s: iic_count < 0!", __func__);
- IIC_UNLOCK(sc);
+ if (priv->started) {
+ iicbus_stop(parent);
+ iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
+ iicbus_release_bus(parent, iicdev);
+ }
- return (0);
+ sx_destroy(&priv->lock);
+ free(priv, M_IIC);
}
static int
-iicwrite(struct cdev *dev, struct uio * uio, int ioflag)
+iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last)
{
- struct iic_softc *sc = dev->si_drv1;
- device_t iicdev = sc->sc_dev;
- int sent, error, count;
-
- IIC_LOCK(sc);
- if (!sc->sc_addr) {
- IIC_UNLOCK(sc);
- return (EINVAL);
+ device_t parent;
+ int error, num_bytes, transferred_bytes, written_bytes;
+ char buffer[128];
+
+ parent = device_get_parent(priv->sc->sc_dev);
+ error = 0;
+
+ /*
+ * We can only transfer up to sizeof(buffer) bytes in 1 shot, so loop until
+ * everything has been transferred.
+ */
+ while ((error == 0) && (uio->uio_resid > 0)) {
+
+ num_bytes = MIN(uio->uio_resid, sizeof(buffer));
+ transferred_bytes = 0;
+
+ if (uio->uio_rw == UIO_WRITE) {
+ error = uiomove(buffer, num_bytes, uio);
+
+ while ((error == 0) && (transferred_bytes < num_bytes)) {
+ written_bytes = 0;
+ error = iicbus_write(parent, &buffer[transferred_bytes],
+ num_bytes - transferred_bytes, &written_bytes, 0);
+ transferred_bytes += written_bytes;
+ }
+
+ } else if (uio->uio_rw == UIO_READ) {
+ error = iicbus_read(parent, buffer,
+ num_bytes, &transferred_bytes,
+ ((uio->uio_resid <= sizeof(buffer)) ? last : 0), 0);
+ if (error == 0)
+ error = uiomove(buffer, transferred_bytes, uio);
+ }
}
- if (sc->sc_count == 0) {
- /* XXX: I don't think this can happen. */
- IIC_UNLOCK(sc);
- return (EINVAL);
- }
+ return (error);
+}
- error = iicbus_request_bus(device_get_parent(iicdev), iicdev,
- IIC_DONTWAIT);
- if (error) {
- IIC_UNLOCK(sc);
+static int
+iicuio(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ device_t parent;
+ struct iic_cdevpriv *priv;
+ int error;
+ uint8_t addr;
+
+ priv = NULL;
+ error = devfs_get_cdevpriv((void**)&priv);
+
+ if (error != 0)
return (error);
+ KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
+
+ IIC_LOCK(priv);
+ if (priv->started || (priv->addr == 0)) {
+ IIC_UNLOCK(priv);
+ return (ENXIO);
}
+ parent = device_get_parent(priv->sc->sc_dev);
- count = min(uio->uio_resid, BUFSIZE);
- error = uiomove(sc->sc_buffer, count, uio);
- if (error) {
- IIC_UNLOCK(sc);
+ error = iicbus_request_bus(parent, priv->sc->sc_dev,
+ (ioflag & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
+ if (error != 0) {
+ IIC_UNLOCK(priv);
return (error);
}
- error = iicbus_block_write(device_get_parent(iicdev), sc->sc_addr,
- sc->sc_buffer, count, &sent);
+ if (uio->uio_rw == UIO_READ)
+ addr = priv->addr | LSB;
+ else
+ addr = priv->addr & ~LSB;
+
+ error = iicbus_start(parent, addr, 0);
+ if (error != 0)
+ {
+ iicbus_release_bus(parent, priv->sc->sc_dev);
+ IIC_UNLOCK(priv);
+ return (error);
+ }
- iicbus_release_bus(device_get_parent(iicdev), iicdev);
- IIC_UNLOCK(sc);
+ error = iicuio_move(priv, uio, IIC_LAST_READ);
+ iicbus_stop(parent);
+ iicbus_release_bus(parent, priv->sc->sc_dev);
+ IIC_UNLOCK(priv);
return (error);
}
static int
-iicread(struct cdev *dev, struct uio * uio, int ioflag)
+iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags)
{
- struct iic_softc *sc = dev->si_drv1;
- device_t iicdev = sc->sc_dev;
- int len, error = 0;
- int bufsize;
-
- IIC_LOCK(sc);
- if (!sc->sc_addr) {
- IIC_UNLOCK(sc);
- return (EINVAL);
- }
+ struct iic_msg *buf, *m;
+ void **usrbufs;
+ device_t iicdev, parent;
+ int error, i;
- if (sc->sc_count == 0) {
- /* XXX: I don't think this can happen. */
- IIC_UNLOCK(sc);
- return (EINVAL);
- }
+ iicdev = priv->sc->sc_dev;
+ parent = device_get_parent(iicdev);
+ error = 0;
- error = iicbus_request_bus(device_get_parent(iicdev), iicdev,
- IIC_DONTWAIT);
- if (error) {
- IIC_UNLOCK(sc);
- return (error);
- }
+ buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_IIC, M_WAITOK);
- /* max amount of data to read */
- len = min(uio->uio_resid, BUFSIZE);
+ error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);
- error = iicbus_block_read(device_get_parent(iicdev), sc->sc_addr,
- sc->sc_inbuf, len, &bufsize);
- if (error) {
- IIC_UNLOCK(sc);
- return (error);
+ /* Alloc kernel buffers for userland data, copyin write data */
+ usrbufs = malloc(sizeof(void *) * d->nmsgs, M_IIC, M_WAITOK | M_ZERO);
+
+ for (i = 0; i < d->nmsgs; i++) {
+ m = &(buf[i]);
+ usrbufs[i] = m->buf;
+
+ /*
+ * At least init the buffer to NULL so we can safely free() it later.
+ * If the copyin() to buf failed, don't try to malloc bogus m->len.
+ */
+ m->buf = NULL;
+ if (error != 0)
+ continue;
+ m->buf = malloc(m->len, M_IIC, M_WAITOK);
+ if (!(m->flags & IIC_M_RD))
+ error = copyin(usrbufs[i], m->buf, m->len);
}
- if (bufsize > uio->uio_resid)
- panic("%s: too much data read!", __func__);
+ if (error == 0)
+ error = iicbus_request_bus(parent, iicdev,
+ (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
- iicbus_release_bus(device_get_parent(iicdev), iicdev);
+ if (error == 0) {
+ error = iicbus_transfer(iicdev, buf, d->nmsgs);
+ iicbus_release_bus(parent, iicdev);
+ }
+
+ /* Copyout all read segments, free up kernel buffers */
+ for (i = 0; i < d->nmsgs; i++) {
+ m = &(buf[i]);
+ if ((error == 0) && (m->flags & IIC_M_RD))
+ error = copyout(m->buf, usrbufs[i], m->len);
+ free(m->buf, M_IIC);
+ }
- error = uiomove(sc->sc_inbuf, bufsize, uio);
- IIC_UNLOCK(sc);
+ free(usrbufs, M_IIC);
+ free(buf, M_IIC);
return (error);
}
static int
iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
{
- struct iic_softc *sc = dev->si_drv1;
- device_t iicdev = sc->sc_dev;
- device_t parent = device_get_parent(iicdev);
- struct iiccmd *s = (struct iiccmd *)data;
- struct iic_rdwr_data *d = (struct iic_rdwr_data *)data;
- struct iic_msg *m;
- int error, count, i;
- char *buf = NULL;
- void **usrbufs = NULL;
-
- if ((error = iicbus_request_bus(parent, iicdev,
- (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR))))
+ device_t parent, iicdev;
+ struct iiccmd *s;
+ struct uio ubuf;
+ struct iovec uvec;
+ struct iic_cdevpriv *priv;
+ int error;
+
+ s = (struct iiccmd *)data;
+ error = devfs_get_cdevpriv((void**)&priv);
+ if (error != 0)
return (error);
+ KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
+
+ iicdev = priv->sc->sc_dev;
+ parent = device_get_parent(iicdev);
+ IIC_LOCK(priv);
+
+
switch (cmd) {
case I2CSTART:
- IIC_LOCK(sc);
- error = iicbus_start(parent, s->slave, 0);
+ if (priv->started) {
+ error = EINVAL;
+ break;
+ }
+ error = iicbus_request_bus(parent, iicdev,
+ (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
- /*
- * Implicitly set the chip addr to the slave addr passed as
- * parameter. Consequently, start/stop shall be called before
- * the read or the write of a block.
- */
- if (!error)
- sc->sc_addr = s->slave;
- IIC_UNLOCK(sc);
+ if (error == 0)
+ error = iicbus_start(parent, s->slave, 0);
+
+ if (error == 0) {
+ priv->addr = s->slave;
+ priv->started = true;
+ } else
+ iicbus_release_bus(parent, iicdev);
break;
case I2CSTOP:
- error = iicbus_stop(parent);
+ if (priv->started) {
+ error = iicbus_stop(parent);
+ iicbus_release_bus(parent, iicdev);
+ priv->started = false;
+ }
+
break;
case I2CRSTCARD:
- error = iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
/*
- * Ignore IIC_ENOADDR as it only means we have a master-only
- * controller.
- */
- if (error == IIC_ENOADDR)
- error = 0;
+ * Bus should be owned before we reset it.
+ * We allow the bus to be already owned as the result of an in-progress
+ * sequence; however, bus reset will always be followed by release
+ * (a new start is presumably needed for I/O anyway). */
+ if (!priv->started)
+ error = iicbus_request_bus(parent, iicdev,
+ (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
+
+ if (error == 0) {
+ error = iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
+ /*
+ * Ignore IIC_ENOADDR as it only means we have a master-only
+ * controller.
+ */
+ if (error == IIC_ENOADDR)
+ error = 0;
+
+ iicbus_release_bus(parent, iicdev);
+ priv->started = false;
+ }
break;
case I2CWRITE:
- if (s->count <= 0) {
+ if (!priv->started) {
error = EINVAL;
break;
}
- buf = malloc((unsigned long)s->count, M_TEMP, M_WAITOK);
- error = copyin(s->buf, buf, s->count);
- if (error)
- break;
- error = iicbus_write(parent, buf, s->count, &count, 10);
+ uvec.iov_base = s->buf;
+ uvec.iov_len = s->count;
+ ubuf.uio_iov = &uvec;
+ ubuf.uio_iovcnt = 1;
+ ubuf.uio_segflg = UIO_USERSPACE;
+ ubuf.uio_td = td;
+ ubuf.uio_resid = s->count;
+ ubuf.uio_offset = 0;
+ ubuf.uio_rw = UIO_WRITE;
+ error = iicuio_move(priv, &ubuf, 0);
break;
case I2CREAD:
- if (s->count <= 0) {
+ if (!priv->started) {
error = EINVAL;
break;
}
- buf = malloc((unsigned long)s->count, M_TEMP, M_WAITOK);
- error = iicbus_read(parent, buf, s->count, &count, s->last, 10);
- if (error)
- break;
- error = copyout(buf, s->buf, s->count);
+ uvec.iov_base = s->buf;
+ uvec.iov_len = s->count;
+ ubuf.uio_iov = &uvec;
+ ubuf.uio_iovcnt = 1;
+ ubuf.uio_segflg = UIO_USERSPACE;
+ ubuf.uio_td = td;
+ ubuf.uio_resid = s->count;
+ ubuf.uio_offset = 0;
+ ubuf.uio_rw = UIO_READ;
+ error = iicuio_move(priv, &ubuf, s->last);
break;
case I2CRDWR:
- buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_TEMP, M_WAITOK);
- error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);
- if (error)
+ /*
+ * The rdwr list should be a self-contained set of
+ * transactions. Fail if another transaction is in progress.
+ */
+ if (priv->started) {
+ error = EINVAL;
break;
- /* Alloc kernel buffers for userland data, copyin write data */
- usrbufs = malloc(sizeof(void *) * d->nmsgs, M_TEMP, M_ZERO | M_WAITOK);
- for (i = 0; i < d->nmsgs; i++) {
- m = &((struct iic_msg *)buf)[i];
- usrbufs[i] = m->buf;
- m->buf = malloc(m->len, M_TEMP, M_WAITOK);
- if (!(m->flags & IIC_M_RD))
- copyin(usrbufs[i], m->buf, m->len);
- }
- error = iicbus_transfer(iicdev, (struct iic_msg *)buf, d->nmsgs);
- /* Copyout all read segments, free up kernel buffers */
- for (i = 0; i < d->nmsgs; i++) {
- m = &((struct iic_msg *)buf)[i];
- if (m->flags & IIC_M_RD)
- copyout(m->buf, usrbufs[i], m->len);
- free(m->buf, M_TEMP);
}
- free(usrbufs, M_TEMP);
+
+ error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags);
+
break;
case I2CRPTSTART:
+ if (!priv->started) {
+ error = EINVAL;
+ break;
+ }
error = iicbus_repeated_start(parent, s->slave, 0);
break;
+ case I2CSADDR:
+ priv->addr = *((uint8_t*)data);
+ break;
+
default:
error = ENOTTY;
}
- iicbus_release_bus(parent, iicdev);
-
- if (buf != NULL)
- free(buf, M_TEMP);
+ IIC_UNLOCK(priv);
return (error);
}
diff --git a/sys/dev/iicbus/iic.h b/sys/dev/iicbus/iic.h
index ab58abf..ba98d28 100644
--- a/sys/dev/iicbus/iic.h
+++ b/sys/dev/iicbus/iic.h
@@ -63,5 +63,6 @@ struct iic_rdwr_data {
#define I2CREAD _IOW('i', 5, struct iiccmd) /* receive data */
#define I2CRDWR _IOW('i', 6, struct iic_rdwr_data) /* General read/write interface */
#define I2CRPTSTART _IOW('i', 7, struct iiccmd) /* repeated start */
+#define I2CSADDR _IOW('i', 8, uint8_t) /* set slave address for future I/O */
#endif
diff --git a/sys/dev/iicbus/iicbus_if.m b/sys/dev/iicbus/iicbus_if.m
index 120b5e7..3f58168 100644
--- a/sys/dev/iicbus/iicbus_if.m
+++ b/sys/dev/iicbus/iicbus_if.m
@@ -51,6 +51,10 @@ METHOD int intr {
#
# iicbus callback
+# Request ownership of bus
+# index: IIC_REQUEST_BUS or IIC_RELEASE_BUS
+# data: pointer to int containing IIC_WAIT or IIC_DONTWAIT and either IIC_INTR or IIC_NOINTR
+# This function is allowed to sleep if *data contains IIC_WAIT.
#
METHOD int callback {
device_t dev;
diff --git a/sys/dev/iicbus/iiconf.c b/sys/dev/iicbus/iiconf.c
index 940760b..09edb39 100644
--- a/sys/dev/iicbus/iiconf.c
+++ b/sys/dev/iicbus/iiconf.c
@@ -71,7 +71,6 @@ iicbus_poll(struct iicbus_softc *sc, int how)
default:
return (EWOULDBLOCK);
- break;
}
return (error);
@@ -90,31 +89,32 @@ iicbus_request_bus(device_t bus, device_t dev, int how)
struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
int error = 0;
- /* first, ask the underlying layers if the request is ok */
IICBUS_LOCK(sc);
- do {
- error = IICBUS_CALLBACK(device_get_parent(bus),
- IIC_REQUEST_BUS, (caddr_t)&how);
- if (error)
- error = iicbus_poll(sc, how);
- } while (error == EWOULDBLOCK);
- while (!error) {
- if (sc->owner && sc->owner != dev) {
-
- error = iicbus_poll(sc, how);
- } else {
- sc->owner = dev;
+ while ((error == 0) && (sc->owner != NULL))
+ error = iicbus_poll(sc, how);
+
+ if (error == 0) {
+ sc->owner = dev;
+ /*
+ * Drop the lock around the call to the bus driver.
+ * This call should be allowed to sleep in the IIC_WAIT case.
+ * Drivers might also need to grab locks that would cause LOR
+ * if our lock is held.
+ */
+ IICBUS_UNLOCK(sc);
+ /* Ask the underlying layers if the request is ok */
+ error = IICBUS_CALLBACK(device_get_parent(bus),
+ IIC_REQUEST_BUS, (caddr_t)&how);
+ IICBUS_LOCK(sc);
- IICBUS_UNLOCK(sc);
- return (0);
+ if (error != 0) {
+ sc->owner = NULL;
+ wakeup_one(sc);
}
-
- /* free any allocated resource */
- if (error)
- IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS,
- (caddr_t)&how);
}
+
+
IICBUS_UNLOCK(sc);
return (error);
@@ -131,12 +131,6 @@ iicbus_release_bus(device_t bus, device_t dev)
struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
int error;
- /* first, ask the underlying layers if the release is ok */
- error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
-
- if (error)
- return (error);
-
IICBUS_LOCK(sc);
if (sc->owner != dev) {
@@ -144,13 +138,26 @@ iicbus_release_bus(device_t bus, device_t dev)
return (EACCES);
}
- sc->owner = NULL;
-
- /* wakeup waiting processes */
- wakeup(sc);
+ /*
+ * Drop the lock around the call to the bus driver.
+ * This call should be allowed to sleep in the IIC_WAIT case.
+ * Drivers might also need to grab locks that would cause LOR
+ * if our lock is held.
+ */
IICBUS_UNLOCK(sc);
+ /* Ask the underlying layers if the release is ok */
+ error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
- return (0);
+ if (error == 0) {
+ IICBUS_LOCK(sc);
+ sc->owner = NULL;
+
+ /* wakeup a waiting thread */
+ wakeup_one(sc);
+ IICBUS_UNLOCK(sc);
+ }
+
+ return (error);
}
/*
diff --git a/sys/dev/iicbus/pcf8563.c b/sys/dev/iicbus/pcf8563.c
index 88307a5..556943a 100644
--- a/sys/dev/iicbus/pcf8563.c
+++ b/sys/dev/iicbus/pcf8563.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2012 Marius Strobl <marius@FreeBSD.org>
+ * Copyright (c) 2015 Juraj Lutter
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,6 +32,8 @@ __FBSDID("$FreeBSD$");
* Driver for NXP PCF8563 real-time clock/calendar
*/
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -41,6 +44,11 @@ __FBSDID("$FreeBSD$");
#include <dev/iicbus/iicbus.h>
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/pcf8563reg.h>
+#ifdef FDT
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
#include "clock_if.h"
#include "iicbus_if.h"
@@ -48,6 +56,7 @@ __FBSDID("$FreeBSD$");
#define PCF8563_NCLOCKREGS (PCF8563_R_YEAR - PCF8563_R_CS1 + 1)
struct pcf8563_softc {
+ struct intr_config_hook enum_hook;
uint32_t sc_flags;
#define PCF8563_CPOL (1 << 0) /* PCF8563_R_MONTH_C means 19xx */
uint16_t sc_addr; /* PCF8563 slave address */
@@ -58,30 +67,62 @@ static device_attach_t pcf8563_attach;
static device_probe_t pcf8563_probe;
static clock_gettime_t pcf8563_gettime;
static clock_settime_t pcf8563_settime;
+static void pcf8563_start(void *);
static int
pcf8563_probe(device_t dev)
{
+#ifdef FDT
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ if (!ofw_bus_is_compatible(dev, "nxp,pcf8563") &&
+ !ofw_bus_is_compatible(dev, "philips,pcf8563") &&
+ !ofw_bus_is_compatible(dev, "pcf8563"))
+ return (ENXIO);
+#endif
device_set_desc(dev, "NXP PCF8563 RTC");
- return (BUS_PROBE_NOWILDCARD);
+
+ return (BUS_PROBE_DEFAULT);
}
static int
pcf8563_attach(device_t dev)
{
+ struct pcf8563_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_addr = iicbus_get_addr(dev);
+ if (sc->sc_addr == 0)
+ sc->sc_addr = PCF8563_ADDR;
+ sc->sc_year0 = 1900;
+ sc->enum_hook.ich_func = pcf8563_start;
+ sc->enum_hook.ich_arg = dev;
+
+ /*
+ * We have to wait until interrupts are enabled. Sometimes I2C read
+ * and write only works when the interrupts are available.
+ */
+ if (config_intrhook_establish(&sc->enum_hook) != 0)
+ return (ENOMEM);
+
+ return (0);
+}
+
+static void
+pcf8563_start(void *xdev)
+{
+ device_t dev;
uint8_t reg = PCF8563_R_SECOND, val;
struct iic_msg msgs[] = {
{ 0, IIC_M_WR, sizeof(reg), &reg },
{ 0, IIC_M_RD, sizeof(val), &val }
};
struct pcf8563_softc *sc;
- int error;
+ dev = (device_t)xdev;
sc = device_get_softc(dev);
- sc->sc_addr = iicbus_get_addr(dev);
- if (sc->sc_addr == 0)
- sc->sc_addr = PCF8563_ADDR;
+ config_intrhook_disestablish(&sc->enum_hook);
/*
* NB: PCF8563_R_SECOND_VL doesn't automatically clear when VDD
@@ -94,18 +135,14 @@ pcf8563_attach(device_t dev)
* as a side-effect.
*/
msgs[0].slave = msgs[1].slave = sc->sc_addr;
- error = iicbus_transfer(device_get_parent(dev), msgs, sizeof(msgs) /
- sizeof(*msgs));
- if (error != 0) {
+ if (iicbus_transfer(dev, msgs, nitems(msgs)) != 0) {
device_printf(dev, "%s: cannot read RTC\n", __func__);
- return (error);
+ return;
}
if ((val & PCF8563_R_SECOND_VL) != 0)
device_printf(dev, "%s: battery low\n", __func__);
- sc->sc_year0 = 1900;
clock_register(dev, 1000000); /* 1 second resolution */
- return (0);
}
static int
@@ -122,8 +159,7 @@ pcf8563_gettime(device_t dev, struct timespec *ts)
sc = device_get_softc(dev);
msgs[0].slave = msgs[1].slave = sc->sc_addr;
- error = iicbus_transfer(device_get_parent(dev), msgs, sizeof(msgs) /
- sizeof(*msgs));
+ error = iicbus_transfer(dev, msgs, nitems(msgs));
if (error != 0) {
device_printf(dev, "%s: cannot read RTC\n", __func__);
return (error);
@@ -145,6 +181,7 @@ pcf8563_gettime(device_t dev, struct timespec *ts)
sc->sc_flags |= PCF8563_CPOL;
} else if (ct.year < 100 + sc->sc_year0)
sc->sc_flags |= PCF8563_CPOL;
+
return (clock_ct_to_ts(&ct, ts));
}
@@ -180,10 +217,10 @@ pcf8563_settime(device_t dev, struct timespec *ts)
val[PCF8563_R_MONTH] |= PCF8563_R_MONTH_C;
msgs[0].slave = sc->sc_addr;
- error = iicbus_transfer(device_get_parent(dev), msgs, sizeof(msgs) /
- sizeof(*msgs));
+ error = iicbus_transfer(dev, msgs, nitems(msgs));
if (error != 0)
device_printf(dev, "%s: cannot write RTC\n", __func__);
+
return (error);
}
diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c
index a1edbf6..8101717 100644
--- a/sys/dev/ipmi/ipmi.c
+++ b/sys/dev/ipmi/ipmi.c
@@ -756,17 +756,22 @@ ipmi_startup(void *arg)
}
device_printf(dev, "Number of channels %d\n", i);
- /* probe for watchdog */
- IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
- IPMI_GET_WDOG, 0, 0);
+ /*
+ * Probe for watchdog, but only for backends which support
+ * polled driver requests.
+ */
+ if (sc->ipmi_driver_requests_polled) {
+ IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_GET_WDOG, 0, 0);
- ipmi_submit_driver_request(sc, req, 0);
+ ipmi_submit_driver_request(sc, req, 0);
- if (req->ir_compcode == 0x00) {
- device_printf(dev, "Attached watchdog\n");
- /* register the watchdog event handler */
- sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(watchdog_list,
- ipmi_wd_event, sc, 0);
+ if (req->ir_compcode == 0x00) {
+ device_printf(dev, "Attached watchdog\n");
+ /* register the watchdog event handler */
+ sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(
+ watchdog_list, ipmi_wd_event, sc, 0);
+ }
}
sc->ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev),
diff --git a/sys/dev/ipmi/ipmi_kcs.c b/sys/dev/ipmi/ipmi_kcs.c
index 1c58646..864e9a0 100644
--- a/sys/dev/ipmi/ipmi_kcs.c
+++ b/sys/dev/ipmi/ipmi_kcs.c
@@ -520,6 +520,7 @@ ipmi_kcs_attach(struct ipmi_softc *sc)
sc->ipmi_startup = kcs_startup;
sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
sc->ipmi_driver_request = kcs_driver_request;
+ sc->ipmi_driver_requests_polled = 1;
/* See if we can talk to the controller. */
status = INB(sc, KCS_CTL_STS);
diff --git a/sys/dev/ipmi/ipmi_smic.c b/sys/dev/ipmi/ipmi_smic.c
index 4e26553..92cf14e 100644
--- a/sys/dev/ipmi/ipmi_smic.c
+++ b/sys/dev/ipmi/ipmi_smic.c
@@ -415,6 +415,7 @@ ipmi_smic_attach(struct ipmi_softc *sc)
sc->ipmi_startup = smic_startup;
sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
sc->ipmi_driver_request = smic_driver_request;
+ sc->ipmi_driver_requests_polled = 1;
/* See if we can talk to the controller. */
flags = INB(sc, SMIC_FLAGS);
diff --git a/sys/dev/ipmi/ipmivars.h b/sys/dev/ipmi/ipmivars.h
index 9d7dc32..9a0b435 100644
--- a/sys/dev/ipmi/ipmivars.h
+++ b/sys/dev/ipmi/ipmivars.h
@@ -105,6 +105,7 @@ struct ipmi_softc {
int ipmi_opened;
struct cdev *ipmi_cdev;
TAILQ_HEAD(,ipmi_request) ipmi_pending_requests;
+ int ipmi_driver_requests_polled;
eventhandler_tag ipmi_watchdog_tag;
int ipmi_watchdog_active;
struct intr_config_hook ipmi_ich;
diff --git a/sys/dev/iscsi/icl_conn_if.m b/sys/dev/iscsi/icl_conn_if.m
index 1a52882..077fabe 100644
--- a/sys/dev/iscsi/icl_conn_if.m
+++ b/sys/dev/iscsi/icl_conn_if.m
@@ -82,10 +82,6 @@ METHOD void close {
struct icl_conn *_ic;
};
-METHOD bool connected {
- struct icl_conn *_ic;
-};
-
METHOD int task_setup {
struct icl_conn *_ic;
struct ccb_scsiio *_csio;
diff --git a/sys/dev/iscsi/icl_soft.c b/sys/dev/iscsi/icl_soft.c
index 2dd5e5c..e31b213 100644
--- a/sys/dev/iscsi/icl_soft.c
+++ b/sys/dev/iscsi/icl_soft.c
@@ -97,7 +97,6 @@ static icl_conn_pdu_queue_t icl_soft_conn_pdu_queue;
static icl_conn_handoff_t icl_soft_conn_handoff;
static icl_conn_free_t icl_soft_conn_free;
static icl_conn_close_t icl_soft_conn_close;
-static icl_conn_connected_t icl_soft_conn_connected;
static icl_conn_task_setup_t icl_soft_conn_task_setup;
static icl_conn_task_done_t icl_soft_conn_task_done;
static icl_conn_transfer_setup_t icl_soft_conn_transfer_setup;
@@ -114,7 +113,6 @@ static kobj_method_t icl_soft_methods[] = {
KOBJMETHOD(icl_conn_handoff, icl_soft_conn_handoff),
KOBJMETHOD(icl_conn_free, icl_soft_conn_free),
KOBJMETHOD(icl_conn_close, icl_soft_conn_close),
- KOBJMETHOD(icl_conn_connected, icl_soft_conn_connected),
KOBJMETHOD(icl_conn_task_setup, icl_soft_conn_task_setup),
KOBJMETHOD(icl_conn_task_done, icl_soft_conn_task_done),
KOBJMETHOD(icl_conn_transfer_setup, icl_soft_conn_transfer_setup),
@@ -1425,24 +1423,6 @@ icl_soft_conn_close(struct icl_conn *ic)
ICL_CONN_UNLOCK(ic);
}
-bool
-icl_soft_conn_connected(struct icl_conn *ic)
-{
- ICL_CONN_LOCK_ASSERT_NOT(ic);
-
- ICL_CONN_LOCK(ic);
- if (ic->ic_socket == NULL) {
- ICL_CONN_UNLOCK(ic);
- return (false);
- }
- if (ic->ic_socket->so_error != 0) {
- ICL_CONN_UNLOCK(ic);
- return (false);
- }
- ICL_CONN_UNLOCK(ic);
- return (true);
-}
-
int
icl_soft_conn_task_setup(struct icl_conn *ic, struct ccb_scsiio *csio,
uint32_t *task_tagp, void **prvp)
diff --git a/sys/dev/iscsi/icl_wrappers.h b/sys/dev/iscsi/icl_wrappers.h
index 2cf7d96..1ed72ae 100644
--- a/sys/dev/iscsi/icl_wrappers.h
+++ b/sys/dev/iscsi/icl_wrappers.h
@@ -105,13 +105,6 @@ icl_conn_close(struct icl_conn *ic)
ICL_CONN_CLOSE(ic);
}
-static inline bool
-icl_conn_connected(struct icl_conn *ic)
-{
-
- return (ICL_CONN_CONNECTED(ic));
-}
-
static inline int
icl_conn_task_setup(struct icl_conn *ic, struct ccb_scsiio *csio,
uint32_t *task_tagp, void **prvp)
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index b287c6c..3733509 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -8060,7 +8060,7 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw,
case IWN_FW_TLV_WOWLAN_INST:
case IWN_FW_TLV_WOWLAN_DATA:
DPRINTF(sc, IWN_DEBUG_RESET,
- "TLV type %d reconized but not handled\n",
+ "TLV type %d recognized but not handled\n",
le16toh(tlv->type));
break;
default:
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index a77a3ef..b9bba31 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -54,7 +54,7 @@ int ixgbe_display_debug_stats = 0;
/*********************************************************************
* Driver version
*********************************************************************/
-char ixgbe_driver_version[] = "2.7.4";
+char ixgbe_driver_version[] = "2.8.3";
/*********************************************************************
* PCI Device ID Table
@@ -117,6 +117,8 @@ static int ixgbe_probe(device_t);
static int ixgbe_attach(device_t);
static int ixgbe_detach(device_t);
static int ixgbe_shutdown(device_t);
+static int ixgbe_suspend(device_t);
+static int ixgbe_resume(device_t);
static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t);
static void ixgbe_init(void *);
static void ixgbe_init_locked(struct adapter *);
@@ -136,7 +138,12 @@ static int ixgbe_setup_msix(struct adapter *);
static void ixgbe_free_pci_resources(struct adapter *);
static void ixgbe_local_timer(void *);
static int ixgbe_setup_interface(device_t, struct adapter *);
+static void ixgbe_config_dmac(struct adapter *);
+static void ixgbe_config_delay_values(struct adapter *);
static void ixgbe_config_link(struct adapter *);
+static void ixgbe_check_eee_support(struct adapter *);
+static void ixgbe_check_wol_support(struct adapter *);
+static int ixgbe_setup_low_power_mode(struct adapter *);
static void ixgbe_rearm_queues(struct adapter *, u64);
static void ixgbe_initialize_transmit_units(struct adapter *);
@@ -150,9 +157,6 @@ static void ixgbe_update_stats_counters(struct adapter *);
static void ixgbe_set_promisc(struct adapter *);
static void ixgbe_set_multi(struct adapter *);
static void ixgbe_update_link_status(struct adapter *);
-static int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS);
-static int ixgbe_set_advertise(SYSCTL_HANDLER_ARGS);
-static int ixgbe_set_thermal_test(SYSCTL_HANDLER_ARGS);
static void ixgbe_set_ivar(struct adapter *, u8, u8, s8);
static void ixgbe_configure_ivars(struct adapter *);
static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *);
@@ -161,7 +165,22 @@ static void ixgbe_setup_vlan_hw_support(struct adapter *);
static void ixgbe_register_vlan(void *, struct ifnet *, u16);
static void ixgbe_unregister_vlan(void *, struct ifnet *, u16);
-static void ixgbe_add_hw_stats(struct adapter *adapter);
+static void ixgbe_add_device_sysctls(struct adapter *);
+static void ixgbe_add_hw_stats(struct adapter *);
+
+/* Sysctl handlers */
+static int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS);
+static int ixgbe_set_advertise(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS);
+static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS);
/* Support for pluggable optic modules */
static bool ixgbe_sfp_probe(struct adapter *);
@@ -179,15 +198,12 @@ static void ixgbe_handle_que(void *, int);
static void ixgbe_handle_link(void *, int);
static void ixgbe_handle_msf(void *, int);
static void ixgbe_handle_mod(void *, int);
+static void ixgbe_handle_phy(void *, int);
#ifdef IXGBE_FDIR
static void ixgbe_reinit_fdir(void *, int);
#endif
-
-/* Missing shared code prototype */
-extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw);
-
/*********************************************************************
* FreeBSD Device Interface Entry Points
*********************************************************************/
@@ -198,6 +214,8 @@ static device_method_t ix_methods[] = {
DEVMETHOD(device_attach, ixgbe_attach),
DEVMETHOD(device_detach, ixgbe_detach),
DEVMETHOD(device_shutdown, ixgbe_shutdown),
+ DEVMETHOD(device_suspend, ixgbe_suspend),
+ DEVMETHOD(device_resume, ixgbe_resume),
DEVMETHOD_END
};
@@ -404,32 +422,6 @@ ixgbe_attach(device_t dev)
/* Core Lock Init*/
IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
- /* SYSCTL APIs */
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
- adapter, 0, ixgbe_set_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC);
-
- SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "enable_aim", CTLFLAG_RW,
- &ixgbe_enable_aim, 1, "Interrupt Moderation");
-
- /*
- ** Allow a kind of speed control by forcing the autoneg
- ** advertised speed list to only a certain value, this
- ** supports 1G on 82599 devices, and 100Mb on x540.
- */
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
- adapter, 0, ixgbe_set_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED);
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "ts", CTLTYPE_INT | CTLFLAG_RW, adapter,
- 0, ixgbe_set_thermal_test, "I", "Thermal Test");
-
/* Set up the timer callout */
callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
@@ -559,22 +551,26 @@ ixgbe_attach(device_t dev)
adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST);
- /*
- ** Check PCIE slot type/speed/width
- */
+ /* Check PCIE slot type/speed/width */
ixgbe_get_slot_info(hw);
/* Set an initial default flow control value */
adapter->fc = ixgbe_fc_full;
+ /* Check for certain supported features */
+ ixgbe_check_wol_support(adapter);
+ ixgbe_check_eee_support(adapter);
+
+ /* Add sysctls */
+ ixgbe_add_device_sysctls(adapter);
+ ixgbe_add_hw_stats(adapter);
+
/* let hardware know driver is loaded */
ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
- ixgbe_add_hw_stats(adapter);
-
#ifdef DEV_NETMAP
ixgbe_netmap_attach(adapter);
#endif /* DEV_NETMAP */
@@ -618,8 +614,9 @@ ixgbe_detach(device_t dev)
return (EBUSY);
}
+ /* Stop the adapter */
IXGBE_CORE_LOCK(adapter);
- ixgbe_stop(adapter);
+ ixgbe_setup_low_power_mode(adapter);
IXGBE_CORE_UNLOCK(adapter);
for (int i = 0; i < adapter->num_queues; i++, que++, txr++) {
@@ -637,6 +634,7 @@ ixgbe_detach(device_t dev)
taskqueue_drain(adapter->tq, &adapter->link_task);
taskqueue_drain(adapter->tq, &adapter->mod_task);
taskqueue_drain(adapter->tq, &adapter->msf_task);
+ taskqueue_drain(adapter->tq, &adapter->phy_task);
#ifdef IXGBE_FDIR
taskqueue_drain(adapter->tq, &adapter->fdir_task);
#endif
@@ -681,9 +679,77 @@ static int
ixgbe_shutdown(device_t dev)
{
struct adapter *adapter = device_get_softc(dev);
+ int error = 0;
+
+ INIT_DEBUGOUT("ixgbe_shutdown: begin");
+
IXGBE_CORE_LOCK(adapter);
- ixgbe_stop(adapter);
+ error = ixgbe_setup_low_power_mode(adapter);
+ IXGBE_CORE_UNLOCK(adapter);
+
+ return (error);
+}
+
+/**
+ * Methods for going from:
+ * D0 -> D3: ixgbe_suspend
+ * D3 -> D0: ixgbe_resume
+ */
+static int
+ixgbe_suspend(device_t dev)
+{
+ struct adapter *adapter = device_get_softc(dev);
+ int error = 0;
+
+ INIT_DEBUGOUT("ixgbe_suspend: begin");
+
+ IXGBE_CORE_LOCK(adapter);
+
+ error = ixgbe_setup_low_power_mode(adapter);
+
+ /* Save state and power down */
+ pci_save_state(dev);
+ pci_set_powerstate(dev, PCI_POWERSTATE_D3);
+
+ IXGBE_CORE_UNLOCK(adapter);
+
+ return (error);
+}
+
+static int
+ixgbe_resume(device_t dev)
+{
+ struct adapter *adapter = device_get_softc(dev);
+ struct ifnet *ifp = adapter->ifp;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 wus;
+
+ INIT_DEBUGOUT("ixgbe_resume: begin");
+
+ IXGBE_CORE_LOCK(adapter);
+
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+ pci_restore_state(dev);
+
+ /* Read & clear WUS register */
+ wus = IXGBE_READ_REG(hw, IXGBE_WUS);
+ if (wus)
+ device_printf(dev, "Woken up by (WUS): %#010x\n",
+ IXGBE_READ_REG(hw, IXGBE_WUS));
+ IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
+ /* And clear WUFC until next low-power transition */
+ IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
+
+ /*
+ * Required after D3->D0 transition;
+ * will re-advertise all previous advertised speeds
+ */
+ if (ifp->if_flags & IFF_UP)
+ ixgbe_init_locked(adapter);
+
IXGBE_CORE_UNLOCK(adapter);
+
+ INIT_DEBUGOUT("ixgbe_resume: end");
return (0);
}
@@ -736,13 +802,13 @@ ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
break;
case SIOCSIFMTU:
IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
- if (ifr->ifr_mtu > IXGBE_MAX_FRAME_SIZE - ETHER_HDR_LEN) {
+ if (ifr->ifr_mtu > IXGBE_MAX_MTU) {
error = EINVAL;
} else {
IXGBE_CORE_LOCK(adapter);
ifp->if_mtu = ifr->ifr_mtu;
adapter->max_frame_size =
- ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+ ifp->if_mtu + IXGBE_MTU_HDR;
ixgbe_init_locked(adapter);
IXGBE_CORE_UNLOCK(adapter);
}
@@ -891,7 +957,7 @@ ixgbe_init_locked(struct adapter *adapter)
/* Prepare transmit descriptors and buffers */
if (ixgbe_setup_transmit_structures(adapter)) {
- device_printf(dev,"Could not setup transmit structures\n");
+ device_printf(dev, "Could not setup transmit structures\n");
ixgbe_stop(adapter);
return;
}
@@ -917,7 +983,7 @@ ixgbe_init_locked(struct adapter *adapter)
/* Prepare receive descriptors and buffers */
if (ixgbe_setup_receive_structures(adapter)) {
- device_printf(dev,"Could not setup receive structures\n");
+ device_printf(dev, "Could not setup receive structures\n");
ixgbe_stop(adapter);
return;
}
@@ -932,11 +998,16 @@ ixgbe_init_locked(struct adapter *adapter)
/* Add for Module detection */
if (hw->mac.type == ixgbe_mac_82599EB)
- gpie |= IXGBE_SDP2_GPIEN_BY_MAC(hw);
+ gpie |= IXGBE_SDP2_GPIEN;
- /* Thermal Failure Detection */
- if (hw->mac.type == ixgbe_mac_X540)
- gpie |= IXGBE_SDP0_GPIEN_BY_MAC(hw);
+ /*
+ * Thermal Failure Detection (X540)
+ * Link Detection (X552)
+ */
+ if (hw->mac.type == ixgbe_mac_X540 ||
+ hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
+ hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
+ gpie |= IXGBE_SDP0_GPIEN_X540;
if (adapter->msix > 1) {
/* Enable Enhanced MSIX mode */
@@ -948,6 +1019,7 @@ ixgbe_init_locked(struct adapter *adapter)
/* Set MTU size */
if (ifp->if_mtu > ETHERMTU) {
+ /* aka IXGBE_MAXFRS on 82599 and newer */
mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
mhadd &= ~IXGBE_MHADD_MFS_MASK;
mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT;
@@ -955,7 +1027,6 @@ ixgbe_init_locked(struct adapter *adapter)
}
/* Now enable all the queues */
-
for (int i = 0; i < adapter->num_queues; i++) {
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
txdctl |= IXGBE_TXDCTL_ENABLE;
@@ -1072,55 +1143,25 @@ ixgbe_init_locked(struct adapter *adapter)
/* Set moderation on the Link interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR);
+ /* Configure Energy Efficient Ethernet for supported devices */
+ if (adapter->eee_support)
+ ixgbe_setup_eee(hw, adapter->eee_enabled);
+
/* Config/Enable Link */
ixgbe_config_link(adapter);
/* Hardware Packet Buffer & Flow Control setup */
- {
- u32 rxpb, frame, size, tmp;
-
- frame = adapter->max_frame_size;
+ ixgbe_config_delay_values(adapter);
- /* Calculate High Water */
- switch (hw->mac.type) {
- case ixgbe_mac_X540:
- case ixgbe_mac_X550:
- case ixgbe_mac_X550EM_a:
- case ixgbe_mac_X550EM_x:
- tmp = IXGBE_DV_X540(frame, frame);
- break;
- default:
- tmp = IXGBE_DV(frame, frame);
- break;
- }
- size = IXGBE_BT2KB(tmp);
- rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
- hw->fc.high_water[0] = rxpb - size;
-
- /* Now calculate Low Water */
- switch (hw->mac.type) {
- case ixgbe_mac_X540:
- case ixgbe_mac_X550:
- case ixgbe_mac_X550EM_a:
- case ixgbe_mac_X550EM_x:
- tmp = IXGBE_LOW_DV_X540(frame);
- break;
- default:
- tmp = IXGBE_LOW_DV(frame);
- break;
- }
- hw->fc.low_water[0] = IXGBE_BT2KB(tmp);
-
- hw->fc.requested_mode = adapter->fc;
- hw->fc.pause_time = IXGBE_FC_PAUSE;
- hw->fc.send_xon = TRUE;
- }
/* Initialize the FC settings */
ixgbe_start_hw(hw);
/* Set up VLAN support and filter */
ixgbe_setup_vlan_hw_support(adapter);
+ /* Setup DMA Coalescing */
+ ixgbe_config_dmac(adapter);
+
/* And now turn on interrupts */
ixgbe_enable_intr(adapter);
@@ -1141,6 +1182,46 @@ ixgbe_init(void *arg)
return;
}
+static void
+ixgbe_config_delay_values(struct adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 rxpb, frame, size, tmp;
+
+ frame = adapter->max_frame_size;
+
+ /* Calculate High Water */
+ switch (hw->mac.type) {
+ case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ tmp = IXGBE_DV_X540(frame, frame);
+ break;
+ default:
+ tmp = IXGBE_DV(frame, frame);
+ break;
+ }
+ size = IXGBE_BT2KB(tmp);
+ rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
+ hw->fc.high_water[0] = rxpb - size;
+
+ /* Now calculate Low Water */
+ switch (hw->mac.type) {
+ case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ tmp = IXGBE_LOW_DV_X540(frame);
+ break;
+ default:
+ tmp = IXGBE_LOW_DV(frame);
+ break;
+ }
+ hw->fc.low_water[0] = IXGBE_BT2KB(tmp);
+
+ hw->fc.requested_mode = adapter->fc;
+ hw->fc.pause_time = IXGBE_FC_PAUSE;
+ hw->fc.send_xon = TRUE;
+}
/*
**
@@ -1271,6 +1352,11 @@ ixgbe_legacy_irq(void *arg)
if (reg_eicr & IXGBE_EICR_LSC)
taskqueue_enqueue(adapter->tq, &adapter->link_task);
+ /* External PHY interrupt */
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
+ (reg_eicr & IXGBE_EICR_GPI_SDP0_X540))
+ taskqueue_enqueue(adapter->tq, &adapter->phy_task);
+
if (more)
taskqueue_enqueue(que->tq, &que->que_task);
else
@@ -1379,9 +1465,9 @@ ixgbe_msix_link(void *arg)
{
struct adapter *adapter = arg;
struct ixgbe_hw *hw = &adapter->hw;
- u32 reg_eicr;
+ u32 reg_eicr, mod_mask;
- ++adapter->vector_irq;
+ ++adapter->link_irq;
/* First get the cause */
reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
@@ -1409,42 +1495,46 @@ ixgbe_msix_link(void *arg)
device_printf(adapter->dev, "\nCRITICAL: ECC ERROR!! "
"Please Reboot!!\n");
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
- } else
+ }
- if (ixgbe_is_sfp(hw)) {
- if (reg_eicr & IXGBE_EICR_GPI_SDP1) {
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
- taskqueue_enqueue(adapter->tq, &adapter->msf_task);
- } else if (reg_eicr & IXGBE_EICR_GPI_SDP2) {
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2_BY_MAC(hw));
- taskqueue_enqueue(adapter->tq, &adapter->mod_task);
- }
+ /* Check for over temp condition */
+ if (reg_eicr & IXGBE_EICR_TS) {
+ device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! "
+ "PHY IS SHUT DOWN!!\n");
+ device_printf(adapter->dev, "System shutdown required!\n");
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS);
}
- }
+ }
+
+ /* Pluggable optics-related interrupt */
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
+ mod_mask = IXGBE_EICR_GPI_SDP0_X540;
+ else
+ mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw);
+
+ if (ixgbe_is_sfp(hw)) {
+ if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) {
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
+ taskqueue_enqueue(adapter->tq, &adapter->msf_task);
+ } else if (reg_eicr & mod_mask) {
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask);
+ taskqueue_enqueue(adapter->tq, &adapter->mod_task);
+ }
+ }
/* Check for fan failure */
if ((hw->device_id == IXGBE_DEV_ID_82598AT) &&
- (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
+ (reg_eicr & IXGBE_EICR_GPI_SDP1)) {
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! "
"REPLACE IMMEDIATELY!!\n");
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
}
- /* Check for over temp condition */
- switch (hw->mac.type) {
- case ixgbe_mac_X540:
- case ixgbe_mac_X550:
- case ixgbe_mac_X550EM_a:
- if (reg_eicr & IXGBE_EICR_TS) {
- device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! "
- "PHY IS SHUT DOWN!!\n");
- device_printf(adapter->dev, "System shutdown required\n");
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS);
- }
- break;
- default:
- /* Other MACs have no thermal sensor interrupt */
- break;
+ /* External PHY interrupt */
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
+ (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) {
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540);
+ taskqueue_enqueue(adapter->tq, &adapter->phy_task);
}
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
@@ -1543,20 +1633,26 @@ ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR)
switch (adapter->link_speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
- ifmr->ifm_active |= IFM_10_T | IFM_FDX;
+ ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
+ break;
+ case IXGBE_LINK_SPEED_2_5GB_FULL:
+ ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
break;
case IXGBE_LINK_SPEED_1GB_FULL:
- ifmr->ifm_active |= IFM_10_5 | IFM_FDX;
+ ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
break;
}
- if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4
+ else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4
|| layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX)
switch (adapter->link_speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
- ifmr->ifm_active |= IFM_10_2 | IFM_FDX;
+ ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX;
+ break;
+ case IXGBE_LINK_SPEED_2_5GB_FULL:
+ ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
break;
case IXGBE_LINK_SPEED_1GB_FULL:
- ifmr->ifm_active |= IFM_10_5 | IFM_FDX;
+ ifmr->ifm_active |= IFM_1000_CX | IFM_FDX;
break;
}
@@ -1565,10 +1661,12 @@ ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
ifmr->ifm_active |= IFM_UNKNOWN;
#if __FreeBSD_version >= 900025
- /* Flow control setting */
- if (adapter->fc == ixgbe_fc_rx_pause || adapter->fc == ixgbe_fc_full)
+ /* Display current flow control setting used on link */
+ if (hw->fc.current_mode == ixgbe_fc_rx_pause ||
+ hw->fc.current_mode == ixgbe_fc_full)
ifmr->ifm_active |= IFM_ETH_RXPAUSE;
- if (adapter->fc == ixgbe_fc_tx_pause || adapter->fc == ixgbe_fc_full)
+ if (hw->fc.current_mode == ixgbe_fc_tx_pause ||
+ hw->fc.current_mode == ixgbe_fc_full)
ifmr->ifm_active |= IFM_ETH_TXPAUSE;
#endif
@@ -1598,21 +1696,22 @@ ixgbe_media_change(struct ifnet * ifp)
if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
return (EINVAL);
+ if (hw->phy.media_type == ixgbe_media_type_backplane)
+ return (EPERM);
+
/*
** We don't actually need to check against the supported
** media types of the adapter; ifmedia will take care of
** that for us.
- ** NOTE: this relies on falling thru the switch
- ** to get all the values set, it can be confusing.
*/
switch (IFM_SUBTYPE(ifm->ifm_media)) {
case IFM_AUTO:
case IFM_10G_T:
speed |= IXGBE_LINK_SPEED_100_FULL;
case IFM_10G_LRM:
- case IFM_10G_SR: /* KR, too */
+ case IFM_10G_SR: /* KR, too */
case IFM_10G_LR:
- case IFM_10G_CX4: /* KX4 for now */
+ case IFM_10G_CX4: /* KX4 */
speed |= IXGBE_LINK_SPEED_1GB_FULL;
case IFM_10G_TWINAX:
speed |= IXGBE_LINK_SPEED_10GB_FULL;
@@ -1621,7 +1720,7 @@ ixgbe_media_change(struct ifnet * ifp)
speed |= IXGBE_LINK_SPEED_100_FULL;
case IFM_1000_LX:
case IFM_1000_SX:
- case IFM_1000_CX: /* KX until there's real support */
+ case IFM_1000_CX: /* KX */
speed |= IXGBE_LINK_SPEED_1GB_FULL;
break;
case IFM_100_TX:
@@ -1641,7 +1740,7 @@ ixgbe_media_change(struct ifnet * ifp)
return (0);
invalid:
- device_printf(adapter->dev, "Invalid media type\n");
+ device_printf(adapter->dev, "Invalid media type!\n");
return (EINVAL);
}
@@ -1866,7 +1965,6 @@ ixgbe_update_link_status(struct adapter *adapter)
struct ifnet *ifp = adapter->ifp;
device_t dev = adapter->dev;
-
if (adapter->link_up){
if (adapter->link_active == FALSE) {
if (bootverbose)
@@ -1876,6 +1974,8 @@ ixgbe_update_link_status(struct adapter *adapter)
adapter->link_active = TRUE;
/* Update any Flow Control changes */
ixgbe_fc_enable(&adapter->hw);
+ /* Update DMA coalescing config */
+ ixgbe_config_dmac(adapter);
if_link_state_change(ifp, LINK_STATE_UP);
}
} else { /* Link down */
@@ -1962,7 +2062,7 @@ ixgbe_identify_hardware(struct adapter *adapter)
/* We need this here to set the num_segs below */
ixgbe_set_mac_type(hw);
- /* Pick up the 82599 and VF settings */
+ /* Pick up the 82599 settings */
if (hw->mac.type != ixgbe_mac_82598EB) {
hw->phy.smart_speed = ixgbe_smart_speed;
adapter->num_segs = IXGBE_82599_SCATTER;
@@ -2072,6 +2172,7 @@ ixgbe_allocate_legacy(struct adapter *adapter)
TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter);
TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter);
TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter);
+ TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter);
#ifdef IXGBE_FDIR
TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter);
#endif
@@ -2137,8 +2238,6 @@ ixgbe_allocate_msix(struct adapter *adapter)
}
#endif
-
-
for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) {
rid = vector + 1;
que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
@@ -2188,14 +2287,11 @@ ixgbe_allocate_msix(struct adapter *adapter)
"Bound RSS bucket %d to CPU %d\n",
i, cpu_id);
#else
-#if 0 // This is too noisy
- device_printf(dev,
- "Bound queue %d to cpu %d\n",
- i, cpu_id);
+ if (bootverbose)
+ device_printf(dev,
+ "Bound queue %d to cpu %d\n",
+ i, cpu_id);
#endif
-#endif
-
-
#ifndef IXGBE_LEGACY_TX
TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr);
#endif
@@ -2241,6 +2337,7 @@ ixgbe_allocate_msix(struct adapter *adapter)
TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter);
TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter);
TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter);
+ TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter);
#ifdef IXGBE_FDIR
TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter);
#endif
@@ -2466,6 +2563,12 @@ ixgbe_setup_interface(device_t dev, struct adapter *adapter)
#if __FreeBSD_version >= 1100036
if_setgetcounterfn(ifp, ixgbe_get_counter);
#endif
+#if __FreeBSD_version >= 1100045
+ /* TSO parameters */
+ ifp->if_hw_tsomax = 65518;
+ ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER;
+ ifp->if_hw_tsomaxsegsize = 2048;
+#endif
#ifndef IXGBE_LEGACY_TX
ifp->if_transmit = ixgbe_mq_start;
ifp->if_qflush = ixgbe_qflush;
@@ -2549,10 +2652,6 @@ ixgbe_add_media_types(struct adapter *adapter)
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX)
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
-#if 0
- if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_LX)
- ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
-#endif
/*
** Other (no matching FreeBSD media type):
@@ -2561,25 +2660,24 @@ ixgbe_add_media_types(struct adapter *adapter)
*/
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) {
device_printf(dev, "Media supported: 10GbaseKR\n");
- device_printf(dev, "10GbaseKR mapped to 10baseT\n");
- ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL);
+ device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n");
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
}
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) {
device_printf(dev, "Media supported: 10GbaseKX4\n");
- device_printf(dev, "10GbaseKX4 mapped to 10base2\n");
- ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_2, 0, NULL);
+ device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n");
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
}
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) {
device_printf(dev, "Media supported: 1000baseKX\n");
- device_printf(dev, "1000baseKX mapped to 10base5\n");
- ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_5, 0, NULL);
+ device_printf(dev, "1000baseKX mapped to 1000baseCX\n");
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
}
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) {
/* Someday, someone will care about you... */
device_printf(dev, "Media supported: 1000baseBX\n");
}
- /* Very old */
if (hw->device_id == IXGBE_DEV_ID_82598AT) {
ifmedia_add(&adapter->media,
IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
@@ -2707,7 +2805,8 @@ ixgbe_initialise_rss_mapping(struct adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
uint32_t reta;
- int i, j, queue_id;
+ int i, j, queue_id, table_size;
+ int index_mult;
uint32_t rss_key[10];
uint32_t mrqc;
#ifdef RSS
@@ -2725,8 +2824,23 @@ ixgbe_initialise_rss_mapping(struct adapter *adapter)
arc4rand(&rss_key, sizeof(rss_key), 0);
#endif
+ /* Set multiplier for RETA setup and table size based on MAC */
+ index_mult = 0x1;
+ table_size = 128;
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
+ index_mult = 0x11;
+ break;
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ table_size = 512;
+ break;
+ default:
+ break;
+ }
+
/* Set up the redirection table */
- for (i = 0, j = 0; i < 128; i++, j++) {
+ for (i = 0, j = 0; i < table_size; i++, j++) {
if (j == adapter->num_queues) j = 0;
#ifdef RSS
/*
@@ -2737,7 +2851,7 @@ ixgbe_initialise_rss_mapping(struct adapter *adapter)
queue_id = rss_get_indirection_to_bucket(i);
queue_id = queue_id % adapter->num_queues;
#else
- queue_id = (j * 0x11);
+ queue_id = (j * index_mult);
#endif
/*
* The low 8 bits are for hash value (n+0);
@@ -2746,7 +2860,10 @@ ixgbe_initialise_rss_mapping(struct adapter *adapter)
reta = reta >> 8;
reta = reta | ( ((uint32_t) queue_id) << 24);
if ((i & 3) == 3) {
- IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
+ if (i < 128)
+ IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta);
reta = 0;
}
}
@@ -2835,8 +2952,10 @@ ixgbe_initialize_receive_units(struct adapter *adapter)
/* Enable broadcasts */
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
fctrl |= IXGBE_FCTRL_BAM;
- fctrl |= IXGBE_FCTRL_DPF;
- fctrl |= IXGBE_FCTRL_PMCF;
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ fctrl |= IXGBE_FCTRL_DPF;
+ fctrl |= IXGBE_FCTRL_PMCF;
+ }
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
/* Set for Jumbo Frames? */
@@ -3046,30 +3165,37 @@ ixgbe_enable_intr(struct adapter *adapter)
mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
/* Enable Fan Failure detection */
if (hw->device_id == IXGBE_DEV_ID_82598AT)
- mask |= IXGBE_EIMS_GPI_SDP1_BY_MAC(hw);
+ mask |= IXGBE_EIMS_GPI_SDP1;
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
mask |= IXGBE_EIMS_ECC;
/* Temperature sensor on some adapters */
- mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
+ mask |= IXGBE_EIMS_GPI_SDP0;
/* SFP+ (RX_LOS_N & MOD_ABS_N) */
- mask |= IXGBE_EIMS_GPI_SDP1_BY_MAC(hw);
- mask |= IXGBE_EIMS_GPI_SDP2_BY_MAC(hw);
+ mask |= IXGBE_EIMS_GPI_SDP1;
+ mask |= IXGBE_EIMS_GPI_SDP2;
#ifdef IXGBE_FDIR
mask |= IXGBE_EIMS_FLOW_DIR;
#endif
break;
case ixgbe_mac_X540:
- case ixgbe_mac_X550:
- case ixgbe_mac_X550EM_a:
- case ixgbe_mac_X550EM_x:
/* Detect if Thermal Sensor is enabled */
fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
if (fwsm & IXGBE_FWSM_TS_ENABLED)
mask |= IXGBE_EIMS_TS;
- /* XXX: Which SFP mode line does this look at? */
- if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
+ mask |= IXGBE_EIMS_ECC;
+#ifdef IXGBE_FDIR
+ mask |= IXGBE_EIMS_FLOW_DIR;
+#endif
+ break;
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ /* MAC thermal sensor is automatically enabled */
+ mask |= IXGBE_EIMS_TS;
+ /* Some devices use SDP0 for important information */
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
+ hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T)
mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
mask |= IXGBE_EIMS_ECC;
#ifdef IXGBE_FDIR
@@ -3082,7 +3208,7 @@ ixgbe_enable_intr(struct adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask);
- /* With RSS we use auto clear */
+ /* With MSI-X we use auto clear */
if (adapter->msix_mem) {
mask = IXGBE_EIMS_ENABLE_MASK;
/* Don't autoclear Link */
@@ -3136,10 +3262,12 @@ ixgbe_get_slot_info(struct ixgbe_hw *hw)
if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) {
ixgbe_get_bus_info(hw);
/* These devices don't use PCI-E */
- if (hw->mac.type == ixgbe_mac_X550EM_x
- || hw->mac.type == ixgbe_mac_X550EM_a)
+ switch (hw->mac.type) {
+ case ixgbe_mac_X550EM_x:
return;
- goto display;
+ default:
+ goto display;
+ }
}
/*
@@ -3261,7 +3389,6 @@ ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type)
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
case ixgbe_mac_X550:
- case ixgbe_mac_X550EM_a:
case ixgbe_mac_X550EM_x:
if (type == -1) { /* MISC IVAR */
index = (entry & 1) * 8;
@@ -3290,8 +3417,14 @@ ixgbe_configure_ivars(struct adapter *adapter)
if (ixgbe_max_interrupt_rate > 0)
newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8;
- else
+ else {
+ /*
+ ** Disable DMA coalescing if interrupt moderation is
+ ** disabled.
+ */
+ adapter->dmac = 0;
newitr = 0;
+ }
for (int i = 0; i < adapter->num_queues; i++, que++) {
/* First the RX queue entry */
@@ -3351,7 +3484,7 @@ ixgbe_handle_link(void *context, int pending)
ixgbe_check_link(&adapter->hw,
&adapter->link_speed, &adapter->link_up, 0);
- ixgbe_update_link_status(adapter);
+ ixgbe_update_link_status(adapter);
}
/*
@@ -3411,6 +3544,28 @@ ixgbe_handle_msf(void *context, int pending)
return;
}
+/*
+** Tasklet for handling interrupts from an external PHY
+*/
+static void
+ixgbe_handle_phy(void *context, int pending)
+{
+ struct adapter *adapter = context;
+ struct ixgbe_hw *hw = &adapter->hw;
+ int error;
+
+ error = hw->phy.ops.handle_lasi(hw);
+ if (error == IXGBE_ERR_OVERTEMP)
+ device_printf(adapter->dev,
+ "CRITICAL: EXTERNAL PHY OVER TEMP!! "
+ " PHY will downshift to lower power state!\n");
+ else if (error)
+ device_printf(adapter->dev,
+ "Error handling LASI interrupt: %d\n",
+ error);
+ return;
+}
+
#ifdef IXGBE_FDIR
/*
** Tasklet for reinitializing the Flow Director filter table
@@ -3433,6 +3588,127 @@ ixgbe_reinit_fdir(void *context, int pending)
}
#endif
+/*********************************************************************
+ *
+ * Configure DMA Coalescing
+ *
+ **********************************************************************/
+static void
+ixgbe_config_dmac(struct adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config;
+
+ if (hw->mac.type < ixgbe_mac_X550 ||
+ !hw->mac.ops.dmac_config)
+ return;
+
+ if (dcfg->watchdog_timer ^ adapter->dmac ||
+ dcfg->link_speed ^ adapter->link_speed) {
+ dcfg->watchdog_timer = adapter->dmac;
+ dcfg->fcoe_en = false;
+ dcfg->link_speed = adapter->link_speed;
+ dcfg->num_tcs = 1;
+
+ INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n",
+ dcfg->watchdog_timer, dcfg->link_speed);
+
+ hw->mac.ops.dmac_config(hw);
+ }
+}
+
+/*
+ * Checks whether the adapter supports Energy Efficient Ethernet
+ * or not, based on device ID.
+ */
+static void
+ixgbe_check_eee_support(struct adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ adapter->eee_support = adapter->eee_enabled =
+ (hw->device_id == IXGBE_DEV_ID_X550T ||
+ hw->device_id == IXGBE_DEV_ID_X550EM_X_KR);
+}
+
+/*
+ * Checks whether the adapter's ports are capable of
+ * Wake On LAN by reading the adapter's NVM.
+ *
+ * Sets each port's hw->wol_enabled value depending
+ * on the value read here.
+ */
+static void
+ixgbe_check_wol_support(struct adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 dev_caps = 0;
+
+ /* Find out WoL support for port */
+ adapter->wol_support = hw->wol_enabled = 0;
+ ixgbe_get_device_caps(hw, &dev_caps);
+ if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
+ ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) &&
+ hw->bus.func == 0))
+ adapter->wol_support = hw->wol_enabled = 1;
+
+ /* Save initial wake up filter configuration */
+ adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC);
+
+ return;
+}
+
+/*
+ * Prepare the adapter/port for LPLU and/or WoL
+ */
+static int
+ixgbe_setup_low_power_mode(struct adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ device_t dev = adapter->dev;
+ s32 error = 0;
+
+ mtx_assert(&adapter->core_mtx, MA_OWNED);
+
+ /* Limit power management flow to X550EM baseT */
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T
+ && hw->phy.ops.enter_lplu) {
+ /* Turn off support for APM wakeup. (Using ACPI instead) */
+ IXGBE_WRITE_REG(hw, IXGBE_GRC,
+ IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2);
+
+ /*
+ * Clear Wake Up Status register to prevent any previous wakeup
+ * events from waking us up immediately after we suspend.
+ */
+ IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff);
+
+ /*
+ * Program the Wakeup Filter Control register with user filter
+ * settings
+ */
+ IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc);
+
+ /* Enable wakeups and power management in Wakeup Control */
+ IXGBE_WRITE_REG(hw, IXGBE_WUC,
+ IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN);
+
+ /* X550EM baseT adapters need a special LPLU flow */
+ hw->phy.reset_disable = true;
+ ixgbe_stop(adapter);
+ error = hw->phy.ops.enter_lplu(hw);
+ if (error)
+ device_printf(dev,
+ "Error entering LPLU: %d\n", error);
+ hw->phy.reset_disable = false;
+ } else {
+ /* Just stop for other adapters */
+ ixgbe_stop(adapter);
+ }
+
+ return error;
+}
+
/**********************************************************************
*
* Update the board statistics counters.
@@ -3450,42 +3726,6 @@ ixgbe_update_stats_counters(struct adapter *adapter)
adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC);
adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC);
- /*
- ** Note: these are for the 8 possible traffic classes,
- ** which in current implementation is unused,
- ** therefore only 0 should read real data.
- */
- for (int i = 0; i < 8; i++) {
- u32 mp;
- mp = IXGBE_READ_REG(hw, IXGBE_MPC(i));
- /* missed_rx tallies misses for the gprc workaround */
- missed_rx += mp;
- /* global total per queue */
- adapter->stats.pf.mpc[i] += mp;
- /* total for stats display */
- total_missed_rx += adapter->stats.pf.mpc[i];
- if (hw->mac.type == ixgbe_mac_82598EB) {
- adapter->stats.pf.rnbc[i] +=
- IXGBE_READ_REG(hw, IXGBE_RNBC(i));
- adapter->stats.pf.qbtc[i] +=
- IXGBE_READ_REG(hw, IXGBE_QBTC(i));
- adapter->stats.pf.qbrc[i] +=
- IXGBE_READ_REG(hw, IXGBE_QBRC(i));
- adapter->stats.pf.pxonrxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
- } else
- adapter->stats.pf.pxonrxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
- adapter->stats.pf.pxontxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
- adapter->stats.pf.pxofftxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
- if (hw->mac.type != ixgbe_mac_X550EM_x)
- adapter->stats.pf.pxoffrxc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
- adapter->stats.pf.pxon2offc[i] +=
- IXGBE_READ_REG(hw, IXGBE_PXON2OFFCNT(i));
- }
for (int i = 0; i < 16; i++) {
adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
@@ -3593,6 +3833,8 @@ static uint64_t
ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt)
{
struct adapter *adapter;
+ struct tx_ring *txr;
+ uint64_t rv;
adapter = if_getsoftc(ifp);
@@ -3613,6 +3855,12 @@ ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt)
return (0);
case IFCOUNTER_IQDROPS:
return (adapter->iqdrops);
+ case IFCOUNTER_OQDROPS:
+ rv = 0;
+ txr = adapter->tx_rings;
+ for (int i = 0; i < adapter->num_queues; i++, txr++)
+ rv += txr->br->br_drops;
+ return (rv);
case IFCOUNTER_IERRORS:
return (adapter->ierrors);
default:
@@ -3721,6 +3969,108 @@ ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
return 0;
}
+static void
+ixgbe_add_device_sysctls(struct adapter *adapter)
+{
+ device_t dev = adapter->dev;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct sysctl_oid_list *child;
+ struct sysctl_ctx_list *ctx;
+
+ ctx = device_get_sysctl_ctx(dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
+
+ /* Sysctls for all devices */
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc",
+ CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
+ ixgbe_set_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC);
+
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim",
+ CTLFLAG_RW,
+ &ixgbe_enable_aim, 1, "Interrupt Moderation");
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed",
+ CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
+ ixgbe_set_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED);
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test",
+ CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
+ ixgbe_sysctl_thermal_test, "I", "Thermal Test");
+
+ /* for X550 devices */
+ if (hw->mac.type >= ixgbe_mac_X550)
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac",
+ CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
+ ixgbe_sysctl_dmac, "I", "DMA Coalesce");
+
+ /* for X550T and X550EM backplane devices */
+ if (hw->device_id == IXGBE_DEV_ID_X550T ||
+ hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) {
+ struct sysctl_oid *eee_node;
+ struct sysctl_oid_list *eee_list;
+
+ eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee",
+ CTLFLAG_RD, NULL,
+ "Energy Efficient Ethernet sysctls");
+ eee_list = SYSCTL_CHILDREN(eee_node);
+
+ SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable",
+ CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
+ ixgbe_sysctl_eee_enable, "I",
+ "Enable or Disable EEE");
+
+ SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated",
+ CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
+ ixgbe_sysctl_eee_negotiated, "I",
+ "EEE negotiated on link");
+
+ SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status",
+ CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
+ ixgbe_sysctl_eee_tx_lpi_status, "I",
+ "Whether or not TX link is in LPI state");
+
+ SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status",
+ CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
+ ixgbe_sysctl_eee_rx_lpi_status, "I",
+ "Whether or not RX link is in LPI state");
+ }
+
+ /* for certain 10GBaseT devices */
+ if (hw->device_id == IXGBE_DEV_ID_X550T ||
+ hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable",
+ CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
+ ixgbe_sysctl_wol_enable, "I",
+ "Enable/Disable Wake on LAN");
+
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc",
+ CTLTYPE_INT | CTLFLAG_RW, adapter, 0,
+ ixgbe_sysctl_wufc, "I",
+ "Enable/Disable Wake Up Filters");
+ }
+
+ /* for X550EM 10GBaseT devices */
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
+ struct sysctl_oid *phy_node;
+ struct sysctl_oid_list *phy_list;
+
+ phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy",
+ CTLFLAG_RD, NULL,
+ "External PHY sysctls");
+ phy_list = SYSCTL_CHILDREN(phy_node);
+
+ SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp",
+ CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
+ ixgbe_sysctl_phy_temp, "I",
+ "Current External PHY Temperature (Celsius)");
+
+ SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred",
+ CTLTYPE_INT | CTLFLAG_RD, adapter, 0,
+ ixgbe_sysctl_phy_overtemp_occurred, "I",
+ "External PHY High Temperature Event Occurred");
+ }
+}
+
/*
* Add sysctl variables, one per statistic, to the system.
*/
@@ -3754,7 +4104,7 @@ ixgbe_add_hw_stats(struct adapter *adapter)
CTLFLAG_RD, &adapter->watchdog_events,
"Watchdog timeouts");
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq",
- CTLFLAG_RD, &adapter->vector_irq,
+ CTLFLAG_RD, &adapter->link_irq,
"Link MSIX IRQ Handled");
for (int i = 0; i < adapter->num_queues; i++, txr++) {
@@ -3791,6 +4141,9 @@ ixgbe_add_hw_stats(struct adapter *adapter)
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
CTLFLAG_RD, &txr->total_packets,
"Queue Packets Transmitted");
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops",
+ CTLFLAG_RD, &txr->br->br_drops,
+ "Packets dropped in buf_ring");
}
for (int i = 0; i < adapter->num_queues; i++, rxr++) {
@@ -4083,20 +4436,77 @@ ixgbe_set_advertise(SYSCTL_HANDLER_ARGS)
}
/*
-** Thermal Shutdown Trigger
-** - cause a Thermal Overtemp IRQ
-** - this now requires firmware enabling
-*/
+ * The following two sysctls are for X550 BaseT devices;
+ * they deal with the external PHY used in them.
+ */
static int
-ixgbe_set_thermal_test(SYSCTL_HANDLER_ARGS)
+ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS)
{
- int error, fire = 0;
struct adapter *adapter = (struct adapter *) arg1;
struct ixgbe_hw *hw = &adapter->hw;
+ u16 reg;
+ if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
+ device_printf(adapter->dev,
+ "Device has no supported external thermal sensor.\n");
+ return (ENODEV);
+ }
- if (hw->mac.type < ixgbe_mac_X540)
- return (0);
+ if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg)) {
+ device_printf(adapter->dev,
+ "Error reading from PHY's current temperature register\n");
+ return (EAGAIN);
+ }
+
+ /* Shift temp for output */
+ reg = reg >> 8;
+
+ return (sysctl_handle_int(oidp, NULL, reg, req));
+}
+
+/*
+ * Reports whether the current PHY temperature is over
+ * the overtemp threshold.
+ * - This is reported directly from the PHY
+ */
+static int
+ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 reg;
+
+ if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
+ device_printf(adapter->dev,
+ "Device has no supported external thermal sensor.\n");
+ return (ENODEV);
+ }
+
+ if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg)) {
+ device_printf(adapter->dev,
+ "Error reading from PHY's temperature status register\n");
+ return (EAGAIN);
+ }
+
+ /* Get occurrence bit */
+ reg = !!(reg & 0x4000);
+ return (sysctl_handle_int(oidp, 0, reg, req));
+}
+
+/*
+** Thermal Shutdown Trigger (internal MAC)
+** - Set this to 1 to cause an overtemp event to occur
+*/
+static int
+ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ixgbe_hw *hw = &adapter->hw;
+ int error, fire = 0;
error = sysctl_handle_int(oidp, &fire, 0, req);
if ((error) || (req->newptr == NULL))
@@ -4112,6 +4522,223 @@ ixgbe_set_thermal_test(SYSCTL_HANDLER_ARGS)
}
/*
+** Manage DMA Coalescing.
+** Control values:
+** 0/1 - off / on (use default value of 1000)
+**
+** Legal timer values are:
+** 50,100,250,500,1000,2000,5000,10000
+**
+** Turning off interrupt moderation will also turn this off.
+*/
+static int
+ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ifnet *ifp = adapter->ifp;
+ int error;
+ u16 oldval;
+
+ oldval = adapter->dmac;
+ error = sysctl_handle_int(oidp, &adapter->dmac, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+
+ switch (hw->mac.type) {
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ break;
+ default:
+ device_printf(adapter->dev,
+ "DMA Coalescing is only supported on X550 devices\n");
+ return (ENODEV);
+ }
+
+ switch (adapter->dmac) {
+ case 0:
+ /* Disabled */
+ break;
+ case 1: /* Enable and use default */
+ adapter->dmac = 1000;
+ break;
+ case 50:
+ case 100:
+ case 250:
+ case 500:
+ case 1000:
+ case 2000:
+ case 5000:
+ case 10000:
+ /* Legal values - allow */
+ break;
+ default:
+ /* Do nothing, illegal value */
+ adapter->dmac = oldval;
+ return (EINVAL);
+ }
+
+ /* Re-initialize hardware if it's already running */
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ixgbe_init(adapter);
+
+ return (0);
+}
+
+/*
+ * Sysctl to enable/disable the WoL capability, if supported by the adapter.
+ * Values:
+ * 0 - disabled
+ * 1 - enabled
+ */
+static int
+ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ixgbe_hw *hw = &adapter->hw;
+ int new_wol_enabled;
+ int error = 0;
+
+ new_wol_enabled = hw->wol_enabled;
+ error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+ if (new_wol_enabled == hw->wol_enabled)
+ return (0);
+
+ if (new_wol_enabled > 0 && !adapter->wol_support)
+ return (ENODEV);
+ else
+ hw->wol_enabled = !!(new_wol_enabled);
+
+ return (0);
+}
+
+/*
+ * Sysctl to enable/disable the Energy Efficient Ethernet capability,
+ * if supported by the adapter.
+ * Values:
+ * 0 - disabled
+ * 1 - enabled
+ */
+static int
+ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ifnet *ifp = adapter->ifp;
+ int new_eee_enabled, error = 0;
+
+ new_eee_enabled = adapter->eee_enabled;
+ error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+ if (new_eee_enabled == adapter->eee_enabled)
+ return (0);
+
+ if (new_eee_enabled > 0 && !adapter->eee_support)
+ return (ENODEV);
+ else
+ adapter->eee_enabled = !!(new_eee_enabled);
+
+ /* Re-initialize hardware if it's already running */
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ixgbe_init(adapter);
+
+ return (0);
+}
+
+/*
+ * Read-only sysctl indicating whether EEE support was negotiated
+ * on the link.
+ */
+static int
+ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ixgbe_hw *hw = &adapter->hw;
+ bool status;
+
+ status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG);
+
+ return (sysctl_handle_int(oidp, 0, status, req));
+}
+
+/*
+ * Read-only sysctl indicating whether RX Link is in LPI state.
+ */
+static int
+ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ixgbe_hw *hw = &adapter->hw;
+ bool status;
+
+ status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) &
+ IXGBE_EEE_RX_LPI_STATUS);
+
+ return (sysctl_handle_int(oidp, 0, status, req));
+}
+
+/*
+ * Read-only sysctl indicating whether TX Link is in LPI state.
+ */
+static int
+ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ struct ixgbe_hw *hw = &adapter->hw;
+ bool status;
+
+ status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) &
+ IXGBE_EEE_TX_LPI_STATUS);
+
+ return (sysctl_handle_int(oidp, 0, status, req));
+}
+
+/*
+ * Sysctl to enable/disable the types of packets that the
+ * adapter will wake up on upon receipt.
+ * WUFC - Wake Up Filter Control
+ * Flags:
+ * 0x1 - Link Status Change
+ * 0x2 - Magic Packet
+ * 0x4 - Direct Exact
+ * 0x8 - Directed Multicast
+ * 0x10 - Broadcast
+ * 0x20 - ARP/IPv4 Request Packet
+ * 0x40 - Direct IPv4 Packet
+ * 0x80 - Direct IPv6 Packet
+ *
+ * Setting another flag will cause the sysctl to return an
+ * error.
+ */
+static int
+ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS)
+{
+ struct adapter *adapter = (struct adapter *) arg1;
+ int error = 0;
+ u32 new_wufc;
+
+ new_wufc = adapter->wufc;
+
+ error = sysctl_handle_int(oidp, &new_wufc, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+ if (new_wufc == adapter->wufc)
+ return (0);
+
+ if (new_wufc & 0xffffff00)
+ return (EINVAL);
+ else {
+ new_wufc &= 0xff;
+ new_wufc |= (0xffffff & adapter->wufc);
+ adapter->wufc = new_wufc;
+ }
+
+ return (0);
+}
+
+/*
** Enable the hardware to drop packets when the buffer is
** full. This is useful when multiqueue,so that no single
** queue being full stalls the entire RX engine. We only
@@ -4155,6 +4782,7 @@ ixgbe_rearm_queues(struct adapter *adapter, u64 queues)
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
mask = (queues & 0xFFFFFFFF);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
mask = (queues >> 32);
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c
index 672077b..a550a85 100644
--- a/sys/dev/ixgbe/if_ixv.c
+++ b/sys/dev/ixgbe/if_ixv.c
@@ -60,7 +60,6 @@ static ixgbe_vendor_info_t ixv_vendor_info_array[] =
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF, 0, 0, 0},
- {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_VF, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF, 0, 0, 0},
/* required last entry */
{0, 0, 0, 0, 0}
@@ -882,7 +881,7 @@ ixv_msix_mbx(void *arg)
struct ixgbe_hw *hw = &adapter->hw;
u32 reg;
- ++adapter->vector_irq;
+ ++adapter->link_irq;
/* First get the cause */
reg = IXGBE_READ_REG(hw, IXGBE_VTEICS);
@@ -2034,8 +2033,8 @@ ixv_add_stats_sysctls(struct adapter *adapter)
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
CTLFLAG_RD, &(txr->total_packets),
"TX Packets");
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
- CTLFLAG_RD, &(txr->tx_bytes),
+ SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_bytes",
+ CTLFLAG_RD, &(txr->bytes), 0,
"TX Bytes");
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_no_desc",
CTLFLAG_RD, &(txr->no_desc_avail),
@@ -2083,7 +2082,7 @@ ixv_print_debug_info(struct adapter *adapter)
}
device_printf(dev,"MBX IRQ Handled: %lu\n",
- (long)adapter->vector_irq);
+ (long)adapter->link_irq);
return;
}
diff --git a/sys/dev/ixgbe/ix_txrx.c b/sys/dev/ixgbe/ix_txrx.c
index 6c9c84a..bfe1607 100644
--- a/sys/dev/ixgbe/ix_txrx.c
+++ b/sys/dev/ixgbe/ix_txrx.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -210,7 +210,11 @@ ixgbe_mq_start(struct ifnet *ifp, struct mbuf *m)
* If everything is setup correctly, it should be the
* same bucket that the current CPU we're on is.
*/
+#if __FreeBSD_version < 1100054
+ if (m->m_flags & M_FLOWID) {
+#else
if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
+#endif
#ifdef RSS
if (rss_hash2bucket(m->m_pkthdr.flowid,
M_HASHTYPE_GET(m), &bucket_id) == 0)
@@ -276,7 +280,12 @@ ixgbe_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr)
enqueued++;
#if 0 // this is VF-only
#if __FreeBSD_version >= 1100036
- if (next->m_flags & M_MCAST)
+ /*
+ * Since we're looking at the tx ring, we can check
+ * to see if we're a VF by examing our tail register
+ * address.
+ */
+ if (txr->tail < IXGBE_TDT(0) && next->m_flags & M_MCAST)
if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
#endif
#endif
@@ -312,8 +321,8 @@ ixgbe_deferred_mq_start(void *arg, int pending)
}
/*
-** Flush all ring buffers
-*/
+ * Flush all ring buffers
+ */
void
ixgbe_qflush(struct ifnet *ifp)
{
@@ -387,6 +396,10 @@ retry:
/* Try it again? - one try */
if (remap == TRUE) {
remap = FALSE;
+ /*
+ * XXX: m_defrag will choke on
+ * non-MCLBYTES-sized clusters
+ */
m = m_defrag(*m_headp, M_NOWAIT);
if (m == NULL) {
adapter->mbuf_defrag_failed++;
@@ -418,9 +431,9 @@ retry:
m_head = *m_headp;
/*
- ** Set up the appropriate offload context
- ** this will consume the first descriptor
- */
+ * Set up the appropriate offload context
+ * this will consume the first descriptor
+ */
error = ixgbe_tx_ctx_setup(txr, m_head, &cmd_type_len, &olinfo_status);
if (__predict_false(error)) {
if (error == ENOBUFS)
@@ -439,7 +452,6 @@ retry:
}
#endif
- olinfo_status |= IXGBE_ADVTXD_CC;
i = txr->next_avail_desc;
for (j = 0; j < nsegs; j++) {
bus_size_t seglen;
@@ -466,11 +478,11 @@ retry:
txbuf->m_head = m_head;
/*
- ** Here we swap the map so the last descriptor,
- ** which gets the completion interrupt has the
- ** real map, and the first descriptor gets the
- ** unused map from this descriptor.
- */
+ * Here we swap the map so the last descriptor,
+ * which gets the completion interrupt has the
+ * real map, and the first descriptor gets the
+ * unused map from this descriptor.
+ */
txr->tx_buffers[first].map = txbuf->map;
txbuf->map = map;
bus_dmamap_sync(txr->txtag, map, BUS_DMASYNC_PREWRITE);
@@ -493,7 +505,6 @@ retry:
txr->busy = 1;
return (0);
-
}
@@ -732,6 +743,7 @@ static int
ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp,
u32 *cmd_type_len, u32 *olinfo_status)
{
+ struct adapter *adapter = txr->adapter;
struct ixgbe_adv_tx_context_desc *TXD;
struct ether_vlan_header *eh;
struct ip *ip;
@@ -766,6 +778,8 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp,
vtag = htole16(mp->m_pkthdr.ether_vtag);
vlan_macip_lens |= (vtag << IXGBE_ADVTXD_VLAN_SHIFT);
}
+ else if (!IXGBE_IS_X550VF(adapter) && (offload == FALSE))
+ return (0);
/*
* Determine where frame payload starts.
@@ -1727,9 +1741,6 @@ ixgbe_rx_discard(struct rx_ring *rxr, int i)
* the mbufs in the descriptor and sends data which has been
* dma'ed into host memory to upper layer.
*
- * We loop at most count times if count is > 0, or until done if
- * count < 0.
- *
* Return TRUE for more work, FALSE for all clean.
*********************************************************************/
bool
@@ -1792,10 +1803,9 @@ ixgbe_rxeof(struct ix_queue *que)
/* Make sure bad packets are discarded */
if (eop && (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) != 0) {
-#if 0 // VF-only
#if __FreeBSD_version >= 1100036
- if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
-#endif
+ if (IXGBE_IS_VF(adapter))
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
#endif
rxr->rx_discarded++;
ixgbe_rx_discard(rxr, i);
@@ -1906,6 +1916,9 @@ ixgbe_rxeof(struct ix_queue *que)
#ifdef RSS
sendmp->m_pkthdr.flowid =
le32toh(cur->wb.lower.hi_dword.rss);
+#if __FreeBSD_version < 1100054
+ sendmp->m_flags |= M_FLOWID;
+#endif
switch (pkt_info & IXGBE_RXDADV_RSSTYPE_MASK) {
case IXGBE_RXDADV_RSSTYPE_IPV4_TCP:
M_HASHTYPE_SET(sendmp, M_HASHTYPE_RSS_TCP_IPV4);
@@ -1939,7 +1952,11 @@ ixgbe_rxeof(struct ix_queue *que)
}
#else /* RSS */
sendmp->m_pkthdr.flowid = que->msix;
+#if __FreeBSD_version >= 1100054
M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE);
+#else
+ sendmp->m_flags |= M_FLOWID;
+#endif
#endif /* RSS */
#endif /* FreeBSD_version */
}
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index 813ee4f..44e7c3c 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -90,8 +90,11 @@
#include <sys/pcpu.h>
#include <sys/smp.h>
#include <machine/smp.h>
+#include <sys/sbuf.h>
#include "ixgbe_api.h"
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
#include "ixgbe_vf.h"
/* Tunables */
@@ -146,7 +149,11 @@
#define IXGBE_TX_CLEANUP_THRESHOLD (adapter->num_tx_desc / 8)
#define IXGBE_TX_OP_THRESHOLD (adapter->num_tx_desc / 32)
-#define IXGBE_MAX_FRAME_SIZE 0x3F00
+/* These defines are used in MTU calculations */
+#define IXGBE_MAX_FRAME_SIZE 9728
+#define IXGBE_MTU_HDR (ETHER_HDR_LEN + ETHER_CRC_LEN + \
+ ETHER_VLAN_ENCAP_LEN)
+#define IXGBE_MAX_MTU (IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR)
/* Flow control constants */
#define IXGBE_FC_PAUSE 0xFFFF
@@ -227,6 +234,17 @@
#define IXGBE_BULK_LATENCY 1200
#define IXGBE_LINK_ITR 2000
+/* MAC type macros */
+#define IXGBE_IS_X550VF(_adapter) \
+ ((_adapter->hw.mac.type == ixgbe_mac_X550_vf) || \
+ (_adapter->hw.mac.type == ixgbe_mac_X550EM_x_vf))
+
+#define IXGBE_IS_VF(_adapter) \
+ (IXGBE_IS_X550VF(_adapter) || \
+ (_adapter->hw.mac.type == ixgbe_mac_X540_vf) || \
+ (_adapter->hw.mac.type == ixgbe_mac_82599_vf))
+
+
/*
*****************************************************************************
* vendor_info_array
@@ -323,8 +341,8 @@ struct tx_ring {
u32 bytes; /* used for AIM */
u32 packets;
/* Soft Stats */
- u64 tx_bytes;
unsigned long tso_tx;
+ unsigned long no_tx_map_avail;
unsigned long no_tx_dma_setup;
u64 no_desc_avail;
u64 total_packets;
@@ -419,6 +437,13 @@ struct adapter {
u32 link_speed;
bool link_up;
u32 vector;
+ u16 dmac;
+ bool eee_support;
+ bool eee_enabled;
+
+ /* Power management-related */
+ bool wol_support;
+ u32 wufc;
/* Mbuf cluster size */
u32 rx_mbuf_sz;
@@ -432,6 +457,7 @@ struct adapter {
int fdir_reinit;
struct task fdir_task;
#endif
+ struct task phy_task; /* PHY intr tasklet */
struct taskqueue *tq;
/*
@@ -467,7 +493,7 @@ struct adapter {
unsigned long mbuf_header_failed;
unsigned long mbuf_packet_failed;
unsigned long watchdog_events;
- unsigned long vector_irq;
+ unsigned long link_irq;
union {
struct ixgbe_hw_stats pf;
struct ixgbevf_hw_stats vf;
@@ -540,12 +566,17 @@ struct adapter {
#define IXGBE_SET_IQDROPS(sc, count) (sc)->ifp->if_iqdrops = (count)
#endif
+/* External PHY register addresses */
+#define IXGBE_PHY_CURRENT_TEMP 0xC820
+#define IXGBE_PHY_OVERTEMP_STATUS 0xC830
+
/* Sysctl help messages; displayed with sysctl -d */
#define IXGBE_SYSCTL_DESC_ADV_SPEED \
"\nControl advertised link speed using these flags:\n" \
"\t0x1 - advertise 100M\n" \
"\t0x2 - advertise 1G\n" \
- "\t0x4 - advertise 10G"
+ "\t0x4 - advertise 10G\n\n" \
+ "\t100M is only supported on certain 10GBaseT adapters.\n"
#define IXGBE_SYSCTL_DESC_SET_FC \
"\nSet flow control mode using these values:\n" \
diff --git a/sys/dev/ixgbe/ixgbe_82598.c b/sys/dev/ixgbe/ixgbe_82598.c
index d9b8985..46e64c5 100644
--- a/sys/dev/ixgbe/ixgbe_82598.c
+++ b/sys/dev/ixgbe/ixgbe_82598.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -260,6 +260,8 @@ s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw)
DEBUGFUNC("ixgbe_start_hw_82598");
ret_val = ixgbe_start_hw_generic(hw);
+ if (ret_val)
+ return ret_val;
/* Disable relaxed ordering */
for (i = 0; ((i < hw->mac.max_tx_queues) &&
@@ -278,8 +280,7 @@ s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw)
}
/* set the completion timeout for interface */
- if (ret_val == IXGBE_SUCCESS)
- ixgbe_set_pcie_completion_timeout(hw);
+ ixgbe_set_pcie_completion_timeout(hw);
return ret_val;
}
diff --git a/sys/dev/ixgbe/ixgbe_82598.h b/sys/dev/ixgbe/ixgbe_82598.h
index 621be41..d2241c7 100644
--- a/sys/dev/ixgbe/ixgbe_82598.h
+++ b/sys/dev/ixgbe/ixgbe_82598.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_82599.c b/sys/dev/ixgbe/ixgbe_82599.c
index d49d851..b38620f 100644
--- a/sys/dev/ixgbe/ixgbe_82599.c
+++ b/sys/dev/ixgbe/ixgbe_82599.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -421,6 +421,8 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
/* Check if 1G SFP module. */
if (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
*speed = IXGBE_LINK_SPEED_1GB_FULL;
@@ -1803,7 +1805,6 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
switch (hw->mac.type) {
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm);
break;
default:
@@ -2465,7 +2466,6 @@ reset_pipeline_out:
return ret_val;
}
-
/**
* ixgbe_read_i2c_byte_82599 - Reads 8 bit word over I2C
* @hw: pointer to hardware structure
diff --git a/sys/dev/ixgbe/ixgbe_82599.h b/sys/dev/ixgbe/ixgbe_82599.h
index 8c973ac..bcfb043 100644
--- a/sys/dev/ixgbe/ixgbe_82599.h
+++ b/sys/dev/ixgbe/ixgbe_82599.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_api.c b/sys/dev/ixgbe/ixgbe_api.c
index 2535664..9784e3c 100644
--- a/sys/dev/ixgbe/ixgbe_api.c
+++ b/sys/dev/ixgbe/ixgbe_api.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,22 @@
#include "ixgbe_api.h"
#include "ixgbe_common.h"
+static const u32 ixgbe_mvals_base[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT()
+};
+
+static const u32 ixgbe_mvals_X540[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT(_X540)
+};
+
+static const u32 ixgbe_mvals_X550[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT(_X550)
+};
+
+static const u32 ixgbe_mvals_X550EM_x[IXGBE_MVALS_IDX_LIMIT] = {
+ IXGBE_MVALS_INIT(_X550EM_x)
+};
+
/**
* ixgbe_dcb_get_rtrup2tc - read rtrup2tc reg
* @hw: pointer to hardware structure
@@ -81,20 +97,16 @@ s32 ixgbe_init_shared_code(struct ixgbe_hw *hw)
case ixgbe_mac_X540:
status = ixgbe_init_ops_X540(hw);
break;
-#if 0 //JFV temporary disable
case ixgbe_mac_X550:
status = ixgbe_init_ops_X550(hw);
break;
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
status = ixgbe_init_ops_X550EM(hw);
break;
-#endif
case ixgbe_mac_82599_vf:
case ixgbe_mac_X540_vf:
case ixgbe_mac_X550_vf:
case ixgbe_mac_X550EM_x_vf:
- case ixgbe_mac_X550EM_a_vf:
status = ixgbe_init_ops_vf(hw);
break;
default:
@@ -124,6 +136,8 @@ s32 ixgbe_set_mac_type(struct ixgbe_hw *hw)
return IXGBE_ERR_DEVICE_NOT_SUPPORTED;
}
+ hw->mvals = ixgbe_mvals_base;
+
switch (hw->device_id) {
case IXGBE_DEV_ID_82598:
case IXGBE_DEV_ID_82598_BX:
@@ -164,14 +178,17 @@ s32 ixgbe_set_mac_type(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_X540_VF:
case IXGBE_DEV_ID_X540_VF_HV:
hw->mac.type = ixgbe_mac_X540_vf;
+ hw->mvals = ixgbe_mvals_X540;
break;
case IXGBE_DEV_ID_X540T:
case IXGBE_DEV_ID_X540T1:
case IXGBE_DEV_ID_X540_BYPASS:
hw->mac.type = ixgbe_mac_X540;
+ hw->mvals = ixgbe_mvals_X540;
break;
case IXGBE_DEV_ID_X550T:
hw->mac.type = ixgbe_mac_X550;
+ hw->mvals = ixgbe_mvals_X550;
break;
case IXGBE_DEV_ID_X550EM_X_KX4:
case IXGBE_DEV_ID_X550EM_X_KR:
@@ -179,21 +196,17 @@ s32 ixgbe_set_mac_type(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_X550EM_X_1G_T:
case IXGBE_DEV_ID_X550EM_X_SFP:
hw->mac.type = ixgbe_mac_X550EM_x;
- break;
- case IXGBE_DEV_ID_X550EM_A_KR:
- hw->mac.type = ixgbe_mac_X550EM_a;
+ hw->mvals = ixgbe_mvals_X550EM_x;
break;
case IXGBE_DEV_ID_X550_VF:
case IXGBE_DEV_ID_X550_VF_HV:
hw->mac.type = ixgbe_mac_X550_vf;
+ hw->mvals = ixgbe_mvals_X550;
break;
case IXGBE_DEV_ID_X550EM_X_VF:
case IXGBE_DEV_ID_X550EM_X_VF_HV:
hw->mac.type = ixgbe_mac_X550EM_x_vf;
- break;
- case IXGBE_DEV_ID_X550EM_A_VF:
- case IXGBE_DEV_ID_X550EM_A_VF_HV:
- hw->mac.type = ixgbe_mac_X550EM_a_vf;
+ hw->mvals = ixgbe_mvals_X550EM_x;
break;
default:
ret_val = IXGBE_ERR_DEVICE_NOT_SUPPORTED;
@@ -1283,6 +1296,23 @@ s32 ixgbe_enter_lplu(struct ixgbe_hw *hw)
}
/**
+ * ixgbe_handle_lasi - Handle external Base T PHY interrupt
+ * @hw: pointer to hardware structure
+ *
+ * Handle external Base T PHY interrupt. If high temperature
+ * failure alarm then return error, else if link status change
+ * then setup internal/external PHY link
+ *
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
+ * failure alarm, else return PHY access status.
+ */
+s32 ixgbe_handle_lasi(struct ixgbe_hw *hw)
+{
+ return ixgbe_call_func(hw, hw->phy.ops.handle_lasi, (hw),
+ IXGBE_NOT_IMPLEMENTED);
+}
+
+/**
* ixgbe_read_analog_reg8 - Reads 8 bit analog register
* @hw: pointer to hardware structure
* @reg: analog register to read
@@ -1340,6 +1370,23 @@ s32 ixgbe_read_i2c_byte(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr,
}
/**
+ * ixgbe_read_i2c_byte_unlocked - Reads 8 bit word via I2C from device address
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to read
+ * @dev_addr: I2C bus address to read from
+ * @data: value read
+ *
+ * Performs byte read operation to SFP module's EEPROM over I2C interface.
+ **/
+s32 ixgbe_read_i2c_byte_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data)
+{
+ return ixgbe_call_func(hw, hw->phy.ops.read_i2c_byte_unlocked,
+ (hw, byte_offset, dev_addr, data),
+ IXGBE_NOT_IMPLEMENTED);
+}
+
+/**
* ixgbe_read_i2c_combined - Perform I2C read combined operation
* @hw: pointer to the hardware structure
* @addr: I2C bus address to read from
@@ -1355,6 +1402,23 @@ s32 ixgbe_read_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val)
}
/**
+ * ixgbe_read_i2c_combined_unlocked - Perform I2C read combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to read from
+ * @reg: I2C device register to read from
+ * @val: pointer to location to receive read value
+ *
+ * Returns an error code on error.
+ **/
+s32 ixgbe_read_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg,
+ u16 *val)
+{
+ return ixgbe_call_func(hw, hw->phy.ops.read_i2c_combined_unlocked,
+ (hw, addr, reg, val),
+ IXGBE_NOT_IMPLEMENTED);
+}
+
+/**
* ixgbe_write_i2c_byte - Writes 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to write
@@ -1372,6 +1436,24 @@ s32 ixgbe_write_i2c_byte(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr,
}
/**
+ * ixgbe_write_i2c_byte_unlocked - Writes 8 bit word over I2C
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to write
+ * @dev_addr: I2C bus address to write to
+ * @data: value to write
+ *
+ * Performs byte write operation to SFP module's EEPROM over I2C interface
+ * at a specified device address.
+ **/
+s32 ixgbe_write_i2c_byte_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data)
+{
+ return ixgbe_call_func(hw, hw->phy.ops.write_i2c_byte_unlocked,
+ (hw, byte_offset, dev_addr, data),
+ IXGBE_NOT_IMPLEMENTED);
+}
+
+/**
* ixgbe_write_i2c_combined - Perform I2C write combined operation
* @hw: pointer to the hardware structure
* @addr: I2C bus address to write to
@@ -1387,6 +1469,22 @@ s32 ixgbe_write_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val)
}
/**
+ * ixgbe_write_i2c_combined_unlocked - Perform I2C write combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to write to
+ * @reg: I2C device register to write to
+ * @val: value to write
+ *
+ * Returns an error code on error.
+ **/
+s32 ixgbe_write_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg,
+ u16 val)
+{
+ return ixgbe_call_func(hw, hw->phy.ops.write_i2c_combined_unlocked,
+ (hw, addr, reg, val), IXGBE_NOT_IMPLEMENTED);
+}
+
+/**
* ixgbe_write_i2c_eeprom - Writes 8 bit EEPROM word over I2C interface
* @hw: pointer to hardware structure
* @byte_offset: EEPROM byte offset to write
diff --git a/sys/dev/ixgbe/ixgbe_api.h b/sys/dev/ixgbe/ixgbe_api.h
index 650ae67..8c2c4a8 100644
--- a/sys/dev/ixgbe/ixgbe_api.h
+++ b/sys/dev/ixgbe/ixgbe_api.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -173,10 +173,18 @@ u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input,
bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw);
s32 ixgbe_read_i2c_byte(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr,
u8 *data);
+s32 ixgbe_read_i2c_byte_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data);
s32 ixgbe_read_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val);
+s32 ixgbe_read_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg,
+ u16 *val);
s32 ixgbe_write_i2c_byte(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr,
u8 data);
+s32 ixgbe_write_i2c_byte_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data);
s32 ixgbe_write_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val);
+s32 ixgbe_write_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg,
+ u16 val);
s32 ixgbe_write_i2c_eeprom(struct ixgbe_hw *hw, u8 byte_offset, u8 eeprom_data);
s32 ixgbe_get_san_mac_addr(struct ixgbe_hw *hw, u8 *san_mac_addr);
s32 ixgbe_set_san_mac_addr(struct ixgbe_hw *hw, u8 *san_mac_addr);
@@ -203,6 +211,7 @@ void ixgbe_enable_mdd(struct ixgbe_hw *hw);
void ixgbe_mdd_event(struct ixgbe_hw *hw, u32 *vf_bitmap);
void ixgbe_restore_mdd_vf(struct ixgbe_hw *hw, u32 vf);
s32 ixgbe_enter_lplu(struct ixgbe_hw *hw);
+s32 ixgbe_handle_lasi(struct ixgbe_hw *hw);
void ixgbe_set_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed);
void ixgbe_disable_rx(struct ixgbe_hw *hw);
void ixgbe_enable_rx(struct ixgbe_hw *hw);
diff --git a/sys/dev/ixgbe/ixgbe_common.c b/sys/dev/ixgbe/ixgbe_common.c
index 57fe1b5..f0a0776 100644
--- a/sys/dev/ixgbe/ixgbe_common.c
+++ b/sys/dev/ixgbe/ixgbe_common.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -188,6 +188,7 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_X540T1:
case IXGBE_DEV_ID_X540_BYPASS:
case IXGBE_DEV_ID_X550T:
+ case IXGBE_DEV_ID_X550EM_X_10G_T:
supported = TRUE;
break;
default:
@@ -1090,7 +1091,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw)
msec_delay(2);
/*
- * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+ * Prevent the PCI-E bus from hanging by disabling PCI-E master
* access and verify no pending requests
*/
return ixgbe_disable_pcie_master(hw);
@@ -3573,7 +3574,6 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS;
max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599;
break;
diff --git a/sys/dev/ixgbe/ixgbe_common.h b/sys/dev/ixgbe/ixgbe_common.h
index 94c7f97..e685f5b 100644
--- a/sys/dev/ixgbe/ixgbe_common.h
+++ b/sys/dev/ixgbe/ixgbe_common.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_dcb.c b/sys/dev/ixgbe/ixgbe_dcb.c
index 6f848e7..3659d17 100644
--- a/sys/dev/ixgbe/ixgbe_dcb.c
+++ b/sys/dev/ixgbe/ixgbe_dcb.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -396,7 +396,6 @@ s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_get_tc_stats_82599(hw, stats, tc_count);
break;
@@ -427,7 +426,6 @@ s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_get_pfc_stats_82599(hw, stats, tc_count);
break;
@@ -469,7 +467,6 @@ s32 ixgbe_dcb_config_rx_arbiter_cee(struct ixgbe_hw *hw,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwgid,
tsa, map);
@@ -511,7 +508,6 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_cee(struct ixgbe_hw *hw,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max,
bwgid, tsa);
@@ -555,7 +551,6 @@ s32 ixgbe_dcb_config_tx_data_arbiter_cee(struct ixgbe_hw *hw,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max,
bwgid, tsa,
@@ -593,7 +588,6 @@ s32 ixgbe_dcb_config_pfc_cee(struct ixgbe_hw *hw,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, map);
break;
@@ -622,7 +616,6 @@ s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw)
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_config_tc_stats_82599(hw, NULL);
break;
@@ -670,7 +663,6 @@ s32 ixgbe_dcb_hw_config_cee(struct ixgbe_hw *hw,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ixgbe_dcb_config_82599(hw, dcb_config);
ret = ixgbe_dcb_hw_config_82599(hw, dcb_config->link_speed,
@@ -705,7 +697,6 @@ s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw, u8 pfc_en, u8 *map)
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, map);
break;
@@ -731,7 +722,6 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, u16 *refill, u16 *max,
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT)
ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwg_id,
tsa, map);
diff --git a/sys/dev/ixgbe/ixgbe_dcb.h b/sys/dev/ixgbe/ixgbe_dcb.h
index 878bbf8..871b784 100644
--- a/sys/dev/ixgbe/ixgbe_dcb.h
+++ b/sys/dev/ixgbe/ixgbe_dcb.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_dcb_82598.c b/sys/dev/ixgbe/ixgbe_dcb_82598.c
index a5a090d..fb946c9 100644
--- a/sys/dev/ixgbe/ixgbe_dcb_82598.c
+++ b/sys/dev/ixgbe/ixgbe_dcb_82598.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_dcb_82598.h b/sys/dev/ixgbe/ixgbe_dcb_82598.h
index 47f19f6..35974f7 100644
--- a/sys/dev/ixgbe/ixgbe_dcb_82598.h
+++ b/sys/dev/ixgbe/ixgbe_dcb_82598.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_dcb_82599.c b/sys/dev/ixgbe/ixgbe_dcb_82599.c
index 0232d3c..4443411 100644
--- a/sys/dev/ixgbe/ixgbe_dcb_82599.c
+++ b/sys/dev/ixgbe/ixgbe_dcb_82599.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_dcb_82599.h b/sys/dev/ixgbe/ixgbe_dcb_82599.h
index 7702dc9..bab7628 100644
--- a/sys/dev/ixgbe/ixgbe_dcb_82599.h
+++ b/sys/dev/ixgbe/ixgbe_dcb_82599.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_mbx.c b/sys/dev/ixgbe/ixgbe_mbx.c
index 067bba0..d8ba55a 100644
--- a/sys/dev/ixgbe/ixgbe_mbx.c
+++ b/sys/dev/ixgbe/ixgbe_mbx.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -607,7 +607,6 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number)
break;
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- case ixgbe_mac_X550EM_a:
case ixgbe_mac_X540:
vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset));
break;
@@ -745,7 +744,6 @@ void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw)
if (hw->mac.type != ixgbe_mac_82599EB &&
hw->mac.type != ixgbe_mac_X550 &&
hw->mac.type != ixgbe_mac_X550EM_x &&
- hw->mac.type != ixgbe_mac_X550EM_a &&
hw->mac.type != ixgbe_mac_X540)
return;
diff --git a/sys/dev/ixgbe/ixgbe_mbx.h b/sys/dev/ixgbe/ixgbe_mbx.h
index 2cffb8a..ea75cbe 100644
--- a/sys/dev/ixgbe/ixgbe_mbx.h
+++ b/sys/dev/ixgbe/ixgbe_mbx.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_osdep.h b/sys/dev/ixgbe/ixgbe_osdep.h
index ebb55f4..95f6ed5c 100644
--- a/sys/dev/ixgbe/ixgbe_osdep.h
+++ b/sys/dev/ixgbe/ixgbe_osdep.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2013, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -108,13 +108,14 @@
#define UNREFERENCED_3PARAMETER(_p, _q, _r)
#define UNREFERENCED_4PARAMETER(_p, _q, _r, _s)
-
#define IXGBE_NTOHL(_i) ntohl(_i)
#define IXGBE_NTOHS(_i) ntohs(_i)
/* XXX these need to be revisited */
-#define IXGBE_CPU_TO_LE32 le32toh
-#define IXGBE_LE32_TO_CPUS le32dec
+#define IXGBE_CPU_TO_LE32 htole32
+#define IXGBE_LE32_TO_CPUS(x)
+#define IXGBE_CPU_TO_BE16 htobe16
+#define IXGBE_CPU_TO_BE32 htobe32
typedef uint8_t u8;
typedef int8_t s8;
diff --git a/sys/dev/ixgbe/ixgbe_phy.c b/sys/dev/ixgbe/ixgbe_phy.c
index 5ac719c..88206c7 100644
--- a/sys/dev/ixgbe/ixgbe_phy.c
+++ b/sys/dev/ixgbe/ixgbe_phy.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -101,16 +101,17 @@ static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2)
}
/**
- * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation
+ * ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation
* @hw: pointer to the hardware structure
* @addr: I2C bus address to read from
* @reg: I2C device register to read from
* @val: pointer to location to receive read value
+ * @lock: TRUE if to take and release semaphore
*
* Returns an error code on error.
*/
-static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
- u16 reg, u16 *val)
+static s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
+ u16 reg, u16 *val, bool lock)
{
u32 swfw_mask = hw->phy.phy_semaphore_mask;
int max_retry = 10;
@@ -121,11 +122,13 @@ static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
u8 reg_high;
u8 csum;
+ if (hw->mac.type >= ixgbe_mac_X550)
+ max_retry = 3;
reg_high = ((reg >> 7) & 0xFE) | 1; /* Indicate read combined */
csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
csum = ~csum;
do {
- if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+ if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
return IXGBE_ERR_SWFW_SYNC;
ixgbe_i2c_start(hw);
/* Device Address and write indication */
@@ -158,13 +161,15 @@ static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
if (ixgbe_clock_out_i2c_bit(hw, FALSE))
goto fail;
ixgbe_i2c_stop(hw);
- hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ if (lock)
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
*val = (high_bits << 8) | low_bits;
return 0;
fail:
ixgbe_i2c_bus_clear(hw);
- hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ if (lock)
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
retry++;
if (retry < max_retry)
DEBUGOUT("I2C byte read combined error - Retrying.\n");
@@ -176,17 +181,50 @@ fail:
}
/**
- * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation
+ * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to read from
+ * @reg: I2C device register to read from
+ * @val: pointer to location to receive read value
+ *
+ * Returns an error code on error.
+ **/
+static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
+ u16 reg, u16 *val)
+{
+ return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, TRUE);
+}
+
+/**
+ * ixgbe_read_i2c_combined_generic_unlocked - Do I2C read combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to read from
+ * @reg: I2C device register to read from
+ * @val: pointer to location to receive read value
+ *
+ * Returns an error code on error.
+ **/
+static s32
+ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr,
+ u16 reg, u16 *val)
+{
+ return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, FALSE);
+}
+
+/**
+ * ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation
* @hw: pointer to the hardware structure
* @addr: I2C bus address to write to
* @reg: I2C device register to write to
* @val: value to write
+ * @lock: TRUE if to take and release semaphore
*
* Returns an error code on error.
*/
-static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
- u8 addr, u16 reg, u16 val)
+static s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
+ u16 reg, u16 val, bool lock)
{
+ u32 swfw_mask = hw->phy.phy_semaphore_mask;
int max_retry = 1;
int retry = 0;
u8 reg_high;
@@ -198,6 +236,8 @@ static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF);
csum = ~csum;
do {
+ if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+ return IXGBE_ERR_SWFW_SYNC;
ixgbe_i2c_start(hw);
/* Device Address and write indication */
if (ixgbe_out_i2c_byte_ack(hw, addr))
@@ -218,10 +258,14 @@ static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
if (ixgbe_out_i2c_byte_ack(hw, csum))
goto fail;
ixgbe_i2c_stop(hw);
+ if (lock)
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return 0;
fail:
ixgbe_i2c_bus_clear(hw);
+ if (lock)
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
retry++;
if (retry < max_retry)
DEBUGOUT("I2C byte write combined error - Retrying.\n");
@@ -233,6 +277,37 @@ fail:
}
/**
+ * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to write to
+ * @reg: I2C device register to write to
+ * @val: value to write
+ *
+ * Returns an error code on error.
+ **/
+static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
+ u8 addr, u16 reg, u16 val)
+{
+ return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, TRUE);
+}
+
+/**
+ * ixgbe_write_i2c_combined_generic_unlocked - Do I2C write combined operation
+ * @hw: pointer to the hardware structure
+ * @addr: I2C bus address to write to
+ * @reg: I2C device register to write to
+ * @val: value to write
+ *
+ * Returns an error code on error.
+ **/
+static s32
+ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw,
+ u8 addr, u16 reg, u16 val)
+{
+ return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, FALSE);
+}
+
+/**
* ixgbe_init_phy_ops_generic - Inits PHY function ptrs
* @hw: pointer to the hardware structure
*
@@ -265,6 +340,13 @@ s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
phy->sfp_type = ixgbe_sfp_type_unknown;
phy->ops.read_i2c_combined = ixgbe_read_i2c_combined_generic;
phy->ops.write_i2c_combined = ixgbe_write_i2c_combined_generic;
+ phy->ops.read_i2c_combined_unlocked =
+ ixgbe_read_i2c_combined_generic_unlocked;
+ phy->ops.write_i2c_combined_unlocked =
+ ixgbe_write_i2c_combined_generic_unlocked;
+ phy->ops.read_i2c_byte_unlocked = ixgbe_read_i2c_byte_generic_unlocked;
+ phy->ops.write_i2c_byte_unlocked =
+ ixgbe_write_i2c_byte_generic_unlocked;
phy->ops.check_overtemp = ixgbe_tn_check_overtemp;
return IXGBE_SUCCESS;
}
@@ -1363,6 +1445,13 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
else
hw->phy.sfp_type =
ixgbe_sfp_type_1g_sx_core1;
+ } else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) {
+ if (hw->bus.lan_id == 0)
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_1g_lx_core0;
+ else
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_1g_lx_core1;
} else {
hw->phy.sfp_type = ixgbe_sfp_type_unknown;
}
@@ -1450,6 +1539,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
if (comp_codes_10g == 0 &&
!(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
hw->phy.type = ixgbe_phy_sfp_unsupported;
@@ -1467,6 +1558,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
!(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
/* Make sure we're a supported PHY type */
@@ -1600,6 +1693,9 @@ s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
goto out;
}
+ /* LAN ID is needed for I2C access */
+ hw->mac.ops.set_lan_id(hw);
+
status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
&identifier);
@@ -1614,9 +1710,6 @@ s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
hw->phy.id = identifier;
- /* LAN ID is needed for sfp_type determination */
- hw->mac.ops.set_lan_id(hw);
-
status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP,
&comp_codes_10g);
@@ -1804,10 +1897,12 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
* SR modules
*/
if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
+ sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
sfp_type == ixgbe_sfp_type_1g_sx_core0)
sfp_type = ixgbe_sfp_type_srlr_core0;
else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
+ sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
sfp_type == ixgbe_sfp_type_1g_sx_core1)
sfp_type = ixgbe_sfp_type_srlr_core1;
@@ -1932,16 +2027,17 @@ static bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr)
}
/**
- * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
+ * ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to read
* @data: value read
+ * @lock: TRUE if to take and release semaphore
*
* Performs byte read operation to SFP module's EEPROM over I2C interface at
* a specified device address.
**/
-s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 *data)
+static s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data, bool lock)
{
s32 status;
u32 max_retry = 10;
@@ -1952,11 +2048,13 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
DEBUGFUNC("ixgbe_read_i2c_byte_generic");
+ if (hw->mac.type >= ixgbe_mac_X550)
+ max_retry = 3;
if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr))
max_retry = IXGBE_SFP_DETECT_RETRIES;
do {
- if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+ if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
return IXGBE_ERR_SWFW_SYNC;
ixgbe_i2c_start(hw);
@@ -1998,13 +2096,16 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
goto fail;
ixgbe_i2c_stop(hw);
- hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ if (lock)
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return IXGBE_SUCCESS;
fail:
ixgbe_i2c_bus_clear(hw);
- hw->mac.ops.release_swfw_sync(hw, swfw_mask);
- msec_delay(100);
+ if (lock) {
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ msec_delay(100);
+ }
retry++;
if (retry < max_retry)
DEBUGOUT("I2C byte read error - Retrying.\n");
@@ -2017,28 +2118,60 @@ fail:
}
/**
- * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
+ * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to read
+ * @data: value read
+ *
+ * Performs byte read operation to SFP module's EEPROM over I2C interface at
+ * a specified device address.
+ **/
+s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data)
+{
+ return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+ data, TRUE);
+}
+
+/**
+ * ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to read
+ * @data: value read
+ *
+ * Performs byte read operation to SFP module's EEPROM over I2C interface at
+ * a specified device address.
+ **/
+s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data)
+{
+ return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+ data, FALSE);
+}
+
+/**
+ * ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to write
* @data: value to write
+ * @lock: TRUE if to take and release semaphore
*
* Performs byte write operation to SFP module's EEPROM over I2C interface at
* a specified device address.
**/
-s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 data)
+static s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data, bool lock)
{
- s32 status = IXGBE_SUCCESS;
+ s32 status;
u32 max_retry = 1;
u32 retry = 0;
u32 swfw_mask = hw->phy.phy_semaphore_mask;
DEBUGFUNC("ixgbe_write_i2c_byte_generic");
- if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) {
- status = IXGBE_ERR_SWFW_SYNC;
- goto write_byte_out;
- }
+ if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) !=
+ IXGBE_SUCCESS)
+ return IXGBE_ERR_SWFW_SYNC;
do {
ixgbe_i2c_start(hw);
@@ -2068,7 +2201,8 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
goto fail;
ixgbe_i2c_stop(hw);
- hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ if (lock)
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return IXGBE_SUCCESS;
fail:
@@ -2080,13 +2214,45 @@ fail:
DEBUGOUT("I2C byte write error.\n");
} while (retry < max_retry);
- hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ if (lock)
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
-write_byte_out:
return status;
}
/**
+ * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to write
+ * @data: value to write
+ *
+ * Performs byte write operation to SFP module's EEPROM over I2C interface at
+ * a specified device address.
+ **/
+s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data)
+{
+ return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+ data, TRUE);
+}
+
+/**
+ * ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to write
+ * @data: value to write
+ *
+ * Performs byte write operation to SFP module's EEPROM over I2C interface at
+ * a specified device address.
+ **/
+s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data)
+{
+ return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+ data, FALSE);
+}
+
+/**
* ixgbe_i2c_start - Sets I2C start condition
* @hw: pointer to hardware structure
*
diff --git a/sys/dev/ixgbe/ixgbe_phy.h b/sys/dev/ixgbe/ixgbe_phy.h
index 021d5f0..fad31bd 100644
--- a/sys/dev/ixgbe/ixgbe_phy.h
+++ b/sys/dev/ixgbe/ixgbe_phy.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -89,9 +89,24 @@
#define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS 0x3
#define IXGBE_CS4227 0xBE /* CS4227 address */
-#define IXGBE_CS4227_SPARE24_LSB 0x12B0 /* Reg to program EDC */
+#define IXGBE_CS4227_GLOBAL_ID_LSB 0
+#define IXGBE_CS4227_SCRATCH 2
+#define IXGBE_CS4227_GLOBAL_ID_VALUE 0x03E5
+#define IXGBE_CS4227_SCRATCH_VALUE 0x5aa5
+#define IXGBE_CS4227_RETRIES 5
+#define IXGBE_CS4227_LINE_SPARE22_MSB 0x12AD /* Reg to program speed */
+#define IXGBE_CS4227_LINE_SPARE24_LSB 0x12B0 /* Reg to program EDC */
+#define IXGBE_CS4227_HOST_SPARE22_MSB 0x1AAD /* Reg to program speed */
+#define IXGBE_CS4227_HOST_SPARE24_LSB 0x1AB0 /* Reg to program EDC */
#define IXGBE_CS4227_EDC_MODE_CX1 0x0002
#define IXGBE_CS4227_EDC_MODE_SR 0x0004
+#define IXGBE_CS4227_RESET_HOLD 500 /* microseconds */
+#define IXGBE_CS4227_RESET_DELAY 500 /* milliseconds */
+#define IXGBE_CS4227_CHECK_DELAY 30 /* milliseconds */
+#define IXGBE_PE 0xE0 /* Port expander address */
+#define IXGBE_PE_OUTPUT 1 /* Output register offset */
+#define IXGBE_PE_CONFIG 3 /* Config register offset */
+#define IXGBE_PE_BIT1 (1 << 1)
/* Flow control defines */
#define IXGBE_TAF_SYM_PAUSE 0x400
@@ -175,8 +190,12 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data);
+s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data);
s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data);
+s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data);
s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 *eeprom_data);
s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
diff --git a/sys/dev/ixgbe/ixgbe_type.h b/sys/dev/ixgbe/ixgbe_type.h
index 24ba046..2a53952 100644
--- a/sys/dev/ixgbe/ixgbe_type.h
+++ b/sys/dev/ixgbe/ixgbe_type.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -111,6 +111,7 @@
#define IXGBE_SUBDEV_ID_82599_LOM_SNAP6 0x2159
#define IXGBE_SUBDEV_ID_82599_SFP_1OCP 0x000D
#define IXGBE_SUBDEV_ID_82599_SFP_2OCP 0x0008
+#define IXGBE_SUBDEV_ID_82599_SFP_LOM 0x06EE
#define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152A
#define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529
#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
@@ -130,8 +131,6 @@
#define IXGBE_DEV_ID_X540_BYPASS 0x155C
#define IXGBE_DEV_ID_X540T1 0x1560
#define IXGBE_DEV_ID_X550T 0x1563
-/* Placeholder value, pending official value. */
-#define IXGBE_DEV_ID_X550EM_A_KR 0xABCD
#define IXGBE_DEV_ID_X550EM_X_KX4 0x15AA
#define IXGBE_DEV_ID_X550EM_X_KR 0x15AB
#define IXGBE_DEV_ID_X550EM_X_SFP 0x15AC
@@ -139,11 +138,13 @@
#define IXGBE_DEV_ID_X550EM_X_1G_T 0x15AE
#define IXGBE_DEV_ID_X550_VF_HV 0x1564
#define IXGBE_DEV_ID_X550_VF 0x1565
-#define IXGBE_DEV_ID_X550EM_A_VF 0x15B3
-#define IXGBE_DEV_ID_X550EM_A_VF_HV 0x15B4
#define IXGBE_DEV_ID_X550EM_X_VF 0x15A8
#define IXGBE_DEV_ID_X550EM_X_VF_HV 0x15A9
+#define IXGBE_CAT(r,m) IXGBE_##r##m
+
+#define IXGBE_BY_MAC(_hw, r) ((_hw)->mvals[IXGBE_CAT(r, _IDX)])
+
/* General Registers */
#define IXGBE_CTRL 0x00000
#define IXGBE_STATUS 0x00008
@@ -151,9 +152,11 @@
#define IXGBE_ESDP 0x00020
#define IXGBE_EODSDP 0x00028
#define IXGBE_I2CCTL_82599 0x00028
+#define IXGBE_I2CCTL IXGBE_I2CCTL_82599
+#define IXGBE_I2CCTL_X540 IXGBE_I2CCTL_82599
#define IXGBE_I2CCTL_X550 0x15F5C
-#define IXGBE_I2CCTL_BY_MAC(_hw) ((((_hw)->mac.type >= ixgbe_mac_X550) ? \
- IXGBE_I2CCTL_X550 : IXGBE_I2CCTL_82599))
+#define IXGBE_I2CCTL_X550EM_x IXGBE_I2CCTL_X550
+#define IXGBE_I2CCTL_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2CCTL)
#define IXGBE_PHY_GPIO 0x00028
#define IXGBE_MAC_GPIO 0x00030
#define IXGBE_PHYINT_STATUS0 0x00100
@@ -166,18 +169,40 @@
#define IXGBE_EXVET 0x05078
/* NVM Registers */
-#define IXGBE_EEC 0x10010
-#define IXGBE_EERD 0x10014
-#define IXGBE_EEWR 0x10018
-#define IXGBE_FLA 0x1001C
+#define IXGBE_EEC 0x10010
+#define IXGBE_EEC_X540 IXGBE_EEC
+#define IXGBE_EEC_X550 IXGBE_EEC
+#define IXGBE_EEC_X550EM_x IXGBE_EEC
+#define IXGBE_EEC_BY_MAC(_hw) IXGBE_EEC
+
+#define IXGBE_EERD 0x10014
+#define IXGBE_EEWR 0x10018
+
+#define IXGBE_FLA 0x1001C
+#define IXGBE_FLA_X540 IXGBE_FLA
+#define IXGBE_FLA_X550 IXGBE_FLA
+#define IXGBE_FLA_X550EM_x IXGBE_FLA
+#define IXGBE_FLA_BY_MAC(_hw) IXGBE_FLA
+
#define IXGBE_EEMNGCTL 0x10110
#define IXGBE_EEMNGDATA 0x10114
#define IXGBE_FLMNGCTL 0x10118
#define IXGBE_FLMNGDATA 0x1011C
#define IXGBE_FLMNGCNT 0x10120
#define IXGBE_FLOP 0x1013C
-#define IXGBE_GRC 0x10200
-#define IXGBE_SRAMREL 0x10210
+
+#define IXGBE_GRC 0x10200
+#define IXGBE_GRC_X540 IXGBE_GRC
+#define IXGBE_GRC_X550 IXGBE_GRC
+#define IXGBE_GRC_X550EM_x IXGBE_GRC
+#define IXGBE_GRC_BY_MAC(_hw) IXGBE_GRC
+
+#define IXGBE_SRAMREL 0x10210
+#define IXGBE_SRAMREL_X540 IXGBE_SRAMREL
+#define IXGBE_SRAMREL_X550 IXGBE_SRAMREL
+#define IXGBE_SRAMREL_X550EM_x IXGBE_SRAMREL
+#define IXGBE_SRAMREL_BY_MAC(_hw) IXGBE_SRAMREL
+
#define IXGBE_PHYDBG 0x10218
/* General Receive Control */
@@ -188,20 +213,48 @@
#define IXGBE_VPDDIAG1 0x10208
/* I2CCTL Bit Masks */
-#define IXGBE_I2C_CLK_IN_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00004000 : 0x00000001)
-#define IXGBE_I2C_CLK_OUT_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00000200 : 0x00000002)
-#define IXGBE_I2C_DATA_IN_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00001000 : 0x00000004)
-#define IXGBE_I2C_DATA_OUT_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
- 0x00000400 : 0x00000008)
-#define IXGBE_I2C_BB_EN_BY_MAC(hw) ((hw)->mac.type >= ixgbe_mac_X550 ? \
- 0x00000100 : 0)
-#define IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw) ((hw)->mac.type >= ixgbe_mac_X550 ? \
- 0x00000800 : 0)
-#define IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw) ((hw)->mac.type >= ixgbe_mac_X550 ? \
- 0x00002000 : 0)
+#define IXGBE_I2C_CLK_IN 0x00000001
+#define IXGBE_I2C_CLK_IN_X540 IXGBE_I2C_CLK_IN
+#define IXGBE_I2C_CLK_IN_X550 0x00004000
+#define IXGBE_I2C_CLK_IN_X550EM_x IXGBE_I2C_CLK_IN_X550
+#define IXGBE_I2C_CLK_IN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_IN)
+
+#define IXGBE_I2C_CLK_OUT 0x00000002
+#define IXGBE_I2C_CLK_OUT_X540 IXGBE_I2C_CLK_OUT
+#define IXGBE_I2C_CLK_OUT_X550 0x00000200
+#define IXGBE_I2C_CLK_OUT_X550EM_x IXGBE_I2C_CLK_OUT_X550
+#define IXGBE_I2C_CLK_OUT_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_OUT)
+
+#define IXGBE_I2C_DATA_IN 0x00000004
+#define IXGBE_I2C_DATA_IN_X540 IXGBE_I2C_DATA_IN
+#define IXGBE_I2C_DATA_IN_X550 0x00001000
+#define IXGBE_I2C_DATA_IN_X550EM_x IXGBE_I2C_DATA_IN_X550
+#define IXGBE_I2C_DATA_IN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_IN)
+
+#define IXGBE_I2C_DATA_OUT 0x00000008
+#define IXGBE_I2C_DATA_OUT_X540 IXGBE_I2C_DATA_OUT
+#define IXGBE_I2C_DATA_OUT_X550 0x00000400
+#define IXGBE_I2C_DATA_OUT_X550EM_x IXGBE_I2C_DATA_OUT_X550
+#define IXGBE_I2C_DATA_OUT_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_OUT)
+
+#define IXGBE_I2C_DATA_OE_N_EN 0
+#define IXGBE_I2C_DATA_OE_N_EN_X540 IXGBE_I2C_DATA_OE_N_EN
+#define IXGBE_I2C_DATA_OE_N_EN_X550 0x00000800
+#define IXGBE_I2C_DATA_OE_N_EN_X550EM_x IXGBE_I2C_DATA_OE_N_EN_X550
+#define IXGBE_I2C_DATA_OE_N_EN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_OE_N_EN)
+
+#define IXGBE_I2C_BB_EN 0
+#define IXGBE_I2C_BB_EN_X540 IXGBE_I2C_BB_EN
+#define IXGBE_I2C_BB_EN_X550 0x00000100
+#define IXGBE_I2C_BB_EN_X550EM_x IXGBE_I2C_BB_EN_X550
+
+#define IXGBE_I2C_BB_EN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_BB_EN)
+
+#define IXGBE_I2C_CLK_OE_N_EN 0
+#define IXGBE_I2C_CLK_OE_N_EN_X540 IXGBE_I2C_CLK_OE_N_EN
+#define IXGBE_I2C_CLK_OE_N_EN_X550 0x00002000
+#define IXGBE_I2C_CLK_OE_N_EN_X550EM_x IXGBE_I2C_CLK_OE_N_EN_X550
+#define IXGBE_I2C_CLK_OE_N_EN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_OE_N_EN)
#define IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT 500
@@ -612,6 +665,7 @@ struct ixgbe_dmac_config {
#define IXGBE_EEER 0x043A0 /* EEE register */
#define IXGBE_EEE_STAT 0x04398 /* EEE Status */
#define IXGBE_EEE_SU 0x04380 /* EEE Set up */
+#define IXGBE_EEE_SU_TEEE_DLY_SHIFT 26
#define IXGBE_TLPIC 0x041F4 /* EEE Tx LPI count */
#define IXGBE_RLPIC 0x041F8 /* EEE Rx LPI count */
@@ -989,14 +1043,34 @@ struct ixgbe_dmac_config {
#define IXGBE_GSCN_2 0x11028
#define IXGBE_GSCN_3 0x1102C
#define IXGBE_FACTPS 0x10150
+#define IXGBE_FACTPS_X540 IXGBE_FACTPS
+#define IXGBE_FACTPS_X550 IXGBE_FACTPS
+#define IXGBE_FACTPS_X550EM_x IXGBE_FACTPS
+#define IXGBE_FACTPS_BY_MAC(_hw) IXGBE_FACTPS
+
#define IXGBE_PCIEANACTL 0x11040
#define IXGBE_SWSM 0x10140
+#define IXGBE_SWSM_X540 IXGBE_SWSM
+#define IXGBE_SWSM_X550 IXGBE_SWSM
+#define IXGBE_SWSM_X550EM_x IXGBE_SWSM
+#define IXGBE_SWSM_BY_MAC(_hw) IXGBE_SWSM
+
#define IXGBE_FWSM 0x10148
+#define IXGBE_FWSM_X540 IXGBE_FWSM
+#define IXGBE_FWSM_X550 IXGBE_FWSM
+#define IXGBE_FWSM_X550EM_x IXGBE_FWSM
+#define IXGBE_FWSM_BY_MAC(_hw) IXGBE_FWSM
+
+#define IXGBE_SWFW_SYNC IXGBE_GSSR
+#define IXGBE_SWFW_SYNC_X540 IXGBE_SWFW_SYNC
+#define IXGBE_SWFW_SYNC_X550 IXGBE_SWFW_SYNC
+#define IXGBE_SWFW_SYNC_X550EM_x IXGBE_SWFW_SYNC
+#define IXGBE_SWFW_SYNC_BY_MAC(_hw) IXGBE_SWFW_SYNC
+
#define IXGBE_GSSR 0x10160
#define IXGBE_MREVID 0x11064
#define IXGBE_DCA_ID 0x11070
#define IXGBE_DCA_CTRL 0x11074
-#define IXGBE_SWFW_SYNC IXGBE_GSSR
/* PCI-E registers 82599-Specific */
#define IXGBE_GCR_EXT 0x11050
@@ -1008,14 +1082,18 @@ struct ixgbe_dmac_config {
#define IXGBE_PHYDAT_82599 0x11044
#define IXGBE_PHYCTL_82599 0x11048
#define IXGBE_PBACLR_82599 0x11068
-#define IXGBE_CIAA_82599 0x11088
-#define IXGBE_CIAD_82599 0x1108C
+#define IXGBE_CIAA 0x11088
+#define IXGBE_CIAD 0x1108C
+#define IXGBE_CIAA_82599 IXGBE_CIAA
+#define IXGBE_CIAD_82599 IXGBE_CIAD
+#define IXGBE_CIAA_X540 IXGBE_CIAA
+#define IXGBE_CIAD_X540 IXGBE_CIAD
#define IXGBE_CIAA_X550 0x11508
#define IXGBE_CIAD_X550 0x11510
-#define IXGBE_CIAA_BY_MAC(_hw) ((((_hw)->mac.type >= ixgbe_mac_X550) ? \
- IXGBE_CIAA_X550 : IXGBE_CIAA_82599))
-#define IXGBE_CIAD_BY_MAC(_hw) ((((_hw)->mac.type >= ixgbe_mac_X550) ? \
- IXGBE_CIAD_X550 : IXGBE_CIAD_82599))
+#define IXGBE_CIAA_X550EM_x IXGBE_CIAA_X550
+#define IXGBE_CIAD_X550EM_x IXGBE_CIAD_X550
+#define IXGBE_CIAA_BY_MAC(_hw) IXGBE_BY_MAC((_hw), CIAA)
+#define IXGBE_CIAD_BY_MAC(_hw) IXGBE_BY_MAC((_hw), CIAD)
#define IXGBE_PICAUSE 0x110B0
#define IXGBE_PIENA 0x110B8
#define IXGBE_CDQ_MBR_82599 0x110B4
@@ -1365,6 +1443,8 @@ struct ixgbe_dmac_config {
#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */
#define IXGBE_MDIO_AUTO_NEG_VENDOR_STAT 0xC800 /* AUTO_NEG Vendor Status Reg */
#define IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM 0xCC00 /* AUTO_NEG Vendor TX Reg */
+#define IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2 0xCC01 /* AUTO_NEG Vendor Tx Reg */
+#define IXGBE_MDIO_AUTO_NEG_VEN_LSC 0x1 /* AUTO_NEG Vendor Tx LSC */
#define IXGBE_MDIO_AUTO_NEG_ADVT 0x10 /* AUTO_NEG Advt Reg */
#define IXGBE_MDIO_AUTO_NEG_LP 0x13 /* AUTO_NEG LP Status Reg */
#define IXGBE_MDIO_AUTO_NEG_EEE_ADVT 0x3C /* AUTO_NEG EEE Advt Reg */
@@ -1393,11 +1473,24 @@ struct ixgbe_dmac_config {
#define IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK 0x3 /* PHY Reset Complete Mask */
#define IXGBE_MDIO_GLOBAL_RES_PR_10 0xC479 /* Global Resv Provisioning 10 Reg */
#define IXGBE_MDIO_POWER_UP_STALL 0x8000 /* Power Up Stall */
-
+#define IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK 0xFF00 /* int std mask */
+#define IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG 0xFC00 /* chip std int flag */
+#define IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK 0xFF01 /* int chip-wide mask */
+#define IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG 0xFC01 /* int chip-wide mask */
+#define IXGBE_MDIO_GLOBAL_ALARM_1 0xCC00 /* Global alarm 1 */
+#define IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL 0x4000 /* high temp failure */
+#define IXGBE_MDIO_GLOBAL_INT_MASK 0xD400 /* Global int mask */
+#define IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN 0x1000 /* autoneg vendor alarm int enable */
+#define IXGBE_MDIO_GLOBAL_ALARM_1_INT 0x4 /* int in Global alarm 1 */
+#define IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN 0x1 /* vendor alarm int enable */
+#define IXGBE_MDIO_GLOBAL_STD_ALM2_INT 0x200 /* vendor alarm2 int mask */
+#define IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN 0x4000 /* int high temp enable */
#define IXGBE_MDIO_PMA_PMD_CONTROL_ADDR 0x0000 /* PMA/PMD Control Reg */
#define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Addr Reg */
#define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA 0xC30B /* PHY_XS SDA/SCL Data Reg */
#define IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT 0xC30C /* PHY_XS SDA/SCL Status Reg */
+#define IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK 0xD401 /* PHY TX Vendor LASI */
+#define IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN 0x1 /* PHY TX Vendor LASI enable */
#define IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR 0x9 /* Standard Transmit Dis Reg */
#define IXGBE_MDIO_PMD_GLOBAL_TX_DISABLE 0x0001 /* PMD Global Transmit Dis */
@@ -1479,12 +1572,16 @@ struct ixgbe_dmac_config {
#define IXGBE_SDP0_GPIEN_X540 0x00000002 /* SDP0 on X540 and X550 */
#define IXGBE_SDP1_GPIEN_X540 0x00000004 /* SDP1 on X540 and X550 */
#define IXGBE_SDP2_GPIEN_X540 0x00000008 /* SDP2 on X540 and X550 */
-#define IXGBE_SDP0_GPIEN_BY_MAC(_hw) ((_hw)->mac.type >= ixgbe_mac_X540 ? \
- IXGBE_SDP0_GPIEN_X540 : IXGBE_SDP0_GPIEN)
-#define IXGBE_SDP1_GPIEN_BY_MAC(_hw) ((_hw)->mac.type >= ixgbe_mac_X540 ? \
- IXGBE_SDP1_GPIEN_X540 : IXGBE_SDP1_GPIEN)
-#define IXGBE_SDP2_GPIEN_BY_MAC(_hw) ((_hw)->mac.type >= ixgbe_mac_X540 ? \
- IXGBE_SDP2_GPIEN_X540 : IXGBE_SDP2_GPIEN)
+#define IXGBE_SDP0_GPIEN_X550 IXGBE_SDP0_GPIEN_X540
+#define IXGBE_SDP1_GPIEN_X550 IXGBE_SDP1_GPIEN_X540
+#define IXGBE_SDP2_GPIEN_X550 IXGBE_SDP2_GPIEN_X540
+#define IXGBE_SDP0_GPIEN_X550EM_x IXGBE_SDP0_GPIEN_X540
+#define IXGBE_SDP1_GPIEN_X550EM_x IXGBE_SDP1_GPIEN_X540
+#define IXGBE_SDP2_GPIEN_X550EM_x IXGBE_SDP2_GPIEN_X540
+#define IXGBE_SDP0_GPIEN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SDP0_GPIEN)
+#define IXGBE_SDP1_GPIEN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SDP1_GPIEN)
+#define IXGBE_SDP2_GPIEN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SDP2_GPIEN)
+
#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */
#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */
#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */
@@ -1665,15 +1762,16 @@ enum {
#define IXGBE_EICR_GPI_SDP0_X540 0x02000000 /* Gen Purpose Interrupt on SDP0 */
#define IXGBE_EICR_GPI_SDP1_X540 0x04000000 /* Gen Purpose Interrupt on SDP1 */
#define IXGBE_EICR_GPI_SDP2_X540 0x08000000 /* Gen Purpose Interrupt on SDP2 */
-#define IXGBE_EICR_GPI_SDP0_BY_MAC(_hw) ((_hw)->mac.type >= ixgbe_mac_X540 ? \
- IXGBE_EICR_GPI_SDP0_X540 : \
- IXGBE_EICR_GPI_SDP0)
-#define IXGBE_EICR_GPI_SDP1_BY_MAC(_hw) ((_hw)->mac.type >= ixgbe_mac_X540 ? \
- IXGBE_EICR_GPI_SDP1_X540 : \
- IXGBE_EICR_GPI_SDP1)
-#define IXGBE_EICR_GPI_SDP2_BY_MAC(_hw) ((_hw)->mac.type >= ixgbe_mac_X540 ? \
- IXGBE_EICR_GPI_SDP2_X540 : \
- IXGBE_EICR_GPI_SDP2)
+#define IXGBE_EICR_GPI_SDP0_X550 IXGBE_EICR_GPI_SDP0_X540
+#define IXGBE_EICR_GPI_SDP1_X550 IXGBE_EICR_GPI_SDP1_X540
+#define IXGBE_EICR_GPI_SDP2_X550 IXGBE_EICR_GPI_SDP2_X540
+#define IXGBE_EICR_GPI_SDP0_X550EM_x IXGBE_EICR_GPI_SDP0_X540
+#define IXGBE_EICR_GPI_SDP1_X550EM_x IXGBE_EICR_GPI_SDP1_X540
+#define IXGBE_EICR_GPI_SDP2_X550EM_x IXGBE_EICR_GPI_SDP2_X540
+#define IXGBE_EICR_GPI_SDP0_BY_MAC(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP0)
+#define IXGBE_EICR_GPI_SDP1_BY_MAC(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP1)
+#define IXGBE_EICR_GPI_SDP2_BY_MAC(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP2)
+
#define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */
#define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */
#define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */
@@ -1901,6 +1999,9 @@ enum {
#define IXGBE_LED_IVRT(_i) IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i)
#define IXGBE_LED_BLINK(_i) IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i)
#define IXGBE_LED_MODE_MASK(_i) IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i)
+#define IXGBE_X557_LED_MANUAL_SET_MASK (1 << 8)
+#define IXGBE_X557_MAX_LED_INDEX 3
+#define IXGBE_X557_LED_PROVISIONING 0xC430
/* LED modes */
#define IXGBE_LED_LINK_UP 0x0
@@ -2784,6 +2885,7 @@ enum ixgbe_fdir_pballoc_type {
#define IXGBE_HI_FLASH_ERASE_TIMEOUT 1000 /* Process Erase command limit */
#define IXGBE_HI_FLASH_UPDATE_TIMEOUT 5000 /* Process Update command limit */
#define IXGBE_HI_FLASH_APPLY_TIMEOUT 0 /* Process Apply command limit */
+#define IXGBE_HI_PHY_MGMT_REQ_TIMEOUT 2000 /* Wait up to 2 seconds */
/* CEM Support */
#define FW_CEM_HDR_LEN 0x4
@@ -2804,6 +2906,7 @@ enum ixgbe_fdir_pballoc_type {
#define FW_MAX_READ_BUFFER_SIZE 1024
#define FW_DISABLE_RXEN_CMD 0xDE
#define FW_DISABLE_RXEN_LEN 0x1
+#define FW_PHY_MGMT_REQ_CMD 0x20
/* Host Interface Command Structures */
struct ixgbe_hic_hdr {
@@ -3200,6 +3303,36 @@ union ixgbe_atr_hash_dword {
};
+#define IXGBE_MVALS_INIT(m) \
+ IXGBE_CAT(EEC, m), \
+ IXGBE_CAT(FLA, m), \
+ IXGBE_CAT(GRC, m), \
+ IXGBE_CAT(SRAMREL, m), \
+ IXGBE_CAT(FACTPS, m), \
+ IXGBE_CAT(SWSM, m), \
+ IXGBE_CAT(FWSM, m), \
+ IXGBE_CAT(SDP0_GPIEN, m), \
+ IXGBE_CAT(SDP1_GPIEN, m), \
+ IXGBE_CAT(SDP2_GPIEN, m), \
+ IXGBE_CAT(EICR_GPI_SDP0, m), \
+ IXGBE_CAT(EICR_GPI_SDP1, m), \
+ IXGBE_CAT(EICR_GPI_SDP2, m), \
+ IXGBE_CAT(CIAA, m), \
+ IXGBE_CAT(CIAD, m), \
+ IXGBE_CAT(I2C_CLK_IN, m), \
+ IXGBE_CAT(I2C_CLK_OUT, m), \
+ IXGBE_CAT(I2C_DATA_IN, m), \
+ IXGBE_CAT(I2C_DATA_OUT, m), \
+ IXGBE_CAT(I2C_DATA_OE_N_EN, m), \
+ IXGBE_CAT(I2C_BB_EN, m), \
+ IXGBE_CAT(I2C_CLK_OE_N_EN, m), \
+ IXGBE_CAT(I2CCTL, m)
+
+enum ixgbe_mvals {
+ IXGBE_MVALS_INIT(_IDX),
+ IXGBE_MVALS_IDX_LIMIT
+};
+
/*
* Unavailable: The FCoE Boot Option ROM is not present in the flash.
* Disabled: Present; boot order is not set for any targets on the port.
@@ -3225,17 +3358,10 @@ enum ixgbe_mac_type {
ixgbe_mac_82599_vf,
ixgbe_mac_X540,
ixgbe_mac_X540_vf,
- /*
- * X550EM MAC type decoder:
- * ixgbe_mac_X550EM_x: "x" = Xeon
- * ixgbe_mac_X550EM_a: "a" = Atom
- */
ixgbe_mac_X550,
ixgbe_mac_X550EM_x,
- ixgbe_mac_X550EM_a,
ixgbe_mac_X550_vf,
ixgbe_mac_X550EM_x_vf,
- ixgbe_mac_X550EM_a_vf,
ixgbe_num_macs
};
@@ -3294,6 +3420,8 @@ enum ixgbe_sfp_type {
ixgbe_sfp_type_1g_cu_core1 = 10,
ixgbe_sfp_type_1g_sx_core0 = 11,
ixgbe_sfp_type_1g_sx_core1 = 12,
+ ixgbe_sfp_type_1g_lx_core0 = 13,
+ ixgbe_sfp_type_1g_lx_core1 = 14,
ixgbe_sfp_type_not_present = 0xFFFE,
ixgbe_sfp_type_unknown = 0xFFFF
};
@@ -3611,6 +3739,15 @@ struct ixgbe_phy_operations {
s32 (*check_overtemp)(struct ixgbe_hw *);
s32 (*set_phy_power)(struct ixgbe_hw *, bool on);
s32 (*enter_lplu)(struct ixgbe_hw *);
+ s32 (*handle_lasi)(struct ixgbe_hw *hw);
+ s32 (*read_i2c_combined_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg,
+ u16 *value);
+ s32 (*write_i2c_combined_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg,
+ u16 value);
+ s32 (*read_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr,
+ u8 *value);
+ s32 (*write_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr,
+ u8 value);
};
struct ixgbe_eeprom_info {
@@ -3674,6 +3811,7 @@ struct ixgbe_phy_info {
bool multispeed_fiber;
bool reset_if_overtemp;
bool qsfp_shared_i2c_bus;
+ u32 nw_mng_if_sel;
};
#include "ixgbe_mbx.h"
@@ -3717,6 +3855,7 @@ struct ixgbe_hw {
struct ixgbe_eeprom_info eeprom;
struct ixgbe_bus_info bus;
struct ixgbe_mbx_info mbx;
+ const u32 *mvals;
u16 device_id;
u16 vendor_id;
u16 subsystem_device_id;
@@ -3775,6 +3914,10 @@ struct ixgbe_hw {
#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF
+#define IXGBE_FUSES0_GROUP(_i) (0x11158 + ((_i) * 4))
+#define IXGBE_FUSES0_300MHZ (1 << 5)
+#define IXGBE_FUSES0_REV1 (1 << 6)
+
#define IXGBE_KRM_PORT_CAR_GEN_CTRL(P) ((P == 0) ? (0x4010) : (0x8010))
#define IXGBE_KRM_LINK_CTRL_1(P) ((P == 0) ? (0x420C) : (0x820C))
#define IXGBE_KRM_AN_CNTL_1(P) ((P == 0) ? (0x422C) : (0x822C))
@@ -3842,8 +3985,10 @@ struct ixgbe_hw {
#define IXGBE_SB_IOSF_CTRL_BUSY_SHIFT 31
#define IXGBE_SB_IOSF_CTRL_BUSY (1 << IXGBE_SB_IOSF_CTRL_BUSY_SHIFT)
#define IXGBE_SB_IOSF_TARGET_KR_PHY 0
-#define IXGBE_SB_IOSF_TARGET_KX4_UNIPHY 1
-#define IXGBE_SB_IOSF_TARGET_KX4_PCS0 2
-#define IXGBE_SB_IOSF_TARGET_KX4_PCS1 3
+#define IXGBE_SB_IOSF_TARGET_KX4_PHY 1
+#define IXGBE_SB_IOSF_TARGET_KX4_PCS 2
+
+#define IXGBE_NW_MNG_IF_SEL 0x00011178
+#define IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE (1 << 24)
#endif /* _IXGBE_TYPE_H_ */
diff --git a/sys/dev/ixgbe/ixgbe_vf.c b/sys/dev/ixgbe/ixgbe_vf.c
index 964514c..c010cf4 100644
--- a/sys/dev/ixgbe/ixgbe_vf.c
+++ b/sys/dev/ixgbe/ixgbe_vf.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -669,4 +669,3 @@ int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
UNREFERENCED_3PARAMETER(hw, num_tcs, default_tc);
return IXGBE_SUCCESS;
}
-
diff --git a/sys/dev/ixgbe/ixgbe_vf.h b/sys/dev/ixgbe/ixgbe_vf.h
index 8f4d46e..edc8013 100644
--- a/sys/dev/ixgbe/ixgbe_vf.h
+++ b/sys/dev/ixgbe/ixgbe_vf.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_x540.c b/sys/dev/ixgbe/ixgbe_x540.c
index 93c6ca4..ddf0674 100644
--- a/sys/dev/ixgbe/ixgbe_x540.c
+++ b/sys/dev/ixgbe/ixgbe_x540.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -932,14 +932,14 @@ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw)
/* Release both semaphores by writing 0 to the bits REGSMP and SMBI */
- swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
- swsm &= ~IXGBE_SWSM_SMBI;
- IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
-
swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC);
swsm &= ~IXGBE_SWFW_REGSMP;
IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swsm);
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ swsm &= ~IXGBE_SWSM_SMBI;
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+
IXGBE_WRITE_FLUSH(hw);
}
@@ -1011,5 +1011,3 @@ s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index)
return IXGBE_SUCCESS;
}
-
-
diff --git a/sys/dev/ixgbe/ixgbe_x540.h b/sys/dev/ixgbe/ixgbe_x540.h
index 12da827..efd0d41 100644
--- a/sys/dev/ixgbe/ixgbe_x540.h
+++ b/sys/dev/ixgbe/ixgbe_x540.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2014, Intel Corporation
+ Copyright (c) 2001-2015, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/ixgbe/ixgbe_x550.c b/sys/dev/ixgbe/ixgbe_x550.c
new file mode 100644
index 0000000..65daa17
--- /dev/null
+++ b/sys/dev/ixgbe/ixgbe_x550.c
@@ -0,0 +1,3191 @@
+/******************************************************************************
+
+ Copyright (c) 2001-2015, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+/*$FreeBSD$*/
+
+#include "ixgbe_x550.h"
+#include "ixgbe_x540.h"
+#include "ixgbe_type.h"
+#include "ixgbe_api.h"
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed);
+
+/**
+ * ixgbe_init_ops_X550 - Inits func ptrs and MAC type
+ * @hw: pointer to hardware structure
+ *
+ * Initialize the function pointers and assign the MAC type for X550.
+ * Does not touch the hardware.
+ **/
+s32 ixgbe_init_ops_X550(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mac_info *mac = &hw->mac;
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ s32 ret_val;
+
+ DEBUGFUNC("ixgbe_init_ops_X550");
+
+ ret_val = ixgbe_init_ops_X540(hw);
+ mac->ops.dmac_config = ixgbe_dmac_config_X550;
+ mac->ops.dmac_config_tcs = ixgbe_dmac_config_tcs_X550;
+ mac->ops.dmac_update_tcs = ixgbe_dmac_update_tcs_X550;
+ mac->ops.setup_eee = ixgbe_setup_eee_X550;
+ mac->ops.set_source_address_pruning =
+ ixgbe_set_source_address_pruning_X550;
+ mac->ops.set_ethertype_anti_spoofing =
+ ixgbe_set_ethertype_anti_spoofing_X550;
+
+ mac->ops.get_rtrup2tc = ixgbe_dcb_get_rtrup2tc_generic;
+ eeprom->ops.init_params = ixgbe_init_eeprom_params_X550;
+ eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550;
+ eeprom->ops.read = ixgbe_read_ee_hostif_X550;
+ eeprom->ops.read_buffer = ixgbe_read_ee_hostif_buffer_X550;
+ eeprom->ops.write = ixgbe_write_ee_hostif_X550;
+ eeprom->ops.write_buffer = ixgbe_write_ee_hostif_buffer_X550;
+ eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550;
+ eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550;
+
+ mac->ops.disable_mdd = ixgbe_disable_mdd_X550;
+ mac->ops.enable_mdd = ixgbe_enable_mdd_X550;
+ mac->ops.mdd_event = ixgbe_mdd_event_X550;
+ mac->ops.restore_mdd_vf = ixgbe_restore_mdd_vf_X550;
+ mac->ops.disable_rx = ixgbe_disable_rx_x550;
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
+ hw->mac.ops.led_on = ixgbe_led_on_t_X550em;
+ hw->mac.ops.led_off = ixgbe_led_off_t_X550em;
+ }
+ return ret_val;
+}
+
+/**
+ * ixgbe_read_cs4227 - Read CS4227 register
+ * @hw: pointer to hardware structure
+ * @reg: register number to write
+ * @value: pointer to receive value read
+ *
+ * Returns status code
+ **/
+static s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value)
+{
+ return ixgbe_read_i2c_combined_unlocked(hw, IXGBE_CS4227, reg, value);
+}
+
+/**
+ * ixgbe_write_cs4227 - Write CS4227 register
+ * @hw: pointer to hardware structure
+ * @reg: register number to write
+ * @value: value to write to register
+ *
+ * Returns status code
+ **/
+static s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value)
+{
+ return ixgbe_write_i2c_combined_unlocked(hw, IXGBE_CS4227, reg, value);
+}
+
+/**
+ * ixgbe_get_cs4227_status - Return CS4227 status
+ * @hw: pointer to hardware structure
+ *
+ * Returns error if CS4227 not successfully initialized
+ **/
+static s32 ixgbe_get_cs4227_status(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u16 value = 0;
+ u16 reg_slice, reg_val;
+ u8 retry;
+
+ for (retry = 0; retry < IXGBE_CS4227_RETRIES; ++retry) {
+ status = ixgbe_read_cs4227(hw, IXGBE_CS4227_GLOBAL_ID_LSB,
+ &value);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ if (value == IXGBE_CS4227_GLOBAL_ID_VALUE)
+ break;
+ msec_delay(IXGBE_CS4227_CHECK_DELAY);
+ }
+ if (value != IXGBE_CS4227_GLOBAL_ID_VALUE)
+ return IXGBE_ERR_PHY;
+
+ status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If this is the first time after power-on, check the ucode.
+ * Otherwise, this will disrupt link on all ports. Because we
+ * can only do this the first time, we must check all ports,
+ * not just our own.
+ */
+ if (value != IXGBE_CS4227_SCRATCH_VALUE) {
+ reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB;
+ reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
+ status = ixgbe_write_cs4227(hw, reg_slice,
+ reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB;
+ reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
+ status = ixgbe_write_cs4227(hw, reg_slice,
+ reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (1 << 12);
+ reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+ status = ixgbe_write_cs4227(hw, reg_slice,
+ reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (1 << 12);
+ reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+ status = ixgbe_write_cs4227(hw, reg_slice,
+ reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ msec_delay(10);
+ }
+
+ /* Verify that the ucode is operational on all ports. */
+ reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB;
+ reg_val = 0xFFFF;
+ status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ if (reg_val != 0)
+ return IXGBE_ERR_PHY;
+
+ reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB;
+ reg_val = 0xFFFF;
+ status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ if (reg_val != 0)
+ return IXGBE_ERR_PHY;
+
+ reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (1 << 12);
+ reg_val = 0xFFFF;
+ status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ if (reg_val != 0)
+ return IXGBE_ERR_PHY;
+
+ reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (1 << 12);
+ reg_val = 0xFFFF;
+ status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ if (reg_val != 0)
+ return IXGBE_ERR_PHY;
+
+ /* Set scratch for next time. */
+ status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
+ IXGBE_CS4227_SCRATCH_VALUE);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ if (value != IXGBE_CS4227_SCRATCH_VALUE)
+ return IXGBE_ERR_PHY;
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_read_pe - Read register from port expander
+ * @hw: pointer to hardware structure
+ * @reg: register number to read
+ * @value: pointer to receive read value
+ *
+ * Returns status code
+ **/
+static s32 ixgbe_read_pe(struct ixgbe_hw *hw, u8 reg, u8 *value)
+{
+ s32 status;
+
+ status = ixgbe_read_i2c_byte_unlocked(hw, reg, IXGBE_PE, value);
+ if (status != IXGBE_SUCCESS)
+ ERROR_REPORT2(IXGBE_ERROR_CAUTION,
+ "port expander access failed with %d\n", status);
+ return status;
+}
+
+/**
+ * ixgbe_write_pe - Write register to port expander
+ * @hw: pointer to hardware structure
+ * @reg: register number to write
+ * @value: value to write
+ *
+ * Returns status code
+ **/
+static s32 ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value)
+{
+ s32 status;
+
+ status = ixgbe_write_i2c_byte_unlocked(hw, reg, IXGBE_PE, value);
+ if (status != IXGBE_SUCCESS)
+ ERROR_REPORT2(IXGBE_ERROR_CAUTION,
+ "port expander access failed with %d\n", status);
+ return status;
+}
+
+/**
+ * ixgbe_reset_cs4227 - Reset CS4227 using port expander
+ * @hw: pointer to hardware structure
+ *
+ * Returns error code
+ **/
+static s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u8 reg;
+
+ status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg |= IXGBE_PE_BIT1;
+ status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ status = ixgbe_read_pe(hw, IXGBE_PE_CONFIG, &reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg &= ~IXGBE_PE_BIT1;
+ status = ixgbe_write_pe(hw, IXGBE_PE_CONFIG, reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg &= ~IXGBE_PE_BIT1;
+ status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ usec_delay(IXGBE_CS4227_RESET_HOLD);
+
+ status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg |= IXGBE_PE_BIT1;
+ status = ixgbe_write_pe(hw, IXGBE_PE_OUTPUT, reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ msec_delay(IXGBE_CS4227_RESET_DELAY);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_check_cs4227 - Check CS4227 and reset as needed
+ * @hw: pointer to hardware structure
+ **/
+static void ixgbe_check_cs4227(struct ixgbe_hw *hw)
+{
+ u32 swfw_mask = hw->phy.phy_semaphore_mask;
+ s32 status;
+ u8 retry;
+
+ for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
+ status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
+ if (status != IXGBE_SUCCESS) {
+ ERROR_REPORT2(IXGBE_ERROR_CAUTION,
+ "semaphore failed with %d\n", status);
+ return;
+ }
+ status = ixgbe_get_cs4227_status(hw);
+ if (status == IXGBE_SUCCESS) {
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ msec_delay(hw->eeprom.semaphore_delay);
+ return;
+ }
+ ixgbe_reset_cs4227(hw);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+ msec_delay(hw->eeprom.semaphore_delay);
+ }
+ ERROR_REPORT2(IXGBE_ERROR_CAUTION,
+ "Unable to initialize CS4227, err=%d\n", status);
+}
+
+/**
+ * ixgbe_setup_mux_ctl - Setup ESDP register for I2C mux control
+ * @hw: pointer to hardware structure
+ **/
+static void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw)
+{
+ u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+
+ if (hw->bus.lan_id) {
+ esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
+ esdp |= IXGBE_ESDP_SDP1_DIR;
+ }
+ esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+ IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
+ * ixgbe_identify_phy_x550em - Get PHY type based on device id
+ * @hw: pointer to hardware structure
+ *
+ * Returns error code
+ */
+static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
+{
+ switch (hw->device_id) {
+ case IXGBE_DEV_ID_X550EM_X_SFP:
+ /* set up for CS4227 usage */
+ hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
+ ixgbe_setup_mux_ctl(hw);
+ ixgbe_check_cs4227(hw);
+
+ return ixgbe_identify_module_generic(hw);
+ break;
+ case IXGBE_DEV_ID_X550EM_X_KX4:
+ hw->phy.type = ixgbe_phy_x550em_kx4;
+ break;
+ case IXGBE_DEV_ID_X550EM_X_KR:
+ hw->phy.type = ixgbe_phy_x550em_kr;
+ break;
+ case IXGBE_DEV_ID_X550EM_X_1G_T:
+ case IXGBE_DEV_ID_X550EM_X_10G_T:
+ return ixgbe_identify_phy_generic(hw);
+ default:
+ break;
+ }
+ return IXGBE_SUCCESS;
+}
+
+static s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 *phy_data)
+{
+ UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, *phy_data);
+ return IXGBE_NOT_IMPLEMENTED;
+}
+
+static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 phy_data)
+{
+ UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, phy_data);
+ return IXGBE_NOT_IMPLEMENTED;
+}
+
+/**
+* ixgbe_init_ops_X550EM - Inits func ptrs and MAC type
+* @hw: pointer to hardware structure
+*
+* Initialize the function pointers and for MAC type X550EM.
+* Does not touch the hardware.
+**/
+s32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mac_info *mac = &hw->mac;
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ struct ixgbe_phy_info *phy = &hw->phy;
+ s32 ret_val;
+
+ DEBUGFUNC("ixgbe_init_ops_X550EM");
+
+ /* Similar to X550 so start there. */
+ ret_val = ixgbe_init_ops_X550(hw);
+
+ /* Since this function eventually calls
+ * ixgbe_init_ops_540 by design, we are setting
+ * the pointers to NULL explicitly here to overwrite
+ * the values being set in the x540 function.
+ */
+
+ /* FCOE not supported in x550EM */
+ mac->ops.get_san_mac_addr = NULL;
+ mac->ops.set_san_mac_addr = NULL;
+ mac->ops.get_wwn_prefix = NULL;
+ mac->ops.get_fcoe_boot_status = NULL;
+
+ /* IPsec not supported in x550EM */
+ mac->ops.disable_sec_rx_path = NULL;
+ mac->ops.enable_sec_rx_path = NULL;
+
+ /* AUTOC register is not present in x550EM. */
+ mac->ops.prot_autoc_read = NULL;
+ mac->ops.prot_autoc_write = NULL;
+
+ /* X550EM bus type is internal*/
+ hw->bus.type = ixgbe_bus_type_internal;
+ mac->ops.get_bus_info = ixgbe_get_bus_info_X550em;
+
+ mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550;
+ mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550;
+ mac->ops.get_media_type = ixgbe_get_media_type_X550em;
+ mac->ops.setup_sfp = ixgbe_setup_sfp_modules_X550em;
+ mac->ops.get_link_capabilities = ixgbe_get_link_capabilities_X550em;
+ mac->ops.reset_hw = ixgbe_reset_hw_X550em;
+ mac->ops.get_supported_physical_layer =
+ ixgbe_get_supported_physical_layer_X550em;
+
+ if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
+ mac->ops.setup_fc = ixgbe_setup_fc_generic;
+ else
+ mac->ops.setup_fc = ixgbe_setup_fc_X550em;
+
+ mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em;
+ mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em;
+
+ if (hw->device_id != IXGBE_DEV_ID_X550EM_X_KR)
+ mac->ops.setup_eee = NULL;
+
+ /* PHY */
+ phy->ops.init = ixgbe_init_phy_ops_X550em;
+ phy->ops.identify = ixgbe_identify_phy_x550em;
+ if (mac->ops.get_media_type(hw) != ixgbe_media_type_copper)
+ phy->ops.set_phy_power = NULL;
+
+
+ /* EEPROM */
+ eeprom->ops.init_params = ixgbe_init_eeprom_params_X540;
+ eeprom->ops.read = ixgbe_read_ee_hostif_X550;
+ eeprom->ops.read_buffer = ixgbe_read_ee_hostif_buffer_X550;
+ eeprom->ops.write = ixgbe_write_ee_hostif_X550;
+ eeprom->ops.write_buffer = ixgbe_write_ee_hostif_buffer_X550;
+ eeprom->ops.update_checksum = ixgbe_update_eeprom_checksum_X550;
+ eeprom->ops.validate_checksum = ixgbe_validate_eeprom_checksum_X550;
+ eeprom->ops.calc_checksum = ixgbe_calc_eeprom_checksum_X550;
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_dmac_config_X550
+ * @hw: pointer to hardware structure
+ *
+ * Configure DMA coalescing. If enabling dmac, dmac is activated.
+ * When disabling dmac, dmac enable dmac bit is cleared.
+ **/
+s32 ixgbe_dmac_config_X550(struct ixgbe_hw *hw)
+{
+ u32 reg, high_pri_tc;
+
+ DEBUGFUNC("ixgbe_dmac_config_X550");
+
+ /* Disable DMA coalescing before configuring */
+ reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
+ reg &= ~IXGBE_DMACR_DMAC_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
+
+ /* Disable DMA Coalescing if the watchdog timer is 0 */
+ if (!hw->mac.dmac_config.watchdog_timer)
+ goto out;
+
+ ixgbe_dmac_config_tcs_X550(hw);
+
+ /* Configure DMA Coalescing Control Register */
+ reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
+
+ /* Set the watchdog timer in units of 40.96 usec */
+ reg &= ~IXGBE_DMACR_DMACWT_MASK;
+ reg |= (hw->mac.dmac_config.watchdog_timer * 100) / 4096;
+
+ reg &= ~IXGBE_DMACR_HIGH_PRI_TC_MASK;
+ /* If fcoe is enabled, set high priority traffic class */
+ if (hw->mac.dmac_config.fcoe_en) {
+ high_pri_tc = 1 << hw->mac.dmac_config.fcoe_tc;
+ reg |= ((high_pri_tc << IXGBE_DMACR_HIGH_PRI_TC_SHIFT) &
+ IXGBE_DMACR_HIGH_PRI_TC_MASK);
+ }
+ reg |= IXGBE_DMACR_EN_MNG_IND;
+
+ /* Enable DMA coalescing after configuration */
+ reg |= IXGBE_DMACR_DMAC_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
+
+out:
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_dmac_config_tcs_X550
+ * @hw: pointer to hardware structure
+ *
+ * Configure DMA coalescing threshold per TC. The dmac enable bit must
+ * be cleared before configuring.
+ **/
+s32 ixgbe_dmac_config_tcs_X550(struct ixgbe_hw *hw)
+{
+ u32 tc, reg, pb_headroom, rx_pb_size, maxframe_size_kb;
+
+ DEBUGFUNC("ixgbe_dmac_config_tcs_X550");
+
+ /* Configure DMA coalescing enabled */
+ switch (hw->mac.dmac_config.link_speed) {
+ case IXGBE_LINK_SPEED_100_FULL:
+ pb_headroom = IXGBE_DMACRXT_100M;
+ break;
+ case IXGBE_LINK_SPEED_1GB_FULL:
+ pb_headroom = IXGBE_DMACRXT_1G;
+ break;
+ default:
+ pb_headroom = IXGBE_DMACRXT_10G;
+ break;
+ }
+
+ maxframe_size_kb = ((IXGBE_READ_REG(hw, IXGBE_MAXFRS) >>
+ IXGBE_MHADD_MFS_SHIFT) / 1024);
+
+ /* Set the per Rx packet buffer receive threshold */
+ for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) {
+ reg = IXGBE_READ_REG(hw, IXGBE_DMCTH(tc));
+ reg &= ~IXGBE_DMCTH_DMACRXT_MASK;
+
+ if (tc < hw->mac.dmac_config.num_tcs) {
+ /* Get Rx PB size */
+ rx_pb_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(tc));
+ rx_pb_size = (rx_pb_size & IXGBE_RXPBSIZE_MASK) >>
+ IXGBE_RXPBSIZE_SHIFT;
+
+ /* Calculate receive buffer threshold in kilobytes */
+ if (rx_pb_size > pb_headroom)
+ rx_pb_size = rx_pb_size - pb_headroom;
+ else
+ rx_pb_size = 0;
+
+ /* Minimum of MFS shall be set for DMCTH */
+ reg |= (rx_pb_size > maxframe_size_kb) ?
+ rx_pb_size : maxframe_size_kb;
+ }
+ IXGBE_WRITE_REG(hw, IXGBE_DMCTH(tc), reg);
+ }
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_dmac_update_tcs_X550
+ * @hw: pointer to hardware structure
+ *
+ * Disables dmac, updates per TC settings, and then enables dmac.
+ **/
+s32 ixgbe_dmac_update_tcs_X550(struct ixgbe_hw *hw)
+{
+ u32 reg;
+
+ DEBUGFUNC("ixgbe_dmac_update_tcs_X550");
+
+ /* Disable DMA coalescing before configuring */
+ reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
+ reg &= ~IXGBE_DMACR_DMAC_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
+
+ ixgbe_dmac_config_tcs_X550(hw);
+
+ /* Enable DMA coalescing after configuration */
+ reg = IXGBE_READ_REG(hw, IXGBE_DMACR);
+ reg |= IXGBE_DMACR_DMAC_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DMACR, reg);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_init_eeprom_params_X550 - Initialize EEPROM params
+ * @hw: pointer to hardware structure
+ *
+ * Initializes the EEPROM parameters ixgbe_eeprom_info within the
+ * ixgbe_hw struct in order to set up EEPROM access.
+ **/
+s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
+{
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ u32 eec;
+ u16 eeprom_size;
+
+ DEBUGFUNC("ixgbe_init_eeprom_params_X550");
+
+ if (eeprom->type == ixgbe_eeprom_uninitialized) {
+ eeprom->semaphore_delay = 10;
+ eeprom->type = ixgbe_flash;
+
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
+ IXGBE_EEC_SIZE_SHIFT);
+ eeprom->word_size = 1 << (eeprom_size +
+ IXGBE_EEPROM_WORD_SIZE_SHIFT);
+
+ DEBUGOUT2("Eeprom params: type = %d, size = %d\n",
+ eeprom->type, eeprom->word_size);
+ }
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_setup_eee_X550 - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ * @enable_eee: boolean flag to enable EEE
+ *
+ * Enable/disable EEE based on enable_eee flag.
+ * Auto-negotiation must be started after BASE-T EEE bits in PHY register 7.3C
+ * are modified.
+ *
+ **/
+s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee)
+{
+ u32 eeer;
+ u16 autoneg_eee_reg;
+ u32 link_reg;
+ s32 status;
+ u32 fuse;
+
+ DEBUGFUNC("ixgbe_setup_eee_X550");
+
+ eeer = IXGBE_READ_REG(hw, IXGBE_EEER);
+ /* Enable or disable EEE per flag */
+ if (enable_eee) {
+ eeer |= (IXGBE_EEER_TX_LPI_EN | IXGBE_EEER_RX_LPI_EN);
+
+ if (hw->device_id == IXGBE_DEV_ID_X550T) {
+ /* Advertise EEE capability */
+ hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_eee_reg);
+
+ autoneg_eee_reg |= (IXGBE_AUTO_NEG_10GBASE_EEE_ADVT |
+ IXGBE_AUTO_NEG_1000BASE_EEE_ADVT |
+ IXGBE_AUTO_NEG_100BASE_EEE_ADVT);
+
+ hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_eee_reg);
+ } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) {
+ /* Not supported on first revision. */
+ fuse = IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0));
+ if (!(fuse & IXGBE_FUSES0_REV1))
+ return IXGBE_SUCCESS;
+
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &link_reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ link_reg |= IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KR |
+ IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KX;
+
+ /* Don't advertise FEC capability when EEE enabled. */
+ link_reg &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC;
+
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, link_reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ }
+ } else {
+ eeer &= ~(IXGBE_EEER_TX_LPI_EN | IXGBE_EEER_RX_LPI_EN);
+
+ if (hw->device_id == IXGBE_DEV_ID_X550T) {
+ /* Disable advertised EEE capability */
+ hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_eee_reg);
+
+ autoneg_eee_reg &= ~(IXGBE_AUTO_NEG_10GBASE_EEE_ADVT |
+ IXGBE_AUTO_NEG_1000BASE_EEE_ADVT |
+ IXGBE_AUTO_NEG_100BASE_EEE_ADVT);
+
+ hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_eee_reg);
+ } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) {
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &link_reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ link_reg &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KR |
+ IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KX);
+
+ /* Advertise FEC capability when EEE is disabled. */
+ link_reg |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC;
+
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, link_reg);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ }
+ }
+ IXGBE_WRITE_REG(hw, IXGBE_EEER, eeer);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_set_source_address_pruning_X550 - Enable/Disbale source address pruning
+ * @hw: pointer to hardware structure
+ * @enable: enable or disable source address pruning
+ * @pool: Rx pool to set source address pruning for
+ **/
+void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable,
+ unsigned int pool)
+{
+ u64 pfflp;
+
+ /* max rx pool is 63 */
+ if (pool > 63)
+ return;
+
+ pfflp = (u64)IXGBE_READ_REG(hw, IXGBE_PFFLPL);
+ pfflp |= (u64)IXGBE_READ_REG(hw, IXGBE_PFFLPH) << 32;
+
+ if (enable)
+ pfflp |= (1ULL << pool);
+ else
+ pfflp &= ~(1ULL << pool);
+
+ IXGBE_WRITE_REG(hw, IXGBE_PFFLPL, (u32)pfflp);
+ IXGBE_WRITE_REG(hw, IXGBE_PFFLPH, (u32)(pfflp >> 32));
+}
+
+/**
+ * ixgbe_set_ethertype_anti_spoofing_X550 - Enable/Disable Ethertype anti-spoofing
+ * @hw: pointer to hardware structure
+ * @enable: enable or disable switch for Ethertype anti-spoofing
+ * @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing
+ *
+ **/
+void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw,
+ bool enable, int vf)
+{
+ int vf_target_reg = vf >> 3;
+ int vf_target_shift = vf % 8 + IXGBE_SPOOF_ETHERTYPEAS_SHIFT;
+ u32 pfvfspoof;
+
+ DEBUGFUNC("ixgbe_set_ethertype_anti_spoofing_X550");
+
+ pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg));
+ if (enable)
+ pfvfspoof |= (1 << vf_target_shift);
+ else
+ pfvfspoof &= ~(1 << vf_target_shift);
+
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof);
+}
+
+/**
+ * ixgbe_iosf_wait - Wait for IOSF command completion
+ * @hw: pointer to hardware structure
+ * @ctrl: pointer to location to receive final IOSF control value
+ *
+ * Returns failing status on timeout
+ *
+ * Note: ctrl can be NULL if the IOSF control register value is not needed
+ **/
+static s32 ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl)
+{
+ u32 i, command;
+
+ /* Check every 10 usec to see if the address cycle completed.
+ * The SB IOSF BUSY bit will clear when the operation is
+ * complete
+ */
+ for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
+ command = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL);
+ if ((command & IXGBE_SB_IOSF_CTRL_BUSY) == 0)
+ break;
+ usec_delay(10);
+ }
+ if (ctrl)
+ *ctrl = command;
+ if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
+ ERROR_REPORT1(IXGBE_ERROR_POLLING, "Wait timed out\n");
+ return IXGBE_ERR_PHY;
+ }
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register of the IOSF
+ * device
+ * @hw: pointer to hardware structure
+ * @reg_addr: 32 bit PHY register to write
+ * @device_type: 3 bit device type
+ * @data: Data to write to the register
+ **/
+s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u32 data)
+{
+ u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
+ u32 command, error;
+ s32 ret;
+
+ ret = ixgbe_acquire_swfw_semaphore(hw, gssr);
+ if (ret != IXGBE_SUCCESS)
+ return ret;
+
+ ret = ixgbe_iosf_wait(hw, NULL);
+ if (ret != IXGBE_SUCCESS)
+ goto out;
+
+ command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
+ (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
+
+ /* Write IOSF control register */
+ IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
+
+ /* Write IOSF data register */
+ IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA, data);
+
+ ret = ixgbe_iosf_wait(hw, &command);
+
+ if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
+ error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
+ IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
+ ERROR_REPORT2(IXGBE_ERROR_POLLING,
+ "Failed to write, error %x\n", error);
+ ret = IXGBE_ERR_PHY;
+ }
+
+out:
+ ixgbe_release_swfw_semaphore(hw, gssr);
+ return ret;
+}
+
+/**
+ * ixgbe_read_iosf_sb_reg_x550 - Writes a value to specified register of the IOSF
+ * device
+ * @hw: pointer to hardware structure
+ * @reg_addr: 32 bit PHY register to write
+ * @device_type: 3 bit device type
+ * @phy_data: Pointer to read data from the register
+ **/
+s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u32 *data)
+{
+ u32 gssr = IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_PHY0_SM;
+ u32 command, error;
+ s32 ret;
+
+ ret = ixgbe_acquire_swfw_semaphore(hw, gssr);
+ if (ret != IXGBE_SUCCESS)
+ return ret;
+
+ ret = ixgbe_iosf_wait(hw, NULL);
+ if (ret != IXGBE_SUCCESS)
+ goto out;
+
+ command = ((reg_addr << IXGBE_SB_IOSF_CTRL_ADDR_SHIFT) |
+ (device_type << IXGBE_SB_IOSF_CTRL_TARGET_SELECT_SHIFT));
+
+ /* Write IOSF control register */
+ IXGBE_WRITE_REG(hw, IXGBE_SB_IOSF_INDIRECT_CTRL, command);
+
+ ret = ixgbe_iosf_wait(hw, &command);
+
+ if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
+ error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
+ IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
+ ERROR_REPORT2(IXGBE_ERROR_POLLING,
+ "Failed to read, error %x\n", error);
+ ret = IXGBE_ERR_PHY;
+ }
+
+ if (ret == IXGBE_SUCCESS)
+ *data = IXGBE_READ_REG(hw, IXGBE_SB_IOSF_INDIRECT_DATA);
+
+out:
+ ixgbe_release_swfw_semaphore(hw, gssr);
+ return ret;
+}
+
+/**
+ * ixgbe_disable_mdd_X550
+ * @hw: pointer to hardware structure
+ *
+ * Disable malicious driver detection
+ **/
+void ixgbe_disable_mdd_X550(struct ixgbe_hw *hw)
+{
+ u32 reg;
+
+ DEBUGFUNC("ixgbe_disable_mdd_X550");
+
+ /* Disable MDD for TX DMA and interrupt */
+ reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+ reg &= ~(IXGBE_DMATXCTL_MDP_EN | IXGBE_DMATXCTL_MBINTEN);
+ IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg);
+
+ /* Disable MDD for RX and interrupt */
+ reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+ reg &= ~(IXGBE_RDRXCTL_MDP_EN | IXGBE_RDRXCTL_MBINTEN);
+ IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg);
+}
+
+/**
+ * ixgbe_enable_mdd_X550
+ * @hw: pointer to hardware structure
+ *
+ * Enable malicious driver detection
+ **/
+void ixgbe_enable_mdd_X550(struct ixgbe_hw *hw)
+{
+ u32 reg;
+
+ DEBUGFUNC("ixgbe_enable_mdd_X550");
+
+ /* Enable MDD for TX DMA and interrupt */
+ reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+ reg |= (IXGBE_DMATXCTL_MDP_EN | IXGBE_DMATXCTL_MBINTEN);
+ IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg);
+
+ /* Enable MDD for RX and interrupt */
+ reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+ reg |= (IXGBE_RDRXCTL_MDP_EN | IXGBE_RDRXCTL_MBINTEN);
+ IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg);
+}
+
+/**
+ * ixgbe_restore_mdd_vf_X550
+ * @hw: pointer to hardware structure
+ * @vf: vf index
+ *
+ * Restore VF that was disabled during malicious driver detection event
+ **/
+void ixgbe_restore_mdd_vf_X550(struct ixgbe_hw *hw, u32 vf)
+{
+ u32 idx, reg, num_qs, start_q, bitmask;
+
+ DEBUGFUNC("ixgbe_restore_mdd_vf_X550");
+
+ /* Map VF to queues */
+ reg = IXGBE_READ_REG(hw, IXGBE_MRQC);
+ switch (reg & IXGBE_MRQC_MRQE_MASK) {
+ case IXGBE_MRQC_VMDQRT8TCEN:
+ num_qs = 8; /* 16 VFs / pools */
+ bitmask = 0x000000FF;
+ break;
+ case IXGBE_MRQC_VMDQRSS32EN:
+ case IXGBE_MRQC_VMDQRT4TCEN:
+ num_qs = 4; /* 32 VFs / pools */
+ bitmask = 0x0000000F;
+ break;
+ default: /* 64 VFs / pools */
+ num_qs = 2;
+ bitmask = 0x00000003;
+ break;
+ }
+ start_q = vf * num_qs;
+
+ /* Release vf's queues by clearing WQBR_TX and WQBR_RX (RW1C) */
+ idx = start_q / 32;
+ reg = 0;
+ reg |= (bitmask << (start_q % 32));
+ IXGBE_WRITE_REG(hw, IXGBE_WQBR_TX(idx), reg);
+ IXGBE_WRITE_REG(hw, IXGBE_WQBR_RX(idx), reg);
+}
+
+/**
+ * ixgbe_mdd_event_X550
+ * @hw: pointer to hardware structure
+ * @vf_bitmap: vf bitmap of malicious vfs
+ *
+ * Handle malicious driver detection event.
+ **/
+void ixgbe_mdd_event_X550(struct ixgbe_hw *hw, u32 *vf_bitmap)
+{
+ u32 wqbr;
+ u32 i, j, reg, q, shift, vf, idx;
+
+ DEBUGFUNC("ixgbe_mdd_event_X550");
+
+ /* figure out pool size for mapping to vf's */
+ reg = IXGBE_READ_REG(hw, IXGBE_MRQC);
+ switch (reg & IXGBE_MRQC_MRQE_MASK) {
+ case IXGBE_MRQC_VMDQRT8TCEN:
+ shift = 3; /* 16 VFs / pools */
+ break;
+ case IXGBE_MRQC_VMDQRSS32EN:
+ case IXGBE_MRQC_VMDQRT4TCEN:
+ shift = 2; /* 32 VFs / pools */
+ break;
+ default:
+ shift = 1; /* 64 VFs / pools */
+ break;
+ }
+
+ /* Read WQBR_TX and WQBR_RX and check for malicious queues */
+ for (i = 0; i < 4; i++) {
+ wqbr = IXGBE_READ_REG(hw, IXGBE_WQBR_TX(i));
+ wqbr |= IXGBE_READ_REG(hw, IXGBE_WQBR_RX(i));
+
+ if (!wqbr)
+ continue;
+
+ /* Get malicious queue */
+ for (j = 0; j < 32 && wqbr; j++) {
+
+ if (!(wqbr & (1 << j)))
+ continue;
+
+ /* Get queue from bitmask */
+ q = j + (i * 32);
+
+ /* Map queue to vf */
+ vf = (q >> shift);
+
+ /* Set vf bit in vf_bitmap */
+ idx = vf / 32;
+ vf_bitmap[idx] |= (1 << (vf % 32));
+ wqbr &= ~(1 << j);
+ }
+ }
+}
+
+/**
+ * ixgbe_get_media_type_X550em - Get media type
+ * @hw: pointer to hardware structure
+ *
+ * Returns the media type (fiber, copper, backplane)
+ */
+enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
+{
+ enum ixgbe_media_type media_type;
+
+ DEBUGFUNC("ixgbe_get_media_type_X550em");
+
+ /* Detect if there is a copper PHY attached. */
+ switch (hw->device_id) {
+ case IXGBE_DEV_ID_X550EM_X_KR:
+ case IXGBE_DEV_ID_X550EM_X_KX4:
+ media_type = ixgbe_media_type_backplane;
+ break;
+ case IXGBE_DEV_ID_X550EM_X_SFP:
+ media_type = ixgbe_media_type_fiber;
+ break;
+ case IXGBE_DEV_ID_X550EM_X_1G_T:
+ case IXGBE_DEV_ID_X550EM_X_10G_T:
+ media_type = ixgbe_media_type_copper;
+ break;
+ default:
+ media_type = ixgbe_media_type_unknown;
+ break;
+ }
+ return media_type;
+}
+
+/**
+ * ixgbe_supported_sfp_modules_X550em - Check if SFP module type is supported
+ * @hw: pointer to hardware structure
+ * @linear: TRUE if SFP module is linear
+ */
+static s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear)
+{
+ DEBUGFUNC("ixgbe_supported_sfp_modules_X550em");
+
+ switch (hw->phy.sfp_type) {
+ case ixgbe_sfp_type_not_present:
+ return IXGBE_ERR_SFP_NOT_PRESENT;
+ case ixgbe_sfp_type_da_cu_core0:
+ case ixgbe_sfp_type_da_cu_core1:
+ *linear = TRUE;
+ break;
+ case ixgbe_sfp_type_srlr_core0:
+ case ixgbe_sfp_type_srlr_core1:
+ case ixgbe_sfp_type_da_act_lmt_core0:
+ case ixgbe_sfp_type_da_act_lmt_core1:
+ case ixgbe_sfp_type_1g_sx_core0:
+ case ixgbe_sfp_type_1g_sx_core1:
+ case ixgbe_sfp_type_1g_lx_core0:
+ case ixgbe_sfp_type_1g_lx_core1:
+ *linear = FALSE;
+ break;
+ case ixgbe_sfp_type_unknown:
+ case ixgbe_sfp_type_1g_cu_core0:
+ case ixgbe_sfp_type_1g_cu_core1:
+ default:
+ return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ }
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_identify_sfp_module_X550em - Identifies SFP modules
+ * @hw: pointer to hardware structure
+ *
+ * Searches for and identifies the SFP module and assigns appropriate PHY type.
+ **/
+s32 ixgbe_identify_sfp_module_X550em(struct ixgbe_hw *hw)
+{
+ s32 status;
+ bool linear;
+
+ DEBUGFUNC("ixgbe_identify_sfp_module_X550em");
+
+ status = ixgbe_identify_module_generic(hw);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Check if SFP module is supported */
+ status = ixgbe_supported_sfp_modules_X550em(hw, &linear);
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_sfp_modules_X550em - Setup MAC link ops
+ * @hw: pointer to hardware structure
+ */
+s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
+{
+ s32 status;
+ bool linear;
+
+ DEBUGFUNC("ixgbe_setup_sfp_modules_X550em");
+
+ /* Check if SFP module is supported */
+ status = ixgbe_supported_sfp_modules_X550em(hw, &linear);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ ixgbe_init_mac_link_ops_X550em(hw);
+ hw->phy.ops.reset = NULL;
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_init_mac_link_ops_X550em - init mac link function pointers
+ * @hw: pointer to hardware structure
+ */
+void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
+{
+ struct ixgbe_mac_info *mac = &hw->mac;
+
+ DEBUGFUNC("ixgbe_init_mac_link_ops_X550em");
+
+ switch (hw->mac.ops.get_media_type(hw)) {
+ case ixgbe_media_type_fiber:
+ /* CS4227 does not support autoneg, so disable the laser control
+ * functions for SFP+ fiber
+ */
+ mac->ops.disable_tx_laser = NULL;
+ mac->ops.enable_tx_laser = NULL;
+ mac->ops.flap_tx_laser = NULL;
+ mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber;
+ mac->ops.setup_mac_link = ixgbe_setup_mac_link_sfp_x550em;
+ mac->ops.set_rate_select_speed =
+ ixgbe_set_soft_rate_select_speed;
+ break;
+ case ixgbe_media_type_copper:
+ mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
+ mac->ops.check_link = ixgbe_check_link_t_X550em;
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * ixgbe_get_link_capabilities_x550em - Determines link capabilities
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: TRUE when autoneg or autotry is enabled
+ */
+s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed *speed,
+ bool *autoneg)
+{
+ DEBUGFUNC("ixgbe_get_link_capabilities_X550em");
+
+ /* SFP */
+ if (hw->phy.media_type == ixgbe_media_type_fiber) {
+
+ /* CS4227 SFP must not enable auto-negotiation */
+ *autoneg = FALSE;
+
+ /* Check if 1G SFP module. */
+ if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1
+ || hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1) {
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ return IXGBE_SUCCESS;
+ }
+
+ /* Link capabilities are based on SFP */
+ if (hw->phy.multispeed_fiber)
+ *speed = IXGBE_LINK_SPEED_10GB_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL;
+ else
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ } else {
+ *speed = IXGBE_LINK_SPEED_10GB_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = TRUE;
+ }
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_get_lasi_ext_t_x550em - Determime external Base T PHY interrupt cause
+ * @hw: pointer to hardware structure
+ * @lsc: pointer to boolean flag which indicates whether external Base T
+ * PHY interrupt is lsc
+ *
+ * Determime if external Base T PHY interrupt cause is high temperature
+ * failure alarm or link status change.
+ *
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
+ * failure alarm, else return PHY access status.
+ */
+static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
+{
+ u32 status;
+ u16 reg;
+
+ *lsc = FALSE;
+
+ /* Vendor alarm triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS ||
+ !(reg & IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN))
+ return status;
+
+ /* Vendor Auto-Neg alarm triggered or Global alarm 1 triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS ||
+ !(reg & (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
+ IXGBE_MDIO_GLOBAL_ALARM_1_INT)))
+ return status;
+
+ /* High temperature failure alarm triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If high temperature failure, then return over temp error and exit */
+ if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
+ /* power down the PHY in case the PHY FW didn't already */
+ ixgbe_set_copper_phy_power(hw, FALSE);
+ return IXGBE_ERR_OVERTEMP;
+ }
+
+ /* Vendor alarm 2 triggered */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
+
+ if (status != IXGBE_SUCCESS ||
+ !(reg & IXGBE_MDIO_GLOBAL_STD_ALM2_INT))
+ return status;
+
+ /* link connect/disconnect event occurred */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Indicate LSC */
+ if (reg & IXGBE_MDIO_AUTO_NEG_VEN_LSC)
+ *lsc = TRUE;
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_enable_lasi_ext_t_x550em - Enable external Base T PHY interrupts
+ * @hw: pointer to hardware structure
+ *
+ * Enable link status change and temperature failure alarm for the external
+ * Base T PHY
+ *
+ * Returns PHY access status
+ */
+static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
+{
+ u32 status;
+ u16 reg;
+ bool lsc;
+
+ /* Clear interrupt flags */
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+
+ /* Enable link status change alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
+
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Enables high temperature failure alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg |= IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN;
+
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Enable vendor Auto-Neg alarm and Global Interrupt Mask 1 alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg |= (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
+ IXGBE_MDIO_GLOBAL_ALARM_1_INT);
+
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Enable chip-wide vendor alarm */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg |= IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN;
+
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_kr_speed_x550em - Configure the KR PHY for link speed.
+ * @hw: pointer to hardware structure
+ * @speed: link speed
+ *
+ * Configures the integrated KR PHY.
+ **/
+static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed)
+{
+ s32 status;
+ u32 reg_val;
+
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status)
+ return status;
+
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
+ reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ |
+ IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC);
+ reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
+ IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
+
+ /* Advertise 10G support. */
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
+
+ /* Advertise 1G support. */
+ if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
+
+ /* Restart auto-negotiation. */
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+
+ return status;
+}
+
+/**
+ * ixgbe_init_phy_ops_X550em - PHY/SFP specific init
+ * @hw: pointer to hardware structure
+ *
+ * Initialize any function pointers that were not able to be
+ * set during init_shared_code because the PHY/SFP type was
+ * not known. Perform the SFP init if necessary.
+ */
+s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
+{
+ struct ixgbe_phy_info *phy = &hw->phy;
+ ixgbe_link_speed speed;
+ s32 ret_val;
+
+ DEBUGFUNC("ixgbe_init_phy_ops_X550em");
+
+ hw->mac.ops.set_lan_id(hw);
+
+ if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) {
+ phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
+ ixgbe_setup_mux_ctl(hw);
+
+ /* Save NW management interface connected on board. This is used
+ * to determine internal PHY mode.
+ */
+ phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
+
+ /* If internal PHY mode is KR, then initialize KR link */
+ if (phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) {
+ speed = IXGBE_LINK_SPEED_10GB_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL;
+ ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
+ }
+
+ phy->ops.identify_sfp = ixgbe_identify_sfp_module_X550em;
+ }
+
+ /* Identify the PHY or SFP module */
+ ret_val = phy->ops.identify(hw);
+ if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ return ret_val;
+
+ /* Setup function pointers based on detected hardware */
+ ixgbe_init_mac_link_ops_X550em(hw);
+ if (phy->sfp_type != ixgbe_sfp_type_unknown)
+ phy->ops.reset = NULL;
+
+ /* Set functions pointers based on phy type */
+ switch (hw->phy.type) {
+ case ixgbe_phy_x550em_kx4:
+ phy->ops.setup_link = ixgbe_setup_kx4_x550em;
+ phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
+ phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
+ break;
+ case ixgbe_phy_x550em_kr:
+ phy->ops.setup_link = ixgbe_setup_kr_x550em;
+ phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
+ phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
+ break;
+ case ixgbe_phy_x550em_ext_t:
+ /* Save NW management interface connected on board. This is used
+ * to determine internal PHY mode
+ */
+ phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
+
+ /* If internal link mode is XFI, then setup iXFI internal link,
+ * else setup KR now.
+ */
+ if (!(phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+ phy->ops.setup_internal_link =
+ ixgbe_setup_internal_phy_t_x550em;
+ } else {
+ speed = IXGBE_LINK_SPEED_10GB_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL;
+ ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
+ }
+
+ phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em;
+ phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
+ phy->ops.reset = ixgbe_reset_phy_t_X550em;
+ break;
+ default:
+ break;
+ }
+ return ret_val;
+}
+
+/**
+ * ixgbe_reset_hw_X550em - Perform hardware reset
+ * @hw: pointer to hardware structure
+ *
+ * Resets the hardware by resetting the transmit and receive units, masks
+ * and clears all interrupts, perform a PHY reset, and perform a link (MAC)
+ * reset.
+ */
+s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
+{
+ ixgbe_link_speed link_speed;
+ s32 status;
+ u32 ctrl = 0;
+ u32 i;
+ u32 hlreg0;
+ bool link_up = FALSE;
+
+ DEBUGFUNC("ixgbe_reset_hw_X550em");
+
+ /* Call adapter stop to disable Tx/Rx and clear interrupts */
+ status = hw->mac.ops.stop_adapter(hw);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* flush pending Tx transactions */
+ ixgbe_clear_tx_pending(hw);
+
+ /* PHY ops must be identified and initialized prior to reset */
+
+ /* Identify PHY and related function pointers */
+ status = hw->phy.ops.init(hw);
+
+ if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ return status;
+
+ /* start the external PHY */
+ if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
+ status = ixgbe_init_ext_t_x550em(hw);
+ if (status)
+ return status;
+ }
+
+ /* Setup SFP module if there is one present. */
+ if (hw->phy.sfp_setup_needed) {
+ status = hw->mac.ops.setup_sfp(hw);
+ hw->phy.sfp_setup_needed = FALSE;
+ }
+
+ if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ return status;
+
+ /* Reset PHY */
+ if (!hw->phy.reset_disable && hw->phy.ops.reset)
+ hw->phy.ops.reset(hw);
+
+mac_reset_top:
+ /* Issue global reset to the MAC. Needs to be SW reset if link is up.
+ * If link reset is used when link is up, it might reset the PHY when
+ * mng is using it. If link is down or the flag to force full link
+ * reset is set, then perform link reset.
+ */
+ ctrl = IXGBE_CTRL_LNK_RST;
+ if (!hw->force_full_reset) {
+ hw->mac.ops.check_link(hw, &link_speed, &link_up, FALSE);
+ if (link_up)
+ ctrl = IXGBE_CTRL_RST;
+ }
+
+ ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* Poll for reset bit to self-clear meaning reset is complete */
+ for (i = 0; i < 10; i++) {
+ usec_delay(1);
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ if (!(ctrl & IXGBE_CTRL_RST_MASK))
+ break;
+ }
+
+ if (ctrl & IXGBE_CTRL_RST_MASK) {
+ status = IXGBE_ERR_RESET_FAILED;
+ DEBUGOUT("Reset polling failed to complete.\n");
+ }
+
+ msec_delay(50);
+
+ /* Double resets are required for recovery from certain error
+ * conditions. Between resets, it is necessary to stall to
+ * allow time for any pending HW events to complete.
+ */
+ if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
+ hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
+ goto mac_reset_top;
+ }
+
+ /* Store the permanent mac address */
+ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
+
+ /* Store MAC address from RAR0, clear receive address registers, and
+ * clear the multicast table. Also reset num_rar_entries to 128,
+ * since we modify this value when programming the SAN MAC address.
+ */
+ hw->mac.num_rar_entries = 128;
+ hw->mac.ops.init_rx_addrs(hw);
+
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
+ /* Config MDIO clock speed. */
+ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ hlreg0 &= ~IXGBE_HLREG0_MDCSPD;
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
+ }
+
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
+ ixgbe_setup_mux_ctl(hw);
+
+ return status;
+}
+
+/**
+ * ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY.
+ * @hw: pointer to hardware structure
+ */
+s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
+{
+ u32 status;
+ u16 reg;
+
+ status = hw->phy.ops.read_reg(hw,
+ IXGBE_MDIO_TX_VENDOR_ALARMS_3,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If PHY FW reset completed bit is set then this is the first
+ * SW instance after a power on so the PHY FW must be un-stalled.
+ */
+ if (reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
+ status = hw->phy.ops.read_reg(hw,
+ IXGBE_MDIO_GLOBAL_RES_PR_10,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg &= ~IXGBE_MDIO_POWER_UP_STALL;
+
+ status = hw->phy.ops.write_reg(hw,
+ IXGBE_MDIO_GLOBAL_RES_PR_10,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_kr_x550em - Configure the KR PHY.
+ * @hw: pointer to hardware structure
+ *
+ * Configures the integrated KR PHY.
+ **/
+s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
+{
+ return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised);
+}
+
+/**
+ * ixgbe_setup_kx4_x550em - Configure the KX4 PHY.
+ * @hw: pointer to hardware structure
+ *
+ * Configures the integrated KX4 PHY.
+ **/
+s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u32 reg_val;
+
+ status = ixgbe_read_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1,
+ IXGBE_SB_IOSF_TARGET_KX4_PCS, &reg_val);
+ if (status)
+ return status;
+
+ reg_val &= ~(IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4 |
+ IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX);
+
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_ENABLE;
+
+ /* Advertise 10G support. */
+ if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4;
+
+ /* Advertise 1G support. */
+ if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX;
+
+ /* Restart auto-negotiation. */
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_RESTART;
+ status = ixgbe_write_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1,
+ IXGBE_SB_IOSF_TARGET_KX4_PCS, reg_val);
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_mac_link_sfp_x550em - Setup internal/external the PHY for SFP
+ * @hw: pointer to hardware structure
+ *
+ * Configure the external PHY and the integrated KR PHY for SFP support.
+ **/
+s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed,
+ bool autoneg_wait_to_complete)
+{
+ s32 ret_val;
+ u16 reg_slice, reg_val;
+ bool setup_linear = FALSE;
+ UNREFERENCED_1PARAMETER(autoneg_wait_to_complete);
+
+ /* Check if SFP module is supported and linear */
+ ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear);
+
+ /* If no SFP module present, then return success. Return success since
+ * there is no reason to configure CS4227 and SFP not present error is
+ * not excepted in the setup MAC link flow.
+ */
+ if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
+ return IXGBE_SUCCESS;
+
+ if (ret_val != IXGBE_SUCCESS)
+ return ret_val;
+
+ /* Configure CS4227 for LINE connection rate then type. */
+ reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB + (hw->bus.lan_id << 12);
+ reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 0 : 0x8000;
+ ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+ reg_val);
+
+ reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (hw->bus.lan_id << 12);
+ if (setup_linear)
+ reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
+ else
+ reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+ ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+ reg_val);
+
+ /* Configure CS4227 for HOST connection rate then type. */
+ reg_slice = IXGBE_CS4227_HOST_SPARE22_MSB + (hw->bus.lan_id << 12);
+ reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 0 : 0x8000;
+ ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+ reg_val);
+
+ reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (hw->bus.lan_id << 12);
+ if (setup_linear)
+ reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
+ else
+ reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+ ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+ reg_val);
+
+ /* If internal link mode is XFI, then setup XFI internal link. */
+ if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE))
+ ret_val = ixgbe_setup_ixfi_x550em(hw, &speed);
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode.
+ * @hw: pointer to hardware structure
+ * @speed: the link speed to force
+ *
+ * Configures the integrated KR PHY to use iXFI mode. Used to connect an
+ * internal and external PHY at a specific speed, without autonegotiation.
+ **/
+static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
+{
+ s32 status;
+ u32 reg_val;
+
+ /* Disable AN and force speed to 10G Serial. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
+ reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
+
+ /* Select forced link speed for internal PHY. */
+ switch (*speed) {
+ case IXGBE_LINK_SPEED_10GB_FULL:
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
+ break;
+ case IXGBE_LINK_SPEED_1GB_FULL:
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
+ break;
+ default:
+ /* Other link speeds are not supported by internal KR PHY. */
+ return IXGBE_ERR_LINK_SETUP;
+ }
+
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Disable training protocol FSM. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Disable Flex from training TXFFE. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
+ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Enable override for coefficients. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_OVRRD_EN;
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN;
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN;
+ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Toggle port SW reset by AN reset. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+
+ return status;
+}
+
+/**
+ * ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status
+ * @hw: address of hardware structure
+ * @link_up: address of boolean to indicate link status
+ *
+ * Returns error code if unable to get link status.
+ */
+static s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
+{
+ u32 ret;
+ u16 autoneg_status;
+
+ *link_up = FALSE;
+
+ /* read this twice back to back to indicate current status */
+ ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+ if (ret != IXGBE_SUCCESS)
+ return ret;
+
+ ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+ if (ret != IXGBE_SUCCESS)
+ return ret;
+
+ *link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_setup_internal_phy_t_x550em - Configure KR PHY to X557 link
+ * @hw: point to hardware structure
+ *
+ * Configures the link between the integrated KR PHY and the external X557 PHY
+ * The driver will call this function when it gets a link status change
+ * interrupt from the X557 PHY. This function configures the link speed
+ * between the PHYs to match the link speed of the BASE-T link.
+ *
+ * A return of a non-zero value indicates an error, and the base driver should
+ * not report link up.
+ */
+s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
+{
+ ixgbe_link_speed force_speed;
+ bool link_up;
+ u32 status;
+ u16 speed;
+
+ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
+ return IXGBE_ERR_CONFIG;
+
+ /* If link is not up, then there is no setup necessary so return */
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ if (!link_up)
+ return IXGBE_SUCCESS;
+
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &speed);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If link is not still up, then no setup is necessary so return */
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ if (!link_up)
+ return IXGBE_SUCCESS;
+
+ /* clear everything but the speed and duplex bits */
+ speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
+
+ switch (speed) {
+ case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL:
+ force_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ break;
+ case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL:
+ force_speed = IXGBE_LINK_SPEED_1GB_FULL;
+ break;
+ default:
+ /* Internal PHY does not support anything else */
+ return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ }
+
+ return ixgbe_setup_ixfi_x550em(hw, &force_speed);
+}
+
+/**
+ * ixgbe_setup_phy_loopback_x550em - Configure the KR PHY for loopback.
+ * @hw: pointer to hardware structure
+ *
+ * Configures the integrated KR PHY to use internal loopback mode.
+ **/
+s32 ixgbe_setup_phy_loopback_x550em(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u32 reg_val;
+
+ /* Disable AN and force speed to 10G Serial. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
+ reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Set near-end loopback clocks. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_32B;
+ reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_KRPCS;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Set loopback enable. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val |= IXGBE_KRM_PMD_DFX_BURNIN_TX_RX_KR_LB_MASK;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Training bypass. */
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (status != IXGBE_SUCCESS)
+ return status;
+ reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_PROTOCOL_BYPASS;
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+
+ return status;
+}
+
+/**
+ * ixgbe_read_ee_hostif_X550 - Read EEPROM word using a host interface command
+ * assuming that the semaphore is already obtained.
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the hostif.
+ **/
+s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 *data)
+{
+ s32 status;
+ struct ixgbe_hic_read_shadow_ram buffer;
+
+ DEBUGFUNC("ixgbe_read_ee_hostif_data_X550");
+ buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
+ buffer.hdr.req.buf_lenh = 0;
+ buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
+ buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+ /* convert offset from words to bytes */
+ buffer.address = IXGBE_CPU_TO_BE32(offset * 2);
+ /* one word */
+ buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16));
+
+ status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
+ sizeof(buffer),
+ IXGBE_HI_COMMAND_TIMEOUT, FALSE);
+
+ if (status)
+ return status;
+
+ *data = (u16)IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG,
+ FW_NVM_DATA_OFFSET);
+
+ return 0;
+}
+
+/**
+ * ixgbe_read_ee_hostif_X550 - Read EEPROM word using a host interface command
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the hostif.
+ **/
+s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 *data)
+{
+ s32 status = IXGBE_SUCCESS;
+
+ DEBUGFUNC("ixgbe_read_ee_hostif_X550");
+
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+ IXGBE_SUCCESS) {
+ status = ixgbe_read_ee_hostif_data_X550(hw, offset, data);
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+ } else {
+ status = IXGBE_ERR_SWFW_SYNC;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_read_ee_hostif_buffer_X550- Read EEPROM word(s) using hostif
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words
+ * @data: word(s) read from the EEPROM
+ *
+ * Reads a 16 bit word(s) from the EEPROM using the hostif.
+ **/
+s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
+ u16 offset, u16 words, u16 *data)
+{
+ struct ixgbe_hic_read_shadow_ram buffer;
+ u32 current_word = 0;
+ u16 words_to_read;
+ s32 status;
+ u32 i;
+
+ DEBUGFUNC("ixgbe_read_ee_hostif_buffer_X550");
+
+ /* Take semaphore for the entire operation. */
+ status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+ if (status) {
+ DEBUGOUT("EEPROM read buffer - semaphore failed\n");
+ return status;
+ }
+ while (words) {
+ if (words > FW_MAX_READ_BUFFER_SIZE / 2)
+ words_to_read = FW_MAX_READ_BUFFER_SIZE / 2;
+ else
+ words_to_read = words;
+
+ buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
+ buffer.hdr.req.buf_lenh = 0;
+ buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
+ buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+ /* convert offset from words to bytes */
+ buffer.address = IXGBE_CPU_TO_BE32((offset + current_word) * 2);
+ buffer.length = IXGBE_CPU_TO_BE16(words_to_read * 2);
+
+ status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
+ sizeof(buffer),
+ IXGBE_HI_COMMAND_TIMEOUT,
+ FALSE);
+
+ if (status) {
+ DEBUGOUT("Host interface command failed\n");
+ goto out;
+ }
+
+ for (i = 0; i < words_to_read; i++) {
+ u32 reg = IXGBE_FLEX_MNG + (FW_NVM_DATA_OFFSET << 2) +
+ 2 * i;
+ u32 value = IXGBE_READ_REG(hw, reg);
+
+ data[current_word] = (u16)(value & 0xffff);
+ current_word++;
+ i++;
+ if (i < words_to_read) {
+ value >>= 16;
+ data[current_word] = (u16)(value & 0xffff);
+ current_word++;
+ }
+ }
+ words -= words_to_read;
+ }
+
+out:
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+ return status;
+}
+
+/**
+ * ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @data: word write to the EEPROM
+ *
+ * Write a 16 bit word to the EEPROM using the hostif.
+ **/
+s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 data)
+{
+ s32 status;
+ struct ixgbe_hic_write_shadow_ram buffer;
+
+ DEBUGFUNC("ixgbe_write_ee_hostif_data_X550");
+
+ buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
+ buffer.hdr.req.buf_lenh = 0;
+ buffer.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
+ buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+ /* one word */
+ buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16));
+ buffer.data = data;
+ buffer.address = IXGBE_CPU_TO_BE32(offset * 2);
+
+ status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
+ sizeof(buffer),
+ IXGBE_HI_COMMAND_TIMEOUT, FALSE);
+
+ return status;
+}
+
+/**
+ * ixgbe_write_ee_hostif_X550 - Write EEPROM word using hostif
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @data: word write to the EEPROM
+ *
+ * Write a 16 bit word to the EEPROM using the hostif.
+ **/
+s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 data)
+{
+ s32 status = IXGBE_SUCCESS;
+
+ DEBUGFUNC("ixgbe_write_ee_hostif_X550");
+
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+ IXGBE_SUCCESS) {
+ status = ixgbe_write_ee_hostif_data_X550(hw, offset, data);
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+ } else {
+ DEBUGOUT("write ee hostif failed to get semaphore");
+ status = IXGBE_ERR_SWFW_SYNC;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_write_ee_hostif_buffer_X550 - Write EEPROM word(s) using hostif
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @words: number of words
+ * @data: word(s) write to the EEPROM
+ *
+ * Write a 16 bit word(s) to the EEPROM using the hostif.
+ **/
+s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
+ u16 offset, u16 words, u16 *data)
+{
+ s32 status = IXGBE_SUCCESS;
+ u32 i = 0;
+
+ DEBUGFUNC("ixgbe_write_ee_hostif_buffer_X550");
+
+ /* Take semaphore for the entire operation. */
+ status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+ if (status != IXGBE_SUCCESS) {
+ DEBUGOUT("EEPROM write buffer - semaphore failed\n");
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ status = ixgbe_write_ee_hostif_data_X550(hw, offset + i,
+ data[i]);
+
+ if (status != IXGBE_SUCCESS) {
+ DEBUGOUT("Eeprom buffered write failed\n");
+ break;
+ }
+ }
+
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+out:
+
+ return status;
+}
+
+/**
+ * ixgbe_checksum_ptr_x550 - Checksum one pointer region
+ * @hw: pointer to hardware structure
+ * @ptr: pointer offset in eeprom
+ * @size: size of section pointed by ptr, if 0 first word will be used as size
+ * @csum: address of checksum to update
+ *
+ * Returns error status for any failure
+ */
+static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr,
+ u16 size, u16 *csum, u16 *buffer,
+ u32 buffer_size)
+{
+ u16 buf[256];
+ s32 status;
+ u16 length, bufsz, i, start;
+ u16 *local_buffer;
+
+ bufsz = sizeof(buf) / sizeof(buf[0]);
+
+ /* Read a chunk at the pointer location */
+ if (!buffer) {
+ status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, bufsz, buf);
+ if (status) {
+ DEBUGOUT("Failed to read EEPROM image\n");
+ return status;
+ }
+ local_buffer = buf;
+ } else {
+ if (buffer_size < ptr)
+ return IXGBE_ERR_PARAM;
+ local_buffer = &buffer[ptr];
+ }
+
+ if (size) {
+ start = 0;
+ length = size;
+ } else {
+ start = 1;
+ length = local_buffer[0];
+
+ /* Skip pointer section if length is invalid. */
+ if (length == 0xFFFF || length == 0 ||
+ (ptr + length) >= hw->eeprom.word_size)
+ return IXGBE_SUCCESS;
+ }
+
+ if (buffer && ((u32)start + (u32)length > buffer_size))
+ return IXGBE_ERR_PARAM;
+
+ for (i = start; length; i++, length--) {
+ if (i == bufsz && !buffer) {
+ ptr += bufsz;
+ i = 0;
+ if (length < bufsz)
+ bufsz = length;
+
+ /* Read a chunk at the pointer location */
+ status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr,
+ bufsz, buf);
+ if (status) {
+ DEBUGOUT("Failed to read EEPROM image\n");
+ return status;
+ }
+ }
+ *csum += local_buffer[i];
+ }
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_calc_checksum_X550 - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ * @buffer: pointer to buffer containing calculated checksum
+ * @buffer_size: size of buffer
+ *
+ * Returns a negative error code on error, or the 16-bit checksum
+ **/
+s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size)
+{
+ u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1];
+ u16 *local_buffer;
+ s32 status;
+ u16 checksum = 0;
+ u16 pointer, i, size;
+
+ DEBUGFUNC("ixgbe_calc_eeprom_checksum_X550");
+
+ hw->eeprom.ops.init_params(hw);
+
+ if (!buffer) {
+ /* Read pointer area */
+ status = ixgbe_read_ee_hostif_buffer_X550(hw, 0,
+ IXGBE_EEPROM_LAST_WORD + 1,
+ eeprom_ptrs);
+ if (status) {
+ DEBUGOUT("Failed to read EEPROM image\n");
+ return status;
+ }
+ local_buffer = eeprom_ptrs;
+ } else {
+ if (buffer_size < IXGBE_EEPROM_LAST_WORD)
+ return IXGBE_ERR_PARAM;
+ local_buffer = buffer;
+ }
+
+ /*
+ * For X550 hardware include 0x0-0x41 in the checksum, skip the
+ * checksum word itself
+ */
+ for (i = 0; i <= IXGBE_EEPROM_LAST_WORD; i++)
+ if (i != IXGBE_EEPROM_CHECKSUM)
+ checksum += local_buffer[i];
+
+ /*
+ * Include all data from pointers 0x3, 0x6-0xE. This excludes the
+ * FW, PHY module, and PCIe Expansion/Option ROM pointers.
+ */
+ for (i = IXGBE_PCIE_ANALOG_PTR_X550; i < IXGBE_FW_PTR; i++) {
+ if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
+ continue;
+
+ pointer = local_buffer[i];
+
+ /* Skip pointer section if the pointer is invalid. */
+ if (pointer == 0xFFFF || pointer == 0 ||
+ pointer >= hw->eeprom.word_size)
+ continue;
+
+ switch (i) {
+ case IXGBE_PCIE_GENERAL_PTR:
+ size = IXGBE_IXGBE_PCIE_GENERAL_SIZE;
+ break;
+ case IXGBE_PCIE_CONFIG0_PTR:
+ case IXGBE_PCIE_CONFIG1_PTR:
+ size = IXGBE_PCIE_CONFIG_SIZE;
+ break;
+ default:
+ size = 0;
+ break;
+ }
+
+ status = ixgbe_checksum_ptr_x550(hw, pointer, size, &checksum,
+ buffer, buffer_size);
+ if (status)
+ return status;
+ }
+
+ checksum = (u16)IXGBE_EEPROM_SUM - checksum;
+
+ return (s32)checksum;
+}
+
+/**
+ * ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ *
+ * Returns a negative error code on error, or the 16-bit checksum
+ **/
+s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
+{
+ return ixgbe_calc_checksum_X550(hw, NULL, 0);
+}
+
+/**
+ * ixgbe_validate_eeprom_checksum_X550 - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum_val: calculated checksum
+ *
+ * Performs checksum calculation and validates the EEPROM checksum. If the
+ * caller does not need checksum_val, the value can be NULL.
+ **/
+s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val)
+{
+ s32 status;
+ u16 checksum;
+ u16 read_checksum = 0;
+
+ DEBUGFUNC("ixgbe_validate_eeprom_checksum_X550");
+
+ /* Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ status = hw->eeprom.ops.read(hw, 0, &checksum);
+ if (status) {
+ DEBUGOUT("EEPROM read failed\n");
+ return status;
+ }
+
+ status = hw->eeprom.ops.calc_checksum(hw);
+ if (status < 0)
+ return status;
+
+ checksum = (u16)(status & 0xffff);
+
+ status = ixgbe_read_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
+ &read_checksum);
+ if (status)
+ return status;
+
+ /* Verify read checksum from EEPROM is the same as
+ * calculated checksum
+ */
+ if (read_checksum != checksum) {
+ status = IXGBE_ERR_EEPROM_CHECKSUM;
+ ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
+ "Invalid EEPROM checksum");
+ }
+
+ /* If the user cares, return the calculated checksum */
+ if (checksum_val)
+ *checksum_val = checksum;
+
+ return status;
+}
+
+/**
+ * ixgbe_update_eeprom_checksum_X550 - Updates the EEPROM checksum and flash
+ * @hw: pointer to hardware structure
+ *
+ * After writing EEPROM to shadow RAM using EEWR register, software calculates
+ * checksum and updates the EEPROM and instructs the hardware to update
+ * the flash.
+ **/
+s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u16 checksum = 0;
+
+ DEBUGFUNC("ixgbe_update_eeprom_checksum_X550");
+
+ /* Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ status = ixgbe_read_ee_hostif_X550(hw, 0, &checksum);
+ if (status) {
+ DEBUGOUT("EEPROM read failed\n");
+ return status;
+ }
+
+ status = ixgbe_calc_eeprom_checksum_X550(hw);
+ if (status < 0)
+ return status;
+
+ checksum = (u16)(status & 0xffff);
+
+ status = ixgbe_write_ee_hostif_X550(hw, IXGBE_EEPROM_CHECKSUM,
+ checksum);
+ if (status)
+ return status;
+
+ status = ixgbe_update_flash_X550(hw);
+
+ return status;
+}
+
+/**
+ * ixgbe_update_flash_X550 - Instruct HW to copy EEPROM to Flash device
+ * @hw: pointer to hardware structure
+ *
+ * Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash.
+ **/
+s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_SUCCESS;
+ union ixgbe_hic_hdr2 buffer;
+
+ DEBUGFUNC("ixgbe_update_flash_X550");
+
+ buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD;
+ buffer.req.buf_lenh = 0;
+ buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN;
+ buffer.req.checksum = FW_DEFAULT_CHECKSUM;
+
+ status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
+ sizeof(buffer),
+ IXGBE_HI_COMMAND_TIMEOUT, FALSE);
+
+ return status;
+}
+
+/**
+ * ixgbe_get_supported_physical_layer_X550em - Returns physical layer type
+ * @hw: pointer to hardware structure
+ *
+ * Determines physical layer capabilities of the current configuration.
+ **/
+u32 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw)
+{
+ u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+ u16 ext_ability = 0;
+
+ DEBUGFUNC("ixgbe_get_supported_physical_layer_X550em");
+
+ hw->phy.ops.identify(hw);
+
+ switch (hw->phy.type) {
+ case ixgbe_phy_x550em_kr:
+ physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR |
+ IXGBE_PHYSICAL_LAYER_1000BASE_KX;
+ break;
+ case ixgbe_phy_x550em_kx4:
+ physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
+ IXGBE_PHYSICAL_LAYER_1000BASE_KX;
+ break;
+ case ixgbe_phy_x550em_ext_t:
+ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &ext_ability);
+ if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY)
+ physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T;
+ if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY)
+ physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T;
+ break;
+ default:
+ break;
+ }
+
+ if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber)
+ physical_layer = ixgbe_get_supported_phy_sfp_layer_generic(hw);
+
+ return physical_layer;
+}
+
+/**
+ * ixgbe_get_bus_info_x550em - Set PCI bus info
+ * @hw: pointer to hardware structure
+ *
+ * Sets bus link width and speed to unknown because X550em is
+ * not a PCI device.
+ **/
+s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw)
+{
+
+ DEBUGFUNC("ixgbe_get_bus_info_x550em");
+
+ hw->bus.width = ixgbe_bus_width_unknown;
+ hw->bus.speed = ixgbe_bus_speed_unknown;
+
+ hw->mac.ops.set_lan_id(hw);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_disable_rx_x550 - Disable RX unit
+ *
+ * Enables the Rx DMA unit for x550
+ **/
+void ixgbe_disable_rx_x550(struct ixgbe_hw *hw)
+{
+ u32 rxctrl, pfdtxgswc;
+ s32 status;
+ struct ixgbe_hic_disable_rxen fw_cmd;
+
+ DEBUGFUNC("ixgbe_enable_rx_dma_x550");
+
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ if (rxctrl & IXGBE_RXCTRL_RXEN) {
+ pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
+ if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
+ pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
+ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
+ hw->mac.set_lben = TRUE;
+ } else {
+ hw->mac.set_lben = FALSE;
+ }
+
+ fw_cmd.hdr.cmd = FW_DISABLE_RXEN_CMD;
+ fw_cmd.hdr.buf_len = FW_DISABLE_RXEN_LEN;
+ fw_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
+ fw_cmd.port_number = (u8)hw->bus.lan_id;
+
+ status = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd,
+ sizeof(struct ixgbe_hic_disable_rxen),
+ IXGBE_HI_COMMAND_TIMEOUT, TRUE);
+
+ /* If we fail - disable RX using register write */
+ if (status) {
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ if (rxctrl & IXGBE_RXCTRL_RXEN) {
+ rxctrl &= ~IXGBE_RXCTRL_RXEN;
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
+ }
+ }
+ }
+}
+
+/**
+ * ixgbe_enter_lplu_x550em - Transition to low power states
+ * @hw: pointer to hardware structure
+ *
+ * Configures Low Power Link Up on transition to low power states
+ * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
+ * X557 PHY immediately prior to entering LPLU.
+ **/
+s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw)
+{
+ u16 an_10g_cntl_reg, autoneg_reg, speed;
+ s32 status;
+ ixgbe_link_speed lcd_speed;
+ u32 save_autoneg;
+ bool link_up;
+
+ /* If blocked by MNG FW, then don't restart AN */
+ if (ixgbe_check_reset_blocked(hw))
+ return IXGBE_SUCCESS;
+
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ status = ixgbe_read_eeprom(hw, NVM_INIT_CTRL_3, &hw->eeprom.ctrl_word_3);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If link is down, LPLU disabled in NVM, WoL disabled, or manageability
+ * disabled, then force link down by entering low power mode.
+ */
+ if (!link_up || !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) ||
+ !(hw->wol_enabled || ixgbe_mng_present(hw)))
+ return ixgbe_set_copper_phy_power(hw, FALSE);
+
+ /* Determine LCD */
+ status = ixgbe_get_lcd_t_x550em(hw, &lcd_speed);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If no valid LCD link speed, then force link down and exit. */
+ if (lcd_speed == IXGBE_LINK_SPEED_UNKNOWN)
+ return ixgbe_set_copper_phy_power(hw, FALSE);
+
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &speed);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If no link now, speed is invalid so take link down */
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
+ if (status != IXGBE_SUCCESS)
+ return ixgbe_set_copper_phy_power(hw, FALSE);
+
+ /* clear everything but the speed bits */
+ speed &= IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK;
+
+ /* If current speed is already LCD, then exit. */
+ if (((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB) &&
+ (lcd_speed == IXGBE_LINK_SPEED_1GB_FULL)) ||
+ ((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB) &&
+ (lcd_speed == IXGBE_LINK_SPEED_10GB_FULL)))
+ return status;
+
+ /* Clear AN completed indication */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ status = hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &an_10g_cntl_reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ status = hw->phy.ops.read_reg(hw,
+ IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ save_autoneg = hw->phy.autoneg_advertised;
+
+ /* Setup link at least common link speed */
+ status = hw->mac.ops.setup_link(hw, lcd_speed, FALSE);
+
+ /* restore autoneg from before setting lplu speed */
+ hw->phy.autoneg_advertised = save_autoneg;
+
+ return status;
+}
+
+/**
+ * ixgbe_get_lcd_x550em - Determine lowest common denominator
+ * @hw: pointer to hardware structure
+ * @lcd_speed: pointer to lowest common link speed
+ *
+ * Determine lowest common link speed with link partner.
+ **/
+s32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed)
+{
+ u16 an_lp_status;
+ s32 status;
+ u16 word = hw->eeprom.ctrl_word_3;
+
+ *lcd_speed = IXGBE_LINK_SPEED_UNKNOWN;
+
+ status = hw->phy.ops.read_reg(hw, IXGBE_AUTO_NEG_LP_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &an_lp_status);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If link partner advertised 1G, return 1G */
+ if (an_lp_status & IXGBE_AUTO_NEG_LP_1000BASE_CAP) {
+ *lcd_speed = IXGBE_LINK_SPEED_1GB_FULL;
+ return status;
+ }
+
+ /* If 10G disabled for LPLU via NVM D10GMP, then return no valid LCD */
+ if ((hw->bus.lan_id && (word & NVM_INIT_CTRL_3_D10GMP_PORT1)) ||
+ (word & NVM_INIT_CTRL_3_D10GMP_PORT0))
+ return status;
+
+ /* Link partner not capable of lower speeds, return 10G */
+ *lcd_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ return status;
+}
+
+/**
+ * ixgbe_setup_fc_X550em - Set up flow control
+ * @hw: pointer to hardware structure
+ *
+ * Called at init time to set up flow control.
+ **/
+s32 ixgbe_setup_fc_X550em(struct ixgbe_hw *hw)
+{
+ s32 ret_val = IXGBE_SUCCESS;
+ u32 pause, asm_dir, reg_val;
+
+ DEBUGFUNC("ixgbe_setup_fc_X550em");
+
+ /* Validate the requested mode */
+ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
+ ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
+ "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
+ ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
+ goto out;
+ }
+
+ /* 10gig parts do not have a word in the EEPROM to determine the
+ * default flow control setting, so we explicitly set it to full.
+ */
+ if (hw->fc.requested_mode == ixgbe_fc_default)
+ hw->fc.requested_mode = ixgbe_fc_full;
+
+ /* Determine PAUSE and ASM_DIR bits. */
+ switch (hw->fc.requested_mode) {
+ case ixgbe_fc_none:
+ pause = 0;
+ asm_dir = 0;
+ break;
+ case ixgbe_fc_tx_pause:
+ pause = 0;
+ asm_dir = 1;
+ break;
+ case ixgbe_fc_rx_pause:
+ /* Rx Flow control is enabled and Tx Flow control is
+ * disabled by software override. Since there really
+ * isn't a way to advertise that we are capable of RX
+ * Pause ONLY, we will advertise that we support both
+ * symmetric and asymmetric Rx PAUSE, as such we fall
+ * through to the fc_full statement. Later, we will
+ * disable the adapter's ability to send PAUSE frames.
+ */
+ case ixgbe_fc_full:
+ pause = 1;
+ asm_dir = 1;
+ break;
+ default:
+ ERROR_REPORT1(IXGBE_ERROR_ARGUMENT,
+ "Flow control param set incorrectly\n");
+ ret_val = IXGBE_ERR_CONFIG;
+ goto out;
+ }
+
+ if (hw->phy.media_type == ixgbe_media_type_backplane) {
+ ret_val = ixgbe_read_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, &reg_val);
+ if (ret_val != IXGBE_SUCCESS)
+ goto out;
+ reg_val &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE |
+ IXGBE_KRM_AN_CNTL_1_ASM_PAUSE);
+ if (pause)
+ reg_val |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE;
+ if (asm_dir)
+ reg_val |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE;
+ ret_val = ixgbe_write_iosf_sb_reg_x550(hw,
+ IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id),
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+
+ /* Not all devices fully support AN. */
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR)
+ hw->fc.disable_fc_autoneg = TRUE;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * ixgbe_set_mux - Set mux for port 1 access with CS4227
+ * @hw: pointer to hardware structure
+ * @state: set mux if 1, clear if 0
+ */
+static void ixgbe_set_mux(struct ixgbe_hw *hw, u8 state)
+{
+ u32 esdp;
+
+ if (!hw->bus.lan_id)
+ return;
+ esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+ if (state)
+ esdp |= IXGBE_ESDP_SDP1;
+ else
+ esdp &= ~IXGBE_ESDP_SDP1;
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+ IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
+ * ixgbe_acquire_swfw_sync_X550em - Acquire SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify which semaphore to acquire
+ *
+ * Acquires the SWFW semaphore and sets the I2C MUX
+ **/
+s32 ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask)
+{
+ s32 status;
+
+ DEBUGFUNC("ixgbe_acquire_swfw_sync_X550em");
+
+ status = ixgbe_acquire_swfw_sync_X540(hw, mask);
+ if (status)
+ return status;
+
+ if (mask & IXGBE_GSSR_I2C_MASK)
+ ixgbe_set_mux(hw, 1);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_release_swfw_sync_X550em - Release SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify which semaphore to release
+ *
+ * Releases the SWFW semaphore and sets the I2C MUX
+ **/
+void ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask)
+{
+ DEBUGFUNC("ixgbe_release_swfw_sync_X550em");
+
+ if (mask & IXGBE_GSSR_I2C_MASK)
+ ixgbe_set_mux(hw, 0);
+
+ ixgbe_release_swfw_sync_X540(hw, mask);
+}
+
+/**
+ * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
+ * @hw: pointer to hardware structure
+ *
+ * Handle external Base T PHY interrupt. If high temperature
+ * failure alarm then return error, else if link status change
+ * then setup internal/external PHY link
+ *
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
+ * failure alarm, else return PHY access status.
+ */
+s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
+{
+ bool lsc;
+ u32 status;
+
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ if (lsc)
+ return ixgbe_setup_internal_phy(hw);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg_wait_to_complete: TRUE when waiting for completion is needed
+ *
+ * Setup internal/external PHY link speed based on link speed, then set
+ * external PHY auto advertised link speed.
+ *
+ * Returns error status for any failure
+ **/
+s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed,
+ bool autoneg_wait_to_complete)
+{
+ s32 status;
+ ixgbe_link_speed force_speed;
+
+ DEBUGFUNC("ixgbe_setup_mac_link_t_X550em");
+
+ /* Setup internal/external PHY link speed to iXFI (10G), unless
+ * only 1G is auto advertised then setup KX link.
+ */
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+ force_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ else
+ force_speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+ /* If internal link mode is XFI, then setup XFI internal link. */
+ if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+ status = ixgbe_setup_ixfi_x550em(hw, &force_speed);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+ }
+
+ return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete);
+}
+
+/**
+ * ixgbe_check_link_t_X550em - Determine link and speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: TRUE when link is up
+ * @link_up_wait_to_complete: bool used to wait for link up or not
+ *
+ * Check that both the MAC and X557 external PHY have link.
+ **/
+s32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+ bool *link_up, bool link_up_wait_to_complete)
+{
+ u32 status;
+ u16 autoneg_status;
+
+ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
+ return IXGBE_ERR_CONFIG;
+
+ status = ixgbe_check_mac_link_generic(hw, speed, link_up,
+ link_up_wait_to_complete);
+
+ /* If check link fails or MAC link is not up, then return */
+ if (status != IXGBE_SUCCESS || !(*link_up))
+ return status;
+
+ /* MAC link is up, so check external PHY link.
+ * Read this twice back to back to indicate current status.
+ */
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If external PHY link is not up, then indicate link not up */
+ if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
+ *link_up = FALSE;
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_reset_phy_t_X550em - Performs X557 PHY reset and enables LASI
+ * @hw: pointer to hardware structure
+ **/
+s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw)
+{
+ s32 status;
+
+ status = ixgbe_reset_phy_generic(hw);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Configure Link Status Alarm and Temperature Threshold interrupts */
+ return ixgbe_enable_lasi_ext_t_x550em(hw);
+}
+
+/**
+ * ixgbe_led_on_t_X550em - Turns on the software controllable LEDs.
+ * @hw: pointer to hardware structure
+ * @led_idx: led number to turn on
+ **/
+s32 ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, u32 led_idx)
+{
+ u16 phy_data;
+
+ DEBUGFUNC("ixgbe_led_on_t_X550em");
+
+ if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
+ return IXGBE_ERR_PARAM;
+
+ /* To turn on the LED, set mode to ON. */
+ ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data);
+ phy_data |= IXGBE_X557_LED_MANUAL_SET_MASK;
+ ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data);
+
+ return IXGBE_SUCCESS;
+}
+
+/**
+ * ixgbe_led_off_t_X550em - Turns off the software controllable LEDs.
+ * @hw: pointer to hardware structure
+ * @led_idx: led number to turn off
+ **/
+s32 ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, u32 led_idx)
+{
+ u16 phy_data;
+
+ DEBUGFUNC("ixgbe_led_off_t_X550em");
+
+ if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
+ return IXGBE_ERR_PARAM;
+
+ /* To turn on the LED, set mode to ON. */
+ ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data);
+ phy_data &= ~IXGBE_X557_LED_MANUAL_SET_MASK;
+ ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data);
+
+ return IXGBE_SUCCESS;
+}
+
diff --git a/sys/dev/ixgbe/ixgbe_x550.h b/sys/dev/ixgbe/ixgbe_x550.h
new file mode 100644
index 0000000..8a544ec
--- /dev/null
+++ b/sys/dev/ixgbe/ixgbe_x550.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+
+ Copyright (c) 2001-2015, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+/*$FreeBSD$*/
+
+#ifndef _IXGBE_X550_H_
+#define _IXGBE_X550_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbe_dmac_config_X550(struct ixgbe_hw *hw);
+s32 ixgbe_dmac_config_tcs_X550(struct ixgbe_hw *hw);
+s32 ixgbe_dmac_update_tcs_X550(struct ixgbe_hw *hw);
+
+s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw);
+s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw);
+s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw);
+s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size);
+s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val);
+s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw);
+s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
+ u16 offset, u16 words, u16 *data);
+s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 data);
+s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
+ u16 offset, u16 words, u16 *data);
+s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset,
+u16 *data);
+s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 *data);
+s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 data);
+s32 ixgbe_set_eee_X550(struct ixgbe_hw *hw, bool enable_eee);
+s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee);
+void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable,
+ unsigned int pool);
+void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw,
+ bool enable, int vf);
+s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u32 data);
+s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u32 *data);
+void ixgbe_disable_mdd_X550(struct ixgbe_hw *hw);
+void ixgbe_enable_mdd_X550(struct ixgbe_hw *hw);
+void ixgbe_mdd_event_X550(struct ixgbe_hw *hw, u32 *vf_bitmap);
+void ixgbe_restore_mdd_vf_X550(struct ixgbe_hw *hw, u32 vf);
+enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed *speed, bool *autoneg);
+void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw);
+s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw);
+s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw);
+s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw);
+s32 ixgbe_setup_phy_loopback_x550em(struct ixgbe_hw *hw);
+u32 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw);
+void ixgbe_disable_rx_x550(struct ixgbe_hw *hw);
+s32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed);
+s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw);
+s32 ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask);
+void ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask);
+s32 ixgbe_setup_fc_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed,
+ bool autoneg_wait_to_complete);
+s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw);
+s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed,
+ bool autoneg_wait_to_complete);
+s32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+ bool *link_up, bool link_up_wait_to_complete);
+s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_identify_sfp_module_X550em(struct ixgbe_hw *hw);
+s32 ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, u32 led_idx);
+s32 ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, u32 led_idx);
+#endif /* _IXGBE_X550_H_ */
diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h
index df8f04f..1ddfbca3 100644
--- a/sys/dev/ixl/ixl.h
+++ b/sys/dev/ixl/ixl.h
@@ -324,7 +324,7 @@
#define IXL_SET_IMCASTS(vsi, count) (vsi)->imcasts = (count)
#define IXL_SET_OMCASTS(vsi, count) (vsi)->omcasts = (count)
#define IXL_SET_IQDROPS(vsi, count) (vsi)->iqdrops = (count)
-#define IXL_SET_OQDROPS(vsi, count) (vsi)->iqdrops = (count)
+#define IXL_SET_OQDROPS(vsi, count) (vsi)->oqdrops = (count)
#define IXL_SET_NOPROTO(vsi, count) (vsi)->noproto = (count)
#else
#define IXL_SET_IPACKETS(vsi, count) (vsi)->ifp->if_ipackets = (count)
diff --git a/sys/dev/mii/acphy.c b/sys/dev/mii/acphy.c
index edb5221..6eb58ce 100644
--- a/sys/dev/mii/acphy.c
+++ b/sys/dev/mii/acphy.c
@@ -139,14 +139,12 @@ acphy_attach(device_t dev)
sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
device_printf(dev, " ");
-#define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL)
+#define ADD(m) ifmedia_add(&sc->mii_pdata->mii_media, (m), 0, NULL)
if ((PHY_READ(sc, MII_ACPHY_MCTL) & AC_MCTL_FX_SEL) != 0) {
sc->mii_flags |= MIIF_HAVEFIBER;
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst),
- MII_MEDIA_100_TX);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst));
printf("100baseFX, ");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst),
- MII_MEDIA_100_TX_FDX);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst));
printf("100baseFX-FDX, ");
}
#undef ADD
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c
index 54beed4..32914a3 100644
--- a/sys/dev/mii/brgphy.c
+++ b/sys/dev/mii/brgphy.c
@@ -160,25 +160,33 @@ static const struct mii_phy_funcs brgphy_funcs = {
brgphy_reset
};
-#define HS21_PRODUCT_ID "IBM eServer BladeCenter HS21"
-#define HS21_BCM_CHIPID 0x57081021
+static const struct hs21_type {
+ const uint32_t id;
+ const char *prod;
+} hs21_type_lists[] = {
+ { 0x57081021, "IBM eServer BladeCenter HS21" },
+ { 0x57081011, "IBM eServer BladeCenter HS21 -[8853PAU]-" },
+};
static int
detect_hs21(struct bce_softc *bce_sc)
{
char *sysenv;
- int found;
+ int found, i;
found = 0;
- if (bce_sc->bce_chipid == HS21_BCM_CHIPID) {
- sysenv = kern_getenv("smbios.system.product");
- if (sysenv != NULL) {
- if (strncmp(sysenv, HS21_PRODUCT_ID,
- strlen(HS21_PRODUCT_ID)) == 0)
- found = 1;
- freeenv(sysenv);
+ sysenv = kern_getenv("smbios.system.product");
+ if (sysenv == NULL)
+ return (found);
+ for (i = 0; i < nitems(hs21_type_lists); i++) {
+ if (bce_sc->bce_chipid == hs21_type_lists[i].id &&
+ strncmp(sysenv, hs21_type_lists[i].prod,
+ strlen(hs21_type_lists[i].prod)) == 0) {
+ found++;
+ break;
}
}
+ freeenv(sysenv);
return (found);
}
@@ -266,20 +274,25 @@ brgphy_attach(device_t dev)
sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
device_printf(dev, " ");
-#define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL)
-
/* Add the supported media types */
if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
mii_phy_add_media(sc);
printf("\n");
} else {
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
- BRGPHY_S1000 | BRGPHY_BMCR_FDX);
+ ifmedia_add(&sc->mii_pdata->mii_media,
+ IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
+ 0, NULL);
printf("1000baseSX-FDX, ");
- /* 2.5G support is a software enabled feature on the 5708S and 5709S. */
- if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) {
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0);
+ /*
+ * 2.5G support is a software enabled feature
+ * on the 5708S and 5709S.
+ */
+ if (bce_sc && (bce_sc->bce_phy_flags &
+ BCE_PHY_2_5G_CAPABLE_FLAG)) {
+ ifmedia_add(&sc->mii_pdata->mii_media,
+ IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX,
+ sc->mii_inst), 0, NULL);
printf("2500baseSX-FDX, ");
} else if ((bsc->serdes_flags & BRGPHY_5708S) && bce_sc &&
(detect_hs21(bce_sc) != 0)) {
@@ -295,11 +308,11 @@ brgphy_attach(device_t dev)
printf("auto-neg workaround, ");
bsc->serdes_flags |= BRGPHY_NOANWAIT;
}
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+ ifmedia_add(&sc->mii_pdata->mii_media, IFM_MAKEWORD(IFM_ETHER,
+ IFM_AUTO, 0, sc->mii_inst), 0, NULL);
printf("auto\n");
}
-#undef ADD
MIIBUS_MEDIAINIT(sc->mii_dev);
return (0);
}
diff --git a/sys/dev/mii/lxtphy.c b/sys/dev/mii/lxtphy.c
index d673f2c..a796b11 100644
--- a/sys/dev/mii/lxtphy.c
+++ b/sys/dev/mii/lxtphy.c
@@ -142,12 +142,10 @@ lxtphy_attach(device_t dev)
sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
device_printf(dev, " ");
-#define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL)
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst),
- MII_MEDIA_100_TX);
+#define ADD(m) ifmedia_add(&sc->mii_pdata->mii_media, (m), 0, NULL)
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst));
printf("100baseFX, ");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst),
- MII_MEDIA_100_TX_FDX);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst));
printf("100baseFX-FDX, ");
#undef ADD
diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c
index 43e7a10..84f4f44 100644
--- a/sys/dev/mii/mii_physubr.c
+++ b/sys/dev/mii/mii_physubr.c
@@ -54,9 +54,28 @@ __FBSDID("$FreeBSD$");
#include "miibus_if.h"
/*
- * Media to register setting conversion table. Order matters.
+ *
+ * An array of structures to map MII media types to BMCR/ANAR settings.
*/
-static const struct mii_media mii_media_table[MII_NMEDIA] = {
+enum {
+ MII_MEDIA_NONE = 0,
+ MII_MEDIA_10_T,
+ MII_MEDIA_10_T_FDX,
+ MII_MEDIA_100_T4,
+ MII_MEDIA_100_TX,
+ MII_MEDIA_100_TX_FDX,
+ MII_MEDIA_1000_X,
+ MII_MEDIA_1000_X_FDX,
+ MII_MEDIA_1000_T,
+ MII_MEDIA_1000_T_FDX,
+ MII_NMEDIA,
+};
+
+static const struct mii_media {
+ u_int mm_bmcr; /* BMCR settings for this media */
+ u_int mm_anar; /* ANAR settings for this media */
+ u_int mm_gtcr; /* 100base-T2 or 1000base-T CR */
+} mii_media_table[MII_NMEDIA] = {
/* None */
{ BMCR_ISO, ANAR_CSMA,
0, },
@@ -104,8 +123,10 @@ mii_phy_setmedia(struct mii_softc *sc)
struct mii_data *mii = sc->mii_pdata;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmcr, anar, gtcr;
+ int index = -1;
- if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
/*
* Force renegotiation if MIIF_DOPAUSE or MIIF_FORCEANEG.
* The former is necessary as we might switch from flow-
@@ -115,19 +136,78 @@ mii_phy_setmedia(struct mii_softc *sc)
(sc->mii_flags & (MIIF_DOPAUSE | MIIF_FORCEANEG)) != 0)
(void)mii_phy_auto(sc);
return;
- }
- /*
- * Table index is stored in the media entry.
- */
+ case IFM_NONE:
+ index = MII_MEDIA_NONE;
+ break;
+
+ case IFM_HPNA_1:
+ index = MII_MEDIA_10_T;
+ break;
+
+ case IFM_10_T:
+ switch (IFM_OPTIONS(ife->ifm_media)) {
+ case 0:
+ index = MII_MEDIA_10_T;
+ break;
+ case IFM_FDX:
+ case (IFM_FDX | IFM_FLOW):
+ index = MII_MEDIA_10_T_FDX;
+ break;
+ };
+ break;
+
+ case IFM_100_TX:
+ case IFM_100_FX:
+ switch (IFM_OPTIONS(ife->ifm_media)) {
+ case 0:
+ index = MII_MEDIA_100_TX;
+ break;
+ case IFM_FDX:
+ case (IFM_FDX | IFM_FLOW):
+ index = MII_MEDIA_100_TX_FDX;
+ break;
+ }
+ break;
+
+ case IFM_100_T4:
+ index = MII_MEDIA_100_T4;
+ break;
+
+ case IFM_1000_SX:
+ switch (IFM_OPTIONS(ife->ifm_media)) {
+ case 0:
+ index = MII_MEDIA_1000_X;
+ break;
+ case IFM_FDX:
+ case (IFM_FDX | IFM_FLOW):
+ index = MII_MEDIA_1000_X_FDX;
+ break;
+ }
+ break;
+
+ case IFM_1000_T:
+ switch (IFM_OPTIONS(ife->ifm_media)) {
+ case 0:
+ case IFM_ETH_MASTER:
+ index = MII_MEDIA_1000_T;
+ break;
+ case IFM_FDX:
+ case (IFM_FDX | IFM_ETH_MASTER):
+ case (IFM_FDX | IFM_FLOW):
+ case (IFM_FDX | IFM_FLOW | IFM_ETH_MASTER):
+ index = MII_MEDIA_1000_T_FDX;
+ break;
+ }
+ break;
+ }
- KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
- ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
- ife->ifm_data));
+ KASSERT(index != -1, ("%s: failed to map media word %d",
+ __func__, ife->ifm_media));
- anar = mii_media_table[ife->ifm_data].mm_anar;
- bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
- gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
+ anar = mii_media_table[index].mm_anar;
+ bmcr = mii_media_table[index].mm_bmcr;
+ gtcr = mii_media_table[index].mm_gtcr;
if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
gtcr |= GTCR_MAN_MS;
@@ -318,12 +398,11 @@ mii_phy_add_media(struct mii_softc *sc)
*/
sc->mii_anegticks = MII_ANEGTICKS;
-#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define ADD(m) ifmedia_add(&mii->mii_media, (m), 0, NULL)
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
if ((sc->mii_flags & MIIF_NOISOLATE) == 0) {
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
- MII_MEDIA_NONE);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst));
PRINT("none");
}
@@ -335,51 +414,44 @@ mii_phy_add_media(struct mii_softc *sc)
if ((sc->mii_flags & MIIF_IS_HPNA) != 0) {
if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
- sc->mii_inst), MII_MEDIA_10_T);
+ sc->mii_inst));
PRINT("HomePNA1");
}
return;
}
if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
- MII_MEDIA_10_T);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst));
PRINT("10baseT");
}
if ((sc->mii_capabilities & BMSR_10TFDX) != 0) {
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
- MII_MEDIA_10_T_FDX);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst));
PRINT("10baseT-FDX");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T,
- IFM_FDX | IFM_FLOW, sc->mii_inst),
- MII_MEDIA_10_T_FDX);
+ IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("10baseT-FDX-flow");
}
fdx = 1;
}
if ((sc->mii_capabilities & BMSR_100TXHDX) != 0) {
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
- MII_MEDIA_100_TX);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst));
PRINT("100baseTX");
}
if ((sc->mii_capabilities & BMSR_100TXFDX) != 0) {
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
- MII_MEDIA_100_TX_FDX);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst));
PRINT("100baseTX-FDX");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX,
- IFM_FDX | IFM_FLOW, sc->mii_inst),
- MII_MEDIA_100_TX_FDX);
+ IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("100baseTX-FDX-flow");
}
fdx = 1;
}
if ((sc->mii_capabilities & BMSR_100T4) != 0) {
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
- MII_MEDIA_100_T4);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst));
PRINT("100baseT4");
}
@@ -392,20 +464,19 @@ mii_phy_add_media(struct mii_softc *sc)
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_IS_1000X;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
- sc->mii_inst), MII_MEDIA_1000_X);
+ sc->mii_inst));
PRINT("1000baseSX");
}
if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0) {
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_IS_1000X;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
- sc->mii_inst), MII_MEDIA_1000_X_FDX);
+ sc->mii_inst));
PRINT("1000baseSX-FDX");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX,
- IFM_FDX | IFM_FLOW, sc->mii_inst),
- MII_MEDIA_1000_X_FDX);
+ IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("1000baseSX-FDX-flow");
}
fdx = 1;
@@ -421,31 +492,29 @@ mii_phy_add_media(struct mii_softc *sc)
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_HAVE_GTCR;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
- sc->mii_inst), MII_MEDIA_1000_T);
+ sc->mii_inst));
PRINT("1000baseT");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
- IFM_ETH_MASTER, sc->mii_inst), MII_MEDIA_1000_T);
+ IFM_ETH_MASTER, sc->mii_inst));
PRINT("1000baseT-master");
}
if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) {
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_HAVE_GTCR;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
- sc->mii_inst), MII_MEDIA_1000_T_FDX);
+ sc->mii_inst));
PRINT("1000baseT-FDX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
- IFM_FDX | IFM_ETH_MASTER, sc->mii_inst),
- MII_MEDIA_1000_T_FDX);
+ IFM_FDX | IFM_ETH_MASTER, sc->mii_inst));
PRINT("1000baseT-FDX-master");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
- IFM_FDX | IFM_FLOW, sc->mii_inst),
- MII_MEDIA_1000_T_FDX);
+ IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("1000baseT-FDX-flow");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
IFM_FDX | IFM_FLOW | IFM_ETH_MASTER,
- sc->mii_inst), MII_MEDIA_1000_T_FDX);
+ sc->mii_inst));
PRINT("1000baseT-FDX-flow-master");
}
fdx = 1;
@@ -454,12 +523,11 @@ mii_phy_add_media(struct mii_softc *sc)
if ((sc->mii_capabilities & BMSR_ANEG) != 0) {
/* intentionally invalid index */
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
- MII_NMEDIA);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst));
PRINT("auto");
if (fdx != 0 && (sc->mii_flags & MIIF_DOPAUSE) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FLOW,
- sc->mii_inst), MII_NMEDIA);
+ sc->mii_inst));
PRINT("auto-flow");
}
}
diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h
index bc2a91c..498e720 100644
--- a/sys/dev/mii/miivar.h
+++ b/sys/dev/mii/miivar.h
@@ -180,27 +180,6 @@ struct mii_phydesc {
MII_STR_ ## a ## _ ## b }
#define MII_PHY_END { 0, 0, NULL }
-/*
- * An array of these structures map MII media types to BMCR/ANAR settings.
- */
-struct mii_media {
- u_int mm_bmcr; /* BMCR settings for this media */
- u_int mm_anar; /* ANAR settings for this media */
- u_int mm_gtcr; /* 100base-T2 or 1000base-T CR */
-};
-
-#define MII_MEDIA_NONE 0
-#define MII_MEDIA_10_T 1
-#define MII_MEDIA_10_T_FDX 2
-#define MII_MEDIA_100_T4 3
-#define MII_MEDIA_100_TX 4
-#define MII_MEDIA_100_TX_FDX 5
-#define MII_MEDIA_1000_X 6
-#define MII_MEDIA_1000_X_FDX 7
-#define MII_MEDIA_1000_T 8
-#define MII_MEDIA_1000_T_FDX 9
-#define MII_NMEDIA 10
-
#ifdef _KERNEL
#define PHY_READ(p, r) \
diff --git a/sys/dev/mii/mlphy.c b/sys/dev/mii/mlphy.c
index fbb3481..89b4f2c 100644
--- a/sys/dev/mii/mlphy.c
+++ b/sys/dev/mii/mlphy.c
@@ -220,29 +220,11 @@ mlphy_service(xsc, mii, cmd)
msc->ml_linked = 0;
return (0);
case IFM_10_T:
- /*
- * For 10baseT modes, reset and program the
- * companion PHY (of any), then program ourselves
- * to match. This will put us in pass-through
- * mode and let the companion PHY do all the
- * work.
- *
- * BMCR data is stored in the ifmedia entry.
- */
- if (other != NULL) {
- PHY_RESET(other);
- PHY_WRITE(other, MII_BMCR, ife->ifm_data);
- }
- mii_phy_setmedia(sc);
- msc->ml_state = 0;
- break;
case IFM_100_TX:
/*
- * For 100baseTX modes, reset and isolate the
- * companion PHY (if any), then program ourselves
+ * For 10baseT and 100baseTX modes, reset and isolate
+ * the companion PHY (if any), then program ourselves
* accordingly.
- *
- * BMCR data is stored in the ifmedia entry.
*/
if (other != NULL) {
PHY_RESET(other);
diff --git a/sys/dev/mii/xmphy.c b/sys/dev/mii/xmphy.c
index 2e2fff9..8c35aa5 100644
--- a/sys/dev/mii/xmphy.c
+++ b/sys/dev/mii/xmphy.c
@@ -116,16 +116,15 @@ xmphy_attach(device_t dev)
PHY_RESET(sc);
-#define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL)
+#define ADD(m) ifmedia_add(&sc->mii_pdata->mii_media, (m), 0, NULL)
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
device_printf(dev, " ");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst),
- XMPHY_BMCR_FDX);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst));
PRINT("1000baseSX");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst));
PRINT("1000baseSX-FDX");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst));
PRINT("auto");
printf("\n");
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index fe8c08a..983caa3 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/taskqueue.h>
+#include <sys/zlib.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -58,7 +59,6 @@ __FBSDID("$FreeBSD$");
#include <net/if_types.h>
#include <net/if_vlan_var.h>
-#include <net/zlib.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5401df3..11229cc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2710,11 +2710,17 @@ netmap_attach(struct netmap_adapter *arg)
}
#endif /* linux */
+#ifdef __FreeBSD__
+ if_printf(ifp, "netmap queues/slots: TX %d/%d, RX %d/%d\n",
+ hwna->up.num_tx_rings, hwna->up.num_tx_desc,
+ hwna->up.num_rx_rings, hwna->up.num_rx_desc);
+#else
D("success for %s tx %d/%d rx %d/%d queues/slots",
hwna->up.name,
hwna->up.num_tx_rings, hwna->up.num_tx_desc,
hwna->up.num_rx_rings, hwna->up.num_rx_desc
);
+#endif
return 0;
fail:
diff --git a/sys/dev/nvme/nvme.c b/sys/dev/nvme/nvme.c
index 464d851..329c5e5 100644
--- a/sys/dev/nvme/nvme.c
+++ b/sys/dev/nvme/nvme.c
@@ -81,27 +81,54 @@ MODULE_VERSION(nvme, 1);
static struct _pcsid
{
- u_int32_t type;
- const char *desc;
+ uint32_t devid;
+ int match_subdevice;
+ uint16_t subdevice;
+ const char *desc;
} pci_ids[] = {
- { 0x01118086, "NVMe Controller" },
- { CHATHAM_PCI_ID, "Chatham Prototype NVMe Controller" },
- { IDT32_PCI_ID, "IDT NVMe Controller (32 channel)" },
- { IDT8_PCI_ID, "IDT NVMe Controller (8 channel)" },
- { 0x00000000, NULL }
+ { 0x01118086, 0, 0, "NVMe Controller" },
+ { IDT32_PCI_ID, 0, 0, "IDT NVMe Controller (32 channel)" },
+ { IDT8_PCI_ID, 0, 0, "IDT NVMe Controller (8 channel)" },
+ { 0x09538086, 1, 0x3702, "DC P3700 SSD" },
+ { 0x09538086, 1, 0x3703, "DC P3700 SSD [2.5\" SFF]" },
+ { 0x09538086, 1, 0x3704, "DC P3500 SSD [Add-in Card]" },
+ { 0x09538086, 1, 0x3705, "DC P3500 SSD [2.5\" SFF]" },
+ { 0x09538086, 1, 0x3709, "DC P3600 SSD [Add-in Card]" },
+ { 0x09538086, 1, 0x370a, "DC P3600 SSD [2.5\" SFF]" },
+ { 0x00000000, 0, 0, NULL }
};
static int
+nvme_match(uint32_t devid, uint16_t subdevice, struct _pcsid *ep)
+{
+ if (devid != ep->devid)
+ return 0;
+
+ if (!ep->match_subdevice)
+ return 1;
+
+ if (subdevice == ep->subdevice)
+ return 1;
+ else
+ return 0;
+}
+
+static int
nvme_probe (device_t device)
{
struct _pcsid *ep;
- u_int32_t type;
+ uint32_t devid;
+ uint16_t subdevice;
- type = pci_get_devid(device);
+ devid = pci_get_devid(device);
+ subdevice = pci_get_subdevice(device);
ep = pci_ids;
- while (ep->type && ep->type != type)
+ while (ep->devid) {
+ if (nvme_match(devid, subdevice, ep))
+ break;
++ep;
+ }
if (ep->desc) {
device_set_desc(device, ep->desc);
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index cf3b3b2..00dc92a 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -49,11 +49,7 @@ static int
nvme_ctrlr_allocate_bar(struct nvme_controller *ctrlr)
{
- /* Chatham puts the NVMe MMRs behind BAR 2/3, not BAR 0/1. */
- if (pci_get_devid(ctrlr->dev) == CHATHAM_PCI_ID)
- ctrlr->resource_id = PCIR_BAR(2);
- else
- ctrlr->resource_id = PCIR_BAR(0);
+ ctrlr->resource_id = PCIR_BAR(0);
ctrlr->resource = bus_alloc_resource(ctrlr->dev, SYS_RES_MEMORY,
&ctrlr->resource_id, 0, ~0, 1, RF_ACTIVE);
@@ -81,117 +77,6 @@ nvme_ctrlr_allocate_bar(struct nvme_controller *ctrlr)
return (0);
}
-#ifdef CHATHAM2
-static int
-nvme_ctrlr_allocate_chatham_bar(struct nvme_controller *ctrlr)
-{
-
- ctrlr->chatham_resource_id = PCIR_BAR(CHATHAM_CONTROL_BAR);
- ctrlr->chatham_resource = bus_alloc_resource(ctrlr->dev,
- SYS_RES_MEMORY, &ctrlr->chatham_resource_id, 0, ~0, 1,
- RF_ACTIVE);
-
- if(ctrlr->chatham_resource == NULL) {
- nvme_printf(ctrlr, "unable to alloc pci resource\n");
- return (ENOMEM);
- }
-
- ctrlr->chatham_bus_tag = rman_get_bustag(ctrlr->chatham_resource);
- ctrlr->chatham_bus_handle =
- rman_get_bushandle(ctrlr->chatham_resource);
-
- return (0);
-}
-
-static void
-nvme_ctrlr_setup_chatham(struct nvme_controller *ctrlr)
-{
- uint64_t reg1, reg2, reg3;
- uint64_t temp1, temp2;
- uint32_t temp3;
- uint32_t use_flash_timings = 0;
-
- DELAY(10000);
-
- temp3 = chatham_read_4(ctrlr, 0x8080);
-
- device_printf(ctrlr->dev, "Chatham version: 0x%x\n", temp3);
-
- ctrlr->chatham_lbas = chatham_read_4(ctrlr, 0x8068) - 0x110;
- ctrlr->chatham_size = ctrlr->chatham_lbas * 512;
-
- device_printf(ctrlr->dev, "Chatham size: %jd\n",
- (intmax_t)ctrlr->chatham_size);
-
- reg1 = reg2 = reg3 = ctrlr->chatham_size - 1;
-
- TUNABLE_INT_FETCH("hw.nvme.use_flash_timings", &use_flash_timings);
- if (use_flash_timings) {
- device_printf(ctrlr->dev, "Chatham: using flash timings\n");
- temp1 = 0x00001b58000007d0LL;
- temp2 = 0x000000cb00000131LL;
- } else {
- device_printf(ctrlr->dev, "Chatham: using DDR timings\n");
- temp1 = temp2 = 0x0LL;
- }
-
- chatham_write_8(ctrlr, 0x8000, reg1);
- chatham_write_8(ctrlr, 0x8008, reg2);
- chatham_write_8(ctrlr, 0x8010, reg3);
-
- chatham_write_8(ctrlr, 0x8020, temp1);
- temp3 = chatham_read_4(ctrlr, 0x8020);
-
- chatham_write_8(ctrlr, 0x8028, temp2);
- temp3 = chatham_read_4(ctrlr, 0x8028);
-
- chatham_write_8(ctrlr, 0x8030, temp1);
- chatham_write_8(ctrlr, 0x8038, temp2);
- chatham_write_8(ctrlr, 0x8040, temp1);
- chatham_write_8(ctrlr, 0x8048, temp2);
- chatham_write_8(ctrlr, 0x8050, temp1);
- chatham_write_8(ctrlr, 0x8058, temp2);
-
- DELAY(10000);
-}
-
-static void
-nvme_chatham_populate_cdata(struct nvme_controller *ctrlr)
-{
- struct nvme_controller_data *cdata;
-
- cdata = &ctrlr->cdata;
-
- cdata->vid = 0x8086;
- cdata->ssvid = 0x2011;
-
- /*
- * Chatham2 puts garbage data in these fields when we
- * invoke IDENTIFY_CONTROLLER, so we need to re-zero
- * the fields before calling bcopy().
- */
- memset(cdata->sn, 0, sizeof(cdata->sn));
- memcpy(cdata->sn, "2012", strlen("2012"));
- memset(cdata->mn, 0, sizeof(cdata->mn));
- memcpy(cdata->mn, "CHATHAM2", strlen("CHATHAM2"));
- memset(cdata->fr, 0, sizeof(cdata->fr));
- memcpy(cdata->fr, "0", strlen("0"));
- cdata->rab = 8;
- cdata->aerl = 3;
- cdata->lpa.ns_smart = 1;
- cdata->sqes.min = 6;
- cdata->sqes.max = 6;
- cdata->cqes.min = 4;
- cdata->cqes.max = 4;
- cdata->nn = 1;
-
- /* Chatham2 doesn't support DSM command */
- cdata->oncs.dsm = 0;
-
- cdata->vwc.present = 1;
-}
-#endif /* CHATHAM2 */
-
static void
nvme_ctrlr_construct_admin_qpair(struct nvme_controller *ctrlr)
{
@@ -461,11 +346,6 @@ nvme_ctrlr_identify(struct nvme_controller *ctrlr)
return (ENXIO);
}
-#ifdef CHATHAM2
- if (pci_get_devid(ctrlr->dev) == CHATHAM_PCI_ID)
- nvme_chatham_populate_cdata(ctrlr);
-#endif
-
/*
* Use MDTS to ensure our default max_xfer_size doesn't exceed what the
* controller supports.
@@ -779,10 +659,6 @@ nvme_ctrlr_configure_aer(struct nvme_controller *ctrlr)
/* aerl is a zero-based value, so we need to add 1 here. */
ctrlr->num_aers = min(NVME_MAX_ASYNC_EVENTS, (ctrlr->cdata.aerl+1));
- /* Chatham doesn't support AERs. */
- if (pci_get_devid(ctrlr->dev) == CHATHAM_PCI_ID)
- ctrlr->num_aers = 0;
-
for (i = 0; i < ctrlr->num_aers; i++) {
aer = &ctrlr->aer[i];
nvme_ctrlr_construct_and_submit_aer(ctrlr, aer);
@@ -1034,27 +910,6 @@ nvme_ctrlr_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
break;
case NVME_PASSTHROUGH_CMD:
pt = (struct nvme_pt_command *)arg;
-#ifdef CHATHAM2
- /*
- * Chatham IDENTIFY data is spoofed, so copy the spoofed data
- * rather than issuing the command to the Chatham controller.
- */
- if (pci_get_devid(ctrlr->dev) == CHATHAM_PCI_ID &&
- pt->cmd.opc == NVME_OPC_IDENTIFY) {
- if (pt->cmd.cdw10 == 1) {
- if (pt->len != sizeof(ctrlr->cdata))
- return (EINVAL);
- return (copyout(&ctrlr->cdata, pt->buf,
- pt->len));
- } else {
- if (pt->len != sizeof(ctrlr->ns[0].data) ||
- pt->cmd.nsid != 1)
- return (EINVAL);
- return (copyout(&ctrlr->ns[0].data, pt->buf,
- pt->len));
- }
- }
-#endif
return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, pt->cmd.nsid,
1 /* is_user_buffer */, 1 /* is_admin_cmd */));
default:
@@ -1087,15 +942,6 @@ nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev)
if (status != 0)
return (status);
-#ifdef CHATHAM2
- if (pci_get_devid(dev) == CHATHAM_PCI_ID) {
- status = nvme_ctrlr_allocate_chatham_bar(ctrlr);
- if (status != 0)
- return (status);
- nvme_ctrlr_setup_chatham(ctrlr);
- }
-#endif
-
/*
* Software emulators may set the doorbell stride to something
* other than zero, but this driver is not set up to handle that.
@@ -1144,9 +990,17 @@ nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev)
/* One vector per IO queue, plus one vector for admin queue. */
num_vectors = ctrlr->num_io_queues + 1;
- if (pci_msix_count(dev) < num_vectors) {
+ /*
+ * If we cannot even allocate 2 vectors (one for admin, one for
+ * I/O), then revert to INTx.
+ */
+ if (pci_msix_count(dev) < 2) {
ctrlr->msix_enabled = 0;
goto intx;
+ } else if (pci_msix_count(dev) < num_vectors) {
+ ctrlr->per_cpu_io_queues = FALSE;
+ ctrlr->num_io_queues = 1;
+ num_vectors = 2; /* one for admin, one for I/O */
}
if (pci_alloc_msix(dev, &num_vectors) != 0) {
@@ -1236,14 +1090,8 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
* during shutdown). This ensures the controller receives a
* shutdown notification in case the system is shutdown before
* reloading the driver.
- *
- * Chatham does not let you re-enable the controller after shutdown
- * notification has been received, so do not send it in this case.
- * This is OK because Chatham does not depend on the shutdown
- * notification anyways.
*/
- if (pci_get_devid(ctrlr->dev) != CHATHAM_PCI_ID)
- nvme_ctrlr_shutdown(ctrlr);
+ nvme_ctrlr_shutdown(ctrlr);
nvme_ctrlr_disable(ctrlr);
taskqueue_free(ctrlr->taskqueue);
@@ -1272,13 +1120,6 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
ctrlr->bar4_resource_id, ctrlr->bar4_resource);
}
-#ifdef CHATHAM2
- if (ctrlr->chatham_resource != NULL) {
- bus_release_resource(dev, SYS_RES_MEMORY,
- ctrlr->chatham_resource_id, ctrlr->chatham_resource);
- }
-#endif
-
if (ctrlr->tag)
bus_teardown_intr(ctrlr->dev, ctrlr->res, ctrlr->tag);
diff --git a/sys/dev/nvme/nvme_ns.c b/sys/dev/nvme/nvme_ns.c
index ed2214d..84a1980 100644
--- a/sys/dev/nvme/nvme_ns.c
+++ b/sys/dev/nvme/nvme_ns.c
@@ -465,28 +465,6 @@ nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp,
return (err);
}
-#ifdef CHATHAM2
-static void
-nvme_ns_populate_chatham_data(struct nvme_namespace *ns)
-{
- struct nvme_controller *ctrlr;
- struct nvme_namespace_data *nsdata;
-
- ctrlr = ns->ctrlr;
- nsdata = &ns->data;
-
- nsdata->nsze = ctrlr->chatham_lbas;
- nsdata->ncap = ctrlr->chatham_lbas;
- nsdata->nuse = ctrlr->chatham_lbas;
-
- /* Chatham2 doesn't support thin provisioning. */
- nsdata->nsfeat.thin_prov = 0;
-
- /* Set LBA size to 512 bytes. */
- nsdata->lbaf[0].lbads = 9;
-}
-#endif /* CHATHAM2 */
-
int
nvme_ns_construct(struct nvme_namespace *ns, uint16_t id,
struct nvme_controller *ctrlr)
@@ -513,23 +491,15 @@ nvme_ns_construct(struct nvme_namespace *ns, uint16_t id,
if (!mtx_initialized(&ns->lock))
mtx_init(&ns->lock, "nvme ns lock", NULL, MTX_DEF);
-#ifdef CHATHAM2
- if (pci_get_devid(ctrlr->dev) == CHATHAM_PCI_ID)
- nvme_ns_populate_chatham_data(ns);
- else {
-#endif
- status.done = FALSE;
- nvme_ctrlr_cmd_identify_namespace(ctrlr, id, &ns->data,
- nvme_completion_poll_cb, &status);
- while (status.done == FALSE)
- DELAY(5);
- if (nvme_completion_is_error(&status.cpl)) {
- nvme_printf(ctrlr, "nvme_identify_namespace failed\n");
- return (ENXIO);
- }
-#ifdef CHATHAM2
+ status.done = FALSE;
+ nvme_ctrlr_cmd_identify_namespace(ctrlr, id, &ns->data,
+ nvme_completion_poll_cb, &status);
+ while (status.done == FALSE)
+ DELAY(5);
+ if (nvme_completion_is_error(&status.cpl)) {
+ nvme_printf(ctrlr, "nvme_identify_namespace failed\n");
+ return (ENXIO);
}
-#endif
/*
* Note: format is a 0-based value, so > is appropriate here,
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index fa9cb80..6137b41 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -50,13 +50,6 @@
MALLOC_DECLARE(M_NVME);
-#define CHATHAM2
-
-#ifdef CHATHAM2
-#define CHATHAM_PCI_ID 0x20118086
-#define CHATHAM_CONTROL_BAR 0
-#endif
-
#define IDT32_PCI_ID 0x80d0111d /* 32 channel board */
#define IDT8_PCI_ID 0x80d2111d /* 8 channel board */
@@ -211,6 +204,7 @@ struct nvme_qpair {
struct nvme_completion *cpl;
bus_dma_tag_t dma_tag;
+ bus_dma_tag_t dma_tag_payload;
bus_dmamap_t cmd_dma_map;
uint64_t cmd_bus_addr;
@@ -266,13 +260,6 @@ struct nvme_controller {
int bar4_resource_id;
struct resource *bar4_resource;
-#ifdef CHATHAM2
- bus_space_tag_t chatham_bus_tag;
- bus_space_handle_t chatham_bus_handle;
- int chatham_resource_id;
- struct resource *chatham_resource;
-#endif
-
uint32_t msix_enabled;
uint32_t force_intx;
uint32_t enable_aborts;
@@ -338,11 +325,6 @@ struct nvme_controller {
boolean_t is_failed;
STAILQ_HEAD(, nvme_request) fail_req;
-
-#ifdef CHATHAM2
- uint64_t chatham_size;
- uint64_t chatham_lbas;
-#endif
};
#define nvme_mmio_offsetof(reg) \
@@ -365,22 +347,6 @@ struct nvme_controller {
(val & 0xFFFFFFFF00000000UL) >> 32); \
} while (0);
-#ifdef CHATHAM2
-#define chatham_read_4(softc, reg) \
- bus_space_read_4((softc)->chatham_bus_tag, \
- (softc)->chatham_bus_handle, reg)
-
-#define chatham_write_8(sc, reg, val) \
- do { \
- bus_space_write_4((sc)->chatham_bus_tag, \
- (sc)->chatham_bus_handle, reg, val & 0xffffffff); \
- bus_space_write_4((sc)->chatham_bus_tag, \
- (sc)->chatham_bus_handle, reg+4, \
- (val & 0xFFFFFFFF00000000UL) >> 32); \
- } while (0);
-
-#endif /* CHATHAM2 */
-
#if __FreeBSD_version < 800054
#define wmb() __asm volatile("sfence" ::: "memory")
#define mb() __asm volatile("mfence" ::: "memory")
@@ -491,6 +457,8 @@ nvme_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
{
uint64_t *bus_addr = (uint64_t *)arg;
+ if (error != 0)
+ printf("nvme_single_map err %d\n", error);
*bus_addr = seg[0].ds_addr;
}
diff --git a/sys/dev/nvme/nvme_qpair.c b/sys/dev/nvme/nvme_qpair.c
index e54adf7..d0cb8c6 100644
--- a/sys/dev/nvme/nvme_qpair.c
+++ b/sys/dev/nvme/nvme_qpair.c
@@ -294,7 +294,7 @@ nvme_qpair_construct_tracker(struct nvme_qpair *qpair, struct nvme_tracker *tr,
uint16_t cid)
{
- bus_dmamap_create(qpair->dma_tag, 0, &tr->payload_dma_map);
+ bus_dmamap_create(qpair->dma_tag_payload, 0, &tr->payload_dma_map);
bus_dmamap_create(qpair->dma_tag, 0, &tr->prp_dma_map);
bus_dmamap_load(qpair->dma_tag, tr->prp_dma_map, tr->prp,
@@ -337,7 +337,7 @@ nvme_qpair_complete_tracker(struct nvme_qpair *qpair, struct nvme_tracker *tr,
nvme_qpair_submit_tracker(qpair, tr);
} else {
if (req->type != NVME_REQUEST_NULL)
- bus_dmamap_unload(qpair->dma_tag,
+ bus_dmamap_unload(qpair->dma_tag_payload,
tr->payload_dma_map);
nvme_free_request(req);
@@ -464,19 +464,11 @@ nvme_qpair_construct(struct nvme_qpair *qpair, uint32_t id,
{
struct nvme_tracker *tr;
uint32_t i;
+ int err;
qpair->id = id;
qpair->vector = vector;
qpair->num_entries = num_entries;
-#ifdef CHATHAM2
- /*
- * Chatham prototype board starts having issues at higher queue
- * depths. So use a conservative estimate here of no more than 64
- * outstanding I/O per queue at any one point.
- */
- if (pci_get_devid(ctrlr->dev) == CHATHAM_PCI_ID)
- num_trackers = min(num_trackers, 64);
-#endif
qpair->num_trackers = num_trackers;
qpair->ctrlr = ctrlr;
@@ -497,11 +489,20 @@ nvme_qpair_construct(struct nvme_qpair *qpair, uint32_t id,
mtx_init(&qpair->lock, "nvme qpair lock", NULL, MTX_DEF);
/* Note: NVMe PRP format is restricted to 4-byte alignment. */
- bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev),
+ err = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev),
4, PAGE_SIZE, BUS_SPACE_MAXADDR,
BUS_SPACE_MAXADDR, NULL, NULL, NVME_MAX_XFER_SIZE,
(NVME_MAX_XFER_SIZE/PAGE_SIZE)+1, PAGE_SIZE, 0,
+ NULL, NULL, &qpair->dma_tag_payload);
+ if (err != 0)
+ nvme_printf(ctrlr, "payload tag create failed %d\n", err);
+
+ err = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev),
+ 4, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE, 1, BUS_SPACE_MAXSIZE, 0,
NULL, NULL, &qpair->dma_tag);
+ if (err != 0)
+ nvme_printf(ctrlr, "tag create failed %d\n", err);
qpair->num_cmds = 0;
qpair->num_intr_handler_calls = 0;
@@ -513,8 +514,13 @@ nvme_qpair_construct(struct nvme_qpair *qpair, uint32_t id,
sizeof(struct nvme_completion), M_NVME, M_ZERO,
0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
- bus_dmamap_create(qpair->dma_tag, 0, &qpair->cmd_dma_map);
- bus_dmamap_create(qpair->dma_tag, 0, &qpair->cpl_dma_map);
+ err = bus_dmamap_create(qpair->dma_tag, 0, &qpair->cmd_dma_map);
+ if (err != 0)
+ nvme_printf(ctrlr, "cmd_dma_map create failed %d\n", err);
+
+ err = bus_dmamap_create(qpair->dma_tag, 0, &qpair->cpl_dma_map);
+ if (err != 0)
+ nvme_printf(ctrlr, "cpl_dma_map create failed %d\n", err);
bus_dmamap_load(qpair->dma_tag, qpair->cmd_dma_map,
qpair->cmd, qpair->num_entries * sizeof(struct nvme_command),
@@ -570,6 +576,9 @@ nvme_qpair_destroy(struct nvme_qpair *qpair)
if (qpair->dma_tag)
bus_dma_tag_destroy(qpair->dma_tag);
+ if (qpair->dma_tag_payload)
+ bus_dma_tag_destroy(qpair->dma_tag_payload);
+
if (qpair->act_tr)
free(qpair->act_tr, M_NVME);
@@ -707,8 +716,11 @@ nvme_payload_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
* is responsible for detecting the error status and failing the
* tracker manually.
*/
- if (error != 0)
+ if (error != 0) {
+ nvme_printf(tr->qpair->ctrlr,
+ "nvme_payload_map err %d\n", error);
return;
+ }
/*
* Note that we specified PAGE_SIZE for alignment and max
@@ -728,6 +740,13 @@ nvme_payload_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
(uint64_t)seg[cur_nseg].ds_addr;
cur_nseg++;
}
+ } else {
+ /*
+ * prp2 should not be used by the controller
+ * since there is only one segment, but set
+ * to 0 just to be safe.
+ */
+ tr->req->cmd.prp2 = 0;
}
nvme_qpair_submit_tracker(tr->qpair, tr);
@@ -780,8 +799,9 @@ _nvme_qpair_submit_request(struct nvme_qpair *qpair, struct nvme_request *req)
KASSERT(req->payload_size <= qpair->ctrlr->max_xfer_size,
("payload_size (%d) exceeds max_xfer_size (%d)\n",
req->payload_size, qpair->ctrlr->max_xfer_size));
- err = bus_dmamap_load(tr->qpair->dma_tag, tr->payload_dma_map,
- req->u.payload, req->payload_size, nvme_payload_map, tr, 0);
+ err = bus_dmamap_load(tr->qpair->dma_tag_payload,
+ tr->payload_dma_map, req->u.payload, req->payload_size,
+ nvme_payload_map, tr, 0);
if (err != 0)
nvme_printf(qpair->ctrlr,
"bus_dmamap_load returned 0x%x!\n", err);
@@ -795,7 +815,7 @@ _nvme_qpair_submit_request(struct nvme_qpair *qpair, struct nvme_request *req)
("bio->bio_bcount (%jd) exceeds max_xfer_size (%d)\n",
(intmax_t)req->u.bio->bio_bcount,
qpair->ctrlr->max_xfer_size));
- err = bus_dmamap_load_bio(tr->qpair->dma_tag,
+ err = bus_dmamap_load_bio(tr->qpair->dma_tag_payload,
tr->payload_dma_map, req->u.bio, nvme_payload_map, tr, 0);
if (err != 0)
nvme_printf(qpair->ctrlr,
diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c
index d4f1baa..7dca418 100644
--- a/sys/dev/pccbb/pccbb_pci.c
+++ b/sys/dev/pccbb/pccbb_pci.c
@@ -259,32 +259,6 @@ cbb_pci_probe(device_t brdev)
}
/*
- * Still need this because the pci code only does power for type 0
- * header devices.
- */
-static void
-cbb_powerstate_d0(device_t dev)
-{
- u_int32_t membase, irq;
-
- if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
- /* Save important PCI config data. */
- membase = pci_read_config(dev, CBBR_SOCKBASE, 4);
- irq = pci_read_config(dev, PCIR_INTLINE, 4);
-
- /* Reset the power state. */
- device_printf(dev, "chip is in D%d power mode "
- "-- setting to D0\n", pci_get_powerstate(dev));
-
- pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-
- /* Restore PCI config data. */
- pci_write_config(dev, CBBR_SOCKBASE, membase, 4);
- pci_write_config(dev, PCIR_INTLINE, irq, 4);
- }
-}
-
-/*
* Print out the config space
*/
static void
@@ -321,15 +295,15 @@ cbb_pci_attach(device_t brdev)
sc->cbdev = NULL;
sc->exca[0].pccarddev = NULL;
sc->domain = pci_get_domain(brdev);
- sc->bus.sec = pci_read_config(brdev, PCIR_SECBUS_2, 1);
- sc->bus.sub = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
sc->pribus = pcib_get_bus(parent);
#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1);
pcib_setup_secbus(brdev, &sc->bus, 1);
+#else
+ sc->bus.sec = pci_read_config(brdev, PCIR_SECBUS_2, 1);
+ sc->bus.sub = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
#endif
SLIST_INIT(&sc->rl);
- cbb_powerstate_d0(brdev);
rid = CBBR_SOCKBASE;
sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid,
@@ -467,18 +441,13 @@ cbb_chipinit(struct cbb_softc *sc)
uint32_t mux, sysctrl, reg;
/* Set CardBus latency timer */
- if (pci_read_config(sc->dev, PCIR_SECLAT_1, 1) < 0x20)
- pci_write_config(sc->dev, PCIR_SECLAT_1, 0x20, 1);
+ if (pci_read_config(sc->dev, PCIR_SECLAT_2, 1) < 0x20)
+ pci_write_config(sc->dev, PCIR_SECLAT_2, 0x20, 1);
/* Set PCI latency timer */
if (pci_read_config(sc->dev, PCIR_LATTIMER, 1) < 0x20)
pci_write_config(sc->dev, PCIR_LATTIMER, 0x20, 1);
- /* Restore bus configuration */
- pci_write_config(sc->dev, PCIR_PRIBUS_2, sc->pribus, 1);
- pci_write_config(sc->dev, PCIR_SECBUS_2, sc->bus.sec, 1);
- pci_write_config(sc->dev, PCIR_SUBBUS_2, sc->bus.sub, 1);
-
/* Enable DMA, memory access for this card and I/O acces for children */
pci_enable_busmaster(sc->dev);
pci_enable_io(sc->dev, SYS_RES_IOPORT);
@@ -906,15 +875,10 @@ cbb_pci_resume(device_t brdev)
* from D0 and back to D0 cause the bridge to lose its config space, so
* all the bus mappings and such are preserved.
*
- * For most drivers, the PCI layer handles this saving. However, since
- * there's much black magic and arcane art hidden in these few lines of
- * code that would be difficult to transition into the PCI
- * layer. chipinit was several years of trial and error to write.
+ * The PCI layer handles standard PCI registers like the
+ * command register and BARs, but cbb-specific registers are
+ * handled here.
*/
- pci_write_config(brdev, CBBR_SOCKBASE, rman_get_start(sc->base_res), 4);
- DEVPRINTF((brdev, "PCI Memory allocated: %08lx\n",
- rman_get_start(sc->base_res)));
-
sc->chipinit(sc);
/* reset interrupt -- Do we really need to do this? */
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 3fab486..b4c6151 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -583,12 +583,24 @@ pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
case PCIM_HDRTYPE_NORMAL:
cfg->subvendor = REG(PCIR_SUBVEND_0, 2);
cfg->subdevice = REG(PCIR_SUBDEV_0, 2);
+ cfg->mingnt = REG(PCIR_MINGNT, 1);
+ cfg->maxlat = REG(PCIR_MAXLAT, 1);
cfg->nummaps = PCI_MAXMAPS_0;
break;
case PCIM_HDRTYPE_BRIDGE:
+ cfg->bridge.br_seclat = REG(PCIR_SECLAT_1, 1);
+ cfg->bridge.br_subbus = REG(PCIR_SUBBUS_1, 1);
+ cfg->bridge.br_secbus = REG(PCIR_SECBUS_1, 1);
+ cfg->bridge.br_pribus = REG(PCIR_PRIBUS_1, 1);
+ cfg->bridge.br_control = REG(PCIR_BRIDGECTL_1, 2);
cfg->nummaps = PCI_MAXMAPS_1;
break;
case PCIM_HDRTYPE_CARDBUS:
+ cfg->bridge.br_seclat = REG(PCIR_SECLAT_2, 1);
+ cfg->bridge.br_subbus = REG(PCIR_SUBBUS_2, 1);
+ cfg->bridge.br_secbus = REG(PCIR_SECBUS_2, 1);
+ cfg->bridge.br_pribus = REG(PCIR_PRIBUS_2, 1);
+ cfg->bridge.br_control = REG(PCIR_BRIDGECTL_2, 2);
cfg->subvendor = REG(PCIR_SUBVEND_2, 2);
cfg->subdevice = REG(PCIR_SUBDEV_2, 2);
cfg->nummaps = PCI_MAXMAPS_2;
@@ -641,9 +653,6 @@ pci_fill_devinfo(device_t pcib, int d, int b, int s, int f, uint16_t vid,
cfg->intpin = REG(PCIR_INTPIN, 1);
cfg->intline = REG(PCIR_INTLINE, 1);
- cfg->mingnt = REG(PCIR_MINGNT, 1);
- cfg->maxlat = REG(PCIR_MAXLAT, 1);
-
cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0;
cfg->hdrtype &= ~PCIM_MFDEV;
STAILQ_INIT(&cfg->maps);
@@ -4425,9 +4434,17 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
*result = cfg->cachelnsz;
break;
case PCI_IVAR_MINGNT:
+ if (cfg->hdrtype != PCIM_HDRTYPE_NORMAL) {
+ *result = -1;
+ return (EINVAL);
+ }
*result = cfg->mingnt;
break;
case PCI_IVAR_MAXLAT:
+ if (cfg->hdrtype != PCIM_HDRTYPE_NORMAL) {
+ *result = -1;
+ return (EINVAL);
+ }
*result = cfg->maxlat;
break;
case PCI_IVAR_LATTIMER:
@@ -5125,16 +5142,6 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
{
/*
- * Only do header type 0 devices. Type 1 devices are bridges,
- * which we know need special treatment. Type 2 devices are
- * cardbus bridges which also require special treatment.
- * Other types are unknown, and we err on the side of safety
- * by ignoring them.
- */
- if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) != PCIM_HDRTYPE_NORMAL)
- return;
-
- /*
* Restore the device to full power mode. We must do this
* before we restore the registers because moving from D3 to
* D0 will cause the chip's BARs and some other registers to
@@ -5144,16 +5151,44 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
*/
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0)
pci_set_powerstate(dev, PCI_POWERSTATE_D0);
- pci_restore_bars(dev);
pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2);
pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1);
pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1);
- pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1);
- pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1);
pci_write_config(dev, PCIR_CACHELNSZ, dinfo->cfg.cachelnsz, 1);
pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1);
pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1);
pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1);
+ switch (dinfo->cfg.hdrtype & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_NORMAL:
+ pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1);
+ pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1);
+ break;
+ case PCIM_HDRTYPE_BRIDGE:
+ pci_write_config(dev, PCIR_SECLAT_1,
+ dinfo->cfg.bridge.br_seclat, 1);
+ pci_write_config(dev, PCIR_SUBBUS_1,
+ dinfo->cfg.bridge.br_subbus, 1);
+ pci_write_config(dev, PCIR_SECBUS_1,
+ dinfo->cfg.bridge.br_secbus, 1);
+ pci_write_config(dev, PCIR_PRIBUS_1,
+ dinfo->cfg.bridge.br_pribus, 1);
+ pci_write_config(dev, PCIR_BRIDGECTL_1,
+ dinfo->cfg.bridge.br_control, 2);
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ pci_write_config(dev, PCIR_SECLAT_2,
+ dinfo->cfg.bridge.br_seclat, 1);
+ pci_write_config(dev, PCIR_SUBBUS_2,
+ dinfo->cfg.bridge.br_subbus, 1);
+ pci_write_config(dev, PCIR_SECBUS_2,
+ dinfo->cfg.bridge.br_secbus, 1);
+ pci_write_config(dev, PCIR_PRIBUS_2,
+ dinfo->cfg.bridge.br_pribus, 1);
+ pci_write_config(dev, PCIR_BRIDGECTL_2,
+ dinfo->cfg.bridge.br_control, 2);
+ break;
+ }
+ pci_restore_bars(dev);
/*
* Restore extended capabilities for PCI-Express and PCI-X
@@ -5222,40 +5257,57 @@ pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
int ps;
/*
- * Only do header type 0 devices. Type 1 devices are bridges, which
- * we know need special treatment. Type 2 devices are cardbus bridges
- * which also require special treatment. Other types are unknown, and
- * we err on the side of safety by ignoring them. Powering down
- * bridges should not be undertaken lightly.
- */
- if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) != PCIM_HDRTYPE_NORMAL)
- return;
-
- /*
* Some drivers apparently write to these registers w/o updating our
* cached copy. No harm happens if we update the copy, so do so here
* so we can restore them. The COMMAND register is modified by the
* bus w/o updating the cache. This should represent the normally
- * writable portion of the 'defined' part of type 0 headers. In
- * theory we also need to save/restore the PCI capability structures
- * we know about, but apart from power we don't know any that are
- * writable.
+ * writable portion of the 'defined' part of type 0/1/2 headers.
*/
- dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_0, 2);
- dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_0, 2);
dinfo->cfg.vendor = pci_read_config(dev, PCIR_VENDOR, 2);
dinfo->cfg.device = pci_read_config(dev, PCIR_DEVICE, 2);
dinfo->cfg.cmdreg = pci_read_config(dev, PCIR_COMMAND, 2);
dinfo->cfg.intline = pci_read_config(dev, PCIR_INTLINE, 1);
dinfo->cfg.intpin = pci_read_config(dev, PCIR_INTPIN, 1);
- dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1);
- dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1);
dinfo->cfg.cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
dinfo->cfg.lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
dinfo->cfg.baseclass = pci_read_config(dev, PCIR_CLASS, 1);
dinfo->cfg.subclass = pci_read_config(dev, PCIR_SUBCLASS, 1);
dinfo->cfg.progif = pci_read_config(dev, PCIR_PROGIF, 1);
dinfo->cfg.revid = pci_read_config(dev, PCIR_REVID, 1);
+ switch (dinfo->cfg.hdrtype & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_NORMAL:
+ dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_0, 2);
+ dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_0, 2);
+ dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1);
+ dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1);
+ break;
+ case PCIM_HDRTYPE_BRIDGE:
+ dinfo->cfg.bridge.br_seclat = pci_read_config(dev,
+ PCIR_SECLAT_1, 1);
+ dinfo->cfg.bridge.br_subbus = pci_read_config(dev,
+ PCIR_SUBBUS_1, 1);
+ dinfo->cfg.bridge.br_secbus = pci_read_config(dev,
+ PCIR_SECBUS_1, 1);
+ dinfo->cfg.bridge.br_pribus = pci_read_config(dev,
+ PCIR_PRIBUS_1, 1);
+ dinfo->cfg.bridge.br_control = pci_read_config(dev,
+ PCIR_BRIDGECTL_1, 2);
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ dinfo->cfg.bridge.br_seclat = pci_read_config(dev,
+ PCIR_SECLAT_2, 1);
+ dinfo->cfg.bridge.br_subbus = pci_read_config(dev,
+ PCIR_SUBBUS_2, 1);
+ dinfo->cfg.bridge.br_secbus = pci_read_config(dev,
+ PCIR_SECBUS_2, 1);
+ dinfo->cfg.bridge.br_pribus = pci_read_config(dev,
+ PCIR_PRIBUS_2, 1);
+ dinfo->cfg.bridge.br_control = pci_read_config(dev,
+ PCIR_BRIDGECTL_2, 2);
+ dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_2, 2);
+ dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_2, 2);
+ break;
+ }
if (dinfo->cfg.pcie.pcie_location != 0)
pci_cfg_save_pcie(dev, dinfo);
diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c
index e256a5d..4672e55 100644
--- a/sys/dev/pci/pci_iov.c
+++ b/sys/dev/pci/pci_iov.c
@@ -386,7 +386,7 @@ pci_iov_parse_config(struct pcicfg_iov *iov, struct pci_iov_arg *arg,
if (error != 0)
goto out;
- config = nvlist_unpack(packed_config, arg->len);
+ config = nvlist_unpack(packed_config, arg->len, NV_FLAG_IGNORE_CASE);
if (config == NULL) {
error = EINVAL;
goto out;
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index d0d8fb7..789a918 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -553,18 +553,22 @@ void
pcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count)
{
char buf[64];
- int error, rid;
+ int error, rid, sec_reg;
switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) {
case PCIM_HDRTYPE_BRIDGE:
+ sec_reg = PCIR_SECBUS_1;
bus->sub_reg = PCIR_SUBBUS_1;
break;
case PCIM_HDRTYPE_CARDBUS:
+ sec_reg = PCIR_SECBUS_2;
bus->sub_reg = PCIR_SUBBUS_2;
break;
default:
panic("not a PCI bridge");
}
+ bus->sec = pci_read_config(dev, sec_reg, 1);
+ bus->sub = pci_read_config(dev, bus->sub_reg, 1);
bus->dev = dev;
bus->rman.rm_start = 0;
bus->rman.rm_end = PCI_BUSMAX;
@@ -849,20 +853,16 @@ pcib_set_mem_decode(struct pcib_softc *sc)
static void
pcib_cfg_save(struct pcib_softc *sc)
{
+#ifndef NEW_PCIB
device_t dev;
+ uint16_t command;
dev = sc->dev;
- sc->command = pci_read_config(dev, PCIR_COMMAND, 2);
- sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1);
- sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1);
- sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
- sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
- sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1);
-#ifndef NEW_PCIB
- if (sc->command & PCIM_CMD_PORTEN)
+ command = pci_read_config(dev, PCIR_COMMAND, 2);
+ if (command & PCIM_CMD_PORTEN)
pcib_get_io_decode(sc);
- if (sc->command & PCIM_CMD_MEMEN)
+ if (command & PCIM_CMD_MEMEN)
pcib_get_mem_decode(sc);
#endif
}
@@ -874,21 +874,18 @@ static void
pcib_cfg_restore(struct pcib_softc *sc)
{
device_t dev;
-
+#ifndef NEW_PCIB
+ uint16_t command;
+#endif
dev = sc->dev;
- pci_write_config(dev, PCIR_COMMAND, sc->command, 2);
- pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
- pci_write_config(dev, PCIR_SECBUS_1, sc->bus.sec, 1);
- pci_write_config(dev, PCIR_SUBBUS_1, sc->bus.sub, 1);
- pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2);
- pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1);
#ifdef NEW_PCIB
pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM);
#else
- if (sc->command & PCIM_CMD_PORTEN)
+ command = pci_read_config(dev, PCIR_COMMAND, 2);
+ if (command & PCIM_CMD_PORTEN)
pcib_set_io_decode(sc);
- if (sc->command & PCIM_CMD_MEMEN)
+ if (command & PCIM_CMD_MEMEN)
pcib_set_mem_decode(sc);
#endif
}
@@ -922,7 +919,11 @@ pcib_attach_common(device_t dev)
* Get current bridge configuration.
*/
sc->domain = pci_get_domain(dev);
- sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2);
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
+ sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1);
+ sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
+#endif
+ sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
pcib_cfg_save(sc);
/*
@@ -950,7 +951,7 @@ pcib_attach_common(device_t dev)
* Quirk handling.
*/
switch (pci_get_devid(dev)) {
-#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS)
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
case 0x12258086: /* Intel 82454KX/GX (Orion) */
{
uint8_t supbus;
@@ -976,7 +977,7 @@ pcib_attach_common(device_t dev)
sc->flags |= PCIB_SUBTRACTIVE;
break;
-#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS)
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
/* Compaq R3000 BIOS sets wrong subordinate bus number. */
case 0x00dd10de:
{
@@ -1101,32 +1102,15 @@ pcib_attach(device_t dev)
int
pcib_suspend(device_t dev)
{
- device_t pcib;
- int dstate, error;
pcib_cfg_save(device_get_softc(dev));
- error = bus_generic_suspend(dev);
- if (error == 0 && pci_do_power_suspend) {
- dstate = PCI_POWERSTATE_D3;
- pcib = device_get_parent(device_get_parent(dev));
- if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
- pci_set_powerstate(dev, dstate);
- }
- return (error);
+ return (bus_generic_suspend(dev));
}
int
pcib_resume(device_t dev)
{
- device_t pcib;
- int dstate;
-
- if (pci_do_power_resume) {
- pcib = device_get_parent(device_get_parent(dev));
- dstate = PCI_POWERSTATE_D0;
- if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
- pci_set_powerstate(dev, dstate);
- }
+
pcib_cfg_restore(device_get_softc(dev));
return (bus_generic_resume(dev));
}
diff --git a/sys/dev/pci/pci_subr.c b/sys/dev/pci/pci_subr.c
index 5d0db36..03bcdc0 100644
--- a/sys/dev/pci/pci_subr.c
+++ b/sys/dev/pci/pci_subr.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2011 Advanced Computing Technologies LLC
+ * Copyright (c) 2011 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/dev/pci/pcib_private.h b/sys/dev/pci/pcib_private.h
index d8d82b6..20cb014 100644
--- a/sys/dev/pci/pcib_private.h
+++ b/sys/dev/pci/pcib_private.h
@@ -106,7 +106,6 @@ struct pcib_softc
#define PCIB_DISABLE_MSI 0x2
#define PCIB_DISABLE_MSIX 0x4
#define PCIB_ENABLE_ARI 0x8
- uint16_t command; /* command register */
u_int domain; /* domain number */
u_int pribus; /* primary bus number */
struct pcib_secbus bus; /* secondary bus numbers */
@@ -122,9 +121,7 @@ struct pcib_softc
uint32_t iobase; /* base address of port window */
uint32_t iolimit; /* topmost address of port window */
#endif
- uint16_t secstat; /* secondary bus status register */
uint16_t bridgectl; /* bridge control register */
- uint8_t seclat; /* secondary bus latency timer */
};
#define PCIB_SUPPORTED_ARI_VER 1
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 478c98e..2fd76b6 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -41,6 +41,15 @@ typedef uint64_t pci_addr_t;
struct nvlist;
+/* Config registers for PCI-PCI and PCI-Cardbus bridges. */
+struct pcicfg_bridge {
+ uint8_t br_seclat;
+ uint8_t br_subbus;
+ uint8_t br_secbus;
+ uint8_t br_pribus;
+ uint16_t br_control;
+};
+
/* Interesting values for PCI power management */
struct pcicfg_pp {
uint16_t pp_cap; /* PCI power management capabilities */
@@ -190,6 +199,7 @@ typedef struct pcicfg {
uint32_t flags; /* flags defined above */
size_t devinfo_size; /* Size of devinfo for this bus type. */
+ struct pcicfg_bridge bridge; /* Bridges */
struct pcicfg_pp pp; /* Power management */
struct pcicfg_vpd vpd; /* Vital product data */
struct pcicfg_msi msi; /* PCI MSI */
diff --git a/sys/dev/psci/psci.c b/sys/dev/psci/psci.c
new file mode 100644
index 0000000..67f700a
--- /dev/null
+++ b/sys/dev/psci/psci.c
@@ -0,0 +1,286 @@
+/*-
+ * Copyright (c) 2014 Robin Randhawa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * This implements support for ARM's Power State Co-ordination Interface
+ * [PSCI]. The implementation adheres to version 0.2 of the PSCI specification
+ * but also supports v0.1. PSCI standardizes operations such as system reset, CPU
+ * on/off/suspend. PSCI requires a compliant firmware implementation.
+ *
+ * The PSCI specification used for this implementation is available at:
+ *
+ * <http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0022b/index.html>.
+ *
+ * TODO:
+ * - Add support for remaining PSCI calls [this implementation only
+ * supports get_version, system_reset and cpu_on].
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/reboot.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/psci/psci.h>
+
+struct psci_softc {
+ device_t dev;
+
+ psci_callfn_t psci_call;
+ uint32_t psci_fnids[PSCI_FN_MAX];
+};
+
+static int psci_v0_1_init(device_t dev);
+static int psci_v0_2_init(device_t dev);
+
+struct psci_softc *psci_softc = NULL;
+
+static struct ofw_compat_data compat_data[] = {
+ {"arm,psci-0.2", (uintptr_t)psci_v0_2_init},
+ {"arm,psci", (uintptr_t)psci_v0_1_init},
+ {NULL, 0}
+};
+
+static int psci_probe(device_t dev);
+static int psci_attach(device_t dev);
+static void psci_shutdown(void *, int);
+
+static device_method_t psci_methods[] = {
+ DEVMETHOD(device_probe, psci_probe),
+ DEVMETHOD(device_attach, psci_attach),
+
+ DEVMETHOD_END
+};
+
+static driver_t psci_driver = {
+ "psci",
+ psci_methods,
+ sizeof(struct psci_softc),
+};
+
+static devclass_t psci_devclass;
+
+EARLY_DRIVER_MODULE(psci, simplebus, psci_driver, psci_devclass, 0, 0,
+ BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);
+EARLY_DRIVER_MODULE(psci, ofwbus, psci_driver, psci_devclass, 0, 0,
+ BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);
+
+static int
+psci_probe(device_t dev)
+{
+ const struct ofw_compat_data *ocd;
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ ocd = ofw_bus_search_compatible(dev, compat_data);
+ if (ocd->ocd_str == NULL)
+ return (ENXIO);
+
+ device_set_desc(dev, "ARM Power State Co-ordination Interface Driver");
+
+ return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+psci_attach(device_t dev)
+{
+ struct psci_softc *sc = device_get_softc(dev);
+ const struct ofw_compat_data *ocd;
+ psci_initfn_t psci_init;
+ phandle_t node;
+ char method[16];
+
+ if (psci_softc != NULL)
+ return (ENXIO);
+
+ ocd = ofw_bus_search_compatible(dev, compat_data);
+ psci_init = (psci_initfn_t)ocd->ocd_data;
+ KASSERT(psci_init != NULL, ("PSCI init function cannot be NULL"));
+
+ node = ofw_bus_get_node(dev);
+ if ((OF_getprop(node, "method", method, sizeof(method))) > 0) {
+ if (strcmp(method, "hvc") == 0)
+ sc->psci_call = psci_hvc_despatch;
+ else if (strcmp(method, "smc") == 0)
+ sc->psci_call = psci_smc_despatch;
+ else {
+ device_printf(dev,
+ "psci_attach: PSCI conduit \"%s\" invalid\n",
+ method);
+ return (ENXIO);
+ }
+ } else {
+ device_printf(dev,
+ "psci_attach: PSCI conduit not supplied in the DT\n");
+ return (ENXIO);
+ }
+
+ if (psci_init(dev))
+ return (ENXIO);
+
+ psci_softc = sc;
+
+ return (0);
+}
+
+static int
+psci_get_version(struct psci_softc *sc)
+{
+ uint32_t fnid;
+
+ /* PSCI version wasn't supported in v0.1. */
+ fnid = sc->psci_fnids[PSCI_FN_VERSION];
+ if (fnid)
+ return (sc->psci_call(fnid, 0, 0, 0));
+
+ return (PSCI_RETVAL_NOT_SUPPORTED);
+}
+
+int
+psci_cpu_on(unsigned long cpu, unsigned long entry, unsigned long context_id)
+{
+
+ /* PSCI v0.1 and v0.2 both support cpu_on. */
+ return(psci_softc->psci_call(psci_softc->psci_fnids[PSCI_FN_CPU_ON], cpu,
+ entry, context_id));
+}
+
+static void
+psci_shutdown(void *xsc, int howto)
+{
+ uint32_t fn = 0;
+
+ /* PSCI system_off and system_reset werent't supported in v0.1. */
+ if ((howto & RB_POWEROFF) != 0)
+ fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_OFF];
+ else if ((howto & RB_HALT) == 0)
+ fn = psci_softc->psci_fnids[PSCI_FN_SYSTEM_RESET];
+
+ if (fn)
+ psci_softc->psci_call(fn, 0, 0, 0);
+
+ /* System reset and off do not return. */
+}
+
+static int
+psci_v0_1_init(device_t dev)
+{
+ struct psci_softc *sc = device_get_softc(dev);
+ int psci_fn;
+ uint32_t psci_fnid;
+ phandle_t node;
+ int len;
+
+
+ /* Zero out the function ID table - Is this needed ? */
+ for (psci_fn = PSCI_FN_VERSION, psci_fnid = PSCI_FNID_VERSION;
+ psci_fn < PSCI_FN_MAX; psci_fn++, psci_fnid++)
+ sc->psci_fnids[psci_fn] = 0;
+
+ /* PSCI v0.1 doesn't specify function IDs. Get them from DT */
+ node = ofw_bus_get_node(dev);
+
+ if ((len = OF_getproplen(node, "cpu_suspend")) > 0) {
+ OF_getencprop(node, "cpu_suspend", &psci_fnid, len);
+ sc->psci_fnids[PSCI_FN_CPU_SUSPEND] = psci_fnid;
+ }
+
+ if ((len = OF_getproplen(node, "cpu_on")) > 0) {
+ OF_getencprop(node, "cpu_on", &psci_fnid, len);
+ sc->psci_fnids[PSCI_FN_CPU_ON] = psci_fnid;
+ }
+
+ if ((len = OF_getproplen(node, "cpu_off")) > 0) {
+ OF_getencprop(node, "cpu_off", &psci_fnid, len);
+ sc->psci_fnids[PSCI_FN_CPU_OFF] = psci_fnid;
+ }
+
+ if ((len = OF_getproplen(node, "migrate")) > 0) {
+ OF_getencprop(node, "migrate", &psci_fnid, len);
+ sc->psci_fnids[PSCI_FN_MIGRATE] = psci_fnid;
+ }
+
+ if (bootverbose)
+ device_printf(dev, "PSCI version 0.1 available\n");
+
+ return(0);
+}
+
+static int
+psci_v0_2_init(device_t dev)
+{
+ struct psci_softc *sc = device_get_softc(dev);
+ int version;
+
+ /* PSCI v0.2 specifies explicit function IDs. */
+ sc->psci_fnids[PSCI_FN_VERSION] = PSCI_FNID_VERSION;
+ sc->psci_fnids[PSCI_FN_CPU_SUSPEND] = PSCI_FNID_CPU_SUSPEND;
+ sc->psci_fnids[PSCI_FN_CPU_OFF] = PSCI_FNID_CPU_OFF;
+ sc->psci_fnids[PSCI_FN_CPU_ON] = PSCI_FNID_CPU_ON;
+ sc->psci_fnids[PSCI_FN_AFFINITY_INFO] = PSCI_FNID_AFFINITY_INFO;
+ sc->psci_fnids[PSCI_FN_MIGRATE] = PSCI_FNID_MIGRATE;
+ sc->psci_fnids[PSCI_FN_MIGRATE_INFO_TYPE] = PSCI_FNID_MIGRATE_INFO_TYPE;
+ sc->psci_fnids[PSCI_FN_MIGRATE_INFO_UP_CPU] = PSCI_FNID_MIGRATE_INFO_UP_CPU;
+ sc->psci_fnids[PSCI_FN_SYSTEM_OFF] = PSCI_FNID_SYSTEM_OFF;
+ sc->psci_fnids[PSCI_FN_SYSTEM_RESET] = PSCI_FNID_SYSTEM_RESET;
+
+ version = psci_get_version(sc);
+
+ if (version == PSCI_RETVAL_NOT_SUPPORTED)
+ return (1);
+
+ if ((PSCI_VER_MAJOR(version) != 0) && (PSCI_VER_MINOR(version) != 2)) {
+ device_printf(dev, "PSCI version number mismatched with DT\n");
+ return (1);
+ }
+
+ if (bootverbose)
+ device_printf(dev, "PSCI version 0.2 available\n");
+
+ /*
+ * We only register this for v0.2 since v0.1 doesn't support
+ * system_reset.
+ */
+ EVENTHANDLER_REGISTER(shutdown_final, psci_shutdown, sc,
+ SHUTDOWN_PRI_LAST);
+
+ return (0);
+}
diff --git a/sys/dev/psci/psci.h b/sys/dev/psci/psci.h
new file mode 100644
index 0000000..58f1e79
--- /dev/null
+++ b/sys/dev/psci/psci.h
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2013, 2014 Robin Randhawa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_PSCI_H_
+#define _MACHINE_PSCI_H_
+
+#include <sys/types.h>
+
+typedef int (*psci_initfn_t)(device_t dev);
+typedef int (*psci_callfn_t)(register_t, register_t, register_t, register_t);
+
+extern int psci_present;
+
+void psci_system_reset(void);
+int psci_cpu_on(unsigned long, unsigned long, unsigned long);
+int psci_hvc_despatch(register_t, register_t, register_t, register_t);
+int psci_smc_despatch(register_t, register_t, register_t, register_t);
+
+
+/*
+ * PSCI return codes.
+ */
+#define PSCI_RETVAL_SUCCESS 0
+#define PSCI_RETVAL_NOT_SUPPORTED -1
+#define PSCI_RETVAL_INVALID_PARAMS -2
+#define PSCI_RETVAL_DENIED -3
+#define PSCI_RETVAL_ALREADY_ON -4
+#define PSCI_RETVAL_ON_PENDING -5
+#define PSCI_RETVAL_INTERNAL_FAILURE -6
+#define PSCI_RETVAL_NOT_PRESENT -7
+#define PSCI_RETVAL_DISABLED -8
+
+/*
+ * PSCI function codes (as per PSCI v0.2).
+ */
+#ifdef __aarch64__
+#define PSCI_FNID_VERSION 0x84000000
+#define PSCI_FNID_CPU_SUSPEND 0xc4000001
+#define PSCI_FNID_CPU_OFF 0x84000002
+#define PSCI_FNID_CPU_ON 0xc4000003
+#define PSCI_FNID_AFFINITY_INFO 0xc4000004
+#define PSCI_FNID_MIGRATE 0xc4000005
+#define PSCI_FNID_MIGRATE_INFO_TYPE 0x84000006
+#define PSCI_FNID_MIGRATE_INFO_UP_CPU 0xc4000007
+#define PSCI_FNID_SYSTEM_OFF 0x84000008
+#define PSCI_FNID_SYSTEM_RESET 0x84000009
+#else
+#define PSCI_FNID_VERSION 0x84000000
+#define PSCI_FNID_CPU_SUSPEND 0x84000001
+#define PSCI_FNID_CPU_OFF 0x84000002
+#define PSCI_FNID_CPU_ON 0x84000003
+#define PSCI_FNID_AFFINITY_INFO 0x84000004
+#define PSCI_FNID_MIGRATE 0x84000005
+#define PSCI_FNID_MIGRATE_INFO_TYPE 0x84000006
+#define PSCI_FNID_MIGRATE_INFO_UP_CPU 0x84000007
+#define PSCI_FNID_SYSTEM_OFF 0x84000008
+#define PSCI_FNID_SYSTEM_RESET 0x84000009
+#endif
+
+#define PSCI_VER_MAJOR(v) (((v) >> 16) & 0xFF)
+#define PSCI_VER_MINOR(v) ((v) & 0xFF)
+
+enum psci_fn {
+ PSCI_FN_VERSION,
+ PSCI_FN_CPU_SUSPEND,
+ PSCI_FN_CPU_OFF,
+ PSCI_FN_CPU_ON,
+ PSCI_FN_AFFINITY_INFO,
+ PSCI_FN_MIGRATE,
+ PSCI_FN_MIGRATE_INFO_TYPE,
+ PSCI_FN_MIGRATE_INFO_UP_CPU,
+ PSCI_FN_SYSTEM_OFF,
+ PSCI_FN_SYSTEM_RESET,
+ PSCI_FN_MAX
+};
+
+#endif /* _MACHINE_PSCI_H_ */
diff --git a/sys/dev/psci/psci_arm.S b/sys/dev/psci/psci_arm.S
new file mode 100644
index 0000000..987e3d1
--- /dev/null
+++ b/sys/dev/psci/psci_arm.S
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2015 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.arch_extension virt /* For hvc */
+
+/*
+ * int psci_hvc_despatch(register_t psci_fnid, register_t...)
+ */
+ENTRY(psci_hvc_despatch)
+ hvc #0
+ RET
+END(psci_hvc_despatch)
+
+/*
+ * int psci_smc_despatch(register_t psci_fnid, register_t...)
+ */
+ENTRY(psci_smc_despatch)
+ smc #0
+ RET
+END(psci_hvc_despatch)
diff --git a/sys/dev/psci/psci_arm64.S b/sys/dev/psci/psci_arm64.S
new file mode 100644
index 0000000..039ba1f
--- /dev/null
+++ b/sys/dev/psci/psci_arm64.S
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2013, 2014 Robin Randhawa
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * uint64_t psci_hvc_despatch(uint64_t psci_fnid, uint64_t, uint64_t, uint64_t)
+ */
+ENTRY(psci_hvc_despatch)
+ hvc #0
+ ret
+END(psci_hvc_despatch)
+
+/*
+ * uint64_t psci_smc_despatch(uint64_t psci_fnid, uint64_t, uint64_t, uint64_t)
+ */
+ENTRY(psci_smc_despatch)
+ smc #0
+ ret
+END(psci_hvc_despatch)
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index e27a812..a67d367 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -3196,11 +3196,6 @@ re_init_locked(struct rl_softc *sc)
~0x00080000);
/*
- * Enable transmit and receive.
- */
- CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
-
- /*
* Set the initial TX configuration.
*/
if (sc->rl_testmode) {
@@ -3226,6 +3221,11 @@ re_init_locked(struct rl_softc *sc)
CSR_WRITE_2(sc, RL_INTRMOD, 0x5100);
}
+ /*
+ * Enable transmit and receive.
+ */
+ CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB | RL_CMD_RX_ENB);
+
#ifdef DEVICE_POLLING
/*
* Disable interrupts if we are polling.
@@ -3249,10 +3249,6 @@ re_init_locked(struct rl_softc *sc)
/* Start RX/TX process. */
CSR_WRITE_4(sc, RL_MISSEDPKT, 0);
-#ifdef notdef
- /* Enable receiver and transmitter. */
- CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
-#endif
/*
* Initialize the timer interrupt register so that
diff --git a/sys/dev/smbus/smb.c b/sys/dev/smbus/smb.c
index 579204d..e842441 100644
--- a/sys/dev/smbus/smb.c
+++ b/sys/dev/smbus/smb.c
@@ -26,10 +26,6 @@
* $FreeBSD$
*/
-#ifdef HAVE_KERNEL_OPTION_HEADERS
-#include "opt_compat.h"
-#endif
-
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@@ -104,19 +100,24 @@ smb_identify(driver_t *driver, device_t parent)
static int
smb_probe(device_t dev)
{
- device_set_desc(dev, "SMBus generic I/O");
+ if (smbus_get_addr(dev) != -1)
+ return (ENXIO);
- return (0);
+ device_set_desc(dev, "SMBus generic I/O");
+ return (BUS_PROBE_NOWILDCARD);
}
static int
smb_attach(device_t dev)
{
struct smb_softc *sc = device_get_softc(dev);
-
+ int unit;
+
+ unit = device_get_unit(dev);
sc->sc_dev = dev;
- sc->sc_devnode = make_dev(&smb_cdevsw, device_get_unit(dev),
- UID_ROOT, GID_WHEEL, 0600, "smb%d", device_get_unit(dev));
+
+ sc->sc_devnode = make_dev(&smb_cdevsw, unit, UID_ROOT, GID_WHEEL,
+ 0600, "smb%d", unit);
sc->sc_devnode->si_drv1 = sc;
mtx_init(&sc->sc_lock, device_get_nameunit(dev), NULL, MTX_DEF);
@@ -174,9 +175,16 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
struct smb_softc *sc = dev->si_drv1;
device_t smbdev = sc->sc_dev;
int error;
- short w;
- u_char count;
- char c;
+ int unit;
+ u_char bcount;
+
+ /*
+ * If a specific slave device is being used, override any passed-in
+ * slave.
+ */
+ unit = dev2unit(dev);
+ if (unit & 0x0400)
+ s->slave = unit & 0x03ff;
parent = device_get_parent(smbdev);
@@ -208,77 +216,101 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
case SMB_WRITEB:
error = smbus_error(smbus_writeb(parent, s->slave, s->cmd,
- s->data.byte));
+ s->wdata.byte));
break;
case SMB_WRITEW:
error = smbus_error(smbus_writew(parent, s->slave,
- s->cmd, s->data.word));
+ s->cmd, s->wdata.word));
break;
case SMB_READB:
- if (s->data.byte_ptr) {
- error = smbus_error(smbus_readb(parent, s->slave,
- s->cmd, &c));
- if (error)
- break;
- error = copyout(&c, s->data.byte_ptr,
- sizeof(*(s->data.byte_ptr)));
+ error = smbus_error(smbus_readb(parent, s->slave, s->cmd,
+ &s->rdata.byte));
+ if (error)
+ break;
+ if (s->rbuf && s->rcount >= 1) {
+ error = copyout(&s->rdata.byte, s->rbuf, 1);
+ s->rcount = 1;
}
break;
case SMB_READW:
- if (s->data.word_ptr) {
- error = smbus_error(smbus_readw(parent, s->slave,
- s->cmd, &w));
- if (error == 0) {
- error = copyout(&w, s->data.word_ptr,
- sizeof(*(s->data.word_ptr)));
- }
+ error = smbus_error(smbus_readw(parent, s->slave, s->cmd,
+ &s->rdata.word));
+ if (error)
+ break;
+ if (s->rbuf && s->rcount >= 2) {
+ buf[0] = (u_char)s->rdata.word;
+ buf[1] = (u_char)(s->rdata.word >> 8);
+ error = copyout(buf, s->rbuf, 2);
+ s->rcount = 2;
}
break;
case SMB_PCALL:
- if (s->data.process.rdata) {
-
- error = smbus_error(smbus_pcall(parent, s->slave, s->cmd,
- s->data.process.sdata, &w));
- if (error)
- break;
- error = copyout(&w, s->data.process.rdata,
- sizeof(*(s->data.process.rdata)));
+ error = smbus_error(smbus_pcall(parent, s->slave, s->cmd,
+ s->wdata.word, &s->rdata.word));
+ if (error)
+ break;
+ if (s->rbuf && s->rcount >= 2) {
+ buf[0] = (u_char)s->rdata.word;
+ buf[1] = (u_char)(s->rdata.word >> 8);
+ error = copyout(buf, s->rbuf, 2);
+ s->rcount = 2;
}
-
+
break;
case SMB_BWRITE:
- if (s->count && s->data.byte_ptr) {
- if (s->count > SMB_MAXBLOCKSIZE)
- s->count = SMB_MAXBLOCKSIZE;
- error = copyin(s->data.byte_ptr, buf, s->count);
- if (error)
- break;
- error = smbus_error(smbus_bwrite(parent, s->slave,
- s->cmd, s->count, buf));
+ if (s->wcount < 0) {
+ error = EINVAL;
+ break;
}
+ if (s->wcount > SMB_MAXBLOCKSIZE)
+ s->wcount = SMB_MAXBLOCKSIZE;
+ if (s->wcount)
+ error = copyin(s->wbuf, buf, s->wcount);
+ if (error)
+ break;
+ error = smbus_error(smbus_bwrite(parent, s->slave, s->cmd,
+ s->wcount, buf));
break;
-#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD6)
- case SMB_OLD_BREAD:
-#endif
case SMB_BREAD:
- if (s->count && s->data.byte_ptr) {
- count = min(s->count, SMB_MAXBLOCKSIZE);
- error = smbus_error(smbus_bread(parent, s->slave,
- s->cmd, &count, buf));
- if (error)
- break;
- error = copyout(buf, s->data.byte_ptr,
- min(count, s->count));
- s->count = count;
+ if (s->rcount < 0) {
+ error = EINVAL;
+ break;
+ }
+ if (s->rcount > SMB_MAXBLOCKSIZE)
+ s->rcount = SMB_MAXBLOCKSIZE;
+ error = smbus_error(smbus_bread(parent, s->slave, s->cmd,
+ &bcount, buf));
+ if (error)
+ break;
+ if (s->rcount > bcount)
+ s->rcount = bcount;
+ error = copyout(buf, s->rbuf, s->rcount);
+ break;
+
+ case SMB_TRANS:
+ if (s->rcount < 0 || s->wcount < 0) {
+ error = EINVAL;
+ break;
}
+ if (s->rcount > SMB_MAXBLOCKSIZE)
+ s->rcount = SMB_MAXBLOCKSIZE;
+ if (s->wcount > SMB_MAXBLOCKSIZE)
+ s->wcount = SMB_MAXBLOCKSIZE;
+ if (s->wcount)
+ error = copyin(s->wbuf, buf, s->wcount);
+ if (error)
+ break;
+ error = smbus_error(smbus_trans(parent, s->slave, s->cmd,
+ s->op, buf, s->wcount, buf, s->rcount, &s->rcount));
+ if (error == 0)
+ error = copyout(buf, s->rbuf, s->rcount);
break;
-
default:
error = ENOTTY;
}
diff --git a/sys/dev/smbus/smb.h b/sys/dev/smbus/smb.h
index 32347f8..8007653 100644
--- a/sys/dev/smbus/smb.h
+++ b/sys/dev/smbus/smb.h
@@ -32,27 +32,33 @@
#include <sys/ioccom.h>
struct smbcmd {
- char cmd;
- int count;
- u_char slave;
+ u_char cmd;
+ u_char reserved;
+ u_short op;
union {
- char byte;
- short word;
-
- char *byte_ptr;
- short *word_ptr;
-
- struct {
- short sdata;
- short *rdata;
- } process;
- } data;
+ char byte;
+ char buf[2];
+ short word;
+ } wdata;
+ union {
+ char byte;
+ char buf[2];
+ short word;
+ } rdata;
+ int slave;
+ char *wbuf; /* use wdata if NULL */
+ int wcount;
+ char *rbuf; /* use rdata if NULL */
+ int rcount;
};
/*
* SMBus spec 2.0 says block transfers may be at most 32 bytes.
+ * We use SMBus for i2c as well, make the size limit something more
+ * reasonable. Keep in mind that a char buf array is declared on the
+ * kernel stack.
*/
-#define SMB_MAXBLOCKSIZE 32
+#define SMB_MAXBLOCKSIZE 1024
#define SMB_QUICK_WRITE _IOW('i', 1, struct smbcmd)
#define SMB_QUICK_READ _IOW('i', 2, struct smbcmd)
@@ -66,5 +72,6 @@ struct smbcmd {
#define SMB_BWRITE _IOW('i', 10, struct smbcmd)
#define SMB_OLD_BREAD _IOW('i', 11, struct smbcmd)
#define SMB_BREAD _IOWR('i', 11, struct smbcmd)
+#define SMB_TRANS _IOWR('i', 12, struct smbcmd)
#endif
diff --git a/sys/dev/smbus/smbconf.h b/sys/dev/smbus/smbconf.h
index a3d403d..f39c442 100644
--- a/sys/dev/smbus/smbconf.h
+++ b/sys/dev/smbus/smbconf.h
@@ -68,9 +68,30 @@
#define SMB_QREAD 0x1
/*
+ * smbus transction op with pass-thru capabilities
+ *
+ * This smbus function is capable of doing a smbus command transaction
+ * (read or write), and can be flagged to not issue the 'cmd' and/or
+ * issue or expect a count field as well as flagged for chaining (no STOP),
+ * which gives it an i2c pass-through capability.
+ *
+ * NOSTOP- Caller chaining transactions, do not issue STOP
+ * NOCMD- Do not transmit the command field
+ * NOCNT- Do not transmit (wr) or expect (rd) the count field
+ */
+#define SMB_TRANS_NOSTOP 0x0001 /* do not send STOP at end */
+#define SMB_TRANS_NOCMD 0x0002 /* ignore cmd field (do not tx) */
+#define SMB_TRANS_NOCNT 0x0004 /* do not tx or rx count field */
+#define SMB_TRANS_7BIT 0x0008 /* change address mode to 7-bit */
+#define SMB_TRANS_10BIT 0x0010 /* change address mode to 10-bit */
+#define SMB_TRANS_NOREPORT 0x0020 /* do not report errors */
+
+/*
* ivars codes
*/
-#define SMBUS_IVAR_ADDR 0x1 /* slave address of the device */
+enum smbus_ivars {
+ SMBUS_IVAR_ADDR, /* slave address of the device */
+};
int smbus_request_bus(device_t, device_t, int);
int smbus_release_bus(device_t, device_t);
@@ -79,7 +100,12 @@ int smbus_error(int error);
void smbus_intr(device_t, u_char, char low, char high, int error);
-u_char smbus_get_addr(device_t);
+#define SMBUS_ACCESSOR(var, ivar, type) \
+ __BUS_ACCESSOR(smbus, var, SMBUS, ivar, type)
+
+SMBUS_ACCESSOR(addr, ADDR, int)
+
+#undef SMBUS_ACCESSOR
extern driver_t smbus_driver;
extern devclass_t smbus_devclass;
@@ -104,6 +130,9 @@ extern devclass_t smbus_devclass;
(SMBUS_BWRITE(device_get_parent(bus), slave, cmd, count, buf))
#define smbus_bread(bus,slave,cmd,count,buf) \
(SMBUS_BREAD(device_get_parent(bus), slave, cmd, count, buf))
+#define smbus_trans(bus,slave,cmd,op,wbuf,wcount,rbuf,rcount,actualp) \
+ (SMBUS_TRANS(device_get_parent(bus), slave, cmd, op, \
+ wbuf, wcount, rbuf, rcount, actualp))
#define SMBUS_MODVER 1
#define SMBUS_MINVER 1
diff --git a/sys/dev/smbus/smbus.c b/sys/dev/smbus/smbus.c
index a111332..389efac 100644
--- a/sys/dev/smbus/smbus.c
+++ b/sys/dev/smbus/smbus.c
@@ -33,11 +33,15 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h>
-#include <sys/bus.h>
+#include <sys/bus.h>
#include <dev/smbus/smbconf.h>
#include <dev/smbus/smbus.h>
+#include "smbus_if.h"
+#include "bus_if.h"
+
+
/*
* Autoconfiguration and support routines for System Management bus
*/
@@ -49,6 +53,13 @@ static int smbus_probe(device_t);
static int smbus_attach(device_t);
static int smbus_detach(device_t);
+static int smbus_child_location_str(device_t parent, device_t child,
+ char *buf, size_t buflen);
+static int smbus_print_child(device_t parent, device_t child);
+static void smbus_probe_device(device_t dev, u_char* addr);
+static int smbus_read_ivar(device_t parent, device_t child, int which,
+ uintptr_t *result);
+
static device_method_t smbus_methods[] = {
/* device interface */
DEVMETHOD(device_probe, smbus_probe),
@@ -57,6 +68,10 @@ static device_method_t smbus_methods[] = {
/* bus interface */
DEVMETHOD(bus_add_child, bus_generic_add_child),
+ DEVMETHOD(bus_child_location_str, smbus_child_location_str),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ DEVMETHOD(bus_print_child, smbus_print_child),
+ DEVMETHOD(bus_read_ivar, smbus_read_ivar),
DEVMETHOD_END
};
@@ -87,9 +102,14 @@ static int
smbus_attach(device_t dev)
{
struct smbus_softc *sc = device_get_softc(dev);
+ unsigned char addr;
mtx_init(&sc->lock, device_get_nameunit(dev), "smbus", MTX_DEF);
bus_generic_probe(dev);
+ for (addr = SMBUS_ADDR_MIN; addr < SMBUS_ADDR_MAX; ++addr) {
+ sc->addrs[addr] = addr;
+ smbus_probe_device(dev, &sc->addrs[addr]);
+ }
bus_generic_attach(dev);
return (0);
@@ -114,4 +134,70 @@ smbus_generic_intr(device_t dev, u_char devaddr, char low, char high, int err)
{
}
+static void
+smbus_probe_device(device_t dev, u_char* addr)
+{
+ device_t child;
+ int error;
+ u_char cmd;
+ u_char buf[2];
+
+ cmd = 0x01;
+ error = smbus_trans(dev, *addr, cmd,
+ SMB_TRANS_NOCNT | SMB_TRANS_NOREPORT,
+ NULL, 0, buf, 1, NULL);
+ if (error == 0) {
+ if (bootverbose)
+ device_printf(dev, "Probed address 0x%02x\n", *addr);
+ child = device_add_child(dev, NULL, -1);
+ device_set_ivars(child, addr);
+ }
+}
+
+static int
+smbus_child_location_str(device_t parent, device_t child, char *buf,
+ size_t buflen)
+{
+ unsigned char *addr;
+
+ addr = device_get_ivars(child);
+ if (addr)
+ snprintf(buf, buflen, "addr=0x%x", *addr);
+ else if (buflen)
+ buf[0] = 0;
+ return (0);
+}
+
+static int
+smbus_print_child(device_t parent, device_t child)
+{
+ unsigned char *addr;
+ int retval;
+
+ addr = device_get_ivars(child);
+ retval = bus_print_child_header(parent, child);
+ if (addr)
+ retval += printf(" at addr 0x%x", *addr);
+ retval += bus_print_child_footer(parent, child);
+
+ return (retval);
+}
+
+static int
+smbus_read_ivar(device_t parent, device_t child, int which,
+ uintptr_t *result)
+{
+ unsigned char *addr;
+
+ addr = device_get_ivars(child);
+ switch (which) {
+ case SMBUS_IVAR_ADDR:
+ *result = (addr == NULL) ? -1 : *addr;
+ break;
+ default:
+ return (ENOENT);
+ }
+ return (0);
+}
+
MODULE_VERSION(smbus, SMBUS_MODVER);
diff --git a/sys/dev/smbus/smbus.h b/sys/dev/smbus/smbus.h
index 5626835..2093aa0 100644
--- a/sys/dev/smbus/smbus.h
+++ b/sys/dev/smbus/smbus.h
@@ -29,9 +29,13 @@
#ifndef __SMBUS_H
#define __SMBUS_H
+#define SMBUS_ADDR_MIN 0x10
+#define SMBUS_ADDR_MAX 0x70
+
struct smbus_softc {
device_t owner; /* smbus owner device structure */
struct mtx lock;
+ unsigned char addrs[SMBUS_ADDR_MAX];
};
void smbus_generic_intr(device_t dev, u_char devaddr, char low, char high, int err);
diff --git a/sys/dev/smbus/smbus_if.m b/sys/dev/smbus/smbus_if.m
index d969e25..6a5acf5 100644
--- a/sys/dev/smbus/smbus_if.m
+++ b/sys/dev/smbus/smbus_if.m
@@ -149,3 +149,20 @@ METHOD int bread {
u_char *count;
char *buf;
};
+
+#
+# SMB roll-up transaction with flags that also allow it to be
+# used for (mostly) i2c pass-through and with 10-bit addresses.
+# This function can be used to roll-up all of the above functions.
+#
+METHOD int trans {
+ device_t dev;
+ int slave;
+ char cmd;
+ int op;
+ char *wbuf;
+ int wcount;
+ char *rbuf;
+ int rcount;
+ int *actualp;
+};
diff --git a/sys/dev/sound/pci/hda/hdaa_patches.c b/sys/dev/sound/pci/hda/hdaa_patches.c
index 44b7242..8852215 100644
--- a/sys/dev/sound/pci/hda/hdaa_patches.c
+++ b/sys/dev/sound/pci/hda/hdaa_patches.c
@@ -401,6 +401,13 @@ hdac_pin_patch(struct hdaa_widget *w)
patch = "as=1 seq=15";
break;
}
+ } else if (id == HDA_CODEC_ALC292 &&
+ subid == LENOVO_X120BS_SUBVENDOR) {
+ switch (nid) {
+ case 21:
+ patch = "as=1 seq=15";
+ break;
+ }
}
if (patch != NULL)
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c
index 925ff3f..1e173c6 100644
--- a/sys/dev/sound/pci/hda/hdac.c
+++ b/sys/dev/sound/pci/hda/hdac.c
@@ -81,6 +81,8 @@ static const struct {
{ HDA_INTEL_HSW1, "Intel Haswell", 0, 0 },
{ HDA_INTEL_HSW2, "Intel Haswell", 0, 0 },
{ HDA_INTEL_HSW3, "Intel Haswell", 0, 0 },
+ { HDA_INTEL_BDW1, "Intel Broadwell", 0, 0 },
+ { HDA_INTEL_BDW2, "Intel Broadwell", 0, 0 },
{ HDA_INTEL_CPT, "Intel Cougar Point", 0, 0 },
{ HDA_INTEL_PATSBURG,"Intel Patsburg", 0, 0 },
{ HDA_INTEL_PPT1, "Intel Panther Point", 0, 0 },
diff --git a/sys/dev/sound/pci/hda/hdac.h b/sys/dev/sound/pci/hda/hdac.h
index 153426d..9538b307 100644
--- a/sys/dev/sound/pci/hda/hdac.h
+++ b/sys/dev/sound/pci/hda/hdac.h
@@ -46,6 +46,7 @@
#define HDA_INTEL_HSW1 HDA_MODEL_CONSTRUCT(INTEL, 0x0a0c)
#define HDA_INTEL_HSW2 HDA_MODEL_CONSTRUCT(INTEL, 0x0c0c)
#define HDA_INTEL_HSW3 HDA_MODEL_CONSTRUCT(INTEL, 0x0d0c)
+#define HDA_INTEL_BDW1 HDA_MODEL_CONSTRUCT(INTEL, 0x160c)
#define HDA_INTEL_CPT HDA_MODEL_CONSTRUCT(INTEL, 0x1c20)
#define HDA_INTEL_PATSBURG HDA_MODEL_CONSTRUCT(INTEL, 0x1d20)
#define HDA_INTEL_PPT1 HDA_MODEL_CONSTRUCT(INTEL, 0x1e20)
@@ -67,6 +68,7 @@
#define HDA_INTEL_WELLS2 HDA_MODEL_CONSTRUCT(INTEL, 0x8d21)
#define HDA_INTEL_LPTLP1 HDA_MODEL_CONSTRUCT(INTEL, 0x9c20)
#define HDA_INTEL_LPTLP2 HDA_MODEL_CONSTRUCT(INTEL, 0x9c21)
+#define HDA_INTEL_BDW2 HDA_MODEL_CONSTRUCT(INTEL, 0x9ca0)
#define HDA_INTEL_ALL HDA_MODEL_CONSTRUCT(INTEL, 0xffff)
/* Nvidia */
@@ -235,6 +237,7 @@
#define LENOVO_TCA55_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x1015)
#define LENOVO_X1_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21e8)
#define LENOVO_X1CRBN_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21f9)
+#define LENOVO_X120BS_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x2227)
#define LENOVO_X220_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x21da)
#define LENOVO_X300_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x20ac)
#define LENOVO_T400_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x20f2)
@@ -338,6 +341,7 @@
#define HDA_CODEC_ALC273 HDA_CODEC_CONSTRUCT(REALTEK, 0x0273)
#define HDA_CODEC_ALC275 HDA_CODEC_CONSTRUCT(REALTEK, 0x0275)
#define HDA_CODEC_ALC276 HDA_CODEC_CONSTRUCT(REALTEK, 0x0276)
+#define HDA_CODEC_ALC292 HDA_CODEC_CONSTRUCT(REALTEK, 0x0292)
#define HDA_CODEC_ALC660 HDA_CODEC_CONSTRUCT(REALTEK, 0x0660)
#define HDA_CODEC_ALC662 HDA_CODEC_CONSTRUCT(REALTEK, 0x0662)
#define HDA_CODEC_ALC663 HDA_CODEC_CONSTRUCT(REALTEK, 0x0663)
@@ -622,6 +626,7 @@
#define HDA_CODEC_INTELCPT HDA_CODEC_CONSTRUCT(INTEL, 0x2805)
#define HDA_CODEC_INTELPPT HDA_CODEC_CONSTRUCT(INTEL, 0x2806)
#define HDA_CODEC_INTELHSW HDA_CODEC_CONSTRUCT(INTEL, 0x2807)
+#define HDA_CODEC_INTELBDW HDA_CODEC_CONSTRUCT(INTEL, 0x2808)
#define HDA_CODEC_INTELCL HDA_CODEC_CONSTRUCT(INTEL, 0x29fb)
#define HDA_CODEC_INTELXXXX HDA_CODEC_CONSTRUCT(INTEL, 0xffff)
diff --git a/sys/dev/sound/pci/hda/hdacc.c b/sys/dev/sound/pci/hda/hdacc.c
index fcecf33..5b785a8 100644
--- a/sys/dev/sound/pci/hda/hdacc.c
+++ b/sys/dev/sound/pci/hda/hdacc.c
@@ -87,6 +87,7 @@ static const struct {
{ HDA_CODEC_ALC273, 0, "Realtek ALC273" },
{ HDA_CODEC_ALC275, 0, "Realtek ALC275" },
{ HDA_CODEC_ALC276, 0, "Realtek ALC276" },
+ { HDA_CODEC_ALC292, 0, "Realtek ALC292" },
{ HDA_CODEC_ALC660, 0, "Realtek ALC660-VD" },
{ HDA_CODEC_ALC662, 0x0002, "Realtek ALC662 rev2" },
{ HDA_CODEC_ALC662, 0, "Realtek ALC662" },
@@ -319,6 +320,7 @@ static const struct {
{ HDA_CODEC_INTELCPT, 0, "Intel Cougar Point" },
{ HDA_CODEC_INTELPPT, 0, "Intel Panther Point" },
{ HDA_CODEC_INTELHSW, 0, "Intel Haswell" },
+ { HDA_CODEC_INTELBDW, 0, "Intel Broadwell" },
{ HDA_CODEC_INTELCL, 0, "Intel Crestline" },
{ HDA_CODEC_SII1390, 0, "Silicon Image SiI1390" },
{ HDA_CODEC_SII1392, 0, "Silicon Image SiI1392" },
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 68204ff..5b92963 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -48,6 +48,11 @@ SYSCTL_INT(_hw_snd, OID_AUTO, compat_linux_mmap, CTLFLAG_RWTUN,
&dsp_mmap_allow_prot_exec, 0,
"linux mmap compatibility (-1=force disable 0=auto 1=force enable)");
+static int dsp_basename_clone = 1;
+SYSCTL_INT(_hw_snd, OID_AUTO, basename_clone, CTLFLAG_RWTUN,
+ &dsp_basename_clone, 0,
+ "DSP basename cloning (0: Disable; 1: Enabled)");
+
struct dsp_cdevinfo {
struct pcm_channel *rdch, *wrch;
struct pcm_channel *volch;
@@ -2357,9 +2362,10 @@ dsp_clone(void *arg,
devname = devcmp;
devhw = dsp_cdevs[i].hw;
devcmax = dsp_cdevs[i].max - 1;
- if (strcmp(name, devcmp) == 0)
- unit = snd_unit;
- else if (dsp_stdclone(name, devcmp, devsep,
+ if (strcmp(name, devcmp) == 0) {
+ if (dsp_basename_clone != 0)
+ unit = snd_unit;
+ } else if (dsp_stdclone(name, devcmp, devsep,
dsp_cdevs[i].use_sep, &unit, &cunit) != 0) {
unit = -1;
cunit = -1;
diff --git a/sys/dev/streams/streams.c b/sys/dev/streams/streams.c
index 6a9219e..032d10c 100644
--- a/sys/dev/streams/streams.c
+++ b/sys/dev/streams/streams.c
@@ -180,7 +180,6 @@ MODULE_VERSION(streams, 1);
static int
streamsopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
- struct filedesc *fdp;
struct svr4_strm *st;
struct socket *so;
struct file *fp;
@@ -236,14 +235,13 @@ streamsopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
return EOPNOTSUPP;
}
- fdp = td->td_proc->p_fd;
if ((error = falloc(td, &fp, &fd, 0)) != 0)
return error;
/* An extra reference on `fp' has been held for us by falloc(). */
error = socreate(family, &so, type, protocol, td->td_ucred, td);
if (error) {
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
return error;
}
diff --git a/sys/dev/uart/uart_bus.h b/sys/dev/uart/uart_bus.h
index 322e9a8..7394651 100644
--- a/sys/dev/uart/uart_bus.h
+++ b/sys/dev/uart/uart_bus.h
@@ -70,6 +70,7 @@ struct uart_class {
struct uart_ops *uc_ops; /* Low-level console operations. */
u_int uc_range; /* Bus space address range. */
u_int uc_rclk; /* Default rclk for this device. */
+ u_int uc_rshift; /* Default regshift for this device. */
};
struct uart_softc {
diff --git a/sys/dev/uart/uart_bus_fdt.c b/sys/dev/uart/uart_bus_fdt.c
index 3c68d95..1498eb8 100644
--- a/sys/dev/uart/uart_bus_fdt.c
+++ b/sys/dev/uart/uart_bus_fdt.c
@@ -63,37 +63,29 @@ static driver_t uart_fdt_driver = {
sizeof(struct uart_softc),
};
-static int
+int
uart_fdt_get_clock(phandle_t node, pcell_t *cell)
{
- pcell_t clock;
-
- /*
- * clock-frequency is a FreeBSD-specific hack. Make its presence optional.
- */
- if ((OF_getprop(node, "clock-frequency", &clock,
- sizeof(clock))) <= 0)
- clock = 0;
- if (clock == 0)
+ /* clock-frequency is a FreeBSD-only extention. */
+ if ((OF_getencprop(node, "clock-frequency", cell,
+ sizeof(*cell))) <= 0) {
/* Try to retrieve parent 'bus-frequency' */
/* XXX this should go to simple-bus fixup or so */
- if ((OF_getprop(OF_parent(node), "bus-frequency", &clock,
- sizeof(clock))) <= 0)
- clock = 0;
+ if ((OF_getencprop(OF_parent(node), "bus-frequency", cell,
+ sizeof(*cell))) <= 0)
+ *cell = 0;
+ }
- *cell = fdt32_to_cpu(clock);
return (0);
}
-static int
+int
uart_fdt_get_shift(phandle_t node, pcell_t *cell)
{
- pcell_t shift;
- if ((OF_getprop(node, "reg-shift", &shift, sizeof(shift))) <= 0)
- shift = 0;
- *cell = fdt32_to_cpu(shift);
+ if ((OF_getencprop(node, "reg-shift", cell, sizeof(*cell))) <= 0)
+ return (-1);
return (0);
}
@@ -132,7 +124,8 @@ uart_fdt_probe(device_t dev)
if ((err = uart_fdt_get_clock(node, &clock)) != 0)
return (err);
- uart_fdt_get_shift(node, &shift);
+ if (uart_fdt_get_shift(node, &shift) != 0)
+ shift = uart_getregshift(sc->sc_class);
return (uart_bus_probe(dev, (int)shift, (int)clock, 0, 0));
}
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c
index eea2d8c..bbb06ff 100644
--- a/sys/dev/uart/uart_core.c
+++ b/sys/dev/uart/uart_core.c
@@ -88,6 +88,12 @@ uart_getrange(struct uart_class *uc)
return ((uc != NULL) ? uc->uc_range : 0);
}
+u_int
+uart_getregshift(struct uart_class *uc)
+{
+ return ((uc != NULL) ? uc->uc_rshift : 0);
+}
+
/*
* Schedule a soft interrupt. We do this on the 0 to !0 transition
* of the TTY pending interrupt status.
diff --git a/sys/dev/uart/uart_cpu.h b/sys/dev/uart/uart_cpu.h
index 2db0412..d9e5410 100644
--- a/sys/dev/uart/uart_cpu.h
+++ b/sys/dev/uart/uart_cpu.h
@@ -79,6 +79,7 @@ int uart_getenv(int, struct uart_devinfo *, struct uart_class *);
const char *uart_getname(struct uart_class *);
struct uart_ops *uart_getops(struct uart_class *);
int uart_getrange(struct uart_class *);
+u_int uart_getregshift(struct uart_class *);
void uart_add_sysdev(struct uart_devinfo *);
diff --git a/sys/dev/uart/uart_cpu_fdt.c b/sys/dev/uart/uart_cpu_fdt.c
index 8dfdb3c..344aad5 100644
--- a/sys/dev/uart/uart_cpu_fdt.c
+++ b/sys/dev/uart/uart_cpu_fdt.c
@@ -42,7 +42,9 @@ __FBSDID("$FreeBSD$");
#include <vm/pmap.h>
#include <machine/bus.h>
+#ifndef __aarch64__
#include <machine/fdt.h>
+#endif
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
@@ -52,44 +54,16 @@ __FBSDID("$FreeBSD$");
#include <dev/uart/uart_cpu.h>
#include <dev/uart/uart_cpu_fdt.h>
+#ifdef __aarch64__
+extern bus_space_tag_t fdtbus_bs_tag;
+#endif
+
/*
* UART console routines.
*/
bus_space_tag_t uart_bus_space_io;
bus_space_tag_t uart_bus_space_mem;
-static int
-uart_fdt_get_clock(phandle_t node, pcell_t *cell)
-{
- pcell_t clock;
-
- /* clock-frequency is a FreeBSD-only extention. */
- if ((OF_getprop(node, "clock-frequency", &clock,
- sizeof(clock))) <= 0)
- clock = 0;
-
- if (clock == 0)
- /* Try to retrieve parent 'bus-frequency' */
- /* XXX this should go to simple-bus fixup or so */
- if ((OF_getprop(OF_parent(node), "bus-frequency", &clock,
- sizeof(clock))) <= 0)
- clock = 0;
-
- *cell = fdt32_to_cpu(clock);
- return (0);
-}
-
-static int
-uart_fdt_get_shift(phandle_t node, pcell_t *cell)
-{
- pcell_t shift;
-
- if ((OF_getprop(node, "reg-shift", &shift, sizeof(shift))) <= 0)
- shift = 0;
- *cell = fdt32_to_cpu(shift);
- return (0);
-}
-
int
uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
{
@@ -191,15 +165,6 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
return (ENXIO);
/*
- * Retrieve serial attributes.
- */
- uart_fdt_get_shift(node, &shift);
- if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0)
- br = 0;
- else
- br = fdt32_to_cpu(br);
-
- /*
* Check old style of UART definition first. Unfortunately, the common
* FDT processing is not possible if we have clock, power domains and
* pinmux stuff.
@@ -218,6 +183,17 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
}
/*
+ * Retrieve serial attributes.
+ */
+ if (uart_fdt_get_shift(node, &shift) != 0)
+ shift = uart_getregshift(class);
+
+ if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0)
+ br = 0;
+ else
+ br = fdt32_to_cpu(br);
+
+ /*
* Finalize configuration.
*/
di->bas.chan = 0;
diff --git a/sys/dev/uart/uart_cpu_fdt.h b/sys/dev/uart/uart_cpu_fdt.h
index e7aaecd..b2f2920 100644
--- a/sys/dev/uart/uart_cpu_fdt.h
+++ b/sys/dev/uart/uart_cpu_fdt.h
@@ -50,5 +50,7 @@ SET_DECLARE(uart_fdt_class_set, struct ofw_compat_data );
#define UART_FDT_CLASS(data) \
DATA_SET(uart_fdt_class_set, data)
+int uart_fdt_get_clock(phandle_t node, pcell_t *cell);
+int uart_fdt_get_shift(phandle_t node, pcell_t *cell);
#endif /* _DEV_UART_CPU_FDT_H_ */
diff --git a/sys/dev/uart/uart_dev_imx.c b/sys/dev/uart/uart_dev_imx.c
index 9e34473..bc25df3 100644
--- a/sys/dev/uart/uart_dev_imx.c
+++ b/sys/dev/uart/uart_dev_imx.c
@@ -298,7 +298,8 @@ static struct uart_class uart_imx_class = {
sizeof(struct imx_uart_softc),
.uc_ops = &uart_imx_uart_ops,
.uc_range = 0x100,
- .uc_rclk = 24000000 /* TODO: get value from CCM */
+ .uc_rclk = 24000000, /* TODO: get value from CCM */
+ .uc_rshift = 0
};
static struct ofw_compat_data compat_data[] = {
diff --git a/sys/dev/uart/uart_dev_lpc.c b/sys/dev/uart/uart_dev_lpc.c
index 992e890..6cd10f1 100644
--- a/sys/dev/uart/uart_dev_lpc.c
+++ b/sys/dev/uart/uart_dev_lpc.c
@@ -428,7 +428,8 @@ static struct uart_class uart_lpc_class = {
sizeof(struct lpc_ns8250_softc),
.uc_ops = &uart_lpc_ns8250_ops,
.uc_range = 8,
- .uc_rclk = DEFAULT_RCLK
+ .uc_rclk = DEFAULT_RCLK,
+ .uc_rshift = 0
};
static struct ofw_compat_data compat_data[] = {
diff --git a/sys/dev/uart/uart_dev_msm.c b/sys/dev/uart/uart_dev_msm.c
index 114a415..7ba46ac 100644
--- a/sys/dev/uart/uart_dev_msm.c
+++ b/sys/dev/uart/uart_dev_msm.c
@@ -566,6 +566,7 @@ static struct uart_class uart_msm_class = {
.uc_ops = &uart_msm_ops,
.uc_range = 8,
.uc_rclk = DEF_CLK,
+ .uc_rshift = 0
};
static struct ofw_compat_data compat_data[] = {
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index 190ee29..9ff295a 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -378,7 +378,8 @@ struct uart_class uart_ns8250_class = {
sizeof(struct ns8250_softc),
.uc_ops = &uart_ns8250_ops,
.uc_range = 8,
- .uc_rclk = DEFAULT_RCLK
+ .uc_rclk = DEFAULT_RCLK,
+ .uc_rshift = 0
};
#ifdef FDT
diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c
index 8443adb..e90e7f8 100644
--- a/sys/dev/uart/uart_dev_pl011.c
+++ b/sys/dev/uart/uart_dev_pl011.c
@@ -273,7 +273,8 @@ static struct uart_class uart_pl011_class = {
sizeof(struct uart_pl011_softc),
.uc_ops = &uart_pl011_ops,
.uc_range = 0x48,
- .uc_rclk = 0
+ .uc_rclk = 0,
+ .uc_rshift = 2
};
static struct ofw_compat_data compat_data[] = {
diff --git a/sys/dev/uart/uart_dev_quicc.c b/sys/dev/uart/uart_dev_quicc.c
index bbbc3bd..0237d64 100644
--- a/sys/dev/uart/uart_dev_quicc.c
+++ b/sys/dev/uart/uart_dev_quicc.c
@@ -271,7 +271,8 @@ struct uart_class uart_quicc_class = {
sizeof(struct quicc_softc),
.uc_ops = &uart_quicc_ops,
.uc_range = 2,
- .uc_rclk = DEFAULT_RCLK
+ .uc_rclk = DEFAULT_RCLK,
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/dev/uart/uart_dev_sab82532.c b/sys/dev/uart/uart_dev_sab82532.c
index 8caa7a7..59a9639 100644
--- a/sys/dev/uart/uart_dev_sab82532.c
+++ b/sys/dev/uart/uart_dev_sab82532.c
@@ -391,7 +391,8 @@ struct uart_class uart_sab82532_class = {
sizeof(struct sab82532_softc),
.uc_ops = &uart_sab82532_ops,
.uc_range = 64,
- .uc_rclk = DEFAULT_RCLK
+ .uc_rclk = DEFAULT_RCLK,
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/dev/uart/uart_dev_ti8250.c b/sys/dev/uart/uart_dev_ti8250.c
index daddbb7..373dc74 100644
--- a/sys/dev/uart/uart_dev_ti8250.c
+++ b/sys/dev/uart/uart_dev_ti8250.c
@@ -137,7 +137,8 @@ static struct uart_class uart_ti8250_class = {
sizeof(struct ti8250_softc),
.uc_ops = &uart_ns8250_ops,
.uc_range = 0x88,
- .uc_rclk = 48000000
+ .uc_rclk = 48000000,
+ .uc_rshift = 0
};
static struct ofw_compat_data compat_data[] = {
{"ti,ns16550", (uintptr_t)&uart_ti8250_class},
diff --git a/sys/dev/uart/uart_dev_z8530.c b/sys/dev/uart/uart_dev_z8530.c
index 5cc24a8..5bacd40 100644
--- a/sys/dev/uart/uart_dev_z8530.c
+++ b/sys/dev/uart/uart_dev_z8530.c
@@ -307,7 +307,8 @@ struct uart_class uart_z8530_class = {
sizeof(struct z8530_softc),
.uc_ops = &uart_z8530_ops,
.uc_range = 2,
- .uc_rclk = DEFAULT_RCLK
+ .uc_rclk = DEFAULT_RCLK,
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c
index 05d2f71..37b5333 100644
--- a/sys/dev/usb/controller/dwc_otg.c
+++ b/sys/dev/usb/controller/dwc_otg.c
@@ -3876,20 +3876,18 @@ dwc_otg_init(struct dwc_otg_softc *sc)
if (temp & GHWCFG2_MPI) {
uint8_t x;
- DPRINTF("Multi Process Interrupts\n");
+ DPRINTF("Disable Multi Process Interrupts\n");
for (x = 0; x != sc->sc_dev_in_ep_max; x++) {
- DWC_OTG_WRITE_4(sc, DOTG_DIEPEACHINTMSK(x),
- DIEPMSK_XFERCOMPLMSK);
+ DWC_OTG_WRITE_4(sc, DOTG_DIEPEACHINTMSK(x), 0);
DWC_OTG_WRITE_4(sc, DOTG_DOEPEACHINTMSK(x), 0);
}
- DWC_OTG_WRITE_4(sc, DOTG_DEACHINTMSK, 0xFFFF);
- } else {
- DWC_OTG_WRITE_4(sc, DOTG_DIEPMSK,
- DIEPMSK_XFERCOMPLMSK);
- DWC_OTG_WRITE_4(sc, DOTG_DOEPMSK, 0);
- DWC_OTG_WRITE_4(sc, DOTG_DAINTMSK, 0xFFFF);
+ DWC_OTG_WRITE_4(sc, DOTG_DEACHINTMSK, 0);
}
+ DWC_OTG_WRITE_4(sc, DOTG_DIEPMSK,
+ DIEPMSK_XFERCOMPLMSK);
+ DWC_OTG_WRITE_4(sc, DOTG_DOEPMSK, 0);
+ DWC_OTG_WRITE_4(sc, DOTG_DAINTMSK, 0xFFFF);
}
if (sc->sc_mode == DWC_MODE_OTG || sc->sc_mode == DWC_MODE_HOST) {
diff --git a/sys/dev/usb/controller/ehci_pci.c b/sys/dev/usb/controller/ehci_pci.c
index b71fb41..9b862a5 100644
--- a/sys/dev/usb/controller/ehci_pci.c
+++ b/sys/dev/usb/controller/ehci_pci.c
@@ -220,7 +220,7 @@ ehci_pci_probe(device_t self)
if (desc) {
device_set_desc(self, desc);
- return (0);
+ return (BUS_PROBE_DEFAULT);
} else {
return (ENXIO);
}
diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c
index 4ac0d54..89fc983 100644
--- a/sys/dev/usb/controller/uhci_pci.c
+++ b/sys/dev/usb/controller/uhci_pci.c
@@ -244,7 +244,7 @@ uhci_pci_probe(device_t self)
if (desc) {
device_set_desc(self, desc);
- return (0);
+ return (BUS_PROBE_DEFAULT);
} else {
return (ENXIO);
}
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
index c2367f4..0e2c632 100644
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -131,7 +131,7 @@ xhci_pci_probe(device_t self)
if (desc) {
device_set_desc(self, desc);
- return (0);
+ return (BUS_PROBE_DEFAULT);
} else {
return (ENXIO);
}
diff --git a/sys/dev/usb/net/if_axge.c b/sys/dev/usb/net/if_axge.c
index f21b67e..2c695cd 100644
--- a/sys/dev/usb/net/if_axge.c
+++ b/sys/dev/usb/net/if_axge.c
@@ -67,6 +67,7 @@ static const STRUCT_USB_HOST_ID axge_devs[] = {
AXGE_DEV(ASIX, AX88178A),
AXGE_DEV(ASIX, AX88179),
AXGE_DEV(DLINK, DUB1312),
+ AXGE_DEV(LENOVO, GIGALAN),
AXGE_DEV(SITECOMEU, LN032),
#undef AXGE_DEV
};
diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c
index a08ce48..0159520 100644
--- a/sys/dev/usb/serial/uftdi.c
+++ b/sys/dev/usb/serial/uftdi.c
@@ -1701,7 +1701,7 @@ uftdi_get_bitmode(struct ucom_softc *ucom, uint8_t *iomask)
struct uftdi_softc *sc = ucom->sc_parent;
usb_device_request_t req;
- req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_GET_BITMODE;
USETW(req.wIndex, sc->sc_ucom.sc_portno);
@@ -1738,7 +1738,7 @@ uftdi_get_latency(struct ucom_softc *ucom, int *latency)
usb_error_t err;
uint8_t buf;
- req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_GET_LATENCY;
USETW(req.wIndex, sc->sc_ucom.sc_portno);
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 7959cb4..d972bdc 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -2627,6 +2627,7 @@ product LARSENBRUSGAARD ALTITRACK 0x0001 FTDI compatible adapter
product LEADTEK 9531 0x2101 9531 GPS
/* Lenovo products */
+product LENOVO GIGALAN 0x304b USB 3.0 Ethernet
product LENOVO ETHERNET 0x7203 USB 2.0 Ethernet
/* Lexar products */
@@ -3016,11 +3017,12 @@ product MELCO WLRUCG 0x0116 WLR-UC-G
product MELCO WLRUCGAOSS 0x0119 WLR-UC-G-AOSS
product MELCO WLIUCAG300N 0x012e WLI-UC-AG300N
product MELCO WLIUCG 0x0137 WLI-UC-G
-product MELCO RT2870_1 0x0148 RT2870
+product MELCO WLIUCG300HP 0x0148 WLI-UC-G300HP
product MELCO RT2870_2 0x0150 RT2870
product MELCO WLIUCGN 0x015d WLI-UC-GN
product MELCO WLIUCG301N 0x016f WLI-UC-G301N
product MELCO WLIUCGNM 0x01a2 WLI-UC-GNM
+product MELCO WLIUCG300HPV1 0x01a8 WLI-UC-G300HP-V1
product MELCO WLIUCGNM2 0x01ee WLI-UC-GNM2
/* Merlin products */
@@ -3753,6 +3755,7 @@ product REALTEK RTL8188CU_1 0x817a RTL8188CU
product REALTEK RTL8188CU_2 0x817b RTL8188CU
product REALTEK RTL8187 0x8187 RTL8187 Wireless Adapter
product REALTEK RTL8187B_0 0x8189 RTL8187B Wireless Adapter
+product REALTEK RTL8188CU_3 0x8191 RTL8188CU
product REALTEK RTL8196EU 0x8196 RTL8196EU
product REALTEK RTL8187B_1 0x8197 RTL8187B Wireless Adapter
product REALTEK RTL8187B_2 0x8198 RTL8187B Wireless Adapter
diff --git a/sys/dev/usb/video/udl.c b/sys/dev/usb/video/udl.c
index 10762e1..69e2429 100644
--- a/sys/dev/usb/video/udl.c
+++ b/sys/dev/usb/video/udl.c
@@ -76,6 +76,11 @@ static int udl_fps = 25;
SYSCTL_INT(_hw_usb_udl, OID_AUTO, fps, CTLFLAG_RWTUN,
&udl_fps, 0, "Frames Per Second, 1-60");
+static struct mtx udl_buffer_mtx;
+static struct udl_buffer_head udl_buffer_head;
+
+MALLOC_DEFINE(M_USB_DL, "USB", "USB DisplayLink");
+
/*
* Prototypes.
*/
@@ -175,6 +180,56 @@ static const STRUCT_USB_HOST_ID udl_devs[] = {
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)}
};
+static void
+udl_buffer_init(void *arg)
+{
+ mtx_init(&udl_buffer_mtx, "USB", "UDL", MTX_DEF);
+ TAILQ_INIT(&udl_buffer_head);
+}
+SYSINIT(udl_buffer_init, SI_SUB_LOCK, SI_ORDER_FIRST, udl_buffer_init, NULL);
+
+CTASSERT(sizeof(struct udl_buffer) < PAGE_SIZE);
+
+static void *
+udl_buffer_alloc(uint32_t size)
+{
+ struct udl_buffer *buf;
+ mtx_lock(&udl_buffer_mtx);
+ TAILQ_FOREACH(buf, &udl_buffer_head, entry) {
+ if (buf->size == size) {
+ TAILQ_REMOVE(&udl_buffer_head, buf, entry);
+ break;
+ }
+ }
+ mtx_unlock(&udl_buffer_mtx);
+ if (buf != NULL) {
+ /* wipe and recycle buffer */
+ memset(buf, 0, size);
+ return (buf);
+ }
+ /* allocate new buffer */
+ return (malloc(size, M_USB_DL, M_WAITOK | M_ZERO));
+}
+
+static void
+udl_buffer_free(void *_buf, uint32_t size)
+{
+ struct udl_buffer *buf;
+
+ buf = (struct udl_buffer *)_buf;
+ if (buf == NULL)
+ return;
+
+ /*
+ * Memory mapped buffers should never be freed.
+ * Put display buffer into a recycle list.
+ */
+ mtx_lock(&udl_buffer_mtx);
+ buf->size = size;
+ TAILQ_INSERT_TAIL(&udl_buffer_head, buf, entry);
+ mtx_unlock(&udl_buffer_mtx);
+}
+
static uint32_t
udl_get_fb_size(struct udl_softc *sc)
{
@@ -403,11 +458,11 @@ udl_detach(device_t dev)
mtx_destroy(&sc->sc_mtx);
cv_destroy(&sc->sc_cv);
- /*
- * Free framebuffer memory, if any.
- */
- free(sc->sc_fb_addr, M_DEVBUF);
- free(sc->sc_fb_copy, M_DEVBUF);
+ /* put main framebuffer into a recycle list, if any */
+ udl_buffer_free(sc->sc_fb_addr, sc->sc_fb_size);
+
+ /* free shadow framebuffer memory, if any */
+ free(sc->sc_fb_copy, M_USB_DL);
return (0);
}
@@ -782,13 +837,15 @@ udl_fbmem_alloc(struct udl_softc *sc)
size = udl_get_fb_size(sc);
size = round_page(size);
-
+ /* check for zero size */
+ if (size == 0)
+ size = PAGE_SIZE;
/*
* It is assumed that allocations above PAGE_SIZE bytes will
* be PAGE_SIZE aligned for use with mmap()
*/
- sc->sc_fb_addr = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
- sc->sc_fb_copy = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
+ sc->sc_fb_addr = udl_buffer_alloc(size);
+ sc->sc_fb_copy = malloc(size, M_USB_DL, M_WAITOK | M_ZERO);
sc->sc_fb_size = size;
}
@@ -1025,8 +1082,7 @@ udl_select_mode(struct udl_softc *sc)
}
if (index == UDL_MAX_MODES) {
- DPRINTF("no mode line found for %dx%d @ %dHz!\n",
- mode.hdisplay, mode.vdisplay, mode.hz);
+ DPRINTF("no mode line found\n");
i = 0;
while (i < sc->sc_edid_info.edid_nmodes) {
diff --git a/sys/dev/usb/video/udl.h b/sys/dev/usb/video/udl.h
index 1fdae7a..a7d5069 100644
--- a/sys/dev/usb/video/udl.h
+++ b/sys/dev/usb/video/udl.h
@@ -34,6 +34,15 @@
#define UDL_FONT_HEIGHT 16 /* pixels */
#define UDL_MAX_MODES 25 /* units */
+MALLOC_DECLARE(M_USB_DL);
+
+struct udl_buffer {
+ TAILQ_ENTRY(udl_buffer) entry;
+ uint32_t size;
+};
+
+TAILQ_HEAD(udl_buffer_head, udl_buffer);
+
struct udl_cmd_buf {
TAILQ_ENTRY(udl_cmd_buf) entry;
uint32_t off;
diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c
index 3112ce5..22cc180 100644
--- a/sys/dev/usb/wlan/if_run.c
+++ b/sys/dev/usb/wlan/if_run.c
@@ -225,13 +225,14 @@ static const STRUCT_USB_HOST_ID run_devs[] = {
RUN_DEV(LOGITEC, LANW300NU2),
RUN_DEV(LOGITEC, LANW150NU2),
RUN_DEV(LOGITEC, LANW300NU2S),
- RUN_DEV(MELCO, RT2870_1),
+ RUN_DEV(MELCO, WLIUCG300HP),
RUN_DEV(MELCO, RT2870_2),
RUN_DEV(MELCO, WLIUCAG300N),
RUN_DEV(MELCO, WLIUCG300N),
RUN_DEV(MELCO, WLIUCG301N),
RUN_DEV(MELCO, WLIUCGN),
RUN_DEV(MELCO, WLIUCGNM),
+ RUN_DEV(MELCO, WLIUCG300HPV1),
RUN_DEV(MELCO, WLIUCGNM2),
RUN_DEV(MOTOROLA4, RT2770),
RUN_DEV(MOTOROLA4, RT3070),
diff --git a/sys/dev/usb/wlan/if_urtwn.c b/sys/dev/usb/wlan/if_urtwn.c
index 38fbef4..72004d9 100644
--- a/sys/dev/usb/wlan/if_urtwn.c
+++ b/sys/dev/usb/wlan/if_urtwn.c
@@ -137,6 +137,7 @@ static const STRUCT_USB_HOST_ID urtwn_devs[] = {
URTWN_DEV(REALTEK, RTL8188CU_0),
URTWN_DEV(REALTEK, RTL8188CU_1),
URTWN_DEV(REALTEK, RTL8188CU_2),
+ URTWN_DEV(REALTEK, RTL8188CU_3),
URTWN_DEV(REALTEK, RTL8188CU_COMBO),
URTWN_DEV(REALTEK, RTL8188CUS),
URTWN_DEV(REALTEK, RTL8188RU_1),
@@ -145,7 +146,6 @@ static const STRUCT_USB_HOST_ID urtwn_devs[] = {
URTWN_DEV(REALTEK, RTL8191CU),
URTWN_DEV(REALTEK, RTL8192CE),
URTWN_DEV(REALTEK, RTL8192CU),
- URTWN_DEV(REALTEK, RTL8188CU_0),
URTWN_DEV(SITECOMEU, RTL8188CU_1),
URTWN_DEV(SITECOMEU, RTL8188CU_2),
URTWN_DEV(SITECOMEU, RTL8192CU),
@@ -176,12 +176,12 @@ static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *,
const uint8_t [IEEE80211_ADDR_LEN],
const uint8_t [IEEE80211_ADDR_LEN]);
static void urtwn_vap_delete(struct ieee80211vap *);
-static struct mbuf * urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int,
+static struct mbuf * urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int,
int *);
-static struct mbuf * urtwn_rxeof(struct usb_xfer *, struct urtwn_data *,
+static struct mbuf * urtwn_rxeof(struct usb_xfer *, struct urtwn_data *,
int *, int8_t *);
static void urtwn_txeof(struct usb_xfer *, struct urtwn_data *);
-static int urtwn_alloc_list(struct urtwn_softc *,
+static int urtwn_alloc_list(struct urtwn_softc *,
struct urtwn_data[], int, int);
static int urtwn_alloc_rx_list(struct urtwn_softc *);
static int urtwn_alloc_tx_list(struct urtwn_softc *);
@@ -191,24 +191,24 @@ static void urtwn_free_list(struct urtwn_softc *,
struct urtwn_data data[], int);
static struct urtwn_data * _urtwn_getbuf(struct urtwn_softc *);
static struct urtwn_data * urtwn_getbuf(struct urtwn_softc *);
-static int urtwn_write_region_1(struct urtwn_softc *, uint16_t,
+static int urtwn_write_region_1(struct urtwn_softc *, uint16_t,
uint8_t *, int);
static void urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t);
static void urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t);
static void urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t);
-static int urtwn_read_region_1(struct urtwn_softc *, uint16_t,
+static int urtwn_read_region_1(struct urtwn_softc *, uint16_t,
uint8_t *, int);
static uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t);
static uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t);
static uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t);
-static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t,
+static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t,
const void *, int);
static void urtwn_r92c_rf_write(struct urtwn_softc *, int,
uint8_t, uint32_t);
-static void urtwn_r88e_rf_write(struct urtwn_softc *, int,
+static void urtwn_r88e_rf_write(struct urtwn_softc *, int,
uint8_t, uint32_t);
static uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t);
-static int urtwn_llt_write(struct urtwn_softc *, uint32_t,
+static int urtwn_llt_write(struct urtwn_softc *, uint32_t,
uint32_t);
static uint8_t urtwn_efuse_read_1(struct urtwn_softc *, uint16_t);
static void urtwn_efuse_read(struct urtwn_softc *);
@@ -219,7 +219,7 @@ static void urtwn_r88e_read_rom(struct urtwn_softc *);
static int urtwn_ra_init(struct urtwn_softc *);
static void urtwn_tsf_sync_enable(struct urtwn_softc *);
static void urtwn_set_led(struct urtwn_softc *, int, int);
-static int urtwn_newstate(struct ieee80211vap *,
+static int urtwn_newstate(struct ieee80211vap *,
enum ieee80211_state, int);
static void urtwn_watchdog(void *);
static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t);
@@ -237,7 +237,7 @@ static int urtwn_r88e_power_on(struct urtwn_softc *);
static int urtwn_llt_init(struct urtwn_softc *);
static void urtwn_fw_reset(struct urtwn_softc *);
static void urtwn_r88e_fw_reset(struct urtwn_softc *);
-static int urtwn_fw_loadpage(struct urtwn_softc *, int,
+static int urtwn_fw_loadpage(struct urtwn_softc *, int,
const uint8_t *, int);
static int urtwn_load_firmware(struct urtwn_softc *);
static int urtwn_r92c_dma_init(struct urtwn_softc *);
@@ -249,22 +249,22 @@ static void urtwn_cam_init(struct urtwn_softc *);
static void urtwn_pa_bias_init(struct urtwn_softc *);
static void urtwn_rxfilter_init(struct urtwn_softc *);
static void urtwn_edca_init(struct urtwn_softc *);
-static void urtwn_write_txpower(struct urtwn_softc *, int,
+static void urtwn_write_txpower(struct urtwn_softc *, int,
uint16_t[]);
static void urtwn_get_txpower(struct urtwn_softc *, int,
- struct ieee80211_channel *,
+ struct ieee80211_channel *,
struct ieee80211_channel *, uint16_t[]);
static void urtwn_r88e_get_txpower(struct urtwn_softc *, int,
- struct ieee80211_channel *,
+ struct ieee80211_channel *,
struct ieee80211_channel *, uint16_t[]);
static void urtwn_set_txpower(struct urtwn_softc *,
- struct ieee80211_channel *,
+ struct ieee80211_channel *,
struct ieee80211_channel *);
static void urtwn_scan_start(struct ieee80211com *);
static void urtwn_scan_end(struct ieee80211com *);
static void urtwn_set_channel(struct ieee80211com *);
static void urtwn_set_chan(struct urtwn_softc *,
- struct ieee80211_channel *,
+ struct ieee80211_channel *,
struct ieee80211_channel *);
static void urtwn_update_mcast(struct ifnet *);
static void urtwn_iq_calib(struct urtwn_softc *);
@@ -470,7 +470,7 @@ urtwn_attach(device_t self)
ic->ic_vap_delete = urtwn_vap_delete;
ic->ic_update_mcast = urtwn_update_mcast;
- ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
+ ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT,
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
URTWN_RX_RADIOTAP_PRESENT);
@@ -492,7 +492,7 @@ urtwn_detach(device_t self)
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
unsigned int x;
-
+
/* Prevent further ioctls. */
URTWN_LOCK(sc);
sc->sc_flags |= URTWN_DETACHED;
@@ -604,7 +604,7 @@ urtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
vap = &uvp->vap;
/* enable s/w bmiss handling for sta mode */
- if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
+ if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) {
/* out of memory */
free(uvp, M_80211_VAP);
@@ -673,7 +673,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p)
/* Get RSSI from PHY status descriptor if present. */
if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
- if (sc->chip & URTWN_CHIP_88E)
+ if (sc->chip & URTWN_CHIP_88E)
rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]);
else
rssi = urtwn_get_rssi(sc, rate, &stat[1]);
@@ -1184,7 +1184,7 @@ urtwn_efuse_read_1(struct urtwn_softc *sc, uint16_t addr)
return (MS(reg, R92C_EFUSE_CTRL_DATA));
urtwn_ms_delay(sc);
}
- device_printf(sc->sc_dev,
+ device_printf(sc->sc_dev,
"could not read efuse byte at address 0x%x\n", addr);
return (0xff);
}
@@ -1195,7 +1195,7 @@ urtwn_efuse_read(struct urtwn_softc *sc)
uint8_t *rom = (uint8_t *)&sc->rom;
uint16_t addr = 0;
uint32_t reg;
- uint8_t off, msk;
+ uint8_t off, msk, vol;
int i;
urtwn_efuse_switch_power(sc);
@@ -1228,12 +1228,19 @@ urtwn_efuse_read(struct urtwn_softc *sc)
printf("\n");
}
#endif
+ /* Disable LDO 2.5V. */
+ vol = urtwn_read_1(sc, R92C_EFUSE_TEST + 3);
+ urtwn_write_1(sc, R92C_EFUSE_TEST + 3, vol & ~(0x80));
+
}
static void
urtwn_efuse_switch_power(struct urtwn_softc *sc)
{
uint32_t reg;
+ if (sc->chip & URTWN_CHIP_88E)
+ urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON);
+
reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL);
if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
urtwn_write_2(sc, R92C_SYS_ISO_CTRL,
@@ -1250,6 +1257,16 @@ urtwn_efuse_switch_power(struct urtwn_softc *sc)
urtwn_write_2(sc, R92C_SYS_CLKR,
reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
}
+
+ if (!(sc->chip & URTWN_CHIP_88E)) {
+ uint8_t vol;
+
+ /* Enable LDO 2.5V. */
+ vol = urtwn_read_1(sc, R92C_EFUSE_TEST + 3);
+ vol &= 0x0f;
+ vol |= 0x30;
+ urtwn_write_1(sc, R92C_EFUSE_TEST + 3, (vol | 0x80));
+ }
}
static int
@@ -1317,7 +1334,7 @@ urtwn_r88e_read_rom(struct urtwn_softc *sc)
/* Read full ROM image. */
memset(&sc->r88e_rom, 0xff, sizeof(sc->r88e_rom));
- while (addr < 1024) {
+ while (addr < 512) {
reg = urtwn_efuse_read_1(sc, addr);
if (reg == 0xff)
break;
@@ -1343,6 +1360,8 @@ urtwn_r88e_read_rom(struct urtwn_softc *sc)
}
}
+ urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF);
+
addr = 0x10;
for (i = 0; i < 6; i++)
sc->cck_tx_pwr[i] = sc->r88e_rom[addr++];
@@ -1477,7 +1496,7 @@ static void
urtwn_set_led(struct urtwn_softc *sc, int led, int on)
{
uint8_t reg;
-
+
if (led == URTWN_LED_LINK) {
if (sc->chip & URTWN_CHIP_88E) {
reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0xf0;
@@ -1568,14 +1587,9 @@ urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
}
}
- /* Make link LED blink during scan. */
- urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink);
-
/* Pause AC Tx queues. */
urtwn_write_1(sc, R92C_TXPAUSE,
urtwn_read_1(sc, R92C_TXPAUSE) | 0x0f);
-
- urtwn_set_chan(sc, ic->ic_curchan, NULL);
break;
case IEEE80211_S_AUTH:
/* Set initial gain under link. */
@@ -1643,7 +1657,7 @@ urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
if (sc->chip & URTWN_CHIP_88E)
ni->ni_txrate =
ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates-1];
- else
+ else
urtwn_ra_init(sc);
/* Turn link LED on. */
urtwn_set_led(sc, URTWN_LED_LINK, 1);
@@ -1754,7 +1768,7 @@ urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
cck = (struct r88e_rx_cck *)physt;
cck_agc_rpt = cck->agc_rpt;
lna_idx = (cck_agc_rpt & 0xe0) >> 5;
- vga_idx = cck_agc_rpt & 0x1f;
+ vga_idx = cck_agc_rpt & 0x1f;
switch (lna_idx) {
case 7:
if (vga_idx <= 27)
@@ -1794,7 +1808,7 @@ urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
static int
-urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
+urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
struct mbuf *m0, struct urtwn_data *data)
{
struct ifnet *ifp = sc->sc_ifp;
@@ -1835,7 +1849,7 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
/* in case packet header moved, reset pointer */
wh = mtod(m0, struct ieee80211_frame *);
}
-
+
switch (type) {
case IEEE80211_FC0_TYPE_CTL:
case IEEE80211_FC0_TYPE_MGT:
@@ -1847,7 +1861,7 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
xfer = urtwn_pipes[M_WME_GETAC(m0)];
break;
}
-
+
hasqos = 0;
/* Fill Tx descriptor. */
@@ -2187,14 +2201,12 @@ urtwn_r92c_power_on(struct urtwn_softc *sc)
static int
urtwn_r88e_power_on(struct urtwn_softc *sc)
{
- uint8_t val;
uint32_t reg;
int ntries;
/* Wait for power ready bit. */
for (ntries = 0; ntries < 5000; ntries++) {
- val = urtwn_read_1(sc, 0x6) & 0x2;
- if (val == 0x2)
+ if (urtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST)
break;
urtwn_ms_delay(sc);
}
@@ -2209,17 +2221,23 @@ urtwn_r88e_power_on(struct urtwn_softc *sc)
urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB |
R92C_SYS_FUNC_EN_BB_GLB_RST));
- urtwn_write_1(sc, 0x26, urtwn_read_1(sc, 0x26) | 0x80);
+ urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2,
+ urtwn_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80);
/* Disable HWPDN. */
- urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) & ~0x80);
+ urtwn_write_2(sc, R92C_APS_FSMCO,
+ urtwn_read_2(sc, R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN);
/* Disable WL suspend. */
- urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) & ~0x18);
+ urtwn_write_2(sc, R92C_APS_FSMCO,
+ urtwn_read_2(sc, R92C_APS_FSMCO) &
+ ~(R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE));
- urtwn_write_1(sc, 0x5, urtwn_read_1(sc, 0x5) | 0x1);
+ urtwn_write_2(sc, R92C_APS_FSMCO,
+ urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
for (ntries = 0; ntries < 5000; ntries++) {
- if (!(urtwn_read_1(sc, 0x5) & 0x1))
+ if (!(urtwn_read_2(sc, R92C_APS_FSMCO) &
+ R92C_APS_FSMCO_APFM_ONMAC))
break;
urtwn_ms_delay(sc);
}
@@ -2227,7 +2245,8 @@ urtwn_r88e_power_on(struct urtwn_softc *sc)
return (ETIMEDOUT);
/* Enable LDO normal mode. */
- urtwn_write_1(sc, 0x23, urtwn_read_1(sc, 0x23) & ~0x10);
+ urtwn_write_1(sc, R92C_LPLDO_CTRL,
+ urtwn_read_1(sc, R92C_LPLDO_CTRL) & ~0x10);
/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
urtwn_write_2(sc, R92C_CR, 0);
@@ -2320,7 +2339,7 @@ urtwn_fw_loadpage(struct urtwn_softc *sc, int page, const uint8_t *buf, int len)
else
mlen = 1;
/* XXX fix this deconst */
- error = urtwn_write_region_1(sc, off,
+ error = urtwn_write_region_1(sc, off,
__DECONST(uint8_t *, buf), mlen);
if (error != 0)
break;
@@ -2455,7 +2474,7 @@ fail:
static __inline int
urtwn_dma_init(struct urtwn_softc *sc)
{
-
+
return sc->sc_dma_init(sc);
}
@@ -2559,7 +2578,6 @@ urtwn_r88e_dma_init(struct urtwn_softc *sc)
return (EIO);
/* Set number of pages for normal priority queue. */
- urtwn_write_2(sc, R92C_RQPN_NPQ, 0);
urtwn_write_2(sc, R92C_RQPN_NPQ, 0x000d);
urtwn_write_4(sc, R92C_RQPN, 0x808e000d);
@@ -3131,8 +3149,13 @@ static void
urtwn_set_channel(struct ieee80211com *ic)
{
struct urtwn_softc *sc = ic->ic_ifp->if_softc;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
URTWN_LOCK(sc);
+ if (vap->iv_state == IEEE80211_S_SCAN) {
+ /* Make link LED blink during scan. */
+ urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink);
+ }
urtwn_set_chan(sc, ic->ic_curchan, NULL);
URTWN_UNLOCK(sc);
}
@@ -3219,10 +3242,10 @@ urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c,
urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) |
R92C_FPGA0_ANAPARAM2_CBW20);
}
-
+
/* Select 20MHz bandwidth. */
urtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
- (sc->rf_chnlbw[0] & ~0xfff) | chan |
+ (sc->rf_chnlbw[0] & ~0xfff) | chan |
((sc->chip & URTWN_CHIP_88E) ? R88E_RF_CHNLBW_BW20 :
R92C_RF_CHNLBW_BW20));
}
@@ -3297,7 +3320,7 @@ urtwn_init_locked(void *arg)
error = urtwn_alloc_rx_list(sc);
if (error != 0)
goto fail;
-
+
error = urtwn_alloc_tx_list(sc);
if (error != 0)
goto fail;
@@ -3373,16 +3396,17 @@ urtwn_init_locked(void *arg)
urtwn_write_1(sc, R92C_TRXDMA_CTRL,
urtwn_read_1(sc, R92C_TRXDMA_CTRL) |
R92C_TRXDMA_CTRL_RXDMA_AGG_EN);
- urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION,
- urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) |
- R92C_USB_SPECIAL_OPTION_AGG_EN);
urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48);
if (sc->chip & URTWN_CHIP_88E)
urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4);
- else
+ else {
urtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4);
- urtwn_write_1(sc, R92C_USB_AGG_TH, 8);
- urtwn_write_1(sc, R92C_USB_AGG_TO, 6);
+ urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION,
+ urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) |
+ R92C_USB_SPECIAL_OPTION_AGG_EN);
+ urtwn_write_1(sc, R92C_USB_AGG_TH, 8);
+ urtwn_write_1(sc, R92C_USB_AGG_TO, 6);
+ }
/* Initialize beacon parameters. */
urtwn_write_2(sc, R92C_BCN_CTRL, 0x1010);
diff --git a/sys/dev/virtio/block/virtio_blk.c b/sys/dev/virtio/block/virtio_blk.c
index 28a363b..0cfebf1 100644
--- a/sys/dev/virtio/block/virtio_blk.c
+++ b/sys/dev/virtio/block/virtio_blk.c
@@ -710,7 +710,8 @@ vtblk_alloc_disk(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg)
dp->d_fwheads = blkcfg->geometry.heads;
}
- if (virtio_with_feature(dev, VIRTIO_BLK_F_TOPOLOGY)) {
+ if (virtio_with_feature(dev, VIRTIO_BLK_F_TOPOLOGY) &&
+ blkcfg->topology.physical_block_exp > 0) {
dp->d_stripesize = dp->d_sectorsize *
(1 << blkcfg->topology.physical_block_exp);
dp->d_stripeoffset = (dp->d_stripesize -
diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c
index 39fc28d..704a3d9 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -2745,6 +2745,11 @@ vtnet_drain_rxtx_queues(struct vtnet_softc *sc)
struct vtnet_txq *txq;
int i;
+#ifdef DEV_NETMAP
+ if (nm_native_on(NA(sc->vtnet_ifp)))
+ return;
+#endif /* DEV_NETMAP */
+
for (i = 0; i < sc->vtnet_act_vq_pairs; i++) {
rxq = &sc->vtnet_rxqs[i];
vtnet_rxq_free_mbufs(rxq);
diff --git a/sys/dev/vt/hw/fb/vt_fb.c b/sys/dev/vt/hw/fb/vt_fb.c
index 40f56fc..b2babd1 100644
--- a/sys/dev/vt/hw/fb/vt_fb.c
+++ b/sys/dev/vt/hw/fb/vt_fb.c
@@ -264,46 +264,40 @@ vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
{
struct fb_info *info;
uint32_t fgc, bgc, cc, o;
- int c, l, bpp, bpl;
- u_long line;
- uint8_t b, m;
- const uint8_t *ch;
+ int bpp, bpl, xi, yi;
+ int bit, byte;
info = vd->vd_softc;
bpp = FBTYPE_GET_BYTESPP(info);
fgc = info->fb_cmap[fg];
bgc = info->fb_cmap[bg];
- b = m = 0;
- bpl = (width + 7) >> 3; /* Bytes per source line. */
+ bpl = (width + 7) / 8; /* Bytes per source line. */
if (info->fb_flags & FB_FLAG_NOWRITE)
return;
KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
- line = (info->fb_stride * y) + (x * bpp);
- for (l = 0;
- l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
- l++) {
- ch = pattern;
- for (c = 0;
- c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
- c++) {
- if (c % 8 == 0)
- b = *ch++;
- else
- b <<= 1;
- if (mask != NULL) {
- if (c % 8 == 0)
- m = *mask++;
- else
- m <<= 1;
- /* Skip pixel write, if mask has no bit set. */
- if ((m & 0x80) == 0)
- continue;
- }
- o = line + (c * bpp);
- cc = b & 0x80 ? fgc : bgc;
+ /* Bound by right and bottom edges. */
+ if (y + height > vw->vw_draw_area.tr_end.tp_row) {
+ if (y >= vw->vw_draw_area.tr_end.tp_row)
+ return;
+ height = vw->vw_draw_area.tr_end.tp_row - y;
+ }
+ if (x + width > vw->vw_draw_area.tr_end.tp_col) {
+ if (x >= vw->vw_draw_area.tr_end.tp_col)
+ return;
+ width = vw->vw_draw_area.tr_end.tp_col - x;
+ }
+ for (yi = 0; yi < height; yi++) {
+ for (xi = 0; xi < width; xi++) {
+ byte = yi * bpl + xi / 8;
+ bit = 0x80 >> (xi % 8);
+ /* Skip pixel write, if mask bit not set. */
+ if (mask != NULL && (mask[byte] & bit) == 0)
+ continue;
+ o = (y + yi) * info->fb_stride + (x + xi) * bpp;
+ cc = pattern[byte] & bit ? fgc : bgc;
switch(bpp) {
case 1:
@@ -326,8 +320,6 @@ vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
break;
}
}
- line += info->fb_stride;
- pattern += bpl;
}
}
diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c
index e939fdd..689692e 100644
--- a/sys/dev/vt/hw/vga/vt_vga.c
+++ b/sys/dev/vt/hw/vga/vt_vga.c
@@ -1035,11 +1035,12 @@ vga_initialize_graphics(struct vt_device *vd)
REG_WRITE1(sc, VGA_GC_DATA, 0xff);
}
-static void
+static int
vga_initialize(struct vt_device *vd, int textmode)
{
struct vga_softc *sc = vd->vd_softc;
uint8_t x;
+ int timeout;
/* Make sure the VGA adapter is not in monochrome emulation mode. */
x = REG_READ1(sc, VGA_GEN_MISC_OUTPUT_R);
@@ -1060,10 +1061,16 @@ vga_initialize(struct vt_device *vd, int textmode)
* code therefore also removes that guarantee and appropriate measures
* need to be taken.
*/
+ timeout = 10000;
do {
+ DELAY(10);
x = REG_READ1(sc, VGA_GEN_INPUT_STAT_1);
x &= VGA_GEN_IS1_VR | VGA_GEN_IS1_DE;
- } while (x != (VGA_GEN_IS1_VR | VGA_GEN_IS1_DE));
+ } while (x != (VGA_GEN_IS1_VR | VGA_GEN_IS1_DE) && --timeout != 0);
+ if (timeout == 0) {
+ printf("Timeout initializing vt_vga\n");
+ return (ENXIO);
+ }
/* Now, disable the sync. signals. */
REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_MODE_CONTROL);
@@ -1194,6 +1201,8 @@ vga_initialize(struct vt_device *vd, int textmode)
*/
sc->vga_curfg = sc->vga_curbg = 0xff;
}
+
+ return (0);
}
static int
@@ -1235,7 +1244,8 @@ vga_init(struct vt_device *vd)
vd->vd_width = VT_VGA_WIDTH;
vd->vd_height = VT_VGA_HEIGHT;
}
- vga_initialize(vd, textmode);
+ if (vga_initialize(vd, textmode) != 0)
+ return (CN_DEAD);
sc->vga_enabled = true;
return (CN_INTERNAL);
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 1f8731e..a637055 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -1029,7 +1029,7 @@ vt_determine_colors(term_char_t c, int cursor,
int
vt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area)
{
- unsigned int mx, my, x1, y1, x2, y2;
+ unsigned int mx, my;
/*
* We use the cursor position saved during the current refresh,
@@ -1038,18 +1038,12 @@ vt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area)
mx = vd->vd_mx_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_col;
my = vd->vd_my_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_row;
- x1 = area->tr_begin.tp_col;
- y1 = area->tr_begin.tp_row;
- x2 = area->tr_end.tp_col;
- y2 = area->tr_end.tp_row;
-
- if (((mx >= x1 && x2 - 1 >= mx) ||
- (mx < x1 && mx + vd->vd_mcursor->width >= x1)) &&
- ((my >= y1 && y2 - 1 >= my) ||
- (my < y1 && my + vd->vd_mcursor->height >= y1)))
- return (1);
-
- return (0);
+ if (mx >= area->tr_end.tp_col ||
+ mx + vd->vd_mcursor->width <= area->tr_begin.tp_col ||
+ my >= area->tr_end.tp_row ||
+ my + vd->vd_mcursor->height <= area->tr_begin.tp_row)
+ return (0);
+ return (1);
}
static void
diff --git a/sys/dev/vt/vt_font.c b/sys/dev/vt/vt_font.c
index b98115f..4c369c6 100644
--- a/sys/dev/vt/vt_font.c
+++ b/sys/dev/vt/vt_font.c
@@ -41,8 +41,8 @@ __FBSDID("$FreeBSD$");
static MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font");
/* Some limits to prevent abnormal fonts from being loaded. */
-#define VTFONT_MAXMAPPINGS 8192
-#define VTFONT_MAXGLYPHSIZE 1048576
+#define VTFONT_MAXMAPPINGS 65536
+#define VTFONT_MAXGLYPHSIZE 2097152
#define VTFONT_MAXDIMENSION 128
static uint16_t
diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c
index ab382b6..9579c61 100644
--- a/sys/dev/wpi/if_wpi.c
+++ b/sys/dev/wpi/if_wpi.c
@@ -218,7 +218,7 @@ static int wpi_set_timing(struct wpi_softc *, struct ieee80211_node *);
static void wpi_power_calibration(struct wpi_softc *);
static int wpi_set_txpower(struct wpi_softc *, int);
static int wpi_get_power_index(struct wpi_softc *,
- struct wpi_power_group *, struct ieee80211_channel *, int);
+ struct wpi_power_group *, uint8_t, int, int);
static int wpi_set_pslevel(struct wpi_softc *, uint8_t, int, int);
static int wpi_send_btcoex(struct wpi_softc *);
static int wpi_send_rxon(struct wpi_softc *, int, int);
@@ -3455,19 +3455,17 @@ wpi_power_calibration(struct wpi_softc *sc)
static int
wpi_set_txpower(struct wpi_softc *sc, int async)
{
- struct ieee80211com *ic = sc->sc_ifp->if_l2com;
- struct ieee80211_channel *ch;
struct wpi_power_group *group;
struct wpi_cmd_txpower cmd;
uint8_t chan;
- int idx, i;
+ int idx, is_chan_5ghz, i;
/* Retrieve current channel from last RXON. */
chan = sc->rxon.chan;
- ch = &ic->ic_channels[chan];
+ is_chan_5ghz = (sc->rxon.flags & htole32(WPI_RXON_24GHZ)) == 0;
/* Find the TX power group to which this channel belongs. */
- if (IEEE80211_IS_CHAN_5GHZ(ch)) {
+ if (is_chan_5ghz) {
for (group = &sc->groups[1]; group < &sc->groups[4]; group++)
if (chan <= group->chan)
break;
@@ -3475,17 +3473,17 @@ wpi_set_txpower(struct wpi_softc *sc, int async)
group = &sc->groups[0];
memset(&cmd, 0, sizeof cmd);
- cmd.band = IEEE80211_IS_CHAN_5GHZ(ch) ? 0 : 1;
+ cmd.band = is_chan_5ghz ? WPI_BAND_5GHZ : WPI_BAND_2GHZ;
cmd.chan = htole16(chan);
/* Set TX power for all OFDM and CCK rates. */
for (i = 0; i <= WPI_RIDX_MAX ; i++) {
/* Retrieve TX power for this channel/rate. */
- idx = wpi_get_power_index(sc, group, ch, i);
+ idx = wpi_get_power_index(sc, group, chan, is_chan_5ghz, i);
cmd.rates[i].plcp = wpi_ridx_to_plcp[i];
- if (IEEE80211_IS_CHAN_5GHZ(ch)) {
+ if (is_chan_5ghz) {
cmd.rates[i].rf_gain = wpi_rf_gain_5ghz[idx];
cmd.rates[i].dsp_gain = wpi_dsp_gain_5ghz[idx];
} else {
@@ -3506,7 +3504,7 @@ wpi_set_txpower(struct wpi_softc *sc, int async)
*/
static int
wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group,
- struct ieee80211_channel *c, int ridx)
+ uint8_t chan, int is_chan_5ghz, int ridx)
{
/* Fixed-point arithmetic division using a n-bit fractional part. */
#define fdivround(a, b, n) \
@@ -3516,13 +3514,8 @@ wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group,
#define interpolate(x, x1, y1, x2, y2, n) \
((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n))
- struct ieee80211com *ic = sc->sc_ifp->if_l2com;
struct wpi_power_sample *sample;
int pwr, idx;
- u_int chan;
-
- /* Get channel number. */
- chan = ieee80211_chan2ieee(ic, c);
/* Default TX power is group maximum TX power minus 3dB. */
pwr = group->maxpwr / 2;
@@ -3530,13 +3523,13 @@ wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group,
/* Decrease TX power for highest OFDM rates to reduce distortion. */
switch (ridx) {
case WPI_RIDX_OFDM36:
- pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5;
+ pwr -= is_chan_5ghz ? 5 : 0;
break;
case WPI_RIDX_OFDM48:
- pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10;
+ pwr -= is_chan_5ghz ? 10 : 7;
break;
case WPI_RIDX_OFDM54:
- pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12;
+ pwr -= is_chan_5ghz ? 12 : 9;
break;
}
@@ -4912,10 +4905,6 @@ wpi_apm_init(struct wpi_softc *sc)
/* Set FH wait threshold to max (HW bug under stress workaround). */
WPI_SETBITS(sc, WPI_DBG_HPET_MEM, 0xffff0000);
- /* Cleanup. */
- wpi_prph_write(sc, WPI_APMG_CLK_DIS, 0x00000400);
- wpi_prph_clrbits(sc, WPI_APMG_PS, 0x00000E00);
-
/* Retrieve PCIe Active State Power Management (ASPM). */
reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1);
/* Workaround for HW instability in PCIe L0->L0s->L1 transition. */
@@ -4932,6 +4921,10 @@ wpi_apm_init(struct wpi_softc *sc)
if ((error = wpi_nic_lock(sc)) != 0)
return error;
+ /* Cleanup. */
+ wpi_prph_write(sc, WPI_APMG_CLK_DIS, 0x00000400);
+ wpi_prph_clrbits(sc, WPI_APMG_PS, 0x00000200);
+
/* Enable DMA and BSM (Bootstrap State Machine). */
wpi_prph_write(sc, WPI_APMG_CLK_EN,
WPI_APMG_CLK_CTRL_DMA_CLK_RQT | WPI_APMG_CLK_CTRL_BSM_CLK_RQT);
diff --git a/sys/dev/xen/balloon/balloon.c b/sys/dev/xen/balloon/balloon.c
index e113e2c..a6036d8 100644
--- a/sys/dev/xen/balloon/balloon.c
+++ b/sys/dev/xen/balloon/balloon.c
@@ -118,11 +118,6 @@ current_target(void)
static unsigned long
minimum_target(void)
{
-#ifdef XENHVM
-#define max_pfn realmem
-#else
-#define max_pfn HYPERVISOR_shared_info->arch.max_pfn
-#endif
unsigned long min_pages, curr_pages = current_target();
#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
@@ -139,16 +134,15 @@ minimum_target(void)
* 32768 1320
* 131072 4392
*/
- if (max_pfn < MB2PAGES(128))
- min_pages = MB2PAGES(8) + (max_pfn >> 1);
- else if (max_pfn < MB2PAGES(512))
- min_pages = MB2PAGES(40) + (max_pfn >> 2);
- else if (max_pfn < MB2PAGES(2048))
- min_pages = MB2PAGES(104) + (max_pfn >> 3);
+ if (realmem < MB2PAGES(128))
+ min_pages = MB2PAGES(8) + (realmem >> 1);
+ else if (realmem < MB2PAGES(512))
+ min_pages = MB2PAGES(40) + (realmem >> 2);
+ else if (realmem < MB2PAGES(2048))
+ min_pages = MB2PAGES(104) + (realmem >> 3);
else
- min_pages = MB2PAGES(296) + (max_pfn >> 5);
+ min_pages = MB2PAGES(296) + (realmem >> 5);
#undef MB2PAGES
-#undef max_pfn
/* Don't enforce growth */
return (min(min_pages, curr_pages));
@@ -204,12 +198,9 @@ increase_reservation(unsigned long nr_pages)
bs.balloon_low--;
pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT);
- KASSERT((xen_feature(XENFEAT_auto_translated_physmap) ||
- !phys_to_machine_mapping_valid(pfn)),
+ KASSERT(xen_feature(XENFEAT_auto_translated_physmap),
("auto translated physmap but mapping is valid"));
- set_phys_to_machine(pfn, frame_list[i]);
-
vm_page_free(page);
}
@@ -258,9 +249,8 @@ decrease_reservation(unsigned long nr_pages)
}
pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT);
- frame_list[i] = PFNTOMFN(pfn);
+ frame_list[i] = pfn;
- set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q);
bs.balloon_low++;
}
@@ -393,21 +383,11 @@ static int
xenballoon_attach(device_t dev)
{
int err;
-#ifndef XENHVM
- vm_page_t page;
- unsigned long pfn;
-
-#define max_pfn HYPERVISOR_shared_info->arch.max_pfn
-#endif
mtx_init(&balloon_mutex, "balloon_mutex", NULL, MTX_DEF);
-#ifndef XENHVM
- bs.current_pages = min(xen_start_info->nr_pages, max_pfn);
-#else
bs.current_pages = xen_pv_domain() ?
HYPERVISOR_start_info->nr_pages : realmem;
-#endif
bs.target_pages = bs.current_pages;
bs.balloon_low = 0;
bs.balloon_high = 0;
@@ -416,16 +396,6 @@ xenballoon_attach(device_t dev)
kproc_create(balloon_process, NULL, NULL, 0, 0, "balloon");
-#ifndef XENHVM
- /* Initialise the balloon with excess memory space. */
- for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
- page = PHYS_TO_VM_PAGE(pfn << PAGE_SHIFT);
- TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q);
- bs.balloon_low++;
- }
-#undef max_pfn
-#endif
-
target_watch.callback = watch_target;
err = xs_register_watch(&target_watch);
diff --git a/sys/dev/xen/blkback/blkback.c b/sys/dev/xen/blkback/blkback.c
index 1273961..b647fec 100644
--- a/sys/dev/xen/blkback/blkback.c
+++ b/sys/dev/xen/blkback/blkback.c
@@ -742,7 +742,6 @@ struct xbb_softc {
/** Mutex protecting per-instance data. */
struct mtx lock;
-#ifdef XENHVM
/**
* Resource representing allocated physical address space
* associated with our per-instance kva region.
@@ -751,7 +750,6 @@ struct xbb_softc {
/** Resource id for allocated physical address space. */
int pseudo_phys_res_id;
-#endif
/**
* I/O statistics from BlockBack dispatch down. These are
@@ -2818,16 +2816,12 @@ static void
xbb_free_communication_mem(struct xbb_softc *xbb)
{
if (xbb->kva != 0) {
-#ifndef XENHVM
- kva_free(xbb->kva, xbb->kva_size);
-#else
if (xbb->pseudo_phys_res != NULL) {
bus_release_resource(xbb->dev, SYS_RES_MEMORY,
xbb->pseudo_phys_res_id,
xbb->pseudo_phys_res);
xbb->pseudo_phys_res = NULL;
}
-#endif
}
xbb->kva = 0;
xbb->gnt_base_addr = 0;
@@ -3055,12 +3049,6 @@ xbb_alloc_communication_mem(struct xbb_softc *xbb)
DPRINTF("%s: kva_size = %d, reqlist_kva_size = %d\n",
device_get_nameunit(xbb->dev), xbb->kva_size,
xbb->reqlist_kva_size);
-#ifndef XENHVM
- xbb->kva = kva_alloc(xbb->kva_size);
- if (xbb->kva == 0)
- return (ENOMEM);
- xbb->gnt_base_addr = xbb->kva;
-#else /* XENHVM */
/*
* Reserve a range of pseudo physical memory that we can map
* into kva. These pages will only be backed by machine
@@ -3078,7 +3066,6 @@ xbb_alloc_communication_mem(struct xbb_softc *xbb)
}
xbb->kva = (vm_offset_t)rman_get_virtual(xbb->pseudo_phys_res);
xbb->gnt_base_addr = rman_get_start(xbb->pseudo_phys_res);
-#endif /* XENHVM */
DPRINTF("%s: kva: %#jx, gnt_base_addr: %#jx\n",
device_get_nameunit(xbb->dev), (uintmax_t)xbb->kva,
diff --git a/sys/dev/xen/control/control.c b/sys/dev/xen/control/control.c
index 665a5ac..2a0d459 100644
--- a/sys/dev/xen/control/control.c
+++ b/sys/dev/xen/control/control.c
@@ -138,9 +138,7 @@ __FBSDID("$FreeBSD$");
#include <xen/gnttab.h>
#include <xen/xen_intr.h>
-#ifdef XENHVM
#include <xen/hvm.h>
-#endif
#include <xen/interface/event_channel.h>
#include <xen/interface/grant_table.h>
@@ -192,133 +190,6 @@ xctrl_reboot()
shutdown_nice(0);
}
-#ifndef XENHVM
-extern void xencons_suspend(void);
-extern void xencons_resume(void);
-
-/* Full PV mode suspension. */
-static void
-xctrl_suspend()
-{
- int i, j, k, fpp, suspend_cancelled;
- unsigned long max_pfn, start_info_mfn;
-
- EVENTHANDLER_INVOKE(power_suspend);
-
-#ifdef SMP
- struct thread *td;
- cpuset_t map;
- u_int cpuid;
-
- /*
- * Bind us to CPU 0 and stop any other VCPUs.
- */
- td = curthread;
- thread_lock(td);
- sched_bind(td, 0);
- thread_unlock(td);
- cpuid = PCPU_GET(cpuid);
- KASSERT(cpuid == 0, ("xen_suspend: not running on cpu 0"));
-
- map = all_cpus;
- CPU_CLR(cpuid, &map);
- CPU_NAND(&map, &stopped_cpus);
- if (!CPU_EMPTY(&map))
- stop_cpus(map);
-#endif
-
- /*
- * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
- * drivers need this.
- */
- mtx_lock(&Giant);
- if (DEVICE_SUSPEND(root_bus) != 0) {
- mtx_unlock(&Giant);
- printf("%s: device_suspend failed\n", __func__);
-#ifdef SMP
- if (!CPU_EMPTY(&map))
- restart_cpus(map);
-#endif
- return;
- }
- mtx_unlock(&Giant);
-
- local_irq_disable();
-
- xencons_suspend();
- gnttab_suspend();
- intr_suspend();
-
- max_pfn = HYPERVISOR_shared_info->arch.max_pfn;
-
- void *shared_info = HYPERVISOR_shared_info;
- HYPERVISOR_shared_info = NULL;
- pmap_kremove((vm_offset_t) shared_info);
- PT_UPDATES_FLUSH();
-
- xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn);
- xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn);
-
- /*
- * We'll stop somewhere inside this hypercall. When it returns,
- * we'll start resuming after the restore.
- */
- start_info_mfn = VTOMFN(xen_start_info);
- pmap_suspend();
- suspend_cancelled = HYPERVISOR_suspend(start_info_mfn);
- pmap_resume();
-
- pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info);
- HYPERVISOR_shared_info = shared_info;
-
- HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
- VTOMFN(xen_pfn_to_mfn_frame_list_list);
-
- fpp = PAGE_SIZE/sizeof(unsigned long);
- for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
- if ((j % fpp) == 0) {
- k++;
- xen_pfn_to_mfn_frame_list_list[k] =
- VTOMFN(xen_pfn_to_mfn_frame_list[k]);
- j = 0;
- }
- xen_pfn_to_mfn_frame_list[k][j] =
- VTOMFN(&xen_phys_machine[i]);
- }
- HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
-
- gnttab_resume(NULL);
- intr_resume(suspend_cancelled != 0);
- local_irq_enable();
- xencons_resume();
-
-#ifdef CONFIG_SMP
- for_each_cpu(i)
- vcpu_prepare(i);
-
-#endif
-
- /*
- * Only resume xenbus /after/ we've prepared our VCPUs; otherwise
- * the VCPU hotplug callback can race with our vcpu_prepare
- */
- mtx_lock(&Giant);
- DEVICE_RESUME(root_bus);
- mtx_unlock(&Giant);
-
-#ifdef SMP
- thread_lock(curthread);
- sched_unbind(curthread);
- thread_unlock(curthread);
- if (!CPU_EMPTY(&map))
- restart_cpus(map);
-#endif
- EVENTHANDLER_INVOKE(power_resume);
-}
-
-#else
-
-/* HVM mode suspension. */
static void
xctrl_suspend()
{
@@ -417,7 +288,6 @@ xctrl_suspend()
printf("System resumed after suspension\n");
}
-#endif
static void
xctrl_crash()
diff --git a/sys/dev/xen/grant_table/grant_table.c b/sys/dev/xen/grant_table/grant_table.c
index 2511657..ad65fe0 100644
--- a/sys/dev/xen/grant_table/grant_table.c
+++ b/sys/dev/xen/grant_table/grant_table.c
@@ -53,7 +53,6 @@ static int gnttab_free_count;
static grant_ref_t gnttab_free_head;
static struct mtx gnttab_list_lock;
-#ifdef XENHVM
/*
* Resource representing allocated physical address space
* for the grant table metainfo
@@ -62,7 +61,6 @@ static struct resource *gnttab_pseudo_phys_res;
/* Resource id for allocated physical address space. */
static int gnttab_pseudo_phys_res_id;
-#endif
static grant_entry_t *shared;
@@ -510,72 +508,6 @@ unmap_pte_fn(pte_t *pte, struct page *pmd_page,
}
#endif
-#ifndef XENHVM
-
-static int
-gnttab_map(unsigned int start_idx, unsigned int end_idx)
-{
- struct gnttab_setup_table setup;
- u_long *frames;
-
- unsigned int nr_gframes = end_idx + 1;
- int i, rc;
-
- frames = malloc(nr_gframes * sizeof(unsigned long), M_DEVBUF, M_NOWAIT);
- if (!frames)
- return (ENOMEM);
-
- setup.dom = DOMID_SELF;
- setup.nr_frames = nr_gframes;
- set_xen_guest_handle(setup.frame_list, frames);
-
- rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
- if (rc == -ENOSYS) {
- free(frames, M_DEVBUF);
- return (ENOSYS);
- }
- KASSERT(!(rc || setup.status),
- ("unexpected result from grant_table_op"));
-
- if (shared == NULL) {
- vm_offset_t area;
-
- area = kva_alloc(PAGE_SIZE * max_nr_grant_frames());
- KASSERT(area, ("can't allocate VM space for grant table"));
- shared = (grant_entry_t *)area;
- }
-
- for (i = 0; i < nr_gframes; i++)
- PT_SET_MA(((caddr_t)shared) + i*PAGE_SIZE,
- ((vm_paddr_t)frames[i]) << PAGE_SHIFT | PG_RW | PG_V);
-
- free(frames, M_DEVBUF);
-
- return (0);
-}
-
-int
-gnttab_resume(device_t dev)
-{
-
- if (max_nr_grant_frames() < nr_grant_frames)
- return (ENOSYS);
- return (gnttab_map(0, nr_grant_frames - 1));
-}
-
-int
-gnttab_suspend(void)
-{
- int i;
-
- for (i = 0; i < nr_grant_frames; i++)
- pmap_kremove((vm_offset_t) shared + i * PAGE_SIZE);
-
- return (0);
-}
-
-#else /* XENHVM */
-
static vm_paddr_t resume_frames;
static int
@@ -638,8 +570,6 @@ gnttab_resume(device_t dev)
return (gnttab_map(0, nr_gframes - 1));
}
-#endif
-
static int
gnttab_expand(unsigned int req_entries)
{
diff --git a/sys/dev/xen/netback/netback.c b/sys/dev/xen/netback/netback.c
index 63337ad..b5c1c13 100644
--- a/sys/dev/xen/netback/netback.c
+++ b/sys/dev/xen/netback/netback.c
@@ -473,7 +473,6 @@ struct xnb_softc {
*/
gnttab_copy_table tx_gnttab;
-#ifdef XENHVM
/**
* Resource representing allocated physical address space
* associated with our per-instance kva region.
@@ -482,7 +481,6 @@ struct xnb_softc {
/** Resource id for allocated physical address space. */
int pseudo_phys_res_id;
-#endif
/** Ring mapping and interrupt configuration data. */
struct xnb_ring_config ring_configs[XNB_NUM_RING_TYPES];
@@ -626,16 +624,12 @@ static void
xnb_free_communication_mem(struct xnb_softc *xnb)
{
if (xnb->kva != 0) {
-#ifndef XENHVM
- kva_free(xnb->kva, xnb->kva_size);
-#else
if (xnb->pseudo_phys_res != NULL) {
bus_release_resource(xnb->dev, SYS_RES_MEMORY,
xnb->pseudo_phys_res_id,
xnb->pseudo_phys_res);
xnb->pseudo_phys_res = NULL;
}
-#endif /* XENHVM */
}
xnb->kva = 0;
xnb->gnt_base_addr = 0;
@@ -816,12 +810,7 @@ xnb_alloc_communication_mem(struct xnb_softc *xnb)
for (i=0; i < XNB_NUM_RING_TYPES; i++) {
xnb->kva_size += xnb->ring_configs[i].ring_pages * PAGE_SIZE;
}
-#ifndef XENHVM
- xnb->kva = kva_alloc(xnb->kva_size);
- if (xnb->kva == 0)
- return (ENOMEM);
- xnb->gnt_base_addr = xnb->kva;
-#else /* defined XENHVM */
+
/*
* Reserve a range of pseudo physical memory that we can map
* into kva. These pages will only be backed by machine
@@ -840,7 +829,6 @@ xnb_alloc_communication_mem(struct xnb_softc *xnb)
}
xnb->kva = (vm_offset_t)rman_get_virtual(xnb->pseudo_phys_res);
xnb->gnt_base_addr = rman_get_start(xnb->pseudo_phys_res);
-#endif /* !defined XENHVM */
return (0);
}
diff --git a/sys/dev/xen/netfront/netfront.c b/sys/dev/xen/netfront/netfront.c
index f65e29c..3c1f952 100644
--- a/sys/dev/xen/netfront/netfront.c
+++ b/sys/dev/xen/netfront/netfront.c
@@ -879,12 +879,11 @@ refill:
if (sc->copying_receiver == 0) {
gnttab_grant_foreign_transfer_ref(ref,
otherend_id, pfn);
- sc->rx_pfn_array[nr_flips] = PFNTOMFN(pfn);
+ sc->rx_pfn_array[nr_flips] = pfn;
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
/* Remove this page before passing
* back to Xen.
*/
- set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
MULTI_update_va_mapping(&sc->rx_mcl[i],
vaddr, 0, 0);
}
@@ -892,7 +891,7 @@ refill:
} else {
gnttab_grant_foreign_access_ref(ref,
otherend_id,
- PFNTOMFN(pfn), 0);
+ pfn, 0);
}
req->id = id;
req->gref = ref;
@@ -907,7 +906,6 @@ refill:
* We may have allocated buffers which have entries outstanding
* in the page * update queue -- make sure we flush those first!
*/
- PT_UPDATES_FLUSH();
if (nr_flips != 0) {
#ifdef notyet
/* Tell the ballon driver what is going on. */
@@ -1361,8 +1359,6 @@ xennet_get_responses(struct netfront_info *np,
mmu->ptr = ((vm_paddr_t)mfn << PAGE_SHIFT) |
MMU_MACHPHYS_UPDATE;
mmu->val = pfn;
-
- set_phys_to_machine(pfn, mfn);
}
pages_flipped++;
} else {
@@ -1472,7 +1468,6 @@ xn_assemble_tx_request(struct netfront_info *sc, struct mbuf *m_head)
struct ifnet *ifp;
struct mbuf *m;
u_int nfrags;
- netif_extra_info_t *extra;
int otherend_id;
ifp = sc->xn_ifp;
@@ -1546,7 +1541,6 @@ xn_assemble_tx_request(struct netfront_info *sc, struct mbuf *m_head)
* of fragments or hit the end of the mbuf chain.
*/
m = m_head;
- extra = NULL;
otherend_id = xenbus_get_otherend_id(sc->xbdev);
for (m = m_head; m; m = m->m_next) {
netif_tx_request_t *tx;
@@ -1929,7 +1923,7 @@ network_connect(struct netfront_info *np)
} else {
gnttab_grant_foreign_access_ref(ref,
xenbus_get_otherend_id(np->xbdev),
- PFNTOMFN(pfn), 0);
+ pfn, 0);
}
req->gref = ref;
req->id = requeue_idx;
diff --git a/sys/fs/ext2fs/ext2_dir.h b/sys/fs/ext2fs/ext2_dir.h
index 8d92882..1138b86 100644
--- a/sys/fs/ext2fs/ext2_dir.h
+++ b/sys/fs/ext2fs/ext2_dir.h
@@ -40,21 +40,6 @@ struct ext2fs_direct {
uint16_t e2d_namlen; /* length of string in e2d_name */
char e2d_name[EXT2FS_MAXNAMLEN];/* name with length<=EXT2FS_MAXNAMLEN */
};
-
-enum slotstatus {
- NONE,
- COMPACT,
- FOUND
-};
-
-struct ext2fs_searchslot {
- enum slotstatus slotstatus;
- doff_t slotoffset; /* offset of area with free space */
- int slotsize; /* size of area at slotoffset */
- int slotfreespace; /* amount of space free in slot */
- int slotneeded; /* sizeof the entry we are seeking */
-};
-
/*
* The new version of the directory entry. Since EXT2 structures are
* stored in intel byte order, and the name_len field could never be
diff --git a/sys/fs/ext2fs/ext2_extern.h b/sys/fs/ext2fs/ext2_extern.h
index 93bd3f7..f7b7657 100644
--- a/sys/fs/ext2fs/ext2_extern.h
+++ b/sys/fs/ext2fs/ext2_extern.h
@@ -40,15 +40,12 @@
#define _FS_EXT2FS_EXT2_EXTERN_H_
struct ext2fs_dinode;
-struct ext2fs_direct_2;
-struct ext2fs_searchslot;
struct indir;
struct inode;
struct mount;
struct vfsconf;
struct vnode;
-int ext2_add_entry(struct vnode *, struct ext2fs_direct_2 *);
int ext2_alloc(struct inode *, daddr_t, e4fs_daddr_t, int,
struct ucred *, e4fs_daddr_t *);
int ext2_balloc(struct inode *,
@@ -86,18 +83,6 @@ int ext2_dirempty(struct inode *, ino_t, struct ucred *);
int ext2_checkpath(struct inode *, struct inode *, struct ucred *);
int cg_has_sb(int i);
int ext2_inactive(struct vop_inactive_args *);
-int ext2_htree_add_entry(struct vnode *, struct ext2fs_direct_2 *,
- struct componentname *);
-int ext2_htree_create_index(struct vnode *, struct componentname *,
- struct ext2fs_direct_2 *);
-int ext2_htree_has_idx(struct inode *);
-int ext2_htree_hash(const char *, int, uint32_t *, int, uint32_t *,
- uint32_t *);
-int ext2_htree_lookup(struct inode *, const char *, int, struct buf **,
- int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
-int ext2_search_dirblock(struct inode *, void *, int *, const char *, int,
- int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
-
/* Flags to low-level allocation routines.
* The low 16-bits are reserved for IO_ flags from vnode.h.
diff --git a/sys/fs/ext2fs/ext2_hash.c b/sys/fs/ext2fs/ext2_hash.c
deleted file mode 100644
index 663a2df..0000000
--- a/sys/fs/ext2fs/ext2_hash.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*-
- * Copyright (c) 2010, 2013 Zheng Liu <lz@freebsd.org>
- * Copyright (c) 2012, Vyacheslav Matyushin
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-/*
- * The following notice applies to the code in ext2_half_md4():
- *
- * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
- *
- * License to copy and use this software is granted provided that it
- * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
- * Algorithm" in all material mentioning or referencing this software
- * or this function.
- *
- * License is also granted to make and use derivative works provided
- * that such works are identified as "derived from the RSA Data
- * Security, Inc. MD4 Message-Digest Algorithm" in all material
- * mentioning or referencing the derived work.
- *
- * RSA Data Security, Inc. makes no representations concerning either
- * the merchantability of this software or the suitability of this
- * software for any particular purpose. It is provided "as is"
- * without express or implied warranty of any kind.
- *
- * These notices must be retained in any copies of any part of this
- * documentation and/or software.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/vnode.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
-
-#include <fs/ext2fs/htree.h>
-#include <fs/ext2fs/inode.h>
-#include <fs/ext2fs/ext2_mount.h>
-#include <fs/ext2fs/ext2_extern.h>
-
-/* F, G, and H are MD4 functions */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/* ROTATE_LEFT rotates x left n bits */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-/*
- * FF, GG, and HH are transformations for rounds 1, 2, and 3.
- * Rotation is separated from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s) { \
- (a) += F ((b), (c), (d)) + (x); \
- (a) = ROTATE_LEFT ((a), (s)); \
-}
-
-#define GG(a, b, c, d, x, s) { \
- (a) += G ((b), (c), (d)) + (x) + (uint32_t)0x5A827999; \
- (a) = ROTATE_LEFT ((a), (s)); \
-}
-
-#define HH(a, b, c, d, x, s) { \
- (a) += H ((b), (c), (d)) + (x) + (uint32_t)0x6ED9EBA1; \
- (a) = ROTATE_LEFT ((a), (s)); \
-}
-
-/*
- * MD4 basic transformation. It transforms state based on block.
- *
- * This is a half md4 algorithm since Linux uses this algorithm for dir
- * index. This function is derived from the RSA Data Security, Inc. MD4
- * Message-Digest Algorithm and was modified as necessary.
- *
- * The return value of this function is uint32_t in Linux, but actually we don't
- * need to check this value, so in our version this function doesn't return any
- * value.
- */
-static void
-ext2_half_md4(uint32_t hash[4], uint32_t data[8])
-{
- uint32_t a = hash[0], b = hash[1], c = hash[2], d = hash[3];
-
- /* Round 1 */
- FF(a, b, c, d, data[0], 3);
- FF(d, a, b, c, data[1], 7);
- FF(c, d, a, b, data[2], 11);
- FF(b, c, d, a, data[3], 19);
- FF(a, b, c, d, data[4], 3);
- FF(d, a, b, c, data[5], 7);
- FF(c, d, a, b, data[6], 11);
- FF(b, c, d, a, data[7], 19);
-
- /* Round 2 */
- GG(a, b, c, d, data[1], 3);
- GG(d, a, b, c, data[3], 5);
- GG(c, d, a, b, data[5], 9);
- GG(b, c, d, a, data[7], 13);
- GG(a, b, c, d, data[0], 3);
- GG(d, a, b, c, data[2], 5);
- GG(c, d, a, b, data[4], 9);
- GG(b, c, d, a, data[6], 13);
-
- /* Round 3 */
- HH(a, b, c, d, data[3], 3);
- HH(d, a, b, c, data[7], 9);
- HH(c, d, a, b, data[2], 11);
- HH(b, c, d, a, data[6], 15);
- HH(a, b, c, d, data[1], 3);
- HH(d, a, b, c, data[5], 9);
- HH(c, d, a, b, data[0], 11);
- HH(b, c, d, a, data[4], 15);
-
- hash[0] += a;
- hash[1] += b;
- hash[2] += c;
- hash[3] += d;
-}
-
-/*
- * Tiny Encryption Algorithm.
- */
-static void
-ext2_tea(uint32_t hash[4], uint32_t data[8])
-{
- uint32_t tea_delta = 0x9E3779B9;
- uint32_t sum;
- uint32_t x = hash[0], y = hash[1];
- int n = 16;
- int i = 1;
-
- while (n-- > 0) {
- sum = i * tea_delta;
- x += ((y << 4) + data[0]) ^ (y + sum) ^ ((y >> 5) + data[1]);
- y += ((x << 4) + data[2]) ^ (x + sum) ^ ((x >> 5) + data[3]);
- i++;
- }
-
- hash[0] += x;
- hash[1] += y;
-}
-
-static uint32_t
-ext2_legacy_hash(const char *name, int len, int unsigned_char)
-{
- uint32_t h0, h1 = 0x12A3FE2D, h2 = 0x37ABE8F9;
- uint32_t multi = 0x6D22F5;
- const unsigned char *uname = (const unsigned char *)name;
- const signed char *sname = (const signed char *)name;
- int val, i;
-
- for (i = 0; i < len; i++) {
- if (unsigned_char)
- val = (u_int)*uname++;
- else
- val = (int)*sname++;
-
- h0 = h2 + (h1 ^ (val * multi));
- if (h0 & 0x80000000)
- h0 -= 0x7FFFFFFF;
- h2 = h1;
- h1 = h0;
- }
-
- return (h1 << 1);
-}
-
-static void
-ext2_prep_hashbuf(const char *src, int slen, uint32_t *dst, int dlen,
- int unsigned_char)
-{
- uint32_t padding = slen | (slen << 8) | (slen << 16) | (slen << 24);
- uint32_t buf_val;
- const unsigned char *ubuf = (const unsigned char *)src;
- const signed char *sbuf = (const signed char *)src;
- int len, i;
- int buf_byte;
-
- if (slen > dlen)
- len = dlen;
- else
- len = slen;
-
- buf_val = padding;
-
- for (i = 0; i < len; i++) {
- if (unsigned_char)
- buf_byte = (u_int)ubuf[i];
- else
- buf_byte = (int)sbuf[i];
-
- if ((i % 4) == 0)
- buf_val = padding;
-
- buf_val <<= 8;
- buf_val += buf_byte;
-
- if ((i % 4) == 3) {
- *dst++ = buf_val;
- dlen -= sizeof(uint32_t);
- buf_val = padding;
- }
- }
-
- dlen -= sizeof(uint32_t);
- if (dlen >= 0)
- *dst++ = buf_val;
-
- dlen -= sizeof(uint32_t);
- while (dlen >= 0) {
- *dst++ = padding;
- dlen -= sizeof(uint32_t);
- }
-}
-
-int
-ext2_htree_hash(const char *name, int len,
- uint32_t *hash_seed, int hash_version,
- uint32_t *hash_major, uint32_t *hash_minor)
-{
- uint32_t hash[4];
- uint32_t data[8];
- uint32_t major = 0, minor = 0;
- int unsigned_char = 0;
-
- if (!name || !hash_major)
- return (-1);
-
- if (len < 1 || len > 255)
- goto error;
-
- hash[0] = 0x67452301;
- hash[1] = 0xEFCDAB89;
- hash[2] = 0x98BADCFE;
- hash[3] = 0x10325476;
-
- if (hash_seed)
- memcpy(hash, hash_seed, sizeof(hash));
-
- switch (hash_version) {
- case EXT2_HTREE_TEA_UNSIGNED:
- unsigned_char = 1;
- /* FALLTHROUGH */
- case EXT2_HTREE_TEA:
- while (len > 0) {
- ext2_prep_hashbuf(name, len, data, 16, unsigned_char);
- ext2_tea(hash, data);
- len -= 16;
- name += 16;
- }
- major = hash[0];
- minor = hash[1];
- break;
- case EXT2_HTREE_LEGACY_UNSIGNED:
- unsigned_char = 1;
- /* FALLTHROUGH */
- case EXT2_HTREE_LEGACY:
- major = ext2_legacy_hash(name, len, unsigned_char);
- break;
- case EXT2_HTREE_HALF_MD4_UNSIGNED:
- unsigned_char = 1;
- /* FALLTHROUGH */
- case EXT2_HTREE_HALF_MD4:
- while (len > 0) {
- ext2_prep_hashbuf(name, len, data, 32, unsigned_char);
- ext2_half_md4(hash, data);
- len -= 32;
- name += 32;
- }
- major = hash[1];
- minor = hash[2];
- break;
- default:
- goto error;
- }
-
- major &= ~1;
- if (major == (EXT2_HTREE_EOF << 1))
- major = (EXT2_HTREE_EOF - 1) << 1;
- *hash_major = major;
- if (hash_minor)
- *hash_minor = minor;
-
- return (0);
-
-error:
- *hash_major = 0;
- if (hash_minor)
- *hash_minor = 0;
- return (-1);
-}
diff --git a/sys/fs/ext2fs/ext2_htree.c b/sys/fs/ext2fs/ext2_htree.c
deleted file mode 100644
index c847aa4..0000000
--- a/sys/fs/ext2fs/ext2_htree.c
+++ /dev/null
@@ -1,899 +0,0 @@
-/*-
- * Copyright (c) 2010, 2012 Zheng Liu <lz@freebsd.org>
- * Copyright (c) 2012, Vyacheslav Matyushin
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/param.h>
-#include <sys/endian.h>
-#include <sys/systm.h>
-#include <sys/namei.h>
-#include <sys/bio.h>
-#include <sys/buf.h>
-#include <sys/endian.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/malloc.h>
-#include <sys/dirent.h>
-#include <sys/sysctl.h>
-
-#include <ufs/ufs/dir.h>
-
-#include <fs/ext2fs/inode.h>
-#include <fs/ext2fs/ext2_mount.h>
-#include <fs/ext2fs/ext2fs.h>
-#include <fs/ext2fs/fs.h>
-#include <fs/ext2fs/ext2_extern.h>
-#include <fs/ext2fs/ext2_dinode.h>
-#include <fs/ext2fs/ext2_dir.h>
-#include <fs/ext2fs/htree.h>
-
-static void ext2_append_entry(char *block, uint32_t blksize,
- struct ext2fs_direct_2 *last_entry,
- struct ext2fs_direct_2 *new_entry);
-static int ext2_htree_append_block(struct vnode *vp, char *data,
- struct componentname *cnp, uint32_t blksize);
-static int ext2_htree_check_next(struct inode *ip, uint32_t hash,
- const char *name, struct ext2fs_htree_lookup_info *info);
-static int ext2_htree_cmp_sort_entry(const void *e1, const void *e2);
-static int ext2_htree_find_leaf(struct inode *ip, const char *name,
- int namelen, uint32_t *hash, uint8_t *hash_version,
- struct ext2fs_htree_lookup_info *info);
-static uint32_t ext2_htree_get_block(struct ext2fs_htree_entry *ep);
-static uint16_t ext2_htree_get_count(struct ext2fs_htree_entry *ep);
-static uint32_t ext2_htree_get_hash(struct ext2fs_htree_entry *ep);
-static uint16_t ext2_htree_get_limit(struct ext2fs_htree_entry *ep);
-static void ext2_htree_insert_entry_to_level(struct ext2fs_htree_lookup_level *level,
- uint32_t hash, uint32_t blk);
-static void ext2_htree_insert_entry(struct ext2fs_htree_lookup_info *info,
- uint32_t hash, uint32_t blk);
-static uint32_t ext2_htree_node_limit(struct inode *ip);
-static void ext2_htree_set_block(struct ext2fs_htree_entry *ep,
- uint32_t blk);
-static void ext2_htree_set_count(struct ext2fs_htree_entry *ep,
- uint16_t cnt);
-static void ext2_htree_set_hash(struct ext2fs_htree_entry *ep,
- uint32_t hash);
-static void ext2_htree_set_limit(struct ext2fs_htree_entry *ep,
- uint16_t limit);
-static int ext2_htree_split_dirblock(char *block1, char *block2,
- uint32_t blksize, uint32_t *hash_seed, uint8_t hash_version,
- uint32_t *split_hash, struct ext2fs_direct_2 *entry);
-static void ext2_htree_release(struct ext2fs_htree_lookup_info *info);
-static uint32_t ext2_htree_root_limit(struct inode *ip, int len);
-static int ext2_htree_writebuf(struct ext2fs_htree_lookup_info *info);
-
-int
-ext2_htree_has_idx(struct inode *ip)
-{
- if (EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX) &&
- ip->i_flag & IN_E4INDEX)
- return (1);
- else
- return (0);
-}
-
-static int
-ext2_htree_check_next(struct inode *ip, uint32_t hash, const char *name,
- struct ext2fs_htree_lookup_info *info)
-{
- struct vnode *vp = ITOV(ip);
- struct ext2fs_htree_lookup_level *level;
- struct buf *bp;
- uint32_t next_hash;
- int idx = info->h_levels_num - 1;
- int levels = 0;
-
- do {
- level = &info->h_levels[idx];
- level->h_entry++;
- if (level->h_entry < level->h_entries +
- ext2_htree_get_count(level->h_entries))
- break;
- if (idx == 0)
- return (0);
- idx--;
- levels++;
- } while (1);
-
- next_hash = ext2_htree_get_hash(level->h_entry);
- if ((hash & 1) == 0) {
- if (hash != (next_hash & ~1))
- return (0);
- }
-
- while (levels > 0) {
- levels--;
- if (ext2_blkatoff(vp, ext2_htree_get_block(level->h_entry) *
- ip->i_e2fs->e2fs_bsize, NULL, &bp) != 0)
- return (0);
- level = &info->h_levels[idx + 1];
- brelse(level->h_bp);
- level->h_bp = bp;
- level->h_entry = level->h_entries =
- ((struct ext2fs_htree_node *)bp->b_data)->h_entries;
- }
-
- return (1);
-}
-
-static uint32_t
-ext2_htree_get_block(struct ext2fs_htree_entry *ep)
-{
- return (ep->h_blk & 0x00FFFFFF);
-}
-
-static void
-ext2_htree_set_block(struct ext2fs_htree_entry *ep, uint32_t blk)
-{
- ep->h_blk = blk;
-}
-
-static uint16_t
-ext2_htree_get_count(struct ext2fs_htree_entry *ep)
-{
- return (((struct ext2fs_htree_count *)(ep))->h_entries_num);
-}
-
-static void
-ext2_htree_set_count(struct ext2fs_htree_entry *ep, uint16_t cnt)
-{
- ((struct ext2fs_htree_count *)(ep))->h_entries_num = cnt;
-}
-
-static uint32_t
-ext2_htree_get_hash(struct ext2fs_htree_entry *ep)
-{
- return (ep->h_hash);
-}
-
-static uint16_t
-ext2_htree_get_limit(struct ext2fs_htree_entry *ep)
-{
- return (((struct ext2fs_htree_count *)(ep))->h_entries_max);
-}
-
-static void
-ext2_htree_set_hash(struct ext2fs_htree_entry *ep, uint32_t hash)
-{
- ep->h_hash = hash;
-}
-
-static void
-ext2_htree_set_limit(struct ext2fs_htree_entry *ep, uint16_t limit)
-{
- ((struct ext2fs_htree_count *)(ep))->h_entries_max = limit;
-}
-
-static void
-ext2_htree_release(struct ext2fs_htree_lookup_info *info)
-{
- int i;
-
- for (i = 0; i < info->h_levels_num; i++) {
- struct buf *bp = info->h_levels[i].h_bp;
- if (bp != NULL)
- brelse(bp);
- }
-}
-
-static uint32_t
-ext2_htree_root_limit(struct inode *ip, int len)
-{
- uint32_t space;
-
- space = ip->i_e2fs->e2fs_bsize - EXT2_DIR_REC_LEN(1) -
- EXT2_DIR_REC_LEN(2) - len;
- return (space / sizeof(struct ext2fs_htree_entry));
-}
-
-static uint32_t
-ext2_htree_node_limit(struct inode *ip)
-{
- struct m_ext2fs *fs;
- uint32_t space;
-
- fs = ip->i_e2fs;
- space = fs->e2fs_bsize - EXT2_DIR_REC_LEN(0);
-
- return (space / sizeof(struct ext2fs_htree_entry));
-}
-
-static int
-ext2_htree_find_leaf(struct inode *ip, const char *name, int namelen,
- uint32_t *hash, uint8_t *hash_ver,
- struct ext2fs_htree_lookup_info *info)
-{
- struct vnode *vp;
- struct ext2fs *fs;
- struct m_ext2fs *m_fs;
- struct buf *bp = NULL;
- struct ext2fs_htree_root *rootp;
- struct ext2fs_htree_entry *entp, *start, *end, *middle, *found;
- struct ext2fs_htree_lookup_level *level_info;
- uint32_t hash_major = 0, hash_minor = 0;
- uint32_t levels, cnt;
- uint8_t hash_version;
-
- if (name == NULL || info == NULL)
- return (-1);
-
- vp = ITOV(ip);
- fs = ip->i_e2fs->e2fs;
- m_fs = ip->i_e2fs;
-
- if (ext2_blkatoff(vp, 0, NULL, &bp) != 0)
- return (-1);
-
- info->h_levels_num = 1;
- info->h_levels[0].h_bp = bp;
- rootp = (struct ext2fs_htree_root *)bp->b_data;
- if (rootp->h_info.h_hash_version != EXT2_HTREE_LEGACY &&
- rootp->h_info.h_hash_version != EXT2_HTREE_HALF_MD4 &&
- rootp->h_info.h_hash_version != EXT2_HTREE_TEA)
- goto error;
-
- hash_version = rootp->h_info.h_hash_version;
- if (hash_version <= EXT2_HTREE_TEA)
- hash_version += m_fs->e2fs_uhash;
- *hash_ver = hash_version;
-
- ext2_htree_hash(name, namelen, fs->e3fs_hash_seed,
- hash_version, &hash_major, &hash_minor);
- *hash = hash_major;
-
- if ((levels = rootp->h_info.h_ind_levels) > 1)
- goto error;
-
- entp = (struct ext2fs_htree_entry *)(((char *)&rootp->h_info) +
- rootp->h_info.h_info_len);
-
- if (ext2_htree_get_limit(entp) !=
- ext2_htree_root_limit(ip, rootp->h_info.h_info_len))
- goto error;
-
- while (1) {
- cnt = ext2_htree_get_count(entp);
- if (cnt == 0 || cnt > ext2_htree_get_limit(entp))
- goto error;
-
- start = entp + 1;
- end = entp + cnt - 1;
- while (start <= end) {
- middle = start + (end - start) / 2;
- if (ext2_htree_get_hash(middle) > hash_major)
- end = middle - 1;
- else
- start = middle + 1;
- }
- found = start - 1;
-
- level_info = &(info->h_levels[info->h_levels_num - 1]);
- level_info->h_bp = bp;
- level_info->h_entries = entp;
- level_info->h_entry = found;
- if (levels == 0)
- return (0);
- levels--;
- if (ext2_blkatoff(vp,
- ext2_htree_get_block(found) * m_fs->e2fs_bsize,
- NULL, &bp) != 0)
- goto error;
- entp = ((struct ext2fs_htree_node *)bp->b_data)->h_entries;
- info->h_levels_num++;
- info->h_levels[info->h_levels_num - 1].h_bp = bp;
- }
-
-error:
- ext2_htree_release(info);
- return (-1);
-}
-
-/*
- * Try to lookup a directory entry in HTree index
- */
-int
-ext2_htree_lookup(struct inode *ip, const char *name, int namelen,
- struct buf **bpp, int *entryoffp, doff_t *offp,
- doff_t *prevoffp, doff_t *endusefulp,
- struct ext2fs_searchslot *ss)
-{
- struct vnode *vp;
- struct ext2fs_htree_lookup_info info;
- struct ext2fs_htree_entry *leaf_node;
- struct m_ext2fs *m_fs;
- struct buf *bp;
- uint32_t blk;
- uint32_t dirhash;
- uint32_t bsize;
- uint8_t hash_version;
- int search_next;
- int found = 0;
-
- m_fs = ip->i_e2fs;
- bsize = m_fs->e2fs_bsize;
- vp = ITOV(ip);
-
- /* TODO: print error msg because we don't lookup '.' and '..' */
-
- memset(&info, 0, sizeof(info));
- if (ext2_htree_find_leaf(ip, name, namelen, &dirhash,
- &hash_version, &info))
- return (-1);
-
- do {
- leaf_node = info.h_levels[info.h_levels_num - 1].h_entry;
- blk = ext2_htree_get_block(leaf_node);
- if (ext2_blkatoff(vp, blk * bsize, NULL, &bp) != 0) {
- ext2_htree_release(&info);
- return (-1);
- }
-
- *offp = blk * bsize;
- *entryoffp = 0;
- *prevoffp = blk * bsize;
- *endusefulp = blk * bsize;
-
- if (ss->slotstatus == NONE) {
- ss->slotoffset = -1;
- ss->slotfreespace = 0;
- }
-
- if (ext2_search_dirblock(ip, bp->b_data, &found,
- name, namelen, entryoffp, offp, prevoffp,
- endusefulp, ss) != 0) {
- brelse(bp);
- ext2_htree_release(&info);
- return (-1);
- }
-
- if (found) {
- *bpp = bp;
- ext2_htree_release(&info);
- return (0);
- }
-
- brelse(bp);
- search_next = ext2_htree_check_next(ip, dirhash, name, &info);
- } while (search_next);
-
- ext2_htree_release(&info);
- return (ENOENT);
-}
-
-static int
-ext2_htree_append_block(struct vnode *vp, char *data,
- struct componentname *cnp, uint32_t blksize)
-{
- struct iovec aiov;
- struct uio auio;
- struct inode *dp = VTOI(vp);
- uint64_t cursize, newsize;
- int error;
-
- cursize = roundup(dp->i_size, blksize);
- newsize = cursize + blksize;
-
- auio.uio_offset = cursize;
- auio.uio_resid = blksize;
- aiov.iov_len = blksize;
- aiov.iov_base = data;
- auio.uio_iov = &aiov;
- auio.uio_iovcnt = 1;
- auio.uio_rw = UIO_WRITE;
- auio.uio_segflg = UIO_SYSSPACE;
- error = VOP_WRITE(vp, &auio, IO_SYNC, cnp->cn_cred);
- if (!error)
- dp->i_size = newsize;
-
- return (error);
-}
-
-static int
-ext2_htree_writebuf(struct ext2fs_htree_lookup_info *info)
-{
- int i, error;
-
- for (i = 0; i < info->h_levels_num; i++) {
- struct buf *bp = info->h_levels[i].h_bp;
- error = bwrite(bp);
- if (error)
- return (error);
- }
-
- return (0);
-}
-
-static void
-ext2_htree_insert_entry_to_level(struct ext2fs_htree_lookup_level *level,
- uint32_t hash, uint32_t blk)
-{
- struct ext2fs_htree_entry *target;
- int entries_num;
-
- target = level->h_entry + 1;
- entries_num = ext2_htree_get_count(level->h_entries);
-
- memmove(target + 1, target, (char *)(level->h_entries + entries_num) -
- (char *)target);
- ext2_htree_set_block(target, blk);
- ext2_htree_set_hash(target, hash);
- ext2_htree_set_count(level->h_entries, entries_num + 1);
-}
-
-/*
- * Insert an index entry to the index node.
- */
-static void
-ext2_htree_insert_entry(struct ext2fs_htree_lookup_info *info,
- uint32_t hash, uint32_t blk)
-{
- struct ext2fs_htree_lookup_level *level;
-
- level = &info->h_levels[info->h_levels_num - 1];
- ext2_htree_insert_entry_to_level(level, hash, blk);
-}
-
-/*
- * Compare two entry sort descriptors by name hash value.
- * This is used together with qsort.
- */
-static int
-ext2_htree_cmp_sort_entry(const void *e1, const void *e2)
-{
- const struct ext2fs_htree_sort_entry *entry1, *entry2;
-
- entry1 = (const struct ext2fs_htree_sort_entry *)e1;
- entry2 = (const struct ext2fs_htree_sort_entry *)e2;
-
- if (entry1->h_hash < entry2->h_hash)
- return (-1);
- if (entry1->h_hash > entry2->h_hash)
- return (1);
- return (0);
-}
-
-/*
- * Append an entry to the end of the directory block.
- */
-static void
-ext2_append_entry(char *block, uint32_t blksize,
- struct ext2fs_direct_2 *last_entry,
- struct ext2fs_direct_2 *new_entry)
-{
- uint16_t entry_len;
-
- entry_len = EXT2_DIR_REC_LEN(last_entry->e2d_namlen);
- last_entry->e2d_reclen = entry_len;
- last_entry = (struct ext2fs_direct_2 *)((char *)last_entry + entry_len);
- new_entry->e2d_reclen = block + blksize - (char *)last_entry;
- memcpy(last_entry, new_entry, EXT2_DIR_REC_LEN(new_entry->e2d_namlen));
-}
-
-/*
- * Move half of entries from the old directory block to the new one.
- */
-static int
-ext2_htree_split_dirblock(char *block1, char *block2, uint32_t blksize,
- uint32_t *hash_seed, uint8_t hash_version,
- uint32_t *split_hash, struct ext2fs_direct_2 *entry)
-{
- int entry_cnt = 0;
- int size = 0;
- int i, k;
- uint32_t offset;
- uint16_t entry_len = 0;
- uint32_t entry_hash;
- struct ext2fs_direct_2 *ep, *last;
- char *dest;
- struct ext2fs_htree_sort_entry *sort_info;
-
- ep = (struct ext2fs_direct_2 *)block1;
- dest = block2;
- sort_info = (struct ext2fs_htree_sort_entry *)
- ((char *)block2 + blksize);
-
- /*
- * Calculate name hash value for the entry which is to be added.
- */
- ext2_htree_hash(entry->e2d_name, entry->e2d_namlen, hash_seed,
- hash_version, &entry_hash, NULL);
-
- /*
- * Fill in directory entry sort descriptors.
- */
- while ((char *)ep < block1 + blksize) {
- if (ep->e2d_ino && ep->e2d_namlen) {
- entry_cnt++;
- sort_info--;
- sort_info->h_size = ep->e2d_reclen;
- sort_info->h_offset = (char *)ep - block1;
- ext2_htree_hash(ep->e2d_name, ep->e2d_namlen,
- hash_seed, hash_version,
- &sort_info->h_hash, NULL);
- }
- ep = (struct ext2fs_direct_2 *)
- ((char *)ep + ep->e2d_reclen);
- }
-
- /*
- * Sort directory entry descriptors by name hash value.
- */
- qsort(sort_info, entry_cnt, sizeof(struct ext2fs_htree_sort_entry),
- ext2_htree_cmp_sort_entry);
-
- /*
- * Count the number of entries to move to directory block 2.
- */
- for (i = entry_cnt - 1; i >= 0; i--) {
- if (sort_info[i].h_size + size > blksize / 2)
- break;
- size += sort_info[i].h_size;
- }
-
- *split_hash = sort_info[i + 1].h_hash;
-
- /*
- * Set collision bit.
- */
- if (*split_hash == sort_info[i].h_hash)
- *split_hash += 1;
-
- /*
- * Move half of directory entries from block 1 to block 2.
- */
- for (k = i + 1; k < entry_cnt; k++) {
- ep = (struct ext2fs_direct_2 *)((char *)block1 +
- sort_info[k].h_offset);
- entry_len = EXT2_DIR_REC_LEN(ep->e2d_namlen);
- memcpy(dest, ep, entry_len);
- ((struct ext2fs_direct_2 *)dest)->e2d_reclen = entry_len;
- /* Mark directory entry as unused. */
- ep->e2d_ino = 0;
- dest += entry_len;
- }
- dest -= entry_len;
-
- /* Shrink directory entries in block 1. */
- last = (struct ext2fs_direct_2 *)block1;
- entry_len = EXT2_DIR_REC_LEN(last->e2d_namlen);
- for (offset = last->e2d_reclen; offset < blksize; ) {
- ep = (struct ext2fs_direct_2 *)(block1 + offset);
- offset += ep->e2d_reclen;
- if (last->e2d_ino) {
- /* Trim the existing slot */
- last->e2d_reclen = entry_len;
- last = (struct ext2fs_direct_2 *)
- ((char *)last + entry_len);
- }
- entry_len = EXT2_DIR_REC_LEN(ep->e2d_namlen);
- memcpy((void *)last, (void *)ep, entry_len);
- }
-
- if (entry_hash >= *split_hash) {
- /* Add entry to block 2. */
- ext2_append_entry(block2, blksize,
- (struct ext2fs_direct_2 *)dest, entry);
-
- /* Adjust length field of last entry of block 1. */
- last->e2d_reclen = block1 + blksize - (char *)last;
- } else {
- /* Add entry to block 1. */
- ext2_append_entry(block1, blksize, last, entry);
-
- /* Adjust length field of last entry of block 2. */
- ((struct ext2fs_direct_2 *)dest)->e2d_reclen =
- block2 + blksize - dest;
- }
-
- return (0);
-}
-
-/*
- * Create an HTree index for a directory
- */
-int
-ext2_htree_create_index(struct vnode *vp, struct componentname *cnp,
- struct ext2fs_direct_2 *new_entry)
-{
- struct buf *bp = NULL;
- struct inode *dp;
- struct ext2fs *fs;
- struct m_ext2fs *m_fs;
- struct ext2fs_direct_2 *ep, *dotdot;
- struct ext2fs_htree_root *root;
- struct ext2fs_htree_lookup_info info;
- uint32_t blksize, dirlen, split_hash;
- uint8_t hash_version;
- char *buf1 = NULL;
- char *buf2 = NULL;
- int error = 0;
-
- dp = VTOI(vp);
- fs = dp->i_e2fs->e2fs;
- m_fs = dp->i_e2fs;
- blksize = m_fs->e2fs_bsize;
-
- buf1 = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
- buf2 = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
-
- if ((error = ext2_blkatoff(vp, 0, NULL, &bp)) != 0)
- goto out;
-
- root = (struct ext2fs_htree_root *)bp->b_data;
- dotdot = (struct ext2fs_direct_2 *)((char *)&(root->h_dotdot));
- ep = (struct ext2fs_direct_2 *)((char *)dotdot + dotdot->e2d_reclen);
- dirlen = (char *)root + blksize - (char *)ep;
- memcpy(buf1, ep, dirlen);
- ep = (struct ext2fs_direct_2 *)buf1;
- while ((char *)ep < buf1 + dirlen)
- ep = (struct ext2fs_direct_2 *)
- ((char *)ep + ep->e2d_reclen);
- ep->e2d_reclen = buf1 + blksize - (char *)ep;
-
- dp->i_flag |= IN_E4INDEX;
-
- /*
- * Initialize index root.
- */
- dotdot->e2d_reclen = blksize - EXT2_DIR_REC_LEN(1);
- memset(&root->h_info, 0, sizeof(root->h_info));
- root->h_info.h_hash_version = fs->e3fs_def_hash_version;
- root->h_info.h_info_len = sizeof(root->h_info);
- ext2_htree_set_block(root->h_entries, 1);
- ext2_htree_set_count(root->h_entries, 1);
- ext2_htree_set_limit(root->h_entries,
- ext2_htree_root_limit(dp, sizeof(root->h_info)));
-
- memset(&info, 0, sizeof(info));
- info.h_levels_num = 1;
- info.h_levels[0].h_entries = root->h_entries;
- info.h_levels[0].h_entry = root->h_entries;
-
- hash_version = root->h_info.h_hash_version;
- if (hash_version <= EXT2_HTREE_TEA)
- hash_version += m_fs->e2fs_uhash;
- ext2_htree_split_dirblock(buf1, buf2, blksize, fs->e3fs_hash_seed,
- hash_version, &split_hash, new_entry);
- ext2_htree_insert_entry(&info, split_hash, 2);
-
- /*
- * Write directory block 0.
- */
- if (DOINGASYNC(vp)) {
- bdwrite(bp);
- error = 0;
- } else {
- error = bwrite(bp);
- }
- dp->i_flag |= IN_CHANGE | IN_UPDATE;
- if (error)
- goto out;
-
- /*
- * Write directory block 1.
- */
- error = ext2_htree_append_block(vp, buf1, cnp, blksize);
- if (error)
- goto out1;
-
- /*
- * Write directory block 2.
- */
- error = ext2_htree_append_block(vp, buf2, cnp, blksize);
-
- free(buf1, M_TEMP);
- free(buf2, M_TEMP);
- return (error);
-out:
- if (bp != NULL)
- brelse(bp);
-out1:
- free(buf1, M_TEMP);
- free(buf2, M_TEMP);
- return (error);
-}
-
-/*
- * Add an entry to the directory using htree index.
- */
-int
-ext2_htree_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry,
- struct componentname *cnp)
-{
- struct ext2fs_htree_entry *entries, *leaf_node;
- struct ext2fs_htree_lookup_info info;
- struct buf *bp = NULL;
- struct ext2fs *fs;
- struct m_ext2fs *m_fs;
- struct inode *ip;
- uint16_t ent_num;
- uint32_t dirhash, split_hash;
- uint32_t blksize, blknum;
- uint64_t cursize, dirsize;
- uint8_t hash_version;
- char *newdirblock = NULL;
- char *newidxblock = NULL;
- struct ext2fs_htree_node *dst_node;
- struct ext2fs_htree_entry *dst_entries;
- struct ext2fs_htree_entry *root_entires;
- struct buf *dst_bp = NULL;
- int error, write_bp = 0, write_dst_bp = 0, write_info = 0;
-
- ip = VTOI(dvp);
- m_fs = ip->i_e2fs;
- fs = m_fs->e2fs;
- blksize = m_fs->e2fs_bsize;
-
- if (ip->i_count != 0)
- return ext2_add_entry(dvp, entry);
-
- /* Target directory block is full, split it */
- memset(&info, 0, sizeof(info));
- error = ext2_htree_find_leaf(ip, entry->e2d_name, entry->e2d_namlen,
- &dirhash, &hash_version, &info);
- if (error)
- return (error);
-
- entries = info.h_levels[info.h_levels_num - 1].h_entries;
- ent_num = ext2_htree_get_count(entries);
- if (ent_num == ext2_htree_get_limit(entries)) {
- /* Split the index node. */
- root_entires = info.h_levels[0].h_entries;
- newidxblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
- dst_node = (struct ext2fs_htree_node *)newidxblock;
- dst_entries = dst_node->h_entries;
- memset(&dst_node->h_fake_dirent, 0,
- sizeof(dst_node->h_fake_dirent));
- dst_node->h_fake_dirent.e2d_reclen = blksize;
-
- cursize = roundup(ip->i_size, blksize);
- dirsize = cursize + blksize;
- blknum = dirsize / blksize - 1;
-
- error = ext2_htree_append_block(dvp, newidxblock,
- cnp, blksize);
- if (error)
- goto finish;
- error = ext2_blkatoff(dvp, cursize, NULL, &dst_bp);
- if (error)
- goto finish;
- dst_node = (struct ext2fs_htree_node *)dst_bp->b_data;
- dst_entries = dst_node->h_entries;
-
- if (info.h_levels_num == 2) {
- uint16_t src_ent_num, dst_ent_num;
-
- if (ext2_htree_get_count(root_entires) ==
- ext2_htree_get_limit(root_entires)) {
- /* Directory index is full */
- error = EIO;
- goto finish;
- }
-
- src_ent_num = ent_num / 2;
- dst_ent_num = ent_num - src_ent_num;
- split_hash = ext2_htree_get_hash(entries + src_ent_num);
-
- /* Move half of index entries to the new index node */
- memcpy(dst_entries, entries + src_ent_num,
- dst_ent_num * sizeof(struct ext2fs_htree_entry));
- ext2_htree_set_count(entries, src_ent_num);
- ext2_htree_set_count(dst_entries, dst_ent_num);
- ext2_htree_set_limit(dst_entries,
- ext2_htree_node_limit(ip));
-
- if (info.h_levels[1].h_entry >= entries + src_ent_num) {
- struct buf *tmp = info.h_levels[1].h_bp;
- info.h_levels[1].h_bp = dst_bp;
- dst_bp = tmp;
-
- info.h_levels[1].h_entry =
- info.h_levels[1].h_entry -
- (entries + src_ent_num) +
- dst_entries;
- info.h_levels[1].h_entries = dst_entries;
- }
- ext2_htree_insert_entry_to_level(&info.h_levels[0],
- split_hash, blknum);
-
- /* Write new index node to disk */
- error = bwrite(dst_bp);
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
- if (error)
- goto finish;
- write_dst_bp = 1;
- } else {
- /* Create second level for htree index */
- struct ext2fs_htree_root *idx_root;
-
- memcpy(dst_entries, entries,
- ent_num * sizeof(struct ext2fs_htree_entry));
- ext2_htree_set_limit(dst_entries,
- ext2_htree_node_limit(ip));
-
- idx_root = (struct ext2fs_htree_root *)
- info.h_levels[0].h_bp->b_data;
- idx_root->h_info.h_ind_levels = 1;
-
- ext2_htree_set_count(entries, 1);
- ext2_htree_set_block(entries, blknum);
-
- info.h_levels_num = 2;
- info.h_levels[1].h_entries = dst_entries;
- info.h_levels[1].h_entry = info.h_levels[0].h_entry -
- info.h_levels[0].h_entries + dst_entries;
- info.h_levels[1].h_bp = dst_bp;
- }
- }
-
- leaf_node = info.h_levels[info.h_levels_num - 1].h_entry;
- blknum = ext2_htree_get_block(leaf_node);
- error = ext2_blkatoff(dvp, blknum * blksize, NULL, &bp);
- if (error)
- goto finish;
-
- /* Split target directory block */
- newdirblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
- ext2_htree_split_dirblock((char *)bp->b_data, newdirblock, blksize,
- fs->e3fs_hash_seed, hash_version, &split_hash, entry);
- cursize = roundup(ip->i_size, blksize);
- dirsize = cursize + blksize;
- blknum = dirsize / blksize - 1;
-
- /* Add index entry for the new directory block */
- ext2_htree_insert_entry(&info, split_hash, blknum);
-
- /* Write the new directory block to the end of the directory */
- error = ext2_htree_append_block(dvp, newdirblock, cnp, blksize);
- if (error)
- goto finish;
-
- /* Write the target directory block */
- error = bwrite(bp);
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
- if (error)
- goto finish;
- write_bp = 1;
-
- /* Write the index block */
- error = ext2_htree_writebuf(&info);
- if (!error)
- write_info = 1;
-
-finish:
- if (dst_bp != NULL && !write_dst_bp)
- brelse(dst_bp);
- if (bp != NULL && !write_bp)
- brelse(bp);
- if (newdirblock != NULL)
- free(newdirblock, M_TEMP);
- if (newidxblock != NULL)
- free(newidxblock, M_TEMP);
- if (!write_info)
- ext2_htree_release(&info);
- return (error);
-}
diff --git a/sys/fs/ext2fs/ext2_lookup.c b/sys/fs/ext2fs/ext2_lookup.c
index f9845bd..379eb44 100644
--- a/sys/fs/ext2fs/ext2_lookup.c
+++ b/sys/fs/ext2fs/ext2_lookup.c
@@ -113,19 +113,9 @@ static u_char dt_to_ext2_ft[] = {
static int ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de,
int entryoffsetinblock);
-static int ext2_is_dot_entry(struct componentname *cnp);
static int ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp,
struct componentname *cnp, ino_t *dd_ino);
-static int
-ext2_is_dot_entry(struct componentname *cnp)
-{
- if (cnp->cn_namelen <= 2 && cnp->cn_nameptr[0] == '.' &&
- (cnp->cn_nameptr[1] == '.' || cnp->cn_nameptr[1] == '0'))
- return (1);
- return (0);
-}
-
/*
* Vnode op for reading directories.
*/
@@ -306,9 +296,13 @@ ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp
struct buf *bp; /* a buffer of directory entries */
struct ext2fs_direct_2 *ep; /* the current directory entry */
int entryoffsetinblock; /* offset of ep in bp's buffer */
- struct ext2fs_searchslot ss;
+ enum {NONE, COMPACT, FOUND} slotstatus;
+ doff_t slotoffset; /* offset of area with free space */
doff_t i_diroff; /* cached i_diroff value */
doff_t i_offset; /* cached i_offset value */
+ int slotsize; /* size of area at slotoffset */
+ int slotfreespace; /* amount of space free in slot */
+ int slotneeded; /* size of the entry we're seeking */
int numdirpasses; /* strategy for directory search */
doff_t endsearch; /* offset to end directory search */
doff_t prevoff; /* prev entry dp->i_offset */
@@ -316,13 +310,12 @@ ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp
struct vnode *tdp; /* returned by VFS_VGET */
doff_t enduseful; /* pointer past last used dir slot */
u_long bmask; /* block offset mask */
- int error;
+ int namlen, error;
struct ucred *cred = cnp->cn_cred;
int flags = cnp->cn_flags;
int nameiop = cnp->cn_nameiop;
ino_t ino, ino1;
int ltype;
- int entry_found = 0;
int DIRBLKSIZ = VTOI(vdp)->i_e2fs->e2fs_bsize;
@@ -333,57 +326,31 @@ ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp
bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
restart:
bp = NULL;
- ss.slotoffset = -1;
+ slotoffset = -1;
/*
* We now have a segment name to search for, and a directory to search.
- *
+ */
+
+ /*
* Suppress search for slots unless creating
* file and at end of pathname, in which case
* we watch for a place to put the new file in
* case it doesn't already exist.
*/
i_diroff = dp->i_diroff;
- ss.slotstatus = FOUND;
- ss.slotfreespace = ss.slotsize = ss.slotneeded = 0;
+ slotstatus = FOUND;
+ slotfreespace = slotsize = slotneeded = 0;
if ((nameiop == CREATE || nameiop == RENAME) &&
(flags & ISLASTCN)) {
- ss.slotstatus = NONE;
- ss.slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen);
+ slotstatus = NONE;
+ slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen);
/* was
- ss.slotneeded = (sizeof(struct direct) - MAXNAMLEN +
+ slotneeded = (sizeof(struct direct) - MAXNAMLEN +
cnp->cn_namelen + 3) &~ 3; */
}
/*
- * Try to lookup dir entry using htree directory index.
- *
- * If we got an error or we want to find '.' or '..' entry,
- * we will fall back to linear search.
- */
- if (!ext2_is_dot_entry(cnp) && ext2_htree_has_idx(dp)) {
- numdirpasses = 1;
- entryoffsetinblock = 0;
- switch (ext2_htree_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen,
- &bp, &entryoffsetinblock, &i_offset, &prevoff,
- &enduseful, &ss)) {
- case 0:
- ep = (struct ext2fs_direct_2 *)((char *)bp->b_data +
- (i_offset & bmask));
- goto foundentry;
- case ENOENT:
- i_offset = roundup2(dp->i_size, DIRBLKSIZ);
- goto notfound;
- default:
- /*
- * Something failed; just fallback to do a linear
- * search.
- */
- break;
- }
- }
-
- /*
* If there is cached information on a previous search of
* this directory, pick up where we last left off.
* We cache only lookups as these are the most common
@@ -417,38 +384,96 @@ searchloop:
/*
* If necessary, get the next directory block.
*/
- if (bp != NULL)
- brelse(bp);
- error = ext2_blkatoff(vdp, (off_t)i_offset, NULL, &bp);
- if (error != 0)
- return (error);
- entryoffsetinblock = 0;
+ if ((i_offset & bmask) == 0) {
+ if (bp != NULL)
+ brelse(bp);
+ if ((error =
+ ext2_blkatoff(vdp, (off_t)i_offset, NULL,
+ &bp)) != 0)
+ return (error);
+ entryoffsetinblock = 0;
+ }
/*
* If still looking for a slot, and at a DIRBLKSIZE
* boundary, have to start looking for free space again.
*/
- if (ss.slotstatus == NONE &&
+ if (slotstatus == NONE &&
(entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
- ss.slotoffset = -1;
- ss.slotfreespace = 0;
+ slotoffset = -1;
+ slotfreespace = 0;
}
- error = ext2_search_dirblock(dp, bp->b_data, &entry_found,
- cnp->cn_nameptr, cnp->cn_namelen,
- &entryoffsetinblock, &i_offset, &prevoff,
- &enduseful, &ss);
- if (error != 0) {
- brelse(bp);
- return (error);
+ /*
+ * Get pointer to next entry.
+ * Full validation checks are slow, so we only check
+ * enough to insure forward progress through the
+ * directory. Complete checks can be run by setting
+ * "vfs.e2fs.dirchk" to be true.
+ */
+ ep = (struct ext2fs_direct_2 *)
+ ((char *)bp->b_data + entryoffsetinblock);
+ if (ep->e2d_reclen == 0 ||
+ (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
+ int i;
+ ext2_dirbad(dp, i_offset, "mangled entry");
+ i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
+ i_offset += i;
+ entryoffsetinblock += i;
+ continue;
+ }
+
+ /*
+ * If an appropriate sized slot has not yet been found,
+ * check to see if one is available. Also accumulate space
+ * in the current block so that we can determine if
+ * compaction is viable.
+ */
+ if (slotstatus != FOUND) {
+ int size = ep->e2d_reclen;
+
+ if (ep->e2d_ino != 0)
+ size -= EXT2_DIR_REC_LEN(ep->e2d_namlen);
+ if (size > 0) {
+ if (size >= slotneeded) {
+ slotstatus = FOUND;
+ slotoffset = i_offset;
+ slotsize = ep->e2d_reclen;
+ } else if (slotstatus == NONE) {
+ slotfreespace += size;
+ if (slotoffset == -1)
+ slotoffset = i_offset;
+ if (slotfreespace >= slotneeded) {
+ slotstatus = COMPACT;
+ slotsize = i_offset +
+ ep->e2d_reclen - slotoffset;
+ }
+ }
+ }
}
- if (entry_found) {
- ep = (struct ext2fs_direct_2 *)((char *)bp->b_data +
- (entryoffsetinblock & bmask));
-foundentry:
- ino = ep->e2d_ino;
- goto found;
+
+ /*
+ * Check for a name match.
+ */
+ if (ep->e2d_ino) {
+ namlen = ep->e2d_namlen;
+ if (namlen == cnp->cn_namelen &&
+ !bcmp(cnp->cn_nameptr, ep->e2d_name,
+ (unsigned)namlen)) {
+ /*
+ * Save directory entry's inode number and
+ * reclen in ndp->ni_ufs area, and release
+ * directory buffer.
+ */
+ ino = ep->e2d_ino;
+ goto found;
+ }
}
+ prevoff = i_offset;
+ i_offset += ep->e2d_reclen;
+ entryoffsetinblock += ep->e2d_reclen;
+ if (ep->e2d_ino)
+ enduseful = i_offset;
}
-notfound:
+/* notfound: */
/*
* If we started in the middle of the directory and failed
* to find our target, we must check the beginning as well.
@@ -483,15 +508,15 @@ notfound:
* can be put in the range from dp->i_offset to
* dp->i_offset + dp->i_count.
*/
- if (ss.slotstatus == NONE) {
+ if (slotstatus == NONE) {
dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ);
dp->i_count = 0;
enduseful = dp->i_offset;
} else {
- dp->i_offset = ss.slotoffset;
- dp->i_count = ss.slotsize;
- if (enduseful < ss.slotoffset + ss.slotsize)
- enduseful = ss.slotoffset + ss.slotsize;
+ dp->i_offset = slotoffset;
+ dp->i_count = slotsize;
+ if (enduseful < slotoffset + slotsize)
+ enduseful = slotoffset + slotsize;
}
dp->i_endoff = roundup2(enduseful, DIRBLKSIZ);
/*
@@ -697,102 +722,6 @@ found:
return (0);
}
-int
-ext2_search_dirblock(struct inode *ip, void *data, int *foundp,
- const char *name, int namelen, int *entryoffsetinblockp,
- doff_t *offp, doff_t *prevoffp, doff_t *endusefulp,
- struct ext2fs_searchslot *ssp)
-{
- struct vnode *vdp;
- struct ext2fs_direct_2 *ep, *top;
- uint32_t bsize = ip->i_e2fs->e2fs_bsize;
- int offset = *entryoffsetinblockp;
- int namlen;
-
- vdp = ITOV(ip);
-
- ep = (struct ext2fs_direct_2 *)((char *)data + offset);
- top = (struct ext2fs_direct_2 *)((char *)data +
- bsize - EXT2_DIR_REC_LEN(0));
-
- while (ep < top) {
- /*
- * Full validation checks are slow, so we only check
- * enough to insure forward progress through the
- * directory. Complete checks can be run by setting
- * "vfs.e2fs.dirchk" to be true.
- */
- if (ep->e2d_reclen == 0 ||
- (dirchk && ext2_dirbadentry(vdp, ep, offset))) {
- int i;
- ext2_dirbad(ip, *offp, "mangled entry");
- i = bsize - (offset & (bsize - 1));
- *offp += i;
- offset += i;
- continue;
- }
-
- /*
- * If an appropriate sized slot has not yet been found,
- * check to see if one is available. Also accumulate space
- * in the current block so that we can determine if
- * compaction is viable.
- */
- if (ssp->slotstatus != FOUND) {
- int size = ep->e2d_reclen;
-
- if (ep->e2d_ino != 0)
- size -= EXT2_DIR_REC_LEN(ep->e2d_namlen);
- if (size > 0) {
- if (size >= ssp->slotneeded) {
- ssp->slotstatus = FOUND;
- ssp->slotoffset = *offp;
- ssp->slotsize = ep->e2d_reclen;
- } else if (ssp->slotstatus == NONE) {
- ssp->slotfreespace += size;
- if (ssp->slotoffset == -1)
- ssp->slotoffset = *offp;
- if (ssp->slotfreespace >= ssp->slotneeded) {
- ssp->slotstatus = COMPACT;
- ssp->slotsize = *offp +
- ep->e2d_reclen -
- ssp->slotoffset;
- }
- }
- }
- }
-
- /*
- * Check for a name match.
- */
- if (ep->e2d_ino) {
- namlen = ep->e2d_namlen;
- if (namlen == namelen &&
- !bcmp(name, ep->e2d_name, (unsigned)namlen)) {
- /*
- * Save directory entry's inode number and
- * reclen in ndp->ni_ufs area, and release
- * directory buffer.
- */
- *foundp = 1;
- return (0);
- }
- }
- *prevoffp = *offp;
- *offp += ep->e2d_reclen;
- offset += ep->e2d_reclen;
- *entryoffsetinblockp = offset;
- if (ep->e2d_ino)
- *endusefulp = *offp;
- /*
- * Get pointer to the next entry.
- */
- ep = (struct ext2fs_direct_2 *)((char *)data + offset);
- }
-
- return (0);
-}
-
void
ext2_dirbad(struct inode *ip, doff_t offset, char *how)
{
@@ -862,12 +791,16 @@ ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de,
int
ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
{
+ struct ext2fs_direct_2 *ep, *nep;
struct inode *dp;
+ struct buf *bp;
struct ext2fs_direct_2 newdir;
struct iovec aiov;
struct uio auio;
- int error, newentrysize;
- int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
+ u_int dsize;
+ int error, loc, newentrysize, spacefree;
+ char *dirbuf;
+ int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
#ifdef INVARIANTS
@@ -884,28 +817,6 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
newdir.e2d_type = EXT2_FT_UNKNOWN;
bcopy(cnp->cn_nameptr, newdir.e2d_name, (unsigned)cnp->cn_namelen + 1);
newentrysize = EXT2_DIR_REC_LEN(newdir.e2d_namlen);
-
- if (ext2_htree_has_idx(dp)) {
- error = ext2_htree_add_entry(dvp, &newdir, cnp);
- if (error) {
- dp->i_flag &= ~IN_E4INDEX;
- dp->i_flag |= IN_CHANGE | IN_UPDATE;
- }
- return (error);
- }
-
- if (EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX) &&
- !ext2_htree_has_idx(dp)) {
- if ((dp->i_size / DIRBLKSIZ) == 1 &&
- dp->i_offset == DIRBLKSIZ) {
- /*
- * Making indexed directory when one block is not
- * enough to save all entries.
- */
- return ext2_htree_create_index(dvp, cnp, &newdir);
- }
- }
-
if (dp->i_count == 0) {
/*
* If dp->i_count is 0, then namei could find no
@@ -937,29 +848,6 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
return (error);
}
- error = ext2_add_entry(dvp, &newdir);
- if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
- error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
- cnp->cn_cred, cnp->cn_thread);
- return (error);
-}
-
-/*
- * Insert an entry into the directory block.
- * Compact the contents.
- */
-int
-ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry)
-{
- struct ext2fs_direct_2 *ep, *nep;
- struct inode *dp;
- struct buf *bp;
- u_int dsize;
- int error, loc, newentrysize, spacefree;
- char *dirbuf;
-
- dp = VTOI(dvp);
-
/*
* If dp->i_count is non-zero, then namei found space
* for the new entry in the range dp->i_offset to
@@ -991,7 +879,6 @@ ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry)
* dp->i_offset + dp->i_count would yield the
* space.
*/
- newentrysize = EXT2_DIR_REC_LEN(entry->e2d_namlen);
ep = (struct ext2fs_direct_2 *)dirbuf;
dsize = EXT2_DIR_REC_LEN(ep->e2d_namlen);
spacefree = ep->e2d_reclen - dsize;
@@ -1017,15 +904,15 @@ ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry)
if (ep->e2d_ino == 0) {
if (spacefree + dsize < newentrysize)
panic("ext2_direnter: compact1");
- entry->e2d_reclen = spacefree + dsize;
+ newdir.e2d_reclen = spacefree + dsize;
} else {
if (spacefree < newentrysize)
panic("ext2_direnter: compact2");
- entry->e2d_reclen = spacefree;
+ newdir.e2d_reclen = spacefree;
ep->e2d_reclen = dsize;
ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
}
- bcopy((caddr_t)entry, (caddr_t)ep, (u_int)newentrysize);
+ bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
if (DOINGASYNC(dvp)) {
bdwrite(bp);
error = 0;
@@ -1033,6 +920,9 @@ ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry)
error = bwrite(bp);
}
dp->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
+ error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
+ cnp->cn_cred, cnp->cn_thread);
return (error);
}
diff --git a/sys/fs/ext2fs/ext2_vfsops.c b/sys/fs/ext2fs/ext2_vfsops.c
index b82a41e..ce943ea 100644
--- a/sys/fs/ext2fs/ext2_vfsops.c
+++ b/sys/fs/ext2fs/ext2_vfsops.c
@@ -399,22 +399,8 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
if (es->e2fs_rev == E2FS_REV0 ||
!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE))
fs->e2fs_maxfilesize = 0x7fffffff;
- else {
- fs->e2fs_maxfilesize = 0xffffffffffff;
- if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE))
- fs->e2fs_maxfilesize = 0x7fffffffffffffff;
- }
- if (es->e4fs_flags & E2FS_UNSIGNED_HASH) {
- fs->e2fs_uhash = 3;
- } else if ((es->e4fs_flags & E2FS_SIGNED_HASH) == 0) {
-#ifdef __CHAR_UNSIGNED__
- es->e4fs_flags |= E2FS_UNSIGNED_HASH;
- fs->e2fs_uhash = 3;
-#else
- es->e4fs_flags |= E2FS_SIGNED_HASH;
-#endif
- }
-
+ else
+ fs->e2fs_maxfilesize = 0x7fffffffffffffff;
return (0);
}
@@ -675,7 +661,8 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
* Initialize filesystem stat information in mount struct.
*/
MNT_ILOCK(mp);
- mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
+ mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
+ MNTK_USES_BCACHE;
MNT_IUNLOCK(mp);
return (0);
out:
diff --git a/sys/fs/ext2fs/ext2fs.h b/sys/fs/ext2fs/ext2fs.h
index 6e3a945..ec19300 100644
--- a/sys/fs/ext2fs/ext2fs.h
+++ b/sys/fs/ext2fs/ext2fs.h
@@ -147,7 +147,6 @@ struct m_ext2fs {
int32_t e2fs_contigsumsize; /* size of cluster summary array */
int32_t *e2fs_maxcluster; /* max cluster in each cyl group */
struct csum *e2fs_clustersum; /* cluster summary in each cyl group */
- int32_t e2fs_uhash; /* 3 if hash should be signed, 0 if not */
};
/* cluster summary information */
@@ -212,7 +211,6 @@ struct csum {
* - EXT2F_INCOMPAT_FLEX_BG
* - EXT2F_INCOMPAT_META_BG
*/
-#define EXT2F_COMPAT_SUPP EXT2F_COMPAT_DIRHASHINDEX
#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER | \
EXT2F_ROCOMPAT_LARGEFILE | \
EXT2F_ROCOMPAT_EXTRA_ISIZE)
@@ -242,12 +240,6 @@ struct csum {
#define E2FS_ISCLEAN 0x0001 /* Unmounted cleanly */
#define E2FS_ERRORS 0x0002 /* Errors detected */
-/*
- * Filesystem miscellaneous flags
- */
-#define E2FS_SIGNED_HASH 0x0001
-#define E2FS_UNSIGNED_HASH 0x0002
-
/* ext2 file system block group descriptor */
struct ext2_gd {
diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c
index c00a96c..0a33373 100644
--- a/sys/fs/fuse/fuse_vfsops.c
+++ b/sys/fs/fuse/fuse_vfsops.c
@@ -337,6 +337,7 @@ fuse_vfsop_mount(struct mount *mp)
MNT_ILOCK(mp);
mp->mnt_data = data;
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_kern_flag |= MNTK_USES_BCACHE;
MNT_IUNLOCK(mp);
/* We need this here as this slot is used by getnewvnode() */
mp->mnt_stat.f_iosize = PAGE_SIZE;
diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c
index 3c17f00..cf03e00 100644
--- a/sys/fs/msdosfs/msdosfs_fat.c
+++ b/sys/fs/msdosfs/msdosfs_fat.c
@@ -380,6 +380,8 @@ usemap_alloc(struct msdosfsmount *pmp, u_long cn)
MSDOSFS_ASSERT_MP_LOCKED(pmp);
+ KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
+ ("usemap_alloc on ro msdosfs mount"));
KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
== 0, ("Allocating used sector %ld %ld %x", cn, cn % N_INUSEBITS,
(unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]));
@@ -394,6 +396,8 @@ usemap_free(struct msdosfsmount *pmp, u_long cn)
{
MSDOSFS_ASSERT_MP_LOCKED(pmp);
+ KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
+ ("usemap_free on ro msdosfs mount"));
pmp->pm_freeclustercount++;
pmp->pm_flags |= MSDOSFS_FSIMOD;
KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
@@ -675,6 +679,8 @@ chainalloc(struct msdosfsmount *pmp, u_long start, u_long count,
u_long cl, n;
MSDOSFS_ASSERT_MP_LOCKED(pmp);
+ KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
+ ("chainalloc on ro msdosfs mount"));
for (cl = start, n = count; n-- > 0;)
usemap_alloc(pmp, cl++);
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index d14cdef..7c6d3ed 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -759,6 +759,7 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
MNT_ILOCK(mp);
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_kern_flag |= MNTK_USES_BCACHE;
MNT_IUNLOCK(mp);
if (pmp->pm_flags & MSDOSFS_LARGEFS)
@@ -796,17 +797,17 @@ msdosfs_unmount(struct mount *mp, int mntflags)
struct msdosfsmount *pmp;
int error, flags;
- flags = 0;
- error = msdosfs_sync(mp, MNT_WAIT);
- if ((mntflags & MNT_FORCE) != 0) {
+ error = flags = 0;
+ pmp = VFSTOMSDOSFS(mp);
+ if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0)
+ error = msdosfs_sync(mp, MNT_WAIT);
+ if ((mntflags & MNT_FORCE) != 0)
flags |= FORCECLOSE;
- } else if (error != 0) {
+ else if (error != 0)
return (error);
- }
error = vflush(mp, 0, flags, curthread);
if (error != 0 && error != ENXIO)
return (error);
- pmp = VFSTOMSDOSFS(mp);
if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) {
error = markvoldirty(pmp, 0);
if (error && error != ENXIO) {
diff --git a/sys/fs/nandfs/nandfs_vfsops.c b/sys/fs/nandfs/nandfs_vfsops.c
index eb07d4f..7132635 100644
--- a/sys/fs/nandfs/nandfs_vfsops.c
+++ b/sys/fs/nandfs/nandfs_vfsops.c
@@ -1391,6 +1391,7 @@ nandfs_mountfs(struct vnode *devvp, struct mount *mp)
nmp->nm_ronly = ronly;
MNT_ILOCK(mp);
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_kern_flag |= MNTK_USES_BCACHE;
MNT_IUNLOCK(mp);
nmp->nm_nandfsdev = nandfsdev;
/* Add our mountpoint */
diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h
index 6106de9..2ee9145 100644
--- a/sys/fs/nfs/nfs.h
+++ b/sys/fs/nfs/nfs.h
@@ -159,7 +159,7 @@
(t).tv_sec = time.tv_sec; (t).tv_nsec = 1000 * time.tv_usec; } while (0)
#define NFS_SRVMAXDATA(n) \
(((n)->nd_flag & (ND_NFSV3 | ND_NFSV4)) ? \
- NFS_MAXDATA : NFS_V2MAXDATA)
+ NFS_SRVMAXIO : NFS_V2MAXDATA)
#define NFS64BITSSET 0xffffffffffffffffull
#define NFS64BITSMINUS1 0xfffffffffffffffeull
diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c
index 27aca26..eea146a 100644
--- a/sys/fs/nfs/nfs_commonport.c
+++ b/sys/fs/nfs/nfs_commonport.c
@@ -69,7 +69,7 @@ void (*ncl_call_invalcaches)(struct vnode *) = NULL;
static int nfs_realign_test;
static int nfs_realign_count;
-SYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "New NFS filesystem");
+SYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "NFS filesystem");
SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test,
0, "Number of realign tests done");
SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count,
@@ -78,7 +78,7 @@ SYSCTL_STRING(_vfs_nfs, OID_AUTO, callback_addr, CTLFLAG_RW,
nfsv4_callbackaddr, sizeof(nfsv4_callbackaddr),
"NFSv4 callback addr for server to use");
SYSCTL_INT(_vfs_nfs, OID_AUTO, debuglevel, CTLFLAG_RW, &nfscl_debuglevel,
- 0, "Debug level for new nfs client");
+ 0, "Debug level for NFS client");
/*
* Defines for malloc
@@ -100,12 +100,12 @@ MALLOC_DEFINE(M_NEWNFSCLDELEG, "NFSCL deleg", "NFSCL Delegation");
MALLOC_DEFINE(M_NEWNFSCLCLIENT, "NFSCL client", "NFSCL Client");
MALLOC_DEFINE(M_NEWNFSCLLOCKOWNER, "NFSCL lckown", "NFSCL Lock Owner");
MALLOC_DEFINE(M_NEWNFSCLLOCK, "NFSCL lck", "NFSCL Lock");
-MALLOC_DEFINE(M_NEWNFSV4NODE, "NEWNFSnode", "New nfs vnode");
-MALLOC_DEFINE(M_NEWNFSDIRECTIO, "NEWdirectio", "New nfs Direct IO buffer");
+MALLOC_DEFINE(M_NEWNFSV4NODE, "NEWNFSnode", "NFS vnode");
+MALLOC_DEFINE(M_NEWNFSDIRECTIO, "NEWdirectio", "NFS Direct IO buffer");
MALLOC_DEFINE(M_NEWNFSDIROFF, "NFSCL diroffdiroff",
- "New NFS directory offset data");
+ "NFS directory offset data");
MALLOC_DEFINE(M_NEWNFSDROLLBACK, "NFSD rollback",
- "New NFS local lock rollback");
+ "NFS local lock rollback");
MALLOC_DEFINE(M_NEWNFSLAYOUT, "NFSCL layout", "NFSv4.1 Layout");
MALLOC_DEFINE(M_NEWNFSFLAYOUT, "NFSCL flayout", "NFSv4.1 File Layout");
MALLOC_DEFINE(M_NEWNFSDEVINFO, "NFSCL devinfo", "NFSv4.1 Device Info");
@@ -281,11 +281,11 @@ nfsvno_getfs(struct nfsfsinfo *sip, int isdgram)
if (isdgram)
pref = NFS_MAXDGRAMDATA;
else
- pref = NFS_MAXDATA;
- sip->fs_rtmax = NFS_MAXDATA;
+ pref = NFS_SRVMAXIO;
+ sip->fs_rtmax = NFS_SRVMAXIO;
sip->fs_rtpref = pref;
sip->fs_rtmult = NFS_FABLKSIZE;
- sip->fs_wtmax = NFS_MAXDATA;
+ sip->fs_wtmax = NFS_SRVMAXIO;
sip->fs_wtpref = pref;
sip->fs_wtmult = NFS_FABLKSIZE;
sip->fs_dtpref = pref;
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index 9f08854..42a7f94 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -950,7 +950,7 @@ struct nfsreq {
};
#ifndef NFS_MAXBSIZE
-#define NFS_MAXBSIZE MAXBSIZE
+#define NFS_MAXBSIZE MAXBCACHEBUF
#endif
/*
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
index 768dfcb..08e7b24 100644
--- a/sys/fs/nfs/nfsproto.h
+++ b/sys/fs/nfs/nfsproto.h
@@ -54,11 +54,10 @@
#define NFS_VER4 4
#define NFS_V2MAXDATA 8192
#define NFS_MAXDGRAMDATA 16384
-#define NFS_MAXDATA NFS_MAXBSIZE
#define NFS_MAXPATHLEN 1024
#define NFS_MAXNAMLEN 255
#define NFS_MAXPKTHDR 404
-#define NFS_MAXPACKET (NFS_MAXDATA + 2048)
+#define NFS_MAXPACKET (NFS_SRVMAXIO + 2048)
#define NFS_MINPACKET 20
#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */
#define NFSV4_MINORVERSION 0 /* V4 Minor version */
@@ -67,6 +66,18 @@
#define NFSV41_CBVERS 4 /* V4.1 CB Version */
#define NFSV4_SMALLSTR 50 /* Strings small enough for stack */
+/*
+ * This value isn't a fixed value in the RFCs.
+ * It is the maximum data size supported by NFSv3 or NFSv4 over TCP for
+ * the server. It should be set to the I/O size preferred by ZFS or
+ * MAXBSIZE, whichever is greater.
+ * ZFS currently prefers 128K.
+ * It used to be called NFS_MAXDATA, but has been renamed to clarify that
+ * it refers to server side only and doesn't conflict with the NFS_MAXDATA
+ * defined in rpcsvc/nfs_prot.h for userland.
+ */
+#define NFS_SRVMAXIO (128 * 1024)
+
/* Stat numbers for rpc returns (version 2, 3 and 4) */
/*
* These numbers are hard-wired in the RFCs, so they can't be changed.
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index e1bfa29..7968353 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -537,8 +537,10 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
(void) nfs_catnap(PZERO, ret, "nfs_open2");
} while (ret == NFSERR_DELAY);
if (ret) {
- if (ndp != NULL)
+ if (ndp != NULL) {
FREE((caddr_t)ndp, M_NFSCLDELEG);
+ ndp = NULL;
+ }
if (ret == NFSERR_STALECLIENTID ||
ret == NFSERR_STALEDONTRECOVER ||
ret == NFSERR_BADSESSION)
@@ -2153,8 +2155,10 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
(void) nfs_catnap(PZERO, ret, "nfs_crt2");
} while (ret == NFSERR_DELAY);
if (ret) {
- if (dp != NULL)
+ if (dp != NULL) {
FREE((caddr_t)dp, M_NFSCLDELEG);
+ dp = NULL;
+ }
if (ret == NFSERR_STALECLIENTID ||
ret == NFSERR_STALEDONTRECOVER ||
ret == NFSERR_BADSESSION)
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c
index 9758b4c..73c6eb6 100644
--- a/sys/fs/nfsclient/nfs_clvfsops.c
+++ b/sys/fs/nfsclient/nfs_clvfsops.c
@@ -86,8 +86,8 @@ extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
extern struct mtx ncl_iod_mutex;
NFSCLSTATEMUTEX;
-MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header");
-MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct");
+MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "NFS request header");
+MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "NFS mount struct");
SYSCTL_DECL(_vfs_nfs);
static int nfs_ip_paranoia = 1;
@@ -201,16 +201,16 @@ newnfs_iosize(struct nfsmount *nmp)
}
if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
nmp->nm_rsize = maxio;
- if (nmp->nm_rsize > MAXBSIZE)
- nmp->nm_rsize = MAXBSIZE;
+ if (nmp->nm_rsize > NFS_MAXBSIZE)
+ nmp->nm_rsize = NFS_MAXBSIZE;
if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
nmp->nm_readdirsize = maxio;
if (nmp->nm_readdirsize > nmp->nm_rsize)
nmp->nm_readdirsize = nmp->nm_rsize;
if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
nmp->nm_wsize = maxio;
- if (nmp->nm_wsize > MAXBSIZE)
- nmp->nm_wsize = MAXBSIZE;
+ if (nmp->nm_wsize > NFS_MAXBSIZE)
+ nmp->nm_wsize = NFS_MAXBSIZE;
/*
* Calculate the size used for io buffers. Use the larger
@@ -1198,7 +1198,8 @@ nfs_mount(struct mount *mp)
out:
if (!error) {
MNT_ILOCK(mp);
- mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF;
+ mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
+ MNTK_USES_BCACHE;
MNT_IUNLOCK(mp);
}
return (error);
@@ -1323,10 +1324,13 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
nmp->nm_timeo = NFS_TIMEO;
nmp->nm_retry = NFS_RETRANS;
nmp->nm_readahead = NFS_DEFRAHEAD;
- if (desiredvnodes >= 11000)
- nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
- else
- nmp->nm_wcommitsize = hibufspace / 10;
+
+ /* This is empirical approximation of sqrt(hibufspace) * 256. */
+ nmp->nm_wcommitsize = NFS_MAXBSIZE / 256;
+ while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace)
+ nmp->nm_wcommitsize *= 2;
+ nmp->nm_wcommitsize *= 256;
+
if ((argp->flags & NFSMNT_NFSV4) != 0)
nmp->nm_minorvers = minvers;
else
diff --git a/sys/fs/nfsserver/nfs_nfsdkrpc.c b/sys/fs/nfsserver/nfs_nfsdkrpc.c
index 4fb9c93..f9b8eb8 100644
--- a/sys/fs/nfsserver/nfs_nfsdkrpc.c
+++ b/sys/fs/nfsserver/nfs_nfsdkrpc.c
@@ -117,7 +117,8 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
memset(&nd, 0, sizeof(nd));
if (rqst->rq_vers == NFS_VER2) {
- if (rqst->rq_proc > NFSV2PROC_STATFS) {
+ if (rqst->rq_proc > NFSV2PROC_STATFS ||
+ newnfs_nfsv3_procid[rqst->rq_proc] == NFSPROC_NOOP) {
svcerr_noproc(rqst);
svc_freereq(rqst);
goto out;
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 0ea48cd..94475d9 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -84,7 +84,7 @@ extern int nfsrv_issuedelegs;
extern int nfsrv_dolocallocks;
extern int nfsd_enable_stringtouid;
-SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW, 0, "New NFS server");
+SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW, 0, "NFS server");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, mirrormnt, CTLFLAG_RW,
&nfsrv_enable_crossmntpt, 0, "Enable nfsd to cross mount points");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks,
@@ -96,7 +96,7 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW,
SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW,
&nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel,
- 0, "Debug level for new nfs server");
+ 0, "Debug level for NFS server");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW,
&nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names");
@@ -1270,8 +1270,11 @@ nfsvno_fsync(struct vnode *vp, u_int64_t off, int cnt, struct ucred *cred,
* file is done. At this time VOP_FSYNC does not accept offset and
* byte count parameters so call VOP_FSYNC the whole file for now.
* The same is true for NFSv4: RFC 3530 Sec. 14.2.3.
+ * File systems that do not use the buffer cache (as indicated
+ * by MNTK_USES_BCACHE not being set) must use VOP_FSYNC().
*/
- if (cnt == 0 || cnt > MAX_COMMIT_COUNT) {
+ if (cnt == 0 || cnt > MAX_COMMIT_COUNT ||
+ (vp->v_mount->mnt_kern_flag & MNTK_USES_BCACHE) == 0) {
/*
* Give up and do the whole thing
*/
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index e6e02d7..bd0c2da 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -881,7 +881,7 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
i = mbuf_len(mp);
}
- if (retlen > NFS_MAXDATA || retlen < 0)
+ if (retlen > NFS_SRVMAXIO || retlen < 0)
nd->nd_repstat = EIO;
if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
if (nd->nd_flag & ND_NFSV3)
diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c
index fd3d385..618090b 100644
--- a/sys/fs/nullfs/null_vfsops.c
+++ b/sys/fs/nullfs/null_vfsops.c
@@ -199,7 +199,7 @@ nullfs_mount(struct mount *mp)
}
mp->mnt_kern_flag |= MNTK_LOOKUP_EXCL_DOTDOT;
mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag &
- MNTK_SUSPENDABLE;
+ (MNTK_SUSPENDABLE | MNTK_USES_BCACHE);
MNT_IUNLOCK(mp);
mp->mnt_data = xmp;
vfs_getnewfsid(mp);
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 885f84c..9bdb1e9 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -342,7 +342,7 @@ tmpfs_getattr(struct vop_getattr_args *v)
{
struct vnode *vp = v->a_vp;
struct vattr *vap = v->a_vap;
-
+ vm_object_t obj;
struct tmpfs_node *node;
node = VP_TO_TMPFS_NODE(vp);
@@ -366,7 +366,11 @@ tmpfs_getattr(struct vop_getattr_args *v)
vap->va_flags = node->tn_flags;
vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
node->tn_rdev : NODEV;
- vap->va_bytes = round_page(node->tn_size);
+ if (vp->v_type == VREG) {
+ obj = node->tn_reg.tn_aobj;
+ vap->va_bytes = (u_quad_t)obj->resident_page_count * PAGE_SIZE;
+ } else
+ vap->va_bytes = node->tn_size;
vap->va_filerev = 0;
return 0;
diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c
index decbbe0..2539e1b 100644
--- a/sys/geom/geom_dev.c
+++ b/sys/geom/geom_dev.c
@@ -572,7 +572,7 @@ g_dev_done(struct bio *bp2)
}
mtx_unlock(&sc->sc_mtx);
if (destroy)
- g_post_event(g_dev_destroy, cp, M_WAITOK, NULL);
+ g_post_event(g_dev_destroy, cp, M_NOWAIT, NULL);
biodone(bp);
}
diff --git a/sys/geom/multipath/g_multipath.c b/sys/geom/multipath/g_multipath.c
index 7593cca..0953d18 100644
--- a/sys/geom/multipath/g_multipath.c
+++ b/sys/geom/multipath/g_multipath.c
@@ -369,9 +369,9 @@ g_multipath_done(struct bio *bp)
mtx_lock(&sc->sc_mtx);
(*cnt)--;
if (*cnt == 0 && (cp->index & MP_LOST)) {
- cp->index |= MP_POSTED;
+ if (g_post_event(g_mpd, cp, M_NOWAIT, NULL) == 0)
+ cp->index |= MP_POSTED;
mtx_unlock(&sc->sc_mtx);
- g_post_event(g_mpd, cp, M_WAITOK, NULL);
} else
mtx_unlock(&sc->sc_mtx);
g_std_done(bp);
diff --git a/sys/geom/uncompress/g_uncompress.c b/sys/geom/uncompress/g_uncompress.c
index 5bc8d30..8c2d5cb 100644
--- a/sys/geom/uncompress/g_uncompress.c
+++ b/sys/geom/uncompress/g_uncompress.c
@@ -45,10 +45,10 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/malloc.h>
#include <sys/systm.h>
+#include <sys/zlib.h>
#include <geom/geom.h>
-#include <net/zlib.h>
#include <contrib/xz-embedded/linux/include/linux/xz.h>
#ifdef GEOM_UNCOMPRESS_DEBUG
@@ -571,6 +571,7 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags)
(buf+sizeof(struct cloop_header)))[i]);
}
free(buf, M_GEOM);
+ buf = NULL;
DPRINTF(("%s: done reading offsets\n", gp->name));
mtx_init(&sc->last_mtx, "geom_uncompress cache", NULL, MTX_DEF);
sc->last_blk = -1;
diff --git a/sys/geom/uzip/g_uzip.c b/sys/geom/uzip/g_uzip.c
index c2ed64b..732de9d 100644
--- a/sys/geom/uzip/g_uzip.c
+++ b/sys/geom/uzip/g_uzip.c
@@ -38,9 +38,9 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <sys/zlib.h>
#include <geom/geom.h>
-#include <net/zlib.h>
FEATURE(geom_uzip, "GEOM uzip read-only compressed disks support");
diff --git a/sys/gnu/dts/arm/meson.dtsi b/sys/gnu/dts/arm/meson.dtsi
index b67ede5..5260cb0 100644
--- a/sys/gnu/dts/arm/meson.dtsi
+++ b/sys/gnu/dts/arm/meson.dtsi
@@ -67,7 +67,7 @@
timer@c1109940 {
compatible = "amlogic,meson6-timer";
- reg = <0xc1109940 0x14>;
+ reg = <0xc1109940 0x18>;
interrupts = <0 10 1>;
};
@@ -80,36 +80,37 @@
wdt: watchdog@c1109900 {
compatible = "amlogic,meson6-wdt";
reg = <0xc1109900 0x8>;
+ interrupts = <0 0 1>;
};
uart_AO: serial@c81004c0 {
compatible = "amlogic,meson-uart";
- reg = <0xc81004c0 0x14>;
+ reg = <0xc81004c0 0x18>;
interrupts = <0 90 1>;
clocks = <&clk81>;
status = "disabled";
};
- uart_A: serial@c81084c0 {
+ uart_A: serial@c11084c0 {
compatible = "amlogic,meson-uart";
- reg = <0xc81084c0 0x14>;
- interrupts = <0 90 1>;
+ reg = <0xc11084c0 0x18>;
+ interrupts = <0 26 1>;
clocks = <&clk81>;
status = "disabled";
};
- uart_B: serial@c81084dc {
+ uart_B: serial@c11084dc {
compatible = "amlogic,meson-uart";
- reg = <0xc81084dc 0x14>;
- interrupts = <0 90 1>;
+ reg = <0xc11084dc 0x18>;
+ interrupts = <0 75 1>;
clocks = <&clk81>;
status = "disabled";
};
- uart_C: serial@c8108700 {
+ uart_C: serial@c1108700 {
compatible = "amlogic,meson-uart";
- reg = <0xc8108700 0x14>;
- interrupts = <0 90 1>;
+ reg = <0xc1108700 0x18>;
+ interrupts = <0 93 1>;
clocks = <&clk81>;
status = "disabled";
};
diff --git a/sys/gnu/dts/arm/meson6.dtsi b/sys/gnu/dts/arm/meson6.dtsi
index 8b33be1..7bfbb35 100644
--- a/sys/gnu/dts/arm/meson6.dtsi
+++ b/sys/gnu/dts/arm/meson6.dtsi
@@ -78,3 +78,7 @@
clock-frequency = <200000000>;
};
}; /* end of / */
+
+&L2 {
+ interrupts = <0 61 1>;
+};
diff --git a/sys/gnu/dts/arm/meson8.dtsi b/sys/gnu/dts/arm/meson8.dtsi
index 1f442a7..819a979 100644
--- a/sys/gnu/dts/arm/meson8.dtsi
+++ b/sys/gnu/dts/arm/meson8.dtsi
@@ -90,3 +90,7 @@
clock-frequency = <141666666>;
};
}; /* end of / */
+
+&L2 {
+ interrupts = <0 143 1>;
+};
diff --git a/sys/i386/conf/DEFAULTS b/sys/i386/conf/DEFAULTS
index 78d807c..d5bdb1d 100644
--- a/sys/i386/conf/DEFAULTS
+++ b/sys/i386/conf/DEFAULTS
@@ -26,7 +26,6 @@ options GEOM_PART_EBR_COMPAT
options GEOM_PART_MBR
# enable support for native hardware
-options NATIVE
device atpic
options NEW_PCIB
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index 086844a..b1740f3 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -358,7 +358,9 @@ device virtio_blk # VirtIO Block device
device virtio_scsi # VirtIO SCSI device
device virtio_balloon # VirtIO Memory Balloon device
-# HyperV drivers
+# HyperV drivers and enchancement support
+# NOTE: HYPERV depends on hyperv. They must be added or removed together.
+options HYPERV # Hyper-V kernel infrastructure
device hyperv # HyperV drivers
# Xen HVM Guest Optimizations
diff --git a/sys/i386/conf/XEN b/sys/i386/conf/XEN
deleted file mode 100644
index dd83670..0000000
--- a/sys/i386/conf/XEN
+++ /dev/null
@@ -1,96 +0,0 @@
-#
-# XEN -- Kernel configuration for i386 XEN DomU
-#
-# $FreeBSD$
-
-cpu I686_CPU
-ident XEN
-
-makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
-
-# The following drivers don't build with PAE or XEN enabled.
-makeoptions WITHOUT_MODULES="ctl dpt drm drm2 hptmv ida"
-
-# The following drivers don't work with PAE enabled.
-makeoptions WITHOUT_MODULES+="ncr pst"
-
-options SCHED_ULE # ULE scheduler
-options PREEMPTION # Enable kernel thread preemption
-
-options INET # InterNETworking
-options INET6 # IPv6 communications protocols
-options SCTP # Stream Control Transmission Protocol
-options FFS # Berkeley Fast Filesystem
-options SOFTUPDATES # Enable FFS soft updates support
-options UFS_ACL # Support for access control lists
-options UFS_DIRHASH # Improve performance on big directories
-options UFS_GJOURNAL # Enable gjournal-based UFS journaling
-options NFSCL # Network Filesystem Client
-options NFSD # Network Filesystem Server
-options NFSLOCKD # Network Lock Manager
-options NFS_ROOT # NFS usable as /, requires NFSCL
-options MSDOSFS # MSDOS Filesystem
-options CD9660 # ISO 9660 Filesystem
-options PROCFS # Process filesystem (requires PSEUDOFS)
-options PSEUDOFS # Pseudo-filesystem framework
-options GEOM_PART_GPT # GUID Partition Tables.
-options GEOM_LABEL # Provides labelization
-options COMPAT_FREEBSD4 # Compatible with FreeBSD4
-options COMPAT_FREEBSD5 # Compatible with FreeBSD5
-options COMPAT_FREEBSD6 # Compatible with FreeBSD6
-options COMPAT_FREEBSD7 # Compatible with FreeBSD7
-options COMPAT_FREEBSD9 # Compatible with FreeBSD9
-options COMPAT_FREEBSD10 # Compatible with FreeBSD10
-options KTRACE # ktrace(1) support
-options STACK # stack(9) support
-options SYSVSHM # SYSV-style shared memory
-options SYSVMSG # SYSV-style message queues
-options SYSVSEM # SYSV-style semaphores
-options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
-options KBD_INSTALL_CDEV # install a CDEV entry in /dev
-options AUDIT # Security event auditing
-
-# Debugging for use in -current
-options KDB # Enable kernel debugger support.
-options DDB # Support DDB.
-options GDB # Support remote GDB.
-options DEADLKRES # Enable the deadlock resolver
-options INVARIANTS # Enable calls of extra sanity checking
-options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
-options WITNESS # Enable checks to detect deadlocks and cycles
-options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
-
-options PAE
-nooption NATIVE
-option XEN
-nodevice atpic
-nodevice isa
-options MCLSHIFT=12
-
-# To make an SMP kernel, the next two lines are needed
-options SMP # Symmetric MultiProcessor Kernel
-device apic # I/O APIC
-
-#device atkbdc # AT keyboard controller
-#device atkbd # AT keyboard
-device psm # PS/2 mouse
-device pci
-
-#device kbdmux # keyboard multiplexer
-
-# Pseudo devices.
-device loop # Network loopback
-device random # Entropy device
-device ether # Ethernet support
-device tun # Packet tunnel.
-device md # Memory "disks"
-device gif # IPv6 and IPv4 tunneling
-
-# Wireless cards
-options IEEE80211_SUPPORT_MESH
-options AH_SUPPORT_AR5416
-
-# The `bpf' device enables the Berkeley Packet Filter.
-# Be aware of the administrative consequences of enabling this!
-# Note that 'bpf' is required for DHCP.
-device bpf # Berkeley packet filter
diff --git a/sys/i386/i386/apic_vector.s b/sys/i386/i386/apic_vector.s
index 7cae220..18b3c5d 100644
--- a/sys/i386/i386/apic_vector.s
+++ b/sys/i386/i386/apic_vector.s
@@ -181,6 +181,25 @@ IDTVEC(xen_intr_upcall)
jmp doreti
#endif
+#ifdef HYPERV
+/*
+ * This is the Hyper-V vmbus channel direct callback interrupt.
+ * Only used when it is running on Hyper-V.
+ */
+ .text
+ SUPERALIGN_TEXT
+IDTVEC(hv_vmbus_callback)
+ PUSH_FRAME
+ SET_KERNEL_SREGS
+ cld
+ FAKE_MCOUNT(TF_EIP(%esp))
+ pushl %esp
+ call hv_vector_handler
+ add $4, %esp
+ MEXITCOUNT
+ jmp doreti
+#endif
+
#ifdef SMP
/*
* Global address space TLB shootdown.
@@ -247,7 +266,6 @@ IDTVEC(invlcache)
/*
* Handler for IPIs sent via the per-cpu IPI bitmap.
*/
-#ifndef XEN
.text
SUPERALIGN_TEXT
IDTVEC(ipi_intr_bitmap_handler)
@@ -262,7 +280,7 @@ IDTVEC(ipi_intr_bitmap_handler)
call ipi_bitmap_handler
MEXITCOUNT
jmp doreti
-#endif
+
/*
* Executed by a CPU when it receives an IPI_STOP from another CPU.
*/
@@ -282,7 +300,6 @@ IDTVEC(cpustop)
/*
* Executed by a CPU when it receives an IPI_SUSPEND from another CPU.
*/
-#ifndef XEN
.text
SUPERALIGN_TEXT
IDTVEC(cpususpend)
@@ -295,7 +312,6 @@ IDTVEC(cpususpend)
POP_FRAME
jmp doreti_iret
-#endif
/*
* Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU.
@@ -320,19 +336,4 @@ IDTVEC(rendezvous)
POP_FRAME
iret
-/*
- * Clean up when we lose out on the lazy context switch optimization.
- * ie: when we are about to release a PTD but a cpu is still borrowing it.
- */
- SUPERALIGN_TEXT
-IDTVEC(lazypmap)
- PUSH_FRAME
- SET_KERNEL_SREGS
- cld
-
- call pmap_lazyfix_action
-
- call as_lapic_eoi
- POP_FRAME
- iret
#endif /* SMP */
diff --git a/sys/i386/i386/bios.c b/sys/i386/i386/bios.c
index 1bce11c..6502749 100644
--- a/sys/i386/i386/bios.c
+++ b/sys/i386/i386/bios.c
@@ -389,7 +389,7 @@ bios16(struct bios_args *args, char *fmt, ...)
args->seg.code32.limit = 0xffff;
ptd = (pd_entry_t *)rcr3();
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if (ptd == IdlePDPT)
#else
if (ptd == IdlePTD)
diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c
index 822cc56..f797656 100644
--- a/sys/i386/i386/db_trace.c
+++ b/sys/i386/i386/db_trace.c
@@ -316,8 +316,7 @@ db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
frame_type = TRAP_TIMERINT;
else if (strcmp(name, "Xcpustop") == 0 ||
strcmp(name, "Xrendezvous") == 0 ||
- strcmp(name, "Xipi_intr_bitmap_handler") == 0 ||
- strcmp(name, "Xlazypmap") == 0)
+ strcmp(name, "Xipi_intr_bitmap_handler") == 0)
frame_type = TRAP_INTERRUPT;
}
diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c
index 97e2e97..7a00740 100644
--- a/sys/i386/i386/genassym.c
+++ b/sys/i386/i386/genassym.c
@@ -238,11 +238,6 @@ ASSYM(BUS_SPACE_HANDLE_BASE, offsetof(struct bus_space_handle, bsh_base));
ASSYM(BUS_SPACE_HANDLE_IAT, offsetof(struct bus_space_handle, bsh_iat));
#endif
-#ifdef XEN
-ASSYM(PC_CR3, offsetof(struct pcpu, pc_cr3));
-ASSYM(XEN_HYPERVISOR_VIRT_START, HYPERVISOR_VIRT_START);
-#endif
-
#ifdef HWPMC_HOOKS
ASSYM(PMC_FN_USER_CALLCHAIN, PMC_FN_USER_CALLCHAIN);
#endif
diff --git a/sys/i386/i386/initcpu.c b/sys/i386/i386/initcpu.c
index 291f3fc..9d8c265 100644
--- a/sys/i386/i386/initcpu.c
+++ b/sys/i386/i386/initcpu.c
@@ -784,7 +784,7 @@ initializecpu(void)
init_transmeta();
break;
}
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((amd_feature & AMDID_NX) != 0) {
uint64_t msr;
diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s
index 34acbf6..5bf7944 100644
--- a/sys/i386/i386/locore.s
+++ b/sys/i386/i386/locore.s
@@ -99,7 +99,7 @@ physfree: .long 0 /* phys addr of next free page */
.globl IdlePTD
IdlePTD: .long 0 /* phys addr of kernel PTD */
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
.globl IdlePDPT
IdlePDPT: .long 0 /* phys addr of kernel PDPT */
#endif
@@ -281,7 +281,7 @@ NON_GPROF_ENTRY(btext)
1:
/* Now enable paging */
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
movl R(IdlePDPT), %eax
movl %eax, %cr3
movl %cr4, %eax
@@ -722,7 +722,7 @@ no_kernend:
movl %esi,R(KPTmap)
/* Allocate Page Table Directory */
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
/* XXX only need 32 bytes (easier for now) */
ALLOCPAGES(1)
movl %esi,R(IdlePDPT)
@@ -788,7 +788,7 @@ no_kernend:
fillkptphys($PG_RW)
/* Map page directory. */
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
movl R(IdlePDPT), %eax
movl $1, %ecx
fillkptphys($PG_RW)
@@ -890,7 +890,7 @@ done_pde:
movl $NPGPTD,%ecx
fillkpt(R(IdlePTD), $PG_RW)
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
movl R(IdlePTD), %eax
xorl %ebx, %ebx
movl $NPGPTD, %ecx
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 33d22de..a5867c4 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -160,24 +160,6 @@ int arch_i386_is_xbox = 0;
uint32_t arch_i386_xbox_memsize = 0;
#endif
-#ifdef XEN
-/* XEN includes */
-#include <xen/xen-os.h>
-#include <xen/hypervisor.h>
-#include <machine/xen/xenvar.h>
-#include <machine/xen/xenfunc.h>
-#include <xen/xen_intr.h>
-
-void Xhypervisor_callback(void);
-void failsafe_callback(void);
-
-extern trap_info_t trap_table[];
-struct proc_ldt default_proc_ldt;
-extern int init_first;
-int running_xen = 1;
-extern unsigned long physfree;
-#endif /* XEN */
-
/* Sanity check for __curthread() */
CTASSERT(offsetof(struct pcpu, pc_curthread) == 0);
@@ -356,9 +338,7 @@ cpu_startup(dummy)
*/
bufinit();
vm_pager_bufferinit();
-#ifndef XEN
cpu_setregs();
-#endif
}
/*
@@ -1176,436 +1156,6 @@ sys_sigreturn(td, uap)
}
/*
- * Machine dependent boot() routine
- *
- * I haven't seen anything to put here yet
- * Possibly some stuff might be grafted back here from boot()
- */
-void
-cpu_boot(int howto)
-{
-}
-
-/*
- * Flush the D-cache for non-DMA I/O so that the I-cache can
- * be made coherent later.
- */
-void
-cpu_flush_dcache(void *ptr, size_t len)
-{
- /* Not applicable */
-}
-
-/* Get current clock frequency for the given cpu id. */
-int
-cpu_est_clockrate(int cpu_id, uint64_t *rate)
-{
- uint64_t tsc1, tsc2;
- uint64_t acnt, mcnt, perf;
- register_t reg;
-
- if (pcpu_find(cpu_id) == NULL || rate == NULL)
- return (EINVAL);
- if ((cpu_feature & CPUID_TSC) == 0)
- return (EOPNOTSUPP);
-
- /*
- * If TSC is P-state invariant and APERF/MPERF MSRs do not exist,
- * DELAY(9) based logic fails.
- */
- if (tsc_is_invariant && !tsc_perf_stat)
- return (EOPNOTSUPP);
-
-#ifdef SMP
- if (smp_cpus > 1) {
- /* Schedule ourselves on the indicated cpu. */
- thread_lock(curthread);
- sched_bind(curthread, cpu_id);
- thread_unlock(curthread);
- }
-#endif
-
- /* Calibrate by measuring a short delay. */
- reg = intr_disable();
- if (tsc_is_invariant) {
- wrmsr(MSR_MPERF, 0);
- wrmsr(MSR_APERF, 0);
- tsc1 = rdtsc();
- DELAY(1000);
- mcnt = rdmsr(MSR_MPERF);
- acnt = rdmsr(MSR_APERF);
- tsc2 = rdtsc();
- intr_restore(reg);
- perf = 1000 * acnt / mcnt;
- *rate = (tsc2 - tsc1) * perf;
- } else {
- tsc1 = rdtsc();
- DELAY(1000);
- tsc2 = rdtsc();
- intr_restore(reg);
- *rate = (tsc2 - tsc1) * 1000;
- }
-
-#ifdef SMP
- if (smp_cpus > 1) {
- thread_lock(curthread);
- sched_unbind(curthread);
- thread_unlock(curthread);
- }
-#endif
-
- return (0);
-}
-
-#ifdef XEN
-
-static void
-idle_block(void)
-{
-
- HYPERVISOR_sched_op(SCHEDOP_block, 0);
-}
-
-void
-cpu_halt(void)
-{
- HYPERVISOR_shutdown(SHUTDOWN_poweroff);
-}
-
-int scheduler_running;
-
-static void
-cpu_idle_hlt(sbintime_t sbt)
-{
-
- scheduler_running = 1;
- enable_intr();
- idle_block();
-}
-
-#else
-/*
- * Shutdown the CPU as much as possible
- */
-void
-cpu_halt(void)
-{
- for (;;)
- halt();
-}
-
-#endif
-
-void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */
-static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */
-static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */
-SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RWTUN, &idle_mwait,
- 0, "Use MONITOR/MWAIT for short idle");
-
-#define STATE_RUNNING 0x0
-#define STATE_MWAIT 0x1
-#define STATE_SLEEPING 0x2
-
-#ifndef PC98
-static void
-cpu_idle_acpi(sbintime_t sbt)
-{
- int *state;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_SLEEPING;
-
- /* See comments in cpu_idle_hlt(). */
- disable_intr();
- if (sched_runnable())
- enable_intr();
- else if (cpu_idle_hook)
- cpu_idle_hook(sbt);
- else
- __asm __volatile("sti; hlt");
- *state = STATE_RUNNING;
-}
-#endif /* !PC98 */
-
-#ifndef XEN
-static void
-cpu_idle_hlt(sbintime_t sbt)
-{
- int *state;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_SLEEPING;
-
- /*
- * Since we may be in a critical section from cpu_idle(), if
- * an interrupt fires during that critical section we may have
- * a pending preemption. If the CPU halts, then that thread
- * may not execute until a later interrupt awakens the CPU.
- * To handle this race, check for a runnable thread after
- * disabling interrupts and immediately return if one is
- * found. Also, we must absolutely guarentee that hlt is
- * the next instruction after sti. This ensures that any
- * interrupt that fires after the call to disable_intr() will
- * immediately awaken the CPU from hlt. Finally, please note
- * that on x86 this works fine because of interrupts enabled only
- * after the instruction following sti takes place, while IF is set
- * to 1 immediately, allowing hlt instruction to acknowledge the
- * interrupt.
- */
- disable_intr();
- if (sched_runnable())
- enable_intr();
- else
- __asm __volatile("sti; hlt");
- *state = STATE_RUNNING;
-}
-#endif
-
-/*
- * MWAIT cpu power states. Lower 4 bits are sub-states.
- */
-#define MWAIT_C0 0xf0
-#define MWAIT_C1 0x00
-#define MWAIT_C2 0x10
-#define MWAIT_C3 0x20
-#define MWAIT_C4 0x30
-
-static void
-cpu_idle_mwait(sbintime_t sbt)
-{
- int *state;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_MWAIT;
-
- /* See comments in cpu_idle_hlt(). */
- disable_intr();
- if (sched_runnable()) {
- enable_intr();
- *state = STATE_RUNNING;
- return;
- }
- cpu_monitor(state, 0, 0);
- if (*state == STATE_MWAIT)
- __asm __volatile("sti; mwait" : : "a" (MWAIT_C1), "c" (0));
- else
- enable_intr();
- *state = STATE_RUNNING;
-}
-
-static void
-cpu_idle_spin(sbintime_t sbt)
-{
- int *state;
- int i;
-
- state = (int *)PCPU_PTR(monitorbuf);
- *state = STATE_RUNNING;
-
- /*
- * The sched_runnable() call is racy but as long as there is
- * a loop missing it one time will have just a little impact if any
- * (and it is much better than missing the check at all).
- */
- for (i = 0; i < 1000; i++) {
- if (sched_runnable())
- return;
- cpu_spinwait();
- }
-}
-
-/*
- * C1E renders the local APIC timer dead, so we disable it by
- * reading the Interrupt Pending Message register and clearing
- * both C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
- *
- * Reference:
- * "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors"
- * #32559 revision 3.00+
- */
-#define MSR_AMDK8_IPM 0xc0010055
-#define AMDK8_SMIONCMPHALT (1ULL << 27)
-#define AMDK8_C1EONCMPHALT (1ULL << 28)
-#define AMDK8_CMPHALT (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT)
-
-static void
-cpu_probe_amdc1e(void)
-{
-
- /*
- * Detect the presence of C1E capability mostly on latest
- * dual-cores (or future) k8 family.
- */
- if (cpu_vendor_id == CPU_VENDOR_AMD &&
- (cpu_id & 0x00000f00) == 0x00000f00 &&
- (cpu_id & 0x0fff0000) >= 0x00040000) {
- cpu_ident_amdc1e = 1;
- }
-}
-
-#if defined(PC98) || defined(XEN)
-void (*cpu_idle_fn)(sbintime_t) = cpu_idle_hlt;
-#else
-void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi;
-#endif
-
-void
-cpu_idle(int busy)
-{
-#ifndef XEN
- uint64_t msr;
-#endif
- sbintime_t sbt = -1;
-
- CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
- busy, curcpu);
-#if defined(MP_WATCHDOG) && !defined(XEN)
- ap_watchdog(PCPU_GET(cpuid));
-#endif
-#ifndef XEN
- /* If we are busy - try to use fast methods. */
- if (busy) {
- if ((cpu_feature2 & CPUID2_MON) && idle_mwait) {
- cpu_idle_mwait(busy);
- goto out;
- }
- }
-#endif
-
- /* If we have time - switch timers into idle mode. */
- if (!busy) {
- critical_enter();
- sbt = cpu_idleclock();
- }
-
-#ifndef XEN
- /* Apply AMD APIC timer C1E workaround. */
- if (cpu_ident_amdc1e && cpu_disable_c3_sleep) {
- msr = rdmsr(MSR_AMDK8_IPM);
- if (msr & AMDK8_CMPHALT)
- wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT);
- }
-#endif
-
- /* Call main idle method. */
- cpu_idle_fn(sbt);
-
- /* Switch timers back into active mode. */
- if (!busy) {
- cpu_activeclock();
- critical_exit();
- }
-#ifndef XEN
-out:
-#endif
- CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
- busy, curcpu);
-}
-
-int
-cpu_idle_wakeup(int cpu)
-{
- struct pcpu *pcpu;
- int *state;
-
- pcpu = pcpu_find(cpu);
- state = (int *)pcpu->pc_monitorbuf;
- /*
- * This doesn't need to be atomic since missing the race will
- * simply result in unnecessary IPIs.
- */
- if (*state == STATE_SLEEPING)
- return (0);
- if (*state == STATE_MWAIT)
- *state = STATE_RUNNING;
- return (1);
-}
-
-/*
- * Ordered by speed/power consumption.
- */
-struct {
- void *id_fn;
- char *id_name;
-} idle_tbl[] = {
- { cpu_idle_spin, "spin" },
- { cpu_idle_mwait, "mwait" },
- { cpu_idle_hlt, "hlt" },
-#ifndef PC98
- { cpu_idle_acpi, "acpi" },
-#endif
- { NULL, NULL }
-};
-
-static int
-idle_sysctl_available(SYSCTL_HANDLER_ARGS)
-{
- char *avail, *p;
- int error;
- int i;
-
- avail = malloc(256, M_TEMP, M_WAITOK);
- p = avail;
- for (i = 0; idle_tbl[i].id_name != NULL; i++) {
- if (strstr(idle_tbl[i].id_name, "mwait") &&
- (cpu_feature2 & CPUID2_MON) == 0)
- continue;
-#ifndef PC98
- if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
- cpu_idle_hook == NULL)
- continue;
-#endif
- p += sprintf(p, "%s%s", p != avail ? ", " : "",
- idle_tbl[i].id_name);
- }
- error = sysctl_handle_string(oidp, avail, 0, req);
- free(avail, M_TEMP);
- return (error);
-}
-
-SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD,
- 0, 0, idle_sysctl_available, "A", "list of available idle functions");
-
-static int
-idle_sysctl(SYSCTL_HANDLER_ARGS)
-{
- char buf[16];
- int error;
- char *p;
- int i;
-
- p = "unknown";
- for (i = 0; idle_tbl[i].id_name != NULL; i++) {
- if (idle_tbl[i].id_fn == cpu_idle_fn) {
- p = idle_tbl[i].id_name;
- break;
- }
- }
- strncpy(buf, p, sizeof(buf));
- error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
- if (error != 0 || req->newptr == NULL)
- return (error);
- for (i = 0; idle_tbl[i].id_name != NULL; i++) {
- if (strstr(idle_tbl[i].id_name, "mwait") &&
- (cpu_feature2 & CPUID2_MON) == 0)
- continue;
-#ifndef PC98
- if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
- cpu_idle_hook == NULL)
- continue;
-#endif
- if (strcmp(idle_tbl[i].id_name, buf))
- continue;
- cpu_idle_fn = idle_tbl[i].id_fn;
- return (0);
- }
- return (EINVAL);
-}
-
-SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
- idle_sysctl, "A", "currently selected idle function");
-
-/*
* Reset registers to default values on exec.
*/
void
@@ -1721,13 +1271,8 @@ SYSCTL_STRING(_machdep, OID_AUTO, bootmethod, CTLFLAG_RD, bootmethod, 0,
int _default_ldt;
-#ifdef XEN
-union descriptor *gdt;
-union descriptor *ldt;
-#else
union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */
union descriptor ldt[NLDT]; /* local descriptor table */
-#endif
static struct gate_descriptor idt0[NIDT];
struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */
struct region_descriptor r_gdt, r_idt; /* table descriptors */
@@ -1827,7 +1372,6 @@ struct soft_segment_descriptor gdt_segs[] = {
.ssd_xx = 0, .ssd_xx1 = 0,
.ssd_def32 = 1,
.ssd_gran = 1 },
-#ifndef XEN
/* GPROC0_SEL 9 Proc 0 Tss Descriptor */
{
.ssd_base = 0x0,
@@ -1919,7 +1463,6 @@ struct soft_segment_descriptor gdt_segs[] = {
.ssd_xx = 0, .ssd_xx1 = 0,
.ssd_def32 = 0,
.ssd_gran = 0 },
-#endif /* !XEN */
};
static struct soft_segment_descriptor ldt_segs[] = {
@@ -2071,7 +1614,7 @@ sdtossd(sd, ssd)
ssd->ssd_gran = sd->sd_gran;
}
-#if !defined(PC98) && !defined(XEN)
+#if !defined(PC98)
static int
add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
int *physmap_idxp)
@@ -2178,9 +1721,8 @@ add_smap_entries(struct bios_smap *smapbase, vm_paddr_t *physmap,
if (!add_smap_entry(smap, physmap, physmap_idxp))
break;
}
-#endif /* !PC98 && !XEN */
+#endif /* !PC98 */
-#ifndef XEN
static void
basemem_setup(void)
{
@@ -2228,7 +1770,6 @@ basemem_setup(void)
for (i = basemem / 4; i < 160; i++)
pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
}
-#endif /* !XEN */
/*
* Populate the (physmap) array with base/bound pairs describing the
@@ -2504,8 +2045,6 @@ do_next:
for (off = 0; off < round_page(msgbufsize); off += PAGE_SIZE)
pmap_kenter((vm_offset_t)msgbufp + off, phys_avail[pa_indx] +
off);
-
- PT_UPDATES_FLUSH();
}
#else /* PC98 */
static void
@@ -2516,7 +2055,6 @@ getmemsize(int first)
vm_paddr_t physmap[PHYSMAP_SIZE];
pt_entry_t *pte;
quad_t dcons_addr, dcons_size, physmem_tunable;
-#ifndef XEN
int hasbrokenint12, i, res;
u_int extmem;
struct vm86frame vmf;
@@ -2524,17 +2062,8 @@ getmemsize(int first)
vm_paddr_t pa;
struct bios_smap *smap, *smapbase;
caddr_t kmdp;
-#endif
has_smap = 0;
-#if defined(XEN)
- Maxmem = xen_start_info->nr_pages - init_first;
- physmem = Maxmem;
- basemem = 0;
- physmap[0] = init_first << PAGE_SHIFT;
- physmap[1] = ptoa(Maxmem) - round_page(msgbufsize);
- physmap_idx = 0;
-#else
#ifdef XBOX
if (arch_i386_is_xbox) {
/*
@@ -2677,7 +2206,6 @@ have_smap:
physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024;
physmap_done:
-#endif
/*
* Now, physmap contains a map of physical memory.
*/
@@ -2751,7 +2279,6 @@ physmap_done:
getenv_quad("dcons.size", &dcons_size) == 0)
dcons_addr = 0;
-#ifndef XEN
/*
* physmap is in bytes, so when converting to page boundaries,
* round up the start address and round down the end address.
@@ -2872,13 +2399,6 @@ do_next:
}
*pte = 0;
invltlb();
-#else
- phys_avail[0] = physfree;
- phys_avail[1] = xen_start_info->nr_pages*PAGE_SIZE;
- dump_avail[0] = 0;
- dump_avail[1] = xen_start_info->nr_pages*PAGE_SIZE;
-
-#endif
/*
* XXX
@@ -2902,272 +2422,9 @@ do_next:
for (off = 0; off < round_page(msgbufsize); off += PAGE_SIZE)
pmap_kenter((vm_offset_t)msgbufp + off, phys_avail[pa_indx] +
off);
-
- PT_UPDATES_FLUSH();
}
#endif /* PC98 */
-#ifdef XEN
-#define MTOPSIZE (1<<(14 + PAGE_SHIFT))
-
-register_t
-init386(first)
- int first;
-{
- unsigned long gdtmachpfn;
- int error, gsel_tss, metadata_missing, x, pa;
- struct pcpu *pc;
-#ifdef CPU_ENABLE_SSE
- struct xstate_hdr *xhdr;
-#endif
- struct callback_register event = {
- .type = CALLBACKTYPE_event,
- .address = {GSEL(GCODE_SEL, SEL_KPL), (unsigned long)Xhypervisor_callback },
- };
- struct callback_register failsafe = {
- .type = CALLBACKTYPE_failsafe,
- .address = {GSEL(GCODE_SEL, SEL_KPL), (unsigned long)failsafe_callback },
- };
-
- thread0.td_kstack = proc0kstack;
- thread0.td_kstack_pages = KSTACK_PAGES;
-
- /*
- * This may be done better later if it gets more high level
- * components in it. If so just link td->td_proc here.
- */
- proc_linkup0(&proc0, &thread0);
-
- metadata_missing = 0;
- if (xen_start_info->mod_start) {
- preload_metadata = (caddr_t)xen_start_info->mod_start;
- preload_bootstrap_relocate(KERNBASE);
- } else {
- metadata_missing = 1;
- }
- if (envmode == 1)
- kern_envp = static_env;
- else if ((caddr_t)xen_start_info->cmd_line)
- kern_envp = xen_setbootenv((caddr_t)xen_start_info->cmd_line);
-
- boothowto |= xen_boothowto(kern_envp);
-
- /* Init basic tunables, hz etc */
- init_param1();
-
- /*
- * XEN occupies a portion of the upper virtual address space
- * At its base it manages an array mapping machine page frames
- * to physical page frames - hence we need to be able to
- * access 4GB - (64MB - 4MB + 64k)
- */
- gdt_segs[GPRIV_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
- gdt_segs[GUFS_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
- gdt_segs[GUGS_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
- gdt_segs[GCODE_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
- gdt_segs[GDATA_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
- gdt_segs[GUCODE_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
- gdt_segs[GUDATA_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
- gdt_segs[GBIOSLOWMEM_SEL].ssd_limit = atop(HYPERVISOR_VIRT_START + MTOPSIZE);
-
- pc = &__pcpu[0];
- gdt_segs[GPRIV_SEL].ssd_base = (int) pc;
- gdt_segs[GPROC0_SEL].ssd_base = (int) &pc->pc_common_tss;
-
- PT_SET_MA(gdt, xpmap_ptom(VTOP(gdt)) | PG_V | PG_RW);
- bzero(gdt, PAGE_SIZE);
- for (x = 0; x < NGDT; x++)
- ssdtosd(&gdt_segs[x], &gdt[x].sd);
-
- mtx_init(&dt_lock, "descriptor tables", NULL, MTX_SPIN);
-
- gdtmachpfn = vtomach(gdt) >> PAGE_SHIFT;
- PT_SET_MA(gdt, xpmap_ptom(VTOP(gdt)) | PG_V);
- PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, 512) != 0);
- lgdt(&r_gdt);
- gdtset = 1;
-
- if ((error = HYPERVISOR_set_trap_table(trap_table)) != 0) {
- panic("set_trap_table failed - error %d\n", error);
- }
-
- error = HYPERVISOR_callback_op(CALLBACKOP_register, &event);
- if (error == 0)
- error = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
-#if CONFIG_XEN_COMPAT <= 0x030002
- if (error == -ENOXENSYS)
- HYPERVISOR_set_callbacks(GSEL(GCODE_SEL, SEL_KPL),
- (unsigned long)Xhypervisor_callback,
- GSEL(GCODE_SEL, SEL_KPL), (unsigned long)failsafe_callback);
-#endif
- pcpu_init(pc, 0, sizeof(struct pcpu));
- for (pa = first; pa < first + DPCPU_SIZE; pa += PAGE_SIZE)
- pmap_kenter(pa + KERNBASE, pa);
- dpcpu_init((void *)(first + KERNBASE), 0);
- first += DPCPU_SIZE;
- physfree += DPCPU_SIZE;
- init_first += DPCPU_SIZE / PAGE_SIZE;
-
- PCPU_SET(prvspace, pc);
- PCPU_SET(curthread, &thread0);
-
- /*
- * Initialize mutexes.
- *
- * icu_lock: in order to allow an interrupt to occur in a critical
- * section, to set pcpu->ipending (etc...) properly, we
- * must be able to get the icu lock, so it can't be
- * under witness.
- */
- mutex_init();
- mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS | MTX_NOPROFILE);
-
- /* make ldt memory segments */
- PT_SET_MA(ldt, xpmap_ptom(VTOP(ldt)) | PG_V | PG_RW);
- bzero(ldt, PAGE_SIZE);
- ldt_segs[LUCODE_SEL].ssd_limit = atop(0 - 1);
- ldt_segs[LUDATA_SEL].ssd_limit = atop(0 - 1);
- for (x = 0; x < sizeof ldt_segs / sizeof ldt_segs[0]; x++)
- ssdtosd(&ldt_segs[x], &ldt[x].sd);
-
- default_proc_ldt.ldt_base = (caddr_t)ldt;
- default_proc_ldt.ldt_len = 6;
- _default_ldt = (int)&default_proc_ldt;
- PCPU_SET(currentldt, _default_ldt);
- PT_SET_MA(ldt, *vtopte((unsigned long)ldt) & ~PG_RW);
- xen_set_ldt((unsigned long) ldt, (sizeof ldt_segs / sizeof ldt_segs[0]));
-
-#if defined(XEN_PRIVILEGED)
- /*
- * Initialize the i8254 before the console so that console
- * initialization can use DELAY().
- */
- i8254_init();
-#endif
-
- /*
- * Initialize the console before we print anything out.
- */
- cninit();
-
- if (metadata_missing)
- printf("WARNING: loader(8) metadata is missing!\n");
-
-#ifdef DEV_ISA
-#ifdef DEV_ATPIC
- elcr_probe();
- atpic_startup();
-#else
- /* Reset and mask the atpics and leave them shut down. */
- atpic_reset();
-
- /*
- * Point the ICU spurious interrupt vectors at the APIC spurious
- * interrupt handler.
- */
- setidt(IDT_IO_INTS + 7, IDTVEC(spuriousint), SDT_SYS386IGT, SEL_KPL,
- GSEL(GCODE_SEL, SEL_KPL));
- setidt(IDT_IO_INTS + 15, IDTVEC(spuriousint), SDT_SYS386IGT, SEL_KPL,
- GSEL(GCODE_SEL, SEL_KPL));
-#endif
-#endif
-
-#ifdef DDB
- db_fetch_ksymtab(bootinfo.bi_symtab, bootinfo.bi_esymtab);
-#endif
-
- kdb_init();
-
-#ifdef KDB
- if (boothowto & RB_KDB)
- kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
-#endif
-
- finishidentcpu(); /* Final stage of CPU initialization */
- setidt(IDT_UD, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL,
- GSEL(GCODE_SEL, SEL_KPL));
- setidt(IDT_GP, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL,
- GSEL(GCODE_SEL, SEL_KPL));
- initializecpu(); /* Initialize CPU registers */
- initializecpucache();
-
- /* pointer to selector slot for %fs/%gs */
- PCPU_SET(fsgs_gdt, &gdt[GUFS_SEL].sd);
-
- dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 =
- dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)];
- dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 =
- dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL);
-#ifdef PAE
- dblfault_tss.tss_cr3 = (int)IdlePDPT;
-#else
- dblfault_tss.tss_cr3 = (int)IdlePTD;
-#endif
- dblfault_tss.tss_eip = (int)dblfault_handler;
- dblfault_tss.tss_eflags = PSL_KERNEL;
- dblfault_tss.tss_ds = dblfault_tss.tss_es =
- dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
- dblfault_tss.tss_fs = GSEL(GPRIV_SEL, SEL_KPL);
- dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
- dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
-
- vm86_initialize();
- getmemsize(first);
- init_param2(physmem);
-
- /* now running on new page tables, configured,and u/iom is accessible */
-
- msgbufinit(msgbufp, msgbufsize);
-#ifdef DEV_NPX
- npxinit(true);
-#endif
- /*
- * Set up thread0 pcb after npxinit calculated pcb + fpu save
- * area size. Zero out the extended state header in fpu save
- * area.
- */
- thread0.td_pcb = get_pcb_td(&thread0);
- bzero(get_pcb_user_save_td(&thread0), cpu_max_ext_state_size);
-#ifdef CPU_ENABLE_SSE
- if (use_xsave) {
- xhdr = (struct xstate_hdr *)(get_pcb_user_save_td(&thread0) +
- 1);
- xhdr->xstate_bv = xsave_mask;
- }
-#endif
- PCPU_SET(curpcb, thread0.td_pcb);
- /* make an initial tss so cpu can get interrupt stack on syscall! */
- /* Note: -16 is so we can grow the trapframe if we came from vm86 */
- PCPU_SET(common_tss.tss_esp0, (vm_offset_t)thread0.td_pcb - 16);
- PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL));
- gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
- HYPERVISOR_stack_switch(GSEL(GDATA_SEL, SEL_KPL),
- PCPU_GET(common_tss.tss_esp0));
-
- /* transfer to user mode */
-
- _ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
- _udatasel = GSEL(GUDATA_SEL, SEL_UPL);
-
- /* setup proc 0's pcb */
- thread0.td_pcb->pcb_flags = 0;
-#ifdef PAE
- thread0.td_pcb->pcb_cr3 = (int)IdlePDPT;
-#else
- thread0.td_pcb->pcb_cr3 = (int)IdlePTD;
-#endif
- thread0.td_pcb->pcb_ext = 0;
- thread0.td_frame = &proc0_tf;
- thread0.td_pcb->pcb_fsd = PCPU_GET(fsgs_gdt)[0];
- thread0.td_pcb->pcb_gsd = PCPU_GET(fsgs_gdt)[1];
-
- cpu_probe_amdc1e();
-
- /* Location of kernel stack for locore */
- return ((register_t)thread0.td_pcb);
-}
-
-#else
register_t
init386(first)
int first;
@@ -3402,7 +2659,7 @@ init386(first)
dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)];
dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 =
dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
dblfault_tss.tss_cr3 = (int)IdlePDPT;
#else
dblfault_tss.tss_cr3 = (int)IdlePTD;
@@ -3474,7 +2731,7 @@ init386(first)
/* setup proc 0's pcb */
thread0.td_pcb->pcb_flags = 0;
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
thread0.td_pcb->pcb_cr3 = (int)IdlePDPT;
#else
thread0.td_pcb->pcb_cr3 = (int)IdlePTD;
@@ -3491,7 +2748,6 @@ init386(first)
/* Location of kernel stack for locore */
return ((register_t)thread0.td_pcb);
}
-#endif
void
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
diff --git a/sys/i386/i386/minidump_machdep.c b/sys/i386/i386/minidump_machdep.c
index dd3490b..8f78abc 100644
--- a/sys/i386/i386/minidump_machdep.c
+++ b/sys/i386/i386/minidump_machdep.c
@@ -68,10 +68,6 @@ static void *dump_va;
static uint64_t counter, progress;
CTASSERT(sizeof(*vm_page_dump) == 4);
-#ifndef XEN
-#define xpmap_mtop(x) (x)
-#define xpmap_ptom(x) (x)
-#endif
static int
@@ -205,7 +201,7 @@ minidumpsys(struct dumperinfo *di)
j = va >> PDRSHIFT;
if ((pd[j] & (PG_PS | PG_V)) == (PG_PS | PG_V)) {
/* This is an entire 2M page. */
- pa = xpmap_mtop(pd[j] & PG_PS_FRAME);
+ pa = pd[j] & PG_PS_FRAME;
for (k = 0; k < NPTEPG; k++) {
if (is_dumpable(pa))
dump_add_page(pa);
@@ -215,10 +211,10 @@ minidumpsys(struct dumperinfo *di)
}
if ((pd[j] & PG_V) == PG_V) {
/* set bit for each valid page in this 2MB block */
- pt = pmap_kenter_temporary(xpmap_mtop(pd[j] & PG_FRAME), 0);
+ pt = pmap_kenter_temporary(pd[j] & PG_FRAME, 0);
for (k = 0; k < NPTEPG; k++) {
if ((pt[k] & PG_V) == PG_V) {
- pa = xpmap_mtop(pt[k] & PG_FRAME);
+ pa = pt[k] & PG_FRAME;
if (is_dumpable(pa))
dump_add_page(pa);
}
@@ -265,7 +261,7 @@ minidumpsys(struct dumperinfo *di)
mdhdr.bitmapsize = vm_page_dump_size;
mdhdr.ptesize = ptesize;
mdhdr.kernbase = KERNBASE;
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
mdhdr.paemode = 1;
#endif
@@ -318,24 +314,8 @@ minidumpsys(struct dumperinfo *di)
continue;
}
if ((pd[j] & PG_V) == PG_V) {
- pa = xpmap_mtop(pd[j] & PG_FRAME);
-#ifndef XEN
+ pa = pd[j] & PG_FRAME;
error = blk_write(di, 0, pa, PAGE_SIZE);
-#else
- pt = pmap_kenter_temporary(pa, 0);
- memcpy(fakept, pt, PAGE_SIZE);
- for (i = 0; i < NPTEPG; i++)
- fakept[i] = xpmap_mtop(fakept[i]);
- error = blk_write(di, (char *)&fakept, 0, PAGE_SIZE);
- if (error)
- goto fail;
- /* flush, in case we reuse fakept in the same block */
- error = blk_flush(di);
- if (error)
- goto fail;
- bzero(fakept, sizeof(fakept));
-#endif
-
if (error)
goto fail;
} else {
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 083b283..bad69ee 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -130,332 +130,23 @@ __FBSDID("$FreeBSD$");
#endif /* CHECK_POINTS */
-/* lock region used by kernel profiling */
-int mcount_lock;
-
-int mp_naps; /* # of Applications processors */
-int boot_cpu_id = -1; /* designated BSP */
-
extern struct pcpu __pcpu[];
-/* AP uses this during bootstrap. Do not staticize. */
-char *bootSTK;
-static int bootAP;
-
-/* Free these after use */
-void *bootstacks[MAXCPU];
-static void *dpcpu;
-
-struct pcb stoppcbs[MAXCPU];
-struct susppcb **susppcbs;
-
/* Variables needed for SMP tlb shootdown. */
vm_offset_t smp_tlb_addr1;
vm_offset_t smp_tlb_addr2;
volatile int smp_tlb_wait;
-#ifdef COUNT_IPIS
-/* Interrupt counts. */
-static u_long *ipi_preempt_counts[MAXCPU];
-static u_long *ipi_ast_counts[MAXCPU];
-u_long *ipi_invltlb_counts[MAXCPU];
-u_long *ipi_invlrng_counts[MAXCPU];
-u_long *ipi_invlpg_counts[MAXCPU];
-u_long *ipi_invlcache_counts[MAXCPU];
-u_long *ipi_rendezvous_counts[MAXCPU];
-u_long *ipi_lazypmap_counts[MAXCPU];
-static u_long *ipi_hardclock_counts[MAXCPU];
-#endif
-
-/* Default cpu_ops implementation. */
-struct cpu_ops cpu_ops;
-
/*
* Local data and functions.
*/
-static volatile cpuset_t ipi_nmi_pending;
-
-/* used to hold the AP's until we are ready to release them */
-static struct mtx ap_boot_mtx;
-
-/* Set to 1 once we're ready to let the APs out of the pen. */
-static volatile int aps_ready = 0;
-
-/*
- * Store data from cpu_add() until later in the boot when we actually setup
- * the APs.
- */
-struct cpu_info {
- int cpu_present:1;
- int cpu_bsp:1;
- int cpu_disabled:1;
- int cpu_hyperthread:1;
-} static cpu_info[MAX_APIC_ID + 1];
-int cpu_apic_ids[MAXCPU];
-int apic_cpuids[MAX_APIC_ID + 1];
-
-/* Holds pending bitmap based IPIs per CPU */
-volatile u_int cpu_ipi_pending[MAXCPU];
-
-static u_int boot_address;
-static int cpu_logical; /* logical cpus per core */
-static int cpu_cores; /* cores per package */
-
-static void assign_cpu_ids(void);
static void install_ap_tramp(void);
-static void set_interrupt_apic_ids(void);
static int start_all_aps(void);
static int start_ap(int apic_id);
static void release_aps(void *dummy);
-static u_int hyperthreading_cpus; /* logical cpus sharing L1 cache */
-static int hyperthreading_allowed = 1;
-
-static void
-mem_range_AP_init(void)
-{
- if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
- mem_range_softc.mr_op->initAP(&mem_range_softc);
-}
-
-static void
-topo_probe_amd(void)
-{
- int core_id_bits;
- int id;
-
- /* AMD processors do not support HTT. */
- cpu_logical = 1;
-
- if ((amd_feature2 & AMDID2_CMP) == 0) {
- cpu_cores = 1;
- return;
- }
-
- core_id_bits = (cpu_procinfo2 & AMDID_COREID_SIZE) >>
- AMDID_COREID_SIZE_SHIFT;
- if (core_id_bits == 0) {
- cpu_cores = (cpu_procinfo2 & AMDID_CMP_CORES) + 1;
- return;
- }
-
- /* Fam 10h and newer should get here. */
- for (id = 0; id <= MAX_APIC_ID; id++) {
- /* Check logical CPU availability. */
- if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
- continue;
- /* Check if logical CPU has the same package ID. */
- if ((id >> core_id_bits) != (boot_cpu_id >> core_id_bits))
- continue;
- cpu_cores++;
- }
-}
-
-/*
- * Round up to the next power of two, if necessary, and then
- * take log2.
- * Returns -1 if argument is zero.
- */
-static __inline int
-mask_width(u_int x)
-{
-
- return (fls(x << (1 - powerof2(x))) - 1);
-}
-
-static void
-topo_probe_0x4(void)
-{
- u_int p[4];
- int pkg_id_bits;
- int core_id_bits;
- int max_cores;
- int max_logical;
- int id;
-
- /* Both zero and one here mean one logical processor per package. */
- max_logical = (cpu_feature & CPUID_HTT) != 0 ?
- (cpu_procinfo & CPUID_HTT_CORES) >> 16 : 1;
- if (max_logical <= 1)
- return;
-
- /*
- * Because of uniformity assumption we examine only
- * those logical processors that belong to the same
- * package as BSP. Further, we count number of
- * logical processors that belong to the same core
- * as BSP thus deducing number of threads per core.
- */
- if (cpu_high >= 0x4) {
- cpuid_count(0x04, 0, p);
- max_cores = ((p[0] >> 26) & 0x3f) + 1;
- } else
- max_cores = 1;
- core_id_bits = mask_width(max_logical/max_cores);
- if (core_id_bits < 0)
- return;
- pkg_id_bits = core_id_bits + mask_width(max_cores);
-
- for (id = 0; id <= MAX_APIC_ID; id++) {
- /* Check logical CPU availability. */
- if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
- continue;
- /* Check if logical CPU has the same package ID. */
- if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits))
- continue;
- cpu_cores++;
- /* Check if logical CPU has the same package and core IDs. */
- if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits))
- cpu_logical++;
- }
-
- KASSERT(cpu_cores >= 1 && cpu_logical >= 1,
- ("topo_probe_0x4 couldn't find BSP"));
-
- cpu_cores /= cpu_logical;
- hyperthreading_cpus = cpu_logical;
-}
-
-static void
-topo_probe_0xb(void)
-{
- u_int p[4];
- int bits;
- int cnt;
- int i;
- int logical;
- int type;
- int x;
-
- /* We only support three levels for now. */
- for (i = 0; i < 3; i++) {
- cpuid_count(0x0b, i, p);
-
- /* Fall back if CPU leaf 11 doesn't really exist. */
- if (i == 0 && p[1] == 0) {
- topo_probe_0x4();
- return;
- }
-
- bits = p[0] & 0x1f;
- logical = p[1] &= 0xffff;
- type = (p[2] >> 8) & 0xff;
- if (type == 0 || logical == 0)
- break;
- /*
- * Because of uniformity assumption we examine only
- * those logical processors that belong to the same
- * package as BSP.
- */
- for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) {
- if (!cpu_info[x].cpu_present ||
- cpu_info[x].cpu_disabled)
- continue;
- if (x >> bits == boot_cpu_id >> bits)
- cnt++;
- }
- if (type == CPUID_TYPE_SMT)
- cpu_logical = cnt;
- else if (type == CPUID_TYPE_CORE)
- cpu_cores = cnt;
- }
- if (cpu_logical == 0)
- cpu_logical = 1;
- cpu_cores /= cpu_logical;
-}
-
-/*
- * Both topology discovery code and code that consumes topology
- * information assume top-down uniformity of the topology.
- * That is, all physical packages must be identical and each
- * core in a package must have the same number of threads.
- * Topology information is queried only on BSP, on which this
- * code runs and for which it can query CPUID information.
- * Then topology is extrapolated on all packages using the
- * uniformity assumption.
- */
-static void
-topo_probe(void)
-{
- static int cpu_topo_probed = 0;
-
- if (cpu_topo_probed)
- return;
-
- CPU_ZERO(&logical_cpus_mask);
- if (mp_ncpus <= 1)
- cpu_cores = cpu_logical = 1;
- else if (cpu_vendor_id == CPU_VENDOR_AMD)
- topo_probe_amd();
- else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
- /*
- * See Intel(R) 64 Architecture Processor
- * Topology Enumeration article for details.
- *
- * Note that 0x1 <= cpu_high < 4 case should be
- * compatible with topo_probe_0x4() logic when
- * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
- * or it should trigger the fallback otherwise.
- */
- if (cpu_high >= 0xb)
- topo_probe_0xb();
- else if (cpu_high >= 0x1)
- topo_probe_0x4();
- }
-
- /*
- * Fallback: assume each logical CPU is in separate
- * physical package. That is, no multi-core, no SMT.
- */
- if (cpu_cores == 0 || cpu_logical == 0)
- cpu_cores = cpu_logical = 1;
- cpu_topo_probed = 1;
-}
-
-struct cpu_group *
-cpu_topo(void)
-{
- int cg_flags;
-
- /*
- * Determine whether any threading flags are
- * necessry.
- */
- topo_probe();
- if (cpu_logical > 1 && hyperthreading_cpus)
- cg_flags = CG_FLAG_HTT;
- else if (cpu_logical > 1)
- cg_flags = CG_FLAG_SMT;
- else
- cg_flags = 0;
- if (mp_ncpus % (cpu_cores * cpu_logical) != 0) {
- printf("WARNING: Non-uniform processors.\n");
- printf("WARNING: Using suboptimal topology.\n");
- return (smp_topo_none());
- }
- /*
- * No multi-core or hyper-threaded.
- */
- if (cpu_logical * cpu_cores == 1)
- return (smp_topo_none());
- /*
- * Only HTT no multi-core.
- */
- if (cpu_logical > 1 && cpu_cores == 1)
- return (smp_topo_1level(CG_SHARE_L1, cpu_logical, cg_flags));
- /*
- * Only multi-core no HTT.
- */
- if (cpu_cores > 1 && cpu_logical == 1)
- return (smp_topo_1level(CG_SHARE_L2, cpu_cores, cg_flags));
- /*
- * Both HTT and multi-core.
- */
- return (smp_topo_2level(CG_SHARE_L2, cpu_cores,
- CG_SHARE_L1, cpu_logical, cg_flags));
-}
-
+static u_int boot_address;
/*
* Calculate usable address in base memory for AP trampoline code.
@@ -471,85 +162,6 @@ mp_bootaddress(u_int basemem)
return boot_address;
}
-void
-cpu_add(u_int apic_id, char boot_cpu)
-{
-
- if (apic_id > MAX_APIC_ID) {
- panic("SMP: APIC ID %d too high", apic_id);
- return;
- }
- KASSERT(cpu_info[apic_id].cpu_present == 0, ("CPU %d added twice",
- apic_id));
- cpu_info[apic_id].cpu_present = 1;
- if (boot_cpu) {
- KASSERT(boot_cpu_id == -1,
- ("CPU %d claims to be BSP, but CPU %d already is", apic_id,
- boot_cpu_id));
- boot_cpu_id = apic_id;
- cpu_info[apic_id].cpu_bsp = 1;
- }
- if (mp_ncpus < MAXCPU) {
- mp_ncpus++;
- mp_maxid = mp_ncpus - 1;
- }
- if (bootverbose)
- printf("SMP: Added CPU %d (%s)\n", apic_id, boot_cpu ? "BSP" :
- "AP");
-}
-
-void
-cpu_mp_setmaxid(void)
-{
-
- /*
- * mp_maxid should be already set by calls to cpu_add().
- * Just sanity check its value here.
- */
- if (mp_ncpus == 0)
- KASSERT(mp_maxid == 0,
- ("%s: mp_ncpus is zero, but mp_maxid is not", __func__));
- else if (mp_ncpus == 1)
- mp_maxid = 0;
- else
- KASSERT(mp_maxid >= mp_ncpus - 1,
- ("%s: counters out of sync: max %d, count %d", __func__,
- mp_maxid, mp_ncpus));
-}
-
-int
-cpu_mp_probe(void)
-{
-
- /*
- * Always record BSP in CPU map so that the mbuf init code works
- * correctly.
- */
- CPU_SETOF(0, &all_cpus);
- if (mp_ncpus == 0) {
- /*
- * No CPUs were found, so this must be a UP system. Setup
- * the variables to represent a system with a single CPU
- * with an id of 0.
- */
- mp_ncpus = 1;
- return (0);
- }
-
- /* At least one CPU was found. */
- if (mp_ncpus == 1) {
- /*
- * One CPU was found, so this must be a UP system with
- * an I/O APIC.
- */
- mp_maxid = 0;
- return (0);
- }
-
- /* At least two CPUs were found. */
- return (1);
-}
-
/*
* Initialize the IPI handlers and start up the AP's.
*/
@@ -576,10 +188,6 @@ cpu_mp_start(void)
setidt(IPI_INVLCACHE, IDTVEC(invlcache),
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
- /* Install an inter-CPU IPI for lazy pmap release */
- setidt(IPI_LAZYPMAP, IDTVEC(lazypmap),
- SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
-
/* Install an inter-CPU IPI for all-CPU rendezvous */
setidt(IPI_RENDEZVOUS, IDTVEC(rendezvous),
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
@@ -615,48 +223,6 @@ cpu_mp_start(void)
set_interrupt_apic_ids();
}
-
-/*
- * Print various information about the SMP system hardware and setup.
- */
-void
-cpu_mp_announce(void)
-{
- const char *hyperthread;
- int i;
-
- printf("FreeBSD/SMP: %d package(s) x %d core(s)",
- mp_ncpus / (cpu_cores * cpu_logical), cpu_cores);
- if (hyperthreading_cpus > 1)
- printf(" x %d HTT threads", cpu_logical);
- else if (cpu_logical > 1)
- printf(" x %d SMT threads", cpu_logical);
- printf("\n");
-
- /* List active CPUs first. */
- printf(" cpu0 (BSP): APIC ID: %2d\n", boot_cpu_id);
- for (i = 1; i < mp_ncpus; i++) {
- if (cpu_info[cpu_apic_ids[i]].cpu_hyperthread)
- hyperthread = "/HT";
- else
- hyperthread = "";
- printf(" cpu%d (AP%s): APIC ID: %2d\n", i, hyperthread,
- cpu_apic_ids[i]);
- }
-
- /* List disabled CPUs last. */
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || !cpu_info[i].cpu_disabled)
- continue;
- if (cpu_info[i].cpu_hyperthread)
- hyperthread = "/HT";
- else
- hyperthread = "";
- printf(" cpu (AP%s): APIC ID: %2d (disabled)\n", hyperthread,
- i);
- }
-}
-
/*
* AP CPU's call this to initialize themselves.
*/
@@ -667,7 +233,7 @@ init_secondary(void)
vm_offset_t addr;
int gsel_tss;
int x, myid;
- u_int cpuid, cr0;
+ u_int cr0;
/* bootAP is set in start_ap() to our ID. */
myid = bootAP;
@@ -736,84 +302,7 @@ init_secondary(void)
lidt(&r_idt);
#endif
- /*
- * On real hardware, switch to x2apic mode if possible. Do it
- * after aps_ready was signalled, to avoid manipulating the
- * mode while BSP might still want to send some IPI to us
- * (second startup IPI is ignored on modern hardware etc).
- */
- lapic_xapic_mode();
-
- /* Initialize the PAT MSR if present. */
- pmap_init_pat();
-
- /* set up CPU registers and state */
- cpu_setregs();
-
- /* set up SSE/NX */
- initializecpu();
-
- /* set up FPU state on the AP */
- npxinit(false);
-
- if (cpu_ops.cpu_init)
- cpu_ops.cpu_init();
-
- /* A quick check from sanity claus */
- cpuid = PCPU_GET(cpuid);
- if (PCPU_GET(apic_id) != lapic_id()) {
- printf("SMP: cpuid = %d\n", cpuid);
- printf("SMP: actual apic_id = %d\n", lapic_id());
- printf("SMP: correct apic_id = %d\n", PCPU_GET(apic_id));
- panic("cpuid mismatch! boom!!");
- }
-
- /* Initialize curthread. */
- KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
- PCPU_SET(curthread, PCPU_GET(idlethread));
-
- mca_init();
-
- mtx_lock_spin(&ap_boot_mtx);
-
- /* Init local apic for irq's */
- lapic_setup(1);
-
- /* Set memory range attributes for this CPU to match the BSP */
- mem_range_AP_init();
-
- smp_cpus++;
-
- CTR1(KTR_SMP, "SMP: AP CPU #%d Launched", cpuid);
- printf("SMP: AP CPU #%d Launched!\n", cpuid);
-
- /* Determine if we are a logical CPU. */
- /* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */
- if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0)
- CPU_SET(cpuid, &logical_cpus_mask);
-
- if (bootverbose)
- lapic_dump("AP");
-
- if (smp_cpus == mp_ncpus) {
- /* enable IPI's, tlb shootdown, freezes etc */
- atomic_store_rel_int(&smp_started, 1);
- }
-
- mtx_unlock_spin(&ap_boot_mtx);
-
- /* Wait until all the AP's are up. */
- while (smp_started == 0)
- ia32_pause();
-
- /* Start per-CPU event timers. */
- cpu_initclocks_ap();
-
- /* Enter the scheduler. */
- sched_throw(NULL);
-
- panic("scheduler returned us to %s", __func__);
- /* NOTREACHED */
+ init_secondary_tail();
}
/*******************************************************************
@@ -821,108 +310,6 @@ init_secondary(void)
*/
/*
- * We tell the I/O APIC code about all the CPUs we want to receive
- * interrupts. If we don't want certain CPUs to receive IRQs we
- * can simply not tell the I/O APIC code about them in this function.
- * We also do not tell it about the BSP since it tells itself about
- * the BSP internally to work with UP kernels and on UP machines.
- */
-static void
-set_interrupt_apic_ids(void)
-{
- u_int i, apic_id;
-
- for (i = 0; i < MAXCPU; i++) {
- apic_id = cpu_apic_ids[i];
- if (apic_id == -1)
- continue;
- if (cpu_info[apic_id].cpu_bsp)
- continue;
- if (cpu_info[apic_id].cpu_disabled)
- continue;
-
- /* Don't let hyperthreads service interrupts. */
- if (cpu_logical > 1 &&
- apic_id % cpu_logical != 0)
- continue;
-
- intr_add_cpu(i);
- }
-}
-
-/*
- * Assign logical CPU IDs to local APICs.
- */
-static void
-assign_cpu_ids(void)
-{
- u_int i;
-
- TUNABLE_INT_FETCH("machdep.hyperthreading_allowed",
- &hyperthreading_allowed);
-
- /* Check for explicitly disabled CPUs. */
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp)
- continue;
-
- if (hyperthreading_cpus > 1 && i % hyperthreading_cpus != 0) {
- cpu_info[i].cpu_hyperthread = 1;
-
- /*
- * Don't use HT CPU if it has been disabled by a
- * tunable.
- */
- if (hyperthreading_allowed == 0) {
- cpu_info[i].cpu_disabled = 1;
- continue;
- }
- }
-
- /* Don't use this CPU if it has been disabled by a tunable. */
- if (resource_disabled("lapic", i)) {
- cpu_info[i].cpu_disabled = 1;
- continue;
- }
- }
-
- if (hyperthreading_allowed == 0 && hyperthreading_cpus > 1) {
- hyperthreading_cpus = 0;
- cpu_logical = 1;
- }
-
- /*
- * Assign CPU IDs to local APIC IDs and disable any CPUs
- * beyond MAXCPU. CPU 0 is always assigned to the BSP.
- *
- * To minimize confusion for userland, we attempt to number
- * CPUs such that all threads and cores in a package are
- * grouped together. For now we assume that the BSP is always
- * the first thread in a package and just start adding APs
- * starting with the BSP's APIC ID.
- */
- mp_ncpus = 1;
- cpu_apic_ids[0] = boot_cpu_id;
- apic_cpuids[boot_cpu_id] = 0;
- for (i = boot_cpu_id + 1; i != boot_cpu_id;
- i == MAX_APIC_ID ? i = 0 : i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp ||
- cpu_info[i].cpu_disabled)
- continue;
-
- if (mp_ncpus < MAXCPU) {
- cpu_apic_ids[mp_ncpus] = i;
- apic_cpuids[i] = mp_ncpus;
- mp_ncpus++;
- } else
- cpu_info[i].cpu_disabled = 1;
- }
- KASSERT(mp_maxid >= mp_ncpus - 1,
- ("%s: counters out of sync: max %d, count %d", __func__, mp_maxid,
- mp_ncpus));
-}
-
-/*
* start each AP in our list
*/
/* Lowest 1MB is already mapped: don't touch*/
@@ -1099,129 +486,6 @@ start_ap(int apic_id)
return 0; /* return FAILURE */
}
-#ifdef COUNT_XINVLTLB_HITS
-u_int xhits_gbl[MAXCPU];
-u_int xhits_pg[MAXCPU];
-u_int xhits_rng[MAXCPU];
-static SYSCTL_NODE(_debug, OID_AUTO, xhits, CTLFLAG_RW, 0, "");
-SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, global, CTLFLAG_RW, &xhits_gbl,
- sizeof(xhits_gbl), "IU", "");
-SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, page, CTLFLAG_RW, &xhits_pg,
- sizeof(xhits_pg), "IU", "");
-SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, range, CTLFLAG_RW, &xhits_rng,
- sizeof(xhits_rng), "IU", "");
-
-u_int ipi_global;
-u_int ipi_page;
-u_int ipi_range;
-u_int ipi_range_size;
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_global, CTLFLAG_RW, &ipi_global, 0, "");
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_page, CTLFLAG_RW, &ipi_page, 0, "");
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_range, CTLFLAG_RW, &ipi_range, 0, "");
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_range_size, CTLFLAG_RW, &ipi_range_size,
- 0, "");
-
-u_int ipi_masked_global;
-u_int ipi_masked_page;
-u_int ipi_masked_range;
-u_int ipi_masked_range_size;
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_global, CTLFLAG_RW,
- &ipi_masked_global, 0, "");
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_page, CTLFLAG_RW,
- &ipi_masked_page, 0, "");
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_range, CTLFLAG_RW,
- &ipi_masked_range, 0, "");
-SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_range_size, CTLFLAG_RW,
- &ipi_masked_range_size, 0, "");
-#endif /* COUNT_XINVLTLB_HITS */
-
-/*
- * Init and startup IPI.
- */
-void
-ipi_startup(int apic_id, int vector)
-{
-
- /*
- * This attempts to follow the algorithm described in the
- * Intel Multiprocessor Specification v1.4 in section B.4.
- * For each IPI, we allow the local APIC ~20us to deliver the
- * IPI. If that times out, we panic.
- */
-
- /*
- * first we do an INIT IPI: this INIT IPI might be run, resetting
- * and running the target CPU. OR this INIT IPI might be latched (P5
- * bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be
- * ignored.
- */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
- APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
- lapic_ipi_wait(100);
-
- /* Explicitly deassert the INIT IPI. */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT,
- apic_id);
-
- DELAY(10000); /* wait ~10mS */
-
- /*
- * next we do a STARTUP IPI: the previous INIT IPI might still be
- * latched, (P5 bug) this 1st STARTUP would then terminate
- * immediately, and the previously started INIT IPI would continue. OR
- * the previous INIT IPI has already run. and this STARTUP IPI will
- * run. OR the previous INIT IPI was ignored. and this STARTUP IPI
- * will run.
- */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
- vector, apic_id);
- if (!lapic_ipi_wait(100))
- panic("Failed to deliver first STARTUP IPI to APIC %d",
- apic_id);
- DELAY(200); /* wait ~200uS */
-
- /*
- * finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF
- * the previous STARTUP IPI was cancelled by a latched INIT IPI. OR
- * this STARTUP IPI will be ignored, as only ONE STARTUP IPI is
- * recognized after hardware RESET or INIT IPI.
- */
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
- vector, apic_id);
- if (!lapic_ipi_wait(100))
- panic("Failed to deliver second STARTUP IPI to APIC %d",
- apic_id);
-
- DELAY(200); /* wait ~200uS */
-}
-
-/*
- * Send an IPI to specified CPU handling the bitmap logic.
- */
-static void
-ipi_send_cpu(int cpu, u_int ipi)
-{
- u_int bitmap, old_pending, new_pending;
-
- KASSERT(cpu_apic_ids[cpu] != -1, ("IPI to non-existent CPU %d", cpu));
-
- if (IPI_IS_BITMAPED(ipi)) {
- bitmap = 1 << ipi;
- ipi = IPI_BITMAP_VECTOR;
- do {
- old_pending = cpu_ipi_pending[cpu];
- new_pending = old_pending | bitmap;
- } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu],
- old_pending, new_pending));
- if (old_pending)
- return;
- }
- lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
-}
-
/*
* Flush the TLB on all other CPU's
*/
@@ -1285,14 +549,6 @@ smp_targeted_tlb_shootdown(cpuset_t mask, u_int vector, vm_offset_t addr1, vm_of
}
void
-smp_cache_flush(void)
-{
-
- if (smp_started)
- smp_tlb_shootdown(IPI_INVLCACHE, 0, 0);
-}
-
-void
smp_invltlb(void)
{
@@ -1367,203 +623,11 @@ smp_masked_invlpg_range(cpuset_t mask, vm_offset_t addr1, vm_offset_t addr2)
}
void
-ipi_bitmap_handler(struct trapframe frame)
-{
- struct trapframe *oldframe;
- struct thread *td;
- int cpu = PCPU_GET(cpuid);
- u_int ipi_bitmap;
-
- critical_enter();
- td = curthread;
- td->td_intr_nesting_level++;
- oldframe = td->td_intr_frame;
- td->td_intr_frame = &frame;
- ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]);
- if (ipi_bitmap & (1 << IPI_PREEMPT)) {
-#ifdef COUNT_IPIS
- (*ipi_preempt_counts[cpu])++;
-#endif
- sched_preempt(td);
- }
- if (ipi_bitmap & (1 << IPI_AST)) {
-#ifdef COUNT_IPIS
- (*ipi_ast_counts[cpu])++;
-#endif
- /* Nothing to do for AST */
- }
- if (ipi_bitmap & (1 << IPI_HARDCLOCK)) {
-#ifdef COUNT_IPIS
- (*ipi_hardclock_counts[cpu])++;
-#endif
- hardclockintr();
- }
- td->td_intr_frame = oldframe;
- td->td_intr_nesting_level--;
- critical_exit();
-}
-
-/*
- * send an IPI to a set of cpus.
- */
-void
-ipi_selected(cpuset_t cpus, u_int ipi)
-{
- int cpu;
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_OR_ATOMIC(&ipi_nmi_pending, &cpus);
-
- while ((cpu = CPU_FFS(&cpus)) != 0) {
- cpu--;
- CPU_CLR(cpu, &cpus);
- CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
- ipi_send_cpu(cpu, ipi);
- }
-}
-
-/*
- * send an IPI to a specific CPU.
- */
-void
-ipi_cpu(int cpu, u_int ipi)
-{
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_SET_ATOMIC(cpu, &ipi_nmi_pending);
-
- CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
- ipi_send_cpu(cpu, ipi);
-}
-
-/*
- * send an IPI to all CPUs EXCEPT myself
- */
-void
-ipi_all_but_self(u_int ipi)
-{
- cpuset_t other_cpus;
-
- other_cpus = all_cpus;
- CPU_CLR(PCPU_GET(cpuid), &other_cpus);
- if (IPI_IS_BITMAPED(ipi)) {
- ipi_selected(other_cpus, ipi);
- return;
- }
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
-
- CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
- lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
-}
-
-int
-ipi_nmi_handler()
-{
- u_int cpuid;
-
- /*
- * As long as there is not a simple way to know about a NMI's
- * source, if the bitmask for the current CPU is present in
- * the global pending bitword an IPI_STOP_HARD has been issued
- * and should be handled.
- */
- cpuid = PCPU_GET(cpuid);
- if (!CPU_ISSET(cpuid, &ipi_nmi_pending))
- return (1);
-
- CPU_CLR_ATOMIC(cpuid, &ipi_nmi_pending);
- cpustop_handler();
- return (0);
-}
-
-/*
- * Handle an IPI_STOP by saving our current context and spinning until we
- * are resumed.
- */
-void
-cpustop_handler(void)
-{
- u_int cpu;
-
- cpu = PCPU_GET(cpuid);
-
- savectx(&stoppcbs[cpu]);
-
- /* Indicate that we are stopped */
- CPU_SET_ATOMIC(cpu, &stopped_cpus);
-
- /* Wait for restart */
- while (!CPU_ISSET(cpu, &started_cpus))
- ia32_pause();
-
- CPU_CLR_ATOMIC(cpu, &started_cpus);
- CPU_CLR_ATOMIC(cpu, &stopped_cpus);
-
- if (cpu == 0 && cpustop_restartfunc != NULL) {
- cpustop_restartfunc();
- cpustop_restartfunc = NULL;
- }
-}
-
-/*
- * Handle an IPI_SUSPEND by saving our current context and spinning until we
- * are resumed.
- */
-void
-cpususpend_handler(void)
+smp_cache_flush(void)
{
- u_int cpu;
-
- mtx_assert(&smp_ipi_mtx, MA_NOTOWNED);
-
- cpu = PCPU_GET(cpuid);
- if (savectx(&susppcbs[cpu]->sp_pcb)) {
- npxsuspend(susppcbs[cpu]->sp_fpususpend);
- wbinvd();
- CPU_SET_ATOMIC(cpu, &suspended_cpus);
- } else {
- npxresume(susppcbs[cpu]->sp_fpususpend);
- pmap_init_pat();
- initializecpu();
- PCPU_SET(switchtime, 0);
- PCPU_SET(switchticks, ticks);
-
- /* Indicate that we are resumed */
- CPU_CLR_ATOMIC(cpu, &suspended_cpus);
- }
-
- /* Wait for resume */
- while (!CPU_ISSET(cpu, &started_cpus))
- ia32_pause();
-
- if (cpu_ops.cpu_resume)
- cpu_ops.cpu_resume();
- /* Resume MCA and local APIC */
- lapic_xapic_mode();
- mca_resume();
- lapic_setup(0);
-
- /* Indicate that we are resumed */
- CPU_CLR_ATOMIC(cpu, &suspended_cpus);
- CPU_CLR_ATOMIC(cpu, &started_cpus);
+ if (smp_started)
+ smp_tlb_shootdown(IPI_INVLCACHE, 0, 0);
}
/*
@@ -1619,64 +683,3 @@ invlrng_handler(void)
atomic_add_int(&smp_tlb_wait, 1);
}
-
-void
-invlcache_handler(void)
-{
-#ifdef COUNT_IPIS
- (*ipi_invlcache_counts[PCPU_GET(cpuid)])++;
-#endif /* COUNT_IPIS */
-
- wbinvd();
- atomic_add_int(&smp_tlb_wait, 1);
-}
-
-/*
- * This is called once the rest of the system is up and running and we're
- * ready to let the AP's out of the pen.
- */
-static void
-release_aps(void *dummy __unused)
-{
-
- if (mp_ncpus == 1)
- return;
- atomic_store_rel_int(&aps_ready, 1);
- while (smp_started == 0)
- ia32_pause();
-}
-SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
-
-#ifdef COUNT_IPIS
-/*
- * Setup interrupt counters for IPI handlers.
- */
-static void
-mp_ipi_intrcnt(void *dummy)
-{
- char buf[64];
- int i;
-
- CPU_FOREACH(i) {
- snprintf(buf, sizeof(buf), "cpu%d:invltlb", i);
- intrcnt_add(buf, &ipi_invltlb_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:invlrng", i);
- intrcnt_add(buf, &ipi_invlrng_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:invlpg", i);
- intrcnt_add(buf, &ipi_invlpg_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:invlcache", i);
- intrcnt_add(buf, &ipi_invlcache_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:preempt", i);
- intrcnt_add(buf, &ipi_preempt_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:ast", i);
- intrcnt_add(buf, &ipi_ast_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:rendezvous", i);
- intrcnt_add(buf, &ipi_rendezvous_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:lazypmap", i);
- intrcnt_add(buf, &ipi_lazypmap_counts[i]);
- snprintf(buf, sizeof(buf), "cpu%d:hardclock", i);
- intrcnt_add(buf, &ipi_hardclock_counts[i]);
- }
-}
-SYSINIT(mp_ipi_intrcnt, SI_SUB_INTR, SI_ORDER_MIDDLE, mp_ipi_intrcnt, NULL);
-#endif
diff --git a/sys/i386/i386/mpboot.s b/sys/i386/i386/mpboot.s
index a3ef283..8f5098d 100644
--- a/sys/i386/i386/mpboot.s
+++ b/sys/i386/i386/mpboot.s
@@ -99,7 +99,7 @@ NON_GPROF_ENTRY(MPentry)
movl %eax,%cr4
/* Now enable paging mode */
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
movl R(IdlePDPT), %eax
movl %eax, %cr3
movl %cr4, %eax
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index 2d2be0f..029a277 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -214,7 +214,7 @@ vm_offset_t kernel_vm_end = KERNBASE + NKPT * NBPDR;
extern u_int32_t KERNend;
extern u_int32_t KPTphys;
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
pt_entry_t pg_nx;
static uma_zone_t pdptzone;
#endif
@@ -339,7 +339,7 @@ static void _pmap_unwire_ptp(pmap_t pmap, vm_page_t m, struct spglist *free);
static pt_entry_t *pmap_pte_quick(pmap_t pmap, vm_offset_t va);
static void pmap_pte_release(pt_entry_t *pte);
static int pmap_unuse_pt(pmap_t, vm_offset_t, struct spglist *);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
static void *pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, uint8_t *flags,
int wait);
#endif
@@ -400,7 +400,7 @@ pmap_bootstrap(vm_paddr_t firstaddr)
*/
PMAP_LOCK_INIT(kernel_pmap);
kernel_pmap->pm_pdir = (pd_entry_t *) (KERNBASE + (u_int)IdlePTD);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
kernel_pmap->pm_pdpt = (pdpt_entry_t *) (KERNBASE + (u_int)IdlePDPT);
#endif
CPU_FILL(&kernel_pmap->pm_active); /* don't allow deactivation */
@@ -657,7 +657,7 @@ pmap_page_init(vm_page_t m)
m->md.pat_mode = PAT_WRITE_BACK;
}
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
static void *
pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, uint8_t *flags, int wait)
{
@@ -670,7 +670,7 @@ pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, uint8_t *flags, int wait)
#endif
/*
- * ABuse the pte nodes for unmapped kva to thread a kva freelist through.
+ * Abuse the pte nodes for unmapped kva to thread a kva freelist through.
* Requirements:
* - Must deal with pages in order to ensure that none of the PG_* bits
* are ever set, PG_V in particular.
@@ -809,7 +809,7 @@ pmap_init(void)
if (pv_chunkbase == NULL)
panic("pmap_init: not enough kvm for pv chunks");
pmap_ptelist_init(&pv_vafree, pv_chunkbase, pv_maxchunks);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
pdptzone = uma_zcreate("PDPT", NPGPTD * sizeof(pdpt_entry_t), NULL,
NULL, NULL, NULL, (NPGPTD * sizeof(pdpt_entry_t)) - 1,
UMA_ZONE_VM | UMA_ZONE_NOFREE);
@@ -1248,18 +1248,14 @@ pmap_invalidate_cache_pages(vm_page_t *pages, int count)
}
/*
- * Are we current address space or kernel? N.B. We return FALSE when
- * a pmap's page table is in use because a kernel thread is borrowing
- * it. The borrowed page table can change spontaneously, making any
- * dependence on its continued use subject to a race condition.
+ * Are we current address space or kernel?
*/
static __inline int
pmap_is_current(pmap_t pmap)
{
- return (pmap == kernel_pmap ||
- (pmap == vmspace_pmap(curthread->td_proc->p_vmspace) &&
- (pmap->pm_pdir[PTDPTDI] & PG_FRAME) == (PTDpde[0] & PG_FRAME)));
+ return (pmap == kernel_pmap || pmap ==
+ vmspace_pmap(curthread->td_proc->p_vmspace));
}
/*
@@ -1744,7 +1740,7 @@ pmap_pinit0(pmap_t pmap)
* not need to be inserted into that list.
*/
pmap->pm_pdir = (pd_entry_t *)(KERNBASE + (vm_offset_t)IdlePTD);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
pmap->pm_pdpt = (pdpt_entry_t *)(KERNBASE + (vm_offset_t)IdlePDPT);
#endif
pmap->pm_root.rt_root = 0;
@@ -1773,7 +1769,7 @@ pmap_pinit(pmap_t pmap)
pmap->pm_pdir = (pd_entry_t *)kva_alloc(NBPTD);
if (pmap->pm_pdir == NULL)
return (0);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
pmap->pm_pdpt = uma_zalloc(pdptzone, M_WAITOK | M_ZERO);
KASSERT(((vm_offset_t)pmap->pm_pdpt &
((NPGPTD * sizeof(pdpt_entry_t)) - 1)) == 0,
@@ -1815,7 +1811,7 @@ pmap_pinit(pmap_t pmap)
for (i = 0; i < NPGPTD; i++) {
pa = VM_PAGE_TO_PHYS(ptdpg[i]);
pmap->pm_pdir[PTDPTDI + i] = pa | PG_V | PG_RW | PG_A | PG_M;
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
pmap->pm_pdpt[i] = pa | PG_V;
#endif
}
@@ -1923,108 +1919,6 @@ retry:
* Pmap allocation/deallocation routines.
***************************************************/
-#ifdef SMP
-/*
- * Deal with a SMP shootdown of other users of the pmap that we are
- * trying to dispose of. This can be a bit hairy.
- */
-static cpuset_t *lazymask;
-static u_int lazyptd;
-static volatile u_int lazywait;
-
-void pmap_lazyfix_action(void);
-
-void
-pmap_lazyfix_action(void)
-{
-
-#ifdef COUNT_IPIS
- (*ipi_lazypmap_counts[PCPU_GET(cpuid)])++;
-#endif
- if (rcr3() == lazyptd)
- load_cr3(curpcb->pcb_cr3);
- CPU_CLR_ATOMIC(PCPU_GET(cpuid), lazymask);
- atomic_store_rel_int(&lazywait, 1);
-}
-
-static void
-pmap_lazyfix_self(u_int cpuid)
-{
-
- if (rcr3() == lazyptd)
- load_cr3(curpcb->pcb_cr3);
- CPU_CLR_ATOMIC(cpuid, lazymask);
-}
-
-
-static void
-pmap_lazyfix(pmap_t pmap)
-{
- cpuset_t mymask, mask;
- u_int cpuid, spins;
- int lsb;
-
- mask = pmap->pm_active;
- while (!CPU_EMPTY(&mask)) {
- spins = 50000000;
-
- /* Find least significant set bit. */
- lsb = CPU_FFS(&mask);
- MPASS(lsb != 0);
- lsb--;
- CPU_SETOF(lsb, &mask);
- mtx_lock_spin(&smp_ipi_mtx);
-#ifdef PAE
- lazyptd = vtophys(pmap->pm_pdpt);
-#else
- lazyptd = vtophys(pmap->pm_pdir);
-#endif
- cpuid = PCPU_GET(cpuid);
-
- /* Use a cpuset just for having an easy check. */
- CPU_SETOF(cpuid, &mymask);
- if (!CPU_CMP(&mask, &mymask)) {
- lazymask = &pmap->pm_active;
- pmap_lazyfix_self(cpuid);
- } else {
- atomic_store_rel_int((u_int *)&lazymask,
- (u_int)&pmap->pm_active);
- atomic_store_rel_int(&lazywait, 0);
- ipi_selected(mask, IPI_LAZYPMAP);
- while (lazywait == 0) {
- ia32_pause();
- if (--spins == 0)
- break;
- }
- }
- mtx_unlock_spin(&smp_ipi_mtx);
- if (spins == 0)
- printf("pmap_lazyfix: spun for 50000000\n");
- mask = pmap->pm_active;
- }
-}
-
-#else /* SMP */
-
-/*
- * Cleaning up on uniprocessor is easy. For various reasons, we're
- * unlikely to have to even execute this code, including the fact
- * that the cleanup is deferred until the parent does a wait(2), which
- * means that another userland process has run.
- */
-static void
-pmap_lazyfix(pmap_t pmap)
-{
- u_int cr3;
-
- cr3 = vtophys(pmap->pm_pdir);
- if (cr3 == rcr3()) {
- load_cr3(curpcb->pcb_cr3);
- CPU_CLR(PCPU_GET(cpuid), &pmap->pm_active);
- }
-}
-#endif /* SMP */
-
/*
* Release any resources held by the given physical map.
* Called when a pmap initialized by pmap_pinit is being released.
@@ -2041,8 +1935,9 @@ pmap_release(pmap_t pmap)
pmap->pm_stats.resident_count));
KASSERT(vm_radix_is_empty(&pmap->pm_root),
("pmap_release: pmap has reserved page table page(s)"));
+ KASSERT(CPU_EMPTY(&pmap->pm_active),
+ ("releasing active pmap %p", pmap));
- pmap_lazyfix(pmap);
mtx_lock_spin(&allpmaps_lock);
LIST_REMOVE(pmap, pm_list);
mtx_unlock_spin(&allpmaps_lock);
@@ -2058,7 +1953,7 @@ pmap_release(pmap_t pmap)
for (i = 0; i < NPGPTD; i++) {
m = ptdpg[i];
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
KASSERT(VM_PAGE_TO_PHYS(m) == (pmap->pm_pdpt[i] & PG_FRAME),
("pmap_release: got wrong ptd page"));
#endif
@@ -3150,7 +3045,7 @@ retry:
}
if ((prot & VM_PROT_WRITE) == 0)
newpde &= ~(PG_RW | PG_M);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((prot & VM_PROT_EXECUTE) == 0)
newpde |= pg_nx;
#endif
@@ -3183,7 +3078,7 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
return;
}
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
(VM_PROT_WRITE|VM_PROT_EXECUTE))
return;
@@ -3286,13 +3181,13 @@ retry:
}
pbits &= ~(PG_RW | PG_M);
}
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((prot & VM_PROT_EXECUTE) == 0)
pbits |= pg_nx;
#endif
if (pbits != obits) {
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if (!atomic_cmpset_64(pte, obits, pbits))
goto retry;
#else
@@ -3606,7 +3501,7 @@ validate:
if ((newpte & PG_MANAGED) != 0)
vm_page_aflag_set(m, PGA_WRITEABLE);
}
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((prot & VM_PROT_EXECUTE) == 0)
newpte |= pg_nx;
#endif
@@ -3633,7 +3528,7 @@ validate:
vm_page_aflag_set(om, PGA_REFERENCED);
if (opa != VM_PAGE_TO_PHYS(m))
invlva = TRUE;
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((origpte & PG_NX) == 0 &&
(newpte & PG_NX) != 0)
invlva = TRUE;
@@ -3704,7 +3599,7 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot)
return (FALSE);
}
}
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((prot & VM_PROT_EXECUTE) == 0)
newpde |= pg_nx;
#endif
@@ -3881,7 +3776,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
pmap->pm_stats.resident_count++;
pa = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(m->md.pat_mode, 0);
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
if ((prot & VM_PROT_EXECUTE) == 0)
pa |= pg_nx;
#endif
@@ -5461,7 +5356,7 @@ pmap_activate(struct thread *td)
CPU_CLR(cpuid, &oldpmap->pm_active);
CPU_SET(cpuid, &pmap->pm_active);
#endif
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
cr3 = vtophys(pmap->pm_pdpt);
#else
cr3 = vtophys(pmap->pm_pdir);
diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s
index 0a08012..78d76ef 100644
--- a/sys/i386/i386/support.s
+++ b/sys/i386/i386/support.s
@@ -695,11 +695,9 @@ END(bcmp)
*/
/* void lgdt(struct region_descriptor *rdp); */
ENTRY(lgdt)
-#ifndef XEN
/* reload the descriptor table */
movl 4(%esp),%eax
lgdt (%eax)
-#endif
/* flush the prefetch q */
jmp 1f
diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s
index e810434..6bedb48 100644
--- a/sys/i386/i386/swtch.s
+++ b/sys/i386/i386/swtch.s
@@ -88,7 +88,7 @@ ENTRY(cpu_throw)
movl 8(%esp),%ecx /* New thread */
movl TD_PCB(%ecx),%edx
movl PCB_CR3(%edx),%eax
- LOAD_CR3(%eax)
+ movl %eax,%cr3
/* set bit in new pm_active */
movl TD_PROC(%ecx),%eax
movl P_VMSPACE(%eax), %ebx
@@ -174,16 +174,10 @@ ENTRY(cpu_switch)
/* switch address space */
movl PCB_CR3(%edx),%eax
-#ifdef PAE
- cmpl %eax,IdlePDPT /* Kernel address space? */
-#else
- cmpl %eax,IdlePTD /* Kernel address space? */
-#endif
- je sw0
- READ_CR3(%ebx) /* The same address space? */
+ movl %cr3,%ebx /* The same address space? */
cmpl %ebx,%eax
je sw0
- LOAD_CR3(%eax) /* new address space */
+ movl %eax,%cr3 /* new address space */
movl %esi,%eax
movl PCPU(CPUID),%esi
SETOP %eax,TD_LOCK(%edi) /* Switchout td_lock */
@@ -210,18 +204,6 @@ sw0:
SETOP %esi,TD_LOCK(%edi) /* Switchout td_lock */
sw1:
BLOCK_SPIN(%ecx)
-#ifdef XEN
- pushl %eax
- pushl %ecx
- pushl %edx
- call xen_handle_thread_switch
- popl %edx
- popl %ecx
- popl %eax
- /*
- * XXX set IOPL
- */
-#else
/*
* At this point, we've switched address spaces and are ready
* to load up the rest of the next context.
@@ -270,7 +252,7 @@ sw1:
movl 12(%esi), %ebx
movl %eax, 8(%edi)
movl %ebx, 12(%edi)
-#endif
+
/* Restore context. */
movl PCB_EBX(%edx),%ebx
movl PCB_ESP(%edx),%esp
@@ -296,7 +278,7 @@ sw1:
movl _default_ldt,%eax
cmpl PCPU(CURRENTLDT),%eax
je 2f
- LLDT(_default_ldt)
+ lldt _default_ldt
movl %eax,PCPU(CURRENTLDT)
jmp 2f
1:
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
index 9518862..9044d19 100644
--- a/sys/i386/i386/sys_machdep.c
+++ b/sys/i386/i386/sys_machdep.c
@@ -59,20 +59,6 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
-#ifdef XEN
-#include <machine/xen/xenfunc.h>
-
-void i386_reset_ldt(struct proc_ldt *pldt);
-
-void
-i386_reset_ldt(struct proc_ldt *pldt)
-{
- xen_set_ldt((vm_offset_t)pldt->ldt_base, pldt->ldt_len);
-}
-#else
-#define i386_reset_ldt(x)
-#endif
-
#include <vm/vm_kern.h> /* for kernel_map */
#define MAX_LD 8192
@@ -211,12 +197,7 @@ sysarch(td, uap)
*/
sd.sd_lobase = base & 0xffffff;
sd.sd_hibase = (base >> 24) & 0xff;
-#ifdef XEN
- /* need to do nosegneg like Linux */
- sd.sd_lolimit = (HYPERVISOR_VIRT_START >> 12) & 0xffff;
-#else
sd.sd_lolimit = 0xffff; /* 4GB limit, wraps around */
-#endif
sd.sd_hilimit = 0xf;
sd.sd_type = SDT_MEMRWA;
sd.sd_dpl = SEL_UPL;
@@ -226,12 +207,7 @@ sysarch(td, uap)
sd.sd_gran = 1;
critical_enter();
td->td_pcb->pcb_fsd = sd;
-#ifdef XEN
- HYPERVISOR_update_descriptor(vtomach(&PCPU_GET(fsgs_gdt)[0]),
- *(uint64_t *)&sd);
-#else
PCPU_GET(fsgs_gdt)[0] = sd;
-#endif
critical_exit();
td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
}
@@ -252,12 +228,7 @@ sysarch(td, uap)
sd.sd_lobase = base & 0xffffff;
sd.sd_hibase = (base >> 24) & 0xff;
-#ifdef XEN
- /* need to do nosegneg like Linux */
- sd.sd_lolimit = (HYPERVISOR_VIRT_START >> 12) & 0xffff;
-#else
sd.sd_lolimit = 0xffff; /* 4GB limit, wraps around */
-#endif
sd.sd_hilimit = 0xf;
sd.sd_type = SDT_MEMRWA;
sd.sd_dpl = SEL_UPL;
@@ -267,12 +238,7 @@ sysarch(td, uap)
sd.sd_gran = 1;
critical_enter();
td->td_pcb->pcb_gsd = sd;
-#ifdef XEN
- HYPERVISOR_update_descriptor(vtomach(&PCPU_GET(fsgs_gdt)[1]),
- *(uint64_t *)&sd);
-#else
PCPU_GET(fsgs_gdt)[1] = sd;
-#endif
critical_exit();
load_gs(GSEL(GUGS_SEL, SEL_UPL));
}
@@ -434,10 +400,6 @@ set_user_ldt(struct mdproc *mdp)
}
pldt = mdp->md_ldt;
-#ifdef XEN
- i386_reset_ldt(pldt);
- PCPU_SET(currentldt, (int)pldt);
-#else
#ifdef SMP
gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd;
#else
@@ -445,7 +407,6 @@ set_user_ldt(struct mdproc *mdp)
#endif
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
-#endif /* XEN */
if (dtlocked)
mtx_unlock_spin(&dt_lock);
}
@@ -464,43 +425,6 @@ set_user_ldt_rv(struct vmspace *vmsp)
}
#endif
-#ifdef XEN
-
-/*
- * dt_lock must be held. Returns with dt_lock held.
- */
-struct proc_ldt *
-user_ldt_alloc(struct mdproc *mdp, int len)
-{
- struct proc_ldt *pldt, *new_ldt;
-
- mtx_assert(&dt_lock, MA_OWNED);
- mtx_unlock_spin(&dt_lock);
- new_ldt = malloc(sizeof(struct proc_ldt),
- M_SUBPROC, M_WAITOK);
-
- new_ldt->ldt_len = len = NEW_MAX_LD(len);
- new_ldt->ldt_base = (caddr_t)kmem_malloc(kernel_arena,
- round_page(len * sizeof(union descriptor)), M_WAITOK);
- new_ldt->ldt_refcnt = 1;
- new_ldt->ldt_active = 0;
-
- mtx_lock_spin(&dt_lock);
- if ((pldt = mdp->md_ldt)) {
- if (len > pldt->ldt_len)
- len = pldt->ldt_len;
- bcopy(pldt->ldt_base, new_ldt->ldt_base,
- len * sizeof(union descriptor));
- } else {
- bcopy(ldt, new_ldt->ldt_base, PAGE_SIZE);
- }
- mtx_unlock_spin(&dt_lock); /* XXX kill once pmap locking fixed. */
- pmap_map_readonly(kernel_pmap, (vm_offset_t)new_ldt->ldt_base,
- new_ldt->ldt_len*sizeof(union descriptor));
- mtx_lock_spin(&dt_lock); /* XXX kill once pmap locking fixed. */
- return (new_ldt);
-}
-#else
/*
* dt_lock must be held. Returns with dt_lock held.
*/
@@ -535,7 +459,6 @@ user_ldt_alloc(struct mdproc *mdp, int len)
return (new_ldt);
}
-#endif /* !XEN */
/*
* Must be called with dt_lock held. Returns with dt_lock unheld.
@@ -553,13 +476,8 @@ user_ldt_free(struct thread *td)
}
if (td == curthread) {
-#ifdef XEN
- i386_reset_ldt(&default_proc_ldt);
- PCPU_SET(currentldt, (int)&default_proc_ldt);
-#else
lldt(_default_ldt);
PCPU_SET(currentldt, _default_ldt);
-#endif
}
mdp->md_ldt = NULL;
@@ -785,27 +703,7 @@ again:
td->td_retval[0] = uap->start;
return (error);
}
-#ifdef XEN
-static int
-i386_set_ldt_data(struct thread *td, int start, int num,
- union descriptor *descs)
-{
- struct mdproc *mdp = &td->td_proc->p_md;
- struct proc_ldt *pldt = mdp->md_ldt;
- mtx_assert(&dt_lock, MA_OWNED);
-
- while (num) {
- xen_update_descriptor(
- &((union descriptor *)(pldt->ldt_base))[start],
- descs);
- num--;
- start++;
- descs++;
- }
- return (0);
-}
-#else
static int
i386_set_ldt_data(struct thread *td, int start, int num,
union descriptor *descs)
@@ -821,7 +719,6 @@ i386_set_ldt_data(struct thread *td, int start, int num,
num * sizeof(union descriptor));
return (0);
}
-#endif /* !XEN */
static int
i386_ldt_grow(struct thread *td, int len)
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 6d35c3a..d783a2b 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -881,7 +881,7 @@ trap_pfault(frame, usermode, eva)
*/
if (frame->tf_err & PGEX_W)
ftype = VM_PROT_WRITE;
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
else if ((frame->tf_err & PGEX_I) && pg_nx != 0)
ftype = VM_PROT_EXECUTE;
#endif
diff --git a/sys/i386/i386/vm86bios.s b/sys/i386/i386/vm86bios.s
index 450374e..f81b784 100644
--- a/sys/i386/i386/vm86bios.s
+++ b/sys/i386/i386/vm86bios.s
@@ -120,7 +120,7 @@ ENTRY(vm86_bioscall)
movl SCR_NEWPTD(%edx),%eax /* mapping for vm86 page table */
movl %eax,0(%ebx) /* ... install as PTD entry 0 */
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
movl IdlePDPT,%ecx
#endif
movl %ecx,%cr3 /* new page tables */
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index ebd177a..5671dc9 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -89,9 +89,6 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_map.h>
#include <vm/vm_param.h>
-#ifdef XEN
-#include <xen/hypervisor.h>
-#endif
#ifdef PC98
#include <pc98/cbus/cbus.h>
#else
@@ -262,7 +259,7 @@ cpu_fork(td1, p2, td2, flags)
* Set registers for trampoline to user mode. Leave space for the
* return address on stack. These are the kernel mode register values.
*/
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
pcb2->pcb_cr3 = vtophys(vmspace_pmap(p2->p_vmspace)->pm_pdpt);
#else
pcb2->pcb_cr3 = vtophys(vmspace_pmap(p2->p_vmspace)->pm_pdir);
@@ -304,10 +301,8 @@ cpu_fork(td1, p2, td2, flags)
/* Setup to release spin count in fork_exit(). */
td2->td_md.md_spinlock_count = 1;
- /*
- * XXX XEN need to check on PSL_USER is handled
- */
td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I;
+
/*
* Now, cpu_switch() can schedule the new process.
* pcb_esp is loaded pointing to the cpu_switch() stack frame
@@ -698,12 +693,6 @@ cpu_reset_real()
#endif
disable_intr();
-#ifdef XEN
- if (smp_processor_id() == 0)
- HYPERVISOR_shutdown(SHUTDOWN_reboot);
- else
- HYPERVISOR_shutdown(SHUTDOWN_poweroff);
-#endif
#ifdef CPU_ELAN
if (elan_mmcr != NULL)
elan_mmcr->RESCFG = 1;
@@ -797,13 +786,8 @@ sf_buf_map(struct sf_buf *sf, int flags)
*/
ptep = vtopte(sf->kva);
opte = *ptep;
-#ifdef XEN
- PT_SET_MA(sf->kva, xpmap_ptom(VM_PAGE_TO_PHYS(sf->m)) | pgeflag
- | PG_RW | PG_V | pmap_cache_bits(sf->m->md.pat_mode, 0));
-#else
*ptep = VM_PAGE_TO_PHYS(sf->m) | pgeflag | PG_RW | PG_V |
pmap_cache_bits(sf->m->md.pat_mode, 0);
-#endif
/*
* Avoid unnecessary TLB invalidations: If the sf_buf's old
@@ -854,15 +838,8 @@ sf_buf_shootdown(struct sf_buf *sf, int flags)
int
sf_buf_unmap(struct sf_buf *sf)
{
-#ifdef XEN
- /*
- * Xen doesn't like having dangling R/W mappings
- */
- pmap_qremove(sf->kva, 1);
- return (1);
-#else
+
return (0);
-#endif
}
static void
diff --git a/sys/i386/include/asmacros.h b/sys/i386/include/asmacros.h
index c1c3f64..716915c 100644
--- a/sys/i386/include/asmacros.h
+++ b/sys/i386/include/asmacros.h
@@ -176,37 +176,6 @@
movl $KPSEL, %eax ; /* reload with per-CPU data segment */ \
movl %eax, %fs
-#ifdef XEN
-#define LOAD_CR3(reg) \
- movl reg,PCPU(CR3); \
- pushl %ecx ; \
- pushl %edx ; \
- pushl %esi ; \
- pushl reg ; \
- call xen_load_cr3 ; \
- addl $4,%esp ; \
- popl %esi ; \
- popl %edx ; \
- popl %ecx ; \
-
-#define READ_CR3(reg) movl PCPU(CR3),reg;
-#define LLDT(arg) \
- pushl %edx ; \
- pushl %eax ; \
- xorl %eax,%eax ; \
- movl %eax,%gs ; \
- call i386_reset_ldt ; \
- popl %eax ; \
- popl %edx
-#define CLI call ni_cli
-#else
-#define LOAD_CR3(reg) movl reg,%cr3;
-#define READ_CR3(reg) movl %cr3,reg;
-#define LLDT(arg) lldt arg;
-#define CLI cli
-#endif /* !XEN */
-
-
#endif /* LOCORE */
#ifdef __STDC__
diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h
index f80a898..3bc25d4 100644
--- a/sys/i386/include/cpufunc.h
+++ b/sys/i386/include/cpufunc.h
@@ -42,17 +42,6 @@
#error this file needs sys/cdefs.h as a prerequisite
#endif
-#ifdef XEN
-extern void xen_cli(void);
-extern void xen_sti(void);
-extern u_int xen_rcr2(void);
-extern void xen_load_cr3(u_int data);
-extern void xen_tlb_flush(void);
-extern void xen_invlpg(u_int addr);
-extern void write_eflags(u_int eflags);
-extern u_int read_eflags(void);
-#endif
-
struct region_descriptor;
#define readb(va) (*(volatile uint8_t *) (va))
@@ -106,11 +95,8 @@ clts(void)
static __inline void
disable_intr(void)
{
-#ifdef XEN
- xen_cli();
-#else
+
__asm __volatile("cli" : : : "memory");
-#endif
}
static __inline void
@@ -132,11 +118,8 @@ cpuid_count(u_int ax, u_int cx, u_int *p)
static __inline void
enable_intr(void)
{
-#ifdef XEN
- xen_sti();
-#else
+
__asm __volatile("sti");
-#endif
}
static __inline void
@@ -325,11 +308,7 @@ ia32_pause(void)
}
static __inline u_int
-#ifdef XEN
-_read_eflags(void)
-#else
read_eflags(void)
-#endif
{
u_int ef;
@@ -389,11 +368,7 @@ wbinvd(void)
}
static __inline void
-#ifdef XEN
-_write_eflags(u_int ef)
-#else
write_eflags(u_int ef)
-#endif
{
__asm __volatile("pushl %0; popfl" : : "r" (ef));
}
@@ -425,9 +400,6 @@ rcr2(void)
{
u_int data;
-#ifdef XEN
- return (xen_rcr2());
-#endif
__asm __volatile("movl %%cr2,%0" : "=r" (data));
return (data);
}
@@ -435,11 +407,8 @@ rcr2(void)
static __inline void
load_cr3(u_int data)
{
-#ifdef XEN
- xen_load_cr3(data);
-#else
+
__asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
-#endif
}
static __inline u_int
@@ -491,11 +460,8 @@ load_xcr(u_int reg, uint64_t val)
static __inline void
invltlb(void)
{
-#ifdef XEN
- xen_tlb_flush();
-#else
+
load_cr3(rcr3());
-#endif
}
/*
@@ -506,11 +472,7 @@ static __inline void
invlpg(u_int addr)
{
-#ifdef XEN
- xen_invlpg(addr);
-#else
__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
-#endif
}
static __inline u_short
diff --git a/sys/i386/include/intr_machdep.h b/sys/i386/include/intr_machdep.h
index 082b649..96ac06a 100644
--- a/sys/i386/include/intr_machdep.h
+++ b/sys/i386/include/intr_machdep.h
@@ -58,13 +58,7 @@
(FIRST_MSI_INT + NUM_MSI_INTS)
#define LAST_EVTCHN_INT \
(FIRST_EVTCHN_INT + NUM_EVTCHN_INTS - 1)
-#elif defined(XEN)
-#include <xen/xen-os.h>
-#define NUM_EVTCHN_INTS NR_EVENT_CHANNELS
-#define FIRST_EVTCHN_INT 0
-#define LAST_EVTCHN_INT \
- (FIRST_EVTCHN_INT + NUM_EVTCHN_INTS - 1)
-#else /* !XEN && !XENHVM */
+#else /* !XENHVM */
#define NUM_EVTCHN_INTS 0
#endif
#define NUM_IO_INTS (FIRST_MSI_INT + NUM_MSI_INTS + NUM_EVTCHN_INTS)
diff --git a/sys/i386/include/md_var.h b/sys/i386/include/md_var.h
index 339dff3..bffdd57 100644
--- a/sys/i386/include/md_var.h
+++ b/sys/i386/include/md_var.h
@@ -97,6 +97,7 @@ struct dumperinfo;
void *alloc_fpusave(int flags);
void bcopyb(const void *from, void *to, size_t len);
void busdma_swi(void);
+void cpu_probe_amdc1e(void);
void cpu_setregs(void);
void cpu_switch_load_gs(void) __asm(__STRING(cpu_switch_load_gs));
void doreti_iret(void) __asm(__STRING(doreti_iret));
diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h
index d7148ae..54477c1 100644
--- a/sys/i386/include/param.h
+++ b/sys/i386/include/param.h
@@ -90,7 +90,7 @@
#define PAGE_MASK (PAGE_SIZE-1)
#define NPTEPG (PAGE_SIZE/(sizeof (pt_entry_t)))
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
#define NPGPTD 4
#define PDRSHIFT 21 /* LOG2(NBPDR) */
#define NPGPTD_SHIFT 9
diff --git a/sys/i386/include/pcpu.h b/sys/i386/include/pcpu.h
index dc29b6d..231f80f 100644
--- a/sys/i386/include/pcpu.h
+++ b/sys/i386/include/pcpu.h
@@ -44,34 +44,6 @@
* other processors"
*/
-#if defined(XEN)
-
-/* These are peridically updated in shared_info, and then copied here. */
-struct shadow_time_info {
- uint64_t tsc_timestamp; /* TSC at last update of time vals. */
- uint64_t system_timestamp; /* Time, in nanosecs, since boot. */
- uint32_t tsc_to_nsec_mul;
- uint32_t tsc_to_usec_mul;
- int tsc_shift;
- uint32_t version;
-};
-
-#define PCPU_XEN_FIELDS \
- ; \
- u_int pc_cr3; /* track cr3 for R1/R3*/ \
- vm_paddr_t *pc_pdir_shadow; \
- uint64_t pc_processed_system_time; \
- struct shadow_time_info pc_shadow_time; \
- char __pad[185]
-
-#else /* !XEN */
-
-#define PCPU_XEN_FIELDS \
- ; \
- char __pad[233]
-
-#endif
-
#define PCPU_MD_FIELDS \
char pc_monitorbuf[128] __aligned(128); /* cache line */ \
struct pcpu *pc_prvspace; /* Self-reference */ \
@@ -85,8 +57,8 @@ struct shadow_time_info {
u_int pc_apic_id; \
int pc_private_tss; /* Flag indicating private tss*/\
u_int pc_cmci_mask; /* MCx banks for CMCI */ \
- u_int pc_vcpu_id /* Xen vCPU ID */ \
- PCPU_XEN_FIELDS
+ u_int pc_vcpu_id; /* Xen vCPU ID */ \
+ char __pad[233]
#ifdef _KERNEL
diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h
index 05656cd..76822b1 100644
--- a/sys/i386/include/pmap.h
+++ b/sys/i386/include/pmap.h
@@ -63,7 +63,7 @@
#define PG_AVAIL2 0x400 /* < programmers use */
#define PG_AVAIL3 0x800 /* \ */
#define PG_PDE_PAT 0x1000 /* PAT PAT index */
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
#define PG_NX (1ull<<63) /* No-execute */
#endif
@@ -71,7 +71,7 @@
/* Our various interpretations of the above */
#define PG_W PG_AVAIL1 /* "Wired" pseudoflag */
#define PG_MANAGED PG_AVAIL2
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
#define PG_FRAME (0x000ffffffffff000ull)
#define PG_PS_FRAME (0x000fffffffe00000ull)
#else
@@ -110,7 +110,7 @@
* is 1 Gigabyte. Double everything. It must be a multiple of 8 for PAE.
*/
#ifndef KVA_PAGES
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
#define KVA_PAGES 512
#else
#define KVA_PAGES 256
@@ -122,13 +122,21 @@
*/
#define VADDR(pdi, pti) ((vm_offset_t)(((pdi)<<PDRSHIFT)|((pti)<<PAGE_SHIFT)))
-/* Initial number of kernel page tables. */
+/*
+ * The initial number of kernel page table pages that are constructed
+ * by locore must be sufficient to map vm_page_array. That number can
+ * be calculated as follows:
+ * max_phys / PAGE_SIZE * sizeof(struct vm_page) / NBPDR
+ * PAE: max_phys 16G, sizeof(vm_page) 76, NBPDR 2M, 152 page table pages.
+ * PAE_TABLES: max_phys 4G, sizeof(vm_page) 68, NBPDR 2M, 36 page table pages.
+ * Non-PAE: max_phys 4G, sizeof(vm_page) 68, NBPDR 4M, 18 page table pages.
+ */
#ifndef NKPT
-#ifdef PAE
-/* 152 page tables needed to map 16G (76B "struct vm_page", 2M page tables). */
+#if defined(PAE)
#define NKPT 240
+#elif defined(PAE_TABLES)
+#define NKPT 60
#else
-/* 18 page tables needed to map 4G (72B "struct vm_page", 4M page tables). */
#define NKPT 30
#endif
#endif
@@ -161,7 +169,7 @@
#include <vm/_vm_radix.h>
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
typedef uint64_t pdpt_entry_t;
typedef uint64_t pd_entry_t;
@@ -188,7 +196,7 @@ extern pt_entry_t PTmap[];
extern pd_entry_t PTD[];
extern pd_entry_t PTDpde[];
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
extern pdpt_entry_t *IdlePDPT;
#endif
extern pd_entry_t *IdlePTD; /* physical address of "Idle" state directory */
@@ -211,76 +219,6 @@ extern pd_entry_t *IdlePTD; /* physical address of "Idle" state directory */
*/
#define vtophys(va) pmap_kextract((vm_offset_t)(va))
-#if defined(XEN)
-#include <sys/param.h>
-
-#include <xen/xen-os.h>
-
-#include <machine/xen/xenvar.h>
-#include <machine/xen/xenpmap.h>
-
-extern pt_entry_t pg_nx;
-
-#define PG_KERNEL (PG_V | PG_A | PG_RW | PG_M)
-
-#define MACH_TO_VM_PAGE(ma) PHYS_TO_VM_PAGE(xpmap_mtop((ma)))
-#define VM_PAGE_TO_MACH(m) xpmap_ptom(VM_PAGE_TO_PHYS((m)))
-
-#define VTOM(va) xpmap_ptom(VTOP(va))
-
-static __inline vm_paddr_t
-pmap_kextract_ma(vm_offset_t va)
-{
- vm_paddr_t ma;
- if ((ma = PTD[va >> PDRSHIFT]) & PG_PS) {
- ma = (ma & ~(NBPDR - 1)) | (va & (NBPDR - 1));
- } else {
- ma = (*vtopte(va) & PG_FRAME) | (va & PAGE_MASK);
- }
- return ma;
-}
-
-static __inline vm_paddr_t
-pmap_kextract(vm_offset_t va)
-{
- return xpmap_mtop(pmap_kextract_ma(va));
-}
-#define vtomach(va) pmap_kextract_ma(((vm_offset_t) (va)))
-
-vm_paddr_t pmap_extract_ma(struct pmap *pmap, vm_offset_t va);
-
-void pmap_kenter_ma(vm_offset_t va, vm_paddr_t pa);
-void pmap_map_readonly(struct pmap *pmap, vm_offset_t va, int len);
-void pmap_map_readwrite(struct pmap *pmap, vm_offset_t va, int len);
-
-static __inline pt_entry_t
-pte_load_store(pt_entry_t *ptep, pt_entry_t v)
-{
- pt_entry_t r;
-
- r = *ptep;
- PT_SET_VA(ptep, v, TRUE);
- return (r);
-}
-
-static __inline pt_entry_t
-pte_load_store_ma(pt_entry_t *ptep, pt_entry_t v)
-{
- pt_entry_t r;
-
- r = *ptep;
- PT_SET_VA_MA(ptep, v, TRUE);
- return (r);
-}
-
-#define pte_load_clear(ptep) pte_load_store((ptep), (pt_entry_t)0ULL)
-
-#define pte_store(ptep, pte) pte_load_store((ptep), (pt_entry_t)pte)
-#define pte_store_ma(ptep, pte) pte_load_store_ma((ptep), (pt_entry_t)pte)
-#define pde_store_ma(ptep, pte) pte_load_store_ma((ptep), (pt_entry_t)pte)
-
-#elif !defined(XEN)
-
/*
* KPTmap is a linear mapping of the kernel page table. It differs from the
* recursive mapping in two ways: (1) it only provides access to kernel page
@@ -320,13 +258,8 @@ pmap_kextract(vm_offset_t va)
}
return (pa);
}
-#endif
-
-#if !defined(XEN)
-#define PT_UPDATES_FLUSH()
-#endif
-#if defined(PAE) && !defined(XEN)
+#if (defined(PAE) || defined(PAE_TABLES))
#define pde_cmpset(pdep, old, new) atomic_cmpset_64_i586(pdep, old, new)
#define pte_load_store(ptep, pte) atomic_swap_64_i586(ptep, pte)
@@ -335,7 +268,7 @@ pmap_kextract(vm_offset_t va)
extern pt_entry_t pg_nx;
-#elif !defined(PAE) && !defined(XEN)
+#else /* !(PAE || PAE_TABLES) */
#define pde_cmpset(pdep, old, new) atomic_cmpset_int(pdep, old, new)
#define pte_load_store(ptep, pte) atomic_swap_int(ptep, pte)
@@ -344,7 +277,7 @@ extern pt_entry_t pg_nx;
*(u_int *)(ptep) = (u_int)(pte); \
} while (0)
-#endif /* PAE */
+#endif /* !(PAE || PAE_TABLES) */
#define pte_clear(ptep) pte_store(ptep, 0)
@@ -370,8 +303,8 @@ struct pmap {
cpuset_t pm_active; /* active on cpus */
struct pmap_statistics pm_stats; /* pmap statistics */
LIST_ENTRY(pmap) pm_list; /* List of all pmaps */
-#ifdef PAE
- pdpt_entry_t *pm_pdpt; /* KVA of page director pointer
+#if defined(PAE) || defined(PAE_TABLES)
+ pdpt_entry_t *pm_pdpt; /* KVA of page directory pointer
table */
#endif
struct vm_radix pm_root; /* spare page table pages */
diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h
index d67f2e0..635dffc 100644
--- a/sys/i386/include/segments.h
+++ b/sys/i386/include/segments.h
@@ -82,14 +82,8 @@ struct region_descriptor {
#ifdef _KERNEL
extern int _default_ldt;
-#ifdef XEN
-extern struct proc_ldt default_proc_ldt;
-extern union descriptor *gdt;
-extern union descriptor *ldt;
-#else
extern union descriptor gdt[];
extern union descriptor ldt[NLDT];
-#endif
extern struct soft_segment_descriptor gdt_segs[];
extern struct gate_descriptor *idt;
extern struct region_descriptor r_gdt, r_idt;
diff --git a/sys/i386/include/smp.h b/sys/i386/include/smp.h
index cc9a8ea..71c830e 100644
--- a/sys/i386/include/smp.h
+++ b/sys/i386/include/smp.h
@@ -36,13 +36,43 @@ extern int mp_naps;
extern int boot_cpu_id;
extern struct pcb stoppcbs[];
extern int cpu_apic_ids[];
+extern int bootAP;
+extern void *dpcpu;
+extern char *bootSTK;
+extern int bootAP;
+extern void *bootstacks[];
+extern volatile u_int cpu_ipi_pending[];
+extern volatile int aps_ready;
+extern struct mtx ap_boot_mtx;
+extern int cpu_logical;
+extern int cpu_cores;
+extern volatile int smp_tlb_wait;
+extern u_int xhits_gbl[];
+extern u_int xhits_pg[];
+extern u_int xhits_rng[];
+extern u_int ipi_global;
+extern u_int ipi_page;
+extern u_int ipi_range;
+extern u_int ipi_range_size;
+extern u_int ipi_masked_global;
+extern u_int ipi_masked_page;
+extern u_int ipi_masked_range;
+extern u_int ipi_masked_range_size;
+
+struct cpu_info {
+ int cpu_present:1;
+ int cpu_bsp:1;
+ int cpu_disabled:1;
+ int cpu_hyperthread:1;
+};
+extern struct cpu_info cpu_info[];
+
#ifdef COUNT_IPIS
extern u_long *ipi_invltlb_counts[MAXCPU];
extern u_long *ipi_invlrng_counts[MAXCPU];
extern u_long *ipi_invlpg_counts[MAXCPU];
extern u_long *ipi_invlcache_counts[MAXCPU];
extern u_long *ipi_rendezvous_counts[MAXCPU];
-extern u_long *ipi_lazypmap_counts[MAXCPU];
#endif
/* IPI handlers */
@@ -54,15 +84,14 @@ inthand_t
IDTVEC(ipi_intr_bitmap_handler), /* Bitmap based IPIs */
IDTVEC(cpustop), /* CPU stops & waits to be restarted */
IDTVEC(cpususpend), /* CPU suspends & waits to be resumed */
- IDTVEC(rendezvous), /* handle CPU rendezvous */
- IDTVEC(lazypmap); /* handle lazy pmap release */
+ IDTVEC(rendezvous); /* handle CPU rendezvous */
/* functions in mp_machdep.c */
+void assign_cpu_ids(void);
void cpu_add(u_int apic_id, char boot_cpu);
void cpustop_handler(void);
-#ifndef XEN
void cpususpend_handler(void);
-#endif
+void init_secondary_tail(void);
void invltlb_handler(void);
void invlpg_handler(void);
void invlrng_handler(void);
@@ -70,13 +99,12 @@ void invlcache_handler(void);
void init_secondary(void);
void ipi_startup(int apic_id, int vector);
void ipi_all_but_self(u_int ipi);
-#ifndef XEN
void ipi_bitmap_handler(struct trapframe frame);
-#endif
void ipi_cpu(int cpu, u_int ipi);
int ipi_nmi_handler(void);
void ipi_selected(cpuset_t cpus, u_int ipi);
u_int mp_bootaddress(u_int);
+void set_interrupt_apic_ids(void);
void smp_cache_flush(void);
void smp_invlpg(vm_offset_t addr);
void smp_masked_invlpg(cpuset_t mask, vm_offset_t addr);
@@ -85,10 +113,10 @@ void smp_masked_invlpg_range(cpuset_t mask, vm_offset_t startva,
vm_offset_t endva);
void smp_invltlb(void);
void smp_masked_invltlb(cpuset_t mask);
+void mem_range_AP_init(void);
+void topo_probe(void);
+void ipi_send_cpu(int cpu, u_int ipi);
-#ifdef XEN
-void ipi_to_irq_init(void);
-#endif
#endif /* !LOCORE */
#endif /* SMP */
diff --git a/sys/i386/include/vm.h b/sys/i386/include/vm.h
index 6573e37..22d2eca 100644
--- a/sys/i386/include/vm.h
+++ b/sys/i386/include/vm.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/i386/include/vmparam.h b/sys/i386/include/vmparam.h
index 5dc5669..cb23b05 100644
--- a/sys/i386/include/vmparam.h
+++ b/sys/i386/include/vmparam.h
@@ -120,11 +120,11 @@
#endif
/*
- * Level 0 reservations consist of 512 pages under PAE and 1024 pages
- * otherwise.
+ * Level 0 reservations consist of 512 pages when PAE pagetables are
+ * used, and 1024 pages otherwise.
*/
#ifndef VM_LEVEL_0_ORDER
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
#define VM_LEVEL_0_ORDER 9
#else
#define VM_LEVEL_0_ORDER 10
@@ -135,11 +135,7 @@
* Kernel physical load address.
*/
#ifndef KERNLOAD
-#if defined(XEN) && !defined(XEN_PRIVILEGED_GUEST)
-#define KERNLOAD 0
-#else
#define KERNLOAD (1 << PDRSHIFT)
-#endif
#endif /* !defined(KERNLOAD) */
/*
@@ -149,11 +145,7 @@
* messy at times, but hey, we'll do anything to save a page :-)
*/
-#ifdef XEN
-#define VM_MAX_KERNEL_ADDRESS HYPERVISOR_VIRT_START
-#else
#define VM_MAX_KERNEL_ADDRESS VADDR(KPTDI+NKPDE-1, NPTEPG-1)
-#endif
#define VM_MIN_KERNEL_ADDRESS VADDR(PTDPTDI, PTDPTDI)
diff --git a/sys/i386/include/xen/features.h b/sys/i386/include/xen/features.h
deleted file mode 100644
index fb4f680..0000000
--- a/sys/i386/include/xen/features.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/******************************************************************************
- * features.h
- *
- * Query the features reported by Xen.
- *
- * Copyright (c) 2006, Ian Campbell
- *
- * $FreeBSD$
- */
-
-#ifndef __ASM_XEN_FEATURES_H__
-#define __ASM_XEN_FEATURES_H__
-
-#include <xen/interface/version.h>
-
-extern void setup_xen_features(void);
-
-extern uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32];
-
-#define xen_feature(flag) (xen_features[flag])
-
-#endif /* __ASM_XEN_FEATURES_H__ */
diff --git a/sys/i386/include/xen/hypercall.h b/sys/i386/include/xen/hypercall.h
index c7e2a00..1c4d529 100644
--- a/sys/i386/include/xen/hypercall.h
+++ b/sys/i386/include/xen/hypercall.h
@@ -246,14 +246,8 @@ HYPERVISOR_memory_op(
return _hypercall2(int, memory_op, cmd, arg);
}
-#if defined(XEN)
-int HYPERVISOR_multicall(multicall_entry_t *, int);
-static inline int
-_HYPERVISOR_multicall(
-#else /* XENHVM */
static inline int
HYPERVISOR_multicall(
-#endif
void *call_list, int nr_calls)
{
return _hypercall2(int, multicall, call_list, nr_calls);
diff --git a/sys/i386/include/xen/xen-os.h b/sys/i386/include/xen/xen-os.h
index 3d1ef04..9b9b63f 100644
--- a/sys/i386/include/xen/xen-os.h
+++ b/sys/i386/include/xen/xen-os.h
@@ -44,105 +44,6 @@ static inline void rep_nop(void)
}
#define cpu_relax() rep_nop()
-#ifndef XENHVM
-
-#ifdef SMP
-extern int gdtset;
-
-#include <sys/time.h> /* XXX for pcpu.h */
-#include <sys/pcpu.h> /* XXX for PCPU_GET */
-static inline int
-smp_processor_id(void)
-{
- if (__predict_true(gdtset))
- return PCPU_GET(cpuid);
- return 0;
-}
-
-#else
-#define smp_processor_id() 0
-#endif
-
-#ifndef PANIC_IF
-#define PANIC_IF(exp) if (__predict_false(exp)) {printf("panic - %s: %s:%d\n",#exp, __FILE__, __LINE__); panic("%s: %s:%d", #exp, __FILE__, __LINE__);}
-#endif
-
-/*
- * Crude memory allocator for memory allocation early in boot.
- */
-void *bootmem_alloc(unsigned int size);
-void bootmem_free(void *ptr, unsigned int size);
-
-/*
- * STI/CLI equivalents. These basically set and clear the virtual
- * event_enable flag in the shared_info structure. Note that when
- * the enable bit is set, there may be pending events to be handled.
- * We may therefore call into do_hypervisor_callback() directly.
- */
-
-#define __cli() \
-do { \
- vcpu_info_t *_vcpu; \
- _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
- _vcpu->evtchn_upcall_mask = 1; \
- barrier(); \
-} while (0)
-
-#define __sti() \
-do { \
- vcpu_info_t *_vcpu; \
- barrier(); \
- _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
- _vcpu->evtchn_upcall_mask = 0; \
- barrier(); /* unmask then check (avoid races) */ \
- if (__predict_false(_vcpu->evtchn_upcall_pending)) \
- force_evtchn_callback(); \
-} while (0)
-
-#define __restore_flags(x) \
-do { \
- vcpu_info_t *_vcpu; \
- barrier(); \
- _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
- if ((_vcpu->evtchn_upcall_mask = (x)) == 0) { \
- barrier(); /* unmask then check (avoid races) */ \
- if (__predict_false(_vcpu->evtchn_upcall_pending)) \
- force_evtchn_callback(); \
- } \
-} while (0)
-
-/*
- * Add critical_{enter, exit}?
- *
- */
-#define __save_and_cli(x) \
-do { \
- vcpu_info_t *_vcpu; \
- _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
- (x) = _vcpu->evtchn_upcall_mask; \
- _vcpu->evtchn_upcall_mask = 1; \
- barrier(); \
-} while (0)
-
-
-#define cli() __cli()
-#define sti() __sti()
-#define save_flags(x) __save_flags(x)
-#define restore_flags(x) __restore_flags(x)
-#define save_and_cli(x) __save_and_cli(x)
-
-#define local_irq_save(x) __save_and_cli(x)
-#define local_irq_restore(x) __restore_flags(x)
-#define local_irq_disable() __cli()
-#define local_irq_enable() __sti()
-
-#define mtx_lock_irqsave(lock, x) {local_irq_save((x)); mtx_lock_spin((lock));}
-#define mtx_unlock_irqrestore(lock, x) {mtx_unlock_spin((lock)); local_irq_restore((x)); }
-#define spin_lock_irqsave mtx_lock_irqsave
-#define spin_unlock_irqrestore mtx_unlock_irqrestore
-
-#endif /* !XENHVM */
-
/* This is a barrier for the compiler only, NOT the processor! */
#define barrier() __asm__ __volatile__("": : :"memory")
diff --git a/sys/i386/include/xen/xenfunc.h b/sys/i386/include/xen/xenfunc.h
index f02ee12..f48b1f1 100644
--- a/sys/i386/include/xen/xenfunc.h
+++ b/sys/i386/include/xen/xenfunc.h
@@ -34,7 +34,6 @@
#include <vm/pmap.h>
-#include <machine/xen/xenpmap.h>
#include <machine/segments.h>
#include <sys/pcpu.h>
diff --git a/sys/i386/include/xen/xenpmap.h b/sys/i386/include/xen/xenpmap.h
deleted file mode 100644
index 8287e72..0000000
--- a/sys/i386/include/xen/xenpmap.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- *
- * Copyright (c) 2004 Christian Limpach.
- * Copyright (c) 2004,2005 Kip Macy
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Christian Limpach.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * $FreeBSD$
- */
-
-#ifndef _XEN_XENPMAP_H_
-#define _XEN_XENPMAP_H_
-
-#if defined(XEN)
-void _xen_queue_pt_update(vm_paddr_t, vm_paddr_t, char *, int);
-void xen_pt_switch(vm_paddr_t);
-void xen_set_ldt(vm_paddr_t, unsigned long);
-void xen_pgdpt_pin(vm_paddr_t);
-void xen_pgd_pin(vm_paddr_t);
-void xen_pgd_unpin(vm_paddr_t);
-void xen_pt_pin(vm_paddr_t);
-void xen_pt_unpin(vm_paddr_t);
-void xen_flush_queue(void);
-void pmap_ref(pt_entry_t *pte, vm_paddr_t ma);
-void pmap_suspend(void);
-void pmap_resume(void);
-void xen_check_queue(void);
-
-#ifdef INVARIANTS
-#define xen_queue_pt_update(a, b) _xen_queue_pt_update((a), (b), __FILE__, __LINE__)
-#else
-#define xen_queue_pt_update(a, b) _xen_queue_pt_update((a), (b), NULL, 0)
-#endif
-
-
-#include <sys/param.h>
-#include <sys/pcpu.h>
-
-#ifdef PMAP_DEBUG
-#define PMAP_REF pmap_ref
-#define PMAP_DEC_REF_PAGE pmap_dec_ref_page
-#define PMAP_MARK_PRIV pmap_mark_privileged
-#define PMAP_MARK_UNPRIV pmap_mark_unprivileged
-#else
-#define PMAP_MARK_PRIV(a)
-#define PMAP_MARK_UNPRIV(a)
-#define PMAP_REF(a, b)
-#define PMAP_DEC_REF_PAGE(a)
-#endif
-
-#define ALWAYS_SYNC 0
-
-#ifdef PT_DEBUG
-#define PT_LOG() printk("WP PT_SET %s:%d\n", __FILE__, __LINE__)
-#else
-#define PT_LOG()
-#endif
-
-#define INVALID_P2M_ENTRY (~0UL)
-
-#define pmap_valid_entry(E) ((E) & PG_V) /* is PDE or PTE valid? */
-
-#define SH_PD_SET_VA 1
-#define SH_PD_SET_VA_MA 2
-#define SH_PD_SET_VA_CLEAR 3
-
-struct pmap;
-void pd_set(struct pmap *pmap, int ptepindex, vm_paddr_t val, int type);
-#ifdef notyet
-static vm_paddr_t
-vptetomachpte(vm_paddr_t *pte)
-{
- vm_offset_t offset, ppte;
- vm_paddr_t pgoffset, retval, *pdir_shadow_ptr;
- int pgindex;
-
- ppte = (vm_offset_t)pte;
- pgoffset = (ppte & PAGE_MASK);
- offset = ppte - (vm_offset_t)PTmap;
- pgindex = ppte >> PDRSHIFT;
-
- pdir_shadow_ptr = (vm_paddr_t *)PCPU_GET(pdir_shadow);
- retval = (pdir_shadow_ptr[pgindex] & ~PAGE_MASK) + pgoffset;
- return (retval);
-}
-#endif
-#define PT_GET(_ptp) \
- (pmap_valid_entry(*(_ptp)) ? xpmap_mtop(*(_ptp)) : (0))
-
-#ifdef WRITABLE_PAGETABLES
-
-#define PT_SET_VA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- PT_LOG(); \
- *(_ptp) = xpmap_ptom((_npte)); \
-} while (/*CONSTCOND*/0)
-#define PT_SET_VA_MA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- PT_LOG(); \
- *(_ptp) = (_npte); \
-} while (/*CONSTCOND*/0)
-#define PT_CLEAR_VA(_ptp, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- PT_LOG(); \
- *(_ptp) = 0; \
-} while (/*CONSTCOND*/0)
-
-#define PD_SET_VA(_pmap, _ptp, _npte, sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- pd_set((_pmap),(_ptp),(_npte), SH_PD_SET_VA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_SET_VA_MA(_pmap, _ptp, _npte, sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- pd_set((_pmap),(_ptp),(_npte), SH_PD_SET_VA_MA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_CLEAR_VA(_pmap, _ptp, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- pd_set((_pmap),(_ptp), 0, SH_PD_SET_VA_CLEAR); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-#else /* !WRITABLE_PAGETABLES */
-
-#define PT_SET_VA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- xen_queue_pt_update(vtomach(_ptp), \
- xpmap_ptom(_npte)); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PT_SET_VA_MA(_ptp,_npte,sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- xen_queue_pt_update(vtomach(_ptp), _npte); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PT_CLEAR_VA(_ptp, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- xen_queue_pt_update(vtomach(_ptp), 0); \
- if (sync || ALWAYS_SYNC) \
- xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-#define PD_SET_VA(_pmap, _ptepindex,_npte,sync) do { \
- PMAP_REF((_ptp), xpmap_ptom(_npte)); \
- pd_set((_pmap),(_ptepindex),(_npte), SH_PD_SET_VA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_SET_VA_MA(_pmap, _ptepindex,_npte,sync) do { \
- PMAP_REF((_ptp), (_npte)); \
- pd_set((_pmap),(_ptepindex),(_npte), SH_PD_SET_VA_MA); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-#define PD_CLEAR_VA(_pmap, _ptepindex, sync) do { \
- PMAP_REF((pt_entry_t *)(_ptp), 0); \
- pd_set((_pmap),(_ptepindex), 0, SH_PD_SET_VA_CLEAR); \
- if (sync || ALWAYS_SYNC) xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-#endif
-
-#define PT_SET_MA(_va, _ma) \
-do { \
- PANIC_IF(HYPERVISOR_update_va_mapping(((unsigned long)(_va)),\
- (_ma), \
- UVMF_INVLPG| UVMF_ALL) < 0); \
-} while (/*CONSTCOND*/0)
-
-#define PT_UPDATES_FLUSH() do { \
- xen_flush_queue(); \
-} while (/*CONSTCOND*/0)
-
-static __inline vm_paddr_t
-xpmap_mtop(vm_paddr_t mpa)
-{
- vm_paddr_t tmp = (mpa & PG_FRAME);
-
- return machtophys(tmp) | (mpa & ~PG_FRAME);
-}
-
-static __inline vm_paddr_t
-xpmap_ptom(vm_paddr_t ppa)
-{
- vm_paddr_t tmp = (ppa & PG_FRAME);
-
- return phystomach(tmp) | (ppa & ~PG_FRAME);
-}
-
-static __inline void
-set_phys_to_machine(unsigned long pfn, unsigned long mfn)
-{
-#ifdef notyet
- PANIC_IF(max_mapnr && pfn >= max_mapnr);
-#endif
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
-#ifdef notyet
- PANIC_IF((pfn != mfn && mfn != INVALID_P2M_ENTRY));
-#endif
- return;
- }
- xen_phys_machine[pfn] = mfn;
-}
-
-static __inline int
-phys_to_machine_mapping_valid(unsigned long pfn)
-{
- return xen_phys_machine[pfn] != INVALID_P2M_ENTRY;
-}
-
-#endif /* !XEN */
-
-#endif /* _XEN_XENPMAP_H_ */
diff --git a/sys/i386/include/xen/xenstored.h b/sys/i386/include/xen/xenstored.h
deleted file mode 100644
index e584fa5..0000000
--- a/sys/i386/include/xen/xenstored.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Simple prototyle Xen Store Daemon providing simple tree-like database.
- * Copyright (C) 2005 Rusty Russell IBM Corporation
- *
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef _XENSTORED_H
-#define _XENSTORED_H
-
-enum xsd_sockmsg_type
-{
- XS_DEBUG,
- XS_SHUTDOWN,
- XS_DIRECTORY,
- XS_READ,
- XS_GET_PERMS,
- XS_WATCH,
- XS_WATCH_ACK,
- XS_UNWATCH,
- XS_TRANSACTION_START,
- XS_TRANSACTION_END,
- XS_OP_READ_ONLY = XS_TRANSACTION_END,
- XS_INTRODUCE,
- XS_RELEASE,
- XS_GETDOMAINPATH,
- XS_WRITE,
- XS_MKDIR,
- XS_RM,
- XS_SET_PERMS,
- XS_WATCH_EVENT,
- XS_ERROR,
-};
-
-#define XS_WRITE_NONE "NONE"
-#define XS_WRITE_CREATE "CREATE"
-#define XS_WRITE_CREATE_EXCL "CREATE|EXCL"
-
-/* We hand errors as strings, for portability. */
-struct xsd_errors
-{
- int errnum;
- const char *errstring;
-};
-#define XSD_ERROR(x) { x, #x }
-static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
- XSD_ERROR(EINVAL),
- XSD_ERROR(EACCES),
- XSD_ERROR(EEXIST),
- XSD_ERROR(EISDIR),
- XSD_ERROR(ENOENT),
- XSD_ERROR(ENOMEM),
- XSD_ERROR(ENOSPC),
- XSD_ERROR(EIO),
- XSD_ERROR(ENOTEMPTY),
- XSD_ERROR(ENOSYS),
- XSD_ERROR(EROFS),
- XSD_ERROR(EBUSY),
- XSD_ERROR(ETIMEDOUT),
- XSD_ERROR(EISCONN),
-};
-struct xsd_sockmsg
-{
- uint32_t type;
- uint32_t len; /* Length of data following this. */
-
- /* Generally followed by nul-terminated string(s). */
-};
-
-#endif /* _XENSTORED_H */
diff --git a/sys/i386/include/xen/xenvar.h b/sys/i386/include/xen/xenvar.h
index 5694607..484c279 100644
--- a/sys/i386/include/xen/xenvar.h
+++ b/sys/i386/include/xen/xenvar.h
@@ -29,91 +29,8 @@
#ifndef XENVAR_H_
#define XENVAR_H_
-#include <machine/xen/features.h>
-
-#if defined(XEN)
-
-#define XBOOTUP 0x1
-#define XPMAP 0x2
-extern int xendebug_flags;
-#ifndef NOXENDEBUG
-/* Print directly to the Xen console during debugging. */
-#define XENPRINTF xc_printf
-#else
-#define XENPRINTF printf
-#endif
-
-extern xen_pfn_t *xen_phys_machine;
-extern xen_pfn_t *xen_pfn_to_mfn_frame_list[16];
-extern xen_pfn_t *xen_pfn_to_mfn_frame_list_list;
-
-#if 0
-#define TRACE_ENTER XENPRINTF("(file=%s, line=%d) entered %s\n", __FILE__, __LINE__, __FUNCTION__)
-#define TRACE_EXIT XENPRINTF("(file=%s, line=%d) exiting %s\n", __FILE__, __LINE__, __FUNCTION__)
-#define TRACE_DEBUG(argflags, _f, _a...) \
-if (xendebug_flags & argflags) XENPRINTF("(file=%s, line=%d) " _f "\n", __FILE__, __LINE__, ## _a);
-#else
-#define TRACE_ENTER
-#define TRACE_EXIT
-#define TRACE_DEBUG(argflags, _f, _a...)
-#endif
-
-extern xen_pfn_t *xen_machine_phys;
-/* Xen starts physical pages after the 4MB ISA hole -
- * FreeBSD doesn't
- */
-
-
-#undef ADD_ISA_HOLE /* XXX */
-
-#ifdef ADD_ISA_HOLE
-#define ISA_INDEX_OFFSET 1024
-#define ISA_PDR_OFFSET 1
-#else
-#define ISA_INDEX_OFFSET 0
-#define ISA_PDR_OFFSET 0
-#endif
-
-
-#define PFNTOMFN(i) (xen_phys_machine[(i)])
-#define MFNTOPFN(i) ((vm_paddr_t)xen_machine_phys[(i)])
-
-#define VTOP(x) ((((uintptr_t)(x))) - KERNBASE)
-#define PTOV(x) (((uintptr_t)(x)) + KERNBASE)
-
-#define VTOPFN(x) (VTOP(x) >> PAGE_SHIFT)
-#define PFNTOV(x) PTOV((vm_paddr_t)(x) << PAGE_SHIFT)
-
-#define VTOMFN(va) (vtomach(va) >> PAGE_SHIFT)
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-
-#define phystomach(pa) (((vm_paddr_t)(PFNTOMFN((pa) >> PAGE_SHIFT))) << PAGE_SHIFT)
-#define machtophys(ma) (((vm_paddr_t)(MFNTOPFN((ma) >> PAGE_SHIFT))) << PAGE_SHIFT)
-
-
-void xpq_init(void);
-
-#define BITS_PER_LONG 32
-#define NR_CPUS XEN_LEGACY_MAX_VCPUS
-
-#define BITS_TO_LONGS(bits) \
- (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
-#define DECLARE_BITMAP(name,bits) \
- unsigned long name[BITS_TO_LONGS(bits)]
-
-int xen_create_contiguous_region(vm_page_t pages, int npages);
-
-void xen_destroy_contiguous_region(void * addr, int npages);
-
-#elif defined(XENHVM)
+#include <xen/features.h>
#define vtomach(va) pmap_kextract((vm_offset_t) (va))
-#define PFNTOMFN(pa) (pa)
-#define MFNTOPFN(ma) (ma)
-
-#define set_phys_to_machine(pfn, mfn) ((void)0)
-#define phys_to_machine_mapping_valid(pfn) (TRUE)
-
-#endif /* !XEN && !XENHVM */
#endif
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index b0ea4e7..a7113e2 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -69,10 +69,6 @@ __FBSDID("$FreeBSD$");
#include <machine/ucontext.h>
#include <machine/intr_machdep.h>
-#ifdef XEN
-#include <xen/xen-os.h>
-#include <xen/hypervisor.h>
-#endif
#ifdef DEV_ISA
#include <isa/isavar.h>
@@ -157,13 +153,8 @@ void xsaveopt(char *addr, uint64_t mask);
#endif /* __GNUCLIKE_ASM && !lint */
-#ifdef XEN
-#define start_emulating() (HYPERVISOR_fpu_taskswitch(1))
-#define stop_emulating() (HYPERVISOR_fpu_taskswitch(0))
-#else
#define start_emulating() load_cr0(rcr0() | CR0_TS)
#define stop_emulating() clts()
-#endif
#ifdef CPU_ENABLE_SSE
#define GET_FPU_CW(thread) \
diff --git a/sys/i386/pci/pci_cfgreg.c b/sys/i386/pci/pci_cfgreg.c
index 5d57e89..2716a7a 100644
--- a/sys/i386/pci/pci_cfgreg.c
+++ b/sys/i386/pci/pci_cfgreg.c
@@ -93,9 +93,7 @@ static uint32_t pci_docfgregread(int bus, int slot, int func, int reg,
int bytes);
static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
-#ifndef XEN
static int pcireg_cfgopen(void);
-#endif
static int pciereg_cfgread(int bus, unsigned slot, unsigned func,
unsigned reg, unsigned bytes);
static void pciereg_cfgwrite(int bus, unsigned slot, unsigned func,
@@ -116,7 +114,6 @@ pci_i386_map_intline(int line)
return (line);
}
-#ifndef XEN
static u_int16_t
pcibios_get_version(void)
{
@@ -137,7 +134,6 @@ pcibios_get_version(void)
}
return (args.ebx & 0xffff);
}
-#endif
/*
* Initialise access to PCI configuration space
@@ -145,9 +141,6 @@ pcibios_get_version(void)
int
pci_cfgregopen(void)
{
-#ifdef XEN
- return (0);
-#else
static int opened = 0;
uint64_t pciebar;
u_int16_t vid, did;
@@ -202,7 +195,6 @@ pci_cfgregopen(void)
}
return(1);
-#endif
}
static uint32_t
@@ -390,7 +382,6 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
mtx_unlock_spin(&pcicfg_mtx);
}
-#ifndef XEN
/* check whether the configuration mechanism has been correctly identified */
static int
pci_cfgcheck(int maxdev)
@@ -607,7 +598,6 @@ pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus)
return (1);
}
-#endif /* !XEN */
#define PCIE_PADDR(base, reg, bus, slot, func) \
((base) + \
diff --git a/sys/i386/pci/pci_pir.c b/sys/i386/pci/pci_pir.c
index 0d64cab..6aeaae3 100644
--- a/sys/i386/pci/pci_pir.c
+++ b/sys/i386/pci/pci_pir.c
@@ -137,9 +137,6 @@ pci_pir_open(void)
int i;
uint8_t ck, *cv;
-#ifdef XEN
- return;
-#else
/* Don't try if we've already found a table. */
if (pci_route_table != NULL)
return;
@@ -150,7 +147,7 @@ pci_pir_open(void)
sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
if (sigaddr == 0)
return;
-#endif
+
/* If we found something, check the checksum and length. */
/* XXX - Use pmap_mapdev()? */
pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
@@ -481,11 +478,7 @@ pci_pir_biosroute(int bus, int device, int func, int pin, int irq)
args.eax = PCIBIOS_ROUTE_INTERRUPT;
args.ebx = (bus << 8) | (device << 3) | func;
args.ecx = (irq << 8) | (0xa + pin);
-#ifdef XEN
- return (0);
-#else
return (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)));
-#endif
}
diff --git a/sys/i386/xen/clock.c b/sys/i386/xen/clock.c
deleted file mode 100644
index ffb436e..0000000
--- a/sys/i386/xen/clock.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz and Don Ahn.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/* #define DELAYDEBUG */
-/*
- * Routines to handle clock hardware.
- */
-
-#include "opt_ddb.h"
-#include "opt_clock.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/clock.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/time.h>
-#include <sys/timeet.h>
-#include <sys/timetc.h>
-#include <sys/kernel.h>
-#include <sys/limits.h>
-#include <sys/sysctl.h>
-#include <sys/cons.h>
-#include <sys/power.h>
-
-#include <machine/clock.h>
-#include <machine/cputypes.h>
-#include <machine/frame.h>
-#include <machine/intr_machdep.h>
-#include <machine/md_var.h>
-#include <machine/psl.h>
-#include <machine/pvclock.h>
-#if defined(SMP)
-#include <machine/smp.h>
-#endif
-#include <machine/specialreg.h>
-#include <machine/timerreg.h>
-
-#include <x86/isa/icu.h>
-#include <isa/isareg.h>
-#include <isa/rtc.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <machine/pmap.h>
-#include <xen/hypervisor.h>
-#include <xen/xen-os.h>
-#include <machine/xen/xenfunc.h>
-#include <xen/interface/vcpu.h>
-#include <machine/cpu.h>
-#include <xen/xen_intr.h>
-
-/*
- * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
- * can use a simple formula for leap years.
- */
-#define LEAPYEAR(y) (!((y) % 4))
-#define DAYSPERYEAR (28+30*4+31*7)
-
-#ifndef TIMER_FREQ
-#define TIMER_FREQ 1193182
-#endif
-
-#ifdef CYC2NS_SCALE_FACTOR
-#undef CYC2NS_SCALE_FACTOR
-#endif
-#define CYC2NS_SCALE_FACTOR 10
-
-/* Values for timerX_state: */
-#define RELEASED 0
-#define RELEASE_PENDING 1
-#define ACQUIRED 2
-#define ACQUIRE_PENDING 3
-
-struct mtx clock_lock;
-#define RTC_LOCK_INIT \
- mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE)
-#define RTC_LOCK mtx_lock_spin(&clock_lock)
-#define RTC_UNLOCK mtx_unlock_spin(&clock_lock)
-#define NS_PER_TICK (1000000000ULL/hz)
-
-int adjkerntz; /* local offset from UTC in seconds */
-int clkintr_pending;
-int pscnt = 1;
-int psdiv = 1;
-int wall_cmos_clock;
-u_int timer_freq = TIMER_FREQ;
-static u_long cyc2ns_scale;
-static uint64_t processed_system_time; /* stime (ns) at last processing. */
-
-#define do_div(n,base) ({ \
- unsigned long __upper, __low, __high, __mod, __base; \
- __base = (base); \
- __asm("":"=a" (__low), "=d" (__high):"A" (n)); \
- __upper = __high; \
- if (__high) { \
- __upper = __high % (__base); \
- __high = __high / (__base); \
- } \
- __asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
- __asm("":"=A" (n):"a" (__low),"d" (__high)); \
- __mod; \
-})
-
-
-/* convert from cycles(64bits) => nanoseconds (64bits)
- * basic equation:
- * ns = cycles / (freq / ns_per_sec)
- * ns = cycles * (ns_per_sec / freq)
- * ns = cycles * (10^9 / (cpu_mhz * 10^6))
- * ns = cycles * (10^3 / cpu_mhz)
- *
- * Then we use scaling math (suggested by george@mvista.com) to get:
- * ns = cycles * (10^3 * SC / cpu_mhz) / SC
- * ns = cycles * cyc2ns_scale / SC
- *
- * And since SC is a constant power of two, we can convert the div
- * into a shift.
- * -johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-static inline void set_cyc2ns_scale(unsigned long cpu_mhz)
-{
- cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz;
-}
-
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
- return ((cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR);
-}
-
-static uint32_t
-getit(void)
-{
- return (pvclock_get_last_cycles());
-}
-
-
-/*
- * XXX: timer needs more SMP work.
- */
-void
-i8254_init(void)
-{
-
- RTC_LOCK_INIT;
-}
-
-/*
- * Wait "n" microseconds.
- * Relies on timer 1 counting down from (timer_freq / hz)
- * Note: timer had better have been programmed before this is first used!
- */
-void
-i8254_delay(int n)
-{
- int delta, ticks_left;
- uint32_t tick, prev_tick;
-#ifdef DELAYDEBUG
- int getit_calls = 1;
- int n1;
- static int state = 0;
-
- if (state == 0) {
- state = 1;
- for (n1 = 1; n1 <= 10000000; n1 *= 10)
- DELAY(n1);
- state = 2;
- }
- if (state == 1)
- printf("DELAY(%d)...", n);
-#endif
- /*
- * Read the counter first, so that the rest of the setup overhead is
- * counted. Guess the initial overhead is 20 usec (on most systems it
- * takes about 1.5 usec for each of the i/o's in getit(). The loop
- * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
- * multiplications and divisions to scale the count take a while).
- *
- * However, if ddb is active then use a fake counter since reading
- * the i8254 counter involves acquiring a lock. ddb must not go
- * locking for many reasons, but it calls here for at least atkbd
- * input.
- */
- prev_tick = getit();
-
- n -= 0; /* XXX actually guess no initial overhead */
- /*
- * Calculate (n * (timer_freq / 1e6)) without using floating point
- * and without any avoidable overflows.
- */
- if (n <= 0)
- ticks_left = 0;
- else if (n < 256)
- /*
- * Use fixed point to avoid a slow division by 1000000.
- * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
- * 2^15 is the first power of 2 that gives exact results
- * for n between 0 and 256.
- */
- ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
- else
- /*
- * Don't bother using fixed point, although gcc-2.7.2
- * generates particularly poor code for the long long
- * division, since even the slow way will complete long
- * before the delay is up (unless we're interrupted).
- */
- ticks_left = ((u_int)n * (long long)timer_freq + 999999)
- / 1000000;
-
- while (ticks_left > 0) {
- tick = getit();
-#ifdef DELAYDEBUG
- ++getit_calls;
-#endif
- delta = tick - prev_tick;
- prev_tick = tick;
- if (delta < 0) {
- /*
- * Guard against timer0_max_count being wrong.
- * This shouldn't happen in normal operation,
- * but it may happen if set_timer_freq() is
- * traced.
- */
- /* delta += timer0_max_count; ??? */
- if (delta < 0)
- delta = 0;
- }
- ticks_left -= delta;
- }
-#ifdef DELAYDEBUG
- if (state == 1)
- printf(" %d calls to getit() at %d usec each\n",
- getit_calls, (n + 5) / getit_calls);
-#endif
-}
-
-void
-startrtclock()
-{
- uint64_t __cpu_khz;
- uint32_t cpu_khz;
- struct vcpu_time_info *info;
-
- __cpu_khz = 1000000ULL << 32;
- info = &HYPERVISOR_shared_info->vcpu_info[0].time;
-
- (void)do_div(__cpu_khz, info->tsc_to_system_mul);
- if ( info->tsc_shift < 0 )
- cpu_khz = __cpu_khz << -info->tsc_shift;
- else
- cpu_khz = __cpu_khz >> info->tsc_shift;
-
- printf("Xen reported: %u.%03u MHz processor.\n",
- cpu_khz / 1000, cpu_khz % 1000);
-
- /* (10^6 * 2^32) / cpu_hz = (10^3 * 2^32) / cpu_khz =
- (2^32 * 1 / (clocks/us)) */
-
- set_cyc2ns_scale(cpu_khz/1000);
- tsc_freq = cpu_khz * 1000;
-}
-
-/*
- * RTC support routines
- */
-
-
-static __inline int
-readrtc(int port)
-{
- return(bcd2bin(rtcin(port)));
-}
-
-
-#ifdef XEN_PRIVILEGED_GUEST
-
-/*
- * Initialize the time of day register, based on the time base which is, e.g.
- * from a filesystem.
- */
-static void
-domu_inittodr(time_t base)
-{
- unsigned long sec;
- int s, y;
- struct timespec ts;
-
- update_wallclock();
- add_uptime_to_wallclock();
-
- RTC_LOCK;
-
- if (base) {
- ts.tv_sec = base;
- ts.tv_nsec = 0;
- tc_setclock(&ts);
- }
-
- sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
-
- y = time_second - shadow_tv.tv_sec;
- if (y <= -2 || y >= 2) {
- /* badly off, adjust it */
- tc_setclock(&shadow_tv);
- }
- RTC_UNLOCK;
-}
-
-/*
- * Write system time back to RTC.
- */
-static void
-domu_resettodr(void)
-{
- unsigned long tm;
- int s;
- dom0_op_t op;
- struct shadow_time_info *shadow;
- struct pcpu *pc;
-
- pc = pcpu_find(smp_processor_id());
- shadow = &pc->pc_shadow_time;
- if (xen_disable_rtc_set)
- return;
-
- s = splclock();
- tm = time_second;
- splx(s);
-
- tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
-
- if ((xen_start_info->flags & SIF_INITDOMAIN) &&
- !independent_wallclock)
- {
- op.cmd = DOM0_SETTIME;
- op.u.settime.secs = tm;
- op.u.settime.nsecs = 0;
- op.u.settime.system_time = shadow->system_timestamp;
- HYPERVISOR_dom0_op(&op);
- update_wallclock();
- add_uptime_to_wallclock();
- } else if (independent_wallclock) {
- /* notyet */
- ;
- }
-}
-
-/*
- * Initialize the time of day register, based on the time base which is, e.g.
- * from a filesystem.
- */
-void
-inittodr(time_t base)
-{
- unsigned long sec, days;
- int year, month;
- int y, m, s;
- struct timespec ts;
-
- if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
- domu_inittodr(base);
- return;
- }
-
- if (base) {
- s = splclock();
- ts.tv_sec = base;
- ts.tv_nsec = 0;
- tc_setclock(&ts);
- splx(s);
- }
-
- /* Look if we have a RTC present and the time is valid */
- if (!(rtcin(RTC_STATUSD) & RTCSD_PWR))
- goto wrong_time;
-
- /* wait for time update to complete */
- /* If RTCSA_TUP is zero, we have at least 244us before next update */
- s = splhigh();
- while (rtcin(RTC_STATUSA) & RTCSA_TUP) {
- splx(s);
- s = splhigh();
- }
-
- days = 0;
-#ifdef USE_RTC_CENTURY
- year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100;
-#else
- year = readrtc(RTC_YEAR) + 1900;
- if (year < 1970)
- year += 100;
-#endif
- if (year < 1970) {
- splx(s);
- goto wrong_time;
- }
- month = readrtc(RTC_MONTH);
- for (m = 1; m < month; m++)
- days += daysinmonth[m-1];
- if ((month > 2) && LEAPYEAR(year))
- days ++;
- days += readrtc(RTC_DAY) - 1;
- for (y = 1970; y < year; y++)
- days += DAYSPERYEAR + LEAPYEAR(y);
- sec = ((( days * 24 +
- readrtc(RTC_HRS)) * 60 +
- readrtc(RTC_MIN)) * 60 +
- readrtc(RTC_SEC));
- /* sec now contains the number of seconds, since Jan 1 1970,
- in the local time zone */
-
- sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
-
- y = time_second - sec;
- if (y <= -2 || y >= 2) {
- /* badly off, adjust it */
- ts.tv_sec = sec;
- ts.tv_nsec = 0;
- tc_setclock(&ts);
- }
- splx(s);
- return;
-
- wrong_time:
- printf("Invalid time in real time clock.\n");
- printf("Check and reset the date immediately!\n");
-}
-
-
-/*
- * Write system time back to RTC
- */
-void
-resettodr()
-{
- unsigned long tm;
- int y, m, s;
-
- if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
- domu_resettodr();
- return;
- }
-
- if (xen_disable_rtc_set)
- return;
-
- s = splclock();
- tm = time_second;
- splx(s);
-
- /* Disable RTC updates and interrupts. */
- writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
-
- /* Calculate local time to put in RTC */
-
- tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
-
- writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */
- writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */
- writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24; /* Write back Hours */
-
- /* We have now the days since 01-01-1970 in tm */
- writertc(RTC_WDAY, (tm + 4) % 7 + 1); /* Write back Weekday */
- for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y);
- tm >= m;
- y++, m = DAYSPERYEAR + LEAPYEAR(y))
- tm -= m;
-
- /* Now we have the years in y and the day-of-the-year in tm */
- writertc(RTC_YEAR, bin2bcd(y%100)); /* Write back Year */
-#ifdef USE_RTC_CENTURY
- writertc(RTC_CENTURY, bin2bcd(y/100)); /* ... and Century */
-#endif
- for (m = 0; ; m++) {
- int ml;
-
- ml = daysinmonth[m];
- if (m == 1 && LEAPYEAR(y))
- ml++;
- if (tm < ml)
- break;
- tm -= ml;
- }
-
- writertc(RTC_MONTH, bin2bcd(m + 1)); /* Write back Month */
- writertc(RTC_DAY, bin2bcd(tm + 1)); /* Write back Month Day */
-
- /* Reenable RTC updates and interrupts. */
- writertc(RTC_STATUSB, RTCSB_24HR);
- rtcin(RTC_INTR);
-}
-#endif
-
-/*
- * Start clocks running.
- */
-void
-cpu_initclocks(void)
-{
- cpu_initclocks_bsp();
-}
-
-/* Return system time offset by ticks */
-uint64_t
-get_system_time(int ticks)
-{
- return (processed_system_time + (ticks * NS_PER_TICK));
-}
-
-int
-timer_spkr_acquire(void)
-{
-
- return (0);
-}
-
-int
-timer_spkr_release(void)
-{
-
- return (0);
-}
-
-void
-timer_spkr_setfreq(int freq)
-{
-
-}
-
diff --git a/sys/i386/xen/exception.s b/sys/i386/xen/exception.s
deleted file mode 100644
index 95f1c0e..0000000
--- a/sys/i386/xen/exception.s
+++ /dev/null
@@ -1,494 +0,0 @@
-/*-
- * Copyright (c) 1989, 1990 William F. Jolitz.
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include "opt_apic.h"
-#include "opt_npx.h"
-
-#include <machine/asmacros.h>
-#include <machine/psl.h>
-#include <machine/trap.h>
-
-#include "assym.s"
-
-#define SEL_RPL_MASK 0x0002
-#define __HYPERVISOR_iret 23
-
-/* Offsets into shared_info_t. */
-
-#define evtchn_upcall_pending /* 0 */
-#define evtchn_upcall_mask 1
-
-#define sizeof_vcpu_shift 6
-
-
-#ifdef SMP
-#define GET_VCPU_INFO(reg) movl PCPU(CPUID),reg ; \
- shl $sizeof_vcpu_shift,reg ; \
- addl HYPERVISOR_shared_info,reg
-#else
-#define GET_VCPU_INFO(reg) movl HYPERVISOR_shared_info,reg
-#endif
-
-#define __DISABLE_INTERRUPTS(reg) movb $1,evtchn_upcall_mask(reg)
-#define __ENABLE_INTERRUPTS(reg) movb $0,evtchn_upcall_mask(reg)
-#define DISABLE_INTERRUPTS(reg) GET_VCPU_INFO(reg) ; \
- __DISABLE_INTERRUPTS(reg)
-#define ENABLE_INTERRUPTS(reg) GET_VCPU_INFO(reg) ; \
- __ENABLE_INTERRUPTS(reg)
-#define __TEST_PENDING(reg) testb $0xFF,evtchn_upcall_pending(reg)
-
-#define POPA \
- popl %edi; \
- popl %esi; \
- popl %ebp; \
- popl %ebx; \
- popl %ebx; \
- popl %edx; \
- popl %ecx; \
- popl %eax;
-
- .text
-
-/*****************************************************************************/
-/* Trap handling */
-/*****************************************************************************/
-/*
- * Trap and fault vector routines.
- *
- * Most traps are 'trap gates', SDT_SYS386TGT. A trap gate pushes state on
- * the stack that mostly looks like an interrupt, but does not disable
- * interrupts. A few of the traps we are use are interrupt gates,
- * SDT_SYS386IGT, which are nearly the same thing except interrupts are
- * disabled on entry.
- *
- * The cpu will push a certain amount of state onto the kernel stack for
- * the current process. The amount of state depends on the type of trap
- * and whether the trap crossed rings or not. See i386/include/frame.h.
- * At the very least the current EFLAGS (status register, which includes
- * the interrupt disable state prior to the trap), the code segment register,
- * and the return instruction pointer are pushed by the cpu. The cpu
- * will also push an 'error' code for certain traps. We push a dummy
- * error code for those traps where the cpu doesn't in order to maintain
- * a consistent frame. We also push a contrived 'trap number'.
- *
- * The cpu does not push the general registers, we must do that, and we
- * must restore them prior to calling 'iret'. The cpu adjusts the %cs and
- * %ss segment registers, but does not mess with %ds, %es, or %fs. Thus we
- * must load them with appropriate values for supervisor mode operation.
- */
-
-MCOUNT_LABEL(user)
-MCOUNT_LABEL(btrap)
-
-#define TRAP(a) pushl $(a) ; jmp alltraps
-
-IDTVEC(div)
- pushl $0; TRAP(T_DIVIDE)
-IDTVEC(dbg)
- pushl $0; TRAP(T_TRCTRAP)
-IDTVEC(nmi)
- pushl $0; TRAP(T_NMI)
-IDTVEC(bpt)
- pushl $0; TRAP(T_BPTFLT)
-IDTVEC(ofl)
- pushl $0; TRAP(T_OFLOW)
-IDTVEC(bnd)
- pushl $0; TRAP(T_BOUND)
-IDTVEC(ill)
- pushl $0; TRAP(T_PRIVINFLT)
-IDTVEC(dna)
- pushl $0; TRAP(T_DNA)
-IDTVEC(fpusegm)
- pushl $0; TRAP(T_FPOPFLT)
-IDTVEC(tss)
- TRAP(T_TSSFLT)
-IDTVEC(missing)
- TRAP(T_SEGNPFLT)
-IDTVEC(stk)
- TRAP(T_STKFLT)
-IDTVEC(prot)
- TRAP(T_PROTFLT)
-IDTVEC(page)
- TRAP(T_PAGEFLT)
-IDTVEC(mchk)
- pushl $0; TRAP(T_MCHK)
-IDTVEC(rsvd)
- pushl $0; TRAP(T_RESERVED)
-IDTVEC(fpu)
- pushl $0; TRAP(T_ARITHTRAP)
-IDTVEC(align)
- TRAP(T_ALIGNFLT)
-IDTVEC(xmm)
- pushl $0; TRAP(T_XMMFLT)
-
-IDTVEC(hypervisor_callback)
- pushl $0;
- pushl $0;
- pushal
- pushl %ds
- pushl %es
- pushl %fs
-upcall_with_regs_pushed:
- SET_KERNEL_SREGS
- FAKE_MCOUNT(TF_EIP(%esp))
-call_evtchn_upcall:
- movl TF_EIP(%esp),%eax
- cmpl $scrit,%eax
- jb 10f
- cmpl $ecrit,%eax
- jb critical_region_fixup
-
-10: pushl %esp
- call xen_intr_handle_upcall
- addl $4,%esp
-
- /*
- * Return via doreti to handle ASTs.
- */
- MEXITCOUNT
- jmp doreti
-
-
-hypervisor_callback_pending:
- DISABLE_INTERRUPTS(%esi) /* cli */
- jmp 10b
- /*
- * alltraps entry point. Interrupts are enabled if this was a trap
- * gate (TGT), else disabled if this was an interrupt gate (IGT).
- * Note that int0x80_syscall is a trap gate. Only page faults
- * use an interrupt gate.
- */
- SUPERALIGN_TEXT
- .globl alltraps
- .type alltraps,@function
-alltraps:
- pushal
- pushl %ds
- pushl %es
- pushl %fs
-
-alltraps_with_regs_pushed:
- SET_KERNEL_SREGS
- FAKE_MCOUNT(TF_EIP(%esp))
-
-calltrap:
- push %esp
- call trap
- add $4, %esp
-
- /*
- * Return via doreti to handle ASTs.
- */
- MEXITCOUNT
- jmp doreti
-
-/*
- * SYSCALL CALL GATE (old entry point for a.out binaries)
- *
- * The intersegment call has been set up to specify one dummy parameter.
- *
- * This leaves a place to put eflags so that the call frame can be
- * converted to a trap frame. Note that the eflags is (semi-)bogusly
- * pushed into (what will be) tf_err and then copied later into the
- * final spot. It has to be done this way because esp can't be just
- * temporarily altered for the pushfl - an interrupt might come in
- * and clobber the saved cs/eip.
- */
- SUPERALIGN_TEXT
-IDTVEC(lcall_syscall)
- pushfl /* save eflags */
- popl 8(%esp) /* shuffle into tf_eflags */
- pushl $7 /* sizeof "lcall 7,0" */
- subl $4,%esp /* skip over tf_trapno */
- pushal
- pushl %ds
- pushl %es
- pushl %fs
- SET_KERNEL_SREGS
- FAKE_MCOUNT(TF_EIP(%esp))
- pushl %esp
- call syscall
- add $4, %esp
- MEXITCOUNT
- jmp doreti
-
-/*
- * Call gate entry for FreeBSD ELF and Linux/NetBSD syscall (int 0x80)
- *
- * Even though the name says 'int0x80', this is actually a TGT (trap gate)
- * rather then an IGT (interrupt gate). Thus interrupts are enabled on
- * entry just as they are for a normal syscall.
- */
- SUPERALIGN_TEXT
-IDTVEC(int0x80_syscall)
- pushl $2 /* sizeof "int 0x80" */
- pushl $0xBEEF /* for debug */
- pushal
- pushl %ds
- pushl %es
- pushl %fs
- SET_KERNEL_SREGS
- FAKE_MCOUNT(TF_EIP(%esp))
- pushl %esp
- call syscall
- add $4, %esp
- MEXITCOUNT
- jmp doreti
-
-ENTRY(fork_trampoline)
- pushl %esp /* trapframe pointer */
- pushl %ebx /* arg1 */
- pushl %esi /* function */
- call fork_exit
- addl $12,%esp
- /* cut from syscall */
-
- /*
- * Return via doreti to handle ASTs.
- */
- MEXITCOUNT
- jmp doreti
-
-
-/*
- * To efficiently implement classification of trap and interrupt handlers
- * for profiling, there must be only trap handlers between the labels btrap
- * and bintr, and only interrupt handlers between the labels bintr and
- * eintr. This is implemented (partly) by including files that contain
- * some of the handlers. Before including the files, set up a normal asm
- * environment so that the included files doen't need to know that they are
- * included.
- */
-
- .data
- .p2align 4
- .text
- SUPERALIGN_TEXT
-MCOUNT_LABEL(bintr)
-
-#ifdef DEV_APIC
- .data
- .p2align 4
- .text
- SUPERALIGN_TEXT
-
-#include <i386/i386/apic_vector.s>
-#endif
-
- .data
- .p2align 4
- .text
- SUPERALIGN_TEXT
-#include <i386/i386/vm86bios.s>
-
- .text
-MCOUNT_LABEL(eintr)
-
-/*
- * void doreti(struct trapframe)
- *
- * Handle return from interrupts, traps and syscalls.
- */
- .text
- SUPERALIGN_TEXT
- .type doreti,@function
-doreti:
- FAKE_MCOUNT($bintr) /* init "from" bintr -> doreti */
-doreti_next:
-#ifdef notyet
- /*
- * Check if ASTs can be handled now. PSL_VM must be checked first
- * since segment registers only have an RPL in non-VM86 mode.
- */
- testl $PSL_VM,TF_EFLAGS(%esp) /* are we in vm86 mode? */
- jz doreti_notvm86
- movl PCPU(CURPCB),%ecx
- testl $PCB_VM86CALL,PCB_FLAGS(%ecx) /* are we in a vm86 call? */
- jz doreti_ast /* can handle ASTS now if not */
- jmp doreti_exit
-
-doreti_notvm86:
-#endif
- testb $SEL_RPL_MASK,TF_CS(%esp) /* are we returning to user mode? */
- jz doreti_exit /* can't handle ASTs now if not */
-
-doreti_ast:
- /*
- * Check for ASTs atomically with returning. Disabling CPU
- * interrupts provides sufficient locking even in the SMP case,
- * since we will be informed of any new ASTs by an IPI.
- */
- DISABLE_INTERRUPTS(%esi) /* cli */
- movl PCPU(CURTHREAD),%eax
- testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%eax)
- je doreti_exit
- ENABLE_INTERRUPTS(%esi) /* sti */
- pushl %esp /* pass a pointer to the trapframe */
- call ast
- add $4,%esp
- jmp doreti_ast
-
- /*
- * doreti_exit: pop registers, iret.
- *
- * The segment register pop is a special case, since it may
- * fault if (for example) a sigreturn specifies bad segment
- * registers. The fault is handled in trap.c.
- */
-doreti_exit:
- ENABLE_INTERRUPTS(%esi) # reenable event callbacks (sti)
-
- .globl scrit
-scrit:
- __TEST_PENDING(%esi)
- jnz hypervisor_callback_pending /* More to go */
-
- MEXITCOUNT
-
- .globl doreti_popl_fs
-doreti_popl_fs:
- popl %fs
- .globl doreti_popl_es
-doreti_popl_es:
- popl %es
- .globl doreti_popl_ds
-doreti_popl_ds:
- popl %ds
-
- /*
- * This is important: as nothing is atomic over here (we can get
- * interrupted any time), we use the critical_region_fixup() in
- * order to figure out where out stack is. Therefore, do NOT use
- * 'popal' here without fixing up the table!
- */
- POPA
- addl $8,%esp
- .globl doreti_iret
-doreti_iret:
- jmp hypercall_page + (__HYPERVISOR_iret * 32)
- .globl ecrit
-ecrit:
- /*
- * doreti_iret_fault and friends. Alternative return code for
- * the case where we get a fault in the doreti_exit code
- * above. trap() (i386/i386/trap.c) catches this specific
- * case, sends the process a signal and continues in the
- * corresponding place in the code below.
- */
- ALIGN_TEXT
- .globl doreti_iret_fault
-doreti_iret_fault:
- subl $8,%esp
- pushal
- pushl %ds
- .globl doreti_popl_ds_fault
-doreti_popl_ds_fault:
- pushl %es
- .globl doreti_popl_es_fault
-doreti_popl_es_fault:
- pushl %fs
- .globl doreti_popl_fs_fault
-doreti_popl_fs_fault:
- movl $0,TF_ERR(%esp) /* XXX should be the error code */
- movl $T_PROTFLT,TF_TRAPNO(%esp)
- jmp alltraps_with_regs_pushed
-
- /*
-# [How we do the fixup]. We want to merge the current stack frame with the
-# just-interrupted frame. How we do this depends on where in the critical
-# region the interrupted handler was executing, and so how many saved
-# registers are in each frame. We do this quickly using the lookup table
-# 'critical_fixup_table'. For each byte offset in the critical region, it
-# provides the number of bytes which have already been popped from the
-# interrupted stack frame.
-*/
-
-.globl critical_region_fixup
-critical_region_fixup:
- addl $critical_fixup_table-scrit,%eax
- movzbl (%eax),%eax # %eax contains num bytes popped
- movl %esp,%esi
- add %eax,%esi # %esi points at end of src region
- movl %esp,%edi
- add $0x40,%edi # %edi points at end of dst region
- movl %eax,%ecx
- shr $2,%ecx # convert bytes to words
- je 16f # skip loop if nothing to copy
-15: subl $4,%esi # pre-decrementing copy loop
- subl $4,%edi
- movl (%esi),%eax
- movl %eax,(%edi)
- loop 15b
-16: movl %edi,%esp # final %edi is top of merged stack
- jmp hypervisor_callback_pending
-
-
-critical_fixup_table:
-.byte 0x0,0x0,0x0 #testb $0x1,(%esi)
-.byte 0x0,0x0,0x0,0x0,0x0,0x0 #jne ea
-.byte 0x0,0x0 #pop %fs
-.byte 0x04 #pop %es
-.byte 0x08 #pop %ds
-.byte 0x0c #pop %edi
-.byte 0x10 #pop %esi
-.byte 0x14 #pop %ebp
-.byte 0x18 #pop %ebx
-.byte 0x1c #pop %ebx
-.byte 0x20 #pop %edx
-.byte 0x24 #pop %ecx
-.byte 0x28 #pop %eax
-.byte 0x2c,0x2c,0x2c #add $0x8,%esp
-#if 0
- .byte 0x34 #iret
-#endif
-.byte 0x34,0x34,0x34,0x34,0x34 #HYPERVISOR_iret
-
-
-/* # Hypervisor uses this for application faults while it executes.*/
-ENTRY(failsafe_callback)
- pushal
- call xen_failsafe_handler
-/*# call install_safe_pf_handler */
- movl 28(%esp),%ebx
-1: movl %ebx,%ds
- movl 32(%esp),%ebx
-2: movl %ebx,%es
- movl 36(%esp),%ebx
-3: movl %ebx,%fs
- movl 40(%esp),%ebx
-4: movl %ebx,%gs
-/*# call install_normal_pf_handler */
- popal
- addl $12,%esp
- iret
-
-
diff --git a/sys/i386/xen/locore.s b/sys/i386/xen/locore.s
deleted file mode 100644
index 7e67684..0000000
--- a/sys/i386/xen/locore.s
+++ /dev/null
@@ -1,360 +0,0 @@
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)locore.s 7.3 (Berkeley) 5/13/91
- * $FreeBSD$
- *
- * originally from: locore.s, by William F. Jolitz
- *
- * Substantially rewritten by David Greenman, Rod Grimes,
- * Bruce Evans, Wolfgang Solfrank, Poul-Henning Kamp
- * and many others.
- */
-
-#include "opt_bootp.h"
-#include "opt_compat.h"
-#include "opt_nfsroot.h"
-#include "opt_pmap.h"
-
-#include <sys/syscall.h>
-#include <sys/reboot.h>
-
-#include <machine/asmacros.h>
-#include <machine/cputypes.h>
-#include <machine/psl.h>
-#include <machine/pmap.h>
-#include <machine/specialreg.h>
-
-#define __ASSEMBLY__
-#include <xen/interface/elfnote.h>
-
-/* The defines below have been lifted out of <machine/xen-public/arch-x86_32.h> */
-#define FLAT_RING1_CS 0xe019 /* GDT index 259 */
-#define FLAT_RING1_DS 0xe021 /* GDT index 260 */
-#define KERNEL_CS FLAT_RING1_CS
-#define KERNEL_DS FLAT_RING1_DS
-
-#include "assym.s"
-
-.section __xen_guest
- .ascii "LOADER=generic,GUEST_OS=freebsd,GUEST_VER=7.0,XEN_VER=xen-3.0,BSD_SYMTAB,VIRT_BASE=0xc0000000"
- .byte 0
-
- ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "FreeBSD")
- ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "HEAD")
- ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0")
- ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long, KERNBASE)
- ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, KERNBASE)
- ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long, btext)
- ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long, hypercall_page)
- ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, .long, XEN_HYPERVISOR_VIRT_START)
-#if 0
- ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel")
-#endif
- ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|supervisor_mode_kernel|writable_descriptor_tables")
-
-#ifdef PAE
- ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "yes")
- ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .long, PG_V, PG_V)
-#else
- ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "no")
- ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .long, PG_V, PG_V)
-#endif
- ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic")
- ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long, 1)
-
-
-
-/*
- * XXX
- *
- * Note: This version greatly munged to avoid various assembler errors
- * that may be fixed in newer versions of gas. Perhaps newer versions
- * will have more pleasant appearance.
- */
-
-/*
- * PTmap is recursive pagemap at top of virtual address space.
- * Within PTmap, the page directory can be found (third indirection).
- */
- .globl PTmap,PTD,PTDpde
- .set PTmap,(PTDPTDI << PDRSHIFT)
- .set PTD,PTmap + (PTDPTDI * PAGE_SIZE)
- .set PTDpde,PTD + (PTDPTDI * PDESIZE)
-
-/*
- * Compiled KERNBASE location and the kernel load address
- */
- .globl kernbase
- .set kernbase,KERNBASE
- .globl kernload
- .set kernload,KERNLOAD
-
-/*
- * Globals
- */
- .data
- ALIGN_DATA /* just to be sure */
-
- .space 0x2000 /* space for tmpstk - temporary stack */
-tmpstk:
-
- .globl bootinfo
-bootinfo: .space BOOTINFO_SIZE /* bootinfo that we can handle */
-
- .globl KERNend
-KERNend: .long 0 /* phys addr end of kernel (just after bss) */
- .globl physfree
-physfree: .long 0 /* phys addr of next free page */
-
- .globl IdlePTD
-IdlePTD: .long 0 /* phys addr of kernel PTD */
-
-#ifdef PAE
- .globl IdlePDPT
-IdlePDPT: .long 0 /* phys addr of kernel PDPT */
-#endif
-
-#ifdef SMP
- .globl KPTphys
-#endif
-KPTphys: .long 0 /* phys addr of kernel page tables */
- .globl gdtset
-gdtset: .long 0 /* GDT is valid */
-
- .globl proc0kstack
-proc0kstack: .long 0 /* address of proc 0 kstack space */
-p0kpa: .long 0 /* phys addr of proc0's STACK */
-
-vm86phystk: .long 0 /* PA of vm86/bios stack */
-
- .globl vm86paddr, vm86pa
-vm86paddr: .long 0 /* address of vm86 region */
-vm86pa: .long 0 /* phys addr of vm86 region */
-
-#ifdef PC98
- .globl pc98_system_parameter
-pc98_system_parameter:
- .space 0x240
-#endif
-
- .globl avail_space
-avail_space: .long 0
-
-/**********************************************************************
- *
- * Some handy macros
- *
- */
-
-/*
- * We're already in protected mode, so no remapping is needed.
- */
-#define R(foo) (foo)
-
-#define ALLOCPAGES(foo) \
- movl R(physfree), %esi ; \
- movl $((foo)*PAGE_SIZE), %eax ; \
- addl %esi, %eax ; \
- movl %eax, R(physfree) ; \
- movl %esi, %edi ; \
- movl $((foo)*PAGE_SIZE),%ecx ; \
- xorl %eax,%eax ; \
- cld ; \
- rep ; \
- stosb
-
-/*
- * fillkpt
- * eax = page frame address
- * ebx = index into page table
- * ecx = how many pages to map
- * base = base address of page dir/table
- * prot = protection bits
- */
-#define fillkpt(base, prot) \
- shll $PTESHIFT,%ebx ; \
- addl base,%ebx ; \
- orl $PG_V,%eax ; \
- orl prot,%eax ; \
-1: movl %eax,(%ebx) ; \
- addl $PAGE_SIZE,%eax ; /* increment physical address */ \
- addl $PTESIZE,%ebx ; /* next pte */ \
- loop 1b
-
-/*
- * fillkptphys(prot)
- * eax = physical address
- * ecx = how many pages to map
- * prot = protection bits
- */
-#define fillkptphys(prot) \
- movl %eax, %ebx ; \
- shrl $PAGE_SHIFT, %ebx ; \
- fillkpt(R(KPTphys), prot)
-
-/* Temporary stack */
-.space 8192
-tmpstack:
- .long tmpstack, KERNEL_DS
-
- .text
-
-.p2align 12, 0x90
-
-#define HYPERCALL_PAGE_OFFSET 0x1000
-.org HYPERCALL_PAGE_OFFSET
-ENTRY(hypercall_page)
- .cfi_startproc
- .skip 0x1000
- .cfi_endproc
-
-/**********************************************************************
- *
- * This is where the bootblocks start us, set the ball rolling...
- *
- */
-NON_GPROF_ENTRY(btext)
- /* At the end of our stack, we shall have free space - so store it */
- movl %esp,%ebx
- movl %ebx,R(avail_space)
-
- lss tmpstack,%esp
-
- pushl %esi
- call initvalues
- popl %esi
-
- /* Store the CPUID information */
- xorl %eax,%eax
- cpuid # cpuid 0
- movl %eax,R(cpu_high) # highest capability
- movl %ebx,R(cpu_vendor) # store vendor string
- movl %edx,R(cpu_vendor+4)
- movl %ecx,R(cpu_vendor+8)
- movb $0,R(cpu_vendor+12)
-
- movl $1,%eax
- cpuid # cpuid 1
- movl %eax,R(cpu_id) # store cpu_id
- movl %ebx,R(cpu_procinfo) # store cpu_procinfo
- movl %edx,R(cpu_feature) # store cpu_feature
- movl %ecx,R(cpu_feature2) # store cpu_feature2
- rorl $8,%eax # extract family type
- andl $15,%eax
- cmpl $5,%eax
- movl $CPU_686,R(cpu)
-
- movl proc0kstack,%eax
- leal (KSTACK_PAGES*PAGE_SIZE-PCB_SIZE)(%eax),%esp
- xorl %ebp,%ebp /* mark end of frames */
-#ifdef PAE
- movl IdlePDPT,%esi
-#else
- movl IdlePTD,%esi
-#endif
- movl %esi,(KSTACK_PAGES*PAGE_SIZE-PCB_SIZE+PCB_CR3)(%eax)
- pushl physfree
- call init386
- addl $4, %esp
- call mi_startup
- /* NOTREACHED */
- int $3
-
-/*
- * Signal trampoline, copied to top of user stack
- */
-NON_GPROF_ENTRY(sigcode)
- calll *SIGF_HANDLER(%esp)
- leal SIGF_UC(%esp),%eax /* get ucontext */
- pushl %eax
- testl $PSL_VM,UC_EFLAGS(%eax)
- jne 1f
- mov UC_GS(%eax), %gs /* restore %gs */
-1:
- movl $SYS_sigreturn,%eax
- pushl %eax /* junk to fake return addr. */
- int $0x80 /* enter kernel with args */
- /* on stack */
-1:
- jmp 1b
-
-#ifdef COMPAT_FREEBSD4
- ALIGN_TEXT
-freebsd4_sigcode:
- calll *SIGF_HANDLER(%esp)
- leal SIGF_UC4(%esp),%eax /* get ucontext */
- pushl %eax
- testl $PSL_VM,UC4_EFLAGS(%eax)
- jne 1f
- mov UC4_GS(%eax),%gs /* restore %gs */
-1:
- movl $344,%eax /* 4.x SYS_sigreturn */
- pushl %eax /* junk to fake return addr. */
- int $0x80 /* enter kernel with args */
- /* on stack */
-1:
- jmp 1b
-#endif
-
-#ifdef COMPAT_43
- ALIGN_TEXT
-osigcode:
- call *SIGF_HANDLER(%esp) /* call signal handler */
- lea SIGF_SC(%esp),%eax /* get sigcontext */
- pushl %eax
- testl $PSL_VM,SC_PS(%eax)
- jne 9f
- movl SC_GS(%eax),%gs /* restore %gs */
-9:
- movl $103,%eax /* 3.x SYS_sigreturn */
- pushl %eax /* junk to fake return addr. */
- int $0x80 /* enter kernel with args */
-0: jmp 0b
-#endif /* COMPAT_43 */
-
- ALIGN_TEXT
-esigcode:
-
- .data
- .globl szsigcode
-szsigcode:
- .long esigcode-sigcode
-#ifdef COMPAT_FREEBSD4
- .globl szfreebsd4_sigcode
-szfreebsd4_sigcode:
- .long esigcode-freebsd4_sigcode
-#endif
-#ifdef COMPAT_43
- .globl szosigcode
-szosigcode:
- .long esigcode-osigcode
-#endif
diff --git a/sys/i386/xen/mp_machdep.c b/sys/i386/xen/mp_machdep.c
deleted file mode 100644
index e391981..0000000
--- a/sys/i386/xen/mp_machdep.c
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*-
- * Copyright (c) 1996, by Steve Passe
- * Copyright (c) 2008, by Kip Macy
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the developer may NOT be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_apic.h"
-#include "opt_cpu.h"
-#include "opt_kstack_pages.h"
-#include "opt_mp_watchdog.h"
-#include "opt_pmap.h"
-#include "opt_sched.h"
-#include "opt_smp.h"
-
-#if !defined(lint)
-#if !defined(SMP)
-#error How did you get here?
-#endif
-
-#ifndef DEV_APIC
-#error The apic device is required for SMP, add "device apic" to your config file.
-#endif
-#if defined(CPU_DISABLE_CMPXCHG) && !defined(COMPILING_LINT)
-#error SMP not supported with CPU_DISABLE_CMPXCHG
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/cons.h> /* cngetc() */
-#include <sys/cpuset.h>
-#ifdef GPROF
-#include <sys/gmon.h>
-#endif
-#include <sys/kernel.h>
-#include <sys/ktr.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/memrange.h>
-#include <sys/mutex.h>
-#include <sys/pcpu.h>
-#include <sys/proc.h>
-#include <sys/rwlock.h>
-#include <sys/sched.h>
-#include <sys/smp.h>
-#include <sys/sysctl.h>
-
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
-#include <vm/vm_kern.h>
-#include <vm/vm_extern.h>
-#include <vm/vm_page.h>
-
-#include <x86/apicreg.h>
-#include <machine/md_var.h>
-#include <machine/mp_watchdog.h>
-#include <machine/pcb.h>
-#include <machine/psl.h>
-#include <machine/smp.h>
-#include <machine/specialreg.h>
-#include <machine/pcpu.h>
-
-#include <xen/xen-os.h>
-#include <xen/evtchn.h>
-#include <xen/xen_intr.h>
-#include <xen/hypervisor.h>
-#include <xen/interface/vcpu.h>
-
-/*---------------------------- Extern Declarations ---------------------------*/
-extern struct pcpu __pcpu[];
-
-extern void Xhypervisor_callback(void);
-extern void failsafe_callback(void);
-extern void pmap_lazyfix_action(void);
-
-/*--------------------------- Forward Declarations ---------------------------*/
-static driver_filter_t smp_reschedule_interrupt;
-static driver_filter_t smp_call_function_interrupt;
-static void assign_cpu_ids(void);
-static void set_interrupt_apic_ids(void);
-static int start_all_aps(void);
-static int start_ap(int apic_id);
-static void release_aps(void *dummy);
-
-/*---------------------------------- Macros ----------------------------------*/
-#define IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
-
-/*-------------------------------- Local Types -------------------------------*/
-typedef void call_data_func_t(uintptr_t , uintptr_t);
-
-struct cpu_info {
- int cpu_present:1;
- int cpu_bsp:1;
- int cpu_disabled:1;
-};
-
-struct xen_ipi_handler
-{
- driver_filter_t *filter;
- const char *description;
-};
-
-enum {
- RESCHEDULE_VECTOR,
- CALL_FUNCTION_VECTOR,
-};
-
-/*-------------------------------- Global Data -------------------------------*/
-static u_int hyperthreading_cpus;
-static cpuset_t hyperthreading_cpus_mask;
-
-int mp_naps; /* # of Applications processors */
-int boot_cpu_id = -1; /* designated BSP */
-
-static int bootAP;
-static union descriptor *bootAPgdt;
-
-/* Free these after use */
-void *bootstacks[MAXCPU];
-
-struct pcb stoppcbs[MAXCPU];
-
-/* Variables needed for SMP tlb shootdown. */
-vm_offset_t smp_tlb_addr1;
-vm_offset_t smp_tlb_addr2;
-volatile int smp_tlb_wait;
-
-static u_int logical_cpus;
-static volatile cpuset_t ipi_nmi_pending;
-
-/* used to hold the AP's until we are ready to release them */
-static struct mtx ap_boot_mtx;
-
-/* Set to 1 once we're ready to let the APs out of the pen. */
-static volatile int aps_ready = 0;
-
-/*
- * Store data from cpu_add() until later in the boot when we actually setup
- * the APs.
- */
-static struct cpu_info cpu_info[MAX_APIC_ID + 1];
-int cpu_apic_ids[MAXCPU];
-int apic_cpuids[MAX_APIC_ID + 1];
-
-/* Holds pending bitmap based IPIs per CPU */
-static volatile u_int cpu_ipi_pending[MAXCPU];
-
-static int cpu_logical;
-static int cpu_cores;
-
-static const struct xen_ipi_handler xen_ipis[] =
-{
- [RESCHEDULE_VECTOR] = { smp_reschedule_interrupt, "resched" },
- [CALL_FUNCTION_VECTOR] = { smp_call_function_interrupt,"callfunc" }
-};
-
-/*------------------------------- Per-CPU Data -------------------------------*/
-DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
-DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
-
-/*------------------------------ Implementation ------------------------------*/
-struct cpu_group *
-cpu_topo(void)
-{
- if (cpu_cores == 0)
- cpu_cores = 1;
- if (cpu_logical == 0)
- cpu_logical = 1;
- if (mp_ncpus % (cpu_cores * cpu_logical) != 0) {
- printf("WARNING: Non-uniform processors.\n");
- printf("WARNING: Using suboptimal topology.\n");
- return (smp_topo_none());
- }
- /*
- * No multi-core or hyper-threaded.
- */
- if (cpu_logical * cpu_cores == 1)
- return (smp_topo_none());
- /*
- * Only HTT no multi-core.
- */
- if (cpu_logical > 1 && cpu_cores == 1)
- return (smp_topo_1level(CG_SHARE_L1, cpu_logical, CG_FLAG_HTT));
- /*
- * Only multi-core no HTT.
- */
- if (cpu_cores > 1 && cpu_logical == 1)
- return (smp_topo_1level(CG_SHARE_NONE, cpu_cores, 0));
- /*
- * Both HTT and multi-core.
- */
- return (smp_topo_2level(CG_SHARE_NONE, cpu_cores,
- CG_SHARE_L1, cpu_logical, CG_FLAG_HTT));
-}
-
-/*
- * Calculate usable address in base memory for AP trampoline code.
- */
-u_int
-mp_bootaddress(u_int basemem)
-{
-
- return (basemem);
-}
-
-void
-cpu_add(u_int apic_id, char boot_cpu)
-{
-
- if (apic_id > MAX_APIC_ID) {
- panic("SMP: APIC ID %d too high", apic_id);
- return;
- }
- KASSERT(cpu_info[apic_id].cpu_present == 0, ("CPU %d added twice",
- apic_id));
- cpu_info[apic_id].cpu_present = 1;
- if (boot_cpu) {
- KASSERT(boot_cpu_id == -1,
- ("CPU %d claims to be BSP, but CPU %d already is", apic_id,
- boot_cpu_id));
- boot_cpu_id = apic_id;
- cpu_info[apic_id].cpu_bsp = 1;
- }
- if (mp_ncpus < MAXCPU)
- mp_ncpus++;
- if (bootverbose)
- printf("SMP: Added CPU %d (%s)\n", apic_id, boot_cpu ? "BSP" :
- "AP");
-}
-
-void
-cpu_mp_setmaxid(void)
-{
-
- mp_maxid = MAXCPU - 1;
-}
-
-int
-cpu_mp_probe(void)
-{
-
- /*
- * Always record BSP in CPU map so that the mbuf init code works
- * correctly.
- */
- CPU_SETOF(0, &all_cpus);
- if (mp_ncpus == 0) {
- /*
- * No CPUs were found, so this must be a UP system. Setup
- * the variables to represent a system with a single CPU
- * with an id of 0.
- */
- mp_ncpus = 1;
- return (0);
- }
-
- /* At least one CPU was found. */
- if (mp_ncpus == 1) {
- /*
- * One CPU was found, so this must be a UP system with
- * an I/O APIC.
- */
- return (0);
- }
-
- /* At least two CPUs were found. */
- return (1);
-}
-
-/*
- * Initialize the IPI handlers and start up the AP's.
- */
-void
-cpu_mp_start(void)
-{
- int i;
-
- /* Initialize the logical ID to APIC ID table. */
- for (i = 0; i < MAXCPU; i++) {
- cpu_apic_ids[i] = -1;
- cpu_ipi_pending[i] = 0;
- }
-
- /* Set boot_cpu_id if needed. */
- if (boot_cpu_id == -1) {
- boot_cpu_id = PCPU_GET(apic_id);
- cpu_info[boot_cpu_id].cpu_bsp = 1;
- } else
- KASSERT(boot_cpu_id == PCPU_GET(apic_id),
- ("BSP's APIC ID doesn't match boot_cpu_id"));
- cpu_apic_ids[0] = boot_cpu_id;
- apic_cpuids[boot_cpu_id] = 0;
-
- assign_cpu_ids();
-
- /* Start each Application Processor */
- start_all_aps();
-
- /* Setup the initial logical CPUs info. */
- logical_cpus = 0;
- CPU_ZERO(&logical_cpus_mask);
- if (cpu_feature & CPUID_HTT)
- logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
-
- set_interrupt_apic_ids();
-}
-
-
-static void
-iv_rendezvous(uintptr_t a, uintptr_t b)
-{
- smp_rendezvous_action();
-}
-
-static void
-iv_invltlb(uintptr_t a, uintptr_t b)
-{
- xen_tlb_flush();
-}
-
-static void
-iv_invlpg(uintptr_t a, uintptr_t b)
-{
- xen_invlpg(a);
-}
-
-static void
-iv_invlrng(uintptr_t a, uintptr_t b)
-{
- vm_offset_t start = (vm_offset_t)a;
- vm_offset_t end = (vm_offset_t)b;
-
- while (start < end) {
- xen_invlpg(start);
- start += PAGE_SIZE;
- }
-}
-
-
-static void
-iv_invlcache(uintptr_t a, uintptr_t b)
-{
-
- wbinvd();
- atomic_add_int(&smp_tlb_wait, 1);
-}
-
-static void
-iv_lazypmap(uintptr_t a, uintptr_t b)
-{
- pmap_lazyfix_action();
- atomic_add_int(&smp_tlb_wait, 1);
-}
-
-/*
- * These start from "IPI offset" APIC_IPI_INTS
- */
-static call_data_func_t *ipi_vectors[6] =
-{
- iv_rendezvous,
- iv_invltlb,
- iv_invlpg,
- iv_invlrng,
- iv_invlcache,
- iv_lazypmap,
-};
-
-/*
- * Reschedule call back. Nothing to do,
- * all the work is done automatically when
- * we return from the interrupt.
- */
-static int
-smp_reschedule_interrupt(void *unused)
-{
- int cpu = PCPU_GET(cpuid);
- u_int ipi_bitmap;
-
- ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]);
-
- if (ipi_bitmap & (1 << IPI_PREEMPT)) {
-#ifdef COUNT_IPIS
- (*ipi_preempt_counts[cpu])++;
-#endif
- sched_preempt(curthread);
- }
-
- if (ipi_bitmap & (1 << IPI_AST)) {
-#ifdef COUNT_IPIS
- (*ipi_ast_counts[cpu])++;
-#endif
- /* Nothing to do for AST */
- }
- return (FILTER_HANDLED);
-}
-
-struct _call_data {
- uint16_t func_id;
- uint16_t wait;
- uintptr_t arg1;
- uintptr_t arg2;
- atomic_t started;
- atomic_t finished;
-};
-
-static struct _call_data *call_data;
-
-static int
-smp_call_function_interrupt(void *unused)
-{
- call_data_func_t *func;
- uintptr_t arg1 = call_data->arg1;
- uintptr_t arg2 = call_data->arg2;
- int wait = call_data->wait;
- atomic_t *started = &call_data->started;
- atomic_t *finished = &call_data->finished;
-
- /* We only handle function IPIs, not bitmap IPIs */
- if (call_data->func_id < APIC_IPI_INTS ||
- call_data->func_id > IPI_BITMAP_VECTOR)
- panic("invalid function id %u", call_data->func_id);
-
- func = ipi_vectors[IPI_TO_IDX(call_data->func_id)];
- /*
- * Notify initiating CPU that I've grabbed the data and am
- * about to execute the function
- */
- mb();
- atomic_inc(started);
- /*
- * At this point the info structure may be out of scope unless wait==1
- */
- (*func)(arg1, arg2);
-
- if (wait) {
- mb();
- atomic_inc(finished);
- }
- atomic_add_int(&smp_tlb_wait, 1);
- return (FILTER_HANDLED);
-}
-
-/*
- * Print various information about the SMP system hardware and setup.
- */
-void
-cpu_mp_announce(void)
-{
- int i, x;
-
- /* List CPUs */
- printf(" cpu0 (BSP): APIC ID: %2d\n", boot_cpu_id);
- for (i = 1, x = 0; x <= MAX_APIC_ID; x++) {
- if (!cpu_info[x].cpu_present || cpu_info[x].cpu_bsp)
- continue;
- if (cpu_info[x].cpu_disabled)
- printf(" cpu (AP): APIC ID: %2d (disabled)\n", x);
- else {
- KASSERT(i < mp_ncpus,
- ("mp_ncpus and actual cpus are out of whack"));
- printf(" cpu%d (AP): APIC ID: %2d\n", i++, x);
- }
- }
-}
-
-static int
-xen_smp_cpu_init(unsigned int cpu)
-{
- xen_intr_handle_t *ipi_handle;
- const struct xen_ipi_handler *ipi;
- int idx, rc;
-
- ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
- for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
-
- /*
- * The PCPU variable pc_device is not initialized on i386 PV,
- * so we have to use the root_bus device in order to setup
- * the IPIs.
- */
- rc = xen_intr_alloc_and_bind_ipi(root_bus, cpu,
- ipi->filter, INTR_TYPE_TTY, &ipi_handle[idx]);
- if (rc != 0) {
- printf("Unable to allocate a XEN IPI port. "
- "Error %d\n", rc);
- break;
- }
- xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
- }
-
- for (;idx < nitems(xen_ipis); idx++)
- ipi_handle[idx] = NULL;
-
- if (rc == 0)
- return (0);
-
- /* Either all are successfully mapped, or none at all. */
- for (idx = 0; idx < nitems(xen_ipis); idx++) {
- if (ipi_handle[idx] == NULL)
- continue;
-
- xen_intr_unbind(ipi_handle[idx]);
- ipi_handle[idx] = NULL;
- }
-
- return (rc);
-}
-
-static void
-xen_smp_intr_init_cpus(void *unused)
-{
- int i;
-
- for (i = 0; i < mp_ncpus; i++)
- xen_smp_cpu_init(i);
-}
-
-static void
-xen_smp_intr_setup_cpus(void *unused)
-{
- int i;
-
- for (i = 0; i < mp_ncpus; i++)
- DPCPU_ID_SET(i, vcpu_info,
- &HYPERVISOR_shared_info->vcpu_info[i]);
-}
-
-#define MTOPSIZE (1<<(14 + PAGE_SHIFT))
-
-/*
- * AP CPU's call this to initialize themselves.
- */
-void
-init_secondary(void)
-{
- vm_offset_t addr;
- u_int cpuid;
- int gsel_tss;
-
-
- /* bootAP is set in start_ap() to our ID. */
- PCPU_SET(currentldt, _default_ldt);
- gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
-#if 0
- gdt[bootAP * NGDT + GPROC0_SEL].sd.sd_type = SDT_SYS386TSS;
-#endif
- PCPU_SET(common_tss.tss_esp0, 0); /* not used until after switch */
- PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL));
- PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16);
-#if 0
- PCPU_SET(tss_gdt, &gdt[bootAP * NGDT + GPROC0_SEL].sd);
-
- PCPU_SET(common_tssd, *PCPU_GET(tss_gdt));
-#endif
- PCPU_SET(fsgs_gdt, &gdt[GUFS_SEL].sd);
-
- /*
- * Set to a known state:
- * Set by mpboot.s: CR0_PG, CR0_PE
- * Set by cpu_setregs: CR0_NE, CR0_MP, CR0_TS, CR0_WP, CR0_AM
- */
- /*
- * signal our startup to the BSP.
- */
- mp_naps++;
-
- /* Spin until the BSP releases the AP's. */
- while (!aps_ready)
- ia32_pause();
-
- /* BSP may have changed PTD while we were waiting */
- invltlb();
- for (addr = 0; addr < NKPT * NBPDR - 1; addr += PAGE_SIZE)
- invlpg(addr);
-
-#if 0
- /* set up SSE/NX */
- initializecpu();
-#endif
-
- /* set up FPU state on the AP */
- npxinit(false);
-#if 0
- /* A quick check from sanity claus */
- if (PCPU_GET(apic_id) != lapic_id()) {
- printf("SMP: cpuid = %d\n", PCPU_GET(cpuid));
- printf("SMP: actual apic_id = %d\n", lapic_id());
- printf("SMP: correct apic_id = %d\n", PCPU_GET(apic_id));
- panic("cpuid mismatch! boom!!");
- }
-#endif
-
- /* Initialize curthread. */
- KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
- PCPU_SET(curthread, PCPU_GET(idlethread));
-
- mtx_lock_spin(&ap_boot_mtx);
-#if 0
-
- /* Init local apic for irq's */
- lapic_setup(1);
-#endif
- smp_cpus++;
-
- cpuid = PCPU_GET(cpuid);
- CTR1(KTR_SMP, "SMP: AP CPU #%d Launched", cpuid);
- printf("SMP: AP CPU #%d Launched!\n", cpuid);
-
- /* Determine if we are a logical CPU. */
- if (logical_cpus > 1 && PCPU_GET(apic_id) % logical_cpus != 0)
- CPU_SET(cpuid, &logical_cpus_mask);
-
- /* Determine if we are a hyperthread. */
- if (hyperthreading_cpus > 1 &&
- PCPU_GET(apic_id) % hyperthreading_cpus != 0)
- CPU_SET(cpuid, &hyperthreading_cpus_mask);
-#if 0
- if (bootverbose)
- lapic_dump("AP");
-#endif
- if (smp_cpus == mp_ncpus) {
- /* enable IPI's, tlb shootdown, freezes etc */
- atomic_store_rel_int(&smp_started, 1);
- }
-
- mtx_unlock_spin(&ap_boot_mtx);
-
- /* wait until all the AP's are up */
- while (smp_started == 0)
- ia32_pause();
-
- PCPU_SET(curthread, PCPU_GET(idlethread));
-
- /* Start per-CPU event timers. */
- cpu_initclocks_ap();
-
- /* enter the scheduler */
- sched_throw(NULL);
-
- panic("scheduler returned us to %s", __func__);
- /* NOTREACHED */
-}
-
-/*******************************************************************
- * local functions and data
- */
-
-/*
- * We tell the I/O APIC code about all the CPUs we want to receive
- * interrupts. If we don't want certain CPUs to receive IRQs we
- * can simply not tell the I/O APIC code about them in this function.
- * We also do not tell it about the BSP since it tells itself about
- * the BSP internally to work with UP kernels and on UP machines.
- */
-static void
-set_interrupt_apic_ids(void)
-{
- u_int i, apic_id;
-
- for (i = 0; i < MAXCPU; i++) {
- apic_id = cpu_apic_ids[i];
- if (apic_id == -1)
- continue;
- if (cpu_info[apic_id].cpu_bsp)
- continue;
- if (cpu_info[apic_id].cpu_disabled)
- continue;
-
- /* Don't let hyperthreads service interrupts. */
- if (hyperthreading_cpus > 1 &&
- apic_id % hyperthreading_cpus != 0)
- continue;
-
- intr_add_cpu(i);
- }
-}
-
-/*
- * Assign logical CPU IDs to local APICs.
- */
-static void
-assign_cpu_ids(void)
-{
- u_int i;
-
- /* Check for explicitly disabled CPUs. */
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp)
- continue;
-
- /* Don't use this CPU if it has been disabled by a tunable. */
- if (resource_disabled("lapic", i)) {
- cpu_info[i].cpu_disabled = 1;
- continue;
- }
- }
-
- /*
- * Assign CPU IDs to local APIC IDs and disable any CPUs
- * beyond MAXCPU. CPU 0 has already been assigned to the BSP,
- * so we only have to assign IDs for APs.
- */
- mp_ncpus = 1;
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp ||
- cpu_info[i].cpu_disabled)
- continue;
-
- if (mp_ncpus < MAXCPU) {
- cpu_apic_ids[mp_ncpus] = i;
- apic_cpuids[i] = mp_ncpus;
- mp_ncpus++;
- } else
- cpu_info[i].cpu_disabled = 1;
- }
- KASSERT(mp_maxid >= mp_ncpus - 1,
- ("%s: counters out of sync: max %d, count %d", __func__, mp_maxid,
- mp_ncpus));
-}
-
-/*
- * start each AP in our list
- */
-/* Lowest 1MB is already mapped: don't touch*/
-#define TMPMAP_START 1
-int
-start_all_aps(void)
-{
- int x,apic_id, cpu;
- struct pcpu *pc;
-
- mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
-
- /* set up temporary P==V mapping for AP boot */
- /* XXX this is a hack, we should boot the AP on its own stack/PTD */
-
- /* start each AP */
- for (cpu = 1; cpu < mp_ncpus; cpu++) {
- apic_id = cpu_apic_ids[cpu];
-
-
- bootAP = cpu;
- bootAPgdt = gdt + (512*cpu);
-
- /* Get per-cpu data */
- pc = &__pcpu[bootAP];
- pcpu_init(pc, bootAP, sizeof(struct pcpu));
- dpcpu_init((void *)kmem_malloc(kernel_arena, DPCPU_SIZE,
- M_WAITOK | M_ZERO), bootAP);
- pc->pc_apic_id = cpu_apic_ids[bootAP];
- pc->pc_vcpu_id = cpu_apic_ids[bootAP];
- pc->pc_prvspace = pc;
- pc->pc_curthread = 0;
-
- gdt_segs[GPRIV_SEL].ssd_base = (int) pc;
- gdt_segs[GPROC0_SEL].ssd_base = (int) &pc->pc_common_tss;
-
- PT_SET_MA(bootAPgdt, VTOM(bootAPgdt) | PG_V | PG_RW);
- bzero(bootAPgdt, PAGE_SIZE);
- for (x = 0; x < NGDT; x++)
- ssdtosd(&gdt_segs[x], &bootAPgdt[x].sd);
- PT_SET_MA(bootAPgdt, vtomach(bootAPgdt) | PG_V);
-#ifdef notyet
-
- if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, cpu, &cpu_id) == 0) {
- apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id);
- acpiid = xen_vcpu_physid_to_x86_acpiid(cpu_id.phys_id);
-#ifdef CONFIG_ACPI
- if (acpiid != 0xff)
- x86_acpiid_to_apicid[acpiid] = apicid;
-#endif
- }
-#endif
-
- /* attempt to start the Application Processor */
- if (!start_ap(cpu)) {
- printf("AP #%d (PHY# %d) failed!\n", cpu, apic_id);
- /* better panic as the AP may be running loose */
- printf("panic y/n? [y] ");
- if (cngetc() != 'n')
- panic("bye-bye");
- }
-
- CPU_SET(cpu, &all_cpus); /* record AP in CPU map */
- }
-
-
- pmap_invalidate_range(kernel_pmap, 0, NKPT * NBPDR - 1);
-
- /* number of APs actually started */
- return (mp_naps);
-}
-
-extern uint8_t *pcpu_boot_stack;
-extern trap_info_t trap_table[];
-
-static void
-smp_trap_init(trap_info_t *trap_ctxt)
-{
- const trap_info_t *t = trap_table;
-
- for (t = trap_table; t->address; t++) {
- trap_ctxt[t->vector].flags = t->flags;
- trap_ctxt[t->vector].cs = t->cs;
- trap_ctxt[t->vector].address = t->address;
- }
-}
-
-extern struct rwlock pvh_global_lock;
-extern int nkpt;
-static void
-cpu_initialize_context(unsigned int cpu)
-{
- /* vcpu_guest_context_t is too large to allocate on the stack.
- * Hence we allocate statically and protect it with a lock */
- vm_page_t m[NPGPTD + 2];
- static vcpu_guest_context_t ctxt;
- vm_offset_t boot_stack;
- vm_offset_t newPTD;
- vm_paddr_t ma[NPGPTD];
- int i;
-
- /*
- * Page 0,[0-3] PTD
- * Page 1, [4] boot stack
- * Page [5] PDPT
- *
- */
- for (i = 0; i < NPGPTD + 2; i++) {
- m[i] = vm_page_alloc(NULL, 0,
- VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
- VM_ALLOC_ZERO);
-
- pmap_zero_page(m[i]);
-
- }
- boot_stack = kva_alloc(PAGE_SIZE);
- newPTD = kva_alloc(NPGPTD * PAGE_SIZE);
- ma[0] = VM_PAGE_TO_MACH(m[0])|PG_V;
-
-#ifdef PAE
- pmap_kenter(boot_stack, VM_PAGE_TO_PHYS(m[NPGPTD + 1]));
- for (i = 0; i < NPGPTD; i++) {
- ((vm_paddr_t *)boot_stack)[i] =
- ma[i] = VM_PAGE_TO_MACH(m[i])|PG_V;
- }
-#endif
-
- /*
- * Copy cpu0 IdlePTD to new IdlePTD - copying only
- * kernel mappings
- */
- pmap_qenter(newPTD, m, 4);
-
- memcpy((uint8_t *)newPTD + KPTDI*sizeof(vm_paddr_t),
- (uint8_t *)PTOV(IdlePTD) + KPTDI*sizeof(vm_paddr_t),
- nkpt*sizeof(vm_paddr_t));
-
- pmap_qremove(newPTD, 4);
- kva_free(newPTD, 4 * PAGE_SIZE);
- /*
- * map actual idle stack to boot_stack
- */
- pmap_kenter(boot_stack, VM_PAGE_TO_PHYS(m[NPGPTD]));
-
-
- xen_pgdpt_pin(VM_PAGE_TO_MACH(m[NPGPTD + 1]));
- rw_wlock(&pvh_global_lock);
- for (i = 0; i < 4; i++) {
- int pdir = (PTDPTDI + i) / NPDEPG;
- int curoffset = (PTDPTDI + i) % NPDEPG;
-
- xen_queue_pt_update((vm_paddr_t)
- ((ma[pdir] & ~PG_V) + (curoffset*sizeof(vm_paddr_t))),
- ma[i]);
- }
- PT_UPDATES_FLUSH();
- rw_wunlock(&pvh_global_lock);
-
- memset(&ctxt, 0, sizeof(ctxt));
- ctxt.flags = VGCF_IN_KERNEL;
- ctxt.user_regs.ds = GSEL(GDATA_SEL, SEL_KPL);
- ctxt.user_regs.es = GSEL(GDATA_SEL, SEL_KPL);
- ctxt.user_regs.fs = GSEL(GPRIV_SEL, SEL_KPL);
- ctxt.user_regs.gs = GSEL(GDATA_SEL, SEL_KPL);
- ctxt.user_regs.cs = GSEL(GCODE_SEL, SEL_KPL);
- ctxt.user_regs.ss = GSEL(GDATA_SEL, SEL_KPL);
- ctxt.user_regs.eip = (unsigned long)init_secondary;
- ctxt.user_regs.eflags = PSL_KERNEL | 0x1000; /* IOPL_RING1 */
-
- memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
-
- smp_trap_init(ctxt.trap_ctxt);
-
- ctxt.ldt_ents = 0;
- ctxt.gdt_frames[0] =
- (uint32_t)((uint64_t)vtomach(bootAPgdt) >> PAGE_SHIFT);
- ctxt.gdt_ents = 512;
-
-#ifdef __i386__
- ctxt.user_regs.esp = boot_stack + PAGE_SIZE;
-
- ctxt.kernel_ss = GSEL(GDATA_SEL, SEL_KPL);
- ctxt.kernel_sp = boot_stack + PAGE_SIZE;
-
- ctxt.event_callback_cs = GSEL(GCODE_SEL, SEL_KPL);
- ctxt.event_callback_eip = (unsigned long)Xhypervisor_callback;
- ctxt.failsafe_callback_cs = GSEL(GCODE_SEL, SEL_KPL);
- ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
-
- ctxt.ctrlreg[3] = VM_PAGE_TO_MACH(m[NPGPTD + 1]);
-#else /* __x86_64__ */
- ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs);
- ctxt.kernel_ss = GSEL(GDATA_SEL, SEL_KPL);
- ctxt.kernel_sp = idle->thread.rsp0;
-
- ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
- ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
- ctxt.syscall_callback_eip = (unsigned long)system_call;
-
- ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt));
-
- ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu));
-#endif
-
- printf("gdtpfn=%lx pdptpfn=%lx\n",
- ctxt.gdt_frames[0],
- ctxt.ctrlreg[3] >> PAGE_SHIFT);
-
- PANIC_IF(HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, &ctxt));
- DELAY(3000);
- PANIC_IF(HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL));
-}
-
-/*
- * This function starts the AP (application processor) identified
- * by the APIC ID 'physicalCpu'. It does quite a "song and dance"
- * to accomplish this. This is necessary because of the nuances
- * of the different hardware we might encounter. It isn't pretty,
- * but it seems to work.
- */
-
-int cpus;
-static int
-start_ap(int apic_id)
-{
- int ms;
-
- /* used as a watchpoint to signal AP startup */
- cpus = mp_naps;
-
- cpu_initialize_context(apic_id);
-
- /* Wait up to 5 seconds for it to start. */
- for (ms = 0; ms < 5000; ms++) {
- if (mp_naps > cpus)
- return (1); /* return SUCCESS */
- DELAY(1000);
- }
- return (0); /* return FAILURE */
-}
-
-static void
-ipi_pcpu(int cpu, u_int ipi)
-{
- KASSERT((ipi <= nitems(xen_ipis)), ("invalid IPI"));
- xen_intr_signal(DPCPU_ID_GET(cpu, ipi_handle[ipi]));
-}
-
-/*
- * send an IPI to a specific CPU.
- */
-static void
-ipi_send_cpu(int cpu, u_int ipi)
-{
- u_int bitmap, old_pending, new_pending;
-
- if (IPI_IS_BITMAPED(ipi)) {
- bitmap = 1 << ipi;
- ipi = IPI_BITMAP_VECTOR;
- do {
- old_pending = cpu_ipi_pending[cpu];
- new_pending = old_pending | bitmap;
- } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu],
- old_pending, new_pending));
- if (!old_pending)
- ipi_pcpu(cpu, RESCHEDULE_VECTOR);
- } else {
- KASSERT(call_data != NULL, ("call_data not set"));
- ipi_pcpu(cpu, CALL_FUNCTION_VECTOR);
- }
-}
-
-/*
- * Flush the TLB on all other CPU's
- */
-static void
-smp_tlb_shootdown(u_int vector, vm_offset_t addr1, vm_offset_t addr2)
-{
- u_int ncpu;
- struct _call_data data;
-
- ncpu = mp_ncpus - 1; /* does not shootdown self */
- if (ncpu < 1)
- return; /* no other cpus */
- if (!(read_eflags() & PSL_I))
- panic("%s: interrupts disabled", __func__);
- mtx_lock_spin(&smp_ipi_mtx);
- KASSERT(call_data == NULL, ("call_data isn't null?!"));
- call_data = &data;
- call_data->func_id = vector;
- call_data->arg1 = addr1;
- call_data->arg2 = addr2;
- atomic_store_rel_int(&smp_tlb_wait, 0);
- ipi_all_but_self(vector);
- while (smp_tlb_wait < ncpu)
- ia32_pause();
- call_data = NULL;
- mtx_unlock_spin(&smp_ipi_mtx);
-}
-
-static void
-smp_targeted_tlb_shootdown(cpuset_t mask, u_int vector, vm_offset_t addr1,
- vm_offset_t addr2)
-{
- int cpu, ncpu, othercpus;
- struct _call_data data;
-
- othercpus = mp_ncpus - 1;
- if (CPU_ISFULLSET(&mask)) {
- if (othercpus < 1)
- return;
- } else {
- CPU_CLR(PCPU_GET(cpuid), &mask);
- if (CPU_EMPTY(&mask))
- return;
- }
- if (!(read_eflags() & PSL_I))
- panic("%s: interrupts disabled", __func__);
- mtx_lock_spin(&smp_ipi_mtx);
- KASSERT(call_data == NULL, ("call_data isn't null?!"));
- call_data = &data;
- call_data->func_id = vector;
- call_data->arg1 = addr1;
- call_data->arg2 = addr2;
- atomic_store_rel_int(&smp_tlb_wait, 0);
- if (CPU_ISFULLSET(&mask)) {
- ncpu = othercpus;
- ipi_all_but_self(vector);
- } else {
- ncpu = 0;
- while ((cpu = CPU_FFS(&mask)) != 0) {
- cpu--;
- CPU_CLR(cpu, &mask);
- CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu,
- vector);
- ipi_send_cpu(cpu, vector);
- ncpu++;
- }
- }
- while (smp_tlb_wait < ncpu)
- ia32_pause();
- call_data = NULL;
- mtx_unlock_spin(&smp_ipi_mtx);
-}
-
-void
-smp_cache_flush(void)
-{
-
- if (smp_started)
- smp_tlb_shootdown(IPI_INVLCACHE, 0, 0);
-}
-
-void
-smp_invltlb(void)
-{
-
- if (smp_started) {
- smp_tlb_shootdown(IPI_INVLTLB, 0, 0);
- }
-}
-
-void
-smp_invlpg(vm_offset_t addr)
-{
-
- if (smp_started) {
- smp_tlb_shootdown(IPI_INVLPG, addr, 0);
- }
-}
-
-void
-smp_invlpg_range(vm_offset_t addr1, vm_offset_t addr2)
-{
-
- if (smp_started) {
- smp_tlb_shootdown(IPI_INVLRNG, addr1, addr2);
- }
-}
-
-void
-smp_masked_invltlb(cpuset_t mask)
-{
-
- if (smp_started) {
- smp_targeted_tlb_shootdown(mask, IPI_INVLTLB, 0, 0);
- }
-}
-
-void
-smp_masked_invlpg(cpuset_t mask, vm_offset_t addr)
-{
-
- if (smp_started) {
- smp_targeted_tlb_shootdown(mask, IPI_INVLPG, addr, 0);
- }
-}
-
-void
-smp_masked_invlpg_range(cpuset_t mask, vm_offset_t addr1, vm_offset_t addr2)
-{
-
- if (smp_started) {
- smp_targeted_tlb_shootdown(mask, IPI_INVLRNG, addr1, addr2);
- }
-}
-
-/*
- * send an IPI to a set of cpus.
- */
-void
-ipi_selected(cpuset_t cpus, u_int ipi)
-{
- int cpu;
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_OR_ATOMIC(&ipi_nmi_pending, &cpus);
-
- while ((cpu = CPU_FFS(&cpus)) != 0) {
- cpu--;
- CPU_CLR(cpu, &cpus);
- CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
- ipi_send_cpu(cpu, ipi);
- }
-}
-
-/*
- * send an IPI to a specific CPU.
- */
-void
-ipi_cpu(int cpu, u_int ipi)
-{
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- if (ipi == IPI_STOP_HARD)
- CPU_SET_ATOMIC(cpu, &ipi_nmi_pending);
-
- CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
- ipi_send_cpu(cpu, ipi);
-}
-
-/*
- * send an IPI to all CPUs EXCEPT myself
- */
-void
-ipi_all_but_self(u_int ipi)
-{
- cpuset_t other_cpus;
-
- /*
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- */
- other_cpus = all_cpus;
- CPU_CLR(PCPU_GET(cpuid), &other_cpus);
- if (ipi == IPI_STOP_HARD)
- CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
-
- CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
- ipi_selected(other_cpus, ipi);
-}
-
-int
-ipi_nmi_handler()
-{
- u_int cpuid;
-
- /*
- * As long as there is not a simple way to know about a NMI's
- * source, if the bitmask for the current CPU is present in
- * the global pending bitword an IPI_STOP_HARD has been issued
- * and should be handled.
- */
- cpuid = PCPU_GET(cpuid);
- if (!CPU_ISSET(cpuid, &ipi_nmi_pending))
- return (1);
-
- CPU_CLR_ATOMIC(cpuid, &ipi_nmi_pending);
- cpustop_handler();
- return (0);
-}
-
-/*
- * Handle an IPI_STOP by saving our current context and spinning until we
- * are resumed.
- */
-void
-cpustop_handler(void)
-{
- int cpu;
-
- cpu = PCPU_GET(cpuid);
-
- savectx(&stoppcbs[cpu]);
-
- /* Indicate that we are stopped */
- CPU_SET_ATOMIC(cpu, &stopped_cpus);
-
- /* Wait for restart */
- while (!CPU_ISSET(cpu, &started_cpus))
- ia32_pause();
-
- CPU_CLR_ATOMIC(cpu, &started_cpus);
- CPU_CLR_ATOMIC(cpu, &stopped_cpus);
-
- if (cpu == 0 && cpustop_restartfunc != NULL) {
- cpustop_restartfunc();
- cpustop_restartfunc = NULL;
- }
-}
-
-/*
- * Handlers for TLB related IPIs
- *
- * On i386 Xen PV this are no-ops since this port doesn't support SMP.
- */
-void
-invltlb_handler(void)
-{
-}
-
-void
-invlpg_handler(void)
-{
-}
-
-void
-invlrng_handler(void)
-{
-}
-
-void
-invlcache_handler(void)
-{
-}
-
-/*
- * This is called once the rest of the system is up and running and we're
- * ready to let the AP's out of the pen.
- */
-static void
-release_aps(void *dummy __unused)
-{
-
- if (mp_ncpus == 1)
- return;
- atomic_store_rel_int(&aps_ready, 1);
- while (smp_started == 0)
- ia32_pause();
-}
-SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
-SYSINIT(start_ipis, SI_SUB_SMP, SI_ORDER_ANY, xen_smp_intr_init_cpus, NULL);
-SYSINIT(start_cpu, SI_SUB_INTR, SI_ORDER_ANY, xen_smp_intr_setup_cpus, NULL);
diff --git a/sys/i386/xen/mptable.c b/sys/i386/xen/mptable.c
deleted file mode 100644
index 81d7c1b..0000000
--- a/sys/i386/xen/mptable.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*-
- * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
- * Copyright (c) 1996, by Steve Passe
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the developer may NOT be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
-
-#include <machine/frame.h>
-#include <machine/intr_machdep.h>
-#include <x86/apicvar.h>
-
-#include <xen/hypervisor.h>
-#include <xen/xen-os.h>
-#include <machine/smp.h>
-#include <xen/interface/vcpu.h>
-
-
-static int mptable_probe(void);
-static int mptable_probe_cpus(void);
-static void mptable_register(void *dummy);
-static int mptable_setup_local(void);
-static int mptable_setup_io(void);
-
-static struct apic_enumerator mptable_enumerator = {
- "MPTable",
- mptable_probe,
- mptable_probe_cpus,
- mptable_setup_local,
- mptable_setup_io
-};
-
-static int
-mptable_probe(void)
-{
-
- return (-100);
-}
-
-static int
-mptable_probe_cpus(void)
-{
- int i, rc;
-
- for (i = 0; i < MAXCPU; i++) {
- rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
- if (rc >= 0)
- cpu_add(i, (i == 0));
- }
-
- return (0);
-}
-
-/*
- * Initialize the local APIC on the BSP.
- */
-static int
-mptable_setup_local(void)
-{
-
- PCPU_SET(apic_id, 0);
- PCPU_SET(vcpu_id, 0);
- return (0);
-}
-
-static int
-mptable_setup_io(void)
-{
-
- return (0);
-}
-
-static void
-mptable_register(void *dummy __unused)
-{
-
- apic_register_enumerator(&mptable_enumerator);
-}
-SYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, mptable_register,
- NULL);
diff --git a/sys/i386/xen/pmap.c b/sys/i386/xen/pmap.c
deleted file mode 100644
index 1dc50b2..0000000
--- a/sys/i386/xen/pmap.c
+++ /dev/null
@@ -1,4520 +0,0 @@
-/*-
- * Copyright (c) 1991 Regents of the University of California.
- * All rights reserved.
- * Copyright (c) 1994 John S. Dyson
- * All rights reserved.
- * Copyright (c) 1994 David Greenman
- * All rights reserved.
- * Copyright (c) 2005 Alan L. Cox <alc@cs.rice.edu>
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * the Systems Programming Group of the University of Utah Computer
- * Science Department and William Jolitz of UUNET Technologies Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
- */
-/*-
- * Copyright (c) 2003 Networks Associates Technology, Inc.
- * All rights reserved.
- *
- * This software was developed for the FreeBSD Project by Jake Burkholder,
- * Safeport Network Services, and Network Associates Laboratories, the
- * Security Research Division of Network Associates, Inc. under
- * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
- * CHATS research program.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Manages physical address maps.
- *
- * Since the information managed by this module is
- * also stored by the logical address mapping module,
- * this module may throw away valid virtual-to-physical
- * mappings at almost any time. However, invalidations
- * of virtual-to-physical mappings must be done as
- * requested.
- *
- * In order to cope with hardware architectures which
- * make virtual-to-physical map invalidates expensive,
- * this module may delay invalidate or reduced protection
- * operations until such time as they are actually
- * necessary. This module is given full information as
- * to which processors are currently using which maps,
- * and to when physical maps must be made correct.
- */
-
-#include "opt_cpu.h"
-#include "opt_pmap.h"
-#include "opt_smp.h"
-#include "opt_xbox.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/ktr.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mman.h>
-#include <sys/msgbuf.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/rwlock.h>
-#include <sys/sf_buf.h>
-#include <sys/sx.h>
-#include <sys/vmmeter.h>
-#include <sys/sched.h>
-#include <sys/sysctl.h>
-#ifdef SMP
-#include <sys/smp.h>
-#else
-#include <sys/cpuset.h>
-#endif
-
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/vm_kern.h>
-#include <vm/vm_page.h>
-#include <vm/vm_map.h>
-#include <vm/vm_object.h>
-#include <vm/vm_extern.h>
-#include <vm/vm_pageout.h>
-#include <vm/vm_pager.h>
-#include <vm/uma.h>
-
-#include <machine/cpu.h>
-#include <machine/cputypes.h>
-#include <machine/md_var.h>
-#include <machine/pcb.h>
-#include <machine/specialreg.h>
-#ifdef SMP
-#include <machine/smp.h>
-#endif
-
-#ifdef XBOX
-#include <machine/xbox.h>
-#endif
-
-#include <xen/interface/xen.h>
-#include <xen/hypervisor.h>
-#include <machine/xen/hypercall.h>
-#include <machine/xen/xenvar.h>
-#include <machine/xen/xenfunc.h>
-
-#if !defined(CPU_DISABLE_SSE) && defined(I686_CPU)
-#define CPU_ENABLE_SSE
-#endif
-
-#ifndef PMAP_SHPGPERPROC
-#define PMAP_SHPGPERPROC 200
-#endif
-
-#define DIAGNOSTIC
-
-#if !defined(DIAGNOSTIC)
-#ifdef __GNUC_GNU_INLINE__
-#define PMAP_INLINE __attribute__((__gnu_inline__)) inline
-#else
-#define PMAP_INLINE extern inline
-#endif
-#else
-#define PMAP_INLINE
-#endif
-
-#ifdef PV_STATS
-#define PV_STAT(x) do { x ; } while (0)
-#else
-#define PV_STAT(x) do { } while (0)
-#endif
-
-/*
- * Get PDEs and PTEs for user/kernel address space
- */
-#define pmap_pde(m, v) (&((m)->pm_pdir[(vm_offset_t)(v) >> PDRSHIFT]))
-#define pdir_pde(m, v) (m[(vm_offset_t)(v) >> PDRSHIFT])
-
-#define pmap_pde_v(pte) ((*(int *)pte & PG_V) != 0)
-#define pmap_pte_w(pte) ((*(int *)pte & PG_W) != 0)
-#define pmap_pte_m(pte) ((*(int *)pte & PG_M) != 0)
-#define pmap_pte_u(pte) ((*(int *)pte & PG_A) != 0)
-#define pmap_pte_v(pte) ((*(int *)pte & PG_V) != 0)
-
-#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v)))
-
-#define HAMFISTED_LOCKING
-#ifdef HAMFISTED_LOCKING
-static struct mtx createdelete_lock;
-#endif
-
-struct pmap kernel_pmap_store;
-LIST_HEAD(pmaplist, pmap);
-static struct pmaplist allpmaps;
-static struct mtx allpmaps_lock;
-
-vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss) */
-vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
-int pgeflag = 0; /* PG_G or-in */
-int pseflag = 0; /* PG_PS or-in */
-
-int nkpt;
-vm_offset_t kernel_vm_end;
-extern u_int32_t KERNend;
-
-#ifdef PAE
-pt_entry_t pg_nx;
-#endif
-
-static SYSCTL_NODE(_vm, OID_AUTO, pmap, CTLFLAG_RD, 0, "VM/pmap parameters");
-
-static int pat_works; /* Is page attribute table sane? */
-
-/*
- * This lock is defined as static in other pmap implementations. It cannot,
- * however, be defined as static here, because it is (ab)used to serialize
- * queued page table changes in other sources files.
- */
-struct rwlock pvh_global_lock;
-
-/*
- * Data for the pv entry allocation mechanism
- */
-static TAILQ_HEAD(pch, pv_chunk) pv_chunks = TAILQ_HEAD_INITIALIZER(pv_chunks);
-static int pv_entry_count = 0, pv_entry_max = 0, pv_entry_high_water = 0;
-static int shpgperproc = PMAP_SHPGPERPROC;
-
-struct pv_chunk *pv_chunkbase; /* KVA block for pv_chunks */
-int pv_maxchunks; /* How many chunks we have KVA for */
-vm_offset_t pv_vafree; /* freelist stored in the PTE */
-
-/*
- * All those kernel PT submaps that BSD is so fond of
- */
-struct sysmaps {
- struct mtx lock;
- pt_entry_t *CMAP1;
- pt_entry_t *CMAP2;
- caddr_t CADDR1;
- caddr_t CADDR2;
-};
-static struct sysmaps sysmaps_pcpu[MAXCPU];
-pt_entry_t *CMAP3;
-caddr_t ptvmmap = 0;
-caddr_t CADDR3;
-struct msgbuf *msgbufp = 0;
-
-/*
- * Crashdump maps.
- */
-static caddr_t crashdumpmap;
-
-static pt_entry_t *PMAP1 = 0, *PMAP2;
-static pt_entry_t *PADDR1 = 0, *PADDR2;
-#ifdef SMP
-static int PMAP1cpu;
-static int PMAP1changedcpu;
-SYSCTL_INT(_debug, OID_AUTO, PMAP1changedcpu, CTLFLAG_RD,
- &PMAP1changedcpu, 0,
- "Number of times pmap_pte_quick changed CPU with same PMAP1");
-#endif
-static int PMAP1changed;
-SYSCTL_INT(_debug, OID_AUTO, PMAP1changed, CTLFLAG_RD,
- &PMAP1changed, 0,
- "Number of times pmap_pte_quick changed PMAP1");
-static int PMAP1unchanged;
-SYSCTL_INT(_debug, OID_AUTO, PMAP1unchanged, CTLFLAG_RD,
- &PMAP1unchanged, 0,
- "Number of times pmap_pte_quick didn't change PMAP1");
-static struct mtx PMAP2mutex;
-
-static void free_pv_chunk(struct pv_chunk *pc);
-static void free_pv_entry(pmap_t pmap, pv_entry_t pv);
-static pv_entry_t get_pv_entry(pmap_t pmap, boolean_t try);
-static void pmap_pvh_free(struct md_page *pvh, pmap_t pmap, vm_offset_t va);
-static pv_entry_t pmap_pvh_remove(struct md_page *pvh, pmap_t pmap,
- vm_offset_t va);
-
-static vm_page_t pmap_enter_quick_locked(multicall_entry_t **mcl, int *count, pmap_t pmap, vm_offset_t va,
- vm_page_t m, vm_prot_t prot, vm_page_t mpte);
-static void pmap_flush_page(vm_page_t m);
-static void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int mode);
-static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t sva,
- vm_page_t *free);
-static void pmap_remove_page(struct pmap *pmap, vm_offset_t va,
- vm_page_t *free);
-static void pmap_remove_entry(struct pmap *pmap, vm_page_t m,
- vm_offset_t va);
-static boolean_t pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va,
- vm_page_t m);
-
-static vm_page_t pmap_allocpte(pmap_t pmap, vm_offset_t va, u_int flags);
-
-static vm_page_t _pmap_allocpte(pmap_t pmap, u_int ptepindex, u_int flags);
-static void _pmap_unwire_ptp(pmap_t pmap, vm_page_t m, vm_page_t *free);
-static pt_entry_t *pmap_pte_quick(pmap_t pmap, vm_offset_t va);
-static void pmap_pte_release(pt_entry_t *pte);
-static int pmap_unuse_pt(pmap_t, vm_offset_t, vm_page_t *);
-static boolean_t pmap_is_prefaultable_locked(pmap_t pmap, vm_offset_t addr);
-
-static __inline void pagezero(void *page);
-
-CTASSERT(1 << PDESHIFT == sizeof(pd_entry_t));
-CTASSERT(1 << PTESHIFT == sizeof(pt_entry_t));
-
-/*
- * If you get an error here, then you set KVA_PAGES wrong! See the
- * description of KVA_PAGES in sys/i386/include/pmap.h. It must be
- * multiple of 4 for a normal kernel, or a multiple of 8 for a PAE.
- */
-CTASSERT(KERNBASE % (1 << 24) == 0);
-
-void
-pd_set(struct pmap *pmap, int ptepindex, vm_paddr_t val, int type)
-{
- vm_paddr_t pdir_ma = vtomach(&pmap->pm_pdir[ptepindex]);
-
- switch (type) {
- case SH_PD_SET_VA:
-#if 0
- xen_queue_pt_update(shadow_pdir_ma,
- xpmap_ptom(val & ~(PG_RW)));
-#endif
- xen_queue_pt_update(pdir_ma,
- xpmap_ptom(val));
- break;
- case SH_PD_SET_VA_MA:
-#if 0
- xen_queue_pt_update(shadow_pdir_ma,
- val & ~(PG_RW));
-#endif
- xen_queue_pt_update(pdir_ma, val);
- break;
- case SH_PD_SET_VA_CLEAR:
-#if 0
- xen_queue_pt_update(shadow_pdir_ma, 0);
-#endif
- xen_queue_pt_update(pdir_ma, 0);
- break;
- }
-}
-
-/*
- * Bootstrap the system enough to run with virtual memory.
- *
- * On the i386 this is called after mapping has already been enabled
- * and just syncs the pmap module with what has already been done.
- * [We can't call it easily with mapping off since the kernel is not
- * mapped with PA == VA, hence we would have to relocate every address
- * from the linked base (virtual) address "KERNBASE" to the actual
- * (physical) address starting relative to 0]
- */
-void
-pmap_bootstrap(vm_paddr_t firstaddr)
-{
- vm_offset_t va;
- pt_entry_t *pte, *unused;
- struct sysmaps *sysmaps;
- int i;
-
- /*
- * Initialize the first available kernel virtual address. However,
- * using "firstaddr" may waste a few pages of the kernel virtual
- * address space, because locore may not have mapped every physical
- * page that it allocated. Preferably, locore would provide a first
- * unused virtual address in addition to "firstaddr".
- */
- virtual_avail = (vm_offset_t) KERNBASE + firstaddr;
-
- virtual_end = VM_MAX_KERNEL_ADDRESS;
-
- /*
- * Initialize the kernel pmap (which is statically allocated).
- */
- PMAP_LOCK_INIT(kernel_pmap);
- kernel_pmap->pm_pdir = (pd_entry_t *) (KERNBASE + (u_int)IdlePTD);
-#ifdef PAE
- kernel_pmap->pm_pdpt = (pdpt_entry_t *) (KERNBASE + (u_int)IdlePDPT);
-#endif
- CPU_FILL(&kernel_pmap->pm_active); /* don't allow deactivation */
- TAILQ_INIT(&kernel_pmap->pm_pvchunk);
-
- /*
- * Initialize the global pv list lock.
- */
- rw_init_flags(&pvh_global_lock, "pmap pv global", RW_RECURSE);
-
- LIST_INIT(&allpmaps);
- mtx_init(&allpmaps_lock, "allpmaps", NULL, MTX_SPIN);
- mtx_lock_spin(&allpmaps_lock);
- LIST_INSERT_HEAD(&allpmaps, kernel_pmap, pm_list);
- mtx_unlock_spin(&allpmaps_lock);
- if (nkpt == 0)
- nkpt = NKPT;
-
- /*
- * Reserve some special page table entries/VA space for temporary
- * mapping of pages.
- */
-#define SYSMAP(c, p, v, n) \
- v = (c)va; va += ((n)*PAGE_SIZE); p = pte; pte += (n);
-
- va = virtual_avail;
- pte = vtopte(va);
-
- /*
- * CMAP1/CMAP2 are used for zeroing and copying pages.
- * CMAP3 is used for the idle process page zeroing.
- */
- for (i = 0; i < MAXCPU; i++) {
- sysmaps = &sysmaps_pcpu[i];
- mtx_init(&sysmaps->lock, "SYSMAPS", NULL, MTX_DEF);
- SYSMAP(caddr_t, sysmaps->CMAP1, sysmaps->CADDR1, 1)
- SYSMAP(caddr_t, sysmaps->CMAP2, sysmaps->CADDR2, 1)
- PT_SET_MA(sysmaps->CADDR1, 0);
- PT_SET_MA(sysmaps->CADDR2, 0);
- }
- SYSMAP(caddr_t, CMAP3, CADDR3, 1)
- PT_SET_MA(CADDR3, 0);
-
- /*
- * Crashdump maps.
- */
- SYSMAP(caddr_t, unused, crashdumpmap, MAXDUMPPGS)
-
- /*
- * ptvmmap is used for reading arbitrary physical pages via /dev/mem.
- */
- SYSMAP(caddr_t, unused, ptvmmap, 1)
-
- /*
- * msgbufp is used to map the system message buffer.
- */
- SYSMAP(struct msgbuf *, unused, msgbufp, atop(round_page(msgbufsize)))
-
- /*
- * PADDR1 and PADDR2 are used by pmap_pte_quick() and pmap_pte(),
- * respectively.
- */
- SYSMAP(pt_entry_t *, PMAP1, PADDR1, 1)
- SYSMAP(pt_entry_t *, PMAP2, PADDR2, 1)
-
- mtx_init(&PMAP2mutex, "PMAP2", NULL, MTX_DEF);
-
- virtual_avail = va;
-
- /*
- * Leave in place an identity mapping (virt == phys) for the low 1 MB
- * physical memory region that is used by the ACPI wakeup code. This
- * mapping must not have PG_G set.
- */
-#ifndef XEN
- /*
- * leave here deliberately to show that this is not supported
- */
-#ifdef XBOX
- /* FIXME: This is gross, but needed for the XBOX. Since we are in such
- * an early stadium, we cannot yet neatly map video memory ... :-(
- * Better fixes are very welcome! */
- if (!arch_i386_is_xbox)
-#endif
- for (i = 1; i < NKPT; i++)
- PTD[i] = 0;
-
- /* Initialize the PAT MSR if present. */
- pmap_init_pat();
-
- /* Turn on PG_G on kernel page(s) */
- pmap_set_pg();
-#endif
-
-#ifdef HAMFISTED_LOCKING
- mtx_init(&createdelete_lock, "pmap create/delete", NULL, MTX_DEF);
-#endif
-}
-
-/*
- * Setup the PAT MSR.
- */
-void
-pmap_init_pat(void)
-{
- uint64_t pat_msr;
-
- /* Bail if this CPU doesn't implement PAT. */
- if (!(cpu_feature & CPUID_PAT))
- return;
-
- if (cpu_vendor_id != CPU_VENDOR_INTEL ||
- (CPUID_TO_FAMILY(cpu_id) == 6 && CPUID_TO_MODEL(cpu_id) >= 0xe)) {
- /*
- * Leave the indices 0-3 at the default of WB, WT, UC, and UC-.
- * Program 4 and 5 as WP and WC.
- * Leave 6 and 7 as UC and UC-.
- */
- pat_msr = rdmsr(MSR_PAT);
- pat_msr &= ~(PAT_MASK(4) | PAT_MASK(5));
- pat_msr |= PAT_VALUE(4, PAT_WRITE_PROTECTED) |
- PAT_VALUE(5, PAT_WRITE_COMBINING);
- pat_works = 1;
- } else {
- /*
- * Due to some Intel errata, we can only safely use the lower 4
- * PAT entries. Thus, just replace PAT Index 2 with WC instead
- * of UC-.
- *
- * Intel Pentium III Processor Specification Update
- * Errata E.27 (Upper Four PAT Entries Not Usable With Mode B
- * or Mode C Paging)
- *
- * Intel Pentium IV Processor Specification Update
- * Errata N46 (PAT Index MSB May Be Calculated Incorrectly)
- */
- pat_msr = rdmsr(MSR_PAT);
- pat_msr &= ~PAT_MASK(2);
- pat_msr |= PAT_VALUE(2, PAT_WRITE_COMBINING);
- pat_works = 0;
- }
- wrmsr(MSR_PAT, pat_msr);
-}
-
-/*
- * Initialize a vm_page's machine-dependent fields.
- */
-void
-pmap_page_init(vm_page_t m)
-{
-
- TAILQ_INIT(&m->md.pv_list);
- m->md.pat_mode = PAT_WRITE_BACK;
-}
-
-/*
- * ABuse the pte nodes for unmapped kva to thread a kva freelist through.
- * Requirements:
- * - Must deal with pages in order to ensure that none of the PG_* bits
- * are ever set, PG_V in particular.
- * - Assumes we can write to ptes without pte_store() atomic ops, even
- * on PAE systems. This should be ok.
- * - Assumes nothing will ever test these addresses for 0 to indicate
- * no mapping instead of correctly checking PG_V.
- * - Assumes a vm_offset_t will fit in a pte (true for i386).
- * Because PG_V is never set, there can be no mappings to invalidate.
- */
-static int ptelist_count = 0;
-static vm_offset_t
-pmap_ptelist_alloc(vm_offset_t *head)
-{
- vm_offset_t va;
- vm_offset_t *phead = (vm_offset_t *)*head;
-
- if (ptelist_count == 0) {
- printf("out of memory!!!!!!\n");
- return (0); /* Out of memory */
- }
- ptelist_count--;
- va = phead[ptelist_count];
- return (va);
-}
-
-static void
-pmap_ptelist_free(vm_offset_t *head, vm_offset_t va)
-{
- vm_offset_t *phead = (vm_offset_t *)*head;
-
- phead[ptelist_count++] = va;
-}
-
-static void
-pmap_ptelist_init(vm_offset_t *head, void *base, int npages)
-{
- int i, nstackpages;
- vm_offset_t va;
- vm_page_t m;
-
- nstackpages = (npages + PAGE_SIZE/sizeof(vm_offset_t) - 1)/ (PAGE_SIZE/sizeof(vm_offset_t));
- for (i = 0; i < nstackpages; i++) {
- va = (vm_offset_t)base + i * PAGE_SIZE;
- m = vm_page_alloc(NULL, i,
- VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
- VM_ALLOC_ZERO);
- pmap_qenter(va, &m, 1);
- }
-
- *head = (vm_offset_t)base;
- for (i = npages - 1; i >= nstackpages; i--) {
- va = (vm_offset_t)base + i * PAGE_SIZE;
- pmap_ptelist_free(head, va);
- }
-}
-
-
-/*
- * Initialize the pmap module.
- * Called by vm_init, to initialize any structures that the pmap
- * system needs to map virtual memory.
- */
-void
-pmap_init(void)
-{
-
- /*
- * Initialize the address space (zone) for the pv entries. Set a
- * high water mark so that the system can recover from excessive
- * numbers of pv entries.
- */
- TUNABLE_INT_FETCH("vm.pmap.shpgperproc", &shpgperproc);
- pv_entry_max = shpgperproc * maxproc + vm_cnt.v_page_count;
- TUNABLE_INT_FETCH("vm.pmap.pv_entries", &pv_entry_max);
- pv_entry_max = roundup(pv_entry_max, _NPCPV);
- pv_entry_high_water = 9 * (pv_entry_max / 10);
-
- pv_maxchunks = MAX(pv_entry_max / _NPCPV, maxproc);
- pv_chunkbase = (struct pv_chunk *)kva_alloc(PAGE_SIZE * pv_maxchunks);
- if (pv_chunkbase == NULL)
- panic("pmap_init: not enough kvm for pv chunks");
- pmap_ptelist_init(&pv_vafree, pv_chunkbase, pv_maxchunks);
-}
-
-
-SYSCTL_INT(_vm_pmap, OID_AUTO, pv_entry_max, CTLFLAG_RD, &pv_entry_max, 0,
- "Max number of PV entries");
-SYSCTL_INT(_vm_pmap, OID_AUTO, shpgperproc, CTLFLAG_RD, &shpgperproc, 0,
- "Page share factor per proc");
-
-static SYSCTL_NODE(_vm_pmap, OID_AUTO, pde, CTLFLAG_RD, 0,
- "2/4MB page mapping counters");
-
-static u_long pmap_pde_mappings;
-SYSCTL_ULONG(_vm_pmap_pde, OID_AUTO, mappings, CTLFLAG_RD,
- &pmap_pde_mappings, 0, "2/4MB page mappings");
-
-/***************************************************
- * Low level helper routines.....
- ***************************************************/
-
-/*
- * Determine the appropriate bits to set in a PTE or PDE for a specified
- * caching mode.
- */
-int
-pmap_cache_bits(int mode, boolean_t is_pde)
-{
- int pat_flag, pat_index, cache_bits;
-
- /* The PAT bit is different for PTE's and PDE's. */
- pat_flag = is_pde ? PG_PDE_PAT : PG_PTE_PAT;
-
- /* If we don't support PAT, map extended modes to older ones. */
- if (!(cpu_feature & CPUID_PAT)) {
- switch (mode) {
- case PAT_UNCACHEABLE:
- case PAT_WRITE_THROUGH:
- case PAT_WRITE_BACK:
- break;
- case PAT_UNCACHED:
- case PAT_WRITE_COMBINING:
- case PAT_WRITE_PROTECTED:
- mode = PAT_UNCACHEABLE;
- break;
- }
- }
-
- /* Map the caching mode to a PAT index. */
- if (pat_works) {
- switch (mode) {
- case PAT_UNCACHEABLE:
- pat_index = 3;
- break;
- case PAT_WRITE_THROUGH:
- pat_index = 1;
- break;
- case PAT_WRITE_BACK:
- pat_index = 0;
- break;
- case PAT_UNCACHED:
- pat_index = 2;
- break;
- case PAT_WRITE_COMBINING:
- pat_index = 5;
- break;
- case PAT_WRITE_PROTECTED:
- pat_index = 4;
- break;
- default:
- panic("Unknown caching mode %d\n", mode);
- }
- } else {
- switch (mode) {
- case PAT_UNCACHED:
- case PAT_UNCACHEABLE:
- case PAT_WRITE_PROTECTED:
- pat_index = 3;
- break;
- case PAT_WRITE_THROUGH:
- pat_index = 1;
- break;
- case PAT_WRITE_BACK:
- pat_index = 0;
- break;
- case PAT_WRITE_COMBINING:
- pat_index = 2;
- break;
- default:
- panic("Unknown caching mode %d\n", mode);
- }
- }
-
- /* Map the 3-bit index value into the PAT, PCD, and PWT bits. */
- cache_bits = 0;
- if (pat_index & 0x4)
- cache_bits |= pat_flag;
- if (pat_index & 0x2)
- cache_bits |= PG_NC_PCD;
- if (pat_index & 0x1)
- cache_bits |= PG_NC_PWT;
- return (cache_bits);
-}
-#ifdef SMP
-/*
- * For SMP, these functions have to use the IPI mechanism for coherence.
- *
- * N.B.: Before calling any of the following TLB invalidation functions,
- * the calling processor must ensure that all stores updating a non-
- * kernel page table are globally performed. Otherwise, another
- * processor could cache an old, pre-update entry without being
- * invalidated. This can happen one of two ways: (1) The pmap becomes
- * active on another processor after its pm_active field is checked by
- * one of the following functions but before a store updating the page
- * table is globally performed. (2) The pmap becomes active on another
- * processor before its pm_active field is checked but due to
- * speculative loads one of the following functions stills reads the
- * pmap as inactive on the other processor.
- *
- * The kernel page table is exempt because its pm_active field is
- * immutable. The kernel page table is always active on every
- * processor.
- */
-void
-pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
-{
- cpuset_t other_cpus;
- u_int cpuid;
-
- CTR2(KTR_PMAP, "pmap_invalidate_page: pmap=%p va=0x%x",
- pmap, va);
-
- sched_pin();
- if (pmap == kernel_pmap || !CPU_CMP(&pmap->pm_active, &all_cpus)) {
- invlpg(va);
- smp_invlpg(va);
- } else {
- cpuid = PCPU_GET(cpuid);
- other_cpus = all_cpus;
- CPU_CLR(cpuid, &other_cpus);
- if (CPU_ISSET(cpuid, &pmap->pm_active))
- invlpg(va);
- CPU_AND(&other_cpus, &pmap->pm_active);
- if (!CPU_EMPTY(&other_cpus))
- smp_masked_invlpg(other_cpus, va);
- }
- sched_unpin();
- PT_UPDATES_FLUSH();
-}
-
-void
-pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
-{
- cpuset_t other_cpus;
- vm_offset_t addr;
- u_int cpuid;
-
- CTR3(KTR_PMAP, "pmap_invalidate_page: pmap=%p eva=0x%x sva=0x%x",
- pmap, sva, eva);
-
- sched_pin();
- if (pmap == kernel_pmap || !CPU_CMP(&pmap->pm_active, &all_cpus)) {
- for (addr = sva; addr < eva; addr += PAGE_SIZE)
- invlpg(addr);
- smp_invlpg_range(sva, eva);
- } else {
- cpuid = PCPU_GET(cpuid);
- other_cpus = all_cpus;
- CPU_CLR(cpuid, &other_cpus);
- if (CPU_ISSET(cpuid, &pmap->pm_active))
- for (addr = sva; addr < eva; addr += PAGE_SIZE)
- invlpg(addr);
- CPU_AND(&other_cpus, &pmap->pm_active);
- if (!CPU_EMPTY(&other_cpus))
- smp_masked_invlpg_range(other_cpus, sva, eva);
- }
- sched_unpin();
- PT_UPDATES_FLUSH();
-}
-
-void
-pmap_invalidate_all(pmap_t pmap)
-{
- cpuset_t other_cpus;
- u_int cpuid;
-
- CTR1(KTR_PMAP, "pmap_invalidate_page: pmap=%p", pmap);
-
- sched_pin();
- if (pmap == kernel_pmap || !CPU_CMP(&pmap->pm_active, &all_cpus)) {
- invltlb();
- smp_invltlb();
- } else {
- cpuid = PCPU_GET(cpuid);
- other_cpus = all_cpus;
- CPU_CLR(cpuid, &other_cpus);
- if (CPU_ISSET(cpuid, &pmap->pm_active))
- invltlb();
- CPU_AND(&other_cpus, &pmap->pm_active);
- if (!CPU_EMPTY(&other_cpus))
- smp_masked_invltlb(other_cpus);
- }
- sched_unpin();
-}
-
-void
-pmap_invalidate_cache(void)
-{
-
- sched_pin();
- wbinvd();
- smp_cache_flush();
- sched_unpin();
-}
-#else /* !SMP */
-/*
- * Normal, non-SMP, 486+ invalidation functions.
- * We inline these within pmap.c for speed.
- */
-PMAP_INLINE void
-pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
-{
- CTR2(KTR_PMAP, "pmap_invalidate_page: pmap=%p va=0x%x",
- pmap, va);
-
- if (pmap == kernel_pmap || !CPU_EMPTY(&pmap->pm_active))
- invlpg(va);
- PT_UPDATES_FLUSH();
-}
-
-PMAP_INLINE void
-pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
-{
- vm_offset_t addr;
-
- if (eva - sva > PAGE_SIZE)
- CTR3(KTR_PMAP, "pmap_invalidate_range: pmap=%p sva=0x%x eva=0x%x",
- pmap, sva, eva);
-
- if (pmap == kernel_pmap || !CPU_EMPTY(&pmap->pm_active))
- for (addr = sva; addr < eva; addr += PAGE_SIZE)
- invlpg(addr);
- PT_UPDATES_FLUSH();
-}
-
-PMAP_INLINE void
-pmap_invalidate_all(pmap_t pmap)
-{
-
- CTR1(KTR_PMAP, "pmap_invalidate_all: pmap=%p", pmap);
-
- if (pmap == kernel_pmap || !CPU_EMPTY(&pmap->pm_active))
- invltlb();
-}
-
-PMAP_INLINE void
-pmap_invalidate_cache(void)
-{
-
- wbinvd();
-}
-#endif /* !SMP */
-
-#define PMAP_CLFLUSH_THRESHOLD (2 * 1024 * 1024)
-
-void
-pmap_invalidate_cache_range(vm_offset_t sva, vm_offset_t eva, boolean_t force)
-{
-
- if (force) {
- sva &= ~(vm_offset_t)cpu_clflush_line_size;
- } else {
- KASSERT((sva & PAGE_MASK) == 0,
- ("pmap_invalidate_cache_range: sva not page-aligned"));
- KASSERT((eva & PAGE_MASK) == 0,
- ("pmap_invalidate_cache_range: eva not page-aligned"));
- }
-
- if ((cpu_feature & CPUID_SS) != 0 && !force)
- ; /* If "Self Snoop" is supported, do nothing. */
- else if ((cpu_feature & CPUID_CLFSH) != 0 &&
- eva - sva < PMAP_CLFLUSH_THRESHOLD) {
-
- /*
- * Otherwise, do per-cache line flush. Use the mfence
- * instruction to insure that previous stores are
- * included in the write-back. The processor
- * propagates flush to other processors in the cache
- * coherence domain.
- */
- mfence();
- for (; sva < eva; sva += cpu_clflush_line_size)
- clflush(sva);
- mfence();
- } else {
-
- /*
- * No targeted cache flush methods are supported by CPU,
- * or the supplied range is bigger than 2MB.
- * Globally invalidate cache.
- */
- pmap_invalidate_cache();
- }
-}
-
-void
-pmap_invalidate_cache_pages(vm_page_t *pages, int count)
-{
- int i;
-
- if (count >= PMAP_CLFLUSH_THRESHOLD / PAGE_SIZE ||
- (cpu_feature & CPUID_CLFSH) == 0) {
- pmap_invalidate_cache();
- } else {
- for (i = 0; i < count; i++)
- pmap_flush_page(pages[i]);
- }
-}
-
-/*
- * Are we current address space or kernel? N.B. We return FALSE when
- * a pmap's page table is in use because a kernel thread is borrowing
- * it. The borrowed page table can change spontaneously, making any
- * dependence on its continued use subject to a race condition.
- */
-static __inline int
-pmap_is_current(pmap_t pmap)
-{
-
- return (pmap == kernel_pmap ||
- (pmap == vmspace_pmap(curthread->td_proc->p_vmspace) &&
- (pmap->pm_pdir[PTDPTDI] & PG_FRAME) == (PTDpde[0] & PG_FRAME)));
-}
-
-/*
- * If the given pmap is not the current or kernel pmap, the returned pte must
- * be released by passing it to pmap_pte_release().
- */
-pt_entry_t *
-pmap_pte(pmap_t pmap, vm_offset_t va)
-{
- pd_entry_t newpf;
- pd_entry_t *pde;
-
- pde = pmap_pde(pmap, va);
- if (*pde & PG_PS)
- return (pde);
- if (*pde != 0) {
- /* are we current address space or kernel? */
- if (pmap_is_current(pmap))
- return (vtopte(va));
- mtx_lock(&PMAP2mutex);
- newpf = *pde & PG_FRAME;
- if ((*PMAP2 & PG_FRAME) != newpf) {
- PT_SET_MA(PADDR2, newpf | PG_V | PG_A | PG_M);
- CTR3(KTR_PMAP, "pmap_pte: pmap=%p va=0x%x newpte=0x%08x",
- pmap, va, (*PMAP2 & 0xffffffff));
- }
- return (PADDR2 + (i386_btop(va) & (NPTEPG - 1)));
- }
- return (NULL);
-}
-
-/*
- * Releases a pte that was obtained from pmap_pte(). Be prepared for the pte
- * being NULL.
- */
-static __inline void
-pmap_pte_release(pt_entry_t *pte)
-{
-
- if ((pt_entry_t *)((vm_offset_t)pte & ~PAGE_MASK) == PADDR2) {
- CTR1(KTR_PMAP, "pmap_pte_release: pte=0x%jx",
- *PMAP2);
- rw_wlock(&pvh_global_lock);
- PT_SET_VA(PMAP2, 0, TRUE);
- rw_wunlock(&pvh_global_lock);
- mtx_unlock(&PMAP2mutex);
- }
-}
-
-static __inline void
-invlcaddr(void *caddr)
-{
-
- invlpg((u_int)caddr);
- PT_UPDATES_FLUSH();
-}
-
-/*
- * Super fast pmap_pte routine best used when scanning
- * the pv lists. This eliminates many coarse-grained
- * invltlb calls. Note that many of the pv list
- * scans are across different pmaps. It is very wasteful
- * to do an entire invltlb for checking a single mapping.
- *
- * If the given pmap is not the current pmap, pvh_global_lock
- * must be held and curthread pinned to a CPU.
- */
-static pt_entry_t *
-pmap_pte_quick(pmap_t pmap, vm_offset_t va)
-{
- pd_entry_t newpf;
- pd_entry_t *pde;
-
- pde = pmap_pde(pmap, va);
- if (*pde & PG_PS)
- return (pde);
- if (*pde != 0) {
- /* are we current address space or kernel? */
- if (pmap_is_current(pmap))
- return (vtopte(va));
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- KASSERT(curthread->td_pinned > 0, ("curthread not pinned"));
- newpf = *pde & PG_FRAME;
- if ((*PMAP1 & PG_FRAME) != newpf) {
- PT_SET_MA(PADDR1, newpf | PG_V | PG_A | PG_M);
- CTR3(KTR_PMAP, "pmap_pte_quick: pmap=%p va=0x%x newpte=0x%08x",
- pmap, va, (u_long)*PMAP1);
-
-#ifdef SMP
- PMAP1cpu = PCPU_GET(cpuid);
-#endif
- PMAP1changed++;
- } else
-#ifdef SMP
- if (PMAP1cpu != PCPU_GET(cpuid)) {
- PMAP1cpu = PCPU_GET(cpuid);
- invlcaddr(PADDR1);
- PMAP1changedcpu++;
- } else
-#endif
- PMAP1unchanged++;
- return (PADDR1 + (i386_btop(va) & (NPTEPG - 1)));
- }
- return (0);
-}
-
-/*
- * Routine: pmap_extract
- * Function:
- * Extract the physical page address associated
- * with the given map/virtual_address pair.
- */
-vm_paddr_t
-pmap_extract(pmap_t pmap, vm_offset_t va)
-{
- vm_paddr_t rtval;
- pt_entry_t *pte;
- pd_entry_t pde;
- pt_entry_t pteval;
-
- rtval = 0;
- PMAP_LOCK(pmap);
- pde = pmap->pm_pdir[va >> PDRSHIFT];
- if (pde != 0) {
- if ((pde & PG_PS) != 0) {
- rtval = xpmap_mtop(pde & PG_PS_FRAME) | (va & PDRMASK);
- PMAP_UNLOCK(pmap);
- return rtval;
- }
- pte = pmap_pte(pmap, va);
- pteval = *pte ? xpmap_mtop(*pte) : 0;
- rtval = (pteval & PG_FRAME) | (va & PAGE_MASK);
- pmap_pte_release(pte);
- }
- PMAP_UNLOCK(pmap);
- return (rtval);
-}
-
-/*
- * Routine: pmap_extract_ma
- * Function:
- * Like pmap_extract, but returns machine address
- */
-vm_paddr_t
-pmap_extract_ma(pmap_t pmap, vm_offset_t va)
-{
- vm_paddr_t rtval;
- pt_entry_t *pte;
- pd_entry_t pde;
-
- rtval = 0;
- PMAP_LOCK(pmap);
- pde = pmap->pm_pdir[va >> PDRSHIFT];
- if (pde != 0) {
- if ((pde & PG_PS) != 0) {
- rtval = (pde & ~PDRMASK) | (va & PDRMASK);
- PMAP_UNLOCK(pmap);
- return rtval;
- }
- pte = pmap_pte(pmap, va);
- rtval = (*pte & PG_FRAME) | (va & PAGE_MASK);
- pmap_pte_release(pte);
- }
- PMAP_UNLOCK(pmap);
- return (rtval);
-}
-
-/*
- * Routine: pmap_extract_and_hold
- * Function:
- * Atomically extract and hold the physical page
- * with the given pmap and virtual address pair
- * if that mapping permits the given protection.
- */
-vm_page_t
-pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot)
-{
- pd_entry_t pde;
- pt_entry_t pte, *ptep;
- vm_page_t m;
- vm_paddr_t pa;
-
- pa = 0;
- m = NULL;
- PMAP_LOCK(pmap);
-retry:
- pde = PT_GET(pmap_pde(pmap, va));
- if (pde != 0) {
- if (pde & PG_PS) {
- if ((pde & PG_RW) || (prot & VM_PROT_WRITE) == 0) {
- if (vm_page_pa_tryrelock(pmap, (pde &
- PG_PS_FRAME) | (va & PDRMASK), &pa))
- goto retry;
- m = PHYS_TO_VM_PAGE((pde & PG_PS_FRAME) |
- (va & PDRMASK));
- vm_page_hold(m);
- }
- } else {
- ptep = pmap_pte(pmap, va);
- pte = PT_GET(ptep);
- pmap_pte_release(ptep);
- if (pte != 0 &&
- ((pte & PG_RW) || (prot & VM_PROT_WRITE) == 0)) {
- if (vm_page_pa_tryrelock(pmap, pte & PG_FRAME,
- &pa))
- goto retry;
- m = PHYS_TO_VM_PAGE(pte & PG_FRAME);
- vm_page_hold(m);
- }
- }
- }
- PA_UNLOCK_COND(pa);
- PMAP_UNLOCK(pmap);
- return (m);
-}
-
-/***************************************************
- * Low level mapping routines.....
- ***************************************************/
-
-/*
- * Add a wired page to the kva.
- * Note: not SMP coherent.
- *
- * This function may be used before pmap_bootstrap() is called.
- */
-void
-pmap_kenter(vm_offset_t va, vm_paddr_t pa)
-{
-
- PT_SET_MA(va, xpmap_ptom(pa)| PG_RW | PG_V | pgeflag);
-}
-
-void
-pmap_kenter_ma(vm_offset_t va, vm_paddr_t ma)
-{
- pt_entry_t *pte;
-
- pte = vtopte(va);
- pte_store_ma(pte, ma | PG_RW | PG_V | pgeflag);
-}
-
-static __inline void
-pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int mode)
-{
-
- PT_SET_MA(va, pa | PG_RW | PG_V | pgeflag | pmap_cache_bits(mode, 0));
-}
-
-/*
- * Remove a page from the kernel pagetables.
- * Note: not SMP coherent.
- *
- * This function may be used before pmap_bootstrap() is called.
- */
-PMAP_INLINE void
-pmap_kremove(vm_offset_t va)
-{
- pt_entry_t *pte;
-
- pte = vtopte(va);
- PT_CLEAR_VA(pte, FALSE);
-}
-
-/*
- * Used to map a range of physical addresses into kernel
- * virtual address space.
- *
- * The value passed in '*virt' is a suggested virtual address for
- * the mapping. Architectures which can support a direct-mapped
- * physical to virtual region can return the appropriate address
- * within that region, leaving '*virt' unchanged. Other
- * architectures should map the pages starting at '*virt' and
- * update '*virt' with the first usable address after the mapped
- * region.
- */
-vm_offset_t
-pmap_map(vm_offset_t *virt, vm_paddr_t start, vm_paddr_t end, int prot)
-{
- vm_offset_t va, sva;
-
- va = sva = *virt;
- CTR4(KTR_PMAP, "pmap_map: va=0x%x start=0x%jx end=0x%jx prot=0x%x",
- va, start, end, prot);
- while (start < end) {
- pmap_kenter(va, start);
- va += PAGE_SIZE;
- start += PAGE_SIZE;
- }
- pmap_invalidate_range(kernel_pmap, sva, va);
- *virt = va;
- return (sva);
-}
-
-
-/*
- * Add a list of wired pages to the kva
- * this routine is only used for temporary
- * kernel mappings that do not need to have
- * page modification or references recorded.
- * Note that old mappings are simply written
- * over. The page *must* be wired.
- * Note: SMP coherent. Uses a ranged shootdown IPI.
- */
-void
-pmap_qenter(vm_offset_t sva, vm_page_t *ma, int count)
-{
- pt_entry_t *endpte, *pte;
- vm_paddr_t pa;
- vm_offset_t va = sva;
- int mclcount = 0;
- multicall_entry_t mcl[16];
- multicall_entry_t *mclp = mcl;
- int error;
-
- CTR2(KTR_PMAP, "pmap_qenter:sva=0x%x count=%d", va, count);
- pte = vtopte(sva);
- endpte = pte + count;
- while (pte < endpte) {
- pa = VM_PAGE_TO_MACH(*ma) | pgeflag | PG_RW | PG_V | PG_M | PG_A;
-
- mclp->op = __HYPERVISOR_update_va_mapping;
- mclp->args[0] = va;
- mclp->args[1] = (uint32_t)(pa & 0xffffffff);
- mclp->args[2] = (uint32_t)(pa >> 32);
- mclp->args[3] = (*pte & PG_V) ? UVMF_INVLPG|UVMF_ALL : 0;
-
- va += PAGE_SIZE;
- pte++;
- ma++;
- mclp++;
- mclcount++;
- if (mclcount == 16) {
- error = HYPERVISOR_multicall(mcl, mclcount);
- mclp = mcl;
- mclcount = 0;
- KASSERT(error == 0, ("bad multicall %d", error));
- }
- }
- if (mclcount) {
- error = HYPERVISOR_multicall(mcl, mclcount);
- KASSERT(error == 0, ("bad multicall %d", error));
- }
-
-#ifdef INVARIANTS
- for (pte = vtopte(sva), mclcount = 0; mclcount < count; mclcount++, pte++)
- KASSERT(*pte, ("pte not set for va=0x%x", sva + mclcount*PAGE_SIZE));
-#endif
-}
-
-/*
- * This routine tears out page mappings from the
- * kernel -- it is meant only for temporary mappings.
- * Note: SMP coherent. Uses a ranged shootdown IPI.
- */
-void
-pmap_qremove(vm_offset_t sva, int count)
-{
- vm_offset_t va;
-
- CTR2(KTR_PMAP, "pmap_qremove: sva=0x%x count=%d", sva, count);
- va = sva;
- rw_wlock(&pvh_global_lock);
- critical_enter();
- while (count-- > 0) {
- pmap_kremove(va);
- va += PAGE_SIZE;
- }
- PT_UPDATES_FLUSH();
- pmap_invalidate_range(kernel_pmap, sva, va);
- critical_exit();
- rw_wunlock(&pvh_global_lock);
-}
-
-/***************************************************
- * Page table page management routines.....
- ***************************************************/
-static __inline void
-pmap_free_zero_pages(vm_page_t free)
-{
- vm_page_t m;
-
- while (free != NULL) {
- m = free;
- free = (void *)m->object;
- m->object = NULL;
- vm_page_free_zero(m);
- }
-}
-
-/*
- * Decrements a page table page's wire count, which is used to record the
- * number of valid page table entries within the page. If the wire count
- * drops to zero, then the page table page is unmapped. Returns TRUE if the
- * page table page was unmapped and FALSE otherwise.
- */
-static inline boolean_t
-pmap_unwire_ptp(pmap_t pmap, vm_page_t m, vm_page_t *free)
-{
-
- --m->wire_count;
- if (m->wire_count == 0) {
- _pmap_unwire_ptp(pmap, m, free);
- return (TRUE);
- } else
- return (FALSE);
-}
-
-static void
-_pmap_unwire_ptp(pmap_t pmap, vm_page_t m, vm_page_t *free)
-{
- vm_offset_t pteva;
-
- PT_UPDATES_FLUSH();
- /*
- * unmap the page table page
- */
- xen_pt_unpin(pmap->pm_pdir[m->pindex]);
- /*
- * page *might* contain residual mapping :-/
- */
- PD_CLEAR_VA(pmap, m->pindex, TRUE);
- pmap_zero_page(m);
- --pmap->pm_stats.resident_count;
-
- /*
- * This is a release store so that the ordinary store unmapping
- * the page table page is globally performed before TLB shoot-
- * down is begun.
- */
- atomic_subtract_rel_int(&vm_cnt.v_wire_count, 1);
-
- /*
- * Do an invltlb to make the invalidated mapping
- * take effect immediately.
- */
- pteva = VM_MAXUSER_ADDRESS + i386_ptob(m->pindex);
- pmap_invalidate_page(pmap, pteva);
-
- /*
- * Put page on a list so that it is released after
- * *ALL* TLB shootdown is done
- */
- m->object = (void *)*free;
- *free = m;
-}
-
-/*
- * After removing a page table entry, this routine is used to
- * conditionally free the page, and manage the hold/wire counts.
- */
-static int
-pmap_unuse_pt(pmap_t pmap, vm_offset_t va, vm_page_t *free)
-{
- pd_entry_t ptepde;
- vm_page_t mpte;
-
- if (va >= VM_MAXUSER_ADDRESS)
- return (0);
- ptepde = PT_GET(pmap_pde(pmap, va));
- mpte = PHYS_TO_VM_PAGE(ptepde & PG_FRAME);
- return (pmap_unwire_ptp(pmap, mpte, free));
-}
-
-/*
- * Initialize the pmap for the swapper process.
- */
-void
-pmap_pinit0(pmap_t pmap)
-{
-
- PMAP_LOCK_INIT(pmap);
- /*
- * Since the page table directory is shared with the kernel pmap,
- * which is already included in the list "allpmaps", this pmap does
- * not need to be inserted into that list.
- */
- pmap->pm_pdir = (pd_entry_t *)(KERNBASE + (vm_offset_t)IdlePTD);
-#ifdef PAE
- pmap->pm_pdpt = (pdpt_entry_t *)(KERNBASE + (vm_offset_t)IdlePDPT);
-#endif
- CPU_ZERO(&pmap->pm_active);
- PCPU_SET(curpmap, pmap);
- TAILQ_INIT(&pmap->pm_pvchunk);
- bzero(&pmap->pm_stats, sizeof pmap->pm_stats);
-}
-
-/*
- * Initialize a preallocated and zeroed pmap structure,
- * such as one in a vmspace structure.
- */
-int
-pmap_pinit(pmap_t pmap)
-{
- vm_page_t m, ptdpg[NPGPTD + 1];
- int npgptd = NPGPTD + 1;
- int i;
-
-#ifdef HAMFISTED_LOCKING
- mtx_lock(&createdelete_lock);
-#endif
-
- /*
- * No need to allocate page table space yet but we do need a valid
- * page directory table.
- */
- if (pmap->pm_pdir == NULL) {
- pmap->pm_pdir = (pd_entry_t *)kva_alloc(NBPTD);
- if (pmap->pm_pdir == NULL) {
-#ifdef HAMFISTED_LOCKING
- mtx_unlock(&createdelete_lock);
-#endif
- return (0);
- }
-#ifdef PAE
- pmap->pm_pdpt = (pd_entry_t *)kva_alloc(1);
-#endif
- }
-
- /*
- * allocate the page directory page(s)
- */
- for (i = 0; i < npgptd;) {
- m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ |
- VM_ALLOC_WIRED | VM_ALLOC_ZERO);
- if (m == NULL)
- VM_WAIT;
- else {
- ptdpg[i++] = m;
- }
- }
-
- pmap_qenter((vm_offset_t)pmap->pm_pdir, ptdpg, NPGPTD);
-
- for (i = 0; i < NPGPTD; i++)
- if ((ptdpg[i]->flags & PG_ZERO) == 0)
- pagezero(pmap->pm_pdir + (i * NPDEPG));
-
- mtx_lock_spin(&allpmaps_lock);
- LIST_INSERT_HEAD(&allpmaps, pmap, pm_list);
- /* Copy the kernel page table directory entries. */
- bcopy(PTD + KPTDI, pmap->pm_pdir + KPTDI, nkpt * sizeof(pd_entry_t));
- mtx_unlock_spin(&allpmaps_lock);
-
-#ifdef PAE
- pmap_qenter((vm_offset_t)pmap->pm_pdpt, &ptdpg[NPGPTD], 1);
- if ((ptdpg[NPGPTD]->flags & PG_ZERO) == 0)
- bzero(pmap->pm_pdpt, PAGE_SIZE);
- for (i = 0; i < NPGPTD; i++) {
- vm_paddr_t ma;
-
- ma = VM_PAGE_TO_MACH(ptdpg[i]);
- pmap->pm_pdpt[i] = ma | PG_V;
-
- }
-#endif
- for (i = 0; i < NPGPTD; i++) {
- pt_entry_t *pd;
- vm_paddr_t ma;
-
- ma = VM_PAGE_TO_MACH(ptdpg[i]);
- pd = pmap->pm_pdir + (i * NPDEPG);
- PT_SET_MA(pd, *vtopte((vm_offset_t)pd) & ~(PG_M|PG_A|PG_U|PG_RW));
-#if 0
- xen_pgd_pin(ma);
-#endif
- }
-
-#ifdef PAE
- PT_SET_MA(pmap->pm_pdpt, *vtopte((vm_offset_t)pmap->pm_pdpt) & ~PG_RW);
-#endif
- rw_wlock(&pvh_global_lock);
- xen_flush_queue();
- xen_pgdpt_pin(VM_PAGE_TO_MACH(ptdpg[NPGPTD]));
- for (i = 0; i < NPGPTD; i++) {
- vm_paddr_t ma = VM_PAGE_TO_MACH(ptdpg[i]);
- PT_SET_VA_MA(&pmap->pm_pdir[PTDPTDI + i], ma | PG_V | PG_A, FALSE);
- }
- xen_flush_queue();
- rw_wunlock(&pvh_global_lock);
- CPU_ZERO(&pmap->pm_active);
- TAILQ_INIT(&pmap->pm_pvchunk);
- bzero(&pmap->pm_stats, sizeof pmap->pm_stats);
-
-#ifdef HAMFISTED_LOCKING
- mtx_unlock(&createdelete_lock);
-#endif
- return (1);
-}
-
-/*
- * this routine is called if the page table page is not
- * mapped correctly.
- */
-static vm_page_t
-_pmap_allocpte(pmap_t pmap, u_int ptepindex, u_int flags)
-{
- vm_paddr_t ptema;
- vm_page_t m;
-
- /*
- * Allocate a page table page.
- */
- if ((m = vm_page_alloc(NULL, ptepindex, VM_ALLOC_NOOBJ |
- VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) {
- if ((flags & PMAP_ENTER_NOSLEEP) == 0) {
- PMAP_UNLOCK(pmap);
- rw_wunlock(&pvh_global_lock);
- VM_WAIT;
- rw_wlock(&pvh_global_lock);
- PMAP_LOCK(pmap);
- }
-
- /*
- * Indicate the need to retry. While waiting, the page table
- * page may have been allocated.
- */
- return (NULL);
- }
- if ((m->flags & PG_ZERO) == 0)
- pmap_zero_page(m);
-
- /*
- * Map the pagetable page into the process address space, if
- * it isn't already there.
- */
-
- pmap->pm_stats.resident_count++;
-
- ptema = VM_PAGE_TO_MACH(m);
- xen_pt_pin(ptema);
- PT_SET_VA_MA(&pmap->pm_pdir[ptepindex],
- (ptema | PG_U | PG_RW | PG_V | PG_A | PG_M), TRUE);
-
- KASSERT(pmap->pm_pdir[ptepindex],
- ("_pmap_allocpte: ptepindex=%d did not get mapped", ptepindex));
- return (m);
-}
-
-static vm_page_t
-pmap_allocpte(pmap_t pmap, vm_offset_t va, u_int flags)
-{
- u_int ptepindex;
- pd_entry_t ptema;
- vm_page_t m;
-
- /*
- * Calculate pagetable page index
- */
- ptepindex = va >> PDRSHIFT;
-retry:
- /*
- * Get the page directory entry
- */
- ptema = pmap->pm_pdir[ptepindex];
-
- /*
- * This supports switching from a 4MB page to a
- * normal 4K page.
- */
- if (ptema & PG_PS) {
- /*
- * XXX
- */
- pmap->pm_pdir[ptepindex] = 0;
- ptema = 0;
- pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
- pmap_invalidate_all(kernel_pmap);
- }
-
- /*
- * If the page table page is mapped, we just increment the
- * hold count, and activate it.
- */
- if (ptema & PG_V) {
- m = PHYS_TO_VM_PAGE(xpmap_mtop(ptema) & PG_FRAME);
- m->wire_count++;
- } else {
- /*
- * Here if the pte page isn't mapped, or if it has
- * been deallocated.
- */
- CTR3(KTR_PMAP, "pmap_allocpte: pmap=%p va=0x%08x flags=0x%x",
- pmap, va, flags);
- m = _pmap_allocpte(pmap, ptepindex, flags);
- if (m == NULL && (flags & PMAP_ENTER_NOSLEEP) == 0)
- goto retry;
-
- KASSERT(pmap->pm_pdir[ptepindex], ("ptepindex=%d did not get mapped", ptepindex));
- }
- return (m);
-}
-
-
-/***************************************************
-* Pmap allocation/deallocation routines.
- ***************************************************/
-
-#ifdef SMP
-/*
- * Deal with a SMP shootdown of other users of the pmap that we are
- * trying to dispose of. This can be a bit hairy.
- */
-static cpuset_t *lazymask;
-static u_int lazyptd;
-static volatile u_int lazywait;
-
-void pmap_lazyfix_action(void);
-
-void
-pmap_lazyfix_action(void)
-{
-
-#ifdef COUNT_IPIS
- (*ipi_lazypmap_counts[PCPU_GET(cpuid)])++;
-#endif
- if (rcr3() == lazyptd)
- load_cr3(PCPU_GET(curpcb)->pcb_cr3);
- CPU_CLR_ATOMIC(PCPU_GET(cpuid), lazymask);
- atomic_store_rel_int(&lazywait, 1);
-}
-
-static void
-pmap_lazyfix_self(u_int cpuid)
-{
-
- if (rcr3() == lazyptd)
- load_cr3(PCPU_GET(curpcb)->pcb_cr3);
- CPU_CLR_ATOMIC(cpuid, lazymask);
-}
-
-
-static void
-pmap_lazyfix(pmap_t pmap)
-{
- cpuset_t mymask, mask;
- u_int cpuid, spins;
- int lsb;
-
- mask = pmap->pm_active;
- while (!CPU_EMPTY(&mask)) {
- spins = 50000000;
-
- /* Find least significant set bit. */
- lsb = CPU_FFS(&mask);
- MPASS(lsb != 0);
- lsb--;
- CPU_SETOF(lsb, &mask);
- mtx_lock_spin(&smp_ipi_mtx);
-#ifdef PAE
- lazyptd = vtophys(pmap->pm_pdpt);
-#else
- lazyptd = vtophys(pmap->pm_pdir);
-#endif
- cpuid = PCPU_GET(cpuid);
-
- /* Use a cpuset just for having an easy check. */
- CPU_SETOF(cpuid, &mymask);
- if (!CPU_CMP(&mask, &mymask)) {
- lazymask = &pmap->pm_active;
- pmap_lazyfix_self(cpuid);
- } else {
- atomic_store_rel_int((u_int *)&lazymask,
- (u_int)&pmap->pm_active);
- atomic_store_rel_int(&lazywait, 0);
- ipi_selected(mask, IPI_LAZYPMAP);
- while (lazywait == 0) {
- ia32_pause();
- if (--spins == 0)
- break;
- }
- }
- mtx_unlock_spin(&smp_ipi_mtx);
- if (spins == 0)
- printf("pmap_lazyfix: spun for 50000000\n");
- mask = pmap->pm_active;
- }
-}
-
-#else /* SMP */
-
-/*
- * Cleaning up on uniprocessor is easy. For various reasons, we're
- * unlikely to have to even execute this code, including the fact
- * that the cleanup is deferred until the parent does a wait(2), which
- * means that another userland process has run.
- */
-static void
-pmap_lazyfix(pmap_t pmap)
-{
- u_int cr3;
-
- cr3 = vtophys(pmap->pm_pdir);
- if (cr3 == rcr3()) {
- load_cr3(PCPU_GET(curpcb)->pcb_cr3);
- CPU_CLR(PCPU_GET(cpuid), &pmap->pm_active);
- }
-}
-#endif /* SMP */
-
-/*
- * Release any resources held by the given physical map.
- * Called when a pmap initialized by pmap_pinit is being released.
- * Should only be called if the map contains no valid mappings.
- */
-void
-pmap_release(pmap_t pmap)
-{
- vm_page_t m, ptdpg[2*NPGPTD+1];
- vm_paddr_t ma;
- int i;
-#ifdef PAE
- int npgptd = NPGPTD + 1;
-#else
- int npgptd = NPGPTD;
-#endif
-
- KASSERT(pmap->pm_stats.resident_count == 0,
- ("pmap_release: pmap resident count %ld != 0",
- pmap->pm_stats.resident_count));
- PT_UPDATES_FLUSH();
-
-#ifdef HAMFISTED_LOCKING
- mtx_lock(&createdelete_lock);
-#endif
-
- pmap_lazyfix(pmap);
- mtx_lock_spin(&allpmaps_lock);
- LIST_REMOVE(pmap, pm_list);
- mtx_unlock_spin(&allpmaps_lock);
-
- for (i = 0; i < NPGPTD; i++)
- ptdpg[i] = PHYS_TO_VM_PAGE(vtophys(pmap->pm_pdir + (i*NPDEPG)) & PG_FRAME);
- pmap_qremove((vm_offset_t)pmap->pm_pdir, NPGPTD);
-#ifdef PAE
- ptdpg[NPGPTD] = PHYS_TO_VM_PAGE(vtophys(pmap->pm_pdpt));
-#endif
-
- for (i = 0; i < npgptd; i++) {
- m = ptdpg[i];
- ma = VM_PAGE_TO_MACH(m);
- /* unpinning L1 and L2 treated the same */
-#if 0
- xen_pgd_unpin(ma);
-#else
- if (i == NPGPTD)
- xen_pgd_unpin(ma);
-#endif
-#ifdef PAE
- if (i < NPGPTD)
- KASSERT(VM_PAGE_TO_MACH(m) == (pmap->pm_pdpt[i] & PG_FRAME),
- ("pmap_release: got wrong ptd page"));
-#endif
- m->wire_count--;
- atomic_subtract_int(&vm_cnt.v_wire_count, 1);
- vm_page_free(m);
- }
-#ifdef PAE
- pmap_qremove((vm_offset_t)pmap->pm_pdpt, 1);
-#endif
-
-#ifdef HAMFISTED_LOCKING
- mtx_unlock(&createdelete_lock);
-#endif
-}
-
-static int
-kvm_size(SYSCTL_HANDLER_ARGS)
-{
- unsigned long ksize = VM_MAX_KERNEL_ADDRESS - KERNBASE;
-
- return (sysctl_handle_long(oidp, &ksize, 0, req));
-}
-SYSCTL_PROC(_vm, OID_AUTO, kvm_size, CTLTYPE_LONG|CTLFLAG_RD,
- 0, 0, kvm_size, "IU", "Size of KVM");
-
-static int
-kvm_free(SYSCTL_HANDLER_ARGS)
-{
- unsigned long kfree = VM_MAX_KERNEL_ADDRESS - kernel_vm_end;
-
- return (sysctl_handle_long(oidp, &kfree, 0, req));
-}
-SYSCTL_PROC(_vm, OID_AUTO, kvm_free, CTLTYPE_LONG|CTLFLAG_RD,
- 0, 0, kvm_free, "IU", "Amount of KVM free");
-
-/*
- * grow the number of kernel page table entries, if needed
- */
-void
-pmap_growkernel(vm_offset_t addr)
-{
- struct pmap *pmap;
- vm_paddr_t ptppaddr;
- vm_page_t nkpg;
- pd_entry_t newpdir;
-
- mtx_assert(&kernel_map->system_mtx, MA_OWNED);
- if (kernel_vm_end == 0) {
- kernel_vm_end = KERNBASE;
- nkpt = 0;
- while (pdir_pde(PTD, kernel_vm_end)) {
- kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
- nkpt++;
- if (kernel_vm_end - 1 >= kernel_map->max_offset) {
- kernel_vm_end = kernel_map->max_offset;
- break;
- }
- }
- }
- addr = roundup2(addr, NBPDR);
- if (addr - 1 >= kernel_map->max_offset)
- addr = kernel_map->max_offset;
- while (kernel_vm_end < addr) {
- if (pdir_pde(PTD, kernel_vm_end)) {
- kernel_vm_end = (kernel_vm_end + NBPDR) & ~PDRMASK;
- if (kernel_vm_end - 1 >= kernel_map->max_offset) {
- kernel_vm_end = kernel_map->max_offset;
- break;
- }
- continue;
- }
-
- nkpg = vm_page_alloc(NULL, kernel_vm_end >> PDRSHIFT,
- VM_ALLOC_INTERRUPT | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
- VM_ALLOC_ZERO);
- if (nkpg == NULL)
- panic("pmap_growkernel: no memory to grow kernel");
-
- nkpt++;
-
- if ((nkpg->flags & PG_ZERO) == 0)
- pmap_zero_page(nkpg);
- ptppaddr = VM_PAGE_TO_PHYS(nkpg);
- newpdir = (pd_entry_t) (ptppaddr | PG_V | PG_RW | PG_A | PG_M);
- rw_wlock(&pvh_global_lock);
- PD_SET_VA(kernel_pmap, (kernel_vm_end >> PDRSHIFT), newpdir, TRUE);
- mtx_lock_spin(&allpmaps_lock);
- LIST_FOREACH(pmap, &allpmaps, pm_list)
- PD_SET_VA(pmap, (kernel_vm_end >> PDRSHIFT), newpdir, TRUE);
-
- mtx_unlock_spin(&allpmaps_lock);
- rw_wunlock(&pvh_global_lock);
-
- kernel_vm_end = (kernel_vm_end + NBPDR) & ~PDRMASK;
- if (kernel_vm_end - 1 >= kernel_map->max_offset) {
- kernel_vm_end = kernel_map->max_offset;
- break;
- }
- }
-}
-
-
-/***************************************************
- * page management routines.
- ***************************************************/
-
-CTASSERT(sizeof(struct pv_chunk) == PAGE_SIZE);
-CTASSERT(_NPCM == 11);
-CTASSERT(_NPCPV == 336);
-
-static __inline struct pv_chunk *
-pv_to_chunk(pv_entry_t pv)
-{
-
- return ((struct pv_chunk *)((uintptr_t)pv & ~(uintptr_t)PAGE_MASK));
-}
-
-#define PV_PMAP(pv) (pv_to_chunk(pv)->pc_pmap)
-
-#define PC_FREE0_9 0xfffffffful /* Free values for index 0 through 9 */
-#define PC_FREE10 0x0000fffful /* Free values for index 10 */
-
-static const uint32_t pc_freemask[_NPCM] = {
- PC_FREE0_9, PC_FREE0_9, PC_FREE0_9,
- PC_FREE0_9, PC_FREE0_9, PC_FREE0_9,
- PC_FREE0_9, PC_FREE0_9, PC_FREE0_9,
- PC_FREE0_9, PC_FREE10
-};
-
-SYSCTL_INT(_vm_pmap, OID_AUTO, pv_entry_count, CTLFLAG_RD, &pv_entry_count, 0,
- "Current number of pv entries");
-
-#ifdef PV_STATS
-static int pc_chunk_count, pc_chunk_allocs, pc_chunk_frees, pc_chunk_tryfail;
-
-SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_count, CTLFLAG_RD, &pc_chunk_count, 0,
- "Current number of pv entry chunks");
-SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_allocs, CTLFLAG_RD, &pc_chunk_allocs, 0,
- "Current number of pv entry chunks allocated");
-SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_frees, CTLFLAG_RD, &pc_chunk_frees, 0,
- "Current number of pv entry chunks frees");
-SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_tryfail, CTLFLAG_RD, &pc_chunk_tryfail, 0,
- "Number of times tried to get a chunk page but failed.");
-
-static long pv_entry_frees, pv_entry_allocs;
-static int pv_entry_spare;
-
-SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_frees, CTLFLAG_RD, &pv_entry_frees, 0,
- "Current number of pv entry frees");
-SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_allocs, CTLFLAG_RD, &pv_entry_allocs, 0,
- "Current number of pv entry allocs");
-SYSCTL_INT(_vm_pmap, OID_AUTO, pv_entry_spare, CTLFLAG_RD, &pv_entry_spare, 0,
- "Current number of spare pv entries");
-#endif
-
-/*
- * We are in a serious low memory condition. Resort to
- * drastic measures to free some pages so we can allocate
- * another pv entry chunk.
- */
-static vm_page_t
-pmap_pv_reclaim(pmap_t locked_pmap)
-{
- struct pch newtail;
- struct pv_chunk *pc;
- pmap_t pmap;
- pt_entry_t *pte, tpte;
- pv_entry_t pv;
- vm_offset_t va;
- vm_page_t free, m, m_pc;
- uint32_t inuse;
- int bit, field, freed;
-
- PMAP_LOCK_ASSERT(locked_pmap, MA_OWNED);
- pmap = NULL;
- free = m_pc = NULL;
- TAILQ_INIT(&newtail);
- while ((pc = TAILQ_FIRST(&pv_chunks)) != NULL && (pv_vafree == 0 ||
- free == NULL)) {
- TAILQ_REMOVE(&pv_chunks, pc, pc_lru);
- if (pmap != pc->pc_pmap) {
- if (pmap != NULL) {
- pmap_invalidate_all(pmap);
- if (pmap != locked_pmap)
- PMAP_UNLOCK(pmap);
- }
- pmap = pc->pc_pmap;
- /* Avoid deadlock and lock recursion. */
- if (pmap > locked_pmap)
- PMAP_LOCK(pmap);
- else if (pmap != locked_pmap && !PMAP_TRYLOCK(pmap)) {
- pmap = NULL;
- TAILQ_INSERT_TAIL(&newtail, pc, pc_lru);
- continue;
- }
- }
-
- /*
- * Destroy every non-wired, 4 KB page mapping in the chunk.
- */
- freed = 0;
- for (field = 0; field < _NPCM; field++) {
- for (inuse = ~pc->pc_map[field] & pc_freemask[field];
- inuse != 0; inuse &= ~(1UL << bit)) {
- bit = bsfl(inuse);
- pv = &pc->pc_pventry[field * 32 + bit];
- va = pv->pv_va;
- pte = pmap_pte(pmap, va);
- tpte = *pte;
- if ((tpte & PG_W) == 0)
- tpte = pte_load_clear(pte);
- pmap_pte_release(pte);
- if ((tpte & PG_W) != 0)
- continue;
- KASSERT(tpte != 0,
- ("pmap_pv_reclaim: pmap %p va %x zero pte",
- pmap, va));
- if ((tpte & PG_G) != 0)
- pmap_invalidate_page(pmap, va);
- m = PHYS_TO_VM_PAGE(tpte & PG_FRAME);
- if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW))
- vm_page_dirty(m);
- if ((tpte & PG_A) != 0)
- vm_page_aflag_set(m, PGA_REFERENCED);
- TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
- if (TAILQ_EMPTY(&m->md.pv_list))
- vm_page_aflag_clear(m, PGA_WRITEABLE);
- pc->pc_map[field] |= 1UL << bit;
- pmap_unuse_pt(pmap, va, &free);
- freed++;
- }
- }
- if (freed == 0) {
- TAILQ_INSERT_TAIL(&newtail, pc, pc_lru);
- continue;
- }
- /* Every freed mapping is for a 4 KB page. */
- pmap->pm_stats.resident_count -= freed;
- PV_STAT(pv_entry_frees += freed);
- PV_STAT(pv_entry_spare += freed);
- pv_entry_count -= freed;
- TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
- for (field = 0; field < _NPCM; field++)
- if (pc->pc_map[field] != pc_freemask[field]) {
- TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc,
- pc_list);
- TAILQ_INSERT_TAIL(&newtail, pc, pc_lru);
-
- /*
- * One freed pv entry in locked_pmap is
- * sufficient.
- */
- if (pmap == locked_pmap)
- goto out;
- break;
- }
- if (field == _NPCM) {
- PV_STAT(pv_entry_spare -= _NPCPV);
- PV_STAT(pc_chunk_count--);
- PV_STAT(pc_chunk_frees++);
- /* Entire chunk is free; return it. */
- m_pc = PHYS_TO_VM_PAGE(pmap_kextract((vm_offset_t)pc));
- pmap_qremove((vm_offset_t)pc, 1);
- pmap_ptelist_free(&pv_vafree, (vm_offset_t)pc);
- break;
- }
- }
-out:
- TAILQ_CONCAT(&pv_chunks, &newtail, pc_lru);
- if (pmap != NULL) {
- pmap_invalidate_all(pmap);
- if (pmap != locked_pmap)
- PMAP_UNLOCK(pmap);
- }
- if (m_pc == NULL && pv_vafree != 0 && free != NULL) {
- m_pc = free;
- free = (void *)m_pc->object;
- /* Recycle a freed page table page. */
- m_pc->wire_count = 1;
- atomic_add_int(&vm_cnt.v_wire_count, 1);
- }
- pmap_free_zero_pages(free);
- return (m_pc);
-}
-
-/*
- * free the pv_entry back to the free list
- */
-static void
-free_pv_entry(pmap_t pmap, pv_entry_t pv)
-{
- struct pv_chunk *pc;
- int idx, field, bit;
-
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- PMAP_LOCK_ASSERT(pmap, MA_OWNED);
- PV_STAT(pv_entry_frees++);
- PV_STAT(pv_entry_spare++);
- pv_entry_count--;
- pc = pv_to_chunk(pv);
- idx = pv - &pc->pc_pventry[0];
- field = idx / 32;
- bit = idx % 32;
- pc->pc_map[field] |= 1ul << bit;
- for (idx = 0; idx < _NPCM; idx++)
- if (pc->pc_map[idx] != pc_freemask[idx]) {
- /*
- * 98% of the time, pc is already at the head of the
- * list. If it isn't already, move it to the head.
- */
- if (__predict_false(TAILQ_FIRST(&pmap->pm_pvchunk) !=
- pc)) {
- TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
- TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc,
- pc_list);
- }
- return;
- }
- TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
- free_pv_chunk(pc);
-}
-
-static void
-free_pv_chunk(struct pv_chunk *pc)
-{
- vm_page_t m;
-
- TAILQ_REMOVE(&pv_chunks, pc, pc_lru);
- PV_STAT(pv_entry_spare -= _NPCPV);
- PV_STAT(pc_chunk_count--);
- PV_STAT(pc_chunk_frees++);
- /* entire chunk is free, return it */
- m = PHYS_TO_VM_PAGE(pmap_kextract((vm_offset_t)pc));
- pmap_qremove((vm_offset_t)pc, 1);
- vm_page_unwire(m, PQ_INACTIVE);
- vm_page_free(m);
- pmap_ptelist_free(&pv_vafree, (vm_offset_t)pc);
-}
-
-/*
- * get a new pv_entry, allocating a block from the system
- * when needed.
- */
-static pv_entry_t
-get_pv_entry(pmap_t pmap, boolean_t try)
-{
- static const struct timeval printinterval = { 60, 0 };
- static struct timeval lastprint;
- int bit, field;
- pv_entry_t pv;
- struct pv_chunk *pc;
- vm_page_t m;
-
- PMAP_LOCK_ASSERT(pmap, MA_OWNED);
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- PV_STAT(pv_entry_allocs++);
- pv_entry_count++;
- if (pv_entry_count > pv_entry_high_water)
- if (ratecheck(&lastprint, &printinterval))
- printf("Approaching the limit on PV entries, consider "
- "increasing either the vm.pmap.shpgperproc or the "
- "vm.pmap.pv_entry_max tunable.\n");
-retry:
- pc = TAILQ_FIRST(&pmap->pm_pvchunk);
- if (pc != NULL) {
- for (field = 0; field < _NPCM; field++) {
- if (pc->pc_map[field]) {
- bit = bsfl(pc->pc_map[field]);
- break;
- }
- }
- if (field < _NPCM) {
- pv = &pc->pc_pventry[field * 32 + bit];
- pc->pc_map[field] &= ~(1ul << bit);
- /* If this was the last item, move it to tail */
- for (field = 0; field < _NPCM; field++)
- if (pc->pc_map[field] != 0) {
- PV_STAT(pv_entry_spare--);
- return (pv); /* not full, return */
- }
- TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
- TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, pc_list);
- PV_STAT(pv_entry_spare--);
- return (pv);
- }
- }
- /*
- * Access to the ptelist "pv_vafree" is synchronized by the page
- * queues lock. If "pv_vafree" is currently non-empty, it will
- * remain non-empty until pmap_ptelist_alloc() completes.
- */
- if (pv_vafree == 0 || (m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
- VM_ALLOC_NOOBJ | VM_ALLOC_WIRED)) == NULL) {
- if (try) {
- pv_entry_count--;
- PV_STAT(pc_chunk_tryfail++);
- return (NULL);
- }
- m = pmap_pv_reclaim(pmap);
- if (m == NULL)
- goto retry;
- }
- PV_STAT(pc_chunk_count++);
- PV_STAT(pc_chunk_allocs++);
- pc = (struct pv_chunk *)pmap_ptelist_alloc(&pv_vafree);
- pmap_qenter((vm_offset_t)pc, &m, 1);
- if ((m->flags & PG_ZERO) == 0)
- pagezero(pc);
- pc->pc_pmap = pmap;
- pc->pc_map[0] = pc_freemask[0] & ~1ul; /* preallocated bit 0 */
- for (field = 1; field < _NPCM; field++)
- pc->pc_map[field] = pc_freemask[field];
- TAILQ_INSERT_TAIL(&pv_chunks, pc, pc_lru);
- pv = &pc->pc_pventry[0];
- TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list);
- PV_STAT(pv_entry_spare += _NPCPV - 1);
- return (pv);
-}
-
-static __inline pv_entry_t
-pmap_pvh_remove(struct md_page *pvh, pmap_t pmap, vm_offset_t va)
-{
- pv_entry_t pv;
-
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) {
- if (pmap == PV_PMAP(pv) && va == pv->pv_va) {
- TAILQ_REMOVE(&pvh->pv_list, pv, pv_next);
- break;
- }
- }
- return (pv);
-}
-
-static void
-pmap_pvh_free(struct md_page *pvh, pmap_t pmap, vm_offset_t va)
-{
- pv_entry_t pv;
-
- pv = pmap_pvh_remove(pvh, pmap, va);
- KASSERT(pv != NULL, ("pmap_pvh_free: pv not found"));
- free_pv_entry(pmap, pv);
-}
-
-static void
-pmap_remove_entry(pmap_t pmap, vm_page_t m, vm_offset_t va)
-{
-
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- pmap_pvh_free(&m->md, pmap, va);
- if (TAILQ_EMPTY(&m->md.pv_list))
- vm_page_aflag_clear(m, PGA_WRITEABLE);
-}
-
-/*
- * Conditionally create a pv entry.
- */
-static boolean_t
-pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m)
-{
- pv_entry_t pv;
-
- PMAP_LOCK_ASSERT(pmap, MA_OWNED);
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- if (pv_entry_count < pv_entry_high_water &&
- (pv = get_pv_entry(pmap, TRUE)) != NULL) {
- pv->pv_va = va;
- TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next);
- return (TRUE);
- } else
- return (FALSE);
-}
-
-/*
- * pmap_remove_pte: do the things to unmap a page in a process
- */
-static int
-pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va, vm_page_t *free)
-{
- pt_entry_t oldpte;
- vm_page_t m;
-
- CTR3(KTR_PMAP, "pmap_remove_pte: pmap=%p *ptq=0x%x va=0x%x",
- pmap, (u_long)*ptq, va);
-
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- PMAP_LOCK_ASSERT(pmap, MA_OWNED);
- oldpte = *ptq;
- PT_SET_VA_MA(ptq, 0, TRUE);
- KASSERT(oldpte != 0,
- ("pmap_remove_pte: pmap %p va %x zero pte", pmap, va));
- if (oldpte & PG_W)
- pmap->pm_stats.wired_count -= 1;
- /*
- * Machines that don't support invlpg, also don't support
- * PG_G.
- */
- if (oldpte & PG_G)
- pmap_invalidate_page(kernel_pmap, va);
- pmap->pm_stats.resident_count -= 1;
- if (oldpte & PG_MANAGED) {
- m = PHYS_TO_VM_PAGE(xpmap_mtop(oldpte) & PG_FRAME);
- if ((oldpte & (PG_M | PG_RW)) == (PG_M | PG_RW))
- vm_page_dirty(m);
- if (oldpte & PG_A)
- vm_page_aflag_set(m, PGA_REFERENCED);
- pmap_remove_entry(pmap, m, va);
- }
- return (pmap_unuse_pt(pmap, va, free));
-}
-
-/*
- * Remove a single page from a process address space
- */
-static void
-pmap_remove_page(pmap_t pmap, vm_offset_t va, vm_page_t *free)
-{
- pt_entry_t *pte;
-
- CTR2(KTR_PMAP, "pmap_remove_page: pmap=%p va=0x%x",
- pmap, va);
-
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- KASSERT(curthread->td_pinned > 0, ("curthread not pinned"));
- PMAP_LOCK_ASSERT(pmap, MA_OWNED);
- if ((pte = pmap_pte_quick(pmap, va)) == NULL || (*pte & PG_V) == 0)
- return;
- pmap_remove_pte(pmap, pte, va, free);
- pmap_invalidate_page(pmap, va);
- if (*PMAP1)
- PT_SET_MA(PADDR1, 0);
-
-}
-
-/*
- * Remove the given range of addresses from the specified map.
- *
- * It is assumed that the start and end are properly
- * rounded to the page size.
- */
-void
-pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
-{
- vm_offset_t pdnxt;
- pd_entry_t ptpaddr;
- pt_entry_t *pte;
- vm_page_t free = NULL;
- int anyvalid;
-
- CTR3(KTR_PMAP, "pmap_remove: pmap=%p sva=0x%x eva=0x%x",
- pmap, sva, eva);
-
- /*
- * Perform an unsynchronized read. This is, however, safe.
- */
- if (pmap->pm_stats.resident_count == 0)
- return;
-
- anyvalid = 0;
-
- rw_wlock(&pvh_global_lock);
- sched_pin();
- PMAP_LOCK(pmap);
-
- /*
- * special handling of removing one page. a very
- * common operation and easy to short circuit some
- * code.
- */
- if ((sva + PAGE_SIZE == eva) &&
- ((pmap->pm_pdir[(sva >> PDRSHIFT)] & PG_PS) == 0)) {
- pmap_remove_page(pmap, sva, &free);
- goto out;
- }
-
- for (; sva < eva; sva = pdnxt) {
- u_int pdirindex;
-
- /*
- * Calculate index for next page table.
- */
- pdnxt = (sva + NBPDR) & ~PDRMASK;
- if (pdnxt < sva)
- pdnxt = eva;
- if (pmap->pm_stats.resident_count == 0)
- break;
-
- pdirindex = sva >> PDRSHIFT;
- ptpaddr = pmap->pm_pdir[pdirindex];
-
- /*
- * Weed out invalid mappings. Note: we assume that the page
- * directory table is always allocated, and in kernel virtual.
- */
- if (ptpaddr == 0)
- continue;
-
- /*
- * Check for large page.
- */
- if ((ptpaddr & PG_PS) != 0) {
- PD_CLEAR_VA(pmap, pdirindex, TRUE);
- pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
- anyvalid = 1;
- continue;
- }
-
- /*
- * Limit our scan to either the end of the va represented
- * by the current page table page, or to the end of the
- * range being removed.
- */
- if (pdnxt > eva)
- pdnxt = eva;
-
- for (pte = pmap_pte_quick(pmap, sva); sva != pdnxt; pte++,
- sva += PAGE_SIZE) {
- if ((*pte & PG_V) == 0)
- continue;
-
- /*
- * The TLB entry for a PG_G mapping is invalidated
- * by pmap_remove_pte().
- */
- if ((*pte & PG_G) == 0)
- anyvalid = 1;
- if (pmap_remove_pte(pmap, pte, sva, &free))
- break;
- }
- }
- PT_UPDATES_FLUSH();
- if (*PMAP1)
- PT_SET_VA_MA(PMAP1, 0, TRUE);
-out:
- if (anyvalid)
- pmap_invalidate_all(pmap);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
- pmap_free_zero_pages(free);
-}
-
-/*
- * Routine: pmap_remove_all
- * Function:
- * Removes this physical page from
- * all physical maps in which it resides.
- * Reflects back modify bits to the pager.
- *
- * Notes:
- * Original versions of this routine were very
- * inefficient because they iteratively called
- * pmap_remove (slow...)
- */
-
-void
-pmap_remove_all(vm_page_t m)
-{
- pv_entry_t pv;
- pmap_t pmap;
- pt_entry_t *pte, tpte;
- vm_page_t free;
-
- KASSERT((m->oflags & VPO_UNMANAGED) == 0,
- ("pmap_remove_all: page %p is not managed", m));
- free = NULL;
- rw_wlock(&pvh_global_lock);
- sched_pin();
- while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) {
- pmap = PV_PMAP(pv);
- PMAP_LOCK(pmap);
- pmap->pm_stats.resident_count--;
- pte = pmap_pte_quick(pmap, pv->pv_va);
- tpte = *pte;
- PT_SET_VA_MA(pte, 0, TRUE);
- KASSERT(tpte != 0, ("pmap_remove_all: pmap %p va %x zero pte",
- pmap, pv->pv_va));
- if (tpte & PG_W)
- pmap->pm_stats.wired_count--;
- if (tpte & PG_A)
- vm_page_aflag_set(m, PGA_REFERENCED);
-
- /*
- * Update the vm_page_t clean and reference bits.
- */
- if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW))
- vm_page_dirty(m);
- pmap_unuse_pt(pmap, pv->pv_va, &free);
- pmap_invalidate_page(pmap, pv->pv_va);
- TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
- free_pv_entry(pmap, pv);
- PMAP_UNLOCK(pmap);
- }
- vm_page_aflag_clear(m, PGA_WRITEABLE);
- PT_UPDATES_FLUSH();
- if (*PMAP1)
- PT_SET_MA(PADDR1, 0);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- pmap_free_zero_pages(free);
-}
-
-/*
- * Set the physical protection on the
- * specified range of this map as requested.
- */
-void
-pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
-{
- vm_offset_t pdnxt;
- pd_entry_t ptpaddr;
- pt_entry_t *pte;
- int anychanged;
-
- CTR4(KTR_PMAP, "pmap_protect: pmap=%p sva=0x%x eva=0x%x prot=0x%x",
- pmap, sva, eva, prot);
-
- if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
- pmap_remove(pmap, sva, eva);
- return;
- }
-
-#ifdef PAE
- if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
- (VM_PROT_WRITE|VM_PROT_EXECUTE))
- return;
-#else
- if (prot & VM_PROT_WRITE)
- return;
-#endif
-
- anychanged = 0;
-
- rw_wlock(&pvh_global_lock);
- sched_pin();
- PMAP_LOCK(pmap);
- for (; sva < eva; sva = pdnxt) {
- pt_entry_t obits, pbits;
- u_int pdirindex;
-
- pdnxt = (sva + NBPDR) & ~PDRMASK;
- if (pdnxt < sva)
- pdnxt = eva;
-
- pdirindex = sva >> PDRSHIFT;
- ptpaddr = pmap->pm_pdir[pdirindex];
-
- /*
- * Weed out invalid mappings. Note: we assume that the page
- * directory table is always allocated, and in kernel virtual.
- */
- if (ptpaddr == 0)
- continue;
-
- /*
- * Check for large page.
- */
- if ((ptpaddr & PG_PS) != 0) {
- if ((prot & VM_PROT_WRITE) == 0)
- pmap->pm_pdir[pdirindex] &= ~(PG_M|PG_RW);
-#ifdef PAE
- if ((prot & VM_PROT_EXECUTE) == 0)
- pmap->pm_pdir[pdirindex] |= pg_nx;
-#endif
- anychanged = 1;
- continue;
- }
-
- if (pdnxt > eva)
- pdnxt = eva;
-
- for (pte = pmap_pte_quick(pmap, sva); sva != pdnxt; pte++,
- sva += PAGE_SIZE) {
- vm_page_t m;
-
-retry:
- /*
- * Regardless of whether a pte is 32 or 64 bits in
- * size, PG_RW, PG_A, and PG_M are among the least
- * significant 32 bits.
- */
- obits = pbits = *pte;
- if ((pbits & PG_V) == 0)
- continue;
-
- if ((prot & VM_PROT_WRITE) == 0) {
- if ((pbits & (PG_MANAGED | PG_M | PG_RW)) ==
- (PG_MANAGED | PG_M | PG_RW)) {
- m = PHYS_TO_VM_PAGE(xpmap_mtop(pbits) &
- PG_FRAME);
- vm_page_dirty(m);
- }
- pbits &= ~(PG_RW | PG_M);
- }
-#ifdef PAE
- if ((prot & VM_PROT_EXECUTE) == 0)
- pbits |= pg_nx;
-#endif
-
- if (pbits != obits) {
- obits = *pte;
- PT_SET_VA_MA(pte, pbits, TRUE);
- if (*pte != pbits)
- goto retry;
- if (obits & PG_G)
- pmap_invalidate_page(pmap, sva);
- else
- anychanged = 1;
- }
- }
- }
- PT_UPDATES_FLUSH();
- if (*PMAP1)
- PT_SET_VA_MA(PMAP1, 0, TRUE);
- if (anychanged)
- pmap_invalidate_all(pmap);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
-}
-
-/*
- * Insert the given physical page (p) at
- * the specified virtual address (v) in the
- * target physical map with the protection requested.
- *
- * If specified, the page will be wired down, meaning
- * that the related pte can not be reclaimed.
- *
- * NB: This is the only routine which MAY NOT lazy-evaluate
- * or lose information. That is, this routine must actually
- * insert this page into the given map NOW.
- */
-int
-pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
- u_int flags, int8_t psind __unused)
-{
- pd_entry_t *pde;
- pt_entry_t *pte;
- pt_entry_t newpte, origpte;
- pv_entry_t pv;
- vm_paddr_t opa, pa;
- vm_page_t mpte, om;
- boolean_t invlva, wired;
-
- CTR5(KTR_PMAP,
- "pmap_enter: pmap=%08p va=0x%08x ma=0x%08x prot=0x%x flags=0x%x",
- pmap, va, VM_PAGE_TO_MACH(m), prot, flags);
- va = trunc_page(va);
- KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig"));
- KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS,
- ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)",
- va));
- if ((m->oflags & VPO_UNMANAGED) == 0 && !vm_page_xbusied(m))
- VM_OBJECT_ASSERT_LOCKED(m->object);
-
- mpte = NULL;
- wired = (flags & PMAP_ENTER_WIRED) != 0;
-
- rw_wlock(&pvh_global_lock);
- PMAP_LOCK(pmap);
- sched_pin();
-
- /*
- * In the case that a page table page is not
- * resident, we are creating it here.
- */
- if (va < VM_MAXUSER_ADDRESS) {
- mpte = pmap_allocpte(pmap, va, flags);
- if (mpte == NULL) {
- KASSERT((flags & PMAP_ENTER_NOSLEEP) != 0,
- ("pmap_allocpte failed with sleep allowed"));
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
- return (KERN_RESOURCE_SHORTAGE);
- }
- }
-
- pde = pmap_pde(pmap, va);
- if ((*pde & PG_PS) != 0)
- panic("pmap_enter: attempted pmap_enter on 4MB page");
- pte = pmap_pte_quick(pmap, va);
-
- /*
- * Page Directory table entry not valid, we need a new PT page
- */
- if (pte == NULL) {
- panic("pmap_enter: invalid page directory pdir=%#jx, va=%#x",
- (uintmax_t)pmap->pm_pdir[va >> PDRSHIFT], va);
- }
-
- pa = VM_PAGE_TO_PHYS(m);
- om = NULL;
- opa = origpte = 0;
-
-#if 0
- KASSERT((*pte & PG_V) || (*pte == 0), ("address set but not valid pte=%p *pte=0x%016jx",
- pte, *pte));
-#endif
- origpte = *pte;
- if (origpte)
- origpte = xpmap_mtop(origpte);
- opa = origpte & PG_FRAME;
-
- /*
- * Mapping has not changed, must be protection or wiring change.
- */
- if (origpte && (opa == pa)) {
- /*
- * Wiring change, just update stats. We don't worry about
- * wiring PT pages as they remain resident as long as there
- * are valid mappings in them. Hence, if a user page is wired,
- * the PT page will be also.
- */
- if (wired && ((origpte & PG_W) == 0))
- pmap->pm_stats.wired_count++;
- else if (!wired && (origpte & PG_W))
- pmap->pm_stats.wired_count--;
-
- /*
- * Remove extra pte reference
- */
- if (mpte)
- mpte->wire_count--;
-
- if (origpte & PG_MANAGED) {
- om = m;
- pa |= PG_MANAGED;
- }
- goto validate;
- }
-
- pv = NULL;
-
- /*
- * Mapping has changed, invalidate old range and fall through to
- * handle validating new mapping.
- */
- if (opa) {
- if (origpte & PG_W)
- pmap->pm_stats.wired_count--;
- if (origpte & PG_MANAGED) {
- om = PHYS_TO_VM_PAGE(opa);
- pv = pmap_pvh_remove(&om->md, pmap, va);
- } else if (va < VM_MAXUSER_ADDRESS)
- printf("va=0x%x is unmanaged :-( \n", va);
-
- if (mpte != NULL) {
- mpte->wire_count--;
- KASSERT(mpte->wire_count > 0,
- ("pmap_enter: missing reference to page table page,"
- " va: 0x%x", va));
- }
- } else
- pmap->pm_stats.resident_count++;
-
- /*
- * Enter on the PV list if part of our managed memory.
- */
- if ((m->oflags & VPO_UNMANAGED) == 0) {
- KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva,
- ("pmap_enter: managed mapping within the clean submap"));
- if (pv == NULL)
- pv = get_pv_entry(pmap, FALSE);
- pv->pv_va = va;
- TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next);
- pa |= PG_MANAGED;
- } else if (pv != NULL)
- free_pv_entry(pmap, pv);
-
- /*
- * Increment counters
- */
- if (wired)
- pmap->pm_stats.wired_count++;
-
-validate:
- /*
- * Now validate mapping with desired protection/wiring.
- */
- newpte = (pt_entry_t)(pa | PG_V);
- if ((prot & VM_PROT_WRITE) != 0) {
- newpte |= PG_RW;
- if ((newpte & PG_MANAGED) != 0)
- vm_page_aflag_set(m, PGA_WRITEABLE);
- }
-#ifdef PAE
- if ((prot & VM_PROT_EXECUTE) == 0)
- newpte |= pg_nx;
-#endif
- if (wired)
- newpte |= PG_W;
- if (va < VM_MAXUSER_ADDRESS)
- newpte |= PG_U;
- if (pmap == kernel_pmap)
- newpte |= pgeflag;
-
- critical_enter();
- /*
- * if the mapping or permission bits are different, we need
- * to update the pte.
- */
- if ((origpte & ~(PG_M|PG_A)) != newpte) {
- if (origpte) {
- invlva = FALSE;
- origpte = *pte;
- PT_SET_VA(pte, newpte | PG_A, FALSE);
- if (origpte & PG_A) {
- if (origpte & PG_MANAGED)
- vm_page_aflag_set(om, PGA_REFERENCED);
- if (opa != VM_PAGE_TO_PHYS(m))
- invlva = TRUE;
-#ifdef PAE
- if ((origpte & PG_NX) == 0 &&
- (newpte & PG_NX) != 0)
- invlva = TRUE;
-#endif
- }
- if ((origpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) {
- if ((origpte & PG_MANAGED) != 0)
- vm_page_dirty(om);
- if ((prot & VM_PROT_WRITE) == 0)
- invlva = TRUE;
- }
- if ((origpte & PG_MANAGED) != 0 &&
- TAILQ_EMPTY(&om->md.pv_list))
- vm_page_aflag_clear(om, PGA_WRITEABLE);
- if (invlva)
- pmap_invalidate_page(pmap, va);
- } else{
- PT_SET_VA(pte, newpte | PG_A, FALSE);
- }
-
- }
- PT_UPDATES_FLUSH();
- critical_exit();
- if (*PMAP1)
- PT_SET_VA_MA(PMAP1, 0, TRUE);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
- return (KERN_SUCCESS);
-}
-
-/*
- * Maps a sequence of resident pages belonging to the same object.
- * The sequence begins with the given page m_start. This page is
- * mapped at the given virtual address start. Each subsequent page is
- * mapped at a virtual address that is offset from start by the same
- * amount as the page is offset from m_start within the object. The
- * last page in the sequence is the page with the largest offset from
- * m_start that can be mapped at a virtual address less than the given
- * virtual address end. Not every virtual page between start and end
- * is mapped; only those for which a resident page exists with the
- * corresponding offset from m_start are mapped.
- */
-void
-pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end,
- vm_page_t m_start, vm_prot_t prot)
-{
- vm_page_t m, mpte;
- vm_pindex_t diff, psize;
- multicall_entry_t mcl[16];
- multicall_entry_t *mclp = mcl;
- int error, count = 0;
-
- VM_OBJECT_ASSERT_LOCKED(m_start->object);
-
- psize = atop(end - start);
- mpte = NULL;
- m = m_start;
- rw_wlock(&pvh_global_lock);
- PMAP_LOCK(pmap);
- while (m != NULL && (diff = m->pindex - m_start->pindex) < psize) {
- mpte = pmap_enter_quick_locked(&mclp, &count, pmap, start + ptoa(diff), m,
- prot, mpte);
- m = TAILQ_NEXT(m, listq);
- if (count == 16) {
- error = HYPERVISOR_multicall(mcl, count);
- KASSERT(error == 0, ("bad multicall %d", error));
- mclp = mcl;
- count = 0;
- }
- }
- if (count) {
- error = HYPERVISOR_multicall(mcl, count);
- KASSERT(error == 0, ("bad multicall %d", error));
- }
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
-}
-
-/*
- * this code makes some *MAJOR* assumptions:
- * 1. Current pmap & pmap exists.
- * 2. Not wired.
- * 3. Read access.
- * 4. No page table pages.
- * but is *MUCH* faster than pmap_enter...
- */
-
-void
-pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot)
-{
- multicall_entry_t mcl, *mclp;
- int count = 0;
- mclp = &mcl;
-
- CTR4(KTR_PMAP, "pmap_enter_quick: pmap=%p va=0x%x m=%p prot=0x%x",
- pmap, va, m, prot);
-
- rw_wlock(&pvh_global_lock);
- PMAP_LOCK(pmap);
- (void)pmap_enter_quick_locked(&mclp, &count, pmap, va, m, prot, NULL);
- if (count)
- HYPERVISOR_multicall(&mcl, count);
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
-}
-
-#ifdef notyet
-void
-pmap_enter_quick_range(pmap_t pmap, vm_offset_t *addrs, vm_page_t *pages, vm_prot_t *prots, int count)
-{
- int i, error, index = 0;
- multicall_entry_t mcl[16];
- multicall_entry_t *mclp = mcl;
-
- PMAP_LOCK(pmap);
- for (i = 0; i < count; i++, addrs++, pages++, prots++) {
- if (!pmap_is_prefaultable_locked(pmap, *addrs))
- continue;
-
- (void) pmap_enter_quick_locked(&mclp, &index, pmap, *addrs, *pages, *prots, NULL);
- if (index == 16) {
- error = HYPERVISOR_multicall(mcl, index);
- mclp = mcl;
- index = 0;
- KASSERT(error == 0, ("bad multicall %d", error));
- }
- }
- if (index) {
- error = HYPERVISOR_multicall(mcl, index);
- KASSERT(error == 0, ("bad multicall %d", error));
- }
-
- PMAP_UNLOCK(pmap);
-}
-#endif
-
-static vm_page_t
-pmap_enter_quick_locked(multicall_entry_t **mclpp, int *count, pmap_t pmap, vm_offset_t va, vm_page_t m,
- vm_prot_t prot, vm_page_t mpte)
-{
- pt_entry_t *pte;
- vm_paddr_t pa;
- vm_page_t free;
- multicall_entry_t *mcl = *mclpp;
-
- KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva ||
- (m->oflags & VPO_UNMANAGED) != 0,
- ("pmap_enter_quick_locked: managed mapping within the clean submap"));
- rw_assert(&pvh_global_lock, RA_WLOCKED);
- PMAP_LOCK_ASSERT(pmap, MA_OWNED);
-
- /*
- * In the case that a page table page is not
- * resident, we are creating it here.
- */
- if (va < VM_MAXUSER_ADDRESS) {
- u_int ptepindex;
- pd_entry_t ptema;
-
- /*
- * Calculate pagetable page index
- */
- ptepindex = va >> PDRSHIFT;
- if (mpte && (mpte->pindex == ptepindex)) {
- mpte->wire_count++;
- } else {
- /*
- * Get the page directory entry
- */
- ptema = pmap->pm_pdir[ptepindex];
-
- /*
- * If the page table page is mapped, we just increment
- * the hold count, and activate it.
- */
- if (ptema & PG_V) {
- if (ptema & PG_PS)
- panic("pmap_enter_quick: unexpected mapping into 4MB page");
- mpte = PHYS_TO_VM_PAGE(xpmap_mtop(ptema) & PG_FRAME);
- mpte->wire_count++;
- } else {
- mpte = _pmap_allocpte(pmap, ptepindex,
- PMAP_ENTER_NOSLEEP);
- if (mpte == NULL)
- return (mpte);
- }
- }
- } else {
- mpte = NULL;
- }
-
- /*
- * This call to vtopte makes the assumption that we are
- * entering the page into the current pmap. In order to support
- * quick entry into any pmap, one would likely use pmap_pte_quick.
- * But that isn't as quick as vtopte.
- */
- KASSERT(pmap_is_current(pmap), ("entering pages in non-current pmap"));
- pte = vtopte(va);
- if (*pte & PG_V) {
- if (mpte != NULL) {
- mpte->wire_count--;
- mpte = NULL;
- }
- return (mpte);
- }
-
- /*
- * Enter on the PV list if part of our managed memory.
- */
- if ((m->oflags & VPO_UNMANAGED) == 0 &&
- !pmap_try_insert_pv_entry(pmap, va, m)) {
- if (mpte != NULL) {
- free = NULL;
- if (pmap_unwire_ptp(pmap, mpte, &free)) {
- pmap_invalidate_page(pmap, va);
- pmap_free_zero_pages(free);
- }
-
- mpte = NULL;
- }
- return (mpte);
- }
-
- /*
- * Increment counters
- */
- pmap->pm_stats.resident_count++;
-
- pa = VM_PAGE_TO_PHYS(m);
-#ifdef PAE
- if ((prot & VM_PROT_EXECUTE) == 0)
- pa |= pg_nx;
-#endif
-
-#if 0
- /*
- * Now validate mapping with RO protection
- */
- if ((m->oflags & VPO_UNMANAGED) != 0)
- pte_store(pte, pa | PG_V | PG_U);
- else
- pte_store(pte, pa | PG_V | PG_U | PG_MANAGED);
-#else
- /*
- * Now validate mapping with RO protection
- */
- if ((m->oflags & VPO_UNMANAGED) != 0)
- pa = xpmap_ptom(pa | PG_V | PG_U);
- else
- pa = xpmap_ptom(pa | PG_V | PG_U | PG_MANAGED);
-
- mcl->op = __HYPERVISOR_update_va_mapping;
- mcl->args[0] = va;
- mcl->args[1] = (uint32_t)(pa & 0xffffffff);
- mcl->args[2] = (uint32_t)(pa >> 32);
- mcl->args[3] = 0;
- *mclpp = mcl + 1;
- *count = *count + 1;
-#endif
- return (mpte);
-}
-
-/*
- * Make a temporary mapping for a physical address. This is only intended
- * to be used for panic dumps.
- */
-void *
-pmap_kenter_temporary(vm_paddr_t pa, int i)
-{
- vm_offset_t va;
- vm_paddr_t ma = xpmap_ptom(pa);
-
- va = (vm_offset_t)crashdumpmap + (i * PAGE_SIZE);
- PT_SET_MA(va, (ma & ~PAGE_MASK) | PG_V | pgeflag);
- invlpg(va);
- return ((void *)crashdumpmap);
-}
-
-/*
- * This code maps large physical mmap regions into the
- * processor address space. Note that some shortcuts
- * are taken, but the code works.
- */
-void
-pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_object_t object,
- vm_pindex_t pindex, vm_size_t size)
-{
- pd_entry_t *pde;
- vm_paddr_t pa, ptepa;
- vm_page_t p;
- int pat_mode;
-
- VM_OBJECT_ASSERT_WLOCKED(object);
- KASSERT(object->type == OBJT_DEVICE || object->type == OBJT_SG,
- ("pmap_object_init_pt: non-device object"));
- if (pseflag &&
- (addr & (NBPDR - 1)) == 0 && (size & (NBPDR - 1)) == 0) {
- if (!vm_object_populate(object, pindex, pindex + atop(size)))
- return;
- p = vm_page_lookup(object, pindex);
- KASSERT(p->valid == VM_PAGE_BITS_ALL,
- ("pmap_object_init_pt: invalid page %p", p));
- pat_mode = p->md.pat_mode;
-
- /*
- * Abort the mapping if the first page is not physically
- * aligned to a 2/4MB page boundary.
- */
- ptepa = VM_PAGE_TO_PHYS(p);
- if (ptepa & (NBPDR - 1))
- return;
-
- /*
- * Skip the first page. Abort the mapping if the rest of
- * the pages are not physically contiguous or have differing
- * memory attributes.
- */
- p = TAILQ_NEXT(p, listq);
- for (pa = ptepa + PAGE_SIZE; pa < ptepa + size;
- pa += PAGE_SIZE) {
- KASSERT(p->valid == VM_PAGE_BITS_ALL,
- ("pmap_object_init_pt: invalid page %p", p));
- if (pa != VM_PAGE_TO_PHYS(p) ||
- pat_mode != p->md.pat_mode)
- return;
- p = TAILQ_NEXT(p, listq);
- }
-
- /*
- * Map using 2/4MB pages. Since "ptepa" is 2/4M aligned and
- * "size" is a multiple of 2/4M, adding the PAT setting to
- * "pa" will not affect the termination of this loop.
- */
- PMAP_LOCK(pmap);
- for (pa = ptepa | pmap_cache_bits(pat_mode, 1); pa < ptepa +
- size; pa += NBPDR) {
- pde = pmap_pde(pmap, addr);
- if (*pde == 0) {
- pde_store(pde, pa | PG_PS | PG_M | PG_A |
- PG_U | PG_RW | PG_V);
- pmap->pm_stats.resident_count += NBPDR /
- PAGE_SIZE;
- pmap_pde_mappings++;
- }
- /* Else continue on if the PDE is already valid. */
- addr += NBPDR;
- }
- PMAP_UNLOCK(pmap);
- }
-}
-
-/*
- * Clear the wired attribute from the mappings for the specified range of
- * addresses in the given pmap. Every valid mapping within that range
- * must have the wired attribute set. In contrast, invalid mappings
- * cannot have the wired attribute set, so they are ignored.
- *
- * The wired attribute of the page table entry is not a hardware feature,
- * so there is no need to invalidate any TLB entries.
- */
-void
-pmap_unwire(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
-{
- vm_offset_t pdnxt;
- pd_entry_t *pde;
- pt_entry_t *pte;
-
- CTR3(KTR_PMAP, "pmap_unwire: pmap=%p sva=0x%x eva=0x%x", pmap, sva,
- eva);
- rw_wlock(&pvh_global_lock);
- sched_pin();
- PMAP_LOCK(pmap);
- for (; sva < eva; sva = pdnxt) {
- pdnxt = (sva + NBPDR) & ~PDRMASK;
- if (pdnxt < sva)
- pdnxt = eva;
- pde = pmap_pde(pmap, sva);
- if ((*pde & PG_V) == 0)
- continue;
- if ((*pde & PG_PS) != 0)
- panic("pmap_unwire: unexpected PG_PS in pde %#jx",
- (uintmax_t)*pde);
- if (pdnxt > eva)
- pdnxt = eva;
- for (pte = pmap_pte_quick(pmap, sva); sva != pdnxt; pte++,
- sva += PAGE_SIZE) {
- if ((*pte & PG_V) == 0)
- continue;
- if ((*pte & PG_W) == 0)
- panic("pmap_unwire: pte %#jx is missing PG_W",
- (uintmax_t)*pte);
- PT_SET_VA_MA(pte, *pte & ~PG_W, FALSE);
- pmap->pm_stats.wired_count--;
- }
- }
- if (*PMAP1)
- PT_CLEAR_VA(PMAP1, FALSE);
- PT_UPDATES_FLUSH();
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
-}
-
-
-/*
- * Copy the range specified by src_addr/len
- * from the source map to the range dst_addr/len
- * in the destination map.
- *
- * This routine is only advisory and need not do anything.
- */
-
-void
-pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
- vm_offset_t src_addr)
-{
- vm_page_t free;
- vm_offset_t addr;
- vm_offset_t end_addr = src_addr + len;
- vm_offset_t pdnxt;
-
- if (dst_addr != src_addr)
- return;
-
- if (!pmap_is_current(src_pmap)) {
- CTR2(KTR_PMAP,
- "pmap_copy, skipping: pdir[PTDPTDI]=0x%jx PTDpde[0]=0x%jx",
- (src_pmap->pm_pdir[PTDPTDI] & PG_FRAME), (PTDpde[0] & PG_FRAME));
-
- return;
- }
- CTR5(KTR_PMAP, "pmap_copy: dst_pmap=%p src_pmap=%p dst_addr=0x%x len=%d src_addr=0x%x",
- dst_pmap, src_pmap, dst_addr, len, src_addr);
-
-#ifdef HAMFISTED_LOCKING
- mtx_lock(&createdelete_lock);
-#endif
-
- rw_wlock(&pvh_global_lock);
- if (dst_pmap < src_pmap) {
- PMAP_LOCK(dst_pmap);
- PMAP_LOCK(src_pmap);
- } else {
- PMAP_LOCK(src_pmap);
- PMAP_LOCK(dst_pmap);
- }
- sched_pin();
- for (addr = src_addr; addr < end_addr; addr = pdnxt) {
- pt_entry_t *src_pte, *dst_pte;
- vm_page_t dstmpte, srcmpte;
- pd_entry_t srcptepaddr;
- u_int ptepindex;
-
- KASSERT(addr < UPT_MIN_ADDRESS,
- ("pmap_copy: invalid to pmap_copy page tables"));
-
- pdnxt = (addr + NBPDR) & ~PDRMASK;
- if (pdnxt < addr)
- pdnxt = end_addr;
- ptepindex = addr >> PDRSHIFT;
-
- srcptepaddr = PT_GET(&src_pmap->pm_pdir[ptepindex]);
- if (srcptepaddr == 0)
- continue;
-
- if (srcptepaddr & PG_PS) {
- if (dst_pmap->pm_pdir[ptepindex] == 0) {
- PD_SET_VA(dst_pmap, ptepindex, srcptepaddr & ~PG_W, TRUE);
- dst_pmap->pm_stats.resident_count +=
- NBPDR / PAGE_SIZE;
- }
- continue;
- }
-
- srcmpte = PHYS_TO_VM_PAGE(srcptepaddr & PG_FRAME);
- KASSERT(srcmpte->wire_count > 0,
- ("pmap_copy: source page table page is unused"));
-
- if (pdnxt > end_addr)
- pdnxt = end_addr;
-
- src_pte = vtopte(addr);
- while (addr < pdnxt) {
- pt_entry_t ptetemp;
- ptetemp = *src_pte;
- /*
- * we only virtual copy managed pages
- */
- if ((ptetemp & PG_MANAGED) != 0) {
- dstmpte = pmap_allocpte(dst_pmap, addr,
- PMAP_ENTER_NOSLEEP);
- if (dstmpte == NULL)
- goto out;
- dst_pte = pmap_pte_quick(dst_pmap, addr);
- if (*dst_pte == 0 &&
- pmap_try_insert_pv_entry(dst_pmap, addr,
- PHYS_TO_VM_PAGE(xpmap_mtop(ptetemp) & PG_FRAME))) {
- /*
- * Clear the wired, modified, and
- * accessed (referenced) bits
- * during the copy.
- */
- KASSERT(ptetemp != 0, ("src_pte not set"));
- PT_SET_VA_MA(dst_pte, ptetemp & ~(PG_W | PG_M | PG_A), TRUE /* XXX debug */);
- KASSERT(*dst_pte == (ptetemp & ~(PG_W | PG_M | PG_A)),
- ("no pmap copy expected: 0x%jx saw: 0x%jx",
- ptetemp & ~(PG_W | PG_M | PG_A), *dst_pte));
- dst_pmap->pm_stats.resident_count++;
- } else {
- free = NULL;
- if (pmap_unwire_ptp(dst_pmap, dstmpte,
- &free)) {
- pmap_invalidate_page(dst_pmap,
- addr);
- pmap_free_zero_pages(free);
- }
- goto out;
- }
- if (dstmpte->wire_count >= srcmpte->wire_count)
- break;
- }
- addr += PAGE_SIZE;
- src_pte++;
- }
- }
-out:
- PT_UPDATES_FLUSH();
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(src_pmap);
- PMAP_UNLOCK(dst_pmap);
-
-#ifdef HAMFISTED_LOCKING
- mtx_unlock(&createdelete_lock);
-#endif
-}
-
-static __inline void
-pagezero(void *page)
-{
-#if defined(I686_CPU)
- if (cpu_class == CPUCLASS_686) {
-#if defined(CPU_ENABLE_SSE)
- if (cpu_feature & CPUID_SSE2)
- sse2_pagezero(page);
- else
-#endif
- i686_pagezero(page);
- } else
-#endif
- bzero(page, PAGE_SIZE);
-}
-
-/*
- * pmap_zero_page zeros the specified hardware page by mapping
- * the page into KVM and using bzero to clear its contents.
- */
-void
-pmap_zero_page(vm_page_t m)
-{
- struct sysmaps *sysmaps;
-
- sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)];
- mtx_lock(&sysmaps->lock);
- if (*sysmaps->CMAP2)
- panic("pmap_zero_page: CMAP2 busy");
- sched_pin();
- PT_SET_MA(sysmaps->CADDR2, PG_V | PG_RW | VM_PAGE_TO_MACH(m) | PG_A | PG_M);
- pagezero(sysmaps->CADDR2);
- PT_SET_MA(sysmaps->CADDR2, 0);
- sched_unpin();
- mtx_unlock(&sysmaps->lock);
-}
-
-/*
- * pmap_zero_page_area zeros the specified hardware page by mapping
- * the page into KVM and using bzero to clear its contents.
- *
- * off and size may not cover an area beyond a single hardware page.
- */
-void
-pmap_zero_page_area(vm_page_t m, int off, int size)
-{
- struct sysmaps *sysmaps;
-
- sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)];
- mtx_lock(&sysmaps->lock);
- if (*sysmaps->CMAP2)
- panic("pmap_zero_page_area: CMAP2 busy");
- sched_pin();
- PT_SET_MA(sysmaps->CADDR2, PG_V | PG_RW | VM_PAGE_TO_MACH(m) | PG_A | PG_M);
-
- if (off == 0 && size == PAGE_SIZE)
- pagezero(sysmaps->CADDR2);
- else
- bzero((char *)sysmaps->CADDR2 + off, size);
- PT_SET_MA(sysmaps->CADDR2, 0);
- sched_unpin();
- mtx_unlock(&sysmaps->lock);
-}
-
-/*
- * pmap_zero_page_idle zeros the specified hardware page by mapping
- * the page into KVM and using bzero to clear its contents. This
- * is intended to be called from the vm_pagezero process only and
- * outside of Giant.
- */
-void
-pmap_zero_page_idle(vm_page_t m)
-{
-
- if (*CMAP3)
- panic("pmap_zero_page_idle: CMAP3 busy");
- sched_pin();
- PT_SET_MA(CADDR3, PG_V | PG_RW | VM_PAGE_TO_MACH(m) | PG_A | PG_M);
- pagezero(CADDR3);
- PT_SET_MA(CADDR3, 0);
- sched_unpin();
-}
-
-/*
- * pmap_copy_page copies the specified (machine independent)
- * page by mapping the page into virtual memory and using
- * bcopy to copy the page, one machine dependent page at a
- * time.
- */
-void
-pmap_copy_page(vm_page_t src, vm_page_t dst)
-{
- struct sysmaps *sysmaps;
-
- sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)];
- mtx_lock(&sysmaps->lock);
- if (*sysmaps->CMAP1)
- panic("pmap_copy_page: CMAP1 busy");
- if (*sysmaps->CMAP2)
- panic("pmap_copy_page: CMAP2 busy");
- sched_pin();
- PT_SET_MA(sysmaps->CADDR1, PG_V | VM_PAGE_TO_MACH(src) | PG_A);
- PT_SET_MA(sysmaps->CADDR2, PG_V | PG_RW | VM_PAGE_TO_MACH(dst) | PG_A | PG_M);
- bcopy(sysmaps->CADDR1, sysmaps->CADDR2, PAGE_SIZE);
- PT_SET_MA(sysmaps->CADDR1, 0);
- PT_SET_MA(sysmaps->CADDR2, 0);
- sched_unpin();
- mtx_unlock(&sysmaps->lock);
-}
-
-int unmapped_buf_allowed = 1;
-
-void
-pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[],
- vm_offset_t b_offset, int xfersize)
-{
- struct sysmaps *sysmaps;
- vm_page_t a_pg, b_pg;
- char *a_cp, *b_cp;
- vm_offset_t a_pg_offset, b_pg_offset;
- int cnt;
-
- sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)];
- mtx_lock(&sysmaps->lock);
- if (*sysmaps->CMAP1 != 0)
- panic("pmap_copy_pages: CMAP1 busy");
- if (*sysmaps->CMAP2 != 0)
- panic("pmap_copy_pages: CMAP2 busy");
- sched_pin();
- while (xfersize > 0) {
- a_pg = ma[a_offset >> PAGE_SHIFT];
- a_pg_offset = a_offset & PAGE_MASK;
- cnt = min(xfersize, PAGE_SIZE - a_pg_offset);
- b_pg = mb[b_offset >> PAGE_SHIFT];
- b_pg_offset = b_offset & PAGE_MASK;
- cnt = min(cnt, PAGE_SIZE - b_pg_offset);
- PT_SET_MA(sysmaps->CADDR1, PG_V | VM_PAGE_TO_MACH(a_pg) | PG_A);
- PT_SET_MA(sysmaps->CADDR2, PG_V | PG_RW |
- VM_PAGE_TO_MACH(b_pg) | PG_A | PG_M);
- a_cp = sysmaps->CADDR1 + a_pg_offset;
- b_cp = sysmaps->CADDR2 + b_pg_offset;
- bcopy(a_cp, b_cp, cnt);
- a_offset += cnt;
- b_offset += cnt;
- xfersize -= cnt;
- }
- PT_SET_MA(sysmaps->CADDR1, 0);
- PT_SET_MA(sysmaps->CADDR2, 0);
- sched_unpin();
- mtx_unlock(&sysmaps->lock);
-}
-
-/*
- * Returns true if the pmap's pv is one of the first
- * 16 pvs linked to from this page. This count may
- * be changed upwards or downwards in the future; it
- * is only necessary that true be returned for a small
- * subset of pmaps for proper page aging.
- */
-boolean_t
-pmap_page_exists_quick(pmap_t pmap, vm_page_t m)
-{
- pv_entry_t pv;
- int loops = 0;
- boolean_t rv;
-
- KASSERT((m->oflags & VPO_UNMANAGED) == 0,
- ("pmap_page_exists_quick: page %p is not managed", m));
- rv = FALSE;
- rw_wlock(&pvh_global_lock);
- TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
- if (PV_PMAP(pv) == pmap) {
- rv = TRUE;
- break;
- }
- loops++;
- if (loops >= 16)
- break;
- }
- rw_wunlock(&pvh_global_lock);
- return (rv);
-}
-
-/*
- * pmap_page_wired_mappings:
- *
- * Return the number of managed mappings to the given physical page
- * that are wired.
- */
-int
-pmap_page_wired_mappings(vm_page_t m)
-{
- pv_entry_t pv;
- pt_entry_t *pte;
- pmap_t pmap;
- int count;
-
- count = 0;
- if ((m->oflags & VPO_UNMANAGED) != 0)
- return (count);
- rw_wlock(&pvh_global_lock);
- sched_pin();
- TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
- pmap = PV_PMAP(pv);
- PMAP_LOCK(pmap);
- pte = pmap_pte_quick(pmap, pv->pv_va);
- if ((*pte & PG_W) != 0)
- count++;
- PMAP_UNLOCK(pmap);
- }
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- return (count);
-}
-
-/*
- * Returns TRUE if the given page is mapped. Otherwise, returns FALSE.
- */
-boolean_t
-pmap_page_is_mapped(vm_page_t m)
-{
-
- if ((m->oflags & VPO_UNMANAGED) != 0)
- return (FALSE);
- return (!TAILQ_EMPTY(&m->md.pv_list));
-}
-
-/*
- * Remove all pages from specified address space
- * this aids process exit speeds. Also, this code
- * is special cased for current process only, but
- * can have the more generic (and slightly slower)
- * mode enabled. This is much faster than pmap_remove
- * in the case of running down an entire address space.
- */
-void
-pmap_remove_pages(pmap_t pmap)
-{
- pt_entry_t *pte, tpte;
- vm_page_t m, free = NULL;
- pv_entry_t pv;
- struct pv_chunk *pc, *npc;
- int field, idx;
- int32_t bit;
- uint32_t inuse, bitmask;
- int allfree;
-
- CTR1(KTR_PMAP, "pmap_remove_pages: pmap=%p", pmap);
-
- if (pmap != vmspace_pmap(curthread->td_proc->p_vmspace)) {
- printf("warning: pmap_remove_pages called with non-current pmap\n");
- return;
- }
- rw_wlock(&pvh_global_lock);
- KASSERT(pmap_is_current(pmap), ("removing pages from non-current pmap"));
- PMAP_LOCK(pmap);
- sched_pin();
- TAILQ_FOREACH_SAFE(pc, &pmap->pm_pvchunk, pc_list, npc) {
- KASSERT(pc->pc_pmap == pmap, ("Wrong pmap %p %p", pmap,
- pc->pc_pmap));
- allfree = 1;
- for (field = 0; field < _NPCM; field++) {
- inuse = ~pc->pc_map[field] & pc_freemask[field];
- while (inuse != 0) {
- bit = bsfl(inuse);
- bitmask = 1UL << bit;
- idx = field * 32 + bit;
- pv = &pc->pc_pventry[idx];
- inuse &= ~bitmask;
-
- pte = vtopte(pv->pv_va);
- tpte = *pte ? xpmap_mtop(*pte) : 0;
-
- if (tpte == 0) {
- printf(
- "TPTE at %p IS ZERO @ VA %08x\n",
- pte, pv->pv_va);
- panic("bad pte");
- }
-
-/*
- * We cannot remove wired pages from a process' mapping at this time
- */
- if (tpte & PG_W) {
- allfree = 0;
- continue;
- }
-
- m = PHYS_TO_VM_PAGE(tpte & PG_FRAME);
- KASSERT(m->phys_addr == (tpte & PG_FRAME),
- ("vm_page_t %p phys_addr mismatch %016jx %016jx",
- m, (uintmax_t)m->phys_addr,
- (uintmax_t)tpte));
-
- KASSERT(m < &vm_page_array[vm_page_array_size],
- ("pmap_remove_pages: bad tpte %#jx",
- (uintmax_t)tpte));
-
-
- PT_CLEAR_VA(pte, FALSE);
-
- /*
- * Update the vm_page_t clean/reference bits.
- */
- if (tpte & PG_M)
- vm_page_dirty(m);
-
- TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
- if (TAILQ_EMPTY(&m->md.pv_list))
- vm_page_aflag_clear(m, PGA_WRITEABLE);
-
- pmap_unuse_pt(pmap, pv->pv_va, &free);
-
- /* Mark free */
- PV_STAT(pv_entry_frees++);
- PV_STAT(pv_entry_spare++);
- pv_entry_count--;
- pc->pc_map[field] |= bitmask;
- pmap->pm_stats.resident_count--;
- }
- }
- PT_UPDATES_FLUSH();
- if (allfree) {
- TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
- free_pv_chunk(pc);
- }
- }
- PT_UPDATES_FLUSH();
- if (*PMAP1)
- PT_SET_MA(PADDR1, 0);
-
- sched_unpin();
- pmap_invalidate_all(pmap);
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
- pmap_free_zero_pages(free);
-}
-
-/*
- * pmap_is_modified:
- *
- * Return whether or not the specified physical page was modified
- * in any physical maps.
- */
-boolean_t
-pmap_is_modified(vm_page_t m)
-{
- pv_entry_t pv;
- pt_entry_t *pte;
- pmap_t pmap;
- boolean_t rv;
-
- KASSERT((m->oflags & VPO_UNMANAGED) == 0,
- ("pmap_is_modified: page %p is not managed", m));
- rv = FALSE;
-
- /*
- * If the page is not exclusive busied, then PGA_WRITEABLE cannot be
- * concurrently set while the object is locked. Thus, if PGA_WRITEABLE
- * is clear, no PTEs can have PG_M set.
- */
- VM_OBJECT_ASSERT_WLOCKED(m->object);
- if (!vm_page_xbusied(m) && (m->aflags & PGA_WRITEABLE) == 0)
- return (rv);
- rw_wlock(&pvh_global_lock);
- sched_pin();
- TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
- pmap = PV_PMAP(pv);
- PMAP_LOCK(pmap);
- pte = pmap_pte_quick(pmap, pv->pv_va);
- rv = (*pte & PG_M) != 0;
- PMAP_UNLOCK(pmap);
- if (rv)
- break;
- }
- if (*PMAP1)
- PT_SET_MA(PADDR1, 0);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- return (rv);
-}
-
-/*
- * pmap_is_prefaultable:
- *
- * Return whether or not the specified virtual address is elgible
- * for prefault.
- */
-static boolean_t
-pmap_is_prefaultable_locked(pmap_t pmap, vm_offset_t addr)
-{
- pt_entry_t *pte;
- boolean_t rv = FALSE;
-
- return (rv);
-
- if (pmap_is_current(pmap) && *pmap_pde(pmap, addr)) {
- pte = vtopte(addr);
- rv = (*pte == 0);
- }
- return (rv);
-}
-
-boolean_t
-pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr)
-{
- boolean_t rv;
-
- PMAP_LOCK(pmap);
- rv = pmap_is_prefaultable_locked(pmap, addr);
- PMAP_UNLOCK(pmap);
- return (rv);
-}
-
-boolean_t
-pmap_is_referenced(vm_page_t m)
-{
- pv_entry_t pv;
- pt_entry_t *pte;
- pmap_t pmap;
- boolean_t rv;
-
- KASSERT((m->oflags & VPO_UNMANAGED) == 0,
- ("pmap_is_referenced: page %p is not managed", m));
- rv = FALSE;
- rw_wlock(&pvh_global_lock);
- sched_pin();
- TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
- pmap = PV_PMAP(pv);
- PMAP_LOCK(pmap);
- pte = pmap_pte_quick(pmap, pv->pv_va);
- rv = (*pte & (PG_A | PG_V)) == (PG_A | PG_V);
- PMAP_UNLOCK(pmap);
- if (rv)
- break;
- }
- if (*PMAP1)
- PT_SET_MA(PADDR1, 0);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- return (rv);
-}
-
-void
-pmap_map_readonly(pmap_t pmap, vm_offset_t va, int len)
-{
- int i, npages = round_page(len) >> PAGE_SHIFT;
- for (i = 0; i < npages; i++) {
- pt_entry_t *pte;
- pte = pmap_pte(pmap, (vm_offset_t)(va + i*PAGE_SIZE));
- rw_wlock(&pvh_global_lock);
- pte_store(pte, xpmap_mtop(*pte & ~(PG_RW|PG_M)));
- rw_wunlock(&pvh_global_lock);
- PMAP_MARK_PRIV(xpmap_mtop(*pte));
- pmap_pte_release(pte);
- }
-}
-
-void
-pmap_map_readwrite(pmap_t pmap, vm_offset_t va, int len)
-{
- int i, npages = round_page(len) >> PAGE_SHIFT;
- for (i = 0; i < npages; i++) {
- pt_entry_t *pte;
- pte = pmap_pte(pmap, (vm_offset_t)(va + i*PAGE_SIZE));
- PMAP_MARK_UNPRIV(xpmap_mtop(*pte));
- rw_wlock(&pvh_global_lock);
- pte_store(pte, xpmap_mtop(*pte) | (PG_RW|PG_M));
- rw_wunlock(&pvh_global_lock);
- pmap_pte_release(pte);
- }
-}
-
-/*
- * Clear the write and modified bits in each of the given page's mappings.
- */
-void
-pmap_remove_write(vm_page_t m)
-{
- pv_entry_t pv;
- pmap_t pmap;
- pt_entry_t oldpte, *pte;
-
- KASSERT((m->oflags & VPO_UNMANAGED) == 0,
- ("pmap_remove_write: page %p is not managed", m));
-
- /*
- * If the page is not exclusive busied, then PGA_WRITEABLE cannot be
- * set by another thread while the object is locked. Thus,
- * if PGA_WRITEABLE is clear, no page table entries need updating.
- */
- VM_OBJECT_ASSERT_WLOCKED(m->object);
- if (!vm_page_xbusied(m) && (m->aflags & PGA_WRITEABLE) == 0)
- return;
- rw_wlock(&pvh_global_lock);
- sched_pin();
- TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
- pmap = PV_PMAP(pv);
- PMAP_LOCK(pmap);
- pte = pmap_pte_quick(pmap, pv->pv_va);
-retry:
- oldpte = *pte;
- if ((oldpte & PG_RW) != 0) {
- vm_paddr_t newpte = oldpte & ~(PG_RW | PG_M);
-
- /*
- * Regardless of whether a pte is 32 or 64 bits
- * in size, PG_RW and PG_M are among the least
- * significant 32 bits.
- */
- PT_SET_VA_MA(pte, newpte, TRUE);
- if (*pte != newpte)
- goto retry;
-
- if ((oldpte & PG_M) != 0)
- vm_page_dirty(m);
- pmap_invalidate_page(pmap, pv->pv_va);
- }
- PMAP_UNLOCK(pmap);
- }
- vm_page_aflag_clear(m, PGA_WRITEABLE);
- PT_UPDATES_FLUSH();
- if (*PMAP1)
- PT_SET_MA(PADDR1, 0);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
-}
-
-/*
- * pmap_ts_referenced:
- *
- * Return a count of reference bits for a page, clearing those bits.
- * It is not necessary for every reference bit to be cleared, but it
- * is necessary that 0 only be returned when there are truly no
- * reference bits set.
- *
- * XXX: The exact number of bits to check and clear is a matter that
- * should be tested and standardized at some point in the future for
- * optimal aging of shared pages.
- */
-int
-pmap_ts_referenced(vm_page_t m)
-{
- pv_entry_t pv, pvf, pvn;
- pmap_t pmap;
- pt_entry_t *pte;
- int rtval = 0;
-
- KASSERT((m->oflags & VPO_UNMANAGED) == 0,
- ("pmap_ts_referenced: page %p is not managed", m));
- rw_wlock(&pvh_global_lock);
- sched_pin();
- if ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) {
- pvf = pv;
- do {
- pvn = TAILQ_NEXT(pv, pv_next);
- TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
- TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next);
- pmap = PV_PMAP(pv);
- PMAP_LOCK(pmap);
- pte = pmap_pte_quick(pmap, pv->pv_va);
- if ((*pte & PG_A) != 0) {
- PT_SET_VA_MA(pte, *pte & ~PG_A, FALSE);
- pmap_invalidate_page(pmap, pv->pv_va);
- rtval++;
- if (rtval > 4)
- pvn = NULL;
- }
- PMAP_UNLOCK(pmap);
- } while ((pv = pvn) != NULL && pv != pvf);
- }
- PT_UPDATES_FLUSH();
- if (*PMAP1)
- PT_SET_MA(PADDR1, 0);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- return (rtval);
-}
-
-/*
- * Apply the given advice to the specified range of addresses within the
- * given pmap. Depending on the advice, clear the referenced and/or
- * modified flags in each mapping and set the mapped page's dirty field.
- */
-void
-pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, int advice)
-{
- pd_entry_t oldpde;
- pt_entry_t *pte;
- vm_offset_t pdnxt;
- vm_page_t m;
- boolean_t anychanged;
-
- if (advice != MADV_DONTNEED && advice != MADV_FREE)
- return;
- anychanged = FALSE;
- rw_wlock(&pvh_global_lock);
- sched_pin();
- PMAP_LOCK(pmap);
- for (; sva < eva; sva = pdnxt) {
- pdnxt = (sva + NBPDR) & ~PDRMASK;
- if (pdnxt < sva)
- pdnxt = eva;
- oldpde = pmap->pm_pdir[sva >> PDRSHIFT];
- if ((oldpde & (PG_PS | PG_V)) != PG_V)
- continue;
- if (pdnxt > eva)
- pdnxt = eva;
- for (pte = pmap_pte_quick(pmap, sva); sva != pdnxt; pte++,
- sva += PAGE_SIZE) {
- if ((*pte & (PG_MANAGED | PG_V)) != (PG_MANAGED |
- PG_V))
- continue;
- else if ((*pte & (PG_M | PG_RW)) == (PG_M | PG_RW)) {
- if (advice == MADV_DONTNEED) {
- /*
- * Future calls to pmap_is_modified()
- * can be avoided by making the page
- * dirty now.
- */
- m = PHYS_TO_VM_PAGE(xpmap_mtop(*pte) &
- PG_FRAME);
- vm_page_dirty(m);
- }
- PT_SET_VA_MA(pte, *pte & ~(PG_M | PG_A), TRUE);
- } else if ((*pte & PG_A) != 0)
- PT_SET_VA_MA(pte, *pte & ~PG_A, TRUE);
- else
- continue;
- if ((*pte & PG_G) != 0)
- pmap_invalidate_page(pmap, sva);
- else
- anychanged = TRUE;
- }
- }
- PT_UPDATES_FLUSH();
- if (*PMAP1)
- PT_SET_VA_MA(PMAP1, 0, TRUE);
- if (anychanged)
- pmap_invalidate_all(pmap);
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
- PMAP_UNLOCK(pmap);
-}
-
-/*
- * Clear the modify bits on the specified physical page.
- */
-void
-pmap_clear_modify(vm_page_t m)
-{
- pv_entry_t pv;
- pmap_t pmap;
- pt_entry_t *pte;
-
- KASSERT((m->oflags & VPO_UNMANAGED) == 0,
- ("pmap_clear_modify: page %p is not managed", m));
- VM_OBJECT_ASSERT_WLOCKED(m->object);
- KASSERT(!vm_page_xbusied(m),
- ("pmap_clear_modify: page %p is exclusive busied", m));
-
- /*
- * If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set.
- * If the object containing the page is locked and the page is not
- * exclusive busied, then PGA_WRITEABLE cannot be concurrently set.
- */
- if ((m->aflags & PGA_WRITEABLE) == 0)
- return;
- rw_wlock(&pvh_global_lock);
- sched_pin();
- TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
- pmap = PV_PMAP(pv);
- PMAP_LOCK(pmap);
- pte = pmap_pte_quick(pmap, pv->pv_va);
- if ((*pte & (PG_M | PG_RW)) == (PG_M | PG_RW)) {
- /*
- * Regardless of whether a pte is 32 or 64 bits
- * in size, PG_M is among the least significant
- * 32 bits.
- */
- PT_SET_VA_MA(pte, *pte & ~PG_M, FALSE);
- pmap_invalidate_page(pmap, pv->pv_va);
- }
- PMAP_UNLOCK(pmap);
- }
- sched_unpin();
- rw_wunlock(&pvh_global_lock);
-}
-
-/*
- * Miscellaneous support routines follow
- */
-
-/*
- * Map a set of physical memory pages into the kernel virtual
- * address space. Return a pointer to where it is mapped. This
- * routine is intended to be used for mapping device memory,
- * NOT real memory.
- */
-void *
-pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mode)
-{
- vm_offset_t va, offset;
- vm_size_t tmpsize;
-
- offset = pa & PAGE_MASK;
- size = round_page(offset + size);
- pa = pa & PG_FRAME;
-
- if (pa < KERNLOAD && pa + size <= KERNLOAD)
- va = KERNBASE + pa;
- else
- va = kva_alloc(size);
- if (!va)
- panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
-
- for (tmpsize = 0; tmpsize < size; tmpsize += PAGE_SIZE)
- pmap_kenter_attr(va + tmpsize, pa + tmpsize, mode);
- pmap_invalidate_range(kernel_pmap, va, va + tmpsize);
- pmap_invalidate_cache_range(va, va + size, FALSE);
- return ((void *)(va + offset));
-}
-
-void *
-pmap_mapdev(vm_paddr_t pa, vm_size_t size)
-{
-
- return (pmap_mapdev_attr(pa, size, PAT_UNCACHEABLE));
-}
-
-void *
-pmap_mapbios(vm_paddr_t pa, vm_size_t size)
-{
-
- return (pmap_mapdev_attr(pa, size, PAT_WRITE_BACK));
-}
-
-void
-pmap_unmapdev(vm_offset_t va, vm_size_t size)
-{
- vm_offset_t base, offset;
-
- if (va >= KERNBASE && va + size <= KERNBASE + KERNLOAD)
- return;
- base = trunc_page(va);
- offset = va & PAGE_MASK;
- size = round_page(offset + size);
- kva_free(base, size);
-}
-
-/*
- * Sets the memory attribute for the specified page.
- */
-void
-pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
-{
-
- m->md.pat_mode = ma;
- if ((m->flags & PG_FICTITIOUS) != 0)
- return;
-
- /*
- * If "m" is a normal page, flush it from the cache.
- * See pmap_invalidate_cache_range().
- *
- * First, try to find an existing mapping of the page by sf
- * buffer. sf_buf_invalidate_cache() modifies mapping and
- * flushes the cache.
- */
- if (sf_buf_invalidate_cache(m))
- return;
-
- /*
- * If page is not mapped by sf buffer, but CPU does not
- * support self snoop, map the page transient and do
- * invalidation. In the worst case, whole cache is flushed by
- * pmap_invalidate_cache_range().
- */
- if ((cpu_feature & CPUID_SS) == 0)
- pmap_flush_page(m);
-}
-
-static void
-pmap_flush_page(vm_page_t m)
-{
- struct sysmaps *sysmaps;
- vm_offset_t sva, eva;
-
- if ((cpu_feature & CPUID_CLFSH) != 0) {
- sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)];
- mtx_lock(&sysmaps->lock);
- if (*sysmaps->CMAP2)
- panic("pmap_flush_page: CMAP2 busy");
- sched_pin();
- PT_SET_MA(sysmaps->CADDR2, PG_V | PG_RW |
- VM_PAGE_TO_MACH(m) | PG_A | PG_M |
- pmap_cache_bits(m->md.pat_mode, 0));
- invlcaddr(sysmaps->CADDR2);
- sva = (vm_offset_t)sysmaps->CADDR2;
- eva = sva + PAGE_SIZE;
-
- /*
- * Use mfence despite the ordering implied by
- * mtx_{un,}lock() because clflush is not guaranteed
- * to be ordered by any other instruction.
- */
- mfence();
- for (; sva < eva; sva += cpu_clflush_line_size)
- clflush(sva);
- mfence();
- PT_SET_MA(sysmaps->CADDR2, 0);
- sched_unpin();
- mtx_unlock(&sysmaps->lock);
- } else
- pmap_invalidate_cache();
-}
-
-/*
- * Changes the specified virtual address range's memory type to that given by
- * the parameter "mode". The specified virtual address range must be
- * completely contained within either the kernel map.
- *
- * Returns zero if the change completed successfully, and either EINVAL or
- * ENOMEM if the change failed. Specifically, EINVAL is returned if some part
- * of the virtual address range was not mapped, and ENOMEM is returned if
- * there was insufficient memory available to complete the change.
- */
-int
-pmap_change_attr(vm_offset_t va, vm_size_t size, int mode)
-{
- vm_offset_t base, offset, tmpva;
- pt_entry_t *pte;
- u_int opte, npte;
- pd_entry_t *pde;
- boolean_t changed;
-
- base = trunc_page(va);
- offset = va & PAGE_MASK;
- size = round_page(offset + size);
-
- /* Only supported on kernel virtual addresses. */
- if (base <= VM_MAXUSER_ADDRESS)
- return (EINVAL);
-
- /* 4MB pages and pages that aren't mapped aren't supported. */
- for (tmpva = base; tmpva < (base + size); tmpva += PAGE_SIZE) {
- pde = pmap_pde(kernel_pmap, tmpva);
- if (*pde & PG_PS)
- return (EINVAL);
- if ((*pde & PG_V) == 0)
- return (EINVAL);
- pte = vtopte(va);
- if ((*pte & PG_V) == 0)
- return (EINVAL);
- }
-
- changed = FALSE;
-
- /*
- * Ok, all the pages exist and are 4k, so run through them updating
- * their cache mode.
- */
- for (tmpva = base; size > 0; ) {
- pte = vtopte(tmpva);
-
- /*
- * The cache mode bits are all in the low 32-bits of the
- * PTE, so we can just spin on updating the low 32-bits.
- */
- do {
- opte = *(u_int *)pte;
- npte = opte & ~(PG_PTE_PAT | PG_NC_PCD | PG_NC_PWT);
- npte |= pmap_cache_bits(mode, 0);
- PT_SET_VA_MA(pte, npte, TRUE);
- } while (npte != opte && (*pte != npte));
- if (npte != opte)
- changed = TRUE;
- tmpva += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- /*
- * Flush CPU caches to make sure any data isn't cached that
- * shouldn't be, etc.
- */
- if (changed) {
- pmap_invalidate_range(kernel_pmap, base, tmpva);
- pmap_invalidate_cache_range(base, tmpva, FALSE);
- }
- return (0);
-}
-
-/*
- * perform the pmap work for mincore
- */
-int
-pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa)
-{
- pt_entry_t *ptep, pte;
- vm_paddr_t pa;
- int val;
-
- PMAP_LOCK(pmap);
-retry:
- ptep = pmap_pte(pmap, addr);
- pte = (ptep != NULL) ? PT_GET(ptep) : 0;
- pmap_pte_release(ptep);
- val = 0;
- if ((pte & PG_V) != 0) {
- val |= MINCORE_INCORE;
- if ((pte & (PG_M | PG_RW)) == (PG_M | PG_RW))
- val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER;
- if ((pte & PG_A) != 0)
- val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER;
- }
- if ((val & (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER)) !=
- (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER) &&
- (pte & (PG_MANAGED | PG_V)) == (PG_MANAGED | PG_V)) {
- pa = pte & PG_FRAME;
- /* Ensure that "PHYS_TO_VM_PAGE(pa)->object" doesn't change. */
- if (vm_page_pa_tryrelock(pmap, pa, locked_pa))
- goto retry;
- } else
- PA_UNLOCK_COND(*locked_pa);
- PMAP_UNLOCK(pmap);
- return (val);
-}
-
-void
-pmap_activate(struct thread *td)
-{
- pmap_t pmap, oldpmap;
- u_int cpuid;
- u_int32_t cr3;
-
- critical_enter();
- pmap = vmspace_pmap(td->td_proc->p_vmspace);
- oldpmap = PCPU_GET(curpmap);
- cpuid = PCPU_GET(cpuid);
-#if defined(SMP)
- CPU_CLR_ATOMIC(cpuid, &oldpmap->pm_active);
- CPU_SET_ATOMIC(cpuid, &pmap->pm_active);
-#else
- CPU_CLR(cpuid, &oldpmap->pm_active);
- CPU_SET(cpuid, &pmap->pm_active);
-#endif
-#ifdef PAE
- cr3 = vtophys(pmap->pm_pdpt);
-#else
- cr3 = vtophys(pmap->pm_pdir);
-#endif
- /*
- * pmap_activate is for the current thread on the current cpu
- */
- td->td_pcb->pcb_cr3 = cr3;
- PT_UPDATES_FLUSH();
- load_cr3(cr3);
- PCPU_SET(curpmap, pmap);
- critical_exit();
-}
-
-void
-pmap_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz)
-{
-}
-
-/*
- * Increase the starting virtual address of the given mapping if a
- * different alignment might result in more superpage mappings.
- */
-void
-pmap_align_superpage(vm_object_t object, vm_ooffset_t offset,
- vm_offset_t *addr, vm_size_t size)
-{
- vm_offset_t superpage_offset;
-
- if (size < NBPDR)
- return;
- if (object != NULL && (object->flags & OBJ_COLORED) != 0)
- offset += ptoa(object->pg_color);
- superpage_offset = offset & PDRMASK;
- if (size - ((NBPDR - superpage_offset) & PDRMASK) < NBPDR ||
- (*addr & PDRMASK) == superpage_offset)
- return;
- if ((*addr & PDRMASK) < superpage_offset)
- *addr = (*addr & ~PDRMASK) + superpage_offset;
- else
- *addr = ((*addr + PDRMASK) & ~PDRMASK) + superpage_offset;
-}
-
-void
-pmap_suspend()
-{
- pmap_t pmap;
- int i, pdir, offset;
- vm_paddr_t pdirma;
- mmu_update_t mu[4];
-
- /*
- * We need to remove the recursive mapping structure from all
- * our pmaps so that Xen doesn't get confused when it restores
- * the page tables. The recursive map lives at page directory
- * index PTDPTDI. We assume that the suspend code has stopped
- * the other vcpus (if any).
- */
- LIST_FOREACH(pmap, &allpmaps, pm_list) {
- for (i = 0; i < 4; i++) {
- /*
- * Figure out which page directory (L2) page
- * contains this bit of the recursive map and
- * the offset within that page of the map
- * entry
- */
- pdir = (PTDPTDI + i) / NPDEPG;
- offset = (PTDPTDI + i) % NPDEPG;
- pdirma = pmap->pm_pdpt[pdir] & PG_FRAME;
- mu[i].ptr = pdirma + offset * sizeof(pd_entry_t);
- mu[i].val = 0;
- }
- HYPERVISOR_mmu_update(mu, 4, NULL, DOMID_SELF);
- }
-}
-
-void
-pmap_resume()
-{
- pmap_t pmap;
- int i, pdir, offset;
- vm_paddr_t pdirma;
- mmu_update_t mu[4];
-
- /*
- * Restore the recursive map that we removed on suspend.
- */
- LIST_FOREACH(pmap, &allpmaps, pm_list) {
- for (i = 0; i < 4; i++) {
- /*
- * Figure out which page directory (L2) page
- * contains this bit of the recursive map and
- * the offset within that page of the map
- * entry
- */
- pdir = (PTDPTDI + i) / NPDEPG;
- offset = (PTDPTDI + i) % NPDEPG;
- pdirma = pmap->pm_pdpt[pdir] & PG_FRAME;
- mu[i].ptr = pdirma + offset * sizeof(pd_entry_t);
- mu[i].val = (pmap->pm_pdpt[i] & PG_FRAME) | PG_V;
- }
- HYPERVISOR_mmu_update(mu, 4, NULL, DOMID_SELF);
- }
-}
-
-#if defined(PMAP_DEBUG)
-pmap_pid_dump(int pid)
-{
- pmap_t pmap;
- struct proc *p;
- int npte = 0;
- int index;
-
- sx_slock(&allproc_lock);
- FOREACH_PROC_IN_SYSTEM(p) {
- if (p->p_pid != pid)
- continue;
-
- if (p->p_vmspace) {
- int i,j;
- index = 0;
- pmap = vmspace_pmap(p->p_vmspace);
- for (i = 0; i < NPDEPTD; i++) {
- pd_entry_t *pde;
- pt_entry_t *pte;
- vm_offset_t base = i << PDRSHIFT;
-
- pde = &pmap->pm_pdir[i];
- if (pde && pmap_pde_v(pde)) {
- for (j = 0; j < NPTEPG; j++) {
- vm_offset_t va = base + (j << PAGE_SHIFT);
- if (va >= (vm_offset_t) VM_MIN_KERNEL_ADDRESS) {
- if (index) {
- index = 0;
- printf("\n");
- }
- sx_sunlock(&allproc_lock);
- return (npte);
- }
- pte = pmap_pte(pmap, va);
- if (pte && pmap_pte_v(pte)) {
- pt_entry_t pa;
- vm_page_t m;
- pa = PT_GET(pte);
- m = PHYS_TO_VM_PAGE(pa & PG_FRAME);
- printf("va: 0x%x, pt: 0x%x, h: %d, w: %d, f: 0x%x",
- va, pa, m->hold_count, m->wire_count, m->flags);
- npte++;
- index++;
- if (index >= 2) {
- index = 0;
- printf("\n");
- } else {
- printf(" ");
- }
- }
- }
- }
- }
- }
- }
- sx_sunlock(&allproc_lock);
- return (npte);
-}
-#endif
-
-#if defined(DEBUG)
-
-static void pads(pmap_t pm);
-void pmap_pvdump(vm_paddr_t pa);
-
-/* print address space of pmap*/
-static void
-pads(pmap_t pm)
-{
- int i, j;
- vm_paddr_t va;
- pt_entry_t *ptep;
-
- if (pm == kernel_pmap)
- return;
- for (i = 0; i < NPDEPTD; i++)
- if (pm->pm_pdir[i])
- for (j = 0; j < NPTEPG; j++) {
- va = (i << PDRSHIFT) + (j << PAGE_SHIFT);
- if (pm == kernel_pmap && va < KERNBASE)
- continue;
- if (pm != kernel_pmap && va > UPT_MAX_ADDRESS)
- continue;
- ptep = pmap_pte(pm, va);
- if (pmap_pte_v(ptep))
- printf("%x:%x ", va, *ptep);
- };
-
-}
-
-void
-pmap_pvdump(vm_paddr_t pa)
-{
- pv_entry_t pv;
- pmap_t pmap;
- vm_page_t m;
-
- printf("pa %x", pa);
- m = PHYS_TO_VM_PAGE(pa);
- TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
- pmap = PV_PMAP(pv);
- printf(" -> pmap %p, va %x", (void *)pmap, pv->pv_va);
- pads(pmap);
- }
- printf(" ");
-}
-#endif
diff --git a/sys/i386/xen/xen_machdep.c b/sys/i386/xen/xen_machdep.c
deleted file mode 100644
index dbaa7ad..0000000
--- a/sys/i386/xen/xen_machdep.c
+++ /dev/null
@@ -1,1236 +0,0 @@
-/*
- *
- * Copyright (c) 2004 Christian Limpach.
- * Copyright (c) 2004-2006,2008 Kip Macy
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Christian Limpach.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/ktr.h>
-#include <sys/lock.h>
-#include <sys/mount.h>
-#include <sys/malloc.h>
-#include <sys/mutex.h>
-#include <sys/kernel.h>
-#include <sys/proc.h>
-#include <sys/reboot.h>
-#include <sys/rwlock.h>
-#include <sys/sysproto.h>
-#include <sys/boot.h>
-
-#include <xen/xen-os.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <machine/segments.h>
-#include <machine/pcb.h>
-#include <machine/stdarg.h>
-#include <machine/vmparam.h>
-#include <machine/cpu.h>
-#include <machine/intr_machdep.h>
-#include <machine/md_var.h>
-#include <machine/asmacros.h>
-
-
-
-#include <xen/hypervisor.h>
-#include <xen/xenstore/xenstorevar.h>
-#include <machine/xen/xenvar.h>
-#include <machine/xen/xenfunc.h>
-#include <machine/xen/xenpmap.h>
-#include <machine/xen/xenfunc.h>
-#include <xen/interface/memory.h>
-#include <machine/xen/features.h>
-#ifdef SMP
-#include <machine/privatespace.h>
-#endif
-
-
-#include <vm/vm_page.h>
-
-
-#define IDTVEC(name) __CONCAT(X,name)
-
-extern inthand_t
-IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
- IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm),
- IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
- IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align),
- IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall);
-
-
-int xendebug_flags;
-start_info_t *xen_start_info;
-start_info_t *HYPERVISOR_start_info;
-shared_info_t *HYPERVISOR_shared_info;
-xen_pfn_t *xen_machine_phys = machine_to_phys_mapping;
-xen_pfn_t *xen_phys_machine;
-xen_pfn_t *xen_pfn_to_mfn_frame_list[16];
-xen_pfn_t *xen_pfn_to_mfn_frame_list_list;
-int preemptable, init_first;
-extern unsigned int avail_space;
-int xen_vector_callback_enabled = 0;
-enum xen_domain_type xen_domain_type = XEN_PV_DOMAIN;
-
-void ni_cli(void);
-void ni_sti(void);
-
-
-void
-ni_cli(void)
-{
- CTR0(KTR_SPARE2, "ni_cli disabling interrupts");
- __asm__("pushl %edx;"
- "pushl %eax;"
- );
- __cli();
- __asm__("popl %eax;"
- "popl %edx;"
- );
-}
-
-
-void
-ni_sti(void)
-{
- __asm__("pushl %edx;"
- "pushl %esi;"
- "pushl %eax;"
- );
- __sti();
- __asm__("popl %eax;"
- "popl %esi;"
- "popl %edx;"
- );
-}
-
-void
-force_evtchn_callback(void)
-{
- (void)HYPERVISOR_xen_version(0, NULL);
-}
-
-/*
- * Modify the cmd_line by converting ',' to NULLs so that it is in a format
- * suitable for the static env vars.
- */
-char *
-xen_setbootenv(char *cmd_line)
-{
- char *cmd_line_next;
-
- /* Skip leading spaces */
- for (; *cmd_line == ' '; cmd_line++);
-
- xc_printf("xen_setbootenv(): cmd_line='%s'\n", cmd_line);
-
- for (cmd_line_next = cmd_line; strsep(&cmd_line_next, ",") != NULL;);
- return cmd_line;
-}
-
-int
-xen_boothowto(char *envp)
-{
- int i, howto = 0;
-
- /* get equivalents from the environment */
- for (i = 0; howto_names[i].ev != NULL; i++)
- if (kern_getenv(howto_names[i].ev) != NULL)
- howto |= howto_names[i].mask;
- return howto;
-}
-
-
-#define XPQUEUE_SIZE 128
-
-struct mmu_log {
- char *file;
- int line;
-};
-
-#ifdef SMP
-/* per-cpu queues and indices */
-#ifdef INVARIANTS
-static struct mmu_log xpq_queue_log[XEN_LEGACY_MAX_VCPUS][XPQUEUE_SIZE];
-#endif
-
-static int xpq_idx[XEN_LEGACY_MAX_VCPUS];
-static mmu_update_t xpq_queue[XEN_LEGACY_MAX_VCPUS][XPQUEUE_SIZE];
-
-#define XPQ_QUEUE_LOG xpq_queue_log[vcpu]
-#define XPQ_QUEUE xpq_queue[vcpu]
-#define XPQ_IDX xpq_idx[vcpu]
-#define SET_VCPU() int vcpu = smp_processor_id()
-#else
-
-static mmu_update_t xpq_queue[XPQUEUE_SIZE];
-#ifdef INVARIANTS
-static struct mmu_log xpq_queue_log[XPQUEUE_SIZE];
-#endif
-static int xpq_idx = 0;
-
-#define XPQ_QUEUE_LOG xpq_queue_log
-#define XPQ_QUEUE xpq_queue
-#define XPQ_IDX xpq_idx
-#define SET_VCPU()
-#endif /* !SMP */
-
-#define XPQ_IDX_INC atomic_add_int(&XPQ_IDX, 1);
-
-#if 0
-static void
-xen_dump_queue(void)
-{
- int _xpq_idx = XPQ_IDX;
- int i;
-
- if (_xpq_idx <= 1)
- return;
-
- xc_printf("xen_dump_queue(): %u entries\n", _xpq_idx);
- for (i = 0; i < _xpq_idx; i++) {
- xc_printf(" val: %llx ptr: %llx\n", XPQ_QUEUE[i].val,
- XPQ_QUEUE[i].ptr);
- }
-}
-#endif
-
-
-static __inline void
-_xen_flush_queue(void)
-{
- SET_VCPU();
- int _xpq_idx = XPQ_IDX;
- int error, i;
-
-#ifdef INVARIANTS
- if (__predict_true(gdtset))
- CRITICAL_ASSERT(curthread);
-#endif
-
- XPQ_IDX = 0;
- /* Make sure index is cleared first to avoid double updates. */
- error = HYPERVISOR_mmu_update((mmu_update_t *)&XPQ_QUEUE,
- _xpq_idx, NULL, DOMID_SELF);
-
-#if 0
- if (__predict_true(gdtset))
- for (i = _xpq_idx; i > 0;) {
- if (i >= 3) {
- CTR6(KTR_PMAP, "mmu:val: %lx ptr: %lx val: %lx "
- "ptr: %lx val: %lx ptr: %lx",
- (XPQ_QUEUE[i-1].val & 0xffffffff),
- (XPQ_QUEUE[i-1].ptr & 0xffffffff),
- (XPQ_QUEUE[i-2].val & 0xffffffff),
- (XPQ_QUEUE[i-2].ptr & 0xffffffff),
- (XPQ_QUEUE[i-3].val & 0xffffffff),
- (XPQ_QUEUE[i-3].ptr & 0xffffffff));
- i -= 3;
- } else if (i == 2) {
- CTR4(KTR_PMAP, "mmu: val: %lx ptr: %lx val: %lx ptr: %lx",
- (XPQ_QUEUE[i-1].val & 0xffffffff),
- (XPQ_QUEUE[i-1].ptr & 0xffffffff),
- (XPQ_QUEUE[i-2].val & 0xffffffff),
- (XPQ_QUEUE[i-2].ptr & 0xffffffff));
- i = 0;
- } else {
- CTR2(KTR_PMAP, "mmu: val: %lx ptr: %lx",
- (XPQ_QUEUE[i-1].val & 0xffffffff),
- (XPQ_QUEUE[i-1].ptr & 0xffffffff));
- i = 0;
- }
- }
-#endif
- if (__predict_false(error < 0)) {
- for (i = 0; i < _xpq_idx; i++)
- printf("val: %llx ptr: %llx\n",
- XPQ_QUEUE[i].val, XPQ_QUEUE[i].ptr);
- panic("Failed to execute MMU updates: %d", error);
- }
-
-}
-
-void
-xen_flush_queue(void)
-{
- SET_VCPU();
-
- if (__predict_true(gdtset))
- critical_enter();
- if (XPQ_IDX != 0) _xen_flush_queue();
- if (__predict_true(gdtset))
- critical_exit();
-}
-
-static __inline void
-xen_increment_idx(void)
-{
- SET_VCPU();
-
- XPQ_IDX++;
- if (__predict_false(XPQ_IDX == XPQUEUE_SIZE))
- xen_flush_queue();
-}
-
-void
-xen_check_queue(void)
-{
-#ifdef INVARIANTS
- SET_VCPU();
-
- KASSERT(XPQ_IDX == 0, ("pending operations XPQ_IDX=%d", XPQ_IDX));
-#endif
-}
-
-void
-xen_invlpg(vm_offset_t va)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_INVLPG_ALL;
- op.arg1.linear_addr = va & ~PAGE_MASK;
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void
-xen_load_cr3(u_int val)
-{
- struct mmuext_op op;
-#ifdef INVARIANTS
- SET_VCPU();
-
- KASSERT(XPQ_IDX == 0, ("pending operations XPQ_IDX=%d", XPQ_IDX));
-#endif
- op.cmd = MMUEXT_NEW_BASEPTR;
- op.arg1.mfn = xpmap_ptom(val) >> PAGE_SHIFT;
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-#ifdef KTR
-static __inline u_int
-rebp(void)
-{
- u_int data;
-
- __asm __volatile("movl 4(%%ebp),%0" : "=r" (data));
- return (data);
-}
-#endif
-
-u_int
-read_eflags(void)
-{
- vcpu_info_t *_vcpu;
- u_int eflags;
-
- eflags = _read_eflags();
- _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
- if (_vcpu->evtchn_upcall_mask)
- eflags &= ~PSL_I;
-
- return (eflags);
-}
-
-void
-write_eflags(u_int eflags)
-{
- u_int intr;
-
- CTR2(KTR_SPARE2, "%x xen_restore_flags eflags %x", rebp(), eflags);
- intr = ((eflags & PSL_I) == 0);
- __restore_flags(intr);
- _write_eflags(eflags);
-}
-
-void
-xen_cli(void)
-{
- CTR1(KTR_SPARE2, "%x xen_cli disabling interrupts", rebp());
- __cli();
-}
-
-void
-xen_sti(void)
-{
- CTR1(KTR_SPARE2, "%x xen_sti enabling interrupts", rebp());
- __sti();
-}
-
-u_int
-xen_rcr2(void)
-{
-
- return (HYPERVISOR_shared_info->vcpu_info[curcpu].arch.cr2);
-}
-
-void
-_xen_machphys_update(vm_paddr_t mfn, vm_paddr_t pfn, char *file, int line)
-{
- SET_VCPU();
-
- if (__predict_true(gdtset))
- critical_enter();
- XPQ_QUEUE[XPQ_IDX].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
- XPQ_QUEUE[XPQ_IDX].val = pfn;
-#ifdef INVARIANTS
- XPQ_QUEUE_LOG[XPQ_IDX].file = file;
- XPQ_QUEUE_LOG[XPQ_IDX].line = line;
-#endif
- xen_increment_idx();
- if (__predict_true(gdtset))
- critical_exit();
-}
-
-extern struct rwlock pvh_global_lock;
-
-void
-_xen_queue_pt_update(vm_paddr_t ptr, vm_paddr_t val, char *file, int line)
-{
- SET_VCPU();
-
- if (__predict_true(gdtset))
- rw_assert(&pvh_global_lock, RA_WLOCKED);
-
- KASSERT((ptr & 7) == 0, ("misaligned update"));
-
- if (__predict_true(gdtset))
- critical_enter();
-
- XPQ_QUEUE[XPQ_IDX].ptr = ((uint64_t)ptr) | MMU_NORMAL_PT_UPDATE;
- XPQ_QUEUE[XPQ_IDX].val = (uint64_t)val;
-#ifdef INVARIANTS
- XPQ_QUEUE_LOG[XPQ_IDX].file = file;
- XPQ_QUEUE_LOG[XPQ_IDX].line = line;
-#endif
- xen_increment_idx();
- if (__predict_true(gdtset))
- critical_exit();
-}
-
-void
-xen_pgdpt_pin(vm_paddr_t ma)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_PIN_L3_TABLE;
- op.arg1.mfn = ma >> PAGE_SHIFT;
- xen_flush_queue();
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void
-xen_pgd_pin(vm_paddr_t ma)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_PIN_L2_TABLE;
- op.arg1.mfn = ma >> PAGE_SHIFT;
- xen_flush_queue();
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void
-xen_pgd_unpin(vm_paddr_t ma)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_UNPIN_TABLE;
- op.arg1.mfn = ma >> PAGE_SHIFT;
- xen_flush_queue();
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void
-xen_pt_pin(vm_paddr_t ma)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_PIN_L1_TABLE;
- op.arg1.mfn = ma >> PAGE_SHIFT;
- xen_flush_queue();
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void
-xen_pt_unpin(vm_paddr_t ma)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_UNPIN_TABLE;
- op.arg1.mfn = ma >> PAGE_SHIFT;
- xen_flush_queue();
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void
-xen_set_ldt(vm_paddr_t ptr, unsigned long len)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_SET_LDT;
- op.arg1.linear_addr = ptr;
- op.arg2.nr_ents = len;
- xen_flush_queue();
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void xen_tlb_flush(void)
-{
- struct mmuext_op op;
- op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
- xen_flush_queue();
- PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
-}
-
-void
-xen_update_descriptor(union descriptor *table, union descriptor *entry)
-{
- vm_paddr_t pa;
- pt_entry_t *ptp;
-
- ptp = vtopte((vm_offset_t)table);
- pa = (*ptp & PG_FRAME) | ((vm_offset_t)table & PAGE_MASK);
- if (HYPERVISOR_update_descriptor(pa, *(uint64_t *)entry))
- panic("HYPERVISOR_update_descriptor failed\n");
-}
-
-
-#if 0
-/*
- * Bitmap is indexed by page number. If bit is set, the page is part of a
- * xen_create_contiguous_region() area of memory.
- */
-unsigned long *contiguous_bitmap;
-
-static void
-contiguous_bitmap_set(unsigned long first_page, unsigned long nr_pages)
-{
- unsigned long start_off, end_off, curr_idx, end_idx;
-
- curr_idx = first_page / BITS_PER_LONG;
- start_off = first_page & (BITS_PER_LONG-1);
- end_idx = (first_page + nr_pages) / BITS_PER_LONG;
- end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
-
- if (curr_idx == end_idx) {
- contiguous_bitmap[curr_idx] |=
- ((1UL<<end_off)-1) & -(1UL<<start_off);
- } else {
- contiguous_bitmap[curr_idx] |= -(1UL<<start_off);
- while ( ++curr_idx < end_idx )
- contiguous_bitmap[curr_idx] = ~0UL;
- contiguous_bitmap[curr_idx] |= (1UL<<end_off)-1;
- }
-}
-
-static void
-contiguous_bitmap_clear(unsigned long first_page, unsigned long nr_pages)
-{
- unsigned long start_off, end_off, curr_idx, end_idx;
-
- curr_idx = first_page / BITS_PER_LONG;
- start_off = first_page & (BITS_PER_LONG-1);
- end_idx = (first_page + nr_pages) / BITS_PER_LONG;
- end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
-
- if (curr_idx == end_idx) {
- contiguous_bitmap[curr_idx] &=
- -(1UL<<end_off) | ((1UL<<start_off)-1);
- } else {
- contiguous_bitmap[curr_idx] &= (1UL<<start_off)-1;
- while ( ++curr_idx != end_idx )
- contiguous_bitmap[curr_idx] = 0;
- contiguous_bitmap[curr_idx] &= -(1UL<<end_off);
- }
-}
-#endif
-
-/* Ensure multi-page extents are contiguous in machine memory. */
-int
-xen_create_contiguous_region(vm_page_t pages, int npages)
-{
- unsigned long mfn, i, flags;
- int order;
- struct xen_memory_reservation reservation = {
- .nr_extents = 1,
- .extent_order = 0,
- .domid = DOMID_SELF
- };
- set_xen_guest_handle(reservation.extent_start, &mfn);
-
- balloon_lock(flags);
-
- /* can currently only handle power of two allocation */
- PANIC_IF(ffs(npages) != fls(npages));
-
- /* 0. determine order */
- order = (ffs(npages) == fls(npages)) ? fls(npages) - 1 : fls(npages);
-
- /* 1. give away machine pages. */
- for (i = 0; i < (1 << order); i++) {
- int pfn;
- pfn = VM_PAGE_TO_PHYS(&pages[i]) >> PAGE_SHIFT;
- mfn = PFNTOMFN(pfn);
- PFNTOMFN(pfn) = INVALID_P2M_ENTRY;
- PANIC_IF(HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation) != 1);
- }
-
-
- /* 2. Get a new contiguous memory extent. */
- reservation.extent_order = order;
- /* xenlinux hardcodes this because of aacraid - maybe set to 0 if we're not
- * running with a broxen driver XXXEN
- */
- reservation.address_bits = 31;
- if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation) != 1)
- goto fail;
-
- /* 3. Map the new extent in place of old pages. */
- for (i = 0; i < (1 << order); i++) {
- int pfn;
- pfn = VM_PAGE_TO_PHYS(&pages[i]) >> PAGE_SHIFT;
- xen_machphys_update(mfn+i, pfn);
- PFNTOMFN(pfn) = mfn+i;
- }
-
- xen_tlb_flush();
-
-#if 0
- contiguous_bitmap_set(VM_PAGE_TO_PHYS(&pages[0]) >> PAGE_SHIFT, 1UL << order);
-#endif
-
- balloon_unlock(flags);
-
- return 0;
-
- fail:
- reservation.extent_order = 0;
- reservation.address_bits = 0;
-
- for (i = 0; i < (1 << order); i++) {
- int pfn;
- pfn = VM_PAGE_TO_PHYS(&pages[i]) >> PAGE_SHIFT;
- PANIC_IF(HYPERVISOR_memory_op(
- XENMEM_increase_reservation, &reservation) != 1);
- xen_machphys_update(mfn, pfn);
- PFNTOMFN(pfn) = mfn;
- }
-
- xen_tlb_flush();
-
- balloon_unlock(flags);
-
- return ENOMEM;
-}
-
-void
-xen_destroy_contiguous_region(void *addr, int npages)
-{
- unsigned long mfn, i, flags, order, pfn0;
- struct xen_memory_reservation reservation = {
- .nr_extents = 1,
- .extent_order = 0,
- .domid = DOMID_SELF
- };
- set_xen_guest_handle(reservation.extent_start, &mfn);
-
- pfn0 = vtophys(addr) >> PAGE_SHIFT;
-#if 0
- scrub_pages(vstart, 1 << order);
-#endif
- /* can currently only handle power of two allocation */
- PANIC_IF(ffs(npages) != fls(npages));
-
- /* 0. determine order */
- order = (ffs(npages) == fls(npages)) ? fls(npages) - 1 : fls(npages);
-
- balloon_lock(flags);
-
-#if 0
- contiguous_bitmap_clear(vtophys(addr) >> PAGE_SHIFT, 1UL << order);
-#endif
-
- /* 1. Zap current PTEs, giving away the underlying pages. */
- for (i = 0; i < (1 << order); i++) {
- int pfn;
- uint64_t new_val = 0;
- pfn = vtomach((char *)addr + i*PAGE_SIZE) >> PAGE_SHIFT;
-
- PANIC_IF(HYPERVISOR_update_va_mapping((vm_offset_t)((char *)addr + (i * PAGE_SIZE)), new_val, 0));
- PFNTOMFN(pfn) = INVALID_P2M_ENTRY;
- PANIC_IF(HYPERVISOR_memory_op(
- XENMEM_decrease_reservation, &reservation) != 1);
- }
-
- /* 2. Map new pages in place of old pages. */
- for (i = 0; i < (1 << order); i++) {
- int pfn;
- uint64_t new_val;
- pfn = pfn0 + i;
- PANIC_IF(HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation) != 1);
-
- new_val = mfn << PAGE_SHIFT;
- PANIC_IF(HYPERVISOR_update_va_mapping((vm_offset_t)addr + (i * PAGE_SIZE),
- new_val, PG_KERNEL));
- xen_machphys_update(mfn, pfn);
- PFNTOMFN(pfn) = mfn;
- }
-
- xen_tlb_flush();
-
- balloon_unlock(flags);
-}
-
-extern vm_offset_t proc0kstack;
-extern int vm86paddr, vm86phystk;
-char *bootmem_start, *bootmem_current, *bootmem_end;
-
-pteinfo_t *pteinfo_list;
-void initvalues(start_info_t *startinfo);
-
-void *
-bootmem_alloc(unsigned int size)
-{
- char *retptr;
-
- retptr = bootmem_current;
- PANIC_IF(retptr + size > bootmem_end);
- bootmem_current += size;
-
- return retptr;
-}
-
-void
-bootmem_free(void *ptr, unsigned int size)
-{
- char *tptr;
-
- tptr = ptr;
- PANIC_IF(tptr != bootmem_current - size ||
- bootmem_current - size < bootmem_start);
-
- bootmem_current -= size;
-}
-
-#if 0
-static vm_paddr_t
-xpmap_mtop2(vm_paddr_t mpa)
-{
- return ((machine_to_phys_mapping[mpa >> PAGE_SHIFT] << PAGE_SHIFT)
- ) | (mpa & ~PG_FRAME);
-}
-
-static pd_entry_t
-xpmap_get_bootpde(vm_paddr_t va)
-{
-
- return ((pd_entry_t *)xen_start_info->pt_base)[va >> 22];
-}
-
-static pd_entry_t
-xpmap_get_vbootpde(vm_paddr_t va)
-{
- pd_entry_t pde;
-
- pde = xpmap_get_bootpde(va);
- if ((pde & PG_V) == 0)
- return (pde & ~PG_FRAME);
- return (pde & ~PG_FRAME) |
- (xpmap_mtop2(pde & PG_FRAME) + KERNBASE);
-}
-
-static pt_entry_t 8*
-xpmap_get_bootptep(vm_paddr_t va)
-{
- pd_entry_t pde;
-
- pde = xpmap_get_vbootpde(va);
- if ((pde & PG_V) == 0)
- return (void *)-1;
-#define PT_MASK 0x003ff000 /* page table address bits */
- return &(((pt_entry_t *)(pde & PG_FRAME))[(va & PT_MASK) >> PAGE_SHIFT]);
-}
-
-static pt_entry_t
-xpmap_get_bootpte(vm_paddr_t va)
-{
-
- return xpmap_get_bootptep(va)[0];
-}
-#endif
-
-
-#ifdef ADD_ISA_HOLE
-static void
-shift_phys_machine(unsigned long *phys_machine, int nr_pages)
-{
-
- unsigned long *tmp_page, *current_page, *next_page;
- int i;
-
- tmp_page = bootmem_alloc(PAGE_SIZE);
- current_page = phys_machine + nr_pages - (PAGE_SIZE/sizeof(unsigned long));
- next_page = current_page - (PAGE_SIZE/sizeof(unsigned long));
- bcopy(phys_machine, tmp_page, PAGE_SIZE);
-
- while (current_page > phys_machine) {
- /* save next page */
- bcopy(next_page, tmp_page, PAGE_SIZE);
- /* shift down page */
- bcopy(current_page, next_page, PAGE_SIZE);
- /* finish swap */
- bcopy(tmp_page, current_page, PAGE_SIZE);
-
- current_page -= (PAGE_SIZE/sizeof(unsigned long));
- next_page -= (PAGE_SIZE/sizeof(unsigned long));
- }
- bootmem_free(tmp_page, PAGE_SIZE);
-
- for (i = 0; i < nr_pages; i++) {
- xen_machphys_update(phys_machine[i], i);
- }
- memset(phys_machine, INVALID_P2M_ENTRY, PAGE_SIZE);
-
-}
-#endif /* ADD_ISA_HOLE */
-
-/*
- * Build a directory of the pages that make up our Physical to Machine
- * mapping table. The Xen suspend/restore code uses this to find our
- * mapping table.
- */
-static void
-init_frame_list_list(void *arg)
-{
- unsigned long nr_pages = xen_start_info->nr_pages;
-#define FPP (PAGE_SIZE/sizeof(xen_pfn_t))
- int i, j, k;
-
- xen_pfn_to_mfn_frame_list_list = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
- for (i = 0, j = 0, k = -1; i < nr_pages;
- i += FPP, j++) {
- if ((j & (FPP - 1)) == 0) {
- k++;
- xen_pfn_to_mfn_frame_list[k] =
- malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
- xen_pfn_to_mfn_frame_list_list[k] =
- VTOMFN(xen_pfn_to_mfn_frame_list[k]);
- j = 0;
- }
- xen_pfn_to_mfn_frame_list[k][j] =
- VTOMFN(&xen_phys_machine[i]);
- }
-
- HYPERVISOR_shared_info->arch.max_pfn = nr_pages;
- HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list
- = VTOMFN(xen_pfn_to_mfn_frame_list_list);
-}
-SYSINIT(init_fll, SI_SUB_DEVFS, SI_ORDER_ANY, init_frame_list_list, NULL);
-
-extern unsigned long physfree;
-
-int pdir, curoffset;
-extern int nkpt;
-
-extern uint32_t kernbase;
-
-void
-initvalues(start_info_t *startinfo)
-{
- vm_offset_t cur_space, cur_space_pt;
- struct physdev_set_iopl set_iopl;
-
- int l3_pages, l2_pages, l1_pages, offset;
- vm_paddr_t console_page_ma, xen_store_ma;
- vm_offset_t tmpva;
- vm_paddr_t shinfo;
-#ifdef PAE
- vm_paddr_t IdlePDPTma, IdlePDPTnewma;
- vm_paddr_t IdlePTDnewma[4];
- pd_entry_t *IdlePDPTnew, *IdlePTDnew;
- vm_paddr_t IdlePTDma[4];
-#else
- vm_paddr_t IdlePTDma[1];
-#endif
- unsigned long i;
- int ncpus = MAXCPU;
-
- nkpt = min(
- min(
- max((startinfo->nr_pages >> NPGPTD_SHIFT), nkpt),
- NPGPTD*NPDEPG - KPTDI),
- (HYPERVISOR_VIRT_START - KERNBASE) >> PDRSHIFT);
-
- HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
-#ifdef notyet
- /*
- * need to install handler
- */
- HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments_notify);
-#endif
- xen_start_info = startinfo;
- HYPERVISOR_start_info = startinfo;
- xen_phys_machine = (xen_pfn_t *)startinfo->mfn_list;
-
- IdlePTD = (pd_entry_t *)((uint8_t *)startinfo->pt_base + PAGE_SIZE);
- l1_pages = 0;
-
-#ifdef PAE
- l3_pages = 1;
- l2_pages = 0;
- IdlePDPT = (pd_entry_t *)startinfo->pt_base;
- IdlePDPTma = VTOM(startinfo->pt_base);
- for (i = (KERNBASE >> 30);
- (i < 4) && (IdlePDPT[i] != 0); i++)
- l2_pages++;
- /*
- * Note that only one page directory has been allocated at this point.
- * Thus, if KERNBASE
- */
- for (i = 0; i < l2_pages; i++)
- IdlePTDma[i] = VTOM(IdlePTD + i*PAGE_SIZE);
-
- l2_pages = (l2_pages == 0) ? 1 : l2_pages;
-#else
- l3_pages = 0;
- l2_pages = 1;
-#endif
- for (i = (((KERNBASE>>18) & PAGE_MASK)>>PAGE_SHIFT);
- (i<l2_pages*NPDEPG) && (i<(VM_MAX_KERNEL_ADDRESS>>PDRSHIFT)); i++) {
-
- if (IdlePTD[i] == 0)
- break;
- l1_pages++;
- }
-
- /* number of pages allocated after the pts + 1*/;
- cur_space = xen_start_info->pt_base +
- (l3_pages + l2_pages + l1_pages + 1)*PAGE_SIZE;
-
- xc_printf("initvalues(): wooh - availmem=%x,%x\n", avail_space,
- cur_space);
-
- xc_printf("KERNBASE=%x,pt_base=%lx, VTOPFN(base)=%x, nr_pt_frames=%lx\n",
- KERNBASE,xen_start_info->pt_base, VTOPFN(xen_start_info->pt_base),
- xen_start_info->nr_pt_frames);
- xendebug_flags = 0; /* 0xffffffff; */
-
-#ifdef ADD_ISA_HOLE
- shift_phys_machine(xen_phys_machine, xen_start_info->nr_pages);
-#endif
- XENPRINTF("IdlePTD %p\n", IdlePTD);
- XENPRINTF("nr_pages: %ld shared_info: 0x%lx flags: 0x%x pt_base: 0x%lx "
- "mod_start: 0x%lx mod_len: 0x%lx\n",
- xen_start_info->nr_pages, xen_start_info->shared_info,
- xen_start_info->flags, xen_start_info->pt_base,
- xen_start_info->mod_start, xen_start_info->mod_len);
-
-#ifdef PAE
- IdlePDPTnew = (pd_entry_t *)cur_space; cur_space += PAGE_SIZE;
- bzero(IdlePDPTnew, PAGE_SIZE);
-
- IdlePDPTnewma = VTOM(IdlePDPTnew);
- IdlePTDnew = (pd_entry_t *)cur_space; cur_space += 4*PAGE_SIZE;
- bzero(IdlePTDnew, 4*PAGE_SIZE);
-
- for (i = 0; i < 4; i++)
- IdlePTDnewma[i] = VTOM((uint8_t *)IdlePTDnew + i*PAGE_SIZE);
- /*
- * L3
- *
- * Copy the 4 machine addresses of the new PTDs in to the PDPT
- *
- */
- for (i = 0; i < 4; i++)
- IdlePDPTnew[i] = IdlePTDnewma[i] | PG_V;
-
- __asm__("nop;");
- /*
- *
- * re-map the new PDPT read-only
- */
- PT_SET_MA(IdlePDPTnew, IdlePDPTnewma | PG_V);
- /*
- *
- * Unpin the current PDPT
- */
- xen_pt_unpin(IdlePDPTma);
-
-#endif /* PAE */
-
- /* Map proc0's KSTACK */
- proc0kstack = cur_space; cur_space += (KSTACK_PAGES * PAGE_SIZE);
- xc_printf("proc0kstack=%u\n", proc0kstack);
-
- /* vm86/bios stack */
- cur_space += PAGE_SIZE;
-
- /* Map space for the vm86 region */
- vm86paddr = (vm_offset_t)cur_space;
- cur_space += (PAGE_SIZE * 3);
-
- /* allocate 4 pages for bootmem allocator */
- bootmem_start = bootmem_current = (char *)cur_space;
- cur_space += (4 * PAGE_SIZE);
- bootmem_end = (char *)cur_space;
-
- /* allocate pages for gdt */
- gdt = (union descriptor *)cur_space;
- cur_space += PAGE_SIZE*ncpus;
-
- /* allocate page for ldt */
- ldt = (union descriptor *)cur_space; cur_space += PAGE_SIZE;
- cur_space += PAGE_SIZE;
-
- /* unmap remaining pages from initial chunk
- *
- */
- for (tmpva = cur_space; tmpva < (((uint32_t)&kernbase) + (l1_pages<<PDRSHIFT));
- tmpva += PAGE_SIZE) {
- bzero((char *)tmpva, PAGE_SIZE);
- PT_SET_MA(tmpva, (vm_paddr_t)0);
- }
-
- PT_UPDATES_FLUSH();
-
- memcpy(((uint8_t *)IdlePTDnew) + ((unsigned int)(KERNBASE >> 18)),
- ((uint8_t *)IdlePTD) + ((KERNBASE >> 18) & PAGE_MASK),
- l1_pages*sizeof(pt_entry_t));
-
- for (i = 0; i < 4; i++) {
- PT_SET_MA((uint8_t *)IdlePTDnew + i*PAGE_SIZE,
- IdlePTDnewma[i] | PG_V);
- }
- xen_load_cr3(VTOP(IdlePDPTnew));
- xen_pgdpt_pin(VTOM(IdlePDPTnew));
-
- /* allocate remainder of nkpt pages */
- cur_space_pt = cur_space;
- for (offset = (KERNBASE >> PDRSHIFT), i = l1_pages; i < nkpt;
- i++, cur_space += PAGE_SIZE) {
- pdir = (offset + i) / NPDEPG;
- curoffset = ((offset + i) % NPDEPG);
- if (((offset + i) << PDRSHIFT) == VM_MAX_KERNEL_ADDRESS)
- break;
-
- /*
- * make sure that all the initial page table pages
- * have been zeroed
- */
- PT_SET_MA(cur_space, VTOM(cur_space) | PG_V | PG_RW);
- bzero((char *)cur_space, PAGE_SIZE);
- PT_SET_MA(cur_space, (vm_paddr_t)0);
- xen_pt_pin(VTOM(cur_space));
- xen_queue_pt_update((vm_paddr_t)(IdlePTDnewma[pdir] +
- curoffset*sizeof(vm_paddr_t)),
- VTOM(cur_space) | PG_KERNEL);
- PT_UPDATES_FLUSH();
- }
-
- for (i = 0; i < 4; i++) {
- pdir = (PTDPTDI + i) / NPDEPG;
- curoffset = (PTDPTDI + i) % NPDEPG;
-
- xen_queue_pt_update((vm_paddr_t)(IdlePTDnewma[pdir] +
- curoffset*sizeof(vm_paddr_t)),
- IdlePTDnewma[i] | PG_V);
- }
-
- PT_UPDATES_FLUSH();
-
- IdlePTD = IdlePTDnew;
- IdlePDPT = IdlePDPTnew;
- IdlePDPTma = IdlePDPTnewma;
-
- HYPERVISOR_shared_info = (shared_info_t *)cur_space;
- cur_space += PAGE_SIZE;
-
- xen_store = (struct xenstore_domain_interface *)cur_space;
- cur_space += PAGE_SIZE;
-
- console_page = (char *)cur_space;
- cur_space += PAGE_SIZE;
-
- /*
- * shared_info is an unsigned long so this will randomly break if
- * it is allocated above 4GB - I guess people are used to that
- * sort of thing with Xen ... sigh
- */
- shinfo = xen_start_info->shared_info;
- PT_SET_MA(HYPERVISOR_shared_info, shinfo | PG_KERNEL);
-
- xc_printf("#4\n");
-
- xen_store_ma = (((vm_paddr_t)xen_start_info->store_mfn) << PAGE_SHIFT);
- PT_SET_MA(xen_store, xen_store_ma | PG_KERNEL);
- console_page_ma = (((vm_paddr_t)xen_start_info->console.domU.mfn) << PAGE_SHIFT);
- PT_SET_MA(console_page, console_page_ma | PG_KERNEL);
-
- xc_printf("#5\n");
-
- set_iopl.iopl = 1;
- PANIC_IF(HYPERVISOR_physdev_op(PHYSDEVOP_SET_IOPL, &set_iopl));
- xc_printf("#6\n");
-#if 0
- /* add page table for KERNBASE */
- xen_queue_pt_update(IdlePTDma + KPTDI*sizeof(vm_paddr_t),
- VTOM(cur_space) | PG_KERNEL);
- xen_flush_queue();
-#ifdef PAE
- xen_queue_pt_update(pdir_shadow_ma[3] + KPTDI*sizeof(vm_paddr_t),
- VTOM(cur_space) | PG_V | PG_A);
-#else
- xen_queue_pt_update(pdir_shadow_ma + KPTDI*sizeof(vm_paddr_t),
- VTOM(cur_space) | PG_V | PG_A);
-#endif
- xen_flush_queue();
- cur_space += PAGE_SIZE;
- xc_printf("#6\n");
-#endif /* 0 */
-#ifdef notyet
- if (xen_start_info->flags & SIF_INITDOMAIN) {
- /* Map first megabyte */
- for (i = 0; i < (256 << PAGE_SHIFT); i += PAGE_SIZE)
- PT_SET_MA(KERNBASE + i, i | PG_KERNEL | PG_NC_PCD);
- xen_flush_queue();
- }
-#endif
- /*
- * re-map kernel text read-only
- *
- */
- for (i = (((vm_offset_t)&btext) & ~PAGE_MASK);
- i < (((vm_offset_t)&etext) & ~PAGE_MASK); i += PAGE_SIZE)
- PT_SET_MA(i, VTOM(i) | PG_V | PG_A);
-
- xc_printf("#7\n");
- physfree = VTOP(cur_space);
- init_first = physfree >> PAGE_SHIFT;
- IdlePTD = (pd_entry_t *)VTOP(IdlePTD);
- IdlePDPT = (pd_entry_t *)VTOP(IdlePDPT);
- setup_xen_features();
- xc_printf("#8, proc0kstack=%u\n", proc0kstack);
-}
-
-
-trap_info_t trap_table[] = {
- { 0, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(div)},
- { 1, 0|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dbg)},
- { 3, 3|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bpt)},
- { 4, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ofl)},
- /* This is UPL on Linux and KPL on BSD */
- { 5, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bnd)},
- { 6, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ill)},
- { 7, 0|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dna)},
- /*
- * { 8, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(XXX)},
- * no handler for double fault
- */
- { 9, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpusegm)},
- {10, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(tss)},
- {11, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(missing)},
- {12, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(stk)},
- {13, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(prot)},
- {14, 0|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(page)},
- {15, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(rsvd)},
- {16, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpu)},
- {17, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(align)},
- {18, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(mchk)},
- {19, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(xmm)},
- {0x80, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(int0x80_syscall)},
- { 0, 0, 0, 0 }
-};
-
-/* Perform a multicall and check that individual calls succeeded. */
-int
-HYPERVISOR_multicall(struct multicall_entry * call_list, int nr_calls)
-{
- int ret = 0;
- int i;
-
- /* Perform the multicall. */
- PANIC_IF(_HYPERVISOR_multicall(call_list, nr_calls));
-
- /* Check the results of individual hypercalls. */
- for (i = 0; i < nr_calls; i++)
- if (__predict_false(call_list[i].result < 0))
- ret++;
- if (__predict_false(ret > 0))
- panic("%d multicall(s) failed: cpu %d\n",
- ret, smp_processor_id());
-
- /* If we didn't panic already, everything succeeded. */
- return (0);
-}
-
-/********** CODE WORTH KEEPING ABOVE HERE *****************/
-
-void xen_failsafe_handler(void);
-
-void
-xen_failsafe_handler(void)
-{
-
- panic("xen_failsafe_handler called!\n");
-}
-
-void xen_handle_thread_switch(struct pcb *pcb);
-
-/* This is called by cpu_switch() when switching threads. */
-/* The pcb arg refers to the process control block of the */
-/* next thread which is to run */
-void
-xen_handle_thread_switch(struct pcb *pcb)
-{
- uint32_t *a = (uint32_t *)&PCPU_GET(fsgs_gdt)[0];
- uint32_t *b = (uint32_t *)&pcb->pcb_fsd;
- multicall_entry_t mcl[3];
- int i = 0;
-
- /* Notify Xen of task switch */
- mcl[i].op = __HYPERVISOR_stack_switch;
- mcl[i].args[0] = GSEL(GDATA_SEL, SEL_KPL);
- mcl[i++].args[1] = (unsigned long)pcb;
-
- /* Check for update of fsd */
- if (*a != *b || *(a+1) != *(b+1)) {
- mcl[i].op = __HYPERVISOR_update_descriptor;
- *(uint64_t *)&mcl[i].args[0] = vtomach((vm_offset_t)a);
- *(uint64_t *)&mcl[i++].args[2] = *(uint64_t *)b;
- }
-
- a += 2;
- b += 2;
-
- /* Check for update of gsd */
- if (*a != *b || *(a+1) != *(b+1)) {
- mcl[i].op = __HYPERVISOR_update_descriptor;
- *(uint64_t *)&mcl[i].args[0] = vtomach((vm_offset_t)a);
- *(uint64_t *)&mcl[i++].args[2] = *(uint64_t *)b;
- }
-
- (void)HYPERVISOR_multicall(mcl, i);
-}
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 0a8b79a..3ff3440 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -782,6 +782,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
if (__elfN(nxstack))
imgp->stack_prot =
__elfN(trans_prot)(phdr[i].p_flags);
+ imgp->stack_sz = phdr[i].p_memsz;
break;
}
}
@@ -1237,12 +1238,14 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
coresize = round_page(hdrsize + notesz) + seginfo.size;
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- error = racct_add(td->td_proc, RACCT_CORE, coresize);
- PROC_UNLOCK(td->td_proc);
- if (error != 0) {
- error = EFAULT;
- goto done;
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ error = racct_add(td->td_proc, RACCT_CORE, coresize);
+ PROC_UNLOCK(td->td_proc);
+ if (error != 0) {
+ error = EFAULT;
+ goto done;
+ }
}
#endif
if (coresize >= limit) {
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 88cd44c..b77b788 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -710,6 +710,9 @@ start_init(void *dummy)
vfs_mountroot();
+ /* Wipe GELI passphrase from the environment. */
+ kern_unsetenv("kern.geom.eli.passphrase");
+
/*
* Need just enough stack to hold the faked-up "execve()" arguments.
*/
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 8aefa3f..14e8281 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles
+ * created from FreeBSD: head/sys/kern/syscalls.master 281714 2015-04-18 21:50:13Z kib
*/
#include "opt_compat.h"
@@ -26,6 +26,12 @@
#define compat4(n, name) 0, (sy_call_t *)nosys
#endif
+#ifdef COMPAT_FREEBSD6
+#define compat6(n, name) n, (sy_call_t *)__CONCAT(freebsd6_,name)
+#else
+#define compat6(n, name) 0, (sy_call_t *)nosys
+#endif
+
#ifdef COMPAT_FREEBSD7
#define compat7(n, name) n, (sy_call_t *)__CONCAT(freebsd7_,name)
#else
@@ -207,8 +213,8 @@ struct sysent sysent[] = {
{ AS(msgsys_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 170 = msgsys */
{ AS(shmsys_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 171 = shmsys */
{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 172 = nosys */
- { AS(freebsd6_pread_args), (sy_call_t *)freebsd6_pread, AUE_PREAD, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 173 = freebsd6_pread */
- { AS(freebsd6_pwrite_args), (sy_call_t *)freebsd6_pwrite, AUE_PWRITE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 174 = freebsd6_pwrite */
+ { compat6(AS(freebsd6_pread_args),pread), AUE_PREAD, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 173 = freebsd6 pread */
+ { compat6(AS(freebsd6_pwrite_args),pwrite), AUE_PWRITE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 174 = freebsd6 pwrite */
{ AS(setfib_args), (sy_call_t *)sys_setfib, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 175 = setfib */
{ AS(ntp_adjtime_args), (sy_call_t *)sys_ntp_adjtime, AUE_NTP_ADJTIME, NULL, 0, 0, 0, SY_THR_STATIC }, /* 176 = ntp_adjtime */
{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 177 = sfork */
@@ -231,11 +237,11 @@ struct sysent sysent[] = {
{ AS(__getrlimit_args), (sy_call_t *)sys_getrlimit, AUE_GETRLIMIT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 194 = getrlimit */
{ AS(__setrlimit_args), (sy_call_t *)sys_setrlimit, AUE_SETRLIMIT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 195 = setrlimit */
{ AS(getdirentries_args), (sy_call_t *)sys_getdirentries, AUE_GETDIRENTRIES, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 196 = getdirentries */
- { AS(freebsd6_mmap_args), (sy_call_t *)freebsd6_mmap, AUE_MMAP, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 197 = freebsd6_mmap */
+ { compat6(AS(freebsd6_mmap_args),mmap), AUE_MMAP, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 197 = freebsd6 mmap */
{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 198 = __syscall */
- { AS(freebsd6_lseek_args), (sy_call_t *)freebsd6_lseek, AUE_LSEEK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 199 = freebsd6_lseek */
- { AS(freebsd6_truncate_args), (sy_call_t *)freebsd6_truncate, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 200 = freebsd6_truncate */
- { AS(freebsd6_ftruncate_args), (sy_call_t *)freebsd6_ftruncate, AUE_FTRUNCATE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 201 = freebsd6_ftruncate */
+ { compat6(AS(freebsd6_lseek_args),lseek), AUE_LSEEK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 199 = freebsd6 lseek */
+ { compat6(AS(freebsd6_truncate_args),truncate), AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 200 = freebsd6 truncate */
+ { compat6(AS(freebsd6_ftruncate_args),ftruncate), AUE_FTRUNCATE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 201 = freebsd6 ftruncate */
{ AS(sysctl_args), (sy_call_t *)sys___sysctl, AUE_SYSCTL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 202 = __sysctl */
{ AS(mlock_args), (sy_call_t *)sys_mlock, AUE_MLOCK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 203 = mlock */
{ AS(munlock_args), (sy_call_t *)sys_munlock, AUE_MUNLOCK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 204 = munlock */
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 4041353..329f418 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -857,13 +857,15 @@ do_dup(struct thread *td, int flags, int old, int new)
* the limit on the size of the file descriptor table.
*/
#ifdef RACCT
- PROC_LOCK(p);
- error = racct_set(p, RACCT_NOFILE, new + 1);
- PROC_UNLOCK(p);
- if (error != 0) {
- FILEDESC_XUNLOCK(fdp);
- fdrop(fp, td);
- return (EMFILE);
+ if (racct_enable) {
+ PROC_LOCK(p);
+ error = racct_set(p, RACCT_NOFILE, new + 1);
+ PROC_UNLOCK(p);
+ if (error != 0) {
+ FILEDESC_XUNLOCK(fdp);
+ fdrop(fp, td);
+ return (EMFILE);
+ }
}
#endif
fdgrowtable_exp(fdp, new + 1);
@@ -1609,7 +1611,7 @@ fdalloc(struct thread *td, int minfd, int *result)
{
struct proc *p = td->td_proc;
struct filedesc *fdp = p->p_fd;
- int fd = -1, maxfd, allocfd;
+ int fd, maxfd, allocfd;
#ifdef RACCT
int error;
#endif
@@ -1631,11 +1633,13 @@ fdalloc(struct thread *td, int minfd, int *result)
if (fd >= fdp->fd_nfiles) {
allocfd = min(fd * 2, maxfd);
#ifdef RACCT
- PROC_LOCK(p);
- error = racct_set(p, RACCT_NOFILE, allocfd);
- PROC_UNLOCK(p);
- if (error != 0)
- return (EMFILE);
+ if (racct_enable) {
+ PROC_LOCK(p);
+ error = racct_set(p, RACCT_NOFILE, allocfd);
+ PROC_UNLOCK(p);
+ if (error != 0)
+ return (EMFILE);
+ }
#endif
/*
* fd is already equal to first free descriptor >= minfd, so
@@ -2042,9 +2046,11 @@ fdescfree(struct thread *td)
MPASS(fdp != NULL);
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- racct_set(td->td_proc, RACCT_NOFILE, 0);
- PROC_UNLOCK(td->td_proc);
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ racct_set(td->td_proc, RACCT_NOFILE, 0);
+ PROC_UNLOCK(td->td_proc);
+ }
#endif
if (td->td_proc->p_fdtol != NULL)
@@ -2155,8 +2161,9 @@ fdsetugidsafety(struct thread *td)
* file descriptor out from under the thread creating the file object.
*/
void
-fdclose(struct filedesc *fdp, struct file *fp, int idx, struct thread *td)
+fdclose(struct thread *td, struct file *fp, int idx)
{
+ struct filedesc *fdp = td->td_proc->p_fd;
FILEDESC_XLOCK(fdp);
if (fdp->fd_ofiles[idx].fde_file == fp) {
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 388ed19..9d893f8 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1009,6 +1009,7 @@ exec_new_vmspace(imgp, sv)
struct proc *p = imgp->proc;
struct vmspace *vmspace = p->p_vmspace;
vm_object_t obj;
+ struct rlimit rlim_stack;
vm_offset_t sv_minuser, stack_addr;
vm_map_t map;
u_long ssiz;
@@ -1058,10 +1059,22 @@ exec_new_vmspace(imgp, sv)
}
/* Allocate a new stack */
- if (sv->sv_maxssiz != NULL)
+ if (imgp->stack_sz != 0) {
+ ssiz = trunc_page(imgp->stack_sz);
+ PROC_LOCK(p);
+ lim_rlimit(p, RLIMIT_STACK, &rlim_stack);
+ PROC_UNLOCK(p);
+ if (ssiz > rlim_stack.rlim_max)
+ ssiz = rlim_stack.rlim_max;
+ if (ssiz > rlim_stack.rlim_cur) {
+ rlim_stack.rlim_cur = ssiz;
+ kern_setrlimit(curthread, RLIMIT_STACK, &rlim_stack);
+ }
+ } else if (sv->sv_maxssiz != NULL) {
ssiz = *sv->sv_maxssiz;
- else
+ } else {
ssiz = maxssiz;
+ }
stack_addr = sv->sv_usrstack - ssiz;
error = vm_map_stack(map, stack_addr, (vm_size_t)ssiz,
obj != NULL && imgp->stack_prot != 0 ? imgp->stack_prot :
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 4d23fc0..0a601a1 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -907,9 +907,11 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options)
* Destroy resource accounting information associated with the process.
*/
#ifdef RACCT
- PROC_LOCK(p);
- racct_sub(p, RACCT_NPROC, 1);
- PROC_UNLOCK(p);
+ if (racct_enable) {
+ PROC_LOCK(p);
+ racct_sub(p, RACCT_NPROC, 1);
+ PROC_UNLOCK(p);
+ }
#endif
racct_proc_exit(p);
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index a3a70b8..c3dd792 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -949,7 +949,7 @@ fail2:
vmspace_free(vm2);
uma_zfree(proc_zone, newproc);
if ((flags & RFPROCDESC) != 0 && fp_procdesc != NULL) {
- fdclose(td->td_proc->p_fd, fp_procdesc, *procdescp, td);
+ fdclose(td, fp_procdesc, *procdescp);
fdrop(fp_procdesc, td);
}
pause("fork", hz / 2);
diff --git a/sys/kern/kern_gzio.c b/sys/kern/kern_gzio.c
index a4974a7..cee21f0 100644
--- a/sys/kern/kern_gzio.c
+++ b/sys/kern/kern_gzio.c
@@ -32,8 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/gzio.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-
-#include <net/zutil.h>
+#include <sys/zutil.h>
#define KERN_GZ_HDRLEN 10 /* gzip header length */
#define KERN_GZ_TRAILERLEN 8 /* gzip trailer length */
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
index 7a5d936..a84019a 100644
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -1455,12 +1455,7 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame)
/* Schedule the ithread if needed. */
if (thread) {
error = intr_event_schedule_thread(ie);
-#ifndef XEN
KASSERT(error == 0, ("bad stray interrupt"));
-#else
- if (error != 0)
- log(LOG_WARNING, "bad stray interrupt");
-#endif
}
critical_exit();
td->td_intr_nesting_level--;
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 5b23129..c87c4e2 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -1778,7 +1778,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
mtx_unlock(&pr->pr_mtx);
#ifdef RACCT
- if (created)
+ if (racct_enable && created)
prison_racct_attach(pr);
#endif
@@ -1862,7 +1862,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
}
#ifdef RACCT
- if (!created) {
+ if (racct_enable && !created) {
if (!(flags & JAIL_ATTACH))
sx_sunlock(&allprison_lock);
prison_racct_modify(pr);
@@ -2652,7 +2652,8 @@ prison_deref(struct prison *pr, int flags)
cpuset_rel(pr->pr_cpuset);
osd_jail_exit(pr);
#ifdef RACCT
- prison_racct_detach(pr);
+ if (racct_enable)
+ prison_racct_detach(pr);
#endif
free(pr, M_PRISON);
@@ -4460,12 +4461,15 @@ SYSCTL_JAIL_PARAM(_allow_mount, tmpfs, CTLTYPE_INT | CTLFLAG_RW,
SYSCTL_JAIL_PARAM(_allow_mount, zfs, CTLTYPE_INT | CTLFLAG_RW,
"B", "Jail may mount the zfs file system");
+#ifdef RACCT
void
prison_racct_foreach(void (*callback)(struct racct *racct,
void *arg2, void *arg3), void *arg2, void *arg3)
{
struct prison_racct *prr;
+ ASSERT_RACCT_ENABLED();
+
sx_slock(&allprison_lock);
LIST_FOREACH(prr, &allprison_racct, prr_next)
(callback)(prr->prr_racct, arg2, arg3);
@@ -4477,6 +4481,7 @@ prison_racct_find_locked(const char *name)
{
struct prison_racct *prr;
+ ASSERT_RACCT_ENABLED();
sx_assert(&allprison_lock, SA_XLOCKED);
if (name[0] == '\0' || strlen(name) >= MAXHOSTNAMELEN)
@@ -4507,6 +4512,8 @@ prison_racct_find(const char *name)
{
struct prison_racct *prr;
+ ASSERT_RACCT_ENABLED();
+
sx_xlock(&allprison_lock);
prr = prison_racct_find_locked(name);
sx_xunlock(&allprison_lock);
@@ -4517,6 +4524,8 @@ void
prison_racct_hold(struct prison_racct *prr)
{
+ ASSERT_RACCT_ENABLED();
+
refcount_acquire(&prr->prr_refcount);
}
@@ -4524,6 +4533,7 @@ static void
prison_racct_free_locked(struct prison_racct *prr)
{
+ ASSERT_RACCT_ENABLED();
sx_assert(&allprison_lock, SA_XLOCKED);
if (refcount_release(&prr->prr_refcount)) {
@@ -4538,6 +4548,7 @@ prison_racct_free(struct prison_racct *prr)
{
int old;
+ ASSERT_RACCT_ENABLED();
sx_assert(&allprison_lock, SA_UNLOCKED);
old = prr->prr_refcount;
@@ -4549,12 +4560,12 @@ prison_racct_free(struct prison_racct *prr)
sx_xunlock(&allprison_lock);
}
-#ifdef RACCT
static void
prison_racct_attach(struct prison *pr)
{
struct prison_racct *prr;
+ ASSERT_RACCT_ENABLED();
sx_assert(&allprison_lock, SA_XLOCKED);
prr = prison_racct_find_locked(pr->pr_name);
@@ -4574,6 +4585,8 @@ prison_racct_modify(struct prison *pr)
struct ucred *cred;
struct prison_racct *oldprr;
+ ASSERT_RACCT_ENABLED();
+
sx_slock(&allproc_lock);
sx_xlock(&allprison_lock);
@@ -4613,6 +4626,7 @@ static void
prison_racct_detach(struct prison *pr)
{
+ ASSERT_RACCT_ENABLED();
sx_assert(&allprison_lock, SA_UNLOCKED);
if (pr->pr_prison_racct == NULL)
diff --git a/sys/kern/kern_physio.c b/sys/kern/kern_physio.c
index b37b9f3..71cfded 100644
--- a/sys/kern/kern_physio.c
+++ b/sys/kern/kern_physio.c
@@ -25,27 +25,26 @@ __FBSDID("$FreeBSD$");
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/conf.h>
+#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/uio.h>
+#include <geom/geom.h>
#include <vm/vm.h>
+#include <vm/vm_page.h>
#include <vm/vm_extern.h>
+#include <vm/vm_map.h>
int
physio(struct cdev *dev, struct uio *uio, int ioflag)
{
- struct buf *bp;
- struct cdevsw *csw;
+ struct buf *pbuf;
+ struct bio *bp;
+ struct vm_page **pages;
caddr_t sa;
- u_int iolen;
- int error, i, mapped;
-
- /* Keep the process UPAGES from being swapped. XXX: why ? */
- PHOLD(curproc);
-
- bp = getpbuf(NULL);
- sa = bp->b_data;
- error = 0;
+ u_int iolen, poff;
+ int error, i, npages, maxpages;
+ vm_prot_t prot;
/* XXX: sanity check */
if(dev->si_iosize_max < PAGE_SIZE) {
@@ -76,95 +75,128 @@ physio(struct cdev *dev, struct uio *uio, int ioflag)
uprintf("%s: request vectors=%d > 1; "
"cannot split request\n", devtoname(dev),
uio->uio_iovcnt);
-
- error = EFBIG;
- goto doerror;
+ return (EFBIG);
}
+ /*
+ * Keep the process UPAGES from being swapped. Processes swapped
+ * out while holding pbufs, used by swapper, may lead to deadlock.
+ */
+ PHOLD(curproc);
+
+ bp = g_alloc_bio();
+ if (uio->uio_segflg != UIO_USERSPACE) {
+ pbuf = NULL;
+ pages = NULL;
+ } else if ((dev->si_flags & SI_UNMAPPED) && unmapped_buf_allowed) {
+ pbuf = NULL;
+ maxpages = btoc(MIN(uio->uio_resid, MAXPHYS)) + 1;
+ pages = malloc(sizeof(*pages) * maxpages, M_DEVBUF, M_WAITOK);
+ } else {
+ pbuf = getpbuf(NULL);
+ sa = pbuf->b_data;
+ maxpages = btoc(MAXPHYS);
+ pages = pbuf->b_pages;
+ }
+ prot = VM_PROT_READ;
+ if (uio->uio_rw == UIO_READ)
+ prot |= VM_PROT_WRITE; /* Less backwards than it looks */
+ error = 0;
for (i = 0; i < uio->uio_iovcnt; i++) {
while (uio->uio_iov[i].iov_len) {
- bp->b_flags = 0;
+ bzero(bp, sizeof(*bp));
if (uio->uio_rw == UIO_READ) {
- bp->b_iocmd = BIO_READ;
+ bp->bio_cmd = BIO_READ;
curthread->td_ru.ru_inblock++;
} else {
- bp->b_iocmd = BIO_WRITE;
+ bp->bio_cmd = BIO_WRITE;
curthread->td_ru.ru_oublock++;
}
- bp->b_iodone = bdone;
- bp->b_data = uio->uio_iov[i].iov_base;
- bp->b_bcount = uio->uio_iov[i].iov_len;
- bp->b_offset = uio->uio_offset;
- bp->b_iooffset = uio->uio_offset;
- bp->b_saveaddr = sa;
-
- /* Don't exceed drivers iosize limit */
- if (bp->b_bcount > dev->si_iosize_max)
- bp->b_bcount = dev->si_iosize_max;
-
- /*
- * Make sure the pbuf can map the request
- * XXX: The pbuf has kvasize = MAXPHYS so a request
- * XXX: larger than MAXPHYS - PAGE_SIZE must be
- * XXX: page aligned or it will be fragmented.
+ bp->bio_offset = uio->uio_offset;
+ bp->bio_data = uio->uio_iov[i].iov_base;
+ bp->bio_length = uio->uio_iov[i].iov_len;
+ if (bp->bio_length > dev->si_iosize_max)
+ bp->bio_length = dev->si_iosize_max;
+ if (bp->bio_length > MAXPHYS)
+ bp->bio_length = MAXPHYS;
+
+ /*
+ * Make sure the pbuf can map the request.
+ * The pbuf has kvasize = MAXPHYS, so a request
+ * larger than MAXPHYS - PAGE_SIZE must be
+ * page aligned or it will be fragmented.
*/
- iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK;
- if ((bp->b_bcount + iolen) > bp->b_kvasize) {
- /*
- * This device does not want I/O to be split.
- */
+ poff = (vm_offset_t)bp->bio_data & PAGE_MASK;
+ if (pbuf && bp->bio_length + poff > pbuf->b_kvasize) {
if (dev->si_flags & SI_NOSPLIT) {
uprintf("%s: request ptr %p is not "
"on a page boundary; cannot split "
"request\n", devtoname(dev),
- bp->b_data);
+ bp->bio_data);
error = EFBIG;
goto doerror;
}
- bp->b_bcount = bp->b_kvasize;
- if (iolen != 0)
- bp->b_bcount -= PAGE_SIZE;
+ bp->bio_length = pbuf->b_kvasize;
+ if (poff != 0)
+ bp->bio_length -= PAGE_SIZE;
}
- bp->b_bufsize = bp->b_bcount;
- bp->b_blkno = btodb(bp->b_offset);
+ bp->bio_bcount = bp->bio_length;
+ bp->bio_dev = dev;
- csw = dev->si_devsw;
- if (uio->uio_segflg == UIO_USERSPACE) {
- if (dev->si_flags & SI_UNMAPPED)
- mapped = 0;
- else
- mapped = 1;
- if (vmapbuf(bp, mapped) < 0) {
+ if (pages) {
+ if ((npages = vm_fault_quick_hold_pages(
+ &curproc->p_vmspace->vm_map,
+ (vm_offset_t)bp->bio_data, bp->bio_length,
+ prot, pages, maxpages)) < 0) {
error = EFAULT;
goto doerror;
}
+ if (pbuf) {
+ pmap_qenter((vm_offset_t)sa,
+ pages, npages);
+ bp->bio_data = sa + poff;
+ } else {
+ bp->bio_ma = pages;
+ bp->bio_ma_n = npages;
+ bp->bio_ma_offset = poff;
+ bp->bio_data = unmapped_buf;
+ bp->bio_flags |= BIO_UNMAPPED;
+ }
}
- dev_strategy_csw(dev, csw, bp);
+ dev->si_devsw->d_strategy(bp);
if (uio->uio_rw == UIO_READ)
- bwait(bp, PRIBIO, "physrd");
+ biowait(bp, "physrd");
else
- bwait(bp, PRIBIO, "physwr");
+ biowait(bp, "physwr");
+
+ if (pages) {
+ if (pbuf)
+ pmap_qremove((vm_offset_t)sa, npages);
+ vm_page_unhold_pages(pages, npages);
+ }
- if (uio->uio_segflg == UIO_USERSPACE)
- vunmapbuf(bp);
- iolen = bp->b_bcount - bp->b_resid;
- if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR))
+ iolen = bp->bio_length - bp->bio_resid;
+ if (iolen == 0 && !(bp->bio_flags & BIO_ERROR))
goto doerror; /* EOF */
uio->uio_iov[i].iov_len -= iolen;
uio->uio_iov[i].iov_base =
(char *)uio->uio_iov[i].iov_base + iolen;
uio->uio_resid -= iolen;
uio->uio_offset += iolen;
- if( bp->b_ioflags & BIO_ERROR) {
- error = bp->b_error;
+ if (bp->bio_flags & BIO_ERROR) {
+ error = bp->bio_error;
goto doerror;
}
}
}
doerror:
- relpbuf(bp, NULL);
+ if (pbuf)
+ relpbuf(pbuf, NULL);
+ else if (pages)
+ free(pages, M_DEVBUF);
+ g_destroy_bio(bp);
PRELE(curproc);
return (error);
}
diff --git a/sys/kern/kern_poll.c b/sys/kern/kern_poll.c
index 04b4e79..5aa12f0 100644
--- a/sys/kern/kern_poll.c
+++ b/sys/kern/kern_poll.c
@@ -367,6 +367,9 @@ netisr_pollmore()
struct timeval t;
int kern_load;
+ if (poll_handlers == 0)
+ return;
+
mtx_lock(&poll_mtx);
if (!netisr_pollmore_scheduled) {
mtx_unlock(&poll_mtx);
@@ -424,6 +427,9 @@ netisr_poll(void)
int i, cycles;
enum poll_cmd arg = POLL_ONLY;
+ if (poll_handlers == 0)
+ return;
+
mtx_lock(&poll_mtx);
if (!netisr_poll_scheduled) {
mtx_unlock(&poll_mtx);
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index 505521d..6618c08 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -2822,7 +2822,7 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC_PROC, proc, CTLFLAG_RD | CTLFLAG_MPSAFE
sysctl_kern_proc, "Return process table, no threads");
static SYSCTL_NODE(_kern_proc, KERN_PROC_ARGS, args,
- CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
+ CTLFLAG_RW | CTLFLAG_CAPWR | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
sysctl_kern_proc_args, "Process argument list");
static SYSCTL_NODE(_kern_proc, KERN_PROC_ENV, env, CTLFLAG_RD | CTLFLAG_MPSAFE,
diff --git a/sys/kern/kern_racct.c b/sys/kern/kern_racct.c
index 05becea..5cee140 100644
--- a/sys/kern/kern_racct.c
+++ b/sys/kern/kern_racct.c
@@ -70,8 +70,15 @@ FEATURE(racct, "Resource Accounting");
* Do not block processes that have their %cpu usage <= pcpu_threshold.
*/
static int pcpu_threshold = 1;
+#ifdef RACCT_DISABLED
+int racct_enable = 0;
+#else
+int racct_enable = 1;
+#endif
SYSCTL_NODE(_kern, OID_AUTO, racct, CTLFLAG_RW, 0, "Resource Accounting");
+SYSCTL_UINT(_kern_racct, OID_AUTO, enable, CTLFLAG_RDTUN, &racct_enable,
+ 0, "Enable RACCT/RCTL");
SYSCTL_UINT(_kern_racct, OID_AUTO, pcpu_threshold, CTLFLAG_RW, &pcpu_threshold,
0, "Processes with higher %cpu usage than this value can be throttled.");
@@ -313,6 +320,8 @@ racct_getpcpu(struct proc *p, u_int pcpu)
fixpt_t p_pctcpu;
struct thread *td;
+ ASSERT_RACCT_ENABLED();
+
/*
* If the process is swapped out, we count its %cpu usage as zero.
* This behaviour is consistent with the userland ps(1) tool.
@@ -377,6 +386,7 @@ racct_add_racct(struct racct *dest, const struct racct *src)
{
int i;
+ ASSERT_RACCT_ENABLED();
mtx_assert(&racct_lock, MA_OWNED);
/*
@@ -398,6 +408,7 @@ racct_sub_racct(struct racct *dest, const struct racct *src)
{
int i;
+ ASSERT_RACCT_ENABLED();
mtx_assert(&racct_lock, MA_OWNED);
/*
@@ -431,6 +442,9 @@ void
racct_create(struct racct **racctp)
{
+ if (!racct_enable)
+ return;
+
SDT_PROBE(racct, kernel, racct, create, racctp, 0, 0, 0, 0);
KASSERT(*racctp == NULL, ("racct already allocated"));
@@ -444,6 +458,8 @@ racct_destroy_locked(struct racct **racctp)
int i;
struct racct *racct;
+ ASSERT_RACCT_ENABLED();
+
SDT_PROBE(racct, kernel, racct, destroy, racctp, 0, 0, 0, 0);
mtx_assert(&racct_lock, MA_OWNED);
@@ -470,6 +486,9 @@ void
racct_destroy(struct racct **racct)
{
+ if (!racct_enable)
+ return;
+
mtx_lock(&racct_lock);
racct_destroy_locked(racct);
mtx_unlock(&racct_lock);
@@ -485,6 +504,7 @@ racct_alloc_resource(struct racct *racct, int resource,
uint64_t amount)
{
+ ASSERT_RACCT_ENABLED();
mtx_assert(&racct_lock, MA_OWNED);
KASSERT(racct != NULL, ("NULL racct"));
@@ -516,6 +536,8 @@ racct_add_locked(struct proc *p, int resource, uint64_t amount)
int error;
#endif
+ ASSERT_RACCT_ENABLED();
+
SDT_PROBE(racct, kernel, rusage, add, p, resource, amount, 0, 0);
/*
@@ -546,6 +568,9 @@ racct_add(struct proc *p, int resource, uint64_t amount)
{
int error;
+ if (!racct_enable)
+ return (0);
+
mtx_lock(&racct_lock);
error = racct_add_locked(p, resource, amount);
mtx_unlock(&racct_lock);
@@ -557,6 +582,8 @@ racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount)
{
struct prison *pr;
+ ASSERT_RACCT_ENABLED();
+
SDT_PROBE(racct, kernel, rusage, add__cred, cred, resource, amount,
0, 0);
@@ -577,6 +604,9 @@ void
racct_add_cred(struct ucred *cred, int resource, uint64_t amount)
{
+ if (!racct_enable)
+ return;
+
mtx_lock(&racct_lock);
racct_add_cred_locked(cred, resource, amount);
mtx_unlock(&racct_lock);
@@ -590,6 +620,9 @@ void
racct_add_force(struct proc *p, int resource, uint64_t amount)
{
+ if (!racct_enable)
+ return;
+
SDT_PROBE(racct, kernel, rusage, add__force, p, resource, amount, 0, 0);
/*
@@ -612,6 +645,8 @@ racct_set_locked(struct proc *p, int resource, uint64_t amount)
int error;
#endif
+ ASSERT_RACCT_ENABLED();
+
SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0);
/*
@@ -671,6 +706,9 @@ racct_set(struct proc *p, int resource, uint64_t amount)
{
int error;
+ if (!racct_enable)
+ return (0);
+
mtx_lock(&racct_lock);
error = racct_set_locked(p, resource, amount);
mtx_unlock(&racct_lock);
@@ -683,6 +721,8 @@ racct_set_force_locked(struct proc *p, int resource, uint64_t amount)
int64_t old_amount, decayed_amount;
int64_t diff_proc, diff_cred;
+ ASSERT_RACCT_ENABLED();
+
SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0);
/*
@@ -717,6 +757,10 @@ racct_set_force_locked(struct proc *p, int resource, uint64_t amount)
void
racct_set_force(struct proc *p, int resource, uint64_t amount)
{
+
+ if (!racct_enable)
+ return;
+
mtx_lock(&racct_lock);
racct_set_force_locked(p, resource, amount);
mtx_unlock(&racct_lock);
@@ -732,6 +776,9 @@ uint64_t
racct_get_limit(struct proc *p, int resource)
{
+ if (!racct_enable)
+ return (UINT64_MAX);
+
#ifdef RCTL
return (rctl_get_limit(p, resource));
#else
@@ -749,6 +796,9 @@ uint64_t
racct_get_available(struct proc *p, int resource)
{
+ if (!racct_enable)
+ return (UINT64_MAX);
+
#ifdef RCTL
return (rctl_get_available(p, resource));
#else
@@ -765,6 +815,8 @@ static int64_t
racct_pcpu_available(struct proc *p)
{
+ ASSERT_RACCT_ENABLED();
+
#ifdef RCTL
return (rctl_pcpu_available(p));
#else
@@ -779,6 +831,9 @@ void
racct_sub(struct proc *p, int resource, uint64_t amount)
{
+ if (!racct_enable)
+ return;
+
SDT_PROBE(racct, kernel, rusage, sub, p, resource, amount, 0, 0);
/*
@@ -804,6 +859,8 @@ racct_sub_cred_locked(struct ucred *cred, int resource, uint64_t amount)
{
struct prison *pr;
+ ASSERT_RACCT_ENABLED();
+
SDT_PROBE(racct, kernel, rusage, sub__cred, cred, resource, amount,
0, 0);
@@ -827,6 +884,9 @@ void
racct_sub_cred(struct ucred *cred, int resource, uint64_t amount)
{
+ if (!racct_enable)
+ return;
+
mtx_lock(&racct_lock);
racct_sub_cred_locked(cred, resource, amount);
mtx_unlock(&racct_lock);
@@ -840,6 +900,9 @@ racct_proc_fork(struct proc *parent, struct proc *child)
{
int i, error = 0;
+ if (!racct_enable)
+ return (0);
+
/*
* Create racct for the child process.
*/
@@ -896,6 +959,9 @@ racct_proc_fork_done(struct proc *child)
{
#ifdef RCTL
+ if (!racct_enable)
+ return;
+
PROC_LOCK(child);
mtx_lock(&racct_lock);
rctl_enforce(child, RACCT_NPROC, 0);
@@ -913,6 +979,9 @@ racct_proc_exit(struct proc *p)
struct timeval wallclock;
uint64_t pct_estimate, pct;
+ if (!racct_enable)
+ return;
+
PROC_LOCK(p);
/*
* We don't need to calculate rux, proc_reap() has already done this.
@@ -967,6 +1036,9 @@ racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred,
struct loginclass *oldlc, *newlc;
struct prison *oldpr, *newpr, *pr;
+ if (!racct_enable)
+ return;
+
PROC_LOCK_ASSERT(p, MA_NOTOWNED);
newuip = newcred->cr_ruidinfo;
@@ -1004,6 +1076,8 @@ void
racct_move(struct racct *dest, struct racct *src)
{
+ ASSERT_RACCT_ENABLED();
+
mtx_lock(&racct_lock);
racct_add_racct(dest, src);
@@ -1020,6 +1094,7 @@ racct_proc_throttle(struct proc *p)
int cpuid;
#endif
+ ASSERT_RACCT_ENABLED();
PROC_LOCK_ASSERT(p, MA_OWNED);
/*
@@ -1065,6 +1140,9 @@ racct_proc_throttle(struct proc *p)
static void
racct_proc_wakeup(struct proc *p)
{
+
+ ASSERT_RACCT_ENABLED();
+
PROC_LOCK_ASSERT(p, MA_OWNED);
if (p->p_throttled) {
@@ -1079,6 +1157,8 @@ racct_decay_resource(struct racct *racct, void * res, void* dummy)
int resource;
int64_t r_old, r_new;
+ ASSERT_RACCT_ENABLED();
+
resource = *(int *)res;
r_old = racct->r_resources[resource];
@@ -1095,6 +1175,9 @@ racct_decay_resource(struct racct *racct, void * res, void* dummy)
static void
racct_decay(int resource)
{
+
+ ASSERT_RACCT_ENABLED();
+
ui_racct_foreach(racct_decay_resource, &resource, NULL);
loginclass_racct_foreach(racct_decay_resource, &resource, NULL);
prison_racct_foreach(racct_decay_resource, &resource, NULL);
@@ -1109,6 +1192,8 @@ racctd(void)
uint64_t runtime;
uint64_t pct, pct_estimate;
+ ASSERT_RACCT_ENABLED();
+
for (;;) {
racct_decay(RACCT_PCTCPU);
@@ -1188,11 +1273,22 @@ static struct kproc_desc racctd_kp = {
racctd,
NULL
};
-SYSINIT(racctd, SI_SUB_RACCTD, SI_ORDER_FIRST, kproc_start, &racctd_kp);
+
+static void
+racctd_init(void)
+{
+ if (!racct_enable)
+ return;
+
+ kproc_start(&racctd_kp);
+}
+SYSINIT(racctd, SI_SUB_RACCTD, SI_ORDER_FIRST, racctd_init, NULL);
static void
racct_init(void)
{
+ if (!racct_enable)
+ return;
racct_zone = uma_zcreate("racct", sizeof(struct racct),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
diff --git a/sys/kern/kern_rctl.c b/sys/kern/kern_rctl.c
index 934327a..c43b83d 100644
--- a/sys/kern/kern_rctl.c
+++ b/sys/kern/kern_rctl.c
@@ -225,6 +225,7 @@ rctl_available_resource(const struct proc *p, const struct rctl_rule *rule)
int64_t available = INT64_MAX;
struct ucred *cred = p->p_ucred;
+ ASSERT_RACCT_ENABLED();
rw_assert(&rctl_lock, RA_LOCKED);
resource = rule->rr_resource;
@@ -264,6 +265,8 @@ rctl_would_exceed(const struct proc *p, const struct rctl_rule *rule,
{
int64_t available;
+ ASSERT_RACCT_ENABLED();
+
rw_assert(&rctl_lock, RA_LOCKED);
available = rctl_available_resource(p, rule);
@@ -283,6 +286,8 @@ rctl_pcpu_available(const struct proc *p) {
struct rctl_rule_link *link;
int64_t available, minavailable, limit;
+ ASSERT_RACCT_ENABLED();
+
minavailable = INT64_MAX;
limit = 0;
@@ -334,6 +339,8 @@ rctl_enforce(struct proc *p, int resource, uint64_t amount)
static int curtime = 0;
static struct timeval lasttime;
+ ASSERT_RACCT_ENABLED();
+
rw_rlock(&rctl_lock);
/*
@@ -457,6 +464,8 @@ rctl_get_limit(struct proc *p, int resource)
struct rctl_rule_link *link;
uint64_t amount = UINT64_MAX;
+ ASSERT_RACCT_ENABLED();
+
rw_rlock(&rctl_lock);
/*
@@ -487,6 +496,8 @@ rctl_get_available(struct proc *p, int resource)
minavailable = INT64_MAX;
+ ASSERT_RACCT_ENABLED();
+
rw_rlock(&rctl_lock);
/*
@@ -521,6 +532,8 @@ static int
rctl_rule_matches(const struct rctl_rule *rule, const struct rctl_rule *filter)
{
+ ASSERT_RACCT_ENABLED();
+
if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_UNDEFINED) {
if (rule->rr_subject_type != filter->rr_subject_type)
return (0);
@@ -635,6 +648,7 @@ rctl_racct_add_rule(struct racct *racct, struct rctl_rule *rule)
{
struct rctl_rule_link *link;
+ ASSERT_RACCT_ENABLED();
KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
rctl_rule_acquire(rule);
@@ -652,6 +666,7 @@ rctl_racct_add_rule_locked(struct racct *racct, struct rctl_rule *rule)
{
struct rctl_rule_link *link;
+ ASSERT_RACCT_ENABLED();
KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
rw_assert(&rctl_lock, RA_WLOCKED);
@@ -678,6 +693,7 @@ rctl_racct_remove_rules(struct racct *racct,
int removed = 0;
struct rctl_rule_link *link, *linktmp;
+ ASSERT_RACCT_ENABLED();
rw_assert(&rctl_lock, RA_WLOCKED);
LIST_FOREACH_SAFE(link, &racct->r_rule_links, rrl_next, linktmp) {
@@ -696,6 +712,8 @@ static void
rctl_rule_acquire_subject(struct rctl_rule *rule)
{
+ ASSERT_RACCT_ENABLED();
+
switch (rule->rr_subject_type) {
case RCTL_SUBJECT_TYPE_UNDEFINED:
case RCTL_SUBJECT_TYPE_PROCESS:
@@ -722,6 +740,8 @@ static void
rctl_rule_release_subject(struct rctl_rule *rule)
{
+ ASSERT_RACCT_ENABLED();
+
switch (rule->rr_subject_type) {
case RCTL_SUBJECT_TYPE_UNDEFINED:
case RCTL_SUBJECT_TYPE_PROCESS:
@@ -749,6 +769,8 @@ rctl_rule_alloc(int flags)
{
struct rctl_rule *rule;
+ ASSERT_RACCT_ENABLED();
+
rule = uma_zalloc(rctl_rule_zone, flags);
if (rule == NULL)
return (NULL);
@@ -771,6 +793,8 @@ rctl_rule_duplicate(const struct rctl_rule *rule, int flags)
{
struct rctl_rule *copy;
+ ASSERT_RACCT_ENABLED();
+
copy = uma_zalloc(rctl_rule_zone, flags);
if (copy == NULL)
return (NULL);
@@ -793,6 +817,7 @@ void
rctl_rule_acquire(struct rctl_rule *rule)
{
+ ASSERT_RACCT_ENABLED();
KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0"));
refcount_acquire(&rule->rr_refcount);
@@ -805,6 +830,7 @@ rctl_rule_free(void *context, int pending)
rule = (struct rctl_rule *)context;
+ ASSERT_RACCT_ENABLED();
KASSERT(rule->rr_refcount == 0, ("rule->rr_refcount != 0"));
/*
@@ -819,6 +845,7 @@ void
rctl_rule_release(struct rctl_rule *rule)
{
+ ASSERT_RACCT_ENABLED();
KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0"));
if (refcount_release(&rule->rr_refcount)) {
@@ -838,6 +865,8 @@ static int
rctl_rule_fully_specified(const struct rctl_rule *rule)
{
+ ASSERT_RACCT_ENABLED();
+
switch (rule->rr_subject_type) {
case RCTL_SUBJECT_TYPE_UNDEFINED:
return (0);
@@ -882,6 +911,8 @@ rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep)
struct rctl_rule *rule;
id_t id;
+ ASSERT_RACCT_ENABLED();
+
rule = rctl_rule_alloc(M_WAITOK);
subjectstr = strsep(&rulestr, ":");
@@ -1008,6 +1039,7 @@ rctl_rule_add(struct rctl_rule *rule)
struct rctl_rule *rule2;
int match;
+ ASSERT_RACCT_ENABLED();
KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
/*
@@ -1118,6 +1150,8 @@ rctl_rule_remove_callback(struct racct *racct, void *arg2, void *arg3)
struct rctl_rule *filter = (struct rctl_rule *)arg2;
int found = 0;
+ ASSERT_RACCT_ENABLED();
+
rw_wlock(&rctl_lock);
found += rctl_racct_remove_rules(racct, filter);
rw_wunlock(&rctl_lock);
@@ -1134,6 +1168,8 @@ rctl_rule_remove(struct rctl_rule *filter)
int found = 0;
struct proc *p;
+ ASSERT_RACCT_ENABLED();
+
if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_PROCESS &&
filter->rr_subject.rs_proc != NULL) {
p = filter->rr_subject.rs_proc;
@@ -1172,6 +1208,8 @@ rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule)
{
int64_t amount;
+ ASSERT_RACCT_ENABLED();
+
sbuf_printf(sb, "%s:", rctl_subject_type_name(rule->rr_subject_type));
switch (rule->rr_subject_type) {
@@ -1231,6 +1269,8 @@ rctl_read_inbuf(char **inputstr, const char *inbufp, size_t inbuflen)
int error;
char *str;
+ ASSERT_RACCT_ENABLED();
+
if (inbuflen <= 0)
return (EINVAL);
if (inbuflen > RCTL_MAX_INBUFLEN)
@@ -1256,6 +1296,8 @@ rctl_write_outbuf(struct sbuf *outputsbuf, char *outbufp, size_t outbuflen)
{
int error;
+ ASSERT_RACCT_ENABLED();
+
if (outputsbuf == NULL)
return (0);
@@ -1277,6 +1319,8 @@ rctl_racct_to_sbuf(struct racct *racct, int sloppy)
int64_t amount;
struct sbuf *sb;
+ ASSERT_RACCT_ENABLED();
+
sb = sbuf_new_auto();
for (i = 0; i <= RACCT_MAX; i++) {
if (sloppy == 0 && RACCT_IS_SLOPPY(i))
@@ -1302,6 +1346,9 @@ sys_rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
struct loginclass *lc;
struct prison_racct *prr;
+ if (!racct_enable)
+ return (ENOSYS);
+
error = priv_check(td, PRIV_RCTL_GET_RACCT);
if (error != 0)
return (error);
@@ -1372,6 +1419,8 @@ rctl_get_rules_callback(struct racct *racct, void *arg2, void *arg3)
struct rctl_rule_link *link;
struct sbuf *sb = (struct sbuf *)arg3;
+ ASSERT_RACCT_ENABLED();
+
rw_rlock(&rctl_lock);
LIST_FOREACH(link, &racct->r_rule_links, rrl_next) {
if (!rctl_rule_matches(link->rrl_rule, filter))
@@ -1393,6 +1442,9 @@ sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap)
struct rctl_rule_link *link;
struct proc *p;
+ if (!racct_enable)
+ return (ENOSYS);
+
error = priv_check(td, PRIV_RCTL_GET_RULES);
if (error != 0)
return (error);
@@ -1467,6 +1519,9 @@ sys_rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap)
struct rctl_rule *filter;
struct rctl_rule_link *link;
+ if (!racct_enable)
+ return (ENOSYS);
+
error = priv_check(td, PRIV_RCTL_GET_LIMITS);
if (error != 0)
return (error);
@@ -1538,6 +1593,9 @@ sys_rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap)
struct rctl_rule *rule;
char *inputstr;
+ if (!racct_enable)
+ return (ENOSYS);
+
error = priv_check(td, PRIV_RCTL_ADD_RULE);
if (error != 0)
return (error);
@@ -1580,6 +1638,9 @@ sys_rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap)
struct rctl_rule *filter;
char *inputstr;
+ if (!racct_enable)
+ return (ENOSYS);
+
error = priv_check(td, PRIV_RCTL_REMOVE_RULE);
if (error != 0)
return (error);
@@ -1616,6 +1677,8 @@ rctl_proc_ucred_changed(struct proc *p, struct ucred *newcred)
struct prison_racct *newprr;
LIST_HEAD(, rctl_rule_link) newrules;
+ ASSERT_RACCT_ENABLED();
+
newuip = newcred->cr_ruidinfo;
newlc = newcred->cr_loginclass;
newprr = newcred->cr_prison->pr_prison_racct;
@@ -1756,6 +1819,7 @@ rctl_proc_fork(struct proc *parent, struct proc *child)
LIST_INIT(&child->p_racct->r_rule_links);
+ ASSERT_RACCT_ENABLED();
KASSERT(parent->p_racct != NULL, ("process without racct; p = %p", parent));
rw_wlock(&rctl_lock);
@@ -1809,6 +1873,8 @@ rctl_racct_release(struct racct *racct)
{
struct rctl_rule_link *link;
+ ASSERT_RACCT_ENABLED();
+
rw_wlock(&rctl_lock);
while (!LIST_EMPTY(&racct->r_rule_links)) {
link = LIST_FIRST(&racct->r_rule_links);
@@ -1823,6 +1889,9 @@ static void
rctl_init(void)
{
+ if (!racct_enable)
+ return;
+
rctl_rule_link_zone = uma_zcreate("rctl_rule_link",
sizeof(struct rctl_rule_link), NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index 56b598f..dac49cd 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -745,7 +745,12 @@ kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which,
if (newlim != NULL)
lim_free(oldlim);
- if (which == RLIMIT_STACK) {
+ if (which == RLIMIT_STACK &&
+ /*
+ * Skip calls from exec_new_vmspace(), done when stack is
+ * not mapped yet.
+ */
+ (td != curthread || (p->p_flag & P_INEXEC) == 0)) {
/*
* Stack is allocated to the max at exec time with only
* "rlim_cur" bytes accessible. If stack limit is going
diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c
index e547c5f..5125480 100644
--- a/sys/kern/kern_shutdown.c
+++ b/sys/kern/kern_shutdown.c
@@ -154,7 +154,6 @@ static void poweroff_wait(void *, int);
static void shutdown_halt(void *junk, int howto);
static void shutdown_panic(void *junk, int howto);
static void shutdown_reset(void *junk, int howto);
-static void vpanic(const char *fmt, va_list ap) __dead2;
/* register various local shutdown events */
static void
@@ -676,7 +675,7 @@ panic(const char *fmt, ...)
vpanic(fmt, ap);
}
-static void
+void
vpanic(const char *fmt, va_list ap)
{
#ifdef SMP
@@ -701,10 +700,8 @@ vpanic(const char *fmt, va_list ap)
}
/*
- * We set stop_scheduler here and not in the block above,
- * because we want to ensure that if panic has been called and
- * stop_scheduler_on_panic is true, then stop_scheduler will
- * always be set. Even if panic has been entered from kdb.
+ * Ensure that the scheduler is stopped while panicking, even if panic
+ * has been entered from kdb.
*/
td->td_stopsched = 1;
#endif
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index 9501ba2..a238a09 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -66,12 +66,6 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
-#ifdef XEN
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
-#endif
-
#define KTDSTATE(td) \
(((td)->td_inhibitors & TDI_SLEEPING) != 0 ? "sleep" : \
((td)->td_inhibitors & TDI_SUSPENDED) != 0 ? "suspended" : \
@@ -108,17 +102,6 @@ static void loadav(void *arg);
SDT_PROVIDER_DECLARE(sched);
SDT_PROBE_DEFINE(sched, , , preempt);
-/*
- * These probes reference Solaris features that are not implemented in FreeBSD.
- * Create the probes anyway for compatibility with existing D scripts; they'll
- * just never fire.
- */
-SDT_PROBE_DEFINE(sched, , , cpucaps__sleep);
-SDT_PROBE_DEFINE(sched, , , cpucaps__wakeup);
-SDT_PROBE_DEFINE(sched, , , schedctl__nopreempt);
-SDT_PROBE_DEFINE(sched, , , schedctl__preempt);
-SDT_PROBE_DEFINE(sched, , , schedctl__yield);
-
static void
sleepinit(void *unused)
{
@@ -486,9 +469,6 @@ mi_switch(int flags, struct thread *newtd)
"lockname:\"%s\"", td->td_lockname);
#endif
SDT_PROBE0(sched, , , preempt);
-#ifdef XEN
- PT_UPDATES_FLUSH();
-#endif
sched_switch(td, newtd, flags);
KTR_STATE1(KTR_SCHED, "thread", sched_tdname(td), "running",
"prio:%d", td->td_priority);
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
index 280bc0b..6911bb97 100644
--- a/sys/kern/kern_thr.c
+++ b/sys/kern/kern_thr.c
@@ -187,11 +187,13 @@ create_thread(struct thread *td, mcontext_t *ctx,
}
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- error = racct_add(p, RACCT_NTHR, 1);
- PROC_UNLOCK(td->td_proc);
- if (error != 0)
- return (EPROCLIM);
+ if (racct_enable) {
+ PROC_LOCK(p);
+ error = racct_add(p, RACCT_NTHR, 1);
+ PROC_UNLOCK(p);
+ if (error != 0)
+ return (EPROCLIM);
+ }
#endif
/* Initialize our td */
@@ -250,9 +252,9 @@ create_thread(struct thread *td, mcontext_t *ctx,
}
}
- PROC_LOCK(td->td_proc);
- td->td_proc->p_flag |= P_HADTHREADS;
- thread_link(newtd, p);
+ PROC_LOCK(p);
+ p->p_flag |= P_HADTHREADS;
+ thread_link(newtd, p);
bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
thread_lock(td);
/* let the scheduler know about these things. */
@@ -280,9 +282,11 @@ create_thread(struct thread *td, mcontext_t *ctx,
fail:
#ifdef RACCT
- PROC_LOCK(p);
- racct_sub(p, RACCT_NTHR, 1);
- PROC_UNLOCK(p);
+ if (racct_enable) {
+ PROC_LOCK(p);
+ racct_sub(p, RACCT_NTHR, 1);
+ PROC_UNLOCK(p);
+ }
#endif
return (error);
}
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index dd11e5c..0a93dbd 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -209,6 +209,7 @@ thread_init(void *mem, int size, int flags)
td->td_sched = (struct td_sched *)&td[1];
umtx_thread_init(td);
td->td_kstack = 0;
+ td->td_sel = NULL;
return (0);
}
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 45892dc..01da596 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -591,6 +591,8 @@ callout_cc_add(struct callout *c, struct callout_cpu *cc,
c->c_iflags |= CALLOUT_PENDING;
c->c_iflags &= ~CALLOUT_PROCESSED;
c->c_flags |= CALLOUT_ACTIVE;
+ if (flags & C_DIRECT_EXEC)
+ c->c_iflags |= CALLOUT_DIRECT;
c->c_func = func;
c->c_time = sbt;
c->c_precision = precision;
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 65c8276..26be035 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -66,7 +66,7 @@ __FBSDID("$FreeBSD$");
#include <sys/link_elf.h>
#ifdef DDB_CTF
-#include <net/zlib.h>
+#include <sys/zlib.h>
#endif
#include "linker_if.h"
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 5c107fe..021381d 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$");
#include <sys/link_elf.h>
#ifdef DDB_CTF
-#include <net/zlib.h>
+#include <sys/zlib.h>
#endif
#include "linker_if.h"
diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c
index 3e39d55..59bd387 100644
--- a/sys/kern/sched_4bsd.c
+++ b/sys/kern/sched_4bsd.c
@@ -1585,7 +1585,7 @@ sched_pctcpu(struct thread *td)
return (ts->ts_pctcpu);
}
-#ifdef RACCT
+#ifdef RACCT
/*
* Calculates the contribution to the thread cpu usage for the latest
* (unfinished) second.
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index fdb92e3..0dde5a5 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -2113,6 +2113,16 @@ device_probe_child(device_t dev, device_t child)
}
/*
+ * Probes that return BUS_PROBE_NOWILDCARD or lower
+ * only match on devices whose driver was explicitly
+ * specified.
+ */
+ if (result <= BUS_PROBE_NOWILDCARD &&
+ !(child->flags & DF_FIXEDCLASS)) {
+ result = ENXIO;
+ }
+
+ /*
* The driver returned an error so it
* certainly doesn't match.
*/
@@ -2127,14 +2137,6 @@ device_probe_child(device_t dev, device_t child)
* of pri for the first match.
*/
if (best == NULL || result > pri) {
- /*
- * Probes that return BUS_PROBE_NOWILDCARD
- * or lower only match on devices whose
- * driver was explicitly specified.
- */
- if (result <= BUS_PROBE_NOWILDCARD &&
- !(child->flags & DF_FIXEDCLASS))
- continue;
best = dl;
pri = result;
continue;
diff --git a/sys/kern/subr_dnvlist.c b/sys/kern/subr_dnvlist.c
index fe17684..9058520 100644
--- a/sys/kern/subr_dnvlist.c
+++ b/sys/kern/subr_dnvlist.c
@@ -89,89 +89,6 @@ dnvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep,
return (value);
}
-#ifndef _KERNEL
-#define DNVLIST_GETF(ftype, type) \
-ftype \
-dnvlist_getf_##type(const nvlist_t *nvl, ftype defval, \
- const char *namefmt, ...) \
-{ \
- va_list nameap; \
- ftype value; \
- \
- va_start(nameap, namefmt); \
- value = dnvlist_getv_##type(nvl, defval, namefmt, nameap); \
- va_end(nameap); \
- \
- return (value); \
-}
-
-DNVLIST_GETF(bool, bool)
-DNVLIST_GETF(uint64_t, number)
-DNVLIST_GETF(const char *, string)
-DNVLIST_GETF(const nvlist_t *, nvlist)
-DNVLIST_GETF(int, descriptor)
-
-#undef DNVLIST_GETF
-
-const void *
-dnvlist_getf_binary(const nvlist_t *nvl, size_t *sizep, const void *defval,
- size_t defsize, const char *namefmt, ...)
-{
- va_list nameap;
- const void *value;
-
- va_start(nameap, namefmt);
- value = dnvlist_getv_binary(nvl, sizep, defval, defsize, namefmt,
- nameap);
- va_end(nameap);
-
- return (value);
-}
-
-#define DNVLIST_GETV(ftype, type) \
-ftype \
-dnvlist_getv_##type(const nvlist_t *nvl, ftype defval, \
- const char *namefmt, va_list nameap) \
-{ \
- char *name; \
- ftype value; \
- \
- vasprintf(&name, namefmt, nameap); \
- if (name == NULL) \
- return (defval); \
- value = dnvlist_get_##type(nvl, name, defval); \
- free(name); \
- return (value); \
-}
-
-DNVLIST_GETV(bool, bool)
-DNVLIST_GETV(uint64_t, number)
-DNVLIST_GETV(const char *, string)
-DNVLIST_GETV(const nvlist_t *, nvlist)
-DNVLIST_GETV(int, descriptor)
-
-#undef DNVLIST_GETV
-
-const void *
-dnvlist_getv_binary(const nvlist_t *nvl, size_t *sizep, const void *defval,
- size_t defsize, const char *namefmt, va_list nameap)
-{
- char *name;
- const void *value;
-
- nv_vasprintf(&name, namefmt, nameap);
- if (name != NULL) {
- value = dnvlist_get_binary(nvl, name, sizep, defval, defsize);
- nv_free(name);
- } else {
- if (sizep != NULL)
- *sizep = defsize;
- value = defval;
- }
- return (value);
-}
-#endif
-
#define DNVLIST_TAKE(ftype, type) \
ftype \
dnvlist_take_##type(nvlist_t *nvl, const char *name, ftype defval) \
@@ -209,86 +126,3 @@ dnvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep,
return (value);
}
-#ifndef _KERNEL
-#define DNVLIST_TAKEF(ftype, type) \
-ftype \
-dnvlist_takef_##type(nvlist_t *nvl, ftype defval, \
- const char *namefmt, ...) \
-{ \
- va_list nameap; \
- ftype value; \
- \
- va_start(nameap, namefmt); \
- value = dnvlist_takev_##type(nvl, defval, namefmt, nameap); \
- va_end(nameap); \
- \
- return (value); \
-}
-
-DNVLIST_TAKEF(bool, bool)
-DNVLIST_TAKEF(uint64_t, number)
-DNVLIST_TAKEF(char *, string)
-DNVLIST_TAKEF(nvlist_t *, nvlist)
-DNVLIST_TAKEF(int, descriptor)
-
-#undef DNVLIST_TAKEF
-
-void *
-dnvlist_takef_binary(nvlist_t *nvl, size_t *sizep, void *defval,
- size_t defsize, const char *namefmt, ...)
-{
- va_list nameap;
- void *value;
-
- va_start(nameap, namefmt);
- value = dnvlist_takev_binary(nvl, sizep, defval, defsize, namefmt,
- nameap);
- va_end(nameap);
-
- return (value);
-}
-
-#define DNVLIST_TAKEV(ftype, type) \
-ftype \
-dnvlist_takev_##type(nvlist_t *nvl, ftype defval, const char *namefmt, \
- va_list nameap) \
-{ \
- char *name; \
- ftype value; \
- \
- vasprintf(&name, namefmt, nameap); \
- if (name == NULL) \
- return (defval); \
- value = dnvlist_take_##type(nvl, name, defval); \
- free(name); \
- return (value); \
-}
-
-DNVLIST_TAKEV(bool, bool)
-DNVLIST_TAKEV(uint64_t, number)
-DNVLIST_TAKEV(char *, string)
-DNVLIST_TAKEV(nvlist_t *, nvlist)
-DNVLIST_TAKEV(int, descriptor)
-
-#undef DNVLIST_TAKEV
-
-void *
-dnvlist_takev_binary(nvlist_t *nvl, size_t *sizep, void *defval,
- size_t defsize, const char *namefmt, va_list nameap)
-{
- char *name;
- void *value;
-
- nv_vasprintf(&name, namefmt, nameap);
- if (name != NULL) {
- value = dnvlist_take_binary(nvl, name, sizep, defval, defsize);
- nv_free(name);
- } else {
- if (sizep != NULL)
- *sizep = defsize;
- value = defval;
- }
-
- return (value);
-}
-#endif
diff --git a/sys/kern/subr_nvlist.c b/sys/kern/subr_nvlist.c
index f352c62..40e49ff 100644
--- a/sys/kern/subr_nvlist.c
+++ b/sys/kern/subr_nvlist.c
@@ -88,7 +88,7 @@ __FBSDID("$FreeBSD$");
#endif
#define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN)
-#define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE)
+#define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE)
#define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
#define NVLIST_MAGIC 0x6e766c /* "nvl" */
@@ -129,6 +129,8 @@ nvlist_create(int flags)
PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
nvl = nv_malloc(sizeof(*nvl));
+ if (nvl == NULL)
+ return (NULL);
nvl->nvl_error = 0;
nvl->nvl_flags = flags;
nvl->nvl_parent = NULL;
@@ -142,12 +144,11 @@ void
nvlist_destroy(nvlist_t *nvl)
{
nvpair_t *nvp;
- int serrno;
if (nvl == NULL)
return;
- SAVE_ERRNO(serrno);
+ ERRNO_SAVE();
NVLIST_ASSERT(nvl);
@@ -158,7 +159,7 @@ nvlist_destroy(nvlist_t *nvl)
nvl->nvl_magic = 0;
nv_free(nvl);
- RESTORE_ERRNO(serrno);
+ ERRNO_RESTORE();
}
void
@@ -231,6 +232,17 @@ nvlist_empty(const nvlist_t *nvl)
return (nvlist_first_nvpair(nvl) == NULL);
}
+int
+nvlist_flags(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ PJDLOG_ASSERT((nvl->nvl_flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
+
+ return (nvl->nvl_flags);
+}
+
static void
nvlist_report_missing(int type, const char *name)
{
@@ -264,7 +276,7 @@ nvlist_find(const nvlist_t *nvl, int type, const char *name)
}
if (nvp == NULL)
- RESTORE_ERRNO(ENOENT);
+ ERRNO_SET(ENOENT);
return (nvp);
}
@@ -281,37 +293,6 @@ nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
return (nvlist_find(nvl, type, name) != NULL);
}
-#ifndef _KERNEL
-bool
-nvlist_existsf_type(const nvlist_t *nvl, int type, const char *namefmt, ...)
-{
- va_list nameap;
- bool ret;
-
- va_start(nameap, namefmt);
- ret = nvlist_existsv_type(nvl, type, namefmt, nameap);
- va_end(nameap);
-
- return (ret);
-}
-
-bool
-nvlist_existsv_type(const nvlist_t *nvl, int type, const char *namefmt,
- va_list nameap)
-{
- char *name;
- bool exists;
-
- nv_vasprintf(&name, namefmt, nameap);
- if (name == NULL)
- return (false);
-
- exists = nvlist_exists_type(nvl, name, type);
- nv_free(name);
- return (exists);
-}
-#endif
-
void
nvlist_free_type(nvlist_t *nvl, const char *name, int type)
{
@@ -329,30 +310,6 @@ nvlist_free_type(nvlist_t *nvl, const char *name, int type)
nvlist_report_missing(type, name);
}
-#ifndef _KERNEL
-void
-nvlist_freef_type(nvlist_t *nvl, int type, const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_freev_type(nvl, type, namefmt, nameap);
- va_end(nameap);
-}
-
-void
-nvlist_freev_type(nvlist_t *nvl, int type, const char *namefmt, va_list nameap)
-{
- char *name;
-
- nv_vasprintf(&name, namefmt, nameap);
- if (name == NULL)
- nvlist_report_missing(type, "<unknown>");
- nvlist_free_type(nvl, name, type);
- nv_free(name);
-}
-#endif
-
nvlist_t *
nvlist_clone(const nvlist_t *nvl)
{
@@ -362,7 +319,7 @@ nvlist_clone(const nvlist_t *nvl)
NVLIST_ASSERT(nvl);
if (nvl->nvl_error != 0) {
- RESTORE_ERRNO(nvl->nvl_error);
+ ERRNO_SET(nvl->nvl_error);
return (NULL);
}
@@ -533,27 +490,30 @@ out:
#ifndef _KERNEL
static int *
-nvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level)
+nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
{
- const nvpair_t *nvp;
+ nvpair_t *nvp;
+ const char *name;
+ int type;
NVLIST_ASSERT(nvl);
PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(level < 3);
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
- switch (nvpair_type(nvp)) {
- case NV_TYPE_DESCRIPTOR:
- *descs = nvpair_get_descriptor(nvp);
- descs++;
- break;
- case NV_TYPE_NVLIST:
- descs = nvlist_xdescriptors(nvpair_get_nvlist(nvp),
- descs, level + 1);
- break;
+ nvp = NULL;
+ do {
+ while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
+ switch (type) {
+ case NV_TYPE_DESCRIPTOR:
+ *descs = nvpair_get_descriptor(nvp);
+ descs++;
+ break;
+ case NV_TYPE_NVLIST:
+ nvl = nvpair_get_nvlist(nvp);
+ nvp = NULL;
+ break;
+ }
}
- }
+ } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL);
return (descs);
}
@@ -571,7 +531,7 @@ nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
if (fds == NULL)
return (NULL);
if (nitems > 0)
- nvlist_xdescriptors(nvl, fds, 0);
+ nvlist_xdescriptors(nvl, fds);
fds[nitems] = -1;
if (nitemsp != NULL)
*nitemsp = nitems;
@@ -579,30 +539,33 @@ nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
}
#endif
-static size_t
-nvlist_xndescriptors(const nvlist_t *nvl, int level)
+size_t
+nvlist_ndescriptors(const nvlist_t *nvl)
{
#ifndef _KERNEL
- const nvpair_t *nvp;
+ nvpair_t *nvp;
+ const char *name;
size_t ndescs;
+ int type;
NVLIST_ASSERT(nvl);
PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(level < 3);
ndescs = 0;
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
- switch (nvpair_type(nvp)) {
- case NV_TYPE_DESCRIPTOR:
- ndescs++;
- break;
- case NV_TYPE_NVLIST:
- ndescs += nvlist_xndescriptors(nvpair_get_nvlist(nvp),
- level + 1);
- break;
+ nvp = NULL;
+ do {
+ while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
+ switch (type) {
+ case NV_TYPE_DESCRIPTOR:
+ ndescs++;
+ break;
+ case NV_TYPE_NVLIST:
+ nvl = nvpair_get_nvlist(nvp);
+ nvp = NULL;
+ break;
+ }
}
- }
+ } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL);
return (ndescs);
#else
@@ -610,13 +573,6 @@ nvlist_xndescriptors(const nvlist_t *nvl, int level)
#endif
}
-size_t
-nvlist_ndescriptors(const nvlist_t *nvl)
-{
-
- return (nvlist_xndescriptors(nvl, 0));
-}
-
static unsigned char *
nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
{
@@ -640,7 +596,7 @@ nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
return (ptr);
}
-void *
+static void *
nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
{
unsigned char *buf, *ptr;
@@ -652,7 +608,7 @@ nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
NVLIST_ASSERT(nvl);
if (nvl->nvl_error != 0) {
- RESTORE_ERRNO(nvl->nvl_error);
+ ERRNO_SET(nvl->nvl_error);
return (NULL);
}
@@ -742,12 +698,12 @@ nvlist_pack(const nvlist_t *nvl, size_t *sizep)
NVLIST_ASSERT(nvl);
if (nvl->nvl_error != 0) {
- RESTORE_ERRNO(nvl->nvl_error);
+ ERRNO_SET(nvl->nvl_error);
return (NULL);
}
if (nvlist_ndescriptors(nvl) > 0) {
- RESTORE_ERRNO(EOPNOTSUPP);
+ ERRNO_SET(EOPNOTSUPP);
return (NULL);
}
@@ -759,11 +715,11 @@ nvlist_check_header(struct nvlist_header *nvlhdrp)
{
if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (false);
}
if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (false);
}
#if BYTE_ORDER == BIG_ENDIAN
@@ -815,12 +771,13 @@ nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
return (ptr);
failed:
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
-nvlist_t *
-nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
+static nvlist_t *
+nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
+ int flags)
{
const unsigned char *ptr;
nvlist_t *nvl, *retnvl, *tmpnvl;
@@ -828,6 +785,8 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
size_t left;
bool isbe;
+ PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
+
left = size;
ptr = buf;
@@ -839,6 +798,10 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
if (ptr == NULL)
goto failed;
+ if (nvl->nvl_flags != flags) {
+ ERRNO_SET(EILSEQ);
+ goto failed;
+ }
while (left > 0) {
ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
@@ -895,10 +858,10 @@ failed:
}
nvlist_t *
-nvlist_unpack(const void *buf, size_t size)
+nvlist_unpack(const void *buf, size_t size, int flags)
{
- return (nvlist_xunpack(buf, size, NULL, 0));
+ return (nvlist_xunpack(buf, size, NULL, 0, flags));
}
#ifndef _KERNEL
@@ -909,10 +872,10 @@ nvlist_send(int sock, const nvlist_t *nvl)
int *fds;
void *data;
int64_t fdidx;
- int serrno, ret;
+ int ret;
if (nvlist_error(nvl) != 0) {
- errno = nvlist_error(nvl);
+ ERRNO_SET(nvlist_error(nvl));
return (-1);
}
@@ -938,21 +901,21 @@ nvlist_send(int sock, const nvlist_t *nvl)
ret = 0;
out:
- serrno = errno;
+ ERRNO_SAVE();
free(fds);
free(data);
- errno = serrno;
+ ERRNO_RESTORE();
return (ret);
}
nvlist_t *
-nvlist_recv(int sock)
+nvlist_recv(int sock, int flags)
{
struct nvlist_header nvlhdr;
nvlist_t *nvl, *ret;
unsigned char *buf;
size_t nfds, size, i;
- int serrno, *fds;
+ int *fds;
if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
return (NULL);
@@ -963,7 +926,7 @@ nvlist_recv(int sock)
nfds = (size_t)nvlhdr.nvlh_descriptors;
size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
- buf = malloc(size);
+ buf = nv_malloc(size);
if (buf == NULL)
return (NULL);
@@ -976,32 +939,34 @@ nvlist_recv(int sock)
goto out;
if (nfds > 0) {
- fds = malloc(nfds * sizeof(fds[0]));
+ fds = nv_malloc(nfds * sizeof(fds[0]));
if (fds == NULL)
goto out;
if (fd_recv(sock, fds, nfds) == -1)
goto out;
}
- nvl = nvlist_xunpack(buf, size, fds, nfds);
+ nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
if (nvl == NULL) {
+ ERRNO_SAVE();
for (i = 0; i < nfds; i++)
close(fds[i]);
+ ERRNO_RESTORE();
goto out;
}
ret = nvl;
out:
- serrno = errno;
+ ERRNO_SAVE();
free(buf);
free(fds);
- errno = serrno;
+ ERRNO_RESTORE();
return (ret);
}
nvlist_t *
-nvlist_xfer(int sock, nvlist_t *nvl)
+nvlist_xfer(int sock, nvlist_t *nvl, int flags)
{
if (nvlist_send(sock, nvl) < 0) {
@@ -1009,7 +974,7 @@ nvlist_xfer(int sock, nvlist_t *nvl)
return (NULL);
}
nvlist_destroy(nvl);
- return (nvlist_recv(sock));
+ return (nvlist_recv(sock, flags));
}
#endif
@@ -1100,86 +1065,6 @@ NVLIST_EXISTS(binary, BINARY)
#undef NVLIST_EXISTS
-#ifndef _KERNEL
-bool
-nvlist_existsf(const nvlist_t *nvl, const char *namefmt, ...)
-{
- va_list nameap;
- bool ret;
-
- va_start(nameap, namefmt);
- ret = nvlist_existsv(nvl, namefmt, nameap);
- va_end(nameap);
- return (ret);
-}
-
-#define NVLIST_EXISTSF(type) \
-bool \
-nvlist_existsf_##type(const nvlist_t *nvl, const char *namefmt, ...) \
-{ \
- va_list nameap; \
- bool ret; \
- \
- va_start(nameap, namefmt); \
- ret = nvlist_existsv_##type(nvl, namefmt, nameap); \
- va_end(nameap); \
- return (ret); \
-}
-
-NVLIST_EXISTSF(null)
-NVLIST_EXISTSF(bool)
-NVLIST_EXISTSF(number)
-NVLIST_EXISTSF(string)
-NVLIST_EXISTSF(nvlist)
-#ifndef _KERNEL
-NVLIST_EXISTSF(descriptor)
-#endif
-NVLIST_EXISTSF(binary)
-
-#undef NVLIST_EXISTSF
-
-bool
-nvlist_existsv(const nvlist_t *nvl, const char *namefmt, va_list nameap)
-{
- char *name;
- bool exists;
-
- nv_vasprintf(&name, namefmt, nameap);
- if (name == NULL)
- return (false);
-
- exists = nvlist_exists(nvl, name);
- nv_free(name);
- return (exists);
-}
-
-#define NVLIST_EXISTSV(type) \
-bool \
-nvlist_existsv_##type(const nvlist_t *nvl, const char *namefmt, \
- va_list nameap) \
-{ \
- char *name; \
- bool exists; \
- \
- vasprintf(&name, namefmt, nameap); \
- if (name == NULL) \
- return (false); \
- exists = nvlist_exists_##type(nvl, name); \
- free(name); \
- return (exists); \
-}
-
-NVLIST_EXISTSV(null)
-NVLIST_EXISTSV(bool)
-NVLIST_EXISTSV(number)
-NVLIST_EXISTSV(string)
-NVLIST_EXISTSV(nvlist)
-NVLIST_EXISTSV(descriptor)
-NVLIST_EXISTSV(binary)
-
-#undef NVLIST_EXISTSV
-#endif
-
void
nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
{
@@ -1188,19 +1073,21 @@ nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
NVPAIR_ASSERT(nvp);
if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- if (nvlist_exists(nvl, nvpair_name(nvp))) {
- nvl->nvl_error = EEXIST;
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
+ if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
+ if (nvlist_exists(nvl, nvpair_name(nvp))) {
+ nvl->nvl_error = EEXIST;
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
}
newnvp = nvpair_clone(nvp);
if (newnvp == NULL) {
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
@@ -1208,34 +1095,6 @@ nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
}
void
-nvlist_add_null(nvlist_t *nvl, const char *name)
-{
-
- nvlist_addf_null(nvl, "%s", name);
-}
-
-void
-nvlist_add_bool(nvlist_t *nvl, const char *name, bool value)
-{
-
- nvlist_addf_bool(nvl, value, "%s", name);
-}
-
-void
-nvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value)
-{
-
- nvlist_addf_number(nvl, value, "%s", name);
-}
-
-void
-nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
-{
-
- nvlist_addf_string(nvl, value, "%s", name);
-}
-
-void
nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
{
va_list valueap;
@@ -1252,247 +1111,88 @@ nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
nvp = nvpair_create_stringv(name, valuefmt, valueap);
if (nvp == NULL) {
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
+ ERRNO_SET(nvl->nvl_error);
+ } else {
nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value)
-{
-
- nvlist_addf_nvlist(nvl, value, "%s", name);
-}
-
-#ifndef _KERNEL
-void
-nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value)
-{
-
- nvlist_addf_descriptor(nvl, value, "%s", name);
-}
-#endif
-
-void
-nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
- size_t size)
-{
-
- nvlist_addf_binary(nvl, value, size, "%s", name);
-}
-
-void
-nvlist_addf_null(nvlist_t *nvl, const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_addv_null(nvl, namefmt, nameap);
- va_end(nameap);
-}
-
-void
-nvlist_addf_bool(nvlist_t *nvl, bool value, const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_addv_bool(nvl, value, namefmt, nameap);
- va_end(nameap);
-}
-
-void
-nvlist_addf_number(nvlist_t *nvl, uint64_t value, const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_addv_number(nvl, value, namefmt, nameap);
- va_end(nameap);
-}
-
-void
-nvlist_addf_string(nvlist_t *nvl, const char *value, const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_addv_string(nvl, value, namefmt, nameap);
- va_end(nameap);
-}
-
-void
-nvlist_addf_nvlist(nvlist_t *nvl, const nvlist_t *value, const char *namefmt,
- ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_addv_nvlist(nvl, value, namefmt, nameap);
- va_end(nameap);
-}
-
-#ifndef _KERNEL
-void
-nvlist_addf_descriptor(nvlist_t *nvl, int value, const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_addv_descriptor(nvl, value, namefmt, nameap);
- va_end(nameap);
-}
-#endif
-
-void
-nvlist_addf_binary(nvlist_t *nvl, const void *value, size_t size,
- const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_addv_binary(nvl, value, size, namefmt, nameap);
- va_end(nameap);
-}
-
-void
-nvlist_addv_null(nvlist_t *nvl, const char *namefmt, va_list nameap)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
}
-
- nvp = nvpair_createv_null(namefmt, nameap);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
}
void
-nvlist_addv_bool(nvlist_t *nvl, bool value, const char *namefmt, va_list nameap)
+nvlist_add_null(nvlist_t *nvl, const char *name)
{
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- nvp = nvpair_createv_bool(value, namefmt, nameap);
+ nvp = nvpair_create_null(name);
if (nvp == NULL) {
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
+ ERRNO_SET(nvl->nvl_error);
+ } else {
nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_addv_number(nvlist_t *nvl, uint64_t value, const char *namefmt,
- va_list nameap)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
}
-
- nvp = nvpair_createv_number(value, namefmt, nameap);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
}
void
-nvlist_addv_string(nvlist_t *nvl, const char *value, const char *namefmt,
- va_list nameap)
+nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
+ size_t size)
{
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- nvp = nvpair_createv_string(value, namefmt, nameap);
+ nvp = nvpair_create_binary(name, value, size);
if (nvp == NULL) {
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
+ ERRNO_SET(nvl->nvl_error);
+ } else {
nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_addv_nvlist(nvlist_t *nvl, const nvlist_t *value, const char *namefmt,
- va_list nameap)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
}
-
- nvp = nvpair_createv_nvlist(value, namefmt, nameap);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
}
-#ifndef _KERNEL
-void
-nvlist_addv_descriptor(nvlist_t *nvl, int value, const char *namefmt,
- va_list nameap)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- errno = nvlist_error(nvl);
- return;
- }
- nvp = nvpair_createv_descriptor(value, namefmt, nameap);
- if (nvp == NULL)
- nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
- else
- nvlist_move_nvpair(nvl, nvp);
-}
+#define NVLIST_ADD(vtype, type) \
+void \
+nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \
+{ \
+ nvpair_t *nvp; \
+ \
+ if (nvlist_error(nvl) != 0) { \
+ ERRNO_SET(nvlist_error(nvl)); \
+ return; \
+ } \
+ \
+ nvp = nvpair_create_##type(name, value); \
+ if (nvp == NULL) { \
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
+ ERRNO_SET(nvl->nvl_error); \
+ } else { \
+ nvlist_move_nvpair(nvl, nvp); \
+ } \
+}
+
+NVLIST_ADD(bool, bool)
+NVLIST_ADD(uint64_t, number)
+NVLIST_ADD(const char *, string)
+NVLIST_ADD(const nvlist_t *, nvlist)
+#ifndef _KERNEL
+NVLIST_ADD(int, descriptor);
#endif
-void
-nvlist_addv_binary(nvlist_t *nvl, const void *value, size_t size,
- const char *namefmt, va_list nameap)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_createv_binary(value, size, namefmt, nameap);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
+#undef NVLIST_ADD
void
nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
@@ -1503,153 +1203,102 @@ nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
if (nvlist_error(nvl) != 0) {
nvpair_free(nvp);
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- if (nvlist_exists(nvl, nvpair_name(nvp))) {
- nvpair_free(nvp);
- nvl->nvl_error = EEXIST;
- RESTORE_ERRNO(nvl->nvl_error);
- return;
+ if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
+ if (nvlist_exists(nvl, nvpair_name(nvp))) {
+ nvpair_free(nvp);
+ nvl->nvl_error = EEXIST;
+ ERRNO_SET(nvl->nvl_error);
+ return;
+ }
}
nvpair_insert(&nvl->nvl_head, nvp, nvl);
}
-#define NVLIST_MOVE(vtype, type) \
-void \
-nvlist_move_##type(nvlist_t *nvl, const char *name, vtype value) \
-{ \
- \
- nvlist_movef_##type(nvl, value, "%s", name); \
-}
-
-NVLIST_MOVE(char *, string)
-NVLIST_MOVE(nvlist_t *, nvlist)
-#ifndef _KERNEL
-NVLIST_MOVE(int, descriptor)
-#endif
-
-#undef NVLIST_MOVE
-
void
-nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
-{
-
- nvlist_movef_binary(nvl, value, size, "%s", name);
-}
-
-#define NVLIST_MOVEF(vtype, type) \
-void \
-nvlist_movef_##type(nvlist_t *nvl, vtype value, const char *namefmt, \
- ...) \
-{ \
- va_list nameap; \
- \
- va_start(nameap, namefmt); \
- nvlist_movev_##type(nvl, value, namefmt, nameap); \
- va_end(nameap); \
-}
-
-NVLIST_MOVEF(char *, string)
-NVLIST_MOVEF(nvlist_t *, nvlist)
-#ifndef _KERNEL
-NVLIST_MOVEF(int, descriptor)
-#endif
-
-#undef NVLIST_MOVEF
-
-void
-nvlist_movef_binary(nvlist_t *nvl, void *value, size_t size,
- const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_movev_binary(nvl, value, size, namefmt, nameap);
- va_end(nameap);
-}
-
-void
-nvlist_movev_string(nvlist_t *nvl, char *value, const char *namefmt,
- va_list nameap)
+nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
{
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
nv_free(value);
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- nvp = nvpair_movev_string(value, namefmt, nameap);
+ nvp = nvpair_move_string(name, value);
if (nvp == NULL) {
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
+ ERRNO_SET(nvl->nvl_error);
+ } else {
nvlist_move_nvpair(nvl, nvp);
+ }
}
void
-nvlist_movev_nvlist(nvlist_t *nvl, nvlist_t *value, const char *namefmt,
- va_list nameap)
+nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
{
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
nvlist_destroy(value);
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- nvp = nvpair_movev_nvlist(value, namefmt, nameap);
+ nvp = nvpair_move_nvlist(name, value);
if (nvp == NULL) {
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
+ ERRNO_SET(nvl->nvl_error);
+ } else {
nvlist_move_nvpair(nvl, nvp);
+ }
}
#ifndef _KERNEL
void
-nvlist_movev_descriptor(nvlist_t *nvl, int value, const char *namefmt,
- va_list nameap)
+nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
{
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
close(value);
- errno = nvlist_error(nvl);
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- nvp = nvpair_movev_descriptor(value, namefmt, nameap);
- if (nvp == NULL)
- nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
- else
+ nvp = nvpair_move_descriptor(name, value);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
nvlist_move_nvpair(nvl, nvp);
+ }
}
#endif
void
-nvlist_movev_binary(nvlist_t *nvl, void *value, size_t size,
- const char *namefmt, va_list nameap)
+nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
{
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
nv_free(value);
- RESTORE_ERRNO(nvlist_error(nvl));
+ ERRNO_SET(nvlist_error(nvl));
return;
}
- nvp = nvpair_movev_binary(value, size, namefmt, nameap);
+ nvp = nvpair_move_binary(name, value, size);
if (nvp == NULL) {
nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
+ ERRNO_SET(nvl->nvl_error);
+ } else {
nvlist_move_nvpair(nvl, nvp);
+ }
}
const nvpair_t *
@@ -1693,84 +1342,6 @@ nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
return (nvpair_get_binary(nvp, sizep));
}
-#define NVLIST_GETF(ftype, type) \
-ftype \
-nvlist_getf_##type(const nvlist_t *nvl, const char *namefmt, ...) \
-{ \
- va_list nameap; \
- ftype value; \
- \
- va_start(nameap, namefmt); \
- value = nvlist_getv_##type(nvl, namefmt, nameap); \
- va_end(nameap); \
- \
- return (value); \
-}
-
-#ifndef _KERNEL
-NVLIST_GETF(bool, bool)
-NVLIST_GETF(uint64_t, number)
-NVLIST_GETF(const char *, string)
-NVLIST_GETF(const nvlist_t *, nvlist)
-NVLIST_GETF(int, descriptor)
-
-#undef NVLIST_GETF
-
-const void *
-nvlist_getf_binary(const nvlist_t *nvl, size_t *sizep, const char *namefmt, ...)
-{
- va_list nameap;
- const void *value;
-
- va_start(nameap, namefmt);
- value = nvlist_getv_binary(nvl, sizep, namefmt, nameap);
- va_end(nameap);
-
- return (value);
-}
-
-#define NVLIST_GETV(ftype, type, TYPE) \
-ftype \
-nvlist_getv_##type(const nvlist_t *nvl, const char *namefmt, \
- va_list nameap) \
-{ \
- char *name; \
- ftype value; \
- \
- vasprintf(&name, namefmt, nameap); \
- if (name == NULL) \
- nvlist_report_missing(NV_TYPE_##TYPE, "<unknown>"); \
- value = nvlist_get_##type(nvl, name); \
- free(name); \
- \
- return (value); \
-}
-
-NVLIST_GETV(bool, bool, BOOL)
-NVLIST_GETV(uint64_t, number, NUMBER)
-NVLIST_GETV(const char *, string, STRING)
-NVLIST_GETV(const nvlist_t *, nvlist, NVLIST)
-NVLIST_GETV(int, descriptor, DESCRIPTOR)
-
-#undef NVLIST_GETV
-
-const void *
-nvlist_getv_binary(const nvlist_t *nvl, size_t *sizep, const char *namefmt,
- va_list nameap)
-{
- char *name;
- const void *binary;
-
- nv_vasprintf(&name, namefmt, nameap);
- if (name == NULL)
- nvlist_report_missing(NV_TYPE_BINARY, "<unknown>");
-
- binary = nvlist_get_binary(nvl, name, sizep);
- nv_free(name);
- return (binary);
-}
-#endif
-
#define NVLIST_TAKE(ftype, type, TYPE) \
ftype \
nvlist_take_##type(nvlist_t *nvl, const char *name) \
@@ -1813,82 +1384,6 @@ nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
return (value);
}
-#define NVLIST_TAKEF(ftype, type) \
-ftype \
-nvlist_takef_##type(nvlist_t *nvl, const char *namefmt, ...) \
-{ \
- va_list nameap; \
- ftype value; \
- \
- va_start(nameap, namefmt); \
- value = nvlist_takev_##type(nvl, namefmt, nameap); \
- va_end(nameap); \
- \
- return (value); \
-}
-
-#ifndef _KERNEL
-NVLIST_TAKEF(bool, bool)
-NVLIST_TAKEF(uint64_t, number)
-NVLIST_TAKEF(char *, string)
-NVLIST_TAKEF(nvlist_t *, nvlist)
-NVLIST_TAKEF(int, descriptor)
-
-#undef NVLIST_TAKEF
-
-void *
-nvlist_takef_binary(nvlist_t *nvl, size_t *sizep, const char *namefmt, ...)
-{
- va_list nameap;
- void *value;
-
- va_start(nameap, namefmt);
- value = nvlist_takev_binary(nvl, sizep, namefmt, nameap);
- va_end(nameap);
-
- return (value);
-}
-
-#define NVLIST_TAKEV(ftype, type, TYPE) \
-ftype \
-nvlist_takev_##type(nvlist_t *nvl, const char *namefmt, va_list nameap) \
-{ \
- char *name; \
- ftype value; \
- \
- vasprintf(&name, namefmt, nameap); \
- if (name == NULL) \
- nvlist_report_missing(NV_TYPE_##TYPE, "<unknown>"); \
- value = nvlist_take_##type(nvl, name); \
- free(name); \
- return (value); \
-}
-
-NVLIST_TAKEV(bool, bool, BOOL)
-NVLIST_TAKEV(uint64_t, number, NUMBER)
-NVLIST_TAKEV(char *, string, STRING)
-NVLIST_TAKEV(nvlist_t *, nvlist, NVLIST)
-NVLIST_TAKEV(int, descriptor, DESCRIPTOR)
-
-#undef NVLIST_TAKEV
-
-void *
-nvlist_takev_binary(nvlist_t *nvl, size_t *sizep, const char *namefmt,
- va_list nameap)
-{
- char *name;
- void *binary;
-
- nv_vasprintf(&name, namefmt, nameap);
- if (name == NULL)
- nvlist_report_missing(NV_TYPE_BINARY, "<unknown>");
-
- binary = nvlist_take_binary(nvl, name, sizep);
- nv_free(name);
- return (binary);
-}
-#endif
-
void
nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
{
@@ -1927,68 +1422,6 @@ NVLIST_FREE(binary, BINARY)
#undef NVLIST_FREE
-#ifndef _KERNEL
-void
-nvlist_freef(nvlist_t *nvl, const char *namefmt, ...)
-{
- va_list nameap;
-
- va_start(nameap, namefmt);
- nvlist_freev(nvl, namefmt, nameap);
- va_end(nameap);
-}
-
-#define NVLIST_FREEF(type) \
-void \
-nvlist_freef_##type(nvlist_t *nvl, const char *namefmt, ...) \
-{ \
- va_list nameap; \
- \
- va_start(nameap, namefmt); \
- nvlist_freev_##type(nvl, namefmt, nameap); \
- va_end(nameap); \
-}
-
-NVLIST_FREEF(null)
-NVLIST_FREEF(bool)
-NVLIST_FREEF(number)
-NVLIST_FREEF(string)
-NVLIST_FREEF(nvlist)
-NVLIST_FREEF(descriptor)
-NVLIST_FREEF(binary)
-
-#undef NVLIST_FREEF
-
-void
-nvlist_freev(nvlist_t *nvl, const char *namefmt, va_list nameap)
-{
-
- nvlist_freev_type(nvl, NV_TYPE_NONE, namefmt, nameap);
-}
-
-#define NVLIST_FREEV(type, TYPE) \
-void \
-nvlist_freev_##type(nvlist_t *nvl, const char *namefmt, va_list nameap) \
-{ \
- char *name; \
- \
- vasprintf(&name, namefmt, nameap); \
- if (name == NULL) \
- nvlist_report_missing(NV_TYPE_##TYPE, "<unknown>"); \
- nvlist_free_##type(nvl, name); \
- free(name); \
-}
-
-NVLIST_FREEV(null, NULL)
-NVLIST_FREEV(bool, BOOL)
-NVLIST_FREEV(number, NUMBER)
-NVLIST_FREEV(string, STRING)
-NVLIST_FREEV(nvlist, NVLIST)
-NVLIST_FREEV(descriptor, DESCRIPTOR)
-NVLIST_FREEV(binary, BINARY)
-#undef NVLIST_FREEV
-#endif
-
void
nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
{
@@ -2000,3 +1433,4 @@ nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
nvlist_remove_nvpair(nvl, nvp);
nvpair_free(nvp);
}
+
diff --git a/sys/kern/subr_nvpair.c b/sys/kern/subr_nvpair.c
index 7b88e42..cde08e6 100644
--- a/sys/kern/subr_nvpair.c
+++ b/sys/kern/subr_nvpair.c
@@ -143,7 +143,8 @@ nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_list == NULL);
- PJDLOG_ASSERT(!nvlist_exists(nvl, nvpair_name(nvp)));
+ PJDLOG_ASSERT((nvlist_flags(nvl) & NV_FLAG_NO_UNIQUE) != 0 ||
+ !nvlist_exists(nvl, nvpair_name(nvp)));
TAILQ_INSERT_TAIL(head, nvp, nvp_next);
nvp->nvp_list = nvl;
@@ -468,7 +469,7 @@ nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
return (ptr);
failed:
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -480,7 +481,7 @@ nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
if (nvp->nvp_datasize != 0) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -496,11 +497,11 @@ nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
if (nvp->nvp_datasize != sizeof(value)) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
if (*leftp < sizeof(value)) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -509,7 +510,7 @@ nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
*leftp -= sizeof(value);
if (value != 0 && value != 1) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -526,11 +527,11 @@ nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
if (nvp->nvp_datasize != sizeof(uint64_t)) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
if (*leftp < sizeof(uint64_t)) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -552,13 +553,13 @@ nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
nvp->nvp_datasize - 1) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -581,7 +582,7 @@ nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -609,11 +610,11 @@ nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
if (nvp->nvp_datasize != sizeof(idx)) {
- errno = EINVAL;
+ ERRNO_SET(EINVAL);
return (NULL);
}
if (*leftp < sizeof(idx)) {
- errno = EINVAL;
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -623,12 +624,12 @@ nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
idx = le64dec(ptr);
if (idx < 0) {
- errno = EINVAL;
+ ERRNO_SET(EINVAL);
return (NULL);
}
if ((size_t)idx >= nfds) {
- errno = EINVAL;
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -650,7 +651,7 @@ nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -716,69 +717,34 @@ nvpair_name(const nvpair_t *nvp)
}
static nvpair_t *
-nvpair_allocv(int type, uint64_t data, size_t datasize, const char *namefmt,
- va_list nameap)
+nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize)
{
nvpair_t *nvp;
- char *name;
- int namelen;
+ size_t namelen;
PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
- namelen = nv_vasprintf(&name, namefmt, nameap);
- if (namelen < 0)
- return (NULL);
-
- PJDLOG_ASSERT(namelen > 0);
+ namelen = strlen(name);
if (namelen >= NV_NAME_MAX) {
- nv_free(name);
- RESTORE_ERRNO(ENAMETOOLONG);
+ ERRNO_SET(ENAMETOOLONG);
return (NULL);
}
nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
if (nvp != NULL) {
nvp->nvp_name = (char *)(nvp + 1);
- memcpy(nvp->nvp_name, name, namelen + 1);
+ memcpy(nvp->nvp_name, name, namelen);
+ nvp->nvp_name[namelen] = '\0';
nvp->nvp_type = type;
nvp->nvp_data = data;
nvp->nvp_datasize = datasize;
nvp->nvp_magic = NVPAIR_MAGIC;
}
- nv_free(name);
return (nvp);
};
nvpair_t *
-nvpair_create_null(const char *name)
-{
-
- return (nvpair_createf_null("%s", name));
-}
-
-nvpair_t *
-nvpair_create_bool(const char *name, bool value)
-{
-
- return (nvpair_createf_bool(value, "%s", name));
-}
-
-nvpair_t *
-nvpair_create_number(const char *name, uint64_t value)
-{
-
- return (nvpair_createf_number(value, "%s", name));
-}
-
-nvpair_t *
-nvpair_create_string(const char *name, const char *value)
-{
-
- return (nvpair_createf_string(value, "%s", name));
-}
-
-nvpair_t *
nvpair_create_stringf(const char *name, const char *valuefmt, ...)
{
va_list valueap;
@@ -808,153 +774,36 @@ nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
}
nvpair_t *
-nvpair_create_nvlist(const char *name, const nvlist_t *value)
-{
-
- return (nvpair_createf_nvlist(value, "%s", name));
-}
-
-#ifndef _KERNEL
-nvpair_t *
-nvpair_create_descriptor(const char *name, int value)
-{
-
- return (nvpair_createf_descriptor(value, "%s", name));
-}
-#endif
-
-nvpair_t *
-nvpair_create_binary(const char *name, const void *value, size_t size)
-{
-
- return (nvpair_createf_binary(value, size, "%s", name));
-}
-
-nvpair_t *
-nvpair_createf_null(const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_createv_null(namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_createf_bool(bool value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_createv_bool(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_createf_number(uint64_t value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_createv_number(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_createf_string(const char *value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_createv_string(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_createf_nvlist(const nvlist_t *value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_createv_nvlist(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-#ifndef _KERNEL
-nvpair_t *
-nvpair_createf_descriptor(int value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_createv_descriptor(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-#endif
-
-nvpair_t *
-nvpair_createf_binary(const void *value, size_t size, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_createv_binary(value, size, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_createv_null(const char *namefmt, va_list nameap)
+nvpair_create_null(const char *name)
{
- return (nvpair_allocv(NV_TYPE_NULL, 0, 0, namefmt, nameap));
+ return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0));
}
nvpair_t *
-nvpair_createv_bool(bool value, const char *namefmt, va_list nameap)
+nvpair_create_bool(const char *name, bool value)
{
- return (nvpair_allocv(NV_TYPE_BOOL, value ? 1 : 0, sizeof(uint8_t),
- namefmt, nameap));
+ return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
+ sizeof(uint8_t)));
}
nvpair_t *
-nvpair_createv_number(uint64_t value, const char *namefmt, va_list nameap)
+nvpair_create_number(const char *name, uint64_t value)
{
- return (nvpair_allocv(NV_TYPE_NUMBER, value, sizeof(value), namefmt,
- nameap));
+ return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value)));
}
nvpair_t *
-nvpair_createv_string(const char *value, const char *namefmt, va_list nameap)
+nvpair_create_string(const char *name, const char *value)
{
nvpair_t *nvp;
size_t size;
char *data;
if (value == NULL) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -963,8 +812,8 @@ nvpair_createv_string(const char *value, const char *namefmt, va_list nameap)
return (NULL);
size = strlen(value) + 1;
- nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)data, size,
- namefmt, nameap);
+ nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
+ size);
if (nvp == NULL)
nv_free(data);
@@ -972,14 +821,13 @@ nvpair_createv_string(const char *value, const char *namefmt, va_list nameap)
}
nvpair_t *
-nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
- va_list nameap)
+nvpair_create_nvlist(const char *name, const nvlist_t *value)
{
nvlist_t *nvl;
nvpair_t *nvp;
if (value == NULL) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -987,8 +835,7 @@ nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
if (nvl == NULL)
return (NULL);
- nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
- namefmt, nameap);
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0);
if (nvp == NULL)
nvlist_destroy(nvl);
else
@@ -999,12 +846,12 @@ nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
#ifndef _KERNEL
nvpair_t *
-nvpair_createv_descriptor(int value, const char *namefmt, va_list nameap)
+nvpair_create_descriptor(const char *name, int value)
{
nvpair_t *nvp;
if (value < 0 || !fd_is_valid(value)) {
- errno = EBADF;
+ ERRNO_SET(EBADF);
return (NULL);
}
@@ -1012,24 +859,26 @@ nvpair_createv_descriptor(int value, const char *namefmt, va_list nameap)
if (value < 0)
return (NULL);
- nvp = nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
- sizeof(int64_t), namefmt, nameap);
- if (nvp == NULL)
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
+ sizeof(int64_t));
+ if (nvp == NULL) {
+ ERRNO_SAVE();
close(value);
+ ERRNO_RESTORE();
+ }
return (nvp);
}
#endif
nvpair_t *
-nvpair_createv_binary(const void *value, size_t size, const char *namefmt,
- va_list nameap)
+nvpair_create_binary(const char *name, const void *value, size_t size)
{
nvpair_t *nvp;
void *data;
if (value == NULL || size == 0) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
@@ -1038,8 +887,8 @@ nvpair_createv_binary(const void *value, size_t size, const char *namefmt,
return (NULL);
memcpy(data, value, size);
- nvp = nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)data, size,
- namefmt, nameap);
+ nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
+ size);
if (nvp == NULL)
nv_free(data);
@@ -1049,127 +898,42 @@ nvpair_createv_binary(const void *value, size_t size, const char *namefmt,
nvpair_t *
nvpair_move_string(const char *name, char *value)
{
-
- return (nvpair_movef_string(value, "%s", name));
-}
-
-nvpair_t *
-nvpair_move_nvlist(const char *name, nvlist_t *value)
-{
-
- return (nvpair_movef_nvlist(value, "%s", name));
-}
-
-#ifndef _KERNEL
-nvpair_t *
-nvpair_move_descriptor(const char *name, int value)
-{
-
- return (nvpair_movef_descriptor(value, "%s", name));
-}
-#endif
-
-nvpair_t *
-nvpair_move_binary(const char *name, void *value, size_t size)
-{
-
- return (nvpair_movef_binary(value, size, "%s", name));
-}
-
-nvpair_t *
-nvpair_movef_string(char *value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_movev_string(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_movef_nvlist(nvlist_t *value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_movev_nvlist(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-#ifndef _KERNEL
-nvpair_t *
-nvpair_movef_descriptor(int value, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_movev_descriptor(value, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-#endif
-
-nvpair_t *
-nvpair_movef_binary(void *value, size_t size, const char *namefmt, ...)
-{
- va_list nameap;
- nvpair_t *nvp;
-
- va_start(nameap, namefmt);
- nvp = nvpair_movev_binary(value, size, namefmt, nameap);
- va_end(nameap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_movev_string(char *value, const char *namefmt, va_list nameap)
-{
nvpair_t *nvp;
- int serrno;
if (value == NULL) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
- nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
- strlen(value) + 1, namefmt, nameap);
+ nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
+ strlen(value) + 1);
if (nvp == NULL) {
- SAVE_ERRNO(serrno);
+ ERRNO_SAVE();
nv_free(value);
- RESTORE_ERRNO(serrno);
+ ERRNO_RESTORE();
}
return (nvp);
}
nvpair_t *
-nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
+nvpair_move_nvlist(const char *name, nvlist_t *value)
{
nvpair_t *nvp;
if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
if (nvlist_error(value) != 0) {
- RESTORE_ERRNO(nvlist_error(value));
+ ERRNO_SET(nvlist_error(value));
nvlist_destroy(value);
return (NULL);
}
- nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value, 0,
- namefmt, nameap);
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
+ 0);
if (nvp == NULL)
nvlist_destroy(value);
else
@@ -1180,22 +944,21 @@ nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
#ifndef _KERNEL
nvpair_t *
-nvpair_movev_descriptor(int value, const char *namefmt, va_list nameap)
+nvpair_move_descriptor(const char *name, int value)
{
nvpair_t *nvp;
- int serrno;
if (value < 0 || !fd_is_valid(value)) {
- errno = EBADF;
+ ERRNO_SET(EBADF);
return (NULL);
}
- nvp = nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
- sizeof(int64_t), namefmt, nameap);
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
+ sizeof(int64_t));
if (nvp == NULL) {
- serrno = errno;
+ ERRNO_SAVE();
close(value);
- errno = serrno;
+ ERRNO_RESTORE();
}
return (nvp);
@@ -1203,23 +966,21 @@ nvpair_movev_descriptor(int value, const char *namefmt, va_list nameap)
#endif
nvpair_t *
-nvpair_movev_binary(void *value, size_t size, const char *namefmt,
- va_list nameap)
+nvpair_move_binary(const char *name, void *value, size_t size)
{
nvpair_t *nvp;
- int serrno;
if (value == NULL || size == 0) {
- RESTORE_ERRNO(EINVAL);
+ ERRNO_SET(EINVAL);
return (NULL);
}
- nvp = nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)value, size,
- namefmt, nameap);
+ nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
+ size);
if (nvp == NULL) {
- SAVE_ERRNO(serrno);
+ ERRNO_SAVE();
nv_free(value);
- RESTORE_ERRNO(serrno);
+ ERRNO_RESTORE();
}
return (nvp);
@@ -1348,3 +1109,4 @@ nvpair_type_string(int type)
return ("<UNKNOWN>");
}
}
+
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c
index f662ec2..cba656a 100644
--- a/sys/kern/subr_param.c
+++ b/sys/kern/subr_param.c
@@ -99,11 +99,7 @@ pid_t pid_max = PID_MAX;
long maxswzone; /* max swmeta KVA storage */
long maxbcache; /* max buffer cache KVA storage */
long maxpipekva; /* Limit on pipe KVA */
-#ifdef XEN
-int vm_guest = VM_GUEST_XEN;
-#else
int vm_guest = VM_GUEST_NO; /* Running as virtual machine guest? */
-#endif
u_long maxtsiz; /* max text size */
u_long dfldsiz; /* initial data size limit */
u_long maxdsiz; /* max data size */
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c
index 7e6fd09..6509522 100644
--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -295,7 +295,7 @@ log(int level, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- (void)_vprintf(level, log_open ? TOLOG : TOCONS, fmt, ap);
+ (void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
va_end(ap);
msgbuftrigger = 1;
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index cfc3ed7..93f7557 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ktr.h>
#include <sys/pioctl.h>
#include <sys/ptrace.h>
+#include <sys/racct.h>
#include <sys/resourcevar.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
@@ -79,12 +80,6 @@ __FBSDID("$FreeBSD$");
#include <net/vnet.h>
#endif
-#ifdef XEN
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
-#endif
-
#ifdef HWPMC_HOOKS
#include <sys/pmckern.h>
#endif
@@ -135,9 +130,6 @@ userret(struct thread *td, struct trapframe *frame)
* Let the scheduler adjust our priority etc.
*/
sched_userret(td);
-#ifdef XEN
- PT_UPDATES_FLUSH();
-#endif
/*
* Check for misbehavior.
@@ -172,11 +164,13 @@ userret(struct thread *td, struct trapframe *frame)
__func__, td, p->p_pid, td->td_name, curvnet,
(td->td_vnet_lpush != NULL) ? td->td_vnet_lpush : "N/A"));
#endif
-#ifdef RACCT
- PROC_LOCK(p);
- while (p->p_throttled == 1)
- msleep(p->p_racct, &p->p_mtx, 0, "racct", 0);
- PROC_UNLOCK(p);
+#ifdef RACCT
+ if (racct_enable) {
+ PROC_LOCK(p);
+ while (p->p_throttled == 1)
+ msleep(p->p_racct, &p->p_mtx, 0, "racct", 0);
+ PROC_UNLOCK(p);
+ }
#endif
}
diff --git a/sys/kern/subr_vmem.c b/sys/kern/subr_vmem.c
index 47e583b..80940be 100644
--- a/sys/kern/subr_vmem.c
+++ b/sys/kern/subr_vmem.c
@@ -1330,12 +1330,15 @@ vmem_size(vmem_t *vm, int typemask)
case VMEM_FREE|VMEM_ALLOC:
return vm->vm_size;
case VMEM_MAXFREE:
+ VMEM_LOCK(vm);
for (i = VMEM_MAXORDER - 1; i >= 0; i--) {
if (LIST_EMPTY(&vm->vm_freelist[i]))
continue;
+ VMEM_UNLOCK(vm);
return ((vmem_size_t)ORDER2SIZE(i) <<
vm->vm_quantum_shift);
}
+ VMEM_UNLOCK(vm);
return (0);
default:
panic("vmem_size");
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 8fc1db9..213801a 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -219,6 +219,7 @@ sys_pread(td, uap)
return(error);
}
+#if defined(COMPAT_FREEBSD6)
int
freebsd6_pread(td, uap)
struct thread *td;
@@ -232,6 +233,7 @@ freebsd6_pread(td, uap)
oargs.offset = uap->offset;
return (sys_pread(td, &oargs));
}
+#endif
/*
* Scatter read system call.
@@ -430,6 +432,7 @@ sys_pwrite(td, uap)
return(error);
}
+#if defined(COMPAT_FREEBSD6)
int
freebsd6_pwrite(td, uap)
struct thread *td;
@@ -443,6 +446,7 @@ freebsd6_pwrite(td, uap)
oargs.offset = uap->offset;
return (sys_pwrite(td, &oargs));
}
+#endif
/*
* Gather write system call.
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index fa06784..06a4d5a 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -406,13 +406,11 @@ kern_pipe(struct thread *td, int fildes[2])
int
kern_pipe2(struct thread *td, int fildes[2], int flags)
{
- struct filedesc *fdp;
struct file *rf, *wf;
struct pipe *rpipe, *wpipe;
struct pipepair *pp;
int fd, fflags, error;
- fdp = td->td_proc->p_fd;
pipe_paircreate(td, &pp);
rpipe = &pp->pp_rpipe;
wpipe = &pp->pp_wpipe;
@@ -438,7 +436,7 @@ kern_pipe2(struct thread *td, int fildes[2], int flags)
finit(rf, fflags, DTYPE_PIPE, rpipe, &pipeops);
error = falloc(td, &wf, &fd, flags);
if (error) {
- fdclose(fdp, rf, fildes[0], td);
+ fdclose(td, rf, fildes[0]);
fdrop(rf, td);
/* rpipe has been closed by fdrop(). */
pipeclose(wpipe);
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index e99ae94..a404c51 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles
+ * created from FreeBSD: head/sys/kern/syscalls.master 281714 2015-04-18 21:50:13Z kib
*/
const char *syscallnames[] = {
@@ -180,8 +180,8 @@ const char *syscallnames[] = {
"msgsys", /* 170 = msgsys */
"shmsys", /* 171 = shmsys */
"#172", /* 172 = nosys */
- "freebsd6_pread", /* 173 = freebsd6_pread */
- "freebsd6_pwrite", /* 174 = freebsd6_pwrite */
+ "compat6.pread", /* 173 = freebsd6 pread */
+ "compat6.pwrite", /* 174 = freebsd6 pwrite */
"setfib", /* 175 = setfib */
"ntp_adjtime", /* 176 = ntp_adjtime */
"#177", /* 177 = sfork */
@@ -204,11 +204,11 @@ const char *syscallnames[] = {
"getrlimit", /* 194 = getrlimit */
"setrlimit", /* 195 = setrlimit */
"getdirentries", /* 196 = getdirentries */
- "freebsd6_mmap", /* 197 = freebsd6_mmap */
+ "compat6.mmap", /* 197 = freebsd6 mmap */
"__syscall", /* 198 = __syscall */
- "freebsd6_lseek", /* 199 = freebsd6_lseek */
- "freebsd6_truncate", /* 200 = freebsd6_truncate */
- "freebsd6_ftruncate", /* 201 = freebsd6_ftruncate */
+ "compat6.lseek", /* 199 = freebsd6 lseek */
+ "compat6.truncate", /* 200 = freebsd6 truncate */
+ "compat6.ftruncate", /* 201 = freebsd6 ftruncate */
"__sysctl", /* 202 = __sysctl */
"mlock", /* 203 = mlock */
"munlock", /* 204 = munlock */
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 09d38d4..9873868 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -342,9 +342,9 @@
int a4); }
; XXX should be { int shmsys(int which, ...); }
172 AUE_NULL UNIMPL nosys
-173 AUE_PREAD STD { ssize_t freebsd6_pread(int fd, void *buf, \
+173 AUE_PREAD COMPAT6 { ssize_t pread(int fd, void *buf, \
size_t nbyte, int pad, off_t offset); }
-174 AUE_PWRITE STD { ssize_t freebsd6_pwrite(int fd, \
+174 AUE_PWRITE COMPAT6 { ssize_t pwrite(int fd, \
const void *buf, \
size_t nbyte, int pad, off_t offset); }
175 AUE_NULL STD { int setfib(int fibnum); }
@@ -376,16 +376,16 @@
__setrlimit_args int
196 AUE_GETDIRENTRIES STD { int getdirentries(int fd, char *buf, \
u_int count, long *basep); }
-197 AUE_MMAP STD { caddr_t freebsd6_mmap(caddr_t addr, \
+197 AUE_MMAP COMPAT6 { caddr_t mmap(caddr_t addr, \
size_t len, int prot, int flags, int fd, \
int pad, off_t pos); }
198 AUE_NULL NOPROTO { int nosys(void); } __syscall \
__syscall_args int
-199 AUE_LSEEK STD { off_t freebsd6_lseek(int fd, int pad, \
+199 AUE_LSEEK COMPAT6 { off_t lseek(int fd, int pad, \
off_t offset, int whence); }
-200 AUE_TRUNCATE STD { int freebsd6_truncate(char *path, int pad, \
+200 AUE_TRUNCATE COMPAT6 { int truncate(char *path, int pad, \
off_t length); }
-201 AUE_FTRUNCATE STD { int freebsd6_ftruncate(int fd, int pad, \
+201 AUE_FTRUNCATE COMPAT6 { int ftruncate(int fd, int pad, \
off_t length); }
202 AUE_SYSCTL STD { int __sysctl(int *name, u_int namelen, \
void *old, size_t *oldlenp, void *new, \
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
index c5d3b85..a06d7dc 100644
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -914,28 +914,6 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 4;
break;
}
- /* freebsd6_pread */
- case 173: {
- struct freebsd6_pread_args *p = params;
- iarg[0] = p->fd; /* int */
- uarg[1] = (intptr_t) p->buf; /* void * */
- uarg[2] = p->nbyte; /* size_t */
- iarg[3] = p->pad; /* int */
- iarg[4] = p->offset; /* off_t */
- *n_args = 5;
- break;
- }
- /* freebsd6_pwrite */
- case 174: {
- struct freebsd6_pwrite_args *p = params;
- iarg[0] = p->fd; /* int */
- uarg[1] = (intptr_t) p->buf; /* const void * */
- uarg[2] = p->nbyte; /* size_t */
- iarg[3] = p->pad; /* int */
- iarg[4] = p->offset; /* off_t */
- *n_args = 5;
- break;
- }
/* setfib */
case 175: {
struct setfib_args *p = params;
@@ -1037,52 +1015,11 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 4;
break;
}
- /* freebsd6_mmap */
- case 197: {
- struct freebsd6_mmap_args *p = params;
- uarg[0] = (intptr_t) p->addr; /* caddr_t */
- uarg[1] = p->len; /* size_t */
- iarg[2] = p->prot; /* int */
- iarg[3] = p->flags; /* int */
- iarg[4] = p->fd; /* int */
- iarg[5] = p->pad; /* int */
- iarg[6] = p->pos; /* off_t */
- *n_args = 7;
- break;
- }
/* nosys */
case 198: {
*n_args = 0;
break;
}
- /* freebsd6_lseek */
- case 199: {
- struct freebsd6_lseek_args *p = params;
- iarg[0] = p->fd; /* int */
- iarg[1] = p->pad; /* int */
- iarg[2] = p->offset; /* off_t */
- iarg[3] = p->whence; /* int */
- *n_args = 4;
- break;
- }
- /* freebsd6_truncate */
- case 200: {
- struct freebsd6_truncate_args *p = params;
- uarg[0] = (intptr_t) p->path; /* char * */
- iarg[1] = p->pad; /* int */
- iarg[2] = p->length; /* off_t */
- *n_args = 3;
- break;
- }
- /* freebsd6_ftruncate */
- case 201: {
- struct freebsd6_ftruncate_args *p = params;
- iarg[0] = p->fd; /* int */
- iarg[1] = p->pad; /* int */
- iarg[2] = p->length; /* off_t */
- *n_args = 3;
- break;
- }
/* __sysctl */
case 202: {
struct sysctl_args *p = params;
@@ -4873,50 +4810,6 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
- /* freebsd6_pread */
- case 173:
- switch(ndx) {
- case 0:
- p = "int";
- break;
- case 1:
- p = "void *";
- break;
- case 2:
- p = "size_t";
- break;
- case 3:
- p = "int";
- break;
- case 4:
- p = "off_t";
- break;
- default:
- break;
- };
- break;
- /* freebsd6_pwrite */
- case 174:
- switch(ndx) {
- case 0:
- p = "int";
- break;
- case 1:
- p = "const void *";
- break;
- case 2:
- p = "size_t";
- break;
- case 3:
- p = "int";
- break;
- case 4:
- p = "off_t";
- break;
- default:
- break;
- };
- break;
/* setfib */
case 175:
switch(ndx) {
@@ -5077,88 +4970,9 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
- /* freebsd6_mmap */
- case 197:
- switch(ndx) {
- case 0:
- p = "caddr_t";
- break;
- case 1:
- p = "size_t";
- break;
- case 2:
- p = "int";
- break;
- case 3:
- p = "int";
- break;
- case 4:
- p = "int";
- break;
- case 5:
- p = "int";
- break;
- case 6:
- p = "off_t";
- break;
- default:
- break;
- };
- break;
/* nosys */
case 198:
break;
- /* freebsd6_lseek */
- case 199:
- switch(ndx) {
- case 0:
- p = "int";
- break;
- case 1:
- p = "int";
- break;
- case 2:
- p = "off_t";
- break;
- case 3:
- p = "int";
- break;
- default:
- break;
- };
- break;
- /* freebsd6_truncate */
- case 200:
- switch(ndx) {
- case 0:
- p = "char *";
- break;
- case 1:
- p = "int";
- break;
- case 2:
- p = "off_t";
- break;
- default:
- break;
- };
- break;
- /* freebsd6_ftruncate */
- case 201:
- switch(ndx) {
- case 0:
- p = "int";
- break;
- case 1:
- p = "int";
- break;
- case 2:
- p = "off_t";
- break;
- default:
- break;
- };
- break;
/* __sysctl */
case 202:
switch(ndx) {
@@ -9598,16 +9412,6 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
- /* freebsd6_pread */
- case 173:
- if (ndx == 0 || ndx == 1)
- p = "ssize_t";
- break;
- /* freebsd6_pwrite */
- case 174:
- if (ndx == 0 || ndx == 1)
- p = "ssize_t";
- break;
/* setfib */
case 175:
if (ndx == 0 || ndx == 1)
@@ -9673,28 +9477,8 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
- /* freebsd6_mmap */
- case 197:
- if (ndx == 0 || ndx == 1)
- p = "caddr_t";
- break;
/* nosys */
case 198:
- /* freebsd6_lseek */
- case 199:
- if (ndx == 0 || ndx == 1)
- p = "off_t";
- break;
- /* freebsd6_truncate */
- case 200:
- if (ndx == 0 || ndx == 1)
- p = "int";
- break;
- /* freebsd6_ftruncate */
- case 201:
- if (ndx == 0 || ndx == 1)
- p = "int";
- break;
/* __sysctl */
case 202:
if (ndx == 0 || ndx == 1)
diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c
index acc44710..59357c4 100644
--- a/sys/kern/sysv_msg.c
+++ b/sys/kern/sysv_msg.c
@@ -617,12 +617,14 @@ sys_msgget(td, uap)
goto done2;
}
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- error = racct_add(td->td_proc, RACCT_NMSGQ, 1);
- PROC_UNLOCK(td->td_proc);
- if (error != 0) {
- error = ENOSPC;
- goto done2;
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ error = racct_add(td->td_proc, RACCT_NMSGQ, 1);
+ PROC_UNLOCK(td->td_proc);
+ if (error != 0) {
+ error = ENOSPC;
+ goto done2;
+ }
}
#endif
DPRINTF(("msqid %d is available\n", msqid));
@@ -724,20 +726,22 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype)
#endif
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) {
- PROC_UNLOCK(td->td_proc);
- error = EAGAIN;
- goto done2;
- }
- saved_msgsz = msgsz;
- if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) {
- racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) {
+ PROC_UNLOCK(td->td_proc);
+ error = EAGAIN;
+ goto done2;
+ }
+ saved_msgsz = msgsz;
+ if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) {
+ racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
+ PROC_UNLOCK(td->td_proc);
+ error = EAGAIN;
+ goto done2;
+ }
PROC_UNLOCK(td->td_proc);
- error = EAGAIN;
- goto done2;
}
- PROC_UNLOCK(td->td_proc);
#endif
segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
@@ -994,7 +998,7 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype)
td->td_retval[0] = 0;
done3:
#ifdef RACCT
- if (error != 0) {
+ if (racct_enable && error != 0) {
PROC_LOCK(td->td_proc);
racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
racct_sub(td->td_proc, RACCT_MSGQSIZE, saved_msgsz);
diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c
index 6ff5789..d9324f4 100644
--- a/sys/kern/sysv_sem.c
+++ b/sys/kern/sysv_sem.c
@@ -915,12 +915,14 @@ sys_semget(struct thread *td, struct semget_args *uap)
goto done2;
}
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- error = racct_add(td->td_proc, RACCT_NSEM, nsems);
- PROC_UNLOCK(td->td_proc);
- if (error != 0) {
- error = ENOSPC;
- goto done2;
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ error = racct_add(td->td_proc, RACCT_NSEM, nsems);
+ PROC_UNLOCK(td->td_proc);
+ if (error != 0) {
+ error = ENOSPC;
+ goto done2;
+ }
}
#endif
DPRINTF(("semid %d is available\n", semid));
@@ -1009,12 +1011,15 @@ sys_semop(struct thread *td, struct semop_args *uap)
return (E2BIG);
} else {
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- if (nsops > racct_get_available(td->td_proc, RACCT_NSEMOP)) {
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ if (nsops >
+ racct_get_available(td->td_proc, RACCT_NSEMOP)) {
+ PROC_UNLOCK(td->td_proc);
+ return (E2BIG);
+ }
PROC_UNLOCK(td->td_proc);
- return (E2BIG);
}
- PROC_UNLOCK(td->td_proc);
#endif
sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK);
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index 5f3e00e..3240a5f 100644
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -327,7 +327,7 @@ kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr,
{
struct proc *p = td->td_proc;
struct shmid_kernel *shmseg;
- struct shmmap_state *shmmap_s = NULL;
+ struct shmmap_state *shmmap_s;
vm_offset_t attach_va;
vm_prot_t prot;
vm_size_t size;
@@ -651,17 +651,19 @@ shmget_allocate_segment(struct thread *td, struct shmget_args *uap, int mode)
("segnum %d shmalloced %d", segnum, shmalloced));
shmseg = &shmsegs[segnum];
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- if (racct_add(td->td_proc, RACCT_NSHM, 1)) {
- PROC_UNLOCK(td->td_proc);
- return (ENOSPC);
- }
- if (racct_add(td->td_proc, RACCT_SHMSIZE, size)) {
- racct_sub(td->td_proc, RACCT_NSHM, 1);
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ if (racct_add(td->td_proc, RACCT_NSHM, 1)) {
+ PROC_UNLOCK(td->td_proc);
+ return (ENOSPC);
+ }
+ if (racct_add(td->td_proc, RACCT_SHMSIZE, size)) {
+ racct_sub(td->td_proc, RACCT_NSHM, 1);
+ PROC_UNLOCK(td->td_proc);
+ return (ENOMEM);
+ }
PROC_UNLOCK(td->td_proc);
- return (ENOMEM);
}
- PROC_UNLOCK(td->td_proc);
#endif
/*
@@ -672,10 +674,12 @@ shmget_allocate_segment(struct thread *td, struct shmget_args *uap, int mode)
0, size, VM_PROT_DEFAULT, 0, cred);
if (shm_object == NULL) {
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- racct_sub(td->td_proc, RACCT_NSHM, 1);
- racct_sub(td->td_proc, RACCT_SHMSIZE, size);
- PROC_UNLOCK(td->td_proc);
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ racct_sub(td->td_proc, RACCT_NSHM, 1);
+ racct_sub(td->td_proc, RACCT_SHMSIZE, size);
+ PROC_UNLOCK(td->td_proc);
+ }
#endif
return (ENOMEM);
}
@@ -961,39 +965,39 @@ oshmctl(struct thread *td, struct oshmctl_args *uap)
if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
return (ENOSYS);
+ if (uap->cmd != IPC_STAT) {
+ return (freebsd7_shmctl(td,
+ (struct freebsd7_shmctl_args *)uap));
+ }
SYSVSHM_LOCK();
shmseg = shm_find_segment(uap->shmid, true);
if (shmseg == NULL) {
SYSVSHM_UNLOCK();
+ return (EINVAL);
+ }
+ error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
+ if (error != 0) {
+ SYSVSHM_UNLOCK();
return (error);
}
- switch (uap->cmd) {
- case IPC_STAT:
- error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
- if (error != 0)
- break;
#ifdef MAC
- error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg,
- uap->cmd);
- if (error != 0)
- break;
-#endif
- ipcperm_new2old(&shmseg->u.shm_perm, &outbuf.shm_perm);
- outbuf.shm_segsz = shmseg->u.shm_segsz;
- outbuf.shm_cpid = shmseg->u.shm_cpid;
- outbuf.shm_lpid = shmseg->u.shm_lpid;
- outbuf.shm_nattch = shmseg->u.shm_nattch;
- outbuf.shm_atime = shmseg->u.shm_atime;
- outbuf.shm_dtime = shmseg->u.shm_dtime;
- outbuf.shm_ctime = shmseg->u.shm_ctime;
- outbuf.shm_handle = shmseg->object;
- error = copyout(&outbuf, uap->ubuf, sizeof(outbuf));
- break;
- default:
- error = freebsd7_shmctl(td, (struct freebsd7_shmctl_args *)uap);
- break;
+ error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, uap->cmd);
+ if (error != 0) {
+ SYSVSHM_UNLOCK();
+ return (error);
}
+#endif
+ ipcperm_new2old(&shmseg->u.shm_perm, &outbuf.shm_perm);
+ outbuf.shm_segsz = shmseg->u.shm_segsz;
+ outbuf.shm_cpid = shmseg->u.shm_cpid;
+ outbuf.shm_lpid = shmseg->u.shm_lpid;
+ outbuf.shm_nattch = shmseg->u.shm_nattch;
+ outbuf.shm_atime = shmseg->u.shm_atime;
+ outbuf.shm_dtime = shmseg->u.shm_dtime;
+ outbuf.shm_ctime = shmseg->u.shm_ctime;
+ outbuf.shm_handle = shmseg->object;
SYSVSHM_UNLOCK();
+ error = copyout(&outbuf, uap->ubuf, sizeof(outbuf));
return (error);
#else
return (EINVAL);
@@ -1025,9 +1029,7 @@ sys_shmsys(struct thread *td, struct shmsys_args *uap)
return (ENOSYS);
if (uap->which < 0 || uap->which >= nitems(shmcalls))
return (EINVAL);
- SYSVSHM_LOCK();
error = (*shmcalls[uap->which])(td, &uap->a2);
- SYSVSHM_UNLOCK();
return (error);
}
diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c
index 0833362..2d1e8fe 100644
--- a/sys/kern/tty_pts.c
+++ b/sys/kern/tty_pts.c
@@ -845,7 +845,7 @@ sys_posix_openpt(struct thread *td, struct posix_openpt_args *uap)
/* Allocate the actual pseudo-TTY. */
error = pts_alloc(FFLAGS(uap->flags & O_ACCMODE), td, fp);
if (error != 0) {
- fdclose(td->td_proc->p_fd, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
return (error);
}
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index e3fb149..0589f4a 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -2022,7 +2022,7 @@ kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode,
if (error) {
sx_xunlock(&mqfs_data.mi_lock);
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
return (error);
}
diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c
index 935a245..dbfa28a 100644
--- a/sys/kern/uipc_sem.c
+++ b/sys/kern/uipc_sem.c
@@ -471,7 +471,7 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
*/
error = ksem_create_copyout_semid(td, semidp, fd, compat32);
if (error) {
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
return (error);
}
@@ -491,7 +491,7 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
if (error == 0 && path[0] != '/')
error = EINVAL;
if (error) {
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
free(path, M_KSEM);
return (error);
@@ -542,7 +542,7 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
if (error) {
KASSERT(ks == NULL, ("ksem_create error with a ksem"));
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
return (error);
}
diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index 1df89ad..93c7ed1 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -163,6 +163,17 @@ uiomove_object_page(vm_object_t obj, size_t len, struct uio *uio)
VM_OBJECT_WLOCK(obj);
/*
+ * Read I/O without either a corresponding resident page or swap
+ * page: use zero_region. This is intended to avoid instantiating
+ * pages on read from a sparse region.
+ */
+ if (uio->uio_rw == UIO_READ && vm_page_lookup(obj, idx) == NULL &&
+ !vm_pager_has_page(obj, idx, NULL, NULL)) {
+ VM_OBJECT_WUNLOCK(obj);
+ return (uiomove(__DECONST(void *, zero_region), tlen, uio));
+ }
+
+ /*
* Parallel reads of the page content from disk are prevented
* by exclusive busy.
*
@@ -718,7 +729,7 @@ sys_shm_open(struct thread *td, struct shm_open_args *uap)
if (uap->path == SHM_ANON) {
/* A read-only anonymous object is pointless. */
if ((uap->flags & O_ACCMODE) == O_RDONLY) {
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
return (EINVAL);
}
@@ -734,7 +745,7 @@ sys_shm_open(struct thread *td, struct shm_open_args *uap)
if (error == 0 && path[0] != '/')
error = EINVAL;
if (error) {
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
free(path, M_SHMFD);
return (error);
@@ -800,7 +811,7 @@ sys_shm_open(struct thread *td, struct shm_open_args *uap)
sx_xunlock(&shm_dict_lock);
if (error) {
- fdclose(fdp, fp, fd, td);
+ fdclose(td, fp, fd);
fdrop(fp, td);
return (error);
}
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index a326a02..1efe3da 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -150,17 +150,17 @@ SYSCTL_PROC(_kern_ipc, OID_AUTO, sfstat, CTLTYPE_OPAQUE | CTLFLAG_RW,
* A reference on the file entry is held upon returning.
*/
int
-getsock_cap(struct filedesc *fdp, int fd, cap_rights_t *rightsp,
+getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
struct file **fpp, u_int *fflagp)
{
struct file *fp;
int error;
- error = fget_unlocked(fdp, fd, rightsp, &fp, NULL);
+ error = fget_unlocked(td->td_proc->p_fd, fd, rightsp, &fp, NULL);
if (error != 0)
return (error);
if (fp->f_type != DTYPE_SOCKET) {
- fdrop(fp, curthread);
+ fdrop(fp, td);
return (ENOTSOCK);
}
if (fflagp != NULL)
@@ -216,7 +216,7 @@ sys_socket(td, uap)
error = socreate(uap->domain, &so, type, uap->protocol,
td->td_ucred, td);
if (error != 0) {
- fdclose(td->td_proc->p_fd, fp, fd, td);
+ fdclose(td, fp, fd);
} else {
finit(fp, FREAD | FWRITE | fflag, DTYPE_SOCKET, so, &socketops);
if ((fflag & FNONBLOCK) != 0)
@@ -258,8 +258,8 @@ kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
- error = getsock_cap(td->td_proc->p_fd, fd,
- cap_rights_init(&rights, CAP_BIND), &fp, NULL);
+ error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_BIND),
+ &fp, NULL);
if (error != 0)
return (error);
so = fp->f_data;
@@ -319,8 +319,8 @@ sys_listen(td, uap)
int error;
AUDIT_ARG_FD(uap->s);
- error = getsock_cap(td->td_proc->p_fd, uap->s,
- cap_rights_init(&rights, CAP_LISTEN), &fp, NULL);
+ error = getsock_cap(td, uap->s, cap_rights_init(&rights, CAP_LISTEN),
+ &fp, NULL);
if (error == 0) {
so = fp->f_data;
#ifdef MAC
@@ -373,7 +373,7 @@ accept1(td, s, uname, anamelen, flags)
error = copyout(&namelen, anamelen,
sizeof(namelen));
if (error != 0)
- fdclose(td->td_proc->p_fd, fp, td->td_retval[0], td);
+ fdclose(td, fp, td->td_retval[0]);
fdrop(fp, td);
free(name, M_SONAME);
return (error);
@@ -390,7 +390,6 @@ int
kern_accept4(struct thread *td, int s, struct sockaddr **name,
socklen_t *namelen, int flags, struct file **fp)
{
- struct filedesc *fdp;
struct file *headfp, *nfp = NULL;
struct sockaddr *sa = NULL;
struct socket *head, *so;
@@ -403,8 +402,7 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name,
*name = NULL;
AUDIT_ARG_FD(s);
- fdp = td->td_proc->p_fd;
- error = getsock_cap(fdp, s, cap_rights_init(&rights, CAP_ACCEPT),
+ error = getsock_cap(td, s, cap_rights_init(&rights, CAP_ACCEPT),
&headfp, &fflag);
if (error != 0)
return (error);
@@ -520,7 +518,7 @@ noconnection:
* out from under us.
*/
if (error != 0)
- fdclose(fdp, nfp, fd, td);
+ fdclose(td, nfp, fd);
/*
* Release explicitly held references before returning. We return
@@ -604,8 +602,8 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
- error = getsock_cap(td->td_proc->p_fd, fd,
- cap_rights_init(&rights, CAP_CONNECT), &fp, NULL);
+ error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_CONNECT),
+ &fp, NULL);
if (error != 0)
return (error);
so = fp->f_data;
@@ -683,7 +681,6 @@ int
kern_socketpair(struct thread *td, int domain, int type, int protocol,
int *rsv)
{
- struct filedesc *fdp = td->td_proc->p_fd;
struct file *fp1, *fp2;
struct socket *so1, *so2;
int fd, error, oflag, fflag;
@@ -747,10 +744,10 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol,
fdrop(fp2, td);
return (0);
free4:
- fdclose(fdp, fp2, rsv[1], td);
+ fdclose(td, fp2, rsv[1]);
fdrop(fp2, td);
free3:
- fdclose(fdp, fp1, rsv[0], td);
+ fdclose(td, fp1, rsv[0]);
fdrop(fp1, td);
free2:
if (so2 != NULL)
@@ -866,7 +863,7 @@ kern_sendit(td, s, mp, flags, control, segflg)
AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name);
cap_rights_set(&rights, CAP_CONNECT);
}
- error = getsock_cap(td->td_proc->p_fd, s, &rights, &fp, NULL);
+ error = getsock_cap(td, s, &rights, &fp, NULL);
if (error != 0)
return (error);
so = (struct socket *)fp->f_data;
@@ -1066,8 +1063,8 @@ kern_recvit(td, s, mp, fromseg, controlp)
*controlp = NULL;
AUDIT_ARG_FD(s);
- error = getsock_cap(td->td_proc->p_fd, s,
- cap_rights_init(&rights, CAP_RECV), &fp, NULL);
+ error = getsock_cap(td, s, cap_rights_init(&rights, CAP_RECV),
+ &fp, NULL);
if (error != 0)
return (error);
so = fp->f_data;
@@ -1381,8 +1378,8 @@ sys_shutdown(td, uap)
int error;
AUDIT_ARG_FD(uap->s);
- error = getsock_cap(td->td_proc->p_fd, uap->s,
- cap_rights_init(&rights, CAP_SHUTDOWN), &fp, NULL);
+ error = getsock_cap(td, uap->s, cap_rights_init(&rights, CAP_SHUTDOWN),
+ &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = soshutdown(so, uap->how);
@@ -1446,8 +1443,8 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize)
}
AUDIT_ARG_FD(s);
- error = getsock_cap(td->td_proc->p_fd, s,
- cap_rights_init(&rights, CAP_SETSOCKOPT), &fp, NULL);
+ error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SETSOCKOPT),
+ &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sosetopt(so, &sopt);
@@ -1527,8 +1524,8 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize)
}
AUDIT_ARG_FD(s);
- error = getsock_cap(td->td_proc->p_fd, s,
- cap_rights_init(&rights, CAP_GETSOCKOPT), &fp, NULL);
+ error = getsock_cap(td, s, cap_rights_init(&rights, CAP_GETSOCKOPT),
+ &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sogetopt(so, &sopt);
@@ -1588,8 +1585,8 @@ kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
int error;
AUDIT_ARG_FD(fd);
- error = getsock_cap(td->td_proc->p_fd, fd,
- cap_rights_init(&rights, CAP_GETSOCKNAME), &fp, NULL);
+ error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETSOCKNAME),
+ &fp, NULL);
if (error != 0)
return (error);
so = fp->f_data;
@@ -1687,8 +1684,8 @@ kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
int error;
AUDIT_ARG_FD(fd);
- error = getsock_cap(td->td_proc->p_fd, fd,
- cap_rights_init(&rights, CAP_GETPEERNAME), &fp, NULL);
+ error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETPEERNAME),
+ &fp, NULL);
if (error != 0)
return (error);
so = fp->f_data;
@@ -2154,8 +2151,8 @@ kern_sendfile_getsock(struct thread *td, int s, struct file **sock_fp,
/*
* The socket must be a stream socket and connected.
*/
- error = getsock_cap(td->td_proc->p_fd, s, cap_rights_init(&rights,
- CAP_SEND), sock_fp, NULL);
+ error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SEND),
+ sock_fp, NULL);
if (error != 0)
return (error);
*so = (*sock_fp)->f_data;
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index c7e602e..0bfcf2d 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -59,10 +59,12 @@ __FBSDID("$FreeBSD$");
#include <sys/conf.h>
#include <sys/event.h>
#include <sys/mount.h>
+#include <geom/geom.h>
#include <machine/atomic.h>
#include <vm/vm.h>
+#include <vm/vm_page.h>
#include <vm/vm_extern.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
@@ -232,9 +234,10 @@ struct aiocblist {
int jobstate; /* (b) job state */
int inputcharge; /* (*) input blockes */
int outputcharge; /* (*) output blockes */
- struct buf *bp; /* (*) private to BIO backend,
- * buffer pointer
- */
+ struct bio *bp; /* (*) BIO backend BIO pointer */
+ struct buf *pbuf; /* (*) BIO backend buffer pointer */
+ struct vm_page *pages[btoc(MAXPHYS)+1]; /* BIO backend pages */
+ int npages; /* BIO backend number of pages */
struct proc *userproc; /* (*) user process */
struct ucred *cred; /* (*) active credential when created */
struct file *fd_file; /* (*) pointer to file structure */
@@ -243,7 +246,6 @@ struct aiocblist {
struct knlist klist; /* (a) list of knotes */
struct aiocb uaiocb; /* (*) kernel I/O control block */
ksiginfo_t ksi; /* (a) realtime signal info */
- struct task biotask; /* (*) private to BIO backend */
uint64_t seqno; /* (*) job number */
int pending; /* (a) number of pending I/O, aio_fsync only */
};
@@ -344,11 +346,10 @@ static void aio_process_mlock(struct aiocblist *aiocbe);
static int aio_newproc(int *);
int aio_aqueue(struct thread *td, struct aiocb *job,
struct aioliojob *lio, int type, struct aiocb_ops *ops);
-static void aio_physwakeup(struct buf *bp);
+static void aio_physwakeup(struct bio *bp);
static void aio_proc_rundown(void *arg, struct proc *p);
static void aio_proc_rundown_exec(void *arg, struct proc *p, struct image_params *imgp);
static int aio_qphysio(struct proc *p, struct aiocblist *iocb);
-static void biohelper(void *, int);
static void aio_daemon(void *param);
static void aio_swake_cb(struct socket *, struct sockbuf *);
static int aio_unload(void);
@@ -1294,13 +1295,15 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
{
struct aiocb *cb;
struct file *fp;
- struct buf *bp;
+ struct bio *bp;
+ struct buf *pbuf;
struct vnode *vp;
struct cdevsw *csw;
struct cdev *dev;
struct kaioinfo *ki;
struct aioliojob *lj;
- int error, ref;
+ int error, ref, unmap, poff;
+ vm_prot_t prot;
cb = &aiocbe->uaiocb;
fp = aiocbe->fd_file;
@@ -1309,107 +1312,121 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
return (-1);
vp = fp->f_vnode;
-
- /*
- * If its not a disk, we don't want to return a positive error.
- * It causes the aio code to not fall through to try the thread
- * way when you're talking to a regular file.
- */
- if (!vn_isdisk(vp, &error)) {
- if (error == ENOTBLK)
- return (-1);
- else
- return (error);
- }
-
- if (vp->v_bufobj.bo_bsize == 0)
- return (-1);
-
- if (cb->aio_nbytes % vp->v_bufobj.bo_bsize)
+ if (vp->v_type != VCHR)
return (-1);
-
- if (cb->aio_nbytes >
- MAXPHYS - (((vm_offset_t) cb->aio_buf) & PAGE_MASK))
+ if (vp->v_bufobj.bo_bsize == 0)
return (-1);
-
- ki = p->p_aioinfo;
- if (ki->kaio_buffer_count >= ki->kaio_ballowed_count)
+ if (cb->aio_nbytes % vp->v_bufobj.bo_bsize)
return (-1);
ref = 0;
csw = devvn_refthread(vp, &dev, &ref);
if (csw == NULL)
return (ENXIO);
+
+ if ((csw->d_flags & D_DISK) == 0) {
+ error = -1;
+ goto unref;
+ }
if (cb->aio_nbytes > dev->si_iosize_max) {
error = -1;
goto unref;
}
- /* Create and build a buffer header for a transfer. */
- bp = (struct buf *)getpbuf(NULL);
- BUF_KERNPROC(bp);
+ ki = p->p_aioinfo;
+ poff = (vm_offset_t)cb->aio_buf & PAGE_MASK;
+ unmap = ((dev->si_flags & SI_UNMAPPED) && unmapped_buf_allowed);
+ if (unmap) {
+ if (cb->aio_nbytes > MAXPHYS) {
+ error = -1;
+ goto unref;
+ }
+ } else {
+ if (cb->aio_nbytes > MAXPHYS - poff) {
+ error = -1;
+ goto unref;
+ }
+ if (ki->kaio_buffer_count >= ki->kaio_ballowed_count) {
+ error = -1;
+ goto unref;
+ }
+ }
+ aiocbe->bp = bp = g_alloc_bio();
+ if (!unmap) {
+ aiocbe->pbuf = pbuf = (struct buf *)getpbuf(NULL);
+ BUF_KERNPROC(pbuf);
+ }
AIO_LOCK(ki);
ki->kaio_count++;
- ki->kaio_buffer_count++;
+ if (!unmap)
+ ki->kaio_buffer_count++;
lj = aiocbe->lio;
if (lj)
lj->lioj_count++;
- AIO_UNLOCK(ki);
-
- /*
- * Get a copy of the kva from the physical buffer.
- */
- error = 0;
-
- bp->b_bcount = cb->aio_nbytes;
- bp->b_bufsize = cb->aio_nbytes;
- bp->b_iodone = aio_physwakeup;
- bp->b_saveaddr = bp->b_data;
- bp->b_data = (void *)(uintptr_t)cb->aio_buf;
- bp->b_offset = cb->aio_offset;
- bp->b_iooffset = cb->aio_offset;
- bp->b_blkno = btodb(cb->aio_offset);
- bp->b_iocmd = cb->aio_lio_opcode == LIO_WRITE ? BIO_WRITE : BIO_READ;
-
- /*
- * Bring buffer into kernel space.
- */
- if (vmapbuf(bp, (dev->si_flags & SI_UNMAPPED) == 0) < 0) {
- error = EFAULT;
- goto doerror;
- }
-
- AIO_LOCK(ki);
- aiocbe->bp = bp;
- bp->b_caller1 = (void *)aiocbe;
TAILQ_INSERT_TAIL(&ki->kaio_bufqueue, aiocbe, plist);
TAILQ_INSERT_TAIL(&ki->kaio_all, aiocbe, allist);
aiocbe->jobstate = JOBST_JOBQBUF;
cb->_aiocb_private.status = cb->aio_nbytes;
AIO_UNLOCK(ki);
- atomic_add_int(&num_queue_count, 1);
- atomic_add_int(&num_buf_aio, 1);
-
- bp->b_error = 0;
+ bp->bio_length = cb->aio_nbytes;
+ bp->bio_bcount = cb->aio_nbytes;
+ bp->bio_done = aio_physwakeup;
+ bp->bio_data = (void *)(uintptr_t)cb->aio_buf;
+ bp->bio_offset = cb->aio_offset;
+ bp->bio_cmd = cb->aio_lio_opcode == LIO_WRITE ? BIO_WRITE : BIO_READ;
+ bp->bio_dev = dev;
+ bp->bio_caller1 = (void *)aiocbe;
+
+ prot = VM_PROT_READ;
+ if (cb->aio_lio_opcode == LIO_READ)
+ prot |= VM_PROT_WRITE; /* Less backwards than it looks */
+ if ((aiocbe->npages = vm_fault_quick_hold_pages(
+ &curproc->p_vmspace->vm_map,
+ (vm_offset_t)bp->bio_data, bp->bio_length, prot, aiocbe->pages,
+ sizeof(aiocbe->pages)/sizeof(aiocbe->pages[0]))) < 0) {
+ error = EFAULT;
+ goto doerror;
+ }
+ if (!unmap) {
+ pmap_qenter((vm_offset_t)pbuf->b_data,
+ aiocbe->pages, aiocbe->npages);
+ bp->bio_data = pbuf->b_data + poff;
+ } else {
+ bp->bio_ma = aiocbe->pages;
+ bp->bio_ma_n = aiocbe->npages;
+ bp->bio_ma_offset = poff;
+ bp->bio_data = unmapped_buf;
+ bp->bio_flags |= BIO_UNMAPPED;
+ }
- TASK_INIT(&aiocbe->biotask, 0, biohelper, aiocbe);
+ atomic_add_int(&num_queue_count, 1);
+ if (!unmap)
+ atomic_add_int(&num_buf_aio, 1);
/* Perform transfer. */
- dev_strategy_csw(dev, csw, bp);
+ csw->d_strategy(bp);
dev_relthread(dev, ref);
return (0);
doerror:
AIO_LOCK(ki);
+ aiocbe->jobstate = JOBST_NULL;
+ TAILQ_REMOVE(&ki->kaio_bufqueue, aiocbe, plist);
+ TAILQ_REMOVE(&ki->kaio_all, aiocbe, allist);
ki->kaio_count--;
- ki->kaio_buffer_count--;
+ if (!unmap)
+ ki->kaio_buffer_count--;
if (lj)
lj->lioj_count--;
- aiocbe->bp = NULL;
AIO_UNLOCK(ki);
- relpbuf(bp, NULL);
+ if (pbuf) {
+ relpbuf(pbuf, NULL);
+ aiocbe->pbuf = NULL;
+ }
+ g_destroy_bio(bp);
+ aiocbe->bp = NULL;
unref:
dev_relthread(dev, ref);
return (error);
@@ -1787,8 +1804,6 @@ no_kqueue:
}
#endif
queueit:
- /* No buffer for daemon I/O. */
- aiocbe->bp = NULL;
atomic_add_int(&num_queue_count, 1);
AIO_LOCK(ki);
@@ -2425,54 +2440,43 @@ sys_lio_listio(struct thread *td, struct lio_listio_args *uap)
return (error);
}
-/*
- * Called from interrupt thread for physio, we should return as fast
- * as possible, so we schedule a biohelper task.
- */
static void
-aio_physwakeup(struct buf *bp)
+aio_physwakeup(struct bio *bp)
{
- struct aiocblist *aiocbe;
-
- aiocbe = (struct aiocblist *)bp->b_caller1;
- taskqueue_enqueue(taskqueue_aiod_bio, &aiocbe->biotask);
-}
-
-/*
- * Task routine to perform heavy tasks, process wakeup, and signals.
- */
-static void
-biohelper(void *context, int pending)
-{
- struct aiocblist *aiocbe = context;
- struct buf *bp;
+ struct aiocblist *aiocbe = (struct aiocblist *)bp->bio_caller1;
struct proc *userp;
struct kaioinfo *ki;
int nblks;
+ /* Release mapping into kernel space. */
+ if (aiocbe->pbuf) {
+ pmap_qremove((vm_offset_t)aiocbe->pbuf->b_data, aiocbe->npages);
+ relpbuf(aiocbe->pbuf, NULL);
+ aiocbe->pbuf = NULL;
+ atomic_subtract_int(&num_buf_aio, 1);
+ }
+ vm_page_unhold_pages(aiocbe->pages, aiocbe->npages);
+
bp = aiocbe->bp;
+ aiocbe->bp = NULL;
userp = aiocbe->userproc;
ki = userp->p_aioinfo;
AIO_LOCK(ki);
- aiocbe->uaiocb._aiocb_private.status -= bp->b_resid;
+ aiocbe->uaiocb._aiocb_private.status -= bp->bio_resid;
aiocbe->uaiocb._aiocb_private.error = 0;
- if (bp->b_ioflags & BIO_ERROR)
- aiocbe->uaiocb._aiocb_private.error = bp->b_error;
+ if (bp->bio_flags & BIO_ERROR)
+ aiocbe->uaiocb._aiocb_private.error = bp->bio_error;
nblks = btodb(aiocbe->uaiocb.aio_nbytes);
if (aiocbe->uaiocb.aio_lio_opcode == LIO_WRITE)
aiocbe->outputcharge += nblks;
else
aiocbe->inputcharge += nblks;
- aiocbe->bp = NULL;
TAILQ_REMOVE(&userp->p_aioinfo->kaio_bufqueue, aiocbe, plist);
ki->kaio_buffer_count--;
aio_bio_done_notify(userp, aiocbe, DONE_BUF);
AIO_UNLOCK(ki);
- /* Release mapping into kernel space. */
- vunmapbuf(bp);
- relpbuf(bp, NULL);
- atomic_subtract_int(&num_buf_aio, 1);
+ g_destroy_bio(bp);
}
/* syscall - wait for the next completion of an aio request */
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index dfe2997..5ac04ac 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -113,8 +113,8 @@ static void vfs_setdirty_locked_object(struct buf *bp);
static void vfs_vmio_release(struct buf *bp);
static int vfs_bio_clcheck(struct vnode *vp, int size,
daddr_t lblkno, daddr_t blkno);
-static int buf_flush(int);
-static int flushbufqueues(int, int);
+static int buf_flush(struct vnode *vp, int);
+static int flushbufqueues(struct vnode *, int, int);
static void buf_daemon(void);
static void bremfreel(struct buf *bp);
static __inline void bd_wakeup(void);
@@ -805,6 +805,7 @@ bufinit(void)
struct buf *bp;
int i;
+ CTASSERT(MAXBCACHEBUF >= MAXBSIZE);
mtx_init(&bqclean, "bufq clean lock", NULL, MTX_DEF);
mtx_init(&bqdirty, "bufq dirty lock", NULL, MTX_DEF);
mtx_init(&rbreqlock, "runningbufspace lock", NULL, MTX_DEF);
@@ -846,8 +847,8 @@ bufinit(void)
* by the system.
*/
maxbufspace = (long)nbuf * BKVASIZE;
- hibufspace = lmax(3 * maxbufspace / 4, maxbufspace - MAXBSIZE * 10);
- lobufspace = hibufspace - MAXBSIZE;
+ hibufspace = lmax(3 * maxbufspace / 4, maxbufspace - MAXBCACHEBUF * 10);
+ lobufspace = hibufspace - MAXBCACHEBUF;
/*
* Note: The 16 MiB upper limit for hirunningspace was chosen
@@ -857,9 +858,9 @@ bufinit(void)
* The lower 1 MiB limit is the historical upper limit for
* hirunningspace.
*/
- hirunningspace = lmax(lmin(roundup(hibufspace / 64, MAXBSIZE),
+ hirunningspace = lmax(lmin(roundup(hibufspace / 64, MAXBCACHEBUF),
16 * 1024 * 1024), 1024 * 1024);
- lorunningspace = roundup((hirunningspace * 2) / 3, MAXBSIZE);
+ lorunningspace = roundup((hirunningspace * 2) / 3, MAXBCACHEBUF);
/*
* Limit the amount of malloc memory since it is wired permanently into
@@ -2096,7 +2097,7 @@ getnewbuf_bufd_help(struct vnode *vp, int gbflags, int slpflag, int slptimeo,
{
struct thread *td;
char *waitmsg;
- int cnt, error, flags, norunbuf, wait;
+ int error, fl, flags, norunbuf;
mtx_assert(&bqclean, MA_OWNED);
@@ -2118,8 +2119,6 @@ getnewbuf_bufd_help(struct vnode *vp, int gbflags, int slpflag, int slptimeo,
return;
td = curthread;
- cnt = 0;
- wait = MNT_NOWAIT;
rw_wlock(&nblock);
while ((needsbuffer & flags) != 0) {
if (vp != NULL && vp->v_type != VCHR &&
@@ -2133,20 +2132,23 @@ getnewbuf_bufd_help(struct vnode *vp, int gbflags, int slpflag, int slptimeo,
* cannot be achieved by the buf_daemon, that
* cannot lock the vnode.
*/
- if (cnt++ > 2)
- wait = MNT_WAIT;
- ASSERT_VOP_LOCKED(vp, "bufd_helper");
- error = VOP_ISLOCKED(vp) == LK_EXCLUSIVE ? 0 :
- vn_lock(vp, LK_TRYUPGRADE);
- if (error == 0) {
- /* play bufdaemon */
- norunbuf = curthread_pflags_set(TDP_BUFNEED |
- TDP_NORUNNINGBUF);
- VOP_FSYNC(vp, wait, td);
- atomic_add_long(&notbufdflushes, 1);
- curthread_pflags_restore(norunbuf);
- }
+ norunbuf = ~(TDP_BUFNEED | TDP_NORUNNINGBUF) |
+ (td->td_pflags & TDP_NORUNNINGBUF);
+
+ /*
+ * Play bufdaemon. The getnewbuf() function
+ * may be called while the thread owns lock
+ * for another dirty buffer for the same
+ * vnode, which makes it impossible to use
+ * VOP_FSYNC() there, due to the buffer lock
+ * recursion.
+ */
+ td->td_pflags |= TDP_BUFNEED | TDP_NORUNNINGBUF;
+ fl = buf_flush(vp, flushbufqtarget);
+ td->td_pflags &= norunbuf;
rw_wlock(&nblock);
+ if (fl != 0)
+ continue;
if ((needsbuffer & flags) == 0)
break;
}
@@ -2565,18 +2567,20 @@ static struct kproc_desc buf_kp = {
SYSINIT(bufdaemon, SI_SUB_KTHREAD_BUF, SI_ORDER_FIRST, kproc_start, &buf_kp);
static int
-buf_flush(int target)
+buf_flush(struct vnode *vp, int target)
{
int flushed;
- flushed = flushbufqueues(target, 0);
+ flushed = flushbufqueues(vp, target, 0);
if (flushed == 0) {
/*
* Could not find any buffers without rollback
* dependencies, so just write the first one
* in the hopes of eventually making progress.
*/
- flushed = flushbufqueues(target, 1);
+ if (vp != NULL && target > 2)
+ target /= 2;
+ flushbufqueues(vp, target, 1);
}
return (flushed);
}
@@ -2613,7 +2617,7 @@ buf_daemon()
* the I/O system.
*/
while (numdirtybuffers > lodirty) {
- if (buf_flush(numdirtybuffers - lodirty) == 0)
+ if (buf_flush(NULL, numdirtybuffers - lodirty) == 0)
break;
kern_yield(PRI_USER);
}
@@ -2668,7 +2672,7 @@ SYSCTL_INT(_vfs, OID_AUTO, flushwithdeps, CTLFLAG_RW, &flushwithdeps,
0, "Number of buffers flushed with dependecies that require rollbacks");
static int
-flushbufqueues(int target, int flushdeps)
+flushbufqueues(struct vnode *lvp, int target, int flushdeps)
{
struct buf *sentinel;
struct vnode *vp;
@@ -2678,6 +2682,7 @@ flushbufqueues(int target, int flushdeps)
int flushed;
int queue;
int error;
+ bool unlock;
flushed = 0;
queue = QUEUE_DIRTY;
@@ -2699,8 +2704,18 @@ flushbufqueues(int target, int flushdeps)
mtx_unlock(&bqdirty);
break;
}
- KASSERT(bp->b_qindex != QUEUE_SENTINEL,
- ("parallel calls to flushbufqueues() bp %p", bp));
+ /*
+ * Skip sentinels inserted by other invocations of the
+ * flushbufqueues(), taking care to not reorder them.
+ *
+ * Only flush the buffers that belong to the
+ * vnode locked by the curthread.
+ */
+ if (bp->b_qindex == QUEUE_SENTINEL || (lvp != NULL &&
+ bp->b_vp != lvp)) {
+ mtx_unlock(&bqdirty);
+ continue;
+ }
error = BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL);
mtx_unlock(&bqdirty);
if (error != 0)
@@ -2748,16 +2763,37 @@ flushbufqueues(int target, int flushdeps)
BUF_UNLOCK(bp);
continue;
}
- error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT);
+ if (lvp == NULL) {
+ unlock = true;
+ error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT);
+ } else {
+ ASSERT_VOP_LOCKED(vp, "getbuf");
+ unlock = false;
+ error = VOP_ISLOCKED(vp) == LK_EXCLUSIVE ? 0 :
+ vn_lock(vp, LK_TRYUPGRADE);
+ }
if (error == 0) {
CTR3(KTR_BUF, "flushbufqueue(%p) vp %p flags %X",
bp, bp->b_vp, bp->b_flags);
- vfs_bio_awrite(bp);
+ if (curproc == bufdaemonproc) {
+ vfs_bio_awrite(bp);
+ } else {
+ bremfree(bp);
+ bwrite(bp);
+ notbufdflushes++;
+ }
vn_finished_write(mp);
- VOP_UNLOCK(vp, 0);
+ if (unlock)
+ VOP_UNLOCK(vp, 0);
flushwithdeps += hasdeps;
flushed++;
- if (runningbufspace > hirunningspace)
+
+ /*
+ * Sleeping on runningbufspace while holding
+ * vnode lock leads to deadlock.
+ */
+ if (curproc == bufdaemonproc &&
+ runningbufspace > hirunningspace)
waitrunningbufspace();
continue;
}
@@ -3073,8 +3109,9 @@ getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo,
KASSERT((flags & (GB_UNMAPPED | GB_KVAALLOC)) != GB_KVAALLOC,
("GB_KVAALLOC only makes sense with GB_UNMAPPED"));
ASSERT_VOP_LOCKED(vp, "getblk");
- if (size > MAXBSIZE)
- panic("getblk: size(%d) > MAXBSIZE(%d)\n", size, MAXBSIZE);
+ if (size > MAXBCACHEBUF)
+ panic("getblk: size(%d) > MAXBCACHEBUF(%d)\n", size,
+ MAXBCACHEBUF);
if (!unmapped_buf_allowed)
flags &= ~(GB_UNMAPPED | GB_KVAALLOC);
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index d57dc90..19ef783 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -323,29 +323,25 @@ static SYSCTL_NODE(_debug, OID_AUTO, hashstat, CTLFLAG_RW, NULL,
static int
sysctl_debug_hashstat_rawnchash(SYSCTL_HANDLER_ARGS)
{
- int error;
struct nchashhead *ncpp;
struct namecache *ncp;
- int n_nchash;
- int count;
+ int i, error, n_nchash, *cntbuf;
n_nchash = nchash + 1; /* nchash is max index, not count */
- if (!req->oldptr)
+ if (req->oldptr == NULL)
return SYSCTL_OUT(req, 0, n_nchash * sizeof(int));
-
- /* Scan hash tables for applicable entries */
- for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) {
- CACHE_RLOCK();
- count = 0;
- LIST_FOREACH(ncp, ncpp, nc_hash) {
- count++;
- }
- CACHE_RUNLOCK();
- error = SYSCTL_OUT(req, &count, sizeof(count));
- if (error)
- return (error);
- }
- return (0);
+ cntbuf = malloc(n_nchash * sizeof(int), M_TEMP, M_ZERO | M_WAITOK);
+ CACHE_RLOCK();
+ /* Scan hash tables counting entries */
+ for (ncpp = nchashtbl, i = 0; i < n_nchash; ncpp++, i++)
+ LIST_FOREACH(ncp, ncpp, nc_hash)
+ cntbuf[i]++;
+ CACHE_RUNLOCK();
+ for (error = 0, i = 0; i < n_nchash; i++)
+ if ((error = SYSCTL_OUT(req, &cntbuf[i], sizeof(int))) != 0)
+ break;
+ free(cntbuf, M_TEMP);
+ return (error);
}
SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnchash, CTLTYPE_INT|CTLFLAG_RD|
CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_rawnchash, "S,int",
@@ -363,6 +359,7 @@ sysctl_debug_hashstat_nchash(SYSCTL_HANDLER_ARGS)
if (!req->oldptr)
return SYSCTL_OUT(req, 0, 4 * sizeof(int));
+ CACHE_RLOCK();
n_nchash = nchash + 1; /* nchash is max index, not count */
used = 0;
maxlength = 0;
@@ -370,17 +367,16 @@ sysctl_debug_hashstat_nchash(SYSCTL_HANDLER_ARGS)
/* Scan hash tables for applicable entries */
for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) {
count = 0;
- CACHE_RLOCK();
LIST_FOREACH(ncp, ncpp, nc_hash) {
count++;
}
- CACHE_RUNLOCK();
if (count)
used++;
if (maxlength < count)
maxlength = count;
}
n_nchash = nchash + 1;
+ CACHE_RUNLOCK();
pct = (used * 100) / (n_nchash / 100);
error = SYSCTL_OUT(req, &n_nchash, sizeof(n_nchash));
if (error)
@@ -1057,11 +1053,13 @@ sys___getcwd(td, uap)
struct __getcwd_args *uap;
{
- return (kern___getcwd(td, uap->buf, UIO_USERSPACE, uap->buflen));
+ return (kern___getcwd(td, uap->buf, UIO_USERSPACE, uap->buflen,
+ MAXPATHLEN));
}
int
-kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen)
+kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen,
+ u_int path_max)
{
char *bp, *tmpbuf;
struct filedesc *fdp;
@@ -1072,8 +1070,8 @@ kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen)
return (ENODEV);
if (buflen < 2)
return (EINVAL);
- if (buflen > MAXPATHLEN)
- buflen = MAXPATHLEN;
+ if (buflen > path_max)
+ buflen = path_max;
tmpbuf = malloc(buflen, M_TEMP, M_WAITOK);
fdp = td->td_proc->p_fd;
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index fda80c9..8e34456 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -3147,6 +3147,7 @@ DB_SHOW_COMMAND(mount, db_show_mount)
MNT_KERN_FLAG(MNTK_VGONE_WAITER);
MNT_KERN_FLAG(MNTK_LOOKUP_EXCL_DOTDOT);
MNT_KERN_FLAG(MNTK_MARKER);
+ MNT_KERN_FLAG(MNTK_USES_BCACHE);
MNT_KERN_FLAG(MNTK_NOASYNC);
MNT_KERN_FLAG(MNTK_UNMOUNT);
MNT_KERN_FLAG(MNTK_MWAIT);
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 14be379..c5c479d 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -434,9 +434,14 @@ sys_getfsstat(td, uap)
int flags;
} */ *uap;
{
+ size_t count;
+ int error;
- return (kern_getfsstat(td, &uap->buf, uap->bufsize, UIO_USERSPACE,
- uap->flags));
+ error = kern_getfsstat(td, &uap->buf, uap->bufsize, &count,
+ UIO_USERSPACE, uap->flags);
+ if (error == 0)
+ td->td_retval[0] = count;
+ return (error);
}
/*
@@ -446,7 +451,7 @@ sys_getfsstat(td, uap)
*/
int
kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
- enum uio_seg bufseg, int flags)
+ size_t *countp, enum uio_seg bufseg, int flags)
{
struct mount *mp, *nmp;
struct statfs *sfsp, *sp, sb;
@@ -533,9 +538,9 @@ kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
}
mtx_unlock(&mountlist_mtx);
if (sfsp && count > maxcount)
- td->td_retval[0] = maxcount;
+ *countp = maxcount;
else
- td->td_retval[0] = count;
+ *countp = count;
return (0);
}
@@ -624,9 +629,9 @@ freebsd4_getfsstat(td, uap)
count = uap->bufsize / sizeof(struct ostatfs);
size = count * sizeof(struct statfs);
- error = kern_getfsstat(td, &buf, size, UIO_SYSSPACE, uap->flags);
+ error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE,
+ uap->flags);
if (size > 0) {
- count = td->td_retval[0];
sp = buf;
while (count > 0 && error == 0) {
cvtstatfs(sp, &osb);
@@ -637,6 +642,8 @@ freebsd4_getfsstat(td, uap)
}
free(buf, M_TEMP);
}
+ if (error == 0)
+ td->td_retval[0] = count;
return (error);
}
@@ -1926,6 +1933,7 @@ olseek(td, uap)
}
#endif /* COMPAT_43 */
+#if defined(COMPAT_FREEBSD6)
/* Version with the 'pad' argument */
int
freebsd6_lseek(td, uap)
@@ -1939,6 +1947,7 @@ freebsd6_lseek(td, uap)
ouap.whence = uap->whence;
return (sys_lseek(td, &ouap));
}
+#endif
/*
* Check access permissions using passed credentials.
@@ -3294,6 +3303,7 @@ kern_utimensat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
{
struct nameidata nd;
struct timespec ts[2];
+ cap_rights_t rights;
int error, flags;
if (flag & ~AT_SYMLINK_NOFOLLOW)
@@ -3301,8 +3311,9 @@ kern_utimensat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0)
return (error);
- NDINIT_AT(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
- FOLLOW) | AUDITVNODE1, pathseg, path, fd, td);
+ NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
+ FOLLOW) | AUDITVNODE1, pathseg, path, fd,
+ cap_rights_init(&rights, CAP_FUTIMES), td);
if ((error = namei(&nd)) != 0)
return (error);
/*
@@ -3414,6 +3425,7 @@ otruncate(td, uap)
}
#endif /* COMPAT_43 */
+#if defined(COMPAT_FREEBSD6)
/* Versions with the pad argument */
int
freebsd6_truncate(struct thread *td, struct freebsd6_truncate_args *uap)
@@ -3434,6 +3446,7 @@ freebsd6_ftruncate(struct thread *td, struct freebsd6_ftruncate_args *uap)
ouap.length = uap->length;
return (sys_ftruncate(td, &ouap));
}
+#endif
/*
* Sync an open file.
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index ed4ad4d..01d448e 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -306,9 +306,15 @@ vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
if ((fmode & O_APPEND) && (fmode & FWRITE))
accmode |= VAPPEND;
#ifdef MAC
+ if (fmode & O_CREAT)
+ accmode |= VCREAT;
+ if (fmode & O_VERIFY)
+ accmode |= VVERIFY;
error = mac_vnode_check_open(cred, vp, accmode);
if (error)
return (error);
+
+ accmode &= ~(VCREAT | VVERIFY);
#endif
if ((fmode & O_CREAT) == 0) {
if (accmode & VWRITE) {
diff --git a/sys/net/zlib.c b/sys/libkern/zlib.c
index b348248..f5c3854 100644
--- a/sys/net/zlib.c
+++ b/sys/libkern/zlib.c
@@ -54,7 +54,7 @@
#define _Z_UTIL_H
#ifdef _KERNEL
-#include <net/zlib.h>
+#include <sys/zlib.h>
#else
#include "zlib.h"
#endif
diff --git a/sys/mips/adm5120/uart_dev_adm5120.c b/sys/mips/adm5120/uart_dev_adm5120.c
index 5ec18c8..5c3e691 100644
--- a/sys/mips/adm5120/uart_dev_adm5120.c
+++ b/sys/mips/adm5120/uart_dev_adm5120.c
@@ -175,7 +175,8 @@ struct uart_class uart_adm5120_uart_class = {
sizeof(struct adm5120_uart_softc),
.uc_ops = &uart_adm5120_uart_ops,
.uc_range = 1, /* use hinted range */
- .uc_rclk = 62500000
+ .uc_rclk = 62500000,
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/mips/atheros/uart_dev_ar933x.c b/sys/mips/atheros/uart_dev_ar933x.c
index 7be92bc..e769cbe 100644
--- a/sys/mips/atheros/uart_dev_ar933x.c
+++ b/sys/mips/atheros/uart_dev_ar933x.c
@@ -351,7 +351,8 @@ struct uart_class uart_ar933x_class = {
sizeof(struct ar933x_softc),
.uc_ops = &uart_ar933x_ops,
.uc_range = 8,
- .uc_rclk = DEFAULT_RCLK
+ .uc_rclk = DEFAULT_RCLK,
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/mips/cavium/uart_dev_oct16550.c b/sys/mips/cavium/uart_dev_oct16550.c
index f3d47ca..cfb347f 100644
--- a/sys/mips/cavium/uart_dev_oct16550.c
+++ b/sys/mips/cavium/uart_dev_oct16550.c
@@ -424,7 +424,8 @@ struct uart_class uart_oct16550_class = {
sizeof(struct oct16550_softc),
.uc_ops = &uart_oct16550_ops,
.uc_range = 8 << 3,
- .uc_rclk = 0
+ .uc_rclk = 0,
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/mips/conf/CARAMBOLA2.hints b/sys/mips/conf/CARAMBOLA2.hints
index c7aac34..34f4865 100644
--- a/sys/mips/conf/CARAMBOLA2.hints
+++ b/sys/mips/conf/CARAMBOLA2.hints
@@ -98,19 +98,4 @@ hint.gpio.0.function_set=0x00000000
hint.gpio.0.function_clear=0x00000000
# These are the GPIO LEDs and buttons which can be software controlled.
-#hint.gpio.0.pinmask=0x001c02ae
-hint.gpio.0.pinmask=0x00001803
-
-# gpio0 - WLAN LED
-# gpio1 - USB LED
-# gpio11 - Jumpstart button
-# gpio12 - Reset button
-
-# LEDs are configured separately and driven by the LED device
-hint.gpioled.0.at="gpiobus0"
-hint.gpioled.0.name="wlan"
-hint.gpioled.0.pins=0x0001
-
-hint.gpioled.1.at="gpiobus0"
-hint.gpioled.1.name="usb"
-hint.gpioled.1.pins=0x0002
+hint.gpio.0.pinmask=0x00fc1803
diff --git a/sys/mips/conf/DIR-655A1.hints b/sys/mips/conf/DIR-655A1.hints
index 8e5756b..3946fd1 100644
--- a/sys/mips/conf/DIR-655A1.hints
+++ b/sys/mips/conf/DIR-655A1.hints
@@ -7,6 +7,32 @@
# QCA955X_ETH_CFG_RGMII_EN (1 << 0)
hint.qca955x_gmac.0.gmac_cfg=0x1
+# Use this to derive ath0 from arge0 MAC address.
+# 0x1ffe0004 is the arge0 MAC; but it's also the "unit MAC".
+# So make that the ath0 MAC, and make arge0 -1 from that.
+# ath0: offset 0
+# arge0: offset -1
+# arge1: use +1 from the arge0 MAC, even though
+# there's a secondary MAC address configured in EEPROM
+# at 0x1ffe0018.
+hint.ar71xx.0.eeprom_mac_addr=0x1ffe0004
+hint.ar71xx.0.eeprom_mac_isascii=1
+
+hint.ar71xx_mac_map.0.devid=ath
+hint.ar71xx_mac_map.0.unitid=0
+hint.ar71xx_mac_map.0.offset=0
+hint.ar71xx_mac_map.0.is_local=0
+
+hint.ar71xx_mac_map.1.devid=arge
+hint.ar71xx_mac_map.1.unitid=0
+hint.ar71xx_mac_map.1.offset=-1
+hint.ar71xx_mac_map.1.is_local=0
+
+hint.ar71xx_mac_map.2.devid=arge
+hint.ar71xx_mac_map.2.unitid=1
+hint.ar71xx_mac_map.2.offset=1
+hint.ar71xx_mac_map.2.is_local=0
+
# mdiobus0 on arge0
hint.argemdio.0.at="nexus0"
hint.argemdio.0.maddr=0x19000000
@@ -91,9 +117,8 @@ hint.arge.0.miimode=3 # RGMII
hint.arge.0.media=1000
hint.arge.0.fduplex=1
hint.arge.0.pll_1000=0x56000000
-
-# MAC for arge0 is the first 6 bytes of the ART
-hint.arge.0.eeprommac=0x1fff0000
+# hint.arge.0.eeprommac=0x1ffe0004
+# hint.arge.0.readascii=1
# arge1 - lock up to 1000/full
hint.arge.1.phymask=0x0
@@ -101,11 +126,12 @@ hint.arge.1.media=1000
hint.arge.1.fduplex=1
hint.arge.1.miimode=5 # SGMII
hint.arge.1.pll_1000=0x03000101
-
-# MAC for arge1 is the second 6 bytes of the ART
-hint.arge.1.eeprommac=0x1fff0006
+#hint.arge.1.eeprommac=0x1ffe0018
+#hint.arge.1.readascii=1
# ath0: Where the ART is - last 64k in the flash
+# Note: ath0 MAC is default (00:11:22:33:44:55) and thus
+# requires replacing via the board MAC address map.
hint.ath.0.eepromaddr=0x1fff0000
hint.ath.0.eepromsize=16384
diff --git a/sys/mips/conf/DIR-825C1.hints b/sys/mips/conf/DIR-825C1.hints
index 18ad6b8..7f19be6 100644
--- a/sys/mips/conf/DIR-825C1.hints
+++ b/sys/mips/conf/DIR-825C1.hints
@@ -1,13 +1,37 @@
# $FreeBSD$
-# This is a placeholder until the hardware support is complete.
-
# mdiobus0 on arge0
hint.argemdio.0.at="nexus0"
hint.argemdio.0.maddr=0x19000000
hint.argemdio.0.msize=0x1000
hint.argemdio.0.order=0
+# 0x1ffe0004 is the the "unit MAC".
+# 0x1ffe0018 is the second "MAC".
+# Right now this doesn't have any option for more than one
+# "unit MACs", so:
+# ath0: unit MAC
+# ath1: unit MAC + 1
+# arge0: unit MAC + 2
+# arge1: leave as default; not used.
+hint.ar71xx.0.eeprom_mac_addr=0x1ffe0004
+hint.ar71xx.0.eeprom_mac_isascii=1
+
+hint.ar71xx_mac_map.0.devid=ath
+hint.ar71xx_mac_map.0.unitid=0
+hint.ar71xx_mac_map.0.offset=0
+hint.ar71xx_mac_map.0.is_local=0
+
+hint.ar71xx_mac_map.1.devid=ath
+hint.ar71xx_mac_map.1.unitid=1
+hint.ar71xx_mac_map.1.offset=1
+hint.ar71xx_mac_map.1.is_local=0
+
+hint.ar71xx_mac_map.2.devid=arge
+hint.ar71xx_mac_map.2.unitid=0
+hint.ar71xx_mac_map.2.offset=2
+hint.ar71xx_mac_map.2.is_local=0
+
# DIR-825C1 GMAC configuration
# + AR934X_ETH_CFG_RGMII_GMAC0 (1 << 0)
# Onboard AR9344 10/100 switch is not wired up
diff --git a/sys/mips/include/reg.h b/sys/mips/include/reg.h
index c240506..0dc36c6 100644
--- a/sys/mips/include/reg.h
+++ b/sys/mips/include/reg.h
@@ -70,7 +70,7 @@ struct dbreg {
unsigned long junk;
};
-#ifdef COMPAT_FREEBSD32
+#ifdef __LP64__
/* Must match struct trapframe */
struct reg32 {
uint32_t r_regs[NUMSAVEREGS];
@@ -83,6 +83,8 @@ struct fpreg32 {
struct dbreg32 {
uint32_t junk;
};
+
+#define __HAVE_REG32
#endif
#ifdef _KERNEL
diff --git a/sys/mips/mips/busdma_machdep.c b/sys/mips/mips/busdma_machdep.c
index 083e8f5..90ec399 100644
--- a/sys/mips/mips/busdma_machdep.c
+++ b/sys/mips/mips/busdma_machdep.c
@@ -1359,8 +1359,8 @@ add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
/* Page offset needs to be preserved. */
- bpage->vaddr |= vaddr & PAGE_MASK;
- bpage->busaddr |= vaddr & PAGE_MASK;
+ bpage->vaddr |= addr & PAGE_MASK;
+ bpage->busaddr |= addr & PAGE_MASK;
}
bpage->datavaddr = vaddr;
bpage->dataaddr = addr;
diff --git a/sys/mips/rt305x/uart_dev_rt305x.c b/sys/mips/rt305x/uart_dev_rt305x.c
index d4f2319..5d23b1e 100644
--- a/sys/mips/rt305x/uart_dev_rt305x.c
+++ b/sys/mips/rt305x/uart_dev_rt305x.c
@@ -217,7 +217,8 @@ struct uart_class uart_rt305x_uart_class = {
sizeof(struct rt305x_uart_softc),
.uc_ops = &uart_rt305x_uart_ops,
.uc_range = 1, /* use hinted range */
- .uc_rclk = SYSTEM_CLOCK
+ .uc_rclk = SYSTEM_CLOCK,
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/modules/dtb/allwinner/Makefile b/sys/modules/dtb/allwinner/Makefile
new file mode 100644
index 0000000..705b597
--- /dev/null
+++ b/sys/modules/dtb/allwinner/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+# All the dts files for allwinner systems we support.
+DTS= \
+ cubieboard.dts \
+ cubieboard2.dts
+
+.include <bsd.dtb.mk>
diff --git a/sys/modules/ext2fs/Makefile b/sys/modules/ext2fs/Makefile
index fc10ab0..48697da 100644
--- a/sys/modules/ext2fs/Makefile
+++ b/sys/modules/ext2fs/Makefile
@@ -3,8 +3,8 @@
.PATH: ${.CURDIR}/../../fs/ext2fs
KMOD= ext2fs
SRCS= opt_ddb.h opt_directio.h opt_quota.h opt_suiddir.h vnode_if.h \
- ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_extents.c ext2_hash.c \
- ext2_htree.c ext2_inode.c ext2_inode_cnv.c ext2_lookup.c ext2_subr.c \
+ ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_extents.c \
+ ext2_inode.c ext2_inode_cnv.c ext2_lookup.c ext2_subr.c \
ext2_vfsops.c ext2_vnops.c
.include <bsd.kmod.mk>
diff --git a/sys/modules/hwpmc/Makefile b/sys/modules/hwpmc/Makefile
index c9c60fc..cfae7b6 100644
--- a/sys/modules/hwpmc/Makefile
+++ b/sys/modules/hwpmc/Makefile
@@ -25,7 +25,7 @@ SRCS+= device_if.h bus_if.h
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
-SRCS+= hwpmc_powerpc.c hwpmc_mpc7xxx.c hwpmc_ppc970.c
+SRCS+= hwpmc_powerpc.c hwpmc_e500.c hwpmc_mpc7xxx.c hwpmc_ppc970.c
.endif
.if ${MACHINE_CPUARCH} == "sparc64"
diff --git a/sys/modules/i2c/iicbb/Makefile b/sys/modules/i2c/iicbb/Makefile
index 75d1c83..bd4e506 100644
--- a/sys/modules/i2c/iicbb/Makefile
+++ b/sys/modules/i2c/iicbb/Makefile
@@ -1,8 +1,11 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/iicbus
+.if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "powerpc"
+ofw_bus_if= ofw_bus_if.h
+.endif
KMOD = iicbb
SRCS = device_if.h bus_if.h iicbus_if.h \
- iicbb_if.h iicbb_if.c iicbb.c opt_platform.h
+ iicbb_if.h iicbb_if.c iicbb.c ${ofw_bus_if} opt_platform.h
.include <bsd.kmod.mk>
diff --git a/sys/modules/ix/Makefile b/sys/modules/ix/Makefile
index 5a5485d..1f30cb0 100644
--- a/sys/modules/ix/Makefile
+++ b/sys/modules/ix/Makefile
@@ -9,7 +9,7 @@ SRCS += if_ix.c ix_txrx.c
# Shared source
SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c
SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c
-SRCS += ixgbe_82599.c ixgbe_82598.c ixgbe_x540.c
+SRCS += ixgbe_82598.c ixgbe_82599.c ixgbe_x540.c ixgbe_x550.c
CFLAGS+= -I${.CURDIR}/../../dev/ixgbe -DSMP
.include <bsd.kmod.mk>
diff --git a/sys/modules/ixv/Makefile b/sys/modules/ixv/Makefile
index 20ecaf1..f8ce347 100644
--- a/sys/modules/ixv/Makefile
+++ b/sys/modules/ixv/Makefile
@@ -9,7 +9,7 @@ SRCS += if_ixv.c ix_txrx.c
# Shared source
SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c
SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c
-SRCS += ixgbe_82599.c ixgbe_82598.c ixgbe_x540.c
+SRCS += ixgbe_82598.c ixgbe_82599.c ixgbe_x540.c ixgbe_x550.c
CFLAGS+= -I${.CURDIR}/../../dev/ixgbe -DSMP
.include <bsd.kmod.mk>
diff --git a/sys/modules/oce/Makefile b/sys/modules/oce/Makefile
index 4821533..95e828d 100644
--- a/sys/modules/oce/Makefile
+++ b/sys/modules/oce/Makefile
@@ -3,7 +3,7 @@
#
.PATH: ${.CURDIR}/../../dev/oce
-KMOD = oce
+KMOD = if_oce
SRCS = oce_if.c oce_hw.c oce_mbox.c oce_util.c oce_queue.c oce_sysctl.c
SRCS += bus_if.h device_if.h pci_if.h opt_inet.h opt_inet6.h
diff --git a/sys/modules/usb/Makefile b/sys/modules/usb/Makefile
index c0490a9..84d5ef2 100644
--- a/sys/modules/usb/Makefile
+++ b/sys/modules/usb/Makefile
@@ -56,6 +56,7 @@ SUBDIR += ${_urtwn} ${_urtwnfw}
SUBDIR += atp uhid ukbd ums udbp ufm uep wsp uled
SUBDIR += ucom u3g uark ubsa ubser uchcom ucycom ufoma uftdi ugensa uipaq ulpt \
umct umcs umodem umoscom uplcom uslcom uvisor uvscom
+SUBDIR += udl
SUBDIR += uether aue axe axge cdce cue ${_kue} mos rue smsc udav uhso ipheth
SUBDIR += urndis
SUBDIR += usfs umass urio
diff --git a/sys/modules/zlib/Makefile b/sys/modules/zlib/Makefile
index 0a475b5..235d1c7 100644
--- a/sys/modules/zlib/Makefile
+++ b/sys/modules/zlib/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-.PATH: ${.CURDIR}/../../net
+.PATH: ${.CURDIR}/../../libkern
KMOD= zlib
SRCS= zlib.c
diff --git a/sys/contrib/altq/altq/altq.h b/sys/net/altq/altq.h
index c740ed3..cdf6546 100644
--- a/sys/contrib/altq/altq/altq.h
+++ b/sys/net/altq/altq.h
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq.h,v 1.10 2003/07/10 12:07:47 kjc Exp $ */
-
-/*
+/*-
* Copyright (C) 1998-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -25,6 +22,9 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq.h,v 1.10 2003/07/10 12:07:47 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_H_
#define _ALTQ_ALTQ_H_
@@ -198,7 +198,7 @@ struct pktcntr {
#endif /* ALTQ3_COMPAT */
#ifdef _KERNEL
-#include <altq/altq_var.h>
+#include <net/altq/altq_var.h>
#endif
#endif /* _ALTQ_ALTQ_H_ */
diff --git a/sys/contrib/altq/altq/altq_cbq.c b/sys/net/altq/altq_cbq.c
index 3991d1d..995c819 100644
--- a/sys/contrib/altq/altq/altq_cbq.c
+++ b/sys/net/altq/altq_cbq.c
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_cbq.c,v 1.19 2003/09/17 14:23:25 kjc Exp $ */
-
-/*
+/*-
* Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,15 +26,14 @@
* provided "as is" without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this software.
+ *
+ * $KAME: altq_cbq.c,v 1.19 2003/09/17 14:23:25 kjc Exp $
+ * $FreeBSD$
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */
#include <sys/param.h>
@@ -60,10 +56,10 @@
#include <netpfil/pf/pf.h>
#include <netpfil/pf/pf_altq.h>
#include <netpfil/pf/pf_mtag.h>
-#include <altq/altq.h>
-#include <altq/altq_cbq.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
#ifdef ALTQ3_COMPAT
-#include <altq/altq_conf.h>
+#include <net/altq/altq_conf.h>
#endif
#ifdef ALTQ3_COMPAT
@@ -251,11 +247,7 @@ cbq_pfattach(struct pf_altq *a)
if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
return (EINVAL);
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
error = altq_attach(&ifp->if_snd, ALTQT_CBQ, a->altq_disc,
cbq_enqueue, cbq_dequeue, cbq_request, NULL, NULL);
splx(s);
diff --git a/sys/contrib/altq/altq/altq_cbq.h b/sys/net/altq/altq_cbq.h
index 30a15c7..792c9fd 100644
--- a/sys/contrib/altq/altq/altq_cbq.h
+++ b/sys/net/altq/altq_cbq.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_cbq.h,v 1.12 2003/10/03 05:05:15 kjc Exp $ */
-
-/*
+/*-
* Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,15 +26,18 @@
* provided "as is" without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this software.
+ *
+ * $KAME: altq_cbq.h,v 1.12 2003/10/03 05:05:15 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_CBQ_H_
#define _ALTQ_ALTQ_CBQ_H_
-#include <altq/altq.h>
-#include <altq/altq_rmclass.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_rmclass.h>
+#include <net/altq/altq_red.h>
+#include <net/altq/altq_rio.h>
#ifdef __cplusplus
extern "C" {
diff --git a/sys/contrib/altq/altq/altq_cdnr.c b/sys/net/altq/altq_cdnr.c
index ee36fe8..ff531dc 100644
--- a/sys/contrib/altq/altq/altq_cdnr.c
+++ b/sys/net/altq/altq_cdnr.c
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_cdnr.c,v 1.15 2005/04/13 03:44:24 suz Exp $ */
-
-/*
+/*-
* Copyright (C) 1999-2002
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -25,15 +22,14 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_cdnr.c,v 1.15 2005/04/13 03:44:24 suz Exp $
+ * $FreeBSD$
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#include <sys/param.h>
#include <sys/malloc.h>
@@ -55,12 +51,12 @@
#include <netinet/ip6.h>
#endif
-#include <altq/if_altq.h>
-#include <altq/altq.h>
+#include <net/altq/if_altq.h>
+#include <net/altq/altq.h>
#ifdef ALTQ3_COMPAT
-#include <altq/altq_conf.h>
+#include <net/altq/altq_conf.h>
#endif
-#include <altq/altq_cdnr.h>
+#include <net/altq/altq_cdnr.h>
#ifdef ALTQ3_COMPAT
/*
@@ -1272,11 +1268,7 @@ cdnrioctl(dev, cmd, addr, flag, p)
break;
}
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
switch (cmd) {
case CDNR_IF_ATTACH:
diff --git a/sys/contrib/altq/altq/altq_cdnr.h b/sys/net/altq/altq_cdnr.h
index d55402f..06fa9c9 100644
--- a/sys/contrib/altq/altq/altq_cdnr.h
+++ b/sys/net/altq/altq_cdnr.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_cdnr.h,v 1.9 2003/07/10 12:07:48 kjc Exp $ */
-
-/*
+/*-
* Copyright (C) 1999-2002
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -24,12 +22,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_cdnr.h,v 1.9 2003/07/10 12:07:48 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_CDNR_H_
#define _ALTQ_ALTQ_CDNR_H_
-#include <altq/altq.h>
+#include <net/altq/altq.h>
/*
* traffic conditioner element types
diff --git a/sys/contrib/altq/altq/altq_classq.h b/sys/net/altq/altq_classq.h
index dc5c646..e30f9e2 100644
--- a/sys/contrib/altq/altq/altq_classq.h
+++ b/sys/net/altq/altq_classq.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_classq.h,v 1.6 2003/01/07 07:33:38 kjc Exp $ */
-
-/*
+/*-
* Copyright (c) 1991-1997 Regents of the University of California.
* All rights reserved.
*
@@ -31,6 +29,9 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_classq.h,v 1.6 2003/01/07 07:33:38 kjc Exp $
+ * $FreeBSD$
*/
/*
* class queue definitions extracted from rm_class.h.
diff --git a/sys/contrib/altq/altq/altq_hfsc.c b/sys/net/altq/altq_hfsc.c
index 0363016..517ecd7 100644
--- a/sys/contrib/altq/altq/altq_hfsc.c
+++ b/sys/net/altq/altq_hfsc.c
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_hfsc.c,v 1.24 2003/12/05 05:40:46 kjc Exp $ */
-
-/*
+/*-
* Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
@@ -29,6 +26,9 @@
* software to return any improvements or extensions that they make,
* and to grant Carnegie Mellon the rights to redistribute these
* changes without encumbrance.
+ *
+ * $KAME: altq_hfsc.c,v 1.24 2003/12/05 05:40:46 kjc Exp $
+ * $FreeBSD$
*/
/*
* H-FSC is described in Proceedings of SIGCOMM'97,
@@ -42,13 +42,9 @@
* a class whose fit-time exceeds the current time.
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#ifdef ALTQ_HFSC /* hfsc is enabled by ALTQ_HFSC option in opt_altq.h */
@@ -72,10 +68,10 @@
#include <netpfil/pf/pf.h>
#include <netpfil/pf/pf_altq.h>
#include <netpfil/pf/pf_mtag.h>
-#include <altq/altq.h>
-#include <altq/altq_hfsc.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_hfsc.h>
#ifdef ALTQ3_COMPAT
-#include <altq/altq_conf.h>
+#include <net/altq/altq_conf.h>
#endif
/*
@@ -177,11 +173,7 @@ hfsc_pfattach(struct pf_altq *a)
if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
return (EINVAL);
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
error = altq_attach(&ifp->if_snd, ALTQT_HFSC, a->altq_disc,
hfsc_enqueue, hfsc_dequeue, hfsc_request, NULL, NULL);
splx(s);
@@ -483,11 +475,7 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc,
cl->cl_hif = hif;
cl->cl_parent = parent;
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(hif->hif_ifq);
hif->hif_classes++;
@@ -567,11 +555,7 @@ hfsc_class_destroy(struct hfsc_class *cl)
if (is_a_parent_class(cl))
return (EBUSY);
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(cl->cl_hif->hif_ifq);
#ifdef ALTQ3_COMPAT
@@ -1771,11 +1755,7 @@ hfsc_class_modify(cl, rsc, fsc, usc)
}
cur_time = read_machclk();
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(cl->cl_hif->hif_ifq);
if (rsc != NULL) {
diff --git a/sys/contrib/altq/altq/altq_hfsc.h b/sys/net/altq/altq_hfsc.h
index d04b378..8101428 100644
--- a/sys/contrib/altq/altq/altq_hfsc.h
+++ b/sys/net/altq/altq_hfsc.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_hfsc.h,v 1.12 2003/12/05 05:40:46 kjc Exp $ */
-
-/*
+/*-
* Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
@@ -28,14 +26,17 @@
* software to return any improvements or extensions that they make,
* and to grant Carnegie Mellon the rights to redistribute these
* changes without encumbrance.
+ *
+ * $KAME: altq_hfsc.h,v 1.12 2003/12/05 05:40:46 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_HFSC_H_
#define _ALTQ_ALTQ_HFSC_H_
-#include <altq/altq.h>
-#include <altq/altq_classq.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_classq.h>
+#include <net/altq/altq_red.h>
+#include <net/altq/altq_rio.h>
#ifdef __cplusplus
extern "C" {
diff --git a/sys/contrib/altq/altq/altq_priq.c b/sys/net/altq/altq_priq.c
index 3ce65dc..de18c03 100644
--- a/sys/contrib/altq/altq/altq_priq.c
+++ b/sys/net/altq/altq_priq.c
@@ -1,6 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_priq.c,v 1.11 2003/09/17 14:23:25 kjc Exp $ */
-/*
+/*-
* Copyright (C) 2000-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -24,18 +22,17 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_priq.c,v 1.11 2003/09/17 14:23:25 kjc Exp $
+ * $FreeBSD$
*/
/*
* priority queue
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#ifdef ALTQ_PRIQ /* priq is enabled by ALTQ_PRIQ option in opt_altq.h */
@@ -57,11 +54,11 @@
#include <netpfil/pf/pf.h>
#include <netpfil/pf/pf_altq.h>
#include <netpfil/pf/pf_mtag.h>
-#include <altq/altq.h>
+#include <net/altq/altq.h>
#ifdef ALTQ3_COMPAT
-#include <altq/altq_conf.h>
+#include <net/altq/altq_conf.h>
#endif
-#include <altq/altq_priq.h>
+#include <net/altq/altq_priq.h>
/*
* function prototypes
@@ -113,11 +110,7 @@ priq_pfattach(struct pf_altq *a)
if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
return (EINVAL);
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, a->altq_disc,
priq_enqueue, priq_dequeue, priq_request, NULL, NULL);
splx(s);
@@ -300,11 +293,7 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
if ((cl = pif->pif_classes[pri]) != NULL) {
/* modify the class instead of creating a new one */
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(cl->cl_pif->pif_ifq);
if (!qempty(cl->cl_q))
priq_purgeq(cl);
@@ -407,11 +396,7 @@ priq_class_destroy(struct priq_class *cl)
struct priq_if *pif;
int s, pri;
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(cl->cl_pif->pif_ifq);
#ifdef ALTQ3_CLFIER_COMPAT
diff --git a/sys/contrib/altq/altq/altq_priq.h b/sys/net/altq/altq_priq.h
index 481d31b..d3cea33 100644
--- a/sys/contrib/altq/altq/altq_priq.h
+++ b/sys/net/altq/altq_priq.h
@@ -1,5 +1,4 @@
-/* $KAME: altq_priq.h,v 1.7 2003/10/03 05:05:15 kjc Exp $ */
-/*
+/*-
* Copyright (C) 2000-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -23,15 +22,18 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_priq.h,v 1.7 2003/10/03 05:05:15 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_PRIQ_H_
#define _ALTQ_ALTQ_PRIQ_H_
-#include <altq/altq.h>
-#include <altq/altq_classq.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_classq.h>
+#include <net/altq/altq_red.h>
+#include <net/altq/altq_rio.h>
#ifdef __cplusplus
extern "C" {
diff --git a/sys/contrib/altq/altq/altq_red.c b/sys/net/altq/altq_red.c
index defee29..1347851 100644
--- a/sys/contrib/altq/altq/altq_red.c
+++ b/sys/net/altq/altq_red.c
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_red.c,v 1.18 2003/09/05 22:40:36 itojun Exp $ */
-
-/*
+/*-
* Copyright (C) 1997-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -27,7 +24,7 @@
* SUCH DAMAGE.
*
*/
-/*
+/*-
* Copyright (c) 1990-1994 Regents of the University of California.
* All rights reserved.
*
@@ -58,15 +55,14 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_red.c,v 1.18 2003/09/05 22:40:36 itojun Exp $
+ * $FreeBSD$
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#ifdef ALTQ_RED /* red is enabled by ALTQ_RED option in opt_altq.h */
#include <sys/param.h>
@@ -98,12 +94,12 @@
#include <netpfil/pf/pf.h>
#include <netpfil/pf/pf_altq.h>
#include <netpfil/pf/pf_mtag.h>
-#include <altq/altq.h>
-#include <altq/altq_red.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_red.h>
#ifdef ALTQ3_COMPAT
-#include <altq/altq_conf.h>
+#include <net/altq/altq_conf.h>
#ifdef ALTQ_FLOWVALVE
-#include <altq/altq_flowvalve.h>
+#include <net/altq/altq_flowvalve.h>
#endif
#endif
@@ -944,11 +940,7 @@ redioctl(dev, cmd, addr, flag, p)
break;
}
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
red_purgeq(rqp);
limit = fc->red_limit;
if (limit < fc->red_thmax)
diff --git a/sys/contrib/altq/altq/altq_red.h b/sys/net/altq/altq_red.h
index dc8ea0a..8ae8d29 100644
--- a/sys/contrib/altq/altq/altq_red.h
+++ b/sys/net/altq/altq_red.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_red.h,v 1.8 2003/07/10 12:07:49 kjc Exp $ */
-
-/*
+/*-
* Copyright (C) 1997-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -24,12 +22,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_red.h,v 1.8 2003/07/10 12:07:49 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_RED_H_
#define _ALTQ_ALTQ_RED_H_
-#include <altq/altq_classq.h>
+#include <net/altq/altq_classq.h>
#ifdef ALTQ3_COMPAT
struct red_interface {
diff --git a/sys/contrib/altq/altq/altq_rio.c b/sys/net/altq/altq_rio.c
index 151debe..0f19735e 100644
--- a/sys/contrib/altq/altq/altq_rio.c
+++ b/sys/net/altq/altq_rio.c
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_rio.c,v 1.17 2003/07/10 12:07:49 kjc Exp $ */
-
-/*
+/*-
* Copyright (C) 1998-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -26,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-/*
+/*-
* Copyright (c) 1990-1994 Regents of the University of California.
* All rights reserved.
*
@@ -57,15 +54,14 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_rio.c,v 1.17 2003/07/10 12:07:49 kjc Exp $
+ * $FreeBSD$
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#ifdef ALTQ_RIO /* rio is enabled by ALTQ_RIO option in opt_altq.h */
#include <sys/param.h>
@@ -92,12 +88,12 @@
#include <netpfil/pf/pf.h>
#include <netpfil/pf/pf_altq.h>
-#include <altq/altq.h>
-#include <altq/altq_cdnr.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cdnr.h>
+#include <net/altq/altq_red.h>
+#include <net/altq/altq_rio.h>
#ifdef ALTQ3_COMPAT
-#include <altq/altq_conf.h>
+#include <net/altq/altq_conf.h>
#endif
/*
@@ -684,11 +680,7 @@ rioioctl(dev, cmd, addr, flag, p)
break;
}
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
_flushq(rqp->rq_q);
limit = fc->rio_limit;
if (limit < fc->q_params[RIO_NDROPPREC-1].th_max)
diff --git a/sys/contrib/altq/altq/altq_rio.h b/sys/net/altq/altq_rio.h
index 83210f2..ce9dc0e 100644
--- a/sys/contrib/altq/altq/altq_rio.h
+++ b/sys/net/altq/altq_rio.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_rio.h,v 1.9 2003/07/10 12:07:49 kjc Exp $ */
-
-/*
+/*-
* Copyright (C) 1998-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -24,12 +22,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_rio.h,v 1.9 2003/07/10 12:07:49 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_RIO_H_
#define _ALTQ_ALTQ_RIO_H_
-#include <altq/altq_classq.h>
+#include <net/altq/altq_classq.h>
/*
* RIO: RED with IN/OUT bit
diff --git a/sys/contrib/altq/altq/altq_rmclass.c b/sys/net/altq/altq_rmclass.c
index c433024..3f76f2c 100644
--- a/sys/contrib/altq/altq/altq_rmclass.c
+++ b/sys/net/altq/altq_rmclass.c
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_rmclass.c,v 1.19 2005/04/13 03:44:25 suz Exp $ */
-
-/*
+/*-
* Copyright (c) 1991-1997 Regents of the University of California.
* All rights reserved.
*
@@ -37,14 +34,12 @@
* For questions and/or comments, please send mail to cbq@ee.lbl.gov
*
* @(#)rm_class.c 1.48 97/12/05 SMI
+ * $KAME: altq_rmclass.c,v 1.19 2005/04/13 03:44:25 suz Exp $
+ * $FreeBSD$
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */
#include <sys/param.h>
@@ -66,12 +61,12 @@
#include <netinet/ip.h>
#endif
-#include <altq/if_altq.h>
-#include <altq/altq.h>
-#include <altq/altq_rmclass.h>
-#include <altq/altq_rmclass_debug.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
+#include <net/altq/if_altq.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_rmclass.h>
+#include <net/altq/altq_rmclass_debug.h>
+#include <net/altq/altq_red.h>
+#include <net/altq/altq_rio.h>
/*
* Local Macros
@@ -306,11 +301,7 @@ rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte,
/*
* put the class into the class tree
*/
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(ifd->ifq_);
if ((peer = ifd->active_[pri]) != NULL) {
/* find the last class at this pri */
@@ -359,11 +350,7 @@ rmc_modclass(struct rm_class *cl, u_int nsecPerByte, int maxq, u_int maxidle,
ifd = cl->ifdat_;
old_allotment = cl->allotment_;
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(ifd->ifq_);
cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
cl->qthresh_ = 0;
@@ -559,11 +546,7 @@ rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl)
if (cl->sleeping_)
CALLOUT_STOP(&cl->callout_);
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(ifd->ifq_);
/*
* Free packets in the packet queue.
@@ -1531,13 +1514,8 @@ rmc_delay_action(struct rm_class *cl, struct rm_class *borrow)
* a 'backstop' to restart this class.
*/
if (delay > tick * 2) {
-#ifdef __FreeBSD__
/* FreeBSD rounds up the tick */
t = hzto(&cl->undertime_);
-#else
- /* other BSDs round down the tick */
- t = hzto(&cl->undertime_) + 1;
-#endif
} else
t = 2;
CALLOUT_RESET(&cl->callout_, t,
@@ -1568,11 +1546,7 @@ rmc_restart(struct rm_class *cl)
struct rm_ifdat *ifd = cl->ifdat_;
int s;
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_LOCK(ifd->ifq_);
if (cl->sleeping_) {
cl->sleeping_ = 0;
diff --git a/sys/contrib/altq/altq/altq_rmclass.h b/sys/net/altq/altq_rmclass.h
index cf0ddf4..e2cae89 100644
--- a/sys/contrib/altq/altq/altq_rmclass.h
+++ b/sys/net/altq/altq_rmclass.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_rmclass.h,v 1.10 2003/08/20 23:30:23 itojun Exp $ */
-
-/*
+/*-
* Copyright (c) 1991-1997 Regents of the University of California.
* All rights reserved.
*
@@ -31,12 +29,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_rmclass.h,v 1.10 2003/08/20 23:30:23 itojun Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_RMCLASS_H_
#define _ALTQ_ALTQ_RMCLASS_H_
-#include <altq/altq_classq.h>
+#include <net/altq/altq_classq.h>
/* #pragma ident "@(#)rm_class.h 1.20 97/10/23 SMI" */
diff --git a/sys/contrib/altq/altq/altq_rmclass_debug.h b/sys/net/altq/altq_rmclass_debug.h
index 8f471b2..7adbaec 100644
--- a/sys/contrib/altq/altq/altq_rmclass_debug.h
+++ b/sys/net/altq/altq_rmclass_debug.h
@@ -1,6 +1,4 @@
-/* $KAME: altq_rmclass_debug.h,v 1.3 2002/11/29 04:36:24 kjc Exp $ */
-
-/*
+/*-
* Copyright (c) Sun Microsystems, Inc. 1998 All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,6 +26,9 @@
* provided "as is" without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this software.
+ *
+ * $KAME: altq_rmclass_debug.h,v 1.3 2002/11/29 04:36:24 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_RMCLASS_DEBUG_H_
diff --git a/sys/contrib/altq/altq/altq_subr.c b/sys/net/altq/altq_subr.c
index 16b796a..0c3da66 100644
--- a/sys/contrib/altq/altq/altq_subr.c
+++ b/sys/net/altq/altq_subr.c
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_subr.c,v 1.21 2003/11/06 06:32:53 kjc Exp $ */
-
-/*
+/*-
* Copyright (C) 1997-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -25,15 +22,14 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_subr.c,v 1.21 2003/11/06 06:32:53 kjc Exp $
+ * $FreeBSD$
*/
-#if defined(__FreeBSD__) || defined(__NetBSD__)
#include "opt_altq.h"
#include "opt_inet.h"
-#ifdef __FreeBSD__
#include "opt_inet6.h"
-#endif
-#endif /* __FreeBSD__ || __NetBSD__ */
#include <sys/param.h>
#include <sys/malloc.h>
@@ -52,9 +48,7 @@
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
-#ifdef __FreeBSD__
#include <net/vnet.h>
-#endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -67,26 +61,20 @@
#include <netpfil/pf/pf.h>
#include <netpfil/pf/pf_altq.h>
-#include <altq/altq.h>
+#include <net/altq/altq.h>
#ifdef ALTQ3_COMPAT
-#include <altq/altq_conf.h>
+#include <net/altq/altq_conf.h>
#endif
/* machine dependent clock related includes */
-#ifdef __FreeBSD__
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/eventhandler.h>
#include <machine/clock.h>
-#endif
#if defined(__amd64__) || defined(__i386__)
#include <machine/cpufunc.h> /* for pentium tsc */
#include <machine/specialreg.h> /* for CPUID_TSC */
-#ifdef __FreeBSD__
#include <machine/md_var.h> /* for cpu_feature */
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-#include <machine/cpu.h> /* for cpu_feature */
-#endif
#endif /* __amd64 || __i386__ */
/*
@@ -254,11 +242,7 @@ altq_enable(ifq)
return 0;
}
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_PURGE_NOLOCK(ifq);
ASSERT(ifq->ifq_len == 0);
ifq->ifq_drv_maxlen = 0; /* disable bulk dequeue */
@@ -283,11 +267,7 @@ altq_disable(ifq)
return 0;
}
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
IFQ_PURGE_NOLOCK(ifq);
ASSERT(ifq->ifq_len == 0);
ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY);
@@ -444,24 +424,16 @@ static void
tbr_timeout(arg)
void *arg;
{
-#ifdef __FreeBSD__
VNET_ITERATOR_DECL(vnet_iter);
-#endif
struct ifnet *ifp;
int active, s;
active = 0;
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
-#ifdef __FreeBSD__
IFNET_RLOCK_NOSLEEP();
VNET_LIST_RLOCK_NOSLEEP();
VNET_FOREACH(vnet_iter) {
CURVNET_SET(vnet_iter);
-#endif
for (ifp = TAILQ_FIRST(&V_ifnet); ifp;
ifp = TAILQ_NEXT(ifp, if_list)) {
/* read from if_snd unlocked */
@@ -472,12 +444,10 @@ tbr_timeout(arg)
ifp->if_start != NULL)
(*ifp->if_start)(ifp);
}
-#ifdef __FreeBSD__
CURVNET_RESTORE();
}
VNET_LIST_RUNLOCK_NOSLEEP();
IFNET_RUNLOCK_NOSLEEP();
-#endif
splx(s);
if (active > 0)
CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
@@ -563,11 +533,7 @@ altq_pfdetach(struct pf_altq *a)
if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc)
return (0);
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
/* read unlocked from if_snd, _disable and _detach take care */
if (ALTQ_IS_ENABLED(&ifp->if_snd))
error = altq_disable(&ifp->if_snd);
@@ -926,12 +892,8 @@ init_machclk_setup(void)
#endif
#if defined(__amd64__) || defined(__i386__)
/* check if TSC is available */
-#ifdef __FreeBSD__
if ((cpu_feature & CPUID_TSC) == 0 ||
atomic_load_acq_64(&tsc_freq) == 0)
-#else
- if ((cpu_feature & CPUID_TSC) == 0)
-#endif
machclk_usepcc = 0;
#endif
}
@@ -962,13 +924,7 @@ init_machclk(void)
* accessible, just use it.
*/
#if defined(__amd64__) || defined(__i386__)
-#ifdef __FreeBSD__
machclk_freq = atomic_load_acq_64(&tsc_freq);
-#elif defined(__NetBSD__)
- machclk_freq = (u_int32_t)cpu_tsc_freq;
-#elif defined(__OpenBSD__) && (defined(I586_CPU) || defined(I686_CPU))
- machclk_freq = pentium_mhz * 1000000;
-#endif
#endif
/*
@@ -1449,11 +1405,7 @@ acc_add_filter(classifier, filter, class, phandle)
* add this filter to the filter list.
* filters are ordered from the highest rule number.
*/
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
prev = NULL;
LIST_FOREACH(tmp, &classifier->acc_filters[i], f_chain) {
if (tmp->f_filter.ff_ruleno > afp->f_filter.ff_ruleno)
@@ -1482,11 +1434,7 @@ acc_delete_filter(classifier, handle)
if ((afp = filth_to_filtp(classifier, handle)) == NULL)
return (EINVAL);
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
LIST_REMOVE(afp, f_chain);
splx(s);
@@ -1510,11 +1458,7 @@ acc_discard_filters(classifier, class, all)
struct acc_filter *afp;
int i, s;
-#ifdef __NetBSD__
s = splnet();
-#else
- s = splimp();
-#endif
for (i = 0; i < ACC_FILTER_TABLESIZE; i++) {
do {
LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain)
diff --git a/sys/contrib/altq/altq/altq_var.h b/sys/net/altq/altq_var.h
index 956ee16..df12144 100644
--- a/sys/contrib/altq/altq/altq_var.h
+++ b/sys/net/altq/altq_var.h
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: altq_var.h,v 1.16 2003/10/03 05:05:15 kjc Exp $ */
-
-/*
+/*-
* Copyright (C) 1998-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -25,6 +22,9 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: altq_var.h,v 1.16 2003/10/03 05:05:15 kjc Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_ALTQ_VAR_H_
#define _ALTQ_ALTQ_VAR_H_
@@ -161,7 +161,6 @@ typedef u_long ioctlcmd_t;
#endif
/* macro for timeout/untimeout */
-#if (__FreeBSD_version > 300000) || defined(__NetBSD__)
/* use callout */
#include <sys/callout.h>
@@ -175,35 +174,6 @@ typedef u_long ioctlcmd_t;
#if !defined(CALLOUT_INITIALIZER) && (__FreeBSD_version < 600000)
#define CALLOUT_INITIALIZER { { { NULL } }, 0, NULL, NULL, 0 }
#endif
-#elif defined(__OpenBSD__)
-#include <sys/timeout.h>
-/* callout structure as a wrapper of struct timeout */
-struct callout {
- struct timeout c_to;
-};
-#define CALLOUT_INIT(c) do { bzero((c), sizeof(*(c))); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_RESET(c,t,f,a) do { if (!timeout_initialized(&(c)->c_to)) \
- timeout_set(&(c)->c_to, (f), (a)); \
- timeout_add(&(c)->c_to, (t)); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_STOP(c) timeout_del(&(c)->c_to)
-#define CALLOUT_INITIALIZER { { { NULL }, NULL, NULL, 0, 0 } }
-#else
-/* use old-style timeout/untimeout */
-/* dummy callout structure */
-struct callout {
- void *c_arg; /* function argument */
- void (*c_func)(void *); /* functiuon to call */
-};
-#define CALLOUT_INIT(c) do { bzero((c), sizeof(*(c))); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_RESET(c,t,f,a) do { (c)->c_arg = (a); \
- (c)->c_func = (f); \
- timeout((f),(a),(t)); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_STOP(c) untimeout((c)->c_func,(c)->c_arg)
-#define CALLOUT_INITIALIZER { NULL, NULL }
-#endif
-#if !defined(__FreeBSD__)
-typedef void (timeout_t)(void *);
-#endif
#define m_pktlen(m) ((m)->m_pkthdr.len)
diff --git a/sys/contrib/altq/altq/if_altq.h b/sys/net/altq/if_altq.h
index 7c4d1c2..3dcc96c 100644
--- a/sys/contrib/altq/altq/if_altq.h
+++ b/sys/net/altq/if_altq.h
@@ -1,7 +1,4 @@
-/* $FreeBSD$ */
-/* $KAME: if_altq.h,v 1.12 2005/04/13 03:44:25 suz Exp $ */
-
-/*
+/*-
* Copyright (C) 1997-2003
* Sony Computer Science Laboratories Inc. All rights reserved.
*
@@ -25,19 +22,16 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $KAME: if_altq.h,v 1.12 2005/04/13 03:44:25 suz Exp $
+ * $FreeBSD$
*/
#ifndef _ALTQ_IF_ALTQ_H_
#define _ALTQ_IF_ALTQ_H_
-#ifdef __FreeBSD__
#include <sys/lock.h> /* XXX */
#include <sys/mutex.h> /* XXX */
#include <sys/event.h> /* XXX */
-#endif
-
-#ifdef _KERNEL_OPT
-#include <altq/altqconf.h>
-#endif
struct altq_pktattr; struct tb_regulator; struct top_cdnr;
@@ -50,9 +44,7 @@ struct ifaltq {
struct mbuf *ifq_tail;
int ifq_len;
int ifq_maxlen;
-#ifdef __FreeBSD__
struct mtx ifq_mtx;
-#endif
/* driver owned queue (used for bulk dequeue and prepend) UNLOCKED */
struct mbuf *ifq_drv_head;
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index a04fdef..9fc5e9f 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -69,7 +69,6 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_var.h>
-#define BPF_INTERNAL
#include <net/bpf.h>
#include <net/bpf_buffer.h>
#ifdef BPF_JITTER
@@ -90,6 +89,20 @@ __FBSDID("$FreeBSD$");
MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
+struct bpf_if {
+#define bif_next bif_ext.bif_next
+#define bif_dlist bif_ext.bif_dlist
+ struct bpf_if_ext bif_ext; /* public members */
+ u_int bif_dlt; /* link layer type */
+ u_int bif_hdrlen; /* length of link header */
+ struct ifnet *bif_ifp; /* corresponding interface */
+ struct rwlock bif_lock; /* interface lock */
+ LIST_HEAD(, bpf_d) bif_wlist; /* writer-only list */
+ int bif_flags; /* Interface flags */
+};
+
+CTASSERT(offsetof(struct bpf_if, bif_ext) == 0);
+
#if defined(DEV_BPF) || defined(NETGRAPH_BPF)
#define PRINET 26 /* interruptible */
@@ -601,7 +614,7 @@ bpf_attachd(struct bpf_d *d, struct bpf_if *bp)
* Save sysctl value to protect from sysctl change
* between reads
*/
- op_w = V_bpf_optimize_writers;
+ op_w = V_bpf_optimize_writers || d->bd_writer;
if (d->bd_bif != NULL)
bpf_detachd_locked(d);
@@ -864,6 +877,8 @@ bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td)
* particular buffer method.
*/
bpf_buffer_init(d);
+ if ((flags & FREAD) == 0)
+ d->bd_writer = 2;
d->bd_hbuf_in_use = 0;
d->bd_bufmode = BPF_BUFMODE_BUFFER;
d->bd_sig = SIGIO;
@@ -1890,7 +1905,7 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
/* Check if interface is not being detached from BPF */
BPFIF_RLOCK(bp);
- if (bp->flags & BPFIF_FLAG_DYING) {
+ if (bp->bif_flags & BPFIF_FLAG_DYING) {
BPFIF_RUNLOCK(bp);
return (ENXIO);
}
@@ -2559,7 +2574,7 @@ bpfdetach(struct ifnet *ifp)
* Mark bp as detached to restrict new consumers.
*/
BPFIF_WLOCK(bp);
- bp->flags |= BPFIF_FLAG_DYING;
+ bp->bif_flags |= BPFIF_FLAG_DYING;
BPFIF_WUNLOCK(bp);
CTR4(KTR_NET, "%s: sheduling free for encap %d (%p) for if %p",
diff --git a/sys/net/bpf.h b/sys/net/bpf.h
index 47cbb87..df326e6 100644
--- a/sys/net/bpf.h
+++ b/sys/net/bpf.h
@@ -1451,21 +1451,14 @@ SYSCTL_DECL(_net_bpf);
/*
* Descriptor associated with each attached hardware interface.
- * FIXME: this structure is exposed to external callers to speed up
- * bpf_peers_present() call. However we cover all fields not needed by
- * this function via BPF_INTERNAL define
+ * Part of this structure is exposed to external callers to speed up
+ * bpf_peers_present() calls.
*/
-struct bpf_if {
+struct bpf_if;
+
+struct bpf_if_ext {
LIST_ENTRY(bpf_if) bif_next; /* list of all interfaces */
LIST_HEAD(, bpf_d) bif_dlist; /* descriptor list */
-#ifdef BPF_INTERNAL
- u_int bif_dlt; /* link layer type */
- u_int bif_hdrlen; /* length of link header */
- struct ifnet *bif_ifp; /* corresponding interface */
- struct rwlock bif_lock; /* interface lock */
- LIST_HEAD(, bpf_d) bif_wlist; /* writer-only list */
- int flags; /* Interface flags */
-#endif
};
void bpf_bufheld(struct bpf_d *d);
@@ -1483,8 +1476,10 @@ u_int bpf_filter(const struct bpf_insn *, u_char *, u_int, u_int);
static __inline int
bpf_peers_present(struct bpf_if *bpf)
{
+ struct bpf_if_ext *ext;
- if (!LIST_EMPTY(&bpf->bif_dlist))
+ ext = (struct bpf_if_ext *)bpf;
+ if (!LIST_EMPTY(&ext->bif_dlist))
return (1);
return (0);
}
diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c
index c422c25..64aafb1 100644
--- a/sys/net/ieee8023ad_lacp.c
+++ b/sys/net/ieee8023ad_lacp.c
@@ -1066,12 +1066,16 @@ lacp_compose_key(struct lacp_port *lp)
case IFM_100_T4:
case IFM_100_VG:
case IFM_100_T2:
+ case IFM_100_T:
key = IFM_100_TX;
break;
case IFM_1000_SX:
case IFM_1000_LX:
case IFM_1000_CX:
case IFM_1000_T:
+ case IFM_1000_KX:
+ case IFM_1000_SGMII:
+ case IFM_1000_CX_SGMII:
key = IFM_1000_SX;
break;
case IFM_10G_LR:
@@ -1081,15 +1085,53 @@ lacp_compose_key(struct lacp_port *lp)
case IFM_10G_TWINAX_LONG:
case IFM_10G_LRM:
case IFM_10G_T:
+ case IFM_10G_KX4:
+ case IFM_10G_KR:
+ case IFM_10G_CR1:
+ case IFM_10G_ER:
+ case IFM_10G_SFI:
key = IFM_10G_LR;
break;
+ case IFM_20G_KR2:
+ key = IFM_20G_KR2;
+ break;
+ case IFM_2500_KX:
+ case IFM_2500_T:
+ key = IFM_2500_KX;
+ break;
+ case IFM_5000_T:
+ key = IFM_5000_T;
+ break;
+ case IFM_50G_PCIE:
+ case IFM_50G_CR2:
+ case IFM_50G_KR2:
+ key = IFM_50G_PCIE;
+ break;
+ case IFM_56G_R4:
+ key = IFM_56G_R4;
+ break;
+ case IFM_25G_PCIE:
+ case IFM_25G_CR:
+ case IFM_25G_KR:
+ case IFM_25G_SR:
+ key = IFM_25G_PCIE;
+ break;
case IFM_40G_CR4:
case IFM_40G_SR4:
case IFM_40G_LR4:
+ case IFM_40G_XLPPI:
+ case IFM_40G_KR4:
key = IFM_40G_CR4;
break;
+ case IFM_100G_CR4:
+ case IFM_100G_SR4:
+ case IFM_100G_KR4:
+ case IFM_100G_LR4:
+ key = IFM_100G_CR4;
+ break;
default:
key = subtype;
+ break;
}
/* bit 5..14: (some bits of) if_index of lagg device */
key |= 0x7fe0 & ((sc->sc_ifp->if_index) << 5);
diff --git a/sys/net/if.c b/sys/net/if.c
index 9d56803..1dec451 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -2582,6 +2582,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
case SIOCGIFPSRCADDR:
case SIOCGIFPDSTADDR:
case SIOCGIFMEDIA:
+ case SIOCGIFXMEDIA:
case SIOCGIFGENERIC:
if (ifp->if_ioctl == NULL)
return (EOPNOTSUPP);
diff --git a/sys/net/if_media.c b/sys/net/if_media.c
index 810db3f..abdfa2b 100644
--- a/sys/net/if_media.c
+++ b/sys/net/if_media.c
@@ -46,6 +46,8 @@
* to implement this interface.
*/
+#include "opt_ifmedia.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
@@ -68,6 +70,7 @@ static struct ifmedia_entry *ifmedia_match(struct ifmedia *ifm,
int flags, int mask);
#ifdef IFMEDIA_DEBUG
+#include <net/if_var.h>
int ifmedia_debug = 0;
SYSCTL_INT(_debug, OID_AUTO, ifmedia, CTLFLAG_RW, &ifmedia_debug,
0, "if_media debugging msgs");
@@ -193,6 +196,21 @@ ifmedia_set(ifm, target)
}
/*
+ * Given a media word, return one suitable for an application
+ * using the original encoding.
+ */
+static int
+compat_media(int media)
+{
+
+ if (IFM_TYPE(media) == IFM_ETHER && IFM_SUBTYPE(media) > IFM_OTHER) {
+ media &= ~(IFM_ETH_XTYPE|IFM_TMASK);
+ media |= IFM_OTHER;
+ }
+ return (media);
+}
+
+/*
* Device-independent media ioctl support function.
*/
int
@@ -271,6 +289,7 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd)
* Get list of available media and current media on interface.
*/
case SIOCGIFMEDIA:
+ case SIOCGIFXMEDIA:
{
struct ifmedia_entry *ep;
int i;
@@ -278,8 +297,13 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd)
if (ifmr->ifm_count < 0)
return (EINVAL);
- ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
- ifm->ifm_cur->ifm_media : IFM_NONE;
+ if (cmd == SIOCGIFMEDIA) {
+ ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
+ compat_media(ifm->ifm_cur->ifm_media) : IFM_NONE;
+ } else {
+ ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
+ ifm->ifm_cur->ifm_media : IFM_NONE;
+ }
ifmr->ifm_mask = ifm->ifm_mask;
ifmr->ifm_status = 0;
(*ifm->ifm_status)(ifp, ifmr);
@@ -354,8 +378,7 @@ ifmedia_baudrate(int mword)
int i;
for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
- if ((mword & (IFM_NMASK|IFM_TMASK)) ==
- ifmedia_baudrate_descriptions[i].ifmb_word)
+ if (IFM_TYPE_MATCH(mword, ifmedia_baudrate_descriptions[i].ifmb_word))
return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
}
@@ -461,7 +484,7 @@ ifmedia_printword(ifmw)
printf("<unknown type>\n");
return;
}
- printf(desc->ifmt_string);
+ printf("%s", desc->ifmt_string);
/* Any mode. */
for (desc = ttos->modes; desc && desc->ifmt_string != NULL; desc++)
diff --git a/sys/net/if_media.h b/sys/net/if_media.h
index 88384f3..8643995 100644
--- a/sys/net/if_media.h
+++ b/sys/net/if_media.h
@@ -118,7 +118,7 @@ uint64_t ifmedia_baudrate(int);
* ---- -------
* 0-4 Media variant
* 5-7 Media type
- * 8-15 Type specific options
+ * 8-15 Type specific options (includes added variant bits on Ethernet)
* 16-18 Mode (for multi-mode devices)
* 19 RFU
* 20-27 Shared (global) options
@@ -127,8 +127,18 @@ uint64_t ifmedia_baudrate(int);
/*
* Ethernet
+ * In order to use more than 31 subtypes, Ethernet uses some of the option
+ * bits as part of the subtype field. See the options section below for
+ * relevant definitions
*/
#define IFM_ETHER 0x00000020
+#define IFM_ETHER_SUBTYPE(x) (((x) & IFM_TMASK) | \
+ (((x) & (IFM_ETH_XTYPE >> IFM_ETH_XSHIFT)) << IFM_ETH_XSHIFT))
+#define IFM_X(x) IFM_ETHER_SUBTYPE(x) /* internal shorthand */
+#define IFM_ETHER_SUBTYPE_SET(x) (IFM_ETHER_SUBTYPE(x) | IFM_ETHER)
+#define IFM_ETHER_SUBTYPE_GET(x) ((x) & (IFM_TMASK|IFM_ETH_XTYPE))
+#define IFM_ETHER_IS_EXTENDED(x) ((x) & IFM_ETH_XTYPE)
+
#define IFM_10_T 3 /* 10BaseT - RJ45 */
#define IFM_10_2 4 /* 10Base2 - Thinnet */
#define IFM_10_5 5 /* 10Base5 - AUI */
@@ -156,15 +166,49 @@ uint64_t ifmedia_baudrate(int);
#define IFM_40G_CR4 27 /* 40GBase-CR4 */
#define IFM_40G_SR4 28 /* 40GBase-SR4 */
#define IFM_40G_LR4 29 /* 40GBase-LR4 */
+#define IFM_1000_KX 30 /* 1000Base-KX backplane */
+#define IFM_OTHER 31 /* Other: one of the following */
+
+/* following types are not visible to old binaries using only IFM_TMASK */
+#define IFM_10G_KX4 IFM_X(32) /* 10GBase-KX4 backplane */
+#define IFM_10G_KR IFM_X(33) /* 10GBase-KR backplane */
+#define IFM_10G_CR1 IFM_X(34) /* 10GBase-CR1 Twinax splitter */
+#define IFM_20G_KR2 IFM_X(35) /* 20GBase-KR2 backplane */
+#define IFM_2500_KX IFM_X(36) /* 2500Base-KX backplane */
+#define IFM_2500_T IFM_X(37) /* 2500Base-T - RJ45 (NBaseT) */
+#define IFM_5000_T IFM_X(38) /* 5000Base-T - RJ45 (NBaseT) */
+#define IFM_50G_PCIE IFM_X(39) /* 50G Ethernet over PCIE */
+#define IFM_25G_PCIE IFM_X(40) /* 25G Ethernet over PCIE */
+#define IFM_1000_SGMII IFM_X(41) /* 1G media interface */
+#define IFM_10G_SFI IFM_X(42) /* 10G media interface */
+#define IFM_40G_XLPPI IFM_X(43) /* 40G media interface */
+#define IFM_1000_CX_SGMII IFM_X(44) /* 1000Base-CX-SGMII */
+#define IFM_40G_KR4 IFM_X(45) /* 40GBase-KR4 */
+#define IFM_10G_ER IFM_X(46) /* 10GBase-ER */
+#define IFM_100G_CR4 IFM_X(47) /* 100GBase-CR4 */
+#define IFM_100G_SR4 IFM_X(48) /* 100GBase-SR4 */
+#define IFM_100G_KR4 IFM_X(49) /* 100GBase-KR4 */
+#define IFM_100G_LR4 IFM_X(50) /* 100GBase-LR4 */
+#define IFM_56G_R4 IFM_X(51) /* 56GBase-R4 */
+#define IFM_100_T IFM_X(52) /* 100BaseT - RJ45 */
+#define IFM_25G_CR IFM_X(53) /* 25GBase-CR */
+#define IFM_25G_KR IFM_X(54) /* 25GBase-KR */
+#define IFM_25G_SR IFM_X(55) /* 25GBase-SR */
+#define IFM_50G_CR2 IFM_X(56) /* 50GBase-CR2 */
+#define IFM_50G_KR2 IFM_X(57) /* 50GBase-KR2 */
+
/*
* Please update ieee8023ad_lacp.c:lacp_compose_key()
* after adding new Ethernet media types.
*/
-/* note 31 is the max! */
+/* Note IFM_X(511) is the max! */
+/* Ethernet option values; includes bits used for extended variant field */
#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */
#define IFM_ETH_RXPAUSE 0x00000200 /* receive PAUSE frames */
#define IFM_ETH_TXPAUSE 0x00000400 /* transmit PAUSE frames */
+#define IFM_ETH_XTYPE 0x00007800 /* extended media variants */
+#define IFM_ETH_XSHIFT 6 /* shift XTYPE next to TMASK */
/*
* Token ring
@@ -307,7 +351,10 @@ uint64_t ifmedia_baudrate(int);
* Macros to extract various bits of information from the media word.
*/
#define IFM_TYPE(x) ((x) & IFM_NMASK)
-#define IFM_SUBTYPE(x) ((x) & IFM_TMASK)
+#define IFM_SUBTYPE(x) \
+ (IFM_TYPE(x) == IFM_ETHER ? IFM_ETHER_SUBTYPE_GET(x) : ((x) & IFM_TMASK))
+#define IFM_TYPE_MATCH(x,y) \
+ (IFM_TYPE(x) == IFM_TYPE(y) && IFM_SUBTYPE(x) == IFM_SUBTYPE(y))
#define IFM_TYPE_OPTIONS(x) ((x) & IFM_OMASK)
#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT)
#define IFM_OPTIONS(x) ((x) & (IFM_OMASK | IFM_GMASK))
@@ -372,6 +419,34 @@ struct ifmedia_description {
{ IFM_40G_CR4, "40Gbase-CR4" }, \
{ IFM_40G_SR4, "40Gbase-SR4" }, \
{ IFM_40G_LR4, "40Gbase-LR4" }, \
+ { IFM_1000_KX, "1000Base-KX" }, \
+ { IFM_OTHER, "Other" }, \
+ { IFM_10G_KX4, "10GBase-KX4" }, \
+ { IFM_10G_KR, "10GBase-KR" }, \
+ { IFM_10G_CR1, "10GBase-CR1" }, \
+ { IFM_20G_KR2, "20GBase-KR2" }, \
+ { IFM_2500_KX, "2500Base-KX" }, \
+ { IFM_2500_T, "2500Base-T" }, \
+ { IFM_5000_T, "5000Base-T" }, \
+ { IFM_50G_PCIE, "PCIExpress-50G" }, \
+ { IFM_25G_PCIE, "PCIExpress-25G" }, \
+ { IFM_1000_SGMII, "1000Base-SGMII" }, \
+ { IFM_10G_SFI, "10GBase-SFI" }, \
+ { IFM_40G_XLPPI, "40GBase-XLPPI" }, \
+ { IFM_1000_CX_SGMII, "1000Base-CX-SGMII" }, \
+ { IFM_40G_KR4, "40GBase-KR4" }, \
+ { IFM_10G_ER, "10GBase-ER" }, \
+ { IFM_100G_CR4, "100GBase-CR4" }, \
+ { IFM_100G_SR4, "100GBase-SR4" }, \
+ { IFM_100G_KR4, "100GBase-KR4" }, \
+ { IFM_100G_LR4, "100GBase-LR4" }, \
+ { IFM_56G_R4, "56GBase-R4" }, \
+ { IFM_100_T, "100BaseT" }, \
+ { IFM_25G_CR, "25GBase-CR" }, \
+ { IFM_25G_KR, "25GBase-KR" }, \
+ { IFM_25G_SR, "25GBase-SR" }, \
+ { IFM_50G_CR2, "50GBase-CR2" }, \
+ { IFM_50G_KR2, "50GBase-KR2" }, \
{ 0, NULL }, \
}
@@ -673,6 +748,33 @@ struct ifmedia_baudrate {
{ IFM_ETHER | IFM_40G_CR4, IF_Gbps(40ULL) }, \
{ IFM_ETHER | IFM_40G_SR4, IF_Gbps(40ULL) }, \
{ IFM_ETHER | IFM_40G_LR4, IF_Gbps(40ULL) }, \
+ { IFM_ETHER | IFM_1000_KX, IF_Mbps(1000) }, \
+ { IFM_ETHER | IFM_10G_KX4, IF_Gbps(10ULL) }, \
+ { IFM_ETHER | IFM_10G_KR, IF_Gbps(10ULL) }, \
+ { IFM_ETHER | IFM_10G_CR1, IF_Gbps(10ULL) }, \
+ { IFM_ETHER | IFM_20G_KR2, IF_Gbps(20ULL) }, \
+ { IFM_ETHER | IFM_2500_KX, IF_Mbps(2500) }, \
+ { IFM_ETHER | IFM_2500_T, IF_Mbps(2500) }, \
+ { IFM_ETHER | IFM_5000_T, IF_Mbps(5000) }, \
+ { IFM_ETHER | IFM_50G_PCIE, IF_Gbps(50ULL) }, \
+ { IFM_ETHER | IFM_25G_PCIE, IF_Gbps(25ULL) }, \
+ { IFM_ETHER | IFM_1000_SGMII, IF_Mbps(1000) }, \
+ { IFM_ETHER | IFM_10G_SFI, IF_Gbps(10ULL) }, \
+ { IFM_ETHER | IFM_40G_XLPPI, IF_Gbps(40ULL) }, \
+ { IFM_ETHER | IFM_1000_CX_SGMII, IF_Mbps(1000) }, \
+ { IFM_ETHER | IFM_40G_KR4, IF_Gbps(40ULL) }, \
+ { IFM_ETHER | IFM_10G_ER, IF_Gbps(10ULL) }, \
+ { IFM_ETHER | IFM_100G_CR4, IF_Gbps(100ULL) }, \
+ { IFM_ETHER | IFM_100G_SR4, IF_Gbps(100ULL) }, \
+ { IFM_ETHER | IFM_100G_KR4, IF_Gbps(100ULL) }, \
+ { IFM_ETHER | IFM_100G_LR4, IF_Gbps(100ULL) }, \
+ { IFM_ETHER | IFM_56G_R4, IF_Gbps(56ULL) }, \
+ { IFM_ETHER | IFM_100_T, IF_Mbps(100ULL) }, \
+ { IFM_ETHER | IFM_25G_CR, IF_Gbps(25ULL) }, \
+ { IFM_ETHER | IFM_25G_KR, IF_Gbps(25ULL) }, \
+ { IFM_ETHER | IFM_25G_SR, IF_Gbps(25ULL) }, \
+ { IFM_ETHER | IFM_50G_CR2, IF_Gbps(50ULL) }, \
+ { IFM_ETHER | IFM_50G_KR2, IF_Gbps(50ULL) }, \
\
{ IFM_TOKEN | IFM_TOK_STP4, IF_Mbps(4) }, \
{ IFM_TOKEN | IFM_TOK_STP16, IF_Mbps(16) }, \
diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c
index 5f6f0aa..b23ab34 100644
--- a/sys/net/if_tap.c
+++ b/sys/net/if_tap.c
@@ -156,7 +156,6 @@ static int tapdebug = 0; /* debug flag */
static int tapuopen = 0; /* allow user open() */
static int tapuponopen = 0; /* IFF_UP on open() */
static int tapdclone = 1; /* enable devfs cloning */
-static int tapclosedeladdrs = 1; /* del addrs on close */
static SLIST_HEAD(, tap_softc) taphead; /* first device */
static struct clonedevs *tapclones;
@@ -173,9 +172,6 @@ SYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0,
"Bring interface up when /dev/tap is opened");
SYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RWTUN, &tapdclone, 0,
"Enably legacy devfs interface creation");
-SYSCTL_INT(_net_link_tap, OID_AUTO, deladdrs_on_close, CTLFLAG_RW,
- &tapclosedeladdrs, 0, "Delete addresses and routes when /dev/tap is "
- "closed");
SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
DEV_MODULE(if_tap, tapmodevent, NULL);
@@ -536,12 +532,11 @@ tapclose(struct cdev *dev, int foo, int bar, struct thread *td)
IF_DRAIN(&ifp->if_snd);
/*
- * do not bring the interface down, and do not anything with
- * interface, if we are in VMnet mode. just close the device.
+ * Do not bring the interface down, and do not anything with
+ * interface, if we are in VMnet mode. Just close the device.
*/
-
- if (tapclosedeladdrs == 1 && ((tp->tap_flags & TAP_VMNET) == 0) &&
- (ifp->if_flags & IFF_UP)) {
+ if (((tp->tap_flags & TAP_VMNET) == 0) &&
+ (ifp->if_flags & (IFF_UP | IFF_LINK0)) == IFF_UP) {
mtx_unlock(&tp->tap_mtx);
if_down(ifp);
mtx_lock(&tp->tap_mtx);
diff --git a/sys/net/if_types.h b/sys/net/if_types.h
index c9b20db..92e101a 100644
--- a/sys/net/if_types.h
+++ b/sys/net/if_types.h
@@ -42,211 +42,232 @@
* http://www.iana.org/assignments/smi-numbers
*/
-#define IFT_OTHER 0x1 /* none of the following */
-#define IFT_1822 0x2 /* old-style arpanet imp */
-#define IFT_HDH1822 0x3 /* HDH arpanet imp */
-#define IFT_X25DDN 0x4 /* x25 to imp */
-#define IFT_X25 0x5 /* PDN X25 interface (RFC877) */
-#define IFT_ETHER 0x6 /* Ethernet CSMA/CD */
-#define IFT_ISO88023 0x7 /* CMSA/CD */
-#define IFT_ISO88024 0x8 /* Token Bus */
-#define IFT_ISO88025 0x9 /* Token Ring */
-#define IFT_ISO88026 0xa /* MAN */
-#define IFT_STARLAN 0xb
-#define IFT_P10 0xc /* Proteon 10MBit ring */
-#define IFT_P80 0xd /* Proteon 80MBit ring */
-#define IFT_HY 0xe /* Hyperchannel */
-#define IFT_FDDI 0xf
-#define IFT_LAPB 0x10
-#define IFT_SDLC 0x11
-#define IFT_T1 0x12
-#define IFT_CEPT 0x13 /* E1 - european T1 */
-#define IFT_ISDNBASIC 0x14
-#define IFT_ISDNPRIMARY 0x15
-#define IFT_PTPSERIAL 0x16 /* Proprietary PTP serial */
-#define IFT_PPP 0x17 /* RFC 1331 */
-#define IFT_LOOP 0x18 /* loopback */
-#define IFT_EON 0x19 /* ISO over IP */
-#define IFT_XETHER 0x1a /* obsolete 3MB experimental ethernet */
-#define IFT_NSIP 0x1b /* XNS over IP */
-#define IFT_SLIP 0x1c /* IP over generic TTY */
-#define IFT_ULTRA 0x1d /* Ultra Technologies */
-#define IFT_DS3 0x1e /* Generic T3 */
-#define IFT_SIP 0x1f /* SMDS */
-#define IFT_FRELAY 0x20 /* Frame Relay DTE only */
-#define IFT_RS232 0x21
-#define IFT_PARA 0x22 /* parallel-port */
-#define IFT_ARCNET 0x23
-#define IFT_ARCNETPLUS 0x24
-#define IFT_ATM 0x25 /* ATM cells */
-#define IFT_MIOX25 0x26
-#define IFT_SONET 0x27 /* SONET or SDH */
-#define IFT_X25PLE 0x28
-#define IFT_ISO88022LLC 0x29
-#define IFT_LOCALTALK 0x2a
-#define IFT_SMDSDXI 0x2b
-#define IFT_FRELAYDCE 0x2c /* Frame Relay DCE */
-#define IFT_V35 0x2d
-#define IFT_HSSI 0x2e
-#define IFT_HIPPI 0x2f
-#define IFT_MODEM 0x30 /* Generic Modem */
-#define IFT_AAL5 0x31 /* AAL5 over ATM */
-#define IFT_SONETPATH 0x32
-#define IFT_SONETVT 0x33
-#define IFT_SMDSICIP 0x34 /* SMDS InterCarrier Interface */
-#define IFT_PROPVIRTUAL 0x35 /* Proprietary Virtual/internal */
-#define IFT_PROPMUX 0x36 /* Proprietary Multiplexing */
-#define IFT_IEEE80212 0x37 /* 100BaseVG */
-#define IFT_FIBRECHANNEL 0x38 /* Fibre Channel */
-#define IFT_HIPPIINTERFACE 0x39 /* HIPPI interfaces */
-#define IFT_FRAMERELAYINTERCONNECT 0x3a /* Obsolete, use either 0x20 or 0x2c */
-#define IFT_AFLANE8023 0x3b /* ATM Emulated LAN for 802.3 */
-#define IFT_AFLANE8025 0x3c /* ATM Emulated LAN for 802.5 */
-#define IFT_CCTEMUL 0x3d /* ATM Emulated circuit */
-#define IFT_FASTETHER 0x3e /* Fast Ethernet (100BaseT) */
-#define IFT_ISDN 0x3f /* ISDN and X.25 */
-#define IFT_V11 0x40 /* CCITT V.11/X.21 */
-#define IFT_V36 0x41 /* CCITT V.36 */
-#define IFT_G703AT64K 0x42 /* CCITT G703 at 64Kbps */
-#define IFT_G703AT2MB 0x43 /* Obsolete see DS1-MIB */
-#define IFT_QLLC 0x44 /* SNA QLLC */
-#define IFT_FASTETHERFX 0x45 /* Fast Ethernet (100BaseFX) */
-#define IFT_CHANNEL 0x46 /* channel */
-#define IFT_IEEE80211 0x47 /* radio spread spectrum */
-#define IFT_IBM370PARCHAN 0x48 /* IBM System 360/370 OEMI Channel */
-#define IFT_ESCON 0x49 /* IBM Enterprise Systems Connection */
-#define IFT_DLSW 0x4a /* Data Link Switching */
-#define IFT_ISDNS 0x4b /* ISDN S/T interface */
-#define IFT_ISDNU 0x4c /* ISDN U interface */
-#define IFT_LAPD 0x4d /* Link Access Protocol D */
-#define IFT_IPSWITCH 0x4e /* IP Switching Objects */
-#define IFT_RSRB 0x4f /* Remote Source Route Bridging */
-#define IFT_ATMLOGICAL 0x50 /* ATM Logical Port */
-#define IFT_DS0 0x51 /* Digital Signal Level 0 */
-#define IFT_DS0BUNDLE 0x52 /* group of ds0s on the same ds1 */
-#define IFT_BSC 0x53 /* Bisynchronous Protocol */
-#define IFT_ASYNC 0x54 /* Asynchronous Protocol */
-#define IFT_CNR 0x55 /* Combat Net Radio */
-#define IFT_ISO88025DTR 0x56 /* ISO 802.5r DTR */
-#define IFT_EPLRS 0x57 /* Ext Pos Loc Report Sys */
-#define IFT_ARAP 0x58 /* Appletalk Remote Access Protocol */
-#define IFT_PROPCNLS 0x59 /* Proprietary Connectionless Protocol*/
-#define IFT_HOSTPAD 0x5a /* CCITT-ITU X.29 PAD Protocol */
-#define IFT_TERMPAD 0x5b /* CCITT-ITU X.3 PAD Facility */
-#define IFT_FRAMERELAYMPI 0x5c /* Multiproto Interconnect over FR */
-#define IFT_X213 0x5d /* CCITT-ITU X213 */
-#define IFT_ADSL 0x5e /* Asymmetric Digital Subscriber Loop */
-#define IFT_RADSL 0x5f /* Rate-Adapt. Digital Subscriber Loop*/
-#define IFT_SDSL 0x60 /* Symmetric Digital Subscriber Loop */
-#define IFT_VDSL 0x61 /* Very H-Speed Digital Subscrib. Loop*/
-#define IFT_ISO88025CRFPINT 0x62 /* ISO 802.5 CRFP */
-#define IFT_MYRINET 0x63 /* Myricom Myrinet */
-#define IFT_VOICEEM 0x64 /* voice recEive and transMit */
-#define IFT_VOICEFXO 0x65 /* voice Foreign Exchange Office */
-#define IFT_VOICEFXS 0x66 /* voice Foreign Exchange Station */
-#define IFT_VOICEENCAP 0x67 /* voice encapsulation */
-#define IFT_VOICEOVERIP 0x68 /* voice over IP encapsulation */
-#define IFT_ATMDXI 0x69 /* ATM DXI */
-#define IFT_ATMFUNI 0x6a /* ATM FUNI */
-#define IFT_ATMIMA 0x6b /* ATM IMA */
-#define IFT_PPPMULTILINKBUNDLE 0x6c /* PPP Multilink Bundle */
-#define IFT_IPOVERCDLC 0x6d /* IBM ipOverCdlc */
-#define IFT_IPOVERCLAW 0x6e /* IBM Common Link Access to Workstn */
-#define IFT_STACKTOSTACK 0x6f /* IBM stackToStack */
-#define IFT_VIRTUALIPADDRESS 0x70 /* IBM VIPA */
-#define IFT_MPC 0x71 /* IBM multi-protocol channel support */
-#define IFT_IPOVERATM 0x72 /* IBM ipOverAtm */
-#define IFT_ISO88025FIBER 0x73 /* ISO 802.5j Fiber Token Ring */
-#define IFT_TDLC 0x74 /* IBM twinaxial data link control */
-#define IFT_GIGABITETHERNET 0x75 /* Gigabit Ethernet */
-#define IFT_HDLC 0x76 /* HDLC */
-#define IFT_LAPF 0x77 /* LAP F */
-#define IFT_V37 0x78 /* V.37 */
-#define IFT_X25MLP 0x79 /* Multi-Link Protocol */
-#define IFT_X25HUNTGROUP 0x7a /* X25 Hunt Group */
-#define IFT_TRANSPHDLC 0x7b /* Transp HDLC */
-#define IFT_INTERLEAVE 0x7c /* Interleave channel */
-#define IFT_FAST 0x7d /* Fast channel */
-#define IFT_IP 0x7e /* IP (for APPN HPR in IP networks) */
-#define IFT_DOCSCABLEMACLAYER 0x7f /* CATV Mac Layer */
-#define IFT_DOCSCABLEDOWNSTREAM 0x80 /* CATV Downstream interface */
-#define IFT_DOCSCABLEUPSTREAM 0x81 /* CATV Upstream interface */
-#define IFT_A12MPPSWITCH 0x82 /* Avalon Parallel Processor */
-#define IFT_TUNNEL 0x83 /* Encapsulation interface */
-#define IFT_COFFEE 0x84 /* coffee pot */
-#define IFT_CES 0x85 /* Circiut Emulation Service */
-#define IFT_ATMSUBINTERFACE 0x86 /* (x) ATM Sub Interface */
-#define IFT_L2VLAN 0x87 /* Layer 2 Virtual LAN using 802.1Q */
-#define IFT_L3IPVLAN 0x88 /* Layer 3 Virtual LAN - IP Protocol */
-#define IFT_L3IPXVLAN 0x89 /* Layer 3 Virtual LAN - IPX Prot. */
-#define IFT_DIGITALPOWERLINE 0x8a /* IP over Power Lines */
-#define IFT_MEDIAMAILOVERIP 0x8b /* (xxx) Multimedia Mail over IP */
-#define IFT_DTM 0x8c /* Dynamic synchronous Transfer Mode */
-#define IFT_DCN 0x8d /* Data Communications Network */
-#define IFT_IPFORWARD 0x8e /* IP Forwarding Interface */
-#define IFT_MSDSL 0x8f /* Multi-rate Symmetric DSL */
-#define IFT_IEEE1394 0x90 /* IEEE1394 High Performance SerialBus*/
-#define IFT_IFGSN 0x91 /* HIPPI-6400 */
-#define IFT_DVBRCCMACLAYER 0x92 /* DVB-RCC MAC Layer */
-#define IFT_DVBRCCDOWNSTREAM 0x93 /* DVB-RCC Downstream Channel */
-#define IFT_DVBRCCUPSTREAM 0x94 /* DVB-RCC Upstream Channel */
-#define IFT_ATMVIRTUAL 0x95 /* ATM Virtual Interface */
-#define IFT_MPLSTUNNEL 0x96 /* MPLS Tunnel Virtual Interface */
-#define IFT_SRP 0x97 /* Spatial Reuse Protocol */
-#define IFT_VOICEOVERATM 0x98 /* Voice over ATM */
-#define IFT_VOICEOVERFRAMERELAY 0x99 /* Voice Over Frame Relay */
-#define IFT_IDSL 0x9a /* Digital Subscriber Loop over ISDN */
-#define IFT_COMPOSITELINK 0x9b /* Avici Composite Link Interface */
-#define IFT_SS7SIGLINK 0x9c /* SS7 Signaling Link */
-#define IFT_PROPWIRELESSP2P 0x9d /* Prop. P2P wireless interface */
-#define IFT_FRFORWARD 0x9e /* Frame forward Interface */
-#define IFT_RFC1483 0x9f /* Multiprotocol over ATM AAL5 */
-#define IFT_USB 0xa0 /* USB Interface */
-#define IFT_IEEE8023ADLAG 0xa1 /* IEEE 802.3ad Link Aggregate*/
-#define IFT_BGPPOLICYACCOUNTING 0xa2 /* BGP Policy Accounting */
-#define IFT_FRF16MFRBUNDLE 0xa3 /* FRF.16 Multilik Frame Relay*/
-#define IFT_H323GATEKEEPER 0xa4 /* H323 Gatekeeper */
-#define IFT_H323PROXY 0xa5 /* H323 Voice and Video Proxy */
-#define IFT_MPLS 0xa6 /* MPLS */
-#define IFT_MFSIGLINK 0xa7 /* Multi-frequency signaling link */
-#define IFT_HDSL2 0xa8 /* High Bit-Rate DSL, 2nd gen. */
-#define IFT_SHDSL 0xa9 /* Multirate HDSL2 */
-#define IFT_DS1FDL 0xaa /* Facility Data Link (4Kbps) on a DS1*/
-#define IFT_POS 0xab /* Packet over SONET/SDH Interface */
-#define IFT_DVBASILN 0xac /* DVB-ASI Input */
-#define IFT_DVBASIOUT 0xad /* DVB-ASI Output */
-#define IFT_PLC 0xae /* Power Line Communications */
-#define IFT_NFAS 0xaf /* Non-Facility Associated Signaling */
-#define IFT_TR008 0xb0 /* TROO8 */
-#define IFT_GR303RDT 0xb1 /* Remote Digital Terminal */
-#define IFT_GR303IDT 0xb2 /* Integrated Digital Terminal */
-#define IFT_ISUP 0xb3 /* ISUP */
-#define IFT_PROPDOCSWIRELESSMACLAYER 0xb4 /* prop/Wireless MAC Layer */
-#define IFT_PROPDOCSWIRELESSDOWNSTREAM 0xb5 /* prop/Wireless Downstream */
-#define IFT_PROPDOCSWIRELESSUPSTREAM 0xb6 /* prop/Wireless Upstream */
-#define IFT_HIPERLAN2 0xb7 /* HIPERLAN Type 2 Radio Interface */
-#define IFT_PROPBWAP2MP 0xb8 /* PropBroadbandWirelessAccess P2MP*/
-#define IFT_SONETOVERHEADCHANNEL 0xb9 /* SONET Overhead Channel */
-#define IFT_DIGITALWRAPPEROVERHEADCHANNEL 0xba /* Digital Wrapper Overhead */
-#define IFT_AAL2 0xbb /* ATM adaptation layer 2 */
-#define IFT_RADIOMAC 0xbc /* MAC layer over radio links */
-#define IFT_ATMRADIO 0xbd /* ATM over radio links */
-#define IFT_IMT 0xbe /* Inter-Machine Trunks */
-#define IFT_MVL 0xbf /* Multiple Virtual Lines DSL */
-#define IFT_REACHDSL 0xc0 /* Long Reach DSL */
-#define IFT_FRDLCIENDPT 0xc1 /* Frame Relay DLCI End Point */
-#define IFT_ATMVCIENDPT 0xc2 /* ATM VCI End Point */
-#define IFT_OPTICALCHANNEL 0xc3 /* Optical Channel */
-#define IFT_OPTICALTRANSPORT 0xc4 /* Optical Transport */
-#define IFT_INFINIBAND 0xc7 /* Infiniband */
-#define IFT_BRIDGE 0xd1 /* Transparent bridge interface */
+typedef enum {
+ IFT_OTHER = 0x1, /* none of the following */
+ IFT_1822 = 0x2, /* old-style arpanet imp */
+ IFT_HDH1822 = 0x3, /* HDH arpanet imp */
+ IFT_X25DDN = 0x4, /* x25 to imp */
+ IFT_X25 = 0x5, /* PDN X25 interface (RFC877) */
+ IFT_ETHER = 0x6, /* Ethernet CSMA/CD */
+ IFT_ISO88023 = 0x7, /* CMSA/CD */
+ IFT_ISO88024 = 0x8, /* Token Bus */
+ IFT_ISO88025 = 0x9, /* Token Ring */
+ IFT_ISO88026 = 0xa, /* MAN */
+ IFT_STARLAN = 0xb,
+ IFT_P10 = 0xc, /* Proteon 10MBit ring */
+ IFT_P80 = 0xd, /* Proteon 80MBit ring */
+ IFT_HY = 0xe, /* Hyperchannel */
+ IFT_FDDI = 0xf,
+ IFT_LAPB = 0x10,
+ IFT_SDLC = 0x11,
+ IFT_T1 = 0x12,
+ IFT_CEPT = 0x13, /* E1 - european T1 */
+ IFT_ISDNBASIC = 0x14,
+ IFT_ISDNPRIMARY = 0x15,
+ IFT_PTPSERIAL = 0x16, /* Proprietary PTP serial */
+ IFT_PPP = 0x17, /* RFC 1331 */
+ IFT_LOOP = 0x18, /* loopback */
+ IFT_EON = 0x19, /* ISO over IP */
+ IFT_XETHER = 0x1a, /* obsolete 3MB experimental ethernet */
+ IFT_NSIP = 0x1b, /* XNS over IP */
+ IFT_SLIP = 0x1c, /* IP over generic TTY */
+ IFT_ULTRA = 0x1d, /* Ultra Technologies */
+ IFT_DS3 = 0x1e, /* Generic T3 */
+ IFT_SIP = 0x1f, /* SMDS */
+ IFT_FRELAY = 0x20, /* Frame Relay DTE only */
+ IFT_RS232 = 0x21,
+ IFT_PARA = 0x22, /* parallel-port */
+ IFT_ARCNET = 0x23,
+ IFT_ARCNETPLUS = 0x24,
+ IFT_ATM = 0x25, /* ATM cells */
+ IFT_MIOX25 = 0x26,
+ IFT_SONET = 0x27, /* SONET or SDH */
+ IFT_X25PLE = 0x28,
+ IFT_ISO88022LLC = 0x29,
+ IFT_LOCALTALK = 0x2a,
+ IFT_SMDSDXI = 0x2b,
+ IFT_FRELAYDCE = 0x2c, /* Frame Relay DCE */
+ IFT_V35 = 0x2d,
+ IFT_HSSI = 0x2e,
+ IFT_HIPPI = 0x2f,
+ IFT_MODEM = 0x30, /* Generic Modem */
+ IFT_AAL5 = 0x31, /* AAL5 over ATM */
+ IFT_SONETPATH = 0x32,
+ IFT_SONETVT = 0x33,
+ IFT_SMDSICIP = 0x34, /* SMDS InterCarrier Interface */
+ IFT_PROPVIRTUAL = 0x35, /* Proprietary Virtual/internal */
+ IFT_PROPMUX = 0x36, /* Proprietary Multiplexing */
+ IFT_IEEE80212 = 0x37, /* 100BaseVG */
+ IFT_FIBRECHANNEL = 0x38, /* Fibre Channel */
+ IFT_HIPPIINTERFACE = 0x39, /* HIPPI interfaces */
+ IFT_FRAMERELAYINTERCONNECT = 0x3a, /* Obsolete, use 0x20 either 0x2c */
+ IFT_AFLANE8023 = 0x3b, /* ATM Emulated LAN for 802.3 */
+ IFT_AFLANE8025 = 0x3c, /* ATM Emulated LAN for 802.5 */
+ IFT_CCTEMUL = 0x3d, /* ATM Emulated circuit */
+ IFT_FASTETHER = 0x3e, /* Fast Ethernet (100BaseT) */
+ IFT_ISDN = 0x3f, /* ISDN and X.25 */
+ IFT_V11 = 0x40, /* CCITT V.11/X.21 */
+ IFT_V36 = 0x41, /* CCITT V.36 */
+ IFT_G703AT64K = 0x42, /* CCITT G703 at 64Kbps */
+ IFT_G703AT2MB = 0x43, /* Obsolete see DS1-MIB */
+ IFT_QLLC = 0x44, /* SNA QLLC */
+ IFT_FASTETHERFX = 0x45, /* Fast Ethernet (100BaseFX) */
+ IFT_CHANNEL = 0x46, /* channel */
+ IFT_IEEE80211 = 0x47, /* radio spread spectrum */
+ IFT_IBM370PARCHAN = 0x48, /* IBM System 360/370 OEMI Channel */
+ IFT_ESCON = 0x49, /* IBM Enterprise Systems Connection */
+ IFT_DLSW = 0x4a, /* Data Link Switching */
+ IFT_ISDNS = 0x4b, /* ISDN S/T interface */
+ IFT_ISDNU = 0x4c, /* ISDN U interface */
+ IFT_LAPD = 0x4d, /* Link Access Protocol D */
+ IFT_IPSWITCH = 0x4e, /* IP Switching Objects */
+ IFT_RSRB = 0x4f, /* Remote Source Route Bridging */
+ IFT_ATMLOGICAL = 0x50, /* ATM Logical Port */
+ IFT_DS0 = 0x51, /* Digital Signal Level 0 */
+ IFT_DS0BUNDLE = 0x52, /* group of ds0s on the same ds1 */
+ IFT_BSC = 0x53, /* Bisynchronous Protocol */
+ IFT_ASYNC = 0x54, /* Asynchronous Protocol */
+ IFT_CNR = 0x55, /* Combat Net Radio */
+ IFT_ISO88025DTR = 0x56, /* ISO 802.5r DTR */
+ IFT_EPLRS = 0x57, /* Ext Pos Loc Report Sys */
+ IFT_ARAP = 0x58, /* Appletalk Remote Access Protocol */
+ IFT_PROPCNLS = 0x59, /* Proprietary Connectionless Protocol*/
+ IFT_HOSTPAD = 0x5a, /* CCITT-ITU X.29 PAD Protocol */
+ IFT_TERMPAD = 0x5b, /* CCITT-ITU X.3 PAD Facility */
+ IFT_FRAMERELAYMPI = 0x5c, /* Multiproto Interconnect over FR */
+ IFT_X213 = 0x5d, /* CCITT-ITU X213 */
+ IFT_ADSL = 0x5e, /* Asymmetric Digital Subscriber Loop */
+ IFT_RADSL = 0x5f, /* Rate-Adapt. Digital Subscriber Loop*/
+ IFT_SDSL = 0x60, /* Symmetric Digital Subscriber Loop */
+ IFT_VDSL = 0x61, /* Very H-Speed Digital Subscrib. Loop*/
+ IFT_ISO88025CRFPINT = 0x62, /* ISO 802.5 CRFP */
+ IFT_MYRINET = 0x63, /* Myricom Myrinet */
+ IFT_VOICEEM = 0x64, /* voice recEive and transMit */
+ IFT_VOICEFXO = 0x65, /* voice Foreign Exchange Office */
+ IFT_VOICEFXS = 0x66, /* voice Foreign Exchange Station */
+ IFT_VOICEENCAP = 0x67, /* voice encapsulation */
+ IFT_VOICEOVERIP = 0x68, /* voice over IP encapsulation */
+ IFT_ATMDXI = 0x69, /* ATM DXI */
+ IFT_ATMFUNI = 0x6a, /* ATM FUNI */
+ IFT_ATMIMA = 0x6b, /* ATM IMA */
+ IFT_PPPMULTILINKBUNDLE = 0x6c, /* PPP Multilink Bundle */
+ IFT_IPOVERCDLC = 0x6d, /* IBM ipOverCdlc */
+ IFT_IPOVERCLAW = 0x6e, /* IBM Common Link Access to Workstn */
+ IFT_STACKTOSTACK = 0x6f, /* IBM stackToStack */
+ IFT_VIRTUALIPADDRESS = 0x70, /* IBM VIPA */
+ IFT_MPC = 0x71, /* IBM multi-protocol channel support */
+ IFT_IPOVERATM = 0x72, /* IBM ipOverAtm */
+ IFT_ISO88025FIBER = 0x73, /* ISO 802.5j Fiber Token Ring */
+ IFT_TDLC = 0x74, /* IBM twinaxial data link control */
+ IFT_GIGABITETHERNET = 0x75, /* Gigabit Ethernet */
+ IFT_HDLC = 0x76, /* HDLC */
+ IFT_LAPF = 0x77, /* LAP F */
+ IFT_V37 = 0x78, /* V.37 */
+ IFT_X25MLP = 0x79, /* Multi-Link Protocol */
+ IFT_X25HUNTGROUP = 0x7a, /* X25 Hunt Group */
+ IFT_TRANSPHDLC = 0x7b, /* Transp HDLC */
+ IFT_INTERLEAVE = 0x7c, /* Interleave channel */
+ IFT_FAST = 0x7d, /* Fast channel */
+ IFT_IP = 0x7e, /* IP (for APPN HPR in IP networks) */
+ IFT_DOCSCABLEMACLAYER = 0x7f, /* CATV Mac Layer */
+ IFT_DOCSCABLEDOWNSTREAM = 0x80, /* CATV Downstream interface */
+ IFT_DOCSCABLEUPSTREAM = 0x81, /* CATV Upstream interface */
+ IFT_A12MPPSWITCH = 0x82, /* Avalon Parallel Processor */
+ IFT_TUNNEL = 0x83, /* Encapsulation interface */
+ IFT_COFFEE = 0x84, /* coffee pot */
+ IFT_CES = 0x85, /* Circiut Emulation Service */
+ IFT_ATMSUBINTERFACE = 0x86, /* (x) ATM Sub Interface */
+ IFT_L2VLAN = 0x87, /* Layer 2 Virtual LAN using 802.1Q */
+ IFT_L3IPVLAN = 0x88, /* Layer 3 Virtual LAN - IP Protocol */
+ IFT_L3IPXVLAN = 0x89, /* Layer 3 Virtual LAN - IPX Prot. */
+ IFT_DIGITALPOWERLINE = 0x8a, /* IP over Power Lines */
+ IFT_MEDIAMAILOVERIP = 0x8b, /* (xxx) Multimedia Mail over IP */
+ IFT_DTM = 0x8c, /* Dynamic synchronous Transfer Mode */
+ IFT_DCN = 0x8d, /* Data Communications Network */
+ IFT_IPFORWARD = 0x8e, /* IP Forwarding Interface */
+ IFT_MSDSL = 0x8f, /* Multi-rate Symmetric DSL */
+ IFT_IEEE1394 = 0x90, /* IEEE1394 High Performance SerialBus*/
+ IFT_IFGSN = 0x91, /* HIPPI-6400 */
+ IFT_DVBRCCMACLAYER = 0x92, /* DVB-RCC MAC Layer */
+ IFT_DVBRCCDOWNSTREAM = 0x93, /* DVB-RCC Downstream Channel */
+ IFT_DVBRCCUPSTREAM = 0x94, /* DVB-RCC Upstream Channel */
+ IFT_ATMVIRTUAL = 0x95, /* ATM Virtual Interface */
+ IFT_MPLSTUNNEL = 0x96, /* MPLS Tunnel Virtual Interface */
+ IFT_SRP = 0x97, /* Spatial Reuse Protocol */
+ IFT_VOICEOVERATM = 0x98, /* Voice over ATM */
+ IFT_VOICEOVERFRAMERELAY = 0x99, /* Voice Over Frame Relay */
+ IFT_IDSL = 0x9a, /* Digital Subscriber Loop over ISDN */
+ IFT_COMPOSITELINK = 0x9b, /* Avici Composite Link Interface */
+ IFT_SS7SIGLINK = 0x9c, /* SS7 Signaling Link */
+ IFT_PROPWIRELESSP2P = 0x9d, /* Prop. P2P wireless interface */
+ IFT_FRFORWARD = 0x9e, /* Frame forward Interface */
+ IFT_RFC1483 = 0x9f, /* Multiprotocol over ATM AAL5 */
+ IFT_USB = 0xa0, /* USB Interface */
+ IFT_IEEE8023ADLAG = 0xa1, /* IEEE 802.3ad Link Aggregate*/
+ IFT_BGPPOLICYACCOUNTING = 0xa2, /* BGP Policy Accounting */
+ IFT_FRF16MFRBUNDLE = 0xa3, /* FRF.16 Multilik Frame Relay*/
+ IFT_H323GATEKEEPER = 0xa4, /* H323 Gatekeeper */
+ IFT_H323PROXY = 0xa5, /* H323 Voice and Video Proxy */
+ IFT_MPLS = 0xa6, /* MPLS */
+ IFT_MFSIGLINK = 0xa7, /* Multi-frequency signaling link */
+ IFT_HDSL2 = 0xa8, /* High Bit-Rate DSL, 2nd gen. */
+ IFT_SHDSL = 0xa9, /* Multirate HDSL2 */
+ IFT_DS1FDL = 0xaa, /* Facility Data Link (4Kbps) on a DS1*/
+ IFT_POS = 0xab, /* Packet over SONET/SDH Interface */
+ IFT_DVBASILN = 0xac, /* DVB-ASI Input */
+ IFT_DVBASIOUT = 0xad, /* DVB-ASI Output */
+ IFT_PLC = 0xae, /* Power Line Communications */
+ IFT_NFAS = 0xaf, /* Non-Facility Associated Signaling */
+ IFT_TR008 = 0xb0, /* TROO8 */
+ IFT_GR303RDT = 0xb1, /* Remote Digital Terminal */
+ IFT_GR303IDT = 0xb2, /* Integrated Digital Terminal */
+ IFT_ISUP = 0xb3, /* ISUP */
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4, /* prop/Wireless MAC Layer */
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5, /* prop/Wireless Downstream */
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6, /* prop/Wireless Upstream */
+ IFT_HIPERLAN2 = 0xb7, /* HIPERLAN Type 2 Radio Interface */
+ IFT_PROPBWAP2MP = 0xb8, /* PropBroadbandWirelessAccess P2MP*/
+ IFT_SONETOVERHEADCHANNEL = 0xb9, /* SONET Overhead Channel */
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba, /* Digital Wrapper Overhead */
+ IFT_AAL2 = 0xbb, /* ATM adaptation layer 2 */
+ IFT_RADIOMAC = 0xbc, /* MAC layer over radio links */
+ IFT_ATMRADIO = 0xbd, /* ATM over radio links */
+ IFT_IMT = 0xbe, /* Inter-Machine Trunks */
+ IFT_MVL = 0xbf, /* Multiple Virtual Lines DSL */
+ IFT_REACHDSL = 0xc0, /* Long Reach DSL */
+ IFT_FRDLCIENDPT = 0xc1, /* Frame Relay DLCI End Point */
+ IFT_ATMVCIENDPT = 0xc2, /* ATM VCI End Point */
+ IFT_OPTICALCHANNEL = 0xc3, /* Optical Channel */
+ IFT_OPTICALTRANSPORT = 0xc4, /* Optical Transport */
+ IFT_INFINIBAND = 0xc7, /* Infiniband */
+ IFT_BRIDGE = 0xd1, /* Transparent bridge interface */
+ IFT_STF = 0xd7, /* 6to4 interface */
-#define IFT_STF 0xd7 /* 6to4 interface */
+ /*
+ * Not based on IANA assignments. Conflicting with IANA assignments.
+ * We should make them negative probably.
+ * This requires changes to struct if_data.
+ */
+ IFT_GIF = 0xf0, /* Generic tunnel interface */
+ IFT_PVC = 0xf1, /* Unused */
+ IFT_ENC = 0xf4, /* Encapsulating interface */
+ IFT_PFLOG = 0xf6, /* PF packet filter logging */
+ IFT_PFSYNC = 0xf7, /* PF packet filter synchronization */
+} ifType;
+
+/*
+ * Some (broken) software uses #ifdef IFT_TYPE to check whether
+ * an operating systems supports certain interface type. Lack of
+ * ifdef leads to a piece of functionality compiled out.
+ */
+#ifndef BURN_BRIDGES
+#define IFT_BRIDGE IFT_BRIDGE
+#define IFT_PPP IFT_PPP
+#define IFT_PROPVIRTUAL IFT_PROPVIRTUAL
+#define IFT_L2VLAN IFT_L2VLAN
+#define IFT_L3IPVLAN IFT_L3IPVLAN
+#define IFT_IEEE1394 IFT_IEEE1394
+#define IFT_INFINIBAND IFT_INFINIBAND
+#endif
-/* not based on IANA assignments */
-#define IFT_GIF 0xf0
-#define IFT_PVC 0xf1
-#define IFT_ENC 0xf4
-#define IFT_PFLOG 0xf6
-#define IFT_PFSYNC 0xf7
#endif /* !_NET_IF_TYPES_H_ */
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index c770374..4af6b52 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -83,7 +83,7 @@ struct netmap_adapter;
#define IF_DUNIT_NONE -1
-#include <altq/if_altq.h>
+#include <net/altq/if_altq.h>
TAILQ_HEAD(ifnethead, ifnet); /* we use TAILQs so that the order of */
TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 0753e0a..462c907 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1705,27 +1705,6 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
break;
- case SIOCSIFCAP:
- VLAN_LOCK();
- if (TRUNK(ifv) != NULL) {
- p = PARENT(ifv);
- VLAN_UNLOCK();
- if ((p->if_type != IFT_ETHER) &&
- (ifr->ifr_reqcap & IFCAP_VLAN_HWTAGGING) == 0) {
- error = EINVAL;
- break;
- }
- error = (*p->if_ioctl)(p, cmd, data);
- if (error)
- break;
- /* Propogate vlan interface capabilities */
- vlan_trunk_capabilities(p);
- } else {
- VLAN_UNLOCK();
- error = EINVAL;
- }
- break;
-
default:
error = EINVAL;
break;
diff --git a/sys/net/ifq.h b/sys/net/ifq.h
index d1fc3fe..769d5a5 100644
--- a/sys/net/ifq.h
+++ b/sys/net/ifq.h
@@ -47,7 +47,7 @@
*/
#define IF_DUNIT_NONE -1
-#include <altq/if_altq.h>
+#include <net/altq/if_altq.h>
/*
* Structure defining a queue for a network interface.
diff --git a/sys/net/netisr.c b/sys/net/netisr.c
index 178c3cb..4b3576d 100644
--- a/sys/net/netisr.c
+++ b/sys/net/netisr.c
@@ -156,10 +156,13 @@ SYSCTL_PROC(_net_isr, OID_AUTO, dispatch, CTLTYPE_STRING | CTLFLAG_RWTUN,
/*
* Allow the administrator to limit the number of threads (CPUs) to use for
* netisr. We don't check netisr_maxthreads before creating the thread for
- * CPU 0, so in practice we ignore values <= 1. This must be set at boot.
- * We will create at most one thread per CPU.
+ * CPU 0. This must be set at boot. We will create at most one thread per CPU.
+ * By default we initialize this to 1 which would assign just 1 cpu (cpu0) and
+ * therefore only 1 workstream. If set to -1, netisr would use all cpus
+ * (mp_ncpus) and therefore would have those many workstreams. One workstream
+ * per thread (CPU).
*/
-static int netisr_maxthreads = -1; /* Max number of threads. */
+static int netisr_maxthreads = 1; /* Max number of threads. */
SYSCTL_INT(_net_isr, OID_AUTO, maxthreads, CTLFLAG_RDTUN,
&netisr_maxthreads, 0,
"Use at most this many CPUs for netisr processing");
@@ -1120,8 +1123,10 @@ netisr_init(void *arg)
KASSERT(curcpu == 0, ("%s: not on CPU 0", __func__));
NETISR_LOCK_INIT();
- if (netisr_maxthreads < 1)
- netisr_maxthreads = 1;
+ if (netisr_maxthreads == 0 || netisr_maxthreads < -1 )
+ netisr_maxthreads = 1; /* default behavior */
+ else if (netisr_maxthreads == -1)
+ netisr_maxthreads = mp_ncpus; /* use max cpus */
if (netisr_maxthreads > mp_ncpus) {
printf("netisr_init: forcing maxthreads from %d to %d\n",
netisr_maxthreads, mp_ncpus);
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index a79f412..4a5f2a0 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -192,21 +192,20 @@ extern struct rwlock pf_rules_lock;
#define PF_AEQ(a, b, c) \
((c == AF_INET && (a)->addr32[0] == (b)->addr32[0]) || \
- ((a)->addr32[3] == (b)->addr32[3] && \
+ (c == AF_INET6 && (a)->addr32[3] == (b)->addr32[3] && \
(a)->addr32[2] == (b)->addr32[2] && \
(a)->addr32[1] == (b)->addr32[1] && \
(a)->addr32[0] == (b)->addr32[0])) \
#define PF_ANEQ(a, b, c) \
- ((c == AF_INET && (a)->addr32[0] != (b)->addr32[0]) || \
- ((a)->addr32[3] != (b)->addr32[3] || \
- (a)->addr32[2] != (b)->addr32[2] || \
+ ((a)->addr32[0] != (b)->addr32[0] || \
(a)->addr32[1] != (b)->addr32[1] || \
- (a)->addr32[0] != (b)->addr32[0])) \
+ (a)->addr32[2] != (b)->addr32[2] || \
+ (a)->addr32[3] != (b)->addr32[3]) \
#define PF_AZERO(a, c) \
((c == AF_INET && !(a)->addr32[0]) || \
- (!(a)->addr32[0] && !(a)->addr32[1] && \
+ (c == AF_INET6 && !(a)->addr32[0] && !(a)->addr32[1] && \
!(a)->addr32[2] && !(a)->addr32[3] )) \
#define PF_MATCHA(n, a, m, b, f) \
diff --git a/sys/net/route.c b/sys/net/route.c
index 8ab9e22..992cf8e 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -43,7 +43,6 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/syslog.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c
index 8cd95c6..de9d60b 100644
--- a/sys/net80211/ieee80211_mesh.c
+++ b/sys/net80211/ieee80211_mesh.c
@@ -126,7 +126,7 @@ static int ieee80211_mesh_backofftimeout = -1;
SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, backofftimeout, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_mesh_backofftimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
"Backoff timeout (msec). This is to throutles peering forever when "
- "not receving answer or is rejected by a neighbor");
+ "not receiving answer or is rejected by a neighbor");
static int ieee80211_mesh_maxretries = 2;
SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLFLAG_RW,
&ieee80211_mesh_maxretries, 0,
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_cmds.c b/sys/netgraph/bluetooth/hci/ng_hci_cmds.c
index 1dc9854..0edb44c 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_cmds.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_cmds.c
@@ -71,11 +71,15 @@ static int process_status_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_testing_params
(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
+static int process_le_params
+ (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
static int process_link_control_status
(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
static int process_link_policy_status
(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
+static int process_le_status
+ (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
/*
* Send HCI command to the driver.
@@ -222,7 +226,10 @@ ng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e)
error = process_testing_params(unit,
NG_HCI_OCF(ep->opcode), cp, e);
break;
-
+ case NG_HCI_OGF_LE:
+ error = process_le_params(unit,
+ NG_HCI_OCF(ep->opcode), cp, e);
+ break;
case NG_HCI_OGF_BT_LOGO:
case NG_HCI_OGF_VENDOR:
NG_FREE_M(cp);
@@ -294,7 +301,9 @@ ng_hci_process_command_status(ng_hci_unit_p unit, struct mbuf *e)
case NG_HCI_OGF_LINK_POLICY:
error = process_link_policy_status(unit, ep, cp);
break;
-
+ case NG_HCI_OGF_LE:
+ error = process_le_status(unit, ep, cp);
+ break;
case NG_HCI_OGF_BT_LOGO:
case NG_HCI_OGF_VENDOR:
NG_FREE_M(cp);
@@ -604,6 +613,8 @@ process_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf,
case NG_HCI_OCF_READ_LOCAL_NAME:
case NG_HCI_OCF_READ_UNIT_CLASS:
case NG_HCI_OCF_WRITE_UNIT_CLASS:
+ case NG_HCI_OCF_READ_LE_HOST_SUPPORTED:
+ case NG_HCI_OCF_WRITE_LE_HOST_SUPPORTED:
/* These do not need post processing */
break;
@@ -796,6 +807,132 @@ process_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
return (error);
} /* process_testing_params */
+/*
+ * Process LE command return parameters
+ */
+
+static int
+process_le_params(ng_hci_unit_p unit, u_int16_t ocf,
+ struct mbuf *mcp, struct mbuf *mrp)
+{
+ int error = 0;
+
+ switch (ocf){
+ case NG_HCI_OCF_LE_SET_EVENT_MASK:
+ case NG_HCI_OCF_LE_READ_BUFFER_SIZE:
+ case NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES:
+ case NG_HCI_OCF_LE_SET_RANDOM_ADDRESS:
+ case NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS:
+ case NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER:
+ case NG_HCI_OCF_LE_SET_ADVERTISING_DATA:
+ case NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA:
+ case NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE:
+ case NG_HCI_OCF_LE_SET_SCAN_PARAMETERS:
+ case NG_HCI_OCF_LE_SET_SCAN_ENABLE:
+ case NG_HCI_OCF_LE_CREATE_CONNECTION_CANCEL:
+ case NG_HCI_OCF_LE_CLEAR_WHITE_LIST:
+ case NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE:
+ case NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST:
+ case NG_HCI_OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST:
+ case NG_HCI_OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION:
+ case NG_HCI_OCF_LE_READ_CHANNEL_MAP:
+ case NG_HCI_OCF_LE_ENCRYPT:
+ case NG_HCI_OCF_LE_RAND:
+ case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_REPLY:
+ case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY:
+ case NG_HCI_OCF_LE_READ_SUPPORTED_STATUS:
+ case NG_HCI_OCF_LE_RECEIVER_TEST:
+ case NG_HCI_OCF_LE_TRANSMITTER_TEST:
+ case NG_HCI_OCF_LE_TEST_END:
+
+ /* These do not need post processing */
+ break;
+ case NG_HCI_OCF_LE_CREATE_CONNECTION:
+ case NG_HCI_OCF_LE_CONNECTION_UPDATE:
+ case NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES:
+ case NG_HCI_OCF_LE_START_ENCRYPTION:
+
+
+ default:
+ /*
+ * None of these command was supposed to generate
+ * Command_Complete event. Instead Command_Status event
+ * should have been generated and then appropriate event
+ * should have been sent to indicate the final result.
+ */
+
+ error = EINVAL;
+ break;
+ }
+
+ NG_FREE_M(mcp);
+ NG_FREE_M(mrp);
+
+ return (error);
+
+}
+
+
+
+static int
+process_le_status(ng_hci_unit_p unit,ng_hci_command_status_ep *ep,
+ struct mbuf *mcp)
+{
+ int error = 0;
+
+ switch (NG_HCI_OCF(ep->opcode)){
+ case NG_HCI_OCF_LE_CREATE_CONNECTION:
+ case NG_HCI_OCF_LE_CONNECTION_UPDATE:
+ case NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES:
+ case NG_HCI_OCF_LE_START_ENCRYPTION:
+
+ /* These do not need post processing */
+ break;
+
+ case NG_HCI_OCF_LE_SET_EVENT_MASK:
+ case NG_HCI_OCF_LE_READ_BUFFER_SIZE:
+ case NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES:
+ case NG_HCI_OCF_LE_SET_RANDOM_ADDRESS:
+ case NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS:
+ case NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER:
+ case NG_HCI_OCF_LE_SET_ADVERTISING_DATA:
+ case NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA:
+ case NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE:
+ case NG_HCI_OCF_LE_SET_SCAN_PARAMETERS:
+ case NG_HCI_OCF_LE_SET_SCAN_ENABLE:
+ case NG_HCI_OCF_LE_CREATE_CONNECTION_CANCEL:
+ case NG_HCI_OCF_LE_CLEAR_WHITE_LIST:
+ case NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE:
+ case NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST:
+ case NG_HCI_OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST:
+ case NG_HCI_OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION:
+ case NG_HCI_OCF_LE_READ_CHANNEL_MAP:
+ case NG_HCI_OCF_LE_ENCRYPT:
+ case NG_HCI_OCF_LE_RAND:
+ case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_REPLY:
+ case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY:
+ case NG_HCI_OCF_LE_READ_SUPPORTED_STATUS:
+ case NG_HCI_OCF_LE_RECEIVER_TEST:
+ case NG_HCI_OCF_LE_TRANSMITTER_TEST:
+ case NG_HCI_OCF_LE_TEST_END:
+
+
+ default:
+ /*
+ * None of these command was supposed to generate
+ * Command_Stutus event. Command Complete instead.
+ */
+
+ error = EINVAL;
+ break;
+ }
+
+ NG_FREE_M(mcp);
+
+ return (error);
+
+}
+
/*
* Process link control command status
*/
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c b/sys/netgraph/bluetooth/hci/ng_hci_evnt.c
index b8dd21f..a31c5fb 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_evnt.c
@@ -76,6 +76,7 @@ static int page_scan_mode_change (ng_hci_unit_p, struct mbuf *);
static int page_scan_rep_mode_change (ng_hci_unit_p, struct mbuf *);
static int sync_con_queue (ng_hci_unit_p, ng_hci_unit_con_p, int);
static int send_data_packets (ng_hci_unit_p, int, int);
+static int le_event (ng_hci_unit_p, struct mbuf *);
/*
* Process HCI event packet
@@ -121,6 +122,9 @@ ng_hci_process_event(ng_hci_unit_p unit, struct mbuf *event)
/* These do not need post processing */
NG_FREE_M(event);
break;
+ case NG_HCI_EVENT_LE:
+ error = le_event(unit, event);
+ break;
case NG_HCI_EVENT_INQUIRY_RESULT:
error = inquiry_result(unit, event);
@@ -247,6 +251,7 @@ static int
send_data_packets(ng_hci_unit_p unit, int link_type, int limit)
{
ng_hci_unit_con_p con = NULL, winner = NULL;
+ int reallink_type;
item_p item = NULL;
int min_pending, total_sent, sent, error, v;
@@ -260,8 +265,11 @@ send_data_packets(ng_hci_unit_p unit, int link_type, int limit)
*/
LIST_FOREACH(con, &unit->con_list, next) {
- if (con->link_type != link_type)
+ reallink_type = (con->link_type == NG_HCI_LINK_SCO)?
+ NG_HCI_LINK_SCO: NG_HCI_LINK_ACL;
+ if (reallink_type != link_type){
continue;
+ }
if (NG_BT_ITEMQ_LEN(&con->conq) == 0)
continue;
@@ -327,7 +335,6 @@ send_data_packets(ng_hci_unit_p unit, int link_type, int limit)
/*
* Sync connection queue for the winner
*/
-
sync_con_queue(unit, winner, sent);
}
@@ -346,7 +353,7 @@ sync_con_queue(ng_hci_unit_p unit, ng_hci_unit_con_p con, int completed)
ng_hci_sync_con_queue_ep *state = NULL;
int error;
- hook = (con->link_type == NG_HCI_LINK_ACL)? unit->acl : unit->sco;
+ hook = (con->link_type != NG_HCI_LINK_SCO)? unit->acl : unit->sco;
if (hook == NULL || NG_HOOK_NOT_VALID(hook))
return (ENOTCONN);
@@ -363,6 +370,223 @@ sync_con_queue(ng_hci_unit_p unit, ng_hci_unit_con_p con, int completed)
return (error);
} /* sync_con_queue */
+/* le meta event */
+/* Inquiry result event */
+static int
+le_advertizing_report(ng_hci_unit_p unit, struct mbuf *event)
+{
+ ng_hci_le_advertising_report_ep *ep = NULL;
+ ng_hci_neighbor_p n = NULL;
+ bdaddr_t bdaddr;
+ int error = 0;
+ u_int8_t event_type;
+ u_int8_t addr_type;
+
+ NG_HCI_M_PULLUP(event, sizeof(*ep));
+ if (event == NULL)
+ return (ENOBUFS);
+
+ ep = mtod(event, ng_hci_le_advertising_report_ep *);
+ m_adj(event, sizeof(*ep));
+
+ for (; ep->num_reports > 0; ep->num_reports --) {
+ /* Get remote unit address */
+ NG_HCI_M_PULLUP(event, sizeof(u_int8_t));
+ event_type = *mtod(event, u_int8_t *);
+ m_adj(event, sizeof(u_int8_t));
+ NG_HCI_M_PULLUP(event, sizeof(u_int8_t));
+ addr_type = *mtod(event, u_int8_t *);
+ m_adj(event, sizeof(u_int8_t));
+
+ m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr);
+ m_adj(event, sizeof(bdaddr));
+
+ /* Lookup entry in the cache */
+ n = ng_hci_get_neighbor(unit, &bdaddr, (addr_type) ? NG_HCI_LINK_LE_RANDOM:NG_HCI_LINK_LE_PUBLIC);
+ if (n == NULL) {
+ /* Create new entry */
+ n = ng_hci_new_neighbor(unit);
+ if (n == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr));
+ n->addrtype = (addr_type)? NG_HCI_LINK_LE_RANDOM :
+ NG_HCI_LINK_LE_PUBLIC;
+
+ } else
+ getmicrotime(&n->updated);
+
+#if 0
+ {
+ /*
+ * TODO: Make these information
+ * Available from userland.
+ */
+ u_int8_t length_data;
+
+ char *rssi;
+
+ NG_HCI_M_PULLUP(event, sizeof(u_int8_t));
+ length_data = *mtod(event, u_int8_t *);
+ m_adj(event, sizeof(u_int8_t));
+ /*Advertizement data*/
+ NG_HCI_M_PULLUP(event, length_data);
+ m_adj(event, length_data);
+ NG_HCI_M_PULLUP(event, sizeof(char ));
+ /*Get RSSI*/
+ rssi = mtod(event, char *);
+ m_adj(event, sizeof(u_int8_t));
+ }
+#endif
+ }
+ NG_FREE_M(event);
+
+ return (error);
+} /* inquiry_result */
+
+static int le_connection_complete(ng_hci_unit_p unit, struct mbuf *event)
+{
+ int error = 0;
+
+ ng_hci_le_connection_complete_ep *ep = NULL;
+ ng_hci_unit_con_p con = NULL;
+ int link_type;
+ uint8_t uclass[3] = {0,0,0};//dummy uclass
+
+ NG_HCI_M_PULLUP(event, sizeof(*ep));
+ if (event == NULL)
+ return (ENOBUFS);
+
+ ep = mtod(event, ng_hci_le_connection_complete_ep *);
+ link_type = (ep->address_type)? NG_HCI_LINK_LE_RANDOM :
+ NG_HCI_LINK_LE_PUBLIC;
+ /*
+ * Find the first connection descriptor that matches the following:
+ *
+ * 1) con->link_type == link_type
+ * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
+ * 3) con->bdaddr == ep->address
+ */
+ LIST_FOREACH(con, &unit->con_list, next)
+ if (con->link_type == link_type &&
+ con->state == NG_HCI_CON_W4_CONN_COMPLETE &&
+ bcmp(&con->bdaddr, &ep->address, sizeof(bdaddr_t)) == 0)
+ break;
+
+ /*
+ * Two possible cases:
+ *
+ * 1) We have found connection descriptor. That means upper layer has
+ * requested this connection via LP_CON_REQ message. In this case
+ * connection must have timeout set. If ng_hci_con_untimeout() fails
+ * then timeout message already went into node's queue. In this case
+ * ignore Connection_Complete event and let timeout deal with it.
+ *
+ * 2) We do not have connection descriptor. That means upper layer
+ * nas not requested this connection , (less likely) we gave up
+ * on this connection (timeout) or as node act as slave role.
+ * The most likely scenario is that
+ * we have received LE_Create_Connection command
+ * from the RAW hook
+ */
+
+ if (con == NULL) {
+ if (ep->status != 0)
+ goto out;
+
+ con = ng_hci_new_con(unit, link_type);
+ if (con == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ con->state = NG_HCI_CON_W4_LP_CON_RSP;
+ ng_hci_con_timeout(con);
+
+ bcopy(&ep->address, &con->bdaddr, sizeof(con->bdaddr));
+ error = ng_hci_lp_con_ind(con, uclass);
+ if (error != 0) {
+ ng_hci_con_untimeout(con);
+ ng_hci_free_con(con);
+ }
+
+ } else if ((error = ng_hci_con_untimeout(con)) != 0)
+ goto out;
+
+ /*
+ * Update connection descriptor and send notification
+ * to the upper layers.
+ */
+
+ con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->handle));
+ con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE;
+
+ ng_hci_lp_con_cfm(con, ep->status);
+
+ /* Adjust connection state */
+ if (ep->status != 0)
+ ng_hci_free_con(con);
+ else {
+ con->state = NG_HCI_CON_OPEN;
+
+ /*
+ * Change link policy for the ACL connections. Enable all
+ * supported link modes. Enable Role switch as well if
+ * device supports it.
+ */
+
+ }
+
+out:
+ NG_FREE_M(event);
+
+ return (error);
+
+}
+
+static int le_connection_update(ng_hci_unit_p unit, struct mbuf *event)
+{
+ int error = 0;
+ /*TBD*/
+
+ NG_FREE_M(event);
+ return error;
+
+}
+static int
+le_event(ng_hci_unit_p unit, struct mbuf *event)
+{
+ int error = 0;
+ ng_hci_le_ep *lep;
+
+ NG_HCI_M_PULLUP(event, sizeof(*lep));
+ if(event ==NULL){
+ return ENOBUFS;
+ }
+ lep = mtod(event, ng_hci_le_ep *);
+ m_adj(event, sizeof(*lep));
+ switch(lep->subevent_code){
+ case NG_HCI_LEEV_CON_COMPL:
+ le_connection_complete(unit, event);
+ break;
+ case NG_HCI_LEEV_ADVREP:
+ le_advertizing_report(unit, event);
+ break;
+ case NG_HCI_LEEV_CON_UPDATE_COMPL:
+ le_connection_update(unit, event);
+ break;
+ case NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL:
+ //TBD
+ /*FALLTHROUGH*/
+ case NG_HCI_LEEV_LONG_TERM_KEY_REQUEST:
+ //TBD
+ /*FALLTHROUGH*/
+ default:
+ NG_FREE_M(event);
+ }
+ return error;
+}
/* Inquiry result event */
static int
@@ -386,7 +610,7 @@ inquiry_result(ng_hci_unit_p unit, struct mbuf *event)
m_adj(event, sizeof(bdaddr));
/* Lookup entry in the cache */
- n = ng_hci_get_neighbor(unit, &bdaddr);
+ n = ng_hci_get_neighbor(unit, &bdaddr, NG_HCI_LINK_ACL);
if (n == NULL) {
/* Create new entry */
n = ng_hci_new_neighbor(unit);
@@ -398,6 +622,7 @@ inquiry_result(ng_hci_unit_p unit, struct mbuf *event)
getmicrotime(&n->updated);
bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr));
+ n->addrtype = NG_HCI_LINK_ACL;
/* XXX call m_pullup here? */
@@ -754,7 +979,7 @@ read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event)
}
/* Update cache entry */
- n = ng_hci_get_neighbor(unit, &con->bdaddr);
+ n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
if (n == NULL) {
n = ng_hci_new_neighbor(unit);
if (n == NULL) {
@@ -763,6 +988,7 @@ read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event)
}
bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
+ n->addrtype = NG_HCI_LINK_ACL;
} else
getmicrotime(&n->updated);
@@ -909,7 +1135,7 @@ num_compl_pkts(ng_hci_unit_p unit, struct mbuf *event)
}
/* Update buffer descriptor */
- if (con->link_type == NG_HCI_LINK_ACL)
+ if (con->link_type != NG_HCI_LINK_SCO)
NG_HCI_BUFF_ACL_FREE(unit->buffer, p);
else
NG_HCI_BUFF_SCO_FREE(unit->buffer, p);
@@ -1010,7 +1236,7 @@ read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event)
}
/* Update cache entry */
- n = ng_hci_get_neighbor(unit, &con->bdaddr);
+ n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
if (n == NULL) {
n = ng_hci_new_neighbor(unit);
if (n == NULL) {
@@ -1019,6 +1245,7 @@ read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event)
}
bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
+ n->addrtype = NG_HCI_LINK_ACL;
} else
getmicrotime(&n->updated);
@@ -1089,7 +1316,7 @@ page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event)
ep = mtod(event, ng_hci_page_scan_mode_change_ep *);
/* Update cache entry */
- n = ng_hci_get_neighbor(unit, &ep->bdaddr);
+ n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
if (n == NULL) {
n = ng_hci_new_neighbor(unit);
if (n == NULL) {
@@ -1098,6 +1325,7 @@ page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event)
}
bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
+ n->addrtype = NG_HCI_LINK_ACL;
} else
getmicrotime(&n->updated);
@@ -1123,7 +1351,7 @@ page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event)
ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *);
/* Update cache entry */
- n = ng_hci_get_neighbor(unit, &ep->bdaddr);
+ n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
if (n == NULL) {
n = ng_hci_new_neighbor(unit);
if (n == NULL) {
@@ -1132,6 +1360,7 @@ page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event)
}
bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
+ n->addrtype = NG_HCI_LINK_ACL;
} else
getmicrotime(&n->updated);
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_main.c b/sys/netgraph/bluetooth/hci/ng_hci_main.c
index c5b3040..9abe595 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_main.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_main.c
@@ -775,7 +775,6 @@ ng_hci_acl_rcvdata(hook_p hook, item_p item)
int size, error = 0;
NG_HCI_BUFF_ACL_SIZE(unit->buffer, size);
-
/* Check packet */
NGI_GET_M(item, m);
@@ -788,7 +787,6 @@ ng_hci_acl_rcvdata(hook_p hook, item_p item)
error = EINVAL;
goto drop;
}
-
if (m->m_pkthdr.len < sizeof(ng_hci_acldata_pkt_t) ||
m->m_pkthdr.len > sizeof(ng_hci_acldata_pkt_t) + size) {
NG_HCI_ALERT(
@@ -831,7 +829,7 @@ ng_hci_acl_rcvdata(hook_p hook, item_p item)
goto drop;
}
- if (con->link_type != NG_HCI_LINK_ACL) {
+ if (con->link_type == NG_HCI_LINK_SCO) {
NG_HCI_ERR(
"%s: %s - unexpected HCI ACL data packet. Not ACL link, con_handle=%d, " \
"link_type=%d\n", __func__, NG_NODE_NAME(unit->node),
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_misc.c b/sys/netgraph/bluetooth/hci/ng_hci_misc.c
index 2209fbd..c33b873 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_misc.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_misc.c
@@ -214,7 +214,7 @@ ng_hci_flush_neighbor_cache(ng_hci_unit_p unit)
*/
ng_hci_neighbor_p
-ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr)
+ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr,int link_type)
{
ng_hci_neighbor_p n = NULL;
@@ -222,7 +222,8 @@ ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr)
ng_hci_neighbor_p nn = LIST_NEXT(n, next);
if (!ng_hci_neighbor_stale(n)) {
- if (bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0)
+ if (n->addrtype == link_type &&
+ bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0)
break;
} else
ng_hci_free_neighbor(n); /* remove old entry */
@@ -284,7 +285,7 @@ ng_hci_new_con(ng_hci_unit_p unit, int link_type)
con->link_type = link_type;
- if (con->link_type == NG_HCI_LINK_ACL)
+ if (con->link_type != NG_HCI_LINK_SCO)
NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts);
else
NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts);
@@ -313,7 +314,7 @@ ng_hci_free_con(ng_hci_unit_con_p con)
* flushed these packets and we can free them too
*/
- if (con->link_type == NG_HCI_LINK_ACL)
+ if (con->link_type != NG_HCI_LINK_SCO)
NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending);
else
NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending);
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_misc.h b/sys/netgraph/bluetooth/hci/ng_hci_misc.h
index 59e8a3b..4902c7e 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_misc.h
+++ b/sys/netgraph/bluetooth/hci/ng_hci_misc.h
@@ -41,7 +41,7 @@ void ng_hci_unit_clean (ng_hci_unit_p, int);
ng_hci_neighbor_p ng_hci_new_neighbor (ng_hci_unit_p);
void ng_hci_free_neighbor (ng_hci_neighbor_p);
void ng_hci_flush_neighbor_cache (ng_hci_unit_p);
-ng_hci_neighbor_p ng_hci_get_neighbor (ng_hci_unit_p, bdaddr_p);
+ng_hci_neighbor_p ng_hci_get_neighbor (ng_hci_unit_p, bdaddr_p, int);
int ng_hci_neighbor_stale (ng_hci_neighbor_p);
ng_hci_unit_con_p ng_hci_new_con (ng_hci_unit_p, int);
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c b/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c
index 33ed0e9..9934ea8 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c
@@ -56,6 +56,7 @@
static int ng_hci_lp_acl_con_req (ng_hci_unit_p, item_p, hook_p);
static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p);
+static int ng_hci_lp_le_con_req (ng_hci_unit_p, item_p, hook_p, int);
/*
* Process LP_ConnectReq event from the upper layer protocol
@@ -64,6 +65,8 @@ static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p);
int
ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
{
+ int link_type;
+
if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
NG_HCI_WARN(
"%s: %s - unit is not ready, state=%#x\n",
@@ -84,21 +87,30 @@ ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
return (EMSGSIZE);
}
-
- if (((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type == NG_HCI_LINK_ACL)
+ link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type;
+ switch(link_type){
+ case NG_HCI_LINK_ACL:
return (ng_hci_lp_acl_con_req(unit, item, hook));
-
- if (hook != unit->sco) {
- NG_HCI_WARN(
-"%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n",
- __func__, NG_NODE_NAME(unit->node), hook);
-
- NG_FREE_ITEM(item);
-
- return (EINVAL);
+ case NG_HCI_LINK_SCO:
+ if (hook != unit->sco ) {
+ NG_HCI_WARN(
+ "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n",
+ __func__, NG_NODE_NAME(unit->node), hook);
+
+ NG_FREE_ITEM(item);
+
+ return (EINVAL);
+ }
+
+ return (ng_hci_lp_sco_con_req(unit, item, hook));
+ case NG_HCI_LINK_LE_PUBLIC:
+ case NG_HCI_LINK_LE_RANDOM:
+ return (ng_hci_lp_le_con_req(unit, item, hook, link_type));
+ default:
+ panic("%s: link_type invalid.", __func__);
}
-
- return (ng_hci_lp_sco_con_req(unit, item, hook));
+
+ return (EINVAL);
} /* ng_hci_lp_con_req */
/*
@@ -264,7 +276,7 @@ ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
* So check the neighbor cache.
*/
- n = ng_hci_get_neighbor(unit, &ep->bdaddr);
+ n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
if (n == NULL) {
req->cp.page_scan_rep_mode = 0;
req->cp.page_scan_mode = 0;
@@ -469,6 +481,180 @@ out:
return (error);
} /* ng_hci_lp_sco_con_req */
+static int
+ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type)
+{
+ struct acl_con_req {
+ ng_hci_cmd_pkt_t hdr;
+ ng_hci_le_create_connection_cp cp;
+ } __attribute__ ((packed)) *req = NULL;
+ ng_hci_lp_con_req_ep *ep = NULL;
+ ng_hci_unit_con_p con = NULL;
+ struct mbuf *m = NULL;
+ int error = 0;
+
+ ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
+ if((link_type != NG_HCI_LINK_LE_PUBLIC)&&
+ (link_type != NG_HCI_LINK_LE_RANDOM)){
+ printf("%s: Link type %d Cannot be here \n", __func__,
+ link_type);
+ }
+ /*
+ * Only one ACL connection can exist between each pair of units.
+ * So try to find ACL connection descriptor (in any state) that
+ * has requested remote BD_ADDR.
+ *
+ * Two cases:
+ *
+ * 1) We do not have connection to the remote unit. This is simple.
+ * Just create new connection descriptor and send HCI command to
+ * create new connection.
+ *
+ * 2) We do have connection descriptor. We need to check connection
+ * state:
+ *
+ * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
+ * accepting connection from the remote unit. This is a race
+ * condition. We will ignore this message.
+ *
+ * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
+ * requested connection or we just accepted it. In any case
+ * all we need to do here is set appropriate notification bit
+ * and wait.
+ *
+ * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
+ * and let upper layer know that we have connection already.
+ */
+
+ con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type);
+ if (con != NULL) {
+ switch (con->state) {
+ case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
+ error = EALREADY;
+ break;
+
+ case NG_HCI_CON_W4_CONN_COMPLETE:
+ if (hook != unit->sco)
+ con->flags |= NG_HCI_CON_NOTIFY_ACL;
+ else
+ con->flags |= NG_HCI_CON_NOTIFY_SCO;
+ break;
+
+ case NG_HCI_CON_OPEN: {
+ struct ng_mesg *msg = NULL;
+ ng_hci_lp_con_cfm_ep *cfm = NULL;
+
+ if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
+ NGI_GET_MSG(item, msg);
+ NG_FREE_MSG(msg);
+
+ NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
+ NGM_HCI_LP_CON_CFM, sizeof(*cfm),
+ M_NOWAIT);
+ if (msg != NULL) {
+ cfm = (ng_hci_lp_con_cfm_ep *)msg->data;
+ cfm->status = 0;
+ cfm->link_type = con->link_type;
+ cfm->con_handle = con->con_handle;
+ bcopy(&con->bdaddr, &cfm->bdaddr,
+ sizeof(cfm->bdaddr));
+
+ /*
+ * This will forward item back to
+ * sender and set item to NULL
+ */
+
+ _NGI_MSG(item) = msg;
+ NG_FWD_ITEM_HOOK(error, item, hook);
+ } else
+ error = ENOMEM;
+ } else
+ NG_HCI_INFO(
+"%s: %s - Source hook is not valid, hook=%p\n",
+ __func__, NG_NODE_NAME(unit->node),
+ hook);
+ } break;
+
+ default:
+ panic(
+"%s: %s - Invalid connection state=%d\n",
+ __func__, NG_NODE_NAME(unit->node), con->state);
+ break;
+ }
+
+ goto out;
+ }
+
+ /*
+ * If we got here then we need to create new ACL connection descriptor
+ * and submit HCI command. First create new connection desriptor, set
+ * bdaddr and notification flags.
+ */
+
+ con = ng_hci_new_con(unit, link_type);
+ if (con == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
+
+ /*
+ * Create HCI command
+ */
+
+ MGETHDR(m, M_NOWAIT, MT_DATA);
+ if (m == NULL) {
+ ng_hci_free_con(con);
+ error = ENOBUFS;
+ goto out;
+ }
+
+ m->m_pkthdr.len = m->m_len = sizeof(*req);
+ req = mtod(m, struct acl_con_req *);
+ req->hdr.type = NG_HCI_CMD_PKT;
+ req->hdr.length = sizeof(req->cp);
+ req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE,
+ NG_HCI_OCF_LE_CREATE_CONNECTION));
+
+ bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr));
+ req->cp.own_address_type = 0;
+ req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0;
+ req->cp.scan_interval = htole16(4);
+ req->cp.scan_window = htole16(4);
+ req->cp.filter_policy = 0;
+ req->cp.conn_interval_min = htole16(0xf);
+ req->cp.conn_interval_max = htole16(0xf);
+ req->cp.conn_latency = htole16(0);
+ req->cp.supervision_timeout = htole16(0xc80);
+ req->cp.min_ce_length = htole16(1);
+ req->cp.max_ce_length = htole16(1);
+ /*
+ * Adust connection state
+ */
+
+ if (hook != unit->sco)
+ con->flags |= NG_HCI_CON_NOTIFY_ACL;
+ else
+ con->flags |= NG_HCI_CON_NOTIFY_SCO;
+
+ con->state = NG_HCI_CON_W4_CONN_COMPLETE;
+ ng_hci_con_timeout(con);
+
+ /*
+ * Queue and send HCI command
+ */
+
+ NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
+ if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
+ error = ng_hci_send_command(unit);
+out:
+ if (item != NULL)
+ NG_FREE_ITEM(item);
+
+ return (error);
+} /* ng_hci_lp_acl_con_req */
+
/*
* Process LP_DisconnectReq event from the upper layer protocol
*/
@@ -578,7 +764,7 @@ ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status)
* only SCO upstream hook will receive notification
*/
- if (con->link_type == NG_HCI_LINK_ACL &&
+ if (con->link_type != NG_HCI_LINK_SCO &&
con->flags & NG_HCI_CON_NOTIFY_ACL) {
if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM,
@@ -646,7 +832,7 @@ ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass)
* Use link_type to select upstream hook.
*/
- if (con->link_type == NG_HCI_LINK_ACL)
+ if (con->link_type != NG_HCI_LINK_SCO)
hook = unit->acl;
else
hook = unit->sco;
@@ -887,7 +1073,7 @@ ng_hci_lp_discon_ind(ng_hci_unit_con_p con, int reason)
* only SCO upstream hook will receive notification.
*/
- if (con->link_type == NG_HCI_LINK_ACL) {
+ if (con->link_type != NG_HCI_LINK_SCO) {
if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
NGM_HCI_LP_DISCON_IND, sizeof(*ep), M_NOWAIT);
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_var.h b/sys/netgraph/bluetooth/hci/ng_hci_var.h
index bce4a25..171c437 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_var.h
+++ b/sys/netgraph/bluetooth/hci/ng_hci_var.h
@@ -205,6 +205,7 @@ typedef struct ng_hci_neighbor {
bdaddr_t bdaddr; /* address */
u_int8_t features[NG_HCI_FEATURES_SIZE];
/* LMP features */
+ u_int8_t addrtype; /*Address Type*/
u_int8_t page_scan_rep_mode; /* PS rep. mode */
u_int8_t page_scan_mode; /* page scan mode */
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket.h b/sys/netgraph/bluetooth/include/ng_btsocket.h
index 6c3ce8d..483858e 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket.h
@@ -221,13 +221,32 @@ struct sockaddr_sco {
* Bluetooth version of struct sockaddr for L2CAP sockets (RAW and SEQPACKET)
*/
+struct sockaddr_l2cap_compat {
+ u_char l2cap_len; /* total length */
+ u_char l2cap_family; /* address family */
+ u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */
+ bdaddr_t l2cap_bdaddr; /* address */
+};
+
+#define BDADDR_BREDR 0
+#define BDADDR_LE_PUBLIC 1
+#define BDADDR_LE_RANDOM 2
+
struct sockaddr_l2cap {
u_char l2cap_len; /* total length */
u_char l2cap_family; /* address family */
u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */
bdaddr_t l2cap_bdaddr; /* address */
+ u_int16_t l2cap_cid; /*cid*/
+ u_int8_t l2cap_bdaddr_type; /*address type*/
};
+
+#if !defined(L2CAP_SOCKET_CHECKED) && !defined(_KERNEL)
+#warning "Make sure new member of socket address initialized"
+#endif
+
+
/* L2CAP socket options */
#define SOL_L2CAP 0x1609 /* socket option level */
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h b/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
index 493ea42..7d8a200 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
@@ -70,6 +70,8 @@ struct ng_btsocket_l2cap_raw_pcb {
bdaddr_t src; /* source address */
bdaddr_t dst; /* dest address */
+ uint8_t srctype;/*source addr type*/
+ uint8_t dsttype;/*source addr type*/
ng_btsocket_l2cap_rtentry_p rt; /* routing info */
u_int32_t token; /* message token */
@@ -129,6 +131,8 @@ struct ng_btsocket_l2cap_pcb {
bdaddr_t src; /* Source address */
bdaddr_t dst; /* Destination address */
+ uint8_t srctype; /*source addr type*/
+ uint8_t dsttype; /*source addr type*/
u_int16_t psm; /* PSM */
u_int16_t cid; /* Local channel ID */
diff --git a/sys/netgraph/bluetooth/include/ng_hci.h b/sys/netgraph/bluetooth/include/ng_hci.h
index 5cdfd5c..1688c4c 100644
--- a/sys/netgraph/bluetooth/include/ng_hci.h
+++ b/sys/netgraph/bluetooth/include/ng_hci.h
@@ -75,10 +75,11 @@
#define NG_HCI_KEY_SIZE 16 /* link key */
#define NG_HCI_PIN_SIZE 16 /* link PIN */
#define NG_HCI_EVENT_MASK_SIZE 8 /* event mask */
+#define NG_HCI_LE_EVENT_MASK_SIZE 8 /* event mask */
#define NG_HCI_CLASS_SIZE 3 /* unit class */
#define NG_HCI_FEATURES_SIZE 8 /* LMP features */
#define NG_HCI_UNIT_NAME_SIZE 248 /* unit name size */
-
+#define NG_HCI_COMMANDS_SIZE 64 /*Command list BMP size*/
/* HCI specification */
#define NG_HCI_SPEC_V10 0x00 /* v1.0 */
#define NG_HCI_SPEC_V11 0x01 /* v1.1 */
@@ -115,6 +116,8 @@
/* Link types */
#define NG_HCI_LINK_SCO 0x00 /* Voice */
#define NG_HCI_LINK_ACL 0x01 /* Data */
+#define NG_HCI_LINK_LE_PUBLIC 0x02 /* LE Public*/
+#define NG_HCI_LINK_LE_RANDOM 0x03 /* LE Random*/
/* 0x02 - 0xFF - reserved for future use */
/* Packet types */
@@ -894,6 +897,8 @@ typedef struct {
} __attribute__ ((packed)) ng_hci_set_event_mask_cp;
typedef ng_hci_status_rp ng_hci_set_event_mask_rp;
+#define NG_HCI_EVENT_MASK_DEFAULT 0x1fffffffffff
+#define NG_HCI_EVENT_MASK_LE 0x2000000000000000
#define NG_HCI_OCF_RESET 0x0003
/* No command parameter(s) */
@@ -1265,6 +1270,7 @@ typedef struct {
typedef ng_hci_status_rp ng_hci_write_iac_lap_rp;
+/*0x003b-0x003e commands are depricated v2.0 or later*/
#define NG_HCI_OCF_READ_PAGE_SCAN_PERIOD 0x003b
/* No command parameter(s) */
typedef struct {
@@ -1293,6 +1299,21 @@ typedef struct {
typedef ng_hci_status_rp ng_hci_write_page_scan_rp;
+#define NG_HCI_OCF_READ_LE_HOST_SUPPORTED 0x6c
+typedef struct {
+ u_int8_t status; /* 0x00 - success */
+ u_int8_t le_supported_host ;/* LE host supported?*/
+ u_int8_t simultaneous_le_host; /* BR/LE simulateneous? */
+} __attribute__ ((packed)) ng_hci_read_le_host_supported_rp;
+
+#define NG_HCI_OCF_WRITE_LE_HOST_SUPPORTED 0x6d
+typedef struct {
+ u_int8_t le_supported_host; /* LE host supported?*/
+ u_int8_t simultaneous_le_host; /* LE host supported?*/
+} __attribute__ ((packed)) ng_hci_write_le_host_supported_cp;
+
+typedef ng_hci_status_rp ng_hci_write_le_host_supported_rp;
+
/**************************************************************************
**************************************************************************
** Informational commands and return parameters
@@ -1312,6 +1333,12 @@ typedef struct {
u_int16_t lmp_subversion; /* LMP sub-version */
} __attribute__ ((packed)) ng_hci_read_local_ver_rp;
+#define NG_HCI_OCF_READ_LOCAL_COMMANDS 0x0002
+typedef struct {
+ u_int8_t status; /* 0x00 - success */
+ u_int8_t features[NG_HCI_COMMANDS_SIZE]; /* command bitmsk*/
+} __attribute__ ((packed)) ng_hci_read_local_commands_rp;
+
#define NG_HCI_OCF_READ_LOCAL_FEATURES 0x0003
typedef struct {
u_int8_t status; /* 0x00 - success */
@@ -1418,6 +1445,252 @@ typedef ng_hci_status_rp ng_hci_enable_unit_under_test_rp;
/**************************************************************************
**************************************************************************
+ ** LE OpCode group field
+ **************************************************************************
+ **************************************************************************/
+
+#define NG_HCI_OGF_LE 0x08 /* OpCode Group Field */
+#define NG_HCI_OCF_LE_SET_EVENT_MASK 0x0001
+typedef struct {
+ u_int8_t event_mask[NG_HCI_LE_EVENT_MASK_SIZE]; /* event_mask*/
+
+} __attribute__ ((packed)) ng_hci_le_set_event_mask_cp;
+typedef ng_hci_status_rp ng_hci_le_set_event_mask_rp;
+#define NG_HCI_LE_EVENT_MASK_ALL 0x1f
+
+#define NG_HCI_OCF_LE_READ_BUFFER_SIZE 0x0002
+/*No command parameter */
+typedef struct {
+ u_int8_t status; /*status*/
+ u_int16_t hc_le_data_packet_length;
+ u_int8_t hc_total_num_le_data_packets;
+} __attribute__ ((packed)) ng_hci_le_read_buffer_size_rp;
+
+
+#define NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES 0x0003
+/*No command parameter */
+typedef struct {
+ u_int8_t status; /*status*/
+ u_int64_t le_features;
+} __attribute__ ((packed)) ng_hci_le_read_local_supported_features_rp;
+
+#define NG_HCI_OCF_LE_SET_RANDOM_ADDRESS 0x0005
+typedef struct {
+ bdaddr_t random_address;
+} __attribute__ ((packed)) ng_hci_le_set_random_address_cp_;
+typedef ng_hci_status_rp ng_hci_le_set_random_address_rp;
+
+#define NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS 0x0006
+typedef struct {
+ u_int16_t advertising_interval_min;
+ u_int16_t advertising_interval_max;
+ u_int8_t advertising_type;
+ u_int8_t own_address_type;
+ u_int8_t direct_address_type;
+ bdaddr_t direct_address;
+ u_int8_t advertising_channel_map;
+ u_int8_t advertising_filter_policy;
+} __attribute__ ((packed)) ng_hci_le_set_advertising_parameters_cp;
+typedef ng_hci_status_rp ng_hci_le_set_advertising_parameters_rp;
+
+#define NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER 0x0007
+/*No command parameter*/
+typedef struct {
+ u_int8_t status;
+ u_int8_t transmit_power_level;
+} __attribute__ ((packed)) ng_hci_le_read_advertising_channel_tx_power_rp;
+
+#define NG_HCI_OCF_LE_SET_ADVERTISING_DATA 0x0008
+#define NG_HCI_ADVERTISING_DATA_SIZE 31
+typedef struct {
+ u_int8_t advertising_data_length;
+ char advertising_data[NG_HCI_ADVERTISING_DATA_SIZE];
+} __attribute__ ((packed)) ng_hci_le_set_advertising_data_cp;
+typedef ng_hci_status_rp ng_hci_le_set_advertising_data_rp;
+
+#define NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA 0x0009
+
+typedef struct {
+ u_int8_t scan_response_data_length;
+ char scan_response_data[NG_HCI_ADVERTISING_DATA_SIZE];
+} __attribute__ ((packed)) ng_hci_le_set_scan_response_data_cp;
+typedef ng_hci_status_rp ng_hci_le_set_scan_response_data_rp;
+
+#define NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE 0x000a
+typedef struct {
+ u_int8_t advertising_enable;
+}__attribute__ ((packed)) ng_hci_le_set_advertise_enable_cp;
+typedef ng_hci_status_rp ng_hci_le_set_advertise_enable_rp;
+
+#define NG_HCI_OCF_LE_SET_SCAN_PARAMETERS 0x000b
+typedef struct {
+ u_int8_t le_scan_type;
+ u_int16_t le_scan_interval;
+ u_int16_t le_scan_window;
+ u_int8_t own_address_type;
+ u_int8_t scanning_filter_policy;
+}__attribute__ ((packed)) ng_hci_le_set_scan_parameters_cp;
+typedef ng_hci_status_rp ng_hci_le_set_scan_parameters_rp;
+
+#define NG_HCI_OCF_LE_SET_SCAN_ENABLE 0x000c
+typedef struct {
+ u_int8_t le_scan_enable;
+ u_int8_t filter_duplicates;
+}__attribute__ ((packed)) ng_hci_le_set_scan_enable_cp;
+typedef ng_hci_status_rp ng_hci_le_set_scan_enable_rp;
+
+#define NG_HCI_OCF_LE_CREATE_CONNECTION 0x000d
+typedef struct {
+ u_int16_t scan_interval;
+ u_int16_t scan_window;
+ u_int8_t filter_policy;
+ u_int8_t peer_addr_type;
+ bdaddr_t peer_addr;
+ u_int8_t own_address_type;
+ u_int16_t conn_interval_min;
+ u_int16_t conn_interval_max;
+ u_int16_t conn_latency;
+ u_int16_t supervision_timeout;
+ u_int16_t min_ce_length;
+ u_int16_t max_ce_length;
+}__attribute__((packed)) ng_hci_le_create_connection_cp;
+/* no return paramters*/
+#define NG_HCI_OCF_LE_CREATE_CONNECTION_CANCEL 0x000e
+/*No command parameter*/
+typedef ng_hci_status_rp ng_hci_le_create_connection_cancel_rp;
+#define NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE 0x000f
+/*No command parameter*/
+typedef struct {
+ u_int8_t status;
+ u_int8_t white_list_size;
+} __attribute__ ((packed)) ng_hci_le_read_white_list_size_rp;
+
+#define NG_HCI_OCF_LE_CLEAR_WHITE_LIST 0x0010
+/*No command paramters*/
+typedef ng_hci_status_rp ng_hci_le_clear_white_list_rp;
+#define NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST 0x0011
+typedef struct {
+ u_int8_t address_type;
+ bdaddr_t address;
+} __attribute__ ((packed)) ng_hci_le_add_device_to_white_list_cp;
+typedef ng_hci_status_rp ng_hci_le_add_device_to_white_list_rp;
+
+#define NG_HCI_OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST 0x0012
+typedef struct {
+ u_int8_t address_type;
+ bdaddr_t address;
+} __attribute__ ((packed)) ng_hci_le_remove_device_from_white_list_cp;
+typedef ng_hci_status_rp ng_hci_le_remove_device_from_white_list_rp;
+
+#define NG_HCI_OCF_LE_CONNECTION_UPDATE 0x0013
+typedef struct {
+ u_int16_t connection_handle;
+ u_int16_t conn_interval_min;
+ u_int16_t conn_interval_max;
+ u_int16_t conn_latency;
+ u_int16_t supervision_timeout;
+ u_int16_t minimum_ce_length;
+ u_int16_t maximum_ce_length;
+}__attribute__ ((packed)) ng_hci_le_connection_update_cp;
+/*no return parameter*/
+
+#define NG_HCI_OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION 0x0014
+typedef struct{
+ u_int8_t le_channel_map[5];
+}__attribute__ ((packed)) ng_hci_le_set_host_channel_classification_cp;
+typedef ng_hci_status_rp ng_hci_le_set_host_channel_classification_rp;
+
+#define NG_HCI_OCF_LE_READ_CHANNEL_MAP 0x0015
+typedef struct {
+ u_int16_t connection_handle;
+}__attribute__ ((packed)) ng_hci_le_read_channel_map_cp;
+typedef struct {
+ u_int8_t status;
+ u_int16_t connection_handle;
+ u_int8_t le_channel_map[5];
+} __attribute__ ((packed)) ng_hci_le_read_channel_map_rp;
+
+#define NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES 0x0016
+typedef struct {
+ u_int16_t connection_handle;
+}__attribute__ ((packed)) ng_hci_le_read_remote_used_features_cp;
+/*No return parameter*/
+#define NG_HCI_128BIT 16
+#define NG_HCI_OCF_LE_ENCRYPT 0x0017
+typedef struct {
+ u_int8_t key[NG_HCI_128BIT];
+ u_int8_t plaintext_data[NG_HCI_128BIT];
+}__attribute__ ((packed)) ng_hci_le_encrypt_cp;
+typedef struct {
+ u_int8_t status;
+ u_int8_t plaintext_data[NG_HCI_128BIT];
+}__attribute__ ((packed)) ng_hci_le_encrypt_rp;
+
+#define NG_HCI_OCF_LE_RAND 0x0018
+/*No command parameter*/
+typedef struct {
+ u_int8_t status;
+ u_int64_t random_number;
+}__attribute__ ((packed)) ng_hci_le_rand_rp;
+
+#define NG_HCI_OCF_LE_START_ENCRYPTION 0x0019
+typedef struct {
+ u_int16_t connection_handle;
+ u_int64_t random_number;
+ u_int16_t encrypted_diversifier;
+ u_int8_t long_term_key[NG_HCI_128BIT];
+}__attribute__ ((packed)) ng_hci_le_start_encryption_cp;
+/*No return parameter*/
+#define NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_REPLY 0x001a
+typedef struct {
+ u_int16_t connection_handle;
+ u_int8_t long_term_key[NG_HCI_128BIT];
+}__attribute__ ((packed)) ng_hci_le_long_term_key_request_reply_cp;
+typedef struct {
+ u_int8_t status;
+ u_int16_t connection_handle;
+}__attribute__ ((packed)) ng_hci_le_long_term_key_request_reply_rp;
+
+#define NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY 0x001b
+typedef struct{
+ u_int16_t connection_handle;
+}ng_hci_le_long_term_key_request_negative_reply_cp;
+typedef struct {
+ u_int8_t status;
+ u_int16_t connection_handle;
+}__attribute__ ((packed)) ng_hci_le_long_term_key_request_negative_reply_rp;
+
+
+#define NG_HCI_OCF_LE_READ_SUPPORTED_STATUS 0x001c
+/*No command parameter*/
+typedef struct {
+ u_int8_t status;
+ u_int64_t le_status;
+}__attribute__ ((packed)) ng_hci_le_read_supported_status_rp;
+
+#define NG_HCI_OCF_LE_RECEIVER_TEST 0x001d
+typedef struct{
+ u_int8_t rx_frequency;
+} __attribute__((packed)) ng_le_receiver_test_cp;
+typedef ng_hci_status_rp ng_hci_le_receiver_test_rp;
+
+#define NG_HCI_OCF_LE_TRANSMITTER_TEST 0x001e
+typedef struct{
+ u_int8_t tx_frequency;
+ u_int8_t length_of_test_data;
+ u_int8_t packet_payload;
+} __attribute__((packed)) ng_le_transmitter_test_cp;
+typedef ng_hci_status_rp ng_hci_le_transmitter_test_rp;
+
+#define NG_HCI_OCF_LE_TEST_END 0x001f
+/*No command paramter*/
+typedef struct {
+ u_int8_t status;
+ u_int16_t number_of_packets;
+}__attribute__ ((packed)) ng_hci_le_test_end_rp;
+
+/**************************************************************************
+ **************************************************************************
** Special HCI OpCode group field values
**************************************************************************
**************************************************************************/
@@ -1654,6 +1927,54 @@ typedef struct {
bdaddr_t bdaddr; /* destination address */
u_int8_t page_scan_rep_mode; /* page scan repetition mode */
} __attribute__ ((packed)) ng_hci_page_scan_rep_mode_change_ep;
+#define NG_HCI_EVENT_LE 0x3e
+typedef struct {
+ u_int8_t subevent_code;
+}__attribute__ ((packed)) ng_hci_le_ep;
+
+#define NG_HCI_LEEV_CON_COMPL 0x01
+
+typedef struct {
+ u_int8_t status;
+ u_int16_t handle;
+ u_int8_t role;
+ u_int8_t address_type;
+ bdaddr_t address;
+ u_int16_t interval;
+ u_int8_t latency;
+ u_int16_t supervision_timeout;
+ u_int8_t master_clock_accracy;
+
+} __attribute__ ((packed)) ng_hci_le_connection_complete_ep;
+
+#define NG_HCI_LEEV_ADVREP 0x02
+typedef struct {
+ u_int8_t num_reports;
+
+}__attribute__ ((packed)) ng_hci_le_advertising_report_ep;
+#define NG_HCI_SCAN_RESPONSE_DATA_MAX 0x1f
+
+typedef struct {
+ u_int8_t event_type;
+ u_int8_t addr_type;
+ bdaddr_t bdaddr;
+ u_int8_t length_data;
+ u_int8_t data[NG_HCI_SCAN_RESPONSE_DATA_MAX];
+}__attribute__((packed)) ng_hci_le_advreport;
+
+#define NG_HCI_LEEV_CON_UPDATE_COMPL 0x03
+typedef struct {
+ u_int8_t status;
+ u_int16_t connection_handle;
+ u_int16_t conn_interval;
+ u_int16_t conn_latency;
+ u_int16_t supervision_timeout;
+}__attribute__((packed)) ng_hci_connection_update_complete_ep;
+#define NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL 0x04
+//TBD
+#define NG_HCI_LEEV_LONG_TERM_KEY_REQUEST 0x05
+//TBD
+
#define NG_HCI_EVENT_BT_LOGO 0xfe
diff --git a/sys/netgraph/bluetooth/include/ng_l2cap.h b/sys/netgraph/bluetooth/include/ng_l2cap.h
index f57b5cb..48b3b55 100644
--- a/sys/netgraph/bluetooth/include/ng_l2cap.h
+++ b/sys/netgraph/bluetooth/include/ng_l2cap.h
@@ -73,11 +73,18 @@
#define NG_L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */
#define NG_L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */
#define NG_L2CAP_CLT_CID 0x0002 /* connectionless channel ID */
- /* 0x0003 - 0x003f Reserved */
+#define NG_L2CAP_A2MP_CID 0x0003
+#define NG_L2CAP_ATT_CID 0x0004
+#define NG_L2CAP_LESIGNAL_CID 0x0005
+#define NG_L2CAP_SMP_CID 0x0006
+ /* 0x0007 - 0x003f Reserved */
#define NG_L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */
#define NG_L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */
+#define NG_L2CAP_LELAST_CID 0x007f
+
/* L2CAP MTU */
+#define NG_L2CAP_MTU_LE_MINIMAM 23
#define NG_L2CAP_MTU_MINIMUM 48
#define NG_L2CAP_MTU_DEFAULT 672
#define NG_L2CAP_MTU_MAXIMUM 0xffff
@@ -289,7 +296,6 @@ typedef struct {
* NG_L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU
*/
} __attribute__ ((packed)) ng_l2cap_info_rsp_cp;
-
typedef union {
/* NG_L2CAP_CONNLESS_MTU */
struct {
@@ -298,6 +304,20 @@ typedef union {
} ng_l2cap_info_rsp_data_t;
typedef ng_l2cap_info_rsp_data_t * ng_l2cap_info_rsp_data_p;
+#define NG_L2CAP_CMD_PARAM_UPDATE_REQUEST 0x12
+
+typedef struct {
+ uint16_t interval_min;
+ uint16_t interval_max;
+ uint16_t slave_latency;
+ uint16_t timeout_mpl;
+} __attribute__ ((packed)) ng_l2cap_param_update_req_cp;
+
+#define NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE 0x13
+#define NG_L2CAP_UPDATE_PARAM_ACCEPT 0
+#define NG_L2CAP_UPDATE_PARAM_REJECT 1
+
+//typedef uint16_t update_response;
/**************************************************************************
**************************************************************************
** Upper layer protocol interface. L2CA_xxx messages
@@ -332,19 +352,25 @@ typedef struct {
u_int32_t token; /* token to use in L2CAP_L2CA_WRITE */
u_int16_t length; /* length of the data */
u_int16_t lcid; /* local channel ID */
+ uint16_t idtype;
} __attribute__ ((packed)) ng_l2cap_l2ca_hdr_t;
-
+#define NG_L2CAP_L2CA_IDTYPE_BREDR 0
+#define NG_L2CAP_L2CA_IDTYPE_ATT 1
+#define NG_L2CAP_L2CA_IDTYPE_LE 2
/* L2CA_Connect */
#define NGM_L2CAP_L2CA_CON 0x80
/* Upper -> L2CAP */
typedef struct {
u_int16_t psm; /* Protocol/Service Multiplexor */
bdaddr_t bdaddr; /* remote unit address */
+ uint8_t linktype;
+ uint8_t idtype;
} ng_l2cap_l2ca_con_ip;
/* L2CAP -> Upper */
typedef struct {
u_int16_t lcid; /* local channel ID */
+ uint16_t idtype; /*ID type*/
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* if result != 0x00 */
} ng_l2cap_l2ca_con_op;
@@ -357,7 +383,7 @@ typedef struct {
u_int16_t lcid; /* local channel ID */
u_int16_t psm; /* Procotol/Service Multiplexor */
u_int8_t ident; /* indentifier */
- u_int8_t unused; /* place holder */
+ u_int8_t linktype; /* link type*/
} ng_l2cap_l2ca_con_ind_ip;
/* No output parameters */
@@ -367,7 +393,7 @@ typedef struct {
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int8_t ident; /* "ident" from L2CAP_ConnectInd event */
- u_int8_t unused; /* place holder */
+ u_int8_t linktype; /*link type */
u_int16_t lcid; /* local channel ID */
u_int16_t result; /* 0x00 - success */
u_int16_t status; /* if response != 0x00 */
@@ -435,6 +461,7 @@ typedef struct {
/* Upper -> L2CAP */
typedef struct {
u_int16_t lcid; /* local channel ID */
+ u_int16_t idtype;
} ng_l2cap_l2ca_discon_ip;
/* L2CAP -> Upper */
@@ -457,6 +484,7 @@ typedef struct {
int result; /* result (0x00 - success) */
u_int16_t length; /* amount of data written */
u_int16_t lcid; /* local channel ID */
+ uint16_t idtype;
} ng_l2cap_l2ca_write_op;
/* L2CA_GroupCreate */
@@ -545,6 +573,8 @@ typedef struct {
typedef struct {
bdaddr_t bdaddr; /* remote unit address */
u_int16_t info_type; /* info type */
+ uint8_t linktype;
+ uint8_t unused;
} ng_l2cap_l2ca_get_info_ip;
/* L2CAP -> Upper */
@@ -610,7 +640,9 @@ typedef u_int16_t ng_l2cap_node_flags_ep;
typedef u_int16_t ng_l2cap_node_debug_ep;
#define NGM_L2CAP_NODE_HOOK_INFO 0x409 /* L2CAP -> Upper */
-/* bdaddr_t bdaddr; -- local (source BDADDR) */
+typedef struct {
+ bdaddr_t addr;
+}ng_l2cap_node_hook_info_ep;
#define NGM_L2CAP_NODE_GET_CON_LIST 0x40a /* L2CAP -> User */
typedef struct {
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c b/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c
index db667b9..167fcb6 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c
@@ -86,7 +86,6 @@ ng_l2cap_con_wakeup(ng_l2cap_con_p con)
/* Process command */
switch (cmd->code) {
- case NG_L2CAP_CMD_REJ:
case NG_L2CAP_DISCON_RSP:
case NG_L2CAP_ECHO_RSP:
case NG_L2CAP_INFO_RSP:
@@ -104,7 +103,16 @@ ng_l2cap_con_wakeup(ng_l2cap_con_p con)
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
break;
-
+ case NG_L2CAP_CMD_REJ:
+ (void) ng_l2cap_lp_send(con,
+ (con->linktype == NG_HCI_LINK_ACL)?
+ NG_L2CAP_SIGNAL_CID:
+ NG_L2CAP_LESIGNAL_CID
+ , m);
+ ng_l2cap_unlink_cmd(cmd);
+ ng_l2cap_free_cmd(cmd);
+ break;
+
case NG_L2CAP_CON_REQ:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
if (error != 0) {
@@ -115,7 +123,6 @@ ng_l2cap_con_wakeup(ng_l2cap_con_p con)
ng_l2cap_command_timeout(cmd,
bluetooth_l2cap_rtx_timeout());
break;
-
case NG_L2CAP_CON_RSP:
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
ng_l2cap_unlink_cmd(cmd);
@@ -208,9 +215,14 @@ ng_l2cap_con_wakeup(ng_l2cap_con_p con)
ng_l2cap_unlink_cmd(cmd);
ng_l2cap_free_cmd(cmd);
} break;
-
+ case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
+ error = ng_l2cap_lp_send(con, NG_L2CAP_LESIGNAL_CID, m);
+ ng_l2cap_unlink_cmd(cmd);
+ ng_l2cap_free_cmd(cmd);
+ break;
+ case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST:
+ /*TBD.*/
/* XXX FIXME add other commands */
-
default:
panic(
"%s: %s - unknown command code=%d\n",
@@ -256,6 +268,7 @@ ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
case NG_L2CAP_DISCON_RSP:
case NG_L2CAP_ECHO_RSP:
case NG_L2CAP_INFO_RSP:
+ case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
break;
case NG_L2CAP_CON_REQ:
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.h b/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.h
index 52789a1..7f22023 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.h
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.h
@@ -199,6 +199,25 @@ do { \
c->hdr.length = htole16(c->hdr.length); \
} while (0)
+#define _ng_l2cap_cmd_urs(_m, _ident, _result) \
+do { \
+ struct _cmd_urs{ \
+ ng_l2cap_cmd_hdr_t hdr; \
+ uint16_t result; \
+ } __attribute__ ((packed)) *c = NULL; \
+ \
+ MGETHDR((_m), M_NOWAIT, MT_DATA); \
+ \
+ (_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c); \
+ \
+ c = mtod((_m), struct _cmd_urs *); \
+ c->hdr.code = NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE; \
+ c->hdr.ident = (_ident); \
+ c->hdr.length = sizeof(c->result); \
+ \
+ c->result = htole16((_result)); \
+} while (0)
+
/* Build configuration options */
#define _ng_l2cap_build_cfg_options(_m, _mtu, _flush_timo, _flow) \
do { \
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_evnt.c b/sys/netgraph/bluetooth/l2cap/ng_l2cap_evnt.c
index 747b74c..287ab66 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_evnt.c
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_evnt.c
@@ -57,7 +57,10 @@
******************************************************************************/
static int ng_l2cap_process_signal_cmd (ng_l2cap_con_p);
+static int ng_l2cap_process_lesignal_cmd (ng_l2cap_con_p);
static int ng_l2cap_process_cmd_rej (ng_l2cap_con_p, u_int8_t);
+static int ng_l2cap_process_cmd_urq (ng_l2cap_con_p, u_int8_t);
+static int ng_l2cap_process_cmd_urs (ng_l2cap_con_p, u_int8_t);
static int ng_l2cap_process_con_req (ng_l2cap_con_p, u_int8_t);
static int ng_l2cap_process_con_rsp (ng_l2cap_con_p, u_int8_t);
static int ng_l2cap_process_cfg_req (ng_l2cap_con_p, u_int8_t);
@@ -74,6 +77,9 @@ static int send_l2cap_con_rej
(ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, u_int16_t);
static int send_l2cap_cfg_rsp
(ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, struct mbuf *);
+static int send_l2cap_param_urs
+ (ng_l2cap_con_p , u_int8_t , u_int16_t);
+
static int get_next_l2cap_opt
(struct mbuf *, int *, ng_l2cap_cfg_opt_p, ng_l2cap_cfg_opt_val_p);
@@ -124,7 +130,10 @@ ng_l2cap_receive(ng_l2cap_con_p con)
m_adj(con->rx_pkt, sizeof(*hdr));
error = ng_l2cap_process_signal_cmd(con);
break;
-
+ case NG_L2CAP_LESIGNAL_CID:
+ m_adj(con->rx_pkt, sizeof(*hdr));
+ error = ng_l2cap_process_lesignal_cmd(con);
+ break;
case NG_L2CAP_CLT_CID: /* Connectionless packet */
error = ng_l2cap_l2ca_clt_receive(con);
break;
@@ -264,6 +273,105 @@ ng_l2cap_process_signal_cmd(ng_l2cap_con_p con)
return (0);
} /* ng_l2cap_process_signal_cmd */
+static int
+ng_l2cap_process_lesignal_cmd(ng_l2cap_con_p con)
+{
+ ng_l2cap_p l2cap = con->l2cap;
+ ng_l2cap_cmd_hdr_t *hdr = NULL;
+ struct mbuf *m = NULL;
+
+ while (con->rx_pkt != NULL) {
+ /* Verify packet length */
+ if (con->rx_pkt->m_pkthdr.len < sizeof(*hdr)) {
+ NG_L2CAP_ERR(
+"%s: %s - invalid L2CAP signaling command. Packet too small, len=%d\n",
+ __func__, NG_NODE_NAME(l2cap->node),
+ con->rx_pkt->m_pkthdr.len);
+ NG_FREE_M(con->rx_pkt);
+
+ return (EMSGSIZE);
+ }
+
+ /* Get signaling command */
+ NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
+ if (con->rx_pkt == NULL)
+ return (ENOBUFS);
+
+ hdr = mtod(con->rx_pkt, ng_l2cap_cmd_hdr_t *);
+ hdr->length = le16toh(hdr->length);
+ m_adj(con->rx_pkt, sizeof(*hdr));
+
+ /* Verify command length */
+ if (con->rx_pkt->m_pkthdr.len < hdr->length) {
+ NG_L2CAP_ERR(
+"%s: %s - invalid L2CAP signaling command, code=%#x, ident=%d. " \
+"Invalid command length=%d, m_pkthdr.len=%d\n",
+ __func__, NG_NODE_NAME(l2cap->node),
+ hdr->code, hdr->ident, hdr->length,
+ con->rx_pkt->m_pkthdr.len);
+ NG_FREE_M(con->rx_pkt);
+
+ return (EMSGSIZE);
+ }
+
+ /* Get the command, save the rest (if any) */
+ if (con->rx_pkt->m_pkthdr.len > hdr->length)
+ m = m_split(con->rx_pkt, hdr->length, M_NOWAIT);
+ else
+ m = NULL;
+
+ /* Process command */
+ switch (hdr->code) {
+ case NG_L2CAP_CMD_REJ:
+ ng_l2cap_process_cmd_rej(con, hdr->ident);
+ break;
+ case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST:
+ ng_l2cap_process_cmd_urq(con, hdr->ident);
+ break;
+ case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
+ ng_l2cap_process_cmd_urs(con, hdr->ident);
+ break;
+
+
+ default:
+ NG_L2CAP_ERR(
+"%s: %s - unknown L2CAP signaling command, code=%#x, ident=%d, length=%d\n",
+ __func__, NG_NODE_NAME(l2cap->node),
+ hdr->code, hdr->ident, hdr->length);
+
+ /*
+ * Send L2CAP_CommandRej. Do not really care
+ * about the result
+ */
+
+ send_l2cap_reject(con, hdr->ident,
+ NG_L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);
+ NG_FREE_M(con->rx_pkt);
+ break;
+ }
+
+ con->rx_pkt = m;
+ }
+
+ return (0);
+} /* ng_l2cap_process_signal_cmd */
+/*Update Paramater Request*/
+static int ng_l2cap_process_cmd_urq(ng_l2cap_con_p con, uint8_t ident)
+{
+ /*We do not implement paramter negotiasion for now*/
+ send_l2cap_param_urs(con, ident, NG_L2CAP_UPDATE_PARAM_ACCEPT);
+ NG_FREE_M(con->rx_pkt);
+ return 0;
+}
+
+static int ng_l2cap_process_cmd_urs(ng_l2cap_con_p con, uint8_t ident)
+{
+ /* We only support master side yet .*/
+ //send_l2cap_reject(con,ident ... );
+
+ NG_FREE_M(con->rx_pkt);
+ return 0;
+}
/*
* Process L2CAP_CommandRej command
@@ -352,7 +460,8 @@ ng_l2cap_process_con_req(ng_l2cap_con_p con, u_int8_t ident)
ng_l2cap_chan_p ch = NULL;
int error = 0;
u_int16_t dcid, psm;
-
+ int idtype;
+
/* Get command parameters */
NG_L2CAP_M_PULLUP(m, sizeof(*cp));
if (m == NULL)
@@ -364,13 +473,20 @@ ng_l2cap_process_con_req(ng_l2cap_con_p con, u_int8_t ident)
NG_FREE_M(m);
con->rx_pkt = NULL;
+ if(dcid == NG_L2CAP_ATT_CID)
+ idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
+ else if( con->linktype != NG_HCI_LINK_ACL)
+ idtype = NG_L2CAP_L2CA_IDTYPE_LE;
+ else
+ idtype = NG_L2CAP_L2CA_IDTYPE_BREDR;
/*
* Create new channel and send L2CA_ConnectInd notification
* to the upper layer protocol.
*/
- ch = ng_l2cap_new_chan(l2cap, con, psm);
+ ch = ng_l2cap_new_chan(l2cap, con, psm, idtype);
+
if (ch == NULL)
return (send_l2cap_con_rej(con, ident, 0, dcid,
NG_L2CAP_NO_RESOURCES));
@@ -486,7 +602,8 @@ ng_l2cap_process_con_rsp(ng_l2cap_con_p con, u_int8_t ident)
*/
cmd->ch->dcid = dcid;
- cmd->ch->state = NG_L2CAP_CONFIG;
+ cmd->ch->state = (cmd->ch->scid == NG_L2CAP_ATT_CID)?
+ NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
} else
/* There was an error, so close the channel */
NG_L2CAP_INFO(
@@ -541,7 +658,7 @@ ng_l2cap_process_cfg_req(ng_l2cap_con_p con, u_int8_t ident)
m_adj(m, sizeof(*cp));
/* Check if we have this channel and it is in valid state */
- ch = ng_l2cap_chan_by_scid(l2cap, dcid);
+ ch = ng_l2cap_chan_by_scid(l2cap, dcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
if (ch == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected L2CAP_ConfigReq command. " \
@@ -826,7 +943,7 @@ ng_l2cap_process_discon_req(ng_l2cap_con_p con, u_int8_t ident)
NG_FREE_M(con->rx_pkt);
/* Check if we have this channel and it is in valid state */
- ch = ng_l2cap_chan_by_scid(l2cap, dcid);
+ ch = ng_l2cap_chan_by_scid(l2cap, dcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
if (ch == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected L2CAP_DisconnectReq message. " \
@@ -1251,6 +1368,34 @@ send_l2cap_cfg_rsp(ng_l2cap_con_p con, u_int8_t ident, u_int16_t scid,
return (0);
} /* send_l2cap_cfg_rsp */
+static int
+send_l2cap_param_urs(ng_l2cap_con_p con, u_int8_t ident,
+ u_int16_t result)
+{
+ ng_l2cap_cmd_p cmd = NULL;
+
+ cmd = ng_l2cap_new_cmd(con, NULL, ident,
+ NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE,
+ 0);
+ if (cmd == NULL) {
+
+ return (ENOMEM);
+ }
+
+ _ng_l2cap_cmd_urs(cmd->aux, cmd->ident, result);
+ if (cmd->aux == NULL) {
+ ng_l2cap_free_cmd(cmd);
+
+ return (ENOBUFS);
+ }
+
+ /* Link command to the queue */
+ ng_l2cap_link_cmd(con, cmd);
+ ng_l2cap_lp_deliver(con);
+
+ return (0);
+} /* send_l2cap_cfg_rsp */
+
/*
* Get next L2CAP configuration option
*
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c b/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c
index 704e74a..e9e7412 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c
@@ -64,7 +64,7 @@
*/
int
-ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
+ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type)
{
struct ng_mesg *msg = NULL;
ng_hci_lp_con_req_ep *ep = NULL;
@@ -72,7 +72,7 @@ ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
int error = 0;
/* Verify that we DO NOT have connection to the remote unit */
- con = ng_l2cap_con_by_addr(l2cap, bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, bdaddr, type);
if (con != NULL) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectReq event. " \
@@ -93,7 +93,7 @@ ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
}
/* Create and intialize new connection descriptor */
- con = ng_l2cap_new_con(l2cap, bdaddr);
+ con = ng_l2cap_new_con(l2cap, bdaddr, type);
if (con == NULL)
return (ENOMEM);
@@ -108,7 +108,7 @@ ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
ep = (ng_hci_lp_con_req_ep *) (msg->data);
bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
- ep->link_type = NG_HCI_LINK_ACL;
+ ep->link_type = type;
con->flags |= NG_L2CAP_CON_OUTGOING;
con->state = NG_L2CAP_W4_LP_CON_CFM;
@@ -152,9 +152,8 @@ ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
}
ep = (ng_hci_lp_con_cfm_ep *) (msg->data);
-
/* Check if we have requested/accepted this connection */
- con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type);
if (con == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n",
@@ -224,7 +223,7 @@ ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
ep = (ng_hci_lp_con_ind_ep *) (msg->data);
/* Make sure we have only one connection to the remote unit */
- con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type);
if (con != NULL) {
NG_L2CAP_ALERT(
"%s: %s - unexpected LP_ConnectInd event. " \
@@ -245,7 +244,7 @@ ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
}
/* Create and intialize new connection descriptor */
- con = ng_l2cap_new_con(l2cap, &ep->bdaddr);
+ con = ng_l2cap_new_con(l2cap, &ep->bdaddr, ep->link_type);
if (con == NULL)
return (ENOMEM);
@@ -773,6 +772,10 @@ ng_l2cap_lp_deliver(ng_l2cap_con_p con)
con->tx_pkt = con->tx_pkt->m_nextpkt;
m->m_nextpkt = NULL;
+ if(m->m_flags &M_PROTO2){
+ ng_l2cap_lp_receive(con->l2cap, m);
+ continue;
+ }
NG_L2CAP_INFO(
"%s: %s - sending ACL packet, con_handle=%d, len=%d\n",
__func__, NG_NODE_NAME(l2cap->node), con->con_handle,
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.h b/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.h
index 919a0aa..67ea6c0 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.h
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.h
@@ -34,7 +34,7 @@
#ifndef _NETGRAPH_L2CAP_LLPI_H_
#define _NETGRAPH_L2CAP_LLPI_H_
-int ng_l2cap_lp_con_req (ng_l2cap_p, bdaddr_p);
+int ng_l2cap_lp_con_req (ng_l2cap_p, bdaddr_p, int);
int ng_l2cap_lp_con_cfm (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_con_ind (ng_l2cap_p, struct ng_mesg *);
int ng_l2cap_lp_discon_ind (ng_l2cap_p, struct ng_mesg *);
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c b/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c
index 0c3f1d0..886a918 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c
@@ -49,7 +49,7 @@
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
-static u_int16_t ng_l2cap_get_cid (ng_l2cap_p);
+static u_int16_t ng_l2cap_get_cid (ng_l2cap_p, int);
/******************************************************************************
******************************************************************************
@@ -67,6 +67,7 @@ ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
ng_l2cap_p l2cap = NULL;
struct ng_mesg *msg = NULL;
int error = 0;
+ ng_l2cap_node_hook_info_ep *ep ;
if (node == NULL || NG_NODE_NOT_VALID(node) ||
hook == NULL || NG_HOOK_NOT_VALID(hook))
@@ -78,9 +79,11 @@ ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
return;
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO,
- sizeof(bdaddr_t), M_NOWAIT);
+ sizeof(*ep), M_NOWAIT);
+
if (msg != NULL) {
- bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t));
+ ep = (ng_l2cap_node_hook_info_ep *) &msg->data;
+ bcopy(&l2cap->bdaddr, &ep->addr, sizeof(bdaddr_t));
NG_SEND_MSG_HOOK(error, node, msg, hook, 0);
} else
error = ENOMEM;
@@ -98,7 +101,7 @@ ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
*/
ng_l2cap_con_p
-ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr)
+ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type)
{
static int fake_con_handle = 0x0f00;
ng_l2cap_con_p con = NULL;
@@ -131,6 +134,7 @@ ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr)
fake_con_handle = 0x0f00;
bcopy(bdaddr, &con->remote, sizeof(con->remote));
+ con->linktype = type;
ng_callout_init(&con->con_timo);
con->ident = NG_L2CAP_FIRST_IDENT - 1;
@@ -292,12 +296,13 @@ ng_l2cap_free_con(ng_l2cap_con_p con)
*/
ng_l2cap_con_p
-ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr)
+ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr, unsigned int type)
{
ng_l2cap_con_p con = NULL;
LIST_FOREACH(con, &l2cap->con_list, next)
- if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)
+ if ((bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)&&
+ (con->linktype == type))
break;
return (con);
@@ -325,7 +330,7 @@ ng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle)
*/
ng_l2cap_chan_p
-ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm)
+ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm, int idtype)
{
ng_l2cap_chan_p ch = NULL;
@@ -333,8 +338,12 @@ ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm)
M_NOWAIT|M_ZERO);
if (ch == NULL)
return (NULL);
-
- ch->scid = ng_l2cap_get_cid(l2cap);
+ if(idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
+ ch->scid = ch->dcid = NG_L2CAP_ATT_CID;
+ }else{
+ ch->scid = ng_l2cap_get_cid(l2cap,
+ (con->linktype!= NG_HCI_LINK_ACL));
+ }
if (ch->scid != NG_L2CAP_NULL_CID) {
/* Initialize channel */
@@ -364,19 +373,42 @@ ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm)
return (ch);
} /* ng_l2cap_new_chan */
-/*
- * Get channel by source (local) channel ID
- */
ng_l2cap_chan_p
-ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid)
+ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid, int idtype)
{
ng_l2cap_chan_p ch = NULL;
- LIST_FOREACH(ch, &l2cap->chan_list, next)
+ if(idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
+ return NULL;
+ }
+
+ LIST_FOREACH(ch, &l2cap->chan_list, next){
+ if((idtype != NG_L2CAP_L2CA_IDTYPE_BREDR)&&
+ (ch->con->linktype == NG_HCI_LINK_ACL ))
+ continue;
+ if((idtype != NG_L2CAP_L2CA_IDTYPE_LE)&&
+ (ch->con->linktype != NG_HCI_LINK_ACL ))
+ continue;
+
if (ch->scid == scid)
break;
+ }
+ return (ch);
+} /* ng_l2cap_chan_by_scid */
+ng_l2cap_chan_p
+ng_l2cap_chan_by_conhandle(ng_l2cap_p l2cap, uint16_t scid,
+ u_int16_t con_handle)
+{
+ ng_l2cap_chan_p ch = NULL;
+
+
+ LIST_FOREACH(ch, &l2cap->chan_list, next){
+ if ((ch->scid == scid) &&
+ (ch->con->con_handle == con_handle))
+ break;
+ }
return (ch);
} /* ng_l2cap_chan_by_scid */
@@ -390,6 +422,7 @@ ng_l2cap_free_chan(ng_l2cap_chan_p ch)
ng_l2cap_cmd_p f = NULL, n = NULL;
f = TAILQ_FIRST(&ch->con->cmd_list);
+
while (f != NULL) {
n = TAILQ_NEXT(f, next);
@@ -591,21 +624,40 @@ ng_l2cap_default_flow(void)
*/
static u_int16_t
-ng_l2cap_get_cid(ng_l2cap_p l2cap)
+ng_l2cap_get_cid(ng_l2cap_p l2cap,int isle)
{
- u_int16_t cid = l2cap->cid + 1;
-
+ u_int16_t cid ;
+ u_int16_t endcid;
+ uint16_t mask;
+ int idtype;
+ if(isle){
+ endcid = l2cap->lecid;
+ /*Assume Last CID is 2^n-1 */
+ mask = NG_L2CAP_LELAST_CID;
+ idtype = NG_L2CAP_L2CA_IDTYPE_LE;
+ }else{
+ endcid = l2cap->cid;
+ /*Assume Last CID is 2^n-1 */
+ mask = NG_L2CAP_LAST_CID;
+ idtype = NG_L2CAP_L2CA_IDTYPE_BREDR;
+ }
+ cid = (endcid+1) & mask;
+
if (cid < NG_L2CAP_FIRST_CID)
cid = NG_L2CAP_FIRST_CID;
- while (cid != l2cap->cid) {
- if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) {
- l2cap->cid = cid;
-
+ while (cid != endcid) {
+ if (ng_l2cap_chan_by_scid(l2cap, cid, idtype) == NULL) {
+ if(!isle){
+ l2cap->cid = cid;
+ }else{
+ l2cap->lecid = cid;
+ }
return (cid);
}
cid ++;
+ cid &= mask;
if (cid < NG_L2CAP_FIRST_CID)
cid = NG_L2CAP_FIRST_CID;
}
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.h b/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.h
index 22cff48..aa30fac 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.h
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.h
@@ -40,10 +40,10 @@ void ng_l2cap_send_hook_info (node_p, hook_p, void *, int);
* ACL Connections
*/
-ng_l2cap_con_p ng_l2cap_new_con (ng_l2cap_p, bdaddr_p);
+ng_l2cap_con_p ng_l2cap_new_con (ng_l2cap_p, bdaddr_p, int);
void ng_l2cap_con_ref (ng_l2cap_con_p);
void ng_l2cap_con_unref (ng_l2cap_con_p);
-ng_l2cap_con_p ng_l2cap_con_by_addr (ng_l2cap_p, bdaddr_p);
+ng_l2cap_con_p ng_l2cap_con_by_addr (ng_l2cap_p, bdaddr_p, unsigned int);
ng_l2cap_con_p ng_l2cap_con_by_handle (ng_l2cap_p, u_int16_t);
void ng_l2cap_free_con (ng_l2cap_con_p);
@@ -51,8 +51,10 @@ void ng_l2cap_free_con (ng_l2cap_con_p);
* L2CAP channels
*/
-ng_l2cap_chan_p ng_l2cap_new_chan (ng_l2cap_p, ng_l2cap_con_p, u_int16_t);
-ng_l2cap_chan_p ng_l2cap_chan_by_scid (ng_l2cap_p, u_int16_t);
+ng_l2cap_chan_p ng_l2cap_new_chan (ng_l2cap_p, ng_l2cap_con_p, u_int16_t, int);
+ng_l2cap_chan_p ng_l2cap_chan_by_scid (ng_l2cap_p, u_int16_t, int);
+ng_l2cap_chan_p ng_l2cap_chan_by_conhandle(ng_l2cap_p , uint16_t , u_int16_t);
+
void ng_l2cap_free_chan (ng_l2cap_chan_p);
/*
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c b/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c
index 8a8e31d..a0cfbcd 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c
@@ -81,10 +81,10 @@ ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
/* Check if we have connection to the remote unit */
- con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
if (con == NULL) {
/* Submit LP_ConnectReq to the lower layer */
- error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr);
+ error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
if (error != 0) {
NG_L2CAP_ERR(
"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
@@ -93,7 +93,7 @@ ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
}
/* This should not fail */
- con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
KASSERT((con != NULL),
("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
}
@@ -103,7 +103,7 @@ ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
* not touch connection descriptor.
*/
- ch = ng_l2cap_new_chan(l2cap, con, ip->psm);
+ ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);
if (ch == NULL) {
error = ENOMEM;
goto out;
@@ -126,7 +126,13 @@ ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
}
/* Create L2CAP command packet */
- _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
+ if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
+ _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID,
+ NG_L2CAP_ATT_CID, 0, 0);
+ cmd->aux->m_flags |= M_PROTO2;
+ }else{
+ _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
+ }
if (cmd->aux == NULL) {
ng_l2cap_free_cmd(cmd);
ng_l2cap_free_chan(ch);
@@ -182,8 +188,16 @@ ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
* What about PENDING? What the heck, for now always populate
* LCID :)
*/
+ if(ch->scid == NG_L2CAP_ATT_CID){
+ op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
+ op->lcid = ch->con->con_handle;
+ }else{
+ op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
+ NG_L2CAP_L2CA_IDTYPE_BREDR :
+ NG_L2CAP_L2CA_IDTYPE_LE;
+ op->lcid = ch->scid;
+ }
- op->lcid = ch->scid;
op->result = result;
op->status = status;
@@ -220,7 +234,15 @@ ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
/* Check if we have this channel */
- ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid);
+ if(ip->lcid != NG_L2CAP_ATT_CID){
+ ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid
+ ,(ip->linktype == NG_HCI_LINK_ACL)?
+ NG_L2CAP_L2CA_IDTYPE_BREDR:
+ NG_L2CAP_L2CA_IDTYPE_LE);
+ }else{
+ // For now not support on ATT device.
+ ch = NULL;
+ }
if (ch == NULL) {
NG_L2CAP_ALERT(
"%s: %s - unexpected L2CA_ConnectRsp request message. " \
@@ -259,7 +281,8 @@ ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
/* Check result */
switch (ip->result) {
case NG_L2CAP_SUCCESS:
- ch->state = NG_L2CAP_CONFIG;
+ ch->state = (ch->scid == NG_L2CAP_ATT_CID)?
+ NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
ch->cfg_state = 0;
break;
@@ -410,7 +433,7 @@ ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
/* Check if we have this channel */
- ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid);
+ ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
if (ch == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_Config request message. " \
@@ -478,7 +501,8 @@ ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
/* Adjust channel state for re-configuration */
if (ch->state == NG_L2CAP_OPEN) {
- ch->state = NG_L2CAP_CONFIG;
+ ch->state = (ch->scid == NG_L2CAP_ATT_CID)?
+ NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
ch->cfg_state = 0;
}
@@ -580,7 +604,8 @@ ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
/* Check if we have this channel */
- ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid);
+ ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
+ NG_L2CAP_L2CA_IDTYPE_BREDR);
if (ch == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_ConfigRsp request message. " \
@@ -784,16 +809,24 @@ ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
}
/* Check channel ID */
- if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
- NG_L2CAP_ERR(
-"%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
- __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
- error = EINVAL;
- goto drop;
- }
+ if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
+ ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
+ l2ca_hdr->lcid);
+ } else{
+ if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
+ NG_L2CAP_ERR(
+ "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
+ __func__, NG_NODE_NAME(l2cap->node),
+ l2ca_hdr->lcid);
+ error = EINVAL;
+ goto drop;
+ }
- /* Verify that we have the channel and make sure it is open */
- ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid);
+ /* Verify that we have the channel and make sure it is open */
+ ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
+ l2ca_hdr->idtype);
+ }
+
if (ch == NULL) {
NG_L2CAP_ERR(
"%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
@@ -865,8 +898,16 @@ ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
op = (ng_l2cap_l2ca_write_op *)(msg->data);
op->result = result;
op->length = length;
- op->lcid = ch->scid;
-
+ if(ch->scid == NG_L2CAP_ATT_CID){
+ op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
+ op->lcid = ch->con->con_handle;
+ }else{
+ op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
+ NG_L2CAP_L2CA_IDTYPE_BREDR :
+ NG_L2CAP_L2CA_IDTYPE_LE;
+ op->lcid = ch->scid;
+
+ }
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
}
@@ -885,6 +926,8 @@ ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
ng_l2cap_hdr_t *hdr = NULL;
ng_l2cap_chan_p ch = NULL;
int error = 0;
+ int idtype;
+ uint16_t *idp;
NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
if (con->rx_pkt == NULL)
@@ -893,11 +936,26 @@ ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
/* Check channel */
- ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid);
+
+ if(hdr->dcid == NG_L2CAP_ATT_CID){
+ idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
+ ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
+ con->con_handle);
+ /*
+ * Here,ATT channel is distinguished by
+ * connection handle
+ */
+ hdr->dcid = con->con_handle;
+ }else{
+ idtype = (con->linktype==NG_HCI_LINK_ACL)?
+ NG_L2CAP_L2CA_IDTYPE_BREDR:
+ NG_L2CAP_L2CA_IDTYPE_LE;
+ ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);
+ }
if (ch == NULL) {
NG_L2CAP_ERR(
-"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d\n",
- __func__, NG_NODE_NAME(l2cap->node), hdr->dcid);
+"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",
+ __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);
error = ENOENT;
goto drop;
}
@@ -938,6 +996,11 @@ ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
error = ENOTCONN;
goto drop;
}
+ M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
+ if(con->rx_pkt == NULL)
+ goto drop;
+ idp = mtod(con->rx_pkt, uint16_t *);
+ *idp = idtype;
NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
con->rx_pkt = NULL;
@@ -1091,8 +1154,26 @@ ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
- /* Check if we have this channel */
- ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid);
+
+ if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
+ /* Don't send Disconnect request on L2CAP Layer*/
+ ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
+ ip->lcid);
+
+ if(ch != NULL){
+ ng_l2cap_free_chan(ch);
+ }else{
+ NG_L2CAP_ERR(
+"%s: %s - unexpected L2CA_Disconnect request message. " \
+"Channel does not exist, conhandle=%d\n",
+ __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
+ error = EINVAL;
+ }
+ goto out;
+ }else{
+ /* Check if we have this channel */
+ ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
+ }
if (ch == NULL) {
NG_L2CAP_ERR(
"%s: %s - unexpected L2CA_Disconnect request message. " \
@@ -1322,10 +1403,10 @@ ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
}
/* Check if we have connection to the unit */
- con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
if (con == NULL) {
/* Submit LP_ConnectReq to the lower layer */
- error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr);
+ error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
if (error != 0) {
NG_L2CAP_ERR(
"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
@@ -1334,7 +1415,7 @@ ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
}
/* This should not fail */
- con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
KASSERT((con != NULL),
("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
}
@@ -1444,10 +1525,10 @@ ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
/* Check if we have connection to the unit */
- con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
if (con == NULL) {
/* Submit LP_ConnectReq to the lower layer */
- error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr);
+ error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
if (error != 0) {
NG_L2CAP_ERR(
"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
@@ -1456,7 +1537,7 @@ ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
}
/* This should not fail */
- con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr);
+ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
KASSERT((con != NULL),
("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
}
diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_var.h b/sys/netgraph/bluetooth/l2cap/ng_l2cap_var.h
index 2188492..55db4ba 100644
--- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_var.h
+++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_var.h
@@ -92,7 +92,9 @@ typedef struct ng_l2cap {
LIST_HEAD(, ng_l2cap_con) con_list; /* ACL connections */
- u_int16_t cid; /* last allocated CID */
+ u_int16_t cid; /* last allocated CID */
+ u_int16_t lecid; /* last allocated CID for LE */
+
LIST_HEAD(, ng_l2cap_chan) chan_list; /* L2CAP channels */
} ng_l2cap_t;
typedef ng_l2cap_t * ng_l2cap_p;
@@ -116,6 +118,8 @@ typedef struct ng_l2cap_con {
struct callout con_timo; /* connection timeout */
u_int8_t ident; /* last allocated ident */
+ uint8_t linktype;
+
TAILQ_HEAD(, ng_l2cap_cmd) cmd_list; /* pending L2CAP cmds */
struct mbuf *tx_pkt; /* xmitted L2CAP packet */
@@ -148,6 +152,7 @@ typedef struct ng_l2cap_chan {
u_int16_t scid; /* source channel ID */
u_int16_t dcid; /* destination channel ID */
+ uint16_t idtype;
u_int16_t imtu; /* incoming channel MTU */
ng_l2cap_flow_t iflow; /* incoming flow control */
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
index 4c71414..139d6db 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
@@ -876,6 +876,9 @@ ng_btsocket_hci_raw_init(void)
/* Commands - Testing */
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_TESTING - 1];
bit_set(f, NG_HCI_OCF_READ_LOOPBACK_MODE - 1);
+ /*Commands - LE*/
+ f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LE -1];
+
} /* ng_btsocket_hci_raw_init */
/*
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
index d2e0487..7b666b1 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
@@ -184,7 +184,7 @@ static int ng_btsocket_l2cap_process_l2ca_write_rsp
static int ng_btsocket_l2cap_send_l2ca_con_req
(ng_btsocket_l2cap_pcb_p);
static int ng_btsocket_l2cap_send_l2ca_con_rsp_req
- (u_int32_t, ng_btsocket_l2cap_rtentry_p, bdaddr_p, int, int, int);
+ (u_int32_t, ng_btsocket_l2cap_rtentry_p, bdaddr_p, int, int, int, int);
static int ng_btsocket_l2cap_send_l2ca_cfg_req
(ng_btsocket_l2cap_pcb_p);
static int ng_btsocket_l2cap_send_l2ca_cfg_rsp
@@ -209,15 +209,42 @@ static void ng_btsocket_l2cap_process_timeout (void *);
static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_addr(bdaddr_p, int);
static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_token(u_int32_t);
-static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_cid (bdaddr_p, int);
+static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_cid (bdaddr_p, int,int);
static int ng_btsocket_l2cap_result2errno(int);
+static int ng_btsock_l2cap_addrtype_to_linktype(int addrtype);
+static int ng_btsock_l2cap_pcb_to_idtype(struct ng_btsocket_l2cap_pcb *);
#define ng_btsocket_l2cap_wakeup_input_task() \
taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_queue_task)
#define ng_btsocket_l2cap_wakeup_route_task() \
taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_rt_task)
+
+int ng_btsock_l2cap_pcb_to_idtype(struct ng_btsocket_l2cap_pcb *pcb)
+{
+ if(pcb->dsttype == BDADDR_BREDR){
+ return NG_L2CAP_L2CA_IDTYPE_BREDR;
+ }else if(pcb->psm == 0){
+ return NG_L2CAP_L2CA_IDTYPE_ATT;
+ }else{
+ return NG_L2CAP_L2CA_IDTYPE_LE;
+ }
+}
+
+int ng_btsock_l2cap_addrtype_to_linktype(int addrtype)
+{
+ switch(addrtype){
+ case BDADDR_LE_PUBLIC:
+ return NG_HCI_LINK_LE_PUBLIC;
+ case BDADDR_LE_RANDOM:
+ return NG_HCI_LINK_LE_RANDOM;
+ default:
+ return NG_HCI_LINK_ACL;
+ }
+}
+
+
/*****************************************************************************
*****************************************************************************
** Netgraph node interface
@@ -445,28 +472,35 @@ ng_btsocket_l2cap_process_l2ca_con_req_rsp(struct ng_mesg *msg,
return (0);
}
- if (op->result == NG_L2CAP_SUCCESS) {
- /*
- * Channel is now open, so update local channel ID and
- * start configuration process. Source and destination
- * addresses as well as route must be already set.
- */
-
- pcb->cid = op->lcid;
-
- error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb);
- if (error != 0) {
- /* Send disconnect request with "zero" token */
- ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
-
- /* ... and close the socket */
- pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
- soisdisconnected(pcb->so);
- } else {
- pcb->cfg_state = NG_BTSOCKET_L2CAP_CFG_IN_SENT;
- pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING;
-
- ng_btsocket_l2cap_timeout(pcb);
+ if (op->result == NG_L2CAP_SUCCESS){
+ if(ng_btsock_l2cap_pcb_to_idtype(pcb) ==
+ NG_L2CAP_L2CA_IDTYPE_ATT){
+ pcb->state = NG_BTSOCKET_L2CAP_OPEN;
+ soisconnected(pcb->so);
+ pcb->cid = op->lcid;
+ }else{
+ /*
+ * Channel is now open, so update local channel ID and
+ * start configuration process. Source and destination
+ * addresses as well as route must be already set.
+ */
+
+ pcb->cid = op->lcid;
+
+ error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb);
+ if (error != 0) {
+ /* Send disconnect request with "zero" token */
+ ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
+
+ /* ... and close the socket */
+ pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
+ soisdisconnected(pcb->so);
+ } else {
+ pcb->cfg_state = NG_BTSOCKET_L2CAP_CFG_IN_SENT;
+ pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING;
+
+ ng_btsocket_l2cap_timeout(pcb);
+ }
}
} else {
/*
@@ -643,7 +677,9 @@ ng_btsocket_l2cap_process_l2ca_con_ind(struct ng_mesg *msg,
respond:
error = ng_btsocket_l2cap_send_l2ca_con_rsp_req(token, rt,
- &ip->bdaddr, ip->ident, ip->lcid, result);
+ &ip->bdaddr,
+ ip->ident, ip->lcid,
+ result,ip->linktype);
if (pcb1 != NULL) {
if (error != 0) {
pcb1->so->so_error = error;
@@ -899,7 +935,8 @@ ng_btsocket_l2cap_process_l2ca_cfg_ind(struct ng_mesg *msg,
mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
/* Check for the open socket that has given channel ID */
- pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid);
+ pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid,
+ NG_L2CAP_L2CA_IDTYPE_BREDR);
if (pcb == NULL) {
mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
return (ENOENT);
@@ -1040,7 +1077,8 @@ ng_btsocket_l2cap_process_l2ca_discon_ind(struct ng_mesg *msg,
mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
/* Look for the socket with given channel ID */
- pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid);
+ pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid,
+ NG_L2CAP_L2CA_IDTYPE_BREDR);
if (pcb == NULL) {
mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
return (0);
@@ -1176,7 +1214,8 @@ ng_btsocket_l2cap_send_l2ca_con_req(ng_btsocket_l2cap_pcb_p pcb)
ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
ip->psm = pcb->psm;
-
+ ip->linktype = ng_btsock_l2cap_addrtype_to_linktype(pcb->dsttype);
+ ip->idtype = ng_btsock_l2cap_pcb_to_idtype(pcb);
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
return (error);
@@ -1189,7 +1228,7 @@ ng_btsocket_l2cap_send_l2ca_con_req(ng_btsocket_l2cap_pcb_p pcb)
static int
ng_btsocket_l2cap_send_l2ca_con_rsp_req(u_int32_t token,
ng_btsocket_l2cap_rtentry_p rt, bdaddr_p dst, int ident,
- int lcid, int result)
+ int lcid, int result, int linktype)
{
struct ng_mesg *msg = NULL;
ng_l2cap_l2ca_con_rsp_ip *ip = NULL;
@@ -1209,6 +1248,7 @@ ng_btsocket_l2cap_send_l2ca_con_rsp_req(u_int32_t token,
bcopy(dst, &ip->bdaddr, sizeof(ip->bdaddr));
ip->ident = ident;
ip->lcid = lcid;
+ ip->linktype = linktype;
ip->result = result;
ip->status = 0;
@@ -1314,6 +1354,7 @@ ng_btsocket_l2cap_send_l2ca_discon_req(u_int32_t token,
ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
ip->lcid = pcb->cid;
+ ip->idtype = ng_btsock_l2cap_pcb_to_idtype(pcb);
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
@@ -1337,6 +1378,7 @@ ng_btsocket_l2cap_data_input(struct mbuf *m, hook_p hook)
ng_l2cap_clt_hdr_t *clt_hdr = NULL;
ng_btsocket_l2cap_pcb_t *pcb = NULL;
ng_btsocket_l2cap_rtentry_t *rt = NULL;
+ uint16_t idtype;
if (hook == NULL) {
NG_BTSOCKET_L2CAP_ALERT(
@@ -1351,6 +1393,10 @@ ng_btsocket_l2cap_data_input(struct mbuf *m, hook_p hook)
goto drop;
}
+ m = m_pullup(m, sizeof(uint16_t));
+ idtype = *mtod(m, uint16_t *);
+ m_adj(m, sizeof(uint16_t));
+
/* Make sure we can access header */
if (m->m_pkthdr.len < sizeof(*hdr)) {
NG_BTSOCKET_L2CAP_ERR(
@@ -1394,12 +1440,13 @@ ng_btsocket_l2cap_data_input(struct mbuf *m, hook_p hook)
rt->src.b[2], rt->src.b[1], rt->src.b[0],
hdr->dcid, hdr->length);
- if (hdr->dcid >= NG_L2CAP_FIRST_CID) {
+ if ((hdr->dcid >= NG_L2CAP_FIRST_CID) ||
+ (idtype == NG_L2CAP_L2CA_IDTYPE_ATT)){
mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
/* Normal packet: find connected socket */
- pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, hdr->dcid);
+ pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, hdr->dcid,idtype);
if (pcb == NULL) {
mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
goto drop;
@@ -1557,11 +1604,12 @@ ng_btsocket_l2cap_default_msg_input(struct ng_mesg *msg, hook_p hook)
switch (msg->header.cmd) {
case NGM_L2CAP_NODE_HOOK_INFO: {
ng_btsocket_l2cap_rtentry_t *rt = NULL;
-
- if (hook == NULL || msg->header.arglen != sizeof(bdaddr_t))
+ ng_l2cap_node_hook_info_ep *ep =
+ (ng_l2cap_node_hook_info_ep *)msg->data;
+ if (hook == NULL || msg->header.arglen != sizeof(*ep))
break;
- if (bcmp(msg->data, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
+ if (bcmp(&ep->addr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
break;
mtx_lock(&ng_btsocket_l2cap_rt_mtx);
@@ -1580,7 +1628,7 @@ ng_btsocket_l2cap_default_msg_input(struct ng_mesg *msg, hook_p hook)
NG_HOOK_SET_PRIVATE(hook, rt);
}
- bcopy(msg->data, &rt->src, sizeof(rt->src));
+ bcopy(&ep->addr, &rt->src, sizeof(rt->src));
rt->hook = hook;
mtx_unlock(&ng_btsocket_l2cap_rt_mtx);
@@ -2035,7 +2083,9 @@ ng_btsocket_l2cap_bind(struct socket *so, struct sockaddr *nam,
return (EINVAL);
if (sa->l2cap_family != AF_BLUETOOTH)
return (EAFNOSUPPORT);
- if (sa->l2cap_len != sizeof(*sa))
+ /*For the time being, Not support LE binding.*/
+ if ((sa->l2cap_len != sizeof(*sa))&&
+ (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
return (EINVAL);
psm = le16toh(sa->l2cap_psm);
@@ -2080,7 +2130,9 @@ ng_btsocket_l2cap_connect(struct socket *so, struct sockaddr *nam,
struct thread *td)
{
ng_btsocket_l2cap_pcb_t *pcb = so2l2cap_pcb(so);
- struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
+ struct sockaddr_l2cap_compat *sal = (struct sockaddr_l2cap_compat *) nam;
+ struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *)nam;
+ struct sockaddr_l2cap ba;
ng_btsocket_l2cap_rtentry_t *rt = NULL;
int have_src, error = 0;
@@ -2097,14 +2149,27 @@ ng_btsocket_l2cap_connect(struct socket *so, struct sockaddr *nam,
return (EINVAL);
if (sa->l2cap_family != AF_BLUETOOTH)
return (EAFNOSUPPORT);
+ if (sa->l2cap_len == sizeof(*sal)){
+ bcopy(sal, &ba, sizeof(*sal));
+ sa = &ba;
+ sa->l2cap_len = sizeof(*sa);
+ sa->l2cap_bdaddr_type = BDADDR_BREDR;
+ }
if (sa->l2cap_len != sizeof(*sa))
return (EINVAL);
- if (sa->l2cap_psm == 0 ||
- bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
+ if ((sa->l2cap_psm && sa->l2cap_cid))
+ return EINVAL;
+ if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
return (EDESTADDRREQ);
+ if((sa->l2cap_bdaddr_type == BDADDR_BREDR)&&
+ (sa->l2cap_psm == 0))
+ return EDESTADDRREQ;
+ if((sa->l2cap_bdaddr_type != BDADDR_BREDR)&&
+ (sa->l2cap_cid != NG_L2CAP_ATT_CID)){
+ return EINVAL;
+ }
if (pcb->psm != 0 && pcb->psm != le16toh(sa->l2cap_psm))
return (EINVAL);
-
/*
* Routing. Socket should be bound to some source address. The source
* address can be ANY. Destination address must be set and it must not
@@ -2119,7 +2184,9 @@ ng_btsocket_l2cap_connect(struct socket *so, struct sockaddr *nam,
/* Send destination address and PSM */
bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
pcb->psm = le16toh(sa->l2cap_psm);
-
+ pcb->dsttype = sa->l2cap_bdaddr_type;
+ pcb->cid = sa->l2cap_cid;
+
pcb->rt = NULL;
have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
@@ -2140,8 +2207,12 @@ ng_btsocket_l2cap_connect(struct socket *so, struct sockaddr *nam,
if (rt != NULL) {
pcb->rt = rt;
- if (!have_src)
+ if (!have_src){
bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
+ pcb->srctype =
+ (sa->l2cap_bdaddr_type == BDADDR_BREDR)?
+ BDADDR_BREDR : BDADDR_LE_RANDOM;
+ }
} else
error = EHOSTUNREACH;
@@ -2418,7 +2489,8 @@ ng_btsocket_l2cap_peeraddr(struct socket *so, struct sockaddr **nam)
sa.l2cap_psm = htole16(pcb->psm);
sa.l2cap_len = sizeof(sa);
sa.l2cap_family = AF_BLUETOOTH;
-
+ sa.l2cap_cid = 0;
+ sa.l2cap_bdaddr_type = pcb->dsttype;
*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
return ((*nam == NULL)? ENOMEM : 0);
@@ -2536,7 +2608,7 @@ ng_btsocket_l2cap_send2(ng_btsocket_l2cap_pcb_p pcb)
hdr->token = pcb->token;
hdr->length = m->m_pkthdr.len - sizeof(*hdr);
hdr->lcid = pcb->cid;
-
+ hdr->idtype = ng_btsock_l2cap_pcb_to_idtype(pcb);
NG_BTSOCKET_L2CAP_INFO(
"%s: Sending packet: len=%d, length=%d, lcid=%d, token=%d, state=%d\n",
__func__, m->m_pkthdr.len, hdr->length, hdr->lcid,
@@ -2571,6 +2643,8 @@ ng_btsocket_l2cap_sockaddr(struct socket *so, struct sockaddr **nam)
sa.l2cap_psm = htole16(pcb->psm);
sa.l2cap_len = sizeof(sa);
sa.l2cap_family = AF_BLUETOOTH;
+ sa.l2cap_cid = 0;
+ sa.l2cap_bdaddr_type = pcb->srctype;
*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
@@ -2638,16 +2712,19 @@ ng_btsocket_l2cap_pcb_by_token(u_int32_t token)
*/
static ng_btsocket_l2cap_pcb_p
-ng_btsocket_l2cap_pcb_by_cid(bdaddr_p src, int cid)
+ng_btsocket_l2cap_pcb_by_cid(bdaddr_p src, int cid, int idtype)
{
ng_btsocket_l2cap_pcb_p p = NULL;
mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED);
- LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next)
- if (p->cid == cid && bcmp(src, &p->src, sizeof(p->src)) == 0)
+ LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next){
+ if (p->cid == cid &&
+ bcmp(src, &p->src, sizeof(p->src)) == 0&&
+ ng_btsock_l2cap_pcb_to_idtype(p) == idtype)
break;
+ }
return (p);
} /* ng_btsocket_l2cap_pcb_by_cid */
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
index e0b57e1..bb66510 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
@@ -667,7 +667,8 @@ ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,
return (EINVAL);
if (sa->l2cap_family != AF_BLUETOOTH)
return (EAFNOSUPPORT);
- if (sa->l2cap_len != sizeof(*sa))
+ if((sa->l2cap_len != sizeof(*sa))&&
+ (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
return (EINVAL);
if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
@@ -720,8 +721,10 @@ ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
return (EINVAL);
if (sa->l2cap_family != AF_BLUETOOTH)
return (EAFNOSUPPORT);
- if (sa->l2cap_len != sizeof(*sa))
+ if((sa->l2cap_len != sizeof(*sa))&&
+ (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
return (EINVAL);
+
if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
return (EINVAL);
@@ -1179,6 +1182,8 @@ ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
sa.l2cap_psm = 0;
sa.l2cap_len = sizeof(sa);
sa.l2cap_family = AF_BLUETOOTH;
+ sa.l2cap_cid = 0;
+ sa.l2cap_bdaddr_type = BDADDR_BREDR;
*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
@@ -1221,7 +1226,8 @@ ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
sa.l2cap_psm = 0;
sa.l2cap_len = sizeof(sa);
sa.l2cap_family = AF_BLUETOOTH;
-
+ sa.l2cap_cid = 0;
+ sa.l2cap_bdaddr_type = BDADDR_BREDR;
*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
return ((*nam == NULL)? ENOMEM : 0);
diff --git a/sys/netgraph/ng_deflate.c b/sys/netgraph/ng_deflate.c
index da68e49..be52942 100644
--- a/sys/netgraph/ng_deflate.c
+++ b/sys/netgraph/ng_deflate.c
@@ -39,8 +39,7 @@
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/syslog.h>
-
-#include <net/zlib.h>
+#include <sys/zlib.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
index 986ee3c..a094a49 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -1540,7 +1540,6 @@ igmp_input(struct mbuf **mp, int *offp, int proto)
struct igmpv3 *igmpv3;
uint16_t igmpv3len;
uint16_t nsrc;
- int srclen;
IGMPSTAT_INC(igps_rcv_v3_queries);
igmpv3 = (struct igmpv3 *)igmp;
@@ -1548,8 +1547,8 @@ igmp_input(struct mbuf **mp, int *offp, int proto)
* Validate length based on source count.
*/
nsrc = ntohs(igmpv3->igmp_numsrc);
- srclen = sizeof(struct in_addr) * nsrc;
- if (nsrc * sizeof(in_addr_t) > srclen) {
+ if (nsrc * sizeof(in_addr_t) >
+ UINT16_MAX - iphlen - IGMP_V3_QUERY_MINLEN) {
IGMPSTAT_INC(igps_rcv_tooshort);
return (IPPROTO_DONE);
}
@@ -1558,7 +1557,7 @@ igmp_input(struct mbuf **mp, int *offp, int proto)
* this scope.
*/
igmpv3len = iphlen + IGMP_V3_QUERY_MINLEN +
- srclen;
+ sizeof(struct in_addr) * nsrc;
if ((!M_WRITABLE(m) ||
m->m_len < igmpv3len) &&
(m = m_pullup(m, igmpv3len)) == NULL) {
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index bfcb33a..f47492d 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -128,6 +128,30 @@ in_localip(struct in_addr in)
}
/*
+ * Return 1 if an internet address is configured on an interface.
+ */
+int
+in_ifhasaddr(struct ifnet *ifp, struct in_addr in)
+{
+ struct ifaddr *ifa;
+ struct in_ifaddr *ia;
+
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ ia = (struct in_ifaddr *)ifa;
+ if (ia->ia_addr.sin_addr.s_addr == in.s_addr) {
+ IF_ADDR_RUNLOCK(ifp);
+ return (1);
+ }
+ }
+ IF_ADDR_RUNLOCK(ifp);
+
+ return (0);
+}
+
+/*
* Return a reference to the interface address which is different to
* the supplied one but with same IP address value.
*/
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 1f79761..325b523 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -642,6 +642,7 @@ int in_broadcast(struct in_addr, struct ifnet *);
int in_canforward(struct in_addr);
int in_localaddr(struct in_addr);
int in_localip(struct in_addr);
+int in_ifhasaddr(struct ifnet *, struct in_addr);
int inet_aton(const char *, struct in_addr *); /* in libkern */
char *inet_ntoa(struct in_addr); /* in libkern */
char *inet_ntoa_r(struct in_addr ina, char *buf); /* in libkern */
diff --git a/sys/netinet/in_kdtrace.c b/sys/netinet/in_kdtrace.c
index d37e3c0..edcc853 100644
--- a/sys/netinet/in_kdtrace.c
+++ b/sys/netinet/in_kdtrace.c
@@ -102,6 +102,9 @@ SDT_PROBE_DEFINE5_XLATE(tcp, , , send,
"struct tcpcb *", "tcpsinfo_t *" ,
"struct tcphdr *", "tcpinfo_t *");
+SDT_PROBE_DEFINE1_XLATE(tcp, , , siftr,
+ "struct pkt_node *", "siftrinfo_t *");
+
SDT_PROBE_DEFINE6_XLATE(tcp, , , state__change,
"void *", "void *",
"struct tcpcb *", "csinfo_t *",
diff --git a/sys/netinet/in_kdtrace.h b/sys/netinet/in_kdtrace.h
index 07b3e3a..c0511d0 100644
--- a/sys/netinet/in_kdtrace.h
+++ b/sys/netinet/in_kdtrace.h
@@ -32,6 +32,8 @@
SDT_PROBE6(ip, , , probe, arg0, arg1, arg2, arg3, arg4, arg5)
#define UDP_PROBE(probe, arg0, arg1, arg2, arg3, arg4) \
SDT_PROBE5(udp, , , probe, arg0, arg1, arg2, arg3, arg4)
+#define TCP_PROBE1(probe, arg0) \
+ SDT_PROBE1(tcp, , , probe, arg0)
#define TCP_PROBE5(probe, arg0, arg1, arg2, arg3, arg4) \
SDT_PROBE5(tcp, , , probe, arg0, arg1, arg2, arg3, arg4)
#define TCP_PROBE6(probe, arg0, arg1, arg2, arg3, arg4, arg5) \
@@ -51,6 +53,7 @@ SDT_PROBE_DECLARE(tcp, , , connect__refused);
SDT_PROBE_DECLARE(tcp, , , connect__request);
SDT_PROBE_DECLARE(tcp, , , receive);
SDT_PROBE_DECLARE(tcp, , , send);
+SDT_PROBE_DECLARE(tcp, , , siftr);
SDT_PROBE_DECLARE(tcp, , , state__change);
SDT_PROBE_DECLARE(udp, , , receive);
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
index f7737ec..0318fb2 100644
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -176,15 +176,6 @@ do { \
} while (0)
/*
- * IP datagram reassembly.
- */
-#define IPREASS_NHASH_LOG2 6
-#define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2)
-#define IPREASS_HMASK (IPREASS_NHASH - 1)
-#define IPREASS_HASH(x,y) \
- (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
-
-/*
* Legacy IPv4 IGMP per-link structure.
*/
struct router_info {
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 20962b0..2fa8820 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -180,9 +180,6 @@ static int proto_reg[] = {-1, -1};
*
* Known issues with locking:
*
- * - There is no protection for races between two ioctl() requests,
- * neither SIOCSVH, nor SIOCAIFADDR & SIOCAIFADDR_IN6. I think that all
- * interface ioctl()s should be serialized right in net/if.c.
* - Sending ad, we put the pointer to the softc in an mtag, and no reference
* counting is done on the softc.
* - On module unload we may race (?) with packet processing thread
@@ -259,7 +256,7 @@ SYSCTL_VNET_PCPUSTAT(_net_inet_carp, OID_AUTO, stats, struct carpstats,
#define CIF_LOCK(cif) mtx_lock(&(cif)->cif_mtx)
#define CIF_UNLOCK(cif) mtx_unlock(&(cif)->cif_mtx)
#define CIF_FREE(cif) do { \
- CIF_LOCK_ASSERT(cif); \
+ CIF_LOCK(cif); \
if (TAILQ_EMPTY(&(cif)->cif_vrs)) \
carp_free_if(cif); \
else \
@@ -299,7 +296,6 @@ SYSCTL_VNET_PCPUSTAT(_net_inet_carp, OID_AUTO, stats, struct carpstats,
static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t);
static struct carp_softc
*carp_alloc(struct ifnet *);
-static void carp_detach_locked(struct ifaddr *);
static void carp_destroy(struct carp_softc *);
static struct carp_if
*carp_alloc_if(struct ifnet *);
@@ -321,6 +317,7 @@ static void carp_demote_adj(int, char *);
static LIST_HEAD(, carp_softc) carp_list;
static struct mtx carp_mtx;
+static struct sx carp_sx;
static struct task carp_sendall_task =
TASK_INITIALIZER(0, carp_send_ad_all, NULL);
@@ -1252,8 +1249,6 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa)
struct ifnet *ifp = cif->cif_ifp;
int error = 0;
- CIF_LOCK_ASSERT(cif);
-
switch (sa) {
#ifdef INET
case AF_INET:
@@ -1266,9 +1261,7 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa)
imo->imo_membership = (struct in_multi **)malloc(
(sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP,
- M_NOWAIT);
- if (imo->imo_membership == NULL)
- return (ENOMEM);
+ M_WAITOK);
imo->imo_mfilters = NULL;
imo->imo_max_memberships = IP_MIN_MEMBERSHIPS;
imo->imo_multicast_vif = -1;
@@ -1298,9 +1291,7 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa)
im6o->im6o_membership = (struct in6_multi **)malloc(
(sizeof(struct in6_multi *) * IPV6_MIN_MEMBERSHIPS), M_CARP,
- M_ZERO | M_NOWAIT);
- if (im6o->im6o_membership == NULL)
- return (ENOMEM);
+ M_ZERO | M_WAITOK);
im6o->im6o_mfilters = NULL;
im6o->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS;
im6o->im6o_multicast_hlim = CARP_DFLTTL;
@@ -1357,7 +1348,8 @@ static void
carp_multicast_cleanup(struct carp_if *cif, sa_family_t sa)
{
- CIF_LOCK_ASSERT(cif);
+ sx_assert(&carp_sx, SA_XLOCKED);
+
switch (sa) {
#ifdef INET
case AF_INET:
@@ -1506,22 +1498,18 @@ carp_alloc(struct ifnet *ifp)
return (sc);
}
-static int
+static void
carp_grow_ifas(struct carp_softc *sc)
{
struct ifaddr **new;
- CARP_LOCK_ASSERT(sc);
-
- new = malloc(sc->sc_ifasiz * 2, M_CARP, M_NOWAIT|M_ZERO);
- if (new == NULL)
- return (ENOMEM);
+ new = malloc(sc->sc_ifasiz * 2, M_CARP, M_WAITOK | M_ZERO);
+ CARP_LOCK(sc);
bcopy(sc->sc_ifas, new, sc->sc_ifasiz);
free(sc->sc_ifas, M_CARP);
sc->sc_ifas = new;
sc->sc_ifasiz *= 2;
-
- return (0);
+ CARP_UNLOCK(sc);
}
static void
@@ -1530,17 +1518,20 @@ carp_destroy(struct carp_softc *sc)
struct ifnet *ifp = sc->sc_carpdev;
struct carp_if *cif = ifp->if_carp;
- CIF_LOCK_ASSERT(cif);
+ sx_assert(&carp_sx, SA_XLOCKED);
+
+ if (sc->sc_suppress)
+ carp_demote_adj(-V_carp_ifdown_adj, "vhid removed");
+ CARP_UNLOCK(sc);
+ CIF_LOCK(cif);
TAILQ_REMOVE(&cif->cif_vrs, sc, sc_list);
+ CIF_UNLOCK(cif);
mtx_lock(&carp_mtx);
LIST_REMOVE(sc, sc_next);
mtx_unlock(&carp_mtx);
- CARP_LOCK(sc);
- if (sc->sc_suppress)
- carp_demote_adj(-V_carp_ifdown_adj, "vhid removed");
callout_drain(&sc->sc_ad_tmo);
#ifdef INET
callout_drain(&sc->sc_md_tmo);
@@ -1650,6 +1641,7 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
goto out;
}
+ sx_xlock(&carp_sx);
switch (cmd) {
case SIOCSVH:
if ((error = priv_check(td, PRIV_NETINET_CARP)))
@@ -1780,6 +1772,7 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
default:
error = EINVAL;
}
+ sx_xunlock(&carp_sx);
out:
if (locked)
@@ -1807,8 +1800,7 @@ carp_attach(struct ifaddr *ifa, int vhid)
struct carp_softc *sc;
int index, error;
- if (ifp->if_carp == NULL)
- return (ENOPROTOOPT);
+ KASSERT(ifa->ifa_carp == NULL, ("%s: ifa %p attached", __func__, ifa));
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
@@ -1822,40 +1814,32 @@ carp_attach(struct ifaddr *ifa, int vhid)
return (EPROTOTYPE);
}
+ sx_xlock(&carp_sx);
+ if (ifp->if_carp == NULL) {
+ sx_xunlock(&carp_sx);
+ return (ENOPROTOOPT);
+ }
+
CIF_LOCK(cif);
IFNET_FOREACH_CARP(ifp, sc)
if (sc->sc_vhid == vhid)
break;
+ CIF_UNLOCK(cif);
if (sc == NULL) {
- CIF_UNLOCK(cif);
+ sx_xunlock(&carp_sx);
return (ENOENT);
}
- if (ifa->ifa_carp) {
- if (ifa->ifa_carp->sc_vhid != vhid)
- carp_detach_locked(ifa);
- else {
- CIF_UNLOCK(cif);
- return (0);
- }
- }
-
error = carp_multicast_setup(cif, ifa->ifa_addr->sa_family);
if (error) {
CIF_FREE(cif);
+ sx_xunlock(&carp_sx);
return (error);
}
- CARP_LOCK(sc);
index = sc->sc_naddrs + sc->sc_naddrs6 + 1;
if (index > sc->sc_ifasiz / sizeof(struct ifaddr *))
- if ((error = carp_grow_ifas(sc)) != 0) {
- carp_multicast_cleanup(cif,
- ifa->ifa_addr->sa_family);
- CARP_UNLOCK(sc);
- CIF_FREE(cif);
- return (error);
- }
+ carp_grow_ifas(sc);
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
@@ -1873,14 +1857,15 @@ carp_attach(struct ifaddr *ifa, int vhid)
}
ifa_ref(ifa);
+
+ CARP_LOCK(sc);
sc->sc_ifas[index - 1] = ifa;
ifa->ifa_carp = sc;
-
carp_hmac_prepare(sc);
carp_sc_state(sc);
-
CARP_UNLOCK(sc);
- CIF_UNLOCK(cif);
+
+ sx_xunlock(&carp_sx);
return (0);
}
@@ -1890,25 +1875,14 @@ carp_detach(struct ifaddr *ifa)
{
struct ifnet *ifp = ifa->ifa_ifp;
struct carp_if *cif = ifp->if_carp;
-
- CIF_LOCK(cif);
- carp_detach_locked(ifa);
- CIF_FREE(cif);
-}
-
-static void
-carp_detach_locked(struct ifaddr *ifa)
-{
- struct ifnet *ifp = ifa->ifa_ifp;
- struct carp_if *cif = ifp->if_carp;
struct carp_softc *sc = ifa->ifa_carp;
int i, index;
KASSERT(sc != NULL, ("%s: %p not attached", __func__, ifa));
- CIF_LOCK_ASSERT(cif);
- CARP_LOCK(sc);
+ sx_xlock(&carp_sx);
+ CARP_LOCK(sc);
/* Shift array. */
index = sc->sc_naddrs + sc->sc_naddrs6;
for (i = 0; i < index; i++)
@@ -1943,11 +1917,14 @@ carp_detach_locked(struct ifaddr *ifa)
carp_hmac_prepare(sc);
carp_sc_state(sc);
- if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) {
- CARP_UNLOCK(sc);
+ if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)
carp_destroy(sc);
- } else
+ else
CARP_UNLOCK(sc);
+
+ CIF_FREE(cif);
+
+ sx_xunlock(&carp_sx);
}
static void
@@ -2099,6 +2076,7 @@ carp_mod_cleanup(void)
mtx_unlock(&carp_mtx);
taskqueue_drain(taskqueue_swi, &carp_sendall_task);
mtx_destroy(&carp_mtx);
+ sx_destroy(&carp_sx);
}
static int
@@ -2107,6 +2085,7 @@ carp_mod_load(void)
int err;
mtx_init(&carp_mtx, "carp_mtx", NULL, MTX_DEF);
+ sx_init(&carp_sx, "carp_sx");
LIST_INIT(&carp_list);
carp_get_vhid_p = carp_get_vhid;
carp_forus_p = carp_forus;
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 9c53793..d1764bb 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -40,10 +40,12 @@
#define IPFW_MAX_SETS 32 /* Number of sets supported by ipfw*/
/*
- * Default number of ipfw tables.
+ * Compat values for old clients
*/
+#ifndef _KERNEL
#define IPFW_TABLES_MAX 65535
#define IPFW_TABLES_DEFAULT 128
+#endif
/*
* Most commands (queue, pipe, tag, untag, limit...) can have a 16-bit
@@ -963,7 +965,6 @@ typedef struct _ipfw_ta_info {
uint64_t spare1;
} ipfw_ta_info;
-#define IPFW_OBJTYPE_TABLE 1
typedef struct _ipfw_obj_header {
ip_fw3_opheader opheader; /* IP_FW3 opcode */
uint32_t spare;
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index a3dd57f..f4b6dfc 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -89,6 +89,14 @@ __FBSDID("$FreeBSD$");
CTASSERT(sizeof(struct ip) == 20);
#endif
+/* IP reassembly functions are defined in ip_reass.c. */
+extern void ipreass_init(void);
+extern void ipreass_drain(void);
+extern void ipreass_slowtimo(void);
+#ifdef VIMAGE
+extern void ipreass_destroy(void);
+#endif
+
struct rwlock in_ifaddr_lock;
RW_SYSINIT(in_ifaddr_lock, &in_ifaddr_lock, "in_ifaddr_lock");
@@ -164,36 +172,6 @@ VNET_DEFINE(struct in_ifaddrhead, in_ifaddrhead); /* first inet address */
VNET_DEFINE(struct in_ifaddrhashhead *, in_ifaddrhashtbl); /* inet addr hash table */
VNET_DEFINE(u_long, in_ifaddrhmask); /* mask for hash table */
-static VNET_DEFINE(uma_zone_t, ipq_zone);
-static VNET_DEFINE(TAILQ_HEAD(ipqhead, ipq), ipq[IPREASS_NHASH]);
-static struct mtx ipqlock;
-
-#define V_ipq_zone VNET(ipq_zone)
-#define V_ipq VNET(ipq)
-
-#define IPQ_LOCK() mtx_lock(&ipqlock)
-#define IPQ_UNLOCK() mtx_unlock(&ipqlock)
-#define IPQ_LOCK_INIT() mtx_init(&ipqlock, "ipqlock", NULL, MTX_DEF)
-#define IPQ_LOCK_ASSERT() mtx_assert(&ipqlock, MA_OWNED)
-
-static void maxnipq_update(void);
-static void ipq_zone_change(void *);
-static void ip_drain_locked(void);
-
-static VNET_DEFINE(int, maxnipq); /* Administrative limit on # reass queues. */
-static VNET_DEFINE(int, nipq); /* Total # of reass queues */
-#define V_maxnipq VNET(maxnipq)
-#define V_nipq VNET(nipq)
-SYSCTL_INT(_net_inet_ip, OID_AUTO, fragpackets, CTLFLAG_VNET | CTLFLAG_RD,
- &VNET_NAME(nipq), 0,
- "Current number of IPv4 fragment reassembly queue entries");
-
-static VNET_DEFINE(int, maxfragsperpacket);
-#define V_maxfragsperpacket VNET(maxfragsperpacket)
-SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragsperpacket, CTLFLAG_VNET | CTLFLAG_RW,
- &VNET_NAME(maxfragsperpacket), 0,
- "Maximum number of IPv4 fragments allowed per packet");
-
#ifdef IPCTL_DEFMTU
SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
&ip_mtu, 0, "Default MTU");
@@ -206,8 +184,6 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_VNET | CTLFLAG_RW,
"IP stealth mode, no TTL decrementation on forwarding");
#endif
-static void ip_freef(struct ipqhead *, struct ipq *);
-
/*
* IP statistics are stored in the "array" of counter(9)s.
*/
@@ -330,13 +306,7 @@ ip_init(void)
V_in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &V_in_ifaddrhmask);
/* Initialize IP reassembly queue. */
- for (i = 0; i < IPREASS_NHASH; i++)
- TAILQ_INIT(&V_ipq[i]);
- V_maxnipq = nmbclusters / 32;
- V_maxfragsperpacket = 16;
- V_ipq_zone = uma_zcreate("ipq", sizeof(struct ipq), NULL, NULL, NULL,
- NULL, UMA_ALIGN_PTR, 0);
- maxnipq_update();
+ ipreass_init();
/* Initialize packet filter hooks. */
V_inet_pfil_hook.ph_type = PFIL_TYPE_AF;
@@ -369,11 +339,6 @@ ip_init(void)
ip_protox[pr->pr_protocol] = pr - inetsw;
}
- EVENTHANDLER_REGISTER(nmbclusters_change, ipq_zone_change,
- NULL, EVENTHANDLER_PRI_ANY);
-
- /* Initialize various other remaining things. */
- IPQ_LOCK_INIT();
netisr_register(&ip_nh);
#ifdef RSS
netisr_register(&ip_direct_nh);
@@ -393,11 +358,8 @@ ip_destroy(void)
/* Cleanup in_ifaddr hash table; should be empty. */
hashdestroy(V_in_ifaddrhashtbl, M_IFADDR, V_in_ifaddrhmask);
- IPQ_LOCK();
- ip_drain_locked();
- IPQ_UNLOCK();
-
- uma_zdestroy(V_ipq_zone);
+ /* Destroy IP reassembly queue. */
+ ipreass_destroy();
}
#endif
@@ -791,451 +753,6 @@ bad:
}
/*
- * After maxnipq has been updated, propagate the change to UMA. The UMA zone
- * max has slightly different semantics than the sysctl, for historical
- * reasons.
- */
-static void
-maxnipq_update(void)
-{
-
- /*
- * -1 for unlimited allocation.
- */
- if (V_maxnipq < 0)
- uma_zone_set_max(V_ipq_zone, 0);
- /*
- * Positive number for specific bound.
- */
- if (V_maxnipq > 0)
- uma_zone_set_max(V_ipq_zone, V_maxnipq);
- /*
- * Zero specifies no further fragment queue allocation -- set the
- * bound very low, but rely on implementation elsewhere to actually
- * prevent allocation and reclaim current queues.
- */
- if (V_maxnipq == 0)
- uma_zone_set_max(V_ipq_zone, 1);
-}
-
-static void
-ipq_zone_change(void *tag)
-{
-
- if (V_maxnipq > 0 && V_maxnipq < (nmbclusters / 32)) {
- V_maxnipq = nmbclusters / 32;
- maxnipq_update();
- }
-}
-
-static int
-sysctl_maxnipq(SYSCTL_HANDLER_ARGS)
-{
- int error, i;
-
- i = V_maxnipq;
- error = sysctl_handle_int(oidp, &i, 0, req);
- if (error || !req->newptr)
- return (error);
-
- /*
- * XXXRW: Might be a good idea to sanity check the argument and place
- * an extreme upper bound.
- */
- if (i < -1)
- return (EINVAL);
- V_maxnipq = i;
- maxnipq_update();
- return (0);
-}
-
-SYSCTL_PROC(_net_inet_ip, OID_AUTO, maxfragpackets, CTLTYPE_INT|CTLFLAG_RW,
- NULL, 0, sysctl_maxnipq, "I",
- "Maximum number of IPv4 fragment reassembly queue entries");
-
-#define M_IP_FRAG M_PROTO9
-
-/*
- * Take incoming datagram fragment and try to reassemble it into
- * whole datagram. If the argument is the first fragment or one
- * in between the function will return NULL and store the mbuf
- * in the fragment chain. If the argument is the last fragment
- * the packet will be reassembled and the pointer to the new
- * mbuf returned for further processing. Only m_tags attached
- * to the first packet/fragment are preserved.
- * The IP header is *NOT* adjusted out of iplen.
- */
-struct mbuf *
-ip_reass(struct mbuf *m)
-{
- struct ip *ip;
- struct mbuf *p, *q, *nq, *t;
- struct ipq *fp = NULL;
- struct ipqhead *head;
- int i, hlen, next;
- u_int8_t ecn, ecn0;
- u_short hash;
-#ifdef RSS
- uint32_t rss_hash, rss_type;
-#endif
-
- /* If maxnipq or maxfragsperpacket are 0, never accept fragments. */
- if (V_maxnipq == 0 || V_maxfragsperpacket == 0) {
- IPSTAT_INC(ips_fragments);
- IPSTAT_INC(ips_fragdropped);
- m_freem(m);
- return (NULL);
- }
-
- ip = mtod(m, struct ip *);
- hlen = ip->ip_hl << 2;
-
- hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
- head = &V_ipq[hash];
- IPQ_LOCK();
-
- /*
- * Look for queue of fragments
- * of this datagram.
- */
- TAILQ_FOREACH(fp, head, ipq_list)
- if (ip->ip_id == fp->ipq_id &&
- ip->ip_src.s_addr == fp->ipq_src.s_addr &&
- ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
-#ifdef MAC
- mac_ipq_match(m, fp) &&
-#endif
- ip->ip_p == fp->ipq_p)
- goto found;
-
- fp = NULL;
-
- /*
- * Attempt to trim the number of allocated fragment queues if it
- * exceeds the administrative limit.
- */
- if ((V_nipq > V_maxnipq) && (V_maxnipq > 0)) {
- /*
- * drop something from the tail of the current queue
- * before proceeding further
- */
- struct ipq *q = TAILQ_LAST(head, ipqhead);
- if (q == NULL) { /* gak */
- for (i = 0; i < IPREASS_NHASH; i++) {
- struct ipq *r = TAILQ_LAST(&V_ipq[i], ipqhead);
- if (r) {
- IPSTAT_ADD(ips_fragtimeout,
- r->ipq_nfrags);
- ip_freef(&V_ipq[i], r);
- break;
- }
- }
- } else {
- IPSTAT_ADD(ips_fragtimeout, q->ipq_nfrags);
- ip_freef(head, q);
- }
- }
-
-found:
- /*
- * Adjust ip_len to not reflect header,
- * convert offset of this to bytes.
- */
- ip->ip_len = htons(ntohs(ip->ip_len) - hlen);
- if (ip->ip_off & htons(IP_MF)) {
- /*
- * Make sure that fragments have a data length
- * that's a non-zero multiple of 8 bytes.
- */
- if (ip->ip_len == htons(0) || (ntohs(ip->ip_len) & 0x7) != 0) {
- IPSTAT_INC(ips_toosmall); /* XXX */
- goto dropfrag;
- }
- m->m_flags |= M_IP_FRAG;
- } else
- m->m_flags &= ~M_IP_FRAG;
- ip->ip_off = htons(ntohs(ip->ip_off) << 3);
-
- /*
- * Attempt reassembly; if it succeeds, proceed.
- * ip_reass() will return a different mbuf.
- */
- IPSTAT_INC(ips_fragments);
- m->m_pkthdr.PH_loc.ptr = ip;
-
- /* Previous ip_reass() started here. */
- /*
- * Presence of header sizes in mbufs
- * would confuse code below.
- */
- m->m_data += hlen;
- m->m_len -= hlen;
-
- /*
- * If first fragment to arrive, create a reassembly queue.
- */
- if (fp == NULL) {
- fp = uma_zalloc(V_ipq_zone, M_NOWAIT);
- if (fp == NULL)
- goto dropfrag;
-#ifdef MAC
- if (mac_ipq_init(fp, M_NOWAIT) != 0) {
- uma_zfree(V_ipq_zone, fp);
- fp = NULL;
- goto dropfrag;
- }
- mac_ipq_create(m, fp);
-#endif
- TAILQ_INSERT_HEAD(head, fp, ipq_list);
- V_nipq++;
- fp->ipq_nfrags = 1;
- fp->ipq_ttl = IPFRAGTTL;
- fp->ipq_p = ip->ip_p;
- fp->ipq_id = ip->ip_id;
- fp->ipq_src = ip->ip_src;
- fp->ipq_dst = ip->ip_dst;
- fp->ipq_frags = m;
- m->m_nextpkt = NULL;
- goto done;
- } else {
- fp->ipq_nfrags++;
-#ifdef MAC
- mac_ipq_update(m, fp);
-#endif
- }
-
-#define GETIP(m) ((struct ip*)((m)->m_pkthdr.PH_loc.ptr))
-
- /*
- * Handle ECN by comparing this segment with the first one;
- * if CE is set, do not lose CE.
- * drop if CE and not-ECT are mixed for the same packet.
- */
- ecn = ip->ip_tos & IPTOS_ECN_MASK;
- ecn0 = GETIP(fp->ipq_frags)->ip_tos & IPTOS_ECN_MASK;
- if (ecn == IPTOS_ECN_CE) {
- if (ecn0 == IPTOS_ECN_NOTECT)
- goto dropfrag;
- if (ecn0 != IPTOS_ECN_CE)
- GETIP(fp->ipq_frags)->ip_tos |= IPTOS_ECN_CE;
- }
- if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT)
- goto dropfrag;
-
- /*
- * Find a segment which begins after this one does.
- */
- for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
- if (ntohs(GETIP(q)->ip_off) > ntohs(ip->ip_off))
- break;
-
- /*
- * If there is a preceding segment, it may provide some of
- * our data already. If so, drop the data from the incoming
- * segment. If it provides all of our data, drop us, otherwise
- * stick new segment in the proper place.
- *
- * If some of the data is dropped from the preceding
- * segment, then it's checksum is invalidated.
- */
- if (p) {
- i = ntohs(GETIP(p)->ip_off) + ntohs(GETIP(p)->ip_len) -
- ntohs(ip->ip_off);
- if (i > 0) {
- if (i >= ntohs(ip->ip_len))
- goto dropfrag;
- m_adj(m, i);
- m->m_pkthdr.csum_flags = 0;
- ip->ip_off = htons(ntohs(ip->ip_off) + i);
- ip->ip_len = htons(ntohs(ip->ip_len) - i);
- }
- m->m_nextpkt = p->m_nextpkt;
- p->m_nextpkt = m;
- } else {
- m->m_nextpkt = fp->ipq_frags;
- fp->ipq_frags = m;
- }
-
- /*
- * While we overlap succeeding segments trim them or,
- * if they are completely covered, dequeue them.
- */
- for (; q != NULL && ntohs(ip->ip_off) + ntohs(ip->ip_len) >
- ntohs(GETIP(q)->ip_off); q = nq) {
- i = (ntohs(ip->ip_off) + ntohs(ip->ip_len)) -
- ntohs(GETIP(q)->ip_off);
- if (i < ntohs(GETIP(q)->ip_len)) {
- GETIP(q)->ip_len = htons(ntohs(GETIP(q)->ip_len) - i);
- GETIP(q)->ip_off = htons(ntohs(GETIP(q)->ip_off) + i);
- m_adj(q, i);
- q->m_pkthdr.csum_flags = 0;
- break;
- }
- nq = q->m_nextpkt;
- m->m_nextpkt = nq;
- IPSTAT_INC(ips_fragdropped);
- fp->ipq_nfrags--;
- m_freem(q);
- }
-
- /*
- * Check for complete reassembly and perform frag per packet
- * limiting.
- *
- * Frag limiting is performed here so that the nth frag has
- * a chance to complete the packet before we drop the packet.
- * As a result, n+1 frags are actually allowed per packet, but
- * only n will ever be stored. (n = maxfragsperpacket.)
- *
- */
- next = 0;
- for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
- if (ntohs(GETIP(q)->ip_off) != next) {
- if (fp->ipq_nfrags > V_maxfragsperpacket) {
- IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
- ip_freef(head, fp);
- }
- goto done;
- }
- next += ntohs(GETIP(q)->ip_len);
- }
- /* Make sure the last packet didn't have the IP_MF flag */
- if (p->m_flags & M_IP_FRAG) {
- if (fp->ipq_nfrags > V_maxfragsperpacket) {
- IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
- ip_freef(head, fp);
- }
- goto done;
- }
-
- /*
- * Reassembly is complete. Make sure the packet is a sane size.
- */
- q = fp->ipq_frags;
- ip = GETIP(q);
- if (next + (ip->ip_hl << 2) > IP_MAXPACKET) {
- IPSTAT_INC(ips_toolong);
- IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
- ip_freef(head, fp);
- goto done;
- }
-
- /*
- * Concatenate fragments.
- */
- m = q;
- t = m->m_next;
- m->m_next = NULL;
- m_cat(m, t);
- nq = q->m_nextpkt;
- q->m_nextpkt = NULL;
- for (q = nq; q != NULL; q = nq) {
- nq = q->m_nextpkt;
- q->m_nextpkt = NULL;
- m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
- m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
- m_cat(m, q);
- }
- /*
- * In order to do checksumming faster we do 'end-around carry' here
- * (and not in for{} loop), though it implies we are not going to
- * reassemble more than 64k fragments.
- */
- while (m->m_pkthdr.csum_data & 0xffff0000)
- m->m_pkthdr.csum_data = (m->m_pkthdr.csum_data & 0xffff) +
- (m->m_pkthdr.csum_data >> 16);
-#ifdef MAC
- mac_ipq_reassemble(fp, m);
- mac_ipq_destroy(fp);
-#endif
-
- /*
- * Create header for new ip packet by modifying header of first
- * packet; dequeue and discard fragment reassembly header.
- * Make header visible.
- */
- ip->ip_len = htons((ip->ip_hl << 2) + next);
- ip->ip_src = fp->ipq_src;
- ip->ip_dst = fp->ipq_dst;
- TAILQ_REMOVE(head, fp, ipq_list);
- V_nipq--;
- uma_zfree(V_ipq_zone, fp);
- m->m_len += (ip->ip_hl << 2);
- m->m_data -= (ip->ip_hl << 2);
- /* some debugging cruft by sklower, below, will go away soon */
- if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */
- m_fixhdr(m);
- IPSTAT_INC(ips_reassembled);
- IPQ_UNLOCK();
-
-#ifdef RSS
- /*
- * Query the RSS layer for the flowid / flowtype for the
- * mbuf payload.
- *
- * For now, just assume we have to calculate a new one.
- * Later on we should check to see if the assigned flowid matches
- * what RSS wants for the given IP protocol and if so, just keep it.
- *
- * We then queue into the relevant netisr so it can be dispatched
- * to the correct CPU.
- *
- * Note - this may return 1, which means the flowid in the mbuf
- * is correct for the configured RSS hash types and can be used.
- */
- if (rss_mbuf_software_hash_v4(m, 0, &rss_hash, &rss_type) == 0) {
- m->m_pkthdr.flowid = rss_hash;
- M_HASHTYPE_SET(m, rss_type);
- }
-
- /*
- * Queue/dispatch for reprocessing.
- *
- * Note: this is much slower than just handling the frame in the
- * current receive context. It's likely worth investigating
- * why this is.
- */
- netisr_dispatch(NETISR_IP_DIRECT, m);
- return (NULL);
-#endif
-
- /* Handle in-line */
- return (m);
-
-dropfrag:
- IPSTAT_INC(ips_fragdropped);
- if (fp != NULL)
- fp->ipq_nfrags--;
- m_freem(m);
-done:
- IPQ_UNLOCK();
- return (NULL);
-
-#undef GETIP
-}
-
-/*
- * Free a fragment reassembly header and all
- * associated datagrams.
- */
-static void
-ip_freef(struct ipqhead *fhp, struct ipq *fp)
-{
- struct mbuf *q;
-
- IPQ_LOCK_ASSERT();
-
- while (fp->ipq_frags) {
- q = fp->ipq_frags;
- fp->ipq_frags = q->m_nextpkt;
- m_freem(q);
- }
- TAILQ_REMOVE(fhp, fp, ipq_list);
- uma_zfree(V_ipq_zone, fp);
- V_nipq--;
-}
-
-/*
* IP timer processing;
* if a timer expires on a reassembly
* queue, discard it.
@@ -1244,80 +761,27 @@ void
ip_slowtimo(void)
{
VNET_ITERATOR_DECL(vnet_iter);
- struct ipq *fp;
- int i;
VNET_LIST_RLOCK_NOSLEEP();
- IPQ_LOCK();
VNET_FOREACH(vnet_iter) {
CURVNET_SET(vnet_iter);
- for (i = 0; i < IPREASS_NHASH; i++) {
- for(fp = TAILQ_FIRST(&V_ipq[i]); fp;) {
- struct ipq *fpp;
-
- fpp = fp;
- fp = TAILQ_NEXT(fp, ipq_list);
- if(--fpp->ipq_ttl == 0) {
- IPSTAT_ADD(ips_fragtimeout,
- fpp->ipq_nfrags);
- ip_freef(&V_ipq[i], fpp);
- }
- }
- }
- /*
- * If we are over the maximum number of fragments
- * (due to the limit being lowered), drain off
- * enough to get down to the new limit.
- */
- if (V_maxnipq >= 0 && V_nipq > V_maxnipq) {
- for (i = 0; i < IPREASS_NHASH; i++) {
- while (V_nipq > V_maxnipq &&
- !TAILQ_EMPTY(&V_ipq[i])) {
- IPSTAT_ADD(ips_fragdropped,
- TAILQ_FIRST(&V_ipq[i])->ipq_nfrags);
- ip_freef(&V_ipq[i],
- TAILQ_FIRST(&V_ipq[i]));
- }
- }
- }
+ ipreass_slowtimo();
CURVNET_RESTORE();
}
- IPQ_UNLOCK();
VNET_LIST_RUNLOCK_NOSLEEP();
}
-/*
- * Drain off all datagram fragments.
- */
-static void
-ip_drain_locked(void)
-{
- int i;
-
- IPQ_LOCK_ASSERT();
-
- for (i = 0; i < IPREASS_NHASH; i++) {
- while(!TAILQ_EMPTY(&V_ipq[i])) {
- IPSTAT_ADD(ips_fragdropped,
- TAILQ_FIRST(&V_ipq[i])->ipq_nfrags);
- ip_freef(&V_ipq[i], TAILQ_FIRST(&V_ipq[i]));
- }
- }
-}
-
void
ip_drain(void)
{
VNET_ITERATOR_DECL(vnet_iter);
VNET_LIST_RLOCK_NOSLEEP();
- IPQ_LOCK();
VNET_FOREACH(vnet_iter) {
CURVNET_SET(vnet_iter);
- ip_drain_locked();
+ ipreass_drain();
CURVNET_RESTORE();
}
- IPQ_UNLOCK();
VNET_LIST_RUNLOCK_NOSLEEP();
}
diff --git a/sys/netinet/ip_ipsec.c b/sys/netinet/ip_ipsec.c
index 1a643fb..47f683d 100644
--- a/sys/netinet/ip_ipsec.c
+++ b/sys/netinet/ip_ipsec.c
@@ -199,6 +199,9 @@ ip_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error)
/* NB: callee frees mbuf */
*error = ipsec4_process_packet(*m, sp->req);
+ /* Release SP if an error occured */
+ if (*error != 0)
+ KEY_FREESP(&sp);
if (*error == EJUSTRETURN) {
/*
* We had a SP with a level of 'use' and no SA. We
@@ -234,13 +237,9 @@ ip_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error)
/* No IPsec processing for this packet. */
}
done:
- if (sp != NULL)
- KEY_FREESP(&sp);
- return 0;
+ return (0);
reinjected:
- if (sp != NULL)
- KEY_FREESP(&sp);
- return -1;
+ return (-1);
bad:
if (sp != NULL)
KEY_FREESP(&sp);
diff --git a/sys/netinet/ip_reass.c b/sys/netinet/ip_reass.c
new file mode 100644
index 0000000..dc1ac14
--- /dev/null
+++ b/sys/netinet/ip_reass.c
@@ -0,0 +1,658 @@
+/*-
+ * Copyright (c) 2015 Gleb Smirnoff <glebius@FreeBSD.org>
+ * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_rss.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/eventhandler.h>
+#include <sys/hash.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+
+#include <net/rss_config.h>
+#include <net/netisr.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/in_rss.h>
+#ifdef MAC
+#include <security/mac/mac_framework.h>
+#endif
+
+SYSCTL_DECL(_net_inet_ip);
+
+/*
+ * Reassembly headers are stored in hash buckets.
+ */
+#define IPREASS_NHASH_LOG2 6
+#define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2)
+#define IPREASS_HMASK (IPREASS_NHASH - 1)
+
+struct ipqbucket {
+ TAILQ_HEAD(ipqhead, ipq) head;
+ struct mtx lock;
+};
+
+static VNET_DEFINE(struct ipqbucket, ipq[IPREASS_NHASH]);
+#define V_ipq VNET(ipq)
+static VNET_DEFINE(uint32_t, ipq_hashseed);
+#define V_ipq_hashseed VNET(ipq_hashseed)
+
+#define IPQ_LOCK(i) mtx_lock(&V_ipq[i].lock)
+#define IPQ_TRYLOCK(i) mtx_trylock(&V_ipq[i].lock)
+#define IPQ_UNLOCK(i) mtx_unlock(&V_ipq[i].lock)
+#define IPQ_LOCK_ASSERT(i) mtx_assert(&V_ipq[i].lock, MA_OWNED)
+
+void ipreass_init(void);
+void ipreass_drain(void);
+void ipreass_slowtimo(void);
+#ifdef VIMAGE
+void ipreass_destroy(void);
+#endif
+static int sysctl_maxfragpackets(SYSCTL_HANDLER_ARGS);
+static void ipreass_zone_change(void *);
+static void ipreass_drain_tomax(void);
+static void ipq_free(struct ipqhead *, struct ipq *);
+static struct ipq * ipq_reuse(int);
+
+static inline void
+ipq_timeout(struct ipqhead *head, struct ipq *fp)
+{
+
+ IPSTAT_ADD(ips_fragtimeout, fp->ipq_nfrags);
+ ipq_free(head, fp);
+}
+
+static inline void
+ipq_drop(struct ipqhead *head, struct ipq *fp)
+{
+
+ IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
+ ipq_free(head, fp);
+}
+
+static VNET_DEFINE(uma_zone_t, ipq_zone);
+#define V_ipq_zone VNET(ipq_zone)
+SYSCTL_PROC(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_VNET |
+ CTLTYPE_INT | CTLFLAG_RW, NULL, 0, sysctl_maxfragpackets, "I",
+ "Maximum number of IPv4 fragment reassembly queue entries");
+SYSCTL_UMA_CUR(_net_inet_ip, OID_AUTO, fragpackets, CTLFLAG_VNET,
+ &VNET_NAME(ipq_zone),
+ "Current number of IPv4 fragment reassembly queue entries");
+
+static VNET_DEFINE(int, noreass);
+#define V_noreass VNET(noreass)
+
+static VNET_DEFINE(int, maxfragsperpacket);
+#define V_maxfragsperpacket VNET(maxfragsperpacket)
+SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragsperpacket, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(maxfragsperpacket), 0,
+ "Maximum number of IPv4 fragments allowed per packet");
+
+/*
+ * Take incoming datagram fragment and try to reassemble it into
+ * whole datagram. If the argument is the first fragment or one
+ * in between the function will return NULL and store the mbuf
+ * in the fragment chain. If the argument is the last fragment
+ * the packet will be reassembled and the pointer to the new
+ * mbuf returned for further processing. Only m_tags attached
+ * to the first packet/fragment are preserved.
+ * The IP header is *NOT* adjusted out of iplen.
+ */
+#define M_IP_FRAG M_PROTO9
+struct mbuf *
+ip_reass(struct mbuf *m)
+{
+ struct ip *ip;
+ struct mbuf *p, *q, *nq, *t;
+ struct ipq *fp;
+ struct ipqhead *head;
+ int i, hlen, next;
+ u_int8_t ecn, ecn0;
+ uint32_t hash;
+#ifdef RSS
+ uint32_t rss_hash, rss_type;
+#endif
+
+ /*
+ * If no reassembling or maxfragsperpacket are 0,
+ * never accept fragments.
+ */
+ if (V_noreass == 1 || V_maxfragsperpacket == 0) {
+ IPSTAT_INC(ips_fragments);
+ IPSTAT_INC(ips_fragdropped);
+ m_freem(m);
+ return (NULL);
+ }
+
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
+
+ /*
+ * Adjust ip_len to not reflect header,
+ * convert offset of this to bytes.
+ */
+ ip->ip_len = htons(ntohs(ip->ip_len) - hlen);
+ if (ip->ip_off & htons(IP_MF)) {
+ /*
+ * Make sure that fragments have a data length
+ * that's a non-zero multiple of 8 bytes.
+ */
+ if (ip->ip_len == htons(0) || (ntohs(ip->ip_len) & 0x7) != 0) {
+ IPSTAT_INC(ips_toosmall); /* XXX */
+ IPSTAT_INC(ips_fragdropped);
+ m_freem(m);
+ return (NULL);
+ }
+ m->m_flags |= M_IP_FRAG;
+ } else
+ m->m_flags &= ~M_IP_FRAG;
+ ip->ip_off = htons(ntohs(ip->ip_off) << 3);
+
+ /*
+ * Attempt reassembly; if it succeeds, proceed.
+ * ip_reass() will return a different mbuf.
+ */
+ IPSTAT_INC(ips_fragments);
+ m->m_pkthdr.PH_loc.ptr = ip;
+
+ /*
+ * Presence of header sizes in mbufs
+ * would confuse code below.
+ */
+ m->m_data += hlen;
+ m->m_len -= hlen;
+
+ hash = ip->ip_src.s_addr ^ ip->ip_id;
+ hash = jenkins_hash32(&hash, 1, V_ipq_hashseed) & IPREASS_HMASK;
+ head = &V_ipq[hash].head;
+ IPQ_LOCK(hash);
+
+ /*
+ * Look for queue of fragments
+ * of this datagram.
+ */
+ TAILQ_FOREACH(fp, head, ipq_list)
+ if (ip->ip_id == fp->ipq_id &&
+ ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+ ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+#ifdef MAC
+ mac_ipq_match(m, fp) &&
+#endif
+ ip->ip_p == fp->ipq_p)
+ break;
+ /*
+ * If first fragment to arrive, create a reassembly queue.
+ */
+ if (fp == NULL) {
+ fp = uma_zalloc(V_ipq_zone, M_NOWAIT);
+ if (fp == NULL)
+ fp = ipq_reuse(hash);
+#ifdef MAC
+ if (mac_ipq_init(fp, M_NOWAIT) != 0) {
+ uma_zfree(V_ipq_zone, fp);
+ fp = NULL;
+ goto dropfrag;
+ }
+ mac_ipq_create(m, fp);
+#endif
+ TAILQ_INSERT_HEAD(head, fp, ipq_list);
+ fp->ipq_nfrags = 1;
+ fp->ipq_ttl = IPFRAGTTL;
+ fp->ipq_p = ip->ip_p;
+ fp->ipq_id = ip->ip_id;
+ fp->ipq_src = ip->ip_src;
+ fp->ipq_dst = ip->ip_dst;
+ fp->ipq_frags = m;
+ m->m_nextpkt = NULL;
+ goto done;
+ } else {
+ fp->ipq_nfrags++;
+#ifdef MAC
+ mac_ipq_update(m, fp);
+#endif
+ }
+
+#define GETIP(m) ((struct ip*)((m)->m_pkthdr.PH_loc.ptr))
+
+ /*
+ * Handle ECN by comparing this segment with the first one;
+ * if CE is set, do not lose CE.
+ * drop if CE and not-ECT are mixed for the same packet.
+ */
+ ecn = ip->ip_tos & IPTOS_ECN_MASK;
+ ecn0 = GETIP(fp->ipq_frags)->ip_tos & IPTOS_ECN_MASK;
+ if (ecn == IPTOS_ECN_CE) {
+ if (ecn0 == IPTOS_ECN_NOTECT)
+ goto dropfrag;
+ if (ecn0 != IPTOS_ECN_CE)
+ GETIP(fp->ipq_frags)->ip_tos |= IPTOS_ECN_CE;
+ }
+ if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT)
+ goto dropfrag;
+
+ /*
+ * Find a segment which begins after this one does.
+ */
+ for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
+ if (ntohs(GETIP(q)->ip_off) > ntohs(ip->ip_off))
+ break;
+
+ /*
+ * If there is a preceding segment, it may provide some of
+ * our data already. If so, drop the data from the incoming
+ * segment. If it provides all of our data, drop us, otherwise
+ * stick new segment in the proper place.
+ *
+ * If some of the data is dropped from the preceding
+ * segment, then it's checksum is invalidated.
+ */
+ if (p) {
+ i = ntohs(GETIP(p)->ip_off) + ntohs(GETIP(p)->ip_len) -
+ ntohs(ip->ip_off);
+ if (i > 0) {
+ if (i >= ntohs(ip->ip_len))
+ goto dropfrag;
+ m_adj(m, i);
+ m->m_pkthdr.csum_flags = 0;
+ ip->ip_off = htons(ntohs(ip->ip_off) + i);
+ ip->ip_len = htons(ntohs(ip->ip_len) - i);
+ }
+ m->m_nextpkt = p->m_nextpkt;
+ p->m_nextpkt = m;
+ } else {
+ m->m_nextpkt = fp->ipq_frags;
+ fp->ipq_frags = m;
+ }
+
+ /*
+ * While we overlap succeeding segments trim them or,
+ * if they are completely covered, dequeue them.
+ */
+ for (; q != NULL && ntohs(ip->ip_off) + ntohs(ip->ip_len) >
+ ntohs(GETIP(q)->ip_off); q = nq) {
+ i = (ntohs(ip->ip_off) + ntohs(ip->ip_len)) -
+ ntohs(GETIP(q)->ip_off);
+ if (i < ntohs(GETIP(q)->ip_len)) {
+ GETIP(q)->ip_len = htons(ntohs(GETIP(q)->ip_len) - i);
+ GETIP(q)->ip_off = htons(ntohs(GETIP(q)->ip_off) + i);
+ m_adj(q, i);
+ q->m_pkthdr.csum_flags = 0;
+ break;
+ }
+ nq = q->m_nextpkt;
+ m->m_nextpkt = nq;
+ IPSTAT_INC(ips_fragdropped);
+ fp->ipq_nfrags--;
+ m_freem(q);
+ }
+
+ /*
+ * Check for complete reassembly and perform frag per packet
+ * limiting.
+ *
+ * Frag limiting is performed here so that the nth frag has
+ * a chance to complete the packet before we drop the packet.
+ * As a result, n+1 frags are actually allowed per packet, but
+ * only n will ever be stored. (n = maxfragsperpacket.)
+ *
+ */
+ next = 0;
+ for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
+ if (ntohs(GETIP(q)->ip_off) != next) {
+ if (fp->ipq_nfrags > V_maxfragsperpacket)
+ ipq_drop(head, fp);
+ goto done;
+ }
+ next += ntohs(GETIP(q)->ip_len);
+ }
+ /* Make sure the last packet didn't have the IP_MF flag */
+ if (p->m_flags & M_IP_FRAG) {
+ if (fp->ipq_nfrags > V_maxfragsperpacket)
+ ipq_drop(head, fp);
+ goto done;
+ }
+
+ /*
+ * Reassembly is complete. Make sure the packet is a sane size.
+ */
+ q = fp->ipq_frags;
+ ip = GETIP(q);
+ if (next + (ip->ip_hl << 2) > IP_MAXPACKET) {
+ IPSTAT_INC(ips_toolong);
+ ipq_drop(head, fp);
+ goto done;
+ }
+
+ /*
+ * Concatenate fragments.
+ */
+ m = q;
+ t = m->m_next;
+ m->m_next = NULL;
+ m_cat(m, t);
+ nq = q->m_nextpkt;
+ q->m_nextpkt = NULL;
+ for (q = nq; q != NULL; q = nq) {
+ nq = q->m_nextpkt;
+ q->m_nextpkt = NULL;
+ m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
+ m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
+ m_cat(m, q);
+ }
+ /*
+ * In order to do checksumming faster we do 'end-around carry' here
+ * (and not in for{} loop), though it implies we are not going to
+ * reassemble more than 64k fragments.
+ */
+ while (m->m_pkthdr.csum_data & 0xffff0000)
+ m->m_pkthdr.csum_data = (m->m_pkthdr.csum_data & 0xffff) +
+ (m->m_pkthdr.csum_data >> 16);
+#ifdef MAC
+ mac_ipq_reassemble(fp, m);
+ mac_ipq_destroy(fp);
+#endif
+
+ /*
+ * Create header for new ip packet by modifying header of first
+ * packet; dequeue and discard fragment reassembly header.
+ * Make header visible.
+ */
+ ip->ip_len = htons((ip->ip_hl << 2) + next);
+ ip->ip_src = fp->ipq_src;
+ ip->ip_dst = fp->ipq_dst;
+ TAILQ_REMOVE(head, fp, ipq_list);
+ uma_zfree(V_ipq_zone, fp);
+ m->m_len += (ip->ip_hl << 2);
+ m->m_data -= (ip->ip_hl << 2);
+ /* some debugging cruft by sklower, below, will go away soon */
+ if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */
+ m_fixhdr(m);
+ IPSTAT_INC(ips_reassembled);
+ IPQ_UNLOCK(hash);
+
+#ifdef RSS
+ /*
+ * Query the RSS layer for the flowid / flowtype for the
+ * mbuf payload.
+ *
+ * For now, just assume we have to calculate a new one.
+ * Later on we should check to see if the assigned flowid matches
+ * what RSS wants for the given IP protocol and if so, just keep it.
+ *
+ * We then queue into the relevant netisr so it can be dispatched
+ * to the correct CPU.
+ *
+ * Note - this may return 1, which means the flowid in the mbuf
+ * is correct for the configured RSS hash types and can be used.
+ */
+ if (rss_mbuf_software_hash_v4(m, 0, &rss_hash, &rss_type) == 0) {
+ m->m_pkthdr.flowid = rss_hash;
+ M_HASHTYPE_SET(m, rss_type);
+ }
+
+ /*
+ * Queue/dispatch for reprocessing.
+ *
+ * Note: this is much slower than just handling the frame in the
+ * current receive context. It's likely worth investigating
+ * why this is.
+ */
+ netisr_dispatch(NETISR_IP_DIRECT, m);
+ return (NULL);
+#endif
+
+ /* Handle in-line */
+ return (m);
+
+dropfrag:
+ IPSTAT_INC(ips_fragdropped);
+ if (fp != NULL)
+ fp->ipq_nfrags--;
+ m_freem(m);
+done:
+ IPQ_UNLOCK(hash);
+ return (NULL);
+
+#undef GETIP
+}
+
+/*
+ * Initialize IP reassembly structures.
+ */
+void
+ipreass_init(void)
+{
+
+ for (int i = 0; i < IPREASS_NHASH; i++) {
+ TAILQ_INIT(&V_ipq[i].head);
+ mtx_init(&V_ipq[i].lock, "IP reassembly", NULL,
+ MTX_DEF | MTX_DUPOK);
+ }
+ V_ipq_hashseed = arc4random();
+ V_maxfragsperpacket = 16;
+ V_ipq_zone = uma_zcreate("ipq", sizeof(struct ipq), NULL, NULL, NULL,
+ NULL, UMA_ALIGN_PTR, 0);
+ uma_zone_set_max(V_ipq_zone, nmbclusters / 32);
+
+ if (IS_DEFAULT_VNET(curvnet))
+ EVENTHANDLER_REGISTER(nmbclusters_change, ipreass_zone_change,
+ NULL, EVENTHANDLER_PRI_ANY);
+}
+
+/*
+ * If a timer expires on a reassembly queue, discard it.
+ */
+void
+ipreass_slowtimo(void)
+{
+ struct ipq *fp, *tmp;
+
+ for (int i = 0; i < IPREASS_NHASH; i++) {
+ IPQ_LOCK(i);
+ TAILQ_FOREACH_SAFE(fp, &V_ipq[i].head, ipq_list, tmp)
+ if (--fp->ipq_ttl == 0)
+ ipq_timeout(&V_ipq[i].head, fp);
+ IPQ_UNLOCK(i);
+ }
+}
+
+/*
+ * Drain off all datagram fragments.
+ */
+void
+ipreass_drain(void)
+{
+
+ for (int i = 0; i < IPREASS_NHASH; i++) {
+ IPQ_LOCK(i);
+ while(!TAILQ_EMPTY(&V_ipq[i].head))
+ ipq_drop(&V_ipq[i].head, TAILQ_FIRST(&V_ipq[i].head));
+ IPQ_UNLOCK(i);
+ }
+}
+
+#ifdef VIMAGE
+/*
+ * Destroy IP reassembly structures.
+ */
+void
+ipreass_destroy(void)
+{
+
+ ipreass_drain();
+ uma_zdestroy(V_ipq_zone);
+ for (int i = 0; i < IPREASS_NHASH; i++)
+ mtx_destroy(&V_ipq[i].lock);
+}
+#endif
+
+/*
+ * After maxnipq has been updated, propagate the change to UMA. The UMA zone
+ * max has slightly different semantics than the sysctl, for historical
+ * reasons.
+ */
+static void
+ipreass_drain_tomax(void)
+{
+ int target;
+
+ /*
+ * If we are over the maximum number of fragments,
+ * drain off enough to get down to the new limit,
+ * stripping off last elements on queues. Every
+ * run we strip the oldest element from each bucket.
+ */
+ target = uma_zone_get_max(V_ipq_zone);
+ while (uma_zone_get_cur(V_ipq_zone) > target) {
+ struct ipq *fp;
+
+ for (int i = 0; i < IPREASS_NHASH; i++) {
+ IPQ_LOCK(i);
+ fp = TAILQ_LAST(&V_ipq[i].head, ipqhead);
+ if (fp != NULL)
+ ipq_timeout(&V_ipq[i].head, fp);
+ IPQ_UNLOCK(i);
+ }
+ }
+}
+
+static void
+ipreass_zone_change(void *tag)
+{
+
+ uma_zone_set_max(V_ipq_zone, nmbclusters / 32);
+ ipreass_drain_tomax();
+}
+
+/*
+ * Change the limit on the UMA zone, or disable the fragment allocation
+ * at all. Since 0 and -1 is a special values here, we need our own handler,
+ * instead of sysctl_handle_uma_zone_max().
+ */
+static int
+sysctl_maxfragpackets(SYSCTL_HANDLER_ARGS)
+{
+ int error, max;
+
+ if (V_noreass == 0) {
+ max = uma_zone_get_max(V_ipq_zone);
+ if (max == 0)
+ max = -1;
+ } else
+ max = 0;
+ error = sysctl_handle_int(oidp, &max, 0, req);
+ if (error || !req->newptr)
+ return (error);
+ if (max > 0) {
+ /*
+ * XXXRW: Might be a good idea to sanity check the argument
+ * and place an extreme upper bound.
+ */
+ max = uma_zone_set_max(V_ipq_zone, max);
+ ipreass_drain_tomax();
+ V_noreass = 0;
+ } else if (max == 0) {
+ V_noreass = 1;
+ ipreass_drain();
+ } else if (max == -1) {
+ V_noreass = 0;
+ uma_zone_set_max(V_ipq_zone, 0);
+ } else
+ return (EINVAL);
+ return (0);
+}
+
+/*
+ * Seek for old fragment queue header that can be reused. Try to
+ * reuse a header from currently locked hash bucket.
+ */
+static struct ipq *
+ipq_reuse(int start)
+{
+ struct ipq *fp;
+ int i;
+
+ IPQ_LOCK_ASSERT(start);
+
+ for (i = start;; i++) {
+ if (i == IPREASS_NHASH)
+ i = 0;
+ if (i != start && IPQ_TRYLOCK(i) == 0)
+ continue;
+ fp = TAILQ_LAST(&V_ipq[i].head, ipqhead);
+ if (fp) {
+ struct mbuf *m;
+
+ IPSTAT_ADD(ips_fragtimeout, fp->ipq_nfrags);
+ while (fp->ipq_frags) {
+ m = fp->ipq_frags;
+ fp->ipq_frags = m->m_nextpkt;
+ m_freem(m);
+ }
+ TAILQ_REMOVE(&V_ipq[i].head, fp, ipq_list);
+ if (i != start)
+ IPQ_UNLOCK(i);
+ IPQ_LOCK_ASSERT(start);
+ return (fp);
+ }
+ if (i != start)
+ IPQ_UNLOCK(i);
+ }
+}
+
+/*
+ * Free a fragment reassembly header and all associated datagrams.
+ */
+static void
+ipq_free(struct ipqhead *fhp, struct ipq *fp)
+{
+ struct mbuf *q;
+
+ while (fp->ipq_frags) {
+ q = fp->ipq_frags;
+ fp->ipq_frags = q->m_nextpkt;
+ m_freem(q);
+ }
+ TAILQ_REMOVE(fhp, fp, ipq_list);
+ uma_zfree(V_ipq_zone, fp);
+}
diff --git a/sys/netinet/libalias/libalias.3 b/sys/netinet/libalias/libalias.3
index 45e7fa4..543420b 100644
--- a/sys/netinet/libalias/libalias.3
+++ b/sys/netinet/libalias/libalias.3
@@ -173,10 +173,12 @@ Mainly useful for debugging when the log file is viewed continuously with
.It Dv PKT_ALIAS_DENY_INCOMING
If this mode bit is set, all incoming packets associated with new TCP
connections or new UDP transactions will be marked for being ignored
-.Fn ( LibAliasIn
+.Po
+.Fn LibAliasIn
returns
.Dv PKT_ALIAS_IGNORED
-code)
+code
+.Pc
by the calling program.
Response packets to connections or transactions initiated from the packet
aliasing host or local network will be unaffected.
@@ -1001,7 +1003,7 @@ If this results in a conflict, then port numbers are randomly chosen until
a unique aliasing link can be established.
In an alternate operating mode, the first choice of an aliasing port is also
random and unrelated to the local port number.
-.Sh MODULAR ARCHITECTURE (AND Xr ipfw 4 Sh SUPPORT)
+.Sh MODULAR ARCHITECTURE Po AND Xr ipfw 4 SUPPORT Pc
One of the latest improvements to
.Nm
was to make its support
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index ea3d3e7..d3b4855 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -3614,24 +3614,17 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
send_s = asoc->sending_seq;
}
if (SCTP_TSN_GE(cumack, send_s)) {
-#ifndef INVARIANTS
struct mbuf *op_err;
char msg[SCTP_DIAG_INFO_LEN];
-#endif
-#ifdef INVARIANTS
- panic("Impossible sack 1");
-#else
-
*abort_now = 1;
/* XXX */
- snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal then TSN %8.8x",
+ snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x",
cumack, send_s);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
return;
-#endif
}
}
asoc->this_sack_highest_gap = cumack;
@@ -4195,7 +4188,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
hopeless_peer:
*abort_now = 1;
/* XXX */
- snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal then TSN %8.8x",
+ snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x",
cum_ack, send_s);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
diff --git a/sys/netinet/sctp_syscalls.c b/sys/netinet/sctp_syscalls.c
index 3161abc..28b4445 100644
--- a/sys/netinet/sctp_syscalls.c
+++ b/sys/netinet/sctp_syscalls.c
@@ -187,7 +187,7 @@ noconnection:
* out from under us.
*/
if (error != 0)
- fdclose(td->td_proc->p_fd, nfp, fd, td);
+ fdclose(td, nfp, fd);
/*
* Release explicitly held references before returning.
@@ -248,7 +248,7 @@ sys_sctp_generic_sendmsg (td, uap)
}
AUDIT_ARG_FD(uap->sd);
- error = getsock_cap(td->td_proc->p_fd, uap->sd, &rights, &fp, NULL);
+ error = getsock_cap(td, uap->sd, &rights, &fp, NULL);
if (error != 0)
goto sctp_bad;
#ifdef KTRACE
@@ -357,7 +357,7 @@ sys_sctp_generic_sendmsg_iov(td, uap)
}
AUDIT_ARG_FD(uap->sd);
- error = getsock_cap(td->td_proc->p_fd, uap->sd, &rights, &fp, NULL);
+ error = getsock_cap(td, uap->sd, &rights, &fp, NULL);
if (error != 0)
goto sctp_bad1;
@@ -468,8 +468,8 @@ sys_sctp_generic_recvmsg(td, uap)
int error, fromlen, i, msg_flags;
AUDIT_ARG_FD(uap->sd);
- error = getsock_cap(td->td_proc->p_fd, uap->sd,
- cap_rights_init(&rights, CAP_RECV), &fp, NULL);
+ error = getsock_cap(td, uap->sd, cap_rights_init(&rights, CAP_RECV),
+ &fp, NULL);
if (error != 0)
return (error);
#ifdef COMPAT_FREEBSD32
diff --git a/sys/netinet/siftr.c b/sys/netinet/siftr.c
index 2cd58ad..6b31d7b 100644
--- a/sys/netinet/siftr.c
+++ b/sys/netinet/siftr.c
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/sbuf.h>
+#include <sys/sdt.h>
#include <sys/smp.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@@ -86,6 +87,7 @@ __FBSDID("$FreeBSD$");
#include <net/pfil.h>
#include <netinet/in.h>
+#include <netinet/in_kdtrace.h>
#include <netinet/in_pcb.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
@@ -811,6 +813,8 @@ siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp,
* maximum pps throughput processing when SIFTR is loaded and enabled.
*/
microtime(&pn->tval);
+ TCP_PROBE1(siftr, &pn);
+
}
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 5b845f0..d75221c 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -230,6 +230,7 @@ static struct inpcb *tcp_notify(struct inpcb *, int);
static struct inpcb *tcp_mtudisc_notify(struct inpcb *, int);
static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th,
void *ip4hdr, const void *ip6hdr);
+static void tcp_timer_discard(struct tcpcb *, uint32_t);
/*
* Target size of TCP PCB hash tables. Must be a power of two.
@@ -801,7 +802,13 @@ tcp_newtcpcb(struct inpcb *inp)
if (V_tcp_do_sack)
tp->t_flags |= TF_SACK_PERMIT;
TAILQ_INIT(&tp->snd_holes);
- tp->t_inpcb = inp; /* XXX */
+ /*
+ * The tcpcb will hold a reference on its inpcb until tcp_discardcb()
+ * is called.
+ */
+ in_pcbref(inp); /* Reference for tcpcb */
+ tp->t_inpcb = inp;
+
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
* rtt estimate. Set rttvar so that srtt + 4 * rttvar gives
@@ -920,6 +927,7 @@ tcp_discardcb(struct tcpcb *tp)
#ifdef INET6
int isipv6 = (inp->inp_vflag & INP_IPV6) != 0;
#endif /* INET6 */
+ int released;
INP_WLOCK_ASSERT(inp);
@@ -927,22 +935,15 @@ tcp_discardcb(struct tcpcb *tp)
* Make sure that all of our timers are stopped before we delete the
* PCB.
*
- * XXXRW: Really, we would like to use callout_drain() here in order
- * to avoid races experienced in tcp_timer.c where a timer is already
- * executing at this point. However, we can't, both because we're
- * running in a context where we can't sleep, and also because we
- * hold locks required by the timers. What we instead need to do is
- * test to see if callout_drain() is required, and if so, defer some
- * portion of the remainder of tcp_discardcb() to an asynchronous
- * context that can callout_drain() and then continue. Some care
- * will be required to ensure that no further processing takes place
- * on the tcpcb, even though it hasn't been freed (a flag?).
+ * If stopping a timer fails, we schedule a discard function in same
+ * callout, and the last discard function called will take care of
+ * deleting the tcpcb.
*/
- callout_stop(&tp->t_timers->tt_rexmt);
- callout_stop(&tp->t_timers->tt_persist);
- callout_stop(&tp->t_timers->tt_keep);
- callout_stop(&tp->t_timers->tt_2msl);
- callout_stop(&tp->t_timers->tt_delack);
+ tcp_timer_stop(tp, TT_REXMT);
+ tcp_timer_stop(tp, TT_PERSIST);
+ tcp_timer_stop(tp, TT_KEEP);
+ tcp_timer_stop(tp, TT_2MSL);
+ tcp_timer_stop(tp, TT_DELACK);
/*
* If we got enough samples through the srtt filter,
@@ -1019,8 +1020,80 @@ tcp_discardcb(struct tcpcb *tp)
CC_ALGO(tp) = NULL;
inp->inp_ppcb = NULL;
- tp->t_inpcb = NULL;
- uma_zfree(V_tcpcb_zone, tp);
+ if ((tp->t_timers->tt_flags & TT_MASK) == 0) {
+ /* We own the last reference on tcpcb, let's free it. */
+ tp->t_inpcb = NULL;
+ uma_zfree(V_tcpcb_zone, tp);
+ released = in_pcbrele_wlocked(inp);
+ KASSERT(!released, ("%s: inp %p should not have been released "
+ "here", __func__, inp));
+ }
+}
+
+void
+tcp_timer_2msl_discard(void *xtp)
+{
+
+ tcp_timer_discard((struct tcpcb *)xtp, TT_2MSL);
+}
+
+void
+tcp_timer_keep_discard(void *xtp)
+{
+
+ tcp_timer_discard((struct tcpcb *)xtp, TT_KEEP);
+}
+
+void
+tcp_timer_persist_discard(void *xtp)
+{
+
+ tcp_timer_discard((struct tcpcb *)xtp, TT_PERSIST);
+}
+
+void
+tcp_timer_rexmt_discard(void *xtp)
+{
+
+ tcp_timer_discard((struct tcpcb *)xtp, TT_REXMT);
+}
+
+void
+tcp_timer_delack_discard(void *xtp)
+{
+
+ tcp_timer_discard((struct tcpcb *)xtp, TT_DELACK);
+}
+
+void
+tcp_timer_discard(struct tcpcb *tp, uint32_t timer_type)
+{
+ struct inpcb *inp;
+
+ CURVNET_SET(tp->t_vnet);
+ INP_INFO_WLOCK(&V_tcbinfo);
+ inp = tp->t_inpcb;
+ KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL",
+ __func__, tp));
+ INP_WLOCK(inp);
+ KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0,
+ ("%s: tcpcb has to be stopped here", __func__));
+ KASSERT((tp->t_timers->tt_flags & timer_type) != 0,
+ ("%s: discard callout should be running", __func__));
+ tp->t_timers->tt_flags &= ~timer_type;
+ if ((tp->t_timers->tt_flags & TT_MASK) == 0) {
+ /* We own the last reference on this tcpcb, let's free it. */
+ tp->t_inpcb = NULL;
+ uma_zfree(V_tcpcb_zone, tp);
+ if (in_pcbrele_wlocked(inp)) {
+ INP_INFO_WUNLOCK(&V_tcbinfo);
+ CURVNET_RESTORE();
+ return;
+ }
+ }
+ INP_WUNLOCK(inp);
+ INP_INFO_WUNLOCK(&V_tcbinfo);
+ CURVNET_RESTORE();
}
/*
@@ -2086,6 +2159,7 @@ tcp_signature_do_compute(struct mbuf *m, int len, int optlen,
break;
#endif
default:
+ KEY_FREESAV(&sav);
return (-1);
/* NOTREACHED */
break;
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index e6007e0..a64e403 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -258,10 +258,6 @@ int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
static int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */
-static int tcp_timer_race;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, timer_race, CTLFLAG_RD, &tcp_timer_race,
- 0, "Count of t_inpcb races on tcp_discardcb");
-
/*
* TCP timer processing.
*/
@@ -274,18 +270,7 @@ tcp_timer_delack(void *xtp)
CURVNET_SET(tp->t_vnet);
inp = tp->t_inpcb;
- /*
- * XXXRW: While this assert is in fact correct, bugs in the tcpcb
- * tear-down mean we need it as a work-around for races between
- * timers and tcp_discardcb().
- *
- * KASSERT(inp != NULL, ("tcp_timer_delack: inp == NULL"));
- */
- if (inp == NULL) {
- tcp_timer_race++;
- CURVNET_RESTORE();
- return;
- }
+ KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp));
INP_WLOCK(inp);
if (callout_pending(&tp->t_timers->tt_delack) ||
!callout_active(&tp->t_timers->tt_delack)) {
@@ -299,6 +284,10 @@ tcp_timer_delack(void *xtp)
CURVNET_RESTORE();
return;
}
+ KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0,
+ ("%s: tp %p tcpcb can't be stopped here", __func__, tp));
+ KASSERT((tp->t_timers->tt_flags & TT_DELACK) != 0,
+ ("%s: tp %p delack callout should be running", __func__, tp));
tp->t_flags |= TF_ACKNOW;
TCPSTAT_INC(tcps_delack);
@@ -318,24 +307,9 @@ tcp_timer_2msl(void *xtp)
ostate = tp->t_state;
#endif
- /*
- * XXXRW: Does this actually happen?
- */
INP_INFO_WLOCK(&V_tcbinfo);
inp = tp->t_inpcb;
- /*
- * XXXRW: While this assert is in fact correct, bugs in the tcpcb
- * tear-down mean we need it as a work-around for races between
- * timers and tcp_discardcb().
- *
- * KASSERT(inp != NULL, ("tcp_timer_2msl: inp == NULL"));
- */
- if (inp == NULL) {
- tcp_timer_race++;
- INP_INFO_WUNLOCK(&V_tcbinfo);
- CURVNET_RESTORE();
- return;
- }
+ KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp));
INP_WLOCK(inp);
tcp_free_sackholes(tp);
if (callout_pending(&tp->t_timers->tt_2msl) ||
@@ -352,6 +326,10 @@ tcp_timer_2msl(void *xtp)
CURVNET_RESTORE();
return;
}
+ KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0,
+ ("%s: tp %p tcpcb can't be stopped here", __func__, tp));
+ KASSERT((tp->t_timers->tt_flags & TT_2MSL) != 0,
+ ("%s: tp %p 2msl callout should be running", __func__, tp));
/*
* 2 MSL timeout in shutdown went off. If we're closed but
* still waiting for peer to close and connection has been idle
@@ -402,19 +380,7 @@ tcp_timer_keep(void *xtp)
#endif
INP_INFO_WLOCK(&V_tcbinfo);
inp = tp->t_inpcb;
- /*
- * XXXRW: While this assert is in fact correct, bugs in the tcpcb
- * tear-down mean we need it as a work-around for races between
- * timers and tcp_discardcb().
- *
- * KASSERT(inp != NULL, ("tcp_timer_keep: inp == NULL"));
- */
- if (inp == NULL) {
- tcp_timer_race++;
- INP_INFO_WUNLOCK(&V_tcbinfo);
- CURVNET_RESTORE();
- return;
- }
+ KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp));
INP_WLOCK(inp);
if (callout_pending(&tp->t_timers->tt_keep) ||
!callout_active(&tp->t_timers->tt_keep)) {
@@ -430,6 +396,10 @@ tcp_timer_keep(void *xtp)
CURVNET_RESTORE();
return;
}
+ KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0,
+ ("%s: tp %p tcpcb can't be stopped here", __func__, tp));
+ KASSERT((tp->t_timers->tt_flags & TT_KEEP) != 0,
+ ("%s: tp %p keep callout should be running", __func__, tp));
/*
* Keep-alive timer went off; send something
* or drop connection if idle for too long.
@@ -505,19 +475,7 @@ tcp_timer_persist(void *xtp)
#endif
INP_INFO_WLOCK(&V_tcbinfo);
inp = tp->t_inpcb;
- /*
- * XXXRW: While this assert is in fact correct, bugs in the tcpcb
- * tear-down mean we need it as a work-around for races between
- * timers and tcp_discardcb().
- *
- * KASSERT(inp != NULL, ("tcp_timer_persist: inp == NULL"));
- */
- if (inp == NULL) {
- tcp_timer_race++;
- INP_INFO_WUNLOCK(&V_tcbinfo);
- CURVNET_RESTORE();
- return;
- }
+ KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp));
INP_WLOCK(inp);
if (callout_pending(&tp->t_timers->tt_persist) ||
!callout_active(&tp->t_timers->tt_persist)) {
@@ -533,6 +491,10 @@ tcp_timer_persist(void *xtp)
CURVNET_RESTORE();
return;
}
+ KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0,
+ ("%s: tp %p tcpcb can't be stopped here", __func__, tp));
+ KASSERT((tp->t_timers->tt_flags & TT_PERSIST) != 0,
+ ("%s: tp %p persist callout should be running", __func__, tp));
/*
* Persistance timer into zero window.
* Force a byte to be output, if possible.
@@ -594,19 +556,7 @@ tcp_timer_rexmt(void * xtp)
INP_INFO_RLOCK(&V_tcbinfo);
inp = tp->t_inpcb;
- /*
- * XXXRW: While this assert is in fact correct, bugs in the tcpcb
- * tear-down mean we need it as a work-around for races between
- * timers and tcp_discardcb().
- *
- * KASSERT(inp != NULL, ("tcp_timer_rexmt: inp == NULL"));
- */
- if (inp == NULL) {
- tcp_timer_race++;
- INP_INFO_RUNLOCK(&V_tcbinfo);
- CURVNET_RESTORE();
- return;
- }
+ KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp));
INP_WLOCK(inp);
if (callout_pending(&tp->t_timers->tt_rexmt) ||
!callout_active(&tp->t_timers->tt_rexmt)) {
@@ -622,6 +572,10 @@ tcp_timer_rexmt(void * xtp)
CURVNET_RESTORE();
return;
}
+ KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0,
+ ("%s: tp %p tcpcb can't be stopped here", __func__, tp));
+ KASSERT((tp->t_timers->tt_flags & TT_REXMT) != 0,
+ ("%s: tp %p rexmt callout should be running", __func__, tp));
tcp_free_sackholes(tp);
/*
* Retransmission timer went off. Message has not
@@ -850,7 +804,7 @@ out:
}
void
-tcp_timer_activate(struct tcpcb *tp, int timer_type, u_int delta)
+tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta)
{
struct callout *t_callout;
timeout_t *f_callout;
@@ -862,6 +816,9 @@ tcp_timer_activate(struct tcpcb *tp, int timer_type, u_int delta)
return;
#endif
+ if (tp->t_timers->tt_flags & TT_STOPPED)
+ return;
+
switch (timer_type) {
case TT_DELACK:
t_callout = &tp->t_timers->tt_delack;
@@ -887,14 +844,23 @@ tcp_timer_activate(struct tcpcb *tp, int timer_type, u_int delta)
panic("tp %p bad timer_type %#x", tp, timer_type);
}
if (delta == 0) {
- callout_stop(t_callout);
+ if ((tp->t_timers->tt_flags & timer_type) &&
+ callout_stop(t_callout)) {
+ tp->t_timers->tt_flags &= ~timer_type;
+ }
} else {
- callout_reset_on(t_callout, delta, f_callout, tp, cpu);
+ if ((tp->t_timers->tt_flags & timer_type) == 0) {
+ tp->t_timers->tt_flags |= timer_type;
+ callout_reset_on(t_callout, delta, f_callout, tp, cpu);
+ } else {
+ /* Reset already running callout on the same CPU. */
+ callout_reset(t_callout, delta, f_callout, tp);
+ }
}
}
int
-tcp_timer_active(struct tcpcb *tp, int timer_type)
+tcp_timer_active(struct tcpcb *tp, uint32_t timer_type)
{
struct callout *t_callout;
@@ -920,6 +886,58 @@ tcp_timer_active(struct tcpcb *tp, int timer_type)
return callout_active(t_callout);
}
+void
+tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type)
+{
+ struct callout *t_callout;
+ timeout_t *f_callout;
+
+ tp->t_timers->tt_flags |= TT_STOPPED;
+
+ switch (timer_type) {
+ case TT_DELACK:
+ t_callout = &tp->t_timers->tt_delack;
+ f_callout = tcp_timer_delack_discard;
+ break;
+ case TT_REXMT:
+ t_callout = &tp->t_timers->tt_rexmt;
+ f_callout = tcp_timer_rexmt_discard;
+ break;
+ case TT_PERSIST:
+ t_callout = &tp->t_timers->tt_persist;
+ f_callout = tcp_timer_persist_discard;
+ break;
+ case TT_KEEP:
+ t_callout = &tp->t_timers->tt_keep;
+ f_callout = tcp_timer_keep_discard;
+ break;
+ case TT_2MSL:
+ t_callout = &tp->t_timers->tt_2msl;
+ f_callout = tcp_timer_2msl_discard;
+ break;
+ default:
+ panic("tp %p bad timer_type %#x", tp, timer_type);
+ }
+
+ if (tp->t_timers->tt_flags & timer_type) {
+ if (callout_stop(t_callout)) {
+ tp->t_timers->tt_flags &= ~timer_type;
+ } else {
+ /*
+ * Can't stop the callout, defer tcpcb actual deletion
+ * to the last tcp timer discard callout.
+ * The TT_STOPPED flag will ensure that no tcp timer
+ * callouts can be restarted on our behalf, and
+ * past this point currently running callouts waiting
+ * on inp lock will return right away after the
+ * classical check for callout reset/stop events:
+ * callout_pending() || !callout_active()
+ */
+ callout_reset(t_callout, 1, f_callout, tp);
+ }
+ }
+}
+
#define ticks_to_msecs(t) (1000*(t) / hz)
void
diff --git a/sys/netinet/tcp_timer.h b/sys/netinet/tcp_timer.h
index f80e744..02a7782 100644
--- a/sys/netinet/tcp_timer.h
+++ b/sys/netinet/tcp_timer.h
@@ -146,12 +146,21 @@ struct tcp_timer {
struct callout tt_keep; /* keepalive */
struct callout tt_2msl; /* 2*msl TIME_WAIT timer */
struct callout tt_delack; /* delayed ACK timer */
+ uint32_t tt_flags; /* Timers flags */
+ uint32_t tt_spare; /* TDB */
};
-#define TT_DELACK 0x01
-#define TT_REXMT 0x02
-#define TT_PERSIST 0x04
-#define TT_KEEP 0x08
-#define TT_2MSL 0x10
+
+/*
+ * Flags for the tt_flags field.
+ */
+#define TT_DELACK 0x0001
+#define TT_REXMT 0x0002
+#define TT_PERSIST 0x0004
+#define TT_KEEP 0x0008
+#define TT_2MSL 0x0010
+#define TT_MASK (TT_DELACK|TT_REXMT|TT_PERSIST|TT_KEEP|TT_2MSL)
+
+#define TT_STOPPED 0x00010000
#define TP_KEEPINIT(tp) ((tp)->t_keepinit ? (tp)->t_keepinit : tcp_keepinit)
#define TP_KEEPIDLE(tp) ((tp)->t_keepidle ? (tp)->t_keepidle : tcp_keepidle)
@@ -183,6 +192,11 @@ void tcp_timer_keep(void *xtp);
void tcp_timer_persist(void *xtp);
void tcp_timer_rexmt(void *xtp);
void tcp_timer_delack(void *xtp);
+void tcp_timer_2msl_discard(void *xtp);
+void tcp_timer_keep_discard(void *xtp);
+void tcp_timer_persist_discard(void *xtp);
+void tcp_timer_rexmt_discard(void *xtp);
+void tcp_timer_delack_discard(void *xtp);
void tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer,
struct xtcp_timer *xtimer);
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index da48615..1ba74d8 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -251,6 +251,13 @@ tcp_twstart(struct tcpcb *tp)
}
}
+
+ /*
+ * For use only by DTrace. We do not reference the state
+ * after this point so modifying it in place is not a problem.
+ */
+ tcp_state_change(tp, TCPS_TIME_WAIT);
+
tw = uma_zalloc(V_tcptw_zone, M_NOWAIT);
if (tw == NULL) {
/*
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 0bf5be4..df01735 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -708,8 +708,9 @@ void tcp_slowtimo(void);
struct tcptemp *
tcpip_maketemplate(struct inpcb *);
void tcpip_fillheaders(struct inpcb *, void *, void *);
-void tcp_timer_activate(struct tcpcb *, int, u_int);
-int tcp_timer_active(struct tcpcb *, int);
+void tcp_timer_activate(struct tcpcb *, uint32_t, u_int);
+int tcp_timer_active(struct tcpcb *, uint32_t);
+void tcp_timer_stop(struct tcpcb *, uint32_t);
void tcp_trace(short, short, struct tcpcb *, void *, struct tcphdr *, int);
/*
* All tcp_hc_* functions are IPv4 and IPv6 (via in_conninfo)
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index ae68f26..d2570c4 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1684,6 +1684,36 @@ in6_localip(struct in6_addr *in6)
IN6_IFADDR_RUNLOCK();
return (0);
}
+
+/*
+ * Return 1 if an internet address is configured on an interface.
+ */
+int
+in6_ifhasaddr(struct ifnet *ifp, struct in6_addr *addr)
+{
+ struct in6_addr in6;
+ struct ifaddr *ifa;
+ struct in6_ifaddr *ia6;
+
+ in6 = *addr;
+ if (in6_clearscope(&in6))
+ return (0);
+ in6_setscope(&in6, ifp, NULL);
+
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ia6 = (struct in6_ifaddr *)ifa;
+ if (IN6_ARE_ADDR_EQUAL(&ia6->ia_addr.sin6_addr, &in6)) {
+ IF_ADDR_RUNLOCK(ifp);
+ return (1);
+ }
+ }
+ IF_ADDR_RUNLOCK(ifp);
+
+ return (0);
+}
int
in6_is_addr_deprecated(struct sockaddr_in6 *sa6)
@@ -1967,18 +1997,9 @@ in6_if2idlen(struct ifnet *ifp)
{
switch (ifp->if_type) {
case IFT_ETHER: /* RFC2464 */
-#ifdef IFT_PROPVIRTUAL
case IFT_PROPVIRTUAL: /* XXX: no RFC. treat it as ether */
-#endif
-#ifdef IFT_L2VLAN
case IFT_L2VLAN: /* ditto */
-#endif
-#ifdef IFT_IEEE80211
case IFT_IEEE80211: /* ditto */
-#endif
-#ifdef IFT_MIP
- case IFT_MIP: /* ditto */
-#endif
case IFT_INFINIBAND:
return (64);
case IFT_FDDI: /* RFC2467 */
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 1a33527..50ca387 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -650,6 +650,7 @@ int in6_cksum_partial(struct mbuf *, u_int8_t, u_int32_t, u_int32_t,
u_int32_t);
int in6_localaddr(struct in6_addr *);
int in6_localip(struct in6_addr *);
+int in6_ifhasaddr(struct ifnet *, struct in6_addr *);
int in6_addrscope(const struct in6_addr *);
char *ip6_sprintf(char *, const struct in6_addr *);
struct in6_ifaddr *in6_ifawithifp(struct ifnet *, struct in6_addr *);
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 06d931b..8c25e98 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -274,9 +274,7 @@ found:
case IFT_ISO88025:
case IFT_ATM:
case IFT_IEEE1394:
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
/* IEEE802/EUI64 cases - what others? */
/* IEEE1394 uses 16byte length address starting with EUI64 */
if (addrlen > 8)
@@ -338,9 +336,7 @@ found:
break;
case IFT_GIF:
-#ifdef IFT_STF
case IFT_STF:
-#endif
/*
* RFC2893 says: "SHOULD use IPv4 address as ifid source".
* however, IPv4 address is not very suitable as unique
diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c
index d872b87..4bc66e6 100644
--- a/sys/netinet6/in6_mcast.c
+++ b/sys/netinet6/in6_mcast.c
@@ -2348,11 +2348,15 @@ in6p_set_multicast_if(struct inpcb *inp, struct sockopt *sopt)
return (error);
if (V_if_index < ifindex)
return (EINVAL);
-
- ifp = ifnet_byindex(ifindex);
- if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
- return (EADDRNOTAVAIL);
-
+ if (ifindex == 0)
+ ifp = NULL;
+ else {
+ ifp = ifnet_byindex(ifindex);
+ if (ifp == NULL)
+ return (EINVAL);
+ if ((ifp->if_flags & IFF_MULTICAST) == 0)
+ return (EADDRNOTAVAIL);
+ }
imo = in6p_findmoptions(inp);
imo->im6o_multicast_ifp = ifp;
INP_WUNLOCK(inp);
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index d66b674..83e58c1 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -248,8 +248,7 @@ ip6_forward(struct mbuf *m, int srcrt)
/*
* when the kernel forwards a packet, it is not proper to apply
- * IPsec transport mode to the packet is not proper. this check
- * avoid from this.
+ * IPsec transport mode to the packet. This check avoid from this.
* at present, if there is even a transport mode SA request in the
* security policy, the kernel does not apply IPsec to the packet.
* this check is not enough because the following case is valid.
@@ -283,9 +282,9 @@ ip6_forward(struct mbuf *m, int srcrt)
* ipsec6_proces_packet will send the packet using ip6_output
*/
error = ipsec6_process_packet(m, sp->req);
-
- KEY_FREESP(&sp);
-
+ /* Release SP if an error occured */
+ if (error != 0)
+ KEY_FREESP(&sp);
if (error == EJUSTRETURN) {
/*
* We had a SP with a level of 'use' and no SA. We
@@ -413,39 +412,6 @@ again2:
goto bad;
}
- if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
- in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
- if (mcopy) {
- u_long mtu;
-#ifdef IPSEC
- size_t ipsechdrsiz;
-#endif /* IPSEC */
-
- mtu = IN6_LINKMTU(rt->rt_ifp);
-#ifdef IPSEC
- /*
- * When we do IPsec tunnel ingress, we need to play
- * with the link value (decrement IPsec header size
- * from mtu value). The code is much simpler than v4
- * case, as we have the outgoing interface for
- * encapsulated packet as "rt->rt_ifp".
- */
- ipsechdrsiz = ipsec_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND,
- NULL);
- if (ipsechdrsiz < mtu)
- mtu -= ipsechdrsiz;
- /*
- * if mtu becomes less than minimum MTU,
- * tell minimum MTU (and I'll need to fragment it).
- */
- if (mtu < IPV6_MMTU)
- mtu = IPV6_MMTU;
-#endif /* IPSEC */
- icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
- }
- goto bad;
- }
-
if (rt->rt_flags & RTF_GATEWAY)
dst = (struct sockaddr_in6 *)rt->rt_gateway;
@@ -537,22 +503,9 @@ again2:
if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {
m->m_flags |= M_SKIP_FIREWALL;
/* If destination is now ourself drop to ip6_input(). */
- if (in6_localip(&ip6->ip6_dst)) {
+ if (in6_localip(&ip6->ip6_dst))
m->m_flags |= M_FASTFWD_OURS;
- if (m->m_pkthdr.rcvif == NULL)
- m->m_pkthdr.rcvif = V_loif;
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
- m->m_pkthdr.csum_flags |=
- CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
- m->m_pkthdr.csum_data = 0xffff;
- }
-#ifdef SCTP
- if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
- m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
-#endif
- error = netisr_queue(NETISR_IPV6, m);
- goto out;
- } else
+ else
goto again; /* Redo the routing table lookup. */
}
@@ -584,6 +537,40 @@ again2:
}
pass:
+ /* See if the size was changed by the packet filter. */
+ if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
+ in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
+ if (mcopy) {
+ u_long mtu;
+#ifdef IPSEC
+ size_t ipsechdrsiz;
+#endif /* IPSEC */
+
+ mtu = IN6_LINKMTU(rt->rt_ifp);
+#ifdef IPSEC
+ /*
+ * When we do IPsec tunnel ingress, we need to play
+ * with the link value (decrement IPsec header size
+ * from mtu value). The code is much simpler than v4
+ * case, as we have the outgoing interface for
+ * encapsulated packet as "rt->rt_ifp".
+ */
+ ipsechdrsiz = ipsec_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND,
+ NULL);
+ if (ipsechdrsiz < mtu)
+ mtu -= ipsechdrsiz;
+ /*
+ * if mtu becomes less than minimum MTU,
+ * tell minimum MTU (and I'll need to fragment it).
+ */
+ if (mtu < IPV6_MMTU)
+ mtu = IPV6_MMTU;
+#endif /* IPSEC */
+ icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
+ }
+ goto bad;
+ }
+
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
diff --git a/sys/netinet6/ip6_ipsec.c b/sys/netinet6/ip6_ipsec.c
index 0a416cd..e6e16ed 100644
--- a/sys/netinet6/ip6_ipsec.c
+++ b/sys/netinet6/ip6_ipsec.c
@@ -213,7 +213,9 @@ ip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error)
/* NB: callee frees mbuf */
*error = ipsec6_process_packet(*m, sp->req);
-
+ /* Release SP if an error occured */
+ if (*error != 0)
+ KEY_FREESP(&sp);
if (*error == EJUSTRETURN) {
/*
* We had a SP with a level of 'use' and no SA. We
@@ -249,13 +251,9 @@ ip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error)
/* No IPsec processing for this packet. */
}
done:
- if (sp != NULL)
- KEY_FREESP(&sp);
- return 0;
+ return (0);
reinjected:
- if (sp != NULL)
- KEY_FREESP(&sp);
- return -1;
+ return (-1);
bad:
if (sp != NULL)
KEY_FREESP(&sp);
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index 3976b08..a2f9a7c 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -196,9 +196,34 @@ static struct mtx mfc6_mtx;
static u_char n6expire[MF6CTBLSIZ];
static struct mif6 mif6table[MAXMIFS];
-SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mif6table, CTLFLAG_RD,
- &mif6table, sizeof(mif6table), "S,mif6[MAXMIFS]",
- "IPv6 Multicast Interfaces (struct mif6[MAXMIFS], netinet6/ip6_mroute.h)");
+static int
+sysctl_mif6table(SYSCTL_HANDLER_ARGS)
+{
+ struct mif6_sctl *out;
+ int error;
+
+ out = malloc(sizeof(struct mif6_sctl) * MAXMIFS, M_TEMP, M_WAITOK);
+ for (int i = 0; i < MAXMIFS; i++) {
+ out[i].m6_flags = mif6table[i].m6_flags;
+ out[i].m6_rate_limit = mif6table[i].m6_rate_limit;
+ out[i].m6_lcl_addr = mif6table[i].m6_lcl_addr;
+ if (mif6table[i].m6_ifp != NULL)
+ out[i].m6_ifp = mif6table[i].m6_ifp->if_index;
+ else
+ out[i].m6_ifp = 0;
+ out[i].m6_pkt_in = mif6table[i].m6_pkt_in;
+ out[i].m6_pkt_out = mif6table[i].m6_pkt_out;
+ out[i].m6_bytes_in = mif6table[i].m6_bytes_in;
+ out[i].m6_bytes_out = mif6table[i].m6_bytes_out;
+ }
+ error = SYSCTL_OUT(req, out, sizeof(struct mif6_sctl) * MAXMIFS);
+ free(out, M_TEMP);
+ return (error);
+}
+SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, mif6table, CTLTYPE_OPAQUE | CTLFLAG_RD,
+ NULL, 0, sysctl_mif6table, "S,mif6_sctl[MAXMIFS]",
+ "IPv6 Multicast Interfaces (struct mif6_sctl[MAXMIFS], "
+ "netinet6/ip6_mroute.h)");
static struct mtx mif6_mtx;
#define MIF6_LOCK() mtx_lock(&mif6_mtx)
diff --git a/sys/netinet6/ip6_mroute.h b/sys/netinet6/ip6_mroute.h
index d7b0014..51e1d49 100644
--- a/sys/netinet6/ip6_mroute.h
+++ b/sys/netinet6/ip6_mroute.h
@@ -194,6 +194,20 @@ struct sioc_mif_req6 {
u_quad_t obytes; /* Output byte count on mif */
};
+/*
+ * Structure to export 'struct mif6' to userland via sysctl.
+ */
+struct mif6_sctl {
+ u_char m6_flags; /* MIFF_ flags defined above */
+ u_int m6_rate_limit; /* max rate */
+ struct in6_addr m6_lcl_addr; /* local interface address */
+ uint32_t m6_ifp; /* interface index */
+ u_quad_t m6_pkt_in; /* # pkts in on interface */
+ u_quad_t m6_pkt_out; /* # pkts out on interface */
+ u_quad_t m6_bytes_in; /* # bytes in on interface */
+ u_quad_t m6_bytes_out; /* # bytes out on interface */
+};
+
#if defined(_KERNEL) || defined(KERNEL)
/*
* The kernel's multicast-interface structure.
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index da32f07..83dda1a 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -765,11 +765,10 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
* address with the prefix.
*/
if (!IFA6_IS_DEPRECATED(it6))
- public_ifa6 = it6;
-
- if (public_ifa6 != NULL)
- ifa_ref(&public_ifa6->ia_ifa);
+ public_ifa6 = it6;
}
+ if (public_ifa6 != NULL)
+ ifa_ref(&public_ifa6->ia_ifa);
IF_ADDR_RUNLOCK(ifp);
if (public_ifa6 != NULL) {
@@ -2146,12 +2145,8 @@ nd6_need_cache(struct ifnet *ifp)
case IFT_ETHER:
case IFT_FDDI:
case IFT_IEEE1394:
-#ifdef IFT_L2VLAN
case IFT_L2VLAN:
-#endif
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
case IFT_INFINIBAND:
case IFT_BRIDGE:
case IFT_PROPVIRTUAL:
@@ -2236,12 +2231,8 @@ nd6_storelladdr(struct ifnet *ifp, struct mbuf *m,
switch (ifp->if_type) {
case IFT_ETHER:
case IFT_FDDI:
-#ifdef IFT_L2VLAN
case IFT_L2VLAN:
-#endif
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
case IFT_BRIDGE:
case IFT_ISO88025:
ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr,
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 2d319ed..a4ae618 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -417,14 +417,9 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6,
/* estimate the size of message */
maxlen = sizeof(*ip6) + sizeof(*nd_ns);
maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
- if (max_linkhdr + maxlen >= MCLBYTES) {
-#ifdef DIAGNOSTIC
- printf("%s: max_linkhdr + maxlen >= MCLBYTES "
- "(%d + %d > %d)\n", __func__, max_linkhdr, maxlen,
- MCLBYTES);
-#endif
- return;
- }
+ KASSERT(max_linkhdr + maxlen <= MCLBYTES, (
+ "%s: max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)",
+ __func__, max_linkhdr, maxlen, MCLBYTES));
if (max_linkhdr + maxlen > MHLEN)
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
@@ -992,13 +987,9 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
/* estimate the size of message */
maxlen = sizeof(*ip6) + sizeof(*nd_na);
maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
- if (max_linkhdr + maxlen >= MCLBYTES) {
-#ifdef DIAGNOSTIC
- printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
- "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
-#endif
- return;
- }
+ KASSERT(max_linkhdr + maxlen <= MCLBYTES, (
+ "%s: max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)",
+ __func__, max_linkhdr, maxlen, MCLBYTES));
if (max_linkhdr + maxlen > MHLEN)
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
@@ -1158,12 +1149,8 @@ nd6_ifptomac(struct ifnet *ifp)
case IFT_ETHER:
case IFT_FDDI:
case IFT_IEEE1394:
-#ifdef IFT_L2VLAN
case IFT_L2VLAN:
-#endif
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
case IFT_INFINIBAND:
case IFT_BRIDGE:
case IFT_ISO88025:
@@ -1558,9 +1545,7 @@ nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp)
case IFT_FDDI:
case IFT_ATM:
case IFT_IEEE1394:
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
case IFT_INFINIBAND:
in6 = ia->ia_addr.sin6_addr;
if (in6_get_hw_ifid(ifp, &in6) == 0 &&
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index 19c5f8d..0576aa2 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -297,8 +297,16 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
}
if (nd_ra->nd_ra_retransmit)
ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
- if (nd_ra->nd_ra_curhoplimit)
- ndi->chlim = nd_ra->nd_ra_curhoplimit;
+ if (nd_ra->nd_ra_curhoplimit) {
+ if (ndi->chlim < nd_ra->nd_ra_curhoplimit)
+ ndi->chlim = nd_ra->nd_ra_curhoplimit;
+ else if (ndi->chlim != nd_ra->nd_ra_curhoplimit) {
+ log(LOG_ERR, "RA with a lower CurHopLimit sent from "
+ "%s on %s (current = %d, received = %d). "
+ "Ignored.\n", ip6_sprintf(ip6bufs, &ip6->ip6_src),
+ if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit);
+ }
+ }
dr = defrtrlist_update(&dr0);
}
diff --git a/sys/netipsec/ipsec.c b/sys/netipsec/ipsec.c
index 8a79052..266f6d0 100644
--- a/sys/netipsec/ipsec.c
+++ b/sys/netipsec/ipsec.c
@@ -238,6 +238,7 @@ SYSCTL_VNET_PCPUSTAT(_net_inet6_ipsec6, IPSECCTL_STATS, ipsecstats,
struct ipsecstat, ipsec6stat, "IPsec IPv6 statistics.");
#endif /* INET6 */
+static int ipsec_in_reject(struct secpolicy *, struct mbuf *);
static int ipsec_setspidx_inpcb(struct mbuf *, struct inpcb *);
static int ipsec_setspidx(struct mbuf *, struct secpolicyindex *, int);
static void ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *, int);
@@ -1191,7 +1192,7 @@ ipsec_get_reqlevel(struct ipsecrequest *isr)
* 0: valid
* 1: invalid
*/
-int
+static int
ipsec_in_reject(struct secpolicy *sp, struct mbuf *m)
{
struct ipsecrequest *isr;
@@ -1488,6 +1489,7 @@ ipsec_chkreplay(u_int32_t seq, struct secasvar *sav)
int
ipsec_updatereplay(u_int32_t seq, struct secasvar *sav)
{
+ char buf[128];
struct secreplay *replay;
u_int32_t diff;
int fr;
@@ -1567,7 +1569,8 @@ ok:
return (1);
ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n",
- __func__, replay->overflow, ipsec_logsastr(sav)));
+ __func__, replay->overflow,
+ ipsec_logsastr(sav, buf, sizeof(buf))));
}
replay->count++;
@@ -1598,67 +1601,37 @@ vshiftl(unsigned char *bitmap, int nbit, int wsize)
}
}
-#ifdef INET
-/* Return a printable string for the IPv4 address. */
-static char *
-inet_ntoa4(struct in_addr ina)
-{
- static char buf[4][4 * sizeof "123" + 4];
- unsigned char *ucp = (unsigned char *) &ina;
- static int i = 3;
-
- /* XXX-BZ Returns static buffer. */
- i = (i + 1) % 4;
- sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff,
- ucp[2] & 0xff, ucp[3] & 0xff);
- return (buf[i]);
-}
-#endif
-
/* Return a printable string for the address. */
-char *
-ipsec_address(union sockaddr_union* sa)
+char*
+ipsec_address(union sockaddr_union* sa, char *buf, socklen_t size)
{
-#ifdef INET6
- char ip6buf[INET6_ADDRSTRLEN];
-#endif
switch (sa->sa.sa_family) {
#ifdef INET
case AF_INET:
- return (inet_ntoa4(sa->sin.sin_addr));
+ return (inet_ntop(AF_INET, &sa->sin.sin_addr, buf, size));
#endif /* INET */
#ifdef INET6
case AF_INET6:
- return (ip6_sprintf(ip6buf, &sa->sin6.sin6_addr));
+ return (inet_ntop(AF_INET6, &sa->sin6.sin6_addr, buf, size));
#endif /* INET6 */
default:
return ("(unknown address family)");
}
}
-const char *
-ipsec_logsastr(struct secasvar *sav)
+char *
+ipsec_logsastr(struct secasvar *sav, char *buf, size_t size)
{
- static char buf[256];
- char *p;
- struct secasindex *saidx = &sav->sah->saidx;
-
- IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family,
- ("address family mismatch"));
-
- p = buf;
- snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi));
- while (p && *p)
- p++;
- /* NB: only use ipsec_address on one address at a time. */
- snprintf(p, sizeof (buf) - (p - buf), "src=%s ",
- ipsec_address(&saidx->src));
- while (p && *p)
- p++;
- snprintf(p, sizeof (buf) - (p - buf), "dst=%s)",
- ipsec_address(&saidx->dst));
+ char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
+
+ IPSEC_ASSERT(sav->sah->saidx.src.sa.sa_family ==
+ sav->sah->saidx.dst.sa.sa_family, ("address family mismatch"));
+ snprintf(buf, size, "SA(SPI=%08lx src=%s dst=%s)",
+ (u_long)ntohl(sav->spi),
+ ipsec_address(&sav->sah->saidx.src, sbuf, sizeof(sbuf)),
+ ipsec_address(&sav->sah->saidx.dst, dbuf, sizeof(dbuf)));
return (buf);
}
diff --git a/sys/netipsec/ipsec.h b/sys/netipsec/ipsec.h
index 226ef70..442387a 100644
--- a/sys/netipsec/ipsec.h
+++ b/sys/netipsec/ipsec.h
@@ -309,7 +309,6 @@ struct inpcb;
extern int ipsec_init_policy(struct socket *so, struct inpcbpolicy **);
extern int ipsec_copy_policy(struct inpcbpolicy *, struct inpcbpolicy *);
extern u_int ipsec_get_reqlevel(struct ipsecrequest *);
-extern int ipsec_in_reject(struct secpolicy *, struct mbuf *);
extern int ipsec_set_policy(struct inpcb *inp, int optname,
caddr_t request, size_t len, struct ucred *cred);
@@ -327,8 +326,8 @@ extern size_t ipsec_hdrsiz(struct mbuf *, u_int, struct inpcb *);
extern size_t ipsec_hdrsiz_tcp(struct tcpcb *);
union sockaddr_union;
-extern char * ipsec_address(union sockaddr_union* sa);
-extern const char *ipsec_logsastr(struct secasvar *);
+extern char *ipsec_address(union sockaddr_union *, char *, socklen_t);
+extern char *ipsec_logsastr(struct secasvar *, char *, size_t);
extern void ipsec_dumpmbuf(struct mbuf *);
diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c
index 86cc5b5..5837699 100644
--- a/sys/netipsec/ipsec_input.c
+++ b/sys/netipsec/ipsec_input.c
@@ -121,6 +121,7 @@ static void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int);
static int
ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
{
+ char buf[INET6_ADDRSTRLEN];
union sockaddr_union dst_address;
struct secasvar *sav;
u_int32_t spi;
@@ -195,6 +196,13 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
sizeof(struct in6_addr),
(caddr_t) &dst_address.sin6.sin6_addr);
+ /* We keep addresses in SADB without embedded scope id */
+ if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) {
+ /* XXX: sa6_recoverscope() */
+ dst_address.sin6.sin6_scope_id =
+ ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]);
+ dst_address.sin6.sin6_addr.s6_addr16[1] = 0;
+ }
break;
#endif /* INET6 */
default:
@@ -208,8 +216,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
sav = KEY_ALLOCSA(&dst_address, sproto, spi);
if (sav == NULL) {
DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n",
- __func__, ipsec_address(&dst_address),
- (u_long) ntohl(spi), sproto));
+ __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
+ (u_long) ntohl(spi), sproto));
IPSEC_ISTAT(sproto, notdb);
m_freem(m);
return ENOENT;
@@ -217,8 +225,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
if (sav->tdb_xform == NULL) {
DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n",
- __func__, ipsec_address(&dst_address),
- (u_long) ntohl(spi), sproto));
+ __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
+ (u_long) ntohl(spi), sproto));
IPSEC_ISTAT(sproto, noxform);
KEY_FREESAV(&sav);
m_freem(m);
@@ -320,6 +328,7 @@ int
ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
int protoff)
{
+ char buf[INET6_ADDRSTRLEN];
int prot, af, sproto, isr_prot;
struct ip *ip;
struct m_tag *mtag;
@@ -358,8 +367,8 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
*/
if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
DPRINTF(("%s: processing failed for SA %s/%08lx\n",
- __func__, ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ __func__, ipsec_address(&sav->sah->saidx.dst,
+ buf, sizeof(buf)), (u_long) ntohl(sav->spi)));
IPSEC_ISTAT(sproto, hdrops);
error = ENOBUFS;
goto bad;
@@ -382,6 +391,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE);
if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0)
return (error);
+ ip = mtod(m, struct ip *);
#endif /* DEV_ENC */
/* IP-in-IP encapsulation */
@@ -615,12 +625,13 @@ int
ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
int protoff)
{
+ char buf[INET6_ADDRSTRLEN];
int prot, af, sproto;
struct ip6_hdr *ip6;
struct m_tag *mtag;
struct tdb_ident *tdbi;
struct secasindex *saidx;
- int nxt;
+ int nxt, isr_prot;
u_int8_t nxt8;
int error, nest;
#ifdef notyet
@@ -651,8 +662,8 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
(m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
DPRINTF(("%s: processing failed for SA %s/%08lx\n",
- __func__, ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ __func__, ipsec_address(&sav->sah->saidx.dst, buf,
+ sizeof(buf)), (u_long) ntohl(sav->spi)));
IPSEC_ISTAT(sproto, hdrops);
error = EACCES;
@@ -796,6 +807,35 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER)) != 0)
return (error);
#endif /* DEV_ENC */
+ if (skip == 0) {
+ /*
+ * We stripped outer IPv6 header.
+ * Now we should requeue decrypted packet via netisr.
+ */
+ switch (prot) {
+#ifdef INET
+ case IPPROTO_IPIP:
+ isr_prot = NETISR_IP;
+ break;
+#endif
+ case IPPROTO_IPV6:
+ isr_prot = NETISR_IPV6;
+ break;
+ default:
+ DPRINTF(("%s: cannot handle inner ip proto %d\n",
+ __func__, prot));
+ IPSEC_ISTAT(sproto, nopf);
+ error = EPFNOSUPPORT;
+ goto bad;
+ }
+ error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m);
+ if (error) {
+ IPSEC_ISTAT(sproto, qfull);
+ DPRINTF(("%s: queue full; proto %u packet dropped\n",
+ __func__, sproto));
+ }
+ return (error);
+ }
/*
* See the end of ip6_input for this logic.
* IPPROTO_IPV[46] case will be processed just like other ones
diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c
index 8e65005..ae36070 100644
--- a/sys/netipsec/ipsec_output.c
+++ b/sys/netipsec/ipsec_output.c
@@ -61,6 +61,7 @@
#include <netinet/ip6.h>
#ifdef INET6
#include <netinet6/ip6_var.h>
+#include <netinet6/scope6_var.h>
#endif
#include <netinet/in_pcb.h>
#ifdef INET6
@@ -103,6 +104,7 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
IPSEC_ASSERT(m != NULL, ("null mbuf"));
IPSEC_ASSERT(isr != NULL, ("null ISR"));
+ IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp"));
sav = isr->sav;
IPSEC_ASSERT(sav != NULL, ("null SA"));
IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
@@ -162,6 +164,10 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
* If this is a problem we'll need to introduce a queue
* to set the packet on so we can unwind the stack before
* doing further processing.
+ *
+ * If ipsec[46]_process_packet() will successfully queue
+ * the request, we need to take additional reference to SP,
+ * because xform callback will release reference.
*/
if (isr->next) {
/* XXX-BZ currently only support same AF bundles. */
@@ -169,7 +175,11 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
#ifdef INET
case AF_INET:
IPSECSTAT_INC(ips_out_bundlesa);
- return ipsec4_process_packet(m, isr->next);
+ key_addref(isr->sp);
+ error = ipsec4_process_packet(m, isr->next);
+ if (error != 0)
+ KEY_FREESP(&isr->sp);
+ return (error);
/* NOTREACHED */
#endif
#ifdef notyet
@@ -177,7 +187,11 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
case AF_INET6:
/* XXX */
IPSEC6STAT_INC(ips_out_bundlesa);
- return ipsec6_process_packet(m, isr->next);
+ key_addref(isr->sp);
+ error = ipsec6_process_packet(m, isr->next);
+ if (error != 0)
+ KEY_FREESP(&isr->sp);
+ return (error);
/* NOTREACHED */
#endif /* INET6 */
#endif
@@ -192,8 +206,7 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
/*
* We're done with IPsec processing, transmit the packet using the
- * appropriate network protocol (IP or IPv6). SPD lookup will be
- * performed again there.
+ * appropriate network protocol (IP or IPv6).
*/
switch (saidx->dst.sa.sa_family) {
#ifdef INET
@@ -419,6 +432,108 @@ bad:
#undef IPSEC_OSTAT
}
+static int
+ipsec_encap(struct mbuf **mp, struct secasindex *saidx)
+{
+#ifdef INET6
+ struct ip6_hdr *ip6;
+#endif
+ struct ip *ip;
+ int setdf;
+ uint8_t itos, proto;
+
+ ip = mtod(*mp, struct ip *);
+ switch (ip->ip_v) {
+#ifdef INET
+ case IPVERSION:
+ proto = IPPROTO_IPIP;
+ /*
+ * Collect IP_DF state from the inner header
+ * and honor system-wide control of how to handle it.
+ */
+ switch (V_ip4_ipsec_dfbit) {
+ case 0: /* clear in outer header */
+ case 1: /* set in outer header */
+ setdf = V_ip4_ipsec_dfbit;
+ break;
+ default:/* propagate to outer header */
+ setdf = (ip->ip_off & ntohs(IP_DF)) != 0;
+ }
+ itos = ip->ip_tos;
+ break;
+#endif
+#ifdef INET6
+ case (IPV6_VERSION >> 4):
+ proto = IPPROTO_IPV6;
+ ip6 = mtod(*mp, struct ip6_hdr *);
+ itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ setdf = V_ip4_ipsec_dfbit ? 1: 0;
+ /* scoped address handling */
+ in6_clearscope(&ip6->ip6_src);
+ in6_clearscope(&ip6->ip6_dst);
+ break;
+#endif
+ default:
+ return (EAFNOSUPPORT);
+ }
+ switch (saidx->dst.sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (saidx->src.sa.sa_family != AF_INET ||
+ saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
+ saidx->dst.sin.sin_addr.s_addr == INADDR_ANY)
+ return (EINVAL);
+ M_PREPEND(*mp, sizeof(struct ip), M_NOWAIT);
+ if (*mp == NULL)
+ return (ENOBUFS);
+ ip = mtod(*mp, struct ip *);
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ ip->ip_p = proto;
+ ip->ip_len = htons((*mp)->m_pkthdr.len);
+ ip->ip_ttl = V_ip_defttl;
+ ip->ip_sum = 0;
+ ip->ip_off = setdf ? htons(IP_DF): 0;
+ ip->ip_src = saidx->src.sin.sin_addr;
+ ip->ip_dst = saidx->dst.sin.sin_addr;
+ ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos);
+ ip_fillid(ip);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ if (saidx->src.sa.sa_family != AF_INET6 ||
+ IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr) ||
+ IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr))
+ return (EINVAL);
+ M_PREPEND(*mp, sizeof(struct ip6_hdr), M_NOWAIT);
+ if (*mp == NULL)
+ return (ENOBUFS);
+ ip6 = mtod(*mp, struct ip6_hdr *);
+ ip6->ip6_flow = 0;
+ ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_hlim = V_ip6_defhlim;
+ ip6->ip6_nxt = proto;
+ ip6->ip6_dst = saidx->dst.sin6.sin6_addr;
+ /* For link-local address embed scope zone id */
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1] =
+ htons(saidx->dst.sin6.sin6_scope_id & 0xffff);
+ ip6->ip6_src = saidx->src.sin6.sin6_addr;
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1] =
+ htons(saidx->src.sin6.sin6_scope_id & 0xffff);
+ ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6));
+ ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos);
+ ip6->ip6_flow |= htonl((uint32_t)proto << 20);
+ break;
+#endif /* INET6 */
+ default:
+ return (EAFNOSUPPORT);
+ }
+ return (0);
+}
+
#ifdef INET
/*
* IPsec output logic for IPv4.
@@ -426,11 +541,12 @@ bad:
int
ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr)
{
+ char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
union sockaddr_union *dst;
struct secasindex saidx;
struct secasvar *sav;
struct ip *ip;
- int error, i, off, setdf;
+ int error, i, off;
IPSEC_ASSERT(m != NULL, ("null mbuf"));
IPSEC_ASSERT(isr != NULL, ("null isr"));
@@ -461,57 +577,29 @@ ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr)
/* pass the mbuf to enc0 for packet filtering */
if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0)
goto bad;
+ ip = mtod(m, struct ip *);
#endif
/* Do the appropriate encapsulation, if necessary */
if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
dst->sa.sa_family != AF_INET || /* PF mismatch */
-#if 0
- (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
- sav->tdb_xform->xf_type == XF_IP4 || /* ditto */
-#endif
(dst->sa.sa_family == AF_INET && /* Proxy */
dst->sin.sin_addr.s_addr != INADDR_ANY &&
dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
- struct mbuf *mp;
-
/* Fix IPv4 header checksum and length */
ip->ip_len = htons(m->m_pkthdr.len);
ip->ip_sum = 0;
ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
- /*
- * Collect IP_DF state from the outer header
- * and honor system-wide control of how to handle it.
- */
- switch (V_ip4_ipsec_dfbit) {
- case 0: /* clear in outer header */
- case 1: /* set in outer header */
- setdf = V_ip4_ipsec_dfbit;
- break;
- default: /* propagate to outer header */
- setdf = ntohs(ip->ip_off & IP_DF);
- }
- /* Encapsulate the packet */
- error = ipip_output(m, isr, &mp, 0, 0);
+ error = ipsec_encap(&m, &sav->sah->saidx);
if (error != 0) {
- m = NULL; /* ipip_output() already freed it */
+ DPRINTF(("%s: encapsulation for SA %s->%s "
+ "SPI 0x%08x failed with error %d\n", __func__,
+ ipsec_address(&sav->sah->saidx.src, sbuf,
+ sizeof(sbuf)),
+ ipsec_address(&sav->sah->saidx.dst, dbuf,
+ sizeof(dbuf)), ntohl(sav->spi), error));
goto bad;
}
- m = mp;
- /*
- * ipip_output clears IP_DF in the new header. If
- * we need to propagate IP_DF from the outer header,
- * then we have to do it here.
- *
- * XXX shouldn't assume what ipip_output does.
- */
- if (dst->sa.sa_family == AF_INET && setdf) {
- ip = mtod(m, struct ip *);
- ip->ip_off = ntohs(ip->ip_off);
- ip->ip_off |= IP_DF;
- ip->ip_off = htons(ip->ip_off);
- }
}
-
#ifdef DEV_ENC
/* pass the mbuf to enc0 for bpf processing */
ipsec_bpf(m, sav, sav->sah->saidx.dst.sa.sa_family, ENC_OUT|ENC_AFTER);
@@ -523,40 +611,33 @@ ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr)
/*
* Dispatch to the appropriate IPsec transform logic. The
* packet will be returned for transmission after crypto
- * processing, etc. are completed. For encapsulation we
- * bypass this call because of the explicit call done above
- * (necessary to deal with IP_DF handling for IPv4).
+ * processing, etc. are completed.
*
* NB: m & sav are ``passed to caller'' who's reponsible for
* for reclaiming their resources.
*/
- if (sav->tdb_xform->xf_type != XF_IP4) {
- union sockaddr_union *dst = &sav->sah->saidx.dst;
- switch(dst->sa.sa_family) {
- case AF_INET:
- ip = mtod(m, struct ip *);
- i = ip->ip_hl << 2;
- off = offsetof(struct ip, ip_p);
- break;
+ switch(dst->sa.sa_family) {
+ case AF_INET:
+ ip = mtod(m, struct ip *);
+ i = ip->ip_hl << 2;
+ off = offsetof(struct ip, ip_p);
+ break;
#ifdef INET6
- case AF_INET6:
- i = sizeof(struct ip6_hdr);
- off = offsetof(struct ip6_hdr, ip6_nxt);
- break;
+ case AF_INET6:
+ i = sizeof(struct ip6_hdr);
+ off = offsetof(struct ip6_hdr, ip6_nxt);
+ break;
#endif /* INET6 */
- default:
+ default:
DPRINTF(("%s: unsupported protocol family %u\n",
- __func__, dst->sa.sa_family));
- error = EPFNOSUPPORT;
- IPSECSTAT_INC(ips_out_inval);
- goto bad;
- }
- error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
- } else {
- error = ipsec_process_done(m, isr);
+ __func__, dst->sa.sa_family));
+ error = EPFNOSUPPORT;
+ IPSECSTAT_INC(ips_out_inval);
+ goto bad;
}
+ error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
IPSECREQUEST_UNLOCK(isr);
- return error;
+ return (error);
bad:
if (isr)
IPSECREQUEST_UNLOCK(isr);
@@ -584,11 +665,9 @@ in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr
* IPsec output logic for IPv6.
*/
int
-ipsec6_process_packet(
- struct mbuf *m,
- struct ipsecrequest *isr
- )
+ipsec6_process_packet(struct mbuf *m, struct ipsecrequest *isr)
{
+ char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
struct secasindex saidx;
struct secasvar *sav;
struct ip6_hdr *ip6;
@@ -606,7 +685,6 @@ ipsec6_process_packet(
goto bad;
return EJUSTRETURN;
}
-
sav = isr->sav;
dst = &sav->sah->saidx.dst;
@@ -621,6 +699,7 @@ ipsec6_process_packet(
/* pass the mbuf to enc0 for packet filtering */
if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0)
goto bad;
+ ip6 = mtod(m, struct ip6_hdr *);
#endif /* DEV_ENC */
/* Do the appropriate encapsulation, if necessary */
@@ -630,42 +709,21 @@ ipsec6_process_packet(
(!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
(!in6_sa_equal_addrwithscope(&dst->sin6,
&ip6->ip6_dst)))) {
- struct mbuf *mp;
-
- /* Fix IPv6 header payload length. */
- if (m->m_len < sizeof(struct ip6_hdr))
- if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) {
- error = ENOBUFS;
- goto bad;
- }
-
if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
/* No jumbogram support. */
error = ENXIO; /*XXX*/
goto bad;
}
-
- /* Encapsulate the packet */
- error = ipip_output(m, isr, &mp, 0, 0);
- if (mp == NULL && !error) {
- /* Should never happen. */
- DPRINTF(("ipsec6_process_packet: ipip_output "
- "returns no mbuf and no error!"));
- error = EFAULT;
- goto bad;
- }
-
- if (error) {
- if (mp) {
- /* XXX: Should never happen! */
- m_freem(mp);
- }
- m = NULL; /* ipip_output() already freed it */
+ error = ipsec_encap(&m, &sav->sah->saidx);
+ if (error != 0) {
+ DPRINTF(("%s: encapsulation for SA %s->%s "
+ "SPI 0x%08x failed with error %d\n", __func__,
+ ipsec_address(&sav->sah->saidx.src, sbuf,
+ sizeof(sbuf)),
+ ipsec_address(&sav->sah->saidx.dst, dbuf,
+ sizeof(dbuf)), ntohl(sav->spi), error));
goto bad;
}
-
- m = mp;
- mp = NULL;
}
#ifdef DEV_ENC
diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c
index a19adab..353dd32 100644
--- a/sys/netipsec/key.c
+++ b/sys/netipsec/key.c
@@ -3856,48 +3856,19 @@ key_ismyaddr(struct sockaddr *sa)
* compare my own address for IPv6.
* 1: ours
* 0: other
- * NOTE: derived ip6_input() in KAME. This is necessary to modify more.
*/
-#include <netinet6/in6_var.h>
-
static int
key_ismyaddr6(struct sockaddr_in6 *sin6)
{
- struct in6_ifaddr *ia;
-#if 0
- struct in6_multi *in6m;
-#endif
+ struct in6_addr in6;
- IN6_IFADDR_RLOCK();
- TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
- if (key_sockaddrcmp((struct sockaddr *)sin6,
- (struct sockaddr *)&ia->ia_addr, 0) == 0) {
- IN6_IFADDR_RUNLOCK();
- return 1;
- }
+ if (!IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
+ return (in6_localip(&sin6->sin6_addr));
-#if 0
- /*
- * XXX Multicast
- * XXX why do we care about multlicast here while we don't care
- * about IPv4 multicast??
- * XXX scope
- */
- in6m = NULL;
- IN6_LOOKUP_MULTI(sin6->sin6_addr, ia->ia_ifp, in6m);
- if (in6m) {
- IN6_IFADDR_RUNLOCK();
- return 1;
- }
-#endif
- }
- IN6_IFADDR_RUNLOCK();
-
- /* loopback, just for safety */
- if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
- return 1;
-
- return 0;
+ /* Convert address into kernel-internal form */
+ in6 = sin6->sin6_addr;
+ in6.s6_addr16[1] = htons(sin6->sin6_scope_id & 0xffff);
+ return (in6_localip(&in6));
}
#endif /*INET6*/
diff --git a/sys/netipsec/xform.h b/sys/netipsec/xform.h
index a6bce34..132717f 100644
--- a/sys/netipsec/xform.h
+++ b/sys/netipsec/xform.h
@@ -83,7 +83,7 @@ struct ipescrequest;
struct xformsw {
u_short xf_type; /* xform ID */
-#define XF_IP4 1 /* IP inside IP */
+#define XF_IP4 1 /* unused */
#define XF_AH 2 /* AH */
#define XF_ESP 3 /* ESP */
#define XF_TCPSIGNATURE 5 /* TCP MD5 Signature option, RFC 2358 */
@@ -108,10 +108,6 @@ extern int xform_init(struct secasvar *sav, int xftype);
struct cryptoini;
-/* XF_IP4 */
-extern int ipip_output(struct mbuf *, struct ipsecrequest *,
- struct mbuf **, int, int);
-
/* XF_AH */
extern int ah_init0(struct secasvar *, struct xformsw *, struct cryptoini *);
extern int ah_zeroize(struct secasvar *sav);
diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c
index 292dba2..8f791db 100644
--- a/sys/netipsec/xform_ah.c
+++ b/sys/netipsec/xform_ah.c
@@ -567,6 +567,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
static int
ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
{
+ char buf[128];
struct auth_hash *ahx;
struct tdb_crypto *tc;
struct newah *ah;
@@ -596,7 +597,7 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) {
AHSTAT_INC(ahs_replay);
DPRINTF(("%s: packet replay failure: %s\n", __func__,
- ipsec_logsastr(sav)));
+ ipsec_logsastr(sav, buf, sizeof(buf))));
m_freem(m);
return ENOBUFS;
}
@@ -607,10 +608,10 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
authsize = AUTHSIZE(sav);
if (hl != authsize + rplen - sizeof (struct ah)) {
DPRINTF(("%s: bad authenticator length %u (expecting %lu)"
- " for packet in SA %s/%08lx\n", __func__,
- hl, (u_long) (authsize + rplen - sizeof (struct ah)),
- ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ " for packet in SA %s/%08lx\n", __func__, hl,
+ (u_long) (authsize + rplen - sizeof (struct ah)),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_badauthl);
m_freem(m);
return EACCES;
@@ -695,6 +696,7 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
static int
ah_input_cb(struct cryptop *crp)
{
+ char buf[INET6_ADDRSTRLEN];
int rplen, error, skip, protoff;
unsigned char calc[AH_ALEN_MAX];
struct mbuf *m;
@@ -764,7 +766,7 @@ ah_input_cb(struct cryptop *crp)
if (bcmp(ptr + skip + rplen, calc, authsize)) {
DPRINTF(("%s: authentication hash mismatch for packet "
"in SA %s/%08lx\n", __func__,
- ipsec_address(&saidx->dst),
+ ipsec_address(&saidx->dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_badauth);
error = EACCES;
@@ -803,8 +805,8 @@ ah_input_cb(struct cryptop *crp)
error = m_striphdr(m, skip, rplen + authsize);
if (error) {
DPRINTF(("%s: mangled mbuf chain for SA %s/%08lx\n", __func__,
- ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi)));
-
+ ipsec_address(&saidx->dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_hdrops);
goto bad;
}
@@ -843,13 +845,10 @@ bad:
* AH output routine, called by ipsec[46]_process_packet().
*/
static int
-ah_output(
- struct mbuf *m,
- struct ipsecrequest *isr,
- struct mbuf **mp,
- int skip,
- int protoff)
+ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
+ int skip, int protoff)
{
+ char buf[INET6_ADDRSTRLEN];
struct secasvar *sav;
struct auth_hash *ahx;
struct cryptodesc *crda;
@@ -887,7 +886,7 @@ ah_output(
DPRINTF(("%s: unknown/unsupported protocol family %u, "
"SA %s/%08lx\n", __func__,
sav->sah->saidx.dst.sa.sa_family,
- ipsec_address(&sav->sah->saidx.dst),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_nopf);
error = EPFNOSUPPORT;
@@ -897,7 +896,7 @@ ah_output(
if (rplen + authsize + m->m_pkthdr.len > maxpacketsize) {
DPRINTF(("%s: packet in SA %s/%08lx got too big "
"(len %u, max len %u)\n", __func__,
- ipsec_address(&sav->sah->saidx.dst),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi),
rplen + authsize + m->m_pkthdr.len, maxpacketsize));
AHSTAT_INC(ahs_toobig);
@@ -911,7 +910,7 @@ ah_output(
m = m_unshare(m, M_NOWAIT);
if (m == NULL) {
DPRINTF(("%s: cannot clone mbuf chain, SA %s/%08lx\n", __func__,
- ipsec_address(&sav->sah->saidx.dst),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_hdrops);
error = ENOBUFS;
@@ -924,7 +923,7 @@ ah_output(
DPRINTF(("%s: failed to inject %u byte AH header for SA "
"%s/%08lx\n", __func__,
rplen + authsize,
- ipsec_address(&sav->sah->saidx.dst),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_hdrops); /*XXX differs from openbsd */
error = ENOBUFS;
@@ -951,9 +950,8 @@ ah_output(
if (sav->replay->count == ~0 &&
(sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
DPRINTF(("%s: replay counter wrapped for SA %s/%08lx\n",
- __func__,
- ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ __func__, ipsec_address(&sav->sah->saidx.dst, buf,
+ sizeof(buf)), (u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_wrap);
error = EINVAL;
goto bad;
@@ -1093,6 +1091,7 @@ ah_output_cb(struct cryptop *crp)
m = (struct mbuf *) crp->crp_buf;
isr = tc->tc_isr;
+ IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp"));
IPSECREQUEST_LOCK(isr);
sav = tc->tc_sav;
/* With the isr lock released SA pointer can be updated. */
@@ -1156,16 +1155,18 @@ ah_output_cb(struct cryptop *crp)
error = ipsec_process_done(m, isr);
KEY_FREESAV(&sav);
IPSECREQUEST_UNLOCK(isr);
- return error;
+ KEY_FREESP(&isr->sp);
+ return (error);
bad:
if (sav)
KEY_FREESAV(&sav);
IPSECREQUEST_UNLOCK(isr);
+ KEY_FREESP(&isr->sp);
if (m)
m_freem(m);
free(tc, M_XDATA);
crypto_freereq(crp);
- return error;
+ return (error);
}
static struct xformsw ah_xformsw = {
diff --git a/sys/netipsec/xform_esp.c b/sys/netipsec/xform_esp.c
index cc95996..003c514 100644
--- a/sys/netipsec/xform_esp.c
+++ b/sys/netipsec/xform_esp.c
@@ -268,6 +268,7 @@ esp_zeroize(struct secasvar *sav)
static int
esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
{
+ char buf[128];
struct auth_hash *esph;
struct enc_xform *espx;
struct tdb_crypto *tc;
@@ -326,9 +327,8 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
if ((plen & (espx->blocksize - 1)) || (plen <= 0)) {
DPRINTF(("%s: payload of %d octets not a multiple of %d octets,"
" SA %s/%08lx\n", __func__,
- plen, espx->blocksize,
- ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ plen, espx->blocksize, ipsec_address(&sav->sah->saidx.dst,
+ buf, sizeof(buf)), (u_long) ntohl(sav->spi)));
ESPSTAT_INC(esps_badilen);
m_freem(m);
return EINVAL;
@@ -340,7 +340,7 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
if (esph != NULL && sav->replay != NULL &&
!ipsec_chkreplay(ntohl(esp->esp_seq), sav)) {
DPRINTF(("%s: packet replay check for %s\n", __func__,
- ipsec_logsastr(sav))); /*XXX*/
+ ipsec_logsastr(sav, buf, sizeof(buf)))); /*XXX*/
ESPSTAT_INC(esps_replay);
m_freem(m);
return ENOBUFS; /*XXX*/
@@ -431,6 +431,7 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
static int
esp_input_cb(struct cryptop *crp)
{
+ char buf[128];
u_int8_t lastthree[3], aalg[AH_HMAC_MAXHASHLEN];
int hlen, skip, protoff, error, alen;
struct mbuf *m;
@@ -507,7 +508,7 @@ esp_input_cb(struct cryptop *crp)
if (bcmp(ptr, aalg, alen) != 0) {
DPRINTF(("%s: authentication hash mismatch for "
"packet in SA %s/%08lx\n", __func__,
- ipsec_address(&saidx->dst),
+ ipsec_address(&saidx->dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
ESPSTAT_INC(esps_badauth);
error = EACCES;
@@ -537,7 +538,7 @@ esp_input_cb(struct cryptop *crp)
sizeof (seq), (caddr_t) &seq);
if (ipsec_updatereplay(ntohl(seq), sav)) {
DPRINTF(("%s: packet replay check for %s\n", __func__,
- ipsec_logsastr(sav)));
+ ipsec_logsastr(sav, buf, sizeof(buf))));
ESPSTAT_INC(esps_replay);
error = ENOBUFS;
goto bad;
@@ -555,7 +556,7 @@ esp_input_cb(struct cryptop *crp)
if (error) {
ESPSTAT_INC(esps_hdrops);
DPRINTF(("%s: bad mbuf chain, SA %s/%08lx\n", __func__,
- ipsec_address(&sav->sah->saidx.dst),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
goto bad;
}
@@ -567,10 +568,10 @@ esp_input_cb(struct cryptop *crp)
if (lastthree[1] + 2 > m->m_pkthdr.len - skip) {
ESPSTAT_INC(esps_badilen);
DPRINTF(("%s: invalid padding length %d for %u byte packet "
- "in SA %s/%08lx\n", __func__,
- lastthree[1], m->m_pkthdr.len - skip,
- ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ "in SA %s/%08lx\n", __func__, lastthree[1],
+ m->m_pkthdr.len - skip,
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi)));
error = EINVAL;
goto bad;
}
@@ -580,9 +581,9 @@ esp_input_cb(struct cryptop *crp)
if (lastthree[1] != lastthree[0] && lastthree[1] != 0) {
ESPSTAT_INC(esps_badenc);
DPRINTF(("%s: decryption failed for packet in "
- "SA %s/%08lx\n", __func__,
- ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ "SA %s/%08lx\n", __func__, ipsec_address(
+ &sav->sah->saidx.dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi)));
error = EINVAL;
goto bad;
}
@@ -628,14 +629,10 @@ bad:
* ESP output routine, called by ipsec[46]_process_packet().
*/
static int
-esp_output(
- struct mbuf *m,
- struct ipsecrequest *isr,
- struct mbuf **mp,
- int skip,
- int protoff
-)
+esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
+ int skip, int protoff)
{
+ char buf[INET6_ADDRSTRLEN];
struct enc_xform *espx;
struct auth_hash *esph;
int hlen, rlen, padding, blks, alen, i, roff;
@@ -703,8 +700,8 @@ esp_output(
default:
DPRINTF(("%s: unknown/unsupported protocol "
"family %d, SA %s/%08lx\n", __func__,
- saidx->dst.sa.sa_family, ipsec_address(&saidx->dst),
- (u_long) ntohl(sav->spi)));
+ saidx->dst.sa.sa_family, ipsec_address(&saidx->dst,
+ buf, sizeof(buf)), (u_long) ntohl(sav->spi)));
ESPSTAT_INC(esps_nopf);
error = EPFNOSUPPORT;
goto bad;
@@ -712,7 +709,8 @@ esp_output(
if (skip + hlen + rlen + padding + alen > maxpacketsize) {
DPRINTF(("%s: packet in SA %s/%08lx got too big "
"(len %u, max len %u)\n", __func__,
- ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi),
+ ipsec_address(&saidx->dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi),
skip + hlen + rlen + padding + alen, maxpacketsize));
ESPSTAT_INC(esps_toobig);
error = EMSGSIZE;
@@ -725,7 +723,8 @@ esp_output(
m = m_unshare(m, M_NOWAIT);
if (m == NULL) {
DPRINTF(("%s: cannot clone mbuf chain, SA %s/%08lx\n", __func__,
- ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi)));
+ ipsec_address(&saidx->dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi)));
ESPSTAT_INC(esps_hdrops);
error = ENOBUFS;
goto bad;
@@ -735,8 +734,8 @@ esp_output(
mo = m_makespace(m, skip, hlen, &roff);
if (mo == NULL) {
DPRINTF(("%s: %u byte ESP hdr inject failed for SA %s/%08lx\n",
- __func__, hlen, ipsec_address(&saidx->dst),
- (u_long) ntohl(sav->spi)));
+ __func__, hlen, ipsec_address(&saidx->dst, buf,
+ sizeof(buf)), (u_long) ntohl(sav->spi)));
ESPSTAT_INC(esps_hdrops); /* XXX diffs from openbsd */
error = ENOBUFS;
goto bad;
@@ -765,7 +764,8 @@ esp_output(
pad = (u_char *) m_pad(m, padding + alen);
if (pad == NULL) {
DPRINTF(("%s: m_pad failed for SA %s/%08lx\n", __func__,
- ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi)));
+ ipsec_address(&saidx->dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi)));
m = NULL; /* NB: free'd by m_pad */
error = ENOBUFS;
goto bad;
@@ -876,6 +876,7 @@ bad:
static int
esp_output_cb(struct cryptop *crp)
{
+ char buf[INET6_ADDRSTRLEN];
struct tdb_crypto *tc;
struct ipsecrequest *isr;
struct secasvar *sav;
@@ -887,13 +888,14 @@ esp_output_cb(struct cryptop *crp)
m = (struct mbuf *) crp->crp_buf;
isr = tc->tc_isr;
+ IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp"));
IPSECREQUEST_LOCK(isr);
sav = tc->tc_sav;
/* With the isr lock released SA pointer can be updated. */
if (sav != isr->sav) {
ESPSTAT_INC(esps_notdb);
DPRINTF(("%s: SA gone during crypto (SA %s/%08lx proto %u)\n",
- __func__, ipsec_address(&tc->tc_dst),
+ __func__, ipsec_address(&tc->tc_dst, buf, sizeof(buf)),
(u_long) ntohl(tc->tc_spi), tc->tc_proto));
error = ENOBUFS; /*XXX*/
goto bad;
@@ -965,16 +967,18 @@ esp_output_cb(struct cryptop *crp)
error = ipsec_process_done(m, isr);
KEY_FREESAV(&sav);
IPSECREQUEST_UNLOCK(isr);
- return error;
+ KEY_FREESP(&isr->sp);
+ return (error);
bad:
if (sav)
KEY_FREESAV(&sav);
IPSECREQUEST_UNLOCK(isr);
+ KEY_FREESP(&isr->sp);
if (m)
m_freem(m);
free(tc, M_XDATA);
crypto_freereq(crp);
- return error;
+ return (error);
}
static struct xformsw esp_xformsw = {
diff --git a/sys/netipsec/xform_ipcomp.c b/sys/netipsec/xform_ipcomp.c
index e7035cb..ef460cd 100644
--- a/sys/netipsec/xform_ipcomp.c
+++ b/sys/netipsec/xform_ipcomp.c
@@ -224,6 +224,7 @@ ipcomp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
static int
ipcomp_input_cb(struct cryptop *crp)
{
+ char buf[INET6_ADDRSTRLEN];
struct cryptodesc *crd;
struct tdb_crypto *tc;
int skip, protoff;
@@ -298,8 +299,8 @@ ipcomp_input_cb(struct cryptop *crp)
if (error) {
IPCOMPSTAT_INC(ipcomps_hdrops);
DPRINTF(("%s: bad mbuf chain, IPCA %s/%08lx\n", __func__,
- ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
+ (u_long) ntohl(sav->spi)));
goto bad;
}
@@ -340,14 +341,10 @@ bad:
* IPComp output routine, called by ipsec[46]_process_packet()
*/
static int
-ipcomp_output(
- struct mbuf *m,
- struct ipsecrequest *isr,
- struct mbuf **mp,
- int skip,
- int protoff
-)
+ipcomp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
+ int skip, int protoff)
{
+ char buf[INET6_ADDRSTRLEN];
struct secasvar *sav;
struct comp_algo *ipcompx;
int error, ralen, maxpacketsize;
@@ -391,7 +388,7 @@ ipcomp_output(
DPRINTF(("%s: unknown/unsupported protocol family %d, "
"IPCA %s/%08lx\n", __func__,
sav->sah->saidx.dst.sa.sa_family,
- ipsec_address(&sav->sah->saidx.dst),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
error = EPFNOSUPPORT;
goto bad;
@@ -400,7 +397,7 @@ ipcomp_output(
IPCOMPSTAT_INC(ipcomps_toobig);
DPRINTF(("%s: packet in IPCA %s/%08lx got too big "
"(len %u, max len %u)\n", __func__,
- ipsec_address(&sav->sah->saidx.dst),
+ ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi),
ralen + skip + IPCOMP_HLENGTH, maxpacketsize));
error = EMSGSIZE;
@@ -414,8 +411,8 @@ ipcomp_output(
if (m == NULL) {
IPCOMPSTAT_INC(ipcomps_hdrops);
DPRINTF(("%s: cannot clone mbuf chain, IPCA %s/%08lx\n",
- __func__, ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ __func__, ipsec_address(&sav->sah->saidx.dst, buf,
+ sizeof(buf)), (u_long) ntohl(sav->spi)));
error = ENOBUFS;
goto bad;
}
@@ -482,6 +479,7 @@ bad:
static int
ipcomp_output_cb(struct cryptop *crp)
{
+ char buf[INET6_ADDRSTRLEN];
struct tdb_crypto *tc;
struct ipsecrequest *isr;
struct secasvar *sav;
@@ -494,6 +492,7 @@ ipcomp_output_cb(struct cryptop *crp)
skip = tc->tc_skip;
isr = tc->tc_isr;
+ IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp"));
IPSECREQUEST_LOCK(isr);
sav = tc->tc_sav;
/* With the isr lock released SA pointer can be updated. */
@@ -539,8 +538,8 @@ ipcomp_output_cb(struct cryptop *crp)
if (mo == NULL) {
IPCOMPSTAT_INC(ipcomps_wrap);
DPRINTF(("%s: IPCOMP header inject failed for IPCA %s/%08lx\n",
- __func__, ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ __func__, ipsec_address(&sav->sah->saidx.dst, buf,
+ sizeof(buf)), (u_long) ntohl(sav->spi)));
error = ENOBUFS;
goto bad;
}
@@ -586,8 +585,8 @@ ipcomp_output_cb(struct cryptop *crp)
DPRINTF(("%s: unknown/unsupported protocol "
"family %d, IPCA %s/%08lx\n", __func__,
sav->sah->saidx.dst.sa.sa_family,
- ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ ipsec_address(&sav->sah->saidx.dst, buf,
+ sizeof(buf)), (u_long) ntohl(sav->spi)));
error = EPFNOSUPPORT;
goto bad;
}
@@ -608,16 +607,18 @@ ipcomp_output_cb(struct cryptop *crp)
error = ipsec_process_done(m, isr);
KEY_FREESAV(&sav);
IPSECREQUEST_UNLOCK(isr);
- return error;
+ KEY_FREESP(&isr->sp);
+ return (error);
bad:
if (sav)
KEY_FREESAV(&sav);
IPSECREQUEST_UNLOCK(isr);
+ KEY_FREESP(&isr->sp);
if (m)
m_freem(m);
free(tc, M_XDATA);
crypto_freereq(crp);
- return error;
+ return (error);
}
static struct xformsw ipcomp_xformsw = {
diff --git a/sys/netipsec/xform_ipip.c b/sys/netipsec/xform_ipip.c
deleted file mode 100644
index fc6c4a1..0000000
--- a/sys/netipsec/xform_ipip.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* $FreeBSD$ */
-/* $OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
-/*-
- * The authors of this code are John Ioannidis (ji@tla.org),
- * Angelos D. Keromytis (kermit@csd.uch.gr) and
- * Niels Provos (provos@physnet.uni-hamburg.de).
- *
- * The original version of this code was written by John Ioannidis
- * for BSD/OS in Athens, Greece, in November 1995.
- *
- * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
- * by Angelos D. Keromytis.
- *
- * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
- * and Niels Provos.
- *
- * Additional features in 1999 by Angelos D. Keromytis.
- *
- * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
- * Angelos D. Keromytis and Niels Provos.
- * Copyright (c) 2001, Angelos D. Keromytis.
- *
- * Permission to use, copy, and modify this software with or without fee
- * is hereby granted, provided that this entire notice is included in
- * all copies of any software which is or includes a copy or
- * modification of this software.
- * You may use this code under the GNU public license if you so wish. Please
- * contribute changes back to the authors under this freer than GPL license
- * so that we may further the use of strong encryption without limitations to
- * all.
- *
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
- * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
- * PURPOSE.
- */
-
-/*
- * IP-inside-IP processing
- */
-#include "opt_inet.h"
-#include "opt_inet6.h"
-#include "opt_enc.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/kernel.h>
-#include <sys/protosw.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/pfil.h>
-#include <net/netisr.h>
-#include <net/vnet.h>
-
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
-#include <netinet/ip.h>
-#include <netinet/ip_ecn.h>
-#include <netinet/ip_var.h>
-
-#include <netipsec/ipsec.h>
-#include <netipsec/xform.h>
-
-#ifdef INET6
-#include <netinet/ip6.h>
-#include <netipsec/ipsec6.h>
-#include <netinet6/ip6_ecn.h>
-#include <netinet6/in6_var.h>
-#include <netinet6/scope6_var.h>
-#endif
-
-#include <netipsec/key.h>
-#include <netipsec/key_debug.h>
-
-int
-ipip_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
- int skip, int protoff)
-{
- struct secasvar *sav;
- u_int8_t tp, otos;
- struct secasindex *saidx;
- int error;
-#if defined(INET) || defined(INET6)
- u_int8_t itos;
-#endif
-#ifdef INET
- struct ip *ipo;
-#endif /* INET */
-#ifdef INET6
- struct ip6_hdr *ip6, *ip6o;
-#endif /* INET6 */
-
- sav = isr->sav;
- IPSEC_ASSERT(sav != NULL, ("null SA"));
- IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
-
- /* XXX Deal with empty TDB source/destination addresses. */
-
- m_copydata(m, 0, 1, &tp);
- tp = (tp >> 4) & 0xff; /* Get the IP version number. */
-
- saidx = &sav->sah->saidx;
- switch (saidx->dst.sa.sa_family) {
-#ifdef INET
- case AF_INET:
- if (saidx->src.sa.sa_family != AF_INET ||
- saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
- saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) {
- DPRINTF(("%s: unspecified tunnel endpoint "
- "address in SA %s/%08lx\n", __func__,
- ipsec_address(&saidx->dst),
- (u_long) ntohl(sav->spi)));
- error = EINVAL;
- goto bad;
- }
-
- M_PREPEND(m, sizeof(struct ip), M_NOWAIT);
- if (m == 0) {
- DPRINTF(("%s: M_PREPEND failed\n", __func__));
- error = ENOBUFS;
- goto bad;
- }
-
- ipo = mtod(m, struct ip *);
-
- ipo->ip_v = IPVERSION;
- ipo->ip_hl = 5;
- ipo->ip_len = htons(m->m_pkthdr.len);
- ipo->ip_ttl = V_ip_defttl;
- ipo->ip_sum = 0;
- ipo->ip_src = saidx->src.sin.sin_addr;
- ipo->ip_dst = saidx->dst.sin.sin_addr;
- /* If the inner protocol is IP... */
- switch (tp) {
- case IPVERSION:
- /* Save ECN notification */
- m_copydata(m, sizeof(struct ip) +
- offsetof(struct ip, ip_tos),
- sizeof(u_int8_t), (caddr_t) &itos);
-
- ipo->ip_p = IPPROTO_IPIP;
-
- /*
- * We should be keeping tunnel soft-state and
- * send back ICMPs if needed.
- */
- m_copydata(m, sizeof(struct ip) +
- offsetof(struct ip, ip_off),
- sizeof(u_int16_t), (caddr_t) &ipo->ip_off);
- ipo->ip_off = ntohs(ipo->ip_off);
- ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK);
- ipo->ip_off = htons(ipo->ip_off);
- break;
-#ifdef INET6
- case (IPV6_VERSION >> 4):
- {
- u_int32_t itos32;
-
- /* Save ECN notification. */
- m_copydata(m, sizeof(struct ip) +
- offsetof(struct ip6_hdr, ip6_flow),
- sizeof(u_int32_t), (caddr_t) &itos32);
- itos = ntohl(itos32) >> 20;
- ipo->ip_p = IPPROTO_IPV6;
- ipo->ip_off = 0;
- break;
- }
-#endif /* INET6 */
- default:
- goto nofamily;
- }
- ip_fillid(ipo);
-
- otos = 0;
- ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
- ipo->ip_tos = otos;
- break;
-#endif /* INET */
-
-#ifdef INET6
- case AF_INET6:
- if (IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr) ||
- saidx->src.sa.sa_family != AF_INET6 ||
- IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr)) {
- DPRINTF(("%s: unspecified tunnel endpoint "
- "address in SA %s/%08lx\n", __func__,
- ipsec_address(&saidx->dst),
- (u_long) ntohl(sav->spi)));
- error = ENOBUFS;
- goto bad;
- }
-
- /* scoped address handling */
- ip6 = mtod(m, struct ip6_hdr *);
- in6_clearscope(&ip6->ip6_src);
- in6_clearscope(&ip6->ip6_dst);
- M_PREPEND(m, sizeof(struct ip6_hdr), M_NOWAIT);
- if (m == 0) {
- DPRINTF(("%s: M_PREPEND failed\n", __func__));
- error = ENOBUFS;
- goto bad;
- }
-
- /* Initialize IPv6 header */
- ip6o = mtod(m, struct ip6_hdr *);
- ip6o->ip6_flow = 0;
- ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
- ip6o->ip6_vfc |= IPV6_VERSION;
- ip6o->ip6_hlim = IPV6_DEFHLIM;
- ip6o->ip6_dst = saidx->dst.sin6.sin6_addr;
- ip6o->ip6_src = saidx->src.sin6.sin6_addr;
- ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
-
- switch (tp) {
-#ifdef INET
- case IPVERSION:
- /* Save ECN notification */
- m_copydata(m, sizeof(struct ip6_hdr) +
- offsetof(struct ip, ip_tos), sizeof(u_int8_t),
- (caddr_t) &itos);
-
- /* This is really IPVERSION. */
- ip6o->ip6_nxt = IPPROTO_IPIP;
- break;
-#endif /* INET */
- case (IPV6_VERSION >> 4):
- {
- u_int32_t itos32;
-
- /* Save ECN notification. */
- m_copydata(m, sizeof(struct ip6_hdr) +
- offsetof(struct ip6_hdr, ip6_flow),
- sizeof(u_int32_t), (caddr_t) &itos32);
- itos = ntohl(itos32) >> 20;
-
- ip6o->ip6_nxt = IPPROTO_IPV6;
- break;
- }
- default:
- goto nofamily;
- }
-
- otos = 0;
- ip_ecn_ingress(V_ip6_ipsec_ecn, &otos, &itos);
- ip6o->ip6_flow |= htonl((u_int32_t) otos << 20);
- break;
-#endif /* INET6 */
-
- default:
-nofamily:
- DPRINTF(("%s: unsupported protocol family %u\n", __func__,
- saidx->dst.sa.sa_family));
- error = EAFNOSUPPORT; /* XXX diffs from openbsd */
- goto bad;
- }
-
- *mp = m;
- return (0);
-bad:
- if (m)
- m_freem(m);
- *mp = NULL;
- return (error);
-}
-
-static int
-ipe4_init(struct secasvar *sav, struct xformsw *xsp)
-{
- sav->tdb_xform = xsp;
- return 0;
-}
-
-static int
-ipe4_zeroize(struct secasvar *sav)
-{
- sav->tdb_xform = NULL;
- return 0;
-}
-
-static int
-ipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
-{
- /* This is a rather serious mistake, so no conditional printing. */
- printf("%s: should never be called\n", __func__);
- if (m)
- m_freem(m);
- return EOPNOTSUPP;
-}
-
-static struct xformsw ipe4_xformsw = {
- XF_IP4, 0, "IPv4 Simple Encapsulation",
- ipe4_init, ipe4_zeroize, ipe4_input, ipip_output,
-};
-
-static void
-ipe4_attach(void)
-{
-
- xform_register(&ipe4_xformsw);
-}
-SYSINIT(ipe4_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipe4_attach, NULL);
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index a30f6bf..4da0ee0 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -2762,6 +2762,10 @@ vnet_ipfw_init(const void *unused)
LIST_INIT(&chain->nat);
#endif
+ /* Init shared services hash table */
+ ipfw_init_srv(chain);
+
+ ipfw_init_obj_rewriter();
ipfw_init_counters();
/* insert the default rule and create the initial map */
chain->n_rules = 1;
@@ -2860,9 +2864,11 @@ vnet_ipfw_uninit(const void *unused)
if (reap != NULL)
ipfw_reap_rules(reap);
vnet_ipfw_iface_destroy(chain);
+ ipfw_destroy_srv(chain);
IPFW_LOCK_DESTROY(chain);
ipfw_dyn_uninit(1); /* free the remaining parts */
ipfw_destroy_counters();
+ ipfw_destroy_obj_rewriter();
return (0);
}
diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c
index 201be2f..df40398 100644
--- a/sys/netpfil/ipfw/ip_fw_nat.c
+++ b/sys/netpfil/ipfw/ip_fw_nat.c
@@ -242,6 +242,8 @@ add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
}
if (r->alink[0] == NULL) {
printf("LibAliasRedirect* returned NULL\n");
+ free(r->alink, M_IPFW);
+ free(r, M_IPFW);
return (EINVAL);
}
/* LSNAT handling. */
@@ -263,6 +265,16 @@ add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
return (0);
}
+static void
+free_nat_instance(struct cfg_nat *ptr)
+{
+
+ del_redir_spool_cfg(ptr, &ptr->redir_chain);
+ LibAliasUninit(ptr->lib);
+ free(ptr, M_IPFW);
+}
+
+
/*
* ipfw_nat - perform mbuf header translation.
*
@@ -536,7 +548,7 @@ nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg)
IPFW_UH_WUNLOCK(chain);
if (tcfg != NULL)
- free(tcfg, M_IPFW);
+ free_nat_instance(ptr);
}
/*
@@ -626,9 +638,7 @@ nat44_destroy(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
IPFW_WUNLOCK(chain);
IPFW_UH_WUNLOCK(chain);
- del_redir_spool_cfg(ptr, &ptr->redir_chain);
- LibAliasUninit(ptr->lib);
- free(ptr, M_IPFW);
+ free_nat_instance(ptr);
return (0);
}
@@ -994,9 +1004,7 @@ ipfw_nat_del(struct sockopt *sopt)
flush_nat_ptrs(chain, i);
IPFW_WUNLOCK(chain);
IPFW_UH_WUNLOCK(chain);
- del_redir_spool_cfg(ptr, &ptr->redir_chain);
- LibAliasUninit(ptr->lib);
- free(ptr, M_IPFW);
+ free_nat_instance(ptr);
return (0);
}
@@ -1139,9 +1147,7 @@ vnet_ipfw_nat_uninit(const void *arg __unused)
IPFW_WLOCK(chain);
LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
LIST_REMOVE(ptr, _next);
- del_redir_spool_cfg(ptr, &ptr->redir_chain);
- LibAliasUninit(ptr->lib);
- free(ptr, M_IPFW);
+ free_nat_instance(ptr);
}
flush_nat_ptrs(chain, -1 /* flush all */);
V_ipfw_nat_ready = 0;
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index bb5b3ba..504093b 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -264,10 +264,10 @@ struct ip_fw_chain {
struct ip_fw **map; /* array of rule ptrs to ease lookup */
uint32_t id; /* ruleset id */
int n_rules; /* number of static rules */
- LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
void *tablestate; /* runtime table info */
void *valuestate; /* runtime table value info */
int *idxmap; /* skipto array of rules */
+ void **srvstate; /* runtime service mappings */
#if defined( __linux__ ) || defined( _WIN32 )
spinlock_t rwmtx;
#else
@@ -275,10 +275,12 @@ struct ip_fw_chain {
#endif
int static_len; /* total len of static rules (v0) */
uint32_t gencnt; /* NAT generation count */
+ LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
struct ip_fw *default_rule;
struct tables_config *tblcfg; /* tables module data */
void *ifcfg; /* interface module data */
int *idxmap_back; /* standby skipto array of rules */
+ struct namedobj_instance *srvmap; /* cfg name->number mappings */
#if defined( __linux__ ) || defined( _WIN32 )
spinlock_t uh_lock;
#else
@@ -306,16 +308,15 @@ struct table_value {
uint64_t refcnt; /* Number of references */
};
-struct namedobj_instance;
struct named_object {
TAILQ_ENTRY(named_object) nn_next; /* namehash */
TAILQ_ENTRY(named_object) nv_next; /* valuehash */
char *name; /* object name */
- uint8_t type; /* object type */
- uint8_t compat; /* Object name is number */
+ uint8_t subtype; /* object subtype within class */
+ uint8_t etlv; /* Export TLV id */
+ uint16_t spare[2];
uint16_t kidx; /* object kernel index */
- uint16_t uidx; /* userland idx for compat records */
uint32_t set; /* set object belongs to */
uint32_t refcnt; /* number of references */
};
@@ -450,7 +451,7 @@ struct obj_idx {
struct rule_check_info {
uint16_t flags; /* rule-specific check flags */
- uint16_t table_opcodes; /* count of opcodes referencing table */
+ uint16_t object_opcodes; /* num of opcodes referencing objects */
uint16_t urule_numoff; /* offset of rulenum in bytes */
uint8_t version; /* rule version */
uint8_t spare;
@@ -507,6 +508,84 @@ struct ip_fw_bcounter0 {
(r)->cmd_len * 4 - 4, 8))
#define RULEKSIZE1(r) roundup2((sizeof(struct ip_fw) + (r)->cmd_len*4 - 4), 8)
+/*
+ * Tables/Objects index rewriting code
+ */
+
+/* Default and maximum number of ipfw tables/objects. */
+#define IPFW_TABLES_MAX 65536
+#define IPFW_TABLES_DEFAULT 128
+#define IPFW_OBJECTS_MAX 65536
+#define IPFW_OBJECTS_DEFAULT 128
+
+#define CHAIN_TO_SRV(ch) ((ch)->srvmap)
+
+struct tid_info {
+ uint32_t set; /* table set */
+ uint16_t uidx; /* table index */
+ uint8_t type; /* table type */
+ uint8_t atype;
+ uint8_t spare;
+ int tlen; /* Total TLV size block */
+ void *tlvs; /* Pointer to first TLV */
+};
+
+/*
+ * Classifier callback. Checks if @cmd opcode contains kernel object reference.
+ * If true, returns its index and type.
+ * Returns 0 if match is found, 1 overwise.
+ */
+typedef int (ipfw_obj_rw_cl)(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype);
+/*
+ * Updater callback. Sets kernel object reference index to @puidx
+ */
+typedef void (ipfw_obj_rw_upd)(ipfw_insn *cmd, uint16_t puidx);
+/*
+ * Finder callback. Tries to find named object by name (specified via @ti).
+ * Stores found named object pointer in @pno.
+ * If object was not found, NULL is stored.
+ *
+ * Return 0 if input data was valid.
+ */
+typedef int (ipfw_obj_fname_cb)(struct ip_fw_chain *ch,
+ struct tid_info *ti, struct named_object **pno);
+/*
+ * Another finder callback. Tries to findex named object by kernel index.
+ *
+ * Returns pointer to named object or NULL.
+ */
+typedef struct named_object *(ipfw_obj_fidx_cb)(struct ip_fw_chain *ch,
+ uint16_t kidx);
+/*
+ * Object creator callback. Tries to create object specified by @ti.
+ * Stores newly-allocated object index in @pkidx.
+ *
+ * Returns 0 on success.
+ */
+typedef int (ipfw_obj_create_cb)(struct ip_fw_chain *ch, struct tid_info *ti,
+ uint16_t *pkidx);
+
+
+struct opcode_obj_rewrite {
+ uint32_t opcode; /* Opcode to act upon */
+ uint32_t etlv; /* Relevant export TLV id */
+ ipfw_obj_rw_cl *classifier; /* Check if rewrite is needed */
+ ipfw_obj_rw_upd *update; /* update cmd with new value */
+ ipfw_obj_fname_cb *find_byname; /* Find named object by name */
+ ipfw_obj_fidx_cb *find_bykidx; /* Find named object by kidx */
+ ipfw_obj_create_cb *create_object; /* Create named object */
+};
+
+#define IPFW_ADD_OBJ_REWRITER(f, c) do { \
+ if ((f) != 0) \
+ ipfw_add_obj_rewriter(c, \
+ sizeof(c) / sizeof(c[0])); \
+ } while(0)
+#define IPFW_DEL_OBJ_REWRITER(l, c) do { \
+ if ((l) != 0) \
+ ipfw_del_obj_rewriter(c, \
+ sizeof(c) / sizeof(c[0])); \
+ } while(0)
/* In ip_fw_iface.c */
int ipfw_iface_init(void);
@@ -562,6 +641,7 @@ caddr_t ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed);
sizeof(c) / sizeof(c[0])); \
} while(0)
+struct namedobj_instance;
typedef void (objhash_cb_t)(struct namedobj_instance *ni, struct named_object *,
void *arg);
typedef uint32_t (objhash_hash_f)(struct namedobj_instance *ni, void *key,
@@ -578,6 +658,8 @@ void ipfw_objhash_bitmap_free(void *idx, int blocks);
void ipfw_objhash_set_hashf(struct namedobj_instance *ni, objhash_hash_f *f);
struct named_object *ipfw_objhash_lookup_name(struct namedobj_instance *ni,
uint32_t set, char *name);
+struct named_object *ipfw_objhash_lookup_name_type(struct namedobj_instance *ni,
+ uint32_t set, uint32_t type, char *name);
struct named_object *ipfw_objhash_lookup_kidx(struct namedobj_instance *ni,
uint16_t idx);
int ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
@@ -591,6 +673,25 @@ int ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx);
int ipfw_objhash_alloc_idx(void *n, uint16_t *pidx);
void ipfw_objhash_set_funcs(struct namedobj_instance *ni,
objhash_hash_f *hash_f, objhash_cmp_f *cmp_f);
+void ipfw_init_obj_rewriter(void);
+void ipfw_destroy_obj_rewriter(void);
+void ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count);
+int ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count);
+
+int ipfw_rewrite_rule_uidx(struct ip_fw_chain *chain,
+ struct rule_check_info *ci);
+int ipfw_mark_object_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
+ uint32_t *bmask);
+int ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti,
+ struct obj_idx *pidx, int *found, int *unresolved);
+void unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd,
+ struct obj_idx *oib, struct obj_idx *end);
+int create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd,
+ struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti);
+void update_opcode_kidx(ipfw_insn *cmd, uint16_t idx);
+int classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx);
+void ipfw_init_srv(struct ip_fw_chain *ch);
+void ipfw_destroy_srv(struct ip_fw_chain *ch);
/* In ip_fw_table.c */
struct table_info;
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index ef1ff6c..d618a6c 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -148,6 +148,21 @@ static struct ipfw_sopt_handler scodes[] = {
{ IP_FW_DUMP_SOPTCODES, 0, HDIR_GET, dump_soptcodes },
};
+static int
+set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule);
+struct opcode_obj_rewrite *ipfw_find_op_rw(uint16_t opcode);
+static int mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
+ uint32_t *bmask);
+static void unref_rule_objects(struct ip_fw_chain *chain, struct ip_fw *rule);
+static int export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
+ struct sockopt_data *sd);
+
+/*
+ * Opcode object rewriter variables
+ */
+struct opcode_obj_rewrite *ctl3_rewriters;
+static size_t ctl3_rsize;
+
/*
* static variables followed by global ones
*/
@@ -646,17 +661,18 @@ commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
struct ip_fw *krule;
struct ip_fw **map; /* the new array of pointers */
- /* Check if we need to do table remap */
+ /* Check if we need to do table/obj index remap */
tcount = 0;
for (ci = rci, i = 0; i < count; ci++, i++) {
- if (ci->table_opcodes == 0)
+ if (ci->object_opcodes == 0)
continue;
/*
- * Rule has some table opcodes.
- * Reference & allocate needed tables/
+ * Rule has some object opcodes.
+ * We need to find (and create non-existing)
+ * kernel objects, and reference existing ones.
*/
- error = ipfw_rewrite_table_uidx(chain, ci);
+ error = ipfw_rewrite_rule_uidx(chain, ci);
if (error != 0) {
/*
@@ -674,9 +690,9 @@ commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
IPFW_UH_WLOCK(chain);
while (ci != rci) {
ci--;
- if (ci->table_opcodes == 0)
+ if (ci->object_opcodes == 0)
continue;
- ipfw_unref_rule_tables(chain,ci->krule);
+ unref_rule_objects(chain,ci->krule);
}
IPFW_UH_WUNLOCK(chain);
@@ -696,10 +712,10 @@ commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
/* Unbind tables */
IPFW_UH_WLOCK(chain);
for (ci = rci, i = 0; i < count; ci++, i++) {
- if (ci->table_opcodes == 0)
+ if (ci->object_opcodes == 0)
continue;
- ipfw_unref_rule_tables(chain, ci->krule);
+ unref_rule_objects(chain, ci->krule);
}
IPFW_UH_WUNLOCK(chain);
}
@@ -759,7 +775,7 @@ ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head,
IPFW_UH_WLOCK_ASSERT(chain);
/* Unlink rule from everywhere */
- ipfw_unref_rule_tables(chain, rule);
+ unref_rule_objects(chain, rule);
*((struct ip_fw **)rule) = *head;
*head = rule;
@@ -1542,7 +1558,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
cmdlen != F_INSN_SIZE(ipfw_insn_u32))
goto bad_size;
- ci->table_opcodes++;
+ ci->object_opcodes++;
break;
case O_IP_FLOW_LOOKUP:
if (cmd->arg1 >= V_fw_tables_max) {
@@ -1553,7 +1569,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
cmdlen != F_INSN_SIZE(ipfw_insn_u32))
goto bad_size;
- ci->table_opcodes++;
+ ci->object_opcodes++;
break;
case O_MACADDR2:
if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
@@ -1587,7 +1603,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
case O_XMIT:
case O_VIA:
if (((ipfw_insn_if *)cmd)->name[0] == '\1')
- ci->table_opcodes++;
+ ci->object_opcodes++;
if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
goto bad_size;
break;
@@ -1788,7 +1804,7 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
l = RULESIZE7(rule);
if (bp + l + sizeof(uint32_t) <= ep) {
bcopy(rule, bp, l + sizeof(uint32_t));
- error = ipfw_rewrite_table_kidx(chain,
+ error = set_legacy_obj_kidx(chain,
(struct ip_fw_rule0 *)bp);
if (error != 0)
return (0);
@@ -1817,7 +1833,7 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
}
dst = (struct ip_fw_rule0 *)bp;
export_rule0(rule, dst, l);
- error = ipfw_rewrite_table_kidx(chain, dst);
+ error = set_legacy_obj_kidx(chain, dst);
/*
* XXX HACK. Store the disable mask in the "next"
@@ -1861,6 +1877,34 @@ struct dump_args {
};
/*
+ * Export named object info in instance @ni, identified by @kidx
+ * to ipfw_obj_ntlv. TLV is allocated from @sd space.
+ *
+ * Returns 0 on success.
+ */
+static int
+export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
+ struct sockopt_data *sd)
+{
+ struct named_object *no;
+ ipfw_obj_ntlv *ntlv;
+
+ no = ipfw_objhash_lookup_kidx(ni, kidx);
+ KASSERT(no != NULL, ("invalid object kernel index passed"));
+
+ ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
+ if (ntlv == NULL)
+ return (ENOMEM);
+
+ ntlv->head.type = no->etlv;
+ ntlv->head.length = sizeof(*ntlv);
+ ntlv->idx = no->kidx;
+ strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
+
+ return (0);
+}
+
+/*
* Dumps static rules with table TLVs in buffer @sd.
*
* Returns 0 on success.
@@ -1874,6 +1918,7 @@ dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
uint32_t tcount;
ipfw_obj_ctlv *ctlv;
struct ip_fw *krule;
+ struct namedobj_instance *ni;
caddr_t dst;
/* Dump table names first (if any) */
@@ -1891,13 +1936,21 @@ dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
i = 0;
tcount = da->tcount;
+ ni = ipfw_get_table_objhash(chain);
while (tcount > 0) {
if ((bmask[i / 32] & (1 << (i % 32))) == 0) {
i++;
continue;
}
- if ((error = ipfw_export_table_ntlv(chain, i, sd)) != 0)
+ /* Jump to shared named object bitmask */
+ if (i >= IPFW_TABLES_MAX) {
+ ni = CHAIN_TO_SRV(chain);
+ i -= IPFW_TABLES_MAX;
+ bmask += IPFW_TABLES_MAX / 32;
+ }
+
+ if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
return (error);
i++;
@@ -1929,6 +1982,52 @@ dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
}
/*
+ * Marks every object index used in @rule with bit in @bmask.
+ * Used to generate bitmask of referenced tables/objects for given ruleset
+ * or its part.
+ *
+ * Returns number of newly-referenced objects.
+ */
+static int
+mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
+ uint32_t *bmask)
+{
+ int cmdlen, l, count;
+ ipfw_insn *cmd;
+ uint16_t kidx;
+ struct opcode_obj_rewrite *rw;
+ int bidx;
+ uint8_t subtype;
+
+ l = rule->cmd_len;
+ cmd = rule->cmd;
+ cmdlen = 0;
+ count = 0;
+ for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
+ cmdlen = F_LEN(cmd);
+
+ rw = ipfw_find_op_rw(cmd->opcode);
+ if (rw == NULL)
+ continue;
+
+ if (rw->classifier(cmd, &kidx, &subtype) != 0)
+ continue;
+
+ bidx = kidx / 32;
+ /* Maintain separate bitmasks for table and non-table objects */
+ if (rw->etlv != IPFW_TLV_TBL_NAME)
+ bidx += IPFW_TABLES_MAX / 32;
+
+ if ((bmask[bidx] & (1 << (kidx % 32))) == 0)
+ count++;
+
+ bmask[bidx] |= 1 << (kidx % 32);
+ }
+
+ return (count);
+}
+
+/*
* Dumps requested objects data
* Data layout (version 0)(current):
* Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags
@@ -1963,9 +2062,9 @@ dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
error = 0;
bmask = NULL;
- /* Allocate needed state */
+ /* Allocate needed state. Note we allocate 2xspace mask, for table&srv */
if (hdr->flags & IPFW_CFG_GET_STATIC)
- bmask = malloc(IPFW_TABLES_MAX / 8, M_TEMP, M_WAITOK | M_ZERO);
+ bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO);
IPFW_UH_RLOCK(chain);
@@ -1994,7 +2093,8 @@ dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
rule = chain->map[i];
da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv);
da.rcount++;
- da.tcount += ipfw_mark_table_kidx(chain, rule, bmask);
+ /* Update bitmask of used objects for given range */
+ da.tcount += mark_object_kidx(chain, rule, bmask);
}
/* Add counters if requested */
if (hdr->flags & IPFW_CFG_GET_COUNTERS) {
@@ -2064,6 +2164,241 @@ check_object_name(ipfw_obj_ntlv *ntlv)
}
/*
+ * Creates non-existent objects referenced by rule.
+ *
+ * Return 0 on success.
+ */
+int
+create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd,
+ struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti)
+{
+ struct opcode_obj_rewrite *rw;
+ struct obj_idx *p;
+ uint16_t kidx;
+ int error;
+
+ /*
+ * Compatibility stuff: do actual creation for non-existing,
+ * but referenced objects.
+ */
+ for (p = oib; p < pidx; p++) {
+ if (p->kidx != 0)
+ continue;
+
+ ti->uidx = p->uidx;
+ ti->type = p->type;
+ ti->atype = 0;
+
+ rw = ipfw_find_op_rw((cmd + p->off)->opcode);
+ KASSERT(rw != NULL, ("Unable to find handler for op %d",
+ (cmd + p->off)->opcode));
+
+ error = rw->create_object(ch, ti, &kidx);
+ if (error == 0) {
+ p->kidx = kidx;
+ continue;
+ }
+
+ /*
+ * Error happened. We have to rollback everything.
+ * Drop all already acquired references.
+ */
+ IPFW_UH_WLOCK(ch);
+ unref_oib_objects(ch, cmd, oib, pidx);
+ IPFW_UH_WUNLOCK(ch);
+
+ return (error);
+ }
+
+ return (0);
+}
+
+/*
+ * Compatibility function for old ipfw(8) binaries.
+ * Rewrites table/nat kernel indices with userland ones.
+ * Convert tables matching '/^\d+$/' to their atoi() value.
+ * Use number 65535 for other tables.
+ *
+ * Returns 0 on success.
+ */
+static int
+set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule)
+{
+ int cmdlen, error, l;
+ ipfw_insn *cmd;
+ uint16_t kidx, uidx;
+ struct named_object *no;
+ struct opcode_obj_rewrite *rw;
+ uint8_t subtype;
+ char *end;
+ long val;
+
+ error = 0;
+
+ l = rule->cmd_len;
+ cmd = rule->cmd;
+ cmdlen = 0;
+ for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
+ cmdlen = F_LEN(cmd);
+
+ rw = ipfw_find_op_rw(cmd->opcode);
+ if (rw == NULL)
+ continue;
+
+ /* Check if is index in given opcode */
+ if (rw->classifier(cmd, &kidx, &subtype) != 0)
+ continue;
+
+ /* Try to find referenced kernel object */
+ no = rw->find_bykidx(ch, kidx);
+ if (no == NULL)
+ continue;
+
+ val = strtol(no->name, &end, 10);
+ if (*end == '\0' && val < 65535) {
+ uidx = val;
+ } else {
+
+ /*
+ * We are called via legacy opcode.
+ * Save error and show table as fake number
+ * not to make ipfw(8) hang.
+ */
+ uidx = 65535;
+ error = 2;
+ }
+
+ rw->update(cmd, uidx);
+ }
+
+ return (error);
+}
+
+
+/*
+ * Unreferences all already-referenced objects in given @cmd rule,
+ * using information in @oib.
+ *
+ * Used to rollback partially converted rule on error.
+ */
+void
+unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib,
+ struct obj_idx *end)
+{
+ struct opcode_obj_rewrite *rw;
+ struct named_object *no;
+ struct obj_idx *p;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+
+ for (p = oib; p < end; p++) {
+ if (p->kidx == 0)
+ continue;
+
+ rw = ipfw_find_op_rw((cmd + p->off)->opcode);
+ KASSERT(rw != NULL, ("Unable to find handler for op %d",
+ (cmd + p->off)->opcode));
+
+ /* Find & unref by existing idx */
+ no = rw->find_bykidx(ch, p->kidx);
+ KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx));
+ no->refcnt--;
+ }
+}
+
+/*
+ * Remove references from every object used in @rule.
+ * Used at rule removal code.
+ */
+static void
+unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule)
+{
+ int cmdlen, l;
+ ipfw_insn *cmd;
+ struct named_object *no;
+ uint16_t kidx;
+ struct opcode_obj_rewrite *rw;
+ uint8_t subtype;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+
+ l = rule->cmd_len;
+ cmd = rule->cmd;
+ cmdlen = 0;
+ for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
+ cmdlen = F_LEN(cmd);
+
+ rw = ipfw_find_op_rw(cmd->opcode);
+ if (rw == NULL)
+ continue;
+ if (rw->classifier(cmd, &kidx, &subtype) != 0)
+ continue;
+
+ no = rw->find_bykidx(ch, kidx);
+
+ KASSERT(no != NULL, ("table id %d not found", kidx));
+ KASSERT(no->subtype == subtype,
+ ("wrong type %d (%d) for table id %d",
+ no->subtype, subtype, kidx));
+ KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
+ kidx, no->refcnt));
+
+ no->refcnt--;
+ }
+}
+
+
+/*
+ * Find and reference object (if any) stored in instruction @cmd.
+ *
+ * Saves object info in @pidx, sets
+ * - @found to 1 if object was found and references
+ * - @unresolved to 1 if object should exists but not found
+ *
+ * Returns non-zero value in case of error.
+ */
+int
+ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti,
+ struct obj_idx *pidx, int *found, int *unresolved)
+{
+ struct named_object *no;
+ struct opcode_obj_rewrite *rw;
+ int error;
+
+ *found = 0;
+ *unresolved = 0;
+
+ /* Check if this opcode is candidate for rewrite */
+ rw = ipfw_find_op_rw(cmd->opcode);
+ if (rw == NULL)
+ return (0);
+
+ /* Check if we need to rewrite this opcode */
+ if (rw->classifier(cmd, &ti->uidx, &ti->type) != 0)
+ return (0);
+
+ /* Need to rewrite. Save necessary fields */
+ pidx->uidx = ti->uidx;
+ pidx->type = ti->type;
+
+ /* Try to find referenced kernel object */
+ error = rw->find_byname(ch, ti, &no);
+ if (error != 0)
+ return (error);
+ if (no == NULL) {
+ *unresolved = 1;
+ return (0);
+ }
+
+ /* Found. bump refcount */
+ *found = 1;
+ no->refcnt++;
+ pidx->kidx = no->kidx;
+
+ return (0);
+}
+
+/*
* Adds one or more rules to ipfw @chain.
* Data layout (version 0)(current):
* Request:
@@ -2315,6 +2650,160 @@ dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
}
/*
+ * Compares two opcodes.
+ * Used both in qsort() and bsearch().
+ *
+ * Returns 0 if match is found.
+ */
+static int
+compare_opcodes(const void *_a, const void *_b)
+{
+ const struct opcode_obj_rewrite *a, *b;
+
+ a = (const struct opcode_obj_rewrite *)_a;
+ b = (const struct opcode_obj_rewrite *)_b;
+
+ if (a->opcode < b->opcode)
+ return (-1);
+ else if (a->opcode > b->opcode)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Finds opcode object rewriter based on @code.
+ *
+ * Returns pointer to handler or NULL.
+ */
+struct opcode_obj_rewrite *
+ipfw_find_op_rw(uint16_t opcode)
+{
+ struct opcode_obj_rewrite *rw, h;
+
+ memset(&h, 0, sizeof(h));
+ h.opcode = opcode;
+
+ rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters,
+ ctl3_rsize, sizeof(h), compare_opcodes);
+
+ return (rw);
+}
+
+int
+classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx)
+{
+ struct opcode_obj_rewrite *rw;
+ uint8_t subtype;
+
+ rw = ipfw_find_op_rw(cmd->opcode);
+ if (rw == NULL)
+ return (1);
+
+ return (rw->classifier(cmd, puidx, &subtype));
+}
+
+void
+update_opcode_kidx(ipfw_insn *cmd, uint16_t idx)
+{
+ struct opcode_obj_rewrite *rw;
+
+ rw = ipfw_find_op_rw(cmd->opcode);
+ KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode));
+ rw->update(cmd, idx);
+}
+
+void
+ipfw_init_obj_rewriter()
+{
+
+ ctl3_rewriters = NULL;
+ ctl3_rsize = 0;
+}
+
+void
+ipfw_destroy_obj_rewriter()
+{
+
+ if (ctl3_rewriters != NULL)
+ free(ctl3_rewriters, M_IPFW);
+ ctl3_rewriters = NULL;
+ ctl3_rsize = 0;
+}
+
+/*
+ * Adds one or more opcode object rewrite handlers to the global array.
+ * Function may sleep.
+ */
+void
+ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
+{
+ size_t sz;
+ struct opcode_obj_rewrite *tmp;
+
+ CTL3_LOCK();
+
+ for (;;) {
+ sz = ctl3_rsize + count;
+ CTL3_UNLOCK();
+ tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO);
+ CTL3_LOCK();
+ if (ctl3_rsize + count <= sz)
+ break;
+
+ /* Retry */
+ free(tmp, M_IPFW);
+ }
+
+ /* Merge old & new arrays */
+ sz = ctl3_rsize + count;
+ memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw));
+ memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw));
+ qsort(tmp, sz, sizeof(*rw), compare_opcodes);
+ /* Switch new and free old */
+ if (ctl3_rewriters != NULL)
+ free(ctl3_rewriters, M_IPFW);
+ ctl3_rewriters = tmp;
+ ctl3_rsize = sz;
+
+ CTL3_UNLOCK();
+}
+
+/*
+ * Removes one or more object rewrite handlers from the global array.
+ */
+int
+ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
+{
+ size_t sz;
+ struct opcode_obj_rewrite *tmp, *h;
+ int i;
+
+ CTL3_LOCK();
+
+ for (i = 0; i < count; i++) {
+ tmp = &rw[i];
+ h = ipfw_find_op_rw(tmp->opcode);
+ if (h == NULL)
+ continue;
+
+ sz = (ctl3_rewriters + ctl3_rsize - (h + 1)) * sizeof(*h);
+ memmove(h, h + 1, sz);
+ ctl3_rsize--;
+ }
+
+ if (ctl3_rsize == 0) {
+ if (ctl3_rewriters != NULL)
+ free(ctl3_rewriters, M_IPFW);
+ ctl3_rewriters = NULL;
+ }
+
+ CTL3_UNLOCK();
+
+ return (0);
+}
+
+/*
* Compares two sopt handlers (code, version and handler ptr).
* Used both as qsort() and bsearch().
* Does not compare handler for latter case.
@@ -3150,6 +3639,23 @@ convert_rule_to_8(struct ip_fw_rule0 *rule)
*
*/
+void
+ipfw_init_srv(struct ip_fw_chain *ch)
+{
+
+ ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT);
+ ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT,
+ M_IPFW, M_WAITOK | M_ZERO);
+}
+
+void
+ipfw_destroy_srv(struct ip_fw_chain *ch)
+{
+
+ free(ch->srvstate, M_IPFW);
+ ipfw_objhash_destroy(ch->srvmap);
+}
+
/*
* Allocate new bitmask which can be used to enlarge/shrink
* named instance index.
@@ -3323,6 +3829,26 @@ ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name)
return (NULL);
}
+/*
+ * Find named object by name, considering also its TLV type.
+ */
+struct named_object *
+ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set,
+ uint32_t type, char *name)
+{
+ struct named_object *no;
+ uint32_t hash;
+
+ hash = ni->hash_f(ni, name, set) % ni->nn_size;
+
+ TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
+ if (ni->cmp_f(no, name, set) == 0 && no->etlv == type)
+ return (no);
+ }
+
+ return (NULL);
+}
+
struct named_object *
ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx)
{
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index 4498ace..ca4e0e4 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -89,6 +89,8 @@ struct table_config {
struct namedobj_instance *vi;
};
+static int find_table_err(struct namedobj_instance *ni, struct tid_info *ti,
+ struct table_config **tc);
static struct table_config *find_table(struct namedobj_instance *ni,
struct tid_info *ti);
static struct table_config *alloc_table_config(struct ip_fw_chain *ch,
@@ -122,7 +124,6 @@ static struct table_algo *find_table_algo(struct tables_config *tableconf,
static void objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti);
static void ntlv_to_ti(struct _ipfw_obj_ntlv *ntlv, struct tid_info *ti);
-static int classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype);
#define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash)
#define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k]))
@@ -297,7 +298,7 @@ find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti,
tc = NULL;
if ((tc = find_table(ni, ti)) != NULL) {
/* check table type */
- if (tc->no.type != ti->type)
+ if (tc->no.subtype != ti->type)
return (EINVAL);
if (tc->locked != 0)
@@ -1116,7 +1117,7 @@ find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
}
/* check table type */
- if (tc->no.type != ti.type) {
+ if (tc->no.subtype != ti.type) {
IPFW_UH_RUNLOCK(ch);
return (EINVAL);
}
@@ -1399,7 +1400,7 @@ swap_tables(struct ip_fw_chain *ch, struct tid_info *a,
}
/* Check type and value are the same */
- if (tc_a->no.type != tc_b->no.type || tc_a->tflags != tc_b->tflags) {
+ if (tc_a->no.subtype!=tc_b->no.subtype || tc_a->tflags!=tc_b->tflags) {
IPFW_UH_WUNLOCK(ch);
return (EINVAL);
}
@@ -1613,7 +1614,6 @@ ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int sets)
ipfw_insn *cmd;
int cmdlen, i, l;
uint16_t kidx;
- uint8_t type;
IPFW_UH_WLOCK(ch);
@@ -1636,7 +1636,7 @@ ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int sets)
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
cmdlen = F_LEN(cmd);
- if (classify_table_opcode(cmd, &kidx, &type) != 0)
+ if (classify_opcode_kidx(cmd, &kidx) != 0)
continue;
no = ipfw_objhash_lookup_kidx(ni, kidx);
@@ -1920,7 +1920,7 @@ create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
* requesting to create existing table
* which has the same type
*/
- if (compat == 0 || tc_new->no.type != tc->no.type) {
+ if (compat == 0 || tc_new->no.subtype != tc->no.subtype) {
IPFW_UH_WUNLOCK(ch);
free_table_config(ni, tc);
return (EEXIST);
@@ -1940,6 +1940,7 @@ create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
return (EBUSY);
}
tc->no.kidx = kidx;
+ tc->no.etlv = IPFW_TLV_TBL_NAME;
IPFW_WLOCK(ch);
link_table(ch, tc);
@@ -1977,6 +1978,13 @@ objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
ntlv_to_ti(&oh->ntlv, ti);
}
+struct namedobj_instance *
+ipfw_get_table_objhash(struct ip_fw_chain *ch)
+{
+
+ return (CHAIN_TO_NI(ch));
+}
+
/*
* Exports basic table info as name TLV.
* Used inside dump_static_rules() to provide info
@@ -2009,40 +2017,6 @@ ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
return (0);
}
-/*
- * Marks every table kidx used in @rule with bit in @bmask.
- * Used to generate bitmask of referenced tables for given ruleset.
- *
- * Returns number of newly-referenced tables.
- */
-int
-ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
- uint32_t *bmask)
-{
- int cmdlen, l, count;
- ipfw_insn *cmd;
- uint16_t kidx;
- uint8_t type;
-
- l = rule->cmd_len;
- cmd = rule->cmd;
- cmdlen = 0;
- count = 0;
- for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
- cmdlen = F_LEN(cmd);
-
- if (classify_table_opcode(cmd, &kidx, &type) != 0)
- continue;
-
- if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0)
- count++;
-
- bmask[kidx / 32] |= 1 << (kidx % 32);
- }
-
- return (count);
-}
-
struct dump_args {
struct ip_fw_chain *ch;
struct table_info *ti;
@@ -2111,7 +2085,7 @@ export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
struct table_info *ti;
struct table_algo *ta;
- i->type = tc->no.type;
+ i->type = tc->no.subtype;
i->tflags = tc->tflags;
i->vmask = tc->vmask;
i->set = tc->no.set;
@@ -2296,7 +2270,7 @@ dump_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
xtbl->cnt = count;
xtbl->size = sz;
- xtbl->type = tc->no.type;
+ xtbl->type = tc->no.subtype;
xtbl->tbl = ti.uidx;
if (sd->valsize < sz) {
@@ -2440,7 +2414,7 @@ ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
ta = tc->ta;
/* This dump format supports IPv4 only */
- if (tc->no.type != IPFW_TABLE_ADDR)
+ if (tc->no.subtype != IPFW_TABLE_ADDR)
return (0);
memset(&da, 0, sizeof(da));
@@ -2531,7 +2505,7 @@ dump_table_xentry(void *e, void *arg)
pval = get_table_value(da->ch, da->tc, da->tent.v.kidx);
xent->value = ipfw_export_table_value_legacy(pval);
/* Apply some hacks */
- if (tc->no.type == IPFW_TABLE_ADDR && tent->subtype == AF_INET) {
+ if (tc->no.subtype == IPFW_TABLE_ADDR && tent->subtype == AF_INET) {
xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr;
xent->flags = IPFW_TCF_INET;
} else
@@ -2781,114 +2755,157 @@ list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
return (0);
}
-/*
- * Tables rewriting code
- */
-
-/*
- * Determine table number and lookup type for @cmd.
- * Fill @tbl and @type with appropriate values.
- * Returns 0 for relevant opcodes, 1 otherwise.
- */
static int
-classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
+classify_srcdst(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
{
- ipfw_insn_if *cmdif;
- int skip;
- uint16_t v;
-
- skip = 1;
-
- switch (cmd->opcode) {
- case O_IP_SRC_LOOKUP:
- case O_IP_DST_LOOKUP:
- /* Basic IPv4/IPv6 or u32 lookups */
- *puidx = cmd->arg1;
- /* Assume ADDR by default */
- *ptype = IPFW_TABLE_ADDR;
- skip = 0;
+ /* Basic IPv4/IPv6 or u32 lookups */
+ *puidx = cmd->arg1;
+ /* Assume ADDR by default */
+ *ptype = IPFW_TABLE_ADDR;
+ int v;
- if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) {
- /*
- * generic lookup. The key must be
- * in 32bit big-endian format.
- */
- v = ((ipfw_insn_u32 *)cmd)->d[1];
- switch (v) {
- case 0:
- case 1:
- /* IPv4 src/dst */
- break;
- case 2:
- case 3:
- /* src/dst port */
- *ptype = IPFW_TABLE_NUMBER;
- break;
- case 4:
- /* uid/gid */
- *ptype = IPFW_TABLE_NUMBER;
- break;
- case 5:
- /* jid */
- *ptype = IPFW_TABLE_NUMBER;
- break;
- case 6:
- /* dscp */
- *ptype = IPFW_TABLE_NUMBER;
- break;
- }
- }
- break;
- case O_XMIT:
- case O_RECV:
- case O_VIA:
- /* Interface table, possibly */
- cmdif = (ipfw_insn_if *)cmd;
- if (cmdif->name[0] != '\1')
+ if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) {
+ /*
+ * generic lookup. The key must be
+ * in 32bit big-endian format.
+ */
+ v = ((ipfw_insn_u32 *)cmd)->d[1];
+ switch (v) {
+ case 0:
+ case 1:
+ /* IPv4 src/dst */
break;
-
- *ptype = IPFW_TABLE_INTERFACE;
- *puidx = cmdif->p.kidx;
- skip = 0;
- break;
- case O_IP_FLOW_LOOKUP:
- *puidx = cmd->arg1;
- *ptype = IPFW_TABLE_FLOW;
- skip = 0;
- break;
+ case 2:
+ case 3:
+ /* src/dst port */
+ *ptype = IPFW_TABLE_NUMBER;
+ break;
+ case 4:
+ /* uid/gid */
+ *ptype = IPFW_TABLE_NUMBER;
+ break;
+ case 5:
+ /* jid */
+ *ptype = IPFW_TABLE_NUMBER;
+ break;
+ case 6:
+ /* dscp */
+ *ptype = IPFW_TABLE_NUMBER;
+ break;
+ }
}
- return (skip);
+ return (0);
+}
+
+static int
+classify_via(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
+{
+ ipfw_insn_if *cmdif;
+
+ /* Interface table, possibly */
+ cmdif = (ipfw_insn_if *)cmd;
+ if (cmdif->name[0] != '\1')
+ return (1);
+
+ *ptype = IPFW_TABLE_INTERFACE;
+ *puidx = cmdif->p.kidx;
+
+ return (0);
+}
+
+static int
+classify_flow(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
+{
+
+ *puidx = cmd->arg1;
+ *ptype = IPFW_TABLE_FLOW;
+
+ return (0);
+}
+
+static void
+update_arg1(ipfw_insn *cmd, uint16_t idx)
+{
+
+ cmd->arg1 = idx;
}
-/*
- * Sets new table value for given opcode.
- * Assume the same opcodes as classify_table_opcode()
- */
static void
-update_table_opcode(ipfw_insn *cmd, uint16_t idx)
+update_via(ipfw_insn *cmd, uint16_t idx)
{
ipfw_insn_if *cmdif;
- switch (cmd->opcode) {
- case O_IP_SRC_LOOKUP:
- case O_IP_DST_LOOKUP:
- /* Basic IPv4/IPv6 or u32 lookups */
- cmd->arg1 = idx;
- break;
- case O_XMIT:
- case O_RECV:
- case O_VIA:
- /* Interface table, possibly */
- cmdif = (ipfw_insn_if *)cmd;
- cmdif->p.kidx = idx;
- break;
- case O_IP_FLOW_LOOKUP:
- cmd->arg1 = idx;
- break;
- }
+ cmdif = (ipfw_insn_if *)cmd;
+ cmdif->p.kidx = idx;
}
+static int
+table_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
+ struct named_object **pno)
+{
+ struct table_config *tc;
+ int error;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+
+ error = find_table_err(CHAIN_TO_NI(ch), ti, &tc);
+ if (error != 0)
+ return (error);
+
+ *pno = &tc->no;
+ return (0);
+}
+
+/* XXX: sets-sets! */
+static struct named_object *
+table_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
+{
+ struct namedobj_instance *ni;
+ struct table_config *tc;
+
+ IPFW_UH_WLOCK_ASSERT(ch);
+ ni = CHAIN_TO_NI(ch);
+ tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, idx);
+ KASSERT(tc != NULL, ("Table with index %d not found", idx));
+
+ return (&tc->no);
+}
+
+static struct opcode_obj_rewrite opcodes[] = {
+ {
+ O_IP_SRC_LOOKUP, IPFW_TLV_TBL_NAME,
+ classify_srcdst, update_arg1,
+ table_findbyname, table_findbykidx, create_table_compat
+ },
+ {
+ O_IP_DST_LOOKUP, IPFW_TLV_TBL_NAME,
+ classify_srcdst, update_arg1,
+ table_findbyname, table_findbykidx, create_table_compat
+ },
+ {
+ O_IP_FLOW_LOOKUP, IPFW_TLV_TBL_NAME,
+ classify_flow, update_arg1,
+ table_findbyname, table_findbykidx, create_table_compat
+ },
+ {
+ O_XMIT, IPFW_TLV_TBL_NAME,
+ classify_via, update_via,
+ table_findbyname, table_findbykidx, create_table_compat
+ },
+ {
+ O_RECV, IPFW_TLV_TBL_NAME,
+ classify_via, update_via,
+ table_findbyname, table_findbykidx, create_table_compat
+ },
+ {
+ O_VIA, IPFW_TLV_TBL_NAME,
+ classify_via, update_via,
+ table_findbyname, table_findbykidx, create_table_compat
+ },
+};
+
+
/*
* Checks table name for validity.
* Enforce basic length checks, the rest
@@ -2960,10 +2977,11 @@ find_name_tlv(void *tlvs, int len, uint16_t uidx)
* or name in ntlv.
* Note @ti structure contains unchecked data from userland.
*
- * Returns pointer to table_config or NULL.
+ * Returns 0 in success and fills in @tc with found config
*/
-static struct table_config *
-find_table(struct namedobj_instance *ni, struct tid_info *ti)
+static int
+find_table_err(struct namedobj_instance *ni, struct tid_info *ti,
+ struct table_config **tc)
{
char *name, bname[16];
struct named_object *no;
@@ -2973,7 +2991,7 @@ find_table(struct namedobj_instance *ni, struct tid_info *ti)
if (ti->tlvs != NULL) {
ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx);
if (ntlv == NULL)
- return (NULL);
+ return (EINVAL);
name = ntlv->name;
/*
@@ -2989,8 +3007,27 @@ find_table(struct namedobj_instance *ni, struct tid_info *ti)
}
no = ipfw_objhash_lookup_name(ni, set, name);
+ *tc = (struct table_config *)no;
+
+ return (0);
+}
+
+/*
+ * Finds table config based on either legacy index
+ * or name in ntlv.
+ * Note @ti structure contains unchecked data from userland.
+ *
+ * Returns pointer to table_config or NULL.
+ */
+static struct table_config *
+find_table(struct namedobj_instance *ni, struct tid_info *ti)
+{
+ struct table_config *tc;
+
+ if (find_table_err(ni, ti, &tc) != 0)
+ return (NULL);
- return ((struct table_config *)no);
+ return (tc);
}
/*
@@ -3016,6 +3053,7 @@ alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti,
name = ntlv->name;
set = ntlv->set;
} else {
+ /* Compat part: convert number to string representation */
snprintf(bname, sizeof(bname), "%d", ti->uidx);
name = bname;
set = 0;
@@ -3023,7 +3061,7 @@ alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti,
tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO);
tc->no.name = tc->tablename;
- tc->no.type = ta->type;
+ tc->no.subtype = ta->type;
tc->no.set = set;
tc->tflags = tflags;
tc->ta = ta;
@@ -3031,11 +3069,6 @@ alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti,
/* Set "shared" value type by default */
tc->vshared = 1;
- if (ti->tlvs == NULL) {
- tc->no.compat = 1;
- tc->no.uidx = ti->uidx;
- }
-
/* Preallocate data structures for new tables */
error = ta->init(ch, &tc->astate, &tc->ti_copy, aname, tflags);
if (error != 0) {
@@ -3211,7 +3244,6 @@ ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt,
struct namedobj_instance *ni;
int bad, i, l, cmdlen;
uint16_t kidx;
- uint8_t type;
ipfw_insn *cmd;
IPFW_UH_WLOCK_ASSERT(ch);
@@ -3229,7 +3261,7 @@ ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt,
cmdlen = 0;
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
cmdlen = F_LEN(cmd);
- if (classify_table_opcode(cmd, &kidx, &type) != 0)
+ if (classify_opcode_kidx(cmd, &kidx) != 0)
continue;
no = ipfw_objhash_lookup_kidx(ni, kidx);
KASSERT(no != NULL,
@@ -3252,7 +3284,7 @@ ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt,
cmdlen = 0;
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
cmdlen = F_LEN(cmd);
- if (classify_table_opcode(cmd, &kidx, &type) != 0)
+ if (classify_opcode_kidx(cmd, &kidx) != 0)
continue;
no = ipfw_objhash_lookup_kidx(ni, kidx);
KASSERT(no != NULL,
@@ -3291,7 +3323,7 @@ ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt,
cmdlen = 0;
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
cmdlen = F_LEN(cmd);
- if (classify_table_opcode(cmd, &kidx, &type) != 0)
+ if (classify_opcode_kidx(cmd, &kidx) != 0)
continue;
no = ipfw_objhash_lookup_kidx(ni, kidx);
KASSERT(no != NULL,
@@ -3313,215 +3345,68 @@ ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt,
}
/*
- * Finds and bumps refcount for tables referenced by given @rule.
+ * Finds and bumps refcount for objects referenced by given @rule.
* Auto-creates non-existing tables.
* Fills in @oib array with userland/kernel indexes.
- * First free oidx pointer is saved back in @oib.
*
* Returns 0 on success.
*/
static int
-find_ref_rule_tables(struct ip_fw_chain *ch, struct ip_fw *rule,
- struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti)
+ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
+ struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti)
{
- struct table_config *tc;
- struct namedobj_instance *ni;
- struct named_object *no;
int cmdlen, error, l, numnew;
- uint16_t kidx;
ipfw_insn *cmd;
- struct obj_idx *pidx, *pidx_first, *p;
+ struct obj_idx *pidx;
+ int found, unresolved;
- pidx_first = *oib;
- pidx = pidx_first;
+ pidx = oib;
l = rule->cmd_len;
cmd = rule->cmd;
cmdlen = 0;
error = 0;
numnew = 0;
+ found = 0;
+ unresolved = 0;
IPFW_UH_WLOCK(ch);
- ni = CHAIN_TO_NI(ch);
/* Increase refcount on each existing referenced table. */
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
cmdlen = F_LEN(cmd);
- if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0)
- continue;
-
- pidx->uidx = ti->uidx;
- pidx->type = ti->type;
-
- if ((tc = find_table(ni, ti)) != NULL) {
- if (tc->no.type != ti->type) {
- /* Incompatible types */
- error = EINVAL;
- break;
- }
-
- /* Reference found table and save kidx */
- tc->no.refcnt++;
- pidx->kidx = tc->no.kidx;
+ error = ref_opcode_object(ch, cmd, ti, pidx, &found, &unresolved);
+ if (error != 0)
+ break;
+ if (found || unresolved) {
+ pidx->off = rule->cmd_len - l;
pidx++;
- continue;
}
-
/*
* Compability stuff for old clients:
- * prepare to manually create non-existing tables.
+ * prepare to manually create non-existing objects.
*/
- pidx++;
- numnew++;
+ if (unresolved)
+ numnew++;
}
if (error != 0) {
/* Unref everything we have already done */
- for (p = *oib; p < pidx; p++) {
- if (p->kidx == 0)
- continue;
-
- /* Find & unref by existing idx */
- no = ipfw_objhash_lookup_kidx(ni, p->kidx);
- KASSERT(no != NULL, ("Ref'd table %d disappeared",
- p->kidx));
-
- no->refcnt--;
- }
- }
-
- IPFW_UH_WUNLOCK(ch);
-
- if (numnew == 0) {
- *oib = pidx;
- return (error);
- }
-
- /*
- * Compatibility stuff: do actual creation for non-existing,
- * but referenced tables.
- */
- for (p = pidx_first; p < pidx; p++) {
- if (p->kidx != 0)
- continue;
-
- ti->uidx = p->uidx;
- ti->type = p->type;
- ti->atype = 0;
-
- error = create_table_compat(ch, ti, &kidx);
- if (error == 0) {
- p->kidx = kidx;
- continue;
- }
-
- /* Error. We have to drop references */
- IPFW_UH_WLOCK(ch);
- for (p = pidx_first; p < pidx; p++) {
- if (p->kidx == 0)
- continue;
-
- /* Find & unref by existing idx */
- no = ipfw_objhash_lookup_kidx(ni, p->kidx);
- KASSERT(no != NULL, ("Ref'd table %d disappeared",
- p->kidx));
-
- no->refcnt--;
- }
+ unref_oib_objects(ch, rule->cmd, oib, pidx);
IPFW_UH_WUNLOCK(ch);
-
return (error);
}
- *oib = pidx;
-
- return (error);
-}
-
-/*
- * Remove references from every table used in @rule.
- */
-void
-ipfw_unref_rule_tables(struct ip_fw_chain *chain, struct ip_fw *rule)
-{
- int cmdlen, l;
- ipfw_insn *cmd;
- struct namedobj_instance *ni;
- struct named_object *no;
- uint16_t kidx;
- uint8_t type;
-
- IPFW_UH_WLOCK_ASSERT(chain);
- ni = CHAIN_TO_NI(chain);
-
- l = rule->cmd_len;
- cmd = rule->cmd;
- cmdlen = 0;
- for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
- cmdlen = F_LEN(cmd);
-
- if (classify_table_opcode(cmd, &kidx, &type) != 0)
- continue;
-
- no = ipfw_objhash_lookup_kidx(ni, kidx);
-
- KASSERT(no != NULL, ("table id %d not found", kidx));
- KASSERT(no->type == type, ("wrong type %d (%d) for table id %d",
- no->type, type, kidx));
- KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
- kidx, no->refcnt));
-
- no->refcnt--;
- }
-}
-
-/*
- * Compatibility function for old ipfw(8) binaries.
- * Rewrites table kernel indices with userland ones.
- * Convert tables matching '/^\d+$/' to their atoi() value.
- * Use number 65535 for other tables.
- *
- * Returns 0 on success.
- */
-int
-ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw_rule0 *rule)
-{
- int cmdlen, error, l;
- ipfw_insn *cmd;
- uint16_t kidx, uidx;
- uint8_t type;
- struct named_object *no;
- struct namedobj_instance *ni;
-
- ni = CHAIN_TO_NI(chain);
- error = 0;
-
- l = rule->cmd_len;
- cmd = rule->cmd;
- cmdlen = 0;
- for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
- cmdlen = F_LEN(cmd);
-
- if (classify_table_opcode(cmd, &kidx, &type) != 0)
- continue;
+ IPFW_UH_WUNLOCK(ch);
- if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL)
- return (1);
+ found = pidx - oib;
+ KASSERT(found == ci->object_opcodes,
+ ("refcount inconsistency: found: %d total: %d",
+ found, ci->object_opcodes));
- uidx = no->uidx;
- if (no->compat == 0) {
-
- /*
- * We are called via legacy opcode.
- * Save error and show table as fake number
- * not to make ipfw(8) hang.
- */
- uidx = 65535;
- error = 2;
- }
-
- update_table_opcode(cmd, uidx);
- }
+ /* Perform auto-creation for non-existing objects */
+ if (numnew != 0)
+ error = create_objects_compat(ch, rule->cmd, oib, pidx, ti);
return (error);
}
@@ -3534,31 +3419,27 @@ ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw_rule0 *rule)
* Returns 0 on success and appropriate error code otherwise.
*/
int
-ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
+ipfw_rewrite_rule_uidx(struct ip_fw_chain *chain,
struct rule_check_info *ci)
{
- int cmdlen, error, l;
+ int error;
ipfw_insn *cmd;
- uint16_t uidx;
uint8_t type;
- struct namedobj_instance *ni;
struct obj_idx *p, *pidx_first, *pidx_last;
struct tid_info ti;
- ni = CHAIN_TO_NI(chain);
-
/*
* Prepare an array for storing opcode indices.
* Use stack allocation by default.
*/
- if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
+ if (ci->object_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
/* Stack */
pidx_first = ci->obuf;
} else
- pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx),
+ pidx_first = malloc(ci->object_opcodes * sizeof(struct obj_idx),
M_IPFW, M_WAITOK | M_ZERO);
- pidx_last = pidx_first;
+ pidx_last = pidx_first + ci->object_opcodes;
error = 0;
type = 0;
memset(&ti, 0, sizeof(ti));
@@ -3573,28 +3454,18 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
}
- /* Reference all used tables */
- error = find_ref_rule_tables(chain, ci->krule, ci, &pidx_last, &ti);
+ /* Reference all used tables and other objects */
+ error = ref_rule_objects(chain, ci->krule, ci, pidx_first, &ti);
if (error != 0)
goto free;
- IPFW_UH_WLOCK(chain);
-
/* Perform rule rewrite */
- l = ci->krule->cmd_len;
- cmd = ci->krule->cmd;
- cmdlen = 0;
p = pidx_first;
- for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
- cmdlen = F_LEN(cmd);
- if (classify_table_opcode(cmd, &uidx, &type) != 0)
- continue;
- update_table_opcode(cmd, p->kidx);
- p++;
+ for (p = pidx_first; p < pidx_last; p++) {
+ cmd = ci->krule->cmd + p->off;
+ update_opcode_kidx(cmd, p->kidx);
}
- IPFW_UH_WUNLOCK(chain);
-
free:
if (pidx_first != ci->obuf)
free(pidx_first, M_IPFW);
@@ -3641,6 +3512,7 @@ ipfw_destroy_tables(struct ip_fw_chain *ch, int last)
{
IPFW_DEL_SOPT_HANDLER(last, scodes);
+ IPFW_DEL_OBJ_REWRITER(last, opcodes);
/* Remove all tables from working set */
IPFW_UH_WLOCK(ch);
@@ -3678,6 +3550,7 @@ ipfw_init_tables(struct ip_fw_chain *ch, int first)
ipfw_table_value_init(ch, first);
ipfw_table_algo_init(ch);
+ IPFW_ADD_OBJ_REWRITER(first, opcodes);
IPFW_ADD_SOPT_HANDLER(first, scodes);
return (0);
}
diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h
index 028e450..ca49fd4 100644
--- a/sys/netpfil/ipfw/ip_fw_table.h
+++ b/sys/netpfil/ipfw/ip_fw_table.h
@@ -53,16 +53,6 @@ struct table_info {
u_long data; /* Hints for given func */
};
-/* Internal structures for handling sockopt data */
-struct tid_info {
- uint32_t set; /* table set */
- uint16_t uidx; /* table index */
- uint8_t type; /* table type */
- uint8_t atype;
- void *tlvs; /* Pointer to first TLV */
- int tlen; /* Total TLV size block */
-};
-
struct table_value;
struct tentry_info {
void *paddr;
@@ -189,13 +179,12 @@ void rollback_table_values(struct tableop_state *ts);
int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
struct rule_check_info *ci);
-int ipfw_rewrite_table_kidx(struct ip_fw_chain *chain,
- struct ip_fw_rule0 *rule);
int ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
uint32_t *bmask);
int ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
struct sockopt_data *sd);
void ipfw_unref_rule_tables(struct ip_fw_chain *chain, struct ip_fw *rule);
+struct namedobj_instance *ipfw_get_table_objhash(struct ip_fw_chain *ch);
/* utility functions */
int ipfw_check_table_name(char *name);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index ce0c6bd..6d24634 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -6070,7 +6070,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
M_ASSERTPKTHDR(m);
- if (ifp != m->m_pkthdr.rcvif)
+ if (dir == PF_OUT && m->m_pkthdr.rcvif && ifp != m->m_pkthdr.rcvif)
fwdir = PF_FWD;
if (!V_pf_status.running)
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 359d9de..c20e00a 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -84,7 +84,7 @@ __FBSDID("$FreeBSD$");
#endif /* INET6 */
#ifdef ALTQ
-#include <altq/altq.h>
+#include <net/altq/altq.h>
#endif
static int pfattach(void);
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 5ffb86d..f169723 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -1152,6 +1152,7 @@ pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag)
for (t = m; m; m = t) {
t = m->m_nextpkt;
m->m_nextpkt = NULL;
+ m->m_flags |= M_SKIP_FIREWALL;
memset(&pd, 0, sizeof(pd));
pd.pf_mtag = pf_find_mtag(m);
if (error == 0)
@@ -1642,7 +1643,7 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
goto tcp_drop;
if (flags & TH_FIN)
- flags &= ~TH_FIN;
+ goto tcp_drop;
} else {
/* Illegal packet */
if (!(flags & (TH_ACK|TH_RST)))
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h
index 22a291a..a085da1 100644
--- a/sys/nfsclient/nfs.h
+++ b/sys/nfsclient/nfs.h
@@ -114,10 +114,7 @@
#ifdef _KERNEL
#ifdef MALLOC_DECLARE
-MALLOC_DECLARE(M_NFSREQ);
MALLOC_DECLARE(M_NFSDIROFF);
-MALLOC_DECLARE(M_NFSBIGFH);
-MALLOC_DECLARE(M_NFSHASH);
MALLOC_DECLARE(M_NFSDIRECTIO);
#endif
diff --git a/sys/ofed/include/linux/file.h b/sys/ofed/include/linux/file.h
index 22a035f..f1a7398 100644
--- a/sys/ofed/include/linux/file.h
+++ b/sys/ofed/include/linux/file.h
@@ -82,7 +82,7 @@ put_unused_fd(unsigned int fd)
* installed, so no need to free the associated Linux file
* structure.
*/
- fdclose(curthread->td_proc->p_fd, file, fd, curthread);
+ fdclose(curthread, file, fd);
/* drop extra reference */
fdrop(file, curthread);
diff --git a/sys/ofed/include/linux/linux_idr.c b/sys/ofed/include/linux/linux_idr.c
index 809e178..a692fb8 100644
--- a/sys/ofed/include/linux/linux_idr.c
+++ b/sys/ofed/include/linux/linux_idr.c
@@ -185,27 +185,37 @@ out:
return (res);
}
-void *
-idr_find(struct idr *idr, int id)
+static inline void *
+idr_find_locked(struct idr *idr, int id)
{
struct idr_layer *il;
void *res;
int layer;
- res = NULL;
+ mtx_assert(&idr->lock, MA_OWNED);
+
id &= MAX_ID_MASK;
- mtx_lock(&idr->lock);
+ res = NULL;
il = idr->top;
layer = idr->layers - 1;
if (il == NULL || id > idr_max(idr))
- goto out;
+ return (NULL);
while (layer && il) {
il = il->ary[idr_pos(id, layer)];
layer--;
}
if (il != NULL)
res = il->ary[id & IDR_MASK];
-out:
+ return (res);
+}
+
+void *
+idr_find(struct idr *idr, int id)
+{
+ void *res;
+
+ mtx_lock(&idr->lock);
+ res = idr_find_locked(idr, id);
mtx_unlock(&idr->lock);
return (res);
}
@@ -331,13 +341,13 @@ idr_get_new(struct idr *idr, void *ptr, int *idp)
}
error = 0;
out:
- mtx_unlock(&idr->lock);
#ifdef INVARIANTS
- if (error == 0 && idr_find(idr, id) != ptr) {
+ if (error == 0 && idr_find_locked(idr, id) != ptr) {
panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n",
idr, id, ptr);
}
#endif
+ mtx_unlock(&idr->lock);
return (error);
}
@@ -438,12 +448,12 @@ restart:
}
error = 0;
out:
- mtx_unlock(&idr->lock);
#ifdef INVARIANTS
- if (error == 0 && idr_find(idr, id) != ptr) {
+ if (error == 0 && idr_find_locked(idr, id) != ptr) {
panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n",
idr, id, ptr);
}
#endif
+ mtx_unlock(&idr->lock);
return (error);
}
diff --git a/sys/opencrypto/cryptodeflate.c b/sys/opencrypto/cryptodeflate.c
index 0ad86e3..c55210d 100644
--- a/sys/opencrypto/cryptodeflate.c
+++ b/sys/opencrypto/cryptodeflate.c
@@ -29,7 +29,7 @@
/*
* This file contains a wrapper around the deflate algo compression
- * functions using the zlib library (see net/zlib.{c,h})
+ * functions using the zlib library (see libkern/zlib.c and sys/zlib.h})
*/
#include <sys/cdefs.h>
@@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/sdt.h>
#include <sys/systm.h>
-#include <net/zlib.h>
+#include <sys/zlib.h>
#include <opencrypto/cryptodev.h>
#include <opencrypto/deflate.h>
diff --git a/sys/opencrypto/deflate.h b/sys/opencrypto/deflate.h
index dcf7a84..d31a3bf 100644
--- a/sys/opencrypto/deflate.h
+++ b/sys/opencrypto/deflate.h
@@ -36,7 +36,7 @@
#ifndef _CRYPTO_DEFLATE_H_
#define _CRYPTO_DEFLATE_H_
-#include <net/zlib.h>
+#include <sys/zlib.h>
#define Z_METHOD 8
#define Z_MEMLEVEL 8
diff --git a/sys/opencrypto/gmac.h b/sys/opencrypto/gmac.h
index 79a9e11..909b78c 100644
--- a/sys/opencrypto/gmac.h
+++ b/sys/opencrypto/gmac.h
@@ -31,6 +31,7 @@
*/
#ifndef _GMAC_H_
+#define _GMAC_H_
#include "gfmult.h"
#include <crypto/rijndael/rijndael.h>
diff --git a/sys/pc98/pc98/genassym.c b/sys/pc98/pc98/genassym.c
new file mode 100644
index 0000000..26858e5
--- /dev/null
+++ b/sys/pc98/pc98/genassym.c
@@ -0,0 +1,3 @@
+/* $FreeBSD$ */
+
+#include "../../i386/i386/genassym.c"
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/aim_machdep.c
index 22f3b2f..ab09ab6 100644
--- a/sys/powerpc/aim/machdep.c
+++ b/sys/powerpc/aim/aim_machdep.c
@@ -129,106 +129,14 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
-int cold = 1;
#ifdef __powerpc64__
extern int n_slbs;
-int cacheline_size = 128;
-#else
-int cacheline_size = 32;
#endif
-int hw_direct_map = 1;
-
-extern void *ap_pcpu;
-
-struct pcpu __pcpu[MAXCPU];
-
-static struct trapframe frame0;
-
-char machine[] = "powerpc";
-SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
-
-static void cpu_startup(void *);
-SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
-
-SYSCTL_INT(_machdep, CPU_CACHELINE, cacheline_size,
- CTLFLAG_RD, &cacheline_size, 0, "");
-
-uintptr_t powerpc_init(vm_offset_t, vm_offset_t, vm_offset_t, void *);
-
-long Maxmem = 0;
-long realmem = 0;
#ifndef __powerpc64__
struct bat battable[16];
#endif
-struct kva_md_info kmi;
-
-static void
-cpu_startup(void *dummy)
-{
-
- /*
- * Initialise the decrementer-based clock.
- */
- decr_init();
-
- /*
- * Good {morning,afternoon,evening,night}.
- */
- cpu_setup(PCPU_GET(cpuid));
-
-#ifdef PERFMON
- perfmon_init();
-#endif
- printf("real memory = %ld (%ld MB)\n", ptoa(physmem),
- ptoa(physmem) / 1048576);
- realmem = physmem;
-
- if (bootverbose)
- printf("available KVA = %zd (%zd MB)\n",
- virtual_end - virtual_avail,
- (virtual_end - virtual_avail) / 1048576);
-
- /*
- * Display any holes after the first chunk of extended memory.
- */
- if (bootverbose) {
- int indx;
-
- printf("Physical memory chunk(s):\n");
- for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
- vm_offset_t size1 =
- phys_avail[indx + 1] - phys_avail[indx];
-
- #ifdef __powerpc64__
- printf("0x%016lx - 0x%016lx, %ld bytes (%ld pages)\n",
- #else
- printf("0x%08x - 0x%08x, %d bytes (%ld pages)\n",
- #endif
- phys_avail[indx], phys_avail[indx + 1] - 1, size1,
- size1 / PAGE_SIZE);
- }
- }
-
- vm_ksubmap_init(&kmi);
-
- printf("avail memory = %ld (%ld MB)\n", ptoa(vm_cnt.v_free_count),
- ptoa(vm_cnt.v_free_count) / 1048576);
-
- /*
- * Set up buffers, so they can be used to read disk labels.
- */
- bufinit();
- vm_pager_bufferinit();
-}
-
-extern vm_offset_t __startkernel, __endkernel;
-extern unsigned char __bss_start[];
-extern unsigned char __sbss_start[];
-extern unsigned char __sbss_end[];
-extern unsigned char _end[];
-
#ifndef __powerpc64__
/* Bits for running on 64-bit systems in 32-bit mode. */
extern void *testppc64, *testppc64size;
@@ -252,121 +160,25 @@ extern void *imisstrap, *imisssize;
extern void *dlmisstrap, *dlmisssize;
extern void *dsmisstrap, *dsmisssize;
-uintptr_t
-powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp)
+extern void *ap_pcpu;
+
+void aim_cpu_init(vm_offset_t toc);
+
+void
+aim_cpu_init(vm_offset_t toc)
{
- struct pcpu *pc;
- vm_offset_t startkernel, endkernel;
size_t trap_offset, trapsize;
vm_offset_t trap;
- void *kmdp;
- char *env;
register_t msr, scratch;
uint8_t *cache_check;
int cacheline_warn;
#ifndef __powerpc64__
int ppc64;
#endif
-#ifdef DDB
- vm_offset_t ksym_start;
- vm_offset_t ksym_end;
-#endif
- kmdp = NULL;
trap_offset = 0;
cacheline_warn = 0;
- /* First guess at start/end kernel positions */
- startkernel = __startkernel;
- endkernel = __endkernel;
-
- /* Check for ePAPR loader, which puts a magic value into r6 */
- if (mdp == (void *)0x65504150)
- mdp = NULL;
-
- /*
- * Parse metadata if present and fetch parameters. Must be done
- * before console is inited so cninit gets the right value of
- * boothowto.
- */
- if (mdp != NULL) {
- preload_metadata = mdp;
- kmdp = preload_search_by_type("elf kernel");
- if (kmdp != NULL) {
- boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
- kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
- endkernel = ulmax(endkernel, MD_FETCH(kmdp,
- MODINFOMD_KERNEND, vm_offset_t));
-#ifdef DDB
- ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
- ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
- db_fetch_ksymtab(ksym_start, ksym_end);
-#endif
- }
- } else {
- bzero(__sbss_start, __sbss_end - __sbss_start);
- bzero(__bss_start, _end - __bss_start);
- }
-
- /* Store boot environment state */
- OF_initial_setup((void *)fdt, NULL, (int (*)(void *))ofentry);
-
- /*
- * Init params/tunables that can be overridden by the loader
- */
- init_param1();
-
- /*
- * Start initializing proc0 and thread0.
- */
- proc_linkup0(&proc0, &thread0);
- thread0.td_frame = &frame0;
-
- /*
- * Set up per-cpu data.
- */
- pc = __pcpu;
- pcpu_init(pc, 0, sizeof(struct pcpu));
- pc->pc_curthread = &thread0;
-#ifdef __powerpc64__
- __asm __volatile("mr 13,%0" :: "r"(pc->pc_curthread));
-#else
- __asm __volatile("mr 2,%0" :: "r"(pc->pc_curthread));
-#endif
- pc->pc_cpuid = 0;
-
- __asm __volatile("mtsprg 0, %0" :: "r"(pc));
-
- /*
- * Init mutexes, which we use heavily in PMAP
- */
-
- mutex_init();
-
- /*
- * Install the OF client interface
- */
-
- OF_bootstrap();
-
- /*
- * Initialize the console before printing anything.
- */
- cninit();
-
- /*
- * Complain if there is no metadata.
- */
- if (mdp == NULL || kmdp == NULL) {
- printf("powerpc_init: no loader metadata.\n");
- }
-
- /*
- * Init KDB
- */
-
- kdb_init();
-
/* Various very early CPU fix ups */
switch (mfpvr() >> 16) {
/*
@@ -431,9 +243,6 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp)
cacheline_size = 32;
}
- /* Make sure the kernel icache is valid before we go too much further */
- __syncicache((caddr_t)startkernel, endkernel - startkernel);
-
#ifndef __powerpc64__
/*
* Figure out whether we need to use the 64 bit PMAP. This works by
@@ -552,12 +361,6 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp)
}
/*
- * Choose a platform module so we can get the physical memory map.
- */
-
- platform_probe_and_attach();
-
- /*
* Initialise virtual memory. Use BUS_PROBE_GENERIC priority
* in case the platform module had a better idea of what we
* should do.
@@ -566,96 +369,6 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp)
pmap_mmu_install(MMU_TYPE_G5, BUS_PROBE_GENERIC);
else
pmap_mmu_install(MMU_TYPE_OEA, BUS_PROBE_GENERIC);
-
- pmap_bootstrap(startkernel, endkernel);
- mtmsr(PSL_KERNSET & ~PSL_EE);
-
- /*
- * Initialize params/tunables that are derived from memsize
- */
- init_param2(physmem);
-
- /*
- * Grab booted kernel's name
- */
- env = kern_getenv("kernelname");
- if (env != NULL) {
- strlcpy(kernelname, env, sizeof(kernelname));
- freeenv(env);
- }
-
- /*
- * Finish setting up thread0.
- */
- thread0.td_pcb = (struct pcb *)
- ((thread0.td_kstack + thread0.td_kstack_pages * PAGE_SIZE -
- sizeof(struct pcb)) & ~15UL);
- bzero((void *)thread0.td_pcb, sizeof(struct pcb));
- pc->pc_curpcb = thread0.td_pcb;
-
- /* Initialise the message buffer. */
- msgbufinit(msgbufp, msgbufsize);
-
-#ifdef KDB
- if (boothowto & RB_KDB)
- kdb_enter(KDB_WHY_BOOTFLAGS,
- "Boot flags requested debugger");
-#endif
-
- return (((uintptr_t)thread0.td_pcb -
- (sizeof(struct callframe) - 3*sizeof(register_t))) & ~15UL);
-}
-
-void
-bzero(void *buf, size_t len)
-{
- caddr_t p;
-
- p = buf;
-
- while (((vm_offset_t) p & (sizeof(u_long) - 1)) && len) {
- *p++ = 0;
- len--;
- }
-
- while (len >= sizeof(u_long) * 8) {
- *(u_long*) p = 0;
- *((u_long*) p + 1) = 0;
- *((u_long*) p + 2) = 0;
- *((u_long*) p + 3) = 0;
- len -= sizeof(u_long) * 8;
- *((u_long*) p + 4) = 0;
- *((u_long*) p + 5) = 0;
- *((u_long*) p + 6) = 0;
- *((u_long*) p + 7) = 0;
- p += sizeof(u_long) * 8;
- }
-
- while (len >= sizeof(u_long)) {
- *(u_long*) p = 0;
- len -= sizeof(u_long);
- p += sizeof(u_long);
- }
-
- while (len) {
- *p++ = 0;
- len--;
- }
-}
-
-void
-cpu_boot(int howto)
-{
-}
-
-/*
- * Flush the D-cache for non-DMA I/O so that the I-cache can
- * be made coherent later.
- */
-void
-cpu_flush_dcache(void *ptr, size_t len)
-{
- /* TBD */
}
/*
@@ -669,17 +382,6 @@ cpu_halt(void)
}
int
-ptrace_set_pc(struct thread *td, unsigned long addr)
-{
- struct trapframe *tf;
-
- tf = td->td_frame;
- tf->srr0 = (register_t)addr;
-
- return (0);
-}
-
-int
ptrace_single_step(struct thread *td)
{
struct trapframe *tf;
@@ -727,66 +429,7 @@ memcpy(pcpu->pc_slb, PCPU_GET(slb), sizeof(pcpu->pc_slb));
#endif
}
-void
-spinlock_enter(void)
-{
- struct thread *td;
- register_t msr;
-
- td = curthread;
- if (td->td_md.md_spinlock_count == 0) {
- __asm __volatile("or 2,2,2"); /* Set high thread priority */
- msr = intr_disable();
- td->td_md.md_spinlock_count = 1;
- td->td_md.md_saved_msr = msr;
- } else
- td->td_md.md_spinlock_count++;
- critical_enter();
-}
-
-void
-spinlock_exit(void)
-{
- struct thread *td;
- register_t msr;
-
- td = curthread;
- critical_exit();
- msr = td->td_md.md_saved_msr;
- td->td_md.md_spinlock_count--;
- if (td->td_md.md_spinlock_count == 0) {
- intr_restore(msr);
- __asm __volatile("or 6,6,6"); /* Set normal thread priority */
- }
-}
-
-int db_trap_glue(struct trapframe *); /* Called from trap_subr.S */
-
-int
-db_trap_glue(struct trapframe *frame)
-{
- if (!(frame->srr1 & PSL_PR)
- && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC
- || (frame->exc == EXC_PGM
- && (frame->srr1 & 0x20000))
- || frame->exc == EXC_BPT
- || frame->exc == EXC_DSI)) {
- int type = frame->exc;
-
- /* Ignore DTrace traps. */
- if (*(uint32_t *)frame->srr0 == EXC_DTRACE)
- return (0);
- if (type == EXC_PGM && (frame->srr1 & 0x20000)) {
- type = T_BREAKPOINT;
- }
- return (kdb_trap(type, 0, frame));
- }
-
- return (0);
-}
-
#ifndef __powerpc64__
-
uint64_t
va_to_vsid(pmap_t pm, vm_offset_t va)
{
@@ -970,3 +613,4 @@ cpu_sleep()
enable_vec(curthread);
powerpc_sync();
}
+
diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c
index 23bd449..c45f941 100644
--- a/sys/powerpc/aim/mmu_oea64.c
+++ b/sys/powerpc/aim/mmu_oea64.c
@@ -137,8 +137,6 @@ struct ofw_map {
extern unsigned char _etext[];
extern unsigned char _end[];
-extern int ofw_real_mode;
-
/*
* Map of physical memory regions.
*/
@@ -852,8 +850,7 @@ moea64_late_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend
*/
chosen = OF_finddevice("/chosen");
- if (!ofw_real_mode && chosen != -1 &&
- OF_getprop(chosen, "mmu", &mmui, 4) != -1) {
+ if (chosen != -1 && OF_getprop(chosen, "mmu", &mmui, 4) != -1) {
mmu = OF_instance_to_package(mmui);
if (mmu == -1 ||
(sz = OF_getproplen(mmu, "translations")) == -1)
diff --git a/sys/powerpc/booke/machdep.c b/sys/powerpc/booke/booke_machdep.c
index f3ef9e3..2a27775 100644
--- a/sys/powerpc/booke/machdep.c
+++ b/sys/powerpc/booke/booke_machdep.c
@@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_ddb.h"
+#include "opt_hwpmc_hooks.h"
#include "opt_kstack_pages.h"
#include "opt_platform.h"
@@ -162,6 +163,7 @@ extern unsigned char __bss_start[];
extern unsigned char __sbss_start[];
extern unsigned char __sbss_end[];
extern unsigned char _end[];
+extern vm_offset_t __endkernel;
/*
* Bootinfo is passed to us by legacy loaders. Save the address of the
@@ -169,25 +171,6 @@ extern unsigned char _end[];
*/
uint32_t *bootinfo;
-struct kva_md_info kmi;
-struct pcpu __pcpu[MAXCPU];
-struct trapframe frame0;
-int cold = 1;
-long realmem = 0;
-long Maxmem = 0;
-char machine[] = "powerpc";
-SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
-
-int cacheline_size = 32;
-
-SYSCTL_INT(_machdep, CPU_CACHELINE, cacheline_size,
- CTLFLAG_RD, &cacheline_size, 0, "");
-
-int hw_direct_map = 0;
-
-static void cpu_booke_startup(void *);
-SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_booke_startup, NULL);
-
void print_kernel_section_addr(void);
void print_kenv(void);
u_int booke_init(uint32_t, uint32_t);
@@ -208,6 +191,9 @@ extern void *int_watchdog;
extern void *int_data_tlb_error;
extern void *int_inst_tlb_error;
extern void *int_debug;
+#ifdef HWPMC_HOOKS
+extern void *int_performance_counter;
+#endif
#define SET_TRAP(ivor, handler) \
KASSERT(((uintptr_t)(&handler) & ~0xffffUL) == \
@@ -215,6 +201,16 @@ extern void *int_debug;
("Handler " #handler " too far from interrupt vector base")); \
mtspr(ivor, (uintptr_t)(&handler) & 0xffffUL);
+uintptr_t powerpc_init(vm_offset_t fdt, vm_offset_t, vm_offset_t, void *mdp);
+void booke_cpu_init(void);
+
+void
+booke_cpu_init(void)
+{
+
+ pmap_mmu_install(MMU_TYPE_BOOKE, BUS_PROBE_GENERIC);
+}
+
void
ivor_setup(void)
{
@@ -235,90 +231,9 @@ ivor_setup(void)
SET_TRAP(SPR_IVOR13, int_data_tlb_error);
SET_TRAP(SPR_IVOR14, int_inst_tlb_error);
SET_TRAP(SPR_IVOR15, int_debug);
-}
-
-static void
-cpu_booke_startup(void *dummy)
-{
- int indx;
- unsigned long size;
-
- /* Initialise the decrementer-based clock. */
- decr_init();
-
- /* Good {morning,afternoon,evening,night}. */
- cpu_setup(PCPU_GET(cpuid));
-
- printf("real memory = %lu (%ld MB)\n", ptoa(physmem),
- ptoa(physmem) / 1048576);
- realmem = physmem;
-
- /* Display any holes after the first chunk of extended memory. */
- if (bootverbose) {
- printf("Physical memory chunk(s):\n");
- for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
- size = phys_avail[indx + 1] - phys_avail[indx];
-
- printf("0x%08x - 0x%08x, %lu bytes (%lu pages)\n",
- phys_avail[indx], phys_avail[indx + 1] - 1,
- size, size / PAGE_SIZE);
- }
- }
-
- vm_ksubmap_init(&kmi);
-
- printf("avail memory = %lu (%ld MB)\n", ptoa(vm_cnt.v_free_count),
- ptoa(vm_cnt.v_free_count) / 1048576);
-
- /* Set up buffers, so they can be used to read disk labels. */
- bufinit();
- vm_pager_bufferinit();
-}
-
-static char *
-kenv_next(char *cp)
-{
-
- if (cp != NULL) {
- while (*cp != 0)
- cp++;
- cp++;
- if (*cp == 0)
- cp = NULL;
- }
- return (cp);
-}
-
-void
-print_kenv(void)
-{
- int len;
- char *cp;
-
- debugf("loader passed (static) kenv:\n");
- if (kern_envp == NULL) {
- debugf(" no env, null ptr\n");
- return;
- }
- debugf(" kern_envp = 0x%08x\n", (u_int32_t)kern_envp);
-
- len = 0;
- for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
- debugf(" %x %s\n", (u_int32_t)cp, cp);
-}
-
-void
-print_kernel_section_addr(void)
-{
-
- debugf("kernel image addresses:\n");
- debugf(" kernel_text = 0x%08x\n", (uint32_t)kernel_text);
- debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
- debugf(" _edata = 0x%08x\n", (uint32_t)_edata);
- debugf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start);
- debugf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end);
- debugf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start);
- debugf(" _end = 0x%08x\n", (uint32_t)_end);
+#ifdef HWPMC_HOOKS
+ SET_TRAP(SPR_IVOR35, int_performance_counter);
+#endif
}
static int
@@ -338,24 +253,20 @@ booke_check_for_fdt(uint32_t arg1, vm_offset_t *dtbp)
return (0);
}
-u_int
+uintptr_t
booke_init(uint32_t arg1, uint32_t arg2)
{
- struct pcpu *pc;
- void *kmdp, *mdp;
+ uintptr_t ret;
+ void *mdp;
vm_offset_t dtbp, end;
-#ifdef DDB
- vm_offset_t ksym_start;
- vm_offset_t ksym_end;
-#endif
-
- kmdp = NULL;
end = (uintptr_t)_end;
dtbp = (vm_offset_t)NULL;
/* Set up TLB initially */
bootinfo = NULL;
+ bzero(__sbss_start, __sbss_end - __sbss_start);
+ bzero(__bss_start, _end - __bss_start);
tlb1_init();
/*
@@ -384,152 +295,22 @@ booke_init(uint32_t arg1, uint32_t arg2)
memmove((void *)end, (void *)dtbp, fdt_totalsize((void *)dtbp));
dtbp = end;
end += fdt_totalsize((void *)dtbp);
+ __endkernel = end;
mdp = NULL;
} else if (arg1 > (uintptr_t)kernel_text) /* FreeBSD loader */
mdp = (void *)arg1;
else /* U-Boot */
mdp = NULL;
- /*
- * Parse metadata and fetch parameters.
- */
- if (mdp != NULL) {
- preload_metadata = mdp;
- kmdp = preload_search_by_type("elf kernel");
- if (kmdp != NULL) {
- boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
- kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
- dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
- end = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
-
- bootinfo = (uint32_t *)preload_search_info(kmdp,
- MODINFO_METADATA | MODINFOMD_BOOTINFO);
-
-#ifdef DDB
- ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
- ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
- db_fetch_ksymtab(ksym_start, ksym_end);
-#endif
- }
- } else {
- bzero(__sbss_start, __sbss_end - __sbss_start);
- bzero(__bss_start, _end - __bss_start);
- }
-
-#if defined(FDT_DTB_STATIC)
- /*
- * In case the device tree blob was not retrieved (from metadata) try
- * to use the statically embedded one.
- */
- if (dtbp == (vm_offset_t)NULL)
- dtbp = (vm_offset_t)&fdt_static_dtb;
-#endif
-
- if (OF_install(OFW_FDT, 0) == FALSE)
- while (1);
-
- if (OF_init((void *)dtbp) != 0)
- while (1);
-
- OF_interpret("perform-fixup", 0);
-
/* Reset TLB1 to get rid of temporary mappings */
tlb1_init();
- /* Reset Time Base */
- mttb(0);
-
- /* Init params/tunables that can be overridden by the loader. */
- init_param1();
-
- /* Start initializing proc0 and thread0. */
- proc_linkup0(&proc0, &thread0);
- thread0.td_frame = &frame0;
-
- /* Set up per-cpu data and store the pointer in SPR general 0. */
- pc = &__pcpu[0];
- pcpu_init(pc, 0, sizeof(struct pcpu));
- pc->pc_curthread = &thread0;
-#ifdef __powerpc64__
- __asm __volatile("mr 13,%0" :: "r"(pc->pc_curthread));
-#else
- __asm __volatile("mr 2,%0" :: "r"(pc->pc_curthread));
-#endif
- __asm __volatile("mtsprg 0, %0" :: "r"(pc));
-
- /* Initialize system mutexes. */
- mutex_init();
-
- /* Initialize the console before printing anything. */
- cninit();
-
- /* Print out some debug info... */
- debugf("%s: console initialized\n", __func__);
- debugf(" arg3 mdp = 0x%08x\n", (u_int32_t)mdp);
- debugf(" end = 0x%08x\n", (u_int32_t)end);
- debugf(" boothowto = 0x%08x\n", boothowto);
-#ifdef MPC85XX
- debugf(" kernel ccsrbar = 0x%08x\n", CCSRBAR_VA);
-#endif
- debugf(" MSR = 0x%08x\n", mfmsr());
-#if defined(BOOKE_E500)
- debugf(" HID0 = 0x%08x\n", mfspr(SPR_HID0));
- debugf(" HID1 = 0x%08x\n", mfspr(SPR_HID1));
- debugf(" BUCSR = 0x%08x\n", mfspr(SPR_BUCSR));
-#endif
-
- debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
-
- print_kernel_section_addr();
- print_kenv();
-#if defined(BOOKE_E500)
- //tlb1_print_entries();
- //tlb1_print_tlbentries();
-#endif
-
- kdb_init();
-
-#ifdef KDB
- if (boothowto & RB_KDB)
- kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
-#endif
-
- /* Initialise platform module */
- platform_probe_and_attach();
-
- /* Initialise virtual memory. */
- pmap_mmu_install(MMU_TYPE_BOOKE, 0);
- pmap_bootstrap((uintptr_t)kernel_text, end);
- debugf("MSR = 0x%08x\n", mfmsr());
-#if defined(BOOKE_E500)
- //tlb1_print_entries();
- //tlb1_print_tlbentries();
-#endif
-
- /* Initialize params/tunables that are derived from memsize. */
- init_param2(physmem);
-
- /* Finish setting up thread0. */
- thread0.td_pcb = (struct pcb *)
- ((thread0.td_kstack + thread0.td_kstack_pages * PAGE_SIZE -
- sizeof(struct pcb)) & ~15);
- bzero((void *)thread0.td_pcb, sizeof(struct pcb));
- pc->pc_curpcb = thread0.td_pcb;
-
- /* Initialise the message buffer. */
- msgbufinit(msgbufp, msgbufsize);
-
- /* Enable Machine Check interrupt. */
- mtmsr(mfmsr() | PSL_ME);
- isync();
+ ret = powerpc_init(dtbp, 0, 0, mdp);
/* Enable L1 caches */
booke_enable_l1_cache();
- debugf("%s: SP = 0x%08x\n", __func__,
- ((uintptr_t)thread0.td_pcb - 16) & ~15);
-
- return (((uintptr_t)thread0.td_pcb - 16) & ~15);
+ return (ret);
}
#define RES_GRANULE 32
@@ -553,63 +334,6 @@ cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t sz)
#endif
}
-/*
- * Flush the D-cache for non-DMA I/O so that the I-cache can
- * be made coherent later.
- */
-void
-cpu_flush_dcache(void *ptr, size_t len)
-{
- register_t addr, off;
-
- /*
- * Align the address to a cacheline and adjust the length
- * accordingly. Then round the length to a multiple of the
- * cacheline for easy looping.
- */
- addr = (uintptr_t)ptr;
- off = addr & (cacheline_size - 1);
- addr -= off;
- len = (len + off + cacheline_size - 1) & ~(cacheline_size - 1);
-
- while (len > 0) {
- __asm __volatile ("dcbf 0,%0" :: "r"(addr));
- __asm __volatile ("sync");
- addr += cacheline_size;
- len -= cacheline_size;
- }
-}
-
-void
-spinlock_enter(void)
-{
- struct thread *td;
- register_t msr;
-
- td = curthread;
- if (td->td_md.md_spinlock_count == 0) {
- msr = intr_disable();
- td->td_md.md_spinlock_count = 1;
- td->td_md.md_saved_msr = msr;
- } else
- td->td_md.md_spinlock_count++;
- critical_enter();
-}
-
-void
-spinlock_exit(void)
-{
- struct thread *td;
- register_t msr;
-
- td = curthread;
- critical_exit();
- msr = td->td_md.md_saved_msr;
- td->td_md.md_spinlock_count--;
- if (td->td_md.md_spinlock_count == 0)
- intr_restore(msr);
-}
-
/* Shutdown the CPU as much as possible. */
void
cpu_halt(void)
@@ -621,17 +345,6 @@ cpu_halt(void)
}
int
-ptrace_set_pc(struct thread *td, unsigned long addr)
-{
- struct trapframe *tf;
-
- tf = td->td_frame;
- tf->srr0 = (register_t)addr;
-
- return (0);
-}
-
-int
ptrace_single_step(struct thread *td)
{
struct trapframe *tf;
@@ -673,40 +386,3 @@ kdb_cpu_set_singlestep(void)
kdb_frame->srr1 |= PSL_DE;
}
-void
-bzero(void *buf, size_t len)
-{
- caddr_t p;
-
- p = buf;
-
- while (((vm_offset_t) p & (sizeof(u_long) - 1)) && len) {
- *p++ = 0;
- len--;
- }
-
- while (len >= sizeof(u_long) * 8) {
- *(u_long*) p = 0;
- *((u_long*) p + 1) = 0;
- *((u_long*) p + 2) = 0;
- *((u_long*) p + 3) = 0;
- len -= sizeof(u_long) * 8;
- *((u_long*) p + 4) = 0;
- *((u_long*) p + 5) = 0;
- *((u_long*) p + 6) = 0;
- *((u_long*) p + 7) = 0;
- p += sizeof(u_long) * 8;
- }
-
- while (len >= sizeof(u_long)) {
- *(u_long*) p = 0;
- len -= sizeof(u_long);
- p += sizeof(u_long);
- }
-
- while (len) {
- *p++ = 0;
- len--;
- }
-}
-
diff --git a/sys/powerpc/booke/interrupt.c b/sys/powerpc/booke/interrupt.c
index b5f6140..3786c68 100644
--- a/sys/powerpc/booke/interrupt.c
+++ b/sys/powerpc/booke/interrupt.c
@@ -32,6 +32,8 @@
* Interrupts are dispatched to here from locore asm
*/
+#include "opt_hwpmc_hooks.h"
+
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__FBSDID("$FreeBSD$");
@@ -45,6 +47,9 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#ifdef HWPMC_HOOKS
+#include <sys/pmckern.h>
+#endif
#include <sys/proc.h>
#include <sys/smp.h>
#include <sys/unistd.h>
@@ -67,6 +72,9 @@ void powerpc_decr_interrupt(struct trapframe *);
void powerpc_extr_interrupt(struct trapframe *);
void powerpc_crit_interrupt(struct trapframe *);
void powerpc_mchk_interrupt(struct trapframe *);
+#ifdef HWPMC_HOOKS
+void powerpc_pmc_interrupt(struct trapframe *framep);
+#endif
static void dump_frame(struct trapframe *framep);
@@ -142,3 +150,20 @@ powerpc_extr_interrupt(struct trapframe *framep)
critical_exit();
framep->srr1 &= ~PSL_WE;
}
+
+#ifdef HWPMC_HOOKS
+/*
+ * Performance Counter interrupt routine
+ */
+void
+powerpc_pmc_interrupt(struct trapframe *framep)
+{
+
+ critical_enter();
+ KASSERT(pmc_intr != NULL, ("Performance exception, but no handler!"));
+ (*pmc_intr)(PCPU_GET(cpuid), framep);
+ critical_exit();
+ if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN))
+ pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, framep);
+}
+#endif
diff --git a/sys/powerpc/booke/locore.S b/sys/powerpc/booke/locore.S
index 37860e5..330a61f 100644
--- a/sys/powerpc/booke/locore.S
+++ b/sys/powerpc/booke/locore.S
@@ -28,6 +28,8 @@
#include "assym.s"
+#include "opt_hwpmc_hooks.h"
+
#include <machine/asm.h>
#include <machine/hid.h>
#include <machine/param.h>
@@ -722,12 +724,10 @@ setfault:
lwz %r4, TD_PCB(%r2)
stw %r3, PCB_ONFAULT(%r4)
mfcr %r10
- mfctr %r11
- mfxer %r12
stw %r0, 0(%r3)
stw %r1, 4(%r3)
stw %r2, 8(%r3)
- stmw %r10, 12(%r3) /* store CR, CTR, XER, [r13 .. r31] */
+ stmw %r13, 12(%r3) /* store CR, CTR, XER, [r13 .. r31] */
li %r3, 0 /* return FALSE */
blr
diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c
index 2c6df63..c5e3bf3 100644
--- a/sys/powerpc/booke/pmap.c
+++ b/sys/powerpc/booke/pmap.c
@@ -1031,13 +1031,8 @@ mmu_booke_bootstrap(mmu_t mmu, vm_offset_t start, vm_offset_t kernelend)
* Align kernel start and end address (kernel image).
* Note that kernel end does not necessarily relate to kernsize.
* kernsize is the size of the kernel that is actually mapped.
- * Also note that "start - 1" is deliberate. With SMP, the
- * entry point is exactly a page from the actual load address.
- * As such, trunc_page() has no effect and we're off by a page.
- * Since we always have the ELF header between the load address
- * and the entry point, we can safely subtract 1 to compensate.
*/
- kernstart = trunc_page(start - 1);
+ kernstart = trunc_page(start);
data_start = round_page(kernelend);
data_end = data_start;
diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c
deleted file mode 100644
index d1899ef..0000000
--- a/sys/powerpc/booke/trap.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*-
- * Copyright (C) 1995, 1996 Wolfgang Solfrank.
- * Copyright (C) 1995, 1996 TooLs GmbH.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by TooLs GmbH.
- * 4. The name of TooLs GmbH may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_fpu_emu.h"
-
-#include <sys/param.h>
-#include <sys/kdb.h>
-#include <sys/proc.h>
-#include <sys/ktr.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/pioctl.h>
-#include <sys/ptrace.h>
-#include <sys/reboot.h>
-#include <sys/syscall.h>
-#include <sys/sysent.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/uio.h>
-#include <sys/signalvar.h>
-#include <sys/vmmeter.h>
-
-#include <security/audit/audit.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <vm/vm_extern.h>
-#include <vm/vm_param.h>
-#include <vm/vm_kern.h>
-#include <vm/vm_map.h>
-#include <vm/vm_page.h>
-
-#include <machine/cpu.h>
-#include <machine/db_machdep.h>
-#include <machine/frame.h>
-#include <machine/pcb.h>
-#include <machine/pmap.h>
-#include <machine/psl.h>
-#include <machine/trap.h>
-#include <machine/spr.h>
-
-#define FAULTBUF_LR 0
-#define FAULTBUF_R1 1
-#define FAULTBUF_R2 2
-#define FAULTBUF_CR 3
-#define FAULTBUF_CTR 4
-#define FAULTBUF_XER 5
-#define FAULTBUF_R13 6
-
-static void trap_fatal(struct trapframe *frame);
-static void printtrap(u_int vector, struct trapframe *frame, int isfatal,
- int user);
-static int trap_pfault(struct trapframe *frame, int user);
-static int fix_unaligned(struct thread *td, struct trapframe *frame);
-static int handle_onfault(struct trapframe *frame);
-static void syscall(struct trapframe *frame);
-
-struct powerpc_exception {
- u_int vector;
- char *name;
-};
-
-static struct powerpc_exception powerpc_exceptions[] = {
- { EXC_CRIT, "critical input" },
- { EXC_MCHK, "machine check" },
- { EXC_DSI, "data storage interrupt" },
- { EXC_ISI, "instruction storage interrupt" },
- { EXC_EXI, "external interrupt" },
- { EXC_ALI, "alignment" },
- { EXC_PGM, "program" },
- { EXC_SC, "system call" },
- { EXC_APU, "auxiliary proc unavailable" },
- { EXC_DECR, "decrementer" },
- { EXC_FIT, "fixed-interval timer" },
- { EXC_WDOG, "watchdog timer" },
- { EXC_DTMISS, "data tlb miss" },
- { EXC_ITMISS, "instruction tlb miss" },
- { EXC_DEBUG, "debug" },
- { EXC_PERF, "performance monitoring" },
- { EXC_LAST, NULL }
-};
-
-static const char *
-trapname(u_int vector)
-{
- struct powerpc_exception *pe;
-
- for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) {
- if (pe->vector == vector)
- return (pe->name);
- }
-
- return ("unknown");
-}
-
-void
-trap(struct trapframe *frame)
-{
- struct thread *td;
- struct proc *p;
- int sig, type, user;
- ksiginfo_t ksi;
-
-#ifdef KDB
- if (kdb_active) {
- kdb_reenter();
- return;
- }
-#endif
-
- PCPU_INC(cnt.v_trap);
-
- td = curthread;
- p = td->td_proc;
-
- type = frame->exc;
- sig = 0;
- user = (frame->srr1 & PSL_PR) ? 1 : 0;
-
- CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm,
- trapname(type), user ? "user" : "kernel");
-
- if (user) {
- td->td_frame = frame;
- if (td->td_ucred != p->p_ucred)
- cred_update_thread(td);
-
- /* User Mode Traps */
- switch (type) {
- case EXC_DSI:
- case EXC_ISI:
- sig = trap_pfault(frame, 1);
- break;
-
- case EXC_SC:
- syscall(frame);
- break;
-
- case EXC_ALI:
- if (fix_unaligned(td, frame) != 0)
- sig = SIGBUS;
- else
- frame->srr0 += 4;
- break;
-
- case EXC_DEBUG: /* Single stepping */
- mtspr(SPR_DBSR, mfspr(SPR_DBSR));
- frame->srr1 &= ~PSL_DE;
- frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC);
- sig = SIGTRAP;
- break;
-
- case EXC_PGM: /* Program exception */
- sig = ppc_instr_emulate(frame, td->td_pcb);
- break;
-
- default:
- trap_fatal(frame);
- }
- } else {
- /* Kernel Mode Traps */
- KASSERT(cold || td->td_ucred != NULL,
- ("kernel trap doesn't have ucred"));
-
- switch (type) {
- case EXC_DEBUG:
- mtspr(SPR_DBSR, mfspr(SPR_DBSR));
- kdb_trap(frame->exc, 0, frame);
- return;
-
- case EXC_DSI:
- if (trap_pfault(frame, 0) == 0)
- return;
- break;
-
- case EXC_MCHK:
- if (handle_onfault(frame))
- return;
- break;
-#ifdef KDB
- case EXC_PGM:
- if (frame->cpu.booke.esr & ESR_PTR)
- kdb_trap(EXC_PGM, 0, frame);
- return;
-#endif
- default:
- break;
- }
- trap_fatal(frame);
- }
-
- if (sig != 0) {
- if (p->p_sysent->sv_transtrap != NULL)
- sig = (p->p_sysent->sv_transtrap)(sig, type);
- ksiginfo_init_trap(&ksi);
- ksi.ksi_signo = sig;
- ksi.ksi_code = type; /* XXX, not POSIX */
- /* ksi.ksi_addr = ? */
- ksi.ksi_trapno = type;
- trapsignal(td, &ksi);
- }
-
- userret(td, frame);
-}
-
-static void
-trap_fatal(struct trapframe *frame)
-{
-
- printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
-#ifdef KDB
- if ((debugger_on_panic || kdb_active) &&
- kdb_trap(frame->exc, 0, frame))
- return;
-#endif
- panic("%s trap", trapname(frame->exc));
-}
-
-static void
-printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
-{
- register_t va = 0;
-
- printf("\n");
- printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
- user ? "user" : "kernel");
- printf("\n");
- printf(" exception = 0x%x (%s)\n", vector, trapname(vector));
-
- switch (vector) {
- case EXC_DTMISS:
- case EXC_DSI:
- va = frame->dar;
- break;
-
- case EXC_ITMISS:
- case EXC_ISI:
- va = frame->srr0;
- break;
- }
-
- printf(" virtual address = 0x%08x\n", va);
- printf(" srr0 = 0x%08x\n", frame->srr0);
- printf(" srr1 = 0x%08x\n", frame->srr1);
- printf(" curthread = %p\n", curthread);
- if (curthread != NULL)
- printf(" pid = %d, comm = %s\n",
- curthread->td_proc->p_pid, curthread->td_proc->p_comm);
- printf("\n");
-}
-
-/*
- * Handles a fatal fault when we have onfault state to recover. Returns
- * non-zero if there was onfault recovery state available.
- */
-static int
-handle_onfault(struct trapframe *frame)
-{
- struct thread *td;
- faultbuf *fb;
-
- td = curthread;
- fb = td->td_pcb->pcb_onfault;
- if (fb != NULL) {
- frame->srr0 = (*fb)[FAULTBUF_LR];
- frame->fixreg[1] = (*fb)[FAULTBUF_R1];
- frame->fixreg[2] = (*fb)[FAULTBUF_R2];
- frame->fixreg[3] = 1;
- frame->cr = (*fb)[FAULTBUF_CR];
- frame->ctr = (*fb)[FAULTBUF_CTR];
- frame->xer = (*fb)[FAULTBUF_XER];
- bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13],
- 19 * sizeof(register_t));
- return (1);
- }
- return (0);
-}
-
-int
-cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
-{
- struct proc *p;
- struct trapframe *frame;
- caddr_t params;
- int error, n;
-
- p = td->td_proc;
- frame = td->td_frame;
-
- sa->code = frame->fixreg[0];
- params = (caddr_t)(frame->fixreg + FIRSTARG);
- n = NARGREG;
-
- if (sa->code == SYS_syscall) {
- /*
- * code is first argument,
- * followed by actual args.
- */
- sa->code = *(u_int *) params;
- params += sizeof(register_t);
- n -= 1;
- } else if (sa->code == SYS___syscall) {
- /*
- * Like syscall, but code is a quad,
- * so as to maintain quad alignment
- * for the rest of the args.
- */
- params += sizeof(register_t);
- sa->code = *(u_int *) params;
- params += sizeof(register_t);
- n -= 2;
- }
-
- if (p->p_sysent->sv_mask)
- sa->code &= p->p_sysent->sv_mask;
- if (sa->code >= p->p_sysent->sv_size)
- sa->callp = &p->p_sysent->sv_table[0];
- else
- sa->callp = &p->p_sysent->sv_table[sa->code];
- sa->narg = sa->callp->sy_narg;
-
- bcopy(params, sa->args, n * sizeof(register_t));
- if (sa->narg > n) {
- error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
- (sa->narg - n) * sizeof(register_t));
- } else
- error = 0;
-
- if (error == 0) {
- td->td_retval[0] = 0;
- td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
- }
- return (error);
-}
-
-#include "../../kern/subr_syscall.c"
-
-void
-syscall(struct trapframe *frame)
-{
- struct thread *td;
- struct syscall_args sa;
- int error;
-
- td = curthread;
- td->td_frame = frame;
-
- error = syscallenter(td, &sa);
- syscallret(td, error, &sa);
-}
-
-static int
-trap_pfault(struct trapframe *frame, int user)
-{
- vm_offset_t eva, va;
- struct thread *td;
- struct proc *p;
- vm_map_t map;
- vm_prot_t ftype;
- int rv;
-
- td = curthread;
- p = td->td_proc;
-
- if (frame->exc == EXC_ISI) {
- eva = frame->srr0;
- ftype = VM_PROT_READ | VM_PROT_EXECUTE;
-
- } else {
- eva = frame->dar;
- if (frame->cpu.booke.esr & ESR_ST)
- ftype = VM_PROT_WRITE;
- else
- ftype = VM_PROT_READ;
- }
-
- if (user) {
- KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL"));
- map = &p->p_vmspace->vm_map;
- } else {
- if (eva < VM_MAXUSER_ADDRESS) {
-
- if (p->p_vmspace == NULL)
- return (SIGSEGV);
-
- map = &p->p_vmspace->vm_map;
-
- } else {
- map = kernel_map;
- }
- }
- va = trunc_page(eva);
-
- if (map != kernel_map) {
- /*
- * Keep swapout from messing with us during this
- * critical time.
- */
- PROC_LOCK(p);
- ++p->p_lock;
- PROC_UNLOCK(p);
-
- /* Fault in the user page: */
- rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
-
- PROC_LOCK(p);
- --p->p_lock;
- PROC_UNLOCK(p);
- } else {
- /*
- * Don't have to worry about process locking or stacks in the
- * kernel.
- */
- rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
- }
-
- if (rv == KERN_SUCCESS)
- return (0);
-
- if (!user && handle_onfault(frame))
- return (0);
-
- return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV);
-}
-
-/*
- * For now, this only deals with the particular unaligned access case
- * that gcc tends to generate. Eventually it should handle all of the
- * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
- */
-
-static int
-fix_unaligned(struct thread *td, struct trapframe *frame)
-{
-#if 0
- struct thread *fputhread;
- int indicator, reg;
- double *fpr;
-
- indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
-
- switch (indicator) {
- case EXC_ALI_LFD:
- case EXC_ALI_STFD:
- reg = EXC_ALI_RST(frame->dsisr);
- fpr = &td->td_pcb->pcb_fpu.fpr[reg];
- fputhread = PCPU_GET(fputhread);
- /* Juggle the FPU to ensure that we've initialized
- * the FPRs, and that their current state is in
- * the PCB.
- */
- if (fputhread != td) {
- if (fputhread)
- save_fpu(fputhread);
- enable_fpu(td);
- }
- save_fpu(td);
-
- if (indicator == EXC_ALI_LFD) {
- if (copyin((void *)frame->dar, fpr,
- sizeof(double)) != 0)
- return -1;
- enable_fpu(td);
- } else {
- if (copyout(fpr, (void *)frame->dar,
- sizeof(double)) != 0)
- return -1;
- }
- return 0;
- break;
- }
-
-#endif
- return (-1);
-}
-
-#ifdef KDB
-int db_trap_glue(struct trapframe *);
-int
-db_trap_glue(struct trapframe *tf)
-{
- if (!(tf->srr1 & PSL_PR))
- return (kdb_trap(tf->exc, 0, tf));
- return (0);
-}
-#endif
diff --git a/sys/powerpc/booke/trap_subr.S b/sys/powerpc/booke/trap_subr.S
index bc6bad3..c585f14 100644
--- a/sys/powerpc/booke/trap_subr.S
+++ b/sys/powerpc/booke/trap_subr.S
@@ -497,6 +497,19 @@ INTERRUPT(int_watchdog)
b trap_common
+#ifdef HWPMC_HOOKS
+/*****************************************************************************
+ * PMC Interrupt
+ ****************************************************************************/
+INTERRUPT(int_performance_counter)
+ STANDARD_PROLOG(SPR_SPRG3, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
+ FRAME_SETUP(SPR_SPRG3, PC_TEMPSAVE, EXC_PERF)
+ addi %r3, %r1, 8
+ bl CNAME(powerpc_pmc_interrupt)
+ b trapexit
+#endif
+
+
/*****************************************************************************
* Data TLB miss interrupt
*
diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC
index e3939be..b5bf850 100644
--- a/sys/powerpc/conf/GENERIC
+++ b/sys/powerpc/conf/GENERIC
@@ -32,6 +32,7 @@ options PSIM #GDB PSIM ppc simulator
options MAMBO #IBM Mambo Full System Simulator
options PSERIES #PAPR-compliant systems
+options FDT
options SCHED_ULE #ULE scheduler
options PREEMPTION #Enable kernel thread preemption
options INET #InterNETworking
diff --git a/sys/powerpc/include/pmc_mdep.h b/sys/powerpc/include/pmc_mdep.h
index 87dc76c..eb74b56 100644
--- a/sys/powerpc/include/pmc_mdep.h
+++ b/sys/powerpc/include/pmc_mdep.h
@@ -7,9 +7,7 @@
#ifndef _MACHINE_PMC_MDEP_H_
#define _MACHINE_PMC_MDEP_H_
-#define PMC_MDEP_CLASS_INDEX_CPU 1
-#define PMC_MDEP_CLASS_INDEX_PPC7450 1
-#define PMC_MDEP_CLASS_INDEX_PPC970 1
+#define PMC_MDEP_CLASS_INDEX_POWERPC 1
union pmc_md_op_pmcallocate {
uint64_t __pad[4];
@@ -19,6 +17,60 @@ union pmc_md_op_pmcallocate {
#define PMCLOG_READADDR PMCLOG_READ32
#define PMCLOG_EMITADDR PMCLOG_EMIT32
+#define mtpmr(reg, val) \
+ __asm __volatile("mtpmr %0,%1" : : "K"(reg), "r"(val))
+#define mfpmr(reg) \
+ ( { register_t val; \
+ __asm __volatile("mfpmr %0,%1" : "=r"(val) : "K"(reg)); \
+ val; } )
+
+#define PMR_PMC0 16
+#define PMR_PMC1 17
+#define PMR_PMC2 18
+#define PMR_PMC3 19
+#define PMR_PMLCa0 144
+#define PMLCax_FC 0x80000000
+#define PMLCax_FCS 0x40000000
+#define PMLCax_FCU 0x20000000
+#define PMLCax_FCM1 0x10000000
+#define PMLCax_FCM0 0x08000000
+#define PMLCax_CE 0x04000000
+#define PMLCax_EVENT(x) ((x) << 16)
+#define PMLCax_FCGS1 0x00000002
+#define PMLCax_FCGS0 0x00000001
+#define PMR_PMLCa1 145
+#define PMR_PMLCa2 146
+#define PMR_PMLCa3 147
+#define PMR_PMLCb0 272
+#define PMLCbx_TRIGONCTL(x) ((x) << 28)
+#define PMLCbx_TRIGOFFCTL(x) ((x) << 24)
+#define PMLCbx_PMCC 0x00800000
+#define PMLCbx_PMP(x) ((x) << 13)
+#define PMLCbx_TREHMUL(x) ((x) << 8)
+#define PMLCbx_TRESHOLD(x) ((x) << 0)
+#define PMR_PMLCb1 273
+#define PMR_PMLCb2 274
+#define PMR_PMLCb3 275
+#define PMR_PMGC0 400
+#define PMGC_FAC 0x80000000
+#define PMGC_PMIE 0x40000000
+#define PMGC_FCECE 0x20000000
+#define PMGC_TBSEL(x) ((x) << 11)
+#define PMGC_TBEE 0x00000100
+#define PMR_UPMC0 0
+#define PMR_UPMC1 1
+#define PMR_UPMC2 2
+#define PMR_UPMC3 3
+#define PMR_UPMLCa0 128
+#define PMR_UPMLCa1 129
+#define PMR_UPMLCa2 130
+#define PMR_UPMLCa3 131
+#define PMR_UPMLCb0 256
+#define PMR_UPMLCb1 257
+#define PMR_UPMLCb2 258
+#define PMR_UPMLCb3 259
+#define PMR_UPMGC0 384
+
#if _KERNEL
struct pmc_md_powerpc_pmc {
diff --git a/sys/powerpc/include/reg.h b/sys/powerpc/include/reg.h
index f6c1722..e77625a 100644
--- a/sys/powerpc/include/reg.h
+++ b/sys/powerpc/include/reg.h
@@ -39,7 +39,7 @@ struct dbreg {
unsigned int junk;
};
-#ifdef COMPAT_FREEBSD32
+#ifdef __LP64__
/* Must match struct trapframe */
struct reg32 {
int32_t fixreg[32];
@@ -61,6 +61,8 @@ struct vmxreg32 {
struct dbreg32 {
struct dbreg data;
};
+
+#define __HAVE_REG32
#endif
#ifdef _KERNEL
diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h
index b3391b1..3ca4b13 100644
--- a/sys/powerpc/include/trap.h
+++ b/sys/powerpc/include/trap.h
@@ -85,7 +85,7 @@
#define EXC_DTMISS 0x1100 /* Data TLB Miss */
#define EXC_ITMISS 0x1200 /* Instruction TLB Miss */
#define EXC_APU 0x1300 /* Auxiliary Processing Unit */
-#define EXC_DEBUG 0x2000 /* Debug trap */
+#define EXC_DEBUG 0x2f10 /* Debug trap */
#define EXC_LAST 0x2f00 /* Last possible exception vector */
diff --git a/sys/powerpc/mpc85xx/mpc85xx_gpio.c b/sys/powerpc/mpc85xx/mpc85xx_gpio.c
new file mode 100644
index 0000000..e62f727
--- /dev/null
+++ b/sys/powerpc/mpc85xx/mpc85xx_gpio.c
@@ -0,0 +1,307 @@
+/*-
+ * Copyright (c) 2015 Justin Hibbits
+ * Copyright (c) 2013 Thomas Skibo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+#define MAXPIN (7)
+
+#define VALID_PIN(u) ((u) >= 0 && (u) <= MAXPIN)
+
+#define GPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define GPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define GPIO_LOCK_INIT(sc) \
+ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
+ "gpio", MTX_DEF)
+#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+
+struct mpc85xx_gpio_softc {
+ device_t dev;
+ device_t busdev;
+ struct mtx sc_mtx;
+ struct resource *out_res; /* Memory resource */
+ struct resource *in_res;
+};
+
+static device_t
+mpc85xx_gpio_get_bus(device_t dev)
+{
+ struct mpc85xx_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->busdev);
+}
+
+static int
+mpc85xx_gpio_pin_max(device_t dev, int *maxpin)
+{
+
+ *maxpin = MAXPIN;
+ return (0);
+}
+
+/* Get a specific pin's capabilities. */
+static int
+mpc85xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
+
+ return (0);
+}
+
+/* Get a specific pin's name. */
+static int
+mpc85xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ snprintf(name, GPIOMAXNAME, "GPIO%d", pin);
+ name[GPIOMAXNAME-1] = '\0';
+
+ return (0);
+}
+
+/* Set a specific output pin's value. */
+static int
+mpc85xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+ struct mpc85xx_gpio_softc *sc = device_get_softc(dev);
+ uint32_t outvals;
+ uint8_t pinbit;
+
+ if (!VALID_PIN(pin) || value > 1)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ pinbit = 31 - pin;
+
+ outvals = bus_read_4(sc->out_res, 0);
+ outvals &= ~(1 << pinbit);
+ outvals |= (value << pinbit);
+ bus_write_4(sc->out_res, 0, outvals);
+
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/* Get a specific pin's input value. */
+static int
+mpc85xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
+{
+ struct mpc85xx_gpio_softc *sc = device_get_softc(dev);
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ *value = (bus_read_4(sc->in_res, 0) >> (31 - pin)) & 1;
+
+ return (0);
+}
+
+/* Toggle a pin's output value. */
+static int
+mpc85xx_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct mpc85xx_gpio_softc *sc = device_get_softc(dev);
+ uint32_t val;
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+
+ val = bus_read_4(sc->out_res, 0);
+ val ^= (1 << (31 - pin));
+ bus_write_4(sc->out_res, 0, val);
+
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+mpc85xx_gpio_probe(device_t dev)
+{
+ uint16_t vers;
+ uint32_t svr;
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "gpio"))
+ return (ENXIO);
+
+ vers = mfpvr() >> 16;
+ switch (vers) {
+ case FSL_E500v1:
+ case FSL_E500v2:
+ case FSL_E500mc:
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ svr = mfspr(SPR_SVR);
+ switch (SVR_VER(svr)) {
+ case SVR_MPC8533:
+ case SVR_MPC8533E:
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ device_set_desc(dev, "MPC85xx GPIO driver");
+ return (0);
+}
+
+static int mpc85xx_gpio_detach(device_t dev);
+
+static int
+mpc85xx_gpio_attach(device_t dev)
+{
+ struct mpc85xx_gpio_softc *sc = device_get_softc(dev);
+ int rid;
+
+ sc->dev = dev;
+
+ GPIO_LOCK_INIT(sc);
+
+ /* Allocate memory. */
+ rid = 0;
+ sc->out_res = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (sc->out_res == NULL) {
+ device_printf(dev, "Can't allocate memory for device output port");
+ mpc85xx_gpio_detach(dev);
+ return (ENOMEM);
+ }
+
+ rid = 1;
+ sc->in_res = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (sc->in_res == NULL) {
+ device_printf(dev, "Can't allocate memory for device input port");
+ mpc85xx_gpio_detach(dev);
+ return (ENOMEM);
+ }
+
+ sc->busdev = gpiobus_attach_bus(dev);
+ if (sc->busdev == NULL) {
+ mpc85xx_gpio_detach(dev);
+ return (ENOMEM);
+ }
+
+ OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
+
+ return (0);
+}
+
+static int
+mpc85xx_gpio_detach(device_t dev)
+{
+ struct mpc85xx_gpio_softc *sc = device_get_softc(dev);
+
+ gpiobus_detach_bus(dev);
+
+ if (sc->out_res != NULL) {
+ /* Release output port resource. */
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->out_res), sc->out_res);
+ }
+
+ if (sc->in_res != NULL) {
+ /* Release input port resource. */
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->in_res), sc->in_res);
+ }
+
+ GPIO_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_method_t mpc85xx_gpio_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, mpc85xx_gpio_probe),
+ DEVMETHOD(device_attach, mpc85xx_gpio_attach),
+ DEVMETHOD(device_detach, mpc85xx_gpio_detach),
+
+ /* GPIO protocol */
+ DEVMETHOD(gpio_get_bus, mpc85xx_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, mpc85xx_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, mpc85xx_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getcaps, mpc85xx_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_get, mpc85xx_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, mpc85xx_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, mpc85xx_gpio_pin_toggle),
+
+ DEVMETHOD_END
+};
+
+static driver_t mpc85xx_gpio_driver = {
+ "gpio",
+ mpc85xx_gpio_methods,
+ sizeof(struct mpc85xx_gpio_softc),
+};
+static devclass_t mpc85xx_gpio_devclass;
+
+EARLY_DRIVER_MODULE(mpc85xx_gpio, simplebus, mpc85xx_gpio_driver,
+ mpc85xx_gpio_devclass, NULL, NULL,
+ BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c
index 05af094..31813fb 100644
--- a/sys/powerpc/ofw/ofw_machdep.c
+++ b/sys/powerpc/ofw/ofw_machdep.c
@@ -62,11 +62,12 @@ __FBSDID("$FreeBSD$");
#include <machine/ofw_machdep.h>
#include <machine/trap.h>
+static void *fdt;
+int ofw_real_mode;
+
#ifdef AIM
extern register_t ofmsr[5];
extern void *openfirmware_entry;
-static void *fdt;
-int ofw_real_mode;
char save_trap_init[0x2f00]; /* EXC_LAST */
char save_trap_of[0x2f00]; /* EXC_LAST */
@@ -336,10 +337,10 @@ ofw_mem_regions(struct mem_region *memp, int *memsz,
*availsz = asz;
}
-#ifdef AIM
void
OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
{
+#ifdef AIM
ofmsr[0] = mfmsr();
#ifdef __powerpc64__
ofmsr[0] &= ~PSL_SF;
@@ -348,22 +349,25 @@ OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
__asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2]));
__asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3]));
__asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4]));
+ openfirmware_entry = openfirm;
if (ofmsr[0] & PSL_DR)
ofw_real_mode = 0;
else
ofw_real_mode = 1;
+ ofw_save_trap_vec(save_trap_init);
+#else
+ ofw_real_mode = 1;
+#endif
+
fdt = fdt_ptr;
- openfirmware_entry = openfirm;
#ifdef FDT_DTB_STATIC
/* Check for a statically included blob */
if (fdt == NULL)
fdt = &fdt_static_dtb;
#endif
-
- ofw_save_trap_vec(save_trap_init);
}
boolean_t
@@ -371,6 +375,7 @@ OF_bootstrap()
{
boolean_t status = FALSE;
+#ifdef AIM
if (openfirmware_entry != NULL) {
if (ofw_real_mode) {
status = OF_install(OFW_STD_REAL, 0);
@@ -386,18 +391,22 @@ OF_bootstrap()
return status;
OF_init(openfirmware);
- } else if (fdt != NULL) {
+ } else
+#endif
+ if (fdt != NULL) {
status = OF_install(OFW_FDT, 0);
if (status != TRUE)
return status;
OF_init(fdt);
+ OF_interpret("perform-fixup", 0);
}
return (status);
}
+#ifdef AIM
void
ofw_quiesce(void)
{
diff --git a/sys/powerpc/powerpc/busdma_machdep.c b/sys/powerpc/powerpc/busdma_machdep.c
index bd226c8..9ea51ce 100644
--- a/sys/powerpc/powerpc/busdma_machdep.c
+++ b/sys/powerpc/powerpc/busdma_machdep.c
@@ -1121,8 +1121,8 @@ add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
/* Page offset needs to be preserved. */
- bpage->vaddr |= vaddr & PAGE_MASK;
- bpage->busaddr |= vaddr & PAGE_MASK;
+ bpage->vaddr |= addr & PAGE_MASK;
+ bpage->busaddr |= addr & PAGE_MASK;
}
bpage->datavaddr = vaddr;
bpage->dataaddr = addr;
diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c
new file mode 100644
index 0000000..2bc9496
--- /dev/null
+++ b/sys/powerpc/powerpc/machdep.c
@@ -0,0 +1,502 @@
+/*-
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (C) 2001 Benno Rice
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * $NetBSD: machdep.c,v 1.74.2.1 2000/11/01 16:13:48 tv Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+#include "opt_ddb.h"
+#include "opt_kstack_pages.h"
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/cpu.h>
+#include <sys/eventhandler.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/msgbuf.h>
+#include <sys/mutex.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/rwlock.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+#include <sys/uio.h>
+#include <sys/vmmeter.h>
+#include <sys/vnode.h>
+
+#include <net/netisr.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+
+#include <machine/altivec.h>
+#ifndef __powerpc64__
+#include <machine/bat.h>
+#endif
+#include <machine/cpu.h>
+#include <machine/elf.h>
+#include <machine/fpu.h>
+#include <machine/hid.h>
+#include <machine/kdb.h>
+#include <machine/md_var.h>
+#include <machine/metadata.h>
+#include <machine/mmuvar.h>
+#include <machine/pcb.h>
+#include <machine/reg.h>
+#include <machine/sigframe.h>
+#include <machine/spr.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+#include <machine/ofw_machdep.h>
+
+#include <ddb/ddb.h>
+
+#include <dev/ofw/openfirm.h>
+
+int cold = 1;
+#ifdef __powerpc64__
+int cacheline_size = 128;
+#else
+int cacheline_size = 32;
+#endif
+int hw_direct_map = 1;
+
+extern void *ap_pcpu;
+
+struct pcpu __pcpu[MAXCPU];
+
+static struct trapframe frame0;
+
+char machine[] = "powerpc";
+SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
+
+static void cpu_startup(void *);
+SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
+
+SYSCTL_INT(_machdep, CPU_CACHELINE, cacheline_size,
+ CTLFLAG_RD, &cacheline_size, 0, "");
+
+uintptr_t powerpc_init(vm_offset_t, vm_offset_t, vm_offset_t, void *);
+
+long Maxmem = 0;
+long realmem = 0;
+
+struct kva_md_info kmi;
+
+static void
+cpu_startup(void *dummy)
+{
+
+ /*
+ * Initialise the decrementer-based clock.
+ */
+ decr_init();
+
+ /*
+ * Good {morning,afternoon,evening,night}.
+ */
+ cpu_setup(PCPU_GET(cpuid));
+
+#ifdef PERFMON
+ perfmon_init();
+#endif
+ printf("real memory = %ld (%ld MB)\n", ptoa(physmem),
+ ptoa(physmem) / 1048576);
+ realmem = physmem;
+
+ if (bootverbose)
+ printf("available KVA = %zd (%zd MB)\n",
+ virtual_end - virtual_avail,
+ (virtual_end - virtual_avail) / 1048576);
+
+ /*
+ * Display any holes after the first chunk of extended memory.
+ */
+ if (bootverbose) {
+ int indx;
+
+ printf("Physical memory chunk(s):\n");
+ for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
+ vm_offset_t size1 =
+ phys_avail[indx + 1] - phys_avail[indx];
+
+ #ifdef __powerpc64__
+ printf("0x%016lx - 0x%016lx, %ld bytes (%ld pages)\n",
+ #else
+ printf("0x%08x - 0x%08x, %d bytes (%ld pages)\n",
+ #endif
+ phys_avail[indx], phys_avail[indx + 1] - 1, size1,
+ size1 / PAGE_SIZE);
+ }
+ }
+
+ vm_ksubmap_init(&kmi);
+
+ printf("avail memory = %ld (%ld MB)\n", ptoa(vm_cnt.v_free_count),
+ ptoa(vm_cnt.v_free_count) / 1048576);
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+ vm_pager_bufferinit();
+}
+
+extern vm_offset_t __startkernel, __endkernel;
+extern unsigned char __bss_start[];
+extern unsigned char __sbss_start[];
+extern unsigned char __sbss_end[];
+extern unsigned char _end[];
+
+void aim_cpu_init(vm_offset_t toc);
+void booke_cpu_init(void);
+
+uintptr_t
+powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp)
+{
+ struct pcpu *pc;
+ vm_offset_t startkernel, endkernel;
+ void *kmdp;
+ char *env;
+#ifdef DDB
+ vm_offset_t ksym_start;
+ vm_offset_t ksym_end;
+#endif
+
+ kmdp = NULL;
+
+ /* First guess at start/end kernel positions */
+ startkernel = __startkernel;
+ endkernel = __endkernel;
+
+ /* Check for ePAPR loader, which puts a magic value into r6 */
+ if (mdp == (void *)0x65504150)
+ mdp = NULL;
+
+ /*
+ * Parse metadata if present and fetch parameters. Must be done
+ * before console is inited so cninit gets the right value of
+ * boothowto.
+ */
+ if (mdp != NULL) {
+ preload_metadata = mdp;
+ kmdp = preload_search_by_type("elf kernel");
+ if (kmdp != NULL) {
+ boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
+ kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
+ endkernel = ulmax(endkernel, MD_FETCH(kmdp,
+ MODINFOMD_KERNEND, vm_offset_t));
+#ifdef DDB
+ ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
+ ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
+ db_fetch_ksymtab(ksym_start, ksym_end);
+#endif
+ }
+ } else {
+ bzero(__sbss_start, __sbss_end - __sbss_start);
+ bzero(__bss_start, _end - __bss_start);
+ }
+#ifdef BOOKE
+ tlb1_init();
+#endif
+
+ /* Store boot environment state */
+ OF_initial_setup((void *)fdt, NULL, (int (*)(void *))ofentry);
+
+ /*
+ * Init params/tunables that can be overridden by the loader
+ */
+ init_param1();
+
+ /*
+ * Start initializing proc0 and thread0.
+ */
+ proc_linkup0(&proc0, &thread0);
+ thread0.td_frame = &frame0;
+
+ /*
+ * Set up per-cpu data.
+ */
+ pc = __pcpu;
+ pcpu_init(pc, 0, sizeof(struct pcpu));
+ pc->pc_curthread = &thread0;
+#ifdef __powerpc64__
+ __asm __volatile("mr 13,%0" :: "r"(pc->pc_curthread));
+#else
+ __asm __volatile("mr 2,%0" :: "r"(pc->pc_curthread));
+#endif
+ pc->pc_cpuid = 0;
+
+ __asm __volatile("mtsprg 0, %0" :: "r"(pc));
+
+ /*
+ * Init mutexes, which we use heavily in PMAP
+ */
+
+ mutex_init();
+
+ /*
+ * Install the OF client interface
+ */
+
+ OF_bootstrap();
+
+ /*
+ * Initialize the console before printing anything.
+ */
+ cninit();
+
+ /*
+ * Complain if there is no metadata.
+ */
+ if (mdp == NULL || kmdp == NULL) {
+ printf("powerpc_init: no loader metadata.\n");
+ }
+
+ /*
+ * Init KDB
+ */
+
+ kdb_init();
+
+#ifdef AIM
+ aim_cpu_init(toc);
+#else /* BOOKE */
+ booke_cpu_init();
+
+ /* Make sure the kernel icache is valid before we go too much further */
+ __syncicache((caddr_t)startkernel, endkernel - startkernel);
+#endif
+
+ /*
+ * Choose a platform module so we can get the physical memory map.
+ */
+
+ platform_probe_and_attach();
+
+ /*
+ * Bring up MMU
+ */
+ pmap_bootstrap(startkernel, endkernel);
+ mtmsr(PSL_KERNSET & ~PSL_EE);
+
+ /*
+ * Initialize params/tunables that are derived from memsize
+ */
+ init_param2(physmem);
+
+ /*
+ * Grab booted kernel's name
+ */
+ env = kern_getenv("kernelname");
+ if (env != NULL) {
+ strlcpy(kernelname, env, sizeof(kernelname));
+ freeenv(env);
+ }
+
+ /*
+ * Finish setting up thread0.
+ */
+ thread0.td_pcb = (struct pcb *)
+ ((thread0.td_kstack + thread0.td_kstack_pages * PAGE_SIZE -
+ sizeof(struct pcb)) & ~15UL);
+ bzero((void *)thread0.td_pcb, sizeof(struct pcb));
+ pc->pc_curpcb = thread0.td_pcb;
+
+ /* Initialise the message buffer. */
+ msgbufinit(msgbufp, msgbufsize);
+
+#ifdef KDB
+ if (boothowto & RB_KDB)
+ kdb_enter(KDB_WHY_BOOTFLAGS,
+ "Boot flags requested debugger");
+#endif
+
+ return (((uintptr_t)thread0.td_pcb -
+ (sizeof(struct callframe) - 3*sizeof(register_t))) & ~15UL);
+}
+
+void
+bzero(void *buf, size_t len)
+{
+ caddr_t p;
+
+ p = buf;
+
+ while (((vm_offset_t) p & (sizeof(u_long) - 1)) && len) {
+ *p++ = 0;
+ len--;
+ }
+
+ while (len >= sizeof(u_long) * 8) {
+ *(u_long*) p = 0;
+ *((u_long*) p + 1) = 0;
+ *((u_long*) p + 2) = 0;
+ *((u_long*) p + 3) = 0;
+ len -= sizeof(u_long) * 8;
+ *((u_long*) p + 4) = 0;
+ *((u_long*) p + 5) = 0;
+ *((u_long*) p + 6) = 0;
+ *((u_long*) p + 7) = 0;
+ p += sizeof(u_long) * 8;
+ }
+
+ while (len >= sizeof(u_long)) {
+ *(u_long*) p = 0;
+ len -= sizeof(u_long);
+ p += sizeof(u_long);
+ }
+
+ while (len) {
+ *p++ = 0;
+ len--;
+ }
+}
+
+/*
+ * Flush the D-cache for non-DMA I/O so that the I-cache can
+ * be made coherent later.
+ */
+void
+cpu_flush_dcache(void *ptr, size_t len)
+{
+ register_t addr, off;
+
+ /*
+ * Align the address to a cacheline and adjust the length
+ * accordingly. Then round the length to a multiple of the
+ * cacheline for easy looping.
+ */
+ addr = (uintptr_t)ptr;
+ off = addr & (cacheline_size - 1);
+ addr -= off;
+ len = (len + off + cacheline_size - 1) & ~(cacheline_size - 1);
+
+ while (len > 0) {
+ __asm __volatile ("dcbf 0,%0" :: "r"(addr));
+ __asm __volatile ("sync");
+ addr += cacheline_size;
+ len -= cacheline_size;
+ }
+}
+
+int
+ptrace_set_pc(struct thread *td, unsigned long addr)
+{
+ struct trapframe *tf;
+
+ tf = td->td_frame;
+ tf->srr0 = (register_t)addr;
+
+ return (0);
+}
+
+void
+spinlock_enter(void)
+{
+ struct thread *td;
+ register_t msr;
+
+ td = curthread;
+ if (td->td_md.md_spinlock_count == 0) {
+ __asm __volatile("or 2,2,2"); /* Set high thread priority */
+ msr = intr_disable();
+ td->td_md.md_spinlock_count = 1;
+ td->td_md.md_saved_msr = msr;
+ } else
+ td->td_md.md_spinlock_count++;
+ critical_enter();
+}
+
+void
+spinlock_exit(void)
+{
+ struct thread *td;
+ register_t msr;
+
+ td = curthread;
+ critical_exit();
+ msr = td->td_md.md_saved_msr;
+ td->td_md.md_spinlock_count--;
+ if (td->td_md.md_spinlock_count == 0) {
+ intr_restore(msr);
+ __asm __volatile("or 6,6,6"); /* Set normal thread priority */
+ }
+}
+
diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/powerpc/trap.c
index e0e2fe6..0ceb170 100644
--- a/sys/powerpc/aim/trap.c
+++ b/sys/powerpc/powerpc/trap.c
@@ -74,6 +74,12 @@ __FBSDID("$FreeBSD$");
#include <machine/spr.h>
#include <machine/sr.h>
+#define FAULTBUF_LR 0
+#define FAULTBUF_R1 1
+#define FAULTBUF_R2 2
+#define FAULTBUF_CR 3
+#define FAULTBUF_R13 4
+
static void trap_fatal(struct trapframe *frame);
static void printtrap(u_int vector, struct trapframe *frame, int isfatal,
int user);
@@ -100,32 +106,37 @@ int (*dtrace_invop_jump_addr)(struct trapframe *);
#endif
static struct powerpc_exception powerpc_exceptions[] = {
- { 0x0100, "system reset" },
- { 0x0200, "machine check" },
- { 0x0300, "data storage interrupt" },
- { 0x0380, "data segment exception" },
- { 0x0400, "instruction storage interrupt" },
- { 0x0480, "instruction segment exception" },
- { 0x0500, "external interrupt" },
- { 0x0600, "alignment" },
- { 0x0700, "program" },
- { 0x0800, "floating-point unavailable" },
- { 0x0900, "decrementer" },
- { 0x0c00, "system call" },
- { 0x0d00, "trace" },
- { 0x0e00, "floating-point assist" },
- { 0x0f00, "performance monitoring" },
- { 0x0f20, "altivec unavailable" },
- { 0x0f40, "vsx unavailable" },
- { 0x1000, "instruction tlb miss" },
- { 0x1100, "data load tlb miss" },
- { 0x1200, "data store tlb miss" },
- { 0x1300, "instruction breakpoint" },
- { 0x1400, "system management" },
- { 0x1600, "altivec assist" },
- { 0x1700, "thermal management" },
- { 0x2000, "run mode/trace" },
- { 0x3000, NULL }
+ { EXC_CRIT, "critical input" },
+ { EXC_RST, "system reset" },
+ { EXC_MCHK, "machine check" },
+ { EXC_DSI, "data storage interrupt" },
+ { EXC_DSE, "data segment exception" },
+ { EXC_ISI, "instruction storage interrupt" },
+ { EXC_ISE, "instruction segment exception" },
+ { EXC_EXI, "external interrupt" },
+ { EXC_ALI, "alignment" },
+ { EXC_PGM, "program" },
+ { EXC_FPU, "floating-point unavailable" },
+ { EXC_APU, "auxiliary proc unavailable" },
+ { EXC_DECR, "decrementer" },
+ { EXC_FIT, "fixed-interval timer" },
+ { EXC_WDOG, "watchdog timer" },
+ { EXC_SC, "system call" },
+ { EXC_TRC, "trace" },
+ { EXC_FPA, "floating-point assist" },
+ { EXC_DEBUG, "debug" },
+ { EXC_PERF, "performance monitoring" },
+ { EXC_VEC, "altivec unavailable" },
+ { EXC_VSX, "vsx unavailable" },
+ { EXC_ITMISS, "instruction tlb miss" },
+ { EXC_DLMISS, "data load tlb miss" },
+ { EXC_DSMISS, "data store tlb miss" },
+ { EXC_BPT, "instruction breakpoint" },
+ { EXC_SMI, "system management" },
+ { EXC_VECAST_G4, "altivec assist" },
+ { EXC_THRM, "thermal management" },
+ { EXC_RUNMODETRC, "run mode/trace" },
+ { EXC_LAST, NULL }
};
static const char *
@@ -133,7 +144,7 @@ trapname(u_int vector)
{
struct powerpc_exception *pe;
- for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
+ for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) {
if (pe->vector == vector)
return (pe->name);
}
@@ -265,9 +276,21 @@ trap(struct trapframe *frame)
frame->srr0 += 4;
break;
+ case EXC_DEBUG: /* Single stepping */
+ mtspr(SPR_DBSR, mfspr(SPR_DBSR));
+ frame->srr1 &= ~PSL_DE;
+ frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC);
+ sig = SIGTRAP;
+ ucode = TRAP_TRACE;
+ break;
+
case EXC_PGM:
/* Identify the trap reason */
+#ifdef AIM
if (frame->srr1 & EXC_PGM_TRAP) {
+#else
+ if (frame->cpu.booke.esr & ESR_PTR) {
+#endif
#ifdef KDTRACE_HOOKS
inst = fuword32((const void *)frame->srr0);
if (inst == 0x0FFFDDDD &&
@@ -386,15 +409,23 @@ printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
switch (vector) {
case EXC_DSE:
case EXC_DSI:
+ case EXC_DTMISS:
printf(" virtual address = 0x%" PRIxPTR "\n", frame->dar);
+#ifdef AIM
printf(" dsisr = 0x%" PRIxPTR "\n",
frame->cpu.aim.dsisr);
+#endif
break;
case EXC_ISE:
case EXC_ISI:
+ case EXC_ITMISS:
printf(" virtual address = 0x%" PRIxPTR "\n", frame->srr0);
break;
}
+#ifdef BOOKE
+ printf(" esr = 0x%" PRIxPTR "\n",
+ frame->cpu.booke.esr);
+#endif
printf(" srr0 = 0x%" PRIxPTR "\n", frame->srr0);
printf(" srr1 = 0x%" PRIxPTR "\n", frame->srr1);
printf(" lr = 0x%" PRIxPTR "\n", frame->lr);
@@ -418,12 +449,12 @@ handle_onfault(struct trapframe *frame)
td = curthread;
fb = td->td_pcb->pcb_onfault;
if (fb != NULL) {
- frame->srr0 = (*fb)[0];
- frame->fixreg[1] = (*fb)[1];
- frame->fixreg[2] = (*fb)[2];
+ frame->srr0 = (*fb)[FAULTBUF_LR];
+ frame->fixreg[1] = (*fb)[FAULTBUF_R1];
+ frame->fixreg[2] = (*fb)[FAULTBUF_R2];
frame->fixreg[3] = 1;
- frame->cr = (*fb)[3];
- bcopy(&(*fb)[4], &frame->fixreg[13],
+ frame->cr = (*fb)[FAULTBUF_CR];
+ bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13],
19 * sizeof(register_t));
return (1);
}
@@ -630,7 +661,9 @@ trap_pfault(struct trapframe *frame, int user)
vm_map_t map;
vm_prot_t ftype;
int rv;
+#ifdef AIM
register_t user_sr;
+#endif
td = curthread;
p = td->td_proc;
@@ -641,24 +674,35 @@ trap_pfault(struct trapframe *frame, int user)
ftype |= VM_PROT_READ;
} else {
eva = frame->dar;
+#ifdef BOOKE
+ if (frame->cpu.booke.esr & ESR_ST)
+#else
if (frame->cpu.aim.dsisr & DSISR_STORE)
+#endif
ftype = VM_PROT_WRITE;
else
ftype = VM_PROT_READ;
}
if (user) {
+ KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace NULL"));
map = &p->p_vmspace->vm_map;
} else {
+#ifdef BOOKE
+ if (eva < VM_MAXUSER_ADDRESS) {
+#else
if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) {
+#endif
if (p->p_vmspace == NULL)
return (SIGSEGV);
map = &p->p_vmspace->vm_map;
+#ifdef AIM
user_sr = td->td_pcb->pcb_cpu.aim.usr_segm;
eva &= ADDR_PIDX | ADDR_POFF;
eva |= user_sr << ADDR_SR_SHFT;
+#endif
} else {
map = kernel_map;
}
@@ -736,17 +780,51 @@ fix_unaligned(struct thread *td, struct trapframe *frame)
if (indicator == EXC_ALI_LFD) {
if (copyin((void *)frame->dar, fpr,
sizeof(double)) != 0)
- return -1;
+ return (-1);
enable_fpu(td);
} else {
if (copyout(fpr, (void *)frame->dar,
sizeof(double)) != 0)
- return -1;
+ return (-1);
}
- return 0;
+ return (0);
break;
}
- return -1;
+ return (-1);
}
+#ifdef KDB
+int db_trap_glue(struct trapframe *); /* Called from trap_subr.S */
+
+int
+db_trap_glue(struct trapframe *frame)
+{
+ if (!(frame->srr1 & PSL_PR)
+ && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC
+#ifdef AIM
+ || (frame->exc == EXC_PGM
+ && (frame->srr1 & 0x20000))
+#else
+ || (frame->exc == EXC_DEBUG)
+#endif
+ || frame->exc == EXC_BPT
+ || frame->exc == EXC_DSI)) {
+ int type = frame->exc;
+
+ /* Ignore DTrace traps. */
+ if (*(uint32_t *)frame->srr0 == EXC_DTRACE)
+ return (0);
+#ifdef AIM
+ if (type == EXC_PGM && (frame->srr1 & 0x20000)) {
+#else
+ if (frame->cpu.booke.esr & ESR_PTR) {
+#endif
+ type = T_BREAKPOINT;
+ }
+ return (kdb_trap(type, 0, frame));
+ }
+
+ return (0);
+}
+#endif
diff --git a/sys/powerpc/aim/uma_machdep.c b/sys/powerpc/powerpc/uma_machdep.c
index 1c27e3e..1c27e3e 100644
--- a/sys/powerpc/aim/uma_machdep.c
+++ b/sys/powerpc/powerpc/uma_machdep.c
diff --git a/sys/rpc/svc_generic.c b/sys/rpc/svc_generic.c
index 59e36c2..2ce010d 100644
--- a/sys/rpc/svc_generic.c
+++ b/sys/rpc/svc_generic.c
@@ -168,7 +168,7 @@ svc_tp_create(
taddr = uaddr2taddr(nconf, uaddr);
bind.addr = *taddr;
free(taddr, M_RPC);
- bind.qlen = SOMAXCONN;
+ bind.qlen = -1;
xprt = svc_tli_create(pool, NULL, nconf, &bind, 0, 0);
free(bind.addr.buf, M_RPC);
} else {
@@ -256,7 +256,7 @@ svc_tli_create(
goto freedata;
}
}
- solisten(so, SOMAXCONN, curthread);
+ solisten(so, -1, curthread);
} else {
if (bindresvport(so,
(struct sockaddr *)bindaddr->addr.buf)) {
diff --git a/sys/rpc/svc_vc.c b/sys/rpc/svc_vc.c
index 920c4b5..1d3d041 100644
--- a/sys/rpc/svc_vc.c
+++ b/sys/rpc/svc_vc.c
@@ -177,7 +177,7 @@ svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
xprt_register(xprt);
- solisten(so, SOMAXCONN, curthread);
+ solisten(so, -1, curthread);
SOCKBUF_LOCK(&so->so_rcv);
xprt->xp_upcallset = 1;
diff --git a/sys/sparc64/include/reg.h b/sys/sparc64/include/reg.h
index d224186..8a4dd2a 100644
--- a/sys/sparc64/include/reg.h
+++ b/sys/sparc64/include/reg.h
@@ -98,6 +98,12 @@ struct dbreg {
int dummy;
};
+/*
+ * NB: sparcv8 binaries are not supported even though this header
+ * defines the relevant structures.
+ */
+#define __HAVE_REG32
+
#ifdef _KERNEL
/*
* XXX these interfaces are MI, so they should be declared in a MI place.
diff --git a/sys/sparc64/pci/apb.c b/sys/sparc64/pci/apb.c
index 9b3fa44..c0d6172 100644
--- a/sys/sparc64/pci/apb.c
+++ b/sys/sparc64/pci/apb.c
@@ -171,20 +171,14 @@ apb_attach(device_t dev)
* Get current bridge configuration.
*/
sc->sc_bsc.ops_pcib_sc.domain = pci_get_domain(dev);
- sc->sc_bsc.ops_pcib_sc.secstat =
- pci_read_config(dev, PCIR_SECSTAT_1, 2);
- sc->sc_bsc.ops_pcib_sc.command =
- pci_read_config(dev, PCIR_COMMAND, 2);
- sc->sc_bsc.ops_pcib_sc.pribus =
- pci_read_config(dev, PCIR_PRIBUS_1, 1);
+ sc->sc_bsc.ops_pcib_sc.pribus = pci_get_bus(dev);
+ pci_write_config(dev, PCIR_PRIBUS_1, sc->sc_bsc.ops_pcib_sc.pribus, 1);
sc->sc_bsc.ops_pcib_sc.bus.sec =
pci_read_config(dev, PCIR_SECBUS_1, 1);
sc->sc_bsc.ops_pcib_sc.bus.sub =
pci_read_config(dev, PCIR_SUBBUS_1, 1);
sc->sc_bsc.ops_pcib_sc.bridgectl =
pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
- sc->sc_bsc.ops_pcib_sc.seclat =
- pci_read_config(dev, PCIR_SECLAT_1, 1);
sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1);
sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1);
diff --git a/sys/sparc64/pci/sbbc.c b/sys/sparc64/pci/sbbc.c
index c19fb71..f1e7fab 100644
--- a/sys/sparc64/pci/sbbc.c
+++ b/sys/sparc64/pci/sbbc.c
@@ -813,7 +813,8 @@ struct uart_class uart_sbbc_class = {
sizeof(struct uart_softc),
.uc_ops = &sbbc_uart_ops,
.uc_range = 1,
- .uc_rclk = 0x5bbc /* arbitrary */
+ .uc_rclk = 0x5bbc, /* arbitrary */
+ .uc_rshift = 0
};
#define SIGCHG(c, i, s, d) \
diff --git a/sys/sys/buf.h b/sys/sys/buf.h
index 72ab61b..4e2af1a 100644
--- a/sys/sys/buf.h
+++ b/sys/sys/buf.h
@@ -231,8 +231,8 @@ struct buf {
#define PRINT_BUF_FLAGS "\20\40remfree\37cluster\36vmio\35ram\34managed" \
"\33paging\32infreecnt\31nocopy\30b23\27relbuf\26dirty\25b20" \
"\24b19\23b18\22clusterok\21malloc\20nocache\17b14\16inval" \
- "\15b12\14b11\13eintr\12done\11persist\10delwri\7validsuspwrt" \
- "\6cache\5deferred\4direct\3async\2needcommit\1age"
+ "\15kvaalloc\14unmapped\13eintr\12done\11persist\10delwri" \
+ "\7validsuspwrt\6cache\5deferred\4direct\3async\2needcommit\1age"
/*
* These flags are kept in b_xflags.
diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h
index fa0caa5..ab7d59d 100644
--- a/sys/sys/cdefs.h
+++ b/sys/sys/cdefs.h
@@ -375,8 +375,10 @@
#endif
#if __GNUC_PREREQ__(4, 1)
+#define __gnu_inline __attribute__((__gnu_inline__))
#define __returns_twice __attribute__((__returns_twice__))
#else
+#define __gnu_inline
#define __returns_twice
#endif
@@ -386,6 +388,12 @@
#define __alloc_size(x)
#endif
+#if __has_attribute(alloc_align) || __GNUC_PREREQ__(4, 9)
+#define __alloc_align(x) __attribute__((__alloc_align__(x)))
+#else
+#define __alloc_align(x)
+#endif
+
/* XXX: should use `#if __STDC_VERSION__ < 199901'. */
#if !__GNUC_PREREQ__(2, 7) && !defined(__INTEL_COMPILER)
#define __func__ NULL
@@ -761,6 +769,24 @@
#endif
/*
+ * Type Safety Checking
+ *
+ * Clang provides additional attributes to enable checking type safety
+ * properties that cannot be enforced by the C type system.
+ */
+
+#if __has_attribute(argument_with_type_tag) && \
+ __has_attribute(type_tag_for_datatype) && !defined(lint)
+#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx) \
+ __attribute__((__argument_with_type_tag__(arg_kind, arg_idx, type_tag_idx)))
+#define __datatype_type_tag(kind, type) \
+ __attribute__((__type_tag_for_datatype__(kind, type)))
+#else
+#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx)
+#define __datatype_type_tag(kind, type)
+#endif
+
+/*
* Lock annotations.
*
* Clang provides support for doing basic thread-safety tests at
diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h
index 19f460d..aa06c70 100644
--- a/sys/sys/elf_common.h
+++ b/sys/sys/elf_common.h
@@ -863,6 +863,7 @@ typedef struct {
#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */
#define R_386_IRELATIVE 42 /* PLT entry resolved indirectly at runtime */
+#define R_AARCH64_NONE 0 /* No relocation */
#define R_AARCH64_ABS64 257 /* Absolute offset */
#define R_AARCH64_ABS32 258 /* Absolute, 32-bit overflow check */
#define R_AARCH64_ABS16 259 /* Absolute, 16-bit overflow check */
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index 85db07f..5793229 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -129,6 +129,10 @@ typedef __pid_t pid_t;
#define O_CLOEXEC 0x00100000
#endif
+#if __BSD_VISIBLE
+#define O_VERIFY 0x00200000 /* open only after verification */
+#endif
+
/*
* XXX missing O_DSYNC, O_RSYNC.
*/
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
index 4eef17b..eca30ff 100644
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -152,7 +152,7 @@ int finstall(struct thread *td, struct file *fp, int *resultfp, int flags,
int fdalloc(struct thread *td, int minfd, int *result);
int fdallocn(struct thread *td, int minfd, int *fds, int n);
int fdcheckstd(struct thread *td);
-void fdclose(struct filedesc *fdp, struct file *fp, int idx, struct thread *td);
+void fdclose(struct thread *td, struct file *fp, int idx);
void fdcloseexec(struct thread *td);
void fdsetugidsafety(struct thread *td);
struct filedesc *fdcopy(struct filedesc *fdp);
diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h
index 8440939..ac88a14 100644
--- a/sys/sys/imgact.h
+++ b/sys/sys/imgact.h
@@ -80,6 +80,7 @@ struct image_params {
unsigned long pagesizes;
int pagesizeslen;
vm_prot_t stack_prot;
+ u_long stack_sz;
};
#ifdef _KERNEL
diff --git a/sys/sys/kerneldump.h b/sys/sys/kerneldump.h
index 4254ab2..763b7cd 100644
--- a/sys/sys/kerneldump.h
+++ b/sys/sys/kerneldump.h
@@ -66,6 +66,7 @@ struct kerneldumpheader {
uint32_t version;
#define KERNELDUMPVERSION 1
uint32_t architectureversion;
+#define KERNELDUMP_AARCH64_VERSION 1
#define KERNELDUMP_AMD64_VERSION 2
#define KERNELDUMP_ARM_VERSION 1
#define KERNELDUMP_I386_VERSION 2
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index dcb4290..6b8a9c0 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -173,9 +173,11 @@ typedef void malloc_type_list_func_t(struct malloc_type *, void *);
void contigfree(void *addr, unsigned long size, struct malloc_type *type);
void *contigmalloc(unsigned long size, struct malloc_type *type, int flags,
vm_paddr_t low, vm_paddr_t high, unsigned long alignment,
- vm_paddr_t boundary) __malloc_like;
+ vm_paddr_t boundary) __malloc_like __result_use_check
+ __alloc_size(1);
void free(void *addr, struct malloc_type *type);
-void *malloc(unsigned long size, struct malloc_type *type, int flags) __malloc_like;
+void *malloc(unsigned long size, struct malloc_type *type, int flags)
+ __malloc_like __result_use_check __alloc_size(1);
void malloc_init(void *);
int malloc_last_fail(void);
void malloc_type_allocated(struct malloc_type *type, unsigned long size);
@@ -183,9 +185,9 @@ void malloc_type_freed(struct malloc_type *type, unsigned long size);
void malloc_type_list(malloc_type_list_func_t *, void *);
void malloc_uninit(void *);
void *realloc(void *addr, unsigned long size, struct malloc_type *type,
- int flags);
+ int flags) __result_use_check __alloc_size(2);
void *reallocf(void *addr, unsigned long size, struct malloc_type *type,
- int flags);
+ int flags) __alloc_size(2);
struct malloc_type *malloc_desc2type(const char *desc);
#endif /* _KERNEL */
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 6203212..ab06547 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -616,8 +616,8 @@ m_getzone(int size)
* should go away with constant propagation for !MGETHDR.
*/
static __inline int
-m_init(struct mbuf *m, uma_zone_t zone, int size, int how, short type,
- int flags)
+m_init(struct mbuf *m, uma_zone_t zone __unused, int size __unused, int how,
+ short type, int flags)
{
int error;
@@ -686,8 +686,8 @@ static __inline int
m_clget(struct mbuf *m, int how)
{
- if (m->m_flags & M_EXT)
- printf("%s: %p mbuf already has external storage\n", __func__, m);
+ KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
+ __func__, m));
m->m_ext.ext_buf = (char *)NULL;
uma_zalloc_arg(zone_clust, m, how);
/*
@@ -713,10 +713,11 @@ m_cljget(struct mbuf *m, int how, int size)
{
uma_zone_t zone;
- if (m && m->m_flags & M_EXT)
- printf("%s: %p mbuf already has external storage\n", __func__, m);
- if (m != NULL)
+ if (m != NULL) {
+ KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
+ __func__, m));
m->m_ext.ext_buf = NULL;
+ }
zone = m_getzone(size);
return (uma_zalloc_arg(zone, m, how));
@@ -1121,7 +1122,7 @@ m_tag_first(struct mbuf *m)
* Return the next tag in the list of tags associated with an mbuf.
*/
static __inline struct m_tag *
-m_tag_next(struct mbuf *m, struct m_tag *t)
+m_tag_next(struct mbuf *m __unused, struct m_tag *t)
{
return (SLIST_NEXT(t, m_tag_link));
@@ -1177,7 +1178,7 @@ m_free(struct mbuf *m)
return (n);
}
-static int inline
+static __inline int
rt_m_getfib(struct mbuf *m)
{
KASSERT(m->m_flags & M_PKTHDR , ("Attempt to get FIB from non header mbuf."));
diff --git a/sys/sys/module.h b/sys/sys/module.h
index 3baa755..69b74ff 100644
--- a/sys/sys/module.h
+++ b/sys/sys/module.h
@@ -71,7 +71,7 @@ typedef union modspecific {
} modspecific_t;
/*
- * Module dependency declarartion
+ * Module dependency declaration
*/
struct mod_depend {
int md_ver_minimum;
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index 6fb2d08..b167845 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -355,6 +355,7 @@ void __mnt_vnode_markerfree_active(struct vnode **mvp, struct mount *);
#define MNTK_LOOKUP_EXCL_DOTDOT 0x00000800
#define MNTK_MARKER 0x00001000
#define MNTK_UNMAPPED_BUFS 0x00002000
+#define MNTK_USES_BCACHE 0x00004000 /* FS uses the buffer cache. */
#define MNTK_NOASYNC 0x00800000 /* disable async */
#define MNTK_UNMOUNT 0x01000000 /* unmount in progress */
#define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */
diff --git a/sys/sys/mouse.h b/sys/sys/mouse.h
index e03bc40..5329693 100644
--- a/sys/sys/mouse.h
+++ b/sys/sys/mouse.h
@@ -86,7 +86,7 @@ typedef struct mousehw {
int type; /* mouse/track ball/pad... */
int model; /* I/F dependent model ID: MOUSE_MODEL_XXX */
int hwid; /* I/F dependent hardware ID
- * for the PS/2 mouse, it will be PSM_XXX_ID
+ * for the PS/2 mouse, it will be PSM_XXX_ID
*/
} mousehw_t;
@@ -108,8 +108,26 @@ typedef struct synapticshw {
int capPalmDetect;
int capPassthrough;
int capMiddle;
+ int capLowPower;
+ int capMultiFingerReport;
+ int capBallistics;
int nExtendedButtons;
int nExtendedQueries;
+ int capClickPad;
+ int capDeluxeLEDs;
+ int noAbsoluteFilter;
+ int capReportsV;
+ int capUniformClickPad;
+ int capReportsMin;
+ int capInterTouch;
+ int capReportsMax;
+ int capClearPad;
+ int capAdvancedGestures;
+ int multiFingerMode;
+ int capCoveredPad;
+ int verticalScroll;
+ int horizontalScroll;
+ int verticalWheel;
} synapticshw_t;
/* iftype */
@@ -269,7 +287,7 @@ typedef struct mousevar {
#define MOUSE_PS2_BUTTON2DOWN 0x04 /* middle */
#define MOUSE_PS2_BUTTON3DOWN 0x02 /* right */
#define MOUSE_PS2_TAP MOUSE_PS2_SYNC /* GlidePoint (PS/2) `tapping'
- * Yes! this is the same bit
+ * Yes! this is the same bit
* as SYNC!
*/
@@ -324,11 +342,11 @@ typedef struct mousevar {
#define MOUSE_PS2VERSA_TAP 0x02
/* A4 Tech 4D Mouse (PS/2) data packet */
-#define MOUSE_4D_PACKETSIZE 3
+#define MOUSE_4D_PACKETSIZE 3
#define MOUSE_4D_WHEELBITS 0xf0
/* A4 Tech 4D+ Mouse (PS/2) data packet */
-#define MOUSE_4DPLUS_PACKETSIZE 3
+#define MOUSE_4DPLUS_PACKETSIZE 3
#define MOUSE_4DPLUS_ZNEG 0x04 /* sign bit */
#define MOUSE_4DPLUS_BUTTON4DOWN 0x08
@@ -340,7 +358,7 @@ typedef struct mousevar {
* as at the level 0. There are additional three bytes which shows
* `dz' and the states of additional buttons. `dz' is expressed as the
* sum of the byte 5 and 6 which contain signed seven bit values.
- * The states of the button 4 though 10 are in the bit 0 though 6 in
+ * The states of the button 4 though 10 are in the bit 0 though 6 in
* the byte 7 respectively: 1 indicates the button is up.
*/
#define MOUSE_SYS_PACKETSIZE 8
diff --git a/sys/sys/nv.h b/sys/sys/nv.h
index 0876e57..fa5d138 100644
--- a/sys/sys/nv.h
+++ b/sys/sys/nv.h
@@ -64,6 +64,10 @@ typedef struct nvlist nvlist_t;
* Perform case-insensitive lookups of provided names.
*/
#define NV_FLAG_IGNORE_CASE 0x01
+/*
+ * Names don't have to be unique.
+ */
+#define NV_FLAG_NO_UNIQUE 0x02
#if defined(_KERNEL) && defined(MALLOC_DECLARE)
MALLOC_DECLARE(M_NVLIST);
@@ -75,6 +79,7 @@ nvlist_t *nvlist_create(int flags);
void nvlist_destroy(nvlist_t *nvl);
int nvlist_error(const nvlist_t *nvl);
bool nvlist_empty(const nvlist_t *nvl);
+int nvlist_flags(const nvlist_t *nvl);
void nvlist_set_error(nvlist_t *nvl, int error);
nvlist_t *nvlist_clone(const nvlist_t *nvl);
@@ -86,11 +91,11 @@ void nvlist_fdump(const nvlist_t *nvl, FILE *fp);
size_t nvlist_size(const nvlist_t *nvl);
void *nvlist_pack(const nvlist_t *nvl, size_t *sizep);
-nvlist_t *nvlist_unpack(const void *buf, size_t size);
+nvlist_t *nvlist_unpack(const void *buf, size_t size, int flags);
int nvlist_send(int sock, const nvlist_t *nvl);
-nvlist_t *nvlist_recv(int sock);
-nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl);
+nvlist_t *nvlist_recv(int sock, int flags);
+nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl, int flags);
const char *nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep);
@@ -194,129 +199,6 @@ void nvlist_free_descriptor(nvlist_t *nvl, const char *name);
#endif
void nvlist_free_binary(nvlist_t *nvl, const char *name);
-/*
- * Below are the same functions, but which operate on format strings and
- * variable argument lists.
- *
- * Functions that are not inserting a new pair into the nvlist cannot handle
- * a failure to allocate the memory to hold the new name. Therefore these
- * functions are not provided in the kernel.
- */
-
-#ifndef _KERNEL
-bool nvlist_existsf(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-bool nvlist_existsf_type(const nvlist_t *nvl, int type, const char *namefmt, ...) __printflike(3, 4);
-
-bool nvlist_existsf_null(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-bool nvlist_existsf_bool(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-bool nvlist_existsf_number(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-bool nvlist_existsf_string(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-bool nvlist_existsf_nvlist(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-bool nvlist_existsf_descriptor(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-bool nvlist_existsf_binary(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-
-bool nvlist_existsv(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-bool nvlist_existsv_type(const nvlist_t *nvl, int type, const char *namefmt, va_list nameap) __printflike(3, 0);
-
-bool nvlist_existsv_null(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-bool nvlist_existsv_bool(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-bool nvlist_existsv_number(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-bool nvlist_existsv_string(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-bool nvlist_existsv_nvlist(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-bool nvlist_existsv_descriptor(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-bool nvlist_existsv_binary(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-#endif
-
-void nvlist_addf_null(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_addf_bool(nvlist_t *nvl, bool value, const char *namefmt, ...) __printflike(3, 4);
-void nvlist_addf_number(nvlist_t *nvl, uint64_t value, const char *namefmt, ...) __printflike(3, 4);
-void nvlist_addf_string(nvlist_t *nvl, const char *value, const char *namefmt, ...) __printflike(3, 4);
-void nvlist_addf_nvlist(nvlist_t *nvl, const nvlist_t *value, const char *namefmt, ...) __printflike(3, 4);
-#ifndef _KERNEL
-void nvlist_addf_descriptor(nvlist_t *nvl, int value, const char *namefmt, ...) __printflike(3, 4);
-#endif
-void nvlist_addf_binary(nvlist_t *nvl, const void *value, size_t size, const char *namefmt, ...) __printflike(4, 5);
-
-#if !defined(_KERNEL) || defined(_VA_LIST_DECLARED)
-void nvlist_addv_null(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_addv_bool(nvlist_t *nvl, bool value, const char *namefmt, va_list nameap) __printflike(3, 0);
-void nvlist_addv_number(nvlist_t *nvl, uint64_t value, const char *namefmt, va_list nameap) __printflike(3, 0);
-void nvlist_addv_string(nvlist_t *nvl, const char *value, const char *namefmt, va_list nameap) __printflike(3, 0);
-void nvlist_addv_nvlist(nvlist_t *nvl, const nvlist_t *value, const char *namefmt, va_list nameap) __printflike(3, 0);
-#ifndef _KERNEL
-void nvlist_addv_descriptor(nvlist_t *nvl, int value, const char *namefmt, va_list nameap) __printflike(3, 0);
-#endif
-void nvlist_addv_binary(nvlist_t *nvl, const void *value, size_t size, const char *namefmt, va_list nameap) __printflike(4, 0);
-#endif
-
-void nvlist_movef_string(nvlist_t *nvl, char *value, const char *namefmt, ...) __printflike(3, 4);
-void nvlist_movef_nvlist(nvlist_t *nvl, nvlist_t *value, const char *namefmt, ...) __printflike(3, 4);
-#ifndef _KERNEL
-void nvlist_movef_descriptor(nvlist_t *nvl, int value, const char *namefmt, ...) __printflike(3, 4);
-#endif
-void nvlist_movef_binary(nvlist_t *nvl, void *value, size_t size, const char *namefmt, ...) __printflike(4, 5);
-
-#if !defined(_KERNEL) || defined(_VA_LIST_DECLARED)
-void nvlist_movev_string(nvlist_t *nvl, char *value, const char *namefmt, va_list nameap) __printflike(3, 0);
-void nvlist_movev_nvlist(nvlist_t *nvl, nvlist_t *value, const char *namefmt, va_list nameap) __printflike(3, 0);
-#ifndef _KERNEL
-void nvlist_movev_descriptor(nvlist_t *nvl, int value, const char *namefmt, va_list nameap) __printflike(3, 0);
-#endif
-void nvlist_movev_binary(nvlist_t *nvl, void *value, size_t size, const char *namefmt, va_list nameap) __printflike(4, 0);
-#endif
-
-#ifndef _KERNEL
-bool nvlist_getf_bool(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-uint64_t nvlist_getf_number(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-const char *nvlist_getf_string(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-const nvlist_t *nvlist_getf_nvlist(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-int nvlist_getf_descriptor(const nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-const void *nvlist_getf_binary(const nvlist_t *nvl, size_t *sizep, const char *namefmt, ...) __printflike(3, 4);
-
-bool nvlist_getv_bool(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-uint64_t nvlist_getv_number(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-const char *nvlist_getv_string(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-const nvlist_t *nvlist_getv_nvlist(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-int nvlist_getv_descriptor(const nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-const void *nvlist_getv_binary(const nvlist_t *nvl, size_t *sizep, const char *namefmt, va_list nameap) __printflike(3, 0);
-
-bool nvlist_takef_bool(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-uint64_t nvlist_takef_number(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-char *nvlist_takef_string(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-nvlist_t *nvlist_takef_nvlist(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-int nvlist_takef_descriptor(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void *nvlist_takef_binary(nvlist_t *nvl, size_t *sizep, const char *namefmt, ...) __printflike(3, 4);
-
-bool nvlist_takev_bool(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-uint64_t nvlist_takev_number(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-char *nvlist_takev_string(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvlist_t *nvlist_takev_nvlist(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-int nvlist_takev_descriptor(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void *nvlist_takev_binary(nvlist_t *nvl, size_t *sizep, const char *namefmt, va_list nameap) __printflike(3, 0);
-
-void nvlist_freef(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_freef_type(nvlist_t *nvl, int type, const char *namefmt, ...) __printflike(3, 4);
-
-void nvlist_freef_null(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_freef_bool(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_freef_number(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_freef_string(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_freef_nvlist(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_freef_descriptor(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-void nvlist_freef_binary(nvlist_t *nvl, const char *namefmt, ...) __printflike(2, 3);
-
-void nvlist_freev(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_freev_type(nvlist_t *nvl, int type, const char *namefmt, va_list nameap) __printflike(3, 0);
-
-void nvlist_freev_null(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_freev_bool(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_freev_number(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_freev_string(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_freev_nvlist(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_freev_descriptor(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-void nvlist_freev_binary(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
-#endif /* _KERNEL */
-
__END_DECLS
#endif /* !_NV_H_ */
diff --git a/sys/sys/nv_impl.h b/sys/sys/nv_impl.h
index da90e79..c088c3d 100644
--- a/sys/sys/nv_impl.h
+++ b/sys/sys/nv_impl.h
@@ -41,23 +41,24 @@ typedef struct nvpair nvpair_t;
#define NV_TYPE_NVLIST_UP 255
-#define NV_TYPE_FIRST NV_TYPE_NULL
-#define NV_TYPE_LAST NV_TYPE_BINARY
+#define NV_TYPE_FIRST NV_TYPE_NULL
+#define NV_TYPE_LAST NV_TYPE_BINARY
#define NV_FLAG_BIG_ENDIAN 0x80
#ifdef _KERNEL
-#define nv_malloc(size) malloc((size), M_NVLIST, M_NOWAIT)
+#define nv_malloc(size) malloc((size), M_NVLIST, M_WAITOK)
#define nv_calloc(n, size) malloc((n) * (size), M_NVLIST, \
- M_NOWAIT | M_ZERO)
+ M_WAITOK | M_ZERO)
#define nv_realloc(buf, size) realloc((buf), (size), M_NVLIST, \
- M_NOWAIT)
+ M_WAITOK)
#define nv_free(buf) free((buf), M_NVLIST)
#define nv_strdup(buf) strdup((buf), M_NVLIST)
#define nv_vasprintf(ptr, ...) vasprintf(ptr, M_NVLIST, __VA_ARGS__)
-#define SAVE_ERRNO(var) ((void)(var))
-#define RESTORE_ERRNO(var) ((void)(var))
+#define ERRNO_SET(var) do { } while (0)
+#define ERRNO_SAVE() do { do { } while(0)
+#define ERRNO_RESTORE() } while (0)
#define ERRNO_OR_DEFAULT(default) (default)
@@ -70,8 +71,14 @@ typedef struct nvpair nvpair_t;
#define nv_strdup(buf) strdup((buf))
#define nv_vasprintf(ptr, ...) vasprintf(ptr, __VA_ARGS__)
-#define SAVE_ERRNO(var) (var) = errno
-#define RESTORE_ERRNO(var) errno = (var)
+#define ERRNO_SET(var) do { errno = (var); } while (0)
+#define ERRNO_SAVE() do { \
+ int _serrno; \
+ \
+ _serrno = errno
+
+#define ERRNO_RESTORE() errno = _serrno; \
+ } while (0)
#define ERRNO_OR_DEFAULT(default) (errno == 0 ? (default) : errno)
@@ -128,30 +135,4 @@ const void *nvpair_get_binary(const nvpair_t *nvp, size_t *sizep);
void nvpair_free(nvpair_t *nvp);
-nvpair_t *nvpair_createf_null(const char *namefmt, ...) __printflike(1, 2);
-nvpair_t *nvpair_createf_bool(bool value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_createf_number(uint64_t value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_createf_string(const char *value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_createf_nvlist(const nvlist_t *value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_createf_descriptor(int value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_createf_binary(const void *value, size_t size, const char *namefmt, ...) __printflike(3, 4);
-
-nvpair_t *nvpair_createv_null(const char *namefmt, va_list nameap) __printflike(1, 0);
-nvpair_t *nvpair_createv_bool(bool value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_createv_number(uint64_t value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_createv_string(const char *value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_createv_descriptor(int value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_createv_binary(const void *value, size_t size, const char *namefmt, va_list nameap) __printflike(3, 0);
-
-nvpair_t *nvpair_movef_string(char *value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_movef_nvlist(nvlist_t *value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_movef_descriptor(int value, const char *namefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_movef_binary(void *value, size_t size, const char *namefmt, ...) __printflike(3, 4);
-
-nvpair_t *nvpair_movev_string(char *value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_movev_descriptor(int value, const char *namefmt, va_list nameap) __printflike(2, 0);
-nvpair_t *nvpair_movev_binary(void *value, size_t size, const char *namefmt, va_list nameap) __printflike(3, 0);
-
#endif /* !_NV_IMPL_H_ */
diff --git a/sys/sys/nvlist_impl.h b/sys/sys/nvlist_impl.h
index a59a90e..8aeac67 100644
--- a/sys/sys/nvlist_impl.h
+++ b/sys/sys/nvlist_impl.h
@@ -38,10 +38,6 @@
#include "nv.h"
-void *nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep);
-nvlist_t *nvlist_xunpack(const void *buf, size_t size, const int *fds,
- size_t nfds);
-
nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl);
const unsigned char *nvlist_unpack_header(nvlist_t *nvl,
const unsigned char *ptr, size_t nfds, bool *isbep, size_t *leftp);
diff --git a/sys/sys/param.h b/sys/sys/param.h
index cb8b9bd..bc722df 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -50,7 +50,7 @@
* there.
* Currently this lives here in the doc/ repository:
*
- * head/en_US.ISO8859-1/books/porters-handbook/book.xml
+ * head/en_US.ISO8859-1/books/porters-handbook/versions/chapter.xml
*
* scheme is: <major><two digit minor>Rxx
* 'R' is in the range 0 to 4 if this is a release branch or
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1100067 /* Master, propagated to newvers */
+#define __FreeBSD_version 1100072 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
@@ -233,10 +233,19 @@
* and may be made smaller at the risk of not being able to use
* filesystems which require a block size exceeding MAXBSIZE.
*
+ * MAXBCACHEBUF - Maximum size of a buffer in the buffer cache. This must
+ * be >= MAXBSIZE and can be set differently for different
+ * architectures by defining it in <machine/param.h>.
+ * Making this larger allows NFS to do larger reads/writes.
+ *
* BKVASIZE - Nominal buffer space per buffer, in bytes. BKVASIZE is the
* minimum KVM memory reservation the kernel is willing to make.
* Filesystems can of course request smaller chunks. Actual
* backing memory uses a chunk size of a page (PAGE_SIZE).
+ * The default value here can be overridden on a per-architecture
+ * basis by defining it in <machine/param.h>. This should
+ * probably be done to increase its value, when MAXBCACHEBUF is
+ * defined as a larger value in <machine/param.h>.
*
* If you make BKVASIZE too small you risk seriously fragmenting
* the buffer KVM map which may slow things down a bit. If you
@@ -248,7 +257,12 @@
* normal UFS filesystem.
*/
#define MAXBSIZE 65536 /* must be power of 2 */
+#ifndef MAXBCACHEBUF
+#define MAXBCACHEBUF MAXBSIZE /* must be a power of 2 >= MAXBSIZE */
+#endif
+#ifndef BKVASIZE
#define BKVASIZE 16384 /* must be power of 2 */
+#endif
#define BKVAMASK (BKVASIZE-1)
/*
diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h
index ca0d076..34d9c34 100644
--- a/sys/sys/pmc.h
+++ b/sys/sys/pmc.h
@@ -96,10 +96,14 @@
__PMC_CPU(INTEL_NEHALEM_EX, 0x93, "Intel Nehalem Xeon 7500") \
__PMC_CPU(INTEL_WESTMERE_EX, 0x94, "Intel Westmere Xeon E7") \
__PMC_CPU(INTEL_HASWELL_XEON, 0x95, "Intel Haswell Xeon E5 v3") \
+ __PMC_CPU(INTEL_BROADWELL, 0x96, "Intel Broadwell") \
__PMC_CPU(INTEL_XSCALE, 0x100, "Intel XScale") \
__PMC_CPU(MIPS_24K, 0x200, "MIPS 24K") \
__PMC_CPU(MIPS_OCTEON, 0x201, "Cavium Octeon") \
+ __PMC_CPU(MIPS_74K, 0x202, "MIPS 74K") \
__PMC_CPU(PPC_7450, 0x300, "PowerPC MPC7450") \
+ __PMC_CPU(PPC_E500, 0x340, "PowerPC e500 Core") \
+ __PMC_CPU(PPC_MPC85XX, 0x340, "Freescale PowerPC MPC85XX") \
__PMC_CPU(PPC_970, 0x380, "IBM PowerPC 970") \
__PMC_CPU(GENERIC, 0x400, "Generic")
@@ -131,8 +135,10 @@ enum pmc_cputype {
__PMC_CLASS(ARMV7) /* ARMv7 */ \
__PMC_CLASS(MIPS24K) /* MIPS 24K */ \
__PMC_CLASS(OCTEON) /* Cavium Octeon */ \
+ __PMC_CLASS(MIPS74K) /* MIPS 74K */ \
__PMC_CLASS(PPC7450) /* Motorola MPC7450 class */ \
__PMC_CLASS(PPC970) /* IBM PowerPC 970 class */ \
+ __PMC_CLASS(E500) /* Freescale e500 class */ \
__PMC_CLASS(SOFT) /* Software events */
enum pmc_class {
diff --git a/sys/sys/procctl.h b/sys/sys/procctl.h
index c57eee6..75dbf53 100644
--- a/sys/sys/procctl.h
+++ b/sys/sys/procctl.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/sys/procfs.h b/sys/sys/procfs.h
index cab9c30..6b32dfd 100644
--- a/sys/sys/procfs.h
+++ b/sys/sys/procfs.h
@@ -80,8 +80,6 @@ typedef struct prpsinfo {
char pr_psargs[PRARGSZ+1]; /* Arguments, null terminated (1) */
} prpsinfo_t;
-#define THRMISC_VERSION 1 /* Current version of thrmisc_t */
-
typedef struct thrmisc {
char pr_tname[MAXCOMLEN+1]; /* Thread name, null terminated (1) */
u_int _pad; /* Convenience pad, 0-filled (1) */
@@ -89,4 +87,29 @@ typedef struct thrmisc {
typedef uint64_t psaddr_t; /* An address in the target process. */
+#ifdef __HAVE_REG32
+typedef struct prstatus32 {
+ int32_t pr_version;
+ uint32_t pr_statussz;
+ uint32_t pr_gregsetsz;
+ uint32_t pr_fpregsetsz;
+ int32_t pr_osreldate;
+ int32_t pr_cursig;
+ int32_t pr_pid;
+ struct reg32 pr_reg;
+} prstatus32_t;
+
+typedef struct prpsinfo32 {
+ int32_t pr_version;
+ uint32_t pr_psinfosz;
+ char pr_fname[PRFNAMESZ+1];
+ char pr_psargs[PRARGSZ+1];
+} prpsinfo32_t;
+
+struct thrmisc32 {
+ char pr_tname[MAXCOMLEN+1];
+ uint32_t _pad;
+};
+#endif /* __HAVE_REG32 */
+
#endif /* _SYS_PROCFS_H_ */
diff --git a/sys/sys/racct.h b/sys/sys/racct.h
index 966d27a..313d5d0 100644
--- a/sys/sys/racct.h
+++ b/sys/sys/racct.h
@@ -83,6 +83,10 @@ struct ucred;
#define RACCT_DECAYING 0x20
extern int racct_types[];
+extern int racct_enable;
+
+#define ASSERT_RACCT_ENABLED() KASSERT(racct_enable, \
+ ("%s called with !racct_enable", __func__))
/*
* Amount stored in c_resources[] is 10**6 times bigger than what's
diff --git a/sys/sys/seq.h b/sys/sys/seq.h
index eaab86e..21067cb 100644
--- a/sys/sys/seq.h
+++ b/sys/sys/seq.h
@@ -79,7 +79,7 @@ typedef uint32_t seq_t;
* on amd64 but still has unnecessary cost.
*/
static __inline int
-atomic_load_rmb_int(volatile u_int *p)
+atomic_load_rmb_int(volatile const u_int *p)
{
volatile u_int v;
@@ -89,7 +89,7 @@ atomic_load_rmb_int(volatile u_int *p)
}
static __inline int
-atomic_rmb_load_int(volatile u_int *p)
+atomic_rmb_load_int(volatile const u_int *p)
{
volatile u_int v = 0;
@@ -122,7 +122,7 @@ seq_write_end(seq_t *seqp)
}
static __inline seq_t
-seq_read(seq_t *seqp)
+seq_read(const seq_t *seqp)
{
seq_t ret;
@@ -139,7 +139,7 @@ seq_read(seq_t *seqp)
}
static __inline seq_t
-seq_consistent(seq_t *seqp, seq_t oldseq)
+seq_consistent(const seq_t *seqp, seq_t oldseq)
{
return (atomic_rmb_load_int(seqp) == oldseq);
diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h
index dfeeede..112bb2c 100644
--- a/sys/sys/socketvar.h
+++ b/sys/sys/socketvar.h
@@ -339,7 +339,7 @@ struct uio;
*/
int sockargs(struct mbuf **mp, caddr_t buf, int buflen, int type);
int getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len);
-int getsock_cap(struct filedesc *fdp, int fd, cap_rights_t *rightsp,
+int getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
struct file **fpp, u_int *fflagp);
void soabort(struct socket *so);
int soaccept(struct socket *so, struct sockaddr **nam);
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index 7b09acf..f04bb12 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -128,5 +128,6 @@
#define SIOCGIFGROUP _IOWR('i', 136, struct ifgroupreq) /* get ifgroups */
#define SIOCDIFGROUP _IOW('i', 137, struct ifgroupreq) /* delete ifgroup */
#define SIOCGIFGMEMB _IOWR('i', 138, struct ifgroupreq) /* get members */
+#define SIOCGIFXMEDIA _IOWR('i', 139, struct ifmediareq) /* get net xmedia */
#endif /* !_SYS_SOCKIO_H_ */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index 54a450f..5e757bf 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles
+ * created from FreeBSD: head/sys/kern/syscalls.master 281714 2015-04-18 21:50:13Z kib
*/
#define SYS_syscall 0
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
index 4e8e891..50c02cb 100644
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -1,7 +1,7 @@
# FreeBSD system call names.
# DO NOT EDIT-- this file is automatically generated.
# $FreeBSD$
-# created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles
+# created from FreeBSD: head/sys/kern/syscalls.master 281714 2015-04-18 21:50:13Z kib
MIASM = \
syscall.o \
exit.o \
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index cb6d4e3..8d8c173 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -58,7 +58,7 @@ struct thr_param;
struct __wrusage;
int kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg,
- u_int buflen);
+ u_int buflen, u_int path_max);
int kern_accept(struct thread *td, int s, struct sockaddr **name,
socklen_t *namelen, struct file **fp);
int kern_accept4(struct thread *td, int s, struct sockaddr **name,
@@ -104,7 +104,7 @@ int kern_futimens(struct thread *td, int fd, struct timespec *tptr,
int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
long *basep, ssize_t *residp, enum uio_seg bufseg);
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
- enum uio_seg bufseg, int flags);
+ size_t *countp, enum uio_seg bufseg, int flags);
int kern_getitimer(struct thread *, u_int, struct itimerval *);
int kern_getppid(struct thread *);
int kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index 71dc979..3a35861 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 277610 2015-01-23 21:07:08Z jilles
+ * created from FreeBSD: head/sys/kern/syscalls.master 281714 2015-04-18 21:50:13Z kib
*/
#ifndef _SYS_SYSPROTO_H_
@@ -532,20 +532,6 @@ struct shmsys_args {
char a3_l_[PADL_(int)]; int a3; char a3_r_[PADR_(int)];
char a4_l_[PADL_(int)]; int a4; char a4_r_[PADR_(int)];
};
-struct freebsd6_pread_args {
- char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
- char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
- char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
- char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
- char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)];
-};
-struct freebsd6_pwrite_args {
- char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
- char buf_l_[PADL_(const void *)]; const void * buf; char buf_r_[PADR_(const void *)];
- char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
- char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
- char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)];
-};
struct setfib_args {
char fibnum_l_[PADL_(int)]; int fibnum; char fibnum_r_[PADR_(int)];
};
@@ -595,31 +581,6 @@ struct getdirentries_args {
char count_l_[PADL_(u_int)]; u_int count; char count_r_[PADR_(u_int)];
char basep_l_[PADL_(long *)]; long * basep; char basep_r_[PADR_(long *)];
};
-struct freebsd6_mmap_args {
- char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)];
- char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
- char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)];
- char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
- char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
- char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
- char pos_l_[PADL_(off_t)]; off_t pos; char pos_r_[PADR_(off_t)];
-};
-struct freebsd6_lseek_args {
- char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
- char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
- char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)];
- char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)];
-};
-struct freebsd6_truncate_args {
- char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
- char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
- char length_l_[PADL_(off_t)]; off_t length; char length_r_[PADR_(off_t)];
-};
-struct freebsd6_ftruncate_args {
- char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
- char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
- char length_l_[PADL_(off_t)]; off_t length; char length_r_[PADR_(off_t)];
-};
struct sysctl_args {
char name_l_[PADL_(int *)]; int * name; char name_r_[PADR_(int *)];
char namelen_l_[PADL_(u_int)]; u_int namelen; char namelen_r_[PADR_(u_int)];
@@ -1941,8 +1902,6 @@ int sys_rtprio(struct thread *, struct rtprio_args *);
int sys_semsys(struct thread *, struct semsys_args *);
int sys_msgsys(struct thread *, struct msgsys_args *);
int sys_shmsys(struct thread *, struct shmsys_args *);
-int freebsd6_pread(struct thread *, struct freebsd6_pread_args *);
-int freebsd6_pwrite(struct thread *, struct freebsd6_pwrite_args *);
int sys_setfib(struct thread *, struct setfib_args *);
int sys_ntp_adjtime(struct thread *, struct ntp_adjtime_args *);
int sys_setgid(struct thread *, struct setgid_args *);
@@ -1956,10 +1915,6 @@ int sys_fpathconf(struct thread *, struct fpathconf_args *);
int sys_getrlimit(struct thread *, struct __getrlimit_args *);
int sys_setrlimit(struct thread *, struct __setrlimit_args *);
int sys_getdirentries(struct thread *, struct getdirentries_args *);
-int freebsd6_mmap(struct thread *, struct freebsd6_mmap_args *);
-int freebsd6_lseek(struct thread *, struct freebsd6_lseek_args *);
-int freebsd6_truncate(struct thread *, struct freebsd6_truncate_args *);
-int freebsd6_ftruncate(struct thread *, struct freebsd6_ftruncate_args *);
int sys___sysctl(struct thread *, struct sysctl_args *);
int sys_mlock(struct thread *, struct mlock_args *);
int sys_munlock(struct thread *, struct munlock_args *);
@@ -2459,6 +2414,51 @@ int freebsd4_sigreturn(struct thread *, struct freebsd4_sigreturn_args *);
#ifdef COMPAT_FREEBSD6
+struct freebsd6_pread_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)];
+};
+struct freebsd6_pwrite_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char buf_l_[PADL_(const void *)]; const void * buf; char buf_r_[PADR_(const void *)];
+ char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)];
+};
+struct freebsd6_mmap_args {
+ char addr_l_[PADL_(caddr_t)]; caddr_t addr; char addr_r_[PADR_(caddr_t)];
+ char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)];
+ char prot_l_[PADL_(int)]; int prot; char prot_r_[PADR_(int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char pos_l_[PADL_(off_t)]; off_t pos; char pos_r_[PADR_(off_t)];
+};
+struct freebsd6_lseek_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)];
+ char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)];
+};
+struct freebsd6_truncate_args {
+ char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char length_l_[PADL_(off_t)]; off_t length; char length_r_[PADR_(off_t)];
+};
+struct freebsd6_ftruncate_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char pad_l_[PADL_(int)]; int pad; char pad_r_[PADR_(int)];
+ char length_l_[PADL_(off_t)]; off_t length; char length_r_[PADR_(off_t)];
+};
+int freebsd6_pread(struct thread *, struct freebsd6_pread_args *);
+int freebsd6_pwrite(struct thread *, struct freebsd6_pwrite_args *);
+int freebsd6_mmap(struct thread *, struct freebsd6_mmap_args *);
+int freebsd6_lseek(struct thread *, struct freebsd6_lseek_args *);
+int freebsd6_truncate(struct thread *, struct freebsd6_truncate_args *);
+int freebsd6_ftruncate(struct thread *, struct freebsd6_ftruncate_args *);
#endif /* COMPAT_FREEBSD6 */
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 8a358ce..786414f 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -187,6 +187,7 @@ void *phashinit(int count, struct malloc_type *type, u_long *nentries);
void g_waitidle(void);
void panic(const char *, ...) __dead2 __printflike(1, 2);
+void vpanic(const char *, __va_list) __dead2 __printflike(1, 0);
void cpu_boot(int);
void cpu_flush_dcache(void *, size_t);
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index e1f912e..d70aa57 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -336,6 +336,8 @@ struct vattr {
#define VWRITE_ACL 000040000000 /* change ACL and/or file mode */
#define VWRITE_OWNER 000100000000 /* change file owner */
#define VSYNCHRONIZE 000200000000 /* not used */
+#define VCREAT 000400000000 /* creating new file */
+#define VVERIFY 001000000000 /* verification required */
/*
* Permissions that were traditionally granted only to the file owner.
diff --git a/sys/net/zlib.h b/sys/sys/zlib.h
index 16edae1..16edae1 100644
--- a/sys/net/zlib.h
+++ b/sys/sys/zlib.h
diff --git a/sys/net/zutil.h b/sys/sys/zutil.h
index 74f0221..1431b6f 100644
--- a/sys/net/zutil.h
+++ b/sys/sys/zutil.h
@@ -17,7 +17,7 @@
#define ZEXPORT
#ifdef _KERNEL
-#include <net/zlib.h>
+#include <sys/zlib.h>
#else
#include "zlib.h"
#endif
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index c918cd7..c384064 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -112,8 +112,7 @@ static void ffs_blkfree_trim_task(void *ctx, int pending __unused);
#ifdef INVARIANTS
static int ffs_checkblk(struct inode *, ufs2_daddr_t, long);
#endif
-static ufs2_daddr_t ffs_clusteralloc(struct inode *, u_int, ufs2_daddr_t, int,
- int);
+static ufs2_daddr_t ffs_clusteralloc(struct inode *, u_int, ufs2_daddr_t, int);
static ino_t ffs_dirpref(struct inode *);
static ufs2_daddr_t ffs_fragextend(struct inode *, u_int, ufs2_daddr_t,
int, int);
@@ -460,10 +459,16 @@ nospace:
SYSCTL_NODE(_vfs, OID_AUTO, ffs, CTLFLAG_RW, 0, "FFS filesystem");
static int doasyncfree = 1;
-SYSCTL_INT(_vfs_ffs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
+SYSCTL_INT(_vfs_ffs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0,
+"do not force synchronous writes when blocks are reallocated");
static int doreallocblks = 1;
-SYSCTL_INT(_vfs_ffs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, "");
+SYSCTL_INT(_vfs_ffs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0,
+"enable block reallocation");
+
+static int maxclustersearch = 10;
+SYSCTL_INT(_vfs_ffs, OID_AUTO, maxclustersearch, CTLFLAG_RW, &maxclustersearch,
+0, "max number of cylinder group to search for contigous blocks");
#ifdef DEBUG
static volatile int prtrealloc = 0;
@@ -510,7 +515,7 @@ ffs_reallocblks_ufs1(ap)
ufs1_daddr_t soff, newblk, blkno;
ufs2_daddr_t pref;
struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
- int i, len, start_lvl, end_lvl, ssize;
+ int i, cg, len, start_lvl, end_lvl, ssize;
vp = ap->a_vp;
ip = VTOI(vp);
@@ -597,18 +602,39 @@ ffs_reallocblks_ufs1(ap)
ebap = (ufs1_daddr_t *)ebp->b_data;
}
/*
- * Find the preferred location for the cluster.
+ * Find the preferred location for the cluster. If we have not
+ * previously failed at this endeavor, then follow our standard
+ * preference calculation. If we have failed at it, then pick up
+ * where we last ended our search.
*/
UFS_LOCK(ump);
- pref = ffs_blkpref_ufs1(ip, start_lbn, soff, sbap);
+ if (ip->i_nextclustercg == -1)
+ pref = ffs_blkpref_ufs1(ip, start_lbn, soff, sbap);
+ else
+ pref = cgdata(fs, ip->i_nextclustercg);
/*
* Search the block map looking for an allocation of the desired size.
+ * To avoid wasting too much time, we limit the number of cylinder
+ * groups that we will search.
+ */
+ cg = dtog(fs, pref);
+ for (i = min(maxclustersearch, fs->fs_ncg); i > 0; i--) {
+ if ((newblk = ffs_clusteralloc(ip, cg, pref, len)) != 0)
+ break;
+ cg += 1;
+ if (cg >= fs->fs_ncg)
+ cg = 0;
+ }
+ /*
+ * If we have failed in our search, record where we gave up for
+ * next time. Otherwise, fall back to our usual search citerion.
*/
- if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref,
- len, len, ffs_clusteralloc)) == 0) {
+ if (newblk == 0) {
+ ip->i_nextclustercg = cg;
UFS_UNLOCK(ump);
goto fail;
}
+ ip->i_nextclustercg = -1;
/*
* We have found a new contiguous block.
*
@@ -737,7 +763,7 @@ ffs_reallocblks_ufs2(ap)
ufs_lbn_t start_lbn, end_lbn;
ufs2_daddr_t soff, newblk, blkno, pref;
struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
- int i, len, start_lvl, end_lvl, ssize;
+ int i, cg, len, start_lvl, end_lvl, ssize;
vp = ap->a_vp;
ip = VTOI(vp);
@@ -824,18 +850,39 @@ ffs_reallocblks_ufs2(ap)
ebap = (ufs2_daddr_t *)ebp->b_data;
}
/*
- * Find the preferred location for the cluster.
+ * Find the preferred location for the cluster. If we have not
+ * previously failed at this endeavor, then follow our standard
+ * preference calculation. If we have failed at it, then pick up
+ * where we last ended our search.
*/
UFS_LOCK(ump);
- pref = ffs_blkpref_ufs2(ip, start_lbn, soff, sbap);
+ if (ip->i_nextclustercg == -1)
+ pref = ffs_blkpref_ufs2(ip, start_lbn, soff, sbap);
+ else
+ pref = cgdata(fs, ip->i_nextclustercg);
/*
* Search the block map looking for an allocation of the desired size.
+ * To avoid wasting too much time, we limit the number of cylinder
+ * groups that we will search.
+ */
+ cg = dtog(fs, pref);
+ for (i = min(maxclustersearch, fs->fs_ncg); i > 0; i--) {
+ if ((newblk = ffs_clusteralloc(ip, cg, pref, len)) != 0)
+ break;
+ cg += 1;
+ if (cg >= fs->fs_ncg)
+ cg = 0;
+ }
+ /*
+ * If we have failed in our search, record where we gave up for
+ * next time. Otherwise, fall back to our usual search citerion.
*/
- if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref,
- len, len, ffs_clusteralloc)) == 0) {
+ if (newblk == 0) {
+ ip->i_nextclustercg = cg;
UFS_UNLOCK(ump);
goto fail;
}
+ ip->i_nextclustercg = -1;
/*
* We have found a new contiguous block.
*
@@ -1786,12 +1833,11 @@ gotit:
* take the first one that we find following bpref.
*/
static ufs2_daddr_t
-ffs_clusteralloc(ip, cg, bpref, len, unused)
+ffs_clusteralloc(ip, cg, bpref, len)
struct inode *ip;
u_int cg;
ufs2_daddr_t bpref;
int len;
- int unused;
{
struct fs *fs;
struct cg *cgp;
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 6e2e556..2a368bd 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1055,7 +1055,8 @@ ffs_mountfs(devvp, mp, td)
*/
MNT_ILOCK(mp);
mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
- MNTK_NO_IOPF | MNTK_UNMAPPED_BUFS | MNTK_SUSPENDABLE;
+ MNTK_NO_IOPF | MNTK_UNMAPPED_BUFS | MNTK_SUSPENDABLE |
+ MNTK_USES_BCACHE;
MNT_IUNLOCK(mp);
#ifdef UFS_EXTATTR
#ifdef UFS_EXTATTR_AUTOSTART
@@ -1687,6 +1688,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags)
ip->i_dev = dev;
ip->i_number = ino;
ip->i_ea_refs = 0;
+ ip->i_nextclustercg = -1;
#ifdef QUOTA
{
int i;
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
index 37081d5..cd7c472 100644
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -87,6 +87,8 @@ struct inode {
daddr_t *snapblklist; /* Collect expunged snapshot blocks. */
} i_un;
+ int i_nextclustercg; /* last cg searched for cluster */
+
/*
* Data for extended attribute modification.
*/
diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c
index 4cd245a..d05ea33 100644
--- a/sys/vm/device_pager.c
+++ b/sys/vm/device_pager.c
@@ -294,7 +294,6 @@ static int
old_dev_pager_fault(vm_object_t object, vm_ooffset_t offset, int prot,
vm_page_t *mres)
{
- vm_pindex_t pidx;
vm_paddr_t paddr;
vm_page_t m_paddr, page;
struct cdev *dev;
@@ -304,7 +303,6 @@ old_dev_pager_fault(vm_object_t object, vm_ooffset_t offset, int prot,
vm_memattr_t memattr;
int ref, ret;
- pidx = OFF_TO_IDX(offset);
memattr = object->memattr;
VM_OBJECT_WUNLOCK(object);
diff --git a/sys/vm/sg_pager.c b/sys/vm/sg_pager.c
index 08e8fc7..e35741e 100644
--- a/sys/vm/sg_pager.c
+++ b/sys/vm/sg_pager.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index 435f412..9a83989 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -198,11 +198,13 @@ swap_reserve_by_cred(vm_ooffset_t incr, struct ucred *cred)
panic("swap_reserve: & PAGE_MASK");
#ifdef RACCT
- PROC_LOCK(curproc);
- error = racct_add(curproc, RACCT_SWAP, incr);
- PROC_UNLOCK(curproc);
- if (error != 0)
- return (0);
+ if (racct_enable) {
+ PROC_LOCK(curproc);
+ error = racct_add(curproc, RACCT_SWAP, incr);
+ PROC_UNLOCK(curproc);
+ if (error != 0)
+ return (0);
+ }
#endif
res = 0;
@@ -326,17 +328,16 @@ static int nsw_wcount_async; /* limit write buffers / asynchronous */
static int nsw_wcount_async_max;/* assigned maximum */
static int nsw_cluster_max; /* maximum VOP I/O allowed */
+static int sysctl_swap_async_max(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_vm, OID_AUTO, swap_async_max, CTLTYPE_INT | CTLFLAG_RW,
+ NULL, 0, sysctl_swap_async_max, "I", "Maximum running async swap ops");
+
static struct swblock **swhash;
static int swhash_mask;
static struct mtx swhash_mtx;
-static int swap_async_max = 4; /* maximum in-progress async I/O's */
static struct sx sw_alloc_sx;
-
-SYSCTL_INT(_vm, OID_AUTO, swap_async_max,
- CTLFLAG_RW, &swap_async_max, 0, "Maximum running async swap ops");
-
/*
* "named" and "unnamed" anon region objects. Try to reduce the overhead
* of searching a named list by hashing it just a little.
@@ -1348,39 +1349,6 @@ swap_pager_putpages(vm_object_t object, vm_page_t *m, int count,
/*
* Step 2
*
- * Update nsw parameters from swap_async_max sysctl values.
- * Do not let the sysop crash the machine with bogus numbers.
- */
- mtx_lock(&pbuf_mtx);
- if (swap_async_max != nsw_wcount_async_max) {
- int n;
-
- /*
- * limit range
- */
- if ((n = swap_async_max) > nswbuf / 2)
- n = nswbuf / 2;
- if (n < 1)
- n = 1;
- swap_async_max = n;
-
- /*
- * Adjust difference ( if possible ). If the current async
- * count is too low, we may not be able to make the adjustment
- * at this time.
- */
- n -= nsw_wcount_async_max;
- if (nsw_wcount_async + n >= 0) {
- nsw_wcount_async += n;
- nsw_wcount_async_max += n;
- wakeup(&nsw_wcount_async);
- }
- }
- mtx_unlock(&pbuf_mtx);
-
- /*
- * Step 3
- *
* Assign swap blocks and issue I/O. We reallocate swap on the fly.
* The page is left dirty until the pageout operation completes
* successfully.
@@ -2579,7 +2547,6 @@ swapgeom_done(struct bio *bp2)
struct swdevt *sp;
struct buf *bp;
struct g_consumer *cp;
- int destroy;
bp = bp2->bio_caller2;
cp = bp2->bio_from;
@@ -2590,15 +2557,14 @@ swapgeom_done(struct bio *bp2)
bp->b_error = bp2->bio_error;
bufdone(bp);
mtx_lock(&sw_dev_mtx);
- destroy = ((--cp->index) == 0 && cp->private);
- if (destroy) {
- sp = bp2->bio_caller1;
- sp->sw_id = NULL;
+ if ((--cp->index) == 0 && cp->private) {
+ if (g_post_event(swapgeom_close_ev, cp, M_NOWAIT, NULL) == 0) {
+ sp = bp2->bio_caller1;
+ sp->sw_id = NULL;
+ }
}
mtx_unlock(&sw_dev_mtx);
g_destroy_bio(bp2);
- if (destroy)
- g_waitfor_event(swapgeom_close_ev, cp, M_WAITOK, NULL);
}
static void
@@ -2835,3 +2801,40 @@ swaponvp(struct thread *td, struct vnode *vp, u_long nblks)
NODEV, 0);
return (0);
}
+
+static int
+sysctl_swap_async_max(SYSCTL_HANDLER_ARGS)
+{
+ int error, new, n;
+
+ new = nsw_wcount_async_max;
+ error = sysctl_handle_int(oidp, &new, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ if (new > nswbuf / 2 || new < 1)
+ return (EINVAL);
+
+ mtx_lock(&pbuf_mtx);
+ while (nsw_wcount_async_max != new) {
+ /*
+ * Adjust difference. If the current async count is too low,
+ * we will need to sqeeze our update slowly in. Sleep with a
+ * higher priority than getpbuf() to finish faster.
+ */
+ n = new - nsw_wcount_async_max;
+ if (nsw_wcount_async + n >= 0) {
+ nsw_wcount_async += n;
+ nsw_wcount_async_max += n;
+ wakeup(&nsw_wcount_async);
+ } else {
+ nsw_wcount_async_max -= nsw_wcount_async;
+ nsw_wcount_async = 0;
+ msleep(&nsw_wcount_async, &pbuf_mtx, PSWP,
+ "swpsysctl", 0);
+ }
+ }
+ mtx_unlock(&pbuf_mtx);
+
+ return (0);
+}
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c
index 7556803..4ff177f 100644
--- a/sys/vm/uma_core.c
+++ b/sys/vm/uma_core.c
@@ -307,9 +307,8 @@ bucket_init(void)
{
struct uma_bucket_zone *ubz;
int size;
- int i;
- for (i = 0, ubz = &bucket_zones[0]; ubz->ubz_entries != 0; ubz++) {
+ for (ubz = &bucket_zones[0]; ubz->ubz_entries != 0; ubz++) {
size = roundup(sizeof(struct uma_bucket), sizeof(void *));
size += sizeof(void *) * ubz->ubz_entries;
ubz->ubz_zone = uma_zcreate(ubz->ubz_name, size,
@@ -3060,7 +3059,7 @@ uma_zone_set_fini(uma_zone_t zone, uma_fini fini)
uma_keg_t keg;
keg = zone_first_keg(zone);
- KASSERT(keg != NULL, ("uma_zone_set_init: Invalid zone type"));
+ KASSERT(keg != NULL, ("uma_zone_set_fini: Invalid zone type"));
KEG_LOCK(keg);
KASSERT(keg->uk_pages == 0,
("uma_zone_set_fini on non-empty keg"));
@@ -3100,7 +3099,7 @@ uma_zone_set_freef(uma_zone_t zone, uma_free freef)
uma_keg_t keg;
keg = zone_first_keg(zone);
- KASSERT(keg != NULL, ("uma_zone_set_init: Invalid zone type"));
+ KASSERT(keg != NULL, ("uma_zone_set_freef: Invalid zone type"));
KEG_LOCK(keg);
keg->uk_freef = freef;
KEG_UNLOCK(keg);
@@ -3540,16 +3539,13 @@ int
sysctl_handle_uma_zone_max(SYSCTL_HANDLER_ARGS)
{
uma_zone_t zone = *(uma_zone_t *)arg1;
- int error, max, old;
+ int error, max;
- old = max = uma_zone_get_max(zone);
+ max = uma_zone_get_max(zone);
error = sysctl_handle_int(oidp, &max, 0, req);
if (error || !req->newptr)
return (error);
- if (max < old)
- return (EINVAL);
-
uma_zone_set_max(zone, max);
return (0);
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 536076a..0c84d44 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
+#include <sys/mman.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
#include <sys/rwlock.h>
@@ -113,7 +114,8 @@ static int vm_fault_additional_pages(vm_page_t, int, int, vm_page_t *, int *);
#define VM_FAULT_READ_MAX (1 + VM_FAULT_READ_AHEAD_MAX)
#define VM_FAULT_NINCR (VM_FAULT_READ_MAX / VM_FAULT_READ_BEHIND)
#define VM_FAULT_SUM (VM_FAULT_NINCR * (VM_FAULT_NINCR + 1) / 2)
-#define VM_FAULT_CACHE_BEHIND (VM_FAULT_READ_BEHIND * VM_FAULT_SUM)
+
+#define VM_FAULT_DONTNEED_MIN 1048576
struct faultstate {
vm_page_t m;
@@ -128,7 +130,8 @@ struct faultstate {
struct vnode *vp;
};
-static void vm_fault_cache_behind(const struct faultstate *fs, int distance);
+static void vm_fault_dontneed(const struct faultstate *fs, vm_offset_t vaddr,
+ int ahead);
static void vm_fault_prefault(const struct faultstate *fs, vm_offset_t addra,
int faultcount, int reqpage);
@@ -345,6 +348,10 @@ RetryFault:;
vm_map_lock(fs.map);
if (vm_map_lookup_entry(fs.map, vaddr, &fs.entry) &&
(fs.entry->eflags & MAP_ENTRY_IN_TRANSITION)) {
+ if (fs.vp != NULL) {
+ vput(fs.vp);
+ fs.vp = NULL;
+ }
fs.entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP;
vm_map_unlock_and_wait(fs.map, 0);
} else
@@ -566,8 +573,7 @@ readrest:
nera = VM_FAULT_READ_AHEAD_MAX;
ahead = nera;
if (fs.pindex == fs.entry->next_read)
- vm_fault_cache_behind(&fs,
- VM_FAULT_READ_MAX);
+ vm_fault_dontneed(&fs, vaddr, ahead);
} else if (fs.pindex == fs.entry->next_read) {
/*
* This is a sequential fault. Arithmetically
@@ -585,8 +591,7 @@ readrest:
}
ahead = nera;
if (era == VM_FAULT_READ_AHEAD_MAX)
- vm_fault_cache_behind(&fs,
- VM_FAULT_CACHE_BEHIND);
+ vm_fault_dontneed(&fs, vaddr, ahead);
} else {
/*
* This is a non-sequential fault. Request a
@@ -1034,15 +1039,26 @@ vnode_locked:
}
/*
- * Speed up the reclamation of up to "distance" pages that precede the
- * faulting pindex within the first object of the shadow chain.
+ * Speed up the reclamation of pages that precede the faulting pindex within
+ * the first object of the shadow chain. Essentially, perform the equivalent
+ * to madvise(..., MADV_DONTNEED) on a large cluster of pages that precedes
+ * the faulting pindex by the cluster size when the pages read by vm_fault()
+ * cross a cluster-size boundary. The cluster size is the greater of the
+ * smallest superpage size and VM_FAULT_DONTNEED_MIN.
+ *
+ * When "fs->first_object" is a shadow object, the pages in the backing object
+ * that precede the faulting pindex are deactivated by vm_fault(). So, this
+ * function must only be concerned with pages in the first object.
*/
static void
-vm_fault_cache_behind(const struct faultstate *fs, int distance)
+vm_fault_dontneed(const struct faultstate *fs, vm_offset_t vaddr, int ahead)
{
+ vm_map_entry_t entry;
vm_object_t first_object, object;
- vm_page_t m, m_prev;
- vm_pindex_t pindex;
+ vm_offset_t end, start;
+ vm_page_t m, m_next;
+ vm_pindex_t pend, pstart;
+ vm_size_t size;
object = fs->object;
VM_OBJECT_ASSERT_WLOCKED(object);
@@ -1054,32 +1070,34 @@ vm_fault_cache_behind(const struct faultstate *fs, int distance)
VM_OBJECT_WLOCK(object);
}
}
- /* Neither fictitious nor unmanaged pages can be cached. */
+ /* Neither fictitious nor unmanaged pages can be reclaimed. */
if ((first_object->flags & (OBJ_FICTITIOUS | OBJ_UNMANAGED)) == 0) {
- if (fs->first_pindex < distance)
- pindex = 0;
- else
- pindex = fs->first_pindex - distance;
- if (pindex < OFF_TO_IDX(fs->entry->offset))
- pindex = OFF_TO_IDX(fs->entry->offset);
- m = first_object != object ? fs->first_m : fs->m;
- vm_page_assert_xbusied(m);
- m_prev = vm_page_prev(m);
- while ((m = m_prev) != NULL && m->pindex >= pindex &&
- m->valid == VM_PAGE_BITS_ALL) {
- m_prev = vm_page_prev(m);
- if (vm_page_busied(m))
- continue;
- vm_page_lock(m);
- if (m->hold_count == 0 && m->wire_count == 0) {
- pmap_remove_all(m);
- vm_page_aflag_clear(m, PGA_REFERENCED);
- if (m->dirty != 0)
- vm_page_deactivate(m);
- else
- vm_page_cache(m);
+ size = VM_FAULT_DONTNEED_MIN;
+ if (MAXPAGESIZES > 1 && size < pagesizes[1])
+ size = pagesizes[1];
+ end = rounddown2(vaddr, size);
+ if (vaddr - end >= size - PAGE_SIZE - ptoa(ahead) &&
+ (entry = fs->entry)->start < end) {
+ if (end - entry->start < size)
+ start = entry->start;
+ else
+ start = end - size;
+ pmap_advise(fs->map->pmap, start, end, MADV_DONTNEED);
+ pstart = OFF_TO_IDX(entry->offset) + atop(start -
+ entry->start);
+ m_next = vm_page_find_least(first_object, pstart);
+ pend = OFF_TO_IDX(entry->offset) + atop(end -
+ entry->start);
+ while ((m = m_next) != NULL && m->pindex < pend) {
+ m_next = TAILQ_NEXT(m, listq);
+ if (m->valid != VM_PAGE_BITS_ALL ||
+ vm_page_busied(m))
+ continue;
+ vm_page_lock(m);
+ if (m->hold_count == 0 && m->wire_count == 0)
+ vm_page_advise(m, MADV_DONTNEED);
+ vm_page_unlock(m);
}
- vm_page_unlock(m);
}
}
if (first_object != object)
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index b7e668b..bad9994 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -300,11 +300,11 @@ vmspace_alloc(vm_offset_t min, vm_offset_t max, pmap_pinit_t pinit)
return (vm);
}
+#ifdef RACCT
static void
vmspace_container_reset(struct proc *p)
{
-#ifdef RACCT
PROC_LOCK(p);
racct_set(p, RACCT_DATA, 0);
racct_set(p, RACCT_STACK, 0);
@@ -312,8 +312,8 @@ vmspace_container_reset(struct proc *p)
racct_set(p, RACCT_MEMLOCK, 0);
racct_set(p, RACCT_VMEM, 0);
PROC_UNLOCK(p);
-#endif
}
+#endif
static inline void
vmspace_dofree(struct vmspace *vm)
@@ -415,7 +415,10 @@ vmspace_exit(struct thread *td)
pmap_activate(td);
vmspace_dofree(vm);
}
- vmspace_container_reset(p);
+#ifdef RACCT
+ if (racct_enable)
+ vmspace_container_reset(p);
+#endif
}
/* Acquire reference to vmspace owned by another process. */
@@ -3652,14 +3655,16 @@ Retry:
return (KERN_NO_SPACE);
}
#ifdef RACCT
- PROC_LOCK(p);
- if (is_procstack &&
- racct_set(p, RACCT_STACK, ctob(vm->vm_ssize) + grow_amount)) {
+ if (racct_enable) {
+ PROC_LOCK(p);
+ if (is_procstack && racct_set(p, RACCT_STACK,
+ ctob(vm->vm_ssize) + grow_amount)) {
+ PROC_UNLOCK(p);
+ vm_map_unlock_read(map);
+ return (KERN_NO_SPACE);
+ }
PROC_UNLOCK(p);
- vm_map_unlock_read(map);
- return (KERN_NO_SPACE);
}
- PROC_UNLOCK(p);
#endif
/* Round up the grow amount modulo sgrowsiz */
@@ -3685,15 +3690,17 @@ Retry:
goto out;
}
#ifdef RACCT
- PROC_LOCK(p);
- if (racct_set(p, RACCT_MEMLOCK,
- ptoa(pmap_wired_count(map->pmap)) + grow_amount)) {
+ if (racct_enable) {
+ PROC_LOCK(p);
+ if (racct_set(p, RACCT_MEMLOCK,
+ ptoa(pmap_wired_count(map->pmap)) + grow_amount)) {
+ PROC_UNLOCK(p);
+ vm_map_unlock_read(map);
+ rv = KERN_NO_SPACE;
+ goto out;
+ }
PROC_UNLOCK(p);
- vm_map_unlock_read(map);
- rv = KERN_NO_SPACE;
- goto out;
}
- PROC_UNLOCK(p);
#endif
}
/* If we would blow our VMEM resource limit, no go */
@@ -3703,14 +3710,16 @@ Retry:
goto out;
}
#ifdef RACCT
- PROC_LOCK(p);
- if (racct_set(p, RACCT_VMEM, map->size + grow_amount)) {
+ if (racct_enable) {
+ PROC_LOCK(p);
+ if (racct_set(p, RACCT_VMEM, map->size + grow_amount)) {
+ PROC_UNLOCK(p);
+ vm_map_unlock_read(map);
+ rv = KERN_NO_SPACE;
+ goto out;
+ }
PROC_UNLOCK(p);
- vm_map_unlock_read(map);
- rv = KERN_NO_SPACE;
- goto out;
}
- PROC_UNLOCK(p);
#endif
if (vm_map_lock_upgrade(map))
@@ -3809,7 +3818,7 @@ Retry:
out:
#ifdef RACCT
- if (rv != KERN_SUCCESS) {
+ if (racct_enable && rv != KERN_SUCCESS) {
PROC_LOCK(p);
error = racct_set(p, RACCT_VMEM, map->size);
KASSERT(error == 0, ("decreasing RACCT_VMEM failed"));
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
index a9ff248..1dd2479 100644
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -462,6 +462,7 @@ done:
return (error);
}
+#if defined(COMPAT_FREEBSD6)
int
freebsd6_mmap(struct thread *td, struct freebsd6_mmap_args *uap)
{
@@ -475,6 +476,7 @@ freebsd6_mmap(struct thread *td, struct freebsd6_mmap_args *uap)
oargs.pos = uap->pos;
return (sys_mmap(td, &oargs));
}
+#endif
#ifdef COMPAT_43
#ifndef _SYS_SYSPROTO_H_
@@ -1120,16 +1122,18 @@ vm_mlock(struct proc *proc, struct ucred *cred, const void *addr0, size_t len)
if (npages + vm_cnt.v_wire_count > vm_page_max_wired)
return (EAGAIN);
#ifdef RACCT
- PROC_LOCK(proc);
- error = racct_set(proc, RACCT_MEMLOCK, nsize);
- PROC_UNLOCK(proc);
- if (error != 0)
- return (ENOMEM);
+ if (racct_enable) {
+ PROC_LOCK(proc);
+ error = racct_set(proc, RACCT_MEMLOCK, nsize);
+ PROC_UNLOCK(proc);
+ if (error != 0)
+ return (ENOMEM);
+ }
#endif
error = vm_map_wire(map, start, end,
VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES);
#ifdef RACCT
- if (error != KERN_SUCCESS) {
+ if (racct_enable && error != KERN_SUCCESS) {
PROC_LOCK(proc);
racct_set(proc, RACCT_MEMLOCK,
ptoa(pmap_wired_count(map->pmap)));
@@ -1177,11 +1181,13 @@ sys_mlockall(td, uap)
PROC_UNLOCK(td->td_proc);
}
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- error = racct_set(td->td_proc, RACCT_MEMLOCK, map->size);
- PROC_UNLOCK(td->td_proc);
- if (error != 0)
- return (ENOMEM);
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ error = racct_set(td->td_proc, RACCT_MEMLOCK, map->size);
+ PROC_UNLOCK(td->td_proc);
+ if (error != 0)
+ return (ENOMEM);
+ }
#endif
if (uap->how & MCL_FUTURE) {
@@ -1203,7 +1209,7 @@ sys_mlockall(td, uap)
error = (error == KERN_SUCCESS ? 0 : EAGAIN);
}
#ifdef RACCT
- if (error != KERN_SUCCESS) {
+ if (racct_enable && error != KERN_SUCCESS) {
PROC_LOCK(td->td_proc);
racct_set(td->td_proc, RACCT_MEMLOCK,
ptoa(pmap_wired_count(map->pmap)));
@@ -1245,7 +1251,7 @@ sys_munlockall(td, uap)
error = vm_map_unwire(map, vm_map_min(map), vm_map_max(map),
VM_MAP_WIRE_USER|VM_MAP_WIRE_HOLESOK);
#ifdef RACCT
- if (error == KERN_SUCCESS) {
+ if (racct_enable && error == KERN_SUCCESS) {
PROC_LOCK(td->td_proc);
racct_set(td->td_proc, RACCT_MEMLOCK, 0);
PROC_UNLOCK(td->td_proc);
@@ -1289,7 +1295,7 @@ sys_munlock(td, uap)
error = vm_map_unwire(&td->td_proc->p_vmspace->vm_map, start, end,
VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES);
#ifdef RACCT
- if (error == KERN_SUCCESS) {
+ if (racct_enable && error == KERN_SUCCESS) {
PROC_LOCK(td->td_proc);
map = &td->td_proc->p_vmspace->vm_map;
racct_set(td->td_proc, RACCT_MEMLOCK,
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index 64ca130..0aec01f 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -91,12 +91,14 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/kernel.h>
#include <sys/limits.h>
+#include <sys/linker.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/msgbuf.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
+#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <sys/vnode.h>
@@ -142,6 +144,12 @@ static int pa_tryrelock_restart;
SYSCTL_INT(_vm, OID_AUTO, tryrelock_restart, CTLFLAG_RD,
&pa_tryrelock_restart, 0, "Number of tryrelock restarts");
+static TAILQ_HEAD(, vm_page) blacklist_head;
+static int sysctl_vm_page_blacklist(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_vm, OID_AUTO, page_blacklist, CTLTYPE_STRING | CTLFLAG_RD |
+ CTLFLAG_MPSAFE, NULL, 0, sysctl_vm_page_blacklist, "A", "Blacklist pages");
+
+
static uma_zone_t fakepg_zone;
static struct vnode *vm_page_alloc_init(vm_page_t m);
@@ -216,35 +224,153 @@ vm_set_page_size(void)
}
/*
- * vm_page_blacklist_lookup:
+ * vm_page_blacklist_next:
*
- * See if a physical address in this page has been listed
- * in the blacklist tunable. Entries in the tunable are
- * separated by spaces or commas. If an invalid integer is
- * encountered then the rest of the string is skipped.
+ * Find the next entry in the provided string of blacklist
+ * addresses. Entries are separated by space, comma, or newline.
+ * If an invalid integer is encountered then the rest of the
+ * string is skipped. Updates the list pointer to the next
+ * character, or NULL if the string is exhausted or invalid.
*/
-static int
-vm_page_blacklist_lookup(char *list, vm_paddr_t pa)
+static vm_paddr_t
+vm_page_blacklist_next(char **list, char *end)
{
vm_paddr_t bad;
char *cp, *pos;
- for (pos = list; *pos != '\0'; pos = cp) {
+ if (list == NULL || *list == NULL)
+ return (0);
+ if (**list =='\0') {
+ *list = NULL;
+ return (0);
+ }
+
+ /*
+ * If there's no end pointer then the buffer is coming from
+ * the kenv and we know it's null-terminated.
+ */
+ if (end == NULL)
+ end = *list + strlen(*list);
+
+ /* Ensure that strtoq() won't walk off the end */
+ if (*end != '\0') {
+ if (*end == '\n' || *end == ' ' || *end == ',')
+ *end = '\0';
+ else {
+ printf("Blacklist not terminated, skipping\n");
+ *list = NULL;
+ return (0);
+ }
+ }
+
+ for (pos = *list; *pos != '\0'; pos = cp) {
bad = strtoq(pos, &cp, 0);
- if (*cp != '\0') {
- if (*cp == ' ' || *cp == ',') {
- cp++;
- if (cp == pos)
+ if (*cp == '\0' || *cp == ' ' || *cp == ',' || *cp == '\n') {
+ if (bad == 0) {
+ if (++cp < end)
continue;
- } else
- break;
- }
- if (pa == trunc_page(bad))
- return (1);
+ else
+ break;
+ }
+ } else
+ break;
+ if (*cp == '\0' || ++cp >= end)
+ *list = NULL;
+ else
+ *list = cp;
+ return (trunc_page(bad));
}
+ printf("Garbage in RAM blacklist, skipping\n");
+ *list = NULL;
return (0);
}
+/*
+ * vm_page_blacklist_check:
+ *
+ * Iterate through the provided string of blacklist addresses, pulling
+ * each entry out of the physical allocator free list and putting it
+ * onto a list for reporting via the vm.page_blacklist sysctl.
+ */
+static void
+vm_page_blacklist_check(char *list, char *end)
+{
+ vm_paddr_t pa;
+ vm_page_t m;
+ char *next;
+ int ret;
+
+ next = list;
+ while (next != NULL) {
+ if ((pa = vm_page_blacklist_next(&next, end)) == 0)
+ continue;
+ m = vm_phys_paddr_to_vm_page(pa);
+ if (m == NULL)
+ continue;
+ mtx_lock(&vm_page_queue_free_mtx);
+ ret = vm_phys_unfree_page(m);
+ mtx_unlock(&vm_page_queue_free_mtx);
+ if (ret == TRUE) {
+ TAILQ_INSERT_TAIL(&blacklist_head, m, listq);
+ if (bootverbose)
+ printf("Skipping page with pa 0x%jx\n",
+ (uintmax_t)pa);
+ }
+ }
+}
+
+/*
+ * vm_page_blacklist_load:
+ *
+ * Search for a special module named "ram_blacklist". It'll be a
+ * plain text file provided by the user via the loader directive
+ * of the same name.
+ */
+static void
+vm_page_blacklist_load(char **list, char **end)
+{
+ void *mod;
+ u_char *ptr;
+ u_int len;
+
+ mod = NULL;
+ ptr = NULL;
+
+ mod = preload_search_by_type("ram_blacklist");
+ if (mod != NULL) {
+ ptr = preload_fetch_addr(mod);
+ len = preload_fetch_size(mod);
+ }
+ *list = ptr;
+ if (ptr != NULL)
+ *end = ptr + len;
+ else
+ *end = NULL;
+ return;
+}
+
+static int
+sysctl_vm_page_blacklist(SYSCTL_HANDLER_ARGS)
+{
+ vm_page_t m;
+ struct sbuf sbuf;
+ int error, first;
+
+ first = 1;
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error != 0)
+ return (error);
+ sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+ TAILQ_FOREACH(m, &blacklist_head, listq) {
+ sbuf_printf(&sbuf, "%s%#jx", first ? "" : ",",
+ (uintmax_t)m->phys_addr);
+ first = 0;
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ return (error);
+}
+
static void
vm_page_domain_init(struct vm_domain *vmd)
{
@@ -290,7 +416,7 @@ vm_page_startup(vm_offset_t vaddr)
int i;
vm_paddr_t pa;
vm_paddr_t last_pa;
- char *list;
+ char *list, *listend;
vm_paddr_t end;
vm_paddr_t biggestsize;
vm_paddr_t low_water, high_water;
@@ -305,14 +431,6 @@ vm_page_startup(vm_offset_t vaddr)
phys_avail[i + 1] = trunc_page(phys_avail[i + 1]);
}
-#ifdef XEN
- /*
- * There is no obvious reason why i386 PV Xen needs vm_page structs
- * created for these pseudo-physical addresses. XXX
- */
- vm_phys_add_seg(0, phys_avail[0]);
-#endif
-
low_water = phys_avail[0];
high_water = phys_avail[1];
@@ -477,20 +595,22 @@ vm_page_startup(vm_offset_t vaddr)
*/
vm_cnt.v_page_count = 0;
vm_cnt.v_free_count = 0;
- list = kern_getenv("vm.blacklist");
for (i = 0; phys_avail[i + 1] != 0; i += 2) {
pa = phys_avail[i];
last_pa = phys_avail[i + 1];
while (pa < last_pa) {
- if (list != NULL &&
- vm_page_blacklist_lookup(list, pa))
- printf("Skipping page with pa 0x%jx\n",
- (uintmax_t)pa);
- else
- vm_phys_add_page(pa);
+ vm_phys_add_page(pa);
pa += PAGE_SIZE;
}
}
+
+ TAILQ_INIT(&blacklist_head);
+ vm_page_blacklist_load(&list, &listend);
+ vm_page_blacklist_check(list, listend);
+
+ list = kern_getenv("vm.blacklist");
+ vm_page_blacklist_check(list, NULL);
+
freeenv(list);
#if VM_NRESERVLEVEL > 0
/*
diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c
index 2fb7c55..872ffd8 100644
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -118,7 +118,8 @@ __FBSDID("$FreeBSD$");
/* the kernel process "vm_pageout"*/
static void vm_pageout(void);
static void vm_pageout_init(void);
-static int vm_pageout_clean(vm_page_t);
+static int vm_pageout_clean(vm_page_t m);
+static int vm_pageout_cluster(vm_page_t m);
static void vm_pageout_scan(struct vm_domain *vmd, int pass);
static void vm_pageout_mightbe_oom(struct vm_domain *vmd, int pass);
@@ -347,7 +348,7 @@ vm_pageout_page_lock(vm_page_t m, vm_page_t *next)
* late and we cannot do anything that will mess with the page.
*/
static int
-vm_pageout_clean(vm_page_t m)
+vm_pageout_cluster(vm_page_t m)
{
vm_object_t object;
vm_page_t mc[2*vm_pageout_page_count], pb, ps;
@@ -906,6 +907,115 @@ vm_pageout_map_deactivate_pages(map, desired)
#endif /* !defined(NO_SWAPPING) */
/*
+ * Attempt to acquire all of the necessary locks to launder a page and
+ * then call through the clustering layer to PUTPAGES. Wait a short
+ * time for a vnode lock.
+ *
+ * Requires the page and object lock on entry, releases both before return.
+ * Returns 0 on success and an errno otherwise.
+ */
+static int
+vm_pageout_clean(vm_page_t m)
+{
+ struct vnode *vp;
+ struct mount *mp;
+ vm_object_t object;
+ vm_pindex_t pindex;
+ int error, lockmode;
+
+ vm_page_assert_locked(m);
+ object = m->object;
+ VM_OBJECT_ASSERT_WLOCKED(object);
+ error = 0;
+ vp = NULL;
+ mp = NULL;
+
+ /*
+ * The object is already known NOT to be dead. It
+ * is possible for the vget() to block the whole
+ * pageout daemon, but the new low-memory handling
+ * code should prevent it.
+ *
+ * We can't wait forever for the vnode lock, we might
+ * deadlock due to a vn_read() getting stuck in
+ * vm_wait while holding this vnode. We skip the
+ * vnode if we can't get it in a reasonable amount
+ * of time.
+ */
+ if (object->type == OBJT_VNODE) {
+ vm_page_unlock(m);
+ vp = object->handle;
+ if (vp->v_type == VREG &&
+ vn_start_write(vp, &mp, V_NOWAIT) != 0) {
+ mp = NULL;
+ error = EDEADLK;
+ goto unlock_all;
+ }
+ KASSERT(mp != NULL,
+ ("vp %p with NULL v_mount", vp));
+ vm_object_reference_locked(object);
+ pindex = m->pindex;
+ VM_OBJECT_WUNLOCK(object);
+ lockmode = MNT_SHARED_WRITES(vp->v_mount) ?
+ LK_SHARED : LK_EXCLUSIVE;
+ if (vget(vp, lockmode | LK_TIMELOCK, curthread)) {
+ vp = NULL;
+ error = EDEADLK;
+ goto unlock_mp;
+ }
+ VM_OBJECT_WLOCK(object);
+ vm_page_lock(m);
+ /*
+ * While the object and page were unlocked, the page
+ * may have been:
+ * (1) moved to a different queue,
+ * (2) reallocated to a different object,
+ * (3) reallocated to a different offset, or
+ * (4) cleaned.
+ */
+ if (m->queue != PQ_INACTIVE || m->object != object ||
+ m->pindex != pindex || m->dirty == 0) {
+ vm_page_unlock(m);
+ error = ENXIO;
+ goto unlock_all;
+ }
+
+ /*
+ * The page may have been busied or held while the object
+ * and page locks were released.
+ */
+ if (vm_page_busied(m) || m->hold_count != 0) {
+ vm_page_unlock(m);
+ error = EBUSY;
+ goto unlock_all;
+ }
+ }
+
+ /*
+ * If a page is dirty, then it is either being washed
+ * (but not yet cleaned) or it is still in the
+ * laundry. If it is still in the laundry, then we
+ * start the cleaning operation.
+ */
+ if (vm_pageout_cluster(m) == 0)
+ error = EIO;
+
+unlock_all:
+ VM_OBJECT_WUNLOCK(object);
+
+unlock_mp:
+ vm_page_lock_assert(m, MA_NOTOWNED);
+ if (mp != NULL) {
+ if (vp != NULL)
+ vput(vp);
+ vm_object_deallocate(object);
+ vn_finished_write(mp);
+ }
+
+ return (error);
+}
+
+/*
* vm_pageout_scan does the dirty work for the pageout daemon.
*
* pass 0 - Update active LRU/deactivate pages
@@ -921,7 +1031,6 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
int act_delta, addl_page_shortage, deficit, maxscan, page_shortage;
int vnodes_skipped = 0;
int maxlaunder;
- int lockmode;
boolean_t queues_locked;
/*
@@ -1155,9 +1264,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
* on the inactive queue, we may have to go all out.
*/
int swap_pageouts_ok;
- struct vnode *vp = NULL;
- struct mount *mp = NULL;
- vm_pindex_t pindex;
+ int error;
if ((object->type != OBJT_SWAP) && (object->type != OBJT_DEFAULT)) {
swap_pageouts_ok = 1;
@@ -1180,124 +1287,20 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
vm_page_requeue_locked(m);
goto relock_queues;
}
-
- /*
- * The object is already known NOT to be dead. It
- * is possible for the vget() to block the whole
- * pageout daemon, but the new low-memory handling
- * code should prevent it.
- *
- * The previous code skipped locked vnodes and, worse,
- * reordered pages in the queue. This results in
- * completely non-deterministic operation and, on a
- * busy system, can lead to extremely non-optimal
- * pageouts. For example, it can cause clean pages
- * to be freed and dirty pages to be moved to the end
- * of the queue. Since dirty pages are also moved to
- * the end of the queue once-cleaned, this gives
- * way too large a weighting to deferring the freeing
- * of dirty pages.
- *
- * We can't wait forever for the vnode lock, we might
- * deadlock due to a vn_read() getting stuck in
- * vm_wait while holding this vnode. We skip the
- * vnode if we can't get it in a reasonable amount
- * of time.
- */
- if (object->type == OBJT_VNODE) {
- vm_page_unlock(m);
- vp = object->handle;
- if (vp->v_type == VREG &&
- vn_start_write(vp, &mp, V_NOWAIT) != 0) {
- mp = NULL;
- ++pageout_lock_miss;
- if (object->flags & OBJ_MIGHTBEDIRTY)
- vnodes_skipped++;
- goto unlock_and_continue;
- }
- KASSERT(mp != NULL,
- ("vp %p with NULL v_mount", vp));
- vm_object_reference_locked(object);
- pindex = m->pindex;
- VM_OBJECT_WUNLOCK(object);
- lockmode = MNT_SHARED_WRITES(vp->v_mount) ?
- LK_SHARED : LK_EXCLUSIVE;
- if (vget(vp, lockmode | LK_TIMELOCK,
- curthread)) {
- VM_OBJECT_WLOCK(object);
- ++pageout_lock_miss;
- if (object->flags & OBJ_MIGHTBEDIRTY)
- vnodes_skipped++;
- vp = NULL;
- goto unlock_and_continue;
- }
- VM_OBJECT_WLOCK(object);
- vm_page_lock(m);
- /*
- * While the object and page were unlocked,
- * the page may have been
- * (1) moved to a different queue,
- * (2) reallocated to a different object,
- * (3) reallocated to a different offset, or
- * (4) cleaned.
- */
- if (m->queue != PQ_INACTIVE ||
- m->object != object ||
- m->pindex != pindex ||
- m->dirty == 0) {
- vm_page_unlock(m);
- if (object->flags & OBJ_MIGHTBEDIRTY)
- vnodes_skipped++;
- goto unlock_and_continue;
- }
-
- /*
- * The page may have been busied during the
- * blocking in vget(). We don't move the
- * page back onto the end of the queue so that
- * statistics are more correct if we don't.
- */
- if (vm_page_busied(m)) {
- vm_page_unlock(m);
- addl_page_shortage++;
- goto unlock_and_continue;
- }
-
- /*
- * If the page has become held it might
- * be undergoing I/O, so skip it
- */
- if (m->hold_count != 0) {
- vm_page_unlock(m);
- addl_page_shortage++;
- if (object->flags & OBJ_MIGHTBEDIRTY)
- vnodes_skipped++;
- goto unlock_and_continue;
- }
- }
-
+ error = vm_pageout_clean(m);
/*
- * If a page is dirty, then it is either being washed
- * (but not yet cleaned) or it is still in the
- * laundry. If it is still in the laundry, then we
- * start the cleaning operation.
- *
- * decrement page_shortage on success to account for
+ * Decrement page_shortage on success to account for
* the (future) cleaned page. Otherwise we could wind
* up laundering or cleaning too many pages.
*/
- if (vm_pageout_clean(m) != 0) {
- --page_shortage;
- --maxlaunder;
- }
-unlock_and_continue:
- vm_page_lock_assert(m, MA_NOTOWNED);
- VM_OBJECT_WUNLOCK(object);
- if (mp != NULL) {
- if (vp != NULL)
- vput(vp);
- vm_object_deallocate(object);
- vn_finished_write(mp);
+ if (error == 0) {
+ page_shortage--;
+ maxlaunder--;
+ } else if (error == EDEADLK) {
+ pageout_lock_miss++;
+ vnodes_skipped++;
+ } else if (error == EBUSY) {
+ addl_page_shortage++;
}
vm_page_lock_assert(m, MA_NOTOWNED);
goto relock_queues;
@@ -1784,11 +1787,13 @@ vm_daemon(void)
while (TRUE) {
mtx_lock(&vm_daemon_mtx);
+ msleep(&vm_daemon_needed, &vm_daemon_mtx, PPAUSE, "psleep",
#ifdef RACCT
- msleep(&vm_daemon_needed, &vm_daemon_mtx, PPAUSE, "psleep", hz);
+ racct_enable ? hz : 0
#else
- msleep(&vm_daemon_needed, &vm_daemon_mtx, PPAUSE, "psleep", 0);
+ 0
#endif
+ );
swapout_flags = vm_pageout_req_swapout;
vm_pageout_req_swapout = 0;
mtx_unlock(&vm_daemon_mtx);
@@ -1863,33 +1868,40 @@ again:
&vm->vm_map, limit);
}
#ifdef RACCT
- rsize = IDX_TO_OFF(size);
- PROC_LOCK(p);
- racct_set(p, RACCT_RSS, rsize);
- ravailable = racct_get_available(p, RACCT_RSS);
- PROC_UNLOCK(p);
- if (rsize > ravailable) {
- /*
- * Don't be overly aggressive; this might be
- * an innocent process, and the limit could've
- * been exceeded by some memory hog. Don't
- * try to deactivate more than 1/4th of process'
- * resident set size.
- */
- if (attempts <= 8) {
- if (ravailable < rsize - (rsize / 4))
- ravailable = rsize - (rsize / 4);
- }
- vm_pageout_map_deactivate_pages(
- &vm->vm_map, OFF_TO_IDX(ravailable));
- /* Update RSS usage after paging out. */
- size = vmspace_resident_count(vm);
+ if (racct_enable) {
rsize = IDX_TO_OFF(size);
PROC_LOCK(p);
racct_set(p, RACCT_RSS, rsize);
+ ravailable = racct_get_available(p, RACCT_RSS);
PROC_UNLOCK(p);
- if (rsize > ravailable)
- tryagain = 1;
+ if (rsize > ravailable) {
+ /*
+ * Don't be overly aggressive; this
+ * might be an innocent process,
+ * and the limit could've been exceeded
+ * by some memory hog. Don't try
+ * to deactivate more than 1/4th
+ * of process' resident set size.
+ */
+ if (attempts <= 8) {
+ if (ravailable < rsize -
+ (rsize / 4)) {
+ ravailable = rsize -
+ (rsize / 4);
+ }
+ }
+ vm_pageout_map_deactivate_pages(
+ &vm->vm_map,
+ OFF_TO_IDX(ravailable));
+ /* Update RSS usage after paging out. */
+ size = vmspace_resident_count(vm);
+ rsize = IDX_TO_OFF(size);
+ PROC_LOCK(p);
+ racct_set(p, RACCT_RSS, rsize);
+ PROC_UNLOCK(p);
+ if (rsize > ravailable)
+ tryagain = 1;
+ }
}
#endif
vmspace_free(vm);
diff --git a/sys/vm/vm_reserv.c b/sys/vm/vm_reserv.c
index 585a749..b74c768 100644
--- a/sys/vm/vm_reserv.c
+++ b/sys/vm/vm_reserv.c
@@ -983,8 +983,18 @@ vm_reserv_reclaim_contig(u_long npages, vm_paddr_t low, vm_paddr_t high,
break;
} else if ((pa & (alignment - 1)) != 0 ||
((pa ^ (pa + size - 1)) & ~(boundary - 1)) != 0) {
- /* Continue with this reservation. */
- hi = lo;
+ /*
+ * The current page doesn't meet the alignment
+ * and/or boundary requirements. Continue
+ * searching this reservation until the rest
+ * of its free pages are either excluded or
+ * exhausted.
+ */
+ hi = lo + 1;
+ if (hi >= NBPOPMAP) {
+ hi = 0;
+ i++;
+ }
continue;
}
/* Find the next used page. */
diff --git a/sys/vm/vm_unix.c b/sys/vm/vm_unix.c
index de9aa78..cc77ff7 100644
--- a/sys/vm/vm_unix.c
+++ b/sys/vm/vm_unix.c
@@ -130,35 +130,39 @@ sys_obreak(td, uap)
goto done;
}
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- error = racct_set(td->td_proc, RACCT_DATA, new - base);
- if (error != 0) {
- PROC_UNLOCK(td->td_proc);
- error = ENOMEM;
- goto done;
- }
- error = racct_set(td->td_proc, RACCT_VMEM,
- map->size + (new - old));
- if (error != 0) {
- racct_set_force(td->td_proc, RACCT_DATA, old - base);
- PROC_UNLOCK(td->td_proc);
- error = ENOMEM;
- goto done;
- }
- if (!old_mlock && map->flags & MAP_WIREFUTURE) {
- error = racct_set(td->td_proc, RACCT_MEMLOCK,
- ptoa(pmap_wired_count(map->pmap)) + (new - old));
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ error = racct_set(td->td_proc, RACCT_DATA, new - base);
+ if (error != 0) {
+ PROC_UNLOCK(td->td_proc);
+ error = ENOMEM;
+ goto done;
+ }
+ error = racct_set(td->td_proc, RACCT_VMEM,
+ map->size + (new - old));
if (error != 0) {
racct_set_force(td->td_proc, RACCT_DATA,
old - base);
- racct_set_force(td->td_proc, RACCT_VMEM,
- map->size);
PROC_UNLOCK(td->td_proc);
error = ENOMEM;
goto done;
}
+ if (!old_mlock && map->flags & MAP_WIREFUTURE) {
+ error = racct_set(td->td_proc, RACCT_MEMLOCK,
+ ptoa(pmap_wired_count(map->pmap)) +
+ (new - old));
+ if (error != 0) {
+ racct_set_force(td->td_proc, RACCT_DATA,
+ old - base);
+ racct_set_force(td->td_proc, RACCT_VMEM,
+ map->size);
+ PROC_UNLOCK(td->td_proc);
+ error = ENOMEM;
+ goto done;
+ }
+ }
+ PROC_UNLOCK(td->td_proc);
}
- PROC_UNLOCK(td->td_proc);
#endif
prot = VM_PROT_RW;
#ifdef COMPAT_FREEBSD32
@@ -170,14 +174,19 @@ sys_obreak(td, uap)
rv = vm_map_insert(map, NULL, 0, old, new, prot, VM_PROT_ALL, 0);
if (rv != KERN_SUCCESS) {
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- racct_set_force(td->td_proc, RACCT_DATA, old - base);
- racct_set_force(td->td_proc, RACCT_VMEM, map->size);
- if (!old_mlock && map->flags & MAP_WIREFUTURE) {
- racct_set_force(td->td_proc, RACCT_MEMLOCK,
- ptoa(pmap_wired_count(map->pmap)));
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ racct_set_force(td->td_proc,
+ RACCT_DATA, old - base);
+ racct_set_force(td->td_proc,
+ RACCT_VMEM, map->size);
+ if (!old_mlock && map->flags & MAP_WIREFUTURE) {
+ racct_set_force(td->td_proc,
+ RACCT_MEMLOCK,
+ ptoa(pmap_wired_count(map->pmap)));
+ }
+ PROC_UNLOCK(td->td_proc);
}
- PROC_UNLOCK(td->td_proc);
#endif
error = ENOMEM;
goto done;
@@ -205,14 +214,16 @@ sys_obreak(td, uap)
}
vm->vm_dsize -= btoc(old - new);
#ifdef RACCT
- PROC_LOCK(td->td_proc);
- racct_set_force(td->td_proc, RACCT_DATA, new - base);
- racct_set_force(td->td_proc, RACCT_VMEM, map->size);
- if (!old_mlock && map->flags & MAP_WIREFUTURE) {
- racct_set_force(td->td_proc, RACCT_MEMLOCK,
- ptoa(pmap_wired_count(map->pmap)));
+ if (racct_enable) {
+ PROC_LOCK(td->td_proc);
+ racct_set_force(td->td_proc, RACCT_DATA, new - base);
+ racct_set_force(td->td_proc, RACCT_VMEM, map->size);
+ if (!old_mlock && map->flags & MAP_WIREFUTURE) {
+ racct_set_force(td->td_proc, RACCT_MEMLOCK,
+ ptoa(pmap_wired_count(map->pmap)));
+ }
+ PROC_UNLOCK(td->td_proc);
}
- PROC_UNLOCK(td->td_proc);
#endif
}
done:
diff --git a/sys/x86/acpica/OsdEnvironment.c b/sys/x86/acpica/OsdEnvironment.c
index 380f1bf..be612b5 100644
--- a/sys/x86/acpica/OsdEnvironment.c
+++ b/sys/x86/acpica/OsdEnvironment.c
@@ -68,7 +68,7 @@ acpi_get_root_from_loader(void)
static u_long
acpi_get_root_from_memory(void)
{
- ACPI_SIZE acpi_root;
+ ACPI_PHYSICAL_ADDRESS acpi_root;
if (ACPI_SUCCESS(AcpiFindRootPointer(&acpi_root)))
return (acpi_root);
diff --git a/sys/x86/acpica/acpi_wakeup.c b/sys/x86/acpica/acpi_wakeup.c
index e8782c2..0eb6823 100644
--- a/sys/x86/acpica/acpi_wakeup.c
+++ b/sys/x86/acpica/acpi_wakeup.c
@@ -379,7 +379,7 @@ acpi_install_wakeup_handler(struct acpi_softc *sc)
/* Save pointers to some global data. */
WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
#ifndef __amd64__
-#ifdef PAE
+#if defined(PAE) || defined(PAE_TABLES)
WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdpt));
#else
WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdir));
diff --git a/sys/x86/acpica/srat.c b/sys/x86/acpica/srat.c
index 8335a8c..8d2a741 100644
--- a/sys/x86/acpica/srat.c
+++ b/sys/x86/acpica/srat.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2010 Advanced Computing Technologies LLC
+ * Copyright (c) 2010 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h
index 818a831..0bd9fe5 100644
--- a/sys/x86/include/apicvar.h
+++ b/sys/x86/include/apicvar.h
@@ -454,6 +454,7 @@ void lapic_handle_error(void);
void lapic_handle_intr(int vector, struct trapframe *frame);
void lapic_handle_timer(struct trapframe *frame);
void xen_intr_handle_upcall(struct trapframe *frame);
+void hv_vector_handler(struct trapframe *frame);
extern int x2apic_mode;
extern int lapic_eoi_suppression;
diff --git a/sys/x86/include/mca.h b/sys/x86/include/mca.h
index 29728b9..6420eb8 100644
--- a/sys/x86/include/mca.h
+++ b/sys/x86/include/mca.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/x86/include/reg.h b/sys/x86/include/reg.h
index 56668ea8..a1452cc 100644
--- a/sys/x86/include/reg.h
+++ b/sys/x86/include/reg.h
@@ -91,6 +91,7 @@
#define __fpreg64 fpreg
#define __dbreg32 dbreg32
#define __dbreg64 dbreg
+#define __HAVE_REG32
#endif
/*
diff --git a/sys/x86/include/segments.h b/sys/x86/include/segments.h
index a5c1ea4..65b5870 100644
--- a/sys/x86/include/segments.h
+++ b/sys/x86/include/segments.h
@@ -46,11 +46,7 @@
*/
#define SEL_RPL_MASK 3 /* requester priv level */
#define ISPL(s) ((s)&3) /* priority level of a selector */
-#ifdef XEN
-#define SEL_KPL 1 /* kernel priority level */
-#else
#define SEL_KPL 0 /* kernel priority level */
-#endif
#define SEL_UPL 3 /* user priority level */
#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */
#define SEL_LDT 4 /* local descriptor table */
@@ -244,11 +240,7 @@ union descriptor {
#define GBIOSUTIL_SEL 16 /* BIOS interface (Utility) */
#define GBIOSARGS_SEL 17 /* BIOS interface (Arguments) */
#define GNDIS_SEL 18 /* For the NDIS layer */
-#ifdef XEN
-#define NGDT 9
-#else
#define NGDT 19
-#endif
/*
* Entries in the Local Descriptor Table (LDT)
diff --git a/sys/x86/iommu/busdma_dmar.c b/sys/x86/iommu/busdma_dmar.c
index 3f86c78..96b0bce 100644
--- a/sys/x86/iommu/busdma_dmar.c
+++ b/sys/x86/iommu/busdma_dmar.c
@@ -462,6 +462,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
bus_size_t buflen1;
int error, idx, gas_flags, seg;
+ KASSERT(offset < DMAR_PAGE_SIZE, ("offset %d", offset));
if (segs == NULL)
segs = tag->segments;
ctx = tag->ctx;
@@ -476,7 +477,6 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
}
buflen1 = buflen > tag->common.maxsegsz ?
tag->common.maxsegsz : buflen;
- buflen -= buflen1;
size = round_page(offset + buflen1);
/*
@@ -487,7 +487,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
if (seg + 1 < tag->common.nsegments)
gas_flags |= DMAR_GM_CANSPLIT;
- error = dmar_gas_map(ctx, &tag->common, size,
+ error = dmar_gas_map(ctx, &tag->common, size, offset,
DMAR_MAP_ENTRY_READ | DMAR_MAP_ENTRY_WRITE,
gas_flags, ma + idx, &entry);
if (error != 0)
@@ -506,6 +506,10 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
(uintmax_t)size, (uintmax_t)entry->start,
(uintmax_t)entry->end));
}
+ if (offset + buflen1 > size)
+ buflen1 = size - offset;
+ if (buflen1 > tag->common.maxsegsz)
+ buflen1 = tag->common.maxsegsz;
KASSERT(((entry->start + offset) & (tag->common.alignment - 1))
== 0,
@@ -519,15 +523,16 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
(uintmax_t)entry->start, (uintmax_t)entry->end,
(uintmax_t)tag->common.lowaddr,
(uintmax_t)tag->common.highaddr));
- KASSERT(dmar_test_boundary(entry->start, entry->end -
- entry->start, tag->common.boundary),
+ KASSERT(dmar_test_boundary(entry->start + offset, buflen1,
+ tag->common.boundary),
("boundary failed: ctx %p start 0x%jx end 0x%jx "
"boundary 0x%jx", ctx, (uintmax_t)entry->start,
(uintmax_t)entry->end, (uintmax_t)tag->common.boundary));
KASSERT(buflen1 <= tag->common.maxsegsz,
("segment too large: ctx %p start 0x%jx end 0x%jx "
- "maxsegsz 0x%jx", ctx, (uintmax_t)entry->start,
- (uintmax_t)entry->end, (uintmax_t)tag->common.maxsegsz));
+ "buflen1 0x%jx maxsegsz 0x%jx", ctx,
+ (uintmax_t)entry->start, (uintmax_t)entry->end,
+ (uintmax_t)buflen1, (uintmax_t)tag->common.maxsegsz));
DMAR_CTX_LOCK(ctx);
TAILQ_INSERT_TAIL(&map->map_entries, entry, dmamap_link);
@@ -541,6 +546,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
idx += OFF_TO_IDX(trunc_page(offset + buflen1));
offset += buflen1;
offset &= DMAR_PAGE_MASK;
+ buflen -= buflen1;
}
if (error == 0)
*segp = seg;
diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h
index 2865ab5..401ff2f 100644
--- a/sys/x86/iommu/intel_dmar.h
+++ b/sys/x86/iommu/intel_dmar.h
@@ -308,7 +308,7 @@ struct dmar_map_entry *dmar_gas_alloc_entry(struct dmar_ctx *ctx, u_int flags);
void dmar_gas_free_entry(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
void dmar_gas_free_space(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
int dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
- dmar_gaddr_t size, u_int eflags, u_int flags, vm_page_t *ma,
+ dmar_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma,
struct dmar_map_entry **res);
void dmar_gas_free_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
int dmar_gas_map_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry,
diff --git a/sys/x86/iommu/intel_gas.c b/sys/x86/iommu/intel_gas.c
index d91da97..5a7a730 100644
--- a/sys/x86/iommu/intel_gas.c
+++ b/sys/x86/iommu/intel_gas.c
@@ -294,6 +294,7 @@ dmar_gas_fini_ctx(struct dmar_ctx *ctx)
struct dmar_gas_match_args {
struct dmar_ctx *ctx;
dmar_gaddr_t size;
+ int offset;
const struct bus_dma_tag_common *common;
u_int gas_flags;
struct dmar_map_entry *entry;
@@ -310,25 +311,28 @@ dmar_gas_match_one(struct dmar_gas_match_args *a, struct dmar_map_entry *prev,
/* DMAR_PAGE_SIZE to create gap after new entry. */
if (a->entry->start < prev->end + DMAR_PAGE_SIZE ||
- a->entry->start + a->size + DMAR_PAGE_SIZE > prev->end +
- prev->free_after)
+ a->entry->start + a->size + a->offset + DMAR_PAGE_SIZE >
+ prev->end + prev->free_after)
return (false);
/* No boundary crossing. */
- if (dmar_test_boundary(a->entry->start, a->size, a->common->boundary))
+ if (dmar_test_boundary(a->entry->start + a->offset, a->size,
+ a->common->boundary))
return (true);
/*
- * The start to start + size region crosses the boundary.
- * Check if there is enough space after the next boundary
- * after the prev->end.
+ * The start + offset to start + offset + size region crosses
+ * the boundary. Check if there is enough space after the
+ * next boundary after the prev->end.
*/
- bs = (a->entry->start + a->common->boundary) & ~(a->common->boundary
- - 1);
+ bs = (a->entry->start + a->offset + a->common->boundary) &
+ ~(a->common->boundary - 1);
start = roundup2(bs, a->common->alignment);
/* DMAR_PAGE_SIZE to create gap after new entry. */
- if (start + a->size + DMAR_PAGE_SIZE <= prev->end + prev->free_after &&
- start + a->size <= end && dmar_test_boundary(start, a->size,
+ if (start + a->offset + a->size + DMAR_PAGE_SIZE <=
+ prev->end + prev->free_after &&
+ start + a->offset + a->size <= end &&
+ dmar_test_boundary(start + a->offset, a->size,
a->common->boundary)) {
a->entry->start = start;
return (true);
@@ -410,7 +414,7 @@ dmar_gas_lowermatch(struct dmar_gas_match_args *a, struct dmar_map_entry *prev)
return (0);
}
}
- if (prev->free_down < a->size + DMAR_PAGE_SIZE)
+ if (prev->free_down < a->size + a->offset + DMAR_PAGE_SIZE)
return (ENOMEM);
l = RB_LEFT(prev, rb_entry);
if (l != NULL) {
@@ -466,7 +470,7 @@ dmar_gas_uppermatch(struct dmar_gas_match_args *a)
static int
dmar_gas_find_space(struct dmar_ctx *ctx,
const struct bus_dma_tag_common *common, dmar_gaddr_t size,
- u_int flags, struct dmar_map_entry *entry)
+ int offset, u_int flags, struct dmar_map_entry *entry)
{
struct dmar_gas_match_args a;
int error;
@@ -477,6 +481,7 @@ dmar_gas_find_space(struct dmar_ctx *ctx,
a.ctx = ctx;
a.size = size;
+ a.offset = offset;
a.common = common;
a.gas_flags = flags;
a.entry = entry;
@@ -618,7 +623,7 @@ dmar_gas_free_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
int
dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
- dmar_gaddr_t size, u_int eflags, u_int flags, vm_page_t *ma,
+ dmar_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma,
struct dmar_map_entry **res)
{
struct dmar_map_entry *entry;
@@ -632,7 +637,7 @@ dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
if (entry == NULL)
return (ENOMEM);
DMAR_CTX_LOCK(ctx);
- error = dmar_gas_find_space(ctx, common, size, flags, entry);
+ error = dmar_gas_find_space(ctx, common, size, offset, flags, entry);
if (error == ENOMEM) {
DMAR_CTX_UNLOCK(ctx);
dmar_gas_free_entry(ctx, entry);
diff --git a/sys/x86/pci/qpi.c b/sys/x86/pci/qpi.c
index 2f88891..ae29daa 100644
--- a/sys/x86/pci/qpi.c
+++ b/sys/x86/pci/qpi.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2010 Advanced Computing Technologies LLC
+ * Copyright (c) 2010 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/sys/x86/x86/busdma_bounce.c b/sys/x86/x86/busdma_bounce.c
index 1438053..dcdeafa 100644
--- a/sys/x86/x86/busdma_bounce.c
+++ b/sys/x86/x86/busdma_bounce.c
@@ -147,11 +147,6 @@ static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
int flags);
-#ifdef XEN
-#undef pmap_kextract
-#define pmap_kextract pmap_kextract_ma
-#endif
-
/*
* Allocate a device specific dma_tag.
*/
@@ -994,8 +989,8 @@ add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
if (dmat->common.flags & BUS_DMA_KEEP_PG_OFFSET) {
/* Page offset needs to be preserved. */
- bpage->vaddr |= vaddr & PAGE_MASK;
- bpage->busaddr |= vaddr & PAGE_MASK;
+ bpage->vaddr |= addr & PAGE_MASK;
+ bpage->busaddr |= addr & PAGE_MASK;
}
bpage->datavaddr = vaddr;
bpage->dataaddr = addr;
diff --git a/sys/x86/x86/cpu_machdep.c b/sys/x86/x86/cpu_machdep.c
new file mode 100644
index 0000000..f8d1f08
--- /dev/null
+++ b/sys/x86/x86/cpu_machdep.c
@@ -0,0 +1,486 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm.
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_atpic.h"
+#include "opt_compat.h"
+#include "opt_cpu.h"
+#include "opt_ddb.h"
+#include "opt_inet.h"
+#include "opt_isa.h"
+#include "opt_kstack_pages.h"
+#include "opt_maxmem.h"
+#include "opt_mp_watchdog.h"
+#include "opt_perfmon.h"
+#include "opt_platform.h"
+#ifdef __i386__
+#include "opt_npx.h"
+#include "opt_apic.h"
+#include "opt_xbox.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/rwlock.h>
+#include <sys/sched.h>
+#ifdef SMP
+#include <sys/smp.h>
+#endif
+#include <sys/sysctl.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cputypes.h>
+#include <machine/specialreg.h>
+#include <machine/md_var.h>
+#include <machine/mp_watchdog.h>
+#ifdef PERFMON
+#include <machine/perfmon.h>
+#endif
+#include <machine/tss.h>
+#ifdef SMP
+#include <machine/smp.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_param.h>
+
+/*
+ * Machine dependent boot() routine
+ *
+ * I haven't seen anything to put here yet
+ * Possibly some stuff might be grafted back here from boot()
+ */
+void
+cpu_boot(int howto)
+{
+}
+
+/*
+ * Flush the D-cache for non-DMA I/O so that the I-cache can
+ * be made coherent later.
+ */
+void
+cpu_flush_dcache(void *ptr, size_t len)
+{
+ /* Not applicable */
+}
+
+/* Get current clock frequency for the given cpu id. */
+int
+cpu_est_clockrate(int cpu_id, uint64_t *rate)
+{
+ uint64_t tsc1, tsc2;
+ uint64_t acnt, mcnt, perf;
+ register_t reg;
+
+ if (pcpu_find(cpu_id) == NULL || rate == NULL)
+ return (EINVAL);
+#ifdef __i386__
+ if ((cpu_feature & CPUID_TSC) == 0)
+ return (EOPNOTSUPP);
+#endif
+
+ /*
+ * If TSC is P-state invariant and APERF/MPERF MSRs do not exist,
+ * DELAY(9) based logic fails.
+ */
+ if (tsc_is_invariant && !tsc_perf_stat)
+ return (EOPNOTSUPP);
+
+#ifdef SMP
+ if (smp_cpus > 1) {
+ /* Schedule ourselves on the indicated cpu. */
+ thread_lock(curthread);
+ sched_bind(curthread, cpu_id);
+ thread_unlock(curthread);
+ }
+#endif
+
+ /* Calibrate by measuring a short delay. */
+ reg = intr_disable();
+ if (tsc_is_invariant) {
+ wrmsr(MSR_MPERF, 0);
+ wrmsr(MSR_APERF, 0);
+ tsc1 = rdtsc();
+ DELAY(1000);
+ mcnt = rdmsr(MSR_MPERF);
+ acnt = rdmsr(MSR_APERF);
+ tsc2 = rdtsc();
+ intr_restore(reg);
+ perf = 1000 * acnt / mcnt;
+ *rate = (tsc2 - tsc1) * perf;
+ } else {
+ tsc1 = rdtsc();
+ DELAY(1000);
+ tsc2 = rdtsc();
+ intr_restore(reg);
+ *rate = (tsc2 - tsc1) * 1000;
+ }
+
+#ifdef SMP
+ if (smp_cpus > 1) {
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+ }
+#endif
+
+ return (0);
+}
+
+/*
+ * Shutdown the CPU as much as possible
+ */
+void
+cpu_halt(void)
+{
+ for (;;)
+ halt();
+}
+
+void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */
+static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */
+static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */
+SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RWTUN, &idle_mwait,
+ 0, "Use MONITOR/MWAIT for short idle");
+
+#define STATE_RUNNING 0x0
+#define STATE_MWAIT 0x1
+#define STATE_SLEEPING 0x2
+
+#ifndef PC98
+static void
+cpu_idle_acpi(sbintime_t sbt)
+{
+ int *state;
+
+ state = (int *)PCPU_PTR(monitorbuf);
+ *state = STATE_SLEEPING;
+
+ /* See comments in cpu_idle_hlt(). */
+ disable_intr();
+ if (sched_runnable())
+ enable_intr();
+ else if (cpu_idle_hook)
+ cpu_idle_hook(sbt);
+ else
+ __asm __volatile("sti; hlt");
+ *state = STATE_RUNNING;
+}
+#endif /* !PC98 */
+
+static void
+cpu_idle_hlt(sbintime_t sbt)
+{
+ int *state;
+
+ state = (int *)PCPU_PTR(monitorbuf);
+ *state = STATE_SLEEPING;
+
+ /*
+ * Since we may be in a critical section from cpu_idle(), if
+ * an interrupt fires during that critical section we may have
+ * a pending preemption. If the CPU halts, then that thread
+ * may not execute until a later interrupt awakens the CPU.
+ * To handle this race, check for a runnable thread after
+ * disabling interrupts and immediately return if one is
+ * found. Also, we must absolutely guarentee that hlt is
+ * the next instruction after sti. This ensures that any
+ * interrupt that fires after the call to disable_intr() will
+ * immediately awaken the CPU from hlt. Finally, please note
+ * that on x86 this works fine because of interrupts enabled only
+ * after the instruction following sti takes place, while IF is set
+ * to 1 immediately, allowing hlt instruction to acknowledge the
+ * interrupt.
+ */
+ disable_intr();
+ if (sched_runnable())
+ enable_intr();
+ else
+ __asm __volatile("sti; hlt");
+ *state = STATE_RUNNING;
+}
+
+static void
+cpu_idle_mwait(sbintime_t sbt)
+{
+ int *state;
+
+ state = (int *)PCPU_PTR(monitorbuf);
+ *state = STATE_MWAIT;
+
+ /* See comments in cpu_idle_hlt(). */
+ disable_intr();
+ if (sched_runnable()) {
+ enable_intr();
+ *state = STATE_RUNNING;
+ return;
+ }
+ cpu_monitor(state, 0, 0);
+ if (*state == STATE_MWAIT)
+ __asm __volatile("sti; mwait" : : "a" (MWAIT_C1), "c" (0));
+ else
+ enable_intr();
+ *state = STATE_RUNNING;
+}
+
+static void
+cpu_idle_spin(sbintime_t sbt)
+{
+ int *state;
+ int i;
+
+ state = (int *)PCPU_PTR(monitorbuf);
+ *state = STATE_RUNNING;
+
+ /*
+ * The sched_runnable() call is racy but as long as there is
+ * a loop missing it one time will have just a little impact if any
+ * (and it is much better than missing the check at all).
+ */
+ for (i = 0; i < 1000; i++) {
+ if (sched_runnable())
+ return;
+ cpu_spinwait();
+ }
+}
+
+/*
+ * C1E renders the local APIC timer dead, so we disable it by
+ * reading the Interrupt Pending Message register and clearing
+ * both C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
+ *
+ * Reference:
+ * "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors"
+ * #32559 revision 3.00+
+ */
+#define MSR_AMDK8_IPM 0xc0010055
+#define AMDK8_SMIONCMPHALT (1ULL << 27)
+#define AMDK8_C1EONCMPHALT (1ULL << 28)
+#define AMDK8_CMPHALT (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT)
+
+void
+cpu_probe_amdc1e(void)
+{
+
+ /*
+ * Detect the presence of C1E capability mostly on latest
+ * dual-cores (or future) k8 family.
+ */
+ if (cpu_vendor_id == CPU_VENDOR_AMD &&
+ (cpu_id & 0x00000f00) == 0x00000f00 &&
+ (cpu_id & 0x0fff0000) >= 0x00040000) {
+ cpu_ident_amdc1e = 1;
+ }
+}
+
+#if defined(__i386__) && defined(PC98)
+void (*cpu_idle_fn)(sbintime_t) = cpu_idle_hlt;
+#else
+void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi;
+#endif
+
+void
+cpu_idle(int busy)
+{
+ uint64_t msr;
+ sbintime_t sbt = -1;
+
+ CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
+ busy, curcpu);
+#ifdef MP_WATCHDOG
+ ap_watchdog(PCPU_GET(cpuid));
+#endif
+
+ /* If we are busy - try to use fast methods. */
+ if (busy) {
+ if ((cpu_feature2 & CPUID2_MON) && idle_mwait) {
+ cpu_idle_mwait(busy);
+ goto out;
+ }
+ }
+
+ /* If we have time - switch timers into idle mode. */
+ if (!busy) {
+ critical_enter();
+ sbt = cpu_idleclock();
+ }
+
+ /* Apply AMD APIC timer C1E workaround. */
+ if (cpu_ident_amdc1e && cpu_disable_c3_sleep) {
+ msr = rdmsr(MSR_AMDK8_IPM);
+ if (msr & AMDK8_CMPHALT)
+ wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT);
+ }
+
+ /* Call main idle method. */
+ cpu_idle_fn(sbt);
+
+ /* Switch timers back into active mode. */
+ if (!busy) {
+ cpu_activeclock();
+ critical_exit();
+ }
+out:
+ CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
+ busy, curcpu);
+}
+
+int
+cpu_idle_wakeup(int cpu)
+{
+ struct pcpu *pcpu;
+ int *state;
+
+ pcpu = pcpu_find(cpu);
+ state = (int *)pcpu->pc_monitorbuf;
+ /*
+ * This doesn't need to be atomic since missing the race will
+ * simply result in unnecessary IPIs.
+ */
+ if (*state == STATE_SLEEPING)
+ return (0);
+ if (*state == STATE_MWAIT)
+ *state = STATE_RUNNING;
+ return (1);
+}
+
+/*
+ * Ordered by speed/power consumption.
+ */
+struct {
+ void *id_fn;
+ char *id_name;
+} idle_tbl[] = {
+ { cpu_idle_spin, "spin" },
+ { cpu_idle_mwait, "mwait" },
+ { cpu_idle_hlt, "hlt" },
+#if !defined(__i386__) || !defined(PC98)
+ { cpu_idle_acpi, "acpi" },
+#endif
+ { NULL, NULL }
+};
+
+static int
+idle_sysctl_available(SYSCTL_HANDLER_ARGS)
+{
+ char *avail, *p;
+ int error;
+ int i;
+
+ avail = malloc(256, M_TEMP, M_WAITOK);
+ p = avail;
+ for (i = 0; idle_tbl[i].id_name != NULL; i++) {
+ if (strstr(idle_tbl[i].id_name, "mwait") &&
+ (cpu_feature2 & CPUID2_MON) == 0)
+ continue;
+#if !defined(__i386__) || !defined(PC98)
+ if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
+ cpu_idle_hook == NULL)
+ continue;
+#endif
+ p += sprintf(p, "%s%s", p != avail ? ", " : "",
+ idle_tbl[i].id_name);
+ }
+ error = sysctl_handle_string(oidp, avail, 0, req);
+ free(avail, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD,
+ 0, 0, idle_sysctl_available, "A", "list of available idle functions");
+
+static int
+idle_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ char buf[16];
+ int error;
+ char *p;
+ int i;
+
+ p = "unknown";
+ for (i = 0; idle_tbl[i].id_name != NULL; i++) {
+ if (idle_tbl[i].id_fn == cpu_idle_fn) {
+ p = idle_tbl[i].id_name;
+ break;
+ }
+ }
+ strncpy(buf, p, sizeof(buf));
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ for (i = 0; idle_tbl[i].id_name != NULL; i++) {
+ if (strstr(idle_tbl[i].id_name, "mwait") &&
+ (cpu_feature2 & CPUID2_MON) == 0)
+ continue;
+#if !defined(__i386__) || !defined(PC98)
+ if (strcmp(idle_tbl[i].id_name, "acpi") == 0 &&
+ cpu_idle_hook == NULL)
+ continue;
+#endif
+ if (strcmp(idle_tbl[i].id_name, buf))
+ continue;
+ cpu_idle_fn = idle_tbl[i].id_fn;
+ return (0);
+ }
+ return (EINVAL);
+}
+
+SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
+ idle_sysctl, "A", "currently selected idle function");
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
index ca2b5ca..9f39d1c 100644
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -1190,7 +1190,6 @@ hook_tsc_freq(void *arg __unused)
SYSINIT(hook_tsc_freq, SI_SUB_CONFIGURE, SI_ORDER_ANY, hook_tsc_freq, NULL);
-#ifndef XEN
static const char *const vm_bnames[] = {
"QEMU", /* QEMU */
"Plex86", /* Plex86 */
@@ -1281,7 +1280,6 @@ identify_hypervisor(void)
freeenv(p);
}
}
-#endif
/*
* Final stage of CPU identification.
@@ -1314,9 +1312,7 @@ identify_cpu(void)
cpu_feature2 = regs[2];
#endif
-#ifndef XEN
identify_hypervisor();
-#endif
cpu_vendor_id = find_cpu_vendor_id();
/*
diff --git a/sys/x86/x86/intr_machdep.c b/sys/x86/x86/intr_machdep.c
index b27df4a..d81c913 100644
--- a/sys/x86/x86/intr_machdep.c
+++ b/sys/x86/x86/intr_machdep.c
@@ -532,13 +532,6 @@ intr_shuffle_irqs(void *arg __unused)
struct intsrc *isrc;
int i;
-#ifdef XEN
- /*
- * Doesn't work yet
- */
- return;
-#endif
-
/* Don't bother on UP. */
if (mp_ncpus == 1)
return;
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index e0656ef..d75a452 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -1579,17 +1579,13 @@ apic_setup_io(void *dummy __unused)
* Local APIC must be registered before other PICs and pseudo PICs
* for proper suspend/resume order.
*/
-#ifndef XEN
intr_register_pic(&lapic_pic);
-#endif
retval = best_enum->apic_setup_io();
if (retval != 0)
printf("%s: Failed to setup I/O APICs: returned %d\n",
best_enum->apic_name, retval);
-#ifdef XEN
- return;
-#endif
+
/*
* Finish setting up the local APIC on the BSP once we know
* how to properly program the LINT pins. In particular, this
diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c
index 2fd959f..8026b15 100644
--- a/sys/x86/x86/mca.c
+++ b/sys/x86/x86/mca.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
@@ -251,15 +251,24 @@ mca_mute(const struct mca_record *rec)
{
/*
- * Skip spurious corrected parity errors generated by desktop Haswell
- * (see HSD131 erratum) unless reporting is enabled.
- * Note that these errors also have been observed with D0-stepping,
- * while the revision 014 desktop Haswell specification update only
- * talks about C0-stepping.
+ * Skip spurious corrected parity errors generated by Intel Haswell-
+ * and Broadwell-based CPUs (see HSD131, HSM142, HSW131 and BDM48
+ * erratum respectively), unless reporting is enabled.
+ * Note that these errors also have been observed with the D0-stepping
+ * of Haswell, while at least initially the CPU specification updates
+ * suggested only the C0-stepping to be affected. Similarly, Celeron
+ * 2955U with a CPU ID of 0x45 apparently are also concerned with the
+ * same problem, with HSM142 only referring to 0x3c and 0x46.
*/
- if (rec->mr_cpu_vendor_id == CPU_VENDOR_INTEL &&
- rec->mr_cpu_id == 0x306c3 && rec->mr_bank == 0 &&
- rec->mr_status == 0x90000040000f0005 && !intel6h_HSD131)
+ if (cpu_vendor_id == CPU_VENDOR_INTEL &&
+ CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ (CPUID_TO_MODEL(cpu_id) == 0x3c || /* HSD131, HSM142, HSW131 */
+ CPUID_TO_MODEL(cpu_id) == 0x3d || /* BDM48 */
+ CPUID_TO_MODEL(cpu_id) == 0x45 ||
+ CPUID_TO_MODEL(cpu_id) == 0x46) && /* HSM142 */
+ rec->mr_bank == 0 &&
+ (rec->mr_status & 0xa0000000ffffffff) == 0x80000000000f0005 &&
+ !intel6h_HSD131)
return (1);
return (0);
diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c
new file mode 100644
index 0000000..b4c66a5
--- /dev/null
+++ b/sys/x86/x86/mp_x86.c
@@ -0,0 +1,1120 @@
+/*-
+ * Copyright (c) 1996, by Steve Passe
+ * Copyright (c) 2003, by Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __i386__
+#include "opt_apic.h"
+#endif
+#include "opt_cpu.h"
+#include "opt_kstack_pages.h"
+#include "opt_pmap.h"
+#include "opt_sched.h"
+#include "opt_smp.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h> /* cngetc() */
+#include <sys/cpuset.h>
+#ifdef GPROF
+#include <sys/gmon.h>
+#endif
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/memrange.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/smp.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+
+#include <x86/apicreg.h>
+#include <machine/clock.h>
+#include <machine/cputypes.h>
+#include <x86/mca.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/psl.h>
+#include <machine/smp.h>
+#include <machine/specialreg.h>
+#include <machine/cpu.h>
+
+#define WARMBOOT_TARGET 0
+#define WARMBOOT_OFF (KERNBASE + 0x0467)
+#define WARMBOOT_SEG (KERNBASE + 0x0469)
+
+#define CMOS_REG (0x70)
+#define CMOS_DATA (0x71)
+#define BIOS_RESET (0x0f)
+#define BIOS_WARM (0x0a)
+
+/* lock region used by kernel profiling */
+int mcount_lock;
+
+int mp_naps; /* # of Applications processors */
+int boot_cpu_id = -1; /* designated BSP */
+
+extern struct pcpu __pcpu[];
+
+/* AP uses this during bootstrap. Do not staticize. */
+char *bootSTK;
+int bootAP;
+
+/* Free these after use */
+void *bootstacks[MAXCPU];
+void *dpcpu;
+
+struct pcb stoppcbs[MAXCPU];
+struct susppcb **susppcbs;
+
+#ifdef COUNT_IPIS
+/* Interrupt counts. */
+static u_long *ipi_preempt_counts[MAXCPU];
+static u_long *ipi_ast_counts[MAXCPU];
+u_long *ipi_invltlb_counts[MAXCPU];
+u_long *ipi_invlrng_counts[MAXCPU];
+u_long *ipi_invlpg_counts[MAXCPU];
+u_long *ipi_invlcache_counts[MAXCPU];
+u_long *ipi_rendezvous_counts[MAXCPU];
+static u_long *ipi_hardclock_counts[MAXCPU];
+#endif
+
+/* Default cpu_ops implementation. */
+struct cpu_ops cpu_ops;
+
+/*
+ * Local data and functions.
+ */
+
+static volatile cpuset_t ipi_nmi_pending;
+
+/* used to hold the AP's until we are ready to release them */
+struct mtx ap_boot_mtx;
+
+/* Set to 1 once we're ready to let the APs out of the pen. */
+volatile int aps_ready = 0;
+
+/*
+ * Store data from cpu_add() until later in the boot when we actually setup
+ * the APs.
+ */
+struct cpu_info cpu_info[MAX_APIC_ID + 1];
+int cpu_apic_ids[MAXCPU];
+int apic_cpuids[MAX_APIC_ID + 1];
+
+/* Holds pending bitmap based IPIs per CPU */
+volatile u_int cpu_ipi_pending[MAXCPU];
+
+int cpu_logical; /* logical cpus per core */
+int cpu_cores; /* cores per package */
+
+static void release_aps(void *dummy);
+
+static u_int hyperthreading_cpus; /* logical cpus sharing L1 cache */
+static int hyperthreading_allowed = 1;
+
+void
+mem_range_AP_init(void)
+{
+
+ if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
+ mem_range_softc.mr_op->initAP(&mem_range_softc);
+}
+
+static void
+topo_probe_amd(void)
+{
+ int core_id_bits;
+ int id;
+
+ /* AMD processors do not support HTT. */
+ cpu_logical = 1;
+
+ if ((amd_feature2 & AMDID2_CMP) == 0) {
+ cpu_cores = 1;
+ return;
+ }
+
+ core_id_bits = (cpu_procinfo2 & AMDID_COREID_SIZE) >>
+ AMDID_COREID_SIZE_SHIFT;
+ if (core_id_bits == 0) {
+ cpu_cores = (cpu_procinfo2 & AMDID_CMP_CORES) + 1;
+ return;
+ }
+
+ /* Fam 10h and newer should get here. */
+ for (id = 0; id <= MAX_APIC_ID; id++) {
+ /* Check logical CPU availability. */
+ if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
+ continue;
+ /* Check if logical CPU has the same package ID. */
+ if ((id >> core_id_bits) != (boot_cpu_id >> core_id_bits))
+ continue;
+ cpu_cores++;
+ }
+}
+
+/*
+ * Round up to the next power of two, if necessary, and then
+ * take log2.
+ * Returns -1 if argument is zero.
+ */
+static __inline int
+mask_width(u_int x)
+{
+
+ return (fls(x << (1 - powerof2(x))) - 1);
+}
+
+static void
+topo_probe_0x4(void)
+{
+ u_int p[4];
+ int pkg_id_bits;
+ int core_id_bits;
+ int max_cores;
+ int max_logical;
+ int id;
+
+ /* Both zero and one here mean one logical processor per package. */
+ max_logical = (cpu_feature & CPUID_HTT) != 0 ?
+ (cpu_procinfo & CPUID_HTT_CORES) >> 16 : 1;
+ if (max_logical <= 1)
+ return;
+
+ /*
+ * Because of uniformity assumption we examine only
+ * those logical processors that belong to the same
+ * package as BSP. Further, we count number of
+ * logical processors that belong to the same core
+ * as BSP thus deducing number of threads per core.
+ */
+ if (cpu_high >= 0x4) {
+ cpuid_count(0x04, 0, p);
+ max_cores = ((p[0] >> 26) & 0x3f) + 1;
+ } else
+ max_cores = 1;
+ core_id_bits = mask_width(max_logical/max_cores);
+ if (core_id_bits < 0)
+ return;
+ pkg_id_bits = core_id_bits + mask_width(max_cores);
+
+ for (id = 0; id <= MAX_APIC_ID; id++) {
+ /* Check logical CPU availability. */
+ if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
+ continue;
+ /* Check if logical CPU has the same package ID. */
+ if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits))
+ continue;
+ cpu_cores++;
+ /* Check if logical CPU has the same package and core IDs. */
+ if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits))
+ cpu_logical++;
+ }
+
+ KASSERT(cpu_cores >= 1 && cpu_logical >= 1,
+ ("topo_probe_0x4 couldn't find BSP"));
+
+ cpu_cores /= cpu_logical;
+ hyperthreading_cpus = cpu_logical;
+}
+
+static void
+topo_probe_0xb(void)
+{
+ u_int p[4];
+ int bits;
+ int cnt;
+ int i;
+ int logical;
+ int type;
+ int x;
+
+ /* We only support three levels for now. */
+ for (i = 0; i < 3; i++) {
+ cpuid_count(0x0b, i, p);
+
+ /* Fall back if CPU leaf 11 doesn't really exist. */
+ if (i == 0 && p[1] == 0) {
+ topo_probe_0x4();
+ return;
+ }
+
+ bits = p[0] & 0x1f;
+ logical = p[1] &= 0xffff;
+ type = (p[2] >> 8) & 0xff;
+ if (type == 0 || logical == 0)
+ break;
+ /*
+ * Because of uniformity assumption we examine only
+ * those logical processors that belong to the same
+ * package as BSP.
+ */
+ for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) {
+ if (!cpu_info[x].cpu_present ||
+ cpu_info[x].cpu_disabled)
+ continue;
+ if (x >> bits == boot_cpu_id >> bits)
+ cnt++;
+ }
+ if (type == CPUID_TYPE_SMT)
+ cpu_logical = cnt;
+ else if (type == CPUID_TYPE_CORE)
+ cpu_cores = cnt;
+ }
+ if (cpu_logical == 0)
+ cpu_logical = 1;
+ cpu_cores /= cpu_logical;
+}
+
+/*
+ * Both topology discovery code and code that consumes topology
+ * information assume top-down uniformity of the topology.
+ * That is, all physical packages must be identical and each
+ * core in a package must have the same number of threads.
+ * Topology information is queried only on BSP, on which this
+ * code runs and for which it can query CPUID information.
+ * Then topology is extrapolated on all packages using the
+ * uniformity assumption.
+ */
+void
+topo_probe(void)
+{
+ static int cpu_topo_probed = 0;
+
+ if (cpu_topo_probed)
+ return;
+
+ CPU_ZERO(&logical_cpus_mask);
+ if (mp_ncpus <= 1)
+ cpu_cores = cpu_logical = 1;
+ else if (cpu_vendor_id == CPU_VENDOR_AMD)
+ topo_probe_amd();
+ else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
+ /*
+ * See Intel(R) 64 Architecture Processor
+ * Topology Enumeration article for details.
+ *
+ * Note that 0x1 <= cpu_high < 4 case should be
+ * compatible with topo_probe_0x4() logic when
+ * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
+ * or it should trigger the fallback otherwise.
+ */
+ if (cpu_high >= 0xb)
+ topo_probe_0xb();
+ else if (cpu_high >= 0x1)
+ topo_probe_0x4();
+ }
+
+ /*
+ * Fallback: assume each logical CPU is in separate
+ * physical package. That is, no multi-core, no SMT.
+ */
+ if (cpu_cores == 0 || cpu_logical == 0)
+ cpu_cores = cpu_logical = 1;
+ cpu_topo_probed = 1;
+}
+
+struct cpu_group *
+cpu_topo(void)
+{
+ int cg_flags;
+
+ /*
+ * Determine whether any threading flags are
+ * necessry.
+ */
+ topo_probe();
+ if (cpu_logical > 1 && hyperthreading_cpus)
+ cg_flags = CG_FLAG_HTT;
+ else if (cpu_logical > 1)
+ cg_flags = CG_FLAG_SMT;
+ else
+ cg_flags = 0;
+ if (mp_ncpus % (cpu_cores * cpu_logical) != 0) {
+ printf("WARNING: Non-uniform processors.\n");
+ printf("WARNING: Using suboptimal topology.\n");
+ return (smp_topo_none());
+ }
+ /*
+ * No multi-core or hyper-threaded.
+ */
+ if (cpu_logical * cpu_cores == 1)
+ return (smp_topo_none());
+ /*
+ * Only HTT no multi-core.
+ */
+ if (cpu_logical > 1 && cpu_cores == 1)
+ return (smp_topo_1level(CG_SHARE_L1, cpu_logical, cg_flags));
+ /*
+ * Only multi-core no HTT.
+ */
+ if (cpu_cores > 1 && cpu_logical == 1)
+ return (smp_topo_1level(CG_SHARE_L2, cpu_cores, cg_flags));
+ /*
+ * Both HTT and multi-core.
+ */
+ return (smp_topo_2level(CG_SHARE_L2, cpu_cores,
+ CG_SHARE_L1, cpu_logical, cg_flags));
+}
+
+
+void
+cpu_add(u_int apic_id, char boot_cpu)
+{
+
+ if (apic_id > MAX_APIC_ID) {
+ panic("SMP: APIC ID %d too high", apic_id);
+ return;
+ }
+ KASSERT(cpu_info[apic_id].cpu_present == 0, ("CPU %d added twice",
+ apic_id));
+ cpu_info[apic_id].cpu_present = 1;
+ if (boot_cpu) {
+ KASSERT(boot_cpu_id == -1,
+ ("CPU %d claims to be BSP, but CPU %d already is", apic_id,
+ boot_cpu_id));
+ boot_cpu_id = apic_id;
+ cpu_info[apic_id].cpu_bsp = 1;
+ }
+ if (mp_ncpus < MAXCPU) {
+ mp_ncpus++;
+ mp_maxid = mp_ncpus - 1;
+ }
+ if (bootverbose)
+ printf("SMP: Added CPU %d (%s)\n", apic_id, boot_cpu ? "BSP" :
+ "AP");
+}
+
+void
+cpu_mp_setmaxid(void)
+{
+
+ /*
+ * mp_maxid should be already set by calls to cpu_add().
+ * Just sanity check its value here.
+ */
+ if (mp_ncpus == 0)
+ KASSERT(mp_maxid == 0,
+ ("%s: mp_ncpus is zero, but mp_maxid is not", __func__));
+ else if (mp_ncpus == 1)
+ mp_maxid = 0;
+ else
+ KASSERT(mp_maxid >= mp_ncpus - 1,
+ ("%s: counters out of sync: max %d, count %d", __func__,
+ mp_maxid, mp_ncpus));
+}
+
+int
+cpu_mp_probe(void)
+{
+
+ /*
+ * Always record BSP in CPU map so that the mbuf init code works
+ * correctly.
+ */
+ CPU_SETOF(0, &all_cpus);
+ if (mp_ncpus == 0) {
+ /*
+ * No CPUs were found, so this must be a UP system. Setup
+ * the variables to represent a system with a single CPU
+ * with an id of 0.
+ */
+ mp_ncpus = 1;
+ return (0);
+ }
+
+ /* At least one CPU was found. */
+ if (mp_ncpus == 1) {
+ /*
+ * One CPU was found, so this must be a UP system with
+ * an I/O APIC.
+ */
+ mp_maxid = 0;
+ return (0);
+ }
+
+ /* At least two CPUs were found. */
+ return (1);
+}
+
+/*
+ * Print various information about the SMP system hardware and setup.
+ */
+void
+cpu_mp_announce(void)
+{
+ const char *hyperthread;
+ int i;
+
+ printf("FreeBSD/SMP: %d package(s) x %d core(s)",
+ mp_ncpus / (cpu_cores * cpu_logical), cpu_cores);
+ if (hyperthreading_cpus > 1)
+ printf(" x %d HTT threads", cpu_logical);
+ else if (cpu_logical > 1)
+ printf(" x %d SMT threads", cpu_logical);
+ printf("\n");
+
+ /* List active CPUs first. */
+ printf(" cpu0 (BSP): APIC ID: %2d\n", boot_cpu_id);
+ for (i = 1; i < mp_ncpus; i++) {
+ if (cpu_info[cpu_apic_ids[i]].cpu_hyperthread)
+ hyperthread = "/HT";
+ else
+ hyperthread = "";
+ printf(" cpu%d (AP%s): APIC ID: %2d\n", i, hyperthread,
+ cpu_apic_ids[i]);
+ }
+
+ /* List disabled CPUs last. */
+ for (i = 0; i <= MAX_APIC_ID; i++) {
+ if (!cpu_info[i].cpu_present || !cpu_info[i].cpu_disabled)
+ continue;
+ if (cpu_info[i].cpu_hyperthread)
+ hyperthread = "/HT";
+ else
+ hyperthread = "";
+ printf(" cpu (AP%s): APIC ID: %2d (disabled)\n", hyperthread,
+ i);
+ }
+}
+
+void
+init_secondary_tail(void)
+{
+ u_int cpuid;
+
+ /*
+ * On real hardware, switch to x2apic mode if possible. Do it
+ * after aps_ready was signalled, to avoid manipulating the
+ * mode while BSP might still want to send some IPI to us
+ * (second startup IPI is ignored on modern hardware etc).
+ */
+ lapic_xapic_mode();
+
+ /* Initialize the PAT MSR. */
+ pmap_init_pat();
+
+ /* set up CPU registers and state */
+ cpu_setregs();
+
+ /* set up SSE/NX */
+ initializecpu();
+
+ /* set up FPU state on the AP */
+#ifdef __amd64__
+ fpuinit();
+#else
+ npxinit(false);
+#endif
+
+ if (cpu_ops.cpu_init)
+ cpu_ops.cpu_init();
+
+ /* A quick check from sanity claus */
+ cpuid = PCPU_GET(cpuid);
+ if (PCPU_GET(apic_id) != lapic_id()) {
+ printf("SMP: cpuid = %d\n", cpuid);
+ printf("SMP: actual apic_id = %d\n", lapic_id());
+ printf("SMP: correct apic_id = %d\n", PCPU_GET(apic_id));
+ panic("cpuid mismatch! boom!!");
+ }
+
+ /* Initialize curthread. */
+ KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
+ PCPU_SET(curthread, PCPU_GET(idlethread));
+
+ mca_init();
+
+ mtx_lock_spin(&ap_boot_mtx);
+
+ /* Init local apic for irq's */
+ lapic_setup(1);
+
+ /* Set memory range attributes for this CPU to match the BSP */
+ mem_range_AP_init();
+
+ smp_cpus++;
+
+ CTR1(KTR_SMP, "SMP: AP CPU #%d Launched", cpuid);
+ printf("SMP: AP CPU #%d Launched!\n", cpuid);
+
+ /* Determine if we are a logical CPU. */
+ /* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */
+ if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0)
+ CPU_SET(cpuid, &logical_cpus_mask);
+
+ if (bootverbose)
+ lapic_dump("AP");
+
+ if (smp_cpus == mp_ncpus) {
+ /* enable IPI's, tlb shootdown, freezes etc */
+ atomic_store_rel_int(&smp_started, 1);
+ }
+
+#ifdef __amd64__
+ /*
+ * Enable global pages TLB extension
+ * This also implicitly flushes the TLB
+ */
+ load_cr4(rcr4() | CR4_PGE);
+ if (pmap_pcid_enabled)
+ load_cr4(rcr4() | CR4_PCIDE);
+ load_ds(_udatasel);
+ load_es(_udatasel);
+ load_fs(_ufssel);
+#endif
+
+ mtx_unlock_spin(&ap_boot_mtx);
+
+ /* Wait until all the AP's are up. */
+ while (smp_started == 0)
+ ia32_pause();
+
+ /* Start per-CPU event timers. */
+ cpu_initclocks_ap();
+
+ sched_throw(NULL);
+
+ panic("scheduler returned us to %s", __func__);
+ /* NOTREACHED */
+}
+
+/*******************************************************************
+ * local functions and data
+ */
+
+/*
+ * We tell the I/O APIC code about all the CPUs we want to receive
+ * interrupts. If we don't want certain CPUs to receive IRQs we
+ * can simply not tell the I/O APIC code about them in this function.
+ * We also do not tell it about the BSP since it tells itself about
+ * the BSP internally to work with UP kernels and on UP machines.
+ */
+void
+set_interrupt_apic_ids(void)
+{
+ u_int i, apic_id;
+
+ for (i = 0; i < MAXCPU; i++) {
+ apic_id = cpu_apic_ids[i];
+ if (apic_id == -1)
+ continue;
+ if (cpu_info[apic_id].cpu_bsp)
+ continue;
+ if (cpu_info[apic_id].cpu_disabled)
+ continue;
+
+ /* Don't let hyperthreads service interrupts. */
+ if (cpu_logical > 1 &&
+ apic_id % cpu_logical != 0)
+ continue;
+
+ intr_add_cpu(i);
+ }
+}
+
+/*
+ * Assign logical CPU IDs to local APICs.
+ */
+void
+assign_cpu_ids(void)
+{
+ u_int i;
+
+ TUNABLE_INT_FETCH("machdep.hyperthreading_allowed",
+ &hyperthreading_allowed);
+
+ /* Check for explicitly disabled CPUs. */
+ for (i = 0; i <= MAX_APIC_ID; i++) {
+ if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp)
+ continue;
+
+ if (hyperthreading_cpus > 1 && i % hyperthreading_cpus != 0) {
+ cpu_info[i].cpu_hyperthread = 1;
+
+ /*
+ * Don't use HT CPU if it has been disabled by a
+ * tunable.
+ */
+ if (hyperthreading_allowed == 0) {
+ cpu_info[i].cpu_disabled = 1;
+ continue;
+ }
+ }
+
+ /* Don't use this CPU if it has been disabled by a tunable. */
+ if (resource_disabled("lapic", i)) {
+ cpu_info[i].cpu_disabled = 1;
+ continue;
+ }
+ }
+
+ if (hyperthreading_allowed == 0 && hyperthreading_cpus > 1) {
+ hyperthreading_cpus = 0;
+ cpu_logical = 1;
+ }
+
+ /*
+ * Assign CPU IDs to local APIC IDs and disable any CPUs
+ * beyond MAXCPU. CPU 0 is always assigned to the BSP.
+ *
+ * To minimize confusion for userland, we attempt to number
+ * CPUs such that all threads and cores in a package are
+ * grouped together. For now we assume that the BSP is always
+ * the first thread in a package and just start adding APs
+ * starting with the BSP's APIC ID.
+ */
+ mp_ncpus = 1;
+ cpu_apic_ids[0] = boot_cpu_id;
+ apic_cpuids[boot_cpu_id] = 0;
+ for (i = boot_cpu_id + 1; i != boot_cpu_id;
+ i == MAX_APIC_ID ? i = 0 : i++) {
+ if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp ||
+ cpu_info[i].cpu_disabled)
+ continue;
+
+ if (mp_ncpus < MAXCPU) {
+ cpu_apic_ids[mp_ncpus] = i;
+ apic_cpuids[i] = mp_ncpus;
+ mp_ncpus++;
+ } else
+ cpu_info[i].cpu_disabled = 1;
+ }
+ KASSERT(mp_maxid >= mp_ncpus - 1,
+ ("%s: counters out of sync: max %d, count %d", __func__, mp_maxid,
+ mp_ncpus));
+}
+
+#ifdef COUNT_XINVLTLB_HITS
+u_int xhits_gbl[MAXCPU];
+u_int xhits_pg[MAXCPU];
+u_int xhits_rng[MAXCPU];
+static SYSCTL_NODE(_debug, OID_AUTO, xhits, CTLFLAG_RW, 0, "");
+SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, global, CTLFLAG_RW, &xhits_gbl,
+ sizeof(xhits_gbl), "IU", "");
+SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, page, CTLFLAG_RW, &xhits_pg,
+ sizeof(xhits_pg), "IU", "");
+SYSCTL_OPAQUE(_debug_xhits, OID_AUTO, range, CTLFLAG_RW, &xhits_rng,
+ sizeof(xhits_rng), "IU", "");
+
+u_int ipi_global;
+u_int ipi_page;
+u_int ipi_range;
+u_int ipi_range_size;
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_global, CTLFLAG_RW, &ipi_global, 0, "");
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_page, CTLFLAG_RW, &ipi_page, 0, "");
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_range, CTLFLAG_RW, &ipi_range, 0, "");
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_range_size, CTLFLAG_RW, &ipi_range_size,
+ 0, "");
+
+u_int ipi_masked_global;
+u_int ipi_masked_page;
+u_int ipi_masked_range;
+u_int ipi_masked_range_size;
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_global, CTLFLAG_RW,
+ &ipi_masked_global, 0, "");
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_page, CTLFLAG_RW,
+ &ipi_masked_page, 0, "");
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_range, CTLFLAG_RW,
+ &ipi_masked_range, 0, "");
+SYSCTL_INT(_debug_xhits, OID_AUTO, ipi_masked_range_size, CTLFLAG_RW,
+ &ipi_masked_range_size, 0, "");
+#endif /* COUNT_XINVLTLB_HITS */
+
+/*
+ * Init and startup IPI.
+ */
+void
+ipi_startup(int apic_id, int vector)
+{
+
+ /*
+ * This attempts to follow the algorithm described in the
+ * Intel Multiprocessor Specification v1.4 in section B.4.
+ * For each IPI, we allow the local APIC ~20us to deliver the
+ * IPI. If that times out, we panic.
+ */
+
+ /*
+ * first we do an INIT IPI: this INIT IPI might be run, resetting
+ * and running the target CPU. OR this INIT IPI might be latched (P5
+ * bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be
+ * ignored.
+ */
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
+ lapic_ipi_wait(100);
+
+ /* Explicitly deassert the INIT IPI. */
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
+ APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT,
+ apic_id);
+
+ DELAY(10000); /* wait ~10mS */
+
+ /*
+ * next we do a STARTUP IPI: the previous INIT IPI might still be
+ * latched, (P5 bug) this 1st STARTUP would then terminate
+ * immediately, and the previously started INIT IPI would continue. OR
+ * the previous INIT IPI has already run. and this STARTUP IPI will
+ * run. OR the previous INIT IPI was ignored. and this STARTUP IPI
+ * will run.
+ */
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ vector, apic_id);
+ if (!lapic_ipi_wait(100))
+ panic("Failed to deliver first STARTUP IPI to APIC %d",
+ apic_id);
+ DELAY(200); /* wait ~200uS */
+
+ /*
+ * finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF
+ * the previous STARTUP IPI was cancelled by a latched INIT IPI. OR
+ * this STARTUP IPI will be ignored, as only ONE STARTUP IPI is
+ * recognized after hardware RESET or INIT IPI.
+ */
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ vector, apic_id);
+ if (!lapic_ipi_wait(100))
+ panic("Failed to deliver second STARTUP IPI to APIC %d",
+ apic_id);
+
+ DELAY(200); /* wait ~200uS */
+}
+
+/*
+ * Send an IPI to specified CPU handling the bitmap logic.
+ */
+void
+ipi_send_cpu(int cpu, u_int ipi)
+{
+ u_int bitmap, old_pending, new_pending;
+
+ KASSERT(cpu_apic_ids[cpu] != -1, ("IPI to non-existent CPU %d", cpu));
+
+ if (IPI_IS_BITMAPED(ipi)) {
+ bitmap = 1 << ipi;
+ ipi = IPI_BITMAP_VECTOR;
+ do {
+ old_pending = cpu_ipi_pending[cpu];
+ new_pending = old_pending | bitmap;
+ } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu],
+ old_pending, new_pending));
+ if (old_pending)
+ return;
+ }
+ lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
+}
+
+void
+ipi_bitmap_handler(struct trapframe frame)
+{
+ struct trapframe *oldframe;
+ struct thread *td;
+ int cpu = PCPU_GET(cpuid);
+ u_int ipi_bitmap;
+
+ critical_enter();
+ td = curthread;
+ td->td_intr_nesting_level++;
+ oldframe = td->td_intr_frame;
+ td->td_intr_frame = &frame;
+ ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]);
+ if (ipi_bitmap & (1 << IPI_PREEMPT)) {
+#ifdef COUNT_IPIS
+ (*ipi_preempt_counts[cpu])++;
+#endif
+ sched_preempt(td);
+ }
+ if (ipi_bitmap & (1 << IPI_AST)) {
+#ifdef COUNT_IPIS
+ (*ipi_ast_counts[cpu])++;
+#endif
+ /* Nothing to do for AST */
+ }
+ if (ipi_bitmap & (1 << IPI_HARDCLOCK)) {
+#ifdef COUNT_IPIS
+ (*ipi_hardclock_counts[cpu])++;
+#endif
+ hardclockintr();
+ }
+ td->td_intr_frame = oldframe;
+ td->td_intr_nesting_level--;
+ critical_exit();
+}
+
+/*
+ * send an IPI to a set of cpus.
+ */
+void
+ipi_selected(cpuset_t cpus, u_int ipi)
+{
+ int cpu;
+
+ /*
+ * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
+ * of help in order to understand what is the source.
+ * Set the mask of receiving CPUs for this purpose.
+ */
+ if (ipi == IPI_STOP_HARD)
+ CPU_OR_ATOMIC(&ipi_nmi_pending, &cpus);
+
+ while ((cpu = CPU_FFS(&cpus)) != 0) {
+ cpu--;
+ CPU_CLR(cpu, &cpus);
+ CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
+ ipi_send_cpu(cpu, ipi);
+ }
+}
+
+/*
+ * send an IPI to a specific CPU.
+ */
+void
+ipi_cpu(int cpu, u_int ipi)
+{
+
+ /*
+ * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
+ * of help in order to understand what is the source.
+ * Set the mask of receiving CPUs for this purpose.
+ */
+ if (ipi == IPI_STOP_HARD)
+ CPU_SET_ATOMIC(cpu, &ipi_nmi_pending);
+
+ CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
+ ipi_send_cpu(cpu, ipi);
+}
+
+/*
+ * send an IPI to all CPUs EXCEPT myself
+ */
+void
+ipi_all_but_self(u_int ipi)
+{
+ cpuset_t other_cpus;
+
+ other_cpus = all_cpus;
+ CPU_CLR(PCPU_GET(cpuid), &other_cpus);
+ if (IPI_IS_BITMAPED(ipi)) {
+ ipi_selected(other_cpus, ipi);
+ return;
+ }
+
+ /*
+ * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
+ * of help in order to understand what is the source.
+ * Set the mask of receiving CPUs for this purpose.
+ */
+ if (ipi == IPI_STOP_HARD)
+ CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus);
+
+ CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+ lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
+}
+
+int
+ipi_nmi_handler()
+{
+ u_int cpuid;
+
+ /*
+ * As long as there is not a simple way to know about a NMI's
+ * source, if the bitmask for the current CPU is present in
+ * the global pending bitword an IPI_STOP_HARD has been issued
+ * and should be handled.
+ */
+ cpuid = PCPU_GET(cpuid);
+ if (!CPU_ISSET(cpuid, &ipi_nmi_pending))
+ return (1);
+
+ CPU_CLR_ATOMIC(cpuid, &ipi_nmi_pending);
+ cpustop_handler();
+ return (0);
+}
+
+/*
+ * Handle an IPI_STOP by saving our current context and spinning until we
+ * are resumed.
+ */
+void
+cpustop_handler(void)
+{
+ u_int cpu;
+
+ cpu = PCPU_GET(cpuid);
+
+ savectx(&stoppcbs[cpu]);
+
+ /* Indicate that we are stopped */
+ CPU_SET_ATOMIC(cpu, &stopped_cpus);
+
+ /* Wait for restart */
+ while (!CPU_ISSET(cpu, &started_cpus))
+ ia32_pause();
+
+ CPU_CLR_ATOMIC(cpu, &started_cpus);
+ CPU_CLR_ATOMIC(cpu, &stopped_cpus);
+
+#if defined(__amd64__) && defined(DDB)
+ amd64_db_resume_dbreg();
+#endif
+
+ if (cpu == 0 && cpustop_restartfunc != NULL) {
+ cpustop_restartfunc();
+ cpustop_restartfunc = NULL;
+ }
+}
+
+/*
+ * Handle an IPI_SUSPEND by saving our current context and spinning until we
+ * are resumed.
+ */
+void
+cpususpend_handler(void)
+{
+ u_int cpu;
+
+ mtx_assert(&smp_ipi_mtx, MA_NOTOWNED);
+
+ cpu = PCPU_GET(cpuid);
+ if (savectx(&susppcbs[cpu]->sp_pcb)) {
+#ifdef __amd64__
+ fpususpend(susppcbs[cpu]->sp_fpususpend);
+#else
+ npxsuspend(susppcbs[cpu]->sp_fpususpend);
+#endif
+ wbinvd();
+ CPU_SET_ATOMIC(cpu, &suspended_cpus);
+ } else {
+#ifdef __amd64__
+ fpuresume(susppcbs[cpu]->sp_fpususpend);
+#else
+ npxresume(susppcbs[cpu]->sp_fpususpend);
+#endif
+ pmap_init_pat();
+ initializecpu();
+ PCPU_SET(switchtime, 0);
+ PCPU_SET(switchticks, ticks);
+
+ /* Indicate that we are resumed */
+ CPU_CLR_ATOMIC(cpu, &suspended_cpus);
+ }
+
+ /* Wait for resume */
+ while (!CPU_ISSET(cpu, &started_cpus))
+ ia32_pause();
+
+ if (cpu_ops.cpu_resume)
+ cpu_ops.cpu_resume();
+#ifdef __amd64__
+ if (vmm_resume_p)
+ vmm_resume_p();
+#endif
+
+ /* Resume MCA and local APIC */
+ lapic_xapic_mode();
+ mca_resume();
+ lapic_setup(0);
+
+ /* Indicate that we are resumed */
+ CPU_CLR_ATOMIC(cpu, &suspended_cpus);
+ CPU_CLR_ATOMIC(cpu, &started_cpus);
+}
+
+
+void
+invlcache_handler(void)
+{
+#ifdef COUNT_IPIS
+ (*ipi_invlcache_counts[PCPU_GET(cpuid)])++;
+#endif /* COUNT_IPIS */
+
+ wbinvd();
+ atomic_add_int(&smp_tlb_wait, 1);
+}
+
+/*
+ * This is called once the rest of the system is up and running and we're
+ * ready to let the AP's out of the pen.
+ */
+static void
+release_aps(void *dummy __unused)
+{
+
+ if (mp_ncpus == 1)
+ return;
+ atomic_store_rel_int(&aps_ready, 1);
+ while (smp_started == 0)
+ ia32_pause();
+}
+SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
+
+#ifdef COUNT_IPIS
+/*
+ * Setup interrupt counters for IPI handlers.
+ */
+static void
+mp_ipi_intrcnt(void *dummy)
+{
+ char buf[64];
+ int i;
+
+ CPU_FOREACH(i) {
+ snprintf(buf, sizeof(buf), "cpu%d:invltlb", i);
+ intrcnt_add(buf, &ipi_invltlb_counts[i]);
+ snprintf(buf, sizeof(buf), "cpu%d:invlrng", i);
+ intrcnt_add(buf, &ipi_invlrng_counts[i]);
+ snprintf(buf, sizeof(buf), "cpu%d:invlpg", i);
+ intrcnt_add(buf, &ipi_invlpg_counts[i]);
+ snprintf(buf, sizeof(buf), "cpu%d:invlcache", i);
+ intrcnt_add(buf, &ipi_invlcache_counts[i]);
+ snprintf(buf, sizeof(buf), "cpu%d:preempt", i);
+ intrcnt_add(buf, &ipi_preempt_counts[i]);
+ snprintf(buf, sizeof(buf), "cpu%d:ast", i);
+ intrcnt_add(buf, &ipi_ast_counts[i]);
+ snprintf(buf, sizeof(buf), "cpu%d:rendezvous", i);
+ intrcnt_add(buf, &ipi_rendezvous_counts[i]);
+ snprintf(buf, sizeof(buf), "cpu%d:hardclock", i);
+ intrcnt_add(buf, &ipi_hardclock_counts[i]);
+ }
+}
+SYSINIT(mp_ipi_intrcnt, SI_SUB_INTR, SI_ORDER_MIDDLE, mp_ipi_intrcnt, NULL);
+#endif
diff --git a/sys/x86/xen/xen_apic.c b/sys/x86/xen/xen_apic.c
index 8e83184..c742920 100644
--- a/sys/x86/xen/xen_apic.c
+++ b/sys/x86/xen/xen_apic.c
@@ -68,9 +68,6 @@ static driver_filter_t xen_invltlb;
static driver_filter_t xen_invlpg;
static driver_filter_t xen_invlrng;
static driver_filter_t xen_invlcache;
-#ifdef __i386__
-static driver_filter_t xen_lazypmap;
-#endif
static driver_filter_t xen_ipi_bitmap_handler;
static driver_filter_t xen_cpustop_handler;
static driver_filter_t xen_cpususpend_handler;
@@ -79,9 +76,6 @@ static driver_filter_t xen_cpustophard_handler;
/*---------------------------- Extern Declarations ---------------------------*/
/* Variables used by mp_machdep to perform the MMU related IPIs */
-#ifdef __i386__
-extern void pmap_lazyfix_action(void);
-#endif
#ifdef __amd64__
extern int pmap_pcid_enabled;
#endif
@@ -104,9 +98,6 @@ static struct xen_ipi_handler xen_ipis[] =
[IPI_TO_IDX(IPI_INVLPG)] = { xen_invlpg, "ipg" },
[IPI_TO_IDX(IPI_INVLRNG)] = { xen_invlrng, "irg" },
[IPI_TO_IDX(IPI_INVLCACHE)] = { xen_invlcache, "ic" },
-#ifdef __i386__
- [IPI_TO_IDX(IPI_LAZYPMAP)] = { xen_lazypmap, "lp" },
-#endif
[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler, "b" },
[IPI_TO_IDX(IPI_STOP)] = { xen_cpustop_handler, "st" },
[IPI_TO_IDX(IPI_SUSPEND)] = { xen_cpususpend_handler, "sp" },
@@ -474,16 +465,6 @@ xen_invlcache(void *arg)
return (FILTER_HANDLED);
}
-#ifdef __i386__
-static int
-xen_lazypmap(void *arg)
-{
-
- pmap_lazyfix_action();
- return (FILTER_HANDLED);
-}
-#endif
-
static int
xen_cpustop_handler(void *arg)
{
diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c
index 64979b1..3bc4b43 100644
--- a/sys/x86/xen/xen_intr.c
+++ b/sys/x86/xen/xen_intr.c
@@ -1,7 +1,7 @@
/******************************************************************************
* xen_intr.c
*
- * Xen event and interrupt services for x86 PV and HVM guests.
+ * Xen event and interrupt services for x86 HVM guests.
*
* Copyright (c) 2002-2005, K A Fraser
* Copyright (c) 2005, Intel Corporation <xiaofeng.ling@intel.com>
@@ -864,10 +864,8 @@ xen_intr_assign_cpu(struct intsrc *base_isrc, u_int apic_id)
u_int to_cpu, vcpu_id;
int error, masked;
-#ifdef XENHVM
if (xen_vector_callback_enabled == 0)
return (EOPNOTSUPP);
-#endif
to_cpu = apic_cpuid(apic_id);
vcpu_id = pcpu_find(to_cpu)->pc_vcpu_id;
diff --git a/sys/x86/xen/xen_nexus.c b/sys/x86/xen/xen_nexus.c
index f25f970..73506fc 100644
--- a/sys/x86/xen/xen_nexus.c
+++ b/sys/x86/xen/xen_nexus.c
@@ -66,14 +66,11 @@ static int
nexus_xen_attach(device_t dev)
{
int error;
-#ifndef XEN
device_t acpi_dev = NULL;
-#endif
nexus_init_resources();
bus_generic_probe(dev);
-#ifndef XEN
if (xen_initial_domain()) {
/* Disable some ACPI devices that are not usable by Dom0 */
acpi_cpu_disabled = true;
@@ -84,13 +81,10 @@ nexus_xen_attach(device_t dev)
if (acpi_dev == NULL)
panic("Unable to add ACPI bus to Xen Dom0");
}
-#endif
error = bus_generic_attach(dev);
-#ifndef XEN
if (xen_initial_domain() && (error == 0))
acpi_install_wakeup_handler(device_get_softc(acpi_dev));
-#endif
return (error);
}
diff --git a/tests/freebsd_test_suite/macros.h b/tests/freebsd_test_suite/macros.h
new file mode 100644
index 0000000..8d95f05
--- /dev/null
+++ b/tests/freebsd_test_suite/macros.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2015 EMC / Isilon Storage Division
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FREEBSD_TEST_MACROS_H_
+#define _FREEBSD_TEST_MACROS_H_
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#define ATF_REQUIRE_KERNEL_MODULE(_mod_name) do { \
+ if (modfind(_mod_name) == -1) { \
+ atf_tc_skip("module %s could not be resolved: %s", \
+ _mod_name, strerror(errno)); \
+ } \
+} while(0)
+
+#define PLAIN_REQUIRE_KERNEL_MODULE(_mod_name, _exit_code) do { \
+ if (modfind(_mod_name) == -1) { \
+ printf("module %s could not be resolved: %s\n", \
+ _mod_name, strerror(errno)); \
+ _exit(_exit_code); \
+ } \
+} while(0)
+
+#endif
diff --git a/tests/sys/Makefile b/tests/sys/Makefile
index 9225eab..066c918 100644
--- a/tests/sys/Makefile
+++ b/tests/sys/Makefile
@@ -4,9 +4,15 @@
TESTSDIR= ${TESTSBASE}/sys
+TESTS_SUBDIRS+= aio
+TESTS_SUBDIRS+= fifo
+TESTS_SUBDIRS+= file
TESTS_SUBDIRS+= kern
+TESTS_SUBDIRS+= kqueue
+TESTS_SUBDIRS+= mqueue
TESTS_SUBDIRS+= netinet
TESTS_SUBDIRS+= opencrypto
+TESTS_SUBDIRS+= vm
# Items not integrated into kyua runs by default
SUBDIR+= pjdfstest
diff --git a/tests/sys/aio/Makefile b/tests/sys/aio/Makefile
new file mode 100644
index 0000000..851252d
--- /dev/null
+++ b/tests/sys/aio/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/aio
+
+PLAIN_TESTS_C+= aio_kqueue_test
+PLAIN_TESTS_C+= lio_kqueue_test
+ATF_TESTS_C+= aio_test
+
+DPADD.aio_test+= ${LIBUTIL}
+LDADD.aio_test+= -lutil
+
+CFLAGS+= -I${.CURDIR:H:H}
+
+WARNS?= 6
+
+.include <bsd.test.mk>
diff --git a/tools/regression/aio/kqueue/aio_kqueue.c b/tests/sys/aio/aio_kqueue_test.c
index 87b4125..14e4729 100644
--- a/tools/regression/aio/kqueue/aio_kqueue.c
+++ b/tests/sys/aio/aio_kqueue_test.c
@@ -46,25 +46,29 @@
#include <string.h>
#include <unistd.h>
-#define PATH_TEMPLATE "/tmp/aio.XXXXXXXXXX"
+#include "freebsd_test_suite/macros.h"
-#define MAX 128
+#define PATH_TEMPLATE "aio.XXXXXXXXXX"
+
+#define MAX_IOCBS 128
#define MAX_RUNS 300
/* #define DEBUG */
int
main (int argc, char *argv[])
{
- int fd;
- struct aiocb *iocb[MAX], *kq_iocb;
- int i, result, run, error, j;
- char buffer[32768];
- int kq = kqueue();
+ struct aiocb *iocb[MAX_IOCBS], *kq_iocb;
+ char *file, pathname[sizeof(PATH_TEMPLATE)+1];
struct kevent ke, kq_returned;
struct timespec ts;
- int cancel, pending, tmp_file = 0, failed = 0;
- char *file, pathname[sizeof(PATH_TEMPLATE)+1];
+ char buffer[32768];
+ int cancel, error, failed = 0, fd, kq, pending, result, run;
+ int tmp_file = 0;
+ unsigned i, j;
+
+ PLAIN_REQUIRE_KERNEL_MODULE("aio", 0);
+ kq = kqueue();
if (kq < 0) {
perror("No kqeueue\n");
exit(1);
@@ -86,7 +90,7 @@ main (int argc, char *argv[])
#ifdef DEBUG
printf("Run %d\n", run);
#endif
- for (i = 0; i < MAX; i++) {
+ for (i = 0; i < nitems(iocb); i++) {
iocb[i] = (struct aiocb *)calloc(1,
sizeof(struct aiocb));
if (iocb[i] == NULL)
@@ -94,7 +98,7 @@ main (int argc, char *argv[])
}
pending = 0;
- for (i = 0; i < MAX; i++) {
+ for (i = 0; i < nitems(iocb); i++) {
pending++;
iocb[i]->aio_nbytes = sizeof(buffer);
iocb[i]->aio_buf = buffer;
@@ -129,8 +133,8 @@ main (int argc, char *argv[])
}
}
}
- cancel = MAX - pending;
-
+ cancel = nitems(iocb) - pending;
+
i = 0;
while (pending) {
@@ -159,11 +163,11 @@ main (int argc, char *argv[])
break;
#ifdef DEBUG
printf("Try again left %d out of %d %d\n",
- pending, MAX, cancel);
+ pending, nitems(iocb), cancel);
#endif
}
- for (j = 0; j < MAX && iocb[j] != kq_iocb;
+ for (j = 0; j < nitems(iocb) && iocb[j] != kq_iocb;
j++) ;
#ifdef DEBUG
printf("kq_iocb %p\n", kq_iocb);
@@ -190,7 +194,7 @@ main (int argc, char *argv[])
i++;
}
- for (i = 0; i < MAX; i++)
+ for (i = 0; i < nitems(iocb); i++)
free(iocb[i]);
}
diff --git a/tools/regression/aio/aiotest/aiotest.c b/tests/sys/aio/aio_test.c
index 6a3d612..4134e78 100644
--- a/tools/regression/aio/aiotest/aiotest.c
+++ b/tests/sys/aio/aio_test.c
@@ -57,7 +57,11 @@
#include <termios.h>
#include <unistd.h>
-#define PATH_TEMPLATE "/tmp/aio.XXXXXXXXXX"
+#include <atf-c.h>
+
+#include "freebsd_test_suite/macros.h"
+
+#define PATH_TEMPLATE "aio.XXXXXXXXXX"
/*
* GLOBAL_MAX sets the largest usable buffer size to be read and written, as
@@ -69,7 +73,6 @@
#define BUFFER_MAX GLOBAL_MAX
struct aio_context {
- const char *ac_test;
int ac_read_fd, ac_write_fd;
long ac_seed;
char ac_buffer[GLOBAL_MAX];
@@ -81,16 +84,6 @@ struct aio_context {
static int aio_timedout;
-static void
-aio_available(void)
-{
-
- if (modfind("aio") == -1)
- errx(0,
- "aio support not available in the kernel; skipping "
- "testcases");
-}
-
/*
* Each test run specifies a timeout in seconds. Use the somewhat obsoleted
* signal(3) and alarm(3) APIs to set this up.
@@ -103,23 +96,21 @@ aio_timeout_signal(int sig __unused)
}
static void
-aio_timeout_start(const char *string1, const char *string2, int seconds)
+aio_timeout_start(int seconds)
{
aio_timedout = 0;
- if (signal(SIGALRM, aio_timeout_signal) == SIG_ERR)
- errx(1, "FAIL: %s: %s: aio_timeout_set: signal(SIGALRM): %s",
- string1, string2, strerror(errno));
+ ATF_REQUIRE_MSG(signal(SIGALRM, aio_timeout_signal) != SIG_ERR,
+ "failed to set SIGALRM handler: %s", strerror(errno));
alarm(seconds);
}
static void
-aio_timeout_stop(const char *string1, const char *string2)
+aio_timeout_stop(void)
{
- if (signal(SIGALRM, NULL) == SIG_ERR)
- errx(1, "FAIL: %s: %s: aio_timeout_stop: signal(NULL): %s",
- string1, string2, strerror(errno));
+ ATF_REQUIRE_MSG(signal(SIGALRM, NULL) != SIG_ERR,
+ "failed to reset SIGALRM handler to default: %s", strerror(errno));
alarm(0);
}
@@ -164,25 +155,23 @@ aio_test_buffer(char *buffer, int len, long seed)
* test setup.
*/
static void
-aio_context_init(struct aio_context *ac, const char *test, int read_fd,
+aio_context_init(struct aio_context *ac, int read_fd,
int write_fd, int buflen, int seconds, void (*cleanup)(void *),
void *cleanup_arg)
{
- if (buflen > BUFFER_MAX)
- errx(1, "FAIL: %s: aio_context_init: buffer too large",
- test);
+ ATF_REQUIRE_MSG(buflen <= BUFFER_MAX,
+ "aio_context_init: buffer too large (%d > %d)",
+ buflen, BUFFER_MAX);
bzero(ac, sizeof(*ac));
- ac->ac_test = test;
ac->ac_read_fd = read_fd;
ac->ac_write_fd = write_fd;
ac->ac_buflen = buflen;
srandomdev();
ac->ac_seed = random();
aio_fill_buffer(ac->ac_buffer, buflen, ac->ac_seed);
- if (aio_test_buffer(ac->ac_buffer, buflen, ac->ac_seed) == 0)
- errx(1, "%s: aio_context_init: aio_test_buffer: internal "
- "error", test);
+ ATF_REQUIRE_MSG(aio_test_buffer(ac->ac_buffer, buflen,
+ ac->ac_seed) != 0, "aio_test_buffer: internal error");
ac->ac_seconds = seconds;
ac->ac_cleanup = cleanup;
ac->ac_cleanup_arg = cleanup_arg;
@@ -215,7 +204,7 @@ aio_write_test(struct aio_context *ac)
struct aiocb aio, *aiop;
ssize_t len;
- aio_available();
+ ATF_REQUIRE_KERNEL_MODULE("aio");
bzero(&aio, sizeof(aio));
aio.aio_buf = ac->ac_buffer;
@@ -223,19 +212,17 @@ aio_write_test(struct aio_context *ac)
aio.aio_fildes = ac->ac_write_fd;
aio.aio_offset = 0;
- aio_timeout_start(ac->ac_test, "aio_write_test", ac->ac_seconds);
+ aio_timeout_start(ac->ac_seconds);
if (aio_write(&aio) < 0) {
if (errno == EINTR) {
if (aio_timedout) {
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_write_test: "
- "aio_write: timed out", ac->ac_test);
+ atf_tc_fail("aio_write timed out");
}
}
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_write_test: aio_write: %s",
- ac->ac_test, strerror(errno));
+ atf_tc_fail("aio_write failed: %s", strerror(errno));
}
len = aio_waitcomplete(&aiop, NULL);
@@ -243,22 +230,19 @@ aio_write_test(struct aio_context *ac)
if (errno == EINTR) {
if (aio_timedout) {
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_write_test: "
- "aio_waitcomplete: timed out",
- ac->ac_test);
+ atf_tc_fail("aio_waitcomplete timed out");
}
}
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_write_test: aio_waitcomplete: %s",
- ac->ac_test, strerror(errno));
+ atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno));
}
- aio_timeout_stop(ac->ac_test, "aio_write_test");
+ aio_timeout_stop();
if (len != ac->ac_buflen) {
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_write_test: aio_waitcomplete: short "
- "write (%jd)", ac->ac_test, (intmax_t)len);
+ atf_tc_fail("aio_waitcomplete short write (%jd)",
+ (intmax_t)len);
}
}
@@ -272,7 +256,7 @@ aio_read_test(struct aio_context *ac)
struct aiocb aio, *aiop;
ssize_t len;
- aio_available();
+ ATF_REQUIRE_KERNEL_MODULE("aio");
bzero(ac->ac_buffer, ac->ac_buflen);
bzero(&aio, sizeof(aio));
@@ -281,19 +265,17 @@ aio_read_test(struct aio_context *ac)
aio.aio_fildes = ac->ac_read_fd;
aio.aio_offset = 0;
- aio_timeout_start(ac->ac_test, "aio_read_test", ac->ac_seconds);
+ aio_timeout_start(ac->ac_seconds);
if (aio_read(&aio) < 0) {
if (errno == EINTR) {
if (aio_timedout) {
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_read_test: "
- "aio_read: timed out", ac->ac_test);
+ atf_tc_fail("aio_write timed out");
}
}
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_read_test: aio_read %s", ac->ac_test,
- strerror(errno));
+ atf_tc_fail("aio_read failed: %s", strerror(errno));
}
len = aio_waitcomplete(&aiop, NULL);
@@ -301,28 +283,24 @@ aio_read_test(struct aio_context *ac)
if (errno == EINTR) {
if (aio_timedout) {
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_read_test: "
- "aio_waitcomplete: timed out",
- ac->ac_test);
+ atf_tc_fail("aio_waitcomplete timed out");
}
}
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_read_test: aio_waitcomplete: %s",
- ac->ac_test, strerror(errno));
+ atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno));
}
- aio_timeout_stop(ac->ac_test, "aio_read_test");
+ aio_timeout_stop();
if (len != ac->ac_buflen) {
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_read_test: aio_waitcomplete: short "
- "read (%jd)", ac->ac_test, (intmax_t)len);
+ atf_tc_fail("aio_waitcomplete short read (%jd)",
+ (intmax_t)len);
}
if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0) {
aio_cleanup(ac);
- errx(1, "FAIL: %s: aio_read_test: buffer mismatch",
- ac->ac_test);
+ atf_tc_fail("buffer mismatched");
}
}
@@ -353,33 +331,29 @@ aio_file_cleanup(void *arg)
#define FILE_LEN GLOBAL_MAX
#define FILE_TIMEOUT 30
-static void
-aio_file_test(void)
+ATF_TC_WITHOUT_HEAD(aio_file_test);
+ATF_TC_BODY(aio_file_test, tc)
{
char pathname[PATH_MAX];
struct aio_file_arg arg;
struct aio_context ac;
int fd;
- aio_available();
+ ATF_REQUIRE_KERNEL_MODULE("aio");
strcpy(pathname, PATH_TEMPLATE);
fd = mkstemp(pathname);
- if (fd == -1)
- errx(1, "FAIL: aio_file_test: mkstemp: %s",
- strerror(errno));
+ ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno));
arg.afa_fd = fd;
arg.afa_pathname = pathname;
- aio_context_init(&ac, "aio_file_test", fd, fd, FILE_LEN,
+ aio_context_init(&ac, fd, fd, FILE_LEN,
FILE_TIMEOUT, aio_file_cleanup, &arg);
aio_write_test(&ac);
aio_read_test(&ac);
aio_file_cleanup(&arg);
-
- fprintf(stderr, "PASS: aio_file_test\n");
}
struct aio_fifo_arg {
@@ -403,15 +377,15 @@ aio_fifo_cleanup(void *arg)
#define FIFO_LEN 256
#define FIFO_TIMEOUT 30
-static void
-aio_fifo_test(void)
+ATF_TC_WITHOUT_HEAD(aio_fifo_test);
+ATF_TC_BODY(aio_fifo_test, tc)
{
int error, read_fd = -1, write_fd = -1;
struct aio_fifo_arg arg;
char pathname[PATH_MAX];
struct aio_context ac;
- aio_available();
+ ATF_REQUIRE_KERNEL_MODULE("aio");
/*
* In theory, mkstemp() can return a name that is then collided with.
@@ -419,12 +393,12 @@ aio_fifo_test(void)
* rather than retrying.
*/
strcpy(pathname, PATH_TEMPLATE);
- if (mkstemp(pathname) == -1)
- err(1, "FAIL: aio_fifo_test: mkstemp failed");
- if (unlink(pathname) == -1)
- err(1, "FAIL: aio_fifo_test: unlink failed");
- if (mkfifo(pathname, 0600) == -1)
- errx(1, "FAIL: aio_fifo_test: mkfifo: %s", strerror(errno));
+ ATF_REQUIRE_MSG(mkstemp(pathname) != -1,
+ "mkstemp failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(unlink(pathname) == 0,
+ "unlink failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(mkfifo(pathname, 0600) != -1,
+ "mkfifo failed: %s", strerror(errno));
arg.afa_pathname = pathname;
arg.afa_read_fd = -1;
arg.afa_write_fd = -1;
@@ -434,7 +408,7 @@ aio_fifo_test(void)
error = errno;
aio_fifo_cleanup(&arg);
errno = error;
- errx(1, "FAIL: aio_fifo_test: read_fd open: %s",
+ atf_tc_fail("read_fd open failed: %s",
strerror(errno));
}
arg.afa_read_fd = read_fd;
@@ -444,19 +418,17 @@ aio_fifo_test(void)
error = errno;
aio_fifo_cleanup(&arg);
errno = error;
- errx(1, "FAIL: aio_fifo_test: write_fd open: %s",
+ atf_tc_fail("write_fd open failed: %s",
strerror(errno));
}
arg.afa_write_fd = write_fd;
- aio_context_init(&ac, "aio_fifo_test", read_fd, write_fd, FIFO_LEN,
+ aio_context_init(&ac, read_fd, write_fd, FIFO_LEN,
FIFO_TIMEOUT, aio_fifo_cleanup, &arg);
aio_write_test(&ac);
aio_read_test(&ac);
aio_fifo_cleanup(&arg);
-
- fprintf(stderr, "PASS: aio_fifo_test\n");
}
struct aio_unix_socketpair_arg {
@@ -475,30 +447,27 @@ aio_unix_socketpair_cleanup(void *arg)
#define UNIX_SOCKETPAIR_LEN 256
#define UNIX_SOCKETPAIR_TIMEOUT 30
-static void
-aio_unix_socketpair_test(void)
+ATF_TC_WITHOUT_HEAD(aio_unix_socketpair_test);
+ATF_TC_BODY(aio_unix_socketpair_test, tc)
{
struct aio_unix_socketpair_arg arg;
struct aio_context ac;
int sockets[2];
- aio_available();
+ ATF_REQUIRE_KERNEL_MODULE("aio");
- if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) < 0)
- errx(1, "FAIL: aio_socketpair_test: socketpair: %s",
- strerror(errno));
+ ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) != -1,
+ "socketpair failed: %s", strerror(errno));
arg.asa_sockets[0] = sockets[0];
arg.asa_sockets[1] = sockets[1];
- aio_context_init(&ac, "aio_unix_socketpair_test", sockets[0],
+ aio_context_init(&ac, sockets[0],
sockets[1], UNIX_SOCKETPAIR_LEN, UNIX_SOCKETPAIR_TIMEOUT,
aio_unix_socketpair_cleanup, &arg);
aio_write_test(&ac);
aio_read_test(&ac);
aio_unix_socketpair_cleanup(&arg);
-
- fprintf(stderr, "PASS: aio_unix_socketpair_test\n");
}
struct aio_pty_arg {
@@ -518,8 +487,8 @@ aio_pty_cleanup(void *arg)
#define PTY_LEN 256
#define PTY_TIMEOUT 30
-static void
-aio_pty_test(void)
+ATF_TC_WITHOUT_HEAD(aio_pty_test);
+ATF_TC_BODY(aio_pty_test, tc)
{
struct aio_pty_arg arg;
struct aio_context ac;
@@ -527,10 +496,10 @@ aio_pty_test(void)
struct termios ts;
int error;
- aio_available();
+ ATF_REQUIRE_KERNEL_MODULE("aio");
- if (openpty(&read_fd, &write_fd, NULL, NULL, NULL) < 0)
- errx(1, "FAIL: aio_pty_test: openpty: %s", strerror(errno));
+ ATF_REQUIRE_MSG(openpty(&read_fd, &write_fd, NULL, NULL, NULL) == 0,
+ "openpty failed: %s", strerror(errno));
arg.apa_read_fd = read_fd;
arg.apa_write_fd = write_fd;
@@ -539,26 +508,22 @@ aio_pty_test(void)
error = errno;
aio_pty_cleanup(&arg);
errno = error;
- errx(1, "FAIL: aio_pty_test: tcgetattr: %s",
- strerror(errno));
+ atf_tc_fail("tcgetattr failed: %s", strerror(errno));
}
cfmakeraw(&ts);
if (tcsetattr(write_fd, TCSANOW, &ts) < 0) {
error = errno;
aio_pty_cleanup(&arg);
errno = error;
- errx(1, "FAIL: aio_pty_test: tcsetattr: %s",
- strerror(errno));
+ atf_tc_fail("tcsetattr failed: %s", strerror(errno));
}
-
- aio_context_init(&ac, "aio_pty_test", read_fd, write_fd, PTY_LEN,
+ aio_context_init(&ac, read_fd, write_fd, PTY_LEN,
PTY_TIMEOUT, aio_pty_cleanup, &arg);
+
aio_write_test(&ac);
aio_read_test(&ac);
aio_pty_cleanup(&arg);
-
- fprintf(stderr, "PASS: aio_pty_test\n");
}
static void
@@ -572,25 +537,23 @@ aio_pipe_cleanup(void *arg)
#define PIPE_LEN 256
#define PIPE_TIMEOUT 30
-static void
-aio_pipe_test(void)
-{
+ATF_TC_WITHOUT_HEAD(aio_pipe_test);
+ATF_TC_BODY(aio_pipe_test, tc)
+{
struct aio_context ac;
int pipes[2];
- aio_available();
+ ATF_REQUIRE_KERNEL_MODULE("aio");
- if (pipe(pipes) < 0)
- errx(1, "FAIL: aio_pipe_test: pipe: %s", strerror(errno));
+ ATF_REQUIRE_MSG(pipe(pipes) != -1,
+ "pipe failed: %s", strerror(errno));
- aio_context_init(&ac, "aio_file_test", pipes[0], pipes[1], PIPE_LEN,
+ aio_context_init(&ac, pipes[0], pipes[1], PIPE_LEN,
PIPE_TIMEOUT, aio_pipe_cleanup, pipes);
aio_write_test(&ac);
aio_read_test(&ac);
aio_pipe_cleanup(pipes);
-
- fprintf(stderr, "PASS: aio_pipe_test\n");
}
struct aio_md_arg {
@@ -615,11 +578,11 @@ aio_md_cleanup(void *arg)
bzero(&mdio, sizeof(mdio));
mdio.md_version = MDIOVERSION;
mdio.md_unit = ama->ama_unit;
- if (ioctl(ama->ama_mdctl_fd, MDIOCDETACH, &mdio) < 0) {
+ if (ioctl(ama->ama_mdctl_fd, MDIOCDETACH, &mdio) == -1) {
error = errno;
close(ama->ama_mdctl_fd);
errno = error;
- warnx("FAIL: aio_md_test: MDIOCDETACH: %s",
+ atf_tc_fail("ioctl MDIOCDETACH failed: %s",
strerror(errno));
}
}
@@ -629,8 +592,13 @@ aio_md_cleanup(void *arg)
#define MD_LEN GLOBAL_MAX
#define MD_TIMEOUT 30
-static void
-aio_md_test(void)
+ATF_TC(aio_md_test);
+ATF_TC_HEAD(aio_md_test, tc)
+{
+
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(aio_md_test, tc)
{
int error, fd, mdctl_fd, unit;
char pathname[PATH_MAX];
@@ -638,18 +606,11 @@ aio_md_test(void)
struct aio_context ac;
struct md_ioctl mdio;
- aio_available();
-
- if (geteuid() != 0) {
- fprintf(stderr, "WARNING: aio_md_test: skipped as euid "
- "!= 0\n");
- return;
- }
+ ATF_REQUIRE_KERNEL_MODULE("aio");
mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0);
- if (mdctl_fd < 0)
- errx(1, "FAIL: aio_md_test: open(/dev/%s): %s", MDCTL_NAME,
- strerror(errno));
+ ATF_REQUIRE_MSG(mdctl_fd != -1,
+ "opening /dev/%s failed: %s", MDCTL_NAME, strerror(errno));
bzero(&mdio, sizeof(mdio));
mdio.md_version = MDIOVERSION;
@@ -665,42 +626,33 @@ aio_md_test(void)
error = errno;
aio_md_cleanup(&arg);
errno = error;
- errx(1, "FAIL: aio_md_test: MDIOCATTACH: %s",
- strerror(errno));
+ atf_tc_fail("ioctl MDIOCATTACH failed: %s", strerror(errno));
}
arg.ama_unit = unit = mdio.md_unit;
snprintf(pathname, PATH_MAX, "/dev/md%d", unit);
fd = open(pathname, O_RDWR);
- if (fd < 0) {
- error = errno;
- aio_md_cleanup(&arg);
- errno = error;
- errx(1, "FAIL: aio_md_test: open(%s): %s", pathname,
- strerror(errno));
- }
+ ATF_REQUIRE_MSG(fd != -1,
+ "opening %s failed: %s", pathname, strerror(errno));
arg.ama_fd = fd;
- aio_context_init(&ac, "aio_md_test", fd, fd, MD_LEN, MD_TIMEOUT,
+ aio_context_init(&ac, fd, fd, MD_LEN, MD_TIMEOUT,
aio_md_cleanup, &arg);
aio_write_test(&ac);
aio_read_test(&ac);
aio_md_cleanup(&arg);
-
- fprintf(stderr, "PASS: aio_md_test\n");
}
-int
-main(void)
+ATF_TP_ADD_TCS(tp)
{
- aio_file_test();
- aio_fifo_test();
- aio_unix_socketpair_test();
- aio_pty_test();
- aio_pipe_test();
- aio_md_test();
+ ATF_TP_ADD_TC(tp, aio_file_test);
+ ATF_TP_ADD_TC(tp, aio_fifo_test);
+ ATF_TP_ADD_TC(tp, aio_unix_socketpair_test);
+ ATF_TP_ADD_TC(tp, aio_pty_test);
+ ATF_TP_ADD_TC(tp, aio_pipe_test);
+ ATF_TP_ADD_TC(tp, aio_md_test);
- return (0);
+ return (atf_no_error());
}
diff --git a/tools/regression/aio/kqueue/lio/lio_kqueue.c b/tests/sys/aio/lio_kqueue_test.c
index ad7fc68..5cc87b3 100644
--- a/tools/regression/aio/kqueue/lio/lio_kqueue.c
+++ b/tests/sys/aio/lio_kqueue_test.c
@@ -48,16 +48,18 @@
#include <string.h>
#include <unistd.h>
-#define PATH_TEMPLATE "/tmp/aio.XXXXXXXXXX"
+#include "freebsd_test_suite/macros.h"
+
+#define PATH_TEMPLATE "aio.XXXXXXXXXX"
#define LIO_MAX 5
-#define MAX LIO_MAX * 16
+#define MAX_IOCBS LIO_MAX * 16
#define MAX_RUNS 300
int
main(int argc, char *argv[]){
int fd;
- struct aiocb *iocb[MAX];
+ struct aiocb *iocb[MAX_IOCBS];
struct aiocb **lio[LIO_MAX], **lio_element, **kq_lio;
int i, result, run, error, j, k;
char buffer[32768];
@@ -69,6 +71,8 @@ main(int argc, char *argv[]){
char *file, pathname[sizeof(PATH_TEMPLATE)-1];
int tmp_file = 0, failed = 0;
+ PLAIN_REQUIRE_KERNEL_MODULE("aio", 0);
+
if (kq < 0) {
perror("No kqeueue\n");
exit(1);
@@ -99,9 +103,9 @@ main(int argc, char *argv[]){
#endif
for (j = 0; j < LIO_MAX; j++) {
lio[j] = (struct aiocb **)
- malloc(sizeof(struct aiocb *) * MAX/LIO_MAX);
- for(i = 0; i < MAX / LIO_MAX; i++) {
- k = (MAX / LIO_MAX * j) + i;
+ malloc(sizeof(struct aiocb *) * MAX_IOCBS/LIO_MAX);
+ for(i = 0; i < MAX_IOCBS / LIO_MAX; i++) {
+ k = (MAX_IOCBS / LIO_MAX * j) + i;
lio_element = lio[j];
lio[j][i] = iocb[k] = (struct aiocb *)
malloc(sizeof(struct aiocb));
@@ -123,7 +127,7 @@ main(int argc, char *argv[]){
sig.sigev_notify = SIGEV_KEVENT;
time(&time1);
result = lio_listio(LIO_NOWAIT, lio[j],
- MAX / LIO_MAX, &sig);
+ MAX_IOCBS / LIO_MAX, &sig);
error = errno;
time(&time2);
#ifdef DEBUG
@@ -203,7 +207,7 @@ main(int argc, char *argv[]){
} else {
printf("PASS: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result);
}
- for(k = 0; k < MAX / LIO_MAX; k++){
+ for(k = 0; k < MAX_IOCBS / LIO_MAX; k++){
result = aio_return(kq_lio[k]);
#ifdef DEBUG
printf("Return Resulto for %d %d is %d\n", j, k, result);
@@ -220,7 +224,7 @@ main(int argc, char *argv[]){
printf("\n");
#endif
- for(k = 0; k < MAX / LIO_MAX; k++) {
+ for(k = 0; k < MAX_IOCBS / LIO_MAX; k++) {
free(lio[j][k]);
}
free(lio[j]);
diff --git a/tests/sys/fifo/Makefile b/tests/sys/fifo/Makefile
new file mode 100644
index 0000000..602bf1e
--- /dev/null
+++ b/tests/sys/fifo/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/fifo
+
+PLAIN_TESTS_C+= fifo_create
+PLAIN_TESTS_C+= fifo_io
+PLAIN_TESTS_C+= fifo_misc
+PLAIN_TESTS_C+= fifo_open
+
+TEST_METADATA.fifo_create+= required_user="root"
+TEST_METADATA.fifo_open+= required_user="root"
+
+.include <bsd.test.mk>
diff --git a/tools/regression/fifo/fifo_create/fifo_create.c b/tests/sys/fifo/fifo_create.c
index 4e8a8a4..2eb01e5 100644
--- a/tools/regression/fifo/fifo_create/fifo_create.c
+++ b/tests/sys/fifo/fifo_create.c
@@ -75,7 +75,7 @@
* All activity occurs within a temporary directory created early in the
* test.
*/
-char temp_dir[PATH_MAX];
+static char temp_dir[PATH_MAX];
static void __unused
atexit_temp_dir(void)
@@ -94,7 +94,7 @@ fifo_create_test(int use_mkfifo)
{
struct stat old_dirsb, dirsb, fifosb;
const char *testname;
- char path[PATH_MAX];
+ char path[] = "testfifo";
int error;
if (use_mkfifo)
@@ -106,14 +106,12 @@ fifo_create_test(int use_mkfifo)
* Sleep to make sure that the time stamp on the directory will be
* updated.
*/
- if (stat(temp_dir, &old_dirsb) < 0)
+ if (stat(".", &old_dirsb) < 0)
err(-1, "basic_create_test: %s: stat: %s", testname,
temp_dir);
sleep(2);
- snprintf(path, PATH_MAX, "%s/testfifo", temp_dir);
-
if (use_mkfifo) {
if (mkfifo(path, 0600) < 0)
err(-1, "basic_create_test: %s: %s", testname, path);
@@ -149,7 +147,7 @@ fifo_create_test(int use_mkfifo)
err(-1, "basic_create_test: dup %s unexpected error",
testname);
- if (stat(temp_dir, &dirsb) < 0) {
+ if (stat(".", &dirsb) < 0) {
error = errno;
(void)unlink(path);
errno = error;
@@ -205,7 +203,7 @@ fifo_permission_test(int use_mkfifo)
{
const struct permission_test *ptp;
mode_t __unused old_umask;
- char path[PATH_MAX];
+ char path[] = "testfifo";
const char *testname;
struct stat sb;
int error, i;
@@ -215,7 +213,6 @@ fifo_permission_test(int use_mkfifo)
else
testname = "mknod";
- snprintf(path, PATH_MAX, "%s/testfifo", temp_dir);
old_umask = umask(0022);
for (i = 0; i < permission_test_count; i++) {
ptp = &permission_test[i];
@@ -256,14 +253,14 @@ fifo_permission_test(int use_mkfifo)
}
int
-main(int argc, char *argv[])
+main(void)
{
int i;
if (geteuid() != 0)
errx(-1, "must be run as root");
- strcpy(temp_dir, "/tmp/fifo_create.XXXXXXXXXXX");
+ strcpy(temp_dir, "fifo_create.XXXXXXXXXXX");
if (mkdtemp(temp_dir) == NULL)
err(-1, "mkdtemp");
atexit(atexit_temp_dir);
diff --git a/tools/regression/fifo/fifo_io/fifo_io.c b/tests/sys/fifo/fifo_io.c
index 4d3c54e..93d4be7 100644
--- a/tools/regression/fifo/fifo_io/fifo_io.c
+++ b/tests/sys/fifo/fifo_io.c
@@ -88,7 +88,7 @@
* All activity occurs within a temporary directory created early in the
* test.
*/
-char temp_dir[PATH_MAX];
+static char temp_dir[PATH_MAX];
static void __unused
atexit_temp_dir(void)
@@ -130,8 +130,7 @@ cleanfifo3(const char *fifoname, int fd1, int fd2, int fd3)
* so using non-blocking opens in order to avoid deadlocking the process.
*/
static int
-openfifo(const char *fifoname, const char *testname, int *reader_fdp,
- int *writer_fdp)
+openfifo(const char *fifoname, int *reader_fdp, int *writer_fdp)
{
int error, fd1, fd2;
@@ -155,7 +154,7 @@ openfifo(const char *fifoname, const char *testname, int *reader_fdp,
* Open one file descriptor for the fifo, supporting both read and write.
*/
static int
-openfifo_rw(const char *fifoname, const char *testname, int *fdp)
+openfifo_rw(const char *fifoname, int *fdp)
{
int fd;
@@ -249,7 +248,7 @@ test_simpleio(void)
ssize_t len;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", "test_simpleio", &reader_fd, &writer_fd)
+ if (openfifo("testfifo", &reader_fd, &writer_fd)
< 0) {
warn("test_simpleio: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
@@ -296,12 +295,12 @@ test_simpleio(void)
cleanfifo2("testfifo", reader_fd, writer_fd);
}
-static int alarm_fired;
+static volatile int alarm_fired;
/*
* Non-destructive SIGALRM handler.
*/
static void
-sigalarm(int signum)
+sigalarm(int signum __unused)
{
alarm_fired = 1;
@@ -408,7 +407,7 @@ test_blocking_read_empty(void)
u_char ch;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
+ if (openfifo("testfifo", &reader_fd, &writer_fd)
< 0) {
warn("test_blocking_read_empty: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
@@ -477,8 +476,7 @@ test_blocking_one_byte(void)
u_char ch;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_blocking: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -544,8 +542,7 @@ test_nonblocking_one_byte(void)
u_char ch;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_nonblocking: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -609,8 +606,7 @@ test_blocking_partial_write(void)
ssize_t len;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_blocking_partial_write: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -668,8 +664,7 @@ test_nonblocking_partial_write(void)
ssize_t len;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_blocking_partial_write: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -736,8 +731,7 @@ test_coalesce_big_read(void)
ssize_t len;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_coalesce_big_read: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -808,8 +802,7 @@ test_coalesce_big_write(void)
ssize_t len;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_coalesce_big_write: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -1078,7 +1071,7 @@ test_events_outofbox(void)
int kqueue_fd, reader_fd, writer_fd;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_events_outofbox: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -1134,8 +1127,7 @@ test_events_write_read_byte(void)
u_char ch;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_events_write_read_byte: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -1227,8 +1219,7 @@ test_events_partial_write(void)
ssize_t len;
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd)
- < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("test_events_partial_write: openfifo: testfifo");
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -1313,8 +1304,7 @@ test_events_rdwr(void)
char ch;
makefifo("testfifo", __func__);
- if (openfifo_rw("testfifo", __func__, &fd)
- < 0) {
+ if (openfifo_rw("testfifo", &fd) < 0) {
warn("%s: openfifo_rw: testfifo", __func__);
cleanfifo2("testfifo", -1, -1);
exit(-1);
@@ -1381,10 +1371,10 @@ test_events_rdwr(void)
}
int
-main(int argc, char *argv[])
+main(void)
{
- strcpy(temp_dir, "/tmp/fifo_io.XXXXXXXXXXX");
+ strcpy(temp_dir, "fifo_io.XXXXXXXXXXX");
if (mkdtemp(temp_dir) == NULL)
err(-1, "mkdtemp");
atexit(atexit_temp_dir);
diff --git a/tools/regression/fifo/fifo_misc/fifo_misc.c b/tests/sys/fifo/fifo_misc.c
index 4215212..888547e 100644
--- a/tools/regression/fifo/fifo_misc/fifo_misc.c
+++ b/tests/sys/fifo/fifo_misc.c
@@ -50,7 +50,7 @@
* All activity occurs within a temporary directory created early in the
* test.
*/
-char temp_dir[PATH_MAX];
+static char temp_dir[PATH_MAX];
static void __unused
atexit_temp_dir(void)
@@ -79,8 +79,7 @@ cleanfifo(const char *fifoname, int fd1, int fd2)
}
static int
-openfifo(const char *fifoname, const char *testname, int *reader_fdp,
- int *writer_fdp)
+openfifo(const char *fifoname, int *reader_fdp, int *writer_fdp)
{
int error, fd1, fd2;
@@ -110,7 +109,7 @@ test_lseek(void)
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("%s: openfifo", __func__);
cleanfifo("testfifo", -1, -1);
exit(-1);
@@ -185,7 +184,7 @@ test_ioctl(void)
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("%s: openfifo", __func__);
cleanfifo("testfifo", -1, -1);
exit(-1);
@@ -237,7 +236,7 @@ test_chmodchown(void)
makefifo("testfifo", __func__);
- if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) {
+ if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
warn("%s: openfifo", __func__);
cleanfifo("testfifo", -1, -1);
exit(-1);
@@ -316,10 +315,10 @@ test_chmodchown(void)
}
int
-main(int argc, char *argv[])
+main(void)
{
- strcpy(temp_dir, "/tmp/fifo_misc.XXXXXXXXXXX");
+ strcpy(temp_dir, "fifo_misc.XXXXXXXXXXX");
if (mkdtemp(temp_dir) == NULL)
err(-1, "mkdtemp");
atexit(atexit_temp_dir);
diff --git a/tools/regression/fifo/fifo_open/fifo_open.c b/tests/sys/fifo/fifo_open.c
index 6899a3a..892f481 100644
--- a/tools/regression/fifo/fifo_open/fifo_open.c
+++ b/tests/sys/fifo/fifo_open.c
@@ -87,7 +87,7 @@
* All activity occurs within a temporary directory created early in the
* test.
*/
-char temp_dir[PATH_MAX];
+static char temp_dir[PATH_MAX];
static void __unused
atexit_temp_dir(void)
@@ -453,13 +453,13 @@ test_non_blocking_writer(void)
}
int
-main(int argc, char *argv[])
+main(void)
{
if (geteuid() != 0)
errx(-1, "must be run as root");
- strcpy(temp_dir, "/tmp/fifo_open.XXXXXXXXXXX");
+ strcpy(temp_dir, "fifo_open.XXXXXXXXXXX");
if (mkdtemp(temp_dir) == NULL)
err(-1, "mkdtemp");
if (chdir(temp_dir) < 0)
diff --git a/tests/sys/file/Makefile b/tests/sys/file/Makefile
new file mode 100644
index 0000000..6151c9f
--- /dev/null
+++ b/tests/sys/file/Makefile
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/file
+
+BINDIR= ${TESTSDIR}
+
+TAP_TESTS_C+= closefrom_test
+TAP_TESTS_C+= dup_test
+TAP_TESTS_C+= fcntlflags_test
+TAP_TESTS_SH+= flock_test
+PLAIN_TESTS_C+= ftruncate_test
+PLAIN_TESTS_C+= newfileops_on_fork_test
+
+PROGS+= flock_helper
+
+DPADD.closefrom_test= ${LIBUTIL}
+LDADD.closefrom_test= -lutil
+
+DPADD.flock_helper= ${LIBPTHREAD}
+LDADD.flock_helper= -lpthread
+
+DPADD.newfileops_on_fork_test= ${LIBPTHREAD}
+LDADD.newfileops_on_fork_test= -lpthread
+
+.include <bsd.test.mk>
diff --git a/tests/sys/file/closefrom_test.c b/tests/sys/file/closefrom_test.c
new file mode 100644
index 0000000..78cfeec
--- /dev/null
+++ b/tests/sys/file/closefrom_test.c
@@ -0,0 +1,275 @@
+/*-
+ * Copyright (c) 2009 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Regression tests for the closefrom(2) system call.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <paths.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct shared_info {
+ int failed;
+ char tag[64];
+ char message[0];
+};
+
+static int test = 1;
+
+static void
+ok(const char *descr)
+{
+
+ printf("ok %d - %s\n", test, descr);
+ test++;
+}
+
+static void
+fail(const char *descr, const char *fmt, ...)
+{
+ va_list ap;
+
+ printf("not ok %d - %s", test, descr);
+ test++;
+ if (fmt) {
+ va_start(ap, fmt);
+ printf(" # ");
+ vprintf(fmt, ap);
+ va_end(ap);
+ }
+ printf("\n");
+ exit(1);
+}
+
+#define fail_err(descr) fail((descr), "%s", strerror(errno))
+
+static void
+cok(struct shared_info *info, const char *descr)
+{
+
+ info->failed = 0;
+ strlcpy(info->tag, descr, sizeof(info->tag));
+ exit(0);
+}
+
+static void
+cfail(struct shared_info *info, const char *descr, const char *fmt, ...)
+{
+ va_list ap;
+
+ info->failed = 1;
+ strlcpy(info->tag, descr, sizeof(info->tag));
+ if (fmt) {
+ va_start(ap, fmt);
+ vsprintf(info->message, fmt, ap);
+ va_end(ap);
+ }
+ exit(0);
+}
+
+#define cfail_err(info, descr) cfail((info), (descr), "%s", strerror(errno))
+
+/*
+ * Use kinfo_getfile() to fetch the list of file descriptors and figure out
+ * the highest open file descriptor.
+ */
+static int
+highest_fd(void)
+{
+ struct kinfo_file *kif;
+ int cnt, i, highest;
+
+ kif = kinfo_getfile(getpid(), &cnt);
+ if (kif == NULL)
+ fail_err("kinfo_getfile");
+ highest = INT_MIN;
+ for (i = 0; i < cnt; i++)
+ if (kif[i].kf_fd > highest)
+ highest = kif[i].kf_fd;
+ free(kif);
+ return (highest);
+}
+
+static int
+devnull(void)
+{
+ int fd;
+
+ fd = open(_PATH_DEVNULL, O_RDONLY);
+ if (fd < 0)
+ fail_err("open(\" "_PATH_DEVNULL" \")");
+ return (fd);
+}
+
+int
+main(void)
+{
+ struct shared_info *info;
+ pid_t pid;
+ int fd, i, start;
+
+ printf("1..15\n");
+
+ /* We better start up with fd's 0, 1, and 2 open. */
+ start = devnull();
+ if (start == -1)
+ fail("open", "bad descriptor %d", start);
+ ok("open");
+
+ /* Make sure highest_fd() works. */
+ fd = highest_fd();
+ if (start != fd)
+ fail("highest_fd", "bad descriptor %d != %d", start, fd);
+ ok("highest_fd");
+
+ /* Try to use closefrom() for just closing fd 3. */
+ closefrom(start + 1);
+ fd = highest_fd();
+ if (fd != start)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Eat up 16 descriptors. */
+ for (i = 0; i < 16; i++)
+ (void)devnull();
+ fd = highest_fd();
+ if (fd != start + 16)
+ fail("open 16", "highest fd %d", fd);
+ ok("open 16");
+
+ /* Close half of them. */
+ closefrom(11);
+ fd = highest_fd();
+ if (fd != 10)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Explicitly close descriptors 6 and 8 to create holes. */
+ if (close(6) < 0 || close(8) < 0)
+ fail_err("close2 ");
+ ok("close 2");
+
+ /* Verify that close on 6 and 8 fails with EBADF. */
+ if (close(6) == 0)
+ fail("close(6)", "did not fail");
+ if (errno != EBADF)
+ fail_err("close(6)");
+ ok("close(6)");
+ if (close(8) == 0)
+ fail("close(8)", "did not fail");
+ if (errno != EBADF)
+ fail_err("close(8)");
+ ok("close(8)");
+
+ /* Close from 4 on. */
+ closefrom(4);
+ fd = highest_fd();
+ if (fd != 3)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Allocate a small SHM region for IPC with our child. */
+ info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON |
+ MAP_SHARED, -1, 0);
+ if (info == MAP_FAILED)
+ fail_err("mmap");
+ ok("mmap");
+
+ /* Fork a child process to test closefrom(0). */
+ pid = fork();
+ if (pid < 0)
+ fail_err("fork");
+ if (pid == 0) {
+ /* Child. */
+ closefrom(0);
+ fd = highest_fd();
+ if (fd >= 0)
+ cfail(info, "closefrom(0)", "highest fd %d", fd);
+ cok(info, "closefrom(0)");
+ }
+ if (wait(NULL) < 0)
+ fail_err("wait");
+ if (info->failed)
+ fail(info->tag, "%s", info->message);
+ ok(info->tag);
+
+ /* Fork a child process to test closefrom(-1). */
+ pid = fork();
+ if (pid < 0)
+ fail_err("fork");
+ if (pid == 0) {
+ /* Child. */
+ closefrom(-1);
+ fd = highest_fd();
+ if (fd >= 0)
+ cfail(info, "closefrom(-1)", "highest fd %d", fd);
+ cok(info, "closefrom(-1)");
+ }
+ if (wait(NULL) < 0)
+ fail_err("wait");
+ if (info->failed)
+ fail(info->tag, "%s", info->message);
+ ok(info->tag);
+
+ /* Dup stdout to 6. */
+ if (dup2(1, 6) < 0)
+ fail_err("dup2");
+ fd = highest_fd();
+ if (fd != 6)
+ fail("dup2", "highest fd %d", fd);
+ ok("dup2");
+
+ /* Do a closefrom() starting in a hole. */
+ closefrom(4);
+ fd = highest_fd();
+ if (fd != 3)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ /* Do a closefrom() beyond our highest open fd. */
+ closefrom(32);
+ fd = highest_fd();
+ if (fd != 3)
+ fail("closefrom", "highest fd %d", fd);
+ ok("closefrom");
+
+ return (0);
+}
diff --git a/tools/regression/file/dup/dup.c b/tests/sys/file/dup_test.c
index 8173818..8173818 100644
--- a/tools/regression/file/dup/dup.c
+++ b/tests/sys/file/dup_test.c
diff --git a/tools/regression/file/fcntlflags/fcntlflags.c b/tests/sys/file/fcntlflags_test.c
index bcb3b54..bcb3b54 100644
--- a/tools/regression/file/fcntlflags/fcntlflags.c
+++ b/tests/sys/file/fcntlflags_test.c
diff --git a/tools/regression/file/flock/flock.c b/tests/sys/file/flock_helper.c
index 49e47b8..49e47b8 100644
--- a/tools/regression/file/flock/flock.c
+++ b/tests/sys/file/flock_helper.c
diff --git a/tests/sys/file/flock_test.sh b/tests/sys/file/flock_test.sh
new file mode 100755
index 0000000..ac3e799
--- /dev/null
+++ b/tests/sys/file/flock_test.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Copyright 2014 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD$
+
+# Testcase # 11 is racy; uses an undocumented kernel interface for testing
+# locking
+# Testcase # 16 is racy/doesn't handle EINTR properly
+last_testcase=16
+
+echo "1..$last_testcase"
+
+for n in `seq 1 $last_testcase`; do
+ todomsg=""
+
+ if [ $n -eq 11 ]; then
+ todomsg=" # TODO: racy testcase"
+ # Test 16 fails:
+ # F_SETLKW on locked region by two threads: FAIL ((uintptr_t)res != 0)
+ elif [ $n -eq 16 ]; then
+ todomsg=" # TODO: racy testcase (doesn't handle EINTR properly)"
+ fi
+
+ $(dirname $0)/flock_helper . $n | grep -q SUCCEED
+ if [ $? -eq 0 ]; then
+ echo "ok $n$todomsg"
+ else
+ echo "not ok $n$todomsg"
+ fi
+done
diff --git a/tools/regression/file/ftruncate/ftruncate.c b/tests/sys/file/ftruncate_test.c
index aebcdcd..7eaba14 100644
--- a/tools/regression/file/ftruncate/ftruncate.c
+++ b/tests/sys/file/ftruncate_test.c
@@ -62,7 +62,7 @@ main(int argc, char *argv[])
int error, fd, fds[2], i, read_only_fd;
char path[PATH_MAX];
struct stat sb;
- size_t size;
+ ssize_t size;
off_t len;
char ch;
@@ -78,7 +78,7 @@ main(int argc, char *argv[])
snprintf(path, PATH_MAX, "/tmp/ftruncate.XXXXXXXXXXXXX");
fd = mkstemp(path);
if (fd < 0)
- err(-1, "makestemp");
+ err(-1, "mkstemp");
read_only_fd = open(path, O_RDONLY);
if (read_only_fd < 0) {
error = errno;
@@ -96,34 +96,34 @@ main(int argc, char *argv[])
for (i = 0; i < lengths_count; i++) {
len = lengths[i];
if (ftruncate(fd, len) < 0)
- err(-1, "ftruncate(%llu) up", len);
+ err(-1, "ftruncate(%jd) up", (intmax_t)len);
if (fstat(fd, &sb) < 0)
err(-1, "stat");
if (sb.st_size != len)
- errx(-1, "fstat(%llu) returned len %llu up", len,
- sb.st_size);
+ errx(-1, "fstat with len=%jd returned len %jd up",
+ (intmax_t)len, (intmax_t)sb.st_size);
if (len != 0) {
size = pread(fd, &ch, sizeof(ch), len - 1);
if (size < 0)
- err(-1, "pread on len %llu up", len);
+ err(-1, "pread on len %jd up", (intmax_t)len);
if (size != sizeof(ch))
- errx(-1, "pread len %llu size %jd up",
- len, (intmax_t)size);
+ errx(-1, "pread len %jd size %jd up",
+ (intmax_t)len, (intmax_t)size);
if (ch != 0)
errx(-1,
- "pread length %llu size %jd ch %d up",
- len, (intmax_t)size, ch);
+ "pread length %jd size %jd ch %d up",
+ (intmax_t)len, (intmax_t)size, ch);
}
}
for (i = lengths_count - 1; i >= 0; i--) {
len = lengths[i];
if (ftruncate(fd, len) < 0)
- err(-1, "ftruncate(%llu) down", len);
+ err(-1, "ftruncate(%jd) down", (intmax_t)len);
if (fstat(fd, &sb) < 0)
err(-1, "stat");
if (sb.st_size != len)
- errx(-1, "fstat(%llu) returned %llu down", len,
+ errx(-1, "fstat(%jd) returned %jd down", (intmax_t)len,
sb.st_size);
}
close(fd);
diff --git a/tools/regression/file/newfileops_on_fork/newfileops_on_fork.c b/tests/sys/file/newfileops_on_fork_test.c
index 8713a82..8713a82 100644
--- a/tools/regression/file/newfileops_on_fork/newfileops_on_fork.c
+++ b/tests/sys/file/newfileops_on_fork_test.c
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index 4a1e671..d366aa1 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -10,4 +10,6 @@ LDADD.unix_seqpacket_test+= -lpthread
WARNS?= 5
+TESTS_SUBDIRS+= execve
+
.include <bsd.test.mk>
diff --git a/tests/sys/kern/execve/Makefile b/tests/sys/kern/execve/Makefile
new file mode 100644
index 0000000..82c5d4b
--- /dev/null
+++ b/tests/sys/kern/execve/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/kern/execve
+
+BINDIR= ${TESTSDIR}
+
+MAN=
+
+ATF_TESTS_SH+= execve_test
+
+PROGS+= good_aout
+PROGS+= execve_helper
+
+LDFLAGS.goodaout+= -static
+
+CLEANFILES+= empty
+CLEANFILES+= sparse_aout
+CLEANFILES+= trunc_aout
+
+SCRIPTS+= bad_interp_len
+SCRIPTS+= dev_null_script
+SCRIPTS+= empty
+SCRIPTS+= good_script
+SCRIPTS+= non_exist_shell
+SCRIPTS+= script_arg
+SCRIPTS+= script_arg_nospace
+SCRIPTS+= sparse_aout
+SCRIPTS+= trunc_aout
+
+empty:
+ @touch $@
+
+sparse_aout:
+ @truncate -s 20480 $@
+
+trunc_aout:
+ @truncate -s 16 $@
+
+.include <bsd.test.mk>
diff --git a/tools/regression/execve/tests/badinterplen b/tests/sys/kern/execve/bad_interp_len
index 96c049f..96c049f 100644
--- a/tools/regression/execve/tests/badinterplen
+++ b/tests/sys/kern/execve/bad_interp_len
diff --git a/tools/regression/execve/tests/devnullscript b/tests/sys/kern/execve/dev_null_script
index 73b1020..73b1020 100644
--- a/tools/regression/execve/tests/devnullscript
+++ b/tests/sys/kern/execve/dev_null_script
diff --git a/tools/regression/execve/doexec.c b/tests/sys/kern/execve/execve_helper.c
index 0aa82ec..164a8f3 100644
--- a/tools/regression/execve/doexec.c
+++ b/tests/sys/kern/execve/execve_helper.c
@@ -34,25 +34,21 @@
* $FreeBSD$
*/
+#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char **argv)
{
+
if (argc != 2) {
fprintf(stderr, "usage: %s <progname>\n", argv[0]);
exit(2);
}
- unsetenv("LANG"); /* we compare C error strings */
- if (execve(argv[1], &argv[1], NULL) == -1) {
- printf("%s\n", strerror(errno));
- exit(1);
- }
+ execve(argv[1], &argv[1], NULL);
+ err(1, "");
}
diff --git a/tests/sys/kern/execve/execve_test.sh b/tests/sys/kern/execve/execve_test.sh
new file mode 100644
index 0000000..ef803a1
--- /dev/null
+++ b/tests/sys/kern/execve/execve_test.sh
@@ -0,0 +1,115 @@
+
+bad_interp_len_head()
+{
+ atf_set "descr" "Bad interpreter length"
+}
+bad_interp_len_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper bad_interp_len"
+}
+
+empty_head()
+{
+ atf_set "descr" "Empty file"
+}
+empty_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper empty"
+}
+
+good_aout_head()
+{
+ atf_set "descr" "Good a.out"
+}
+good_aout_body()
+{
+ atf_check -s exit:0 -e empty -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper ./good_aout"
+}
+
+good_script_head()
+{
+ atf_set "descr" "Good script"
+}
+good_script_body()
+{
+ atf_check -s exit:0 -e empty -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper good_script"
+}
+
+non_exist_head()
+{
+ atf_set "descr" "Non-existent file"
+}
+non_exist_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper non_exist"
+}
+
+non_exist_shell_head()
+{
+ atf_set "descr" "Non-existent shell"
+}
+non_exist_shell_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper non_exist_shell"
+}
+
+script_arg_head()
+{
+ atf_set "descr" "-x in the shebang"
+}
+script_arg_body()
+{
+ atf_check -s exit:0 -e 'match:\+ echo succeeded' -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper script_arg"
+}
+
+script_arg_nospace_head()
+{
+ atf_set "descr" '-x in the shebang; no space between #! and /bin/sh'
+}
+script_arg_nospace_body()
+{
+ atf_check -s exit:0 -e 'match:\+ echo succeeded' -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper script_arg_nospace"
+}
+
+sparse_aout_head()
+{
+ atf_set "descr" 'Sparse file'
+}
+sparse_aout_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper sparse_aout"
+}
+
+trunc_aout_head()
+{
+ atf_set "descr" 'Truncated file'
+}
+trunc_aout_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper trunc_aout"
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case bad_interp_len
+ atf_add_test_case empty
+ atf_add_test_case good_aout
+ atf_add_test_case good_script
+ atf_add_test_case non_exist
+ atf_add_test_case non_exist_shell
+ atf_add_test_case script_arg
+ atf_add_test_case script_arg_nospace
+ atf_add_test_case sparse_aout
+ atf_add_test_case trunc_aout
+
+}
diff --git a/tools/regression/execve/tests/goodaout.c b/tests/sys/kern/execve/good_aout.c
index ebf476b..39e9867 100644
--- a/tools/regression/execve/tests/goodaout.c
+++ b/tests/sys/kern/execve/good_aout.c
@@ -38,9 +38,7 @@
#include <stdlib.h>
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(void)
{
printf("succeeded\n");
exit(0);
diff --git a/tools/regression/execve/tests/goodscript b/tests/sys/kern/execve/good_script
index 51270dc..11c7689 100644
--- a/tools/regression/execve/tests/goodscript
+++ b/tests/sys/kern/execve/good_script
@@ -1,4 +1,4 @@
-#! /bin/csh
+#!/bin/sh
# $FreeBSD$
echo succeeded
diff --git a/tools/regression/execve/tests/nonexistshell b/tests/sys/kern/execve/non_exist_shell
index f9ee705..f9ee705 100644
--- a/tools/regression/execve/tests/nonexistshell
+++ b/tests/sys/kern/execve/non_exist_shell
diff --git a/tools/regression/execve/tests/scriptarg b/tests/sys/kern/execve/script_arg
index 2700f1c..2700f1c 100644
--- a/tools/regression/execve/tests/scriptarg
+++ b/tests/sys/kern/execve/script_arg
diff --git a/tools/regression/execve/tests/scriptarg-nospace b/tests/sys/kern/execve/script_arg_nospace
index 6731ad5..6731ad5 100644
--- a/tools/regression/execve/tests/scriptarg-nospace
+++ b/tests/sys/kern/execve/script_arg_nospace
diff --git a/tools/regression/kqueue/Makefile b/tests/sys/kqueue/Makefile
index 12b7527..43277ca 100644
--- a/tools/regression/kqueue/Makefile
+++ b/tests/sys/kqueue/Makefile
@@ -6,8 +6,14 @@
# libkqueue and test suite by Mark Heily <mark@heily.com>
#
-PROG=kqtest
-SRCS= \
+TAP_TESTS_SH= kqueue_test
+
+TESTSDIR= ${TESTSBASE}/sys/kqueue
+BINDIR= ${TESTSDIR}
+
+PROGS= kqtest
+
+SRCS.kqtest= \
main.c \
read.c \
timer.c \
@@ -15,7 +21,6 @@ SRCS= \
proc.c \
signal.c \
user.c
-MAN=
WARNS?= 2
-.include "bsd.prog.mk"
+.include <bsd.test.mk>
diff --git a/tools/regression/kqueue/common.h b/tests/sys/kqueue/common.h
index aada778..aada778 100644
--- a/tools/regression/kqueue/common.h
+++ b/tests/sys/kqueue/common.h
diff --git a/tools/regression/kqueue/config.h b/tests/sys/kqueue/config.h
index a204092..a204092 100644
--- a/tools/regression/kqueue/config.h
+++ b/tests/sys/kqueue/config.h
diff --git a/tests/sys/kqueue/kqueue_test.sh b/tests/sys/kqueue/kqueue_test.sh
new file mode 100755
index 0000000..62a7e23
--- /dev/null
+++ b/tests/sys/kqueue/kqueue_test.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+cd $(dirname $0)
+i=1
+./kqtest | while read line; do
+ echo $line | grep -q passed
+ if [ $? -eq 0 ]; then
+ echo "ok - $i $line"
+ : $(( i += 1 ))
+ fi
+
+ echo $line | grep -q 'tests completed'
+ if [ $? -eq 0 ]; then
+ echo -n "1.."
+ echo $line | cut -d' ' -f3
+ fi
+done
diff --git a/tools/regression/kqueue/main.c b/tests/sys/kqueue/main.c
index f76c4e2..f76c4e2 100644
--- a/tools/regression/kqueue/main.c
+++ b/tests/sys/kqueue/main.c
diff --git a/tools/regression/kqueue/proc.c b/tests/sys/kqueue/proc.c
index 6288ee6..6288ee6 100644
--- a/tools/regression/kqueue/proc.c
+++ b/tests/sys/kqueue/proc.c
diff --git a/tools/regression/kqueue/read.c b/tests/sys/kqueue/read.c
index cc65427..cc65427 100644
--- a/tools/regression/kqueue/read.c
+++ b/tests/sys/kqueue/read.c
diff --git a/tools/regression/kqueue/signal.c b/tests/sys/kqueue/signal.c
index 14e751d..14e751d 100644
--- a/tools/regression/kqueue/signal.c
+++ b/tests/sys/kqueue/signal.c
diff --git a/tools/regression/kqueue/timer.c b/tests/sys/kqueue/timer.c
index 766125d..766125d 100644
--- a/tools/regression/kqueue/timer.c
+++ b/tests/sys/kqueue/timer.c
diff --git a/tools/regression/kqueue/user.c b/tests/sys/kqueue/user.c
index 9ba25f9..9ba25f9 100644
--- a/tools/regression/kqueue/user.c
+++ b/tests/sys/kqueue/user.c
diff --git a/tools/regression/kqueue/vnode.c b/tests/sys/kqueue/vnode.c
index dfa0b5e..dfa0b5e 100644
--- a/tools/regression/kqueue/vnode.c
+++ b/tests/sys/kqueue/vnode.c
diff --git a/tests/sys/mqueue/Makefile b/tests/sys/mqueue/Makefile
new file mode 100644
index 0000000..5af8b25
--- /dev/null
+++ b/tests/sys/mqueue/Makefile
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/mqueue
+
+ATF_TESTS_SH= mqueue_test
+
+BINDIR= ${TESTSDIR}
+
+CFLAGS+= -I${.CURDIR:H:H}
+
+PROGS+= mqtest1
+PROGS+= mqtest2
+PROGS+= mqtest3
+PROGS+= mqtest4
+PROGS+= mqtest5
+
+LDADD+= -lrt
+DPADD+= ${LIBRT}
+
+WARNS?= 6
+
+.include <bsd.test.mk>
diff --git a/tools/regression/mqueue/mqtest1/mqtest1.c b/tests/sys/mqueue/mqtest1.c
index 25fc1ba..3accb28 100644
--- a/tools/regression/mqueue/mqtest1/mqtest1.c
+++ b/tests/sys/mqueue/mqtest1.c
@@ -7,15 +7,20 @@
#include <signal.h>
#include <stdio.h>
+#include "freebsd_test_suite/macros.h"
+
#define MQNAME "/mytstqueue1"
-int main()
+int
+main(void)
{
struct mq_attr attr, attr2;
struct sigevent sigev;
mqd_t mq;
int status;
+ PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0);
+
attr.mq_maxmsg = 2;
attr.mq_msgsize = 100;
mq = mq_open(MQNAME, O_CREAT | O_RDWR | O_EXCL, 0666, &attr);
diff --git a/tools/regression/mqueue/mqtest2/mqtest2.c b/tests/sys/mqueue/mqtest2.c
index bfe6d97..067e619 100644
--- a/tools/regression/mqueue/mqtest2/mqtest2.c
+++ b/tests/sys/mqueue/mqtest2.c
@@ -10,21 +10,28 @@
#include <stdlib.h>
#include <unistd.h>
+#include "freebsd_test_suite/macros.h"
+
#define MQNAME "/mytstqueue2"
#define LOOPS 1000
#define PRIO 10
-void alarmhandler(int sig)
+static void
+alarmhandler(int sig __unused)
{
write(1, "timeout\n", 8);
_exit(1);
}
-int main()
+int
+main(void)
{
struct mq_attr attr;
mqd_t mq;
- int status, pid;
+ int status;
+ pid_t pid;
+
+ PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0);
mq_unlink(MQNAME);
@@ -38,8 +45,9 @@ int main()
err(1, "mq_getattr");
pid = fork();
if (pid == 0) { /* child */
- int prio, j, i;
char *buf;
+ int j, i;
+ unsigned int prio;
mq_close(mq);
@@ -69,7 +77,7 @@ int main()
err(1, "fork()");
} else {
char *buf;
- int i, j, prio;
+ int i, j;
signal(SIGALRM, alarmhandler);
buf = malloc(attr.mq_msgsize);
diff --git a/tools/regression/mqueue/mqtest3/mqtest3.c b/tests/sys/mqueue/mqtest3.c
index aa47ffa..c4b849e 100644
--- a/tools/regression/mqueue/mqtest3/mqtest3.c
+++ b/tests/sys/mqueue/mqtest3.c
@@ -11,23 +11,29 @@
#include <stdlib.h>
#include <unistd.h>
+#include "freebsd_test_suite/macros.h"
+
#define MQNAME "/mytstqueue3"
#define LOOPS 1000
#define PRIO 10
-void sighandler(int sig)
+static void
+sighandler(int sig __unused)
{
write(1, "timeout\n", 8);
_exit(1);
}
-int main()
+int
+main(void)
{
- mqd_t mq;
- int status;
- struct mq_attr attr;
- int pid;
fd_set set;
+ struct mq_attr attr;
+ int status;
+ mqd_t mq;
+ pid_t pid;
+
+ PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0);
mq_unlink(MQNAME);
@@ -42,8 +48,9 @@ int main()
pid = fork();
if (pid == 0) { /* child */
- int prio, j, i;
char *buf;
+ int j, i;
+ unsigned int prio;
mq_close(mq);
@@ -77,7 +84,7 @@ int main()
err(1, "fork()");
} else {
char *buf;
- int i, j, prio;
+ int i, j;
signal(SIGALRM, sighandler);
buf = malloc(attr.mq_msgsize);
diff --git a/tools/regression/mqueue/mqtest4/mqtest4.c b/tests/sys/mqueue/mqtest4.c
index 80a7f88..474d212 100644
--- a/tools/regression/mqueue/mqtest4/mqtest4.c
+++ b/tests/sys/mqueue/mqtest4.c
@@ -12,25 +12,29 @@
#include <stdlib.h>
#include <unistd.h>
+#include "freebsd_test_suite/macros.h"
+
#define MQNAME "/mytstqueue4"
#define LOOPS 1000
#define PRIO 10
-void sighandler(int sig)
+static void
+sighandler(int sig __unused)
{
write(1, "timeout\n", 8);
_exit(1);
}
-int main()
+int
+main(void)
{
- mqd_t mq;
- int status;
- struct mq_attr attr;
- int pid;
- fd_set set;
- int kq;
struct kevent kev;
+ struct mq_attr attr;
+ mqd_t mq;
+ int kq, status;
+ pid_t pid;
+
+ PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0);
mq_unlink(MQNAME);
@@ -44,8 +48,9 @@ int main()
err(1, "mq_getattr()");
pid = fork();
if (pid == 0) { /* child */
- int prio, j, i;
char *buf;
+ int j, i;
+ unsigned int prio;
mq_close(mq);
kq = kqueue();
@@ -80,7 +85,7 @@ int main()
err(1, "fork()");
} else {
char *buf;
- int i, j, prio;
+ int i, j;
signal(SIGALRM, sighandler);
kq = kqueue();
diff --git a/tools/regression/mqueue/mqtest5/mqtest5.c b/tests/sys/mqueue/mqtest5.c
index 354a7bb..0c8aa89 100644
--- a/tools/regression/mqueue/mqtest5/mqtest5.c
+++ b/tests/sys/mqueue/mqtest5.c
@@ -12,25 +12,31 @@
#include <stdlib.h>
#include <unistd.h>
+#include "freebsd_test_suite/macros.h"
+
#define MQNAME "/mytstqueue5"
#define LOOPS 1000
#define PRIO 10
-void sighandler(int sig)
+static void
+sighandler(int sig __unused)
{
write(1, "timeout\n", 8);
_exit(1);
}
-int main()
+int
+main(void)
{
- mqd_t mq;
int status;
struct mq_attr attr;
- int pid;
- sigset_t set;
struct sigaction sa;
+ sigset_t set;
siginfo_t info;
+ mqd_t mq;
+ pid_t pid;
+
+ PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0);
mq_unlink(MQNAME);
@@ -95,7 +101,7 @@ int main()
err(1, "fork()");
} else {
char *buf;
- int i, j, prio;
+ int i, j;
signal(SIGALRM, sighandler);
buf = malloc(attr.mq_msgsize);
diff --git a/tools/regression/sockets/so_setfib/so_setfib.t b/tests/sys/mqueue/mqueue_test.sh
index c80c173..4841418 100644..100755
--- a/tools/regression/sockets/so_setfib/so_setfib.t
+++ b/tests/sys/mqueue/mqueue_test.sh
@@ -1,10 +1,6 @@
-#!/bin/sh
-#-
-# Copyright (c) 2012 Cisco Systems, Inc.
-# All rights reserved.
#
-# This software was developed by Bjoern Zeeb under contract to
-# Cisco Systems, Inc..
+# Copyright (c) 2015 EMC / Isilon Storage Division
+# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -30,30 +26,56 @@
# $FreeBSD$
#
-cd `dirname $0`
-
-EXECUTABLE=`basename $0 .t`
-
-FIBS=`sysctl -n net.fibs`
-INET=`sysctl -n kern.features.inet`
-INET6=`sysctl -n kern.features.inet6`
+mqtest1_head()
+{
+ :
+}
+mqtest1_body()
+{
+ atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest1
+}
-case "${INET}" in
-1) OPTS="${OPTS} -DINET" ;;
-*) INET=0 ;;
-esac
-case "${INET6}" in
-1) OPTS="${OPTS} -DINET6" ;;
-*) INET6=0 ;;
-esac
+mqtest2_head()
+{
+ :
+}
+mqtest2_body()
+{
+ atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest2
+}
-make ${EXECUTABLE} ${OPTS} 2>&1 > /dev/null
+mqtest3_head()
+{
+ :
+}
+mqtest3_body()
+{
+ atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest3
+}
-# two out of bounds on each side + 3 random
-FIBS=$((2 + FIBS + 2 + 3))
-# ROUTE and LOCAL are 1 domain together given 2 or 1 types only
-TESTS=$(((1 + ${INET} + ${INET6}) * 3 * ${FIBS}))
+mqtest4_head()
+{
+ :
+}
+mqtest4_body()
+{
+ atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest4
+}
-echo "1..${TESTS}"
+mqtest5_head()
+{
+ :
+}
+mqtest5_body()
+{
+ atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest5
+}
-exec ./${EXECUTABLE}
+atf_init_test_cases()
+{
+ atf_add_test_case mqtest1
+ atf_add_test_case mqtest2
+ atf_add_test_case mqtest3
+ atf_add_test_case mqtest4
+ atf_add_test_case mqtest5
+}
diff --git a/tests/sys/vm/Makefile b/tests/sys/vm/Makefile
new file mode 100644
index 0000000..1795eef
--- /dev/null
+++ b/tests/sys/vm/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/vm
+
+TAP_TESTS_C+= mmap_test
+
+.include <bsd.test.mk>
diff --git a/tools/regression/mmap/mmap.c b/tests/sys/vm/mmap_test.c
index 14c55a1..7591a09 100644
--- a/tools/regression/mmap/mmap.c
+++ b/tests/sys/vm/mmap_test.c
@@ -31,10 +31,11 @@
#include <sys/sysctl.h>
#include <sys/types.h>
+#include <errno.h>
#include <stdio.h>
-#include <err.h>
+#include <string.h>
-const struct tests {
+static const struct {
void *addr;
int ok[2]; /* Depending on security.bsd.map_at_zero {0, !=0}. */
} tests[] = {
@@ -49,6 +50,8 @@ const struct tests {
{ (void *)(0x1000 * PAGE_SIZE), { 1, 1 } },
};
+#define MAP_AT_ZERO "security.bsd.map_at_zero"
+
int
main(void)
{
@@ -60,37 +63,43 @@ main(void)
/* Get the current sysctl value of security.bsd.map_at_zero. */
len = sizeof(mib) / sizeof(*mib);
- if (sysctlnametomib("security.bsd.map_at_zero", mib, &len) == -1)
- err(1, "sysctlnametomib(security.bsd.map_at_zero)");
+ if (sysctlnametomib(MAP_AT_ZERO, mib, &len) == -1) {
+ printf("1..0 # SKIP: sysctlnametomib(\"%s\") failed: %s\n",
+ MAP_AT_ZERO, strerror(errno));
+ return (0);
+ }
len = sizeof(map_at_zero);
- if (sysctl(mib, 3, &map_at_zero, &len, NULL, 0) == -1)
- err(1, "sysctl(security.bsd.map_at_zero)");
+ if (sysctl(mib, 3, &map_at_zero, &len, NULL, 0) == -1) {
+ printf("1..0 # SKIP: sysctl for %s failed: %s\n", MAP_AT_ZERO,
+ strerror(errno));
+ return (0);
+ }
/* Normalize to 0 or 1 for array access. */
map_at_zero = !!map_at_zero;
- for (i=0; i < (sizeof(tests) / sizeof(*tests)); i++) {
+ printf("1..%zu\n", nitems(tests));
+ for (i = 0; i < (int)nitems(tests); i++) {
p = mmap((void *)tests[i].addr, PAGE_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_FIXED,
-1, 0);
if (p == MAP_FAILED) {
if (tests[i].ok[map_at_zero] != 0)
error++;
- warnx("%s: mmap(%p, ...) failed.",
- (tests[i].ok[map_at_zero] == 0) ? "OK " : "ERR",
- tests[i].addr);
+ printf("%sok %d # mmap(%p, ...) failed\n",
+ tests[i].ok[map_at_zero] == 0 ? "" : "not ",
+ i + 1,
+ tests[i].addr);
} else {
if (tests[i].ok[map_at_zero] != 1)
error++;
- warnx("%s: mmap(%p, ...) succeeded: p=%p",
- (tests[i].ok[map_at_zero] == 1) ? "OK " : "ERR",
+ printf("%sok %d # mmap(%p, ...) succeeded: p=%p\n",
+ tests[i].ok[map_at_zero] == 1 ? "" : "not ",
+ i + 1,
tests[i].addr, p);
}
}
- if (error)
- err(1, "---\nERROR: %d unexpected results.", error);
-
return (error != 0);
}
diff --git a/tools/build/check-links.sh b/tools/build/check-links.sh
index 28e52b5..57c9437 100755
--- a/tools/build/check-links.sh
+++ b/tools/build/check-links.sh
@@ -1,37 +1,111 @@
#!/bin/sh
# $FreeBSD$
-mime=$(file --mime-type $1)
+libkey() {
+ libkey="lib_symbols_$1"
+ patterns=[.+,/-]
+ replacement=_
+ while :; do
+ case " ${libkey} " in
+ *${patterns}*)
+ libkey="${libkey%%${patterns}*}${replacement}${libkey#*${patterns}}"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+ return 0
+}
+
+ret=0
+CHECK_UNRESOLVED=1
+VERBOSE_RESOLVED=0
+while getopts "Uv" flag; do
+ case "${flag}" in
+ U) CHECK_UNRESOLVED=0 ;;
+ v) VERBOSE_RESOLVED=1 ;;
+ esac
+done
+shift $((OPTIND-1))
+
+mime=$(file -L --mime-type $1)
+isbin=0
case $mime in
-*application/x-executable);;
+*application/x-executable) isbin=1 ;;
*application/x-sharedlib);;
*) echo "Not an elf file" >&2 ; exit 1;;
esac
+# Gather all symbols from the target
+unresolved_symbols=$(nm -u -D --format=posix "$1" | awk '$2 == "U" {print $1}' | tr '\n' ' ')
+[ ${isbin} -eq 1 ] && bss_symbols=$(nm -D --format=posix "$1" | awk '$2 == "B" && $4 != "" {print $1}' | tr '\n' ' ')
+ldd_libs=$(ldd $(realpath $1) | awk '{print $1 ":" $3}')
+
# Check for useful libs
-list_libs=""
-for lib in $(readelf -d $1 | awk '$2 == "(NEEDED)" { sub(/\[/,"",$NF); sub(/\]/,"",$NF); print $NF }'); do
- echo -n "checking if $lib is needed: "
- libpath=$(ldd $1 | awk -v lib=$lib '$1 == lib { print $3 }')
- list_libs="$list_libs $libpath"
- foundone=0
- for fct in $(nm -D $libpath | awk '$2 == "T" || $2 == "W" || $2 == "B" { print $3 }'); do
- nm -D $1 | awk -v s=$fct '$1 == "U" && $2 == s { found=1 ; exit } END { if (found != 1) { exit 1 } }' && foundone=1 && break
- done
- if [ $foundone -eq 1 ]; then
- echo "yes"
- else
- echo "no"
- fi
+list_libs=
+resolved_symbols=
+for lib in $(readelf -d $1 | awk '$2 ~ /\(?NEEDED\)?/ { sub(/\[/,"",$NF); sub(/\]/,"",$NF); print $NF }'); do
+ echo -n "checking if $lib is needed: "
+ if [ -n "${lib##/*}" ]; then
+ for libpair in ${ldd_libs}; do
+ case "${libpair}" in
+ ${lib}:*) libpath="${libpair#*:}" && break ;;
+ esac
+ done
+ else
+ libpath="${lib}"
+ fi
+ list_libs="$list_libs $lib"
+ foundone=
+ lib_symbols="$(nm -D --defined-only --format=posix "${libpath}" | awk '$2 ~ /C|R|D|T|W|B|V/ {print $1}' | tr '\n' ' ')"
+ if [ ${CHECK_UNRESOLVED} -eq 1 ]; then
+ # Save the global symbols for this lib
+ libkey "${lib}"
+ setvar "${libkey}" "${lib_symbols}"
+ fi
+ for fct in ${lib_symbols}; do
+ case " ${unresolved_symbols} ${bss_symbols} " in
+ *\ ${fct}\ *) foundone="${fct}" && break ;;
+ esac
+ done
+ if [ -n "${foundone}" ]; then
+ echo "yes... ${foundone}"
+ else
+ echo "no"
+ ret=1
+ fi
done
-for sym in $(nm -D $1 | awk '$1 == "U" { print $2 }'); do
- found=0
- for l in ${list_libs} ; do
- nm -D $l | awk -v s=$sym '($2 == "T" || $2 == "W" || $2 == "B") && $3 == s { found=1 ; exit } END { if (found != 1) { exit 1 } }' && found=1 && break
- done
- if [ $found -eq 0 ]; then
- echo "Unresolved symbol $sym"
- fi
-done
+if [ ${CHECK_UNRESOLVED} -eq 1 ]; then
+ # Add in crt1 symbols
+ list_libs="${list_libs} crt1.o"
+ lib_symbols="$(nm --defined-only --format=posix "/usr/lib/crt1.o" | awk '$2 ~ /C|R|D|T|W|B|V/ {print $1}' | tr '\n' ' ')"
+ # Save the global symbols for this lib
+ libkey "crt1.o"
+ setvar "${libkey}" "${lib_symbols}"
+
+ # Now search libs for all symbols and report missing ones.
+ for sym in ${unresolved_symbols}; do
+ found=0
+ for lib in ${list_libs}; do
+ libkey "${lib}"
+ eval "lib_symbols=\"\${${libkey}}\""
+ # lib_symbols now contains symbols for the lib.
+ case " ${lib_symbols} " in
+ *\ ${sym}\ *)
+ [ ${VERBOSE_RESOLVED} -eq 1 ] &&
+ echo "Resolved symbol ${sym} from ${lib}"
+ found=1
+ break
+ ;;
+ esac
+ done
+ if [ $found -eq 0 ]; then
+ echo "Unresolved symbol $sym"
+ ret=1
+ fi
+ done
+fi
+exit ${ret}
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 7a4549e..a519580 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -1004,7 +1004,9 @@ OLD_DIRS+=usr/include/fs/cuse
.if ${MK_CXX} == no
OLD_FILES+=usr/bin/CC
OLD_FILES+=usr/bin/c++
+.if ${MK_ELFTOOLCHAIN_TOOLS} == no
OLD_FILES+=usr/bin/c++filt
+.endif
OLD_FILES+=usr/bin/g++
OLD_FILES+=usr/libexec/cc1plus
.if ${MK_GCC} == no
@@ -1720,7 +1722,9 @@ OLD_FILES+=usr/share/man/man8/unstr.8.gz
.endif
.if ${MK_GCC} == no
+.if ${MK_ELFTOOLCHAIN_TOOLS} == no
OLD_FILES+=usr/bin/c++filt
+.endif
OLD_FILES+=usr/bin/g++
OLD_FILES+=usr/bin/gcc
OLD_FILES+=usr/bin/gcov
@@ -1835,7 +1839,6 @@ OLD_FILES+=usr/bin/post-grohtml
OLD_FILES+=usr/bin/pre-grohtml
OLD_FILES+=usr/bin/psroff
OLD_FILES+=usr/bin/refer
-OLD_FILES+=usr/bin/soelim
OLD_FILES+=usr/bin/tbl
OLD_FILES+=usr/bin/tfmtodit
OLD_FILES+=usr/bin/troff
@@ -2242,7 +2245,6 @@ OLD_FILES+=usr/share/man/man1/pfbtops.1.gz
OLD_FILES+=usr/share/man/man1/pic.1.gz
OLD_FILES+=usr/share/man/man1/psroff.1.gz
OLD_FILES+=usr/share/man/man1/refer.1.gz
-OLD_FILES+=usr/share/man/man1/soelim.1.gz
OLD_FILES+=usr/share/man/man1/tbl.1.gz
OLD_FILES+=usr/share/man/man1/tfmtodit.1.gz
OLD_FILES+=usr/share/man/man1/troff.1.gz
diff --git a/tools/build/options/WITHOUT_CXX b/tools/build/options/WITHOUT_CXX
index 541cc3c..ab9346a 100644
--- a/tools/build/options/WITHOUT_CXX
+++ b/tools/build/options/WITHOUT_CXX
@@ -1,6 +1,6 @@
.\" $FreeBSD$
Set to not build
-.Xr g++ 1
+.Xr c++ 1
and related libraries.
It will also prevent building of
.Xr gperf 1
diff --git a/tools/build/options/WITHOUT_SYSCALL_COMPAT b/tools/build/options/WITHOUT_SYSCALL_COMPAT
deleted file mode 100644
index a20adcb..0000000
--- a/tools/build/options/WITHOUT_SYSCALL_COMPAT
+++ /dev/null
@@ -1,2 +0,0 @@
-.\" $FreeBSD$
-Do not include some compatible syscall wrappers in libc.
diff --git a/tools/debugscripts/netstat-anr.gdb b/tools/debugscripts/netstat-anr.gdb
new file mode 100644
index 0000000..d27ae65
--- /dev/null
+++ b/tools/debugscripts/netstat-anr.gdb
@@ -0,0 +1,163 @@
+#
+# $FreeBSD$
+#
+
+document netstat-anr
+Print routing tables as 'netstat -anr' does.
+end
+
+set $debug = 0
+
+set $AF_INET = 2
+set $AF_LINK = 18
+
+set $RNF_ROOT = 2
+set $RNF_ACTIVE = 4
+
+set $RTF_UP = 0x1
+set $RTF_GATEWAY = 0x2
+set $RTF_HOST = 0x4
+set $RTF_STATIC = 0x800
+
+#
+# XXX: alas, we can't script "show endian"
+#
+if (machine[0] == 'a' && machine[1] == 'm' && machine[2] == 'd') || \
+ (machine[0] == 'i' && machine[1] == '3' && machine[2] == '8')
+ set $byteswap = 1
+else
+ set $byteswap = 0
+end
+
+define routename
+ if ($byteswap)
+ printf "%u.%u.%u.%u", \
+ $arg0 & 0xff, ($arg0 >> 8) & 0xff, \
+ ($arg0 >> 16) & 0xff, ($arg0 >> 24) & 0xff
+ else
+ printf "%u.%u.%u.%u", \
+ ($arg0 >> 24) & 0xff, ($arg0 >> 16) & 0xff, \
+ ($arg0 >> 8) & 0xff, $arg0 & 0xff
+ end
+end
+
+define domask
+ set $i = 0
+ set $b = 0
+ while $b < 32
+ if ($arg0 & (1 << $b))
+ set $i = $i + 1
+ end
+ set $b = $b + 1
+ end
+ printf "/%d", $i
+end
+
+define p_flags
+ if ($arg0 & $RTF_UP)
+ printf "U"
+ end
+ if ($arg0 & $RTF_GATEWAY)
+ printf "G"
+ end
+ if ($arg0 & $RTF_HOST)
+ printf "H"
+ end
+ if ($arg0 & $RTF_STATIC)
+ printf "S"
+ end
+end
+
+define p_sockaddr
+ set $sa = (struct sockaddr *)$arg0
+ set $flags = $arg2
+ if ($sa->sa_family == $AF_INET)
+ set $sin = (struct sockaddr_in *)$arg0
+ set $mask = (struct sockaddr_in *)$arg1
+ if ($flags & $RTF_HOST)
+ routename $sin->sin_addr.s_addr
+ else
+ routename $sin->sin_addr.s_addr
+ if ($mask != 0)
+ domask $mask->sin_addr.s_addr
+ else
+ domask 0
+ end
+ end
+ end
+ if ($sa->sa_family == $AF_LINK)
+ set $sdl = (struct sockaddr_dl *)$arg0
+ if ($sdl->sdl_nlen == 0 && $sdl->sdl_alen == 0 && \
+ $sdl->sdl_slen == 0)
+ printf "link#%d", $sdl->sdl_index
+ end
+ end
+end
+
+define p_rtentry
+ set $rte = (struct rtentry *)$arg0
+ set $rn = (struct radix_node *)$arg0
+ set $sa = ((struct sockaddr **)($rn->rn_u.rn_leaf.rn_Key))
+ set $sam = ((struct sockaddr **)($rn->rn_u.rn_leaf.rn_Mask))
+ set $gw = $rte->rt_gateway
+
+ p_sockaddr $sa $sam $rte->rt_flags
+ printf "\t"
+ p_sockaddr $gw 0 $RTF_HOST
+ printf "\t"
+ p_flags $rte->rt_flags
+ printf "\t"
+ if ($rte->rt_ifp != 0)
+ printf "%s", $rte->rt_ifp->if_xname
+ end
+ printf "\n"
+end
+
+define p_rtree
+ set $rn_$arg0 = (struct radix_node *)$arg1
+ set $left_$arg0 = $arg0 + 1
+ set $right_$arg0 = $arg0 + 2
+ set $duped_$arg0 = $arg0 + 3
+
+ if ($rn_$arg0->rn_bit < 0 || ($rn_$arg0->rn_flags & $RNF_ACTIVE) == 0)
+ if ($debug == 1)
+ printf "print "
+ p $rn_$arg0
+ end
+ if (($rn_$arg0->rn_flags & ($RNF_ACTIVE | $RNF_ROOT)) == \
+ $RNF_ACTIVE)
+ p_rtentry $rn_$arg0
+ end
+ if (($rn_$arg0->rn_flags & $RNF_ACTIVE) != 0 && \
+ $rn_$arg0->rn_u.rn_leaf.rn_Dupedkey != 0)
+ if ($debug == 1)
+ printf "duped "
+ p $rn_$arg0
+ end
+ p_rtree $duped_$arg0 $rn_$arg0->rn_u.rn_leaf.rn_Dupedkey
+ end
+ else
+ if ($rn_$arg0->rn_u.rn_node.rn_R != 0)
+ if ($debug == 1)
+ printf "right "
+ p $rn_$arg0
+ end
+ p_rtree $right_$arg0 $rn_$arg0->rn_u.rn_node.rn_R
+ end
+ if ($rn_$arg0->rn_u.rn_node.rn_L != 0)
+ if ($debug == 1)
+ printf "left "
+ p $rn_$arg0
+ end
+ p_rtree $left_$arg0 $rn_$arg0->rn_u.rn_node.rn_L
+ end
+ end
+end
+
+define netstat-anr
+ printf "Routing tables\n\nInternet:\n"
+ set $af = $AF_INET
+ set $rt = (struct radix_node_head **)rt_tables + $af
+ printf "Destination\tGateway\tFlags\tNetif\n"
+ p_rtree 0 $rt->rnh_treetop
+end
diff --git a/tools/regression/aio/aiop/Makefile b/tools/regression/aio/aiop/Makefile
index aac9a3b..38d9db6 100644
--- a/tools/regression/aio/aiop/Makefile
+++ b/tools/regression/aio/aiop/Makefile
@@ -3,4 +3,6 @@
PROG= aiop
MAN=
+WARNS= 6
+
.include <bsd.prog.mk>
diff --git a/tools/regression/aio/aiop/aiop.c b/tools/regression/aio/aiop/aiop.c
index 3e64dbe..98a176e 100644
--- a/tools/regression/aio/aiop/aiop.c
+++ b/tools/regression/aio/aiop/aiop.c
@@ -39,21 +39,22 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/time.h>
#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <sys/ioctl.h>
#include <sys/disk.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
#include <aio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include <assert.h>
+#include <time.h>
+#include <unistd.h>
/*
* This is a bit of a quick hack to do parallel IO testing through POSIX AIO.
@@ -84,14 +85,12 @@ disk_getsize(int fd)
{
off_t mediasize;
- if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
- perror("ioctl(DIOCGMEDIASIZE)");
- exit(1);
- }
- return mediasize;
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0)
+ err(1, "ioctl(DIOCGMEDIASIZE)");
+ return (mediasize);
}
-iot_t
+static iot_t
choose_aio(iot_t iomask)
{
/* choose a random read or write event, limited by the mask */
@@ -102,7 +101,7 @@ choose_aio(iot_t iomask)
return (random() & 0x01 ? IOT_READ : IOT_WRITE);
}
-void
+static void
set_aio(struct aiocb *a, iot_t iot, int fd, off_t offset, int size, char *buf)
{
int r;
@@ -115,10 +114,8 @@ set_aio(struct aiocb *a, iot_t iot, int fd, off_t offset, int size, char *buf)
r = aio_read(a);
else
r = aio_write(a);
- if (r != 0) {
- perror("set_aio");
- exit(1);
- }
+ if (r != 0)
+ err(1, "set_aio call failed");
}
int
@@ -134,30 +131,35 @@ main(int argc, char *argv[])
off_t file_size, offset;
struct aiocb *a;
int i, n;
- struct timeval st, et, rt;
- float f_rt;
+ struct timeval st, et, rt;
+ float f_rt;
iot_t iowhat;
if (argc < 6) {
- printf("Usage: %s <file> <io size> <number of runs> <concurrency> <ro|wo|rw>\n", argv[0]);
+ printf("Usage: %s <file> <io size> <number of runs> <concurrency> <ro|wo|rw>\n",
+ argv[0]);
exit(1);
}
fn = argv[1];
io_size = atoi(argv[2]);
+ if (io_size <= 0)
+ errx(1, "the I/O size must be >0");
nrun = atoi(argv[3]);
+ if (nrun <= 0)
+ errx(1, "the number of runs must be >0");
aio_len = atoi(argv[4]);
- if (strcmp(argv[5], "ro") == 0) {
+ if (aio_len <= 0)
+ errx(1, "AIO concurrency must be >0");
+ if (strcmp(argv[5], "ro") == 0)
iowhat = IOT_READ;
- } else if (strcmp(argv[5], "rw") == 0) {
+ else if (strcmp(argv[5], "rw") == 0)
iowhat = IOT_READ | IOT_WRITE;
- } else if (strcmp(argv[5], "wo") == 0) {
+ else if (strcmp(argv[5], "wo") == 0)
iowhat = IOT_WRITE;
- } else {
- fprintf(stderr, "needs to be ro, rw, wo!\n");
- exit(1);
- }
+ else
+ errx(1, "the I/O type needs to be \"ro\", \"rw\", or \"wo\"!\n");
/*
* Random returns values between 0 and (2^32)-1; only good for 4 gig.
@@ -171,35 +173,31 @@ main(int argc, char *argv[])
else
fd = open(fn, O_RDWR | O_DIRECT);
- if (fd < 0) {
- perror("open");
- exit(1);
- }
- if (fstat(fd, &sb) < 0) {
- perror("fstat");
- exit(1);
- }
+ if (fd < 0)
+ err(1, "open failed");
+ if (fstat(fd, &sb) < 0)
+ err(1, "fstat failed");
if (S_ISREG(sb.st_mode)) {
file_size = sb.st_size;
} else if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
file_size = disk_getsize(fd);
- } else {
- perror("unknown file type\n");
- exit(1);
- }
+ } else
+ errx(1, "unknown file type");
+ if (file_size <= 0)
+ errx(1, "path provided too small");
+
printf("File: %s; File size %jd bytes\n", fn, (intmax_t)file_size);
aio = calloc(aio_len, sizeof(struct aiocb));
abuf = calloc(aio_len, sizeof(char *));
- for (i = 0; i < aio_len; i++) {
+ for (i = 0; i < aio_len; i++)
abuf[i] = calloc(1, io_size * sizeof(char));
- }
/* Fill with the initial contents */
- gettimeofday(&st, NULL);
+ gettimeofday(&st, NULL);
for (i = 0; i < aio_len; i++) {
- offset = random() % (file_size / io_size);
- offset *= io_size;
+ offset = random() % (file_size / io_size);
+ offset *= io_size;
set_aio(aio + i, choose_aio(iowhat), fd, offset, io_size, abuf[i]);
}
@@ -208,18 +206,18 @@ main(int argc, char *argv[])
n = a - aio;
assert(n < aio_len);
assert(n >= 0);
- offset = random() % (file_size / io_size);
- offset *= io_size;
+ offset = random() % (file_size / io_size);
+ offset *= io_size;
set_aio(aio + n, choose_aio(iowhat), fd, offset, io_size, abuf[n]);
}
- gettimeofday(&et, NULL);
- timersub(&et, &st, &rt);
- f_rt = ((float) (rt.tv_usec)) / 1000000.0;
- f_rt += (float) (rt.tv_sec);
- printf("Runtime: %.2f seconds, ", f_rt);
- printf("Op rate: %.2f ops/sec, ", ((float) (nrun)) / f_rt);
- printf("Avg transfer rate: %.2f bytes/sec\n", ((float) (nrun)) * ((float)io_size) / f_rt);
+ gettimeofday(&et, NULL);
+ timersub(&et, &st, &rt);
+ f_rt = ((float) (rt.tv_usec)) / 1000000.0;
+ f_rt += (float) (rt.tv_sec);
+ printf("Runtime: %.2f seconds, ", f_rt);
+ printf("Op rate: %.2f ops/sec, ", ((float) (nrun)) / f_rt);
+ printf("Avg transfer rate: %.2f bytes/sec\n", ((float) (nrun)) * ((float)io_size) / f_rt);
diff --git a/tools/regression/aio/aiotest/Makefile b/tools/regression/aio/aiotest/Makefile
deleted file mode 100644
index 59d4316..0000000
--- a/tools/regression/aio/aiotest/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# $FreeBSD$
-
-PROG= aiotest
-MAN=
-
-DPADD= ${LIBUTIL}
-LDADD= -lutil
-
-WARNS?= 6
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/aio/kqueue/Makefile b/tools/regression/aio/kqueue/Makefile
deleted file mode 100644
index 39c1aa1..0000000
--- a/tools/regression/aio/kqueue/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# $FreeBSD$
-
-PROG= aio_kqueue
-MAN=
-
-WARNS?= 6
-
-SUBDIR+= lio
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/aio/kqueue/lio/Makefile b/tools/regression/aio/kqueue/lio/Makefile
deleted file mode 100644
index da054e4..0000000
--- a/tools/regression/aio/kqueue/lio/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# $FreeBSD$
-
-PROG= lio_kqueue
-MAN=
-
-WARNS?= 6
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/execve/Makefile b/tools/regression/execve/Makefile
deleted file mode 100644
index 018678c..0000000
--- a/tools/regression/execve/Makefile
+++ /dev/null
@@ -1,70 +0,0 @@
-# $FreeBSD$
-
-PROG= doexec
-MAN=
-
-RP= ./${PROG}
-TD= ${.CURDIR}/tests
-
-TESTSCRIPTS= nonexistshell devnullscript badinterplen goodscript \
- scriptarg scriptarg-nospace
-CLEANFILES= goodaout truncaout sparseaout empty ${TESTSCRIPTS}
-
-all: ${PROG} goodaout ${TESTSCRIPTS}
-
-.for x in ${TESTSCRIPTS}
-${x}: ${TD}/${x}
- ${CP} ${TD}/${x} .
- chmod +x ${x}
-.endfor
-
-regress: test-empty test-nonexist test-nonexistshell \
- test-devnullscript test-badinterplen test-goodscript \
- test-scriptarg test-scriptarg-nospace test-goodaout \
- test-truncaout test-sparseaout
-
-test-empty: ${PROG}
- rm -f empty
- touch empty
- chmod +x empty
- ${RP} empty | grep 'Exec format error'
-
-test-nonexist: ${PROG}
- ${RP} ${TD}/nonexistent | grep 'No such file or directory'
-
-test-nonexistshell: ${PROG} nonexistshell
- ${RP} nonexistshell | grep 'No such file or directory'
-
-test-devnullscript: ${PROG} devnullscript
- ${RP} devnullscript | grep 'Permission denied'
-
-test-badinterplen: ${PROG} badinterplen
- ${RP} badinterplen | grep 'No such file or directory'
-
-test-goodscript: ${PROG} goodscript
- ${RP} goodscript | grep 'succeeded'
-
-test-scriptarg: ${PROG} scriptarg
- ${RP} scriptarg 2>&1 | grep '+ echo succeeded'
-
-test-scriptarg-nospace: ${PROG} scriptarg-nospace
- ${RP} scriptarg-nospace 2>&1 | grep '+ echo succeeded'
-
-goodaout: ${TD}/goodaout.c
- ${CC} -static -o ${.TARGET} ${TD}/goodaout.c
-
-test-goodaout: ${PROG} goodaout
- ${RP} goodaout | grep 'succeeded'
-
-test-truncaout: ${PROG} goodaout
- truncate -s 16 truncaout
- chmod a+x truncaout
- ${RP} truncaout | grep 'Exec format error'
-
-test-sparseaout: ${PROG}
- /bin/rm -rf sparseaout
- truncate -s 20480 sparseaout
- chmod a+x sparseaout
- ${RP} sparseaout | grep 'Exec format error'
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/execve/execve.t b/tools/regression/execve/execve.t
deleted file mode 100644
index dd2be9a..0000000
--- a/tools/regression/execve/execve.t
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-# $FreeBSD$
-
-cd `dirname $0`
-cmd="./`basename $0 .t`"
-
-make >/dev/null 2>&1
-
-tests="test-empty test-nonexist test-nonexistshell \
- test-devnullscript test-badinterplen test-goodscript \
- test-scriptarg test-scriptarg-nospace test-goodaout \
- test-truncaout test-sparseaout"
-
-n=0
-
-echo "1..11"
-
-for atest in ${tests}
-do
- n=`expr ${n} + 1`
- if make ${atest}
- then
- echo "ok ${n} - ${atest}"
- else
- echo "not ok ${n} - ${atest}"
- fi
-done
diff --git a/tools/regression/fifo/fifo_create/Makefile b/tools/regression/fifo/fifo_create/Makefile
deleted file mode 100644
index 10e2b14..0000000
--- a/tools/regression/fifo/fifo_create/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= fifo_create
-MAN=
-WARNS?= 3
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/fifo/fifo_io/Makefile b/tools/regression/fifo/fifo_io/Makefile
deleted file mode 100644
index 49bf5bd..0000000
--- a/tools/regression/fifo/fifo_io/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= fifo_io
-MAN=
-WARNS?= 3
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/fifo/fifo_misc/Makefile b/tools/regression/fifo/fifo_misc/Makefile
deleted file mode 100644
index 97f85ec..0000000
--- a/tools/regression/fifo/fifo_misc/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= fifo_misc
-MAN=
-WARNS?= 3
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/fifo/fifo_open/Makefile b/tools/regression/fifo/fifo_open/Makefile
deleted file mode 100644
index d90811c..0000000
--- a/tools/regression/fifo/fifo_open/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= fifo_open
-MAN=
-WARNS?= 3
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/file/closefrom/closefrom.c b/tools/regression/file/closefrom/closefrom.c
index e119f20..b27ec51 100644
--- a/tools/regression/file/closefrom/closefrom.c
+++ b/tools/regression/file/closefrom/closefrom.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/tools/regression/file/dup/Makefile b/tools/regression/file/dup/Makefile
deleted file mode 100644
index 225c2e2..0000000
--- a/tools/regression/file/dup/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= dup
-MAN=
-WARNS?= 6
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/file/dup/dup.t b/tools/regression/file/dup/dup.t
deleted file mode 100644
index 8bdfd03..0000000
--- a/tools/regression/file/dup/dup.t
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-# $FreeBSD$
-
-cd `dirname $0`
-
-executable=`basename $0 .t`
-
-make $executable 2>&1 > /dev/null
-
-exec ./$executable
diff --git a/tools/regression/file/fcntlflags/Makefile b/tools/regression/file/fcntlflags/Makefile
deleted file mode 100644
index 9e7fc3e..0000000
--- a/tools/regression/file/fcntlflags/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= fcntlflags
-MAN=
-WARNS?= 6
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/file/fcntlflags/fcntlflags.t b/tools/regression/file/fcntlflags/fcntlflags.t
deleted file mode 100644
index 8bdfd03..0000000
--- a/tools/regression/file/fcntlflags/fcntlflags.t
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-# $FreeBSD$
-
-cd `dirname $0`
-
-executable=`basename $0 .t`
-
-make $executable 2>&1 > /dev/null
-
-exec ./$executable
diff --git a/tools/regression/file/flock/Makefile b/tools/regression/file/flock/Makefile
deleted file mode 100644
index cd1a46d..0000000
--- a/tools/regression/file/flock/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# $FreeBSD$
-
-PROG= flock
-MAN=
-WARNS?= 6
-DPADD= ${LIBPTHREAD}
-LDADD= -lpthread
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/file/ftruncate/Makefile b/tools/regression/file/ftruncate/Makefile
deleted file mode 100644
index 40b753e..0000000
--- a/tools/regression/file/ftruncate/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= ftruncate
-MAN=
-WARNS?= 2
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/file/newfileops_on_fork/Makefile b/tools/regression/file/newfileops_on_fork/Makefile
deleted file mode 100644
index be0c5fe..0000000
--- a/tools/regression/file/newfileops_on_fork/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# $FreeBSD$
-
-PROG= newfileops_on_fork
-MAN=
-WARNS?= 6
-LDFLAGS= -lpthread
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/gaithrstress/gaithrstress.c b/tools/regression/gaithrstress/gaithrstress.c
index c76f94f..2506625 100644
--- a/tools/regression/gaithrstress/gaithrstress.c
+++ b/tools/regression/gaithrstress/gaithrstress.c
@@ -230,7 +230,7 @@ usage:
err(1, "reading word file %s", wordfile);
if (nrandwords < 1)
errx(1, "word file %s did not have >0 words", wordfile);
- printf("Read %u random words from %s.\n", nrandwords, wordfile);
+ printf("Read %zu random words from %s.\n", nrandwords, wordfile);
workers = calloc(nworkers, sizeof(*workers));
if (workers == NULL)
err(1, "allocating workers");
@@ -242,8 +242,8 @@ usage:
for (i = 0; i < nworkers; i++) {
if (pthread_create(&workers[i].w_thread, NULL, work,
&workers[i]) != 0)
- err(1, "creating worker %u", i);
- printf("%u%s", i, i == nworkers - 1 ? ".\n" : ", ");
+ err(1, "creating worker %zu", i);
+ printf("%zu%s", i, i == nworkers - 1 ? ".\n" : ", ");
fflush(stdout);
}
@@ -255,7 +255,7 @@ usage:
fflush(stdout);
for (i = 0; i < nworkers; i++) {
pthread_join(workers[i].w_thread, NULL);
- printf("%u%s", i, i == nworkers - 1 ? ".\n" : ", ");
+ printf("%zu%s", i, i == nworkers - 1 ? ".\n" : ", ");
fflush(stdout);
}
@@ -264,7 +264,7 @@ usage:
printf("%-10s%-20s%-20s%-29s\n", "------", "--------------",
"----------", "---------------------------");
for (i = 0; i < nworkers; i++) {
- printf("%-10u%-20ju%-20ju%u:%s%.2f\n", i,
+ printf("%-10zu%-20ju%-20ju%ld:%s%.2f\n", i,
workers[i].w_lookup_success, workers[i].w_lookup_failure,
workers[i].w_max_lookup_time.tv_sec / 60,
workers[i].w_max_lookup_time.tv_sec % 60 < 10 ? "0" : "",
diff --git a/tools/regression/lib/libc/stdio/test-open_memstream.c b/tools/regression/lib/libc/stdio/test-open_memstream.c
index 1a168c6..fdbda30 100644
--- a/tools/regression/lib/libc/stdio/test-open_memstream.c
+++ b/tools/regression/lib/libc/stdio/test-open_memstream.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/tools/regression/lib/libc/stdio/test-open_wmemstream.c b/tools/regression/lib/libc/stdio/test-open_wmemstream.c
index 4cd0ab9..2a90fcd 100644
--- a/tools/regression/lib/libc/stdio/test-open_wmemstream.c
+++ b/tools/regression/lib/libc/stdio/test-open_wmemstream.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/tools/regression/mmap/Makefile b/tools/regression/mmap/Makefile
deleted file mode 100644
index c9bb5c4..0000000
--- a/tools/regression/mmap/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# $FreeBSD$
-
-PROG= mmap
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/mqueue/Makefile b/tools/regression/mqueue/Makefile
deleted file mode 100644
index a4f386b..0000000
--- a/tools/regression/mqueue/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# $FreeBSD$
-
-SUBDIR=mqtest1 mqtest2 mqtest3 mqtest4 mqtest5
-
-.include <bsd.subdir.mk>
diff --git a/tools/regression/mqueue/mqtest1/Makefile b/tools/regression/mqueue/mqtest1/Makefile
deleted file mode 100644
index 3a50cee..0000000
--- a/tools/regression/mqueue/mqtest1/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# $FreeBSD$
-
-PROG=mqtest1
-DPADD= ${LIBRT}
-LDADD= -lrt
-MAN=
-DEBUG_FLAGS=-g
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/mqueue/mqtest2/Makefile b/tools/regression/mqueue/mqtest2/Makefile
deleted file mode 100644
index 0709854..0000000
--- a/tools/regression/mqueue/mqtest2/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# $FreeBSD$
-
-PROG=mqtest2
-DPADD= ${LIBRT}
-LDADD= -lrt
-MAN=
-DEBUG_FLAGS=-g
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/mqueue/mqtest3/Makefile b/tools/regression/mqueue/mqtest3/Makefile
deleted file mode 100644
index 514cbac..0000000
--- a/tools/regression/mqueue/mqtest3/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# $FreeBSD$
-
-PROG=mqtest3
-DPADD= ${LIBRT}
-LDADD= -lrt
-MAN=
-DEBUG_FLAGS=-g
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/mqueue/mqtest4/Makefile b/tools/regression/mqueue/mqtest4/Makefile
deleted file mode 100644
index 781d76d..0000000
--- a/tools/regression/mqueue/mqtest4/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# $FreeBSD$
-
-PROG=mqtest4
-DPADD= ${LIBRT}
-LDADD= -lrt
-MAN=
-DEBUG_FLAGS=-g
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/mqueue/mqtest5/Makefile b/tools/regression/mqueue/mqtest5/Makefile
deleted file mode 100644
index d94e541..0000000
--- a/tools/regression/mqueue/mqtest5/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# $FreeBSD$
-
-PROG=mqtest5
-DPADD= ${LIBRT}
-LDADD= -lrt
-MAN=
-DEBUG_FLAGS=-g
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/netinet/arphold/arphold.c b/tools/regression/netinet/arphold/arphold.c
index 8d694fe..417a2d8 100644
--- a/tools/regression/netinet/arphold/arphold.c
+++ b/tools/regression/netinet/arphold/arphold.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Advanced Computing Technologies LLC
+ * Copyright (c) 2010 Hudson River Trading LLC
* Written by George Neville-Neil gnn@freebsd.org
* All rights reserved.
*
diff --git a/tools/regression/p1003_1b/Makefile b/tools/regression/p1003_1b/Makefile
index 8cf7d5a..902666c 100644
--- a/tools/regression/p1003_1b/Makefile
+++ b/tools/regression/p1003_1b/Makefile
@@ -14,4 +14,5 @@ SRCS=\
MAN=
CFLAGS+=-DNO_MEMLOCK
+
.include <bsd.prog.mk>
diff --git a/tools/regression/p1003_1b/fifo.c b/tools/regression/p1003_1b/fifo.c
index 455f7f9..925e7c2 100644
--- a/tools/regression/p1003_1b/fifo.c
+++ b/tools/regression/p1003_1b/fifo.c
@@ -31,17 +31,17 @@
*
* $FreeBSD$
*/
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <err.h>
-#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sched.h>
#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
volatile int ticked;
#define CAN_USE_ALARMS
@@ -109,7 +109,7 @@ int fifo(int argc, char *argv[])
fifo_param.sched_priority = 1;
p = (long *)mmap(0, sizeof(*p),
- PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED|MAP_INHERIT, -1, 0);
+ PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
if (p == (long *)-1)
err(errno, "mmap");
diff --git a/tools/regression/p1003_1b/sched.c b/tools/regression/p1003_1b/sched.c
index bd978f8..1814c79 100644
--- a/tools/regression/p1003_1b/sched.c
+++ b/tools/regression/p1003_1b/sched.c
@@ -41,16 +41,17 @@
#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 199309L
-#include <unistd.h>
-#include <stdlib.h>
-
-#include <stdio.h>
-#include <string.h>
+#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/mman.h>
-
+#include <limits.h>
#include <sched.h>
+#include <stdio.h>
+#define __XSI_VISIBLE 1
+#include <stdlib.h>
+#undef __XSI_VISIBLE
+#include <string.h>
+#include <unistd.h>
#include "prutil.h"
@@ -209,17 +210,14 @@ int sched(int ac, char *av[])
{
-#define NAM "P1003_1b_schedXXXX"
- char nam[L_tmpnam];
+ char nam[] = "P1003_1b_schedXXXXXX";
int fd;
pid_t p;
pid_t *lastrun;
- strcpy(nam, NAM);
- if (tmpnam(nam) != nam)
- q(__LINE__, errno, "tmpnam " NAM);
- q(__LINE__, (fd = open(nam, O_RDWR|O_CREAT, 0666)),
- "open " NAM);
+ fd = mkstemp(nam);
+ if (fd == -1)
+ q(__LINE__, errno, "mkstemp failed");
(void)unlink(nam);
diff --git a/tools/regression/p1003_1b/yield.c b/tools/regression/p1003_1b/yield.c
index ac31a99..a9b7bad 100644
--- a/tools/regression/p1003_1b/yield.c
+++ b/tools/regression/p1003_1b/yield.c
@@ -89,7 +89,7 @@ int yield(int argc, char *argv[])
n = nslaves = atoi(argv[1]);
p = (int *)mmap(0, sizeof(int),
- PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED|MAP_INHERIT, -1, 0);
+ PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
if (p == (int *)-1)
err(errno, "mmap");
diff --git a/tools/regression/sockets/accept_fd_leak/Makefile b/tools/regression/sockets/accept_fd_leak/Makefile
index 208df0d..e9bfba6 100644
--- a/tools/regression/sockets/accept_fd_leak/Makefile
+++ b/tools/regression/sockets/accept_fd_leak/Makefile
@@ -4,8 +4,6 @@
PROG= accept_fd_leak
MAN=
-
-regress:
- ./accept_fd_leak
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c b/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c
index 32d4edf..659c22d 100644
--- a/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c
+++ b/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c
@@ -26,7 +26,7 @@
* $FreeBSD$
*/
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
@@ -41,13 +41,16 @@
#include <string.h>
#include <unistd.h>
+#define BIND_ATTEMPTS 10
#define LOOPS 500
+#define NUM_ATTEMPTS 1000
-volatile int quit;
+static volatile int quit;
static void
-child_died(int sig)
+child_died(int sig __unused)
{
+
quit = 1;
}
@@ -59,13 +62,12 @@ child_died(int sig)
* briefly before beginning (not 100% reliable, but a good start).
*/
int
-main(int argc, char *argv[])
+main(void)
{
struct sockaddr_in sin;
socklen_t size;
pid_t child;
- int fd1, fd2, fd3, i, s;
- int status;
+ int fd1, fd2, fd3, i, listen_port, s, status;
printf("1..2\n");
@@ -85,10 +87,22 @@ main(int argc, char *argv[])
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- sin.sin_port = htons(8080);
- if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) != 0)
- errx(-1, "bind: %s", strerror(errno));
+ srandomdev();
+
+ for (i = 0; i < BIND_ATTEMPTS; i++) {
+ /* Pick a random unprivileged port 1025-65535 */
+ listen_port = MAX((int)random() % 65535, 1025);
+ sin.sin_port = htons(listen_port);
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0)
+ break;
+ warn("bind with %d failed", listen_port);
+ usleep(1000);
+ }
+ if (i >= BIND_ATTEMPTS) {
+ printf("Bail out!\n");
+ exit(1);
+ }
if (listen(s, -1) != 0)
errx(-1, "listen: %s", strerror(errno));
@@ -134,16 +148,20 @@ main(int argc, char *argv[])
errx(-1, "fork: %s", strerror(errno));
/*
- * Child process does 1000 connect's.
+ * Child process does `NUM_ATTEMPTS` connects.
*/
if (child == 0) {
+ close(fd1);
+ close(fd2);
+ close(s);
+
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- sin.sin_port = htons(8080);
+ sin.sin_port = htons(listen_port);
- for (i = 0; i < 1000; i++) {
+ for (i = 0; i < NUM_ATTEMPTS; i++) {
s = socket(PF_INET, SOCK_STREAM, 0);
if (s == -1)
errx(-1, "socket: %s", strerror(errno));
@@ -152,7 +170,7 @@ main(int argc, char *argv[])
errx(-1, "connect: %s", strerror(errno));
close(s);
}
- exit(0);
+ _exit(0);
}
/* Reset back to a blocking socket. */
@@ -167,9 +185,9 @@ main(int argc, char *argv[])
errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
if (i & O_NONBLOCK)
errx(-1, "Failed to clear O_NONBLOCK (i=0x%x)\n", i);
-
- /* Do 1000 accept's with an invalid pointer. */
- for (i = 0; !quit && i < 1000; i++) {
+
+ /* Do `NUM_ATTEMPTS` accepts with an invalid pointer. */
+ for (i = 0; !quit && i < NUM_ATTEMPTS; i++) {
size = sizeof(sin);
if (accept(s, (struct sockaddr *)(uintptr_t)(0x100),
&size) != -1)
@@ -182,7 +200,7 @@ main(int argc, char *argv[])
errx(-1, "waitpid: %s", strerror(errno));
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
warnx("child process died");
-
+
/*
* Allocate a file descriptor and make sure it's fd2+2. 2 because
* we allocate an fd for the socket.
diff --git a/tools/regression/sockets/accf_data_attach/Makefile b/tools/regression/sockets/accf_data_attach/Makefile
index 75ed46b..4d33728 100644
--- a/tools/regression/sockets/accf_data_attach/Makefile
+++ b/tools/regression/sockets/accf_data_attach/Makefile
@@ -4,8 +4,6 @@
PROG= accf_data_attach
MAN=
-
-accf_data_attach: accf_data_attach.c
- gcc -Wall -o accf_data_attach accf_data_attach.c
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/accf_data_attach/accf_data_attach.c b/tools/regression/sockets/accf_data_attach/accf_data_attach.c
index 369481e..59ea68c 100644
--- a/tools/regression/sockets/accf_data_attach/accf_data_attach.c
+++ b/tools/regression/sockets/accf_data_attach/accf_data_attach.c
@@ -58,7 +58,7 @@
* make sure it is removed.
*/
int
-main(int argc, char *argv[])
+main(void)
{
struct accept_filter_arg afa;
struct sockaddr_in sin;
diff --git a/tools/regression/sockets/fstat/Makefile b/tools/regression/sockets/fstat/Makefile
index 28282ca..a583166 100644
--- a/tools/regression/sockets/fstat/Makefile
+++ b/tools/regression/sockets/fstat/Makefile
@@ -4,6 +4,6 @@
PROG= fstat
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/fstat/fstat.c b/tools/regression/sockets/fstat/fstat.c
index 2534f78..6ea931d 100644
--- a/tools/regression/sockets/fstat/fstat.c
+++ b/tools/regression/sockets/fstat/fstat.c
@@ -57,7 +57,7 @@ dotest(int domain, int type, int protocol)
}
int
-main(int argc, char *argv[])
+main(void)
{
dotest(PF_INET, SOCK_DGRAM, 0);
diff --git a/tools/regression/sockets/kqueue/Makefile b/tools/regression/sockets/kqueue/Makefile
index e37eadf..6771d25 100644
--- a/tools/regression/sockets/kqueue/Makefile
+++ b/tools/regression/sockets/kqueue/Makefile
@@ -4,5 +4,6 @@
PROG= kqueue
MAN=
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/kqueue/kqueue.c b/tools/regression/sockets/kqueue/kqueue.c
index d46db96..f73704a 100644
--- a/tools/regression/sockets/kqueue/kqueue.c
+++ b/tools/regression/sockets/kqueue/kqueue.c
@@ -250,9 +250,9 @@ test_evfilt_write(int kq, int fd[2], const char *socktype)
* sockets, and confirm that we can register for various events on them.
*/
int
-main(int argc, char *argv[])
+main(void)
{
- int i, kq, sv[2];
+ int kq, sv[2];
printf("1..49\n");
diff --git a/tools/regression/sockets/listen_backlog/Makefile b/tools/regression/sockets/listen_backlog/Makefile
index c7171ec..e2eb135 100644
--- a/tools/regression/sockets/listen_backlog/Makefile
+++ b/tools/regression/sockets/listen_backlog/Makefile
@@ -1,7 +1,7 @@
# $FreeBSD$
PROG= listen_backlog
-WARNS?= 3
MAN=
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/listen_backlog/listen_backlog.c b/tools/regression/sockets/listen_backlog/listen_backlog.c
index be170ab..2276393 100644
--- a/tools/regression/sockets/listen_backlog/listen_backlog.c
+++ b/tools/regression/sockets/listen_backlog/listen_backlog.c
@@ -218,7 +218,8 @@ test_defaults(void)
* the first and second listen().
*/
static int
-socket_listen_update(int domain, int type, int protocol, int backlog,
+socket_listen_update(int domain __unused, int type __unused,
+ int protocol __unused, int backlog,
int update_backlog, int listen_backlog_assertion,
int update_backlog_assertion, int *sockp, const char *domainstring,
const char *typestring, const char *testclass, const char *test)
@@ -365,7 +366,7 @@ test_set_qlimit(void)
}
int
-main(int argc, char *argv[])
+main(void)
{
size_t len;
diff --git a/tools/regression/sockets/listenclose/Makefile b/tools/regression/sockets/listenclose/Makefile
index 1e146dc..8f4dc4e 100644
--- a/tools/regression/sockets/listenclose/Makefile
+++ b/tools/regression/sockets/listenclose/Makefile
@@ -4,6 +4,6 @@
PROG= listenclose
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/listenclose/listenclose.c b/tools/regression/sockets/listenclose/listenclose.c
index 425e39f..f920846 100644
--- a/tools/regression/sockets/listenclose/listenclose.c
+++ b/tools/regression/sockets/listenclose/listenclose.c
@@ -52,7 +52,7 @@
*/
int
-main(int argc, char *argv[])
+main(void)
{
int listen_sock, connect_sock;
struct sockaddr_in sin;
diff --git a/tools/regression/sockets/pr_atomic/Makefile b/tools/regression/sockets/pr_atomic/Makefile
index b7ed9a6..1dc85ff 100644
--- a/tools/regression/sockets/pr_atomic/Makefile
+++ b/tools/regression/sockets/pr_atomic/Makefile
@@ -2,6 +2,6 @@
PROG= pr_atomic
MAN=
-WARNS?= 3
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/pr_atomic/pr_atomic.c b/tools/regression/sockets/pr_atomic/pr_atomic.c
index 69bbac7..e902cf7 100644
--- a/tools/regression/sockets/pr_atomic/pr_atomic.c
+++ b/tools/regression/sockets/pr_atomic/pr_atomic.c
@@ -42,31 +42,31 @@
#include <errno.h>
#include <unistd.h>
-#define TEST_SOCKET "/tmp/test_socket"
+static char socket_path[] = "tmp.XXXXXX";
static jmp_buf myjmpbuf;
-void handle_sigalrm(int signo);
-
-void handle_sigalrm(int signo)
+static void handle_sigalrm(int signo __unused)
{
longjmp(myjmpbuf, 1);
}
int
-main(int argc, char *argv[])
+main(void)
{
struct sockaddr_un un;
pid_t pid;
int s;
+ if (mkstemp(socket_path) == -1)
+ err(1, "mkstemp");
s = socket(PF_LOCAL, SOCK_DGRAM, 0);
if (s == -1)
errx(-1, "socket");
memset(&un, 0, sizeof(un));
un.sun_family = AF_LOCAL;
- unlink(TEST_SOCKET);
- strcpy(un.sun_path, TEST_SOCKET);
+ unlink(socket_path);
+ strcpy(un.sun_path, socket_path);
if (bind(s, (struct sockaddr *)&un, sizeof(un)) == -1)
errx(-1, "bind");
pid = fork();
diff --git a/tools/regression/sockets/reconnect/Makefile b/tools/regression/sockets/reconnect/Makefile
index edd6b47..d8fa5e0 100644
--- a/tools/regression/sockets/reconnect/Makefile
+++ b/tools/regression/sockets/reconnect/Makefile
@@ -4,6 +4,6 @@
PROG= reconnect
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/reconnect/reconnect.c b/tools/regression/sockets/reconnect/reconnect.c
index 02922bf..27f32cc 100644
--- a/tools/regression/sockets/reconnect/reconnect.c
+++ b/tools/regression/sockets/reconnect/reconnect.c
@@ -45,12 +45,12 @@
#include <string.h>
#include <unistd.h>
-static char *uds_name1 = NULL;
-static char *uds_name2 = NULL;
+static char uds_name1[] = "reconnect.XXXXXXXX";
+static char uds_name2[] = "reconnect.XXXXXXXX";
#define sstosa(ss) ((struct sockaddr *)(ss))
-void
+static void
prepare_ifsun(struct sockaddr_un *ifsun, const char *path)
{
@@ -62,7 +62,7 @@ prepare_ifsun(struct sockaddr_un *ifsun, const char *path)
strcpy(ifsun->sun_path, path);
}
-int
+static int
create_uds_server(const char *path)
{
struct sockaddr_un ifsun;
@@ -82,7 +82,7 @@ create_uds_server(const char *path)
return sock;
}
-void
+static void
connect_uds_server(int sock, const char *path)
{
struct sockaddr_un ifsun;
@@ -95,14 +95,12 @@ connect_uds_server(int sock, const char *path)
err(1, "can't connect to a socket");
}
-void
+static void
cleanup(void)
{
- if (uds_name1 != NULL)
- unlink(uds_name1);
- if (uds_name2 != NULL)
- unlink(uds_name2);
+ unlink(uds_name1);
+ unlink(uds_name2);
}
int
@@ -112,20 +110,14 @@ main()
atexit(cleanup);
- uds_name1 = strdup("/tmp/reconnect.XXXXXX");
- if (uds_name1 == NULL)
- err(1, "can't allocate memory");
- uds_name1 = mktemp(uds_name1);
- if (uds_name1 == NULL)
- err(1, "mktemp(3) failed");
+ if (mkstemp(uds_name1) == -1)
+ err(1, "mkstemp");
+ unlink(uds_name1);
s_sock1 = create_uds_server(uds_name1);
- uds_name2 = strdup("/tmp/reconnect.XXXXXX");
- if (uds_name2 == NULL)
- err(1, "can't allocate memory");
- uds_name2 = mktemp(uds_name2);
- if (uds_name2 == NULL)
- err(1, "mktemp(3) failed");
+ if (mkstemp(uds_name2) == -1)
+ err(1, "mkstemp");
+ unlink(uds_name2);
s_sock2 = create_uds_server(uds_name2);
c_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
diff --git a/tools/regression/sockets/rtsocket/Makefile b/tools/regression/sockets/rtsocket/Makefile
index 13a1238..f68b6c3 100644
--- a/tools/regression/sockets/rtsocket/Makefile
+++ b/tools/regression/sockets/rtsocket/Makefile
@@ -2,6 +2,6 @@
PROG= rtsocket
MAN=
-WARNS?= 3
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/rtsocket/rtsocket.c b/tools/regression/sockets/rtsocket/rtsocket.c
index 6a0738b..b5824b3 100644
--- a/tools/regression/sockets/rtsocket/rtsocket.c
+++ b/tools/regression/sockets/rtsocket/rtsocket.c
@@ -41,7 +41,7 @@
#include <unistd.h>
int
-main(int argc, char *argv[])
+main(void)
{
int sock, socks[2];
diff --git a/tools/regression/sockets/sblock/Makefile b/tools/regression/sockets/sblock/Makefile
index af8d0e4..aa2f890 100644
--- a/tools/regression/sockets/sblock/Makefile
+++ b/tools/regression/sockets/sblock/Makefile
@@ -4,6 +4,6 @@
PROG= sblock
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/sblock/sblock.c b/tools/regression/sockets/sblock/sblock.c
index a9f9518..415c4d4 100644
--- a/tools/regression/sockets/sblock/sblock.c
+++ b/tools/regression/sockets/sblock/sblock.c
@@ -54,7 +54,7 @@
static int interrupted;
static void
-signal_handler(int signum)
+signal_handler(int signum __unused)
{
interrupted++;
@@ -95,7 +95,7 @@ locking_recver(int fd)
ssize_t len;
char ch;
- if (sleep(1) < 0)
+ if (sleep(1) != 0)
err(-1, "FAIL: locking_recver: sleep");
len = recv(fd, &ch, sizeof(ch), 0);
if (len < 0 && errno != EINTR)
@@ -116,7 +116,7 @@ signaller(pid_t locking_recver_pid, int fd)
ssize_t len;
char ch;
- if (sleep(2) < 0) {
+ if (sleep(2) != 0) {
warn("signaller sleep(2)");
return;
}
@@ -124,7 +124,7 @@ signaller(pid_t locking_recver_pid, int fd)
warn("signaller kill(%d)", locking_recver_pid);
return;
}
- if (sleep(1) < 0) {
+ if (sleep(1) != 0) {
warn("signaller sleep(1)");
return;
}
@@ -141,14 +141,14 @@ signaller(pid_t locking_recver_pid, int fd)
warn("signaller close");
return;
}
- if (sleep(1) < 0) {
+ if (sleep(1) != 0) {
warn("signaller sleep(1)");
return;
}
}
int
-main(int argc, char *argv[])
+main(void)
{
int error, fds[2], recver_fd, sender_fd;
pid_t blocking_recver_pid;
diff --git a/tools/regression/sockets/sendfile/sendfile.c b/tools/regression/sockets/sendfile/sendfile.c
index 73033d7..18ae9ad 100644
--- a/tools/regression/sockets/sendfile/sendfile.c
+++ b/tools/regression/sockets/sendfile/sendfile.c
@@ -452,8 +452,8 @@ run_parent(void)
static void
cleanup(void)
{
- if (*path != '\0')
- unlink(path);
+
+ unlink(path);
}
int
@@ -461,12 +461,12 @@ main(int argc, char *argv[])
{
int pagesize;
- *path = '\0';
+ path[0] = '\0';
pagesize = getpagesize();
if (argc == 1) {
- snprintf(path, PATH_MAX, "/tmp/sendfile.XXXXXXXXXXXX");
+ snprintf(path, sizeof(path), "sendfile.XXXXXXXXXXXX");
file_fd = mkstemp(path);
if (file_fd == -1)
FAIL_ERR("mkstemp");
diff --git a/tools/regression/sockets/shutdown/Makefile b/tools/regression/sockets/shutdown/Makefile
index 07ba65d..63045f5 100644
--- a/tools/regression/sockets/shutdown/Makefile
+++ b/tools/regression/sockets/shutdown/Makefile
@@ -4,6 +4,6 @@
PROG= shutdown
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/shutdown/shutdown.c b/tools/regression/sockets/shutdown/shutdown.c
index c4e884d..3d23c94 100644
--- a/tools/regression/sockets/shutdown/shutdown.c
+++ b/tools/regression/sockets/shutdown/shutdown.c
@@ -45,6 +45,8 @@ main(void)
int listen_sock, connect_sock;
u_short port;
+ listen_sock = -1;
+
/* Shutdown(2) on an invalid file descriptor has to return EBADF. */
if ((shutdown(listen_sock, SHUT_RDWR) != -1) && (errno != EBADF))
errx(-1, "shutdown() for invalid file descriptor does not "
diff --git a/tools/regression/sockets/sigpipe/Makefile b/tools/regression/sockets/sigpipe/Makefile
index 030703e..5116701 100644
--- a/tools/regression/sockets/sigpipe/Makefile
+++ b/tools/regression/sockets/sigpipe/Makefile
@@ -4,6 +4,6 @@
PROG= sigpipe
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/sigpipe/sigpipe.c b/tools/regression/sockets/sigpipe/sigpipe.c
index 641536a..894d9de 100644
--- a/tools/regression/sockets/sigpipe/sigpipe.c
+++ b/tools/regression/sockets/sigpipe/sigpipe.c
@@ -69,7 +69,7 @@ got_signal(void)
}
static void
-signal_handler(int signum)
+signal_handler(int signum __unused)
{
signaled = 1;
diff --git a/tools/regression/sockets/so_setfib/Makefile b/tools/regression/sockets/so_setfib/Makefile
index fc12745..90111fb 100644
--- a/tools/regression/sockets/so_setfib/Makefile
+++ b/tools/regression/sockets/so_setfib/Makefile
@@ -1,14 +1,16 @@
# $FreeBSD$
+.include <src.opts.mk>
+
PROG= so_setfib
MAN=
WARNS?= 6
-.ifdef INET6
-CFLAGS+= -DINET6
-.endif
-.ifdef INET
+.if ${MK_INET} != "no"
CFLAGS+= -DINET
.endif
+.if ${MK_INET6} != "no"
+CFLAGS+= -DINET6
+.endif
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/so_setfib/so_setfib.c b/tools/regression/sockets/so_setfib/so_setfib.c
index 3c07852..50cb020 100644
--- a/tools/regression/sockets/so_setfib/so_setfib.c
+++ b/tools/regression/sockets/so_setfib/so_setfib.c
@@ -45,6 +45,7 @@
* 5. Repeat for next domain family and type from (2) on.
*/
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
@@ -143,6 +144,7 @@ t(u_int dom, u_int type)
if (s == -1) {
printf("not ok %d %s_%s # socket(): %s\n", testno,
t_dom[dom].name, t_type[type].name, strerror(errno));
+ testno++;
return;
}
@@ -168,6 +170,11 @@ main(int argc __unused, char *argv[] __unused)
u_int i, j;
size_t s;
+ if (geteuid() != 0) {
+ printf("1..0 # SKIP: must be root");
+ return (0);
+ }
+
/* Initalize randomness. */
srandomdev();
@@ -175,6 +182,10 @@ main(int argc __unused, char *argv[] __unused)
s = sizeof(rt_numfibs);
if (sysctlbyname("net.fibs", &rt_numfibs, &s, NULL, 0) == -1)
err(1, "sysctlbyname(net.fibs, ..)");
+
+ printf("1..%lu\n",
+ (nitems(t_dom) - 1) * nitems(t_type) * (2 + rt_numfibs + 2 + 3));
+
/* Adjust from number to index. */
rt_numfibs -= 1;
diff --git a/tools/regression/sockets/socketpair/Makefile b/tools/regression/sockets/socketpair/Makefile
index ae71b17..ed66e3c 100644
--- a/tools/regression/sockets/socketpair/Makefile
+++ b/tools/regression/sockets/socketpair/Makefile
@@ -4,6 +4,6 @@
PROG= socketpair
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/socketpair/socketpair.c b/tools/regression/sockets/socketpair/socketpair.c
index 5f46476..779878a 100644
--- a/tools/regression/sockets/socketpair/socketpair.c
+++ b/tools/regression/sockets/socketpair/socketpair.c
@@ -47,7 +47,7 @@
* right places.
*/
int
-main(int argc, char *argv[])
+main(void)
{
int fd1, fd2, fd3;
int sv[2];
diff --git a/tools/regression/sockets/unix_bindconnect/Makefile b/tools/regression/sockets/unix_bindconnect/Makefile
index 2c4edfd..52cc844 100644
--- a/tools/regression/sockets/unix_bindconnect/Makefile
+++ b/tools/regression/sockets/unix_bindconnect/Makefile
@@ -2,6 +2,6 @@
PROG= unix_bindconnect
MAN=
-WARNS?= 2
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c b/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c
index 7db82a0..079dc4d 100644
--- a/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c
+++ b/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c
@@ -54,8 +54,8 @@
#define UNWIND_MAX 1024
-int unwind_len;
-struct unwind {
+static int unwind_len;
+static struct unwind {
char u_path[PATH_MAX];
} unwind_list[UNWIND_MAX];
@@ -105,7 +105,7 @@ bind_test(const char *directory_path)
sun.sun_len = sizeof(sun);
sun.sun_family = AF_UNIX;
if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path)
- >= sizeof(sun.sun_path)) {
+ >= (int)sizeof(sun.sun_path)) {
warn("bind_test: snprintf(sun.sun_path)");
close(sock1);
return (-1);
@@ -216,7 +216,7 @@ connect_test(const char *directory_path)
sun.sun_len = sizeof(sun);
sun.sun_family = AF_UNIX;
if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path)
- >= sizeof(sun.sun_path)) {
+ >= (int)sizeof(sun.sun_path)) {
warn("connect_test: snprintf(sun.sun_path)");
close(sock1);
return (-1);
@@ -298,7 +298,7 @@ connect_test(const char *directory_path)
return (0);
}
int
-main(int argc, char *argv[])
+main(void)
{
char directory_path[PATH_MAX];
int error;
diff --git a/tools/regression/sockets/unix_close_race/Makefile b/tools/regression/sockets/unix_close_race/Makefile
index 8b9f792..370adc4 100644
--- a/tools/regression/sockets/unix_close_race/Makefile
+++ b/tools/regression/sockets/unix_close_race/Makefile
@@ -2,6 +2,6 @@
PROG= unix_close_race
MAN=
-WARNS?= 3
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_close_race/unix_close_race.c b/tools/regression/sockets/unix_close_race/unix_close_race.c
index 97783e3..89c1b20 100644
--- a/tools/regression/sockets/unix_close_race/unix_close_race.c
+++ b/tools/regression/sockets/unix_close_race/unix_close_race.c
@@ -54,12 +54,13 @@
#include <unistd.h>
#include <err.h>
-#define UNIXSTR_PATH "/tmp/mytest.socket"
+static char socket_path[] = "tmp.XXXXXXXX";
+
#define USLEEP 100
#define LOOPS 100000
int
-main(int argc, char **argv)
+main(void)
{
struct sockaddr_un servaddr;
int listenfd, connfd, pid;
@@ -74,16 +75,20 @@ main(int argc, char **argv)
if (ncpus < 2)
warnx("SMP not present, test may be unable to trigger race");
+ if (mkstemp(socket_path) == -1)
+ err(1, "mkstemp failed");
+ unlink(socket_path);
+
/*
* Create a UNIX domain socket that the child will repeatedly
* accept() from, and that the parent will repeatedly connect() to.
*/
if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
err(1, "parent: socket error");
- (void)unlink(UNIXSTR_PATH);
+ (void)unlink(socket_path);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
- strcpy(servaddr.sun_path, UNIXSTR_PATH);
+ strcpy(servaddr.sun_path, socket_path);
if (bind(listenfd, (struct sockaddr *) &servaddr,
sizeof(servaddr)) < 0)
err(1, "parent: bind error");
@@ -102,7 +107,7 @@ main(int argc, char **argv)
sleep(1);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
- strcpy(servaddr.sun_path, UNIXSTR_PATH);
+ strcpy(servaddr.sun_path, socket_path);
for (counter = 0; counter < LOOPS; counter++) {
if ((connfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
(void)kill(pid, SIGTERM);
diff --git a/tools/regression/sockets/unix_passfd/Makefile b/tools/regression/sockets/unix_passfd/Makefile
index 77c6b03..600b7b1 100644
--- a/tools/regression/sockets/unix_passfd/Makefile
+++ b/tools/regression/sockets/unix_passfd/Makefile
@@ -2,6 +2,6 @@
PROG= unix_passfd
MAN=
-WARNS?= 2
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_passfd/unix_passfd.c b/tools/regression/sockets/unix_passfd/unix_passfd.c
index cc0acaa..07ef589 100644
--- a/tools/regression/sockets/unix_passfd/unix_passfd.c
+++ b/tools/regression/sockets/unix_passfd/unix_passfd.c
@@ -139,7 +139,7 @@ sendfd_payload(const char *test, int sockfd, int sendfd,
len = sendmsg(sockfd, &msghdr, 0);
if (len < 0)
err(-1, "%s: sendmsg", test);
- if (len != paylen)
+ if ((size_t)len != paylen)
errx(-1, "%s: sendmsg: %zd bytes sent", test, len);
}
@@ -175,7 +175,7 @@ recvfd_payload(const char *test, int sockfd, int *recvfd,
len = recvmsg(sockfd, &msghdr, 0);
if (len < 0)
err(-1, "%s: recvmsg", test);
- if (len != buflen)
+ if ((size_t)len != buflen)
errx(-1, "%s: recvmsg: %zd bytes received", test, len);
cmsghdr = CMSG_FIRSTHDR(&msghdr);
@@ -205,7 +205,7 @@ recvfd(const char *test, int sockfd, int *recvfd)
}
int
-main(int argc, char *argv[])
+main(void)
{
struct stat putfd_1_stat, putfd_2_stat, getfd_1_stat, getfd_2_stat;
int fd[2], putfd_1, putfd_2, getfd_1, getfd_2;
@@ -354,7 +354,7 @@ main(int argc, char *argv[])
* payload. Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer
* limit, and receiver receives truncated data.
*/
- test = "test8-rigths+creds+payload";
+ test = "test8-rights+creds+payload";
printf("beginning %s\n", test);
{
diff --git a/tools/regression/sockets/unix_sendtorace/Makefile b/tools/regression/sockets/unix_sendtorace/Makefile
index 0b18376..75e7b9f 100644
--- a/tools/regression/sockets/unix_sendtorace/Makefile
+++ b/tools/regression/sockets/unix_sendtorace/Makefile
@@ -2,6 +2,6 @@
PROG= unix_sendtorace
MAN=
-WARNS?= 3
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c b/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c
index 2445b81..9fd748d 100644
--- a/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c
+++ b/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c
@@ -45,9 +45,10 @@
#include <string.h>
#include <unistd.h>
-#define PATH "/tmp/123"
#define ITERATIONS 1000000
+static char socket_path[] = "tmp.XXXXXX";
+
static void
stream_server(int listenfd)
{
@@ -75,7 +76,7 @@ stream_client(void)
bzero(&sun, sizeof(sun));
sun.sun_len = sizeof(sun);
sun.sun_family = AF_UNIX;
- strcpy(sun.sun_path, PATH);
+ strcpy(sun.sun_path, socket_path);
for (i = 0; i < ITERATIONS; i++) {
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
@@ -104,7 +105,7 @@ stream_test(void)
bzero(&sun, sizeof(sun));
sun.sun_len = sizeof(sun);
sun.sun_family = AF_UNIX;
- strcpy(sun.sun_path, PATH);
+ strcpy(sun.sun_path, socket_path);
if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
err(-1, "stream_test: bind");
@@ -124,7 +125,7 @@ stream_test(void)
} else
stream_server(listenfd);
- (void)unlink(PATH);
+ (void)unlink(socket_path);
}
static void
@@ -151,7 +152,7 @@ datagram_client(void)
bzero(&sun, sizeof(sun));
sun.sun_len = sizeof(sun);
sun.sun_family = AF_UNIX;
- strcpy(sun.sun_path, PATH);
+ strcpy(sun.sun_path, socket_path);
for (i = 0; i < ITERATIONS; i++) {
fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
@@ -180,7 +181,7 @@ datagram_test(void)
bzero(&sun, sizeof(sun));
sun.sun_len = sizeof(sun);
sun.sun_family = AF_UNIX;
- strcpy(sun.sun_path, PATH);
+ strcpy(sun.sun_path, socket_path);
if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
err(-1, "datagram_test: bind");
@@ -197,14 +198,16 @@ datagram_test(void)
} else
datagram_server(serverfd);
- (void)unlink(PATH);
+ (void)unlink(socket_path);
}
int
-main(int argc, char *argv[])
+main(void)
{
-
- (void)unlink(PATH);
+
+ if (mkstemp(socket_path) == -1)
+ err(1, "mkstemp failed");
+ (void)unlink(socket_path);
datagram_test();
if (0)
stream_test();
diff --git a/tools/regression/sockets/unix_socket/Makefile b/tools/regression/sockets/unix_socket/Makefile
index 40f6b92..bb60456 100644
--- a/tools/regression/sockets/unix_socket/Makefile
+++ b/tools/regression/sockets/unix_socket/Makefile
@@ -2,6 +2,6 @@
PROG= unix_socket
MAN=
-WARNS?= 3
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_socket/unix_socket.c b/tools/regression/sockets/unix_socket/unix_socket.c
index 24b6baf..085366f 100644
--- a/tools/regression/sockets/unix_socket/unix_socket.c
+++ b/tools/regression/sockets/unix_socket/unix_socket.c
@@ -40,7 +40,7 @@
#include <unistd.h>
int
-main(int argc, char *argv[])
+main(void)
{
int sock, socks[2];
diff --git a/tools/regression/sockets/unix_sorflush/Makefile b/tools/regression/sockets/unix_sorflush/Makefile
index 237eb3d..db0aa6a 100644
--- a/tools/regression/sockets/unix_sorflush/Makefile
+++ b/tools/regression/sockets/unix_sorflush/Makefile
@@ -2,6 +2,6 @@
PROG= unix_sorflush
MAN=
-WARNS?= 3
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_sorflush/unix_sorflush.c b/tools/regression/sockets/unix_sorflush/unix_sorflush.c
index 126de2f..e0deb00 100644
--- a/tools/regression/sockets/unix_sorflush/unix_sorflush.c
+++ b/tools/regression/sockets/unix_sorflush/unix_sorflush.c
@@ -68,7 +68,7 @@ shutdown_and_exit(int s)
}
int
-main(int argc, char *argv[])
+main(void)
{
pid_t pida, pidb;
int sv[2];
diff --git a/tools/regression/sockets/zerosend/zerosend.c b/tools/regression/sockets/zerosend/zerosend.c
index a42ec51..1f3217a 100644
--- a/tools/regression/sockets/zerosend/zerosend.c
+++ b/tools/regression/sockets/zerosend/zerosend.c
@@ -209,12 +209,12 @@ setup_pipe(const char *test, int *fdp)
static void
setup_fifo(const char *test, int *fdp)
{
- char path[PATH_MAX];
+ char path[] = "0send_fifo.XXXXXXX";
int fd1, fd2;
- strcpy(path, "/tmp/0send_fifo.XXXXXXX");
- if (mktemp(path) == NULL)
+ if (mkstemp(path) == -1)
err(-1, "%s: setup_fifo: mktemp", test);
+ unlink(path);
if (mkfifo(path, 0600) < 0)
err(-1, "%s: setup_fifo: mkfifo(%s)", test, path);
diff --git a/tools/tools/ath/athratestats/main.c b/tools/tools/ath/athratestats/main.c
index 815ed91..3881e85 100644
--- a/tools/tools/ath/athratestats/main.c
+++ b/tools/tools/ath/athratestats/main.c
@@ -38,7 +38,6 @@
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_media.h>
-#include <net/if_var.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/tools/tools/ath/athstats/athstats.c b/tools/tools/ath/athstats/athstats.c
index 10b2f1f..82b5620 100644
--- a/tools/tools/ath/athstats/athstats.c
+++ b/tools/tools/ath/athstats/athstats.c
@@ -796,10 +796,12 @@ ath_get_totstat(struct bsdstat *sf, int s, char b[], size_t bs)
switch (s) {
case S_INPUT:
snprintf(b, bs, "%lu",
- wf->total.ath.ast_rx_packets - wf->total.ath.ast_rx_mgt);
+ (unsigned long) wf->total.ath.ast_rx_packets -
+ (unsigned long) wf->total.ath.ast_rx_mgt);
return 1;
case S_OUTPUT:
- snprintf(b, bs, "%lu", wf->total.ath.ast_tx_packets);
+ snprintf(b, bs, "%lu",
+ (unsigned long) wf->total.ath.ast_tx_packets);
return 1;
case S_RATE:
snprintrate(b, bs, wf->total.ath.ast_tx_rate);
diff --git a/tools/tools/cxgbtool/cxgbtool.c b/tools/tools/cxgbtool/cxgbtool.c
index f73f1a4..8eaaf28 100644
--- a/tools/tools/cxgbtool/cxgbtool.c
+++ b/tools/tools/cxgbtool/cxgbtool.c
@@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$");
#include <arpa/inet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_types.h>
#include <sys/endian.h>
diff --git a/tools/tools/iwn/iwnstats/iwn_ioctl.c b/tools/tools/iwn/iwnstats/iwn_ioctl.c
index 13c6153..97b2a91 100644
--- a/tools/tools/iwn/iwnstats/iwn_ioctl.c
+++ b/tools/tools/iwn/iwnstats/iwn_ioctl.c
@@ -38,7 +38,6 @@
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
-#include <net/if_var.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/tools/tools/netmap/pkt-gen.c b/tools/tools/netmap/pkt-gen.c
index 3afb326..6d9bee6 100644
--- a/tools/tools/netmap/pkt-gen.c
+++ b/tools/tools/netmap/pkt-gen.c
@@ -183,6 +183,8 @@ struct glob_arg {
#define OPT_DUMP 64 /* dump rx/tx traffic */
#define OPT_MONITOR_TX 128
#define OPT_MONITOR_RX 256
+#define OPT_RANDOM_SRC 512
+#define OPT_RANDOM_DST 1024
int dev_type;
#ifndef NO_PCAP
pcap_t *p;
@@ -567,32 +569,44 @@ update_addresses(struct pkt *pkt, struct glob_arg *g)
struct udphdr *udp = &pkt->udp;
do {
- p = ntohs(udp->uh_sport);
- if (p < g->src_ip.port1) { /* just inc, no wrap */
- udp->uh_sport = htons(p + 1);
- break;
- }
- udp->uh_sport = htons(g->src_ip.port0);
+ /* XXX for now it doesn't handle non-random src, random dst */
+ if (g->options & OPT_RANDOM_SRC) {
+ udp->uh_sport = random();
+ ip->ip_src.s_addr = random();
+ } else {
+ p = ntohs(udp->uh_sport);
+ if (p < g->src_ip.port1) { /* just inc, no wrap */
+ udp->uh_sport = htons(p + 1);
+ break;
+ }
+ udp->uh_sport = htons(g->src_ip.port0);
- a = ntohl(ip->ip_src.s_addr);
- if (a < g->src_ip.end) { /* just inc, no wrap */
- ip->ip_src.s_addr = htonl(a + 1);
- break;
- }
- ip->ip_src.s_addr = htonl(g->src_ip.start);
+ a = ntohl(ip->ip_src.s_addr);
+ if (a < g->src_ip.end) { /* just inc, no wrap */
+ ip->ip_src.s_addr = htonl(a + 1);
+ break;
+ }
+ ip->ip_src.s_addr = htonl(g->src_ip.start);
- udp->uh_sport = htons(g->src_ip.port0);
- p = ntohs(udp->uh_dport);
- if (p < g->dst_ip.port1) { /* just inc, no wrap */
- udp->uh_dport = htons(p + 1);
- break;
+ udp->uh_sport = htons(g->src_ip.port0);
}
- udp->uh_dport = htons(g->dst_ip.port0);
- a = ntohl(ip->ip_dst.s_addr);
- if (a < g->dst_ip.end) { /* just inc, no wrap */
- ip->ip_dst.s_addr = htonl(a + 1);
- break;
+ if (g->options & OPT_RANDOM_DST) {
+ udp->uh_dport = random();
+ ip->ip_dst.s_addr = random();
+ } else {
+ p = ntohs(udp->uh_dport);
+ if (p < g->dst_ip.port1) { /* just inc, no wrap */
+ udp->uh_dport = htons(p + 1);
+ break;
+ }
+ udp->uh_dport = htons(g->dst_ip.port0);
+
+ a = ntohl(ip->ip_dst.s_addr);
+ if (a < g->dst_ip.end) { /* just inc, no wrap */
+ ip->ip_dst.s_addr = htonl(a + 1);
+ break;
+ }
}
ip->ip_dst.s_addr = htonl(g->dst_ip.start);
} while (0);
@@ -1394,7 +1408,9 @@ usage(void)
"\t-R rate in packets per second\n"
"\t-X dump payload\n"
"\t-H len add empty virtio-net-header with size 'len'\n"
- "\t-P file load packet from pcap file"
+ "\t-P file load packet from pcap file\n"
+ "\t-z use random IPv4 src address/port\n"
+ "\t-Z use random IPv4 dst address/port\n"
"",
cmd);
@@ -1667,7 +1683,7 @@ main(int arc, char **argv)
g.virt_header = 0;
while ( (ch = getopt(arc, argv,
- "a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:m:P:")) != -1) {
+ "a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:m:P:zZ")) != -1) {
struct sf *fn;
switch(ch) {
@@ -1813,8 +1829,13 @@ main(int arc, char **argv)
case 'P':
g.packet_file = strdup(optarg);
break;
+ case 'z':
+ g.options |= OPT_RANDOM_SRC;
+ break;
+ case 'Z':
+ g.options |= OPT_RANDOM_DST;
+ break;
}
-
}
if (strlen(g.ifname) <=0 ) {
diff --git a/tools/tools/tscdrift/tscdrift.c b/tools/tools/tscdrift/tscdrift.c
index c607e48..13e754e 100644
--- a/tools/tools/tscdrift/tscdrift.c
+++ b/tools/tools/tscdrift/tscdrift.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Advanced Computing Technologies LLC
+ * Copyright (c) 2014 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index b1e4b83..a0c83bb 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -36,6 +36,7 @@ SUBDIR= ${_addr2line} \
csplit \
ctlstat \
cut \
+ ${_cxxfilt} \
demandoc \
dirname \
dpv \
@@ -150,7 +151,7 @@ SUBDIR= ${_addr2line} \
showmount \
${_size} \
sockstat \
- soeliminate \
+ soelim \
sort \
split \
stat \
@@ -237,6 +238,7 @@ SUBDIR+= ee
.if ${MK_ELFTOOLCHAIN_TOOLS} != "no"
_addr2line= addr2line
+_cxxfilt= cxxfilt
_elfcopy= elfcopy
_nm= nm
_readelf= readelf
@@ -284,8 +286,10 @@ SUBDIR+= iscsictl
.if ${MK_KDUMP} != "no"
SUBDIR+= kdump
+.if ${MACHINE_ARCH} != "aarch64" # ARM64TODO truss does not build
SUBDIR+= truss
.endif
+.endif
.if ${MK_KERBEROS_SUPPORT} != "no"
SUBDIR+= compile_et
@@ -382,13 +386,17 @@ SUBDIR+= c89
SUBDIR+= c99
SUBDIR+= ctags
SUBDIR+= file2c
+.if ${MACHINE_ARCH} != "aarch64" # ARM64TODO gprof does not build
SUBDIR+= gprof
+.endif
SUBDIR+= indent
SUBDIR+= lex
SUBDIR+= mkstr
SUBDIR+= rpcgen
SUBDIR+= unifdef
+.if ${MACHINE_ARCH} != "aarch64" # ARM64TODO xlint does not build
SUBDIR+= xlint
+.endif
SUBDIR+= xstr
SUBDIR+= yacc
.endif
diff --git a/usr.bin/ar/read.c b/usr.bin/ar/read.c
index ed7a94a..704812c 100644
--- a/usr.bin/ar/read.c
+++ b/usr.bin/ar/read.c
@@ -187,7 +187,15 @@ read_archive(struct bsdar *bsdar, char mode)
if (bsdar->options & AR_V)
(void)fprintf(stdout, "x - %s\n", name);
- flags = 0;
+ /* Disallow absolute paths. */
+ if (name[0] == '/') {
+ bsdar_warnc(bsdar, 0,
+ "Absolute path '%s'", name);
+ continue;
+ }
+ /* Basic path security flags. */
+ flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS |
+ ARCHIVE_EXTRACT_SECURE_NODOTDOT;
if (bsdar->options & AR_O)
flags |= ARCHIVE_EXTRACT_TIME;
diff --git a/usr.bin/bluetooth/bthost/bthost.c b/usr.bin/bluetooth/bthost/bthost.c
index 2dd5635..69ce3f5 100644
--- a/usr.bin/bluetooth/bthost/bthost.c
+++ b/usr.bin/bluetooth/bthost/bthost.c
@@ -29,6 +29,7 @@
* $FreeBSD$
*/
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/usr.bin/bluetooth/btsockstat/btsockstat.c b/usr.bin/bluetooth/btsockstat/btsockstat.c
index 20f4de8..aa85286 100644
--- a/usr.bin/bluetooth/btsockstat/btsockstat.c
+++ b/usr.bin/bluetooth/btsockstat/btsockstat.c
@@ -38,8 +38,8 @@
#include <sys/socketvar.h>
#include <net/if.h>
-#include <net/if_var.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <fcntl.h>
diff --git a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c
index 5873071..239597d 100644
--- a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c
+++ b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c
@@ -28,7 +28,7 @@
* $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $
* $FreeBSD$
*/
-
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
diff --git a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c
index ab6e1a7..309bab9 100644
--- a/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c
+++ b/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c
@@ -33,6 +33,7 @@
#include <sys/stat.h>
#include <sys/types.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <ctype.h>
#include <err.h>
diff --git a/usr.bin/bmake/Makefile b/usr.bin/bmake/Makefile
index 2fc2bee..93a1d7d 100644
--- a/usr.bin/bmake/Makefile
+++ b/usr.bin/bmake/Makefile
@@ -14,10 +14,10 @@ CFLAGS+= -I${.CURDIR}
CLEANDIRS+= FreeBSD
CLEANFILES+= bootstrap
-# $Id: Makefile,v 1.27 2014/06/20 14:51:54 sjg Exp $
+# $Id: Makefile,v 1.36 2015/04/18 19:58:53 sjg Exp $
# Base version on src date
-MAKE_VERSION= 20140620
+MAKE_VERSION= 20150418
PROG?= ${.CURDIR:T}
@@ -148,9 +148,9 @@ COPTS.parse.c += -Wno-format-nonliteral
COPTS.var.c += -Wno-format-nonliteral
# Force these
-SHAREDIR= ${prefix}/share
-BINDIR= ${prefix}/bin
-MANDIR= ${SHAREDIR}/man
+SHAREDIR= ${SHAREDIR.bmake:U${prefix}/share}
+BINDIR= ${BINDIR.bmake:U${prefix}/bin}
+MANDIR= ${MANDIR.bmake:U${SHAREDIR}/man}
.if !exists(.depend)
${OBJS}: config.h
diff --git a/usr.bin/bmake/unit-tests/Makefile b/usr.bin/bmake/unit-tests/Makefile
index be4cd2f..ee35dda 100644
--- a/usr.bin/bmake/unit-tests/Makefile
+++ b/usr.bin/bmake/unit-tests/Makefile
@@ -5,20 +5,21 @@
SRCTOP?= ${.CURDIR:H:H:H}
-# $Id: Makefile.in,v 1.44 2013/08/28 22:09:29 sjg Exp $
+# $Id: Makefile.in,v 1.46 2014/11/06 01:47:57 sjg Exp $
#
-# $NetBSD: Makefile,v 1.38 2013/08/28 21:56:50 sjg Exp $
+# $NetBSD: Makefile,v 1.51 2014/10/20 23:21:11 sjg Exp $
#
# Unit tests for make(1)
# The main targets are:
#
# all: run all the tests
-# test: run 'all', capture output and compare to expected results
+# test: run 'all', and compare to expected results
# accept: move generated output to expected results
#
# Adding a test case.
# Each feature should get its own set of tests in its own suitably
-# named makefile which should be added to SUBFILES to hook it in.
+# named makefile (*.mk), with its own set of expected results (*.exp),
+# and it should be added to the TESTNAMES list.
#
srcdir= ${SRCTOP}/contrib/bmake/unit-tests
@@ -26,10 +27,11 @@ srcdir= ${SRCTOP}/contrib/bmake/unit-tests
.MAIN: all
UNIT_TESTS:= ${srcdir}
+.PATH: ${UNIT_TESTS}
-# Simple sub-makefiles - we run them as a black box
-# keep the list sorted.
-SUBFILES= \
+# Each test is in a sub-makefile.
+# Keep the list sorted.
+TESTNAMES= \
comment \
cond1 \
error \
@@ -49,7 +51,6 @@ SUBFILES= \
modts \
modword \
order \
- phony-end \
posix \
qequals \
sunshcmd \
@@ -57,23 +58,36 @@ SUBFILES= \
ternary \
unexport \
unexport-env \
- varcmd
-
-all: ${SUBFILES}
+ varcmd \
+ varmisc \
+ varshell
+
+# these tests were broken by referting POSIX chanegs
+STRICT_POSIX_TESTS = \
+ escape \
+ impsrc \
+ phony-end \
+ posix1 \
+ suffixes
+# Override make flags for certain tests
flags.doterror=
flags.order=-j1
-# the tests are actually done with sub-makes.
-.PHONY: ${SUBFILES}
-.PRECIOUS: ${SUBFILES}
-${SUBFILES}:
- -@${.MAKE} ${flags.$@:U-k} -f ${UNIT_TESTS}/$@
+OUTFILES= ${TESTNAMES:S/$/.out/}
-clean:
- rm -f *.out *.fail *.core
+all: ${OUTFILES}
-.sinclude <bsd.obj.mk>
+CLEANFILES += *.rawout *.out *.status *.tmp *.core *.tmp
+CLEANFILES += obj*.[och] lib*.a # posix1.mk
+CLEANFILES += issue* .[ab]* # suffixes.mk
+CLEANRECURSIVE += dir dummy # posix1.mk
+
+clean:
+ rm -f ${CLEANFILES}
+.if !empty(CLEANRECURSIVE)
+ rm -rf ${CLEANRECURSIVE}
+.endif
TEST_MAKE?= ${.MAKE}
TOOL_SED?= sed
@@ -88,22 +102,56 @@ LANG= C
.export LANG LC_ALL
.endif
-# The driver.
+# some tests need extra post-processing
+SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \
+ -e '/command/s,No such.*,not found,'
+
+# the tests are actually done with sub-makes.
+.SUFFIXES: .mk .rawout .out
+.mk.rawout:
+ @echo ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC}
+ -@cd ${.OBJDIR} && \
+ { ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} \
+ 2>&1 ; echo $$? >${.TARGET:R}.status ; } > ${.TARGET}.tmp
+ @mv ${.TARGET}.tmp ${.TARGET}
+
# We always pretend .MAKE was called 'make'
# and strip ${.CURDIR}/ from the output
# and replace anything after 'stopped in' with unit-tests
# so the results can be compared.
-test:
- @echo "${TEST_MAKE} -f ${MAKEFILE} > ${.TARGET}.out 2>&1"
- @cd ${.OBJDIR} && ${TEST_MAKE} -f ${MAKEFILE} 2>&1 | \
- ${TOOL_TR} -d '\015' | \
- ${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[^:]*:,make:,' \
- -e '/stopped/s, /.*, unit-tests,' \
- -e 's,${.CURDIR:C/\./\\\./g}/,,g' \
- -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' > ${.TARGET}.out || { \
- tail ${.TARGET}.out; mv ${.TARGET}.out ${.TARGET}.fail; exit 1; }
- ${TOOL_DIFF} ${DIFF_FLAGS} ${UNIT_TESTS}/${.TARGET}.exp ${.TARGET}.out
+.rawout.out:
+ @echo postprocess ${.TARGET}
+ @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \
+ -e 's,${TEST_MAKE:C/\./\\\./g},make,' \
+ -e '/stopped/s, /.*, unit-tests,' \
+ -e 's,${.CURDIR:C/\./\\\./g}/,,g' \
+ -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \
+ < ${.IMPSRC} > ${.TARGET}.tmp
+ @echo "exit status `cat ${.TARGET:R}.status`" >> ${.TARGET}.tmp
+ @mv ${.TARGET}.tmp ${.TARGET}
+
+# Compare all output files
+test: ${OUTFILES} .PHONY
+ @failed= ; \
+ for test in ${TESTNAMES}; do \
+ ${TOOL_DIFF} -u ${UNIT_TESTS}/$${test}.exp $${test}.out \
+ || failed="$${failed}$${failed:+ }$${test}" ; \
+ done ; \
+ if [ -n "$${failed}" ]; then \
+ echo "Failed tests: $${failed}" ; false ; \
+ else \
+ echo "All tests passed" ; \
+ fi
accept:
- mv test.out ${srcdir}/test.exp
+ @for test in ${TESTNAMES}; do \
+ cmp -s ${UNIT_TESTS}/$${test}.exp $${test}.out \
+ || { echo "Replacing $${test}.exp" ; \
+ cp $${test}.out ${UNIT_TESTS}/$${test}.exp ; } \
+ done
+
+.if exists(${TEST_MAKE})
+${TESTNAMES:S/$/.rawout/}: ${TEST_MAKE}
+.endif
+.sinclude <bsd.obj.mk>
diff --git a/usr.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd
index fc6df82..9ea3d81 100644
--- a/usr.bin/calendar/calendars/calendar.freebsd
+++ b/usr.bin/calendar/calendars/calendar.freebsd
@@ -359,6 +359,7 @@
12/01 Alexey Dokuchaev <danfe@FreeBSD.org> born in Magadan, USSR, 1980
12/02 Ermal Luçi <eri@FreeBSD.org> born in Tirane, Albania, 1980
12/03 Diane Bruce <db@FreeBSD.org> born in Ottawa, Ontario, Canada, 1952
+12/04 Mariusz Zaborski <oshogbo@FreeBSD.org> born in Skierniewice, Poland, 1990
12/05 Ivan Voras <ivoras@FreeBSD.org> born in Slavonski Brod, Croatia, 1981
12/06 Stefan Farfeleder <stefanf@FreeBSD.org> born in Wien, Austria, 1980
12/11 Ganael Laplanche <martymac@FreeBSD.org> born in Reims, France, 1980
diff --git a/usr.bin/calendar/calendars/calendar.holiday b/usr.bin/calendar/calendars/calendar.holiday
index 3fdee69..fe9029e 100644
--- a/usr.bin/calendar/calendars/calendar.holiday
+++ b/usr.bin/calendar/calendars/calendar.holiday
@@ -144,8 +144,8 @@
04/26 Confederate Memorial Day in Florida & Georgia
04/26 Union Day in Tanzania
04/27 Independence Day in Togo
+04/27 King's Birthday in the Netherlands, the Netherlands Antilles
04/29 Showa Day in Japan
-04/30 Queen's Birthday in the Netherlands, the Netherlands Antilles
04/30 The Workers Day in Uruguay
04/MonLast Arbor Day in Wyoming (last Monday)
04/MonLast Confederate Memorial Day in Alabama & Mississippi (last Monday)
diff --git a/usr.bin/calendar/io.c b/usr.bin/calendar/io.c
index fd030c1..5e5c146 100644
--- a/usr.bin/calendar/io.c
+++ b/usr.bin/calendar/io.c
@@ -257,9 +257,6 @@ cal_parse(FILE *in, FILE *out)
return (1);
while ((linelen = getline(&line, &linecap, in)) > 0) {
- if (linelen == 0)
- continue;
-
if (*line == '#') {
switch (token(line+1, out, &skip)) {
case T_ERR:
diff --git a/usr.bin/col/Makefile b/usr.bin/col/Makefile
index 8e3a959..a162866 100644
--- a/usr.bin/col/Makefile
+++ b/usr.bin/col/Makefile
@@ -1,6 +1,12 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
+.include <src.opts.mk>
+
PROG= col
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.bin/col/col.c b/usr.bin/col/col.c
index e811a52..74c59b6 100644
--- a/usr.bin/col/col.c
+++ b/usr.bin/col/col.c
@@ -45,11 +45,15 @@ static char sccsid[] = "@(#)col.c 8.5 (Berkeley) 5/4/95";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/capsicum.h>
+
#include <err.h>
+#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
@@ -63,9 +67,9 @@ __FBSDID("$FreeBSD$");
#define SI '\017' /* shift in to normal character set */
#define SO '\016' /* shift out to alternate character set */
#define VT '\013' /* vertical tab (aka reverse line feed) */
-#define RLF '\007' /* ESC-07 reverse line feed */
-#define RHLF '\010' /* ESC-010 reverse half-line feed */
-#define FHLF '\011' /* ESC-011 forward half-line feed */
+#define RLF '7' /* ESC-7 reverse line feed */
+#define RHLF '8' /* ESC-8 reverse half-line feed */
+#define FHLF '9' /* ESC-9 forward half-line feed */
/* build up at least this many lines before flushing them out */
#define BUFFER_MARGIN 32
@@ -129,9 +133,24 @@ main(int argc, char **argv)
int this_line; /* line l points to */
int nflushd_lines; /* number of lines that were flushed */
int adjust, opt, warned, width;
+ cap_rights_t rights;
+ unsigned long cmd;
(void)setlocale(LC_CTYPE, "");
+ cap_rights_init(&rights, CAP_FSTAT, CAP_READ);
+ if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
+ err(1, "unable to limit rights for stdin");
+ cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE, CAP_IOCTL);
+ if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
+ err(1, "unable to limit rights for stdout");
+ cmd = TIOCGETA; /* required by isatty(3) in printf(3) */
+ if (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS)
+ err(1, "unable to limit ioctls for stdout");
+
+ if (cap_enter() < 0 && errno != ENOSYS)
+ err(1, "unable to enter capability mode");
+
max_bufd_lines = 128;
compress_spaces = 1; /* compress spaces into tabs */
while ((opt = getopt(argc, argv, "bfhl:px")) != -1)
@@ -321,7 +340,7 @@ main(int argc, char **argv)
/* make sure we leave things in a sane state */
if (last_set != CS_NORMAL)
- PUTC('\017');
+ PUTC(SI);
/* flush out the last few blank lines */
nblank_lines = max_line - this_line;
@@ -377,8 +396,8 @@ flush_blanks(void)
for (i = nb; --i >= 0;)
PUTC('\n');
if (half) {
- PUTC('\033');
- PUTC('\011');
+ PUTC(ESC);
+ PUTC(FHLF);
if (!nb)
PUTC('\r');
}
@@ -480,10 +499,10 @@ flush_line(LINE *l)
if (c->c_set != last_set) {
switch (c->c_set) {
case CS_NORMAL:
- PUTC('\017');
+ PUTC(SI);
break;
case CS_ALTERNATE:
- PUTC('\016');
+ PUTC(SO);
}
last_set = c->c_set;
}
diff --git a/usr.bin/col/tests/Makefile b/usr.bin/col/tests/Makefile
new file mode 100644
index 0000000..43838e9
--- /dev/null
+++ b/usr.bin/col/tests/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/usr.bin/col
+
+ATF_TESTS_SH= col
+
+FILES= rlf.in \
+ rlf2.in
+FILESDIR= ${TESTSDIR}
+
+.include <bsd.test.mk>
diff --git a/usr.bin/col/tests/col.sh b/usr.bin/col/tests/col.sh
new file mode 100755
index 0000000..c072aab
--- /dev/null
+++ b/usr.bin/col/tests/col.sh
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+atf_test_case rlf
+
+rlf_head()
+{
+ atf_set "descr" "testing reverse line feed"
+}
+rlf_body()
+{
+ atf_check \
+ -o inline:"a b\n" \
+ -e empty \
+ -s exit:0 \
+ col < $(atf_get_srcdir)/rlf.in
+
+ atf_check \
+ -o inline:"a b\n" \
+ -e empty \
+ -s exit:0 \
+ col < $(atf_get_srcdir)/rlf2.in
+
+ atf_check \
+ -o inline:"a b\n" \
+ -e empty \
+ -s exit:0 \
+ col -x < $(atf_get_srcdir)/rlf2.in
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case rlf
+}
diff --git a/usr.bin/col/tests/rlf.in b/usr.bin/col/tests/rlf.in
new file mode 100644
index 0000000..57a14e5
--- /dev/null
+++ b/usr.bin/col/tests/rlf.in
@@ -0,0 +1,2 @@
+a
+ 7b
diff --git a/usr.bin/col/tests/rlf2.in b/usr.bin/col/tests/rlf2.in
new file mode 100644
index 0000000..dd46851
--- /dev/null
+++ b/usr.bin/col/tests/rlf2.in
@@ -0,0 +1,2 @@
+a
+ 7b
diff --git a/usr.bin/cxxfilt/Makefile b/usr.bin/cxxfilt/Makefile
new file mode 100644
index 0000000..496b240
--- /dev/null
+++ b/usr.bin/cxxfilt/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+ELFTCDIR= ${.CURDIR}/../../contrib/elftoolchain
+SRCDIR= ${ELFTCDIR}/cxxfilt
+
+.PATH: ${SRCDIR}
+
+PROG= c++filt
+SRCS= cxxfilt.c
+
+LIBADD= elftc
+
+CFLAGS+=-I${ELFTCDIR}/libelftc -I${ELFTCDIR}/common
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1
index 0eb3bf5..a6e4d66 100644
--- a/usr.bin/find/find.1
+++ b/usr.bin/find/find.1
@@ -1015,7 +1015,7 @@ and
as well as
.Ic -amin , -anewer , -cmin , -cnewer , -delete , -empty , -fstype ,
.Ic -iname , -inum , -iregex , -ls , -maxdepth , -mindepth , -mmin ,
-.Ic -path , -print0 , -regex, -sparse
+.Ic -path , -print0 , -regex , -sparse
and all of the
.Ic -B*
birthtime related primaries are extensions to
diff --git a/usr.bin/gcore/elf32core.c b/usr.bin/gcore/elf32core.c
index de48500..d13a4ef 100644
--- a/usr.bin/gcore/elf32core.c
+++ b/usr.bin/gcore/elf32core.c
@@ -8,24 +8,6 @@
#include <sys/procfs.h>
-struct prpsinfo32 {
- int pr_version;
- u_int pr_psinfosz;
- char pr_fname[PRFNAMESZ+1];
- char pr_psargs[PRARGSZ+1];
-};
-
-struct prstatus32 {
- int pr_version;
- u_int pr_statussz;
- u_int pr_gregsetsz;
- u_int pr_fpregsetsz;
- int pr_osreldate;
- int pr_cursig;
- pid_t pr_pid;
- struct reg32 pr_reg;
-};
-
#define ELFCORE_COMPAT_32 1
#include "elfcore.c"
diff --git a/usr.bin/gzip/gzip.1 b/usr.bin/gzip/gzip.1
index 5abf1ae..43d0e72 100644
--- a/usr.bin/gzip/gzip.1
+++ b/usr.bin/gzip/gzip.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: gzip.1,v 1.23 2014/03/18 18:20:45 riastradh Exp $
+.\" $NetBSD: gzip.1,v 1.25 2015/04/06 21:41:17 wiz Exp $
.\"
.\" Copyright (c) 1997, 2003, 2004 Matthew R. Green
.\" All rights reserved.
@@ -25,7 +25,7 @@
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
-.Dd October 9, 2011
+.Dd April 6, 2015
.Dt GZIP 1
.Os
.Sh NAME
@@ -105,9 +105,10 @@ options are enabled.
This version of
.Nm
is also capable of decompressing files compressed using
-.Xr compress 1
+.Xr compress 1 ,
+.Xr bzip2 1 ,
or
-.Xr bzip2 1 .
+.Xr xz 1 .
.Sh OPTIONS
The following options are available:
.Bl -tag -width XXrXXXrecursiveX
diff --git a/usr.bin/gzip/gzip.c b/usr.bin/gzip/gzip.c
index f197f18..8469c05 100644
--- a/usr.bin/gzip/gzip.c
+++ b/usr.bin/gzip/gzip.c
@@ -1,4 +1,4 @@
-/* $NetBSD: gzip.c,v 1.106 2014/10/18 08:33:30 snj Exp $ */
+/* $NetBSD: gzip.c,v 1.108 2015/04/15 02:29:12 christos Exp $ */
/*-
* Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green
@@ -158,7 +158,7 @@ static suffixes_t suffixes[] = {
#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0])
#define SUFFIX_MAXLEN 30
-static const char gzip_version[] = "FreeBSD gzip 20141022";
+static const char gzip_version[] = "FreeBSD gzip 20150413";
#ifndef SMALL
static const char gzip_copyright[] = \
@@ -1354,7 +1354,7 @@ file_uncompress(char *file, char *outfile, size_t outsize)
#ifndef SMALL
ssize_t rv;
time_t timestamp = 0;
- unsigned char name[PATH_MAX + 1];
+ char name[PATH_MAX + 1];
#endif
/* gather the old name info */
@@ -1409,21 +1409,33 @@ file_uncompress(char *file, char *outfile, size_t outsize)
timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0];
if (header1[3] & ORIG_NAME) {
- rbytes = pread(fd, name, sizeof name, GZIP_ORIGNAME);
+ rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME);
if (rbytes < 0) {
maybe_warn("can't read %s", file);
goto lose;
}
- if (name[0] != 0) {
+ if (name[0] != '\0') {
+ char *dp, *nf;
+
+ /* Make sure that name is NUL-terminated */
+ name[rbytes] = '\0';
+
+ /* strip saved directory name */
+ nf = strrchr(name, '/');
+ if (nf == NULL)
+ nf = name;
+ else
+ nf++;
+
/* preserve original directory name */
- char *dp = strrchr(file, '/');
+ dp = strrchr(file, '/');
if (dp == NULL)
dp = file;
else
dp++;
snprintf(outfile, outsize, "%.*s%.*s",
(int) (dp - file),
- file, (int) rbytes, name);
+ file, (int) rbytes, nf);
}
}
}
@@ -2110,7 +2122,7 @@ static void
display_license(void)
{
- fprintf(stderr, "%s (based on NetBSD gzip 20141018)\n", gzip_version);
+ fprintf(stderr, "%s (based on NetBSD gzip 20150113)\n", gzip_version);
fprintf(stderr, "%s\n", gzip_copyright);
exit(0);
}
diff --git a/usr.bin/hexdump/display.c b/usr.bin/hexdump/display.c
index a5f2a47..4ff3308 100644
--- a/usr.bin/hexdump/display.c
+++ b/usr.bin/hexdump/display.c
@@ -380,7 +380,7 @@ doskip(const char *fname, int statok)
return;
}
}
- if (S_ISREG(sb.st_mode)) {
+ if (statok && S_ISREG(sb.st_mode)) {
if (fseeko(stdin, skip, SEEK_SET))
err(1, "%s", fname);
address += skip;
diff --git a/usr.bin/iconv/iconv.c b/usr.bin/iconv/iconv.c
index dc2aec0..494aaf7 100644
--- a/usr.bin/iconv/iconv.c
+++ b/usr.bin/iconv/iconv.c
@@ -71,9 +71,8 @@ do_conv(FILE *fp, const char *from, const char *to, bool silent,
bool hide_invalid)
{
iconv_t cd;
- char inbuf[INBUFSIZE], outbuf[OUTBUFSIZE], *out;
+ char inbuf[INBUFSIZE], outbuf[OUTBUFSIZE], *in, *out;
unsigned long long invalids;
- const char *in;
size_t inbytes, outbytes, ret;
if ((cd = iconv_open(to, from)) == (iconv_t)-1)
diff --git a/usr.bin/ipcs/Makefile b/usr.bin/ipcs/Makefile
index 3106004..d14723f 100644
--- a/usr.bin/ipcs/Makefile
+++ b/usr.bin/ipcs/Makefile
@@ -4,6 +4,4 @@ PROG= ipcs
SRCS= ipcs.c ipc.c
LIBADD= kvm
-WARNS?= 1
-
.include <bsd.prog.mk>
diff --git a/usr.bin/ipcs/ipc.c b/usr.bin/ipcs/ipc.c
index 4c62743..306d659 100644
--- a/usr.bin/ipcs/ipc.c
+++ b/usr.bin/ipcs/ipc.c
@@ -55,16 +55,15 @@ struct msginfo msginfo;
struct msqid_kernel *msqids;
struct shminfo shminfo;
struct shmid_kernel *shmsegs;
-void kget(int idx, void *addr, size_t size);
struct nlist symbols[] = {
- {"sema"},
- {"seminfo"},
- {"msginfo"},
- {"msqids"},
- {"shminfo"},
- {"shmsegs"},
- {NULL}
+ { .n_name = "sema" },
+ { .n_name = "seminfo" },
+ { .n_name = "msginfo" },
+ { .n_name = "msqids" },
+ { .n_name = "shminfo" },
+ { .n_name = "shmsegs" },
+ { .n_name = NULL }
};
#define SHMINFO_XVEC X(shmmax, sizeof(u_long)) \
@@ -92,13 +91,13 @@ struct nlist symbols[] = {
#define X(a, b) { "kern.ipc." #a, offsetof(TYPEC, a), (b) },
#define TYPEC struct shminfo
-struct scgs_vector shminfo_scgsv[] = { SHMINFO_XVEC { NULL } };
+static struct scgs_vector shminfo_scgsv[] = { SHMINFO_XVEC { .sysctl=NULL } };
#undef TYPEC
#define TYPEC struct seminfo
-struct scgs_vector seminfo_scgsv[] = { SEMINFO_XVEC { NULL } };
+static struct scgs_vector seminfo_scgsv[] = { SEMINFO_XVEC { .sysctl=NULL } };
#undef TYPEC
#define TYPEC struct msginfo
-struct scgs_vector msginfo_scgsv[] = { MSGINFO_XVEC { NULL } };
+static struct scgs_vector msginfo_scgsv[] = { MSGINFO_XVEC { .sysctl=NULL } };
#undef TYPEC
#undef X
diff --git a/usr.bin/ipcs/ipc.h b/usr.bin/ipcs/ipc.h
index 640c3fd..0b6188a 100644
--- a/usr.bin/ipcs/ipc.h
+++ b/usr.bin/ipcs/ipc.h
@@ -52,7 +52,7 @@
/* SysCtlGatherStruct structure. */
struct scgs_vector {
const char *sysctl;
- off_t offset;
+ size_t offset;
size_t size;
};
@@ -64,8 +64,5 @@ extern struct nlist symbols[];
extern kvm_t *kd;
extern struct semid_kernel *sema;
-extern struct seminfo seminfo;
-extern struct msginfo msginfo;
extern struct msqid_kernel *msqids;
-extern struct shminfo shminfo;
extern struct shmid_kernel *shmsegs;
diff --git a/usr.bin/ipcs/ipcs.c b/usr.bin/ipcs/ipcs.c
index 1d8e354..be6ca56 100644
--- a/usr.bin/ipcs/ipcs.c
+++ b/usr.bin/ipcs/ipcs.c
@@ -112,6 +112,7 @@ main(int argc, char *argv[])
char *core = NULL, *user = NULL, *namelist = NULL;
char kvmoferr[_POSIX2_LINE_MAX]; /* Error buf for kvm_openfiles. */
int i;
+ u_long shmidx;
uid_t uid = 0;
while ((i = getopt(argc, argv, "MmQqSsabC:cN:optTu:y")) != -1)
@@ -247,13 +248,13 @@ main(int argc, char *argv[])
print_kshmheader(option);
- for (i = 0; i < shminfo.shmmni; i += 1) {
- if (kxshmids[i].u.shm_perm.mode & 0x0800) {
+ for (shmidx = 0; shmidx < shminfo.shmmni; shmidx += 1) {
+ if (kxshmids[shmidx].u.shm_perm.mode & 0x0800) {
if (user &&
- uid != kxshmids[i].u.shm_perm.uid)
+ uid != kxshmids[shmidx].u.shm_perm.uid)
continue;
- print_kshmptr(i, option, &kxshmids[i]);
+ print_kshmptr(shmidx, option, &kxshmids[shmidx]);
}
}
printf("\n");
@@ -309,22 +310,22 @@ main(int argc, char *argv[])
}
void
-print_kmsqtotal(struct msginfo msginfo)
+print_kmsqtotal(struct msginfo local_msginfo)
{
printf("msginfo:\n");
printf("\tmsgmax: %12d\t(max characters in a message)\n",
- msginfo.msgmax);
+ local_msginfo.msgmax);
printf("\tmsgmni: %12d\t(# of message queues)\n",
- msginfo.msgmni);
+ local_msginfo.msgmni);
printf("\tmsgmnb: %12d\t(max characters in a message queue)\n",
- msginfo.msgmnb);
+ local_msginfo.msgmnb);
printf("\tmsgtql: %12d\t(max # of messages in system)\n",
- msginfo.msgtql);
+ local_msginfo.msgtql);
printf("\tmsgssz: %12d\t(size of a message segment)\n",
- msginfo.msgssz);
+ local_msginfo.msgssz);
printf("\tmsgseg: %12d\t(# of message segments in system)\n\n",
- msginfo.msgseg);
+ local_msginfo.msgseg);
}
void print_kmsqheader(int option)
@@ -390,20 +391,20 @@ print_kmsqptr(int i, int option, struct msqid_kernel *kmsqptr)
}
void
-print_kshmtotal(struct shminfo shminfo)
+print_kshmtotal(struct shminfo local_shminfo)
{
printf("shminfo:\n");
printf("\tshmmax: %12lu\t(max shared memory segment size)\n",
- shminfo.shmmax);
+ local_shminfo.shmmax);
printf("\tshmmin: %12lu\t(min shared memory segment size)\n",
- shminfo.shmmin);
+ local_shminfo.shmmin);
printf("\tshmmni: %12lu\t(max number of shared memory identifiers)\n",
- shminfo.shmmni);
+ local_shminfo.shmmni);
printf("\tshmseg: %12lu\t(max shared memory segments per process)\n",
- shminfo.shmseg);
+ local_shminfo.shmseg);
printf("\tshmall: %12lu\t(max amount of shared memory in pages)\n\n",
- shminfo.shmall);
+ local_shminfo.shmall);
}
void
@@ -470,28 +471,28 @@ print_kshmptr(int i, int option, struct shmid_kernel *kshmptr)
}
void
-print_ksemtotal(struct seminfo seminfo)
+print_ksemtotal(struct seminfo local_seminfo)
{
printf("seminfo:\n");
printf("\tsemmni: %12d\t(# of semaphore identifiers)\n",
- seminfo.semmni);
+ local_seminfo.semmni);
printf("\tsemmns: %12d\t(# of semaphores in system)\n",
- seminfo.semmns);
+ local_seminfo.semmns);
printf("\tsemmnu: %12d\t(# of undo structures in system)\n",
- seminfo.semmnu);
+ local_seminfo.semmnu);
printf("\tsemmsl: %12d\t(max # of semaphores per id)\n",
- seminfo.semmsl);
+ local_seminfo.semmsl);
printf("\tsemopm: %12d\t(max # of operations per semop call)\n",
- seminfo.semopm);
+ local_seminfo.semopm);
printf("\tsemume: %12d\t(max # of undo entries per process)\n",
- seminfo.semume);
+ local_seminfo.semume);
printf("\tsemusz: %12d\t(size in bytes of undo structure)\n",
- seminfo.semusz);
+ local_seminfo.semusz);
printf("\tsemvmx: %12d\t(semaphore maximum value)\n",
- seminfo.semvmx);
+ local_seminfo.semvmx);
printf("\tsemaem: %12d\t(adjust on exit max value)\n\n",
- seminfo.semaem);
+ local_seminfo.semaem);
}
void
diff --git a/usr.bin/iscsictl/Makefile b/usr.bin/iscsictl/Makefile
index 811c19e..4437e2d 100644
--- a/usr.bin/iscsictl/Makefile
+++ b/usr.bin/iscsictl/Makefile
@@ -6,7 +6,7 @@ CFLAGS+= -I${.CURDIR}
CFLAGS+= -I${.CURDIR}/../../sys/dev/iscsi
MAN= iscsi.conf.5 iscsictl.8
-LIBADD= cam util
+LIBADD= xo
YFLAGS+= -v
LFLAGS+= -i
diff --git a/usr.bin/iscsictl/iscsictl.c b/usr.bin/iscsictl/iscsictl.c
index e6abf93..ac83b49 100644
--- a/usr.bin/iscsictl/iscsictl.c
+++ b/usr.bin/iscsictl/iscsictl.c
@@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <assert.h>
#include <ctype.h>
-#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -44,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libxo/xo.h>
#include <iscsi_ioctl.h>
#include "iscsictl.h"
@@ -55,7 +55,7 @@ conf_new(void)
conf = calloc(1, sizeof(*conf));
if (conf == NULL)
- err(1, "calloc");
+ xo_err(1, "calloc");
TAILQ_INIT(&conf->conf_targets);
@@ -83,7 +83,7 @@ target_new(struct conf *conf)
targ = calloc(1, sizeof(*targ));
if (targ == NULL)
- err(1, "calloc");
+ xo_err(1, "calloc");
targ->t_conf = conf;
TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next);
@@ -110,12 +110,12 @@ default_initiator_name(void)
name = calloc(1, namelen + 1);
if (name == NULL)
- err(1, "calloc");
+ xo_err(1, "calloc");
strcpy(name, DEFAULT_IQN);
error = gethostname(name + strlen(DEFAULT_IQN),
namelen - strlen(DEFAULT_IQN));
if (error != 0)
- err(1, "gethostname");
+ xo_err(1, "gethostname");
return (name);
}
@@ -158,7 +158,7 @@ valid_iscsi_name(const char *name)
int i;
if (strlen(name) >= MAX_NAME_LEN) {
- warnx("overlong name for \"%s\"; max length allowed "
+ xo_warnx("overlong name for \"%s\"; max length allowed "
"by iSCSI specification is %d characters",
name, MAX_NAME_LEN);
return (false);
@@ -178,7 +178,7 @@ valid_iscsi_name(const char *name)
continue;
if (name[i] == '-' || name[i] == '.' || name[i] == ':')
continue;
- warnx("invalid character \"%c\" in iSCSI name "
+ xo_warnx("invalid character \"%c\" in iSCSI name "
"\"%s\"; allowed characters are letters, digits, "
"'-', '.', and ':'", name[i], name);
break;
@@ -188,12 +188,12 @@ valid_iscsi_name(const char *name)
*/
} else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) {
if (strlen(name) != strlen("eui.") + 16)
- warnx("invalid iSCSI name \"%s\"; the \"eui.\" "
+ xo_warnx("invalid iSCSI name \"%s\"; the \"eui.\" "
"should be followed by exactly 16 hexadecimal "
"digits", name);
for (i = strlen("eui."); name[i] != '\0'; i++) {
if (!valid_hex(name[i])) {
- warnx("invalid character \"%c\" in iSCSI "
+ xo_warnx("invalid character \"%c\" in iSCSI "
"name \"%s\"; allowed characters are 1-9 "
"and A-F", name[i], name);
break;
@@ -201,19 +201,19 @@ valid_iscsi_name(const char *name)
}
} else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) {
if (strlen(name) > strlen("naa.") + 32)
- warnx("invalid iSCSI name \"%s\"; the \"naa.\" "
+ xo_warnx("invalid iSCSI name \"%s\"; the \"naa.\" "
"should be followed by at most 32 hexadecimal "
"digits", name);
for (i = strlen("naa."); name[i] != '\0'; i++) {
if (!valid_hex(name[i])) {
- warnx("invalid character \"%c\" in ISCSI "
+ xo_warnx("invalid character \"%c\" in ISCSI "
"name \"%s\"; allowed characters are 1-9 "
"and A-F", name[i], name);
break;
}
}
} else {
- warnx("invalid iSCSI name \"%s\"; should start with "
+ xo_warnx("invalid iSCSI name \"%s\"; should start with "
"either \".iqn\", \"eui.\", or \"naa.\"",
name);
}
@@ -231,26 +231,26 @@ conf_verify(struct conf *conf)
targ->t_session_type = SESSION_TYPE_NORMAL;
if (targ->t_session_type == SESSION_TYPE_NORMAL &&
targ->t_name == NULL)
- errx(1, "missing TargetName for target \"%s\"",
+ xo_errx(1, "missing TargetName for target \"%s\"",
targ->t_nickname);
if (targ->t_session_type == SESSION_TYPE_DISCOVERY &&
targ->t_name != NULL)
- errx(1, "cannot specify TargetName for discovery "
+ xo_errx(1, "cannot specify TargetName for discovery "
"sessions for target \"%s\"", targ->t_nickname);
if (targ->t_name != NULL) {
if (valid_iscsi_name(targ->t_name) == false)
- errx(1, "invalid target name \"%s\"",
+ xo_errx(1, "invalid target name \"%s\"",
targ->t_name);
}
if (targ->t_protocol == PROTOCOL_UNSPECIFIED)
targ->t_protocol = PROTOCOL_ISCSI;
if (targ->t_address == NULL)
- errx(1, "missing TargetAddress for target \"%s\"",
+ xo_errx(1, "missing TargetAddress for target \"%s\"",
targ->t_nickname);
if (targ->t_initiator_name == NULL)
targ->t_initiator_name = default_initiator_name();
if (valid_iscsi_name(targ->t_initiator_name) == false)
- errx(1, "invalid initiator name \"%s\"",
+ xo_errx(1, "invalid initiator name \"%s\"",
targ->t_initiator_name);
if (targ->t_header_digest == DIGEST_UNSPECIFIED)
targ->t_header_digest = DIGEST_NONE;
@@ -268,19 +268,19 @@ conf_verify(struct conf *conf)
}
if (targ->t_auth_method == AUTH_METHOD_CHAP) {
if (targ->t_user == NULL) {
- errx(1, "missing chapIName for target \"%s\"",
+ xo_errx(1, "missing chapIName for target \"%s\"",
targ->t_nickname);
}
if (targ->t_secret == NULL)
- errx(1, "missing chapSecret for target \"%s\"",
+ xo_errx(1, "missing chapSecret for target \"%s\"",
targ->t_nickname);
if (targ->t_mutual_user != NULL ||
targ->t_mutual_secret != NULL) {
if (targ->t_mutual_user == NULL)
- errx(1, "missing tgtChapName for "
+ xo_errx(1, "missing tgtChapName for "
"target \"%s\"", targ->t_nickname);
if (targ->t_mutual_secret == NULL)
- errx(1, "missing tgtChapSecret for "
+ xo_errx(1, "missing tgtChapSecret for "
"target \"%s\"", targ->t_nickname);
}
}
@@ -350,7 +350,7 @@ kernel_add(int iscsi_fd, const struct target *targ)
conf_from_target(&isa.isa_conf, targ);
error = ioctl(iscsi_fd, ISCSISADD, &isa);
if (error != 0)
- warn("ISCSISADD");
+ xo_warn("ISCSISADD");
return (error);
}
@@ -365,7 +365,7 @@ kernel_modify(int iscsi_fd, unsigned int session_id, const struct target *targ)
conf_from_target(&ism.ism_conf, targ);
error = ioctl(iscsi_fd, ISCSISMODIFY, &ism);
if (error != 0)
- warn("ISCSISMODIFY");
+ xo_warn("ISCSISMODIFY");
return (error);
}
@@ -385,7 +385,7 @@ kernel_modify_some(int iscsi_fd, unsigned int session_id, const char *target,
states = realloc(states,
nentries * sizeof(struct iscsi_session_state));
if (states == NULL)
- err(1, "realloc");
+ xo_err(1, "realloc");
memset(&isl, 0, sizeof(isl));
isl.isl_nentries = nentries;
@@ -399,7 +399,7 @@ kernel_modify_some(int iscsi_fd, unsigned int session_id, const char *target,
break;
}
if (error != 0)
- errx(1, "ISCSISLIST");
+ xo_errx(1, "ISCSISLIST");
for (i = 0; i < isl.isl_nentries; i++) {
state = &states[i];
@@ -408,7 +408,7 @@ kernel_modify_some(int iscsi_fd, unsigned int session_id, const char *target,
break;
}
if (i == isl.isl_nentries)
- errx(1, "session-id %u not found", session_id);
+ xo_errx(1, "session-id %u not found", session_id);
conf = &state->iss_conf;
@@ -427,7 +427,7 @@ kernel_modify_some(int iscsi_fd, unsigned int session_id, const char *target,
memcpy(&ism.ism_conf, conf, sizeof(ism.ism_conf));
error = ioctl(iscsi_fd, ISCSISMODIFY, &ism);
if (error != 0)
- warn("ISCSISMODIFY");
+ xo_warn("ISCSISMODIFY");
}
static int
@@ -440,7 +440,7 @@ kernel_remove(int iscsi_fd, const struct target *targ)
conf_from_target(&isr.isr_conf, targ);
error = ioctl(iscsi_fd, ISCSISREMOVE, &isr);
if (error != 0)
- warn("ISCSISREMOVE");
+ xo_warn("ISCSISREMOVE");
return (error);
}
@@ -462,7 +462,7 @@ kernel_list(int iscsi_fd, const struct target *targ __unused,
states = realloc(states,
nentries * sizeof(struct iscsi_session_state));
if (states == NULL)
- err(1, "realloc");
+ xo_err(1, "realloc");
memset(&isl, 0, sizeof(isl));
isl.isl_nentries = nentries;
@@ -476,79 +476,117 @@ kernel_list(int iscsi_fd, const struct target *targ __unused,
break;
}
if (error != 0) {
- warn("ISCSISLIST");
+ xo_warn("ISCSISLIST");
return (error);
}
if (verbose != 0) {
+ xo_open_list("session");
for (i = 0; i < isl.isl_nentries; i++) {
state = &states[i];
conf = &state->iss_conf;
- printf("Session ID: %u\n", state->iss_id);
- printf("Initiator name: %s\n", conf->isc_initiator);
- printf("Initiator portal: %s\n",
- conf->isc_initiator_addr);
- printf("Initiator alias: %s\n",
- conf->isc_initiator_alias);
- printf("Target name: %s\n", conf->isc_target);
- printf("Target portal: %s\n",
- conf->isc_target_addr);
- printf("Target alias: %s\n",
- state->iss_target_alias);
- printf("User: %s\n", conf->isc_user);
- printf("Secret: %s\n", conf->isc_secret);
- printf("Mutual user: %s\n",
- conf->isc_mutual_user);
- printf("Mutual secret: %s\n",
- conf->isc_mutual_secret);
- printf("Session type: %s\n",
+ xo_open_instance("session");
+
+ /*
+ * Display-only modifier as this information
+ * is also present within the 'session' container
+ */
+ xo_emit("{L:/%-18s}{V:sessionId/%u}\n",
+ "Session ID:", state->iss_id);
+
+ xo_open_container("initiator");
+ xo_emit("{L:/%-18s}{V:name/%s}\n",
+ "Initiator name:", conf->isc_initiator);
+ xo_emit("{L:/%-18s}{V:portal/%s}\n",
+ "Initiator portal:", conf->isc_initiator_addr);
+ xo_emit("{L:/%-18s}{V:alias/%s}\n",
+ "Initiator alias:", conf->isc_initiator_alias);
+ xo_close_container("initiator");
+
+ xo_open_container("target");
+ xo_emit("{L:/%-18s}{V:name/%s}\n",
+ "Target name:", conf->isc_target);
+ xo_emit("{L:/%-18s}{V:portal/%s}\n",
+ "Target portal:", conf->isc_target_addr);
+ xo_emit("{L:/%-18s}{V:alias/%s}\n",
+ "Target alias:", state->iss_target_alias);
+ xo_close_container("target");
+
+ xo_open_container("auth");
+ xo_emit("{L:/%-18s}{V:user/%s}\n",
+ "User:", conf->isc_user);
+ xo_emit("{L:/%-18s}{V:secret/%s}\n",
+ "Secret:", conf->isc_secret);
+ xo_emit("{L:/%-18s}{V:mutualUser/%s}\n",
+ "Mutual user:", conf->isc_mutual_user);
+ xo_emit("{L:/%-18s}{V:mutualSecret/%s}\n",
+ "Mutual secret:", conf->isc_mutual_secret);
+ xo_close_container("auth");
+
+ xo_emit("{L:/%-18s}{V:type/%s}\n",
+ "Session type:",
conf->isc_discovery ? "Discovery" : "Normal");
- printf("Session state: %s\n",
- state->iss_connected ?
- "Connected" : "Disconnected");
- printf("Failure reason: %s\n", state->iss_reason);
- printf("Header digest: %s\n",
+ xo_emit("{L:/%-18s}{V:state/%s}\n",
+ "Session state:",
+ state->iss_connected ? "Connected" : "Disconnected");
+ xo_emit("{L:/%-18s}{V:failureReason/%s}\n",
+ "Failure reason:", state->iss_reason);
+ xo_emit("{L:/%-18s}{V:headerDigest/%s}\n",
+ "Header digest:",
state->iss_header_digest == ISCSI_DIGEST_CRC32C ?
"CRC32C" : "None");
- printf("Data digest: %s\n",
+ xo_emit("{L:/%-18s}{V:dataDigest/%s}\n",
+ "Data digest:",
state->iss_data_digest == ISCSI_DIGEST_CRC32C ?
"CRC32C" : "None");
- printf("DataSegmentLen: %d\n",
- state->iss_max_data_segment_length);
- printf("ImmediateData: %s\n",
- state->iss_immediate_data ? "Yes" : "No");
- printf("iSER (RDMA): %s\n",
- conf->isc_iser ? "Yes" : "No");
- printf("Offload driver: %s\n", state->iss_offload);
- printf("Device nodes: ");
+ xo_emit("{L:/%-18s}{V:dataSegmentLen/%d}\n",
+ "DataSegmentLen:", state->iss_max_data_segment_length);
+ xo_emit("{L:/%-18s}{V:immediateData/%s}\n",
+ "ImmediateData:", state->iss_immediate_data ? "Yes" : "No");
+ xo_emit("{L:/%-18s}{V:iSER/%s}\n",
+ "iSER (RDMA):", conf->isc_iser ? "Yes" : "No");
+ xo_emit("{L:/%-18s}{V:offloadDriver/%s}\n",
+ "Offload driver:", state->iss_offload);
+ xo_emit("{L:/%-18s}",
+ "Device nodes:");
print_periphs(state->iss_id);
- printf("\n\n");
+ xo_emit("\n\n");
+ xo_close_instance("session");
}
+ xo_close_list("session");
} else {
- printf("%-36s %-16s %s\n",
+ xo_emit("{T:/%-36s} {T:/%-16s} {T:/%s}\n",
"Target name", "Target portal", "State");
+
+ if (isl.isl_nentries != 0)
+ xo_open_list("session");
for (i = 0; i < isl.isl_nentries; i++) {
+
state = &states[i];
conf = &state->iss_conf;
- printf("%-36s %-16s ",
+ xo_open_instance("session");
+ xo_emit("{V:name/%-36s/%s} {V:portal/%-16s/%s} ",
conf->isc_target, conf->isc_target_addr);
if (state->iss_reason[0] != '\0') {
- printf("%s\n", state->iss_reason);
+ xo_emit("{V:state/%s}\n", state->iss_reason);
} else {
if (conf->isc_discovery) {
- printf("Discovery\n");
+ xo_emit("{V:state}\n", "Discovery");
} else if (state->iss_connected) {
- printf("Connected: ");
+ xo_emit("{V:state}: ", "Connected");
print_periphs(state->iss_id);
- printf("\n");
+ xo_emit("\n");
} else {
- printf("Disconnected\n");
+ xo_emit("{V:state}\n", "Disconnected");
}
}
+ xo_close_instance("session");
}
+ if (isl.isl_nentries != 0)
+ xo_close_list("session");
}
return (0);
@@ -582,7 +620,7 @@ checked_strdup(const char *s)
c = strdup(s);
if (c == NULL)
- err(1, "strdup");
+ xo_err(1, "strdup");
return (c);
}
@@ -600,6 +638,9 @@ main(int argc, char **argv)
struct conf *conf;
struct target *targ;
+ argc = xo_parse_args(argc, argv);
+ xo_open_container("iscsictl");
+
while ((ch = getopt(argc, argv, "AMRLac:d:i:n:p:t:u:s:v")) != -1) {
switch (ch) {
case 'A':
@@ -626,11 +667,11 @@ main(int argc, char **argv)
case 'i':
session_id = strtol(optarg, &end, 10);
if ((size_t)(end - optarg) != strlen(optarg))
- errx(1, "trailing characters after session-id");
+ xo_errx(1, "trailing characters after session-id");
if (session_id < 0)
- errx(1, "session-id cannot be negative");
+ xo_errx(1, "session-id cannot be negative");
if (session_id > UINT_MAX)
- errx(1, "session-id cannot be greater than %u",
+ xo_errx(1, "session-id cannot be greater than %u",
UINT_MAX);
break;
case 'n':
@@ -663,7 +704,7 @@ main(int argc, char **argv)
if (Aflag + Mflag + Rflag + Lflag == 0)
Lflag = 1;
if (Aflag + Mflag + Rflag + Lflag > 1)
- errx(1, "at most one of -A, -M, -R, or -L may be specified");
+ xo_errx(1, "at most one of -A, -M, -R, or -L may be specified");
/*
* Note that we ignore unneccessary/inapplicable "-c" flag; so that
@@ -673,122 +714,122 @@ main(int argc, char **argv)
if (Aflag != 0) {
if (aflag != 0) {
if (portal != NULL)
- errx(1, "-a and -p and mutually exclusive");
+ xo_errx(1, "-a and -p and mutually exclusive");
if (target != NULL)
- errx(1, "-a and -t and mutually exclusive");
+ xo_errx(1, "-a and -t and mutually exclusive");
if (user != NULL)
- errx(1, "-a and -u and mutually exclusive");
+ xo_errx(1, "-a and -u and mutually exclusive");
if (secret != NULL)
- errx(1, "-a and -s and mutually exclusive");
+ xo_errx(1, "-a and -s and mutually exclusive");
if (nickname != NULL)
- errx(1, "-a and -n and mutually exclusive");
+ xo_errx(1, "-a and -n and mutually exclusive");
if (discovery_host != NULL)
- errx(1, "-a and -d and mutually exclusive");
+ xo_errx(1, "-a and -d and mutually exclusive");
} else if (nickname != NULL) {
if (portal != NULL)
- errx(1, "-n and -p and mutually exclusive");
+ xo_errx(1, "-n and -p and mutually exclusive");
if (target != NULL)
- errx(1, "-n and -t and mutually exclusive");
+ xo_errx(1, "-n and -t and mutually exclusive");
if (user != NULL)
- errx(1, "-n and -u and mutually exclusive");
+ xo_errx(1, "-n and -u and mutually exclusive");
if (secret != NULL)
- errx(1, "-n and -s and mutually exclusive");
+ xo_errx(1, "-n and -s and mutually exclusive");
if (discovery_host != NULL)
- errx(1, "-n and -d and mutually exclusive");
+ xo_errx(1, "-n and -d and mutually exclusive");
} else if (discovery_host != NULL) {
if (portal != NULL)
- errx(1, "-d and -p and mutually exclusive");
+ xo_errx(1, "-d and -p and mutually exclusive");
if (target != NULL)
- errx(1, "-d and -t and mutually exclusive");
+ xo_errx(1, "-d and -t and mutually exclusive");
} else {
if (target == NULL && portal == NULL)
- errx(1, "must specify -a, -n or -t/-p");
+ xo_errx(1, "must specify -a, -n or -t/-p");
if (target != NULL && portal == NULL)
- errx(1, "-t must always be used with -p");
+ xo_errx(1, "-t must always be used with -p");
if (portal != NULL && target == NULL)
- errx(1, "-p must always be used with -t");
+ xo_errx(1, "-p must always be used with -t");
}
if (user != NULL && secret == NULL)
- errx(1, "-u must always be used with -s");
+ xo_errx(1, "-u must always be used with -s");
if (secret != NULL && user == NULL)
- errx(1, "-s must always be used with -u");
+ xo_errx(1, "-s must always be used with -u");
if (session_id != -1)
- errx(1, "-i cannot be used with -A");
+ xo_errx(1, "-i cannot be used with -A");
if (vflag != 0)
- errx(1, "-v cannot be used with -A");
+ xo_errx(1, "-v cannot be used with -A");
} else if (Mflag != 0) {
if (session_id == -1)
- errx(1, "-M requires -i");
+ xo_errx(1, "-M requires -i");
if (discovery_host != NULL)
- errx(1, "-M and -d are mutually exclusive");
+ xo_errx(1, "-M and -d are mutually exclusive");
if (aflag != 0)
- errx(1, "-M and -a are mutually exclusive");
+ xo_errx(1, "-M and -a are mutually exclusive");
if (nickname != NULL) {
if (portal != NULL)
- errx(1, "-n and -p and mutually exclusive");
+ xo_errx(1, "-n and -p and mutually exclusive");
if (target != NULL)
- errx(1, "-n and -t and mutually exclusive");
+ xo_errx(1, "-n and -t and mutually exclusive");
if (user != NULL)
- errx(1, "-n and -u and mutually exclusive");
+ xo_errx(1, "-n and -u and mutually exclusive");
if (secret != NULL)
- errx(1, "-n and -s and mutually exclusive");
+ xo_errx(1, "-n and -s and mutually exclusive");
}
if (vflag != 0)
- errx(1, "-v cannot be used with -M");
+ xo_errx(1, "-v cannot be used with -M");
} else if (Rflag != 0) {
if (user != NULL)
- errx(1, "-R and -u are mutually exclusive");
+ xo_errx(1, "-R and -u are mutually exclusive");
if (secret != NULL)
- errx(1, "-R and -s are mutually exclusive");
+ xo_errx(1, "-R and -s are mutually exclusive");
if (discovery_host != NULL)
- errx(1, "-R and -d are mutually exclusive");
+ xo_errx(1, "-R and -d are mutually exclusive");
if (aflag != 0) {
if (portal != NULL)
- errx(1, "-a and -p and mutually exclusive");
+ xo_errx(1, "-a and -p and mutually exclusive");
if (target != NULL)
- errx(1, "-a and -t and mutually exclusive");
+ xo_errx(1, "-a and -t and mutually exclusive");
if (nickname != NULL)
- errx(1, "-a and -n and mutually exclusive");
+ xo_errx(1, "-a and -n and mutually exclusive");
} else if (nickname != NULL) {
if (portal != NULL)
- errx(1, "-n and -p and mutually exclusive");
+ xo_errx(1, "-n and -p and mutually exclusive");
if (target != NULL)
- errx(1, "-n and -t and mutually exclusive");
+ xo_errx(1, "-n and -t and mutually exclusive");
} else if (target == NULL && portal == NULL) {
- errx(1, "must specify either -a, -n, -t, or -p");
+ xo_errx(1, "must specify either -a, -n, -t, or -p");
}
if (session_id != -1)
- errx(1, "-i cannot be used with -R");
+ xo_errx(1, "-i cannot be used with -R");
if (vflag != 0)
- errx(1, "-v cannot be used with -R");
+ xo_errx(1, "-v cannot be used with -R");
} else {
assert(Lflag != 0);
if (portal != NULL)
- errx(1, "-L and -p and mutually exclusive");
+ xo_errx(1, "-L and -p and mutually exclusive");
if (target != NULL)
- errx(1, "-L and -t and mutually exclusive");
+ xo_errx(1, "-L and -t and mutually exclusive");
if (user != NULL)
- errx(1, "-L and -u and mutually exclusive");
+ xo_errx(1, "-L and -u and mutually exclusive");
if (secret != NULL)
- errx(1, "-L and -s and mutually exclusive");
+ xo_errx(1, "-L and -s and mutually exclusive");
if (nickname != NULL)
- errx(1, "-L and -n and mutually exclusive");
+ xo_errx(1, "-L and -n and mutually exclusive");
if (discovery_host != NULL)
- errx(1, "-L and -d and mutually exclusive");
+ xo_errx(1, "-L and -d and mutually exclusive");
if (session_id != -1)
- errx(1, "-i cannot be used with -L");
+ xo_errx(1, "-i cannot be used with -L");
}
iscsi_fd = open(ISCSI_PATH, O_RDWR);
@@ -801,7 +842,7 @@ main(int argc, char **argv)
errno = saved_errno;
}
if (iscsi_fd < 0)
- err(1, "failed to open %s", ISCSI_PATH);
+ xo_err(1, "failed to open %s", ISCSI_PATH);
if (Aflag != 0 && aflag != 0) {
conf = conf_new_from_file(conf_path);
@@ -812,7 +853,7 @@ main(int argc, char **argv)
conf = conf_new_from_file(conf_path);
targ = target_find(conf, nickname);
if (targ == NULL)
- errx(1, "target %s not found in %s",
+ xo_errx(1, "target %s not found in %s",
nickname, conf_path);
if (Aflag != 0)
@@ -829,7 +870,7 @@ main(int argc, char **argv)
} else {
if (Aflag != 0 && target != NULL) {
if (valid_iscsi_name(target) == false)
- errx(1, "invalid target name \"%s\"", target);
+ xo_errx(1, "invalid target name \"%s\"", target);
}
conf = conf_new();
targ = target_new(conf);
@@ -857,9 +898,12 @@ main(int argc, char **argv)
error = close(iscsi_fd);
if (error != 0)
- err(1, "close");
+ xo_err(1, "close");
if (failed > 0)
return (1);
+
+ xo_close_container("iscsictl");
+ xo_finish();
return (0);
}
diff --git a/usr.bin/iscsictl/parse.y b/usr.bin/iscsictl/parse.y
index 7beb53e..9941904 100644
--- a/usr.bin/iscsictl/parse.y
+++ b/usr.bin/iscsictl/parse.y
@@ -34,12 +34,13 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
-#include <err.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <libxo/xo.h>
+
#include "iscsictl.h"
extern FILE *yyin;
@@ -77,7 +78,7 @@ targets:
target: STR OPENING_BRACKET target_entries CLOSING_BRACKET
{
if (target_find(conf, $1) != NULL)
- errx(1, "duplicated target %s", $1);
+ xo_errx(1, "duplicated target %s", $1);
target->t_nickname = $1;
target = target_new(conf);
}
@@ -127,7 +128,7 @@ target_entry:
target_name: TARGET_NAME EQUALS STR
{
if (target->t_name != NULL)
- errx(1, "duplicated TargetName at line %d", lineno);
+ xo_errx(1, "duplicated TargetName at line %d", lineno);
target->t_name = $3;
}
;
@@ -135,7 +136,7 @@ target_name: TARGET_NAME EQUALS STR
target_address: TARGET_ADDRESS EQUALS STR
{
if (target->t_address != NULL)
- errx(1, "duplicated TargetAddress at line %d", lineno);
+ xo_errx(1, "duplicated TargetAddress at line %d", lineno);
target->t_address = $3;
}
;
@@ -143,7 +144,7 @@ target_address: TARGET_ADDRESS EQUALS STR
initiator_name: INITIATOR_NAME EQUALS STR
{
if (target->t_initiator_name != NULL)
- errx(1, "duplicated InitiatorName at line %d", lineno);
+ xo_errx(1, "duplicated InitiatorName at line %d", lineno);
target->t_initiator_name = $3;
}
;
@@ -151,7 +152,7 @@ initiator_name: INITIATOR_NAME EQUALS STR
initiator_address: INITIATOR_ADDRESS EQUALS STR
{
if (target->t_initiator_address != NULL)
- errx(1, "duplicated InitiatorAddress at line %d", lineno);
+ xo_errx(1, "duplicated InitiatorAddress at line %d", lineno);
target->t_initiator_address = $3;
}
;
@@ -159,7 +160,7 @@ initiator_address: INITIATOR_ADDRESS EQUALS STR
initiator_alias: INITIATOR_ALIAS EQUALS STR
{
if (target->t_initiator_alias != NULL)
- errx(1, "duplicated InitiatorAlias at line %d", lineno);
+ xo_errx(1, "duplicated InitiatorAlias at line %d", lineno);
target->t_initiator_alias = $3;
}
;
@@ -167,7 +168,7 @@ initiator_alias: INITIATOR_ALIAS EQUALS STR
user: USER EQUALS STR
{
if (target->t_user != NULL)
- errx(1, "duplicated chapIName at line %d", lineno);
+ xo_errx(1, "duplicated chapIName at line %d", lineno);
target->t_user = $3;
}
;
@@ -175,7 +176,7 @@ user: USER EQUALS STR
secret: SECRET EQUALS STR
{
if (target->t_secret != NULL)
- errx(1, "duplicated chapSecret at line %d", lineno);
+ xo_errx(1, "duplicated chapSecret at line %d", lineno);
target->t_secret = $3;
}
;
@@ -183,7 +184,7 @@ secret: SECRET EQUALS STR
mutual_user: MUTUAL_USER EQUALS STR
{
if (target->t_mutual_user != NULL)
- errx(1, "duplicated tgtChapName at line %d", lineno);
+ xo_errx(1, "duplicated tgtChapName at line %d", lineno);
target->t_mutual_user = $3;
}
;
@@ -191,7 +192,7 @@ mutual_user: MUTUAL_USER EQUALS STR
mutual_secret: MUTUAL_SECRET EQUALS STR
{
if (target->t_mutual_secret != NULL)
- errx(1, "duplicated tgtChapSecret at line %d", lineno);
+ xo_errx(1, "duplicated tgtChapSecret at line %d", lineno);
target->t_mutual_secret = $3;
}
;
@@ -199,13 +200,13 @@ mutual_secret: MUTUAL_SECRET EQUALS STR
auth_method: AUTH_METHOD EQUALS STR
{
if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
- errx(1, "duplicated AuthMethod at line %d", lineno);
+ xo_errx(1, "duplicated AuthMethod at line %d", lineno);
if (strcasecmp($3, "none") == 0)
target->t_auth_method = AUTH_METHOD_NONE;
else if (strcasecmp($3, "chap") == 0)
target->t_auth_method = AUTH_METHOD_CHAP;
else
- errx(1, "invalid AuthMethod at line %d; "
+ xo_errx(1, "invalid AuthMethod at line %d; "
"must be either \"none\" or \"CHAP\"", lineno);
}
;
@@ -213,13 +214,13 @@ auth_method: AUTH_METHOD EQUALS STR
header_digest: HEADER_DIGEST EQUALS STR
{
if (target->t_header_digest != DIGEST_UNSPECIFIED)
- errx(1, "duplicated HeaderDigest at line %d", lineno);
+ xo_errx(1, "duplicated HeaderDigest at line %d", lineno);
if (strcasecmp($3, "none") == 0)
target->t_header_digest = DIGEST_NONE;
else if (strcasecmp($3, "CRC32C") == 0)
target->t_header_digest = DIGEST_CRC32C;
else
- errx(1, "invalid HeaderDigest at line %d; "
+ xo_errx(1, "invalid HeaderDigest at line %d; "
"must be either \"none\" or \"CRC32C\"", lineno);
}
;
@@ -227,13 +228,13 @@ header_digest: HEADER_DIGEST EQUALS STR
data_digest: DATA_DIGEST EQUALS STR
{
if (target->t_data_digest != DIGEST_UNSPECIFIED)
- errx(1, "duplicated DataDigest at line %d", lineno);
+ xo_errx(1, "duplicated DataDigest at line %d", lineno);
if (strcasecmp($3, "none") == 0)
target->t_data_digest = DIGEST_NONE;
else if (strcasecmp($3, "CRC32C") == 0)
target->t_data_digest = DIGEST_CRC32C;
else
- errx(1, "invalid DataDigest at line %d; "
+ xo_errx(1, "invalid DataDigest at line %d; "
"must be either \"none\" or \"CRC32C\"", lineno);
}
;
@@ -241,13 +242,13 @@ data_digest: DATA_DIGEST EQUALS STR
session_type: SESSION_TYPE EQUALS STR
{
if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
- errx(1, "duplicated SessionType at line %d", lineno);
+ xo_errx(1, "duplicated SessionType at line %d", lineno);
if (strcasecmp($3, "normal") == 0)
target->t_session_type = SESSION_TYPE_NORMAL;
else if (strcasecmp($3, "discovery") == 0)
target->t_session_type = SESSION_TYPE_DISCOVERY;
else
- errx(1, "invalid SessionType at line %d; "
+ xo_errx(1, "invalid SessionType at line %d; "
"must be either \"normal\" or \"discovery\"", lineno);
}
;
@@ -255,7 +256,7 @@ session_type: SESSION_TYPE EQUALS STR
offload: OFFLOAD EQUALS STR
{
if (target->t_offload != NULL)
- errx(1, "duplicated offload at line %d", lineno);
+ xo_errx(1, "duplicated offload at line %d", lineno);
target->t_offload = $3;
}
;
@@ -263,20 +264,20 @@ offload: OFFLOAD EQUALS STR
protocol: PROTOCOL EQUALS STR
{
if (target->t_protocol != PROTOCOL_UNSPECIFIED)
- errx(1, "duplicated protocol at line %d", lineno);
+ xo_errx(1, "duplicated protocol at line %d", lineno);
if (strcasecmp($3, "iscsi") == 0)
target->t_protocol = PROTOCOL_ISCSI;
else if (strcasecmp($3, "iser") == 0)
target->t_protocol = PROTOCOL_ISER;
else
- errx(1, "invalid protocol at line %d; "
+ xo_errx(1, "invalid protocol at line %d; "
"must be either \"iscsi\" or \"iser\"", lineno);
}
;
ignored: IGNORED EQUALS STR
{
- warnx("obsolete statement ignored at line %d", lineno);
+ xo_warnx("obsolete statement ignored at line %d", lineno);
}
;
@@ -286,7 +287,7 @@ void
yyerror(const char *str)
{
- errx(1, "error in configuration file at line %d near '%s': %s",
+ xo_errx(1, "error in configuration file at line %d near '%s': %s",
lineno, yytext, str);
}
@@ -298,19 +299,19 @@ check_perms(const char *path)
error = stat(path, &sb);
if (error != 0) {
- warn("stat");
+ xo_warn("stat");
return;
}
if (sb.st_mode & S_IWOTH) {
- warnx("%s is world-writable", path);
+ xo_warnx("%s is world-writable", path);
} else if (sb.st_mode & S_IROTH) {
- warnx("%s is world-readable", path);
+ xo_warnx("%s is world-readable", path);
} else if (sb.st_mode & S_IXOTH) {
/*
* Ok, this one doesn't matter, but still do it,
* just for consistency.
*/
- warnx("%s is world-executable", path);
+ xo_warnx("%s is world-executable", path);
}
/*
@@ -328,7 +329,7 @@ conf_new_from_file(const char *path)
yyin = fopen(path, "r");
if (yyin == NULL)
- err(1, "unable to open configuration file %s", path);
+ xo_err(1, "unable to open configuration file %s", path);
check_perms(path);
lineno = 1;
yyrestart(yyin);
diff --git a/usr.bin/iscsictl/periphs.c b/usr.bin/iscsictl/periphs.c
index fb4a686..0697860 100644
--- a/usr.bin/iscsictl/periphs.c
+++ b/usr.bin/iscsictl/periphs.c
@@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
#include <inttypes.h>
#include <limits.h>
#include <fcntl.h>
-#include <err.h>
#include <cam/cam.h>
#include <cam/cam_debug.h>
@@ -58,6 +57,7 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/smp_all.h>
#include <cam/ata/ata_all.h>
#include <camlib.h>
+#include <libxo/xo.h>
#include "iscsictl.h"
@@ -67,10 +67,11 @@ print_periphs(int session_id)
union ccb ccb;
int bufsize, fd;
unsigned int i;
- int skip_bus, skip_device;
+ int have_path_id, skip_bus, skip_device;
+ path_id_t path_id;
if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
- warn("couldn't open %s", XPT_DEVICE);
+ xo_warn("couldn't open %s", XPT_DEVICE);
return;
}
@@ -89,7 +90,7 @@ print_periphs(int session_id)
ccb.cdm.match_buf_len = bufsize;
ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
if (ccb.cdm.matches == NULL) {
- warnx("can't malloc memory for matches");
+ xo_warnx("can't malloc memory for matches");
close(fd);
return;
}
@@ -102,23 +103,27 @@ print_periphs(int session_id)
ccb.cdm.num_patterns = 0;
ccb.cdm.pattern_buf_len = 0;
+ path_id = -1; /* Make GCC happy. */
+ have_path_id = 0;
skip_bus = 1;
skip_device = 1;
+ xo_open_container("devices");
+ xo_open_list("lun");
/*
* We do the ioctl multiple times if necessary, in case there are
* more than 100 nodes in the EDT.
*/
do {
if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
- warn("error sending CAMIOCOMMAND ioctl");
+ xo_warn("error sending CAMIOCOMMAND ioctl");
break;
}
if ((ccb.ccb_h.status != CAM_REQ_CMP)
|| ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
&& (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
- warnx("got CAM error %#x, CDM error %d\n",
+ xo_warnx("got CAM error %#x, CDM error %d\n",
ccb.ccb_h.status, ccb.cdm.status);
break;
}
@@ -141,7 +146,6 @@ print_periphs(int session_id)
//printf("wrong unit, %d != %d\n", bus_result->unit_number, session_id);
continue;
}
-
skip_bus = 0;
}
case DEV_MATCH_DEVICE: {
@@ -151,7 +155,6 @@ print_periphs(int session_id)
continue;
skip_device = 0;
-
break;
}
case DEV_MATCH_PERIPH: {
@@ -166,9 +169,17 @@ print_periphs(int session_id)
if (strcmp(periph_result->periph_name, "pass") == 0)
continue;
- fprintf(stdout, "%s%d ",
- periph_result->periph_name,
- periph_result->unit_number);
+ xo_open_instance("lun");
+ xo_emit("{e:lun/%d}", periph_result->target_lun);
+ xo_emit("{Vq:device/%s%d} ",
+ periph_result->periph_name,
+ periph_result->unit_number);
+ xo_close_instance("lun");
+
+ if (have_path_id == 0) {
+ path_id = periph_result->path_id;
+ have_path_id = 1;
+ }
break;
}
@@ -180,6 +191,11 @@ print_periphs(int session_id)
} while ((ccb.ccb_h.status == CAM_REQ_CMP)
&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
+ xo_close_list("lun");
+
+ xo_emit("{e:scbus/%d}{e:bus/%d}{e:target/%d}",
+ have_path_id ? (int)path_id : -1, 0, have_path_id ? 0 : -1);
+ xo_close_container("devices");
close(fd);
}
diff --git a/usr.bin/jot/jot.1 b/usr.bin/jot/jot.1
index b6d1d14..8b93837 100644
--- a/usr.bin/jot/jot.1
+++ b/usr.bin/jot/jot.1
@@ -28,7 +28,7 @@
.\" @(#)jot.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd June 2, 2010
+.Dd April 7, 2015
.Dt JOT 1
.Os
.Sh NAME
@@ -324,3 +324,5 @@ The
.Nm
utility first appeared in
.Bx 4.2 .
+.Sh AUTHORS
+.An John A. Kunze
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index fe7bcd2..3b5a847 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -586,6 +586,7 @@ dumpheader(struct ktr_header *kth)
static char unknown[64];
static struct timeval prevtime, prevtime_e, temp;
const char *type;
+ const char *sign;
switch (kth->ktr_type) {
case KTR_SYSCALL:
@@ -662,10 +663,20 @@ dumpheader(struct ktr_header *kth)
timevaladd(&kth->ktr_time, &prevtime_e);
}
if (timestamp & TIMESTAMP_RELATIVE) {
+ if (prevtime.tv_sec == 0)
+ prevtime = kth->ktr_time;
temp = kth->ktr_time;
timevalsub(&kth->ktr_time, &prevtime);
- prevtime = temp;
- printf("%jd.%06ld ", (intmax_t)kth->ktr_time.tv_sec,
+ if ((intmax_t)kth->ktr_time.tv_sec < 0) {
+ kth->ktr_time = prevtime;
+ prevtime = temp;
+ timevalsub(&kth->ktr_time, &prevtime);
+ sign = "-";
+ } else {
+ prevtime = temp;
+ sign = "";
+ }
+ printf("%s%jd.%06ld ", sign, (intmax_t)kth->ktr_time.tv_sec,
kth->ktr_time.tv_usec);
}
}
diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls
index a9ba860..525e143 100644
--- a/usr.bin/kdump/mkioctls
+++ b/usr.bin/kdump/mkioctls
@@ -54,7 +54,6 @@ BEGIN {
print "#include <bsm/audit.h>"
print "#include <net/ethernet.h>"
print "#include <net/if.h>"
- print "#include <net/if_var.h>"
print "#ifdef PF"
print "#include <net/pfvar.h>"
print "#include <net/if_pfsync.h>"
diff --git a/usr.bin/lam/lam.1 b/usr.bin/lam/lam.1
index 5c95a3f..896cea2 100644
--- a/usr.bin/lam/lam.1
+++ b/usr.bin/lam/lam.1
@@ -28,7 +28,7 @@
.\" @(#)lam.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd August 12, 2004
+.Dd April 7, 2015
.Dt LAM 1
.Os
.Sh NAME
@@ -136,6 +136,8 @@ The
.Nm
utility first appeared in
.Bx 4.2 .
+.Sh AUTHORS
+.An John A. Kunze
.Sh BUGS
The
.Nm
diff --git a/usr.bin/lockf/lockf.1 b/usr.bin/lockf/lockf.1
index 57119e5..e6204a1 100644
--- a/usr.bin/lockf/lockf.1
+++ b/usr.bin/lockf/lockf.1
@@ -162,6 +162,7 @@ but may have been signaled or stopped.
.El
.Sh SEE ALSO
.Xr flock 2 ,
+.Xr lockf 3 ,
.Xr sysexits 3
.Sh HISTORY
A
diff --git a/usr.bin/lockf/lockf.c b/usr.bin/lockf/lockf.c
index 9a6141f..5555c48 100644
--- a/usr.bin/lockf/lockf.c
+++ b/usr.bin/lockf/lockf.c
@@ -169,7 +169,7 @@ acquire_lock(const char *name, int flags)
{
int fd;
- if ((fd = open(name, flags|O_RDONLY|O_EXLOCK|flags, 0666)) == -1) {
+ if ((fd = open(name, O_RDONLY|O_EXLOCK|flags, 0666)) == -1) {
if (errno == EAGAIN || errno == EINTR)
return (-1);
err(EX_CANTCREAT, "cannot open %s", name);
diff --git a/usr.bin/m4/misc.c b/usr.bin/m4/misc.c
index 30fb690..5223a35 100644
--- a/usr.bin/m4/misc.c
+++ b/usr.bin/m4/misc.c
@@ -64,8 +64,6 @@ unsigned char *bbase[MAXINP]; /* the base for each ilevel */
unsigned char *bp; /* first available character */
unsigned char *endpbb; /* end of push-back buffer */
-static void *reallocarray(void *, size_t, size_t);
-
/*
* find the index of second str in the first str.
*/
@@ -467,37 +465,3 @@ dump_buffer(FILE *f, size_t m)
for (s = bp; s-buf > (long)m;)
fputc(*--s, f);
}
-
-/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
-/*
- * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
- * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
- */
-#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
-
-void *
-reallocarray(void *optr, size_t nmemb, size_t size)
-{
- if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
- nmemb > 0 && SIZE_MAX / nmemb < size) {
- errno = ENOMEM;
- return NULL;
- }
- return realloc(optr, size * nmemb);
-}
diff --git a/usr.bin/mt/Makefile b/usr.bin/mt/Makefile
index 802eed1..b71c2f8 100644
--- a/usr.bin/mt/Makefile
+++ b/usr.bin/mt/Makefile
@@ -2,7 +2,6 @@
# $FreeBSD$
PROG= mt
-DPADD= ${LIBMT} ${LIBSBUF} ${LIBBSDXML}
-LDADD= -lmt -lsbuf -lbsdxml
+LIBADD= mt
.include <bsd.prog.mk>
diff --git a/usr.bin/mt/mt.c b/usr.bin/mt/mt.c
index 745766c..8cec707 100644
--- a/usr.bin/mt/mt.c
+++ b/usr.bin/mt/mt.c
@@ -81,7 +81,6 @@ __FBSDID("$FreeBSD$");
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/queue.h>
-#include <sys/sbuf.h>
#include <ctype.h>
#include <err.h>
diff --git a/usr.bin/netstat/bpf.c b/usr.bin/netstat/bpf.c
index b48f9a1..60546e3 100644
--- a/usr.bin/netstat/bpf.c
+++ b/usr.bin/netstat/bpf.c
@@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
#include <sys/user.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/bpf.h>
#include <net/bpfdesc.h>
#include <arpa/inet.h>
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index cc8405e..f04c531 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/ethernet.h>
diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c
index 0d2006a..3535f45 100644
--- a/usr.bin/netstat/inet6.c
+++ b/usr.bin/netstat/inet6.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c
index f00b119..d9c127a 100644
--- a/usr.bin/netstat/mroute6.c
+++ b/usr.bin/netstat/mroute6.c
@@ -79,13 +79,11 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <err.h>
-#include <nlist.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -98,20 +96,6 @@ __FBSDID("$FreeBSD$");
#include "netstat.h"
-/*
- * kvm(3) bindings for every needed symbol
- */
-static struct nlist mrl[] = {
-#define N_MF6CTABLE 0
- { .n_name = "_mf6ctable" },
-#define N_MIF6TABLE 1
- { .n_name = "_mif6table" },
-#define N_MRT6STAT 2
- { .n_name = "_mrt6stat" },
- { .n_name = NULL },
-};
-
-
#define WID_ORG (Wflag ? 39 : (numeric_addr ? 29 : 18)) /* width of origin column */
#define WID_GRP (Wflag ? 18 : (numeric_addr ? 16 : 18)) /* width of group column */
@@ -119,11 +103,10 @@ void
mroute6pr()
{
struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp;
- struct mif6 mif6table[MAXMIFS];
+ struct mif6_sctl mif6table[MAXMIFS];
struct mf6c mfc;
struct rtdetq rte, *rtep;
- struct mif6 *mifp;
- u_long mfcaddr, mifaddr;
+ struct mif6_sctl *mifp;
mifi_t mifi;
int i;
int banner_printed;
@@ -132,39 +115,26 @@ mroute6pr()
long int waitings;
size_t len;
- kresolve_list(mrl);
- mfcaddr = mrl[N_MF6CTABLE].n_value;
- mifaddr = mrl[N_MIF6TABLE].n_value;
-
- if (mfcaddr == 0 || mifaddr == 0) {
- fprintf(stderr, "No IPv6 MROUTING kernel support.\n");
+ if (live == 0)
return;
- }
len = sizeof(mif6table);
- if (live) {
- if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len,
- NULL, 0) < 0) {
- xo_warn("sysctl: net.inet6.ip6.mif6table");
- return;
- }
- } else
- kread(mifaddr, (char *)mif6table, sizeof(mif6table));
+ if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len, NULL, 0) <
+ 0) {
+ xo_warn("sysctl: net.inet6.ip6.mif6table");
+ return;
+ }
saved_numeric_addr = numeric_addr;
numeric_addr = 1;
banner_printed = 0;
for (mifi = 0, mifp = mif6table; mifi < MAXMIFS; ++mifi, ++mifp) {
- struct ifnet ifnet;
char ifname[IFNAMSIZ];
- if (mifp->m6_ifp == NULL)
+ if (mifp->m6_ifp == 0)
continue;
- /* XXX KVM */
- kread((u_long)mifp->m6_ifp, (char *)&ifnet, sizeof(ifnet));
-
maxmif = mifi;
if (!banner_printed) {
xo_open_list("multicast-interface");
@@ -177,7 +147,7 @@ mroute6pr()
xo_emit(" {:mif/%2u} {:rate-limit/%4d}",
mifi, mifp->m6_rate_limit);
xo_emit(" {:ifname/%5s}", (mifp->m6_flags & MIFF_REGISTER) ?
- "reg0" : if_indextoname(ifnet.if_index, ifname));
+ "reg0" : if_indextoname(mifp->m6_ifp, ifname));
xo_emit(" {:received-packets/%9ju} {:sent-packets/%9ju}\n",
(uintmax_t)mifp->m6_pkt_in,
@@ -190,14 +160,11 @@ mroute6pr()
xo_emit("\n{T:IPv6 Multicast Interface Table is empty}\n");
len = sizeof(mf6ctable);
- if (live) {
- if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len,
- NULL, 0) < 0) {
- xo_warn("sysctl: net.inet6.ip6.mf6ctable");
- return;
- }
- } else
- kread(mfcaddr, (char *)mf6ctable, sizeof(mf6ctable));
+ if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len, NULL, 0) <
+ 0) {
+ xo_warn("sysctl: net.inet6.ip6.mf6ctable");
+ return;
+ }
banner_printed = 0;
@@ -262,26 +229,14 @@ void
mrt6_stats()
{
struct mrt6stat mrtstat;
- u_long mstaddr;
size_t len = sizeof mrtstat;
- kresolve_list(mrl);
- mstaddr = mrl[N_MRT6STAT].n_value;
-
- if (mstaddr == 0) {
- fprintf(stderr, "No IPv6 MROUTING kernel support.\n");
+ if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len, NULL, 0) <
+ 0) {
+ xo_warn("sysctl: net.inet6.ip6.mrt6stat");
return;
}
- if (live) {
- if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len,
- NULL, 0) < 0) {
- xo_warn("sysctl: net.inet6.ip6.mrt6stat");
- return;
- }
- } else
- kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
-
xo_open_container("multicast-statistics");
xo_emit("{T:IPv6 multicast forwarding}:\n");
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 1b67b1a..c9d3e42 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -28,7 +28,7 @@
.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
-.Dd February 21, 2015
+.Dd April 7, 2015
.Dt NETSTAT 1
.Os
.Sh NAME
@@ -78,11 +78,9 @@
.Op Fl I Ar interface
.It Nm Fl r
.Op Fl -libxo
-.Op Fl 46AnW
+.Op Fl 46nW
.Op Fl F Ar fibnum
.Op Fl f Ar address_family
-.Op Fl M Ar core
-.Op Fl N Ar system
.It Nm Fl rs
.Op Fl -libxo
.Op Fl s
@@ -92,8 +90,6 @@
.Op Fl -libxo
.Op Fl 46W
.Op Fl f Ar address_family
-.Op Fl M Ar core
-.Op Fl N Ar system
.It Nm Fl gs
.Op Fl -libxo
.Op Fl 46s
@@ -583,9 +579,6 @@ See
Show IPv6 only.
See
.Sx GENERAL OPTIONS .
-.It Fl A
-Show the contents of the internal Patricia tree
-structures; used for debugging.
.It Fl n
Do not resolve numeric addresses and port numbers to names.
See
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index 5ae40b1..676f616 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -40,22 +40,18 @@ __FBSDID("$FreeBSD$");
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/sysctl.h>
#include <sys/time.h>
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
-#include <net/radix.h>
-#define _WANT_RTENTRY
#include <net/route.h>
#include <netinet/in.h>
#include <netgraph/ng_socket.h>
-#include <sys/sysctl.h>
-
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <libutil.h>
@@ -72,8 +68,6 @@ __FBSDID("$FreeBSD$");
#include <libxo/xo.h>
#include "netstat.h"
-#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
-
/*
* Definitions for showing gateway flags.
*/
@@ -108,9 +102,7 @@ struct bits {
static struct nlist rl[] = {
#define N_RTSTAT 0
{ .n_name = "_rtstat" },
-#define N_RTREE 1
- { .n_name = "_rt_tables"},
-#define N_RTTRASH 2
+#define N_RTTRASH 1
{ .n_name = "_rttrash" },
{ .n_name = NULL },
};
@@ -121,33 +113,14 @@ typedef union {
u_short u_data[128];
} sa_u;
-static sa_u pt_u;
-
struct ifmap_entry {
char ifname[IFNAMSIZ];
};
-
static struct ifmap_entry *ifmap;
static int ifmap_size;
-
-int do_rtent = 0;
-struct rtentry rtentry;
-struct radix_node rnode;
-struct radix_mask rmask;
-
-int NewTree = 1;
-
struct timespec uptime;
-static struct sockaddr *kgetsa(struct sockaddr *);
-static void size_cols(int ef, struct radix_node *rn);
-static void size_cols_tree(struct radix_node *rn);
-static void size_cols_rtentry(struct rtentry *rt);
-static void p_rtnode_kvm(void);
static void p_rtable_sysctl(int, int);
-static void p_rtable_kvm(int, int );
-static void p_rtree_kvm(const char *name, struct radix_node *);
-static void p_rtentry_kvm(const char *name, struct rtentry *);
static void p_rtentry_sysctl(const char *name, struct rt_msghdr *);
static void p_sockaddr(const char *name, struct sockaddr *, struct sockaddr *,
int, int);
@@ -166,6 +139,9 @@ routepr(int fibnum, int af)
size_t intsize;
int numfibs;
+ if (live == 0)
+ return;
+
intsize = sizeof(int);
if (fibnum == -1 &&
sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1)
@@ -187,11 +163,7 @@ routepr(int fibnum, int af)
if (fibnum)
xo_emit(" ({L:fib}: {:fib/%d})", fibnum);
xo_emit("\n");
-
- if (Aflag == 0 && live != 0 && NewTree)
- p_rtable_sysctl(fibnum, af);
- else
- p_rtable_kvm(fibnum, af);
+ p_rtable_sysctl(fibnum, af);
xo_close_container("route-information");
}
@@ -253,100 +225,6 @@ static int wid_mtu;
static int wid_if;
static int wid_expire;
-static void
-size_cols(int ef, struct radix_node *rn)
-{
- wid_dst = WID_DST_DEFAULT(ef);
- wid_gw = WID_GW_DEFAULT(ef);
- wid_flags = 6;
- wid_pksent = 8;
- wid_mtu = 6;
- wid_if = WID_IF_DEFAULT(ef);
- wid_expire = 6;
-
- if (Wflag && rn != NULL)
- size_cols_tree(rn);
-}
-
-static void
-size_cols_tree(struct radix_node *rn)
-{
-again:
- if (kget(rn, rnode) != 0)
- return;
- if (!(rnode.rn_flags & RNF_ACTIVE))
- return;
- if (rnode.rn_bit < 0) {
- if ((rnode.rn_flags & RNF_ROOT) == 0) {
- if (kget(rn, rtentry) != 0)
- return;
- size_cols_rtentry(&rtentry);
- }
- if ((rn = rnode.rn_dupedkey))
- goto again;
- } else {
- rn = rnode.rn_right;
- size_cols_tree(rnode.rn_left);
- size_cols_tree(rn);
- }
-}
-
-static void
-size_cols_rtentry(struct rtentry *rt)
-{
- static struct ifnet ifnet, *lastif;
- static char buffer[100];
- const char *bp;
- struct sockaddr *sa;
- sa_u addr, mask;
- int len;
-
- bzero(&addr, sizeof(addr));
- if ((sa = kgetsa(rt_key(rt))))
- bcopy(sa, &addr, sa->sa_len);
- bzero(&mask, sizeof(mask));
- if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
- bcopy(sa, &mask, sa->sa_len);
- bp = fmt_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags);
- len = strlen(bp);
- wid_dst = MAX(len, wid_dst);
-
- bp = fmt_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST);
- len = strlen(bp);
- wid_gw = MAX(len, wid_gw);
-
- bp = fmt_flags(rt->rt_flags);
- len = strlen(bp);
- wid_flags = MAX(len, wid_flags);
-
- if (Wflag) {
- len = snprintf(buffer, sizeof(buffer), "%ju",
- (uintmax_t )kread_counter((u_long )rt->rt_pksent));
- wid_pksent = MAX(len, wid_pksent);
- }
- if (rt->rt_ifp) {
- if (rt->rt_ifp != lastif) {
- if (kget(rt->rt_ifp, ifnet) == 0)
- len = strlen(ifnet.if_xname);
- else
- len = strlen("---");
- lastif = rt->rt_ifp;
- wid_if = MAX(len, wid_if);
- }
- if (rt->rt_expire) {
- time_t expire_time;
-
- if ((expire_time =
- rt->rt_expire - uptime.tv_sec) > 0) {
- len = snprintf(buffer, sizeof(buffer), "%d",
- (int)expire_time);
- wid_expire = MAX(len, wid_expire);
- }
- }
- }
-}
-
-
/*
* Print header for routing table columns.
*/
@@ -377,210 +255,6 @@ pr_rthdr(int af1)
}
}
-static struct sockaddr *
-kgetsa(struct sockaddr *dst)
-{
-
- if (kget(dst, pt_u.u_sa) != 0)
- return (NULL);
- if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
- kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
- return (&pt_u.u_sa);
-}
-
-/*
- * Print kernel routing tables for given fib
- * using debugging kvm(3) interface.
- */
-static void
-p_rtable_kvm(int fibnum, int af)
-{
- struct radix_node_head **rnhp, *rnh, head;
- struct radix_node_head **rt_tables;
- u_long rtree;
- int fam, af_size;
- bool did_rt_family = false;
-
- kresolve_list(rl);
- if ((rtree = rl[N_RTREE].n_value) == 0) {
- xo_emit("rt_tables: symbol not in namelist\n");
- return;
- }
-
- af_size = (AF_MAX + 1) * sizeof(struct radix_node_head *);
- rt_tables = calloc(1, af_size);
- if (rt_tables == NULL)
- err(EX_OSERR, "memory allocation failed");
-
- if (kread((u_long)(rtree), (char *)(rt_tables) + fibnum * af_size,
- af_size) != 0)
- err(EX_OSERR, "error retrieving radix pointers");
- xo_open_container("route-table");
- for (fam = 0; fam <= AF_MAX; fam++) {
- int tmpfib;
-
- switch (fam) {
- case AF_INET6:
- case AF_INET:
- tmpfib = fibnum;
- break;
- default:
- tmpfib = 0;
- }
- rnhp = (struct radix_node_head **)*rt_tables;
- /* Calculate the in-kernel address. */
- rnhp += tmpfib * (AF_MAX + 1) + fam;
- /* Read the in kernel rhn pointer. */
- if (kget(rnhp, rnh) != 0)
- continue;
- if (rnh == NULL)
- continue;
- /* Read the rnh data. */
- if (kget(rnh, head) != 0)
- continue;
- if (fam == AF_UNSPEC) {
- if (Aflag && af == 0) {
- xo_emit("{T:Netmasks}:\n");
- xo_open_list("netmasks");
- p_rtree_kvm("netmasks", head.rnh_treetop);
- xo_close_list("netmasks");
- }
- } else if (af == AF_UNSPEC || af == fam) {
- if (!did_rt_family) {
- xo_open_list("rt-family");
- did_rt_family = true;
- }
- size_cols(fam, head.rnh_treetop);
- xo_open_instance("rt-family");
- pr_family(fam);
- do_rtent = 1;
- xo_open_list("rt-entry");
- pr_rthdr(fam);
- p_rtree_kvm("rt-entry", head.rnh_treetop);
- xo_close_list("rt-entry");
- xo_close_instance("rt-family");
- }
- }
- if (did_rt_family)
- xo_close_list("rt-family");
- xo_close_container("route-table");
-
- free(rt_tables);
-}
-
-/*
- * Print given kernel radix tree using
- * debugging kvm(3) interface.
- */
-static void
-p_rtree_kvm(const char *name, struct radix_node *rn)
-{
- bool opened;
-
- opened = false;
-
-#define DOOPEN() do { \
- if (!opened) { xo_open_instance(name); opened = true; } \
- } while (0)
-#define DOCLOSE() do { \
- if (opened) { opened = false; xo_close_instance(name); } \
- } while(0)
-
-again:
- if (kget(rn, rnode) != 0)
- return;
- if (!(rnode.rn_flags & RNF_ACTIVE))
- return;
- if (rnode.rn_bit < 0) {
- if (Aflag) {
- DOOPEN();
- xo_emit("{q:radix-node/%-8.8lx} ", (u_long)rn);
- }
- if (rnode.rn_flags & RNF_ROOT) {
- if (Aflag) {
- DOOPEN();
- xo_emit("({:root/root} node){L:/%s}",
- rnode.rn_dupedkey ? " =>\n" : "\n");
- }
- } else if (do_rtent) {
- if (kget(rn, rtentry) == 0) {
- DOOPEN();
- p_rtentry_kvm(name, &rtentry);
- if (Aflag) {
- DOOPEN();
- p_rtnode_kvm();
- DOCLOSE();
- }
- }
- } else {
- DOOPEN();
- p_sockaddr("address",
- kgetsa((struct sockaddr *)rnode.rn_key),
- NULL, 0, 44);
- xo_emit("\n");
- }
- DOCLOSE();
- if ((rn = rnode.rn_dupedkey))
- goto again;
- } else {
- if (Aflag && do_rtent) {
- DOOPEN();
- xo_emit("{q:radix-node/%-8.8lx} ", (u_long)rn);
- p_rtnode_kvm();
- DOCLOSE();
- }
- rn = rnode.rn_right;
- p_rtree_kvm(name, rnode.rn_left);
- p_rtree_kvm(name, rn);
- }
-}
-
-char nbuf[20];
-
-static void
-p_rtnode_kvm(void)
-{
- struct radix_mask *rm = rnode.rn_mklist;
-
- if (rnode.rn_bit < 0) {
- if (rnode.rn_mask) {
- xo_emit("\t {L:mask} ");
- p_sockaddr("netmask",
- kgetsa((struct sockaddr *)rnode.rn_mask),
- NULL, 0, -1);
- } else if (rm == 0)
- return;
- } else {
- xo_emit("{[:6}{:bit/(%d)}{]:} {q:left-node/%8.8lx} "
- ": {q:right-node/%8.8lx}", rnode.rn_bit,
- (u_long)rnode.rn_left, (u_long)rnode.rn_right);
- }
- while (rm) {
- if (kget(rm, rmask) != 0)
- break;
- sprintf(nbuf, " %d refs, ", rmask.rm_refs);
- xo_emit(" mk = {q:node/%8.8lx} \\{({:bit/%d}),{nbufs/%s}",
- (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " ");
- if (rmask.rm_flags & RNF_NORMAL) {
- struct radix_node rnode_aux;
- xo_emit(" <{:mode/normal}>, ");
- if (kget(rmask.rm_leaf, rnode_aux) == 0)
- p_sockaddr("netmask",
- kgetsa(/*XXX*/(void *)rnode_aux.rn_mask),
- NULL, 0, -1);
- else
- p_sockaddr(NULL, NULL, NULL, 0, -1);
- } else
- p_sockaddr("netmask",
- kgetsa((struct sockaddr *)rmask.rm_mask),
- NULL, 0, -1);
- xo_emit("\\}");
- if ((rm = rmask.rm_mklist))
- xo_emit(" {D:->}");
- }
- xo_emit("\n");
-}
-
static void
p_rtable_sysctl(int fibnum, int af)
{
@@ -664,7 +338,13 @@ p_rtable_sysctl(int fibnum, int af)
need_table_close = true;
fam = sa->sa_family;
- size_cols(fam, NULL);
+ wid_dst = WID_DST_DEFAULT(fam);
+ wid_gw = WID_GW_DEFAULT(fam);
+ wid_flags = 6;
+ wid_pksent = 8;
+ wid_mtu = 6;
+ wid_if = WID_IF_DEFAULT(fam);
+ wid_expire = 6;
xo_open_instance("rt-family");
pr_family(fam);
xo_open_list("rt-entry");
@@ -905,61 +585,6 @@ fmt_flags(int f)
return (name);
}
-static void
-p_rtentry_kvm(const char *name, struct rtentry *rt)
-{
- static struct ifnet ifnet, *lastif;
- static char buffer[128];
- static char prettyname[128];
- struct sockaddr *sa;
- sa_u addr, mask;
-
- bzero(&addr, sizeof(addr));
- if ((sa = kgetsa(rt_key(rt))))
- bcopy(sa, &addr, sa->sa_len);
- bzero(&mask, sizeof(mask));
- if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
- bcopy(sa, &mask, sa->sa_len);
-
- p_sockaddr("destination", &addr.u_sa, &mask.u_sa, rt->rt_flags,
- wid_dst);
- p_sockaddr("gateway", kgetsa(rt->rt_gateway), NULL, RTF_HOST, wid_gw);
- snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:}",
- wid_flags);
- p_flags(rt->rt_flags, buffer);
- if (Wflag) {
- xo_emit("{[:%d}{t:use/%ju}{]:} ", -wid_pksent,
- (uintmax_t )kread_counter((u_long )rt->rt_pksent));
-
- if (rt->rt_mtu != 0)
- xo_emit("{t:mtu/%*lu} ", wid_mtu, rt->rt_mtu);
- else
- xo_emit("{P:/%*s} ", wid_mtu, "");
- }
- if (rt->rt_ifp) {
- if (rt->rt_ifp != lastif) {
- if (kget(rt->rt_ifp, ifnet) == 0)
- strlcpy(prettyname, ifnet.if_xname,
- sizeof(prettyname));
- else
- strlcpy(prettyname, "---", sizeof(prettyname));
- lastif = rt->rt_ifp;
- }
- xo_emit("{t:interface-name/%*.*s}", wid_if, wid_if, prettyname);
- if (rt->rt_expire) {
- time_t expire_time;
-
- if ((expire_time =
- rt->rt_expire - uptime.tv_sec) > 0)
- xo_emit(" {:expire-time/%*d}",
- wid_expire, (int)expire_time);
- }
- if (rt->rt_nodes[0].rn_dupedkey)
- xo_emit(" =>");
- }
- xo_emit("\n");
-}
-
char *
routename(in_addr_t in)
{
diff --git a/usr.bin/nfsstat/Makefile b/usr.bin/nfsstat/Makefile
index 10b0b31..fc92008 100644
--- a/usr.bin/nfsstat/Makefile
+++ b/usr.bin/nfsstat/Makefile
@@ -6,6 +6,4 @@ CFLAGS+=-DNFS
LIBADD= kvm
-WARNS?= 3
-
.include <bsd.prog.mk>
diff --git a/usr.bin/nfsstat/nfsstat.1 b/usr.bin/nfsstat/nfsstat.1
index 5ec048f..6568c6a 100644
--- a/usr.bin/nfsstat/nfsstat.1
+++ b/usr.bin/nfsstat/nfsstat.1
@@ -28,7 +28,7 @@
.\" From: @(#)nfsstat.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd May 1, 2013
+.Dd April 23, 2015
.Dt NFSSTAT 1
.Os
.Sh NAME
@@ -38,7 +38,7 @@
statistics
.Sh SYNOPSIS
.Nm
-.Op Fl cemoszW
+.Op Fl cemszW
.Op Fl M Ar core
.Op Fl N Ar system
.Op Fl w Ar wait
@@ -58,10 +58,8 @@ The options are as follows:
.It Fl c
Only display client side statistics.
.It Fl e
-Report the extra statistics collected by the new NFS client and
+Report the extra statistics collected by the NFS client and
server for NFSv4.
-This option is incompatible with
-.Fl o .
.It Fl M
Extract values associated with the name list from the specified core
instead of the default
@@ -75,10 +73,6 @@ This option is only supported by the new NFS client.
.It Fl N
Extract the name list from the specified system instead of the default
.Pa /boot/kernel/kernel .
-.It Fl o
-Report statistics for the old NFS client and/or server.
-Without this
-option statistics for the new NFS client and/or server will be reported.
.It Fl s
Only display server side statistics.
.It Fl W
diff --git a/usr.bin/nfsstat/nfsstat.c b/usr.bin/nfsstat/nfsstat.c
index a5537f7..32fbc96 100644
--- a/usr.bin/nfsstat/nfsstat.c
+++ b/usr.bin/nfsstat/nfsstat.c
@@ -70,31 +70,19 @@ static const char rcsid[] =
#include <paths.h>
#include <err.h>
-struct nlist nl[] = {
-#define N_NFSSTAT 0
- { .n_name = "nfsstats" },
-#define N_NFSRVSTAT 1
- { .n_name = "nfsrvstats" },
- { .n_name = NULL },
-};
-kvm_t *kd;
-
-static int deadkernel = 0;
static int widemode = 0;
static int zflag = 0;
-static int run_v4 = 1;
static int printtitle = 1;
static struct ext_nfsstats ext_nfsstats;
static int extra_output = 0;
-void intpr(int, int);
-void printhdr(int, int);
-void sidewaysintpr(u_int, int, int);
-void usage(void);
-char *sperc1(int, int);
-char *sperc2(int, int);
-void exp_intpr(int, int);
-void exp_sidewaysintpr(u_int, int, int);
+static void intpr(int, int);
+static void printhdr(int, int);
+static void usage(void);
+static char *sperc1(int, int);
+static char *sperc2(int, int);
+static void exp_intpr(int, int);
+static void exp_sidewaysintpr(u_int, int, int);
#define DELTA(field) (nfsstats.field - lastst.field)
@@ -106,7 +94,6 @@ main(int argc, char **argv)
int serverOnly = -1;
int ch;
char *memf, *nlistf;
- char errbuf[_POSIX2_LINE_MAX];
int mntlen, i;
char buf[1024];
struct statfs *mntbuf;
@@ -114,7 +101,7 @@ main(int argc, char **argv)
interval = 0;
memf = nlistf = NULL;
- while ((ch = getopt(argc, argv, "cesWM:mN:ow:z")) != -1)
+ while ((ch = getopt(argc, argv, "cesWM:mN:w:z")) != -1)
switch(ch) {
case 'M':
memf = optarg;
@@ -162,14 +149,7 @@ main(int argc, char **argv)
case 'z':
zflag = 1;
break;
- case 'o':
- if (extra_output != 0)
- err(1, "-o incompatible with -e");
- run_v4 = 0;
- break;
case 'e':
- if (run_v4 == 0)
- err(1, "-e incompatible with -o");
extra_output = 1;
break;
case '?':
@@ -190,26 +170,11 @@ main(int argc, char **argv)
}
}
#endif
- if (run_v4 != 0 && modfind("nfscommon") < 0)
- errx(1, "new client/server not loaded");
-
- if (run_v4 == 0 && (nlistf != NULL || memf != NULL)) {
- deadkernel = 1;
-
- if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY,
- errbuf)) == 0) {
- errx(1, "kvm_openfiles: %s", errbuf);
- }
- if (kvm_nlist(kd, nl) != 0) {
- errx(1, "kvm_nlist: can't get names");
- }
- }
+ if (modfind("nfscommon") < 0)
+ errx(1, "NFS client/server not loaded");
if (interval) {
- if (run_v4 > 0)
- exp_sidewaysintpr(interval, clientOnly, serverOnly);
- else
- sidewaysintpr(interval, clientOnly, serverOnly);
+ exp_sidewaysintpr(interval, clientOnly, serverOnly);
} else {
if (extra_output != 0)
exp_intpr(clientOnly, serverOnly);
@@ -220,441 +185,160 @@ main(int argc, char **argv)
}
/*
- * Read the nfs stats using sysctl(3) for live kernels, or kvm_read
- * for dead ones.
- */
-static void
-readstats(struct nfsstats **stp, struct nfsrvstats **srvstp, int zero)
-{
- union {
- struct nfsstats client;
- struct nfsrvstats server;
- } zerostat;
- size_t buflen;
-
- if (deadkernel) {
- if (*stp != NULL && kvm_read(kd, (u_long)nl[N_NFSSTAT].n_value,
- *stp, sizeof(struct nfsstats)) < 0) {
- *stp = NULL;
- }
- if (*srvstp != NULL && kvm_read(kd,
- (u_long)nl[N_NFSRVSTAT].n_value, *srvstp,
- sizeof(struct nfsrvstats)) < 0) {
- *srvstp = NULL;
- }
- } else {
- if (zero)
- bzero(&zerostat, sizeof(zerostat));
- buflen = sizeof(struct nfsstats);
- if (*stp != NULL && sysctlbyname("vfs.oldnfs.nfsstats", *stp,
- &buflen, zero ? &zerostat : NULL, zero ? buflen : 0) < 0) {
- if (errno != ENOENT)
- err(1, "sysctl: vfs.oldnfs.nfsstats");
- *stp = NULL;
- }
- buflen = sizeof(struct nfsrvstats);
- if (*srvstp != NULL && sysctlbyname("vfs.nfsrv.nfsrvstats",
- *srvstp, &buflen, zero ? &zerostat : NULL,
- zero ? buflen : 0) < 0) {
- if (errno != ENOENT)
- err(1, "sysctl: vfs.nfsrv.nfsrvstats");
- *srvstp = NULL;
- }
- }
-}
-
-/*
* Print a description of the nfs stats.
*/
-void
+static void
intpr(int clientOnly, int serverOnly)
{
- struct nfsstats nfsstats, *nfsstatsp;
- struct nfsrvstats nfsrvstats, *nfsrvstatsp;
int nfssvc_flag;
- if (run_v4 == 0) {
- /*
- * Only read the stats we are going to display to avoid zeroing
- * stats the user didn't request.
- */
- if (clientOnly)
- nfsstatsp = &nfsstats;
- else
- nfsstatsp = NULL;
- if (serverOnly)
- nfsrvstatsp = &nfsrvstats;
- else
- nfsrvstatsp = NULL;
-
- readstats(&nfsstatsp, &nfsrvstatsp, zflag);
-
- if (clientOnly && !nfsstatsp) {
- printf("Client not present!\n");
- clientOnly = 0;
- }
- } else {
- nfssvc_flag = NFSSVC_GETSTATS;
- if (zflag != 0) {
- if (clientOnly != 0)
- nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
- if (serverOnly != 0)
- nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
- }
- if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
- err(1, "Can't get stats");
+ nfssvc_flag = NFSSVC_GETSTATS;
+ if (zflag != 0) {
+ if (clientOnly != 0)
+ nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
+ if (serverOnly != 0)
+ nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
}
+ if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
+ err(1, "Can't get stats");
if (clientOnly) {
printf("Client Info:\n");
printf("Rpc Counts:\n");
printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Getattr", "Setattr", "Lookup", "Readlink", "Read",
"Write", "Create", "Remove");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- nfsstats.rpccnt[NFSPROC_GETATTR],
- nfsstats.rpccnt[NFSPROC_SETATTR],
- nfsstats.rpccnt[NFSPROC_LOOKUP],
- nfsstats.rpccnt[NFSPROC_READLINK],
- nfsstats.rpccnt[NFSPROC_READ],
- nfsstats.rpccnt[NFSPROC_WRITE],
- nfsstats.rpccnt[NFSPROC_CREATE],
- nfsstats.rpccnt[NFSPROC_REMOVE]);
- else
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- ext_nfsstats.rpccnt[NFSPROC_GETATTR],
- ext_nfsstats.rpccnt[NFSPROC_SETATTR],
- ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
- ext_nfsstats.rpccnt[NFSPROC_READLINK],
- ext_nfsstats.rpccnt[NFSPROC_READ],
- ext_nfsstats.rpccnt[NFSPROC_WRITE],
- ext_nfsstats.rpccnt[NFSPROC_CREATE],
- ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
+ printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
+ ext_nfsstats.rpccnt[NFSPROC_GETATTR],
+ ext_nfsstats.rpccnt[NFSPROC_SETATTR],
+ ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
+ ext_nfsstats.rpccnt[NFSPROC_READLINK],
+ ext_nfsstats.rpccnt[NFSPROC_READ],
+ ext_nfsstats.rpccnt[NFSPROC_WRITE],
+ ext_nfsstats.rpccnt[NFSPROC_CREATE],
+ ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
"Readdir", "RdirPlus", "Access");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- nfsstats.rpccnt[NFSPROC_RENAME],
- nfsstats.rpccnt[NFSPROC_LINK],
- nfsstats.rpccnt[NFSPROC_SYMLINK],
- nfsstats.rpccnt[NFSPROC_MKDIR],
- nfsstats.rpccnt[NFSPROC_RMDIR],
- nfsstats.rpccnt[NFSPROC_READDIR],
- nfsstats.rpccnt[NFSPROC_READDIRPLUS],
- nfsstats.rpccnt[NFSPROC_ACCESS]);
- else
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- ext_nfsstats.rpccnt[NFSPROC_RENAME],
- ext_nfsstats.rpccnt[NFSPROC_LINK],
- ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
- ext_nfsstats.rpccnt[NFSPROC_MKDIR],
- ext_nfsstats.rpccnt[NFSPROC_RMDIR],
- ext_nfsstats.rpccnt[NFSPROC_READDIR],
- ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
- ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
+ printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
+ ext_nfsstats.rpccnt[NFSPROC_RENAME],
+ ext_nfsstats.rpccnt[NFSPROC_LINK],
+ ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
+ ext_nfsstats.rpccnt[NFSPROC_MKDIR],
+ ext_nfsstats.rpccnt[NFSPROC_RMDIR],
+ ext_nfsstats.rpccnt[NFSPROC_READDIR],
+ ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
+ ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d %9d\n",
- nfsstats.rpccnt[NFSPROC_MKNOD],
- nfsstats.rpccnt[NFSPROC_FSSTAT],
- nfsstats.rpccnt[NFSPROC_FSINFO],
- nfsstats.rpccnt[NFSPROC_PATHCONF],
- nfsstats.rpccnt[NFSPROC_COMMIT]);
- else
- printf("%9d %9d %9d %9d %9d\n",
- ext_nfsstats.rpccnt[NFSPROC_MKNOD],
- ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
- ext_nfsstats.rpccnt[NFSPROC_FSINFO],
- ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
- ext_nfsstats.rpccnt[NFSPROC_COMMIT]);
+ printf("%9d %9d %9d %9d %9d\n",
+ ext_nfsstats.rpccnt[NFSPROC_MKNOD],
+ ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
+ ext_nfsstats.rpccnt[NFSPROC_FSINFO],
+ ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
+ ext_nfsstats.rpccnt[NFSPROC_COMMIT]);
printf("Rpc Info:\n");
printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
"TimedOut", "Invalid", "X Replies", "Retries",
"Requests");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d %9d\n",
- nfsstats.rpctimeouts,
- nfsstats.rpcinvalid,
- nfsstats.rpcunexpected,
- nfsstats.rpcretries,
- nfsstats.rpcrequests);
- else
- printf("%9d %9d %9d %9d %9d\n",
- ext_nfsstats.rpctimeouts,
- ext_nfsstats.rpcinvalid,
- ext_nfsstats.rpcunexpected,
- ext_nfsstats.rpcretries,
- ext_nfsstats.rpcrequests);
+ printf("%9d %9d %9d %9d %9d\n",
+ ext_nfsstats.rpctimeouts,
+ ext_nfsstats.rpcinvalid,
+ ext_nfsstats.rpcunexpected,
+ ext_nfsstats.rpcretries,
+ ext_nfsstats.rpcrequests);
printf("Cache Info:\n");
printf("%9.9s %9.9s %9.9s %9.9s",
"Attr Hits", "Misses", "Lkup Hits", "Misses");
printf(" %9.9s %9.9s %9.9s %9.9s\n",
"BioR Hits", "Misses", "BioW Hits", "Misses");
- if (run_v4 == 0) {
- printf("%9d %9d %9d %9d",
- nfsstats.attrcache_hits,
- nfsstats.attrcache_misses,
- nfsstats.lookupcache_hits,
- nfsstats.lookupcache_misses);
- printf(" %9d %9d %9d %9d\n",
- nfsstats.biocache_reads-nfsstats.read_bios,
- nfsstats.read_bios,
- nfsstats.biocache_writes-nfsstats.write_bios,
- nfsstats.write_bios);
- } else {
- printf("%9d %9d %9d %9d",
- ext_nfsstats.attrcache_hits,
- ext_nfsstats.attrcache_misses,
- ext_nfsstats.lookupcache_hits,
- ext_nfsstats.lookupcache_misses);
- printf(" %9d %9d %9d %9d\n",
- ext_nfsstats.biocache_reads -
- ext_nfsstats.read_bios,
- ext_nfsstats.read_bios,
- ext_nfsstats.biocache_writes -
- ext_nfsstats.write_bios,
- ext_nfsstats.write_bios);
- }
+ printf("%9d %9d %9d %9d",
+ ext_nfsstats.attrcache_hits,
+ ext_nfsstats.attrcache_misses,
+ ext_nfsstats.lookupcache_hits,
+ ext_nfsstats.lookupcache_misses);
+ printf(" %9d %9d %9d %9d\n",
+ ext_nfsstats.biocache_reads -
+ ext_nfsstats.read_bios,
+ ext_nfsstats.read_bios,
+ ext_nfsstats.biocache_writes -
+ ext_nfsstats.write_bios,
+ ext_nfsstats.write_bios);
printf("%9.9s %9.9s %9.9s %9.9s",
"BioRLHits", "Misses", "BioD Hits", "Misses");
printf(" %9.9s %9.9s %9.9s %9.9s\n", "DirE Hits", "Misses", "Accs Hits", "Misses");
- if (run_v4 == 0) {
- printf("%9d %9d %9d %9d",
- nfsstats.biocache_readlinks -
- nfsstats.readlink_bios,
- nfsstats.readlink_bios,
- nfsstats.biocache_readdirs -
- nfsstats.readdir_bios,
- nfsstats.readdir_bios);
- printf(" %9d %9d %9d %9d\n",
- nfsstats.direofcache_hits,
- nfsstats.direofcache_misses,
- nfsstats.accesscache_hits,
- nfsstats.accesscache_misses);
- } else {
- printf("%9d %9d %9d %9d",
- ext_nfsstats.biocache_readlinks -
- ext_nfsstats.readlink_bios,
- ext_nfsstats.readlink_bios,
- ext_nfsstats.biocache_readdirs -
- ext_nfsstats.readdir_bios,
- ext_nfsstats.readdir_bios);
- printf(" %9d %9d %9d %9d\n",
- ext_nfsstats.direofcache_hits,
- ext_nfsstats.direofcache_misses,
- ext_nfsstats.accesscache_hits,
- ext_nfsstats.accesscache_misses);
- }
- }
- if (run_v4 == 0 && serverOnly && !nfsrvstatsp) {
- printf("Server not present!\n");
- serverOnly = 0;
+ printf("%9d %9d %9d %9d",
+ ext_nfsstats.biocache_readlinks -
+ ext_nfsstats.readlink_bios,
+ ext_nfsstats.readlink_bios,
+ ext_nfsstats.biocache_readdirs -
+ ext_nfsstats.readdir_bios,
+ ext_nfsstats.readdir_bios);
+ printf(" %9d %9d %9d %9d\n",
+ ext_nfsstats.direofcache_hits,
+ ext_nfsstats.direofcache_misses,
+ ext_nfsstats.accesscache_hits,
+ ext_nfsstats.accesscache_misses);
}
if (serverOnly) {
printf("\nServer Info:\n");
printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Getattr", "Setattr", "Lookup", "Readlink", "Read",
"Write", "Create", "Remove");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- nfsrvstats.srvrpccnt[NFSPROC_GETATTR],
- nfsrvstats.srvrpccnt[NFSPROC_SETATTR],
- nfsrvstats.srvrpccnt[NFSPROC_LOOKUP],
- nfsrvstats.srvrpccnt[NFSPROC_READLINK],
- nfsrvstats.srvrpccnt[NFSPROC_READ],
- nfsrvstats.srvrpccnt[NFSPROC_WRITE],
- nfsrvstats.srvrpccnt[NFSPROC_CREATE],
- nfsrvstats.srvrpccnt[NFSPROC_REMOVE]);
- else
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
- ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
- ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
- ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
- ext_nfsstats.srvrpccnt[NFSV4OP_READ],
- ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
- ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
- ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
+ printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
+ ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
+ ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
+ ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
+ ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
+ ext_nfsstats.srvrpccnt[NFSV4OP_READ],
+ ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
+ ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
+ ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
"Readdir", "RdirPlus", "Access");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- nfsrvstats.srvrpccnt[NFSPROC_RENAME],
- nfsrvstats.srvrpccnt[NFSPROC_LINK],
- nfsrvstats.srvrpccnt[NFSPROC_SYMLINK],
- nfsrvstats.srvrpccnt[NFSPROC_MKDIR],
- nfsrvstats.srvrpccnt[NFSPROC_RMDIR],
- nfsrvstats.srvrpccnt[NFSPROC_READDIR],
- nfsrvstats.srvrpccnt[NFSPROC_READDIRPLUS],
- nfsrvstats.srvrpccnt[NFSPROC_ACCESS]);
- else
- printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
- ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
- ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
- ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
- ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
- ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
- ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
- ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
- ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
+ printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
+ ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
+ ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
+ ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
+ ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
+ ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
+ ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
+ ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
+ ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d %9d\n",
- nfsrvstats.srvrpccnt[NFSPROC_MKNOD],
- nfsrvstats.srvrpccnt[NFSPROC_FSSTAT],
- nfsrvstats.srvrpccnt[NFSPROC_FSINFO],
- nfsrvstats.srvrpccnt[NFSPROC_PATHCONF],
- nfsrvstats.srvrpccnt[NFSPROC_COMMIT]);
- else
- printf("%9d %9d %9d %9d %9d\n",
- ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
- ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
- ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
- ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
- ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);
+ printf("%9d %9d %9d %9d %9d\n",
+ ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
+ ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
+ ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
+ ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
+ ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);
printf("Server Ret-Failed\n");
- if (run_v4 == 0)
- printf("%17d\n", nfsrvstats.srvrpc_errs);
- else
- printf("%17d\n", ext_nfsstats.srvrpc_errs);
+ printf("%17d\n", ext_nfsstats.srvrpc_errs);
printf("Server Faults\n");
- if (run_v4 == 0)
- printf("%13d\n", nfsrvstats.srv_errs);
- else
- printf("%13d\n", ext_nfsstats.srv_errs);
+ printf("%13d\n", ext_nfsstats.srv_errs);
printf("Server Cache Stats:\n");
printf("%9.9s %9.9s %9.9s %9.9s\n",
"Inprog", "Idem", "Non-idem", "Misses");
- if (run_v4 == 0)
- printf("%9d %9d %9d %9d\n",
- nfsrvstats.srvcache_inproghits,
- nfsrvstats.srvcache_idemdonehits,
- nfsrvstats.srvcache_nonidemdonehits,
- nfsrvstats.srvcache_misses);
- else
- printf("%9d %9d %9d %9d\n",
- ext_nfsstats.srvcache_inproghits,
- ext_nfsstats.srvcache_idemdonehits,
- ext_nfsstats.srvcache_nonidemdonehits,
- ext_nfsstats.srvcache_misses);
+ printf("%9d %9d %9d %9d\n",
+ ext_nfsstats.srvcache_inproghits,
+ ext_nfsstats.srvcache_idemdonehits,
+ ext_nfsstats.srvcache_nonidemdonehits,
+ ext_nfsstats.srvcache_misses);
printf("Server Write Gathering:\n");
printf("%9.9s %9.9s %9.9s\n",
"WriteOps", "WriteRPC", "Opsaved");
- if (run_v4 == 0)
- printf("%9d %9d %9d\n",
- nfsrvstats.srvvop_writes,
- nfsrvstats.srvrpccnt[NFSPROC_WRITE],
- nfsrvstats.srvrpccnt[NFSPROC_WRITE] -
- nfsrvstats.srvvop_writes);
- else
- /*
- * The new client doesn't do write gathering. It was
- * only useful for NFSv2.
- */
- printf("%9d %9d %9d\n",
- ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
- ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);
- }
-}
-
-u_char signalled; /* set if alarm goes off "early" */
-
-/*
- * Print a running summary of nfs statistics.
- * Repeat display every interval seconds, showing statistics
- * collected over that interval. Assumes that interval is non-zero.
- * First line printed at top of screen is always cumulative.
- */
-void
-sidewaysintpr(u_int interval, int clientOnly, int serverOnly)
-{
- struct nfsstats nfsstats, lastst, *nfsstatsp;
- struct nfsrvstats nfsrvstats, lastsrvst, *nfsrvstatsp;
- int hdrcnt = 1;
-
- nfsstatsp = &lastst;
- nfsrvstatsp = &lastsrvst;
- readstats(&nfsstatsp, &nfsrvstatsp, 0);
- if (clientOnly && !nfsstatsp) {
- printf("Client not present!\n");
- clientOnly = 0;
- }
- if (serverOnly && !nfsrvstatsp) {
- printf("Server not present!\n");
- serverOnly = 0;
- }
- sleep(interval);
-
- for (;;) {
- nfsstatsp = &nfsstats;
- nfsrvstatsp = &nfsrvstats;
- readstats(&nfsstatsp, &nfsrvstatsp, 0);
-
- if (--hdrcnt == 0) {
- printhdr(clientOnly, serverOnly);
- if (clientOnly && serverOnly)
- hdrcnt = 10;
- else
- hdrcnt = 20;
- }
- if (clientOnly) {
- printf("%s %6d %6d %6d %6d %6d %6d %6d %6d",
- ((clientOnly && serverOnly) ? "Client:" : ""),
- DELTA(rpccnt[NFSPROC_GETATTR]),
- DELTA(rpccnt[NFSPROC_LOOKUP]),
- DELTA(rpccnt[NFSPROC_READLINK]),
- DELTA(rpccnt[NFSPROC_READ]),
- DELTA(rpccnt[NFSPROC_WRITE]),
- DELTA(rpccnt[NFSPROC_RENAME]),
- DELTA(rpccnt[NFSPROC_ACCESS]),
- DELTA(rpccnt[NFSPROC_READDIR]) +
- DELTA(rpccnt[NFSPROC_READDIRPLUS])
- );
- if (widemode) {
- printf(" %s %s %s %s %s %s",
- sperc1(DELTA(attrcache_hits),
- DELTA(attrcache_misses)),
- sperc1(DELTA(lookupcache_hits),
- DELTA(lookupcache_misses)),
- sperc2(DELTA(biocache_reads),
- DELTA(read_bios)),
- sperc2(DELTA(biocache_writes),
- DELTA(write_bios)),
- sperc1(DELTA(accesscache_hits),
- DELTA(accesscache_misses)),
- sperc2(DELTA(biocache_readdirs),
- DELTA(readdir_bios))
- );
- }
- printf("\n");
- lastst = nfsstats;
- }
- if (serverOnly) {
- printf("%s %6d %6d %6d %6d %6d %6d %6d %6d",
- ((clientOnly && serverOnly) ? "Server:" : ""),
- nfsrvstats.srvrpccnt[NFSPROC_GETATTR]-lastsrvst.srvrpccnt[NFSPROC_GETATTR],
- nfsrvstats.srvrpccnt[NFSPROC_LOOKUP]-lastsrvst.srvrpccnt[NFSPROC_LOOKUP],
- nfsrvstats.srvrpccnt[NFSPROC_READLINK]-lastsrvst.srvrpccnt[NFSPROC_READLINK],
- nfsrvstats.srvrpccnt[NFSPROC_READ]-lastsrvst.srvrpccnt[NFSPROC_READ],
- nfsrvstats.srvrpccnt[NFSPROC_WRITE]-lastsrvst.srvrpccnt[NFSPROC_WRITE],
- nfsrvstats.srvrpccnt[NFSPROC_RENAME]-lastsrvst.srvrpccnt[NFSPROC_RENAME],
- nfsrvstats.srvrpccnt[NFSPROC_ACCESS]-lastsrvst.srvrpccnt[NFSPROC_ACCESS],
- (nfsrvstats.srvrpccnt[NFSPROC_READDIR]-lastsrvst.srvrpccnt[NFSPROC_READDIR])
- +(nfsrvstats.srvrpccnt[NFSPROC_READDIRPLUS]-lastsrvst.srvrpccnt[NFSPROC_READDIRPLUS]));
- printf("\n");
- lastsrvst = nfsrvstats;
- }
- fflush(stdout);
- sleep(interval);
+ /*
+ * The new client doesn't do write gathering. It was
+ * only useful for NFSv2.
+ */
+ printf("%9d %9d %9d\n",
+ ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
+ ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);
}
- /*NOTREACHED*/
}
-void
+static void
printhdr(int clientOnly, int serverOnly)
{
printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s",
@@ -668,18 +352,18 @@ printhdr(int clientOnly, int serverOnly)
fflush(stdout);
}
-void
+static void
usage(void)
{
(void)fprintf(stderr,
- "usage: nfsstat [-cemoszW] [-M core] [-N system] [-w wait]\n");
+ "usage: nfsstat [-cemszW] [-M core] [-N system] [-w wait]\n");
exit(1);
}
static char SPBuf[64][8];
static int SPIndex;
-char *
+static char *
sperc1(int hits, int misses)
{
char *p = SPBuf[SPIndex];
@@ -694,7 +378,7 @@ sperc1(int hits, int misses)
return(p);
}
-char *
+static char *
sperc2(int ttl, int misses)
{
char *p = SPBuf[SPIndex];
@@ -712,7 +396,7 @@ sperc2(int ttl, int misses)
/*
* Print a description of the nfs stats for the experimental client/server.
*/
-void
+static void
exp_intpr(int clientOnly, int serverOnly)
{
int nfssvc_flag;
@@ -968,7 +652,7 @@ exp_intpr(int clientOnly, int serverOnly)
* collected over that interval. Assumes that interval is non-zero.
* First line printed at top of screen is always cumulative.
*/
-void
+static void
exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly)
{
struct ext_nfsstats nfsstats, lastst, *ext_nfsstatsp;
@@ -1042,4 +726,3 @@ exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly)
}
/*NOTREACHED*/
}
-
diff --git a/usr.bin/patch/inp.c b/usr.bin/patch/inp.c
index 54b0bf2..826f85b 100644
--- a/usr.bin/patch/inp.c
+++ b/usr.bin/patch/inp.c
@@ -34,8 +34,8 @@
#include <ctype.h>
#include <libgen.h>
-#include <limits.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -57,8 +57,9 @@ static char empty_line[] = { '\0' };
static int tifd = -1; /* plan b virtual string array */
static char *tibuf[2]; /* plan b buffers */
static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
-static LINENUM lines_per_buf; /* how many lines per buffer */
-static int tireclen; /* length of records in tmp file */
+static size_t lines_per_buf; /* how many lines per buffer */
+static size_t tibuflen; /* plan b buffer length */
+static size_t tireclen; /* length of records in tmp file */
static bool rev_in_string(const char *);
static bool reallocate_lines(size_t *);
@@ -319,7 +320,7 @@ plan_a(const char *filename)
/* now check for revision, if any */
if (revision != NULL) {
- if (!rev_in_string(i_womp)) {
+ if (i_womp == NULL || !rev_in_string(i_womp)) {
if (force) {
if (verbose)
say("Warning: this file doesn't appear "
@@ -349,8 +350,8 @@ static void
plan_b(const char *filename)
{
FILE *ifp;
- size_t i = 0, j, maxlen = 1;
- char *p;
+ size_t i = 0, j, len, maxlen = 1;
+ char *lbuf = NULL, *p;
bool found_revision = (revision == NULL);
using_plan_a = false;
@@ -359,15 +360,28 @@ plan_b(const char *filename)
unlink(TMPINNAME);
if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0)
pfatal("can't open file %s", TMPINNAME);
- while (fgets(buf, buf_size, ifp) != NULL) {
- if (revision != NULL && !found_revision && rev_in_string(buf))
+ while ((p = fgetln(ifp, &len)) != NULL) {
+ if (p[len - 1] == '\n')
+ p[len - 1] = '\0';
+ else {
+ /* EOF without EOL, copy and add the NUL */
+ if ((lbuf = malloc(len + 1)) == NULL)
+ fatal("out of memory\n");
+ memcpy(lbuf, p, len);
+ lbuf[len] = '\0';
+ p = lbuf;
+
+ last_line_missing_eol = true;
+ len++;
+ }
+ if (revision != NULL && !found_revision && rev_in_string(p))
found_revision = true;
- if ((i = strlen(buf)) > maxlen)
- maxlen = i; /* find longest line */
+ if (len > maxlen)
+ maxlen = len; /* find longest line */
}
- last_line_missing_eol = i > 0 && buf[i - 1] != '\n';
- if (last_line_missing_eol && maxlen == i)
- maxlen++;
+ free(lbuf);
+ if (ferror(ifp))
+ pfatal("can't read file %s", filename);
if (revision != NULL) {
if (!found_revision) {
@@ -392,23 +406,26 @@ plan_b(const char *filename)
revision);
}
fseek(ifp, 0L, SEEK_SET); /* rewind file */
- lines_per_buf = BUFFERSIZE / maxlen;
tireclen = maxlen;
- tibuf[0] = malloc(BUFFERSIZE + 1);
+ tibuflen = maxlen > BUFFERSIZE ? maxlen : BUFFERSIZE;
+ lines_per_buf = tibuflen / maxlen;
+ tibuf[0] = malloc(tibuflen + 1);
if (tibuf[0] == NULL)
fatal("out of memory\n");
- tibuf[1] = malloc(BUFFERSIZE + 1);
+ tibuf[1] = malloc(tibuflen + 1);
if (tibuf[1] == NULL)
fatal("out of memory\n");
for (i = 1;; i++) {
p = tibuf[0] + maxlen * (i % lines_per_buf);
if (i % lines_per_buf == 0) /* new block */
- if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ if (write(tifd, tibuf[0], tibuflen) !=
+ (ssize_t) tibuflen)
pfatal("can't write temp file");
if (fgets(p, maxlen + 1, ifp) == NULL) {
input_lines = i - 1;
if (i % lines_per_buf != 0)
- if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ if (write(tifd, tibuf[0], tibuflen) !=
+ (ssize_t) tibuflen)
pfatal("can't write temp file");
break;
}
@@ -450,10 +467,11 @@ ifetch(LINENUM line, int whichbuf)
tiline[whichbuf] = baseline;
if (lseek(tifd, (off_t) (baseline / lines_per_buf *
- BUFFERSIZE), SEEK_SET) < 0)
+ tibuflen), SEEK_SET) < 0)
pfatal("cannot seek in the temporary input file");
- if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
+ if (read(tifd, tibuf[whichbuf], tibuflen) !=
+ (ssize_t) tibuflen)
pfatal("error reading tmp file %s", TMPINNAME);
}
return tibuf[whichbuf] + (tireclen * offline);
diff --git a/usr.bin/patch/pch.c b/usr.bin/patch/pch.c
index aacafc8..e731ca1 100644
--- a/usr.bin/patch/pch.c
+++ b/usr.bin/patch/pch.c
@@ -34,6 +34,7 @@
#include <ctype.h>
#include <libgen.h>
#include <limits.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.bin/patch/util.c b/usr.bin/patch/util.c
index 27ee1ae..1859e17 100644
--- a/usr.bin/patch/util.c
+++ b/usr.bin/patch/util.c
@@ -27,13 +27,13 @@
* $FreeBSD$
*/
-#include <sys/param.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
+#include <limits.h>
#include <paths.h>
#include <signal.h>
#include <stdarg.h>
@@ -96,7 +96,7 @@ int
backup_file(const char *orig)
{
struct stat filestat;
- char bakname[MAXPATHLEN], *s, *simplename;
+ char bakname[PATH_MAX], *s, *simplename;
dev_t orig_device;
ino_t orig_inode;
@@ -406,7 +406,7 @@ fetchname(const char *at, bool *exists, int strip_leading)
char *
checked_in(char *file)
{
- char *filebase, *filedir, tmpbuf[MAXPATHLEN];
+ char *filebase, *filedir, tmpbuf[PATH_MAX];
struct stat filestat;
filebase = basename(file);
diff --git a/usr.bin/perror/perror.1 b/usr.bin/perror/perror.1
index 0b724b1..6fa1664 100644
--- a/usr.bin/perror/perror.1
+++ b/usr.bin/perror/perror.1
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 2009 Advanced Computing Technologies LLC
+.\" Copyright (c) 2009 Hudson River Trading LLC
.\" Written by: George V. Neville-Neil <gnn@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/usr.bin/perror/perror.c b/usr.bin/perror/perror.c
index ef3db35..62af5df 100644
--- a/usr.bin/perror/perror.c
+++ b/usr.bin/perror/perror.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009 Advanced Computing Technologies LLC
+ * Copyright (c) 2009 Hudson River Trading LLC
* Written by: George V. Neville-Neil <gnn@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.bin/procstat/procstat_rusage.c b/usr.bin/procstat/procstat_rusage.c
index b3c9d99..63e5ab8 100644
--- a/usr.bin/procstat/procstat_rusage.c
+++ b/usr.bin/procstat/procstat_rusage.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2012 Advanced Computing Technologies LLC
+ * Copyright (c) 2012 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.bin/protect/protect.1 b/usr.bin/protect/protect.1
index 919714e..b9be4af 100644
--- a/usr.bin/protect/protect.1
+++ b/usr.bin/protect/protect.1
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2013 Advanced Computing Technologies LLC
+.\" Copyright (c) 2013 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/usr.bin/protect/protect.c b/usr.bin/protect/protect.c
index ba15aa6..16b0d29 100644
--- a/usr.bin/protect/protect.c
+++ b/usr.bin/protect/protect.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.bin/rctl/rctl.c b/usr.bin/rctl/rctl.c
index 185788d..b534258 100644
--- a/usr.bin/rctl/rctl.c
+++ b/usr.bin/rctl/rctl.c
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/rctl.h>
+#include <sys/sysctl.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
@@ -305,13 +306,37 @@ print_rules(char *rules, int hflag, int nflag)
}
static void
+enosys(void)
+{
+ int error, racct_enable;
+ size_t racct_enable_len;
+
+ racct_enable_len = sizeof(racct_enable);
+ error = sysctlbyname("kern.racct.enable",
+ &racct_enable, &racct_enable_len, NULL, 0);
+
+ if (error != 0) {
+ if (errno == ENOENT)
+ errx(1, "RACCT/RCTL support not present in kernel; see rctl(8) for details");
+
+ err(1, "sysctlbyname");
+ }
+
+ if (racct_enable == 0)
+ errx(1, "RACCT/RCTL present, but disabled; enable using kern.racct.enable=1 tunable");
+}
+
+static void
add_rule(char *rule)
{
int error;
error = rctl_add_rule(rule, strlen(rule) + 1, NULL, 0);
- if (error != 0)
+ if (error != 0) {
+ if (errno == ENOSYS)
+ enosys();
err(1, "rctl_add_rule");
+ }
free(rule);
}
@@ -330,8 +355,11 @@ show_limits(char *filter, int hflag, int nflag)
error = rctl_get_limits(filter, strlen(filter) + 1, outbuf,
outbuflen);
- if (error && errno != ERANGE)
+ if (error && errno != ERANGE) {
+ if (errno == ENOSYS)
+ enosys();
err(1, "rctl_get_limits");
+ }
} while (error && errno == ERANGE);
print_rules(outbuf, hflag, nflag);
@@ -345,8 +373,11 @@ remove_rule(char *filter)
int error;
error = rctl_remove_rule(filter, strlen(filter) + 1, NULL, 0);
- if (error != 0)
+ if (error != 0) {
+ if (errno == ENOSYS)
+ enosys();
err(1, "rctl_remove_rule");
+ }
free(filter);
}
@@ -399,8 +430,11 @@ show_usage(char *filter, int hflag)
error = rctl_get_racct(filter, strlen(filter) + 1, outbuf,
outbuflen);
- if (error && errno != ERANGE)
+ if (error && errno != ERANGE) {
+ if (errno == ENOSYS)
+ enosys();
err(1, "rctl_get_racct");
+ }
} while (error && errno == ERANGE);
while ((tmp = strsep(&outbuf, ",")) != NULL) {
@@ -439,8 +473,11 @@ show_rules(char *filter, int hflag, int nflag)
err(1, "realloc");
error = rctl_get_rules(filter, filterlen, outbuf, outbuflen);
- if (error && errno != ERANGE)
+ if (error && errno != ERANGE) {
+ if (errno == ENOSYS)
+ enosys();
err(1, "rctl_get_rules");
+ }
} while (error && errno == ERANGE);
print_rules(outbuf, hflag, nflag);
diff --git a/usr.bin/rpcgen/rpc_sample.c b/usr.bin/rpcgen/rpc_sample.c
index 6a2bef8..5d6c9a9 100644
--- a/usr.bin/rpcgen/rpc_sample.c
+++ b/usr.bin/rpcgen/rpc_sample.c
@@ -115,7 +115,7 @@ write_sample_client(const char *program_name, version_list *vp)
for (l = proc->args.decls; l != NULL; l = l->next) {
f_print(fout, "\t");
ptype(l->decl.prefix, l->decl.type, 1);
- if (strcmp(l->decl.type,"string") == 1)
+ if (strcmp(l->decl.type,"string") >= 1)
f_print(fout, " ");
pvname(proc->proc_name, vp->vers_num);
f_print(fout, "_%s;\n", l->decl.name);
diff --git a/usr.bin/rs/rs.1 b/usr.bin/rs/rs.1
index 6ff1842..23a37b8 100644
--- a/usr.bin/rs/rs.1
+++ b/usr.bin/rs/rs.1
@@ -28,7 +28,7 @@
.\" @(#)rs.1 8.2 (Berkeley) 12/30/93
.\" $FreeBSD$
.\"
-.Dd February 25, 2011
+.Dd April 7, 2015
.Dt RS 1
.Os
.Sh NAME
@@ -222,6 +222,8 @@ The
.Nm
utility first appeared in
.Bx 4.2 .
+.Sh AUTHORS
+.An John A. Kunze
.Sh BUGS
.Bl -item
.It
diff --git a/usr.bin/smbutil/Makefile b/usr.bin/smbutil/Makefile
index 56367e8..2012124 100644
--- a/usr.bin/smbutil/Makefile
+++ b/usr.bin/smbutil/Makefile
@@ -3,7 +3,7 @@
PROG= smbutil
SRCS= smbutil.c dumptree.c login.c lookup.c view.c print.c
-LIBADD= smb kiconv
+LIBADD= smb
CONTRIBDIR= ${.CURDIR}/../../contrib/smbfs
CFLAGS+= -I${CONTRIBDIR}/include
diff --git a/usr.bin/sockstat/sockstat.1 b/usr.bin/sockstat/sockstat.1
index b27a784..5076ae8 100644
--- a/usr.bin/sockstat/sockstat.1
+++ b/usr.bin/sockstat/sockstat.1
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 16, 2012
+.Dd April 7, 2015
.Dt SOCKSTAT 1
.Os
.Sh NAME
@@ -69,7 +69,7 @@ or do not contain the IPv6 loopback address
.It Fl l
Show listening sockets.
.It Fl p Ar ports
-Only show Internet sockets if either the local or foreign port number
+Only show Internet sockets if the local or foreign port number
is on the specified list.
The
.Ar ports
diff --git a/usr.bin/soelim/Makefile b/usr.bin/soelim/Makefile
new file mode 100644
index 0000000..21eaaff
--- /dev/null
+++ b/usr.bin/soelim/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+PROG= soelim
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/soeliminate/soeliminate.1 b/usr.bin/soelim/soelim.1
index eeb5657..b6ec13c 100644
--- a/usr.bin/soeliminate/soeliminate.1
+++ b/usr.bin/soelim/soelim.1
@@ -24,11 +24,11 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 22, 2014
-.Dt SOELIMINATE 1
+.Dd May 1, 2015
+.Dt SOELIM 1
.Os
.Sh NAME
-.Nm soeliminate
+.Nm soelim
.Nd interpret .so directive in manpages
.Sh SYNOPSIS
.Nm
@@ -48,9 +48,9 @@ it replace the line by processing
Otherwise the line is printed to stdout.
.Bl -tag -width "-I dir"
.It Fl C
-Compatibility with GNU groff's
-.Xr soelim 1
-(does nothing).
+Recognise
+.Em .so
+when not followed by a space character.
.It Fl r
Compatibility with GNU groff's
.Xr soelim 1
diff --git a/usr.bin/soeliminate/soeliminate.c b/usr.bin/soelim/soelim.c
index 80b337f..700ae57 100644
--- a/usr.bin/soeliminate/soeliminate.c
+++ b/usr.bin/soelim/soelim.c
@@ -39,13 +39,15 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <ctype.h>
+#define C_OPTION 0x1
+
static StringList *includes;
static void
usage(void)
{
- fprintf(stderr, "usage: soeliminate [-Crtv] [-I dir] [files]\n");
+ fprintf(stderr, "usage: soelim [-Crtv] [-I dir] [files]\n");
exit(EXIT_FAILURE);
}
@@ -57,6 +59,9 @@ soelim_fopen(const char *name)
char path[MAXPATHLEN];
size_t i;
+ if (strcmp(name, "-") == 0)
+ return (stdin);
+
if ((f = fopen(name, "r")) != NULL)
return (f);
@@ -78,10 +83,10 @@ soelim_fopen(const char *name)
}
static int
-soelim_file(FILE *f)
+soelim_file(FILE *f, int flag)
{
char *line = NULL;
- char *walk;
+ char *walk, *cp;
size_t linecap = 0;
ssize_t linelen;
@@ -93,13 +98,27 @@ soelim_file(FILE *f)
printf("%s", line);
continue;
}
+
walk = line + 3;
+ if (!isspace(*walk) && ((flag & C_OPTION) == 0)) {
+ printf("%s", line);
+ continue;
+ }
+
while (isspace(*walk))
walk++;
- while (isspace(walk[strlen(walk) - 1]))
- walk[strlen(walk) - 1] = '\0';
- if (soelim_file(soelim_fopen(walk)) == 1) {
+ cp = walk + strlen(walk) - 1;
+ while (cp > walk && isspace(*cp)) {
+ *cp = 0;
+ cp--;
+ }
+
+ if (*walk == '\0') {
+ printf("%s", line);
+ continue;
+ }
+ if (soelim_file(soelim_fopen(walk), flag) == 1) {
free(line);
return (1);
}
@@ -116,6 +135,7 @@ main(int argc, char **argv)
{
int ch, i;
int ret = 0;
+ int flags = 0;
includes = sl_init();
if (includes == NULL)
@@ -124,6 +144,8 @@ main(int argc, char **argv)
while ((ch = getopt(argc, argv, "CrtvI:")) != -1) {
switch (ch) {
case 'C':
+ flags |= C_OPTION;
+ break;
case 'r':
case 'v':
case 't':
@@ -142,10 +164,10 @@ main(int argc, char **argv)
argv += optind;
if (argc == 0)
- ret = soelim_file(stdin);
+ ret = soelim_file(stdin, flags);
for (i = 0; i < argc; i++)
- ret = soelim_file(soelim_fopen(argv[i]));
+ ret = soelim_file(soelim_fopen(argv[i]), flags);
sl_free(includes, 0);
diff --git a/usr.bin/soelim/tests/Makefile b/usr.bin/soelim/tests/Makefile
new file mode 100644
index 0000000..604e2f4
--- /dev/null
+++ b/usr.bin/soelim/tests/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/usr.bin/soelim
+
+ATF_TESTS_SH= soelim
+
+FILES= nonexisting.in \
+ basic.in \
+ basic \
+ basic.out
+FILESDIR= ${TESTSDIR}
+
+.include <bsd.test.mk>
diff --git a/usr.bin/soelim/tests/basic b/usr.bin/soelim/tests/basic
new file mode 100644
index 0000000..c4fe1dd
--- /dev/null
+++ b/usr.bin/soelim/tests/basic
@@ -0,0 +1 @@
+basic has been included
diff --git a/usr.bin/soelim/tests/basic.in b/usr.bin/soelim/tests/basic.in
new file mode 100644
index 0000000..cd32eb1
--- /dev/null
+++ b/usr.bin/soelim/tests/basic.in
@@ -0,0 +1,3 @@
+This is a test
+.so basic
+end
diff --git a/usr.bin/soelim/tests/basic.out b/usr.bin/soelim/tests/basic.out
new file mode 100644
index 0000000..db59fbb
--- /dev/null
+++ b/usr.bin/soelim/tests/basic.out
@@ -0,0 +1,3 @@
+This is a test
+basic has been included
+end
diff --git a/usr.bin/soelim/tests/nonexisting.in b/usr.bin/soelim/tests/nonexisting.in
new file mode 100644
index 0000000..e07599d
--- /dev/null
+++ b/usr.bin/soelim/tests/nonexisting.in
@@ -0,0 +1,3 @@
+This is a test
+.so nonexistingfile
+This is next
diff --git a/usr.bin/soelim/tests/soelim.sh b/usr.bin/soelim/tests/soelim.sh
new file mode 100755
index 0000000..ea46618
--- /dev/null
+++ b/usr.bin/soelim/tests/soelim.sh
@@ -0,0 +1,96 @@
+# $FreeBSD$
+
+atf_test_case stdin
+stdin_head()
+{
+ atf_set "descr" "stdin functionality"
+}
+
+stdin_body()
+{
+ # no file after .so
+ atf_check \
+ -o inline:".so\n" \
+ -e empty \
+ -s exit:0 \
+ soelim <<-EOF
+.so
+EOF
+
+ # only space after .so
+ atf_check \
+ -o inline:".so \n" \
+ -e empty \
+ -s exit:0 \
+ soelim <<-EOF
+.so
+EOF
+
+ # explicit stdin
+ atf_check \
+ -o inline:".so\n" \
+ -e empty \
+ -s exit:0 \
+ soelim - <<-EOF
+.so
+EOF
+
+ atf_check \
+ -o empty \
+ -e inline:"soelim: can't open 'afile': No such file or directory\n" \
+ -s exit:1 \
+ soelim <<-EOF
+.so afile
+EOF
+
+ atf_check \
+ -o inline:".soafile\n" \
+ -e empty \
+ -s exit:0 \
+ soelim <<-EOF
+.soafile
+EOF
+
+ atf_check \
+ -o empty \
+ -e inline:"soelim: can't open 'afile': No such file or directory\n" \
+ -s exit:1 \
+ soelim -C <<-EOF
+.soafile
+EOF
+}
+
+atf_test_case files
+files_head()
+{
+ atf_set "descr" "testing files"
+}
+
+files_body()
+{
+ atf_check \
+ -o inline:"This is a test\n" \
+ -e inline:"soelim: can't open 'nonexistingfile': No such file or directory\n" \
+ -s exit:1 \
+ soelim $(atf_get_srcdir)/nonexisting.in
+
+ cp $(atf_get_srcdir)/basic .
+ atf_check \
+ -o file:$(atf_get_srcdir)/basic.out \
+ -e empty \
+ -s exit:0 \
+ soelim $(atf_get_srcdir)/basic.in
+
+ rm -f basic
+ atf_check \
+ -o file:$(atf_get_srcdir)/basic.out \
+ -e empty \
+ -s exit:0 \
+ soelim -I$(atf_get_srcdir) $(atf_get_srcdir)/basic.in
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case stdin
+ atf_add_test_case files
+}
diff --git a/usr.bin/soeliminate/Makefile b/usr.bin/soeliminate/Makefile
deleted file mode 100644
index 17d4525..0000000
--- a/usr.bin/soeliminate/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# $FreeBSD$
-
-PROG= soeliminate
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/sort/bwstring.c b/usr.bin/sort/bwstring.c
index 3def9d0..fc30b56 100644
--- a/usr.bin/sort/bwstring.c
+++ b/usr.bin/sort/bwstring.c
@@ -65,18 +65,12 @@ initialise_months(void)
for (int i = 0; i < 12; i++) {
cmonths[i] = NULL;
tmp = (unsigned char *) nl_langinfo(item[i]);
- if (tmp == NULL)
- continue;
if (debug_sort)
printf("month[%d]=%s\n", i, tmp);
- len = strlen((char*)tmp);
- if (len < 1)
+ if (*tmp == '\0')
continue;
- while (isblank(*tmp))
- ++tmp;
- m = sort_malloc(len + 1);
- memcpy(m, tmp, len + 1);
- m[len] = '\0';
+ m = sort_strdup(tmp);
+ len = strlen(tmp);
for (unsigned int j = 0; j < len; j++)
m[j] = toupper(m[j]);
cmonths[i] = m;
@@ -91,18 +85,17 @@ initialise_months(void)
for (int i = 0; i < 12; i++) {
wmonths[i] = NULL;
tmp = (unsigned char *) nl_langinfo(item[i]);
- if (tmp == NULL)
- continue;
if (debug_sort)
printf("month[%d]=%s\n", i, tmp);
- len = strlen((char*)tmp);
- if (len < 1)
+ if (*tmp == '\0')
continue;
- while (isblank(*tmp))
- ++tmp;
+ len = strlen(tmp);
m = sort_malloc(SIZEOF_WCHAR_STRING(len + 1));
- if (mbstowcs(m, (char*)tmp, len) == ((size_t) -1))
+ if (mbstowcs(m, (char*)tmp, len) ==
+ ((size_t) - 1)) {
+ sort_free(m);
continue;
+ }
m[len] = L'\0';
for (unsigned int j = 0; j < len; j++)
m[j] = towupper(m[j]);
@@ -234,7 +227,7 @@ bwsdup(const struct bwstring *s)
}
/*
- * Create a new binary string from a raw binary buffer.
+ * Create a new binary string from a wide character buffer.
*/
struct bwstring *
bwssbdup(const wchar_t *str, size_t len)
diff --git a/usr.bin/sort/coll.c b/usr.bin/sort/coll.c
index b3c80f6..0b7eb57 100644
--- a/usr.bin/sort/coll.c
+++ b/usr.bin/sort/coll.c
@@ -78,7 +78,7 @@ keys_array_alloc(void)
}
/*
- * Calculate whether we need key hint space
+ * Calculate whether we need key hint space
*/
static size_t
key_hint_size(void)
@@ -595,12 +595,12 @@ list_coll(struct sort_list_item **ss1, struct sort_list_item **ss2)
return (list_coll_offset(ss1, ss2, 0));
}
-#define LSCDEF(N) \
-static int \
-list_coll_##N(struct sort_list_item **ss1, struct sort_list_item **ss2) \
-{ \
- \
- return (list_coll_offset(ss1, ss2, N)); \
+#define LSCDEF(N) \
+static int \
+list_coll_##N(struct sort_list_item **ss1, struct sort_list_item **ss2) \
+{ \
+ \
+ return (list_coll_offset(ss1, ss2, N)); \
}
LSCDEF(1)
diff --git a/usr.bin/sort/file.c b/usr.bin/sort/file.c
index d989008..0a00889 100644
--- a/usr.bin/sort/file.c
+++ b/usr.bin/sort/file.c
@@ -188,42 +188,6 @@ file_is_tmp(const char* fn)
}
/*
- * Read zero-terminated line from a file
- */
-char *
-read_file0_line(struct file0_reader *f0r)
-{
- size_t pos = 0;
- int c;
-
- if ((f0r->f == NULL) || feof(f0r->f))
- return (NULL);
-
- if (f0r->current_line && f0r->current_sz > 0)
- f0r->current_line[0] = 0;
-
- while (!feof(f0r->f)) {
- c = fgetc(f0r->f);
- if (feof(f0r->f) || (c == -1))
- break;
- if ((pos + 1) >= f0r->current_sz) {
- size_t newsz = (f0r->current_sz + 2) * 2;
- f0r->current_line = sort_realloc(f0r->current_line,
- newsz);
- f0r->current_sz = newsz;
- }
- f0r->current_line[pos] = (char)c;
- if (c == 0)
- break;
- else
- f0r->current_line[pos + 1] = 0;
- ++pos;
- }
-
- return f0r->current_line;
-}
-
-/*
* Generate new temporary file name
*/
char *
@@ -1127,7 +1091,7 @@ file_headers_merge(size_t fnum, struct file_header **fh, FILE *f_out)
memset(&lp, 0, sizeof(lp));
/*
- * construct the initial sort structure
+ * construct the initial sort structure
*/
for (i = 0; i < fnum; i++)
file_header_list_push(fh[i], fh, i);
diff --git a/usr.bin/sort/file.h b/usr.bin/sort/file.h
index 7037d87..e87fafd 100644
--- a/usr.bin/sort/file.h
+++ b/usr.bin/sort/file.h
@@ -55,7 +55,7 @@ struct sort_list
};
/*
- * File reader object
+ * File reader object
*/
struct file_reader;
@@ -70,16 +70,6 @@ struct file_list
bool tmp;
};
-/*
- * Structure for zero-separated file reading (for input files list)
- */
-struct file0_reader
-{
- char *current_line;
- FILE *f;
- size_t current_sz;
-};
-
/* memory */
/**/
@@ -110,8 +100,6 @@ struct file_reader *file_reader_init(const char *fsrc);
struct bwstring *file_reader_readline(struct file_reader *fr);
void file_reader_free(struct file_reader *fr);
-char *read_file0_line(struct file0_reader *f0r);
-
void init_tmp_files(void);
void clear_tmp_files(void);
char *new_tmp_file_name(void);
diff --git a/usr.bin/sort/mem.c b/usr.bin/sort/mem.c
index 93cb019..c6e9a53 100644
--- a/usr.bin/sort/mem.c
+++ b/usr.bin/sort/mem.c
@@ -29,7 +29,6 @@
__FBSDID("$FreeBSD$");
#include <err.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.bin/sort/radixsort.c b/usr.bin/sort/radixsort.c
index f6cf6ac..1fa260b 100644
--- a/usr.bin/sort/radixsort.c
+++ b/usr.bin/sort/radixsort.c
@@ -129,7 +129,7 @@ have_sort_left(void)
* Push sort level to the stack
*/
static inline void
-push_ls(struct sort_level* sl)
+push_ls(struct sort_level *sl)
{
struct level_stack *new_ls;
@@ -308,7 +308,7 @@ run_sort_level_next(struct sort_level *sl)
sl->sublevels = NULL;
}
- switch (sl->tosort_num){
+ switch (sl->tosort_num) {
case 0:
goto end;
case (1):
diff --git a/usr.bin/sort/sort.1.in b/usr.bin/sort/sort.1.in
index cd1caac..7559306 100644
--- a/usr.bin/sort/sort.1.in
+++ b/usr.bin/sort/sort.1.in
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sort.1,v 1.31 2007/08/21 21:22:37 millert Exp $
+.\" $OpenBSD: sort.1,v 1.45 2015/03/19 13:51:10 jmc Exp $
.\" $FreeBSD$
.\"
.\" Copyright (c) 1991, 1993
@@ -33,7 +33,7 @@
.\"
.\" @(#)sort.1 8.1 (Berkeley) 6/6/93
.\"
-.Dd July 3, 2012
+.Dd March 19 2015
.Dt SORT 1
.Os
.Sh NAME
@@ -160,9 +160,10 @@ before comparison, that is, perform case-independent sorting.
Sort by general numerical value.
As opposed to
.Fl n ,
-this option handles general floating points, which have a much
-permissive format than those allowed by
-. Fl n ,
+this option handles general floating points.
+It has a more
+permissive format than that allowed by
+.Fl n
but it has a significant performance drawback.
.It Fl h, Fl Fl human-numeric-sort, Fl Fl sort=human-numeric
Sort by numerical value, but take into account the SI suffix,
@@ -247,9 +248,8 @@ can be attached independently to each
argument of the key specifications.
.Fl b .
.It Xo
-.Sm off
-.Fl k\ \& Ar field1 Op , Ar field2 , Fl Fl key Ns = Ns Ar field1 Op , Ar field2
-.Sm on
+.Fl k Ar field1 Ns Op , Ns Ar field2 ,
+.Fl Fl key Ns = Ns Ar field1 Ns Op , Ns Ar field2
.Xc
Define a restricted sort key that has the starting position
.Ar field1 ,
@@ -334,7 +334,7 @@ standard output.
%%THREADS%%Default number equals to the number of CPUs.
.It Fl Fl files0-from Ns = Ns Ar filename
Take the input file list from the file
-.Ar filename.
+.Ar filename .
The file names must be separated by NUL
(like the output produced by the command "find ... -print0").
.It Fl Fl radixsort
diff --git a/usr.bin/sort/sort.c b/usr.bin/sort/sort.c
index 372c661..43ae43c 100644
--- a/usr.bin/sort/sort.c
+++ b/usr.bin/sort/sort.c
@@ -229,34 +229,38 @@ usage(bool opt_err)
static void
read_fns_from_file0(const char *fn)
{
- if (fn) {
- struct file0_reader f0r;
- FILE *f;
+ FILE *f;
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
- f = fopen(fn, "r");
- if (f == NULL)
- err(2, NULL);
-
- memset(&f0r, 0, sizeof(f0r));
- f0r.f = f;
-
- while (!feof(f)) {
- char *line = read_file0_line(&f0r);
+ if (fn == NULL)
+ return;
- if (line && *line) {
- if (argc_from_file0 == (size_t)-1)
- argc_from_file0 = 0;
- ++argc_from_file0;
- argv_from_file0 = sort_realloc(argv_from_file0,
- argc_from_file0 * sizeof(char *));
- if (argv_from_file0 == NULL)
- err(2, NULL);
- argv_from_file0[argc_from_file0 - 1] =
- sort_strdup(line);
- }
+ f = fopen(fn, "r");
+ if (f == NULL)
+ err(2, "%s", fn);
+
+ while ((linelen = getdelim(&line, &linesize, '\0', f)) != -1) {
+ if (*line != '\0') {
+ if (argc_from_file0 == (size_t) - 1)
+ argc_from_file0 = 0;
+ ++argc_from_file0;
+ argv_from_file0 = sort_realloc(argv_from_file0,
+ argc_from_file0 * sizeof(char *));
+ if (argv_from_file0 == NULL)
+ err(2, NULL);
+ argv_from_file0[argc_from_file0 - 1] = line;
+ } else {
+ free(line);
}
- closefile(f, fn);
+ line = NULL;
+ linesize = 0;
}
+ if (ferror(f))
+ err(2, "%s: getdelim", fn);
+
+ closefile(f, fn);
}
/*
@@ -523,7 +527,7 @@ check_mutually_exclusive_flags(char c, bool *mef_flags)
int fo_index, mec;
bool found_others, found_this;
- found_others = found_this =false;
+ found_others = found_this = false;
fo_index = 0;
for (int i = 0; i < NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS; i++) {
diff --git a/usr.bin/vi/Makefile b/usr.bin/vi/Makefile
index 3595aec..3a0fd47 100644
--- a/usr.bin/vi/Makefile
+++ b/usr.bin/vi/Makefile
@@ -21,7 +21,7 @@ LINKS= ${BINDIR}/${VI} ${BINDIR}/${EX} ${BINDIR}/${VI} ${BINDIR}/${VIEW}
LINKS+= ${BINDIR}/${VI} ${BINDIR}/vi ${BINDIR}/${EX} ${BINDIR}/ex
LINKS+= ${BINDIR}/${VI} ${BINDIR}/view
-MAN= ${SRCDIR}/docs/USD.doc/vi.man/vi.1
+MAN= ${SRCDIR}/docs/man/vi.1
MLINKS+=vi.1 ex.1 vi.1 view.1
MLINKS+=vi.1 nex.1 vi.1 nview.1 vi.1 nvi.1
diff --git a/usr.bin/w/Makefile b/usr.bin/w/Makefile
index cb7a063..0c51463 100644
--- a/usr.bin/w/Makefile
+++ b/usr.bin/w/Makefile
@@ -4,7 +4,7 @@
PROG= w
SRCS= fmt.c pr_time.c proc_compare.c w.c
MAN= w.1 uptime.1
-LIBADD= kvm util xo
+LIBADD= kvm sbuf util xo
#BINGRP= kmem
#BINMODE=2555
LINKS= ${BINDIR}/w ${BINDIR}/uptime
diff --git a/usr.bin/w/w.c b/usr.bin/w/w.c
index f21b976..f94d8a6 100644
--- a/usr.bin/w/w.c
+++ b/usr.bin/w/w.c
@@ -54,8 +54,10 @@ static const char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94";
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/ioctl.h>
+#include <sys/sbuf.h>
#include <sys/socket.h>
#include <sys/tty.h>
+#include <sys/types.h>
#include <machine/cpu.h>
#include <netinet/in.h>
@@ -472,7 +474,9 @@ pr_header(time_t *nowp, int nusers)
struct timespec tp;
int days, hrs, i, mins, secs;
char buf[256];
+ struct sbuf *upbuf;
+ upbuf = sbuf_new_auto();
/*
* Print time of day.
*/
@@ -493,21 +497,27 @@ pr_header(time_t *nowp, int nusers)
mins = uptime / 60;
secs = uptime % 60;
xo_emit(" up");
- xo_attr("seconds", "%lu", (unsigned long) tp.tv_sec);
+ xo_emit("{e:uptime/%lu}", (unsigned long) tp.tv_sec);
+ xo_emit("{e:days/%d}{e:hours/%d}{e:minutes/%d}{e:seconds/%d}", days, hrs, mins, secs);
+
if (days > 0)
- xo_emit(" {:uptime/%d day%s},",
+ sbuf_printf(upbuf, " %d day%s,",
days, days > 1 ? "s" : "");
if (hrs > 0 && mins > 0)
- xo_emit(" {:uptime/%2d:%02d},", hrs, mins);
+ sbuf_printf(upbuf, " %2d:%02d,", hrs, mins);
else if (hrs > 0)
- xo_emit(" {:uptime/%d hr%s},",
+ sbuf_printf(upbuf, " %d hr%s,",
hrs, hrs > 1 ? "s" : "");
else if (mins > 0)
- xo_emit(" {:uptime/%d min%s},",
+ sbuf_printf(upbuf, " %d min%s,",
mins, mins > 1 ? "s" : "");
- else
- xo_emit(" {:uptime/%d sec%s},",
+ else
+ sbuf_printf(upbuf, " %d sec%s,",
secs, secs > 1 ? "s" : "");
+ if (sbuf_finish(upbuf) != 0)
+ xo_err(1, "Could not generate output");
+ xo_emit("{:uptime-human/%s}", sbuf_data(upbuf));
+ sbuf_delete(upbuf);
}
/* Print number of users logged in to system */
diff --git a/usr.bin/wc/wc.c b/usr.bin/wc/wc.c
index 9d51ab2..a6ca137 100644
--- a/usr.bin/wc/wc.c
+++ b/usr.bin/wc/wc.c
@@ -76,6 +76,14 @@ siginfo_handler(int sig __unused)
siginfo = 1;
}
+static void
+reset_siginfo(void)
+{
+
+ signal(SIGINFO, SIG_DFL);
+ siginfo = 0;
+}
+
int
main(int argc, char *argv[])
{
@@ -229,6 +237,7 @@ cnt(const char *file)
} else
tmpll++;
}
+ reset_siginfo();
tlinect += linect;
if (dochar)
tcharct += charct;
@@ -251,6 +260,7 @@ cnt(const char *file)
return (1);
}
if (S_ISREG(sb.st_mode)) {
+ reset_siginfo();
charct = sb.st_size;
show_cnt(file, linect, wordct, charct, llct);
tcharct += charct;
@@ -311,6 +321,7 @@ word: gotsp = 1;
}
}
}
+ reset_siginfo();
if (domulti && MB_CUR_MAX > 1)
if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
xo_warn("%s", file != NULL ? file : "stdin");
diff --git a/usr.bin/whois/whois.c b/usr.bin/whois/whois.c
index 3f6f93a..98b0226 100644
--- a/usr.bin/whois/whois.c
+++ b/usr.bin/whois/whois.c
@@ -1,4 +1,4 @@
-/*
+/*-
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
@@ -55,6 +56,8 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
#define ABUSEHOST "whois.abuse.net"
#define NICHOST "whois.crsnic.net"
@@ -280,21 +283,136 @@ whois(const char *query, const char *hostname, int flags)
FILE *fp;
struct addrinfo *hostres, *res;
char *buf, *host, *nhost, *p;
- int i, s;
+ int i, j, s = -1, count;
size_t c, len;
+ struct pollfd *fds;
+ int timeout = 180;
- s = -1;
hostres = gethostinfo(hostname, 1);
- for (res = hostres; res; res = res->ai_next) {
- s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ for (res = hostres, count = 0; res; res = res->ai_next)
+ count++;
+
+ fds = calloc(count, sizeof(*fds));
+ if (fds == NULL)
+ err(EX_OSERR, "calloc()");
+
+ /*
+ * Traverse the result list elements and make non-block
+ * connection attempts.
+ */
+ count = i = 0;
+ for (res = hostres; res != NULL; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
+ res->ai_protocol);
if (s < 0)
continue;
- if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
- break;
- close(s);
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ if (errno == EINPROGRESS) {
+ /* Add the socket to poll list */
+ fds[i].fd = s;
+ fds[i].events = POLLERR | POLLHUP |
+ POLLIN | POLLOUT;
+ count++;
+ i++;
+ } else {
+ close(s);
+ s = -1;
+
+ /*
+ * Poll only if we have something to poll,
+ * otherwise just go ahead and try next
+ * address
+ */
+ if (count == 0)
+ continue;
+ }
+ } else
+ goto done;
+
+ /*
+ * If we are at the last address, poll until a connection is
+ * established or we failed all connection attempts.
+ */
+ if (res->ai_next == NULL)
+ timeout = INFTIM;
+
+ /*
+ * Poll the watched descriptors for successful connections:
+ * if we still have more untried resolved addresses, poll only
+ * once; otherwise, poll until all descriptors have errors,
+ * which will be considered as ETIMEDOUT later.
+ */
+ do {
+ int n;
+
+ n = poll(fds, i, timeout);
+ if (n == 0) {
+ /*
+ * No event reported in time. Try with a
+ * smaller timeout (but cap at 2-3ms)
+ * after a new host have been added.
+ */
+ if (timeout >= 3)
+ timeout <<= 1;
+
+ break;
+ } else if (n < 0) {
+ /*
+ * errno here can only be EINTR which we would want
+ * to clean up and bail out.
+ */
+ s = -1;
+ goto done;
+ }
+
+ /*
+ * Check for the event(s) we have seen.
+ */
+ for (j = 0; j < i; j++) {
+ if (fds[j].fd == -1 || fds[j].events == 0 ||
+ fds[j].revents == 0)
+ continue;
+ if (fds[j].revents & ~(POLLIN | POLLOUT)) {
+ close(s);
+ fds[j].fd = -1;
+ fds[j].events = 0;
+ count--;
+ continue;
+ } else if (fds[j].revents & (POLLIN | POLLOUT)) {
+ /* Connect succeeded. */
+ s = fds[j].fd;
+
+ goto done;
+ }
+
+ }
+ } while (timeout == INFTIM && count != 0);
}
+
+ /* All attempts were failed */
+ s = -1;
+ if (count == 0)
+ errno = ETIMEDOUT;
+
+done:
+ /* Close all watched fds except the succeeded one */
+ for (j = 0; j < i; j++)
+ if (fds[j].fd != s && fds[j].fd != -1)
+ close(fds[j].fd);
+
+ if (s != -1) {
+ /* Restore default blocking behavior. */
+ if ((flags = fcntl(s, F_GETFL)) != -1) {
+ flags &= ~O_NONBLOCK;
+ if (fcntl(s, F_SETFL, flags) == -1)
+ err(EX_OSERR, "fcntl()");
+ } else
+ err(EX_OSERR, "fcntl()");
+ }
+
+ free(fds);
freeaddrinfo(hostres);
- if (res == NULL)
+ if (s == -1)
err(EX_OSERR, "connect()");
fp = fdopen(s, "r+");
diff --git a/usr.sbin/acpi/acpiconf/acpiconf.c b/usr.sbin/acpi/acpiconf/acpiconf.c
index 5ca2f98..1fab4b6 100644
--- a/usr.sbin/acpi/acpiconf/acpiconf.c
+++ b/usr.sbin/acpi/acpiconf/acpiconf.c
@@ -136,16 +136,30 @@ acpi_battinfo(int num)
if (ioctl(acpifd, ACPIIO_BATT_GET_BATTINFO, &battio) == -1)
err(EX_IOERR, "get battery user info (%d) failed", num);
if (battio.battinfo.state != ACPI_BATT_STAT_NOT_PRESENT) {
- printf("State:\t\t\t");
- if (battio.battinfo.state == 0)
- printf("high ");
- if (battio.battinfo.state & ACPI_BATT_STAT_CRITICAL)
- printf("critical ");
- if (battio.battinfo.state & ACPI_BATT_STAT_DISCHARG)
- printf("discharging ");
- if (battio.battinfo.state & ACPI_BATT_STAT_CHARGING)
- printf("charging ");
- printf("\n");
+ const char *state;
+ switch (battio.battinfo.state & ACPI_BATT_STAT_BST_MASK) {
+ case 0:
+ state = "high";
+ break;
+ case ACPI_BATT_STAT_DISCHARG:
+ state = "discharging";
+ break;
+ case ACPI_BATT_STAT_CHARGING:
+ state = "charging";
+ break;
+ case ACPI_BATT_STAT_CRITICAL:
+ state = "critical";
+ break;
+ case ACPI_BATT_STAT_DISCHARG | ACPI_BATT_STAT_CRITICAL:
+ state = "critical discharging";
+ break;
+ case ACPI_BATT_STAT_CHARGING | ACPI_BATT_STAT_CRITICAL:
+ state = "critical charging";
+ break;
+ default:
+ state = "invalid";
+ }
+ printf("State:\t\t\t%s\n", state);
if (battio.battinfo.cap == -1)
printf("Remaining capacity:\tunknown\n");
else
diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c
index ae7ebf2..52a9e8a 100644
--- a/usr.sbin/acpi/acpidump/acpi.c
+++ b/usr.sbin/acpi/acpidump/acpi.c
@@ -168,12 +168,18 @@ acpi_print_gas(ACPI_GENERIC_ADDRESS *gas)
{
switch(gas->SpaceId) {
case ACPI_GAS_MEMORY:
- printf("0x%08lx:%u[%u] (Memory)", (u_long)gas->Address,
- gas->BitOffset, gas->BitWidth);
+ if (gas->BitWidth <= 32)
+ printf("0x%08x:%u[%u] (Memory)",
+ (u_int)gas->Address, gas->BitOffset,
+ gas->BitWidth);
+ else
+ printf("0x%016jx:%u[%u] (Memory)",
+ (uintmax_t)gas->Address, gas->BitOffset,
+ gas->BitWidth);
break;
case ACPI_GAS_IO:
- printf("0x%02lx:%u[%u] (IO)", (u_long)gas->Address,
- gas->BitOffset, gas->BitWidth);
+ printf("0x%02x:%u[%u] (IO)", (u_int)gas->Address,
+ gas->BitOffset, gas->BitWidth);
break;
case ACPI_GAS_PCI:
printf("%x:%x+0x%x (PCI)", (uint16_t)(gas->Address >> 32),
@@ -194,7 +200,7 @@ acpi_print_gas(ACPI_GENERIC_ADDRESS *gas)
case ACPI_GAS_DATATABLE:
case ACPI_GAS_FIXED:
default:
- printf("0x%08lx (?)", (u_long)gas->Address);
+ printf("0x%016jx (?)", (uintmax_t)gas->Address);
break;
}
}
@@ -831,7 +837,7 @@ acpi_handle_dmar_drhd(ACPI_DMAR_HARDWARE_UNIT *drhd)
#undef PRINTFLAG
printf("\tSegment=%d\n", drhd->Segment);
- printf("\tAddress=0x%0jx\n", (uintmax_t)drhd->Address);
+ printf("\tAddress=0x%016jx\n", (uintmax_t)drhd->Address);
remaining = drhd->Header.Length - sizeof(ACPI_DMAR_HARDWARE_UNIT);
if (remaining > 0)
@@ -856,8 +862,8 @@ acpi_handle_dmar_rmrr(ACPI_DMAR_RESERVED_MEMORY *rmrr)
printf("\tType=RMRR\n");
printf("\tLength=%d\n", rmrr->Header.Length);
printf("\tSegment=%d\n", rmrr->Segment);
- printf("\tBaseAddress=0x%0jx\n", (uintmax_t)rmrr->BaseAddress);
- printf("\tLimitAddress=0x%0jx\n", (uintmax_t)rmrr->EndAddress);
+ printf("\tBaseAddress=0x%016jx\n", (uintmax_t)rmrr->BaseAddress);
+ printf("\tLimitAddress=0x%016jx\n", (uintmax_t)rmrr->EndAddress);
remaining = rmrr->Header.Length - sizeof(ACPI_DMAR_RESERVED_MEMORY);
if (remaining > 0)
@@ -912,7 +918,7 @@ acpi_handle_dmar_rhsa(ACPI_DMAR_RHSA *rhsa)
printf("\n");
printf("\tType=RHSA\n");
printf("\tLength=%d\n", rhsa->Header.Length);
- printf("\tBaseAddress=0x%0jx\n", (uintmax_t)rhsa->BaseAddress);
+ printf("\tBaseAddress=0x%016jx\n", (uintmax_t)rhsa->BaseAddress);
printf("\tProximityDomain=0x%08x\n", rhsa->ProximityDomain);
}
@@ -1074,7 +1080,6 @@ acpi_print_rsdt(ACPI_TABLE_HEADER *rsdp)
ACPI_TABLE_RSDT *rsdt;
ACPI_TABLE_XSDT *xsdt;
int i, entries;
- u_long addr;
rsdt = (ACPI_TABLE_RSDT *)rsdp;
xsdt = (ACPI_TABLE_XSDT *)rsdp;
@@ -1085,18 +1090,11 @@ acpi_print_rsdt(ACPI_TABLE_HEADER *rsdp)
for (i = 0; i < entries; i++) {
if (i > 0)
printf(", ");
- switch (addr_size) {
- case 4:
- addr = le32toh(rsdt->TableOffsetEntry[i]);
- break;
- case 8:
- addr = le64toh(xsdt->TableOffsetEntry[i]);
- break;
- default:
- addr = 0;
- }
- assert(addr != 0);
- printf("0x%08lx", addr);
+ if (addr_size == 4)
+ printf("0x%08x", le32toh(rsdt->TableOffsetEntry[i]));
+ else
+ printf("0x%016jx",
+ (uintmax_t)le64toh(xsdt->TableOffsetEntry[i]));
}
printf(" }\n");
printf(END_COMMENT);
@@ -1212,8 +1210,8 @@ acpi_print_fadt(ACPI_TABLE_HEADER *sdp)
printf(", RESET_VALUE=%#x\n", fadt->ResetValue);
}
if (acpi_get_fadt_revision(fadt) > 1) {
- printf("\tX_FACS=0x%08lx, ", (u_long)fadt->XFacs);
- printf("X_DSDT=0x%08lx\n", (u_long)fadt->XDsdt);
+ printf("\tX_FACS=0x%016jx, ", (uintmax_t)fadt->XFacs);
+ printf("X_DSDT=0x%016jx\n", (uintmax_t)fadt->XDsdt);
printf("\tX_PM1a_EVT_BLK=");
acpi_print_gas(&fadt->XPm1aEventBlock);
if (fadt->XPm1bEventBlock.Address != 0) {
@@ -1268,10 +1266,9 @@ acpi_print_facs(ACPI_TABLE_FACS *facs)
printf("S4BIOS");
printf("\n");
- if (facs->XFirmwareWakingVector != 0) {
- printf("\tX_Firm_Wake_Vec=%08lx\n",
- (u_long)facs->XFirmwareWakingVector);
- }
+ if (facs->XFirmwareWakingVector != 0)
+ printf("\tX_Firm_Wake_Vec=%016jx\n",
+ (uintmax_t)facs->XFirmwareWakingVector);
printf("\tVersion=%u\n", facs->Version);
printf(END_COMMENT);
@@ -1321,8 +1318,8 @@ acpi_print_rsd_ptr(ACPI_TABLE_RSDP *rp)
printf("\tRSDT=0x%08x, cksum=%u\n", rp->RsdtPhysicalAddress,
rp->Checksum);
} else {
- printf("\tXSDT=0x%08lx, length=%u, cksum=%u\n",
- (u_long)rp->XsdtPhysicalAddress, rp->Length,
+ printf("\tXSDT=0x%016jx, length=%u, cksum=%u\n",
+ (uintmax_t)rp->XsdtPhysicalAddress, rp->Length,
rp->ExtendedChecksum);
}
printf(END_COMMENT);
@@ -1342,17 +1339,12 @@ acpi_handle_rsdt(ACPI_TABLE_HEADER *rsdp)
xsdt = (ACPI_TABLE_XSDT *)rsdp;
entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size;
for (i = 0; i < entries; i++) {
- switch (addr_size) {
- case 4:
+ if (addr_size == 4)
addr = le32toh(rsdt->TableOffsetEntry[i]);
- break;
- case 8:
+ else
addr = le64toh(xsdt->TableOffsetEntry[i]);
- break;
- default:
- assert((addr = 0));
- }
-
+ if (addr == 0)
+ continue;
sdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr);
if (acpi_checksum(sdp, sdp->Length)) {
warnx("RSDT entry %d (sig %.4s) is corrupt", i,
@@ -1547,16 +1539,12 @@ sdt_from_rsdt(ACPI_TABLE_HEADER *rsdp, const char *sig, ACPI_TABLE_HEADER *last)
xsdt = (ACPI_TABLE_XSDT *)rsdp;
entries = (rsdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size;
for (i = 0; i < entries; i++) {
- switch (addr_size) {
- case 4:
+ if (addr_size == 4)
addr = le32toh(rsdt->TableOffsetEntry[i]);
- break;
- case 8:
+ else
addr = le64toh(xsdt->TableOffsetEntry[i]);
- break;
- default:
- assert((addr = 0));
- }
+ if (addr == 0)
+ continue;
sdt = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr);
if (last != NULL) {
if (sdt == last)
diff --git a/usr.sbin/amd/include/config.h b/usr.sbin/amd/include/config.h
index 5817a46..cffb82a 100644
--- a/usr.sbin/amd/include/config.h
+++ b/usr.sbin/amd/include/config.h
@@ -668,9 +668,6 @@
/* Define to 1 if you have the <net/if.h> header file. */
#define HAVE_NET_IF_H 1
-/* Define to 1 if you have the <net/if_var.h> header file. */
-#define HAVE_NET_IF_VAR_H 1
-
/* Define to 1 if you have the <net/route.h> header file. */
#define HAVE_NET_ROUTE_H 1
diff --git a/usr.sbin/ancontrol/ancontrol.c b/usr.sbin/ancontrol/ancontrol.c
index 839cdcb..4ff32ff 100644
--- a/usr.sbin/ancontrol/ancontrol.c
+++ b/usr.sbin/ancontrol/ancontrol.c
@@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
#include <arpa/inet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/ethernet.h>
#include <dev/an/if_aironet_ieee.h>
diff --git a/usr.sbin/authpf/Makefile b/usr.sbin/authpf/Makefile
index 07b2cdc..be95a4b 100644
--- a/usr.sbin/authpf/Makefile
+++ b/usr.sbin/authpf/Makefile
@@ -13,7 +13,7 @@ SRCS= authpf.c
# XXX ALTQ:
CFLAGS+= -DENABLE_ALTQ
-LIBADD= m md util
+LIBADD= m util
WARNS?= 3
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
index 0273b0f..70b7041 100644
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -44,7 +44,7 @@ SRCS= \
.PATH: ${.CURDIR}/../../sys/amd64/vmm
SRCS+= vmm_instruction_emul.c
-LIBADD= vmmapi md util pthread
+LIBADD= vmmapi md pthread
WARNS?= 2
diff --git a/usr.sbin/bhyve/acpi.c b/usr.sbin/bhyve/acpi.c
index a5a6559..a9dd1cc 100644
--- a/usr.sbin/bhyve/acpi.c
+++ b/usr.sbin/bhyve/acpi.c
@@ -386,7 +386,7 @@ basl_fwrite_fadt(FILE *fp)
EFPRINTF(fp, "[0001]\t\tDuty Cycle Width : 00\n");
EFPRINTF(fp, "[0001]\t\tRTC Day Alarm Index : 00\n");
EFPRINTF(fp, "[0001]\t\tRTC Month Alarm Index : 00\n");
- EFPRINTF(fp, "[0001]\t\tRTC Century Index : 00\n");
+ EFPRINTF(fp, "[0001]\t\tRTC Century Index : 32\n");
EFPRINTF(fp, "[0002]\t\tBoot Flags (decoded below) : 0000\n");
EFPRINTF(fp, "\t\t\tLegacy Devices Supported (V2) : 0\n");
EFPRINTF(fp, "\t\t\t8042 Present on ports 60/64 (V2) : 0\n");
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 271f67c..47a7699 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -325,8 +325,10 @@ vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
error = emulate_inout(ctx, vcpu, vme, strictio);
if (error) {
- fprintf(stderr, "Unhandled %s%c 0x%04x\n", in ? "in" : "out",
- bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port);
+ fprintf(stderr, "Unhandled %s%c 0x%04x at 0x%lx\n",
+ in ? "in" : "out",
+ bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'),
+ port, vmexit->rip);
return (VMEXIT_ABORT);
} else {
return (VMEXIT_CONTINUE);
@@ -803,6 +805,11 @@ main(int argc, char *argv[])
exit(1);
}
+ if (guest_ncpus < 1) {
+ fprintf(stderr, "Invalid guest vCPUs (%d)\n", guest_ncpus);
+ exit(1);
+ }
+
max_vcpus = num_vcpus_allowed(ctx);
if (guest_ncpus > max_vcpus) {
fprintf(stderr, "%d vCPUs requested but only %d available\n",
diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c
index b8b27a6..bcb1617 100644
--- a/usr.sbin/bhyve/block_if.c
+++ b/usr.sbin/bhyve/block_if.c
@@ -85,6 +85,7 @@ struct blockif_ctxt {
int bc_magic;
int bc_fd;
int bc_ischr;
+ int bc_isgeom;
int bc_candelete;
int bc_rdonly;
off_t bc_size;
@@ -198,27 +199,93 @@ blockif_complete(struct blockif_ctxt *bc, struct blockif_elem *be)
}
static void
-blockif_proc(struct blockif_ctxt *bc, struct blockif_elem *be)
+blockif_proc(struct blockif_ctxt *bc, struct blockif_elem *be, uint8_t *buf)
{
struct blockif_req *br;
off_t arg[2];
- int err;
+ ssize_t clen, len, off, boff, voff;
+ int i, err;
br = be->be_req;
+ if (br->br_iovcnt <= 1)
+ buf = NULL;
err = 0;
-
switch (be->be_op) {
case BOP_READ:
- if (preadv(bc->bc_fd, br->br_iov, br->br_iovcnt,
- br->br_offset) < 0)
- err = errno;
+ if (buf == NULL) {
+ if ((len = preadv(bc->bc_fd, br->br_iov, br->br_iovcnt,
+ br->br_offset)) < 0)
+ err = errno;
+ else
+ br->br_resid -= len;
+ break;
+ }
+ i = 0;
+ off = voff = 0;
+ while (br->br_resid > 0) {
+ len = MIN(br->br_resid, MAXPHYS);
+ if (pread(bc->bc_fd, buf, len, br->br_offset +
+ off) < 0) {
+ err = errno;
+ break;
+ }
+ boff = 0;
+ do {
+ clen = MIN(len - boff, br->br_iov[i].iov_len -
+ voff);
+ memcpy(br->br_iov[i].iov_base + voff,
+ buf + boff, clen);
+ if (clen < br->br_iov[i].iov_len - voff)
+ voff += clen;
+ else {
+ i++;
+ voff = 0;
+ }
+ boff += clen;
+ } while (boff < len);
+ off += len;
+ br->br_resid -= len;
+ }
break;
case BOP_WRITE:
- if (bc->bc_rdonly)
+ if (bc->bc_rdonly) {
err = EROFS;
- else if (pwritev(bc->bc_fd, br->br_iov, br->br_iovcnt,
- br->br_offset) < 0)
- err = errno;
+ break;
+ }
+ if (buf == NULL) {
+ if ((len = pwritev(bc->bc_fd, br->br_iov, br->br_iovcnt,
+ br->br_offset)) < 0)
+ err = errno;
+ else
+ br->br_resid -= len;
+ break;
+ }
+ i = 0;
+ off = voff = 0;
+ while (br->br_resid > 0) {
+ len = MIN(br->br_resid, MAXPHYS);
+ boff = 0;
+ do {
+ clen = MIN(len - boff, br->br_iov[i].iov_len -
+ voff);
+ memcpy(buf + boff,
+ br->br_iov[i].iov_base + voff, clen);
+ if (clen < br->br_iov[i].iov_len - voff)
+ voff += clen;
+ else {
+ i++;
+ voff = 0;
+ }
+ boff += clen;
+ } while (boff < len);
+ if (pwrite(bc->bc_fd, buf, len, br->br_offset +
+ off) < 0) {
+ err = errno;
+ break;
+ }
+ off += len;
+ br->br_resid -= len;
+ }
break;
case BOP_FLUSH:
if (bc->bc_ischr) {
@@ -234,9 +301,11 @@ blockif_proc(struct blockif_ctxt *bc, struct blockif_elem *be)
err = EROFS;
else if (bc->bc_ischr) {
arg[0] = br->br_offset;
- arg[1] = br->br_iov[0].iov_len;
+ arg[1] = br->br_resid;
if (ioctl(bc->bc_fd, DIOCGDELETE, arg))
err = errno;
+ else
+ br->br_resid = 0;
} else
err = EOPNOTSUPP;
break;
@@ -256,15 +325,20 @@ blockif_thr(void *arg)
struct blockif_ctxt *bc;
struct blockif_elem *be;
pthread_t t;
+ uint8_t *buf;
bc = arg;
+ if (bc->bc_isgeom)
+ buf = malloc(MAXPHYS);
+ else
+ buf = NULL;
t = pthread_self();
pthread_mutex_lock(&bc->bc_mtx);
for (;;) {
while (blockif_dequeue(bc, t, &be)) {
pthread_mutex_unlock(&bc->bc_mtx);
- blockif_proc(bc, be);
+ blockif_proc(bc, be, buf);
pthread_mutex_lock(&bc->bc_mtx);
blockif_complete(bc, be);
}
@@ -275,6 +349,8 @@ blockif_thr(void *arg)
}
pthread_mutex_unlock(&bc->bc_mtx);
+ if (buf)
+ free(buf);
pthread_exit(NULL);
return (NULL);
}
@@ -315,13 +391,14 @@ struct blockif_ctxt *
blockif_open(const char *optstr, const char *ident)
{
char tname[MAXCOMLEN + 1];
+ char name[MAXPATHLEN];
char *nopt, *xopts;
struct blockif_ctxt *bc;
struct stat sbuf;
struct diocgattr_arg arg;
off_t size, psectsz, psectoff;
int extra, fd, i, sectsz;
- int nocache, sync, ro, candelete;
+ int nocache, sync, ro, candelete, geom;
pthread_once(&blockif_once, blockif_init);
@@ -375,7 +452,7 @@ blockif_open(const char *optstr, const char *ident)
size = sbuf.st_size;
sectsz = DEV_BSIZE;
psectsz = psectoff = 0;
- candelete = 0;
+ candelete = geom = 0;
if (S_ISCHR(sbuf.st_mode)) {
if (ioctl(fd, DIOCGMEDIASIZE, &size) < 0 ||
ioctl(fd, DIOCGSECTORSIZE, &sectsz)) {
@@ -391,6 +468,8 @@ blockif_open(const char *optstr, const char *ident)
arg.len = sizeof(arg.value.i);
if (ioctl(fd, DIOCGATTR, &arg) == 0)
candelete = arg.value.i;
+ if (ioctl(fd, DIOCGPROVIDERNAME, name) == 0)
+ geom = 1;
} else
psectsz = sbuf.st_blksize;
@@ -403,6 +482,7 @@ blockif_open(const char *optstr, const char *ident)
bc->bc_magic = BLOCKIF_SIG;
bc->bc_fd = fd;
bc->bc_ischr = S_ISCHR(sbuf.st_mode);
+ bc->bc_isgeom = geom;
bc->bc_candelete = candelete;
bc->bc_rdonly = ro;
bc->bc_size = size;
diff --git a/usr.sbin/bhyve/block_if.h b/usr.sbin/bhyve/block_if.h
index 1cb7c80..8e63407 100644
--- a/usr.sbin/bhyve/block_if.h
+++ b/usr.sbin/bhyve/block_if.h
@@ -45,6 +45,7 @@ struct blockif_req {
struct iovec br_iov[BLOCKIF_IOV_MAX];
int br_iovcnt;
off_t br_offset;
+ ssize_t br_resid;
void (*br_callback)(struct blockif_req *req, int err);
void *br_param;
};
diff --git a/usr.sbin/bhyve/ioapic.c b/usr.sbin/bhyve/ioapic.c
index 2950d9a..0ad69d9 100644
--- a/usr.sbin/bhyve/ioapic.c
+++ b/usr.sbin/bhyve/ioapic.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Advanced Computing Technologies LLC
+ * Copyright (c) 2014 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.sbin/bhyve/ioapic.h b/usr.sbin/bhyve/ioapic.h
index 3cfca4f..efdd3c6 100644
--- a/usr.sbin/bhyve/ioapic.h
+++ b/usr.sbin/bhyve/ioapic.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Advanced Computing Technologies LLC
+ * Copyright (c) 2014 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index e8cb2da..2d05789 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -124,7 +124,7 @@ struct ahci_ioreq {
uint32_t len;
uint32_t done;
int slot;
- int prdtl;
+ int more;
};
struct ahci_port {
@@ -269,22 +269,24 @@ ahci_write_fis(struct ahci_port *p, enum sata_fis_type ft, uint8_t *fis)
case FIS_TYPE_REGD2H:
offset = 0x40;
len = 20;
- irq = AHCI_P_IX_DHR;
+ irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_DHR : 0;
break;
case FIS_TYPE_SETDEVBITS:
offset = 0x58;
len = 8;
- irq = AHCI_P_IX_SDB;
+ irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_SDB : 0;
break;
case FIS_TYPE_PIOSETUP:
offset = 0x20;
len = 20;
- irq = 0;
+ irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_PS : 0;
break;
default:
WPRINTF("unsupported fis type %d\n", ft);
return;
}
+ if (fis[2] & ATA_S_ERROR)
+ irq |= AHCI_P_IX_TFE;
memcpy(p->rfis + offset, fis, len);
if (irq) {
p->is |= irq;
@@ -309,22 +311,23 @@ ahci_write_fis_sdb(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
uint8_t error;
error = (tfd >> 8) & 0xff;
+ tfd &= 0x77;
memset(fis, 0, sizeof(fis));
fis[0] = FIS_TYPE_SETDEVBITS;
fis[1] = (1 << 6);
- fis[2] = tfd & 0x77;
+ fis[2] = tfd;
fis[3] = error;
if (fis[2] & ATA_S_ERROR) {
- p->is |= AHCI_P_IX_TFE;
p->err_cfis[0] = slot;
- p->err_cfis[2] = tfd & 0x77;
+ p->err_cfis[2] = tfd;
p->err_cfis[3] = error;
memcpy(&p->err_cfis[4], cfis + 4, 16);
} else {
*(uint32_t *)(fis + 4) = (1 << slot);
p->sact &= ~(1 << slot);
}
- p->tfd = tfd;
+ p->tfd &= ~0x77;
+ p->tfd |= tfd;
ahci_write_fis(p, FIS_TYPE_SETDEVBITS, fis);
}
@@ -351,7 +354,6 @@ ahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
fis[12] = cfis[12];
fis[13] = cfis[13];
if (fis[2] & ATA_S_ERROR) {
- p->is |= AHCI_P_IX_TFE;
p->err_cfis[0] = 0x80;
p->err_cfis[2] = tfd & 0xff;
p->err_cfis[3] = error;
@@ -363,6 +365,21 @@ ahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
}
static void
+ahci_write_fis_d2h_ncq(struct ahci_port *p, int slot)
+{
+ uint8_t fis[20];
+
+ p->tfd = ATA_S_READY | ATA_S_DSC;
+ memset(fis, 0, sizeof(fis));
+ fis[0] = FIS_TYPE_REGD2H;
+ fis[1] = 0; /* No interrupt */
+ fis[2] = p->tfd; /* Status */
+ fis[3] = 0; /* No error */
+ p->ci &= ~(1 << slot);
+ ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
+}
+
+static void
ahci_write_reset_fis_d2h(struct ahci_port *p)
{
uint8_t fis[20];
@@ -418,7 +435,8 @@ ahci_port_stop(struct ahci_port *p)
slot = aior->slot;
cfis = aior->cfis;
if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
- cfis[2] == ATA_READ_FPDMA_QUEUED)
+ cfis[2] == ATA_READ_FPDMA_QUEUED ||
+ cfis[2] == ATA_SEND_FPDMA_QUEUED)
ncq = 1;
if (ncq)
@@ -489,6 +507,9 @@ ahci_reset(struct pci_ahci_softc *sc)
for (i = 0; i < sc->ports; i++) {
sc->port[i].ie = 0;
sc->port[i].is = 0;
+ sc->port[i].cmd = (AHCI_P_CMD_SUD | AHCI_P_CMD_POD);
+ if (sc->port[i].bctx)
+ sc->port[i].cmd |= AHCI_P_CMD_CPS;
sc->port[i].sctl = 0;
ahci_port_reset(&sc->port[i]);
}
@@ -520,26 +541,79 @@ atapi_string(uint8_t *dest, const char *src, int len)
}
}
+/*
+ * Build up the iovec based on the PRDT, 'done' and 'len'.
+ */
+static void
+ahci_build_iov(struct ahci_port *p, struct ahci_ioreq *aior,
+ struct ahci_prdt_entry *prdt, uint16_t prdtl)
+{
+ struct blockif_req *breq = &aior->io_req;
+ int i, j, skip, todo, left, extra;
+ uint32_t dbcsz;
+
+ /* Copy part of PRDT between 'done' and 'len' bytes into the iov. */
+ skip = aior->done;
+ left = aior->len - aior->done;
+ todo = 0;
+ for (i = 0, j = 0; i < prdtl && j < BLOCKIF_IOV_MAX && left > 0;
+ i++, prdt++) {
+ dbcsz = (prdt->dbc & DBCMASK) + 1;
+ /* Skip already done part of the PRDT */
+ if (dbcsz <= skip) {
+ skip -= dbcsz;
+ continue;
+ }
+ dbcsz -= skip;
+ if (dbcsz > left)
+ dbcsz = left;
+ breq->br_iov[j].iov_base = paddr_guest2host(ahci_ctx(p->pr_sc),
+ prdt->dba + skip, dbcsz);
+ breq->br_iov[j].iov_len = dbcsz;
+ todo += dbcsz;
+ left -= dbcsz;
+ skip = 0;
+ j++;
+ }
+
+ /* If we got limited by IOV length, round I/O down to sector size. */
+ if (j == BLOCKIF_IOV_MAX) {
+ extra = todo % blockif_sectsz(p->bctx);
+ todo -= extra;
+ assert(todo > 0);
+ while (extra > 0) {
+ if (breq->br_iov[j - 1].iov_len > extra) {
+ breq->br_iov[j - 1].iov_len -= extra;
+ break;
+ }
+ extra -= breq->br_iov[j - 1].iov_len;
+ j--;
+ }
+ }
+
+ breq->br_iovcnt = j;
+ breq->br_resid = todo;
+ aior->done += todo;
+ aior->more = (aior->done < aior->len && i < prdtl);
+}
+
static void
-ahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
- int seek)
+ahci_handle_rw(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)
{
struct ahci_ioreq *aior;
struct blockif_req *breq;
- struct pci_ahci_softc *sc;
struct ahci_prdt_entry *prdt;
struct ahci_cmd_hdr *hdr;
uint64_t lba;
uint32_t len;
- int i, err, iovcnt, ncq, readop;
+ int err, first, ncq, readop;
- sc = p->pr_sc;
prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
ncq = 0;
readop = 1;
+ first = (done == 0);
- prdt += seek;
if (cfis[2] == ATA_WRITE || cfis[2] == ATA_WRITE48 ||
cfis[2] == ATA_WRITE_MUL || cfis[2] == ATA_WRITE_MUL48 ||
cfis[2] == ATA_WRITE_DMA || cfis[2] == ATA_WRITE_DMA48 ||
@@ -580,57 +654,33 @@ ahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
lba *= blockif_sectsz(p->bctx);
len *= blockif_sectsz(p->bctx);
- /*
- * Pull request off free list
- */
+ /* Pull request off free list */
aior = STAILQ_FIRST(&p->iofhd);
assert(aior != NULL);
STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
+
aior->cfis = cfis;
aior->slot = slot;
aior->len = len;
aior->done = done;
breq = &aior->io_req;
breq->br_offset = lba + done;
- iovcnt = hdr->prdtl - seek;
- if (iovcnt > BLOCKIF_IOV_MAX) {
- aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
- iovcnt = BLOCKIF_IOV_MAX;
- } else
- aior->prdtl = 0;
- breq->br_iovcnt = iovcnt;
+ ahci_build_iov(p, aior, prdt, hdr->prdtl);
- /*
- * Mark this command in-flight.
- */
+ /* Mark this command in-flight. */
p->pending |= 1 << slot;
- /*
- * Stuff request onto busy list
- */
+ /* Stuff request onto busy list. */
TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
- /*
- * Build up the iovec based on the prdt
- */
- for (i = 0; i < iovcnt; i++) {
- uint32_t dbcsz;
+ if (ncq && first)
+ ahci_write_fis_d2h_ncq(p, slot);
- dbcsz = (prdt->dbc & DBCMASK) + 1;
- breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
- prdt->dba, dbcsz);
- breq->br_iov[i].iov_len = dbcsz;
- aior->done += dbcsz;
- prdt++;
- }
if (readop)
err = blockif_read(p->bctx, breq);
else
err = blockif_write(p->bctx, breq);
assert(err == 0);
-
- if (ncq)
- p->ci &= ~(1 << slot);
}
static void
@@ -650,7 +700,7 @@ ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
aior->slot = slot;
aior->len = 0;
aior->done = 0;
- aior->prdtl = 0;
+ aior->more = 0;
breq = &aior->io_req;
/*
@@ -703,15 +753,18 @@ ahci_handle_dsm_trim(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done
uint8_t *entry;
uint64_t elba;
uint32_t len, elen;
- int err;
+ int err, first, ncq;
uint8_t buf[512];
+ first = (done == 0);
if (cfis[2] == ATA_DATA_SET_MANAGEMENT) {
len = (uint16_t)cfis[13] << 8 | cfis[12];
len *= 512;
+ ncq = 0;
} else { /* ATA_SEND_FPDMA_QUEUED */
len = (uint16_t)cfis[11] << 8 | cfis[3];
len *= 512;
+ ncq = 1;
}
read_prdt(p, slot, cfis, buf, sizeof(buf));
@@ -745,12 +798,11 @@ next:
aior->slot = slot;
aior->len = len;
aior->done = done;
- aior->prdtl = 0;
+ aior->more = (len != done);
breq = &aior->io_req;
breq->br_offset = elba * blockif_sectsz(p->bctx);
- breq->br_iovcnt = 1;
- breq->br_iov[0].iov_len = elen * blockif_sectsz(p->bctx);
+ breq->br_resid = elen * blockif_sectsz(p->bctx);
/*
* Mark this command in-flight.
@@ -762,6 +814,9 @@ next:
*/
TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+ if (ncq && first)
+ ahci_write_fis_d2h_ncq(p, slot);
+
err = blockif_delete(p->bctx, breq);
assert(err == 0);
}
@@ -903,7 +958,6 @@ handle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
buf[88] = 0x7f;
if (p->xfermode & ATA_UDMA0)
buf[88] |= (1 << ((p->xfermode & 7) + 8));
- buf[93] = (1 | 1 <<14);
buf[100] = sectors;
buf[101] = (sectors >> 16);
buf[102] = (sectors >> 32);
@@ -1242,8 +1296,7 @@ atapi_report_luns(struct ahci_port *p, int slot, uint8_t *cfis)
}
static void
-atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
- uint32_t done, int seek)
+atapi_read(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)
{
struct ahci_ioreq *aior;
struct ahci_cmd_hdr *hdr;
@@ -1253,14 +1306,13 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
uint8_t *acmd;
uint64_t lba;
uint32_t len;
- int i, err, iovcnt;
+ int err;
sc = p->pr_sc;
acmd = cfis + 0x40;
hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
prdt = (struct ahci_prdt_entry *)(cfis + 0x80);
- prdt += seek;
lba = be32dec(acmd + 2);
if (acmd[0] == READ_10)
len = be16dec(acmd + 7);
@@ -1285,37 +1337,14 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
aior->done = done;
breq = &aior->io_req;
breq->br_offset = lba + done;
- iovcnt = hdr->prdtl - seek;
- if (iovcnt > BLOCKIF_IOV_MAX) {
- aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
- iovcnt = BLOCKIF_IOV_MAX;
- } else
- aior->prdtl = 0;
- breq->br_iovcnt = iovcnt;
+ ahci_build_iov(p, aior, prdt, hdr->prdtl);
- /*
- * Mark this command in-flight.
- */
+ /* Mark this command in-flight. */
p->pending |= 1 << slot;
- /*
- * Stuff request onto busy list
- */
+ /* Stuff request onto busy list. */
TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
- /*
- * Build up the iovec based on the prdt
- */
- for (i = 0; i < iovcnt; i++) {
- uint32_t dbcsz;
-
- dbcsz = (prdt->dbc & DBCMASK) + 1;
- breq->br_iov[i].iov_base = paddr_guest2host(ahci_ctx(sc),
- prdt->dba, dbcsz);
- breq->br_iov[i].iov_len = dbcsz;
- aior->done += dbcsz;
- prdt++;
- }
err = blockif_read(p->bctx, breq);
assert(err == 0);
}
@@ -1515,7 +1544,7 @@ handle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
break;
case READ_10:
case READ_12:
- atapi_read(p, slot, cfis, 0, 0);
+ atapi_read(p, slot, cfis, 0);
break;
case REQUEST_SENSE:
atapi_request_sense(p, slot, cfis);
@@ -1543,6 +1572,7 @@ static void
ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
{
+ p->tfd |= ATA_S_BUSY;
switch (cfis[2]) {
case ATA_ATA_IDENTIFY:
handle_identify(p, slot, cfis);
@@ -1614,7 +1644,7 @@ ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
case ATA_WRITE_DMA48:
case ATA_READ_FPDMA_QUEUED:
case ATA_WRITE_FPDMA_QUEUED:
- ahci_handle_dma(p, slot, cfis, 0, 0);
+ ahci_handle_rw(p, slot, cfis, 0);
break;
case ATA_FLUSHCACHE:
case ATA_FLUSHCACHE48:
@@ -1755,7 +1785,7 @@ ata_ioreq_cb(struct blockif_req *br, int err)
struct pci_ahci_softc *sc;
uint32_t tfd;
uint8_t *cfis;
- int pending, slot, ncq, dsm;
+ int slot, ncq, dsm;
DPRINTF("%s %d\n", __func__, err);
@@ -1764,7 +1794,6 @@ ata_ioreq_cb(struct blockif_req *br, int err)
p = aior->io_pr;
cfis = aior->cfis;
slot = aior->slot;
- pending = aior->prdtl;
sc = p->pr_sc;
hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + slot * AHCI_CL_SIZE);
@@ -1792,25 +1821,18 @@ ata_ioreq_cb(struct blockif_req *br, int err)
if (!err)
hdr->prdbc = aior->done;
- if (dsm) {
- if (aior->done != aior->len && !err) {
+ if (!err && aior->more) {
+ if (dsm)
ahci_handle_dsm_trim(p, slot, cfis, aior->done);
- goto out;
- }
- } else {
- if (pending && !err) {
- ahci_handle_dma(p, slot, cfis, aior->done,
- hdr->prdtl - pending);
- goto out;
- }
+ else
+ ahci_handle_rw(p, slot, cfis, aior->done);
+ goto out;
}
- if (!err && aior->done == aior->len) {
+ if (!err)
tfd = ATA_S_READY | ATA_S_DSC;
- } else {
+ else
tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
- }
-
if (ncq)
ahci_write_fis_sdb(p, slot, cfis, tfd);
else
@@ -1836,7 +1858,7 @@ atapi_ioreq_cb(struct blockif_req *br, int err)
struct pci_ahci_softc *sc;
uint8_t *cfis;
uint32_t tfd;
- int pending, slot;
+ int slot;
DPRINTF("%s %d\n", __func__, err);
@@ -1844,7 +1866,6 @@ atapi_ioreq_cb(struct blockif_req *br, int err)
p = aior->io_pr;
cfis = aior->cfis;
slot = aior->slot;
- pending = aior->prdtl;
sc = p->pr_sc;
hdr = (struct ahci_cmd_hdr *)(p->cmd_lst + aior->slot * AHCI_CL_SIZE);
@@ -1863,19 +1884,18 @@ atapi_ioreq_cb(struct blockif_req *br, int err)
if (!err)
hdr->prdbc = aior->done;
- if (pending && !err) {
- atapi_read(p, slot, cfis, aior->done, hdr->prdtl - pending);
+ if (!err && aior->more) {
+ atapi_read(p, slot, cfis, aior->done);
goto out;
}
- if (!err && aior->done == aior->len) {
+ if (!err) {
tfd = ATA_S_READY | ATA_S_DSC;
} else {
p->sense_key = ATA_SENSE_ILLEGAL_REQUEST;
p->asc = 0x21;
tfd = (p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR;
}
-
cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
ahci_write_fis_d2h(p, slot, cfis, tfd);
@@ -1949,8 +1969,15 @@ pci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
break;
case AHCI_P_CMD:
{
- p->cmd = value;
-
+ p->cmd &= ~(AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD |
+ AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE |
+ AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE |
+ AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK);
+ p->cmd |= (AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD |
+ AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE |
+ AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE |
+ AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK) & value;
+
if (!(value & AHCI_P_CMD_ST)) {
ahci_port_stop(p);
} else {
@@ -1978,6 +2005,10 @@ pci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
p->cmd &= ~AHCI_P_CMD_CLO;
}
+ if (value & AHCI_P_CMD_ICC_MASK) {
+ p->cmd &= ~AHCI_P_CMD_ICC_MASK;
+ }
+
ahci_handle_port(p);
break;
}
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index 6b906ed..03ff0c0 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -59,17 +59,6 @@ __FBSDID("$FreeBSD$");
#define CONF1_ENABLE 0x80000000ul
-#define CFGWRITE(pi,off,val,b) \
-do { \
- if ((b) == 1) { \
- pci_set_cfgdata8((pi),(off),(val)); \
- } else if ((b) == 2) { \
- pci_set_cfgdata16((pi),(off),(val)); \
- } else { \
- pci_set_cfgdata32((pi),(off),(val)); \
- } \
-} while (0)
-
#define MAXBUSES (PCI_BUSMAX + 1)
#define MAXSLOTS (PCI_SLOTMAX + 1)
#define MAXFUNCS (PCI_FUNCMAX + 1)
@@ -124,6 +113,30 @@ static void pci_lintr_update(struct pci_devinst *pi);
static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot,
int func, int coff, int bytes, uint32_t *val);
+static __inline void
+CFGWRITE(struct pci_devinst *pi, int coff, uint32_t val, int bytes)
+{
+
+ if (bytes == 1)
+ pci_set_cfgdata8(pi, coff, val);
+ else if (bytes == 2)
+ pci_set_cfgdata16(pi, coff, val);
+ else
+ pci_set_cfgdata32(pi, coff, val);
+}
+
+static __inline uint32_t
+CFGREAD(struct pci_devinst *pi, int coff, int bytes)
+{
+
+ if (bytes == 1)
+ return (pci_get_cfgdata8(pi, coff));
+ else if (bytes == 2)
+ return (pci_get_cfgdata16(pi, coff));
+ else
+ return (pci_get_cfgdata32(pi, coff));
+}
+
/*
* I/O access
*/
@@ -1653,27 +1666,31 @@ pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv)
}
}
-static uint32_t
-bits_changed(uint32_t old, uint32_t new, uint32_t mask)
-{
-
- return ((old ^ new) & mask);
-}
-
static void
-pci_emul_cmdwrite(struct pci_devinst *pi, uint32_t new, int bytes)
+pci_emul_cmdsts_write(struct pci_devinst *pi, int coff, uint32_t new, int bytes)
{
- int i;
- uint16_t old;
+ int i, rshift;
+ uint32_t cmd, cmd2, changed, old, readonly;
+
+ cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); /* stash old value */
/*
- * The command register is at an offset of 4 bytes and thus the
- * guest could write 1, 2 or 4 bytes starting at this offset.
+ * From PCI Local Bus Specification 3.0 sections 6.2.2 and 6.2.3.
+ *
+ * XXX Bits 8, 11, 12, 13, 14 and 15 in the status register are
+ * 'write 1 to clear'. However these bits are not set to '1' by
+ * any device emulation so it is simpler to treat them as readonly.
*/
+ rshift = (coff & 0x3) * 8;
+ readonly = 0xFFFFF880 >> rshift;
- old = pci_get_cfgdata16(pi, PCIR_COMMAND); /* stash old value */
- CFGWRITE(pi, PCIR_COMMAND, new, bytes); /* update config */
- new = pci_get_cfgdata16(pi, PCIR_COMMAND); /* get updated value */
+ old = CFGREAD(pi, coff, bytes);
+ new &= ~readonly;
+ new |= (old & readonly);
+ CFGWRITE(pi, coff, new, bytes); /* update config */
+
+ cmd2 = pci_get_cfgdata16(pi, PCIR_COMMAND); /* get updated value */
+ changed = cmd ^ cmd2;
/*
* If the MMIO or I/O address space decoding has changed then
@@ -1686,7 +1703,7 @@ pci_emul_cmdwrite(struct pci_devinst *pi, uint32_t new, int bytes)
break;
case PCIBAR_IO:
/* I/O address space decoding changed? */
- if (bits_changed(old, new, PCIM_CMD_PORTEN)) {
+ if (changed & PCIM_CMD_PORTEN) {
if (porten(pi))
register_bar(pi, i);
else
@@ -1696,7 +1713,7 @@ pci_emul_cmdwrite(struct pci_devinst *pi, uint32_t new, int bytes)
case PCIBAR_MEM32:
case PCIBAR_MEM64:
/* MMIO address space decoding changed? */
- if (bits_changed(old, new, PCIM_CMD_MEMEN)) {
+ if (changed & PCIM_CMD_MEMEN) {
if (memen(pi))
register_bar(pi, i);
else
@@ -1776,14 +1793,8 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
needcfg = 1;
}
- if (needcfg) {
- if (bytes == 1)
- *eax = pci_get_cfgdata8(pi, coff);
- else if (bytes == 2)
- *eax = pci_get_cfgdata16(pi, coff);
- else
- *eax = pci_get_cfgdata32(pi, coff);
- }
+ if (needcfg)
+ *eax = CFGREAD(pi, coff, bytes);
pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax);
} else {
@@ -1853,8 +1864,8 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
} else if (pci_emul_iscap(pi, coff)) {
pci_emul_capwrite(pi, coff, bytes, *eax);
- } else if (coff == PCIR_COMMAND) {
- pci_emul_cmdwrite(pi, *eax, bytes);
+ } else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) {
+ pci_emul_cmdsts_write(pi, coff, *eax, bytes);
} else {
CFGWRITE(pi, coff, *eax, bytes);
}
@@ -1927,7 +1938,7 @@ INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+3, IOPORT_F_INOUT, pci_emul_cfgdata);
#define DMEMSZ 4096
struct pci_emul_dsoftc {
uint8_t ioregs[DIOSZ];
- uint8_t memregs[DMEMSZ];
+ uint8_t memregs[2][DMEMSZ];
};
#define PCI_EMUL_MSI_MSGS 4
@@ -1956,6 +1967,9 @@ pci_emul_dinit(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, DMEMSZ);
assert(error == 0);
+ error = pci_emul_alloc_bar(pi, 2, PCIBAR_MEM32, DMEMSZ);
+ assert(error == 0);
+
return (0);
}
@@ -1995,21 +2009,23 @@ pci_emul_diow(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
}
}
- if (baridx == 1) {
+ if (baridx == 1 || baridx == 2) {
if (offset + size > DMEMSZ) {
printf("diow: memw too large, offset %ld size %d\n",
offset, size);
return;
}
+ i = baridx - 1; /* 'memregs' index */
+
if (size == 1) {
- sc->memregs[offset] = value;
+ sc->memregs[i][offset] = value;
} else if (size == 2) {
- *(uint16_t *)&sc->memregs[offset] = value;
+ *(uint16_t *)&sc->memregs[i][offset] = value;
} else if (size == 4) {
- *(uint32_t *)&sc->memregs[offset] = value;
+ *(uint32_t *)&sc->memregs[i][offset] = value;
} else if (size == 8) {
- *(uint64_t *)&sc->memregs[offset] = value;
+ *(uint64_t *)&sc->memregs[i][offset] = value;
} else {
printf("diow: memw unknown size %d\n", size);
}
@@ -2019,7 +2035,7 @@ pci_emul_diow(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
*/
}
- if (baridx > 1) {
+ if (baridx > 2) {
printf("diow: unknown bar idx %d\n", baridx);
}
}
@@ -2030,6 +2046,7 @@ pci_emul_dior(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
{
struct pci_emul_dsoftc *sc = pi->pi_arg;
uint32_t value;
+ int i;
if (baridx == 0) {
if (offset + size > DIOSZ) {
@@ -2048,29 +2065,31 @@ pci_emul_dior(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
printf("dior: ior unknown size %d\n", size);
}
}
-
- if (baridx == 1) {
+
+ if (baridx == 1 || baridx == 2) {
if (offset + size > DMEMSZ) {
printf("dior: memr too large, offset %ld size %d\n",
offset, size);
return (0);
}
-
+
+ i = baridx - 1; /* 'memregs' index */
+
if (size == 1) {
- value = sc->memregs[offset];
+ value = sc->memregs[i][offset];
} else if (size == 2) {
- value = *(uint16_t *) &sc->memregs[offset];
+ value = *(uint16_t *) &sc->memregs[i][offset];
} else if (size == 4) {
- value = *(uint32_t *) &sc->memregs[offset];
+ value = *(uint32_t *) &sc->memregs[i][offset];
} else if (size == 8) {
- value = *(uint64_t *) &sc->memregs[offset];
+ value = *(uint64_t *) &sc->memregs[i][offset];
} else {
printf("dior: ior unknown size %d\n", size);
}
}
- if (baridx > 1) {
+ if (baridx > 2) {
printf("dior: unknown bar idx %d\n", baridx);
return (0);
}
diff --git a/usr.sbin/bhyve/pci_irq.c b/usr.sbin/bhyve/pci_irq.c
index 20e033f..f22b15c 100644
--- a/usr.sbin/bhyve/pci_irq.c
+++ b/usr.sbin/bhyve/pci_irq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Advanced Computing Technologies LLC
+ * Copyright (c) 2014 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.sbin/bhyve/pci_irq.h b/usr.sbin/bhyve/pci_irq.h
index 9d331a5..24f9c99 100644
--- a/usr.sbin/bhyve/pci_irq.h
+++ b/usr.sbin/bhyve/pci_irq.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Advanced Computing Technologies LLC
+ * Copyright (c) 2014 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.sbin/bhyve/pci_virtio_block.c b/usr.sbin/bhyve/pci_virtio_block.c
index 967b528..35daa1f 100644
--- a/usr.sbin/bhyve/pci_virtio_block.c
+++ b/usr.sbin/bhyve/pci_virtio_block.c
@@ -198,7 +198,7 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
struct pci_vtblk_ioreq *io;
int i, n;
int err;
- int iolen;
+ ssize_t iolen;
int writeop, type;
off_t offset;
struct iovec iov[BLOCKIF_IOV_MAX + 2];
@@ -246,8 +246,9 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
assert(((flags[i] & VRING_DESC_F_WRITE) == 0) == writeop);
iolen += iov[i].iov_len;
}
+ io->io_req.br_resid = iolen;
- DPRINTF(("virtio-block: %s op, %d bytes, %d segs, offset %ld\n\r",
+ DPRINTF(("virtio-block: %s op, %zd bytes, %d segs, offset %ld\n\r",
writeop ? "write" : "read/ident", iolen, i - 1, offset));
switch (type) {
diff --git a/usr.sbin/bhyve/pci_virtio_net.c b/usr.sbin/bhyve/pci_virtio_net.c
index 457a405..7227488 100644
--- a/usr.sbin/bhyve/pci_virtio_net.c
+++ b/usr.sbin/bhyve/pci_virtio_net.c
@@ -393,6 +393,7 @@ pci_vtnet_ping_rxq(void *vsc, struct vqueue_info *vq)
*/
if (sc->vsc_rx_ready == 0) {
sc->vsc_rx_ready = 1;
+ vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;
}
}
@@ -438,6 +439,7 @@ pci_vtnet_ping_txq(void *vsc, struct vqueue_info *vq)
/* Signal the tx thread for processing */
pthread_mutex_lock(&sc->tx_mtx);
+ vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;
if (sc->tx_in_progress == 0)
pthread_cond_signal(&sc->tx_cond);
pthread_mutex_unlock(&sc->tx_mtx);
@@ -466,6 +468,7 @@ pci_vtnet_tx_thread(void *param)
for (;;) {
/* note - tx mutex is locked here */
do {
+ vq->vq_used->vu_flags &= ~VRING_USED_F_NO_NOTIFY;
if (sc->resetting)
have_work = 0;
else
@@ -478,6 +481,7 @@ pci_vtnet_tx_thread(void *param)
assert(error == 0);
}
} while (!have_work);
+ vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;
sc->tx_in_progress = 1;
pthread_mutex_unlock(&sc->tx_mtx);
@@ -640,8 +644,8 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
- /* link always up */
- sc->vsc_config.status = 1;
+ /* Link is up if we managed to open tap device. */
+ sc->vsc_config.status = (opts == NULL || sc->vsc_tapfd >= 0);
/* use BAR 1 to map MSI-X table and PBA, if we're using MSI-X */
if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
diff --git a/usr.sbin/bhyve/pm.c b/usr.sbin/bhyve/pm.c
index f5a2d43..f7c1c23 100644
--- a/usr.sbin/bhyve/pm.c
+++ b/usr.sbin/bhyve/pm.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.sbin/bhyvectl/Makefile b/usr.sbin/bhyvectl/Makefile
index c48ca6e..5c088a3 100644
--- a/usr.sbin/bhyvectl/Makefile
+++ b/usr.sbin/bhyvectl/Makefile
@@ -8,7 +8,7 @@ PACKAGE= bhyve
MAN=
-LIBADD= vmmapi util
+LIBADD= vmmapi
WARNS?= 3
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
index e2b514d..223ee25 100644
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -640,9 +640,9 @@ get_all_registers(struct vmctx *ctx, int vcpu)
uint64_t cr0, cr3, cr4, dr7, rsp, rip, rflags, efer;
uint64_t rax, rbx, rcx, rdx, rsi, rdi, rbp;
uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
- int error;
+ int error = 0;
- if (get_efer || get_all) {
+ if (!error && (get_efer || get_all)) {
error = vm_get_register(ctx, vcpu, VM_REG_GUEST_EFER, &efer);
if (error == 0)
printf("efer[%d]\t\t0x%016lx\n", vcpu, efer);
@@ -787,10 +787,10 @@ get_all_registers(struct vmctx *ctx, int vcpu)
static int
get_all_segments(struct vmctx *ctx, int vcpu)
{
- int error;
uint64_t cs, ds, es, fs, gs, ss, tr, ldtr;
+ int error = 0;
- if (get_desc_ds || get_all) {
+ if (!error && (get_desc_ds || get_all)) {
error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_DS,
&desc_base, &desc_limit, &desc_access);
if (error == 0) {
@@ -935,9 +935,9 @@ static int
get_misc_vmcs(struct vmctx *ctx, int vcpu)
{
uint64_t ctl, cr0, cr3, cr4, rsp, rip, pat, addr, u64;
- int error;
-
- if (get_cr0_mask || get_all) {
+ int error = 0;
+
+ if (!error && (get_cr0_mask || get_all)) {
uint64_t cr0mask;
error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR0_MASK, &cr0mask);
if (error == 0)
@@ -1161,9 +1161,9 @@ static int
get_misc_vmcb(struct vmctx *ctx, int vcpu)
{
uint64_t ctl, addr;
- int error;
+ int error = 0;
- if (get_vmcb_intercept || get_all) {
+ if (!error && (get_vmcb_intercept || get_all)) {
error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_CR_INTERCEPT, 4,
&ctl);
if (error == 0)
diff --git a/usr.sbin/bhyveload/Makefile b/usr.sbin/bhyveload/Makefile
index 17c6c8d..5fa692d 100644
--- a/usr.sbin/bhyveload/Makefile
+++ b/usr.sbin/bhyveload/Makefile
@@ -5,7 +5,7 @@ SRCS= bhyveload.c
MAN= bhyveload.8
PACKAGE= bhyve
-LIBADD= vmmapi util
+LIBADD= vmmapi
WARNS?= 3
diff --git a/usr.sbin/bluetooth/Makefile b/usr.sbin/bluetooth/Makefile
index 594b440..1737107 100644
--- a/usr.sbin/bluetooth/Makefile
+++ b/usr.sbin/bluetooth/Makefile
@@ -1,12 +1,10 @@
# $Id: Makefile,v 1.5 2003/09/08 02:28:35 max Exp $
# $FreeBSD$
+.include <src.opts.mk>
+
SUBDIR= \
- ath3kfw \
- bcmfw \
bt3cfw \
- bthidcontrol \
- bthidd \
btpand \
hccontrol \
hcsecd \
@@ -17,5 +15,12 @@ SUBDIR= \
sdpcontrol \
sdpd
+.if ${MK_USB} != "no"
+SUBDIR+= ath3kfw
+SUBDIR+= bcmfw
+SUBDIR+= bthidcontrol
+SUBDIR+= bthidd
+.endif
+
.include <bsd.subdir.mk>
diff --git a/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c b/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c
index 900bda5..0f795dd 100644
--- a/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c
+++ b/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c
@@ -31,6 +31,7 @@
#include <sys/queue.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <errno.h>
diff --git a/usr.sbin/bluetooth/bthidcontrol/hid.c b/usr.sbin/bluetooth/bthidcontrol/hid.c
index 9fb6220..e43ef6a 100644
--- a/usr.sbin/bluetooth/bthidcontrol/hid.c
+++ b/usr.sbin/bluetooth/bthidcontrol/hid.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
diff --git a/usr.sbin/bluetooth/bthidcontrol/sdp.c b/usr.sbin/bluetooth/bthidcontrol/sdp.c
index a0b4534..3beabc1 100644
--- a/usr.sbin/bluetooth/bthidcontrol/sdp.c
+++ b/usr.sbin/bluetooth/bthidcontrol/sdp.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
diff --git a/usr.sbin/bluetooth/bthidd/bthidd.c b/usr.sbin/bluetooth/bthidd/bthidd.c
index b93fd3d..7e988fc 100644
--- a/usr.sbin/bluetooth/bthidd/bthidd.c
+++ b/usr.sbin/bluetooth/bthidd/bthidd.c
@@ -34,6 +34,7 @@
#include <sys/time.h>
#include <sys/queue.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <errno.h>
diff --git a/usr.sbin/bluetooth/bthidd/client.c b/usr.sbin/bluetooth/bthidd/client.c
index 59f0d19..5f01133 100644
--- a/usr.sbin/bluetooth/bthidd/client.c
+++ b/usr.sbin/bluetooth/bthidd/client.c
@@ -33,6 +33,7 @@
#include <sys/queue.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <fcntl.h>
@@ -236,7 +237,9 @@ client_socket(bdaddr_p bdaddr, uint16_t psm)
l2addr.l2cap_family = AF_BLUETOOTH;
memset(&l2addr.l2cap_bdaddr, 0, sizeof(l2addr.l2cap_bdaddr));
l2addr.l2cap_psm = 0;
-
+ l2addr.l2cap_bdaddr_type = BDADDR_BREDR;
+ l2addr.l2cap_cid = 0;
+
if (bind(s, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
close(s);
return (-1);
diff --git a/usr.sbin/bluetooth/bthidd/hid.c b/usr.sbin/bluetooth/bthidd/hid.c
index c68865b..69a6fdc 100644
--- a/usr.sbin/bluetooth/bthidd/hid.c
+++ b/usr.sbin/bluetooth/bthidd/hid.c
@@ -35,6 +35,7 @@
#include <sys/mouse.h>
#include <sys/queue.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
@@ -48,12 +49,6 @@
#include "bthidd.h"
#include "kbd.h"
-#undef min
-#define min(x, y) (((x) < (y))? (x) : (y))
-
-#undef ASIZE
-#define ASIZE(a) (sizeof(a)/sizeof(a[0]))
-
/*
* Process data from control channel
*/
@@ -165,9 +160,21 @@ hid_interrupt(bthid_session_p s, uint8_t *data, int32_t len)
continue;
page = HID_PAGE(h.usage);
- usage = HID_USAGE(h.usage);
val = hid_get_data(data, &h);
+ /*
+ * When the input field is an array and the usage is specified
+ * with a range instead of an ID, we have to derive the actual
+ * usage by using the item value as an index in the usage range
+ * list.
+ */
+ if ((h.flags & HIO_VARIABLE)) {
+ usage = HID_USAGE(h.usage);
+ } else {
+ const uint32_t usage_offset = val - h.logical_minimum;
+ usage = HID_USAGE(h.usage_minimum + usage_offset);
+ }
+
switch (page) {
case HUP_GENERIC_DESKTOP:
switch (usage) {
diff --git a/usr.sbin/bluetooth/bthidd/kbd.c b/usr.sbin/bluetooth/bthidd/kbd.c
index 20b6278..e570b80 100644
--- a/usr.sbin/bluetooth/bthidd/kbd.c
+++ b/usr.sbin/bluetooth/bthidd/kbd.c
@@ -37,6 +37,7 @@
#include <sys/queue.h>
#include <sys/wait.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
diff --git a/usr.sbin/bluetooth/bthidd/lexer.l b/usr.sbin/bluetooth/bthidd/lexer.l
index b9f62a1..6d913ee 100644
--- a/usr.sbin/bluetooth/bthidd/lexer.l
+++ b/usr.sbin/bluetooth/bthidd/lexer.l
@@ -31,7 +31,7 @@
* $Id: lexer.l,v 1.3 2006/09/07 21:06:53 max Exp $
* $FreeBSD$
*/
-
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <stdlib.h>
#include "parser.h"
diff --git a/usr.sbin/bluetooth/bthidd/parser.y b/usr.sbin/bluetooth/bthidd/parser.y
index 50468f4..dbb2763 100644
--- a/usr.sbin/bluetooth/bthidd/parser.y
+++ b/usr.sbin/bluetooth/bthidd/parser.y
@@ -33,6 +33,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
diff --git a/usr.sbin/bluetooth/bthidd/server.c b/usr.sbin/bluetooth/bthidd/server.c
index d76bd62..26aeb4a 100644
--- a/usr.sbin/bluetooth/bthidd/server.c
+++ b/usr.sbin/bluetooth/bthidd/server.c
@@ -33,6 +33,7 @@
#include <sys/queue.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <dev/vkbd/vkbd_var.h>
#include <errno.h>
@@ -90,7 +91,9 @@ server_init(bthid_server_p srv)
l2addr.l2cap_family = AF_BLUETOOTH;
memcpy(&l2addr.l2cap_bdaddr, &srv->bdaddr, sizeof(l2addr.l2cap_bdaddr));
l2addr.l2cap_psm = htole16(0x11);
-
+ l2addr.l2cap_bdaddr_type = BDADDR_BREDR;
+ l2addr.l2cap_cid = 0;
+
if (bind(srv->ctrl, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
syslog(LOG_ERR, "Could not bind control L2CAP socket. " \
"%s (%d)", strerror(errno), errno);
diff --git a/usr.sbin/bluetooth/bthidd/session.c b/usr.sbin/bluetooth/bthidd/session.c
index b9f331b..260cb86 100644
--- a/usr.sbin/bluetooth/bthidd/session.c
+++ b/usr.sbin/bluetooth/bthidd/session.c
@@ -33,6 +33,7 @@
#include <sys/queue.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/usr.sbin/bluetooth/btpand/bnep.c b/usr.sbin/bluetooth/btpand/bnep.c
index 200a723..4065b1b 100644
--- a/usr.sbin/bluetooth/btpand/bnep.c
+++ b/usr.sbin/bluetooth/btpand/bnep.c
@@ -31,6 +31,7 @@
__RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
#include <sys/uio.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <stdarg.h>
diff --git a/usr.sbin/bluetooth/btpand/btpand.c b/usr.sbin/bluetooth/btpand/btpand.c
index 9387444..243fcf5 100644
--- a/usr.sbin/bluetooth/btpand/btpand.c
+++ b/usr.sbin/bluetooth/btpand/btpand.c
@@ -33,6 +33,7 @@ __RCSID("$NetBSD: btpand.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
#include <sys/wait.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <fcntl.h>
diff --git a/usr.sbin/bluetooth/btpand/channel.c b/usr.sbin/bluetooth/btpand/channel.c
index b4eb4ab..32f2487 100644
--- a/usr.sbin/bluetooth/btpand/channel.c
+++ b/usr.sbin/bluetooth/btpand/channel.c
@@ -35,7 +35,7 @@ __RCSID("$NetBSD: channel.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
#include <libutil.h>
#include <unistd.h>
-
+#define L2CAP_SOCKET_CHECKED
#include "btpand.h"
static struct chlist channel_list;
diff --git a/usr.sbin/bluetooth/btpand/client.c b/usr.sbin/bluetooth/btpand/client.c
index 2cc9089..f88dc6e 100644
--- a/usr.sbin/bluetooth/btpand/client.c
+++ b/usr.sbin/bluetooth/btpand/client.c
@@ -30,6 +30,7 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: client.c,v 1.2 2008/12/06 20:01:14 plunky Exp $");
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
@@ -65,6 +66,9 @@ client_init(void)
memset(&sa, 0, sizeof(sa));
sa.l2cap_family = AF_BLUETOOTH;
sa.l2cap_len = sizeof(sa);
+ sa.l2cap_bdaddr_type = BDADDR_BREDR;
+ sa.l2cap_cid = 0;
+
bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
log_err("Could not bind client socket: %m");
diff --git a/usr.sbin/bluetooth/btpand/event.c b/usr.sbin/bluetooth/btpand/event.c
index 159f90c..ac51f57 100644
--- a/usr.sbin/bluetooth/btpand/event.c
+++ b/usr.sbin/bluetooth/btpand/event.c
@@ -45,6 +45,7 @@
#include <syslog.h>
#include "event.h"
+#define L2CAP_SOCKET_CHECKED
#include "btpand.h"
#define __event_link(ev) \
diff --git a/usr.sbin/bluetooth/btpand/packet.c b/usr.sbin/bluetooth/btpand/packet.c
index e42e5c5..21a563c 100644
--- a/usr.sbin/bluetooth/btpand/packet.c
+++ b/usr.sbin/bluetooth/btpand/packet.c
@@ -30,6 +30,7 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: packet.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
+#define L2CAP_SOCKET_CHECKED
#include "btpand.h"
packet_t *
diff --git a/usr.sbin/bluetooth/btpand/sdp.c b/usr.sbin/bluetooth/btpand/sdp.c
index e5aec1c..3cad3f8 100644
--- a/usr.sbin/bluetooth/btpand/sdp.c
+++ b/usr.sbin/bluetooth/btpand/sdp.c
@@ -32,6 +32,7 @@ __RCSID("$NetBSD: sdp.c,v 1.2 2008/12/06 20:01:14 plunky Exp $");
#include <string.h>
+#define L2CAP_SOCKET_CHECKED
#include "sdp.h"
/*
diff --git a/usr.sbin/bluetooth/btpand/server.c b/usr.sbin/bluetooth/btpand/server.c
index b24d416..b72b032 100644
--- a/usr.sbin/bluetooth/btpand/server.c
+++ b/usr.sbin/bluetooth/btpand/server.c
@@ -32,6 +32,7 @@ __RCSID("$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $");
#include <sys/ioctl.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <inttypes.h>
#include <errno.h>
@@ -103,6 +104,9 @@ server_open(void)
sa.l2cap_family = AF_BLUETOOTH;
sa.l2cap_len = sizeof(sa);
sa.l2cap_psm = htole16(l2cap_psm);
+ sa.l2cap_bdaddr_type = BDADDR_BREDR;
+ sa.l2cap_cid = 0;
+
bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);
if (bind(server_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
log_err("Could not bind server socket: %m");
diff --git a/usr.sbin/bluetooth/btpand/tap.c b/usr.sbin/bluetooth/btpand/tap.c
index c965633..644bf02 100644
--- a/usr.sbin/bluetooth/btpand/tap.c
+++ b/usr.sbin/bluetooth/btpand/tap.c
@@ -43,6 +43,7 @@ __RCSID("$NetBSD: tap.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
#include <stdio.h>
#include <unistd.h>
+#define L2CAP_SOCKET_CHECKED
#include "btpand.h"
static bool tap_send(channel_t *, packet_t *);
diff --git a/usr.sbin/bluetooth/hccontrol/Makefile b/usr.sbin/bluetooth/hccontrol/Makefile
index 61206df..a81fda4 100644
--- a/usr.sbin/bluetooth/hccontrol/Makefile
+++ b/usr.sbin/bluetooth/hccontrol/Makefile
@@ -3,7 +3,7 @@
PROG= hccontrol
MAN= hccontrol.8
-SRCS= send_recv.c link_policy.c link_control.c \
+SRCS= send_recv.c link_policy.c link_control.c le.c\
host_controller_baseband.c info.c status.c node.c hccontrol.c \
util.c
WARNS?= 2
diff --git a/usr.sbin/bluetooth/hccontrol/hccontrol.c b/usr.sbin/bluetooth/hccontrol/hccontrol.c
index 089869b..b72854f 100644
--- a/usr.sbin/bluetooth/hccontrol/hccontrol.c
+++ b/usr.sbin/bluetooth/hccontrol/hccontrol.c
@@ -29,6 +29,7 @@
* $FreeBSD$
*/
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
@@ -143,6 +144,7 @@ socket_open(char const *node)
bit_set(filter.event_mask, NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_CON_PKT_TYPE_CHANGED - 1);
bit_set(filter.event_mask, NG_HCI_EVENT_ROLE_CHANGE - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_LE -1);
if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
(void * const) &filter, sizeof(filter)) < 0)
@@ -181,6 +183,7 @@ do_hci_command(char const *node, int argc, char **argv)
print_hci_command(host_controller_baseband_commands);
print_hci_command(info_commands);
print_hci_command(status_commands);
+ print_hci_command(le_commands);
print_hci_command(node_commands);
fprintf(stdout, "\nFor more information use " \
"'help command'\n");
@@ -212,6 +215,11 @@ do_hci_command(char const *node, int argc, char **argv)
if (c != NULL)
goto execute;
+ c = find_hci_command(cmd, le_commands);
+ if (c != NULL)
+ goto execute;
+
+
c = find_hci_command(cmd, node_commands);
if (c == NULL) {
fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
diff --git a/usr.sbin/bluetooth/hccontrol/hccontrol.h b/usr.sbin/bluetooth/hccontrol/hccontrol.h
index cd56ebf..c96aab0 100644
--- a/usr.sbin/bluetooth/hccontrol/hccontrol.h
+++ b/usr.sbin/bluetooth/hccontrol/hccontrol.h
@@ -53,6 +53,7 @@ extern struct hci_command host_controller_baseband_commands[];
extern struct hci_command info_commands[];
extern struct hci_command status_commands[];
extern struct hci_command node_commands[];
+extern struct hci_command le_commands[];
int hci_request (int, int, char const *, int, char *, int *);
int hci_simple_request (int, int, char *, int *);
diff --git a/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c b/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c
index aae5dd1..532ca1c 100644
--- a/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c
+++ b/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c
@@ -29,6 +29,7 @@
* $FreeBSD$
*/
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <stdio.h>
@@ -1487,6 +1488,78 @@ hci_write_page_scan_mode(int s, int argc, char **argv)
return (OK);
} /* hci_write_page_scan_mode */
+static int
+hci_read_le_host_supported_command(int s, int argc, char **argv)
+{
+ ng_hci_read_le_host_supported_rp rp;
+ int n;
+ n = sizeof(rp);
+ if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_READ_LE_HOST_SUPPORTED),
+ (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ fprintf(stdout, "LE Host support: %#02x\n", rp.le_supported_host);
+ fprintf(stdout, "Simulateneouse LE Host : %#02x\n", rp.simultaneous_le_host);
+
+ return (OK);
+
+}
+static int
+hci_write_le_host_supported_command(int s, int argc, char **argv)
+{
+ ng_hci_write_le_host_supported_cp cp;
+ ng_hci_write_le_host_supported_rp rp;
+
+ int n;
+
+ cp.le_supported_host = 0;
+ cp.simultaneous_le_host = 0;
+ switch (argc) {
+ case 2:
+ if (sscanf(argv[1], "%d", &n) != 1 || (n != 0 && n != 1)){
+ printf("ARGC2: %d\n", n);
+ return (USAGE);
+ }
+ cp.simultaneous_le_host = (n &1);
+
+ case 1:
+ if (sscanf(argv[0], "%d", &n) != 1 || (n != 0 && n != 1)){
+ printf("ARGC1: %d\n", n);
+ return (USAGE);
+ }
+
+ cp.le_supported_host = (n &1);
+ break;
+
+ default:
+ return (USAGE);
+ }
+
+
+ /* send command */
+ n = sizeof(rp);
+ if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_WRITE_LE_HOST_SUPPORTED),
+ (char const *) &cp, sizeof(cp),
+ (char *) &rp, &n) == ERROR)
+ return (ERROR);
+
+ if (rp.status != 0x00) {
+ fprintf(stdout, "Status: %s [%#02x]\n",
+ hci_status2str(rp.status), rp.status);
+ return (FAILED);
+ }
+
+ return (OK);
+}
+
struct hci_command host_controller_baseband_commands[] = {
{
"reset",
@@ -1872,6 +1945,17 @@ struct hci_command host_controller_baseband_commands[] = {
"\t0x03 - Optional Page Scan Mode III",
&hci_write_page_scan_mode
},
+{
+"read_le_host_supported_command", \
+"Read if this host is in le supported mode and stimulatenouse le supported mode",
+&hci_read_le_host_supported_command,
+},
+{
+"write_le_host_supported_command", \
+"write_le_host_supported_command le_host[0|1] stimultajeous_le[0|1]",
+&hci_write_le_host_supported_command,
+},
+
{ NULL, }
};
diff --git a/usr.sbin/bluetooth/hccontrol/info.c b/usr.sbin/bluetooth/hccontrol/info.c
index d7bad36..ee9d1a1 100644
--- a/usr.sbin/bluetooth/hccontrol/info.c
+++ b/usr.sbin/bluetooth/hccontrol/info.c
@@ -29,6 +29,7 @@
* $FreeBSD$
*/
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <stdio.h>
diff --git a/usr.sbin/bluetooth/hccontrol/le.c b/usr.sbin/bluetooth/hccontrol/le.c
new file mode 100644
index 0000000..afb151e
--- /dev/null
+++ b/usr.sbin/bluetooth/hccontrol/le.c
@@ -0,0 +1,356 @@
+/*
+ * le.c
+ *
+ * Copyright (c) 2015 Takanori Watanabe <takawata@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/bitstring.h>
+#include <sys/select.h>
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <netgraph/ng_message.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include "hccontrol.h"
+
+static int le_set_scan_param(int s, int argc, char *argv[]);
+static int le_set_scan_enable(int s, int argc, char *argv[]);
+static int parse_param(int argc, char *argv[], char *buf, int *len);
+static int le_set_scan_response(int s, int argc, char *argv[]);
+static int le_read_supported_status(int s, int argc, char *argv[]);
+static int le_read_local_supported_features(int s, int argc ,char *argv[]);
+static int set_le_event_mask(int s, uint64_t mask);
+static int set_event_mask(int s, uint64_t mask);
+static int le_enable(int s, int argc, char *argv[]);
+
+static int
+le_set_scan_param(int s, int argc, char *argv[])
+{
+ int type;
+ int interval;
+ int window;
+ int adrtype;
+ int policy;
+ int e, n;
+
+ ng_hci_le_set_scan_parameters_cp cp;
+ ng_hci_le_set_scan_parameters_rp rp;
+
+ if (argc != 5)
+ return USAGE;
+
+ if (strcmp(argv[0], "active") == 0)
+ type = 1;
+ else if (strcmp(argv[0], "passive") == 0)
+ type = 0;
+ else
+ return USAGE;
+
+ interval = (int)(atof(argv[1])/0.625);
+ interval = (interval < 4)? 4: interval;
+ window = (int)(atof(argv[2])/0.625);
+ window = (window < 4) ? 4 : interval;
+
+ if (strcmp(argv[3], "public") == 0)
+ adrtype = 0;
+ else if (strcmp(argv[0], "random") == 0)
+ adrtype = 1;
+ else
+ return USAGE;
+
+ if (strcmp(argv[4], "all") == 0)
+ policy = 0;
+ else if (strcmp(argv[4], "whitelist") == 0)
+ policy = 1;
+ else
+ return USAGE;
+
+ cp.le_scan_type = type;
+ cp.le_scan_interval = interval;
+ cp.own_address_type = adrtype;
+ cp.le_scan_window = window;
+ cp.scanning_filter_policy = policy;
+ n = sizeof(rp);
+ e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
+ NG_HCI_OCF_LE_SET_SCAN_PARAMETERS),
+ (void *)&cp, sizeof(cp), (void *)&rp, &n);
+
+ return 0;
+}
+
+static int
+le_set_scan_enable(int s, int argc, char *argv[])
+{
+ ng_hci_le_set_scan_enable_cp cp;
+ ng_hci_le_set_scan_enable_rp rp;
+ int e, n, enable = 0;
+
+ if (argc != 1)
+ return USAGE;
+
+ if (strcmp(argv[0], "enable") == 0)
+ enable = 1;
+ else if (strcmp(argv[0], "disable") != 0)
+ return USAGE;
+
+ n = sizeof(rp);
+ cp.le_scan_enable = enable;
+ cp.filter_duplicates = 0;
+ e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
+ NG_HCI_OCF_LE_SET_SCAN_ENABLE),
+ (void *)&cp, sizeof(cp), (void *)&rp, &n);
+
+ if (e != 0 || rp.status != 0)
+ return ERROR;
+
+ return OK;
+}
+
+static int
+parse_param(int argc, char *argv[], char *buf, int *len)
+{
+ char *buflast = buf + (*len);
+ char *curbuf = buf;
+ char *token,*lenpos;
+ int ch;
+ int datalen;
+ uint16_t value;
+ optreset = 1;
+ optind = 0;
+ while ((ch = getopt(argc, argv , "n:f:u:")) != -1) {
+ switch(ch){
+ case 'n':
+ datalen = strlen(optarg);
+ if ((curbuf + datalen + 2) >= buflast)
+ goto done;
+ curbuf[0] = datalen + 1;
+ curbuf[1] = 8;
+ curbuf += 2;
+ memcpy(curbuf, optarg, datalen);
+ curbuf += datalen;
+ break;
+ case 'f':
+ if (curbuf+3 > buflast)
+ goto done;
+ curbuf[0] = 2;
+ curbuf[1] = 1;
+ curbuf[2] = atoi(optarg);
+ curbuf += 3;
+ break;
+ case 'u':
+ lenpos = buf;
+ if ((buf+2) >= buflast)
+ goto done;
+ curbuf[1] = 2;
+ *lenpos = 1;
+ curbuf += 2;
+ while ((token = strsep(&optarg, ",")) != NULL) {
+ value = strtol(token, NULL, 16);
+ if ((curbuf+2) >= buflast)
+ break;
+ curbuf[0] = value &0xff;
+ curbuf[1] = (value>>8)&0xff;
+ curbuf += 2;
+ }
+
+ }
+ }
+done:
+ *len = curbuf - buf;
+
+ return OK;
+}
+
+static int
+le_set_scan_response(int s, int argc, char *argv[])
+{
+ ng_hci_le_set_scan_response_data_cp cp;
+ ng_hci_le_set_scan_response_data_rp rp;
+ int n;
+ int e;
+ int len;
+ char buf[NG_HCI_ADVERTISING_DATA_SIZE];
+
+ len = sizeof(buf);
+ parse_param(argc, argv, buf, &len);
+ memset(cp.scan_response_data, 0, sizeof(cp.scan_response_data));
+ cp.scan_response_data_length = len;
+ memcpy(cp.scan_response_data, buf, len);
+ n = sizeof(rp);
+ e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
+ NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA),
+ (void *)&cp, sizeof(cp), (void *)&rp, &n);
+
+ printf("SET SCAN RESPONSE %d %d %d\n", e, rp.status, n);
+
+ return OK;
+}
+
+static int
+le_read_local_supported_features(int s, int argc ,char *argv[])
+{
+ ng_hci_le_read_local_supported_features_rp rp;
+ int e;
+ int n = sizeof(rp);
+
+ e = hci_simple_request(s,
+ NG_HCI_OPCODE(NG_HCI_OGF_LE,
+ NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES),
+ (void *)&rp, &n);
+
+ printf("LOCAL SUPPORTED: %d %d %jx\n", e, rp.status,
+ (uintmax_t) rp.le_features);
+
+ return 0;
+}
+
+static int
+le_read_supported_status(int s, int argc, char *argv[])
+{
+ ng_hci_le_read_supported_status_rp rp;
+ int e;
+ int n = sizeof(rp);
+
+ e = hci_simple_request(s, NG_HCI_OPCODE(
+ NG_HCI_OGF_LE,
+ NG_HCI_OCF_LE_READ_SUPPORTED_STATUS),
+ (void *)&rp, &n);
+
+ printf("LE_STATUS: %d %d %jx\n", e, rp.status, (uintmax_t)rp.le_status);
+
+ return 0;
+}
+
+static int
+set_le_event_mask(int s, uint64_t mask)
+{
+ ng_hci_le_set_event_mask_cp semc;
+ ng_hci_le_set_event_mask_rp rp;
+ int i, n ,e;
+
+ n = sizeof(rp);
+
+ for (i=0; i < NG_HCI_LE_EVENT_MASK_SIZE; i++) {
+ semc.event_mask[i] = mask&0xff;
+ mask >>= 8;
+ }
+ e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LE,
+ NG_HCI_OCF_LE_SET_EVENT_MASK),
+ (void *)&semc, sizeof(semc), (void *)&rp, &n);
+
+ return 0;
+}
+
+static int
+set_event_mask(int s, uint64_t mask)
+{
+ ng_hci_set_event_mask_cp semc;
+ ng_hci_set_event_mask_rp rp;
+ int i, n, e;
+
+ n = sizeof(rp);
+
+ for (i=0; i < NG_HCI_EVENT_MASK_SIZE; i++) {
+ semc.event_mask[i] = mask&0xff;
+ mask >>= 8;
+ }
+ e = hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+ NG_HCI_OCF_SET_EVENT_MASK),
+ (void *)&semc, sizeof(semc), (void *)&rp, &n);
+
+ return 0;
+}
+
+static
+int le_enable(int s, int argc, char *argv[])
+{
+ if (argc != 1)
+ return USAGE;
+
+ if (strcasecmp(argv[0], "enable") == 0) {
+ set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT |
+ NG_HCI_EVENT_MASK_LE);
+ set_le_event_mask(s, NG_HCI_LE_EVENT_MASK_ALL);
+ } else if (strcasecmp(argv[0], "disble") == 0)
+ set_event_mask(s, NG_HCI_EVENT_MASK_DEFAULT);
+ else
+ return USAGE;
+
+ return OK;
+}
+
+struct hci_command le_commands[] = {
+{
+ "le_enable",
+ "le_enable [enable|disable] \n"
+ "Enable LE event ",
+ &le_enable,
+},
+ {
+ "le_read_local_supported_features",
+ "le_read_local_supported_features\n"
+ "read local supported features mask",
+ &le_read_local_supported_features,
+ },
+ {
+ "le_read_supported_status",
+ "le_read_supported_status\n"
+ "read supported status"
+ ,
+ &le_read_supported_status,
+ },
+ {
+ "le_set_scan_response",
+ "le_set_scan_response -n $name -f $flag -u $uuid16,$uuid16 \n"
+ "set LE scan response data"
+ ,
+ &le_set_scan_response,
+ },
+ {
+ "le_set_scan_enable",
+ "le_set_scan_enable [enable|disable] \n"
+ "enable or disable LE device scan",
+ &le_set_scan_enable
+ },
+ {
+ "le_set_scan_param",
+ "le_set_scan_param [active|passive] interval(ms) window(ms) [public|random] [all|whitelist] \n"
+ "set LE device scan parameter",
+ &le_set_scan_param
+ },
+};
diff --git a/usr.sbin/bluetooth/hccontrol/link_control.c b/usr.sbin/bluetooth/hccontrol/link_control.c
index 536520a..a55426c 100644
--- a/usr.sbin/bluetooth/hccontrol/link_control.c
+++ b/usr.sbin/bluetooth/hccontrol/link_control.c
@@ -29,6 +29,7 @@
* $FreeBSD$
*/
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <stdio.h>
diff --git a/usr.sbin/bluetooth/hccontrol/link_policy.c b/usr.sbin/bluetooth/hccontrol/link_policy.c
index 67b32d5..8142b23 100644
--- a/usr.sbin/bluetooth/hccontrol/link_policy.c
+++ b/usr.sbin/bluetooth/hccontrol/link_policy.c
@@ -29,6 +29,7 @@
* $FreeBSD$
*/
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <stdio.h>
diff --git a/usr.sbin/bluetooth/hccontrol/node.c b/usr.sbin/bluetooth/hccontrol/node.c
index ede2153..fb6fd19 100644
--- a/usr.sbin/bluetooth/hccontrol/node.c
+++ b/usr.sbin/bluetooth/hccontrol/node.c
@@ -30,6 +30,7 @@
*/
#include <sys/ioctl.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <netgraph/ng_message.h>
diff --git a/usr.sbin/bluetooth/hccontrol/util.c b/usr.sbin/bluetooth/hccontrol/util.c
index 4bb5000..1b05170 100644
--- a/usr.sbin/bluetooth/hccontrol/util.c
+++ b/usr.sbin/bluetooth/hccontrol/util.c
@@ -30,6 +30,7 @@
*/
#include <sys/param.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <stdio.h>
#include <string.h>
@@ -151,7 +152,12 @@ hci_ver2str(int ver)
/* 0x00 */ "Bluetooth HCI Specification 1.0B",
/* 0x01 */ "Bluetooth HCI Specification 1.1",
/* 0x02 */ "Bluetooth HCI Specification 1.2",
- /* 0x03 */ "Bluetooth HCI Specification 2.0"
+ /* 0x03 */ "Bluetooth HCI Specification 2.0",
+ /* 0x04 */ "Bluetooth HCI Specification 2.1",
+ /* 0x05 */ "Bluetooth HCI Specification 3.0",
+ /* 0x06 */ "Bluetooth HCI Specification 4.0",
+ /* 0x07 */ "Bluetooth HCI Specification 4.1",
+ /* 0x08 */ "Bluetooth HCI Specification 4.2"
};
return (ver >= SIZE(t)? "?" : t[ver]);
@@ -164,7 +170,12 @@ hci_lmpver2str(int ver)
/* 0x00 */ "Bluetooth LMP 1.0",
/* 0x01 */ "Bluetooth LMP 1.1",
/* 0x02 */ "Bluetooth LMP 1.2",
- /* 0x03 */ "Bluetooth LMP 2.0"
+ /* 0x03 */ "Bluetooth LMP 2.0",
+ /* 0x04 */ "Bluetooth LMP 2.1",
+ /* 0x04 */ "Bluetooth LMP 3.0",
+ /* 0x04 */ "Bluetooth LMP 4.0",
+ /* 0x04 */ "Bluetooth LMP 4.1",
+ /* 0x04 */ "Bluetooth LMP 4.2"
};
return (ver >= SIZE(t)? "?" : t[ver]);
diff --git a/usr.sbin/bluetooth/hcsecd/hcsecd.c b/usr.sbin/bluetooth/hcsecd/hcsecd.c
index 72f9c8c..15b5ca4 100644
--- a/usr.sbin/bluetooth/hcsecd/hcsecd.c
+++ b/usr.sbin/bluetooth/hcsecd/hcsecd.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <errno.h>
diff --git a/usr.sbin/bluetooth/hcsecd/parser.y b/usr.sbin/bluetooth/hcsecd/parser.y
index ec91c48..cfaeb02 100644
--- a/usr.sbin/bluetooth/hcsecd/parser.y
+++ b/usr.sbin/bluetooth/hcsecd/parser.y
@@ -32,6 +32,7 @@
#include <sys/fcntl.h>
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <limits.h>
diff --git a/usr.sbin/bluetooth/l2control/l2cap.c b/usr.sbin/bluetooth/l2control/l2cap.c
index c23106c..44009ef 100644
--- a/usr.sbin/bluetooth/l2control/l2cap.c
+++ b/usr.sbin/bluetooth/l2control/l2cap.c
@@ -30,6 +30,7 @@
*/
#include <sys/ioctl.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <stdio.h>
diff --git a/usr.sbin/bluetooth/l2control/l2control.c b/usr.sbin/bluetooth/l2control/l2control.c
index fdbf2f5b..87ec237 100644
--- a/usr.sbin/bluetooth/l2control/l2control.c
+++ b/usr.sbin/bluetooth/l2control/l2control.c
@@ -30,6 +30,7 @@
*/
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <errno.h>
diff --git a/usr.sbin/bluetooth/l2ping/l2ping.c b/usr.sbin/bluetooth/l2ping/l2ping.c
index 4baa354..92e7a0a 100644
--- a/usr.sbin/bluetooth/l2ping/l2ping.c
+++ b/usr.sbin/bluetooth/l2ping/l2ping.c
@@ -34,6 +34,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <errno.h>
diff --git a/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c b/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c
index 956dc4d..e970fb0 100644
--- a/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c
+++ b/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c
@@ -30,7 +30,7 @@
* $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $
* $FreeBSD$
*/
-
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <ctype.h>
#include <err.h>
diff --git a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c
index fca2015..65ee3d0 100644
--- a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c
+++ b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c
@@ -30,6 +30,7 @@
*/
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <err.h>
#include <errno.h>
diff --git a/usr.sbin/bluetooth/sdpcontrol/search.c b/usr.sbin/bluetooth/sdpcontrol/search.c
index e7d8244..acc8c16 100644
--- a/usr.sbin/bluetooth/sdpcontrol/search.c
+++ b/usr.sbin/bluetooth/sdpcontrol/search.c
@@ -30,6 +30,7 @@
*/
#include <netinet/in.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <ctype.h>
#include <sdp.h>
diff --git a/usr.sbin/bluetooth/sdpd/bgd.c b/usr.sbin/bluetooth/sdpd/bgd.c
index 70dda89..2c4e4d9 100644
--- a/usr.sbin/bluetooth/sdpd/bgd.c
+++ b/usr.sbin/bluetooth/sdpd/bgd.c
@@ -28,7 +28,7 @@
* $Id: bgd.c,v 1.4 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
-
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/dun.c b/usr.sbin/bluetooth/sdpd/dun.c
index e7aeb78..1496285 100644
--- a/usr.sbin/bluetooth/sdpd/dun.c
+++ b/usr.sbin/bluetooth/sdpd/dun.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/ftrn.c b/usr.sbin/bluetooth/sdpd/ftrn.c
index bcebfc7..bc1095e 100644
--- a/usr.sbin/bluetooth/sdpd/ftrn.c
+++ b/usr.sbin/bluetooth/sdpd/ftrn.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/gn.c b/usr.sbin/bluetooth/sdpd/gn.c
index d35c0ee..c2bea48 100644
--- a/usr.sbin/bluetooth/sdpd/gn.c
+++ b/usr.sbin/bluetooth/sdpd/gn.c
@@ -32,6 +32,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/irmc.c b/usr.sbin/bluetooth/sdpd/irmc.c
index d28a120..2b8f317 100644
--- a/usr.sbin/bluetooth/sdpd/irmc.c
+++ b/usr.sbin/bluetooth/sdpd/irmc.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/irmc_command.c b/usr.sbin/bluetooth/sdpd/irmc_command.c
index 10dafe0..a55e133 100644
--- a/usr.sbin/bluetooth/sdpd/irmc_command.c
+++ b/usr.sbin/bluetooth/sdpd/irmc_command.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/lan.c b/usr.sbin/bluetooth/sdpd/lan.c
index 2425a89..3ed2b12 100644
--- a/usr.sbin/bluetooth/sdpd/lan.c
+++ b/usr.sbin/bluetooth/sdpd/lan.c
@@ -31,6 +31,7 @@
#include <arpa/inet.h>
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <stdio.h>
diff --git a/usr.sbin/bluetooth/sdpd/main.c b/usr.sbin/bluetooth/sdpd/main.c
index 1df3bf0..a287b9b 100644
--- a/usr.sbin/bluetooth/sdpd/main.c
+++ b/usr.sbin/bluetooth/sdpd/main.c
@@ -30,6 +30,7 @@
*/
#include <sys/select.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <grp.h>
diff --git a/usr.sbin/bluetooth/sdpd/nap.c b/usr.sbin/bluetooth/sdpd/nap.c
index 5a857d8..c034ee6 100644
--- a/usr.sbin/bluetooth/sdpd/nap.c
+++ b/usr.sbin/bluetooth/sdpd/nap.c
@@ -32,6 +32,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/opush.c b/usr.sbin/bluetooth/sdpd/opush.c
index 36359da..bcdfda2 100644
--- a/usr.sbin/bluetooth/sdpd/opush.c
+++ b/usr.sbin/bluetooth/sdpd/opush.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/panu.c b/usr.sbin/bluetooth/sdpd/panu.c
index e00f650..5b2773e 100644
--- a/usr.sbin/bluetooth/sdpd/panu.c
+++ b/usr.sbin/bluetooth/sdpd/panu.c
@@ -32,6 +32,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/profile.c b/usr.sbin/bluetooth/sdpd/profile.c
index f3dfaa7..5c25d03 100644
--- a/usr.sbin/bluetooth/sdpd/profile.c
+++ b/usr.sbin/bluetooth/sdpd/profile.c
@@ -32,6 +32,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/provider.c b/usr.sbin/bluetooth/sdpd/provider.c
index b0f5347..0243305 100644
--- a/usr.sbin/bluetooth/sdpd/provider.c
+++ b/usr.sbin/bluetooth/sdpd/provider.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <string.h>
#include <stdlib.h>
diff --git a/usr.sbin/bluetooth/sdpd/sar.c b/usr.sbin/bluetooth/sdpd/sar.c
index 4fc25d9..705f716 100644
--- a/usr.sbin/bluetooth/sdpd/sar.c
+++ b/usr.sbin/bluetooth/sdpd/sar.c
@@ -34,6 +34,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
diff --git a/usr.sbin/bluetooth/sdpd/scr.c b/usr.sbin/bluetooth/sdpd/scr.c
index d0c9ec5..1df72d1 100644
--- a/usr.sbin/bluetooth/sdpd/scr.c
+++ b/usr.sbin/bluetooth/sdpd/scr.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
diff --git a/usr.sbin/bluetooth/sdpd/sd.c b/usr.sbin/bluetooth/sdpd/sd.c
index 1743ea7..c5397ce 100644
--- a/usr.sbin/bluetooth/sdpd/sd.c
+++ b/usr.sbin/bluetooth/sdpd/sd.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/server.c b/usr.sbin/bluetooth/sdpd/server.c
index 4ef153b..abd1815 100644
--- a/usr.sbin/bluetooth/sdpd/server.c
+++ b/usr.sbin/bluetooth/sdpd/server.c
@@ -38,6 +38,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <pwd.h>
diff --git a/usr.sbin/bluetooth/sdpd/sp.c b/usr.sbin/bluetooth/sdpd/sp.c
index 31a9585a..48edc77 100644
--- a/usr.sbin/bluetooth/sdpd/sp.c
+++ b/usr.sbin/bluetooth/sdpd/sp.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/srr.c b/usr.sbin/bluetooth/sdpd/srr.c
index fd636d5..60f48ca 100644
--- a/usr.sbin/bluetooth/sdpd/srr.c
+++ b/usr.sbin/bluetooth/sdpd/srr.c
@@ -34,6 +34,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
diff --git a/usr.sbin/bluetooth/sdpd/ssar.c b/usr.sbin/bluetooth/sdpd/ssar.c
index eac9235..5e52e80 100644
--- a/usr.sbin/bluetooth/sdpd/ssar.c
+++ b/usr.sbin/bluetooth/sdpd/ssar.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
diff --git a/usr.sbin/bluetooth/sdpd/ssr.c b/usr.sbin/bluetooth/sdpd/ssr.c
index ac27548..785c8ca 100644
--- a/usr.sbin/bluetooth/sdpd/ssr.c
+++ b/usr.sbin/bluetooth/sdpd/ssr.c
@@ -34,6 +34,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
diff --git a/usr.sbin/bluetooth/sdpd/sur.c b/usr.sbin/bluetooth/sdpd/sur.c
index 143eaf3..581b593 100644
--- a/usr.sbin/bluetooth/sdpd/sur.c
+++ b/usr.sbin/bluetooth/sdpd/sur.c
@@ -30,6 +30,7 @@
*/
#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
diff --git a/usr.sbin/bluetooth/sdpd/uuid.c b/usr.sbin/bluetooth/sdpd/uuid.c
index 1989bc5..dff8d2c 100644
--- a/usr.sbin/bluetooth/sdpd/uuid.c
+++ b/usr.sbin/bluetooth/sdpd/uuid.c
@@ -28,7 +28,7 @@
* $Id: uuid.c,v 1.1 2004/12/09 18:20:26 max Exp $
* $FreeBSD$
*/
-
+#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
#include <sdp.h>
#include <uuid.h>
diff --git a/usr.sbin/bsdinstall/scripts/zfsboot b/usr.sbin/bsdinstall/scripts/zfsboot
index edd9f59..eb90b8c 100755
--- a/usr.sbin/bsdinstall/scripts/zfsboot
+++ b/usr.sbin/bsdinstall/scripts/zfsboot
@@ -1128,6 +1128,9 @@ zfs_create_boot()
f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
/dev/random "$bootpool/$zroot_key" \
"bs=4096 count=1" || return $FAILURE
+ f_eval_catch $funcname chmod "$CHMOD_MODE" \
+ go-wrx "$bootpool/$zroot_key" ||
+ return $FAILURE
else
# Clean up
f_eval_catch $funcname zfs "$ZFS_UNMOUNT" \
@@ -1343,6 +1346,9 @@ zfs_create_boot()
$BSDINSTALL_TMPBOOT/loader.conf.aesni || return $FAILURE
f_eval_catch $funcname echo "$ECHO_APPEND" 'geom_eli_load=\"YES\"' \
$BSDINSTALL_TMPBOOT/loader.conf.geli || return $FAILURE
+ f_eval_catch $funcname echo "$ECHO_APPEND" \
+ 'geom_eli_passphrase_prompt=\"YES\"' \
+ $BSDINSTALL_TMPBOOT/loader.conf.geli || return $FAILURE
for disk in $disks; do
f_eval_catch $funcname printf "$PRINTF_CONF" \
geli_%s_keyfile0_load "$disk$targetpart YES" \
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/Makefile b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile
index 49afd94..f63975b 100644
--- a/usr.sbin/bsnmpd/tools/bsnmptools/Makefile
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile
@@ -10,10 +10,6 @@ PROG= bsnmpget
LIBADD= bsnmp bsnmptools
CFLAGS+= -I${.CURDIR}/../libbsnmptools
-.if ${MK_OPENSSL} != "no"
-LIBADD+= crypto
-.endif
-
LINKS= ${BINDIR}/bsnmpget ${BINDIR}/bsnmpwalk
LINKS+= ${BINDIR}/bsnmpget ${BINDIR}/bsnmpset
diff --git a/usr.sbin/chown/chgrp.1 b/usr.sbin/chown/chgrp.1
index 8a4c271..6fb0a31 100644
--- a/usr.sbin/chown/chgrp.1
+++ b/usr.sbin/chown/chgrp.1
@@ -31,7 +31,7 @@
.\" @(#)chgrp.1 8.3 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd February 21, 2010
+.Dd April 20, 2015
.Dt CHGRP 1
.Os
.Sh NAME
@@ -60,8 +60,9 @@ The following options are available:
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during traversal are not followed.)
.It Fl L
If the
.Fl R
@@ -72,8 +73,12 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the group ID for the file hierarchies rooted
-in the files instead of just the files themselves.
+Change the group ID of the file hierarchies rooted in the files,
+instead of just the files themselves.
+Beware of unintentionally matching the
+.Dq Pa ".."
+hard link to the parent directory when using wildcards like
+.Dq Li ".*" .
.It Fl f
The force option ignores errors, except for usage errors and does not
query about strange modes (unless the user does not have proper permissions).
diff --git a/usr.sbin/chown/chown.8 b/usr.sbin/chown/chown.8
index b5882a3..6b82728 100644
--- a/usr.sbin/chown/chown.8
+++ b/usr.sbin/chown/chown.8
@@ -28,7 +28,7 @@
.\" @(#)chown.8 8.3 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd February 21, 2010
+.Dd April 20, 2015
.Dt CHOWN 8
.Os
.Sh NAME
@@ -64,8 +64,9 @@ The options are as follows:
.It Fl H
If the
.Fl R
-option is specified, symbolic links on the command line are followed.
-(Symbolic links encountered in the tree traversal are not followed.)
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during traversal are not followed.)
.It Fl L
If the
.Fl R
@@ -76,8 +77,8 @@ If the
option is specified, no symbolic links are followed.
This is the default.
.It Fl R
-Change the user ID and/or the group ID of the specified directory trees
-(recursively, including their contents) and files.
+Change the user ID and/or the group ID of the file hierarchies rooted
+in the files, instead of just the files themselves.
Beware of unintentionally matching the
.Dq Pa ".."
hard link to the parent directory when using wildcards like
diff --git a/usr.sbin/chown/chown.c b/usr.sbin/chown/chown.c
index 9780f02..457068a 100644
--- a/usr.sbin/chown/chown.c
+++ b/usr.sbin/chown/chown.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <fts.h>
#include <grp.h>
#include <libgen.h>
@@ -119,18 +120,24 @@ main(int argc, char **argv)
usage();
if (Rflag) {
- fts_options = FTS_PHYSICAL;
if (hflag && (Hflag || Lflag))
errx(1, "the -R%c and -h options may not be "
"specified together", Hflag ? 'H' : 'L');
- if (Hflag)
- fts_options |= FTS_COMFOLLOW;
- else if (Lflag) {
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
+ if (Lflag) {
+ fts_options = FTS_LOGICAL;
+ } else {
+ fts_options = FTS_PHYSICAL;
+
+ if (Hflag) {
+ fts_options |= FTS_COMFOLLOW;
+ }
}
- } else
- fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+ } else if (hflag) {
+ fts_options = FTS_PHYSICAL;
+ } else {
+ fts_options = FTS_LOGICAL;
+ }
+
if (xflag)
fts_options |= FTS_XDEV;
@@ -156,6 +163,15 @@ main(int argc, char **argv)
err(1, NULL);
for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ int atflag;
+
+ if ((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) &&
+ p->fts_level == FTS_ROOTLEVEL))
+ atflag = 0;
+ else
+ atflag = AT_SYMLINK_NOFOLLOW;
+
switch (p->fts_info) {
case FTS_D: /* Change it at FTS_DP. */
if (!Rflag)
@@ -170,58 +186,44 @@ main(int argc, char **argv)
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
continue;
- case FTS_SL:
- case FTS_SLNONE:
- /*
- * The only symlinks that end up here are ones that
- * don't point to anything and ones that we found
- * doing a physical walk.
- */
- if (hflag)
- break;
- else
- continue;
default:
break;
}
if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) &&
(gid == (gid_t)-1 || gid == p->fts_statp->st_gid))
continue;
- if ((hflag ? lchown : chown)(p->fts_accpath, uid, gid) == -1) {
- if (!fflag) {
- chownerr(p->fts_path);
- rval = 1;
- }
- } else {
- if (vflag) {
- printf("%s", p->fts_path);
- if (vflag > 1) {
- if (ischown) {
- printf(": %ju:%ju -> %ju:%ju",
- (uintmax_t)
- p->fts_statp->st_uid,
- (uintmax_t)
- p->fts_statp->st_gid,
- (uid == (uid_t)-1) ?
- (uintmax_t)
- p->fts_statp->st_uid :
- (uintmax_t)uid,
- (gid == (gid_t)-1) ?
- (uintmax_t)
- p->fts_statp->st_gid :
- (uintmax_t)gid);
- } else {
- printf(": %ju -> %ju",
- (uintmax_t)
- p->fts_statp->st_gid,
- (gid == (gid_t)-1) ?
- (uintmax_t)
- p->fts_statp->st_gid :
- (uintmax_t)gid);
- }
+ if (fchownat(AT_FDCWD, p->fts_accpath, uid, gid, atflag)
+ == -1 && !fflag) {
+ chownerr(p->fts_path);
+ rval = 1;
+ } else if (vflag) {
+ printf("%s", p->fts_path);
+ if (vflag > 1) {
+ if (ischown) {
+ printf(": %ju:%ju -> %ju:%ju",
+ (uintmax_t)
+ p->fts_statp->st_uid,
+ (uintmax_t)
+ p->fts_statp->st_gid,
+ (uid == (uid_t)-1) ?
+ (uintmax_t)
+ p->fts_statp->st_uid :
+ (uintmax_t)uid,
+ (gid == (gid_t)-1) ?
+ (uintmax_t)
+ p->fts_statp->st_gid :
+ (uintmax_t)gid);
+ } else {
+ printf(": %ju -> %ju",
+ (uintmax_t)
+ p->fts_statp->st_gid,
+ (gid == (gid_t)-1) ?
+ (uintmax_t)
+ p->fts_statp->st_gid :
+ (uintmax_t)gid);
}
- printf("\n");
}
+ printf("\n");
}
}
if (errno)
diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c
index 8875142..f2d2a70 100644
--- a/usr.sbin/config/main.c
+++ b/usr.sbin/config/main.c
@@ -686,7 +686,7 @@ kernconfdump(const char *file)
{
struct stat st;
FILE *fp, *pp;
- int error, len, osz, r;
+ int error, osz, r;
unsigned int i, off, size, t1, t2, align;
char *cmd, *o;
@@ -714,7 +714,7 @@ kernconfdump(const char *file)
if (pp == NULL)
errx(EXIT_FAILURE, "popen() failed");
free(cmd);
- len = fread(o, osz, 1, pp);
+ fread(o, osz, 1, pp);
pclose(pp);
r = sscanf(o, "%d%d%d%d%d", &off, &size, &t1, &t2, &align);
free(o);
diff --git a/usr.sbin/crashinfo/crashinfo.sh b/usr.sbin/crashinfo/crashinfo.sh
index 557d810..3a55e5d 100755
--- a/usr.sbin/crashinfo/crashinfo.sh
+++ b/usr.sbin/crashinfo/crashinfo.sh
@@ -268,12 +268,6 @@ netstat -M $VMCORE -N $KERNEL -m
echo
echo "------------------------------------------------------------------------"
-echo "netstat -anr"
-echo
-netstat -M $VMCORE -N $KERNEL -anr
-echo
-
-echo "------------------------------------------------------------------------"
echo "netstat -anA"
echo
netstat -M $VMCORE -N $KERNEL -anA
diff --git a/usr.sbin/crunch/crunchide/Makefile b/usr.sbin/crunch/crunchide/Makefile
index fd23dec..467b0b6 100644
--- a/usr.sbin/crunch/crunchide/Makefile
+++ b/usr.sbin/crunch/crunchide/Makefile
@@ -1,24 +1,9 @@
# $FreeBSD$
PROG= crunchide
-SRCS= crunchide.c
+SRCS= crunchide.c exec_elf32.c exec_elf64.c
-TARGET_ARCH?= ${MACHINE_ARCH}
-
-.if ${TARGET_ARCH} == i386 && ${MACHINE_ARCH} == i386
-CFLAGS+=-DNLIST_AOUT
-SRCS+= exec_aout.c
-.endif
-
-.if ${TARGET_ARCH} == aarch64 || ${TARGET_ARCH} == amd64 || \
- ${TARGET_ARCH} == powerpc64 || \
- ${TARGET_ARCH} == sparc64 || ${TARGET_ARCH:Mmips64*}
-CFLAGS+=-DNLIST_ELF64
-SRCS+= exec_elf64.c
+CFLAGS+=-DNLIST_ELF32 -DNLIST_ELF64
exec_elf64.o: exec_elf32.c
-.else
-CFLAGS+=-DNLIST_ELF32
-SRCS+= exec_elf32.c
-.endif
.include <bsd.prog.mk>
diff --git a/usr.sbin/crunch/crunchide/crunchide.c b/usr.sbin/crunch/crunchide/crunchide.c
index d2b1123..8665a14 100644
--- a/usr.sbin/crunch/crunchide/crunchide.c
+++ b/usr.sbin/crunch/crunchide/crunchide.c
@@ -212,12 +212,6 @@ struct {
int (*check)(int, const char *); /* 1 if match, zero if not */
int (*hide)(int, const char *); /* non-zero if error */
} exec_formats[] = {
-#ifdef NLIST_AOUT
- { "a.out", check_aout, hide_aout, },
-#endif
-#ifdef NLIST_ECOFF
- { "ECOFF", check_elf64, hide_elf64, },
-#endif
#ifdef NLIST_ELF32
{ "ELF32", check_elf32, hide_elf32, },
#endif
diff --git a/usr.sbin/crunch/crunchide/exec_aout.c b/usr.sbin/crunch/crunchide/exec_aout.c
deleted file mode 100644
index a608c23..0000000
--- a/usr.sbin/crunch/crunchide/exec_aout.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/* $NetBSD: exec_aout.c,v 1.6 1997/08/02 21:30:17 perry Exp $ */
-/*
- * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.
- * Copyright (c) 1994 University of Maryland
- * All Rights Reserved.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of U.M. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. U.M. makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: James da Silva, Systems Design and Analysis Group
- * Computer Science Department
- * University of Maryland at College Park
- */
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: exec_aout.c,v 1.6 1997/08/02 21:30:17 perry Exp $");
-__FBSDID("$FreeBSD$");
-#endif
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <a.out.h>
-#include <sys/types.h>
-#include <sys/endian.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
-#include <netinet/in.h>
-
-#include "extern.h"
-
-#if defined(NLIST_AOUT)
-
-int nsyms, ntextrel, ndatarel;
-struct exec *hdrp;
-char *aoutdata, *strbase;
-struct relocation_info *textrel, *datarel;
-struct nlist *symbase;
-
-
-#define SYMSTR(sp) (&strbase[(sp)->n_un.n_strx])
-
-/* is the symbol a global symbol defined in the current file? */
-#define IS_GLOBAL_DEFINED(sp) \
- (((sp)->n_type & N_EXT) && ((sp)->n_type & N_TYPE) != N_UNDF)
-
-/* is the relocation entry dependent on a symbol? */
-#define IS_SYMBOL_RELOC(rp) \
- ((rp)->r_extern||(rp)->r_baserel||(rp)->r_jmptable)
-
-static void check_reloc(const char *filename, struct relocation_info *relp);
-
-int check_aout(int inf, const char *filename)
-{
- struct stat infstat;
- struct exec eh;
-
- /*
- * check the header to make sure it's an a.out-format file.
- */
-
- if(fstat(inf, &infstat) == -1)
- return 0;
- if(infstat.st_size < sizeof eh)
- return 0;
- if(read(inf, &eh, sizeof eh) != sizeof eh)
- return 0;
-
- if(N_BADMAG(eh))
- return 0;
-
- return 1;
-}
-
-int hide_aout(int inf, const char *filename)
-{
- struct stat infstat;
- struct relocation_info *relp;
- struct nlist *symp;
- int rc;
-
- /*
- * do some error checking.
- */
-
- if(fstat(inf, &infstat) == -1) {
- perror(filename);
- return 1;
- }
-
- /*
- * Read the entire file into memory. XXX - Really, we only need to
- * read the header and from TRELOFF to the end of the file.
- */
-
- if((aoutdata = (char *) malloc(infstat.st_size)) == NULL) {
- fprintf(stderr, "%s: too big to read into memory\n", filename);
- return 1;
- }
-
- if((rc = read(inf, aoutdata, infstat.st_size)) < infstat.st_size) {
- fprintf(stderr, "%s: read error: %s\n", filename,
- rc == -1? strerror(errno) : "short read");
- return 1;
- }
-
- /*
- * Calculate offsets and sizes from the header.
- */
-
- hdrp = (struct exec *) aoutdata;
-
-#ifdef __FreeBSD__
- textrel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp));
- datarel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp) +
- hdrp->a_trsize);
-#else
- textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp));
- datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp));
-#endif
- symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp));
- strbase = (char *) (aoutdata + N_STROFF(*hdrp));
-
- ntextrel = hdrp->a_trsize / sizeof(struct relocation_info);
- ndatarel = hdrp->a_drsize / sizeof(struct relocation_info);
- nsyms = hdrp->a_syms / sizeof(struct nlist);
-
- /*
- * Zap the type field of all globally-defined symbols. The linker will
- * subsequently ignore these entries. Don't zap any symbols in the
- * keep list.
- */
-
- for(symp = symbase; symp < symbase + nsyms; symp++) {
- if(!IS_GLOBAL_DEFINED(symp)) /* keep undefined syms */
- continue;
-
- /* keep (C) symbols which are on the keep list */
- if(SYMSTR(symp)[0] == '_' && in_keep_list(SYMSTR(symp) + 1))
- continue;
-
- symp->n_type = 0;
- }
-
- /*
- * Check whether the relocation entries reference any symbols that we
- * just zapped. I don't know whether ld can handle this case, but I
- * haven't encountered it yet. These checks are here so that the program
- * doesn't fail silently should such symbols be encountered.
- */
-
- for(relp = textrel; relp < textrel + ntextrel; relp++)
- check_reloc(filename, relp);
- for(relp = datarel; relp < datarel + ndatarel; relp++)
- check_reloc(filename, relp);
-
- /*
- * Write the .o file back out to disk. XXX - Really, we only need to
- * write the symbol table entries back out.
- */
- lseek(inf, 0, SEEK_SET);
- if((rc = write(inf, aoutdata, infstat.st_size)) < infstat.st_size) {
- fprintf(stderr, "%s: write error: %s\n", filename,
- rc == -1? strerror(errno) : "short write");
- return 1;
- }
-
- return 0;
-}
-
-
-static void check_reloc(const char *filename, struct relocation_info *relp)
-{
- /* bail out if we zapped a symbol that is needed */
- if(IS_SYMBOL_RELOC(relp) && symbase[relp->r_symbolnum].n_type == 0) {
- fprintf(stderr,
- "%s: oops, have hanging relocation for %s: bailing out!\n",
- filename, SYMSTR(&symbase[relp->r_symbolnum]));
- exit(1);
- }
-}
-
-#endif /* defined(NLIST_AOUT) */
diff --git a/usr.sbin/crunch/crunchide/exec_elf32.c b/usr.sbin/crunch/crunchide/exec_elf32.c
index 10e7d27..89080e9 100644
--- a/usr.sbin/crunch/crunchide/exec_elf32.c
+++ b/usr.sbin/crunch/crunchide/exec_elf32.c
@@ -79,6 +79,9 @@ __FBSDID("$FreeBSD$");
#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE))
#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
+#ifndef ELFCLASS
+#define ELFCLASS CONCAT(ELFCLASS,ELFSIZE)
+#endif
#define xe16toh(x) ((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))
#define xe32toh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
@@ -167,7 +170,7 @@ ELFNAMEEND(check)(int fd, const char *fn)
if (read(fd, &eh, sizeof eh) != sizeof eh)
return 0;
- if (IS_ELF(eh) == 0)
+ if (IS_ELF(eh) == 0 || eh.e_ident[EI_CLASS] != ELFCLASS)
return 0;
data = eh.e_ident[EI_DATA];
@@ -179,33 +182,12 @@ ELFNAMEEND(check)(int fd, const char *fn)
#define EM_AARCH64 183
#endif
case EM_AARCH64: break;
-#ifndef EM_ARM
-#define EM_ARM 40
-#endif
case EM_ARM: break;
-#ifndef EM_MIPS
-#define EM_MIPS 8
-#endif
-#ifndef EM_MIPS_RS4_BE /* same as EM_MIPS_RS3_LE */
-#define EM_MIPS_RS4_BE 10
-#endif
case EM_MIPS: break;
case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break;
-#ifndef EM_PPC
-#define EM_PPC 20
-#endif
case EM_PPC: break;
-#ifndef EM_PPC64
-#define EM_PPC64 21
-#endif
case EM_PPC64: break;
-#ifndef EM_SPARCV9
-#define EM_SPARCV9 43
-#endif
case EM_SPARCV9: break;
-#ifndef EM_X86_64
-#define EM_X86_64 62
-#endif
case EM_X86_64: break;
/* ELFDEFNNAME(MACHDEP_ID_CASES) */
@@ -342,11 +324,14 @@ ELFNAMEEND(hide)(int fd, const char *fn)
*/
/* load section string table for debug use */
- if ((shstrtabp = xmalloc(xewtoh(shstrtabshdr->sh_size), fn,
- "section string table")) == NULL)
+ if ((size = xewtoh(shstrtabshdr->sh_size)) == 0)
+ goto bad;
+ if ((shstrtabp = xmalloc(size, fn, "section string table")) == NULL)
goto bad;
if ((size_t)xreadatoff(fd, shstrtabp, xewtoh(shstrtabshdr->sh_offset),
- xewtoh(shstrtabshdr->sh_size), fn) != xewtoh(shstrtabshdr->sh_size))
+ size, fn) != size)
+ goto bad;
+ if (shstrtabp[size - 1] != '\0')
goto bad;
/* we need symtab, strtab, and everything behind strtab */
@@ -367,7 +352,8 @@ ELFNAMEEND(hide)(int fd, const char *fn)
strtabidx = i;
if (layoutp[i].shdr == symtabshdr || i >= strtabidx) {
off = xewtoh(layoutp[i].shdr->sh_offset);
- size = xewtoh(layoutp[i].shdr->sh_size);
+ if ((size = xewtoh(layoutp[i].shdr->sh_size)) == 0)
+ goto bad;
layoutp[i].bufp = xmalloc(size, fn,
shstrtabp + xewtoh(layoutp[i].shdr->sh_name));
if (layoutp[i].bufp == NULL)
@@ -377,10 +363,13 @@ ELFNAMEEND(hide)(int fd, const char *fn)
goto bad;
/* set symbol table and string table */
- if (layoutp[i].shdr == symtabshdr)
+ if (layoutp[i].shdr == symtabshdr) {
symtabp = layoutp[i].bufp;
- else if (layoutp[i].shdr == strtabshdr)
+ } else if (layoutp[i].shdr == strtabshdr) {
strtabp = layoutp[i].bufp;
+ if (strtabp[size - 1] != '\0')
+ goto bad;
+ }
}
}
diff --git a/usr.sbin/crunch/crunchide/extern.h b/usr.sbin/crunch/crunchide/extern.h
index 4200bc3..1e7809a 100644
--- a/usr.sbin/crunch/crunchide/extern.h
+++ b/usr.sbin/crunch/crunchide/extern.h
@@ -31,14 +31,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef NLIST_AOUT
-int check_aout(int, const char *);
-int hide_aout(int, const char *);
-#endif
-#ifdef NLIST_ECOFF
-int check_ecoff(int, const char *);
-int hide_ecoff(int, const char *);
-#endif
#ifdef NLIST_ELF32
int check_elf32(int, const char *);
int hide_elf32(int, const char *);
diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5
index ef21919..eb65fa1 100644
--- a/usr.sbin/ctld/ctl.conf.5
+++ b/usr.sbin/ctld/ctl.conf.5
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 4, 2015
+.Dd April 19, 2015
.Dt CTL.CONF 5
.Os
.Sh NAME
@@ -365,7 +365,12 @@ All CTL-specific options are documented in the
section of
.Xr ctladm 8 .
.It Ic path Ar path
-The path to the file or device node used to back the LUN.
+The path to the file, device node, or
+.Xr zfs 8
+volume used to back the LUN.
+For optimal performance, create the volume with the
+.Qq Ar volmode=dev
+property set.
.It Ic serial Ar string
The SCSI serial number presented to the initiator.
.It Ic size Ar size
@@ -435,7 +440,8 @@ target naa.50015178f369f092 {
.Sh SEE ALSO
.Xr ctl 4 ,
.Xr ctladm 8 ,
-.Xr ctld 8
+.Xr ctld 8 ,
+.Xr zfs 8
.Sh AUTHORS
The
.Nm
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index 2f4f147..6f0c63b 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -203,7 +203,7 @@ auth_check_secret_length(struct auth *auth)
}
if (auth->a_mutual_secret != NULL) {
- len = strlen(auth->a_secret);
+ len = strlen(auth->a_mutual_secret);
if (len > 16) {
if (auth->a_auth_group->ag_name != NULL)
log_warnx("mutual secret for user \"%s\", "
@@ -2399,8 +2399,11 @@ found:
client_fd = accept(portal->p_socket,
(struct sockaddr *)&client_sa,
&client_salen);
- if (client_fd < 0)
+ if (client_fd < 0) {
+ if (errno == ECONNABORTED)
+ continue;
log_err(1, "accept");
+ }
assert(client_salen >= client_sa.ss_len);
handle_connection(portal, client_fd,
diff --git a/usr.sbin/ctld/discovery.c b/usr.sbin/ctld/discovery.c
index 15eaa76..d7d843e 100644
--- a/usr.sbin/ctld/discovery.c
+++ b/usr.sbin/ctld/discovery.c
@@ -32,7 +32,6 @@
__FBSDID("$FreeBSD$");
#include <assert.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.sbin/ctld/isns.c b/usr.sbin/ctld/isns.c
index 11eef3e0..f7381a1 100644
--- a/usr.sbin/ctld/isns.c
+++ b/usr.sbin/ctld/isns.c
@@ -35,14 +35,8 @@ __FBSDID("$FreeBSD$");
#include <sys/endian.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
#include <netdb.h>
-#include <signal.h>
#include <stdbool.h>
-#include <stdio.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/usr.sbin/ctld/keys.c b/usr.sbin/ctld/keys.c
index c8f222d..f339a10 100644
--- a/usr.sbin/ctld/keys.c
+++ b/usr.sbin/ctld/keys.c
@@ -32,7 +32,6 @@
__FBSDID("$FreeBSD$");
#include <assert.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c
index 9f9ef3c..c6b83d9 100644
--- a/usr.sbin/ctld/login.c
+++ b/usr.sbin/ctld/login.c
@@ -33,8 +33,6 @@ __FBSDID("$FreeBSD$");
#include <assert.h>
#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -802,9 +800,6 @@ login(struct connection *conn)
}
conn->conn_initiator_name = checked_strdup(initiator_name);
log_set_peer_name(conn->conn_initiator_name);
- /*
- * XXX: This doesn't work (does nothing) because of Capsicum.
- */
setproctitle("%s (%s)", conn->conn_initiator_addr, conn->conn_initiator_name);
redirected = login_portal_redirect(conn, request);
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
index 76873d4..cfc202c 100644
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -35,7 +35,6 @@
#include <sys/stat.h>
#include <assert.h>
#include <stdio.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.sbin/ctld/pdu.c b/usr.sbin/ctld/pdu.c
index c3181ac..be3598e 100644
--- a/usr.sbin/ctld/pdu.c
+++ b/usr.sbin/ctld/pdu.c
@@ -34,8 +34,6 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l
index f0cb597..54b803b 100644
--- a/usr.sbin/ctld/token.l
+++ b/usr.sbin/ctld/token.l
@@ -34,7 +34,6 @@
#include <stdint.h>
#include <string.h>
-#include "ctld.h"
#include "y.tab.h"
int lineno;
diff --git a/usr.sbin/etcupdate/etcupdate.8 b/usr.sbin/etcupdate/etcupdate.8
index 1966179..c5a74f3 100644
--- a/usr.sbin/etcupdate/etcupdate.8
+++ b/usr.sbin/etcupdate/etcupdate.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2010-2013 Advanced Computing Technologies LLC
+.\" Copyright (c) 2010-2013 Hudson River Trading LLC
.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
.\" All rights reserved.
.\"
diff --git a/usr.sbin/etcupdate/etcupdate.sh b/usr.sbin/etcupdate/etcupdate.sh
index a4728fa..6be57b6 100755
--- a/usr.sbin/etcupdate/etcupdate.sh
+++ b/usr.sbin/etcupdate/etcupdate.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2010-2013 Advanced Computing Technologies LLC
+# Copyright (c) 2010-2013 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/etcupdate/tests/always_test.sh b/usr.sbin/etcupdate/tests/always_test.sh
index 514481e..2055bb6 100644
--- a/usr.sbin/etcupdate/tests/always_test.sh
+++ b/usr.sbin/etcupdate/tests/always_test.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2010 Advanced Computing Technologies LLC
+# Copyright (c) 2010 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/etcupdate/tests/conflicts_test.sh b/usr.sbin/etcupdate/tests/conflicts_test.sh
index 816c180..71f16fa 100644
--- a/usr.sbin/etcupdate/tests/conflicts_test.sh
+++ b/usr.sbin/etcupdate/tests/conflicts_test.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2010 Advanced Computing Technologies LLC
+# Copyright (c) 2010 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/etcupdate/tests/fbsdid_test.sh b/usr.sbin/etcupdate/tests/fbsdid_test.sh
index c062c06..d8d5cce 100644
--- a/usr.sbin/etcupdate/tests/fbsdid_test.sh
+++ b/usr.sbin/etcupdate/tests/fbsdid_test.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2010 Advanced Computing Technologies LLC
+# Copyright (c) 2010 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/etcupdate/tests/ignore_test.sh b/usr.sbin/etcupdate/tests/ignore_test.sh
index 2d3d2f5..571dd24 100644
--- a/usr.sbin/etcupdate/tests/ignore_test.sh
+++ b/usr.sbin/etcupdate/tests/ignore_test.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2010 Advanced Computing Technologies LLC
+# Copyright (c) 2010 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/etcupdate/tests/preworld_test.sh b/usr.sbin/etcupdate/tests/preworld_test.sh
index c731293..b724154 100644
--- a/usr.sbin/etcupdate/tests/preworld_test.sh
+++ b/usr.sbin/etcupdate/tests/preworld_test.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2013 Advanced Computing Technologies LLC
+# Copyright (c) 2013 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/etcupdate/tests/tests_test.sh b/usr.sbin/etcupdate/tests/tests_test.sh
index b99bbef..5382de3 100644
--- a/usr.sbin/etcupdate/tests/tests_test.sh
+++ b/usr.sbin/etcupdate/tests/tests_test.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2010 Advanced Computing Technologies LLC
+# Copyright (c) 2010 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/etcupdate/tests/tzsetup_test.sh b/usr.sbin/etcupdate/tests/tzsetup_test.sh
index b102938..dbdcc0e 100644
--- a/usr.sbin/etcupdate/tests/tzsetup_test.sh
+++ b/usr.sbin/etcupdate/tests/tzsetup_test.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2013 Advanced Computing Technologies LLC
+# Copyright (c) 2013 Hudson River Trading LLC
# Written by: John H. Baldwin <jhb@FreeBSD.org>
# All rights reserved.
#
diff --git a/usr.sbin/fifolog/fifolog_reader/Makefile b/usr.sbin/fifolog/fifolog_reader/Makefile
index 19ce281..ae5f9e7 100644
--- a/usr.sbin/fifolog/fifolog_reader/Makefile
+++ b/usr.sbin/fifolog/fifolog_reader/Makefile
@@ -6,7 +6,7 @@ CFLAGS+= -I${.CURDIR}/../lib
MAN=
-LIBADD= z fifolog
+LIBADD= fifolog
regress:
./${PROG} /tmp/fifolog.0
diff --git a/usr.sbin/fifolog/fifolog_writer/Makefile b/usr.sbin/fifolog/fifolog_writer/Makefile
index 3e5e6cc..7a9316d 100644
--- a/usr.sbin/fifolog/fifolog_writer/Makefile
+++ b/usr.sbin/fifolog/fifolog_writer/Makefile
@@ -6,7 +6,7 @@ CFLAGS+= -I${.CURDIR}/../lib
MAN=
-LIBADD= z fifolog
+LIBADD= fifolog
regress:
date | ./${PROG} -z 0 /tmp/fifolog.0
diff --git a/usr.sbin/freebsd-update/freebsd-update.sh b/usr.sbin/freebsd-update/freebsd-update.sh
index 2434929..fda1d90 100644
--- a/usr.sbin/freebsd-update/freebsd-update.sh
+++ b/usr.sbin/freebsd-update/freebsd-update.sh
@@ -690,7 +690,7 @@ fetch_check_params () {
fi
# Check that we have updates ready to install
- if [ -f ${BDHASH}-install/kerneldone && $FORCEFETCH -eq 0 ]; then
+ if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then
echo "You have a partially completed upgrade pending"
echo "Run '$0 install' first."
echo "Run '$0 fetch -F' to proceed anyway."
@@ -3220,7 +3220,7 @@ get_params () {
# Fetch command. Make sure that we're being called
# interactively, then run fetch_check_params and fetch_run
cmd_fetch () {
- if [ ! -t 0 && $NOTTYOK -eq 0 ]; then
+ if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then
echo -n "`basename $0` fetch should not "
echo "be run non-interactively."
echo "Run `basename $0` cron instead."
diff --git a/usr.sbin/ifmcstat/ifmcstat.c b/usr.sbin/ifmcstat/ifmcstat.c
index d3798e3..4f3f444 100644
--- a/usr.sbin/ifmcstat/ifmcstat.c
+++ b/usr.sbin/ifmcstat/ifmcstat.c
@@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$");
#include <sys/tree.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/route.h>
diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c
index c48f33c..178cb58 100644
--- a/usr.sbin/inetd/inetd.c
+++ b/usr.sbin/inetd/inetd.c
@@ -1752,10 +1752,10 @@ more:
memmove(sep->se_proto, sep->se_proto + 4,
strlen(sep->se_proto) + 1 - 4);
sep->se_rpc = 1;
- sep->se_rpc_prog = sep->se_rpc_lowvers =
- sep->se_rpc_lowvers = 0;
memcpy(&sep->se_ctrladdr4, bind_sa4,
- sizeof(sep->se_ctrladdr4));
+ sizeof(sep->se_ctrladdr4));
+ sep->se_rpc_prog = sep->se_rpc_lowvers =
+ sep->se_rpc_highvers = 0;
if ((versp = strrchr(sep->se_service, '/'))) {
*versp++ = '\0';
switch (sscanf(versp, "%u-%u",
diff --git a/usr.sbin/iovctl/iovctl.c b/usr.sbin/iovctl/iovctl.c
index faa9586..dbf29d8 100644
--- a/usr.sbin/iovctl/iovctl.c
+++ b/usr.sbin/iovctl/iovctl.c
@@ -80,7 +80,7 @@ get_schema(int fd)
err(1, "Could not fetch config schema");
}
- schema = nvlist_unpack(arg.schema, arg.len);
+ schema = nvlist_unpack(arg.schema, arg.len, NV_FLAG_IGNORE_CASE);
if (schema == NULL)
err(1, "Could not unpack schema");
diff --git a/usr.sbin/iovctl/iovctl.conf.5 b/usr.sbin/iovctl/iovctl.conf.5
index b46a409..f7a6052 100644
--- a/usr.sbin/iovctl/iovctl.conf.5
+++ b/usr.sbin/iovctl/iovctl.conf.5
@@ -144,7 +144,7 @@ passthrough devices through the use of the default section.
VF-0 is not configured as a passthrough device as it explicitly overrides the
default.
VF-0 also sets a device-specific parameter named mac-addr.
-.Bd -literal .offset ident
+.Bd -literal -offset ident
PF {
device : "ix0";
num_vfs : 3;
@@ -160,8 +160,8 @@ VF-0 {
}
.Ed
.Sh SEE ALSO
-.Xr iovctl 8 ,
-.Xr rc.conf 5
+.Xr rc.conf 5 ,
+.Xr iovctl 8
.Sh AUTHORS
This manual page was written by
.An Ryan Stone Aq Mt rstone@FreeBSD.org .
diff --git a/usr.sbin/ip6addrctl/ip6addrctl.c b/usr.sbin/ip6addrctl/ip6addrctl.c
index 6a730ff..d9bf89d 100644
--- a/usr.sbin/ip6addrctl/ip6addrctl.c
+++ b/usr.sbin/ip6addrctl/ip6addrctl.c
@@ -39,7 +39,6 @@
#include <sys/sysctl.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>
diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8
index 8952ae3..189fa36 100644
--- a/usr.sbin/jail/jail.8
+++ b/usr.sbin/jail/jail.8
@@ -1221,7 +1221,6 @@ environment of the first jail.
.Xr jls 8 ,
.Xr mount 8 ,
.Xr named 8 ,
-.Xr procfs 5 ,
.Xr reboot 8 ,
.Xr rpcbind 8 ,
.Xr sendmail 8 ,
diff --git a/usr.sbin/mld6query/mld6.c b/usr.sbin/mld6query/mld6.c
index 53f38ae..a3c8342 100644
--- a/usr.sbin/mld6query/mld6.c
+++ b/usr.sbin/mld6query/mld6.c
@@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
#include <signal.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
diff --git a/usr.sbin/mountd/mountd.8 b/usr.sbin/mountd/mountd.8
index fe73743..4dbf5ff 100644
--- a/usr.sbin/mountd/mountd.8
+++ b/usr.sbin/mountd/mountd.8
@@ -38,7 +38,7 @@
mount requests
.Sh SYNOPSIS
.Nm
-.Op Fl 2delnorS
+.Op Fl 2delnrS
.Op Fl h Ar bindip
.Op Fl p Ar port
.Op Ar exportsfile ...
@@ -69,8 +69,7 @@ Output debugging information.
will not detach from the controlling terminal and will print
debugging messages to stderr.
.It Fl e
-The new NFS server that includes NFSv4 support is now the default, so this
-option is now a no-op and should be considered deprecated.
+Ignored; included for backward compatibility.
.It Fl h Ar bindip
Specify specific IP addresses to bind to for TCP and UDP requests.
This option may be specified multiple times.
@@ -98,9 +97,6 @@ This should only be specified if there are clients such as PC's,
that require it.
It will automatically clear the vfs.nfsrv.nfs_privport sysctl flag, which
controls if the kernel will accept NFS requests from reserved ports only.
-.It Fl o
-This flag forces the system to run the old NFS server, which does not
-have NFSv4 support in it.
.It Fl p Ar port
Force
.Nm
diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
index ad1964e..3508f50 100644
--- a/usr.sbin/mountd/mountd.c
+++ b/usr.sbin/mountd/mountd.c
@@ -253,7 +253,6 @@ static int have_v6 = 1;
int v4root_phase = 0;
char v4root_dirpath[PATH_MAX + 1];
-int run_v4server = 1;
int has_publicfh = 0;
struct pidfh *pfh = NULL;
@@ -312,7 +311,7 @@ main(int argc, char **argv)
else
close(s);
- while ((c = getopt(argc, argv, "2deh:lnop:rS")) != -1)
+ while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1)
switch (c) {
case '2':
force_v2 = 1;
@@ -332,9 +331,6 @@ main(int argc, char **argv)
case 'l':
dolog = 1;
break;
- case 'o':
- run_v4server = 0;
- break;
case 'p':
endptr = NULL;
svcport = (in_port_t)strtoul(optarg, &endptr, 10);
@@ -371,19 +367,9 @@ main(int argc, char **argv)
usage();
};
- /*
- * Unless the "-o" option was specified, try and run "nfsd".
- * If "-o" was specified, try and run "nfsserver".
- */
- if (run_v4server > 0) {
- if (modfind("nfsd") < 0) {
- /* Not present in kernel, try loading it */
- if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
- errx(1, "NFS server is not available");
- }
- } else if (modfind("nfsserver") < 0) {
+ if (modfind("nfsd") < 0) {
/* Not present in kernel, try loading it */
- if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
+ if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
errx(1, "NFS server is not available");
}
@@ -1697,8 +1683,7 @@ get_exportlist(void)
*/
bzero(&eargs, sizeof (eargs));
eargs.export.ex_flags = MNT_DELEXPORT;
- if (run_v4server > 0 &&
- nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 &&
+ if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 &&
errno != ENOENT)
syslog(LOG_ERR, "Can't delete exports for V4:");
@@ -1732,6 +1717,12 @@ get_exportlist(void)
}
/*
+ * We do not need to delete "export" flag from
+ * filesystems that do not have it set.
+ */
+ if (!(fsp->f_flags & MNT_EXPORTED))
+ continue;
+ /*
* Do not delete export for network filesystem by
* passing "export" arg to nmount().
* It only makes sense to do this for local filesystems.
@@ -1797,7 +1788,7 @@ get_exportlist(void)
/*
* If there was no public fh, clear any previous one set.
*/
- if (run_v4server > 0 && has_publicfh == 0)
+ if (has_publicfh == 0)
(void) nfssvc(NFSSVC_NOPUBLICFH, NULL);
/* Resume the nfsd. If they weren't suspended, this is harmless. */
@@ -2394,7 +2385,7 @@ do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
{
struct statfs fsb1;
struct addrinfo *ai;
- struct export_args ea, *eap;
+ struct export_args *eap;
char errmsg[255];
char *cp;
int done;
@@ -2404,10 +2395,7 @@ do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
int ret;
struct nfsex_args nfsea;
- if (run_v4server > 0)
- eap = &nfsea.export;
- else
- eap = &ea;
+ eap = &nfsea.export;
cp = NULL;
savedc = '\0';
@@ -2487,8 +2475,7 @@ do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
*/
if (v4root_phase == 2) {
nfsea.fspec = v4root_dirpath;
- if (run_v4server > 0 &&
- nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) {
+ if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) {
syslog(LOG_ERR, "Exporting V4: failed");
return (2);
}
@@ -2577,7 +2564,7 @@ do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
* If this is the public directory, get the file handle
* and load it into the kernel via the nfssvc() syscall.
*/
- if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) {
+ if ((exflags & MNT_EXPUBLIC) != 0) {
fhandle_t fh;
char *public_name;
diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c
index e896010..339a4b6 100644
--- a/usr.sbin/ndp/ndp.c
+++ b/usr.sbin/ndp/ndp.c
@@ -83,7 +83,6 @@
#include <sys/queue.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
diff --git a/usr.sbin/nfsd/nfsd.8 b/usr.sbin/nfsd/nfsd.8
index 157fc52..d014a01 100644
--- a/usr.sbin/nfsd/nfsd.8
+++ b/usr.sbin/nfsd/nfsd.8
@@ -28,7 +28,7 @@
.\" @(#)nfsd.8 8.4 (Berkeley) 3/29/95
.\" $FreeBSD$
.\"
-.Dd January 1, 2015
+.Dd April 25, 2015
.Dt NFSD 8
.Os
.Sh NAME
@@ -38,7 +38,7 @@
server
.Sh SYNOPSIS
.Nm
-.Op Fl arduteo
+.Op Fl ardute
.Op Fl n Ar num_servers
.Op Fl h Ar bindip
.Op Fl Fl maxthreads Ar max_threads
@@ -112,11 +112,7 @@ Serve
.Tn UDP NFS
clients.
.It Fl e
-The new NFS server that includes NFSv4 support is now the default, so this
-option is now a no-op and should be considered deprecated.
-.It Fl o
-Forces the use of the old NFS server that does not include NFSv4 support
-in it.
+Ignored; included for backward compatibility.
.El
.Pp
For example,
diff --git a/usr.sbin/nfsd/nfsd.c b/usr.sbin/nfsd/nfsd.c
index b114ba6..f58ed30 100644
--- a/usr.sbin/nfsd/nfsd.c
+++ b/usr.sbin/nfsd/nfsd.c
@@ -87,8 +87,6 @@ static int nfsdcnt; /* number of children */
static int nfsdcnt_set;
static int minthreads;
static int maxthreads;
-static int new_syscall;
-static int run_v4server = 1; /* Force running of nfsv4 server */
static int nfssvc_nfsd; /* Set to correct NFSSVC_xxx flag */
static int stablefd = -1; /* Fd for the stable restart file */
static int backupfd; /* Fd for the backup stable restart file */
@@ -156,7 +154,7 @@ main(int argc, char **argv)
socklen_t len;
int on = 1, unregister, reregister, sock;
int tcp6sock, ip6flag, tcpflag, tcpsock;
- int udpflag, ecode, error, s, srvcnt;
+ int udpflag, ecode, error, s;
int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
int nfssvc_addsock;
int longindex = 0;
@@ -167,10 +165,10 @@ main(int argc, char **argv)
nfsdcnt = DEFNFSDCNT;
unregister = reregister = tcpflag = maxsock = 0;
bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
- getopt_shortopts = "ah:n:rdtueo";
+ getopt_shortopts = "ah:n:rdtue";
getopt_usage =
"usage:\n"
- " nfsd [-ardtueo] [-h bindip]\n"
+ " nfsd [-ardtue] [-h bindip]\n"
" [-n numservers] [--minthreads #] [--maxthreads #]\n";
while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts,
&longindex)) != -1)
@@ -205,9 +203,6 @@ main(int argc, char **argv)
case 'e':
/* now a no-op, since this is the default */
break;
- case 'o':
- run_v4server = 0;
- break;
case 0:
lopt = longopts[longindex].name;
if (!strcmp(lopt, "minthreads")) {
@@ -242,15 +237,9 @@ main(int argc, char **argv)
* Unless the "-o" option was specified, try and run "nfsd".
* If "-o" was specified, try and run "nfsserver".
*/
- if (run_v4server > 0) {
- if (modfind("nfsd") < 0) {
- /* Not present in kernel, try loading it */
- if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
- errx(1, "NFS server is not available");
- }
- } else if (modfind("nfsserver") < 0) {
+ if (modfind("nfsd") < 0) {
/* Not present in kernel, try loading it */
- if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
+ if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
errx(1, "NFS server is not available");
}
@@ -392,55 +381,21 @@ main(int argc, char **argv)
* level write-back caching. (See SCSI doc for more information
* on how to prevent write-back caching on SCSI disks.)
*/
- if (run_v4server > 0) {
- open_stable(&stablefd, &backupfd);
- if (stablefd < 0) {
- syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART);
- exit(1);
- }
- /* This system call will fail for old kernels, but that's ok. */
- nfssvc(NFSSVC_BACKUPSTABLE, NULL);
- if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) {
- syslog(LOG_ERR, "Can't read stable storage file: %m\n");
- exit(1);
- }
- nfssvc_addsock = NFSSVC_NFSDADDSOCK;
- nfssvc_nfsd = NFSSVC_NFSDNFSD;
- new_syscall = TRUE;
- } else {
- nfssvc_addsock = NFSSVC_ADDSOCK;
- nfssvc_nfsd = NFSSVC_NFSD;
- /*
- * Figure out if the kernel supports the new-style
- * NFSSVC_NFSD. Old kernels will return ENXIO because they
- * don't recognise the flag value, new ones will return EINVAL
- * because argp is NULL.
- */
- new_syscall = FALSE;
- if (nfssvc(NFSSVC_NFSD, NULL) < 0 && errno == EINVAL)
- new_syscall = TRUE;
+ open_stable(&stablefd, &backupfd);
+ if (stablefd < 0) {
+ syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART);
+ exit(1);
}
+ /* This system call will fail for old kernels, but that's ok. */
+ nfssvc(NFSSVC_BACKUPSTABLE, NULL);
+ if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) {
+ syslog(LOG_ERR, "Can't read stable storage file: %m\n");
+ exit(1);
+ }
+ nfssvc_addsock = NFSSVC_NFSDADDSOCK;
+ nfssvc_nfsd = NFSSVC_NFSDNFSD;
- if (!new_syscall) {
- /* If we use UDP only, we start the last server below. */
- srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
- for (i = 0; i < srvcnt; i++) {
- switch ((pid = fork())) {
- case -1:
- syslog(LOG_ERR, "fork: %m");
- nfsd_exit(1);
- case 0:
- break;
- default:
- children[i] = pid;
- continue;
- }
- (void)signal(SIGUSR1, child_cleanup);
- setproctitle("server");
-
- start_server(0);
- }
- } else if (tcpflag) {
+ if (tcpflag) {
/*
* For TCP mode, we fork once to start the first
* kernel nfsd thread. The kernel will add more
@@ -626,7 +581,7 @@ main(int argc, char **argv)
bindhost[i]);
nfsd_exit(1);
}
- if (listen(tcpsock, 5) < 0) {
+ if (listen(tcpsock, -1) < 0) {
syslog(LOG_ERR, "listen failed");
nfsd_exit(1);
}
@@ -701,7 +656,7 @@ main(int argc, char **argv)
bindhost[i]);
nfsd_exit(1);
}
- if (listen(tcp6sock, 5) < 0) {
+ if (listen(tcp6sock, -1) < 0) {
syslog(LOG_ERR, "listen failed");
nfsd_exit(1);
}
@@ -976,11 +931,6 @@ get_tuned_nfsdcount(void)
} else {
tuned_nfsdcnt = ncpu * 8;
}
- if (!new_syscall && tuned_nfsdcnt > MAXNFSDCNT) {
- warnx("nfsd count %d; truncated to %d", tuned_nfsdcnt,
- MAXNFSDCNT);
- tuned_nfsdcnt = MAXNFSDCNT;
- }
return tuned_nfsdcnt;
}
@@ -994,55 +944,48 @@ start_server(int master)
struct addrinfo *aip, hints;
status = 0;
- if (new_syscall) {
- gethostname(hostname, sizeof (hostname));
- snprintf(principal, sizeof (principal), "nfs@%s", hostname);
- if ((cp = strchr(hostname, '.')) == NULL ||
- *(cp + 1) == '\0') {
- /* If not fully qualified, try getaddrinfo() */
- memset((void *)&hints, 0, sizeof (hints));
- hints.ai_flags = AI_CANONNAME;
- error = getaddrinfo(hostname, NULL, &hints, &aip);
- if (error == 0) {
- if (aip->ai_canonname != NULL &&
- (cp = strchr(aip->ai_canonname, '.')) !=
- NULL && *(cp + 1) != '\0')
- snprintf(principal, sizeof (principal),
- "nfs@%s", aip->ai_canonname);
- freeaddrinfo(aip);
- }
+ gethostname(hostname, sizeof (hostname));
+ snprintf(principal, sizeof (principal), "nfs@%s", hostname);
+ if ((cp = strchr(hostname, '.')) == NULL ||
+ *(cp + 1) == '\0') {
+ /* If not fully qualified, try getaddrinfo() */
+ memset((void *)&hints, 0, sizeof (hints));
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(hostname, NULL, &hints, &aip);
+ if (error == 0) {
+ if (aip->ai_canonname != NULL &&
+ (cp = strchr(aip->ai_canonname, '.')) !=
+ NULL && *(cp + 1) != '\0')
+ snprintf(principal, sizeof (principal),
+ "nfs@%s", aip->ai_canonname);
+ freeaddrinfo(aip);
}
- nfsdargs.principal = principal;
+ }
+ nfsdargs.principal = principal;
- if (nfsdcnt_set)
- nfsdargs.minthreads = nfsdargs.maxthreads = nfsdcnt;
- else {
- nfsdargs.minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount();
- nfsdargs.maxthreads = maxthreads_set ? maxthreads : nfsdargs.minthreads;
- if (nfsdargs.maxthreads < nfsdargs.minthreads)
- nfsdargs.maxthreads = nfsdargs.minthreads;
- }
+ if (nfsdcnt_set)
+ nfsdargs.minthreads = nfsdargs.maxthreads = nfsdcnt;
+ else {
+ nfsdargs.minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount();
+ nfsdargs.maxthreads = maxthreads_set ? maxthreads : nfsdargs.minthreads;
+ if (nfsdargs.maxthreads < nfsdargs.minthreads)
+ nfsdargs.maxthreads = nfsdargs.minthreads;
+ }
+ error = nfssvc(nfssvc_nfsd, &nfsdargs);
+ if (error < 0 && errno == EAUTH) {
+ /*
+ * This indicates that it could not register the
+ * rpcsec_gss credentials, usually because the
+ * gssd daemon isn't running.
+ * (only the experimental server with nfsv4)
+ */
+ syslog(LOG_ERR, "No gssd, using AUTH_SYS only");
+ principal[0] = '\0';
error = nfssvc(nfssvc_nfsd, &nfsdargs);
- if (error < 0 && errno == EAUTH) {
- /*
- * This indicates that it could not register the
- * rpcsec_gss credentials, usually because the
- * gssd daemon isn't running.
- * (only the experimental server with nfsv4)
- */
- syslog(LOG_ERR, "No gssd, using AUTH_SYS only");
- principal[0] = '\0';
- error = nfssvc(nfssvc_nfsd, &nfsdargs);
- }
- if (error < 0) {
- syslog(LOG_ERR, "nfssvc: %m");
- status = 1;
- }
- } else {
- if (nfssvc(NFSSVC_OLDNFSD, NULL) < 0) {
- syslog(LOG_ERR, "nfssvc: %m");
- status = 1;
- }
+ }
+ if (error < 0) {
+ syslog(LOG_ERR, "nfssvc: %m");
+ status = 1;
}
if (master)
nfsd_exit(status);
diff --git a/usr.sbin/ntp/config.h b/usr.sbin/ntp/config.h
index 6c49557..b771834 100644
--- a/usr.sbin/ntp/config.h
+++ b/usr.sbin/ntp/config.h
@@ -613,9 +613,6 @@
/* Define to 1 if you have the <net/if.h> header file. */
#define HAVE_NET_IF_H 1
-/* Define to 1 if you have the <net/if_var.h> header file. */
-#define HAVE_NET_IF_VAR_H 1
-
/* Define to 1 if you have the <net/route.h> header file. */
#define HAVE_NET_ROUTE_H 1
diff --git a/usr.sbin/ntp/doc/ntptime.8 b/usr.sbin/ntp/doc/ntptime.8
index f130307..bb3b41a 100644
--- a/usr.sbin/ntp/doc/ntptime.8
+++ b/usr.sbin/ntp/doc/ntptime.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 7, 2000
+.Dd April 27, 2015
.Dt NTPTIME 8
.Os
.Sh NAME
@@ -52,8 +52,6 @@ Specify estimated error, in microseconds.
Specify frequency offset, in parts per million.
.It Fl h
Display help information.
-.It Fl l
-Specify the leap bits as a code from 0 to 3.
.It Fl m Ar max_error
Specify max possible errors, in microseconds.
.It Fl o Ar offset
diff --git a/usr.sbin/pciconf/err.c b/usr.sbin/pciconf/err.c
index b67d1f5..7a77903 100644
--- a/usr.sbin/pciconf/err.c
+++ b/usr.sbin/pciconf/err.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2012 Advanced Computing Technologies LLC
+ * Copyright (c) 2012 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
diff --git a/usr.sbin/ppp/iface.c b/usr.sbin/ppp/iface.c
index 8fee189..5f17769 100644
--- a/usr.sbin/ppp/iface.c
+++ b/usr.sbin/ppp/iface.c
@@ -31,9 +31,6 @@
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_dl.h>
-#ifdef __FreeBSD__
-#include <net/if_var.h>
-#endif
#include <net/route.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
diff --git a/usr.sbin/rip6query/rip6query.c b/usr.sbin/rip6query/rip6query.c
index ea448ba2..a35c750 100644
--- a/usr.sbin/rip6query/rip6query.c
+++ b/usr.sbin/rip6query/rip6query.c
@@ -46,9 +46,6 @@
#include <sys/queue.h>
#include <net/if.h>
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-#include <net/if_var.h>
-#endif /* __FreeBSD__ >= 3 */
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>
diff --git a/usr.sbin/route6d/route6d.c b/usr.sbin/route6d/route6d.c
index 258219b..3c3d9d3 100644
--- a/usr.sbin/route6d/route6d.c
+++ b/usr.sbin/route6d/route6d.c
@@ -63,7 +63,6 @@ static const char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itoju
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
diff --git a/usr.sbin/rpc.lockd/Makefile b/usr.sbin/rpc.lockd/Makefile
index 16b4d4f..73c69ef 100644
--- a/usr.sbin/rpc.lockd/Makefile
+++ b/usr.sbin/rpc.lockd/Makefile
@@ -9,7 +9,7 @@ SRCS= kern.c nlm_prot_svc.c lockd.c lock_proc.c lockd_lock.c
CFLAGS+= -I. -I${DESTDIR}/usr/include/rpcsvc
WARNS?= 3
-LIBADD= rpcsvc util
+LIBADD= rpcsvc
CLEANFILES= nlm_prot_svc.c nlm_prot.h test
diff --git a/usr.sbin/rrenumd/lexer.l b/usr.sbin/rrenumd/lexer.l
index 6e55f9e..47656e8 100644
--- a/usr.sbin/rrenumd/lexer.l
+++ b/usr.sbin/rrenumd/lexer.l
@@ -40,10 +40,6 @@
#include <string.h>
#include <net/if.h>
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-#include <net/if_var.h>
-#endif /* __FreeBSD__ >= 3 */
-
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/icmp6.h>
diff --git a/usr.sbin/rrenumd/parser.y b/usr.sbin/rrenumd/parser.y
index 65dfd46..6436df7 100644
--- a/usr.sbin/rrenumd/parser.y
+++ b/usr.sbin/rrenumd/parser.y
@@ -39,9 +39,6 @@
#include <sys/queue.h>
#include <net/if.h>
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-#include <net/if_var.h>
-#endif /* __FreeBSD__ >= 3 */
#include <netinet/in.h>
#include <netinet/in_var.h>
diff --git a/usr.sbin/rtadvctl/rtadvctl.c b/usr.sbin/rtadvctl/rtadvctl.c
index 3f22518..f1657d7 100644
--- a/usr.sbin/rtadvctl/rtadvctl.c
+++ b/usr.sbin/rtadvctl/rtadvctl.c
@@ -36,7 +36,6 @@
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
-#include <net/if_var.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index 5c9d778..4f14e0fb 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -36,7 +36,6 @@
#include <sys/socket.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/route.h>
#include <net/if_dl.h>
diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c
index 5413cdf..0eef734 100644
--- a/usr.sbin/rtadvd/if.c
+++ b/usr.sbin/rtadvd/if.c
@@ -38,7 +38,6 @@
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
-#include <net/if_var.h>
#include <net/ethernet.h>
#include <net/route.h>
#include <netinet/in.h>
diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c
index 0c97d98..eede4b6 100644
--- a/usr.sbin/rtadvd/rrenum.c
+++ b/usr.sbin/rtadvd/rrenum.c
@@ -37,7 +37,6 @@
#include <net/if.h>
#include <net/if_dl.h>
-#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c
index 6554b61..0169a56 100644
--- a/usr.sbin/rtadvd/rtadvd.c
+++ b/usr.sbin/rtadvd/rtadvd.c
@@ -51,7 +51,6 @@
#include <arpa/inet.h>
-#include <net/if_var.h>
#include <netinet/in_var.h>
#include <netinet6/nd6.h>
diff --git a/usr.sbin/rtsold/Makefile b/usr.sbin/rtsold/Makefile
index 53dea03..a235dfb 100644
--- a/usr.sbin/rtsold/Makefile
+++ b/usr.sbin/rtsold/Makefile
@@ -21,6 +21,5 @@ SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
WARNS?= 3
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H
-LIBADD= kvm
.include <bsd.prog.mk>
diff --git a/usr.sbin/rtsold/if.c b/usr.sbin/rtsold/if.c
index 2bf946d..b8a90b6 100644
--- a/usr.sbin/rtsold/if.c
+++ b/usr.sbin/rtsold/if.c
@@ -38,7 +38,6 @@
#include <sys/queue.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/if_dl.h>
@@ -248,9 +247,7 @@ lladdropt_length(struct sockaddr_dl *sdl)
{
switch (sdl->sdl_type) {
case IFT_ETHER:
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
return (ROUNDUP8(ETHER_ADDR_LEN + 2));
default:
return (0);
@@ -266,9 +263,7 @@ lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
switch (sdl->sdl_type) {
case IFT_ETHER:
-#ifdef IFT_IEEE80211
case IFT_IEEE80211:
-#endif
ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
addr = (char *)(ndopt + 1);
memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
diff --git a/usr.sbin/rtsold/probe.c b/usr.sbin/rtsold/probe.c
index 5ec54aa..89a1617a 100644
--- a/usr.sbin/rtsold/probe.c
+++ b/usr.sbin/rtsold/probe.c
@@ -40,7 +40,6 @@
#include <sys/queue.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <netinet/in.h>
diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c
index a97b884..bba15bb 100644
--- a/usr.sbin/rtsold/rtsold.c
+++ b/usr.sbin/rtsold/rtsold.c
@@ -38,7 +38,6 @@
#include <net/if.h>
#include <net/if_dl.h>
-#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
diff --git a/usr.sbin/smbmsg/smbmsg.c b/usr.sbin/smbmsg/smbmsg.c
index 425b782..4e7e609 100644
--- a/usr.sbin/smbmsg/smbmsg.c
+++ b/usr.sbin/smbmsg/smbmsg.c
@@ -163,7 +163,8 @@ do_io(void)
}
if (iflag == 1 && oflag == -1) {
/* command + 1 byte input: read byte op. */
- c.data.byte_ptr = ibuf;
+ c.rbuf = ibuf;
+ c.rcount = iflag;
if (ioctl(fd, SMB_READB, &c) == -1)
return (-1);
printf(fmt, (int)(unsigned char)ibuf[0]);
@@ -171,11 +172,12 @@ do_io(void)
return (0);
} else if (iflag == -1 && oflag == 1) {
/* command + 1 byte output: write byte op. */
- c.data.byte = obuf[0];
+ c.wdata.byte = obuf[0];
return (ioctl(fd, SMB_WRITEB, &c));
} else if (wflag && iflag == 2 && oflag == -1) {
/* command + 2 bytes input: read word op. */
- c.data.word_ptr = &iword;
+ c.rbuf = (char*) &iword;
+ c.rcount = iflag;
if (ioctl(fd, SMB_READW, &c) == -1)
return (-1);
printf(fmt, (int)(unsigned short)iword);
@@ -183,15 +185,16 @@ do_io(void)
return (0);
} else if (wflag && iflag == -1 && oflag == 2) {
/* command + 2 bytes output: write word op. */
- c.data.word = oword;
+ c.wdata.word = oword;
return (ioctl(fd, SMB_WRITEW, &c));
} else if (wflag && iflag == 2 && oflag == 2) {
/*
* command + 2 bytes output + 2 bytes input:
* "process call" op.
*/
- c.data.process.sdata = oword;
- c.data.process.rdata = &iword;
+ c.wdata.word = oword;
+ c.rbuf = (char*) &iword;
+ c.rcount = iflag;
if (ioctl(fd, SMB_PCALL, &c) == -1)
return (-1);
printf(fmt, (int)(unsigned short)iword);
@@ -199,8 +202,8 @@ do_io(void)
return (0);
} else if (iflag > 1 && oflag == -1) {
/* command + > 1 bytes of input: block read */
- c.data.byte_ptr = ibuf;
- c.count = iflag;
+ c.rbuf = ibuf;
+ c.rcount = iflag;
if (ioctl(fd, SMB_BREAD, &c) == -1)
return (-1);
for (i = 0; i < iflag; i++) {
@@ -212,8 +215,8 @@ do_io(void)
return (0);
} else if (iflag == -1 && oflag > 1) {
/* command + > 1 bytes of output: block write */
- c.data.byte_ptr = obuf;
- c.count = oflag;
+ c.wbuf = obuf;
+ c.wcount = oflag;
return (ioctl(fd, SMB_BWRITE, &c));
}
diff --git a/usr.sbin/sysrc/sysrc b/usr.sbin/sysrc/sysrc
index bcb2178..67b5e14 100644
--- a/usr.sbin/sysrc/sysrc
+++ b/usr.sbin/sysrc/sysrc
@@ -80,7 +80,7 @@ die()
#
usage()
{
- f_err "Usage: %s [OPTIONS] name[[+]=value] ...\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
f_err "Try \`%s --help' for more information.\n" "$pgm"
die
}
diff --git a/usr.sbin/tzsetup/tzsetup.c b/usr.sbin/tzsetup/tzsetup.c
index 71ba63b..fc80364 100644
--- a/usr.sbin/tzsetup/tzsetup.c
+++ b/usr.sbin/tzsetup/tzsetup.c
@@ -475,7 +475,7 @@ read_zones(void)
FILE *fp;
struct continent *cont;
size_t len;
- char *line, *tlc, *coord, *file, *descr, *p;
+ char *line, *tlc, *file, *descr, *p;
int lineno;
fp = fopen(path_zonetab, "r");
@@ -495,7 +495,7 @@ read_zones(void)
if (strlen(tlc) != 2)
errx(1, "%s:%d: invalid country code `%s'",
path_zonetab, lineno, tlc);
- coord = strsep(&line, "\t"); /* Unused */
+ /* coord = */ strsep(&line, "\t"); /* Unused */
file = strsep(&line, "\t");
p = strchr(file, '/');
if (p == 0)
diff --git a/usr.sbin/uhsoctl/uhsoctl.c b/usr.sbin/uhsoctl/uhsoctl.c
index 21b6220..686d45f 100644
--- a/usr.sbin/uhsoctl/uhsoctl.c
+++ b/usr.sbin/uhsoctl/uhsoctl.c
@@ -37,7 +37,6 @@
#include <arpa/inet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
diff --git a/usr.sbin/vidcontrol/vidcontrol.c b/usr.sbin/vidcontrol/vidcontrol.c
index 3001f69..cbf8f47 100644
--- a/usr.sbin/vidcontrol/vidcontrol.c
+++ b/usr.sbin/vidcontrol/vidcontrol.c
@@ -1085,12 +1085,16 @@ show_mode_info(void)
printf("---------------------------------------"
"---------------------------------------\n");
+ memset(&_info, 0, sizeof(_info));
for (mode = 0; mode <= M_VESA_MODE_MAX; ++mode) {
_info.vi_mode = mode;
if (ioctl(0, CONS_MODEINFO, &_info))
continue;
if (_info.vi_mode != mode)
continue;
+ if (_info.vi_width == 0 && _info.vi_height == 0 &&
+ _info.vi_cwidth == 0 && _info.vi_cheight == 0)
+ continue;
printf("%3d (0x%03x)", mode, mode);
printf(" 0x%08x", _info.vi_flags);
@@ -1343,7 +1347,7 @@ main(int argc, char **argv)
if (vt4_mode)
opts = "b:Cc:fg:h:Hi:M:m:pPr:S:s:T:t:x";
else
- opts = "b:Cc:df:g:h:Hi:l:LM:m:pPr:S:s:T:t:x";
+ opts = "b:Cc:dfg:h:Hi:l:LM:m:pPr:S:s:T:t:x";
while ((opt = getopt(argc, argv, opts)) != -1)
switch(opt) {
diff --git a/usr.sbin/wpa/Makefile.crypto b/usr.sbin/wpa/Makefile.crypto
index 3049011..46cd9ef 100644
--- a/usr.sbin/wpa/Makefile.crypto
+++ b/usr.sbin/wpa/Makefile.crypto
@@ -53,7 +53,8 @@ SRCS+= tls_openssl.c
.endif
.if defined(CONFIG_INTERNAL_AES)
-SRCS+= aes-internal.c \
+SRCS+= aes-unwrap.c aes-wrap.c \
+ aes-internal.c \
aes-internal-dec.c \
aes-internal-enc.c
.endif
@@ -92,7 +93,7 @@ SRCS+= md4-internal.c
.endif
.if defined(CONFIG_INTERNAL_MD5)
-SRCS+= md5-internal.c
+SRCS+= md5.c md5-internal.c
.endif
.if defined(NEED_FIPS186_2_PRF)
diff --git a/usr.sbin/wpa/hostapd/Makefile b/usr.sbin/wpa/hostapd/Makefile
index 4621ad3..04fbc4d 100644
--- a/usr.sbin/wpa/hostapd/Makefile
+++ b/usr.sbin/wpa/hostapd/Makefile
@@ -7,15 +7,17 @@
${WPA_DISTDIR}/src/drivers
PROG= hostapd
-SRCS= accounting.c aes-wrap.c ap_config.c ap_drv_ops.c ap_mlme.c authsrv.c \
- base64.c beacon.c chap.c common.c config_file.c ctrl_iface.c \
+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 \
+ 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 ieee802_11_auth.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 md5.c ms_funcs.c os_unix.c peerkey_auth.c pmksa_cache_auth.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 \
@@ -64,10 +66,9 @@ CFLAGS+=-DDPKCS12_FUNCS \
-DEAP_SERVER_TLS \
-DEAP_SERVER_TTLS \
-DEAP_TLS_FUNCS \
- -DEAP_SERVER_WSC \
- -DCONFIG_NO_DUMP_STATE
-SRCS+= dump_state.c \
- eap_server_gtc.c \
+ -DEAP_SERVER_WSC
+
+SRCS+= eap_server_gtc.c \
eap_server_identity.c \
eap_server_md5.c \
eap_server_mschapv2.c \
diff --git a/usr.sbin/wpa/ndis_events/ndis_events.c b/usr.sbin/wpa/ndis_events/ndis_events.c
index 9c6e9de..b61fd0a 100644
--- a/usr.sbin/wpa/ndis_events/ndis_events.c
+++ b/usr.sbin/wpa/ndis_events/ndis_events.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
-#include <net/if_var.h>
#include <netinet/in.h>
#include <arpa/inet.h>
diff --git a/usr.sbin/wpa/wpa_passphrase/Makefile b/usr.sbin/wpa/wpa_passphrase/Makefile
index c138481..aaf5c19 100644
--- a/usr.sbin/wpa/wpa_passphrase/Makefile
+++ b/usr.sbin/wpa/wpa_passphrase/Makefile
@@ -5,11 +5,10 @@
.PATH.c:${WPA_SUPPLICANT_DISTDIR}
PROG= wpa_passphrase
-SRCS= common.c md5-internal.c md5.c os_unix.c sha1-internal.c sha1-pbkdf2.c sha1.c \
- wpa_passphrase.c
+SRCS= common.c md5-internal.c md5.c os_unix.c sha1-internal.c sha1-pbkdf2.c \
+ sha1.c wpa_passphrase.c
-CFLAGS+= -DINTERNAL_SHA1
-CFLAGS+= -DINTERNAL_MD5
+CFLAGS+= -DCONFIG_CRYPTO_INTERNAL -DINTERNAL_SHA1 -DINTERNAL_MD5
LIBADD+= util
diff --git a/usr.sbin/wpa/wpa_supplicant/Makefile b/usr.sbin/wpa/wpa_supplicant/Makefile
index dd40766..ecbacb1 100644
--- a/usr.sbin/wpa/wpa_supplicant/Makefile
+++ b/usr.sbin/wpa/wpa_supplicant/Makefile
@@ -8,14 +8,17 @@
${WPA_DISTDIR}/src/drivers
PROG= wpa_supplicant
-SRCS= aes-unwrap.c base64.c blacklist.c bss.c common.c config.c \
+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 \
- ieee802_11_common.c interworking.c l2_packet_freebsd.c main.c \
- md5.c notify.c offchannel.c os_unix.c peerkey.c pmksa_cache.c \
- preauth.c scan.c upnp_xml.c uuid.c wpa.c wpa_common.c wpa_debug.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 \
wps_common.c wps_dev_attr.c wps_enrollee.c wps_registrar.c \
diff --git a/usr.sbin/wpa/wpa_supplicant/Packet32.c b/usr.sbin/wpa/wpa_supplicant/Packet32.c
index 876417e..8e7da03 100644
--- a/usr.sbin/wpa/wpa_supplicant/Packet32.c
+++ b/usr.sbin/wpa/wpa_supplicant/Packet32.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <sys/fcntl.h>
#include <net/if.h>
#include <net/if_dl.h>
-#include <net/if_var.h>
#include <netinet/in.h>
#include <arpa/inet.h>
OpenPOWER on IntegriCloud